From 7a8e5e6ab791079e00e81389ce8d1698d009e4f8 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 16 2020 08:09:01 +0000 Subject: numpy-1.14.3 base --- diff --git a/INSTALL.rst.txt b/INSTALL.rst.txt new file mode 100644 index 0000000..8b135e3 --- /dev/null +++ b/INSTALL.rst.txt @@ -0,0 +1,155 @@ +Building and installing NumPy ++++++++++++++++++++++++++++++ + +**IMPORTANT**: the below notes are about building NumPy, which for most users +is *not* the recommended way to install NumPy. Instead, use either a complete +scientific Python distribution (recommended) or a binary installer - see +http://scipy.org/install.html. + + +.. Contents:: + +Prerequisites +============= + +Building NumPy requires the following software installed: + +1) For Python 2, Python__ 2.7.x or newer. + For Python 3, Python__ 3.4.x or newer. + + On Debian and derivative (Ubuntu): python python-dev + + On Windows: the official python installer on Python__ is enough + + Make sure that the Python package distutils is installed before + continuing. For example, in Debian GNU/Linux, distutils is included + in the python-dev package. + + Python must also be compiled with the zlib module enabled. + +2) Cython >= 0.19 (for development versions of numpy, not for released + versions) +3) nose__ (optional) 1.0 or later + + This is required for testing numpy, but not for using it. + +Python__ http://www.python.org +nose__ http://nose.readthedocs.io + + +.. note:: + + If you want to build NumPy in order to work on NumPy itself, use + ``runtests.py``. For more details, see + http://docs.scipy.org/doc/numpy-dev/dev/development_environment.html + +.. note:: + + More extensive information on building NumPy (and Scipy) is maintained at + http://scipy.org/scipylib/building/index.html + + +Basic Installation +================== + +To install numpy run:: + + python setup.py build -j 4 install --prefix $HOME/.local + +This will compile numpy on 4 CPUs and install it into the specified prefix. +To perform an inplace build that can be run from the source folder run:: + + python setup.py build_ext --inplace -j 4 + +The number of build jobs can also be specified via the environment variable +NPY_NUM_BUILD_JOBS. + + +Choosing compilers +================== + +NumPy needs a C compiler, and for development versions also Cython. A Fortran +compiler isn't needed to build NumPy itself; the ``numpy.f2py`` tests will be +skipped when running the test suite if no Fortran compiler is available. For +building Scipy a Fortran compiler is needed though, so we include some details +on Fortran compilers in the rest of this section. + +On OS X and Linux, all common compilers will work. Note that for Fortran, +``gfortran`` is strongly preferred over ``g77``, but if you happen to have both +installed then ``g77`` will be detected and used first. To explicitly select +``gfortran`` in that case, do:: + + python setup.py build --fcompiler=gnu95 + +Windows +------- + +On Windows, building from source can be difficult. Currently the most robust +option is to use the Intel compilers, or alternatively MSVC (the same version +as used to build Python itself) with Intel ifort. Intel itself maintains a +good `application note `_ +on this. + +If you want to use a free compiler toolchain, the recommended compiler is MingwPy__. +The older MinGW32 compiler set used to produce older .exe installers for NumPy +itself is still available at https://github.com/numpy/numpy-vendor, but not +recommended for use anymore. + +MingwPy__ http://mingwpy.github.io + + +Building with optimized BLAS support +==================================== + +Configuring which BLAS/LAPACK is used if you have multiple libraries installed, +or you have only one installed but in a non-standard location, is done via a +``site.cfg`` file. See the ``site.cfg.example`` shipped with NumPy for more +details. + +Windows +------- + +The Intel compilers work with Intel MKL, see the application note linked above. +MingwPy__ works with OpenBLAS. +For an overview of the state of BLAS/LAPACK libraries on Windows, see +`here `_. + +OS X +---- + +OS X ships the Accelerate framework, which NumPy can build against without any +manual configuration. Other BLAS/LAPACK implementations (OpenBLAS, Intel MKL, +ATLAS) will also work. + +Ubuntu/Debian +------------- + +For best performance a development package providing BLAS and CBLAS should be +installed. Some of the options available are: + +- ``libblas-dev``: reference BLAS (not very optimized) +- ``libatlas-base-dev``: generic tuned ATLAS, it is recommended to tune it to + the available hardware, see /usr/share/doc/libatlas3-base/README.Debian for + instructions +- ``libopenblas-base``: fast and runtime detected so no tuning required but a + very recent version is needed (>=0.2.15 is recommended). Older versions of + OpenBLAS suffered from correctness issues on some CPUs. + +The package linked to when numpy is loaded can be chosen after installation via +the alternatives mechanism:: + + update-alternatives --config libblas.so.3 + update-alternatives --config liblapack.so.3 + +Or by preloading a specific BLAS library with:: + + LD_PRELOAD=/usr/lib/atlas-base/atlas/libblas.so.3 python ... + + +Build issues +============ + +If you run into build issues and need help, the NumPy +`mailing list `_ is the best +place to ask. If the issue is clearly a bug in NumPy, please file an issue (or +even better, a pull request) at https://github.com/numpy/numpy. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..0065d46 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,60 @@ +Copyright (c) 2005-2017, NumPy Developers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the NumPy Developers nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +The NumPy repository and source distributions bundle several libraries that are +compatibly licensed. We list these here. + +Name: Numpydoc +Files: doc/sphinxext/numpydoc/* +License: 2-clause BSD + For details, see doc/sphinxext/LICENSE.txt + +Name: scipy-sphinx-theme +Files: doc/scipy-sphinx-theme/* +License: 3-clause BSD, PSF and Apache 2.0 + For details, see doc/sphinxext/LICENSE.txt + +Name: lapack-lite +Files: numpy/linalg/lapack_lite/* +License: 3-clause BSD + For details, see numpy/linalg/lapack_lite/LICENSE.txt + +Name: tempita +Files: tools/npy_tempita/* +License: BSD derived + For details, see tools/npy_tempita/license.txt + +Name: dragon4 +Files: numpy/core/src/multiarray/dragon4.c +License: One of a kind + For license text, see numpy/core/src/multiarray/dragon4.c diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..a15a05c --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,30 @@ +# +# Use .add_data_files and .add_data_dir methods in a appropriate +# setup.py files to include non-python files such as documentation, +# data, etc files to distribution. Avoid using MANIFEST.in for that. +# +include MANIFEST.in +include *.txt +include site.cfg.example +include numpy/random/mtrand/generate_mtrand_c.py +recursive-include numpy/random/mtrand *.pyx *.pxd +# Add build support that should go in sdist, but not go in bdist/be installed +recursive-include numpy/_build_utils * +recursive-include numpy/linalg/lapack_lite *.c *.h +include tox.ini +# Add sdist files whose use depends on local configuration. +include numpy/core/src/multiarray/cblasfuncs.c +include numpy/core/src/multiarray/python_xerbla.c +# Adding scons build related files not found by distutils +recursive-include numpy/core/code_generators *.py *.txt +recursive-include numpy/core *.in *.h +# Add documentation: we don't use add_data_dir since we do not want to include +# this at installation, only for sdist-generated tarballs +include doc/Makefile doc/postprocess.py +recursive-include doc/release * +recursive-include doc/source * +recursive-include doc/sphinxext * +recursive-include tools/swig * +recursive-include doc/scipy-sphinx-theme * + +global-exclude *.pyc *.pyo *.pyd *.swp *.bak *~ diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..6b5d9a9 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,54 @@ +Metadata-Version: 1.2 +Name: numpy +Version: 1.14.3 +Summary: NumPy: array processing for numbers, strings, records, and objects. +Home-page: http://www.numpy.org +Author: Travis E. Oliphant et al. +Maintainer: NumPy Developers +Maintainer-email: numpy-discussion@python.org +License: BSD +Download-URL: https://pypi.python.org/pypi/numpy +Description: NumPy is a general-purpose array-processing package designed to + efficiently manipulate large multi-dimensional arrays of arbitrary + records without sacrificing too much speed for small multi-dimensional + arrays. NumPy is built on the Numeric code base and adds features + introduced by numarray as well as an extended C-API and the ability to + create arrays of arbitrary type which also makes NumPy suitable for + interfacing with general-purpose data-base applications. + + There are also basic facilities for discrete fourier transform, + basic linear algebra and random number generation. + + All numpy wheels distributed from pypi are BSD licensed. + + Windows wheels are linked against the ATLAS BLAS / LAPACK library, restricted + to SSE2 instructions, so may not give optimal linear algebra performance for + your machine. See http://docs.scipy.org/doc/numpy/user/install.html for + alternatives. + + +Platform: Windows +Platform: Linux +Platform: Solaris +Platform: Mac OS-X +Platform: Unix +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Science/Research +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved +Classifier: Programming Language :: C +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Topic :: Software Development +Classifier: Topic :: Scientific/Engineering +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Operating System :: Unix +Classifier: Operating System :: MacOS +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* diff --git a/THANKS.txt b/THANKS.txt new file mode 100644 index 0000000..396f4fb --- /dev/null +++ b/THANKS.txt @@ -0,0 +1,64 @@ +Travis Oliphant for the NumPy core, the NumPy guide, various + bug-fixes and code contributions. +Paul Dubois, who implemented the original Masked Arrays. +Pearu Peterson for f2py, numpy.distutils and help with code + organization. +Robert Kern for mtrand, bug fixes, help with distutils, code + organization, strided tricks and much more. +Eric Jones for planning and code contributions. +Fernando Perez for code snippets, ideas, bugfixes, and testing. +Ed Schofield for matrix.py patches, bugfixes, testing, and docstrings. +Robert Cimrman for array set operations and numpy.distutils help. +John Hunter for code snippets from matplotlib. +Chris Hanley for help with records.py, testing, and bug fixes. +Travis Vaught for administration, community coordination and + marketing. +Joe Cooper, Jeff Strunk for administration. +Eric Firing for bugfixes. +Arnd Baecker for 64-bit testing. +David Cooke for many code improvements including the auto-generated C-API, + and optimizations. +Andrew Straw for help with the web-page, documentation, packaging and + testing. +Alexander Belopolsky (Sasha) for Masked array bug-fixes and tests, + rank-0 array improvements, scalar math help and other code additions. +Francesc Altet for unicode, work on nested record arrays, and bug-fixes. +Tim Hochberg for getting the build working on MSVC, optimization + improvements, and code review. +Charles (Chuck) Harris for the sorting code originally written for + Numarray and for improvements to polyfit, many bug fixes, delving + into the C code, release management, and documentation. +David Huard for histogram improvements including 2-D and d-D code and + other bug-fixes. +Stefan van der Walt for numerous bug-fixes, testing and documentation. +Albert Strasheim for documentation, bug-fixes, regression tests and + Valgrind expertise. +David Cournapeau for build support, doc-and-bug fixes, and code + contributions including fast_clipping. +Jarrod Millman for release management, community coordination, and code + clean up. +Chris Burns for work on memory mapped arrays and bug-fixes. +Pauli Virtanen for documentation, bug-fixes, lookfor and the + documentation editor. +A.M. Archibald for no-copy-reshape code, strided array tricks, + documentation and bug-fixes. +Pierre Gerard-Marchant for rewriting masked array functionality. +Roberto de Almeida for the buffered array iterator. +Alan McIntyre for updating the NumPy test framework to use nose, improve + the test coverage, and enhancing the test system documentation. +Joe Harrington for administering the 2008 Documentation Sprint. +Mark Wiebe for the new NumPy iterator, the float16 data type, improved + low-level data type operations, and other NumPy core improvements. + +NumPy is based on the Numeric (Jim Hugunin, Paul Dubois, Konrad +Hinsen, and David Ascher) and NumArray (Perry Greenfield, J Todd +Miller, Rick White and Paul Barrett) projects. We thank them for +paving the way ahead. + +Institutions +------------ + +Enthought for providing resources and finances for development of NumPy. +UC Berkeley for providing travel money and hosting numerous sprints. +The University of Central Florida for funding the 2008 Documentation Marathon. +The University of Stellenbosch for hosting the buildbot. diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..d414d26 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +PYVER = 2.7 +PYTHON = python$(PYVER) + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = LANG=C sphinx-build +PAPER = + +FILES= + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html web pickle htmlhelp latex changes linkcheck \ + dist dist-build gitwash-update + +#------------------------------------------------------------------------------ + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " html-scipyorg to make standalone HTML files with scipy.org theming" + @echo " pickle to make pickle files (usable by e.g. sphinx-web)" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " changes to make an overview over all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " dist PYVER=... to make a distribution-ready tree" + @echo " gitwash-update GITWASH=path/to/gitwash update gitwash developer docs" + @echo " upload USERNAME=... RELEASE=... to upload built docs to docs.scipy.org" + +clean: + -rm -rf build/* source/reference/generated + +gitwash-update: + rm -rf source/dev/gitwash + install -d source/dev/gitwash + python $(GITWASH)/gitwash_dumper.py source/dev NumPy \ + --repo-name=numpy \ + --github-user=numpy + cat source/dev/gitwash_links.txt >> source/dev/gitwash/git_links.inc + +#------------------------------------------------------------------------------ +# Automated generation of all documents +#------------------------------------------------------------------------------ + +# Build the current numpy version, and extract docs from it. +# We have to be careful of some issues: +# +# - Everything must be done using the same Python version +# - We must use eggs (otherwise they might override PYTHONPATH on import). +# - Different versions of easy_install install to different directories (!) +# + + +INSTALL_DIR = $(CURDIR)/build/inst-dist/ +INSTALL_PPH = $(INSTALL_DIR)/lib/python$(PYVER)/site-packages:$(INSTALL_DIR)/local/lib/python$(PYVER)/site-packages:$(INSTALL_DIR)/lib/python$(PYVER)/dist-packages:$(INSTALL_DIR)/local/lib/python$(PYVER)/dist-packages +UPLOAD_DIR=/srv/docs_scipy_org/doc/numpy-$(RELEASE) + +DIST_VARS=SPHINXBUILD="LANG=C PYTHONPATH=$(INSTALL_PPH) python$(PYVER) `which sphinx-build`" PYTHON="PYTHONPATH=$(INSTALL_PPH) python$(PYVER)" SPHINXOPTS="$(SPHINXOPTS)" + +dist: + make $(DIST_VARS) real-dist + +real-dist: dist-build html html-scipyorg + test -d build/latex || make latex + make -C build/latex all-pdf + -test -d build/htmlhelp || make htmlhelp-build + -rm -rf build/dist + cp -r build/html-scipyorg build/dist + cd build/html && zip -9r ../dist/numpy-html.zip . + cp build/latex/numpy-ref.pdf build/dist + cp build/latex/numpy-user.pdf build/dist + cd build/dist && tar czf ../dist.tar.gz * + chmod ug=rwX,o=rX -R build/dist + find build/dist -type d -print0 | xargs -0r chmod g+s + +dist-build: + rm -f ../dist/*.egg + cd .. && $(PYTHON) setup.py bdist_egg + install -d $(subst :, ,$(INSTALL_PPH)) + $(PYTHON) `which easy_install` --prefix=$(INSTALL_DIR) ../dist/*.egg + +upload: + # SSH must be correctly configured for this to work. + # Assumes that ``make dist`` was already run + # Example usage: ``make upload USERNAME=rgommers RELEASE=1.10.1`` + ssh $(USERNAME)@docs.scipy.org mkdir $(UPLOAD_DIR) + scp build/dist.tar.gz $(USERNAME)@docs.scipy.org:$(UPLOAD_DIR) + ssh $(USERNAME)@docs.scipy.org tar xvC $(UPLOAD_DIR) \ + -zf $(UPLOAD_DIR)/dist.tar.gz + ssh $(USERNAME)@docs.scipy.org mv $(UPLOAD_DIR)/numpy-ref.pdf \ + $(UPLOAD_DIR)/numpy-ref-$(RELEASE).pdf + ssh $(USERNAME)@docs.scipy.org mv $(UPLOAD_DIR)/numpy-user.pdf \ + $(UPLOAD_DIR)/numpy-user-$(RELEASE).pdf + ssh $(USERNAME)@docs.scipy.org mv $(UPLOAD_DIR)/numpy-html.zip \ + $(UPLOAD_DIR)/numpy-html-$(RELEASE).zip + ssh $(USERNAME)@docs.scipy.org rm $(UPLOAD_DIR)/dist.tar.gz + ssh $(USERNAME)@docs.scipy.org ln -snf numpy-$(RELEASE) /srv/docs_scipy_org/doc/numpy + +#------------------------------------------------------------------------------ +# Basic Sphinx generation rules for different formats +#------------------------------------------------------------------------------ + +generate: build/generate-stamp +build/generate-stamp: $(wildcard source/reference/*.rst) + mkdir -p build + touch build/generate-stamp + +html: generate + mkdir -p build/html build/doctrees + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html $(FILES) + $(PYTHON) postprocess.py html build/html/*.html + @echo + @echo "Build finished. The HTML pages are in build/html." + +html-scipyorg: + mkdir -p build/html build/doctrees + $(SPHINXBUILD) -t scipyorg -b html $(ALLSPHINXOPTS) build/html-scipyorg $(FILES) + @echo + @echo "Build finished. The HTML pages are in build/html." + +pickle: generate + mkdir -p build/pickle build/doctrees + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle $(FILES) + @echo + @echo "Build finished; now you can process the pickle files or run" + @echo " sphinx-web build/pickle" + @echo "to start the sphinx-web server." + +web: pickle + +htmlhelp: generate + mkdir -p build/htmlhelp build/doctrees + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp $(FILES) + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in build/htmlhelp." + +htmlhelp-build: htmlhelp build/htmlhelp/numpy.chm +%.chm: %.hhp + -hhc.exe $^ + +qthelp: generate + mkdir -p build/qthelp build/doctrees + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) build/qthelp $(FILES) + +latex: generate + mkdir -p build/latex build/doctrees + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex $(FILES) + $(PYTHON) postprocess.py tex build/latex/*.tex + perl -pi -e 's/\t(latex.*|pdflatex) (.*)/\t-$$1 -interaction batchmode $$2/' build/latex/Makefile + @echo + @echo "Build finished; the LaTeX files are in build/latex." + @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ + "run these through (pdf)latex." + +coverage: build + mkdir -p build/coverage build/doctrees + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) build/coverage $(FILES) + @echo "Coverage finished; see c.txt and python.txt in build/coverage" + +changes: generate + mkdir -p build/changes build/doctrees + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes $(FILES) + @echo + @echo "The overview file is in build/changes." + +linkcheck: generate + mkdir -p build/linkcheck build/doctrees + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck $(FILES) + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in build/linkcheck/output.txt." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) build/texinfo + @echo + @echo "Build finished. The Texinfo files are in build/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) build/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C build/texinfo info + @echo "makeinfo finished; the Info files are in build/texinfo." diff --git a/doc/postprocess.py b/doc/postprocess.py new file mode 100755 index 0000000..2e50c11 --- /dev/null +++ b/doc/postprocess.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +""" +%prog MODE FILES... + +Post-processes HTML and Latex files output by Sphinx. +MODE is either 'html' or 'tex'. + +""" +from __future__ import division, absolute_import, print_function + +import re +import optparse +import io + +def main(): + p = optparse.OptionParser(__doc__) + options, args = p.parse_args() + + if len(args) < 1: + p.error('no mode given') + + mode = args.pop(0) + + if mode not in ('html', 'tex'): + p.error('unknown mode %s' % mode) + + for fn in args: + f = io.open(fn, 'r', encoding="utf-8") + try: + if mode == 'html': + lines = process_html(fn, f.readlines()) + elif mode == 'tex': + lines = process_tex(f.readlines()) + finally: + f.close() + + f = io.open(fn, 'w', encoding="utf-8") + f.write("".join(lines)) + f.close() + +def process_html(fn, lines): + return lines + +def process_tex(lines): + """ + Remove unnecessary section titles from the LaTeX file. + + """ + new_lines = [] + for line in lines: + if (line.startswith(r'\section{numpy.') + or line.startswith(r'\subsection{numpy.') + or line.startswith(r'\subsubsection{numpy.') + or line.startswith(r'\paragraph{numpy.') + or line.startswith(r'\subparagraph{numpy.') + ): + pass # skip! + else: + new_lines.append(line) + return new_lines + +if __name__ == "__main__": + main() diff --git a/doc/release/1.10.0-notes.rst b/doc/release/1.10.0-notes.rst new file mode 100644 index 0000000..88062e4 --- /dev/null +++ b/doc/release/1.10.0-notes.rst @@ -0,0 +1,464 @@ +========================== +NumPy 1.10.0 Release Notes +========================== + +This release supports Python 2.6 - 2.7 and 3.2 - 3.5. + + +Highlights +========== +* numpy.distutils now supports parallel compilation via the --parallel/-j + argument passed to setup.py build +* numpy.distutils now supports additional customization via site.cfg to + control compilation parameters, i.e. runtime libraries, extra + linking/compilation flags. +* Addition of *np.linalg.multi_dot*: compute the dot product of two or more + arrays in a single function call, while automatically selecting the fastest + evaluation order. +* The new function `np.stack` provides a general interface for joining a + sequence of arrays along a new axis, complementing `np.concatenate` for + joining along an existing axis. +* Addition of `nanprod` to the set of nanfunctions. +* Support for the '@' operator in Python 3.5. + +Dropped Support +=============== + +* The _dotblas module has been removed. CBLAS Support is now in + Multiarray. +* The testcalcs.py file has been removed. +* The polytemplate.py file has been removed. +* npy_PyFile_Dup and npy_PyFile_DupClose have been removed from + npy_3kcompat.h. +* splitcmdline has been removed from numpy/distutils/exec_command.py. +* try_run and get_output have been removed from + numpy/distutils/command/config.py +* The a._format attribute is no longer supported for array printing. +* Keywords ``skiprows`` and ``missing`` removed from np.genfromtxt. +* Keyword ``old_behavior`` removed from np.correlate. + +Future Changes +============== + +* In array comparisons like ``arr1 == arr2``, many corner cases + involving strings or structured dtypes that used to return scalars + now issue ``FutureWarning`` or ``DeprecationWarning``, and in the + future will be change to either perform elementwise comparisons or + raise an error. +* In ``np.lib.split`` an empty array in the result always had dimension + ``(0,)`` no matter the dimensions of the array being split. In Numpy 1.11 + that behavior will be changed so that the dimensions will be preserved. A + ``FutureWarning`` for this change has been in place since Numpy 1.9 but, + due to a bug, sometimes no warning was raised and the dimensions were + already preserved. +* The SafeEval class will be removed in Numpy 1.11. +* The alterdot and restoredot functions will be removed in Numpy 1.11. + +See below for more details on these changes. + +Compatibility notes +=================== + +Default casting rule change +--------------------------- +Default casting for inplace operations has changed to ``'same_kind'``. For +instance, if n is an array of integers, and f is an array of floats, then +``n += f`` will result in a ``TypeError``, whereas in previous Numpy +versions the floats would be silently cast to ints. In the unlikely case +that the example code is not an actual bug, it can be updated in a backward +compatible way by rewriting it as ``np.add(n, f, out=n, casting='unsafe')``. +The old ``'unsafe'`` default has been deprecated since Numpy 1.7. + +numpy version string +-------------------- +The numpy version string for development builds has been changed from +``x.y.z.dev-githash`` to ``x.y.z.dev0+githash`` (note the +) in order to comply +with PEP 440. + +relaxed stride checking +----------------------- +NPY_RELAXED_STRIDE_CHECKING is now true by default. + +UPDATE: In 1.10.2 the default value of NPY_RELAXED_STRIDE_CHECKING was +changed to false for back compatibility reasons. More time is needed before +it can be made the default. As part of the roadmap a deprecation of +dimension changing views of f_contiguous not c_contiguous arrays was also +added. + +Concatenation of 1d arrays along any but ``axis=0`` raises ``IndexError`` +------------------------------------------------------------------------- +Using axis != 0 has raised a DeprecationWarning since NumPy 1.7, it now +raises an error. + +*np.ravel*, *np.diagonal* and *np.diag* now preserve subtypes +------------------------------------------------------------- +There was inconsistent behavior between *x.ravel()* and *np.ravel(x)*, as +well as between *x.diagonal()* and *np.diagonal(x)*, with the methods +preserving subtypes while the functions did not. This has been fixed and +the functions now behave like the methods, preserving subtypes except in +the case of matrices. Matrices are special cased for backward +compatibility and still return 1-D arrays as before. If you need to +preserve the matrix subtype, use the methods instead of the functions. + +*rollaxis* and *swapaxes* always return a view +---------------------------------------------- +Previously, a view was returned except when no change was made in the order +of the axes, in which case the input array was returned. A view is now +returned in all cases. + +*nonzero* now returns base ndarrays +----------------------------------- +Previously, an inconsistency existed between 1-D inputs (returning a +base ndarray) and higher dimensional ones (which preserved subclasses). +Behavior has been unified, and the return will now be a base ndarray. +Subclasses can still override this behavior by providing their own +*nonzero* method. + +C API +----- +The changes to *swapaxes* also apply to the *PyArray_SwapAxes* C function, +which now returns a view in all cases. + +The changes to *nonzero* also apply to the *PyArray_Nonzero* C function, +which now returns a base ndarray in all cases. + +The dtype structure (PyArray_Descr) has a new member at the end to cache +its hash value. This shouldn't affect any well-written applications. + +The change to the concatenation function DeprecationWarning also affects +PyArray_ConcatenateArrays, + +recarray field return types +--------------------------- +Previously the returned types for recarray fields accessed by attribute and by +index were inconsistent, and fields of string type were returned as chararrays. +Now, fields accessed by either attribute or indexing will return an ndarray for +fields of non-structured type, and a recarray for fields of structured type. +Notably, this affect recarrays containing strings with whitespace, as trailing +whitespace is trimmed from chararrays but kept in ndarrays of string type. +Also, the dtype.type of nested structured fields is now inherited. + +recarray views +-------------- +Viewing an ndarray as a recarray now automatically converts the dtype to +np.record. See new record array documentation. Additionally, viewing a recarray +with a non-structured dtype no longer converts the result's type to ndarray - +the result will remain a recarray. + +'out' keyword argument of ufuncs now accepts tuples of arrays +------------------------------------------------------------- +When using the 'out' keyword argument of a ufunc, a tuple of arrays, one per +ufunc output, can be provided. For ufuncs with a single output a single array +is also a valid 'out' keyword argument. Previously a single array could be +provided in the 'out' keyword argument, and it would be used as the first +output for ufuncs with multiple outputs, is deprecated, and will result in a +`DeprecationWarning` now and an error in the future. + +byte-array indices now raises an IndexError +------------------------------------------- +Indexing an ndarray using a byte-string in Python 3 now raises an IndexError +instead of a ValueError. + +Masked arrays containing objects with arrays +-------------------------------------------- +For such (rare) masked arrays, getting a single masked item no longer returns a +corrupted masked array, but a fully masked version of the item. + +Median warns and returns nan when invalid values are encountered +---------------------------------------------------------------- +Similar to mean, median and percentile now emits a Runtime warning and +returns `NaN` in slices where a `NaN` is present. +To compute the median or percentile while ignoring invalid values use the +new `nanmedian` or `nanpercentile` functions. + +Functions available from numpy.ma.testutils have changed +-------------------------------------------------------- +All functions from numpy.testing were once available from +numpy.ma.testutils but not all of them were redefined to work with masked +arrays. Most of those functions have now been removed from +numpy.ma.testutils with a small subset retained in order to preserve +backward compatibility. In the long run this should help avoid mistaken use +of the wrong functions, but it may cause import problems for some. + + +New Features +============ + +Reading extra flags from site.cfg +--------------------------------- +Previously customization of compilation of dependency libraries and numpy +itself was only accomblishable via code changes in the distutils package. +Now numpy.distutils reads in the following extra flags from each group of the +*site.cfg*: + +* ``runtime_library_dirs/rpath``, sets runtime library directories to override + ``LD_LIBRARY_PATH`` +* ``extra_compile_args``, add extra flags to the compilation of sources +* ``extra_link_args``, add extra flags when linking libraries + +This should, at least partially, complete user customization. + +*np.cbrt* to compute cube root for real floats +---------------------------------------------- +*np.cbrt* wraps the C99 cube root function *cbrt*. +Compared to *np.power(x, 1./3.)* it is well defined for negative real floats +and a bit faster. + +numpy.distutils now allows parallel compilation +----------------------------------------------- +By passing *--parallel=n* or *-j n* to *setup.py build* the compilation of +extensions is now performed in *n* parallel processes. +The parallelization is limited to files within one extension so projects using +Cython will not profit because it builds extensions from single files. + +*genfromtxt* has a new ``max_rows`` argument +-------------------------------------------- +A ``max_rows`` argument has been added to *genfromtxt* to limit the +number of rows read in a single call. Using this functionality, it is +possible to read in multiple arrays stored in a single file by making +repeated calls to the function. + +New function *np.broadcast_to* for invoking array broadcasting +-------------------------------------------------------------- +*np.broadcast_to* manually broadcasts an array to a given shape according to +numpy's broadcasting rules. The functionality is similar to broadcast_arrays, +which in fact has been rewritten to use broadcast_to internally, but only a +single array is necessary. + +New context manager *clear_and_catch_warnings* for testing warnings +------------------------------------------------------------------- +When Python emits a warning, it records that this warning has been emitted in +the module that caused the warning, in a module attribute +``__warningregistry__``. Once this has happened, it is not possible to emit +the warning again, unless you clear the relevant entry in +``__warningregistry__``. This makes is hard and fragile to test warnings, +because if your test comes after another that has already caused the warning, +you will not be able to emit the warning or test it. The context manager +``clear_and_catch_warnings`` clears warnings from the module registry on entry +and resets them on exit, meaning that warnings can be re-raised. + +*cov* has new ``fweights`` and ``aweights`` arguments +----------------------------------------------------- +The ``fweights`` and ``aweights`` arguments add new functionality to +covariance calculations by applying two types of weighting to observation +vectors. An array of ``fweights`` indicates the number of repeats of each +observation vector, and an array of ``aweights`` provides their relative +importance or probability. + +Support for the '@' operator in Python 3.5+ +------------------------------------------- +Python 3.5 adds support for a matrix multiplication operator '@' proposed +in PEP465. Preliminary support for that has been implemented, and an +equivalent function ``matmul`` has also been added for testing purposes and +use in earlier Python versions. The function is preliminary and the order +and number of its optional arguments can be expected to change. + +New argument ``norm`` to fft functions +-------------------------------------- +The default normalization has the direct transforms unscaled and the inverse +transforms are scaled by :math:`1/n`. It is possible to obtain unitary +transforms by setting the keyword argument ``norm`` to ``"ortho"`` (default is +`None`) so that both direct and inverse transforms will be scaled by +:math:`1/\\sqrt{n}`. + + +Improvements +============ + +*np.digitize* using binary search +--------------------------------- +*np.digitize* is now implemented in terms of *np.searchsorted*. This means +that a binary search is used to bin the values, which scales much better +for larger number of bins than the previous linear search. It also removes +the requirement for the input array to be 1-dimensional. + +*np.poly* now casts integer inputs to float +------------------------------------------- +*np.poly* will now cast 1-dimensional input arrays of integer type to double +precision floating point, to prevent integer overflow when computing the monic +polynomial. It is still possible to obtain higher precision results by +passing in an array of object type, filled e.g. with Python ints. + +*np.interp* can now be used with periodic functions +--------------------------------------------------- +*np.interp* now has a new parameter *period* that supplies the period of the +input data *xp*. In such case, the input data is properly normalized to the +given period and one end point is added to each extremity of *xp* in order to +close the previous and the next period cycles, resulting in the correct +interpolation behavior. + +*np.pad* supports more input types for ``pad_width`` and ``constant_values`` +---------------------------------------------------------------------------- +``constant_values`` parameters now accepts NumPy arrays and float values. +NumPy arrays are supported as input for ``pad_width``, and an exception is +raised if its values are not of integral type. + +*np.argmax* and *np.argmin* now support an ``out`` argument +----------------------------------------------------------- +The ``out`` parameter was added to *np.argmax* and *np.argmin* for consistency +with *ndarray.argmax* and *ndarray.argmin*. The new parameter behaves exactly +as it does in those methods. + +More system C99 complex functions detected and used +--------------------------------------------------- +All of the functions ``in complex.h`` are now detected. There are new +fallback implementations of the following functions. + +* npy_ctan, +* npy_cacos, npy_casin, npy_catan +* npy_ccosh, npy_csinh, npy_ctanh, +* npy_cacosh, npy_casinh, npy_catanh + +As a result of these improvements, there will be some small changes in +returned values, especially for corner cases. + +*np.loadtxt* support for the strings produced by the ``float.hex`` method +------------------------------------------------------------------------- +The strings produced by ``float.hex`` look like ``0x1.921fb54442d18p+1``, +so this is not the hex used to represent unsigned integer types. + +*np.isclose* properly handles minimal values of integer dtypes +-------------------------------------------------------------- +In order to properly handle minimal values of integer types, *np.isclose* will +now cast to the float dtype during comparisons. This aligns its behavior with +what was provided by *np.allclose*. + +*np.allclose* uses *np.isclose* internally. +------------------------------------------- +*np.allclose* now uses *np.isclose* internally and inherits the ability to +compare NaNs as equal by setting ``equal_nan=True``. Subclasses, such as +*np.ma.MaskedArray*, are also preserved now. + +*np.genfromtxt* now handles large integers correctly +---------------------------------------------------- +*np.genfromtxt* now correctly handles integers larger than ``2**31-1`` on +32-bit systems and larger than ``2**63-1`` on 64-bit systems (it previously +crashed with an ``OverflowError`` in these cases). Integers larger than +``2**63-1`` are converted to floating-point values. + +*np.load*, *np.save* have pickle backward compatibility flags +------------------------------------------------------------- + +The functions *np.load* and *np.save* have additional keyword +arguments for controlling backward compatibility of pickled Python +objects. This enables Numpy on Python 3 to load npy files containing +object arrays that were generated on Python 2. + +MaskedArray support for more complicated base classes +----------------------------------------------------- +Built-in assumptions that the baseclass behaved like a plain array are being +removed. In particular, setting and getting elements and ranges will respect +baseclass overrides of ``__setitem__`` and ``__getitem__``, and arithmetic +will respect overrides of ``__add__``, ``__sub__``, etc. + +Changes +======= + +dotblas functionality moved to multiarray +----------------------------------------- +The cblas versions of dot, inner, and vdot have been integrated into +the multiarray module. In particular, vdot is now a multiarray function, +which it was not before. + +stricter check of gufunc signature compliance +--------------------------------------------- +Inputs to generalized universal functions are now more strictly checked +against the function's signature: all core dimensions are now required to +be present in input arrays; core dimensions with the same label must have +the exact same size; and output core dimension's must be specified, either +by a same label input core dimension or by a passed-in output array. + +views returned from *np.einsum* are writeable +--------------------------------------------- +Views returned by *np.einsum* will now be writeable whenever the input +array is writeable. + +*np.argmin* skips NaT values +---------------------------- + +*np.argmin* now skips NaT values in datetime64 and timedelta64 arrays, +making it consistent with *np.min*, *np.argmax* and *np.max*. + + +Deprecations +============ + +Array comparisons involving strings or structured dtypes +-------------------------------------------------------- + +Normally, comparison operations on arrays perform elementwise +comparisons and return arrays of booleans. But in some corner cases, +especially involving strings are structured dtypes, NumPy has +historically returned a scalar instead. For example:: + + ### Current behaviour + + np.arange(2) == "foo" + # -> False + + np.arange(2) < "foo" + # -> True on Python 2, error on Python 3 + + np.ones(2, dtype="i4,i4") == np.ones(2, dtype="i4,i4,i4") + # -> False + +Continuing work started in 1.9, in 1.10 these comparisons will now +raise ``FutureWarning`` or ``DeprecationWarning``, and in the future +they will be modified to behave more consistently with other +comparison operations, e.g.:: + + ### Future behaviour + + np.arange(2) == "foo" + # -> array([False, False]) + + np.arange(2) < "foo" + # -> error, strings and numbers are not orderable + + np.ones(2, dtype="i4,i4") == np.ones(2, dtype="i4,i4,i4") + # -> [False, False] + +SafeEval +-------- +The SafeEval class in numpy/lib/utils.py is deprecated and will be removed +in the next release. + +alterdot, restoredot +-------------------- +The alterdot and restoredot functions no longer do anything, and are +deprecated. + +pkgload, PackageLoader +---------------------- +These ways of loading packages are now deprecated. + +bias, ddof arguments to corrcoef +-------------------------------- + +The values for the ``bias`` and ``ddof`` arguments to the ``corrcoef`` +function canceled in the division implied by the correlation coefficient and +so had no effect on the returned values. + +We now deprecate these arguments to ``corrcoef`` and the masked array version +``ma.corrcoef``. + +Because we are deprecating the ``bias`` argument to ``ma.corrcoef``, we also +deprecate the use of the ``allow_masked`` argument as a positional argument, +as its position will change with the removal of ``bias``. ``allow_masked`` +will in due course become a keyword-only argument. + +dtype string representation changes +----------------------------------- +Since 1.6, creating a dtype object from its string representation, e.g. +``'f4'``, would issue a deprecation warning if the size did not correspond +to an existing type, and default to creating a dtype of the default size +for the type. Starting with this release, this will now raise a ``TypeError``. + +The only exception is object dtypes, where both ``'O4'`` and ``'O8'`` will +still issue a deprecation warning. This platform-dependent representation +will raise an error in the next release. + +In preparation for this upcoming change, the string representation of an +object dtype, i.e. ``np.dtype(object).str``, no longer includes the item +size, i.e. will return ``'|O'`` instead of ``'|O4'`` or ``'|O8'`` as +before. diff --git a/doc/release/1.10.1-notes.rst b/doc/release/1.10.1-notes.rst new file mode 100644 index 0000000..4e541d2 --- /dev/null +++ b/doc/release/1.10.1-notes.rst @@ -0,0 +1,42 @@ +========================== +NumPy 1.10.1 Release Notes +========================== + +This release deals with a few build problems that showed up in 1.10.0. Most +users would not have seen these problems. The differences are: + +* Compiling with msvc9 or msvc10 for 32 bit Windows now requires SSE2. + This was the easiest fix for what looked to be some miscompiled code when + SSE2 was not used. If you need to compile for 32 bit Windows systems + without SSE2 support, mingw32 should still work. + +* Make compiling with VS2008 python2.7 SDK easier + +* Change Intel compiler options so that code will also be generated to + support systems without SSE4.2. + +* Some _config test functions needed an explicit integer return in + order to avoid the openSUSE rpmlinter erring out. + +* We ran into a problem with pipy not allowing reuse of filenames and a + resulting proliferation of *.*.*.postN releases. Not only were the names + getting out of hand, some packages were unable to work with the postN + suffix. + + +Numpy 1.10.1 supports Python 2.6 - 2.7 and 3.2 - 3.5. + + +Commits: + +45a3d84 DEP: Remove warning for `full` when dtype is set. +0c1a5df BLD: import setuptools to allow compile with VS2008 python2.7 sdk +04211c6 BUG: mask nan to 1 in ordered compare +826716f DOC: Document the reason msvc requires SSE2 on 32 bit platforms. +49fa187 BLD: enable SSE2 for 32-bit msvc 9 and 10 compilers +dcbc4cc MAINT: remove Wreturn-type warnings from config checks +d6564cb BLD: do not build exclusively for SSE4.2 processors +15cb66f BLD: do not build exclusively for SSE4.2 processors +c38bc08 DOC: fix var. reference in percentile docstring +78497f4 DOC: Sync 1.10.0-notes.rst in 1.10.x branch with master. + diff --git a/doc/release/1.10.2-notes.rst b/doc/release/1.10.2-notes.rst new file mode 100644 index 0000000..8c26b46 --- /dev/null +++ b/doc/release/1.10.2-notes.rst @@ -0,0 +1,158 @@ +========================== +NumPy 1.10.2 Release Notes +========================== + +This release deals with a number of bugs that turned up in 1.10.1 and +adds various build and release improvements. + +Numpy 1.10.1 supports Python 2.6 - 2.7 and 3.2 - 3.5. + + +Compatibility notes +=================== + +Relaxed stride checking is no longer the default +------------------------------------------------ +There were back compatibility problems involving views changing the dtype of +multidimensional Fortran arrays that need to be dealt with over a longer +timeframe. + +Fix swig bug in ``numpy.i`` +--------------------------- +Relaxed stride checking revealed a bug in ``array_is_fortran(a)``, that was +using PyArray_ISFORTRAN to check for Fortran contiguity instead of +PyArray_IS_F_CONTIGUOUS. You may want to regenerate swigged files using the +updated numpy.i + +Deprecate views changing dimensions in fortran order +---------------------------------------------------- +This deprecates assignment of a new descriptor to the dtype attribute of +a non-C-contiguous array if it result in changing the shape. This +effectively bars viewing a multidimensional Fortran array using a dtype +that changes the element size along the first axis. + +The reason for the deprecation is that, when relaxed strides checking is +enabled, arrays that are both C and Fortran contiguous are always treated +as C contiguous which breaks some code that depended the two being mutually +exclusive for non-scalar arrays of ndim > 1. This deprecation prepares the +way to always enable relaxed stride checking. + + +Issues Fixed +============ + +* gh-6019 Masked array repr fails for structured array with multi-dimensional column. +* gh-6462 Median of empty array produces IndexError. +* gh-6467 Performance regression for record array access. +* gh-6468 numpy.interp uses 'left' value even when x[0]==xp[0]. +* gh-6475 np.allclose returns a memmap when one of its arguments is a memmap. +* gh-6491 Error in broadcasting stride_tricks array. +* gh-6495 Unrecognized command line option '-ffpe-summary' in gfortran. +* gh-6497 Failure of reduce operation on recarrays. +* gh-6498 Mention change in default casting rule in 1.10 release notes. +* gh-6530 The partition function errors out on empty input. +* gh-6532 numpy.inner return wrong inaccurate value sometimes. +* gh-6563 Intent(out) broken in recent versions of f2py. +* gh-6569 Cannot run tests after 'python setup.py build_ext -i' +* gh-6572 Error in broadcasting stride_tricks array component. +* gh-6575 BUG: Split produces empty arrays with wrong number of dimensions +* gh-6590 Fortran Array problem in numpy 1.10. +* gh-6602 Random __all__ missing choice and dirichlet. +* gh-6611 ma.dot no longer always returns a masked array in 1.10. +* gh-6618 NPY_FORTRANORDER in make_fortran() in numpy.i +* gh-6636 Memory leak in nested dtypes in numpy.recarray +* gh-6641 Subsetting recarray by fields yields a structured array. +* gh-6667 ma.make_mask handles ma.nomask input incorrectly. +* gh-6675 Optimized blas detection broken in master and 1.10. +* gh-6678 Getting unexpected error from: X.dtype = complex (or Y = X.view(complex)) +* gh-6718 f2py test fail in pip installed numpy-1.10.1 in virtualenv. +* gh-6719 Error compiling Cython file: Pythonic division not allowed without gil. +* gh-6771 Numpy.rec.fromarrays losing dtype metadata between versions 1.9.2 and 1.10.1 +* gh-6781 The travis-ci script in maintenance/1.10.x needs fixing. +* gh-6807 Windows testing errors for 1.10.2 + + +Merged PRs +========== + +The following PRs have been merged into 1.10.2. When the PR is a backport, +the PR number for the original PR against master is listed. + +* gh-5773 MAINT: Hide testing helper tracebacks when using them with pytest. +* gh-6094 BUG: Fixed a bug with string representation of masked structured arrays. +* gh-6208 MAINT: Speedup field access by removing unneeded safety checks. +* gh-6460 BUG: Replacing the os.environ.clear by less invasive procedure. +* gh-6470 BUG: Fix AttributeError in numpy distutils. +* gh-6472 MAINT: Use Python 3.5 instead of 3.5-dev for travis 3.5 testing. +* gh-6474 REL: Update Paver script for sdist and auto-switch test warnings. +* gh-6478 BUG: Fix Intel compiler flags for OS X build. +* gh-6481 MAINT: LIBPATH with spaces is now supported Python 2.7+ and Win32. +* gh-6487 BUG: Allow nested use of parameters in definition of arrays in f2py. +* gh-6488 BUG: Extend common blocks rather than overwriting in f2py. +* gh-6499 DOC: Mention that default casting for inplace operations has changed. +* gh-6500 BUG: Recarrays viewed as subarrays don't convert to np.record type. +* gh-6501 REL: Add "make upload" command for built docs, update "make dist". +* gh-6526 BUG: Fix use of __doc__ in setup.py for -OO mode. +* gh-6527 BUG: Fix the IndexError when taking the median of an empty array. +* gh-6537 BUG: Make ma.atleast_* with scalar argument return arrays. +* gh-6538 BUG: Fix ma.masked_values does not shrink mask if requested. +* gh-6546 BUG: Fix inner product regression for non-contiguous arrays. +* gh-6553 BUG: Fix partition and argpartition error for empty input. +* gh-6556 BUG: Error in broadcast_arrays with as_strided array. +* gh-6558 MAINT: Minor update to "make upload" doc build command. +* gh-6562 BUG: Disable view safety checks in recarray. +* gh-6567 BUG: Revert some import * fixes in f2py. +* gh-6574 DOC: Release notes for Numpy 1.10.2. +* gh-6577 BUG: Fix for #6569, allowing build_ext --inplace +* gh-6579 MAINT: Fix mistake in doc upload rule. +* gh-6596 BUG: Fix swig for relaxed stride checking. +* gh-6606 DOC: Update 1.10.2 release notes. +* gh-6614 BUG: Add choice and dirichlet to numpy.random.__all__. +* gh-6621 BUG: Fix swig make_fortran function. +* gh-6628 BUG: Make allclose return python bool. +* gh-6642 BUG: Fix memleak in _convert_from_dict. +* gh-6643 ENH: make recarray.getitem return a recarray. +* gh-6653 BUG: Fix ma dot to always return masked array. +* gh-6668 BUG: ma.make_mask should always return nomask for nomask argument. +* gh-6686 BUG: Fix a bug in assert_string_equal. +* gh-6695 BUG: Fix removing tempdirs created during build. +* gh-6697 MAINT: Fix spurious semicolon in macro definition of PyArray_FROM_OT. +* gh-6698 TST: test np.rint bug for large integers. +* gh-6717 BUG: Readd fallback CBLAS detection on linux. +* gh-6721 BUG: Fix for #6719. +* gh-6726 BUG: Fix bugs exposed by relaxed stride rollback. +* gh-6757 BUG: link cblas library if cblas is detected. +* gh-6756 TST: only test f2py, not f2py2.7 etc, fixes #6718. +* gh-6747 DEP: Deprecate changing shape of non-C-contiguous array via descr. +* gh-6775 MAINT: Include from __future__ boilerplate in some files missing it. +* gh-6780 BUG: metadata is not copied to base_dtype. +* gh-6783 BUG: Fix travis ci testing for new google infrastructure. +* gh-6785 BUG: Quick and dirty fix for interp. +* gh-6813 TST,BUG: Make test_mvoid_multidim_print work for 32 bit systems. +* gh-6817 BUG: Disable 32-bit msvc9 compiler optimizations for npy_rint. +* gh-6819 TST: Fix test_mvoid_multidim_print failures on Python 2.x for Windows. + +Initial support for mingwpy was reverted as it was causing problems for +non-windows builds. + +* gh-6536 BUG: Revert gh-5614 to fix non-windows build problems + +A fix for np.lib.split was reverted because it resulted in "fixing" +behavior that will be present in the Numpy 1.11 and that was already +present in Numpy 1.9. See the discussion of the issue at gh-6575 for +clarification. + +* gh-6576 BUG: Revert gh-6376 to fix split behavior for empty arrays. + +Relaxed stride checking was reverted. There were back compatibility +problems involving views changing the dtype of multidimensional Fortran +arrays that need to be dealt with over a longer timeframe. + +* gh-6735 MAINT: Make no relaxed stride checking the default for 1.10. + + +Notes +===== +A bug in the Numpy 1.10.1 release resulted in exceptions being raised for +``RuntimeWarning`` and ``DeprecationWarning`` in projects depending on Numpy. +That has been fixed. diff --git a/doc/release/1.10.3-notes.rst b/doc/release/1.10.3-notes.rst new file mode 100644 index 0000000..0d4df4c --- /dev/null +++ b/doc/release/1.10.3-notes.rst @@ -0,0 +1,5 @@ +========================== +NumPy 1.10.3 Release Notes +========================== + +N/A this release did not happen due to various screwups involving PyPi. diff --git a/doc/release/1.10.4-notes.rst b/doc/release/1.10.4-notes.rst new file mode 100644 index 0000000..481928c --- /dev/null +++ b/doc/release/1.10.4-notes.rst @@ -0,0 +1,40 @@ +========================== +NumPy 1.10.4 Release Notes +========================== + +This release is a bugfix source release motivated by a segfault regression. +No windows binaries are provided for this release, as there appear to be +bugs in the toolchain we use to generate those files. Hopefully that +problem will be fixed for the next release. In the meantime, we suggest +using one of the providers of windows binaries. + +Compatibility notes +=================== + +* The trace function now calls the trace method on subclasses of ndarray, + except for matrix, for which the current behavior is preserved. This is + to help with the units package of AstroPy and hopefully will not cause + problems. + +Issues Fixed +============ + +* gh-6922 BUG: numpy.recarray.sort segfaults on Windows. +* gh-6937 BUG: busday_offset does the wrong thing with modifiedpreceding roll. +* gh-6949 BUG: Type is lost when slicing a subclass of recarray. + +Merged PRs +========== + +The following PRs have been merged into 1.10.4. When the PR is a backport, +the PR number for the original PR against master is listed. + +* gh-6840 TST: Update travis testing script in 1.10.x +* gh-6843 BUG: Fix use of python 3 only FileNotFoundError in test_f2py. +* gh-6884 REL: Update pavement.py and setup.py to reflect current version. +* gh-6916 BUG: Fix test_f2py so it runs correctly in runtests.py. +* gh-6924 BUG: Fix segfault gh-6922. +* gh-6942 Fix datetime roll='modifiedpreceding' bug. +* gh-6943 DOC,BUG: Fix some latex generation problems. +* gh-6950 BUG trace is not subclass aware, np.trace(ma) != ma.trace(). +* gh-6952 BUG recarray slices should preserve subclass. diff --git a/doc/release/1.11.0-notes.rst b/doc/release/1.11.0-notes.rst new file mode 100644 index 0000000..b1dd241 --- /dev/null +++ b/doc/release/1.11.0-notes.rst @@ -0,0 +1,393 @@ +========================== +NumPy 1.11.0 Release Notes +========================== + +This release supports Python 2.6 - 2.7 and 3.2 - 3.5 and contains a number +of enhancements and improvements. Note also the build system changes listed +below as they may have subtle effects. + +No Windows (TM) binaries are provided for this release due to a broken +toolchain. One of the providers of Python packages for Windows (TM) is your +best bet. + + +Highlights +========== + +Details of these improvements can be found below. + +* The datetime64 type is now timezone naive. +* A dtype parameter has been added to ``randint``. +* Improved detection of two arrays possibly sharing memory. +* Automatic bin size estimation for ``np.histogram``. +* Speed optimization of A @ A.T and dot(A, A.T). +* New function ``np.moveaxis`` for reordering array axes. + + +Build System Changes +==================== + +* Numpy now uses ``setuptools`` for its builds instead of plain distutils. + This fixes usage of ``install_requires='numpy'`` in the ``setup.py`` files of + projects that depend on Numpy (see gh-6551). It potentially affects the way + that build/install methods for Numpy itself behave though. Please report any + unexpected behavior on the Numpy issue tracker. +* Bento build support and related files have been removed. +* Single file build support and related files have been removed. + + +Future Changes +============== + +The following changes are scheduled for Numpy 1.12.0. + +* Support for Python 2.6, 3.2, and 3.3 will be dropped. +* Relaxed stride checking will become the default. See the 1.8.0 release + notes for a more extended discussion of what this change implies. +* The behavior of the datetime64 "not a time" (NaT) value will be changed + to match that of floating point "not a number" (NaN) values: all + comparisons involving NaT will return False, except for NaT != NaT which + will return True. +* Indexing with floats will raise IndexError, + e.g., a[0, 0.0]. +* Indexing with non-integer array_like will raise ``IndexError``, + e.g., ``a['1', '2']`` +* Indexing with multiple ellipsis will raise ``IndexError``, + e.g., ``a[..., ...]``. +* Non-integers used as index values will raise ``TypeError``, + e.g., in ``reshape``, ``take``, and specifying reduce axis. + + +In a future release the following changes will be made. + +* The ``rand`` function exposed in ``numpy.testing`` will be removed. That + function is left over from early Numpy and was implemented using the + Python random module. The random number generators from ``numpy.random`` + should be used instead. +* The ``ndarray.view`` method will only allow c_contiguous arrays to be + viewed using a dtype of different size causing the last dimension to + change. That differs from the current behavior where arrays that are + f_contiguous but not c_contiguous can be viewed as a dtype type of + different size causing the first dimension to change. +* Slicing a ``MaskedArray`` will return views of both data **and** mask. + Currently the mask is copy-on-write and changes to the mask in the slice do + not propagate to the original mask. See the FutureWarnings section below for + details. + + +Compatibility notes +=================== + +datetime64 changes +------------------ +In prior versions of NumPy the experimental datetime64 type always stored +times in UTC. By default, creating a datetime64 object from a string or +printing it would convert from or to local time:: + + # old behavior + >>>> np.datetime64('2000-01-01T00:00:00') + numpy.datetime64('2000-01-01T00:00:00-0800') # note the timezone offset -08:00 + + +A consensus of datetime64 users agreed that this behavior is undesirable +and at odds with how datetime64 is usually used (e.g., by `pandas +`__). For most use cases, a timezone naive datetime +type is preferred, similar to the ``datetime.datetime`` type in the Python +standard library. Accordingly, datetime64 no longer assumes that input is in +local time, nor does it print local times:: + + >>>> np.datetime64('2000-01-01T00:00:00') + numpy.datetime64('2000-01-01T00:00:00') + +For backwards compatibility, datetime64 still parses timezone offsets, which +it handles by converting to UTC. However, the resulting datetime is timezone +naive:: + + >>> np.datetime64('2000-01-01T00:00:00-08') + DeprecationWarning: parsing timezone aware datetimes is deprecated; + this will raise an error in the future + numpy.datetime64('2000-01-01T08:00:00') + +As a corollary to this change, we no longer prohibit casting between datetimes +with date units and datetimes with time units. With timezone naive datetimes, +the rule for casting from dates to times is no longer ambiguous. + +``linalg.norm`` return type changes +----------------------------------- +The return type of the ``linalg.norm`` function is now floating point without +exception. Some of the norm types previously returned integers. + +polynomial fit changes +---------------------- +The various fit functions in the numpy polynomial package no longer accept +non-integers for degree specification. + +*np.dot* now raises ``TypeError`` instead of ``ValueError`` +----------------------------------------------------------- +This behaviour mimics that of other functions such as ``np.inner``. If the two +arguments cannot be cast to a common type, it could have raised a ``TypeError`` +or ``ValueError`` depending on their order. Now, ``np.dot`` will now always +raise a ``TypeError``. + +FutureWarning to changed behavior +--------------------------------- + +* In ``np.lib.split`` an empty array in the result always had dimension + ``(0,)`` no matter the dimensions of the array being split. This + has been changed so that the dimensions will be preserved. A + ``FutureWarning`` for this change has been in place since Numpy 1.9 but, + due to a bug, sometimes no warning was raised and the dimensions were + already preserved. + +``%`` and ``//`` operators +-------------------------- +These operators are implemented with the ``remainder`` and ``floor_divide`` +functions respectively. Those functions are now based around ``fmod`` and are +computed together so as to be compatible with each other and with the Python +versions for float types. The results should be marginally more accurate or +outright bug fixes compared to the previous results, but they may +differ significantly in cases where roundoff makes a difference in the integer +returned by ``floor_divide``. Some corner cases also change, for instance, NaN +is always returned for both functions when the divisor is zero, +``divmod(1.0, inf)`` returns ``(0.0, 1.0)`` except on MSVC 2008, and +``divmod(-1.0, inf)`` returns ``(-1.0, inf)``. + +C API +----- + +Removed the ``check_return`` and ``inner_loop_selector`` members of +the ``PyUFuncObject`` struct (replacing them with ``reserved`` slots +to preserve struct layout). These were never used for anything, so +it's unlikely that any third-party code is using them either, but we +mention it here for completeness. + + +object dtype detection for old-style classes +-------------------------------------------- + +In python 2, objects which are instances of old-style user-defined classes no +longer automatically count as 'object' type in the dtype-detection handler. +Instead, as in python 3, they may potentially count as sequences, but only if +they define both a `__len__` and a `__getitem__` method. This fixes a segfault +and inconsistency between python 2 and 3. + +New Features +============ + +* ``np.histogram`` now provides plugin estimators for automatically + estimating the optimal number of bins. Passing one of ['auto', 'fd', + 'scott', 'rice', 'sturges'] as the argument to 'bins' results in the + corresponding estimator being used. + +* A benchmark suite using `Airspeed Velocity + `__ has been added, converting the + previous vbench-based one. You can run the suite locally via ``python + runtests.py --bench``. For more details, see ``benchmarks/README.rst``. + +* A new function ``np.shares_memory`` that can check exactly whether two + arrays have memory overlap is added. ``np.may_share_memory`` also now has + an option to spend more effort to reduce false positives. + +* ``SkipTest`` and ``KnownFailureException`` exception classes are exposed + in the ``numpy.testing`` namespace. Raise them in a test function to mark + the test to be skipped or mark it as a known failure, respectively. + +* ``f2py.compile`` has a new ``extension`` keyword parameter that allows the + fortran extension to be specified for generated temp files. For instance, + the files can be specifies to be ``*.f90``. The ``verbose`` argument is + also activated, it was previously ignored. + +* A ``dtype`` parameter has been added to ``np.random.randint`` + Random ndarrays of the following types can now be generated: + + - ``np.bool``, + - ``np.int8``, ``np.uint8``, + - ``np.int16``, ``np.uint16``, + - ``np.int32``, ``np.uint32``, + - ``np.int64``, ``np.uint64``, + - ``np.int_ ``, ``np.intp`` + + The specification is by precision rather than by C type. Hence, on some + platforms ``np.int64`` may be a ``long`` instead of ``long long`` even if + the specified dtype is ``long long`` because the two may have the same + precision. The resulting type depends on which C type numpy uses for the + given precision. The byteorder specification is also ignored, the + generated arrays are always in native byte order. + +* A new ``np.moveaxis`` function allows for moving one or more array axes + to a new position by explicitly providing source and destination axes. + This function should be easier to use than the current ``rollaxis`` + function as well as providing more functionality. + +* The ``deg`` parameter of the various ``numpy.polynomial`` fits has been + extended to accept a list of the degrees of the terms to be included in + the fit, the coefficients of all other terms being constrained to zero. + The change is backward compatible, passing a scalar ``deg`` will behave + as before. + +* A divmod function for float types modeled after the Python version has + been added to the npy_math library. + + +Improvements +============ + +``np.gradient`` now supports an ``axis`` argument +------------------------------------------------- +The ``axis`` parameter was added to ``np.gradient`` for consistency. It +allows to specify over which axes the gradient is calculated. + +``np.lexsort`` now supports arrays with object data-type +-------------------------------------------------------- +The function now internally calls the generic ``npy_amergesort`` when the +type does not implement a merge-sort kind of ``argsort`` method. + +``np.ma.core.MaskedArray`` now supports an ``order`` argument +------------------------------------------------------------- +When constructing a new ``MaskedArray`` instance, it can be configured with +an ``order`` argument analogous to the one when calling ``np.ndarray``. The +addition of this argument allows for the proper processing of an ``order`` +argument in several MaskedArray-related utility functions such as +``np.ma.core.array`` and ``np.ma.core.asarray``. + +Memory and speed improvements for masked arrays +----------------------------------------------- +Creating a masked array with ``mask=True`` (resp. ``mask=False``) now uses +``np.ones`` (resp. ``np.zeros``) to create the mask, which is faster and +avoid a big memory peak. Another optimization was done to avoid a memory +peak and useless computations when printing a masked array. + +``ndarray.tofile`` now uses fallocate on linux +---------------------------------------------- +The function now uses the fallocate system call to reserve sufficient +disk space on file systems that support it. + +Optimizations for operations of the form ``A.T @ A`` and ``A @ A.T`` +-------------------------------------------------------------------- +Previously, ``gemm`` BLAS operations were used for all matrix products. Now, +if the matrix product is between a matrix and its transpose, it will use +``syrk`` BLAS operations for a performance boost. This optimization has been +extended to ``@``, ``numpy.dot``, ``numpy.inner``, and ``numpy.matmul``. + +**Note:** Requires the transposed and non-transposed matrices to share data. + +``np.testing.assert_warns`` can now be used as a context manager +---------------------------------------------------------------- +This matches the behavior of ``assert_raises``. + +Speed improvement for np.random.shuffle +--------------------------------------- +``np.random.shuffle`` is now much faster for 1d ndarrays. + + +Changes +======= + +Pyrex support was removed from ``numpy.distutils`` +-------------------------------------------------- +The method ``build_src.generate_a_pyrex_source`` will remain available; it +has been monkeypatched by users to support Cython instead of Pyrex. It's +recommended to switch to a better supported method of build Cython +extensions though. + +``np.broadcast`` can now be called with a single argument +--------------------------------------------------------- +The resulting object in that case will simply mimic iteration over +a single array. This change obsoletes distinctions like + + if len(x) == 1: + shape = x[0].shape + else: + shape = np.broadcast(\*x).shape + +Instead, ``np.broadcast`` can be used in all cases. + +``np.trace`` now respects array subclasses +------------------------------------------ +This behaviour mimics that of other functions such as ``np.diagonal`` and +ensures, e.g., that for masked arrays ``np.trace(ma)`` and ``ma.trace()`` give +the same result. + +``np.dot`` now raises ``TypeError`` instead of ``ValueError`` +------------------------------------------------------------- +This behaviour mimics that of other functions such as ``np.inner``. If the two +arguments cannot be cast to a common type, it could have raised a ``TypeError`` +or ``ValueError`` depending on their order. Now, ``np.dot`` will now always +raise a ``TypeError``. + +``linalg.norm`` return type changes +----------------------------------- +The ``linalg.norm`` function now does all its computations in floating point +and returns floating results. This change fixes bugs due to integer overflow +and the failure of abs with signed integers of minimum value, e.g., int8(-128). +For consistancy, floats are used even where an integer might work. + + +Deprecations +============ + +Views of arrays in Fortran order +-------------------------------- +The F_CONTIGUOUS flag was used to signal that views using a dtype that +changed the element size would change the first index. This was always +problematical for arrays that were both F_CONTIGUOUS and C_CONTIGUOUS +because C_CONTIGUOUS took precedence. Relaxed stride checking results in +more such dual contiguous arrays and breaks some existing code as a result. +Note that this also affects changing the dtype by assigning to the dtype +attribute of an array. The aim of this deprecation is to restrict views to +C_CONTIGUOUS arrays at some future time. A work around that is backward +compatible is to use ``a.T.view(...).T`` instead. A parameter may also be +added to the view method to explicitly ask for Fortran order views, but +that will not be backward compatible. + +Invalid arguments for array ordering +------------------------------------ +It is currently possible to pass in arguments for the ``order`` +parameter in methods like ``array.flatten`` or ``array.ravel`` +that were not one of the following: 'C', 'F', 'A', 'K' (note that +all of these possible values are both unicode and case insensitive). +Such behavior will not be allowed in future releases. + +Random number generator in the ``testing`` namespace +---------------------------------------------------- +The Python standard library random number generator was previously exposed +in the ``testing`` namespace as ``testing.rand``. Using this generator is +not recommended and it will be removed in a future release. Use generators +from ``numpy.random`` namespace instead. + +Random integer generation on a closed interval +---------------------------------------------- +In accordance with the Python C API, which gives preference to the half-open +interval over the closed one, ``np.random.random_integers`` is being +deprecated in favor of calling ``np.random.randint``, which has been +enhanced with the ``dtype`` parameter as described under "New Features". +However, ``np.random.random_integers`` will not be removed anytime soon. + + +FutureWarnings +============== + +Assigning to slices/views of ``MaskedArray`` +-------------------------------------------- +Currently a slice of a masked array contains a view of the original data and a +copy-on-write view of the mask. Consequently, any changes to the slice's mask +will result in a copy of the original mask being made and that new mask being +changed rather than the original. For example, if we make a slice of the +original like so, ``view = original[:]``, then modifications to the data in one +array will affect the data of the other but, because the mask will be copied +during assignment operations, changes to the mask will remain local. A similar +situation occurs when explicitly constructing a masked array using +``MaskedArray(data, mask)``, the returned array will contain a view of ``data`` +but the mask will be a copy-on-write view of ``mask``. + +In the future, these cases will be normalized so that the data and mask arrays +are treated the same way and modifications to either will propagate between +views. In 1.11, numpy will issue a ``MaskedArrayFutureWarning`` warning +whenever user code modifies the mask of a view that in the future may cause +values to propagate back to the original. To silence these warnings and make +your code robust against the upcoming changes, you have two options: if you +want to keep the current behavior, call ``masked_view.unshare_mask()`` before +modifying the mask. If you want to get the future behavior early, use +``masked_view._sharedmask = False``. However, note that setting the +``_sharedmask`` attribute will break following explicit calls to +``masked_view.unshare_mask()``. diff --git a/doc/release/1.11.1-notes.rst b/doc/release/1.11.1-notes.rst new file mode 100644 index 0000000..6303c32 --- /dev/null +++ b/doc/release/1.11.1-notes.rst @@ -0,0 +1,32 @@ +========================== +NumPy 1.11.1 Release Notes +========================== + +Numpy 1.11.1 supports Python 2.6 - 2.7 and 3.2 - 3.5. It fixes bugs and +regressions found in Numpy 1.11.0 and includes several build related +improvements. Wheels for Linux, Windows, and OSX can be found on pypi. + +Fixes Merged +============ + +- #7506 BUG: Make sure numpy imports on python 2.6 when nose is unavailable. +- #7530 BUG: Floating exception with invalid axis in np.lexsort. +- #7535 BUG: Extend glibc complex trig functions blacklist to glibc < 2.18. +- #7551 BUG: Allow graceful recovery for no compiler. +- #7558 BUG: Constant padding expected wrong type in constant_values. +- #7578 BUG: Fix OverflowError in Python 3.x. in swig interface. +- #7590 BLD: Fix configparser.InterpolationSyntaxError. +- #7597 BUG: Make np.ma.take work on scalars. +- #7608 BUG: linalg.norm(): Don't convert object arrays to float. +- #7638 BLD: Correct C compiler customization in system_info.py. +- #7654 BUG: ma.median of 1d array should return a scalar. +- #7656 BLD: Remove hardcoded Intel compiler flag -xSSE4.2. +- #7660 BUG: Temporary fix for str(mvoid) for object field types. +- #7665 BUG: Fix incorrect printing of 1D masked arrays. +- #7670 BUG: Correct initial index estimate in histogram. +- #7671 BUG: Boolean assignment no GIL release when transfer needs API. +- #7676 BUG: Fix handling of right edge of final histogram bin. +- #7680 BUG: Fix np.clip bug NaN handling for Visual Studio 2015. +- #7724 BUG: Fix segfaults in np.random.shuffle. +- #7731 MAINT: Change mkl_info.dir_env_var from MKL to MKLROOT. +- #7737 BUG: Fix issue on OS X with Python 3.x, npymath.ini not installed. diff --git a/doc/release/1.11.2-notes.rst b/doc/release/1.11.2-notes.rst new file mode 100644 index 0000000..c954089 --- /dev/null +++ b/doc/release/1.11.2-notes.rst @@ -0,0 +1,40 @@ +========================== +NumPy 1.11.2 Release Notes +========================== + +Numpy 1.11.2 supports Python 2.6 - 2.7 and 3.2 - 3.5. It fixes bugs and +regressions found in Numpy 1.11.1 and includes several build related +improvements. Wheels for Linux, Windows, and OS X can be found on PyPI. + +Pull Requests Merged +==================== + +Fixes overridden by later merges and release notes updates are omitted. + +- #7736 BUG: Many functions silently drop 'keepdims' kwarg. +- #7738 ENH: Add extra kwargs and update doc of many MA methods. +- #7778 DOC: Update Numpy 1.11.1 release notes. +- #7793 BUG: MaskedArray.count treats negative axes incorrectly. +- #7816 BUG: Fix array too big error for wide dtypes. +- #7821 BUG: Make sure npy_mul_with_overflow_ detects overflow. +- #7824 MAINT: Allocate fewer bytes for empty arrays. +- #7847 MAINT,DOC: Fix some imp module uses and update f2py.compile docstring. +- #7849 MAINT: Fix remaining uses of deprecated Python imp module. +- #7851 BLD: Fix ATLAS version detection. +- #7896 BUG: Construct ma.array from np.array which contains padding. +- #7904 BUG: Fix float16 type not being called due to wrong ordering. +- #7917 BUG: Production install of numpy should not require nose. +- #7919 BLD: Fixed MKL detection for recent versions of this library. +- #7920 BUG: Fix for issue #7835 (ma.median of 1d). +- #7932 BUG: Monkey-patch _msvccompile.gen_lib_option like other compilers. +- #7939 BUG: Check for HAVE_LDOUBLE_DOUBLE_DOUBLE_LE in npy_math_complex. +- #7953 BUG: Guard against buggy comparisons in generic quicksort. +- #7954 BUG: Use keyword arguments to initialize Extension base class. +- #7955 BUG: Make sure numpy globals keep identity after reload. +- #7972 BUG: MSVCCompiler grows 'lib' & 'include' env strings exponentially. +- #8005 BLD: Remove __NUMPY_SETUP__ from builtins at end of setup.py. +- #8010 MAINT: Remove leftover imp module imports. +- #8020 BUG: Fix return of np.ma.count if keepdims is True and axis is None. +- #8024 BUG: Fix numpy.ma.median. +- #8031 BUG: Fix np.ma.median with only one non-masked value. +- #8044 BUG: Fix bug in NpyIter buffering with discontinuous arrays. diff --git a/doc/release/1.11.3-notes.rst b/doc/release/1.11.3-notes.rst new file mode 100644 index 0000000..8381a97 --- /dev/null +++ b/doc/release/1.11.3-notes.rst @@ -0,0 +1,25 @@ +========================== +NumPy 1.11.3 Release Notes +========================== + +Numpy 1.11.3 fixes a bug that leads to file corruption when very large files +opened in append mode are used in ``ndarray.tofile``. It supports Python +versions 2.6 - 2.7 and 3.2 - 3.5. Wheels for Linux, Windows, and OS X can be +found on PyPI. + + +Contributors to maintenance/1.11.3 +================================== + +A total of 2 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +- Charles Harris +- Pavel Potocek + + +Pull Requests Merged +==================== + +- `#8341 `__: BUG: Fix ndarray.tofile large file corruption in append mode. +- `#8346 `__: TST: Fix tests in PR #8341 for NumPy 1.11.x + diff --git a/doc/release/1.12.0-notes.rst b/doc/release/1.12.0-notes.rst new file mode 100644 index 0000000..229593e --- /dev/null +++ b/doc/release/1.12.0-notes.rst @@ -0,0 +1,495 @@ +========================== +NumPy 1.12.0 Release Notes +========================== + +This release supports Python 2.7 and 3.4 - 3.6. + +Highlights +========== +The NumPy 1.12.0 release contains a large number of fixes and improvements, but +few that stand out above all others. That makes picking out the highlights +somewhat arbitrary but the following may be of particular interest or indicate +areas likely to have future consequences. + +* Order of operations in ``np.einsum`` can now be optimized for large speed improvements. +* New ``signature`` argument to ``np.vectorize`` for vectorizing with core dimensions. +* The ``keepdims`` argument was added to many functions. +* New context manager for testing warnings +* Support for BLIS in numpy.distutils +* Much improved support for PyPy (not yet finished) + +Dropped Support +=============== + +* Support for Python 2.6, 3.2, and 3.3 has been dropped. + + +Added Support +============= + +* Support for PyPy 2.7 v5.6.0 has been added. While not complete (nditer + ``updateifcopy`` is not supported yet), this is a milestone for PyPy's + C-API compatibility layer. + + +Build System Changes +==================== + +* Library order is preserved, instead of being reordered to match that of + the directories. + + +Deprecations +============ + +Assignment of ndarray object's ``data`` attribute +------------------------------------------------- +Assigning the 'data' attribute is an inherently unsafe operation as pointed +out in gh-7083. Such a capability will be removed in the future. + +Unsafe int casting of the num attribute in ``linspace`` +------------------------------------------------------- +``np.linspace`` now raises DeprecationWarning when num cannot be safely +interpreted as an integer. + +Insufficient bit width parameter to ``binary_repr`` +--------------------------------------------------- +If a 'width' parameter is passed into ``binary_repr`` that is insufficient to +represent the number in base 2 (positive) or 2's complement (negative) form, +the function used to silently ignore the parameter and return a representation +using the minimal number of bits needed for the form in question. Such behavior +is now considered unsafe from a user perspective and will raise an error in the +future. + + +Future Changes +============== + +* In 1.13 NAT will always compare False except for ``NAT != NAT``, + which will be True. In short, NAT will behave like NaN +* In 1.13 ``np.average`` will preserve subclasses, to match the behavior of most + other numpy functions such as np.mean. In particular, this means calls which + returned a scalar may return a 0-d subclass object instead. + +Multiple-field manipulation of structured arrays +------------------------------------------------ +In 1.13 the behavior of structured arrays involving multiple fields will change +in two ways: + +First, indexing a structured array with multiple fields (eg, +``arr[['f1', 'f3']]``) will return a view into the original array in 1.13, +instead of a copy. Note the returned view will have extra padding bytes +corresponding to intervening fields in the original array, unlike the copy in +1.12, which will affect code such as ``arr[['f1', 'f3']].view(newdtype)``. + +Second, for numpy versions 1.6 to 1.12 assignment between structured arrays +occurs "by field name": Fields in the destination array are set to the +identically-named field in the source array or to 0 if the source does not have +a field:: + + >>> a = np.array([(1,2),(3,4)], dtype=[('x', 'i4'), ('y', 'i4')]) + >>> b = np.ones(2, dtype=[('z', 'i4'), ('y', 'i4'), ('x', 'i4')]) + >>> b[:] = a + >>> b + array([(0, 2, 1), (0, 4, 3)], + dtype=[('z', '`. This allows +for vectorizing a much broader class of functions. For example, an arbitrary +distance metric that combines two vectors to produce a scalar could be +vectorized with ``signature='(n),(n)->()'``. See ``np.vectorize`` for full +details. + +Emit py3kwarnings for division of integer arrays +------------------------------------------------ +To help people migrate their code bases from Python 2 to Python 3, the +python interpreter has a handy option -3, which issues warnings at runtime. +One of its warnings is for integer division:: + + $ python -3 -c "2/3" + + -c:1: DeprecationWarning: classic int division + +In Python 3, the new integer division semantics also apply to numpy arrays. +With this version, numpy will emit a similar warning:: + + $ python -3 -c "import numpy as np; np.array(2)/np.array(3)" + + -c:1: DeprecationWarning: numpy: classic int division + +numpy.sctypes now includes bytes on Python3 too +----------------------------------------------- +Previously, it included str (bytes) and unicode on Python2, but only str +(unicode) on Python3. + + +Improvements +============ + +``bitwise_and`` identity changed +-------------------------------- +The previous identity was 1 with the result that all bits except the LSB were +masked out when the reduce method was used. The new identity is -1, which +should work properly on twos complement machines as all bits will be set to +one. + +Generalized Ufuncs will now unlock the GIL +------------------------------------------ +Generalized Ufuncs, including most of the linalg module, will now unlock +the Python global interpreter lock. + +Caches in `np.fft` are now bounded in total size and item count +--------------------------------------------------------------- +The caches in `np.fft` that speed up successive FFTs of the same length can no +longer grow without bounds. They have been replaced with LRU (least recently +used) caches that automatically evict no longer needed items if either the +memory size or item count limit has been reached. + +Improved handling of zero-width string/unicode dtypes +----------------------------------------------------- +Fixed several interfaces that explicitly disallowed arrays with zero-width +string dtypes (i.e. ``dtype('S0')`` or ``dtype('U0')``, and fixed several +bugs where such dtypes were not handled properly. In particular, changed +``ndarray.__new__`` to not implicitly convert ``dtype('S0')`` to +``dtype('S1')`` (and likewise for unicode) when creating new arrays. + +Integer ufuncs vectorized with AVX2 +----------------------------------- +If the cpu supports it at runtime the basic integer ufuncs now use AVX2 +instructions. This feature is currently only available when compiled with GCC. + +Order of operations optimization in ``np.einsum`` +-------------------------------------------------- +``np.einsum`` now supports the ``optimize`` argument which will optimize the +order of contraction. For example, ``np.einsum`` would complete the chain dot +example ``np.einsum(‘ij,jk,kl->il’, a, b, c)`` in a single pass which would +scale like ``N^4``; however, when ``optimize=True`` ``np.einsum`` will create +an intermediate array to reduce this scaling to ``N^3`` or effectively +``np.dot(a, b).dot(c)``. Usage of intermediate tensors to reduce scaling has +been applied to the general einsum summation notation. See ``np.einsum_path`` +for more details. + +quicksort has been changed to an introsort +------------------------------------------ +The quicksort kind of ``np.sort`` and ``np.argsort`` is now an introsort which +is regular quicksort but changing to a heapsort when not enough progress is +made. This retains the good quicksort performance while changing the worst case +runtime from ``O(N^2)`` to ``O(N*log(N))``. + +``ediff1d`` improved performance and subclass handling +------------------------------------------------------ +The ediff1d function uses an array instead on a flat iterator for the +subtraction. When to_begin or to_end is not None, the subtraction is performed +in place to eliminate a copy operation. A side effect is that certain +subclasses are handled better, namely astropy.Quantity, since the complete +array is created, wrapped, and then begin and end values are set, instead of +using concatenate. + +Improved precision of ``ndarray.mean`` for float16 arrays +--------------------------------------------------------- +The computation of the mean of float16 arrays is now carried out in float32 for +improved precision. This should be useful in packages such as Theano +where the precision of float16 is adequate and its smaller footprint is +desirable. + + +Changes +======= + +All array-like methods are now called with keyword arguments in fromnumeric.py +------------------------------------------------------------------------------ +Internally, many array-like methods in fromnumeric.py were being called with +positional arguments instead of keyword arguments as their external signatures +were doing. This caused a complication in the downstream 'pandas' library +that encountered an issue with 'numpy' compatibility. Now, all array-like +methods in this module are called with keyword arguments instead. + +Operations on np.memmap objects return numpy arrays in most cases +----------------------------------------------------------------- +Previously operations on a memmap object would misleadingly return a memmap +instance even if the result was actually not memmapped. For example, +``arr + 1`` or ``arr + arr`` would return memmap instances, although no memory +from the output array is memmapped. Version 1.12 returns ordinary numpy arrays +from these operations. + +Also, reduction of a memmap (e.g. ``.sum(axis=None``) now returns a numpy +scalar instead of a 0d memmap. + +stacklevel of warnings increased +-------------------------------- +The stacklevel for python based warnings was increased so that most warnings +will report the offending line of the user code instead of the line the +warning itself is given. Passing of stacklevel is now tested to ensure that +new warnings will receive the ``stacklevel`` argument. + +This causes warnings with the "default" or "module" filter to be shown once +for every offending user code line or user module instead of only once. On +python versions before 3.4, this can cause warnings to appear that were falsely +ignored before, which may be surprising especially in test suits. diff --git a/doc/release/1.12.1-notes.rst b/doc/release/1.12.1-notes.rst new file mode 100644 index 0000000..f67dab1 --- /dev/null +++ b/doc/release/1.12.1-notes.rst @@ -0,0 +1,26 @@ +========================== +NumPy 1.12.1 Release Notes +========================== + +NumPy 1.12.1 supports Python 2.7 and 3.4 - 3.6 and fixes bugs and regressions +found in NumPy 1.12.0. In particular, the regression in f2py constant parsing +is fixed. Wheels for Linux, Windows, and OSX can be found on pypi, + +Bugs Fixed +========== + +* BUG: Fix wrong future nat warning and equiv type logic error... +* BUG: Fix wrong masked median for some special cases +* DOC: Place np.average in inline code +* TST: Work around isfinite inconsistency on i386 +* BUG: Guard against replacing constants without '_' spec in f2py. +* BUG: Fix mean for float 16 non-array inputs for 1.12 +* BUG: Fix calling python api with error set and minor leaks for... +* BUG: Make iscomplexobj compatible with custom dtypes again +* BUG: Fix undefined behaviour induced by bad __array_wrap__ +* BUG: Fix MaskedArray.__setitem__ +* BUG: PPC64el machines are POWER for Fortran in f2py +* BUG: Look up methods on MaskedArray in `_frommethod` +* BUG: Remove extra digit in binary_repr at limit +* BUG: Fix deepcopy regression for empty arrays. +* BUG: Fix ma.median for empty ndarrays diff --git a/doc/release/1.13.0-notes.rst b/doc/release/1.13.0-notes.rst new file mode 100644 index 0000000..4554e53 --- /dev/null +++ b/doc/release/1.13.0-notes.rst @@ -0,0 +1,556 @@ +========================== +NumPy 1.13.0 Release Notes +========================== + +This release supports Python 2.7 and 3.4 - 3.6. + + +Highlights +========== + + * Operations like ``a + b + c`` will reuse temporaries on some platforms, + resulting in less memory use and faster execution. + * Inplace operations check if inputs overlap outputs and create temporaries + to avoid problems. + * New ``__array_ufunc__`` attribute provides improved ability for classes to + override default ufunc behavior. + * New ``np.block`` function for creating blocked arrays. + + +New functions +============= + +* New ``np.positive`` ufunc. +* New ``np.divmod`` ufunc provides more efficient divmod. +* New ``np.isnat`` ufunc tests for NaT special values. +* New ``np.heaviside`` ufunc computes the Heaviside function. +* New ``np.isin`` function, improves on ``in1d``. +* New ``np.block`` function for creating blocked arrays. +* New ``PyArray_MapIterArrayCopyIfOverlap`` added to NumPy C-API. + +See below for details. + + +Deprecations +============ + +* Calling ``np.fix``, ``np.isposinf``, and ``np.isneginf`` with ``f(x, y=out)`` + is deprecated - the argument should be passed as ``f(x, out=out)``, which + matches other ufunc-like interfaces. +* Use of the C-API ``NPY_CHAR`` type number deprecated since version 1.7 will + now raise deprecation warnings at runtime. Extensions built with older f2py + versions need to be recompiled to remove the warning. +* ``np.ma.argsort``, ``np.ma.minimum.reduce``, and ``np.ma.maximum.reduce`` + should be called with an explicit `axis` argument when applied to arrays with + more than 2 dimensions, as the default value of this argument (``None``) is + inconsistent with the rest of numpy (``-1``, ``0``, and ``0``, respectively). +* ``np.ma.MaskedArray.mini`` is deprecated, as it almost duplicates the + functionality of ``np.MaskedArray.min``. Exactly equivalent behaviour + can be obtained with ``np.ma.minimum.reduce``. +* The single-argument form of ``np.ma.minimum`` and ``np.ma.maximum`` is + deprecated. ``np.maximum``. ``np.ma.minimum(x)`` should now be spelt + ``np.ma.minimum.reduce(x)``, which is consistent with how this would be done + with ``np.minimum``. +* Calling ``ndarray.conjugate`` on non-numeric dtypes is deprecated (it + should match the behavior of ``np.conjugate``, which throws an error). +* Calling ``expand_dims`` when the ``axis`` keyword does not satisfy + ``-a.ndim - 1 <= axis <= a.ndim``, where ``a`` is the array being reshaped, + is deprecated. + + +Future Changes +============== + +* Assignment between structured arrays with different field names will change + in NumPy 1.14. Previously, fields in the dst would be set to the value of the + identically-named field in the src. In numpy 1.14 fields will instead be + assigned 'by position': The n-th field of the dst will be set to the n-th + field of the src array. Note that the ``FutureWarning`` raised in NumPy 1.12 + incorrectly reported this change as scheduled for NumPy 1.13 rather than + NumPy 1.14. + + +Build System Changes +==================== + +* ``numpy.distutils`` now automatically determines C-file dependencies with + GCC compatible compilers. + + +Compatibility notes +=================== + +Error type changes +------------------ + +* ``numpy.hstack()`` now throws ``ValueError`` instead of ``IndexError`` when + input is empty. +* Functions taking an axis argument, when that argument is out of range, now + throw ``np.AxisError`` instead of a mixture of ``IndexError`` and + ``ValueError``. For backwards compatibility, ``AxisError`` subclasses both of + these. + +Tuple object dtypes +------------------- + +Support has been removed for certain obscure dtypes that were unintentionally +allowed, of the form ``(old_dtype, new_dtype)``, where either of the dtypes +is or contains the ``object`` dtype. As an exception, dtypes of the form +``(object, [('name', object)])`` are still supported due to evidence of +existing use. + +DeprecationWarning to error +--------------------------- +See Changes section for more detail. + +* ``partition``, TypeError when non-integer partition index is used. +* ``NpyIter_AdvancedNew``, ValueError when ``oa_ndim == 0`` and ``op_axes`` is NULL +* ``negative(bool_)``, TypeError when negative applied to booleans. +* ``subtract(bool_, bool_)``, TypeError when subtracting boolean from boolean. +* ``np.equal, np.not_equal``, object identity doesn't override failed comparison. +* ``np.equal, np.not_equal``, object identity doesn't override non-boolean comparison. +* Deprecated boolean indexing behavior dropped. See Changes below for details. +* Deprecated ``np.alterdot()`` and ``np.restoredot()`` removed. + +FutureWarning to changed behavior +--------------------------------- +See Changes section for more detail. + +* ``numpy.average`` preserves subclasses +* ``array == None`` and ``array != None`` do element-wise comparison. +* ``np.equal, np.not_equal``, object identity doesn't override comparison result. + +dtypes are now always true +-------------------------- + +Previously ``bool(dtype)`` would fall back to the default python +implementation, which checked if ``len(dtype) > 0``. Since ``dtype`` objects +implement ``__len__`` as the number of record fields, ``bool`` of scalar dtypes +would evaluate to ``False``, which was unintuitive. Now ``bool(dtype) == True`` +for all dtypes. + +``__getslice__`` and ``__setslice__`` are no longer needed in ``ndarray`` subclasses +------------------------------------------------------------------------------------ +When subclassing np.ndarray in Python 2.7, it is no longer _necessary_ to +implement ``__*slice__`` on the derived class, as ``__*item__`` will intercept +these calls correctly. + +Any code that did implement these will work exactly as before. Code that +invokes``ndarray.__getslice__`` (e.g. through ``super(...).__getslice__``) will +now issue a DeprecationWarning - ``.__getitem__(slice(start, end))`` should be +used instead. + +Indexing MaskedArrays/Constants with ``...`` (ellipsis) now returns MaskedArray +------------------------------------------------------------------------------- +This behavior mirrors that of np.ndarray, and accounts for nested arrays in +MaskedArrays of object dtype, and ellipsis combined with other forms of +indexing. + +C API changes +============= + +GUfuncs on empty arrays and NpyIter axis removal +------------------------------------------------ +It is now allowed to remove a zero-sized axis from NpyIter. Which may mean +that code removing axes from NpyIter has to add an additional check when +accessing the removed dimensions later on. + +The largest followup change is that gufuncs are now allowed to have zero-sized +inner dimensions. This means that a gufunc now has to anticipate an empty inner +dimension, while this was never possible and an error raised instead. + +For most gufuncs no change should be necessary. However, it is now possible +for gufuncs with a signature such as ``(..., N, M) -> (..., M)`` to return +a valid result if ``N=0`` without further wrapping code. + +``PyArray_MapIterArrayCopyIfOverlap`` added to NumPy C-API +---------------------------------------------------------- +Similar to ``PyArray_MapIterArray`` but with an additional ``copy_if_overlap`` +argument. If ``copy_if_overlap != 0``, checks if input has memory overlap with +any of the other arrays and make copies as appropriate to avoid problems if the +input is modified during the iteration. See the documentation for more complete +documentation. + + +New Features +============ + +``__array_ufunc__`` added +------------------------- +This is the renamed and redesigned ``__numpy_ufunc__``. Any class, ndarray +subclass or not, can define this method or set it to ``None`` in order to +override the behavior of NumPy's ufuncs. This works quite similarly to Python's +``__mul__`` and other binary operation routines. See the documentation for a +more detailed description of the implementation and behavior of this new +option. The API is provisional, we do not yet guarantee backward compatibility +as modifications may be made pending feedback. See the NEP_ and +documentation_ for more details. + +.. _NEP: https://github.com/numpy/numpy/blob/master/doc/neps/ufunc-overrides.rst +.. _documentation: https://github.com/charris/numpy/blob/master/doc/source/reference/arrays.classes.rst + +New ``positive`` ufunc +---------------------- +This ufunc corresponds to unary `+`, but unlike `+` on an ndarray it will raise +an error if array values do not support numeric operations. + +New ``divmod`` ufunc +-------------------- +This ufunc corresponds to the Python builtin `divmod`, and is used to implement +`divmod` when called on numpy arrays. ``np.divmod(x, y)`` calculates a result +equivalent to ``(np.floor_divide(x, y), np.remainder(x, y))`` but is +approximately twice as fast as calling the functions separately. + +``np.isnat`` ufunc tests for NaT special datetime and timedelta values +---------------------------------------------------------------------- +The new ufunc ``np.isnat`` finds the positions of special NaT values +within datetime and timedelta arrays. This is analogous to ``np.isnan``. + +``np.heaviside`` ufunc computes the Heaviside function +------------------------------------------------------ +The new function ``np.heaviside(x, h0)`` (a ufunc) computes the Heaviside +function: + +.. code:: + + { 0 if x < 0, + heaviside(x, h0) = { h0 if x == 0, + { 1 if x > 0. + +``np.block`` function for creating blocked arrays +------------------------------------------------- +Add a new ``block`` function to the current stacking functions ``vstack``, +``hstack``, and ``stack``. This allows concatenation across multiple axes +simultaneously, with a similar syntax to array creation, but where elements +can themselves be arrays. For instance:: + + >>> A = np.eye(2) * 2 + >>> B = np.eye(3) * 3 + >>> np.block([ + ... [A, np.zeros((2, 3))], + ... [np.ones((3, 2)), B ] + ... ]) + array([[ 2., 0., 0., 0., 0.], + [ 0., 2., 0., 0., 0.], + [ 1., 1., 3., 0., 0.], + [ 1., 1., 0., 3., 0.], + [ 1., 1., 0., 0., 3.]]) + +While primarily useful for block matrices, this works for arbitrary dimensions +of arrays. + +It is similar to Matlab's square bracket notation for creating block matrices. + +``isin`` function, improving on ``in1d`` +---------------------------------------- +The new function ``isin`` tests whether each element of an N-dimensonal +array is present anywhere within a second array. It is an enhancement +of ``in1d`` that preserves the shape of the first array. + +Temporary elision +----------------- +On platforms providing the ``backtrace`` function NumPy will try to avoid +creating temporaries in expression involving basic numeric types. +For example ``d = a + b + c`` is transformed to ``d = a + b; d += c`` which can +improve performance for large arrays as less memory bandwidth is required to +perform the operation. + +``axes`` argument for ``unique`` +-------------------------------- +In an N-dimensional array, the user can now choose the axis along which to look +for duplicate N-1-dimensional elements using ``numpy.unique``. The original +behaviour is recovered if ``axis=None`` (default). + +``np.gradient`` now supports unevenly spaced data +------------------------------------------------- +Users can now specify a not-constant spacing for data. +In particular ``np.gradient`` can now take: + +1. A single scalar to specify a sample distance for all dimensions. +2. N scalars to specify a constant sample distance for each dimension. + i.e. ``dx``, ``dy``, ``dz``, ... +3. N arrays to specify the coordinates of the values along each dimension of F. + The length of the array must match the size of the corresponding dimension +4. Any combination of N scalars/arrays with the meaning of 2. and 3. + +This means that, e.g., it is now possible to do the following:: + + >>> f = np.array([[1, 2, 6], [3, 4, 5]], dtype=np.float) + >>> dx = 2. + >>> y = [1., 1.5, 3.5] + >>> np.gradient(f, dx, y) + [array([[ 1. , 1. , -0.5], [ 1. , 1. , -0.5]]), + array([[ 2. , 2. , 2. ], [ 2. , 1.7, 0.5]])] + +Support for returning arrays of arbitrary dimensions in ``apply_along_axis`` +---------------------------------------------------------------------------- +Previously, only scalars or 1D arrays could be returned by the function passed +to ``apply_along_axis``. Now, it can return an array of any dimensionality +(including 0D), and the shape of this array replaces the axis of the array +being iterated over. + +``.ndim`` property added to ``dtype`` to complement ``.shape`` +-------------------------------------------------------------- +For consistency with ``ndarray`` and ``broadcast``, ``d.ndim`` is a shorthand +for ``len(d.shape)``. + +Support for tracemalloc in Python 3.6 +------------------------------------- +NumPy now supports memory tracing with tracemalloc_ module of Python 3.6 or +newer. Memory allocations from NumPy are placed into the domain defined by +``numpy.lib.tracemalloc_domain``. +Note that NumPy allocation will not show up in tracemalloc_ of earlier Python +versions. + +.. _tracemalloc: https://docs.python.org/3/library/tracemalloc.html + +NumPy may be built with relaxed stride checking debugging +--------------------------------------------------------- +Setting NPY_RELAXED_STRIDES_DEBUG=1 in the environment when relaxed stride +checking is enabled will cause NumPy to be compiled with the affected strides +set to the maximum value of npy_intp in order to help detect invalid usage of +the strides in downstream projects. When enabled, invalid usage often results +in an error being raised, but the exact type of error depends on the details of +the code. TypeError and OverflowError have been observed in the wild. + +It was previously the case that this option was disabled for releases and +enabled in master and changing between the two required editing the code. It is +now disabled by default but can be enabled for test builds. + + +Improvements +============ + +Ufunc behavior for overlapping inputs +------------------------------------- + +Operations where ufunc input and output operands have memory overlap +produced undefined results in previous NumPy versions, due to data +dependency issues. In NumPy 1.13.0, results from such operations are +now defined to be the same as for equivalent operations where there is +no memory overlap. + +Operations affected now make temporary copies, as needed to eliminate +data dependency. As detecting these cases is computationally +expensive, a heuristic is used, which may in rare cases result to +needless temporary copies. For operations where the data dependency +is simple enough for the heuristic to analyze, temporary copies will +not be made even if the arrays overlap, if it can be deduced copies +are not necessary. As an example,``np.add(a, b, out=a)`` will not +involve copies. + +To illustrate a previously undefined operation:: + + >>> x = np.arange(16).astype(float) + >>> np.add(x[1:], x[:-1], out=x[1:]) + +In NumPy 1.13.0 the last line is guaranteed to be equivalent to:: + + >>> np.add(x[1:].copy(), x[:-1].copy(), out=x[1:]) + +A similar operation with simple non-problematic data dependence is:: + + >>> x = np.arange(16).astype(float) + >>> np.add(x[1:], x[:-1], out=x[:-1]) + +It will continue to produce the same results as in previous NumPy +versions, and will not involve unnecessary temporary copies. + +The change applies also to in-place binary operations, for example:: + + >>> x = np.random.rand(500, 500) + >>> x += x.T + +This statement is now guaranteed to be equivalent to ``x[...] = x + x.T``, +whereas in previous NumPy versions the results were undefined. + +Partial support for 64-bit f2py extensions with MinGW +----------------------------------------------------- +Extensions that incorporate Fortran libraries can now be built using the free +MinGW_ toolset, also under Python 3.5. This works best for extensions that only +do calculations and uses the runtime modestly (reading and writing from files, +for instance). Note that this does not remove the need for Mingwpy; if you make +extensive use of the runtime, you will most likely run into issues_. Instead, +it should be regarded as a band-aid until Mingwpy is fully functional. + +Extensions can also be compiled using the MinGW toolset using the runtime +library from the (moveable) WinPython 3.4 distribution, which can be useful for +programs with a PySide1/Qt4 front-end. + +.. _MinGW: https://sf.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/6.2.0/threads-win32/seh/ + +.. _issues: https://mingwpy.github.io/issues.html + +Performance improvements for ``packbits`` and ``unpackbits`` +------------------------------------------------------------ +The functions ``numpy.packbits`` with boolean input and ``numpy.unpackbits`` have +been optimized to be a significantly faster for contiguous data. + +Fix for PPC long double floating point information +-------------------------------------------------- +In previous versions of NumPy, the ``finfo`` function returned invalid +information about the `double double`_ format of the ``longdouble`` float type +on Power PC (PPC). The invalid values resulted from the failure of the NumPy +algorithm to deal with the variable number of digits in the significand +that are a feature of `PPC long doubles`. This release by-passes the failing +algorithm by using heuristics to detect the presence of the PPC double double +format. A side-effect of using these heuristics is that the ``finfo`` +function is faster than previous releases. + +.. _PPC long doubles: https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.genprogc/128bit_long_double_floating-point_datatype.htm + +.. _double double: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format#Double-double_arithmetic + +Better default repr for ``ndarray`` subclasses +---------------------------------------------- +Subclasses of ndarray with no ``repr`` specialization now correctly indent +their data and type lines. + +More reliable comparisons of masked arrays +------------------------------------------ +Comparisons of masked arrays were buggy for masked scalars and failed for +structured arrays with dimension higher than one. Both problems are now +solved. In the process, it was ensured that in getting the result for a +structured array, masked fields are properly ignored, i.e., the result is equal +if all fields that are non-masked in both are equal, thus making the behaviour +identical to what one gets by comparing an unstructured masked array and then +doing ``.all()`` over some axis. + +np.matrix with booleans elements can now be created using the string syntax +--------------------------------------------------------------------------- +``np.matrix`` failed whenever one attempts to use it with booleans, e.g., +``np.matrix('True')``. Now, this works as expected. + +More ``linalg`` operations now accept empty vectors and matrices +---------------------------------------------------------------- +All of the following functions in ``np.linalg`` now work when given input +arrays with a 0 in the last two dimensions: ``det``, ``slogdet``, ``pinv``, +``eigvals``, ``eigvalsh``, ``eig``, ``eigh``. + +Bundled version of LAPACK is now 3.2.2 +-------------------------------------- +NumPy comes bundled with a minimal implementation of lapack for systems without +a lapack library installed, under the name of ``lapack_lite``. This has been +upgraded from LAPACK 3.0.0 (June 30, 1999) to LAPACK 3.2.2 (June 30, 2010). See +the `LAPACK changelogs`_ for details on the all the changes this entails. + +While no new features are exposed through ``numpy``, this fixes some bugs +regarding "workspace" sizes, and in some places may use faster algorithms. + +.. _`LAPACK changelogs`: http://www.netlib.org/lapack/release_notes.html#_4_history_of_lapack_releases + +``reduce`` of ``np.hypot.reduce`` and ``np.logical_xor`` allowed in more cases +------------------------------------------------------------------------------ +This now works on empty arrays, returning 0, and can reduce over multiple axes. +Previously, a ``ValueError`` was thrown in these cases. + +Better ``repr`` of object arrays +-------------------------------- +Object arrays that contain themselves no longer cause a recursion error. + +Object arrays that contain ``list`` objects are now printed in a way that makes +clear the difference between a 2d object array, and a 1d object array of lists. + +Changes +======= + +``argsort`` on masked arrays takes the same default arguments as ``sort`` +------------------------------------------------------------------------- +By default, ``argsort`` now places the masked values at the end of the sorted +array, in the same way that ``sort`` already did. Additionally, the +``end_with`` argument is added to ``argsort``, for consistency with ``sort``. +Note that this argument is not added at the end, so breaks any code that +passed ``fill_value`` as a positional argument. + +``average`` now preserves subclasses +------------------------------------ +For ndarray subclasses, ``numpy.average`` will now return an instance of the +subclass, matching the behavior of most other NumPy functions such as ``mean``. +As a consequence, also calls that returned a scalar may now return a subclass +array scalar. + +``array == None`` and ``array != None`` do element-wise comparison +------------------------------------------------------------------ +Previously these operations returned scalars ``False`` and ``True`` respectively. + +``np.equal, np.not_equal`` for object arrays ignores object identity +-------------------------------------------------------------------- +Previously, these functions always treated identical objects as equal. This had +the effect of overriding comparison failures, comparison of objects that did +not return booleans, such as np.arrays, and comparison of objects where the +results differed from object identity, such as NaNs. + +Boolean indexing changes +------------------------ +* Boolean array-likes (such as lists of python bools) are always treated as + boolean indexes. + +* Boolean scalars (including python ``True``) are legal boolean indexes and + never treated as integers. + +* Boolean indexes must match the dimension of the axis that they index. + +* Boolean indexes used on the lhs of an assignment must match the dimensions of + the rhs. + +* Boolean indexing into scalar arrays return a new 1-d array. This means that + ``array(1)[array(True)]`` gives ``array([1])`` and not the original array. + +``np.random.multivariate_normal`` behavior with bad covariance matrix +--------------------------------------------------------------------- + +It is now possible to adjust the behavior the function will have when dealing +with the covariance matrix by using two new keyword arguments: + +* ``tol`` can be used to specify a tolerance to use when checking that + the covariance matrix is positive semidefinite. + +* ``check_valid`` can be used to configure what the function will do in the + presence of a matrix that is not positive semidefinite. Valid options are + ``ignore``, ``warn`` and ``raise``. The default value, ``warn`` keeps the + the behavior used on previous releases. + +``assert_array_less`` compares ``np.inf`` and ``-np.inf`` now +------------------------------------------------------------- +Previously, ``np.testing.assert_array_less`` ignored all infinite values. This +is not the expected behavior both according to documentation and intuitively. +Now, -inf < x < inf is considered ``True`` for any real number x and all +other cases fail. + +``assert_array_`` and masked arrays ``assert_equal`` hide less warnings +----------------------------------------------------------------------- +Some warnings that were previously hidden by the ``assert_array_`` +functions are not hidden anymore. In most cases the warnings should be +correct and, should they occur, will require changes to the tests using +these functions. +For the masked array ``assert_equal`` version, warnings may occur when +comparing NaT. The function presently does not handle NaT or NaN +specifically and it may be best to avoid it at this time should a warning +show up due to this change. + +``offset`` attribute value in ``memmap`` objects +------------------------------------------------ +The ``offset`` attribute in a ``memmap`` object is now set to the +offset into the file. This is a behaviour change only for offsets +greater than ``mmap.ALLOCATIONGRANULARITY``. + +``np.real`` and ``np.imag`` return scalars for scalar inputs +------------------------------------------------------------ +Previously, ``np.real`` and ``np.imag`` used to return array objects when +provided a scalar input, which was inconsistent with other functions like +``np.angle`` and ``np.conj``. + +The polynomial convenience classes cannot be passed to ufuncs +------------------------------------------------------------- +The ABCPolyBase class, from which the convenience classes are derived, sets +``__array_ufun__ = None`` in order of opt out of ufuncs. If a polynomial +convenience class instance is passed as an argument to a ufunc, a ``TypeError`` +will now be raised. + +Output arguments to ufuncs can be tuples also for ufunc methods +--------------------------------------------------------------- +For calls to ufuncs, it was already possible, and recommended, to use an +``out`` argument with a tuple for ufuncs with multiple outputs. This has now +been extended to output arguments in the ``reduce``, ``accumulate``, and +``reduceat`` methods. This is mostly for compatibility with ``__array_ufunc``; +there are no ufuncs yet that have more than one output. diff --git a/doc/release/1.13.1-notes.rst b/doc/release/1.13.1-notes.rst new file mode 100644 index 0000000..807296a --- /dev/null +++ b/doc/release/1.13.1-notes.rst @@ -0,0 +1,60 @@ +========================== +NumPy 1.13.1 Release Notes +========================== + +This is a bugfix release for problems found in 1.13.0. The major changes are +fixes for the new memory overlap detection and temporary elision as well as +reversion of the removal of the boolean binary ``-`` operator. Users of 1.13.0 +should upgrade. + +Thr Python versions supported are 2.7 and 3.4 - 3.6. Note that the Python 3.6 +wheels available from PIP are built against 3.6.1, hence will not work when +used with 3.6.0 due to Python bug 29943_. NumPy 1.13.2 will be released shortly +after Python 3.6.2 is out to fix that problem. If you are using 3.6.0 the +workaround is to upgrade to 3.6.1 or use an earlier Python version. + +.. _#29943: https://bugs.python.org/issue29943 + + +Pull requests merged +==================== +A total of 19 pull requests were merged for this release. + +* #9240 DOC: BLD: fix lots of Sphinx warnings/errors. +* #9255 Revert "DEP: Raise TypeError for subtract(bool_, bool_)." +* #9261 BUG: don't elide into readonly and updateifcopy temporaries for... +* #9262 BUG: fix missing keyword rename for common block in numpy.f2py +* #9263 BUG: handle resize of 0d array +* #9267 DOC: update f2py front page and some doc build metadata. +* #9299 BUG: Fix Intel compilation on Unix. +* #9317 BUG: fix wrong ndim used in empty where check +* #9319 BUG: Make extensions compilable with MinGW on Py2.7 +* #9339 BUG: Prevent crash if ufunc doc string is null +* #9340 BUG: umath: un-break ufunc where= when no out= is given +* #9371 DOC: Add isnat/positive ufunc to documentation +* #9372 BUG: Fix error in fromstring function from numpy.core.records... +* #9373 BUG: ')' is printed at the end pointer of the buffer in numpy.f2py. +* #9374 DOC: Create NumPy 1.13.1 release notes. +* #9376 BUG: Prevent hang traversing ufunc userloop linked list +* #9377 DOC: Use x1 and x2 in the heaviside docstring. +* #9378 DOC: Add $PARAMS to the isnat docstring +* #9379 DOC: Update the 1.13.1 release notes + + +Contributors +============ +A total of 12 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Andras Deak + +* Bob Eldering + +* Charles Harris +* Daniel Hrisca + +* Eric Wieser +* Joshua Leahy + +* Julian Taylor +* Michael Seifert +* Pauli Virtanen +* Ralf Gommers +* Roland Kaufmann +* Warren Weckesser diff --git a/doc/release/1.13.2-notes.rst b/doc/release/1.13.2-notes.rst new file mode 100644 index 0000000..f2f9120 --- /dev/null +++ b/doc/release/1.13.2-notes.rst @@ -0,0 +1,58 @@ +========================== +NumPy 1.13.2 Release Notes +========================== + +This is a bugfix release for some problems found since 1.13.1. The most +important fixes are for CVE-2017-12852 and temporary elision. Users of earlier +versions of 1.13 should upgrade. + +The Python versions supported are 2.7 and 3.4 - 3.6. The Python 3.6 wheels +available from PIP are built with Python 3.6.2 and should be compatible with +all previous versions of Python 3.6. The Windows wheels are now built +with OpenBlas instead ATLAS, which should improve the performance of the linear +algebra functions. + +Contributors +============ + +A total of 12 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Allan Haldane +* Brandon Carter +* Charles Harris +* Eric Wieser +* Iryna Shcherbina + +* James Bourbeau + +* Jonathan Helmus +* Julian Taylor +* Matti Picus +* Michael Lamparski + +* Michael Seifert +* Ralf Gommers + +Pull requests merged +==================== + +A total of 20 pull requests were merged for this release. + +* #9390 BUG: Return the poly1d coefficients array directly +* #9555 BUG: Fix regression in 1.13.x in distutils.mingw32ccompiler. +* #9556 BUG: Fix true_divide when dtype=np.float64 specified. +* #9557 DOC: Fix some rst markup in numpy/doc/basics.py. +* #9558 BLD: Remove -xhost flag from IntelFCompiler. +* #9559 DOC: Removes broken docstring example (source code, png, pdf)... +* #9580 BUG: Add hypot and cabs functions to WIN32 blacklist. +* #9732 BUG: Make scalar function elision check if temp is writeable. +* #9736 BUG: Various fixes to np.gradient +* #9742 BUG: Fix np.pad for CVE-2017-12852 +* #9744 BUG: Check for exception in sort functions, add tests +* #9745 DOC: Add whitespace after "versionadded::" directive so it actually... +* #9746 BUG: Memory leak in np.dot of size 0 +* #9747 BUG: Adjust gfortran version search regex +* #9757 BUG: Cython 0.27 breaks NumPy on Python 3. +* #9764 BUG: Ensure `_npy_scaled_cexp{,f,l}` is defined when needed. +* #9765 BUG: PyArray_CountNonzero does not check for exceptions +* #9766 BUG: Fixes histogram monotonicity check for unsigned bin values +* #9767 BUG: Ensure consistent result dtype of count_nonzero +* #9771 BUG, MAINT: Fix mtrand for Cython 0.27. diff --git a/doc/release/1.13.3-notes.rst b/doc/release/1.13.3-notes.rst new file mode 100644 index 0000000..7f7170b --- /dev/null +++ b/doc/release/1.13.3-notes.rst @@ -0,0 +1,64 @@ +========================== +NumPy 1.13.3 Release Notes +========================== + +This is a bugfix release for some problems found since 1.13.1. The most +important fixes are for CVE-2017-12852 and temporary elision. Users of earlier +versions of 1.13 should upgrade. + +The Python versions supported are 2.7 and 3.4 - 3.6. The Python 3.6 wheels +available from PIP are built with Python 3.6.2 and should be compatible with +all previous versions of Python 3.6. It was cythonized with Cython 0.26.1, +which should be free of the bugs found in 0.27 while also being compatible with +Python 3.7-dev. The Windows wheels were built with OpenBlas instead ATLAS, +which should improve the performance of the linear algebra functions. + +The NumPy 1.13.3 release is a re-release of 1.13.2, which suffered from a +bug in Cython 0.27.0. + +Contributors +============ + +A total of 12 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Allan Haldane +* Brandon Carter +* Charles Harris +* Eric Wieser +* Iryna Shcherbina + +* James Bourbeau + +* Jonathan Helmus +* Julian Taylor +* Matti Picus +* Michael Lamparski + +* Michael Seifert +* Ralf Gommers + +Pull requests merged +==================== + +A total of 22 pull requests were merged for this release. + +* #9390 BUG: Return the poly1d coefficients array directly +* #9555 BUG: Fix regression in 1.13.x in distutils.mingw32ccompiler. +* #9556 BUG: Fix true_divide when dtype=np.float64 specified. +* #9557 DOC: Fix some rst markup in numpy/doc/basics.py. +* #9558 BLD: Remove -xhost flag from IntelFCompiler. +* #9559 DOC: Removes broken docstring example (source code, png, pdf)... +* #9580 BUG: Add hypot and cabs functions to WIN32 blacklist. +* #9732 BUG: Make scalar function elision check if temp is writeable. +* #9736 BUG: Various fixes to np.gradient +* #9742 BUG: Fix np.pad for CVE-2017-12852 +* #9744 BUG: Check for exception in sort functions, add tests +* #9745 DOC: Add whitespace after "versionadded::" directive so it actually... +* #9746 BUG: Memory leak in np.dot of size 0 +* #9747 BUG: Adjust gfortran version search regex +* #9757 BUG: Cython 0.27 breaks NumPy on Python 3. +* #9764 BUG: Ensure `_npy_scaled_cexp{,f,l}` is defined when needed. +* #9765 BUG: PyArray_CountNonzero does not check for exceptions +* #9766 BUG: Fixes histogram monotonicity check for unsigned bin values +* #9767 BUG: Ensure consistent result dtype of count_nonzero +* #9771 BUG: MAINT: Fix mtrand for Cython 0.27. +* #9772 DOC: Create the 1.13.2 release notes. +* #9794 DOC: Create 1.13.3 release notes. diff --git a/doc/release/1.14.0-notes.rst b/doc/release/1.14.0-notes.rst new file mode 100644 index 0000000..63d37fa --- /dev/null +++ b/doc/release/1.14.0-notes.rst @@ -0,0 +1,669 @@ +========================== +NumPy 1.14.0 Release Notes +========================== + +Numpy 1.14.0 is the result of seven months of work and contains a large number +of bug fixes and new features, along with several changes with potential +compatibility issues. The major change that users will notice are the +stylistic changes in the way numpy arrays and scalars are printed, a change +that will affect doctests. See below for details on how to preserve the +old style printing when needed. + +A major decision affecting future development concerns the schedule for +dropping Python 2.7 support in the runup to 2020. The decision has been made to +support 2.7 for all releases made in 2018, with the last release being +designated a long term release with support for bug fixes extending through +2019. In 2019 support for 2.7 will be dropped in all new releases. More details +can be found in the relevant NEP_. + +This release supports Python 2.7 and 3.4 - 3.6. + +.. _NEP: https://github.com/numpy/numpy/blob/master/doc/neps/dropping-python2.7-proposal.rst + + +Highlights +========== + +* The `np.einsum` function uses BLAS when possible + +* ``genfromtxt``, ``loadtxt``, ``fromregex`` and ``savetxt`` can now handle + files with arbitrary Python supported encoding. + +* Major improvements to printing of NumPy arrays and scalars. + + +New functions +============= + +* ``parametrize``: decorator added to numpy.testing + +* ``chebinterpolate``: Interpolate function at Chebyshev points. + +* ``format_float_positional`` and ``format_float_scientific`` : format + floating-point scalars unambiguously with control of rounding and padding. + +* ``PyArray_ResolveWritebackIfCopy`` and ``PyArray_SetWritebackIfCopyBase``, + new C-API functions useful in achieving PyPy compatibity. + + +Deprecations +============ + +* Using ``np.bool_`` objects in place of integers is deprecated. Previously + ``operator.index(np.bool_)`` was legal and allowed constructs such as + ``[1, 2, 3][np.True_]``. That was misleading, as it behaved differently from + ``np.array([1, 2, 3])[np.True_]``. + +* Truth testing of an empty array is deprecated. To check if an array is not + empty, use ``array.size > 0``. + +* Calling ``np.bincount`` with ``minlength=None`` is deprecated. + ``minlength=0`` should be used instead. + +* Calling ``np.fromstring`` with the default value of the ``sep`` argument is + deprecated. When that argument is not provided, a broken version of + ``np.frombuffer`` is used that silently accepts unicode strings and -- after + encoding them as either utf-8 (python 3) or the default encoding + (python 2) -- treats them as binary data. If reading binary data is + desired, ``np.frombuffer`` should be used directly. + +* The ``style`` option of array2string is deprecated in non-legacy printing mode. + +* ``PyArray_SetUpdateIfCopyBase`` has been deprecated. For NumPy versions >= 1.14 + use ``PyArray_SetWritebackIfCopyBase`` instead, see `C API changes` below for + more details. + + + +* The use of ``UPDATEIFCOPY`` arrays is deprecated, see `C API changes` below + for details. We will not be dropping support for those arrays, but they are + not compatible with PyPy. + + +Future Changes +============== + +* ``np.issubdtype`` will stop downcasting dtype-like arguments. + It might be expected that ``issubdtype(np.float32, 'float64')`` and + ``issubdtype(np.float32, np.float64)`` mean the same thing - however, there + was an undocumented special case that translated the former into + ``issubdtype(np.float32, np.floating)``, giving the surprising result of True. + + This translation now gives a warning that explains what translation is + occurring. In the future, the translation will be disabled, and the first + example will be made equivalent to the second. + +* ``np.linalg.lstsq`` default for ``rcond`` will be changed. The ``rcond`` + parameter to ``np.linalg.lstsq`` will change its default to machine precision + times the largest of the input array dimensions. A FutureWarning is issued + when ``rcond`` is not passed explicitly. + +* ``a.flat.__array__()`` will return a writeable copy of ``a`` when ``a`` is + non-contiguous. Previously it returned an UPDATEIFCOPY array when ``a`` was + writeable. Currently it returns a non-writeable copy. See gh-7054 for a + discussion of the issue. + +* Unstructured void array's ``.item`` method will return a bytes object. In the + future, calling ``.item()`` on arrays or scalars of ``np.void`` datatype will + return a ``bytes`` object instead of a buffer or int array, the same as + returned by ``bytes(void_scalar)``. This may affect code which assumed the + return value was mutable, which will no longer be the case. A + ``FutureWarning`` is now issued when this would occur. + + +Compatibility notes +=================== + +The mask of a masked array view is also a view rather than a copy +----------------------------------------------------------------- +There was a FutureWarning about this change in NumPy 1.11.x. In short, it is +now the case that, when changing a view of a masked array, changes to the mask +are propagated to the original. That was not previously the case. This change +affects slices in particular. Note that this does not yet work properly if the +mask of the original array is ``nomask`` and the mask of the view is changed. +See gh-5580 for an extended discussion. The original behavior of having a copy +of the mask can be obtained by calling the ``unshare_mask`` method of the view. + +``np.ma.masked`` is no longer writeable +--------------------------------------- +Attempts to mutate the ``masked`` constant now error, as the underlying arrays +are marked readonly. In the past, it was possible to get away with:: + + # emulating a function that sometimes returns np.ma.masked + val = random.choice([np.ma.masked, 10]) + var_arr = np.asarray(val) + val_arr += 1 # now errors, previously changed np.ma.masked.data + +``np.ma`` functions producing ``fill_value``s have changed +---------------------------------------------------------- +Previously, ``np.ma.default_fill_value`` would return a 0d array, but +``np.ma.minimum_fill_value`` and ``np.ma.maximum_fill_value`` would return a +tuple of the fields. Instead, all three methods return a structured ``np.void`` +object, which is what you would already find in the ``.fill_value`` attribute. + +Additionally, the dtype guessing now matches that of ``np.array`` - so when +passing a python scalar ``x``, ``maximum_fill_value(x)`` is always the same as +``maximum_fill_value(np.array(x))``. Previously ``x = long(1)`` on Python 2 +violated this assumption. + +``a.flat.__array__()`` returns non-writeable arrays when ``a`` is non-contiguous +-------------------------------------------------------------------------------- +The intent is that the UPDATEIFCOPY array previously returned when ``a`` was +non-contiguous will be replaced by a writeable copy in the future. This +temporary measure is aimed to notify folks who expect the underlying array be +modified in this situation that that will no longer be the case. The most +likely places for this to be noticed is when expressions of the form +``np.asarray(a.flat)`` are used, or when ``a.flat`` is passed as the out +parameter to a ufunc. + +``np.tensordot`` now returns zero array when contracting over 0-length dimension +-------------------------------------------------------------------------------- +Previously ``np.tensordot`` raised a ValueError when contracting over 0-length +dimension. Now it returns a zero array, which is consistent with the behaviour +of ``np.dot`` and ``np.einsum``. + +``numpy.testing`` reorganized +----------------------------- +This is not expected to cause problems, but possibly something has been left +out. If you experience an unexpected import problem using ``numpy.testing`` +let us know. + +``np.asfarray`` no longer accepts non-dtypes through the ``dtype`` argument +--------------------------------------------------------------------------- +This previously would accept ``dtype=some_array``, with the implied semantics +of ``dtype=some_array.dtype``. This was undocumented, unique across the numpy +functions, and if used would likely correspond to a typo. + +1D ``np.linalg.norm`` preserves float input types, even for arbitrary orders +---------------------------------------------------------------------------- +Previously, this would promote to ``float64`` when arbitrary orders were +passed, despite not doing so under the simple cases:: + + >>> f32 = np.float32([[1, 2]]) + >>> np.linalg.norm(f32, 2.0, axis=-1).dtype + dtype('float32') + >>> np.linalg.norm(f32, 2.0001, axis=-1).dtype + dtype('float64') # numpy 1.13 + dtype('float32') # numpy 1.14 + +This change affects only ``float32`` and ``float16`` arrays. + +``count_nonzero(arr, axis=())`` now counts over no axes, not all axes +--------------------------------------------------------------------- +Elsewhere, ``axis==()`` is always understood as "no axes", but +`count_nonzero` had a special case to treat this as "all axes". This was +inconsistent and surprising. The correct way to count over all axes has always +been to pass ``axis == None``. + +``__init__.py`` files added to test directories +----------------------------------------------- +This is for pytest compatibility in the case of duplicate test file names in +the different directories. As a result, ``run_module_suite`` no longer works, +i.e., ``python `` results in an error. + +``.astype(bool)`` on unstructured void arrays now calls ``bool`` on each element +-------------------------------------------------------------------------------- +On Python 2, ``void_array.astype(bool)`` would always return an array of +``True``, unless the dtype is ``V0``. On Python 3, this operation would usually +crash. Going forwards, `astype` matches the behavior of ``bool(np.void)``, +considering a buffer of all zeros as false, and anything else as true. +Checks for ``V0`` can still be done with ``arr.dtype.itemsize == 0``. + +``MaskedArray.squeeze`` never returns ``np.ma.masked`` +------------------------------------------------------ +``np.squeeze`` is documented as returning a view, but the masked variant would +sometimes return ``masked``, which is not a view. This has been fixed, so that +the result is always a view on the original masked array. +This breaks any code that used ``masked_arr.squeeze() is np.ma.masked``, but +fixes code that writes to the result of `.squeeze()`. + +Renamed first parameter of ``can_cast`` from ``from`` to ``from_`` +------------------------------------------------------------------ +The previous parameter name ``from`` is a reserved keyword in Python, which made +it difficult to pass the argument by name. This has been fixed by renaming +the parameter to ``from_``. + +``isnat`` raises ``TypeError`` when passed wrong type +------------------------------------------------------ +The ufunc ``isnat`` used to raise a ``ValueError`` when it was not passed +variables of type ``datetime`` or ``timedelta``. This has been changed to +raising a ``TypeError``. + +``dtype.__getitem__`` raises ``TypeError`` when passed wrong type +----------------------------------------------------------------- +When indexed with a float, the dtype object used to raise ``ValueError``. + +User-defined types now need to implement ``__str__`` and ``__repr__`` +--------------------------------------------------------------------- +Previously, user-defined types could fall back to a default implementation of +``__str__`` and ``__repr__`` implemented in numpy, but this has now been +removed. Now user-defined types will fall back to the python default +``object.__str__`` and ``object.__repr__``. + +Many changes to array printing, disableable with the new "legacy" printing mode +------------------------------------------------------------------------------- +The ``str`` and ``repr`` of ndarrays and numpy scalars have been changed in +a variety of ways. These changes are likely to break downstream user's +doctests. + +These new behaviors can be disabled to mostly reproduce numpy 1.13 behavior by +enabling the new 1.13 "legacy" printing mode. This is enabled by calling +``np.set_printoptions(legacy="1.13")``, or using the new ``legacy`` argument to +``np.array2string``, as ``np.array2string(arr, legacy='1.13')``. + +In summary, the major changes are: + +* For floating-point types: + + * The ``repr`` of float arrays often omits a space previously printed + in the sign position. See the new ``sign`` option to ``np.set_printoptions``. + * Floating-point arrays and scalars use a new algorithm for decimal + representations, giving the shortest unique representation. This will + usually shorten ``float16`` fractional output, and sometimes ``float32`` and + ``float128`` output. ``float64`` should be unaffected. See the new + ``floatmode`` option to ``np.set_printoptions``. + * Float arrays printed in scientific notation no longer use fixed-precision, + and now instead show the shortest unique representation. + * The ``str`` of floating-point scalars is no longer truncated in python2. + +* For other data types: + + * Non-finite complex scalars print like ``nanj`` instead of ``nan*j``. + * ``NaT`` values in datetime arrays are now properly aligned. + * Arrays and scalars of ``np.void`` datatype are now printed using hex + notation. + +* For line-wrapping: + + * The "dtype" part of ndarray reprs will now be printed on the next line + if there isn't space on the last line of array output. + * The ``linewidth`` format option is now always respected. + The `repr` or `str` of an array will never exceed this, unless a single + element is too wide. + * The last line of an array string will never have more elements than earlier + lines. + * An extra space is no longer inserted on the first line if the elements are + too wide. + +* For summarization (the use of ``...`` to shorten long arrays): + + * A trailing comma is no longer inserted for ``str``. + Previously, ``str(np.arange(1001))`` gave + ``'[ 0 1 2 ..., 998 999 1000]'``, which has an extra comma. + * For arrays of 2-D and beyond, when ``...`` is printed on its own line in + order to summarize any but the last axis, newlines are now appended to that + line to match its leading newlines and a trailing space character is + removed. + +* ``MaskedArray`` arrays now separate printed elements with commas, always + print the dtype, and correctly wrap the elements of long arrays to multiple + lines. If there is more than 1 dimension, the array attributes are now + printed in a new "left-justified" printing style. +* ``recarray`` arrays no longer print a trailing space before their dtype, and + wrap to the right number of columns. +* 0d arrays no longer have their own idiosyncratic implementations of ``str`` + and ``repr``. The ``style`` argument to ``np.array2string`` is deprecated. +* Arrays of ``bool`` datatype will omit the datatype in the ``repr``. +* User-defined ``dtypes`` (subclasses of ``np.generic``) now need to + implement ``__str__`` and ``__repr__``. + +Some of these changes are described in more detail below. If you need to retain +the previous behavior for doctests or other reasons, you may want to do +something like:: + + # FIXME: We need the str/repr formatting used in Numpy < 1.14. + try: + np.set_printoptions(legacy='1.13') + except TypeError: + pass +You may want to do something like:: + + # FIXME: Set numpy array str/repr to legacy behaviour on numpy > 1.13 + try: + np.set_printoptions(legacy='1.13') + except TypeError: + pass + +after :: + + import numpy as np + +Some of these changes are described in more detail below. + + +C API changes +============= + +PyPy compatible alternative to ``UPDATEIFCOPY`` arrays +------------------------------------------------------ +``UPDATEIFCOPY`` arrays are contiguous copies of existing arrays, possibly with +different dimensions, whose contents are copied back to the original array when +their refcount goes to zero and they are deallocated. Because PyPy does not use +refcounts, they do not function correctly with PyPy. NumPy is in the process of +eliminating their use internally and two new C-API functions, + +* ``PyArray_SetWritebackIfCopyBase`` +* ``PyArray_ResolveWritebackIfCopy``, + +have been added together with a complimentary flag, +``NPY_ARRAY_WRITEBACKIFCOPY``. Using the new functionality also requires that +some flags be changed when new arrays are created, to wit: +``NPY_ARRAY_INOUT_ARRAY`` should be replaced by ``NPY_ARRAY_INOUT_ARRAY2`` and +``NPY_ARRAY_INOUT_FARRAY`` should be replaced by ``NPY_ARRAY_INOUT_FARRAY2``. +Arrays created with these new flags will then have the ``WRITEBACKIFCOPY`` +semantics. + +If PyPy compatibility is not a concern, these new functions can be ignored, +although there will be a ``DeprecationWarning``. If you do wish to pursue PyPy +compatibility, more information on these functions and their use may be found +in the c-api_ documentation and the example in how-to-extend_. + +.. _c-api: https://github.com/numpy/numpy/blob/master/doc/source/reference/c-api.array.rst +.. _how-to-extend: https://github.com/numpy/numpy/blob/master/doc/source/user/c-info.how-to-extend.rst + + +New Features +============ + +Encoding argument for text IO functions +--------------------------------------- +``genfromtxt``, ``loadtxt``, ``fromregex`` and ``savetxt`` can now handle files +with arbitrary encoding supported by Python via the encoding argument. +For backward compatibility the argument defaults to the special ``bytes`` value +which continues to treat text as raw byte values and continues to pass latin1 +encoded bytes to custom converters. +Using any other value (including ``None`` for system default) will switch the +functions to real text IO so one receives unicode strings instead of bytes in +the resulting arrays. + +External ``nose`` plugins are usable by ``numpy.testing.Tester`` +---------------------------------------------------------------- +``numpy.testing.Tester`` is now aware of ``nose`` plugins that are outside the +``nose`` built-in ones. This allows using, for example, ``nose-timer`` like +so: ``np.test(extra_argv=['--with-timer', '--timer-top-n', '20'])`` to +obtain the runtime of the 20 slowest tests. An extra keyword ``timer`` was +also added to ``Tester.test``, so ``np.test(timer=20)`` will also report the 20 +slowest tests. + +``parametrize`` decorator added to ``numpy.testing`` +---------------------------------------------------- +A basic ``parametrize`` decorator is now available in ``numpy.testing``. It is +intended to allow rewriting yield based tests that have been deprecated in +pytest so as to facilitate the transition to pytest in the future. The nose +testing framework has not been supported for several years and looks like +abandonware. + +The new ``parametrize`` decorator does not have the full functionality of the +one in pytest. It doesn't work for classes, doesn't support nesting, and does +not substitute variable names. Even so, it should be adequate to rewrite the +NumPy tests. + +``chebinterpolate`` function added to ``numpy.polynomial.chebyshev`` +-------------------------------------------------------------------- +The new ``chebinterpolate`` function interpolates a given function at the +Chebyshev points of the first kind. A new ``Chebyshev.interpolate`` class +method adds support for interpolation over arbitrary intervals using the scaled +and shifted Chebyshev points of the first kind. + +Support for reading lzma compressed text files in Python 3 +---------------------------------------------------------- +With Python versions containing the ``lzma`` module the text IO functions can +now transparently read from files with ``xz`` or ``lzma`` extension. + +``sign`` option added to ``np.setprintoptions`` and ``np.array2string`` +----------------------------------------------------------------------- +This option controls printing of the sign of floating-point types, and may be +one of the characters '-', '+' or ' '. With '+' numpy always prints the sign of +positive values, with ' ' it always prints a space (whitespace character) in +the sign position of positive values, and with '-' it will omit the sign +character for positive values. The new default is '-'. + +This new default changes the float output relative to numpy 1.13. The old +behavior can be obtained in 1.13 "legacy" printing mode, see compatibility +notes above. + +``hermitian`` option added to``np.linalg.matrix_rank`` +------------------------------------------------------ +The new ``hermitian`` option allows choosing between standard SVD based matrix +rank calculation and the more efficient eigenvalue based method for +symmetric/hermitian matrices. + +``threshold`` and ``edgeitems`` options added to ``np.array2string`` +-------------------------------------------------------------------- +These options could previously be controlled using ``np.set_printoptions``, but +now can be changed on a per-call basis as arguments to ``np.array2string``. + +``concatenate`` and ``stack`` gained an ``out`` argument +-------------------------------------------------------- +A preallocated buffer of the desired dtype can now be used for the output of +these functions. + +Support for PGI flang compiler on Windows +----------------------------------------- +The PGI flang compiler is a Fortran front end for LLVM released by NVIDIA under +the Apache 2 license. It can be invoked by :: + + python setup.py config --compiler=clang --fcompiler=flang install + +There is little experience with this new compiler, so any feedback from people +using it will be appreciated. + + +Improvements +============ + +Numerator degrees of freedom in ``random.noncentral_f`` need only be positive. +------------------------------------------------------------------------------ +Prior to NumPy 1.14.0, the numerator degrees of freedom needed to be > 1, but +the distribution is valid for values > 0, which is the new requirement. + +The GIL is released for all ``np.einsum`` variations +---------------------------------------------------- +Some specific loop structures which have an accelerated loop version +did not release the GIL prior to NumPy 1.14.0. This oversight has been +fixed. + +The `np.einsum` function will use BLAS when possible and optimize by default +---------------------------------------------------------------------------- +The ``np.einsum`` function will now call ``np.tensordot`` when appropriate. +Because ``np.tensordot`` uses BLAS when possible, that will speed up execution. +By default, ``np.einsum`` will also attempt optimization as the overhead is +small relative to the potential improvement in speed. + +``f2py`` now handles arrays of dimension 0 +------------------------------------------ +``f2py`` now allows for the allocation of arrays of dimension 0. This allows +for more consistent handling of corner cases downstream. + +``numpy.distutils`` supports using MSVC and mingw64-gfortran together +--------------------------------------------------------------------- +Numpy distutils now supports using Mingw64 gfortran and MSVC compilers +together. This enables the production of Python extension modules on Windows +containing Fortran code while retaining compatibility with the +binaries distributed by Python.org. Not all use cases are supported, +but most common ways to wrap Fortran for Python are functional. + +Compilation in this mode is usually enabled automatically, and can be +selected via the ``--fcompiler`` and ``--compiler`` options to +``setup.py``. Moreover, linking Fortran codes to static OpenBLAS is +supported; by default a gfortran compatible static archive +``openblas.a`` is looked for. + +``np.linalg.pinv`` now works on stacked matrices +------------------------------------------------ +Previously it was limited to a single 2d array. + +``numpy.save`` aligns data to 64 bytes instead of 16 +---------------------------------------------------- +Saving NumPy arrays in the ``npy`` format with ``numpy.save`` inserts +padding before the array data to align it at 64 bytes. Previously +this was only 16 bytes (and sometimes less due to a bug in the code +for version 2). Now the alignment is 64 bytes, which matches the +widest SIMD instruction set commonly available, and is also the most +common cache line size. This makes ``npy`` files easier to use in +programs which open them with ``mmap``, especially on Linux where an +``mmap`` offset must be a multiple of the page size. + +NPZ files now can be written without using temporary files +---------------------------------------------------------- +In Python 3.6+ ``numpy.savez`` and ``numpy.savez_compressed`` now write +directly to a ZIP file, without creating intermediate temporary files. + +Better support for empty structured and string types +---------------------------------------------------- +Structured types can contain zero fields, and string dtypes can contain zero +characters. Zero-length strings still cannot be created directly, and must be +constructed through structured dtypes:: + + str0 = np.empty(10, np.dtype([('v', str, N)]))['v'] + void0 = np.empty(10, np.void) + +It was always possible to work with these, but the following operations are +now supported for these arrays: + + * `arr.sort()` + * `arr.view(bytes)` + * `arr.resize(...)` + * `pickle.dumps(arr)` + +Support for ``decimal.Decimal`` in ``np.lib.financial`` +------------------------------------------------------- +Unless otherwise stated all functions within the ``financial`` package now +support using the ``decimal.Decimal`` built-in type. + +Float printing now uses "dragon4" algorithm for shortest decimal representation +------------------------------------------------------------------------------- +The ``str`` and ``repr`` of floating-point values (16, 32, 64 and 128 bit) are +now printed to give the shortest decimal representation which uniquely +identifies the value from others of the same type. Previously this was only +true for ``float64`` values. The remaining float types will now often be shorter +than in numpy 1.13. Arrays printed in scientific notation now also use the +shortest scientific representation, instead of fixed precision as before. + + Additionally, the `str` of float scalars scalars will no longer be truncated + in python2, unlike python2 `float`s. `np.double` scalars now have a ``str`` + and ``repr`` identical to that of a python3 float. + +New functions ``np.format_float_scientific`` and ``np.format_float_positional`` +are provided to generate these decimal representations. + +A new option ``floatmode`` has been added to ``np.set_printoptions`` and +``np.array2string``, which gives control over uniqueness and rounding of +printed elements in an array. The new default is ``floatmode='maxprec'`` with +``precision=8``, which will print at most 8 fractional digits, or fewer if an +element can be uniquely represented with fewer. A useful new mode is +``floatmode="unique"``, which will output enough digits to specify the array +elements uniquely. + +Numpy complex-floating-scalars with values like ``inf*j`` or ``nan*j`` now +print as ``infj`` and ``nanj``, like the pure-python ``complex`` type. + +The ``FloatFormat`` and ``LongFloatFormat`` classes are deprecated and should +both be replaced by ``FloatingFormat``. Similarly ``ComplexFormat`` and +``LongComplexFormat`` should be replaced by ``ComplexFloatingFormat``. + +``void`` datatype elements are now printed in hex notation +---------------------------------------------------------- +A hex representation compatible with the python ``bytes`` type is now printed +for unstructured ``np.void`` elements, e.g., ``V4`` datatype. Previously, in +python2 the raw void data of the element was printed to stdout, or in python3 +the integer byte values were shown. + +printing style for ``void`` datatypes is now independently customizable +----------------------------------------------------------------------- +The printing style of ``np.void`` arrays is now independently customizable +using the ``formatter`` argument to ``np.set_printoptions``, using the +``'void'`` key, instead of the catch-all ``numpystr`` key as before. + +Reduced memory usage of ``np.loadtxt`` +-------------------------------------- +``np.loadtxt`` now reads files in chunks instead of all at once which decreases +its memory usage significantly for large files. + + +Changes +======= + +Multiple-field indexing/assignment of structured arrays +------------------------------------------------------- +The indexing and assignment of structured arrays with multiple fields has +changed in a number of ways, as warned about in previous releases. + +First, indexing a structured array with multiple fields, e.g., +``arr[['f1', 'f3']]``, returns a view into the original array instead of a +copy. The returned view will have extra padding bytes corresponding to +intervening fields in the original array, unlike the copy in 1.13, which will +affect code such as ``arr[['f1', 'f3']].view(newdtype)``. + +Second, assignment between structured arrays will now occur "by position" +instead of "by field name". The Nth field of the destination will be set to the +Nth field of the source regardless of field name, unlike in numpy versions 1.6 +to 1.13 in which fields in the destination array were set to the +identically-named field in the source array or to 0 if the source did not have +a field. + +Correspondingly, the order of fields in a structured dtypes now matters when +computing dtype equality. For example, with the dtypes :: + + x = dtype({'names': ['A', 'B'], 'formats': ['i4', 'f4'], 'offsets': [0, 4]}) + y = dtype({'names': ['B', 'A'], 'formats': ['f4', 'i4'], 'offsets': [4, 0]}) + +the expression ``x == y`` will now return ``False``, unlike before. +This makes dictionary based dtype specifications like +``dtype({'a': ('i4', 0), 'b': ('f4', 4)})`` dangerous in python < 3.6 +since dict key order is not preserved in those versions. + +Assignment from a structured array to a boolean array now raises a ValueError, +unlike in 1.13, where it always set the destination elements to ``True``. + +Assignment from structured array with more than one field to a non-structured +array now raises a ValueError. In 1.13 this copied just the first field of the +source to the destination. + +Using field "titles" in multiple-field indexing is now disallowed, as is +repeating a field name in a multiple-field index. + +The documentation for structured arrays in the user guide has been +significantly updated to reflect these changes. + +Integer and Void scalars are now unaffected by ``np.set_string_function`` +------------------------------------------------------------------------- +Previously, unlike most other numpy scalars, the ``str`` and ``repr`` of +integer and void scalars could be controlled by ``np.set_string_function``. +This is no longer possible. + +0d array printing changed, ``style`` arg of array2string deprecated +------------------------------------------------------------------- +Previously the ``str`` and ``repr`` of 0d arrays had idiosyncratic +implementations which returned ``str(a.item())`` and ``'array(' + +repr(a.item()) + ')'`` respectively for 0d array ``a``, unlike both numpy +scalars and higher dimension ndarrays. + +Now, the ``str`` of a 0d array acts like a numpy scalar using ``str(a[()])`` +and the ``repr`` acts like higher dimension arrays using ``formatter(a[()])``, +where ``formatter`` can be specified using ``np.set_printoptions``. The +``style`` argument of ``np.array2string`` is deprecated. + +This new behavior is disabled in 1.13 legacy printing mode, see compatibility +notes above. + +Seeding ``RandomState`` using an array requires a 1-d array +----------------------------------------------------------- +``RandomState`` previously would accept empty arrays or arrays with 2 or more +dimensions, which resulted in either a failure to seed (empty arrays) or for +some of the passed values to be ignored when setting the seed. + +``MaskedArray`` objects show a more useful ``repr`` +--------------------------------------------------- +The ``repr`` of a ``MaskedArray`` is now closer to the python code that would +produce it, with arrays now being shown with commas and dtypes. Like the other +formatting changes, this can be disabled with the 1.13 legacy printing mode in +order to help transition doctests. + +The ``repr`` of ``np.polynomial`` classes is more explicit +---------------------------------------------------------- +It now shows the domain and window parameters as keyword arguments to make +them more clear:: + + >>> np.polynomial.Polynomial(range(4)) + Polynomial([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1]) diff --git a/doc/release/1.14.1-notes.rst b/doc/release/1.14.1-notes.rst new file mode 100644 index 0000000..c280c94 --- /dev/null +++ b/doc/release/1.14.1-notes.rst @@ -0,0 +1,92 @@ +========================== +NumPy 1.14.1 Release Notes +========================== + +This is a bugfix release for some problems reported following the 1.14.0 release. The major +problems fixed are the following. + +* Problems with the new array printing, particularly the printing of complex + values, Please report any additional problems that may turn up. +* Problems with ``np.einsum`` due to the new ``optimized=True`` default. Some + fixes for optimization have been applied and ``optimize=False`` is now the + default. +* The sort order in ``np.unique`` when ``axis=`` will now always + be lexicographic in the subarray elements. In previous NumPy versions there + was an optimization that could result in sorting the subarrays as unsigned + byte strings. +* The change in 1.14.0 that multi-field indexing of structured arrays returns a + view instead of a copy has been reverted but remains on track for NumPy 1.15. + Affected users should read the 1.14.1 Numpy User Guide section + "basics/structured arrays/accessing multiple fields" for advice on how to + manage this transition. + +The Python versions supported in this release are 2.7 and 3.4 - 3.6. The Python +3.6 wheels available from PIP are built with Python 3.6.2 and should be +compatible with all previous versions of Python 3.6. The source releases were +cythonized with Cython 0.26.1, which is known to **not** support the upcoming +Python 3.7 release. People who wish to run Python 3.7 should check out the +NumPy repo and try building with the, as yet, unreleased master branch of +Cython. + +Contributors +============ + +A total of 14 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Allan Haldane +* Charles Harris +* Daniel Smith +* Dennis Weyland + +* Eric Larson +* Eric Wieser +* Jarrod Millman +* Kenichi Maehashi + +* Marten van Kerkwijk +* Mathieu Lamarre +* Sebastian Berg +* Simon Conseil +* Simon Gibbons +* xoviat + +Pull requests merged +==================== + +A total of 36 pull requests were merged for this release. + +* `#10339 `__: BUG: restrict the __config__ modifications to win32 +* `#10368 `__: MAINT: Adjust type promotion in linalg.norm +* `#10375 `__: BUG: add missing paren and remove quotes from repr of fieldless... +* `#10395 `__: MAINT: Update download URL in setup.py. +* `#10396 `__: BUG: fix einsum issue with unicode input and py2 +* `#10397 `__: BUG: fix error message not formatted in einsum +* `#10398 `__: DOC: add documentation about how to handle new array printing +* `#10403 `__: BUG: Set einsum optimize parameter default to `False`. +* `#10424 `__: ENH: Fix repr of np.record objects to match np.void types #10412 +* `#10425 `__: MAINT: Update zesty to artful for i386 testing +* `#10431 `__: REL: Add 1.14.1 release notes template +* `#10435 `__: MAINT: Use ValueError for duplicate field names in lookup (backport) +* `#10534 `__: BUG: Provide a better error message for out-of-order fields +* `#10536 `__: BUG: Resize bytes_ columns in genfromtxt (backport of #10401) +* `#10537 `__: BUG: multifield-indexing adds padding bytes: revert for 1.14.1 +* `#10539 `__: BUG: fix np.save issue with python 2.7.5 +* `#10540 `__: BUG: Add missing DECREF in Py2 int() cast +* `#10541 `__: TST: Add circleci document testing to maintenance/1.14.x +* `#10542 `__: BUG: complex repr has extra spaces, missing + (1.14 backport) +* `#10550 `__: BUG: Set missing exception after malloc +* `#10557 `__: BUG: In numpy.i, clear CARRAY flag if wrapped buffer is not C_CONTIGUOUS. +* `#10558 `__: DEP: Issue FutureWarning when malformed records detected. +* `#10559 `__: BUG: Fix einsum optimize logic for singleton dimensions +* `#10560 `__: BUG: Fix calling ufuncs with a positional output argument. +* `#10561 `__: BUG: Fix various Big-Endian test failures (ppc64) +* `#10562 `__: BUG: Make dtype.descr error for out-of-order fields. +* `#10563 `__: BUG: arrays not being flattened in `union1d` +* `#10607 `__: MAINT: Update sphinxext submodule hash. +* `#10608 `__: BUG: Revert sort optimization in np.unique. +* `#10609 `__: BUG: infinite recursion in str of 0d subclasses +* `#10610 `__: BUG: Align type definition with generated lapack +* `#10612 `__: BUG/ENH: Improve output for structured non-void types +* `#10622 `__: BUG: deallocate recursive closure in arrayprint.py (1.14 backport) +* `#10624 `__: BUG: Correctly identify comma seperated dtype strings +* `#10629 `__: BUG: deallocate recursive closure in arrayprint.py (backport... +* `#10630 `__: REL: Prepare for 1.14.1 release. diff --git a/doc/release/1.14.2-notes.rst b/doc/release/1.14.2-notes.rst new file mode 100644 index 0000000..3f47cb5 --- /dev/null +++ b/doc/release/1.14.2-notes.rst @@ -0,0 +1,40 @@ +========================== +NumPy 1.14.2 Release Notes +========================== + +This is a bugfix release for some bugs reported following the 1.14.1 release. The major +problems dealt with are as follows. + +* Residual bugs in the new array printing functionality. +* Regression resulting in a relocation problem with shared library. +* Improved PyPy compatibility. + +The Python versions supported in this release are 2.7 and 3.4 - 3.6. The Python +3.6 wheels available from PIP are built with Python 3.6.2 and should be +compatible with all previous versions of Python 3.6. The source releases were +cythonized with Cython 0.26.1, which is known to **not** support the upcoming +Python 3.7 release. People who wish to run Python 3.7 should check out the +NumPy repo and try building with the, as yet, unreleased master branch of +Cython. + +Contributors +============ + +A total of 4 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Allan Haldane +* Charles Harris +* Eric Wieser +* Pauli Virtanen + +Pull requests merged +==================== + +A total of 5 pull requests were merged for this release. + +* `#10674 `__: BUG: Further back-compat fix for subclassed array repr +* `#10725 `__: BUG: dragon4 fractional output mode adds too many trailing zeros +* `#10726 `__: BUG: Fix f2py generated code to work on PyPy +* `#10727 `__: BUG: Fix missing NPY_VISIBILITY_HIDDEN on npy_longdouble_to_PyLong +* `#10729 `__: DOC: Create 1.14.2 notes and changelog. diff --git a/doc/release/1.14.3-notes.rst b/doc/release/1.14.3-notes.rst new file mode 100644 index 0000000..60b6311 --- /dev/null +++ b/doc/release/1.14.3-notes.rst @@ -0,0 +1,41 @@ +========================== +NumPy 1.14.3 Release Notes +========================== + +This is a bugfix release for a few bugs reported following the 1.14.2 release: + +* np.lib.recfunctions.fromrecords accepts a list-of-lists, until 1.15 +* In python2, float types use the new print style when printing to a file +* style arg in "legacy" print mode now works for 0d arrays + +The Python versions supported in this release are 2.7 and 3.4 - 3.6. The Python +3.6 wheels available from PIP are built with Python 3.6.2 and should be +compatible with all previous versions of Python 3.6. The source releases were +cythonized with Cython 0.28.2. + +Contributors +============ + +A total of 6 people contributed to this release. People with a "+" by their +names contributed a patch for the first time. + +* Allan Haldane +* Charles Harris +* Jonathan March + +* Malcolm Smith + +* Matti Picus +* Pauli Virtanen + +Pull requests merged +==================== + +A total of 8 pull requests were merged for this release. + +* `#10862 `__: BUG: floating types should override tp_print (1.14 backport) +* `#10905 `__: BUG: for 1.14 back-compat, accept list-of-lists in fromrecords +* `#10947 `__: BUG: 'style' arg to array2string broken in legacy mode (1.14... +* `#10959 `__: BUG: test, fix for missing flags['WRITEBACKIFCOPY'] key +* `#10960 `__: BUG: Add missing underscore to prototype in check_embedded_lapack +* `#10961 `__: BUG: Fix encoding regression in ma/bench.py (Issue #10868) +* `#10962 `__: BUG: core: fix NPY_TITLE_KEY macro on pypy +* `#10974 `__: BUG: test, fix PyArray_DiscardWritebackIfCopy... diff --git a/doc/release/1.3.0-notes.rst b/doc/release/1.3.0-notes.rst new file mode 100644 index 0000000..246ec58 --- /dev/null +++ b/doc/release/1.3.0-notes.rst @@ -0,0 +1,278 @@ +========================= +NumPy 1.3.0 Release Notes +========================= + +This minor includes numerous bug fixes, official python 2.6 support, and +several new features such as generalized ufuncs. + +Highlights +========== + +Python 2.6 support +------------------ + +Python 2.6 is now supported on all previously supported platforms, including +windows. + +http://www.python.org/dev/peps/pep-0361/ + +Generalized ufuncs +------------------ + +There is a general need for looping over not only functions on scalars but also +over functions on vectors (or arrays), as explained on +http://scipy.org/scipy/numpy/wiki/GeneralLoopingFunctions. We propose to +realize this concept by generalizing the universal functions (ufuncs), and +provide a C implementation that adds ~500 lines to the numpy code base. In +current (specialized) ufuncs, the elementary function is limited to +element-by-element operations, whereas the generalized version supports +"sub-array" by "sub-array" operations. The Perl vector library PDL provides a +similar functionality and its terms are re-used in the following. + +Each generalized ufunc has information associated with it that states what the +"core" dimensionality of the inputs is, as well as the corresponding +dimensionality of the outputs (the element-wise ufuncs have zero core +dimensions). The list of the core dimensions for all arguments is called the +"signature" of a ufunc. For example, the ufunc numpy.add has signature +"(),()->()" defining two scalar inputs and one scalar output. + +Another example is (see the GeneralLoopingFunctions page) the function +inner1d(a,b) with a signature of "(i),(i)->()". This applies the inner product +along the last axis of each input, but keeps the remaining indices intact. For +example, where a is of shape (3,5,N) and b is of shape (5,N), this will return +an output of shape (3,5). The underlying elementary function is called 3*5 +times. In the signature, we specify one core dimension "(i)" for each input and +zero core dimensions "()" for the output, since it takes two 1-d arrays and +returns a scalar. By using the same name "i", we specify that the two +corresponding dimensions should be of the same size (or one of them is of size +1 and will be broadcasted). + +The dimensions beyond the core dimensions are called "loop" dimensions. In the +above example, this corresponds to (3,5). + +The usual numpy "broadcasting" rules apply, where the signature determines how +the dimensions of each input/output object are split into core and loop +dimensions: + +While an input array has a smaller dimensionality than the corresponding number +of core dimensions, 1's are pre-pended to its shape. The core dimensions are +removed from all inputs and the remaining dimensions are broadcasted; defining +the loop dimensions. The output is given by the loop dimensions plus the +output core dimensions. + +Experimental Windows 64 bits support +------------------------------------ + +Numpy can now be built on windows 64 bits (amd64 only, not IA64), with both MS +compilers and mingw-w64 compilers: + +This is *highly experimental*: DO NOT USE FOR PRODUCTION USE. See INSTALL.txt, +Windows 64 bits section for more information on limitations and how to build it +by yourself. + +New features +============ + +Formatting issues +----------------- + +Float formatting is now handled by numpy instead of the C runtime: this enables +locale independent formatting, more robust fromstring and related methods. +Special values (inf and nan) are also more consistent across platforms (nan vs +IND/NaN, etc...), and more consistent with recent python formatting work (in +2.6 and later). + +Nan handling in max/min +----------------------- + +The maximum/minimum ufuncs now reliably propagate nans. If one of the +arguments is a nan, then nan is returned. This affects np.min/np.max, amin/amax +and the array methods max/min. New ufuncs fmax and fmin have been added to deal +with non-propagating nans. + +Nan handling in sign +-------------------- + +The ufunc sign now returns nan for the sign of anan. + + +New ufuncs +---------- + +#. fmax - same as maximum for integer types and non-nan floats. Returns the + non-nan argument if one argument is nan and returns nan if both arguments + are nan. +#. fmin - same as minimum for integer types and non-nan floats. Returns the + non-nan argument if one argument is nan and returns nan if both arguments + are nan. +#. deg2rad - converts degrees to radians, same as the radians ufunc. +#. rad2deg - converts radians to degrees, same as the degrees ufunc. +#. log2 - base 2 logarithm. +#. exp2 - base 2 exponential. +#. trunc - truncate floats to nearest integer towards zero. +#. logaddexp - add numbers stored as logarithms and return the logarithm + of the result. +#. logaddexp2 - add numbers stored as base 2 logarithms and return the base 2 + logarithm of the result. + +Masked arrays +------------- + +Several new features and bug fixes, including: + + * structured arrays should now be fully supported by MaskedArray + (r6463, r6324, r6305, r6300, r6294...) + * Minor bug fixes (r6356, r6352, r6335, r6299, r6298) + * Improved support for __iter__ (r6326) + * made baseclass, sharedmask and hardmask accessible to the user (but + read-only) + * doc update + +gfortran support on windows +--------------------------- + +Gfortran can now be used as a fortran compiler for numpy on windows, even when +the C compiler is Visual Studio (VS 2005 and above; VS 2003 will NOT work). +Gfortran + Visual studio does not work on windows 64 bits (but gcc + gfortran +does). It is unclear whether it will be possible to use gfortran and visual +studio at all on x64. + +Arch option for windows binary +------------------------------ + +Automatic arch detection can now be bypassed from the command line for the superpack installed: + + numpy-1.3.0-superpack-win32.exe /arch=nosse + +will install a numpy which works on any x86, even if the running computer +supports SSE set. + +Deprecated features +=================== + +Histogram +--------- + +The semantics of histogram has been modified to fix long-standing issues +with outliers handling. The main changes concern + +#. the definition of the bin edges, now including the rightmost edge, and +#. the handling of upper outliers, now ignored rather than tallied in the + rightmost bin. + +The previous behavior is still accessible using `new=False`, but this is +deprecated, and will be removed entirely in 1.4.0. + +Documentation changes +===================== + +A lot of documentation has been added. Both user guide and references can be +built from sphinx. + +New C API +========= + +Multiarray API +-------------- + +The following functions have been added to the multiarray C API: + + * PyArray_GetEndianness: to get runtime endianness + +Ufunc API +--------- + +The following functions have been added to the ufunc API: + + * PyUFunc_FromFuncAndDataAndSignature: to declare a more general ufunc + (generalized ufunc). + + +New defines +----------- + +New public C defines are available for ARCH specific code through numpy/npy_cpu.h: + + * NPY_CPU_X86: x86 arch (32 bits) + * NPY_CPU_AMD64: amd64 arch (x86_64, NOT Itanium) + * NPY_CPU_PPC: 32 bits ppc + * NPY_CPU_PPC64: 64 bits ppc + * NPY_CPU_SPARC: 32 bits sparc + * NPY_CPU_SPARC64: 64 bits sparc + * NPY_CPU_S390: S390 + * NPY_CPU_IA64: ia64 + * NPY_CPU_PARISC: PARISC + +New macros for CPU endianness has been added as well (see internal changes +below for details): + + * NPY_BYTE_ORDER: integer + * NPY_LITTLE_ENDIAN/NPY_BIG_ENDIAN defines + +Those provide portable alternatives to glibc endian.h macros for platforms +without it. + +Portable NAN, INFINITY, etc... +------------------------------ + +npy_math.h now makes available several portable macro to get NAN, INFINITY: + + * NPY_NAN: equivalent to NAN, which is a GNU extension + * NPY_INFINITY: equivalent to C99 INFINITY + * NPY_PZERO, NPY_NZERO: positive and negative zero respectively + +Corresponding single and extended precision macros are available as well. All +references to NAN, or home-grown computation of NAN on the fly have been +removed for consistency. + +Internal changes +================ + +numpy.core math configuration revamp +------------------------------------ + +This should make the porting to new platforms easier, and more robust. In +particular, the configuration stage does not need to execute any code on the +target platform, which is a first step toward cross-compilation. + +http://projects.scipy.org/numpy/browser/trunk/doc/neps/math_config_clean.txt + +umath refactor +-------------- + +A lot of code cleanup for umath/ufunc code (charris). + +Improvements to build warnings +------------------------------ + +Numpy can now build with -W -Wall without warnings + +http://projects.scipy.org/numpy/browser/trunk/doc/neps/warnfix.txt + +Separate core math library +-------------------------- + +The core math functions (sin, cos, etc... for basic C types) have been put into +a separate library; it acts as a compatibility layer, to support most C99 maths +functions (real only for now). The library includes platform-specific fixes for +various maths functions, such as using those versions should be more robust +than using your platform functions directly. The API for existing functions is +exactly the same as the C99 math functions API; the only difference is the npy +prefix (npy_cos vs cos). + +The core library will be made available to any extension in 1.4.0. + +CPU arch detection +------------------ + +npy_cpu.h defines numpy specific CPU defines, such as NPY_CPU_X86, etc... +Those are portable across OS and toolchains, and set up when the header is +parsed, so that they can be safely used even in the case of cross-compilation +(the values is not set when numpy is built), or for multi-arch binaries (e.g. +fat binaries on Max OS X). + +npy_endian.h defines numpy specific endianness defines, modeled on the glibc +endian.h. NPY_BYTE_ORDER is equivalent to BYTE_ORDER, and one of +NPY_LITTLE_ENDIAN or NPY_BIG_ENDIAN is defined. As for CPU archs, those are set +when the header is parsed by the compiler, and as such can be used for +cross-compilation and multi-arch binaries. diff --git a/doc/release/1.4.0-notes.rst b/doc/release/1.4.0-notes.rst new file mode 100644 index 0000000..9480a05 --- /dev/null +++ b/doc/release/1.4.0-notes.rst @@ -0,0 +1,238 @@ +========================= +NumPy 1.4.0 Release Notes +========================= + +This minor includes numerous bug fixes, as well as a few new features. It +is backward compatible with 1.3.0 release. + +Highlights +========== + +* New datetime dtype support to deal with dates in arrays + +* Faster import time + +* Extended array wrapping mechanism for ufuncs + +* New Neighborhood iterator (C-level only) + +* C99-like complex functions in npymath + +New features +============ + +Extended array wrapping mechanism for ufuncs +-------------------------------------------- + +An __array_prepare__ method has been added to ndarray to provide subclasses +greater flexibility to interact with ufuncs and ufunc-like functions. ndarray +already provided __array_wrap__, which allowed subclasses to set the array type +for the result and populate metadata on the way out of the ufunc (as seen in +the implementation of MaskedArray). For some applications it is necessary to +provide checks and populate metadata *on the way in*. __array_prepare__ is +therefore called just after the ufunc has initialized the output array but +before computing the results and populating it. This way, checks can be made +and errors raised before operations which may modify data in place. + +Automatic detection of forward incompatibilities +------------------------------------------------ + +Previously, if an extension was built against a version N of NumPy, and used on +a system with NumPy M < N, the import_array was successful, which could cause +crashes because the version M does not have a function in N. Starting from +NumPy 1.4.0, this will cause a failure in import_array, so the error will be +caught early on. + +New iterators +------------- + +A new neighborhood iterator has been added to the C API. It can be used to +iterate over the items in a neighborhood of an array, and can handle boundaries +conditions automatically. Zero and one padding are available, as well as +arbitrary constant value, mirror and circular padding. + +New polynomial support +---------------------- + +New modules chebyshev and polynomial have been added. The new polynomial module +is not compatible with the current polynomial support in numpy, but is much +like the new chebyshev module. The most noticeable difference to most will +be that coefficients are specified from low to high power, that the low +level functions do *not* work with the Chebyshev and Polynomial classes as +arguments, and that the Chebyshev and Polynomial classes include a domain. +Mapping between domains is a linear substitution and the two classes can be +converted one to the other, allowing, for instance, a Chebyshev series in +one domain to be expanded as a polynomial in another domain. The new classes +should generally be used instead of the low level functions, the latter are +provided for those who wish to build their own classes. + +The new modules are not automatically imported into the numpy namespace, +they must be explicitly brought in with an "import numpy.polynomial" +statement. + +New C API +--------- + +The following C functions have been added to the C API: + + #. PyArray_GetNDArrayCFeatureVersion: return the *API* version of the + loaded numpy. + #. PyArray_Correlate2 - like PyArray_Correlate, but implements the usual + definition of correlation. Inputs are not swapped, and conjugate is + taken for complex arrays. + #. PyArray_NeighborhoodIterNew - a new iterator to iterate over a + neighborhood of a point, with automatic boundaries handling. It is + documented in the iterators section of the C-API reference, and you can + find some examples in the multiarray_test.c.src file in numpy.core. + +New ufuncs +---------- + +The following ufuncs have been added to the C API: + + #. copysign - return the value of the first argument with the sign copied + from the second argument. + #. nextafter - return the next representable floating point value of the + first argument toward the second argument. + +New defines +----------- + +The alpha processor is now defined and available in numpy/npy_cpu.h. The +failed detection of the PARISC processor has been fixed. The defines are: + + #. NPY_CPU_HPPA: PARISC + #. NPY_CPU_ALPHA: Alpha + +Testing +------- + + #. deprecated decorator: this decorator may be used to avoid cluttering + testing output while testing DeprecationWarning is effectively raised by + the decorated test. + #. assert_array_almost_equal_nulps: new method to compare two arrays of + floating point values. With this function, two values are considered + close if there are not many representable floating point values in + between, thus being more robust than assert_array_almost_equal when the + values fluctuate a lot. + #. assert_array_max_ulp: raise an assertion if there are more than N + representable numbers between two floating point values. + #. assert_warns: raise an AssertionError if a callable does not generate a + warning of the appropriate class, without altering the warning state. + +Reusing npymath +--------------- + +In 1.3.0, we started putting portable C math routines in npymath library, so +that people can use those to write portable extensions. Unfortunately, it was +not possible to easily link against this library: in 1.4.0, support has been +added to numpy.distutils so that 3rd party can reuse this library. See coremath +documentation for more information. + +Improved set operations +----------------------- + +In previous versions of NumPy some set functions (intersect1d, +setxor1d, setdiff1d and setmember1d) could return incorrect results if +the input arrays contained duplicate items. These now work correctly +for input arrays with duplicates. setmember1d has been renamed to +in1d, as with the change to accept arrays with duplicates it is +no longer a set operation, and is conceptually similar to an +elementwise version of the Python operator 'in'. All of these +functions now accept the boolean keyword assume_unique. This is False +by default, but can be set True if the input arrays are known not +to contain duplicates, which can increase the functions' execution +speed. + +Improvements +============ + + #. numpy import is noticeably faster (from 20 to 30 % depending on the + platform and computer) + + #. The sort functions now sort nans to the end. + + * Real sort order is [R, nan] + * Complex sort order is [R + Rj, R + nanj, nan + Rj, nan + nanj] + + Complex numbers with the same nan placements are sorted according to + the non-nan part if it exists. + #. The type comparison functions have been made consistent with the new + sort order of nans. Searchsorted now works with sorted arrays + containing nan values. + #. Complex division has been made more resistant to overflow. + #. Complex floor division has been made more resistant to overflow. + +Deprecations +============ + +The following functions are deprecated: + + #. correlate: it takes a new keyword argument old_behavior. When True (the + default), it returns the same result as before. When False, compute the + conventional correlation, and take the conjugate for complex arrays. The + old behavior will be removed in NumPy 1.5, and raises a + DeprecationWarning in 1.4. + + #. unique1d: use unique instead. unique1d raises a deprecation + warning in 1.4, and will be removed in 1.5. + + #. intersect1d_nu: use intersect1d instead. intersect1d_nu raises + a deprecation warning in 1.4, and will be removed in 1.5. + + #. setmember1d: use in1d instead. setmember1d raises a deprecation + warning in 1.4, and will be removed in 1.5. + +The following raise errors: + + #. When operating on 0-d arrays, ``numpy.max`` and other functions accept + only ``axis=0``, ``axis=-1`` and ``axis=None``. Using an out-of-bounds + axes is an indication of a bug, so Numpy raises an error for these cases + now. + + #. Specifying ``axis > MAX_DIMS`` is no longer allowed; Numpy raises now an + error instead of behaving similarly as for ``axis=None``. + +Internal changes +================ + +Use C99 complex functions when available +---------------------------------------- + +The numpy complex types are now guaranteed to be ABI compatible with C99 +complex type, if available on the platform. Moreover, the complex ufunc now use +the platform C99 functions instead of our own. + +split multiarray and umath source code +-------------------------------------- + +The source code of multiarray and umath has been split into separate logic +compilation units. This should make the source code more amenable for +newcomers. + +Separate compilation +-------------------- + +By default, every file of multiarray (and umath) is merged into one for +compilation as was the case before, but if NPY_SEPARATE_COMPILATION env +variable is set to a non-negative value, experimental individual compilation of +each file is enabled. This makes the compile/debug cycle much faster when +working on core numpy. + +Separate core math library +-------------------------- + +New functions which have been added: + + * npy_copysign + * npy_nextafter + * npy_cpack + * npy_creal + * npy_cimag + * npy_cabs + * npy_cexp + * npy_clog + * npy_cpow + * npy_csqr + * npy_ccos + * npy_csin diff --git a/doc/release/1.5.0-notes.rst b/doc/release/1.5.0-notes.rst new file mode 100644 index 0000000..a2184ab --- /dev/null +++ b/doc/release/1.5.0-notes.rst @@ -0,0 +1,131 @@ +========================= +NumPy 1.5.0 Release Notes +========================= + + +Highlights +========== + +Python 3 compatibility +---------------------- + +This is the first NumPy release which is compatible with Python 3. Support for +Python 3 and Python 2 is done from a single code base. Extensive notes on +changes can be found at +``_. + +Note that the Numpy testing framework relies on nose, which does not have a +Python 3 compatible release yet. A working Python 3 branch of nose can be found +at ``_ however. + +Porting of SciPy to Python 3 is expected to be completed soon. + +:pep:`3118` compatibility +------------------------- + +The new buffer protocol described by PEP 3118 is fully supported in this +version of Numpy. On Python versions >= 2.6 Numpy arrays expose the buffer +interface, and array(), asarray() and other functions accept new-style buffers +as input. + + +New features +============ + +Warning on casting complex to real +---------------------------------- + +Numpy now emits a `numpy.ComplexWarning` when a complex number is cast +into a real number. For example: + + >>> x = np.array([1,2,3]) + >>> x[:2] = np.array([1+2j, 1-2j]) + ComplexWarning: Casting complex values to real discards the imaginary part + +The cast indeed discards the imaginary part, and this may not be the +intended behavior in all cases, hence the warning. This warning can be +turned off in the standard way: + + >>> import warnings + >>> warnings.simplefilter("ignore", np.ComplexWarning) + +Dot method for ndarrays +----------------------- + +Ndarrays now have the dot product also as a method, which allows writing +chains of matrix products as + + >>> a.dot(b).dot(c) + +instead of the longer alternative + + >>> np.dot(a, np.dot(b, c)) + +linalg.slogdet function +----------------------- + +The slogdet function returns the sign and logarithm of the determinant +of a matrix. Because the determinant may involve the product of many +small/large values, the result is often more accurate than that obtained +by simple multiplication. + +new header +---------- + +The new header file ndarraytypes.h contains the symbols from +ndarrayobject.h that do not depend on the PY_ARRAY_UNIQUE_SYMBOL and +NO_IMPORT/_ARRAY macros. Broadly, these symbols are types, typedefs, +and enumerations; the array function calls are left in +ndarrayobject.h. This allows users to include array-related types and +enumerations without needing to concern themselves with the macro +expansions and their side- effects. + + +Changes +======= + +polynomial.polynomial +--------------------- + +* The polyint and polyder functions now check that the specified number + integrations or derivations is a non-negative integer. The number 0 is + a valid value for both functions. +* A degree method has been added to the Polynomial class. +* A trimdeg method has been added to the Polynomial class. It operates like + truncate except that the argument is the desired degree of the result, + not the number of coefficients. +* Polynomial.fit now uses None as the default domain for the fit. The default + Polynomial domain can be specified by using [] as the domain value. +* Weights can be used in both polyfit and Polynomial.fit +* A linspace method has been added to the Polynomial class to ease plotting. +* The polymulx function was added. + +polynomial.chebyshev +-------------------- + +* The chebint and chebder functions now check that the specified number + integrations or derivations is a non-negative integer. The number 0 is + a valid value for both functions. +* A degree method has been added to the Chebyshev class. +* A trimdeg method has been added to the Chebyshev class. It operates like + truncate except that the argument is the desired degree of the result, + not the number of coefficients. +* Chebyshev.fit now uses None as the default domain for the fit. The default + Chebyshev domain can be specified by using [] as the domain value. +* Weights can be used in both chebfit and Chebyshev.fit +* A linspace method has been added to the Chebyshev class to ease plotting. +* The chebmulx function was added. +* Added functions for the Chebyshev points of the first and second kind. + + +histogram +--------- + +After a two years transition period, the old behavior of the histogram function +has been phased out, and the "new" keyword has been removed. + +correlate +--------- + +The old behavior of correlate was deprecated in 1.4.0, the new behavior (the +usual definition for cross-correlation) is now the default. diff --git a/doc/release/1.6.0-notes.rst b/doc/release/1.6.0-notes.rst new file mode 100644 index 0000000..c5f53a0 --- /dev/null +++ b/doc/release/1.6.0-notes.rst @@ -0,0 +1,177 @@ +========================= +NumPy 1.6.0 Release Notes +========================= + +This release includes several new features as well as numerous bug fixes and +improved documentation. It is backward compatible with the 1.5.0 release, and +supports Python 2.4 - 2.7 and 3.1 - 3.2. + + +Highlights +========== + +* Re-introduction of datetime dtype support to deal with dates in arrays. + +* A new 16-bit floating point type. + +* A new iterator, which improves performance of many functions. + + +New features +============ + +New 16-bit floating point type +------------------------------ + +This release adds support for the IEEE 754-2008 binary16 format, available as +the data type ``numpy.half``. Within Python, the type behaves similarly to +`float` or `double`, and C extensions can add support for it with the exposed +half-float API. + + +New iterator +------------ + +A new iterator has been added, replacing the functionality of the +existing iterator and multi-iterator with a single object and API. +This iterator works well with general memory layouts different from +C or Fortran contiguous, and handles both standard NumPy and +customized broadcasting. The buffering, automatic data type +conversion, and optional output parameters, offered by +ufuncs but difficult to replicate elsewhere, are now exposed by this +iterator. + + +Legendre, Laguerre, Hermite, HermiteE polynomials in ``numpy.polynomial`` +------------------------------------------------------------------------- + +Extend the number of polynomials available in the polynomial package. In +addition, a new ``window`` attribute has been added to the classes in +order to specify the range the ``domain`` maps to. This is mostly useful +for the Laguerre, Hermite, and HermiteE polynomials whose natural domains +are infinite and provides a more intuitive way to get the correct mapping +of values without playing unnatural tricks with the domain. + + +Fortran assumed shape array and size function support in ``numpy.f2py`` +----------------------------------------------------------------------- + +F2py now supports wrapping Fortran 90 routines that use assumed shape +arrays. Before such routines could be called from Python but the +corresponding Fortran routines received assumed shape arrays as zero +length arrays which caused unpredicted results. Thanks to Lorenz +Hüdepohl for pointing out the correct way to interface routines with +assumed shape arrays. + +In addition, f2py supports now automatic wrapping of Fortran routines +that use two argument ``size`` function in dimension specifications. + + +Other new functions +------------------- + +``numpy.ravel_multi_index`` : Converts a multi-index tuple into +an array of flat indices, applying boundary modes to the indices. + +``numpy.einsum`` : Evaluate the Einstein summation convention. Using the +Einstein summation convention, many common multi-dimensional array operations +can be represented in a simple fashion. This function provides a way compute +such summations. + +``numpy.count_nonzero`` : Counts the number of non-zero elements in an array. + +``numpy.result_type`` and ``numpy.min_scalar_type`` : These functions expose +the underlying type promotion used by the ufuncs and other operations to +determine the types of outputs. These improve upon the ``numpy.common_type`` +and ``numpy.mintypecode`` which provide similar functionality but do +not match the ufunc implementation. + + +Changes +======= + +``default error handling`` +-------------------------- + +The default error handling has been change from ``print`` to ``warn`` for +all except for ``underflow``, which remains as ``ignore``. + + +``numpy.distutils`` +------------------- + +Several new compilers are supported for building Numpy: the Portland Group +Fortran compiler on OS X, the PathScale compiler suite and the 64-bit Intel C +compiler on Linux. + + +``numpy.testing`` +----------------- + +The testing framework gained ``numpy.testing.assert_allclose``, which provides +a more convenient way to compare floating point arrays than +`assert_almost_equal`, `assert_approx_equal` and `assert_array_almost_equal`. + + +``C API`` +--------- + +In addition to the APIs for the new iterator and half data type, a number +of other additions have been made to the C API. The type promotion +mechanism used by ufuncs is exposed via ``PyArray_PromoteTypes``, +``PyArray_ResultType``, and ``PyArray_MinScalarType``. A new enumeration +``NPY_CASTING`` has been added which controls what types of casts are +permitted. This is used by the new functions ``PyArray_CanCastArrayTo`` +and ``PyArray_CanCastTypeTo``. A more flexible way to handle +conversion of arbitrary python objects into arrays is exposed by +``PyArray_GetArrayParamsFromObject``. + + +Deprecated features +=================== + +The "normed" keyword in ``numpy.histogram`` is deprecated. Its functionality +will be replaced by the new "density" keyword. + + +Removed features +================ + +``numpy.fft`` +------------- + +The functions `refft`, `refft2`, `refftn`, `irefft`, `irefft2`, `irefftn`, +which were aliases for the same functions without the 'e' in the name, were +removed. + + +``numpy.memmap`` +---------------- + +The `sync()` and `close()` methods of memmap were removed. Use `flush()` and +"del memmap" instead. + + +``numpy.lib`` +------------- + +The deprecated functions ``numpy.unique1d``, ``numpy.setmember1d``, +``numpy.intersect1d_nu`` and ``numpy.lib.ufunclike.log2`` were removed. + + +``numpy.ma`` +------------ + +Several deprecated items were removed from the ``numpy.ma`` module:: + + * ``numpy.ma.MaskedArray`` "raw_data" method + * ``numpy.ma.MaskedArray`` constructor "flag" keyword + * ``numpy.ma.make_mask`` "flag" keyword + * ``numpy.ma.allclose`` "fill_value" keyword + + +``numpy.distutils`` +------------------- + +The ``numpy.get_numpy_include`` function was removed, use ``numpy.get_include`` +instead. diff --git a/doc/release/1.6.1-notes.rst b/doc/release/1.6.1-notes.rst new file mode 100644 index 0000000..05fcb4a --- /dev/null +++ b/doc/release/1.6.1-notes.rst @@ -0,0 +1,21 @@ +========================= +NumPy 1.6.1 Release Notes +========================= + +This is a bugfix only release in the 1.6.x series. + + +Issues Fixed +============ + +* #1834: einsum fails for specific shapes +* #1837: einsum throws nan or freezes python for specific array shapes +* #1838: object <-> structured type arrays regression +* #1851: regression for SWIG based code in 1.6.0 +* #1863: Buggy results when operating on array copied with astype() +* #1870: Fix corner case of object array assignment +* #1843: Py3k: fix error with recarray +* #1885: nditer: Error in detecting double reduction loop +* #1874: f2py: fix --include_paths bug +* #1749: Fix ctypes.load_library() +* #1895/1896: iter: writeonly operands weren't always being buffered correctly diff --git a/doc/release/1.6.2-notes.rst b/doc/release/1.6.2-notes.rst new file mode 100644 index 0000000..8f0b06f --- /dev/null +++ b/doc/release/1.6.2-notes.rst @@ -0,0 +1,93 @@ +========================= +NumPy 1.6.2 Release Notes +========================= + +This is a bugfix release in the 1.6.x series. Due to the delay of the NumPy +1.7.0 release, this release contains far more fixes than a regular NumPy bugfix +release. It also includes a number of documentation and build improvements. + +Issues fixed +============ + +``numpy.core`` +-------------- + +* #2063: make unique() return consistent index +* #1138: allow creating arrays from empty buffers or empty slices +* #1446: correct note about correspondence vstack and concatenate +* #1149: make argmin() work for datetime +* #1672: fix allclose() to work for scalar inf +* #1747: make np.median() work for 0-D arrays +* #1776: make complex division by zero to yield inf properly +* #1675: add scalar support for the format() function +* #1905: explicitly check for NaNs in allclose() +* #1952: allow floating ddof in std() and var() +* #1948: fix regression for indexing chararrays with empty list +* #2017: fix type hashing +* #2046: deleting array attributes causes segfault +* #2033: a**2.0 has incorrect type +* #2045: make attribute/iterator_element deletions not segfault +* #2021: fix segfault in searchsorted() +* #2073: fix float16 __array_interface__ bug + + +``numpy.lib`` +------------- + +* #2048: break reference cycle in NpzFile +* #1573: savetxt() now handles complex arrays +* #1387: allow bincount() to accept empty arrays +* #1899: fixed histogramdd() bug with empty inputs +* #1793: fix failing npyio test under py3k +* #1936: fix extra nesting for subarray dtypes +* #1848: make tril/triu return the same dtype as the original array +* #1918: use Py_TYPE to access ob_type, so it works also on Py3 + + +``numpy.distutils`` +------------------- + +* #1261: change compile flag on AIX from -O5 to -O3 +* #1377: update HP compiler flags +* #1383: provide better support for C++ code on HPUX +* #1857: fix build for py3k + pip +* BLD: raise a clearer warning in case of building without cleaning up first +* BLD: follow build_ext coding convention in build_clib +* BLD: fix up detection of Intel CPU on OS X in system_info.py +* BLD: add support for the new X11 directory structure on Ubuntu & co. +* BLD: add ufsparse to the libraries search path. +* BLD: add 'pgfortran' as a valid compiler in the Portland Group +* BLD: update version match regexp for IBM AIX Fortran compilers. + + +``numpy.random`` +---------------- + +* BUG: Use npy_intp instead of long in mtrand + +Changes +======= + +``numpy.f2py`` +-------------- + +* ENH: Introduce new options extra_f77_compiler_args and extra_f90_compiler_args +* BLD: Improve reporting of fcompiler value +* BUG: Fix f2py test_kind.py test + + +``numpy.poly`` +-------------- + +* ENH: Add some tests for polynomial printing +* ENH: Add companion matrix functions +* DOC: Rearrange the polynomial documents +* BUG: Fix up links to classes +* DOC: Add version added to some of the polynomial package modules +* DOC: Document xxxfit functions in the polynomial package modules +* BUG: The polynomial convenience classes let different types interact +* DOC: Document the use of the polynomial convenience classes +* DOC: Improve numpy reference documentation of polynomial classes +* ENH: Improve the computation of polynomials from roots +* STY: Code cleanup in polynomial [*]fromroots functions +* DOC: Remove references to cast and NA, which were added in 1.7 diff --git a/doc/release/1.7.0-notes.rst b/doc/release/1.7.0-notes.rst new file mode 100644 index 0000000..72aab4d --- /dev/null +++ b/doc/release/1.7.0-notes.rst @@ -0,0 +1,289 @@ +========================= +NumPy 1.7.0 Release Notes +========================= + +This release includes several new features as well as numerous bug fixes and +refactorings. It supports Python 2.4 - 2.7 and 3.1 - 3.3 and is the last +release that supports Python 2.4 - 2.5. + +Highlights +========== + +* ``where=`` parameter to ufuncs (allows the use of boolean arrays to choose + where a computation should be done) +* ``vectorize`` improvements (added 'excluded' and 'cache' keyword, general + cleanup and bug fixes) +* ``numpy.random.choice`` (random sample generating function) + + +Compatibility notes +=================== + +In a future version of numpy, the functions np.diag, np.diagonal, and the +diagonal method of ndarrays will return a view onto the original array, +instead of producing a copy as they do now. This makes a difference if you +write to the array returned by any of these functions. To facilitate this +transition, numpy 1.7 produces a FutureWarning if it detects that you may +be attempting to write to such an array. See the documentation for +np.diagonal for details. + +Similar to np.diagonal above, in a future version of numpy, indexing a +record array by a list of field names will return a view onto the original +array, instead of producing a copy as they do now. As with np.diagonal, +numpy 1.7 produces a FutureWarning if it detects that you may be attempting +to write to such an array. See the documentation for array indexing for +details. + +In a future version of numpy, the default casting rule for UFunc out= +parameters will be changed from 'unsafe' to 'same_kind'. (This also applies +to in-place operations like a += b, which is equivalent to np.add(a, b, +out=a).) Most usages which violate the 'same_kind' rule are likely bugs, so +this change may expose previously undetected errors in projects that depend +on NumPy. In this version of numpy, such usages will continue to succeed, +but will raise a DeprecationWarning. + +Full-array boolean indexing has been optimized to use a different, +optimized code path. This code path should produce the same results, +but any feedback about changes to your code would be appreciated. + +Attempting to write to a read-only array (one with ``arr.flags.writeable`` +set to ``False``) used to raise either a RuntimeError, ValueError, or +TypeError inconsistently, depending on which code path was taken. It now +consistently raises a ValueError. + +The .reduce functions evaluate some reductions in a different order +than in previous versions of NumPy, generally providing higher performance. +Because of the nature of floating-point arithmetic, this may subtly change +some results, just as linking NumPy to a different BLAS implementations +such as MKL can. + +If upgrading from 1.5, then generally in 1.6 and 1.7 there have been +substantial code added and some code paths altered, particularly in the +areas of type resolution and buffered iteration over universal functions. +This might have an impact on your code particularly if you relied on +accidental behavior in the past. + +New features +============ + +Reduction UFuncs Generalize axis= Parameter +------------------------------------------- + +Any ufunc.reduce function call, as well as other reductions like sum, prod, +any, all, max and min support the ability to choose a subset of the axes to +reduce over. Previously, one could say axis=None to mean all the axes or +axis=# to pick a single axis. Now, one can also say axis=(#,#) to pick a +list of axes for reduction. + +Reduction UFuncs New keepdims= Parameter +---------------------------------------- + +There is a new keepdims= parameter, which if set to True, doesn't throw +away the reduction axes but instead sets them to have size one. When this +option is set, the reduction result will broadcast correctly to the +original operand which was reduced. + +Datetime support +---------------- + +.. note:: The datetime API is *experimental* in 1.7.0, and may undergo changes + in future versions of NumPy. + +There have been a lot of fixes and enhancements to datetime64 compared +to NumPy 1.6: + +* the parser is quite strict about only accepting ISO 8601 dates, with a few + convenience extensions +* converts between units correctly +* datetime arithmetic works correctly +* business day functionality (allows the datetime to be used in contexts where + only certain days of the week are valid) + +The notes in `doc/source/reference/arrays.datetime.rst `_ +(also available in the online docs at `arrays.datetime.html +`_) should be +consulted for more details. + +Custom formatter for printing arrays +------------------------------------ + +See the new ``formatter`` parameter of the ``numpy.set_printoptions`` +function. + +New function numpy.random.choice +-------------------------------- + +A generic sampling function has been added which will generate samples from +a given array-like. The samples can be with or without replacement, and +with uniform or given non-uniform probabilities. + +New function isclose +-------------------- + +Returns a boolean array where two arrays are element-wise equal within a +tolerance. Both relative and absolute tolerance can be specified. + +Preliminary multi-dimensional support in the polynomial package +--------------------------------------------------------------- + +Axis keywords have been added to the integration and differentiation +functions and a tensor keyword was added to the evaluation functions. +These additions allow multi-dimensional coefficient arrays to be used in +those functions. New functions for evaluating 2-D and 3-D coefficient +arrays on grids or sets of points were added together with 2-D and 3-D +pseudo-Vandermonde matrices that can be used for fitting. + + +Ability to pad rank-n arrays +---------------------------- + +A pad module containing functions for padding n-dimensional arrays has been +added. The various private padding functions are exposed as options to a +public 'pad' function. Example:: + + pad(a, 5, mode='mean') + +Current modes are ``constant``, ``edge``, ``linear_ramp``, ``maximum``, +``mean``, ``median``, ``minimum``, ``reflect``, ``symmetric``, ``wrap``, and +````. + + +New argument to searchsorted +---------------------------- + +The function searchsorted now accepts a 'sorter' argument that is a +permutation array that sorts the array to search. + +Build system +------------ + +Added experimental support for the AArch64 architecture. + +C API +----- + +New function ``PyArray_RequireWriteable`` provides a consistent interface +for checking array writeability -- any C code which works with arrays whose +WRITEABLE flag is not known to be True a priori, should make sure to call +this function before writing. + +NumPy C Style Guide added (``doc/C_STYLE_GUIDE.rst.txt``). + +Changes +======= + +General +------- + +The function np.concatenate tries to match the layout of its input arrays. +Previously, the layout did not follow any particular reason, and depended +in an undesirable way on the particular axis chosen for concatenation. A +bug was also fixed which silently allowed out of bounds axis arguments. + +The ufuncs logical_or, logical_and, and logical_not now follow Python's +behavior with object arrays, instead of trying to call methods on the +objects. For example the expression (3 and 'test') produces the string +'test', and now np.logical_and(np.array(3, 'O'), np.array('test', 'O')) +produces 'test' as well. + +The ``.base`` attribute on ndarrays, which is used on views to ensure that the +underlying array owning the memory is not deallocated prematurely, now +collapses out references when you have a view-of-a-view. For example:: + + a = np.arange(10) + b = a[1:] + c = b[1:] + +In numpy 1.6, ``c.base`` is ``b``, and ``c.base.base`` is ``a``. In numpy 1.7, +``c.base`` is ``a``. + +To increase backwards compatibility for software which relies on the old +behaviour of ``.base``, we only 'skip over' objects which have exactly the same +type as the newly created view. This makes a difference if you use ``ndarray`` +subclasses. For example, if we have a mix of ``ndarray`` and ``matrix`` objects +which are all views on the same original ``ndarray``:: + + a = np.arange(10) + b = np.asmatrix(a) + c = b[0, 1:] + d = c[0, 1:] + +then ``d.base`` will be ``b``. This is because ``d`` is a ``matrix`` object, +and so the collapsing process only continues so long as it encounters other +``matrix`` objects. It considers ``c``, ``b``, and ``a`` in that order, and +``b`` is the last entry in that list which is a ``matrix`` object. + +Casting Rules +------------- + +Casting rules have undergone some changes in corner cases, due to the +NA-related work. In particular for combinations of scalar+scalar: + +* the `longlong` type (`q`) now stays `longlong` for operations with any other + number (`? b h i l q p B H I`), previously it was cast as `int_` (`l`). The + `ulonglong` type (`Q`) now stays as `ulonglong` instead of `uint` (`L`). + +* the `timedelta64` type (`m`) can now be mixed with any integer type (`b h i l + q p B H I L Q P`), previously it raised `TypeError`. + +For array + scalar, the above rules just broadcast except the case when +the array and scalars are unsigned/signed integers, then the result gets +converted to the array type (of possibly larger size) as illustrated by the +following examples:: + + >>> (np.zeros((2,), dtype=np.uint8) + np.int16(257)).dtype + dtype('uint16') + >>> (np.zeros((2,), dtype=np.int8) + np.uint16(257)).dtype + dtype('int16') + >>> (np.zeros((2,), dtype=np.int16) + np.uint32(2**17)).dtype + dtype('int32') + +Whether the size gets increased depends on the size of the scalar, for +example:: + + >>> (np.zeros((2,), dtype=np.uint8) + np.int16(255)).dtype + dtype('uint8') + >>> (np.zeros((2,), dtype=np.uint8) + np.int16(256)).dtype + dtype('uint16') + +Also a ``complex128`` scalar + ``float32`` array is cast to ``complex64``. + +In NumPy 1.7 the `datetime64` type (`M`) must be constructed by explicitly +specifying the type as the second argument (e.g. ``np.datetime64(2000, 'Y')``). + + +Deprecations +============ + +General +------- + +Specifying a custom string formatter with a `_format` array attribute is +deprecated. The new `formatter` keyword in ``numpy.set_printoptions`` or +``numpy.array2string`` can be used instead. + +The deprecated imports in the polynomial package have been removed. + +``concatenate`` now raises DepractionWarning for 1D arrays if ``axis != 0``. +Versions of numpy < 1.7.0 ignored axis argument value for 1D arrays. We +allow this for now, but in due course we will raise an error. + +C-API +----- + +Direct access to the fields of PyArrayObject* has been deprecated. Direct +access has been recommended against for many releases. Expect similar +deprecations for PyArray_Descr* and other core objects in the future as +preparation for NumPy 2.0. + +The macros in old_defines.h are deprecated and will be removed in the next +major release (>= 2.0). The sed script tools/replace_old_macros.sed can be +used to replace these macros with the newer versions. + +You can test your code against the deprecated C API by #defining +NPY_NO_DEPRECATED_API to the target version number, for example +NPY_1_7_API_VERSION, before including any NumPy headers. + +The ``NPY_CHAR`` member of the ``NPY_TYPES`` enum is deprecated and will be +removed in NumPy 1.8. See the discussion at +`gh-2801 `_ for more details. diff --git a/doc/release/1.7.1-notes.rst b/doc/release/1.7.1-notes.rst new file mode 100644 index 0000000..04216b0 --- /dev/null +++ b/doc/release/1.7.1-notes.rst @@ -0,0 +1,27 @@ +========================= +NumPy 1.7.1 Release Notes +========================= + +This is a bugfix only release in the 1.7.x series. +It supports Python 2.4 - 2.7 and 3.1 - 3.3 and is the last series that +supports Python 2.4 - 2.5. + + +Issues fixed +============ + +* gh-2973: Fix `1` is printed during numpy.test() +* gh-2983: BUG: gh-2969: Backport memory leak fix 80b3a34. +* gh-3007: Backport gh-3006 +* gh-2984: Backport fix complex polynomial fit +* gh-2982: BUG: Make nansum work with booleans. +* gh-2985: Backport large sort fixes +* gh-3039: Backport object take +* gh-3105: Backport nditer fix op axes initialization +* gh-3108: BUG: npy-pkg-config ini files were missing after Bento build. +* gh-3124: BUG: PyArray_LexSort allocates too much temporary memory. +* gh-3131: BUG: Exported f2py_size symbol prevents linking multiple f2py modules. +* gh-3117: Backport gh-2992 +* gh-3135: DOC: Add mention of PyArray_SetBaseObject stealing a reference +* gh-3134: DOC: Fix typo in fft docs (the indexing variable is 'm', not 'n'). +* gh-3136: Backport #3128 diff --git a/doc/release/1.7.2-notes.rst b/doc/release/1.7.2-notes.rst new file mode 100644 index 0000000..b0951bd --- /dev/null +++ b/doc/release/1.7.2-notes.rst @@ -0,0 +1,55 @@ +========================= +NumPy 1.7.2 Release Notes +========================= + +This is a bugfix only release in the 1.7.x series. +It supports Python 2.4 - 2.7 and 3.1 - 3.3 and is the last series that +supports Python 2.4 - 2.5. + + +Issues fixed +============ + +* gh-3153: Do not reuse nditer buffers when not filled enough +* gh-3192: f2py crashes with UnboundLocalError exception +* gh-442: Concatenate with axis=None now requires equal number of array elements +* gh-2485: Fix for astype('S') string truncate issue +* gh-3312: bug in count_nonzero +* gh-2684: numpy.ma.average casts complex to float under certain conditions +* gh-2403: masked array with named components does not behave as expected +* gh-2495: np.ma.compress treated inputs in wrong order +* gh-576: add __len__ method to ma.mvoid +* gh-3364: reduce performance regression of mmap slicing +* gh-3421: fix non-swapping strided copies in GetStridedCopySwap +* gh-3373: fix small leak in datetime metadata initialization +* gh-2791: add platform specific python include directories to search paths +* gh-3168: fix undefined function and add integer divisions +* gh-3301: memmap does not work with TemporaryFile in python3 +* gh-3057: distutils.misc_util.get_shared_lib_extension returns wrong debug extension +* gh-3472: add module extensions to load_library search list +* gh-3324: Make comparison function (gt, ge, ...) respect __array_priority__ +* gh-3497: np.insert behaves incorrectly with argument 'axis=-1' +* gh-3541: make preprocessor tests consistent in halffloat.c +* gh-3458: array_ass_boolean_subscript() writes 'non-existent' data to array +* gh-2892: Regression in ufunc.reduceat with zero-sized index array +* gh-3608: Regression when filling struct from tuple +* gh-3701: add support for Python 3.4 ast.NameConstant +* gh-3712: do not assume that GIL is enabled in xerbla +* gh-3712: fix LAPACK error handling in lapack_litemodule +* gh-3728: f2py fix decref on wrong object +* gh-3743: Hash changed signature in Python 3.3 +* gh-3793: scalar int hashing broken on 64 bit python3 +* gh-3160: SandboxViolation easyinstalling 1.7.0 on Mac OS X 10.8.3 +* gh-3871: npy_math.h has invalid isinf for Solaris with SUNWspro12.2 +* gh-2561: Disable check for oldstyle classes in python3 +* gh-3900: Ensure NotImplemented is passed on in MaskedArray ufunc's +* gh-2052: del scalar subscript causes segfault +* gh-3832: fix a few uninitialized uses and memleaks +* gh-3971: f2py changed string.lowercase to string.ascii_lowercase for python3 +* gh-3480: numpy.random.binomial raised ValueError for n == 0 +* gh-3992: hypot(inf, 0) shouldn't raise a warning, hypot(inf, inf) wrong result +* gh-4018: Segmentation fault dealing with very large arrays +* gh-4094: fix NaT handling in _strided_to_strided_string_to_datetime +* gh-4051: fix uninitialized use in _strided_to_strided_string_to_datetime +* gh-4123: lexsort segfault +* gh-4141: Fix a few issues that show up with python 3.4b1 diff --git a/doc/release/1.8.0-notes.rst b/doc/release/1.8.0-notes.rst new file mode 100644 index 0000000..80c39f8 --- /dev/null +++ b/doc/release/1.8.0-notes.rst @@ -0,0 +1,526 @@ +========================= +NumPy 1.8.0 Release Notes +========================= + +This release supports Python 2.6 -2.7 and 3.2 - 3.3. + + +Highlights +========== + + +* New, no 2to3, Python 2 and Python 3 are supported by a common code base. +* New, gufuncs for linear algebra, enabling operations on stacked arrays. +* New, inplace fancy indexing for ufuncs with the ``.at`` method. +* New, ``partition`` function, partial sorting via selection for fast median. +* New, ``nanmean``, ``nanvar``, and ``nanstd`` functions skipping NaNs. +* New, ``full`` and ``full_like`` functions to create value initialized arrays. +* New, ``PyUFunc_RegisterLoopForDescr``, better ufunc support for user dtypes. +* Numerous performance improvements in many areas. + + +Dropped Support +=============== + + +Support for Python versions 2.4 and 2.5 has been dropped, + +Support for SCons has been removed. + + +Future Changes +============== + + +The Datetime64 type remains experimental in this release. In 1.9 there will +probably be some changes to make it more useable. + +The diagonal method currently returns a new array and raises a +FutureWarning. In 1.9 it will return a readonly view. + +Multiple field selection from an array of structured type currently +returns a new array and raises a FutureWarning. In 1.9 it will return a +readonly view. + +The numpy/oldnumeric and numpy/numarray compatibility modules will be +removed in 1.9. + + +Compatibility notes +=================== + + +The doc/sphinxext content has been moved into its own github repository, +and is included in numpy as a submodule. See the instructions in +doc/HOWTO_BUILD_DOCS.rst.txt for how to access the content. + +.. _numpydoc: https://github.com/numpy/numpydoc + +The hash function of numpy.void scalars has been changed. Previously the +pointer to the data was hashed as an integer. Now, the hash function uses +the tuple-hash algorithm to combine the hash functions of the elements of +the scalar, but only if the scalar is read-only. + +Numpy has switched its build system to using 'separate compilation' by +default. In previous releases this was supported, but not default. This +should produce the same results as the old system, but if you're trying to +do something complicated like link numpy statically or using an unusual +compiler, then it's possible you will encounter problems. If so, please +file a bug and as a temporary workaround you can re-enable the old build +system by exporting the shell variable NPY_SEPARATE_COMPILATION=0. + +For the AdvancedNew iterator the ``oa_ndim`` flag should now be -1 to indicate +that no ``op_axes`` and ``itershape`` are passed in. The ``oa_ndim == 0`` +case, now indicates a 0-D iteration and ``op_axes`` being NULL and the old +usage is deprecated. This does not effect the ``NpyIter_New`` or +``NpyIter_MultiNew`` functions. + +The functions nanargmin and nanargmax now return np.iinfo['intp'].min for +the index in all-NaN slices. Previously the functions would raise a ValueError +for array returns and NaN for scalar returns. + +NPY_RELAXED_STRIDES_CHECKING +---------------------------- +There is a new compile time environment variable +``NPY_RELAXED_STRIDES_CHECKING``. If this variable is set to 1, then +numpy will consider more arrays to be C- or F-contiguous -- for +example, it becomes possible to have a column vector which is +considered both C- and F-contiguous simultaneously. The new definition +is more accurate, allows for faster code that makes fewer unnecessary +copies, and simplifies numpy's code internally. However, it may also +break third-party libraries that make too-strong assumptions about the +stride values of C- and F-contiguous arrays. (It is also currently +known that this breaks Cython code using memoryviews, which will be +fixed in Cython.) THIS WILL BECOME THE DEFAULT IN A FUTURE RELEASE, SO +PLEASE TEST YOUR CODE NOW AGAINST NUMPY BUILT WITH:: + + NPY_RELAXED_STRIDES_CHECKING=1 python setup.py install + +You can check whether NPY_RELAXED_STRIDES_CHECKING is in effect by +running:: + + np.ones((10, 1), order="C").flags.f_contiguous + +This will be ``True`` if relaxed strides checking is enabled, and +``False`` otherwise. The typical problem we've seen so far is C code +that works with C-contiguous arrays, and assumes that the itemsize can +be accessed by looking at the last element in the ``PyArray_STRIDES(arr)`` +array. When relaxed strides are in effect, this is not true (and in +fact, it never was true in some corner cases). Instead, use +``PyArray_ITEMSIZE(arr)``. + +For more information check the "Internal memory layout of an ndarray" +section in the documentation. + +Binary operations with non-arrays as second argument +---------------------------------------------------- +Binary operations of the form `` * `` +where ```` declares an ``__array_priority__`` higher than +that of ```` will now unconditionally return +*NotImplemented*, giving ```` a chance to handle the +operation. Previously, `NotImplemented` would only be returned if +```` actually implemented the reversed operation, and after +a (potentially expensive) array conversion of ```` had been +attempted. (`bug `_, `pull request +`_) + +Function `median` used with `overwrite_input` only partially sorts array +------------------------------------------------------------------------ +If `median` is used with `overwrite_input` option the input array will now only +be partially sorted instead of fully sorted. + +Fix to financial.npv +-------------------- +The npv function had a bug. Contrary to what the documentation stated, it +summed from indexes ``1`` to ``M`` instead of from ``0`` to ``M - 1``. The +fix changes the returned value. The mirr function called the npv function, +but worked around the problem, so that was also fixed and the return value +of the mirr function remains unchanged. + +Runtime warnings when comparing NaN numbers +------------------------------------------- +Comparing ``NaN`` floating point numbers now raises the ``invalid`` runtime +warning. If a ``NaN`` is expected the warning can be ignored using np.errstate. +E.g.:: + + with np.errstate(invalid='ignore'): + operation() + + +New Features +============ + + +Support for linear algebra on stacked arrays +-------------------------------------------- +The gufunc machinery is now used for np.linalg, allowing operations on +stacked arrays and vectors. For example:: + + >>> a + array([[[ 1., 1.], + [ 0., 1.]], + + [[ 1., 1.], + [ 0., 1.]]]) + + >>> np.linalg.inv(a) + array([[[ 1., -1.], + [ 0., 1.]], + + [[ 1., -1.], + [ 0., 1.]]]) + +In place fancy indexing for ufuncs +---------------------------------- +The function ``at`` has been added to ufunc objects to allow in place +ufuncs with no buffering when fancy indexing is used. For example, the +following will increment the first and second items in the array, and will +increment the third item twice: ``numpy.add.at(arr, [0, 1, 2, 2], 1)`` + +This is what many have mistakenly thought ``arr[[0, 1, 2, 2]] += 1`` would do, +but that does not work as the incremented value of ``arr[2]`` is simply copied +into the third slot in ``arr`` twice, not incremented twice. + +New functions `partition` and `argpartition` +-------------------------------------------- +New functions to partially sort arrays via a selection algorithm. + +A ``partition`` by index ``k`` moves the ``k`` smallest element to the front of +an array. All elements before ``k`` are then smaller or equal than the value +in position ``k`` and all elements following ``k`` are then greater or equal +than the value in position ``k``. The ordering of the values within these +bounds is undefined. +A sequence of indices can be provided to sort all of them into their sorted +position at once iterative partitioning. +This can be used to efficiently obtain order statistics like median or +percentiles of samples. +``partition`` has a linear time complexity of ``O(n)`` while a full sort has +``O(n log(n))``. + +New functions `nanmean`, `nanvar` and `nanstd` +---------------------------------------------- +New nan aware statistical functions are added. In these functions the +results are what would be obtained if nan values were omitted from all +computations. + +New functions `full` and `full_like` +------------------------------------ +New convenience functions to create arrays filled with a specific value; +complementary to the existing `zeros` and `zeros_like` functions. + +IO compatibility with large files +--------------------------------- +Large NPZ files >2GB can be loaded on 64-bit systems. + +Building against OpenBLAS +------------------------- +It is now possible to build numpy against OpenBLAS by editing site.cfg. + +New constant +------------ +Euler's constant is now exposed in numpy as euler_gamma. + +New modes for qr +---------------- +New modes 'complete', 'reduced', and 'raw' have been added to the qr +factorization and the old 'full' and 'economic' modes are deprecated. +The 'reduced' mode replaces the old 'full' mode and is the default as was +the 'full' mode, so backward compatibility can be maintained by not +specifying the mode. + +The 'complete' mode returns a full dimensional factorization, which can be +useful for obtaining a basis for the orthogonal complement of the range +space. The 'raw' mode returns arrays that contain the Householder +reflectors and scaling factors that can be used in the future to apply q +without needing to convert to a matrix. The 'economic' mode is simply +deprecated, there isn't much use for it and it isn't any more efficient +than the 'raw' mode. + +New `invert` argument to `in1d` +------------------------------- +The function `in1d` now accepts a `invert` argument which, when `True`, +causes the returned array to be inverted. + +Advanced indexing using `np.newaxis` +------------------------------------ +It is now possible to use `np.newaxis`/`None` together with index +arrays instead of only in simple indices. This means that +``array[np.newaxis, [0, 1]]`` will now work as expected and select the first +two rows while prepending a new axis to the array. + + +C-API +----- +New ufuncs can now be registered with builtin input types and a custom +output type. Before this change, NumPy wouldn't be able to find the right +ufunc loop function when the ufunc was called from Python, because the ufunc +loop signature matching logic wasn't looking at the output operand type. +Now the correct ufunc loop is found, as long as the user provides an output +argument with the correct output type. + +runtests.py +----------- +A simple test runner script ``runtests.py`` was added. It also builds Numpy via +``setup.py build`` and can be used to run tests easily during development. + + +Improvements +============ + +IO performance improvements +--------------------------- +Performance in reading large files was improved by chunking (see also IO compatibility). + +Performance improvements to `pad` +--------------------------------- +The `pad` function has a new implementation, greatly improving performance for +all inputs except `mode=` (retained for backwards compatibility). +Scaling with dimensionality is dramatically improved for rank >= 4. + +Performance improvements to `isnan`, `isinf`, `isfinite` and `byteswap` +----------------------------------------------------------------------- +`isnan`, `isinf`, `isfinite` and `byteswap` have been improved to take +advantage of compiler builtins to avoid expensive calls to libc. +This improves performance of these operations by about a factor of two on gnu +libc systems. + +Performance improvements via SSE2 vectorization +----------------------------------------------- +Several functions have been optimized to make use of SSE2 CPU SIMD instructions. + +* Float32 and float64: + * base math (`add`, `subtract`, `divide`, `multiply`) + * `sqrt` + * `minimum/maximum` + * `absolute` +* Bool: + * `logical_or` + * `logical_and` + * `logical_not` + +This improves performance of these operations up to 4x/2x for float32/float64 +and up to 10x for bool depending on the location of the data in the CPU caches. +The performance gain is greatest for in-place operations. + +In order to use the improved functions the SSE2 instruction set must be enabled +at compile time. It is enabled by default on x86_64 systems. On x86_32 with a +capable CPU it must be enabled by passing the appropriate flag to the CFLAGS +build variable (-msse2 with gcc). + +Performance improvements to `median` +------------------------------------ +`median` is now implemented in terms of `partition` instead of `sort` which +reduces its time complexity from O(n log(n)) to O(n). +If used with the `overwrite_input` option the array will now only be partially +sorted instead of fully sorted. + + +Overrideable operand flags in ufunc C-API +----------------------------------------- +When creating a ufunc, the default ufunc operand flags can be overridden +via the new op_flags attribute of the ufunc object. For example, to set +the operand flag for the first input to read/write: + +PyObject \*ufunc = PyUFunc_FromFuncAndData(...); +ufunc->op_flags[0] = NPY_ITER_READWRITE; + +This allows a ufunc to perform an operation in place. Also, global nditer flags +can be overridden via the new iter_flags attribute of the ufunc object. +For example, to set the reduce flag for a ufunc: + +ufunc->iter_flags = NPY_ITER_REDUCE_OK; + + +Changes +======= + + +General +------- +The function np.take now allows 0-d arrays as indices. + +The separate compilation mode is now enabled by default. + +Several changes to np.insert and np.delete: + +* Previously, negative indices and indices that pointed past the end of + the array were simply ignored. Now, this will raise a Future or Deprecation + Warning. In the future they will be treated like normal indexing treats + them -- negative indices will wrap around, and out-of-bound indices will + generate an error. +* Previously, boolean indices were treated as if they were integers (always + referring to either the 0th or 1st item in the array). In the future, they + will be treated as masks. In this release, they raise a FutureWarning + warning of this coming change. +* In Numpy 1.7. np.insert already allowed the syntax + `np.insert(arr, 3, [1,2,3])` to insert multiple items at a single position. + In Numpy 1.8. this is also possible for `np.insert(arr, [3], [1, 2, 3])`. + +Padded regions from np.pad are now correctly rounded, not truncated. + +C-API Array Additions +--------------------- +Four new functions have been added to the array C-API. + +* PyArray_Partition +* PyArray_ArgPartition +* PyArray_SelectkindConverter +* PyDataMem_NEW_ZEROED + +C-API Ufunc Additions +--------------------- +One new function has been added to the ufunc C-API that allows to register +an inner loop for user types using the descr. + +* PyUFunc_RegisterLoopForDescr + +C-API Developer Improvements +---------------------------- +The ``PyArray_Type`` instance creation function ``tp_new`` now +uses ``tp_basicsize`` to determine how much memory to allocate. +In previous releases only ``sizeof(PyArrayObject)`` bytes of +memory were allocated, often requiring C-API subtypes to +reimplement ``tp_new``. + +Deprecations +============ + +The 'full' and 'economic' modes of qr factorization are deprecated. + +General +------- +The use of non-integer for indices and most integer arguments has been +deprecated. Previously float indices and function arguments such as axes or +shapes were truncated to integers without warning. For example +`arr.reshape(3., -1)` or `arr[0.]` will trigger a deprecation warning in +NumPy 1.8., and in some future version of NumPy they will raise an error. + + +Authors +======= + +This release contains work by the following people who contributed at least +one patch to this release. The names are in alphabetical order by first name: + +* 87 +* Adam Ginsburg + +* Adam Griffiths + +* Alexander Belopolsky + +* Alex Barth + +* Alex Ford + +* Andreas Hilboll + +* Andreas Kloeckner + +* Andreas Schwab + +* Andrew Horton + +* argriffing + +* Arink Verma + +* Bago Amirbekian + +* Bartosz Telenczuk + +* bebert218 + +* Benjamin Root + +* Bill Spotz + +* Bradley M. Froehle +* Carwyn Pelley + +* Charles Harris +* Chris +* Christian Brueffer + +* Christoph Dann + +* Christoph Gohlke +* Dan Hipschman + +* Daniel + +* Dan Miller + +* daveydave400 + +* David Cournapeau +* David Warde-Farley +* Denis Laxalde +* dmuellner + +* Edward Catmur + +* Egor Zindy + +* endolith +* Eric Firing +* Eric Fode +* Eric Moore + +* Eric Price + +* Fazlul Shahriar + +* Félix Hartmann + +* Fernando Perez +* Frank B + +* Frank Breitling + +* Frederic +* Gabriel +* GaelVaroquaux +* Guillaume Gay + +* Han Genuit +* HaroldMills + +* hklemm + +* jamestwebber + +* Jason Madden + +* Jay Bourque +* jeromekelleher + +* Jesús Gómez + +* jmozmoz + +* jnothman + +* Johannes Schönberger + +* John Benediktsson + +* John Salvatier + +* John Stechschulte + +* Jonathan Waltman + +* Joon Ro + +* Jos de Kloe + +* Joseph Martinot-Lagarde + +* Josh Warner (Mac) + +* Jostein Bø Fløystad + +* Juan Luis Cano Rodríguez + +* Julian Taylor + +* Julien Phalip + +* K.-Michael Aye + +* Kumar Appaiah + +* Lars Buitinck +* Leon Weber + +* Luis Pedro Coelho +* Marcin Juszkiewicz +* Mark Wiebe +* Marten van Kerkwijk + +* Martin Baeuml + +* Martin Spacek +* Martin Teichmann + +* Matt Davis + +* Matthew Brett +* Maximilian Albert + +* m-d-w + +* Michael Droettboom +* mwtoews + +* Nathaniel J. Smith +* Nicolas Scheffer + +* Nils Werner + +* ochoadavid + +* Ondřej Čertík +* ovillellas + +* Paul Ivanov +* Pauli Virtanen +* peterjc +* Ralf Gommers +* Raul Cota + +* Richard Hattersley + +* Robert Costa + +* Robert Kern +* Rob Ruana + +* Ronan Lamy +* Sandro Tosi +* Sascha Peilicke + +* Sebastian Berg +* Skipper Seabold +* Stefan van der Walt +* Steve + +* Takafumi Arakaki + +* Thomas Robitaille + +* Tomas Tomecek + +* Travis E. Oliphant +* Valentin Haenel +* Vladimir Rutsky + +* Warren Weckesser +* Yaroslav Halchenko +* Yury V. Zaytsev + + +A total of 119 people contributed to this release. +People with a "+" by their names contributed a patch for the first time. diff --git a/doc/release/1.8.1-notes.rst b/doc/release/1.8.1-notes.rst new file mode 100644 index 0000000..ea34e75 --- /dev/null +++ b/doc/release/1.8.1-notes.rst @@ -0,0 +1,96 @@ +========================= +NumPy 1.8.1 Release Notes +========================= + +This is a bugfix only release in the 1.8.x series. + + +Issues fixed +============ + +* gh-4276: Fix mean, var, std methods for object arrays +* gh-4262: remove insecure mktemp usage +* gh-2385: absolute(complex(inf)) raises invalid warning in python3 +* gh-4024: Sequence assignment doesn't raise exception on shape mismatch +* gh-4027: Fix chunked reading of strings longer than BUFFERSIZE +* gh-4109: Fix object scalar return type of 0-d array indices +* gh-4018: fix missing check for memory allocation failure in ufuncs +* gh-4156: high order linalg.norm discards imaginary elements of complex arrays +* gh-4144: linalg: norm fails on longdouble, signed int +* gh-4094: fix NaT handling in _strided_to_strided_string_to_datetime +* gh-4051: fix uninitialized use in _strided_to_strided_string_to_datetime +* gh-4093: Loading compressed .npz file fails under Python 2.6.6 +* gh-4138: segfault with non-native endian memoryview in python 3.4 +* gh-4123: Fix missing NULL check in lexsort +* gh-4170: fix native-only long long check in memoryviews +* gh-4187: Fix large file support on 32 bit +* gh-4152: fromfile: ensure file handle positions are in sync in python3 +* gh-4176: clang compatibility: Typos in conversion_utils +* gh-4223: Fetching a non-integer item caused array return +* gh-4197: fix minor memory leak in memoryview failure case +* gh-4206: fix build with single-threaded python +* gh-4220: add versionadded:: 1.8.0 to ufunc.at docstring +* gh-4267: improve handling of memory allocation failure +* gh-4267: fix use of capi without gil in ufunc.at +* gh-4261: Detect vendor versions of GNU Compilers +* gh-4253: IRR was returning nan instead of valid negative answer +* gh-4254: fix unnecessary byte order flag change for byte arrays +* gh-3263: numpy.random.shuffle clobbers mask of a MaskedArray +* gh-4270: np.random.shuffle not work with flexible dtypes +* gh-3173: Segmentation fault when 'size' argument to random.multinomial +* gh-2799: allow using unique with lists of complex +* gh-3504: fix linspace truncation for integer array scalar +* gh-4191: get_info('openblas') does not read libraries key +* gh-3348: Access violation in _descriptor_from_pep3118_format +* gh-3175: segmentation fault with numpy.array() from bytearray +* gh-4266: histogramdd - wrong result for entries very close to last boundary +* gh-4408: Fix stride_stricks.as_strided function for object arrays +* gh-4225: fix log1p and exmp1 return for np.inf on windows compiler builds +* gh-4359: Fix infinite recursion in str.format of flex arrays +* gh-4145: Incorrect shape of broadcast result with the exponent operator +* gh-4483: Fix commutativity of {dot,multiply,inner}(scalar, matrix_of_objs) +* gh-4466: Delay npyiter size check when size may change +* gh-4485: Buffered stride was erroneously marked fixed +* gh-4354: byte_bounds fails with datetime dtypes +* gh-4486: segfault/error converting from/to high-precision datetime64 objects +* gh-4428: einsum(None, None, None, None) causes segfault +* gh-4134: uninitialized use for for size 1 object reductions + +Changes +======= + +NDIter +------ +When ``NpyIter_RemoveAxis`` is now called, the iterator range will be reset. + +When a multi index is being tracked and an iterator is not buffered, it is +possible to use ``NpyIter_RemoveAxis``. In this case an iterator can shrink +in size. Because the total size of an iterator is limited, the iterator +may be too large before these calls. In this case its size will be set to ``-1`` +and an error issued not at construction time but when removing the multi +index, setting the iterator range, or getting the next function. + +This has no effect on currently working code, but highlights the necessity +of checking for an error return if these conditions can occur. In most +cases the arrays being iterated are as large as the iterator so that such +a problem cannot occur. + +Optional reduced verbosity for np.distutils +------------------------------------------- +Set ``numpy.distutils.system_info.system_info.verbosity = 0`` and then +calls to ``numpy.distutils.system_info.get_info('blas_opt')`` will not +print anything on the output. This is mostly for other packages using +numpy.distutils. + +Deprecations +============ + +C-API +----- + +The utility function npy_PyFile_Dup and npy_PyFile_DupClose are broken by the +internal buffering python 3 applies to its file objects. +To fix this two new functions npy_PyFile_Dup2 and npy_PyFile_DupClose2 are +declared in npy_3kcompat.h and the old functions are deprecated. +Due to the fragile nature of these functions it is recommended to instead use +the python API when possible. diff --git a/doc/release/1.8.2-notes.rst b/doc/release/1.8.2-notes.rst new file mode 100644 index 0000000..71e5495 --- /dev/null +++ b/doc/release/1.8.2-notes.rst @@ -0,0 +1,20 @@ +========================= +NumPy 1.8.2 Release Notes +========================= + +This is a bugfix only release in the 1.8.x series. + +Issues fixed +============ + +* gh-4836: partition produces wrong results for multiple selections in equal ranges +* gh-4656: Make fftpack._raw_fft threadsafe +* gh-4628: incorrect argument order to _copyto in in np.nanmax, np.nanmin +* gh-4642: Hold GIL for converting dtypes types with fields +* gh-4733: fix np.linalg.svd(b, compute_uv=False) +* gh-4853: avoid unaligned simd load on reductions on i386 +* gh-4722: Fix seg fault converting empty string to object +* gh-4613: Fix lack of NULL check in array_richcompare +* gh-4774: avoid unaligned access for strided byteswap +* gh-650: Prevent division by zero when creating arrays from some buffers +* gh-4602: ifort has issues with optimization flag O2, use O1 diff --git a/doc/release/1.9.0-notes.rst b/doc/release/1.9.0-notes.rst new file mode 100644 index 0000000..7ea29e3 --- /dev/null +++ b/doc/release/1.9.0-notes.rst @@ -0,0 +1,448 @@ +========================= +NumPy 1.9.0 Release Notes +========================= + +This release supports Python 2.6 - 2.7 and 3.2 - 3.4. + + +Highlights +========== +* Numerous performance improvements in various areas, most notably indexing and + operations on small arrays are significantly faster. + Indexing operations now also release the GIL. +* Addition of `nanmedian` and `nanpercentile` rounds out the nanfunction set. + + +Dropped Support +=============== + +* The oldnumeric and numarray modules have been removed. +* The doc/pyrex and doc/cython directories have been removed. +* The doc/numpybook directory has been removed. +* The numpy/testing/numpytest.py file has been removed together with + the importall function it contained. + + +Future Changes +============== + +* The numpy/polynomial/polytemplate.py file will be removed in NumPy 1.10.0. +* Default casting for inplace operations will change to 'same_kind' in + Numpy 1.10.0. This will certainly break some code that is currently + ignoring the warning. +* Relaxed stride checking will be the default in 1.10.0 +* String version checks will break because, e.g., '1.9' > '1.10' is True. A + NumpyVersion class has been added that can be used for such comparisons. +* The diagonal and diag functions will return writeable views in 1.10.0 +* The `S` and/or `a` dtypes may be changed to represent Python strings + instead of bytes, in Python 3 these two types are very different. + + +Compatibility notes +=================== + +The diagonal and diag functions return readonly views. +------------------------------------------------------ +In NumPy 1.8, the diagonal and diag functions returned readonly copies, in +NumPy 1.9 they return readonly views, and in 1.10 they will return writeable +views. + +Special scalar float values don't cause upcast to double anymore +---------------------------------------------------------------- +In previous numpy versions operations involving floating point scalars +containing special values ``NaN``, ``Inf`` and ``-Inf`` caused the result +type to be at least ``float64``. As the special values can be represented +in the smallest available floating point type, the upcast is not performed +anymore. + +For example the dtype of: + + ``np.array([1.], dtype=np.float32) * float('nan')`` + +now remains ``float32`` instead of being cast to ``float64``. +Operations involving non-special values have not been changed. + +Percentile output changes +------------------------- +If given more than one percentile to compute numpy.percentile returns an +array instead of a list. A single percentile still returns a scalar. The +array is equivalent to converting the list returned in older versions +to an array via ``np.array``. + +If the ``overwrite_input`` option is used the input is only partially +instead of fully sorted. + +ndarray.tofile exception type +----------------------------- +All ``tofile`` exceptions are now ``IOError``, some were previously +``ValueError``. + +Invalid fill value exceptions +----------------------------- +Two changes to numpy.ma.core._check_fill_value: + +* When the fill value is a string and the array type is not one of + 'OSUV', TypeError is raised instead of the default fill value being used. + +* When the fill value overflows the array type, TypeError is raised instead + of OverflowError. + +Polynomial Classes no longer derived from PolyBase +-------------------------------------------------- +This may cause problems with folks who depended on the polynomial classes +being derived from PolyBase. They are now all derived from the abstract +base class ABCPolyBase. Strictly speaking, there should be a deprecation +involved, but no external code making use of the old baseclass could be +found. + +Using numpy.random.binomial may change the RNG state vs. numpy < 1.9 +-------------------------------------------------------------------- +A bug in one of the algorithms to generate a binomial random variate has +been fixed. This change will likely alter the number of random draws +performed, and hence the sequence location will be different after a +call to distribution.c::rk_binomial_btpe. Any tests which rely on the RNG +being in a known state should be checked and/or updated as a result. + +Random seed enforced to be a 32 bit unsigned integer +---------------------------------------------------- +``np.random.seed`` and ``np.random.RandomState`` now throw a ``ValueError`` +if the seed cannot safely be converted to 32 bit unsigned integers. +Applications that now fail can be fixed by masking the higher 32 bit values to +zero: ``seed = seed & 0xFFFFFFFF``. This is what is done silently in older +versions so the random stream remains the same. + +Argmin and argmax out argument +------------------------------ +The ``out`` argument to ``np.argmin`` and ``np.argmax`` and their +equivalent C-API functions is now checked to match the desired output shape +exactly. If the check fails a ``ValueError`` instead of ``TypeError`` is +raised. + +Einsum +------ +Remove unnecessary broadcasting notation restrictions. +``np.einsum('ijk,j->ijk', A, B)`` can also be written as +``np.einsum('ij...,j->ij...', A, B)`` (ellipsis is no longer required on 'j') + +Indexing +-------- + +The NumPy indexing has seen a complete rewrite in this version. This makes +most advanced integer indexing operations much faster and should have no +other implications. However some subtle changes and deprecations were +introduced in advanced indexing operations: + +* Boolean indexing into scalar arrays will always return a new 1-d array. + This means that ``array(1)[array(True)]`` gives ``array([1])`` and + not the original array. + +* Advanced indexing into one dimensional arrays used to have + (undocumented) special handling regarding repeating the value array in + assignments when the shape of the value array was too small or did not + match. Code using this will raise an error. For compatibility you can + use ``arr.flat[index] = values``, which uses the old code branch. (for + example ``a = np.ones(10); a[np.arange(10)] = [1, 2, 3]``) + +* The iteration order over advanced indexes used to be always C-order. + In NumPy 1.9. the iteration order adapts to the inputs and is not + guaranteed (with the exception of a *single* advanced index which is + never reversed for compatibility reasons). This means that the result + is undefined if multiple values are assigned to the same element. An + example for this is ``arr[[0, 0], [1, 1]] = [1, 2]``, which may set + ``arr[0, 1]`` to either 1 or 2. + +* Equivalent to the iteration order, the memory layout of the advanced + indexing result is adapted for faster indexing and cannot be predicted. + +* All indexing operations return a view or a copy. No indexing operation + will return the original array object. (For example ``arr[...]``) + +* In the future Boolean array-likes (such as lists of python bools) will + always be treated as Boolean indexes and Boolean scalars (including + python ``True``) will be a legal *boolean* index. At this time, this is + already the case for scalar arrays to allow the general + ``positive = a[a > 0]`` to work when ``a`` is zero dimensional. + +* In NumPy 1.8 it was possible to use ``array(True)`` and + ``array(False)`` equivalent to 1 and 0 if the result of the operation + was a scalar. This will raise an error in NumPy 1.9 and, as noted + above, treated as a boolean index in the future. + +* All non-integer array-likes are deprecated, object arrays of custom + integer like objects may have to be cast explicitly. + +* The error reporting for advanced indexing is more informative, however + the error type has changed in some cases. (Broadcasting errors of + indexing arrays are reported as ``IndexError``) + +* Indexing with more then one ellipsis (``...``) is deprecated. + +Non-integer reduction axis indexes are deprecated +------------------------------------------------- +Non-integer axis indexes to reduction ufuncs like `add.reduce` or `sum` are +deprecated. + +``promote_types`` and string dtype +---------------------------------- +``promote_types`` function now returns a valid string length when given an +integer or float dtype as one argument and a string dtype as another +argument. Previously it always returned the input string dtype, even if it +wasn't long enough to store the max integer/float value converted to a +string. + +``can_cast`` and string dtype +----------------------------- +``can_cast`` function now returns False in "safe" casting mode for +integer/float dtype and string dtype if the string dtype length is not long +enough to store the max integer/float value converted to a string. +Previously ``can_cast`` in "safe" mode returned True for integer/float +dtype and a string dtype of any length. + +astype and string dtype +----------------------- +The ``astype`` method now returns an error if the string dtype to cast to +is not long enough in "safe" casting mode to hold the max value of +integer/float array that is being casted. Previously the casting was +allowed even if the result was truncated. + +`npyio.recfromcsv` keyword arguments change +------------------------------------------- +`npyio.recfromcsv` no longer accepts the undocumented `update` keyword, +which used to override the `dtype` keyword. + +The ``doc/swig`` directory moved +-------------------------------- +The ``doc/swig`` directory has been moved to ``tools/swig``. + +The ``npy_3kcompat.h`` header changed +------------------------------------- +The unused ``simple_capsule_dtor`` function has been removed from +``npy_3kcompat.h``. Note that this header is not meant to be used outside +of numpy; other projects should be using their own copy of this file when +needed. + +Negative indices in C-Api ``sq_item`` and ``sq_ass_item`` sequence methods +-------------------------------------------------------------------------- +When directly accessing the ``sq_item`` or ``sq_ass_item`` PyObject slots +for item getting, negative indices will not be supported anymore. +``PySequence_GetItem`` and ``PySequence_SetItem`` however fix negative +indices so that they can be used there. + +NDIter +------ +When ``NpyIter_RemoveAxis`` is now called, the iterator range will be reset. + +When a multi index is being tracked and an iterator is not buffered, it is +possible to use ``NpyIter_RemoveAxis``. In this case an iterator can shrink +in size. Because the total size of an iterator is limited, the iterator +may be too large before these calls. In this case its size will be set to ``-1`` +and an error issued not at construction time but when removing the multi +index, setting the iterator range, or getting the next function. + +This has no effect on currently working code, but highlights the necessity +of checking for an error return if these conditions can occur. In most +cases the arrays being iterated are as large as the iterator so that such +a problem cannot occur. + +This change was already applied to the 1.8.1 release. + +``zeros_like`` for string dtypes now returns empty strings +---------------------------------------------------------- +To match the `zeros` function `zeros_like` now returns an array initialized +with empty strings instead of an array filled with `'0'`. + + +New Features +============ + +Percentile supports more interpolation options +---------------------------------------------- +``np.percentile`` now has the interpolation keyword argument to specify in +which way points should be interpolated if the percentiles fall between two +values. See the documentation for the available options. + +Generalized axis support for median and percentile +-------------------------------------------------- +``np.median`` and ``np.percentile`` now support generalized axis arguments like +ufunc reductions do since 1.7. One can now say axis=(index, index) to pick a +list of axes for the reduction. The ``keepdims`` keyword argument was also +added to allow convenient broadcasting to arrays of the original shape. + +Dtype parameter added to ``np.linspace`` and ``np.logspace`` +------------------------------------------------------------ +The returned data type from the ``linspace`` and ``logspace`` functions can +now be specified using the dtype parameter. + +More general ``np.triu`` and ``np.tril`` broadcasting +----------------------------------------------------- +For arrays with ``ndim`` exceeding 2, these functions will now apply to the +final two axes instead of raising an exception. + +``tobytes`` alias for ``tostring`` method +----------------------------------------- +``ndarray.tobytes`` and ``MaskedArray.tobytes`` have been added as aliases +for ``tostring`` which exports arrays as ``bytes``. This is more consistent +in Python 3 where ``str`` and ``bytes`` are not the same. + +Build system +------------ +Added experimental support for the ppc64le and OpenRISC architecture. + +Compatibility to python ``numbers`` module +------------------------------------------ +All numerical numpy types are now registered with the type hierarchy in +the python ``numbers`` module. + +``increasing`` parameter added to ``np.vander`` +----------------------------------------------- +The ordering of the columns of the Vandermonde matrix can be specified with +this new boolean argument. + +``unique_counts`` parameter added to ``np.unique`` +-------------------------------------------------- +The number of times each unique item comes up in the input can now be +obtained as an optional return value. + +Support for median and percentile in nanfunctions +------------------------------------------------- +The ``np.nanmedian`` and ``np.nanpercentile`` functions behave like +the median and percentile functions except that NaNs are ignored. + +NumpyVersion class added +------------------------ +The class may be imported from numpy.lib and can be used for version +comparison when the numpy version goes to 1.10.devel. For example:: + + >>> from numpy.lib import NumpyVersion + >>> if NumpyVersion(np.__version__) < '1.10.0'): + ... print('Wow, that is an old NumPy version!') + +Allow saving arrays with large number of named columns +------------------------------------------------------ +The numpy storage format 1.0 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. A new format 2.0 has been added which extends the header size to 4 +GiB. `np.save` will automatically save in 2.0 format if the data requires it, +else it will always use the more compatible 1.0 format. + +Full broadcasting support for ``np.cross`` +------------------------------------------ +``np.cross`` now properly broadcasts its two input arrays, even if they +have different number of dimensions. In earlier versions this would result +in either an error being raised, or wrong results computed. + + +Improvements +============ + +Better numerical stability for sum in some cases +------------------------------------------------ +Pairwise summation is now used in the sum method, but only along the fast +axis and for groups of the values <= 8192 in length. This should also +improve the accuracy of var and std in some common cases. + +Percentile implemented in terms of ``np.partition`` +--------------------------------------------------- +``np.percentile`` has been implemented in terms of ``np.partition`` which +only partially sorts the data via a selection algorithm. This improves the +time complexity from ``O(nlog(n))`` to ``O(n)``. + +Performance improvement for ``np.array`` +---------------------------------------- +The performance of converting lists containing arrays to arrays using +``np.array`` has been improved. It is now equivalent in speed to +``np.vstack(list)``. + +Performance improvement for ``np.searchsorted`` +----------------------------------------------- +For the built-in numeric types, ``np.searchsorted`` no longer relies on the +data type's ``compare`` function to perform the search, but is now +implemented by type specific functions. Depending on the size of the +inputs, this can result in performance improvements over 2x. + +Optional reduced verbosity for np.distutils +------------------------------------------- +Set ``numpy.distutils.system_info.system_info.verbosity = 0`` and then +calls to ``numpy.distutils.system_info.get_info('blas_opt')`` will not +print anything on the output. This is mostly for other packages using +numpy.distutils. + +Covariance check in ``np.random.multivariate_normal`` +----------------------------------------------------- +A ``RuntimeWarning`` warning is raised when the covariance matrix is not +positive-semidefinite. + +Polynomial Classes no longer template based +------------------------------------------- +The polynomial classes have been refactored to use an abstract base class +rather than a template in order to implement a common interface. This makes +importing the polynomial package faster as the classes do not need to be +compiled on import. + +More GIL releases +----------------- +Several more functions now release the Global Interpreter Lock allowing more +efficient parallelization using the ``threading`` module. Most notably the GIL is +now released for fancy indexing, ``np.where`` and the ``random`` module now +uses a per-state lock instead of the GIL. + +MaskedArray support for more complicated base classes +----------------------------------------------------- +Built-in assumptions that the baseclass behaved like a plain array are being +removed. In particalur, ``repr`` and ``str`` should now work more reliably. + + +C-API +----- + + +Deprecations +============ + +Non-integer scalars for sequence repetition +------------------------------------------- +Using non-integer numpy scalars to repeat python sequences is deprecated. +For example ``np.float_(2) * [1]`` will be an error in the future. + +``select`` input deprecations +----------------------------- +The integer and empty input to ``select`` is deprecated. In the future only +boolean arrays will be valid conditions and an empty ``condlist`` will be +considered an input error instead of returning the default. + +``rank`` function +----------------- +The ``rank`` function has been deprecated to avoid confusion with +``numpy.linalg.matrix_rank``. + +Object array equality comparisons +--------------------------------- +In the future object array comparisons both `==` and `np.equal` will not +make use of identity checks anymore. For example: + +>>> a = np.array([np.array([1, 2, 3]), 1]) +>>> b = np.array([np.array([1, 2, 3]), 1]) +>>> a == b + +will consistently return False (and in the future an error) even if the array +in `a` and `b` was the same object. + +The equality operator `==` will in the future raise errors like `np.equal` +if broadcasting or element comparisons, etc. fails. + +Comparison with `arr == None` will in the future do an elementwise comparison +instead of just returning False. Code should be using `arr is None`. + +All of these changes will give Deprecation- or FutureWarnings at this time. + +C-API +----- + +The utility function npy_PyFile_Dup and npy_PyFile_DupClose are broken by the +internal buffering python 3 applies to its file objects. +To fix this two new functions npy_PyFile_Dup2 and npy_PyFile_DupClose2 are +declared in npy_3kcompat.h and the old functions are deprecated. +Due to the fragile nature of these functions it is recommended to instead use +the python API when possible. + +This change was already applied to the 1.8.1 release. diff --git a/doc/release/1.9.1-notes.rst b/doc/release/1.9.1-notes.rst new file mode 100644 index 0000000..4558237 --- /dev/null +++ b/doc/release/1.9.1-notes.rst @@ -0,0 +1,34 @@ +========================= +NumPy 1.9.1 Release Notes +========================= + +This is a bugfix only release in the 1.9.x series. + +Issues fixed +============ + +* gh-5184: restore linear edge behaviour of gradient to as it was in < 1.9. + The second order behaviour is available via the `edge_order` keyword +* gh-4007: workaround Accelerate sgemv crash on OSX 10.9 +* gh-5100: restore object dtype inference from iterable objects without `len()` +* gh-5163: avoid gcc-4.1.2 (red hat 5) miscompilation causing a crash +* gh-5138: fix nanmedian on arrays containing inf +* gh-5240: fix not returning out array from ufuncs with subok=False set +* gh-5203: copy inherited masks in MaskedArray.__array_finalize__ +* gh-2317: genfromtxt did not handle filling_values=0 correctly +* gh-5067: restore api of npy_PyFile_DupClose in python2 +* gh-5063: cannot convert invalid sequence index to tuple +* gh-5082: Segmentation fault with argmin() on unicode arrays +* gh-5095: don't propagate subtypes from np.where +* gh-5104: np.inner segfaults with SciPy's sparse matrices +* gh-5251: Issue with fromarrays not using correct format for unicode arrays +* gh-5136: Import dummy_threading if importing threading fails +* gh-5148: Make numpy import when run with Python flag '-OO' +* gh-5147: Einsum double contraction in particular order causes ValueError +* gh-479: Make f2py work with intent(in out) +* gh-5170: Make python2 .npy files readable in python3 +* gh-5027: Use 'll' as the default length specifier for long long +* gh-4896: fix build error with MSVC 2013 caused by C99 complex support +* gh-4465: Make PyArray_PutTo respect writeable flag +* gh-5225: fix crash when using arange on datetime without dtype set +* gh-5231: fix build in c99 mode diff --git a/doc/release/1.9.2-notes.rst b/doc/release/1.9.2-notes.rst new file mode 100644 index 0000000..268f3aa --- /dev/null +++ b/doc/release/1.9.2-notes.rst @@ -0,0 +1,26 @@ +========================= +NumPy 1.9.2 Release Notes +========================= + +This is a bugfix only release in the 1.9.x series. + +Issues fixed +============ + +* `#5316 `__: fix too large dtype alignment of strings and complex types +* `#5424 `__: fix ma.median when used on ndarrays +* `#5481 `__: Fix astype for structured array fields of different byte order +* `#5354 `__: fix segfault when clipping complex arrays +* `#5524 `__: allow np.argpartition on non ndarrays +* `#5612 `__: Fixes ndarray.fill to accept full range of uint64 +* `#5155 `__: Fix loadtxt with comments=None and a string None data +* `#4476 `__: Masked array view fails if structured dtype has datetime component +* `#5388 `__: Make RandomState.set_state and RandomState.get_state threadsafe +* `#5390 `__: make seed, randint and shuffle threadsafe +* `#5374 `__: Fixed incorrect assert_array_almost_equal_nulp documentation +* `#5393 `__: Add support for ATLAS > 3.9.33. +* `#5313 `__: PyArray_AsCArray caused segfault for 3d arrays +* `#5492 `__: handle out of memory in rfftf +* `#4181 `__: fix a few bugs in the random.pareto docstring +* `#5359 `__: minor changes to linspace docstring +* `#4723 `__: fix a compile issues on AIX diff --git a/doc/release/time_based_proposal.rst b/doc/release/time_based_proposal.rst new file mode 100644 index 0000000..555be68 --- /dev/null +++ b/doc/release/time_based_proposal.rst @@ -0,0 +1,129 @@ +.. vim:syntax=rst + +Introduction +============ + +This document proposes some enhancements for numpy and scipy releases. +Successive numpy and scipy releases are too far apart from a time point of +view - some people who are in the numpy release team feel that it cannot +improve without a bit more formal release process. The main proposal is to +follow a time-based release, with expected dates for code freeze, beta and rc. +The goal is two folds: make release more predictable, and move the code forward. + +Rationale +========= + +Right now, the release process of numpy is relatively organic. When some +features are there, we may decide to make a new release. Because there is not +fixed schedule, people don't really know when new features and bug fixes will +go into a release. More significantly, having an expected release schedule +helps to *coordinate* efforts: at the beginning of a cycle, everybody can jump +in and put new code, even break things if needed. But after some point, only +bug fixes are accepted: this makes beta and RC releases much easier; calming +things down toward the release date helps focusing on bugs and regressions + +Proposal +======== + +Time schedule +------------- + +The proposed schedule is to release numpy every 9 weeks - the exact period can +be tweaked if it ends up not working as expected. There will be several stages +for the cycle: + + * Development: anything can happen (by anything, we mean as currently + done). The focus is on new features, refactoring, etc... + + * Beta: no new features. No bug fixing which requires heavy changes. + regression fixes which appear on supported platforms and were not + caught earlier. + + * Polish/RC: only docstring changes and blocker regressions are allowed. + +The schedule would be as follows: + + +------+-----------------+-----------------+------------------+ + | Week | 1.3.0 | 1.4.0 | Release time | + +======+=================+=================+==================+ + | 1 | Development | | | + +------+-----------------+-----------------+------------------+ + | 2 | Development | | | + +------+-----------------+-----------------+------------------+ + | 3 | Development | | | + +------+-----------------+-----------------+------------------+ + | 4 | Development | | | + +------+-----------------+-----------------+------------------+ + | 5 | Development | | | + +------+-----------------+-----------------+------------------+ + | 6 | Development | | | + +------+-----------------+-----------------+------------------+ + | 7 | Beta | | | + +------+-----------------+-----------------+------------------+ + | 8 | Beta | | | + +------+-----------------+-----------------+------------------+ + | 9 | Beta | | 1.3.0 released | + +------+-----------------+-----------------+------------------+ + | 10 | Polish | Development | | + +------+-----------------+-----------------+------------------+ + | 11 | Polish | Development | | + +------+-----------------+-----------------+------------------+ + | 12 | Polish | Development | | + +------+-----------------+-----------------+------------------+ + | 13 | Polish | Development | | + +------+-----------------+-----------------+------------------+ + | 14 | | Development | | + +------+-----------------+-----------------+------------------+ + | 15 | | Development | | + +------+-----------------+-----------------+------------------+ + | 16 | | Beta | | + +------+-----------------+-----------------+------------------+ + | 17 | | Beta | | + +------+-----------------+-----------------+------------------+ + | 18 | | Beta | 1.4.0 released | + +------+-----------------+-----------------+------------------+ + +Each stage can be defined as follows: + + +------------------+-------------+----------------+----------------+ + | | Development | Beta | Polish | + +==================+=============+================+================+ + | Python Frozen | | slushy | Y | + +------------------+-------------+----------------+----------------+ + | Docstring Frozen | | slushy | thicker slush | + +------------------+-------------+----------------+----------------+ + | C code Frozen | | thicker slush | thicker slush | + +------------------+-------------+----------------+----------------+ + +Terminology: + + * slushy: you can change it if you beg the release team and it's really + important and you coordinate with docs/translations; no "big" + changes. + + * thicker slush: you can change it if it's an open bug marked + showstopper for the Polish release, you beg the release team, the + change is very very small yet very very important, and you feel + extremely guilty about your transgressions. + +The different frozen states are intended to be gradients. The exact meaning is +decided by the release manager: he has the last word on what's go in, what +doesn't. The proposed schedule means that there would be at most 12 weeks +between putting code into the source code repository and being released. + +Release team +------------ + +For every release, there would be at least one release manager. We propose to +rotate the release manager: rotation means it is not always the same person +doing the dirty job, and it should also keep the release manager honest. + +References +========== + + * Proposed schedule for Gnome from Havoc Pennington (one of the core + GTK and Gnome manager): + http://mail.gnome.org/archives/gnome-hackers/2002-June/msg00041.html + The proposed schedule is heavily based on this email + + * http://live.gnome.org/ReleasePlanning/Freezes diff --git a/doc/scipy-sphinx-theme/.gitignore b/doc/scipy-sphinx-theme/.gitignore new file mode 100644 index 0000000..3b05f19 --- /dev/null +++ b/doc/scipy-sphinx-theme/.gitignore @@ -0,0 +1,14 @@ +*.pyc +*.swp +*.pyd +*.so +*.o +*.lo +*.la +*~ +*.bak +*.swp +.\#* +.deps +.libs +.tox diff --git a/doc/scipy-sphinx-theme/Makefile b/doc/scipy-sphinx-theme/Makefile new file mode 100644 index 0000000..af7da3d --- /dev/null +++ b/doc/scipy-sphinx-theme/Makefile @@ -0,0 +1,55 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext all css + +all: html + +css: $(wildcard _theme/scipy/static/css/*.css) + +_theme/scipy/static/css/%.css: _theme/scipy/static/less/%.less + lessc $^ > $@.new + mv -f $@.new $@ + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/doc/scipy-sphinx-theme/README.rst b/doc/scipy-sphinx-theme/README.rst new file mode 100644 index 0000000..650741d --- /dev/null +++ b/doc/scipy-sphinx-theme/README.rst @@ -0,0 +1,49 @@ +scipy-sphinx-theme +================== + +`Sphinx `__ theme for `Scipy `__. + + +Theme options +------------- + +The theme takes the followin options in the `html_options` +configuration variable: + +- ``edit_link`` + + ``True`` or ``False``. Determines if an "edit this page" link is displayed + in the left sidebar. + +- ``rootlinks`` + + List of tuples ``(url, link_name)`` to show in the beginning of the + breadcrumb list on the top left. You can override it by defining an + `edit_link` block in ``searchbox.html``. + +- ``sidebar`` + + One of ``"left"``, ``"right"``, ``"none"``. Defines where the sidebar + should appear. + +- ``scipy_org_logo`` + + ``True`` or ``False``. Whether to plaster the scipy.org logo on top. + + You can use your own logo by overriding the :attr:`layout.html:header` + block. + +- ``navigation_links`` + + ``True`` or ``False``. Whether to display "next", "prev", "index", etc. + links. + +The following blocks are defined: + +- ``layout.html:header`` + + Block at the top of the page, for logo etc. + +- ``searchbox.html:edit_link`` + + Edit link HTML code to paste in the left sidebar, if `edit_link` is enabled. diff --git a/doc/scipy-sphinx-theme/_static/scipyshiny_small.png b/doc/scipy-sphinx-theme/_static/scipyshiny_small.png new file mode 100644 index 0000000..7ef81a9 Binary files /dev/null and b/doc/scipy-sphinx-theme/_static/scipyshiny_small.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/layout.html b/doc/scipy-sphinx-theme/_theme/scipy/layout.html new file mode 100644 index 0000000..b0406d5 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/layout.html @@ -0,0 +1,268 @@ +{# + scipy/layout.html + ~~~~~~~~~~~~~~~~~ + + Master layout template for Sphinx themes. + + :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{%- block doctype -%} + +{%- endblock %} +{%- set url_root = pathto('', 1) %} +{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} +{%- if not embedded and docstitle %} + {%- set titlesuffix = " — "|safe + docstitle|e %} +{%- else %} + {%- set titlesuffix = "" %} +{%- endif %} + +{%- macro relbar_top() %} + +{%- endmacro %} + +{%- macro relbar_top_right() %} + +{%- endmacro %} + +{%- macro relbar_bottom() %} +{%- endmacro %} + +{%- macro sidebar() %} +
+
+ {%- block sidebarlogo %} + {%- if logo %} + + {%- endif %} + {%- endblock %} + {%- if sidebars != None %} + {#- new style sidebar: explicitly include/exclude templates #} + {%- for sidebartemplate in sidebars %} + {%- include sidebartemplate %} + {%- endfor %} + {%- else %} + {#- old style sidebars: using blocks -- should be deprecated #} + {%- block sidebartoc %} + {%- include "localtoc.html" %} + {%- endblock %} + {%- block sidebarrel %} + {%- include "relations.html" %} + {%- endblock %} + {%- block sidebarsourcelink %} + {%- include "sourcelink.html" %} + {%- endblock %} + {%- if customsidebar %} + {%- include customsidebar %} + {%- endif %} + {%- block sidebarsearch %} + {%- include "searchbox.html" %} + {%- endblock %} + {%- endif %} +
+
+{%- endmacro %} + +{%- macro script() %} + + {%- for scriptfile in script_files %} + + {%- endfor %} + +{%- endmacro %} + +{%- macro css() %} + + + + + {%- for cssfile in css_files %} + + {%- endfor %} +{%- endmacro %} + + + + + {{ metatags }} + {%- block htmltitle %} + {{ title|striptags|e }}{{ titlesuffix }} + {%- endblock %} + {{ css() }} + {%- if not embedded %} + {{ script() }} + {%- if use_opensearch %} + + {%- endif %} + {%- if favicon %} + + {%- endif %} + {%- endif %} +{%- block linktags %} + {%- if hasdoc('about') %} + + {%- endif %} + {%- if hasdoc('genindex') %} + + {%- endif %} + {%- if hasdoc('search') %} + + {%- endif %} + {%- if hasdoc('copyright') %} + + {%- endif %} + + {%- if parents %} + + {%- endif %} + {%- if next %} + + {%- endif %} + {%- if prev %} + + {%- endif %} +{%- endblock %} +{%- block extrahead %} {% endblock %} + + +{%- block header %} +{% if theme_scipy_org_logo %} +
+
+ + SciPy +
+
+ +{% else %} +
+
+
+
+{% endif %} +{% endblock %} + +{%- block content %} +
+
+{%- block navbar %} + {% if theme_navigation_links or sidebar == 'left' %} +
+
+
+ {{ relbar_top() }} + {% if theme_navigation_links %} + {{ relbar_top_right() }} + {% endif %} +
+
+
+ {% endif %} +{% endblock %} +
+ {%- if theme_sidebar == 'left' -%} + {{ sidebar() }} + {%- endif %} + {%- if theme_sidebar == 'none' -%} +
+
+ {% else %} +
+ {%- endif %} + {% if not theme_navigation_links and sidebar != 'left' %} +
+
+
+ {{ relbar_top() }} +
+
+
+ {% endif %} + {%- block document %} +
+
+ {% block body %} {% endblock %} +
+
+ {%- endblock %} +
+ {%- if theme_sidebar == 'right' -%} + {{ sidebar() }} + {%- elif theme_sidebar == 'none' -%} +
+ {%- endif %} +
+
+
+{%- endblock %} + +
+
+ {{ relbar_bottom() }} +
+
+ +{%- block footer %} +
+ +
+{%- endblock %} + + diff --git a/doc/scipy-sphinx-theme/_theme/scipy/searchbox.html b/doc/scipy-sphinx-theme/_theme/scipy/searchbox.html new file mode 100644 index 0000000..3c753e9 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/searchbox.html @@ -0,0 +1,13 @@ +{%- if theme_edit_link -%} +{% block edit_link %} +{%- if sourcename %} +
+{%- if 'generated/' in sourcename %} + {{_('Edit page')}} +{%- else %} + {{_('Edit page')}} +{%- endif %} +
+{%- endif %} +{% endblock %} +{%- endif -%} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/sourcelink.html b/doc/scipy-sphinx-theme/_theme/scipy/sourcelink.html new file mode 100644 index 0000000..2c9109a --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/sourcelink.html @@ -0,0 +1,7 @@ +{%- if show_source and has_source and sourcename %} +

{{ _('This Page') }}

+ +{%- endif %} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/css/extend.css b/doc/scipy-sphinx-theme/_theme/scipy/static/css/extend.css new file mode 100644 index 0000000..bd7a981 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/css/extend.css @@ -0,0 +1,116 @@ +.container { + width: 80%; +} +.navbar1 { + padding-bottom: 10px; +} +.navbar1 .nav-pills { + margin-bottom: 0px; + font-size: 12px; +} +.navbar1 .nav-pills > li > a { + padding-top: 2.5px; + padding-bottom: 2.5px; +} +.navbar1 .dropdown.dropdown-menu { + padding: 0px; +} +.header { + padding-top: 30px; + padding-bottom: 18px; +} +.SearchBar .form-search { + margin-bottom: 0px; +} +.SearchBar .input-append input { + height: 12px; +} +body { + font-family: Segoe UI; + background-color: #f9faf7; +} +.main { + background-color: white; + padding: 18px; + -moz-box-shadow: 0 0 3px #888; + -webkit-box-shadow: 0 0 3px #888; + box-shadow: 0 0 3px #888; +} +.MainHeader h1 { + font-weight: normal; +} +.content .contentTitle h4 { + font-size: 18px; + font-weight: normal; +} +.content .meta { + font-size: small; +} +.tags .btn { + border: none; + font-size: 10px; + font-weight: bold; +} +.navigation { + font-size: 12px; + padding-bottom: 12px; +} +.navigation .nav-title { + color: #333333; + font-family: "Segoe UI semibold"; + font-size: 16px; + text-transform: uppercase; +} +.navigation li { + margin: 5px; +} +.snippetHeader { + margin-bottom: 5px; +} +.snippetHeader .snippetTitle { + font-size: 21px; + line-height: 40px; + border-bottom: 1px solid #e5e5e5; + display: block; + color: #333333; +} +.snippetInfo { + padding-top: 10px; +} +.snippetInfo .dl-horizontal { + margin: 5px; +} +.snippet-body { + padding: 10px; +} +.snippet-body .accordion-group { + border: none; +} +.snippet-body .accordion-heading { + text-transform: uppercase; + font-size: 14px; + border-bottom: 1px solid #e5e5e5; +} +.snippet-body .accordion-heading .accordion-toggle { + padding-top: 10px; + padding-bottom: 5px; +} +.SearchResult { + padding: 10px; + padding-top: 0px; +} +.SearchResult .PageTitle { + font-size: 21px; + line-height: 40px; + border-bottom: 1px solid #e5e5e5; + padding-bottom: 5px; + display: block; + color: #333333; +} +.footer { + padding: 10px; +} +.footer-inside { + border-top: 1px solid #e5e5e5; + padding: 10px; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/css/pygments.css b/doc/scipy-sphinx-theme/_theme/scipy/static/css/pygments.css new file mode 100644 index 0000000..1c9c56a --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/css/pygments.css @@ -0,0 +1,87 @@ +/* Styling for the source code listings: (mostly from pygments)*/ + +.highlight pre{ + overflow: auto; + padding: 5px; + background-color: #ffffff; + color: #333333; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +/* Styling for pre elements: from http://perishablepress.com/press/2009/11/09/perfect-pre-tags/ */ +/* no vertical scrollbars for IE 6 */ +* html pre { + padding-bottom:25px; + overflow-y:hidden; + overflow:visible; + overflow-x:auto +} +/* no vertical scrollbars for IE 7 */ +*:first-child+html pre { + padding-bottom:25px; + overflow-y:hidden; + overflow:visible; + overflow-x:auto +} + +div#spc-section-body td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} +.highlight .hll { background-color: #ffffcc } +.highlight { background: #ffffff; } +.highlight .c { color: #008000 } /* Comment */ +.highlight .k { color: #000080; font-weight: bold } /* Keyword */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #000000 } /* Operator */ +.highlight .cm { color: #008000 } /* Comment.Multiline */ +.highlight .cp { color: #008000 } /* Comment.Preproc */ +.highlight .c1 { color: #008000 } /* Comment.Single */ +.highlight .cs { color: #008000 } /* Comment.Special */ +.highlight .kc { color: #000080; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #000080; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #000080; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #000080; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #000080; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #000080; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #008080 } /* Literal.Number */ +.highlight .s { color: #800080 } /* Literal.String */ +.highlight .na { color: #000000 } /* Name.Attribute */ +.highlight .nb { color: #407090 } /* Name.Builtin */ +.highlight .nc { color: #0000F0; font-weight: bold } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #000000 } /* Name.Decorator */ +.highlight .ni { color: #000000 } /* Name.Entity */ +.highlight .ne { color: #000000 } /* Name.Exception */ +.highlight .nf { color: #008080; font-weight: bold } /* Name.Function */ +.highlight .nl { color: #000000 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #000000 } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .mf { color: #008080 } /* Literal.Number.Float */ +.highlight .mh { color: #008080 } /* Literal.Number.Hex */ +.highlight .mi { color: #008080 } /* Literal.Number.Integer */ +.highlight .mo { color: #008080 } /* Literal.Number.Oct */ +.highlight .sb { color: #800080 } /* Literal.String.Backtick */ +.highlight .sc { color: #800080 } /* Literal.String.Char */ +.highlight .sd { color: #800000 } /* Literal.String.Doc */ +.highlight .s2 { color: #800080 } /* Literal.String.Double */ +.highlight .se { color: #800080 } /* Literal.String.Escape */ +.highlight .sh { color: #800080 } /* Literal.String.Heredoc */ +.highlight .si { color: #800080 } /* Literal.String.Interpol */ +.highlight .sx { color: #800080 } /* Literal.String.Other */ +.highlight .sr { color: #800080 } /* Literal.String.Regex */ +.highlight .s1 { color: #800080 } /* Literal.String.Single */ +.highlight .ss { color: #800080 } /* Literal.String.Symbol */ +.highlight .bp { color: #407090 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .il { color: #008080 } /* Literal.Number.Integer.Long */ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/css/scipy-central.css b/doc/scipy-sphinx-theme/_theme/scipy/static/css/scipy-central.css new file mode 100644 index 0000000..6bbfdda --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/css/scipy-central.css @@ -0,0 +1,795 @@ +/* +Styling to add still +-------------------- + +div: spc-notice (general notices: e.g. submission requested is invalid) + +*/ + +/* -------------------------------------------------------------------------*/ +/* Basic layout of the document: no styling - that is applied further down. */ +/* -------------------------------------------------------------------------*/ +body { + /* From: http://matthewjamestaylor.com/blog/perfect-3-column.htm */ + margin:0; + padding:0; + border:0; /* This removes the border around the viewport in old versions of IE */ + width:100%; + background:#ffffff; + min-width:600px; /* Minimum width of layout - remove line if not required */ + /* The min-width property does not work in old versions of Internet Explorer */ +} + +#spc-document-container{ + position: relative; + min-width: 50em; + max-width: 90em; +} +#spc-header { + clear: both; + float: left; + width: 100%; + display: block; +} +.spc-header-row{ + float: left; + width: 100%; + clear: both; +} +.spc-header-left{ + float: left; + position: relative; + left: +1% +} +.spc-header-right{ + float: right; + position: relative; + left: -1% +} +#spc-contentwrap{ + display: block; + overflow: hidden; +} +#spc-content-main{ + float: left; + width: 100%; +} + +#spc-navigation-bottom{ + clear: both; +} +#spc-footer{ + clear: both; +} + +/* -------------------------------------------- */ +/* Now we will begin styling the various blocks */ +/* -------------------------------------------- */ + +/* Document container */ +#spc-document-container { + font: 13px/1.5 'Lucida Grande','Lucida Sans Unicode','Geneva','Verdana',sans-serif; + background: #FFFFFF; + margin: auto; /* display container in the center of the page */ + padding-top: 12px; +} +#spc-document-container img{ + border: 0 +} +#spc-document-container a:visited { /* for IE6 */ + color: purple; +} +/* Header block styling */ +.spc-header-row{ + text-align: center; +} +.spc-header-right{ + float: right; + text-align: right; +} +#spc-site-notice{ + /*display: none;*/ + color: #aaf; + font-weight: bold; + padding: 6px 0px; + border-bottom: 1px dashed #aaf; + background: #eee; + /*display: none; Uncomment to remove the site notice*/ +} +#spc-site-title{ + border-bottom: 1px solid #aaa; + margin-top: -2em; + +} + +#spc-top-menu{ + padding-top: 0.25em; +} +#spc-header h1 a { + color: black; + text-decoration: none; + text-align: center; + font: 36px/1.0 'Inconsolata','Lucida Grande','Lucida Sans Unicode','Geneva','Verdana',sans-serif; + font-weight: bold; +} +#spc-top-menu a { + text-decoration: none; + font-weight: bold; + font: 20px 'Inconsolata','Lucida Grande','Lucida Sans Unicode','Geneva','Verdana',sans-serif; +} +#spc-top-menu a:hover{ + text-decoration: underline; +} + +/* contentwrap block: applies to everything in the bulk of the page */ +#spc-contentwrap { +} + +/* The major chunk of content (left side); the sidebar comes later */ +#spc-content-main{ + background: #FFFFFF; +} + +/* Border */ +#spc-border { + margin-left: 0px; + background: white; + padding-top: 0em; /* Don't remove top and bottom padding: leads to */ + padding-bottom: 0em; /* unwanted horizontal borders around the document.*/ + padding-left: 2em; + padding-right: 2em; +} + +/* spc-section-body: the current section of the document. The Sphinx + generated HTML is inserted inside this DIV element. Specific formatting for + the HTML should go here */ +/* ----------------------- */ +#spc-section-body { + margin-bottom: 1em; +} + +/* Styling for the headers */ +div#spc-section-body h1, h2, h3, h4, h5, h6{ + color: #20435C; + font-family: 'Trebuchet MS', sans-serif; + font-weight: normal; + border-bottom: 0px solid #ccc; + margin-bottom: 0.5em; +} +div#spc-section-body h1 { font-size: 200%; font-weight: bold;} +div#spc-section-body h2 { font-size: 160%; font-weight: bold; color: #101074;} +div#spc-section-body h3 { font-size: 140%; color: #362A13;} +div#spc-section-body h4 { font-size: 120%; } +div#spc-section-body h5 { font-size: 110%; } +div#spc-section-body h6 { font-size: 100%; } + +.spc-title-in-span{font-size: 160%; font-weight: bold; color: #101074; float: left;} + +/* Styling for forms */ +input, select, textarea{ + border:solid 1px #aacfe4; + padding: 4px 2px; + margin-bottom: 1em; +} + +/* Styling for hyperlinks */ +div#spc-section-body a{ + text-decoration: none; +} +div#spc-section-body a:hover{ + text-decoration: underline; +} + +/* Styling for images and figures: images are inline, figures are centered */ +div#spc-section-body .align-center{ + text-align: center; +} + +/* Styling for elements */ +tt { + background-color:#EEE; + color:#000; + font: 16px/1.0 'Inconsolata', Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif; +} + +/* Main page */ +#spc-site-statement{ + width: 90%; + margin: auto; + text-align: center; + padding-top: 1em; +} +#spc-search{ + clear: both; + float: none; + display: block; + margin: 0 auto; + width: 700px; +} +#spc-search-form{ + margin-top: 10pt; +} +#spc-search-input { + cursor: auto; + display: inline; + height: 31px; + float: left; + width: 580px; + border: 2px solid #3e5d34; + padding: 0; + padding-left: 0.5em; + margin: 0; + margin-right: 20px; + color: #555; + font-family: 'Inconsolata', 'Lucida Grande'; + font-size: 24px; + text-indent: 0px; + text-shadow: none; + text-transform: none; + word-spacing: 0px; + background: none; +} +#spc-search-button{ + border: 1px outset #B6A792; + vertical-align:middle; + border:none; + cursor:pointer; + padding: 0; + display: block; + float: left; + width: 80px; + height: 35px; + margin: 0; + background: #ddd; + display: inline-block; + overflow: hidden; +} +#spc-search-results{ + width: 75%; +} +#spc-search-results li{ + margin: 0 auto; + list-style-type: none; + padding: 0.5em 0; + float: left; +} + +/* Submission buttons */ +.spc-button-container { + float: left; + width: 100%; + clear: both; + margin-bottom:1em; +} +#spc-buttonlist { + margin: 0 auto; + list-style-type: none; + padding: 0; + padding-top: 2em; + float: left; + position: relative; + left: 50%; +} +#spc-buttonlist li { + float: left; + position: relative; + right: 50%; + padding: 0em 1em; +} +#spc-buttonlist a { + text-decoration: none; + margin: 0 auto; + display: block; +} +.spc-button{ + background-position: 0px 0px; + background-color: #DDDDDD; + border: 1px outset #B6A792; + cursor: auto; + display: inline-block; + vertical-align: middle; + overflow: hidden; + padding: 0; + margin: 0; +} + +/* Portals */ +.spc-portal-container{ + width: 65%; + clear: both; + padding: 0px; + position: relative; + display: block; + margin: 0 auto; +} +.spc-portal-row-container { + clear:both; + float:left; + width:100%; /* width of whole page */ + overflow:hidden; /* This chops off any overhanging divs */ +} +.spc-portal-row { + float:left; + width:100%; + position:relative; + right:50%; /* right column width */ + background:#fff; /* left column background colour */ + } +.spc-portal-left, +.spc-portal-right{ + float:left; + position:relative; + padding:0 0 1em 0; + overflow:hidden; +} +.spc-portal-left { + width:46%; /* left column content width (column width minus left and right padding) */ + left:52%; /* right column width plus left column left padding */ +} +.spc-portal-right { + width:46%; /* right column content width (column width minus left and right padding) */ + left:56%; /* (right column width) plus (left column left and right padding) plus (right column left padding) */ +} +.spc-portal-container h3{ + font: 14px/1.0 'Inconsolata', Monaco, Lucida Console, Sans Mono, Courier New, monospace, serif; + text-align: center; + border-bottom: 1px solid; +} +.spc-portal-container a{ + text-decoration: none; + font-weight: bold; + font: 14px sans-serif; +} +.spc-portal-container a:hover{ + text-decoration: underline; +} +.spc-portal-container ul{ + list-style-type: square; +} +.spc-portal-container li{ + margin-left: -1em; +} + + +/* Submission forms */ +#spc-form-error-message{ + margin-bottom: 1em; + text-align: center; + border-bottom:solid 1px #000; +} +.errorlist{ + list-style-type: none; + float: left; + padding: 0; +} +.errorlist li{ + font-style: italic; +} +.spc-field-error{ + background: #ee8888; + padding: 4px; +} +.spc-form-button{ + padding: 5px; +} + + /* column container */ + /* http://matthewjamestaylor.com/blog/perfect-3-column.htm */ +.colmask { + position:relative; /* This fixes the IE7 overflow hidden bug */ + clear:both; + float:left; + width:100%; /* width of whole page */ + overflow:hidden; /* This chops off any overhanging divs */ + padding-bottom: 1em; +} +/* common column settings */ +.colright, +.colmid, +.colleft { + float:left; + width:100%; /* width of page */ + position:relative; +} +.col1, +.col2, +.col3 { + float:left; + position:relative; + padding:0; /* no left and right padding on columns */ + overflow:hidden; +} + /* 3 Column settings */ +.threecol { + background:#fff; /* right column background colour */ +} +.threecol .colmid { + right:25%; /* width of the right column */ + background:#fff; /* center column background colour */ +} +.threecol .colleft { + right:60%; /* width of the middle column */ + background:#fff; /* left column background colour */ +} +.threecol .col1 { + width:58%; /* width of center column content (column width minus padding on either side) */ + left:101%; /* 100% plus left padding of center column */ +} +.threecol .col2 { + width:13%; /* Width of left column content (column width minus padding on either side) */ + left:28%; /* width of (right column) plus (center column left and right padding) plus (left column left padding) */ +} +.threecol .col3 { + width:23%; /* Width of right column content (column width minus padding on either side) */ + left:90%; /* Please make note of the brackets here: + (100% - left column width) plus (center column left and right padding) plus (left column left and right padding) plus (right column left padding) + (100-15)+(1+1)+(1+1)+(1)*/ +} +.form-field input, select, textarea{ + width: 98%; + max-width:1000px; + min-width:500px; +} +.form-field-auto-width{ + width: auto; +} +.spc-code-description{ + height: 15em; +} +span.spc-helptext ul{ + margin: 0; + padding-left: 20px; +} +.spc-odd{ + background: #DDF; +} +.spc-even{ + background: #CCF; +} +li.spc-odd tt{ + background-color: #DDF; +} +li.spc-even tt { + background-color: #CCF; +} + +/* Image upload */ +#spc-item-upload { +} +#spc-item-upload-button{ + padding: 0.5em; + text-align: center; +} +.spc-item-upload-success{ + background: #ffa; + padding: 4px; +} + +/* Tagging */ +.ui-autocomplete { + max-height: 150px; + overflow-y: auto; + overflow-x: hidden; /* prevent horizontal scrollbar */ + padding-right: 20px; /* add padding to account for vertical scrollbar */ +} +/* IE 6 doesn't support max-height + * we use height instead, but this forces the menu to always be this tall */ +* html .ui-autocomplete { + height: 100px; +} +.spc-tag{ + background-color: #E0EAF1; + color: #3E6D8E; + border-bottom: 1px solid #37607D; + border-right: 1px solid #37607D; + text-decoration: none; + padding: 4px 4px 3px 4px; + margin: 2px 5px 2px 0px; + font-size: 90%; + line-height: 1.4; + white-space: nowrap; + cursor: pointer; + float:left; +} +.spc-tag:hover{ + background-color: #3E6D8E; + color: #E0EAF1; +} +.spc-tag-cloud{ + background-color: #FFF; + color: #3E6D8E; + border-bottom: 0px solid #37607D; + border-right: 0px solid #37607D; + text-decoration: none; + padding: 0px 4px 0px 4px; + margin: 2px 5px 2px 0px; + font-size: 90%; + white-space: nowrap; + cursor: pointer; +} +.spc-tag-cloud:hover{ + background-color: #FFF; + color: #1E4D6E; +} + +#spc-preview-edit-submit{ + clear: both; +} +#spc-preview-edit-submit form input{ + display: inline; + padding: 5px; +} +#spc-item-submit{ + margin-left:8em; + font-weight: bold; +} +#spc-item-preview{ + width:auto; + min-width:0; + padding: 0.5em; + text-align:center; +} + +#spc-item-header{ + clear: both; + padding: 0px; + float: left; + width: 102%; + position: relative; + display: block; + margin: 0 auto; + left: -1%; + top: -20px; +} +#spc-item-header-left{ + float: left; + text-align: left; +} +#spc-item-header-right{ + float: right; + text-align: right; +} + +div.spc-item-row { + clear: both; + padding-top: 10px; +} + +div.spc-item-row span.spc-item-label { + float: left; + width: 200px; + text-align: left; + padding-right: 20px; + padding-bottom: 4px; + font-weight: bold; +} + +div.spc-item-row span.spc-item-entry { + float: left; + min-width: 500px; + max-width: 1000px; + text-align: left; +} + +div.spc-item-row span.spc-item-entry ul{ + padding: 0; + margin: 0; + list-style-type: none; +} + +div.spc-item-row span.spc-50-50{ + float: left; + width: 49%; + text-align: left; +} +.spc-help-section a{ + color: #0069CC; + margin-top: 1em; +} +.spc-entries-list ul{ + padding: 0; + margin: 0; + list-style-type: none; +} +/* Unstyle certain elements in the code/link description fields */ +.spc-item-description p{ + margin: 0; + margin-bottom: 1em; +} +.spc-item-row pre{ + border: 0px solid #FFF; + overflow: auto; + padding: 5px; + background-color: #EEE; + border: none; + margin: 0; + font: 16px/1.0 'Inconsolata', Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif; +} + + +/* Item display*/ +#spc-itemdisp-container{ + clear: both; + padding: 0; + padding-top: 1em; + margin: 0 auto; + width: 85%; +} + +.spc-itemdisp-row-container { + clear:both; + float:left; + width:100%; + margin: 0 0 1em 0; +} +.spc-itemdisp-row { + float:left; + width:100%; + } +.spc-itemdisp-td{ + float: left; + padding-right: 1%; +} +.spc-itemdisp-description{ + width: 50%; +} +.spc-itemdisp-link{ + float: right; + font-size: 80%; +} +div .spc-itemdisp-mainlink{ + text-decoration: underline; + float: left; + width: 100%; +} +.spc-itemdisp-revinfo{ + float: right; + font-size: 80%; +} +.spc-itemdisp-created{ + width: 23%; +} +.spc-itemdisp-tags{ + width: 23%; +} +.spc-itemdisp-odd{ + background: #fff8f1; +} +.spc-itemdisp-even{ + background: #fff; +} +.spc-itemdisp-header{ + background: #f1c79d; + padding: 0.4em 0 0.4em 0; + font-weight: bold; +} +#spc-itemdisp-pageheader{ + text-align: center; + font: 24px/1.0 'Inconsolata','Lucida Grande','Lucida Sans Unicode','Geneva','Verdana',sans-serif; + font-weight: bold; +} +.spc-itemdisp-pagination{ + float: left; +} + +div#spc-itemdisp-container h1, h2, h3, h4, h5, h6{ + font-weight: normal; + border-bottom: 1px solid #ccc;} +div#spc-itemdisp-container h1 { font-size: 130%; font-weight: bold;} +div#spc-itemdisp-container h2 { font-size: 120%; font-weight: bold;} +div#spc-itemdisp-container h3 { font-size: 110%;} +div#spc-itemdisp-container h4 { font-size: 100%; } +div#spc-itemdisp-container h5 { font-size: 100%; } +div#spc-itemdisp-container h6 { font-size: 100%; } + +/* Permalinks and other minor info*/ +.spc-minor-info { + font-size: 80%; + float: left; + border-top: 1px solid #ddd; +} +.spc-minor-info p{ + margin: 0; +} +.spc-minor-info a{ + text-decoration: none; +} +.spc-minor-info a:hover{ + text-decoration: underline; +} + +/* User profile pages */ +#spc-profile-user-options ul{ + margin: 0 auto; + padding: 0 0; +} +#spc-profile-user-options li{ + margin: 0 auto; + list-style-type: none; + padding: 0 5px 0 5px; + float: left; + border-right: 1px solid; +} +#spc-profile-user-options li:first-child{ + padding-left: 0px; +} +#spc-profile-user-options li:last-child{ + border-right: none; +} +/* Styling for certain static pages */ +#spc-static-centering{ + display: block; + margin: 0 auto; + min-width: 30em; + max-width: 50em; +} + +/* spc-footer: http://www.alistapart.com/articles/practicalcss/ */ +#spc-footer { + clear: both; + font-size: 90%; + padding: 0px; + float: left; + width: 100%; + position: relative; + display: block; + margin: 0 auto; + border-top: 1px solid #aaa; +} +#spc-footer a{ + text-decoration: none; + font-weight: bold; + font: 15px sans-serif; +} +#spc-footer a:hover{ + text-decoration: underline; +} +.spc-footer-left{ + float: left; + text-align: left; +} +.spc-footer-right{ + float: right; + text-align: right; +} +.spc-footer-left ul{ + margin: 0; + padding: 0; +} +.spc-footer-left li{ + display: inline; + padding-left: 3px; + padding-right: 7px; + border-right: 0px solid #aaa; +} +.spc-indent{ + margin-left: 15px; +} +.spc-flag{ + padding-left: 1em; + vertical-align: middle; +} + +/* ---------------- */ +/* Form styling */ +/* ---------------- */ +.spc-form{ + padding-top: 2em; +} + +.spc-form-label{ + display: block; + font-size: 14px; + color: #444; +} +.spc-centering-div-container{ + clear: both; + margin: 0 auto; + border: 1px; + padding: 1em; + float: left; +} + +/* ---------------------- */ +/* Miscellaneous elements */ +/* ---------------------- */ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/css/spc-bootstrap.css b/doc/scipy-sphinx-theme/_theme/scipy/static/css/spc-bootstrap.css new file mode 100644 index 0000000..0c0ae58 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/css/spc-bootstrap.css @@ -0,0 +1,7893 @@ +@import url(http://fonts.googleapis.com/css?family=Open+Sans); +/*! + * Bootstrap v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, +.clearfix:after { + display: table; + content: ""; + line-height: 0; +} +.clearfix:after { + clear: both; +} +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.input-block-level { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, +a:active { + outline: 0; +} +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + /* Responsive images (ensure images don't scale beyond their parents) */ + + max-width: 100%; + /* Part 1: Set a maxium relative to the parent */ + + width: auto\9; + /* IE7-8 need help adjusting responsive images */ + + height: auto; + /* Part 2: Scale the height according to the width, otherwise you get stretching */ + + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} +#map_canvas img, +.google-maps img { + max-width: none; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, +input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; +} +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +@media print { + * { + text-shadow: none !important; + color: #000 !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } +} +body { + margin: 0; + font-family: 'Open Sans', sans-serif; + font-size: 13px; + line-height: 19px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover, +a:focus { + color: #005580; + text-decoration: underline; +} +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} +.img-circle { + -webkit-border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, +.row:after { + display: table; + content: ""; + line-height: 0; +} +.row:after { + clear: both; +} +.row:before, +.row:after { + display: table; + content: ""; + line-height: 0; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} +.span12 { + width: 940px; +} +.span11 { + width: 860px; +} +.span10 { + width: 780px; +} +.span9 { + width: 700px; +} +.span8 { + width: 620px; +} +.span7 { + width: 540px; +} +.span6 { + width: 460px; +} +.span5 { + width: 380px; +} +.span4 { + width: 300px; +} +.span3 { + width: 220px; +} +.span2 { + width: 140px; +} +.span1 { + width: 60px; +} +.offset12 { + margin-left: 980px; +} +.offset11 { + margin-left: 900px; +} +.offset10 { + margin-left: 820px; +} +.offset9 { + margin-left: 740px; +} +.offset8 { + margin-left: 660px; +} +.offset7 { + margin-left: 580px; +} +.offset6 { + margin-left: 500px; +} +.offset5 { + margin-left: 420px; +} +.offset4 { + margin-left: 340px; +} +.offset3 { + margin-left: 260px; +} +.offset2 { + margin-left: 180px; +} +.offset1 { + margin-left: 100px; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, +.row:after { + display: table; + content: ""; + line-height: 0; +} +.row:after { + clear: both; +} +.row:before, +.row:after { + display: table; + content: ""; + line-height: 0; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} +.span12 { + width: 940px; +} +.span11 { + width: 860px; +} +.span10 { + width: 780px; +} +.span9 { + width: 700px; +} +.span8 { + width: 620px; +} +.span7 { + width: 540px; +} +.span6 { + width: 460px; +} +.span5 { + width: 380px; +} +.span4 { + width: 300px; +} +.span3 { + width: 220px; +} +.span2 { + width: 140px; +} +.span1 { + width: 60px; +} +.offset12 { + margin-left: 980px; +} +.offset11 { + margin-left: 900px; +} +.offset10 { + margin-left: 820px; +} +.offset9 { + margin-left: 740px; +} +.offset8 { + margin-left: 660px; +} +.offset7 { + margin-left: 580px; +} +.offset6 { + margin-left: 500px; +} +.offset5 { + margin-left: 420px; +} +.offset4 { + margin-left: 340px; +} +.offset3 { + margin-left: 260px; +} +.offset2 { + margin-left: 180px; +} +.offset1 { + margin-left: 100px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, +.row-fluid:after { + display: table; + content: ""; + line-height: 0; +} +.row-fluid:after { + clear: both; +} +.row-fluid:before, +.row-fluid:after { + display: table; + content: ""; + line-height: 0; +} +.row-fluid:after { + clear: both; +} +.row-fluid [class*="span"] { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; +} +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, +.row-fluid:after { + display: table; + content: ""; + line-height: 0; +} +.row-fluid:after { + clear: both; +} +.row-fluid:before, +.row-fluid:after { + display: table; + content: ""; + line-height: 0; +} +.row-fluid:after { + clear: both; +} +.row-fluid [class*="span"] { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; +} +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} +.container:before, +.container:after { + display: table; + content: ""; + line-height: 0; +} +.container:after { + clear: both; +} +.container:before, +.container:after { + display: table; + content: ""; + line-height: 0; +} +.container:after { + clear: both; +} +.container:before, +.container:after { + display: table; + content: ""; + line-height: 0; +} +.container:after { + clear: both; +} +.container:before, +.container:after { + display: table; + content: ""; + line-height: 0; +} +.container:after { + clear: both; +} +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} +.container-fluid:before, +.container-fluid:after { + display: table; + content: ""; + line-height: 0; +} +.container-fluid:after { + clear: both; +} +.container-fluid:before, +.container-fluid:after { + display: table; + content: ""; + line-height: 0; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9.5px; +} +.lead { + margin-bottom: 19px; + font-size: 19.5px; + font-weight: 200; + line-height: 28.5px; +} +small { + font-size: 85%; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +cite { + font-style: normal; +} +.muted { + color: #999999; +} +a.muted:hover, +a.muted:focus { + color: #808080; +} +.text-warning { + color: #c09853; +} +a.text-warning:hover, +a.text-warning:focus { + color: #a47e3c; +} +.text-error { + color: #b94a48; +} +a.text-error:hover, +a.text-error:focus { + color: #953b39; +} +.text-info { + color: #3a87ad; +} +a.text-info:hover, +a.text-info:focus { + color: #2d6987; +} +.text-success { + color: #468847; +} +a.text-success:hover, +a.text-success:focus { + color: #356635; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 9.5px 0; + font-family: inherit; + font-weight: bold; + line-height: 19px; + color: inherit; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + line-height: 1; + color: #999999; +} +h1, +h2, +h3 { + line-height: 38px; +} +h1 { + font-size: 35.75px; +} +h2 { + font-size: 29.25px; +} +h3 { + font-size: 22.75px; +} +h4 { + font-size: 16.25px; +} +h5 { + font-size: 13px; +} +h6 { + font-size: 11.049999999999999px; +} +h1 small { + font-size: 22.75px; +} +h2 small { + font-size: 16.25px; +} +h3 small { + font-size: 13px; +} +h4 small { + font-size: 13px; +} +.page-header { + padding-bottom: 8.5px; + margin: 19px 0 28.5px; + border-bottom: 1px solid #eeeeee; +} +ul, +ol { + padding: 0; + margin: 0 0 9.5px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +li { + line-height: 19px; +} +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; +} +ul.inline > li, +ol.inline > li { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + padding-left: 5px; + padding-right: 5px; +} +dl { + margin-bottom: 19px; +} +dt, +dd { + line-height: 19px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9.5px; +} +.dl-horizontal { + *zoom: 1; +} +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + content: ""; + line-height: 0; +} +.dl-horizontal:after { + clear: both; +} +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + content: ""; + line-height: 0; +} +.dl-horizontal:after { + clear: both; +} +.dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.dl-horizontal dd { + margin-left: 180px; +} +hr { + margin: 19px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 19px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16.25px; + font-weight: 300; + line-height: 1.25; +} +blockquote small { + display: block; + line-height: 19px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} +blockquote.pull-right small:before { + content: ''; +} +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 19px; + font-style: normal; + line-height: 19px; +} +code, +pre { + padding: 0 3px 2px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 11px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 2px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; + white-space: nowrap; +} +pre { + display: block; + padding: 9px; + margin: 0 0 9.5px; + font-size: 12px; + line-height: 19px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +pre.prettyprint { + margin-bottom: 19px; +} +pre code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 19px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 19px; + font-size: 19.5px; + line-height: 38px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +legend small { + font-size: 14.25px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 19px; +} +input, +button, +select, +textarea { + font-family: 'Open Sans', sans-serif; +} +label { + display: block; + margin-bottom: 5px; +} +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 19px; + padding: 4px 6px; + margin-bottom: 9.5px; + font-size: 13px; + line-height: 19px; + color: #555555; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + vertical-align: middle; +} +input, +textarea, +.uneditable-input { + width: 206px; +} +textarea { + height: auto; +} +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear .2s, box-shadow linear .2s; + -moz-transition: border linear .2s, box-shadow linear .2s; + -o-transition: border linear .2s, box-shadow linear .2s; + transition: border linear .2s, box-shadow linear .2s; +} +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6); + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6); +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + *margin-top: 0; + /* IE7 */ + + margin-top: 1px \9; + /* IE8-9 */ + + line-height: normal; +} +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} +select, +input[type="file"] { + height: 29px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 29px; +} +select { + width: 220px; + border: 1px solid #cccccc; + background-color: #ffffff; +} +select[multiple], +select[size] { + height: auto; +} +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.uneditable-input, +.uneditable-textarea { + color: #999999; + background-color: #fcfcfc; + border-color: #cccccc; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +.uneditable-input { + overflow: hidden; + white-space: nowrap; +} +.uneditable-textarea { + width: auto; + height: auto; +} +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #999999; +} +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #999999; +} +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} +.radio, +.checkbox { + min-height: 19px; + padding-left: 20px; +} +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} +input, +textarea, +.uneditable-input { + margin-left: 0; +} +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} +input, +textarea, +.uneditable-input { + margin-left: 0; +} +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} +.controls-row { + *zoom: 1; +} +.controls-row:before, +.controls-row:after { + display: table; + content: ""; + line-height: 0; +} +.controls-row:after { + clear: both; +} +.controls-row:before, +.controls-row:after { + display: table; + content: ""; + line-height: 0; +} +.controls-row:after { + clear: both; +} +.controls-row [class*="span"], +.row-fluid .controls-row [class*="span"] { + float: left; +} +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} +.control-group.warning .control-label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; +} +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.warning .control-label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; +} +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error .control-label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; +} +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.error .control-label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; +} +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success .control-label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; +} +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +.control-group.success .control-label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; +} +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:invalid:focus, +textarea:focus:invalid:focus, +select:focus:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 18px 20px 19px; + margin-top: 19px; + margin-bottom: 19px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} +.form-actions:before, +.form-actions:after { + display: table; + content: ""; + line-height: 0; +} +.form-actions:after { + clear: both; +} +.form-actions:before, +.form-actions:after { + display: table; + content: ""; + line-height: 0; +} +.form-actions:after { + clear: both; +} +.help-block, +.help-inline { + color: #595959; +} +.help-block { + display: block; + margin-bottom: 9.5px; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + vertical-align: middle; + padding-left: 5px; +} +.input-append, +.input-prepend { + display: inline-block; + margin-bottom: 9.5px; + vertical-align: middle; + font-size: 0; + white-space: nowrap; +} +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input, +.input-append .dropdown-menu, +.input-prepend .dropdown-menu, +.input-append .popover, +.input-prepend .popover { + font-size: 13px; +} +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: top; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.input-append input:focus, +.input-prepend input:focus, +.input-append select:focus, +.input-prepend select:focus, +.input-append .uneditable-input:focus, +.input-prepend .uneditable-input:focus { + z-index: 2; +} +.input-append .add-on, +.input-prepend .add-on { + display: inline-block; + width: auto; + height: 19px; + min-width: 16px; + padding: 4px 5px; + font-size: 13px; + font-weight: normal; + line-height: 19px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #eeeeee; + border: 1px solid #ccc; +} +.input-append .add-on, +.input-prepend .add-on, +.input-append .btn, +.input-prepend .btn, +.input-append .btn-group > .dropdown-toggle, +.input-prepend .btn-group > .dropdown-toggle { + vertical-align: top; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.input-append .active, +.input-prepend .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.input-append .add-on, +.input-append .btn, +.input-append .btn-group { + margin-left: -1px; +} +.input-append .add-on:last-child, +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.input-prepend.input-append input + .btn-group .btn, +.input-prepend.input-append select + .btn-group .btn, +.input-prepend.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.input-prepend.input-append .btn-group:first-child { + margin-left: 0; +} +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +/* Allow for input prepend/append in search forms */ +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.form-search .input-append .search-query { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} +.form-search .input-append .btn { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} +.form-search .input-prepend .search-query { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} +.form-search .input-prepend .btn { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 0; + vertical-align: middle; +} +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} +.control-group { + margin-bottom: 9.5px; +} +legend + .control-group { + margin-top: 19px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 19px; + *zoom: 1; +} +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + content: ""; + line-height: 0; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + content: ""; + line-height: 0; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 180px; + *margin-left: 0; +} +.form-horizontal .controls:first-child { + *padding-left: 180px; +} +.form-horizontal .help-block { + margin-bottom: 0; +} +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block, +.form-horizontal .uneditable-input + .help-block, +.form-horizontal .input-prepend + .help-block, +.form-horizontal .input-append + .help-block { + margin-top: 9.5px; +} +.form-horizontal .form-actions { + padding-left: 180px; +} +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 19px; +} +.table th, +.table td { + padding: 8px; + line-height: 19px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #dddddd; +} +.table .table { + background-color: #ffffff; +} +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapse; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child > th:first-child, +.table-bordered tbody:first-child tr:first-child > td:first-child, +.table-bordered tbody:first-child tr:first-child > th:first-child { + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; +} +.table-bordered thead:first-child tr:first-child > th:last-child, +.table-bordered tbody:first-child tr:first-child > td:last-child, +.table-bordered tbody:first-child tr:first-child > th:last-child { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; +} +.table-bordered thead:last-child tr:last-child > th:first-child, +.table-bordered tbody:last-child tr:last-child > td:first-child, +.table-bordered tbody:last-child tr:last-child > th:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > th:first-child { + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.table-bordered thead:last-child tr:last-child > th:last-child, +.table-bordered tbody:last-child tr:last-child > td:last-child, +.table-bordered tbody:last-child tr:last-child > th:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > th:last-child { + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { + -webkit-border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; + border-bottom-left-radius: 0; +} +.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; + border-bottom-right-radius: 0; +} +.table-bordered caption + thead tr:first-child th:first-child, +.table-bordered caption + tbody tr:first-child td:first-child, +.table-bordered colgroup + thead tr:first-child th:first-child, +.table-bordered colgroup + tbody tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; +} +.table-bordered caption + thead tr:first-child th:last-child, +.table-bordered caption + tbody tr:first-child td:last-child, +.table-bordered colgroup + thead tr:first-child th:last-child, +.table-bordered colgroup + tbody tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; +} +.table-striped tbody > tr:nth-child(odd) > td, +.table-striped tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} +.table-hover tbody tr:hover > td, +.table-hover tbody tr:hover > th { + background-color: #f5f5f5; +} +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; + margin-left: 0; +} +.table td.span1, +.table th.span1 { + float: none; + width: 44px; + margin-left: 0; +} +.table td.span2, +.table th.span2 { + float: none; + width: 124px; + margin-left: 0; +} +.table td.span3, +.table th.span3 { + float: none; + width: 204px; + margin-left: 0; +} +.table td.span4, +.table th.span4 { + float: none; + width: 284px; + margin-left: 0; +} +.table td.span5, +.table th.span5 { + float: none; + width: 364px; + margin-left: 0; +} +.table td.span6, +.table th.span6 { + float: none; + width: 444px; + margin-left: 0; +} +.table td.span7, +.table th.span7 { + float: none; + width: 524px; + margin-left: 0; +} +.table td.span8, +.table th.span8 { + float: none; + width: 604px; + margin-left: 0; +} +.table td.span9, +.table th.span9 { + float: none; + width: 684px; + margin-left: 0; +} +.table td.span10, +.table th.span10 { + float: none; + width: 764px; + margin-left: 0; +} +.table td.span11, +.table th.span11 { + float: none; + width: 844px; + margin-left: 0; +} +.table td.span12, +.table th.span12 { + float: none; + width: 924px; + margin-left: 0; +} +.table tbody tr.success > td { + background-color: #dff0d8; +} +.table tbody tr.error > td { + background-color: #f2dede; +} +.table tbody tr.warning > td { + background-color: #fcf8e3; +} +.table tbody tr.info > td { + background-color: #d9edf7; +} +.table-hover tbody tr.success:hover > td { + background-color: #d0e9c6; +} +.table-hover tbody tr.error:hover > td { + background-color: #ebcccc; +} +.table-hover tbody tr.warning:hover > td { + background-color: #faf2cc; +} +.table-hover tbody tr.info:hover > td { + background-color: #c4e3f3; +} +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + margin-top: 1px; +} +/* White icons with optional class, or on hover/focus/active states of certain elements */ +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:focus > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { + background-image: url("../../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; + width: 16px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; + width: 16px; +} +.icon-folder-open { + background-position: -408px -120px; + width: 16px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.icon-hdd { + background-position: 0 -144px; +} +.icon-bullhorn { + background-position: -24px -144px; +} +.icon-bell { + background-position: -48px -144px; +} +.icon-certificate { + background-position: -72px -144px; +} +.icon-thumbs-up { + background-position: -96px -144px; +} +.icon-thumbs-down { + background-position: -120px -144px; +} +.icon-hand-right { + background-position: -144px -144px; +} +.icon-hand-left { + background-position: -168px -144px; +} +.icon-hand-up { + background-position: -192px -144px; +} +.icon-hand-down { + background-position: -216px -144px; +} +.icon-circle-arrow-right { + background-position: -240px -144px; +} +.icon-circle-arrow-left { + background-position: -264px -144px; +} +.icon-circle-arrow-up { + background-position: -288px -144px; +} +.icon-circle-arrow-down { + background-position: -312px -144px; +} +.icon-globe { + background-position: -336px -144px; +} +.icon-wrench { + background-position: -360px -144px; +} +.icon-tasks { + background-position: -384px -144px; +} +.icon-filter { + background-position: -408px -144px; +} +.icon-briefcase { + background-position: -432px -144px; +} +.icon-fullscreen { + background-position: -456px -144px; +} +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 8.5px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 19px; + color: #333333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + text-decoration: none; + color: #ffffff; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + outline: 0; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: default; +} +.open { + *z-index: 1000; +} +.open > .dropdown-menu { + display: block; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} +.dropdown-submenu { + position: relative; +} +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + -webkit-border-radius: 5px 5px 5px 0; + -moz-border-radius: 5px 5px 5px 0; + border-radius: 5px 5px 5px 0; +} +.dropdown-submenu > a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: #cccccc; + margin-top: 5px; + margin-right: -10px; +} +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} +.dropdown-submenu.pull-left { + float: none; +} +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} +.dropdown .dropdown-menu .nav-header { + padding-left: 20px; + padding-right: 20px; +} +.typeahead { + z-index: 1051; + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 19px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.btn { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + padding: 4px 12px; + margin-bottom: 0; + font-size: 13px; + line-height: 19px; + text-align: center; + vertical-align: middle; + cursor: pointer; + color: #333333; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #e6e6e6; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #cccccc; + *border: 0; + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + *margin-left: .3em; + -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); +} +.btn:hover, +.btn:focus, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} +.btn:active, +.btn.active { + background-color: #cccccc \9; +} +.btn:hover, +.btn:focus, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} +.btn:active, +.btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, +.btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); + -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); + box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); +} +.btn.disabled, +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 11px 19px; + font-size: 16.25px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} +.btn-small { + padding: 2px 10px; + font-size: 11.049999999999999px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 0 6px; + font-size: 9.75px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.btn-block { + display: block; + width: 100%; + padding-left: 0; + padding-right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #0044cc; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #f89406; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #bd362f; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(to bottom, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #51a351; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #2f96b4; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + background-image: -moz-linear-gradient(top, #444444, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #222222; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:focus, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} +.btn-inverse:hover, +.btn-inverse:focus, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-link { + border-color: transparent; + cursor: pointer; + color: #0088cc; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-link:hover, +.btn-link:focus { + color: #005580; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { + color: #333333; + text-decoration: none; +} +.btn-group { + position: relative; + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + font-size: 0; + vertical-align: middle; + white-space: nowrap; + *margin-left: .3em; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + font-size: 0; + margin-top: 9.5px; + margin-bottom: 9.5px; +} +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group { + margin-left: 5px; +} +.btn-group > .btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group > .btn + .btn { + margin-left: -1px; +} +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: 13px; +} +.btn-group > .btn-mini { + font-size: 9.75px; +} +.btn-group > .btn-small { + font-size: 11.049999999999999px; +} +.btn-group > .btn-large { + font-size: 16.25px; +} +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + -moz-box-shadow: inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + box-shadow: inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group > .btn-mini + .dropdown-toggle { + padding-left: 5px; + padding-right: 5px; + *padding-top: 2px; + *padding-bottom: 2px; +} +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} +.btn-group > .btn-large + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; + *padding-top: 7px; + *padding-bottom: 7px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); + -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); + box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05); +} +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0044cc; +} +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} +.btn .caret { + margin-top: 8px; + margin-left: 0; +} +.btn-large .caret { + margin-top: 6px; +} +.btn-large .caret { + border-left-width: 5px; + border-right-width: 5px; + border-top-width: 5px; +} +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} +.dropup .btn-large .caret { + border-bottom-width: 5px; +} +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group-vertical > .btn + .btn { + margin-left: 0; + margin-top: -1px; +} +.btn-group-vertical > .btn:first-child { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.btn-group-vertical > .btn:last-child { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.btn-group-vertical > .btn-large:first-child { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} +.btn-group-vertical > .btn-large:last-child { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 19px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, +.alert h4 { + color: #c09853; +} +.alert h4 { + margin: 0; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 19px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; + color: #468847; +} +.alert-success h4 { + color: #468847; +} +.alert-danger, +.alert-error { + background-color: #f2dede; + border-color: #eed3d7; + color: #b94a48; +} +.alert-danger h4, +.alert-error h4 { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; + color: #3a87ad; +} +.alert-info h4 { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 19px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.nav > li > a > img { + max-width: none; +} +.nav > .pull-right { + float: right; +} +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 19px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 15px; + padding-right: 15px; + margin-bottom: 0; +} +.nav-list > li > a, +.nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 8.5px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} +.nav-tabs, +.nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; + line-height: 0; +} +.nav-tabs:after, +.nav-pills:after { + clear: both; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; + line-height: 0; +} +.nav-tabs:after, +.nav-pills:after { + clear: both; +} +.nav-tabs > li, +.nav-pills > li { + float: left; +} +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 19px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover, +.nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills > .active > a, +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.nav .dropdown-toggle .caret { + border-top-color: #0088cc; + border-bottom-color: #0088cc; + margin-top: 6px; +} +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} +/* move down carets for tabs */ +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, +.tabbable:after { + display: table; + content: ""; + line-height: 0; +} +.tabbable:after { + clear: both; +} +.tabbable:before, +.tabbable:after { + display: table; + content: ""; + line-height: 0; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: auto; +} +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} +.tab-content > .active, +.pill-content > .active { + display: block; +} +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below > .nav-tabs > li > a:hover, +.tabs-below > .nav-tabs > li > a:focus { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.nav > .disabled > a { + color: #999999; +} +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + cursor: default; +} +.navbar { + overflow: visible; + margin-bottom: 19px; + *position: relative; + *z-index: 2; +} +.navbar-inner { + min-height: 40px; + padding-left: 20px; + padding-right: 20px; + background-color: #fafafa; + background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); + background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); + background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + border: 1px solid #d4d4d4; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + *zoom: 1; +} +.navbar-inner:before, +.navbar-inner:after { + display: table; + content: ""; + line-height: 0; +} +.navbar-inner:after { + clear: both; +} +.navbar-inner:before, +.navbar-inner:after { + display: table; + content: ""; + line-height: 0; +} +.navbar-inner:after { + clear: both; +} +.navbar .container { + width: auto; +} +.nav-collapse.collapse { + height: auto; + overflow: visible; +} +.navbar .brand { + float: left; + display: block; + padding: 10.5px 20px 10.5px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: #777777; + text-shadow: 0 1px 0 #ffffff; +} +.navbar .brand:hover, +.navbar .brand:focus { + text-decoration: none; +} +.navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #777777; +} +.navbar-link { + color: #777777; +} +.navbar-link:hover, +.navbar-link:focus { + color: #333333; +} +.navbar .divider-vertical { + height: 40px; + margin: 0 9px; + border-left: 1px solid #f2f2f2; + border-right: 1px solid #ffffff; +} +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, +.navbar-form:after { + display: table; + content: ""; + line-height: 0; +} +.navbar-form:after { + clear: both; +} +.navbar-form:before, +.navbar-form:after { + display: table; + content: ""; + line-height: 0; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input, +.navbar-form select, +.navbar-form .btn { + display: inline-block; + margin-bottom: 0; +} +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 5px; + white-space: nowrap; +} +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-search .search-query { + margin-bottom: 0; + padding: 4px 14px; + font-family: 'Open Sans', sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.navbar-static-top { + position: static; + margin-bottom: 0; +} +.navbar-static-top .navbar-inner { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} +.navbar-fixed-top { + top: 0; +} +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + -webkit-box-shadow: 0 1px 10px rgba(0,0,0,.1); + -moz-box-shadow: 0 1px 10px rgba(0,0,0,.1); + box-shadow: 0 1px 10px rgba(0,0,0,.1); +} +.navbar-fixed-bottom { + bottom: 0; +} +.navbar-fixed-bottom .navbar-inner { + -webkit-box-shadow: 0 -1px 10px rgba(0,0,0,.1); + -moz-box-shadow: 0 -1px 10px rgba(0,0,0,.1); + box-shadow: 0 -1px 10px rgba(0,0,0,.1); +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; + margin-right: 0; +} +.navbar .nav > li { + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10.5px 15px 10.5px; + color: #777777; + text-decoration: none; + text-shadow: 0 1px 0 #ffffff; +} +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + background-color: transparent; + color: #333333; + text-decoration: none; +} +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #555555; + text-decoration: none; + background-color: #e5e5e5; + -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); +} +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #ededed; + background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); + background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); + border-color: #e5e5e5 #e5e5e5 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #e5e5e5; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075); + -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075); + box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075); +} +.navbar .btn-navbar:hover, +.navbar .btn-navbar:focus, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} +.navbar .btn-navbar:hover, +.navbar .btn-navbar:focus, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.navbar .nav > li > .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .nav > li > .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar-fixed-bottom .nav > li > .dropdown-menu:before { + border-top: 7px solid #ccc; + border-top-color: rgba(0, 0, 0, 0.2); + border-bottom: 0; + bottom: -7px; + top: auto; +} +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + border-top: 6px solid #ffffff; + border-bottom: 0; + bottom: -6px; + top: auto; +} +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + background-color: #e5e5e5; + color: #555555; +} +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + left: auto; + right: 0; +} +.navbar .pull-right > li > .dropdown-menu:before, +.navbar .nav > li > .dropdown-menu.pull-right:before { + left: auto; + right: 12px; +} +.navbar .pull-right > li > .dropdown-menu:after, +.navbar .nav > li > .dropdown-menu.pull-right:after { + left: auto; + right: 13px; +} +.navbar .pull-right > li > .dropdown-menu .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { + left: auto; + right: 100%; + margin-left: 0; + margin-right: -1px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} +.navbar-inverse .navbar-inner { + background-color: #1b1b1b; + background-image: -moz-linear-gradient(top, #222222, #111111); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); + background-image: -webkit-linear-gradient(top, #222222, #111111); + background-image: -o-linear-gradient(top, #222222, #111111); + background-image: linear-gradient(to bottom, #222222, #111111); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); + border-color: #252525; +} +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #999999; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover, +.navbar-inverse .brand:focus, +.navbar-inverse .nav > li > a:focus { + color: #ffffff; +} +.navbar-inverse .brand { + color: #999999; +} +.navbar-inverse .navbar-text { + color: #999999; +} +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + background-color: transparent; + color: #ffffff; +} +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #ffffff; + background-color: #111111; +} +.navbar-inverse .navbar-link { + color: #999999; +} +.navbar-inverse .navbar-link:hover, +.navbar-inverse .navbar-link:focus { + color: #ffffff; +} +.navbar-inverse .divider-vertical { + border-left-color: #111111; + border-right-color: #222222; +} +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + background-color: #111111; + color: #ffffff; +} +.navbar-inverse .nav li.dropdown > a:hover .caret, +.navbar-inverse .nav li.dropdown > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #515151; + border-color: #111111; + -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15); + -moz-box-shadow: inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15); + box-shadow: inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15); + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-inverse .btn-navbar { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e0e0e; + background-image: -moz-linear-gradient(top, #151515, #040404); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); + background-image: -webkit-linear-gradient(top, #151515, #040404); + background-image: -o-linear-gradient(top, #151515, #040404); + background-image: linear-gradient(to bottom, #151515, #040404); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); + border-color: #040404 #040404 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #040404; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:focus, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #040404; + *background-color: #000000; +} +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \9; +} +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:focus, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #040404; + *background-color: #000000; +} +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \9; +} +.breadcrumb { + padding: 8px 15px; + margin: 0 0 19px; + list-style: none; + background-color: #f5f5f5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb > li > .divider { + padding: 0 5px; + color: #ccc; +} +.breadcrumb > .active { + color: #999999; +} +.pagination { + margin: 19px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination ul > li { + display: inline; +} +.pagination ul > li > a, +.pagination ul > li > span { + float: left; + padding: 4px 12px; + line-height: 19px; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + border-left-width: 0; +} +.pagination ul > li > a:hover, +.pagination ul > li > a:focus, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: #f5f5f5; +} +.pagination ul > .active > a, +.pagination ul > .active > span { + color: #999999; + cursor: default; +} +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pagination-large ul > li > a, +.pagination-large ul > li > span { + padding: 11px 19px; + font-size: 16.25px; +} +.pagination-large ul > li:first-child > a, +.pagination-large ul > li:first-child > span { + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.pagination-large ul > li:last-child > a, +.pagination-large ul > li:last-child > span { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.pagination-mini ul > li:first-child > a, +.pagination-small ul > li:first-child > a, +.pagination-mini ul > li:first-child > span, +.pagination-small ul > li:first-child > span { + -webkit-border-top-left-radius: 3px; + -moz-border-radius-topleft: 3px; + border-top-left-radius: 3px; + -webkit-border-bottom-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + border-bottom-left-radius: 3px; +} +.pagination-mini ul > li:last-child > a, +.pagination-small ul > li:last-child > a, +.pagination-mini ul > li:last-child > span, +.pagination-small ul > li:last-child > span { + -webkit-border-top-right-radius: 3px; + -moz-border-radius-topright: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + -moz-border-radius-bottomright: 3px; + border-bottom-right-radius: 3px; +} +.pagination-small ul > li > a, +.pagination-small ul > li > span { + padding: 2px 10px; + font-size: 11.049999999999999px; +} +.pagination-mini ul > li > a, +.pagination-mini ul > li > span { + padding: 0 6px; + font-size: 9.75px; +} +.pager { + margin: 19px 0; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, +.pager:after { + display: table; + content: ""; + line-height: 0; +} +.pager:after { + clear: both; +} +.pager:before, +.pager:after { + display: table; + content: ""; + line-height: 0; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + background-color: #fff; + cursor: default; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: 1050; + width: 560px; + margin-left: -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; + outline: none; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 10%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-header h3 { + margin: 0; + line-height: 30px; +} +.modal-body { + position: relative; + overflow-y: auto; + max-height: 400px; + padding: 15px; +} +.modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, +.modal-footer:after { + display: table; + content: ""; + line-height: 0; +} +.modal-footer:after { + clear: both; +} +.modal-footer:before, +.modal-footer:after { + display: table; + content: ""; + line-height: 0; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn + .btn { + margin-left: 5px; + margin-bottom: 0; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +.tooltip { + position: absolute; + z-index: 1030; + display: block; + visibility: visible; + font-size: 11px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.tooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.tooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.tooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.tooltip-inner { + max-width: 200px; + padding: 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + background-color: #ffffff; + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + white-space: normal; +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} +.popover-title:empty { + display: none; +} +.popover-content { + padding: 9px 14px; +} +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover .arrow { + border-width: 11px; +} +.popover .arrow:after { + border-width: 10px; + content: ""; +} +.popover.top .arrow { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, 0.25); + bottom: -11px; +} +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #ffffff; +} +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, 0.25); +} +.popover.right .arrow:after { + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #ffffff; +} +.popover.bottom .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, 0.25); + top: -11px; +} +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #ffffff; +} +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, 0.25); +} +.popover.left .arrow:after { + right: 1px; + border-right-width: 0; + border-left-color: #ffffff; + bottom: -10px; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, +.thumbnails:after { + display: table; + content: ""; + line-height: 0; +} +.thumbnails:after { + clear: both; +} +.thumbnails:before, +.thumbnails:after { + display: table; + content: ""; + line-height: 0; +} +.thumbnails:after { + clear: both; +} +.row-fluid .thumbnails { + margin-left: 0; +} +.thumbnails > li { + float: left; + margin-bottom: 19px; + margin-left: 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 19px; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +a.thumbnail:hover, +a.thumbnail:focus { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; + color: #555555; +} +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} +.media, +.media .media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media-object { + display: block; +} +.media-heading { + margin: 0 0 5px; +} +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-right { + margin-left: 10px; +} +.media-list { + margin-left: 0; + list-style: none; +} +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: 10.998px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + vertical-align: baseline; + white-space: nowrap; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; +} +.label { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.badge { + padding-left: 9px; + padding-right: 9px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} +.label:empty, +.badge:empty { + display: none; +} +a.label:hover, +a.label:focus, +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.label-important, +.badge-important { + background-color: #b94a48; +} +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} +.label-warning, +.badge-warning { + background-color: #f89406; +} +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} +.label-success, +.badge-success { + background-color: #468847; +} +.label-success[href], +.badge-success[href] { + background-color: #356635; +} +.label-info, +.badge-info { + background-color: #3a87ad; +} +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} +.label-inverse, +.badge-inverse { + background-color: #333333; +} +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} +.btn .label, +.btn .badge { + position: relative; + top: -1px; +} +.btn-mini .label, +.btn-mini .badge { + top: 0; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 19px; + margin-bottom: 19px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 100%; + color: #ffffff; + float: left; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress .bar + .bar { + -webkit-box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15); + -moz-box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15); + box-shadow: inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15); +} +.progress-striped .bar { + background-color: #149bdf; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar, +.progress .bar-danger { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); +} +.progress-danger.progress-striped .bar, +.progress-striped .bar-danger { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar, +.progress .bar-success { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(to bottom, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); +} +.progress-success.progress-striped .bar, +.progress-striped .bar-success { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar, +.progress .bar-info { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(to bottom, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); +} +.progress-info.progress-striped .bar, +.progress-striped .bar-info { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-warning .bar, +.progress .bar-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); +} +.progress-warning.progress-striped .bar, +.progress-striped .bar-warning { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 19px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-toggle { + cursor: pointer; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 19px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel-inner > .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + line-height: 1; +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; +} +.carousel-indicators li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255, 255, 255, 0.25); + border-radius: 5px; +} +.carousel-indicators .active { + background-color: #fff; +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 15px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, +.carousel-caption p { + color: #ffffff; + line-height: 19px; +} +.carousel-caption h4 { + margin: 0 0 5px; +} +.carousel-caption p { + margin-bottom: 0; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: 28.5px; + color: inherit; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + color: inherit; + letter-spacing: -1px; +} +.hero-unit li { + line-height: 28.5px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} +.affix { + position: fixed; +} +/*! + * Bootstrap Responsive v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, +.clearfix:after { + display: table; + content: ""; + line-height: 0; +} +.clearfix:after { + clear: both; +} +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.input-block-level { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +@-ms-viewport { + width: device-width; +} +.hidden { + display: none; + visibility: hidden; +} +.visible-phone { + display: none !important; +} +.visible-tablet { + display: none !important; +} +.hidden-desktop { + display: none !important; +} +.visible-desktop { + display: inherit !important; +} +@media (min-width: 768px) and (max-width: 979px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } +} +@media (max-width: 767px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: inherit !important; + } + .hidden-print { + display: none !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + line-height: 0; + } + .row:after { + clear: both; + } + .row:before, + .row:after { + display: table; + content: ""; + line-height: 0; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 30px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + line-height: 0; + } + .row:after { + clear: both; + } + .row:before, + .row:after { + display: table; + content: ""; + line-height: 0; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 30px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + line-height: 0; + } + .row-fluid:after { + clear: both; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + line-height: 0; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; + margin-left: 2.564102564102564%; + *margin-left: 2.5109110747408616%; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.564102564102564%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145299145%; + *width: 91.39979996362975%; + } + .row-fluid .span10 { + width: 82.90598290598291%; + *width: 82.8527914166212%; + } + .row-fluid .span9 { + width: 74.35897435897436%; + *width: 74.30578286961266%; + } + .row-fluid .span8 { + width: 65.81196581196582%; + *width: 65.75877432260411%; + } + .row-fluid .span7 { + width: 57.26495726495726%; + *width: 57.21176577559556%; + } + .row-fluid .span6 { + width: 48.717948717948715%; + *width: 48.664757228587014%; + } + .row-fluid .span5 { + width: 40.17094017094017%; + *width: 40.11774868157847%; + } + .row-fluid .span4 { + width: 31.623931623931625%; + *width: 31.570740134569924%; + } + .row-fluid .span3 { + width: 23.076923076923077%; + *width: 23.023731587561375%; + } + .row-fluid .span2 { + width: 14.52991452991453%; + *width: 14.476723040552828%; + } + .row-fluid .span1 { + width: 5.982905982905983%; + *width: 5.929714493544281%; + } + .row-fluid .offset12 { + margin-left: 105.12820512820512%; + *margin-left: 105.02182214948171%; + } + .row-fluid .offset12:first-child { + margin-left: 102.56410256410257%; + *margin-left: 102.45771958537915%; + } + .row-fluid .offset11 { + margin-left: 96.58119658119658%; + *margin-left: 96.47481360247316%; + } + .row-fluid .offset11:first-child { + margin-left: 94.01709401709402%; + *margin-left: 93.91071103837061%; + } + .row-fluid .offset10 { + margin-left: 88.03418803418803%; + *margin-left: 87.92780505546462%; + } + .row-fluid .offset10:first-child { + margin-left: 85.47008547008548%; + *margin-left: 85.36370249136206%; + } + .row-fluid .offset9 { + margin-left: 79.48717948717949%; + *margin-left: 79.38079650845607%; + } + .row-fluid .offset9:first-child { + margin-left: 76.92307692307693%; + *margin-left: 76.81669394435352%; + } + .row-fluid .offset8 { + margin-left: 70.94017094017094%; + *margin-left: 70.83378796144753%; + } + .row-fluid .offset8:first-child { + margin-left: 68.37606837606839%; + *margin-left: 68.26968539734497%; + } + .row-fluid .offset7 { + margin-left: 62.393162393162385%; + *margin-left: 62.28677941443899%; + } + .row-fluid .offset7:first-child { + margin-left: 59.82905982905982%; + *margin-left: 59.72267685033642%; + } + .row-fluid .offset6 { + margin-left: 53.84615384615384%; + *margin-left: 53.739770867430444%; + } + .row-fluid .offset6:first-child { + margin-left: 51.28205128205128%; + *margin-left: 51.175668303327875%; + } + .row-fluid .offset5 { + margin-left: 45.299145299145295%; + *margin-left: 45.1927623204219%; + } + .row-fluid .offset5:first-child { + margin-left: 42.73504273504273%; + *margin-left: 42.62865975631933%; + } + .row-fluid .offset4 { + margin-left: 36.75213675213675%; + *margin-left: 36.645753773413354%; + } + .row-fluid .offset4:first-child { + margin-left: 34.18803418803419%; + *margin-left: 34.081651209310785%; + } + .row-fluid .offset3 { + margin-left: 28.205128205128204%; + *margin-left: 28.0987452264048%; + } + .row-fluid .offset3:first-child { + margin-left: 25.641025641025642%; + *margin-left: 25.53464266230224%; + } + .row-fluid .offset2 { + margin-left: 19.65811965811966%; + *margin-left: 19.551736679396257%; + } + .row-fluid .offset2:first-child { + margin-left: 17.094017094017094%; + *margin-left: 16.98763411529369%; + } + .row-fluid .offset1 { + margin-left: 11.11111111111111%; + *margin-left: 11.004728132387708%; + } + .row-fluid .offset1:first-child { + margin-left: 8.547008547008547%; + *margin-left: 8.440625568285142%; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + line-height: 0; + } + .row-fluid:after { + clear: both; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + line-height: 0; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; + margin-left: 2.564102564102564%; + *margin-left: 2.5109110747408616%; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.564102564102564%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145299145%; + *width: 91.39979996362975%; + } + .row-fluid .span10 { + width: 82.90598290598291%; + *width: 82.8527914166212%; + } + .row-fluid .span9 { + width: 74.35897435897436%; + *width: 74.30578286961266%; + } + .row-fluid .span8 { + width: 65.81196581196582%; + *width: 65.75877432260411%; + } + .row-fluid .span7 { + width: 57.26495726495726%; + *width: 57.21176577559556%; + } + .row-fluid .span6 { + width: 48.717948717948715%; + *width: 48.664757228587014%; + } + .row-fluid .span5 { + width: 40.17094017094017%; + *width: 40.11774868157847%; + } + .row-fluid .span4 { + width: 31.623931623931625%; + *width: 31.570740134569924%; + } + .row-fluid .span3 { + width: 23.076923076923077%; + *width: 23.023731587561375%; + } + .row-fluid .span2 { + width: 14.52991452991453%; + *width: 14.476723040552828%; + } + .row-fluid .span1 { + width: 5.982905982905983%; + *width: 5.929714493544281%; + } + .row-fluid .offset12 { + margin-left: 105.12820512820512%; + *margin-left: 105.02182214948171%; + } + .row-fluid .offset12:first-child { + margin-left: 102.56410256410257%; + *margin-left: 102.45771958537915%; + } + .row-fluid .offset11 { + margin-left: 96.58119658119658%; + *margin-left: 96.47481360247316%; + } + .row-fluid .offset11:first-child { + margin-left: 94.01709401709402%; + *margin-left: 93.91071103837061%; + } + .row-fluid .offset10 { + margin-left: 88.03418803418803%; + *margin-left: 87.92780505546462%; + } + .row-fluid .offset10:first-child { + margin-left: 85.47008547008548%; + *margin-left: 85.36370249136206%; + } + .row-fluid .offset9 { + margin-left: 79.48717948717949%; + *margin-left: 79.38079650845607%; + } + .row-fluid .offset9:first-child { + margin-left: 76.92307692307693%; + *margin-left: 76.81669394435352%; + } + .row-fluid .offset8 { + margin-left: 70.94017094017094%; + *margin-left: 70.83378796144753%; + } + .row-fluid .offset8:first-child { + margin-left: 68.37606837606839%; + *margin-left: 68.26968539734497%; + } + .row-fluid .offset7 { + margin-left: 62.393162393162385%; + *margin-left: 62.28677941443899%; + } + .row-fluid .offset7:first-child { + margin-left: 59.82905982905982%; + *margin-left: 59.72267685033642%; + } + .row-fluid .offset6 { + margin-left: 53.84615384615384%; + *margin-left: 53.739770867430444%; + } + .row-fluid .offset6:first-child { + margin-left: 51.28205128205128%; + *margin-left: 51.175668303327875%; + } + .row-fluid .offset5 { + margin-left: 45.299145299145295%; + *margin-left: 45.1927623204219%; + } + .row-fluid .offset5:first-child { + margin-left: 42.73504273504273%; + *margin-left: 42.62865975631933%; + } + .row-fluid .offset4 { + margin-left: 36.75213675213675%; + *margin-left: 36.645753773413354%; + } + .row-fluid .offset4:first-child { + margin-left: 34.18803418803419%; + *margin-left: 34.081651209310785%; + } + .row-fluid .offset3 { + margin-left: 28.205128205128204%; + *margin-left: 28.0987452264048%; + } + .row-fluid .offset3:first-child { + margin-left: 25.641025641025642%; + *margin-left: 25.53464266230224%; + } + .row-fluid .offset2 { + margin-left: 19.65811965811966%; + *margin-left: 19.551736679396257%; + } + .row-fluid .offset2:first-child { + margin-left: 17.094017094017094%; + *margin-left: 16.98763411529369%; + } + .row-fluid .offset1 { + margin-left: 11.11111111111111%; + *margin-left: 11.004728132387708%; + } + .row-fluid .offset1:first-child { + margin-left: 8.547008547008547%; + *margin-left: 8.440625568285142%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 30px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1156px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1056px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 956px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 856px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 756px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 656px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 556px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 456px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 356px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 256px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 156px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 56px; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 30px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1156px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1056px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 956px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 856px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 756px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 656px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 556px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 456px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 356px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 256px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 156px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 56px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + .row-fluid .thumbnails { + margin-left: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + line-height: 0; + } + .row:after { + clear: both; + } + .row:before, + .row:after { + display: table; + content: ""; + line-height: 0; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + line-height: 0; + } + .row:after { + clear: both; + } + .row:before, + .row:after { + display: table; + content: ""; + line-height: 0; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + line-height: 0; + } + .row-fluid:after { + clear: both; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + line-height: 0; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; + margin-left: 2.7624309392265194%; + *margin-left: 2.709239449864817%; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.7624309392265194%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.43646408839778%; + *width: 91.38327259903608%; + } + .row-fluid .span10 { + width: 82.87292817679558%; + *width: 82.81973668743387%; + } + .row-fluid .span9 { + width: 74.30939226519337%; + *width: 74.25620077583166%; + } + .row-fluid .span8 { + width: 65.74585635359117%; + *width: 65.69266486422946%; + } + .row-fluid .span7 { + width: 57.18232044198895%; + *width: 57.12912895262725%; + } + .row-fluid .span6 { + width: 48.61878453038674%; + *width: 48.56559304102504%; + } + .row-fluid .span5 { + width: 40.05524861878453%; + *width: 40.00205712942283%; + } + .row-fluid .span4 { + width: 31.491712707182323%; + *width: 31.43852121782062%; + } + .row-fluid .span3 { + width: 22.92817679558011%; + *width: 22.87498530621841%; + } + .row-fluid .span2 { + width: 14.3646408839779%; + *width: 14.311449394616199%; + } + .row-fluid .span1 { + width: 5.801104972375691%; + *width: 5.747913483013988%; + } + .row-fluid .offset12 { + margin-left: 105.52486187845304%; + *margin-left: 105.41847889972962%; + } + .row-fluid .offset12:first-child { + margin-left: 102.76243093922652%; + *margin-left: 102.6560479605031%; + } + .row-fluid .offset11 { + margin-left: 96.96132596685082%; + *margin-left: 96.8549429881274%; + } + .row-fluid .offset11:first-child { + margin-left: 94.1988950276243%; + *margin-left: 94.09251204890089%; + } + .row-fluid .offset10 { + margin-left: 88.39779005524862%; + *margin-left: 88.2914070765252%; + } + .row-fluid .offset10:first-child { + margin-left: 85.6353591160221%; + *margin-left: 85.52897613729868%; + } + .row-fluid .offset9 { + margin-left: 79.8342541436464%; + *margin-left: 79.72787116492299%; + } + .row-fluid .offset9:first-child { + margin-left: 77.07182320441989%; + *margin-left: 76.96544022569647%; + } + .row-fluid .offset8 { + margin-left: 71.2707182320442%; + *margin-left: 71.16433525332079%; + } + .row-fluid .offset8:first-child { + margin-left: 68.50828729281768%; + *margin-left: 68.40190431409427%; + } + .row-fluid .offset7 { + margin-left: 62.70718232044199%; + *margin-left: 62.600799341718584%; + } + .row-fluid .offset7:first-child { + margin-left: 59.94475138121547%; + *margin-left: 59.838368402492065%; + } + .row-fluid .offset6 { + margin-left: 54.14364640883978%; + *margin-left: 54.037263430116376%; + } + .row-fluid .offset6:first-child { + margin-left: 51.38121546961326%; + *margin-left: 51.27483249088986%; + } + .row-fluid .offset5 { + margin-left: 45.58011049723757%; + *margin-left: 45.47372751851417%; + } + .row-fluid .offset5:first-child { + margin-left: 42.81767955801105%; + *margin-left: 42.71129657928765%; + } + .row-fluid .offset4 { + margin-left: 37.01657458563536%; + *margin-left: 36.91019160691196%; + } + .row-fluid .offset4:first-child { + margin-left: 34.25414364640884%; + *margin-left: 34.14776066768544%; + } + .row-fluid .offset3 { + margin-left: 28.45303867403315%; + *margin-left: 28.346655695309746%; + } + .row-fluid .offset3:first-child { + margin-left: 25.69060773480663%; + *margin-left: 25.584224756083227%; + } + .row-fluid .offset2 { + margin-left: 19.88950276243094%; + *margin-left: 19.783119783707537%; + } + .row-fluid .offset2:first-child { + margin-left: 17.12707182320442%; + *margin-left: 17.02068884448102%; + } + .row-fluid .offset1 { + margin-left: 11.32596685082873%; + *margin-left: 11.219583872105325%; + } + .row-fluid .offset1:first-child { + margin-left: 8.56353591160221%; + *margin-left: 8.457152932878806%; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + line-height: 0; + } + .row-fluid:after { + clear: both; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + line-height: 0; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; + margin-left: 2.7624309392265194%; + *margin-left: 2.709239449864817%; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.7624309392265194%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.43646408839778%; + *width: 91.38327259903608%; + } + .row-fluid .span10 { + width: 82.87292817679558%; + *width: 82.81973668743387%; + } + .row-fluid .span9 { + width: 74.30939226519337%; + *width: 74.25620077583166%; + } + .row-fluid .span8 { + width: 65.74585635359117%; + *width: 65.69266486422946%; + } + .row-fluid .span7 { + width: 57.18232044198895%; + *width: 57.12912895262725%; + } + .row-fluid .span6 { + width: 48.61878453038674%; + *width: 48.56559304102504%; + } + .row-fluid .span5 { + width: 40.05524861878453%; + *width: 40.00205712942283%; + } + .row-fluid .span4 { + width: 31.491712707182323%; + *width: 31.43852121782062%; + } + .row-fluid .span3 { + width: 22.92817679558011%; + *width: 22.87498530621841%; + } + .row-fluid .span2 { + width: 14.3646408839779%; + *width: 14.311449394616199%; + } + .row-fluid .span1 { + width: 5.801104972375691%; + *width: 5.747913483013988%; + } + .row-fluid .offset12 { + margin-left: 105.52486187845304%; + *margin-left: 105.41847889972962%; + } + .row-fluid .offset12:first-child { + margin-left: 102.76243093922652%; + *margin-left: 102.6560479605031%; + } + .row-fluid .offset11 { + margin-left: 96.96132596685082%; + *margin-left: 96.8549429881274%; + } + .row-fluid .offset11:first-child { + margin-left: 94.1988950276243%; + *margin-left: 94.09251204890089%; + } + .row-fluid .offset10 { + margin-left: 88.39779005524862%; + *margin-left: 88.2914070765252%; + } + .row-fluid .offset10:first-child { + margin-left: 85.6353591160221%; + *margin-left: 85.52897613729868%; + } + .row-fluid .offset9 { + margin-left: 79.8342541436464%; + *margin-left: 79.72787116492299%; + } + .row-fluid .offset9:first-child { + margin-left: 77.07182320441989%; + *margin-left: 76.96544022569647%; + } + .row-fluid .offset8 { + margin-left: 71.2707182320442%; + *margin-left: 71.16433525332079%; + } + .row-fluid .offset8:first-child { + margin-left: 68.50828729281768%; + *margin-left: 68.40190431409427%; + } + .row-fluid .offset7 { + margin-left: 62.70718232044199%; + *margin-left: 62.600799341718584%; + } + .row-fluid .offset7:first-child { + margin-left: 59.94475138121547%; + *margin-left: 59.838368402492065%; + } + .row-fluid .offset6 { + margin-left: 54.14364640883978%; + *margin-left: 54.037263430116376%; + } + .row-fluid .offset6:first-child { + margin-left: 51.38121546961326%; + *margin-left: 51.27483249088986%; + } + .row-fluid .offset5 { + margin-left: 45.58011049723757%; + *margin-left: 45.47372751851417%; + } + .row-fluid .offset5:first-child { + margin-left: 42.81767955801105%; + *margin-left: 42.71129657928765%; + } + .row-fluid .offset4 { + margin-left: 37.01657458563536%; + *margin-left: 36.91019160691196%; + } + .row-fluid .offset4:first-child { + margin-left: 34.25414364640884%; + *margin-left: 34.14776066768544%; + } + .row-fluid .offset3 { + margin-left: 28.45303867403315%; + *margin-left: 28.346655695309746%; + } + .row-fluid .offset3:first-child { + margin-left: 25.69060773480663%; + *margin-left: 25.584224756083227%; + } + .row-fluid .offset2 { + margin-left: 19.88950276243094%; + *margin-left: 19.783119783707537%; + } + .row-fluid .offset2:first-child { + margin-left: 17.12707182320442%; + *margin-left: 17.02068884448102%; + } + .row-fluid .offset1 { + margin-left: 11.32596685082873%; + *margin-left: 11.219583872105325%; + } + .row-fluid .offset1:first-child { + margin-left: 8.56353591160221%; + *margin-left: 8.457152932878806%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 710px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 648px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 586px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 524px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 462px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 400px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 338px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 276px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 214px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 152px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 90px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 28px; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 710px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 648px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 586px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 524px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 462px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 400px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 338px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 276px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 214px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 152px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 90px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 28px; + } +} +@media (max-width: 767px) { + body { + padding-left: 20px; + padding-right: 20px; + } + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { + margin-left: -20px; + margin-right: -20px; + } + .container-fluid { + padding: 0; + } + .dl-horizontal dt { + float: none; + clear: none; + width: auto; + text-align: left; + } + .dl-horizontal dd { + margin-left: 0; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row, + .thumbnails { + margin-left: 0; + } + .thumbnails > li { + float: none; + margin-left: 0; + } + [class*="span"], + .uneditable-input[class*="span"], + .row-fluid [class*="span"] { + float: none; + display: block; + width: 100%; + margin-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .span12, + .row-fluid .span12 { + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="offset"]:first-child { + margin-left: 0; + } + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 29px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; + width: auto; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } + .modal { + position: fixed; + top: 20px; + left: 20px; + right: 20px; + width: auto; + margin: 0; + } + .modal.fade { + top: -100px; + } + .modal.fade.in { + top: 20px; + } +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 19px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .media .pull-left, + .media .pull-right { + float: none; + display: block; + margin-bottom: 10px; + } + .media-object { + margin-right: 0; + margin-left: 0; + } + .modal { + top: 10px; + left: 10px; + right: 10px; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: 19px; + } + .navbar-fixed-bottom { + margin-top: 19px; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .nav-collapse { + clear: both; + } + .nav-collapse .nav { + float: none; + margin: 0 0 9.5px; + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: #777777; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: #777777; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .nav > li > a:focus, + .nav-collapse .dropdown-menu a:hover, + .nav-collapse .dropdown-menu a:focus { + background-color: #f2f2f2; + } + .navbar-inverse .nav-collapse .nav > li > a, + .navbar-inverse .nav-collapse .dropdown-menu a { + color: #999999; + } + .navbar-inverse .nav-collapse .nav > li > a:hover, + .navbar-inverse .nav-collapse .nav > li > a:focus, + .navbar-inverse .nav-collapse .dropdown-menu a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:focus { + background-color: #111111; + } + .nav-collapse.in .btn-group { + margin-top: 5px; + padding: 0; + } + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: none; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nav-collapse .open > .dropdown-menu { + display: block; + } + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .nav > li > .dropdown-menu:before, + .nav-collapse .nav > li > .dropdown-menu:after { + display: none; + } + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: 9.5px 15px; + margin: 9.5px 0; + border-top: 1px solid #f2f2f2; + border-bottom: 1px solid #f2f2f2; + -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); + -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); + box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); + } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: #111111; + border-bottom-color: #111111; + } + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + .nav-collapse, + .nav-collapse.collapse { + overflow: hidden; + height: 0; + } + .navbar .btn-navbar { + display: block; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/css/spc-extend.css b/doc/scipy-sphinx-theme/_theme/scipy/static/css/spc-extend.css new file mode 100644 index 0000000..3918954 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/css/spc-extend.css @@ -0,0 +1,102 @@ +body { + background-color: #f9faf5; +} +.container { + width: 80%; +} +.main { + background-color: white; + padding: 18px; + -moz-box-shadow: 0 0 3px #888; + -webkit-box-shadow: 0 0 3px #888; + box-shadow: 0 0 3px #888; +} +.underline { + border-bottom: 1.5px solid #eeeeee; +} +.header { + margin-top: 15px; + margin-bottom: 15px; + margin-left: 0px; + margin-right: 0px; +} +.spc-navbar { + margin-top: 15px; + margin-bottom: 5px; + margin-left: 0px; + margin-right: 0px; +} +.spc-navbar .nav-pills { + margin-bottom: 0px; + font-size: 12px; +} +.spc-navbar .nav-pills > li > a { + padding-top: 2.5px; + padding-bottom: 2.5px; +} +.underline { + border-bottom: 1.5px solid #eeeeee; +} +.spc-page-title h1, +.spc-page-title h2, +.spc-page-title h3, +.spc-page-title h4 { + font-weight: normal; + border-bottom: 1.5px solid #eeeeee; +} +.tags .btn { + border: none; + font-size: 9.5px; + font-weight: bold; +} +.spc-search-result-title h1, +.spc-search-result-title h2, +.spc-search-result-title h3, +.spc-search-result-title h4 { + font-weight: normal; +} +.spc-snippet-header { + margin-bottom: 5px; +} +.spc-snippet-info { + padding-top: 10px; +} +.spc-snippet-info .dl-horizontal { + margin: 5px; +} +.spc-snippet-info .dl-horizontal dt { + font-weight: normal; +} +.spc-snippet-body { + padding: 10px; +} +.spc-snippet-body .accordion-group { + border: none; +} +.spc-snippet-body .accordion-heading { + text-transform: uppercase; + font-size: 14px; + border-bottom: 1px solid #e5e5e5; +} +.spc-snippet-body .accordion-heading .accordion-toggle { + padding-top: 10px; + padding-bottom: 5px; +} +.spc-rightsidebar { + color: #555555; +} +.spc-rightsidebar .navigation { + padding: 2px 10px; + font-size: 11.9px; +} +.spc-rightsidebar .navigation .nav-title { + font-weight: bold; + text-transform: uppercase; +} +.spc-rightsidebar .navigation li { + margin: 5px; +} +.footer { + padding: 5px; + font-size: small; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/all-icons.svg b/doc/scipy-sphinx-theme/_theme/scipy/static/img/all-icons.svg new file mode 100644 index 0000000..f92d026 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/img/all-icons.svg @@ -0,0 +1,3088 @@ + + + + + + + + + + + + copy + edit + + + + + Source: Tango Icon Library: public domain (modified by Kevin Dunn for SciPy-Central website) + + + + + Andreas Nilsson + + + + + Andreas Nilsson + + + 2005-10-15 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + .py + + + + + + + + + + + + + + + + + + + + .py + + + + + http:// + + + + + + + + Put icon inside page boundary. Align center/center.Export "Page" option (icon will be 160 x 160 at 300dpi)Open PNG exported icon in Mac Preview. Save at 25% of the size (40x40 px) for the ....-tiny.png icons (keep alpha). + + + + + + + + + + + + + + + + diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/contents.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/contents.png new file mode 100644 index 0000000..7fb8215 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/contents.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/create-new-account-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/create-new-account-icon.png new file mode 100644 index 0000000..65f57fc Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/create-new-account-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon-shrunk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon-shrunk.png new file mode 100644 index 0000000..6c150f0 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon-shrunk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon.png new file mode 100644 index 0000000..ba554af Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon.svg b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon.svg new file mode 100644 index 0000000..90994b4 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-icon.svg @@ -0,0 +1,1817 @@ + + + + + + + + + + + + e-mail + mail + MUA + + + + + Open Clip Art Library, Public domain (modified by Kevin Dunn for SciPy-Central website) + + + + + Jakub Steiner + + + + + Jakub Steiner + + + + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http:// + + + + + + + Submit a link + + + diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon-tiniest.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon-tiniest.png new file mode 100644 index 0000000..f87c448 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon-tiniest.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon-tiny.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon-tiny.png new file mode 100644 index 0000000..9dff770 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon-tiny.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon.png new file mode 100644 index 0000000..08bae98 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/external-link-list-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ad.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ad.png new file mode 100644 index 0000000..573e054 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ad.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ae.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ae.png new file mode 100644 index 0000000..5186681 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ae.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-af.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-af.png new file mode 100644 index 0000000..5e6e9e8 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-af.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ag.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ag.png new file mode 100644 index 0000000..dafca11 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ag.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ai.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ai.png new file mode 100644 index 0000000..ed8d682 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ai.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-al.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-al.png new file mode 100644 index 0000000..9ce1f54 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-al.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-am.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-am.png new file mode 100644 index 0000000..6222dc6 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-am.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ao.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ao.png new file mode 100644 index 0000000..617640f Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ao.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-aq.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-aq.png new file mode 100644 index 0000000..addf2bb Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-aq.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ar.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ar.png new file mode 100644 index 0000000..c9a09b7 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ar.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-as.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-as.png new file mode 100644 index 0000000..fc985a9 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-as.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-at.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-at.png new file mode 100644 index 0000000..c160c73 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-at.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-au.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-au.png new file mode 100644 index 0000000..86c6912 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-au.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-aw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-aw.png new file mode 100644 index 0000000..2f7afb1 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-aw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-az.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-az.png new file mode 100644 index 0000000..8131751 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-az.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ba.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ba.png new file mode 100644 index 0000000..cfe6962 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ba.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bb.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bb.png new file mode 100644 index 0000000..af3d317 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bb.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bd.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bd.png new file mode 100644 index 0000000..e1873cb Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bd.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-be.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-be.png new file mode 100644 index 0000000..2c27e8d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-be.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bf.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bf.png new file mode 100644 index 0000000..7f154ec Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bf.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bg.png new file mode 100644 index 0000000..28144a8 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bh.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bh.png new file mode 100644 index 0000000..cacff65 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bh.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bi.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bi.png new file mode 100644 index 0000000..e753a68 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bi.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bj.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bj.png new file mode 100644 index 0000000..31f3261 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bj.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bl.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bl.png new file mode 100644 index 0000000..c5bafdd Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bl.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bm.png new file mode 100644 index 0000000..49a9048 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bn.png new file mode 100644 index 0000000..0dae6d5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bo.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bo.png new file mode 100644 index 0000000..4e96dcc Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bo.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-br.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-br.png new file mode 100644 index 0000000..f342a1a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-br.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bs.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bs.png new file mode 100644 index 0000000..224244b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bs.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bt.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bt.png new file mode 100644 index 0000000..d6ef653 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bt.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bw.png new file mode 100644 index 0000000..8d2b3d8 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-by.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-by.png new file mode 100644 index 0000000..b90cadb Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-by.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bz.png new file mode 100644 index 0000000..4ad5d5b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-bz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ca.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ca.png new file mode 100644 index 0000000..c889938 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ca.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cc.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cc.png new file mode 100644 index 0000000..ee977c7 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cc.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cd.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cd.png new file mode 100644 index 0000000..7d6ced2 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cd.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cf.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cf.png new file mode 100644 index 0000000..04ce375 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cf.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cg.png new file mode 100644 index 0000000..0745dd9 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ch.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ch.png new file mode 100644 index 0000000..edc8265 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ch.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ci.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ci.png new file mode 100644 index 0000000..19a0663 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ci.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ck.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ck.png new file mode 100644 index 0000000..c0b6846 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ck.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cl.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cl.png new file mode 100644 index 0000000..2b2e8c6 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cl.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cm.png new file mode 100644 index 0000000..2d516e5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cn.png new file mode 100644 index 0000000..adf0b25 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-co.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-co.png new file mode 100644 index 0000000..0e611d1 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-co.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cr.png new file mode 100644 index 0000000..2df4da2 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cu.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cu.png new file mode 100644 index 0000000..ba908a7 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cu.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cv.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cv.png new file mode 100644 index 0000000..186c33e Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cv.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cw.png new file mode 100644 index 0000000..5b6b936 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cx.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cx.png new file mode 100644 index 0000000..a5ef0e1 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cx.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cy.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cy.png new file mode 100644 index 0000000..3a38582 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cy.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cz.png new file mode 100644 index 0000000..778df06 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-cz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-de.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-de.png new file mode 100644 index 0000000..5d16ca1 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-de.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dj.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dj.png new file mode 100644 index 0000000..22c6a0a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dj.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dk.png new file mode 100644 index 0000000..c236b11 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dm.png new file mode 100644 index 0000000..3ae9a3e Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-do.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-do.png new file mode 100644 index 0000000..96fc34e Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-do.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dz.png new file mode 100644 index 0000000..5c5f4ad Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-dz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ec.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ec.png new file mode 100644 index 0000000..1b37da5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ec.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ee.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ee.png new file mode 100644 index 0000000..5d22af3 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ee.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-eg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-eg.png new file mode 100644 index 0000000..78db55c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-eg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-er.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-er.png new file mode 100644 index 0000000..c867eb4 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-er.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-es.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-es.png new file mode 100644 index 0000000..9d69136 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-es.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-et.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-et.png new file mode 100644 index 0000000..d4b4e86 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-et.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fi.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fi.png new file mode 100644 index 0000000..6dce798 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fi.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fj.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fj.png new file mode 100644 index 0000000..2147064 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fj.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fk.png new file mode 100644 index 0000000..115c41a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fm.png new file mode 100644 index 0000000..7f5175b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fo.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fo.png new file mode 100644 index 0000000..547dc0b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fo.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fr.png new file mode 100644 index 0000000..a222b16 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-fr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ga.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ga.png new file mode 100644 index 0000000..191272e Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ga.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gb.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gb.png new file mode 100644 index 0000000..c1aab01 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gb.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gd.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gd.png new file mode 100644 index 0000000..ce8c148 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gd.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ge.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ge.png new file mode 100644 index 0000000..c9ec117 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ge.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gf.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gf.png new file mode 100644 index 0000000..a222b16 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gf.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gg.png new file mode 100644 index 0000000..471fce5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gh.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gh.png new file mode 100644 index 0000000..3b38482 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gh.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gi.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gi.png new file mode 100644 index 0000000..a8f87ea Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gi.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gl.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gl.png new file mode 100644 index 0000000..806d0c6 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gl.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gm.png new file mode 100644 index 0000000..01d695a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gn.png new file mode 100644 index 0000000..2a15aec Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gq.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gq.png new file mode 100644 index 0000000..68bc451 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gq.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gr.png new file mode 100644 index 0000000..414b69e Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gs.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gs.png new file mode 100644 index 0000000..3da16b6 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gs.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gt.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gt.png new file mode 100644 index 0000000..2244cea Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gt.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gu.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gu.png new file mode 100644 index 0000000..78b9a65 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gu.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gw.png new file mode 100644 index 0000000..f6a3bf1 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gy.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gy.png new file mode 100644 index 0000000..8696b93 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-gy.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hk.png new file mode 100644 index 0000000..788e2da Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hm.png new file mode 100644 index 0000000..8c31174 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hn.png new file mode 100644 index 0000000..2143066 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hr.png new file mode 100644 index 0000000..e92ba7a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ht.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ht.png new file mode 100644 index 0000000..ca504e3 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ht.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hu.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hu.png new file mode 100644 index 0000000..ccd9560 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-hu.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-id.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-id.png new file mode 100644 index 0000000..c0449e3 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-id.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ie.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ie.png new file mode 100644 index 0000000..faae388 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ie.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-il.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-il.png new file mode 100644 index 0000000..d3aaa4a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-il.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-im.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-im.png new file mode 100644 index 0000000..df6018c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-im.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-in.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-in.png new file mode 100644 index 0000000..7772f52 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-in.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-io.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-io.png new file mode 100644 index 0000000..6932883 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-io.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-iq.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-iq.png new file mode 100644 index 0000000..3b02677 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-iq.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ir.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ir.png new file mode 100644 index 0000000..a8a337c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ir.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-is.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-is.png new file mode 100644 index 0000000..fd17b58 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-is.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-it.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-it.png new file mode 100644 index 0000000..1ed2a5a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-it.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-je.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-je.png new file mode 100644 index 0000000..4696c8b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-je.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jm.png new file mode 100644 index 0000000..0c8f622 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jo.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jo.png new file mode 100644 index 0000000..06bf864 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jo.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jp.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jp.png new file mode 100644 index 0000000..9ca0f7b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-jp.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ke.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ke.png new file mode 100644 index 0000000..561145d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ke.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kg.png new file mode 100644 index 0000000..ab3e85c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kh.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kh.png new file mode 100644 index 0000000..9f32733 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kh.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ki.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ki.png new file mode 100644 index 0000000..5f7c6ea Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ki.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-km.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-km.png new file mode 100644 index 0000000..c69b16b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-km.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kn.png new file mode 100644 index 0000000..b750716 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kp.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kp.png new file mode 100644 index 0000000..e26c5b7 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kp.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kr.png new file mode 100644 index 0000000..80d7cf5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kw.png new file mode 100644 index 0000000..570a7de Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ky.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ky.png new file mode 100644 index 0000000..f67d424 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ky.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kz.png new file mode 100644 index 0000000..cdfa14a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-kz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-la.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-la.png new file mode 100644 index 0000000..d727e0d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-la.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lb.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lb.png new file mode 100644 index 0000000..693f889 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lb.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lc.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lc.png new file mode 100644 index 0000000..a65b659 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lc.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-li.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-li.png new file mode 100644 index 0000000..2d3cbd0 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-li.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lk.png new file mode 100644 index 0000000..8022f57 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lr.png new file mode 100644 index 0000000..b9f180b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ls.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ls.png new file mode 100644 index 0000000..d7a959c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ls.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lt.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lt.png new file mode 100644 index 0000000..78579dd Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lt.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lu.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lu.png new file mode 100644 index 0000000..1fe35b7 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lu.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lv.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lv.png new file mode 100644 index 0000000..af45a51 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-lv.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ly.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ly.png new file mode 100644 index 0000000..d6e5d10 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ly.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ma.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ma.png new file mode 100644 index 0000000..55bdb00 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ma.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mc.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mc.png new file mode 100644 index 0000000..4273b33 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mc.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-md.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-md.png new file mode 100644 index 0000000..3d28172 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-md.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-me.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-me.png new file mode 100644 index 0000000..b478ce0 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-me.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mf.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mf.png new file mode 100644 index 0000000..6497d6d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mf.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mg.png new file mode 100644 index 0000000..42a4370 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mh.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mh.png new file mode 100644 index 0000000..4c9a845 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mh.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mk.png new file mode 100644 index 0000000..955b6d0 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ml.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ml.png new file mode 100644 index 0000000..f0726c0 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ml.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mm.png new file mode 100644 index 0000000..5e66d33 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mn.png new file mode 100644 index 0000000..07130e4 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mo.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mo.png new file mode 100644 index 0000000..01ade2f Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mo.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mp.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mp.png new file mode 100644 index 0000000..2fefb68 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mp.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mq.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mq.png new file mode 100644 index 0000000..81b9b0d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mq.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mr.png new file mode 100644 index 0000000..3d4d970 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ms.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ms.png new file mode 100644 index 0000000..b690f98 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ms.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mt.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mt.png new file mode 100644 index 0000000..4c53b3c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mt.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mu.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mu.png new file mode 100644 index 0000000..a820b29 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mu.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mv.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mv.png new file mode 100644 index 0000000..d80ce3d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mv.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mw.png new file mode 100644 index 0000000..0cc800d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mx.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mx.png new file mode 100644 index 0000000..a92300f Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mx.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-my.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-my.png new file mode 100644 index 0000000..8756c94 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-my.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mz.png new file mode 100644 index 0000000..54698bd Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-mz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-na.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-na.png new file mode 100644 index 0000000..4fad544 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-na.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nc.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nc.png new file mode 100644 index 0000000..b29fa9b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nc.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ne.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ne.png new file mode 100644 index 0000000..e496d10 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ne.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nf.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nf.png new file mode 100644 index 0000000..b6fc1f6 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nf.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ng.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ng.png new file mode 100644 index 0000000..64b0d23 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ng.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ni.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ni.png new file mode 100644 index 0000000..84e742d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ni.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nl.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nl.png new file mode 100644 index 0000000..c4b37f1 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nl.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-no.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-no.png new file mode 100644 index 0000000..197bab5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-no.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-np.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-np.png new file mode 100644 index 0000000..5b4bd4d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-np.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nr.png new file mode 100644 index 0000000..a2fedba Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nu.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nu.png new file mode 100644 index 0000000..85f6019 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nu.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nz.png new file mode 100644 index 0000000..df23c2a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-nz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-om.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-om.png new file mode 100644 index 0000000..0f3e235 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-om.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pa.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pa.png new file mode 100644 index 0000000..460680b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pa.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pe.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pe.png new file mode 100644 index 0000000..6d16889 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pe.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pf.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pf.png new file mode 100644 index 0000000..1061eef Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pf.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pg.png new file mode 100644 index 0000000..98cb4fa Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ph.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ph.png new file mode 100644 index 0000000..3526587 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ph.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pk.png new file mode 100644 index 0000000..8f1bbcf Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pl.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pl.png new file mode 100644 index 0000000..c39344b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pl.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pm.png new file mode 100644 index 0000000..c26196d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pn.png new file mode 100644 index 0000000..efab787 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pr.png new file mode 100644 index 0000000..d72b1ed Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ps.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ps.png new file mode 100644 index 0000000..735b09d Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ps.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pt.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pt.png new file mode 100644 index 0000000..089733f Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pt.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pw.png new file mode 100644 index 0000000..c239880 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-pw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-py.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-py.png new file mode 100644 index 0000000..ee85761 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-py.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-qa.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-qa.png new file mode 100644 index 0000000..f811dcb Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-qa.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-re.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-re.png new file mode 100644 index 0000000..b29fa9b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-re.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ro.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ro.png new file mode 100644 index 0000000..dbbd394 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ro.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-rs.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-rs.png new file mode 100644 index 0000000..181d07c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-rs.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ru.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ru.png new file mode 100644 index 0000000..b89520a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ru.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-rw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-rw.png new file mode 100644 index 0000000..bc2e26e Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-rw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sa.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sa.png new file mode 100644 index 0000000..58862ab Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sa.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sb.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sb.png new file mode 100644 index 0000000..8634250 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sb.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sc.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sc.png new file mode 100644 index 0000000..36e2aec Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sc.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sd.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sd.png new file mode 100644 index 0000000..152412c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sd.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-se.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-se.png new file mode 100644 index 0000000..15f7736 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-se.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sg.png new file mode 100644 index 0000000..3e820b5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sh.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sh.png new file mode 100644 index 0000000..6a464db Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sh.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-si.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-si.png new file mode 100644 index 0000000..607577b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-si.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sj.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sj.png new file mode 100644 index 0000000..8cf5bc5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sj.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sk.png new file mode 100644 index 0000000..005252c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sl.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sl.png new file mode 100644 index 0000000..0111126 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sl.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sm.png new file mode 100644 index 0000000..4e9fb11 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sn.png new file mode 100644 index 0000000..a935614 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-so.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-so.png new file mode 100644 index 0000000..c5465fe Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-so.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sr.png new file mode 100644 index 0000000..e30e7a2 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-st.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-st.png new file mode 100644 index 0000000..76b9eeb Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-st.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sv.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sv.png new file mode 100644 index 0000000..6b0075c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sv.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sy.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sy.png new file mode 100644 index 0000000..3ce1043 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sy.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sz.png new file mode 100644 index 0000000..4783c71 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-sz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tc.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tc.png new file mode 100644 index 0000000..216e67e Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tc.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-td.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-td.png new file mode 100644 index 0000000..8afd5b9 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-td.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tf.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tf.png new file mode 100644 index 0000000..dd243b2 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tf.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tg.png new file mode 100644 index 0000000..4020b0a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-th.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-th.png new file mode 100644 index 0000000..718b601 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-th.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tj.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tj.png new file mode 100644 index 0000000..d7b684f Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tj.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tk.png new file mode 100644 index 0000000..7b355e6 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tl.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tl.png new file mode 100644 index 0000000..7cbc448 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tl.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tm.png new file mode 100644 index 0000000..6f41f3c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tn.png new file mode 100644 index 0000000..3490c12 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-to.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-to.png new file mode 100644 index 0000000..ee6d4b6 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-to.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tr.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tr.png new file mode 100644 index 0000000..f5ff007 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tr.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tt.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tt.png new file mode 100644 index 0000000..83b7e72 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tt.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tv.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tv.png new file mode 100644 index 0000000..f488cc5 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tv.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tw.png new file mode 100644 index 0000000..1f99612 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tz.png new file mode 100644 index 0000000..90321c4 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-tz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ua.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ua.png new file mode 100644 index 0000000..4d2bc4b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ua.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ug.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ug.png new file mode 100644 index 0000000..484f84c Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ug.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-um.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-um.png new file mode 100644 index 0000000..1796531 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-um.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-us.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-us.png new file mode 100644 index 0000000..1796531 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-us.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-uy.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-uy.png new file mode 100644 index 0000000..aee0c45 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-uy.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-uz.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-uz.png new file mode 100644 index 0000000..f7c3bd9 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-uz.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-va.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-va.png new file mode 100644 index 0000000..430db56 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-va.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vc.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vc.png new file mode 100644 index 0000000..bf4b953 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vc.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ve.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ve.png new file mode 100644 index 0000000..3bd9e24 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ve.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vg.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vg.png new file mode 100644 index 0000000..d2ae148 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vg.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vi.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vi.png new file mode 100644 index 0000000..78716fd Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vi.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vn.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vn.png new file mode 100644 index 0000000..401a94b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vn.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vu.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vu.png new file mode 100644 index 0000000..01f9868 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-vu.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-wf.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-wf.png new file mode 100644 index 0000000..411ec0b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-wf.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ws.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ws.png new file mode 100644 index 0000000..df36d2e Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ws.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ye.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ye.png new file mode 100644 index 0000000..6af94ab Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-ye.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-za.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-za.png new file mode 100644 index 0000000..d27d402 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-za.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-zm.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-zm.png new file mode 100644 index 0000000..1b5a0fe Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-zm.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-zw.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-zw.png new file mode 100644 index 0000000..10def0a Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/flags/flag-zw.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/glyphicons-halflings-white.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/glyphicons-halflings-white.png new file mode 100644 index 0000000..3bf6484 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/glyphicons-halflings-white.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/glyphicons-halflings.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/glyphicons-halflings.png new file mode 100644 index 0000000..a996999 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/glyphicons-halflings.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/important-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/important-icon.png new file mode 100644 index 0000000..6d3a136 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/important-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/information-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/information-icon.png new file mode 100644 index 0000000..1bf5076 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/information-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/internet-web-browser.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/internet-web-browser.png new file mode 100644 index 0000000..2f656e7 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/internet-web-browser.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon-shrunk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon-shrunk.png new file mode 100644 index 0000000..7cebcfb Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon-shrunk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon.png new file mode 100644 index 0000000..ec6ac23 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon.svg b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon.svg new file mode 100644 index 0000000..05d74ba --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-icon.svg @@ -0,0 +1,484 @@ + + + + + + + + + + + + copy + edit + + + + + Open Clip Art Library, Source: Tango Icon Library (modified by Kevin Dunn for SciPy-Central website) + + + + + Andreas Nilsson + + + + + Andreas Nilsson + + + 2005-10-15 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + .py + + + Submit a libraryof files + + diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-list-icon-tiny.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-list-icon-tiny.png new file mode 100644 index 0000000..78f3ce2 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-list-icon-tiny.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-list-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-list-icon.png new file mode 100644 index 0000000..a935e28 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/multiple-file-list-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/navigation.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/navigation.png new file mode 100644 index 0000000..1081dc1 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/navigation.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/person-list-icon-tiny.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/person-list-icon-tiny.png new file mode 100644 index 0000000..b21ad98 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/person-list-icon-tiny.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/person-list-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/person-list-icon.png new file mode 100644 index 0000000..d00429f Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/person-list-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipy-logo.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipy-logo.png new file mode 100644 index 0000000..a2d8571 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipy-logo.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipy_org_logo.gif b/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipy_org_logo.gif new file mode 100644 index 0000000..ab2e3ac Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipy_org_logo.gif differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipycentral_logo.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipycentral_logo.png new file mode 100644 index 0000000..6f33861 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipycentral_logo.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipyshiny_small.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipyshiny_small.png new file mode 100644 index 0000000..7ef81a9 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/scipyshiny_small.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/send-email-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/send-email-icon.png new file mode 100644 index 0000000..8b11c1b Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/send-email-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon-shrunk.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon-shrunk.png new file mode 100644 index 0000000..7dff231 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon-shrunk.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon.png new file mode 100644 index 0000000..187aae0 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon.svg b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon.svg new file mode 100644 index 0000000..6dc70cc --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-icon.svg @@ -0,0 +1,385 @@ + + + + + + + + + + + + copy + edit + + + + + Source: Tango Icon Library: public domain (modified by Kevin Dunn for SciPy-Central website) + + + + + Andreas Nilsson + + + + + Andreas Nilsson + + + 2005-10-15 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + .py + + + Submit a code snippet + + diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon-tiniest.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon-tiniest.png new file mode 100644 index 0000000..9aa7bdf Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon-tiniest.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon-tiny.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon-tiny.png new file mode 100644 index 0000000..7d97dff Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon-tiny.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon.png b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon.png new file mode 100644 index 0000000..1bc60ae Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/single-file-list-icon.png differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/transparent-pixel.gif b/doc/scipy-sphinx-theme/_theme/scipy/static/img/transparent-pixel.gif new file mode 100644 index 0000000..e4994d9 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/transparent-pixel.gif differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/img/ui-anim_basic_16x16.gif b/doc/scipy-sphinx-theme/_theme/scipy/static/img/ui-anim_basic_16x16.gif new file mode 100644 index 0000000..084ecb8 Binary files /dev/null and b/doc/scipy-sphinx-theme/_theme/scipy/static/img/ui-anim_basic_16x16.gif differ diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/js/copybutton.js b/doc/scipy-sphinx-theme/_theme/scipy/static/js/copybutton.js new file mode 100644 index 0000000..ace6922 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/js/copybutton.js @@ -0,0 +1,60 @@ +// Copyright 2014 PSF. Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +// File originates from the cpython source found in Doc/tools/sphinxext/static/copybutton.js + +$(document).ready(function() { + /* Add a [>>>] button on the top-right corner of code samples to hide + * the >>> and ... prompts and the output and thus make the code + * copyable. */ + var div = $('.highlight-python .highlight,' + + '.highlight-python3 .highlight') + var pre = div.find('pre'); + + // get the styles from the current theme + pre.parent().parent().css('position', 'relative'); + var hide_text = 'Hide the prompts and output'; + var show_text = 'Show the prompts and output'; + var border_width = pre.css('border-top-width'); + var border_style = pre.css('border-top-style'); + var border_color = pre.css('border-top-color'); + var button_styles = { + 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', + 'border-color': border_color, 'border-style': border_style, + 'border-width': border_width, 'color': border_color, 'text-size': '75%', + 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', + 'border-radius': '0 3px 0 0' + } + + // create and add the button to all the code blocks that contain >>> + div.each(function(index) { + var jthis = $(this); + if (jthis.find('.gp').length > 0) { + var button = $('>>>'); + button.css(button_styles) + button.attr('title', hide_text); + jthis.prepend(button); + } + // tracebacks (.gt) contain bare text elements that need to be + // wrapped in a span to work with .nextUntil() (see later) + jthis.find('pre:has(.gt)').contents().filter(function() { + return ((this.nodeType == 3) && (this.data.trim().length > 0)); + }).wrap(''); + }); + + // define the behavior of the button when it's clicked + $('.copybutton').toggle( + function() { + var button = $(this); + button.parent().find('.go, .gp, .gt').hide(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden'); + button.css('text-decoration', 'line-through'); + button.attr('title', show_text); + }, + function() { + var button = $(this); + button.parent().find('.go, .gp, .gt').show(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible'); + button.css('text-decoration', 'none'); + button.attr('title', hide_text); + }); +}); + diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/accordion.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/accordion.less new file mode 100644 index 0000000..d63523b --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/accordion.less @@ -0,0 +1,34 @@ +// +// Accordion +// -------------------------------------------------- + + +// Parent container +.accordion { + margin-bottom: @baseLineHeight; +} + +// Group == heading + body +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + .border-radius(@baseBorderRadius); +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +// General toggle styles +.accordion-toggle { + cursor: pointer; +} + +// Inner needs the styles because you can't animate properly with any styles on the element +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/alerts.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/alerts.less new file mode 100644 index 0000000..0116b19 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/alerts.less @@ -0,0 +1,79 @@ +// +// Alerts +// -------------------------------------------------- + + +// Base styles +// ------------------------- + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: @baseLineHeight; + text-shadow: 0 1px 0 rgba(255,255,255,.5); + background-color: @warningBackground; + border: 1px solid @warningBorder; + .border-radius(@baseBorderRadius); +} +.alert, +.alert h4 { + // Specified for the h4 to prevent conflicts of changing @headingsColor + color: @warningText; +} +.alert h4 { + margin: 0; +} + +// Adjust close link position +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: @baseLineHeight; +} + + +// Alternate styles +// ------------------------- + +.alert-success { + background-color: @successBackground; + border-color: @successBorder; + color: @successText; +} +.alert-success h4 { + color: @successText; +} +.alert-danger, +.alert-error { + background-color: @errorBackground; + border-color: @errorBorder; + color: @errorText; +} +.alert-danger h4, +.alert-error h4 { + color: @errorText; +} +.alert-info { + background-color: @infoBackground; + border-color: @infoBorder; + color: @infoText; +} +.alert-info h4 { + color: @infoText; +} + + +// Block alerts +// ------------------------- + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/bootstrap.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/bootstrap.less new file mode 100644 index 0000000..b56327a --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/bootstrap.less @@ -0,0 +1,63 @@ +/*! + * Bootstrap v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +// Core variables and mixins +@import "variables.less"; // Modify this for custom colors, font-sizes, etc +@import "mixins.less"; + +// CSS Reset +@import "reset.less"; + +// Grid system and page structure +@import "scaffolding.less"; +@import "grid.less"; +@import "layouts.less"; + +// Base CSS +@import "type.less"; +@import "code.less"; +@import "forms.less"; +@import "tables.less"; + +// Components: common +@import "sprites.less"; +@import "dropdowns.less"; +@import "wells.less"; +@import "component-animations.less"; +@import "close.less"; + +// Components: Buttons & Alerts +@import "buttons.less"; +@import "button-groups.less"; +@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less + +// Components: Nav +@import "navs.less"; +@import "navbar.less"; +@import "breadcrumbs.less"; +@import "pagination.less"; +@import "pager.less"; + +// Components: Popovers +@import "modals.less"; +@import "tooltip.less"; +@import "popovers.less"; + +// Components: Misc +@import "thumbnails.less"; +@import "media.less"; +@import "labels-badges.less"; +@import "progress-bars.less"; +@import "accordion.less"; +@import "carousel.less"; +@import "hero-unit.less"; + +// Utility classes +@import "utilities.less"; // Has to be last to override when necessary diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/breadcrumbs.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/breadcrumbs.less new file mode 100644 index 0000000..f753df6 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/breadcrumbs.less @@ -0,0 +1,24 @@ +// +// Breadcrumbs +// -------------------------------------------------- + + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 @baseLineHeight; + list-style: none; + background-color: #f5f5f5; + .border-radius(@baseBorderRadius); + > li { + display: inline-block; + .ie7-inline-block(); + text-shadow: 0 1px 0 @white; + > .divider { + padding: 0 5px; + color: #ccc; + } + } + > .active { + color: @grayLight; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/button-groups.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/button-groups.less new file mode 100644 index 0000000..55cdc60 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/button-groups.less @@ -0,0 +1,229 @@ +// +// Button groups +// -------------------------------------------------- + + +// Make the div behave like a button +.btn-group { + position: relative; + display: inline-block; + .ie7-inline-block(); + font-size: 0; // remove as part 1 of font-size inline-block hack + vertical-align: middle; // match .btn alignment given font-size hack above + white-space: nowrap; // prevent buttons from wrapping when in tight spaces (e.g., the table on the tests page) + .ie7-restore-left-whitespace(); +} + +// Space out series of button groups +.btn-group + .btn-group { + margin-left: 5px; +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + font-size: 0; // Hack to remove whitespace that results from using inline-block + margin-top: @baseLineHeight / 2; + margin-bottom: @baseLineHeight / 2; + > .btn + .btn, + > .btn-group + .btn, + > .btn + .btn-group { + margin-left: 5px; + } +} + +// Float them, remove border radius, then re-add to first and last elements +.btn-group > .btn { + position: relative; + .border-radius(0); +} +.btn-group > .btn + .btn { + margin-left: -1px; +} +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: @baseFontSize; // redeclare as part 2 of font-size inline-block hack +} + +// Reset fonts for other sizes +.btn-group > .btn-mini { + font-size: @fontSizeMini; +} +.btn-group > .btn-small { + font-size: @fontSizeSmall; +} +.btn-group > .btn-large { + font-size: @fontSizeLarge; +} + +// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match +.btn-group > .btn:first-child { + margin-left: 0; + .border-top-left-radius(@baseBorderRadius); + .border-bottom-left-radius(@baseBorderRadius); +} +// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + .border-top-right-radius(@baseBorderRadius); + .border-bottom-right-radius(@baseBorderRadius); +} +// Reset corners for large buttons +.btn-group > .btn.large:first-child { + margin-left: 0; + .border-top-left-radius(@borderRadiusLarge); + .border-bottom-left-radius(@borderRadiusLarge); +} +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + .border-top-right-radius(@borderRadiusLarge); + .border-bottom-right-radius(@borderRadiusLarge); +} + +// On hover/focus/active, bring the proper btn to front +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +// On active and open, don't show outline +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + + + +// Split button dropdowns +// ---------------------- + +// Give the line between buttons some depth +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + .box-shadow(~"inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group > .btn-mini + .dropdown-toggle { + padding-left: 5px; + padding-right: 5px; + *padding-top: 2px; + *padding-bottom: 2px; +} +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} +.btn-group > .btn-large + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; + *padding-top: 7px; + *padding-bottom: 7px; +} + +.btn-group.open { + + // The clickable button for toggling the menu + // Remove the gradient and set the same inset shadow as the :active state + .dropdown-toggle { + background-image: none; + .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)"); + } + + // Keep the hover's background when dropdown is open + .btn.dropdown-toggle { + background-color: @btnBackgroundHighlight; + } + .btn-primary.dropdown-toggle { + background-color: @btnPrimaryBackgroundHighlight; + } + .btn-warning.dropdown-toggle { + background-color: @btnWarningBackgroundHighlight; + } + .btn-danger.dropdown-toggle { + background-color: @btnDangerBackgroundHighlight; + } + .btn-success.dropdown-toggle { + background-color: @btnSuccessBackgroundHighlight; + } + .btn-info.dropdown-toggle { + background-color: @btnInfoBackgroundHighlight; + } + .btn-inverse.dropdown-toggle { + background-color: @btnInverseBackgroundHighlight; + } +} + + +// Reposition the caret +.btn .caret { + margin-top: 8px; + margin-left: 0; +} +// Carets in other button sizes +.btn-large .caret { + margin-top: 6px; +} +.btn-large .caret { + border-left-width: 5px; + border-right-width: 5px; + border-top-width: 5px; +} +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} +// Upside down carets for .dropup +.dropup .btn-large .caret { + border-bottom-width: 5px; +} + + + +// Account for other colors +.btn-primary, +.btn-warning, +.btn-danger, +.btn-info, +.btn-success, +.btn-inverse { + .caret { + border-top-color: @white; + border-bottom-color: @white; + } +} + + + +// Vertical button groups +// ---------------------- + +.btn-group-vertical { + display: inline-block; // makes buttons only take up the width they need + .ie7-inline-block(); +} +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + .border-radius(0); +} +.btn-group-vertical > .btn + .btn { + margin-left: 0; + margin-top: -1px; +} +.btn-group-vertical > .btn:first-child { + .border-radius(@baseBorderRadius @baseBorderRadius 0 0); +} +.btn-group-vertical > .btn:last-child { + .border-radius(0 0 @baseBorderRadius @baseBorderRadius); +} +.btn-group-vertical > .btn-large:first-child { + .border-radius(@borderRadiusLarge @borderRadiusLarge 0 0); +} +.btn-group-vertical > .btn-large:last-child { + .border-radius(0 0 @borderRadiusLarge @borderRadiusLarge); +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/buttons.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/buttons.less new file mode 100644 index 0000000..4cd4d86 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/buttons.less @@ -0,0 +1,228 @@ +// +// Buttons +// -------------------------------------------------- + + +// Base styles +// -------------------------------------------------- + +// Core +.btn { + display: inline-block; + .ie7-inline-block(); + padding: 4px 12px; + margin-bottom: 0; // For input.btn + font-size: @baseFontSize; + line-height: @baseLineHeight; + text-align: center; + vertical-align: middle; + cursor: pointer; + .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75)); + border: 1px solid @btnBorder; + *border: 0; // Remove the border to prevent IE7's black border on input:focus + border-bottom-color: darken(@btnBorder, 10%); + .border-radius(@baseBorderRadius); + .ie7-restore-left-whitespace(); // Give IE7 some love + .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); + + // Hover/focus state + &:hover, + &:focus { + color: @grayDark; + text-decoration: none; + background-position: 0 -15px; + + // transition is only when going to hover/focus, otherwise the background + // behind the gradient (there for IE<=9 fallback) gets mismatched + .transition(background-position .1s linear); + } + + // Focus state for keyboard and accessibility + &:focus { + .tab-focus(); + } + + // Active state + &.active, + &:active { + background-image: none; + outline: 0; + .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)"); + } + + // Disabled state + &.disabled, + &[disabled] { + cursor: default; + background-image: none; + .opacity(65); + .box-shadow(none); + } + +} + + + +// Button Sizes +// -------------------------------------------------- + +// Large +.btn-large { + padding: @paddingLarge; + font-size: @fontSizeLarge; + .border-radius(@borderRadiusLarge); +} +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} + +// Small +.btn-small { + padding: @paddingSmall; + font-size: @fontSizeSmall; + .border-radius(@borderRadiusSmall); +} +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + +// Mini +.btn-mini { + padding: @paddingMini; + font-size: @fontSizeMini; + .border-radius(@borderRadiusSmall); +} + + +// Block button +// ------------------------- + +.btn-block { + display: block; + width: 100%; + padding-left: 0; + padding-right: 0; + .box-sizing(border-box); +} + +// Vertically space out multiple block buttons +.btn-block + .btn-block { + margin-top: 5px; +} + +// Specificity overrides +input[type="submit"], +input[type="reset"], +input[type="button"] { + &.btn-block { + width: 100%; + } +} + + + +// Alternate buttons +// -------------------------------------------------- + +// Provide *some* extra contrast for those who can get it +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255,255,255,.75); +} + +// Set the backgrounds +// ------------------------- +.btn-primary { + .buttonBackground(@btnPrimaryBackground, @btnPrimaryBackgroundHighlight); +} +// Warning appears are orange +.btn-warning { + .buttonBackground(@btnWarningBackground, @btnWarningBackgroundHighlight); +} +// Danger and error appear as red +.btn-danger { + .buttonBackground(@btnDangerBackground, @btnDangerBackgroundHighlight); +} +// Success appears as green +.btn-success { + .buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight); +} +// Info appears as a neutral blue +.btn-info { + .buttonBackground(@btnInfoBackground, @btnInfoBackgroundHighlight); +} +// Inverse appears as dark gray +.btn-inverse { + .buttonBackground(@btnInverseBackground, @btnInverseBackgroundHighlight); +} + + +// Cross-browser Jank +// -------------------------------------------------- + +button.btn, +input[type="submit"].btn { + + // Firefox 3.6 only I believe + &::-moz-focus-inner { + padding: 0; + border: 0; + } + + // IE7 has some default padding on button controls + *padding-top: 3px; + *padding-bottom: 3px; + + &.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; + } + &.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; + } + &.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; + } +} + + +// Link buttons +// -------------------------------------------------- + +// Make a button look and behave like a link +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + .box-shadow(none); +} +.btn-link { + border-color: transparent; + cursor: pointer; + color: @linkColor; + .border-radius(0); +} +.btn-link:hover, +.btn-link:focus { + color: @linkColorHover; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { + color: @grayDark; + text-decoration: none; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/carousel.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/carousel.less new file mode 100644 index 0000000..55bc050 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/carousel.less @@ -0,0 +1,158 @@ +// +// Carousel +// -------------------------------------------------- + + +.carousel { + position: relative; + margin-bottom: @baseLineHeight; + line-height: 1; +} + +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} + +.carousel-inner { + + > .item { + display: none; + position: relative; + .transition(.6s ease-in-out left); + + // Account for jankitude on images + > img, + > a > img { + display: block; + line-height: 1; + } + } + + > .active, + > .next, + > .prev { display: block; } + + > .active { + left: 0; + } + + > .next, + > .prev { + position: absolute; + top: 0; + width: 100%; + } + + > .next { + left: 100%; + } + > .prev { + left: -100%; + } + > .next.left, + > .prev.right { + left: 0; + } + + > .active.left { + left: -100%; + } + > .active.right { + left: 100%; + } + +} + +// Left/right controls for nav +// --------------------------- + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: @white; + text-align: center; + background: @grayDarker; + border: 3px solid @white; + .border-radius(23px); + .opacity(50); + + // we can't have this transition here + // because webkit cancels the carousel + // animation if you trip this while + // in the middle of another animation + // ;_; + // .transition(opacity .2s linear); + + // Reposition the right one + &.right { + left: auto; + right: 15px; + } + + // Hover/focus state + &:hover, + &:focus { + color: @white; + text-decoration: none; + .opacity(90); + } +} + +// Carousel indicator pips +// ----------------------------- +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; + + li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255,255,255,.25); + border-radius: 5px; + } + .active { + background-color: #fff; + } +} + +// Caption for text below images +// ----------------------------- + +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 15px; + background: @grayDark; + background: rgba(0,0,0,.75); +} +.carousel-caption h4, +.carousel-caption p { + color: @white; + line-height: @baseLineHeight; +} +.carousel-caption h4 { + margin: 0 0 5px; +} +.carousel-caption p { + margin-bottom: 0; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/close.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/close.less new file mode 100644 index 0000000..4c626bd --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/close.less @@ -0,0 +1,32 @@ +// +// Close icons +// -------------------------------------------------- + + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: @baseLineHeight; + color: @black; + text-shadow: 0 1px 0 rgba(255,255,255,1); + .opacity(20); + &:hover, + &:focus { + color: @black; + text-decoration: none; + cursor: pointer; + .opacity(40); + } +} + +// Additional properties for button version +// iOS requires the button element instead of an anchor tag. +// If you want the anchor version, it requires `href="#"`. +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/code.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/code.less new file mode 100644 index 0000000..266a926 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/code.less @@ -0,0 +1,61 @@ +// +// Code (inline and blocK) +// -------------------------------------------------- + + +// Inline and block code styles +code, +pre { + padding: 0 3px 2px; + #font > #family > .monospace; + font-size: @baseFontSize - 2; + color: @grayDark; + .border-radius(3px); +} + +// Inline code +code { + padding: 2px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; + white-space: nowrap; +} + +// Blocks of code +pre { + display: block; + padding: (@baseLineHeight - 1) / 2; + margin: 0 0 @baseLineHeight / 2; + font-size: @baseFontSize - 1; // 14px to 13px + line-height: @baseLineHeight; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; // fallback for IE7-8 + border: 1px solid rgba(0,0,0,.15); + .border-radius(@baseBorderRadius); + + // Make prettyprint styles more spaced out for readability + &.prettyprint { + margin-bottom: @baseLineHeight; + } + + // Account for some code outputs that place code tags in pre tags + code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; + } +} + +// Enable scrollable blocks of code +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/component-animations.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/component-animations.less new file mode 100644 index 0000000..d614263 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/component-animations.less @@ -0,0 +1,22 @@ +// +// Component animations +// -------------------------------------------------- + + +.fade { + opacity: 0; + .transition(opacity .15s linear); + &.in { + opacity: 1; + } +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + .transition(height .35s ease); + &.in { + height: auto; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/dropdowns.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/dropdowns.less new file mode 100644 index 0000000..bbfe3fd --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/dropdowns.less @@ -0,0 +1,237 @@ +// +// Dropdown menus +// -------------------------------------------------- + + +// Use the .menu class on any
  • element within the topbar or ul.tabs and you'll get some superfancy dropdowns +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle { + // The caret makes the toggle a bit too tall in IE7 + *margin-bottom: -3px; +} +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +// Dropdown arrow/caret +// -------------------- +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid @black; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +// Place the caret +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +// The dropdown menu (ul) +// ---------------------- +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: @zindexDropdown; + display: none; // none by default, but block on "open" of the menu + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; // override default ul + list-style: none; + background-color: @dropdownBackground; + border: 1px solid #ccc; // Fallback for IE7-8 + border: 1px solid @dropdownBorder; + *border-right-width: 2px; + *border-bottom-width: 2px; + .border-radius(6px); + .box-shadow(0 5px 10px rgba(0,0,0,.2)); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + + // Aligns the dropdown menu to right + &.pull-right { + right: 0; + left: auto; + } + + // Dividers (basically an hr) within the dropdown + .divider { + .nav-divider(@dropdownDividerTop, @dropdownDividerBottom); + } + + // Links within the dropdown menu + > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: @baseLineHeight; + color: @dropdownLinkColor; + white-space: nowrap; + } +} + +// Hover/Focus state +// ----------- +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + text-decoration: none; + color: @dropdownLinkColorHover; + #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%)); +} + +// Active state +// ------------ +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: @dropdownLinkColorActive; + text-decoration: none; + outline: 0; + #gradient > .vertical(@dropdownLinkBackgroundActive, darken(@dropdownLinkBackgroundActive, 5%)); +} + +// Disabled state +// -------------- +// Gray out text and ensure the hover/focus state remains gray +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: @grayLight; +} +// Nuke hover/focus effects +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; // Remove CSS gradient + .reset-filter(); + cursor: default; +} + +// Open state for the dropdown +// --------------------------- +.open { + // IE7's z-index only goes to the nearest positioned ancestor, which would + // make the menu appear below buttons that appeared later on the page + *z-index: @zindexDropdown; + + & > .dropdown-menu { + display: block; + } +} + +// Right aligned dropdowns +// --------------------------- +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +// Allow for dropdowns to go bottom up (aka, dropup-menu) +// ------------------------------------------------------ +// Just add .dropup after the standard .dropdown class and you're set, bro. +// TODO: abstract this so that the navbar fixed styles are not placed here? +.dropup, +.navbar-fixed-bottom .dropdown { + // Reverse the caret + .caret { + border-top: 0; + border-bottom: 4px solid @black; + content: ""; + } + // Different positioning for bottom up menu + .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; + } +} + +// Sub menus +// --------------------------- +.dropdown-submenu { + position: relative; +} +// Default dropdowns +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + .border-radius(0 6px 6px 6px); +} +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +// Dropups +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + .border-radius(5px 5px 5px 0); +} + +// Caret to indicate there is a submenu +.dropdown-submenu > a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: darken(@dropdownBackground, 20%); + margin-top: 5px; + margin-right: -10px; +} +.dropdown-submenu:hover > a:after { + border-left-color: @dropdownLinkColorHover; +} + +// Left aligned submenus +.dropdown-submenu.pull-left { + // Undo the float + // Yes, this is awkward since .pull-left adds a float, but it sticks to our conventions elsewhere. + float: none; + + // Positioning the submenu + > .dropdown-menu { + left: -100%; + margin-left: 10px; + .border-radius(6px 0 6px 6px); + } +} + +// Tweak nav headers +// ----------------- +// Increase padding from 15px to 20px on sides +.dropdown .dropdown-menu .nav-header { + padding-left: 20px; + padding-right: 20px; +} + +// Typeahead +// --------- +.typeahead { + z-index: 1051; + margin-top: 2px; // give it some space to breathe + .border-radius(@baseBorderRadius); +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/forms.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/forms.less new file mode 100644 index 0000000..06767bd --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/forms.less @@ -0,0 +1,690 @@ +// +// Forms +// -------------------------------------------------- + + +// GENERAL STYLES +// -------------- + +// Make all forms have space below them +form { + margin: 0 0 @baseLineHeight; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +// Groups of fields with labels on top (legends) +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: @baseLineHeight; + font-size: @baseFontSize * 1.5; + line-height: @baseLineHeight * 2; + color: @grayDark; + border: 0; + border-bottom: 1px solid #e5e5e5; + + // Small + small { + font-size: @baseLineHeight * .75; + color: @grayLight; + } +} + +// Set font for forms +label, +input, +button, +select, +textarea { + #font > .shorthand(@baseFontSize,normal,@baseLineHeight); // Set size, weight, line-height here +} +input, +button, +select, +textarea { + font-family: @baseFontFamily; // And only set font-family here for those that need it (note the missing label element) +} + +// Identify controls by their labels +label { + display: block; + margin-bottom: 5px; +} + +// Form controls +// ------------------------- + +// Shared size and type resets +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: @baseLineHeight; + padding: 4px 6px; + margin-bottom: @baseLineHeight / 2; + font-size: @baseFontSize; + line-height: @baseLineHeight; + color: @gray; + .border-radius(@inputBorderRadius); + vertical-align: middle; +} + +// Reset appearance properties for textual inputs and textarea +// Declare width for legacy (can't be on input[type=*] selectors or it's too specific) +input, +textarea, +.uneditable-input { + width: 206px; // plus 12px padding and 2px border +} +// Reset height since textareas have rows +textarea { + height: auto; +} +// Everything else +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: @inputBackground; + border: 1px solid @inputBorder; + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); + .transition(~"border linear .2s, box-shadow linear .2s"); + + // Focus state + &:focus { + border-color: rgba(82,168,236,.8); + outline: 0; + outline: thin dotted \9; /* IE6-9 */ + .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)"); + } +} + +// Position radios and checkboxes better +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + *margin-top: 0; /* IE7 */ + margin-top: 1px \9; /* IE8-9 */ + line-height: normal; +} + +// Reset width of input images, buttons, radios, checkboxes +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; // Override of generic input selector +} + +// Set the height of select and file controls to match text inputs +select, +input[type="file"] { + height: @inputHeight; /* In IE7, the height of the select element cannot be changed by height, only font-size */ + *margin-top: 4px; /* For IE7, add top margin to align select with labels */ + line-height: @inputHeight; +} + +// Make select elements obey height by applying a border +select { + width: 220px; // default input width + 10px of padding that doesn't get applied + border: 1px solid @inputBorder; + background-color: @inputBackground; // Chrome on Linux and Mobile Safari need background-color +} + +// Make multiple select elements height not fixed +select[multiple], +select[size] { + height: auto; +} + +// Focus for select, file, radio, and checkbox +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + .tab-focus(); +} + + +// Uneditable inputs +// ------------------------- + +// Make uneditable inputs look inactive +.uneditable-input, +.uneditable-textarea { + color: @grayLight; + background-color: darken(@inputBackground, 1%); + border-color: @inputBorder; + .box-shadow(inset 0 1px 2px rgba(0,0,0,.025)); + cursor: not-allowed; +} + +// For text that needs to appear as an input but should not be an input +.uneditable-input { + overflow: hidden; // prevent text from wrapping, but still cut it off like an input does + white-space: nowrap; +} + +// Make uneditable textareas behave like a textarea +.uneditable-textarea { + width: auto; + height: auto; +} + + +// Placeholder +// ------------------------- + +// Placeholder text gets special styles because when browsers invalidate entire lines if it doesn't understand a selector +input, +textarea { + .placeholder(); +} + + +// CHECKBOXES & RADIOS +// ------------------- + +// Indent the labels to position radios/checkboxes as hanging +.radio, +.checkbox { + min-height: @baseLineHeight; // clear the floating input if there is no label text + padding-left: 20px; +} +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +// Move the options list down to align with labels +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; // has to be padding because margin collaspes +} + +// Radios and checkboxes on same line +// TODO v3: Convert .inline to .control-inline +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; // space out consecutive inline controls +} + + + +// INPUT SIZES +// ----------- + +// General classes for quick sizes +.input-mini { width: 60px; } +.input-small { width: 90px; } +.input-medium { width: 150px; } +.input-large { width: 210px; } +.input-xlarge { width: 270px; } +.input-xxlarge { width: 530px; } + +// Grid style input sizes +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +// Redeclare since the fluid row class is more specific +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} +// Ensure input-prepend/append never wraps +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + + + +// GRID SIZING FOR INPUTS +// ---------------------- + +// Grid sizes +#grid > .input(@gridColumnWidth, @gridGutterWidth); + +// Control row for multiple inputs per line +.controls-row { + .clearfix(); // Clear the float from controls +} + +// Float to collapse white-space for proper grid alignment +.controls-row [class*="span"], +// Redeclare the fluid grid collapse since we undo the float for inputs +.row-fluid .controls-row [class*="span"] { + float: left; +} +// Explicity set top padding on all checkboxes/radios, not just first-child +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + + + + +// DISABLED STATE +// -------------- + +// Disabled and read-only inputs +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: @inputDisabledBackground; +} +// Explicitly reset the colors here +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + + + + +// FORM FIELD FEEDBACK STATES +// -------------------------- + +// Warning +.control-group.warning { + .formFieldState(@warningText, @warningText, @warningBackground); +} +// Error +.control-group.error { + .formFieldState(@errorText, @errorText, @errorBackground); +} +// Success +.control-group.success { + .formFieldState(@successText, @successText, @successBackground); +} +// Success +.control-group.info { + .formFieldState(@infoText, @infoText, @infoBackground); +} + +// HTML5 invalid states +// Shares styles with the .control-group.error above +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; + &:focus { + border-color: darken(#ee5f5b, 10%); + @shadow: 0 0 6px lighten(#ee5f5b, 20%); + .box-shadow(@shadow); + } +} + + + +// FORM ACTIONS +// ------------ + +.form-actions { + padding: (@baseLineHeight - 1) 20px @baseLineHeight; + margin-top: @baseLineHeight; + margin-bottom: @baseLineHeight; + background-color: @formActionsBackground; + border-top: 1px solid #e5e5e5; + .clearfix(); // Adding clearfix to allow for .pull-right button containers +} + + + +// HELP TEXT +// --------- + +.help-block, +.help-inline { + color: lighten(@textColor, 15%); // lighten the text some for contrast +} + +.help-block { + display: block; // account for any element using help-block + margin-bottom: @baseLineHeight / 2; +} + +.help-inline { + display: inline-block; + .ie7-inline-block(); + vertical-align: middle; + padding-left: 5px; +} + + + +// INPUT GROUPS +// ------------ + +// Allow us to put symbols and text within the input field for a cleaner look +.input-append, +.input-prepend { + display: inline-block; + margin-bottom: @baseLineHeight / 2; + vertical-align: middle; + font-size: 0; // white space collapse hack + white-space: nowrap; // Prevent span and input from separating + + // Reset the white space collapse hack + input, + select, + .uneditable-input, + .dropdown-menu, + .popover { + font-size: @baseFontSize; + } + + input, + select, + .uneditable-input { + position: relative; // placed here by default so that on :focus we can place the input above the .add-on for full border and box-shadow goodness + margin-bottom: 0; // prevent bottom margin from screwing up alignment in stacked forms + *margin-left: 0; + vertical-align: top; + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + // Make input on top when focused so blue border and shadow always show + &:focus { + z-index: 2; + } + } + .add-on { + display: inline-block; + width: auto; + height: @baseLineHeight; + min-width: 16px; + padding: 4px 5px; + font-size: @baseFontSize; + font-weight: normal; + line-height: @baseLineHeight; + text-align: center; + text-shadow: 0 1px 0 @white; + background-color: @grayLighter; + border: 1px solid #ccc; + } + .add-on, + .btn, + .btn-group > .dropdown-toggle { + vertical-align: top; + .border-radius(0); + } + .active { + background-color: lighten(@green, 30); + border-color: @green; + } +} + +.input-prepend { + .add-on, + .btn { + margin-right: -1px; + } + .add-on:first-child, + .btn:first-child { + // FYI, `.btn:first-child` accounts for a button group that's prepended + .border-radius(@inputBorderRadius 0 0 @inputBorderRadius); + } +} + +.input-append { + input, + select, + .uneditable-input { + .border-radius(@inputBorderRadius 0 0 @inputBorderRadius); + + .btn-group .btn:last-child { + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + } + } + .add-on, + .btn, + .btn-group { + margin-left: -1px; + } + .add-on:last-child, + .btn:last-child, + .btn-group:last-child > .dropdown-toggle { + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + } +} + +// Remove all border-radius for inputs with both prepend and append +.input-prepend.input-append { + input, + select, + .uneditable-input { + .border-radius(0); + + .btn-group .btn { + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + } + } + .add-on:first-child, + .btn:first-child { + margin-right: -1px; + .border-radius(@inputBorderRadius 0 0 @inputBorderRadius); + } + .add-on:last-child, + .btn:last-child { + margin-left: -1px; + .border-radius(0 @inputBorderRadius @inputBorderRadius 0); + } + .btn-group:first-child { + margin-left: 0; + } +} + + + + +// SEARCH FORM +// ----------- + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; /* IE7-8 doesn't have border-radius, so don't indent the padding */ + margin-bottom: 0; // Remove the default margin on all inputs + .border-radius(15px); +} + +/* Allow for input prepend/append in search forms */ +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + .border-radius(0); // Override due to specificity +} +.form-search .input-append .search-query { + .border-radius(14px 0 0 14px); +} +.form-search .input-append .btn { + .border-radius(0 14px 14px 0); +} +.form-search .input-prepend .search-query { + .border-radius(0 14px 14px 0); +} +.form-search .input-prepend .btn { + .border-radius(14px 0 0 14px); +} + + + + +// HORIZONTAL & VERTICAL FORMS +// --------------------------- + +// Common properties +// ----------------- + +.form-search, +.form-inline, +.form-horizontal { + input, + textarea, + select, + .help-inline, + .uneditable-input, + .input-prepend, + .input-append { + display: inline-block; + .ie7-inline-block(); + margin-bottom: 0; + vertical-align: middle; + } + // Re-hide hidden elements due to specifity + .hide { + display: none; + } +} +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} +// Remove margin for input-prepend/-append +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} +// Inline checkbox/radio labels (remove padding on left) +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} +// Remove float and margin, set to inline-block +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + + +// Margin to space out fieldsets +.control-group { + margin-bottom: @baseLineHeight / 2; +} + +// Legend collapses margin, so next element is responsible for spacing +legend + .control-group { + margin-top: @baseLineHeight; + -webkit-margin-top-collapse: separate; +} + +// Horizontal-specific styles +// -------------------------- + +.form-horizontal { + // Increase spacing between groups + .control-group { + margin-bottom: @baseLineHeight; + .clearfix(); + } + // Float the labels left + .control-label { + float: left; + width: @horizontalComponentOffset - 20; + padding-top: 5px; + text-align: right; + } + // Move over all input controls and content + .controls { + // Super jank IE7 fix to ensure the inputs in .input-append and input-prepend + // don't inherit the margin of the parent, in this case .controls + *display: inline-block; + *padding-left: 20px; + margin-left: @horizontalComponentOffset; + *margin-left: 0; + &:first-child { + *padding-left: @horizontalComponentOffset; + } + } + // Remove bottom margin on block level help text since that's accounted for on .control-group + .help-block { + margin-bottom: 0; + } + // And apply it only to .help-block instances that follow a form control + input, + select, + textarea, + .uneditable-input, + .input-prepend, + .input-append { + + .help-block { + margin-top: @baseLineHeight / 2; + } + } + // Move over buttons in .form-actions to align with .controls + .form-actions { + padding-left: @horizontalComponentOffset; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/grid.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/grid.less new file mode 100644 index 0000000..750d203 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/grid.less @@ -0,0 +1,21 @@ +// +// Grid system +// -------------------------------------------------- + + +// Fixed (940px) +#grid > .core(@gridColumnWidth, @gridGutterWidth); + +// Fluid (940px) +#grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth); + +// Reset utility classes due to specificity +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/hero-unit.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/hero-unit.less new file mode 100644 index 0000000..763d86a --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/hero-unit.less @@ -0,0 +1,25 @@ +// +// Hero unit +// -------------------------------------------------- + + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: @baseLineHeight * 1.5; + color: @heroUnitLeadColor; + background-color: @heroUnitBackground; + .border-radius(6px); + h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + color: @heroUnitHeadingColor; + letter-spacing: -1px; + } + li { + line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/labels-badges.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/labels-badges.less new file mode 100644 index 0000000..bc321fe --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/labels-badges.less @@ -0,0 +1,84 @@ +// +// Labels and badges +// -------------------------------------------------- + + +// Base classes +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: @baseFontSize * .846; + font-weight: bold; + line-height: 14px; // ensure proper line-height if floated + color: @white; + vertical-align: baseline; + white-space: nowrap; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + background-color: @grayLight; +} +// Set unique padding and border-radii +.label { + .border-radius(3px); +} +.badge { + padding-left: 9px; + padding-right: 9px; + .border-radius(9px); +} + +// Empty labels/badges collapse +.label, +.badge { + &:empty { + display: none; + } +} + +// Hover/focus state, but only for links +a { + &.label:hover, + &.label:focus, + &.badge:hover, + &.badge:focus { + color: @white; + text-decoration: none; + cursor: pointer; + } +} + +// Colors +// Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute) +.label, +.badge { + // Important (red) + &-important { background-color: @errorText; } + &-important[href] { background-color: darken(@errorText, 10%); } + // Warnings (orange) + &-warning { background-color: @orange; } + &-warning[href] { background-color: darken(@orange, 10%); } + // Success (green) + &-success { background-color: @successText; } + &-success[href] { background-color: darken(@successText, 10%); } + // Info (turquoise) + &-info { background-color: @infoText; } + &-info[href] { background-color: darken(@infoText, 10%); } + // Inverse (black) + &-inverse { background-color: @grayDark; } + &-inverse[href] { background-color: darken(@grayDark, 10%); } +} + +// Quick fix for labels/badges in buttons +.btn { + .label, + .badge { + position: relative; + top: -1px; + } +} +.btn-mini { + .label, + .badge { + top: 0; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/layouts.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/layouts.less new file mode 100644 index 0000000..24a2062 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/layouts.less @@ -0,0 +1,16 @@ +// +// Layouts +// -------------------------------------------------- + + +// Container (centered, fixed-width layouts) +.container { + .container-fixed(); +} + +// Fluid layouts (left aligned, with sidebar, min- & max-width content) +.container-fluid { + padding-right: @gridGutterWidth; + padding-left: @gridGutterWidth; + .clearfix(); +} \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/media.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/media.less new file mode 100644 index 0000000..e461e44 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/media.less @@ -0,0 +1,55 @@ +// Media objects +// Source: http://stubbornella.org/content/?p=497 +// -------------------------------------------------- + + +// Common styles +// ------------------------- + +// Clear the floats +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +// Proper spacing between instances of .media +.media, +.media .media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} + +// For images and videos, set to block +.media-object { + display: block; +} + +// Reset margins on headings for tighter default spacing +.media-heading { + margin: 0 0 5px; +} + + +// Media image alignment +// ------------------------- + +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-right { + margin-left: 10px; +} + + +// Media list variation +// ------------------------- + +// Undo default ul/ol styles +.media-list { + margin-left: 0; + list-style: none; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/mixins.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/mixins.less new file mode 100644 index 0000000..79d8892 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/mixins.less @@ -0,0 +1,702 @@ +// +// Mixins +// -------------------------------------------------- + + +// UTILITY MIXINS +// -------------------------------------------------- + +// Clearfix +// -------- +// For clearing floats like a boss h5bp.com/q +.clearfix { + *zoom: 1; + &:before, + &:after { + display: table; + content: ""; + // Fixes Opera/contenteditable bug: + // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952 + line-height: 0; + } + &:after { + clear: both; + } +} + +// Webkit-style focus +// ------------------ +.tab-focus() { + // Default + outline: thin dotted #333; + // Webkit + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +// Center-align a block level element +// ---------------------------------- +.center-block() { + display: block; + margin-left: auto; + margin-right: auto; +} + +// IE7 inline-block +// ---------------- +.ie7-inline-block() { + *display: inline; /* IE7 inline-block hack */ + *zoom: 1; +} + +// IE7 likes to collapse whitespace on either side of the inline-block elements. +// Ems because we're attempting to match the width of a space character. Left +// version is for form buttons, which typically come after other elements, and +// right version is for icons, which come before. Applying both is ok, but it will +// mean that space between those elements will be .6em (~2 space characters) in IE7, +// instead of the 1 space in other browsers. +.ie7-restore-left-whitespace() { + *margin-left: .3em; + + &:first-child { + *margin-left: 0; + } +} + +.ie7-restore-right-whitespace() { + *margin-right: .3em; +} + +// Sizing shortcuts +// ------------------------- +.size(@height, @width) { + width: @width; + height: @height; +} +.square(@size) { + .size(@size, @size); +} + +// Placeholder text +// ------------------------- +.placeholder(@color: @placeholderText) { + &:-moz-placeholder { + color: @color; + } + &:-ms-input-placeholder { + color: @color; + } + &::-webkit-input-placeholder { + color: @color; + } +} + +// Text overflow +// ------------------------- +// Requires inline-block or block for proper styling +.text-overflow() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +// CSS image replacement +// ------------------------- +// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + + +// FONTS +// -------------------------------------------------- + +#font { + #family { + .serif() { + font-family: @serifFontFamily; + } + .sans-serif() { + font-family: @sansFontFamily; + } + .monospace() { + font-family: @monoFontFamily; + } + } + .shorthand(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + font-size: @size; + font-weight: @weight; + line-height: @lineHeight; + } + .serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .serif; + #font > .shorthand(@size, @weight, @lineHeight); + } + .sans-serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .sans-serif; + #font > .shorthand(@size, @weight, @lineHeight); + } + .monospace(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .monospace; + #font > .shorthand(@size, @weight, @lineHeight); + } +} + + +// FORMS +// -------------------------------------------------- + +// Block level inputs +.input-block-level { + display: block; + width: 100%; + min-height: @inputHeight; // Make inputs at least the height of their button counterpart (base line-height + padding + border) + .box-sizing(border-box); // Makes inputs behave like true block-level elements +} + + + +// Mixin for form field states +.formFieldState(@textColor: #555, @borderColor: #ccc, @backgroundColor: #f5f5f5) { + // Set the text color + .control-label, + .help-block, + .help-inline { + color: @textColor; + } + // Style inputs accordingly + .checkbox, + .radio, + input, + select, + textarea { + color: @textColor; + } + input, + select, + textarea { + border-color: @borderColor; + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work + &:focus { + border-color: darken(@borderColor, 10%); + @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@borderColor, 20%); + .box-shadow(@shadow); + } + } + // Give a small background color for input-prepend/-append + .input-prepend .add-on, + .input-append .add-on { + color: @textColor; + background-color: @backgroundColor; + border-color: @textColor; + } +} + + + +// CSS3 PROPERTIES +// -------------------------------------------------- + +// Border Radius +.border-radius(@radius) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + border-radius: @radius; +} + +// Single Corner Border Radius +.border-top-left-radius(@radius) { + -webkit-border-top-left-radius: @radius; + -moz-border-radius-topleft: @radius; + border-top-left-radius: @radius; +} +.border-top-right-radius(@radius) { + -webkit-border-top-right-radius: @radius; + -moz-border-radius-topright: @radius; + border-top-right-radius: @radius; +} +.border-bottom-right-radius(@radius) { + -webkit-border-bottom-right-radius: @radius; + -moz-border-radius-bottomright: @radius; + border-bottom-right-radius: @radius; +} +.border-bottom-left-radius(@radius) { + -webkit-border-bottom-left-radius: @radius; + -moz-border-radius-bottomleft: @radius; + border-bottom-left-radius: @radius; +} + +// Single Side Border Radius +.border-top-radius(@radius) { + .border-top-right-radius(@radius); + .border-top-left-radius(@radius); +} +.border-right-radius(@radius) { + .border-top-right-radius(@radius); + .border-bottom-right-radius(@radius); +} +.border-bottom-radius(@radius) { + .border-bottom-right-radius(@radius); + .border-bottom-left-radius(@radius); +} +.border-left-radius(@radius) { + .border-top-left-radius(@radius); + .border-bottom-left-radius(@radius); +} + +// Drop shadows +.box-shadow(@shadow) { + -webkit-box-shadow: @shadow; + -moz-box-shadow: @shadow; + box-shadow: @shadow; +} + +// Transitions +.transition(@transition) { + -webkit-transition: @transition; + -moz-transition: @transition; + -o-transition: @transition; + transition: @transition; +} +.transition-delay(@transition-delay) { + -webkit-transition-delay: @transition-delay; + -moz-transition-delay: @transition-delay; + -o-transition-delay: @transition-delay; + transition-delay: @transition-delay; +} +.transition-duration(@transition-duration) { + -webkit-transition-duration: @transition-duration; + -moz-transition-duration: @transition-duration; + -o-transition-duration: @transition-duration; + transition-duration: @transition-duration; +} + +// Transformations +.rotate(@degrees) { + -webkit-transform: rotate(@degrees); + -moz-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} +.scale(@ratio) { + -webkit-transform: scale(@ratio); + -moz-transform: scale(@ratio); + -ms-transform: scale(@ratio); + -o-transform: scale(@ratio); + transform: scale(@ratio); +} +.translate(@x, @y) { + -webkit-transform: translate(@x, @y); + -moz-transform: translate(@x, @y); + -ms-transform: translate(@x, @y); + -o-transform: translate(@x, @y); + transform: translate(@x, @y); +} +.skew(@x, @y) { + -webkit-transform: skew(@x, @y); + -moz-transform: skew(@x, @y); + -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twitter/bootstrap/issues/4885 + -o-transform: skew(@x, @y); + transform: skew(@x, @y); + -webkit-backface-visibility: hidden; // See https://github.com/twitter/bootstrap/issues/5319 +} +.translate3d(@x, @y, @z) { + -webkit-transform: translate3d(@x, @y, @z); + -moz-transform: translate3d(@x, @y, @z); + -o-transform: translate3d(@x, @y, @z); + transform: translate3d(@x, @y, @z); +} + +// Backface visibility +// Prevent browsers from flickering when using CSS 3D transforms. +// Default value is `visible`, but can be changed to `hidden +// See git pull https://github.com/dannykeane/bootstrap.git backface-visibility for examples +.backface-visibility(@visibility){ + -webkit-backface-visibility: @visibility; + -moz-backface-visibility: @visibility; + backface-visibility: @visibility; +} + +// Background clipping +// Heads up: FF 3.6 and under need "padding" instead of "padding-box" +.background-clip(@clip) { + -webkit-background-clip: @clip; + -moz-background-clip: @clip; + background-clip: @clip; +} + +// Background sizing +.background-size(@size) { + -webkit-background-size: @size; + -moz-background-size: @size; + -o-background-size: @size; + background-size: @size; +} + + +// Box sizing +.box-sizing(@boxmodel) { + -webkit-box-sizing: @boxmodel; + -moz-box-sizing: @boxmodel; + box-sizing: @boxmodel; +} + +// User select +// For selecting text on the page +.user-select(@select) { + -webkit-user-select: @select; + -moz-user-select: @select; + -ms-user-select: @select; + -o-user-select: @select; + user-select: @select; +} + +// Resize anything +.resizable(@direction) { + resize: @direction; // Options: horizontal, vertical, both + overflow: auto; // Safari fix +} + +// CSS3 Content Columns +.content-columns(@columnCount, @columnGap: @gridGutterWidth) { + -webkit-column-count: @columnCount; + -moz-column-count: @columnCount; + column-count: @columnCount; + -webkit-column-gap: @columnGap; + -moz-column-gap: @columnGap; + column-gap: @columnGap; +} + +// Optional hyphenation +.hyphens(@mode: auto) { + word-wrap: break-word; + -webkit-hyphens: @mode; + -moz-hyphens: @mode; + -ms-hyphens: @mode; + -o-hyphens: @mode; + hyphens: @mode; +} + +// Opacity +.opacity(@opacity) { + opacity: @opacity / 100; + filter: ~"alpha(opacity=@{opacity})"; +} + + + +// BACKGROUNDS +// -------------------------------------------------- + +// Add an alphatransparency value to any background or border color (via Elyse Holladay) +#translucent { + .background(@color: @white, @alpha: 1) { + background-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); + } + .border(@color: @white, @alpha: 1) { + border-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); + .background-clip(padding-box); + } +} + +// Gradient Bar Colors for buttons and alerts +.gradientBar(@primaryColor, @secondaryColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) { + color: @textColor; + text-shadow: @textShadow; + #gradient > .vertical(@primaryColor, @secondaryColor); + border-color: @secondaryColor @secondaryColor darken(@secondaryColor, 15%); + border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fadein(rgba(0,0,0,.1), 15%); +} + +// Gradients +#gradient { + .horizontal(@startColor: #555, @endColor: #333) { + background-color: @endColor; + background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to right, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@startColor),argb(@endColor))); // IE9 and down + } + .vertical(@startColor: #555, @endColor: #333) { + background-color: mix(@startColor, @endColor, 60%); + background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down + } + .directional(@startColor: #555, @endColor: #333, @deg: 45deg) { + background-color: @endColor; + background-repeat: repeat-x; + background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(@deg, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(@deg, @startColor, @endColor); // Standard, IE10 + } + .horizontal-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) { + background-color: mix(@midColor, @endColor, 80%); + background-image: -webkit-gradient(left, linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor)); + background-image: -webkit-linear-gradient(left, @startColor, @midColor @colorStop, @endColor); + background-image: -moz-linear-gradient(left, @startColor, @midColor @colorStop, @endColor); + background-image: -o-linear-gradient(left, @startColor, @midColor @colorStop, @endColor); + background-image: linear-gradient(to right, @startColor, @midColor @colorStop, @endColor); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback + } + + .vertical-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) { + background-color: mix(@midColor, @endColor, 80%); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor)); + background-image: -webkit-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: -moz-linear-gradient(top, @startColor, @midColor @colorStop, @endColor); + background-image: -o-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback + } + .radial(@innerColor: #555, @outerColor: #333) { + background-color: @outerColor; + background-image: -webkit-gradient(radial, center center, 0, center center, 460, from(@innerColor), to(@outerColor)); + background-image: -webkit-radial-gradient(circle, @innerColor, @outerColor); + background-image: -moz-radial-gradient(circle, @innerColor, @outerColor); + background-image: -o-radial-gradient(circle, @innerColor, @outerColor); + background-repeat: no-repeat; + } + .striped(@color: #555, @angle: 45deg) { + background-color: @color; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + } +} +// Reset filters for IE +.reset-filter() { + filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); +} + + + +// COMPONENT MIXINS +// -------------------------------------------------- + +// Horizontal dividers +// ------------------------- +// Dividers (basically an hr) within dropdowns and nav lists +.nav-divider(@top: #e5e5e5, @bottom: @white) { + // IE7 needs a set width since we gave a height. Restricting just + // to IE7 to keep the 1px left/right space in other browsers. + // It is unclear where IE is getting the extra space that we need + // to negative-margin away, but so it goes. + *width: 100%; + height: 1px; + margin: ((@baseLineHeight / 2) - 1) 1px; // 8px 1px + *margin: -5px 0 5px; + overflow: hidden; + background-color: @top; + border-bottom: 1px solid @bottom; +} + +// Button backgrounds +// ------------------ +.buttonBackground(@startColor, @endColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) { + // gradientBar will set the background to a pleasing blend of these, to support IE<=9 + .gradientBar(@startColor, @endColor, @textColor, @textShadow); + *background-color: @endColor; /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + .reset-filter(); + + // in these cases the gradient won't cover the background, so we override + &:hover, &:focus, &:active, &.active, &.disabled, &[disabled] { + color: @textColor; + background-color: @endColor; + *background-color: darken(@endColor, 5%); + } + + // IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves + &:active, + &.active { + background-color: darken(@endColor, 10%) e("\9"); + } +} + +// Navbar vertical align +// ------------------------- +// Vertically center elements in the navbar. +// Example: an element has a height of 30px, so write out `.navbarVerticalAlign(30px);` to calculate the appropriate top margin. +.navbarVerticalAlign(@elementHeight) { + margin-top: (@navbarHeight - @elementHeight) / 2; +} + + + +// Grid System +// ----------- + +// Centered container element +.container-fixed() { + margin-right: auto; + margin-left: auto; + .clearfix(); +} + +// Table columns +.tableColumns(@columnSpan: 1) { + float: none; // undo default grid column styles + width: ((@gridColumnWidth) * @columnSpan) + (@gridGutterWidth * (@columnSpan - 1)) - 16; // 16 is total padding on left and right of table cells + margin-left: 0; // undo default grid column styles +} + +// Make a Grid +// Use .makeRow and .makeColumn to assign semantic layouts grid system behavior +.makeRow() { + margin-left: @gridGutterWidth * -1; + .clearfix(); +} +.makeColumn(@columns: 1, @offset: 0) { + float: left; + margin-left: (@gridColumnWidth * @offset) + (@gridGutterWidth * (@offset - 1)) + (@gridGutterWidth * 2); + width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1)); +} + +// The Grid +#grid { + + .core (@gridColumnWidth, @gridGutterWidth) { + + .spanX (@index) when (@index > 0) { + .span@{index} { .span(@index); } + .spanX(@index - 1); + } + .spanX (0) {} + + .offsetX (@index) when (@index > 0) { + .offset@{index} { .offset(@index); } + .offsetX(@index - 1); + } + .offsetX (0) {} + + .offset (@columns) { + margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns + 1)); + } + + .span (@columns) { + width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1)); + } + + .row { + margin-left: @gridGutterWidth * -1; + .clearfix(); + } + + [class*="span"] { + float: left; + min-height: 1px; // prevent collapsing columns + margin-left: @gridGutterWidth; + } + + // Set the container width, and override it for fixed navbars in media queries + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { .span(@gridColumns); } + + // generate .spanX and .offsetX + .spanX (@gridColumns); + .offsetX (@gridColumns); + + } + + .fluid (@fluidGridColumnWidth, @fluidGridGutterWidth) { + + .spanX (@index) when (@index > 0) { + .span@{index} { .span(@index); } + .spanX(@index - 1); + } + .spanX (0) {} + + .offsetX (@index) when (@index > 0) { + .offset@{index} { .offset(@index); } + .offset@{index}:first-child { .offsetFirstChild(@index); } + .offsetX(@index - 1); + } + .offsetX (0) {} + + .offset (@columns) { + margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth*2); + *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + (@fluidGridGutterWidth*2) - (.5 / @gridRowWidth * 100 * 1%); + } + + .offsetFirstChild (@columns) { + margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth); + *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%); + } + + .span (@columns) { + width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)); + *width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%); + } + + .row-fluid { + width: 100%; + .clearfix(); + [class*="span"] { + .input-block-level(); + float: left; + margin-left: @fluidGridGutterWidth; + *margin-left: @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%); + } + [class*="span"]:first-child { + margin-left: 0; + } + + // Space grid-sized controls properly if multiple per line + .controls-row [class*="span"] + [class*="span"] { + margin-left: @fluidGridGutterWidth; + } + + // generate .spanX and .offsetX + .spanX (@gridColumns); + .offsetX (@gridColumns); + } + + } + + .input(@gridColumnWidth, @gridGutterWidth) { + + .spanX (@index) when (@index > 0) { + input.span@{index}, textarea.span@{index}, .uneditable-input.span@{index} { .span(@index); } + .spanX(@index - 1); + } + .spanX (0) {} + + .span(@columns) { + width: ((@gridColumnWidth) * @columns) + (@gridGutterWidth * (@columns - 1)) - 14; + } + + input, + textarea, + .uneditable-input { + margin-left: 0; // override margin-left from core grid system + } + + // Space grid-sized controls properly if multiple per line + .controls-row [class*="span"] + [class*="span"] { + margin-left: @gridGutterWidth; + } + + // generate .spanX + .spanX (@gridColumns); + + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/modals.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/modals.less new file mode 100644 index 0000000..8e272d4 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/modals.less @@ -0,0 +1,95 @@ +// +// Modals +// -------------------------------------------------- + +// Background +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: @zindexModalBackdrop; + background-color: @black; + // Fade for backdrop + &.fade { opacity: 0; } +} + +.modal-backdrop, +.modal-backdrop.fade.in { + .opacity(80); +} + +// Base modal +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: @zindexModal; + width: 560px; + margin-left: -280px; + background-color: @white; + border: 1px solid #999; + border: 1px solid rgba(0,0,0,.3); + *border: 1px solid #999; /* IE6-7 */ + .border-radius(6px); + .box-shadow(0 3px 7px rgba(0,0,0,0.3)); + .background-clip(padding-box); + // Remove focus outline from opened modal + outline: none; + + &.fade { + .transition(e('opacity .3s linear, top .3s ease-out')); + top: -25%; + } + &.fade.in { top: 10%; } +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; + // Close icon + .close { margin-top: 2px; } + // Heading + h3 { + margin: 0; + line-height: 30px; + } +} + +// Body (where all modal content resides) +.modal-body { + position: relative; + overflow-y: auto; + max-height: 400px; + padding: 15px; +} +// Remove bottom margin if need be +.modal-form { + margin-bottom: 0; +} + +// Footer (for actions) +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; // right align buttons + background-color: #f5f5f5; + border-top: 1px solid #ddd; + .border-radius(0 0 6px 6px); + .box-shadow(inset 0 1px 0 @white); + .clearfix(); // clear it in case folks use .pull-* classes on buttons + + // Properly space out buttons + .btn + .btn { + margin-left: 5px; + margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs + } + // but override that for button groups + .btn-group .btn + .btn { + margin-left: -1px; + } + // and override it for block buttons as well + .btn-block + .btn-block { + margin-left: 0; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/navbar.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/navbar.less new file mode 100644 index 0000000..93d09bc --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/navbar.less @@ -0,0 +1,497 @@ +// +// Navbars (Redux) +// -------------------------------------------------- + + +// COMMON STYLES +// ------------- + +// Base class and wrapper +.navbar { + overflow: visible; + margin-bottom: @baseLineHeight; + + // Fix for IE7's bad z-indexing so dropdowns don't appear below content that follows the navbar + *position: relative; + *z-index: 2; +} + +// Inner for background effects +// Gradient is applied to its own element because overflow visible is not honored by IE when filter is present +.navbar-inner { + min-height: @navbarHeight; + padding-left: 20px; + padding-right: 20px; + #gradient > .vertical(@navbarBackgroundHighlight, @navbarBackground); + border: 1px solid @navbarBorder; + .border-radius(@baseBorderRadius); + .box-shadow(0 1px 4px rgba(0,0,0,.065)); + + // Prevent floats from breaking the navbar + .clearfix(); +} + +// Set width to auto for default container +// We then reset it for fixed navbars in the #gridSystem mixin +.navbar .container { + width: auto; +} + +// Override the default collapsed state +.nav-collapse.collapse { + height: auto; + overflow: visible; +} + + +// Brand: website or project name +// ------------------------- +.navbar .brand { + float: left; + display: block; + // Vertically center the text given @navbarHeight + padding: ((@navbarHeight - @baseLineHeight) / 2) 20px ((@navbarHeight - @baseLineHeight) / 2); + margin-left: -20px; // negative indent to left-align the text down the page + font-size: 20px; + font-weight: 200; + color: @navbarBrandColor; + text-shadow: 0 1px 0 @navbarBackgroundHighlight; + &:hover, + &:focus { + text-decoration: none; + } +} + +// Plain text in topbar +// ------------------------- +.navbar-text { + margin-bottom: 0; + line-height: @navbarHeight; + color: @navbarText; +} + +// Janky solution for now to account for links outside the .nav +// ------------------------- +.navbar-link { + color: @navbarLinkColor; + &:hover, + &:focus { + color: @navbarLinkColorHover; + } +} + +// Dividers in navbar +// ------------------------- +.navbar .divider-vertical { + height: @navbarHeight; + margin: 0 9px; + border-left: 1px solid @navbarBackground; + border-right: 1px solid @navbarBackgroundHighlight; +} + +// Buttons in navbar +// ------------------------- +.navbar .btn, +.navbar .btn-group { + .navbarVerticalAlign(30px); // Vertically center in navbar +} +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { + margin-top: 0; // then undo the margin here so we don't accidentally double it +} + +// Navbar forms +// ------------------------- +.navbar-form { + margin-bottom: 0; // remove default bottom margin + .clearfix(); + input, + select, + .radio, + .checkbox { + .navbarVerticalAlign(30px); // Vertically center in navbar + } + input, + select, + .btn { + display: inline-block; + margin-bottom: 0; + } + input[type="image"], + input[type="checkbox"], + input[type="radio"] { + margin-top: 3px; + } + .input-append, + .input-prepend { + margin-top: 5px; + white-space: nowrap; // preven two items from separating within a .navbar-form that has .pull-left + input { + margin-top: 0; // remove the margin on top since it's on the parent + } + } +} + +// Navbar search +// ------------------------- +.navbar-search { + position: relative; + float: left; + .navbarVerticalAlign(30px); // Vertically center in navbar + margin-bottom: 0; + .search-query { + margin-bottom: 0; + padding: 4px 14px; + #font > .sans-serif(13px, normal, 1); + .border-radius(15px); // redeclare because of specificity of the type attribute + } +} + + + +// Static navbar +// ------------------------- + +.navbar-static-top { + position: static; + margin-bottom: 0; // remove 18px margin for default navbar + .navbar-inner { + .border-radius(0); + } +} + + + +// Fixed navbar +// ------------------------- + +// Shared (top/bottom) styles +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: @zindexFixedNavbar; + margin-bottom: 0; // remove 18px margin for default navbar +} +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-left: 0; + padding-right: 0; + .border-radius(0); +} + +// Reset container width +// Required here as we reset the width earlier on and the grid mixins don't override early enough +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + #grid > .core > .span(@gridColumns); +} + +// Fixed to top +.navbar-fixed-top { + top: 0; +} +.navbar-fixed-top, +.navbar-static-top { + .navbar-inner { + .box-shadow(~"0 1px 10px rgba(0,0,0,.1)"); + } +} + +// Fixed to bottom +.navbar-fixed-bottom { + bottom: 0; + .navbar-inner { + .box-shadow(~"0 -1px 10px rgba(0,0,0,.1)"); + } +} + + + +// NAVIGATION +// ---------- + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; // redeclare due to specificity + margin-right: 0; // remove margin on float right nav +} +.navbar .nav > li { + float: left; +} + +// Links +.navbar .nav > li > a { + float: none; + // Vertically center the text given @navbarHeight + padding: ((@navbarHeight - @baseLineHeight) / 2) 15px ((@navbarHeight - @baseLineHeight) / 2); + color: @navbarLinkColor; + text-decoration: none; + text-shadow: 0 1px 0 @navbarBackgroundHighlight; +} +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +// Hover/focus +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + background-color: @navbarLinkBackgroundHover; // "transparent" is default to differentiate :hover/:focus from .active + color: @navbarLinkColorHover; + text-decoration: none; +} + +// Active nav items +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: @navbarLinkColorActive; + text-decoration: none; + background-color: @navbarLinkBackgroundActive; + .box-shadow(inset 0 3px 8px rgba(0,0,0,.125)); +} + +// Navbar button for toggling navbar items in responsive layouts +// These definitions need to come after '.navbar .btn' +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + .buttonBackground(darken(@navbarBackgroundHighlight, 5%), darken(@navbarBackground, 5%)); + .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)"); +} +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + .border-radius(1px); + .box-shadow(0 1px 0 rgba(0,0,0,.25)); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + + + +// Dropdown menus +// -------------- + +// Menu position and menu carets +.navbar .nav > li > .dropdown-menu { + &:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: @dropdownBorder; + position: absolute; + top: -7px; + left: 9px; + } + &:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid @dropdownBackground; + position: absolute; + top: -6px; + left: 10px; + } +} +// Menu position and menu caret support for dropups via extra dropup class +.navbar-fixed-bottom .nav > li > .dropdown-menu { + &:before { + border-top: 7px solid #ccc; + border-top-color: @dropdownBorder; + border-bottom: 0; + bottom: -7px; + top: auto; + } + &:after { + border-top: 6px solid @dropdownBackground; + border-bottom: 0; + bottom: -6px; + top: auto; + } +} + +// Caret should match text color on hover/focus +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: @navbarLinkColorHover; + border-bottom-color: @navbarLinkColorHover; +} + +// Remove background color from open dropdown +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + background-color: @navbarLinkBackgroundActive; + color: @navbarLinkColorActive; +} +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: @navbarLinkColor; + border-bottom-color: @navbarLinkColor; +} +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: @navbarLinkColorActive; + border-bottom-color: @navbarLinkColorActive; +} + +// Right aligned menus need alt position +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + left: auto; + right: 0; + &:before { + left: auto; + right: 12px; + } + &:after { + left: auto; + right: 13px; + } + .dropdown-menu { + left: auto; + right: 100%; + margin-left: 0; + margin-right: -1px; + .border-radius(6px 0 6px 6px); + } +} + + +// Inverted navbar +// ------------------------- + +.navbar-inverse { + + .navbar-inner { + #gradient > .vertical(@navbarInverseBackgroundHighlight, @navbarInverseBackground); + border-color: @navbarInverseBorder; + } + + .brand, + .nav > li > a { + color: @navbarInverseLinkColor; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + &:hover, + &:focus { + color: @navbarInverseLinkColorHover; + } + } + + .brand { + color: @navbarInverseBrandColor; + } + + .navbar-text { + color: @navbarInverseText; + } + + .nav > li > a:focus, + .nav > li > a:hover { + background-color: @navbarInverseLinkBackgroundHover; + color: @navbarInverseLinkColorHover; + } + + .nav .active > a, + .nav .active > a:hover, + .nav .active > a:focus { + color: @navbarInverseLinkColorActive; + background-color: @navbarInverseLinkBackgroundActive; + } + + // Inline text links + .navbar-link { + color: @navbarInverseLinkColor; + &:hover, + &:focus { + color: @navbarInverseLinkColorHover; + } + } + + // Dividers in navbar + .divider-vertical { + border-left-color: @navbarInverseBackground; + border-right-color: @navbarInverseBackgroundHighlight; + } + + // Dropdowns + .nav li.dropdown.open > .dropdown-toggle, + .nav li.dropdown.active > .dropdown-toggle, + .nav li.dropdown.open.active > .dropdown-toggle { + background-color: @navbarInverseLinkBackgroundActive; + color: @navbarInverseLinkColorActive; + } + .nav li.dropdown > a:hover .caret, + .nav li.dropdown > a:focus .caret { + border-top-color: @navbarInverseLinkColorActive; + border-bottom-color: @navbarInverseLinkColorActive; + } + .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: @navbarInverseLinkColor; + border-bottom-color: @navbarInverseLinkColor; + } + .nav li.dropdown.open > .dropdown-toggle .caret, + .nav li.dropdown.active > .dropdown-toggle .caret, + .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: @navbarInverseLinkColorActive; + border-bottom-color: @navbarInverseLinkColorActive; + } + + // Navbar search + .navbar-search { + .search-query { + color: @white; + background-color: @navbarInverseSearchBackground; + border-color: @navbarInverseSearchBorder; + .box-shadow(~"inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15)"); + .transition(none); + .placeholder(@navbarInverseSearchPlaceholderColor); + + // Focus states (we use .focused since IE7-8 and down doesn't support :focus) + &:focus, + &.focused { + padding: 5px 15px; + color: @grayDark; + text-shadow: 0 1px 0 @white; + background-color: @navbarInverseSearchBackgroundFocus; + border: 0; + .box-shadow(0 0 3px rgba(0,0,0,.15)); + outline: 0; + } + } + } + + // Navbar collapse button + .btn-navbar { + .buttonBackground(darken(@navbarInverseBackgroundHighlight, 5%), darken(@navbarInverseBackground, 5%)); + } + +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/navs.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/navs.less new file mode 100644 index 0000000..01cd805 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/navs.less @@ -0,0 +1,409 @@ +// +// Navs +// -------------------------------------------------- + + +// BASE CLASS +// ---------- + +.nav { + margin-left: 0; + margin-bottom: @baseLineHeight; + list-style: none; +} + +// Make links block level +.nav > li > a { + display: block; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: @grayLighter; +} + +// Prevent IE8 from misplacing imgs +// See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989 +.nav > li > a > img { + max-width: none; +} + +// Redeclare pull classes because of specifity +.nav > .pull-right { + float: right; +} + +// Nav headers (for dropdowns and lists) +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: @baseLineHeight; + color: @grayLight; + text-shadow: 0 1px 0 rgba(255,255,255,.5); + text-transform: uppercase; +} +// Space them out when they follow another list item (link) +.nav li + .nav-header { + margin-top: 9px; +} + + + +// NAV LIST +// -------- + +.nav-list { + padding-left: 15px; + padding-right: 15px; + margin-bottom: 0; +} +.nav-list > li > a, +.nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255,255,255,.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: @white; + text-shadow: 0 -1px 0 rgba(0,0,0,.2); + background-color: @linkColor; +} +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} +// Dividers (basically an hr) within the dropdown +.nav-list .divider { + .nav-divider(); +} + + + +// TABS AND PILLS +// ------------- + +// Common styles +.nav-tabs, +.nav-pills { + .clearfix(); +} +.nav-tabs > li, +.nav-pills > li { + float: left; +} +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; // keeps the overall height an even number +} + +// TABS +// ---- + +// Give the tabs something to sit on +.nav-tabs { + border-bottom: 1px solid #ddd; +} +// Make the list-items overlay the bottom border +.nav-tabs > li { + margin-bottom: -1px; +} +// Actual tabs (as links) +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: @baseLineHeight; + border: 1px solid transparent; + .border-radius(4px 4px 0 0); + &:hover, + &:focus { + border-color: @grayLighter @grayLighter #ddd; + } +} +// Active state, and it's :hover/:focus to override normal :hover/:focus +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: @gray; + background-color: @bodyBackground; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} + + +// PILLS +// ----- + +// Links rendered as pills +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + .border-radius(5px); +} + +// Active state +.nav-pills > .active > a, +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { + color: @white; + background-color: @linkColor; +} + + + +// STACKED NAV +// ----------- + +// Stacked tabs and pills +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; // no need for the gap between nav items +} + +// Tabs +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + .border-radius(0); +} +.nav-tabs.nav-stacked > li:first-child > a { + .border-top-radius(4px); +} +.nav-tabs.nav-stacked > li:last-child > a { + .border-bottom-radius(4px); +} +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { + border-color: #ddd; + z-index: 2; +} + +// Pills +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; // decrease margin to match sizing of stacked tabs +} + + + +// DROPDOWNS +// --------- + +.nav-tabs .dropdown-menu { + .border-radius(0 0 6px 6px); // remove the top rounded corners here since there is a hard edge above the menu +} +.nav-pills .dropdown-menu { + .border-radius(6px); // make rounded corners match the pills +} + +// Default dropdown links +// ------------------------- +// Make carets use linkColor to start +.nav .dropdown-toggle .caret { + border-top-color: @linkColor; + border-bottom-color: @linkColor; + margin-top: 6px; +} +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: @linkColorHover; + border-bottom-color: @linkColorHover; +} +/* move down carets for tabs */ +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +// Active dropdown links +// ------------------------- +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: @gray; + border-bottom-color: @gray; +} + +// Active:hover/:focus dropdown links +// ------------------------- +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { + cursor: pointer; +} + +// Open dropdowns +// ------------------------- +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { + color: @white; + background-color: @grayLight; + border-color: @grayLight; +} +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { + border-top-color: @white; + border-bottom-color: @white; + .opacity(100); +} + +// Dropdowns in stacked tabs +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: @grayLight; +} + + + +// TABBABLE +// -------- + + +// COMMON STYLES +// ------------- + +// Clear any floats +.tabbable { + .clearfix(); +} +.tab-content { + overflow: auto; // prevent content from running below tabs +} + +// Remove border on bottom, left, right +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +// Show/hide tabbable areas +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} +.tab-content > .active, +.pill-content > .active { + display: block; +} + + +// BOTTOM +// ------ + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below > .nav-tabs > li > a { + .border-radius(0 0 4px 4px); + &:hover, + &:focus { + border-bottom-color: transparent; + border-top-color: #ddd; + } +} +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { + border-color: transparent #ddd #ddd #ddd; +} + +// LEFT & RIGHT +// ------------ + +// Common styles +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +// Tabs on the left +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + .border-radius(4px 0 0 4px); +} +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { + border-color: @grayLighter #ddd @grayLighter @grayLighter; +} +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: @white; +} + +// Tabs on the right +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + .border-radius(0 4px 4px 0); +} +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { + border-color: @grayLighter @grayLighter @grayLighter #ddd; +} +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: @white; +} + + + +// DISABLED STATES +// --------------- + +// Gray out text +.nav > .disabled > a { + color: @grayLight; +} +// Nuke hover/focus effects +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + cursor: default; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/pager.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/pager.less new file mode 100644 index 0000000..1476188 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/pager.less @@ -0,0 +1,43 @@ +// +// Pager pagination +// -------------------------------------------------- + + +.pager { + margin: @baseLineHeight 0; + list-style: none; + text-align: center; + .clearfix(); +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + .border-radius(15px); +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: @grayLight; + background-color: #fff; + cursor: default; +} \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/pagination.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/pagination.less new file mode 100644 index 0000000..a789db2 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/pagination.less @@ -0,0 +1,123 @@ +// +// Pagination (multiple pages) +// -------------------------------------------------- + +// Space out pagination from surrounding content +.pagination { + margin: @baseLineHeight 0; +} + +.pagination ul { + // Allow for text-based alignment + display: inline-block; + .ie7-inline-block(); + // Reset default ul styles + margin-left: 0; + margin-bottom: 0; + // Visuals + .border-radius(@baseBorderRadius); + .box-shadow(0 1px 2px rgba(0,0,0,.05)); +} +.pagination ul > li { + display: inline; // Remove list-style and block-level defaults +} +.pagination ul > li > a, +.pagination ul > li > span { + float: left; // Collapse white-space + padding: 4px 12px; + line-height: @baseLineHeight; + text-decoration: none; + background-color: @paginationBackground; + border: 1px solid @paginationBorder; + border-left-width: 0; +} +.pagination ul > li > a:hover, +.pagination ul > li > a:focus, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: @paginationActiveBackground; +} +.pagination ul > .active > a, +.pagination ul > .active > span { + color: @grayLight; + cursor: default; +} +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: @grayLight; + background-color: transparent; + cursor: default; +} +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + .border-left-radius(@baseBorderRadius); +} +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + .border-right-radius(@baseBorderRadius); +} + + +// Alignment +// -------------------------------------------------- + +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} + + +// Sizing +// -------------------------------------------------- + +// Large +.pagination-large { + ul > li > a, + ul > li > span { + padding: @paddingLarge; + font-size: @fontSizeLarge; + } + ul > li:first-child > a, + ul > li:first-child > span { + .border-left-radius(@borderRadiusLarge); + } + ul > li:last-child > a, + ul > li:last-child > span { + .border-right-radius(@borderRadiusLarge); + } +} + +// Small and mini +.pagination-mini, +.pagination-small { + ul > li:first-child > a, + ul > li:first-child > span { + .border-left-radius(@borderRadiusSmall); + } + ul > li:last-child > a, + ul > li:last-child > span { + .border-right-radius(@borderRadiusSmall); + } +} + +// Small +.pagination-small { + ul > li > a, + ul > li > span { + padding: @paddingSmall; + font-size: @fontSizeSmall; + } +} +// Mini +.pagination-mini { + ul > li > a, + ul > li > span { + padding: @paddingMini; + font-size: @fontSizeMini; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/popovers.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/popovers.less new file mode 100644 index 0000000..aae35c8 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/popovers.less @@ -0,0 +1,133 @@ +// +// Popovers +// -------------------------------------------------- + + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: @zindexPopover; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; // Reset given new insertion method + background-color: @popoverBackground; + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0,0,0,.2); + .border-radius(6px); + .box-shadow(0 5px 10px rgba(0,0,0,.2)); + + // Overrides for proper insertion + white-space: normal; + + // Offset the popover to account for the popover arrow + &.top { margin-top: -10px; } + &.right { margin-left: 10px; } + &.bottom { margin-top: 10px; } + &.left { margin-left: -10px; } +} + +.popover-title { + margin: 0; // reset heading margin + padding: 8px 14px; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: @popoverTitleBackground; + border-bottom: 1px solid darken(@popoverTitleBackground, 5%); + .border-radius(5px 5px 0 0); + + &:empty { + display: none; + } +} + +.popover-content { + padding: 9px 14px; +} + +// Arrows +// +// .arrow is outer, .arrow:after is inner + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover .arrow { + border-width: @popoverArrowOuterWidth; +} +.popover .arrow:after { + border-width: @popoverArrowWidth; + content: ""; +} + +.popover { + &.top .arrow { + left: 50%; + margin-left: -@popoverArrowOuterWidth; + border-bottom-width: 0; + border-top-color: #999; // IE8 fallback + border-top-color: @popoverArrowOuterColor; + bottom: -@popoverArrowOuterWidth; + &:after { + bottom: 1px; + margin-left: -@popoverArrowWidth; + border-bottom-width: 0; + border-top-color: @popoverArrowColor; + } + } + &.right .arrow { + top: 50%; + left: -@popoverArrowOuterWidth; + margin-top: -@popoverArrowOuterWidth; + border-left-width: 0; + border-right-color: #999; // IE8 fallback + border-right-color: @popoverArrowOuterColor; + &:after { + left: 1px; + bottom: -@popoverArrowWidth; + border-left-width: 0; + border-right-color: @popoverArrowColor; + } + } + &.bottom .arrow { + left: 50%; + margin-left: -@popoverArrowOuterWidth; + border-top-width: 0; + border-bottom-color: #999; // IE8 fallback + border-bottom-color: @popoverArrowOuterColor; + top: -@popoverArrowOuterWidth; + &:after { + top: 1px; + margin-left: -@popoverArrowWidth; + border-top-width: 0; + border-bottom-color: @popoverArrowColor; + } + } + + &.left .arrow { + top: 50%; + right: -@popoverArrowOuterWidth; + margin-top: -@popoverArrowOuterWidth; + border-right-width: 0; + border-left-color: #999; // IE8 fallback + border-left-color: @popoverArrowOuterColor; + &:after { + right: 1px; + border-right-width: 0; + border-left-color: @popoverArrowColor; + bottom: -@popoverArrowWidth; + } + } + +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/progress-bars.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/progress-bars.less new file mode 100644 index 0000000..5e0c3dd --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/progress-bars.less @@ -0,0 +1,122 @@ +// +// Progress bars +// -------------------------------------------------- + + +// ANIMATIONS +// ---------- + +// Webkit +@-webkit-keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + +// Firefox +@-moz-keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + +// IE9 +@-ms-keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + +// Opera +@-o-keyframes progress-bar-stripes { + from { background-position: 0 0; } + to { background-position: 40px 0; } +} + +// Spec +@keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + + + +// THE BARS +// -------- + +// Outer container +.progress { + overflow: hidden; + height: @baseLineHeight; + margin-bottom: @baseLineHeight; + #gradient > .vertical(#f5f5f5, #f9f9f9); + .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); + .border-radius(@baseBorderRadius); +} + +// Bar of progress +.progress .bar { + width: 0%; + height: 100%; + color: @white; + float: left; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + #gradient > .vertical(#149bdf, #0480be); + .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); + .box-sizing(border-box); + .transition(width .6s ease); +} +.progress .bar + .bar { + .box-shadow(~"inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)"); +} + +// Striped bars +.progress-striped .bar { + #gradient > .striped(#149bdf); + .background-size(40px 40px); +} + +// Call animation for the active one +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + + + +// COLORS +// ------ + +// Danger (red) +.progress-danger .bar, .progress .bar-danger { + #gradient > .vertical(#ee5f5b, #c43c35); +} +.progress-danger.progress-striped .bar, .progress-striped .bar-danger { + #gradient > .striped(#ee5f5b); +} + +// Success (green) +.progress-success .bar, .progress .bar-success { + #gradient > .vertical(#62c462, #57a957); +} +.progress-success.progress-striped .bar, .progress-striped .bar-success { + #gradient > .striped(#62c462); +} + +// Info (teal) +.progress-info .bar, .progress .bar-info { + #gradient > .vertical(#5bc0de, #339bb9); +} +.progress-info.progress-striped .bar, .progress-striped .bar-info { + #gradient > .striped(#5bc0de); +} + +// Warning (orange) +.progress-warning .bar, .progress .bar-warning { + #gradient > .vertical(lighten(@orange, 15%), @orange); +} +.progress-warning.progress-striped .bar, .progress-striped .bar-warning { + #gradient > .striped(lighten(@orange, 15%)); +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/reset.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/reset.less new file mode 100644 index 0000000..4806bd5 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/reset.less @@ -0,0 +1,216 @@ +// +// Reset CSS +// Adapted from http://github.com/necolas/normalize.css +// -------------------------------------------------- + + +// Display in IE6-9 and FF3 +// ------------------------- + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +// Display block in IE6-9 and FF3 +// ------------------------- + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +// Prevents modern browsers from displaying 'audio' without controls +// ------------------------- + +audio:not([controls]) { + display: none; +} + +// Base settings +// ------------------------- + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +// Focus states +a:focus { + .tab-focus(); +} +// Hover & Active +a:hover, +a:active { + outline: 0; +} + +// Prevents sub and sup affecting line-height in all browsers +// ------------------------- + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} + +// Img border in a's and image quality +// ------------------------- + +img { + /* Responsive images (ensure images don't scale beyond their parents) */ + max-width: 100%; /* Part 1: Set a maxium relative to the parent */ + width: auto\9; /* IE7-8 need help adjusting responsive images */ + height: auto; /* Part 2: Scale the height according to the width, otherwise you get stretching */ + + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +// Prevent max-width from affecting Google Maps +#map_canvas img, +.google-maps img { + max-width: none; +} + +// Forms +// ------------------------- + +// Font size in all browsers, margin changes, misc consistency +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, +input { + *overflow: visible; // Inner spacing ie IE6/7 + line-height: normal; // FF3/4 have !important on line-height in UA stylesheet +} +button::-moz-focus-inner, +input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 + padding: 0; + border: 0; +} +button, +html input[type="button"], // Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; // Corrects inability to style clickable `input` types in iOS. + cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. +} +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. +} +input[type="search"] { // Appearance in Safari/Chrome + .box-sizing(content-box); + -webkit-appearance: textfield; +} +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 +} +textarea { + overflow: auto; // Remove vertical scrollbar in IE6-9 + vertical-align: top; // Readability and alignment cross-browser +} + + +// Printing +// ------------------------- +// Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css + +@media print { + + * { + text-shadow: none !important; + color: #000 !important; // Black prints faster: h5bp.com/s + background: transparent !important; + box-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + // Don't show links for images, or javascript/internal links + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + thead { + display: table-header-group; // h5bp.com/t + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + @page { + margin: 0.5cm; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-1200px-min.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-1200px-min.less new file mode 100644 index 0000000..4f35ba6 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-1200px-min.less @@ -0,0 +1,28 @@ +// +// Responsive: Large desktop and up +// -------------------------------------------------- + + +@media (min-width: 1200px) { + + // Fixed grid + #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200); + + // Fluid grid + #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200); + + // Input grid + #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200); + + // Thumbnails + .thumbnails { + margin-left: -@gridGutterWidth1200; + } + .thumbnails > li { + margin-left: @gridGutterWidth1200; + } + .row-fluid .thumbnails { + margin-left: 0; + } + +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-767px-max.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-767px-max.less new file mode 100644 index 0000000..128f4ce --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-767px-max.less @@ -0,0 +1,193 @@ +// +// Responsive: Landscape phone to desktop/tablet +// -------------------------------------------------- + + +@media (max-width: 767px) { + + // Padding to set content in a bit + body { + padding-left: 20px; + padding-right: 20px; + } + // Negative indent the now static "fixed" navbar + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { + margin-left: -20px; + margin-right: -20px; + } + // Remove padding on container given explicit padding set on body + .container-fluid { + padding: 0; + } + + // TYPOGRAPHY + // ---------- + // Reset horizontal dl + .dl-horizontal { + dt { + float: none; + clear: none; + width: auto; + text-align: left; + } + dd { + margin-left: 0; + } + } + + // GRID & CONTAINERS + // ----------------- + // Remove width from containers + .container { + width: auto; + } + // Fluid rows + .row-fluid { + width: 100%; + } + // Undo negative margin on rows and thumbnails + .row, + .thumbnails { + margin-left: 0; + } + .thumbnails > li { + float: none; + margin-left: 0; // Reset the default margin for all li elements when no .span* classes are present + } + // Make all grid-sized elements block level again + [class*="span"], + .uneditable-input[class*="span"], // Makes uneditable inputs full-width when using grid sizing + .row-fluid [class*="span"] { + float: none; + display: block; + width: 100%; + margin-left: 0; + .box-sizing(border-box); + } + .span12, + .row-fluid .span12 { + width: 100%; + .box-sizing(border-box); + } + .row-fluid [class*="offset"]:first-child { + margin-left: 0; + } + + // FORM FIELDS + // ----------- + // Make span* classes full width + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + .input-block-level(); + } + // But don't let it screw up prepend/append inputs + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; // redeclare so they don't wrap to new lines + width: auto; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } + + // Modals + .modal { + position: fixed; + top: 20px; + left: 20px; + right: 20px; + width: auto; + margin: 0; + &.fade { top: -100px; } + &.fade.in { top: 20px; } + } + +} + + + +// UP TO LANDSCAPE PHONE +// --------------------- + +@media (max-width: 480px) { + + // Smooth out the collapsing/expanding nav + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); // activate the GPU + } + + // Block level the page header small tag for readability + .page-header h1 small { + display: block; + line-height: @baseLineHeight; + } + + // Update checkboxes for iOS + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + + // Remove the horizontal form styles + .form-horizontal { + .control-label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + // Move over all input controls and content + .controls { + margin-left: 0; + } + // Move the options list down to align with labels + .control-list { + padding-top: 0; // has to be padding because margin collaspes + } + // Move over buttons in .form-actions to align with .controls + .form-actions { + padding-left: 10px; + padding-right: 10px; + } + } + + // Medias + // Reset float and spacing to stack + .media .pull-left, + .media .pull-right { + float: none; + display: block; + margin-bottom: 10px; + } + // Remove side margins since we stack instead of indent + .media-object { + margin-right: 0; + margin-left: 0; + } + + // Modals + .modal { + top: 10px; + left: 10px; + right: 10px; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + + // Carousel + .carousel-caption { + position: static; + } + +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-768px-979px.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-768px-979px.less new file mode 100644 index 0000000..8e8c486 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-768px-979px.less @@ -0,0 +1,19 @@ +// +// Responsive: Tablet to desktop +// -------------------------------------------------- + + +@media (min-width: 768px) and (max-width: 979px) { + + // Fixed grid + #grid > .core(@gridColumnWidth768, @gridGutterWidth768); + + // Fluid grid + #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768); + + // Input grid + #grid > .input(@gridColumnWidth768, @gridGutterWidth768); + + // No need to reset .thumbnails here since it's the same @gridGutterWidth + +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-navbar.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-navbar.less new file mode 100644 index 0000000..21cd3ba --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-navbar.less @@ -0,0 +1,189 @@ +// +// Responsive: Navbar +// -------------------------------------------------- + + +// TABLETS AND BELOW +// ----------------- +@media (max-width: @navbarCollapseWidth) { + + // UNFIX THE TOPBAR + // ---------------- + // Remove any padding from the body + body { + padding-top: 0; + } + // Unfix the navbars + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: @baseLineHeight; + } + .navbar-fixed-bottom { + margin-top: @baseLineHeight; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + // Account for brand name + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + + // COLLAPSIBLE NAVBAR + // ------------------ + // Nav collapse clears brand + .nav-collapse { + clear: both; + } + // Block-level the nav + .nav-collapse .nav { + float: none; + margin: 0 0 (@baseLineHeight / 2); + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: @navbarText; + text-shadow: none; + } + // Nav and dropdown links in navbar + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: @navbarLinkColor; + .border-radius(3px); + } + // Buttons + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + .border-radius(@baseBorderRadius); + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .nav > li > a:focus, + .nav-collapse .dropdown-menu a:hover, + .nav-collapse .dropdown-menu a:focus { + background-color: @navbarBackground; + } + .navbar-inverse .nav-collapse .nav > li > a, + .navbar-inverse .nav-collapse .dropdown-menu a { + color: @navbarInverseLinkColor; + } + .navbar-inverse .nav-collapse .nav > li > a:hover, + .navbar-inverse .nav-collapse .nav > li > a:focus, + .navbar-inverse .nav-collapse .dropdown-menu a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:focus { + background-color: @navbarInverseBackground; + } + // Buttons in the navbar + .nav-collapse.in .btn-group { + margin-top: 5px; + padding: 0; + } + // Dropdowns in the navbar + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: none; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + .border-radius(0); + .box-shadow(none); + } + .nav-collapse .open > .dropdown-menu { + display: block; + } + + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .nav > li > .dropdown-menu { + &:before, + &:after { + display: none; + } + } + // Forms in navbar + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: (@baseLineHeight / 2) 15px; + margin: (@baseLineHeight / 2) 0; + border-top: 1px solid @navbarBackground; + border-bottom: 1px solid @navbarBackground; + .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)"); + } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: @navbarInverseBackground; + border-bottom-color: @navbarInverseBackground; + } + // Pull right (secondary) nav content + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + // Hide everything in the navbar save .brand and toggle button */ + .nav-collapse, + .nav-collapse.collapse { + overflow: hidden; + height: 0; + } + // Navbar button + .navbar .btn-navbar { + display: block; + } + + // STATIC NAVBAR + // ------------- + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + + +} + + +// DEFAULT DESKTOP +// --------------- + +@media (min-width: @navbarCollapseDesktopWidth) { + + // Required to make the collapsing navbar work on regular desktops + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } + +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-utilities.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-utilities.less new file mode 100644 index 0000000..bf43e8e --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive-utilities.less @@ -0,0 +1,59 @@ +// +// Responsive: Utility classes +// -------------------------------------------------- + + +// IE10 Metro responsive +// Required for Windows 8 Metro split-screen snapping with IE10 +// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/ +@-ms-viewport{ + width: device-width; +} + +// Hide from screenreaders and browsers +// Credit: HTML5 Boilerplate +.hidden { + display: none; + visibility: hidden; +} + +// Visibility utilities + +// For desktops +.visible-phone { display: none !important; } +.visible-tablet { display: none !important; } +.hidden-phone { } +.hidden-tablet { } +.hidden-desktop { display: none !important; } +.visible-desktop { display: inherit !important; } + +// Tablets & small desktops only +@media (min-width: 768px) and (max-width: 979px) { + // Hide everything else + .hidden-desktop { display: inherit !important; } + .visible-desktop { display: none !important ; } + // Show + .visible-tablet { display: inherit !important; } + // Hide + .hidden-tablet { display: none !important; } +} + +// Phones only +@media (max-width: 767px) { + // Hide everything else + .hidden-desktop { display: inherit !important; } + .visible-desktop { display: none !important; } + // Show + .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior + // Hide + .hidden-phone { display: none !important; } +} + +// Print utilities +.visible-print { display: none !important; } +.hidden-print { } + +@media print { + .visible-print { display: inherit !important; } + .hidden-print { display: none !important; } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive.less new file mode 100644 index 0000000..b8366de --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/responsive.less @@ -0,0 +1,48 @@ +/*! + * Bootstrap Responsive v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + + +// Responsive.less +// For phone and tablet devices +// ------------------------------------------------------------- + + +// REPEAT VARIABLES & MIXINS +// ------------------------- +// Required since we compile the responsive stuff separately + +@import "variables.less"; // Modify this for custom colors, font-sizes, etc +@import "mixins.less"; + + +// RESPONSIVE CLASSES +// ------------------ + +@import "responsive-utilities.less"; + + +// MEDIA QUERIES +// ------------------ + +// Large desktops +@import "responsive-1200px-min.less"; + +// Tablets to regular desktops +@import "responsive-768px-979px.less"; + +// Phones to portrait tablets and narrow desktops +@import "responsive-767px-max.less"; + + +// RESPONSIVE NAVBAR +// ------------------ + +// From 979px and below, show a button to toggle navbar contents +@import "responsive-navbar.less"; diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/scaffolding.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/scaffolding.less new file mode 100644 index 0000000..f17e8ca --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/scaffolding.less @@ -0,0 +1,53 @@ +// +// Scaffolding +// -------------------------------------------------- + + +// Body reset +// ------------------------- + +body { + margin: 0; + font-family: @baseFontFamily; + font-size: @baseFontSize; + line-height: @baseLineHeight; + color: @textColor; + background-color: @bodyBackground; +} + + +// Links +// ------------------------- + +a { + color: @linkColor; + text-decoration: none; +} +a:hover, +a:focus { + color: @linkColorHover; + text-decoration: underline; +} + + +// Images +// ------------------------- + +// Rounded corners +.img-rounded { + .border-radius(6px); +} + +// Add polaroid-esque trim +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0,0,0,.2); + .box-shadow(0 1px 3px rgba(0,0,0,.1)); +} + +// Perfect circle +.img-circle { + .border-radius(500px); // crank the border-radius so it works with most reasonably sized images +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/sprites.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/sprites.less new file mode 100644 index 0000000..1812bf7 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/sprites.less @@ -0,0 +1,197 @@ +// +// Sprites +// -------------------------------------------------- + + +// ICONS +// ----- + +// All icons receive the styles of the tag with a base class +// of .i and are then given a unique class to add width, height, +// and background-position. Your resulting HTML will look like +// . + +// For the white version of the icons, just add the .icon-white class: +// + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + .ie7-restore-right-whitespace(); + line-height: 14px; + vertical-align: text-top; + background-image: url("@{iconSpritePath}"); + background-position: 14px 14px; + background-repeat: no-repeat; + margin-top: 1px; +} + +/* White icons with optional class, or on hover/focus/active states of certain elements */ +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:focus > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { + background-image: url("@{iconWhiteSpritePath}"); +} + +.icon-glass { background-position: 0 0; } +.icon-music { background-position: -24px 0; } +.icon-search { background-position: -48px 0; } +.icon-envelope { background-position: -72px 0; } +.icon-heart { background-position: -96px 0; } +.icon-star { background-position: -120px 0; } +.icon-star-empty { background-position: -144px 0; } +.icon-user { background-position: -168px 0; } +.icon-film { background-position: -192px 0; } +.icon-th-large { background-position: -216px 0; } +.icon-th { background-position: -240px 0; } +.icon-th-list { background-position: -264px 0; } +.icon-ok { background-position: -288px 0; } +.icon-remove { background-position: -312px 0; } +.icon-zoom-in { background-position: -336px 0; } +.icon-zoom-out { background-position: -360px 0; } +.icon-off { background-position: -384px 0; } +.icon-signal { background-position: -408px 0; } +.icon-cog { background-position: -432px 0; } +.icon-trash { background-position: -456px 0; } + +.icon-home { background-position: 0 -24px; } +.icon-file { background-position: -24px -24px; } +.icon-time { background-position: -48px -24px; } +.icon-road { background-position: -72px -24px; } +.icon-download-alt { background-position: -96px -24px; } +.icon-download { background-position: -120px -24px; } +.icon-upload { background-position: -144px -24px; } +.icon-inbox { background-position: -168px -24px; } +.icon-play-circle { background-position: -192px -24px; } +.icon-repeat { background-position: -216px -24px; } +.icon-refresh { background-position: -240px -24px; } +.icon-list-alt { background-position: -264px -24px; } +.icon-lock { background-position: -287px -24px; } // 1px off +.icon-flag { background-position: -312px -24px; } +.icon-headphones { background-position: -336px -24px; } +.icon-volume-off { background-position: -360px -24px; } +.icon-volume-down { background-position: -384px -24px; } +.icon-volume-up { background-position: -408px -24px; } +.icon-qrcode { background-position: -432px -24px; } +.icon-barcode { background-position: -456px -24px; } + +.icon-tag { background-position: 0 -48px; } +.icon-tags { background-position: -25px -48px; } // 1px off +.icon-book { background-position: -48px -48px; } +.icon-bookmark { background-position: -72px -48px; } +.icon-print { background-position: -96px -48px; } +.icon-camera { background-position: -120px -48px; } +.icon-font { background-position: -144px -48px; } +.icon-bold { background-position: -167px -48px; } // 1px off +.icon-italic { background-position: -192px -48px; } +.icon-text-height { background-position: -216px -48px; } +.icon-text-width { background-position: -240px -48px; } +.icon-align-left { background-position: -264px -48px; } +.icon-align-center { background-position: -288px -48px; } +.icon-align-right { background-position: -312px -48px; } +.icon-align-justify { background-position: -336px -48px; } +.icon-list { background-position: -360px -48px; } +.icon-indent-left { background-position: -384px -48px; } +.icon-indent-right { background-position: -408px -48px; } +.icon-facetime-video { background-position: -432px -48px; } +.icon-picture { background-position: -456px -48px; } + +.icon-pencil { background-position: 0 -72px; } +.icon-map-marker { background-position: -24px -72px; } +.icon-adjust { background-position: -48px -72px; } +.icon-tint { background-position: -72px -72px; } +.icon-edit { background-position: -96px -72px; } +.icon-share { background-position: -120px -72px; } +.icon-check { background-position: -144px -72px; } +.icon-move { background-position: -168px -72px; } +.icon-step-backward { background-position: -192px -72px; } +.icon-fast-backward { background-position: -216px -72px; } +.icon-backward { background-position: -240px -72px; } +.icon-play { background-position: -264px -72px; } +.icon-pause { background-position: -288px -72px; } +.icon-stop { background-position: -312px -72px; } +.icon-forward { background-position: -336px -72px; } +.icon-fast-forward { background-position: -360px -72px; } +.icon-step-forward { background-position: -384px -72px; } +.icon-eject { background-position: -408px -72px; } +.icon-chevron-left { background-position: -432px -72px; } +.icon-chevron-right { background-position: -456px -72px; } + +.icon-plus-sign { background-position: 0 -96px; } +.icon-minus-sign { background-position: -24px -96px; } +.icon-remove-sign { background-position: -48px -96px; } +.icon-ok-sign { background-position: -72px -96px; } +.icon-question-sign { background-position: -96px -96px; } +.icon-info-sign { background-position: -120px -96px; } +.icon-screenshot { background-position: -144px -96px; } +.icon-remove-circle { background-position: -168px -96px; } +.icon-ok-circle { background-position: -192px -96px; } +.icon-ban-circle { background-position: -216px -96px; } +.icon-arrow-left { background-position: -240px -96px; } +.icon-arrow-right { background-position: -264px -96px; } +.icon-arrow-up { background-position: -289px -96px; } // 1px off +.icon-arrow-down { background-position: -312px -96px; } +.icon-share-alt { background-position: -336px -96px; } +.icon-resize-full { background-position: -360px -96px; } +.icon-resize-small { background-position: -384px -96px; } +.icon-plus { background-position: -408px -96px; } +.icon-minus { background-position: -433px -96px; } +.icon-asterisk { background-position: -456px -96px; } + +.icon-exclamation-sign { background-position: 0 -120px; } +.icon-gift { background-position: -24px -120px; } +.icon-leaf { background-position: -48px -120px; } +.icon-fire { background-position: -72px -120px; } +.icon-eye-open { background-position: -96px -120px; } +.icon-eye-close { background-position: -120px -120px; } +.icon-warning-sign { background-position: -144px -120px; } +.icon-plane { background-position: -168px -120px; } +.icon-calendar { background-position: -192px -120px; } +.icon-random { background-position: -216px -120px; width: 16px; } +.icon-comment { background-position: -240px -120px; } +.icon-magnet { background-position: -264px -120px; } +.icon-chevron-up { background-position: -288px -120px; } +.icon-chevron-down { background-position: -313px -119px; } // 1px, 1px off +.icon-retweet { background-position: -336px -120px; } +.icon-shopping-cart { background-position: -360px -120px; } +.icon-folder-close { background-position: -384px -120px; width: 16px; } +.icon-folder-open { background-position: -408px -120px; width: 16px; } +.icon-resize-vertical { background-position: -432px -119px; } // 1px, 1px off +.icon-resize-horizontal { background-position: -456px -118px; } // 1px, 2px off + +.icon-hdd { background-position: 0 -144px; } +.icon-bullhorn { background-position: -24px -144px; } +.icon-bell { background-position: -48px -144px; } +.icon-certificate { background-position: -72px -144px; } +.icon-thumbs-up { background-position: -96px -144px; } +.icon-thumbs-down { background-position: -120px -144px; } +.icon-hand-right { background-position: -144px -144px; } +.icon-hand-left { background-position: -168px -144px; } +.icon-hand-up { background-position: -192px -144px; } +.icon-hand-down { background-position: -216px -144px; } +.icon-circle-arrow-right { background-position: -240px -144px; } +.icon-circle-arrow-left { background-position: -264px -144px; } +.icon-circle-arrow-up { background-position: -288px -144px; } +.icon-circle-arrow-down { background-position: -312px -144px; } +.icon-globe { background-position: -336px -144px; } +.icon-wrench { background-position: -360px -144px; } +.icon-tasks { background-position: -384px -144px; } +.icon-filter { background-position: -408px -144px; } +.icon-briefcase { background-position: -432px -144px; } +.icon-fullscreen { background-position: -456px -144px; } diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/tables.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/tables.less new file mode 100644 index 0000000..0e35271 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/tables.less @@ -0,0 +1,244 @@ +// +// Tables +// -------------------------------------------------- + + +// BASE TABLES +// ----------------- + +table { + max-width: 100%; + background-color: @tableBackground; + border-collapse: collapse; + border-spacing: 0; +} + +// BASELINE STYLES +// --------------- + +.table { + width: 100%; + margin-bottom: @baseLineHeight; + // Cells + th, + td { + padding: 8px; + line-height: @baseLineHeight; + text-align: left; + vertical-align: top; + border-top: 1px solid @tableBorder; + } + th { + font-weight: bold; + } + // Bottom align for column headings + thead th { + vertical-align: bottom; + } + // Remove top border from thead by default + caption + thead tr:first-child th, + caption + thead tr:first-child td, + colgroup + thead tr:first-child th, + colgroup + thead tr:first-child td, + thead:first-child tr:first-child th, + thead:first-child tr:first-child td { + border-top: 0; + } + // Account for multiple tbody instances + tbody + tbody { + border-top: 2px solid @tableBorder; + } + + // Nesting + .table { + background-color: @bodyBackground; + } +} + + + +// CONDENSED TABLE W/ HALF PADDING +// ------------------------------- + +.table-condensed { + th, + td { + padding: 4px 5px; + } +} + + +// BORDERED VERSION +// ---------------- + +.table-bordered { + border: 1px solid @tableBorder; + border-collapse: separate; // Done so we can round those corners! + *border-collapse: collapse; // IE7 can't round corners anyway + border-left: 0; + .border-radius(@baseBorderRadius); + th, + td { + border-left: 1px solid @tableBorder; + } + // Prevent a double border + caption + thead tr:first-child th, + caption + tbody tr:first-child th, + caption + tbody tr:first-child td, + colgroup + thead tr:first-child th, + colgroup + tbody tr:first-child th, + colgroup + tbody tr:first-child td, + thead:first-child tr:first-child th, + tbody:first-child tr:first-child th, + tbody:first-child tr:first-child td { + border-top: 0; + } + // For first th/td in the first row in the first thead or tbody + thead:first-child tr:first-child > th:first-child, + tbody:first-child tr:first-child > td:first-child, + tbody:first-child tr:first-child > th:first-child { + .border-top-left-radius(@baseBorderRadius); + } + // For last th/td in the first row in the first thead or tbody + thead:first-child tr:first-child > th:last-child, + tbody:first-child tr:first-child > td:last-child, + tbody:first-child tr:first-child > th:last-child { + .border-top-right-radius(@baseBorderRadius); + } + // For first th/td (can be either) in the last row in the last thead, tbody, and tfoot + thead:last-child tr:last-child > th:first-child, + tbody:last-child tr:last-child > td:first-child, + tbody:last-child tr:last-child > th:first-child, + tfoot:last-child tr:last-child > td:first-child, + tfoot:last-child tr:last-child > th:first-child { + .border-bottom-left-radius(@baseBorderRadius); + } + // For last th/td (can be either) in the last row in the last thead, tbody, and tfoot + thead:last-child tr:last-child > th:last-child, + tbody:last-child tr:last-child > td:last-child, + tbody:last-child tr:last-child > th:last-child, + tfoot:last-child tr:last-child > td:last-child, + tfoot:last-child tr:last-child > th:last-child { + .border-bottom-right-radius(@baseBorderRadius); + } + + // Clear border-radius for first and last td in the last row in the last tbody for table with tfoot + tfoot + tbody:last-child tr:last-child td:first-child { + .border-bottom-left-radius(0); + } + tfoot + tbody:last-child tr:last-child td:last-child { + .border-bottom-right-radius(0); + } + + // Special fixes to round the left border on the first td/th + caption + thead tr:first-child th:first-child, + caption + tbody tr:first-child td:first-child, + colgroup + thead tr:first-child th:first-child, + colgroup + tbody tr:first-child td:first-child { + .border-top-left-radius(@baseBorderRadius); + } + caption + thead tr:first-child th:last-child, + caption + tbody tr:first-child td:last-child, + colgroup + thead tr:first-child th:last-child, + colgroup + tbody tr:first-child td:last-child { + .border-top-right-radius(@baseBorderRadius); + } + +} + + + + +// ZEBRA-STRIPING +// -------------- + +// Default zebra-stripe styles (alternating gray and transparent backgrounds) +.table-striped { + tbody { + > tr:nth-child(odd) > td, + > tr:nth-child(odd) > th { + background-color: @tableBackgroundAccent; + } + } +} + + +// HOVER EFFECT +// ------------ +// Placed here since it has to come after the potential zebra striping +.table-hover { + tbody { + tr:hover > td, + tr:hover > th { + background-color: @tableBackgroundHover; + } + } +} + + +// TABLE CELL SIZING +// ----------------- + +// Reset default grid behavior +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; // undo default grid column styles + margin-left: 0; // undo default grid column styles +} + +// Change the column widths to account for td/th padding +.table td, +.table th { + &.span1 { .tableColumns(1); } + &.span2 { .tableColumns(2); } + &.span3 { .tableColumns(3); } + &.span4 { .tableColumns(4); } + &.span5 { .tableColumns(5); } + &.span6 { .tableColumns(6); } + &.span7 { .tableColumns(7); } + &.span8 { .tableColumns(8); } + &.span9 { .tableColumns(9); } + &.span10 { .tableColumns(10); } + &.span11 { .tableColumns(11); } + &.span12 { .tableColumns(12); } +} + + + +// TABLE BACKGROUNDS +// ----------------- +// Exact selectors below required to override .table-striped + +.table tbody tr { + &.success > td { + background-color: @successBackground; + } + &.error > td { + background-color: @errorBackground; + } + &.warning > td { + background-color: @warningBackground; + } + &.info > td { + background-color: @infoBackground; + } +} + +// Hover states for .table-hover +.table-hover tbody tr { + &.success:hover > td { + background-color: darken(@successBackground, 5%); + } + &.error:hover > td { + background-color: darken(@errorBackground, 5%); + } + &.warning:hover > td { + background-color: darken(@warningBackground, 5%); + } + &.info:hover > td { + background-color: darken(@infoBackground, 5%); + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/thumbnails.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/thumbnails.less new file mode 100644 index 0000000..4fd07d2 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/thumbnails.less @@ -0,0 +1,53 @@ +// +// Thumbnails +// -------------------------------------------------- + + +// Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files + +// Make wrapper ul behave like the grid +.thumbnails { + margin-left: -@gridGutterWidth; + list-style: none; + .clearfix(); +} +// Fluid rows have no left margin +.row-fluid .thumbnails { + margin-left: 0; +} + +// Float li to make thumbnails appear in a row +.thumbnails > li { + float: left; // Explicity set the float since we don't require .span* classes + margin-bottom: @baseLineHeight; + margin-left: @gridGutterWidth; +} + +// The actual thumbnail (can be `a` or `div`) +.thumbnail { + display: block; + padding: 4px; + line-height: @baseLineHeight; + border: 1px solid #ddd; + .border-radius(@baseBorderRadius); + .box-shadow(0 1px 3px rgba(0,0,0,.055)); + .transition(all .2s ease-in-out); +} +// Add a hover/focus state for linked versions only +a.thumbnail:hover, +a.thumbnail:focus { + border-color: @linkColor; + .box-shadow(0 1px 4px rgba(0,105,214,.25)); +} + +// Images and captions +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; + color: @gray; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/tooltip.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/tooltip.less new file mode 100644 index 0000000..83d5f2b --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/tooltip.less @@ -0,0 +1,70 @@ +// +// Tooltips +// -------------------------------------------------- + + +// Base class +.tooltip { + position: absolute; + z-index: @zindexTooltip; + display: block; + visibility: visible; + font-size: 11px; + line-height: 1.4; + .opacity(0); + &.in { .opacity(80); } + &.top { margin-top: -3px; padding: 5px 0; } + &.right { margin-left: 3px; padding: 0 5px; } + &.bottom { margin-top: 3px; padding: 5px 0; } + &.left { margin-left: -3px; padding: 0 5px; } +} + +// Wrapper for the tooltip content +.tooltip-inner { + max-width: 200px; + padding: 8px; + color: @tooltipColor; + text-align: center; + text-decoration: none; + background-color: @tooltipBackground; + .border-radius(@baseBorderRadius); +} + +// Arrows +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip { + &.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -@tooltipArrowWidth; + border-width: @tooltipArrowWidth @tooltipArrowWidth 0; + border-top-color: @tooltipArrowColor; + } + &.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -@tooltipArrowWidth; + border-width: @tooltipArrowWidth @tooltipArrowWidth @tooltipArrowWidth 0; + border-right-color: @tooltipArrowColor; + } + &.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -@tooltipArrowWidth; + border-width: @tooltipArrowWidth 0 @tooltipArrowWidth @tooltipArrowWidth; + border-left-color: @tooltipArrowColor; + } + &.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -@tooltipArrowWidth; + border-width: 0 @tooltipArrowWidth @tooltipArrowWidth; + border-bottom-color: @tooltipArrowColor; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/type.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/type.less new file mode 100644 index 0000000..337138a --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/type.less @@ -0,0 +1,247 @@ +// +// Typography +// -------------------------------------------------- + + +// Body text +// ------------------------- + +p { + margin: 0 0 @baseLineHeight / 2; +} +.lead { + margin-bottom: @baseLineHeight; + font-size: @baseFontSize * 1.5; + font-weight: 200; + line-height: @baseLineHeight * 1.5; +} + + +// Emphasis & misc +// ------------------------- + +// Ex: 14px base font * 85% = about 12px +small { font-size: 85%; } + +strong { font-weight: bold; } +em { font-style: italic; } +cite { font-style: normal; } + +// Utility classes +.muted { color: @grayLight; } +a.muted:hover, +a.muted:focus { color: darken(@grayLight, 10%); } + +.text-warning { color: @warningText; } +a.text-warning:hover, +a.text-warning:focus { color: darken(@warningText, 10%); } + +.text-error { color: @errorText; } +a.text-error:hover, +a.text-error:focus { color: darken(@errorText, 10%); } + +.text-info { color: @infoText; } +a.text-info:hover, +a.text-info:focus { color: darken(@infoText, 10%); } + +.text-success { color: @successText; } +a.text-success:hover, +a.text-success:focus { color: darken(@successText, 10%); } + +.text-left { text-align: left; } +.text-right { text-align: right; } +.text-center { text-align: center; } + + +// Headings +// ------------------------- + +h1, h2, h3, h4, h5, h6 { + margin: (@baseLineHeight / 2) 0; + font-family: @headingsFontFamily; + font-weight: @headingsFontWeight; + line-height: @baseLineHeight; + color: @headingsColor; + text-rendering: optimizelegibility; // Fix the character spacing for headings + small { + font-weight: normal; + line-height: 1; + color: @grayLight; + } +} + +h1, +h2, +h3 { line-height: @baseLineHeight * 2; } + +h1 { font-size: @baseFontSize * 2.75; } // ~38px +h2 { font-size: @baseFontSize * 2.25; } // ~32px +h3 { font-size: @baseFontSize * 1.75; } // ~24px +h4 { font-size: @baseFontSize * 1.25; } // ~18px +h5 { font-size: @baseFontSize; } +h6 { font-size: @baseFontSize * 0.85; } // ~12px + +h1 small { font-size: @baseFontSize * 1.75; } // ~24px +h2 small { font-size: @baseFontSize * 1.25; } // ~18px +h3 small { font-size: @baseFontSize; } +h4 small { font-size: @baseFontSize; } + + +// Page header +// ------------------------- + +.page-header { + padding-bottom: (@baseLineHeight / 2) - 1; + margin: @baseLineHeight 0 (@baseLineHeight * 1.5); + border-bottom: 1px solid @grayLighter; +} + + + +// Lists +// -------------------------------------------------- + +// Unordered and Ordered lists +ul, ol { + padding: 0; + margin: 0 0 @baseLineHeight / 2 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +li { + line-height: @baseLineHeight; +} + +// Remove default list styles +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +// Single-line list items +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; + > li { + display: inline-block; + .ie7-inline-block(); + padding-left: 5px; + padding-right: 5px; + } +} + +// Description Lists +dl { + margin-bottom: @baseLineHeight; +} +dt, +dd { + line-height: @baseLineHeight; +} +dt { + font-weight: bold; +} +dd { + margin-left: @baseLineHeight / 2; +} +// Horizontal layout (like forms) +.dl-horizontal { + .clearfix(); // Ensure dl clears floats if empty dd elements present + dt { + float: left; + width: @horizontalComponentOffset - 20; + clear: left; + text-align: right; + .text-overflow(); + } + dd { + margin-left: @horizontalComponentOffset; + } +} + +// MISC +// ---- + +// Horizontal rules +hr { + margin: @baseLineHeight 0; + border: 0; + border-top: 1px solid @hrBorder; + border-bottom: 1px solid @white; +} + +// Abbreviations and acronyms +abbr[title], +// Added data-* attribute to help out our tooltip plugin, per https://github.com/twitter/bootstrap/issues/5257 +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted @grayLight; +} +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +// Blockquotes +blockquote { + padding: 0 0 0 15px; + margin: 0 0 @baseLineHeight; + border-left: 5px solid @grayLighter; + p { + margin-bottom: 0; + font-size: @baseFontSize * 1.25; + font-weight: 300; + line-height: 1.25; + } + small { + display: block; + line-height: @baseLineHeight; + color: @grayLight; + &:before { + content: '\2014 \00A0'; + } + } + + // Float right with text-align: right + &.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid @grayLighter; + border-left: 0; + p, + small { + text-align: right; + } + small { + &:before { + content: ''; + } + &:after { + content: '\00A0 \2014'; + } + } + } +} + +// Quotes +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +// Addresses +address { + display: block; + margin-bottom: @baseLineHeight; + font-style: normal; + line-height: @baseLineHeight; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/utilities.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/utilities.less new file mode 100644 index 0000000..314b4ff --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/utilities.less @@ -0,0 +1,30 @@ +// +// Utility classes +// -------------------------------------------------- + + +// Quick floats +.pull-right { + float: right; +} +.pull-left { + float: left; +} + +// Toggling content +.hide { + display: none; +} +.show { + display: block; +} + +// Visibility +.invisible { + visibility: hidden; +} + +// For Affix plugin +.affix { + position: fixed; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/variables.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/variables.less new file mode 100644 index 0000000..31c131b --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/variables.less @@ -0,0 +1,301 @@ +// +// Variables +// -------------------------------------------------- + + +// Global values +// -------------------------------------------------- + + +// Grays +// ------------------------- +@black: #000; +@grayDarker: #222; +@grayDark: #333; +@gray: #555; +@grayLight: #999; +@grayLighter: #eee; +@white: #fff; + + +// Accent colors +// ------------------------- +@blue: #049cdb; +@blueDark: #0064cd; +@green: #46a546; +@red: #9d261d; +@yellow: #ffc40d; +@orange: #f89406; +@pink: #c3325f; +@purple: #7a43b6; + + +// Scaffolding +// ------------------------- +@bodyBackground: @white; +@textColor: @grayDark; + + +// Links +// ------------------------- +@linkColor: #08c; +@linkColorHover: darken(@linkColor, 15%); + + +// Typography +// ------------------------- +@sansFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif; +@serifFontFamily: Georgia, "Times New Roman", Times, serif; +@monoFontFamily: Monaco, Menlo, Consolas, "Courier New", monospace; + +@baseFontSize: 14px; +@baseFontFamily: @sansFontFamily; +@baseLineHeight: 20px; +@altFontFamily: @serifFontFamily; + +@headingsFontFamily: inherit; // empty to use BS default, @baseFontFamily +@headingsFontWeight: bold; // instead of browser default, bold +@headingsColor: inherit; // empty to use BS default, @textColor + + +// Component sizing +// ------------------------- +// Based on 14px font-size and 20px line-height + +@fontSizeLarge: @baseFontSize * 1.25; // ~18px +@fontSizeSmall: @baseFontSize * 0.85; // ~12px +@fontSizeMini: @baseFontSize * 0.75; // ~11px + +@paddingLarge: 11px 19px; // 44px +@paddingSmall: 2px 10px; // 26px +@paddingMini: 0 6px; // 22px + +@baseBorderRadius: 4px; +@borderRadiusLarge: 6px; +@borderRadiusSmall: 3px; + + +// Tables +// ------------------------- +@tableBackground: transparent; // overall background-color +@tableBackgroundAccent: #f9f9f9; // for striping +@tableBackgroundHover: #f5f5f5; // for hover +@tableBorder: #ddd; // table and cell border + +// Buttons +// ------------------------- +@btnBackground: @white; +@btnBackgroundHighlight: darken(@white, 10%); +@btnBorder: #ccc; + +@btnPrimaryBackground: @linkColor; +@btnPrimaryBackgroundHighlight: spin(@btnPrimaryBackground, 20%); + +@btnInfoBackground: #5bc0de; +@btnInfoBackgroundHighlight: #2f96b4; + +@btnSuccessBackground: #62c462; +@btnSuccessBackgroundHighlight: #51a351; + +@btnWarningBackground: lighten(@orange, 15%); +@btnWarningBackgroundHighlight: @orange; + +@btnDangerBackground: #ee5f5b; +@btnDangerBackgroundHighlight: #bd362f; + +@btnInverseBackground: #444; +@btnInverseBackgroundHighlight: @grayDarker; + + +// Forms +// ------------------------- +@inputBackground: @white; +@inputBorder: #ccc; +@inputBorderRadius: @baseBorderRadius; +@inputDisabledBackground: @grayLighter; +@formActionsBackground: #f5f5f5; +@inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border + + +// Dropdowns +// ------------------------- +@dropdownBackground: @white; +@dropdownBorder: rgba(0,0,0,.2); +@dropdownDividerTop: #e5e5e5; +@dropdownDividerBottom: @white; + +@dropdownLinkColor: @grayDark; +@dropdownLinkColorHover: @white; +@dropdownLinkColorActive: @white; + +@dropdownLinkBackgroundActive: @linkColor; +@dropdownLinkBackgroundHover: @dropdownLinkBackgroundActive; + + + +// COMPONENT VARIABLES +// -------------------------------------------------- + + +// Z-index master list +// ------------------------- +// Used for a bird's eye view of components dependent on the z-axis +// Try to avoid customizing these :) +@zindexDropdown: 1000; +@zindexPopover: 1010; +@zindexTooltip: 1030; +@zindexFixedNavbar: 1030; +@zindexModalBackdrop: 1040; +@zindexModal: 1050; + + +// Sprite icons path +// ------------------------- +@iconSpritePath: "../img/glyphicons-halflings.png"; +@iconWhiteSpritePath: "../img/glyphicons-halflings-white.png"; + + +// Input placeholder text color +// ------------------------- +@placeholderText: @grayLight; + + +// Hr border color +// ------------------------- +@hrBorder: @grayLighter; + + +// Horizontal forms & lists +// ------------------------- +@horizontalComponentOffset: 180px; + + +// Wells +// ------------------------- +@wellBackground: #f5f5f5; + + +// Navbar +// ------------------------- +@navbarCollapseWidth: 979px; +@navbarCollapseDesktopWidth: @navbarCollapseWidth + 1; + +@navbarHeight: 40px; +@navbarBackgroundHighlight: #ffffff; +@navbarBackground: darken(@navbarBackgroundHighlight, 5%); +@navbarBorder: darken(@navbarBackground, 12%); + +@navbarText: #777; +@navbarLinkColor: #777; +@navbarLinkColorHover: @grayDark; +@navbarLinkColorActive: @gray; +@navbarLinkBackgroundHover: transparent; +@navbarLinkBackgroundActive: darken(@navbarBackground, 5%); + +@navbarBrandColor: @navbarLinkColor; + +// Inverted navbar +@navbarInverseBackground: #111111; +@navbarInverseBackgroundHighlight: #222222; +@navbarInverseBorder: #252525; + +@navbarInverseText: @grayLight; +@navbarInverseLinkColor: @grayLight; +@navbarInverseLinkColorHover: @white; +@navbarInverseLinkColorActive: @navbarInverseLinkColorHover; +@navbarInverseLinkBackgroundHover: transparent; +@navbarInverseLinkBackgroundActive: @navbarInverseBackground; + +@navbarInverseSearchBackground: lighten(@navbarInverseBackground, 25%); +@navbarInverseSearchBackgroundFocus: @white; +@navbarInverseSearchBorder: @navbarInverseBackground; +@navbarInverseSearchPlaceholderColor: #ccc; + +@navbarInverseBrandColor: @navbarInverseLinkColor; + + +// Pagination +// ------------------------- +@paginationBackground: #fff; +@paginationBorder: #ddd; +@paginationActiveBackground: #f5f5f5; + + +// Hero unit +// ------------------------- +@heroUnitBackground: @grayLighter; +@heroUnitHeadingColor: inherit; +@heroUnitLeadColor: inherit; + + +// Form states and alerts +// ------------------------- +@warningText: #c09853; +@warningBackground: #fcf8e3; +@warningBorder: darken(spin(@warningBackground, -10), 3%); + +@errorText: #b94a48; +@errorBackground: #f2dede; +@errorBorder: darken(spin(@errorBackground, -10), 3%); + +@successText: #468847; +@successBackground: #dff0d8; +@successBorder: darken(spin(@successBackground, -10), 5%); + +@infoText: #3a87ad; +@infoBackground: #d9edf7; +@infoBorder: darken(spin(@infoBackground, -10), 7%); + + +// Tooltips and popovers +// ------------------------- +@tooltipColor: #fff; +@tooltipBackground: #000; +@tooltipArrowWidth: 5px; +@tooltipArrowColor: @tooltipBackground; + +@popoverBackground: #fff; +@popoverArrowWidth: 10px; +@popoverArrowColor: #fff; +@popoverTitleBackground: darken(@popoverBackground, 3%); + +// Special enhancement for popovers +@popoverArrowOuterWidth: @popoverArrowWidth + 1; +@popoverArrowOuterColor: rgba(0,0,0,.25); + + + +// GRID +// -------------------------------------------------- + + +// Default 940px grid +// ------------------------- +@gridColumns: 12; +@gridColumnWidth: 60px; +@gridGutterWidth: 20px; +@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1)); + +// 1200px min +@gridColumnWidth1200: 70px; +@gridGutterWidth1200: 30px; +@gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1)); + +// 768px-979px +@gridColumnWidth768: 42px; +@gridGutterWidth768: 20px; +@gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1)); + + +// Fluid grid +// ------------------------- +@fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth); +@fluidGridGutterWidth: percentage(@gridGutterWidth/@gridRowWidth); + +// 1200px min +@fluidGridColumnWidth1200: percentage(@gridColumnWidth1200/@gridRowWidth1200); +@fluidGridGutterWidth1200: percentage(@gridGutterWidth1200/@gridRowWidth1200); + +// 768px-979px +@fluidGridColumnWidth768: percentage(@gridColumnWidth768/@gridRowWidth768); +@fluidGridGutterWidth768: percentage(@gridGutterWidth768/@gridRowWidth768); diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/wells.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/wells.less new file mode 100644 index 0000000..84a744b --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/bootstrap/wells.less @@ -0,0 +1,29 @@ +// +// Wells +// -------------------------------------------------- + + +// Base class +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: @wellBackground; + border: 1px solid darken(@wellBackground, 7%); + .border-radius(@baseBorderRadius); + .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); + blockquote { + border-color: #ddd; + border-color: rgba(0,0,0,.15); + } +} + +// Sizes +.well-large { + padding: 24px; + .border-radius(@borderRadiusLarge); +} +.well-small { + padding: 9px; + .border-radius(@borderRadiusSmall); +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-bootstrap.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-bootstrap.less new file mode 100644 index 0000000..20a5091 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-bootstrap.less @@ -0,0 +1,18 @@ +// spc bootstrap settings +@import "bootstrap/bootstrap.less"; +@import "bootstrap/responsive.less"; + +// google webfont +@import url(http://fonts.googleapis.com/css?family=Open+Sans); + +//Typography +@sansFontFamily: 'Open Sans', sans-serif !important; +@baseFontSize: 13px; +@baseLineHeight: 19px; + +//Colors +@blue: #12567D; + +//Sprites +@iconSpritePath: '../../img/glyphicons-halflings.png'; +@iconWhiteSpritePath: '../../img/glyphicons-halflings-white.png'; \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-content.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-content.less new file mode 100644 index 0000000..9491123 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-content.less @@ -0,0 +1,57 @@ +@import "spc-utils.less"; +@import "bootstrap/variables.less"; + +.spc-page-title { + h1, h2, h3, h4 { + font-weight: normal; + .underline; + } +} + +//tags -- depricated +// need to design +.tags .btn { + border: none; + font-size: 9.5px; + font-weight: bold; +} + +// search item specific settings +.spc-search-result { + &-title { + h1, h2, h3, h4 { font-weight: normal; } + } +} + +// snippet specific settings +.spc-snippet-header { + margin-bottom: 5px; +} + +.spc-snippet-info { + padding-top: 10px; + + .dl-horizontal { + margin: 5px; + dt { font-weight: normal; } + } +} + +.spc-snippet-body { + padding: 10px; + + .accordion-group { + border: none; + } + + .accordion-heading { + text-transform: uppercase; + font-size: 14px; + border-bottom: 1px solid #e5e5e5; + } + + .accordion-heading .accordion-toggle { + padding-top: 10px; + padding-bottom: 5px; + } +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-extend.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-extend.less new file mode 100644 index 0000000..9e0cd6c --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-extend.less @@ -0,0 +1,22 @@ +//spc extend settings + +body { + background-color: rgb(249,250,245); +} + +.container { + width: 80%; +} + +.main { + background-color: white; + padding: 18px; + -moz-box-shadow: 0 0 3px #888; + -webkit-box-shadow: 0 0 3px #888; + box-shadow: 0 0 3px #888; +} + +@import "spc-header.less"; +@import "spc-content.less"; +@import "spc-rightsidebar.less"; +@import "spc-footer.less"; \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-footer.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-footer.less new file mode 100644 index 0000000..8e4d09b --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-footer.less @@ -0,0 +1,9 @@ +@import "bootstrap/variables.less"; + +//footer-outside +.footer { + padding: 5px; + font-size: small; +} + +//footer inside yet to be done (may be not required). \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-header.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-header.less new file mode 100644 index 0000000..0d77cd2 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-header.less @@ -0,0 +1,25 @@ +// settings for +// 1) .header +// header block is found on the top of the website +// spc-navbar, spc-header-searchbar found inside .header +// 2) .spc-navbar +// 3) .spc-header-searchbar + +@import "spc-utils.less"; + +.header { + .margin(@top: 15px, @bottom: 15px); +} + +.spc-navbar { + .margin (@top: 15px, @bottom: 5px); + .nav-pills { + margin-bottom: 0px; + font-size: 12px; + + >li >a { + padding-top: 2.5px; + padding-bottom: 2.5px; + } + } +} \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-rightsidebar.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-rightsidebar.less new file mode 100644 index 0000000..afef531 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-rightsidebar.less @@ -0,0 +1,14 @@ +@import "bootstrap/variables.less"; + +.spc-rightsidebar { + color: @gray; + .navigation { + padding: @paddingSmall; + font-size: @fontSizeSmall; + } + .navigation .nav-title { + font-weight: bold; + text-transform: uppercase; + } + .navigation li { margin: 5px; } +} \ No newline at end of file diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-utils.less b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-utils.less new file mode 100644 index 0000000..2ac9908 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/less/spc-utils.less @@ -0,0 +1,20 @@ +// LESS Utilities for spc +@import "bootstrap/variables.less"; + +.padding (@top: 0px, @bottom: 0px, @left: 0px, @right: 0px) { + padding-top: @top; + padding-bottom: @bottom; + padding-left: @left; + padding-right: @right; +} + +.margin (@top: 0px, @bottom: 0px, @left: 0px, @right: 0px) { + margin-top: @top; + margin-bottom: @bottom; + margin-left: @left; + margin-right:@right; +} + +.underline { + border-bottom: 1.5px solid @hrBorder; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/static/scipy.css_t b/doc/scipy-sphinx-theme/_theme/scipy/static/scipy.css_t new file mode 100644 index 0000000..3909af9 --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/static/scipy.css_t @@ -0,0 +1,247 @@ +/* -*- css -*- + * + * sphinxdoc.css_t + * ~~~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- sphinxdoc theme. Originally created by + * Armin Ronacher for Werkzeug. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +@import url("css/scipy-central.css"); + + +/* + * General tweaks + */ + +div.container-navbar-bottom { + margin-top: 0; +} + +div.container-navbar-bottom div.spc-navbar { + margin-top: 0; +} + +div.spc-navbar { + margin: 0; +} + +tt { + color: inherit; + font: inherit; +} + +tt.literal { + font-family: monospace; + padding-left: 2px; + background-color: rgb(242, 242, 242); +} + +a tt.literal { + border-bottom: none; + background-color: inherit; +} + +tt.xref { + font-family: inherit; + border-bottom: none; + background-color: inherit; + font-weight: normal; + padding-left: 0px; +} + +tt.descname { + font-size: 16px; +} + +dl.class > dt > em { + font-weight: normal; +} + +dl.function > dt > em { + font-weight: normal; +} + +dl.method > dt > em { + font-weight: normal; +} + +pre { + border-radius: 0; + border: none; + font-family: monospace; +} + + +/* + * Field lists + */ + +table.field-list { + border-collapse: collapse; + border-spacing: 5px; + margin-left: 1px; + border-left: 5px solid rgb(238, 238, 238) !important; +} + +table.field-list th.field-name { + display: inline-block; + padding: 1px 8px 1px 5px; + white-space: nowrap; + background-color: rgb(238, 238, 238); +} + +table.field-list td.field-body { + border-left: none !important; +} + +table.field-list td.field-body > p { + font-style: italic; +} + +table.field-list td.field-body > p > strong { + font-style: normal; +} + +td.field-body blockquote { + border-left: none; + margin: 0; + padding-left: 30px; +} + +td.field-body blockquote p, +dl.class blockquote p, +dl.function blockquote p, +dl.method blockquote p +{ + font-family: inherit; + font-size: inherit; + font-weight: inherit; + line-height: inherit; +} + + +/* + * Sidebars and top logo + */ + +div.sphinxsidebarwrapper { + overflow: hidden; +} + +div.spc-rightsidebar h3 { + font-size: 120%; + line-height: inherit; + border-bottom: none; +} + +div.spc-rightsidebar h4 { + font-size: 120%; + line-height: inherit; + border-bottom: none; +} + +div.top-scipy-org-logo-header { + text-align: left; + background-color: rgb(140, 170, 230); + border-bottom: 8px solid rgb(0, 51, 153); + margin-top: 10px; + padding: 5px; + box-shadow: 0px 0px 3px rgb(136, 136, 136); +} + + +/* + * Headers + */ + +h1 a { color: rgb(85, 85, 85); } +h2 a { color: rgb(85, 85, 85); } +h3 a { color: rgb(85, 85, 85); } +h4 a { color: rgb(85, 85, 85); } +h5 a { color: rgb(85, 85, 85); } +h6 a { color: rgb(85, 85, 85); } + +h1 tt { font: inherit; border-bottom: none; } +h2 tt { font: inherit; border-bottom: none; } +h3 tt { font: inherit; border-bottom: none; } +h4 tt { font: inherit; border-bottom: none; } +h5 tt { font: inherit; border-bottom: none; } +h6 tt { font: inherit; border-bottom: none; } + +div#spc-section-body h1 { color: rgb(85, 85, 85); } +div#spc-section-body h2 { color: rgb(85, 85, 85); } +div#spc-section-body h3 { color: rgb(85, 85, 85); } +div#spc-section-body h4 { color: rgb(85, 85, 85); border-bottom: none; } +div#spc-section-body h5 { color: rgb(85, 85, 85); border-bottom: none; } +div#spc-section-body h6 { color: rgb(85, 85, 85); border-bottom: none; } + +p.rubric { + color: rgb(85, 85, 85); + font-size: 120%; + font-weight: normal; + border-bottom: 1px solid rgb(204, 204, 204); +} + + +/* + * Tables + */ + +table.citation { + border: none; +} + +table.docutils td, table.docutils th { + border: none; +} + +table.docutils { + margin-bottom: 9.5px; +} + + +/* + * Admonitions + */ + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.seealso dt { + float: left; + clear: left; + min-width: 4em; + padding-right: 1em; +} + +div.seealso dd { + margin-top: 0; + margin-bottom: 0; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} diff --git a/doc/scipy-sphinx-theme/_theme/scipy/theme.conf b/doc/scipy-sphinx-theme/_theme/scipy/theme.conf new file mode 100644 index 0000000..7cfff6c --- /dev/null +++ b/doc/scipy-sphinx-theme/_theme/scipy/theme.conf @@ -0,0 +1,11 @@ +[theme] +inherit = basic +stylesheet = scipy.css +pygments_style = friendly + +[options] +edit_link = false +rootlinks = [] +sidebar = left +scipy_org_logo = +navigation_links = true diff --git a/doc/scipy-sphinx-theme/conf.py b/doc/scipy-sphinx-theme/conf.py new file mode 100644 index 0000000..d8c50e0 --- /dev/null +++ b/doc/scipy-sphinx-theme/conf.py @@ -0,0 +1,71 @@ +needs_sphinx = '1.1' + +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.pngmath', 'numpydoc', + 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', + 'sphinx.ext.autosummary', 'matplotlib.sphinxext.plot_directive'] + +templates_path = ['_templates'] +source_suffix = '.rst' +master_doc = 'index' +project = u'scipy-sphinx-theme' +copyright = u'2013, Surya Kasturi and Pauli Virtanen' +version = '0.1' +release = '0.1' +exclude_patterns = ['_build'] +pygments_style = 'sphinx' + +# -- Options for HTML output --------------------------------------------------- + +html_theme = 'scipy' +html_theme_path = ['_theme'] +#html_logo = '_static/scipyshiny_small.png' +html_static_path = ['_static'] +html_theme_options = { + "edit_link": "true", + "sidebar": "right", + "scipy_org_logo": "true", + "rootlinks": [("http://scipy.org/", "Scipy.org"), + ("http://docs.scipy.org/", "Docs")] +} + +pngmath_latex_preamble = r""" +\usepackage{color} +\definecolor{textgray}{RGB}{51,51,51} +\color{textgray} +""" +pngmath_use_preview = True +pngmath_dvipng_args = ['-gamma 1.5', '-D 96', '-bg Transparent'] + +#------------------------------------------------------------------------------ +# Plot style +#------------------------------------------------------------------------------ + +plot_pre_code = """ +import numpy as np +import scipy as sp +np.random.seed(123) +""" +plot_include_source = True +plot_formats = [('png', 96), 'pdf'] +plot_html_show_formats = False + +import math +phi = (math.sqrt(5) + 1)/2 + +font_size = 13*72/96.0 # 13 px + +plot_rcparams = { + 'font.size': font_size, + 'axes.titlesize': font_size, + 'axes.labelsize': font_size, + 'xtick.labelsize': font_size, + 'ytick.labelsize': font_size, + 'legend.fontsize': font_size, + 'figure.figsize': (3*phi, 3), + 'figure.subplot.bottom': 0.2, + 'figure.subplot.left': 0.2, + 'figure.subplot.right': 0.9, + 'figure.subplot.top': 0.85, + 'figure.subplot.wspace': 0.4, + 'text.usetex': False, +} diff --git a/doc/scipy-sphinx-theme/index.rst b/doc/scipy-sphinx-theme/index.rst new file mode 100644 index 0000000..f7f8a75 --- /dev/null +++ b/doc/scipy-sphinx-theme/index.rst @@ -0,0 +1,30 @@ +.. scipy-sphinx-theme documentation master file, created by + sphinx-quickstart on Sun Apr 21 11:22:24 2013. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to scipy-sphinx-theme's documentation! +============================================== + +The theme is under `_theme`, this document contains various test +pages. + +Contents: + +.. toctree:: + :maxdepth: 2 + + README + test_optimize + test_autodoc + test_autodoc_2 + test_autodoc_3 + test_autodoc_4 + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/scipy-sphinx-theme/test_autodoc.rst b/doc/scipy-sphinx-theme/test_autodoc.rst new file mode 100644 index 0000000..b1e7e88 --- /dev/null +++ b/doc/scipy-sphinx-theme/test_autodoc.rst @@ -0,0 +1,6 @@ +scipy.odr.Model +=============== + +.. currentmodule:: scipy.odr + +.. autoclass:: ODR diff --git a/doc/scipy-sphinx-theme/test_autodoc_2.rst b/doc/scipy-sphinx-theme/test_autodoc_2.rst new file mode 100644 index 0000000..a05bbd6 --- /dev/null +++ b/doc/scipy-sphinx-theme/test_autodoc_2.rst @@ -0,0 +1,6 @@ +scipy.interpolate.griddata +========================== + +.. currentmodule:: scipy.interpolate + +.. autofunction:: scipy.interpolate.griddata diff --git a/doc/scipy-sphinx-theme/test_autodoc_3.rst b/doc/scipy-sphinx-theme/test_autodoc_3.rst new file mode 100644 index 0000000..fcc669c --- /dev/null +++ b/doc/scipy-sphinx-theme/test_autodoc_3.rst @@ -0,0 +1,7 @@ +scipy.odr.ODR.run +================= + +.. currentmodule:: scipy.odr + +.. automethod:: scipy.odr.ODR.run + diff --git a/doc/scipy-sphinx-theme/test_autodoc_4.rst b/doc/scipy-sphinx-theme/test_autodoc_4.rst new file mode 100644 index 0000000..1ed6a47 --- /dev/null +++ b/doc/scipy-sphinx-theme/test_autodoc_4.rst @@ -0,0 +1,6 @@ +scipy.sparse.linalg.eigsh +========================= + +.. currentmodule:: scipy.sparse.linalg + +.. autofunction:: scipy.sparse.linalg.eigsh diff --git a/doc/scipy-sphinx-theme/test_optimize.rst b/doc/scipy-sphinx-theme/test_optimize.rst new file mode 100644 index 0000000..a09e0d7 --- /dev/null +++ b/doc/scipy-sphinx-theme/test_optimize.rst @@ -0,0 +1,783 @@ +Optimization (:mod:`scipy.optimize`) +==================================== + +.. sectionauthor:: Travis E. Oliphant + +.. sectionauthor:: Pauli Virtanen + +.. sectionauthor:: Denis Laxalde + +.. currentmodule:: scipy.optimize + +The :mod:`scipy.optimize` package provides several commonly used +optimization algorithms. A detailed listing is available: +:mod:`scipy.optimize` (can also be found by ``help(scipy.optimize)``). + +The module contains: + +1. Unconstrained and constrained minimization of multivariate scalar + functions (:func:`minimize`) using a variety of algorithms (e.g. BFGS, + Nelder-Mead simplex, Newton Conjugate Gradient, COBYLA or SLSQP) + +2. Global (brute-force) optimization routines (e.g., :func:`anneal`, :func:`basinhopping`) + +3. Least-squares minimization (:func:`leastsq`) and curve fitting + (:func:`curve_fit`) algorithms + +4. Scalar univariate functions minimizers (:func:`minimize_scalar`) and + root finders (:func:`newton`) + +5. Multivariate equation system solvers (:func:`root`) using a variety of + algorithms (e.g. hybrid Powell, Levenberg-Marquardt or large-scale + methods such as Newton-Krylov). + +Below, several examples demonstrate their basic usage. + + +Unconstrained minimization of multivariate scalar functions (:func:`minimize`) +------------------------------------------------------------------------------ + +The :func:`minimize` function provides a common interface to unconstrained +and constrained minimization algorithms for multivariate scalar functions +in `scipy.optimize`. To demonstrate the minimization function consider the +problem of minimizing the Rosenbrock function of :math:`N` variables: + +.. math:: + :nowrap: + + \[ f\left(\mathbf{x}\right)=\sum_{i=1}^{N-1}100\left(x_{i}-x_{i-1}^{2}\right)^{2}+\left(1-x_{i-1}\right)^{2}.\] + +The minimum value of this function is 0 which is achieved when +:math:`x_{i}=1.` + +Note that the Rosenbrock function and its derivatives are included in +`scipy.optimize`. The implementations shown in the following sections +provide examples of how to define an objective function as well as its +jacobian and hessian functions. + +Nelder-Mead Simplex algorithm (``method='Nelder-Mead'``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the example below, the :func:`minimize` routine is used +with the *Nelder-Mead* simplex algorithm (selected through the ``method`` +parameter): + + >>> import numpy as np + >>> from scipy.optimize import minimize + + >>> def rosen(x): + ... """The Rosenbrock function""" + ... return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0) + + >>> x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2]) + >>> res = minimize(rosen, x0, method='nelder-mead', + ... options={'xtol': 1e-8, 'disp': True}) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 339 + Function evaluations: 571 + + >>> print(res.x) + [ 1. 1. 1. 1. 1.] + +The simplex algorithm is probably the simplest way to minimize a fairly +well-behaved function. It requires only function evaluations and is a good +choice for simple minimization problems. However, because it does not use +any gradient evaluations, it may take longer to find the minimum. + +Another optimization algorithm that needs only function calls to find +the minimum is *Powell*'s method available by setting ``method='powell'`` in +:func:`minimize`. + + +Broyden-Fletcher-Goldfarb-Shanno algorithm (``method='BFGS'``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In order to converge more quickly to the solution, this routine uses +the gradient of the objective function. If the gradient is not given +by the user, then it is estimated using first-differences. The +Broyden-Fletcher-Goldfarb-Shanno (BFGS) method typically requires +fewer function calls than the simplex algorithm even when the gradient +must be estimated. + +To demonstrate this algorithm, the Rosenbrock function is again used. +The gradient of the Rosenbrock function is the vector: + +.. math:: + :nowrap: + + \begin{eqnarray*} \frac{\partial f}{\partial x_{j}} & = & \sum_{i=1}^{N}200\left(x_{i}-x_{i-1}^{2}\right)\left(\delta_{i,j}-2x_{i-1}\delta_{i-1,j}\right)-2\left(1-x_{i-1}\right)\delta_{i-1,j}.\\ & = & 200\left(x_{j}-x_{j-1}^{2}\right)-400x_{j}\left(x_{j+1}-x_{j}^{2}\right)-2\left(1-x_{j}\right).\end{eqnarray*} + +This expression is valid for the interior derivatives. Special cases +are + +.. math:: + :nowrap: + + \begin{eqnarray*} \frac{\partial f}{\partial x_{0}} & = & -400x_{0}\left(x_{1}-x_{0}^{2}\right)-2\left(1-x_{0}\right),\\ \frac{\partial f}{\partial x_{N-1}} & = & 200\left(x_{N-1}-x_{N-2}^{2}\right).\end{eqnarray*} + +A Python function which computes this gradient is constructed by the +code-segment: + + >>> def rosen_der(x): + ... xm = x[1:-1] + ... xm_m1 = x[:-2] + ... xm_p1 = x[2:] + ... der = np.zeros_like(x) + ... der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm) + ... der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0]) + ... der[-1] = 200*(x[-1]-x[-2]**2) + ... return der + +This gradient information is specified in the :func:`minimize` function +through the ``jac`` parameter as illustrated below. + + + >>> res = minimize(rosen, x0, method='BFGS', jac=rosen_der, + ... options={'disp': True}) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 51 + Function evaluations: 63 + Gradient evaluations: 63 + >>> print(res.x) + [ 1. 1. 1. 1. 1.] + + +Newton-Conjugate-Gradient algorithm (``method='Newton-CG'``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The method which requires the fewest function calls and is therefore often +the fastest method to minimize functions of many variables uses the +Newton-Conjugate Gradient algorithm. This method is a modified Newton's +method and uses a conjugate gradient algorithm to (approximately) invert +the local Hessian. Newton's method is based on fitting the function +locally to a quadratic form: + +.. math:: + :nowrap: + + \[ f\left(\mathbf{x}\right)\approx f\left(\mathbf{x}_{0}\right)+\nabla f\left(\mathbf{x}_{0}\right)\cdot\left(\mathbf{x}-\mathbf{x}_{0}\right)+\frac{1}{2}\left(\mathbf{x}-\mathbf{x}_{0}\right)^{T}\mathbf{H}\left(\mathbf{x}_{0}\right)\left(\mathbf{x}-\mathbf{x}_{0}\right).\] + +where :math:`\mathbf{H}\left(\mathbf{x}_{0}\right)` is a matrix of second-derivatives (the Hessian). If the Hessian is +positive definite then the local minimum of this function can be found +by setting the gradient of the quadratic form to zero, resulting in + +.. math:: + :nowrap: + + \[ \mathbf{x}_{\textrm{opt}}=\mathbf{x}_{0}-\mathbf{H}^{-1}\nabla f.\] + +The inverse of the Hessian is evaluated using the conjugate-gradient +method. An example of employing this method to minimizing the +Rosenbrock function is given below. To take full advantage of the +Newton-CG method, a function which computes the Hessian must be +provided. The Hessian matrix itself does not need to be constructed, +only a vector which is the product of the Hessian with an arbitrary +vector needs to be available to the minimization routine. As a result, +the user can provide either a function to compute the Hessian matrix, +or a function to compute the product of the Hessian with an arbitrary +vector. + + +Full Hessian example: +""""""""""""""""""""" + +The Hessian of the Rosenbrock function is + +.. math:: + :nowrap: + + \begin{eqnarray*} H_{ij}=\frac{\partial^{2}f}{\partial x_{i}\partial x_{j}} & = & 200\left(\delta_{i,j}-2x_{i-1}\delta_{i-1,j}\right)-400x_{i}\left(\delta_{i+1,j}-2x_{i}\delta_{i,j}\right)-400\delta_{i,j}\left(x_{i+1}-x_{i}^{2}\right)+2\delta_{i,j},\\ & = & \left(202+1200x_{i}^{2}-400x_{i+1}\right)\delta_{i,j}-400x_{i}\delta_{i+1,j}-400x_{i-1}\delta_{i-1,j},\end{eqnarray*} + +if :math:`i,j\in\left[1,N-2\right]` with :math:`i,j\in\left[0,N-1\right]` defining the :math:`N\times N` matrix. Other non-zero entries of the matrix are + +.. math:: + :nowrap: + + \begin{eqnarray*} \frac{\partial^{2}f}{\partial x_{0}^{2}} & = & 1200x_{0}^{2}-400x_{1}+2,\\ \frac{\partial^{2}f}{\partial x_{0}\partial x_{1}}=\frac{\partial^{2}f}{\partial x_{1}\partial x_{0}} & = & -400x_{0},\\ \frac{\partial^{2}f}{\partial x_{N-1}\partial x_{N-2}}=\frac{\partial^{2}f}{\partial x_{N-2}\partial x_{N-1}} & = & -400x_{N-2},\\ \frac{\partial^{2}f}{\partial x_{N-1}^{2}} & = & 200.\end{eqnarray*} + +For example, the Hessian when :math:`N=5` is + +.. math:: + :nowrap: + + \[ \mathbf{H}=\left[\begin{array}{ccccc} 1200x_{0}^{2}-400x_{1}+2 & -400x_{0} & 0 & 0 & 0\\ -400x_{0} & 202+1200x_{1}^{2}-400x_{2} & -400x_{1} & 0 & 0\\ 0 & -400x_{1} & 202+1200x_{2}^{2}-400x_{3} & -400x_{2} & 0\\ 0 & & -400x_{2} & 202+1200x_{3}^{2}-400x_{4} & -400x_{3}\\ 0 & 0 & 0 & -400x_{3} & 200\end{array}\right].\] + +The code which computes this Hessian along with the code to minimize +the function using Newton-CG method is shown in the following example: + + >>> def rosen_hess(x): + ... x = np.asarray(x) + ... H = np.diag(-400*x[:-1],1) - np.diag(400*x[:-1],-1) + ... diagonal = np.zeros_like(x) + ... diagonal[0] = 1200*x[0]**2-400*x[1]+2 + ... diagonal[-1] = 200 + ... diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:] + ... H = H + np.diag(diagonal) + ... return H + + >>> res = minimize(rosen, x0, method='Newton-CG', + ... jac=rosen_der, hess=rosen_hess, + ... options={'avextol': 1e-8, 'disp': True}) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 19 + Function evaluations: 22 + Gradient evaluations: 19 + Hessian evaluations: 19 + >>> print(res.x) + [ 1. 1. 1. 1. 1.] + + +Hessian product example: +"""""""""""""""""""""""" + +For larger minimization problems, storing the entire Hessian matrix can +consume considerable time and memory. The Newton-CG algorithm only needs +the product of the Hessian times an arbitrary vector. As a result, the user +can supply code to compute this product rather than the full Hessian by +giving a ``hess`` function which take the minimization vector as the first +argument and the arbitrary vector as the second argument (along with extra +arguments passed to the function to be minimized). If possible, using +Newton-CG with the Hessian product option is probably the fastest way to +minimize the function. + +In this case, the product of the Rosenbrock Hessian with an arbitrary +vector is not difficult to compute. If :math:`\mathbf{p}` is the arbitrary +vector, then :math:`\mathbf{H}\left(\mathbf{x}\right)\mathbf{p}` has +elements: + +.. math:: + :nowrap: + + \[ \mathbf{H}\left(\mathbf{x}\right)\mathbf{p}=\left[\begin{array}{c} \left(1200x_{0}^{2}-400x_{1}+2\right)p_{0}-400x_{0}p_{1}\\ \vdots\\ -400x_{i-1}p_{i-1}+\left(202+1200x_{i}^{2}-400x_{i+1}\right)p_{i}-400x_{i}p_{i+1}\\ \vdots\\ -400x_{N-2}p_{N-2}+200p_{N-1}\end{array}\right].\] + +Code which makes use of this Hessian product to minimize the +Rosenbrock function using :func:`minimize` follows: + + >>> def rosen_hess_p(x,p): + ... x = np.asarray(x) + ... Hp = np.zeros_like(x) + ... Hp[0] = (1200*x[0]**2 - 400*x[1] + 2)*p[0] - 400*x[0]*p[1] + ... Hp[1:-1] = -400*x[:-2]*p[:-2]+(202+1200*x[1:-1]**2-400*x[2:])*p[1:-1] \ + ... -400*x[1:-1]*p[2:] + ... Hp[-1] = -400*x[-2]*p[-2] + 200*p[-1] + ... return Hp + + >>> res = minimize(rosen, x0, method='Newton-CG', + ... jac=rosen_der, hess=rosen_hess_p, + ... options={'avextol': 1e-8, 'disp': True}) + Optimization terminated successfully. + Current function value: 0.000000 + Iterations: 20 + Function evaluations: 23 + Gradient evaluations: 20 + Hessian evaluations: 44 + >>> print(res.x) + [ 1. 1. 1. 1. 1.] + + +.. _tutorial-sqlsp: + +Constrained minimization of multivariate scalar functions (:func:`minimize`) +---------------------------------------------------------------------------- + +The :func:`minimize` function also provides an interface to several +constrained minimization algorithm. As an example, the Sequential Least +SQuares Programming optimization algorithm (SLSQP) will be considered here. +This algorithm allows to deal with constrained minimization problems of the +form: + +.. math:: + :nowrap: + + \begin{eqnarray*} \min F(x) \\ \text{subject to } & C_j(X) = 0 , &j = 1,...,\text{MEQ}\\ + & C_j(x) \geq 0 , &j = \text{MEQ}+1,...,M\\ + & XL \leq x \leq XU , &I = 1,...,N. \end{eqnarray*} + + +As an example, let us consider the problem of maximizing the function: + +.. math:: + :nowrap: + + \[ f(x, y) = 2 x y + 2 x - x^2 - 2 y^2 \] + +subject to an equality and an inequality constraints defined as: + +.. math:: + :nowrap: + + \[ x^3 - y = 0 \] + \[ y - 1 \geq 0 \] + + + +The objective function and its derivative are defined as follows. + + >>> def func(x, sign=1.0): + ... """ Objective function """ + ... return sign*(2*x[0]*x[1] + 2*x[0] - x[0]**2 - 2*x[1]**2) + + >>> def func_deriv(x, sign=1.0): + ... """ Derivative of objective function """ + ... dfdx0 = sign*(-2*x[0] + 2*x[1] + 2) + ... dfdx1 = sign*(2*x[0] - 4*x[1]) + ... return np.array([ dfdx0, dfdx1 ]) + +Note that since :func:`minimize` only minimizes functions, the ``sign`` +parameter is introduced to multiply the objective function (and its +derivative by -1) in order to perform a maximization. + +Then constraints are defined as a sequence of dictionaries, with keys +``type``, ``fun`` and ``jac``. + + >>> cons = ({'type': 'eq', + ... 'fun' : lambda x: np.array([x[0]**3 - x[1]]), + ... 'jac' : lambda x: np.array([3.0*(x[0]**2.0), -1.0])}, + ... {'type': 'ineq', + ... 'fun' : lambda x: np.array([x[1] - 1]), + ... 'jac' : lambda x: np.array([0.0, 1.0])}) + + +Now an unconstrained optimization can be performed as: + + >>> res = minimize(func, [-1.0,1.0], args=(-1.0,), jac=func_deriv, + ... method='SLSQP', options={'disp': True}) + Optimization terminated successfully. (Exit mode 0) + Current function value: -2.0 + Iterations: 4 + Function evaluations: 5 + Gradient evaluations: 4 + >>> print(res.x) + [ 2. 1.] + +and a constrained optimization as: + + >>> res = minimize(func, [-1.0,1.0], args=(-1.0,), jac=func_deriv, + ... constraints=cons, method='SLSQP', options={'disp': True}) + Optimization terminated successfully. (Exit mode 0) + Current function value: -1.00000018311 + Iterations: 9 + Function evaluations: 14 + Gradient evaluations: 9 + >>> print(res.x) + [ 1.00000009 1. ] + + +Least-square fitting (:func:`leastsq`) +-------------------------------------- + +All of the previously-explained minimization procedures can be used to +solve a least-squares problem provided the appropriate objective +function is constructed. For example, suppose it is desired to fit a +set of data :math:`\left\{\mathbf{x}_{i}, \mathbf{y}_{i}\right\}` +to a known model, +:math:`\mathbf{y}=\mathbf{f}\left(\mathbf{x},\mathbf{p}\right)` +where :math:`\mathbf{p}` is a vector of parameters for the model that +need to be found. A common method for determining which parameter +vector gives the best fit to the data is to minimize the sum of squares +of the residuals. The residual is usually defined for each observed +data-point as + +.. math:: + :nowrap: + + \[ e_{i}\left(\mathbf{p},\mathbf{y}_{i},\mathbf{x}_{i}\right)=\left\Vert \mathbf{y}_{i}-\mathbf{f}\left(\mathbf{x}_{i},\mathbf{p}\right)\right\Vert .\] + +An objective function to pass to any of the previous minization +algorithms to obtain a least-squares fit is. + +.. math:: + :nowrap: + + \[ J\left(\mathbf{p}\right)=\sum_{i=0}^{N-1}e_{i}^{2}\left(\mathbf{p}\right).\] + + + +The :obj:`leastsq` algorithm performs this squaring and summing of the +residuals automatically. It takes as an input argument the vector +function :math:`\mathbf{e}\left(\mathbf{p}\right)` and returns the +value of :math:`\mathbf{p}` which minimizes +:math:`J\left(\mathbf{p}\right)=\mathbf{e}^{T}\mathbf{e}` +directly. The user is also encouraged to provide the Jacobian matrix +of the function (with derivatives down the columns or across the +rows). If the Jacobian is not provided, it is estimated. + +An example should clarify the usage. Suppose it is believed some +measured data follow a sinusoidal pattern + +.. math:: + :nowrap: + + \[ y_{i}=A\sin\left(2\pi kx_{i}+\theta\right)\] + +where the parameters :math:`A,` :math:`k` , and :math:`\theta` are unknown. The residual vector is + +.. math:: + :nowrap: + + \[ e_{i}=\left|y_{i}-A\sin\left(2\pi kx_{i}+\theta\right)\right|.\] + +By defining a function to compute the residuals and (selecting an +appropriate starting position), the least-squares fit routine can be +used to find the best-fit parameters :math:`\hat{A},\,\hat{k},\,\hat{\theta}`. +This is shown in the following example: + +.. plot:: + + >>> from numpy import * + >>> x = arange(0,6e-2,6e-2/30) + >>> A,k,theta = 10, 1.0/3e-2, pi/6 + >>> y_true = A*sin(2*pi*k*x+theta) + >>> y_meas = y_true + 2*random.randn(len(x)) + + >>> def residuals(p, y, x): + ... A,k,theta = p + ... err = y-A*sin(2*pi*k*x+theta) + ... return err + + >>> def peval(x, p): + ... return p[0]*sin(2*pi*p[1]*x+p[2]) + + >>> p0 = [8, 1/2.3e-2, pi/3] + >>> print(array(p0)) + [ 8. 43.4783 1.0472] + + >>> from scipy.optimize import leastsq + >>> plsq = leastsq(residuals, p0, args=(y_meas, x)) + >>> print(plsq[0]) + [ 10.9437 33.3605 0.5834] + + >>> print(array([A, k, theta])) + [ 10. 33.3333 0.5236] + + >>> import matplotlib.pyplot as plt + >>> plt.plot(x,peval(x,plsq[0]),x,y_meas,'o',x,y_true) + >>> plt.title('Least-squares fit to noisy data') + >>> plt.legend(['Fit', 'Noisy', 'True']) + >>> plt.show() + +.. :caption: Least-square fitting to noisy data using +.. :obj:`scipy.optimize.leastsq` + + +Univariate function minimizers (:func:`minimize_scalar`) +-------------------------------------------------------- + +Often only the minimum of an univariate function (i.e. a function that +takes a scalar as input) is needed. In these circumstances, other +optimization techniques have been developed that can work faster. These are +accessible from the :func:`minimize_scalar` function which proposes several +algorithms. + + +Unconstrained minimization (``method='brent'``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are actually two methods that can be used to minimize an univariate +function: `brent` and `golden`, but `golden` is included only for academic +purposes and should rarely be used. These can be respectively selected +through the `method` parameter in :func:`minimize_scalar`. The `brent` +method uses Brent's algorithm for locating a minimum. Optimally a bracket +(the `bs` parameter) should be given which contains the minimum desired. A +bracket is a triple :math:`\left( a, b, c \right)` such that :math:`f +\left( a \right) > f \left( b \right) < f \left( c \right)` and :math:`a < +b < c` . If this is not given, then alternatively two starting points can +be chosen and a bracket will be found from these points using a simple +marching algorithm. If these two starting points are not provided `0` and +`1` will be used (this may not be the right choice for your function and +result in an unexpected minimum being returned). + +Here is an example: + + >>> from scipy.optimize import minimize_scalar + >>> f = lambda x: (x - 2) * (x + 1)**2 + >>> res = minimize_scalar(f, method='brent') + >>> print(res.x) + 1.0 + + +Bounded minimization (``method='bounded'``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Very often, there are constraints that can be placed on the solution space +before minimization occurs. The `bounded` method in :func:`minimize_scalar` +is an example of a constrained minimization procedure that provides a +rudimentary interval constraint for scalar functions. The interval +constraint allows the minimization to occur only between two fixed +endpoints, specified using the mandatory `bs` parameter. + +For example, to find the minimum of :math:`J_{1}\left( x \right)` near +:math:`x=5` , :func:`minimize_scalar` can be called using the interval +:math:`\left[ 4, 7 \right]` as a constraint. The result is +:math:`x_{\textrm{min}}=5.3314` : + + >>> from scipy.special import j1 + >>> res = minimize_scalar(j1, bs=(4, 7), method='bounded') + >>> print(res.x) + 5.33144184241 + + +Root finding +------------ + +Scalar functions +^^^^^^^^^^^^^^^^ + +If one has a single-variable equation, there are four different root +finding algorithms that can be tried. Each of these algorithms requires the +endpoints of an interval in which a root is expected (because the function +changes signs). In general :obj:`brentq` is the best choice, but the other +methods may be useful in certain circumstances or for academic purposes. + + +Fixed-point solving +^^^^^^^^^^^^^^^^^^^ + +A problem closely related to finding the zeros of a function is the +problem of finding a fixed-point of a function. A fixed point of a +function is the point at which evaluation of the function returns the +point: :math:`g\left(x\right)=x.` Clearly the fixed point of :math:`g` +is the root of :math:`f\left(x\right)=g\left(x\right)-x.` +Equivalently, the root of :math:`f` is the fixed_point of +:math:`g\left(x\right)=f\left(x\right)+x.` The routine +:obj:`fixed_point` provides a simple iterative method using Aitkens +sequence acceleration to estimate the fixed point of :math:`g` given a +starting point. + +Sets of equations +^^^^^^^^^^^^^^^^^ + +Finding a root of a set of non-linear equations can be achieve using the +:func:`root` function. Several methods are available, amongst which ``hybr`` +(the default) and ``lm`` which respectively use the hybrid method of Powell +and the Levenberg-Marquardt method from MINPACK. + +The following example considers the single-variable transcendental +equation + +.. math:: + :nowrap: + + \[ x+2\cos\left(x\right)=0,\] + +a root of which can be found as follows:: + + >>> import numpy as np + >>> from scipy.optimize import root + >>> def func(x): + ... return x + 2 * np.cos(x) + >>> sol = root(func, 0.3) + >>> sol.x + array([-1.02986653]) + >>> sol.fun + array([ -6.66133815e-16]) + +Consider now a set of non-linear equations + +.. math:: + :nowrap: + + \begin{eqnarray*} + x_{0}\cos\left(x_{1}\right) & = & 4,\\ + x_{0}x_{1}-x_{1} & = & 5. + \end{eqnarray*} + +We define the objective function so that it also returns the Jacobian and +indicate this by setting the ``jac`` parameter to ``True``. Also, the +Levenberg-Marquardt solver is used here. + +:: + + >>> def func2(x): + ... f = [x[0] * np.cos(x[1]) - 4, + ... x[1]*x[0] - x[1] - 5] + ... df = np.array([[np.cos(x[1]), -x[0] * np.sin(x[1])], + ... [x[1], x[0] - 1]]) + ... return f, df + >>> sol = root(func2, [1, 1], jac=True, method='lm') + >>> sol.x + array([ 6.50409711, 0.90841421]) + + +Root finding for large problems +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Methods ``hybr`` and ``lm`` in :func:`root` cannot deal with a very large +number of variables (*N*), as they need to calculate and invert a dense *N +x N* Jacobian matrix on every Newton step. This becomes rather inefficient +when *N* grows. + +Consider for instance the following problem: we need to solve the +following integrodifferential equation on the square +:math:`[0,1]\times[0,1]`: + +.. math:: + + (\partial_x^2 + \partial_y^2) P + 5 \left(\int_0^1\int_0^1\cosh(P)\,dx\,dy\right)^2 = 0 + +with the boundary condition :math:`P(x,1) = 1` on the upper edge and +:math:`P=0` elsewhere on the boundary of the square. This can be done +by approximating the continuous function *P* by its values on a grid, +:math:`P_{n,m}\approx{}P(n h, m h)`, with a small grid spacing +*h*. The derivatives and integrals can then be approximated; for +instance :math:`\partial_x^2 P(x,y)\approx{}(P(x+h,y) - 2 P(x,y) + +P(x-h,y))/h^2`. The problem is then equivalent to finding the root of +some function ``residual(P)``, where ``P`` is a vector of length +:math:`N_x N_y`. + +Now, because :math:`N_x N_y` can be large, methods ``hybr`` or ``lm`` in +:func:`root` will take a long time to solve this problem. The solution can +however be found using one of the large-scale solvers, for example +``krylov``, ``broyden2``, or ``anderson``. These use what is known as the +inexact Newton method, which instead of computing the Jacobian matrix +exactly, forms an approximation for it. + +The problem we have can now be solved as follows: + +.. plot:: + + import numpy as np + from scipy.optimize import root + from numpy import cosh, zeros_like, mgrid, zeros + + # parameters + nx, ny = 75, 75 + hx, hy = 1./(nx-1), 1./(ny-1) + + P_left, P_right = 0, 0 + P_top, P_bottom = 1, 0 + + def residual(P): + d2x = zeros_like(P) + d2y = zeros_like(P) + + d2x[1:-1] = (P[2:] - 2*P[1:-1] + P[:-2]) / hx/hx + d2x[0] = (P[1] - 2*P[0] + P_left)/hx/hx + d2x[-1] = (P_right - 2*P[-1] + P[-2])/hx/hx + + d2y[:,1:-1] = (P[:,2:] - 2*P[:,1:-1] + P[:,:-2])/hy/hy + d2y[:,0] = (P[:,1] - 2*P[:,0] + P_bottom)/hy/hy + d2y[:,-1] = (P_top - 2*P[:,-1] + P[:,-2])/hy/hy + + return d2x + d2y + 5*cosh(P).mean()**2 + + # solve + guess = zeros((nx, ny), float) + sol = root(residual, guess, method='krylov', options={'disp': True}) + #sol = root(residual, guess, method='broyden2', options={'disp': True, 'max_rank': 50}) + #sol = root(residual, guess, method='anderson', options={'disp': True, 'M': 10}) + print('Residual: %g' % abs(residual(sol.x)).max()) + + # visualize + import matplotlib.pyplot as plt + x, y = mgrid[0:1:(nx*1j), 0:1:(ny*1j)] + plt.pcolor(x, y, sol.x) + plt.colorbar() + plt.show() + + +Still too slow? Preconditioning. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When looking for the zero of the functions :math:`f_i({\bf x}) = 0`, +*i = 1, 2, ..., N*, the ``krylov`` solver spends most of its +time inverting the Jacobian matrix, + +.. math:: J_{ij} = \frac{\partial f_i}{\partial x_j} . + +If you have an approximation for the inverse matrix +:math:`M\approx{}J^{-1}`, you can use it for *preconditioning* the +linear inversion problem. The idea is that instead of solving +:math:`J{\bf s}={\bf y}` one solves :math:`MJ{\bf s}=M{\bf y}`: since +matrix :math:`MJ` is "closer" to the identity matrix than :math:`J` +is, the equation should be easier for the Krylov method to deal with. + +The matrix *M* can be passed to :func:`root` with method ``krylov`` as an +option ``options['jac_options']['inner_M']``. It can be a (sparse) matrix +or a :obj:`scipy.sparse.linalg.LinearOperator` instance. + +For the problem in the previous section, we note that the function to +solve consists of two parts: the first one is application of the +Laplace operator, :math:`[\partial_x^2 + \partial_y^2] P`, and the second +is the integral. We can actually easily compute the Jacobian corresponding +to the Laplace operator part: we know that in one dimension + +.. math:: + + \partial_x^2 \approx \frac{1}{h_x^2} \begin{pmatrix} + -2 & 1 & 0 & 0 \cdots \\ + 1 & -2 & 1 & 0 \cdots \\ + 0 & 1 & -2 & 1 \cdots \\ + \ldots + \end{pmatrix} + = h_x^{-2} L + +so that the whole 2-D operator is represented by + +.. math:: + + J_1 = \partial_x^2 + \partial_y^2 + \simeq + h_x^{-2} L \otimes I + h_y^{-2} I \otimes L + +The matrix :math:`J_2` of the Jacobian corresponding to the integral +is more difficult to calculate, and since *all* of it entries are +nonzero, it will be difficult to invert. :math:`J_1` on the other hand +is a relatively simple matrix, and can be inverted by +:obj:`scipy.sparse.linalg.splu` (or the inverse can be approximated by +:obj:`scipy.sparse.linalg.spilu`). So we are content to take +:math:`M\approx{}J_1^{-1}` and hope for the best. + +In the example below, we use the preconditioner :math:`M=J_1^{-1}`. + +.. literalinclude:: examples/newton_krylov_preconditioning.py + +Resulting run, first without preconditioning:: + + 0: |F(x)| = 803.614; step 1; tol 0.000257947 + 1: |F(x)| = 345.912; step 1; tol 0.166755 + 2: |F(x)| = 139.159; step 1; tol 0.145657 + 3: |F(x)| = 27.3682; step 1; tol 0.0348109 + 4: |F(x)| = 1.03303; step 1; tol 0.00128227 + 5: |F(x)| = 0.0406634; step 1; tol 0.00139451 + 6: |F(x)| = 0.00344341; step 1; tol 0.00645373 + 7: |F(x)| = 0.000153671; step 1; tol 0.00179246 + 8: |F(x)| = 6.7424e-06; step 1; tol 0.00173256 + Residual 3.57078908664e-07 + Evaluations 317 + +and then with preconditioning:: + + 0: |F(x)| = 136.993; step 1; tol 7.49599e-06 + 1: |F(x)| = 4.80983; step 1; tol 0.00110945 + 2: |F(x)| = 0.195942; step 1; tol 0.00149362 + 3: |F(x)| = 0.000563597; step 1; tol 7.44604e-06 + 4: |F(x)| = 1.00698e-09; step 1; tol 2.87308e-12 + Residual 9.29603061195e-11 + Evaluations 77 + +Using a preconditioner reduced the number of evaluations of the +``residual`` function by a factor of *4*. For problems where the +residual is expensive to compute, good preconditioning can be crucial +--- it can even decide whether the problem is solvable in practice or +not. + +Preconditioning is an art, science, and industry. Here, we were lucky +in making a simple choice that worked reasonably well, but there is a +lot more depth to this topic than is shown here. + +.. rubric:: References + +Some further reading and related software: + +.. [KK] D.A. Knoll and D.E. Keyes, "Jacobian-free Newton-Krylov methods", + J. Comp. Phys. 193, 357 (2003). + +.. [PP] PETSc http://www.mcs.anl.gov/petsc/ and its Python bindings + http://code.google.com/p/petsc4py/ + +.. [AMG] PyAMG (algebraic multigrid preconditioners/solvers) + http://code.google.com/p/pyamg/ diff --git a/doc/source/_static/.gitignore b/doc/source/_static/.gitignore new file mode 100644 index 0000000..60da047 --- /dev/null +++ b/doc/source/_static/.gitignore @@ -0,0 +1,2 @@ +# This file is here to avoid a sphinx warning about a missing _static folder. +# Empty folders are not allowed into git. diff --git a/doc/source/_templates/autosummary/class.rst b/doc/source/_templates/autosummary/class.rst new file mode 100644 index 0000000..64c1b11 --- /dev/null +++ b/doc/source/_templates/autosummary/class.rst @@ -0,0 +1,27 @@ +{% extends "!autosummary/class.rst" %} + +{% block methods %} +{% if methods %} + .. HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages. + .. autosummary:: + :toctree: + {% for item in all_methods %} + {%- if not item.startswith('_') or item in ['__call__'] %} + {{ name }}.{{ item }} + {%- endif -%} + {%- endfor %} +{% endif %} +{% endblock %} + +{% block attributes %} +{% if attributes %} + .. HACK -- the point here is that we don't want this to appear in the output, but the autosummary should still generate the pages. + .. autosummary:: + :toctree: + {% for item in all_attributes %} + {%- if not item.startswith('_') %} + {{ name }}.{{ item }} + {%- endif -%} + {%- endfor %} +{% endif %} +{% endblock %} diff --git a/doc/source/_templates/defindex.html b/doc/source/_templates/defindex.html new file mode 100644 index 0000000..8eaadec --- /dev/null +++ b/doc/source/_templates/defindex.html @@ -0,0 +1,35 @@ +{# + basic/defindex.html + ~~~~~~~~~~~~~~~~~~~ + + Default template for the "index" page. + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{%- extends "layout.html" %} +{% set title = _('Overview') %} +{% block body %} +

    {{ docstitle|e }}

    +

    + {{ _('Welcome! This is') }} + {% block description %}{{ _('the documentation for') }} {{ project|e }} + {{ release|e }}{% if last_updated %}, {{ _('last updated') }} {{ last_updated|e }}{% endif %}{% endblock %}. +

    + {% block tables %} +

    {{ _('Indices and tables:') }}

    + + +
    + + + + + +
    + {% endblock %} +{% endblock %} diff --git a/doc/source/_templates/indexcontent.html b/doc/source/_templates/indexcontent.html new file mode 100644 index 0000000..3fbb616 --- /dev/null +++ b/doc/source/_templates/indexcontent.html @@ -0,0 +1,61 @@ +{% extends "defindex.html" %} +{% block tables %} +

    Parts of the documentation:

    + + +
    + + + + +
    + +

    Indices and tables:

    + + +
    + + + + + +
    + +

    Meta information:

    + + +
    + + + + + +
    + +

    Acknowledgements

    +

    + Large parts of this manual originate from Travis E. Oliphant's book + "Guide to NumPy" (which generously entered + Public Domain in August 2008). The reference documentation for many of + the functions are written by numerous contributors and developers of + NumPy, both prior to and during the + NumPy Documentation Marathon. +

    +

    + The preferred way to update the documentation is by submitting a pull + request on Github (see the + Developer Guide. + The NumPy Documentation Wiki + can also still be used to submit documentation fixes. + Please help us to further improve the NumPy documentation! +

    +{% endblock %} diff --git a/doc/source/_templates/indexsidebar.html b/doc/source/_templates/indexsidebar.html new file mode 100644 index 0000000..9edb003 --- /dev/null +++ b/doc/source/_templates/indexsidebar.html @@ -0,0 +1,4 @@ +

    Resources

    + diff --git a/doc/source/_templates/layout.html b/doc/source/_templates/layout.html new file mode 100644 index 0000000..77da54a --- /dev/null +++ b/doc/source/_templates/layout.html @@ -0,0 +1,20 @@ +{% extends "!layout.html" %} + +{% block rootrellink %} + {% if pagename != 'index' %} +
  • {{ shorttitle|e }}
  • + {% endif %} +{% endblock %} + +{% block sidebarsearch %} +{%- if sourcename %} + +{%- endif %} +{{ super() }} +{% endblock %} diff --git a/doc/source/about.rst b/doc/source/about.rst new file mode 100644 index 0000000..be1ced1 --- /dev/null +++ b/doc/source/about.rst @@ -0,0 +1,66 @@ +About NumPy +=========== + +`NumPy `__ is the fundamental package +needed for scientific computing with Python. This package contains: + +- a powerful N-dimensional :ref:`array object ` +- sophisticated :ref:`(broadcasting) functions ` +- basic :ref:`linear algebra functions ` +- basic :ref:`Fourier transforms ` +- sophisticated :ref:`random number capabilities ` +- tools for integrating Fortran code +- tools for integrating C/C++ code + +Besides its obvious scientific uses, *NumPy* can also be used as an +efficient multi-dimensional container of generic data. Arbitrary +data types can be defined. This allows *NumPy* to seamlessly and +speedily integrate with a wide variety of databases. + +NumPy is a successor for two earlier scientific Python libraries: +NumPy derives from the old *Numeric* code base and can be used +as a replacement for *Numeric*. It also adds the features introduced +by *Numarray* and can also be used to replace *Numarray*. + +NumPy community +--------------- + +NumPy is a distributed, volunteer, open-source project. *You* can help +us make it better; if you believe something should be improved either +in functionality or in documentation, don't hesitate to contact us --- or +even better, contact us and participate in fixing the problem. + +Our main means of communication are: + +- `scipy.org website `__ + +- `Mailing lists `__ + +- `NumPy Issues `__ (bug reports go here) + +- `Old NumPy Trac `__ (no longer used) + +More information about the development of NumPy can be found at our `Developer Zone `__. + +If you want to fix issues in this documentation, the easiest way +is to participate in `our ongoing documentation marathon +`__. + + +About this documentation +======================== + +Conventions +----------- + +Names of classes, objects, constants, etc. are given in **boldface** font. +Often they are also links to a more detailed documentation of the +referred object. + +This manual contains many examples of use, usually prefixed with the +Python prompt ``>>>`` (which is not a part of the example code). The +examples assume that you have first entered:: + +>>> import numpy as np + +before running the examples. diff --git a/doc/source/bugs.rst b/doc/source/bugs.rst new file mode 100644 index 0000000..950934b --- /dev/null +++ b/doc/source/bugs.rst @@ -0,0 +1,19 @@ +************** +Reporting bugs +************** + +File bug reports or feature requests, and make contributions +(e.g. code patches), by opening a "new issue" on GitHub: + +- NumPy Issues: http://github.com/numpy/numpy/issues + +Please give as much information as you can in the ticket. It is extremely +useful if you can supply a small self-contained code snippet that reproduces +the problem. Also specify the component, the version you are referring to and +the milestone. + +Report bugs to the appropriate GitHub project (there is one for NumPy +and a different one for SciPy). + +More information can be found on the http://scipy.org/Developer_Zone +website. diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 0000000..7c34a62 --- /dev/null +++ b/doc/source/conf.py @@ -0,0 +1,345 @@ +# -*- coding: utf-8 -*- +from __future__ import division, absolute_import, print_function + +import sys, os, re + +# Check Sphinx version +import sphinx +if sphinx.__version__ < "1.2.1": + raise RuntimeError("Sphinx 1.2.1 or newer required") + +needs_sphinx = '1.0' + +# ----------------------------------------------------------------------------- +# General configuration +# ----------------------------------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. + +sys.path.insert(0, os.path.abspath('../sphinxext')) + +extensions = ['sphinx.ext.autodoc', 'numpydoc', + 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', + 'sphinx.ext.doctest', 'sphinx.ext.autosummary', + 'sphinx.ext.graphviz', + 'matplotlib.sphinxext.plot_directive'] + +if sphinx.__version__ >= "1.4": + extensions.append('sphinx.ext.imgmath') + imgmath_image_format = 'svg' +else: + extensions.append('sphinx.ext.pngmath') + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# General substitutions. +project = 'NumPy' +copyright = '2008-2017, The SciPy community' + +# The default replacements for |version| and |release|, also used in various +# other places throughout the built documents. +# +import numpy +# The short X.Y version (including .devXXXX, rcX, b1 suffixes if present) +version = re.sub(r'(\d+\.\d+)\.\d+(.*)', r'\1\2', numpy.__version__) +version = re.sub(r'(\.dev\d+).*?$', r'\1', version) +# The full version, including alpha/beta/rc tags. +release = numpy.__version__ +print("%s %s" % (version, release)) + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +default_role = "autolink" + +# List of directories, relative to source directories, that shouldn't be searched +# for source files. +exclude_dirs = [] + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = False + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# ----------------------------------------------------------------------------- +# HTML output +# ----------------------------------------------------------------------------- + +themedir = os.path.join(os.pardir, 'scipy-sphinx-theme', '_theme') +if not os.path.isdir(themedir): + raise RuntimeError("Get the scipy-sphinx-theme first, " + "via git submodule init && git submodule update") + +html_theme = 'scipy' +html_theme_path = [themedir] + +if 'scipyorg' in tags: + # Build for the scipy.org website + html_theme_options = { + "edit_link": True, + "sidebar": "right", + "scipy_org_logo": True, + "rootlinks": [("http://scipy.org/", "Scipy.org"), + ("http://docs.scipy.org/", "Docs")] + } +else: + # Default build + html_theme_options = { + "edit_link": False, + "sidebar": "left", + "scipy_org_logo": False, + "rootlinks": [] + } + html_sidebars = {'index': 'indexsidebar.html'} + +html_additional_pages = { + 'index': 'indexcontent.html', +} + +html_title = "%s v%s Manual" % (project, version) +html_static_path = ['_static'] +html_last_updated_fmt = '%b %d, %Y' + +html_use_modindex = True +html_copy_source = False +html_domain_indices = False +html_file_suffix = '.html' + +htmlhelp_basename = 'numpy' + +if 'sphinx.ext.pngmath' in extensions: + pngmath_use_preview = True + pngmath_dvipng_args = ['-gamma', '1.5', '-D', '96', '-bg', 'Transparent'] + +plot_html_show_formats = False +plot_html_show_source_link = False + +# ----------------------------------------------------------------------------- +# LaTeX output +# ----------------------------------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, document class [howto/manual]). +_stdauthor = 'Written by the NumPy community' +latex_documents = [ + ('reference/index', 'numpy-ref.tex', 'NumPy Reference', + _stdauthor, 'manual'), + ('user/index', 'numpy-user.tex', 'NumPy User Guide', + _stdauthor, 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +latex_preamble = r''' +\usepackage{amsmath} +\DeclareUnicodeCharacter{00A0}{\nobreakspace} + +% In the parameters section, place a newline after the Parameters +% header +\usepackage{expdlist} +\let\latexdescription=\description +\def\description{\latexdescription{}{} \breaklabel} + +% Make Examples/etc section headers smaller and more compact +\makeatletter +\titleformat{\paragraph}{\normalsize\py@HeaderFamily}% + {\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor} +\titlespacing*{\paragraph}{0pt}{1ex}{0pt} +\makeatother + +% Fix footer/header +\renewcommand{\chaptermark}[1]{\markboth{\MakeUppercase{\thechapter.\ #1}}{}} +\renewcommand{\sectionmark}[1]{\markright{\MakeUppercase{\thesection.\ #1}}} +''' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +latex_use_modindex = False + + +# ----------------------------------------------------------------------------- +# Texinfo output +# ----------------------------------------------------------------------------- + +texinfo_documents = [ + ("contents", 'numpy', 'NumPy Documentation', _stdauthor, 'NumPy', + "NumPy: array processing for numbers, strings, records, and objects.", + 'Programming', + 1), +] + + +# ----------------------------------------------------------------------------- +# Intersphinx configuration +# ----------------------------------------------------------------------------- +intersphinx_mapping = { + 'python': ('https://docs.python.org/dev', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/reference', None), + 'matplotlib': ('http://matplotlib.org', None) +} + + +# ----------------------------------------------------------------------------- +# NumPy extensions +# ----------------------------------------------------------------------------- + +# If we want to do a phantom import from an XML file for all autodocs +phantom_import_file = 'dump.xml' + +# Make numpydoc to generate plots for example sections +numpydoc_use_plots = True + +# ----------------------------------------------------------------------------- +# Autosummary +# ----------------------------------------------------------------------------- + +import glob +autosummary_generate = glob.glob("reference/*.rst") + +# ----------------------------------------------------------------------------- +# Coverage checker +# ----------------------------------------------------------------------------- +coverage_ignore_modules = r""" + """.split() +coverage_ignore_functions = r""" + test($|_) (some|all)true bitwise_not cumproduct pkgload + generic\. + """.split() +coverage_ignore_classes = r""" + """.split() + +coverage_c_path = [] +coverage_c_regexes = {} +coverage_ignore_c_items = {} + + +# ----------------------------------------------------------------------------- +# Plots +# ----------------------------------------------------------------------------- +plot_pre_code = """ +import numpy as np +np.random.seed(0) +""" +plot_include_source = True +plot_formats = [('png', 100), 'pdf'] + +import math +phi = (math.sqrt(5) + 1)/2 + +plot_rcparams = { + 'font.size': 8, + 'axes.titlesize': 8, + 'axes.labelsize': 8, + 'xtick.labelsize': 8, + 'ytick.labelsize': 8, + 'legend.fontsize': 8, + 'figure.figsize': (3*phi, 3), + 'figure.subplot.bottom': 0.2, + 'figure.subplot.left': 0.2, + 'figure.subplot.right': 0.9, + 'figure.subplot.top': 0.85, + 'figure.subplot.wspace': 0.4, + 'text.usetex': False, +} + + +# ----------------------------------------------------------------------------- +# Source code links +# ----------------------------------------------------------------------------- + +import inspect +from os.path import relpath, dirname + +for name in ['sphinx.ext.linkcode', 'numpydoc.linkcode']: + try: + __import__(name) + extensions.append(name) + break + except ImportError: + pass +else: + print("NOTE: linkcode extension not found -- no links to source generated") + +def linkcode_resolve(domain, info): + """ + Determine the URL corresponding to Python object + """ + if domain != 'py': + return None + + modname = info['module'] + fullname = info['fullname'] + + submod = sys.modules.get(modname) + if submod is None: + return None + + obj = submod + for part in fullname.split('.'): + try: + obj = getattr(obj, part) + except Exception: + return None + + try: + fn = inspect.getsourcefile(obj) + except Exception: + fn = None + if not fn: + return None + + try: + source, lineno = inspect.getsourcelines(obj) + except Exception: + lineno = None + + if lineno: + linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1) + else: + linespec = "" + + fn = relpath(fn, start=dirname(numpy.__file__)) + + if 'dev' in numpy.__version__: + return "http://github.com/numpy/numpy/blob/master/numpy/%s%s" % ( + fn, linespec) + else: + return "http://github.com/numpy/numpy/blob/v%s/numpy/%s%s" % ( + numpy.__version__, fn, linespec) diff --git a/doc/source/contents.rst b/doc/source/contents.rst new file mode 100644 index 0000000..61c0037 --- /dev/null +++ b/doc/source/contents.rst @@ -0,0 +1,16 @@ +##################### +NumPy manual contents +##################### + +.. toctree:: + + user/index + reference/index + f2py/index + dev/index + neps/index + release + about + bugs + license + glossary diff --git a/doc/source/dev/development_environment.rst b/doc/source/dev/development_environment.rst new file mode 100644 index 0000000..e6df980 --- /dev/null +++ b/doc/source/dev/development_environment.rst @@ -0,0 +1,227 @@ +.. _development-environment: + +Setting up and using your development environment +================================================= + + +Recommended development setup +----------------------------- + +Since NumPy contains parts written in C and Cython that need to be +compiled before use, make sure you have the necessary compilers and Python +development headers installed - see :ref:`building-from-source`. + +Having compiled code also means that importing NumPy from the development +sources needs some additional steps, which are explained below. For the rest +of this chapter we assume that you have set up your git repo as described in +:ref:`using-git`. + +To build the development version of NumPy and run tests, spawn +interactive shells with the Python import paths properly set up etc., +do one of:: + + $ python runtests.py -v + $ python runtests.py -v -s random + $ python runtests.py -v -t numpy/core/tests/test_iter.py:test_iter_c_order + $ python runtests.py --ipython + $ python runtests.py --python somescript.py + $ python runtests.py --bench + $ python runtests.py -g -m full + +This builds NumPy first, so the first time it may take a few minutes. If +you specify ``-n``, the tests are run against the version of NumPy (if +any) found on current PYTHONPATH. + +When specifying a target using ``-s``, ``-t``, or ``--python``, additional +arguments may be forwarded to the target embedded by ``runtests.py`` by passing +the extra arguments after a bare ``--``. For example, to run a test method with +the ``--pdb`` flag forwarded to nose, run the following:: + + $ python runtests.py -t numpy/tests/test_scripts.py:test_f2py -- --pdb + +Using ``runtests.py`` is the recommended approach to running tests. +There are also a number of alternatives to it, for example in-place +build or installing to a virtualenv. See the FAQ below for details. + + +Building in-place +----------------- + +For development, you can set up an in-place build so that changes made to +``.py`` files have effect without rebuild. First, run:: + + $ python setup.py build_ext -i + +This allows you to import the in-place built NumPy *from the repo base +directory only*. If you want the in-place build to be visible outside that +base dir, you need to point your ``PYTHONPATH`` environment variable to this +directory. Some IDEs (Spyder for example) have utilities to manage +``PYTHONPATH``. On Linux and OSX, you can run the command:: + + $ export PYTHONPATH=$PWD + +and on Windows:: + + $ set PYTHONPATH=/path/to/numpy + +Now editing a Python source file in NumPy allows you to immediately +test and use your changes (in ``.py`` files), by simply restarting the +interpreter. + +Note that another way to do an inplace build visible outside the repo base dir +is with ``python setup.py develop``. Instead of adjusting ``PYTHONPATH``, this +installs a ``.egg-link`` file into your site-packages as well as adjusts the +``easy-install.pth`` there, so its a more permanent (and magical) operation. + + +Other build options +------------------- + +It's possible to do a parallel build with ``numpy.distutils`` with the ``-j`` option; +see :ref:`parallel-builds` for more details. + +In order to install the development version of NumPy in ``site-packages``, use +``python setup.py install --user``. + +A similar approach to in-place builds and use of ``PYTHONPATH`` but outside the +source tree is to use:: + + $ python setup.py install --prefix /some/owned/folder + $ export PYTHONPATH=/some/owned/folder/lib/python3.4/site-packages + + +Using virtualenvs +----------------- + +A frequently asked question is "How do I set up a development version of NumPy +in parallel to a released version that I use to do my job/research?". + +One simple way to achieve this is to install the released version in +site-packages, by using a binary installer or pip for example, and set +up the development version in a virtualenv. First install +`virtualenv`_ (optionally use `virtualenvwrapper`_), then create your +virtualenv (named numpy-dev here) with:: + + $ virtualenv numpy-dev + +Now, whenever you want to switch to the virtual environment, you can use the +command ``source numpy-dev/bin/activate``, and ``deactivate`` to exit from the +virtual environment and back to your previous shell. + + +Running tests +------------- + +Besides using ``runtests.py``, there are various ways to run the tests. Inside +the interpreter, tests can be run like this:: + + >>> np.test() + >>> np.test('full') # Also run tests marked as slow + >>> np.test('full', verbose=2) # Additionally print test name/file + +Or a similar way from the command line:: + + $ python -c "import numpy as np; np.test()" + +Tests can also be run with ``nosetests numpy``, however then the NumPy-specific +``nose`` plugin is not found which causes tests marked as ``KnownFailure`` to +be reported as errors. + +Running individual test files can be useful; it's much faster than running the +whole test suite or that of a whole module (example: ``np.random.test()``). +This can be done with:: + + $ python path_to_testfile/test_file.py + +That also takes extra arguments, like ``--pdb`` which drops you into the Python +debugger when a test fails or an exception is raised. + +Running tests with `tox`_ is also supported. For example, to build NumPy and +run the test suite with Python 3.4, use:: + + $ tox -e py34 + +For more extensive info on running and writing tests, see +https://github.com/numpy/numpy/blob/master/doc/TESTS.rst.txt . + +*Note: do not run the tests from the root directory of your numpy git repo, +that will result in strange test errors.* + + +Rebuilding & cleaning the workspace +----------------------------------- + +Rebuilding NumPy after making changes to compiled code can be done with the +same build command as you used previously - only the changed files will be +re-built. Doing a full build, which sometimes is necessary, requires cleaning +the workspace first. The standard way of doing this is (*note: deletes any +uncommitted files!*):: + + $ git clean -xdf + +When you want to discard all changes and go back to the last commit in the +repo, use one of:: + + $ git checkout . + $ git reset --hard + + +Debugging +--------- + +Another frequently asked question is "How do I debug C code inside NumPy?". +The easiest way to do this is to first write a Python script that invokes the C +code whose execution you want to debug. For instance ``mytest.py``:: + + from numpy import linspace + x = np.arange(5) + np.empty_like(x) + +Now, you can run:: + + $ gdb --args python runtests.py -g --python mytest.py + +And then in the debugger:: + + (gdb) break array_empty_like + (gdb) run + +The execution will now stop at the corresponding C function and you can step +through it as usual. With the Python extensions for gdb installed (often the +default on Linux), a number of useful Python-specific commands are available. +For example to see where in the Python code you are, use ``py-list``. For more +details, see `DebuggingWithGdb`_. + +Instead of plain ``gdb`` you can of course use your favourite +alternative debugger; run it on the python binary with arguments +``runtests.py -g --python mytest.py``. + +Building NumPy with a Python built with debug support (on Linux distributions +typically packaged as ``python-dbg``) is highly recommended. + + + +.. _DebuggingWithGdb: https://wiki.python.org/moin/DebuggingWithGdb + +.. _tox: http://tox.testrun.org + +.. _virtualenv: http://www.virtualenv.org/ + +.. _virtualenvwrapper: http://www.doughellmann.com/projects/virtualenvwrapper/ + +.. _Waf: https://code.google.com/p/waf/ + +Understanding the code & getting started +---------------------------------------- + +The best strategy to better understand the code base is to pick something you +want to change and start reading the code to figure out how it works. When in +doubt, you can ask questions on the mailing list. It is perfectly okay if your +pull requests aren't perfect, the community is always happy to help. As a +volunteer project, things do sometimes get dropped and it's totally fine to +ping us if something has sat without a response for about two to four weeks. + +So go ahead and pick something that annoys or confuses you about numpy, +experiment with the code, hang around for discussions or go through the +reference documents to try to fix it. Things will fall in place and soon +you'll have a pretty good understanding of the project as a whole. Good Luck! diff --git a/doc/source/dev/gitwash/configure_git.rst b/doc/source/dev/gitwash/configure_git.rst new file mode 100644 index 0000000..c62f336 --- /dev/null +++ b/doc/source/dev/gitwash/configure_git.rst @@ -0,0 +1,123 @@ +.. _configure-git: + +================= +Git configuration +================= + +.. _git-config-basic: + +Overview +======== + +Your personal git_ configurations are saved in the ``.gitconfig`` file in +your home directory. +Here is an example ``.gitconfig`` file:: + + [user] + name = Your Name + email = you@yourdomain.example.com + + [alias] + ci = commit -a + co = checkout + st = status -a + stat = status -a + br = branch + wdiff = diff --color-words + + [core] + editor = vim + + [merge] + summary = true + +You can edit this file directly or you can use the ``git config --global`` +command:: + + git config --global user.name "Your Name" + git config --global user.email you@yourdomain.example.com + git config --global alias.ci "commit -a" + git config --global alias.co checkout + git config --global alias.st "status -a" + git config --global alias.stat "status -a" + git config --global alias.br branch + git config --global alias.wdiff "diff --color-words" + git config --global core.editor vim + git config --global merge.summary true + +To set up on another computer, you can copy your ``~/.gitconfig`` file, +or run the commands above. + +In detail +========= + +user.name and user.email +------------------------ + +It is good practice to tell git_ who you are, for labeling any changes +you make to the code. The simplest way to do this is from the command +line:: + + git config --global user.name "Your Name" + git config --global user.email you@yourdomain.example.com + +This will write the settings into your git configuration file, which +should now contain a user section with your name and email:: + + [user] + name = Your Name + email = you@yourdomain.example.com + +Of course you'll need to replace ``Your Name`` and ``you@yourdomain.example.com`` +with your actual name and email address. + +Aliases +------- + +You might well benefit from some aliases to common commands. + +For example, you might well want to be able to shorten ``git checkout`` +to ``git co``. Or you may want to alias ``git diff --color-words`` +(which gives a nicely formatted output of the diff) to ``git wdiff`` + +The following ``git config --global`` commands:: + + git config --global alias.ci "commit -a" + git config --global alias.co checkout + git config --global alias.st "status -a" + git config --global alias.stat "status -a" + git config --global alias.br branch + git config --global alias.wdiff "diff --color-words" + +will create an ``alias`` section in your ``.gitconfig`` file with contents +like this:: + + [alias] + ci = commit -a + co = checkout + st = status -a + stat = status -a + br = branch + wdiff = diff --color-words + +Editor +------ + +You may also want to make sure that your editor of choice is used :: + + git config --global core.editor vim + +Merging +------- + +To enforce summaries when doing merges (``~/.gitconfig`` file again):: + + [merge] + log = true + +Or from the command line:: + + git config --global merge.log true + + +.. include:: git_links.inc diff --git a/doc/source/dev/gitwash/development_setup.rst b/doc/source/dev/gitwash/development_setup.rst new file mode 100644 index 0000000..1ebd4b4 --- /dev/null +++ b/doc/source/dev/gitwash/development_setup.rst @@ -0,0 +1,143 @@ +==================================== +Getting started with Git development +==================================== + +This section and the next describe in detail how to set up git for working +with the NumPy source code. If you have git already set up, skip to +:ref:`development-workflow`. + +Basic Git setup +############### + +* :ref:`install-git`. +* Introduce yourself to Git:: + + git config --global user.email you@yourdomain.example.com + git config --global user.name "Your Name Comes Here" + +.. _forking: + +Making your own copy (fork) of NumPy +#################################### + +You need to do this only once. The instructions here are very similar +to the instructions at http://help.github.com/forking/ - please see that +page for more detail. We're repeating some of it here just to give the +specifics for the NumPy_ project, and to suggest some default names. + +Set up and configure a github_ account +====================================== + +If you don't have a github_ account, go to the github_ page, and make one. + +You then need to configure your account to allow write access - see the +``Generating SSH keys`` help on `github help`_. + +Create your own forked copy of NumPy_ +========================================= + +#. Log into your github_ account. +#. Go to the NumPy_ github home at `NumPy github`_. +#. Click on the *fork* button: + + .. image:: forking_button.png + + After a short pause, you should find yourself at the home page for + your own forked copy of NumPy_. + +.. include:: git_links.inc + + +.. _set-up-fork: + +Set up your fork +################ + +First you follow the instructions for :ref:`forking`. + +Overview +======== + +:: + + git clone https://github.com/your-user-name/numpy.git + cd numpy + git remote add upstream https://github.com/numpy/numpy.git + +In detail +========= + +Clone your fork +--------------- + +#. Clone your fork to the local computer with ``git clone + https://github.com/your-user-name/numpy.git`` +#. Investigate. Change directory to your new repo: ``cd numpy``. Then + ``git branch -a`` to show you all branches. You'll get something + like:: + + * master + remotes/origin/master + + This tells you that you are currently on the ``master`` branch, and + that you also have a ``remote`` connection to ``origin/master``. + What remote repository is ``remote/origin``? Try ``git remote -v`` to + see the URLs for the remote. They will point to your github_ fork. + + Now you want to connect to the upstream `NumPy github`_ repository, so + you can merge in changes from trunk. + +.. _linking-to-upstream: + +Linking your repository to the upstream repo +-------------------------------------------- + +:: + + cd numpy + git remote add upstream https://github.com/numpy/numpy.git + +``upstream`` here is just the arbitrary name we're using to refer to the +main NumPy_ repository at `NumPy github`_. + +Just for your own satisfaction, show yourself that you now have a new +'remote', with ``git remote -v show``, giving you something like:: + + upstream https://github.com/numpy/numpy.git (fetch) + upstream https://github.com/numpy/numpy.git (push) + origin https://github.com/your-user-name/numpy.git (fetch) + origin https://github.com/your-user-name/numpy.git (push) + +To keep in sync with changes in NumPy, you want to set up your repository +so it pulls from ``upstream`` by default. This can be done with:: + + git config branch.master.remote upstream + git config branch.master.merge refs/heads/master + +You may also want to have easy access to all pull requests sent to the +NumPy repository:: + + git config --add remote.upstream.fetch '+refs/pull/*/head:refs/remotes/upstream/pr/*' + +Your config file should now look something like (from +``$ cat .git/config``):: + + [core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = false + [remote "origin"] + url = https://github.com/your-user-name/numpy.git + fetch = +refs/heads/*:refs/remotes/origin/* + [remote "upstream"] + url = https://github.com/numpy/numpy.git + fetch = +refs/heads/*:refs/remotes/upstream/* + fetch = +refs/pull/*/head:refs/remotes/upstream/pr/* + [branch "master"] + remote = upstream + merge = refs/heads/master + +.. include:: git_links.inc diff --git a/doc/source/dev/gitwash/development_workflow.rst b/doc/source/dev/gitwash/development_workflow.rst new file mode 100644 index 0000000..5476e32 --- /dev/null +++ b/doc/source/dev/gitwash/development_workflow.rst @@ -0,0 +1,510 @@ +.. _development-workflow: + +==================== +Development workflow +==================== + +You already have your own forked copy of the NumPy_ repository, by +following :ref:`forking`, :ref:`set-up-fork`, you have configured git_ +by following :ref:`configure-git`, and have linked the upstream +repository as explained in :ref:`linking-to-upstream`. + +What is described below is a recommended workflow with Git. + +Basic workflow +############## + +In short: + +1. Start a new *feature branch* for each set of edits that you do. + See :ref:`below `. + +2. Hack away! See :ref:`below ` + +3. When finished: + + - *Contributors*: push your feature branch to your own Github repo, and + :ref:`create a pull request `. + + - *Core developers* If you want to push changes without + further review, see the notes :ref:`below `. + +This way of working helps to keep work well organized and the history +as clear as possible. + +.. seealso:: + + There are many online tutorials to help you `learn git`_. For discussions + of specific git workflows, see these discussions on `linux git workflow`_, + and `ipython git workflow`_. + +.. _making-a-new-feature-branch: + +Making a new feature branch +=========================== + +First, fetch new commits from the ``upstream`` repository: + +:: + + git fetch upstream + +Then, create a new branch based on the master branch of the upstream +repository:: + + git checkout -b my-new-feature upstream/master + + +.. _editing-workflow: + +The editing workflow +==================== + +Overview +-------- + +:: + + # hack hack + git status # Optional + git diff # Optional + git add modified_file + git commit + # push the branch to your own Github repo + git push origin my-new-feature + +In more detail +-------------- + +#. Make some changes. When you feel that you've made a complete, working set + of related changes, move on to the next steps. + +#. Optional: Check which files have changed with ``git status`` (see `git + status`_). You'll see a listing like this one:: + + # On branch my-new-feature + # Changed but not updated: + # (use "git add ..." to update what will be committed) + # (use "git checkout -- ..." to discard changes in working directory) + # + # modified: README + # + # Untracked files: + # (use "git add ..." to include in what will be committed) + # + # INSTALL + no changes added to commit (use "git add" and/or "git commit -a") + +#. Optional: Compare the changes with the previous version using with ``git + diff`` (`git diff`_). This brings up a simple text browser interface that + highlights the difference between your files and the previous version. + +#. Add any relevant modified or new files using ``git add modified_file`` + (see `git add`_). This puts the files into a staging area, which is a queue + of files that will be added to your next commit. Only add files that have + related, complete changes. Leave files with unfinished changes for later + commits. + +#. To commit the staged files into the local copy of your repo, do ``git + commit``. At this point, a text editor will open up to allow you to write a + commit message. Read the :ref:`commit message + section` to be sure that you are writing a + properly formatted and sufficiently detailed commit message. After saving + your message and closing the editor, your commit will be saved. For trivial + commits, a short commit message can be passed in through the command line + using the ``-m`` flag. For example, ``git commit -am "ENH: Some message"``. + + In some cases, you will see this form of the commit command: ``git commit + -a``. The extra ``-a`` flag automatically commits all modified files and + removes all deleted files. This can save you some typing of numerous ``git + add`` commands; however, it can add unwanted changes to a commit if you're + not careful. For more information, see `why the -a flag?`_ - and the + helpful use-case description in the `tangled working copy problem`_. + +#. Push the changes to your forked repo on github_:: + + git push origin my-new-feature + + For more information, see `git push`_. + +.. note:: + + Assuming you have followed the instructions in these pages, git will create + a default link to your github_ repo called ``origin``. In git >= 1.7 you + can ensure that the link to origin is permanently set by using the + ``--set-upstream`` option:: + + git push --set-upstream origin my-new-feature + + From now on git_ will know that ``my-new-feature`` is related to the + ``my-new-feature`` branch in your own github_ repo. Subsequent push calls + are then simplified to the following:: + + git push + + You have to use ``--set-upstream`` for each new branch that you create. + + +It may be the case that while you were working on your edits, new commits have +been added to ``upstream`` that affect your work. In this case, follow the +:ref:`rebasing-on-master` section of this document to apply those changes to +your branch. + +.. _writing-the-commit-message: + +Writing the commit message +-------------------------- + +Commit messages should be clear and follow a few basic rules. Example:: + + ENH: add functionality X to numpy.. + + The first line of the commit message starts with a capitalized acronym + (options listed below) indicating what type of commit this is. Then a blank + line, then more text if needed. Lines shouldn't be longer than 72 + characters. If the commit is related to a ticket, indicate that with + "See #3456", "See ticket 3456", "Closes #3456" or similar. + +Describing the motivation for a change, the nature of a bug for bug fixes or +some details on what an enhancement does are also good to include in a commit +message. Messages should be understandable without looking at the code +changes. A commit message like ``MAINT: fixed another one`` is an example of +what not to do; the reader has to go look for context elsewhere. + +Standard acronyms to start the commit message with are:: + + API: an (incompatible) API change + BENCH: changes to the benchmark suite + BLD: change related to building numpy + BUG: bug fix + DEP: deprecate something, or remove a deprecated object + DEV: development tool or utility + DOC: documentation + ENH: enhancement + MAINT: maintenance commit (refactoring, typos, etc.) + REV: revert an earlier commit + STY: style fix (whitespace, PEP8) + TST: addition or modification of tests + REL: related to releasing numpy + + +.. _asking-for-merging: + +Asking for your changes to be merged with the main repo +======================================================= + +When you feel your work is finished, you can create a pull request (PR). Github +has a nice help page that outlines the process for `filing pull requests`_. + +If your changes involve modifications to the API or addition/modification of a +function, you should initiate a code review. This involves sending an email to +the `NumPy mailing list`_ with a link to your PR along with a description of +and a motivation for your changes. + +.. _rebasing-on-master: + +Rebasing on master +================== + +This updates your feature branch with changes from the upstream `NumPy +github`_ repo. If you do not absolutely need to do this, try to avoid doing +it, except perhaps when you are finished. The first step will be to update +the remote repository with new commits from upstream:: + + git fetch upstream + +Next, you need to update the feature branch:: + + # go to the feature branch + git checkout my-new-feature + # make a backup in case you mess up + git branch tmp my-new-feature + # rebase on upstream master branch + git rebase upstream/master + +If you have made changes to files that have changed also upstream, +this may generate merge conflicts that you need to resolve. See +:ref:`below` for help in this case. + +Finally, remove the backup branch upon a successful rebase:: + + git branch -D tmp + + +.. note:: + + Rebasing on master is preferred over merging upstream back to your + branch. Using ``git merge`` and ``git pull`` is discouraged when + working on feature branches. + +.. _recovering-from-mess-up: + +Recovering from mess-ups +======================== + +Sometimes, you mess up merges or rebases. Luckily, in Git it is +relatively straightforward to recover from such mistakes. + +If you mess up during a rebase:: + + git rebase --abort + +If you notice you messed up after the rebase:: + + # reset branch back to the saved point + git reset --hard tmp + +If you forgot to make a backup branch:: + + # look at the reflog of the branch + git reflog show my-feature-branch + + 8630830 my-feature-branch@{0}: commit: BUG: io: close file handles immediately + 278dd2a my-feature-branch@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d + 26aa21a my-feature-branch@{2}: commit: BUG: lib: make seek_gzip_factory not leak gzip obj + ... + + # reset the branch to where it was before the botched rebase + git reset --hard my-feature-branch@{2} + +If you didn't actually mess up but there are merge conflicts, you need to +resolve those. This can be one of the trickier things to get right. For a +good description of how to do this, see `this article on merging conflicts`_. + + +Additional things you might want to do +###################################### + +.. _rewriting-commit-history: + +Rewriting commit history +======================== + +.. note:: + + Do this only for your own feature branches. + +There's an embarrassing typo in a commit you made? Or perhaps the you +made several false starts you would like the posterity not to see. + +This can be done via *interactive rebasing*. + +Suppose that the commit history looks like this:: + + git log --oneline + eadc391 Fix some remaining bugs + a815645 Modify it so that it works + 2dec1ac Fix a few bugs + disable + 13d7934 First implementation + 6ad92e5 * masked is now an instance of a new object, MaskedConstant + 29001ed Add pre-nep for a copule of structured_array_extensions. + ... + +and ``6ad92e5`` is the last commit in the ``master`` branch. Suppose we +want to make the following changes: + +* Rewrite the commit message for ``13d7934`` to something more sensible. +* Combine the commits ``2dec1ac``, ``a815645``, ``eadc391`` into a single one. + +We do as follows:: + + # make a backup of the current state + git branch tmp HEAD + # interactive rebase + git rebase -i 6ad92e5 + +This will open an editor with the following text in it:: + + pick 13d7934 First implementation + pick 2dec1ac Fix a few bugs + disable + pick a815645 Modify it so that it works + pick eadc391 Fix some remaining bugs + + # Rebase 6ad92e5..eadc391 onto 6ad92e5 + # + # Commands: + # p, pick = use commit + # r, reword = use commit, but edit the commit message + # e, edit = use commit, but stop for amending + # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # + # If you remove a line here THAT COMMIT WILL BE LOST. + # However, if you remove everything, the rebase will be aborted. + # + +To achieve what we want, we will make the following changes to it:: + + r 13d7934 First implementation + pick 2dec1ac Fix a few bugs + disable + f a815645 Modify it so that it works + f eadc391 Fix some remaining bugs + +This means that (i) we want to edit the commit message for +``13d7934``, and (ii) collapse the last three commits into one. Now we +save and quit the editor. + +Git will then immediately bring up an editor for editing the commit +message. After revising it, we get the output:: + + [detached HEAD 721fc64] FOO: First implementation + 2 files changed, 199 insertions(+), 66 deletions(-) + [detached HEAD 0f22701] Fix a few bugs + disable + 1 files changed, 79 insertions(+), 61 deletions(-) + Successfully rebased and updated refs/heads/my-feature-branch. + +and the history looks now like this:: + + 0f22701 Fix a few bugs + disable + 721fc64 ENH: Sophisticated feature + 6ad92e5 * masked is now an instance of a new object, MaskedConstant + +If it went wrong, recovery is again possible as explained :ref:`above +`. + +Deleting a branch on github_ +============================ + +:: + + git checkout master + # delete branch locally + git branch -D my-unwanted-branch + # delete branch on github + git push origin :my-unwanted-branch + +(Note the colon ``:`` before ``test-branch``. See also: +http://github.com/guides/remove-a-remote-branch + + +Several people sharing a single repository +========================================== + +If you want to work on some stuff with other people, where you are all +committing into the same repository, or even the same branch, then just +share it via github_. + +First fork NumPy into your account, as from :ref:`forking`. + +Then, go to your forked repository github page, say +``http://github.com/your-user-name/numpy`` + +Click on the 'Admin' button, and add anyone else to the repo as a +collaborator: + + .. image:: pull_button.png + +Now all those people can do:: + + git clone git@githhub.com:your-user-name/numpy.git + +Remember that links starting with ``git@`` use the ssh protocol and are +read-write; links starting with ``git://`` are read-only. + +Your collaborators can then commit directly into that repo with the +usual:: + + git commit -am 'ENH - much better code' + git push origin my-feature-branch # pushes directly into your repo + +Exploring your repository +========================= + +To see a graphical representation of the repository branches and +commits:: + + gitk --all + +To see a linear list of commits for this branch:: + + git log + +You can also look at the `network graph visualizer`_ for your github_ +repo. + +Backporting +=========== + +Backporting is the process of copying new feature/fixes committed in +`numpy/master`_ back to stable release branches. To do this you make a branch +off the branch you are backporting to, cherry pick the commits you want from +``numpy/master``, and then submit a pull request for the branch containing the +backport. + +1. First, you need to make the branch you will work on. This needs to be + based on the older version of NumPy (not master):: + + # Make a new branch based on numpy/maintenance/1.8.x, + # backport-3324 is our new name for the branch. + git checkout -b backport-3324 upstream/maintenance/1.8.x + +2. Now you need to apply the changes from master to this branch using + `git cherry-pick`_:: + + # Update remote + git fetch upstream + # Check the commit log for commits to cherry pick + git log upstream/master + # This pull request included commits aa7a047 to c098283 (inclusive) + # so you use the .. syntax (for a range of commits), the ^ makes the + # range inclusive. + git cherry-pick aa7a047^..c098283 + ... + # Fix any conflicts, then if needed: + git cherry-pick --continue + +3. You might run into some conflicts cherry picking here. These are + resolved the same way as merge/rebase conflicts. Except here you can + use `git blame`_ to see the difference between master and the + backported branch to make sure nothing gets screwed up. + +4. Push the new branch to your Github repository:: + + git push -u origin backport-3324 + +5. Finally make a pull request using Github. Make sure it is against the + maintenance branch and not master, Github will usually suggest you + make the pull request against master. + +.. _pushing-to-main: + +Pushing changes to the main repo +================================ + +*This is only relevant if you have commit rights to the main NumPy repo.* + +When you have a set of "ready" changes in a feature branch ready for +NumPy's ``master`` or ``maintenance`` branches, you can push +them to ``upstream`` as follows: + +1. First, merge or rebase on the target branch. + + a) Only a few, unrelated commits then prefer rebasing:: + + git fetch upstream + git rebase upstream/master + + See :ref:`rebasing-on-master`. + + b) If all of the commits are related, create a merge commit:: + + git fetch upstream + git merge --no-ff upstream/master + +2. Check that what you are going to push looks sensible:: + + git log -p upstream/master.. + git log --oneline --graph + +3. Push to upstream:: + + git push upstream my-feature-branch:master + +.. note:: + + It's usually a good idea to use the ``-n`` flag to ``git push`` to check + first that you're about to push the changes you want to the place you + want. + + +.. include:: git_links.inc diff --git a/doc/source/dev/gitwash/dot2_dot3.rst b/doc/source/dev/gitwash/dot2_dot3.rst new file mode 100644 index 0000000..7759e2e --- /dev/null +++ b/doc/source/dev/gitwash/dot2_dot3.rst @@ -0,0 +1,28 @@ +.. _dot2-dot3: + +======================================== + Two and three dots in difference specs +======================================== + +Thanks to Yarik Halchenko for this explanation. + +Imagine a series of commits A, B, C, D... Imagine that there are two +branches, *topic* and *master*. You branched *topic* off *master* when +*master* was at commit 'E'. The graph of the commits looks like this:: + + + A---B---C topic + / + D---E---F---G master + +Then:: + + git diff master..topic + +will output the difference from G to C (i.e. with effects of F and G), +while:: + + git diff master...topic + +would output just differences in the topic branch (i.e. only A, B, and +C). diff --git a/doc/source/dev/gitwash/following_latest.rst b/doc/source/dev/gitwash/following_latest.rst new file mode 100644 index 0000000..ad497bf --- /dev/null +++ b/doc/source/dev/gitwash/following_latest.rst @@ -0,0 +1,42 @@ +.. _following-latest: + +============================= + Following the latest source +============================= + +These are the instructions if you just want to follow the latest +*NumPy* source, but you don't need to do any development for now. +If you do want to contribute a patch (excellent!) or do more extensive +NumPy development, see :ref:`development-workflow`. + +The steps are: + +* :ref:`install-git` +* get local copy of the git repository from Github_ +* update local copy from time to time + +Get the local copy of the code +============================== + +From the command line:: + + git clone git://github.com/numpy/numpy.git + +You now have a copy of the code tree in the new ``numpy`` directory. +If this doesn't work you can try the alternative read-only url:: + + git clone https://github.com/numpy/numpy.git + +Updating the code +================= + +From time to time you may want to pull down the latest code. Do this with:: + + cd numpy + git fetch + git merge --ff-only + +The tree in ``numpy`` will now have the latest changes from the initial +repository. + +.. _Github: https://github.com/numpy diff --git a/doc/source/dev/gitwash/forking_button.png b/doc/source/dev/gitwash/forking_button.png new file mode 100644 index 0000000..d0e0413 Binary files /dev/null and b/doc/source/dev/gitwash/forking_button.png differ diff --git a/doc/source/dev/gitwash/git_development.rst b/doc/source/dev/gitwash/git_development.rst new file mode 100644 index 0000000..ee7787f --- /dev/null +++ b/doc/source/dev/gitwash/git_development.rst @@ -0,0 +1,14 @@ +.. _git-development: + +===================== + Git for development +===================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + development_setup + configure_git + development_workflow diff --git a/doc/source/dev/gitwash/git_intro.rst b/doc/source/dev/gitwash/git_intro.rst new file mode 100644 index 0000000..3ce322f --- /dev/null +++ b/doc/source/dev/gitwash/git_intro.rst @@ -0,0 +1,42 @@ +============ +Introduction +============ + +These pages describe a git_ and github_ workflow for the NumPy_ +project. + +There are several different workflows here, for different ways of +working with *NumPy*. + +This is not a comprehensive git_ reference, it's just a workflow for our +own project. It's tailored to the github_ hosting service. You may well +find better or quicker ways of getting stuff done with git_, but these +should get you started. + +For general resources for learning git_ see :ref:`git-resources`. + +.. _install-git: + +Install git +=========== + +Overview +-------- + +================ ============= +Debian / Ubuntu ``sudo apt-get install git-core`` +Fedora ``sudo yum install git-core`` +Windows Download and install msysGit_ +OS X Use the git-osx-installer_ +================ ============= + +In detail +--------- + +See the git_ page for the most recent information. + +Have a look at the github_ install help pages available from `github help`_ + +There are good instructions here: http://book.git-scm.com/2_installing_git.html + +.. include:: git_links.inc diff --git a/doc/source/dev/gitwash/git_links.inc b/doc/source/dev/gitwash/git_links.inc new file mode 100644 index 0000000..30532da --- /dev/null +++ b/doc/source/dev/gitwash/git_links.inc @@ -0,0 +1,65 @@ +.. This (-*- rst -*-) format file contains commonly used link targets + and name substitutions. It may be included in many files, + therefore it should only contain link targets and name + substitutions. Try grepping for "^\.\. _" to find plausible + candidates for this list. + +.. NOTE: reST targets are + __not_case_sensitive__, so only one target definition is needed for + nipy, NIPY, Nipy, etc... + +.. git stuff +.. _git: http://git-scm.com/ +.. _github: http://github.com +.. _github help: http://help.github.com +.. _msysgit: http://code.google.com/p/msysgit/downloads/list +.. _git-osx-installer: http://code.google.com/p/git-osx-installer/downloads/list +.. _subversion: http://subversion.tigris.org/ +.. _git cheat sheet: http://github.com/guides/git-cheat-sheet +.. _pro git book: http://progit.org/ +.. _git svn crash course: http://git-scm.com/course/svn.html +.. _learn.github: http://learn.github.com/ +.. _network graph visualizer: http://github.com/blog/39-say-hello-to-the-network-graph-visualizer +.. _git user manual: http://www.kernel.org/pub/software/scm/git/docs/user-manual.html +.. _git tutorial: http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html +.. _git community book: http://book.git-scm.com/ +.. _git ready: http://www.gitready.com/ +.. _git casts: http://www.gitcasts.com/ +.. _Fernando's git page: http://www.fperez.org/py4science/git.html +.. _git magic: http://www-cs-students.stanford.edu/~blynn/gitmagic/index.html +.. _git concepts: http://www.eecs.harvard.edu/~cduan/technical/git/ +.. _git clone: http://www.kernel.org/pub/software/scm/git/docs/git-clone.html +.. _git checkout: http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html +.. _git commit: http://www.kernel.org/pub/software/scm/git/docs/git-commit.html +.. _git push: http://www.kernel.org/pub/software/scm/git/docs/git-push.html +.. _git pull: http://www.kernel.org/pub/software/scm/git/docs/git-pull.html +.. _git add: http://www.kernel.org/pub/software/scm/git/docs/git-add.html +.. _git status: http://www.kernel.org/pub/software/scm/git/docs/git-status.html +.. _git diff: http://www.kernel.org/pub/software/scm/git/docs/git-diff.html +.. _git log: http://www.kernel.org/pub/software/scm/git/docs/git-log.html +.. _git branch: http://www.kernel.org/pub/software/scm/git/docs/git-branch.html +.. _git remote: http://www.kernel.org/pub/software/scm/git/docs/git-remote.html +.. _git config: http://www.kernel.org/pub/software/scm/git/docs/git-config.html +.. _why the -a flag?: http://www.gitready.com/beginner/2009/01/18/the-staging-area.html +.. _git staging area: http://www.gitready.com/beginner/2009/01/18/the-staging-area.html +.. _tangled working copy problem: http://tomayko.com/writings/the-thing-about-git +.. _git management: http://kerneltrap.org/Linux/Git_Management +.. _linux git workflow: http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html +.. _ipython git workflow: http://mail.python.org/pipermail/ipython-dev/2010-October/006746.html +.. _git parable: http://tom.preston-werner.com/2009/05/19/the-git-parable.html +.. _git foundation: http://matthew-brett.github.com/pydagogue/foundation.html +.. _numpy/master: https://github.com/numpy/numpy +.. _git cherry-pick: https://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html +.. _git blame: https://www.kernel.org/pub/software/scm/git/docs/git-blame.html +.. _this blog post: http://github.com/blog/612-introducing-github-compare-view +.. _this article on merging conflicts: http://git-scm.com/book/en/Git-Branching-Basic-Branching-and-Merging#Basic-Merge-Conflicts +.. _learn git: https://www.atlassian.com/git/tutorials/ +.. _filing pull requests: https://help.github.com/articles/using-pull-requests/#initiating-the-pull-request +.. _pull request review: https://help.github.com/articles/using-pull-requests/#reviewing-the-pull-request + + +.. other stuff +.. _python: http://www.python.org +.. _NumPy: http://www.numpy.org +.. _`NumPy github`: http://github.com/numpy/numpy +.. _`NumPy mailing list`: http://scipy.org/Mailing_Lists diff --git a/doc/source/dev/gitwash/git_resources.rst b/doc/source/dev/gitwash/git_resources.rst new file mode 100644 index 0000000..5f0c1d0 --- /dev/null +++ b/doc/source/dev/gitwash/git_resources.rst @@ -0,0 +1,58 @@ +.. _git-resources: + +================ + git_ resources +================ + +Tutorials and summaries +======================= + +* `github help`_ has an excellent series of how-to guides. +* `learn.github`_ has an excellent series of tutorials +* The `pro git book`_ is a good in-depth book on git. +* A `git cheat sheet`_ is a page giving summaries of common commands. +* The `git user manual`_ +* The `git tutorial`_ +* The `git community book`_ +* `git ready`_ - a nice series of tutorials +* `git casts`_ - video snippets giving git how-tos. +* `git magic`_ - extended introduction with intermediate detail +* The `git parable`_ is an easy read explaining the concepts behind git. +* Our own `git foundation`_ expands on the `git parable`_. +* Fernando Perez' git page - `Fernando's git page`_ - many links and tips +* A good but technical page on `git concepts`_ +* `git svn crash course`_: git_ for those of us used to subversion_ + +Advanced git workflow +===================== + +There are many ways of working with git_; here are some posts on the +rules of thumb that other projects have come up with: + +* Linus Torvalds on `git management`_ +* Linus Torvalds on `linux git workflow`_ . Summary; use the git tools + to make the history of your edits as clean as possible; merge from + upstream edits as little as possible in branches where you are doing + active development. + +Manual pages online +=================== + +You can get these on your own machine with (e.g) ``git help push`` or +(same thing) ``git push --help``, but, for convenience, here are the +online manual pages for some common commands: + +* `git add`_ +* `git branch`_ +* `git checkout`_ +* `git clone`_ +* `git commit`_ +* `git config`_ +* `git diff`_ +* `git log`_ +* `git pull`_ +* `git push`_ +* `git remote`_ +* `git status`_ + +.. include:: git_links.inc diff --git a/doc/source/dev/gitwash/index.rst b/doc/source/dev/gitwash/index.rst new file mode 100644 index 0000000..ae7ce69 --- /dev/null +++ b/doc/source/dev/gitwash/index.rst @@ -0,0 +1,14 @@ +.. _using-git: + +Working with *NumPy* source code +================================ + +Contents: + +.. toctree:: + :maxdepth: 2 + + git_intro + following_latest + git_development + git_resources diff --git a/doc/source/dev/gitwash/pull_button.png b/doc/source/dev/gitwash/pull_button.png new file mode 100644 index 0000000..e503168 Binary files /dev/null and b/doc/source/dev/gitwash/pull_button.png differ diff --git a/doc/source/dev/gitwash_links.txt b/doc/source/dev/gitwash_links.txt new file mode 100644 index 0000000..f953682 --- /dev/null +++ b/doc/source/dev/gitwash_links.txt @@ -0,0 +1,3 @@ +.. _NumPy: http://www.numpy.org +.. _`NumPy github`: http://github.com/numpy/numpy +.. _`NumPy mailing list`: http://scipy.org/Mailing_Lists diff --git a/doc/source/dev/governance/governance.rst b/doc/source/dev/governance/governance.rst new file mode 100644 index 0000000..54e5236 --- /dev/null +++ b/doc/source/dev/governance/governance.rst @@ -0,0 +1,400 @@ +================================================================ + NumPy project governance and decision-making +================================================================ + +The purpose of this document is to formalize the governance process +used by the NumPy project in both ordinary and extraordinary +situations, and to clarify how decisions are made and how the various +elements of our community interact, including the relationship between +open source collaborative development and work that may be funded by +for-profit or non-profit entities. + +Summary +======= + +NumPy is a community-owned and community-run project. To the maximum +extent possible, decisions about project direction are made by community +consensus (but note that "consensus" here has a somewhat technical +meaning that might not match everyone's expectations -- see below). Some +members of the community additionally contribute by serving on the NumPy +steering council, where they are responsible for facilitating the +establishment of community consensus, for stewarding project resources, +and -- in extreme cases -- for making project decisions if the normal +community-based process breaks down. + +The Project +=========== + +The NumPy Project (The Project) is an open source software project +affiliated with the 501(c)3 NumFOCUS Foundation. The goal of The Project +is to develop open source software for array-based computing in Python, +and in particular the ``numpy`` package, along with related software +such as ``f2py`` and the NumPy Sphinx extensions. The Software developed +by The Project is released under the BSD (or similar) open source +license, developed openly and hosted on public GitHub repositories under +the ``numpy`` GitHub organization. + +The Project is developed by a team of distributed developers, called +Contributors. Contributors are individuals who have contributed code, +documentation, designs or other work to the Project. Anyone can be a +Contributor. Contributors can be affiliated with any legal entity or +none. Contributors participate in the project by submitting, reviewing +and discussing GitHub Pull Requests and Issues and participating in open +and public Project discussions on GitHub, mailing lists, and other +channels. The foundation of Project participation is openness and +transparency. + +The Project Community consists of all Contributors and Users of the +Project. Contributors work on behalf of and are responsible to the +larger Project Community and we strive to keep the barrier between +Contributors and Users as low as possible. + +The Project is formally affiliated with the 501(c)3 NumFOCUS Foundation +(http://numfocus.org), which serves as its fiscal sponsor, may hold +project trademarks and other intellectual property, helps manage project +donations and acts as a parent legal entity. NumFOCUS is the only legal +entity that has a formal relationship with the project (see +Institutional Partners section below). + +Governance +========== + +This section describes the governance and leadership model of The +Project. + +The foundations of Project governance are: + +- Openness & Transparency +- Active Contribution +- Institutional Neutrality + +Consensus-based decision making by the community +------------------------------------------------ + +Normally, all project decisions will be made by consensus of all +interested Contributors. The primary goal of this approach is to ensure +that the people who are most affected by and involved in any given +change can contribute their knowledge in the confidence that their +voices will be heard, because thoughtful review from a broad community +is the best mechanism we know of for creating high-quality software. + +The mechanism we use to accomplish this goal may be unfamiliar for those +who are not experienced with the cultural norms around free/open-source +software development. We provide a summary here, and highly recommend +that all Contributors additionally read `Chapter 4: Social and Political +Infrastructure `_ +of Karl Fogel's classic *Producing Open Source Software*, and in +particular the section on `Consensus-based +Democracy `_, +for a more detailed discussion. + +In this context, consensus does *not* require: + +- that we wait to solicit everybody's opinion on every change, +- that we ever hold a vote on anything, +- or that everybody is happy or agrees with every decision. + +For us, what consensus means is that we entrust *everyone* with the +right to veto any change if they feel it necessary. While this may sound +like a recipe for obstruction and pain, this is not what happens. +Instead, we find that most people take this responsibility seriously, +and only invoke their veto when they judge that a serious problem is +being ignored, and that their veto is necessary to protect the project. +And in practice, it turns out that such vetoes are almost never formally +invoked, because their mere possibility ensures that Contributors are +motivated from the start to find some solution that everyone can live +with -- thus accomplishing our goal of ensuring that all interested +perspectives are taken into account. + +How do we know when consensus has been achieved? In principle, this is +rather difficult, since consensus is defined by the absence of vetos, +which requires us to somehow prove a negative. In practice, we use a +combination of our best judgement (e.g., a simple and uncontroversial +bug fix posted on GitHub and reviewed by a core developer is probably +fine) and best efforts (e.g., all substantive API changes must be posted +to the mailing list in order to give the broader community a chance to +catch any problems and suggest improvements; we assume that anyone who +cares enough about NumPy to invoke their veto right should be on the +mailing list). If no-one bothers to comment on the mailing list after a +few days, then it's probably fine. And worst case, if a change is more +controversial than expected, or a crucial critique is delayed because +someone was on vacation, then it's no big deal: we apologize for +misjudging the situation, `back up, and sort things +out `_. + +If one does need to invoke a formal veto, then it should consist of: + +- an unambiguous statement that a veto is being invoked, +- an explanation of why it is being invoked, and +- a description of what conditions (if any) would convince the vetoer + to withdraw their veto. + +If all proposals for resolving some issue are vetoed, then the status +quo wins by default. + +In the worst case, if a Contributor is genuinely misusing their veto in +an obstructive fashion to the detriment of the project, then they can be +ejected from the project by consensus of the Steering Council -- see +below. + +Steering Council +---------------- + +The Project will have a Steering Council that consists of Project +Contributors who have produced contributions that are substantial in +quality and quantity, and sustained over at least one year. The overall +role of the Council is to ensure, with input from the Community, the +long-term well-being of the project, both technically and as a +community. + +During the everyday project activities, council members participate in +all discussions, code review and other project activities as peers with +all other Contributors and the Community. In these everyday activities, +Council Members do not have any special power or privilege through their +membership on the Council. However, it is expected that because of the +quality and quantity of their contributions and their expert knowledge +of the Project Software and Services that Council Members will provide +useful guidance, both technical and in terms of project direction, to +potentially less experienced contributors. + +The Steering Council and its Members play a special role in certain +situations. In particular, the Council may, if necessary: + +- Make decisions about the overall scope, vision and direction of the + project. +- Make decisions about strategic collaborations with other + organizations or individuals. +- Make decisions about specific technical issues, features, bugs and + pull requests. They are the primary mechanism of guiding the code + review process and merging pull requests. +- Make decisions about the Services that are run by The Project and + manage those Services for the benefit of the Project and Community. +- Update policy documents such as this one. +- Make decisions when regular community discussion doesn’t produce + consensus on an issue in a reasonable time frame. + +However, the Council's primary responsibility is to facilitate the +ordinary community-based decision making procedure described above. If +we ever have to step in and formally override the community for the +health of the Project, then we will do so, but we will consider reaching +this point to indicate a failure in our leadership. + +Council decision making +~~~~~~~~~~~~~~~~~~~~~~~ + +If it becomes necessary for the Steering Council to produce a formal +decision, then they will use a form of the `Apache Foundation voting +process `_. This is a +formalized version of consensus, in which +1 votes indicate agreement, +-1 votes are vetoes (and must be accompanied with a rationale, as +above), and one can also vote fractionally (e.g. -0.5, +0.5) if one +wishes to express an opinion without registering a full veto. These +numeric votes are also often used informally as a way of getting a +general sense of people's feelings on some issue, and should not +normally be taken as formal votes. A formal vote only occurs if +explicitly declared, and if this does occur then the vote should be held +open for long enough to give all interested Council Members a chance to +respond -- at least one week. + +In practice, we anticipate that for most Steering Council decisions +(e.g., voting in new members) a more informal process will suffice. + +Council membership +~~~~~~~~~~~~~~~~~~ + +A list of current Steering Council Members is maintained at the +page :ref:`governance-people`. + +To become eligible to join the Steering Council, an individual must be +a Project Contributor who has produced contributions that are +substantial in quality and quantity, and sustained over at least one +year. Potential Council Members are nominated by existing Council +members, and become members following consensus of the existing +Council members, and confirmation that the potential Member is +interested and willing to serve in that capacity. The Council will be +initially formed from the set of existing Core Developers who, as of +late 2015, have been significantly active over the last year. + +When considering potential Members, the Council will look at candidates +with a comprehensive view of their contributions. This will include but +is not limited to code, code review, infrastructure work, mailing list +and chat participation, community help/building, education and outreach, +design work, etc. We are deliberately not setting arbitrary quantitative +metrics (like “100 commits in this repo”) to avoid encouraging behavior +that plays to the metrics rather than the project’s overall well-being. +We want to encourage a diverse array of backgrounds, viewpoints and +talents in our team, which is why we explicitly do not define code as +the sole metric on which council membership will be evaluated. + +If a Council member becomes inactive in the project for a period of one +year, they will be considered for removal from the Council. Before +removal, inactive Member will be approached to see if they plan on +returning to active participation. If not they will be removed +immediately upon a Council vote. If they plan on returning to active +participation soon, they will be given a grace period of one year. If +they don’t return to active participation within that time period they +will be removed by vote of the Council without further grace period. All +former Council members can be considered for membership again at any +time in the future, like any other Project Contributor. Retired Council +members will be listed on the project website, acknowledging the period +during which they were active in the Council. + +The Council reserves the right to eject current Members, if they are +deemed to be actively harmful to the project’s well-being, and attempts +at communication and conflict resolution have failed. This requires the +consensus of the remaining Members. + + +Conflict of interest +~~~~~~~~~~~~~~~~~~~~ + +It is expected that the Council Members will be employed at a wide range +of companies, universities and non-profit organizations. Because of +this, it is possible that Members will have conflict of interests. Such +conflict of interests include, but are not limited to: + +- Financial interests, such as investments, employment or contracting + work, outside of The Project that may influence their work on The + Project. +- Access to proprietary information of their employer that could + potentially leak into their work with the Project. + +All members of the Council shall disclose to the rest of the Council any +conflict of interest they may have. Members with a conflict of interest +in a particular issue may participate in Council discussions on that +issue, but must recuse themselves from voting on the issue. + +Private communications of the Council +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To the maximum extent possible, Council discussions and activities +will be public and done in collaboration and discussion with the +Project Contributors and Community. The Council will have a private +mailing list that will be used sparingly and only when a specific +matter requires privacy. When private communications and decisions are +needed, the Council will do its best to summarize those to the +Community after eliding personal/private/sensitive information that +should not be posted to the public internet. + +Subcommittees +~~~~~~~~~~~~~ + +The Council can create subcommittees that provide leadership and +guidance for specific aspects of the project. Like the Council as a +whole, subcommittees should conduct their business in an open and public +manner unless privacy is specifically called for. Private subcommittee +communications should happen on the main private mailing list of the +Council unless specifically called for. + +NumFOCUS Subcommittee +~~~~~~~~~~~~~~~~~~~~~ + +The Council will maintain one narrowly focused subcommittee to manage +its interactions with NumFOCUS. + +- The NumFOCUS Subcommittee is comprised of 5 persons who manage + project funding that comes through NumFOCUS. It is expected that + these funds will be spent in a manner that is consistent with the + non-profit mission of NumFOCUS and the direction of the Project as + determined by the full Council. +- This Subcommittee shall NOT make decisions about the direction, scope + or technical direction of the Project. +- This Subcommittee will have 5 members, 4 of whom will be current + Council Members and 1 of whom will be external to the Steering + Council. No more than 2 Subcommitee Members can report to one person + through employment or contracting work (including the reportee, i.e. + the reportee + 1 is the max). This avoids effective majorities + resting on one person. + +The current membership of the NumFOCUS Subcommittee is listed at the +page :ref:`governance-people`. + + +Institutional Partners and Funding +================================== + +The Steering Council are the primary leadership for the project. No +outside institution, individual or legal entity has the ability to own, +control, usurp or influence the project other than by participating in +the Project as Contributors and Council Members. However, because +institutions can be an important funding mechanism for the project, it +is important to formally acknowledge institutional participation in the +project. These are Institutional Partners. + +An Institutional Contributor is any individual Project Contributor who +contributes to the project as part of their official duties at an +Institutional Partner. Likewise, an Institutional Council Member is any +Project Steering Council Member who contributes to the project as part +of their official duties at an Institutional Partner. + +With these definitions, an Institutional Partner is any recognized legal +entity in the United States or elsewhere that employs at least 1 +Institutional Contributor of Institutional Council Member. Institutional +Partners can be for-profit or non-profit entities. + +Institutions become eligible to become an Institutional Partner by +employing individuals who actively contribute to The Project as part of +their official duties. To state this another way, the only way for a +Partner to influence the project is by actively contributing to the open +development of the project, in equal terms to any other member of the +community of Contributors and Council Members. Merely using Project +Software in institutional context does not allow an entity to become an +Institutional Partner. Financial gifts do not enable an entity to become +an Institutional Partner. Once an institution becomes eligible for +Institutional Partnership, the Steering Council must nominate and +approve the Partnership. + +If at some point an existing Institutional Partner stops having any +contributing employees, then a one year grace period commences. If at +the end of this one year period they continue not to have any +contributing employees, then their Institutional Partnership will +lapse, and resuming it will require going through the normal process +for new Partnerships. + +An Institutional Partner is free to pursue funding for their work on The +Project through any legal means. This could involve a non-profit +organization raising money from private foundations and donors or a +for-profit company building proprietary products and services that +leverage Project Software and Services. Funding acquired by +Institutional Partners to work on The Project is called Institutional +Funding. However, no funding obtained by an Institutional Partner can +override the Steering Council. If a Partner has funding to do NumPy work +and the Council decides to not pursue that work as a project, the +Partner is free to pursue it on their own. However in this situation, +that part of the Partner’s work will not be under the NumPy umbrella and +cannot use the Project trademarks in a way that suggests a formal +relationship. + +Institutional Partner benefits are: + +- Acknowledgement on the NumPy websites, in talks and T-shirts. +- Ability to acknowledge their own funding sources on the NumPy + websites, in talks and T-shirts. +- Ability to influence the project through the participation of their + Council Member. +- Council Members invited to NumPy Developer Meetings. + +A list of current Institutional Partners is maintained at the page +:ref:`governance-people`. + + +Document history +================ + +https://github.com/numpy/numpy/commits/master/doc/source/dev/governance/governance.rst + +Acknowledgements +================ + +Substantial portions of this document were adapted from the +`Jupyter/IPython project's governance document +`_. + +License +======= + +To the extent possible under law, the authors have waived all +copyright and related or neighboring rights to the NumPy project +governance and decision-making document, as per the `CC-0 public +domain dedication / license +`_. diff --git a/doc/source/dev/governance/index.rst b/doc/source/dev/governance/index.rst new file mode 100644 index 0000000..3919e5e --- /dev/null +++ b/doc/source/dev/governance/index.rst @@ -0,0 +1,9 @@ +##################### +NumPy governance +##################### + +.. toctree:: + :maxdepth: 3 + + governance + people diff --git a/doc/source/dev/governance/people.rst b/doc/source/dev/governance/people.rst new file mode 100644 index 0000000..b22852a --- /dev/null +++ b/doc/source/dev/governance/people.rst @@ -0,0 +1,63 @@ +.. _governance-people: + +Current steering council and institutional partners +=================================================== + +Steering council +---------------- + +* Sebastian Berg + +* Jaime Fernández del Río + +* Ralf Gommers + +* Charles Harris + +* Nathaniel Smith + +* Julian Taylor + +* Pauli Virtanen + +* Eric Wieser + +* Marten van Kerkwijk + +* Stephan Hoyer + +* Allan Haldane + + +Emeritus members +---------------- + +* Travis Oliphant - Project Founder / Emeritus Leader (served: 2005-2012) + +* Alex Griffing (served: 2015-2017) + + +NumFOCUS Subcommittee +--------------------- + +* Chuck Harris + +* Ralf Gommers + +* Jaime Fernández del Río + +* Nathaniel Smith + +* External member: Thomas Caswell + + +Institutional Partners +---------------------- + +* UC Berkeley (Nathaniel Smith) + + +Document history +---------------- + +https://github.com/numpy/numpy/commits/master/doc/source/dev/governance/governance.rst diff --git a/doc/source/dev/index.rst b/doc/source/dev/index.rst new file mode 100644 index 0000000..5431941 --- /dev/null +++ b/doc/source/dev/index.rst @@ -0,0 +1,12 @@ +##################### +Contributing to NumPy +##################### + +.. toctree:: + :maxdepth: 3 + + gitwash/index + development_environment + governance/index + +For core developers: see :ref:`development-workflow`. diff --git a/doc/source/f2py/advanced.rst b/doc/source/f2py/advanced.rst new file mode 100644 index 0000000..c9f3862 --- /dev/null +++ b/doc/source/f2py/advanced.rst @@ -0,0 +1,45 @@ +====================== +Advanced F2PY usages +====================== + +Adding self-written functions to F2PY generated modules +======================================================= + +Self-written Python C/API functions can be defined inside +signature files using ``usercode`` and ``pymethoddef`` statements +(they must be used inside the ``python module`` block). For +example, the following signature file ``spam.pyf`` + +.. include:: spam.pyf + :literal: + +wraps the C library function ``system()``:: + + f2py -c spam.pyf + +In Python: + +.. include:: spam_session.dat + :literal: + +Modifying the dictionary of a F2PY generated module +=================================================== + +The following example illustrates how to add a user-defined +variables to a F2PY generated extension module. Given the following +signature file + +.. include:: var.pyf + :literal: + +compile it as ``f2py -c var.pyf``. + +Notice that the second ``usercode`` statement must be defined inside +an ``interface`` block and where the module dictionary is available through +the variable ``d`` (see ``f2py var.pyf``-generated ``varmodule.c`` for +additional details). + +In Python: + +.. include:: var_session.dat + :literal: diff --git a/doc/source/f2py/allocarr.f90 b/doc/source/f2py/allocarr.f90 new file mode 100644 index 0000000..e0d6c2e --- /dev/null +++ b/doc/source/f2py/allocarr.f90 @@ -0,0 +1,16 @@ +module mod + real, allocatable, dimension(:,:) :: b +contains + subroutine foo + integer k + if (allocated(b)) then + print*, "b=[" + do k = 1,size(b,1) + print*, b(k,1:size(b,2)) + enddo + print*, "]" + else + print*, "b is not allocated" + endif + end subroutine foo +end module mod diff --git a/doc/source/f2py/allocarr_session.dat b/doc/source/f2py/allocarr_session.dat new file mode 100644 index 0000000..fc91959 --- /dev/null +++ b/doc/source/f2py/allocarr_session.dat @@ -0,0 +1,27 @@ +>>> import allocarr +>>> print allocarr.mod.__doc__ +b - 'f'-array(-1,-1), not allocated +foo - Function signature: + foo() + +>>> allocarr.mod.foo() + b is not allocated +>>> allocarr.mod.b = [[1,2,3],[4,5,6]] # allocate/initialize b +>>> allocarr.mod.foo() + b=[ + 1.000000 2.000000 3.000000 + 4.000000 5.000000 6.000000 + ] +>>> allocarr.mod.b # b is Fortran-contiguous +array([[ 1., 2., 3.], + [ 4., 5., 6.]],'f') +>>> allocarr.mod.b = [[1,2,3],[4,5,6],[7,8,9]] # reallocate/initialize b +>>> allocarr.mod.foo() + b=[ + 1.000000 2.000000 3.000000 + 4.000000 5.000000 6.000000 + 7.000000 8.000000 9.000000 + ] +>>> allocarr.mod.b = None # deallocate array +>>> allocarr.mod.foo() + b is not allocated diff --git a/doc/source/f2py/array.f b/doc/source/f2py/array.f new file mode 100644 index 0000000..ef20c9c --- /dev/null +++ b/doc/source/f2py/array.f @@ -0,0 +1,17 @@ +C FILE: ARRAY.F + SUBROUTINE FOO(A,N,M) +C +C INCREMENT THE FIRST ROW AND DECREMENT THE FIRST COLUMN OF A +C + INTEGER N,M,I,J + REAL*8 A(N,M) +Cf2py intent(in,out,copy) a +Cf2py integer intent(hide),depend(a) :: n=shape(a,0), m=shape(a,1) + DO J=1,M + A(1,J) = A(1,J) + 1D0 + ENDDO + DO I=1,N + A(I,1) = A(I,1) - 1D0 + ENDDO + END +C END OF FILE ARRAY.F diff --git a/doc/source/f2py/array_session.dat b/doc/source/f2py/array_session.dat new file mode 100644 index 0000000..069530d --- /dev/null +++ b/doc/source/f2py/array_session.dat @@ -0,0 +1,65 @@ +>>> import arr +>>> from numpy import array +>>> print arr.foo.__doc__ +foo - Function signature: + a = foo(a,[overwrite_a]) +Required arguments: + a : input rank-2 array('d') with bounds (n,m) +Optional arguments: + overwrite_a := 0 input int +Return objects: + a : rank-2 array('d') with bounds (n,m) + +>>> a=arr.foo([[1,2,3], +... [4,5,6]]) +copied an array using PyArray_CopyFromObject: size=6, elsize=8 +>>> print a +[[ 1. 3. 4.] + [ 3. 5. 6.]] +>>> a.iscontiguous(), arr.has_column_major_storage(a) +(0, 1) +>>> b=arr.foo(a) # even if a is proper-contiguous +... # and has proper type, a copy is made +... # forced by intent(copy) attribute +... # to preserve its original contents +... +copied an array using copy_ND_array: size=6, elsize=8 +>>> print a +[[ 1. 3. 4.] + [ 3. 5. 6.]] +>>> print b +[[ 1. 4. 5.] + [ 2. 5. 6.]] +>>> b=arr.foo(a,overwrite_a=1) # a is passed directly to Fortran +... # routine and its contents is discarded +... +>>> print a +[[ 1. 4. 5.] + [ 2. 5. 6.]] +>>> print b +[[ 1. 4. 5.] + [ 2. 5. 6.]] +>>> a is b # a and b are actually the same objects +1 +>>> print arr.foo([1,2,3]) # different rank arrays are allowed +copied an array using PyArray_CopyFromObject: size=3, elsize=8 +[ 1. 1. 2.] +>>> print arr.foo([[[1],[2],[3]]]) +copied an array using PyArray_CopyFromObject: size=3, elsize=8 +[ [[ 1.] + [ 3.] + [ 4.]]] +>>> +>>> # Creating arrays with column major data storage order: +... +>>> s = arr.as_column_major_storage(array([[1,2,3],[4,5,6]])) +copied an array using copy_ND_array: size=6, elsize=4 +>>> arr.has_column_major_storage(s) +1 +>>> print s +[[1 2 3] + [4 5 6]] +>>> s2 = arr.as_column_major_storage(s) +>>> s2 is s # an array with column major storage order + # is returned immediately +1 diff --git a/doc/source/f2py/calculate.f b/doc/source/f2py/calculate.f new file mode 100644 index 0000000..1cda1c8 --- /dev/null +++ b/doc/source/f2py/calculate.f @@ -0,0 +1,14 @@ + subroutine calculate(x,n) +cf2py intent(callback) func + external func +c The following lines define the signature of func for F2PY: +cf2py real*8 y +cf2py y = func(y) +c +cf2py intent(in,out,copy) x + integer n,i + real*8 x(n) + do i=1,n + x(i) = func(x(i)) + end do + end diff --git a/doc/source/f2py/calculate_session.dat b/doc/source/f2py/calculate_session.dat new file mode 100644 index 0000000..2fe64f5 --- /dev/null +++ b/doc/source/f2py/calculate_session.dat @@ -0,0 +1,6 @@ +>>> import foo +>>> foo.calculate(range(5), lambda x: x*x) +array([ 0., 1., 4., 9., 16.]) +>>> import math +>>> foo.calculate(range(5), math.exp) +array([ 1. , 2.71828175, 7.38905621, 20.08553696, 54.59814835]) diff --git a/doc/source/f2py/callback.f b/doc/source/f2py/callback.f new file mode 100644 index 0000000..6e9bfb9 --- /dev/null +++ b/doc/source/f2py/callback.f @@ -0,0 +1,12 @@ +C FILE: CALLBACK.F + SUBROUTINE FOO(FUN,R) + EXTERNAL FUN + INTEGER I + REAL*8 R +Cf2py intent(out) r + R = 0D0 + DO I=-5,5 + R = R + FUN(I) + ENDDO + END +C END OF FILE CALLBACK.F diff --git a/doc/source/f2py/callback2.pyf b/doc/source/f2py/callback2.pyf new file mode 100644 index 0000000..3d77eed --- /dev/null +++ b/doc/source/f2py/callback2.pyf @@ -0,0 +1,19 @@ +! -*- f90 -*- +python module __user__routines + interface + function fun(i) result (r) + integer :: i + real*8 :: r + end function fun + end interface +end python module __user__routines + +python module callback2 + interface + subroutine foo(f,r) + use __user__routines, f=>fun + external f + real*8 intent(out) :: r + end subroutine foo + end interface +end python module callback2 diff --git a/doc/source/f2py/callback_session.dat b/doc/source/f2py/callback_session.dat new file mode 100644 index 0000000..cd2f260 --- /dev/null +++ b/doc/source/f2py/callback_session.dat @@ -0,0 +1,23 @@ +>>> import callback +>>> print callback.foo.__doc__ +foo - Function signature: + r = foo(fun,[fun_extra_args]) +Required arguments: + fun : call-back function +Optional arguments: + fun_extra_args := () input tuple +Return objects: + r : float +Call-back functions: + def fun(i): return r + Required arguments: + i : input int + Return objects: + r : float + +>>> def f(i): return i*i +... +>>> print callback.foo(f) +110.0 +>>> print callback.foo(lambda i:1) +11.0 diff --git a/doc/source/f2py/common.f b/doc/source/f2py/common.f new file mode 100644 index 0000000..b098ab2 --- /dev/null +++ b/doc/source/f2py/common.f @@ -0,0 +1,13 @@ +C FILE: COMMON.F + SUBROUTINE FOO + INTEGER I,X + REAL A + COMMON /DATA/ I,X(4),A(2,3) + PRINT*, "I=",I + PRINT*, "X=[",X,"]" + PRINT*, "A=[" + PRINT*, "[",A(1,1),",",A(1,2),",",A(1,3),"]" + PRINT*, "[",A(2,1),",",A(2,2),",",A(2,3),"]" + PRINT*, "]" + END +C END OF COMMON.F diff --git a/doc/source/f2py/common_session.dat b/doc/source/f2py/common_session.dat new file mode 100644 index 0000000..846fdaa --- /dev/null +++ b/doc/source/f2py/common_session.dat @@ -0,0 +1,27 @@ +>>> import common +>>> print common.data.__doc__ +i - 'i'-scalar +x - 'i'-array(4) +a - 'f'-array(2,3) + +>>> common.data.i = 5 +>>> common.data.x[1] = 2 +>>> common.data.a = [[1,2,3],[4,5,6]] +>>> common.foo() + I= 5 + X=[ 0 2 0 0] + A=[ + [ 1., 2., 3.] + [ 4., 5., 6.] + ] +>>> common.data.a[1] = 45 +>>> common.foo() + I= 5 + X=[ 0 2 0 0] + A=[ + [ 1., 2., 3.] + [ 45., 45., 45.] + ] +>>> common.data.a # a is Fortran-contiguous +array([[ 1., 2., 3.], + [ 45., 45., 45.]],'f') diff --git a/doc/source/f2py/compile_session.dat b/doc/source/f2py/compile_session.dat new file mode 100644 index 0000000..0d84081 --- /dev/null +++ b/doc/source/f2py/compile_session.dat @@ -0,0 +1,11 @@ +>>> import f2py2e +>>> fsource = ''' +... subroutine foo +... print*, "Hello world!" +... end +... ''' +>>> f2py2e.compile(fsource,modulename='hello',verbose=0) +0 +>>> import hello +>>> hello.foo() + Hello world! diff --git a/doc/source/f2py/distutils.rst b/doc/source/f2py/distutils.rst new file mode 100644 index 0000000..fdcd384 --- /dev/null +++ b/doc/source/f2py/distutils.rst @@ -0,0 +1,73 @@ +============================= +Using via `numpy.distutils` +============================= + +:mod:`numpy.distutils` is part of NumPy extending standard Python ``distutils`` +to deal with Fortran sources and F2PY signature files, e.g. compile Fortran +sources, call F2PY to construct extension modules, etc. + +.. topic:: Example + + Consider the following `setup file`__: + + .. include:: setup_example.py + :literal: + + Running + + :: + + python setup_example.py build + + will build two extension modules ``scalar`` and ``fib2`` to the + build directory. + + __ setup_example.py + +:mod:`numpy.distutils` extends ``distutils`` with the following features: + +* ``Extension`` class argument ``sources`` may contain Fortran source + files. In addition, the list ``sources`` may contain at most one + F2PY signature file, and then the name of an Extension module must + match with the ```` used in signature file. It is + assumed that an F2PY signature file contains exactly one ``python + module`` block. + + If ``sources`` does not contain a signature files, then F2PY is used + to scan Fortran source files for routine signatures to construct the + wrappers to Fortran codes. + + Additional options to F2PY process can be given using ``Extension`` + class argument ``f2py_options``. + +* The following new ``distutils`` commands are defined: + + ``build_src`` + to construct Fortran wrapper extension modules, among many other things. + ``config_fc`` + to change Fortran compiler options + + as well as ``build_ext`` and ``build_clib`` commands are enhanced + to support Fortran sources. + + Run + + :: + + python config_fc build_src build_ext --help + + to see available options for these commands. + +* When building Python packages containing Fortran sources, then one + can choose different Fortran compilers by using ``build_ext`` + command option ``--fcompiler=``. Here ```` can be one of the + following names:: + + absoft sun mips intel intelv intele intelev nag compaq compaqv gnu vast pg hpux + + See ``numpy_distutils/fcompiler.py`` for up-to-date list of + supported compilers or run + + :: + + f2py -c --help-fcompiler diff --git a/doc/source/f2py/extcallback.f b/doc/source/f2py/extcallback.f new file mode 100644 index 0000000..9a80062 --- /dev/null +++ b/doc/source/f2py/extcallback.f @@ -0,0 +1,14 @@ + subroutine f1() + print *, "in f1, calling f2 twice.." + call f2() + call f2() + return + end + + subroutine f2() +cf2py intent(callback, hide) fpy + external fpy + print *, "in f2, calling f2py.." + call fpy() + return + end diff --git a/doc/source/f2py/extcallback_session.dat b/doc/source/f2py/extcallback_session.dat new file mode 100644 index 0000000..c22935e --- /dev/null +++ b/doc/source/f2py/extcallback_session.dat @@ -0,0 +1,19 @@ +>>> import pfromf +>>> pfromf.f2() +Traceback (most recent call last): + File "", line 1, in ? +pfromf.error: Callback fpy not defined (as an argument or module pfromf attribute). + +>>> def f(): print "python f" +... +>>> pfromf.fpy = f +>>> pfromf.f2() + in f2, calling f2py.. +python f +>>> pfromf.f1() + in f1, calling f2 twice.. + in f2, calling f2py.. +python f + in f2, calling f2py.. +python f +>>> \ No newline at end of file diff --git a/doc/source/f2py/fib1.f b/doc/source/f2py/fib1.f new file mode 100644 index 0000000..cfbb1ee --- /dev/null +++ b/doc/source/f2py/fib1.f @@ -0,0 +1,18 @@ +C FILE: FIB1.F + SUBROUTINE FIB(A,N) +C +C CALCULATE FIRST N FIBONACCI NUMBERS +C + INTEGER N + REAL*8 A(N) + DO I=1,N + IF (I.EQ.1) THEN + A(I) = 0.0D0 + ELSEIF (I.EQ.2) THEN + A(I) = 1.0D0 + ELSE + A(I) = A(I-1) + A(I-2) + ENDIF + ENDDO + END +C END FILE FIB1.F diff --git a/doc/source/f2py/fib1.pyf b/doc/source/f2py/fib1.pyf new file mode 100644 index 0000000..3d6cc0a --- /dev/null +++ b/doc/source/f2py/fib1.pyf @@ -0,0 +1,12 @@ +! -*- f90 -*- +python module fib2 ! in + interface ! in :fib2 + subroutine fib(a,n) ! in :fib2:fib1.f + real*8 dimension(n) :: a + integer optional,check(len(a)>=n),depend(a) :: n=len(a) + end subroutine fib + end interface +end python module fib2 + +! This file was auto-generated with f2py (version:2.28.198-1366). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/doc/source/f2py/fib2.pyf b/doc/source/f2py/fib2.pyf new file mode 100644 index 0000000..4a5ae29 --- /dev/null +++ b/doc/source/f2py/fib2.pyf @@ -0,0 +1,9 @@ +! -*- f90 -*- +python module fib2 + interface + subroutine fib(a,n) + real*8 dimension(n),intent(out),depend(n) :: a + integer intent(in) :: n + end subroutine fib + end interface +end python module fib2 diff --git a/doc/source/f2py/fib3.f b/doc/source/f2py/fib3.f new file mode 100644 index 0000000..08b050c --- /dev/null +++ b/doc/source/f2py/fib3.f @@ -0,0 +1,21 @@ +C FILE: FIB3.F + SUBROUTINE FIB(A,N) +C +C CALCULATE FIRST N FIBONACCI NUMBERS +C + INTEGER N + REAL*8 A(N) +Cf2py intent(in) n +Cf2py intent(out) a +Cf2py depend(n) a + DO I=1,N + IF (I.EQ.1) THEN + A(I) = 0.0D0 + ELSEIF (I.EQ.2) THEN + A(I) = 1.0D0 + ELSE + A(I) = A(I-1) + A(I-2) + ENDIF + ENDDO + END +C END FILE FIB3.F diff --git a/doc/source/f2py/ftype.f b/doc/source/f2py/ftype.f new file mode 100644 index 0000000..cabbb9e --- /dev/null +++ b/doc/source/f2py/ftype.f @@ -0,0 +1,9 @@ +C FILE: FTYPE.F + SUBROUTINE FOO(N) + INTEGER N +Cf2py integer optional,intent(in) :: n = 13 + REAL A,X + COMMON /DATA/ A,X(3) + PRINT*, "IN FOO: N=",N," A=",A," X=[",X(1),X(2),X(3),"]" + END +C END OF FTYPE.F diff --git a/doc/source/f2py/ftype_session.dat b/doc/source/f2py/ftype_session.dat new file mode 100644 index 0000000..01f9feb --- /dev/null +++ b/doc/source/f2py/ftype_session.dat @@ -0,0 +1,21 @@ +>>> import ftype +>>> print ftype.__doc__ +This module 'ftype' is auto-generated with f2py (version:2.28.198-1366). +Functions: + foo(n=13) +COMMON blocks: + /data/ a,x(3) +. +>>> type(ftype.foo),type(ftype.data) +(, ) +>>> ftype.foo() + IN FOO: N= 13 A= 0. X=[ 0. 0. 0.] +>>> ftype.data.a = 3 +>>> ftype.data.x = [1,2,3] +>>> ftype.foo() + IN FOO: N= 13 A= 3. X=[ 1. 2. 3.] +>>> ftype.data.x[1] = 45 +>>> ftype.foo(24) + IN FOO: N= 24 A= 3. X=[ 1. 45. 3.] +>>> ftype.data.x +array([ 1., 45., 3.],'f') diff --git a/doc/source/f2py/getting-started.rst b/doc/source/f2py/getting-started.rst new file mode 100644 index 0000000..fffd61c --- /dev/null +++ b/doc/source/f2py/getting-started.rst @@ -0,0 +1,261 @@ +====================================== + Three ways to wrap - getting started +====================================== + +Wrapping Fortran or C functions to Python using F2PY consists of the +following steps: + +* Creating the so-called signature file that contains descriptions of + wrappers to Fortran or C functions, also called as signatures of the + functions. In the case of Fortran routines, F2PY can create initial + signature file by scanning Fortran source codes and + catching all relevant information needed to create wrapper + functions. + +* Optionally, F2PY created signature files can be edited to optimize + wrappers functions, make them "smarter" and more "Pythonic". + +* F2PY reads a signature file and writes a Python C/API module containing + Fortran/C/Python bindings. + +* F2PY compiles all sources and builds an extension module containing + the wrappers. In building extension modules, F2PY uses + ``numpy_distutils`` that supports a number of Fortran 77/90/95 + compilers, including Gnu, Intel, + Sun Fortre, SGI MIPSpro, Absoft, NAG, Compaq etc. compilers. + +Depending on a particular situation, these steps can be carried out +either by just in one command or step-by-step, some steps can be +omitted or combined with others. + +Below I'll describe three typical approaches of using F2PY. +The following `example Fortran 77 code`__ will be used for +illustration: + +.. include:: fib1.f + :literal: + +__ fib1.f + +The quick way +============== + +The quickest way to wrap the Fortran subroutine ``FIB`` to Python is +to run + +:: + + f2py -c fib1.f -m fib1 + +This command builds (see ``-c`` flag, execute ``f2py`` without +arguments to see the explanation of command line options) an extension +module ``fib1.so`` (see ``-m`` flag) to the current directory. Now, in +Python the Fortran subroutine ``FIB`` is accessible via ``fib1.fib``:: + + >>> import numpy + >>> import fib1 + >>> print fib1.fib.__doc__ + fib - Function signature: + fib(a,[n]) + Required arguments: + a : input rank-1 array('d') with bounds (n) + Optional arguments: + n := len(a) input int + + >>> a = numpy.zeros(8,'d') + >>> fib1.fib(a) + >>> print a + [ 0. 1. 1. 2. 3. 5. 8. 13.] + +.. note:: + + * Note that F2PY found that the second argument ``n`` is the + dimension of the first array argument ``a``. Since by default all + arguments are input-only arguments, F2PY concludes that ``n`` can + be optional with the default value ``len(a)``. + + * One can use different values for optional ``n``:: + + >>> a1 = numpy.zeros(8,'d') + >>> fib1.fib(a1,6) + >>> print a1 + [ 0. 1. 1. 2. 3. 5. 0. 0.] + + but an exception is raised when it is incompatible with the input + array ``a``:: + + >>> fib1.fib(a,10) + fib:n=10 + Traceback (most recent call last): + File "", line 1, in ? + fib.error: (len(a)>=n) failed for 1st keyword n + >>> + + This demonstrates one of the useful features in F2PY, that it, + F2PY implements basic compatibility checks between related + arguments in order to avoid any unexpected crashes. + + * When a NumPy array, that is Fortran contiguous and has a dtype + corresponding to presumed Fortran type, is used as an input array + argument, then its C pointer is directly passed to Fortran. + + Otherwise F2PY makes a contiguous copy (with a proper dtype) of + the input array and passes C pointer of the copy to Fortran + subroutine. As a result, any possible changes to the (copy of) + input array have no effect to the original argument, as + demonstrated below:: + + >>> a = numpy.ones(8,'i') + >>> fib1.fib(a) + >>> print a + [1 1 1 1 1 1 1 1] + + Clearly, this is not an expected behaviour. The fact that the + above example worked with ``dtype=float`` is considered + accidental. + + F2PY provides ``intent(inplace)`` attribute that would modify + the attributes of an input array so that any changes made by + Fortran routine will be effective also in input argument. For example, + if one specifies ``intent(inplace) a`` (see below, how), then + the example above would read: + + >>> a = numpy.ones(8,'i') + >>> fib1.fib(a) + >>> print a + [ 0. 1. 1. 2. 3. 5. 8. 13.] + + However, the recommended way to get changes made by Fortran + subroutine back to python is to use ``intent(out)`` attribute. It + is more efficient and a cleaner solution. + + * The usage of ``fib1.fib`` in Python is very similar to using + ``FIB`` in Fortran. However, using *in situ* output arguments in + Python indicates a poor style as there is no safety mechanism + in Python with respect to wrong argument types. When using Fortran + or C, compilers naturally discover any type mismatches during + compile time but in Python the types must be checked in + runtime. So, using *in situ* output arguments in Python may cause + difficult to find bugs, not to mention that the codes will be less + readable when all required type checks are implemented. + + Though the demonstrated way of wrapping Fortran routines to Python + is very straightforward, it has several drawbacks (see the comments + above). These drawbacks are due to the fact that there is no way + that F2PY can determine what is the actual intention of one or the + other argument, is it input or output argument, or both, or + something else. So, F2PY conservatively assumes that all arguments + are input arguments by default. + + However, there are ways (see below) how to "teach" F2PY about the + true intentions (among other things) of function arguments; and then + F2PY is able to generate more Pythonic (more explicit, easier to + use, and less error prone) wrappers to Fortran functions. + +The smart way +============== + +Let's apply the steps of wrapping Fortran functions to Python one by +one. + +* First, we create a signature file from ``fib1.f`` by running + + :: + + f2py fib1.f -m fib2 -h fib1.pyf + + The signature file is saved to ``fib1.pyf`` (see ``-h`` flag) and + its contents is shown below. + + .. include:: fib1.pyf + :literal: + +* Next, we'll teach F2PY that the argument ``n`` is an input argument + (use ``intent(in)`` attribute) and that the result, i.e. the + contents of ``a`` after calling Fortran function ``FIB``, should be + returned to Python (use ``intent(out)`` attribute). In addition, an + array ``a`` should be created dynamically using the size given by + the input argument ``n`` (use ``depend(n)`` attribute to indicate + dependence relation). + + The content of a modified version of ``fib1.pyf`` (saved as + ``fib2.pyf``) is as follows: + + .. include:: fib2.pyf + :literal: + +* And finally, we build the extension module by running + + :: + + f2py -c fib2.pyf fib1.f + +In Python:: + + >>> import fib2 + >>> print fib2.fib.__doc__ + fib - Function signature: + a = fib(n) + Required arguments: + n : input int + Return objects: + a : rank-1 array('d') with bounds (n) + + >>> print fib2.fib(8) + [ 0. 1. 1. 2. 3. 5. 8. 13.] + +.. note:: + + * Clearly, the signature of ``fib2.fib`` now corresponds to the + intention of Fortran subroutine ``FIB`` more closely: given the + number ``n``, ``fib2.fib`` returns the first ``n`` Fibonacci numbers + as a NumPy array. Also, the new Python signature ``fib2.fib`` + rules out any surprises that we experienced with ``fib1.fib``. + + * Note that by default using single ``intent(out)`` also implies + ``intent(hide)``. Argument that has ``intent(hide)`` attribute + specified, will not be listed in the argument list of a wrapper + function. + +The quick and smart way +======================== + +The "smart way" of wrapping Fortran functions, as explained above, is +suitable for wrapping (e.g. third party) Fortran codes for which +modifications to their source codes are not desirable nor even +possible. + +However, if editing Fortran codes is acceptable, then the generation +of an intermediate signature file can be skipped in most +cases. Namely, F2PY specific attributes can be inserted directly to +Fortran source codes using the so-called F2PY directive. A F2PY +directive defines special comment lines (starting with ``Cf2py``, for +example) which are ignored by Fortran compilers but F2PY interprets +them as normal lines. + +Here is shown a `modified version of the example Fortran code`__, saved +as ``fib3.f``: + +.. include:: fib3.f + :literal: + +__ fib3.f + +Building the extension module can be now carried out in one command:: + + f2py -c -m fib3 fib3.f + +Notice that the resulting wrapper to ``FIB`` is as "smart" as in +previous case:: + + >>> import fib3 + >>> print fib3.fib.__doc__ + fib - Function signature: + a = fib(n) + Required arguments: + n : input int + Return objects: + a : rank-1 array('d') with bounds (n) + + >>> print fib3.fib(8) + [ 0. 1. 1. 2. 3. 5. 8. 13.] diff --git a/doc/source/f2py/index.rst b/doc/source/f2py/index.rst new file mode 100644 index 0000000..8b7d145 --- /dev/null +++ b/doc/source/f2py/index.rst @@ -0,0 +1,31 @@ +##################################### +F2PY Users Guide and Reference Manual +##################################### + +The purpose of the ``F2PY`` --*Fortran to Python interface generator*-- +is to provide a connection between Python and Fortran +languages. F2PY is a part of NumPy_ (``numpy.f2py``) and also available as a +standalone command line tool ``f2py`` when ``numpy`` is installed that +facilitates creating/building Python C/API extension modules that make it +possible + +* to call Fortran 77/90/95 external subroutines and Fortran 90/95 + module subroutines as well as C functions; +* to access Fortran 77 ``COMMON`` blocks and Fortran 90/95 module data, + including allocatable arrays + +from Python. + +.. toctree:: + :maxdepth: 2 + + getting-started + signature-file + python-usage + usage + distutils + advanced + +.. _Python: http://www.python.org/ +.. _NumPy: http://www.numpy.org/ +.. _SciPy: http://www.numpy.org/ diff --git a/doc/source/f2py/moddata.f90 b/doc/source/f2py/moddata.f90 new file mode 100644 index 0000000..0e98f04 --- /dev/null +++ b/doc/source/f2py/moddata.f90 @@ -0,0 +1,18 @@ +module mod + integer i + integer :: x(4) + real, dimension(2,3) :: a + real, allocatable, dimension(:,:) :: b +contains + subroutine foo + integer k + print*, "i=",i + print*, "x=[",x,"]" + print*, "a=[" + print*, "[",a(1,1),",",a(1,2),",",a(1,3),"]" + print*, "[",a(2,1),",",a(2,2),",",a(2,3),"]" + print*, "]" + print*, "Setting a(1,2)=a(1,2)+3" + a(1,2) = a(1,2)+3 + end subroutine foo +end module mod diff --git a/doc/source/f2py/moddata_session.dat b/doc/source/f2py/moddata_session.dat new file mode 100644 index 0000000..1ec212f --- /dev/null +++ b/doc/source/f2py/moddata_session.dat @@ -0,0 +1,23 @@ +>>> import moddata +>>> print moddata.mod.__doc__ +i - 'i'-scalar +x - 'i'-array(4) +a - 'f'-array(2,3) +foo - Function signature: + foo() + + +>>> moddata.mod.i = 5 +>>> moddata.mod.x[:2] = [1,2] +>>> moddata.mod.a = [[1,2,3],[4,5,6]] +>>> moddata.mod.foo() + i= 5 + x=[ 1 2 0 0 ] + a=[ + [ 1.000000 , 2.000000 , 3.000000 ] + [ 4.000000 , 5.000000 , 6.000000 ] + ] + Setting a(1,2)=a(1,2)+3 +>>> moddata.mod.a # a is Fortran-contiguous +array([[ 1., 5., 3.], + [ 4., 5., 6.]],'f') diff --git a/doc/source/f2py/python-usage.rst b/doc/source/f2py/python-usage.rst new file mode 100644 index 0000000..7986017 --- /dev/null +++ b/doc/source/f2py/python-usage.rst @@ -0,0 +1,369 @@ +================================== +Using F2PY bindings in Python +================================== + +All wrappers for Fortran/C routines, common blocks, or for Fortran +90 module data generated by F2PY are exposed to Python as ``fortran`` +type objects. Routine wrappers are callable ``fortran`` type objects +while wrappers to Fortran data have attributes referring to data +objects. + +All ``fortran`` type object have attribute ``_cpointer`` that contains +CObject referring to the C pointer of the corresponding Fortran/C +function or variable in C level. Such CObjects can be used as a +callback argument of F2PY generated functions to bypass Python C/API +layer of calling Python functions from Fortran or C when the +computational part of such functions is implemented in C or Fortran +and wrapped with F2PY (or any other tool capable of providing CObject +of a function). + +Consider a Fortran 77 file ``ftype.f``: + + .. include:: ftype.f + :literal: + +and build a wrapper using ``f2py -c ftype.f -m ftype``. + +In Python: + + .. include:: ftype_session.dat + :literal: + + +Scalar arguments +================= + +In general, a scalar argument of a F2PY generated wrapper function can +be ordinary Python scalar (integer, float, complex number) as well as +an arbitrary sequence object (list, tuple, array, string) of +scalars. In the latter case, the first element of the sequence object +is passed to Fortran routine as a scalar argument. + +Note that when type-casting is required and there is possible loss of +information (e.g. when type-casting float to integer or complex to +float), F2PY does not raise any exception. In complex to real +type-casting only the real part of a complex number is used. + +``intent(inout)`` scalar arguments are assumed to be array objects in +order to *in situ* changes to be effective. It is recommended to use +arrays with proper type but also other types work. + +Consider the following Fortran 77 code: + + .. include:: scalar.f + :literal: + +and wrap it using ``f2py -c -m scalar scalar.f``. + +In Python: + + .. include:: scalar_session.dat + :literal: + + +String arguments +================= + +F2PY generated wrapper functions accept (almost) any Python object as +a string argument, ``str`` is applied for non-string objects. +Exceptions are NumPy arrays that must have type code ``'c'`` or +``'1'`` when used as string arguments. + +A string can have arbitrary length when using it as a string argument +to F2PY generated wrapper function. If the length is greater than +expected, the string is truncated. If the length is smaller that +expected, additional memory is allocated and filled with ``\0``. + +Because Python strings are immutable, an ``intent(inout)`` argument +expects an array version of a string in order to *in situ* changes to +be effective. + +Consider the following Fortran 77 code: + + .. include:: string.f + :literal: + +and wrap it using ``f2py -c -m mystring string.f``. + +Python session: + + .. include:: string_session.dat + :literal: + + +Array arguments +================ + +In general, array arguments of F2PY generated wrapper functions accept +arbitrary sequences that can be transformed to NumPy array objects. +An exception is ``intent(inout)`` array arguments that always must be +proper-contiguous and have proper type, otherwise an exception is +raised. Another exception is ``intent(inplace)`` array arguments that +attributes will be changed in-situ if the argument has different type +than expected (see ``intent(inplace)`` attribute for more +information). + +In general, if a NumPy array is proper-contiguous and has a proper +type then it is directly passed to wrapped Fortran/C function. +Otherwise, an element-wise copy of an input array is made and the +copy, being proper-contiguous and with proper type, is used as an +array argument. + +There are two types of proper-contiguous NumPy arrays: + +* Fortran-contiguous arrays when data is stored column-wise, + i.e. indexing of data as stored in memory starts from the lowest + dimension; +* C-contiguous or simply contiguous arrays when data is stored + row-wise, i.e. indexing of data as stored in memory starts from the + highest dimension. + +For one-dimensional arrays these notions coincide. + +For example, a 2x2 array ``A`` is Fortran-contiguous if its elements +are stored in memory in the following order:: + + A[0,0] A[1,0] A[0,1] A[1,1] + +and C-contiguous if the order is as follows:: + + A[0,0] A[0,1] A[1,0] A[1,1] + +To test whether an array is C-contiguous, use ``.iscontiguous()`` +method of NumPy arrays. To test for Fortran contiguity, all +F2PY generated extension modules provide a function +``has_column_major_storage()``. This function is equivalent to +``.flags.f_contiguous`` but more efficient. + +Usually there is no need to worry about how the arrays are stored in +memory and whether the wrapped functions, being either Fortran or C +functions, assume one or another storage order. F2PY automatically +ensures that wrapped functions get arguments with proper storage +order; the corresponding algorithm is designed to make copies of +arrays only when absolutely necessary. However, when dealing with very +large multidimensional input arrays with sizes close to the size of +the physical memory in your computer, then a care must be taken to use +always proper-contiguous and proper type arguments. + +To transform input arrays to column major storage order before passing +them to Fortran routines, use a function +``as_column_major_storage()`` that is provided by all F2PY +generated extension modules. + +Consider Fortran 77 code: + + .. include:: array.f + :literal: + +and wrap it using ``f2py -c -m arr array.f -DF2PY_REPORT_ON_ARRAY_COPY=1``. + +In Python: + + .. include:: array_session.dat + :literal: + +.. _Call-back arguments: + +Call-back arguments +==================== + +F2PY supports calling Python functions from Fortran or C codes. + +Consider the following Fortran 77 code: + + .. include:: callback.f + :literal: + +and wrap it using ``f2py -c -m callback callback.f``. + +In Python: + + .. include:: callback_session.dat + :literal: + +In the above example F2PY was able to guess accurately the signature +of a call-back function. However, sometimes F2PY cannot establish the +signature as one would wish and then the signature of a call-back +function must be modified in the signature file manually. Namely, +signature files may contain special modules (the names of such modules +contain a substring ``__user__``) that collect various signatures of +call-back functions. Callback arguments in routine signatures have +attribute ``external`` (see also ``intent(callback)`` attribute). To +relate a callback argument and its signature in ``__user__`` module +block, use ``use`` statement as illustrated below. The same signature +of a callback argument can be referred in different routine +signatures. + +We use the same Fortran 77 code as in previous example but now +we'll pretend that F2PY was not able to guess the signatures of +call-back arguments correctly. First, we create an initial signature +file ``callback2.pyf`` using F2PY:: + + f2py -m callback2 -h callback2.pyf callback.f + +Then modify it as follows + + .. include:: callback2.pyf + :literal: + +Finally, build the extension module using ``f2py -c callback2.pyf callback.f``. + +An example Python session would be identical to the previous example +except that argument names would differ. + +Sometimes a Fortran package may require that users provide routines +that the package will use. F2PY can construct an interface to such +routines so that Python functions could be called from Fortran. + +Consider the following `Fortran 77 subroutine`__ that takes an array +and applies a function ``func`` to its elements. + + .. include:: calculate.f + :literal: + +It is expected that function ``func`` has been defined +externally. In order to use a Python function as ``func``, it must +have an attribute ``intent(callback)`` (it must be specified before +the ``external`` statement). + +Finally, build an extension module using ``f2py -c -m foo calculate.f`` + +In Python: + + .. include:: calculate_session.dat + :literal: + +The function is included as an argument to the python function call to +the Fortran subroutine even though it was *not* in the Fortran subroutine argument +list. The "external" refers to the C function generated by f2py, not the python +function itself. The python function must be supplied to the C function. + +The callback function may also be explicitly set in the module. +Then it is not necessary to pass the function in the argument list to +the Fortran function. This may be desired if the Fortran function calling +the python callback function is itself called by another Fortran function. + +Consider the following Fortran 77 subroutine: + + .. include:: extcallback.f + :literal: + +and wrap it using ``f2py -c -m pfromf extcallback.f``. + +In Python: + + .. include:: extcallback_session.dat + :literal: + +Resolving arguments to call-back functions +------------------------------------------ + +F2PY generated interface is very flexible with respect to call-back +arguments. For each call-back argument an additional optional +argument ``_extra_args`` is introduced by F2PY. This argument +can be used to pass extra arguments to user provided call-back +arguments. + +If a F2PY generated wrapper function expects the following call-back +argument:: + + def fun(a_1,...,a_n): + ... + return x_1,...,x_k + +but the following Python function + +:: + + def gun(b_1,...,b_m): + ... + return y_1,...,y_l + +is provided by a user, and in addition, + +:: + + fun_extra_args = (e_1,...,e_p) + +is used, then the following rules are applied when a Fortran or C +function calls the call-back argument ``gun``: + +* If ``p == 0`` then ``gun(a_1, ..., a_q)`` is called, here + ``q = min(m, n)``. +* If ``n + p <= m`` then ``gun(a_1, ..., a_n, e_1, ..., e_p)`` is called. +* If ``p <= m < n + p`` then ``gun(a_1, ..., a_q, e_1, ..., e_p)`` is called, here + ``q=m-p``. +* If ``p > m`` then ``gun(e_1, ..., e_m)`` is called. +* If ``n + p`` is less than the number of required arguments to ``gun`` + then an exception is raised. + +The function ``gun`` may return any number of objects as a tuple. Then +following rules are applied: + +* If ``k < l``, then ``y_{k + 1}, ..., y_l`` are ignored. +* If ``k > l``, then only ``x_1, ..., x_l`` are set. + + +Common blocks +============== + +F2PY generates wrappers to ``common`` blocks defined in a routine +signature block. Common blocks are visible by all Fortran codes linked +with the current extension module, but not to other extension modules +(this restriction is due to how Python imports shared libraries). In +Python, the F2PY wrappers to ``common`` blocks are ``fortran`` type +objects that have (dynamic) attributes related to data members of +common blocks. When accessed, these attributes return as NumPy array +objects (multidimensional arrays are Fortran-contiguous) that +directly link to data members in common blocks. Data members can be +changed by direct assignment or by in-place changes to the +corresponding array objects. + +Consider the following Fortran 77 code: + + .. include:: common.f + :literal: + +and wrap it using ``f2py -c -m common common.f``. + +In Python: + + .. include:: common_session.dat + :literal: + + +Fortran 90 module data +======================= + +The F2PY interface to Fortran 90 module data is similar to Fortran 77 +common blocks. + +Consider the following Fortran 90 code: + + .. include:: moddata.f90 + :literal: + +and wrap it using ``f2py -c -m moddata moddata.f90``. + +In Python: + + .. include:: moddata_session.dat + :literal: + + +Allocatable arrays +------------------- + +F2PY has basic support for Fortran 90 module allocatable arrays. + +Consider the following Fortran 90 code: + + .. include:: allocarr.f90 + :literal: + +and wrap it using ``f2py -c -m allocarr allocarr.f90``. + +In Python: + + .. include:: allocarr_session.dat + :literal: diff --git a/doc/source/f2py/run_main_session.dat b/doc/source/f2py/run_main_session.dat new file mode 100644 index 0000000..29ecc3d --- /dev/null +++ b/doc/source/f2py/run_main_session.dat @@ -0,0 +1,14 @@ +>>> import f2py2e +>>> r=f2py2e.run_main(['-m','scalar','docs/usersguide/scalar.f']) +Reading fortran codes... + Reading file 'docs/usersguide/scalar.f' +Post-processing... + Block: scalar + Block: FOO +Building modules... + Building module "scalar"... + Wrote C/API module "scalar" to file "./scalarmodule.c" +>>> print r +{'scalar': {'h': ['/home/users/pearu/src_cvs/f2py2e/src/fortranobject.h'], + 'csrc': ['./scalarmodule.c', + '/home/users/pearu/src_cvs/f2py2e/src/fortranobject.c']}} diff --git a/doc/source/f2py/scalar.f b/doc/source/f2py/scalar.f new file mode 100644 index 0000000..c22f639 --- /dev/null +++ b/doc/source/f2py/scalar.f @@ -0,0 +1,12 @@ +C FILE: SCALAR.F + SUBROUTINE FOO(A,B) + REAL*8 A, B +Cf2py intent(in) a +Cf2py intent(inout) b + PRINT*, " A=",A," B=",B + PRINT*, "INCREMENT A AND B" + A = A + 1D0 + B = B + 1D0 + PRINT*, "NEW A=",A," B=",B + END +C END OF FILE SCALAR.F diff --git a/doc/source/f2py/scalar_session.dat b/doc/source/f2py/scalar_session.dat new file mode 100644 index 0000000..8aff097 --- /dev/null +++ b/doc/source/f2py/scalar_session.dat @@ -0,0 +1,21 @@ +>>> import scalar +>>> print scalar.foo.__doc__ +foo - Function signature: + foo(a,b) +Required arguments: + a : input float + b : in/output rank-0 array(float,'d') + +>>> scalar.foo(2,3) + A= 2. B= 3. + INCREMENT A AND B + NEW A= 3. B= 4. +>>> import numpy +>>> a=numpy.array(2) # these are integer rank-0 arrays +>>> b=numpy.array(3) +>>> scalar.foo(a,b) + A= 2. B= 3. + INCREMENT A AND B + NEW A= 3. B= 4. +>>> print a,b # note that only b is changed in situ +2 4 diff --git a/doc/source/f2py/setup_example.py b/doc/source/f2py/setup_example.py new file mode 100644 index 0000000..54af772 --- /dev/null +++ b/doc/source/f2py/setup_example.py @@ -0,0 +1,18 @@ +from __future__ import division, absolute_import, print_function + +from numpy.distutils.core import Extension + +ext1 = Extension(name = 'scalar', + sources = ['scalar.f']) +ext2 = Extension(name = 'fib2', + sources = ['fib2.pyf', 'fib1.f']) + +if __name__ == "__main__": + from numpy.distutils.core import setup + setup(name = 'f2py_example', + description = "F2PY Users Guide examples", + author = "Pearu Peterson", + author_email = "pearu@cens.ioc.ee", + ext_modules = [ext1, ext2] + ) +# End of setup_example.py diff --git a/doc/source/f2py/signature-file.rst b/doc/source/f2py/signature-file.rst new file mode 100644 index 0000000..bd926f3 --- /dev/null +++ b/doc/source/f2py/signature-file.rst @@ -0,0 +1,652 @@ +================== + Signature file +================== + +The syntax specification for signature files (.pyf files) is borrowed +from the Fortran 90/95 language specification. Almost all Fortran +90/95 standard constructs are understood, both in free and fixed +format (recall that Fortran 77 is a subset of Fortran 90/95). F2PY +introduces also some extensions to Fortran 90/95 language +specification that help designing Fortran to Python interface, make it +more "Pythonic". + +Signature files may contain arbitrary Fortran code (so that Fortran +codes can be considered as signature files). F2PY silently ignores +Fortran constructs that are irrelevant for creating the interface. +However, this includes also syntax errors. So, be careful not making +ones;-). + +In general, the contents of signature files is case-sensitive. When +scanning Fortran codes and writing a signature file, F2PY lowers all +cases automatically except in multiline blocks or when ``--no-lower`` +option is used. + +The syntax of signature files is presented below. + +Python module block +===================== + +A signature file may contain one (recommended) or more ``python +module`` blocks. ``python module`` block describes the contents of +a Python/C extension module ``module.c`` that F2PY +generates. + +Exception: if ```` contains a substring ``__user__``, then +the corresponding ``python module`` block describes the signatures of +so-called call-back functions (see :ref:`Call-back arguments`). + +A ``python module`` block has the following structure:: + + python module + []... + [ + interface + + + + end [interface] + ]... + [ + interface + module + [] + [] + end [module []] + end [interface] + ]... + end [python module []] + +Here brackets ``[]`` indicate an optional part, dots ``...`` indicate +one or more of a previous part. So, ``[]...`` reads zero or more of a +previous part. + + +Fortran/C routine signatures +============================= + +The signature of a Fortran routine has the following structure:: + + [] function | subroutine \ + [ ( [] ) ] [ result ( ) ] + [] + [] + [] + [] + [] + end [ function | subroutine [] ] + +From a Fortran routine signature F2PY generates a Python/C extension +function that has the following signature:: + + def ([,]): + ... + return + +The signature of a Fortran block data has the following structure:: + + block data [ ] + [] + [] + [] + [] + [] + end [ block data [] ] + +Type declarations +----------------- + +The definition of the ```` part +is + +:: + + [ [] :: ] + +where + +:: + + := byte | character [] + | complex [] | real [] + | double complex | double precision + | integer [] | logical [] + + := * + | ( [len=] [ , [kind=] ] ) + | ( kind= [ , len= ] ) + := * | ( [kind=] ) + + := [ [ * ] [ ( ) ] + | [ ( ) ] * ] + | [ / / | = ] \ + [ , ] + +and + ++ ```` is a comma separated list of attributes_; + ++ ```` is a comma separated list of dimension bounds; + ++ ```` is a `C expression`__. + ++ ```` may be negative integer for ``integer`` type + specifications. In such cases ``integer*`` represents + unsigned C integers. + +__ `C expressions`_ + +If an argument has no ````, its type is +determined by applying ``implicit`` rules to its name. + + +Statements +---------- + +Attribute statements: + The ```` is + ```` without ````. + In addition, in an attribute statement one cannot use other + attributes, also ```` can be only a list of names. + +Use statements: + The definition of the ```` part is + + :: + + use [ , | , ONLY : ] + + where + + :: + + := => [ , ] + + Currently F2PY uses ``use`` statement only for linking call-back + modules and ``external`` arguments (call-back functions), see + :ref:`Call-back arguments`. + +Common block statements: + The definition of the ```` part is + + :: + + common / / + + where + + :: + + := [ ( ) ] [ , ] + + If a ``python module`` block contains two or more ``common`` blocks + with the same name, the variables from the additional declarations + are appended. The types of variables in ```` are + defined using ````. Note that the + corresponding ```` may contain array + specifications; then you don't need to specify these in + ````. + +Other statements: + The ```` part refers to any other Fortran language + constructs that are not described above. F2PY ignores most of them + except + + + ``call`` statements and function calls of ``external`` arguments + (`more details`__?); + + __ external_ + + + ``include`` statements + :: + + include '' + include "" + + If a file ```` does not exist, the ``include`` + statement is ignored. Otherwise, the file ```` is + included to a signature file. ``include`` statements can be used + in any part of a signature file, also outside the Fortran/C + routine signature blocks. + + + ``implicit`` statements + :: + + implicit none + implicit + + where + + :: + + := ( ) + + Implicit rules are used to determine the type specification of + a variable (from the first-letter of its name) if the variable + is not defined using ````. Default + implicit rule is given by + + :: + + implicit real (a-h,o-z,$_), integer (i-m) + + + ``entry`` statements + :: + + entry [([])] + + F2PY generates wrappers to all entry names using the signature + of the routine block. + + Tip: ``entry`` statement can be used to describe the signature + of an arbitrary routine allowing F2PY to generate a number of + wrappers from only one routine block signature. There are few + restrictions while doing this: ``fortranname`` cannot be used, + ``callstatement`` and ``callprotoargument`` can be used only if + they are valid for all entry routines, etc. + + In addition, F2PY introduces the following statements: + + + ``threadsafe`` + Use ``Py_BEGIN_ALLOW_THREADS .. Py_END_ALLOW_THREADS`` block + around the call to Fortran/C function. + + + ``callstatement `` + Replace F2PY generated call statement to Fortran/C function with + ````. The wrapped Fortran/C function + is available as ``(*f2py_func)``. To raise an exception, set + ``f2py_success = 0`` in ````. + + + ``callprotoargument `` + When ``callstatement`` statement is used then F2PY may not + generate proper prototypes for Fortran/C functions (because + ```` may contain any function calls and F2PY has no way + to determine what should be the proper prototype). With this + statement you can explicitly specify the arguments of the + corresponding prototype:: + + extern FUNC_F(,)(); + + + ``fortranname []`` + You can use arbitrary ```` for a given Fortran/C + function. Then you have to specify + ```` with this statement. + + If ``fortranname`` statement is used without + ```` then a dummy wrapper is + generated. + + + ``usercode `` + When used inside ``python module`` block, then given C code + will be inserted to generated C/API source just before + wrapper function definitions. Here you can define arbitrary + C functions to be used in initialization of optional arguments, + for example. If ``usercode`` is used twice inside ``python + module`` block then the second multiline block is inserted + after the definition of external routines. + + When used inside ````, then given C code will + be inserted to the corresponding wrapper function just after + declaring variables but before any C statements. So, ``usercode`` + follow-up can contain both declarations and C statements. + + When used inside the first ``interface`` block, then given C + code will be inserted at the end of the initialization + function of the extension module. Here you can modify extension + modules dictionary. For example, for defining additional + variables etc. + + + ``pymethoddef `` + Multiline block will be inserted to the definition of + module methods ``PyMethodDef``-array. It must be a + comma-separated list of C arrays (see `Extending and Embedding`__ + Python documentation for details). + ``pymethoddef`` statement can be used only inside + ``python module`` block. + + __ http://www.python.org/doc/current/ext/ext.html + +Attributes +------------ + +The following attributes are used by F2PY: + +``optional`` + The corresponding argument is moved to the end of ```` list. A default value for an optional argument can be + specified ````, see ``entitydecl`` definition. Note that + the default value must be given as a valid C expression. + + Note that whenever ```` is used, ``optional`` attribute + is set automatically by F2PY. + + For an optional array argument, all its dimensions must be bounded. + +``required`` + The corresponding argument is considered as a required one. This is + default. You need to specify ``required`` only if there is a need to + disable automatic ``optional`` setting when ```` is used. + + If Python ``None`` object is used as a required argument, the + argument is treated as optional. That is, in the case of array + argument, the memory is allocated. And if ```` is given, + the corresponding initialization is carried out. + +``dimension()`` + The corresponding variable is considered as an array with given + dimensions in ````. + +``intent()`` + This specifies the "intention" of the corresponding + argument. ```` is a comma separated list of the + following keys: + + + ``in`` + The argument is considered as an input-only argument. It means + that the value of the argument is passed to Fortran/C function and + that function is expected not to change the value of an argument. + + + ``inout`` + The argument is considered as an input/output or *in situ* + output argument. ``intent(inout)`` arguments can be only + "contiguous" NumPy arrays with proper type and size. Here + "contiguous" can be either in Fortran or C sense. The latter one + coincides with the contiguous concept used in NumPy and is + effective only if ``intent(c)`` is used. Fortran contiguity + is assumed by default. + + Using ``intent(inout)`` is generally not recommended, use + ``intent(in,out)`` instead. See also ``intent(inplace)`` attribute. + + + ``inplace`` + The argument is considered as an input/output or *in situ* + output argument. ``intent(inplace)`` arguments must be + NumPy arrays with proper size. If the type of an array is + not "proper" or the array is non-contiguous then the array + will be changed in-place to fix the type and make it contiguous. + + Using ``intent(inplace)`` is generally not recommended either. + For example, when slices have been taken from an + ``intent(inplace)`` argument then after in-place changes, + slices data pointers may point to unallocated memory area. + + + ``out`` + The argument is considered as a return variable. It is appended + to the ```` list. Using ``intent(out)`` + sets ``intent(hide)`` automatically, unless also + ``intent(in)`` or ``intent(inout)`` were used. + + By default, returned multidimensional arrays are + Fortran-contiguous. If ``intent(c)`` is used, then returned + multidimensional arrays are C-contiguous. + + + ``hide`` + The argument is removed from the list of required or optional + arguments. Typically ``intent(hide)`` is used with ``intent(out)`` + or when ```` completely determines the value of the + argument like in the following example:: + + integer intent(hide),depend(a) :: n = len(a) + real intent(in),dimension(n) :: a + + + ``c`` + The argument is treated as a C scalar or C array argument. In + the case of a scalar argument, its value is passed to C function + as a C scalar argument (recall that Fortran scalar arguments are + actually C pointer arguments). In the case of an array + argument, the wrapper function is assumed to treat + multidimensional arrays as C-contiguous arrays. + + There is no need to use ``intent(c)`` for one-dimensional + arrays, no matter if the wrapped function is either a Fortran or + a C function. This is because the concepts of Fortran- and + C contiguity overlap in one-dimensional cases. + + If ``intent(c)`` is used as a statement but without an entity + declaration list, then F2PY adds the ``intent(c)`` attribute to all + arguments. + + Also, when wrapping C functions, one must use ``intent(c)`` + attribute for ```` in order to disable Fortran + specific ``F_FUNC(..,..)`` macros. + + + ``cache`` + The argument is treated as a junk of memory. No Fortran nor C + contiguity checks are carried out. Using ``intent(cache)`` + makes sense only for array arguments, also in connection with + ``intent(hide)`` or ``optional`` attributes. + + + ``copy`` + Ensure that the original contents of ``intent(in)`` argument is + preserved. Typically used in connection with ``intent(in,out)`` + attribute. F2PY creates an optional argument + ``overwrite_`` with the default value ``0``. + + + ``overwrite`` + The original contents of the ``intent(in)`` argument may be + altered by the Fortran/C function. F2PY creates an optional + argument ``overwrite_`` with the default value + ``1``. + + + ``out=`` + Replace the return name with ```` in the ``__doc__`` + string of a wrapper function. + + + ``callback`` + Construct an external function suitable for calling Python function + from Fortran. ``intent(callback)`` must be specified before the + corresponding ``external`` statement. If 'argument' is not in + argument list then it will be added to Python wrapper but only + initializing external function. + + Use ``intent(callback)`` in situations where a Fortran/C code + assumes that a user implements a function with given prototype + and links it to an executable. Don't use ``intent(callback)`` + if function appears in the argument list of a Fortran routine. + + With ``intent(hide)`` or ``optional`` attributes specified and + using a wrapper function without specifying the callback argument + in argument list then call-back function is looked in the + namespace of F2PY generated extension module where it can be + set as a module attribute by a user. + + + ``aux`` + Define auxiliary C variable in F2PY generated wrapper function. + Useful to save parameter values so that they can be accessed + in initialization expression of other variables. Note that + ``intent(aux)`` silently implies ``intent(c)``. + + The following rules apply: + + + If no ``intent(in | inout | out | hide)`` is specified, + ``intent(in)`` is assumed. + + ``intent(in,inout)`` is ``intent(in)``. + + ``intent(in,hide)`` or ``intent(inout,hide)`` is + ``intent(hide)``. + + ``intent(out)`` is ``intent(out,hide)`` unless ``intent(in)`` or + ``intent(inout)`` is specified. + + If ``intent(copy)`` or ``intent(overwrite)`` is used, then an + additional optional argument is introduced with a name + ``overwrite_`` and a default value 0 or 1, respectively. + + ``intent(inout,inplace)`` is ``intent(inplace)``. + + ``intent(in,inplace)`` is ``intent(inplace)``. + + ``intent(hide)`` disables ``optional`` and ``required``. + +``check([])`` + Perform consistency check of arguments by evaluating + ````; if ```` returns 0, an exception + is raised. + + If ``check(..)`` is not used then F2PY generates few standard checks + (e.g. in a case of an array argument, check for the proper shape + and size) automatically. Use ``check()`` to disable checks generated + by F2PY. + +``depend([])`` + This declares that the corresponding argument depends on the values + of variables in the list ````. For example, ```` + may use the values of other arguments. Using information given by + ``depend(..)`` attributes, F2PY ensures that arguments are + initialized in a proper order. If ``depend(..)`` attribute is not + used then F2PY determines dependence relations automatically. Use + ``depend()`` to disable dependence relations generated by F2PY. + + When you edit dependence relations that were initially generated by + F2PY, be careful not to break the dependence relations of other + relevant variables. Another thing to watch out is cyclic + dependencies. F2PY is able to detect cyclic dependencies + when constructing wrappers and it complains if any are found. + +``allocatable`` + The corresponding variable is Fortran 90 allocatable array defined + as Fortran 90 module data. + +.. _external: + +``external`` + The corresponding argument is a function provided by user. The + signature of this so-called call-back function can be defined + + - in ``__user__`` module block, + - or by demonstrative (or real, if the signature file is a real Fortran + code) call in the ```` block. + + For example, F2PY generates from + + :: + + external cb_sub, cb_fun + integer n + real a(n),r + call cb_sub(a,n) + r = cb_fun(4) + + the following call-back signatures:: + + subroutine cb_sub(a,n) + real dimension(n) :: a + integer optional,check(len(a)>=n),depend(a) :: n=len(a) + end subroutine cb_sub + function cb_fun(e_4_e) result (r) + integer :: e_4_e + real :: r + end function cb_fun + + The corresponding user-provided Python function are then:: + + def cb_sub(a,[n]): + ... + return + def cb_fun(e_4_e): + ... + return r + + See also ``intent(callback)`` attribute. + +``parameter`` + The corresponding variable is a parameter and it must have a fixed + value. F2PY replaces all parameter occurrences by their + corresponding values. + +Extensions +============ + +F2PY directives +----------------- + +The so-called F2PY directives allow using F2PY signature file +constructs also in Fortran 77/90 source codes. With this feature you +can skip (almost) completely intermediate signature file generations +and apply F2PY directly to Fortran source codes. + +F2PY directive has the following form:: + + f2py ... + +where allowed comment characters for fixed and free format Fortran +codes are ``cC*!#`` and ``!``, respectively. Everything that follows +``f2py`` is ignored by a compiler but read by F2PY as a +normal Fortran, non-comment line: + + When F2PY finds a line with F2PY directive, the directive is first + replaced by 5 spaces and then the line is reread. + +For fixed format Fortran codes, ```` must be at the +first column of a file, of course. For free format Fortran codes, +F2PY directives can appear anywhere in a file. + +C expressions +-------------- + +C expressions are used in the following parts of signature files: + +* ```` of variable initialization; +* ```` of the ``check`` attribute; +* `` of the ``dimension`` attribute; +* ``callstatement`` statement, here also a C multiline block can be used. + +A C expression may contain: + +* standard C constructs; +* functions from ``math.h`` and ``Python.h``; +* variables from the argument list, presumably initialized before + according to given dependence relations; +* the following CPP macros: + + ``rank()`` + Returns the rank of an array ````. + ``shape(,)`` + Returns the ````-th dimension of an array ````. + ``len()`` + Returns the length of an array ````. + ``size()`` + Returns the size of an array ````. + ``slen()`` + Returns the length of a string ````. + +For initializing an array ````, F2PY generates a loop over +all indices and dimensions that executes the following +pseudo-statement:: + + (_i[0],_i[1],...) = ; + +where ``_i[]`` refers to the ````-th index value and that runs +from ``0`` to ``shape(,)-1``. + +For example, a function ``myrange(n)`` generated from the following +signature + +:: + + subroutine myrange(a,n) + fortranname ! myrange is a dummy wrapper + integer intent(in) :: n + real*8 intent(c,out),dimension(n),depend(n) :: a = _i[0] + end subroutine myrange + +is equivalent to ``numpy.arange(n,dtype=float)``. + +.. warning:: + + F2PY may lower cases also in C expressions when scanning Fortran codes + (see ``--[no]-lower`` option). + +Multiline blocks +------------------ + +A multiline block starts with ``'''`` (triple single-quotes) and ends +with ``'''`` in some *strictly* subsequent line. Multiline blocks can +be used only within .pyf files. The contents of a multiline block can +be arbitrary (except that it cannot contain ``'''``) and no +transformations (e.g. lowering cases) are applied to it. + +Currently, multiline blocks can be used in the following constructs: + ++ as a C expression of the ``callstatement`` statement; + ++ as a C type specification of the ``callprotoargument`` statement; + ++ as a C code block of the ``usercode`` statement; + ++ as a list of C arrays of the ``pymethoddef`` statement; + ++ as documentation string. diff --git a/doc/source/f2py/spam.pyf b/doc/source/f2py/spam.pyf new file mode 100644 index 0000000..21ea18b --- /dev/null +++ b/doc/source/f2py/spam.pyf @@ -0,0 +1,19 @@ +! -*- f90 -*- +python module spam + usercode ''' + static char doc_spam_system[] = "Execute a shell command."; + static PyObject *spam_system(PyObject *self, PyObject *args) + { + char *command; + int sts; + + if (!PyArg_ParseTuple(args, "s", &command)) + return NULL; + sts = system(command); + return Py_BuildValue("i", sts); + } + ''' + pymethoddef ''' + {"system", spam_system, METH_VARARGS, doc_spam_system}, + ''' +end python module spam diff --git a/doc/source/f2py/spam_session.dat b/doc/source/f2py/spam_session.dat new file mode 100644 index 0000000..7f99d13 --- /dev/null +++ b/doc/source/f2py/spam_session.dat @@ -0,0 +1,5 @@ +>>> import spam +>>> status = spam.system('whoami') +pearu +>> status = spam.system('blah') +sh: line 1: blah: command not found \ No newline at end of file diff --git a/doc/source/f2py/string.f b/doc/source/f2py/string.f new file mode 100644 index 0000000..9246f02 --- /dev/null +++ b/doc/source/f2py/string.f @@ -0,0 +1,21 @@ +C FILE: STRING.F + SUBROUTINE FOO(A,B,C,D) + CHARACTER*5 A, B + CHARACTER*(*) C,D +Cf2py intent(in) a,c +Cf2py intent(inout) b,d + PRINT*, "A=",A + PRINT*, "B=",B + PRINT*, "C=",C + PRINT*, "D=",D + PRINT*, "CHANGE A,B,C,D" + A(1:1) = 'A' + B(1:1) = 'B' + C(1:1) = 'C' + D(1:1) = 'D' + PRINT*, "A=",A + PRINT*, "B=",B + PRINT*, "C=",C + PRINT*, "D=",D + END +C END OF FILE STRING.F diff --git a/doc/source/f2py/string_session.dat b/doc/source/f2py/string_session.dat new file mode 100644 index 0000000..cbae6b7 --- /dev/null +++ b/doc/source/f2py/string_session.dat @@ -0,0 +1,27 @@ +>>> import mystring +>>> print mystring.foo.__doc__ +foo - Function signature: + foo(a,b,c,d) +Required arguments: + a : input string(len=5) + b : in/output rank-0 array(string(len=5),'c') + c : input string(len=-1) + d : in/output rank-0 array(string(len=-1),'c') + +>>> import numpy +>>> a=numpy.array('123') +>>> b=numpy.array('123') +>>> c=numpy.array('123') +>>> d=numpy.array('123') +>>> mystring.foo(a,b,c,d) + A=123 + B=123 + C=123 + D=123 + CHANGE A,B,C,D + A=A23 + B=B23 + C=C23 + D=D23 +>>> a.tostring(),b.tostring(),c.tostring(),d.tostring() +('123', 'B23', '123', 'D23') diff --git a/doc/source/f2py/usage.rst b/doc/source/f2py/usage.rst new file mode 100644 index 0000000..a6f0931 --- /dev/null +++ b/doc/source/f2py/usage.rst @@ -0,0 +1,233 @@ +=========== +Using F2PY +=========== + +F2PY can be used either as a command line tool ``f2py`` or as a Python +module ``f2py2e``. + +Command ``f2py`` +================= + +When used as a command line tool, ``f2py`` has three major modes, +distinguished by the usage of ``-c`` and ``-h`` switches: + +1. To scan Fortran sources and generate a signature file, use + + :: + + f2py -h \ + [[ only: : ] \ + [ skip: : ]]... \ + [ ...] + + Note that a Fortran source file can contain many routines, and not + necessarily all routines are needed to be used from Python. So, you + can either specify which routines should be wrapped (in ``only: .. :`` + part) or which routines F2PY should ignored (in ``skip: .. :`` part). + + If ```` is specified as ``stdout`` then signatures + are send to standard output instead of a file. + + Among other options (see below), the following options can be used + in this mode: + + ``--overwrite-signature`` + Overwrite existing signature file. + +2. To construct an extension module, use + + :: + + f2py \ + [[ only: : ] \ + [ skip: : ]]... \ + [ ...] + + The constructed extension module is saved as + ``module.c`` to the current directory. + + Here ```` may also contain signature files. + Among other options (see below), the following options can be used + in this mode: + + ``--debug-capi`` + Add debugging hooks to the extension module. When using this + extension module, various information about the wrapper is printed + to standard output, for example, the values of variables, the + steps taken, etc. + + ``-include''`` + Add a CPP ``#include`` statement to the extension module source. + ```` should be given in one of the following forms:: + + "filename.ext" + + + The include statement is inserted just before the wrapper + functions. This feature enables using arbitrary C functions + (defined in ````) in F2PY generated wrappers. + + This option is deprecated. Use ``usercode`` statement to specify + C code snippets directly in signature files + + ``--[no-]wrap-functions`` + + Create Fortran subroutine wrappers to Fortran functions. + ``--wrap-functions`` is default because it ensures maximum + portability and compiler independence. + + ``--include-paths ::..`` + Search include files from given directories. + + ``--help-link []`` + List system resources found by ``numpy_distutils/system_info.py``. + For example, try ``f2py --help-link lapack_opt``. + +3. To build an extension module, use + + :: + + f2py -c \ + [[ only: : ] \ + [ skip: : ]]... \ + [ ] [ <.o, .a, .so files> ] + + If ```` contains a signature file, then a source for + an extension module is constructed, all Fortran and C sources are + compiled, and finally all object and library files are linked to the + extension module ``.so`` which is saved into the current + directory. + + If ```` does not contain a signature file, then an + extension module is constructed by scanning all Fortran source codes + for routine signatures. + + Among other options (see below) and options described in previous + mode, the following options can be used in this mode: + + ``--help-fcompiler`` + List available Fortran compilers. + ``--help-compiler`` [depreciated] + List available Fortran compilers. + ``--fcompiler=`` + Specify Fortran compiler type by vendor. + ``--f77exec=`` + Specify the path to F77 compiler + ``--fcompiler-exec=`` [depreciated] + Specify the path to F77 compiler + ``--f90exec=`` + Specify the path to F90 compiler + ``--f90compiler-exec=`` [depreciated] + Specify the path to F90 compiler + + ``--f77flags=`` + Specify F77 compiler flags + ``--f90flags=`` + Specify F90 compiler flags + ``--opt=`` + Specify optimization flags + ``--arch=`` + Specify architecture specific optimization flags + ``--noopt`` + Compile without optimization + ``--noarch`` + Compile without arch-dependent optimization + ``--debug`` + Compile with debugging information + + ``-l`` + Use the library ```` when linking. + ``-D[=]`` + Define macro ```` as ````. + ``-U`` + Define macro ```` + ``-I`` + Append directory ```` to the list of directories searched for + include files. + ``-L`` + Add directory ```` to the list of directories to be searched + for ``-l``. + + ``link-`` + + Link extension module with as defined by + ``numpy_distutils/system_info.py``. E.g. to link with optimized + LAPACK libraries (vecLib on MacOSX, ATLAS elsewhere), use + ``--link-lapack_opt``. See also ``--help-link`` switch. + + When building an extension module, a combination of the following + macros may be required for non-gcc Fortran compilers:: + + -DPREPEND_FORTRAN + -DNO_APPEND_FORTRAN + -DUPPERCASE_FORTRAN + + To test the performance of F2PY generated interfaces, use + ``-DF2PY_REPORT_ATEXIT``. Then a report of various timings is + printed out at the exit of Python. This feature may not work on + all platforms, currently only Linux platform is supported. + + To see whether F2PY generated interface performs copies of array + arguments, use ``-DF2PY_REPORT_ON_ARRAY_COPY=``. When the size + of an array argument is larger than ````, a message about + the coping is sent to ``stderr``. + +Other options: + +``-m `` + Name of an extension module. Default is ``untitled``. Don't use this option + if a signature file (\*.pyf) is used. +``--[no-]lower`` + Do [not] lower the cases in ````. By default, + ``--lower`` is assumed with ``-h`` switch, and ``--no-lower`` + without the ``-h`` switch. +``--build-dir `` + All F2PY generated files are created in ````. Default is + ``tempfile.mkdtemp()``. +``--quiet`` + Run quietly. +``--verbose`` + Run with extra verbosity. +``-v`` + Print f2py version ID and exit. + +Execute ``f2py`` without any options to get an up-to-date list of +available options. + +Python module ``f2py2e`` +========================= + +.. warning:: + + The current Python interface to ``f2py2e`` module is not mature and + may change in future depending on users needs. + +The following functions are provided by the ``f2py2e`` module: + +``run_main()`` + Equivalent to running:: + + f2py + + where ``=string.join(,' ')``, but in Python. Unless + ``-h`` is used, this function returns a dictionary containing + information on generated modules and their dependencies on source + files. For example, the command ``f2py -m scalar scalar.f`` can be + executed from Python as follows + + .. include:: run_main_session.dat + :literal: + + You cannot build extension modules with this function, that is, + using ``-c`` is not allowed. Use ``compile`` command instead, see + below. + +``compile(source, modulename='untitled', extra_args='', verbose=1, source_fn=None)`` + Build extension module from Fortran 77 source string ``source``. + Return 0 if successful. + Note that this function actually calls ``f2py -c ..`` from shell to + ensure safety of the current Python process. + For example, + + .. include:: compile_session.dat + :literal: diff --git a/doc/source/f2py/var.pyf b/doc/source/f2py/var.pyf new file mode 100644 index 0000000..8275ff3 --- /dev/null +++ b/doc/source/f2py/var.pyf @@ -0,0 +1,11 @@ +! -*- f90 -*- +python module var + usercode ''' + int BAR = 5; + ''' + interface + usercode ''' + PyDict_SetItemString(d,"BAR",PyInt_FromLong(BAR)); + ''' + end interface +end python module diff --git a/doc/source/f2py/var_session.dat b/doc/source/f2py/var_session.dat new file mode 100644 index 0000000..fb0f798 --- /dev/null +++ b/doc/source/f2py/var_session.dat @@ -0,0 +1,3 @@ +>>> import var +>>> var.BAR +5 \ No newline at end of file diff --git a/doc/source/glossary.rst b/doc/source/glossary.rst new file mode 100644 index 0000000..b6ea429 --- /dev/null +++ b/doc/source/glossary.rst @@ -0,0 +1,7 @@ +******** +Glossary +******** + +.. toctree:: + +.. automodule:: numpy.doc.glossary diff --git a/doc/source/license.rst b/doc/source/license.rst new file mode 100644 index 0000000..8f360af --- /dev/null +++ b/doc/source/license.rst @@ -0,0 +1,35 @@ +************* +NumPy License +************* + +Copyright (c) 2005, NumPy Developers + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +* Neither the name of the NumPy Developers nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/doc/source/neps/datetime-proposal.rst b/doc/source/neps/datetime-proposal.rst new file mode 100644 index 0000000..05f0182 --- /dev/null +++ b/doc/source/neps/datetime-proposal.rst @@ -0,0 +1 @@ +.. include:: ../../neps/datetime-proposal.rst diff --git a/doc/source/neps/datetime-proposal3.rst b/doc/source/neps/datetime-proposal3.rst new file mode 100644 index 0000000..fa9102a --- /dev/null +++ b/doc/source/neps/datetime-proposal3.rst @@ -0,0 +1 @@ +.. include:: ../../neps/datetime-proposal3.rst diff --git a/doc/source/neps/deferred-ufunc-evaluation.rst b/doc/source/neps/deferred-ufunc-evaluation.rst new file mode 100644 index 0000000..b4a7a45 --- /dev/null +++ b/doc/source/neps/deferred-ufunc-evaluation.rst @@ -0,0 +1 @@ +.. include:: ../../neps/deferred-ufunc-evaluation.rst diff --git a/doc/source/neps/dropping-python2.7-proposal.rst b/doc/source/neps/dropping-python2.7-proposal.rst new file mode 100644 index 0000000..c67a626 --- /dev/null +++ b/doc/source/neps/dropping-python2.7-proposal.rst @@ -0,0 +1 @@ +.. include:: ../../neps/dropping-python2.7-proposal.rst diff --git a/doc/source/neps/generalized-ufuncs.rst b/doc/source/neps/generalized-ufuncs.rst new file mode 100644 index 0000000..8b28f02 --- /dev/null +++ b/doc/source/neps/generalized-ufuncs.rst @@ -0,0 +1 @@ +.. include:: ../../neps/generalized-ufuncs.rst diff --git a/doc/source/neps/groupby_additions.rst b/doc/source/neps/groupby_additions.rst new file mode 100644 index 0000000..61abc95 --- /dev/null +++ b/doc/source/neps/groupby_additions.rst @@ -0,0 +1 @@ +.. include:: ../../neps/groupby_additions.rst diff --git a/doc/source/neps/index.rst b/doc/source/neps/index.rst new file mode 100644 index 0000000..d85f336 --- /dev/null +++ b/doc/source/neps/index.rst @@ -0,0 +1,38 @@ +=========================== +NumPy Enhancement Proposals +=========================== + +NumPy Enhancement Proposals (NEPs) describe proposed changes to NumPy. +NEPs are modeled on Python Enhancement Proposals (PEPs), and are typically +written up when large changes to NumPy are proposed. + +This page provides an overview of all NEPs, making only a distinction between +the ones that have been implemented and those that have not been implemented. + +Implemented NEPs +---------------- + +.. toctree:: + :maxdepth: 1 + + ufunc-overrides + generalized-ufuncs + new-iterator-ufunc + npy-format + +Other NEPs +---------- + +.. toctree:: + :maxdepth: 1 + + missing-data + math_config_clean + groupby_additions + warnfix + newbugtracker + deferred-ufunc-evaluation + structured_array_extensions + datetime-proposal + datetime-proposal3 + dropping-python2.7-proposal diff --git a/doc/source/neps/math_config_clean.rst b/doc/source/neps/math_config_clean.rst new file mode 100644 index 0000000..25b340e --- /dev/null +++ b/doc/source/neps/math_config_clean.rst @@ -0,0 +1 @@ +.. include:: ../../neps/math_config_clean.rst diff --git a/doc/source/neps/missing-data.rst b/doc/source/neps/missing-data.rst new file mode 100644 index 0000000..f9899f1 --- /dev/null +++ b/doc/source/neps/missing-data.rst @@ -0,0 +1 @@ +.. include:: ../../neps/missing-data.rst diff --git a/doc/source/neps/new-iterator-ufunc.rst b/doc/source/neps/new-iterator-ufunc.rst new file mode 100644 index 0000000..7e06aa8 --- /dev/null +++ b/doc/source/neps/new-iterator-ufunc.rst @@ -0,0 +1 @@ +.. include:: ../../neps/new-iterator-ufunc.rst diff --git a/doc/source/neps/newbugtracker.rst b/doc/source/neps/newbugtracker.rst new file mode 100644 index 0000000..70ea21f --- /dev/null +++ b/doc/source/neps/newbugtracker.rst @@ -0,0 +1 @@ +.. include:: ../../neps/newbugtracker.rst diff --git a/doc/source/neps/npy-format.rst b/doc/source/neps/npy-format.rst new file mode 100644 index 0000000..bd1f2bb --- /dev/null +++ b/doc/source/neps/npy-format.rst @@ -0,0 +1 @@ +.. include:: ../../neps/npy-format.rst diff --git a/doc/source/neps/structured_array_extensions.rst b/doc/source/neps/structured_array_extensions.rst new file mode 100644 index 0000000..341e6c9 --- /dev/null +++ b/doc/source/neps/structured_array_extensions.rst @@ -0,0 +1 @@ +.. include:: ../../neps/structured_array_extensions.rst diff --git a/doc/source/neps/ufunc-overrides.rst b/doc/source/neps/ufunc-overrides.rst new file mode 100644 index 0000000..2e293ec --- /dev/null +++ b/doc/source/neps/ufunc-overrides.rst @@ -0,0 +1 @@ +.. include:: ../../neps/ufunc-overrides.rst diff --git a/doc/source/neps/warnfix.rst b/doc/source/neps/warnfix.rst new file mode 100644 index 0000000..1b9b1b8 --- /dev/null +++ b/doc/source/neps/warnfix.rst @@ -0,0 +1 @@ +.. include:: ../../neps/warnfix.rst diff --git a/doc/source/reference/arrays.classes.rst b/doc/source/reference/arrays.classes.rst new file mode 100644 index 0000000..2719f92 --- /dev/null +++ b/doc/source/reference/arrays.classes.rst @@ -0,0 +1,541 @@ +.. _arrays.classes: + +######################### +Standard array subclasses +######################### + +.. currentmodule:: numpy + +The :class:`ndarray` in NumPy is a "new-style" Python +built-in-type. Therefore, it can be inherited from (in Python or in C) +if desired. Therefore, it can form a foundation for many useful +classes. Often whether to sub-class the array object or to simply use +the core array component as an internal part of a new class is a +difficult decision, and can be simply a matter of choice. NumPy has +several tools for simplifying how your new object interacts with other +array objects, and so the choice may not be significant in the +end. One way to simplify the question is by asking yourself if the +object you are interested in can be replaced as a single array or does +it really require two or more arrays at its core. + +Note that :func:`asarray` always returns the base-class ndarray. If +you are confident that your use of the array object can handle any +subclass of an ndarray, then :func:`asanyarray` can be used to allow +subclasses to propagate more cleanly through your subroutine. In +principal a subclass could redefine any aspect of the array and +therefore, under strict guidelines, :func:`asanyarray` would rarely be +useful. However, most subclasses of the array object will not +redefine certain aspects of the array object such as the buffer +interface, or the attributes of the array. One important example, +however, of why your subroutine may not be able to handle an arbitrary +subclass of an array is that matrices redefine the "*" operator to be +matrix-multiplication, rather than element-by-element multiplication. + + +Special attributes and methods +============================== + +.. seealso:: :ref:`Subclassing ndarray ` + +NumPy provides several hooks that classes can customize: + +.. py:method:: class.__array_ufunc__(ufunc, method, *inputs, **kwargs) + + .. versionadded:: 1.13 + + .. note:: The API is `provisional + `_, + i.e., we do not yet guarantee backward compatibility. + + Any class, ndarray subclass or not, can define this method or set it to + :obj:`None` in order to override the behavior of NumPy's ufuncs. This works + quite similarly to Python's ``__mul__`` and other binary operation routines. + + - *ufunc* is the ufunc object that was called. + - *method* is a string indicating which Ufunc method was called + (one of ``"__call__"``, ``"reduce"``, ``"reduceat"``, + ``"accumulate"``, ``"outer"``, ``"inner"``). + - *inputs* is a tuple of the input arguments to the ``ufunc``. + - *kwargs* is a dictionary containing the optional input arguments + of the ufunc. If given, any ``out`` arguments, both positional + and keyword, are passed as a :obj:`tuple` in *kwargs*. See the + discussion in :ref:`ufuncs` for details. + + The method should return either the result of the operation, or + :obj:`NotImplemented` if the operation requested is not implemented. + + If one of the input or output arguments has a :func:`__array_ufunc__` + method, it is executed *instead* of the ufunc. If more than one of the + arguments implements :func:`__array_ufunc__`, they are tried in the + order: subclasses before superclasses, inputs before outputs, otherwise + left to right. The first routine returning something other than + :obj:`NotImplemented` determines the result. If all of the + :func:`__array_ufunc__` operations return :obj:`NotImplemented`, a + :exc:`TypeError` is raised. + + .. note:: We intend to re-implement numpy functions as (generalized) + Ufunc, in which case it will become possible for them to be + overridden by the ``__array_ufunc__`` method. A prime candidate is + :func:`~numpy.matmul`, which currently is not a Ufunc, but could be + relatively easily be rewritten as a (set of) generalized Ufuncs. The + same may happen with functions such as :func:`~numpy.median`, + :func:`~numpy.min`, and :func:`~numpy.argsort`. + + Like with some other special methods in python, such as ``__hash__`` and + ``__iter__``, it is possible to indicate that your class does *not* + support ufuncs by setting ``__array_ufunc__ = None``. Ufuncs always raise + :exc:`TypeError` when called on an object that sets + ``__array_ufunc__ = None``. + + The presence of :func:`__array_ufunc__` also influences how + :class:`ndarray` handles binary operations like ``arr + obj`` and ``arr + < obj`` when ``arr`` is an :class:`ndarray` and ``obj`` is an instance + of a custom class. There are two possibilities. If + ``obj.__array_ufunc__`` is present and not :obj:`None`, then + ``ndarray.__add__`` and friends will delegate to the ufunc machinery, + meaning that ``arr + obj`` becomes ``np.add(arr, obj)``, and then + :func:`~numpy.add` invokes ``obj.__array_ufunc__``. This is useful if you + want to define an object that acts like an array. + + Alternatively, if ``obj.__array_ufunc__`` is set to :obj:`None`, then as a + special case, special methods like ``ndarray.__add__`` will notice this + and *unconditionally* raise :exc:`TypeError`. This is useful if you want to + create objects that interact with arrays via binary operations, but + are not themselves arrays. For example, a units handling system might have + an object ``m`` representing the "meters" unit, and want to support the + syntax ``arr * m`` to represent that the array has units of "meters", but + not want to otherwise interact with arrays via ufuncs or otherwise. This + can be done by setting ``__array_ufunc__ = None`` and defining ``__mul__`` + and ``__rmul__`` methods. (Note that this means that writing an + ``__array_ufunc__`` that always returns :obj:`NotImplemented` is not + quite the same as setting ``__array_ufunc__ = None``: in the former + case, ``arr + obj`` will raise :exc:`TypeError`, while in the latter + case it is possible to define a ``__radd__`` method to prevent this.) + + The above does not hold for in-place operators, for which :class:`ndarray` + never returns :obj:`NotImplemented`. Hence, ``arr += obj`` would always + lead to a :exc:`TypeError`. This is because for arrays in-place operations + cannot generically be replaced by a simple reverse operation. (For + instance, by default, ``arr += obj`` would be translated to ``arr = + arr + obj``, i.e., ``arr`` would be replaced, contrary to what is expected + for in-place array operations.) + + .. note:: If you define ``__array_ufunc__``: + + - If you are not a subclass of :class:`ndarray`, we recommend your + class define special methods like ``__add__`` and ``__lt__`` that + delegate to ufuncs just like ndarray does. An easy way to do this + is to subclass from :class:`~numpy.lib.mixins.NDArrayOperatorsMixin`. + - If you subclass :class:`ndarray`, we recommend that you put all your + override logic in ``__array_ufunc__`` and not also override special + methods. This ensures the class hierarchy is determined in only one + place rather than separately by the ufunc machinery and by the binary + operation rules (which gives preference to special methods of + subclasses; the alternative way to enforce a one-place only hierarchy, + of setting :func:`__array_ufunc__` to :obj:`None`, would seem very + unexpected and thus confusing, as then the subclass would not work at + all with ufuncs). + - :class:`ndarray` defines its own :func:`__array_ufunc__`, which, + evaluates the ufunc if no arguments have overrides, and returns + :obj:`NotImplemented` otherwise. This may be useful for subclasses + for which :func:`__array_ufunc__` converts any instances of its own + class to :class:`ndarray`: it can then pass these on to its + superclass using ``super().__array_ufunc__(*inputs, **kwargs)``, + and finally return the results after possible back-conversion. The + advantage of this practice is that it ensures that it is possible + to have a hierarchy of subclasses that extend the behaviour. See + :ref:`Subclassing ndarray ` for details. + + .. note:: If a class defines the :func:`__array_ufunc__` method, + this disables the :func:`__array_wrap__`, + :func:`__array_prepare__`, :data:`__array_priority__` mechanism + described below for ufuncs (which may eventually be deprecated). + +.. py:method:: class.__array_finalize__(obj) + + This method is called whenever the system internally allocates a + new array from *obj*, where *obj* is a subclass (subtype) of the + :class:`ndarray`. It can be used to change attributes of *self* + after construction (so as to ensure a 2-d matrix for example), or + to update meta-information from the "parent." Subclasses inherit + a default implementation of this method that does nothing. + +.. py:method:: class.__array_prepare__(array, context=None) + + At the beginning of every :ref:`ufunc `, this + method is called on the input object with the highest array + priority, or the output object if one was specified. The output + array is passed in and whatever is returned is passed to the ufunc. + Subclasses inherit a default implementation of this method which + simply returns the output array unmodified. Subclasses may opt to + use this method to transform the output array into an instance of + the subclass and update metadata before returning the array to the + ufunc for computation. + + .. note:: For ufuncs, it is hoped to eventually deprecate this method in + favour of :func:`__array_ufunc__`. + +.. py:method:: class.__array_wrap__(array, context=None) + + At the end of every :ref:`ufunc `, this method + is called on the input object with the highest array priority, or + the output object if one was specified. The ufunc-computed array + is passed in and whatever is returned is passed to the user. + Subclasses inherit a default implementation of this method, which + transforms the array into a new instance of the object's class. + Subclasses may opt to use this method to transform the output array + into an instance of the subclass and update metadata before + returning the array to the user. + + .. note:: For ufuncs, it is hoped to eventually deprecate this method in + favour of :func:`__array_ufunc__`. + +.. py:attribute:: class.__array_priority__ + + The value of this attribute is used to determine what type of + object to return in situations where there is more than one + possibility for the Python type of the returned object. Subclasses + inherit a default value of 0.0 for this attribute. + + .. note:: For ufuncs, it is hoped to eventually deprecate this method in + favour of :func:`__array_ufunc__`. + +.. py:method:: class.__array__([dtype]) + + If a class (ndarray subclass or not) having the :func:`__array__` + method is used as the output object of an :ref:`ufunc + `, results will be written to the object + returned by :func:`__array__`. Similar conversion is done on + input arrays. + + +Matrix objects +============== + +.. index:: + single: matrix + +:class:`matrix` objects inherit from the ndarray and therefore, they +have the same attributes and methods of ndarrays. There are six +important differences of matrix objects, however, that may lead to +unexpected results when you use matrices but expect them to act like +arrays: + +1. Matrix objects can be created using a string notation to allow + Matlab-style syntax where spaces separate columns and semicolons + (';') separate rows. + +2. Matrix objects are always two-dimensional. This has far-reaching + implications, in that m.ravel() is still two-dimensional (with a 1 + in the first dimension) and item selection returns two-dimensional + objects so that sequence behavior is fundamentally different than + arrays. + +3. Matrix objects over-ride multiplication to be + matrix-multiplication. **Make sure you understand this for + functions that you may want to receive matrices. Especially in + light of the fact that asanyarray(m) returns a matrix when m is + a matrix.** + +4. Matrix objects over-ride power to be matrix raised to a power. The + same warning about using power inside a function that uses + asanyarray(...) to get an array object holds for this fact. + +5. The default __array_priority\__ of matrix objects is 10.0, and + therefore mixed operations with ndarrays always produce matrices. + +6. Matrices have special attributes which make calculations easier. + These are + + .. autosummary:: + :toctree: generated/ + + matrix.T + matrix.H + matrix.I + matrix.A + +.. warning:: + + Matrix objects over-ride multiplication, '*', and power, '**', to + be matrix-multiplication and matrix power, respectively. If your + subroutine can accept sub-classes and you do not convert to base- + class arrays, then you must use the ufuncs multiply and power to + be sure that you are performing the correct operation for all + inputs. + +The matrix class is a Python subclass of the ndarray and can be used +as a reference for how to construct your own subclass of the ndarray. +Matrices can be created from other matrices, strings, and anything +else that can be converted to an ``ndarray`` . The name "mat "is an +alias for "matrix "in NumPy. + +.. autosummary:: + :toctree: generated/ + + matrix + asmatrix + bmat + +Example 1: Matrix creation from a string + +>>> a=mat('1 2 3; 4 5 3') +>>> print (a*a.T).I +[[ 0.2924 -0.1345] + [-0.1345 0.0819]] + +Example 2: Matrix creation from nested sequence + +>>> mat([[1,5,10],[1.0,3,4j]]) +matrix([[ 1.+0.j, 5.+0.j, 10.+0.j], + [ 1.+0.j, 3.+0.j, 0.+4.j]]) + +Example 3: Matrix creation from an array + +>>> mat(random.rand(3,3)).T +matrix([[ 0.7699, 0.7922, 0.3294], + [ 0.2792, 0.0101, 0.9219], + [ 0.3398, 0.7571, 0.8197]]) + +Memory-mapped file arrays +========================= + +.. index:: + single: memory maps + +.. currentmodule:: numpy + +Memory-mapped files are useful for reading and/or modifying small +segments of a large file with regular layout, without reading the +entire file into memory. A simple subclass of the ndarray uses a +memory-mapped file for the data buffer of the array. For small files, +the over-head of reading the entire file into memory is typically not +significant, however for large files using memory mapping can save +considerable resources. + +Memory-mapped-file arrays have one additional method (besides those +they inherit from the ndarray): :meth:`.flush() ` which +must be called manually by the user to ensure that any changes to the +array actually get written to disk. + +.. autosummary:: + :toctree: generated/ + + memmap + memmap.flush + +Example: + +>>> a = memmap('newfile.dat', dtype=float, mode='w+', shape=1000) +>>> a[10] = 10.0 +>>> a[30] = 30.0 +>>> del a +>>> b = fromfile('newfile.dat', dtype=float) +>>> print b[10], b[30] +10.0 30.0 +>>> a = memmap('newfile.dat', dtype=float) +>>> print a[10], a[30] +10.0 30.0 + + +Character arrays (:mod:`numpy.char`) +==================================== + +.. seealso:: :ref:`routines.array-creation.char` + +.. index:: + single: character arrays + +.. note:: + The `chararray` class exists for backwards compatibility with + Numarray, it is not recommended for new development. Starting from numpy + 1.4, if one needs arrays of strings, it is recommended to use arrays of + `dtype` `object_`, `string_` or `unicode_`, and use the free functions + in the `numpy.char` module for fast vectorized string operations. + +These are enhanced arrays of either :class:`string_` type or +:class:`unicode_` type. These arrays inherit from the +:class:`ndarray`, but specially-define the operations ``+``, ``*``, +and ``%`` on a (broadcasting) element-by-element basis. These +operations are not available on the standard :class:`ndarray` of +character type. In addition, the :class:`chararray` has all of the +standard :class:`string ` (and :class:`unicode`) methods, +executing them on an element-by-element basis. Perhaps the easiest +way to create a chararray is to use :meth:`self.view(chararray) +` where *self* is an ndarray of str or unicode +data-type. However, a chararray can also be created using the +:meth:`numpy.chararray` constructor, or via the +:func:`numpy.char.array ` function: + +.. autosummary:: + :toctree: generated/ + + chararray + core.defchararray.array + +Another difference with the standard ndarray of str data-type is +that the chararray inherits the feature introduced by Numarray that +white-space at the end of any element in the array will be ignored +on item retrieval and comparison operations. + + +.. _arrays.classes.rec: + +Record arrays (:mod:`numpy.rec`) +================================ + +.. seealso:: :ref:`routines.array-creation.rec`, :ref:`routines.dtype`, + :ref:`arrays.dtypes`. + +NumPy provides the :class:`recarray` class which allows accessing the +fields of a structured array as attributes, and a corresponding +scalar data type object :class:`record`. + +.. currentmodule:: numpy + +.. autosummary:: + :toctree: generated/ + + recarray + record + +Masked arrays (:mod:`numpy.ma`) +=============================== + +.. seealso:: :ref:`maskedarray` + +Standard container class +======================== + +.. currentmodule:: numpy + +For backward compatibility and as a standard "container "class, the +UserArray from Numeric has been brought over to NumPy and named +:class:`numpy.lib.user_array.container` The container class is a +Python class whose self.array attribute is an ndarray. Multiple +inheritance is probably easier with numpy.lib.user_array.container +than with the ndarray itself and so it is included by default. It is +not documented here beyond mentioning its existence because you are +encouraged to use the ndarray class directly if you can. + +.. autosummary:: + :toctree: generated/ + + numpy.lib.user_array.container + +.. index:: + single: user_array + single: container class + + +Array Iterators +=============== + +.. currentmodule:: numpy + +.. index:: + single: array iterator + +Iterators are a powerful concept for array processing. Essentially, +iterators implement a generalized for-loop. If *myiter* is an iterator +object, then the Python code:: + + for val in myiter: + ... + some code involving val + ... + +calls ``val = myiter.next()`` repeatedly until :exc:`StopIteration` is +raised by the iterator. There are several ways to iterate over an +array that may be useful: default iteration, flat iteration, and +:math:`N`-dimensional enumeration. + + +Default iteration +----------------- + +The default iterator of an ndarray object is the default Python +iterator of a sequence type. Thus, when the array object itself is +used as an iterator. The default behavior is equivalent to:: + + for i in range(arr.shape[0]): + val = arr[i] + +This default iterator selects a sub-array of dimension :math:`N-1` +from the array. This can be a useful construct for defining recursive +algorithms. To loop over the entire array requires :math:`N` for-loops. + +>>> a = arange(24).reshape(3,2,4)+10 +>>> for val in a: +... print 'item:', val +item: [[10 11 12 13] + [14 15 16 17]] +item: [[18 19 20 21] + [22 23 24 25]] +item: [[26 27 28 29] + [30 31 32 33]] + + +Flat iteration +-------------- + +.. autosummary:: + :toctree: generated/ + + ndarray.flat + +As mentioned previously, the flat attribute of ndarray objects returns +an iterator that will cycle over the entire array in C-style +contiguous order. + +>>> for i, val in enumerate(a.flat): +... if i%5 == 0: print i, val +0 10 +5 15 +10 20 +15 25 +20 30 + +Here, I've used the built-in enumerate iterator to return the iterator +index as well as the value. + + +N-dimensional enumeration +------------------------- + +.. autosummary:: + :toctree: generated/ + + ndenumerate + +Sometimes it may be useful to get the N-dimensional index while +iterating. The ndenumerate iterator can achieve this. + +>>> for i, val in ndenumerate(a): +... if sum(i)%5 == 0: print i, val +(0, 0, 0) 10 +(1, 1, 3) 25 +(2, 0, 3) 29 +(2, 1, 2) 32 + + +Iterator for broadcasting +------------------------- + +.. autosummary:: + :toctree: generated/ + + broadcast + +The general concept of broadcasting is also available from Python +using the :class:`broadcast` iterator. This object takes :math:`N` +objects as inputs and returns an iterator that returns tuples +providing each of the input sequence elements in the broadcasted +result. + +>>> for val in broadcast([[1,0],[2,3]],[0,1]): +... print val +(1, 0) +(0, 1) +(2, 0) +(3, 1) diff --git a/doc/source/reference/arrays.datetime.rst b/doc/source/reference/arrays.datetime.rst new file mode 100644 index 0000000..e64d0c1 --- /dev/null +++ b/doc/source/reference/arrays.datetime.rst @@ -0,0 +1,494 @@ +.. currentmodule:: numpy + +.. _arrays.datetime: + +************************ +Datetimes and Timedeltas +************************ + +.. versionadded:: 1.7.0 + +Starting in NumPy 1.7, there are core array data types which natively +support datetime functionality. The data type is called "datetime64", +so named because "datetime" is already taken by the datetime library +included in Python. + +.. note:: The datetime API is *experimental* in 1.7.0, and may undergo changes + in future versions of NumPy. + +Basic Datetimes +=============== + +The most basic way to create datetimes is from strings in +ISO 8601 date or datetime format. The unit for internal storage +is automatically selected from the form of the string, and can +be either a :ref:`date unit ` or a +:ref:`time unit `. The date units are years ('Y'), +months ('M'), weeks ('W'), and days ('D'), while the time units are +hours ('h'), minutes ('m'), seconds ('s'), milliseconds ('ms'), and +some additional SI-prefix seconds-based units. + +.. admonition:: Example + + A simple ISO date: + + >>> np.datetime64('2005-02-25') + numpy.datetime64('2005-02-25') + + Using months for the unit: + + >>> np.datetime64('2005-02') + numpy.datetime64('2005-02') + + Specifying just the month, but forcing a 'days' unit: + + >>> np.datetime64('2005-02', 'D') + numpy.datetime64('2005-02-01') + + From a date and time: + + >>> np.datetime64('2005-02-25T03:30') + numpy.datetime64('2005-02-25T03:30') + +When creating an array of datetimes from a string, it is still possible +to automatically select the unit from the inputs, by using the +datetime type with generic units. + +.. admonition:: Example + + >>> np.array(['2007-07-13', '2006-01-13', '2010-08-13'], dtype='datetime64') + array(['2007-07-13', '2006-01-13', '2010-08-13'], dtype='datetime64[D]') + + >>> np.array(['2001-01-01T12:00', '2002-02-03T13:56:03.172'], dtype='datetime64') + array(['2001-01-01T12:00:00.000-0600', '2002-02-03T13:56:03.172-0600'], dtype='datetime64[ms]') + + +The datetime type works with many common NumPy functions, for +example :func:`arange` can be used to generate ranges of dates. + +.. admonition:: Example + + All the dates for one month: + + >>> np.arange('2005-02', '2005-03', dtype='datetime64[D]') + array(['2005-02-01', '2005-02-02', '2005-02-03', '2005-02-04', + '2005-02-05', '2005-02-06', '2005-02-07', '2005-02-08', + '2005-02-09', '2005-02-10', '2005-02-11', '2005-02-12', + '2005-02-13', '2005-02-14', '2005-02-15', '2005-02-16', + '2005-02-17', '2005-02-18', '2005-02-19', '2005-02-20', + '2005-02-21', '2005-02-22', '2005-02-23', '2005-02-24', + '2005-02-25', '2005-02-26', '2005-02-27', '2005-02-28'], + dtype='datetime64[D]') + +The datetime object represents a single moment in time. If two +datetimes have different units, they may still be representing +the same moment of time, and converting from a bigger unit like +months to a smaller unit like days is considered a 'safe' cast +because the moment of time is still being represented exactly. + +.. admonition:: Example + + >>> np.datetime64('2005') == np.datetime64('2005-01-01') + True + + >>> np.datetime64('2010-03-14T15Z') == np.datetime64('2010-03-14T15:00:00.00Z') + True + +Datetime and Timedelta Arithmetic +================================= + +NumPy allows the subtraction of two Datetime values, an operation which +produces a number with a time unit. Because NumPy doesn't have a physical +quantities system in its core, the timedelta64 data type was created +to complement datetime64. + +Datetimes and Timedeltas work together to provide ways for +simple datetime calculations. + +.. admonition:: Example + + >>> np.datetime64('2009-01-01') - np.datetime64('2008-01-01') + numpy.timedelta64(366,'D') + + >>> np.datetime64('2009') + np.timedelta64(20, 'D') + numpy.datetime64('2009-01-21') + + >>> np.datetime64('2011-06-15T00:00') + np.timedelta64(12, 'h') + numpy.datetime64('2011-06-15T12:00-0500') + + >>> np.timedelta64(1,'W') / np.timedelta64(1,'D') + 7.0 + +There are two Timedelta units ('Y', years and 'M', months) which are treated +specially, because how much time they represent changes depending +on when they are used. While a timedelta day unit is equivalent to +24 hours, there is no way to convert a month unit into days, because +different months have different numbers of days. + +.. admonition:: Example + + >>> a = np.timedelta64(1, 'Y') + + >>> np.timedelta64(a, 'M') + numpy.timedelta64(12,'M') + + >>> np.timedelta64(a, 'D') + Traceback (most recent call last): + File "", line 1, in + TypeError: Cannot cast NumPy timedelta64 scalar from metadata [Y] to [D] according to the rule 'same_kind' + +Datetime Units +============== + +The Datetime and Timedelta data types support a large number of time +units, as well as generic units which can be coerced into any of the +other units based on input data. + +Datetimes are always stored based on POSIX time (though having a TAI +mode which allows for accounting of leap-seconds is proposed), with +an epoch of 1970-01-01T00:00Z. This means the supported dates are +always a symmetric interval around the epoch, called "time span" in the +table below. + +The length of the span is the range of a 64-bit integer times the length +of the date or unit. For example, the time span for 'W' (week) is exactly +7 times longer than the time span for 'D' (day), and the time span for +'D' (day) is exactly 24 times longer than the time span for 'h' (hour). + +Here are the date units: + +.. _arrays.dtypes.dateunits: + +======== ================ ======================= ========================== + Code Meaning Time span (relative) Time span (absolute) +======== ================ ======================= ========================== + Y year +/- 9.2e18 years [9.2e18 BC, 9.2e18 AD] + M month +/- 7.6e17 years [7.6e17 BC, 7.6e17 AD] + W week +/- 1.7e17 years [1.7e17 BC, 1.7e17 AD] + D day +/- 2.5e16 years [2.5e16 BC, 2.5e16 AD] +======== ================ ======================= ========================== + +And here are the time units: + +.. _arrays.dtypes.timeunits: + +======== ================ ======================= ========================== + Code Meaning Time span (relative) Time span (absolute) +======== ================ ======================= ========================== + h hour +/- 1.0e15 years [1.0e15 BC, 1.0e15 AD] + m minute +/- 1.7e13 years [1.7e13 BC, 1.7e13 AD] + s second +/- 2.9e11 years [2.9e11 BC, 2.9e11 AD] + ms millisecond +/- 2.9e8 years [ 2.9e8 BC, 2.9e8 AD] + us microsecond +/- 2.9e5 years [290301 BC, 294241 AD] + ns nanosecond +/- 292 years [ 1678 AD, 2262 AD] + ps picosecond +/- 106 days [ 1969 AD, 1970 AD] + fs femtosecond +/- 2.6 hours [ 1969 AD, 1970 AD] + as attosecond +/- 9.2 seconds [ 1969 AD, 1970 AD] +======== ================ ======================= ========================== + +Business Day Functionality +========================== + +To allow the datetime to be used in contexts where only certain days of +the week are valid, NumPy includes a set of "busday" (business day) +functions. + +The default for busday functions is that the only valid days are Monday +through Friday (the usual business days). The implementation is based on +a "weekmask" containing 7 Boolean flags to indicate valid days; custom +weekmasks are possible that specify other sets of valid days. + +The "busday" functions can additionally check a list of "holiday" dates, +specific dates that are not valid days. + +The function :func:`busday_offset` allows you to apply offsets +specified in business days to datetimes with a unit of 'D' (day). + +.. admonition:: Example + + >>> np.busday_offset('2011-06-23', 1) + numpy.datetime64('2011-06-24') + + >>> np.busday_offset('2011-06-23', 2) + numpy.datetime64('2011-06-27') + +When an input date falls on the weekend or a holiday, +:func:`busday_offset` first applies a rule to roll the +date to a valid business day, then applies the offset. The +default rule is 'raise', which simply raises an exception. +The rules most typically used are 'forward' and 'backward'. + +.. admonition:: Example + + >>> np.busday_offset('2011-06-25', 2) + Traceback (most recent call last): + File "", line 1, in + ValueError: Non-business day date in busday_offset + + >>> np.busday_offset('2011-06-25', 0, roll='forward') + numpy.datetime64('2011-06-27') + + >>> np.busday_offset('2011-06-25', 2, roll='forward') + numpy.datetime64('2011-06-29') + + >>> np.busday_offset('2011-06-25', 0, roll='backward') + numpy.datetime64('2011-06-24') + + >>> np.busday_offset('2011-06-25', 2, roll='backward') + numpy.datetime64('2011-06-28') + +In some cases, an appropriate use of the roll and the offset +is necessary to get a desired answer. + +.. admonition:: Example + + The first business day on or after a date: + + >>> np.busday_offset('2011-03-20', 0, roll='forward') + numpy.datetime64('2011-03-21','D') + >>> np.busday_offset('2011-03-22', 0, roll='forward') + numpy.datetime64('2011-03-22','D') + + The first business day strictly after a date: + + >>> np.busday_offset('2011-03-20', 1, roll='backward') + numpy.datetime64('2011-03-21','D') + >>> np.busday_offset('2011-03-22', 1, roll='backward') + numpy.datetime64('2011-03-23','D') + +The function is also useful for computing some kinds of days +like holidays. In Canada and the U.S., Mother's day is on +the second Sunday in May, which can be computed with a custom +weekmask. + +.. admonition:: Example + + >>> np.busday_offset('2012-05', 1, roll='forward', weekmask='Sun') + numpy.datetime64('2012-05-13','D') + +When performance is important for manipulating many business dates +with one particular choice of weekmask and holidays, there is +an object :class:`busdaycalendar` which stores the data necessary +in an optimized form. + +np.is_busday(): +``````````````` +To test a datetime64 value to see if it is a valid day, use :func:`is_busday`. + +.. admonition:: Example + + >>> np.is_busday(np.datetime64('2011-07-15')) # a Friday + True + >>> np.is_busday(np.datetime64('2011-07-16')) # a Saturday + False + >>> np.is_busday(np.datetime64('2011-07-16'), weekmask="Sat Sun") + True + >>> a = np.arange(np.datetime64('2011-07-11'), np.datetime64('2011-07-18')) + >>> np.is_busday(a) + array([ True, True, True, True, True, False, False], dtype='bool') + +np.busday_count(): +`````````````````` +To find how many valid days there are in a specified range of datetime64 +dates, use :func:`busday_count`: + +.. admonition:: Example + + >>> np.busday_count(np.datetime64('2011-07-11'), np.datetime64('2011-07-18')) + 5 + >>> np.busday_count(np.datetime64('2011-07-18'), np.datetime64('2011-07-11')) + -5 + +If you have an array of datetime64 day values, and you want a count of +how many of them are valid dates, you can do this: + +.. admonition:: Example + + >>> a = np.arange(np.datetime64('2011-07-11'), np.datetime64('2011-07-18')) + >>> np.count_nonzero(np.is_busday(a)) + 5 + + + +Custom Weekmasks +---------------- + +Here are several examples of custom weekmask values. These examples +specify the "busday" default of Monday through Friday being valid days. + +Some examples:: + + # Positional sequences; positions are Monday through Sunday. + # Length of the sequence must be exactly 7. + weekmask = [1, 1, 1, 1, 1, 0, 0] + # list or other sequence; 0 == invalid day, 1 == valid day + weekmask = "1111100" + # string '0' == invalid day, '1' == valid day + + # string abbreviations from this list: Mon Tue Wed Thu Fri Sat Sun + weekmask = "Mon Tue Wed Thu Fri" + # any amount of whitespace is allowed; abbreviations are case-sensitive. + weekmask = "MonTue Wed Thu\tFri" + +Changes with NumPy 1.11 +======================= + +In prior versions of NumPy, the datetime64 type always stored +times in UTC. By default, creating a datetime64 object from a string or +printing it would convert from or to local time:: + + # old behavior + >>>> np.datetime64('2000-01-01T00:00:00') + numpy.datetime64('2000-01-01T00:00:00-0800') # note the timezone offset -08:00 + +A consensus of datetime64 users agreed that this behavior is undesirable +and at odds with how datetime64 is usually used (e.g., by pandas_). For +most use cases, a timezone naive datetime type is preferred, similar to the +``datetime.datetime`` type in the Python standard library. Accordingly, +datetime64 no longer assumes that input is in local time, nor does it print +local times:: + + >>>> np.datetime64('2000-01-01T00:00:00') + numpy.datetime64('2000-01-01T00:00:00') + +For backwards compatibility, datetime64 still parses timezone offsets, which +it handles by converting to UTC. However, the resulting datetime is timezone +naive:: + + >>> np.datetime64('2000-01-01T00:00:00-08') + DeprecationWarning: parsing timezone aware datetimes is deprecated; this will raise an error in the future + numpy.datetime64('2000-01-01T08:00:00') + +As a corollary to this change, we no longer prohibit casting between datetimes +with date units and datetimes with timeunits. With timezone naive datetimes, +the rule for casting from dates to times is no longer ambiguous. + +.. _pandas: http://pandas.pydata.org + + +Differences Between 1.6 and 1.7 Datetimes +========================================= + +The NumPy 1.6 release includes a more primitive datetime data type +than 1.7. This section documents many of the changes that have taken +place. + +String Parsing +`````````````` + +The datetime string parser in NumPy 1.6 is very liberal in what it accepts, +and silently allows invalid input without raising errors. The parser in +NumPy 1.7 is quite strict about only accepting ISO 8601 dates, with a few +convenience extensions. 1.6 always creates microsecond (us) units by +default, whereas 1.7 detects a unit based on the format of the string. +Here is a comparison.:: + + # NumPy 1.6.1 + >>> np.datetime64('1979-03-22') + 1979-03-22 00:00:00 + # NumPy 1.7.0 + >>> np.datetime64('1979-03-22') + numpy.datetime64('1979-03-22') + + # NumPy 1.6.1, unit default microseconds + >>> np.datetime64('1979-03-22').dtype + dtype('datetime64[us]') + # NumPy 1.7.0, unit of days detected from string + >>> np.datetime64('1979-03-22').dtype + dtype('>> np.datetime64('1979-03-2corruptedstring') + 1979-03-02 00:00:00 + # NumPy 1.7.0, raises error for invalid input + >>> np.datetime64('1979-03-2corruptedstring') + Traceback (most recent call last): + File "", line 1, in + ValueError: Error parsing datetime string "1979-03-2corruptedstring" at position 8 + + # NumPy 1.6.1, 'nat' produces today's date + >>> np.datetime64('nat') + 2012-04-30 00:00:00 + # NumPy 1.7.0, 'nat' produces not-a-time + >>> np.datetime64('nat') + numpy.datetime64('NaT') + + # NumPy 1.6.1, 'garbage' produces today's date + >>> np.datetime64('garbage') + 2012-04-30 00:00:00 + # NumPy 1.7.0, 'garbage' raises an exception + >>> np.datetime64('garbage') + Traceback (most recent call last): + File "", line 1, in + ValueError: Error parsing datetime string "garbage" at position 0 + + # NumPy 1.6.1, can't specify unit in scalar constructor + >>> np.datetime64('1979-03-22T19:00', 'h') + Traceback (most recent call last): + File "", line 1, in + TypeError: function takes at most 1 argument (2 given) + # NumPy 1.7.0, unit in scalar constructor + >>> np.datetime64('1979-03-22T19:00', 'h') + numpy.datetime64('1979-03-22T19:00-0500','h') + + # NumPy 1.6.1, reads ISO 8601 strings w/o TZ as UTC + >>> np.array(['1979-03-22T19:00'], dtype='M8[h]') + array([1979-03-22 19:00:00], dtype=datetime64[h]) + # NumPy 1.7.0, reads ISO 8601 strings w/o TZ as local (ISO specifies this) + >>> np.array(['1979-03-22T19:00'], dtype='M8[h]') + array(['1979-03-22T19-0500'], dtype='datetime64[h]') + + # NumPy 1.6.1, doesn't parse all ISO 8601 strings correctly + >>> np.array(['1979-03-22T12'], dtype='M8[h]') + array([1979-03-22 00:00:00], dtype=datetime64[h]) + >>> np.array(['1979-03-22T12:00'], dtype='M8[h]') + array([1979-03-22 12:00:00], dtype=datetime64[h]) + # NumPy 1.7.0, handles this case correctly + >>> np.array(['1979-03-22T12'], dtype='M8[h]') + array(['1979-03-22T12-0500'], dtype='datetime64[h]') + >>> np.array(['1979-03-22T12:00'], dtype='M8[h]') + array(['1979-03-22T12-0500'], dtype='datetime64[h]') + +Unit Conversion +``````````````` + +The 1.6 implementation of datetime does not convert between units correctly.:: + + # NumPy 1.6.1, the representation value is untouched + >>> np.array(['1979-03-22'], dtype='M8[D]') + array([1979-03-22 00:00:00], dtype=datetime64[D]) + >>> np.array(['1979-03-22'], dtype='M8[D]').astype('M8[M]') + array([2250-08-01 00:00:00], dtype=datetime64[M]) + # NumPy 1.7.0, the representation is scaled accordingly + >>> np.array(['1979-03-22'], dtype='M8[D]') + array(['1979-03-22'], dtype='datetime64[D]') + >>> np.array(['1979-03-22'], dtype='M8[D]').astype('M8[M]') + array(['1979-03'], dtype='datetime64[M]') + +Datetime Arithmetic +``````````````````` + +The 1.6 implementation of datetime only works correctly for a small subset of +arithmetic operations. Here we show some simple cases.:: + + # NumPy 1.6.1, produces invalid results if units are incompatible + >>> a = np.array(['1979-03-22T12'], dtype='M8[h]') + >>> b = np.array([3*60], dtype='m8[m]') + >>> a + b + array([1970-01-01 00:00:00.080988], dtype=datetime64[us]) + # NumPy 1.7.0, promotes to higher-resolution unit + >>> a = np.array(['1979-03-22T12'], dtype='M8[h]') + >>> b = np.array([3*60], dtype='m8[m]') + >>> a + b + array(['1979-03-22T15:00-0500'], dtype='datetime64[m]') + + # NumPy 1.6.1, arithmetic works if everything is microseconds + >>> a = np.array(['1979-03-22T12:00'], dtype='M8[us]') + >>> b = np.array([3*60*60*1000000], dtype='m8[us]') + >>> a + b + array([1979-03-22 15:00:00], dtype=datetime64[us]) + # NumPy 1.7.0 + >>> a = np.array(['1979-03-22T12:00'], dtype='M8[us]') + >>> b = np.array([3*60*60*1000000], dtype='m8[us]') + >>> a + b + array(['1979-03-22T15:00:00.000000-0500'], dtype='datetime64[us]') diff --git a/doc/source/reference/arrays.dtypes.rst b/doc/source/reference/arrays.dtypes.rst new file mode 100644 index 0000000..dcf04b4 --- /dev/null +++ b/doc/source/reference/arrays.dtypes.rst @@ -0,0 +1,557 @@ +.. currentmodule:: numpy + +.. _arrays.dtypes: + +********************************** +Data type objects (:class:`dtype`) +********************************** + +A data type object (an instance of :class:`numpy.dtype` class) +describes how the bytes in the fixed-size block of memory +corresponding to an array item should be interpreted. It describes the +following aspects of the data: + +1. Type of the data (integer, float, Python object, etc.) +2. Size of the data (how many bytes is in *e.g.* the integer) +3. Byte order of the data (:term:`little-endian` or :term:`big-endian`) +4. If the data type is :term:`structured`, an aggregate of other + data types, (*e.g.*, describing an array item consisting of + an integer and a float), + + 1. what are the names of the ":term:`fields `" of the structure, + by which they can be :ref:`accessed `, + 2. what is the data-type of each :term:`field`, and + 3. which part of the memory block each field takes. + +5. If the data type is a sub-array, what is its shape and data type. + +.. index:: + pair: dtype; scalar + +To describe the type of scalar data, there are several :ref:`built-in +scalar types ` in NumPy for various precision +of integers, floating-point numbers, *etc*. An item extracted from an +array, *e.g.*, by indexing, will be a Python object whose type is the +scalar type associated with the data type of the array. + +Note that the scalar types are not :class:`dtype` objects, even though +they can be used in place of one whenever a data type specification is +needed in NumPy. + +.. index:: + pair: dtype; field + +Structured data types are formed by creating a data type whose +:term:`fields` contain other data types. Each field has a name by +which it can be :ref:`accessed `. The parent data +type should be of sufficient size to contain all its fields; the +parent is nearly always based on the :class:`void` type which allows +an arbitrary item size. Structured data types may also contain nested +structured sub-array data types in their fields. + +.. index:: + pair: dtype; sub-array + +Finally, a data type can describe items that are themselves arrays of +items of another data type. These sub-arrays must, however, be of a +fixed size. + +If an array is created using a data-type describing a sub-array, +the dimensions of the sub-array are appended to the shape +of the array when the array is created. Sub-arrays in a field of a +structured type behave differently, see :ref:`arrays.indexing.fields`. + +Sub-arrays always have a C-contiguous memory layout. + +.. admonition:: Example + + A simple data type containing a 32-bit big-endian integer: + (see :ref:`arrays.dtypes.constructing` for details on construction) + + >>> dt = np.dtype('>i4') + >>> dt.byteorder + '>' + >>> dt.itemsize + 4 + >>> dt.name + 'int32' + >>> dt.type is np.int32 + True + + The corresponding array scalar type is :class:`int32`. + +.. admonition:: Example + + A structured data type containing a 16-character string (in field 'name') + and a sub-array of two 64-bit floating-point number (in field 'grades'): + + >>> dt = np.dtype([('name', np.unicode_, 16), ('grades', np.float64, (2,))]) + >>> dt['name'] + dtype('|U16') + >>> dt['grades'] + dtype(('float64',(2,))) + + Items of an array of this data type are wrapped in an :ref:`array + scalar ` type that also has two fields: + + >>> x = np.array([('Sarah', (8.0, 7.0)), ('John', (6.0, 7.0))], dtype=dt) + >>> x[1] + ('John', [6.0, 7.0]) + >>> x[1]['grades'] + array([ 6., 7.]) + >>> type(x[1]) + + >>> type(x[1]['grades']) + + +.. _arrays.dtypes.constructing: + +Specifying and constructing data types +====================================== + +Whenever a data-type is required in a NumPy function or method, either +a :class:`dtype` object or something that can be converted to one can +be supplied. Such conversions are done by the :class:`dtype` +constructor: + +.. autosummary:: + :toctree: generated/ + + dtype + +What can be converted to a data-type object is described below: + +:class:`dtype` object + + .. index:: + triple: dtype; construction; from dtype + + Used as-is. + +:const:`None` + + .. index:: + triple: dtype; construction; from None + + The default data type: :class:`float_`. + +.. index:: + triple: dtype; construction; from type + +Array-scalar types + + The 24 built-in :ref:`array scalar type objects + ` all convert to an associated data-type object. + This is true for their sub-classes as well. + + Note that not all data-type information can be supplied with a + type-object: for example, :term:`flexible` data-types have + a default *itemsize* of 0, and require an explicitly given size + to be useful. + + .. admonition:: Example + + >>> dt = np.dtype(np.int32) # 32-bit integer + >>> dt = np.dtype(np.complex128) # 128-bit complex floating-point number + +Generic types + + The generic hierarchical type objects convert to corresponding + type objects according to the associations: + + ===================================================== =============== + :class:`number`, :class:`inexact`, :class:`floating` :class:`float` + :class:`complexfloating` :class:`cfloat` + :class:`integer`, :class:`signedinteger` :class:`int\_` + :class:`unsignedinteger` :class:`uint` + :class:`character` :class:`string` + :class:`generic`, :class:`flexible` :class:`void` + ===================================================== =============== + +Built-in Python types + + Several python types are equivalent to a corresponding + array scalar when used to generate a :class:`dtype` object: + + ================ =============== + :class:`int` :class:`int\_` + :class:`bool` :class:`bool\_` + :class:`float` :class:`float\_` + :class:`complex` :class:`cfloat` + :class:`bytes` :class:`bytes\_` + :class:`str` :class:`bytes\_` (Python2) or :class:`unicode\_` (Python3) + :class:`unicode` :class:`unicode\_` + :class:`buffer` :class:`void` + (all others) :class:`object_` + ================ =============== + + Note that ``str`` refers to either null terminated bytes or unicode strings + depending on the Python version. In code targeting both Python 2 and 3 + ``np.unicode_`` should be used as a dtype for strings. + See :ref:`Note on string types`. + + .. admonition:: Example + + >>> dt = np.dtype(float) # Python-compatible floating-point number + >>> dt = np.dtype(int) # Python-compatible integer + >>> dt = np.dtype(object) # Python object + +Types with ``.dtype`` + + Any type object with a ``dtype`` attribute: The attribute will be + accessed and used directly. The attribute must return something + that is convertible into a dtype object. + +.. index:: + triple: dtype; construction; from string + +Several kinds of strings can be converted. Recognized strings can be +prepended with ``'>'`` (:term:`big-endian`), ``'<'`` +(:term:`little-endian`), or ``'='`` (hardware-native, the default), to +specify the byte order. + +One-character strings + + Each built-in data-type has a character code + (the updated Numeric typecodes), that uniquely identifies it. + + .. admonition:: Example + + >>> dt = np.dtype('b') # byte, native byte order + >>> dt = np.dtype('>H') # big-endian unsigned short + >>> dt = np.dtype('>> dt = np.dtype('d') # double-precision floating-point number + +Array-protocol type strings (see :ref:`arrays.interface`) + + The first character specifies the kind of data and the remaining + characters specify the number of bytes per item, except for Unicode, + where it is interpreted as the number of characters. The item size + must correspond to an existing type, or an error will be raised. The + supported kinds are + + ================ ======================== + ``'?'`` boolean + ``'b'`` (signed) byte + ``'B'`` unsigned byte + ``'i'`` (signed) integer + ``'u'`` unsigned integer + ``'f'`` floating-point + ``'c'`` complex-floating point + ``'m'`` timedelta + ``'M'`` datetime + ``'O'`` (Python) objects + ``'S'``, ``'a'`` zero-terminated bytes (not recommended) + ``'U'`` Unicode string + ``'V'`` raw data (:class:`void`) + ================ ======================== + + .. admonition:: Example + + >>> dt = np.dtype('i4') # 32-bit signed integer + >>> dt = np.dtype('f8') # 64-bit floating-point number + >>> dt = np.dtype('c16') # 128-bit complex floating-point number + >>> dt = np.dtype('a25') # 25-length zero-terminated bytes + >>> dt = np.dtype('U25') # 25-character string + + .. _string-dtype-note: + + .. admonition:: Note on string types + + For backward compatibility with Python 2 the ``S`` and ``a`` typestrings + remain zero-terminated bytes and ``np.string_`` continues to map to + ``np.bytes_``. + To use actual strings in Python 3 use ``U`` or ``np.unicode_``. + For signed bytes that do not need zero-termination ``b`` or ``i1`` can be + used. + +String with comma-separated fields + + A short-hand notation for specifying the format of a structured data type is + a comma-separated string of basic formats. + + A basic format in this context is an optional shape specifier + followed by an array-protocol type string. Parenthesis are required + on the shape if it has more than one dimension. NumPy allows a modification + on the format in that any string that can uniquely identify the + type can be used to specify the data-type in a field. + The generated data-type fields are named ``'f0'``, ``'f1'``, ..., + ``'f'`` where N (>1) is the number of comma-separated basic + formats in the string. If the optional shape specifier is provided, + then the data-type for the corresponding field describes a sub-array. + + .. admonition:: Example + + - field named ``f0`` containing a 32-bit integer + - field named ``f1`` containing a 2 x 3 sub-array + of 64-bit floating-point numbers + - field named ``f2`` containing a 32-bit floating-point number + + >>> dt = np.dtype("i4, (2,3)f8, f4") + + - field named ``f0`` containing a 3-character string + - field named ``f1`` containing a sub-array of shape (3,) + containing 64-bit unsigned integers + - field named ``f2`` containing a 3 x 4 sub-array + containing 10-character strings + + >>> dt = np.dtype("a3, 3u8, (3,4)a10") + +Type strings + + Any string in :obj:`numpy.sctypeDict`.keys(): + + .. admonition:: Example + + >>> dt = np.dtype('uint32') # 32-bit unsigned integer + >>> dt = np.dtype('Float64') # 64-bit floating-point number + +.. index:: + triple: dtype; construction; from tuple + +``(flexible_dtype, itemsize)`` + + The first argument must be an object that is converted to a + zero-sized flexible data-type object, the second argument is + an integer providing the desired itemsize. + + .. admonition:: Example + + >>> dt = np.dtype((np.void, 10)) # 10-byte wide data block + >>> dt = np.dtype(('U', 10)) # 10-character unicode string + +``(fixed_dtype, shape)`` + + .. index:: + pair: dtype; sub-array + + The first argument is any object that can be converted into a + fixed-size data-type object. The second argument is the desired + shape of this type. If the shape parameter is 1, then the + data-type object is equivalent to fixed dtype. If *shape* is a + tuple, then the new dtype defines a sub-array of the given shape. + + .. admonition:: Example + + >>> dt = np.dtype((np.int32, (2,2))) # 2 x 2 integer sub-array + >>> dt = np.dtype(('U10', 1)) # 10-character string + >>> dt = np.dtype(('i4, (2,3)f8, f4', (2,3))) # 2 x 3 structured sub-array + +.. index:: + triple: dtype; construction; from list + +``[(field_name, field_dtype, field_shape), ...]`` + + *obj* should be a list of fields where each field is described by a + tuple of length 2 or 3. (Equivalent to the ``descr`` item in the + :obj:`__array_interface__` attribute.) + + The first element, *field_name*, is the field name (if this is + ``''`` then a standard field name, ``'f#'``, is assigned). The + field name may also be a 2-tuple of strings where the first string + is either a "title" (which may be any string or unicode string) or + meta-data for the field which can be any object, and the second + string is the "name" which must be a valid Python identifier. + + The second element, *field_dtype*, can be anything that can be + interpreted as a data-type. + + The optional third element *field_shape* contains the shape if this + field represents an array of the data-type in the second + element. Note that a 3-tuple with a third argument equal to 1 is + equivalent to a 2-tuple. + + This style does not accept *align* in the :class:`dtype` + constructor as it is assumed that all of the memory is accounted + for by the array interface description. + + .. admonition:: Example + + Data-type with fields ``big`` (big-endian 32-bit integer) and + ``little`` (little-endian 32-bit integer): + + >>> dt = np.dtype([('big', '>i4'), ('little', '>> dt = np.dtype([('R','u1'), ('G','u1'), ('B','u1'), ('A','u1')]) + +.. index:: + triple: dtype; construction; from dict + +``{'names': ..., 'formats': ..., 'offsets': ..., 'titles': ..., 'itemsize': ...}`` + + This style has two required and three optional keys. The *names* + and *formats* keys are required. Their respective values are + equal-length lists with the field names and the field formats. + The field names must be strings and the field formats can be any + object accepted by :class:`dtype` constructor. + + When the optional keys *offsets* and *titles* are provided, + their values must each be lists of the same length as the *names* + and *formats* lists. The *offsets* value is a list of byte offsets + (integers) for each field, while the *titles* value is a list of + titles for each field (:const:`None` can be used if no title is + desired for that field). The *titles* can be any :class:`string` + or :class:`unicode` object and will add another entry to the + fields dictionary keyed by the title and referencing the same + field tuple which will contain the title as an additional tuple + member. + + The *itemsize* key allows the total size of the dtype to be + set, and must be an integer large enough so all the fields + are within the dtype. If the dtype being constructed is aligned, + the *itemsize* must also be divisible by the struct alignment. + + .. admonition:: Example + + Data type with fields ``r``, ``g``, ``b``, ``a``, each being + an 8-bit unsigned integer: + + >>> dt = np.dtype({'names': ['r','g','b','a'], + ... 'formats': [uint8, uint8, uint8, uint8]}) + + Data type with fields ``r`` and ``b`` (with the given titles), + both being 8-bit unsigned integers, the first at byte position + 0 from the start of the field and the second at position 2: + + >>> dt = np.dtype({'names': ['r','b'], 'formats': ['u1', 'u1'], + ... 'offsets': [0, 2], + ... 'titles': ['Red pixel', 'Blue pixel']}) + + +``{'field1': ..., 'field2': ..., ...}`` + + This usage is discouraged, because it is ambiguous with the + other dict-based construction method. If you have a field + called 'names' and a field called 'formats' there will be + a conflict. + + This style allows passing in the :attr:`fields ` + attribute of a data-type object. + + *obj* should contain string or unicode keys that refer to + ``(data-type, offset)`` or ``(data-type, offset, title)`` tuples. + + .. admonition:: Example + + Data type containing field ``col1`` (10-character string at + byte position 0), ``col2`` (32-bit float at byte position 10), + and ``col3`` (integers at byte position 14): + + >>> dt = np.dtype({'col1': ('U10', 0), 'col2': (float32, 10), + 'col3': (int, 14)}) + +``(base_dtype, new_dtype)`` + + In NumPy 1.7 and later, this form allows `base_dtype` to be interpreted as + a structured dtype. Arrays created with this dtype will have underlying + dtype `base_dtype` but will have fields and flags taken from `new_dtype`. + This is useful for creating custom structured dtypes, as done in + :ref:`record arrays `. + + This form also makes it possible to specify struct dtypes with overlapping + fields, functioning like the 'union' type in C. This usage is discouraged, + however, and the union mechanism is preferred. + + Both arguments must be convertible to data-type objects with the same total + size. + .. admonition:: Example + + 32-bit integer, whose first two bytes are interpreted as an integer + via field ``real``, and the following two bytes via field ``imag``. + + >>> dt = np.dtype((np.int32,{'real':(np.int16, 0),'imag':(np.int16, 2)}) + + 32-bit integer, which is interpreted as consisting of a sub-array + of shape ``(4,)`` containing 8-bit integers: + + >>> dt = np.dtype((np.int32, (np.int8, 4))) + + 32-bit integer, containing fields ``r``, ``g``, ``b``, ``a`` that + interpret the 4 bytes in the integer as four unsigned integers: + + >>> dt = np.dtype(('i4', [('r','u1'),('g','u1'),('b','u1'),('a','u1')])) + + +:class:`dtype` +============== + +NumPy data type descriptions are instances of the :class:`dtype` class. + +Attributes +---------- + +The type of the data is described by the following :class:`dtype` attributes: + +.. autosummary:: + :toctree: generated/ + + dtype.type + dtype.kind + dtype.char + dtype.num + dtype.str + +Size of the data is in turn described by: + +.. autosummary:: + :toctree: generated/ + + dtype.name + dtype.itemsize + +Endianness of this data: + +.. autosummary:: + :toctree: generated/ + + dtype.byteorder + +Information about sub-data-types in a :term:`structured` data type: + +.. autosummary:: + :toctree: generated/ + + dtype.fields + dtype.names + +For data types that describe sub-arrays: + +.. autosummary:: + :toctree: generated/ + + dtype.subdtype + dtype.shape + +Attributes providing additional information: + +.. autosummary:: + :toctree: generated/ + + dtype.hasobject + dtype.flags + dtype.isbuiltin + dtype.isnative + dtype.descr + dtype.alignment + + +Methods +------- + +Data types have the following method for changing the byte order: + +.. autosummary:: + :toctree: generated/ + + dtype.newbyteorder + +The following methods implement the pickle protocol: + +.. autosummary:: + :toctree: generated/ + + dtype.__reduce__ + dtype.__setstate__ diff --git a/doc/source/reference/arrays.indexing.rst b/doc/source/reference/arrays.indexing.rst new file mode 100644 index 0000000..b5a44c2 --- /dev/null +++ b/doc/source/reference/arrays.indexing.rst @@ -0,0 +1,549 @@ +.. _arrays.indexing: + +Indexing +======== + +.. sectionauthor:: adapted from "Guide to NumPy" by Travis E. Oliphant + +.. currentmodule:: numpy + +.. index:: indexing, slicing + +:class:`ndarrays ` can be indexed using the standard Python +``x[obj]`` syntax, where *x* is the array and *obj* the selection. +There are three kinds of indexing available: field access, basic +slicing, advanced indexing. Which one occurs depends on *obj*. + +.. note:: + + In Python, ``x[(exp1, exp2, ..., expN)]`` is equivalent to + ``x[exp1, exp2, ..., expN]``; the latter is just syntactic sugar + for the former. + + +Basic Slicing and Indexing +-------------------------- + +Basic slicing extends Python's basic concept of slicing to N +dimensions. Basic slicing occurs when *obj* is a :class:`slice` object +(constructed by ``start:stop:step`` notation inside of brackets), an +integer, or a tuple of slice objects and integers. :const:`Ellipsis` +and :const:`newaxis` objects can be interspersed with these as +well. In order to remain backward compatible with a common usage in +Numeric, basic slicing is also initiated if the selection object is +any non-ndarray sequence (such as a :class:`list`) containing :class:`slice` +objects, the :const:`Ellipsis` object, or the :const:`newaxis` object, +but not for integer arrays or other embedded sequences. + +.. index:: + triple: ndarray; special methods; getitem + triple: ndarray; special methods; setitem + single: ellipsis + single: newaxis + +The simplest case of indexing with *N* integers returns an :ref:`array +scalar ` representing the corresponding item. As in +Python, all indices are zero-based: for the *i*-th index :math:`n_i`, +the valid range is :math:`0 \le n_i < d_i` where :math:`d_i` is the +*i*-th element of the shape of the array. Negative indices are +interpreted as counting from the end of the array (*i.e.*, if +:math:`n_i < 0`, it means :math:`n_i + d_i`). + + +All arrays generated by basic slicing are always :term:`views ` +of the original array. + +The standard rules of sequence slicing apply to basic slicing on a +per-dimension basis (including using a step index). Some useful +concepts to remember include: + +- The basic slice syntax is ``i:j:k`` where *i* is the starting index, + *j* is the stopping index, and *k* is the step (:math:`k\neq0`). + This selects the *m* elements (in the corresponding dimension) with + index values *i*, *i + k*, ..., *i + (m - 1) k* where + :math:`m = q + (r\neq0)` and *q* and *r* are the quotient and remainder + obtained by dividing *j - i* by *k*: *j - i = q k + r*, so that + *i + (m - 1) k < j*. + + .. admonition:: Example + + >>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> x[1:7:2] + array([1, 3, 5]) + +- Negative *i* and *j* are interpreted as *n + i* and *n + j* where + *n* is the number of elements in the corresponding dimension. + Negative *k* makes stepping go towards smaller indices. + + .. admonition:: Example + + >>> x[-2:10] + array([8, 9]) + >>> x[-3:3:-1] + array([7, 6, 5, 4]) + +- Assume *n* is the number of elements in the dimension being + sliced. Then, if *i* is not given it defaults to 0 for *k > 0* and + *n - 1* for *k < 0* . If *j* is not given it defaults to *n* for *k > 0* + and *-n-1* for *k < 0* . If *k* is not given it defaults to 1. Note that + ``::`` is the same as ``:`` and means select all indices along this + axis. + + .. admonition:: Example + + >>> x[5:] + array([5, 6, 7, 8, 9]) + +- If the number of objects in the selection tuple is less than + *N* , then ``:`` is assumed for any subsequent dimensions. + + .. admonition:: Example + + >>> x = np.array([[[1],[2],[3]], [[4],[5],[6]]]) + >>> x.shape + (2, 3, 1) + >>> x[1:2] + array([[[4], + [5], + [6]]]) + +- :const:`Ellipsis` expand to the number of ``:`` objects needed to + make a selection tuple of the same length as ``x.ndim``. There may + only be a single ellipsis present. + + .. admonition:: Example + + >>> x[...,0] + array([[1, 2, 3], + [4, 5, 6]]) + +- Each :const:`newaxis` object in the selection tuple serves to expand + the dimensions of the resulting selection by one unit-length + dimension. The added dimension is the position of the :const:`newaxis` + object in the selection tuple. + + .. admonition:: Example + + >>> x[:,np.newaxis,:,:].shape + (2, 1, 3, 1) + +- An integer, *i*, returns the same values as ``i:i+1`` + **except** the dimensionality of the returned object is reduced by + 1. In particular, a selection tuple with the *p*-th + element an integer (and all other entries ``:``) returns the + corresponding sub-array with dimension *N - 1*. If *N = 1* + then the returned object is an array scalar. These objects are + explained in :ref:`arrays.scalars`. + +- If the selection tuple has all entries ``:`` except the + *p*-th entry which is a slice object ``i:j:k``, + then the returned array has dimension *N* formed by + concatenating the sub-arrays returned by integer indexing of + elements *i*, *i+k*, ..., *i + (m - 1) k < j*, + +- Basic slicing with more than one non-``:`` entry in the slicing + tuple, acts like repeated application of slicing using a single + non-``:`` entry, where the non-``:`` entries are successively taken + (with all other non-``:`` entries replaced by ``:``). Thus, + ``x[ind1,...,ind2,:]`` acts like ``x[ind1][...,ind2,:]`` under basic + slicing. + + .. warning:: The above is **not** true for advanced indexing. + +- You may use slicing to set values in the array, but (unlike lists) you + can never grow the array. The size of the value to be set in + ``x[obj] = value`` must be (broadcastable) to the same shape as + ``x[obj]``. + +.. index:: + pair: ndarray; view + +.. note:: + + Remember that a slicing tuple can always be constructed as *obj* + and used in the ``x[obj]`` notation. Slice objects can be used in + the construction in place of the ``[start:stop:step]`` + notation. For example, ``x[1:10:5,::-1]`` can also be implemented + as ``obj = (slice(1,10,5), slice(None,None,-1)); x[obj]`` . This + can be useful for constructing generic code that works on arrays + of arbitrary dimension. + +.. data:: newaxis + + The :const:`newaxis` object can be used in all slicing operations to + create an axis of length one. :const:`newaxis` is an alias for + 'None', and 'None' can be used in place of this with the same result. + + +Advanced Indexing +----------------- + +Advanced indexing is triggered when the selection object, *obj*, is a +non-tuple sequence object, an :class:`ndarray` (of data type integer or bool), +or a tuple with at least one sequence object or ndarray (of data type +integer or bool). There are two types of advanced indexing: integer +and Boolean. + +Advanced indexing always returns a *copy* of the data (contrast with +basic slicing that returns a :term:`view`). + +.. warning:: + + The definition of advanced indexing means that ``x[(1,2,3),]`` is + fundamentally different than ``x[(1,2,3)]``. The latter is + equivalent to ``x[1,2,3]`` which will trigger basic selection while + the former will trigger advanced indexing. Be sure to understand + why this occurs. + + Also recognize that ``x[[1,2,3]]`` will trigger advanced indexing, + whereas ``x[[1,2,slice(None)]]`` will trigger basic slicing. + +Integer array indexing +^^^^^^^^^^^^^^^^^^^^^^ + +Integer array indexing allows selection of arbitrary items in the array +based on their *N*-dimensional index. Each integer array represents a number +of indexes into that dimension. + +Purely integer array indexing +""""""""""""""""""""""""""""" + +When the index consists of as many integer arrays as the array being indexed +has dimensions, the indexing is straight forward, but different from slicing. + +Advanced indexes always are :ref:`broadcast` and +iterated as *one*:: + + result[i_1, ..., i_M] == x[ind_1[i_1, ..., i_M], ind_2[i_1, ..., i_M], + ..., ind_N[i_1, ..., i_M]] + +Note that the result shape is identical to the (broadcast) indexing array +shapes ``ind_1, ..., ind_N``. + +.. admonition:: Example + + From each row, a specific element should be selected. The row index is just + ``[0, 1, 2]`` and the column index specifies the element to choose for the + corresponding row, here ``[0, 1, 0]``. Using both together the task + can be solved using advanced indexing: + + >>> x = np.array([[1, 2], [3, 4], [5, 6]]) + >>> x[[0, 1, 2], [0, 1, 0]] + array([1, 4, 5]) + +To achieve a behaviour similar to the basic slicing above, broadcasting can be +used. The function :func:`ix_` can help with this broadcasting. This is best +understood with an example. + +.. admonition:: Example + + From a 4x3 array the corner elements should be selected using advanced + indexing. Thus all elements for which the column is one of ``[0, 2]`` and + the row is one of ``[0, 3]`` need to be selected. To use advanced indexing + one needs to select all elements *explicitly*. Using the method explained + previously one could write: + + >>> x = array([[ 0, 1, 2], + ... [ 3, 4, 5], + ... [ 6, 7, 8], + ... [ 9, 10, 11]]) + >>> rows = np.array([[0, 0], + ... [3, 3]], dtype=np.intp) + >>> columns = np.array([[0, 2], + ... [0, 2]], dtype=np.intp) + >>> x[rows, columns] + array([[ 0, 2], + [ 9, 11]]) + + However, since the indexing arrays above just repeat themselves, + broadcasting can be used (compare operations such as + ``rows[:, np.newaxis] + columns``) to simplify this: + + >>> rows = np.array([0, 3], dtype=np.intp) + >>> columns = np.array([0, 2], dtype=np.intp) + >>> rows[:, np.newaxis] + array([[0], + [3]]) + >>> x[rows[:, np.newaxis], columns] + array([[ 0, 2], + [ 9, 11]]) + + This broadcasting can also be achieved using the function :func:`ix_`: + + >>> x[np.ix_(rows, columns)] + array([[ 0, 2], + [ 9, 11]]) + + Note that without the ``np.ix_`` call, only the diagonal elements would + be selected, as was used in the previous example. This difference is the + most important thing to remember about indexing with multiple advanced + indexes. + +Combining advanced and basic indexing +""""""""""""""""""""""""""""""""""""" + +When there is at least one slice (``:``), ellipsis (``...``) or ``np.newaxis`` +in the index (or the array has more dimensions than there are advanced indexes), +then the behaviour can be more complicated. It is like concatenating the +indexing result for each advanced index element + +In the simplest case, there is only a *single* advanced index. A single +advanced index can for example replace a slice and the result array will be +the same, however, it is a copy and may have a different memory layout. +A slice is preferable when it is possible. + +.. admonition:: Example + + >>> x[1:2, 1:3] + array([[4, 5]]) + >>> x[1:2, [1, 2]] + array([[4, 5]]) + +The easiest way to understand the situation may be to think in +terms of the result shape. There are two parts to the indexing operation, +the subspace defined by the basic indexing (excluding integers) and the +subspace from the advanced indexing part. Two cases of index combination +need to be distinguished: + +* The advanced indexes are separated by a slice, ellipsis or newaxis. + For example ``x[arr1, :, arr2]``. +* The advanced indexes are all next to each other. + For example ``x[..., arr1, arr2, :]`` but *not* ``x[arr1, :, 1]`` + since ``1`` is an advanced index in this regard. + +In the first case, the dimensions resulting from the advanced indexing +operation come first in the result array, and the subspace dimensions after +that. +In the second case, the dimensions from the advanced indexing operations +are inserted into the result array at the same spot as they were in the +initial array (the latter logic is what makes simple advanced indexing +behave just like slicing). + +.. admonition:: Example + + Suppose ``x.shape`` is (10,20,30) and ``ind`` is a (2,3,4)-shaped + indexing :class:`intp` array, then ``result = x[...,ind,:]`` has + shape (10,2,3,4,30) because the (20,)-shaped subspace has been + replaced with a (2,3,4)-shaped broadcasted indexing subspace. If + we let *i, j, k* loop over the (2,3,4)-shaped subspace then + ``result[...,i,j,k,:] = x[...,ind[i,j,k],:]``. This example + produces the same result as :meth:`x.take(ind, axis=-2) `. + +.. admonition:: Example + + Let ``x.shape`` be (10,20,30,40,50) and suppose ``ind_1`` + and ``ind_2`` can be broadcast to the shape (2,3,4). Then + ``x[:,ind_1,ind_2]`` has shape (10,2,3,4,40,50) because the + (20,30)-shaped subspace from X has been replaced with the + (2,3,4) subspace from the indices. However, + ``x[:,ind_1,:,ind_2]`` has shape (2,3,4,10,30,50) because there + is no unambiguous place to drop in the indexing subspace, thus + it is tacked-on to the beginning. It is always possible to use + :meth:`.transpose() ` to move the subspace + anywhere desired. Note that this example cannot be replicated + using :func:`take`. + + +Boolean array indexing +^^^^^^^^^^^^^^^^^^^^^^ + +This advanced indexing occurs when obj is an array object of Boolean +type, such as may be returned from comparison operators. A single +boolean index array is practically identical to ``x[obj.nonzero()]`` where, +as described above, :meth:`obj.nonzero() ` returns a +tuple (of length :attr:`obj.ndim `) of integer index +arrays showing the :const:`True` elements of *obj*. However, it is +faster when ``obj.shape == x.shape``. + +If ``obj.ndim == x.ndim``, ``x[obj]`` returns a 1-dimensional array +filled with the elements of *x* corresponding to the :const:`True` +values of *obj*. The search order will be :term:`row-major`, +C-style. If *obj* has :const:`True` values at entries that are outside +of the bounds of *x*, then an index error will be raised. If *obj* is +smaller than *x* it is identical to filling it with :const:`False`. + +.. admonition:: Example + + A common use case for this is filtering for desired element values. + For example one may wish to select all entries from an array which + are not NaN: + + >>> x = np.array([[1., 2.], [np.nan, 3.], [np.nan, np.nan]]) + >>> x[~np.isnan(x)] + array([ 1., 2., 3.]) + + Or wish to add a constant to all negative elements: + + >>> x = np.array([1., -1., -2., 3]) + >>> x[x < 0] += 20 + >>> x + array([ 1., 19., 18., 3.]) + +In general if an index includes a Boolean array, the result will be +identical to inserting ``obj.nonzero()`` into the same position +and using the integer array indexing mechanism described above. +``x[ind_1, boolean_array, ind_2]`` is equivalent to +``x[(ind_1,) + boolean_array.nonzero() + (ind_2,)]``. + +If there is only one Boolean array and no integer indexing array present, +this is straight forward. Care must only be taken to make sure that the +boolean index has *exactly* as many dimensions as it is supposed to work +with. + +.. admonition:: Example + + From an array, select all rows which sum up to less or equal two: + + >>> x = np.array([[0, 1], [1, 1], [2, 2]]) + >>> rowsum = x.sum(-1) + >>> x[rowsum <= 2, :] + array([[0, 1], + [1, 1]]) + + But if ``rowsum`` would have two dimensions as well: + + >>> rowsum = x.sum(-1, keepdims=True) + >>> rowsum.shape + (3, 1) + >>> x[rowsum <= 2, :] # fails + IndexError: too many indices + >>> x[rowsum <= 2] + array([0, 1]) + + The last one giving only the first elements because of the extra dimension. + Compare ``rowsum.nonzero()`` to understand this example. + +Combining multiple Boolean indexing arrays or a Boolean with an integer +indexing array can best be understood with the +:meth:`obj.nonzero() ` analogy. The function :func:`ix_` +also supports boolean arrays and will work without any surprises. + +.. admonition:: Example + + Use boolean indexing to select all rows adding up to an even + number. At the same time columns 0 and 2 should be selected with an + advanced integer index. Using the :func:`ix_` function this can be done + with: + + >>> x = array([[ 0, 1, 2], + ... [ 3, 4, 5], + ... [ 6, 7, 8], + ... [ 9, 10, 11]]) + >>> rows = (x.sum(-1) % 2) == 0 + >>> rows + array([False, True, False, True]) + >>> columns = [0, 2] + >>> x[np.ix_(rows, columns)] + array([[ 3, 5], + [ 9, 11]]) + + Without the ``np.ix_`` call or only the diagonal elements would be + selected. + + Or without ``np.ix_`` (compare the integer array examples): + + >>> rows = rows.nonzero()[0] + >>> x[rows[:, np.newaxis], columns] + array([[ 3, 5], + [ 9, 11]]) + +Detailed notes +-------------- + +These are some detailed notes, which are not of importance for day to day +indexing (in no particular order): + +* The native NumPy indexing type is ``intp`` and may differ from the + default integer array type. ``intp`` is the smallest data type + sufficient to safely index any array; for advanced indexing it may be + faster than other types. +* For advanced assignments, there is in general no guarantee for the + iteration order. This means that if an element is set more than once, + it is not possible to predict the final result. +* An empty (tuple) index is a full scalar index into a zero dimensional array. + ``x[()]`` returns a *scalar* if ``x`` is zero dimensional and a view + otherwise. On the other hand ``x[...]`` always returns a view. +* If a zero dimensional array is present in the index *and* it is a full + integer index the result will be a *scalar* and not a zero dimensional array. + (Advanced indexing is not triggered.) +* When an ellipsis (``...``) is present but has no size (i.e. replaces zero + ``:``) the result will still always be an array. A view if no advanced index + is present, otherwise a copy. +* the ``nonzero`` equivalence for Boolean arrays does not hold for zero + dimensional boolean arrays. +* When the result of an advanced indexing operation has no elements but an + individual index is out of bounds, whether or not an ``IndexError`` is + raised is undefined (e.g. ``x[[], [123]]`` with ``123`` being out of bounds). +* When a *casting* error occurs during assignment (for example updating a + numerical array using a sequence of strings), the array being assigned + to may end up in an unpredictable partially updated state. + However, if any other error (such as an out of bounds index) occurs, the + array will remain unchanged. +* The memory layout of an advanced indexing result is optimized for each + indexing operation and no particular memory order can be assumed. +* When using a subclass (especially one which manipulates its shape), the + default ``ndarray.__setitem__`` behaviour will call ``__getitem__`` for + *basic* indexing but not for *advanced* indexing. For such a subclass it may + be preferable to call ``ndarray.__setitem__`` with a *base class* ndarray + view on the data. This *must* be done if the subclasses ``__getitem__`` does + not return views. + +.. _arrays.indexing.fields: + + +Field Access +------------- + +.. seealso:: :ref:`arrays.dtypes`, :ref:`arrays.scalars` + +If the :class:`ndarray` object is a structured array the :term:`fields ` +of the array can be accessed by indexing the array with strings, +dictionary-like. + +Indexing ``x['field-name']`` returns a new :term:`view` to the array, +which is of the same shape as *x* (except when the field is a +sub-array) but of data type ``x.dtype['field-name']`` and contains +only the part of the data in the specified field. Also +:ref:`record array ` scalars can be "indexed" this way. + +Indexing into a structured array can also be done with a list of field names, +*e.g.* ``x[['field-name1','field-name2']]``. Currently this returns a new +array containing a copy of the values in the fields specified in the list. +As of NumPy 1.7, returning a copy is being deprecated in favor of returning +a view. A copy will continue to be returned for now, but a FutureWarning +will be issued when writing to the copy. If you depend on the current +behavior, then we suggest copying the returned array explicitly, i.e. use +x[['field-name1','field-name2']].copy(). This will work with both past and +future versions of NumPy. + +If the accessed field is a sub-array, the dimensions of the sub-array +are appended to the shape of the result. + +.. admonition:: Example + + >>> x = np.zeros((2,2), dtype=[('a', np.int32), ('b', np.float64, (3,3))]) + >>> x['a'].shape + (2, 2) + >>> x['a'].dtype + dtype('int32') + >>> x['b'].shape + (2, 2, 3, 3) + >>> x['b'].dtype + dtype('float64') + + +Flat Iterator indexing +---------------------- + +:attr:`x.flat ` returns an iterator that will iterate +over the entire array (in C-contiguous style with the last index +varying the fastest). This iterator object can also be indexed using +basic slicing or advanced indexing as long as the selection object is +not a tuple. This should be clear from the fact that :attr:`x.flat +` is a 1-dimensional view. It can be used for integer +indexing with 1-dimensional C-style-flat indices. The shape of any +returned array is therefore the shape of the integer indexing object. + +.. index:: + single: indexing + single: ndarray diff --git a/doc/source/reference/arrays.interface.rst b/doc/source/reference/arrays.interface.rst new file mode 100644 index 0000000..4a5fe62 --- /dev/null +++ b/doc/source/reference/arrays.interface.rst @@ -0,0 +1,339 @@ +.. index:: + pair: array; interface + pair: array; protocol + +.. _arrays.interface: + +******************* +The Array Interface +******************* + +.. note:: + + This page describes the numpy-specific API for accessing the contents of + a numpy array from other C extensions. :pep:`3118` -- + :c:func:`The Revised Buffer Protocol ` introduces + similar, standardized API to Python 2.6 and 3.0 for any extension + module to use. Cython__'s buffer array support + uses the :pep:`3118` API; see the `Cython numpy + tutorial`__. Cython provides a way to write code that supports the buffer + protocol with Python versions older than 2.6 because it has a + backward-compatible implementation utilizing the array interface + described here. + +__ http://cython.org/ +__ http://wiki.cython.org/tutorials/numpy + +:version: 3 + +The array interface (sometimes called array protocol) was created in +2005 as a means for array-like Python objects to re-use each other's +data buffers intelligently whenever possible. The homogeneous +N-dimensional array interface is a default mechanism for objects to +share N-dimensional array memory and information. The interface +consists of a Python-side and a C-side using two attributes. Objects +wishing to be considered an N-dimensional array in application code +should support at least one of these attributes. Objects wishing to +support an N-dimensional array in application code should look for at +least one of these attributes and use the information provided +appropriately. + +This interface describes homogeneous arrays in the sense that each +item of the array has the same "type". This type can be very simple +or it can be a quite arbitrary and complicated C-like structure. + +There are two ways to use the interface: A Python side and a C-side. +Both are separate attributes. + +Python side +=========== + +This approach to the interface consists of the object having an +:data:`__array_interface__` attribute. + +.. data:: __array_interface__ + + A dictionary of items (3 required and 5 optional). The optional + keys in the dictionary have implied defaults if they are not + provided. + + The keys are: + + **shape** (required) + + Tuple whose elements are the array size in each dimension. Each + entry is an integer (a Python int or long). Note that these + integers could be larger than the platform "int" or "long" + could hold (a Python int is a C long). It is up to the code + using this attribute to handle this appropriately; either by + raising an error when overflow is possible, or by using + :c:data:`Py_LONG_LONG` as the C type for the shapes. + + **typestr** (required) + + A string providing the basic type of the homogenous array The + basic string format consists of 3 parts: a character describing + the byteorder of the data (``<``: little-endian, ``>``: + big-endian, ``|``: not-relevant), a character code giving the + basic type of the array, and an integer providing the number of + bytes the type uses. + + The basic type character codes are: + + ===== ================================================================ + ``t`` Bit field (following integer gives the number of + bits in the bit field). + ``b`` Boolean (integer type where all values are only True or False) + ``i`` Integer + ``u`` Unsigned integer + ``f`` Floating point + ``c`` Complex floating point + ``m`` Timedelta + ``M`` Datetime + ``O`` Object (i.e. the memory contains a pointer to :c:type:`PyObject`) + ``S`` String (fixed-length sequence of char) + ``U`` Unicode (fixed-length sequence of :c:type:`Py_UNICODE`) + ``V`` Other (void \* -- each item is a fixed-size chunk of memory) + ===== ================================================================ + + **descr** (optional) + + A list of tuples providing a more detailed description of the + memory layout for each item in the homogeneous array. Each + tuple in the list has two or three elements. Normally, this + attribute would be used when *typestr* is ``V[0-9]+``, but this is + not a requirement. The only requirement is that the number of + bytes represented in the *typestr* key is the same as the total + number of bytes represented here. The idea is to support + descriptions of C-like structs that make up array + elements. The elements of each tuple in the list are + + 1. A string providing a name associated with this portion of + the datatype. This could also be a tuple of ``('full name', + 'basic_name')`` where basic name would be a valid Python + variable name representing the full name of the field. + + 2. Either a basic-type description string as in *typestr* or + another list (for nested structured types) + + 3. An optional shape tuple providing how many times this part + of the structure should be repeated. No repeats are assumed + if this is not given. Very complicated structures can be + described using this generic interface. Notice, however, + that each element of the array is still of the same + data-type. Some examples of using this interface are given + below. + + **Default**: ``[('', typestr)]`` + + **data** (optional) + + A 2-tuple whose first argument is an integer (a long integer + if necessary) that points to the data-area storing the array + contents. This pointer must point to the first element of + data (in other words any offset is always ignored in this + case). The second entry in the tuple is a read-only flag (true + means the data area is read-only). + + This attribute can also be an object exposing the + :c:func:`buffer interface ` which + will be used to share the data. If this key is not present (or + returns :class:`None`), then memory sharing will be done + through the buffer interface of the object itself. In this + case, the offset key can be used to indicate the start of the + buffer. A reference to the object exposing the array interface + must be stored by the new object if the memory area is to be + secured. + + **Default**: :const:`None` + + **strides** (optional) + + Either :const:`None` to indicate a C-style contiguous array or + a Tuple of strides which provides the number of bytes needed + to jump to the next array element in the corresponding + dimension. Each entry must be an integer (a Python + :const:`int` or :const:`long`). As with shape, the values may + be larger than can be represented by a C "int" or "long"; the + calling code should handle this appropriately, either by + raising an error, or by using :c:type:`Py_LONG_LONG` in C. The + default is :const:`None` which implies a C-style contiguous + memory buffer. In this model, the last dimension of the array + varies the fastest. For example, the default strides tuple + for an object whose array entries are 8 bytes long and whose + shape is (10,20,30) would be (4800, 240, 8) + + **Default**: :const:`None` (C-style contiguous) + + **mask** (optional) + + :const:`None` or an object exposing the array interface. All + elements of the mask array should be interpreted only as true + or not true indicating which elements of this array are valid. + The shape of this object should be `"broadcastable" + ` to the shape of the + original array. + + **Default**: :const:`None` (All array values are valid) + + **offset** (optional) + + An integer offset into the array data region. This can only be + used when data is :const:`None` or returns a :class:`buffer` + object. + + **Default**: 0. + + **version** (required) + + An integer showing the version of the interface (i.e. 3 for + this version). Be careful not to use this to invalidate + objects exposing future versions of the interface. + + +C-struct access +=============== + +This approach to the array interface allows for faster access to an +array using only one attribute lookup and a well-defined C-structure. + +.. c:var:: __array_struct__ + + A :c:type: `PyCObject` whose :c:data:`voidptr` member contains a + pointer to a filled :c:type:`PyArrayInterface` structure. Memory + for the structure is dynamically created and the :c:type:`PyCObject` + is also created with an appropriate destructor so the retriever of + this attribute simply has to apply :c:func:`Py_DECREF()` to the + object returned by this attribute when it is finished. Also, + either the data needs to be copied out, or a reference to the + object exposing this attribute must be held to ensure the data is + not freed. Objects exposing the :obj:`__array_struct__` interface + must also not reallocate their memory if other objects are + referencing them. + +The PyArrayInterface structure is defined in ``numpy/ndarrayobject.h`` +as:: + + typedef struct { + int two; /* contains the integer 2 -- simple sanity check */ + int nd; /* number of dimensions */ + char typekind; /* kind in array --- character code of typestr */ + int itemsize; /* size of each element */ + int flags; /* flags indicating how the data should be interpreted */ + /* must set ARR_HAS_DESCR bit to validate descr */ + Py_intptr_t *shape; /* A length-nd array of shape information */ + Py_intptr_t *strides; /* A length-nd array of stride information */ + void *data; /* A pointer to the first element of the array */ + PyObject *descr; /* NULL or data-description (same as descr key + of __array_interface__) -- must set ARR_HAS_DESCR + flag or this will be ignored. */ + } PyArrayInterface; + +The flags member may consist of 5 bits showing how the data should be +interpreted and one bit showing how the Interface should be +interpreted. The data-bits are :const:`CONTIGUOUS` (0x1), +:const:`FORTRAN` (0x2), :const:`ALIGNED` (0x100), :const:`NOTSWAPPED` +(0x200), and :const:`WRITEABLE` (0x400). A final flag +:const:`ARR_HAS_DESCR` (0x800) indicates whether or not this structure +has the arrdescr field. The field should not be accessed unless this +flag is present. + +.. admonition:: New since June 16, 2006: + + In the past most implementations used the "desc" member of the + :c:type:`PyCObject` itself (do not confuse this with the "descr" member of + the :c:type:`PyArrayInterface` structure above --- they are two separate + things) to hold the pointer to the object exposing the interface. + This is now an explicit part of the interface. Be sure to own a + reference to the object when the :c:type:`PyCObject` is created using + :c:type:`PyCObject_FromVoidPtrAndDesc`. + + +Type description examples +========================= + +For clarity it is useful to provide some examples of the type +description and corresponding :data:`__array_interface__` 'descr' +entries. Thanks to Scott Gilbert for these examples: + +In every case, the 'descr' key is optional, but of course provides +more information which may be important for various applications:: + + * Float data + typestr == '>f4' + descr == [('','>f4')] + + * Complex double + typestr == '>c8' + descr == [('real','>f4'), ('imag','>f4')] + + * RGB Pixel data + typestr == '|V3' + descr == [('r','|u1'), ('g','|u1'), ('b','|u1')] + + * Mixed endian (weird but could happen). + typestr == '|V8' (or '>u8') + descr == [('big','>i4'), ('little','i4'), ('data','>f8',(16,4))] + + * Padded structure + struct { + int ival; + double dval; + } + typestr == '|V16' + descr == [('ival','>i4'),('','|V4'),('dval','>f8')] + +It should be clear that any structured type could be described using this +interface. + +Differences with Array interface (Version 2) +============================================ + +The version 2 interface was very similar. The differences were +largely aesthetic. In particular: + +1. The PyArrayInterface structure had no descr member at the end + (and therefore no flag ARR_HAS_DESCR) + +2. The desc member of the PyCObject returned from __array_struct__ was + not specified. Usually, it was the object exposing the array (so + that a reference to it could be kept and destroyed when the + C-object was destroyed). Now it must be a tuple whose first + element is a string with "PyArrayInterface Version #" and whose + second element is the object exposing the array. + +3. The tuple returned from __array_interface__['data'] used to be a + hex-string (now it is an integer or a long integer). + +4. There was no __array_interface__ attribute instead all of the keys + (except for version) in the __array_interface__ dictionary were + their own attribute: Thus to obtain the Python-side information you + had to access separately the attributes: + + * __array_data__ + * __array_shape__ + * __array_strides__ + * __array_typestr__ + * __array_descr__ + * __array_offset__ + * __array_mask__ diff --git a/doc/source/reference/arrays.ndarray.rst b/doc/source/reference/arrays.ndarray.rst new file mode 100644 index 0000000..4c8bbf6 --- /dev/null +++ b/doc/source/reference/arrays.ndarray.rst @@ -0,0 +1,620 @@ +.. _arrays.ndarray: + +****************************************** +The N-dimensional array (:class:`ndarray`) +****************************************** + +.. currentmodule:: numpy + +An :class:`ndarray` is a (usually fixed-size) multidimensional +container of items of the same type and size. The number of dimensions +and items in an array is defined by its :attr:`shape `, +which is a :class:`tuple` of *N* positive integers that specify the +sizes of each dimension. The type of items in the array is specified by +a separate :ref:`data-type object (dtype) `, one of which +is associated with each ndarray. + +As with other container objects in Python, the contents of an +:class:`ndarray` can be accessed and modified by :ref:`indexing or +slicing ` the array (using, for example, *N* integers), +and via the methods and attributes of the :class:`ndarray`. + +.. index:: view, base + +Different :class:`ndarrays ` can share the same data, so that +changes made in one :class:`ndarray` may be visible in another. That +is, an ndarray can be a *"view"* to another ndarray, and the data it +is referring to is taken care of by the *"base"* ndarray. ndarrays can +also be views to memory owned by Python :class:`strings ` or +objects implementing the :class:`buffer` or :ref:`array +` interfaces. + + +.. admonition:: Example + + A 2-dimensional array of size 2 x 3, composed of 4-byte integer + elements: + + >>> x = np.array([[1, 2, 3], [4, 5, 6]], np.int32) + >>> type(x) + + >>> x.shape + (2, 3) + >>> x.dtype + dtype('int32') + + The array can be indexed using Python container-like syntax: + + >>> # The element of x in the *second* row, *third* column, namely, 6. + >>> x[1, 2] + + For example :ref:`slicing ` can produce views of + the array: + + >>> y = x[:,1] + >>> y + array([2, 5]) + >>> y[0] = 9 # this also changes the corresponding element in x + >>> y + array([9, 5]) + >>> x + array([[1, 9, 3], + [4, 5, 6]]) + + +Constructing arrays +=================== + +New arrays can be constructed using the routines detailed in +:ref:`routines.array-creation`, and also by using the low-level +:class:`ndarray` constructor: + +.. autosummary:: + :toctree: generated/ + + ndarray + +.. _arrays.ndarray.indexing: + + +Indexing arrays +=============== + +Arrays can be indexed using an extended Python slicing syntax, +``array[selection]``. Similar syntax is also used for accessing +fields in a :ref:`structured array `. + +.. seealso:: :ref:`Array Indexing `. + +Internal memory layout of an ndarray +==================================== + +An instance of class :class:`ndarray` consists of a contiguous +one-dimensional segment of computer memory (owned by the array, or by +some other object), combined with an indexing scheme that maps *N* +integers into the location of an item in the block. The ranges in +which the indices can vary is specified by the :obj:`shape +` of the array. How many bytes each item takes and how +the bytes are interpreted is defined by the :ref:`data-type object +` associated with the array. + +.. index:: C-order, Fortran-order, row-major, column-major, stride, + offset + +A segment of memory is inherently 1-dimensional, and there are many +different schemes for arranging the items of an *N*-dimensional array +in a 1-dimensional block. NumPy is flexible, and :class:`ndarray` +objects can accommodate any *strided indexing scheme*. In a strided +scheme, the N-dimensional index :math:`(n_0, n_1, ..., n_{N-1})` +corresponds to the offset (in bytes): + +.. math:: n_{\mathrm{offset}} = \sum_{k=0}^{N-1} s_k n_k + +from the beginning of the memory block associated with the +array. Here, :math:`s_k` are integers which specify the :obj:`strides +` of the array. The :term:`column-major` order (used, +for example, in the Fortran language and in *Matlab*) and +:term:`row-major` order (used in C) schemes are just specific kinds of +strided scheme, and correspond to memory that can be *addressed* by the strides: + +.. math:: + + s_k^{\mathrm{column}} = \mathrm{itemsize} \prod_{j=0}^{k-1} d_j , + \quad s_k^{\mathrm{row}} = \mathrm{itemsize} \prod_{j=k+1}^{N-1} d_j . + +.. index:: single-segment, contiguous, non-contiguous + +where :math:`d_j` `= self.shape[j]`. + +Both the C and Fortran orders are :term:`contiguous`, *i.e.,* +:term:`single-segment`, memory layouts, in which every part of the +memory block can be accessed by some combination of the indices. + +While a C-style and Fortran-style contiguous array, which has the corresponding +flags set, can be addressed with the above strides, the actual strides may be +different. This can happen in two cases: + + 1. If ``self.shape[k] == 1`` then for any legal index ``index[k] == 0``. + This means that in the formula for the offset :math:`n_k = 0` and thus + :math:`s_k n_k = 0` and the value of :math:`s_k` `= self.strides[k]` is + arbitrary. + 2. If an array has no elements (``self.size == 0``) there is no legal + index and the strides are never used. Any array with no elements may be + considered C-style and Fortran-style contiguous. + +Point 1. means that ``self`` and ``self.squeeze()`` always have the same +contiguity and :term:`aligned` flags value. This also means that even a high +dimensional array could be C-style and Fortran-style contiguous at the same +time. + +.. index:: aligned + +An array is considered aligned if the memory offsets for all elements and the +base offset itself is a multiple of `self.itemsize`. + +.. note:: + + Points (1) and (2) are not yet applied by default. Beginning with + NumPy 1.8.0, they are applied consistently only if the environment + variable ``NPY_RELAXED_STRIDES_CHECKING=1`` was defined when NumPy + was built. Eventually this will become the default. + + You can check whether this option was enabled when your NumPy was + built by looking at the value of ``np.ones((10,1), + order='C').flags.f_contiguous``. If this is ``True``, then your + NumPy has relaxed strides checking enabled. + +.. warning:: + + It does *not* generally hold that ``self.strides[-1] == self.itemsize`` + for C-style contiguous arrays or ``self.strides[0] == self.itemsize`` for + Fortran-style contiguous arrays is true. + +Data in new :class:`ndarrays ` is in the :term:`row-major` +(C) order, unless otherwise specified, but, for example, :ref:`basic +array slicing ` often produces :term:`views ` +in a different scheme. + +.. seealso: :ref:`Indexing `_ + +.. note:: + + Several algorithms in NumPy work on arbitrarily strided arrays. + However, some algorithms require single-segment arrays. When an + irregularly strided array is passed in to such algorithms, a copy + is automatically made. + +.. _arrays.ndarray.attributes: + +Array attributes +================ + +Array attributes reflect information that is intrinsic to the array +itself. Generally, accessing an array through its attributes allows +you to get and sometimes set intrinsic properties of the array without +creating a new array. The exposed attributes are the core parts of an +array and only some of them can be reset meaningfully without creating +a new array. Information on each attribute is given below. + +Memory layout +------------- + +The following attributes contain information about the memory layout +of the array: + +.. autosummary:: + :toctree: generated/ + + ndarray.flags + ndarray.shape + ndarray.strides + ndarray.ndim + ndarray.data + ndarray.size + ndarray.itemsize + ndarray.nbytes + ndarray.base + +Data type +--------- + +.. seealso:: :ref:`Data type objects ` + +The data type object associated with the array can be found in the +:attr:`dtype ` attribute: + +.. autosummary:: + :toctree: generated/ + + ndarray.dtype + +Other attributes +---------------- + +.. autosummary:: + :toctree: generated/ + + ndarray.T + ndarray.real + ndarray.imag + ndarray.flat + ndarray.ctypes + + +.. _arrays.ndarray.array-interface: + +Array interface +--------------- + +.. seealso:: :ref:`arrays.interface`. + +========================== =================================== +:obj:`__array_interface__` Python-side of the array interface +:obj:`__array_struct__` C-side of the array interface +========================== =================================== + +:mod:`ctypes` foreign function interface +---------------------------------------- + +.. autosummary:: + :toctree: generated/ + + ndarray.ctypes + +.. _array.ndarray.methods: + +Array methods +============= + +An :class:`ndarray` object has many methods which operate on or with +the array in some fashion, typically returning an array result. These +methods are briefly explained below. (Each method's docstring has a +more complete description.) + +For the following methods there are also corresponding functions in +:mod:`numpy`: :func:`all`, :func:`any`, :func:`argmax`, +:func:`argmin`, :func:`argpartition`, :func:`argsort`, :func:`choose`, +:func:`clip`, :func:`compress`, :func:`copy`, :func:`cumprod`, +:func:`cumsum`, :func:`diagonal`, :func:`imag`, :func:`max `, +:func:`mean`, :func:`min `, :func:`nonzero`, :func:`partition`, +:func:`prod`, :func:`ptp`, :func:`put`, :func:`ravel`, :func:`real`, +:func:`repeat`, :func:`reshape`, :func:`round `, +:func:`searchsorted`, :func:`sort`, :func:`squeeze`, :func:`std`, +:func:`sum`, :func:`swapaxes`, :func:`take`, :func:`trace`, +:func:`transpose`, :func:`var`. + +Array conversion +---------------- + +.. autosummary:: + :toctree: generated/ + + ndarray.item + ndarray.tolist + ndarray.itemset + ndarray.tostring + ndarray.tobytes + ndarray.tofile + ndarray.dump + ndarray.dumps + ndarray.astype + ndarray.byteswap + ndarray.copy + ndarray.view + ndarray.getfield + ndarray.setflags + ndarray.fill + +Shape manipulation +------------------ + +For reshape, resize, and transpose, the single tuple argument may be +replaced with ``n`` integers which will be interpreted as an n-tuple. + +.. autosummary:: + :toctree: generated/ + + ndarray.reshape + ndarray.resize + ndarray.transpose + ndarray.swapaxes + ndarray.flatten + ndarray.ravel + ndarray.squeeze + +Item selection and manipulation +------------------------------- + +For array methods that take an *axis* keyword, it defaults to +:const:`None`. If axis is *None*, then the array is treated as a 1-D +array. Any other value for *axis* represents the dimension along which +the operation should proceed. + +.. autosummary:: + :toctree: generated/ + + ndarray.take + ndarray.put + ndarray.repeat + ndarray.choose + ndarray.sort + ndarray.argsort + ndarray.partition + ndarray.argpartition + ndarray.searchsorted + ndarray.nonzero + ndarray.compress + ndarray.diagonal + +Calculation +----------- + +.. index:: axis + +Many of these methods take an argument named *axis*. In such cases, + +- If *axis* is *None* (the default), the array is treated as a 1-D + array and the operation is performed over the entire array. This + behavior is also the default if self is a 0-dimensional array or + array scalar. (An array scalar is an instance of the types/classes + float32, float64, etc., whereas a 0-dimensional array is an ndarray + instance containing precisely one array scalar.) + +- If *axis* is an integer, then the operation is done over the given + axis (for each 1-D subarray that can be created along the given axis). + +.. admonition:: Example of the *axis* argument + + A 3-dimensional array of size 3 x 3 x 3, summed over each of its + three axes + + >>> x + array([[[ 0, 1, 2], + [ 3, 4, 5], + [ 6, 7, 8]], + [[ 9, 10, 11], + [12, 13, 14], + [15, 16, 17]], + [[18, 19, 20], + [21, 22, 23], + [24, 25, 26]]]) + >>> x.sum(axis=0) + array([[27, 30, 33], + [36, 39, 42], + [45, 48, 51]]) + >>> # for sum, axis is the first keyword, so we may omit it, + >>> # specifying only its value + >>> x.sum(0), x.sum(1), x.sum(2) + (array([[27, 30, 33], + [36, 39, 42], + [45, 48, 51]]), + array([[ 9, 12, 15], + [36, 39, 42], + [63, 66, 69]]), + array([[ 3, 12, 21], + [30, 39, 48], + [57, 66, 75]])) + +The parameter *dtype* specifies the data type over which a reduction +operation (like summing) should take place. The default reduce data +type is the same as the data type of *self*. To avoid overflow, it can +be useful to perform the reduction using a larger data type. + +For several methods, an optional *out* argument can also be provided +and the result will be placed into the output array given. The *out* +argument must be an :class:`ndarray` and have the same number of +elements. It can have a different data type in which case casting will +be performed. + +.. autosummary:: + :toctree: generated/ + + ndarray.argmax + ndarray.min + ndarray.argmin + ndarray.ptp + ndarray.clip + ndarray.conj + ndarray.round + ndarray.trace + ndarray.sum + ndarray.cumsum + ndarray.mean + ndarray.var + ndarray.std + ndarray.prod + ndarray.cumprod + ndarray.all + ndarray.any + +Arithmetic, matrix multiplication, and comparison operations +============================================================ + +.. index:: comparison, arithmetic, matrix, operation, operator + +Arithmetic and comparison operations on :class:`ndarrays ` +are defined as element-wise operations, and generally yield +:class:`ndarray` objects as results. + +Each of the arithmetic operations (``+``, ``-``, ``*``, ``/``, ``//``, +``%``, ``divmod()``, ``**`` or ``pow()``, ``<<``, ``>>``, ``&``, +``^``, ``|``, ``~``) and the comparisons (``==``, ``<``, ``>``, +``<=``, ``>=``, ``!=``) is equivalent to the corresponding +:term:`universal function` (or :term:`ufunc` for short) in NumPy. For +more information, see the section on :ref:`Universal Functions +`. + +Comparison operators: + +.. autosummary:: + :toctree: generated/ + + ndarray.__lt__ + ndarray.__le__ + ndarray.__gt__ + ndarray.__ge__ + ndarray.__eq__ + ndarray.__ne__ + +Truth value of an array (:func:`bool()`): + +.. autosummary:: + :toctree: generated/ + + ndarray.__nonzero__ + +.. note:: + + Truth-value testing of an array invokes + :meth:`ndarray.__nonzero__`, which raises an error if the number of + elements in the array is larger than 1, because the truth value + of such arrays is ambiguous. Use :meth:`.any() ` and + :meth:`.all() ` instead to be clear about what is meant + in such cases. (If the number of elements is 0, the array evaluates + to ``False``.) + + +Unary operations: + +.. autosummary:: + :toctree: generated/ + + ndarray.__neg__ + ndarray.__pos__ + ndarray.__abs__ + ndarray.__invert__ + +Arithmetic: + +.. autosummary:: + :toctree: generated/ + + ndarray.__add__ + ndarray.__sub__ + ndarray.__mul__ + ndarray.__div__ + ndarray.__truediv__ + ndarray.__floordiv__ + ndarray.__mod__ + ndarray.__divmod__ + ndarray.__pow__ + ndarray.__lshift__ + ndarray.__rshift__ + ndarray.__and__ + ndarray.__or__ + ndarray.__xor__ + +.. note:: + + - Any third argument to :func:`pow()` is silently ignored, + as the underlying :func:`ufunc ` takes only two arguments. + + - The three division operators are all defined; :obj:`div` is active + by default, :obj:`truediv` is active when + :obj:`__future__` division is in effect. + + - Because :class:`ndarray` is a built-in type (written in C), the + ``__r{op}__`` special methods are not directly defined. + + - The functions called to implement many arithmetic special methods + for arrays can be modified using :func:`set_numeric_ops`. + +Arithmetic, in-place: + +.. autosummary:: + :toctree: generated/ + + ndarray.__iadd__ + ndarray.__isub__ + ndarray.__imul__ + ndarray.__idiv__ + ndarray.__itruediv__ + ndarray.__ifloordiv__ + ndarray.__imod__ + ndarray.__ipow__ + ndarray.__ilshift__ + ndarray.__irshift__ + ndarray.__iand__ + ndarray.__ior__ + ndarray.__ixor__ + +.. warning:: + + In place operations will perform the calculation using the + precision decided by the data type of the two operands, but will + silently downcast the result (if necessary) so it can fit back into + the array. Therefore, for mixed precision calculations, ``A {op}= + B`` can be different than ``A = A {op} B``. For example, suppose + ``a = ones((3,3))``. Then, ``a += 3j`` is different than ``a = a + + 3j``: while they both perform the same computation, ``a += 3`` + casts the result to fit back in ``a``, whereas ``a = a + 3j`` + re-binds the name ``a`` to the result. + +Matrix Multiplication: + +.. autosummary:: + :toctree: generated/ + + ndarray.__matmul__ + +.. note:: + + Matrix operators ``@`` and ``@=`` were introduced in Python 3.5 + following PEP465. NumPy 1.10.0 has a preliminary implementation of ``@`` + for testing purposes. Further documentation can be found in the + :func:`matmul` documentation. + + +Special methods +=============== + +For standard library functions: + +.. autosummary:: + :toctree: generated/ + + ndarray.__copy__ + ndarray.__deepcopy__ + ndarray.__reduce__ + ndarray.__setstate__ + +Basic customization: + +.. autosummary:: + :toctree: generated/ + + ndarray.__new__ + ndarray.__array__ + ndarray.__array_wrap__ + +Container customization: (see :ref:`Indexing `) + +.. autosummary:: + :toctree: generated/ + + ndarray.__len__ + ndarray.__getitem__ + ndarray.__setitem__ + ndarray.__contains__ + +Conversion; the operations :func:`complex()`, :func:`int()`, +:func:`long()`, :func:`float()`, :func:`oct()`, and +:func:`hex()`. They work only on arrays that have one element in them +and return the appropriate scalar. + +.. autosummary:: + :toctree: generated/ + + ndarray.__int__ + ndarray.__long__ + ndarray.__float__ + ndarray.__oct__ + ndarray.__hex__ + +String representations: + +.. autosummary:: + :toctree: generated/ + + ndarray.__str__ + ndarray.__repr__ diff --git a/doc/source/reference/arrays.nditer.rst b/doc/source/reference/arrays.nditer.rst new file mode 100644 index 0000000..76f5991 --- /dev/null +++ b/doc/source/reference/arrays.nditer.rst @@ -0,0 +1,714 @@ +.. currentmodule:: numpy + +.. _arrays.nditer: + +********************* +Iterating Over Arrays +********************* + +The iterator object :class:`nditer`, introduced in NumPy 1.6, provides +many flexible ways to visit all the elements of one or more arrays in +a systematic fashion. This page introduces some basic ways to use the +object for computations on arrays in Python, then concludes with how one +can accelerate the inner loop in Cython. Since the Python exposure of +:class:`nditer` is a relatively straightforward mapping of the C array +iterator API, these ideas will also provide help working with array +iteration from C or C++. + +Single Array Iteration +====================== + +The most basic task that can be done with the :class:`nditer` is to +visit every element of an array. Each element is provided one by one +using the standard Python iterator interface. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) + >>> for x in np.nditer(a): + ... print x, + ... + 0 1 2 3 4 5 + +An important thing to be aware of for this iteration is that the order +is chosen to match the memory layout of the array instead of using a +standard C or Fortran ordering. This is done for access efficiency, +reflecting the idea that by default one simply wants to visit each element +without concern for a particular ordering. We can see this by iterating +over the transpose of our previous array, compared to taking a copy +of that transpose in C order. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) + >>> for x in np.nditer(a.T): + ... print x, + ... + 0 1 2 3 4 5 + + >>> for x in np.nditer(a.T.copy(order='C')): + ... print x, + ... + 0 3 1 4 2 5 + +The elements of both `a` and `a.T` get traversed in the same order, +namely the order they are stored in memory, whereas the elements of +`a.T.copy(order='C')` get visited in a different order because they +have been put into a different memory layout. + +Controlling Iteration Order +--------------------------- + +There are times when it is important to visit the elements of an array +in a specific order, irrespective of the layout of the elements in memory. +The :class:`nditer` object provides an `order` parameter to control this +aspect of iteration. The default, having the behavior described above, +is order='K' to keep the existing order. This can be overridden with +order='C' for C order and order='F' for Fortran order. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) + >>> for x in np.nditer(a, order='F'): + ... print x, + ... + 0 3 1 4 2 5 + >>> for x in np.nditer(a.T, order='C'): + ... print x, + ... + 0 3 1 4 2 5 + +Modifying Array Values +---------------------- + +By default, the :class:`nditer` treats the input array as a read-only +object. To modify the array elements, you must specify either read-write +or write-only mode. This is controlled with per-operand flags. + +Regular assignment in Python simply changes a reference in the local or +global variable dictionary instead of modifying an existing variable in +place. This means that simply assigning to `x` will not place the value +into the element of the array, but rather switch `x` from being an array +element reference to being a reference to the value you assigned. To +actually modify the element of the array, `x` should be indexed with +the ellipsis. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) + >>> a + array([[0, 1, 2], + [3, 4, 5]]) + >>> for x in np.nditer(a, op_flags=['readwrite']): + ... x[...] = 2 * x + ... + >>> a + array([[ 0, 2, 4], + [ 6, 8, 10]]) + +Using an External Loop +---------------------- + +In all the examples so far, the elements of `a` are provided by the +iterator one at a time, because all the looping logic is internal to the +iterator. While this is simple and convenient, it is not very efficient. A +better approach is to move the one-dimensional innermost loop into your +code, external to the iterator. This way, NumPy's vectorized operations +can be used on larger chunks of the elements being visited. + +The :class:`nditer` will try to provide chunks that are +as large as possible to the inner loop. By forcing 'C' and 'F' order, +we get different external loop sizes. This mode is enabled by specifying +an iterator flag. + +Observe that with the default of keeping native memory order, the +iterator is able to provide a single one-dimensional chunk, whereas +when forcing Fortran order, it has to provide three chunks of two +elements each. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) + >>> for x in np.nditer(a, flags=['external_loop']): + ... print x, + ... + [0 1 2 3 4 5] + + >>> for x in np.nditer(a, flags=['external_loop'], order='F'): + ... print x, + ... + [0 3] [1 4] [2 5] + +Tracking an Index or Multi-Index +-------------------------------- + +During iteration, you may want to use the index of the current +element in a computation. For example, you may want to visit the +elements of an array in memory order, but use a C-order, Fortran-order, +or multidimensional index to look up values in a different array. + +The Python iterator protocol doesn't have a natural way to query these +additional values from the iterator, so we introduce an alternate syntax +for iterating with an :class:`nditer`. This syntax explicitly works +with the iterator object itself, so its properties are readily accessible +during iteration. With this looping construct, the current value is +accessible by indexing into the iterator, and the index being tracked +is the property `index` or `multi_index` depending on what was requested. + +The Python interactive interpreter unfortunately prints out the +values of expressions inside the while loop during each iteration of the +loop. We have modified the output in the examples using this looping +construct in order to be more readable. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) + >>> it = np.nditer(a, flags=['f_index']) + >>> while not it.finished: + ... print "%d <%d>" % (it[0], it.index), + ... it.iternext() + ... + 0 <0> 1 <2> 2 <4> 3 <1> 4 <3> 5 <5> + + >>> it = np.nditer(a, flags=['multi_index']) + >>> while not it.finished: + ... print "%d <%s>" % (it[0], it.multi_index), + ... it.iternext() + ... + 0 <(0, 0)> 1 <(0, 1)> 2 <(0, 2)> 3 <(1, 0)> 4 <(1, 1)> 5 <(1, 2)> + + >>> it = np.nditer(a, flags=['multi_index'], op_flags=['writeonly']) + >>> while not it.finished: + ... it[0] = it.multi_index[1] - it.multi_index[0] + ... it.iternext() + ... + >>> a + array([[ 0, 1, 2], + [-1, 0, 1]]) + +Tracking an index or multi-index is incompatible with using an external +loop, because it requires a different index value per element. If +you try to combine these flags, the :class:`nditer` object will +raise an exception + +.. admonition:: Example + + >>> a = np.zeros((2,3)) + >>> it = np.nditer(a, flags=['c_index', 'external_loop']) + Traceback (most recent call last): + File "", line 1, in + ValueError: Iterator flag EXTERNAL_LOOP cannot be used if an index or multi-index is being tracked + +Buffering the Array Elements +---------------------------- + +When forcing an iteration order, we observed that the external loop +option may provide the elements in smaller chunks because the elements +can't be visited in the appropriate order with a constant stride. +When writing C code, this is generally fine, however in pure Python code +this can cause a significant reduction in performance. + +By enabling buffering mode, the chunks provided by the iterator to +the inner loop can be made larger, significantly reducing the overhead +of the Python interpreter. In the example forcing Fortran iteration order, +the inner loop gets to see all the elements in one go when buffering +is enabled. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) + >>> for x in np.nditer(a, flags=['external_loop'], order='F'): + ... print x, + ... + [0 3] [1 4] [2 5] + + >>> for x in np.nditer(a, flags=['external_loop','buffered'], order='F'): + ... print x, + ... + [0 3 1 4 2 5] + +Iterating as a Specific Data Type +--------------------------------- + +There are times when it is necessary to treat an array as a different +data type than it is stored as. For instance, one may want to do all +computations on 64-bit floats, even if the arrays being manipulated +are 32-bit floats. Except when writing low-level C code, it's generally +better to let the iterator handle the copying or buffering instead +of casting the data type yourself in the inner loop. + +There are two mechanisms which allow this to be done, temporary copies +and buffering mode. With temporary copies, a copy of the entire array is +made with the new data type, then iteration is done in the copy. Write +access is permitted through a mode which updates the original array after +all the iteration is complete. The major drawback of temporary copies is +that the temporary copy may consume a large amount of memory, particularly +if the iteration data type has a larger itemsize than the original one. + +Buffering mode mitigates the memory usage issue and is more cache-friendly +than making temporary copies. Except for special cases, where the whole +array is needed at once outside the iterator, buffering is recommended +over temporary copying. Within NumPy, buffering is used by the ufuncs and +other functions to support flexible inputs with minimal memory overhead. + +In our examples, we will treat the input array with a complex data type, +so that we can take square roots of negative numbers. Without enabling +copies or buffering mode, the iterator will raise an exception if the +data type doesn't match precisely. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) - 3 + >>> for x in np.nditer(a, op_dtypes=['complex128']): + ... print np.sqrt(x), + ... + Traceback (most recent call last): + File "", line 1, in + TypeError: Iterator operand required copying or buffering, but neither copying nor buffering was enabled + +In copying mode, 'copy' is specified as a per-operand flag. This is +done to provide control in a per-operand fashion. Buffering mode is +specified as an iterator flag. + +.. admonition:: Example + + >>> a = np.arange(6).reshape(2,3) - 3 + >>> for x in np.nditer(a, op_flags=['readonly','copy'], + ... op_dtypes=['complex128']): + ... print np.sqrt(x), + ... + 1.73205080757j 1.41421356237j 1j 0j (1+0j) (1.41421356237+0j) + + >>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['complex128']): + ... print np.sqrt(x), + ... + 1.73205080757j 1.41421356237j 1j 0j (1+0j) (1.41421356237+0j) + +The iterator uses NumPy's casting rules to determine whether a specific +conversion is permitted. By default, it enforces 'safe' casting. This means, +for example, that it will raise an exception if you try to treat a +64-bit float array as a 32-bit float array. In many cases, the rule +'same_kind' is the most reasonable rule to use, since it will allow +conversion from 64 to 32-bit float, but not from float to int or from +complex to float. + +.. admonition:: Example + + >>> a = np.arange(6.) + >>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['float32']): + ... print x, + ... + Traceback (most recent call last): + File "", line 1, in + TypeError: Iterator operand 0 dtype could not be cast from dtype('float64') to dtype('float32') according to the rule 'safe' + + >>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['float32'], + ... casting='same_kind'): + ... print x, + ... + 0.0 1.0 2.0 3.0 4.0 5.0 + + >>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['int32'], casting='same_kind'): + ... print x, + ... + Traceback (most recent call last): + File "", line 1, in + TypeError: Iterator operand 0 dtype could not be cast from dtype('float64') to dtype('int32') according to the rule 'same_kind' + +One thing to watch out for is conversions back to the original data +type when using a read-write or write-only operand. A common case is +to implement the inner loop in terms of 64-bit floats, and use 'same_kind' +casting to allow the other floating-point types to be processed as well. +While in read-only mode, an integer array could be provided, read-write +mode will raise an exception because conversion back to the array +would violate the casting rule. + +.. admonition:: Example + + >>> a = np.arange(6) + >>> for x in np.nditer(a, flags=['buffered'], op_flags=['readwrite'], + ... op_dtypes=['float64'], casting='same_kind'): + ... x[...] = x / 2.0 + ... + Traceback (most recent call last): + File "", line 2, in + TypeError: Iterator requested dtype could not be cast from dtype('float64') to dtype('int64'), the operand 0 dtype, according to the rule 'same_kind' + +Broadcasting Array Iteration +============================ + +NumPy has a set of rules for dealing with arrays that have differing +shapes which are applied whenever functions take multiple operands +which combine element-wise. This is called +:ref:`broadcasting `. The :class:`nditer` +object can apply these rules for you when you need to write such a function. + +As an example, we print out the result of broadcasting a one and +a two dimensional array together. + +.. admonition:: Example + + >>> a = np.arange(3) + >>> b = np.arange(6).reshape(2,3) + >>> for x, y in np.nditer([a,b]): + ... print "%d:%d" % (x,y), + ... + 0:0 1:1 2:2 0:3 1:4 2:5 + +When a broadcasting error occurs, the iterator raises an exception +which includes the input shapes to help diagnose the problem. + +.. admonition:: Example + + >>> a = np.arange(2) + >>> b = np.arange(6).reshape(2,3) + >>> for x, y in np.nditer([a,b]): + ... print "%d:%d" % (x,y), + ... + Traceback (most recent call last): + File "", line 1, in + ValueError: operands could not be broadcast together with shapes (2) (2,3) + +Iterator-Allocated Output Arrays +-------------------------------- + +A common case in NumPy functions is to have outputs allocated based +on the broadcasting of the input, and additionally have an optional +parameter called 'out' where the result will be placed when it is +provided. The :class:`nditer` object provides a convenient idiom that +makes it very easy to support this mechanism. + +We'll show how this works by creating a function `square` which squares +its input. Let's start with a minimal function definition excluding 'out' +parameter support. + +.. admonition:: Example + + >>> def square(a): + ... it = np.nditer([a, None]) + ... for x, y in it: + ... y[...] = x*x + ... return it.operands[1] + ... + >>> square([1,2,3]) + array([1, 4, 9]) + +By default, the :class:`nditer` uses the flags 'allocate' and 'writeonly' +for operands that are passed in as None. This means we were able to provide +just the two operands to the iterator, and it handled the rest. + +When adding the 'out' parameter, we have to explicitly provide those flags, +because if someone passes in an array as 'out', the iterator will default +to 'readonly', and our inner loop would fail. The reason 'readonly' is +the default for input arrays is to prevent confusion about unintentionally +triggering a reduction operation. If the default were 'readwrite', any +broadcasting operation would also trigger a reduction, a topic +which is covered later in this document. + +While we're at it, let's also introduce the 'no_broadcast' flag, which +will prevent the output from being broadcast. This is important, because +we only want one input value for each output. Aggregating more than one +input value is a reduction operation which requires special handling. +It would already raise an error because reductions must be explicitly +enabled in an iterator flag, but the error message that results from +disabling broadcasting is much more understandable for end-users. +To see how to generalize the square function to a reduction, look +at the sum of squares function in the section about Cython. + +For completeness, we'll also add the 'external_loop' and 'buffered' +flags, as these are what you will typically want for performance +reasons. + +.. admonition:: Example + + >>> def square(a, out=None): + ... it = np.nditer([a, out], + ... flags = ['external_loop', 'buffered'], + ... op_flags = [['readonly'], + ... ['writeonly', 'allocate', 'no_broadcast']]) + ... for x, y in it: + ... y[...] = x*x + ... return it.operands[1] + ... + + >>> square([1,2,3]) + array([1, 4, 9]) + + >>> b = np.zeros((3,)) + >>> square([1,2,3], out=b) + array([ 1., 4., 9.]) + >>> b + array([ 1., 4., 9.]) + + >>> square(np.arange(6).reshape(2,3), out=b) + Traceback (most recent call last): + File "", line 1, in + File "", line 4, in square + ValueError: non-broadcastable output operand with shape (3) doesn't match the broadcast shape (2,3) + +Outer Product Iteration +----------------------- + +Any binary operation can be extended to an array operation in an outer +product fashion like in :func:`outer`, and the :class:`nditer` object +provides a way to accomplish this by explicitly mapping the axes of +the operands. It is also possible to do this with :const:`newaxis` +indexing, but we will show you how to directly use the nditer `op_axes` +parameter to accomplish this with no intermediate views. + +We'll do a simple outer product, placing the dimensions of the first +operand before the dimensions of the second operand. The `op_axes` +parameter needs one list of axes for each operand, and provides a mapping +from the iterator's axes to the axes of the operand. + +Suppose the first operand is one dimensional and the second operand is +two dimensional. The iterator will have three dimensions, so `op_axes` +will have two 3-element lists. The first list picks out the one +axis of the first operand, and is -1 for the rest of the iterator axes, +with a final result of [0, -1, -1]. The second list picks out the two +axes of the second operand, but shouldn't overlap with the axes picked +out in the first operand. Its list is [-1, 0, 1]. The output operand +maps onto the iterator axes in the standard manner, so we can provide +None instead of constructing another list. + +The operation in the inner loop is a straightforward multiplication. +Everything to do with the outer product is handled by the iterator setup. + +.. admonition:: Example + + >>> a = np.arange(3) + >>> b = np.arange(8).reshape(2,4) + >>> it = np.nditer([a, b, None], flags=['external_loop'], + ... op_axes=[[0, -1, -1], [-1, 0, 1], None]) + >>> for x, y, z in it: + ... z[...] = x*y + ... + >>> it.operands[2] + array([[[ 0, 0, 0, 0], + [ 0, 0, 0, 0]], + [[ 0, 1, 2, 3], + [ 4, 5, 6, 7]], + [[ 0, 2, 4, 6], + [ 8, 10, 12, 14]]]) + +Reduction Iteration +------------------- + +Whenever a writeable operand has fewer elements than the full iteration space, +that operand is undergoing a reduction. The :class:`nditer` object requires +that any reduction operand be flagged as read-write, and only allows +reductions when 'reduce_ok' is provided as an iterator flag. + +For a simple example, consider taking the sum of all elements in an array. + +.. admonition:: Example + + >>> a = np.arange(24).reshape(2,3,4) + >>> b = np.array(0) + >>> for x, y in np.nditer([a, b], flags=['reduce_ok', 'external_loop'], + ... op_flags=[['readonly'], ['readwrite']]): + ... y[...] += x + ... + >>> b + array(276) + >>> np.sum(a) + 276 + +Things are a little bit more tricky when combining reduction and allocated +operands. Before iteration is started, any reduction operand must be +initialized to its starting values. Here's how we can do this, taking +sums along the last axis of `a`. + +.. admonition:: Example + + >>> a = np.arange(24).reshape(2,3,4) + >>> it = np.nditer([a, None], flags=['reduce_ok', 'external_loop'], + ... op_flags=[['readonly'], ['readwrite', 'allocate']], + ... op_axes=[None, [0,1,-1]]) + >>> it.operands[1][...] = 0 + >>> for x, y in it: + ... y[...] += x + ... + >>> it.operands[1] + array([[ 6, 22, 38], + [54, 70, 86]]) + >>> np.sum(a, axis=2) + array([[ 6, 22, 38], + [54, 70, 86]]) + +To do buffered reduction requires yet another adjustment during the +setup. Normally the iterator construction involves copying the first +buffer of data from the readable arrays into the buffer. Any reduction +operand is readable, so it may be read into a buffer. Unfortunately, +initialization of the operand after this buffering operation is complete +will not be reflected in the buffer that the iteration starts with, and +garbage results will be produced. + +The iterator flag "delay_bufalloc" is there to allow +iterator-allocated reduction operands to exist together with buffering. +When this flag is set, the iterator will leave its buffers uninitialized +until it receives a reset, after which it will be ready for regular +iteration. Here's how the previous example looks if we also enable +buffering. + +.. admonition:: Example + + >>> a = np.arange(24).reshape(2,3,4) + >>> it = np.nditer([a, None], flags=['reduce_ok', 'external_loop', + ... 'buffered', 'delay_bufalloc'], + ... op_flags=[['readonly'], ['readwrite', 'allocate']], + ... op_axes=[None, [0,1,-1]]) + >>> it.operands[1][...] = 0 + >>> it.reset() + >>> for x, y in it: + ... y[...] += x + ... + >>> it.operands[1] + array([[ 6, 22, 38], + [54, 70, 86]]) + +Putting the Inner Loop in Cython +================================ + +Those who want really good performance out of their low level operations +should strongly consider directly using the iteration API provided +in C, but for those who are not comfortable with C or C++, Cython +is a good middle ground with reasonable performance tradeoffs. For +the :class:`nditer` object, this means letting the iterator take care +of broadcasting, dtype conversion, and buffering, while giving the inner +loop to Cython. + +For our example, we'll create a sum of squares function. To start, +let's implement this function in straightforward Python. We want to +support an 'axis' parameter similar to the numpy :func:`sum` function, +so we will need to construct a list for the `op_axes` parameter. +Here's how this looks. + +.. admonition:: Example + + >>> def axis_to_axeslist(axis, ndim): + ... if axis is None: + ... return [-1] * ndim + ... else: + ... if type(axis) is not tuple: + ... axis = (axis,) + ... axeslist = [1] * ndim + ... for i in axis: + ... axeslist[i] = -1 + ... ax = 0 + ... for i in range(ndim): + ... if axeslist[i] != -1: + ... axeslist[i] = ax + ... ax += 1 + ... return axeslist + ... + >>> def sum_squares_py(arr, axis=None, out=None): + ... axeslist = axis_to_axeslist(axis, arr.ndim) + ... it = np.nditer([arr, out], flags=['reduce_ok', 'external_loop', + ... 'buffered', 'delay_bufalloc'], + ... op_flags=[['readonly'], ['readwrite', 'allocate']], + ... op_axes=[None, axeslist], + ... op_dtypes=['float64', 'float64']) + ... it.operands[1][...] = 0 + ... it.reset() + ... for x, y in it: + ... y[...] += x*x + ... return it.operands[1] + ... + >>> a = np.arange(6).reshape(2,3) + >>> sum_squares_py(a) + array(55.0) + >>> sum_squares_py(a, axis=-1) + array([ 5., 50.]) + +To Cython-ize this function, we replace the inner loop (y[...] += x*x) with +Cython code that's specialized for the float64 dtype. With the +'external_loop' flag enabled, the arrays provided to the inner loop will +always be one-dimensional, so very little checking needs to be done. + +Here's the listing of sum_squares.pyx:: + + import numpy as np + cimport numpy as np + cimport cython + + def axis_to_axeslist(axis, ndim): + if axis is None: + return [-1] * ndim + else: + if type(axis) is not tuple: + axis = (axis,) + axeslist = [1] * ndim + for i in axis: + axeslist[i] = -1 + ax = 0 + for i in range(ndim): + if axeslist[i] != -1: + axeslist[i] = ax + ax += 1 + return axeslist + + @cython.boundscheck(False) + def sum_squares_cy(arr, axis=None, out=None): + cdef np.ndarray[double] x + cdef np.ndarray[double] y + cdef int size + cdef double value + + axeslist = axis_to_axeslist(axis, arr.ndim) + it = np.nditer([arr, out], flags=['reduce_ok', 'external_loop', + 'buffered', 'delay_bufalloc'], + op_flags=[['readonly'], ['readwrite', 'allocate']], + op_axes=[None, axeslist], + op_dtypes=['float64', 'float64']) + it.operands[1][...] = 0 + it.reset() + for xarr, yarr in it: + x = xarr + y = yarr + size = x.shape[0] + for i in range(size): + value = x[i] + y[i] = y[i] + value * value + return it.operands[1] + +On this machine, building the .pyx file into a module looked like the +following, but you may have to find some Cython tutorials to tell you +the specifics for your system configuration.:: + + $ cython sum_squares.pyx + $ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -I/usr/include/python2.7 -fno-strict-aliasing -o sum_squares.so sum_squares.c + +Running this from the Python interpreter produces the same answers +as our native Python/NumPy code did. + +.. admonition:: Example + + >>> from sum_squares import sum_squares_cy + >>> a = np.arange(6).reshape(2,3) + >>> sum_squares_cy(a) + array(55.0) + >>> sum_squares_cy(a, axis=-1) + array([ 5., 50.]) + +Doing a little timing in IPython shows that the reduced overhead and +memory allocation of the Cython inner loop is providing a very nice +speedup over both the straightforward Python code and an expression +using NumPy's built-in sum function.:: + + >>> a = np.random.rand(1000,1000) + + >>> timeit sum_squares_py(a, axis=-1) + 10 loops, best of 3: 37.1 ms per loop + + >>> timeit np.sum(a*a, axis=-1) + 10 loops, best of 3: 20.9 ms per loop + + >>> timeit sum_squares_cy(a, axis=-1) + 100 loops, best of 3: 11.8 ms per loop + + >>> np.all(sum_squares_cy(a, axis=-1) == np.sum(a*a, axis=-1)) + True + + >>> np.all(sum_squares_py(a, axis=-1) == np.sum(a*a, axis=-1)) + True diff --git a/doc/source/reference/arrays.rst b/doc/source/reference/arrays.rst new file mode 100644 index 0000000..faa91a3 --- /dev/null +++ b/doc/source/reference/arrays.rst @@ -0,0 +1,49 @@ +.. _arrays: + +************* +Array objects +************* + +.. currentmodule:: numpy + +NumPy provides an N-dimensional array type, the :ref:`ndarray +`, which describes a collection of "items" of the same +type. The items can be :ref:`indexed ` using for +example N integers. + +All ndarrays are :term:`homogenous`: every item takes up the same size +block of memory, and all blocks are interpreted in exactly the same +way. How each item in the array is to be interpreted is specified by a +separate :ref:`data-type object `, one of which is associated +with every array. In addition to basic types (integers, floats, +*etc.*), the data type objects can also represent data structures. + +An item extracted from an array, *e.g.*, by indexing, is represented +by a Python object whose type is one of the :ref:`array scalar types +` built in NumPy. The array scalars allow easy manipulation +of also more complicated arrangements of data. + +.. figure:: figures/threefundamental.png + + **Figure** + Conceptual diagram showing the relationship between the three + fundamental objects used to describe the data in an array: 1) the + ndarray itself, 2) the data-type object that describes the layout + of a single fixed-size element of the array, 3) the array-scalar + Python object that is returned when a single element of the array + is accessed. + + + +.. toctree:: + :maxdepth: 2 + + arrays.ndarray + arrays.scalars + arrays.dtypes + arrays.indexing + arrays.nditer + arrays.classes + maskedarray + arrays.interface + arrays.datetime diff --git a/doc/source/reference/arrays.scalars.rst b/doc/source/reference/arrays.scalars.rst new file mode 100644 index 0000000..9c4f05f --- /dev/null +++ b/doc/source/reference/arrays.scalars.rst @@ -0,0 +1,294 @@ +.. _arrays.scalars: + +******* +Scalars +******* + +.. currentmodule:: numpy + +Python defines only one type of a particular data class (there is only +one integer type, one floating-point type, etc.). This can be +convenient in applications that don't need to be concerned with all +the ways data can be represented in a computer. For scientific +computing, however, more control is often needed. + +In NumPy, there are 24 new fundamental Python types to describe +different types of scalars. These type descriptors are mostly based on +the types available in the C language that CPython is written in, with +several additional types compatible with Python's types. + +Array scalars have the same attributes and methods as :class:`ndarrays +`. [#]_ This allows one to treat items of an array partly on +the same footing as arrays, smoothing out rough edges that result when +mixing scalar and array operations. + +Array scalars live in a hierarchy (see the Figure below) of data +types. They can be detected using the hierarchy: For example, +``isinstance(val, np.generic)`` will return :const:`True` if *val* is +an array scalar object. Alternatively, what kind of array scalar is +present can be determined using other members of the data type +hierarchy. Thus, for example ``isinstance(val, np.complexfloating)`` +will return :const:`True` if *val* is a complex valued type, while +:const:`isinstance(val, np.flexible)` will return true if *val* is one +of the flexible itemsize array types (:class:`string`, +:class:`unicode`, :class:`void`). + +.. figure:: figures/dtype-hierarchy.png + + **Figure:** Hierarchy of type objects representing the array data + types. Not shown are the two integer types :class:`intp` and + :class:`uintp` which just point to the integer type that holds a + pointer for the platform. All the number types can be obtained + using bit-width names as well. + +.. [#] However, array scalars are immutable, so none of the array + scalar attributes are settable. + +.. _arrays.scalars.character-codes: + +.. _arrays.scalars.built-in: + +Built-in scalar types +===================== + +The built-in scalar types are shown below. Along with their (mostly) +C-derived names, the integer, float, and complex data-types are also +available using a bit-width convention so that an array of the right +size can always be ensured (e.g. :class:`int8`, :class:`float64`, +:class:`complex128`). Two aliases (:class:`intp` and :class:`uintp`) +pointing to the integer type that is sufficiently large to hold a C pointer +are also provided. The C-like names are associated with character codes, +which are shown in the table. Use of the character codes, however, +is discouraged. + +Some of the scalar types are essentially equivalent to fundamental +Python types and therefore inherit from them as well as from the +generic array scalar type: + +==================== ================================ +Array scalar type Related Python type +==================== ================================ +:class:`int_` :class:`IntType` (Python 2 only) +:class:`float_` :class:`FloatType` +:class:`complex_` :class:`ComplexType` +:class:`bytes_` :class:`BytesType` +:class:`unicode_` :class:`UnicodeType` +==================== ================================ + +The :class:`bool_` data type is very similar to the Python +:class:`BooleanType` but does not inherit from it because Python's +:class:`BooleanType` does not allow itself to be inherited from, and +on the C-level the size of the actual bool data is not the same as a +Python Boolean scalar. + +.. warning:: + + The :class:`bool_` type is not a subclass of the :class:`int_` type + (the :class:`bool_` is not even a number type). This is different + than Python's default implementation of :class:`bool` as a + sub-class of int. + +.. warning:: + + The :class:`int_` type does **not** inherit from the + :class:`int` built-in under Python 3, because type :class:`int` is no + longer a fixed-width integer type. + +.. tip:: The default data type in NumPy is :class:`float_`. + +In the tables below, ``platform?`` means that the type may not be +available on all platforms. Compatibility with different C or Python +types is indicated: two types are compatible if their data is of the +same size and interpreted in the same way. + +Booleans: + +=================== ============================= =============== +Type Remarks Character code +=================== ============================= =============== +:class:`bool_` compatible: Python bool ``'?'`` +:class:`bool8` 8 bits +=================== ============================= =============== + +Integers: + +=================== ============================= =============== +:class:`byte` compatible: C char ``'b'`` +:class:`short` compatible: C short ``'h'`` +:class:`intc` compatible: C int ``'i'`` +:class:`int_` compatible: Python int ``'l'`` +:class:`longlong` compatible: C long long ``'q'`` +:class:`intp` large enough to fit a pointer ``'p'`` +:class:`int8` 8 bits +:class:`int16` 16 bits +:class:`int32` 32 bits +:class:`int64` 64 bits +=================== ============================= =============== + +Unsigned integers: + +=================== ============================= =============== +:class:`ubyte` compatible: C unsigned char ``'B'`` +:class:`ushort` compatible: C unsigned short ``'H'`` +:class:`uintc` compatible: C unsigned int ``'I'`` +:class:`uint` compatible: Python int ``'L'`` +:class:`ulonglong` compatible: C long long ``'Q'`` +:class:`uintp` large enough to fit a pointer ``'P'`` +:class:`uint8` 8 bits +:class:`uint16` 16 bits +:class:`uint32` 32 bits +:class:`uint64` 64 bits +=================== ============================= =============== + +Floating-point numbers: + +=================== ============================= =============== +:class:`half` ``'e'`` +:class:`single` compatible: C float ``'f'`` +:class:`double` compatible: C double +:class:`float_` compatible: Python float ``'d'`` +:class:`longfloat` compatible: C long float ``'g'`` +:class:`float16` 16 bits +:class:`float32` 32 bits +:class:`float64` 64 bits +:class:`float96` 96 bits, platform? +:class:`float128` 128 bits, platform? +=================== ============================= =============== + +Complex floating-point numbers: + +=================== ============================= =============== +:class:`csingle` ``'F'`` +:class:`complex_` compatible: Python complex ``'D'`` +:class:`clongfloat` ``'G'`` +:class:`complex64` two 32-bit floats +:class:`complex128` two 64-bit floats +:class:`complex192` two 96-bit floats, + platform? +:class:`complex256` two 128-bit floats, + platform? +=================== ============================= =============== + +Any Python object: + +=================== ============================= =============== +:class:`object_` any Python object ``'O'`` +=================== ============================= =============== + +.. note:: + + The data actually stored in :term:`object arrays ` + (*i.e.*, arrays having dtype :class:`object_`) are references to + Python objects, not the objects themselves. Hence, object arrays + behave more like usual Python :class:`lists `, in the sense + that their contents need not be of the same Python type. + + The object type is also special because an array containing + :class:`object_` items does not return an :class:`object_` object + on item access, but instead returns the actual object that + the array item refers to. + +The following data types are :term:`flexible`. They have no predefined +size: the data they describe can be of different length in different +arrays. (In the character codes ``#`` is an integer denoting how many +elements the data type consists of.) + +=================== ============================== ======== +:class:`bytes_` compatible: Python bytes ``'S#'`` +:class:`unicode_` compatible: Python unicode/str ``'U#'`` +:class:`void` ``'V#'`` +=================== ============================== ======== + + +.. warning:: + + See :ref:`Note on string types`. + + Numeric Compatibility: If you used old typecode characters in your + Numeric code (which was never recommended), you will need to change + some of them to the new characters. In particular, the needed + changes are ``c -> S1``, ``b -> B``, ``1 -> b``, ``s -> h``, ``w -> + H``, and ``u -> I``. These changes make the type character + convention more consistent with other Python modules such as the + :mod:`struct` module. + + +Attributes +========== + +The array scalar objects have an :obj:`array priority +<__array_priority__>` of :c:data:`NPY_SCALAR_PRIORITY` +(-1,000,000.0). They also do not (yet) have a :attr:`ctypes ` +attribute. Otherwise, they share the same attributes as arrays: + +.. autosummary:: + :toctree: generated/ + + generic.flags + generic.shape + generic.strides + generic.ndim + generic.data + generic.size + generic.itemsize + generic.base + generic.dtype + generic.real + generic.imag + generic.flat + generic.T + generic.__array_interface__ + generic.__array_struct__ + generic.__array_priority__ + generic.__array_wrap__ + + +Indexing +======== +.. seealso:: :ref:`arrays.indexing`, :ref:`arrays.dtypes` + +Array scalars can be indexed like 0-dimensional arrays: if *x* is an +array scalar, + +- ``x[()]`` returns a copy of array scalar +- ``x[...]`` returns a 0-dimensional :class:`ndarray` +- ``x['field-name']`` returns the array scalar in the field *field-name*. + (*x* can have fields, for example, when it corresponds to a structured data type.) + +Methods +======= + +Array scalars have exactly the same methods as arrays. The default +behavior of these methods is to internally convert the scalar to an +equivalent 0-dimensional array and to call the corresponding array +method. In addition, math operations on array scalars are defined so +that the same hardware flags are set and used to interpret the results +as for :ref:`ufunc `, so that the error state used for ufuncs +also carries over to the math on array scalars. + +The exceptions to the above rules are given below: + +.. autosummary:: + :toctree: generated/ + + generic + generic.__array__ + generic.__array_wrap__ + generic.squeeze + generic.byteswap + generic.__reduce__ + generic.__setstate__ + generic.setflags + + +Defining new types +================== + +There are two ways to effectively define a new array scalar type +(apart from composing structured types :ref:`dtypes ` from +the built-in scalar types): One way is to simply subclass the +:class:`ndarray` and overwrite the methods of interest. This will work to +a degree, but internally certain behaviors are fixed by the data type of +the array. To fully customize the data type of an array you need to +define a new data-type, and register it with NumPy. Such new types can only +be defined in C, using the :ref:`NumPy C-API `. diff --git a/doc/source/reference/c-api.array.rst b/doc/source/reference/c-api.array.rst new file mode 100644 index 0000000..28b017b --- /dev/null +++ b/doc/source/reference/c-api.array.rst @@ -0,0 +1,3615 @@ +Array API +========= + +.. sectionauthor:: Travis E. Oliphant + +| The test of a first-rate intelligence is the ability to hold two +| opposed ideas in the mind at the same time, and still retain the +| ability to function. +| --- *F. Scott Fitzgerald* + +| For a successful technology, reality must take precedence over public +| relations, for Nature cannot be fooled. +| --- *Richard P. Feynman* + +.. index:: + pair: ndarray; C-API + pair: C-API; array + + +Array structure and data access +------------------------------- + +These macros all access the :c:type:`PyArrayObject` structure members. The input +argument, arr, can be any :c:type:`PyObject *` that is directly interpretable +as a :c:type:`PyArrayObject *` (any instance of the :c:data:`PyArray_Type` and its +sub-types). + +.. c:function:: int PyArray_NDIM(PyArrayObject *arr) + + The number of dimensions in the array. + +.. c:function:: npy_intp *PyArray_DIMS(PyArrayObject *arr) + + Returns a pointer to the dimensions/shape of the array. The + number of elements matches the number of dimensions + of the array. + +.. c:function:: npy_intp *PyArray_SHAPE(PyArrayObject *arr) + + .. versionadded:: 1.7 + + A synonym for PyArray_DIMS, named to be consistent with the + 'shape' usage within Python. + +.. c:function:: void *PyArray_DATA(PyArrayObject *arr) + +.. c:function:: char *PyArray_BYTES(PyArrayObject *arr) + + These two macros are similar and obtain the pointer to the + data-buffer for the array. The first macro can (and should be) + assigned to a particular pointer where the second is for generic + processing. If you have not guaranteed a contiguous and/or aligned + array then be sure you understand how to access the data in the + array to avoid memory and/or alignment problems. + +.. c:function:: npy_intp *PyArray_STRIDES(PyArrayObject* arr) + + Returns a pointer to the strides of the array. The + number of elements matches the number of dimensions + of the array. + +.. c:function:: npy_intp PyArray_DIM(PyArrayObject* arr, int n) + + Return the shape in the *n* :math:`^{\textrm{th}}` dimension. + +.. c:function:: npy_intp PyArray_STRIDE(PyArrayObject* arr, int n) + + Return the stride in the *n* :math:`^{\textrm{th}}` dimension. + +.. c:function:: PyObject *PyArray_BASE(PyArrayObject* arr) + + This returns the base object of the array. In most cases, this + means the object which owns the memory the array is pointing at. + + If you are constructing an array using the C API, and specifying + your own memory, you should use the function :c:func:`PyArray_SetBaseObject` + to set the base to an object which owns the memory. + + If the (deprecated) :c:data:`NPY_ARRAY_UPDATEIFCOPY` or the + :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` flags are set, it has a different + meaning, namely base is the array into which the current array will + be copied upon copy resolution. This overloading of the base property + for two functions is likely to change in a future version of NumPy. + +.. c:function:: PyArray_Descr *PyArray_DESCR(PyArrayObject* arr) + + Returns a borrowed reference to the dtype property of the array. + +.. c:function:: PyArray_Descr *PyArray_DTYPE(PyArrayObject* arr) + + .. versionadded:: 1.7 + + A synonym for PyArray_DESCR, named to be consistent with the + 'dtype' usage within Python. + +.. c:function:: void PyArray_ENABLEFLAGS(PyArrayObject* arr, int flags) + + .. versionadded:: 1.7 + + Enables the specified array flags. This function does no validation, + and assumes that you know what you're doing. + +.. c:function:: void PyArray_CLEARFLAGS(PyArrayObject* arr, int flags) + + .. versionadded:: 1.7 + + Clears the specified array flags. This function does no validation, + and assumes that you know what you're doing. + +.. c:function:: int PyArray_FLAGS(PyArrayObject* arr) + +.. c:function:: npy_intp PyArray_ITEMSIZE(PyArrayObject* arr) + + Return the itemsize for the elements of this array. + + Note that, in the old API that was deprecated in version 1.7, this function + had the return type ``int``. + +.. c:function:: int PyArray_TYPE(PyArrayObject* arr) + + Return the (builtin) typenumber for the elements of this array. + +.. c:function:: PyObject *PyArray_GETITEM(PyArrayObject* arr, void* itemptr) + + Get a Python object from the ndarray, *arr*, at the location + pointed to by itemptr. Return ``NULL`` on failure. + +.. c:function:: int PyArray_SETITEM( \ + PyArrayObject* arr, void* itemptr, PyObject* obj) + + Convert obj and place it in the ndarray, *arr*, at the place + pointed to by itemptr. Return -1 if an error occurs or 0 on + success. + +.. c:function:: npy_intp PyArray_SIZE(PyArrayObject* arr) + + Returns the total size (in number of elements) of the array. + +.. c:function:: npy_intp PyArray_Size(PyArrayObject* obj) + + Returns 0 if *obj* is not a sub-class of ndarray. Otherwise, + returns the total number of elements in the array. Safer version + of :c:func:`PyArray_SIZE` (*obj*). + +.. c:function:: npy_intp PyArray_NBYTES(PyArrayObject* arr) + + Returns the total number of bytes consumed by the array. + + +Data access +^^^^^^^^^^^ + +These functions and macros provide easy access to elements of the +ndarray from C. These work for all arrays. You may need to take care +when accessing the data in the array, however, if it is not in machine +byte-order, misaligned, or not writeable. In other words, be sure to +respect the state of the flags unless you know what you are doing, or +have previously guaranteed an array that is writeable, aligned, and in +machine byte-order using :c:func:`PyArray_FromAny`. If you wish to handle all +types of arrays, the copyswap function for each type is useful for +handling misbehaved arrays. Some platforms (e.g. Solaris) do not like +misaligned data and will crash if you de-reference a misaligned +pointer. Other platforms (e.g. x86 Linux) will just work more slowly +with misaligned data. + +.. c:function:: void* PyArray_GetPtr(PyArrayObject* aobj, npy_intp* ind) + + Return a pointer to the data of the ndarray, *aobj*, at the + N-dimensional index given by the c-array, *ind*, (which must be + at least *aobj* ->nd in size). You may want to typecast the + returned pointer to the data type of the ndarray. + +.. c:function:: void* PyArray_GETPTR1(PyArrayObject* obj, npy_intp i) + +.. c:function:: void* PyArray_GETPTR2( \ + PyArrayObject* obj, npy_intp i, npy_intp j) + +.. c:function:: void* PyArray_GETPTR3( \ + PyArrayObject* obj, npy_intp i, npy_intp j, npy_intp k) + +.. c:function:: void* PyArray_GETPTR4( \ + PyArrayObject* obj, npy_intp i, npy_intp j, npy_intp k, npy_intp l) + + Quick, inline access to the element at the given coordinates in + the ndarray, *obj*, which must have respectively 1, 2, 3, or 4 + dimensions (this is not checked). The corresponding *i*, *j*, + *k*, and *l* coordinates can be any integer but will be + interpreted as ``npy_intp``. You may want to typecast the + returned pointer to the data type of the ndarray. + + +Creating arrays +--------------- + + +From scratch +^^^^^^^^^^^^ + +.. c:function:: PyObject* PyArray_NewFromDescr( \ + PyTypeObject* subtype, PyArray_Descr* descr, int nd, npy_intp* dims, \ + npy_intp* strides, void* data, int flags, PyObject* obj) + + This function steals a reference to *descr*. + + This is the main array creation function. Most new arrays are + created with this flexible function. + + The returned object is an object of Python-type *subtype*, which + must be a subtype of :c:data:`PyArray_Type`. The array has *nd* + dimensions, described by *dims*. The data-type descriptor of the + new array is *descr*. + + If *subtype* is of an array subclass instead of the base + :c:data:`&PyArray_Type`, then *obj* is the object to pass to + the :obj:`~numpy.class.__array_finalize__` method of the subclass. + + If *data* is ``NULL``, then new memory will be allocated and *flags* + can be non-zero to indicate a Fortran-style contiguous array. If + *data* is not ``NULL``, then it is assumed to point to the memory + to be used for the array and the *flags* argument is used as the + new flags for the array (except the state of :c:data:`NPY_OWNDATA`, + :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` and :c:data:`NPY_ARRAY_UPDATEIFCOPY` + flags of the new array will be reset). + + In addition, if *data* is non-NULL, then *strides* can + also be provided. If *strides* is ``NULL``, then the array strides + are computed as C-style contiguous (default) or Fortran-style + contiguous (*flags* is nonzero for *data* = ``NULL`` or *flags* & + :c:data:`NPY_ARRAY_F_CONTIGUOUS` is nonzero non-NULL *data*). Any + provided *dims* and *strides* are copied into newly allocated + dimension and strides arrays for the new array object. + +.. c:function:: PyObject* PyArray_NewLikeArray( \ + PyArrayObject* prototype, NPY_ORDER order, PyArray_Descr* descr, \ + int subok) + + .. versionadded:: 1.6 + + This function steals a reference to *descr* if it is not NULL. + + This array creation routine allows for the convenient creation of + a new array matching an existing array's shapes and memory layout, + possibly changing the layout and/or data type. + + When *order* is :c:data:`NPY_ANYORDER`, the result order is + :c:data:`NPY_FORTRANORDER` if *prototype* is a fortran array, + :c:data:`NPY_CORDER` otherwise. When *order* is + :c:data:`NPY_KEEPORDER`, the result order matches that of *prototype*, even + when the axes of *prototype* aren't in C or Fortran order. + + If *descr* is NULL, the data type of *prototype* is used. + + If *subok* is 1, the newly created array will use the sub-type of + *prototype* to create the new array, otherwise it will create a + base-class array. + +.. c:function:: PyObject* PyArray_New( \ + PyTypeObject* subtype, int nd, npy_intp* dims, int type_num, \ + npy_intp* strides, void* data, int itemsize, int flags, PyObject* obj) + + This is similar to :c:func:`PyArray_NewFromDescr` (...) except you + specify the data-type descriptor with *type_num* and *itemsize*, + where *type_num* corresponds to a builtin (or user-defined) + type. If the type always has the same number of bytes, then + itemsize is ignored. Otherwise, itemsize specifies the particular + size of this array. + + + +.. warning:: + + If data is passed to :c:func:`PyArray_NewFromDescr` or :c:func:`PyArray_New`, + this memory must not be deallocated until the new array is + deleted. If this data came from another Python object, this can + be accomplished using :c:func:`Py_INCREF` on that object and setting the + base member of the new array to point to that object. If strides + are passed in they must be consistent with the dimensions, the + itemsize, and the data of the array. + +.. c:function:: PyObject* PyArray_SimpleNew(int nd, npy_intp* dims, int typenum) + + Create a new uninitialized array of type, *typenum*, whose size in + each of *nd* dimensions is given by the integer array, *dims*. + This function cannot be used to create a flexible-type array (no + itemsize given). + +.. c:function:: PyObject* PyArray_SimpleNewFromData( \ + int nd, npy_intp* dims, int typenum, void* data) + + Create an array wrapper around *data* pointed to by the given + pointer. The array flags will have a default that the data area is + well-behaved and C-style contiguous. The shape of the array is + given by the *dims* c-array of length *nd*. The data-type of the + array is indicated by *typenum*. + +.. c:function:: PyObject* PyArray_SimpleNewFromDescr( \ + int nd, npy_intp* dims, PyArray_Descr* descr) + + This function steals a reference to *descr* if it is not NULL. + + Create a new array with the provided data-type descriptor, *descr* + , of the shape determined by *nd* and *dims*. + +.. c:function:: PyArray_FILLWBYTE(PyObject* obj, int val) + + Fill the array pointed to by *obj* ---which must be a (subclass + of) ndarray---with the contents of *val* (evaluated as a byte). + This macro calls memset, so obj must be contiguous. + +.. c:function:: PyObject* PyArray_Zeros( \ + int nd, npy_intp* dims, PyArray_Descr* dtype, int fortran) + + Construct a new *nd* -dimensional array with shape given by *dims* + and data type given by *dtype*. If *fortran* is non-zero, then a + Fortran-order array is created, otherwise a C-order array is + created. Fill the memory with zeros (or the 0 object if *dtype* + corresponds to :c:type:`NPY_OBJECT` ). + +.. c:function:: PyObject* PyArray_ZEROS( \ + int nd, npy_intp* dims, int type_num, int fortran) + + Macro form of :c:func:`PyArray_Zeros` which takes a type-number instead + of a data-type object. + +.. c:function:: PyObject* PyArray_Empty( \ + int nd, npy_intp* dims, PyArray_Descr* dtype, int fortran) + + Construct a new *nd* -dimensional array with shape given by *dims* + and data type given by *dtype*. If *fortran* is non-zero, then a + Fortran-order array is created, otherwise a C-order array is + created. The array is uninitialized unless the data type + corresponds to :c:type:`NPY_OBJECT` in which case the array is + filled with :c:data:`Py_None`. + +.. c:function:: PyObject* PyArray_EMPTY( \ + int nd, npy_intp* dims, int typenum, int fortran) + + Macro form of :c:func:`PyArray_Empty` which takes a type-number, + *typenum*, instead of a data-type object. + +.. c:function:: PyObject* PyArray_Arange( \ + double start, double stop, double step, int typenum) + + Construct a new 1-dimensional array of data-type, *typenum*, that + ranges from *start* to *stop* (exclusive) in increments of *step* + . Equivalent to **arange** (*start*, *stop*, *step*, dtype). + +.. c:function:: PyObject* PyArray_ArangeObj( \ + PyObject* start, PyObject* stop, PyObject* step, PyArray_Descr* descr) + + Construct a new 1-dimensional array of data-type determined by + ``descr``, that ranges from ``start`` to ``stop`` (exclusive) in + increments of ``step``. Equivalent to arange( ``start``, + ``stop``, ``step``, ``typenum`` ). + +.. c:function:: int PyArray_SetBaseObject(PyArrayObject* arr, PyObject* obj) + + .. versionadded:: 1.7 + + This function **steals a reference** to ``obj`` and sets it as the + base property of ``arr``. + + If you construct an array by passing in your own memory buffer as + a parameter, you need to set the array's `base` property to ensure + the lifetime of the memory buffer is appropriate. + + The return value is 0 on success, -1 on failure. + + If the object provided is an array, this function traverses the + chain of `base` pointers so that each array points to the owner + of the memory directly. Once the base is set, it may not be changed + to another value. + +From other objects +^^^^^^^^^^^^^^^^^^ + +.. c:function:: PyObject* PyArray_FromAny( \ + PyObject* op, PyArray_Descr* dtype, int min_depth, int max_depth, \ + int requirements, PyObject* context) + + This is the main function used to obtain an array from any nested + sequence, or object that exposes the array interface, *op*. The + parameters allow specification of the required *dtype*, the + minimum (*min_depth*) and maximum (*max_depth*) number of + dimensions acceptable, and other *requirements* for the array. The + *dtype* argument needs to be a :c:type:`PyArray_Descr` structure + indicating the desired data-type (including required + byteorder). The *dtype* argument may be NULL, indicating that any + data-type (and byteorder) is acceptable. Unless + :c:data:`NPY_ARRAY_FORCECAST` is present in ``flags``, + this call will generate an error if the data + type cannot be safely obtained from the object. If you want to use + ``NULL`` for the *dtype* and ensure the array is notswapped then + use :c:func:`PyArray_CheckFromAny`. A value of 0 for either of the + depth parameters causes the parameter to be ignored. Any of the + following array flags can be added (*e.g.* using \|) to get the + *requirements* argument. If your code can handle general (*e.g.* + strided, byte-swapped, or unaligned arrays) then *requirements* + may be 0. Also, if *op* is not already an array (or does not + expose the array interface), then a new array will be created (and + filled from *op* using the sequence protocol). The new array will + have :c:data:`NPY_ARRAY_DEFAULT` as its flags member. The *context* argument + is passed to the :obj:`~numpy.class.__array__` method of *op* and is only used if + the array is constructed that way. Almost always this + parameter is ``NULL``. + + In versions 1.6 and earlier of NumPy, the following flags + did not have the ``_ARRAY_`` macro namespace in them. That form + of the constant names is deprecated in 1.7. + + .. c:var:: NPY_ARRAY_C_CONTIGUOUS + + Make sure the returned array is C-style contiguous + + .. c:var:: NPY_ARRAY_F_CONTIGUOUS + + Make sure the returned array is Fortran-style contiguous. + + .. c:var:: NPY_ARRAY_ALIGNED + + Make sure the returned array is aligned on proper boundaries for its + data type. An aligned array has the data pointer and every strides + factor as a multiple of the alignment factor for the data-type- + descriptor. + + .. c:var:: NPY_ARRAY_WRITEABLE + + Make sure the returned array can be written to. + + .. c:var:: NPY_ARRAY_ENSURECOPY + + Make sure a copy is made of *op*. If this flag is not + present, data is not copied if it can be avoided. + + .. c:var:: NPY_ARRAY_ENSUREARRAY + + Make sure the result is a base-class ndarray. By + default, if *op* is an instance of a subclass of + ndarray, an instance of that same subclass is returned. If + this flag is set, an ndarray object will be returned instead. + + .. c:var:: NPY_ARRAY_FORCECAST + + Force a cast to the output type even if it cannot be done + safely. Without this flag, a data cast will occur only if it + can be done safely, otherwise an error is raised. + + .. c:var:: NPY_ARRAY_WRITEBACKIFCOPY + + If *op* is already an array, but does not satisfy the + requirements, then a copy is made (which will satisfy the + requirements). If this flag is present and a copy (of an object + that is already an array) must be made, then the corresponding + :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` flag is set in the returned + copy and *op* is made to be read-only. You must be sure to call + :c:func:`PyArray_ResolveWritebackIfCopy` to copy the contents + back into *op* and the *op* array + will be made writeable again. If *op* is not writeable to begin + with, or if it is not already an array, then an error is raised. + + .. c:var:: NPY_ARRAY_UPDATEIFCOPY + + Deprecated. Use :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`, which is similar. + This flag "automatically" copies the data back when the returned + array is deallocated, which is not supported in all python + implementations. + + .. c:var:: NPY_ARRAY_BEHAVED + + :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE` + + .. c:var:: NPY_ARRAY_CARRAY + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_BEHAVED` + + .. c:var:: NPY_ARRAY_CARRAY_RO + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` + + .. c:var:: NPY_ARRAY_FARRAY + + :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_BEHAVED` + + .. c:var:: NPY_ARRAY_FARRAY_RO + + :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` + + .. c:var:: NPY_ARRAY_DEFAULT + + :c:data:`NPY_ARRAY_CARRAY` + + .. c:var:: NPY_ARRAY_IN_ARRAY + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` + + .. c:var:: NPY_ARRAY_IN_FARRAY + + :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` + + .. c:var:: NPY_OUT_ARRAY + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \| + :c:data:`NPY_ARRAY_ALIGNED` + + .. c:var:: NPY_ARRAY_OUT_FARRAY + + :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \| + :c:data:`NPY_ARRAY_ALIGNED` + + .. c:var:: NPY_ARRAY_INOUT_ARRAY + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \| + :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` \| + :c:data:`NPY_ARRAY_UPDATEIFCOPY` + + .. c:var:: NPY_ARRAY_INOUT_FARRAY + + :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \| + :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` \| + :c:data:`NPY_ARRAY_UPDATEIFCOPY` + +.. c:function:: int PyArray_GetArrayParamsFromObject( \ + PyObject* op, PyArray_Descr* requested_dtype, npy_bool writeable, \ + PyArray_Descr** out_dtype, int* out_ndim, npy_intp* out_dims, \ + PyArrayObject** out_arr, PyObject* context) + + .. versionadded:: 1.6 + + Retrieves the array parameters for viewing/converting an arbitrary + PyObject* to a NumPy array. This allows the "innate type and shape" + of Python list-of-lists to be discovered without + actually converting to an array. PyArray_FromAny calls this function + to analyze its input. + + In some cases, such as structured arrays and the :obj:`~numpy.class.__array__` interface, + a data type needs to be used to make sense of the object. When + this is needed, provide a Descr for 'requested_dtype', otherwise + provide NULL. This reference is not stolen. Also, if the requested + dtype doesn't modify the interpretation of the input, out_dtype will + still get the "innate" dtype of the object, not the dtype passed + in 'requested_dtype'. + + If writing to the value in 'op' is desired, set the boolean + 'writeable' to 1. This raises an error when 'op' is a scalar, list + of lists, or other non-writeable 'op'. This differs from passing + :c:data:`NPY_ARRAY_WRITEABLE` to PyArray_FromAny, where the writeable array may + be a copy of the input. + + When success (0 return value) is returned, either out_arr + is filled with a non-NULL PyArrayObject and + the rest of the parameters are untouched, or out_arr is + filled with NULL, and the rest of the parameters are filled. + + Typical usage: + + .. code-block:: c + + PyArrayObject *arr = NULL; + PyArray_Descr *dtype = NULL; + int ndim = 0; + npy_intp dims[NPY_MAXDIMS]; + + if (PyArray_GetArrayParamsFromObject(op, NULL, 1, &dtype, + &ndim, &dims, &arr, NULL) < 0) { + return NULL; + } + if (arr == NULL) { + ... validate/change dtype, validate flags, ndim, etc ... + // Could make custom strides here too + arr = PyArray_NewFromDescr(&PyArray_Type, dtype, ndim, + dims, NULL, + fortran ? NPY_ARRAY_F_CONTIGUOUS : 0, + NULL); + if (arr == NULL) { + return NULL; + } + if (PyArray_CopyObject(arr, op) < 0) { + Py_DECREF(arr); + return NULL; + } + } + else { + ... in this case the other parameters weren't filled, just + validate and possibly copy arr itself ... + } + ... use arr ... + +.. c:function:: PyObject* PyArray_CheckFromAny( \ + PyObject* op, PyArray_Descr* dtype, int min_depth, int max_depth, \ + int requirements, PyObject* context) + + Nearly identical to :c:func:`PyArray_FromAny` (...) except + *requirements* can contain :c:data:`NPY_ARRAY_NOTSWAPPED` (over-riding the + specification in *dtype*) and :c:data:`NPY_ARRAY_ELEMENTSTRIDES` which + indicates that the array should be aligned in the sense that the + strides are multiples of the element size. + + In versions 1.6 and earlier of NumPy, the following flags + did not have the _ARRAY_ macro namespace in them. That form + of the constant names is deprecated in 1.7. + +.. c:var:: NPY_ARRAY_NOTSWAPPED + + Make sure the returned array has a data-type descriptor that is in + machine byte-order, over-riding any specification in the *dtype* + argument. Normally, the byte-order requirement is determined by + the *dtype* argument. If this flag is set and the dtype argument + does not indicate a machine byte-order descriptor (or is NULL and + the object is already an array with a data-type descriptor that is + not in machine byte- order), then a new data-type descriptor is + created and used with its byte-order field set to native. + +.. c:var:: NPY_ARRAY_BEHAVED_NS + + :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE` \| :c:data:`NPY_ARRAY_NOTSWAPPED` + +.. c:var:: NPY_ARRAY_ELEMENTSTRIDES + + Make sure the returned array has strides that are multiples of the + element size. + +.. c:function:: PyObject* PyArray_FromArray( \ + PyArrayObject* op, PyArray_Descr* newtype, int requirements) + + Special case of :c:func:`PyArray_FromAny` for when *op* is already an + array but it needs to be of a specific *newtype* (including + byte-order) or has certain *requirements*. + +.. c:function:: PyObject* PyArray_FromStructInterface(PyObject* op) + + Returns an ndarray object from a Python object that exposes the + :obj:`__array_struct__` attribute and follows the array interface + protocol. If the object does not contain this attribute then a + borrowed reference to :c:data:`Py_NotImplemented` is returned. + +.. c:function:: PyObject* PyArray_FromInterface(PyObject* op) + + Returns an ndarray object from a Python object that exposes the + :obj:`__array_interface__` attribute following the array interface + protocol. If the object does not contain this attribute then a + borrowed reference to :c:data:`Py_NotImplemented` is returned. + +.. c:function:: PyObject* PyArray_FromArrayAttr( \ + PyObject* op, PyArray_Descr* dtype, PyObject* context) + + Return an ndarray object from a Python object that exposes the + :obj:`~numpy.class.__array__` method. The :obj:`~numpy.class.__array__` method can take 0, 1, or 2 + arguments ([dtype, context]) where *context* is used to pass + information about where the :obj:`~numpy.class.__array__` method is being called + from (currently only used in ufuncs). + +.. c:function:: PyObject* PyArray_ContiguousFromAny( \ + PyObject* op, int typenum, int min_depth, int max_depth) + + This function returns a (C-style) contiguous and behaved function + array from any nested sequence or array interface exporting + object, *op*, of (non-flexible) type given by the enumerated + *typenum*, of minimum depth *min_depth*, and of maximum depth + *max_depth*. Equivalent to a call to :c:func:`PyArray_FromAny` with + requirements set to :c:data:`NPY_ARRAY_DEFAULT` and the type_num member of the + type argument set to *typenum*. + +.. c:function:: PyObject *PyArray_FromObject( \ + PyObject *op, int typenum, int min_depth, int max_depth) + + Return an aligned and in native-byteorder array from any nested + sequence or array-interface exporting object, op, of a type given by + the enumerated typenum. The minimum number of dimensions the array can + have is given by min_depth while the maximum is max_depth. This is + equivalent to a call to :c:func:`PyArray_FromAny` with requirements set to + BEHAVED. + +.. c:function:: PyObject* PyArray_EnsureArray(PyObject* op) + + This function **steals a reference** to ``op`` and makes sure that + ``op`` is a base-class ndarray. It special cases array scalars, + but otherwise calls :c:func:`PyArray_FromAny` ( ``op``, NULL, 0, 0, + :c:data:`NPY_ARRAY_ENSUREARRAY`, NULL). + +.. c:function:: PyObject* PyArray_FromString( \ + char* string, npy_intp slen, PyArray_Descr* dtype, npy_intp num, \ + char* sep) + + Construct a one-dimensional ndarray of a single type from a binary + or (ASCII) text ``string`` of length ``slen``. The data-type of + the array to-be-created is given by ``dtype``. If num is -1, then + **copy** the entire string and return an appropriately sized + array, otherwise, ``num`` is the number of items to **copy** from + the string. If ``sep`` is NULL (or ""), then interpret the string + as bytes of binary data, otherwise convert the sub-strings + separated by ``sep`` to items of data-type ``dtype``. Some + data-types may not be readable in text mode and an error will be + raised if that occurs. All errors return NULL. + +.. c:function:: PyObject* PyArray_FromFile( \ + FILE* fp, PyArray_Descr* dtype, npy_intp num, char* sep) + + Construct a one-dimensional ndarray of a single type from a binary + or text file. The open file pointer is ``fp``, the data-type of + the array to be created is given by ``dtype``. This must match + the data in the file. If ``num`` is -1, then read until the end of + the file and return an appropriately sized array, otherwise, + ``num`` is the number of items to read. If ``sep`` is NULL (or + ""), then read from the file in binary mode, otherwise read from + the file in text mode with ``sep`` providing the item + separator. Some array types cannot be read in text mode in which + case an error is raised. + +.. c:function:: PyObject* PyArray_FromBuffer( \ + PyObject* buf, PyArray_Descr* dtype, npy_intp count, npy_intp offset) + + Construct a one-dimensional ndarray of a single type from an + object, ``buf``, that exports the (single-segment) buffer protocol + (or has an attribute __buffer\__ that returns an object that + exports the buffer protocol). A writeable buffer will be tried + first followed by a read- only buffer. The :c:data:`NPY_ARRAY_WRITEABLE` + flag of the returned array will reflect which one was + successful. The data is assumed to start at ``offset`` bytes from + the start of the memory location for the object. The type of the + data in the buffer will be interpreted depending on the data- type + descriptor, ``dtype.`` If ``count`` is negative then it will be + determined from the size of the buffer and the requested itemsize, + otherwise, ``count`` represents how many elements should be + converted from the buffer. + +.. c:function:: int PyArray_CopyInto(PyArrayObject* dest, PyArrayObject* src) + + Copy from the source array, ``src``, into the destination array, + ``dest``, performing a data-type conversion if necessary. If an + error occurs return -1 (otherwise 0). The shape of ``src`` must be + broadcastable to the shape of ``dest``. The data areas of dest + and src must not overlap. + +.. c:function:: int PyArray_MoveInto(PyArrayObject* dest, PyArrayObject* src) + + Move data from the source array, ``src``, into the destination + array, ``dest``, performing a data-type conversion if + necessary. If an error occurs return -1 (otherwise 0). The shape + of ``src`` must be broadcastable to the shape of ``dest``. The + data areas of dest and src may overlap. + +.. c:function:: PyArrayObject* PyArray_GETCONTIGUOUS(PyObject* op) + + If ``op`` is already (C-style) contiguous and well-behaved then + just return a reference, otherwise return a (contiguous and + well-behaved) copy of the array. The parameter op must be a + (sub-class of an) ndarray and no checking for that is done. + +.. c:function:: PyObject* PyArray_FROM_O(PyObject* obj) + + Convert ``obj`` to an ndarray. The argument can be any nested + sequence or object that exports the array interface. This is a + macro form of :c:func:`PyArray_FromAny` using ``NULL``, 0, 0, 0 for the + other arguments. Your code must be able to handle any data-type + descriptor and any combination of data-flags to use this macro. + +.. c:function:: PyObject* PyArray_FROM_OF(PyObject* obj, int requirements) + + Similar to :c:func:`PyArray_FROM_O` except it can take an argument + of *requirements* indicating properties the resulting array must + have. Available requirements that can be enforced are + :c:data:`NPY_ARRAY_C_CONTIGUOUS`, :c:data:`NPY_ARRAY_F_CONTIGUOUS`, + :c:data:`NPY_ARRAY_ALIGNED`, :c:data:`NPY_ARRAY_WRITEABLE`, + :c:data:`NPY_ARRAY_NOTSWAPPED`, :c:data:`NPY_ARRAY_ENSURECOPY`, + :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`, :c:data:`NPY_ARRAY_UPDATEIFCOPY`, + :c:data:`NPY_ARRAY_FORCECAST`, and + :c:data:`NPY_ARRAY_ENSUREARRAY`. Standard combinations of flags can also + be used: + +.. c:function:: PyObject* PyArray_FROM_OT(PyObject* obj, int typenum) + + Similar to :c:func:`PyArray_FROM_O` except it can take an argument of + *typenum* specifying the type-number the returned array. + +.. c:function:: PyObject* PyArray_FROM_OTF( \ + PyObject* obj, int typenum, int requirements) + + Combination of :c:func:`PyArray_FROM_OF` and :c:func:`PyArray_FROM_OT` + allowing both a *typenum* and a *flags* argument to be provided.. + +.. c:function:: PyObject* PyArray_FROMANY( \ + PyObject* obj, int typenum, int min, int max, int requirements) + + Similar to :c:func:`PyArray_FromAny` except the data-type is + specified using a typenumber. :c:func:`PyArray_DescrFromType` + (*typenum*) is passed directly to :c:func:`PyArray_FromAny`. This + macro also adds :c:data:`NPY_ARRAY_DEFAULT` to requirements if + :c:data:`NPY_ARRAY_ENSURECOPY` is passed in as requirements. + +.. c:function:: PyObject *PyArray_CheckAxis( \ + PyObject* obj, int* axis, int requirements) + + Encapsulate the functionality of functions and methods that take + the axis= keyword and work properly with None as the axis + argument. The input array is ``obj``, while ``*axis`` is a + converted integer (so that >=MAXDIMS is the None value), and + ``requirements`` gives the needed properties of ``obj``. The + output is a converted version of the input so that requirements + are met and if needed a flattening has occurred. On output + negative values of ``*axis`` are converted and the new value is + checked to ensure consistency with the shape of ``obj``. + + +Dealing with types +------------------ + + +General check of Python Type +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. c:function:: PyArray_Check(op) + + Evaluates true if *op* is a Python object whose type is a sub-type + of :c:data:`PyArray_Type`. + +.. c:function:: PyArray_CheckExact(op) + + Evaluates true if *op* is a Python object with type + :c:data:`PyArray_Type`. + +.. c:function:: PyArray_HasArrayInterface(op, out) + + If ``op`` implements any part of the array interface, then ``out`` + will contain a new reference to the newly created ndarray using + the interface or ``out`` will contain ``NULL`` if an error during + conversion occurs. Otherwise, out will contain a borrowed + reference to :c:data:`Py_NotImplemented` and no error condition is set. + +.. c:function:: PyArray_HasArrayInterfaceType(op, type, context, out) + + If ``op`` implements any part of the array interface, then ``out`` + will contain a new reference to the newly created ndarray using + the interface or ``out`` will contain ``NULL`` if an error during + conversion occurs. Otherwise, out will contain a borrowed + reference to Py_NotImplemented and no error condition is set. + This version allows setting of the type and context in the part of + the array interface that looks for the :obj:`~numpy.class.__array__` attribute. + +.. c:function:: PyArray_IsZeroDim(op) + + Evaluates true if *op* is an instance of (a subclass of) + :c:data:`PyArray_Type` and has 0 dimensions. + +.. c:function:: PyArray_IsScalar(op, cls) + + Evaluates true if *op* is an instance of :c:data:`Py{cls}ArrType_Type`. + +.. c:function:: PyArray_CheckScalar(op) + + Evaluates true if *op* is either an array scalar (an instance of a + sub-type of :c:data:`PyGenericArr_Type` ), or an instance of (a + sub-class of) :c:data:`PyArray_Type` whose dimensionality is 0. + +.. c:function:: PyArray_IsPythonNumber(op) + + Evaluates true if *op* is an instance of a builtin numeric type (int, + float, complex, long, bool) + +.. c:function:: PyArray_IsPythonScalar(op) + + Evaluates true if *op* is a builtin Python scalar object (int, + float, complex, str, unicode, long, bool). + +.. c:function:: PyArray_IsAnyScalar(op) + + Evaluates true if *op* is either a Python scalar object (see + :c:func:`PyArray_IsPythonScalar`) or an array scalar (an instance of a sub- + type of :c:data:`PyGenericArr_Type` ). + +.. c:function:: PyArray_CheckAnyScalar(op) + + Evaluates true if *op* is a Python scalar object (see + :c:func:`PyArray_IsPythonScalar`), an array scalar (an instance of a + sub-type of :c:data:`PyGenericArr_Type`) or an instance of a sub-type of + :c:data:`PyArray_Type` whose dimensionality is 0. + + +Data-type checking +^^^^^^^^^^^^^^^^^^ + +For the typenum macros, the argument is an integer representing an +enumerated array data type. For the array type checking macros the +argument must be a :c:type:`PyObject *` that can be directly interpreted as a +:c:type:`PyArrayObject *`. + +.. c:function:: PyTypeNum_ISUNSIGNED(num) + +.. c:function:: PyDataType_ISUNSIGNED(descr) + +.. c:function:: PyArray_ISUNSIGNED(obj) + + Type represents an unsigned integer. + +.. c:function:: PyTypeNum_ISSIGNED(num) + +.. c:function:: PyDataType_ISSIGNED(descr) + +.. c:function:: PyArray_ISSIGNED(obj) + + Type represents a signed integer. + +.. c:function:: PyTypeNum_ISINTEGER(num) + +.. c:function:: PyDataType_ISINTEGER(descr) + +.. c:function:: PyArray_ISINTEGER(obj) + + Type represents any integer. + +.. c:function:: PyTypeNum_ISFLOAT(num) + +.. c:function:: PyDataType_ISFLOAT(descr) + +.. c:function:: PyArray_ISFLOAT(obj) + + Type represents any floating point number. + +.. c:function:: PyTypeNum_ISCOMPLEX(num) + +.. c:function:: PyDataType_ISCOMPLEX(descr) + +.. c:function:: PyArray_ISCOMPLEX(obj) + + Type represents any complex floating point number. + +.. c:function:: PyTypeNum_ISNUMBER(num) + +.. c:function:: PyDataType_ISNUMBER(descr) + +.. c:function:: PyArray_ISNUMBER(obj) + + Type represents any integer, floating point, or complex floating point + number. + +.. c:function:: PyTypeNum_ISSTRING(num) + +.. c:function:: PyDataType_ISSTRING(descr) + +.. c:function:: PyArray_ISSTRING(obj) + + Type represents a string data type. + +.. c:function:: PyTypeNum_ISPYTHON(num) + +.. c:function:: PyDataType_ISPYTHON(descr) + +.. c:function:: PyArray_ISPYTHON(obj) + + Type represents an enumerated type corresponding to one of the + standard Python scalar (bool, int, float, or complex). + +.. c:function:: PyTypeNum_ISFLEXIBLE(num) + +.. c:function:: PyDataType_ISFLEXIBLE(descr) + +.. c:function:: PyArray_ISFLEXIBLE(obj) + + Type represents one of the flexible array types ( :c:data:`NPY_STRING`, + :c:data:`NPY_UNICODE`, or :c:data:`NPY_VOID` ). + +.. c:function:: PyDataType_ISUNSIZED(descr): + + Type has no size information attached, and can be resized. Should only be + called on flexible dtypes. Types that are attached to an array will always + be sized, hence the array form of this macro not existing. + +.. c:function:: PyTypeNum_ISUSERDEF(num) + +.. c:function:: PyDataType_ISUSERDEF(descr) + +.. c:function:: PyArray_ISUSERDEF(obj) + + Type represents a user-defined type. + +.. c:function:: PyTypeNum_ISEXTENDED(num) + +.. c:function:: PyDataType_ISEXTENDED(descr) + +.. c:function:: PyArray_ISEXTENDED(obj) + + Type is either flexible or user-defined. + +.. c:function:: PyTypeNum_ISOBJECT(num) + +.. c:function:: PyDataType_ISOBJECT(descr) + +.. c:function:: PyArray_ISOBJECT(obj) + + Type represents object data type. + +.. c:function:: PyTypeNum_ISBOOL(num) + +.. c:function:: PyDataType_ISBOOL(descr) + +.. c:function:: PyArray_ISBOOL(obj) + + Type represents Boolean data type. + +.. c:function:: PyDataType_HASFIELDS(descr) + +.. c:function:: PyArray_HASFIELDS(obj) + + Type has fields associated with it. + +.. c:function:: PyArray_ISNOTSWAPPED(m) + + Evaluates true if the data area of the ndarray *m* is in machine + byte-order according to the array's data-type descriptor. + +.. c:function:: PyArray_ISBYTESWAPPED(m) + + Evaluates true if the data area of the ndarray *m* is **not** in + machine byte-order according to the array's data-type descriptor. + +.. c:function:: Bool PyArray_EquivTypes( \ + PyArray_Descr* type1, PyArray_Descr* type2) + + Return :c:data:`NPY_TRUE` if *type1* and *type2* actually represent + equivalent types for this platform (the fortran member of each + type is ignored). For example, on 32-bit platforms, + :c:data:`NPY_LONG` and :c:data:`NPY_INT` are equivalent. Otherwise + return :c:data:`NPY_FALSE`. + +.. c:function:: Bool PyArray_EquivArrTypes( \ + PyArrayObject* a1, PyArrayObject * a2) + + Return :c:data:`NPY_TRUE` if *a1* and *a2* are arrays with equivalent + types for this platform. + +.. c:function:: Bool PyArray_EquivTypenums(int typenum1, int typenum2) + + Special case of :c:func:`PyArray_EquivTypes` (...) that does not accept + flexible data types but may be easier to call. + +.. c:function:: int PyArray_EquivByteorders({byteorder} b1, {byteorder} b2) + + True if byteorder characters ( :c:data:`NPY_LITTLE`, + :c:data:`NPY_BIG`, :c:data:`NPY_NATIVE`, :c:data:`NPY_IGNORE` ) are + either equal or equivalent as to their specification of a native + byte order. Thus, on a little-endian machine :c:data:`NPY_LITTLE` + and :c:data:`NPY_NATIVE` are equivalent where they are not + equivalent on a big-endian machine. + + +Converting data types +^^^^^^^^^^^^^^^^^^^^^ + +.. c:function:: PyObject* PyArray_Cast(PyArrayObject* arr, int typenum) + + Mainly for backwards compatibility to the Numeric C-API and for + simple casts to non-flexible types. Return a new array object with + the elements of *arr* cast to the data-type *typenum* which must + be one of the enumerated types and not a flexible type. + +.. c:function:: PyObject* PyArray_CastToType( \ + PyArrayObject* arr, PyArray_Descr* type, int fortran) + + Return a new array of the *type* specified, casting the elements + of *arr* as appropriate. The fortran argument specifies the + ordering of the output array. + +.. c:function:: int PyArray_CastTo(PyArrayObject* out, PyArrayObject* in) + + As of 1.6, this function simply calls :c:func:`PyArray_CopyInto`, + which handles the casting. + + Cast the elements of the array *in* into the array *out*. The + output array should be writeable, have an integer-multiple of the + number of elements in the input array (more than one copy can be + placed in out), and have a data type that is one of the builtin + types. Returns 0 on success and -1 if an error occurs. + +.. c:function:: PyArray_VectorUnaryFunc* PyArray_GetCastFunc( \ + PyArray_Descr* from, int totype) + + Return the low-level casting function to cast from the given + descriptor to the builtin type number. If no casting function + exists return ``NULL`` and set an error. Using this function + instead of direct access to *from* ->f->cast will allow support of + any user-defined casting functions added to a descriptors casting + dictionary. + +.. c:function:: int PyArray_CanCastSafely(int fromtype, int totype) + + Returns non-zero if an array of data type *fromtype* can be cast + to an array of data type *totype* without losing information. An + exception is that 64-bit integers are allowed to be cast to 64-bit + floating point values even though this can lose precision on large + integers so as not to proliferate the use of long doubles without + explicit requests. Flexible array types are not checked according + to their lengths with this function. + +.. c:function:: int PyArray_CanCastTo( \ + PyArray_Descr* fromtype, PyArray_Descr* totype) + + :c:func:`PyArray_CanCastTypeTo` supersedes this function in + NumPy 1.6 and later. + + Equivalent to PyArray_CanCastTypeTo(fromtype, totype, NPY_SAFE_CASTING). + +.. c:function:: int PyArray_CanCastTypeTo( \ + PyArray_Descr* fromtype, PyArray_Descr* totype, NPY_CASTING casting) + + .. versionadded:: 1.6 + + Returns non-zero if an array of data type *fromtype* (which can + include flexible types) can be cast safely to an array of data + type *totype* (which can include flexible types) according to + the casting rule *casting*. For simple types with :c:data:`NPY_SAFE_CASTING`, + this is basically a wrapper around :c:func:`PyArray_CanCastSafely`, but + for flexible types such as strings or unicode, it produces results + taking into account their sizes. Integer and float types can only be cast + to a string or unicode type using :c:data:`NPY_SAFE_CASTING` if the string + or unicode type is big enough to hold the max value of the integer/float + type being cast from. + +.. c:function:: int PyArray_CanCastArrayTo( \ + PyArrayObject* arr, PyArray_Descr* totype, NPY_CASTING casting) + + .. versionadded:: 1.6 + + Returns non-zero if *arr* can be cast to *totype* according + to the casting rule given in *casting*. If *arr* is an array + scalar, its value is taken into account, and non-zero is also + returned when the value will not overflow or be truncated to + an integer when converting to a smaller type. + + This is almost the same as the result of + PyArray_CanCastTypeTo(PyArray_MinScalarType(arr), totype, casting), + but it also handles a special case arising because the set + of uint values is not a subset of the int values for types with the + same number of bits. + +.. c:function:: PyArray_Descr* PyArray_MinScalarType(PyArrayObject* arr) + + .. versionadded:: 1.6 + + If *arr* is an array, returns its data type descriptor, but if + *arr* is an array scalar (has 0 dimensions), it finds the data type + of smallest size to which the value may be converted + without overflow or truncation to an integer. + + This function will not demote complex to float or anything to + boolean, but will demote a signed integer to an unsigned integer + when the scalar value is positive. + +.. c:function:: PyArray_Descr* PyArray_PromoteTypes( \ + PyArray_Descr* type1, PyArray_Descr* type2) + + .. versionadded:: 1.6 + + Finds the data type of smallest size and kind to which *type1* and + *type2* may be safely converted. This function is symmetric and + associative. A string or unicode result will be the proper size for + storing the max value of the input types converted to a string or unicode. + +.. c:function:: PyArray_Descr* PyArray_ResultType( \ + npy_intp narrs, PyArrayObject**arrs, npy_intp ndtypes, \ + PyArray_Descr**dtypes) + + .. versionadded:: 1.6 + + This applies type promotion to all the inputs, + using the NumPy rules for combining scalars and arrays, to + determine the output type of a set of operands. This is the + same result type that ufuncs produce. The specific algorithm + used is as follows. + + Categories are determined by first checking which of boolean, + integer (int/uint), or floating point (float/complex) the maximum + kind of all the arrays and the scalars are. + + If there are only scalars or the maximum category of the scalars + is higher than the maximum category of the arrays, + the data types are combined with :c:func:`PyArray_PromoteTypes` + to produce the return value. + + Otherwise, PyArray_MinScalarType is called on each array, and + the resulting data types are all combined with + :c:func:`PyArray_PromoteTypes` to produce the return value. + + The set of int values is not a subset of the uint values for types + with the same number of bits, something not reflected in + :c:func:`PyArray_MinScalarType`, but handled as a special case in + PyArray_ResultType. + +.. c:function:: int PyArray_ObjectType(PyObject* op, int mintype) + + This function is superceded by :c:func:`PyArray_MinScalarType` and/or + :c:func:`PyArray_ResultType`. + + This function is useful for determining a common type that two or + more arrays can be converted to. It only works for non-flexible + array types as no itemsize information is passed. The *mintype* + argument represents the minimum type acceptable, and *op* + represents the object that will be converted to an array. The + return value is the enumerated typenumber that represents the + data-type that *op* should have. + +.. c:function:: void PyArray_ArrayType( \ + PyObject* op, PyArray_Descr* mintype, PyArray_Descr* outtype) + + This function is superceded by :c:func:`PyArray_ResultType`. + + This function works similarly to :c:func:`PyArray_ObjectType` (...) + except it handles flexible arrays. The *mintype* argument can have + an itemsize member and the *outtype* argument will have an + itemsize member at least as big but perhaps bigger depending on + the object *op*. + +.. c:function:: PyArrayObject** PyArray_ConvertToCommonType( \ + PyObject* op, int* n) + + The functionality this provides is largely superceded by iterator + :c:type:`NpyIter` introduced in 1.6, with flag + :c:data:`NPY_ITER_COMMON_DTYPE` or with the same dtype parameter for + all operands. + + Convert a sequence of Python objects contained in *op* to an array + of ndarrays each having the same data type. The type is selected + based on the typenumber (larger type number is chosen over a + smaller one) ignoring objects that are only scalars. The length of + the sequence is returned in *n*, and an *n* -length array of + :c:type:`PyArrayObject` pointers is the return value (or ``NULL`` if an + error occurs). The returned array must be freed by the caller of + this routine (using :c:func:`PyDataMem_FREE` ) and all the array objects + in it ``DECREF`` 'd or a memory-leak will occur. The example + template-code below shows a typically usage: + + .. code-block:: c + + mps = PyArray_ConvertToCommonType(obj, &n); + if (mps==NULL) return NULL; + {code} + + for (i=0; iitemsize that + holds the representation of 0 for that type. The returned pointer, + *ret*, **must be freed** using :c:func:`PyDataMem_FREE` (ret) when it is + not needed anymore. + +.. c:function:: char* PyArray_One(PyArrayObject* arr) + + A pointer to newly created memory of size *arr* ->itemsize that + holds the representation of 1 for that type. The returned pointer, + *ret*, **must be freed** using :c:func:`PyDataMem_FREE` (ret) when it + is not needed anymore. + +.. c:function:: int PyArray_ValidType(int typenum) + + Returns :c:data:`NPY_TRUE` if *typenum* represents a valid type-number + (builtin or user-defined or character code). Otherwise, this + function returns :c:data:`NPY_FALSE`. + + +New data types +^^^^^^^^^^^^^^ + +.. c:function:: void PyArray_InitArrFuncs(PyArray_ArrFuncs* f) + + Initialize all function pointers and members to ``NULL``. + +.. c:function:: int PyArray_RegisterDataType(PyArray_Descr* dtype) + + Register a data-type as a new user-defined data type for + arrays. The type must have most of its entries filled in. This is + not always checked and errors can produce segfaults. In + particular, the typeobj member of the ``dtype`` structure must be + filled with a Python type that has a fixed-size element-size that + corresponds to the elsize member of *dtype*. Also the ``f`` + member must have the required functions: nonzero, copyswap, + copyswapn, getitem, setitem, and cast (some of the cast functions + may be ``NULL`` if no support is desired). To avoid confusion, you + should choose a unique character typecode but this is not enforced + and not relied on internally. + + A user-defined type number is returned that uniquely identifies + the type. A pointer to the new structure can then be obtained from + :c:func:`PyArray_DescrFromType` using the returned type number. A -1 is + returned if an error occurs. If this *dtype* has already been + registered (checked only by the address of the pointer), then + return the previously-assigned type-number. + +.. c:function:: int PyArray_RegisterCastFunc( \ + PyArray_Descr* descr, int totype, PyArray_VectorUnaryFunc* castfunc) + + Register a low-level casting function, *castfunc*, to convert + from the data-type, *descr*, to the given data-type number, + *totype*. Any old casting function is over-written. A ``0`` is + returned on success or a ``-1`` on failure. + +.. c:function:: int PyArray_RegisterCanCast( \ + PyArray_Descr* descr, int totype, NPY_SCALARKIND scalar) + + Register the data-type number, *totype*, as castable from + data-type object, *descr*, of the given *scalar* kind. Use + *scalar* = :c:data:`NPY_NOSCALAR` to register that an array of data-type + *descr* can be cast safely to a data-type whose type_number is + *totype*. + + +Special functions for NPY_OBJECT +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. c:function:: int PyArray_INCREF(PyArrayObject* op) + + Used for an array, *op*, that contains any Python objects. It + increments the reference count of every object in the array + according to the data-type of *op*. A -1 is returned if an error + occurs, otherwise 0 is returned. + +.. c:function:: void PyArray_Item_INCREF(char* ptr, PyArray_Descr* dtype) + + A function to INCREF all the objects at the location *ptr* + according to the data-type *dtype*. If *ptr* is the start of a + structured type with an object at any offset, then this will (recursively) + increment the reference count of all object-like items in the + structured type. + +.. c:function:: int PyArray_XDECREF(PyArrayObject* op) + + Used for an array, *op*, that contains any Python objects. It + decrements the reference count of every object in the array + according to the data-type of *op*. Normal return value is 0. A + -1 is returned if an error occurs. + +.. c:function:: void PyArray_Item_XDECREF(char* ptr, PyArray_Descr* dtype) + + A function to XDECREF all the object-like items at the location + *ptr* as recorded in the data-type, *dtype*. This works + recursively so that if ``dtype`` itself has fields with data-types + that contain object-like items, all the object-like fields will be + XDECREF ``'d``. + +.. c:function:: void PyArray_FillObjectArray(PyArrayObject* arr, PyObject* obj) + + Fill a newly created array with a single value obj at all + locations in the structure with object data-types. No checking is + performed but *arr* must be of data-type :c:type:`NPY_OBJECT` and be + single-segment and uninitialized (no previous objects in + position). Use :c:func:`PyArray_DECREF` (*arr*) if you need to + decrement all the items in the object array prior to calling this + function. + +.. c:function:: int PyArray_SetUpdateIfCopyBase(PyArrayObject* arr, PyArrayObject* base) + + Precondition: ``arr`` is a copy of ``base`` (though possibly with different + strides, ordering, etc.) Set the UPDATEIFCOPY flag and ``arr->base`` so + that when ``arr`` is destructed, it will copy any changes back to ``base``. + DEPRECATED, use :c:func:`PyArray_SetWritebackIfCopyBase``. + + Returns 0 for success, -1 for failure. + +.. c:function:: int PyArray_SetWritebackIfCopyBase(PyArrayObject* arr, PyArrayObject* base) + + Precondition: ``arr`` is a copy of ``base`` (though possibly with different + strides, ordering, etc.) Sets the :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` flag + and ``arr->base``, and set ``base`` to READONLY. Call + :c:func:`PyArray_ResolveWritebackIfCopy` before calling + `Py_DECREF`` in order copy any changes back to ``base`` and + reset the READONLY flag. + + Returns 0 for success, -1 for failure. + + +Array flags +----------- + +The ``flags`` attribute of the ``PyArrayObject`` structure contains +important information about the memory used by the array (pointed to +by the data member) This flag information must be kept accurate or +strange results and even segfaults may result. + +There are 6 (binary) flags that describe the memory area used by the +data buffer. These constants are defined in ``arrayobject.h`` and +determine the bit-position of the flag. Python exposes a nice +attribute- based interface as well as a dictionary-like interface for +getting (and, if appropriate, setting) these flags. + +Memory areas of all kinds can be pointed to by an ndarray, necessitating +these flags. If you get an arbitrary ``PyArrayObject`` in C-code, you +need to be aware of the flags that are set. If you need to guarantee +a certain kind of array (like :c:data:`NPY_ARRAY_C_CONTIGUOUS` and +:c:data:`NPY_ARRAY_BEHAVED`), then pass these requirements into the +PyArray_FromAny function. + + +Basic Array Flags +^^^^^^^^^^^^^^^^^ + +An ndarray can have a data segment that is not a simple contiguous +chunk of well-behaved memory you can manipulate. It may not be aligned +with word boundaries (very important on some platforms). It might have +its data in a different byte-order than the machine recognizes. It +might not be writeable. It might be in Fortan-contiguous order. The +array flags are used to indicate what can be said about data +associated with an array. + +In versions 1.6 and earlier of NumPy, the following flags +did not have the _ARRAY_ macro namespace in them. That form +of the constant names is deprecated in 1.7. + +.. c:var:: NPY_ARRAY_C_CONTIGUOUS + + The data area is in C-style contiguous order (last index varies the + fastest). + +.. c:var:: NPY_ARRAY_F_CONTIGUOUS + + The data area is in Fortran-style contiguous order (first index varies + the fastest). + +.. note:: + + Arrays can be both C-style and Fortran-style contiguous simultaneously. + This is clear for 1-dimensional arrays, but can also be true for higher + dimensional arrays. + + Even for contiguous arrays a stride for a given dimension + ``arr.strides[dim]`` may be *arbitrary* if ``arr.shape[dim] == 1`` + or the array has no elements. + It does *not* generally hold that ``self.strides[-1] == self.itemsize`` + for C-style contiguous arrays or ``self.strides[0] == self.itemsize`` for + Fortran-style contiguous arrays is true. The correct way to access the + ``itemsize`` of an array from the C API is ``PyArray_ITEMSIZE(arr)``. + + .. seealso:: :ref:`Internal memory layout of an ndarray ` + +.. c:var:: NPY_ARRAY_OWNDATA + + The data area is owned by this array. + +.. c:var:: NPY_ARRAY_ALIGNED + + The data area and all array elements are aligned appropriately. + +.. c:var:: NPY_ARRAY_WRITEABLE + + The data area can be written to. + + Notice that the above 3 flags are defined so that a new, well- + behaved array has these flags defined as true. + +.. c:var:: NPY_ARRAY_WRITEBACKIFCOPY + + The data area represents a (well-behaved) copy whose information + should be transferred back to the original when + :c:func:`PyArray_ResolveWritebackIfCopy` is called. + + This is a special flag that is set if this array represents a copy + made because a user required certain flags in + :c:func:`PyArray_FromAny` and a copy had to be made of some other + array (and the user asked for this flag to be set in such a + situation). The base attribute then points to the "misbehaved" + array (which is set read_only). :c:func`PyArray_ResolveWritebackIfCopy` + will copy its contents back to the "misbehaved" + array (casting if necessary) and will reset the "misbehaved" array + to :c:data:`NPY_ARRAY_WRITEABLE`. If the "misbehaved" array was not + :c:data:`NPY_ARRAY_WRITEABLE` to begin with then :c:func:`PyArray_FromAny` + would have returned an error because :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` + would not have been possible. + +.. c:var:: NPY_ARRAY_UPDATEIFCOPY + + A deprecated version of :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` which + depends upon ``dealloc`` to trigger the writeback. For backwards + compatibility, :c:func:`PyArray_ResolveWritebackIfCopy` is called at + ``dealloc`` but relying + on that behavior is deprecated and not supported in PyPy. + +:c:func:`PyArray_UpdateFlags` (obj, flags) will update the ``obj->flags`` +for ``flags`` which can be any of :c:data:`NPY_ARRAY_C_CONTIGUOUS`, +:c:data:`NPY_ARRAY_F_CONTIGUOUS`, :c:data:`NPY_ARRAY_ALIGNED`, or +:c:data:`NPY_ARRAY_WRITEABLE`. + + +Combinations of array flags +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. c:var:: NPY_ARRAY_BEHAVED + + :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE` + +.. c:var:: NPY_ARRAY_CARRAY + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_BEHAVED` + +.. c:var:: NPY_ARRAY_CARRAY_RO + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` + +.. c:var:: NPY_ARRAY_FARRAY + + :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_BEHAVED` + +.. c:var:: NPY_ARRAY_FARRAY_RO + + :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` + +.. c:var:: NPY_ARRAY_DEFAULT + + :c:data:`NPY_ARRAY_CARRAY` + +.. c:var:: NPY_ARRAY_UPDATE_ALL + + :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` + + +Flag-like constants +^^^^^^^^^^^^^^^^^^^ + +These constants are used in :c:func:`PyArray_FromAny` (and its macro forms) to +specify desired properties of the new array. + +.. c:var:: NPY_ARRAY_FORCECAST + + Cast to the desired type, even if it can't be done without losing + information. + +.. c:var:: NPY_ARRAY_ENSURECOPY + + Make sure the resulting array is a copy of the original. + +.. c:var:: NPY_ARRAY_ENSUREARRAY + + Make sure the resulting object is an actual ndarray, and not a sub-class. + +.. c:var:: NPY_ARRAY_NOTSWAPPED + + Only used in :c:func:`PyArray_CheckFromAny` to over-ride the byteorder + of the data-type object passed in. + +.. c:var:: NPY_ARRAY_BEHAVED_NS + + :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE` \| :c:data:`NPY_ARRAY_NOTSWAPPED` + + +Flag checking +^^^^^^^^^^^^^ + +For all of these macros *arr* must be an instance of a (subclass of) +:c:data:`PyArray_Type`, but no checking is done. + +.. c:function:: PyArray_CHKFLAGS(arr, flags) + + The first parameter, arr, must be an ndarray or subclass. The + parameter, *flags*, should be an integer consisting of bitwise + combinations of the possible flags an array can have: + :c:data:`NPY_ARRAY_C_CONTIGUOUS`, :c:data:`NPY_ARRAY_F_CONTIGUOUS`, + :c:data:`NPY_ARRAY_OWNDATA`, :c:data:`NPY_ARRAY_ALIGNED`, + :c:data:`NPY_ARRAY_WRITEABLE`, :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`, + :c:data:`NPY_ARRAY_UPDATEIFCOPY`. + +.. c:function:: PyArray_IS_C_CONTIGUOUS(arr) + + Evaluates true if *arr* is C-style contiguous. + +.. c:function:: PyArray_IS_F_CONTIGUOUS(arr) + + Evaluates true if *arr* is Fortran-style contiguous. + +.. c:function:: PyArray_ISFORTRAN(arr) + + Evaluates true if *arr* is Fortran-style contiguous and *not* + C-style contiguous. :c:func:`PyArray_IS_F_CONTIGUOUS` + is the correct way to test for Fortran-style contiguity. + +.. c:function:: PyArray_ISWRITEABLE(arr) + + Evaluates true if the data area of *arr* can be written to + +.. c:function:: PyArray_ISALIGNED(arr) + + Evaluates true if the data area of *arr* is properly aligned on + the machine. + +.. c:function:: PyArray_ISBEHAVED(arr) + + Evaluates true if the data area of *arr* is aligned and writeable + and in machine byte-order according to its descriptor. + +.. c:function:: PyArray_ISBEHAVED_RO(arr) + + Evaluates true if the data area of *arr* is aligned and in machine + byte-order. + +.. c:function:: PyArray_ISCARRAY(arr) + + Evaluates true if the data area of *arr* is C-style contiguous, + and :c:func:`PyArray_ISBEHAVED` (*arr*) is true. + +.. c:function:: PyArray_ISFARRAY(arr) + + Evaluates true if the data area of *arr* is Fortran-style + contiguous and :c:func:`PyArray_ISBEHAVED` (*arr*) is true. + +.. c:function:: PyArray_ISCARRAY_RO(arr) + + Evaluates true if the data area of *arr* is C-style contiguous, + aligned, and in machine byte-order. + +.. c:function:: PyArray_ISFARRAY_RO(arr) + + Evaluates true if the data area of *arr* is Fortran-style + contiguous, aligned, and in machine byte-order **.** + +.. c:function:: PyArray_ISONESEGMENT(arr) + + Evaluates true if the data area of *arr* consists of a single + (C-style or Fortran-style) contiguous segment. + +.. c:function:: void PyArray_UpdateFlags(PyArrayObject* arr, int flagmask) + + The :c:data:`NPY_ARRAY_C_CONTIGUOUS`, :c:data:`NPY_ARRAY_ALIGNED`, and + :c:data:`NPY_ARRAY_F_CONTIGUOUS` array flags can be "calculated" from the + array object itself. This routine updates one or more of these + flags of *arr* as specified in *flagmask* by performing the + required calculation. + + +.. warning:: + + It is important to keep the flags updated (using + :c:func:`PyArray_UpdateFlags` can help) whenever a manipulation with an + array is performed that might cause them to change. Later + calculations in NumPy that rely on the state of these flags do not + repeat the calculation to update them. + + +Array method alternative API +---------------------------- + + +Conversion +^^^^^^^^^^ + +.. c:function:: PyObject* PyArray_GetField( \ + PyArrayObject* self, PyArray_Descr* dtype, int offset) + + Equivalent to :meth:`ndarray.getfield` (*self*, *dtype*, *offset*). Return + a new array of the given *dtype* using the data in the current + array at a specified *offset* in bytes. The *offset* plus the + itemsize of the new array type must be less than *self* + ->descr->elsize or an error is raised. The same shape and strides + as the original array are used. Therefore, this function has the + effect of returning a field from a structured array. But, it can also + be used to select specific bytes or groups of bytes from any array + type. + +.. c:function:: int PyArray_SetField( \ + PyArrayObject* self, PyArray_Descr* dtype, int offset, PyObject* val) + + Equivalent to :meth:`ndarray.setfield` (*self*, *val*, *dtype*, *offset* + ). Set the field starting at *offset* in bytes and of the given + *dtype* to *val*. The *offset* plus *dtype* ->elsize must be less + than *self* ->descr->elsize or an error is raised. Otherwise, the + *val* argument is converted to an array and copied into the field + pointed to. If necessary, the elements of *val* are repeated to + fill the destination array, But, the number of elements in the + destination must be an integer multiple of the number of elements + in *val*. + +.. c:function:: PyObject* PyArray_Byteswap(PyArrayObject* self, Bool inplace) + + Equivalent to :meth:`ndarray.byteswap` (*self*, *inplace*). Return an array + whose data area is byteswapped. If *inplace* is non-zero, then do + the byteswap inplace and return a reference to self. Otherwise, + create a byteswapped copy and leave self unchanged. + +.. c:function:: PyObject* PyArray_NewCopy(PyArrayObject* old, NPY_ORDER order) + + Equivalent to :meth:`ndarray.copy` (*self*, *fortran*). Make a copy of the + *old* array. The returned array is always aligned and writeable + with data interpreted the same as the old array. If *order* is + :c:data:`NPY_CORDER`, then a C-style contiguous array is returned. If + *order* is :c:data:`NPY_FORTRANORDER`, then a Fortran-style contiguous + array is returned. If *order is* :c:data:`NPY_ANYORDER`, then the array + returned is Fortran-style contiguous only if the old one is; + otherwise, it is C-style contiguous. + +.. c:function:: PyObject* PyArray_ToList(PyArrayObject* self) + + Equivalent to :meth:`ndarray.tolist` (*self*). Return a nested Python list + from *self*. + +.. c:function:: PyObject* PyArray_ToString(PyArrayObject* self, NPY_ORDER order) + + Equivalent to :meth:`ndarray.tobytes` (*self*, *order*). Return the bytes + of this array in a Python string. + +.. c:function:: PyObject* PyArray_ToFile( \ + PyArrayObject* self, FILE* fp, char* sep, char* format) + + Write the contents of *self* to the file pointer *fp* in C-style + contiguous fashion. Write the data as binary bytes if *sep* is the + string ""or ``NULL``. Otherwise, write the contents of *self* as + text using the *sep* string as the item separator. Each item will + be printed to the file. If the *format* string is not ``NULL`` or + "", then it is a Python print statement format string showing how + the items are to be written. + +.. c:function:: int PyArray_Dump(PyObject* self, PyObject* file, int protocol) + + Pickle the object in *self* to the given *file* (either a string + or a Python file object). If *file* is a Python string it is + considered to be the name of a file which is then opened in binary + mode. The given *protocol* is used (if *protocol* is negative, or + the highest available is used). This is a simple wrapper around + cPickle.dump(*self*, *file*, *protocol*). + +.. c:function:: PyObject* PyArray_Dumps(PyObject* self, int protocol) + + Pickle the object in *self* to a Python string and return it. Use + the Pickle *protocol* provided (or the highest available if + *protocol* is negative). + +.. c:function:: int PyArray_FillWithScalar(PyArrayObject* arr, PyObject* obj) + + Fill the array, *arr*, with the given scalar object, *obj*. The + object is first converted to the data type of *arr*, and then + copied into every location. A -1 is returned if an error occurs, + otherwise 0 is returned. + +.. c:function:: PyObject* PyArray_View( \ + PyArrayObject* self, PyArray_Descr* dtype, PyTypeObject *ptype) + + Equivalent to :meth:`ndarray.view` (*self*, *dtype*). Return a new + view of the array *self* as possibly a different data-type, *dtype*, + and different array subclass *ptype*. + + If *dtype* is ``NULL``, then the returned array will have the same + data type as *self*. The new data-type must be consistent with the + size of *self*. Either the itemsizes must be identical, or *self* must + be single-segment and the total number of bytes must be the same. + In the latter case the dimensions of the returned array will be + altered in the last (or first for Fortran-style contiguous arrays) + dimension. The data area of the returned array and self is exactly + the same. + + +Shape Manipulation +^^^^^^^^^^^^^^^^^^ + +.. c:function:: PyObject* PyArray_Newshape( \ + PyArrayObject* self, PyArray_Dims* newshape, NPY_ORDER order) + + Result will be a new array (pointing to the same memory location + as *self* if possible), but having a shape given by *newshape*. + If the new shape is not compatible with the strides of *self*, + then a copy of the array with the new specified shape will be + returned. + +.. c:function:: PyObject* PyArray_Reshape(PyArrayObject* self, PyObject* shape) + + Equivalent to :meth:`ndarray.reshape` (*self*, *shape*) where *shape* is a + sequence. Converts *shape* to a :c:type:`PyArray_Dims` structure and + calls :c:func:`PyArray_Newshape` internally. + For back-ward compatibility -- Not recommended + +.. c:function:: PyObject* PyArray_Squeeze(PyArrayObject* self) + + Equivalent to :meth:`ndarray.squeeze` (*self*). Return a new view of *self* + with all of the dimensions of length 1 removed from the shape. + +.. warning:: + + matrix objects are always 2-dimensional. Therefore, + :c:func:`PyArray_Squeeze` has no effect on arrays of matrix sub-class. + +.. c:function:: PyObject* PyArray_SwapAxes(PyArrayObject* self, int a1, int a2) + + Equivalent to :meth:`ndarray.swapaxes` (*self*, *a1*, *a2*). The returned + array is a new view of the data in *self* with the given axes, + *a1* and *a2*, swapped. + +.. c:function:: PyObject* PyArray_Resize( \ + PyArrayObject* self, PyArray_Dims* newshape, int refcheck, \ + NPY_ORDER fortran) + + Equivalent to :meth:`ndarray.resize` (*self*, *newshape*, refcheck + ``=`` *refcheck*, order= fortran ). This function only works on + single-segment arrays. It changes the shape of *self* inplace and + will reallocate the memory for *self* if *newshape* has a + different total number of elements then the old shape. If + reallocation is necessary, then *self* must own its data, have + *self* - ``>base==NULL``, have *self* - ``>weakrefs==NULL``, and + (unless refcheck is 0) not be referenced by any other array. + The fortran argument can be :c:data:`NPY_ANYORDER`, :c:data:`NPY_CORDER`, + or :c:data:`NPY_FORTRANORDER`. It currently has no effect. Eventually + it could be used to determine how the resize operation should view + the data when constructing a differently-dimensioned array. + Returns None on success and NULL on error. + +.. c:function:: PyObject* PyArray_Transpose( \ + PyArrayObject* self, PyArray_Dims* permute) + + Equivalent to :meth:`ndarray.transpose` (*self*, *permute*). Permute the + axes of the ndarray object *self* according to the data structure + *permute* and return the result. If *permute* is ``NULL``, then + the resulting array has its axes reversed. For example if *self* + has shape :math:`10\times20\times30`, and *permute* ``.ptr`` is + (0,2,1) the shape of the result is :math:`10\times30\times20.` If + *permute* is ``NULL``, the shape of the result is + :math:`30\times20\times10.` + +.. c:function:: PyObject* PyArray_Flatten(PyArrayObject* self, NPY_ORDER order) + + Equivalent to :meth:`ndarray.flatten` (*self*, *order*). Return a 1-d copy + of the array. If *order* is :c:data:`NPY_FORTRANORDER` the elements are + scanned out in Fortran order (first-dimension varies the + fastest). If *order* is :c:data:`NPY_CORDER`, the elements of ``self`` + are scanned in C-order (last dimension varies the fastest). If + *order* :c:data:`NPY_ANYORDER`, then the result of + :c:func:`PyArray_ISFORTRAN` (*self*) is used to determine which order + to flatten. + +.. c:function:: PyObject* PyArray_Ravel(PyArrayObject* self, NPY_ORDER order) + + Equivalent to *self*.ravel(*order*). Same basic functionality + as :c:func:`PyArray_Flatten` (*self*, *order*) except if *order* is 0 + and *self* is C-style contiguous, the shape is altered but no copy + is performed. + + +Item selection and manipulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. c:function:: PyObject* PyArray_TakeFrom( \ + PyArrayObject* self, PyObject* indices, int axis, PyArrayObject* ret, \ + NPY_CLIPMODE clipmode) + + Equivalent to :meth:`ndarray.take` (*self*, *indices*, *axis*, *ret*, + *clipmode*) except *axis* =None in Python is obtained by setting + *axis* = :c:data:`NPY_MAXDIMS` in C. Extract the items from self + indicated by the integer-valued *indices* along the given *axis.* + The clipmode argument can be :c:data:`NPY_RAISE`, :c:data:`NPY_WRAP`, or + :c:data:`NPY_CLIP` to indicate what to do with out-of-bound indices. The + *ret* argument can specify an output array rather than having one + created internally. + +.. c:function:: PyObject* PyArray_PutTo( \ + PyArrayObject* self, PyObject* values, PyObject* indices, \ + NPY_CLIPMODE clipmode) + + Equivalent to *self*.put(*values*, *indices*, *clipmode* + ). Put *values* into *self* at the corresponding (flattened) + *indices*. If *values* is too small it will be repeated as + necessary. + +.. c:function:: PyObject* PyArray_PutMask( \ + PyArrayObject* self, PyObject* values, PyObject* mask) + + Place the *values* in *self* wherever corresponding positions + (using a flattened context) in *mask* are true. The *mask* and + *self* arrays must have the same total number of elements. If + *values* is too small, it will be repeated as necessary. + +.. c:function:: PyObject* PyArray_Repeat( \ + PyArrayObject* self, PyObject* op, int axis) + + Equivalent to :meth:`ndarray.repeat` (*self*, *op*, *axis*). Copy the + elements of *self*, *op* times along the given *axis*. Either + *op* is a scalar integer or a sequence of length *self* + ->dimensions[ *axis* ] indicating how many times to repeat each + item along the axis. + +.. c:function:: PyObject* PyArray_Choose( \ + PyArrayObject* self, PyObject* op, PyArrayObject* ret, \ + NPY_CLIPMODE clipmode) + + Equivalent to :meth:`ndarray.choose` (*self*, *op*, *ret*, *clipmode*). + Create a new array by selecting elements from the sequence of + arrays in *op* based on the integer values in *self*. The arrays + must all be broadcastable to the same shape and the entries in + *self* should be between 0 and len(*op*). The output is placed + in *ret* unless it is ``NULL`` in which case a new output is + created. The *clipmode* argument determines behavior for when + entries in *self* are not between 0 and len(*op*). + + .. c:var:: NPY_RAISE + + raise a ValueError; + + .. c:var:: NPY_WRAP + + wrap values < 0 by adding len(*op*) and values >=len(*op*) + by subtracting len(*op*) until they are in range; + + .. c:var:: NPY_CLIP + + all values are clipped to the region [0, len(*op*) ). + + +.. c:function:: PyObject* PyArray_Sort(PyArrayObject* self, int axis) + + Equivalent to :meth:`ndarray.sort` (*self*, *axis*). Return an array with + the items of *self* sorted along *axis*. + +.. c:function:: PyObject* PyArray_ArgSort(PyArrayObject* self, int axis) + + Equivalent to :meth:`ndarray.argsort` (*self*, *axis*). Return an array of + indices such that selection of these indices along the given + ``axis`` would return a sorted version of *self*. If *self* + ->descr is a data-type with fields defined, then + self->descr->names is used to determine the sort order. A + comparison where the first field is equal will use the second + field and so on. To alter the sort order of a structured array, create + a new data-type with a different order of names and construct a + view of the array with that new data-type. + +.. c:function:: PyObject* PyArray_LexSort(PyObject* sort_keys, int axis) + + Given a sequence of arrays (*sort_keys*) of the same shape, + return an array of indices (similar to :c:func:`PyArray_ArgSort` (...)) + that would sort the arrays lexicographically. A lexicographic sort + specifies that when two keys are found to be equal, the order is + based on comparison of subsequent keys. A merge sort (which leaves + equal entries unmoved) is required to be defined for the + types. The sort is accomplished by sorting the indices first using + the first *sort_key* and then using the second *sort_key* and so + forth. This is equivalent to the lexsort(*sort_keys*, *axis*) + Python command. Because of the way the merge-sort works, be sure + to understand the order the *sort_keys* must be in (reversed from + the order you would use when comparing two elements). + + If these arrays are all collected in a structured array, then + :c:func:`PyArray_Sort` (...) can also be used to sort the array + directly. + +.. c:function:: PyObject* PyArray_SearchSorted( \ + PyArrayObject* self, PyObject* values, NPY_SEARCHSIDE side, \ + PyObject* perm) + + Equivalent to :meth:`ndarray.searchsorted` (*self*, *values*, *side*, + *perm*). Assuming *self* is a 1-d array in ascending order, then the + output is an array of indices the same shape as *values* such that, if + the elements in *values* were inserted before the indices, the order of + *self* would be preserved. No checking is done on whether or not self is + in ascending order. + + The *side* argument indicates whether the index returned should be that of + the first suitable location (if :c:data:`NPY_SEARCHLEFT`) or of the last + (if :c:data:`NPY_SEARCHRIGHT`). + + The *sorter* argument, if not ``NULL``, must be a 1D array of integer + indices the same length as *self*, that sorts it into ascending order. + This is typically the result of a call to :c:func:`PyArray_ArgSort` (...) + Binary search is used to find the required insertion points. + +.. c:function:: int PyArray_Partition( \ + PyArrayObject *self, PyArrayObject * ktharray, int axis, \ + NPY_SELECTKIND which) + + Equivalent to :meth:`ndarray.partition` (*self*, *ktharray*, *axis*, + *kind*). Partitions the array so that the values of the element indexed by + *ktharray* are in the positions they would be if the array is fully sorted + and places all elements smaller than the kth before and all elements equal + or greater after the kth element. The ordering of all elements within the + partitions is undefined. + If *self*->descr is a data-type with fields defined, then + self->descr->names is used to determine the sort order. A comparison where + the first field is equal will use the second field and so on. To alter the + sort order of a structured array, create a new data-type with a different + order of names and construct a view of the array with that new data-type. + Returns zero on success and -1 on failure. + +.. c:function:: PyObject* PyArray_ArgPartition( \ + PyArrayObject *op, PyArrayObject * ktharray, int axis, \ + NPY_SELECTKIND which) + + Equivalent to :meth:`ndarray.argpartition` (*self*, *ktharray*, *axis*, + *kind*). Return an array of indices such that selection of these indices + along the given ``axis`` would return a partitioned version of *self*. + +.. c:function:: PyObject* PyArray_Diagonal( \ + PyArrayObject* self, int offset, int axis1, int axis2) + + Equivalent to :meth:`ndarray.diagonal` (*self*, *offset*, *axis1*, *axis2* + ). Return the *offset* diagonals of the 2-d arrays defined by + *axis1* and *axis2*. + +.. c:function:: npy_intp PyArray_CountNonzero(PyArrayObject* self) + + .. versionadded:: 1.6 + + Counts the number of non-zero elements in the array object *self*. + +.. c:function:: PyObject* PyArray_Nonzero(PyArrayObject* self) + + Equivalent to :meth:`ndarray.nonzero` (*self*). Returns a tuple of index + arrays that select elements of *self* that are nonzero. If (nd= + :c:func:`PyArray_NDIM` ( ``self`` ))==1, then a single index array is + returned. The index arrays have data type :c:data:`NPY_INTP`. If a + tuple is returned (nd :math:`\neq` 1), then its length is nd. + +.. c:function:: PyObject* PyArray_Compress( \ + PyArrayObject* self, PyObject* condition, int axis, PyArrayObject* out) + + Equivalent to :meth:`ndarray.compress` (*self*, *condition*, *axis* + ). Return the elements along *axis* corresponding to elements of + *condition* that are true. + + +Calculation +^^^^^^^^^^^ + +.. tip:: + + Pass in :c:data:`NPY_MAXDIMS` for axis in order to achieve the same + effect that is obtained by passing in *axis* = :const:`None` in Python + (treating the array as a 1-d array). + +.. c:function:: PyObject* PyArray_ArgMax( \ + PyArrayObject* self, int axis, PyArrayObject* out) + + Equivalent to :meth:`ndarray.argmax` (*self*, *axis*). Return the index of + the largest element of *self* along *axis*. + +.. c:function:: PyObject* PyArray_ArgMin( \ + PyArrayObject* self, int axis, PyArrayObject* out) + + Equivalent to :meth:`ndarray.argmin` (*self*, *axis*). Return the index of + the smallest element of *self* along *axis*. + + + + +.. note:: + + The out argument specifies where to place the result. If out is + NULL, then the output array is created, otherwise the output is + placed in out which must be the correct size and type. A new + reference to the output array is always returned even when out + is not NULL. The caller of the routine has the responsibility + to ``DECREF`` out if not NULL or a memory-leak will occur. + +.. c:function:: PyObject* PyArray_Max( \ + PyArrayObject* self, int axis, PyArrayObject* out) + + Equivalent to :meth:`ndarray.max` (*self*, *axis*). Returns the largest + element of *self* along the given *axis*. When the result is a single + element, returns a numpy scalar instead of an ndarray. + +.. c:function:: PyObject* PyArray_Min( \ + PyArrayObject* self, int axis, PyArrayObject* out) + + Equivalent to :meth:`ndarray.min` (*self*, *axis*). Return the smallest + element of *self* along the given *axis*. When the result is a single + element, returns a numpy scalar instead of an ndarray. + + +.. c:function:: PyObject* PyArray_Ptp( \ + PyArrayObject* self, int axis, PyArrayObject* out) + + Equivalent to :meth:`ndarray.ptp` (*self*, *axis*). Return the difference + between the largest element of *self* along *axis* and the + smallest element of *self* along *axis*. When the result is a single + element, returns a numpy scalar instead of an ndarray. + + + + +.. note:: + + The rtype argument specifies the data-type the reduction should + take place over. This is important if the data-type of the array + is not "large" enough to handle the output. By default, all + integer data-types are made at least as large as :c:data:`NPY_LONG` + for the "add" and "multiply" ufuncs (which form the basis for + mean, sum, cumsum, prod, and cumprod functions). + +.. c:function:: PyObject* PyArray_Mean( \ + PyArrayObject* self, int axis, int rtype, PyArrayObject* out) + + Equivalent to :meth:`ndarray.mean` (*self*, *axis*, *rtype*). Returns the + mean of the elements along the given *axis*, using the enumerated + type *rtype* as the data type to sum in. Default sum behavior is + obtained using :c:data:`NPY_NOTYPE` for *rtype*. + +.. c:function:: PyObject* PyArray_Trace( \ + PyArrayObject* self, int offset, int axis1, int axis2, int rtype, \ + PyArrayObject* out) + + Equivalent to :meth:`ndarray.trace` (*self*, *offset*, *axis1*, *axis2*, + *rtype*). Return the sum (using *rtype* as the data type of + summation) over the *offset* diagonal elements of the 2-d arrays + defined by *axis1* and *axis2* variables. A positive offset + chooses diagonals above the main diagonal. A negative offset + selects diagonals below the main diagonal. + +.. c:function:: PyObject* PyArray_Clip( \ + PyArrayObject* self, PyObject* min, PyObject* max) + + Equivalent to :meth:`ndarray.clip` (*self*, *min*, *max*). Clip an array, + *self*, so that values larger than *max* are fixed to *max* and + values less than *min* are fixed to *min*. + +.. c:function:: PyObject* PyArray_Conjugate(PyArrayObject* self) + + Equivalent to :meth:`ndarray.conjugate` (*self*). + Return the complex conjugate of *self*. If *self* is not of + complex data type, then return *self* with a reference. + +.. c:function:: PyObject* PyArray_Round( \ + PyArrayObject* self, int decimals, PyArrayObject* out) + + Equivalent to :meth:`ndarray.round` (*self*, *decimals*, *out*). Returns + the array with elements rounded to the nearest decimal place. The + decimal place is defined as the :math:`10^{-\textrm{decimals}}` + digit so that negative *decimals* cause rounding to the nearest 10's, 100's, etc. If out is ``NULL``, then the output array is created, otherwise the output is placed in *out* which must be the correct size and type. + +.. c:function:: PyObject* PyArray_Std( \ + PyArrayObject* self, int axis, int rtype, PyArrayObject* out) + + Equivalent to :meth:`ndarray.std` (*self*, *axis*, *rtype*). Return the + standard deviation using data along *axis* converted to data type + *rtype*. + +.. c:function:: PyObject* PyArray_Sum( \ + PyArrayObject* self, int axis, int rtype, PyArrayObject* out) + + Equivalent to :meth:`ndarray.sum` (*self*, *axis*, *rtype*). Return 1-d + vector sums of elements in *self* along *axis*. Perform the sum + after converting data to data type *rtype*. + +.. c:function:: PyObject* PyArray_CumSum( \ + PyArrayObject* self, int axis, int rtype, PyArrayObject* out) + + Equivalent to :meth:`ndarray.cumsum` (*self*, *axis*, *rtype*). Return + cumulative 1-d sums of elements in *self* along *axis*. Perform + the sum after converting data to data type *rtype*. + +.. c:function:: PyObject* PyArray_Prod( \ + PyArrayObject* self, int axis, int rtype, PyArrayObject* out) + + Equivalent to :meth:`ndarray.prod` (*self*, *axis*, *rtype*). Return 1-d + products of elements in *self* along *axis*. Perform the product + after converting data to data type *rtype*. + +.. c:function:: PyObject* PyArray_CumProd( \ + PyArrayObject* self, int axis, int rtype, PyArrayObject* out) + + Equivalent to :meth:`ndarray.cumprod` (*self*, *axis*, *rtype*). Return + 1-d cumulative products of elements in ``self`` along ``axis``. + Perform the product after converting data to data type ``rtype``. + +.. c:function:: PyObject* PyArray_All( \ + PyArrayObject* self, int axis, PyArrayObject* out) + + Equivalent to :meth:`ndarray.all` (*self*, *axis*). Return an array with + True elements for every 1-d sub-array of ``self`` defined by + ``axis`` in which all the elements are True. + +.. c:function:: PyObject* PyArray_Any( \ + PyArrayObject* self, int axis, PyArrayObject* out) + + Equivalent to :meth:`ndarray.any` (*self*, *axis*). Return an array with + True elements for every 1-d sub-array of *self* defined by *axis* + in which any of the elements are True. + +Functions +--------- + + +Array Functions +^^^^^^^^^^^^^^^ + +.. c:function:: int PyArray_AsCArray( \ + PyObject** op, void* ptr, npy_intp* dims, int nd, int typenum, \ + int itemsize) + + Sometimes it is useful to access a multidimensional array as a + C-style multi-dimensional array so that algorithms can be + implemented using C's a[i][j][k] syntax. This routine returns a + pointer, *ptr*, that simulates this kind of C-style array, for + 1-, 2-, and 3-d ndarrays. + + :param op: + + The address to any Python object. This Python object will be replaced + with an equivalent well-behaved, C-style contiguous, ndarray of the + given data type specified by the last two arguments. Be sure that + stealing a reference in this way to the input object is justified. + + :param ptr: + + The address to a (ctype* for 1-d, ctype** for 2-d or ctype*** for 3-d) + variable where ctype is the equivalent C-type for the data type. On + return, *ptr* will be addressable as a 1-d, 2-d, or 3-d array. + + :param dims: + + An output array that contains the shape of the array object. This + array gives boundaries on any looping that will take place. + + :param nd: + + The dimensionality of the array (1, 2, or 3). + + :param typenum: + + The expected data type of the array. + + :param itemsize: + + This argument is only needed when *typenum* represents a + flexible array. Otherwise it should be 0. + +.. note:: + + The simulation of a C-style array is not complete for 2-d and 3-d + arrays. For example, the simulated arrays of pointers cannot be passed + to subroutines expecting specific, statically-defined 2-d and 3-d + arrays. To pass to functions requiring those kind of inputs, you must + statically define the required array and copy data. + +.. c:function:: int PyArray_Free(PyObject* op, void* ptr) + + Must be called with the same objects and memory locations returned + from :c:func:`PyArray_AsCArray` (...). This function cleans up memory + that otherwise would get leaked. + +.. c:function:: PyObject* PyArray_Concatenate(PyObject* obj, int axis) + + Join the sequence of objects in *obj* together along *axis* into a + single array. If the dimensions or types are not compatible an + error is raised. + +.. c:function:: PyObject* PyArray_InnerProduct(PyObject* obj1, PyObject* obj2) + + Compute a product-sum over the last dimensions of *obj1* and + *obj2*. Neither array is conjugated. + +.. c:function:: PyObject* PyArray_MatrixProduct(PyObject* obj1, PyObject* obj) + + Compute a product-sum over the last dimension of *obj1* and the + second-to-last dimension of *obj2*. For 2-d arrays this is a + matrix-product. Neither array is conjugated. + +.. c:function:: PyObject* PyArray_MatrixProduct2( \ + PyObject* obj1, PyObject* obj, PyArrayObject* out) + + .. versionadded:: 1.6 + + Same as PyArray_MatrixProduct, but store the result in *out*. The + output array must have the correct shape, type, and be + C-contiguous, or an exception is raised. + +.. c:function:: PyObject* PyArray_EinsteinSum( \ + char* subscripts, npy_intp nop, PyArrayObject** op_in, \ + PyArray_Descr* dtype, NPY_ORDER order, NPY_CASTING casting, \ + PyArrayObject* out) + + .. versionadded:: 1.6 + + Applies the Einstein summation convention to the array operands + provided, returning a new array or placing the result in *out*. + The string in *subscripts* is a comma separated list of index + letters. The number of operands is in *nop*, and *op_in* is an + array containing those operands. The data type of the output can + be forced with *dtype*, the output order can be forced with *order* + (:c:data:`NPY_KEEPORDER` is recommended), and when *dtype* is specified, + *casting* indicates how permissive the data conversion should be. + + See the :func:`~numpy.einsum` function for more details. + +.. c:function:: PyObject* PyArray_CopyAndTranspose(PyObject \* op) + + A specialized copy and transpose function that works only for 2-d + arrays. The returned array is a transposed copy of *op*. + +.. c:function:: PyObject* PyArray_Correlate( \ + PyObject* op1, PyObject* op2, int mode) + + Compute the 1-d correlation of the 1-d arrays *op1* and *op2* + . The correlation is computed at each output point by multiplying + *op1* by a shifted version of *op2* and summing the result. As a + result of the shift, needed values outside of the defined range of + *op1* and *op2* are interpreted as zero. The mode determines how + many shifts to return: 0 - return only shifts that did not need to + assume zero- values; 1 - return an object that is the same size as + *op1*, 2 - return all possible shifts (any overlap at all is + accepted). + + .. rubric:: Notes + + This does not compute the usual correlation: if op2 is larger than op1, the + arguments are swapped, and the conjugate is never taken for complex arrays. + See PyArray_Correlate2 for the usual signal processing correlation. + +.. c:function:: PyObject* PyArray_Correlate2( \ + PyObject* op1, PyObject* op2, int mode) + + Updated version of PyArray_Correlate, which uses the usual definition of + correlation for 1d arrays. The correlation is computed at each output point + by multiplying *op1* by a shifted version of *op2* and summing the result. + As a result of the shift, needed values outside of the defined range of + *op1* and *op2* are interpreted as zero. The mode determines how many + shifts to return: 0 - return only shifts that did not need to assume zero- + values; 1 - return an object that is the same size as *op1*, 2 - return all + possible shifts (any overlap at all is accepted). + + .. rubric:: Notes + + Compute z as follows:: + + z[k] = sum_n op1[n] * conj(op2[n+k]) + +.. c:function:: PyObject* PyArray_Where( \ + PyObject* condition, PyObject* x, PyObject* y) + + If both ``x`` and ``y`` are ``NULL``, then return + :c:func:`PyArray_Nonzero` (*condition*). Otherwise, both *x* and *y* + must be given and the object returned is shaped like *condition* + and has elements of *x* and *y* where *condition* is respectively + True or False. + + +Other functions +^^^^^^^^^^^^^^^ + +.. c:function:: Bool PyArray_CheckStrides( \ + int elsize, int nd, npy_intp numbytes, npy_intp* dims, \ + npy_intp* newstrides) + + Determine if *newstrides* is a strides array consistent with the + memory of an *nd* -dimensional array with shape ``dims`` and + element-size, *elsize*. The *newstrides* array is checked to see + if jumping by the provided number of bytes in each direction will + ever mean jumping more than *numbytes* which is the assumed size + of the available memory segment. If *numbytes* is 0, then an + equivalent *numbytes* is computed assuming *nd*, *dims*, and + *elsize* refer to a single-segment array. Return :c:data:`NPY_TRUE` if + *newstrides* is acceptable, otherwise return :c:data:`NPY_FALSE`. + +.. c:function:: npy_intp PyArray_MultiplyList(npy_intp* seq, int n) + +.. c:function:: int PyArray_MultiplyIntList(int* seq, int n) + + Both of these routines multiply an *n* -length array, *seq*, of + integers and return the result. No overflow checking is performed. + +.. c:function:: int PyArray_CompareLists(npy_intp* l1, npy_intp* l2, int n) + + Given two *n* -length arrays of integers, *l1*, and *l2*, return + 1 if the lists are identical; otherwise, return 0. + + +Auxiliary Data With Object Semantics +------------------------------------ + +.. versionadded:: 1.7.0 + +.. c:type:: NpyAuxData + +When working with more complex dtypes which are composed of other dtypes, +such as the struct dtype, creating inner loops that manipulate the dtypes +requires carrying along additional data. NumPy supports this idea +through a struct :c:type:`NpyAuxData`, mandating a few conventions so that +it is possible to do this. + +Defining an :c:type:`NpyAuxData` is similar to defining a class in C++, +but the object semantics have to be tracked manually since the API is in C. +Here's an example for a function which doubles up an element using +an element copier function as a primitive.:: + + typedef struct { + NpyAuxData base; + ElementCopier_Func *func; + NpyAuxData *funcdata; + } eldoubler_aux_data; + + void free_element_doubler_aux_data(NpyAuxData *data) + { + eldoubler_aux_data *d = (eldoubler_aux_data *)data; + /* Free the memory owned by this auxdata */ + NPY_AUXDATA_FREE(d->funcdata); + PyArray_free(d); + } + + NpyAuxData *clone_element_doubler_aux_data(NpyAuxData *data) + { + eldoubler_aux_data *ret = PyArray_malloc(sizeof(eldoubler_aux_data)); + if (ret == NULL) { + return NULL; + } + + /* Raw copy of all data */ + memcpy(ret, data, sizeof(eldoubler_aux_data)); + + /* Fix up the owned auxdata so we have our own copy */ + ret->funcdata = NPY_AUXDATA_CLONE(ret->funcdata); + if (ret->funcdata == NULL) { + PyArray_free(ret); + return NULL; + } + + return (NpyAuxData *)ret; + } + + NpyAuxData *create_element_doubler_aux_data( + ElementCopier_Func *func, + NpyAuxData *funcdata) + { + eldoubler_aux_data *ret = PyArray_malloc(sizeof(eldoubler_aux_data)); + if (ret == NULL) { + PyErr_NoMemory(); + return NULL; + } + memset(&ret, 0, sizeof(eldoubler_aux_data)); + ret->base->free = &free_element_doubler_aux_data; + ret->base->clone = &clone_element_doubler_aux_data; + ret->func = func; + ret->funcdata = funcdata; + + return (NpyAuxData *)ret; + } + +.. c:type:: NpyAuxData_FreeFunc + + The function pointer type for NpyAuxData free functions. + +.. c:type:: NpyAuxData_CloneFunc + + The function pointer type for NpyAuxData clone functions. These + functions should never set the Python exception on error, because + they may be called from a multi-threaded context. + +.. c:function:: NPY_AUXDATA_FREE(auxdata) + + A macro which calls the auxdata's free function appropriately, + does nothing if auxdata is NULL. + +.. c:function:: NPY_AUXDATA_CLONE(auxdata) + + A macro which calls the auxdata's clone function appropriately, + returning a deep copy of the auxiliary data. + +Array Iterators +--------------- + +As of NumPy 1.6.0, these array iterators are superceded by +the new array iterator, :c:type:`NpyIter`. + +An array iterator is a simple way to access the elements of an +N-dimensional array quickly and efficiently. Section `2 +<#sec-array-iterator>`__ provides more description and examples of +this useful approach to looping over an array. + +.. c:function:: PyObject* PyArray_IterNew(PyObject* arr) + + Return an array iterator object from the array, *arr*. This is + equivalent to *arr*. **flat**. The array iterator object makes + it easy to loop over an N-dimensional non-contiguous array in + C-style contiguous fashion. + +.. c:function:: PyObject* PyArray_IterAllButAxis(PyObject* arr, int \*axis) + + Return an array iterator that will iterate over all axes but the + one provided in *\*axis*. The returned iterator cannot be used + with :c:func:`PyArray_ITER_GOTO1D`. This iterator could be used to + write something similar to what ufuncs do wherein the loop over + the largest axis is done by a separate sub-routine. If *\*axis* is + negative then *\*axis* will be set to the axis having the smallest + stride and that axis will be used. + +.. c:function:: PyObject *PyArray_BroadcastToShape( \ + PyObject* arr, npy_intp *dimensions, int nd) + + Return an array iterator that is broadcast to iterate as an array + of the shape provided by *dimensions* and *nd*. + +.. c:function:: int PyArrayIter_Check(PyObject* op) + + Evaluates true if *op* is an array iterator (or instance of a + subclass of the array iterator type). + +.. c:function:: void PyArray_ITER_RESET(PyObject* iterator) + + Reset an *iterator* to the beginning of the array. + +.. c:function:: void PyArray_ITER_NEXT(PyObject* iterator) + + Incremement the index and the dataptr members of the *iterator* to + point to the next element of the array. If the array is not + (C-style) contiguous, also increment the N-dimensional coordinates + array. + +.. c:function:: void *PyArray_ITER_DATA(PyObject* iterator) + + A pointer to the current element of the array. + +.. c:function:: void PyArray_ITER_GOTO( \ + PyObject* iterator, npy_intp* destination) + + Set the *iterator* index, dataptr, and coordinates members to the + location in the array indicated by the N-dimensional c-array, + *destination*, which must have size at least *iterator* + ->nd_m1+1. + +.. c:function:: PyArray_ITER_GOTO1D(PyObject* iterator, npy_intp index) + + Set the *iterator* index and dataptr to the location in the array + indicated by the integer *index* which points to an element in the + C-styled flattened array. + +.. c:function:: int PyArray_ITER_NOTDONE(PyObject* iterator) + + Evaluates TRUE as long as the iterator has not looped through all of + the elements, otherwise it evaluates FALSE. + + +Broadcasting (multi-iterators) +------------------------------ + +.. c:function:: PyObject* PyArray_MultiIterNew(int num, ...) + + A simplified interface to broadcasting. This function takes the + number of arrays to broadcast and then *num* extra ( :c:type:`PyObject *` + ) arguments. These arguments are converted to arrays and iterators + are created. :c:func:`PyArray_Broadcast` is then called on the resulting + multi-iterator object. The resulting, broadcasted mult-iterator + object is then returned. A broadcasted operation can then be + performed using a single loop and using :c:func:`PyArray_MultiIter_NEXT` + (..) + +.. c:function:: void PyArray_MultiIter_RESET(PyObject* multi) + + Reset all the iterators to the beginning in a multi-iterator + object, *multi*. + +.. c:function:: void PyArray_MultiIter_NEXT(PyObject* multi) + + Advance each iterator in a multi-iterator object, *multi*, to its + next (broadcasted) element. + +.. c:function:: void *PyArray_MultiIter_DATA(PyObject* multi, int i) + + Return the data-pointer of the *i* :math:`^{\textrm{th}}` iterator + in a multi-iterator object. + +.. c:function:: void PyArray_MultiIter_NEXTi(PyObject* multi, int i) + + Advance the pointer of only the *i* :math:`^{\textrm{th}}` iterator. + +.. c:function:: void PyArray_MultiIter_GOTO( \ + PyObject* multi, npy_intp* destination) + + Advance each iterator in a multi-iterator object, *multi*, to the + given :math:`N` -dimensional *destination* where :math:`N` is the + number of dimensions in the broadcasted array. + +.. c:function:: void PyArray_MultiIter_GOTO1D(PyObject* multi, npy_intp index) + + Advance each iterator in a multi-iterator object, *multi*, to the + corresponding location of the *index* into the flattened + broadcasted array. + +.. c:function:: int PyArray_MultiIter_NOTDONE(PyObject* multi) + + Evaluates TRUE as long as the multi-iterator has not looped + through all of the elements (of the broadcasted result), otherwise + it evaluates FALSE. + +.. c:function:: int PyArray_Broadcast(PyArrayMultiIterObject* mit) + + This function encapsulates the broadcasting rules. The *mit* + container should already contain iterators for all the arrays that + need to be broadcast. On return, these iterators will be adjusted + so that iteration over each simultaneously will accomplish the + broadcasting. A negative number is returned if an error occurs. + +.. c:function:: int PyArray_RemoveSmallest(PyArrayMultiIterObject* mit) + + This function takes a multi-iterator object that has been + previously "broadcasted," finds the dimension with the smallest + "sum of strides" in the broadcasted result and adapts all the + iterators so as not to iterate over that dimension (by effectively + making them of length-1 in that dimension). The corresponding + dimension is returned unless *mit* ->nd is 0, then -1 is + returned. This function is useful for constructing ufunc-like + routines that broadcast their inputs correctly and then call a + strided 1-d version of the routine as the inner-loop. This 1-d + version is usually optimized for speed and for this reason the + loop should be performed over the axis that won't require large + stride jumps. + +Neighborhood iterator +--------------------- + +.. versionadded:: 1.4.0 + +Neighborhood iterators are subclasses of the iterator object, and can be used +to iter over a neighborhood of a point. For example, you may want to iterate +over every voxel of a 3d image, and for every such voxel, iterate over an +hypercube. Neighborhood iterator automatically handle boundaries, thus making +this kind of code much easier to write than manual boundaries handling, at the +cost of a slight overhead. + +.. c:function:: PyObject* PyArray_NeighborhoodIterNew( \ + PyArrayIterObject* iter, npy_intp bounds, int mode, \ + PyArrayObject* fill_value) + + This function creates a new neighborhood iterator from an existing + iterator. The neighborhood will be computed relatively to the position + currently pointed by *iter*, the bounds define the shape of the + neighborhood iterator, and the mode argument the boundaries handling mode. + + The *bounds* argument is expected to be a (2 * iter->ao->nd) arrays, such + as the range bound[2*i]->bounds[2*i+1] defines the range where to walk for + dimension i (both bounds are included in the walked coordinates). The + bounds should be ordered for each dimension (bounds[2*i] <= bounds[2*i+1]). + + The mode should be one of: + + * NPY_NEIGHBORHOOD_ITER_ZERO_PADDING: zero padding. Outside bounds values + will be 0. + * NPY_NEIGHBORHOOD_ITER_ONE_PADDING: one padding, Outside bounds values + will be 1. + * NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING: constant padding. Outside bounds + values will be the same as the first item in fill_value. + * NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING: mirror padding. Outside bounds + values will be as if the array items were mirrored. For example, for the + array [1, 2, 3, 4], x[-2] will be 2, x[-2] will be 1, x[4] will be 4, + x[5] will be 1, etc... + * NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING: circular padding. Outside bounds + values will be as if the array was repeated. For example, for the + array [1, 2, 3, 4], x[-2] will be 3, x[-2] will be 4, x[4] will be 1, + x[5] will be 2, etc... + + If the mode is constant filling (NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING), + fill_value should point to an array object which holds the filling value + (the first item will be the filling value if the array contains more than + one item). For other cases, fill_value may be NULL. + + - The iterator holds a reference to iter + - Return NULL on failure (in which case the reference count of iter is not + changed) + - iter itself can be a Neighborhood iterator: this can be useful for .e.g + automatic boundaries handling + - the object returned by this function should be safe to use as a normal + iterator + - If the position of iter is changed, any subsequent call to + PyArrayNeighborhoodIter_Next is undefined behavior, and + PyArrayNeighborhoodIter_Reset must be called. + + .. code-block:: c + + PyArrayIterObject \*iter; + PyArrayNeighborhoodIterObject \*neigh_iter; + iter = PyArray_IterNew(x); + + //For a 3x3 kernel + bounds = {-1, 1, -1, 1}; + neigh_iter = (PyArrayNeighborhoodIterObject*)PyArrayNeighborhoodIter_New( + iter, bounds, NPY_NEIGHBORHOOD_ITER_ZERO_PADDING, NULL); + + for(i = 0; i < iter->size; ++i) { + for (j = 0; j < neigh_iter->size; ++j) { + // Walk around the item currently pointed by iter->dataptr + PyArrayNeighborhoodIter_Next(neigh_iter); + } + + // Move to the next point of iter + PyArrayIter_Next(iter); + PyArrayNeighborhoodIter_Reset(neigh_iter); + } + +.. c:function:: int PyArrayNeighborhoodIter_Reset( \ + PyArrayNeighborhoodIterObject* iter) + + Reset the iterator position to the first point of the neighborhood. This + should be called whenever the iter argument given at + PyArray_NeighborhoodIterObject is changed (see example) + +.. c:function:: int PyArrayNeighborhoodIter_Next( \ + PyArrayNeighborhoodIterObject* iter) + + After this call, iter->dataptr points to the next point of the + neighborhood. Calling this function after every point of the + neighborhood has been visited is undefined. + +Array Scalars +------------- + +.. c:function:: PyObject* PyArray_Return(PyArrayObject* arr) + + This function steals a reference to *arr*. + + This function checks to see if *arr* is a 0-dimensional array and, + if so, returns the appropriate array scalar. It should be used + whenever 0-dimensional arrays could be returned to Python. + +.. c:function:: PyObject* PyArray_Scalar( \ + void* data, PyArray_Descr* dtype, PyObject* itemsize) + + Return an array scalar object of the given enumerated *typenum* + and *itemsize* by **copying** from memory pointed to by *data* + . If *swap* is nonzero then this function will byteswap the data + if appropriate to the data-type because array scalars are always + in correct machine-byte order. + +.. c:function:: PyObject* PyArray_ToScalar(void* data, PyArrayObject* arr) + + Return an array scalar object of the type and itemsize indicated + by the array object *arr* copied from the memory pointed to by + *data* and swapping if the data in *arr* is not in machine + byte-order. + +.. c:function:: PyObject* PyArray_FromScalar( \ + PyObject* scalar, PyArray_Descr* outcode) + + Return a 0-dimensional array of type determined by *outcode* from + *scalar* which should be an array-scalar object. If *outcode* is + NULL, then the type is determined from *scalar*. + +.. c:function:: void PyArray_ScalarAsCtype(PyObject* scalar, void* ctypeptr) + + Return in *ctypeptr* a pointer to the actual value in an array + scalar. There is no error checking so *scalar* must be an + array-scalar object, and ctypeptr must have enough space to hold + the correct type. For flexible-sized types, a pointer to the data + is copied into the memory of *ctypeptr*, for all other types, the + actual data is copied into the address pointed to by *ctypeptr*. + +.. c:function:: void PyArray_CastScalarToCtype( \ + PyObject* scalar, void* ctypeptr, PyArray_Descr* outcode) + + Return the data (cast to the data type indicated by *outcode*) + from the array-scalar, *scalar*, into the memory pointed to by + *ctypeptr* (which must be large enough to handle the incoming + memory). + +.. c:function:: PyObject* PyArray_TypeObjectFromType(int type) + + Returns a scalar type-object from a type-number, *type* + . Equivalent to :c:func:`PyArray_DescrFromType` (*type*)->typeobj + except for reference counting and error-checking. Returns a new + reference to the typeobject on success or ``NULL`` on failure. + +.. c:function:: NPY_SCALARKIND PyArray_ScalarKind( \ + int typenum, PyArrayObject** arr) + + See the function :c:func:`PyArray_MinScalarType` for an alternative + mechanism introduced in NumPy 1.6.0. + + Return the kind of scalar represented by *typenum* and the array + in *\*arr* (if *arr* is not ``NULL`` ). The array is assumed to be + rank-0 and only used if *typenum* represents a signed integer. If + *arr* is not ``NULL`` and the first element is negative then + :c:data:`NPY_INTNEG_SCALAR` is returned, otherwise + :c:data:`NPY_INTPOS_SCALAR` is returned. The possible return values + are :c:data:`NPY_{kind}_SCALAR` where ``{kind}`` can be **INTPOS**, + **INTNEG**, **FLOAT**, **COMPLEX**, **BOOL**, or **OBJECT**. + :c:data:`NPY_NOSCALAR` is also an enumerated value + :c:type:`NPY_SCALARKIND` variables can take on. + +.. c:function:: int PyArray_CanCoerceScalar( \ + char thistype, char neededtype, NPY_SCALARKIND scalar) + + See the function :c:func:`PyArray_ResultType` for details of + NumPy type promotion, updated in NumPy 1.6.0. + + Implements the rules for scalar coercion. Scalars are only + silently coerced from thistype to neededtype if this function + returns nonzero. If scalar is :c:data:`NPY_NOSCALAR`, then this + function is equivalent to :c:func:`PyArray_CanCastSafely`. The rule is + that scalars of the same KIND can be coerced into arrays of the + same KIND. This rule means that high-precision scalars will never + cause low-precision arrays of the same KIND to be upcast. + + +Data-type descriptors +--------------------- + + + +.. warning:: + + Data-type objects must be reference counted so be aware of the + action on the data-type reference of different C-API calls. The + standard rule is that when a data-type object is returned it is a + new reference. Functions that take :c:type:`PyArray_Descr *` objects and + return arrays steal references to the data-type their inputs + unless otherwise noted. Therefore, you must own a reference to any + data-type object used as input to such a function. + +.. c:function:: int PyArray_DescrCheck(PyObject* obj) + + Evaluates as true if *obj* is a data-type object ( :c:type:`PyArray_Descr *` ). + +.. c:function:: PyArray_Descr* PyArray_DescrNew(PyArray_Descr* obj) + + Return a new data-type object copied from *obj* (the fields + reference is just updated so that the new object points to the + same fields dictionary if any). + +.. c:function:: PyArray_Descr* PyArray_DescrNewFromType(int typenum) + + Create a new data-type object from the built-in (or + user-registered) data-type indicated by *typenum*. All builtin + types should not have any of their fields changed. This creates a + new copy of the :c:type:`PyArray_Descr` structure so that you can fill + it in as appropriate. This function is especially needed for + flexible data-types which need to have a new elsize member in + order to be meaningful in array construction. + +.. c:function:: PyArray_Descr* PyArray_DescrNewByteorder( \ + PyArray_Descr* obj, char newendian) + + Create a new data-type object with the byteorder set according to + *newendian*. All referenced data-type objects (in subdescr and + fields members of the data-type object) are also changed + (recursively). If a byteorder of :c:data:`NPY_IGNORE` is encountered it + is left alone. If newendian is :c:data:`NPY_SWAP`, then all byte-orders + are swapped. Other valid newendian values are :c:data:`NPY_NATIVE`, + :c:data:`NPY_LITTLE`, and :c:data:`NPY_BIG` which all cause the returned + data-typed descriptor (and all it's + referenced data-type descriptors) to have the corresponding byte- + order. + +.. c:function:: PyArray_Descr* PyArray_DescrFromObject( \ + PyObject* op, PyArray_Descr* mintype) + + Determine an appropriate data-type object from the object *op* + (which should be a "nested" sequence object) and the minimum + data-type descriptor mintype (which can be ``NULL`` ). Similar in + behavior to array(*op*).dtype. Don't confuse this function with + :c:func:`PyArray_DescrConverter`. This function essentially looks at + all the objects in the (nested) sequence and determines the + data-type from the elements it finds. + +.. c:function:: PyArray_Descr* PyArray_DescrFromScalar(PyObject* scalar) + + Return a data-type object from an array-scalar object. No checking + is done to be sure that *scalar* is an array scalar. If no + suitable data-type can be determined, then a data-type of + :c:data:`NPY_OBJECT` is returned by default. + +.. c:function:: PyArray_Descr* PyArray_DescrFromType(int typenum) + + Returns a data-type object corresponding to *typenum*. The + *typenum* can be one of the enumerated types, a character code for + one of the enumerated types, or a user-defined type. + +.. c:function:: int PyArray_DescrConverter(PyObject* obj, PyArray_Descr** dtype) + + Convert any compatible Python object, *obj*, to a data-type object + in *dtype*. A large number of Python objects can be converted to + data-type objects. See :ref:`arrays.dtypes` for a complete + description. This version of the converter converts None objects + to a :c:data:`NPY_DEFAULT_TYPE` data-type object. This function can + be used with the "O&" character code in :c:func:`PyArg_ParseTuple` + processing. + +.. c:function:: int PyArray_DescrConverter2( \ + PyObject* obj, PyArray_Descr** dtype) + + Convert any compatible Python object, *obj*, to a data-type + object in *dtype*. This version of the converter converts None + objects so that the returned data-type is ``NULL``. This function + can also be used with the "O&" character in PyArg_ParseTuple + processing. + +.. c:function:: int Pyarray_DescrAlignConverter( \ + PyObject* obj, PyArray_Descr** dtype) + + Like :c:func:`PyArray_DescrConverter` except it aligns C-struct-like + objects on word-boundaries as the compiler would. + +.. c:function:: int Pyarray_DescrAlignConverter2( \ + PyObject* obj, PyArray_Descr** dtype) + + Like :c:func:`PyArray_DescrConverter2` except it aligns C-struct-like + objects on word-boundaries as the compiler would. + +.. c:function:: PyObject *PyArray_FieldNames(PyObject* dict) + + Take the fields dictionary, *dict*, such as the one attached to a + data-type object and construct an ordered-list of field names such + as is stored in the names field of the :c:type:`PyArray_Descr` object. + + +Conversion Utilities +-------------------- + + +For use with :c:func:`PyArg_ParseTuple` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All of these functions can be used in :c:func:`PyArg_ParseTuple` (...) with +the "O&" format specifier to automatically convert any Python object +to the required C-object. All of these functions return +:c:data:`NPY_SUCCEED` if successful and :c:data:`NPY_FAIL` if not. The first +argument to all of these function is a Python object. The second +argument is the **address** of the C-type to convert the Python object +to. + + +.. warning:: + + Be sure to understand what steps you should take to manage the + memory when using these conversion functions. These functions can + require freeing memory, and/or altering the reference counts of + specific objects based on your use. + +.. c:function:: int PyArray_Converter(PyObject* obj, PyObject** address) + + Convert any Python object to a :c:type:`PyArrayObject`. If + :c:func:`PyArray_Check` (*obj*) is TRUE then its reference count is + incremented and a reference placed in *address*. If *obj* is not + an array, then convert it to an array using :c:func:`PyArray_FromAny` + . No matter what is returned, you must DECREF the object returned + by this routine in *address* when you are done with it. + +.. c:function:: int PyArray_OutputConverter( \ + PyObject* obj, PyArrayObject** address) + + This is a default converter for output arrays given to + functions. If *obj* is :c:data:`Py_None` or ``NULL``, then *\*address* + will be ``NULL`` but the call will succeed. If :c:func:`PyArray_Check` ( + *obj*) is TRUE then it is returned in *\*address* without + incrementing its reference count. + +.. c:function:: int PyArray_IntpConverter(PyObject* obj, PyArray_Dims* seq) + + Convert any Python sequence, *obj*, smaller than :c:data:`NPY_MAXDIMS` + to a C-array of :c:type:`npy_intp`. The Python object could also be a + single number. The *seq* variable is a pointer to a structure with + members ptr and len. On successful return, *seq* ->ptr contains a + pointer to memory that must be freed, by calling :c:func:`PyDimMem_FREE`, + to avoid a memory leak. The restriction on memory size allows this + converter to be conveniently used for sequences intended to be + interpreted as array shapes. + +.. c:function:: int PyArray_BufferConverter(PyObject* obj, PyArray_Chunk* buf) + + Convert any Python object, *obj*, with a (single-segment) buffer + interface to a variable with members that detail the object's use + of its chunk of memory. The *buf* variable is a pointer to a + structure with base, ptr, len, and flags members. The + :c:type:`PyArray_Chunk` structure is binary compatible with the + Python's buffer object (through its len member on 32-bit platforms + and its ptr member on 64-bit platforms or in Python 2.5). On + return, the base member is set to *obj* (or its base if *obj* is + already a buffer object pointing to another object). If you need + to hold on to the memory be sure to INCREF the base member. The + chunk of memory is pointed to by *buf* ->ptr member and has length + *buf* ->len. The flags member of *buf* is :c:data:`NPY_BEHAVED_RO` with + the :c:data:`NPY_ARRAY_WRITEABLE` flag set if *obj* has a writeable buffer + interface. + +.. c:function:: int PyArray_AxisConverter(PyObject \* obj, int* axis) + + Convert a Python object, *obj*, representing an axis argument to + the proper value for passing to the functions that take an integer + axis. Specifically, if *obj* is None, *axis* is set to + :c:data:`NPY_MAXDIMS` which is interpreted correctly by the C-API + functions that take axis arguments. + +.. c:function:: int PyArray_BoolConverter(PyObject* obj, Bool* value) + + Convert any Python object, *obj*, to :c:data:`NPY_TRUE` or + :c:data:`NPY_FALSE`, and place the result in *value*. + +.. c:function:: int PyArray_ByteorderConverter(PyObject* obj, char* endian) + + Convert Python strings into the corresponding byte-order + character: + '>', '<', 's', '=', or '\|'. + +.. c:function:: int PyArray_SortkindConverter(PyObject* obj, NPY_SORTKIND* sort) + + Convert Python strings into one of :c:data:`NPY_QUICKSORT` (starts + with 'q' or 'Q') , :c:data:`NPY_HEAPSORT` (starts with 'h' or 'H'), + or :c:data:`NPY_MERGESORT` (starts with 'm' or 'M'). + +.. c:function:: int PyArray_SearchsideConverter( \ + PyObject* obj, NPY_SEARCHSIDE* side) + + Convert Python strings into one of :c:data:`NPY_SEARCHLEFT` (starts with 'l' + or 'L'), or :c:data:`NPY_SEARCHRIGHT` (starts with 'r' or 'R'). + +.. c:function:: int PyArray_OrderConverter(PyObject* obj, NPY_ORDER* order) + + Convert the Python strings 'C', 'F', 'A', and 'K' into the :c:type:`NPY_ORDER` + enumeration :c:data:`NPY_CORDER`, :c:data:`NPY_FORTRANORDER`, + :c:data:`NPY_ANYORDER`, and :c:data:`NPY_KEEPORDER`. + +.. c:function:: int PyArray_CastingConverter( \ + PyObject* obj, NPY_CASTING* casting) + + Convert the Python strings 'no', 'equiv', 'safe', 'same_kind', and + 'unsafe' into the :c:type:`NPY_CASTING` enumeration :c:data:`NPY_NO_CASTING`, + :c:data:`NPY_EQUIV_CASTING`, :c:data:`NPY_SAFE_CASTING`, + :c:data:`NPY_SAME_KIND_CASTING`, and :c:data:`NPY_UNSAFE_CASTING`. + +.. c:function:: int PyArray_ClipmodeConverter( \ + PyObject* object, NPY_CLIPMODE* val) + + Convert the Python strings 'clip', 'wrap', and 'raise' into the + :c:type:`NPY_CLIPMODE` enumeration :c:data:`NPY_CLIP`, :c:data:`NPY_WRAP`, + and :c:data:`NPY_RAISE`. + +.. c:function:: int PyArray_ConvertClipmodeSequence( \ + PyObject* object, NPY_CLIPMODE* modes, int n) + + Converts either a sequence of clipmodes or a single clipmode into + a C array of :c:type:`NPY_CLIPMODE` values. The number of clipmodes *n* + must be known before calling this function. This function is provided + to help functions allow a different clipmode for each dimension. + +Other conversions +^^^^^^^^^^^^^^^^^ + +.. c:function:: int PyArray_PyIntAsInt(PyObject* op) + + Convert all kinds of Python objects (including arrays and array + scalars) to a standard integer. On error, -1 is returned and an + exception set. You may find useful the macro: + + .. code-block:: c + + #define error_converting(x) (((x) == -1) && PyErr_Occurred() + +.. c:function:: npy_intp PyArray_PyIntAsIntp(PyObject* op) + + Convert all kinds of Python objects (including arrays and array + scalars) to a (platform-pointer-sized) integer. On error, -1 is + returned and an exception set. + +.. c:function:: int PyArray_IntpFromSequence( \ + PyObject* seq, npy_intp* vals, int maxvals) + + Convert any Python sequence (or single Python number) passed in as + *seq* to (up to) *maxvals* pointer-sized integers and place them + in the *vals* array. The sequence can be smaller then *maxvals* as + the number of converted objects is returned. + +.. c:function:: int PyArray_TypestrConvert(int itemsize, int gentype) + + Convert typestring characters (with *itemsize*) to basic + enumerated data types. The typestring character corresponding to + signed and unsigned integers, floating point numbers, and + complex-floating point numbers are recognized and converted. Other + values of gentype are returned. This function can be used to + convert, for example, the string 'f4' to :c:data:`NPY_FLOAT32`. + + +Miscellaneous +------------- + + +Importing the API +^^^^^^^^^^^^^^^^^ + +In order to make use of the C-API from another extension module, the +:c:func:`import_array` function must be called. If the extension module is +self-contained in a single .c file, then that is all that needs to be +done. If, however, the extension module involves multiple files where +the C-API is needed then some additional steps must be taken. + +.. c:function:: void import_array(void) + + This function must be called in the initialization section of a + module that will make use of the C-API. It imports the module + where the function-pointer table is stored and points the correct + variable to it. + +.. c:macro:: PY_ARRAY_UNIQUE_SYMBOL + +.. c:macro:: NO_IMPORT_ARRAY + + Using these #defines you can use the C-API in multiple files for a + single extension module. In each file you must define + :c:macro:`PY_ARRAY_UNIQUE_SYMBOL` to some name that will hold the + C-API (*e.g.* myextension_ARRAY_API). This must be done **before** + including the numpy/arrayobject.h file. In the module + initialization routine you call :c:func:`import_array`. In addition, + in the files that do not have the module initialization + sub_routine define :c:macro:`NO_IMPORT_ARRAY` prior to including + numpy/arrayobject.h. + + Suppose I have two files coolmodule.c and coolhelper.c which need + to be compiled and linked into a single extension module. Suppose + coolmodule.c contains the required initcool module initialization + function (with the import_array() function called). Then, + coolmodule.c would have at the top: + + .. code-block:: c + + #define PY_ARRAY_UNIQUE_SYMBOL cool_ARRAY_API + #include numpy/arrayobject.h + + On the other hand, coolhelper.c would contain at the top: + + .. code-block:: c + + #define NO_IMPORT_ARRAY + #define PY_ARRAY_UNIQUE_SYMBOL cool_ARRAY_API + #include numpy/arrayobject.h + + You can also put the common two last lines into an extension-local + header file as long as you make sure that NO_IMPORT_ARRAY is + #defined before #including that file. + + Internally, these #defines work as follows: + + * If neither is defined, the C-API is declared to be + :c:type:`static void**`, so it is only visible within the + compilation unit that #includes numpy/arrayobject.h. + * If :c:macro:`PY_ARRAY_UNIQUE_SYMBOL` is #defined, but + :c:macro:`NO_IMPORT_ARRAY` is not, the C-API is declared to + be :c:type:`void**`, so that it will also be visible to other + compilation units. + * If :c:macro:`NO_IMPORT_ARRAY` is #defined, regardless of + whether :c:macro:`PY_ARRAY_UNIQUE_SYMBOL` is, the C-API is + declared to be :c:type:`extern void**`, so it is expected to + be defined in another compilation unit. + * Whenever :c:macro:`PY_ARRAY_UNIQUE_SYMBOL` is #defined, it + also changes the name of the variable holding the C-API, which + defaults to :c:data:`PyArray_API`, to whatever the macro is + #defined to. + +Checking the API Version +^^^^^^^^^^^^^^^^^^^^^^^^ + +Because python extensions are not used in the same way as usual libraries on +most platforms, some errors cannot be automatically detected at build time or +even runtime. For example, if you build an extension using a function available +only for numpy >= 1.3.0, and you import the extension later with numpy 1.2, you +will not get an import error (but almost certainly a segmentation fault when +calling the function). That's why several functions are provided to check for +numpy versions. The macros :c:data:`NPY_VERSION` and +:c:data:`NPY_FEATURE_VERSION` corresponds to the numpy version used to build the +extension, whereas the versions returned by the functions +PyArray_GetNDArrayCVersion and PyArray_GetNDArrayCFeatureVersion corresponds to +the runtime numpy's version. + +The rules for ABI and API compatibilities can be summarized as follows: + + * Whenever :c:data:`NPY_VERSION` != PyArray_GetNDArrayCVersion, the + extension has to be recompiled (ABI incompatibility). + * :c:data:`NPY_VERSION` == PyArray_GetNDArrayCVersion and + :c:data:`NPY_FEATURE_VERSION` <= PyArray_GetNDArrayCFeatureVersion means + backward compatible changes. + +ABI incompatibility is automatically detected in every numpy's version. API +incompatibility detection was added in numpy 1.4.0. If you want to supported +many different numpy versions with one extension binary, you have to build your +extension with the lowest NPY_FEATURE_VERSION as possible. + +.. c:function:: unsigned int PyArray_GetNDArrayCVersion(void) + + This just returns the value :c:data:`NPY_VERSION`. :c:data:`NPY_VERSION` + changes whenever a backward incompatible change at the ABI level. Because + it is in the C-API, however, comparing the output of this function from the + value defined in the current header gives a way to test if the C-API has + changed thus requiring a re-compilation of extension modules that use the + C-API. This is automatically checked in the function :c:func:`import_array`. + +.. c:function:: unsigned int PyArray_GetNDArrayCFeatureVersion(void) + + .. versionadded:: 1.4.0 + + This just returns the value :c:data:`NPY_FEATURE_VERSION`. + :c:data:`NPY_FEATURE_VERSION` changes whenever the API changes (e.g. a + function is added). A changed value does not always require a recompile. + +Internal Flexibility +^^^^^^^^^^^^^^^^^^^^ + +.. c:function:: int PyArray_SetNumericOps(PyObject* dict) + + NumPy stores an internal table of Python callable objects that are + used to implement arithmetic operations for arrays as well as + certain array calculation methods. This function allows the user + to replace any or all of these Python objects with their own + versions. The keys of the dictionary, *dict*, are the named + functions to replace and the paired value is the Python callable + object to use. Care should be taken that the function used to + replace an internal array operation does not itself call back to + that internal array operation (unless you have designed the + function to handle that), or an unchecked infinite recursion can + result (possibly causing program crash). The key names that + represent operations that can be replaced are: + + **add**, **subtract**, **multiply**, **divide**, + **remainder**, **power**, **square**, **reciprocal**, + **ones_like**, **sqrt**, **negative**, **positive**, + **absolute**, **invert**, **left_shift**, **right_shift**, + **bitwise_and**, **bitwise_xor**, **bitwise_or**, + **less**, **less_equal**, **equal**, **not_equal**, + **greater**, **greater_equal**, **floor_divide**, + **true_divide**, **logical_or**, **logical_and**, + **floor**, **ceil**, **maximum**, **minimum**, **rint**. + + + These functions are included here because they are used at least once + in the array object's methods. The function returns -1 (without + setting a Python Error) if one of the objects being assigned is not + callable. + +.. c:function:: PyObject* PyArray_GetNumericOps(void) + + Return a Python dictionary containing the callable Python objects + stored in the internal arithmetic operation table. The keys of + this dictionary are given in the explanation for :c:func:`PyArray_SetNumericOps`. + +.. c:function:: void PyArray_SetStringFunction(PyObject* op, int repr) + + This function allows you to alter the tp_str and tp_repr methods + of the array object to any Python function. Thus you can alter + what happens for all arrays when str(arr) or repr(arr) is called + from Python. The function to be called is passed in as *op*. If + *repr* is non-zero, then this function will be called in response + to repr(arr), otherwise the function will be called in response to + str(arr). No check on whether or not *op* is callable is + performed. The callable passed in to *op* should expect an array + argument and should return a string to be printed. + + +Memory management +^^^^^^^^^^^^^^^^^ + +.. c:function:: char* PyDataMem_NEW(size_t nbytes) + +.. c:function:: PyDataMem_FREE(char* ptr) + +.. c:function:: char* PyDataMem_RENEW(void * ptr, size_t newbytes) + + Macros to allocate, free, and reallocate memory. These macros are used + internally to create arrays. + +.. c:function:: npy_intp* PyDimMem_NEW(nd) + +.. c:function:: PyDimMem_FREE(npy_intp* ptr) + +.. c:function:: npy_intp* PyDimMem_RENEW(npy_intp* ptr, npy_intp newnd) + + Macros to allocate, free, and reallocate dimension and strides memory. + +.. c:function:: PyArray_malloc(nbytes) + +.. c:function:: PyArray_free(ptr) + +.. c:function:: PyArray_realloc(ptr, nbytes) + + These macros use different memory allocators, depending on the + constant :c:data:`NPY_USE_PYMEM`. The system malloc is used when + :c:data:`NPY_USE_PYMEM` is 0, if :c:data:`NPY_USE_PYMEM` is 1, then + the Python memory allocator is used. + +.. c:function:: int PyArray_ResolveWritebackIfCopy(PyArrayObject* obj) + + If ``obj.flags`` has :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` or (deprecated) + :c:data:`NPY_ARRAY_UPDATEIFCOPY`, this function clears the flags, `DECREF` s + `obj->base` and makes it writeable, and sets ``obj->base`` to NULL. It then + copies ``obj->data`` to `obj->base->data`, and returns the error state of + the copy operation. This is the opposite of + :c:func:`PyArray_SetWritebackIfCopyBase`. Usually this is called once + you are finished with ``obj``, just before ``Py_DECREF(obj)``. It may be called + multiple times, or with ``NULL`` input. See also + :c:func:`PyArray_DiscardWritebackIfCopy`. + + Returns 0 if nothing was done, -1 on error, and 1 if action was taken. + +Threading support +^^^^^^^^^^^^^^^^^ + +These macros are only meaningful if :c:data:`NPY_ALLOW_THREADS` +evaluates True during compilation of the extension module. Otherwise, +these macros are equivalent to whitespace. Python uses a single Global +Interpreter Lock (GIL) for each Python process so that only a single +thread may execute at a time (even on multi-cpu machines). When +calling out to a compiled function that may take time to compute (and +does not have side-effects for other threads like updated global +variables), the GIL should be released so that other Python threads +can run while the time-consuming calculations are performed. This can +be accomplished using two groups of macros. Typically, if one macro in +a group is used in a code block, all of them must be used in the same +code block. Currently, :c:data:`NPY_ALLOW_THREADS` is defined to the +python-defined :c:data:`WITH_THREADS` constant unless the environment +variable :c:data:`NPY_NOSMP` is set in which case +:c:data:`NPY_ALLOW_THREADS` is defined to be 0. + +Group 1 +""""""" + + This group is used to call code that may take some time but does not + use any Python C-API calls. Thus, the GIL should be released during + its calculation. + + .. c:macro:: NPY_BEGIN_ALLOW_THREADS + + Equivalent to :c:macro:`Py_BEGIN_ALLOW_THREADS` except it uses + :c:data:`NPY_ALLOW_THREADS` to determine if the macro if + replaced with white-space or not. + + .. c:macro:: NPY_END_ALLOW_THREADS + + Equivalent to :c:macro:`Py_END_ALLOW_THREADS` except it uses + :c:data:`NPY_ALLOW_THREADS` to determine if the macro if + replaced with white-space or not. + + .. c:macro:: NPY_BEGIN_THREADS_DEF + + Place in the variable declaration area. This macro sets up the + variable needed for storing the Python state. + + .. c:macro:: NPY_BEGIN_THREADS + + Place right before code that does not need the Python + interpreter (no Python C-API calls). This macro saves the + Python state and releases the GIL. + + .. c:macro:: NPY_END_THREADS + + Place right after code that does not need the Python + interpreter. This macro acquires the GIL and restores the + Python state from the saved variable. + + .. c:function:: NPY_BEGIN_THREADS_DESCR(PyArray_Descr *dtype) + + Useful to release the GIL only if *dtype* does not contain + arbitrary Python objects which may need the Python interpreter + during execution of the loop. Equivalent to + + .. c:function:: NPY_END_THREADS_DESCR(PyArray_Descr *dtype) + + Useful to regain the GIL in situations where it was released + using the BEGIN form of this macro. + + .. c:function:: NPY_BEGIN_THREADS_THRESHOLDED(int loop_size) + + Useful to release the GIL only if *loop_size* exceeds a + minimum threshold, currently set to 500. Should be matched + with a :c:macro:`NPY_END_THREADS` to regain the GIL. + +Group 2 +""""""" + + This group is used to re-acquire the Python GIL after it has been + released. For example, suppose the GIL has been released (using the + previous calls), and then some path in the code (perhaps in a + different subroutine) requires use of the Python C-API, then these + macros are useful to acquire the GIL. These macros accomplish + essentially a reverse of the previous three (acquire the LOCK saving + what state it had) and then re-release it with the saved state. + + .. c:macro:: NPY_ALLOW_C_API_DEF + + Place in the variable declaration area to set up the necessary + variable. + + .. c:macro:: NPY_ALLOW_C_API + + Place before code that needs to call the Python C-API (when it is + known that the GIL has already been released). + + .. c:macro:: NPY_DISABLE_C_API + + Place after code that needs to call the Python C-API (to re-release + the GIL). + +.. tip:: + + Never use semicolons after the threading support macros. + + +Priority +^^^^^^^^ + +.. c:var:: NPY_PRIORITY + + Default priority for arrays. + +.. c:var:: NPY_SUBTYPE_PRIORITY + + Default subtype priority. + +.. c:var:: NPY_SCALAR_PRIORITY + + Default scalar priority (very small) + +.. c:function:: double PyArray_GetPriority(PyObject* obj, double def) + + Return the :obj:`~numpy.class.__array_priority__` attribute (converted to a + double) of *obj* or *def* if no attribute of that name + exists. Fast returns that avoid the attribute lookup are provided + for objects of type :c:data:`PyArray_Type`. + + +Default buffers +^^^^^^^^^^^^^^^ + +.. c:var:: NPY_BUFSIZE + + Default size of the user-settable internal buffers. + +.. c:var:: NPY_MIN_BUFSIZE + + Smallest size of user-settable internal buffers. + +.. c:var:: NPY_MAX_BUFSIZE + + Largest size allowed for the user-settable buffers. + + +Other constants +^^^^^^^^^^^^^^^ + +.. c:var:: NPY_NUM_FLOATTYPE + + The number of floating-point types + +.. c:var:: NPY_MAXDIMS + + The maximum number of dimensions allowed in arrays. + +.. c:var:: NPY_VERSION + + The current version of the ndarray object (check to see if this + variable is defined to guarantee the numpy/arrayobject.h header is + being used). + +.. c:var:: NPY_FALSE + + Defined as 0 for use with Bool. + +.. c:var:: NPY_TRUE + + Defined as 1 for use with Bool. + +.. c:var:: NPY_FAIL + + The return value of failed converter functions which are called using + the "O&" syntax in :c:func:`PyArg_ParseTuple`-like functions. + +.. c:var:: NPY_SUCCEED + + The return value of successful converter functions which are called + using the "O&" syntax in :c:func:`PyArg_ParseTuple`-like functions. + + +Miscellaneous Macros +^^^^^^^^^^^^^^^^^^^^ + +.. c:function:: PyArray_SAMESHAPE(a1, a2) + + Evaluates as True if arrays *a1* and *a2* have the same shape. + +.. c:function:: PyArray_MAX(a,b) + + Returns the maximum of *a* and *b*. If (*a*) or (*b*) are + expressions they are evaluated twice. + +.. c:function:: PyArray_MIN(a,b) + + Returns the minimum of *a* and *b*. If (*a*) or (*b*) are + expressions they are evaluated twice. + +.. c:function:: PyArray_CLT(a,b) + +.. c:function:: PyArray_CGT(a,b) + +.. c:function:: PyArray_CLE(a,b) + +.. c:function:: PyArray_CGE(a,b) + +.. c:function:: PyArray_CEQ(a,b) + +.. c:function:: PyArray_CNE(a,b) + + Implements the complex comparisons between two complex numbers + (structures with a real and imag member) using NumPy's definition + of the ordering which is lexicographic: comparing the real parts + first and then the complex parts if the real parts are equal. + +.. c:function:: PyArray_REFCOUNT(PyObject* op) + + Returns the reference count of any Python object. + +.. c:function:: PyArray_DiscardWritebackIfCopy(PyObject* obj) + + If ``obj.flags`` has :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` or (deprecated) + :c:data:`NPY_ARRAY_UPDATEIFCOPY`, this function clears the flags, `DECREF` s + `obj->base` and makes it writeable, and sets ``obj->base`` to NULL. In + contrast to :c:func:`PyArray_DiscardWritebackIfCopy` it makes no attempt + to copy the data from `obj->base` This undoes + :c:func:`PyArray_SetWritebackIfCopyBase`. Usually this is called after an + error when you are finished with ``obj``, just before ``Py_DECREF(obj)``. + It may be called multiple times, or with ``NULL`` input. + +.. c:function:: PyArray_XDECREF_ERR(PyObject* obj) + + Deprecated in 1.14, use :c:func:`PyArray_DiscardWritebackIfCopy` + followed by ``Py_XDECREF`` + + DECREF's an array object which may have the (deprecated) + :c:data:`NPY_ARRAY_UPDATEIFCOPY` or :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` + flag set without causing the contents to be copied back into the + original array. Resets the :c:data:`NPY_ARRAY_WRITEABLE` flag on the base + object. This is useful for recovering from an error condition when + writeback semantics are used, but will lead to wrong results. + + +Enumerated Types +^^^^^^^^^^^^^^^^ + +.. c:type:: NPY_SORTKIND + + A special variable-type which can take on the values :c:data:`NPY_{KIND}` + where ``{KIND}`` is + + **QUICKSORT**, **HEAPSORT**, **MERGESORT** + + .. c:var:: NPY_NSORTS + + Defined to be the number of sorts. + +.. c:type:: NPY_SCALARKIND + + A special variable type indicating the number of "kinds" of + scalars distinguished in determining scalar-coercion rules. This + variable can take on the values :c:data:`NPY_{KIND}` where ``{KIND}`` can be + + **NOSCALAR**, **BOOL_SCALAR**, **INTPOS_SCALAR**, + **INTNEG_SCALAR**, **FLOAT_SCALAR**, **COMPLEX_SCALAR**, + **OBJECT_SCALAR** + + .. c:var:: NPY_NSCALARKINDS + + Defined to be the number of scalar kinds + (not including :c:data:`NPY_NOSCALAR`). + +.. c:type:: NPY_ORDER + + An enumeration type indicating the element order that an array should be + interpreted in. When a brand new array is created, generally + only **NPY_CORDER** and **NPY_FORTRANORDER** are used, whereas + when one or more inputs are provided, the order can be based on them. + + .. c:var:: NPY_ANYORDER + + Fortran order if all the inputs are Fortran, C otherwise. + + .. c:var:: NPY_CORDER + + C order. + + .. c:var:: NPY_FORTRANORDER + + Fortran order. + + .. c:var:: NPY_KEEPORDER + + An order as close to the order of the inputs as possible, even + if the input is in neither C nor Fortran order. + +.. c:type:: NPY_CLIPMODE + + A variable type indicating the kind of clipping that should be + applied in certain functions. + + .. c:var:: NPY_RAISE + + The default for most operations, raises an exception if an index + is out of bounds. + + .. c:var:: NPY_CLIP + + Clips an index to the valid range if it is out of bounds. + + .. c:var:: NPY_WRAP + + Wraps an index to the valid range if it is out of bounds. + +.. c:type:: NPY_CASTING + + .. versionadded:: 1.6 + + An enumeration type indicating how permissive data conversions should + be. This is used by the iterator added in NumPy 1.6, and is intended + to be used more broadly in a future version. + + .. c:var:: NPY_NO_CASTING + + Only allow identical types. + + .. c:var:: NPY_EQUIV_CASTING + + Allow identical and casts involving byte swapping. + + .. c:var:: NPY_SAFE_CASTING + + Only allow casts which will not cause values to be rounded, + truncated, or otherwise changed. + + .. c:var:: NPY_SAME_KIND_CASTING + + Allow any safe casts, and casts between types of the same kind. + For example, float64 -> float32 is permitted with this rule. + + .. c:var:: NPY_UNSAFE_CASTING + + Allow any cast, no matter what kind of data loss may occur. + +.. index:: + pair: ndarray; C-API diff --git a/doc/source/reference/c-api.config.rst b/doc/source/reference/c-api.config.rst new file mode 100644 index 0000000..60bf61a --- /dev/null +++ b/doc/source/reference/c-api.config.rst @@ -0,0 +1,103 @@ +System configuration +==================== + +.. sectionauthor:: Travis E. Oliphant + +When NumPy is built, information about system configuration is +recorded, and is made available for extension modules using NumPy's C +API. These are mostly defined in ``numpyconfig.h`` (included in +``ndarrayobject.h``). The public symbols are prefixed by ``NPY_*``. +NumPy also offers some functions for querying information about the +platform in use. + +For private use, NumPy also constructs a ``config.h`` in the NumPy +include directory, which is not exported by NumPy (that is a python +extension which use the numpy C API will not see those symbols), to +avoid namespace pollution. + + +Data type sizes +--------------- + +The :c:data:`NPY_SIZEOF_{CTYPE}` constants are defined so that sizeof +information is available to the pre-processor. + +.. c:var:: NPY_SIZEOF_SHORT + + sizeof(short) + +.. c:var:: NPY_SIZEOF_INT + + sizeof(int) + +.. c:var:: NPY_SIZEOF_LONG + + sizeof(long) + +.. c:var:: NPY_SIZEOF_LONGLONG + + sizeof(longlong) where longlong is defined appropriately on the + platform. + +.. c:var:: NPY_SIZEOF_PY_LONG_LONG + + +.. c:var:: NPY_SIZEOF_FLOAT + + sizeof(float) + +.. c:var:: NPY_SIZEOF_DOUBLE + + sizeof(double) + +.. c:var:: NPY_SIZEOF_LONG_DOUBLE + + sizeof(longdouble) (A macro defines **NPY_SIZEOF_LONGDOUBLE** as well.) + +.. c:var:: NPY_SIZEOF_PY_INTPTR_T + + Size of a pointer on this platform (sizeof(void \*)) (A macro defines + NPY_SIZEOF_INTP as well.) + + +Platform information +-------------------- + +.. c:var:: NPY_CPU_X86 +.. c:var:: NPY_CPU_AMD64 +.. c:var:: NPY_CPU_IA64 +.. c:var:: NPY_CPU_PPC +.. c:var:: NPY_CPU_PPC64 +.. c:var:: NPY_CPU_SPARC +.. c:var:: NPY_CPU_SPARC64 +.. c:var:: NPY_CPU_S390 +.. c:var:: NPY_CPU_PARISC + + .. versionadded:: 1.3.0 + + CPU architecture of the platform; only one of the above is + defined. + + Defined in ``numpy/npy_cpu.h`` + +.. c:var:: NPY_LITTLE_ENDIAN + +.. c:var:: NPY_BIG_ENDIAN + +.. c:var:: NPY_BYTE_ORDER + + .. versionadded:: 1.3.0 + + Portable alternatives to the ``endian.h`` macros of GNU Libc. + If big endian, :c:data:`NPY_BYTE_ORDER` == :c:data:`NPY_BIG_ENDIAN`, and + similarly for little endian architectures. + + Defined in ``numpy/npy_endian.h``. + +.. c:function:: PyArray_GetEndianness() + + .. versionadded:: 1.3.0 + + Returns the endianness of the current platform. + One of :c:data:`NPY_CPU_BIG`, :c:data:`NPY_CPU_LITTLE`, + or :c:data:`NPY_CPU_UNKNOWN_ENDIAN`. diff --git a/doc/source/reference/c-api.coremath.rst b/doc/source/reference/c-api.coremath.rst new file mode 100644 index 0000000..9027a4e --- /dev/null +++ b/doc/source/reference/c-api.coremath.rst @@ -0,0 +1,420 @@ +NumPy core libraries +==================== + +.. sectionauthor:: David Cournapeau + +.. versionadded:: 1.3.0 + +Starting from numpy 1.3.0, we are working on separating the pure C, +"computational" code from the python dependent code. The goal is twofolds: +making the code cleaner, and enabling code reuse by other extensions outside +numpy (scipy, etc...). + +NumPy core math library +----------------------- + +The numpy core math library ('npymath') is a first step in this direction. This +library contains most math-related C99 functionality, which can be used on +platforms where C99 is not well supported. The core math functions have the +same API as the C99 ones, except for the npy_* prefix. + +The available functions are defined in - please refer to this header when +in doubt. + +Floating point classification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. c:var:: NPY_NAN + + This macro is defined to a NaN (Not a Number), and is guaranteed to have + the signbit unset ('positive' NaN). The corresponding single and extension + precision macro are available with the suffix F and L. + +.. c:var:: NPY_INFINITY + + This macro is defined to a positive inf. The corresponding single and + extension precision macro are available with the suffix F and L. + +.. c:var:: NPY_PZERO + + This macro is defined to positive zero. The corresponding single and + extension precision macro are available with the suffix F and L. + +.. c:var:: NPY_NZERO + + This macro is defined to negative zero (that is with the sign bit set). The + corresponding single and extension precision macro are available with the + suffix F and L. + +.. c:function:: int npy_isnan(x) + + This is a macro, and is equivalent to C99 isnan: works for single, double + and extended precision, and return a non 0 value is x is a NaN. + +.. c:function:: int npy_isfinite(x) + + This is a macro, and is equivalent to C99 isfinite: works for single, + double and extended precision, and return a non 0 value is x is neither a + NaN nor an infinity. + +.. c:function:: int npy_isinf(x) + + This is a macro, and is equivalent to C99 isinf: works for single, double + and extended precision, and return a non 0 value is x is infinite (positive + and negative). + +.. c:function:: int npy_signbit(x) + + This is a macro, and is equivalent to C99 signbit: works for single, double + and extended precision, and return a non 0 value is x has the signbit set + (that is the number is negative). + +.. c:function:: double npy_copysign(double x, double y) + + This is a function equivalent to C99 copysign: return x with the same sign + as y. Works for any value, including inf and nan. Single and extended + precisions are available with suffix f and l. + + .. versionadded:: 1.4.0 + +Useful math constants +~~~~~~~~~~~~~~~~~~~~~ + +The following math constants are available in npy_math.h. Single and extended +precision are also available by adding the F and L suffixes respectively. + +.. c:var:: NPY_E + + Base of natural logarithm (:math:`e`) + +.. c:var:: NPY_LOG2E + + Logarithm to base 2 of the Euler constant (:math:`\frac{\ln(e)}{\ln(2)}`) + +.. c:var:: NPY_LOG10E + + Logarithm to base 10 of the Euler constant (:math:`\frac{\ln(e)}{\ln(10)}`) + +.. c:var:: NPY_LOGE2 + + Natural logarithm of 2 (:math:`\ln(2)`) + +.. c:var:: NPY_LOGE10 + + Natural logarithm of 10 (:math:`\ln(10)`) + +.. c:var:: NPY_PI + + Pi (:math:`\pi`) + +.. c:var:: NPY_PI_2 + + Pi divided by 2 (:math:`\frac{\pi}{2}`) + +.. c:var:: NPY_PI_4 + + Pi divided by 4 (:math:`\frac{\pi}{4}`) + +.. c:var:: NPY_1_PI + + Reciprocal of pi (:math:`\frac{1}{\pi}`) + +.. c:var:: NPY_2_PI + + Two times the reciprocal of pi (:math:`\frac{2}{\pi}`) + +.. c:var:: NPY_EULER + + The Euler constant + :math:`\lim_{n\rightarrow\infty}({\sum_{k=1}^n{\frac{1}{k}}-\ln n})` + +Low-level floating point manipulation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Those can be useful for precise floating point comparison. + +.. c:function:: double npy_nextafter(double x, double y) + + This is a function equivalent to C99 nextafter: return next representable + floating point value from x in the direction of y. Single and extended + precisions are available with suffix f and l. + + .. versionadded:: 1.4.0 + +.. c:function:: double npy_spacing(double x) + + This is a function equivalent to Fortran intrinsic. Return distance between + x and next representable floating point value from x, e.g. spacing(1) == + eps. spacing of nan and +/- inf return nan. Single and extended precisions + are available with suffix f and l. + + .. versionadded:: 1.4.0 + +.. c:function:: void npy_set_floatstatus_divbyzero() + + Set the divide by zero floating point exception + + .. versionadded:: 1.6.0 + +.. c:function:: void npy_set_floatstatus_overflow() + + Set the overflow floating point exception + + .. versionadded:: 1.6.0 + +.. c:function:: void npy_set_floatstatus_underflow() + + Set the underflow floating point exception + + .. versionadded:: 1.6.0 + +.. c:function:: void npy_set_floatstatus_invalid() + + Set the invalid floating point exception + + .. versionadded:: 1.6.0 + +.. c:function:: int npy_get_floatstatus() + + Get floating point status. Returns a bitmask with following possible flags: + + * NPY_FPE_DIVIDEBYZERO + * NPY_FPE_OVERFLOW + * NPY_FPE_UNDERFLOW + * NPY_FPE_INVALID + + .. versionadded:: 1.9.0 + +.. c:function:: int npy_clear_floatstatus() + + Clears the floating point status. Returns the previous status mask. + + .. versionadded:: 1.9.0 + +Complex functions +~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.4.0 + +C99-like complex functions have been added. Those can be used if you wish to +implement portable C extensions. Since we still support platforms without C99 +complex type, you need to restrict to C90-compatible syntax, e.g.: + +.. code-block:: c + + /* a = 1 + 2i \*/ + npy_complex a = npy_cpack(1, 2); + npy_complex b; + + b = npy_log(a); + +Linking against the core math library in an extension +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.4.0 + +To use the core math library in your own extension, you need to add the npymath +compile and link options to your extension in your setup.py: + + >>> from numpy.distutils.misc_util import get_info + >>> info = get_info('npymath') + >>> config.add_extension('foo', sources=['foo.c'], extra_info=info) + +In other words, the usage of info is exactly the same as when using blas_info +and co. + +Half-precision functions +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.0.0 + +The header file provides functions to work with +IEEE 754-2008 16-bit floating point values. While this format is +not typically used for numerical computations, it is useful for +storing values which require floating point but do not need much precision. +It can also be used as an educational tool to understand the nature +of floating point round-off error. + +Like for other types, NumPy includes a typedef npy_half for the 16 bit +float. Unlike for most of the other types, you cannot use this as a +normal type in C, since is is a typedef for npy_uint16. For example, +1.0 looks like 0x3c00 to C, and if you do an equality comparison +between the different signed zeros, you will get -0.0 != 0.0 +(0x8000 != 0x0000), which is incorrect. + +For these reasons, NumPy provides an API to work with npy_half values +accessible by including and linking to 'npymath'. +For functions that are not provided directly, such as the arithmetic +operations, the preferred method is to convert to float +or double and back again, as in the following example. + +.. code-block:: c + + npy_half sum(int n, npy_half *array) { + float ret = 0; + while(n--) { + ret += npy_half_to_float(*array++); + } + return npy_float_to_half(ret); + } + +External Links: + +* `754-2008 IEEE Standard for Floating-Point Arithmetic`__ +* `Half-precision Float Wikipedia Article`__. +* `OpenGL Half Float Pixel Support`__ +* `The OpenEXR image format`__. + +__ http://ieeexplore.ieee.org/servlet/opac?punumber=4610933 +__ http://en.wikipedia.org/wiki/Half_precision_floating-point_format +__ http://www.opengl.org/registry/specs/ARB/half_float_pixel.txt +__ http://www.openexr.com/about.html + +.. c:var:: NPY_HALF_ZERO + + This macro is defined to positive zero. + +.. c:var:: NPY_HALF_PZERO + + This macro is defined to positive zero. + +.. c:var:: NPY_HALF_NZERO + + This macro is defined to negative zero. + +.. c:var:: NPY_HALF_ONE + + This macro is defined to 1.0. + +.. c:var:: NPY_HALF_NEGONE + + This macro is defined to -1.0. + +.. c:var:: NPY_HALF_PINF + + This macro is defined to +inf. + +.. c:var:: NPY_HALF_NINF + + This macro is defined to -inf. + +.. c:var:: NPY_HALF_NAN + + This macro is defined to a NaN value, guaranteed to have its sign bit unset. + +.. c:function:: float npy_half_to_float(npy_half h) + + Converts a half-precision float to a single-precision float. + +.. c:function:: double npy_half_to_double(npy_half h) + + Converts a half-precision float to a double-precision float. + +.. c:function:: npy_half npy_float_to_half(float f) + + Converts a single-precision float to a half-precision float. The + value is rounded to the nearest representable half, with ties going + to the nearest even. If the value is too small or too big, the + system's floating point underflow or overflow bit will be set. + +.. c:function:: npy_half npy_double_to_half(double d) + + Converts a double-precision float to a half-precision float. The + value is rounded to the nearest representable half, with ties going + to the nearest even. If the value is too small or too big, the + system's floating point underflow or overflow bit will be set. + +.. c:function:: int npy_half_eq(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 == h2). + +.. c:function:: int npy_half_ne(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 != h2). + +.. c:function:: int npy_half_le(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 <= h2). + +.. c:function:: int npy_half_lt(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 < h2). + +.. c:function:: int npy_half_ge(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 >= h2). + +.. c:function:: int npy_half_gt(npy_half h1, npy_half h2) + + Compares two half-precision floats (h1 > h2). + +.. c:function:: int npy_half_eq_nonan(npy_half h1, npy_half h2) + + Compares two half-precision floats that are known to not be NaN (h1 == h2). If + a value is NaN, the result is undefined. + +.. c:function:: int npy_half_lt_nonan(npy_half h1, npy_half h2) + + Compares two half-precision floats that are known to not be NaN (h1 < h2). If + a value is NaN, the result is undefined. + +.. c:function:: int npy_half_le_nonan(npy_half h1, npy_half h2) + + Compares two half-precision floats that are known to not be NaN (h1 <= h2). If + a value is NaN, the result is undefined. + +.. c:function:: int npy_half_iszero(npy_half h) + + Tests whether the half-precision float has a value equal to zero. This may be slightly + faster than calling npy_half_eq(h, NPY_ZERO). + +.. c:function:: int npy_half_isnan(npy_half h) + + Tests whether the half-precision float is a NaN. + +.. c:function:: int npy_half_isinf(npy_half h) + + Tests whether the half-precision float is plus or minus Inf. + +.. c:function:: int npy_half_isfinite(npy_half h) + + Tests whether the half-precision float is finite (not NaN or Inf). + +.. c:function:: int npy_half_signbit(npy_half h) + + Returns 1 is h is negative, 0 otherwise. + +.. c:function:: npy_half npy_half_copysign(npy_half x, npy_half y) + + Returns the value of x with the sign bit copied from y. Works for any value, + including Inf and NaN. + +.. c:function:: npy_half npy_half_spacing(npy_half h) + + This is the same for half-precision float as npy_spacing and npy_spacingf + described in the low-level floating point section. + +.. c:function:: npy_half npy_half_nextafter(npy_half x, npy_half y) + + This is the same for half-precision float as npy_nextafter and npy_nextafterf + described in the low-level floating point section. + +.. c:function:: npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f) + + Low-level function which converts a 32-bit single-precision float, stored + as a uint32, into a 16-bit half-precision float. + +.. c:function:: npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d) + + Low-level function which converts a 64-bit double-precision float, stored + as a uint64, into a 16-bit half-precision float. + +.. c:function:: npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h) + + Low-level function which converts a 16-bit half-precision float + into a 32-bit single-precision float, stored as a uint32. + +.. c:function:: npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h) + + Low-level function which converts a 16-bit half-precision float + into a 64-bit double-precision float, stored as a uint64. diff --git a/doc/source/reference/c-api.deprecations.rst b/doc/source/reference/c-api.deprecations.rst new file mode 100644 index 0000000..a382017 --- /dev/null +++ b/doc/source/reference/c-api.deprecations.rst @@ -0,0 +1,58 @@ +C API Deprecations +================== + +Background +---------- + +The API exposed by NumPy for third-party extensions has grown over +years of releases, and has allowed programmers to directly access +NumPy functionality from C. This API can be best described as +"organic". It has emerged from multiple competing desires and from +multiple points of view over the years, strongly influenced by the +desire to make it easy for users to move to NumPy from Numeric and +Numarray. The core API originated with Numeric in 1995 and there are +patterns such as the heavy use of macros written to mimic Python's +C-API as well as account for compiler technology of the late 90's. +There is also only a small group of volunteers who have had very little +time to spend on improving this API. + +There is an ongoing effort to improve the API. +It is important in this effort +to ensure that code that compiles for NumPy 1.X continues to +compile for NumPy 1.X. At the same time, certain API's will be marked +as deprecated so that future-looking code can avoid these API's and +follow better practices. + +Another important role played by deprecation markings in the C API is to move +towards hiding internal details of the NumPy implementation. For those +needing direct, easy, access to the data of ndarrays, this will not +remove this ability. Rather, there are many potential performance +optimizations which require changing the implementation details, and +NumPy developers have been unable to try them because of the high +value of preserving ABI compatibility. By deprecating this direct +access, we will in the future be able to improve NumPy's performance +in ways we cannot presently. + +Deprecation Mechanism NPY_NO_DEPRECATED_API +------------------------------------------- + +In C, there is no equivalent to the deprecation warnings that Python +supports. One way to do deprecations is to flag them in the +documentation and release notes, then remove or change the deprecated +features in a future major version (NumPy 2.0 and beyond). Minor +versions of NumPy should not have major C-API changes, however, that +prevent code that worked on a previous minor release. For example, we +will do our best to ensure that code that compiled and worked on NumPy +1.4 should continue to work on NumPy 1.7 (but perhaps with compiler +warnings). + +To use the NPY_NO_DEPRECATED_API mechanism, you need to #define it to +the target API version of NumPy before #including any NumPy headers. +If you want to confirm that your code is clean against 1.7, use:: + + #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION + +On compilers which support a #warning mechanism, NumPy issues a +compiler warning if you do not define the symbol NPY_NO_DEPRECATED_API. +This way, the fact that there are deprecations will be flagged for +third-party developers who may not have read the release notes closely. diff --git a/doc/source/reference/c-api.dtype.rst b/doc/source/reference/c-api.dtype.rst new file mode 100644 index 0000000..8af3a90 --- /dev/null +++ b/doc/source/reference/c-api.dtype.rst @@ -0,0 +1,376 @@ +Data Type API +============= + +.. sectionauthor:: Travis E. Oliphant + +The standard array can have 24 different data types (and has some +support for adding your own types). These data types all have an +enumerated type, an enumerated type-character, and a corresponding +array scalar Python type object (placed in a hierarchy). There are +also standard C typedefs to make it easier to manipulate elements of +the given data type. For the numeric types, there are also bit-width +equivalent C typedefs and named typenumbers that make it easier to +select the precision desired. + +.. warning:: + + The names for the types in c code follows c naming conventions + more closely. The Python names for these types follow Python + conventions. Thus, :c:data:`NPY_FLOAT` picks up a 32-bit float in + C, but :class:`numpy.float_` in Python corresponds to a 64-bit + double. The bit-width names can be used in both Python and C for + clarity. + + +Enumerated Types +---------------- + +There is a list of enumerated types defined providing the basic 24 +data types plus some useful generic names. Whenever the code requires +a type number, one of these enumerated types is requested. The types +are all called :c:data:`NPY_{NAME}`: + +.. c:var:: NPY_BOOL + + The enumeration value for the boolean type, stored as one byte. + It may only be set to the values 0 and 1. + +.. c:var:: NPY_BYTE +.. c:var:: NPY_INT8 + + The enumeration value for an 8-bit/1-byte signed integer. + +.. c:var:: NPY_SHORT +.. c:var:: NPY_INT16 + + The enumeration value for a 16-bit/2-byte signed integer. + +.. c:var:: NPY_INT +.. c:var:: NPY_INT32 + + The enumeration value for a 32-bit/4-byte signed integer. + +.. c:var:: NPY_LONG + + Equivalent to either NPY_INT or NPY_LONGLONG, depending on the + platform. + +.. c:var:: NPY_LONGLONG +.. c:var:: NPY_INT64 + + The enumeration value for a 64-bit/8-byte signed integer. + +.. c:var:: NPY_UBYTE +.. c:var:: NPY_UINT8 + + The enumeration value for an 8-bit/1-byte unsigned integer. + +.. c:var:: NPY_USHORT +.. c:var:: NPY_UINT16 + + The enumeration value for a 16-bit/2-byte unsigned integer. + +.. c:var:: NPY_UINT +.. c:var:: NPY_UINT32 + + The enumeration value for a 32-bit/4-byte unsigned integer. + +.. c:var:: NPY_ULONG + + Equivalent to either NPY_UINT or NPY_ULONGLONG, depending on the + platform. + +.. c:var:: NPY_ULONGLONG +.. c:var:: NPY_UINT64 + + The enumeration value for a 64-bit/8-byte unsigned integer. + +.. c:var:: NPY_HALF +.. c:var:: NPY_FLOAT16 + + The enumeration value for a 16-bit/2-byte IEEE 754-2008 compatible floating + point type. + +.. c:var:: NPY_FLOAT +.. c:var:: NPY_FLOAT32 + + The enumeration value for a 32-bit/4-byte IEEE 754 compatible floating + point type. + +.. c:var:: NPY_DOUBLE +.. c:var:: NPY_FLOAT64 + + The enumeration value for a 64-bit/8-byte IEEE 754 compatible floating + point type. + +.. c:var:: NPY_LONGDOUBLE + + The enumeration value for a platform-specific floating point type which is + at least as large as NPY_DOUBLE, but larger on many platforms. + +.. c:var:: NPY_CFLOAT +.. c:var:: NPY_COMPLEX64 + + The enumeration value for a 64-bit/8-byte complex type made up of + two NPY_FLOAT values. + +.. c:var:: NPY_CDOUBLE +.. c:var:: NPY_COMPLEX128 + + The enumeration value for a 128-bit/16-byte complex type made up of + two NPY_DOUBLE values. + +.. c:var:: NPY_CLONGDOUBLE + + The enumeration value for a platform-specific complex floating point + type which is made up of two NPY_LONGDOUBLE values. + +.. c:var:: NPY_DATETIME + + The enumeration value for a data type which holds dates or datetimes with + a precision based on selectable date or time units. + +.. c:var:: NPY_TIMEDELTA + + The enumeration value for a data type which holds lengths of times in + integers of selectable date or time units. + +.. c:var:: NPY_STRING + + The enumeration value for ASCII strings of a selectable size. The + strings have a fixed maximum size within a given array. + +.. c:var:: NPY_UNICODE + + The enumeration value for UCS4 strings of a selectable size. The + strings have a fixed maximum size within a given array. + +.. c:var:: NPY_OBJECT + + The enumeration value for references to arbitrary Python objects. + +.. c:var:: NPY_VOID + + Primarily used to hold struct dtypes, but can contain arbitrary + binary data. + +Some useful aliases of the above types are + +.. c:var:: NPY_INTP + + The enumeration value for a signed integer type which is the same + size as a (void \*) pointer. This is the type used by all + arrays of indices. + +.. c:var:: NPY_UINTP + + The enumeration value for an unsigned integer type which is the + same size as a (void \*) pointer. + +.. c:var:: NPY_MASK + + The enumeration value of the type used for masks, such as with + the :c:data:`NPY_ITER_ARRAYMASK` iterator flag. This is equivalent + to :c:data:`NPY_UINT8`. + +.. c:var:: NPY_DEFAULT_TYPE + + The default type to use when no dtype is explicitly specified, for + example when calling np.zero(shape). This is equivalent to + :c:data:`NPY_DOUBLE`. + +Other useful related constants are + +.. c:var:: NPY_NTYPES + + The total number of built-in NumPy types. The enumeration covers + the range from 0 to NPY_NTYPES-1. + +.. c:var:: NPY_NOTYPE + + A signal value guaranteed not to be a valid type enumeration number. + +.. c:var:: NPY_USERDEF + + The start of type numbers used for Custom Data types. + +The various character codes indicating certain types are also part of +an enumerated list. References to type characters (should they be +needed at all) should always use these enumerations. The form of them +is :c:data:`NPY_{NAME}LTR` where ``{NAME}`` can be + + **BOOL**, **BYTE**, **UBYTE**, **SHORT**, **USHORT**, **INT**, + **UINT**, **LONG**, **ULONG**, **LONGLONG**, **ULONGLONG**, + **HALF**, **FLOAT**, **DOUBLE**, **LONGDOUBLE**, **CFLOAT**, + **CDOUBLE**, **CLONGDOUBLE**, **DATETIME**, **TIMEDELTA**, + **OBJECT**, **STRING**, **VOID** + + **INTP**, **UINTP** + + **GENBOOL**, **SIGNED**, **UNSIGNED**, **FLOATING**, **COMPLEX** + +The latter group of ``{NAME}s`` corresponds to letters used in the array +interface typestring specification. + + +Defines +------- + +Max and min values for integers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. c:var:: NPY_MAX_INT{bits} + +.. c:var:: NPY_MAX_UINT{bits} + +.. c:var:: NPY_MIN_INT{bits} + + These are defined for ``{bits}`` = 8, 16, 32, 64, 128, and 256 and provide + the maximum (minimum) value of the corresponding (unsigned) integer + type. Note: the actual integer type may not be available on all + platforms (i.e. 128-bit and 256-bit integers are rare). + +.. c:var:: NPY_MIN_{type} + + This is defined for ``{type}`` = **BYTE**, **SHORT**, **INT**, + **LONG**, **LONGLONG**, **INTP** + +.. c:var:: NPY_MAX_{type} + + This is defined for all defined for ``{type}`` = **BYTE**, **UBYTE**, + **SHORT**, **USHORT**, **INT**, **UINT**, **LONG**, **ULONG**, + **LONGLONG**, **ULONGLONG**, **INTP**, **UINTP** + + +Number of bits in data types +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All :c:data:`NPY_SIZEOF_{CTYPE}` constants have corresponding +:c:data:`NPY_BITSOF_{CTYPE}` constants defined. The :c:data:`NPY_BITSOF_{CTYPE}` +constants provide the number of bits in the data type. Specifically, +the available ``{CTYPE}s`` are + + **BOOL**, **CHAR**, **SHORT**, **INT**, **LONG**, + **LONGLONG**, **FLOAT**, **DOUBLE**, **LONGDOUBLE** + + +Bit-width references to enumerated typenums +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All of the numeric data types (integer, floating point, and complex) +have constants that are defined to be a specific enumerated type +number. Exactly which enumerated type a bit-width type refers to is +platform dependent. In particular, the constants available are +:c:data:`PyArray_{NAME}{BITS}` where ``{NAME}`` is **INT**, **UINT**, +**FLOAT**, **COMPLEX** and ``{BITS}`` can be 8, 16, 32, 64, 80, 96, 128, +160, 192, 256, and 512. Obviously not all bit-widths are available on +all platforms for all the kinds of numeric types. Commonly 8-, 16-, +32-, 64-bit integers; 32-, 64-bit floats; and 64-, 128-bit complex +types are available. + + +Integer that can hold a pointer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The constants **NPY_INTP** and **NPY_UINTP** refer to an +enumerated integer type that is large enough to hold a pointer on the +platform. Index arrays should always be converted to **NPY_INTP** +, because the dimension of the array is of type npy_intp. + + +C-type names +------------ + +There are standard variable types for each of the numeric data types +and the bool data type. Some of these are already available in the +C-specification. You can create variables in extension code with these +types. + + +Boolean +^^^^^^^ + +.. c:type:: npy_bool + + unsigned char; The constants :c:data:`NPY_FALSE` and + :c:data:`NPY_TRUE` are also defined. + + +(Un)Signed Integer +^^^^^^^^^^^^^^^^^^ + +Unsigned versions of the integers can be defined by pre-pending a 'u' +to the front of the integer name. + +.. c:type:: npy_(u)byte + + (unsigned) char + +.. c:type:: npy_(u)short + + (unsigned) short + +.. c:type:: npy_(u)int + + (unsigned) int + +.. c:type:: npy_(u)long + + (unsigned) long int + +.. c:type:: npy_(u)longlong + + (unsigned long long int) + +.. c:type:: npy_(u)intp + + (unsigned) Py_intptr_t (an integer that is the size of a pointer on + the platform). + + +(Complex) Floating point +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. c:type:: npy_(c)float + + float + +.. c:type:: npy_(c)double + + double + +.. c:type:: npy_(c)longdouble + + long double + +complex types are structures with **.real** and **.imag** members (in +that order). + + +Bit-width names +^^^^^^^^^^^^^^^ + +There are also typedefs for signed integers, unsigned integers, +floating point, and complex floating point types of specific bit- +widths. The available type names are + + :c:type:`npy_int{bits}`, :c:type:`npy_uint{bits}`, :c:type:`npy_float{bits}`, + and :c:type:`npy_complex{bits}` + +where ``{bits}`` is the number of bits in the type and can be **8**, +**16**, **32**, **64**, 128, and 256 for integer types; 16, **32** +, **64**, 80, 96, 128, and 256 for floating-point types; and 32, +**64**, **128**, 160, 192, and 512 for complex-valued types. Which +bit-widths are available is platform dependent. The bolded bit-widths +are usually available on all platforms. + + +Printf Formatting +----------------- + +For help in printing, the following strings are defined as the correct +format specifier in printf and related commands. + + :c:data:`NPY_LONGLONG_FMT`, :c:data:`NPY_ULONGLONG_FMT`, + :c:data:`NPY_INTP_FMT`, :c:data:`NPY_UINTP_FMT`, + :c:data:`NPY_LONGDOUBLE_FMT` diff --git a/doc/source/reference/c-api.generalized-ufuncs.rst b/doc/source/reference/c-api.generalized-ufuncs.rst new file mode 100644 index 0000000..a53228c --- /dev/null +++ b/doc/source/reference/c-api.generalized-ufuncs.rst @@ -0,0 +1,193 @@ +.. _c-api.generalized-ufuncs: + +================================== +Generalized Universal Function API +================================== + +There is a general need for looping over not only functions on scalars +but also over functions on vectors (or arrays). +This concept is realized in NumPy by generalizing the universal functions +(ufuncs). In regular ufuncs, the elementary function is limited to +element-by-element operations, whereas the generalized version (gufuncs) +supports "sub-array" by "sub-array" operations. The Perl vector library PDL +provides a similar functionality and its terms are re-used in the following. + +Each generalized ufunc has information associated with it that states +what the "core" dimensionality of the inputs is, as well as the +corresponding dimensionality of the outputs (the element-wise ufuncs +have zero core dimensions). The list of the core dimensions for all +arguments is called the "signature" of a ufunc. For example, the +ufunc numpy.add has signature ``(),()->()`` defining two scalar inputs +and one scalar output. + +Another example is the function ``inner1d(a, b)`` with a signature of +``(i),(i)->()``. This applies the inner product along the last axis of +each input, but keeps the remaining indices intact. +For example, where ``a`` is of shape ``(3, 5, N)`` and ``b`` is of shape +``(5, N)``, this will return an output of shape ``(3,5)``. +The underlying elementary function is called ``3 * 5`` times. In the +signature, we specify one core dimension ``(i)`` for each input and zero core +dimensions ``()`` for the output, since it takes two 1-d arrays and +returns a scalar. By using the same name ``i``, we specify that the two +corresponding dimensions should be of the same size. + +The dimensions beyond the core dimensions are called "loop" dimensions. In +the above example, this corresponds to ``(3, 5)``. + +The signature determines how the dimensions of each input/output array are +split into core and loop dimensions: + +#. Each dimension in the signature is matched to a dimension of the + corresponding passed-in array, starting from the end of the shape tuple. + These are the core dimensions, and they must be present in the arrays, or + an error will be raised. +#. Core dimensions assigned to the same label in the signature (e.g. the + ``i`` in ``inner1d``'s ``(i),(i)->()``) must have exactly matching sizes, + no broadcasting is performed. +#. The core dimensions are removed from all inputs and the remaining + dimensions are broadcast together, defining the loop dimensions. +#. The shape of each output is determined from the loop dimensions plus the + output's core dimensions + +Typically, the size of all core dimensions in an output will be determined by +the size of a core dimension with the same label in an input array. This is +not a requirement, and it is possible to define a signature where a label +comes up for the first time in an output, although some precautions must be +taken when calling such a function. An example would be the function +``euclidean_pdist(a)``, with signature ``(n,d)->(p)``, that given an array of +``n`` ``d``-dimensional vectors, computes all unique pairwise Euclidean +distances among them. The output dimension ``p`` must therefore be equal to +``n * (n - 1) / 2``, but it is the caller's responsibility to pass in an +output array of the right size. If the size of a core dimension of an output +cannot be determined from a passed in input or output array, an error will be +raised. + +Note: Prior to NumPy 1.10.0, less strict checks were in place: missing core +dimensions were created by prepending 1's to the shape as necessary, core +dimensions with the same label were broadcast together, and undetermined +dimensions were created with size 1. + + +Definitions +----------- + +Elementary Function + Each ufunc consists of an elementary function that performs the + most basic operation on the smallest portion of array arguments + (e.g. adding two numbers is the most basic operation in adding two + arrays). The ufunc applies the elementary function multiple times + on different parts of the arrays. The input/output of elementary + functions can be vectors; e.g., the elementary function of inner1d + takes two vectors as input. + +Signature + A signature is a string describing the input/output dimensions of + the elementary function of a ufunc. See section below for more + details. + +Core Dimension + The dimensionality of each input/output of an elementary function + is defined by its core dimensions (zero core dimensions correspond + to a scalar input/output). The core dimensions are mapped to the + last dimensions of the input/output arrays. + +Dimension Name + A dimension name represents a core dimension in the signature. + Different dimensions may share a name, indicating that they are of + the same size. + +Dimension Index + A dimension index is an integer representing a dimension name. It + enumerates the dimension names according to the order of the first + occurrence of each name in the signature. + + +Details of Signature +-------------------- + +The signature defines "core" dimensionality of input and output +variables, and thereby also defines the contraction of the +dimensions. The signature is represented by a string of the +following format: + +* Core dimensions of each input or output array are represented by a + list of dimension names in parentheses, ``(i_1,...,i_N)``; a scalar + input/output is denoted by ``()``. Instead of ``i_1``, ``i_2``, + etc, one can use any valid Python variable name. +* Dimension lists for different arguments are separated by ``","``. + Input/output arguments are separated by ``"->"``. +* If one uses the same dimension name in multiple locations, this + enforces the same size of the corresponding dimensions. + +The formal syntax of signatures is as follows:: + + ::= "->" + ::= + ::= + ::= nil | | "," + ::= "(" ")" + ::= nil | | + "," + ::= valid Python variable name + + +Notes: + +#. All quotes are for clarity. +#. Core dimensions that share the same name must have the exact same size. + Each dimension name typically corresponds to one level of looping in the + elementary function's implementation. +#. White spaces are ignored. + +Here are some examples of signatures: + ++-------------+------------------------+-----------------------------------+ +| add | ``(),()->()`` | | ++-------------+------------------------+-----------------------------------+ +| inner1d | ``(i),(i)->()`` | | ++-------------+------------------------+-----------------------------------+ +| sum1d | ``(i)->()`` | | ++-------------+------------------------+-----------------------------------+ +| dot2d | ``(m,n),(n,p)->(m,p)`` | matrix multiplication | ++-------------+------------------------+-----------------------------------+ +| outer_inner | ``(i,t),(j,t)->(i,j)`` | inner over the last dimension, | +| | | outer over the second to last, | +| | | and loop/broadcast over the rest. | ++-------------+------------------------+-----------------------------------+ + +C-API for implementing Elementary Functions +------------------------------------------- + +The current interface remains unchanged, and ``PyUFunc_FromFuncAndData`` +can still be used to implement (specialized) ufuncs, consisting of +scalar elementary functions. + +One can use ``PyUFunc_FromFuncAndDataAndSignature`` to declare a more +general ufunc. The argument list is the same as +``PyUFunc_FromFuncAndData``, with an additional argument specifying the +signature as C string. + +Furthermore, the callback function is of the same type as before, +``void (*foo)(char **args, intp *dimensions, intp *steps, void *func)``. +When invoked, ``args`` is a list of length ``nargs`` containing +the data of all input/output arguments. For a scalar elementary +function, ``steps`` is also of length ``nargs``, denoting the strides used +for the arguments. ``dimensions`` is a pointer to a single integer +defining the size of the axis to be looped over. + +For a non-trivial signature, ``dimensions`` will also contain the sizes +of the core dimensions as well, starting at the second entry. Only +one size is provided for each unique dimension name and the sizes are +given according to the first occurrence of a dimension name in the +signature. + +The first ``nargs`` elements of ``steps`` remain the same as for scalar +ufuncs. The following elements contain the strides of all core +dimensions for all arguments in order. + +For example, consider a ufunc with signature ``(i,j),(i)->()``. In +this case, ``args`` will contain three pointers to the data of the +input/output arrays ``a``, ``b``, ``c``. Furthermore, ``dimensions`` will be +``[N, I, J]`` to define the size of ``N`` of the loop and the sizes ``I`` and ``J`` +for the core dimensions ``i`` and ``j``. Finally, ``steps`` will be +``[a_N, b_N, c_N, a_i, a_j, b_i]``, containing all necessary strides. diff --git a/doc/source/reference/c-api.iterator.rst b/doc/source/reference/c-api.iterator.rst new file mode 100644 index 0000000..4c59bce --- /dev/null +++ b/doc/source/reference/c-api.iterator.rst @@ -0,0 +1,1343 @@ +Array Iterator API +================== + +.. sectionauthor:: Mark Wiebe + +.. index:: + pair: iterator; C-API + pair: C-API; iterator + +.. versionadded:: 1.6 + +Array Iterator +-------------- + +The array iterator encapsulates many of the key features in ufuncs, +allowing user code to support features like output parameters, +preservation of memory layouts, and buffering of data with the wrong +alignment or type, without requiring difficult coding. + +This page documents the API for the iterator. +The iterator is named ``NpyIter`` and functions are +named ``NpyIter_*``. + +There is an :ref:`introductory guide to array iteration ` +which may be of interest for those using this C API. In many instances, +testing out ideas by creating the iterator in Python is a good idea +before writing the C iteration code. + +Simple Iteration Example +------------------------ + +The best way to become familiar with the iterator is to look at its +usage within the NumPy codebase itself. For example, here is a slightly +tweaked version of the code for :c:func:`PyArray_CountNonzero`, which counts the +number of non-zero elements in an array. + +.. code-block:: c + + npy_intp PyArray_CountNonzero(PyArrayObject* self) + { + /* Nonzero boolean function */ + PyArray_NonzeroFunc* nonzero = PyArray_DESCR(self)->f->nonzero; + + NpyIter* iter; + NpyIter_IterNextFunc *iternext; + char** dataptr; + npy_intp nonzero_count; + npy_intp* strideptr,* innersizeptr; + + /* Handle zero-sized arrays specially */ + if (PyArray_SIZE(self) == 0) { + return 0; + } + + /* + * Create and use an iterator to count the nonzeros. + * flag NPY_ITER_READONLY + * - The array is never written to. + * flag NPY_ITER_EXTERNAL_LOOP + * - Inner loop is done outside the iterator for efficiency. + * flag NPY_ITER_NPY_ITER_REFS_OK + * - Reference types are acceptable. + * order NPY_KEEPORDER + * - Visit elements in memory order, regardless of strides. + * This is good for performance when the specific order + * elements are visited is unimportant. + * casting NPY_NO_CASTING + * - No casting is required for this operation. + */ + iter = NpyIter_New(self, NPY_ITER_READONLY| + NPY_ITER_EXTERNAL_LOOP| + NPY_ITER_REFS_OK, + NPY_KEEPORDER, NPY_NO_CASTING, + NULL); + if (iter == NULL) { + return -1; + } + + /* + * The iternext function gets stored in a local variable + * so it can be called repeatedly in an efficient manner. + */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + return -1; + } + /* The location of the data pointer which the iterator may update */ + dataptr = NpyIter_GetDataPtrArray(iter); + /* The location of the stride which the iterator may update */ + strideptr = NpyIter_GetInnerStrideArray(iter); + /* The location of the inner loop size which the iterator may update */ + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + nonzero_count = 0; + do { + /* Get the inner loop data/stride/count values */ + char* data = *dataptr; + npy_intp stride = *strideptr; + npy_intp count = *innersizeptr; + + /* This is a typical inner loop for NPY_ITER_EXTERNAL_LOOP */ + while (count--) { + if (nonzero(data, self)) { + ++nonzero_count; + } + data += stride; + } + + /* Increment the iterator to the next inner loop */ + } while(iternext(iter)); + + NpyIter_Deallocate(iter); + + return nonzero_count; + } + +Simple Multi-Iteration Example +------------------------------ + +Here is a simple copy function using the iterator. The ``order`` parameter +is used to control the memory layout of the allocated result, typically +:c:data:`NPY_KEEPORDER` is desired. + +.. code-block:: c + + PyObject *CopyArray(PyObject *arr, NPY_ORDER order) + { + NpyIter *iter; + NpyIter_IterNextFunc *iternext; + PyObject *op[2], *ret; + npy_uint32 flags; + npy_uint32 op_flags[2]; + npy_intp itemsize, *innersizeptr, innerstride; + char **dataptrarray; + + /* + * No inner iteration - inner loop is handled by CopyArray code + */ + flags = NPY_ITER_EXTERNAL_LOOP; + /* + * Tell the constructor to automatically allocate the output. + * The data type of the output will match that of the input. + */ + op[0] = arr; + op[1] = NULL; + op_flags[0] = NPY_ITER_READONLY; + op_flags[1] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE; + + /* Construct the iterator */ + iter = NpyIter_MultiNew(2, op, flags, order, NPY_NO_CASTING, + op_flags, NULL); + if (iter == NULL) { + return NULL; + } + + /* + * Make a copy of the iternext function pointer and + * a few other variables the inner loop needs. + */ + iternext = NpyIter_GetIterNext(iter, NULL); + innerstride = NpyIter_GetInnerStrideArray(iter)[0]; + itemsize = NpyIter_GetDescrArray(iter)[0]->elsize; + /* + * The inner loop size and data pointers may change during the + * loop, so just cache the addresses. + */ + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + dataptrarray = NpyIter_GetDataPtrArray(iter); + + /* + * Note that because the iterator allocated the output, + * it matches the iteration order and is packed tightly, + * so we don't need to check it like the input. + */ + if (innerstride == itemsize) { + do { + memcpy(dataptrarray[1], dataptrarray[0], + itemsize * (*innersizeptr)); + } while (iternext(iter)); + } else { + /* For efficiency, should specialize this based on item size... */ + npy_intp i; + do { + npy_intp size = *innersizeptr; + char *src = dataptrarray[0], *dst = dataptrarray[1]; + for(i = 0; i < size; i++, src += innerstride, dst += itemsize) { + memcpy(dst, src, itemsize); + } + } while (iternext(iter)); + } + + /* Get the result from the iterator object array */ + ret = NpyIter_GetOperandArray(iter)[1]; + Py_INCREF(ret); + + if (NpyIter_Deallocate(iter) != NPY_SUCCEED) { + Py_DECREF(ret); + return NULL; + } + + return ret; + } + + +Iterator Data Types +--------------------- + +The iterator layout is an internal detail, and user code only sees +an incomplete struct. + +.. c:type:: NpyIter + + This is an opaque pointer type for the iterator. Access to its contents + can only be done through the iterator API. + +.. c:type:: NpyIter_Type + + This is the type which exposes the iterator to Python. Currently, no + API is exposed which provides access to the values of a Python-created + iterator. If an iterator is created in Python, it must be used in Python + and vice versa. Such an API will likely be created in a future version. + +.. c:type:: NpyIter_IterNextFunc + + This is a function pointer for the iteration loop, returned by + :c:func:`NpyIter_GetIterNext`. + +.. c:type:: NpyIter_GetMultiIndexFunc + + This is a function pointer for getting the current iterator multi-index, + returned by :c:func:`NpyIter_GetGetMultiIndex`. + +Construction and Destruction +---------------------------- + +.. c:function:: NpyIter* NpyIter_New( \ + PyArrayObject* op, npy_uint32 flags, NPY_ORDER order, \ + NPY_CASTING casting, PyArray_Descr* dtype) + + Creates an iterator for the given numpy array object ``op``. + + Flags that may be passed in ``flags`` are any combination + of the global and per-operand flags documented in + :c:func:`NpyIter_MultiNew`, except for :c:data:`NPY_ITER_ALLOCATE`. + + Any of the :c:type:`NPY_ORDER` enum values may be passed to ``order``. For + efficient iteration, :c:type:`NPY_KEEPORDER` is the best option, and + the other orders enforce the particular iteration pattern. + + Any of the :c:type:`NPY_CASTING` enum values may be passed to ``casting``. + The values include :c:data:`NPY_NO_CASTING`, :c:data:`NPY_EQUIV_CASTING`, + :c:data:`NPY_SAFE_CASTING`, :c:data:`NPY_SAME_KIND_CASTING`, and + :c:data:`NPY_UNSAFE_CASTING`. To allow the casts to occur, copying or + buffering must also be enabled. + + If ``dtype`` isn't ``NULL``, then it requires that data type. + If copying is allowed, it will make a temporary copy if the data + is castable. If :c:data:`NPY_ITER_UPDATEIFCOPY` is enabled, it will + also copy the data back with another cast upon iterator destruction. + + Returns NULL if there is an error, otherwise returns the allocated + iterator. + + To make an iterator similar to the old iterator, this should work. + + .. code-block:: c + + iter = NpyIter_New(op, NPY_ITER_READWRITE, + NPY_CORDER, NPY_NO_CASTING, NULL); + + If you want to edit an array with aligned ``double`` code, + but the order doesn't matter, you would use this. + + .. code-block:: c + + dtype = PyArray_DescrFromType(NPY_DOUBLE); + iter = NpyIter_New(op, NPY_ITER_READWRITE| + NPY_ITER_BUFFERED| + NPY_ITER_NBO| + NPY_ITER_ALIGNED, + NPY_KEEPORDER, + NPY_SAME_KIND_CASTING, + dtype); + Py_DECREF(dtype); + +.. c:function:: NpyIter* NpyIter_MultiNew( \ + npy_intp nop, PyArrayObject** op, npy_uint32 flags, NPY_ORDER order, \ + NPY_CASTING casting, npy_uint32* op_flags, PyArray_Descr** op_dtypes) + + Creates an iterator for broadcasting the ``nop`` array objects provided + in ``op``, using regular NumPy broadcasting rules. + + Any of the :c:type:`NPY_ORDER` enum values may be passed to ``order``. For + efficient iteration, :c:data:`NPY_KEEPORDER` is the best option, and the + other orders enforce the particular iteration pattern. When using + :c:data:`NPY_KEEPORDER`, if you also want to ensure that the iteration is + not reversed along an axis, you should pass the flag + :c:data:`NPY_ITER_DONT_NEGATE_STRIDES`. + + Any of the :c:type:`NPY_CASTING` enum values may be passed to ``casting``. + The values include :c:data:`NPY_NO_CASTING`, :c:data:`NPY_EQUIV_CASTING`, + :c:data:`NPY_SAFE_CASTING`, :c:data:`NPY_SAME_KIND_CASTING`, and + :c:data:`NPY_UNSAFE_CASTING`. To allow the casts to occur, copying or + buffering must also be enabled. + + If ``op_dtypes`` isn't ``NULL``, it specifies a data type or ``NULL`` + for each ``op[i]``. + + Returns NULL if there is an error, otherwise returns the allocated + iterator. + + Flags that may be passed in ``flags``, applying to the whole + iterator, are: + + .. c:var:: NPY_ITER_C_INDEX + + Causes the iterator to track a raveled flat index matching C + order. This option cannot be used with :c:data:`NPY_ITER_F_INDEX`. + + .. c:var:: NPY_ITER_F_INDEX + + Causes the iterator to track a raveled flat index matching Fortran + order. This option cannot be used with :c:data:`NPY_ITER_C_INDEX`. + + .. c:var:: NPY_ITER_MULTI_INDEX + + Causes the iterator to track a multi-index. + This prevents the iterator from coalescing axes to + produce bigger inner loops. If the loop is also not buffered + and no index is being tracked (`NpyIter_RemoveAxis` can be called), + then the iterator size can be ``-1`` to indicate that the iterator + is too large. This can happen due to complex broadcasting and + will result in errors being created when the setting the iterator + range, removing the multi index, or getting the next function. + However, it is possible to remove axes again and use the iterator + normally if the size is small enough after removal. + + .. c:var:: NPY_ITER_EXTERNAL_LOOP + + Causes the iterator to skip iteration of the innermost + loop, requiring the user of the iterator to handle it. + + This flag is incompatible with :c:data:`NPY_ITER_C_INDEX`, + :c:data:`NPY_ITER_F_INDEX`, and :c:data:`NPY_ITER_MULTI_INDEX`. + + .. c:var:: NPY_ITER_DONT_NEGATE_STRIDES + + This only affects the iterator when :c:type:`NPY_KEEPORDER` is + specified for the order parameter. By default with + :c:type:`NPY_KEEPORDER`, the iterator reverses axes which have + negative strides, so that memory is traversed in a forward + direction. This disables this step. Use this flag if you + want to use the underlying memory-ordering of the axes, + but don't want an axis reversed. This is the behavior of + ``numpy.ravel(a, order='K')``, for instance. + + .. c:var:: NPY_ITER_COMMON_DTYPE + + Causes the iterator to convert all the operands to a common + data type, calculated based on the ufunc type promotion rules. + Copying or buffering must be enabled. + + If the common data type is known ahead of time, don't use this + flag. Instead, set the requested dtype for all the operands. + + .. c:var:: NPY_ITER_REFS_OK + + Indicates that arrays with reference types (object + arrays or structured arrays containing an object type) + may be accepted and used in the iterator. If this flag + is enabled, the caller must be sure to check whether + :c:func:`NpyIter_IterationNeedsAPI(iter)` is true, in which case + it may not release the GIL during iteration. + + .. c:var:: NPY_ITER_ZEROSIZE_OK + + Indicates that arrays with a size of zero should be permitted. + Since the typical iteration loop does not naturally work with + zero-sized arrays, you must check that the IterSize is larger + than zero before entering the iteration loop. + Currently only the operands are checked, not a forced shape. + + .. c:var:: NPY_ITER_REDUCE_OK + + Permits writeable operands with a dimension with zero + stride and size greater than one. Note that such operands + must be read/write. + + When buffering is enabled, this also switches to a special + buffering mode which reduces the loop length as necessary to + not trample on values being reduced. + + Note that if you want to do a reduction on an automatically + allocated output, you must use :c:func:`NpyIter_GetOperandArray` + to get its reference, then set every value to the reduction + unit before doing the iteration loop. In the case of a + buffered reduction, this means you must also specify the + flag :c:data:`NPY_ITER_DELAY_BUFALLOC`, then reset the iterator + after initializing the allocated operand to prepare the + buffers. + + .. c:var:: NPY_ITER_RANGED + + Enables support for iteration of sub-ranges of the full + ``iterindex`` range ``[0, NpyIter_IterSize(iter))``. Use + the function :c:func:`NpyIter_ResetToIterIndexRange` to specify + a range for iteration. + + This flag can only be used with :c:data:`NPY_ITER_EXTERNAL_LOOP` + when :c:data:`NPY_ITER_BUFFERED` is enabled. This is because + without buffering, the inner loop is always the size of the + innermost iteration dimension, and allowing it to get cut up + would require special handling, effectively making it more + like the buffered version. + + .. c:var:: NPY_ITER_BUFFERED + + Causes the iterator to store buffering data, and use buffering + to satisfy data type, alignment, and byte-order requirements. + To buffer an operand, do not specify the :c:data:`NPY_ITER_COPY` + or :c:data:`NPY_ITER_UPDATEIFCOPY` flags, because they will + override buffering. Buffering is especially useful for Python + code using the iterator, allowing for larger chunks + of data at once to amortize the Python interpreter overhead. + + If used with :c:data:`NPY_ITER_EXTERNAL_LOOP`, the inner loop + for the caller may get larger chunks than would be possible + without buffering, because of how the strides are laid out. + + Note that if an operand is given the flag :c:data:`NPY_ITER_COPY` + or :c:data:`NPY_ITER_UPDATEIFCOPY`, a copy will be made in preference + to buffering. Buffering will still occur when the array was + broadcast so elements need to be duplicated to get a constant + stride. + + In normal buffering, the size of each inner loop is equal + to the buffer size, or possibly larger if + :c:data:`NPY_ITER_GROWINNER` is specified. If + :c:data:`NPY_ITER_REDUCE_OK` is enabled and a reduction occurs, + the inner loops may become smaller depending + on the structure of the reduction. + + .. c:var:: NPY_ITER_GROWINNER + + When buffering is enabled, this allows the size of the inner + loop to grow when buffering isn't necessary. This option + is best used if you're doing a straight pass through all the + data, rather than anything with small cache-friendly arrays + of temporary values for each inner loop. + + .. c:var:: NPY_ITER_DELAY_BUFALLOC + + When buffering is enabled, this delays allocation of the + buffers until :c:func:`NpyIter_Reset` or another reset function is + called. This flag exists to avoid wasteful copying of + buffer data when making multiple copies of a buffered + iterator for multi-threaded iteration. + + Another use of this flag is for setting up reduction operations. + After the iterator is created, and a reduction output + is allocated automatically by the iterator (be sure to use + READWRITE access), its value may be initialized to the reduction + unit. Use :c:func:`NpyIter_GetOperandArray` to get the object. + Then, call :c:func:`NpyIter_Reset` to allocate and fill the buffers + with their initial values. + + .. c:var:: NPY_ITER_COPY_IF_OVERLAP + + If any write operand has overlap with any read operand, eliminate all + overlap by making temporary copies (enabling UPDATEIFCOPY for write + operands, if necessary). A pair of operands has overlap if there is + a memory address that contains data common to both arrays. + + Because exact overlap detection has exponential runtime + in the number of dimensions, the decision is made based + on heuristics, which has false positives (needless copies in unusual + cases) but has no false negatives. + + If any read/write overlap exists, this flag ensures the result of the + operation is the same as if all operands were copied. + In cases where copies would need to be made, **the result of the + computation may be undefined without this flag!** + + Flags that may be passed in ``op_flags[i]``, where ``0 <= i < nop``: + + .. c:var:: NPY_ITER_READWRITE + .. c:var:: NPY_ITER_READONLY + .. c:var:: NPY_ITER_WRITEONLY + + Indicate how the user of the iterator will read or write + to ``op[i]``. Exactly one of these flags must be specified + per operand. + + .. c:var:: NPY_ITER_COPY + + Allow a copy of ``op[i]`` to be made if it does not + meet the data type or alignment requirements as specified + by the constructor flags and parameters. + + .. c:var:: NPY_ITER_UPDATEIFCOPY + + Triggers :c:data:`NPY_ITER_COPY`, and when an array operand + is flagged for writing and is copied, causes the data + in a copy to be copied back to ``op[i]`` when the iterator + is destroyed. + + If the operand is flagged as write-only and a copy is needed, + an uninitialized temporary array will be created and then copied + to back to ``op[i]`` on destruction, instead of doing + the unnecessary copy operation. + + .. c:var:: NPY_ITER_NBO + .. c:var:: NPY_ITER_ALIGNED + .. c:var:: NPY_ITER_CONTIG + + Causes the iterator to provide data for ``op[i]`` + that is in native byte order, aligned according to + the dtype requirements, contiguous, or any combination. + + By default, the iterator produces pointers into the + arrays provided, which may be aligned or unaligned, and + with any byte order. If copying or buffering is not + enabled and the operand data doesn't satisfy the constraints, + an error will be raised. + + The contiguous constraint applies only to the inner loop, + successive inner loops may have arbitrary pointer changes. + + If the requested data type is in non-native byte order, + the NBO flag overrides it and the requested data type is + converted to be in native byte order. + + .. c:var:: NPY_ITER_ALLOCATE + + This is for output arrays, and requires that the flag + :c:data:`NPY_ITER_WRITEONLY` or :c:data:`NPY_ITER_READWRITE` + be set. If ``op[i]`` is NULL, creates a new array with + the final broadcast dimensions, and a layout matching + the iteration order of the iterator. + + When ``op[i]`` is NULL, the requested data type + ``op_dtypes[i]`` may be NULL as well, in which case it is + automatically generated from the dtypes of the arrays which + are flagged as readable. The rules for generating the dtype + are the same is for UFuncs. Of special note is handling + of byte order in the selected dtype. If there is exactly + one input, the input's dtype is used as is. Otherwise, + if more than one input dtypes are combined together, the + output will be in native byte order. + + After being allocated with this flag, the caller may retrieve + the new array by calling :c:func:`NpyIter_GetOperandArray` and + getting the i-th object in the returned C array. The caller + must call Py_INCREF on it to claim a reference to the array. + + .. c:var:: NPY_ITER_NO_SUBTYPE + + For use with :c:data:`NPY_ITER_ALLOCATE`, this flag disables + allocating an array subtype for the output, forcing + it to be a straight ndarray. + + TODO: Maybe it would be better to introduce a function + ``NpyIter_GetWrappedOutput`` and remove this flag? + + .. c:var:: NPY_ITER_NO_BROADCAST + + Ensures that the input or output matches the iteration + dimensions exactly. + + .. c:var:: NPY_ITER_ARRAYMASK + + .. versionadded:: 1.7 + + Indicates that this operand is the mask to use for + selecting elements when writing to operands which have + the :c:data:`NPY_ITER_WRITEMASKED` flag applied to them. + Only one operand may have :c:data:`NPY_ITER_ARRAYMASK` flag + applied to it. + + The data type of an operand with this flag should be either + :c:data:`NPY_BOOL`, :c:data:`NPY_MASK`, or a struct dtype + whose fields are all valid mask dtypes. In the latter case, + it must match up with a struct operand being WRITEMASKED, + as it is specifying a mask for each field of that array. + + This flag only affects writing from the buffer back to + the array. This means that if the operand is also + :c:data:`NPY_ITER_READWRITE` or :c:data:`NPY_ITER_WRITEONLY`, + code doing iteration can write to this operand to + control which elements will be untouched and which ones will be + modified. This is useful when the mask should be a combination + of input masks, for example. Mask values can be created + with the :c:func:`NpyMask_Create` function. + + .. c:var:: NPY_ITER_WRITEMASKED + + .. versionadded:: 1.7 + + Indicates that only elements which the operand with + the ARRAYMASK flag indicates are intended to be modified + by the iteration. In general, the iterator does not enforce + this, it is up to the code doing the iteration to follow + that promise. Code can use the :c:func:`NpyMask_IsExposed` + inline function to test whether the mask at a particular + element allows writing. + + When this flag is used, and this operand is buffered, this + changes how data is copied from the buffer into the array. + A masked copying routine is used, which only copies the + elements in the buffer for which :c:func:`NpyMask_IsExposed` + returns true from the corresponding element in the ARRAYMASK + operand. + + .. c:var:: NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE + + In memory overlap checks, assume that operands with + ``NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE`` enabled are accessed only + in the iterator order. + + This enables the iterator to reason about data dependency, + possibly avoiding unnecessary copies. + + This flag has effect only if ``NPY_ITER_COPY_IF_OVERLAP`` is enabled + on the iterator. + +.. c:function:: NpyIter* NpyIter_AdvancedNew( \ + npy_intp nop, PyArrayObject** op, npy_uint32 flags, NPY_ORDER order, \ + NPY_CASTING casting, npy_uint32* op_flags, PyArray_Descr** op_dtypes, \ + int oa_ndim, int** op_axes, npy_intp* itershape, npy_intp buffersize) + + Extends :c:func:`NpyIter_MultiNew` with several advanced options providing + more control over broadcasting and buffering. + + If -1/NULL values are passed to ``oa_ndim``, ``op_axes``, ``itershape``, + and ``buffersize``, it is equivalent to :c:func:`NpyIter_MultiNew`. + + The parameter ``oa_ndim``, when not zero or -1, specifies the number of + dimensions that will be iterated with customized broadcasting. + If it is provided, ``op_axes`` must and ``itershape`` can also be provided. + The ``op_axes`` parameter let you control in detail how the + axes of the operand arrays get matched together and iterated. + In ``op_axes``, you must provide an array of ``nop`` pointers + to ``oa_ndim``-sized arrays of type ``npy_intp``. If an entry + in ``op_axes`` is NULL, normal broadcasting rules will apply. + In ``op_axes[j][i]`` is stored either a valid axis of ``op[j]``, or + -1 which means ``newaxis``. Within each ``op_axes[j]`` array, axes + may not be repeated. The following example is how normal broadcasting + applies to a 3-D array, a 2-D array, a 1-D array and a scalar. + + **Note**: Before NumPy 1.8 ``oa_ndim == 0` was used for signalling that + that ``op_axes`` and ``itershape`` are unused. This is deprecated and + should be replaced with -1. Better backward compatibility may be + achieved by using :c:func:`NpyIter_MultiNew` for this case. + + .. code-block:: c + + int oa_ndim = 3; /* # iteration axes */ + int op0_axes[] = {0, 1, 2}; /* 3-D operand */ + int op1_axes[] = {-1, 0, 1}; /* 2-D operand */ + int op2_axes[] = {-1, -1, 0}; /* 1-D operand */ + int op3_axes[] = {-1, -1, -1} /* 0-D (scalar) operand */ + int* op_axes[] = {op0_axes, op1_axes, op2_axes, op3_axes}; + + The ``itershape`` parameter allows you to force the iterator + to have a specific iteration shape. It is an array of length + ``oa_ndim``. When an entry is negative, its value is determined + from the operands. This parameter allows automatically allocated + outputs to get additional dimensions which don't match up with + any dimension of an input. + + If ``buffersize`` is zero, a default buffer size is used, + otherwise it specifies how big of a buffer to use. Buffers + which are powers of 2 such as 4096 or 8192 are recommended. + + Returns NULL if there is an error, otherwise returns the allocated + iterator. + +.. c:function:: NpyIter* NpyIter_Copy(NpyIter* iter) + + Makes a copy of the given iterator. This function is provided + primarily to enable multi-threaded iteration of the data. + + *TODO*: Move this to a section about multithreaded iteration. + + The recommended approach to multithreaded iteration is to + first create an iterator with the flags + :c:data:`NPY_ITER_EXTERNAL_LOOP`, :c:data:`NPY_ITER_RANGED`, + :c:data:`NPY_ITER_BUFFERED`, :c:data:`NPY_ITER_DELAY_BUFALLOC`, and + possibly :c:data:`NPY_ITER_GROWINNER`. Create a copy of this iterator + for each thread (minus one for the first iterator). Then, take + the iteration index range ``[0, NpyIter_GetIterSize(iter))`` and + split it up into tasks, for example using a TBB parallel_for loop. + When a thread gets a task to execute, it then uses its copy of + the iterator by calling :c:func:`NpyIter_ResetToIterIndexRange` and + iterating over the full range. + + When using the iterator in multi-threaded code or in code not + holding the Python GIL, care must be taken to only call functions + which are safe in that context. :c:func:`NpyIter_Copy` cannot be safely + called without the Python GIL, because it increments Python + references. The ``Reset*`` and some other functions may be safely + called by passing in the ``errmsg`` parameter as non-NULL, so that + the functions will pass back errors through it instead of setting + a Python exception. + +.. c:function:: int NpyIter_RemoveAxis(NpyIter* iter, int axis)`` + + Removes an axis from iteration. This requires that + :c:data:`NPY_ITER_MULTI_INDEX` was set for iterator creation, and does + not work if buffering is enabled or an index is being tracked. This + function also resets the iterator to its initial state. + + This is useful for setting up an accumulation loop, for example. + The iterator can first be created with all the dimensions, including + the accumulation axis, so that the output gets created correctly. + Then, the accumulation axis can be removed, and the calculation + done in a nested fashion. + + **WARNING**: This function may change the internal memory layout of + the iterator. Any cached functions or pointers from the iterator + must be retrieved again! The iterator range will be reset as well. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + + +.. c:function:: int NpyIter_RemoveMultiIndex(NpyIter* iter) + + If the iterator is tracking a multi-index, this strips support for them, + and does further iterator optimizations that are possible if multi-indices + are not needed. This function also resets the iterator to its initial + state. + + **WARNING**: This function may change the internal memory layout of + the iterator. Any cached functions or pointers from the iterator + must be retrieved again! + + After calling this function, :c:func:`NpyIter_HasMultiIndex(iter)` will + return false. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + +.. c:function:: int NpyIter_EnableExternalLoop(NpyIter* iter) + + If :c:func:`NpyIter_RemoveMultiIndex` was called, you may want to enable the + flag :c:data:`NPY_ITER_EXTERNAL_LOOP`. This flag is not permitted + together with :c:data:`NPY_ITER_MULTI_INDEX`, so this function is provided + to enable the feature after :c:func:`NpyIter_RemoveMultiIndex` is called. + This function also resets the iterator to its initial state. + + **WARNING**: This function changes the internal logic of the iterator. + Any cached functions or pointers from the iterator must be retrieved + again! + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + +.. c:function:: int NpyIter_Deallocate(NpyIter* iter) + + Deallocates the iterator object. This additionally frees any + copies made, triggering UPDATEIFCOPY behavior where necessary. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + +.. c:function:: int NpyIter_Reset(NpyIter* iter, char** errmsg) + + Resets the iterator back to its initial state, at the beginning + of the iteration range. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. If errmsg is non-NULL, + no Python exception is set when ``NPY_FAIL`` is returned. + Instead, \*errmsg is set to an error message. When errmsg is + non-NULL, the function may be safely called without holding + the Python GIL. + +.. c:function:: int NpyIter_ResetToIterIndexRange( \ + NpyIter* iter, npy_intp istart, npy_intp iend, char** errmsg) + + Resets the iterator and restricts it to the ``iterindex`` range + ``[istart, iend)``. See :c:func:`NpyIter_Copy` for an explanation of + how to use this for multi-threaded iteration. This requires that + the flag :c:data:`NPY_ITER_RANGED` was passed to the iterator constructor. + + If you want to reset both the ``iterindex`` range and the base + pointers at the same time, you can do the following to avoid + extra buffer copying (be sure to add the return code error checks + when you copy this code). + + .. code-block:: c + + /* Set to a trivial empty range */ + NpyIter_ResetToIterIndexRange(iter, 0, 0); + /* Set the base pointers */ + NpyIter_ResetBasePointers(iter, baseptrs); + /* Set to the desired range */ + NpyIter_ResetToIterIndexRange(iter, istart, iend); + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. If errmsg is non-NULL, + no Python exception is set when ``NPY_FAIL`` is returned. + Instead, \*errmsg is set to an error message. When errmsg is + non-NULL, the function may be safely called without holding + the Python GIL. + +.. c:function:: int NpyIter_ResetBasePointers( \ + NpyIter *iter, char** baseptrs, char** errmsg) + + Resets the iterator back to its initial state, but using the values + in ``baseptrs`` for the data instead of the pointers from the arrays + being iterated. This functions is intended to be used, together with + the ``op_axes`` parameter, by nested iteration code with two or more + iterators. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. If errmsg is non-NULL, + no Python exception is set when ``NPY_FAIL`` is returned. + Instead, \*errmsg is set to an error message. When errmsg is + non-NULL, the function may be safely called without holding + the Python GIL. + + *TODO*: Move the following into a special section on nested iterators. + + Creating iterators for nested iteration requires some care. All + the iterator operands must match exactly, or the calls to + :c:func:`NpyIter_ResetBasePointers` will be invalid. This means that + automatic copies and output allocation should not be used haphazardly. + It is possible to still use the automatic data conversion and casting + features of the iterator by creating one of the iterators with + all the conversion parameters enabled, then grabbing the allocated + operands with the :c:func:`NpyIter_GetOperandArray` function and passing + them into the constructors for the rest of the iterators. + + **WARNING**: When creating iterators for nested iteration, + the code must not use a dimension more than once in the different + iterators. If this is done, nested iteration will produce + out-of-bounds pointers during iteration. + + **WARNING**: When creating iterators for nested iteration, buffering + can only be applied to the innermost iterator. If a buffered iterator + is used as the source for ``baseptrs``, it will point into a small buffer + instead of the array and the inner iteration will be invalid. + + The pattern for using nested iterators is as follows. + + .. code-block:: c + + NpyIter *iter1, *iter1; + NpyIter_IterNextFunc *iternext1, *iternext2; + char **dataptrs1; + + /* + * With the exact same operands, no copies allowed, and + * no axis in op_axes used both in iter1 and iter2. + * Buffering may be enabled for iter2, but not for iter1. + */ + iter1 = ...; iter2 = ...; + + iternext1 = NpyIter_GetIterNext(iter1); + iternext2 = NpyIter_GetIterNext(iter2); + dataptrs1 = NpyIter_GetDataPtrArray(iter1); + + do { + NpyIter_ResetBasePointers(iter2, dataptrs1); + do { + /* Use the iter2 values */ + } while (iternext2(iter2)); + } while (iternext1(iter1)); + +.. c:function:: int NpyIter_GotoMultiIndex(NpyIter* iter, npy_intp* multi_index) + + Adjusts the iterator to point to the ``ndim`` indices + pointed to by ``multi_index``. Returns an error if a multi-index + is not being tracked, the indices are out of bounds, + or inner loop iteration is disabled. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + +.. c:function:: int NpyIter_GotoIndex(NpyIter* iter, npy_intp index) + + Adjusts the iterator to point to the ``index`` specified. + If the iterator was constructed with the flag + :c:data:`NPY_ITER_C_INDEX`, ``index`` is the C-order index, + and if the iterator was constructed with the flag + :c:data:`NPY_ITER_F_INDEX`, ``index`` is the Fortran-order + index. Returns an error if there is no index being tracked, + the index is out of bounds, or inner loop iteration is disabled. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + +.. c:function:: npy_intp NpyIter_GetIterSize(NpyIter* iter) + + Returns the number of elements being iterated. This is the product + of all the dimensions in the shape. When a multi index is being tracked + (and `NpyIter_RemoveAxis` may be called) the size may be ``-1`` to + indicate an iterator is too large. Such an iterator is invalid, but + may become valid after `NpyIter_RemoveAxis` is called. It is not + necessary to check for this case. + +.. c:function:: npy_intp NpyIter_GetIterIndex(NpyIter* iter) + + Gets the ``iterindex`` of the iterator, which is an index matching + the iteration order of the iterator. + +.. c:function:: void NpyIter_GetIterIndexRange( \ + NpyIter* iter, npy_intp* istart, npy_intp* iend) + + Gets the ``iterindex`` sub-range that is being iterated. If + :c:data:`NPY_ITER_RANGED` was not specified, this always returns the + range ``[0, NpyIter_IterSize(iter))``. + +.. c:function:: int NpyIter_GotoIterIndex(NpyIter* iter, npy_intp iterindex) + + Adjusts the iterator to point to the ``iterindex`` specified. + The IterIndex is an index matching the iteration order of the iterator. + Returns an error if the ``iterindex`` is out of bounds, + buffering is enabled, or inner loop iteration is disabled. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + +.. c:function:: npy_bool NpyIter_HasDelayedBufAlloc(NpyIter* iter) + + Returns 1 if the flag :c:data:`NPY_ITER_DELAY_BUFALLOC` was passed + to the iterator constructor, and no call to one of the Reset + functions has been done yet, 0 otherwise. + +.. c:function:: npy_bool NpyIter_HasExternalLoop(NpyIter* iter) + + Returns 1 if the caller needs to handle the inner-most 1-dimensional + loop, or 0 if the iterator handles all looping. This is controlled + by the constructor flag :c:data:`NPY_ITER_EXTERNAL_LOOP` or + :c:func:`NpyIter_EnableExternalLoop`. + +.. c:function:: npy_bool NpyIter_HasMultiIndex(NpyIter* iter) + + Returns 1 if the iterator was created with the + :c:data:`NPY_ITER_MULTI_INDEX` flag, 0 otherwise. + +.. c:function:: npy_bool NpyIter_HasIndex(NpyIter* iter) + + Returns 1 if the iterator was created with the + :c:data:`NPY_ITER_C_INDEX` or :c:data:`NPY_ITER_F_INDEX` + flag, 0 otherwise. + +.. c:function:: npy_bool NpyIter_RequiresBuffering(NpyIter* iter) + + Returns 1 if the iterator requires buffering, which occurs + when an operand needs conversion or alignment and so cannot + be used directly. + +.. c:function:: npy_bool NpyIter_IsBuffered(NpyIter* iter) + + Returns 1 if the iterator was created with the + :c:data:`NPY_ITER_BUFFERED` flag, 0 otherwise. + +.. c:function:: npy_bool NpyIter_IsGrowInner(NpyIter* iter) + + Returns 1 if the iterator was created with the + :c:data:`NPY_ITER_GROWINNER` flag, 0 otherwise. + +.. c:function:: npy_intp NpyIter_GetBufferSize(NpyIter* iter) + + If the iterator is buffered, returns the size of the buffer + being used, otherwise returns 0. + +.. c:function:: int NpyIter_GetNDim(NpyIter* iter) + + Returns the number of dimensions being iterated. If a multi-index + was not requested in the iterator constructor, this value + may be smaller than the number of dimensions in the original + objects. + +.. c:function:: int NpyIter_GetNOp(NpyIter* iter) + + Returns the number of operands in the iterator. + + When :c:data:`NPY_ITER_USE_MASKNA` is used on an operand, a new + operand is added to the end of the operand list in the iterator + to track that operand's NA mask. Thus, this equals the number + of construction operands plus the number of operands for + which the flag :c:data:`NPY_ITER_USE_MASKNA` was specified. + +.. c:function:: int NpyIter_GetFirstMaskNAOp(NpyIter* iter) + + .. versionadded:: 1.7 + + Returns the index of the first NA mask operand in the array. This + value is equal to the number of operands passed into the constructor. + +.. c:function:: npy_intp* NpyIter_GetAxisStrideArray(NpyIter* iter, int axis) + + Gets the array of strides for the specified axis. Requires that + the iterator be tracking a multi-index, and that buffering not + be enabled. + + This may be used when you want to match up operand axes in + some fashion, then remove them with :c:func:`NpyIter_RemoveAxis` to + handle their processing manually. By calling this function + before removing the axes, you can get the strides for the + manual processing. + + Returns ``NULL`` on error. + +.. c:function:: int NpyIter_GetShape(NpyIter* iter, npy_intp* outshape) + + Returns the broadcast shape of the iterator in ``outshape``. + This can only be called on an iterator which is tracking a multi-index. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + +.. c:function:: PyArray_Descr** NpyIter_GetDescrArray(NpyIter* iter) + + This gives back a pointer to the ``nop`` data type Descrs for + the objects being iterated. The result points into ``iter``, + so the caller does not gain any references to the Descrs. + + This pointer may be cached before the iteration loop, calling + ``iternext`` will not change it. + +.. c:function:: PyObject** NpyIter_GetOperandArray(NpyIter* iter) + + This gives back a pointer to the ``nop`` operand PyObjects + that are being iterated. The result points into ``iter``, + so the caller does not gain any references to the PyObjects. + +.. c:function:: npy_int8* NpyIter_GetMaskNAIndexArray(NpyIter* iter) + + .. versionadded:: 1.7 + + This gives back a pointer to the ``nop`` indices which map + construction operands with :c:data:`NPY_ITER_USE_MASKNA` flagged + to their corresponding NA mask operands and vice versa. For + operands which were not flagged with :c:data:`NPY_ITER_USE_MASKNA`, + this array contains negative values. + +.. c:function:: PyObject* NpyIter_GetIterView(NpyIter* iter, npy_intp i) + + This gives back a reference to a new ndarray view, which is a view + into the i-th object in the array :c:func:`NpyIter_GetOperandArray()`, + whose dimensions and strides match the internal optimized + iteration pattern. A C-order iteration of this view is equivalent + to the iterator's iteration order. + + For example, if an iterator was created with a single array as its + input, and it was possible to rearrange all its axes and then + collapse it into a single strided iteration, this would return + a view that is a one-dimensional array. + +.. c:function:: void NpyIter_GetReadFlags(NpyIter* iter, char* outreadflags) + + Fills ``nop`` flags. Sets ``outreadflags[i]`` to 1 if + ``op[i]`` can be read from, and to 0 if not. + +.. c:function:: void NpyIter_GetWriteFlags(NpyIter* iter, char* outwriteflags) + + Fills ``nop`` flags. Sets ``outwriteflags[i]`` to 1 if + ``op[i]`` can be written to, and to 0 if not. + +.. c:function:: int NpyIter_CreateCompatibleStrides( \ + NpyIter* iter, npy_intp itemsize, npy_intp* outstrides) + + Builds a set of strides which are the same as the strides of an + output array created using the :c:data:`NPY_ITER_ALLOCATE` flag, where NULL + was passed for op_axes. This is for data packed contiguously, + but not necessarily in C or Fortran order. This should be used + together with :c:func:`NpyIter_GetShape` and :c:func:`NpyIter_GetNDim` + with the flag :c:data:`NPY_ITER_MULTI_INDEX` passed into the constructor. + + A use case for this function is to match the shape and layout of + the iterator and tack on one or more dimensions. For example, + in order to generate a vector per input value for a numerical gradient, + you pass in ndim*itemsize for itemsize, then add another dimension to + the end with size ndim and stride itemsize. To do the Hessian matrix, + you do the same thing but add two dimensions, or take advantage of + the symmetry and pack it into 1 dimension with a particular encoding. + + This function may only be called if the iterator is tracking a multi-index + and if :c:data:`NPY_ITER_DONT_NEGATE_STRIDES` was used to prevent an axis + from being iterated in reverse order. + + If an array is created with this method, simply adding 'itemsize' + for each iteration will traverse the new array matching the + iterator. + + Returns ``NPY_SUCCEED`` or ``NPY_FAIL``. + +.. c:function:: npy_bool NpyIter_IsFirstVisit(NpyIter* iter, int iop) + + .. versionadded:: 1.7 + + Checks to see whether this is the first time the elements of the + specified reduction operand which the iterator points at are being + seen for the first time. The function returns a reasonable answer + for reduction operands and when buffering is disabled. The answer + may be incorrect for buffered non-reduction operands. + + This function is intended to be used in EXTERNAL_LOOP mode only, + and will produce some wrong answers when that mode is not enabled. + + If this function returns true, the caller should also check the inner + loop stride of the operand, because if that stride is 0, then only + the first element of the innermost external loop is being visited + for the first time. + + *WARNING*: For performance reasons, 'iop' is not bounds-checked, + it is not confirmed that 'iop' is actually a reduction operand, + and it is not confirmed that EXTERNAL_LOOP mode is enabled. These + checks are the responsibility of the caller, and should be done + outside of any inner loops. + +Functions For Iteration +----------------------- + +.. c:function:: NpyIter_IterNextFunc* NpyIter_GetIterNext( \ + NpyIter* iter, char** errmsg) + + Returns a function pointer for iteration. A specialized version + of the function pointer may be calculated by this function + instead of being stored in the iterator structure. Thus, to + get good performance, it is required that the function pointer + be saved in a variable rather than retrieved for each loop iteration. + + Returns NULL if there is an error. If errmsg is non-NULL, + no Python exception is set when ``NPY_FAIL`` is returned. + Instead, \*errmsg is set to an error message. When errmsg is + non-NULL, the function may be safely called without holding + the Python GIL. + + The typical looping construct is as follows. + + .. code-block:: c + + NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(iter, NULL); + char** dataptr = NpyIter_GetDataPtrArray(iter); + + do { + /* use the addresses dataptr[0], ... dataptr[nop-1] */ + } while(iternext(iter)); + + When :c:data:`NPY_ITER_EXTERNAL_LOOP` is specified, the typical + inner loop construct is as follows. + + .. code-block:: c + + NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(iter, NULL); + char** dataptr = NpyIter_GetDataPtrArray(iter); + npy_intp* stride = NpyIter_GetInnerStrideArray(iter); + npy_intp* size_ptr = NpyIter_GetInnerLoopSizePtr(iter), size; + npy_intp iop, nop = NpyIter_GetNOp(iter); + + do { + size = *size_ptr; + while (size--) { + /* use the addresses dataptr[0], ... dataptr[nop-1] */ + for (iop = 0; iop < nop; ++iop) { + dataptr[iop] += stride[iop]; + } + } + } while (iternext()); + + Observe that we are using the dataptr array inside the iterator, not + copying the values to a local temporary. This is possible because + when ``iternext()`` is called, these pointers will be overwritten + with fresh values, not incrementally updated. + + If a compile-time fixed buffer is being used (both flags + :c:data:`NPY_ITER_BUFFERED` and :c:data:`NPY_ITER_EXTERNAL_LOOP`), the + inner size may be used as a signal as well. The size is guaranteed + to become zero when ``iternext()`` returns false, enabling the + following loop construct. Note that if you use this construct, + you should not pass :c:data:`NPY_ITER_GROWINNER` as a flag, because it + will cause larger sizes under some circumstances. + + .. code-block:: c + + /* The constructor should have buffersize passed as this value */ + #define FIXED_BUFFER_SIZE 1024 + + NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(iter, NULL); + char **dataptr = NpyIter_GetDataPtrArray(iter); + npy_intp *stride = NpyIter_GetInnerStrideArray(iter); + npy_intp *size_ptr = NpyIter_GetInnerLoopSizePtr(iter), size; + npy_intp i, iop, nop = NpyIter_GetNOp(iter); + + /* One loop with a fixed inner size */ + size = *size_ptr; + while (size == FIXED_BUFFER_SIZE) { + /* + * This loop could be manually unrolled by a factor + * which divides into FIXED_BUFFER_SIZE + */ + for (i = 0; i < FIXED_BUFFER_SIZE; ++i) { + /* use the addresses dataptr[0], ... dataptr[nop-1] */ + for (iop = 0; iop < nop; ++iop) { + dataptr[iop] += stride[iop]; + } + } + iternext(); + size = *size_ptr; + } + + /* Finish-up loop with variable inner size */ + if (size > 0) do { + size = *size_ptr; + while (size--) { + /* use the addresses dataptr[0], ... dataptr[nop-1] */ + for (iop = 0; iop < nop; ++iop) { + dataptr[iop] += stride[iop]; + } + } + } while (iternext()); + +.. c:function:: NpyIter_GetMultiIndexFunc *NpyIter_GetGetMultiIndex( \ + NpyIter* iter, char** errmsg) + + Returns a function pointer for getting the current multi-index + of the iterator. Returns NULL if the iterator is not tracking + a multi-index. It is recommended that this function + pointer be cached in a local variable before the iteration + loop. + + Returns NULL if there is an error. If errmsg is non-NULL, + no Python exception is set when ``NPY_FAIL`` is returned. + Instead, \*errmsg is set to an error message. When errmsg is + non-NULL, the function may be safely called without holding + the Python GIL. + +.. c:function:: char** NpyIter_GetDataPtrArray(NpyIter* iter) + + This gives back a pointer to the ``nop`` data pointers. If + :c:data:`NPY_ITER_EXTERNAL_LOOP` was not specified, each data + pointer points to the current data item of the iterator. If + no inner iteration was specified, it points to the first data + item of the inner loop. + + This pointer may be cached before the iteration loop, calling + ``iternext`` will not change it. This function may be safely + called without holding the Python GIL. + +.. c:function:: char** NpyIter_GetInitialDataPtrArray(NpyIter* iter) + + Gets the array of data pointers directly into the arrays (never + into the buffers), corresponding to iteration index 0. + + These pointers are different from the pointers accepted by + ``NpyIter_ResetBasePointers``, because the direction along + some axes may have been reversed. + + This function may be safely called without holding the Python GIL. + +.. c:function:: npy_intp* NpyIter_GetIndexPtr(NpyIter* iter) + + This gives back a pointer to the index being tracked, or NULL + if no index is being tracked. It is only useable if one of + the flags :c:data:`NPY_ITER_C_INDEX` or :c:data:`NPY_ITER_F_INDEX` + were specified during construction. + +When the flag :c:data:`NPY_ITER_EXTERNAL_LOOP` is used, the code +needs to know the parameters for doing the inner loop. These +functions provide that information. + +.. c:function:: npy_intp* NpyIter_GetInnerStrideArray(NpyIter* iter) + + Returns a pointer to an array of the ``nop`` strides, + one for each iterated object, to be used by the inner loop. + + This pointer may be cached before the iteration loop, calling + ``iternext`` will not change it. This function may be safely + called without holding the Python GIL. + + **WARNING**: While the pointer may be cached, its values may + change if the iterator is buffered. + +.. c:function:: npy_intp* NpyIter_GetInnerLoopSizePtr(NpyIter* iter) + + Returns a pointer to the number of iterations the + inner loop should execute. + + This address may be cached before the iteration loop, calling + ``iternext`` will not change it. The value itself may change during + iteration, in particular if buffering is enabled. This function + may be safely called without holding the Python GIL. + +.. c:function:: void NpyIter_GetInnerFixedStrideArray( \ + NpyIter* iter, npy_intp* out_strides) + + Gets an array of strides which are fixed, or will not change during + the entire iteration. For strides that may change, the value + NPY_MAX_INTP is placed in the stride. + + Once the iterator is prepared for iteration (after a reset if + :c:data:`NPY_DELAY_BUFALLOC` was used), call this to get the strides + which may be used to select a fast inner loop function. For example, + if the stride is 0, that means the inner loop can always load its + value into a variable once, then use the variable throughout the loop, + or if the stride equals the itemsize, a contiguous version for that + operand may be used. + + This function may be safely called without holding the Python GIL. + +.. index:: + pair: iterator; C-API + +Converting from Previous NumPy Iterators +---------------------------------------- + +The old iterator API includes functions like PyArrayIter_Check, +PyArray_Iter* and PyArray_ITER_*. The multi-iterator array includes +PyArray_MultiIter*, PyArray_Broadcast, and PyArray_RemoveSmallest. The +new iterator design replaces all of this functionality with a single object +and associated API. One goal of the new API is that all uses of the +existing iterator should be replaceable with the new iterator without +significant effort. In 1.6, the major exception to this is the neighborhood +iterator, which does not have corresponding features in this iterator. + +Here is a conversion table for which functions to use with the new iterator: + +===================================== =================================================== +*Iterator Functions* +:c:func:`PyArray_IterNew` :c:func:`NpyIter_New` +:c:func:`PyArray_IterAllButAxis` :c:func:`NpyIter_New` + ``axes`` parameter **or** + Iterator flag :c:data:`NPY_ITER_EXTERNAL_LOOP` +:c:func:`PyArray_BroadcastToShape` **NOT SUPPORTED** (Use the support for + multiple operands instead.) +:c:func:`PyArrayIter_Check` Will need to add this in Python exposure +:c:func:`PyArray_ITER_RESET` :c:func:`NpyIter_Reset` +:c:func:`PyArray_ITER_NEXT` Function pointer from :c:func:`NpyIter_GetIterNext` +:c:func:`PyArray_ITER_DATA` :c:func:`NpyIter_GetDataPtrArray` +:c:func:`PyArray_ITER_GOTO` :c:func:`NpyIter_GotoMultiIndex` +:c:func:`PyArray_ITER_GOTO1D` :c:func:`NpyIter_GotoIndex` or + :c:func:`NpyIter_GotoIterIndex` +:c:func:`PyArray_ITER_NOTDONE` Return value of ``iternext`` function pointer +*Multi-iterator Functions* +:c:func:`PyArray_MultiIterNew` :c:func:`NpyIter_MultiNew` +:c:func:`PyArray_MultiIter_RESET` :c:func:`NpyIter_Reset` +:c:func:`PyArray_MultiIter_NEXT` Function pointer from :c:func:`NpyIter_GetIterNext` +:c:func:`PyArray_MultiIter_DATA` :c:func:`NpyIter_GetDataPtrArray` +:c:func:`PyArray_MultiIter_NEXTi` **NOT SUPPORTED** (always lock-step iteration) +:c:func:`PyArray_MultiIter_GOTO` :c:func:`NpyIter_GotoMultiIndex` +:c:func:`PyArray_MultiIter_GOTO1D` :c:func:`NpyIter_GotoIndex` or + :c:func:`NpyIter_GotoIterIndex` +:c:func:`PyArray_MultiIter_NOTDONE` Return value of ``iternext`` function pointer +:c:func:`PyArray_Broadcast` Handled by :c:func:`NpyIter_MultiNew` +:c:func:`PyArray_RemoveSmallest` Iterator flag :c:data:`NPY_ITER_EXTERNAL_LOOP` +*Other Functions* +:c:func:`PyArray_ConvertToCommonType` Iterator flag :c:data:`NPY_ITER_COMMON_DTYPE` +===================================== =================================================== diff --git a/doc/source/reference/c-api.rst b/doc/source/reference/c-api.rst new file mode 100644 index 0000000..b8cbe97 --- /dev/null +++ b/doc/source/reference/c-api.rst @@ -0,0 +1,51 @@ +.. _c-api: + +########### +NumPy C-API +########### + +.. sectionauthor:: Travis E. Oliphant + +| Beware of the man who won't be bothered with details. +| --- *William Feather, Sr.* + +| The truth is out there. +| --- *Chris Carter, The X Files* + + +NumPy provides a C-API to enable users to extend the system and get +access to the array object for use in other routines. The best way to +truly understand the C-API is to read the source code. If you are +unfamiliar with (C) source code, however, this can be a daunting +experience at first. Be assured that the task becomes easier with +practice, and you may be surprised at how simple the C-code can be to +understand. Even if you don't think you can write C-code from scratch, +it is much easier to understand and modify already-written source code +then create it *de novo*. + +Python extensions are especially straightforward to understand because +they all have a very similar structure. Admittedly, NumPy is not a +trivial extension to Python, and may take a little more snooping to +grasp. This is especially true because of the code-generation +techniques, which simplify maintenance of very similar code, but can +make the code a little less readable to beginners. Still, with a +little persistence, the code can be opened to your understanding. It +is my hope, that this guide to the C-API can assist in the process of +becoming familiar with the compiled-level work that can be done with +NumPy in order to squeeze that last bit of necessary speed out of your +code. + +.. currentmodule:: numpy-c-api + +.. toctree:: + :maxdepth: 2 + + c-api.types-and-structures + c-api.config + c-api.dtype + c-api.array + c-api.iterator + c-api.ufunc + c-api.generalized-ufuncs + c-api.coremath + c-api.deprecations diff --git a/doc/source/reference/c-api.types-and-structures.rst b/doc/source/reference/c-api.types-and-structures.rst new file mode 100644 index 0000000..dcebd1e --- /dev/null +++ b/doc/source/reference/c-api.types-and-structures.rst @@ -0,0 +1,1253 @@ +***************************** +Python Types and C-Structures +***************************** + +.. sectionauthor:: Travis E. Oliphant + +Several new types are defined in the C-code. Most of these are +accessible from Python, but a few are not exposed due to their limited +use. Every new Python type has an associated :c:type:`PyObject *` with an +internal structure that includes a pointer to a "method table" that +defines how the new object behaves in Python. When you receive a +Python object into C code, you always get a pointer to a +:c:type:`PyObject` structure. Because a :c:type:`PyObject` structure is +very generic and defines only :c:macro:`PyObject_HEAD`, by itself it +is not very interesting. However, different objects contain more +details after the :c:macro:`PyObject_HEAD` (but you have to cast to the +correct type to access them --- or use accessor functions or macros). + + +New Python Types Defined +======================== + +Python types are the functional equivalent in C of classes in Python. +By constructing a new Python type you make available a new object for +Python. The ndarray object is an example of a new type defined in C. +New types are defined in C by two basic steps: + +1. creating a C-structure (usually named :c:type:`Py{Name}Object`) that is + binary- compatible with the :c:type:`PyObject` structure itself but holds + the additional information needed for that particular object; + +2. populating the :c:type:`PyTypeObject` table (pointed to by the ob_type + member of the :c:type:`PyObject` structure) with pointers to functions + that implement the desired behavior for the type. + +Instead of special method names which define behavior for Python +classes, there are "function tables" which point to functions that +implement the desired results. Since Python 2.2, the PyTypeObject +itself has become dynamic which allows C types that can be "sub-typed +"from other C-types in C, and sub-classed in Python. The children +types inherit the attributes and methods from their parent(s). + +There are two major new types: the ndarray ( :c:data:`PyArray_Type` ) +and the ufunc ( :c:data:`PyUFunc_Type` ). Additional types play a +supportive role: the :c:data:`PyArrayIter_Type`, the +:c:data:`PyArrayMultiIter_Type`, and the :c:data:`PyArrayDescr_Type` +. The :c:data:`PyArrayIter_Type` is the type for a flat iterator for an +ndarray (the object that is returned when getting the flat +attribute). The :c:data:`PyArrayMultiIter_Type` is the type of the +object returned when calling ``broadcast`` (). It handles iteration +and broadcasting over a collection of nested sequences. Also, the +:c:data:`PyArrayDescr_Type` is the data-type-descriptor type whose +instances describe the data. Finally, there are 21 new scalar-array +types which are new Python scalars corresponding to each of the +fundamental data types available for arrays. An additional 10 other +types are place holders that allow the array scalars to fit into a +hierarchy of actual Python types. + + +PyArray_Type +------------ + +.. c:var:: PyArray_Type + + The Python type of the ndarray is :c:data:`PyArray_Type`. In C, every + ndarray is a pointer to a :c:type:`PyArrayObject` structure. The ob_type + member of this structure contains a pointer to the :c:data:`PyArray_Type` + typeobject. + +.. c:type:: PyArrayObject + + The :c:type:`PyArrayObject` C-structure contains all of the required + information for an array. All instances of an ndarray (and its + subclasses) will have this structure. For future compatibility, + these structure members should normally be accessed using the + provided macros. If you need a shorter name, then you can make use + of :c:type:`NPY_AO` which is defined to be equivalent to + :c:type:`PyArrayObject`. + + .. code-block:: c + + typedef struct PyArrayObject { + PyObject_HEAD + char *data; + int nd; + npy_intp *dimensions; + npy_intp *strides; + PyObject *base; + PyArray_Descr *descr; + int flags; + PyObject *weakreflist; + } PyArrayObject; + +.. c:macro: PyArrayObject.PyObject_HEAD + + This is needed by all Python objects. It consists of (at least) + a reference count member ( ``ob_refcnt`` ) and a pointer to the + typeobject ( ``ob_type`` ). (Other elements may also be present + if Python was compiled with special options see + Include/object.h in the Python source tree for more + information). The ob_type member points to a Python type + object. + +.. c:member:: char *PyArrayObject.data + + A pointer to the first element of the array. This pointer can + (and normally should) be recast to the data type of the array. + +.. c:member:: int PyArrayObject.nd + + An integer providing the number of dimensions for this + array. When nd is 0, the array is sometimes called a rank-0 + array. Such arrays have undefined dimensions and strides and + cannot be accessed. :c:data:`NPY_MAXDIMS` is the largest number of + dimensions for any array. + +.. c:member:: npy_intp PyArrayObject.dimensions + + An array of integers providing the shape in each dimension as + long as nd :math:`\geq` 1. The integer is always large enough + to hold a pointer on the platform, so the dimension size is + only limited by memory. + +.. c:member:: npy_intp *PyArrayObject.strides + + An array of integers providing for each dimension the number of + bytes that must be skipped to get to the next element in that + dimension. + +.. c:member:: PyObject *PyArrayObject.base + + This member is used to hold a pointer to another Python object that + is related to this array. There are two use cases: 1) If this array + does not own its own memory, then base points to the Python object + that owns it (perhaps another array object), 2) If this array has + the (deprecated) :c:data:`NPY_ARRAY_UPDATEIFCOPY` or + :c:data:NPY_ARRAY_WRITEBACKIFCOPY`: flag set, then this array is + a working copy of a "misbehaved" array. When + ``PyArray_ResolveWritebackIfCopy`` is called, the array pointed to by base + will be updated with the contents of this array. + +.. c:member:: PyArray_Descr *PyArrayObject.descr + + A pointer to a data-type descriptor object (see below). The + data-type descriptor object is an instance of a new built-in + type which allows a generic description of memory. There is a + descriptor structure for each data type supported. This + descriptor structure contains useful information about the type + as well as a pointer to a table of function pointers to + implement specific functionality. + +.. c:member:: int PyArrayObject.flags + + Flags indicating how the memory pointed to by data is to be + interpreted. Possible flags are :c:data:`NPY_ARRAY_C_CONTIGUOUS`, + :c:data:`NPY_ARRAY_F_CONTIGUOUS`, :c:data:`NPY_ARRAY_OWNDATA`, + :c:data:`NPY_ARRAY_ALIGNED`, :c:data:`NPY_ARRAY_WRITEABLE`, + :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`, and :c:data:`NPY_ARRAY_UPDATEIFCOPY`. + +.. c:member:: PyObject *PyArrayObject.weakreflist + + This member allows array objects to have weak references (using the + weakref module). + + +PyArrayDescr_Type +----------------- + +.. c:var:: PyArrayDescr_Type + + The :c:data:`PyArrayDescr_Type` is the built-in type of the + data-type-descriptor objects used to describe how the bytes comprising + the array are to be interpreted. There are 21 statically-defined + :c:type:`PyArray_Descr` objects for the built-in data-types. While these + participate in reference counting, their reference count should never + reach zero. There is also a dynamic table of user-defined + :c:type:`PyArray_Descr` objects that is also maintained. Once a + data-type-descriptor object is "registered" it should never be + deallocated either. The function :c:func:`PyArray_DescrFromType` (...) can + be used to retrieve a :c:type:`PyArray_Descr` object from an enumerated + type-number (either built-in or user- defined). + +.. c:type:: PyArray_Descr + + The format of the :c:type:`PyArray_Descr` structure that lies at the + heart of the :c:data:`PyArrayDescr_Type` is + + .. code-block:: c + + typedef struct { + PyObject_HEAD + PyTypeObject *typeobj; + char kind; + char type; + char byteorder; + char unused; + int flags; + int type_num; + int elsize; + int alignment; + PyArray_ArrayDescr *subarray; + PyObject *fields; + PyArray_ArrFuncs *f; + } PyArray_Descr; + +.. c:member:: PyTypeObject *PyArray_Descr.typeobj + + Pointer to a typeobject that is the corresponding Python type for + the elements of this array. For the builtin types, this points to + the corresponding array scalar. For user-defined types, this + should point to a user-defined typeobject. This typeobject can + either inherit from array scalars or not. If it does not inherit + from array scalars, then the :c:data:`NPY_USE_GETITEM` and + :c:data:`NPY_USE_SETITEM` flags should be set in the ``flags`` member. + +.. c:member:: char PyArray_Descr.kind + + A character code indicating the kind of array (using the array + interface typestring notation). A 'b' represents Boolean, a 'i' + represents signed integer, a 'u' represents unsigned integer, 'f' + represents floating point, 'c' represents complex floating point, 'S' + represents 8-bit zero-terminated bytes, 'U' represents 32-bit/character + unicode string, and 'V' represents arbitrary. + +.. c:member:: char PyArray_Descr.type + + A traditional character code indicating the data type. + +.. c:member:: char PyArray_Descr.byteorder + + A character indicating the byte-order: '>' (big-endian), '<' (little- + endian), '=' (native), '\|' (irrelevant, ignore). All builtin data- + types have byteorder '='. + +.. c:member:: int PyArray_Descr.flags + + A data-type bit-flag that determines if the data-type exhibits object- + array like behavior. Each bit in this member is a flag which are named + as: + + .. c:var:: NPY_ITEM_REFCOUNT + + .. c:var:: NPY_ITEM_HASOBJECT + + Indicates that items of this data-type must be reference + counted (using :c:func:`Py_INCREF` and :c:func:`Py_DECREF` ). + + .. c:var:: NPY_LIST_PICKLE + + Indicates arrays of this data-type must be converted to a list + before pickling. + + .. c:var:: NPY_ITEM_IS_POINTER + + Indicates the item is a pointer to some other data-type + + .. c:var:: NPY_NEEDS_INIT + + Indicates memory for this data-type must be initialized (set + to 0) on creation. + + .. c:var:: NPY_NEEDS_PYAPI + + Indicates this data-type requires the Python C-API during + access (so don't give up the GIL if array access is going to + be needed). + + .. c:var:: NPY_USE_GETITEM + + On array access use the ``f->getitem`` function pointer + instead of the standard conversion to an array scalar. Must + use if you don't define an array scalar to go along with + the data-type. + + .. c:var:: NPY_USE_SETITEM + + When creating a 0-d array from an array scalar use + ``f->setitem`` instead of the standard copy from an array + scalar. Must use if you don't define an array scalar to go + along with the data-type. + + .. c:var:: NPY_FROM_FIELDS + + The bits that are inherited for the parent data-type if these + bits are set in any field of the data-type. Currently ( + :c:data:`NPY_NEEDS_INIT` \| :c:data:`NPY_LIST_PICKLE` \| + :c:data:`NPY_ITEM_REFCOUNT` \| :c:data:`NPY_NEEDS_PYAPI` ). + + .. c:var:: NPY_OBJECT_DTYPE_FLAGS + + Bits set for the object data-type: ( :c:data:`NPY_LIST_PICKLE` + \| :c:data:`NPY_USE_GETITEM` \| :c:data:`NPY_ITEM_IS_POINTER` \| + :c:data:`NPY_REFCOUNT` \| :c:data:`NPY_NEEDS_INIT` \| + :c:data:`NPY_NEEDS_PYAPI`). + + .. c:function:: PyDataType_FLAGCHK(PyArray_Descr *dtype, int flags) + + Return true if all the given flags are set for the data-type + object. + + .. c:function:: PyDataType_REFCHK(PyArray_Descr *dtype) + + Equivalent to :c:func:`PyDataType_FLAGCHK` (*dtype*, + :c:data:`NPY_ITEM_REFCOUNT`). + +.. c:member:: int PyArray_Descr.type_num + + A number that uniquely identifies the data type. For new data-types, + this number is assigned when the data-type is registered. + +.. c:member:: int PyArray_Descr.elsize + + For data types that are always the same size (such as long), this + holds the size of the data type. For flexible data types where + different arrays can have a different elementsize, this should be + 0. + +.. c:member:: int PyArray_Descr.alignment + + A number providing alignment information for this data type. + Specifically, it shows how far from the start of a 2-element + structure (whose first element is a ``char`` ), the compiler + places an item of this type: ``offsetof(struct {char c; type v;}, + v)`` + +.. c:member:: PyArray_ArrayDescr *PyArray_Descr.subarray + + If this is non- ``NULL``, then this data-type descriptor is a + C-style contiguous array of another data-type descriptor. In + other-words, each element that this descriptor describes is + actually an array of some other base descriptor. This is most + useful as the data-type descriptor for a field in another + data-type descriptor. The fields member should be ``NULL`` if this + is non- ``NULL`` (the fields member of the base descriptor can be + non- ``NULL`` however). The :c:type:`PyArray_ArrayDescr` structure is + defined using + + .. code-block:: c + + typedef struct { + PyArray_Descr *base; + PyObject *shape; + } PyArray_ArrayDescr; + + The elements of this structure are: + + .. c:member:: PyArray_Descr *PyArray_ArrayDescr.base + + The data-type-descriptor object of the base-type. + + .. c:member:: PyObject *PyArray_ArrayDescr.shape + + The shape (always C-style contiguous) of the sub-array as a Python + tuple. + + +.. c:member:: PyObject *PyArray_Descr.fields + + If this is non-NULL, then this data-type-descriptor has fields + described by a Python dictionary whose keys are names (and also + titles if given) and whose values are tuples that describe the + fields. Recall that a data-type-descriptor always describes a + fixed-length set of bytes. A field is a named sub-region of that + total, fixed-length collection. A field is described by a tuple + composed of another data- type-descriptor and a byte + offset. Optionally, the tuple may contain a title which is + normally a Python string. These tuples are placed in this + dictionary keyed by name (and also title if given). + +.. c:member:: PyArray_ArrFuncs *PyArray_Descr.f + + A pointer to a structure containing functions that the type needs + to implement internal features. These functions are not the same + thing as the universal functions (ufuncs) described later. Their + signatures can vary arbitrarily. + +.. c:type:: PyArray_ArrFuncs + + Functions implementing internal features. Not all of these + function pointers must be defined for a given type. The required + members are ``nonzero``, ``copyswap``, ``copyswapn``, ``setitem``, + ``getitem``, and ``cast``. These are assumed to be non- ``NULL`` + and ``NULL`` entries will cause a program crash. The other + functions may be ``NULL`` which will just mean reduced + functionality for that data-type. (Also, the nonzero function will + be filled in with a default function if it is ``NULL`` when you + register a user-defined data-type). + + .. code-block:: c + + typedef struct { + PyArray_VectorUnaryFunc *cast[NPY_NTYPES]; + PyArray_GetItemFunc *getitem; + PyArray_SetItemFunc *setitem; + PyArray_CopySwapNFunc *copyswapn; + PyArray_CopySwapFunc *copyswap; + PyArray_CompareFunc *compare; + PyArray_ArgFunc *argmax; + PyArray_DotFunc *dotfunc; + PyArray_ScanFunc *scanfunc; + PyArray_FromStrFunc *fromstr; + PyArray_NonzeroFunc *nonzero; + PyArray_FillFunc *fill; + PyArray_FillWithScalarFunc *fillwithscalar; + PyArray_SortFunc *sort[NPY_NSORTS]; + PyArray_ArgSortFunc *argsort[NPY_NSORTS]; + PyObject *castdict; + PyArray_ScalarKindFunc *scalarkind; + int **cancastscalarkindto; + int *cancastto; + PyArray_FastClipFunc *fastclip; + PyArray_FastPutmaskFunc *fastputmask; + PyArray_FastTakeFunc *fasttake; + PyArray_ArgFunc *argmin; + } PyArray_ArrFuncs; + + The concept of a behaved segment is used in the description of the + function pointers. A behaved segment is one that is aligned and in + native machine byte-order for the data-type. The ``nonzero``, + ``copyswap``, ``copyswapn``, ``getitem``, and ``setitem`` + functions can (and must) deal with mis-behaved arrays. The other + functions require behaved memory segments. + + .. c:member:: void cast( \ + void *from, void *to, npy_intp n, void *fromarr, void *toarr) + + An array of function pointers to cast from the current type to + all of the other builtin types. Each function casts a + contiguous, aligned, and notswapped buffer pointed at by + *from* to a contiguous, aligned, and notswapped buffer pointed + at by *to* The number of items to cast is given by *n*, and + the arguments *fromarr* and *toarr* are interpreted as + PyArrayObjects for flexible arrays to get itemsize + information. + + .. c:member:: PyObject *getitem(void *data, void *arr) + + A pointer to a function that returns a standard Python object + from a single element of the array object *arr* pointed to by + *data*. This function must be able to deal with "misbehaved + "(misaligned and/or swapped) arrays correctly. + + .. c:member:: int setitem(PyObject *item, void *data, void *arr) + + A pointer to a function that sets the Python object *item* + into the array, *arr*, at the position pointed to by *data* + . This function deals with "misbehaved" arrays. If successful, + a zero is returned, otherwise, a negative one is returned (and + a Python error set). + + .. c:member:: void copyswapn( \ + void *dest, npy_intp dstride, void *src, npy_intp sstride, \ + npy_intp n, int swap, void *arr) + + .. c:member:: void copyswap(void *dest, void *src, int swap, void *arr) + + These members are both pointers to functions to copy data from + *src* to *dest* and *swap* if indicated. The value of arr is + only used for flexible ( :c:data:`NPY_STRING`, :c:data:`NPY_UNICODE`, + and :c:data:`NPY_VOID` ) arrays (and is obtained from + ``arr->descr->elsize`` ). The second function copies a single + value, while the first loops over n values with the provided + strides. These functions can deal with misbehaved *src* + data. If *src* is NULL then no copy is performed. If *swap* is + 0, then no byteswapping occurs. It is assumed that *dest* and + *src* do not overlap. If they overlap, then use ``memmove`` + (...) first followed by ``copyswap(n)`` with NULL valued + ``src``. + + .. c:member:: int compare(const void* d1, const void* d2, void* arr) + + A pointer to a function that compares two elements of the + array, ``arr``, pointed to by ``d1`` and ``d2``. This + function requires behaved (aligned and not swapped) arrays. + The return value is 1 if * ``d1`` > * ``d2``, 0 if * ``d1`` == * + ``d2``, and -1 if * ``d1`` < * ``d2``. The array object ``arr`` is + used to retrieve itemsize and field information for flexible arrays. + + .. c:member:: int argmax( \ + void* data, npy_intp n, npy_intp* max_ind, void* arr) + + A pointer to a function that retrieves the index of the + largest of ``n`` elements in ``arr`` beginning at the element + pointed to by ``data``. This function requires that the + memory segment be contiguous and behaved. The return value is + always 0. The index of the largest element is returned in + ``max_ind``. + + .. c:member:: void dotfunc( \ + void* ip1, npy_intp is1, void* ip2, npy_intp is2, void* op, \ + npy_intp n, void* arr) + + A pointer to a function that multiplies two ``n`` -length + sequences together, adds them, and places the result in + element pointed to by ``op`` of ``arr``. The start of the two + sequences are pointed to by ``ip1`` and ``ip2``. To get to + the next element in each sequence requires a jump of ``is1`` + and ``is2`` *bytes*, respectively. This function requires + behaved (though not necessarily contiguous) memory. + + .. c:member:: int scanfunc(FILE* fd, void* ip , void* sep , void* arr) + + A pointer to a function that scans (scanf style) one element + of the corresponding type from the file descriptor ``fd`` into + the array memory pointed to by ``ip``. The array is assumed + to be behaved. If ``sep`` is not NULL, then a separator string + is also scanned from the file before returning. The last + argument ``arr`` is the array to be scanned into. A 0 is + returned if the scan is successful. A negative number + indicates something went wrong: -1 means the end of file was + reached before the separator string could be scanned, -4 means + that the end of file was reached before the element could be + scanned, and -3 means that the element could not be + interpreted from the format string. Requires a behaved array. + + .. c:member:: int fromstr(char* str, void* ip, char** endptr, void* arr) + + A pointer to a function that converts the string pointed to by + ``str`` to one element of the corresponding type and places it + in the memory location pointed to by ``ip``. After the + conversion is completed, ``*endptr`` points to the rest of the + string. The last argument ``arr`` is the array into which ip + points (needed for variable-size data- types). Returns 0 on + success or -1 on failure. Requires a behaved array. + + .. c:member:: Bool nonzero(void* data, void* arr) + + A pointer to a function that returns TRUE if the item of + ``arr`` pointed to by ``data`` is nonzero. This function can + deal with misbehaved arrays. + + .. c:member:: void fill(void* data, npy_intp length, void* arr) + + A pointer to a function that fills a contiguous array of given + length with data. The first two elements of the array must + already be filled- in. From these two values, a delta will be + computed and the values from item 3 to the end will be + computed by repeatedly adding this computed delta. The data + buffer must be well-behaved. + + .. c:member:: void fillwithscalar( \ + void* buffer, npy_intp length, void* value, void* arr) + + A pointer to a function that fills a contiguous ``buffer`` of + the given ``length`` with a single scalar ``value`` whose + address is given. The final argument is the array which is + needed to get the itemsize for variable-length arrays. + + .. c:member:: int sort(void* start, npy_intp length, void* arr) + + An array of function pointers to a particular sorting + algorithms. A particular sorting algorithm is obtained using a + key (so far :c:data:`NPY_QUICKSORT`, :c:data:`NPY_HEAPSORT`, + and :c:data:`NPY_MERGESORT` are defined). These sorts are done + in-place assuming contiguous and aligned data. + + .. c:member:: int argsort( \ + void* start, npy_intp* result, npy_intp length, void *arr) + + An array of function pointers to sorting algorithms for this + data type. The same sorting algorithms as for sort are + available. The indices producing the sort are returned in + ``result`` (which must be initialized with indices 0 to + ``length-1`` inclusive). + + .. c:member:: PyObject *castdict + + Either ``NULL`` or a dictionary containing low-level casting + functions for user- defined data-types. Each function is + wrapped in a :c:type:`PyCObject *` and keyed by the data-type number. + + .. c:member:: NPY_SCALARKIND scalarkind(PyArrayObject* arr) + + A function to determine how scalars of this type should be + interpreted. The argument is ``NULL`` or a 0-dimensional array + containing the data (if that is needed to determine the kind + of scalar). The return value must be of type + :c:type:`NPY_SCALARKIND`. + + .. c:member:: int **cancastscalarkindto + + Either ``NULL`` or an array of :c:type:`NPY_NSCALARKINDS` + pointers. These pointers should each be either ``NULL`` or a + pointer to an array of integers (terminated by + :c:data:`NPY_NOTYPE`) indicating data-types that a scalar of + this data-type of the specified kind can be cast to safely + (this usually means without losing precision). + + .. c:member:: int *cancastto + + Either ``NULL`` or an array of integers (terminated by + :c:data:`NPY_NOTYPE` ) indicated data-types that this data-type + can be cast to safely (this usually means without losing + precision). + + .. c:member:: void fastclip( \ + void *in, npy_intp n_in, void *min, void *max, void *out) + + A function that reads ``n_in`` items from ``in``, and writes to + ``out`` the read value if it is within the limits pointed to by + ``min`` and ``max``, or the corresponding limit if outside. The + memory segments must be contiguous and behaved, and either + ``min`` or ``max`` may be ``NULL``, but not both. + + .. c:member:: void fastputmask( \ + void *in, void *mask, npy_intp n_in, void *values, npy_intp nv) + + A function that takes a pointer ``in`` to an array of ``n_in`` + items, a pointer ``mask`` to an array of ``n_in`` boolean + values, and a pointer ``vals`` to an array of ``nv`` items. + Items from ``vals`` are copied into ``in`` wherever the value + in ``mask`` is non-zero, tiling ``vals`` as needed if + ``nv < n_in``. All arrays must be contiguous and behaved. + + .. c:member:: void fasttake( \ + void *dest, void *src, npy_intp *indarray, npy_intp nindarray, \ + npy_intp n_outer, npy_intp m_middle, npy_intp nelem, \ + NPY_CLIPMODE clipmode) + + A function that takes a pointer ``src`` to a C contiguous, + behaved segment, interpreted as a 3-dimensional array of shape + ``(n_outer, nindarray, nelem)``, a pointer ``indarray`` to a + contiguous, behaved segment of ``m_middle`` integer indices, + and a pointer ``dest`` to a C contiguous, behaved segment, + interpreted as a 3-dimensional array of shape + ``(n_outer, m_middle, nelem)``. The indices in ``indarray`` are + used to index ``src`` along the second dimension, and copy the + corresponding chunks of ``nelem`` items into ``dest``. + ``clipmode`` (which can take on the values :c:data:`NPY_RAISE`, + :c:data:`NPY_WRAP` or :c:data:`NPY_CLIP`) determines how will + indices smaller than 0 or larger than ``nindarray`` will be + handled. + + .. c:member:: int argmin( \ + void* data, npy_intp n, npy_intp* min_ind, void* arr) + + A pointer to a function that retrieves the index of the + smallest of ``n`` elements in ``arr`` beginning at the element + pointed to by ``data``. This function requires that the + memory segment be contiguous and behaved. The return value is + always 0. The index of the smallest element is returned in + ``min_ind``. + + +The :c:data:`PyArray_Type` typeobject implements many of the features of +Python objects including the tp_as_number, tp_as_sequence, +tp_as_mapping, and tp_as_buffer interfaces. The rich comparison +(tp_richcompare) is also used along with new-style attribute lookup +for methods (tp_methods) and properties (tp_getset). The +:c:data:`PyArray_Type` can also be sub-typed. + +.. tip:: + + The tp_as_number methods use a generic approach to call whatever + function has been registered for handling the operation. The + function PyNumeric_SetOps(..) can be used to register functions to + handle particular mathematical operations (for all arrays). When + the umath module is imported, it sets the numeric operations for + all arrays to the corresponding ufuncs. The tp_str and tp_repr + methods can also be altered using PyString_SetStringFunction(...). + + +PyUFunc_Type +------------ + +.. c:var:: PyUFunc_Type + + The ufunc object is implemented by creation of the + :c:data:`PyUFunc_Type`. It is a very simple type that implements only + basic getattribute behavior, printing behavior, and has call + behavior which allows these objects to act like functions. The + basic idea behind the ufunc is to hold a reference to fast + 1-dimensional (vector) loops for each data type that supports the + operation. These one-dimensional loops all have the same signature + and are the key to creating a new ufunc. They are called by the + generic looping code as appropriate to implement the N-dimensional + function. There are also some generic 1-d loops defined for + floating and complexfloating arrays that allow you to define a + ufunc using a single scalar function (*e.g.* atanh). + + +.. c:type:: PyUFuncObject + + The core of the ufunc is the :c:type:`PyUFuncObject` which contains all + the information needed to call the underlying C-code loops that + perform the actual work. It has the following structure: + + .. code-block:: c + + typedef struct { + PyObject_HEAD + int nin; + int nout; + int nargs; + int identity; + PyUFuncGenericFunction *functions; + void **data; + int ntypes; + int reserved1; + const char *name; + char *types; + const char *doc; + void *ptr; + PyObject *obj; + PyObject *userloops; + npy_uint32 *op_flags; + npy_uint32 *iter_flags; + } PyUFuncObject; + + .. c:macro: PyUFuncObject.PyObject_HEAD + + required for all Python objects. + + .. c:member:: int PyUFuncObject.nin + + The number of input arguments. + + .. c:member:: int PyUFuncObject.nout + + The number of output arguments. + + .. c:member:: int PyUFuncObject.nargs + + The total number of arguments (*nin* + *nout*). This must be + less than :c:data:`NPY_MAXARGS`. + + .. c:member:: int PyUFuncObject.identity + + Either :c:data:`PyUFunc_One`, :c:data:`PyUFunc_Zero`, + :c:data:`PyUFunc_None` or :c:data:`PyUFunc_AllOnes` to indicate + the identity for this operation. It is only used for a + reduce-like call on an empty array. + + .. c:member:: void PyUFuncObject.functions(char** args, npy_intp* dims, + npy_intp* steps, void* extradata) + + An array of function pointers --- one for each data type + supported by the ufunc. This is the vector loop that is called + to implement the underlying function *dims* [0] times. The + first argument, *args*, is an array of *nargs* pointers to + behaved memory. Pointers to the data for the input arguments + are first, followed by the pointers to the data for the output + arguments. How many bytes must be skipped to get to the next + element in the sequence is specified by the corresponding entry + in the *steps* array. The last argument allows the loop to + receive extra information. This is commonly used so that a + single, generic vector loop can be used for multiple + functions. In this case, the actual scalar function to call is + passed in as *extradata*. The size of this function pointer + array is ntypes. + + .. c:member:: void **PyUFuncObject.data + + Extra data to be passed to the 1-d vector loops or ``NULL`` if + no extra-data is needed. This C-array must be the same size ( + *i.e.* ntypes) as the functions array. ``NULL`` is used if + extra_data is not needed. Several C-API calls for UFuncs are + just 1-d vector loops that make use of this extra data to + receive a pointer to the actual function to call. + + .. c:member:: int PyUFuncObject.ntypes + + The number of supported data types for the ufunc. This number + specifies how many different 1-d loops (of the builtin data + types) are available. + + .. c:member:: char *PyUFuncObject.name + + A string name for the ufunc. This is used dynamically to build + the __doc\__ attribute of ufuncs. + + .. c:member:: char *PyUFuncObject.types + + An array of :math:`nargs \times ntypes` 8-bit type_numbers + which contains the type signature for the function for each of + the supported (builtin) data types. For each of the *ntypes* + functions, the corresponding set of type numbers in this array + shows how the *args* argument should be interpreted in the 1-d + vector loop. These type numbers do not have to be the same type + and mixed-type ufuncs are supported. + + .. c:member:: char *PyUFuncObject.doc + + Documentation for the ufunc. Should not contain the function + signature as this is generated dynamically when __doc\__ is + retrieved. + + .. c:member:: void *PyUFuncObject.ptr + + Any dynamically allocated memory. Currently, this is used for + dynamic ufuncs created from a python function to store room for + the types, data, and name members. + + .. c:member:: PyObject *PyUFuncObject.obj + + For ufuncs dynamically created from python functions, this member + holds a reference to the underlying Python function. + + .. c:member:: PyObject *PyUFuncObject.userloops + + A dictionary of user-defined 1-d vector loops (stored as CObject + ptrs) for user-defined types. A loop may be registered by the + user for any user-defined type. It is retrieved by type number. + User defined type numbers are always larger than + :c:data:`NPY_USERDEF`. + + + .. c:member:: npy_uint32 PyUFuncObject.op_flags + + Override the default operand flags for each ufunc operand. + + .. c:member:: npy_uint32 PyUFuncObject.iter_flags + + Override the default nditer flags for the ufunc. + +PyArrayIter_Type +---------------- + +.. c:var:: PyArrayIter_Type + + This is an iterator object that makes it easy to loop over an + N-dimensional array. It is the object returned from the flat + attribute of an ndarray. It is also used extensively throughout the + implementation internals to loop over an N-dimensional array. The + tp_as_mapping interface is implemented so that the iterator object + can be indexed (using 1-d indexing), and a few methods are + implemented through the tp_methods table. This object implements the + next method and can be used anywhere an iterator can be used in + Python. + +.. c:type:: PyArrayIterObject + + The C-structure corresponding to an object of :c:data:`PyArrayIter_Type` is + the :c:type:`PyArrayIterObject`. The :c:type:`PyArrayIterObject` is used to + keep track of a pointer into an N-dimensional array. It contains associated + information used to quickly march through the array. The pointer can + be adjusted in three basic ways: 1) advance to the "next" position in + the array in a C-style contiguous fashion, 2) advance to an arbitrary + N-dimensional coordinate in the array, and 3) advance to an arbitrary + one-dimensional index into the array. The members of the + :c:type:`PyArrayIterObject` structure are used in these + calculations. Iterator objects keep their own dimension and strides + information about an array. This can be adjusted as needed for + "broadcasting," or to loop over only specific dimensions. + + .. code-block:: c + + typedef struct { + PyObject_HEAD + int nd_m1; + npy_intp index; + npy_intp size; + npy_intp coordinates[NPY_MAXDIMS]; + npy_intp dims_m1[NPY_MAXDIMS]; + npy_intp strides[NPY_MAXDIMS]; + npy_intp backstrides[NPY_MAXDIMS]; + npy_intp factors[NPY_MAXDIMS]; + PyArrayObject *ao; + char *dataptr; + Bool contiguous; + } PyArrayIterObject; + + .. c:member:: int PyArrayIterObject.nd_m1 + + :math:`N-1` where :math:`N` is the number of dimensions in the + underlying array. + + .. c:member:: npy_intp PyArrayIterObject.index + + The current 1-d index into the array. + + .. c:member:: npy_intp PyArrayIterObject.size + + The total size of the underlying array. + + .. c:member:: npy_intp *PyArrayIterObject.coordinates + + An :math:`N` -dimensional index into the array. + + .. c:member:: npy_intp *PyArrayIterObject.dims_m1 + + The size of the array minus 1 in each dimension. + + .. c:member:: npy_intp *PyArrayIterObject.strides + + The strides of the array. How many bytes needed to jump to the next + element in each dimension. + + .. c:member:: npy_intp *PyArrayIterObject.backstrides + + How many bytes needed to jump from the end of a dimension back + to its beginning. Note that ``backstrides[k] == strides[k] * + dims_m1[k]``, but it is stored here as an optimization. + + .. c:member:: npy_intp *PyArrayIterObject.factors + + This array is used in computing an N-d index from a 1-d index. It + contains needed products of the dimensions. + + .. c:member:: PyArrayObject *PyArrayIterObject.ao + + A pointer to the underlying ndarray this iterator was created to + represent. + + .. c:member:: char *PyArrayIterObject.dataptr + + This member points to an element in the ndarray indicated by the + index. + + .. c:member:: Bool PyArrayIterObject.contiguous + + This flag is true if the underlying array is + :c:data:`NPY_ARRAY_C_CONTIGUOUS`. It is used to simplify + calculations when possible. + + +How to use an array iterator on a C-level is explained more fully in +later sections. Typically, you do not need to concern yourself with +the internal structure of the iterator object, and merely interact +with it through the use of the macros :c:func:`PyArray_ITER_NEXT` (it), +:c:func:`PyArray_ITER_GOTO` (it, dest), or :c:func:`PyArray_ITER_GOTO1D` +(it, index). All of these macros require the argument *it* to be a +:c:type:`PyArrayIterObject *`. + + +PyArrayMultiIter_Type +--------------------- + +.. c:var:: PyArrayMultiIter_Type + + This type provides an iterator that encapsulates the concept of + broadcasting. It allows :math:`N` arrays to be broadcast together + so that the loop progresses in C-style contiguous fashion over the + broadcasted array. The corresponding C-structure is the + :c:type:`PyArrayMultiIterObject` whose memory layout must begin any + object, *obj*, passed in to the :c:func:`PyArray_Broadcast` (obj) + function. Broadcasting is performed by adjusting array iterators so + that each iterator represents the broadcasted shape and size, but + has its strides adjusted so that the correct element from the array + is used at each iteration. + + +.. c:type:: PyArrayMultiIterObject + + .. code-block:: c + + typedef struct { + PyObject_HEAD + int numiter; + npy_intp size; + npy_intp index; + int nd; + npy_intp dimensions[NPY_MAXDIMS]; + PyArrayIterObject *iters[NPY_MAXDIMS]; + } PyArrayMultiIterObject; + + .. c:macro: PyArrayMultiIterObject.PyObject_HEAD + + Needed at the start of every Python object (holds reference count + and type identification). + + .. c:member:: int PyArrayMultiIterObject.numiter + + The number of arrays that need to be broadcast to the same shape. + + .. c:member:: npy_intp PyArrayMultiIterObject.size + + The total broadcasted size. + + .. c:member:: npy_intp PyArrayMultiIterObject.index + + The current (1-d) index into the broadcasted result. + + .. c:member:: int PyArrayMultiIterObject.nd + + The number of dimensions in the broadcasted result. + + .. c:member:: npy_intp *PyArrayMultiIterObject.dimensions + + The shape of the broadcasted result (only ``nd`` slots are used). + + .. c:member:: PyArrayIterObject **PyArrayMultiIterObject.iters + + An array of iterator objects that holds the iterators for the + arrays to be broadcast together. On return, the iterators are + adjusted for broadcasting. + +PyArrayNeighborhoodIter_Type +---------------------------- + +.. c:var:: PyArrayNeighborhoodIter_Type + + This is an iterator object that makes it easy to loop over an + N-dimensional neighborhood. + +.. c:type:: PyArrayNeighborhoodIterObject + + The C-structure corresponding to an object of + :c:data:`PyArrayNeighborhoodIter_Type` is the + :c:type:`PyArrayNeighborhoodIterObject`. + +PyArrayFlags_Type +----------------- + +.. c:var:: PyArrayFlags_Type + + When the flags attribute is retrieved from Python, a special + builtin object of this type is constructed. This special type makes + it easier to work with the different flags by accessing them as + attributes or by accessing them as if the object were a dictionary + with the flag names as entries. + + +ScalarArrayTypes +---------------- + +There is a Python type for each of the different built-in data types +that can be present in the array Most of these are simple wrappers +around the corresponding data type in C. The C-names for these types +are :c:data:`Py{TYPE}ArrType_Type` where ``{TYPE}`` can be + + **Bool**, **Byte**, **Short**, **Int**, **Long**, **LongLong**, + **UByte**, **UShort**, **UInt**, **ULong**, **ULongLong**, + **Half**, **Float**, **Double**, **LongDouble**, **CFloat**, + **CDouble**, **CLongDouble**, **String**, **Unicode**, **Void**, and + **Object**. + +These type names are part of the C-API and can therefore be created in +extension C-code. There is also a :c:data:`PyIntpArrType_Type` and a +:c:data:`PyUIntpArrType_Type` that are simple substitutes for one of the +integer types that can hold a pointer on the platform. The structure +of these scalar objects is not exposed to C-code. The function +:c:func:`PyArray_ScalarAsCtype` (..) can be used to extract the C-type +value from the array scalar and the function :c:func:`PyArray_Scalar` +(...) can be used to construct an array scalar from a C-value. + + +Other C-Structures +================== + +A few new C-structures were found to be useful in the development of +NumPy. These C-structures are used in at least one C-API call and are +therefore documented here. The main reason these structures were +defined is to make it easy to use the Python ParseTuple C-API to +convert from Python objects to a useful C-Object. + + +PyArray_Dims +------------ + +.. c:type:: PyArray_Dims + + This structure is very useful when shape and/or strides information + is supposed to be interpreted. The structure is: + + .. code-block:: c + + typedef struct { + npy_intp *ptr; + int len; + } PyArray_Dims; + + The members of this structure are + + .. c:member:: npy_intp *PyArray_Dims.ptr + + A pointer to a list of (:c:type:`npy_intp`) integers which + usually represent array shape or array strides. + + .. c:member:: int PyArray_Dims.len + + The length of the list of integers. It is assumed safe to + access *ptr* [0] to *ptr* [len-1]. + + +PyArray_Chunk +------------- + +.. c:type:: PyArray_Chunk + + This is equivalent to the buffer object structure in Python up to + the ptr member. On 32-bit platforms (*i.e.* if :c:data:`NPY_SIZEOF_INT` + == :c:data:`NPY_SIZEOF_INTP`), the len member also matches an equivalent + member of the buffer object. It is useful to represent a generic + single-segment chunk of memory. + + .. code-block:: c + + typedef struct { + PyObject_HEAD + PyObject *base; + void *ptr; + npy_intp len; + int flags; + } PyArray_Chunk; + + The members are + + .. c:macro: PyArray_Chunk.PyObject_HEAD + + Necessary for all Python objects. Included here so that the + :c:type:`PyArray_Chunk` structure matches that of the buffer object + (at least to the len member). + + .. c:member:: PyObject *PyArray_Chunk.base + + The Python object this chunk of memory comes from. Needed so that + memory can be accounted for properly. + + .. c:member:: void *PyArray_Chunk.ptr + + A pointer to the start of the single-segment chunk of memory. + + .. c:member:: npy_intp PyArray_Chunk.len + + The length of the segment in bytes. + + .. c:member:: int PyArray_Chunk.flags + + Any data flags (*e.g.* :c:data:`NPY_ARRAY_WRITEABLE` ) that should + be used to interpret the memory. + + +PyArrayInterface +---------------- + +.. seealso:: :ref:`arrays.interface` + +.. c:type:: PyArrayInterface + + The :c:type:`PyArrayInterface` structure is defined so that NumPy and + other extension modules can use the rapid array interface + protocol. The :obj:`__array_struct__` method of an object that + supports the rapid array interface protocol should return a + :c:type:`PyCObject` that contains a pointer to a :c:type:`PyArrayInterface` + structure with the relevant details of the array. After the new + array is created, the attribute should be ``DECREF``'d which will + free the :c:type:`PyArrayInterface` structure. Remember to ``INCREF`` the + object (whose :obj:`__array_struct__` attribute was retrieved) and + point the base member of the new :c:type:`PyArrayObject` to this same + object. In this way the memory for the array will be managed + correctly. + + .. code-block:: c + + typedef struct { + int two; + int nd; + char typekind; + int itemsize; + int flags; + npy_intp *shape; + npy_intp *strides; + void *data; + PyObject *descr; + } PyArrayInterface; + + .. c:member:: int PyArrayInterface.two + + the integer 2 as a sanity check. + + .. c:member:: int PyArrayInterface.nd + + the number of dimensions in the array. + + .. c:member:: char PyArrayInterface.typekind + + A character indicating what kind of array is present according to the + typestring convention with 't' -> bitfield, 'b' -> Boolean, 'i' -> + signed integer, 'u' -> unsigned integer, 'f' -> floating point, 'c' -> + complex floating point, 'O' -> object, 'S' -> (byte-)string, 'U' -> + unicode, 'V' -> void. + + .. c:member:: int PyArrayInterface.itemsize + + The number of bytes each item in the array requires. + + .. c:member:: int PyArrayInterface.flags + + Any of the bits :c:data:`NPY_ARRAY_C_CONTIGUOUS` (1), + :c:data:`NPY_ARRAY_F_CONTIGUOUS` (2), :c:data:`NPY_ARRAY_ALIGNED` (0x100), + :c:data:`NPY_ARRAY_NOTSWAPPED` (0x200), or :c:data:`NPY_ARRAY_WRITEABLE` + (0x400) to indicate something about the data. The + :c:data:`NPY_ARRAY_ALIGNED`, :c:data:`NPY_ARRAY_C_CONTIGUOUS`, and + :c:data:`NPY_ARRAY_F_CONTIGUOUS` flags can actually be determined from + the other parameters. The flag :c:data:`NPY_ARR_HAS_DESCR` + (0x800) can also be set to indicate to objects consuming the + version 3 array interface that the descr member of the + structure is present (it will be ignored by objects consuming + version 2 of the array interface). + + .. c:member:: npy_intp *PyArrayInterface.shape + + An array containing the size of the array in each dimension. + + .. c:member:: npy_intp *PyArrayInterface.strides + + An array containing the number of bytes to jump to get to the next + element in each dimension. + + .. c:member:: void *PyArrayInterface.data + + A pointer *to* the first element of the array. + + .. c:member:: PyObject *PyArrayInterface.descr + + A Python object describing the data-type in more detail (same + as the *descr* key in :obj:`__array_interface__`). This can be + ``NULL`` if *typekind* and *itemsize* provide enough + information. This field is also ignored unless + :c:data:`ARR_HAS_DESCR` flag is on in *flags*. + + +Internally used structures +-------------------------- + +Internally, the code uses some additional Python objects primarily for +memory management. These types are not accessible directly from +Python, and are not exposed to the C-API. They are included here only +for completeness and assistance in understanding the code. + + +.. c:type:: PyUFuncLoopObject + + A loose wrapper for a C-structure that contains the information + needed for looping. This is useful if you are trying to understand + the ufunc looping code. The :c:type:`PyUFuncLoopObject` is the associated + C-structure. It is defined in the ``ufuncobject.h`` header. + +.. c:type:: PyUFuncReduceObject + + A loose wrapper for the C-structure that contains the information + needed for reduce-like methods of ufuncs. This is useful if you are + trying to understand the reduce, accumulate, and reduce-at + code. The :c:type:`PyUFuncReduceObject` is the associated C-structure. It + is defined in the ``ufuncobject.h`` header. + +.. c:type:: PyUFunc_Loop1d + + A simple linked-list of C-structures containing the information needed + to define a 1-d loop for a ufunc for every defined signature of a + user-defined data-type. + +.. c:var:: PyArrayMapIter_Type + + Advanced indexing is handled with this Python type. It is simply a + loose wrapper around the C-structure containing the variables + needed for advanced array indexing. The associated C-structure, + :c:type:`PyArrayMapIterObject`, is useful if you are trying to + understand the advanced-index mapping code. It is defined in the + ``arrayobject.h`` header. This type is not exposed to Python and + could be replaced with a C-structure. As a Python type it takes + advantage of reference- counted memory management. diff --git a/doc/source/reference/c-api.ufunc.rst b/doc/source/reference/c-api.ufunc.rst new file mode 100644 index 0000000..79ad256 --- /dev/null +++ b/doc/source/reference/c-api.ufunc.rst @@ -0,0 +1,411 @@ +UFunc API +========= + +.. sectionauthor:: Travis E. Oliphant + +.. index:: + pair: ufunc; C-API + + +Constants +--------- + +.. c:var:: UFUNC_ERR_{HANDLER} + + ``{HANDLER}`` can be **IGNORE**, **WARN**, **RAISE**, or **CALL** + +.. c:var:: UFUNC_{THING}_{ERR} + + ``{THING}`` can be **MASK**, **SHIFT**, or **FPE**, and ``{ERR}`` can + be **DIVIDEBYZERO**, **OVERFLOW**, **UNDERFLOW**, and **INVALID**. + +.. c:var:: PyUFunc_{VALUE} + + ``{VALUE}`` can be **One** (1), **Zero** (0), or **None** (-1) + + +Macros +------ + +.. c:macro:: NPY_LOOP_BEGIN_THREADS + + Used in universal function code to only release the Python GIL if + loop->obj is not true (*i.e.* this is not an OBJECT array + loop). Requires use of :c:macro:`NPY_BEGIN_THREADS_DEF` in variable + declaration area. + +.. c:macro:: NPY_LOOP_END_THREADS + + Used in universal function code to re-acquire the Python GIL if it + was released (because loop->obj was not true). + +.. c:function:: UFUNC_CHECK_ERROR(loop) + + A macro used internally to check for errors and goto fail if + found. This macro requires a fail label in the current code + block. The *loop* variable must have at least members (obj, + errormask, and errorobj). If *loop* ->obj is nonzero, then + :c:func:`PyErr_Occurred` () is called (meaning the GIL must be held). If + *loop* ->obj is zero, then if *loop* ->errormask is nonzero, + :c:func:`PyUFunc_checkfperr` is called with arguments *loop* ->errormask + and *loop* ->errobj. If the result of this check of the IEEE + floating point registers is true then the code redirects to the + fail label which must be defined. + +.. c:function:: UFUNC_CHECK_STATUS(ret) + + Deprecated: use npy_clear_floatstatus from npy_math.h instead. + + A macro that expands to platform-dependent code. The *ret* + variable can be any integer. The :c:data:`UFUNC_FPE_{ERR}` bits are + set in *ret* according to the status of the corresponding error + flags of the floating point processor. + + +Functions +--------- + +.. c:function:: PyObject* PyUFunc_FromFuncAndData( \ + PyUFuncGenericFunction* func, void** data, char* types, int ntypes, \ + int nin, int nout, int identity, char* name, char* doc, int unused) + + Create a new broadcasting universal function from required variables. + Each ufunc builds around the notion of an element-by-element + operation. Each ufunc object contains pointers to 1-d loops + implementing the basic functionality for each supported type. + + .. note:: + + The *func*, *data*, *types*, *name*, and *doc* arguments are not + copied by :c:func:`PyUFunc_FromFuncAndData`. The caller must ensure + that the memory used by these arrays is not freed as long as the + ufunc object is alive. + + :param func: + Must to an array of length *ntypes* containing + :c:type:`PyUFuncGenericFunction` items. These items are pointers to + functions that actually implement the underlying + (element-by-element) function :math:`N` times. + + :param data: + Should be ``NULL`` or a pointer to an array of size *ntypes* + . This array may contain arbitrary extra-data to be passed to + the corresponding 1-d loop function in the func array. + + :param types: + Must be of length (*nin* + *nout*) \* *ntypes*, and it + contains the data-types (built-in only) that the corresponding + function in the *func* array can deal with. + + :param ntypes: + How many different data-type "signatures" the ufunc has implemented. + + :param nin: + The number of inputs to this operation. + + :param nout: + The number of outputs + + :param name: + The name for the ufunc. Specifying a name of 'add' or + 'multiply' enables a special behavior for integer-typed + reductions when no dtype is given. If the input type is an + integer (or boolean) data type smaller than the size of the int_ + data type, it will be internally upcast to the int_ (or uint) + data type. + + :param doc: + Allows passing in a documentation string to be stored with the + ufunc. The documentation string should not contain the name + of the function or the calling signature as that will be + dynamically determined from the object and available when + accessing the **__doc__** attribute of the ufunc. + + :param unused: + Unused and present for backwards compatibility of the C-API. + +.. c:function:: PyObject* PyUFunc_FromFuncAndDataAndSignature( \ + PyUFuncGenericFunction* func, void** data, char* types, int ntypes, \ + int nin, int nout, int identity, char* name, char* doc, int unused, char *signature) + + This function is very similar to PyUFunc_FromFuncAndData above, but has + an extra *signature* argument, to define generalized universal functions. + Similarly to how ufuncs are built around an element-by-element operation, + gufuncs are around subarray-by-subarray operations, the signature defining + the subarrays to operate on. + + :param signature: + The signature for the new gufunc. Setting it to NULL is equivalent + to calling PyUFunc_FromFuncAndData. A copy of the string is made, + so the passed in buffer can be freed. + +.. c:function:: int PyUFunc_RegisterLoopForType( \ + PyUFuncObject* ufunc, int usertype, PyUFuncGenericFunction function, \ + int* arg_types, void* data) + + This function allows the user to register a 1-d loop with an + already- created ufunc to be used whenever the ufunc is called + with any of its input arguments as the user-defined + data-type. This is needed in order to make ufuncs work with + built-in data-types. The data-type must have been previously + registered with the numpy system. The loop is passed in as + *function*. This loop can take arbitrary data which should be + passed in as *data*. The data-types the loop requires are passed + in as *arg_types* which must be a pointer to memory at least as + large as ufunc->nargs. + +.. c:function:: int PyUFunc_RegisterLoopForDescr( \ + PyUFuncObject* ufunc, PyArray_Descr* userdtype, \ + PyUFuncGenericFunction function, PyArray_Descr** arg_dtypes, void* data) + + This function behaves like PyUFunc_RegisterLoopForType above, except + that it allows the user to register a 1-d loop using PyArray_Descr + objects instead of dtype type num values. This allows a 1-d loop to be + registered for structured array data-dtypes and custom data-types + instead of scalar data-types. + +.. c:function:: int PyUFunc_ReplaceLoopBySignature( \ + PyUFuncObject* ufunc, PyUFuncGenericFunction newfunc, int* signature, \ + PyUFuncGenericFunction* oldfunc) + + Replace a 1-d loop matching the given *signature* in the + already-created *ufunc* with the new 1-d loop newfunc. Return the + old 1-d loop function in *oldfunc*. Return 0 on success and -1 on + failure. This function works only with built-in types (use + :c:func:`PyUFunc_RegisterLoopForType` for user-defined types). A + signature is an array of data-type numbers indicating the inputs + followed by the outputs assumed by the 1-d loop. + +.. c:function:: int PyUFunc_GenericFunction( \ + PyUFuncObject* self, PyObject* args, PyObject* kwds, PyArrayObject** mps) + + A generic ufunc call. The ufunc is passed in as *self*, the arguments + to the ufunc as *args* and *kwds*. The *mps* argument is an array of + :c:type:`PyArrayObject` pointers whose values are discarded and which + receive the converted input arguments as well as the ufunc outputs + when success is returned. The user is responsible for managing this + array and receives a new reference for each array in *mps*. The total + number of arrays in *mps* is given by *self* ->nin + *self* ->nout. + + Returns 0 on success, -1 on error. + +.. c:function:: int PyUFunc_checkfperr(int errmask, PyObject* errobj) + + A simple interface to the IEEE error-flag checking support. The + *errmask* argument is a mask of :c:data:`UFUNC_MASK_{ERR}` bitmasks + indicating which errors to check for (and how to check for + them). The *errobj* must be a Python tuple with two elements: a + string containing the name which will be used in any communication + of error and either a callable Python object (call-back function) + or :c:data:`Py_None`. The callable object will only be used if + :c:data:`UFUNC_ERR_CALL` is set as the desired error checking + method. This routine manages the GIL and is safe to call even + after releasing the GIL. If an error in the IEEE-compatible + hardware is determined a -1 is returned, otherwise a 0 is + returned. + +.. c:function:: void PyUFunc_clearfperr() + + Clear the IEEE error flags. + +.. c:function:: void PyUFunc_GetPyValues( \ + char* name, int* bufsize, int* errmask, PyObject** errobj) + + Get the Python values used for ufunc processing from the + thread-local storage area unless the defaults have been set in + which case the name lookup is bypassed. The name is placed as a + string in the first element of *\*errobj*. The second element is + the looked-up function to call on error callback. The value of the + looked-up buffer-size to use is passed into *bufsize*, and the + value of the error mask is placed into *errmask*. + + +Generic functions +----------------- + +At the core of every ufunc is a collection of type-specific functions +that defines the basic functionality for each of the supported types. +These functions must evaluate the underlying function :math:`N\geq1` +times. Extra-data may be passed in that may be used during the +calculation. This feature allows some general functions to be used as +these basic looping functions. The general function has all the code +needed to point variables to the right place and set up a function +call. The general function assumes that the actual function to call is +passed in as the extra data and calls it with the correct values. All +of these functions are suitable for placing directly in the array of +functions stored in the functions member of the PyUFuncObject +structure. + +.. c:function:: void PyUFunc_f_f_As_d_d( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_d_d( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_f_f( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_g_g( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_F_F_As_D_D( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_F_F( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_D_D( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_G_G( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_e_e( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_e_e_As_f_f( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_e_e_As_d_d( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + + Type specific, core 1-d functions for ufuncs where each + calculation is obtained by calling a function taking one input + argument and returning one output. This function is passed in + ``func``. The letters correspond to dtypechar's of the supported + data types ( ``e`` - half, ``f`` - float, ``d`` - double, + ``g`` - long double, ``F`` - cfloat, ``D`` - cdouble, + ``G`` - clongdouble). The argument *func* must support the same + signature. The _As_X_X variants assume ndarray's of one data type + but cast the values to use an underlying function that takes a + different data type. Thus, :c:func:`PyUFunc_f_f_As_d_d` uses + ndarrays of data type :c:data:`NPY_FLOAT` but calls out to a + C-function that takes double and returns double. + +.. c:function:: void PyUFunc_ff_f_As_dd_d( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_ff_f( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_dd_d( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_gg_g( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_FF_F_As_DD_D( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_DD_D( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_FF_F( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_GG_G( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_ee_e( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_ee_e_As_ff_f( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_ee_e_As_dd_d( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + + Type specific, core 1-d functions for ufuncs where each + calculation is obtained by calling a function taking two input + arguments and returning one output. The underlying function to + call is passed in as *func*. The letters correspond to + dtypechar's of the specific data type supported by the + general-purpose function. The argument ``func`` must support the + corresponding signature. The ``_As_XX_X`` variants assume ndarrays + of one data type but cast the values at each iteration of the loop + to use the underlying function that takes a different data type. + +.. c:function:: void PyUFunc_O_O( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + +.. c:function:: void PyUFunc_OO_O( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + + One-input, one-output, and two-input, one-output core 1-d functions + for the :c:data:`NPY_OBJECT` data type. These functions handle reference + count issues and return early on error. The actual function to call is + *func* and it must accept calls with the signature ``(PyObject*) + (PyObject*)`` for :c:func:`PyUFunc_O_O` or ``(PyObject*)(PyObject *, + PyObject *)`` for :c:func:`PyUFunc_OO_O`. + +.. c:function:: void PyUFunc_O_O_method( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + + This general purpose 1-d core function assumes that *func* is a string + representing a method of the input object. For each + iteration of the loop, the Python object is extracted from the array + and its *func* method is called returning the result to the output array. + +.. c:function:: void PyUFunc_OO_O_method( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + + This general purpose 1-d core function assumes that *func* is a + string representing a method of the input object that takes one + argument. The first argument in *args* is the method whose function is + called, the second argument in *args* is the argument passed to the + function. The output of the function is stored in the third entry + of *args*. + +.. c:function:: void PyUFunc_On_Om( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* func) + + This is the 1-d core function used by the dynamic ufuncs created + by umath.frompyfunc(function, nin, nout). In this case *func* is a + pointer to a :c:type:`PyUFunc_PyFuncData` structure which has definition + + .. c:type:: PyUFunc_PyFuncData + + .. code-block:: c + + typedef struct { + int nin; + int nout; + PyObject *callable; + } PyUFunc_PyFuncData; + + At each iteration of the loop, the *nin* input objects are extracted + from their object arrays and placed into an argument tuple, the Python + *callable* is called with the input arguments, and the nout + outputs are placed into their object arrays. + + +Importing the API +----------------- + +.. c:var:: PY_UFUNC_UNIQUE_SYMBOL + +.. c:var:: NO_IMPORT_UFUNC + +.. c:function:: void import_ufunc(void) + + These are the constants and functions for accessing the ufunc + C-API from extension modules in precisely the same way as the + array C-API can be accessed. The ``import_ufunc`` () function must + always be called (in the initialization subroutine of the + extension module). If your extension module is in one file then + that is all that is required. The other two constants are useful + if your extension module makes use of multiple files. In that + case, define :c:data:`PY_UFUNC_UNIQUE_SYMBOL` to something unique to + your code and then in source files that do not contain the module + initialization function but still need access to the UFUNC API, + define :c:data:`PY_UFUNC_UNIQUE_SYMBOL` to the same name used previously + and also define :c:data:`NO_IMPORT_UFUNC`. + + The C-API is actually an array of function pointers. This array is + created (and pointed to by a global variable) by import_ufunc. The + global variable is either statically defined or allowed to be seen + by other files depending on the state of + :c:data:`PY_UFUNC_UNIQUE_SYMBOL` and :c:data:`NO_IMPORT_UFUNC`. + +.. index:: + pair: ufunc; C-API diff --git a/doc/source/reference/distutils.rst b/doc/source/reference/distutils.rst new file mode 100644 index 0000000..2898229 --- /dev/null +++ b/doc/source/reference/distutils.rst @@ -0,0 +1,316 @@ +********************************** +Packaging (:mod:`numpy.distutils`) +********************************** + +.. module:: numpy.distutils + +NumPy provides enhanced distutils functionality to make it easier to +build and install sub-packages, auto-generate code, and extension +modules that use Fortran-compiled libraries. To use features of NumPy +distutils, use the :func:`setup ` command from +:mod:`numpy.distutils.core`. A useful :class:`Configuration +` class is also provided in +:mod:`numpy.distutils.misc_util` that can make it easier to construct +keyword arguments to pass to the setup function (by passing the +dictionary obtained from the todict() method of the class). More +information is available in the NumPy Distutils Users Guide in +``/numpy/doc/DISTUTILS.txt``. + + +.. index:: + single: distutils + + +Modules in :mod:`numpy.distutils` +================================= + +misc_util +--------- + +.. module:: numpy.distutils.misc_util + +.. autosummary:: + :toctree: generated/ + + get_numpy_include_dirs + dict_append + appendpath + allpath + dot_join + generate_config_py + get_cmd + terminal_has_colors + red_text + green_text + yellow_text + blue_text + cyan_text + cyg2win32 + all_strings + has_f_sources + has_cxx_sources + filter_sources + get_dependencies + is_local_src_dir + get_ext_source_files + get_script_files + + +.. class:: Configuration(package_name=None, parent_name=None, top_path=None, package_path=None, **attrs) + + Construct a configuration instance for the given package name. If + *parent_name* is not None, then construct the package as a + sub-package of the *parent_name* package. If *top_path* and + *package_path* are None then they are assumed equal to + the path of the file this instance was created in. The setup.py + files in the numpy distribution are good examples of how to use + the :class:`Configuration` instance. + + .. automethod:: todict + + .. automethod:: get_distribution + + .. automethod:: get_subpackage + + .. automethod:: add_subpackage + + .. automethod:: add_data_files + + .. automethod:: add_data_dir + + .. automethod:: add_include_dirs + + .. automethod:: add_headers + + .. automethod:: add_extension + + .. automethod:: add_library + + .. automethod:: add_scripts + + .. automethod:: add_installed_library + + .. automethod:: add_npy_pkg_config + + .. automethod:: paths + + .. automethod:: get_config_cmd + + .. automethod:: get_build_temp_dir + + .. automethod:: have_f77c + + .. automethod:: have_f90c + + .. automethod:: get_version + + .. automethod:: make_svn_version_py + + .. automethod:: make_config_py + + .. automethod:: get_info + +Other modules +------------- + +.. currentmodule:: numpy.distutils + +.. autosummary:: + :toctree: generated/ + + system_info.get_info + system_info.get_standard_file + cpuinfo.cpu + log.set_verbosity + exec_command + +Building Installable C libraries +================================ + +Conventional C libraries (installed through `add_library`) are not installed, and +are just used during the build (they are statically linked). An installable C +library is a pure C library, which does not depend on the python C runtime, and +is installed such that it may be used by third-party packages. To build and +install the C library, you just use the method `add_installed_library` instead of +`add_library`, which takes the same arguments except for an additional +``install_dir`` argument:: + + >>> config.add_installed_library('foo', sources=['foo.c'], install_dir='lib') + +npy-pkg-config files +-------------------- + +To make the necessary build options available to third parties, you could use +the `npy-pkg-config` mechanism implemented in `numpy.distutils`. This mechanism is +based on a .ini file which contains all the options. A .ini file is very +similar to .pc files as used by the pkg-config unix utility:: + + [meta] + Name: foo + Version: 1.0 + Description: foo library + + [variables] + prefix = /home/user/local + libdir = ${prefix}/lib + includedir = ${prefix}/include + + [default] + cflags = -I${includedir} + libs = -L${libdir} -lfoo + +Generally, the file needs to be generated during the build, since it needs some +information known at build time only (e.g. prefix). This is mostly automatic if +one uses the `Configuration` method `add_npy_pkg_config`. Assuming we have a +template file foo.ini.in as follows:: + + [meta] + Name: foo + Version: @version@ + Description: foo library + + [variables] + prefix = @prefix@ + libdir = ${prefix}/lib + includedir = ${prefix}/include + + [default] + cflags = -I${includedir} + libs = -L${libdir} -lfoo + +and the following code in setup.py:: + + >>> config.add_installed_library('foo', sources=['foo.c'], install_dir='lib') + >>> subst = {'version': '1.0'} + >>> config.add_npy_pkg_config('foo.ini.in', 'lib', subst_dict=subst) + +This will install the file foo.ini into the directory package_dir/lib, and the +foo.ini file will be generated from foo.ini.in, where each ``@version@`` will be +replaced by ``subst_dict['version']``. The dictionary has an additional prefix +substitution rule automatically added, which contains the install prefix (since +this is not easy to get from setup.py). npy-pkg-config files can also be +installed at the same location as used for numpy, using the path returned from +`get_npy_pkg_dir` function. + +Reusing a C library from another package +---------------------------------------- + +Info are easily retrieved from the `get_info` function in +`numpy.distutils.misc_util`:: + + >>> info = get_info('npymath') + >>> config.add_extension('foo', sources=['foo.c'], extra_info=**info) + +An additional list of paths to look for .ini files can be given to `get_info`. + +Conversion of ``.src`` files +============================ + +NumPy distutils supports automatic conversion of source files named +.src. This facility can be used to maintain very similar +code blocks requiring only simple changes between blocks. During the +build phase of setup, if a template file named .src is +encountered, a new file named is constructed from the +template and placed in the build directory to be used instead. Two +forms of template conversion are supported. The first form occurs for +files named .ext.src where ext is a recognized Fortran +extension (f, f90, f95, f77, for, ftn, pyf). The second form is used +for all other cases. + +.. index:: + single: code generation + +Fortran files +------------- + +This template converter will replicate all **function** and +**subroutine** blocks in the file with names that contain '<...>' +according to the rules in '<...>'. The number of comma-separated words +in '<...>' determines the number of times the block is repeated. What +these words are indicates what that repeat rule, '<...>', should be +replaced with in each block. All of the repeat rules in a block must +contain the same number of comma-separated words indicating the number +of times that block should be repeated. If the word in the repeat rule +needs a comma, leftarrow, or rightarrow, then prepend it with a +backslash ' \'. If a word in the repeat rule matches ' \\' then +it will be replaced with the -th word in the same repeat +specification. There are two forms for the repeat rule: named and +short. + + +Named repeat rule +^^^^^^^^^^^^^^^^^ + +A named repeat rule is useful when the same set of repeats must be +used several times in a block. It is specified using , where N is the number of times the block +should be repeated. On each repeat of the block, the entire +expression, '<...>' will be replaced first with item1, and then with +item2, and so forth until N repeats are accomplished. Once a named +repeat specification has been introduced, the same repeat rule may be +used **in the current block** by referring only to the name +(i.e. . + + +Short repeat rule +^^^^^^^^^^^^^^^^^ + +A short repeat rule looks like . The +rule specifies that the entire expression, '<...>' should be replaced +first with item1, and then with item2, and so forth until N repeats +are accomplished. + + +Pre-defined names +^^^^^^^^^^^^^^^^^ + +The following predefined named repeat rules are available: + +- + +- <_c=s,d,c,z> + +- <_t=real, double precision, complex, double complex> + +- + +- + +- + +- + + +Other files +----------- + +Non-Fortran files use a separate syntax for defining template blocks +that should be repeated using a variable expansion similar to the +named repeat rules of the Fortran-specific repeats. The template rules +for these files are: + +1. "/\**begin repeat "on a line by itself marks the beginning of + a segment that should be repeated. + +2. Named variable expansions are defined using #name=item1, item2, item3, + ..., itemN# and placed on successive lines. These variables are + replaced in each repeat block with corresponding word. All named + variables in the same repeat block must define the same number of + words. + +3. In specifying the repeat rule for a named variable, item*N is short- + hand for item, item, ..., item repeated N times. In addition, + parenthesis in combination with \*N can be used for grouping several + items that should be repeated. Thus, #name=(item1, item2)*4# is + equivalent to #name=item1, item2, item1, item2, item1, item2, item1, + item2# + +4. "\*/ "on a line by itself marks the end of the variable expansion + naming. The next line is the first line that will be repeated using + the named rules. + +5. Inside the block to be repeated, the variables that should be expanded + are specified as @name@. + +6. "/\**end repeat**/ "on a line by itself marks the previous line + as the last line of the block to be repeated. diff --git a/doc/source/reference/figures/dtype-hierarchy.dia b/doc/source/reference/figures/dtype-hierarchy.dia new file mode 100644 index 0000000..62e925c Binary files /dev/null and b/doc/source/reference/figures/dtype-hierarchy.dia differ diff --git a/doc/source/reference/figures/dtype-hierarchy.pdf b/doc/source/reference/figures/dtype-hierarchy.pdf new file mode 100644 index 0000000..6ce496a Binary files /dev/null and b/doc/source/reference/figures/dtype-hierarchy.pdf differ diff --git a/doc/source/reference/figures/dtype-hierarchy.png b/doc/source/reference/figures/dtype-hierarchy.png new file mode 100644 index 0000000..6c45758 Binary files /dev/null and b/doc/source/reference/figures/dtype-hierarchy.png differ diff --git a/doc/source/reference/figures/threefundamental.fig b/doc/source/reference/figures/threefundamental.fig new file mode 100644 index 0000000..79760c4 --- /dev/null +++ b/doc/source/reference/figures/threefundamental.fig @@ -0,0 +1,57 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +6 1950 2850 4350 3450 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 1950 2850 4350 2850 4350 3450 1950 3450 1950 2850 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 2550 2850 2550 3450 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 3150 2850 3150 3450 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 3750 2850 3750 3450 +-6 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 5100 2850 7500 2850 7500 3450 5100 3450 5100 2850 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 5700 2850 5700 3450 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 6300 2850 6300 3450 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 6900 2850 6900 3450 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 7800 3600 7800 2700 525 2700 525 3600 7800 3600 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 675 2850 1725 2850 1725 3450 675 3450 675 2850 +2 2 0 4 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 5700 2850 6300 2850 6300 3450 5700 3450 5700 2850 +2 2 0 4 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 5700 1725 6300 1725 6300 2325 5700 2325 5700 1725 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 6450 2475 6450 1275 5550 1275 5550 2475 6450 2475 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 5700 1350 6300 1350 6300 1575 5700 1575 5700 1350 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3 + 2 1 1.00 60.00 120.00 + 900 2850 900 1875 1575 1875 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 1.00 60.00 120.00 + 3375 1800 5550 1800 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 1.00 60.00 120.00 + 6000 2850 6000 2325 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 3375 2100 3375 1575 1575 1575 1575 2100 3375 2100 +4 0 0 50 -1 18 14 0.0000 4 165 720 825 3225 header\001 +4 0 0 50 -1 2 40 0.0000 4 105 450 4500 3225 ...\001 +4 0 0 50 -1 18 14 0.0000 4 210 810 3600 3900 ndarray\001 +4 0 0 50 -1 18 14 0.0000 4 165 630 6600 2175 scalar\001 +4 0 0 50 -1 18 14 0.0000 4 165 540 6600 1950 array\001 +4 0 0 50 -1 16 12 0.0000 4 135 420 5775 1500 head\001 +4 0 0 50 -1 18 14 0.0000 4 210 975 1950 1875 data-type\001 diff --git a/doc/source/reference/figures/threefundamental.pdf b/doc/source/reference/figures/threefundamental.pdf new file mode 100644 index 0000000..b89e9f2 Binary files /dev/null and b/doc/source/reference/figures/threefundamental.pdf differ diff --git a/doc/source/reference/figures/threefundamental.png b/doc/source/reference/figures/threefundamental.png new file mode 100644 index 0000000..de252fc Binary files /dev/null and b/doc/source/reference/figures/threefundamental.png differ diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst new file mode 100644 index 0000000..f74816d --- /dev/null +++ b/doc/source/reference/index.rst @@ -0,0 +1,43 @@ +.. _reference: + +############### +NumPy Reference +############### + +:Release: |version| +:Date: |today| + + +.. module:: numpy + +This reference manual details functions, modules, and objects +included in NumPy, describing what they are and what they do. +For learning how to use NumPy, see also :ref:`user`. + + +.. toctree:: + :maxdepth: 2 + + arrays + ufuncs + routines + distutils + c-api + internals + swig + + +Acknowledgements +================ + +Large parts of this manual originate from Travis E. Oliphant's book +`Guide to NumPy `__ (which generously entered +Public Domain in August 2008). The reference documentation for many of +the functions are written by numerous contributors and developers of +NumPy, both prior to and during the +`NumPy Documentation Marathon +`__. + +Please help to improve NumPy's documentation! Instructions on how to +join the ongoing documentation marathon can be found +`on the scipy.org website `__ diff --git a/doc/source/reference/internals.code-explanations.rst b/doc/source/reference/internals.code-explanations.rst new file mode 100644 index 0000000..ca81e16 --- /dev/null +++ b/doc/source/reference/internals.code-explanations.rst @@ -0,0 +1,617 @@ +.. currentmodule:: numpy + +************************* +NumPy C Code Explanations +************************* + + Fanaticism consists of redoubling your efforts when you have forgotten + your aim. + --- *George Santayana* + + An authority is a person who can tell you more about something than + you really care to know. + --- *Unknown* + +This Chapter attempts to explain the logic behind some of the new +pieces of code. The purpose behind these explanations is to enable +somebody to be able to understand the ideas behind the implementation +somewhat more easily than just staring at the code. Perhaps in this +way, the algorithms can be improved on, borrowed from, and/or +optimized. + + +Memory model +============ + +.. index:: + pair: ndarray; memory model + +One fundamental aspect of the ndarray is that an array is seen as a +"chunk" of memory starting at some location. The interpretation of +this memory depends on the stride information. For each dimension in +an :math:`N` -dimensional array, an integer (stride) dictates how many +bytes must be skipped to get to the next element in that dimension. +Unless you have a single-segment array, this stride information must +be consulted when traversing through an array. It is not difficult to +write code that accepts strides, you just have to use (char \*) +pointers because strides are in units of bytes. Keep in mind also that +strides do not have to be unit-multiples of the element size. Also, +remember that if the number of dimensions of the array is 0 (sometimes +called a rank-0 array), then the strides and dimensions variables are +NULL. + +Besides the structural information contained in the strides and +dimensions members of the :c:type:`PyArrayObject`, the flags contain +important information about how the data may be accessed. In particular, +the :c:data:`NPY_ARRAY_ALIGNED` flag is set when the memory is on a +suitable boundary according to the data-type array. Even if you have +a contiguous chunk of memory, you cannot just assume it is safe to +dereference a data- type-specific pointer to an element. Only if the +:c:data:`NPY_ARRAY_ALIGNED` flag is set is this a safe operation (on +some platforms it will work but on others, like Solaris, it will cause +a bus error). The :c:data:`NPY_ARRAY_WRITEABLE` should also be ensured +if you plan on writing to the memory area of the array. It is also +possible to obtain a pointer to an unwritable memory area. Sometimes, +writing to the memory area when the :c:data:`NPY_ARRAY_WRITEABLE` flag is not +set will just be rude. Other times it can cause program crashes ( *e.g.* +a data-area that is a read-only memory-mapped file). + + +Data-type encapsulation +======================= + +.. index:: + single: dtype + +The data-type is an important abstraction of the ndarray. Operations +will look to the data-type to provide the key functionality that is +needed to operate on the array. This functionality is provided in the +list of function pointers pointed to by the 'f' member of the +:c:type:`PyArray_Descr` structure. In this way, the number of data-types can be +extended simply by providing a :c:type:`PyArray_Descr` structure with suitable +function pointers in the 'f' member. For built-in types there are some +optimizations that by-pass this mechanism, but the point of the data- +type abstraction is to allow new data-types to be added. + +One of the built-in data-types, the void data-type allows for +arbitrary structured types containing 1 or more fields as elements of the +array. A field is simply another data-type object along with an offset +into the current structured type. In order to support arbitrarily nested +fields, several recursive implementations of data-type access are +implemented for the void type. A common idiom is to cycle through the +elements of the dictionary and perform a specific operation based on +the data-type object stored at the given offset. These offsets can be +arbitrary numbers. Therefore, the possibility of encountering mis- +aligned data must be recognized and taken into account if necessary. + + +N-D Iterators +============= + +.. index:: + single: array iterator + +A very common operation in much of NumPy code is the need to iterate +over all the elements of a general, strided, N-dimensional array. This +operation of a general-purpose N-dimensional loop is abstracted in the +notion of an iterator object. To write an N-dimensional loop, you only +have to create an iterator object from an ndarray, work with the +dataptr member of the iterator object structure and call the macro +:c:func:`PyArray_ITER_NEXT` (it) on the iterator object to move to the next +element. The "next" element is always in C-contiguous order. The macro +works by first special casing the C-contiguous, 1-D, and 2-D cases +which work very simply. + +For the general case, the iteration works by keeping track of a list +of coordinate counters in the iterator object. At each iteration, the +last coordinate counter is increased (starting from 0). If this +counter is smaller than one less than the size of the array in that +dimension (a pre-computed and stored value), then the counter is +increased and the dataptr member is increased by the strides in that +dimension and the macro ends. If the end of a dimension is reached, +the counter for the last dimension is reset to zero and the dataptr is +moved back to the beginning of that dimension by subtracting the +strides value times one less than the number of elements in that +dimension (this is also pre-computed and stored in the backstrides +member of the iterator object). In this case, the macro does not end, +but a local dimension counter is decremented so that the next-to-last +dimension replaces the role that the last dimension played and the +previously-described tests are executed again on the next-to-last +dimension. In this way, the dataptr is adjusted appropriately for +arbitrary striding. + +The coordinates member of the :c:type:`PyArrayIterObject` structure maintains +the current N-d counter unless the underlying array is C-contiguous in +which case the coordinate counting is by-passed. The index member of +the :c:type:`PyArrayIterObject` keeps track of the current flat index of the +iterator. It is updated by the :c:func:`PyArray_ITER_NEXT` macro. + + +Broadcasting +============ + +.. index:: + single: broadcasting + +In Numeric, broadcasting was implemented in several lines of code +buried deep in ufuncobject.c. In NumPy, the notion of broadcasting has +been abstracted so that it can be performed in multiple places. +Broadcasting is handled by the function :c:func:`PyArray_Broadcast`. This +function requires a :c:type:`PyArrayMultiIterObject` (or something that is a +binary equivalent) to be passed in. The :c:type:`PyArrayMultiIterObject` keeps +track of the broadcast number of dimensions and size in each +dimension along with the total size of the broadcast result. It also +keeps track of the number of arrays being broadcast and a pointer to +an iterator for each of the arrays being broadcast. + +The :c:func:`PyArray_Broadcast` function takes the iterators that have already +been defined and uses them to determine the broadcast shape in each +dimension (to create the iterators at the same time that broadcasting +occurs then use the :c:func:`PyMultiIter_New` function). Then, the iterators are +adjusted so that each iterator thinks it is iterating over an array +with the broadcast size. This is done by adjusting the iterators +number of dimensions, and the shape in each dimension. This works +because the iterator strides are also adjusted. Broadcasting only +adjusts (or adds) length-1 dimensions. For these dimensions, the +strides variable is simply set to 0 so that the data-pointer for the +iterator over that array doesn't move as the broadcasting operation +operates over the extended dimension. + +Broadcasting was always implemented in Numeric using 0-valued strides +for the extended dimensions. It is done in exactly the same way in +NumPy. The big difference is that now the array of strides is kept +track of in a :c:type:`PyArrayIterObject`, the iterators involved in a +broadcast result are kept track of in a :c:type:`PyArrayMultiIterObject`, +and the :c:func:`PyArray_BroadCast` call implements the broad-casting rules. + + +Array Scalars +============= + +.. index:: + single: array scalars + +The array scalars offer a hierarchy of Python types that allow a one- +to-one correspondence between the data-type stored in an array and the +Python-type that is returned when an element is extracted from the +array. An exception to this rule was made with object arrays. Object +arrays are heterogeneous collections of arbitrary Python objects. When +you select an item from an object array, you get back the original +Python object (and not an object array scalar which does exist but is +rarely used for practical purposes). + +The array scalars also offer the same methods and attributes as arrays +with the intent that the same code can be used to support arbitrary +dimensions (including 0-dimensions). The array scalars are read-only +(immutable) with the exception of the void scalar which can also be +written to so that structured array field setting works more naturally +(a[0]['f1'] = ``value`` ). + + +Indexing +======== + +.. index:: + single: indexing + +All python indexing operations ``arr[index]`` are organized by first preparing +the index and finding the index type. The supported index types are: + +* integer +* newaxis +* slice +* ellipsis +* integer arrays/array-likes (fancy) +* boolean (single boolean array); if there is more than one boolean array as + index or the shape does not match exactly, the boolean array will be + converted to an integer array instead. +* 0-d boolean (and also integer); 0-d boolean arrays are a special + case which has to be handled in the advanced indexing code. They signal + that a 0-d boolean array had to be interpreted as an integer array. + +As well as the scalar array special case signaling that an integer array +was interpreted as an integer index, which is important because an integer +array index forces a copy but is ignored if a scalar is returned (full integer +index). The prepared index is guaranteed to be valid with the exception of +out of bound values and broadcasting errors for advanced indexing. This +includes that an ellipsis is added for incomplete indices for example when +a two dimensional array is indexed with a single integer. + +The next step depends on the type of index which was found. If all +dimensions are indexed with an integer a scalar is returned or set. A +single boolean indexing array will call specialized boolean functions. +Indices containing an ellipsis or slice but no advanced indexing will +always create a view into the old array by calculating the new strides and +memory offset. This view can then either be returned or, for assignments, +filled using :c:func:`PyArray_CopyObject`. Note that `PyArray_CopyObject` +may also be called on temporary arrays in other branches to support +complicated assignments when the array is of object dtype. + +Advanced indexing +----------------- + +By far the most complex case is advanced indexing, which may or may not be +combined with typical view based indexing. Here integer indices are +interpreted as view based. Before trying to understand this, you may want +to make yourself familiar with its subtleties. The advanced indexing code +has three different branches and one special case: + +* There is one indexing array and it, as well as the assignment array, can + be iterated trivially. For example they may be contiguous. Also the + indexing array must be of `intp` type and the value array in assignments + should be of the correct type. This is purely a fast path. +* There are only integer array indices so that no subarray exists. +* View based and advanced indexing is mixed. In this case the view based + indexing defines a collection of subarrays that are combined by the + advanced indexing. For example, ``arr[[1, 2, 3], :]`` is created by + vertically stacking the subarrays ``arr[1, :]``, ``arr[2,:]``, and + ``arr[3, :]``. +* There is a subarray but it has exactly one element. This case can be handled + as if there is no subarray, but needs some care during setup. + +Deciding what case applies, checking broadcasting, and determining the kind +of transposition needed are all done in `PyArray_MapIterNew`. After setting +up, there are two cases. If there is no subarray or it only has one +element, no subarray iteration is necessary and an iterator is prepared +which iterates all indexing arrays *as well as* the result or value array. +If there is a subarray, there are three iterators prepared. One for the +indexing arrays, one for the result or value array (minus its subarray), +and one for the subarrays of the original and the result/assignment array. +The first two iterators give (or allow calculation) of the pointers into +the start of the subarray, which then allows to restart the subarray +iteration. + +When advanced indices are next to each other transposing may be necessary. +All necessary transposing is handled by :c:func:`PyArray_MapIterSwapAxes` and +has to be handled by the caller unless `PyArray_MapIterNew` is asked to +allocate the result. + +After preparation, getting and setting is relatively straight forward, +although the different modes of iteration need to be considered. Unless +there is only a single indexing array during item getting, the validity of +the indices is checked beforehand. Otherwise it is handled in the inner +loop itself for optimization. + + +Universal Functions +=================== + +.. index:: + single: ufunc + +Universal functions are callable objects that take :math:`N` inputs +and produce :math:`M` outputs by wrapping basic 1-D loops that work +element-by-element into full easy-to use functions that seamlessly +implement broadcasting, type-checking and buffered coercion, and +output-argument handling. New universal functions are normally created +in C, although there is a mechanism for creating ufuncs from Python +functions (:func:`frompyfunc`). The user must supply a 1-D loop that +implements the basic function taking the input scalar values and +placing the resulting scalars into the appropriate output slots as +explained in implementation. + + +Setup +----- + +Every ufunc calculation involves some overhead related to setting up +the calculation. The practical significance of this overhead is that +even though the actual calculation of the ufunc is very fast, you will +be able to write array and type-specific code that will work faster +for small arrays than the ufunc. In particular, using ufuncs to +perform many calculations on 0-D arrays will be slower than other +Python-based solutions (the silently-imported scalarmath module exists +precisely to give array scalars the look-and-feel of ufunc based +calculations with significantly reduced overhead). + +When a ufunc is called, many things must be done. The information +collected from these setup operations is stored in a loop-object. This +loop object is a C-structure (that could become a Python object but is +not initialized as such because it is only used internally). This loop +object has the layout needed to be used with PyArray_Broadcast so that +the broadcasting can be handled in the same way as it is handled in +other sections of code. + +The first thing done is to look-up in the thread-specific global +dictionary the current values for the buffer-size, the error mask, and +the associated error object. The state of the error mask controls what +happens when an error condition is found. It should be noted that +checking of the hardware error flags is only performed after each 1-D +loop is executed. This means that if the input and output arrays are +contiguous and of the correct type so that a single 1-D loop is +performed, then the flags may not be checked until all elements of the +array have been calculated. Looking up these values in a thread- +specific dictionary takes time which is easily ignored for all but +very small arrays. + +After checking, the thread-specific global variables, the inputs are +evaluated to determine how the ufunc should proceed and the input and +output arrays are constructed if necessary. Any inputs which are not +arrays are converted to arrays (using context if necessary). Which of +the inputs are scalars (and therefore converted to 0-D arrays) is +noted. + +Next, an appropriate 1-D loop is selected from the 1-D loops available +to the ufunc based on the input array types. This 1-D loop is selected +by trying to match the signature of the data-types of the inputs +against the available signatures. The signatures corresponding to +built-in types are stored in the types member of the ufunc structure. +The signatures corresponding to user-defined types are stored in a +linked-list of function-information with the head element stored as a +``CObject`` in the userloops dictionary keyed by the data-type number +(the first user-defined type in the argument list is used as the key). +The signatures are searched until a signature is found to which the +input arrays can all be cast safely (ignoring any scalar arguments +which are not allowed to determine the type of the result). The +implication of this search procedure is that "lesser types" should be +placed below "larger types" when the signatures are stored. If no 1-D +loop is found, then an error is reported. Otherwise, the argument_list +is updated with the stored signature --- in case casting is necessary +and to fix the output types assumed by the 1-D loop. + +If the ufunc has 2 inputs and 1 output and the second input is an +Object array then a special-case check is performed so that +NotImplemented is returned if the second input is not an ndarray, has +the __array_priority\__ attribute, and has an __r{op}\__ special +method. In this way, Python is signaled to give the other object a +chance to complete the operation instead of using generic object-array +calculations. This allows (for example) sparse matrices to override +the multiplication operator 1-D loop. + +For input arrays that are smaller than the specified buffer size, +copies are made of all non-contiguous, mis-aligned, or out-of- +byteorder arrays to ensure that for small arrays, a single loop is +used. Then, array iterators are created for all the input arrays and +the resulting collection of iterators is broadcast to a single shape. + +The output arguments (if any) are then processed and any missing +return arrays are constructed. If any provided output array doesn't +have the correct type (or is mis-aligned) and is smaller than the +buffer size, then a new output array is constructed with the special +:c:data:`WRITEBACKIFCOPY` flag set. At the end of the function, +:c:func:`PyArray_ResolveWritebackIfCopy` is called so that +its contents will be copied back into the output array. +Iterators for the output arguments are then processed. + +Finally, the decision is made about how to execute the looping +mechanism to ensure that all elements of the input arrays are combined +to produce the output arrays of the correct type. The options for loop +execution are one-loop (for contiguous, aligned, and correct data +type), strided-loop (for non-contiguous but still aligned and correct +data type), and a buffered loop (for mis-aligned or incorrect data +type situations). Depending on which execution method is called for, +the loop is then setup and computed. + + +Function call +------------- + +This section describes how the basic universal function computation loop is +setup and executed for each of the three different kinds of execution. If +:c:data:`NPY_ALLOW_THREADS` is defined during compilation, then as long as +no object arrays are involved, the Python Global Interpreter Lock (GIL) is +released prior to calling the loops. It is re-acquired if necessary to +handle error conditions. The hardware error flags are checked only after +the 1-D loop is completed. + + +One Loop +^^^^^^^^ + +This is the simplest case of all. The ufunc is executed by calling the +underlying 1-D loop exactly once. This is possible only when we have +aligned data of the correct type (including byte-order) for both input +and output and all arrays have uniform strides (either contiguous, +0-D, or 1-D). In this case, the 1-D computational loop is called once +to compute the calculation for the entire array. Note that the +hardware error flags are only checked after the entire calculation is +complete. + + +Strided Loop +^^^^^^^^^^^^ + +When the input and output arrays are aligned and of the correct type, +but the striding is not uniform (non-contiguous and 2-D or larger), +then a second looping structure is employed for the calculation. This +approach converts all of the iterators for the input and output +arguments to iterate over all but the largest dimension. The inner +loop is then handled by the underlying 1-D computational loop. The +outer loop is a standard iterator loop on the converted iterators. The +hardware error flags are checked after each 1-D loop is completed. + + +Buffered Loop +^^^^^^^^^^^^^ + +This is the code that handles the situation whenever the input and/or +output arrays are either misaligned or of the wrong data-type +(including being byte-swapped) from what the underlying 1-D loop +expects. The arrays are also assumed to be non-contiguous. The code +works very much like the strided-loop except for the inner 1-D loop is +modified so that pre-processing is performed on the inputs and post- +processing is performed on the outputs in bufsize chunks (where +bufsize is a user-settable parameter). The underlying 1-D +computational loop is called on data that is copied over (if it needs +to be). The setup code and the loop code is considerably more +complicated in this case because it has to handle: + +- memory allocation of the temporary buffers + +- deciding whether or not to use buffers on the input and output data + (mis-aligned and/or wrong data-type) + +- copying and possibly casting data for any inputs or outputs for which + buffers are necessary. + +- special-casing Object arrays so that reference counts are properly + handled when copies and/or casts are necessary. + +- breaking up the inner 1-D loop into bufsize chunks (with a possible + remainder). + +Again, the hardware error flags are checked at the end of each 1-D +loop. + + +Final output manipulation +------------------------- + +Ufuncs allow other array-like classes to be passed seamlessly through +the interface in that inputs of a particular class will induce the +outputs to be of that same class. The mechanism by which this works is +the following. If any of the inputs are not ndarrays and define the +:obj:`~numpy.class.__array_wrap__` method, then the class with the largest +:obj:`~numpy.class.__array_priority__` attribute determines the type of all the +outputs (with the exception of any output arrays passed in). The +:obj:`~numpy.class.__array_wrap__` method of the input array will be called with the +ndarray being returned from the ufunc as it's input. There are two +calling styles of the :obj:`~numpy.class.__array_wrap__` function supported. The first +takes the ndarray as the first argument and a tuple of "context" as +the second argument. The context is (ufunc, arguments, output argument +number). This is the first call tried. If a TypeError occurs, then the +function is called with just the ndarray as the first argument. + + +Methods +------- + +There are three methods of ufuncs that require calculation similar to +the general-purpose ufuncs. These are reduce, accumulate, and +reduceat. Each of these methods requires a setup command followed by a +loop. There are four loop styles possible for the methods +corresponding to no-elements, one-element, strided-loop, and buffered- +loop. These are the same basic loop styles as implemented for the +general purpose function call except for the no-element and one- +element cases which are special-cases occurring when the input array +objects have 0 and 1 elements respectively. + + +Setup +^^^^^ + +The setup function for all three methods is ``construct_reduce``. +This function creates a reducing loop object and fills it with +parameters needed to complete the loop. All of the methods only work +on ufuncs that take 2-inputs and return 1 output. Therefore, the +underlying 1-D loop is selected assuming a signature of [ ``otype``, +``otype``, ``otype`` ] where ``otype`` is the requested reduction +data-type. The buffer size and error handling is then retrieved from +(per-thread) global storage. For small arrays that are mis-aligned or +have incorrect data-type, a copy is made so that the un-buffered +section of code is used. Then, the looping strategy is selected. If +there is 1 element or 0 elements in the array, then a simple looping +method is selected. If the array is not mis-aligned and has the +correct data-type, then strided looping is selected. Otherwise, +buffered looping must be performed. Looping parameters are then +established, and the return array is constructed. The output array is +of a different shape depending on whether the method is reduce, +accumulate, or reduceat. If an output array is already provided, then +it's shape is checked. If the output array is not C-contiguous, +aligned, and of the correct data type, then a temporary copy is made +with the WRITEBACKIFCOPY flag set. In this way, the methods will be able +to work with a well-behaved output array but the result will be copied +back into the true output array when :c:func:`PyArray_ResolveWritebackIfCopy` +is called at function completion. +Finally, iterators are set up to loop over the correct axis +(depending on the value of axis provided to the method) and the setup +routine returns to the actual computation routine. + + +Reduce +^^^^^^ + +.. index:: + triple: ufunc; methods; reduce + +All of the ufunc methods use the same underlying 1-D computational +loops with input and output arguments adjusted so that the appropriate +reduction takes place. For example, the key to the functioning of +reduce is that the 1-D loop is called with the output and the second +input pointing to the same position in memory and both having a step- +size of 0. The first input is pointing to the input array with a step- +size given by the appropriate stride for the selected axis. In this +way, the operation performed is + +.. math:: + :nowrap: + + \begin{align*} + o & = & i[0] \\ + o & = & i[k]\textrm{}o\quad k=1\ldots N + \end{align*} + +where :math:`N+1` is the number of elements in the input, :math:`i`, +:math:`o` is the output, and :math:`i[k]` is the +:math:`k^{\textrm{th}}` element of :math:`i` along the selected axis. +This basic operations is repeated for arrays with greater than 1 +dimension so that the reduction takes place for every 1-D sub-array +along the selected axis. An iterator with the selected dimension +removed handles this looping. + +For buffered loops, care must be taken to copy and cast data before +the loop function is called because the underlying loop expects +aligned data of the correct data-type (including byte-order). The +buffered loop must handle this copying and casting prior to calling +the loop function on chunks no greater than the user-specified +bufsize. + + +Accumulate +^^^^^^^^^^ + +.. index:: + triple: ufunc; methods; accumulate + +The accumulate function is very similar to the reduce function in that +the output and the second input both point to the output. The +difference is that the second input points to memory one stride behind +the current output pointer. Thus, the operation performed is + +.. math:: + :nowrap: + + \begin{align*} + o[0] & = & i[0] \\ + o[k] & = & i[k]\textrm{}o[k-1]\quad k=1\ldots N. + \end{align*} + +The output has the same shape as the input and each 1-D loop operates +over :math:`N` elements when the shape in the selected axis is :math:`N+1`. +Again, buffered loops take care to copy and cast the data before +calling the underlying 1-D computational loop. + + +Reduceat +^^^^^^^^ + +.. index:: + triple: ufunc; methods; reduceat + single: ufunc + +The reduceat function is a generalization of both the reduce and +accumulate functions. It implements a reduce over ranges of the input +array specified by indices. The extra indices argument is checked to +be sure that every input is not too large for the input array along +the selected dimension before the loop calculations take place. The +loop implementation is handled using code that is very similar to the +reduce code repeated as many times as there are elements in the +indices input. In particular: the first input pointer passed to the +underlying 1-D computational loop points to the input array at the +correct location indicated by the index array. In addition, the output +pointer and the second input pointer passed to the underlying 1-D loop +point to the same position in memory. The size of the 1-D +computational loop is fixed to be the difference between the current +index and the next index (when the current index is the last index, +then the next index is assumed to be the length of the array along the +selected dimension). In this way, the 1-D loop will implement a reduce +over the specified indices. + +Mis-aligned or a loop data-type that does not match the input and/or +output data-type is handled using buffered code where-in data is +copied to a temporary buffer and cast to the correct data-type if +necessary prior to calling the underlying 1-D function. The temporary +buffers are created in (element) sizes no bigger than the user +settable buffer-size value. Thus, the loop must be flexible enough to +call the underlying 1-D computational loop enough times to complete +the total calculation in chunks no bigger than the buffer-size. diff --git a/doc/source/reference/internals.rst b/doc/source/reference/internals.rst new file mode 100644 index 0000000..e1d6644 --- /dev/null +++ b/doc/source/reference/internals.rst @@ -0,0 +1,9 @@ +*************** +NumPy internals +*************** + +.. toctree:: + + internals.code-explanations + +.. automodule:: numpy.doc.internals diff --git a/doc/source/reference/maskedarray.baseclass.rst b/doc/source/reference/maskedarray.baseclass.rst new file mode 100644 index 0000000..427ad15 --- /dev/null +++ b/doc/source/reference/maskedarray.baseclass.rst @@ -0,0 +1,461 @@ +.. currentmodule:: numpy.ma + + +.. _numpy.ma.constants: + +Constants of the :mod:`numpy.ma` module +======================================= + +In addition to the :class:`MaskedArray` class, the :mod:`numpy.ma` module +defines several constants. + +.. data:: masked + + The :attr:`masked` constant is a special case of :class:`MaskedArray`, + with a float datatype and a null shape. It is used to test whether a + specific entry of a masked array is masked, or to mask one or several + entries of a masked array:: + + >>> x = ma.array([1, 2, 3], mask=[0, 1, 0]) + >>> x[1] is ma.masked + True + >>> x[-1] = ma.masked + >>> x + masked_array(data = [1 -- --], + mask = [False True True], + fill_value = 999999) + + +.. data:: nomask + + Value indicating that a masked array has no invalid entry. + :attr:`nomask` is used internally to speed up computations when the mask + is not needed. + + +.. data:: masked_print_options + + String used in lieu of missing data when a masked array is printed. + By default, this string is ``'--'``. + + + + +.. _maskedarray.baseclass: + +The :class:`MaskedArray` class +============================== + + +.. class:: MaskedArray + + A subclass of :class:`~numpy.ndarray` designed to manipulate numerical arrays with missing data. + + + + An instance of :class:`MaskedArray` can be thought as the combination of several elements: + +* The :attr:`~MaskedArray.data`, as a regular :class:`numpy.ndarray` of any shape or datatype (the data). +* A boolean :attr:`~numpy.ma.MaskedArray.mask` with the same shape as the data, where a ``True`` value indicates that the corresponding element of the data is invalid. + The special value :const:`nomask` is also acceptable for arrays without named fields, and indicates that no data is invalid. +* A :attr:`~numpy.ma.MaskedArray.fill_value`, a value that may be used to replace the invalid entries in order to return a standard :class:`numpy.ndarray`. + + + +Attributes and properties of masked arrays +------------------------------------------ + +.. seealso:: :ref:`Array Attributes ` + + +.. attribute:: MaskedArray.data + + Returns the underlying data, as a view of the masked array. + If the underlying data is a subclass of :class:`numpy.ndarray`, it is + returned as such. + + >>> x = ma.array(np.matrix([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]]) + >>> x.data + matrix([[1, 2], + [3, 4]]) + + The type of the data can be accessed through the :attr:`baseclass` + attribute. + +.. attribute:: MaskedArray.mask + + Returns the underlying mask, as an array with the same shape and structure + as the data, but where all fields are atomically booleans. + A value of ``True`` indicates an invalid entry. + + +.. attribute:: MaskedArray.recordmask + + Returns the mask of the array if it has no named fields. For structured + arrays, returns a ndarray of booleans where entries are ``True`` if **all** + the fields are masked, ``False`` otherwise:: + + >>> x = ma.array([(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)], + ... mask=[(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)], + ... dtype=[('a', int), ('b', int)]) + >>> x.recordmask + array([False, False, True, False, False]) + + +.. attribute:: MaskedArray.fill_value + + Returns the value used to fill the invalid entries of a masked array. + The value is either a scalar (if the masked array has no named fields), + or a 0-D ndarray with the same :attr:`dtype` as the masked array if it has + named fields. + + The default filling value depends on the datatype of the array: + + ======== ======== + datatype default + ======== ======== + bool True + int 999999 + float 1.e20 + complex 1.e20+0j + object '?' + string 'N/A' + ======== ======== + + + +.. attribute:: MaskedArray.baseclass + + Returns the class of the underlying data. + + >>> x = ma.array(np.matrix([[1, 2], [3, 4]]), mask=[[0, 0], [1, 0]]) + >>> x.baseclass + + + +.. attribute:: MaskedArray.sharedmask + + Returns whether the mask of the array is shared between several masked arrays. + If this is the case, any modification to the mask of one array will be + propagated to the others. + + +.. attribute:: MaskedArray.hardmask + + Returns whether the mask is hard (``True``) or soft (``False``). + When the mask is hard, masked entries cannot be unmasked. + + +As :class:`MaskedArray` is a subclass of :class:`~numpy.ndarray`, a masked array also inherits all the attributes and properties of a :class:`~numpy.ndarray` instance. + +.. autosummary:: + :toctree: generated/ + + MaskedArray.base + MaskedArray.ctypes + MaskedArray.dtype + MaskedArray.flags + + MaskedArray.itemsize + MaskedArray.nbytes + MaskedArray.ndim + MaskedArray.shape + MaskedArray.size + MaskedArray.strides + + MaskedArray.imag + MaskedArray.real + + MaskedArray.flat + MaskedArray.__array_priority__ + + + +:class:`MaskedArray` methods +============================ + +.. seealso:: :ref:`Array methods ` + + +Conversion +---------- + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__float__ + MaskedArray.__hex__ + MaskedArray.__int__ + MaskedArray.__long__ + MaskedArray.__oct__ + + MaskedArray.view + MaskedArray.astype + MaskedArray.byteswap + + MaskedArray.compressed + MaskedArray.filled + MaskedArray.tofile + MaskedArray.toflex + MaskedArray.tolist + MaskedArray.torecords + MaskedArray.tostring + MaskedArray.tobytes + + +Shape manipulation +------------------ + +For reshape, resize, and transpose, the single tuple argument may be +replaced with ``n`` integers which will be interpreted as an n-tuple. + +.. autosummary:: + :toctree: generated/ + + MaskedArray.flatten + MaskedArray.ravel + MaskedArray.reshape + MaskedArray.resize + MaskedArray.squeeze + MaskedArray.swapaxes + MaskedArray.transpose + MaskedArray.T + + +Item selection and manipulation +------------------------------- + +For array methods that take an *axis* keyword, it defaults to `None`. +If axis is *None*, then the array is treated as a 1-D array. +Any other value for *axis* represents the dimension along which +the operation should proceed. + +.. autosummary:: + :toctree: generated/ + + MaskedArray.argmax + MaskedArray.argmin + MaskedArray.argsort + MaskedArray.choose + MaskedArray.compress + MaskedArray.diagonal + MaskedArray.fill + MaskedArray.item + MaskedArray.nonzero + MaskedArray.put + MaskedArray.repeat + MaskedArray.searchsorted + MaskedArray.sort + MaskedArray.take + + +Pickling and copy +----------------- + +.. autosummary:: + :toctree: generated/ + + MaskedArray.copy + MaskedArray.dump + MaskedArray.dumps + + +Calculations +------------ + +.. autosummary:: + :toctree: generated/ + + MaskedArray.all + MaskedArray.anom + MaskedArray.any + MaskedArray.clip + MaskedArray.conj + MaskedArray.conjugate + MaskedArray.cumprod + MaskedArray.cumsum + MaskedArray.max + MaskedArray.mean + MaskedArray.min + MaskedArray.prod + MaskedArray.product + MaskedArray.ptp + MaskedArray.round + MaskedArray.std + MaskedArray.sum + MaskedArray.trace + MaskedArray.var + + +Arithmetic and comparison operations +------------------------------------ + +.. index:: comparison, arithmetic, operation, operator + +Comparison operators: +~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__lt__ + MaskedArray.__le__ + MaskedArray.__gt__ + MaskedArray.__ge__ + MaskedArray.__eq__ + MaskedArray.__ne__ + +Truth value of an array (:func:`bool()`): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__nonzero__ + + +Arithmetic: +~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__abs__ + MaskedArray.__add__ + MaskedArray.__radd__ + MaskedArray.__sub__ + MaskedArray.__rsub__ + MaskedArray.__mul__ + MaskedArray.__rmul__ + MaskedArray.__div__ + MaskedArray.__rdiv__ + MaskedArray.__truediv__ + MaskedArray.__rtruediv__ + MaskedArray.__floordiv__ + MaskedArray.__rfloordiv__ + MaskedArray.__mod__ + MaskedArray.__rmod__ + MaskedArray.__divmod__ + MaskedArray.__rdivmod__ + MaskedArray.__pow__ + MaskedArray.__rpow__ + MaskedArray.__lshift__ + MaskedArray.__rlshift__ + MaskedArray.__rshift__ + MaskedArray.__rrshift__ + MaskedArray.__and__ + MaskedArray.__rand__ + MaskedArray.__or__ + MaskedArray.__ror__ + MaskedArray.__xor__ + MaskedArray.__rxor__ + + +Arithmetic, in-place: +~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__iadd__ + MaskedArray.__isub__ + MaskedArray.__imul__ + MaskedArray.__idiv__ + MaskedArray.__itruediv__ + MaskedArray.__ifloordiv__ + MaskedArray.__imod__ + MaskedArray.__ipow__ + MaskedArray.__ilshift__ + MaskedArray.__irshift__ + MaskedArray.__iand__ + MaskedArray.__ior__ + MaskedArray.__ixor__ + + +Representation +-------------- + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__repr__ + MaskedArray.__str__ + + MaskedArray.ids + MaskedArray.iscontiguous + + +Special methods +--------------- + +For standard library functions: + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__copy__ + MaskedArray.__deepcopy__ + MaskedArray.__getstate__ + MaskedArray.__reduce__ + MaskedArray.__setstate__ + +Basic customization: + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__new__ + MaskedArray.__array__ + MaskedArray.__array_wrap__ + +Container customization: (see :ref:`Indexing `) + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__len__ + MaskedArray.__getitem__ + MaskedArray.__setitem__ + MaskedArray.__delitem__ + MaskedArray.__contains__ + + + +Specific methods +---------------- + +Handling the mask +~~~~~~~~~~~~~~~~~ + +The following methods can be used to access information about the mask or to +manipulate the mask. + +.. autosummary:: + :toctree: generated/ + + MaskedArray.__setmask__ + + MaskedArray.harden_mask + MaskedArray.soften_mask + MaskedArray.unshare_mask + MaskedArray.shrink_mask + + +Handling the `fill_value` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MaskedArray.get_fill_value + MaskedArray.set_fill_value + + + +Counting the missing elements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MaskedArray.count diff --git a/doc/source/reference/maskedarray.generic.rst b/doc/source/reference/maskedarray.generic.rst new file mode 100644 index 0000000..07ad6c2 --- /dev/null +++ b/doc/source/reference/maskedarray.generic.rst @@ -0,0 +1,499 @@ +.. currentmodule:: numpy.ma + +.. _maskedarray.generic: + + + +The :mod:`numpy.ma` module +========================== + +Rationale +--------- + +Masked arrays are arrays that may have missing or invalid entries. +The :mod:`numpy.ma` module provides a nearly work-alike replacement for numpy +that supports data arrays with masks. + + + +What is a masked array? +----------------------- + +In many circumstances, datasets can be incomplete or tainted by the presence +of invalid data. For example, a sensor may have failed to record a data, or +recorded an invalid value. The :mod:`numpy.ma` module provides a convenient +way to address this issue, by introducing masked arrays. + +A masked array is the combination of a standard :class:`numpy.ndarray` and a +mask. A mask is either :attr:`nomask`, indicating that no value of the +associated array is invalid, or an array of booleans that determines for each +element of the associated array whether the value is valid or not. When an +element of the mask is ``False``, the corresponding element of the associated +array is valid and is said to be unmasked. When an element of the mask is +``True``, the corresponding element of the associated array is said to be +masked (invalid). + +The package ensures that masked entries are not used in computations. + +As an illustration, let's consider the following dataset:: + + >>> import numpy as np + >>> import numpy.ma as ma + >>> x = np.array([1, 2, 3, -1, 5]) + +We wish to mark the fourth entry as invalid. The easiest is to create a masked +array:: + + >>> mx = ma.masked_array(x, mask=[0, 0, 0, 1, 0]) + +We can now compute the mean of the dataset, without taking the invalid data +into account:: + + >>> mx.mean() + 2.75 + + +The :mod:`numpy.ma` module +-------------------------- + + +The main feature of the :mod:`numpy.ma` module is the :class:`MaskedArray` +class, which is a subclass of :class:`numpy.ndarray`. The class, its +attributes and methods are described in more details in the +:ref:`MaskedArray class ` section. + +The :mod:`numpy.ma` module can be used as an addition to :mod:`numpy`: :: + + >>> import numpy as np + >>> import numpy.ma as ma + +To create an array with the second element invalid, we would do:: + + >>> y = ma.array([1, 2, 3], mask = [0, 1, 0]) + +To create a masked array where all values close to 1.e20 are invalid, we would +do:: + + >>> z = masked_values([1.0, 1.e20, 3.0, 4.0], 1.e20) + +For a complete discussion of creation methods for masked arrays please see +section :ref:`Constructing masked arrays `. + + + + +Using numpy.ma +============== + +.. _maskedarray.generic.constructing: + +Constructing masked arrays +-------------------------- + +There are several ways to construct a masked array. + +* A first possibility is to directly invoke the :class:`MaskedArray` class. + +* A second possibility is to use the two masked array constructors, + :func:`array` and :func:`masked_array`. + + .. autosummary:: + :toctree: generated/ + + array + masked_array + + +* A third option is to take the view of an existing array. In that case, the + mask of the view is set to :attr:`nomask` if the array has no named fields, + or an array of boolean with the same structure as the array otherwise. + + >>> x = np.array([1, 2, 3]) + >>> x.view(ma.MaskedArray) + masked_array(data = [1 2 3], + mask = False, + fill_value = 999999) + >>> x = np.array([(1, 1.), (2, 2.)], dtype=[('a',int), ('b', float)]) + >>> x.view(ma.MaskedArray) + masked_array(data = [(1, 1.0) (2, 2.0)], + mask = [(False, False) (False, False)], + fill_value = (999999, 1e+20), + dtype = [('a', '>> x = ma.array([[1, 2], [3, 4]], mask=[[0, 1], [1, 0]]) + >>> x[~x.mask] + masked_array(data = [1 4], + mask = [False False], + fill_value = 999999) + +Another way to retrieve the valid data is to use the :meth:`compressed` +method, which returns a one-dimensional :class:`~numpy.ndarray` (or one of its +subclasses, depending on the value of the :attr:`~MaskedArray.baseclass` +attribute):: + + >>> x.compressed() + array([1, 4]) + +Note that the output of :meth:`compressed` is always 1D. + + + +Modifying the mask +------------------ + +Masking an entry +~~~~~~~~~~~~~~~~ + +The recommended way to mark one or several specific entries of a masked array +as invalid is to assign the special value :attr:`masked` to them:: + + >>> x = ma.array([1, 2, 3]) + >>> x[0] = ma.masked + >>> x + masked_array(data = [-- 2 3], + mask = [ True False False], + fill_value = 999999) + >>> y = ma.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + >>> y[(0, 1, 2), (1, 2, 0)] = ma.masked + >>> y + masked_array(data = + [[1 -- 3] + [4 5 --] + [-- 8 9]], + mask = + [[False True False] + [False False True] + [ True False False]], + fill_value = 999999) + >>> z = ma.array([1, 2, 3, 4]) + >>> z[:-2] = ma.masked + >>> z + masked_array(data = [-- -- 3 4], + mask = [ True True False False], + fill_value = 999999) + + +A second possibility is to modify the :attr:`~MaskedArray.mask` directly, +but this usage is discouraged. + +.. note:: + When creating a new masked array with a simple, non-structured datatype, + the mask is initially set to the special value :attr:`nomask`, that + corresponds roughly to the boolean ``False``. Trying to set an element of + :attr:`nomask` will fail with a :exc:`TypeError` exception, as a boolean + does not support item assignment. + + +All the entries of an array can be masked at once by assigning ``True`` to the +mask:: + + >>> x = ma.array([1, 2, 3], mask=[0, 0, 1]) + >>> x.mask = True + >>> x + masked_array(data = [-- -- --], + mask = [ True True True], + fill_value = 999999) + +Finally, specific entries can be masked and/or unmasked by assigning to the +mask a sequence of booleans:: + + >>> x = ma.array([1, 2, 3]) + >>> x.mask = [0, 1, 0] + >>> x + masked_array(data = [1 -- 3], + mask = [False True False], + fill_value = 999999) + +Unmasking an entry +~~~~~~~~~~~~~~~~~~ + +To unmask one or several specific entries, we can just assign one or several +new valid values to them:: + + >>> x = ma.array([1, 2, 3], mask=[0, 0, 1]) + >>> x + masked_array(data = [1 2 --], + mask = [False False True], + fill_value = 999999) + >>> x[-1] = 5 + >>> x + masked_array(data = [1 2 5], + mask = [False False False], + fill_value = 999999) + +.. note:: + Unmasking an entry by direct assignment will silently fail if the masked + array has a *hard* mask, as shown by the :attr:`hardmask` attribute. This + feature was introduced to prevent overwriting the mask. To force the + unmasking of an entry where the array has a hard mask, the mask must first + to be softened using the :meth:`soften_mask` method before the allocation. + It can be re-hardened with :meth:`harden_mask`:: + + >>> x = ma.array([1, 2, 3], mask=[0, 0, 1], hard_mask=True) + >>> x + masked_array(data = [1 2 --], + mask = [False False True], + fill_value = 999999) + >>> x[-1] = 5 + >>> x + masked_array(data = [1 2 --], + mask = [False False True], + fill_value = 999999) + >>> x.soften_mask() + >>> x[-1] = 5 + >>> x + masked_array(data = [1 2 5], + mask = [False False False], + fill_value = 999999) + >>> x.harden_mask() + + +To unmask all masked entries of a masked array (provided the mask isn't a hard +mask), the simplest solution is to assign the constant :attr:`nomask` to the +mask:: + + >>> x = ma.array([1, 2, 3], mask=[0, 0, 1]) + >>> x + masked_array(data = [1 2 --], + mask = [False False True], + fill_value = 999999) + >>> x.mask = ma.nomask + >>> x + masked_array(data = [1 2 3], + mask = [False False False], + fill_value = 999999) + + + +Indexing and slicing +-------------------- + +As a :class:`MaskedArray` is a subclass of :class:`numpy.ndarray`, it inherits +its mechanisms for indexing and slicing. + +When accessing a single entry of a masked array with no named fields, the +output is either a scalar (if the corresponding entry of the mask is +``False``) or the special value :attr:`masked` (if the corresponding entry of +the mask is ``True``):: + + >>> x = ma.array([1, 2, 3], mask=[0, 0, 1]) + >>> x[0] + 1 + >>> x[-1] + masked_array(data = --, + mask = True, + fill_value = 1e+20) + >>> x[-1] is ma.masked + True + +If the masked array has named fields, accessing a single entry returns a +:class:`numpy.void` object if none of the fields are masked, or a 0d masked +array with the same dtype as the initial array if at least one of the fields +is masked. + + >>> y = ma.masked_array([(1,2), (3, 4)], + ... mask=[(0, 0), (0, 1)], + ... dtype=[('a', int), ('b', int)]) + >>> y[0] + (1, 2) + >>> y[-1] + masked_array(data = (3, --), + mask = (False, True), + fill_value = (999999, 999999), + dtype = [('a', '>> x = ma.array([1, 2, 3, 4, 5], mask=[0, 1, 0, 0, 1]) + >>> mx = x[:3] + >>> mx + masked_array(data = [1 -- 3], + mask = [False True False], + fill_value = 999999) + >>> mx[1] = -1 + >>> mx + masked_array(data = [1 -1 3], + mask = [False False False], + fill_value = 999999) + >>> x.mask + array([False, True, False, False, True]) + >>> x.data + array([ 1, -1, 3, 4, 5]) + + +Accessing a field of a masked array with structured datatype returns a +:class:`MaskedArray`. + +Operations on masked arrays +--------------------------- + +Arithmetic and comparison operations are supported by masked arrays. +As much as possible, invalid entries of a masked array are not processed, +meaning that the corresponding :attr:`data` entries *should* be the same +before and after the operation. + +.. warning:: + We need to stress that this behavior may not be systematic, that masked + data may be affected by the operation in some cases and therefore users + should not rely on this data remaining unchanged. + +The :mod:`numpy.ma` module comes with a specific implementation of most +ufuncs. Unary and binary functions that have a validity domain (such as +:func:`~numpy.log` or :func:`~numpy.divide`) return the :data:`masked` +constant whenever the input is masked or falls outside the validity domain:: + + >>> ma.log([-1, 0, 1, 2]) + masked_array(data = [-- -- 0.0 0.69314718056], + mask = [ True True False False], + fill_value = 1e+20) + +Masked arrays also support standard numpy ufuncs. The output is then a masked +array. The result of a unary ufunc is masked wherever the input is masked. The +result of a binary ufunc is masked wherever any of the input is masked. If the +ufunc also returns the optional context output (a 3-element tuple containing +the name of the ufunc, its arguments and its domain), the context is processed +and entries of the output masked array are masked wherever the corresponding +input fall outside the validity domain:: + + >>> x = ma.array([-1, 1, 0, 2, 3], mask=[0, 0, 0, 0, 1]) + >>> np.log(x) + masked_array(data = [-- -- 0.0 0.69314718056 --], + mask = [ True True False False True], + fill_value = 1e+20) + + + +Examples +======== + +Data with a given value representing missing data +------------------------------------------------- + +Let's consider a list of elements, ``x``, where values of -9999. represent +missing data. We wish to compute the average value of the data and the vector +of anomalies (deviations from the average):: + + >>> import numpy.ma as ma + >>> x = [0.,1.,-9999.,3.,4.] + >>> mx = ma.masked_values (x, -9999.) + >>> print mx.mean() + 2.0 + >>> print mx - mx.mean() + [-2.0 -1.0 -- 1.0 2.0] + >>> print mx.anom() + [-2.0 -1.0 -- 1.0 2.0] + + +Filling in the missing data +--------------------------- + +Suppose now that we wish to print that same data, but with the missing values +replaced by the average value. + + >>> print mx.filled(mx.mean()) + [ 0. 1. 2. 3. 4.] + + +Numerical operations +-------------------- + +Numerical operations can be easily performed without worrying about missing +values, dividing by zero, square roots of negative numbers, etc.:: + + >>> import numpy as np, numpy.ma as ma + >>> x = ma.array([1., -1., 3., 4., 5., 6.], mask=[0,0,0,0,1,0]) + >>> y = ma.array([1., 2., 0., 4., 5., 6.], mask=[0,0,0,0,0,1]) + >>> print np.sqrt(x/y) + [1.0 -- -- 1.0 -- --] + +Four values of the output are invalid: the first one comes from taking the +square root of a negative number, the second from the division by zero, and +the last two where the inputs were masked. + + +Ignoring extreme values +----------------------- + +Let's consider an array ``d`` of random floats between 0 and 1. We wish to +compute the average of the values of ``d`` while ignoring any data outside +the range ``[0.1, 0.9]``:: + + >>> print ma.masked_outside(d, 0.1, 0.9).mean() diff --git a/doc/source/reference/maskedarray.rst b/doc/source/reference/maskedarray.rst new file mode 100644 index 0000000..c2deb3b --- /dev/null +++ b/doc/source/reference/maskedarray.rst @@ -0,0 +1,19 @@ +.. _maskedarray: + +************* +Masked arrays +************* + +Masked arrays are arrays that may have missing or invalid entries. +The :mod:`numpy.ma` module provides a nearly work-alike replacement for numpy +that supports data arrays with masks. + +.. index:: + single: masked arrays + +.. toctree:: + :maxdepth: 2 + + maskedarray.generic + maskedarray.baseclass + routines.ma diff --git a/doc/source/reference/routines.array-creation.rst b/doc/source/reference/routines.array-creation.rst new file mode 100644 index 0000000..e718f00 --- /dev/null +++ b/doc/source/reference/routines.array-creation.rst @@ -0,0 +1,106 @@ +.. _routines.array-creation: + +Array creation routines +======================= + +.. seealso:: :ref:`Array creation ` + +.. currentmodule:: numpy + +Ones and zeros +-------------- +.. autosummary:: + :toctree: generated/ + + empty + empty_like + eye + identity + ones + ones_like + zeros + zeros_like + full + full_like + +From existing data +------------------ +.. autosummary:: + :toctree: generated/ + + array + asarray + asanyarray + ascontiguousarray + asmatrix + copy + frombuffer + fromfile + fromfunction + fromiter + fromstring + loadtxt + +.. _routines.array-creation.rec: + +Creating record arrays (:mod:`numpy.rec`) +----------------------------------------- + +.. note:: :mod:`numpy.rec` is the preferred alias for + :mod:`numpy.core.records`. + +.. autosummary:: + :toctree: generated/ + + core.records.array + core.records.fromarrays + core.records.fromrecords + core.records.fromstring + core.records.fromfile + +.. _routines.array-creation.char: + +Creating character arrays (:mod:`numpy.char`) +--------------------------------------------- + +.. note:: :mod:`numpy.char` is the preferred alias for + :mod:`numpy.core.defchararray`. + +.. autosummary:: + :toctree: generated/ + + core.defchararray.array + core.defchararray.asarray + +Numerical ranges +---------------- +.. autosummary:: + :toctree: generated/ + + arange + linspace + logspace + geomspace + meshgrid + mgrid + ogrid + +Building matrices +----------------- +.. autosummary:: + :toctree: generated/ + + diag + diagflat + tri + tril + triu + vander + +The Matrix class +---------------- +.. autosummary:: + :toctree: generated/ + + mat + bmat diff --git a/doc/source/reference/routines.array-manipulation.rst b/doc/source/reference/routines.array-manipulation.rst new file mode 100644 index 0000000..cc93d10 --- /dev/null +++ b/doc/source/reference/routines.array-manipulation.rst @@ -0,0 +1,118 @@ +Array manipulation routines +*************************** + +.. currentmodule:: numpy + +Basic operations +================ +.. autosummary:: + :toctree: generated/ + + copyto + +Changing array shape +==================== +.. autosummary:: + :toctree: generated/ + + + reshape + ravel + ndarray.flat + ndarray.flatten + +Transpose-like operations +========================= +.. autosummary:: + :toctree: generated/ + + moveaxis + rollaxis + swapaxes + ndarray.T + transpose + +Changing number of dimensions +============================= +.. autosummary:: + :toctree: generated/ + + atleast_1d + atleast_2d + atleast_3d + broadcast + broadcast_to + broadcast_arrays + expand_dims + squeeze + +Changing kind of array +====================== +.. autosummary:: + :toctree: generated/ + + asarray + asanyarray + asmatrix + asfarray + asfortranarray + ascontiguousarray + asarray_chkfinite + asscalar + require + +Joining arrays +============== +.. autosummary:: + :toctree: generated/ + + concatenate + stack + column_stack + dstack + hstack + vstack + block + +Splitting arrays +================ +.. autosummary:: + :toctree: generated/ + + split + array_split + dsplit + hsplit + vsplit + +Tiling arrays +============= +.. autosummary:: + :toctree: generated/ + + tile + repeat + +Adding and removing elements +============================ +.. autosummary:: + :toctree: generated/ + + delete + insert + append + resize + trim_zeros + unique + +Rearranging elements +==================== +.. autosummary:: + :toctree: generated/ + + flip + fliplr + flipud + reshape + roll + rot90 diff --git a/doc/source/reference/routines.bitwise.rst b/doc/source/reference/routines.bitwise.rst new file mode 100644 index 0000000..58661ab --- /dev/null +++ b/doc/source/reference/routines.bitwise.rst @@ -0,0 +1,31 @@ +Binary operations +***************** + +.. currentmodule:: numpy + +Elementwise bit operations +-------------------------- +.. autosummary:: + :toctree: generated/ + + bitwise_and + bitwise_or + bitwise_xor + invert + left_shift + right_shift + +Bit packing +----------- +.. autosummary:: + :toctree: generated/ + + packbits + unpackbits + +Output formatting +----------------- +.. autosummary:: + :toctree: generated/ + + binary_repr diff --git a/doc/source/reference/routines.char.rst b/doc/source/reference/routines.char.rst new file mode 100644 index 0000000..7413e36 --- /dev/null +++ b/doc/source/reference/routines.char.rst @@ -0,0 +1,86 @@ +String operations +***************** + +.. currentmodule:: numpy.core.defchararray + +This module provides a set of vectorized string operations for arrays +of type `numpy.string_` or `numpy.unicode_`. All of them are based on +the string methods in the Python standard library. + +String operations +----------------- + +.. autosummary:: + :toctree: generated/ + + add + multiply + mod + capitalize + center + decode + encode + join + ljust + lower + lstrip + partition + replace + rjust + rpartition + rsplit + rstrip + split + splitlines + strip + swapcase + title + translate + upper + zfill + +Comparison +---------- + +Unlike the standard numpy comparison operators, the ones in the `char` +module strip trailing whitespace characters before performing the +comparison. + +.. autosummary:: + :toctree: generated/ + + equal + not_equal + greater_equal + less_equal + greater + less + +String information +------------------ + +.. autosummary:: + :toctree: generated/ + + count + find + index + isalpha + isdecimal + isdigit + islower + isnumeric + isspace + istitle + isupper + rfind + rindex + startswith + +Convenience class +----------------- + +.. autosummary:: + :toctree: generated/ + + chararray diff --git a/doc/source/reference/routines.ctypeslib.rst b/doc/source/reference/routines.ctypeslib.rst new file mode 100644 index 0000000..b04713b --- /dev/null +++ b/doc/source/reference/routines.ctypeslib.rst @@ -0,0 +1,11 @@ +*********************************************************** +C-Types Foreign Function Interface (:mod:`numpy.ctypeslib`) +*********************************************************** + +.. currentmodule:: numpy.ctypeslib + +.. autofunction:: as_array +.. autofunction:: as_ctypes +.. autofunction:: ctypes_load_library +.. autofunction:: load_library +.. autofunction:: ndpointer diff --git a/doc/source/reference/routines.datetime.rst b/doc/source/reference/routines.datetime.rst new file mode 100644 index 0000000..966ed5a --- /dev/null +++ b/doc/source/reference/routines.datetime.rst @@ -0,0 +1,26 @@ +.. _routines.datetime: + +Datetime Support Functions +************************** + +.. currentmodule:: numpy + +.. autosummary:: + :toctree: generated/ + + datetime_as_string + datetime_data + + +Business Day Functions +====================== + +.. currentmodule:: numpy + +.. autosummary:: + :toctree: generated/ + + busdaycalendar + is_busday + busday_offset + busday_count diff --git a/doc/source/reference/routines.dtype.rst b/doc/source/reference/routines.dtype.rst new file mode 100644 index 0000000..ec8d298 --- /dev/null +++ b/doc/source/reference/routines.dtype.rst @@ -0,0 +1,55 @@ +.. _routines.dtype: + +Data type routines +================== + +.. currentmodule:: numpy + +.. autosummary:: + :toctree: generated/ + + can_cast + promote_types + min_scalar_type + result_type + common_type + obj2sctype + +Creating data types +------------------- + +.. autosummary:: + :toctree: generated/ + + + dtype + format_parser + +Data type information +--------------------- +.. autosummary:: + :toctree: generated/ + + finfo + iinfo + MachAr + +Data type testing +----------------- +.. autosummary:: + :toctree: generated/ + + issctype + issubdtype + issubsctype + issubclass_ + find_common_type + +Miscellaneous +------------- +.. autosummary:: + :toctree: generated/ + + typename + sctype2char + mintypecode diff --git a/doc/source/reference/routines.dual.rst b/doc/source/reference/routines.dual.rst new file mode 100644 index 0000000..4ed7098 --- /dev/null +++ b/doc/source/reference/routines.dual.rst @@ -0,0 +1,47 @@ +Optionally Scipy-accelerated routines (:mod:`numpy.dual`) +********************************************************* + +.. automodule:: numpy.dual + +Linear algebra +-------------- + +.. currentmodule:: numpy.linalg + +.. autosummary:: + + cholesky + det + eig + eigh + eigvals + eigvalsh + inv + lstsq + norm + pinv + solve + svd + +FFT +--- + +.. currentmodule:: numpy.fft + +.. autosummary:: + + fft + fft2 + fftn + ifft + ifft2 + ifftn + +Other +----- + +.. currentmodule:: numpy + +.. autosummary:: + + i0 diff --git a/doc/source/reference/routines.emath.rst b/doc/source/reference/routines.emath.rst new file mode 100644 index 0000000..c0c5b61 --- /dev/null +++ b/doc/source/reference/routines.emath.rst @@ -0,0 +1,9 @@ +Mathematical functions with automatic domain (:mod:`numpy.emath`) +*********************************************************************** + +.. currentmodule:: numpy + +.. note:: :mod:`numpy.emath` is a preferred alias for :mod:`numpy.lib.scimath`, + available after :mod:`numpy` is imported. + +.. automodule:: numpy.lib.scimath diff --git a/doc/source/reference/routines.err.rst b/doc/source/reference/routines.err.rst new file mode 100644 index 0000000..b3a7164 --- /dev/null +++ b/doc/source/reference/routines.err.rst @@ -0,0 +1,25 @@ +Floating point error handling +***************************** + +.. currentmodule:: numpy + +Setting and getting error handling +---------------------------------- + +.. autosummary:: + :toctree: generated/ + + seterr + geterr + seterrcall + geterrcall + errstate + +Internal functions +------------------ + +.. autosummary:: + :toctree: generated/ + + seterrobj + geterrobj diff --git a/doc/source/reference/routines.fft.rst b/doc/source/reference/routines.fft.rst new file mode 100644 index 0000000..6c47925 --- /dev/null +++ b/doc/source/reference/routines.fft.rst @@ -0,0 +1,2 @@ +.. _routines.fft: +.. automodule:: numpy.fft diff --git a/doc/source/reference/routines.financial.rst b/doc/source/reference/routines.financial.rst new file mode 100644 index 0000000..5f426d7 --- /dev/null +++ b/doc/source/reference/routines.financial.rst @@ -0,0 +1,21 @@ +Financial functions +******************* + +.. currentmodule:: numpy + +Simple financial functions +-------------------------- + +.. autosummary:: + :toctree: generated/ + + fv + pv + npv + pmt + ppmt + ipmt + irr + mirr + nper + rate diff --git a/doc/source/reference/routines.functional.rst b/doc/source/reference/routines.functional.rst new file mode 100644 index 0000000..e4aabab --- /dev/null +++ b/doc/source/reference/routines.functional.rst @@ -0,0 +1,13 @@ +Functional programming +********************** + +.. currentmodule:: numpy + +.. autosummary:: + :toctree: generated/ + + apply_along_axis + apply_over_axes + vectorize + frompyfunc + piecewise diff --git a/doc/source/reference/routines.help.rst b/doc/source/reference/routines.help.rst new file mode 100644 index 0000000..9b6eb4a --- /dev/null +++ b/doc/source/reference/routines.help.rst @@ -0,0 +1,24 @@ +.. _routines.help: + +NumPy-specific help functions +============================= + +.. currentmodule:: numpy + +Finding help +------------ + +.. autosummary:: + :toctree: generated/ + + lookfor + + +Reading help +------------ + +.. autosummary:: + :toctree: generated/ + + info + source diff --git a/doc/source/reference/routines.indexing.rst b/doc/source/reference/routines.indexing.rst new file mode 100644 index 0000000..4af6845 --- /dev/null +++ b/doc/source/reference/routines.indexing.rst @@ -0,0 +1,65 @@ +.. _routines.indexing: + +Indexing routines +================= + +.. seealso:: :ref:`Indexing ` + +.. currentmodule:: numpy + +Generating index arrays +----------------------- +.. autosummary:: + :toctree: generated/ + + c_ + r_ + s_ + nonzero + where + indices + ix_ + ogrid + ravel_multi_index + unravel_index + diag_indices + diag_indices_from + mask_indices + tril_indices + tril_indices_from + triu_indices + triu_indices_from + +Indexing-like operations +------------------------ +.. autosummary:: + :toctree: generated/ + + take + choose + compress + diag + diagonal + select + lib.stride_tricks.as_strided + +Inserting data into arrays +-------------------------- +.. autosummary:: + :toctree: generated/ + + place + put + putmask + fill_diagonal + +Iterating over arrays +--------------------- +.. autosummary:: + :toctree: generated/ + + nditer + ndenumerate + ndindex + flatiter + lib.Arrayterator diff --git a/doc/source/reference/routines.io.rst b/doc/source/reference/routines.io.rst new file mode 100644 index 0000000..5df590f --- /dev/null +++ b/doc/source/reference/routines.io.rst @@ -0,0 +1,80 @@ +Input and output +**************** + +.. currentmodule:: numpy + +NumPy binary files (NPY, NPZ) +----------------------------- +.. autosummary:: + :toctree: generated/ + + load + save + savez + savez_compressed + +The format of these binary file types is documented in +http://docs.scipy.org/doc/numpy/neps/npy-format.html + +Text files +---------- +.. autosummary:: + :toctree: generated/ + + loadtxt + savetxt + genfromtxt + fromregex + fromstring + ndarray.tofile + ndarray.tolist + +Raw binary files +---------------- + +.. autosummary:: + + fromfile + ndarray.tofile + +String formatting +----------------- +.. autosummary:: + :toctree: generated/ + + array2string + array_repr + array_str + format_float_positional + format_float_scientific + +Memory mapping files +-------------------- +.. autosummary:: + :toctree: generated/ + + memmap + +Text formatting options +----------------------- +.. autosummary:: + :toctree: generated/ + + set_printoptions + get_printoptions + set_string_function + +Base-n representations +---------------------- +.. autosummary:: + :toctree: generated/ + + binary_repr + base_repr + +Data sources +------------ +.. autosummary:: + :toctree: generated/ + + DataSource diff --git a/doc/source/reference/routines.linalg.rst b/doc/source/reference/routines.linalg.rst new file mode 100644 index 0000000..0520df4 --- /dev/null +++ b/doc/source/reference/routines.linalg.rst @@ -0,0 +1,95 @@ +.. _routines.linalg: + +Linear algebra (:mod:`numpy.linalg`) +************************************ + +.. currentmodule:: numpy + +Matrix and vector products +-------------------------- +.. autosummary:: + :toctree: generated/ + + dot + linalg.multi_dot + vdot + inner + outer + matmul + tensordot + einsum + einsum_path + linalg.matrix_power + kron + +Decompositions +-------------- +.. autosummary:: + :toctree: generated/ + + linalg.cholesky + linalg.qr + linalg.svd + +Matrix eigenvalues +------------------ +.. autosummary:: + :toctree: generated/ + + linalg.eig + linalg.eigh + linalg.eigvals + linalg.eigvalsh + +Norms and other numbers +----------------------- +.. autosummary:: + :toctree: generated/ + + linalg.norm + linalg.cond + linalg.det + linalg.matrix_rank + linalg.slogdet + trace + +Solving equations and inverting matrices +---------------------------------------- +.. autosummary:: + :toctree: generated/ + + linalg.solve + linalg.tensorsolve + linalg.lstsq + linalg.inv + linalg.pinv + linalg.tensorinv + +Exceptions +---------- +.. autosummary:: + :toctree: generated/ + + linalg.LinAlgError + +.. _routines.linalg-broadcasting: + +Linear algebra on several matrices at once +------------------------------------------ + +.. versionadded:: 1.8.0 + +Several of the linear algebra routines listed above are able to +compute results for several matrices at once, if they are stacked into +the same array. + +This is indicated in the documentation via input parameter +specifications such as ``a : (..., M, M) array_like``. This means that +if for instance given an input array ``a.shape == (N, M, M)``, it is +interpreted as a "stack" of N matrices, each of size M-by-M. Similar +specification applies to return values, for instance the determinant +has ``det : (...)`` and will in this case return an array of shape +``det(a).shape == (N,)``. This generalizes to linear algebra +operations on higher-dimensional arrays: the last 1 or 2 dimensions of +a multidimensional array are interpreted as vectors or matrices, as +appropriate for each operation. diff --git a/doc/source/reference/routines.logic.rst b/doc/source/reference/routines.logic.rst new file mode 100644 index 0000000..7fa0cd1 --- /dev/null +++ b/doc/source/reference/routines.logic.rst @@ -0,0 +1,66 @@ +Logic functions +*************** + +.. currentmodule:: numpy + +Truth value testing +------------------- +.. autosummary:: + :toctree: generated/ + + all + any + +Array contents +-------------- +.. autosummary:: + :toctree: generated/ + + isfinite + isinf + isnan + isnat + isneginf + isposinf + +Array type testing +------------------ +.. autosummary:: + :toctree: generated/ + + iscomplex + iscomplexobj + isfortran + isreal + isrealobj + isscalar + +Logical operations +------------------ +.. autosummary:: + :toctree: generated/ + + logical_and + logical_or + logical_not + logical_xor + +Comparison +---------- +.. autosummary:: + :toctree: generated/ + + allclose + isclose + array_equal + array_equiv + +.. autosummary:: + :toctree: generated/ + + greater + greater_equal + less + less_equal + equal + not_equal diff --git a/doc/source/reference/routines.ma.rst b/doc/source/reference/routines.ma.rst new file mode 100644 index 0000000..2408899 --- /dev/null +++ b/doc/source/reference/routines.ma.rst @@ -0,0 +1,407 @@ +.. _routines.ma: + +Masked array operations +*********************** + +.. currentmodule:: numpy + + +Constants +========= + +.. autosummary:: + :toctree: generated/ + + ma.MaskType + + +Creation +======== + +From existing data +~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + ma.masked_array + ma.array + ma.copy + ma.frombuffer + ma.fromfunction + + ma.MaskedArray.copy + + +Ones and zeros +~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + ma.empty + ma.empty_like + ma.masked_all + ma.masked_all_like + ma.ones + ma.zeros + + +_____ + +Inspecting the array +==================== + +.. autosummary:: + :toctree: generated/ + + ma.all + ma.any + ma.count + ma.count_masked + ma.getmask + ma.getmaskarray + ma.getdata + ma.nonzero + ma.shape + ma.size + ma.is_masked + ma.is_mask + + ma.MaskedArray.data + ma.MaskedArray.mask + ma.MaskedArray.recordmask + + ma.MaskedArray.all + ma.MaskedArray.any + ma.MaskedArray.count + ma.MaskedArray.nonzero + ma.shape + ma.size + + +_____ + +Manipulating a MaskedArray +========================== + +Changing the shape +~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + ma.ravel + ma.reshape + ma.resize + + ma.MaskedArray.flatten + ma.MaskedArray.ravel + ma.MaskedArray.reshape + ma.MaskedArray.resize + + +Modifying axes +~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.swapaxes + ma.transpose + + ma.MaskedArray.swapaxes + ma.MaskedArray.transpose + + +Changing the number of dimensions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.atleast_1d + ma.atleast_2d + ma.atleast_3d + ma.expand_dims + ma.squeeze + + ma.MaskedArray.squeeze + + ma.column_stack + ma.concatenate + ma.dstack + ma.hstack + ma.hsplit + ma.mr_ + ma.row_stack + ma.vstack + + +Joining arrays +~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.column_stack + ma.concatenate + ma.append + ma.dstack + ma.hstack + ma.vstack + + +_____ + +Operations on masks +=================== + +Creating a mask +~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.make_mask + ma.make_mask_none + ma.mask_or + ma.make_mask_descr + + +Accessing a mask +~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.getmask + ma.getmaskarray + ma.masked_array.mask + + +Finding masked data +~~~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.flatnotmasked_contiguous + ma.flatnotmasked_edges + ma.notmasked_contiguous + ma.notmasked_edges + ma.clump_masked + ma.clump_unmasked + + +Modifying a mask +~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.mask_cols + ma.mask_or + ma.mask_rowcols + ma.mask_rows + ma.harden_mask + ma.soften_mask + + ma.MaskedArray.harden_mask + ma.MaskedArray.soften_mask + ma.MaskedArray.shrink_mask + ma.MaskedArray.unshare_mask + + +_____ + +Conversion operations +====================== + +> to a masked array +~~~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.asarray + ma.asanyarray + ma.fix_invalid + ma.masked_equal + ma.masked_greater + ma.masked_greater_equal + ma.masked_inside + ma.masked_invalid + ma.masked_less + ma.masked_less_equal + ma.masked_not_equal + ma.masked_object + ma.masked_outside + ma.masked_values + ma.masked_where + + +> to a ndarray +~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.compress_cols + ma.compress_rowcols + ma.compress_rows + ma.compressed + ma.filled + + ma.MaskedArray.compressed + ma.MaskedArray.filled + + +> to another object +~~~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.MaskedArray.tofile + ma.MaskedArray.tolist + ma.MaskedArray.torecords + ma.MaskedArray.tobytes + + +Pickling and unpickling +~~~~~~~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.dump + ma.dumps + ma.load + ma.loads + + +Filling a masked array +~~~~~~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.common_fill_value + ma.default_fill_value + ma.maximum_fill_value + ma.maximum_fill_value + ma.set_fill_value + + ma.MaskedArray.get_fill_value + ma.MaskedArray.set_fill_value + ma.MaskedArray.fill_value + + +_____ + +Masked arrays arithmetics +========================= + +Arithmetics +~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.anom + ma.anomalies + ma.average + ma.conjugate + ma.corrcoef + ma.cov + ma.cumsum + ma.cumprod + ma.mean + ma.median + ma.power + ma.prod + ma.std + ma.sum + ma.var + + ma.MaskedArray.anom + ma.MaskedArray.cumprod + ma.MaskedArray.cumsum + ma.MaskedArray.mean + ma.MaskedArray.prod + ma.MaskedArray.std + ma.MaskedArray.sum + ma.MaskedArray.var + + +Minimum/maximum +~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.argmax + ma.argmin + ma.max + ma.min + ma.ptp + + ma.MaskedArray.argmax + ma.MaskedArray.argmin + ma.MaskedArray.max + ma.MaskedArray.min + ma.MaskedArray.ptp + + +Sorting +~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.argsort + ma.sort + ma.MaskedArray.argsort + ma.MaskedArray.sort + + +Algebra +~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.diag + ma.dot + ma.identity + ma.inner + ma.innerproduct + ma.outer + ma.outerproduct + ma.trace + ma.transpose + + ma.MaskedArray.trace + ma.MaskedArray.transpose + + +Polynomial fit +~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.vander + ma.polyfit + + +Clipping and rounding +~~~~~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.around + ma.clip + ma.round + + ma.MaskedArray.clip + ma.MaskedArray.round + + +Miscellanea +~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + ma.allequal + ma.allclose + ma.apply_along_axis + ma.arange + ma.choose + ma.ediff1d + ma.indices + ma.where diff --git a/doc/source/reference/routines.math.rst b/doc/source/reference/routines.math.rst new file mode 100644 index 0000000..4c2f280 --- /dev/null +++ b/doc/source/reference/routines.math.rst @@ -0,0 +1,162 @@ +Mathematical functions +********************** + +.. currentmodule:: numpy + +Trigonometric functions +----------------------- +.. autosummary:: + :toctree: generated/ + + sin + cos + tan + arcsin + arccos + arctan + hypot + arctan2 + degrees + radians + unwrap + deg2rad + rad2deg + +Hyperbolic functions +-------------------- +.. autosummary:: + :toctree: generated/ + + sinh + cosh + tanh + arcsinh + arccosh + arctanh + +Rounding +-------- +.. autosummary:: + :toctree: generated/ + + around + round_ + rint + fix + floor + ceil + trunc + +Sums, products, differences +--------------------------- +.. autosummary:: + :toctree: generated/ + + prod + sum + nanprod + nansum + cumprod + cumsum + nancumprod + nancumsum + diff + ediff1d + gradient + cross + trapz + +Exponents and logarithms +------------------------ +.. autosummary:: + :toctree: generated/ + + exp + expm1 + exp2 + log + log10 + log2 + log1p + logaddexp + logaddexp2 + +Other special functions +----------------------- +.. autosummary:: + :toctree: generated/ + + i0 + sinc + +Floating point routines +----------------------- +.. autosummary:: + :toctree: generated/ + + signbit + copysign + frexp + ldexp + nextafter + spacing + +Arithmetic operations +--------------------- +.. autosummary:: + :toctree: generated/ + + add + reciprocal + positive + negative + multiply + divide + power + subtract + true_divide + floor_divide + float_power + + fmod + mod + modf + remainder + divmod + +Handling complex numbers +------------------------ +.. autosummary:: + :toctree: generated/ + + angle + real + imag + conj + + +Miscellaneous +------------- +.. autosummary:: + :toctree: generated/ + + convolve + clip + + sqrt + cbrt + square + + absolute + fabs + sign + heaviside + maximum + minimum + fmax + fmin + + nan_to_num + real_if_close + + interp diff --git a/doc/source/reference/routines.matlib.rst b/doc/source/reference/routines.matlib.rst new file mode 100644 index 0000000..a35eaec --- /dev/null +++ b/doc/source/reference/routines.matlib.rst @@ -0,0 +1,36 @@ +Matrix library (:mod:`numpy.matlib`) +************************************ + +.. currentmodule:: numpy + +This module contains all functions in the :mod:`numpy` namespace, with +the following replacement functions that return :class:`matrices +` instead of :class:`ndarrays `. + +.. currentmodule:: numpy + +Functions that are also in the numpy namespace and return matrices + +.. autosummary:: + + mat + matrix + asmatrix + bmat + + +Replacement functions in `matlib` + +.. currentmodule:: numpy.matlib + +.. autosummary:: + :toctree: generated/ + + empty + zeros + ones + eye + identity + repmat + rand + randn diff --git a/doc/source/reference/routines.numarray.rst b/doc/source/reference/routines.numarray.rst new file mode 100644 index 0000000..9e84f49 --- /dev/null +++ b/doc/source/reference/routines.numarray.rst @@ -0,0 +1,5 @@ +********************** +Numarray compatibility +********************** + +The numarray module was removed in NumPy 1.9.0. diff --git a/doc/source/reference/routines.oldnumeric.rst b/doc/source/reference/routines.oldnumeric.rst new file mode 100644 index 0000000..2120fc6 --- /dev/null +++ b/doc/source/reference/routines.oldnumeric.rst @@ -0,0 +1,7 @@ +************************* +Old Numeric compatibility +************************* + +.. currentmodule:: numpy + +The oldnumeric module was removed in NumPy 1.9.0. diff --git a/doc/source/reference/routines.other.rst b/doc/source/reference/routines.other.rst new file mode 100644 index 0000000..45b9ac3 --- /dev/null +++ b/doc/source/reference/routines.other.rst @@ -0,0 +1,45 @@ +Miscellaneous routines +********************** + +.. toctree:: + +.. currentmodule:: numpy + +Buffer objects +-------------- +.. autosummary:: + :toctree: generated/ + + getbuffer + newbuffer + +Performance tuning +------------------ +.. autosummary:: + :toctree: generated/ + + setbufsize + getbufsize + +Memory ranges +------------- + +.. autosummary:: + :toctree: generated/ + + shares_memory + may_share_memory + +Array mixins +------------ +.. autosummary:: + :toctree: generated/ + + lib.mixins.NDArrayOperatorsMixin + +NumPy version comparison +------------------------ +.. autosummary:: + :toctree: generated/ + + lib.NumpyVersion diff --git a/doc/source/reference/routines.padding.rst b/doc/source/reference/routines.padding.rst new file mode 100644 index 0000000..38706ed --- /dev/null +++ b/doc/source/reference/routines.padding.rst @@ -0,0 +1,9 @@ +Padding Arrays +============== + +.. currentmodule:: numpy + +.. autosummary:: + :toctree: generated/ + + pad diff --git a/doc/source/reference/routines.polynomials.chebyshev.rst b/doc/source/reference/routines.polynomials.chebyshev.rst new file mode 100644 index 0000000..60c816f --- /dev/null +++ b/doc/source/reference/routines.polynomials.chebyshev.rst @@ -0,0 +1,92 @@ +Chebyshev Module (:mod:`numpy.polynomial.chebyshev`) +==================================================== + +.. versionadded:: 1.4.0 + +.. currentmodule:: numpy.polynomial.chebyshev + +This module provides a number of objects (mostly functions) useful for +dealing with Chebyshev series, including a `Chebyshev` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Chebyshev Class +--------------- + +.. autosummary:: + :toctree: generated/ + + Chebyshev + +Basics +------ + +.. autosummary:: + :toctree: generated/ + + chebval + chebval2d + chebval3d + chebgrid2d + chebgrid3d + chebroots + chebfromroots + +Fitting +------- + +.. autosummary:: + :toctree: generated/ + + chebfit + chebvander + chebvander2d + chebvander3d + +Calculus +-------- + +.. autosummary:: + :toctree: generated/ + + chebder + chebint + +Algebra +------- + +.. autosummary:: + :toctree: generated/ + + chebadd + chebsub + chebmul + chebmulx + chebdiv + chebpow + +Quadrature +---------- + +.. autosummary:: + :toctree: generated/ + + chebgauss + chebweight + +Miscellaneous +------------- + +.. autosummary:: + :toctree: generated/ + + chebcompanion + chebdomain + chebzero + chebone + chebx + chebtrim + chebline + cheb2poly + poly2cheb diff --git a/doc/source/reference/routines.polynomials.classes.rst b/doc/source/reference/routines.polynomials.classes.rst new file mode 100644 index 0000000..f44ddd4 --- /dev/null +++ b/doc/source/reference/routines.polynomials.classes.rst @@ -0,0 +1,324 @@ +Using the Convenience Classes +============================= + +The convenience classes provided by the polynomial package are: + + ============ ================ + Name Provides + ============ ================ + Polynomial Power series + Chebyshev Chebyshev series + Legendre Legendre series + Laguerre Laguerre series + Hermite Hermite series + HermiteE HermiteE series + ============ ================ + +The series in this context are finite sums of the corresponding polynomial +basis functions multiplied by coefficients. For instance, a power series +looks like + +.. math:: p(x) = 1 + 2x + 3x^2 + +and has coefficients :math:`[1, 2, 3]`. The Chebyshev series with the +same coefficients looks like + + +.. math:: p(x) = 1 T_0(x) + 2 T_1(x) + 3 T_2(x) + +and more generally + +.. math:: p(x) = \sum_{i=0}^n c_i T_i(x) + +where in this case the :math:`T_n` are the Chebyshev functions of +degree :math:`n`, but could just as easily be the basis functions of +any of the other classes. The convention for all the classes is that +the coefficient :math:`c[i]` goes with the basis function of degree i. + +All of the classes have the same methods, and especially they implement the +Python numeric operators +, -, \*, //, %, divmod, \*\*, ==, +and !=. The last two can be a bit problematic due to floating point +roundoff errors. We now give a quick demonstration of the various +operations using NumPy version 1.7.0. + +Basics +------ + +First we need a polynomial class and a polynomial instance to play with. +The classes can be imported directly from the polynomial package or from +the module of the relevant type. Here we import from the package and use +the conventional Polynomial class because of its familiarity:: + + >>> from numpy.polynomial import Polynomial as P + >>> p = P([1,2,3]) + >>> p + Polynomial([ 1., 2., 3.], domain=[-1, 1], window=[-1, 1]) + +Note that there are three parts to the long version of the printout. The +first is the coefficients, the second is the domain, and the third is the +window:: + + >>> p.coef + array([ 1., 2., 3.]) + >>> p.domain + array([-1., 1.]) + >>> p.window + array([-1., 1.]) + +Printing a polynomial yields a shorter form without the domain +and window:: + + >>> print p + poly([ 1. 2. 3.]) + +We will deal with the domain and window when we get to fitting, for the moment +we ignore them and run through the basic algebraic and arithmetic operations. + +Addition and Subtraction:: + + >>> p + p + Polynomial([ 2., 4., 6.], domain=[-1, 1], window=[-1, 1]) + >>> p - p + Polynomial([ 0.], domain=[-1, 1], window=[-1, 1]) + +Multiplication:: + + >>> p * p + Polynomial([ 1., 4., 10., 12., 9.], domain=[-1, 1], window=[-1, 1]) + +Powers:: + + >>> p**2 + Polynomial([ 1., 4., 10., 12., 9.], domain=[-1, 1], window=[-1, 1]) + +Division: + +Floor division, '//', is the division operator for the polynomial classes, +polynomials are treated like integers in this regard. For Python versions < +3.x the '/' operator maps to '//', as it does for Python, for later +versions the '/' will only work for division by scalars. At some point it +will be deprecated:: + + >>> p // P([-1, 1]) + Polynomial([ 5., 3.], domain=[-1, 1], window=[-1, 1]) + +Remainder:: + + >>> p % P([-1, 1]) + Polynomial([ 6.], domain=[-1, 1], window=[-1, 1]) + +Divmod:: + + >>> quo, rem = divmod(p, P([-1, 1])) + >>> quo + Polynomial([ 5., 3.], domain=[-1, 1], window=[-1, 1]) + >>> rem + Polynomial([ 6.], domain=[-1, 1], window=[-1, 1]) + +Evaluation:: + + >>> x = np.arange(5) + >>> p(x) + array([ 1., 6., 17., 34., 57.]) + >>> x = np.arange(6).reshape(3,2) + >>> p(x) + array([[ 1., 6.], + [ 17., 34.], + [ 57., 86.]]) + +Substitution: + +Substitute a polynomial for x and expand the result. Here we substitute +p in itself leading to a new polynomial of degree 4 after expansion. If +the polynomials are regarded as functions this is composition of +functions:: + + >>> p(p) + Polynomial([ 6., 16., 36., 36., 27.], domain=[-1, 1], window=[-1, 1]) + +Roots:: + + >>> p.roots() + array([-0.33333333-0.47140452j, -0.33333333+0.47140452j]) + + + +It isn't always convenient to explicitly use Polynomial instances, so +tuples, lists, arrays, and scalars are automatically cast in the arithmetic +operations:: + + >>> p + [1, 2, 3] + Polynomial([ 2., 4., 6.], domain=[-1, 1], window=[-1, 1]) + >>> [1, 2, 3] * p + Polynomial([ 1., 4., 10., 12., 9.], domain=[-1, 1], window=[-1, 1]) + >>> p / 2 + Polynomial([ 0.5, 1. , 1.5], domain=[-1, 1], window=[-1, 1]) + +Polynomials that differ in domain, window, or class can't be mixed in +arithmetic:: + + >>> from numpy.polynomial import Chebyshev as T + >>> p + P([1], domain=[0,1]) + Traceback (most recent call last): + File "", line 1, in + File "", line 213, in __add__ + TypeError: Domains differ + >>> p + P([1], window=[0,1]) + Traceback (most recent call last): + File "", line 1, in + File "", line 215, in __add__ + TypeError: Windows differ + >>> p + T([1]) + Traceback (most recent call last): + File "", line 1, in + File "", line 211, in __add__ + TypeError: Polynomial types differ + + +But different types can be used for substitution. In fact, this is how +conversion of Polynomial classes among themselves is done for type, domain, +and window casting:: + + >>> p(T([0, 1])) + Chebyshev([ 2.5, 2. , 1.5], domain=[-1, 1], window=[-1, 1]) + +Which gives the polynomial `p` in Chebyshev form. This works because +:math:`T_1(x) = x` and substituting :math:`x` for :math:`x` doesn't change +the original polynomial. However, all the multiplications and divisions +will be done using Chebyshev series, hence the type of the result. + +Calculus +-------- + +Polynomial instances can be integrated and differentiated.:: + + >>> from numpy.polynomial import Polynomial as P + >>> p = P([2, 6]) + >>> p.integ() + Polynomial([ 0., 2., 3.], domain=[-1, 1], window=[-1, 1]) + >>> p.integ(2) + Polynomial([ 0., 0., 1., 1.], domain=[-1, 1], window=[-1, 1]) + +The first example integrates `p` once, the second example integrates it +twice. By default, the lower bound of the integration and the integration +constant are 0, but both can be specified.:: + + >>> p.integ(lbnd=-1) + Polynomial([-1., 2., 3.], domain=[-1, 1], window=[-1, 1]) + >>> p.integ(lbnd=-1, k=1) + Polynomial([ 0., 2., 3.], domain=[-1, 1], window=[-1, 1]) + +In the first case the lower bound of the integration is set to -1 and the +integration constant is 0. In the second the constant of integration is set +to 1 as well. Differentiation is simpler since the only option is the +number of times the polynomial is differentiated:: + + >>> p = P([1, 2, 3]) + >>> p.deriv(1) + Polynomial([ 2., 6.], domain=[-1, 1], window=[-1, 1]) + >>> p.deriv(2) + Polynomial([ 6.], domain=[-1, 1], window=[-1, 1]) + + +Other Polynomial Constructors +----------------------------- + +Constructing polynomials by specifying coefficients is just one way of +obtaining a polynomial instance, they may also be created by specifying +their roots, by conversion from other polynomial types, and by least +squares fits. Fitting is discussed in its own section, the other methods +are demonstrated below:: + + >>> from numpy.polynomial import Polynomial as P + >>> from numpy.polynomial import Chebyshev as T + >>> p = P.fromroots([1, 2, 3]) + >>> p + Polynomial([ -6., 11., -6., 1.], domain=[-1, 1], window=[-1, 1]) + >>> p.convert(kind=T) + Chebyshev([ -9. , 11.75, -3. , 0.25], domain=[-1, 1], window=[-1, 1]) + +The convert method can also convert domain and window:: + + >>> p.convert(kind=T, domain=[0, 1]) + Chebyshev([-2.4375 , 2.96875, -0.5625 , 0.03125], [ 0., 1.], [-1., 1.]) + >>> p.convert(kind=P, domain=[0, 1]) + Polynomial([-1.875, 2.875, -1.125, 0.125], [ 0., 1.], [-1., 1.]) + +In numpy versions >= 1.7.0 the `basis` and `cast` class methods are also +available. The cast method works like the convert method while the basis +method returns the basis polynomial of given degree:: + + >>> P.basis(3) + Polynomial([ 0., 0., 0., 1.], domain=[-1, 1], window=[-1, 1]) + >>> T.cast(p) + Chebyshev([ -9. , 11.75, -3. , 0.25], domain=[-1, 1], window=[-1, 1]) + +Conversions between types can be useful, but it is *not* recommended +for routine use. The loss of numerical precision in passing from a +Chebyshev series of degree 50 to a Polynomial series of the same degree +can make the results of numerical evaluation essentially random. + +Fitting +------- + +Fitting is the reason that the `domain` and `window` attributes are part of +the convenience classes. To illustrate the problem, the values of the Chebyshev +polynomials up to degree 5 are plotted below. + +.. plot:: + + >>> import matplotlib.pyplot as plt + >>> from numpy.polynomial import Chebyshev as T + >>> x = np.linspace(-1, 1, 100) + >>> for i in range(6): ax = plt.plot(x, T.basis(i)(x), lw=2, label="$T_%d$"%i) + ... + >>> plt.legend(loc="upper left") + + >>> plt.show() + +In the range -1 <= `x` <= 1 they are nice, equiripple functions lying between +/- 1. +The same plots over the range -2 <= `x` <= 2 look very different: + +.. plot:: + + >>> import matplotlib.pyplot as plt + >>> from numpy.polynomial import Chebyshev as T + >>> x = np.linspace(-2, 2, 100) + >>> for i in range(6): ax = plt.plot(x, T.basis(i)(x), lw=2, label="$T_%d$"%i) + ... + >>> plt.legend(loc="lower right") + + >>> plt.show() + +As can be seen, the "good" parts have shrunk to insignificance. In using +Chebyshev polynomials for fitting we want to use the region where `x` is +between -1 and 1 and that is what the `window` specifies. However, it is +unlikely that the data to be fit has all its data points in that interval, +so we use `domain` to specify the interval where the data points lie. When +the fit is done, the domain is first mapped to the window by a linear +transformation and the usual least squares fit is done using the mapped +data points. The window and domain of the fit are part of the returned series +and are automatically used when computing values, derivatives, and such. If +they aren't specified in the call the fitting routine will use the default +window and the smallest domain that holds all the data points. This is +illustrated below for a fit to a noisy sine curve. + +.. plot:: + + >>> import numpy as np + >>> import matplotlib.pyplot as plt + >>> from numpy.polynomial import Chebyshev as T + >>> np.random.seed(11) + >>> x = np.linspace(0, 2*np.pi, 20) + >>> y = np.sin(x) + np.random.normal(scale=.1, size=x.shape) + >>> p = T.fit(x, y, 5) + >>> plt.plot(x, y, 'o') + [] + >>> xx, yy = p.linspace() + >>> plt.plot(xx, yy, lw=2) + [] + >>> p.domain + array([ 0. , 6.28318531]) + >>> p.window + array([-1., 1.]) + >>> plt.show() diff --git a/doc/source/reference/routines.polynomials.hermite.rst b/doc/source/reference/routines.polynomials.hermite.rst new file mode 100644 index 0000000..8ee72e9 --- /dev/null +++ b/doc/source/reference/routines.polynomials.hermite.rst @@ -0,0 +1,92 @@ +Hermite Module, "Physicists'" (:mod:`numpy.polynomial.hermite`) +=============================================================== + +.. versionadded:: 1.6.0 + +.. currentmodule:: numpy.polynomial.hermite + +This module provides a number of objects (mostly functions) useful for +dealing with Hermite series, including a `Hermite` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Hermite Class +------------- + +.. autosummary:: + :toctree: generated/ + + Hermite + +Basics +------ + +.. autosummary:: + :toctree: generated/ + + hermval + hermval2d + hermval3d + hermgrid2d + hermgrid3d + hermroots + hermfromroots + +Fitting +------- + +.. autosummary:: + :toctree: generated/ + + hermfit + hermvander + hermvander2d + hermvander3d + +Calculus +-------- + +.. autosummary:: + :toctree: generated/ + + hermder + hermint + +Algebra +------- + +.. autosummary:: + :toctree: generated/ + + hermadd + hermsub + hermmul + hermmulx + hermdiv + hermpow + +Quadrature +---------- + +.. autosummary:: + :toctree: generated/ + + hermgauss + hermweight + +Miscellaneous +------------- + +.. autosummary:: + :toctree: generated/ + + hermcompanion + hermdomain + hermzero + hermone + hermx + hermtrim + hermline + herm2poly + poly2herm diff --git a/doc/source/reference/routines.polynomials.hermite_e.rst b/doc/source/reference/routines.polynomials.hermite_e.rst new file mode 100644 index 0000000..33a15bb --- /dev/null +++ b/doc/source/reference/routines.polynomials.hermite_e.rst @@ -0,0 +1,92 @@ +HermiteE Module, "Probabilists'" (:mod:`numpy.polynomial.hermite_e`) +==================================================================== + +.. versionadded:: 1.6.0 + +.. currentmodule:: numpy.polynomial.hermite_e + +This module provides a number of objects (mostly functions) useful for +dealing with HermiteE series, including a `HermiteE` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +HermiteE Class +-------------- + +.. autosummary:: + :toctree: generated/ + + HermiteE + +Basics +------ + +.. autosummary:: + :toctree: generated/ + + hermeval + hermeval2d + hermeval3d + hermegrid2d + hermegrid3d + hermeroots + hermefromroots + +Fitting +------- + +.. autosummary:: + :toctree: generated/ + + hermefit + hermevander + hermevander2d + hermevander3d + +Calculus +-------- + +.. autosummary:: + :toctree: generated/ + + hermeder + hermeint + +Algebra +------- + +.. autosummary:: + :toctree: generated/ + + hermeadd + hermesub + hermemul + hermemulx + hermediv + hermepow + +Quadrature +---------- + +.. autosummary:: + :toctree: generated/ + + hermegauss + hermeweight + +Miscellaneous +------------- + +.. autosummary:: + :toctree: generated/ + + hermecompanion + hermedomain + hermezero + hermeone + hermex + hermetrim + hermeline + herme2poly + poly2herme diff --git a/doc/source/reference/routines.polynomials.laguerre.rst b/doc/source/reference/routines.polynomials.laguerre.rst new file mode 100644 index 0000000..45e288c --- /dev/null +++ b/doc/source/reference/routines.polynomials.laguerre.rst @@ -0,0 +1,92 @@ +Laguerre Module (:mod:`numpy.polynomial.laguerre`) +================================================== + +.. versionadded:: 1.6.0 + +.. currentmodule:: numpy.polynomial.laguerre + +This module provides a number of objects (mostly functions) useful for +dealing with Laguerre series, including a `Laguerre` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Laguerre Class +-------------- + +.. autosummary:: + :toctree: generated/ + + Laguerre + +Basics +------ + +.. autosummary:: + :toctree: generated/ + + lagval + lagval2d + lagval3d + laggrid2d + laggrid3d + lagroots + lagfromroots + +Fitting +------- + +.. autosummary:: + :toctree: generated/ + + lagfit + lagvander + lagvander2d + lagvander3d + +Calculus +-------- + +.. autosummary:: + :toctree: generated/ + + lagder + lagint + +Algebra +------- + +.. autosummary:: + :toctree: generated/ + + lagadd + lagsub + lagmul + lagmulx + lagdiv + lagpow + +Quadrature +---------- + +.. autosummary:: + :toctree: generated/ + + laggauss + lagweight + +Miscellaneous +------------- + +.. autosummary:: + :toctree: generated/ + + lagcompanion + lagdomain + lagzero + lagone + lagx + lagtrim + lagline + lag2poly + poly2lag diff --git a/doc/source/reference/routines.polynomials.legendre.rst b/doc/source/reference/routines.polynomials.legendre.rst new file mode 100644 index 0000000..fe6edc2 --- /dev/null +++ b/doc/source/reference/routines.polynomials.legendre.rst @@ -0,0 +1,92 @@ +Legendre Module (:mod:`numpy.polynomial.legendre`) +================================================== + +.. versionadded:: 1.6.0 + +.. currentmodule:: numpy.polynomial.legendre + +This module provides a number of objects (mostly functions) useful for +dealing with Legendre series, including a `Legendre` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Legendre Class +-------------- + +.. autosummary:: + :toctree: generated/ + + Legendre + +Basics +------ + +.. autosummary:: + :toctree: generated/ + + legval + legval2d + legval3d + leggrid2d + leggrid3d + legroots + legfromroots + +Fitting +------- + +.. autosummary:: + :toctree: generated/ + + legfit + legvander + legvander2d + legvander3d + +Calculus +-------- + +.. autosummary:: + :toctree: generated/ + + legder + legint + +Algebra +------- + +.. autosummary:: + :toctree: generated/ + + legadd + legsub + legmul + legmulx + legdiv + legpow + +Quadrature +---------- + +.. autosummary:: + :toctree: generated/ + + leggauss + legweight + +Miscellaneous +------------- + +.. autosummary:: + :toctree: generated/ + + legcompanion + legdomain + legzero + legone + legx + legtrim + legline + leg2poly + poly2leg diff --git a/doc/source/reference/routines.polynomials.package.rst b/doc/source/reference/routines.polynomials.package.rst new file mode 100644 index 0000000..61cb57f --- /dev/null +++ b/doc/source/reference/routines.polynomials.package.rst @@ -0,0 +1,18 @@ +Polynomial Package +================== + +.. versionadded:: 1.4.0 + +.. currentmodule:: numpy.polynomial + +.. toctree:: + :maxdepth: 2 + + routines.polynomials.classes + routines.polynomials.polynomial + routines.polynomials.chebyshev + routines.polynomials.legendre + routines.polynomials.laguerre + routines.polynomials.hermite + routines.polynomials.hermite_e + routines.polynomials.polyutils diff --git a/doc/source/reference/routines.polynomials.poly1d.rst b/doc/source/reference/routines.polynomials.poly1d.rst new file mode 100644 index 0000000..7eef53c --- /dev/null +++ b/doc/source/reference/routines.polynomials.poly1d.rst @@ -0,0 +1,46 @@ +Poly1d +====== + +.. currentmodule:: numpy + +Basics +------ +.. autosummary:: + :toctree: generated/ + + poly1d + polyval + poly + roots + +Fitting +------- +.. autosummary:: + :toctree: generated/ + + polyfit + +Calculus +-------- +.. autosummary:: + :toctree: generated/ + + polyder + polyint + +Arithmetic +---------- +.. autosummary:: + :toctree: generated/ + + polyadd + polydiv + polymul + polysub + +Warnings +-------- +.. autosummary:: + :toctree: generated/ + + RankWarning diff --git a/doc/source/reference/routines.polynomials.polynomial.rst b/doc/source/reference/routines.polynomials.polynomial.rst new file mode 100644 index 0000000..8194ca8 --- /dev/null +++ b/doc/source/reference/routines.polynomials.polynomial.rst @@ -0,0 +1,82 @@ +Polynomial Module (:mod:`numpy.polynomial.polynomial`) +====================================================== + +.. versionadded:: 1.4.0 + +.. currentmodule:: numpy.polynomial.polynomial + +This module provides a number of objects (mostly functions) useful for +dealing with Polynomial series, including a `Polynomial` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Polynomial Class +---------------- + +.. autosummary:: + :toctree: generated/ + + Polynomial + +Basics +------ + +.. autosummary:: + :toctree: generated/ + + polyval + polyval2d + polyval3d + polygrid2d + polygrid3d + polyroots + polyfromroots + polyvalfromroots + +Fitting +------- + +.. autosummary:: + :toctree: generated/ + + polyfit + polyvander + polyvander2d + polyvander3d + +Calculus +-------- + +.. autosummary:: + :toctree: generated/ + + polyder + polyint + +Algebra +------- + +.. autosummary:: + :toctree: generated/ + + polyadd + polysub + polymul + polymulx + polydiv + polypow + +Miscellaneous +------------- + +.. autosummary:: + :toctree: generated/ + + polycompanion + polydomain + polyzero + polyone + polyx + polytrim + polyline diff --git a/doc/source/reference/routines.polynomials.polyutils.rst b/doc/source/reference/routines.polynomials.polyutils.rst new file mode 100644 index 0000000..4bafd09 --- /dev/null +++ b/doc/source/reference/routines.polynomials.polyutils.rst @@ -0,0 +1,4 @@ +Polyutils +========= + +.. automodule:: numpy.polynomial.polyutils diff --git a/doc/source/reference/routines.polynomials.rst b/doc/source/reference/routines.polynomials.rst new file mode 100644 index 0000000..e85d054 --- /dev/null +++ b/doc/source/reference/routines.polynomials.rst @@ -0,0 +1,32 @@ +Polynomials +*********** + +Polynomials in NumPy can be *created*, *manipulated*, and even *fitted* using +the :doc:`routines.polynomials.classes` +of the `numpy.polynomial` package, introduced in NumPy 1.4. + +Prior to NumPy 1.4, `numpy.poly1d` was the class of choice and it is still +available in order to maintain backward compatibility. +However, the newer Polynomial package is more complete than `numpy.poly1d` +and its convenience classes are better behaved in the numpy environment. +Therefore Polynomial is recommended for new coding. + +Transition notice +----------------- +The various routines in the Polynomial package all deal with +series whose coefficients go from degree zero upward, +which is the *reverse order* of the Poly1d convention. +The easy way to remember this is that indexes +correspond to degree, i.e., coef[i] is the coefficient of the term of +degree i. + + +.. toctree:: + :maxdepth: 2 + + routines.polynomials.package + +.. toctree:: + :maxdepth: 2 + + routines.polynomials.poly1d diff --git a/doc/source/reference/routines.random.rst b/doc/source/reference/routines.random.rst new file mode 100644 index 0000000..c8b097d --- /dev/null +++ b/doc/source/reference/routines.random.rst @@ -0,0 +1,81 @@ +.. _routines.random: + +Random sampling (:mod:`numpy.random`) +************************************* + +.. currentmodule:: numpy.random + +Simple random data +================== +.. autosummary:: + :toctree: generated/ + + rand + randn + randint + random_integers + random_sample + random + ranf + sample + choice + bytes + +Permutations +============ +.. autosummary:: + :toctree: generated/ + + shuffle + permutation + +Distributions +============= +.. autosummary:: + :toctree: generated/ + + beta + binomial + chisquare + dirichlet + exponential + f + gamma + geometric + gumbel + hypergeometric + laplace + logistic + lognormal + logseries + multinomial + multivariate_normal + negative_binomial + noncentral_chisquare + noncentral_f + normal + pareto + poisson + power + rayleigh + standard_cauchy + standard_exponential + standard_gamma + standard_normal + standard_t + triangular + uniform + vonmises + wald + weibull + zipf + +Random generator +================ +.. autosummary:: + :toctree: generated/ + + RandomState + seed + get_state + set_state diff --git a/doc/source/reference/routines.rst b/doc/source/reference/routines.rst new file mode 100644 index 0000000..a9e8048 --- /dev/null +++ b/doc/source/reference/routines.rst @@ -0,0 +1,49 @@ +.. _routines: + +******** +Routines +******** + +In this chapter routine docstrings are presented, grouped by functionality. +Many docstrings contain example code, which demonstrates basic usage +of the routine. The examples assume that NumPy is imported with:: + + >>> import numpy as np + +A convenient way to execute examples is the ``%doctest_mode`` mode of +IPython, which allows for pasting of multi-line examples and preserves +indentation. + +.. toctree:: + :maxdepth: 2 + + routines.array-creation + routines.array-manipulation + routines.bitwise + routines.char + routines.ctypeslib + routines.datetime + routines.dtype + routines.dual + routines.emath + routines.err + routines.fft + routines.financial + routines.functional + routines.help + routines.indexing + routines.io + routines.linalg + routines.logic + routines.ma + routines.math + routines.matlib + routines.other + routines.padding + routines.polynomials + routines.random + routines.set + routines.sort + routines.statistics + routines.testing + routines.window diff --git a/doc/source/reference/routines.set.rst b/doc/source/reference/routines.set.rst new file mode 100644 index 0000000..b12d3d5 --- /dev/null +++ b/doc/source/reference/routines.set.rst @@ -0,0 +1,23 @@ +Set routines +============ + +.. currentmodule:: numpy + +Making proper sets +------------------ +.. autosummary:: + :toctree: generated/ + + unique + +Boolean operations +------------------ +.. autosummary:: + :toctree: generated/ + + in1d + intersect1d + isin + setdiff1d + setxor1d + union1d diff --git a/doc/source/reference/routines.sort.rst b/doc/source/reference/routines.sort.rst new file mode 100644 index 0000000..c22fa0c --- /dev/null +++ b/doc/source/reference/routines.sort.rst @@ -0,0 +1,41 @@ +Sorting, searching, and counting +================================ + +.. currentmodule:: numpy + +Sorting +------- +.. autosummary:: + :toctree: generated/ + + sort + lexsort + argsort + ndarray.sort + msort + sort_complex + partition + argpartition + +Searching +--------- +.. autosummary:: + :toctree: generated/ + + argmax + nanargmax + argmin + nanargmin + argwhere + nonzero + flatnonzero + where + searchsorted + extract + +Counting +-------- +.. autosummary:: + :toctree: generated/ + + count_nonzero diff --git a/doc/source/reference/routines.statistics.rst b/doc/source/reference/routines.statistics.rst new file mode 100644 index 0000000..d359541 --- /dev/null +++ b/doc/source/reference/routines.statistics.rst @@ -0,0 +1,57 @@ +Statistics +========== + +.. currentmodule:: numpy + + +Order statistics +---------------- + +.. autosummary:: + :toctree: generated/ + + amin + amax + nanmin + nanmax + ptp + percentile + nanpercentile + +Averages and variances +---------------------- + +.. autosummary:: + :toctree: generated/ + + median + average + mean + std + var + nanmedian + nanmean + nanstd + nanvar + +Correlating +----------- + +.. autosummary:: + :toctree: generated/ + + corrcoef + correlate + cov + +Histograms +---------- + +.. autosummary:: + :toctree: generated/ + + histogram + histogram2d + histogramdd + bincount + digitize diff --git a/doc/source/reference/routines.testing.rst b/doc/source/reference/routines.testing.rst new file mode 100644 index 0000000..ad95bb3 --- /dev/null +++ b/doc/source/reference/routines.testing.rst @@ -0,0 +1,52 @@ +Test Support (:mod:`numpy.testing`) +=================================== + +.. currentmodule:: numpy.testing + +Common test support for all numpy test scripts. + +This single module should provide all the common functionality for numpy +tests in a single location, so that test scripts can just import it and +work right away. + + +Asserts +------- +.. autosummary:: + :toctree: generated/ + + assert_almost_equal + assert_approx_equal + assert_array_almost_equal + assert_allclose + assert_array_almost_equal_nulp + assert_array_max_ulp + assert_array_equal + assert_array_less + assert_equal + assert_raises + assert_raises_regex + assert_warns + assert_string_equal + +Decorators +---------- +.. autosummary:: + :toctree: generated/ + + decorators.deprecated + decorators.knownfailureif + decorators.setastest + decorators.skipif + decorators.slow + decorate_methods + +Test Running +------------ +.. autosummary:: + :toctree: generated/ + + Tester + run_module_suite + rundocs + suppress_warnings diff --git a/doc/source/reference/routines.window.rst b/doc/source/reference/routines.window.rst new file mode 100644 index 0000000..7f34148 --- /dev/null +++ b/doc/source/reference/routines.window.rst @@ -0,0 +1,16 @@ +Window functions +================ + +.. currentmodule:: numpy + +Various windows +--------------- + +.. autosummary:: + :toctree: generated/ + + bartlett + blackman + hamming + hanning + kaiser diff --git a/doc/source/reference/swig.interface-file.rst b/doc/source/reference/swig.interface-file.rst new file mode 100644 index 0000000..6dd74f4 --- /dev/null +++ b/doc/source/reference/swig.interface-file.rst @@ -0,0 +1,1066 @@ +numpy.i: a SWIG Interface File for NumPy +======================================== + +Introduction +------------ + +The Simple Wrapper and Interface Generator (or `SWIG +`_) is a powerful tool for generating wrapper +code for interfacing to a wide variety of scripting languages. +`SWIG`_ can parse header files, and using only the code prototypes, +create an interface to the target language. But `SWIG`_ is not +omnipotent. For example, it cannot know from the prototype:: + + double rms(double* seq, int n); + +what exactly ``seq`` is. Is it a single value to be altered in-place? +Is it an array, and if so what is its length? Is it input-only? +Output-only? Input-output? `SWIG`_ cannot determine these details, +and does not attempt to do so. + +If we designed ``rms``, we probably made it a routine that takes an +input-only array of length ``n`` of ``double`` values called ``seq`` +and returns the root mean square. The default behavior of `SWIG`_, +however, will be to create a wrapper function that compiles, but is +nearly impossible to use from the scripting language in the way the C +routine was intended. + +For Python, the preferred way of handling contiguous (or technically, +*strided*) blocks of homogeneous data is with NumPy, which provides full +object-oriented access to multidimensial arrays of data. Therefore, the most +logical Python interface for the ``rms`` function would be (including doc +string):: + + def rms(seq): + """ + rms: return the root mean square of a sequence + rms(numpy.ndarray) -> double + rms(list) -> double + rms(tuple) -> double + """ + +where ``seq`` would be a NumPy array of ``double`` values, and its +length ``n`` would be extracted from ``seq`` internally before being +passed to the C routine. Even better, since NumPy supports +construction of arrays from arbitrary Python sequences, ``seq`` +itself could be a nearly arbitrary sequence (so long as each element +can be converted to a ``double``) and the wrapper code would +internally convert it to a NumPy array before extracting its data +and length. + +`SWIG`_ allows these types of conversions to be defined via a +mechanism called *typemaps*. This document provides information on +how to use ``numpy.i``, a `SWIG`_ interface file that defines a series +of typemaps intended to make the type of array-related conversions +described above relatively simple to implement. For example, suppose +that the ``rms`` function prototype defined above was in a header file +named ``rms.h``. To obtain the Python interface discussed above, your +`SWIG`_ interface file would need the following:: + + %{ + #define SWIG_FILE_WITH_INIT + #include "rms.h" + %} + + %include "numpy.i" + + %init %{ + import_array(); + %} + + %apply (double* IN_ARRAY1, int DIM1) {(double* seq, int n)}; + %include "rms.h" + +Typemaps are keyed off a list of one or more function arguments, +either by type or by type and name. We will refer to such lists as +*signatures*. One of the many typemaps defined by ``numpy.i`` is used +above and has the signature ``(double* IN_ARRAY1, int DIM1)``. The +argument names are intended to suggest that the ``double*`` argument +is an input array of one dimension and that the ``int`` represents the +size of that dimension. This is precisely the pattern in the ``rms`` +prototype. + +Most likely, no actual prototypes to be wrapped will have the argument +names ``IN_ARRAY1`` and ``DIM1``. We use the `SWIG`_ ``%apply`` +directive to apply the typemap for one-dimensional input arrays of +type ``double`` to the actual prototype used by ``rms``. Using +``numpy.i`` effectively, therefore, requires knowing what typemaps are +available and what they do. + +A `SWIG`_ interface file that includes the `SWIG`_ directives given +above will produce wrapper code that looks something like:: + + 1 PyObject *_wrap_rms(PyObject *args) { + 2 PyObject *resultobj = 0; + 3 double *arg1 = (double *) 0 ; + 4 int arg2 ; + 5 double result; + 6 PyArrayObject *array1 = NULL ; + 7 int is_new_object1 = 0 ; + 8 PyObject * obj0 = 0 ; + 9 + 10 if (!PyArg_ParseTuple(args,(char *)"O:rms",&obj0)) SWIG_fail; + 11 { + 12 array1 = obj_to_array_contiguous_allow_conversion( + 13 obj0, NPY_DOUBLE, &is_new_object1); + 14 npy_intp size[1] = { + 15 -1 + 16 }; + 17 if (!array1 || !require_dimensions(array1, 1) || + 18 !require_size(array1, size, 1)) SWIG_fail; + 19 arg1 = (double*) array1->data; + 20 arg2 = (int) array1->dimensions[0]; + 21 } + 22 result = (double)rms(arg1,arg2); + 23 resultobj = SWIG_From_double((double)(result)); + 24 { + 25 if (is_new_object1 && array1) Py_DECREF(array1); + 26 } + 27 return resultobj; + 28 fail: + 29 { + 30 if (is_new_object1 && array1) Py_DECREF(array1); + 31 } + 32 return NULL; + 33 } + +The typemaps from ``numpy.i`` are responsible for the following lines +of code: 12--20, 25 and 30. Line 10 parses the input to the ``rms`` +function. From the format string ``"O:rms"``, we can see that the +argument list is expected to be a single Python object (specified +by the ``O`` before the colon) and whose pointer is stored in +``obj0``. A number of functions, supplied by ``numpy.i``, are called +to make and check the (possible) conversion from a generic Python +object to a NumPy array. These functions are explained in the +section `Helper Functions`_, but hopefully their names are +self-explanatory. At line 12 we use ``obj0`` to construct a NumPy +array. At line 17, we check the validity of the result: that it is +non-null and that it has a single dimension of arbitrary length. Once +these states are verified, we extract the data buffer and length in +lines 19 and 20 so that we can call the underlying C function at line +22. Line 25 performs memory management for the case where we have +created a new array that is no longer needed. + +This code has a significant amount of error handling. Note the +``SWIG_fail`` is a macro for ``goto fail``, referring to the label at +line 28. If the user provides the wrong number of arguments, this +will be caught at line 10. If construction of the NumPy array +fails or produces an array with the wrong number of dimensions, these +errors are caught at line 17. And finally, if an error is detected, +memory is still managed correctly at line 30. + +Note that if the C function signature was in a different order:: + + double rms(int n, double* seq); + +that `SWIG`_ would not match the typemap signature given above with +the argument list for ``rms``. Fortunately, ``numpy.i`` has a set of +typemaps with the data pointer given last:: + + %apply (int DIM1, double* IN_ARRAY1) {(int n, double* seq)}; + +This simply has the effect of switching the definitions of ``arg1`` +and ``arg2`` in lines 3 and 4 of the generated code above, and their +assignments in lines 19 and 20. + +Using numpy.i +------------- + +The ``numpy.i`` file is currently located in the ``tools/swig`` +sub-directory under the ``numpy`` installation directory. Typically, +you will want to copy it to the directory where you are developing +your wrappers. + +A simple module that only uses a single `SWIG`_ interface file should +include the following:: + + %{ + #define SWIG_FILE_WITH_INIT + %} + %include "numpy.i" + %init %{ + import_array(); + %} + +Within a compiled Python module, ``import_array()`` should only get +called once. This could be in a C/C++ file that you have written and +is linked to the module. If this is the case, then none of your +interface files should ``#define SWIG_FILE_WITH_INIT`` or call +``import_array()``. Or, this initialization call could be in a +wrapper file generated by `SWIG`_ from an interface file that has the +``%init`` block as above. If this is the case, and you have more than +one `SWIG`_ interface file, then only one interface file should +``#define SWIG_FILE_WITH_INIT`` and call ``import_array()``. + +Available Typemaps +------------------ + +The typemap directives provided by ``numpy.i`` for arrays of different +data types, say ``double`` and ``int``, and dimensions of different +types, say ``int`` or ``long``, are identical to one another except +for the C and NumPy type specifications. The typemaps are +therefore implemented (typically behind the scenes) via a macro:: + + %numpy_typemaps(DATA_TYPE, DATA_TYPECODE, DIM_TYPE) + +that can be invoked for appropriate ``(DATA_TYPE, DATA_TYPECODE, +DIM_TYPE)`` triplets. For example:: + + %numpy_typemaps(double, NPY_DOUBLE, int) + %numpy_typemaps(int, NPY_INT , int) + +The ``numpy.i`` interface file uses the ``%numpy_typemaps`` macro to +implement typemaps for the following C data types and ``int`` +dimension types: + + * ``signed char`` + * ``unsigned char`` + * ``short`` + * ``unsigned short`` + * ``int`` + * ``unsigned int`` + * ``long`` + * ``unsigned long`` + * ``long long`` + * ``unsigned long long`` + * ``float`` + * ``double`` + +In the following descriptions, we reference a generic ``DATA_TYPE``, which +could be any of the C data types listed above, and ``DIM_TYPE`` which +should be one of the many types of integers. + +The typemap signatures are largely differentiated on the name given to +the buffer pointer. Names with ``FARRAY`` are for Fortran-ordered +arrays, and names with ``ARRAY`` are for C-ordered (or 1D arrays). + +Input Arrays +```````````` + +Input arrays are defined as arrays of data that are passed into a +routine but are not altered in-place or returned to the user. The +Python input array is therefore allowed to be almost any Python +sequence (such as a list) that can be converted to the requested type +of array. The input array signatures are + +1D: + + * ``( DATA_TYPE IN_ARRAY1[ANY] )`` + * ``( DATA_TYPE* IN_ARRAY1, int DIM1 )`` + * ``( int DIM1, DATA_TYPE* IN_ARRAY1 )`` + +2D: + + * ``( DATA_TYPE IN_ARRAY2[ANY][ANY] )`` + * ``( DATA_TYPE* IN_ARRAY2, int DIM1, int DIM2 )`` + * ``( int DIM1, int DIM2, DATA_TYPE* IN_ARRAY2 )`` + * ``( DATA_TYPE* IN_FARRAY2, int DIM1, int DIM2 )`` + * ``( int DIM1, int DIM2, DATA_TYPE* IN_FARRAY2 )`` + +3D: + + * ``( DATA_TYPE IN_ARRAY3[ANY][ANY][ANY] )`` + * ``( DATA_TYPE* IN_ARRAY3, int DIM1, int DIM2, int DIM3 )`` + * ``( int DIM1, int DIM2, int DIM3, DATA_TYPE* IN_ARRAY3 )`` + * ``( DATA_TYPE* IN_FARRAY3, int DIM1, int DIM2, int DIM3 )`` + * ``( int DIM1, int DIM2, int DIM3, DATA_TYPE* IN_FARRAY3 )`` + +4D: + + * ``(DATA_TYPE IN_ARRAY4[ANY][ANY][ANY][ANY])`` + * ``(DATA_TYPE* IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4)`` + * ``(DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, , DIM_TYPE DIM4, DATA_TYPE* IN_ARRAY4)`` + * ``(DATA_TYPE* IN_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4)`` + * ``(DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* IN_FARRAY4)`` + +The first signature listed, ``( DATA_TYPE IN_ARRAY[ANY] )`` is for +one-dimensional arrays with hard-coded dimensions. Likewise, +``( DATA_TYPE IN_ARRAY2[ANY][ANY] )`` is for two-dimensional arrays +with hard-coded dimensions, and similarly for three-dimensional. + +In-Place Arrays +``````````````` + +In-place arrays are defined as arrays that are modified in-place. The +input values may or may not be used, but the values at the time the +function returns are significant. The provided Python argument +must therefore be a NumPy array of the required type. The in-place +signatures are + +1D: + + * ``( DATA_TYPE INPLACE_ARRAY1[ANY] )`` + * ``( DATA_TYPE* INPLACE_ARRAY1, int DIM1 )`` + * ``( int DIM1, DATA_TYPE* INPLACE_ARRAY1 )`` + +2D: + + * ``( DATA_TYPE INPLACE_ARRAY2[ANY][ANY] )`` + * ``( DATA_TYPE* INPLACE_ARRAY2, int DIM1, int DIM2 )`` + * ``( int DIM1, int DIM2, DATA_TYPE* INPLACE_ARRAY2 )`` + * ``( DATA_TYPE* INPLACE_FARRAY2, int DIM1, int DIM2 )`` + * ``( int DIM1, int DIM2, DATA_TYPE* INPLACE_FARRAY2 )`` + +3D: + + * ``( DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY] )`` + * ``( DATA_TYPE* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3 )`` + * ``( int DIM1, int DIM2, int DIM3, DATA_TYPE* INPLACE_ARRAY3 )`` + * ``( DATA_TYPE* INPLACE_FARRAY3, int DIM1, int DIM2, int DIM3 )`` + * ``( int DIM1, int DIM2, int DIM3, DATA_TYPE* INPLACE_FARRAY3 )`` + +4D: + + * ``(DATA_TYPE INPLACE_ARRAY4[ANY][ANY][ANY][ANY])`` + * ``(DATA_TYPE* INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4)`` + * ``(DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, , DIM_TYPE DIM4, DATA_TYPE* INPLACE_ARRAY4)`` + * ``(DATA_TYPE* INPLACE_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4)`` + * ``(DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* INPLACE_FARRAY4)`` + +These typemaps now check to make sure that the ``INPLACE_ARRAY`` +arguments use native byte ordering. If not, an exception is raised. + +There is also a "flat" in-place array for situations in which +you would like to modify or process each element, regardless of the +number of dimensions. One example is a "quantization" function that +quantizes each element of an array in-place, be it 1D, 2D or whatever. +This form checks for continuity but allows either C or Fortran ordering. + +ND: + + * ``(DATA_TYPE* INPLACE_ARRAY_FLAT, DIM_TYPE DIM_FLAT)`` + + +Argout Arrays +````````````` + +Argout arrays are arrays that appear in the input arguments in C, but +are in fact output arrays. This pattern occurs often when there is +more than one output variable and the single return argument is +therefore not sufficient. In Python, the conventional way to return +multiple arguments is to pack them into a sequence (tuple, list, etc.) +and return the sequence. This is what the argout typemaps do. If a +wrapped function that uses these argout typemaps has more than one +return argument, they are packed into a tuple or list, depending on +the version of Python. The Python user does not pass these +arrays in, they simply get returned. For the case where a dimension +is specified, the python user must provide that dimension as an +argument. The argout signatures are + +1D: + + * ``( DATA_TYPE ARGOUT_ARRAY1[ANY] )`` + * ``( DATA_TYPE* ARGOUT_ARRAY1, int DIM1 )`` + * ``( int DIM1, DATA_TYPE* ARGOUT_ARRAY1 )`` + +2D: + + * ``( DATA_TYPE ARGOUT_ARRAY2[ANY][ANY] )`` + +3D: + + * ``( DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY] )`` + +4D: + + * ``( DATA_TYPE ARGOUT_ARRAY4[ANY][ANY][ANY][ANY] )`` + +These are typically used in situations where in C/C++, you would +allocate a(n) array(s) on the heap, and call the function to fill the +array(s) values. In Python, the arrays are allocated for you and +returned as new array objects. + +Note that we support ``DATA_TYPE*`` argout typemaps in 1D, but not 2D +or 3D. This is because of a quirk with the `SWIG`_ typemap syntax and +cannot be avoided. Note that for these types of 1D typemaps, the +Python function will take a single argument representing ``DIM1``. + +Argout View Arrays +`````````````````` + +Argoutview arrays are for when your C code provides you with a view of +its internal data and does not require any memory to be allocated by +the user. This can be dangerous. There is almost no way to guarantee +that the internal data from the C code will remain in existence for +the entire lifetime of the NumPy array that encapsulates it. If +the user destroys the object that provides the view of the data before +destroying the NumPy array, then using that array may result in bad +memory references or segmentation faults. Nevertheless, there are +situations, working with large data sets, where you simply have no +other choice. + +The C code to be wrapped for argoutview arrays are characterized by +pointers: pointers to the dimensions and double pointers to the data, +so that these values can be passed back to the user. The argoutview +typemap signatures are therefore + +1D: + + * ``( DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1 )`` + * ``( DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEW_ARRAY1 )`` + +2D: + + * ``( DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2 )`` + * ``( DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_ARRAY2 )`` + * ``( DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2 )`` + * ``( DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_FARRAY2 )`` + +3D: + + * ``( DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3)`` + * ``( DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_ARRAY3)`` + * ``( DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3)`` + * ``( DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_FARRAY3)`` + +4D: + + * ``(DATA_TYPE** ARGOUTVIEW_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4)`` + * ``(DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEW_ARRAY4)`` + * ``(DATA_TYPE** ARGOUTVIEW_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4)`` + * ``(DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEW_FARRAY4)`` + +Note that arrays with hard-coded dimensions are not supported. These +cannot follow the double pointer signatures of these typemaps. + +Memory Managed Argout View Arrays +````````````````````````````````` + +A recent addition to ``numpy.i`` are typemaps that permit argout +arrays with views into memory that is managed. See the discussion `here +`_. + +1D: + + * ``(DATA_TYPE** ARGOUTVIEWM_ARRAY1, DIM_TYPE* DIM1)`` + * ``(DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEWM_ARRAY1)`` + +2D: + + * ``(DATA_TYPE** ARGOUTVIEWM_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2)`` + * ``(DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEWM_ARRAY2)`` + * ``(DATA_TYPE** ARGOUTVIEWM_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2)`` + * ``(DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEWM_FARRAY2)`` + +3D: + + * ``(DATA_TYPE** ARGOUTVIEWM_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3)`` + * ``(DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEWM_ARRAY3)`` + * ``(DATA_TYPE** ARGOUTVIEWM_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3)`` + * ``(DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEWM_FARRAY3)`` + +4D: + + * ``(DATA_TYPE** ARGOUTVIEWM_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4)`` + * ``(DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEWM_ARRAY4)`` + * ``(DATA_TYPE** ARGOUTVIEWM_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4)`` + * ``(DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEWM_FARRAY4)`` + + +Output Arrays +````````````` + +The ``numpy.i`` interface file does not support typemaps for output +arrays, for several reasons. First, C/C++ return arguments are +limited to a single value. This prevents obtaining dimension +information in a general way. Second, arrays with hard-coded lengths +are not permitted as return arguments. In other words:: + + double[3] newVector(double x, double y, double z); + +is not legal C/C++ syntax. Therefore, we cannot provide typemaps of +the form:: + + %typemap(out) (TYPE[ANY]); + +If you run into a situation where a function or method is returning a +pointer to an array, your best bet is to write your own version of the +function to be wrapped, either with ``%extend`` for the case of class +methods or ``%ignore`` and ``%rename`` for the case of functions. + +Other Common Types: bool +```````````````````````` + +Note that C++ type ``bool`` is not supported in the list in the +`Available Typemaps`_ section. NumPy bools are a single byte, while +the C++ ``bool`` is four bytes (at least on my system). Therefore:: + + %numpy_typemaps(bool, NPY_BOOL, int) + +will result in typemaps that will produce code that reference +improper data lengths. You can implement the following macro +expansion:: + + %numpy_typemaps(bool, NPY_UINT, int) + +to fix the data length problem, and `Input Arrays`_ will work fine, +but `In-Place Arrays`_ might fail type-checking. + +Other Common Types: complex +``````````````````````````` + +Typemap conversions for complex floating-point types is also not +supported automatically. This is because Python and NumPy are +written in C, which does not have native complex types. Both +Python and NumPy implement their own (essentially equivalent) +``struct`` definitions for complex variables:: + + /* Python */ + typedef struct {double real; double imag;} Py_complex; + + /* NumPy */ + typedef struct {float real, imag;} npy_cfloat; + typedef struct {double real, imag;} npy_cdouble; + +We could have implemented:: + + %numpy_typemaps(Py_complex , NPY_CDOUBLE, int) + %numpy_typemaps(npy_cfloat , NPY_CFLOAT , int) + %numpy_typemaps(npy_cdouble, NPY_CDOUBLE, int) + +which would have provided automatic type conversions for arrays of +type ``Py_complex``, ``npy_cfloat`` and ``npy_cdouble``. However, it +seemed unlikely that there would be any independent (non-Python, +non-NumPy) application code that people would be using `SWIG`_ to +generate a Python interface to, that also used these definitions +for complex types. More likely, these application codes will define +their own complex types, or in the case of C++, use ``std::complex``. +Assuming these data structures are compatible with Python and +NumPy complex types, ``%numpy_typemap`` expansions as above (with +the user's complex type substituted for the first argument) should +work. + +NumPy Array Scalars and SWIG +---------------------------- + +`SWIG`_ has sophisticated type checking for numerical types. For +example, if your C/C++ routine expects an integer as input, the code +generated by `SWIG`_ will check for both Python integers and +Python long integers, and raise an overflow error if the provided +Python integer is too big to cast down to a C integer. With the +introduction of NumPy scalar arrays into your Python code, you +might conceivably extract an integer from a NumPy array and attempt +to pass this to a `SWIG`_-wrapped C/C++ function that expects an +``int``, but the `SWIG`_ type checking will not recognize the NumPy +array scalar as an integer. (Often, this does in fact work -- it +depends on whether NumPy recognizes the integer type you are using +as inheriting from the Python integer type on the platform you are +using. Sometimes, this means that code that works on a 32-bit machine +will fail on a 64-bit machine.) + +If you get a Python error that looks like the following:: + + TypeError: in method 'MyClass_MyMethod', argument 2 of type 'int' + +and the argument you are passing is an integer extracted from a +NumPy array, then you have stumbled upon this problem. The +solution is to modify the `SWIG`_ type conversion system to accept +NumPy array scalars in addition to the standard integer types. +Fortunately, this capability has been provided for you. Simply copy +the file:: + + pyfragments.swg + +to the working build directory for you project, and this problem will +be fixed. It is suggested that you do this anyway, as it only +increases the capabilities of your Python interface. + +Why is There a Second File? +``````````````````````````` + +The `SWIG`_ type checking and conversion system is a complicated +combination of C macros, `SWIG`_ macros, `SWIG`_ typemaps and `SWIG`_ +fragments. Fragments are a way to conditionally insert code into your +wrapper file if it is needed, and not insert it if not needed. If +multiple typemaps require the same fragment, the fragment only gets +inserted into your wrapper code once. + +There is a fragment for converting a Python integer to a C +``long``. There is a different fragment that converts a Python +integer to a C ``int``, that calls the routine defined in the +``long`` fragment. We can make the changes we want here by changing +the definition for the ``long`` fragment. `SWIG`_ determines the +active definition for a fragment using a "first come, first served" +system. That is, we need to define the fragment for ``long`` +conversions prior to `SWIG`_ doing it internally. `SWIG`_ allows us +to do this by putting our fragment definitions in the file +``pyfragments.swg``. If we were to put the new fragment definitions +in ``numpy.i``, they would be ignored. + +Helper Functions +---------------- + +The ``numpy.i`` file contains several macros and routines that it +uses internally to build its typemaps. However, these functions may +be useful elsewhere in your interface file. These macros and routines +are implemented as fragments, which are described briefly in the +previous section. If you try to use one or more of the following +macros or functions, but your compiler complains that it does not +recognize the symbol, then you need to force these fragments to appear +in your code using:: + + %fragment("NumPy_Fragments"); + +in your `SWIG`_ interface file. + +Macros +`````` + + **is_array(a)** + Evaluates as true if ``a`` is non-``NULL`` and can be cast to a + ``PyArrayObject*``. + + **array_type(a)** + Evaluates to the integer data type code of ``a``, assuming ``a`` can + be cast to a ``PyArrayObject*``. + + **array_numdims(a)** + Evaluates to the integer number of dimensions of ``a``, assuming + ``a`` can be cast to a ``PyArrayObject*``. + + **array_dimensions(a)** + Evaluates to an array of type ``npy_intp`` and length + ``array_numdims(a)``, giving the lengths of all of the dimensions + of ``a``, assuming ``a`` can be cast to a ``PyArrayObject*``. + + **array_size(a,i)** + Evaluates to the ``i``-th dimension size of ``a``, assuming ``a`` + can be cast to a ``PyArrayObject*``. + + **array_strides(a)** + Evaluates to an array of type ``npy_intp`` and length + ``array_numdims(a)``, giving the stridess of all of the dimensions + of ``a``, assuming ``a`` can be cast to a ``PyArrayObject*``. A + stride is the distance in bytes between an element and its + immediate neighbor along the same axis. + + **array_stride(a,i)** + Evaluates to the ``i``-th stride of ``a``, assuming ``a`` can be + cast to a ``PyArrayObject*``. + + **array_data(a)** + Evaluates to a pointer of type ``void*`` that points to the data + buffer of ``a``, assuming ``a`` can be cast to a ``PyArrayObject*``. + + **array_descr(a)** + Returns a borrowed reference to the dtype property + (``PyArray_Descr*``) of ``a``, assuming ``a`` can be cast to a + ``PyArrayObject*``. + + **array_flags(a)** + Returns an integer representing the flags of ``a``, assuming ``a`` + can be cast to a ``PyArrayObject*``. + + **array_enableflags(a,f)** + Sets the flag represented by ``f`` of ``a``, assuming ``a`` can be + cast to a ``PyArrayObject*``. + + **array_is_contiguous(a)** + Evaluates as true if ``a`` is a contiguous array. Equivalent to + ``(PyArray_ISCONTIGUOUS(a))``. + + **array_is_native(a)** + Evaluates as true if the data buffer of ``a`` uses native byte + order. Equivalent to ``(PyArray_ISNOTSWAPPED(a))``. + + **array_is_fortran(a)** + Evaluates as true if ``a`` is FORTRAN ordered. + +Routines +```````` + + **pytype_string()** + + Return type: ``const char*`` + + Arguments: + + * ``PyObject* py_obj``, a general Python object. + + Return a string describing the type of ``py_obj``. + + + **typecode_string()** + + Return type: ``const char*`` + + Arguments: + + * ``int typecode``, a NumPy integer typecode. + + Return a string describing the type corresponding to the NumPy + ``typecode``. + + **type_match()** + + Return type: ``int`` + + Arguments: + + * ``int actual_type``, the NumPy typecode of a NumPy array. + + * ``int desired_type``, the desired NumPy typecode. + + Make sure that ``actual_type`` is compatible with + ``desired_type``. For example, this allows character and + byte types, or int and long types, to match. This is now + equivalent to ``PyArray_EquivTypenums()``. + + + **obj_to_array_no_conversion()** + + Return type: ``PyArrayObject*`` + + Arguments: + + * ``PyObject* input``, a general Python object. + + * ``int typecode``, the desired NumPy typecode. + + Cast ``input`` to a ``PyArrayObject*`` if legal, and ensure that + it is of type ``typecode``. If ``input`` cannot be cast, or the + ``typecode`` is wrong, set a Python error and return ``NULL``. + + + **obj_to_array_allow_conversion()** + + Return type: ``PyArrayObject*`` + + Arguments: + + * ``PyObject* input``, a general Python object. + + * ``int typecode``, the desired NumPy typecode of the resulting + array. + + * ``int* is_new_object``, returns a value of 0 if no conversion + performed, else 1. + + Convert ``input`` to a NumPy array with the given ``typecode``. + On success, return a valid ``PyArrayObject*`` with the correct + type. On failure, the Python error string will be set and the + routine returns ``NULL``. + + + **make_contiguous()** + + Return type: ``PyArrayObject*`` + + Arguments: + + * ``PyArrayObject* ary``, a NumPy array. + + * ``int* is_new_object``, returns a value of 0 if no conversion + performed, else 1. + + * ``int min_dims``, minimum allowable dimensions. + + * ``int max_dims``, maximum allowable dimensions. + + Check to see if ``ary`` is contiguous. If so, return the input + pointer and flag it as not a new object. If it is not contiguous, + create a new ``PyArrayObject*`` using the original data, flag it + as a new object and return the pointer. + + + **make_fortran()** + + Return type: ``PyArrayObject*`` + + Arguments + + * ``PyArrayObject* ary``, a NumPy array. + + * ``int* is_new_object``, returns a value of 0 if no conversion + performed, else 1. + + Check to see if ``ary`` is Fortran contiguous. If so, return the + input pointer and flag it as not a new object. If it is not + Fortran contiguous, create a new ``PyArrayObject*`` using the + original data, flag it as a new object and return the pointer. + + + **obj_to_array_contiguous_allow_conversion()** + + Return type: ``PyArrayObject*`` + + Arguments: + + * ``PyObject* input``, a general Python object. + + * ``int typecode``, the desired NumPy typecode of the resulting + array. + + * ``int* is_new_object``, returns a value of 0 if no conversion + performed, else 1. + + Convert ``input`` to a contiguous ``PyArrayObject*`` of the + specified type. If the input object is not a contiguous + ``PyArrayObject*``, a new one will be created and the new object + flag will be set. + + + **obj_to_array_fortran_allow_conversion()** + + Return type: ``PyArrayObject*`` + + Arguments: + + * ``PyObject* input``, a general Python object. + + * ``int typecode``, the desired NumPy typecode of the resulting + array. + + * ``int* is_new_object``, returns a value of 0 if no conversion + performed, else 1. + + Convert ``input`` to a Fortran contiguous ``PyArrayObject*`` of + the specified type. If the input object is not a Fortran + contiguous ``PyArrayObject*``, a new one will be created and the + new object flag will be set. + + + **require_contiguous()** + + Return type: ``int`` + + Arguments: + + * ``PyArrayObject* ary``, a NumPy array. + + Test whether ``ary`` is contiguous. If so, return 1. Otherwise, + set a Python error and return 0. + + + **require_native()** + + Return type: ``int`` + + Arguments: + + * ``PyArray_Object* ary``, a NumPy array. + + Require that ``ary`` is not byte-swapped. If the array is not + byte-swapped, return 1. Otherwise, set a Python error and + return 0. + + **require_dimensions()** + + Return type: ``int`` + + Arguments: + + * ``PyArrayObject* ary``, a NumPy array. + + * ``int exact_dimensions``, the desired number of dimensions. + + Require ``ary`` to have a specified number of dimensions. If the + array has the specified number of dimensions, return 1. + Otherwise, set a Python error and return 0. + + + **require_dimensions_n()** + + Return type: ``int`` + + Arguments: + + * ``PyArrayObject* ary``, a NumPy array. + + * ``int* exact_dimensions``, an array of integers representing + acceptable numbers of dimensions. + + * ``int n``, the length of ``exact_dimensions``. + + Require ``ary`` to have one of a list of specified number of + dimensions. If the array has one of the specified number of + dimensions, return 1. Otherwise, set the Python error string + and return 0. + + + **require_size()** + + Return type: ``int`` + + Arguments: + + * ``PyArrayObject* ary``, a NumPy array. + + * ``npy_int* size``, an array representing the desired lengths of + each dimension. + + * ``int n``, the length of ``size``. + + Require ``ary`` to have a specified shape. If the array has the + specified shape, return 1. Otherwise, set the Python error + string and return 0. + + + **require_fortran()** + + Return type: ``int`` + + Arguments: + + * ``PyArrayObject* ary``, a NumPy array. + + Require the given ``PyArrayObject`` to to be Fortran ordered. If + the ``PyArrayObject`` is already Fortran ordered, do nothing. + Else, set the Fortran ordering flag and recompute the strides. + + +Beyond the Provided Typemaps +---------------------------- + +There are many C or C++ array/NumPy array situations not covered by +a simple ``%include "numpy.i"`` and subsequent ``%apply`` directives. + +A Common Example +```````````````` + +Consider a reasonable prototype for a dot product function:: + + double dot(int len, double* vec1, double* vec2); + +The Python interface that we want is:: + + def dot(vec1, vec2): + """ + dot(PyObject,PyObject) -> double + """ + +The problem here is that there is one dimension argument and two array +arguments, and our typemaps are set up for dimensions that apply to a +single array (in fact, `SWIG`_ does not provide a mechanism for +associating ``len`` with ``vec2`` that takes two Python input +arguments). The recommended solution is the following:: + + %apply (int DIM1, double* IN_ARRAY1) {(int len1, double* vec1), + (int len2, double* vec2)} + %rename (dot) my_dot; + %exception my_dot { + $action + if (PyErr_Occurred()) SWIG_fail; + } + %inline %{ + double my_dot(int len1, double* vec1, int len2, double* vec2) { + if (len1 != len2) { + PyErr_Format(PyExc_ValueError, + "Arrays of lengths (%d,%d) given", + len1, len2); + return 0.0; + } + return dot(len1, vec1, vec2); + } + %} + +If the header file that contains the prototype for ``double dot()`` +also contains other prototypes that you want to wrap, so that you need +to ``%include`` this header file, then you will also need a ``%ignore +dot;`` directive, placed after the ``%rename`` and before the +``%include`` directives. Or, if the function in question is a class +method, you will want to use ``%extend`` rather than ``%inline`` in +addition to ``%ignore``. + +**A note on error handling:** Note that ``my_dot`` returns a +``double`` but that it can also raise a Python error. The +resulting wrapper function will return a Python float +representation of 0.0 when the vector lengths do not match. Since +this is not ``NULL``, the Python interpreter will not know to check +for an error. For this reason, we add the ``%exception`` directive +above for ``my_dot`` to get the behavior we want (note that +``$action`` is a macro that gets expanded to a valid call to +``my_dot``). In general, you will probably want to write a `SWIG`_ +macro to perform this task. + +Other Situations +```````````````` + +There are other wrapping situations in which ``numpy.i`` may be +helpful when you encounter them. + + * In some situations, it is possible that you could use the + ``%numpy_typemaps`` macro to implement typemaps for your own + types. See the `Other Common Types: bool`_ or `Other Common + Types: complex`_ sections for examples. Another situation is if + your dimensions are of a type other than ``int`` (say ``long`` for + example):: + + %numpy_typemaps(double, NPY_DOUBLE, long) + + * You can use the code in ``numpy.i`` to write your own typemaps. + For example, if you had a five-dimensional array as a function + argument, you could cut-and-paste the appropriate four-dimensional + typemaps into your interface file. The modifications for the + fourth dimension would be trivial. + + * Sometimes, the best approach is to use the ``%extend`` directive + to define new methods for your classes (or overload existing ones) + that take a ``PyObject*`` (that either is or can be converted to a + ``PyArrayObject*``) instead of a pointer to a buffer. In this + case, the helper routines in ``numpy.i`` can be very useful. + + * Writing typemaps can be a bit nonintuitive. If you have specific + questions about writing `SWIG`_ typemaps for NumPy, the + developers of ``numpy.i`` do monitor the + `Numpy-discussion `_ and + `Swig-user `_ mail lists. + +A Final Note +```````````` + +When you use the ``%apply`` directive, as is usually necessary to use +``numpy.i``, it will remain in effect until you tell `SWIG`_ that it +shouldn't be. If the arguments to the functions or methods that you +are wrapping have common names, such as ``length`` or ``vector``, +these typemaps may get applied in situations you do not expect or +want. Therefore, it is always a good idea to add a ``%clear`` +directive after you are done with a specific typemap:: + + %apply (double* IN_ARRAY1, int DIM1) {(double* vector, int length)} + %include "my_header.h" + %clear (double* vector, int length); + +In general, you should target these typemap signatures specifically +where you want them, and then clear them after you are done. + +Summary +------- + +Out of the box, ``numpy.i`` provides typemaps that support conversion +between NumPy arrays and C arrays: + + * That can be one of 12 different scalar types: ``signed char``, + ``unsigned char``, ``short``, ``unsigned short``, ``int``, + ``unsigned int``, ``long``, ``unsigned long``, ``long long``, + ``unsigned long long``, ``float`` and ``double``. + + * That support 74 different argument signatures for each data type, + including: + + + One-dimensional, two-dimensional, three-dimensional and + four-dimensional arrays. + + + Input-only, in-place, argout, argoutview, and memory managed + argoutview behavior. + + + Hard-coded dimensions, data-buffer-then-dimensions + specification, and dimensions-then-data-buffer specification. + + + Both C-ordering ("last dimension fastest") or Fortran-ordering + ("first dimension fastest") support for 2D, 3D and 4D arrays. + +The ``numpy.i`` interface file also provides additional tools for +wrapper developers, including: + + * A `SWIG`_ macro (``%numpy_typemaps``) with three arguments for + implementing the 74 argument signatures for the user's choice of + (1) C data type, (2) NumPy data type (assuming they match), and + (3) dimension type. + + * Fourteen C macros and fifteen C functions that can be used to + write specialized typemaps, extensions, or inlined functions that + handle cases not covered by the provided typemaps. Note that the + macros and functions are coded specifically to work with the NumPy + C/API regardless of NumPy version number, both before and after + the deprecation of some aspects of the API after version 1.6. diff --git a/doc/source/reference/swig.rst b/doc/source/reference/swig.rst new file mode 100644 index 0000000..6865cc9 --- /dev/null +++ b/doc/source/reference/swig.rst @@ -0,0 +1,12 @@ +************** +NumPy and SWIG +************** + +.. sectionauthor:: Bill Spotz + + +.. toctree:: + :maxdepth: 2 + + swig.interface-file + swig.testing diff --git a/doc/source/reference/swig.testing.rst b/doc/source/reference/swig.testing.rst new file mode 100644 index 0000000..13642a5 --- /dev/null +++ b/doc/source/reference/swig.testing.rst @@ -0,0 +1,167 @@ +Testing the numpy.i Typemaps +============================ + +Introduction +------------ + +Writing tests for the ``numpy.i`` `SWIG `_ +interface file is a combinatorial headache. At present, 12 different +data types are supported, each with 74 different argument signatures, +for a total of 888 typemaps supported "out of the box". Each of these +typemaps, in turn, might require several unit tests in order to verify +expected behavior for both proper and improper inputs. Currently, +this results in more than 1,000 individual unit tests executed when +``make test`` is run in the ``numpy/tools/swig`` subdirectory. + +To facilitate this many similar unit tests, some high-level +programming techniques are employed, including C and `SWIG`_ macros, +as well as Python inheritance. The purpose of this document is to describe +the testing infrastructure employed to verify that the ``numpy.i`` +typemaps are working as expected. + +Testing Organization +-------------------- + +There are three indepedent testing frameworks supported, for one-, +two-, and three-dimensional arrays respectively. For one-dimensional +arrays, there are two C++ files, a header and a source, named:: + + Vector.h + Vector.cxx + +that contain prototypes and code for a variety of functions that have +one-dimensional arrays as function arguments. The file:: + + Vector.i + +is a `SWIG`_ interface file that defines a python module ``Vector`` +that wraps the functions in ``Vector.h`` while utilizing the typemaps +in ``numpy.i`` to correctly handle the C arrays. + +The ``Makefile`` calls ``swig`` to generate ``Vector.py`` and +``Vector_wrap.cxx``, and also executes the ``setup.py`` script that +compiles ``Vector_wrap.cxx`` and links together the extension module +``_Vector.so`` or ``_Vector.dylib``, depending on the platform. This +extension module and the proxy file ``Vector.py`` are both placed in a +subdirectory under the ``build`` directory. + +The actual testing takes place with a Python script named:: + + testVector.py + +that uses the standard Python library module ``unittest``, which +performs several tests of each function defined in ``Vector.h`` for +each data type supported. + +Two-dimensional arrays are tested in exactly the same manner. The +above description applies, but with ``Matrix`` substituted for +``Vector``. For three-dimensional tests, substitute ``Tensor`` for +``Vector``. For four-dimensional tests, substitute ``SuperTensor`` +for ``Vector``. For flat in-place array tests, substitute ``Flat`` +for ``Vector``. +For the descriptions that follow, we will reference the +``Vector`` tests, but the same information applies to ``Matrix``, +``Tensor`` and ``SuperTensor`` tests. + +The command ``make test`` will ensure that all of the test software is +built and then run all three test scripts. + +Testing Header Files +-------------------- + +``Vector.h`` is a C++ header file that defines a C macro called +``TEST_FUNC_PROTOS`` that takes two arguments: ``TYPE``, which is a +data type name such as ``unsigned int``; and ``SNAME``, which is a +short name for the same data type with no spaces, e.g. ``uint``. This +macro defines several function prototypes that have the prefix +``SNAME`` and have at least one argument that is an array of type +``TYPE``. Those functions that have return arguments return a +``TYPE`` value. + +``TEST_FUNC_PROTOS`` is then implemented for all of the data types +supported by ``numpy.i``: + + * ``signed char`` + * ``unsigned char`` + * ``short`` + * ``unsigned short`` + * ``int`` + * ``unsigned int`` + * ``long`` + * ``unsigned long`` + * ``long long`` + * ``unsigned long long`` + * ``float`` + * ``double`` + +Testing Source Files +-------------------- + +``Vector.cxx`` is a C++ source file that implements compilable code +for each of the function prototypes specified in ``Vector.h``. It +defines a C macro ``TEST_FUNCS`` that has the same arguments and works +in the same way as ``TEST_FUNC_PROTOS`` does in ``Vector.h``. +``TEST_FUNCS`` is implemented for each of the 12 data types as above. + +Testing SWIG Interface Files +---------------------------- + +``Vector.i`` is a `SWIG`_ interface file that defines python module +``Vector``. It follows the conventions for using ``numpy.i`` as +described in this chapter. It defines a `SWIG`_ macro +``%apply_numpy_typemaps`` that has a single argument ``TYPE``. +It uses the `SWIG`_ directive ``%apply`` to apply the provided +typemaps to the argument signatures found in ``Vector.h``. This macro +is then implemented for all of the data types supported by +``numpy.i``. It then does a ``%include "Vector.h"`` to wrap all of +the function prototypes in ``Vector.h`` using the typemaps in +``numpy.i``. + +Testing Python Scripts +---------------------- + +After ``make`` is used to build the testing extension modules, +``testVector.py`` can be run to execute the tests. As with other +scripts that use ``unittest`` to facilitate unit testing, +``testVector.py`` defines a class that inherits from +``unittest.TestCase``:: + + class VectorTestCase(unittest.TestCase): + +However, this class is not run directly. Rather, it serves as a base +class to several other python classes, each one specific to a +particular data type. The ``VectorTestCase`` class stores two strings +for typing information: + + **self.typeStr** + A string that matches one of the ``SNAME`` prefixes used in + ``Vector.h`` and ``Vector.cxx``. For example, ``"double"``. + + **self.typeCode** + A short (typically single-character) string that represents a + data type in numpy and corresponds to ``self.typeStr``. For + example, if ``self.typeStr`` is ``"double"``, then + ``self.typeCode`` should be ``"d"``. + +Each test defined by the ``VectorTestCase`` class extracts the python +function it is trying to test by accessing the ``Vector`` module's +dictionary:: + + length = Vector.__dict__[self.typeStr + "Length"] + +In the case of double precision tests, this will return the python +function ``Vector.doubleLength``. + +We then define a new test case class for each supported data type with +a short definition such as:: + + class doubleTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "double" + self.typeCode = "d" + +Each of these 12 classes is collected into a ``unittest.TestSuite``, +which is then executed. Errors and failures are summed together and +returned as the exit argument. Any non-zero result indicates that at +least one test did not pass. diff --git a/doc/source/reference/ufuncs.rst b/doc/source/reference/ufuncs.rst new file mode 100644 index 0000000..38f2926 --- /dev/null +++ b/doc/source/reference/ufuncs.rst @@ -0,0 +1,695 @@ +.. sectionauthor:: adapted from "Guide to NumPy" by Travis E. Oliphant + +.. _ufuncs: + +************************************ +Universal functions (:class:`ufunc`) +************************************ + +.. note: XXX: section might need to be made more reference-guideish... + +.. currentmodule:: numpy + +.. index: ufunc, universal function, arithmetic, operation + +A universal function (or :term:`ufunc` for short) is a function that +operates on :class:`ndarrays ` in an element-by-element fashion, +supporting :ref:`array broadcasting `, :ref:`type +casting `, and several other standard features. That +is, a ufunc is a ":term:`vectorized`" wrapper for a function that +takes a fixed number of specific inputs and produces a fixed number of +specific outputs. + +In NumPy, universal functions are instances of the +:class:`numpy.ufunc` class. Many of the built-in functions are +implemented in compiled C code. The basic ufuncs operate on scalars, but +there is also a generalized kind for which the basic elements are sub-arrays +(vectors, matrices, etc.), and broadcasting is done over other dimensions. +One can also produce custom :class:`ufunc` instances using the +:func:`frompyfunc` factory function. + + +.. _ufuncs.broadcasting: + +Broadcasting +============ + +.. index:: broadcasting + +Each universal function takes array inputs and produces array outputs +by performing the core function element-wise on the inputs (where an +element is generally a scalar, but can be a vector or higher-order +sub-array for generalized ufuncs). Standard +broadcasting rules are applied so that inputs not sharing exactly the +same shapes can still be usefully operated on. Broadcasting can be +understood by four rules: + +1. All input arrays with :attr:`ndim ` smaller than the + input array of largest :attr:`ndim `, have 1's + prepended to their shapes. + +2. The size in each dimension of the output shape is the maximum of all + the input sizes in that dimension. + +3. An input can be used in the calculation if its size in a particular + dimension either matches the output size in that dimension, or has + value exactly 1. + +4. If an input has a dimension size of 1 in its shape, the first data + entry in that dimension will be used for all calculations along + that dimension. In other words, the stepping machinery of the + :term:`ufunc` will simply not step along that dimension (the + :term:`stride` will be 0 for that dimension). + +Broadcasting is used throughout NumPy to decide how to handle +disparately shaped arrays; for example, all arithmetic operations (``+``, +``-``, ``*``, ...) between :class:`ndarrays ` broadcast the +arrays before operation. + +.. _arrays.broadcasting.broadcastable: + +.. index:: broadcastable + +A set of arrays is called ":term:`broadcastable`" to the same shape if +the above rules produce a valid result, *i.e.*, one of the following +is true: + +1. The arrays all have exactly the same shape. + +2. The arrays all have the same number of dimensions and the length of + each dimensions is either a common length or 1. + +3. The arrays that have too few dimensions can have their shapes prepended + with a dimension of length 1 to satisfy property 2. + +.. admonition:: Example + + If ``a.shape`` is (5,1), ``b.shape`` is (1,6), ``c.shape`` is (6,) + and ``d.shape`` is () so that *d* is a scalar, then *a*, *b*, *c*, + and *d* are all broadcastable to dimension (5,6); and + + - *a* acts like a (5,6) array where ``a[:,0]`` is broadcast to the other + columns, + + - *b* acts like a (5,6) array where ``b[0,:]`` is broadcast + to the other rows, + + - *c* acts like a (1,6) array and therefore like a (5,6) array + where ``c[:]`` is broadcast to every row, and finally, + + - *d* acts like a (5,6) array where the single value is repeated. + + +.. _ufuncs.output-type: + +Output type determination +========================= + +The output of the ufunc (and its methods) is not necessarily an +:class:`ndarray`, if all input arguments are not :class:`ndarrays `. +Indeed, if any input defines an :obj:`~class.__array_ufunc__` method, +control will be passed completely to that function, i.e., the ufunc is +`overridden `_. + +If none of the inputs overrides the ufunc, then +all output arrays will be passed to the :obj:`~class.__array_prepare__` and +:obj:`~class.__array_wrap__` methods of the input (besides +:class:`ndarrays `, and scalars) that defines it **and** has +the highest :obj:`~class.__array_priority__` of any other input to the +universal function. The default :obj:`~class.__array_priority__` of the +ndarray is 0.0, and the default :obj:`~class.__array_priority__` of a subtype +is 1.0. Matrices have :obj:`~class.__array_priority__` equal to 10.0. + +All ufuncs can also take output arguments. If necessary, output will +be cast to the data-type(s) of the provided output array(s). If a class +with an :obj:`~class.__array__` method is used for the output, results will be +written to the object returned by :obj:`~class.__array__`. Then, if the class +also has an :obj:`~class.__array_prepare__` method, it is called so metadata +may be determined based on the context of the ufunc (the context +consisting of the ufunc itself, the arguments passed to the ufunc, and +the ufunc domain.) The array object returned by +:obj:`~class.__array_prepare__` is passed to the ufunc for computation. +Finally, if the class also has an :obj:`~class.__array_wrap__` method, the returned +:class:`ndarray` result will be passed to that method just before +passing control back to the caller. + +Use of internal buffers +======================= + +.. index:: buffers + +Internally, buffers are used for misaligned data, swapped data, and +data that has to be converted from one data type to another. The size +of internal buffers is settable on a per-thread basis. There can +be up to :math:`2 (n_{\mathrm{inputs}} + n_{\mathrm{outputs}})` +buffers of the specified size created to handle the data from all the +inputs and outputs of a ufunc. The default size of a buffer is +10,000 elements. Whenever buffer-based calculation would be needed, +but all input arrays are smaller than the buffer size, those +misbehaved or incorrectly-typed arrays will be copied before the +calculation proceeds. Adjusting the size of the buffer may therefore +alter the speed at which ufunc calculations of various sorts are +completed. A simple interface for setting this variable is accessible +using the function + +.. autosummary:: + :toctree: generated/ + + setbufsize + + +Error handling +============== + +.. index:: error handling + +Universal functions can trip special floating-point status registers +in your hardware (such as divide-by-zero). If available on your +platform, these registers will be regularly checked during +calculation. Error handling is controlled on a per-thread basis, +and can be configured using the functions + +.. autosummary:: + :toctree: generated/ + + seterr + seterrcall + +.. _ufuncs.casting: + +Casting Rules +============= + +.. index:: + pair: ufunc; casting rules + +.. note:: + + In NumPy 1.6.0, a type promotion API was created to encapsulate the + mechanism for determining output types. See the functions + :func:`result_type`, :func:`promote_types`, and + :func:`min_scalar_type` for more details. + +At the core of every ufunc is a one-dimensional strided loop that +implements the actual function for a specific type combination. When a +ufunc is created, it is given a static list of inner loops and a +corresponding list of type signatures over which the ufunc operates. +The ufunc machinery uses this list to determine which inner loop to +use for a particular case. You can inspect the :attr:`.types +` attribute for a particular ufunc to see which type +combinations have a defined inner loop and which output type they +produce (:ref:`character codes ` are used +in said output for brevity). + +Casting must be done on one or more of the inputs whenever the ufunc +does not have a core loop implementation for the input types provided. +If an implementation for the input types cannot be found, then the +algorithm searches for an implementation with a type signature to +which all of the inputs can be cast "safely." The first one it finds +in its internal list of loops is selected and performed, after all +necessary type casting. Recall that internal copies during ufuncs (even +for casting) are limited to the size of an internal buffer (which is user +settable). + +.. note:: + + Universal functions in NumPy are flexible enough to have mixed type + signatures. Thus, for example, a universal function could be defined + that works with floating-point and integer values. See :func:`ldexp` + for an example. + +By the above description, the casting rules are essentially +implemented by the question of when a data type can be cast "safely" +to another data type. The answer to this question can be determined in +Python with a function call: :func:`can_cast(fromtype, totype) +`. The Figure below shows the results of this call for +the 24 internally supported types on the author's 64-bit system. You +can generate this table for your system with the code given in the Figure. + +.. admonition:: Figure + + Code segment showing the "can cast safely" table for a 32-bit system. + + >>> def print_table(ntypes): + ... print 'X', + ... for char in ntypes: print char, + ... print + ... for row in ntypes: + ... print row, + ... for col in ntypes: + ... print int(np.can_cast(row, col)), + ... print + >>> print_table(np.typecodes['All']) + X ? b h i l q p B H I L Q P e f d g F D G S U V O M m + ? 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + b 0 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 + h 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 + i 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + l 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + q 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + p 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + B 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 + H 0 0 0 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 0 + I 0 0 0 0 1 1 1 0 0 1 1 1 1 0 0 1 1 0 1 1 1 1 1 1 0 0 + L 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 0 0 + Q 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 0 0 + P 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 0 0 + e 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 + f 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 + d 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 0 + g 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 1 1 0 0 + F 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 + D 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 + G 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 + S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 + U 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 + V 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 + O 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 + M 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 + m 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 1 + + +You should note that, while included in the table for completeness, +the 'S', 'U', and 'V' types cannot be operated on by ufuncs. Also, +note that on a 32-bit system the integer types may have different +sizes, resulting in a slightly altered table. + +Mixed scalar-array operations use a different set of casting rules +that ensure that a scalar cannot "upcast" an array unless the scalar is +of a fundamentally different kind of data (*i.e.*, under a different +hierarchy in the data-type hierarchy) than the array. This rule +enables you to use scalar constants in your code (which, as Python +types, are interpreted accordingly in ufuncs) without worrying about +whether the precision of the scalar constant will cause upcasting on +your large (small precision) array. + + +.. _ufuncs.overrides: + +Overriding Ufunc behavior +========================= + +Classes (including ndarray subclasses) can override how ufuncs act on +them by defining certain special methods. For details, see +:ref:`arrays.classes`. + + +:class:`ufunc` +============== + +.. _ufuncs.kwargs: + +Optional keyword arguments +-------------------------- + +All ufuncs take optional keyword arguments. Most of these represent +advanced usage and will not typically be used. + +.. index:: + pair: ufunc; keyword arguments + +*out* + + .. versionadded:: 1.6 + + The first output can be provided as either a positional or a keyword + parameter. Keyword 'out' arguments are incompatible with positional + ones. + + .. versionadded:: 1.10 + + The 'out' keyword argument is expected to be a tuple with one entry per + output (which can be `None` for arrays to be allocated by the ufunc). + For ufuncs with a single output, passing a single array (instead of a + tuple holding a single array) is also valid. + + Passing a single array in the 'out' keyword argument to a ufunc with + multiple outputs is deprecated, and will raise a warning in numpy 1.10, + and an error in a future release. + +*where* + + .. versionadded:: 1.7 + + Accepts a boolean array which is broadcast together with the operands. + Values of True indicate to calculate the ufunc at that position, values + of False indicate to leave the value in the output alone. This argument + cannot be used for generalized ufuncs as those take non-scalar input. + +*casting* + + .. versionadded:: 1.6 + + May be 'no', 'equiv', 'safe', 'same_kind', or 'unsafe'. + See :func:`can_cast` for explanations of the parameter values. + + Provides a policy for what kind of casting is permitted. For compatibility + with previous versions of NumPy, this defaults to 'unsafe' for numpy < 1.7. + In numpy 1.7 a transition to 'same_kind' was begun where ufuncs produce a + DeprecationWarning for calls which are allowed under the 'unsafe' + rules, but not under the 'same_kind' rules. From numpy 1.10 and + onwards, the default is 'same_kind'. + +*order* + + .. versionadded:: 1.6 + + Specifies the calculation iteration order/memory layout of the output array. + Defaults to 'K'. 'C' means the output should be C-contiguous, 'F' means + F-contiguous, 'A' means F-contiguous if the inputs are F-contiguous and + not also not C-contiguous, C-contiguous otherwise, and 'K' means to match + the element ordering of the inputs as closely as possible. + +*dtype* + + .. versionadded:: 1.6 + + Overrides the dtype of the calculation and output arrays. Similar to + *signature*. + +*subok* + + .. versionadded:: 1.6 + + Defaults to true. If set to false, the output will always be a strict + array, not a subtype. + +*signature* + + Either a data-type, a tuple of data-types, or a special signature + string indicating the input and output types of a ufunc. This argument + allows you to provide a specific signature for the 1-d loop to use + in the underlying calculation. If the loop specified does not exist + for the ufunc, then a TypeError is raised. Normally, a suitable loop is + found automatically by comparing the input types with what is + available and searching for a loop with data-types to which all inputs + can be cast safely. This keyword argument lets you bypass that + search and choose a particular loop. A list of available signatures is + provided by the **types** attribute of the ufunc object. For backwards + compatibility this argument can also be provided as *sig*, although + the long form is preferred. Note that this should not be confused with + the generalized ufunc signature that is stored in the **signature** + attribute of the of the ufunc object. + +*extobj* + + a list of length 1, 2, or 3 specifying the ufunc buffer-size, the + error mode integer, and the error call-back function. Normally, these + values are looked up in a thread-specific dictionary. Passing them + here circumvents that look up and uses the low-level specification + provided for the error mode. This may be useful, for example, as an + optimization for calculations requiring many ufunc calls on small arrays + in a loop. + + + +Attributes +---------- + +There are some informational attributes that universal functions +possess. None of the attributes can be set. + +.. index:: + pair: ufunc; attributes + + +============ ================================================================= +**__doc__** A docstring for each ufunc. The first part of the docstring is + dynamically generated from the number of outputs, the name, and + the number of inputs. The second part of the docstring is + provided at creation time and stored with the ufunc. + +**__name__** The name of the ufunc. +============ ================================================================= + +.. autosummary:: + :toctree: generated/ + + ufunc.nin + ufunc.nout + ufunc.nargs + ufunc.ntypes + ufunc.types + ufunc.identity + ufunc.signature + +.. _ufuncs.methods: + +Methods +------- + +All ufuncs have four methods. However, these methods only make sense on scalar +ufuncs that take two input arguments and return one output argument. +Attempting to call these methods on other ufuncs will cause a +:exc:`ValueError`. The reduce-like methods all take an *axis* keyword, a *dtype* +keyword, and an *out* keyword, and the arrays must all have dimension >= 1. +The *axis* keyword specifies the axis of the array over which the reduction +will take place (with negative values counting backwards). Generally, it is an +integer, though for :meth:`ufunc.reduce`, it can also be a tuple of `int` to +reduce over several axes at once, or `None`, to reduce over all axes. +The *dtype* keyword allows you to manage a very common problem that arises +when naively using :meth:`ufunc.reduce`. Sometimes you may +have an array of a certain data type and wish to add up all of its +elements, but the result does not fit into the data type of the +array. This commonly happens if you have an array of single-byte +integers. The *dtype* keyword allows you to alter the data type over which +the reduction takes place (and therefore the type of the output). Thus, +you can ensure that the output is a data type with precision large enough +to handle your output. The responsibility of altering the reduce type is +mostly up to you. There is one exception: if no *dtype* is given for a +reduction on the "add" or "multiply" operations, then if the input type is +an integer (or Boolean) data-type and smaller than the size of the +:class:`int_` data type, it will be internally upcast to the :class:`int_` +(or :class:`uint`) data-type. Finally, the *out* keyword allows you to provide +an output array (for single-output ufuncs, which are currently the only ones +supported; for future extension, however, a tuple with a single argument +can be passed in). If *out* is given, the *dtype* argument is ignored. + +Ufuncs also have a fifth method that allows in place operations to be +performed using fancy indexing. No buffering is used on the dimensions where +fancy indexing is used, so the fancy index can list an item more than once and +the operation will be performed on the result of the previous operation for +that item. + +.. index:: + pair: ufunc; methods + +.. autosummary:: + :toctree: generated/ + + ufunc.reduce + ufunc.accumulate + ufunc.reduceat + ufunc.outer + ufunc.at + + +.. warning:: + + A reduce-like operation on an array with a data-type that has a + range "too small" to handle the result will silently wrap. One + should use `dtype` to increase the size of the data-type over which + reduction takes place. + + +Available ufuncs +================ + +There are currently more than 60 universal functions defined in +:mod:`numpy` on one or more types, covering a wide variety of +operations. Some of these ufuncs are called automatically on arrays +when the relevant infix notation is used (*e.g.*, :func:`add(a, b) ` +is called internally when ``a + b`` is written and *a* or *b* is an +:class:`ndarray`). Nevertheless, you may still want to use the ufunc +call in order to use the optional output argument(s) to place the +output(s) in an object (or objects) of your choice. + +Recall that each ufunc operates element-by-element. Therefore, each scalar +ufunc will be described as if acting on a set of scalar inputs to +return a set of scalar outputs. + +.. note:: + + The ufunc still returns its output(s) even if you use the optional + output argument(s). + +Math operations +--------------- + +.. autosummary:: + + add + subtract + multiply + divide + logaddexp + logaddexp2 + true_divide + floor_divide + negative + positive + power + remainder + mod + fmod + divmod + absolute + fabs + rint + sign + heaviside + conj + exp + exp2 + log + log2 + log10 + expm1 + log1p + sqrt + square + cbrt + reciprocal + +.. tip:: + + The optional output arguments can be used to help you save memory + for large calculations. If your arrays are large, complicated + expressions can take longer than absolutely necessary due to the + creation and (later) destruction of temporary calculation + spaces. For example, the expression ``G = a * b + c`` is equivalent to + ``t1 = A * B; G = T1 + C; del t1``. It will be more quickly executed + as ``G = A * B; add(G, C, G)`` which is the same as + ``G = A * B; G += C``. + + +Trigonometric functions +----------------------- +All trigonometric functions use radians when an angle is called for. +The ratio of degrees to radians is :math:`180^{\circ}/\pi.` + +.. autosummary:: + + sin + cos + tan + arcsin + arccos + arctan + arctan2 + hypot + sinh + cosh + tanh + arcsinh + arccosh + arctanh + deg2rad + rad2deg + +Bit-twiddling functions +----------------------- + +These function all require integer arguments and they manipulate the +bit-pattern of those arguments. + +.. autosummary:: + + bitwise_and + bitwise_or + bitwise_xor + invert + left_shift + right_shift + +Comparison functions +-------------------- + +.. autosummary:: + + greater + greater_equal + less + less_equal + not_equal + equal + +.. warning:: + + Do not use the Python keywords ``and`` and ``or`` to combine + logical array expressions. These keywords will test the truth + value of the entire array (not element-by-element as you might + expect). Use the bitwise operators & and \| instead. + +.. autosummary:: + + logical_and + logical_or + logical_xor + logical_not + +.. warning:: + + The bit-wise operators & and \| are the proper way to perform + element-by-element array comparisons. Be sure you understand the + operator precedence: ``(a > 2) & (a < 5)`` is the proper syntax because + ``a > 2 & a < 5`` will result in an error due to the fact that ``2 & a`` + is evaluated first. + +.. autosummary:: + + maximum + +.. tip:: + + The Python function ``max()`` will find the maximum over a one-dimensional + array, but it will do so using a slower sequence interface. The reduce + method of the maximum ufunc is much faster. Also, the ``max()`` method + will not give answers you might expect for arrays with greater than + one dimension. The reduce method of minimum also allows you to compute + a total minimum over an array. + +.. autosummary:: + + minimum + +.. warning:: + + the behavior of ``maximum(a, b)`` is different than that of ``max(a, b)``. + As a ufunc, ``maximum(a, b)`` performs an element-by-element comparison + of `a` and `b` and chooses each element of the result according to which + element in the two arrays is larger. In contrast, ``max(a, b)`` treats + the objects `a` and `b` as a whole, looks at the (total) truth value of + ``a > b`` and uses it to return either `a` or `b` (as a whole). A similar + difference exists between ``minimum(a, b)`` and ``min(a, b)``. + +.. autosummary:: + + fmax + fmin + +Floating functions +------------------ + +Recall that all of these functions work element-by-element over an +array, returning an array output. The description details only a +single operation. + +.. autosummary:: + + isfinite + isinf + isnan + isnat + fabs + signbit + copysign + nextafter + spacing + modf + ldexp + frexp + fmod + floor + ceil + trunc diff --git a/doc/source/release.rst b/doc/source/release.rst new file mode 100644 index 0000000..507a166 --- /dev/null +++ b/doc/source/release.rst @@ -0,0 +1,37 @@ +************* +Release Notes +************* + +.. include:: ../release/1.14.2-notes.rst +.. include:: ../release/1.14.1-notes.rst +.. include:: ../release/1.14.0-notes.rst +.. include:: ../release/1.13.3-notes.rst +.. include:: ../release/1.13.2-notes.rst +.. include:: ../release/1.13.1-notes.rst +.. include:: ../release/1.13.0-notes.rst +.. include:: ../release/1.12.1-notes.rst +.. include:: ../release/1.12.0-notes.rst +.. include:: ../release/1.11.3-notes.rst +.. include:: ../release/1.11.2-notes.rst +.. include:: ../release/1.11.1-notes.rst +.. include:: ../release/1.11.0-notes.rst +.. include:: ../release/1.10.4-notes.rst +.. include:: ../release/1.10.3-notes.rst +.. include:: ../release/1.10.2-notes.rst +.. include:: ../release/1.10.1-notes.rst +.. include:: ../release/1.10.0-notes.rst +.. include:: ../release/1.9.2-notes.rst +.. include:: ../release/1.9.1-notes.rst +.. include:: ../release/1.9.0-notes.rst +.. include:: ../release/1.8.2-notes.rst +.. include:: ../release/1.8.1-notes.rst +.. include:: ../release/1.8.0-notes.rst +.. include:: ../release/1.7.2-notes.rst +.. include:: ../release/1.7.1-notes.rst +.. include:: ../release/1.7.0-notes.rst +.. include:: ../release/1.6.2-notes.rst +.. include:: ../release/1.6.1-notes.rst +.. include:: ../release/1.6.0-notes.rst +.. include:: ../release/1.5.0-notes.rst +.. include:: ../release/1.4.0-notes.rst +.. include:: ../release/1.3.0-notes.rst diff --git a/doc/source/user/basics.broadcasting.rst b/doc/source/user/basics.broadcasting.rst new file mode 100644 index 0000000..65584b1 --- /dev/null +++ b/doc/source/user/basics.broadcasting.rst @@ -0,0 +1,7 @@ +************ +Broadcasting +************ + +.. seealso:: :class:`numpy.broadcast` + +.. automodule:: numpy.doc.broadcasting diff --git a/doc/source/user/basics.byteswapping.rst b/doc/source/user/basics.byteswapping.rst new file mode 100644 index 0000000..4b1008d --- /dev/null +++ b/doc/source/user/basics.byteswapping.rst @@ -0,0 +1,5 @@ +************* +Byte-swapping +************* + +.. automodule:: numpy.doc.byteswapping diff --git a/doc/source/user/basics.creation.rst b/doc/source/user/basics.creation.rst new file mode 100644 index 0000000..b3fa810 --- /dev/null +++ b/doc/source/user/basics.creation.rst @@ -0,0 +1,9 @@ +.. _arrays.creation: + +************** +Array creation +************** + +.. seealso:: :ref:`Array creation routines ` + +.. automodule:: numpy.doc.creation diff --git a/doc/source/user/basics.indexing.rst b/doc/source/user/basics.indexing.rst new file mode 100644 index 0000000..8844adc --- /dev/null +++ b/doc/source/user/basics.indexing.rst @@ -0,0 +1,9 @@ +.. _basics.indexing: + +******** +Indexing +******** + +.. seealso:: :ref:`Indexing routines ` + +.. automodule:: numpy.doc.indexing diff --git a/doc/source/user/basics.io.genfromtxt.rst b/doc/source/user/basics.io.genfromtxt.rst new file mode 100644 index 0000000..2bdd5a0 --- /dev/null +++ b/doc/source/user/basics.io.genfromtxt.rst @@ -0,0 +1,533 @@ +.. sectionauthor:: Pierre Gerard-Marchant + +********************************************* +Importing data with :func:`~numpy.genfromtxt` +********************************************* + +NumPy provides several functions to create arrays from tabular data. +We focus here on the :func:`~numpy.genfromtxt` function. + +In a nutshell, :func:`~numpy.genfromtxt` runs two main loops. The first +loop converts each line of the file in a sequence of strings. The second +loop converts each string to the appropriate data type. This mechanism is +slower than a single loop, but gives more flexibility. In particular, +:func:`~numpy.genfromtxt` is able to take missing data into account, when +other faster and simpler functions like :func:`~numpy.loadtxt` cannot. + +.. note:: + + When giving examples, we will use the following conventions:: + + >>> import numpy as np + >>> from io import BytesIO + + + +Defining the input +================== + +The only mandatory argument of :func:`~numpy.genfromtxt` is the source of +the data. It can be a string, a list of strings, or a generator. If a +single string is provided, it is assumed to be the name of a local or +remote file, or an open file-like object with a :meth:`read` method, for +example, a file or :class:`StringIO.StringIO` object. If a list of strings +or a generator returning strings is provided, each string is treated as one +line in a file. When the URL of a remote file is passed, the file is +automatically downloaded to the current directory and opened. + +Recognized file types are text files and archives. Currently, the function +recognizes :class:`gzip` and :class:`bz2` (`bzip2`) archives. The type of +the archive is determined from the extension of the file: if the filename +ends with ``'.gz'``, a :class:`gzip` archive is expected; if it ends with +``'bz2'``, a :class:`bzip2` archive is assumed. + + + +Splitting the lines into columns +================================ + +The ``delimiter`` argument +-------------------------- + +Once the file is defined and open for reading, :func:`~numpy.genfromtxt` +splits each non-empty line into a sequence of strings. Empty or commented +lines are just skipped. The ``delimiter`` keyword is used to define +how the splitting should take place. + +Quite often, a single character marks the separation between columns. For +example, comma-separated files (CSV) use a comma (``,``) or a semicolon +(``;``) as delimiter:: + + >>> data = "1, 2, 3\n4, 5, 6" + >>> np.genfromtxt(BytesIO(data), delimiter=",") + array([[ 1., 2., 3.], + [ 4., 5., 6.]]) + +Another common separator is ``"\t"``, the tabulation character. However, +we are not limited to a single character, any string will do. By default, +:func:`~numpy.genfromtxt` assumes ``delimiter=None``, meaning that the line +is split along white spaces (including tabs) and that consecutive white +spaces are considered as a single white space. + +Alternatively, we may be dealing with a fixed-width file, where columns are +defined as a given number of characters. In that case, we need to set +``delimiter`` to a single integer (if all the columns have the same +size) or to a sequence of integers (if columns can have different sizes):: + + >>> data = " 1 2 3\n 4 5 67\n890123 4" + >>> np.genfromtxt(BytesIO(data), delimiter=3) + array([[ 1., 2., 3.], + [ 4., 5., 67.], + [ 890., 123., 4.]]) + >>> data = "123456789\n 4 7 9\n 4567 9" + >>> np.genfromtxt(BytesIO(data), delimiter=(4, 3, 2)) + array([[ 1234., 567., 89.], + [ 4., 7., 9.], + [ 4., 567., 9.]]) + + +The ``autostrip`` argument +-------------------------- + +By default, when a line is decomposed into a series of strings, the +individual entries are not stripped of leading nor trailing white spaces. +This behavior can be overwritten by setting the optional argument +``autostrip`` to a value of ``True``:: + + >>> data = "1, abc , 2\n 3, xxx, 4" + >>> # Without autostrip + >>> np.genfromtxt(BytesIO(data), delimiter=",", dtype="|U5") + array([['1', ' abc ', ' 2'], + ['3', ' xxx', ' 4']], + dtype='|U5') + >>> # With autostrip + >>> np.genfromtxt(BytesIO(data), delimiter=",", dtype="|U5", autostrip=True) + array([['1', 'abc', '2'], + ['3', 'xxx', '4']], + dtype='|U5') + + +The ``comments`` argument +------------------------- + +The optional argument ``comments`` is used to define a character +string that marks the beginning of a comment. By default, +:func:`~numpy.genfromtxt` assumes ``comments='#'``. The comment marker may +occur anywhere on the line. Any character present after the comment +marker(s) is simply ignored:: + + >>> data = """# + ... # Skip me ! + ... # Skip me too ! + ... 1, 2 + ... 3, 4 + ... 5, 6 #This is the third line of the data + ... 7, 8 + ... # And here comes the last line + ... 9, 0 + ... """ + >>> np.genfromtxt(BytesIO(data), comments="#", delimiter=",") + [[ 1. 2.] + [ 3. 4.] + [ 5. 6.] + [ 7. 8.] + [ 9. 0.]] + +.. note:: + + There is one notable exception to this behavior: if the optional argument + ``names=True``, the first commented line will be examined for names. + + + +Skipping lines and choosing columns +=================================== + +The ``skip_header`` and ``skip_footer`` arguments +--------------------------------------------------------------- + +The presence of a header in the file can hinder data processing. In that +case, we need to use the ``skip_header`` optional argument. The +values of this argument must be an integer which corresponds to the number +of lines to skip at the beginning of the file, before any other action is +performed. Similarly, we can skip the last ``n`` lines of the file by +using the ``skip_footer`` attribute and giving it a value of ``n``:: + + >>> data = "\n".join(str(i) for i in range(10)) + >>> np.genfromtxt(BytesIO(data),) + array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) + >>> np.genfromtxt(BytesIO(data), + ... skip_header=3, skip_footer=5) + array([ 3., 4.]) + +By default, ``skip_header=0`` and ``skip_footer=0``, meaning that no lines +are skipped. + + +The ``usecols`` argument +------------------------ + +In some cases, we are not interested in all the columns of the data but +only a few of them. We can select which columns to import with the +``usecols`` argument. This argument accepts a single integer or a +sequence of integers corresponding to the indices of the columns to import. +Remember that by convention, the first column has an index of 0. Negative +integers behave the same as regular Python negative indexes. + +For example, if we want to import only the first and the last columns, we +can use ``usecols=(0, -1)``:: + + >>> data = "1 2 3\n4 5 6" + >>> np.genfromtxt(BytesIO(data), usecols=(0, -1)) + array([[ 1., 3.], + [ 4., 6.]]) + +If the columns have names, we can also select which columns to import by +giving their name to the ``usecols`` argument, either as a sequence +of strings or a comma-separated string:: + + >>> data = "1 2 3\n4 5 6" + >>> np.genfromtxt(BytesIO(data), + ... names="a, b, c", usecols=("a", "c")) + array([(1.0, 3.0), (4.0, 6.0)], + dtype=[('a', '>> np.genfromtxt(BytesIO(data), + ... names="a, b, c", usecols=("a, c")) + array([(1.0, 3.0), (4.0, 6.0)], + dtype=[('a', '>> data = BytesIO("1 2 3\n 4 5 6") + >>> np.genfromtxt(data, dtype=[(_, int) for _ in "abc"]) + array([(1, 2, 3), (4, 5, 6)], + dtype=[('a', '>> data = BytesIO("1 2 3\n 4 5 6") + >>> np.genfromtxt(data, names="A, B, C") + array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], + dtype=[('A', '>> data = BytesIO("So it goes\n#a b c\n1 2 3\n 4 5 6") + >>> np.genfromtxt(data, skip_header=1, names=True) + array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], + dtype=[('a', '>> data = BytesIO("1 2 3\n 4 5 6") + >>> ndtype=[('a',int), ('b', float), ('c', int)] + >>> names = ["A", "B", "C"] + >>> np.genfromtxt(data, names=names, dtype=ndtype) + array([(1, 2.0, 3), (4, 5.0, 6)], + dtype=[('A', '>> data = BytesIO("1 2 3\n 4 5 6") + >>> np.genfromtxt(data, dtype=(int, float, int)) + array([(1, 2.0, 3), (4, 5.0, 6)], + dtype=[('f0', '>> data = BytesIO("1 2 3\n 4 5 6") + >>> np.genfromtxt(data, dtype=(int, float, int), names="a") + array([(1, 2.0, 3), (4, 5.0, 6)], + dtype=[('a', '>> data = BytesIO("1 2 3\n 4 5 6") + >>> np.genfromtxt(data, dtype=(int, float, int), defaultfmt="var_%02i") + array([(1, 2.0, 3), (4, 5.0, 6)], + dtype=[('var_00', ',<``. + ``excludelist`` + Gives a list of the names to exclude, such as ``return``, ``file``, + ``print``... If one of the input name is part of this list, an + underscore character (``'_'``) will be appended to it. + ``case_sensitive`` + Whether the names should be case-sensitive (``case_sensitive=True``), + converted to upper case (``case_sensitive=False`` or + ``case_sensitive='upper'``) or to lower case + (``case_sensitive='lower'``). + + + +Tweaking the conversion +======================= + +The ``converters`` argument +--------------------------- + +Usually, defining a dtype is sufficient to define how the sequence of +strings must be converted. However, some additional control may sometimes +be required. For example, we may want to make sure that a date in a format +``YYYY/MM/DD`` is converted to a :class:`datetime` object, or that a string +like ``xx%`` is properly converted to a float between 0 and 1. In such +cases, we should define conversion functions with the ``converters`` +arguments. + +The value of this argument is typically a dictionary with column indices or +column names as keys and a conversion functions as values. These +conversion functions can either be actual functions or lambda functions. In +any case, they should accept only a string as input and output only a +single element of the wanted type. + +In the following example, the second column is converted from as string +representing a percentage to a float between 0 and 1:: + + >>> convertfunc = lambda x: float(x.strip("%"))/100. + >>> data = "1, 2.3%, 45.\n6, 78.9%, 0" + >>> names = ("i", "p", "n") + >>> # General case ..... + >>> np.genfromtxt(BytesIO(data), delimiter=",", names=names) + array([(1.0, nan, 45.0), (6.0, nan, 0.0)], + dtype=[('i', '>> # Converted case ... + >>> np.genfromtxt(BytesIO(data), delimiter=",", names=names, + ... converters={1: convertfunc}) + array([(1.0, 0.023, 45.0), (6.0, 0.78900000000000003, 0.0)], + dtype=[('i', '>> # Using a name for the converter ... + >>> np.genfromtxt(BytesIO(data), delimiter=",", names=names, + ... converters={"p": convertfunc}) + array([(1.0, 0.023, 45.0), (6.0, 0.78900000000000003, 0.0)], + dtype=[('i', '>> data = "1, , 3\n 4, 5, 6" + >>> convert = lambda x: float(x.strip() or -999) + >>> np.genfromtxt(BytesIO(data), delimiter=",", + ... converters={1: convert}) + array([[ 1., -999., 3.], + [ 4., 5., 6.]]) + + + + +Using missing and filling values +-------------------------------- + +Some entries may be missing in the dataset we are trying to import. In a +previous example, we used a converter to transform an empty string into a +float. However, user-defined converters may rapidly become cumbersome to +manage. + +The :func:`~nummpy.genfromtxt` function provides two other complementary +mechanisms: the ``missing_values`` argument is used to recognize +missing data and a second argument, ``filling_values``, is used to +process these missing data. + +``missing_values`` +------------------ + +By default, any empty string is marked as missing. We can also consider +more complex strings, such as ``"N/A"`` or ``"???"`` to represent missing +or invalid data. The ``missing_values`` argument accepts three kind +of values: + + a string or a comma-separated string + This string will be used as the marker for missing data for all the + columns + a sequence of strings + In that case, each item is associated to a column, in order. + a dictionary + Values of the dictionary are strings or sequence of strings. The + corresponding keys can be column indices (integers) or column names + (strings). In addition, the special key ``None`` can be used to + define a default applicable to all columns. + + +``filling_values`` +------------------ + +We know how to recognize missing data, but we still need to provide a value +for these missing entries. By default, this value is determined from the +expected dtype according to this table: + +============= ============== +Expected type Default +============= ============== +``bool`` ``False`` +``int`` ``-1`` +``float`` ``np.nan`` +``complex`` ``np.nan+0j`` +``string`` ``'???'`` +============= ============== + +We can get a finer control on the conversion of missing values with the +``filling_values`` optional argument. Like +``missing_values``, this argument accepts different kind of values: + + a single value + This will be the default for all columns + a sequence of values + Each entry will be the default for the corresponding column + a dictionary + Each key can be a column index or a column name, and the + corresponding value should be a single object. We can use the + special key ``None`` to define a default for all columns. + +In the following example, we suppose that the missing values are flagged +with ``"N/A"`` in the first column and by ``"???"`` in the third column. +We wish to transform these missing values to 0 if they occur in the first +and second column, and to -999 if they occur in the last column:: + + >>> data = "N/A, 2, 3\n4, ,???" + >>> kwargs = dict(delimiter=",", + ... dtype=int, + ... names="a,b,c", + ... missing_values={0:"N/A", 'b':" ", 2:"???"}, + ... filling_values={0:0, 'b':0, 2:-999}) + >>> np.genfromtxt(BytesIO(data), **kwargs) + array([(0, 2, 3), (4, 0, -999)], + dtype=[('a', '` + +.. automodule:: numpy.doc.basics diff --git a/doc/source/user/building.rst b/doc/source/user/building.rst new file mode 100644 index 0000000..b98f89c --- /dev/null +++ b/doc/source/user/building.rst @@ -0,0 +1,145 @@ +.. _building-from-source: + +Building from source +==================== + +A general overview of building NumPy from source is given here, with detailed +instructions for specific platforms given separately. + +Prerequisites +------------- + +Building NumPy requires the following software installed: + +1) Python 2.7.x, 3.4.x or newer + + On Debian and derivatives (Ubuntu): python, python-dev (or python3-dev) + + On Windows: the official python installer at + `www.python.org `_ is enough + + Make sure that the Python package distutils is installed before + continuing. For example, in Debian GNU/Linux, installing python-dev + also installs distutils. + + Python must also be compiled with the zlib module enabled. This is + practically always the case with pre-packaged Pythons. + +2) Compilers + + To build any extension modules for Python, you'll need a C compiler. + Various NumPy modules use FORTRAN 77 libraries, so you'll also need a + FORTRAN 77 compiler installed. + + Note that NumPy is developed mainly using GNU compilers. Compilers from + other vendors such as Intel, Absoft, Sun, NAG, Compaq, Vast, Portland, + Lahey, HP, IBM, Microsoft are only supported in the form of community + feedback, and may not work out of the box. GCC 4.x (and later) compilers + are recommended. + +3) Linear Algebra libraries + + NumPy does not require any external linear algebra libraries to be + installed. However, if these are available, NumPy's setup script can detect + them and use them for building. A number of different LAPACK library setups + can be used, including optimized LAPACK libraries such as ATLAS, MKL or the + Accelerate/vecLib framework on OS X. + +4) Cython + + To build development versions of NumPy, you'll need a recent version of + Cython. Released NumPy sources on PyPi include the C files generated from + Cython code, so for released versions having Cython installed isn't needed. + +Basic Installation +------------------ + +To install NumPy run:: + + python setup.py install + +To perform an in-place build that can be run from the source folder run:: + + python setup.py build_ext --inplace + +The NumPy build system uses ``setuptools`` (from numpy 1.11.0, before that it +was plain ``distutils``) and ``numpy.distutils``. +Using ``virtualenv`` should work as expected. + +*Note: for build instructions to do development work on NumPy itself, see* +:ref:`development-environment`. + +.. _parallel-builds: + +Parallel builds +~~~~~~~~~~~~~~~ + +From NumPy 1.10.0 on it's also possible to do a parallel build with:: + + python setup.py build -j 4 install --prefix $HOME/.local + +This will compile numpy on 4 CPUs and install it into the specified prefix. +to perform a parallel in-place build, run:: + + python setup.py build_ext --inplace -j 4 + +The number of build jobs can also be specified via the environment variable +``NPY_NUM_BUILD_JOBS``. + + +FORTRAN ABI mismatch +-------------------- + +The two most popular open source fortran compilers are g77 and gfortran. +Unfortunately, they are not ABI compatible, which means that concretely you +should avoid mixing libraries built with one with another. In particular, if +your blas/lapack/atlas is built with g77, you *must* use g77 when building +numpy and scipy; on the contrary, if your atlas is built with gfortran, you +*must* build numpy/scipy with gfortran. This applies for most other cases +where different FORTRAN compilers might have been used. + +Choosing the fortran compiler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To build with gfortran:: + + python setup.py build --fcompiler=gnu95 + +For more information see:: + + python setup.py build --help-fcompiler + +How to check the ABI of blas/lapack/atlas +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One relatively simple and reliable way to check for the compiler used to build +a library is to use ldd on the library. If libg2c.so is a dependency, this +means that g77 has been used. If libgfortran.so is a dependency, gfortran +has been used. If both are dependencies, this means both have been used, which +is almost always a very bad idea. + +Disabling ATLAS and other accelerated libraries +----------------------------------------------- + +Usage of ATLAS and other accelerated libraries in NumPy can be disabled +via:: + + BLAS=None LAPACK=None ATLAS=None python setup.py build + + +Supplying additional compiler flags +----------------------------------- + +Additional compiler flags can be supplied by setting the ``OPT``, +``FOPT`` (for Fortran), and ``CC`` environment variables. + + +Building with ATLAS support +--------------------------- + +Ubuntu +~~~~~~ + +You can install the necessary package for optimized ATLAS with this command:: + + sudo apt-get install libatlas-base-dev diff --git a/doc/source/user/c-info.beyond-basics.rst b/doc/source/user/c-info.beyond-basics.rst new file mode 100644 index 0000000..5c32108 --- /dev/null +++ b/doc/source/user/c-info.beyond-basics.rst @@ -0,0 +1,561 @@ +***************** +Beyond the Basics +***************** + +| The voyage of discovery is not in seeking new landscapes but in having +| new eyes. +| --- *Marcel Proust* + +| Discovery is seeing what everyone else has seen and thinking what no +| one else has thought. +| --- *Albert Szent-Gyorgi* + + +Iterating over elements in the array +==================================== + +.. _`sec:array_iterator`: + +Basic Iteration +--------------- + +One common algorithmic requirement is to be able to walk over all +elements in a multidimensional array. The array iterator object makes +this easy to do in a generic way that works for arrays of any +dimension. Naturally, if you know the number of dimensions you will be +using, then you can always write nested for loops to accomplish the +iteration. If, however, you want to write code that works with any +number of dimensions, then you can make use of the array iterator. An +array iterator object is returned when accessing the .flat attribute +of an array. + +.. index:: + single: array iterator + +Basic usage is to call :c:func:`PyArray_IterNew` ( ``array`` ) where array +is an ndarray object (or one of its sub-classes). The returned object +is an array-iterator object (the same object returned by the .flat +attribute of the ndarray). This object is usually cast to +PyArrayIterObject* so that its members can be accessed. The only +members that are needed are ``iter->size`` which contains the total +size of the array, ``iter->index``, which contains the current 1-d +index into the array, and ``iter->dataptr`` which is a pointer to the +data for the current element of the array. Sometimes it is also +useful to access ``iter->ao`` which is a pointer to the underlying +ndarray object. + +After processing data at the current element of the array, the next +element of the array can be obtained using the macro +:c:func:`PyArray_ITER_NEXT` ( ``iter`` ). The iteration always proceeds in a +C-style contiguous fashion (last index varying the fastest). The +:c:func:`PyArray_ITER_GOTO` ( ``iter``, ``destination`` ) can be used to +jump to a particular point in the array, where ``destination`` is an +array of npy_intp data-type with space to handle at least the number +of dimensions in the underlying array. Occasionally it is useful to +use :c:func:`PyArray_ITER_GOTO1D` ( ``iter``, ``index`` ) which will jump +to the 1-d index given by the value of ``index``. The most common +usage, however, is given in the following example. + +.. code-block:: c + + PyObject *obj; /* assumed to be some ndarray object */ + PyArrayIterObject *iter; + ... + iter = (PyArrayIterObject *)PyArray_IterNew(obj); + if (iter == NULL) goto fail; /* Assume fail has clean-up code */ + while (iter->index < iter->size) { + /* do something with the data at it->dataptr */ + PyArray_ITER_NEXT(it); + } + ... + +You can also use :c:func:`PyArrayIter_Check` ( ``obj`` ) to ensure you have +an iterator object and :c:func:`PyArray_ITER_RESET` ( ``iter`` ) to reset an +iterator object back to the beginning of the array. + +It should be emphasized at this point that you may not need the array +iterator if your array is already contiguous (using an array iterator +will work but will be slower than the fastest code you could write). +The major purpose of array iterators is to encapsulate iteration over +N-dimensional arrays with arbitrary strides. They are used in many, +many places in the NumPy source code itself. If you already know your +array is contiguous (Fortran or C), then simply adding the element- +size to a running pointer variable will step you through the array +very efficiently. In other words, code like this will probably be +faster for you in the contiguous case (assuming doubles). + +.. code-block:: c + + npy_intp size; + double *dptr; /* could make this any variable type */ + size = PyArray_SIZE(obj); + dptr = PyArray_DATA(obj); + while(size--) { + /* do something with the data at dptr */ + dptr++; + } + + +Iterating over all but one axis +------------------------------- + +A common algorithm is to loop over all elements of an array and +perform some function with each element by issuing a function call. As +function calls can be time consuming, one way to speed up this kind of +algorithm is to write the function so it takes a vector of data and +then write the iteration so the function call is performed for an +entire dimension of data at a time. This increases the amount of work +done per function call, thereby reducing the function-call over-head +to a small(er) fraction of the total time. Even if the interior of the +loop is performed without a function call it can be advantageous to +perform the inner loop over the dimension with the highest number of +elements to take advantage of speed enhancements available on micro- +processors that use pipelining to enhance fundmental operations. + +The :c:func:`PyArray_IterAllButAxis` ( ``array``, ``&dim`` ) constructs an +iterator object that is modified so that it will not iterate over the +dimension indicated by dim. The only restriction on this iterator +object, is that the :c:func:`PyArray_Iter_GOTO1D` ( ``it``, ``ind`` ) macro +cannot be used (thus flat indexing won't work either if you pass this +object back to Python --- so you shouldn't do this). Note that the +returned object from this routine is still usually cast to +PyArrayIterObject \*. All that's been done is to modify the strides +and dimensions of the returned iterator to simulate iterating over +array[...,0,...] where 0 is placed on the +:math:`\textrm{dim}^{\textrm{th}}` dimension. If dim is negative, then +the dimension with the largest axis is found and used. + + +Iterating over multiple arrays +------------------------------ + +Very often, it is desirable to iterate over several arrays at the +same time. The universal functions are an example of this kind of +behavior. If all you want to do is iterate over arrays with the same +shape, then simply creating several iterator objects is the standard +procedure. For example, the following code iterates over two arrays +assumed to be the same shape and size (actually obj1 just has to have +at least as many total elements as does obj2): + +.. code-block:: c + + /* It is already assumed that obj1 and obj2 + are ndarrays of the same shape and size. + */ + iter1 = (PyArrayIterObject *)PyArray_IterNew(obj1); + if (iter1 == NULL) goto fail; + iter2 = (PyArrayIterObject *)PyArray_IterNew(obj2); + if (iter2 == NULL) goto fail; /* assume iter1 is DECREF'd at fail */ + while (iter2->index < iter2->size) { + /* process with iter1->dataptr and iter2->dataptr */ + PyArray_ITER_NEXT(iter1); + PyArray_ITER_NEXT(iter2); + } + + +Broadcasting over multiple arrays +--------------------------------- + +.. index:: + single: broadcasting + +When multiple arrays are involved in an operation, you may want to use the +same broadcasting rules that the math operations (*i.e.* the ufuncs) use. +This can be done easily using the :c:type:`PyArrayMultiIterObject`. This is +the object returned from the Python command numpy.broadcast and it is almost +as easy to use from C. The function +:c:func:`PyArray_MultiIterNew` ( ``n``, ``...`` ) is used (with ``n`` input +objects in place of ``...`` ). The input objects can be arrays or anything +that can be converted into an array. A pointer to a PyArrayMultiIterObject is +returned. Broadcasting has already been accomplished which adjusts the +iterators so that all that needs to be done to advance to the next element in +each array is for PyArray_ITER_NEXT to be called for each of the inputs. This +incrementing is automatically performed by +:c:func:`PyArray_MultiIter_NEXT` ( ``obj`` ) macro (which can handle a +multiterator ``obj`` as either a :c:type:`PyArrayMultiObject *` or a +:c:type:`PyObject *`). The data from input number ``i`` is available using +:c:func:`PyArray_MultiIter_DATA` ( ``obj``, ``i`` ) and the total (broadcasted) +size as :c:func:`PyArray_MultiIter_SIZE` ( ``obj``). An example of using this +feature follows. + +.. code-block:: c + + mobj = PyArray_MultiIterNew(2, obj1, obj2); + size = PyArray_MultiIter_SIZE(obj); + while(size--) { + ptr1 = PyArray_MultiIter_DATA(mobj, 0); + ptr2 = PyArray_MultiIter_DATA(mobj, 1); + /* code using contents of ptr1 and ptr2 */ + PyArray_MultiIter_NEXT(mobj); + } + +The function :c:func:`PyArray_RemoveSmallest` ( ``multi`` ) can be used to +take a multi-iterator object and adjust all the iterators so that +iteration does not take place over the largest dimension (it makes +that dimension of size 1). The code being looped over that makes use +of the pointers will very-likely also need the strides data for each +of the iterators. This information is stored in +multi->iters[i]->strides. + +.. index:: + single: array iterator + +There are several examples of using the multi-iterator in the NumPy +source code as it makes N-dimensional broadcasting-code very simple to +write. Browse the source for more examples. + +.. _user.user-defined-data-types: + +User-defined data-types +======================= + +NumPy comes with 24 builtin data-types. While this covers a large +majority of possible use cases, it is conceivable that a user may have +a need for an additional data-type. There is some support for adding +an additional data-type into the NumPy system. This additional data- +type will behave much like a regular data-type except ufuncs must have +1-d loops registered to handle it separately. Also checking for +whether or not other data-types can be cast "safely" to and from this +new type or not will always return "can cast" unless you also register +which types your new data-type can be cast to and from. Adding +data-types is one of the less well-tested areas for NumPy 1.0, so +there may be bugs remaining in the approach. Only add a new data-type +if you can't do what you want to do using the OBJECT or VOID +data-types that are already available. As an example of what I +consider a useful application of the ability to add data-types is the +possibility of adding a data-type of arbitrary precision floats to +NumPy. + +.. index:: + pair: dtype; adding new + + +Adding the new data-type +------------------------ + +To begin to make use of the new data-type, you need to first define a +new Python type to hold the scalars of your new data-type. It should +be acceptable to inherit from one of the array scalars if your new +type has a binary compatible layout. This will allow your new data +type to have the methods and attributes of array scalars. New data- +types must have a fixed memory size (if you want to define a data-type +that needs a flexible representation, like a variable-precision +number, then use a pointer to the object as the data-type). The memory +layout of the object structure for the new Python type must be +PyObject_HEAD followed by the fixed-size memory needed for the data- +type. For example, a suitable structure for the new Python type is: + +.. code-block:: c + + typedef struct { + PyObject_HEAD; + some_data_type obval; + /* the name can be whatever you want */ + } PySomeDataTypeObject; + +After you have defined a new Python type object, you must then define +a new :c:type:`PyArray_Descr` structure whose typeobject member will contain a +pointer to the data-type you've just defined. In addition, the +required functions in the ".f" member must be defined: nonzero, +copyswap, copyswapn, setitem, getitem, and cast. The more functions in +the ".f" member you define, however, the more useful the new data-type +will be. It is very important to initialize unused functions to NULL. +This can be achieved using :c:func:`PyArray_InitArrFuncs` (f). + +Once a new :c:type:`PyArray_Descr` structure is created and filled with the +needed information and useful functions you call +:c:func:`PyArray_RegisterDataType` (new_descr). The return value from this +call is an integer providing you with a unique type_number that +specifies your data-type. This type number should be stored and made +available by your module so that other modules can use it to recognize +your data-type (the other mechanism for finding a user-defined +data-type number is to search based on the name of the type-object +associated with the data-type using :c:func:`PyArray_TypeNumFromName` ). + + +Registering a casting function +------------------------------ + +You may want to allow builtin (and other user-defined) data-types to +be cast automatically to your data-type. In order to make this +possible, you must register a casting function with the data-type you +want to be able to cast from. This requires writing low-level casting +functions for each conversion you want to support and then registering +these functions with the data-type descriptor. A low-level casting +function has the signature. + +.. c:function:: void castfunc( \ + void* from, void* to, npy_intp n, void* fromarr, void* toarr) + + Cast ``n`` elements ``from`` one type ``to`` another. The data to + cast from is in a contiguous, correctly-swapped and aligned chunk + of memory pointed to by from. The buffer to cast to is also + contiguous, correctly-swapped and aligned. The fromarr and toarr + arguments should only be used for flexible-element-sized arrays + (string, unicode, void). + +An example castfunc is: + +.. code-block:: c + + static void + double_to_float(double *from, float* to, npy_intp n, + void* ig1, void* ig2); + while (n--) { + (*to++) = (double) *(from++); + } + +This could then be registered to convert doubles to floats using the +code: + +.. code-block:: c + + doub = PyArray_DescrFromType(NPY_DOUBLE); + PyArray_RegisterCastFunc(doub, NPY_FLOAT, + (PyArray_VectorUnaryFunc *)double_to_float); + Py_DECREF(doub); + + +Registering coercion rules +-------------------------- + +By default, all user-defined data-types are not presumed to be safely +castable to any builtin data-types. In addition builtin data-types are +not presumed to be safely castable to user-defined data-types. This +situation limits the ability of user-defined data-types to participate +in the coercion system used by ufuncs and other times when automatic +coercion takes place in NumPy. This can be changed by registering +data-types as safely castable from a particular data-type object. The +function :c:func:`PyArray_RegisterCanCast` (from_descr, totype_number, +scalarkind) should be used to specify that the data-type object +from_descr can be cast to the data-type with type number +totype_number. If you are not trying to alter scalar coercion rules, +then use :c:data:`NPY_NOSCALAR` for the scalarkind argument. + +If you want to allow your new data-type to also be able to share in +the scalar coercion rules, then you need to specify the scalarkind +function in the data-type object's ".f" member to return the kind of +scalar the new data-type should be seen as (the value of the scalar is +available to that function). Then, you can register data-types that +can be cast to separately for each scalar kind that may be returned +from your user-defined data-type. If you don't register scalar +coercion handling, then all of your user-defined data-types will be +seen as :c:data:`NPY_NOSCALAR`. + + +Registering a ufunc loop +------------------------ + +You may also want to register low-level ufunc loops for your data-type +so that an ndarray of your data-type can have math applied to it +seamlessly. Registering a new loop with exactly the same arg_types +signature, silently replaces any previously registered loops for that +data-type. + +Before you can register a 1-d loop for a ufunc, the ufunc must be +previously created. Then you call :c:func:`PyUFunc_RegisterLoopForType` +(...) with the information needed for the loop. The return value of +this function is ``0`` if the process was successful and ``-1`` with +an error condition set if it was not successful. + +.. c:function:: int PyUFunc_RegisterLoopForType( \ + PyUFuncObject* ufunc, int usertype, PyUFuncGenericFunction function, \ + int* arg_types, void* data) + + *ufunc* + + The ufunc to attach this loop to. + + *usertype* + + The user-defined type this loop should be indexed under. This number + must be a user-defined type or an error occurs. + + *function* + + The ufunc inner 1-d loop. This function must have the signature as + explained in Section `3 <#sec-creating-a-new>`__ . + + *arg_types* + + (optional) If given, this should contain an array of integers of at + least size ufunc.nargs containing the data-types expected by the loop + function. The data will be copied into a NumPy-managed structure so + the memory for this argument should be deleted after calling this + function. If this is NULL, then it will be assumed that all data-types + are of type usertype. + + *data* + + (optional) Specify any optional data needed by the function which will + be passed when the function is called. + +.. index:: + pair: dtype; adding new + + +Subtyping the ndarray in C +========================== + +One of the lesser-used features that has been lurking in Python since +2.2 is the ability to sub-class types in C. This facility is one of +the important reasons for basing NumPy off of the Numeric code-base +which was already in C. A sub-type in C allows much more flexibility +with regards to memory management. Sub-typing in C is not difficult +even if you have only a rudimentary understanding of how to create new +types for Python. While it is easiest to sub-type from a single parent +type, sub-typing from multiple parent types is also possible. Multiple +inheritance in C is generally less useful than it is in Python because +a restriction on Python sub-types is that they have a binary +compatible memory layout. Perhaps for this reason, it is somewhat +easier to sub-type from a single parent type. + +.. index:: + pair: ndarray; subtyping + +All C-structures corresponding to Python objects must begin with +:c:macro:`PyObject_HEAD` (or :c:macro:`PyObject_VAR_HEAD`). In the same +way, any sub-type must have a C-structure that begins with exactly the +same memory layout as the parent type (or all of the parent types in +the case of multiple-inheritance). The reason for this is that Python +may attempt to access a member of the sub-type structure as if it had +the parent structure ( *i.e.* it will cast a given pointer to a +pointer to the parent structure and then dereference one of it's +members). If the memory layouts are not compatible, then this attempt +will cause unpredictable behavior (eventually leading to a memory +violation and program crash). + +One of the elements in :c:macro:`PyObject_HEAD` is a pointer to a +type-object structure. A new Python type is created by creating a new +type-object structure and populating it with functions and pointers to +describe the desired behavior of the type. Typically, a new +C-structure is also created to contain the instance-specific +information needed for each object of the type as well. For example, +:c:data:`&PyArray_Type` is a pointer to the type-object table for the ndarray +while a :c:type:`PyArrayObject *` variable is a pointer to a particular instance +of an ndarray (one of the members of the ndarray structure is, in +turn, a pointer to the type- object table :c:data:`&PyArray_Type`). Finally +:c:func:`PyType_Ready` () must be called for +every new Python type. + + +Creating sub-types +------------------ + +To create a sub-type, a similar procedure must be followed except +only behaviors that are different require new entries in the type- +object structure. All other entries can be NULL and will be filled in +by :c:func:`PyType_Ready` with appropriate functions from the parent +type(s). In particular, to create a sub-type in C follow these steps: + +1. If needed create a new C-structure to handle each instance of your + type. A typical C-structure would be: + + .. code-block:: c + + typedef _new_struct { + PyArrayObject base; + /* new things here */ + } NewArrayObject; + + Notice that the full PyArrayObject is used as the first entry in order + to ensure that the binary layout of instances of the new type is + identical to the PyArrayObject. + +2. Fill in a new Python type-object structure with pointers to new + functions that will over-ride the default behavior while leaving any + function that should remain the same unfilled (or NULL). The tp_name + element should be different. + +3. Fill in the tp_base member of the new type-object structure with a + pointer to the (main) parent type object. For multiple-inheritance, + also fill in the tp_bases member with a tuple containing all of the + parent objects in the order they should be used to define inheritance. + Remember, all parent-types must have the same C-structure for multiple + inheritance to work properly. + +4. Call :c:func:`PyType_Ready` (). If this function + returns a negative number, a failure occurred and the type is not + initialized. Otherwise, the type is ready to be used. It is + generally important to place a reference to the new type into the + module dictionary so it can be accessed from Python. + +More information on creating sub-types in C can be learned by reading +PEP 253 (available at http://www.python.org/dev/peps/pep-0253). + + +Specific features of ndarray sub-typing +--------------------------------------- + +Some special methods and attributes are used by arrays in order to +facilitate the interoperation of sub-types with the base ndarray type. + +The __array_finalize\__ method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. attribute:: ndarray.__array_finalize__ + + Several array-creation functions of the ndarray allow + specification of a particular sub-type to be created. This allows + sub-types to be handled seamlessly in many routines. When a + sub-type is created in such a fashion, however, neither the + __new_\_ method nor the __init\__ method gets called. Instead, the + sub-type is allocated and the appropriate instance-structure + members are filled in. Finally, the :obj:`~numpy.class.__array_finalize__` + attribute is looked-up in the object dictionary. If it is present + and not None, then it can be either a CObject containing a pointer + to a :c:func:`PyArray_FinalizeFunc` or it can be a method taking a + single argument (which could be None). + + If the :obj:`~numpy.class.__array_finalize__` attribute is a CObject, then the pointer + must be a pointer to a function with the signature: + + .. code-block:: c + + (int) (PyArrayObject *, PyObject *) + + The first argument is the newly created sub-type. The second argument + (if not NULL) is the "parent" array (if the array was created using + slicing or some other operation where a clearly-distinguishable parent + is present). This routine can do anything it wants to. It should + return a -1 on error and 0 otherwise. + + If the :obj:`~numpy.class.__array_finalize__` attribute is not None nor a CObject, + then it must be a Python method that takes the parent array as an + argument (which could be None if there is no parent), and returns + nothing. Errors in this method will be caught and handled. + + +The __array_priority\__ attribute +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. attribute:: ndarray.__array_priority__ + + This attribute allows simple but flexible determination of which sub- + type should be considered "primary" when an operation involving two or + more sub-types arises. In operations where different sub-types are + being used, the sub-type with the largest :obj:`~numpy.class.__array_priority__` + attribute will determine the sub-type of the output(s). If two sub- + types have the same :obj:`~numpy.class.__array_priority__` then the sub-type of the + first argument determines the output. The default + :obj:`~numpy.class.__array_priority__` attribute returns a value of 0.0 for the base + ndarray type and 1.0 for a sub-type. This attribute can also be + defined by objects that are not sub-types of the ndarray and can be + used to determine which :obj:`~numpy.class.__array_wrap__` method should be called for + the return output. + +The __array_wrap\__ method +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. attribute:: ndarray.__array_wrap__ + + Any class or type can define this method which should take an ndarray + argument and return an instance of the type. It can be seen as the + opposite of the :obj:`~numpy.class.__array__` method. This method is used by the + ufuncs (and other NumPy functions) to allow other objects to pass + through. For Python >2.4, it can also be used to write a decorator + that converts a function that works only with ndarrays to one that + works with any type with :obj:`~numpy.class.__array__` and :obj:`~numpy.class.__array_wrap__` methods. + +.. index:: + pair: ndarray; subtyping diff --git a/doc/source/user/c-info.how-to-extend.rst b/doc/source/user/c-info.how-to-extend.rst new file mode 100644 index 0000000..22c3b6e --- /dev/null +++ b/doc/source/user/c-info.how-to-extend.rst @@ -0,0 +1,660 @@ +******************* +How to extend NumPy +******************* + +| That which is static and repetitive is boring. That which is dynamic +| and random is confusing. In between lies art. +| --- *John A. Locke* + +| Science is a differential equation. Religion is a boundary condition. +| --- *Alan Turing* + + +.. _writing-an-extension: + +Writing an extension module +=========================== + +While the ndarray object is designed to allow rapid computation in +Python, it is also designed to be general-purpose and satisfy a wide- +variety of computational needs. As a result, if absolute speed is +essential, there is no replacement for a well-crafted, compiled loop +specific to your application and hardware. This is one of the reasons +that numpy includes f2py so that an easy-to-use mechanisms for linking +(simple) C/C++ and (arbitrary) Fortran code directly into Python are +available. You are encouraged to use and improve this mechanism. The +purpose of this section is not to document this tool but to document +the more basic steps to writing an extension module that this tool +depends on. + +.. index:: + single: extension module + +When an extension module is written, compiled, and installed to +somewhere in the Python path (sys.path), the code can then be imported +into Python as if it were a standard python file. It will contain +objects and methods that have been defined and compiled in C code. The +basic steps for doing this in Python are well-documented and you can +find more information in the documentation for Python itself available +online at `www.python.org `_ . + +In addition to the Python C-API, there is a full and rich C-API for +NumPy allowing sophisticated manipulations on a C-level. However, for +most applications, only a few API calls will typically be used. If all +you need to do is extract a pointer to memory along with some shape +information to pass to another calculation routine, then you will use +very different calls, then if you are trying to create a new array- +like type or add a new data type for ndarrays. This chapter documents +the API calls and macros that are most commonly used. + + +Required subroutine +=================== + +There is exactly one function that must be defined in your C-code in +order for Python to use it as an extension module. The function must +be called init{name} where {name} is the name of the module from +Python. This function must be declared so that it is visible to code +outside of the routine. Besides adding the methods and constants you +desire, this subroutine must also contain calls like ``import_array()`` +and/or ``import_ufunc()`` depending on which C-API is needed. Forgetting +to place these commands will show itself as an ugly segmentation fault +(crash) as soon as any C-API subroutine is actually called. It is +actually possible to have multiple init{name} functions in a single +file in which case multiple modules will be defined by that file. +However, there are some tricks to get that to work correctly and it is +not covered here. + +A minimal ``init{name}`` method looks like: + +.. code-block:: c + + PyMODINIT_FUNC + init{name}(void) + { + (void)Py_InitModule({name}, mymethods); + import_array(); + } + +The mymethods must be an array (usually statically declared) of +PyMethodDef structures which contain method names, actual C-functions, +a variable indicating whether the method uses keyword arguments or +not, and docstrings. These are explained in the next section. If you +want to add constants to the module, then you store the returned value +from Py_InitModule which is a module object. The most general way to +add items to the module is to get the module dictionary using +PyModule_GetDict(module). With the module dictionary, you can add +whatever you like to the module manually. An easier way to add objects +to the module is to use one of three additional Python C-API calls +that do not require a separate extraction of the module dictionary. +These are documented in the Python documentation, but repeated here +for convenience: + +.. c:function:: int PyModule_AddObject( \ + PyObject* module, char* name, PyObject* value) + +.. c:function:: int PyModule_AddIntConstant( \ + PyObject* module, char* name, long value) + +.. c:function:: int PyModule_AddStringConstant( \ + PyObject* module, char* name, char* value) + + All three of these functions require the *module* object (the + return value of Py_InitModule). The *name* is a string that + labels the value in the module. Depending on which function is + called, the *value* argument is either a general object + (:c:func:`PyModule_AddObject` steals a reference to it), an integer + constant, or a string constant. + + +Defining functions +================== + +The second argument passed in to the Py_InitModule function is a +structure that makes it easy to to define functions in the module. In +the example given above, the mymethods structure would have been +defined earlier in the file (usually right before the init{name} +subroutine) to: + +.. code-block:: c + + static PyMethodDef mymethods[] = { + { nokeywordfunc,nokeyword_cfunc, + METH_VARARGS, + Doc string}, + { keywordfunc, keyword_cfunc, + METH_VARARGS|METH_KEYWORDS, + Doc string}, + {NULL, NULL, 0, NULL} /* Sentinel */ + } + +Each entry in the mymethods array is a :c:type:`PyMethodDef` structure +containing 1) the Python name, 2) the C-function that implements the +function, 3) flags indicating whether or not keywords are accepted for +this function, and 4) The docstring for the function. Any number of +functions may be defined for a single module by adding more entries to +this table. The last entry must be all NULL as shown to act as a +sentinel. Python looks for this entry to know that all of the +functions for the module have been defined. + +The last thing that must be done to finish the extension module is to +actually write the code that performs the desired functions. There are +two kinds of functions: those that don't accept keyword arguments, and +those that do. + + +Functions without keyword arguments +----------------------------------- + +Functions that don't accept keyword arguments should be written as: + +.. code-block:: c + + static PyObject* + nokeyword_cfunc (PyObject *dummy, PyObject *args) + { + /* convert Python arguments */ + /* do function */ + /* return something */ + } + +The dummy argument is not used in this context and can be safely +ignored. The *args* argument contains all of the arguments passed in +to the function as a tuple. You can do anything you want at this +point, but usually the easiest way to manage the input arguments is to +call :c:func:`PyArg_ParseTuple` (args, format_string, +addresses_to_C_variables...) or :c:func:`PyArg_UnpackTuple` (tuple, "name" , +min, max, ...). A good description of how to use the first function is +contained in the Python C-API reference manual under section 5.5 +(Parsing arguments and building values). You should pay particular +attention to the "O&" format which uses converter functions to go +between the Python object and the C object. All of the other format +functions can be (mostly) thought of as special cases of this general +rule. There are several converter functions defined in the NumPy C-API +that may be of use. In particular, the :c:func:`PyArray_DescrConverter` +function is very useful to support arbitrary data-type specification. +This function transforms any valid data-type Python object into a +:c:type:`PyArray_Descr *` object. Remember to pass in the address of the +C-variables that should be filled in. + +There are lots of examples of how to use :c:func:`PyArg_ParseTuple` +throughout the NumPy source code. The standard usage is like this: + +.. code-block:: c + + PyObject *input; + PyArray_Descr *dtype; + if (!PyArg_ParseTuple(args, "OO&", &input, + PyArray_DescrConverter, + &dtype)) return NULL; + +It is important to keep in mind that you get a *borrowed* reference to +the object when using the "O" format string. However, the converter +functions usually require some form of memory handling. In this +example, if the conversion is successful, *dtype* will hold a new +reference to a :c:type:`PyArray_Descr *` object, while *input* will hold a +borrowed reference. Therefore, if this conversion were mixed with +another conversion (say to an integer) and the data-type conversion +was successful but the integer conversion failed, then you would need +to release the reference count to the data-type object before +returning. A typical way to do this is to set *dtype* to ``NULL`` +before calling :c:func:`PyArg_ParseTuple` and then use :c:func:`Py_XDECREF` +on *dtype* before returning. + +After the input arguments are processed, the code that actually does +the work is written (likely calling other functions as needed). The +final step of the C-function is to return something. If an error is +encountered then ``NULL`` should be returned (making sure an error has +actually been set). If nothing should be returned then increment +:c:data:`Py_None` and return it. If a single object should be returned then +it is returned (ensuring that you own a reference to it first). If +multiple objects should be returned then you need to return a tuple. +The :c:func:`Py_BuildValue` (format_string, c_variables...) function makes +it easy to build tuples of Python objects from C variables. Pay +special attention to the difference between 'N' and 'O' in the format +string or you can easily create memory leaks. The 'O' format string +increments the reference count of the :c:type:`PyObject *` C-variable it +corresponds to, while the 'N' format string steals a reference to the +corresponding :c:type:`PyObject *` C-variable. You should use 'N' if you have +already created a reference for the object and just want to give that +reference to the tuple. You should use 'O' if you only have a borrowed +reference to an object and need to create one to provide for the +tuple. + + +Functions with keyword arguments +-------------------------------- + +These functions are very similar to functions without keyword +arguments. The only difference is that the function signature is: + +.. code-block:: c + + static PyObject* + keyword_cfunc (PyObject *dummy, PyObject *args, PyObject *kwds) + { + ... + } + +The kwds argument holds a Python dictionary whose keys are the names +of the keyword arguments and whose values are the corresponding +keyword-argument values. This dictionary can be processed however you +see fit. The easiest way to handle it, however, is to replace the +:c:func:`PyArg_ParseTuple` (args, format_string, addresses...) function with +a call to :c:func:`PyArg_ParseTupleAndKeywords` (args, kwds, format_string, +char \*kwlist[], addresses...). The kwlist parameter to this function +is a ``NULL`` -terminated array of strings providing the expected +keyword arguments. There should be one string for each entry in the +format_string. Using this function will raise a TypeError if invalid +keyword arguments are passed in. + +For more help on this function please see section 1.8 (Keyword +Parameters for Extension Functions) of the Extending and Embedding +tutorial in the Python documentation. + + +Reference counting +------------------ + +The biggest difficulty when writing extension modules is reference +counting. It is an important reason for the popularity of f2py, weave, +Cython, ctypes, etc.... If you mis-handle reference counts you can get +problems from memory-leaks to segmentation faults. The only strategy I +know of to handle reference counts correctly is blood, sweat, and +tears. First, you force it into your head that every Python variable +has a reference count. Then, you understand exactly what each function +does to the reference count of your objects, so that you can properly +use DECREF and INCREF when you need them. Reference counting can +really test the amount of patience and diligence you have towards your +programming craft. Despite the grim depiction, most cases of reference +counting are quite straightforward with the most common difficulty +being not using DECREF on objects before exiting early from a routine +due to some error. In second place, is the common error of not owning +the reference on an object that is passed to a function or macro that +is going to steal the reference ( *e.g.* :c:func:`PyTuple_SET_ITEM`, and +most functions that take :c:type:`PyArray_Descr` objects). + +.. index:: + single: reference counting + +Typically you get a new reference to a variable when it is created or +is the return value of some function (there are some prominent +exceptions, however --- such as getting an item out of a tuple or a +dictionary). When you own the reference, you are responsible to make +sure that :c:func:`Py_DECREF` (var) is called when the variable is no +longer necessary (and no other function has "stolen" its +reference). Also, if you are passing a Python object to a function +that will "steal" the reference, then you need to make sure you own it +(or use :c:func:`Py_INCREF` to get your own reference). You will also +encounter the notion of borrowing a reference. A function that borrows +a reference does not alter the reference count of the object and does +not expect to "hold on "to the reference. It's just going to use the +object temporarily. When you use :c:func:`PyArg_ParseTuple` or +:c:func:`PyArg_UnpackTuple` you receive a borrowed reference to the +objects in the tuple and should not alter their reference count inside +your function. With practice, you can learn to get reference counting +right, but it can be frustrating at first. + +One common source of reference-count errors is the :c:func:`Py_BuildValue` +function. Pay careful attention to the difference between the 'N' +format character and the 'O' format character. If you create a new +object in your subroutine (such as an output array), and you are +passing it back in a tuple of return values, then you should most- +likely use the 'N' format character in :c:func:`Py_BuildValue`. The 'O' +character will increase the reference count by one. This will leave +the caller with two reference counts for a brand-new array. When the +variable is deleted and the reference count decremented by one, there +will still be that extra reference count, and the array will never be +deallocated. You will have a reference-counting induced memory leak. +Using the 'N' character will avoid this situation as it will return to +the caller an object (inside the tuple) with a single reference count. + +.. index:: + single: reference counting + + + + +Dealing with array objects +========================== + +Most extension modules for NumPy will need to access the memory for an +ndarray object (or one of it's sub-classes). The easiest way to do +this doesn't require you to know much about the internals of NumPy. +The method is to + +1. Ensure you are dealing with a well-behaved array (aligned, in machine + byte-order and single-segment) of the correct type and number of + dimensions. + + 1. By converting it from some Python object using + :c:func:`PyArray_FromAny` or a macro built on it. + + 2. By constructing a new ndarray of your desired shape and type + using :c:func:`PyArray_NewFromDescr` or a simpler macro or function + based on it. + + +2. Get the shape of the array and a pointer to its actual data. + +3. Pass the data and shape information on to a subroutine or other + section of code that actually performs the computation. + +4. If you are writing the algorithm, then I recommend that you use the + stride information contained in the array to access the elements of + the array (the :c:func:`PyArray_GETPTR` macros make this painless). Then, + you can relax your requirements so as not to force a single-segment + array and the data-copying that might result. + +Each of these sub-topics is covered in the following sub-sections. + + +Converting an arbitrary sequence object +--------------------------------------- + +The main routine for obtaining an array from any Python object that +can be converted to an array is :c:func:`PyArray_FromAny`. This +function is very flexible with many input arguments. Several macros +make it easier to use the basic function. :c:func:`PyArray_FROM_OTF` is +arguably the most useful of these macros for the most common uses. It +allows you to convert an arbitrary Python object to an array of a +specific builtin data-type ( *e.g.* float), while specifying a +particular set of requirements ( *e.g.* contiguous, aligned, and +writeable). The syntax is + +.. c:function:: PyObject *PyArray_FROM_OTF( \ + PyObject* obj, int typenum, int requirements) + + Return an ndarray from any Python object, *obj*, that can be + converted to an array. The number of dimensions in the returned + array is determined by the object. The desired data-type of the + returned array is provided in *typenum* which should be one of the + enumerated types. The *requirements* for the returned array can be + any combination of standard array flags. Each of these arguments + is explained in more detail below. You receive a new reference to + the array on success. On failure, ``NULL`` is returned and an + exception is set. + + *obj* + + The object can be any Python object convertible to an ndarray. + If the object is already (a subclass of) the ndarray that + satisfies the requirements then a new reference is returned. + Otherwise, a new array is constructed. The contents of *obj* + are copied to the new array unless the array interface is used + so that data does not have to be copied. Objects that can be + converted to an array include: 1) any nested sequence object, + 2) any object exposing the array interface, 3) any object with + an :obj:`~numpy.class.__array__` method (which should return an ndarray), + and 4) any scalar object (becomes a zero-dimensional + array). Sub-classes of the ndarray that otherwise fit the + requirements will be passed through. If you want to ensure + a base-class ndarray, then use :c:data:`NPY_ARRAY_ENSUREARRAY` in the + requirements flag. A copy is made only if necessary. If you + want to guarantee a copy, then pass in :c:data:`NPY_ARRAY_ENSURECOPY` + to the requirements flag. + + *typenum* + + One of the enumerated types or :c:data:`NPY_NOTYPE` if the data-type + should be determined from the object itself. The C-based names + can be used: + + :c:data:`NPY_BOOL`, :c:data:`NPY_BYTE`, :c:data:`NPY_UBYTE`, + :c:data:`NPY_SHORT`, :c:data:`NPY_USHORT`, :c:data:`NPY_INT`, + :c:data:`NPY_UINT`, :c:data:`NPY_LONG`, :c:data:`NPY_ULONG`, + :c:data:`NPY_LONGLONG`, :c:data:`NPY_ULONGLONG`, :c:data:`NPY_DOUBLE`, + :c:data:`NPY_LONGDOUBLE`, :c:data:`NPY_CFLOAT`, :c:data:`NPY_CDOUBLE`, + :c:data:`NPY_CLONGDOUBLE`, :c:data:`NPY_OBJECT`. + + Alternatively, the bit-width names can be used as supported on the + platform. For example: + + :c:data:`NPY_INT8`, :c:data:`NPY_INT16`, :c:data:`NPY_INT32`, + :c:data:`NPY_INT64`, :c:data:`NPY_UINT8`, + :c:data:`NPY_UINT16`, :c:data:`NPY_UINT32`, + :c:data:`NPY_UINT64`, :c:data:`NPY_FLOAT32`, + :c:data:`NPY_FLOAT64`, :c:data:`NPY_COMPLEX64`, + :c:data:`NPY_COMPLEX128`. + + The object will be converted to the desired type only if it + can be done without losing precision. Otherwise ``NULL`` will + be returned and an error raised. Use :c:data:`NPY_ARRAY_FORCECAST` in the + requirements flag to override this behavior. + + *requirements* + + The memory model for an ndarray admits arbitrary strides in + each dimension to advance to the next element of the array. + Often, however, you need to interface with code that expects a + C-contiguous or a Fortran-contiguous memory layout. In + addition, an ndarray can be misaligned (the address of an + element is not at an integral multiple of the size of the + element) which can cause your program to crash (or at least + work more slowly) if you try and dereference a pointer into + the array data. Both of these problems can be solved by + converting the Python object into an array that is more + "well-behaved" for your specific usage. + + The requirements flag allows specification of what kind of + array is acceptable. If the object passed in does not satisfy + this requirements then a copy is made so that thre returned + object will satisfy the requirements. these ndarray can use a + very generic pointer to memory. This flag allows specification + of the desired properties of the returned array object. All + of the flags are explained in the detailed API chapter. The + flags most commonly needed are :c:data:`NPY_ARRAY_IN_ARRAY`, + :c:data:`NPY_OUT_ARRAY`, and :c:data:`NPY_ARRAY_INOUT_ARRAY`: + + .. c:var:: NPY_ARRAY_IN_ARRAY + + Equivalent to :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| + :c:data:`NPY_ARRAY_ALIGNED`. This combination of flags is useful + for arrays that must be in C-contiguous order and aligned. + These kinds of arrays are usually input arrays for some + algorithm. + + .. c:var:: NPY_ARRAY_OUT_ARRAY + + Equivalent to :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| + :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE`. This + combination of flags is useful to specify an array that is + in C-contiguous order, is aligned, and can be written to + as well. Such an array is usually returned as output + (although normally such output arrays are created from + scratch). + + .. c:var:: NPY_ARRAY_INOUT_ARRAY + + Equivalent to :c:data:`NPY_ARRAY_C_CONTIGUOUS` \| + :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE` \| + :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` \| + :c:data:`NPY_ARRAY_UPDATEIFCOPY`. This combination of flags is + useful to specify an array that will be used for both + input and output. :c:func:`PyArray_ResolveWritebackIfCopy` + must be called before :func:`Py_DECREF` at + the end of the interface routine to write back the temporary data + into the original array passed in. Use + of the :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` or + :c:data:`NPY_ARRAY_UPDATEIFCOPY` flags requires that the input + object is already an array (because other objects cannot + be automatically updated in this fashion). If an error + occurs use :c:func:`PyArray_DiscardWritebackIfCopy` (obj) on an + array with these flags set. This will set the underlying base array + writable without causing the contents to be copied + back into the original array. + + + Other useful flags that can be OR'd as additional requirements are: + + .. c:var:: NPY_ARRAY_FORCECAST + + Cast to the desired type, even if it can't be done without losing + information. + + .. c:var:: NPY_ARRAY_ENSURECOPY + + Make sure the resulting array is a copy of the original. + + .. c:var:: NPY_ARRAY_ENSUREARRAY + + Make sure the resulting object is an actual ndarray and not a sub- + class. + +.. note:: + + Whether or not an array is byte-swapped is determined by the + data-type of the array. Native byte-order arrays are always + requested by :c:func:`PyArray_FROM_OTF` and so there is no need for + a :c:data:`NPY_ARRAY_NOTSWAPPED` flag in the requirements argument. There + is also no way to get a byte-swapped array from this routine. + + +Creating a brand-new ndarray +---------------------------- + +Quite often new arrays must be created from within extension-module +code. Perhaps an output array is needed and you don't want the caller +to have to supply it. Perhaps only a temporary array is needed to hold +an intermediate calculation. Whatever the need there are simple ways +to get an ndarray object of whatever data-type is needed. The most +general function for doing this is :c:func:`PyArray_NewFromDescr`. All array +creation functions go through this heavily re-used code. Because of +its flexibility, it can be somewhat confusing to use. As a result, +simpler forms exist that are easier to use. + +.. c:function:: PyObject *PyArray_SimpleNew(int nd, npy_intp* dims, int typenum) + + This function allocates new memory and places it in an ndarray + with *nd* dimensions whose shape is determined by the array of + at least *nd* items pointed to by *dims*. The memory for the + array is uninitialized (unless typenum is :c:data:`NPY_OBJECT` in + which case each element in the array is set to NULL). The + *typenum* argument allows specification of any of the builtin + data-types such as :c:data:`NPY_FLOAT` or :c:data:`NPY_LONG`. The + memory for the array can be set to zero if desired using + :c:func:`PyArray_FILLWBYTE` (return_object, 0). + +.. c:function:: PyObject *PyArray_SimpleNewFromData( \ + int nd, npy_intp* dims, int typenum, void* data) + + Sometimes, you want to wrap memory allocated elsewhere into an + ndarray object for downstream use. This routine makes it + straightforward to do that. The first three arguments are the same + as in :c:func:`PyArray_SimpleNew`, the final argument is a pointer to a + block of contiguous memory that the ndarray should use as it's + data-buffer which will be interpreted in C-style contiguous + fashion. A new reference to an ndarray is returned, but the + ndarray will not own its data. When this ndarray is deallocated, + the pointer will not be freed. + + You should ensure that the provided memory is not freed while the + returned array is in existence. The easiest way to handle this is + if data comes from another reference-counted Python object. The + reference count on this object should be increased after the + pointer is passed in, and the base member of the returned ndarray + should point to the Python object that owns the data. Then, when + the ndarray is deallocated, the base-member will be DECREF'd + appropriately. If you want the memory to be freed as soon as the + ndarray is deallocated then simply set the OWNDATA flag on the + returned ndarray. + + +Getting at ndarray memory and accessing elements of the ndarray +--------------------------------------------------------------- + +If obj is an ndarray (:c:type:`PyArrayObject *`), then the data-area of the +ndarray is pointed to by the void* pointer :c:func:`PyArray_DATA` (obj) or +the char* pointer :c:func:`PyArray_BYTES` (obj). Remember that (in general) +this data-area may not be aligned according to the data-type, it may +represent byte-swapped data, and/or it may not be writeable. If the +data area is aligned and in native byte-order, then how to get at a +specific element of the array is determined only by the array of +npy_intp variables, :c:func:`PyArray_STRIDES` (obj). In particular, this +c-array of integers shows how many **bytes** must be added to the +current element pointer to get to the next element in each dimension. +For arrays less than 4-dimensions there are :c:func:`PyArray_GETPTR{k}` +(obj, ...) macros where {k} is the integer 1, 2, 3, or 4 that make +using the array strides easier. The arguments .... represent {k} non- +negative integer indices into the array. For example, suppose ``E`` is +a 3-dimensional ndarray. A (void*) pointer to the element ``E[i,j,k]`` +is obtained as :c:func:`PyArray_GETPTR3` (E, i, j, k). + +As explained previously, C-style contiguous arrays and Fortran-style +contiguous arrays have particular striding patterns. Two array flags +(:c:data:`NPY_ARRAY_C_CONTIGUOUS` and :c:data:`NPY_ARRAY_F_CONTIGUOUS`) indicate +whether or not the striding pattern of a particular array matches the +C-style contiguous or Fortran-style contiguous or neither. Whether or +not the striding pattern matches a standard C or Fortran one can be +tested Using :c:func:`PyArray_ISCONTIGUOUS` (obj) and +:c:func:`PyArray_ISFORTRAN` (obj) respectively. Most third-party +libraries expect contiguous arrays. But, often it is not difficult to +support general-purpose striding. I encourage you to use the striding +information in your own code whenever possible, and reserve +single-segment requirements for wrapping third-party code. Using the +striding information provided with the ndarray rather than requiring a +contiguous striding reduces copying that otherwise must be made. + + +Example +======= + +.. index:: + single: extension module + +The following example shows how you might write a wrapper that accepts +two input arguments (that will be converted to an array) and an output +argument (that must be an array). The function returns None and +updates the output array. Note the updated use of WRITEBACKIFCOPY semantics +for NumPy v1.14 and above + +.. code-block:: c + + static PyObject * + example_wrapper(PyObject *dummy, PyObject *args) + { + PyObject *arg1=NULL, *arg2=NULL, *out=NULL; + PyObject *arr1=NULL, *arr2=NULL, *oarr=NULL; + + if (!PyArg_ParseTuple(args, "OOO!", &arg1, &arg2, + &PyArray_Type, &out)) return NULL; + + arr1 = PyArray_FROM_OTF(arg1, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY); + if (arr1 == NULL) return NULL; + arr2 = PyArray_FROM_OTF(arg2, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY); + if (arr2 == NULL) goto fail; + #if NPY_API_VERSION >= 0x0000000c + oarr = PyArray_FROM_OTF(out, NPY_DOUBLE, NPY_ARRAY_INOUT_ARRAY2); + #else + oarr = PyArray_FROM_OTF(out, NPY_DOUBLE, NPY_ARRAY_INOUT_ARRAY); + #endif + if (oarr == NULL) goto fail; + + /* code that makes use of arguments */ + /* You will probably need at least + nd = PyArray_NDIM(<..>) -- number of dimensions + dims = PyArray_DIMS(<..>) -- npy_intp array of length nd + showing length in each dim. + dptr = (double *)PyArray_DATA(<..>) -- pointer to data. + + If an error occurs goto fail. + */ + + Py_DECREF(arr1); + Py_DECREF(arr2); + #if NPY_API_VERSION >= 0x0000000c + PyArray_ResolveWritebackIfCopy(oarr); + #endif + Py_DECREF(oarr); + Py_INCREF(Py_None); + return Py_None; + + fail: + Py_XDECREF(arr1); + Py_XDECREF(arr2); + #if NPY_API_VERSION >= 0x0000000c + PyArray_DiscardWritebackIfCopy(oarr); + #endif + Py_XDECREF(oarr); + return NULL; + } diff --git a/doc/source/user/c-info.python-as-glue.rst b/doc/source/user/c-info.python-as-glue.rst new file mode 100644 index 0000000..0152ac5 --- /dev/null +++ b/doc/source/user/c-info.python-as-glue.rst @@ -0,0 +1,1182 @@ +******************** +Using Python as glue +******************** + +| There is no conversation more boring than the one where everybody +| agrees. +| --- *Michel de Montaigne* + +| Duct tape is like the force. It has a light side, and a dark side, and +| it holds the universe together. +| --- *Carl Zwanzig* + +Many people like to say that Python is a fantastic glue language. +Hopefully, this Chapter will convince you that this is true. The first +adopters of Python for science were typically people who used it to +glue together large application codes running on super-computers. Not +only was it much nicer to code in Python than in a shell script or +Perl, in addition, the ability to easily extend Python made it +relatively easy to create new classes and types specifically adapted +to the problems being solved. From the interactions of these early +contributors, Numeric emerged as an array-like object that could be +used to pass data between these applications. + +As Numeric has matured and developed into NumPy, people have been able +to write more code directly in NumPy. Often this code is fast-enough +for production use, but there are still times that there is a need to +access compiled code. Either to get that last bit of efficiency out of +the algorithm or to make it easier to access widely-available codes +written in C/C++ or Fortran. + +This chapter will review many of the tools that are available for the +purpose of accessing code written in other compiled languages. There +are many resources available for learning to call other compiled +libraries from Python and the purpose of this Chapter is not to make +you an expert. The main goal is to make you aware of some of the +possibilities so that you will know what to "Google" in order to learn more. + + +Calling other compiled libraries from Python +============================================ + +While Python is a great language and a pleasure to code in, its +dynamic nature results in overhead that can cause some code ( *i.e.* +raw computations inside of for loops) to be up 10-100 times slower +than equivalent code written in a static compiled language. In +addition, it can cause memory usage to be larger than necessary as +temporary arrays are created and destroyed during computation. For +many types of computing needs, the extra slow-down and memory +consumption can often not be spared (at least for time- or memory- +critical portions of your code). Therefore one of the most common +needs is to call out from Python code to a fast, machine-code routine +(e.g. compiled using C/C++ or Fortran). The fact that this is +relatively easy to do is a big reason why Python is such an excellent +high-level language for scientific and engineering programming. + +Their are two basic approaches to calling compiled code: writing an +extension module that is then imported to Python using the import +command, or calling a shared-library subroutine directly from Python +using the `ctypes `_ +module. Writing an extension module is the most common method. + +.. warning:: + + Calling C-code from Python can result in Python crashes if you are not + careful. None of the approaches in this chapter are immune. You have + to know something about the way data is handled by both NumPy and by + the third-party library being used. + + +Hand-generated wrappers +======================= + +Extension modules were discussed in :ref:`writing-an-extension`. +The most basic way to interface with compiled code is to write +an extension module and construct a module method that calls +the compiled code. For improved readability, your method should +take advantage of the ``PyArg_ParseTuple`` call to convert between +Python objects and C data-types. For standard C data-types there +is probably already a built-in converter. For others you may need +to write your own converter and use the ``"O&"`` format string which +allows you to specify a function that will be used to perform the +conversion from the Python object to whatever C-structures are needed. + +Once the conversions to the appropriate C-structures and C data-types +have been performed, the next step in the wrapper is to call the +underlying function. This is straightforward if the underlying +function is in C or C++. However, in order to call Fortran code you +must be familiar with how Fortran subroutines are called from C/C++ +using your compiler and platform. This can vary somewhat platforms and +compilers (which is another reason f2py makes life much simpler for +interfacing Fortran code) but generally involves underscore mangling +of the name and the fact that all variables are passed by reference +(i.e. all arguments are pointers). + +The advantage of the hand-generated wrapper is that you have complete +control over how the C-library gets used and called which can lead to +a lean and tight interface with minimal over-head. The disadvantage is +that you have to write, debug, and maintain C-code, although most of +it can be adapted using the time-honored technique of +"cutting-pasting-and-modifying" from other extension modules. Because, +the procedure of calling out to additional C-code is fairly +regimented, code-generation procedures have been developed to make +this process easier. One of these code-generation techniques is +distributed with NumPy and allows easy integration with Fortran and +(simple) C code. This package, f2py, will be covered briefly in the +next section. + + +f2py +==== + +F2py allows you to automatically construct an extension module that +interfaces to routines in Fortran 77/90/95 code. It has the ability to +parse Fortran 77/90/95 code and automatically generate Python +signatures for the subroutines it encounters, or you can guide how the +subroutine interfaces with Python by constructing an interface-definition-file +(or modifying the f2py-produced one). + +.. index:: + single: f2py + +Creating source for a basic extension module +-------------------------------------------- + +Probably the easiest way to introduce f2py is to offer a simple +example. Here is one of the subroutines contained in a file named +:file:`add.f`: + +.. code-block:: none + + C + SUBROUTINE ZADD(A,B,C,N) + C + DOUBLE COMPLEX A(*) + DOUBLE COMPLEX B(*) + DOUBLE COMPLEX C(*) + INTEGER N + DO 20 J = 1, N + C(J) = A(J)+B(J) + 20 CONTINUE + END + +This routine simply adds the elements in two contiguous arrays and +places the result in a third. The memory for all three arrays must be +provided by the calling routine. A very basic interface to this +routine can be automatically generated by f2py:: + + f2py -m add add.f + +You should be able to run this command assuming your search-path is +set-up properly. This command will produce an extension module named +addmodule.c in the current directory. This extension module can now be +compiled and used from Python just like any other extension module. + + +Creating a compiled extension module +------------------------------------ + +You can also get f2py to compile add.f and also compile its produced +extension module leaving only a shared-library extension file that can +be imported from Python:: + + f2py -c -m add add.f + +This command leaves a file named add.{ext} in the current directory +(where {ext} is the appropriate extension for a python extension +module on your platform --- so, pyd, *etc.* ). This module may then be +imported from Python. It will contain a method for each subroutine in +add (zadd, cadd, dadd, sadd). The docstring of each method contains +information about how the module method may be called:: + + >>> import add + >>> print add.zadd.__doc__ + zadd - Function signature: + zadd(a,b,c,n) + Required arguments: + a : input rank-1 array('D') with bounds (*) + b : input rank-1 array('D') with bounds (*) + c : input rank-1 array('D') with bounds (*) + n : input int + + +Improving the basic interface +----------------------------- + +The default interface is a very literal translation of the fortran +code into Python. The Fortran array arguments must now be NumPy arrays +and the integer argument should be an integer. The interface will +attempt to convert all arguments to their required types (and shapes) +and issue an error if unsuccessful. However, because it knows nothing +about the semantics of the arguments (such that C is an output and n +should really match the array sizes), it is possible to abuse this +function in ways that can cause Python to crash. For example:: + + >>> add.zadd([1,2,3], [1,2], [3,4], 1000) + +will cause a program crash on most systems. Under the covers, the +lists are being converted to proper arrays but then the underlying add +loop is told to cycle way beyond the borders of the allocated memory. + +In order to improve the interface, directives should be provided. This +is accomplished by constructing an interface definition file. It is +usually best to start from the interface file that f2py can produce +(where it gets its default behavior from). To get f2py to generate the +interface file use the -h option:: + + f2py -h add.pyf -m add add.f + +This command leaves the file add.pyf in the current directory. The +section of this file corresponding to zadd is: + +.. code-block:: none + + subroutine zadd(a,b,c,n) ! in :add:add.f + double complex dimension(*) :: a + double complex dimension(*) :: b + double complex dimension(*) :: c + integer :: n + end subroutine zadd + +By placing intent directives and checking code, the interface can be +cleaned up quite a bit until the Python module method is both easier +to use and more robust. + +.. code-block:: none + + subroutine zadd(a,b,c,n) ! in :add:add.f + double complex dimension(n) :: a + double complex dimension(n) :: b + double complex intent(out),dimension(n) :: c + integer intent(hide),depend(a) :: n=len(a) + end subroutine zadd + +The intent directive, intent(out) is used to tell f2py that ``c`` is +an output variable and should be created by the interface before being +passed to the underlying code. The intent(hide) directive tells f2py +to not allow the user to specify the variable, ``n``, but instead to +get it from the size of ``a``. The depend( ``a`` ) directive is +necessary to tell f2py that the value of n depends on the input a (so +that it won't try to create the variable n until the variable a is +created). + +After modifying ``add.pyf``, the new python module file can be generated +by compiling both ``add.f95`` and ``add.pyf``:: + + f2py -c add.pyf add.f95 + +The new interface has docstring:: + + >>> import add + >>> print add.zadd.__doc__ + zadd - Function signature: + c = zadd(a,b) + Required arguments: + a : input rank-1 array('D') with bounds (n) + b : input rank-1 array('D') with bounds (n) + Return objects: + c : rank-1 array('D') with bounds (n) + +Now, the function can be called in a much more robust way:: + + >>> add.zadd([1,2,3],[4,5,6]) + array([ 5.+0.j, 7.+0.j, 9.+0.j]) + +Notice the automatic conversion to the correct format that occurred. + + +Inserting directives in Fortran source +-------------------------------------- + +The nice interface can also be generated automatically by placing the +variable directives as special comments in the original fortran code. +Thus, if I modify the source code to contain: + +.. code-block:: none + + C + SUBROUTINE ZADD(A,B,C,N) + C + CF2PY INTENT(OUT) :: C + CF2PY INTENT(HIDE) :: N + CF2PY DOUBLE COMPLEX :: A(N) + CF2PY DOUBLE COMPLEX :: B(N) + CF2PY DOUBLE COMPLEX :: C(N) + DOUBLE COMPLEX A(*) + DOUBLE COMPLEX B(*) + DOUBLE COMPLEX C(*) + INTEGER N + DO 20 J = 1, N + C(J) = A(J) + B(J) + 20 CONTINUE + END + +Then, I can compile the extension module using:: + + f2py -c -m add add.f + +The resulting signature for the function add.zadd is exactly the same +one that was created previously. If the original source code had +contained ``A(N)`` instead of ``A(*)`` and so forth with ``B`` and ``C``, +then I could obtain (nearly) the same interface simply by placing the +``INTENT(OUT) :: C`` comment line in the source code. The only difference +is that ``N`` would be an optional input that would default to the length +of ``A``. + + +A filtering example +------------------- + +For comparison with the other methods to be discussed. Here is another +example of a function that filters a two-dimensional array of double +precision floating-point numbers using a fixed averaging filter. The +advantage of using Fortran to index into multi-dimensional arrays +should be clear from this example. + +.. code-block:: none + + SUBROUTINE DFILTER2D(A,B,M,N) + C + DOUBLE PRECISION A(M,N) + DOUBLE PRECISION B(M,N) + INTEGER N, M + CF2PY INTENT(OUT) :: B + CF2PY INTENT(HIDE) :: N + CF2PY INTENT(HIDE) :: M + DO 20 I = 2,M-1 + DO 40 J=2,N-1 + B(I,J) = A(I,J) + + $ (A(I-1,J)+A(I+1,J) + + $ A(I,J-1)+A(I,J+1) )*0.5D0 + + $ (A(I-1,J-1) + A(I-1,J+1) + + $ A(I+1,J-1) + A(I+1,J+1))*0.25D0 + 40 CONTINUE + 20 CONTINUE + END + +This code can be compiled and linked into an extension module named +filter using:: + + f2py -c -m filter filter.f + +This will produce an extension module named filter.so in the current +directory with a method named dfilter2d that returns a filtered +version of the input. + + +Calling f2py from Python +------------------------ + +The f2py program is written in Python and can be run from inside your code +to compile Fortran code at runtime, as follows: + +.. code-block:: python + + from numpy import f2py + with open("add.f") as sourcefile: + sourcecode = sourcefile.read() + f2py.compile(sourcecode, modulename='add') + import add + +The source string can be any valid Fortran code. If you want to save +the extension-module source code then a suitable file-name can be +provided by the ``source_fn`` keyword to the compile function. + + +Automatic extension module generation +------------------------------------- + +If you want to distribute your f2py extension module, then you only +need to include the .pyf file and the Fortran code. The distutils +extensions in NumPy allow you to define an extension module entirely +in terms of this interface file. A valid ``setup.py`` file allowing +distribution of the ``add.f`` module (as part of the package +``f2py_examples`` so that it would be loaded as ``f2py_examples.add``) is: + +.. code-block:: python + + def configuration(parent_package='', top_path=None) + from numpy.distutils.misc_util import Configuration + config = Configuration('f2py_examples',parent_package, top_path) + config.add_extension('add', sources=['add.pyf','add.f']) + return config + + if __name__ == '__main__': + from numpy.distutils.core import setup + setup(**configuration(top_path='').todict()) + +Installation of the new package is easy using:: + + python setup.py install + +assuming you have the proper permissions to write to the main site- +packages directory for the version of Python you are using. For the +resulting package to work, you need to create a file named ``__init__.py`` +(in the same directory as ``add.pyf``). Notice the extension module is +defined entirely in terms of the ``add.pyf`` and ``add.f`` files. The +conversion of the .pyf file to a .c file is handled by `numpy.disutils`. + + +Conclusion +---------- + +The interface definition file (.pyf) is how you can fine-tune the +interface between Python and Fortran. There is decent documentation +for f2py found in the numpy/f2py/docs directory where-ever NumPy is +installed on your system (usually under site-packages). There is also +more information on using f2py (including how to use it to wrap C +codes) at http://www.scipy.org/Cookbook under the "Using NumPy with +Other Languages" heading. + +The f2py method of linking compiled code is currently the most +sophisticated and integrated approach. It allows clean separation of +Python with compiled code while still allowing for separate +distribution of the extension module. The only draw-back is that it +requires the existence of a Fortran compiler in order for a user to +install the code. However, with the existence of the free-compilers +g77, gfortran, and g95, as well as high-quality commercial compilers, +this restriction is not particularly onerous. In my opinion, Fortran +is still the easiest way to write fast and clear code for scientific +computing. It handles complex numbers, and multi-dimensional indexing +in the most straightforward way. Be aware, however, that some Fortran +compilers will not be able to optimize code as well as good hand- +written C-code. + +.. index:: + single: f2py + + +Cython +====== + +`Cython `_ is a compiler for a Python dialect that adds +(optional) static typing for speed, and allows mixing C or C++ code +into your modules. It produces C or C++ extensions that can be compiled +and imported in Python code. + +If you are writing an extension module that will include quite a bit of your +own algorithmic code as well, then Cython is a good match. Among its +features is the ability to easily and quickly +work with multidimensional arrays. + +.. index:: + single: cython + +Notice that Cython is an extension-module generator only. Unlike f2py, +it includes no automatic facility for compiling and linking +the extension module (which must be done in the usual fashion). It +does provide a modified distutils class called ``build_ext`` which lets +you build an extension module from a ``.pyx`` source. Thus, you could +write in a ``setup.py`` file: + +.. code-block:: python + + from Cython.Distutils import build_ext + from distutils.extension import Extension + from distutils.core import setup + import numpy + + setup(name='mine', description='Nothing', + ext_modules=[Extension('filter', ['filter.pyx'], + include_dirs=[numpy.get_include()])], + cmdclass = {'build_ext':build_ext}) + +Adding the NumPy include directory is, of course, only necessary if +you are using NumPy arrays in the extension module (which is what we +assume you are using Cython for). The distutils extensions in NumPy +also include support for automatically producing the extension-module +and linking it from a ``.pyx`` file. It works so that if the user does +not have Cython installed, then it looks for a file with the same +file-name but a ``.c`` extension which it then uses instead of trying +to produce the ``.c`` file again. + +If you just use Cython to compile a standard Python module, then you +will get a C extension module that typically runs a bit faster than the +equivalent Python module. Further speed increases can be gained by using +the ``cdef`` keyword to statically define C variables. + +Let's look at two examples we've seen before to see how they might be +implemented using Cython. These examples were compiled into extension +modules using Cython 0.21.1. + + +Complex addition in Cython +-------------------------- + +Here is part of a Cython module named ``add.pyx`` which implements the +complex addition functions we previously implemented using f2py: + +.. code-block:: none + + cimport cython + cimport numpy as np + import numpy as np + + # We need to initialize NumPy. + np.import_array() + + #@cython.boundscheck(False) + def zadd(in1, in2): + cdef double complex[:] a = in1.ravel() + cdef double complex[:] b = in2.ravel() + + out = np.empty(a.shape[0], np.complex64) + cdef double complex[:] c = out.ravel() + + for i in range(c.shape[0]): + c[i].real = a[i].real + b[i].real + c[i].imag = a[i].imag + b[i].imag + + return out + +This module shows use of the ``cimport`` statement to load the definitions +from the ``numpy.pxd`` header that ships with Cython. It looks like NumPy is +imported twice; ``cimport`` only makes the NumPy C-API available, while the +regular ``import`` causes a Python-style import at runtime and makes it +possible to call into the familiar NumPy Python API. + +The example also demonstrates Cython's "typed memoryviews", which are like +NumPy arrays at the C level, in the sense that they are shaped and strided +arrays that know their own extent (unlike a C array addressed through a bare +pointer). The syntax ``double complex[:]`` denotes a one-dimensional array +(vector) of doubles, with arbitrary strides. A contiguous array of ints would +be ``int[::1]``, while a matrix of floats would be ``float[:, :]``. + +Shown commented is the ``cython.boundscheck`` decorator, which turns +bounds-checking for memory view accesses on or off on a per-function basis. +We can use this to further speed up our code, at the expense of safety +(or a manual check prior to entering the loop). + +Other than the view syntax, the function is immediately readable to a Python +programmer. Static typing of the variable ``i`` is implicit. Instead of the +view syntax, we could also have used Cython's special NumPy array syntax, +but the view syntax is preferred. + + +Image filter in Cython +---------------------- + +The two-dimensional example we created using Fortran is just as easy to write +in Cython: + +.. code-block:: none + + cimport numpy as np + import numpy as np + + np.import_array() + + def filter(img): + cdef double[:, :] a = np.asarray(img, dtype=np.double) + out = np.zeros(img.shape, dtype=np.double) + cdef double[:, ::1] b = out + + cdef np.npy_intp i, j + + for i in range(1, a.shape[0] - 1): + for j in range(1, a.shape[1] - 1): + b[i, j] = (a[i, j] + + .5 * ( a[i-1, j] + a[i+1, j] + + a[i, j-1] + a[i, j+1]) + + .25 * ( a[i-1, j-1] + a[i-1, j+1] + + a[i+1, j-1] + a[i+1, j+1])) + + return out + +This 2-d averaging filter runs quickly because the loop is in C and +the pointer computations are done only as needed. If the code above is +compiled as a module ``image``, then a 2-d image, ``img``, can be filtered +using this code very quickly using: + +.. code-block:: python + + import image + out = image.filter(img) + +Regarding the code, two things are of note: firstly, it is impossible to +return a memory view to Python. Instead, a NumPy array ``out`` is first +created, and then a view ``b`` onto this array is used for the computation. +Secondly, the view ``b`` is typed ``double[:, ::1]``. This means 2-d array +with contiguous rows, i.e., C matrix order. Specifying the order explicitly +can speed up some algorithms since they can skip stride computations. + + +Conclusion +---------- + +Cython is the extension mechanism of choice for several scientific Python +libraries, including Scipy, Pandas, SAGE, scikit-image and scikit-learn, +as well as the XML processing library LXML. +The language and compiler are well-maintained. + +There are several disadvantages of using Cython: + +1. When coding custom algorithms, and sometimes when wrapping existing C + libraries, some familiarity with C is required. In particular, when using + C memory management (``malloc`` and friends), it's easy to introduce + memory leaks. However, just compiling a Python module renamed to ``.pyx`` + can already speed it up, and adding a few type declarations can give + dramatic speedups in some code. + +2. It is easy to lose a clean separation between Python and C which makes + re-using your C-code for other non-Python-related projects more + difficult. + +3. The C-code generated by Cython is hard to read and modify (and typically + compiles with annoying but harmless warnings). + +One big advantage of Cython-generated extension modules is that they are +easy to distribute. In summary, Cython is a very capable tool for either +gluing C code or generating an extension module quickly and should not be +over-looked. It is especially useful for people that can't or won't write +C or Fortran code. + +.. index:: + single: cython + + +ctypes +====== + +`Ctypes `_ +is a Python extension module, included in the stdlib, that +allows you to call an arbitrary function in a shared library directly +from Python. This approach allows you to interface with C-code directly +from Python. This opens up an enormous number of libraries for use from +Python. The drawback, however, is that coding mistakes can lead to ugly +program crashes very easily (just as can happen in C) because there is +little type or bounds checking done on the parameters. This is especially +true when array data is passed in as a pointer to a raw memory +location. The responsibility is then on you that the subroutine will +not access memory outside the actual array area. But, if you don't +mind living a little dangerously ctypes can be an effective tool for +quickly taking advantage of a large shared library (or writing +extended functionality in your own shared library). + +.. index:: + single: ctypes + +Because the ctypes approach exposes a raw interface to the compiled +code it is not always tolerant of user mistakes. Robust use of the +ctypes module typically involves an additional layer of Python code in +order to check the data types and array bounds of objects passed to +the underlying subroutine. This additional layer of checking (not to +mention the conversion from ctypes objects to C-data-types that ctypes +itself performs), will make the interface slower than a hand-written +extension-module interface. However, this overhead should be negligible +if the C-routine being called is doing any significant amount of work. +If you are a great Python programmer with weak C skills, ctypes is an +easy way to write a useful interface to a (shared) library of compiled +code. + +To use ctypes you must + +1. Have a shared library. + +2. Load the shared library. + +3. Convert the python objects to ctypes-understood arguments. + +4. Call the function from the library with the ctypes arguments. + + +Having a shared library +----------------------- + +There are several requirements for a shared library that can be used +with ctypes that are platform specific. This guide assumes you have +some familiarity with making a shared library on your system (or +simply have a shared library available to you). Items to remember are: + +- A shared library must be compiled in a special way ( *e.g.* using + the ``-shared`` flag with gcc). + +- On some platforms (*e.g.* Windows) , a shared library requires a + .def file that specifies the functions to be exported. For example a + mylib.def file might contain:: + + LIBRARY mylib.dll + EXPORTS + cool_function1 + cool_function2 + + Alternatively, you may be able to use the storage-class specifier + ``__declspec(dllexport)`` in the C-definition of the function to avoid + the need for this ``.def`` file. + +There is no standard way in Python distutils to create a standard +shared library (an extension module is a "special" shared library +Python understands) in a cross-platform manner. Thus, a big +disadvantage of ctypes at the time of writing this book is that it is +difficult to distribute in a cross-platform manner a Python extension +that uses ctypes and includes your own code which should be compiled +as a shared library on the users system. + + +Loading the shared library +-------------------------- + +A simple, but robust way to load the shared library is to get the +absolute path name and load it using the cdll object of ctypes: + +.. code-block:: python + + lib = ctypes.cdll[] + +However, on Windows accessing an attribute of the ``cdll`` method will +load the first DLL by that name found in the current directory or on +the PATH. Loading the absolute path name requires a little finesse for +cross-platform work since the extension of shared libraries varies. +There is a ``ctypes.util.find_library`` utility available that can +simplify the process of finding the library to load but it is not +foolproof. Complicating matters, different platforms have different +default extensions used by shared libraries (e.g. .dll -- Windows, .so +-- Linux, .dylib -- Mac OS X). This must also be taken into account if +you are using ctypes to wrap code that needs to work on several +platforms. + +NumPy provides a convenience function called +``ctypeslib.load_library`` (name, path). This function takes the name +of the shared library (including any prefix like 'lib' but excluding +the extension) and a path where the shared library can be located. It +returns a ctypes library object or raises an ``OSError`` if the library +cannot be found or raises an ``ImportError`` if the ctypes module is not +available. (Windows users: the ctypes library object loaded using +``load_library`` is always loaded assuming cdecl calling convention. +See the ctypes documentation under ``ctypes.windll`` and/or ``ctypes.oledll`` +for ways to load libraries under other calling conventions). + +The functions in the shared library are available as attributes of the +ctypes library object (returned from ``ctypeslib.load_library``) or +as items using ``lib['func_name']`` syntax. The latter method for +retrieving a function name is particularly useful if the function name +contains characters that are not allowable in Python variable names. + + +Converting arguments +-------------------- + +Python ints/longs, strings, and unicode objects are automatically +converted as needed to equivalent ctypes arguments The None object is +also converted automatically to a NULL pointer. All other Python +objects must be converted to ctypes-specific types. There are two ways +around this restriction that allow ctypes to integrate with other +objects. + +1. Don't set the argtypes attribute of the function object and define an + :obj:`_as_parameter_` method for the object you want to pass in. The + :obj:`_as_parameter_` method must return a Python int which will be passed + directly to the function. + +2. Set the argtypes attribute to a list whose entries contain objects + with a classmethod named from_param that knows how to convert your + object to an object that ctypes can understand (an int/long, string, + unicode, or object with the :obj:`_as_parameter_` attribute). + +NumPy uses both methods with a preference for the second method +because it can be safer. The ctypes attribute of the ndarray returns +an object that has an ``_as_parameter_`` attribute which returns an +integer representing the address of the ndarray to which it is +associated. As a result, one can pass this ctypes attribute object +directly to a function expecting a pointer to the data in your +ndarray. The caller must be sure that the ndarray object is of the +correct type, shape, and has the correct flags set or risk nasty +crashes if the data-pointer to inappropriate arrays are passed in. + +To implement the second method, NumPy provides the class-factory +function :func:`ndpointer` in the :mod:`ctypeslib` module. This +class-factory function produces an appropriate class that can be +placed in an argtypes attribute entry of a ctypes function. The class +will contain a from_param method which ctypes will use to convert any +ndarray passed in to the function to a ctypes-recognized object. In +the process, the conversion will perform checking on any properties of +the ndarray that were specified by the user in the call to :func:`ndpointer`. +Aspects of the ndarray that can be checked include the data-type, the +number-of-dimensions, the shape, and/or the state of the flags on any +array passed. The return value of the from_param method is the ctypes +attribute of the array which (because it contains the ``_as_parameter_`` +attribute pointing to the array data area) can be used by ctypes +directly. + +The ctypes attribute of an ndarray is also endowed with additional +attributes that may be convenient when passing additional information +about the array into a ctypes function. The attributes **data**, +**shape**, and **strides** can provide ctypes compatible types +corresponding to the data-area, the shape, and the strides of the +array. The data attribute returns a ``c_void_p`` representing a +pointer to the data area. The shape and strides attributes each return +an array of ctypes integers (or None representing a NULL pointer, if a +0-d array). The base ctype of the array is a ctype integer of the same +size as a pointer on the platform. There are also methods +``data_as({ctype})``, ``shape_as()``, and ``strides_as()``. These return the data as a ctype object of your choice and +the shape/strides arrays using an underlying base type of your choice. +For convenience, the ``ctypeslib`` module also contains ``c_intp`` as +a ctypes integer data-type whose size is the same as the size of +``c_void_p`` on the platform (its value is None if ctypes is not +installed). + + +Calling the function +-------------------- + +The function is accessed as an attribute of or an item from the loaded +shared-library. Thus, if ``./mylib.so`` has a function named +``cool_function1`` , I could access this function either as: + +.. code-block:: python + + lib = numpy.ctypeslib.load_library('mylib','.') + func1 = lib.cool_function1 # or equivalently + func1 = lib['cool_function1'] + +In ctypes, the return-value of a function is set to be 'int' by +default. This behavior can be changed by setting the restype attribute +of the function. Use None for the restype if the function has no +return value ('void'): + +.. code-block:: python + + func1.restype = None + +As previously discussed, you can also set the argtypes attribute of +the function in order to have ctypes check the types of the input +arguments when the function is called. Use the :func:`ndpointer` factory +function to generate a ready-made class for data-type, shape, and +flags checking on your new function. The :func:`ndpointer` function has the +signature + +.. function:: ndpointer(dtype=None, ndim=None, shape=None, flags=None) + + Keyword arguments with the value ``None`` are not checked. + Specifying a keyword enforces checking of that aspect of the + ndarray on conversion to a ctypes-compatible object. The dtype + keyword can be any object understood as a data-type object. The + ndim keyword should be an integer, and the shape keyword should be + an integer or a sequence of integers. The flags keyword specifies + the minimal flags that are required on any array passed in. This + can be specified as a string of comma separated requirements, an + integer indicating the requirement bits OR'd together, or a flags + object returned from the flags attribute of an array with the + necessary requirements. + +Using an ndpointer class in the argtypes method can make it +significantly safer to call a C function using ctypes and the data- +area of an ndarray. You may still want to wrap the function in an +additional Python wrapper to make it user-friendly (hiding some +obvious arguments and making some arguments output arguments). In this +process, the ``requires`` function in NumPy may be useful to return the right +kind of array from a given input. + + +Complete example +---------------- + +In this example, I will show how the addition function and the filter +function implemented previously using the other approaches can be +implemented using ctypes. First, the C code which implements the +algorithms contains the functions ``zadd``, ``dadd``, ``sadd``, ``cadd``, +and ``dfilter2d``. The ``zadd`` function is: + +.. code-block:: c + + /* Add arrays of contiguous data */ + typedef struct {double real; double imag;} cdouble; + typedef struct {float real; float imag;} cfloat; + void zadd(cdouble *a, cdouble *b, cdouble *c, long n) + { + while (n--) { + c->real = a->real + b->real; + c->imag = a->imag + b->imag; + a++; b++; c++; + } + } + +with similar code for ``cadd``, ``dadd``, and ``sadd`` that handles complex +float, double, and float data-types, respectively: + +.. code-block:: c + + void cadd(cfloat *a, cfloat *b, cfloat *c, long n) + { + while (n--) { + c->real = a->real + b->real; + c->imag = a->imag + b->imag; + a++; b++; c++; + } + } + void dadd(double *a, double *b, double *c, long n) + { + while (n--) { + *c++ = *a++ + *b++; + } + } + void sadd(float *a, float *b, float *c, long n) + { + while (n--) { + *c++ = *a++ + *b++; + } + } + +The ``code.c`` file also contains the function ``dfilter2d``: + +.. code-block:: c + + /* + * Assumes b is contiguous and has strides that are multiples of + * sizeof(double) + */ + void + dfilter2d(double *a, double *b, ssize_t *astrides, ssize_t *dims) + { + ssize_t i, j, M, N, S0, S1; + ssize_t r, c, rm1, rp1, cp1, cm1; + + M = dims[0]; N = dims[1]; + S0 = astrides[0]/sizeof(double); + S1 = astrides[1]/sizeof(double); + for (i = 1; i < M - 1; i++) { + r = i*S0; + rp1 = r + S0; + rm1 = r - S0; + for (j = 1; j < N - 1; j++) { + c = j*S1; + cp1 = j + S1; + cm1 = j - S1; + b[i*N + j] = a[r + c] + + (a[rp1 + c] + a[rm1 + c] + + a[r + cp1] + a[r + cm1])*0.5 + + (a[rp1 + cp1] + a[rp1 + cm1] + + a[rm1 + cp1] + a[rm1 + cp1])*0.25; + } + } + } + +A possible advantage this code has over the Fortran-equivalent code is +that it takes arbitrarily strided (i.e. non-contiguous arrays) and may +also run faster depending on the optimization capability of your +compiler. But, it is an obviously more complicated than the simple code +in ``filter.f``. This code must be compiled into a shared library. On my +Linux system this is accomplished using:: + + gcc -o code.so -shared code.c + +Which creates a shared_library named code.so in the current directory. +On Windows don't forget to either add ``__declspec(dllexport)`` in front +of void on the line preceding each function definition, or write a +code.def file that lists the names of the functions to be exported. + +A suitable Python interface to this shared library should be +constructed. To do this create a file named interface.py with the +following lines at the top: + +.. code-block:: python + + __all__ = ['add', 'filter2d'] + + import numpy as N + import os + + _path = os.path.dirname('__file__') + lib = N.ctypeslib.load_library('code', _path) + _typedict = {'zadd' : complex, 'sadd' : N.single, + 'cadd' : N.csingle, 'dadd' : float} + for name in _typedict.keys(): + val = getattr(lib, name) + val.restype = None + _type = _typedict[name] + val.argtypes = [N.ctypeslib.ndpointer(_type, + flags='aligned, contiguous'), + N.ctypeslib.ndpointer(_type, + flags='aligned, contiguous'), + N.ctypeslib.ndpointer(_type, + flags='aligned, contiguous,'\ + 'writeable'), + N.ctypeslib.c_intp] + +This code loads the shared library named ``code.{ext}`` located in the +same path as this file. It then adds a return type of void to the +functions contained in the library. It also adds argument checking to +the functions in the library so that ndarrays can be passed as the +first three arguments along with an integer (large enough to hold a +pointer on the platform) as the fourth argument. + +Setting up the filtering function is similar and allows the filtering +function to be called with ndarray arguments as the first two +arguments and with pointers to integers (large enough to handle the +strides and shape of an ndarray) as the last two arguments.: + +.. code-block:: python + + lib.dfilter2d.restype=None + lib.dfilter2d.argtypes = [N.ctypeslib.ndpointer(float, ndim=2, + flags='aligned'), + N.ctypeslib.ndpointer(float, ndim=2, + flags='aligned, contiguous,'\ + 'writeable'), + ctypes.POINTER(N.ctypeslib.c_intp), + ctypes.POINTER(N.ctypeslib.c_intp)] + +Next, define a simple selection function that chooses which addition +function to call in the shared library based on the data-type: + +.. code-block:: python + + def select(dtype): + if dtype.char in ['?bBhHf']: + return lib.sadd, single + elif dtype.char in ['F']: + return lib.cadd, csingle + elif dtype.char in ['DG']: + return lib.zadd, complex + else: + return lib.dadd, float + return func, ntype + +Finally, the two functions to be exported by the interface can be +written simply as: + +.. code-block:: python + + def add(a, b): + requires = ['CONTIGUOUS', 'ALIGNED'] + a = N.asanyarray(a) + func, dtype = select(a.dtype) + a = N.require(a, dtype, requires) + b = N.require(b, dtype, requires) + c = N.empty_like(a) + func(a,b,c,a.size) + return c + +and: + +.. code-block:: python + + def filter2d(a): + a = N.require(a, float, ['ALIGNED']) + b = N.zeros_like(a) + lib.dfilter2d(a, b, a.ctypes.strides, a.ctypes.shape) + return b + + +Conclusion +---------- + +.. index:: + single: ctypes + +Using ctypes is a powerful way to connect Python with arbitrary +C-code. Its advantages for extending Python include + +- clean separation of C code from Python code + + - no need to learn a new syntax except Python and C + + - allows re-use of C code + + - functionality in shared libraries written for other purposes can be + obtained with a simple Python wrapper and search for the library. + + +- easy integration with NumPy through the ctypes attribute + +- full argument checking with the ndpointer class factory + +Its disadvantages include + +- It is difficult to distribute an extension module made using ctypes + because of a lack of support for building shared libraries in + distutils (but I suspect this will change in time). + +- You must have shared-libraries of your code (no static libraries). + +- Very little support for C++ code and its different library-calling + conventions. You will probably need a C wrapper around C++ code to use + with ctypes (or just use Boost.Python instead). + +Because of the difficulty in distributing an extension module made +using ctypes, f2py and Cython are still the easiest ways to extend Python +for package creation. However, ctypes is in some cases a useful alternative. +This should bring more features to ctypes that should +eliminate the difficulty in extending Python and distributing the +extension using ctypes. + + +Additional tools you may find useful +==================================== + +These tools have been found useful by others using Python and so are +included here. They are discussed separately because they are +either older ways to do things now handled by f2py, Cython, or ctypes +(SWIG, PyFort) or because I don't know much about them (SIP, Boost). +I have not added links to these +methods because my experience is that you can find the most relevant +link faster using Google or some other search engine, and any links +provided here would be quickly dated. Do not assume that just because +it is included in this list, I don't think the package deserves your +attention. I'm including information about these packages because many +people have found them useful and I'd like to give you as many options +as possible for tackling the problem of easily integrating your code. + + +SWIG +---- + +.. index:: + single: swig + +Simplified Wrapper and Interface Generator (SWIG) is an old and fairly +stable method for wrapping C/C++-libraries to a large variety of other +languages. It does not specifically understand NumPy arrays but can be +made useable with NumPy through the use of typemaps. There are some +sample typemaps in the numpy/tools/swig directory under numpy.i together +with an example module that makes use of them. SWIG excels at wrapping +large C/C++ libraries because it can (almost) parse their headers and +auto-produce an interface. Technically, you need to generate a ``.i`` +file that defines the interface. Often, however, this ``.i`` file can +be parts of the header itself. The interface usually needs a bit of +tweaking to be very useful. This ability to parse C/C++ headers and +auto-generate the interface still makes SWIG a useful approach to +adding functionalilty from C/C++ into Python, despite the other +methods that have emerged that are more targeted to Python. SWIG can +actually target extensions for several languages, but the typemaps +usually have to be language-specific. Nonetheless, with modifications +to the Python-specific typemaps, SWIG can be used to interface a +library with other languages such as Perl, Tcl, and Ruby. + +My experience with SWIG has been generally positive in that it is +relatively easy to use and quite powerful. I used to use it quite +often before becoming more proficient at writing C-extensions. +However, I struggled writing custom interfaces with SWIG because it +must be done using the concept of typemaps which are not Python +specific and are written in a C-like syntax. Therefore, I tend to +prefer other gluing strategies and would only attempt to use SWIG to +wrap a very-large C/C++ library. Nonetheless, there are others who use +SWIG quite happily. + + +SIP +--- + +.. index:: + single: SIP + +SIP is another tool for wrapping C/C++ libraries that is Python +specific and appears to have very good support for C++. Riverbank +Computing developed SIP in order to create Python bindings to the QT +library. An interface file must be written to generate the binding, +but the interface file looks a lot like a C/C++ header file. While SIP +is not a full C++ parser, it understands quite a bit of C++ syntax as +well as its own special directives that allow modification of how the +Python binding is accomplished. It also allows the user to define +mappings between Python types and C/C++ structures and classes. + + +Boost Python +------------ + +.. index:: + single: Boost.Python + +Boost is a repository of C++ libraries and Boost.Python is one of +those libraries which provides a concise interface for binding C++ +classes and functions to Python. The amazing part of the Boost.Python +approach is that it works entirely in pure C++ without introducing a +new syntax. Many users of C++ report that Boost.Python makes it +possible to combine the best of both worlds in a seamless fashion. I +have not used Boost.Python because I am not a big user of C++ and +using Boost to wrap simple C-subroutines is usually over-kill. It's +primary purpose is to make C++ classes available in Python. So, if you +have a set of C++ classes that need to be integrated cleanly into +Python, consider learning about and using Boost.Python. + + +PyFort +------ + +PyFort is a nice tool for wrapping Fortran and Fortran-like C-code +into Python with support for Numeric arrays. It was written by Paul +Dubois, a distinguished computer scientist and the very first +maintainer of Numeric (now retired). It is worth mentioning in the +hopes that somebody will update PyFort to work with NumPy arrays as +well which now support either Fortran or C-style contiguous arrays. diff --git a/doc/source/user/c-info.rst b/doc/source/user/c-info.rst new file mode 100644 index 0000000..0ac0ed2 --- /dev/null +++ b/doc/source/user/c-info.rst @@ -0,0 +1,10 @@ +################# +Using NumPy C-API +################# + +.. toctree:: + + c-info.how-to-extend + c-info.python-as-glue + c-info.ufunc-tutorial + c-info.beyond-basics diff --git a/doc/source/user/c-info.ufunc-tutorial.rst b/doc/source/user/c-info.ufunc-tutorial.rst new file mode 100644 index 0000000..addc38f --- /dev/null +++ b/doc/source/user/c-info.ufunc-tutorial.rst @@ -0,0 +1,1210 @@ +********************** +Writing your own ufunc +********************** + +| I have the Power! +| --- *He-Man* + + +.. _`sec:Creating-a-new`: + +Creating a new universal function +================================= + +.. index:: + pair: ufunc; adding new + +Before reading this, it may help to familiarize yourself with the basics +of C extensions for Python by reading/skimming the tutorials in Section 1 +of `Extending and Embedding the Python Interpreter +`_ and in `How to extend +NumPy `_ + +The umath module is a computer-generated C-module that creates many +ufuncs. It provides a great many examples of how to create a universal +function. Creating your own ufunc that will make use of the ufunc +machinery is not difficult either. Suppose you have a function that +you want to operate element-by-element over its inputs. By creating a +new ufunc you will obtain a function that handles + +- broadcasting + +- N-dimensional looping + +- automatic type-conversions with minimal memory usage + +- optional output arrays + +It is not difficult to create your own ufunc. All that is required is +a 1-d loop for each data-type you want to support. Each 1-d loop must +have a specific signature, and only ufuncs for fixed-size data-types +can be used. The function call used to create a new ufunc to work on +built-in data-types is given below. A different mechanism is used to +register ufuncs for user-defined data-types. + +In the next several sections we give example code that can be +easily modified to create your own ufuncs. The examples are +successively more complete or complicated versions of the logit +function, a common function in statistical modeling. Logit is also +interesting because, due to the magic of IEEE standards (specifically +IEEE 754), all of the logit functions created below +automatically have the following behavior. + +>>> logit(0) +-inf +>>> logit(1) +inf +>>> logit(2) +nan +>>> logit(-2) +nan + +This is wonderful because the function writer doesn't have to +manually propagate infs or nans. + +.. _`sec:Non-numpy-example`: + +Example Non-ufunc extension +=========================== + +.. index:: + pair: ufunc; adding new + +For comparison and general edification of the reader we provide +a simple implementation of a C extension of logit that uses no +numpy. + +To do this we need two files. The first is the C file which contains +the actual code, and the second is the setup.py file used to create +the module. + + .. code-block:: c + + #include + #include + + /* + * spammodule.c + * This is the C code for a non-numpy Python extension to + * define the logit function, where logit(p) = log(p/(1-p)). + * This function will not work on numpy arrays automatically. + * numpy.vectorize must be called in python to generate + * a numpy-friendly function. + * + * Details explaining the Python-C API can be found under + * 'Extending and Embedding' and 'Python/C API' at + * docs.python.org . + */ + + + /* This declares the logit function */ + static PyObject* spam_logit(PyObject *self, PyObject *args); + + + /* + * This tells Python what methods this module has. + * See the Python-C API for more information. + */ + static PyMethodDef SpamMethods[] = { + {"logit", + spam_logit, + METH_VARARGS, "compute logit"}, + {NULL, NULL, 0, NULL} + }; + + + /* + * This actually defines the logit function for + * input args from Python. + */ + + static PyObject* spam_logit(PyObject *self, PyObject *args) + { + double p; + + /* This parses the Python argument into a double */ + if(!PyArg_ParseTuple(args, "d", &p)) { + return NULL; + } + + /* THE ACTUAL LOGIT FUNCTION */ + p = p/(1-p); + p = log(p); + + /*This builds the answer back into a python object */ + return Py_BuildValue("d", p); + } + + + /* This initiates the module using the above definitions. */ + #if PY_VERSION_HEX >= 0x03000000 + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "spam", + NULL, + -1, + SpamMethods, + NULL, + NULL, + NULL, + NULL + }; + + PyMODINIT_FUNC PyInit_spam(void) + { + PyObject *m; + m = PyModule_Create(&moduledef); + if (!m) { + return NULL; + } + return m; + } + #else + PyMODINIT_FUNC initspam(void) + { + PyObject *m; + + m = Py_InitModule("spam", SpamMethods); + if (m == NULL) { + return; + } + } + #endif + +To use the setup.py file, place setup.py and spammodule.c in the same +folder. Then python setup.py build will build the module to import, +or setup.py install will install the module to your site-packages +directory. + + .. code-block:: python + + ''' + setup.py file for spammodule.c + + Calling + $python setup.py build_ext --inplace + will build the extension library in the current file. + + Calling + $python setup.py build + will build a file that looks like ./build/lib*, where + lib* is a file that begins with lib. The library will + be in this file and end with a C library extension, + such as .so + + Calling + $python setup.py install + will install the module in your site-packages file. + + See the distutils section of + 'Extending and Embedding the Python Interpreter' + at docs.python.org for more information. + ''' + + + from distutils.core import setup, Extension + + module1 = Extension('spam', sources=['spammodule.c'], + include_dirs=['/usr/local/lib']) + + setup(name = 'spam', + version='1.0', + description='This is my spam package', + ext_modules = [module1]) + + +Once the spam module is imported into python, you can call logit +via spam.logit. Note that the function used above cannot be applied +as-is to numpy arrays. To do so we must call numpy.vectorize on it. +For example, if a python interpreter is opened in the file containing +the spam library or spam has been installed, one can perform the +following commands: + +>>> import numpy as np +>>> import spam +>>> spam.logit(0) +-inf +>>> spam.logit(1) +inf +>>> spam.logit(0.5) +0.0 +>>> x = np.linspace(0,1,10) +>>> spam.logit(x) +TypeError: only length-1 arrays can be converted to Python scalars +>>> f = np.vectorize(spam.logit) +>>> f(x) +array([ -inf, -2.07944154, -1.25276297, -0.69314718, -0.22314355, + 0.22314355, 0.69314718, 1.25276297, 2.07944154, inf]) + +THE RESULTING LOGIT FUNCTION IS NOT FAST! numpy.vectorize simply +loops over spam.logit. The loop is done at the C level, but the numpy +array is constantly being parsed and build back up. This is expensive. +When the author compared numpy.vectorize(spam.logit) against the +logit ufuncs constructed below, the logit ufuncs were almost exactly +4 times faster. Larger or smaller speedups are, of course, possible +depending on the nature of the function. + + +.. _`sec:NumPy-one-loop`: + +Example NumPy ufunc for one dtype +================================= + +.. index:: + pair: ufunc; adding new + +For simplicity we give a ufunc for a single dtype, the 'f8' double. +As in the previous section, we first give the .c file and then the +setup.py file used to create the module containing the ufunc. + +The place in the code corresponding to the actual computations for +the ufunc are marked with /\*BEGIN main ufunc computation\*/ and +/\*END main ufunc computation\*/. The code in between those lines is +the primary thing that must be changed to create your own ufunc. + + .. code-block:: c + + #include "Python.h" + #include "math.h" + #include "numpy/ndarraytypes.h" + #include "numpy/ufuncobject.h" + #include "numpy/npy_3kcompat.h" + + /* + * single_type_logit.c + * This is the C code for creating your own + * NumPy ufunc for a logit function. + * + * In this code we only define the ufunc for + * a single dtype. The computations that must + * be replaced to create a ufunc for + * a different function are marked with BEGIN + * and END. + * + * Details explaining the Python-C API can be found under + * 'Extending and Embedding' and 'Python/C API' at + * docs.python.org . + */ + + static PyMethodDef LogitMethods[] = { + {NULL, NULL, 0, NULL} + }; + + /* The loop definition must precede the PyMODINIT_FUNC. */ + + static void double_logit(char **args, npy_intp *dimensions, + npy_intp* steps, void* data) + { + npy_intp i; + npy_intp n = dimensions[0]; + char *in = args[0], *out = args[1]; + npy_intp in_step = steps[0], out_step = steps[1]; + + double tmp; + + for (i = 0; i < n; i++) { + /*BEGIN main ufunc computation*/ + tmp = *(double *)in; + tmp /= 1-tmp; + *((double *)out) = log(tmp); + /*END main ufunc computation*/ + + in += in_step; + out += out_step; + } + } + + /*This a pointer to the above function*/ + PyUFuncGenericFunction funcs[1] = {&double_logit}; + + /* These are the input and return dtypes of logit.*/ + static char types[2] = {NPY_DOUBLE, NPY_DOUBLE}; + + static void *data[1] = {NULL}; + + #if PY_VERSION_HEX >= 0x03000000 + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "npufunc", + NULL, + -1, + LogitMethods, + NULL, + NULL, + NULL, + NULL + }; + + PyMODINIT_FUNC PyInit_npufunc(void) + { + PyObject *m, *logit, *d; + m = PyModule_Create(&moduledef); + if (!m) { + return NULL; + } + + import_array(); + import_umath(); + + logit = PyUFunc_FromFuncAndData(funcs, data, types, 1, 1, 1, + PyUFunc_None, "logit", + "logit_docstring", 0); + + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "logit", logit); + Py_DECREF(logit); + + return m; + } + #else + PyMODINIT_FUNC initnpufunc(void) + { + PyObject *m, *logit, *d; + + + m = Py_InitModule("npufunc", LogitMethods); + if (m == NULL) { + return; + } + + import_array(); + import_umath(); + + logit = PyUFunc_FromFuncAndData(funcs, data, types, 1, 1, 1, + PyUFunc_None, "logit", + "logit_docstring", 0); + + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "logit", logit); + Py_DECREF(logit); + } + #endif + +This is a setup.py file for the above code. As before, the module +can be build via calling python setup.py build at the command prompt, +or installed to site-packages via python setup.py install. + + .. code-block:: python + + ''' + setup.py file for logit.c + Note that since this is a numpy extension + we use numpy.distutils instead of + distutils from the python standard library. + + Calling + $python setup.py build_ext --inplace + will build the extension library in the current file. + + Calling + $python setup.py build + will build a file that looks like ./build/lib*, where + lib* is a file that begins with lib. The library will + be in this file and end with a C library extension, + such as .so + + Calling + $python setup.py install + will install the module in your site-packages file. + + See the distutils section of + 'Extending and Embedding the Python Interpreter' + at docs.python.org and the documentation + on numpy.distutils for more information. + ''' + + + def configuration(parent_package='', top_path=None): + import numpy + from numpy.distutils.misc_util import Configuration + + config = Configuration('npufunc_directory', + parent_package, + top_path) + config.add_extension('npufunc', ['single_type_logit.c']) + + return config + + if __name__ == "__main__": + from numpy.distutils.core import setup + setup(configuration=configuration) + +After the above has been installed, it can be imported and used as follows. + +>>> import numpy as np +>>> import npufunc +>>> npufunc.logit(0.5) +0.0 +>>> a = np.linspace(0,1,5) +>>> npufunc.logit(a) +array([ -inf, -1.09861229, 0. , 1.09861229, inf]) + + + +.. _`sec:NumPy-many-loop`: + +Example NumPy ufunc with multiple dtypes +======================================== + +.. index:: + pair: ufunc; adding new + +We finally give an example of a full ufunc, with inner loops for +half-floats, floats, doubles, and long doubles. As in the previous +sections we first give the .c file and then the corresponding +setup.py file. + +The places in the code corresponding to the actual computations for +the ufunc are marked with /\*BEGIN main ufunc computation\*/ and +/\*END main ufunc computation\*/. The code in between those lines is +the primary thing that must be changed to create your own ufunc. + + + .. code-block:: c + + #include "Python.h" + #include "math.h" + #include "numpy/ndarraytypes.h" + #include "numpy/ufuncobject.h" + #include "numpy/halffloat.h" + + /* + * multi_type_logit.c + * This is the C code for creating your own + * NumPy ufunc for a logit function. + * + * Each function of the form type_logit defines the + * logit function for a different numpy dtype. Each + * of these functions must be modified when you + * create your own ufunc. The computations that must + * be replaced to create a ufunc for + * a different function are marked with BEGIN + * and END. + * + * Details explaining the Python-C API can be found under + * 'Extending and Embedding' and 'Python/C API' at + * docs.python.org . + * + */ + + + static PyMethodDef LogitMethods[] = { + {NULL, NULL, 0, NULL} + }; + + /* The loop definitions must precede the PyMODINIT_FUNC. */ + + static void long_double_logit(char **args, npy_intp *dimensions, + npy_intp* steps, void* data) + { + npy_intp i; + npy_intp n = dimensions[0]; + char *in = args[0], *out=args[1]; + npy_intp in_step = steps[0], out_step = steps[1]; + + long double tmp; + + for (i = 0; i < n; i++) { + /*BEGIN main ufunc computation*/ + tmp = *(long double *)in; + tmp /= 1-tmp; + *((long double *)out) = logl(tmp); + /*END main ufunc computation*/ + + in += in_step; + out += out_step; + } + } + + static void double_logit(char **args, npy_intp *dimensions, + npy_intp* steps, void* data) + { + npy_intp i; + npy_intp n = dimensions[0]; + char *in = args[0], *out = args[1]; + npy_intp in_step = steps[0], out_step = steps[1]; + + double tmp; + + for (i = 0; i < n; i++) { + /*BEGIN main ufunc computation*/ + tmp = *(double *)in; + tmp /= 1-tmp; + *((double *)out) = log(tmp); + /*END main ufunc computation*/ + + in += in_step; + out += out_step; + } + } + + static void float_logit(char **args, npy_intp *dimensions, + npy_intp* steps, void* data) + { + npy_intp i; + npy_intp n = dimensions[0]; + char *in=args[0], *out = args[1]; + npy_intp in_step = steps[0], out_step = steps[1]; + + float tmp; + + for (i = 0; i < n; i++) { + /*BEGIN main ufunc computation*/ + tmp = *(float *)in; + tmp /= 1-tmp; + *((float *)out) = logf(tmp); + /*END main ufunc computation*/ + + in += in_step; + out += out_step; + } + } + + + static void half_float_logit(char **args, npy_intp *dimensions, + npy_intp* steps, void* data) + { + npy_intp i; + npy_intp n = dimensions[0]; + char *in = args[0], *out = args[1]; + npy_intp in_step = steps[0], out_step = steps[1]; + + float tmp; + + for (i = 0; i < n; i++) { + + /*BEGIN main ufunc computation*/ + tmp = *(npy_half *)in; + tmp = npy_half_to_float(tmp); + tmp /= 1-tmp; + tmp = logf(tmp); + *((npy_half *)out) = npy_float_to_half(tmp); + /*END main ufunc computation*/ + + in += in_step; + out += out_step; + } + } + + + /*This gives pointers to the above functions*/ + PyUFuncGenericFunction funcs[4] = {&half_float_logit, + &float_logit, + &double_logit, + &long_double_logit}; + + static char types[8] = {NPY_HALF, NPY_HALF, + NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE,NPY_DOUBLE, + NPY_LONGDOUBLE, NPY_LONGDOUBLE}; + static void *data[4] = {NULL, NULL, NULL, NULL}; + + #if PY_VERSION_HEX >= 0x03000000 + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "npufunc", + NULL, + -1, + LogitMethods, + NULL, + NULL, + NULL, + NULL + }; + + PyMODINIT_FUNC PyInit_npufunc(void) + { + PyObject *m, *logit, *d; + m = PyModule_Create(&moduledef); + if (!m) { + return NULL; + } + + import_array(); + import_umath(); + + logit = PyUFunc_FromFuncAndData(funcs, data, types, 4, 1, 1, + PyUFunc_None, "logit", + "logit_docstring", 0); + + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "logit", logit); + Py_DECREF(logit); + + return m; + } + #else + PyMODINIT_FUNC initnpufunc(void) + { + PyObject *m, *logit, *d; + + + m = Py_InitModule("npufunc", LogitMethods); + if (m == NULL) { + return; + } + + import_array(); + import_umath(); + + logit = PyUFunc_FromFuncAndData(funcs, data, types, 4, 1, 1, + PyUFunc_None, "logit", + "logit_docstring", 0); + + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "logit", logit); + Py_DECREF(logit); + } + #endif + +This is a setup.py file for the above code. As before, the module +can be build via calling python setup.py build at the command prompt, +or installed to site-packages via python setup.py install. + + .. code-block:: python + + ''' + setup.py file for logit.c + Note that since this is a numpy extension + we use numpy.distutils instead of + distutils from the python standard library. + + Calling + $python setup.py build_ext --inplace + will build the extension library in the current file. + + Calling + $python setup.py build + will build a file that looks like ./build/lib*, where + lib* is a file that begins with lib. The library will + be in this file and end with a C library extension, + such as .so + + Calling + $python setup.py install + will install the module in your site-packages file. + + See the distutils section of + 'Extending and Embedding the Python Interpreter' + at docs.python.org and the documentation + on numpy.distutils for more information. + ''' + + + def configuration(parent_package='', top_path=None): + import numpy + from numpy.distutils.misc_util import Configuration + from numpy.distutils.misc_util import get_info + + #Necessary for the half-float d-type. + info = get_info('npymath') + + config = Configuration('npufunc_directory', + parent_package, + top_path) + config.add_extension('npufunc', + ['multi_type_logit.c'], + extra_info=info) + + return config + + if __name__ == "__main__": + from numpy.distutils.core import setup + setup(configuration=configuration) + +After the above has been installed, it can be imported and used as follows. + +>>> import numpy as np +>>> import npufunc +>>> npufunc.logit(0.5) +0.0 +>>> a = np.linspace(0,1,5) +>>> npufunc.logit(a) +array([ -inf, -1.09861229, 0. , 1.09861229, inf]) + + + +.. _`sec:NumPy-many-arg`: + +Example NumPy ufunc with multiple arguments/return values +========================================================= + +Our final example is a ufunc with multiple arguments. It is a modification +of the code for a logit ufunc for data with a single dtype. We +compute (A*B, logit(A*B)). + +We only give the C code as the setup.py file is exactly the same as +the setup.py file in `Example NumPy ufunc for one dtype`_, except that +the line + + .. code-block:: python + + config.add_extension('npufunc', ['single_type_logit.c']) + +is replaced with + + .. code-block:: python + + config.add_extension('npufunc', ['multi_arg_logit.c']) + +The C file is given below. The ufunc generated takes two arguments A +and B. It returns a tuple whose first element is A*B and whose second +element is logit(A*B). Note that it automatically supports broadcasting, +as well as all other properties of a ufunc. + + .. code-block:: c + + #include "Python.h" + #include "math.h" + #include "numpy/ndarraytypes.h" + #include "numpy/ufuncobject.h" + #include "numpy/halffloat.h" + + /* + * multi_arg_logit.c + * This is the C code for creating your own + * NumPy ufunc for a multiple argument, multiple + * return value ufunc. The places where the + * ufunc computation is carried out are marked + * with comments. + * + * Details explaining the Python-C API can be found under + * 'Extending and Embedding' and 'Python/C API' at + * docs.python.org . + * + */ + + + static PyMethodDef LogitMethods[] = { + {NULL, NULL, 0, NULL} + }; + + /* The loop definition must precede the PyMODINIT_FUNC. */ + + static void double_logitprod(char **args, npy_intp *dimensions, + npy_intp* steps, void* data) + { + npy_intp i; + npy_intp n = dimensions[0]; + char *in1 = args[0], *in2 = args[1]; + char *out1 = args[2], *out2 = args[3]; + npy_intp in1_step = steps[0], in2_step = steps[1]; + npy_intp out1_step = steps[2], out2_step = steps[3]; + + double tmp; + + for (i = 0; i < n; i++) { + /*BEGIN main ufunc computation*/ + tmp = *(double *)in1; + tmp *= *(double *)in2; + *((double *)out1) = tmp; + *((double *)out2) = log(tmp/(1-tmp)); + /*END main ufunc computation*/ + + in1 += in1_step; + in2 += in2_step; + out1 += out1_step; + out2 += out2_step; + } + } + + + /*This a pointer to the above function*/ + PyUFuncGenericFunction funcs[1] = {&double_logitprod}; + + /* These are the input and return dtypes of logit.*/ + + static char types[4] = {NPY_DOUBLE, NPY_DOUBLE, + NPY_DOUBLE, NPY_DOUBLE}; + + + static void *data[1] = {NULL}; + + #if PY_VERSION_HEX >= 0x03000000 + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "npufunc", + NULL, + -1, + LogitMethods, + NULL, + NULL, + NULL, + NULL + }; + + PyMODINIT_FUNC PyInit_npufunc(void) + { + PyObject *m, *logit, *d; + m = PyModule_Create(&moduledef); + if (!m) { + return NULL; + } + + import_array(); + import_umath(); + + logit = PyUFunc_FromFuncAndData(funcs, data, types, 1, 2, 2, + PyUFunc_None, "logit", + "logit_docstring", 0); + + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "logit", logit); + Py_DECREF(logit); + + return m; + } + #else + PyMODINIT_FUNC initnpufunc(void) + { + PyObject *m, *logit, *d; + + + m = Py_InitModule("npufunc", LogitMethods); + if (m == NULL) { + return; + } + + import_array(); + import_umath(); + + logit = PyUFunc_FromFuncAndData(funcs, data, types, 1, 2, 2, + PyUFunc_None, "logit", + "logit_docstring", 0); + + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "logit", logit); + Py_DECREF(logit); + } + #endif + + +.. _`sec:NumPy-struct-dtype`: + +Example NumPy ufunc with structured array dtype arguments +========================================================= + +This example shows how to create a ufunc for a structured array dtype. +For the example we show a trivial ufunc for adding two arrays with dtype +'u8,u8,u8'. The process is a bit different from the other examples since +a call to PyUFunc_FromFuncAndData doesn't fully register ufuncs for +custom dtypes and structured array dtypes. We need to also call +PyUFunc_RegisterLoopForDescr to finish setting up the ufunc. + +We only give the C code as the setup.py file is exactly the same as +the setup.py file in `Example NumPy ufunc for one dtype`_, except that +the line + + .. code-block:: python + + config.add_extension('npufunc', ['single_type_logit.c']) + +is replaced with + + .. code-block:: python + + config.add_extension('npufunc', ['add_triplet.c']) + +The C file is given below. + + .. code-block:: c + + #include "Python.h" + #include "math.h" + #include "numpy/ndarraytypes.h" + #include "numpy/ufuncobject.h" + #include "numpy/npy_3kcompat.h" + + + /* + * add_triplet.c + * This is the C code for creating your own + * NumPy ufunc for a structured array dtype. + * + * Details explaining the Python-C API can be found under + * 'Extending and Embedding' and 'Python/C API' at + * docs.python.org . + */ + + static PyMethodDef StructUfuncTestMethods[] = { + {NULL, NULL, 0, NULL} + }; + + /* The loop definition must precede the PyMODINIT_FUNC. */ + + static void add_uint64_triplet(char **args, npy_intp *dimensions, + npy_intp* steps, void* data) + { + npy_intp i; + npy_intp is1=steps[0]; + npy_intp is2=steps[1]; + npy_intp os=steps[2]; + npy_intp n=dimensions[0]; + uint64_t *x, *y, *z; + + char *i1=args[0]; + char *i2=args[1]; + char *op=args[2]; + + for (i = 0; i < n; i++) { + + x = (uint64_t*)i1; + y = (uint64_t*)i2; + z = (uint64_t*)op; + + z[0] = x[0] + y[0]; + z[1] = x[1] + y[1]; + z[2] = x[2] + y[2]; + + i1 += is1; + i2 += is2; + op += os; + } + } + + /* This a pointer to the above function */ + PyUFuncGenericFunction funcs[1] = {&add_uint64_triplet}; + + /* These are the input and return dtypes of add_uint64_triplet. */ + static char types[3] = {NPY_UINT64, NPY_UINT64, NPY_UINT64}; + + static void *data[1] = {NULL}; + + #if defined(NPY_PY3K) + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "struct_ufunc_test", + NULL, + -1, + StructUfuncTestMethods, + NULL, + NULL, + NULL, + NULL + }; + #endif + + #if defined(NPY_PY3K) + PyMODINIT_FUNC PyInit_struct_ufunc_test(void) + #else + PyMODINIT_FUNC initstruct_ufunc_test(void) + #endif + { + PyObject *m, *add_triplet, *d; + PyObject *dtype_dict; + PyArray_Descr *dtype; + PyArray_Descr *dtypes[3]; + + #if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); + #else + m = Py_InitModule("struct_ufunc_test", StructUfuncTestMethods); + #endif + + if (m == NULL) { + #if defined(NPY_PY3K) + return NULL; + #else + return; + #endif + } + + import_array(); + import_umath(); + + /* Create a new ufunc object */ + add_triplet = PyUFunc_FromFuncAndData(NULL, NULL, NULL, 0, 2, 1, + PyUFunc_None, "add_triplet", + "add_triplet_docstring", 0); + + dtype_dict = Py_BuildValue("[(s, s), (s, s), (s, s)]", + "f0", "u8", "f1", "u8", "f2", "u8"); + PyArray_DescrConverter(dtype_dict, &dtype); + Py_DECREF(dtype_dict); + + dtypes[0] = dtype; + dtypes[1] = dtype; + dtypes[2] = dtype; + + /* Register ufunc for structured dtype */ + PyUFunc_RegisterLoopForDescr(add_triplet, + dtype, + &add_uint64_triplet, + dtypes, + NULL); + + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "add_triplet", add_triplet); + Py_DECREF(add_triplet); + #if defined(NPY_PY3K) + return m; + #endif + } + + +.. _`sec:PyUFunc-spec`: + +PyUFunc_FromFuncAndData Specification +===================================== + +What follows is the full specification of PyUFunc_FromFuncAndData, which +automatically generates a ufunc from a C function with the correct signature. + + +.. c:function:: PyObject *PyUFunc_FromFuncAndData( \ + PyUFuncGenericFunction* func, void** data, char* types, int ntypes, \ + int nin, int nout, int identity, char* name, char* doc, int unused) + + *func* + + A pointer to an array of 1-d functions to use. This array must be at + least ntypes long. Each entry in the array must be a + ``PyUFuncGenericFunction`` function. This function has the following + signature. An example of a valid 1d loop function is also given. + + .. c:function:: void loop1d( \ + char** args, npy_intp* dimensions, npy_intp* steps, void* data) + + *args* + + An array of pointers to the actual data for the input and output + arrays. The input arguments are given first followed by the output + arguments. + + *dimensions* + + A pointer to the size of the dimension over which this function is + looping. + + *steps* + + A pointer to the number of bytes to jump to get to the + next element in this dimension for each of the input and + output arguments. + + *data* + + Arbitrary data (extra arguments, function names, *etc.* ) + that can be stored with the ufunc and will be passed in + when it is called. + + .. code-block:: c + + static void + double_add(char **args, npy_intp *dimensions, npy_intp *steps, + void *extra) + { + npy_intp i; + npy_intp is1 = steps[0], is2 = steps[1]; + npy_intp os = steps[2], n = dimensions[0]; + char *i1 = args[0], *i2 = args[1], *op = args[2]; + for (i = 0; i < n; i++) { + *((double *)op) = *((double *)i1) + + *((double *)i2); + i1 += is1; + i2 += is2; + op += os; + } + } + + *data* + + An array of data. There should be ntypes entries (or NULL) --- one for + every loop function defined for this ufunc. This data will be passed + in to the 1-d loop. One common use of this data variable is to pass in + an actual function to call to compute the result when a generic 1-d + loop (e.g. :c:func:`PyUFunc_d_d`) is being used. + + *types* + + An array of type-number signatures (type ``char`` ). This + array should be of size (nin+nout)*ntypes and contain the + data-types for the corresponding 1-d loop. The inputs should + be first followed by the outputs. For example, suppose I have + a ufunc that supports 1 integer and 1 double 1-d loop + (length-2 func and data arrays) that takes 2 inputs and + returns 1 output that is always a complex double, then the + types array would be + + .. code-block:: c + + static char types[3] = {NPY_INT, NPY_DOUBLE, NPY_CDOUBLE} + + The bit-width names can also be used (e.g. :c:data:`NPY_INT32`, + :c:data:`NPY_COMPLEX128` ) if desired. + + *ntypes* + + The number of data-types supported. This is equal to the number of 1-d + loops provided. + + *nin* + + The number of input arguments. + + *nout* + + The number of output arguments. + + *identity* + + Either :c:data:`PyUFunc_One`, :c:data:`PyUFunc_Zero`, + :c:data:`PyUFunc_None`. This specifies what should be returned when + an empty array is passed to the reduce method of the ufunc. + + *name* + + A ``NULL`` -terminated string providing the name of this ufunc + (should be the Python name it will be called). + + *doc* + + A documentation string for this ufunc (will be used in generating the + response to ``{ufunc_name}.__doc__``). Do not include the function + signature or the name as this is generated automatically. + + *unused* + + Unused; kept for compatibility. Just set it to zero. + +.. index:: + pair: ufunc; adding new + +The returned ufunc object is a callable Python object. It should be +placed in a (module) dictionary under the same name as was used in the +name argument to the ufunc-creation routine. The following example is +adapted from the umath module + + .. code-block:: c + + static PyUFuncGenericFunction atan2_functions[] = { + PyUFunc_ff_f, PyUFunc_dd_d, + PyUFunc_gg_g, PyUFunc_OO_O_method}; + static void* atan2_data[] = { + (void *)atan2f,(void *) atan2, + (void *)atan2l,(void *)"arctan2"}; + static char atan2_signatures[] = { + NPY_FLOAT, NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, + NPY_LONGDOUBLE, NPY_LONGDOUBLE, NPY_LONGDOUBLE + NPY_OBJECT, NPY_OBJECT, NPY_OBJECT}; + ... + /* in the module initialization code */ + PyObject *f, *dict, *module; + ... + dict = PyModule_GetDict(module); + ... + f = PyUFunc_FromFuncAndData(atan2_functions, + atan2_data, atan2_signatures, 4, 2, 1, + PyUFunc_None, "arctan2", + "a safe and correct arctan(x1/x2)", 0); + PyDict_SetItemString(dict, "arctan2", f); + Py_DECREF(f); + ... diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst new file mode 100644 index 0000000..a45fec9 --- /dev/null +++ b/doc/source/user/index.rst @@ -0,0 +1,21 @@ +.. _user: + +################ +NumPy User Guide +################ + +This guide is intended as an introductory overview of NumPy and +explains how to install and make use of the most important features of +NumPy. For detailed reference documentation of the functions and +classes contained in the package, see the :ref:`reference`. + +.. toctree:: + :maxdepth: 1 + + setting-up + quickstart + basics + misc + numpy-for-matlab-users + building + c-info diff --git a/doc/source/user/install.rst b/doc/source/user/install.rst new file mode 100644 index 0000000..dd75436 --- /dev/null +++ b/doc/source/user/install.rst @@ -0,0 +1,10 @@ +**************** +Installing NumPy +**************** + +In most use cases the best way to install NumPy on your system is by using a +pre-built package for your operating system. Please see +http://scipy.org/install.html for links to available options. + +For instructions on building for source package, see +:doc:`building`. This information is useful mainly for advanced users. diff --git a/doc/source/user/misc.rst b/doc/source/user/misc.rst new file mode 100644 index 0000000..c10aea4 --- /dev/null +++ b/doc/source/user/misc.rst @@ -0,0 +1,5 @@ +************* +Miscellaneous +************* + +.. automodule:: numpy.doc.misc diff --git a/doc/source/user/numpy-for-matlab-users.rst b/doc/source/user/numpy-for-matlab-users.rst new file mode 100644 index 0000000..00a627a --- /dev/null +++ b/doc/source/user/numpy-for-matlab-users.rst @@ -0,0 +1,750 @@ +.. _numpy-for-matlab-users: + +====================== +NumPy for Matlab users +====================== + +Introduction +============ + +MATLAB® and NumPy/SciPy have a lot in common. But there are many +differences. NumPy and SciPy were created to do numerical and scientific +computing in the most natural way with Python, not to be MATLAB® clones. +This page is intended to be a place to collect wisdom about the +differences, mostly for the purpose of helping proficient MATLAB® users +become proficient NumPy and SciPy users. + +.. raw:: html + + + +Some Key Differences +==================== + +.. list-table:: + + * - In MATLAB®, the basic data type is a multidimensional array of + double precision floating point numbers. Most expressions take such + arrays and return such arrays. Operations on the 2-D instances of + these arrays are designed to act more or less like matrix operations + in linear algebra. + - In NumPy the basic type is a multidimensional ``array``. Operations + on these arrays in all dimensionalities including 2D are element-wise + operations. However, there is a special ``matrix`` type for doing + linear algebra, which is just a subclass of the ``array`` class. + Operations on matrix-class arrays are linear algebra operations. + + * - MATLAB® uses 1 (one) based indexing. The initial element of a + sequence is found using a(1). + :ref:`See note INDEXING ` + - Python uses 0 (zero) based indexing. The initial element of a + sequence is found using a[0]. + + * - MATLAB®'s scripting language was created for doing linear algebra. + The syntax for basic matrix operations is nice and clean, but the API + for adding GUIs and making full-fledged applications is more or less + an afterthought. + - NumPy is based on Python, which was designed from the outset to be + an excellent general-purpose programming language. While Matlab's + syntax for some array manipulations is more compact than + NumPy's, NumPy (by virtue of being an add-on to Python) can do many + things that Matlab just cannot, for instance subclassing the main + array type to do both array and matrix math cleanly. + + * - In MATLAB®, arrays have pass-by-value semantics, with a lazy + copy-on-write scheme to prevent actually creating copies until they + are actually needed. Slice operations copy parts of the array. + - In NumPy arrays have pass-by-reference semantics. Slice operations + are views into an array. + + +'array' or 'matrix'? Which should I use? +======================================== + +NumPy provides, in addition to ``np.ndarray``, an additional matrix type +that you may see used in some existing code. Which one to use? + +Short answer +------------ + +**Use arrays**. + +- They are the standard vector/matrix/tensor type of numpy. Many numpy + functions return arrays, not matrices. +- There is a clear distinction between element-wise operations and + linear algebra operations. +- You can have standard vectors or row/column vectors if you like. + +Until Python 3.5 the only disadvantage of using the array type was that you +had to use ``dot`` instead of ``*`` to multiply (reduce) two tensors +(scalar product, matrix vector multiplication etc.). Since Python 3.5 you +can use the matrix multiplication ``@`` operator. + +Long answer +----------- + +NumPy contains both an ``array`` class and a ``matrix`` class. The +``array`` class is intended to be a general-purpose n-dimensional array +for many kinds of numerical computing, while ``matrix`` is intended to +facilitate linear algebra computations specifically. In practice there +are only a handful of key differences between the two. + +- Operator ``*``, ``dot()``, and ``multiply()``: + + - For ``array``, **'``*``\ ' means element-wise multiplication**, + and the ``dot()`` function is used for matrix multiplication. + - For ``matrix``, **'``*``\ ' means matrix multiplication**, and the + ``multiply()`` function is used for element-wise multiplication. + +- Handling of vectors (one-dimensional arrays) + + - For ``array``, the **vector shapes 1xN, Nx1, and N are all different + things**. Operations like ``A[:,1]`` return a one-dimensional array of + shape N, not a two-dimensional array of shape Nx1. Transpose on a + one-dimensional ``array`` does nothing. + - For ``matrix``, **one-dimensional arrays are always upconverted to 1xN + or Nx1 matrices** (row or column vectors). ``A[:,1]`` returns a + two-dimensional matrix of shape Nx1. + +- Handling of higher-dimensional arrays (ndim > 2) + + - ``array`` objects **can have number of dimensions > 2**; + - ``matrix`` objects **always have exactly two dimensions**. + +- Convenience attributes + + - ``array`` **has a .T attribute**, which returns the transpose of + the data. + - ``matrix`` **also has .H, .I, and .A attributes**, which return + the conjugate transpose, inverse, and ``asarray()`` of the matrix, + respectively. + +- Convenience constructor + + - The ``array`` constructor **takes (nested) Python sequences as + initializers**. As in, ``array([[1,2,3],[4,5,6]])``. + - The ``matrix`` constructor additionally **takes a convenient + string initializer**. As in ``matrix("[1 2 3; 4 5 6]")``. + +There are pros and cons to using both: + +- ``array`` + + - ``:)`` You can treat one-dimensional arrays as *either* row or column + vectors. ``dot(A,v)`` treats ``v`` as a column vector, while + ``dot(v,A)`` treats ``v`` as a row vector. This can save you having to + type a lot of transposes. + - ``<:(`` Having to use the ``dot()`` function for matrix-multiply is + messy -- ``dot(dot(A,B),C)`` vs. ``A*B*C``. This isn't an issue with + Python >= 3.5 because the ``@`` operator allows it to be written as + ``A @ B @ C``. + - ``:)`` Element-wise multiplication is easy: ``A*B``. + - ``:)`` ``array`` is the "default" NumPy type, so it gets the most + testing, and is the type most likely to be returned by 3rd party + code that uses NumPy. + - ``:)`` Is quite at home handling data of any number of dimensions. + - ``:)`` Closer in semantics to tensor algebra, if you are familiar + with that. + - ``:)`` *All* operations (``*``, ``/``, ``+``, ``-`` etc.) are + element-wise. + +- ``matrix`` + + - ``:\\`` Behavior is more like that of MATLAB® matrices. + - ``<:(`` Maximum of two-dimensional. To hold three-dimensional data you + need ``array`` or perhaps a Python list of ``matrix``. + - ``<:(`` Minimum of two-dimensional. You cannot have vectors. They must be + cast as single-column or single-row matrices. + - ``<:(`` Since ``array`` is the default in NumPy, some functions may + return an ``array`` even if you give them a ``matrix`` as an + argument. This shouldn't happen with NumPy functions (if it does + it's a bug), but 3rd party code based on NumPy may not honor type + preservation like NumPy does. + - ``:)`` ``A*B`` is matrix multiplication, so more convenient for + linear algebra (For Python >= 3.5 plain arrays have the same convenience + with the ``@`` operator). + - ``<:(`` Element-wise multiplication requires calling a function, + ``multiply(A,B)``. + - ``<:(`` The use of operator overloading is a bit illogical: ``*`` + does not work element-wise but ``/`` does. + +The ``array`` is thus much more advisable to use. + +Facilities for Matrix Users +=========================== + +NumPy has some features that facilitate the use of the ``matrix`` type, +which hopefully make things easier for Matlab converts. + +- A ``matlib`` module has been added that contains matrix versions of + common array constructors like ``ones()``, ``zeros()``, ``empty()``, + ``eye()``, ``rand()``, ``repmat()``, etc. Normally these functions + return ``array``\ s, but the ``matlib`` versions return ``matrix`` + objects. +- ``mat`` has been changed to be a synonym for ``asmatrix``, rather + than ``matrix``, thus making it a concise way to convert an ``array`` + to a ``matrix`` without copying the data. +- Some top-level functions have been removed. For example + ``numpy.rand()`` now needs to be accessed as ``numpy.random.rand()``. + Or use the ``rand()`` from the ``matlib`` module. But the + "numpythonic" way is to use ``numpy.random.random()``, which takes a + tuple for the shape, like other numpy functions. + +Table of Rough MATLAB-NumPy Equivalents +======================================= + +The table below gives rough equivalents for some common MATLAB® +expressions. **These are not exact equivalents**, but rather should be +taken as hints to get you going in the right direction. For more detail +read the built-in documentation on the NumPy functions. + +Some care is necessary when writing functions that take arrays or +matrices as arguments --- if you are expecting an ``array`` and are +given a ``matrix``, or vice versa, then '\*' (multiplication) will give +you unexpected results. You can convert back and forth between arrays +and matrices using + +- ``asarray``: always returns an object of type ``array`` +- ``asmatrix`` or ``mat``: always return an object of type + ``matrix`` +- ``asanyarray``: always returns an ``array`` object or a subclass + derived from it, depending on the input. For instance if you pass in + a ``matrix`` it returns a ``matrix``. + +These functions all accept both arrays and matrices (among other things +like Python lists), and thus are useful when writing functions that +should accept any array-like object. + +In the table below, it is assumed that you have executed the following +commands in Python: + +:: + + from numpy import * + import scipy.linalg + +Also assume below that if the Notes talk about "matrix" that the +arguments are two-dimensional entities. + +General Purpose Equivalents +--------------------------- + +.. list-table:: + :header-rows: 1 + + * - **MATLAB** + - **numpy** + - **Notes** + + * - ``help func`` + - ``info(func)`` or ``help(func)`` or ``func?`` (in Ipython) + - get help on the function *func* + + * - ``which func`` + - `see note HELP `__ + - find out where *func* is defined + + * - ``type func`` + - ``source(func)`` or ``func??`` (in Ipython) + - print source for *func* (if not a native function) + + * - ``a && b`` + - ``a and b`` + - short-circuiting logical AND operator (Python native operator); + scalar arguments only + + * - ``a || b`` + - ``a or b`` + - short-circuiting logical OR operator (Python native operator); + scalar arguments only + + * - ``1*i``, ``1*j``, ``1i``, ``1j`` + - ``1j`` + - complex numbers + + * - ``eps`` + - ``np.spacing(1)`` + - Distance between 1 and the nearest floating point number. + + * - ``ode45`` + - ``scipy.integrate.solve_ivp(f)`` + - integrate an ODE with Runge-Kutta 4,5 + + * - ``ode15s`` + - ``scipy.integrate.solve_ivp(f, method='BDF')`` + - integrate an ODE with BDF method + +Linear Algebra Equivalents +-------------------------- + +.. list-table:: + :header-rows: 1 + + * - MATLAB + - NumPy + - Notes + + * - ``ndims(a)`` + - ``ndim(a)`` or ``a.ndim`` + - get the number of dimensions of an array + + * - ``numel(a)`` + - ``size(a)`` or ``a.size`` + - get the number of elements of an array + + * - ``size(a)`` + - ``shape(a)`` or ``a.shape`` + - get the "size" of the matrix + + * - ``size(a,n)`` + - ``a.shape[n-1]`` + - get the number of elements of the n-th dimension of array ``a``. (Note + that MATLAB® uses 1 based indexing while Python uses 0 based indexing, + See note :ref:`INDEXING `) + + * - ``[ 1 2 3; 4 5 6 ]`` + - ``array([[1.,2.,3.], [4.,5.,6.]])`` + - 2x3 matrix literal + + * - ``[ a b; c d ]`` + - ``vstack([hstack([a,b]), hstack([c,d])])`` or + ``bmat('a b; c d').A`` + - construct a matrix from blocks ``a``, ``b``, ``c``, and ``d`` + + * - ``a(end)`` + - ``a[-1]`` + - access last element in the 1xn matrix ``a`` + + * - ``a(2,5)`` + - ``a[1,4]`` + - access element in second row, fifth column + + * - ``a(2,:)`` + - ``a[1]`` or ``a[1,:]`` + - entire second row of ``a`` + + * - ``a(1:5,:)`` + - ``a[0:5]`` or ``a[:5]`` or ``a[0:5,:]`` + - the first five rows of ``a`` + + * - ``a(end-4:end,:)`` + - ``a[-5:]`` + - the last five rows of ``a`` + + * - ``a(1:3,5:9)`` + - ``a[0:3][:,4:9]`` + - rows one to three and columns five to nine of ``a``. This gives + read-only access. + + * - ``a([2,4,5],[1,3])`` + - ``a[ix_([1,3,4],[0,2])]`` + - rows 2,4 and 5 and columns 1 and 3. This allows the matrix to be + modified, and doesn't require a regular slice. + + * - ``a(3:2:21,:)`` + - ``a[ 2:21:2,:]`` + - every other row of ``a``, starting with the third and going to the + twenty-first + + * - ``a(1:2:end,:)`` + - ``a[ ::2,:]`` + - every other row of ``a``, starting with the first + + * - ``a(end:-1:1,:)`` or ``flipud(a)`` + - ``a[ ::-1,:]`` + - ``a`` with rows in reverse order + + * - ``a([1:end 1],:)`` + - ``a[r_[:len(a),0]]`` + - ``a`` with copy of the first row appended to the end + + * - ``a.'`` + - ``a.transpose()`` or ``a.T`` + - transpose of ``a`` + + * - ``a'`` + - ``a.conj().transpose()`` or ``a.conj().T`` + - conjugate transpose of ``a`` + + * - ``a * b`` + - ``a.dot(b)`` + - matrix multiply + + * - ``a .* b`` + - ``a * b`` + - element-wise multiply + + * - ``a./b`` + - ``a/b`` + - element-wise divide + + * - ``a.^3`` + - ``a**3`` + - element-wise exponentiation + + * - ``(a>0.5)`` + - ``(a>0.5)`` + - matrix whose i,jth element is (a_ij > 0.5). The Matlab result is an + array of 0s and 1s. The NumPy result is an array of the boolean + values ``False`` and ``True``. + + * - ``find(a>0.5)`` + - ``nonzero(a>0.5)`` + - find the indices where (``a`` > 0.5) + + * - ``a(:,find(v>0.5))`` + - ``a[:,nonzero(v>0.5)[0]]`` + - extract the columms of ``a`` where vector v > 0.5 + + * - ``a(:,find(v>0.5))`` + - ``a[:,v.T>0.5]`` + - extract the columms of ``a`` where column vector v > 0.5 + + * - ``a(a<0.5)=0`` + - ``a[a<0.5]=0`` + - ``a`` with elements less than 0.5 zeroed out + + * - ``a .* (a>0.5)`` + - ``a * (a>0.5)`` + - ``a`` with elements less than 0.5 zeroed out + + * - ``a(:) = 3`` + - ``a[:] = 3`` + - set all values to the same scalar value + + * - ``y=x`` + - ``y = x.copy()`` + - numpy assigns by reference + + * - ``y=x(2,:)`` + - ``y = x[1,:].copy()`` + - numpy slices are by reference + + * - ``y=x(:)`` + - ``y = x.flatten()`` + - turn array into vector (note that this forces a copy) + + * - ``1:10`` + - ``arange(1.,11.)`` or ``r_[1.:11.]`` or ``r_[1:10:10j]`` + - create an increasing vector (see note :ref:`RANGES + `) + + * - ``0:9`` + - ``arange(10.)`` or ``r_[:10.]`` or ``r_[:9:10j]`` + - create an increasing vector (see note :ref:`RANGES + `) + + * - ``[1:10]'`` + - ``arange(1.,11.)[:, newaxis]`` + - create a column vector + + * - ``zeros(3,4)`` + - ``zeros((3,4))`` + - 3x4 two-dimensional array full of 64-bit floating point zeros + + * - ``zeros(3,4,5)`` + - ``zeros((3,4,5))`` + - 3x4x5 three-dimensional array full of 64-bit floating point zeros + + * - ``ones(3,4)`` + - ``ones((3,4))`` + - 3x4 two-dimensional array full of 64-bit floating point ones + + * - ``eye(3)`` + - ``eye(3)`` + - 3x3 identity matrix + + * - ``diag(a)`` + - ``diag(a)`` + - vector of diagonal elements of ``a`` + + * - ``diag(a,0)`` + - ``diag(a,0)`` + - square diagonal matrix whose nonzero values are the elements of + ``a`` + + * - ``rand(3,4)`` + - ``random.rand(3,4)`` + - random 3x4 matrix + + * - ``linspace(1,3,4)`` + - ``linspace(1,3,4)`` + - 4 equally spaced samples between 1 and 3, inclusive + + * - ``[x,y]=meshgrid(0:8,0:5)`` + - ``mgrid[0:9.,0:6.]`` or ``meshgrid(r_[0:9.],r_[0:6.]`` + - two 2D arrays: one of x values, the other of y values + + * - + - ``ogrid[0:9.,0:6.]`` or ``ix_(r_[0:9.],r_[0:6.]`` + - the best way to eval functions on a grid + + * - ``[x,y]=meshgrid([1,2,4],[2,4,5])`` + - ``meshgrid([1,2,4],[2,4,5])`` + - + + * - + - ``ix_([1,2,4],[2,4,5])`` + - the best way to eval functions on a grid + + * - ``repmat(a, m, n)`` + - ``tile(a, (m, n))`` + - create m by n copies of ``a`` + + * - ``[a b]`` + - ``concatenate((a,b),1)`` or ``hstack((a,b))`` or + ``column_stack((a,b))`` or ``c_[a,b]`` + - concatenate columns of ``a`` and ``b`` + + * - ``[a; b]`` + - ``concatenate((a,b))`` or ``vstack((a,b))`` or ``r_[a,b]`` + - concatenate rows of ``a`` and ``b`` + + * - ``max(max(a))`` + - ``a.max()`` + - maximum element of ``a`` (with ndims(a)<=2 for matlab) + + * - ``max(a)`` + - ``a.max(0)`` + - maximum element of each column of matrix ``a`` + + * - ``max(a,[],2)`` + - ``a.max(1)`` + - maximum element of each row of matrix ``a`` + + * - ``max(a,b)`` + - ``maximum(a, b)`` + - compares ``a`` and ``b`` element-wise, and returns the maximum value + from each pair + + * - ``norm(v)`` + - ``sqrt(dot(v,v))`` or ``np.linalg.norm(v)`` + - L2 norm of vector ``v`` + + * - ``a & b`` + - ``logical_and(a,b)`` + - element-by-element AND operator (NumPy ufunc) :ref:`See note + LOGICOPS ` + + * - ``a | b`` + - ``logical_or(a,b)`` + - element-by-element OR operator (NumPy ufunc) :ref:`See note LOGICOPS + ` + + * - ``bitand(a,b)`` + - ``a & b`` + - bitwise AND operator (Python native and NumPy ufunc) + + * - ``bitor(a,b)`` + - ``a | b`` + - bitwise OR operator (Python native and NumPy ufunc) + + * - ``inv(a)`` + - ``linalg.inv(a)`` + - inverse of square matrix ``a`` + + * - ``pinv(a)`` + - ``linalg.pinv(a)`` + - pseudo-inverse of matrix ``a`` + + * - ``rank(a)`` + - ``linalg.matrix_rank(a)`` + - matrix rank of a 2D array / matrix ``a`` + + * - ``a\b`` + - ``linalg.solve(a,b)`` if ``a`` is square; ``linalg.lstsq(a,b)`` + otherwise + - solution of a x = b for x + + * - ``b/a`` + - Solve a.T x.T = b.T instead + - solution of x a = b for x + + * - ``[U,S,V]=svd(a)`` + - ``U, S, Vh = linalg.svd(a), V = Vh.T`` + - singular value decomposition of ``a`` + + * - ``chol(a)`` + - ``linalg.cholesky(a).T`` + - cholesky factorization of a matrix (``chol(a)`` in matlab returns an + upper triangular matrix, but ``linalg.cholesky(a)`` returns a lower + triangular matrix) + + * - ``[V,D]=eig(a)`` + - ``D,V = linalg.eig(a)`` + - eigenvalues and eigenvectors of ``a`` + + * - ``[V,D]=eig(a,b)`` + - ``V,D = np.linalg.eig(a,b)`` + - eigenvalues and eigenvectors of ``a``, ``b`` + + * - ``[V,D]=eigs(a,k)`` + - + - find the ``k`` largest eigenvalues and eigenvectors of ``a`` + + * - ``[Q,R,P]=qr(a,0)`` + - ``Q,R = scipy.linalg.qr(a)`` + - QR decomposition + + * - ``[L,U,P]=lu(a)`` + - ``L,U = scipy.linalg.lu(a)`` or ``LU,P=scipy.linalg.lu_factor(a)`` + - LU decomposition (note: P(Matlab) == transpose(P(numpy)) ) + + * - ``conjgrad`` + - ``scipy.sparse.linalg.cg`` + - Conjugate gradients solver + + * - ``fft(a)`` + - ``fft(a)`` + - Fourier transform of ``a`` + + * - ``ifft(a)`` + - ``ifft(a)`` + - inverse Fourier transform of ``a`` + + * - ``sort(a)`` + - ``sort(a)`` or ``a.sort()`` + - sort the matrix + + * - ``[b,I] = sortrows(a,i)`` + - ``I = argsort(a[:,i]), b=a[I,:]`` + - sort the rows of the matrix + + * - ``regress(y,X)`` + - ``linalg.lstsq(X,y)`` + - multilinear regression + + * - ``decimate(x, q)`` + - ``scipy.signal.resample(x, len(x)/q)`` + - downsample with low-pass filtering + + * - ``unique(a)`` + - ``unique(a)`` + - + + * - ``squeeze(a)`` + - ``a.squeeze()`` + - + +.. _numpy-for-matlab-users.notes: + +Notes +===== + +\ **Submatrix**: Assignment to a submatrix can be done with lists of +indexes using the ``ix_`` command. E.g., for 2d array ``a``, one might +do: ``ind=[1,3]; a[np.ix_(ind,ind)]+=100``. + +\ **HELP**: There is no direct equivalent of MATLAB's ``which`` command, +but the commands ``help`` and ``source`` will usually list the filename +where the function is located. Python also has an ``inspect`` module (do +``import inspect``) which provides a ``getfile`` that often works. + +\ **INDEXING**: MATLAB® uses one based indexing, so the initial element +of a sequence has index 1. Python uses zero based indexing, so the +initial element of a sequence has index 0. Confusion and flamewars arise +because each has advantages and disadvantages. One based indexing is +consistent with common human language usage, where the "first" element +of a sequence has index 1. Zero based indexing `simplifies +indexing `__. +See also `a text by prof.dr. Edsger W. +Dijkstra `__. + +\ **RANGES**: In MATLAB®, ``0:5`` can be used as both a range literal +and a 'slice' index (inside parentheses); however, in Python, constructs +like ``0:5`` can *only* be used as a slice index (inside square +brackets). Thus the somewhat quirky ``r_`` object was created to allow +numpy to have a similarly terse range construction mechanism. Note that +``r_`` is not called like a function or a constructor, but rather +*indexed* using square brackets, which allows the use of Python's slice +syntax in the arguments. + +\ **LOGICOPS**: & or \| in NumPy is bitwise AND/OR, while in Matlab & +and \| are logical AND/OR. The difference should be clear to anyone with +significant programming experience. The two can appear to work the same, +but there are important differences. If you would have used Matlab's & +or \| operators, you should use the NumPy ufuncs +logical\_and/logical\_or. The notable differences between Matlab's and +NumPy's & and \| operators are: + +- Non-logical {0,1} inputs: NumPy's output is the bitwise AND of the + inputs. Matlab treats any non-zero value as 1 and returns the logical + AND. For example (3 & 4) in NumPy is 0, while in Matlab both 3 and 4 + are considered logical true and (3 & 4) returns 1. + +- Precedence: NumPy's & operator is higher precedence than logical + operators like < and >; Matlab's is the reverse. + +If you know you have boolean arguments, you can get away with using +NumPy's bitwise operators, but be careful with parentheses, like this: z += (x > 1) & (x < 2). The absence of NumPy operator forms of logical\_and +and logical\_or is an unfortunate consequence of Python's design. + +**RESHAPE and LINEAR INDEXING**: Matlab always allows multi-dimensional +arrays to be accessed using scalar or linear indices, NumPy does not. +Linear indices are common in Matlab programs, e.g. find() on a matrix +returns them, whereas NumPy's find behaves differently. When converting +Matlab code it might be necessary to first reshape a matrix to a linear +sequence, perform some indexing operations and then reshape back. As +reshape (usually) produces views onto the same storage, it should be +possible to do this fairly efficiently. Note that the scan order used by +reshape in NumPy defaults to the 'C' order, whereas Matlab uses the +Fortran order. If you are simply converting to a linear sequence and +back this doesn't matter. But if you are converting reshapes from Matlab +code which relies on the scan order, then this Matlab code: z = +reshape(x,3,4); should become z = x.reshape(3,4,order='F').copy() in +NumPy. + +Customizing Your Environment +============================ + +In MATLAB® the main tool available to you for customizing the +environment is to modify the search path with the locations of your +favorite functions. You can put such customizations into a startup +script that MATLAB will run on startup. + +NumPy, or rather Python, has similar facilities. + +- To modify your Python search path to include the locations of your + own modules, define the ``PYTHONPATH`` environment variable. + +- To have a particular script file executed when the interactive Python + interpreter is started, define the ``PYTHONSTARTUP`` environment + variable to contain the name of your startup script. + +Unlike MATLAB®, where anything on your path can be called immediately, +with Python you need to first do an 'import' statement to make functions +in a particular file accessible. + +For example you might make a startup script that looks like this (Note: +this is just an example, not a statement of "best practices"): + +:: + + # Make all numpy available via shorter 'num' prefix + import numpy as num + # Make all matlib functions accessible at the top level via M.func() + import numpy.matlib as M + # Make some matlib functions accessible directly at the top level via, e.g. rand(3,3) + from numpy.matlib import rand,zeros,ones,empty,eye + # Define a Hermitian function + def hermitian(A, **kwargs): + return num.transpose(A,**kwargs).conj() + # Make some shortcuts for transpose,hermitian: + # num.transpose(A) --> T(A) + # hermitian(A) --> H(A) + T = num.transpose + H = hermitian + +Links +===== + +See http://mathesaurus.sf.net/ for another MATLAB®/NumPy +cross-reference. + +An extensive list of tools for scientific work with python can be +found in the `topical software page `__. + +MATLAB® and SimuLink® are registered trademarks of The MathWorks. diff --git a/doc/source/user/quickstart.rst b/doc/source/user/quickstart.rst new file mode 100644 index 0000000..67f45a5 --- /dev/null +++ b/doc/source/user/quickstart.rst @@ -0,0 +1,1469 @@ +=================== +Quickstart tutorial +=================== + +.. currentmodule:: numpy + +.. testsetup:: + + import numpy as np + np.random.seed(1) + +Prerequisites +============= + +Before reading this tutorial you should know a bit of Python. If you +would like to refresh your memory, take a look at the `Python +tutorial `__. + +If you wish to work the examples in this tutorial, you must also have +some software installed on your computer. Please see +http://scipy.org/install.html for instructions. + +The Basics +========== + +NumPy's main object is the homogeneous multidimensional array. It is a +table of elements (usually numbers), all of the same type, indexed by a +tuple of positive integers. In NumPy dimensions are called *axes*. + +For example, the coordinates of a point in 3D space ``[1, 2, 1]`` has +one axis. That axis has 3 elements in it, so we say it has a length +of 3. In the example pictured below, the array has 2 axes. The first +axis has a length of 2, the second axis has a length of 3. + +:: + + [[ 1., 0., 0.], + [ 0., 1., 2.]] + +NumPy's array class is called ``ndarray``. It is also known by the alias +``array``. Note that ``numpy.array`` is not the same as the Standard +Python Library class ``array.array``, which only handles one-dimensional +arrays and offers less functionality. The more important attributes of +an ``ndarray`` object are: + +ndarray.ndim + the number of axes (dimensions) of the array. +ndarray.shape + the dimensions of the array. This is a tuple of integers indicating + the size of the array in each dimension. For a matrix with *n* rows + and *m* columns, ``shape`` will be ``(n,m)``. The length of the + ``shape`` tuple is therefore the number of axes, ``ndim``. +ndarray.size + the total number of elements of the array. This is equal to the + product of the elements of ``shape``. +ndarray.dtype + an object describing the type of the elements in the array. One can + create or specify dtype's using standard Python types. Additionally + NumPy provides types of its own. numpy.int32, numpy.int16, and + numpy.float64 are some examples. +ndarray.itemsize + the size in bytes of each element of the array. For example, an + array of elements of type ``float64`` has ``itemsize`` 8 (=64/8), + while one of type ``complex32`` has ``itemsize`` 4 (=32/8). It is + equivalent to ``ndarray.dtype.itemsize``. +ndarray.data + the buffer containing the actual elements of the array. Normally, we + won't need to use this attribute because we will access the elements + in an array using indexing facilities. + +An example +---------- + + >>> import numpy as np + >>> a = np.arange(15).reshape(3, 5) + >>> a + array([[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]]) + >>> a.shape + (3, 5) + >>> a.ndim + 2 + >>> a.dtype.name + 'int64' + >>> a.itemsize + 8 + >>> a.size + 15 + >>> type(a) + + >>> b = np.array([6, 7, 8]) + >>> b + array([6, 7, 8]) + >>> type(b) + + + +Array Creation +-------------- + +There are several ways to create arrays. + +For example, you can create an array from a regular Python list or tuple +using the ``array`` function. The type of the resulting array is deduced +from the type of the elements in the sequences. + +:: + + >>> import numpy as np + >>> a = np.array([2,3,4]) + >>> a + array([2, 3, 4]) + >>> a.dtype + dtype('int64') + >>> b = np.array([1.2, 3.5, 5.1]) + >>> b.dtype + dtype('float64') + +A frequent error consists in calling ``array`` with multiple numeric +arguments, rather than providing a single list of numbers as an +argument. + +:: + + >>> a = np.array(1,2,3,4) # WRONG + >>> a = np.array([1,2,3,4]) # RIGHT + +``array`` transforms sequences of sequences into two-dimensional arrays, +sequences of sequences of sequences into three-dimensional arrays, and +so on. + +:: + + >>> b = np.array([(1.5,2,3), (4,5,6)]) + >>> b + array([[ 1.5, 2. , 3. ], + [ 4. , 5. , 6. ]]) + +The type of the array can also be explicitly specified at creation time: + +:: + + >>> c = np.array( [ [1,2], [3,4] ], dtype=complex ) + >>> c + array([[ 1.+0.j, 2.+0.j], + [ 3.+0.j, 4.+0.j]]) + +Often, the elements of an array are originally unknown, but its size is +known. Hence, NumPy offers several functions to create +arrays with initial placeholder content. These minimize the necessity of +growing arrays, an expensive operation. + +The function ``zeros`` creates an array full of zeros, the function +``ones`` creates an array full of ones, and the function ``empty`` +creates an array whose initial content is random and depends on the +state of the memory. By default, the dtype of the created array is +``float64``. + +:: + + >>> np.zeros( (3,4) ) + array([[ 0., 0., 0., 0.], + [ 0., 0., 0., 0.], + [ 0., 0., 0., 0.]]) + >>> np.ones( (2,3,4), dtype=np.int16 ) # dtype can also be specified + array([[[ 1, 1, 1, 1], + [ 1, 1, 1, 1], + [ 1, 1, 1, 1]], + [[ 1, 1, 1, 1], + [ 1, 1, 1, 1], + [ 1, 1, 1, 1]]], dtype=int16) + >>> np.empty( (2,3) ) # uninitialized, output may vary + array([[ 3.73603959e-262, 6.02658058e-154, 6.55490914e-260], + [ 5.30498948e-313, 3.14673309e-307, 1.00000000e+000]]) + +To create sequences of numbers, NumPy provides a function analogous to +``range`` that returns arrays instead of lists. + +:: + + >>> np.arange( 10, 30, 5 ) + array([10, 15, 20, 25]) + >>> np.arange( 0, 2, 0.3 ) # it accepts float arguments + array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8]) + +When ``arange`` is used with floating point arguments, it is generally +not possible to predict the number of elements obtained, due to the +finite floating point precision. For this reason, it is usually better +to use the function ``linspace`` that receives as an argument the number +of elements that we want, instead of the step:: + + >>> from numpy import pi + >>> np.linspace( 0, 2, 9 ) # 9 numbers from 0 to 2 + array([ 0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ]) + >>> x = np.linspace( 0, 2*pi, 100 ) # useful to evaluate function at lots of points + >>> f = np.sin(x) + +.. seealso:: + `array`, + `zeros`, + `zeros_like`, + `ones`, + `ones_like`, + `empty`, + `empty_like`, + `arange`, + `linspace`, + `numpy.random.rand`, + `numpy.random.randn`, + `fromfunction`, + `fromfile` + +Printing Arrays +--------------- + +When you print an array, NumPy displays it in a similar way to nested +lists, but with the following layout: + +- the last axis is printed from left to right, +- the second-to-last is printed from top to bottom, +- the rest are also printed from top to bottom, with each slice + separated from the next by an empty line. + +One-dimensional arrays are then printed as rows, bidimensionals as +matrices and tridimensionals as lists of matrices. + +:: + + >>> a = np.arange(6) # 1d array + >>> print(a) + [0 1 2 3 4 5] + >>> + >>> b = np.arange(12).reshape(4,3) # 2d array + >>> print(b) + [[ 0 1 2] + [ 3 4 5] + [ 6 7 8] + [ 9 10 11]] + >>> + >>> c = np.arange(24).reshape(2,3,4) # 3d array + >>> print(c) + [[[ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11]] + [[12 13 14 15] + [16 17 18 19] + [20 21 22 23]]] + +See :ref:`below ` to get +more details on ``reshape``. + +If an array is too large to be printed, NumPy automatically skips the +central part of the array and only prints the corners:: + + >>> print(np.arange(10000)) + [ 0 1 2 ..., 9997 9998 9999] + >>> + >>> print(np.arange(10000).reshape(100,100)) + [[ 0 1 2 ..., 97 98 99] + [ 100 101 102 ..., 197 198 199] + [ 200 201 202 ..., 297 298 299] + ..., + [9700 9701 9702 ..., 9797 9798 9799] + [9800 9801 9802 ..., 9897 9898 9899] + [9900 9901 9902 ..., 9997 9998 9999]] + +To disable this behaviour and force NumPy to print the entire array, you +can change the printing options using ``set_printoptions``. + +:: + + >>> np.set_printoptions(threshold=np.nan) + + +Basic Operations +---------------- + +Arithmetic operators on arrays apply *elementwise*. A new array is +created and filled with the result. + +:: + + >>> a = np.array( [20,30,40,50] ) + >>> b = np.arange( 4 ) + >>> b + array([0, 1, 2, 3]) + >>> c = a-b + >>> c + array([20, 29, 38, 47]) + >>> b**2 + array([0, 1, 4, 9]) + >>> 10*np.sin(a) + array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854]) + >>> a<35 + array([ True, True, False, False]) + +Unlike in many matrix languages, the product operator ``*`` operates +elementwise in NumPy arrays. The matrix product can be performed using +the ``dot`` function or method:: + + >>> A = np.array( [[1,1], + ... [0,1]] ) + >>> B = np.array( [[2,0], + ... [3,4]] ) + >>> A*B # elementwise product + array([[2, 0], + [0, 4]]) + >>> A.dot(B) # matrix product + array([[5, 4], + [3, 4]]) + >>> np.dot(A, B) # another matrix product + array([[5, 4], + [3, 4]]) + +Some operations, such as ``+=`` and ``*=``, act in place to modify an +existing array rather than create a new one. + +:: + + >>> a = np.ones((2,3), dtype=int) + >>> b = np.random.random((2,3)) + >>> a *= 3 + >>> a + array([[3, 3, 3], + [3, 3, 3]]) + >>> b += a + >>> b + array([[ 3.417022 , 3.72032449, 3.00011437], + [ 3.30233257, 3.14675589, 3.09233859]]) + >>> a += b # b is not automatically converted to integer type + Traceback (most recent call last): + ... + TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind' + +When operating with arrays of different types, the type of the resulting +array corresponds to the more general or precise one (a behavior known +as upcasting). + +:: + + >>> a = np.ones(3, dtype=np.int32) + >>> b = np.linspace(0,pi,3) + >>> b.dtype.name + 'float64' + >>> c = a+b + >>> c + array([ 1. , 2.57079633, 4.14159265]) + >>> c.dtype.name + 'float64' + >>> d = np.exp(c*1j) + >>> d + array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j, + -0.54030231-0.84147098j]) + >>> d.dtype.name + 'complex128' + +Many unary operations, such as computing the sum of all the elements in +the array, are implemented as methods of the ``ndarray`` class. + +:: + + >>> a = np.random.random((2,3)) + >>> a + array([[ 0.18626021, 0.34556073, 0.39676747], + [ 0.53881673, 0.41919451, 0.6852195 ]]) + >>> a.sum() + 2.5718191614547998 + >>> a.min() + 0.1862602113776709 + >>> a.max() + 0.6852195003967595 + +By default, these operations apply to the array as though it were a list +of numbers, regardless of its shape. However, by specifying the ``axis`` +parameter you can apply an operation along the specified axis of an +array:: + + >>> b = np.arange(12).reshape(3,4) + >>> b + array([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> + >>> b.sum(axis=0) # sum of each column + array([12, 15, 18, 21]) + >>> + >>> b.min(axis=1) # min of each row + array([0, 4, 8]) + >>> + >>> b.cumsum(axis=1) # cumulative sum along each row + array([[ 0, 1, 3, 6], + [ 4, 9, 15, 22], + [ 8, 17, 27, 38]]) + + +Universal Functions +------------------- + +NumPy provides familiar mathematical functions such as sin, cos, and +exp. In NumPy, these are called "universal +functions"(\ ``ufunc``). Within NumPy, these functions +operate elementwise on an array, producing an array as output. + +:: + + >>> B = np.arange(3) + >>> B + array([0, 1, 2]) + >>> np.exp(B) + array([ 1. , 2.71828183, 7.3890561 ]) + >>> np.sqrt(B) + array([ 0. , 1. , 1.41421356]) + >>> C = np.array([2., -1., 4.]) + >>> np.add(B, C) + array([ 2., 0., 6.]) + +.. seealso:: + + `all`, + `any`, + `apply_along_axis`, + `argmax`, + `argmin`, + `argsort`, + `average`, + `bincount`, + `ceil`, + `clip`, + `conj`, + `corrcoef`, + `cov`, + `cross`, + `cumprod`, + `cumsum`, + `diff`, + `dot`, + `floor`, + `inner`, + `inv`, + `lexsort`, + `max`, + `maximum`, + `mean`, + `median`, + `min`, + `minimum`, + `nonzero`, + `outer`, + `prod`, + `re`, + `round`, + `sort`, + `std`, + `sum`, + `trace`, + `transpose`, + `var`, + `vdot`, + `vectorize`, + `where` + +Indexing, Slicing and Iterating +------------------------------- + +**One-dimensional** arrays can be indexed, sliced and iterated over, +much like +`lists `__ +and other Python sequences. + +:: + + >>> a = np.arange(10)**3 + >>> a + array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729]) + >>> a[2] + 8 + >>> a[2:5] + array([ 8, 27, 64]) + >>> a[:6:2] = -1000 # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -1000 + >>> a + array([-1000, 1, -1000, 27, -1000, 125, 216, 343, 512, 729]) + >>> a[ : :-1] # reversed a + array([ 729, 512, 343, 216, 125, -1000, 27, -1000, 1, -1000]) + >>> for i in a: + ... print(i**(1/3.)) + ... + nan + 1.0 + nan + 3.0 + nan + 5.0 + 6.0 + 7.0 + 8.0 + 9.0 + +**Multidimensional** arrays can have one index per axis. These indices +are given in a tuple separated by commas:: + + >>> def f(x,y): + ... return 10*x+y + ... + >>> b = np.fromfunction(f,(5,4),dtype=int) + >>> b + array([[ 0, 1, 2, 3], + [10, 11, 12, 13], + [20, 21, 22, 23], + [30, 31, 32, 33], + [40, 41, 42, 43]]) + >>> b[2,3] + 23 + >>> b[0:5, 1] # each row in the second column of b + array([ 1, 11, 21, 31, 41]) + >>> b[ : ,1] # equivalent to the previous example + array([ 1, 11, 21, 31, 41]) + >>> b[1:3, : ] # each column in the second and third row of b + array([[10, 11, 12, 13], + [20, 21, 22, 23]]) + +When fewer indices are provided than the number of axes, the missing +indices are considered complete slices\ ``:`` + +:: + + >>> b[-1] # the last row. Equivalent to b[-1,:] + array([40, 41, 42, 43]) + +The expression within brackets in ``b[i]`` is treated as an ``i`` +followed by as many instances of ``:`` as needed to represent the +remaining axes. NumPy also allows you to write this using dots as +``b[i,...]``. + +The **dots** (``...``) represent as many colons as needed to produce a +complete indexing tuple. For example, if ``x`` is an array with 5 +axes, then + +- ``x[1,2,...]`` is equivalent to ``x[1,2,:,:,:]``, +- ``x[...,3]`` to ``x[:,:,:,:,3]`` and +- ``x[4,...,5,:]`` to ``x[4,:,:,5,:]``. + +:: + + >>> c = np.array( [[[ 0, 1, 2], # a 3D array (two stacked 2D arrays) + ... [ 10, 12, 13]], + ... [[100,101,102], + ... [110,112,113]]]) + >>> c.shape + (2, 2, 3) + >>> c[1,...] # same as c[1,:,:] or c[1] + array([[100, 101, 102], + [110, 112, 113]]) + >>> c[...,2] # same as c[:,:,2] + array([[ 2, 13], + [102, 113]]) + +**Iterating** over multidimensional arrays is done with respect to the +first axis:: + + >>> for row in b: + ... print(row) + ... + [0 1 2 3] + [10 11 12 13] + [20 21 22 23] + [30 31 32 33] + [40 41 42 43] + +However, if one wants to perform an operation on each element in the +array, one can use the ``flat`` attribute which is an +`iterator `__ +over all the elements of the array:: + + >>> for element in b.flat: + ... print(element) + ... + 0 + 1 + 2 + 3 + 10 + 11 + 12 + 13 + 20 + 21 + 22 + 23 + 30 + 31 + 32 + 33 + 40 + 41 + 42 + 43 + +.. seealso:: + + :ref:`basics.indexing`, + :ref:`arrays.indexing` (reference), + `newaxis`, + `ndenumerate`, + `indices` + +.. _quickstart.shape-manipulation: + +Shape Manipulation +================== + +Changing the shape of an array +------------------------------ + +An array has a shape given by the number of elements along each axis:: + + >>> a = np.floor(10*np.random.random((3,4))) + >>> a + array([[ 2., 8., 0., 6.], + [ 4., 5., 1., 1.], + [ 8., 9., 3., 6.]]) + >>> a.shape + (3, 4) + +The shape of an array can be changed with various commands. Note that the +following three commands all return a modified array, but do not change +the original array:: + + >>> a.ravel() # returns the array, flattened + array([ 2., 8., 0., 6., 4., 5., 1., 1., 8., 9., 3., 6.]) + >>> a.reshape(6,2) # returns the array with a modified shape + array([[ 2., 8.], + [ 0., 6.], + [ 4., 5.], + [ 1., 1.], + [ 8., 9.], + [ 3., 6.]]) + >>> a.T # returns the array, transposed + array([[ 2., 4., 8.], + [ 8., 5., 9.], + [ 0., 1., 3.], + [ 6., 1., 6.]]) + >>> a.T.shape + (4, 3) + >>> a.shape + (3, 4) + +The order of the elements in the array resulting from ravel() is +normally "C-style", that is, the rightmost index "changes the fastest", +so the element after a[0,0] is a[0,1]. If the array is reshaped to some +other shape, again the array is treated as "C-style". NumPy normally +creates arrays stored in this order, so ravel() will usually not need to +copy its argument, but if the array was made by taking slices of another +array or created with unusual options, it may need to be copied. The +functions ravel() and reshape() can also be instructed, using an +optional argument, to use FORTRAN-style arrays, in which the leftmost +index changes the fastest. + +The `reshape` function returns its +argument with a modified shape, whereas the +`ndarray.resize` method modifies the array +itself:: + + >>> a + array([[ 2., 8., 0., 6.], + [ 4., 5., 1., 1.], + [ 8., 9., 3., 6.]]) + >>> a.resize((2,6)) + >>> a + array([[ 2., 8., 0., 6., 4., 5.], + [ 1., 1., 8., 9., 3., 6.]]) + +If a dimension is given as -1 in a reshaping operation, the other +dimensions are automatically calculated:: + + >>> a.reshape(3,-1) + array([[ 2., 8., 0., 6.], + [ 4., 5., 1., 1.], + [ 8., 9., 3., 6.]]) + +.. seealso:: + + `ndarray.shape`, + `reshape`, + `resize`, + `ravel` + +Stacking together different arrays +---------------------------------- + +Several arrays can be stacked together along different axes:: + + >>> a = np.floor(10*np.random.random((2,2))) + >>> a + array([[ 8., 8.], + [ 0., 0.]]) + >>> b = np.floor(10*np.random.random((2,2))) + >>> b + array([[ 1., 8.], + [ 0., 4.]]) + >>> np.vstack((a,b)) + array([[ 8., 8.], + [ 0., 0.], + [ 1., 8.], + [ 0., 4.]]) + >>> np.hstack((a,b)) + array([[ 8., 8., 1., 8.], + [ 0., 0., 0., 4.]]) + +The function `column_stack` +stacks 1D arrays as columns into a 2D array. It is equivalent to +`hstack` only for 2D arrays:: + + >>> from numpy import newaxis + >>> np.column_stack((a,b)) # with 2D arrays + array([[ 8., 8., 1., 8.], + [ 0., 0., 0., 4.]]) + >>> a = np.array([4.,2.]) + >>> b = np.array([3.,8.]) + >>> np.column_stack((a,b)) # returns a 2D array + array([[ 4., 3.], + [ 2., 8.]]) + >>> np.hstack((a,b)) # the result is different + array([ 4., 2., 3., 8.]) + >>> a[:,newaxis] # this allows to have a 2D columns vector + array([[ 4.], + [ 2.]]) + >>> np.column_stack((a[:,newaxis],b[:,newaxis])) + array([[ 4., 3.], + [ 2., 8.]]) + >>> np.hstack((a[:,newaxis],b[:,newaxis])) # the result is the same + array([[ 4., 3.], + [ 2., 8.]]) + +On the other hand, the function `row_stack` is equivalent to `vstack` +for any input arrays. +In general, for arrays of with more than two dimensions, +`hstack` stacks along their second +axes, `vstack` stacks along their +first axes, and `concatenate` +allows for an optional arguments giving the number of the axis along +which the concatenation should happen. + +**Note** + +In complex cases, `r_` and +`c_` are useful for creating arrays +by stacking numbers along one axis. They allow the use of range literals +(":") :: + + >>> np.r_[1:4,0,4] + array([1, 2, 3, 0, 4]) + +When used with arrays as arguments, +`r_` and +`c_` are similar to +`vstack` and +`hstack` in their default behavior, +but allow for an optional argument giving the number of the axis along +which to concatenate. + +.. seealso:: + + `hstack`, + `vstack`, + `column_stack`, + `concatenate`, + `c_`, + `r_` + +Splitting one array into several smaller ones +--------------------------------------------- + +Using `hsplit`, you can split an +array along its horizontal axis, either by specifying the number of +equally shaped arrays to return, or by specifying the columns after +which the division should occur:: + + >>> a = np.floor(10*np.random.random((2,12))) + >>> a + array([[ 9., 5., 6., 3., 6., 8., 0., 7., 9., 7., 2., 7.], + [ 1., 4., 9., 2., 2., 1., 0., 6., 2., 2., 4., 0.]]) + >>> np.hsplit(a,3) # Split a into 3 + [array([[ 9., 5., 6., 3.], + [ 1., 4., 9., 2.]]), array([[ 6., 8., 0., 7.], + [ 2., 1., 0., 6.]]), array([[ 9., 7., 2., 7.], + [ 2., 2., 4., 0.]])] + >>> np.hsplit(a,(3,4)) # Split a after the third and the fourth column + [array([[ 9., 5., 6.], + [ 1., 4., 9.]]), array([[ 3.], + [ 2.]]), array([[ 6., 8., 0., 7., 9., 7., 2., 7.], + [ 2., 1., 0., 6., 2., 2., 4., 0.]])] + +`vsplit` splits along the vertical +axis, and `array_split` allows +one to specify along which axis to split. + +Copies and Views +================ + +When operating and manipulating arrays, their data is sometimes copied +into a new array and sometimes not. This is often a source of confusion +for beginners. There are three cases:: + +No Copy at All +-------------- + +Simple assignments make no copy of array objects or of their data. + +:: + + >>> a = np.arange(12) + >>> b = a # no new object is created + >>> b is a # a and b are two names for the same ndarray object + True + >>> b.shape = 3,4 # changes the shape of a + >>> a.shape + (3, 4) + +Python passes mutable objects as references, so function calls make no +copy. + +:: + + >>> def f(x): + ... print(id(x)) + ... + >>> id(a) # id is a unique identifier of an object + 148293216 + >>> f(a) + 148293216 + +View or Shallow Copy +-------------------- + +Different array objects can share the same data. The ``view`` method +creates a new array object that looks at the same data. + +:: + + >>> c = a.view() + >>> c is a + False + >>> c.base is a # c is a view of the data owned by a + True + >>> c.flags.owndata + False + >>> + >>> c.shape = 2,6 # a's shape doesn't change + >>> a.shape + (3, 4) + >>> c[0,4] = 1234 # a's data changes + >>> a + array([[ 0, 1, 2, 3], + [1234, 5, 6, 7], + [ 8, 9, 10, 11]]) + +Slicing an array returns a view of it:: + + >>> s = a[ : , 1:3] # spaces added for clarity; could also be written "s = a[:,1:3]" + >>> s[:] = 10 # s[:] is a view of s. Note the difference between s=10 and s[:]=10 + >>> a + array([[ 0, 10, 10, 3], + [1234, 10, 10, 7], + [ 8, 10, 10, 11]]) + + +Deep Copy +--------- + +The ``copy`` method makes a complete copy of the array and its data. + +:: + + >>> d = a.copy() # a new array object with new data is created + >>> d is a + False + >>> d.base is a # d doesn't share anything with a + False + >>> d[0,0] = 9999 + >>> a + array([[ 0, 10, 10, 3], + [1234, 10, 10, 7], + [ 8, 10, 10, 11]]) + + +Functions and Methods Overview +------------------------------ + +Here is a list of some useful NumPy functions and methods names +ordered in categories. See :ref:`routines` for the full list. + +Array Creation + `arange`, + `array`, + `copy`, + `empty`, + `empty_like`, + `eye`, + `fromfile`, + `fromfunction`, + `identity`, + `linspace`, + `logspace`, + `mgrid`, + `ogrid`, + `ones`, + `ones_like`, + `r`, + `zeros`, + `zeros_like` +Conversions + `ndarray.astype`, + `atleast_1d`, + `atleast_2d`, + `atleast_3d`, + `mat` +Manipulations + `array_split`, + `column_stack`, + `concatenate`, + `diagonal`, + `dsplit`, + `dstack`, + `hsplit`, + `hstack`, + `ndarray.item`, + `newaxis`, + `ravel`, + `repeat`, + `reshape`, + `resize`, + `squeeze`, + `swapaxes`, + `take`, + `transpose`, + `vsplit`, + `vstack` +Questions + `all`, + `any`, + `nonzero`, + `where` +Ordering + `argmax`, + `argmin`, + `argsort`, + `max`, + `min`, + `ptp`, + `searchsorted`, + `sort` +Operations + `choose`, + `compress`, + `cumprod`, + `cumsum`, + `inner`, + `ndarray.fill`, + `imag`, + `prod`, + `put`, + `putmask`, + `real`, + `sum` +Basic Statistics + `cov`, + `mean`, + `std`, + `var` +Basic Linear Algebra + `cross`, + `dot`, + `outer`, + `linalg.svd`, + `vdot` + +Less Basic +========== + +Broadcasting rules +------------------ + +Broadcasting allows universal functions to deal in a meaningful way with +inputs that do not have exactly the same shape. + +The first rule of broadcasting is that if all input arrays do not have +the same number of dimensions, a "1" will be repeatedly prepended to the +shapes of the smaller arrays until all the arrays have the same number +of dimensions. + +The second rule of broadcasting ensures that arrays with a size of 1 +along a particular dimension act as if they had the size of the array +with the largest shape along that dimension. The value of the array +element is assumed to be the same along that dimension for the +"broadcast" array. + +After application of the broadcasting rules, the sizes of all arrays +must match. More details can be found in :doc:`basics.broadcasting`. + +Fancy indexing and index tricks +=============================== + +NumPy offers more indexing facilities than regular Python sequences. In +addition to indexing by integers and slices, as we saw before, arrays +can be indexed by arrays of integers and arrays of booleans. + +Indexing with Arrays of Indices +------------------------------- + +:: + + >>> a = np.arange(12)**2 # the first 12 square numbers + >>> i = np.array( [ 1,1,3,8,5 ] ) # an array of indices + >>> a[i] # the elements of a at the positions i + array([ 1, 1, 9, 64, 25]) + >>> + >>> j = np.array( [ [ 3, 4], [ 9, 7 ] ] ) # a bidimensional array of indices + >>> a[j] # the same shape as j + array([[ 9, 16], + [81, 49]]) + +When the indexed array ``a`` is multidimensional, a single array of +indices refers to the first dimension of ``a``. The following example +shows this behavior by converting an image of labels into a color image +using a palette. + +:: + + >>> palette = np.array( [ [0,0,0], # black + ... [255,0,0], # red + ... [0,255,0], # green + ... [0,0,255], # blue + ... [255,255,255] ] ) # white + >>> image = np.array( [ [ 0, 1, 2, 0 ], # each value corresponds to a color in the palette + ... [ 0, 3, 4, 0 ] ] ) + >>> palette[image] # the (2,4,3) color image + array([[[ 0, 0, 0], + [255, 0, 0], + [ 0, 255, 0], + [ 0, 0, 0]], + [[ 0, 0, 0], + [ 0, 0, 255], + [255, 255, 255], + [ 0, 0, 0]]]) + +We can also give indexes for more than one dimension. The arrays of +indices for each dimension must have the same shape. + +:: + + >>> a = np.arange(12).reshape(3,4) + >>> a + array([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> i = np.array( [ [0,1], # indices for the first dim of a + ... [1,2] ] ) + >>> j = np.array( [ [2,1], # indices for the second dim + ... [3,3] ] ) + >>> + >>> a[i,j] # i and j must have equal shape + array([[ 2, 5], + [ 7, 11]]) + >>> + >>> a[i,2] + array([[ 2, 6], + [ 6, 10]]) + >>> + >>> a[:,j] # i.e., a[ : , j] + array([[[ 2, 1], + [ 3, 3]], + [[ 6, 5], + [ 7, 7]], + [[10, 9], + [11, 11]]]) + +Naturally, we can put ``i`` and ``j`` in a sequence (say a list) and +then do the indexing with the list. + +:: + + >>> l = [i,j] + >>> a[l] # equivalent to a[i,j] + array([[ 2, 5], + [ 7, 11]]) + +However, we can not do this by putting ``i`` and ``j`` into an array, +because this array will be interpreted as indexing the first dimension +of a. + +:: + + >>> s = np.array( [i,j] ) + >>> a[s] # not what we want + Traceback (most recent call last): + File "", line 1, in ? + IndexError: index (3) out of range (0<=index<=2) in dimension 0 + >>> + >>> a[tuple(s)] # same as a[i,j] + array([[ 2, 5], + [ 7, 11]]) + +Another common use of indexing with arrays is the search of the maximum +value of time-dependent series:: + + >>> time = np.linspace(20, 145, 5) # time scale + >>> data = np.sin(np.arange(20)).reshape(5,4) # 4 time-dependent series + >>> time + array([ 20. , 51.25, 82.5 , 113.75, 145. ]) + >>> data + array([[ 0. , 0.84147098, 0.90929743, 0.14112001], + [-0.7568025 , -0.95892427, -0.2794155 , 0.6569866 ], + [ 0.98935825, 0.41211849, -0.54402111, -0.99999021], + [-0.53657292, 0.42016704, 0.99060736, 0.65028784], + [-0.28790332, -0.96139749, -0.75098725, 0.14987721]]) + >>> + >>> ind = data.argmax(axis=0) # index of the maxima for each series + >>> ind + array([2, 0, 3, 1]) + >>> + >>> time_max = time[ind] # times corresponding to the maxima + >>> + >>> data_max = data[ind, range(data.shape[1])] # => data[ind[0],0], data[ind[1],1]... + >>> + >>> time_max + array([ 82.5 , 20. , 113.75, 51.25]) + >>> data_max + array([ 0.98935825, 0.84147098, 0.99060736, 0.6569866 ]) + >>> + >>> np.all(data_max == data.max(axis=0)) + True + +You can also use indexing with arrays as a target to assign to:: + + >>> a = np.arange(5) + >>> a + array([0, 1, 2, 3, 4]) + >>> a[[1,3,4]] = 0 + >>> a + array([0, 0, 2, 0, 0]) + +However, when the list of indices contains repetitions, the assignment +is done several times, leaving behind the last value:: + + >>> a = np.arange(5) + >>> a[[0,0,2]]=[1,2,3] + >>> a + array([2, 1, 3, 3, 4]) + +This is reasonable enough, but watch out if you want to use Python's +``+=`` construct, as it may not do what you expect:: + + >>> a = np.arange(5) + >>> a[[0,0,2]]+=1 + >>> a + array([1, 1, 3, 3, 4]) + +Even though 0 occurs twice in the list of indices, the 0th element is +only incremented once. This is because Python requires "a+=1" to be +equivalent to "a = a + 1". + +Indexing with Boolean Arrays +---------------------------- + +When we index arrays with arrays of (integer) indices we are providing +the list of indices to pick. With boolean indices the approach is +different; we explicitly choose which items in the array we want and +which ones we don't. + +The most natural way one can think of for boolean indexing is to use +boolean arrays that have *the same shape* as the original array:: + + >>> a = np.arange(12).reshape(3,4) + >>> b = a > 4 + >>> b # b is a boolean with a's shape + array([[False, False, False, False], + [False, True, True, True], + [ True, True, True, True]]) + >>> a[b] # 1d array with the selected elements + array([ 5, 6, 7, 8, 9, 10, 11]) + +This property can be very useful in assignments:: + + >>> a[b] = 0 # All elements of 'a' higher than 4 become 0 + >>> a + array([[0, 1, 2, 3], + [4, 0, 0, 0], + [0, 0, 0, 0]]) + +You can look at the following +example to see +how to use boolean indexing to generate an image of the `Mandelbrot +set `__: + +.. plot:: + + >>> import numpy as np + >>> import matplotlib.pyplot as plt + >>> def mandelbrot( h,w, maxit=20 ): + ... """Returns an image of the Mandelbrot fractal of size (h,w).""" + ... y,x = np.ogrid[ -1.4:1.4:h*1j, -2:0.8:w*1j ] + ... c = x+y*1j + ... z = c + ... divtime = maxit + np.zeros(z.shape, dtype=int) + ... + ... for i in range(maxit): + ... z = z**2 + c + ... diverge = z*np.conj(z) > 2**2 # who is diverging + ... div_now = diverge & (divtime==maxit) # who is diverging now + ... divtime[div_now] = i # note when + ... z[diverge] = 2 # avoid diverging too much + ... + ... return divtime + >>> plt.imshow(mandelbrot(400,400)) + >>> plt.show() + +The second way of indexing with booleans is more similar to integer +indexing; for each dimension of the array we give a 1D boolean array +selecting the slices we want:: + + >>> a = np.arange(12).reshape(3,4) + >>> b1 = np.array([False,True,True]) # first dim selection + >>> b2 = np.array([True,False,True,False]) # second dim selection + >>> + >>> a[b1,:] # selecting rows + array([[ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> + >>> a[b1] # same thing + array([[ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> + >>> a[:,b2] # selecting columns + array([[ 0, 2], + [ 4, 6], + [ 8, 10]]) + >>> + >>> a[b1,b2] # a weird thing to do + array([ 4, 10]) + +Note that the length of the 1D boolean array must coincide with the +length of the dimension (or axis) you want to slice. In the previous +example, ``b1`` has length 3 (the number of *rows* in ``a``), and +``b2`` (of length 4) is suitable to index the 2nd axis (columns) of +``a``. + +The ix_() function +------------------- + +The `ix_` function can be used to combine different vectors so as to +obtain the result for each n-uplet. For example, if you want to compute +all the a+b\*c for all the triplets taken from each of the vectors a, b +and c:: + + >>> a = np.array([2,3,4,5]) + >>> b = np.array([8,5,4]) + >>> c = np.array([5,4,6,8,3]) + >>> ax,bx,cx = np.ix_(a,b,c) + >>> ax + array([[[2]], + [[3]], + [[4]], + [[5]]]) + >>> bx + array([[[8], + [5], + [4]]]) + >>> cx + array([[[5, 4, 6, 8, 3]]]) + >>> ax.shape, bx.shape, cx.shape + ((4, 1, 1), (1, 3, 1), (1, 1, 5)) + >>> result = ax+bx*cx + >>> result + array([[[42, 34, 50, 66, 26], + [27, 22, 32, 42, 17], + [22, 18, 26, 34, 14]], + [[43, 35, 51, 67, 27], + [28, 23, 33, 43, 18], + [23, 19, 27, 35, 15]], + [[44, 36, 52, 68, 28], + [29, 24, 34, 44, 19], + [24, 20, 28, 36, 16]], + [[45, 37, 53, 69, 29], + [30, 25, 35, 45, 20], + [25, 21, 29, 37, 17]]]) + >>> result[3,2,4] + 17 + >>> a[3]+b[2]*c[4] + 17 + +You could also implement the reduce as follows:: + + >>> def ufunc_reduce(ufct, *vectors): + ... vs = np.ix_(*vectors) + ... r = ufct.identity + ... for v in vs: + ... r = ufct(r,v) + ... return r + +and then use it as:: + + >>> ufunc_reduce(np.add,a,b,c) + array([[[15, 14, 16, 18, 13], + [12, 11, 13, 15, 10], + [11, 10, 12, 14, 9]], + [[16, 15, 17, 19, 14], + [13, 12, 14, 16, 11], + [12, 11, 13, 15, 10]], + [[17, 16, 18, 20, 15], + [14, 13, 15, 17, 12], + [13, 12, 14, 16, 11]], + [[18, 17, 19, 21, 16], + [15, 14, 16, 18, 13], + [14, 13, 15, 17, 12]]]) + +The advantage of this version of reduce compared to the normal +ufunc.reduce is that it makes use of the `Broadcasting +Rules `__ +in order to avoid creating an argument array the size of the output +times the number of vectors. + +Indexing with strings +--------------------- + +See :ref:`structured_arrays`. + +Linear Algebra +============== + +Work in progress. Basic linear algebra to be included here. + +Simple Array Operations +----------------------- + +See linalg.py in numpy folder for more. + +:: + + >>> import numpy as np + >>> a = np.array([[1.0, 2.0], [3.0, 4.0]]) + >>> print(a) + [[ 1. 2.] + [ 3. 4.]] + + >>> a.transpose() + array([[ 1., 3.], + [ 2., 4.]]) + + >>> np.linalg.inv(a) + array([[-2. , 1. ], + [ 1.5, -0.5]]) + + >>> u = np.eye(2) # unit 2x2 matrix; "eye" represents "I" + >>> u + array([[ 1., 0.], + [ 0., 1.]]) + >>> j = np.array([[0.0, -1.0], [1.0, 0.0]]) + + >>> np.dot (j, j) # matrix product + array([[-1., 0.], + [ 0., -1.]]) + + >>> np.trace(u) # trace + 2.0 + + >>> y = np.array([[5.], [7.]]) + >>> np.linalg.solve(a, y) + array([[-3.], + [ 4.]]) + + >>> np.linalg.eig(j) + (array([ 0.+1.j, 0.-1.j]), array([[ 0.70710678+0.j , 0.70710678-0.j ], + [ 0.00000000-0.70710678j, 0.00000000+0.70710678j]])) + +:: + + Parameters: + square matrix + Returns + The eigenvalues, each repeated according to its multiplicity. + The normalized (unit "length") eigenvectors, such that the + column ``v[:,i]`` is the eigenvector corresponding to the + eigenvalue ``w[i]`` . + +Tricks and Tips +=============== + +Here we give a list of short and useful tips. + +"Automatic" Reshaping +--------------------- + +To change the dimensions of an array, you can omit one of the sizes +which will then be deduced automatically:: + + >>> a = np.arange(30) + >>> a.shape = 2,-1,3 # -1 means "whatever is needed" + >>> a.shape + (2, 5, 3) + >>> a + array([[[ 0, 1, 2], + [ 3, 4, 5], + [ 6, 7, 8], + [ 9, 10, 11], + [12, 13, 14]], + [[15, 16, 17], + [18, 19, 20], + [21, 22, 23], + [24, 25, 26], + [27, 28, 29]]]) + +Vector Stacking +--------------- + +How do we construct a 2D array from a list of equally-sized row vectors? +In MATLAB this is quite easy: if ``x`` and ``y`` are two vectors of the +same length you only need do ``m=[x;y]``. In NumPy this works via the +functions ``column_stack``, ``dstack``, ``hstack`` and ``vstack``, +depending on the dimension in which the stacking is to be done. For +example:: + + x = np.arange(0,10,2) # x=([0,2,4,6,8]) + y = np.arange(5) # y=([0,1,2,3,4]) + m = np.vstack([x,y]) # m=([[0,2,4,6,8], + # [0,1,2,3,4]]) + xy = np.hstack([x,y]) # xy =([0,2,4,6,8,0,1,2,3,4]) + +The logic behind those functions in more than two dimensions can be +strange. + +.. seealso:: + + :doc:`numpy-for-matlab-users` + +Histograms +---------- + +The NumPy ``histogram`` function applied to an array returns a pair of +vectors: the histogram of the array and the vector of bins. Beware: +``matplotlib`` also has a function to build histograms (called ``hist``, +as in Matlab) that differs from the one in NumPy. The main difference is +that ``pylab.hist`` plots the histogram automatically, while +``numpy.histogram`` only generates the data. + +.. plot:: + + >>> import numpy as np + >>> import matplotlib.pyplot as plt + >>> # Build a vector of 10000 normal deviates with variance 0.5^2 and mean 2 + >>> mu, sigma = 2, 0.5 + >>> v = np.random.normal(mu,sigma,10000) + >>> # Plot a normalized histogram with 50 bins + >>> plt.hist(v, bins=50, normed=1) # matplotlib version (plot) + >>> plt.show() + >>> # Compute the histogram with numpy and then plot it + >>> (n, bins) = np.histogram(v, bins=50, normed=True) # NumPy version (no plot) + >>> plt.plot(.5*(bins[1:]+bins[:-1]), n) + >>> plt.show() + + +Further reading +=============== + +- The `Python tutorial `__ +- :ref:`reference` +- `SciPy Tutorial `__ +- `SciPy Lecture Notes `__ +- A `matlab, R, IDL, NumPy/SciPy dictionary `__ diff --git a/doc/source/user/setting-up.rst b/doc/source/user/setting-up.rst new file mode 100644 index 0000000..f70dacf --- /dev/null +++ b/doc/source/user/setting-up.rst @@ -0,0 +1,9 @@ +********** +Setting up +********** + +.. toctree:: + :maxdepth: 1 + + whatisnumpy + install diff --git a/doc/source/user/whatisnumpy.rst b/doc/source/user/whatisnumpy.rst new file mode 100644 index 0000000..cd74a8d --- /dev/null +++ b/doc/source/user/whatisnumpy.rst @@ -0,0 +1,128 @@ +************** +What is NumPy? +************** + +NumPy is the fundamental package for scientific computing in Python. +It is a Python library that provides a multidimensional array object, +various derived objects (such as masked arrays and matrices), and an +assortment of routines for fast operations on arrays, including +mathematical, logical, shape manipulation, sorting, selecting, I/O, +discrete Fourier transforms, basic linear algebra, basic statistical +operations, random simulation and much more. + +At the core of the NumPy package, is the `ndarray` object. This +encapsulates *n*-dimensional arrays of homogeneous data types, with +many operations being performed in compiled code for performance. +There are several important differences between NumPy arrays and the +standard Python sequences: + +- NumPy arrays have a fixed size at creation, unlike Python lists + (which can grow dynamically). Changing the size of an `ndarray` will + create a new array and delete the original. + +- The elements in a NumPy array are all required to be of the same + data type, and thus will be the same size in memory. The exception: + one can have arrays of (Python, including NumPy) objects, thereby + allowing for arrays of different sized elements. + +- NumPy arrays facilitate advanced mathematical and other types of + operations on large numbers of data. Typically, such operations are + executed more efficiently and with less code than is possible using + Python's built-in sequences. + +- A growing plethora of scientific and mathematical Python-based + packages are using NumPy arrays; though these typically support + Python-sequence input, they convert such input to NumPy arrays prior + to processing, and they often output NumPy arrays. In other words, + in order to efficiently use much (perhaps even most) of today's + scientific/mathematical Python-based software, just knowing how to + use Python's built-in sequence types is insufficient - one also + needs to know how to use NumPy arrays. + +The points about sequence size and speed are particularly important in +scientific computing. As a simple example, consider the case of +multiplying each element in a 1-D sequence with the corresponding +element in another sequence of the same length. If the data are +stored in two Python lists, ``a`` and ``b``, we could iterate over +each element:: + + c = [] + for i in range(len(a)): + c.append(a[i]*b[i]) + +This produces the correct answer, but if ``a`` and ``b`` each contain +millions of numbers, we will pay the price for the inefficiencies of +looping in Python. We could accomplish the same task much more +quickly in C by writing (for clarity we neglect variable declarations +and initializations, memory allocation, etc.) + +:: + + for (i = 0; i < rows; i++): { + c[i] = a[i]*b[i]; + } + +This saves all the overhead involved in interpreting the Python code +and manipulating Python objects, but at the expense of the benefits +gained from coding in Python. Furthermore, the coding work required +increases with the dimensionality of our data. In the case of a 2-D +array, for example, the C code (abridged as before) expands to + +:: + + for (i = 0; i < rows; i++): { + for (j = 0; j < columns; j++): { + c[i][j] = a[i][j]*b[i][j]; + } + } + +NumPy gives us the best of both worlds: element-by-element operations +are the "default mode" when an `ndarray` is involved, but the +element-by-element operation is speedily executed by pre-compiled C +code. In NumPy + +:: + + c = a * b + +does what the earlier examples do, at near-C speeds, but with the code +simplicity we expect from something based on Python. Indeed, the NumPy +idiom is even simpler! This last example illustrates two of NumPy's +features which are the basis of much of its power: vectorization and +broadcasting. + +Vectorization describes the absence of any explicit looping, indexing, +etc., in the code - these things are taking place, of course, just +"behind the scenes" in optimized, pre-compiled C code. Vectorized +code has many advantages, among which are: + +- vectorized code is more concise and easier to read + +- fewer lines of code generally means fewer bugs + +- the code more closely resembles standard mathematical notation + (making it easier, typically, to correctly code mathematical + constructs) + +- vectorization results in more "Pythonic" code. Without + vectorization, our code would be littered with inefficient and + difficult to read ``for`` loops. + +Broadcasting is the term used to describe the implicit +element-by-element behavior of operations; generally speaking, in +NumPy all operations, not just arithmetic operations, but +logical, bit-wise, functional, etc., behave in this implicit +element-by-element fashion, i.e., they broadcast. Moreover, in the +example above, ``a`` and ``b`` could be multidimensional arrays of the +same shape, or a scalar and an array, or even two arrays of with +different shapes, provided that the smaller array is "expandable" to +the shape of the larger in such a way that the resulting broadcast is +unambiguous. For detailed "rules" of broadcasting see +`numpy.doc.broadcasting`. + +NumPy fully supports an object-oriented approach, starting, once +again, with `ndarray`. For example, `ndarray` is a class, possessing +numerous methods and attributes. Many of its methods mirror +functions in the outer-most NumPy namespace, giving the programmer +complete freedom to code in whichever paradigm she prefers and/or +which seems most appropriate to the task at hand. diff --git a/doc/sphinxext/.gitignore b/doc/sphinxext/.gitignore new file mode 100644 index 0000000..81562fd --- /dev/null +++ b/doc/sphinxext/.gitignore @@ -0,0 +1,10 @@ +*~ +.#* +*.bak +*.pyc +*.pyo +*.egg-info +*.swp +*.swo +build +dist diff --git a/doc/sphinxext/.travis.yml b/doc/sphinxext/.travis.yml new file mode 100644 index 0000000..77a3ec9 --- /dev/null +++ b/doc/sphinxext/.travis.yml @@ -0,0 +1,22 @@ +# After changing this file, check it on: +# http://lint.travis-ci.org/ +language: python +sudo: false +python: + - 3.6 + - 2.7 +env: + - SPHINX_SPEC="Sphinx==1.2.3" + - SPHINX_SPEC="Sphinx" +cache: + directories: + - $HOME/.cache/pip +before_install: + - pip install --upgrade pip setuptools # Upgrade pip and setuptools to get ones with `wheel` support + - pip install --find-links http://wheels.astropy.org/ --find-links http://wheels2.astropy.org/ --trusted-host wheels.astropy.org --trusted-host wheels2.astropy.org --use-wheel nose numpy matplotlib ${SPHINX_SPEC} +script: + - | + python setup.py sdist + cd dist + pip install numpydoc* -v + - nosetests numpydoc diff --git a/doc/sphinxext/LICENSE.txt b/doc/sphinxext/LICENSE.txt new file mode 100644 index 0000000..b15c699 --- /dev/null +++ b/doc/sphinxext/LICENSE.txt @@ -0,0 +1,94 @@ +------------------------------------------------------------------------------- + The files + - numpydoc.py + - docscrape.py + - docscrape_sphinx.py + - phantom_import.py + have the following license: + +Copyright (C) 2008 Stefan van der Walt , Pauli Virtanen + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- + The files + - compiler_unparse.py + - comment_eater.py + - traitsdoc.py + have the following license: + +This software is OSI Certified Open Source Software. +OSI Certified is a certification mark of the Open Source Initiative. + +Copyright (c) 2006, Enthought, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Enthought, Inc. nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +------------------------------------------------------------------------------- + The file + - plot_directive.py + originates from Matplotlib (http://matplotlib.sf.net/) which has + the following license: + +Copyright (c) 2002-2008 John D. Hunter; All Rights Reserved. + +1. This LICENSE AGREEMENT is between John D. Hunter (“JDH”), and the Individual or Organization (“Licensee”) accessing and otherwise using matplotlib software in source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, JDH hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use matplotlib 0.98.3 alone or in any derivative version, provided, however, that JDH’s License Agreement and JDH’s notice of copyright, i.e., “Copyright (c) 2002-2008 John D. Hunter; All Rights Reserved” are retained in matplotlib 0.98.3 alone or in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on or incorporates matplotlib 0.98.3 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to matplotlib 0.98.3. + +4. JDH is making matplotlib 0.98.3 available to Licensee on an “AS IS” basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 0.98.3 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB 0.98.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING MATPLOTLIB 0.98.3, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between JDH and Licensee. This License Agreement does not grant permission to use JDH trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using matplotlib 0.98.3, Licensee agrees to be bound by the terms and conditions of this License Agreement. + diff --git a/doc/sphinxext/MANIFEST.in b/doc/sphinxext/MANIFEST.in new file mode 100644 index 0000000..271247e --- /dev/null +++ b/doc/sphinxext/MANIFEST.in @@ -0,0 +1,8 @@ +include MANIFEST.in +recursive-include numpydoc * +include *.txt +include *.rst + +# Exclude what we don't want to include +prune */__pycache__ +global-exclude *.pyc *~ *.bak *.swp *.pyo diff --git a/doc/sphinxext/README.rst b/doc/sphinxext/README.rst new file mode 100644 index 0000000..7c93abc --- /dev/null +++ b/doc/sphinxext/README.rst @@ -0,0 +1,65 @@ +.. image:: https://travis-ci.org/numpy/numpydoc.png?branch=master + :target: https://travis-ci.org/numpy/numpydoc/ + +===================================== +numpydoc -- Numpy's Sphinx extensions +===================================== + +Numpy's documentation uses several custom extensions to Sphinx. These +are shipped in this ``numpydoc`` package, in case you want to make use +of them in third-party projects. + +The following extensions are available: + + - ``numpydoc``: support for the Numpy docstring format in Sphinx, and add + the code description directives ``np:function``, ``np-c:function``, etc. + that support the Numpy docstring syntax. + + - ``numpydoc.traitsdoc``: For gathering documentation about Traits attributes. + + - ``numpydoc.plot_directive``: Adaptation of Matplotlib's ``plot::`` + directive. Note that this implementation may still undergo severe + changes or eventually be deprecated. + +See `A Guide to NumPy/SciPy Documentation `_ +for how to write docs that use this extension. + + +numpydoc +======== + +Numpydoc inserts a hook into Sphinx's autodoc that converts docstrings +following the Numpy/Scipy format to a form palatable to Sphinx. + +Options +------- + +The following options can be set in conf.py: + +- numpydoc_use_plots: bool + + Whether to produce ``plot::`` directives for Examples sections that + contain ``import matplotlib``. + +- numpydoc_show_class_members: bool + + Whether to show all members of a class in the Methods and Attributes + sections automatically. + ``True`` by default. + +- numpydoc_show_inherited_class_members: bool + + Whether to show all inherited members of a class in the Methods and Attributes + sections automatically. If it's false, inherited members won't shown. + ``True`` by default. + +- numpydoc_class_members_toctree: bool + + Whether to create a Sphinx table of contents for the lists of class + methods and attributes. If a table of contents is made, Sphinx expects + each entry to have a separate page. + ``True`` by default. + +- numpydoc_edit_link: bool (DEPRECATED -- edit your HTML template instead) + + Whether to insert an edit link after docstrings. diff --git a/doc/sphinxext/numpydoc/__init__.py b/doc/sphinxext/numpydoc/__init__.py new file mode 100644 index 0000000..0506cf5 --- /dev/null +++ b/doc/sphinxext/numpydoc/__init__.py @@ -0,0 +1,5 @@ +from __future__ import division, absolute_import, print_function + +__version__ = '0.7.0' + +from .numpydoc import setup diff --git a/doc/sphinxext/numpydoc/docscrape.py b/doc/sphinxext/numpydoc/docscrape.py new file mode 100644 index 0000000..074a7f7 --- /dev/null +++ b/doc/sphinxext/numpydoc/docscrape.py @@ -0,0 +1,603 @@ +"""Extract reference documentation from the NumPy source tree. + +""" +from __future__ import division, absolute_import, print_function + +import inspect +import textwrap +import re +import pydoc +from warnings import warn +import collections +import copy +import sys + + +class Reader(object): + """A line-based string reader. + + """ + def __init__(self, data): + """ + Parameters + ---------- + data : str + String with lines separated by '\n'. + + """ + if isinstance(data, list): + self._str = data + else: + self._str = data.split('\n') # store string as list of lines + + self.reset() + + def __getitem__(self, n): + return self._str[n] + + def reset(self): + self._l = 0 # current line nr + + def read(self): + if not self.eof(): + out = self[self._l] + self._l += 1 + return out + else: + return '' + + def seek_next_non_empty_line(self): + for l in self[self._l:]: + if l.strip(): + break + else: + self._l += 1 + + def eof(self): + return self._l >= len(self._str) + + def read_to_condition(self, condition_func): + start = self._l + for line in self[start:]: + if condition_func(line): + return self[start:self._l] + self._l += 1 + if self.eof(): + return self[start:self._l+1] + return [] + + def read_to_next_empty_line(self): + self.seek_next_non_empty_line() + + def is_empty(line): + return not line.strip() + + return self.read_to_condition(is_empty) + + def read_to_next_unindented_line(self): + def is_unindented(line): + return (line.strip() and (len(line.lstrip()) == len(line))) + return self.read_to_condition(is_unindented) + + def peek(self, n=0): + if self._l + n < len(self._str): + return self[self._l + n] + else: + return '' + + def is_empty(self): + return not ''.join(self._str).strip() + + +class ParseError(Exception): + def __str__(self): + message = self.args[0] + if hasattr(self, 'docstring'): + message = "%s in %r" % (message, self.docstring) + return message + + +class NumpyDocString(collections.Mapping): + sections = { + 'Signature': '', + 'Summary': [''], + 'Extended Summary': [], + 'Parameters': [], + 'Returns': [], + 'Yields': [], + 'Raises': [], + 'Warns': [], + 'Other Parameters': [], + 'Attributes': [], + 'Methods': [], + 'See Also': [], + 'Notes': [], + 'Warnings': [], + 'References': '', + 'Examples': '', + 'index': {} + } + + def __init__(self, docstring, config={}): + orig_docstring = docstring + docstring = textwrap.dedent(docstring).split('\n') + + self._doc = Reader(docstring) + self._parsed_data = copy.deepcopy(self.sections) + + try: + self._parse() + except ParseError as e: + e.docstring = orig_docstring + raise + + def __getitem__(self, key): + return self._parsed_data[key] + + def __setitem__(self, key, val): + if key not in self._parsed_data: + warn("Unknown section %s" % key) + else: + self._parsed_data[key] = val + + def __iter__(self): + return iter(self._parsed_data) + + def __len__(self): + return len(self._parsed_data) + + def _is_at_section(self): + self._doc.seek_next_non_empty_line() + + if self._doc.eof(): + return False + + l1 = self._doc.peek().strip() # e.g. Parameters + + if l1.startswith('.. index::'): + return True + + l2 = self._doc.peek(1).strip() # ---------- or ========== + return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1)) + + def _strip(self, doc): + i = 0 + j = 0 + for i, line in enumerate(doc): + if line.strip(): + break + + for j, line in enumerate(doc[::-1]): + if line.strip(): + break + + return doc[i:len(doc)-j] + + def _read_to_next_section(self): + section = self._doc.read_to_next_empty_line() + + while not self._is_at_section() and not self._doc.eof(): + if not self._doc.peek(-1).strip(): # previous line was empty + section += [''] + + section += self._doc.read_to_next_empty_line() + + return section + + def _read_sections(self): + while not self._doc.eof(): + data = self._read_to_next_section() + name = data[0].strip() + + if name.startswith('..'): # index section + yield name, data[1:] + elif len(data) < 2: + yield StopIteration + else: + yield name, self._strip(data[2:]) + + def _parse_param_list(self, content): + r = Reader(content) + params = [] + while not r.eof(): + header = r.read().strip() + if ' : ' in header: + arg_name, arg_type = header.split(' : ')[:2] + else: + arg_name, arg_type = header, '' + + desc = r.read_to_next_unindented_line() + desc = dedent_lines(desc) + + params.append((arg_name, arg_type, desc)) + + return params + + _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" + r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) + + def _parse_see_also(self, content): + """ + func_name : Descriptive text + continued text + another_func_name : Descriptive text + func_name1, func_name2, :meth:`func_name`, func_name3 + + """ + items = [] + + def parse_item_name(text): + """Match ':role:`name`' or 'name'""" + m = self._name_rgx.match(text) + if m: + g = m.groups() + if g[1] is None: + return g[3], None + else: + return g[2], g[1] + raise ParseError("%s is not a item name" % text) + + def push_item(name, rest): + if not name: + return + name, role = parse_item_name(name) + items.append((name, list(rest), role)) + del rest[:] + + current_func = None + rest = [] + + for line in content: + if not line.strip(): + continue + + m = self._name_rgx.match(line) + if m and line[m.end():].strip().startswith(':'): + push_item(current_func, rest) + current_func, line = line[:m.end()], line[m.end():] + rest = [line.split(':', 1)[1].strip()] + if not rest[0]: + rest = [] + elif not line.startswith(' '): + push_item(current_func, rest) + current_func = None + if ',' in line: + for func in line.split(','): + if func.strip(): + push_item(func, []) + elif line.strip(): + current_func = line + elif current_func is not None: + rest.append(line.strip()) + push_item(current_func, rest) + return items + + def _parse_index(self, section, content): + """ + .. index: default + :refguide: something, else, and more + + """ + def strip_each_in(lst): + return [s.strip() for s in lst] + + out = {} + section = section.split('::') + if len(section) > 1: + out['default'] = strip_each_in(section[1].split(','))[0] + for line in content: + line = line.split(':') + if len(line) > 2: + out[line[1]] = strip_each_in(line[2].split(',')) + return out + + def _parse_summary(self): + """Grab signature (if given) and summary""" + if self._is_at_section(): + return + + # If several signatures present, take the last one + while True: + summary = self._doc.read_to_next_empty_line() + summary_str = " ".join([s.strip() for s in summary]).strip() + if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): + self['Signature'] = summary_str + if not self._is_at_section(): + continue + break + + if summary is not None: + self['Summary'] = summary + + if not self._is_at_section(): + self['Extended Summary'] = self._read_to_next_section() + + def _parse(self): + self._doc.reset() + self._parse_summary() + + sections = list(self._read_sections()) + section_names = set([section for section, content in sections]) + + has_returns = 'Returns' in section_names + has_yields = 'Yields' in section_names + # We could do more tests, but we are not. Arbitrarily. + if has_returns and has_yields: + msg = 'Docstring contains both a Returns and Yields section.' + raise ValueError(msg) + + for (section, content) in sections: + if not section.startswith('..'): + section = (s.capitalize() for s in section.split(' ')) + section = ' '.join(section) + if self.get(section): + if hasattr(self, '_obj'): + # we know where the docs came from: + try: + filename = inspect.getsourcefile(self._obj) + except TypeError: + filename = None + msg = ("The section %s appears twice in " + "the docstring of %s in %s." % + (section, self._obj, filename)) + raise ValueError(msg) + else: + msg = ("The section %s appears twice" % section) + raise ValueError(msg) + + if section in ('Parameters', 'Returns', 'Yields', 'Raises', + 'Warns', 'Other Parameters', 'Attributes', + 'Methods'): + self[section] = self._parse_param_list(content) + elif section.startswith('.. index::'): + self['index'] = self._parse_index(section, content) + elif section == 'See Also': + self['See Also'] = self._parse_see_also(content) + else: + self[section] = content + + # string conversion routines + + def _str_header(self, name, symbol='-'): + return [name, len(name)*symbol] + + def _str_indent(self, doc, indent=4): + out = [] + for line in doc: + out += [' '*indent + line] + return out + + def _str_signature(self): + if self['Signature']: + return [self['Signature'].replace('*', '\*')] + [''] + else: + return [''] + + def _str_summary(self): + if self['Summary']: + return self['Summary'] + [''] + else: + return [] + + def _str_extended_summary(self): + if self['Extended Summary']: + return self['Extended Summary'] + [''] + else: + return [] + + def _str_param_list(self, name): + out = [] + if self[name]: + out += self._str_header(name) + for param, param_type, desc in self[name]: + if param_type: + out += ['%s : %s' % (param, param_type)] + else: + out += [param] + out += self._str_indent(desc) + out += [''] + return out + + def _str_section(self, name): + out = [] + if self[name]: + out += self._str_header(name) + out += self[name] + out += [''] + return out + + def _str_see_also(self, func_role): + if not self['See Also']: + return [] + out = [] + out += self._str_header("See Also") + last_had_desc = True + for func, desc, role in self['See Also']: + if role: + link = ':%s:`%s`' % (role, func) + elif func_role: + link = ':%s:`%s`' % (func_role, func) + else: + link = "`%s`_" % func + if desc or last_had_desc: + out += [''] + out += [link] + else: + out[-1] += ", %s" % link + if desc: + out += self._str_indent([' '.join(desc)]) + last_had_desc = True + else: + last_had_desc = False + out += [''] + return out + + def _str_index(self): + idx = self['index'] + out = [] + out += ['.. index:: %s' % idx.get('default', '')] + for section, references in idx.items(): + if section == 'default': + continue + out += [' :%s: %s' % (section, ', '.join(references))] + return out + + def __str__(self, func_role=''): + out = [] + out += self._str_signature() + out += self._str_summary() + out += self._str_extended_summary() + for param_list in ('Parameters', 'Returns', 'Yields', + 'Other Parameters', 'Raises', 'Warns'): + out += self._str_param_list(param_list) + out += self._str_section('Warnings') + out += self._str_see_also(func_role) + for s in ('Notes', 'References', 'Examples'): + out += self._str_section(s) + for param_list in ('Attributes', 'Methods'): + out += self._str_param_list(param_list) + out += self._str_index() + return '\n'.join(out) + + +def indent(str, indent=4): + indent_str = ' '*indent + if str is None: + return indent_str + lines = str.split('\n') + return '\n'.join(indent_str + l for l in lines) + + +def dedent_lines(lines): + """Deindent a list of lines maximally""" + return textwrap.dedent("\n".join(lines)).split("\n") + + +def header(text, style='-'): + return text + '\n' + style*len(text) + '\n' + + +class FunctionDoc(NumpyDocString): + def __init__(self, func, role='func', doc=None, config={}): + self._f = func + self._role = role # e.g. "func" or "meth" + + if doc is None: + if func is None: + raise ValueError("No function or docstring given") + doc = inspect.getdoc(func) or '' + NumpyDocString.__init__(self, doc) + + if not self['Signature'] and func is not None: + func, func_name = self.get_func() + try: + try: + signature = str(inspect.signature(func)) + except (AttributeError, ValueError): + # try to read signature, backward compat for older Python + if sys.version_info[0] >= 3: + argspec = inspect.getfullargspec(func) + else: + argspec = inspect.getargspec(func) + signature = inspect.formatargspec(*argspec) + signature = '%s%s' % (func_name, signature.replace('*', '\*')) + except TypeError: + signature = '%s()' % func_name + self['Signature'] = signature + + def get_func(self): + func_name = getattr(self._f, '__name__', self.__class__.__name__) + if inspect.isclass(self._f): + func = getattr(self._f, '__call__', self._f.__init__) + else: + func = self._f + return func, func_name + + def __str__(self): + out = '' + + func, func_name = self.get_func() + signature = self['Signature'].replace('*', '\*') + + roles = {'func': 'function', + 'meth': 'method'} + + if self._role: + if self._role not in roles: + print("Warning: invalid role %s" % self._role) + out += '.. %s:: %s\n \n\n' % (roles.get(self._role, ''), + func_name) + + out += super(FunctionDoc, self).__str__(func_role=self._role) + return out + + +class ClassDoc(NumpyDocString): + + extra_public_methods = ['__call__'] + + def __init__(self, cls, doc=None, modulename='', func_doc=FunctionDoc, + config={}): + if not inspect.isclass(cls) and cls is not None: + raise ValueError("Expected a class or None, but got %r" % cls) + self._cls = cls + + self.show_inherited_members = config.get( + 'show_inherited_class_members', True) + + if modulename and not modulename.endswith('.'): + modulename += '.' + self._mod = modulename + + if doc is None: + if cls is None: + raise ValueError("No class or documentation string given") + doc = pydoc.getdoc(cls) + + NumpyDocString.__init__(self, doc) + + if config.get('show_class_members', True): + def splitlines_x(s): + if not s: + return [] + else: + return s.splitlines() + + for field, items in [('Methods', self.methods), + ('Attributes', self.properties)]: + if not self[field]: + doc_list = [] + for name in sorted(items): + try: + doc_item = pydoc.getdoc(getattr(self._cls, name)) + doc_list.append((name, '', splitlines_x(doc_item))) + except AttributeError: + pass # method doesn't exist + self[field] = doc_list + + @property + def methods(self): + if self._cls is None: + return [] + return [name for name, func in inspect.getmembers(self._cls) + if ((not name.startswith('_') + or name in self.extra_public_methods) + and isinstance(func, collections.Callable) + and self._is_show_member(name))] + + @property + def properties(self): + if self._cls is None: + return [] + return [name for name, func in inspect.getmembers(self._cls) + if (not name.startswith('_') and + (func is None or isinstance(func, property) or + inspect.isgetsetdescriptor(func)) + and self._is_show_member(name))] + + def _is_show_member(self, name): + if self.show_inherited_members: + return True # show all class members + if name not in self._cls.__dict__: + return False # class member is inherited, we do not show it + return True diff --git a/doc/sphinxext/numpydoc/docscrape_sphinx.py b/doc/sphinxext/numpydoc/docscrape_sphinx.py new file mode 100644 index 0000000..d8a495e --- /dev/null +++ b/doc/sphinxext/numpydoc/docscrape_sphinx.py @@ -0,0 +1,309 @@ +from __future__ import division, absolute_import, print_function + +import sys +import re +import inspect +import textwrap +import pydoc +import collections +import os + +from jinja2 import FileSystemLoader +from jinja2.sandbox import SandboxedEnvironment +import sphinx +from sphinx.jinja2glue import BuiltinTemplateLoader + +from .docscrape import NumpyDocString, FunctionDoc, ClassDoc + +if sys.version_info[0] >= 3: + sixu = lambda s: s +else: + sixu = lambda s: unicode(s, 'unicode_escape') + + +class SphinxDocString(NumpyDocString): + def __init__(self, docstring, config={}): + NumpyDocString.__init__(self, docstring, config=config) + self.load_config(config) + + def load_config(self, config): + self.use_plots = config.get('use_plots', False) + self.class_members_toctree = config.get('class_members_toctree', True) + self.template = config.get('template', None) + if self.template is None: + template_dirs = [os.path.join(os.path.dirname(__file__), 'templates')] + template_loader = FileSystemLoader(template_dirs) + template_env = SandboxedEnvironment(loader=template_loader) + self.template = template_env.get_template('numpydoc_docstring.rst') + + # string conversion routines + def _str_header(self, name, symbol='`'): + return ['.. rubric:: ' + name, ''] + + def _str_field_list(self, name): + return [':' + name + ':'] + + def _str_indent(self, doc, indent=4): + out = [] + for line in doc: + out += [' '*indent + line] + return out + + def _str_signature(self): + return [''] + if self['Signature']: + return ['``%s``' % self['Signature']] + [''] + else: + return [''] + + def _str_summary(self): + return self['Summary'] + [''] + + def _str_extended_summary(self): + return self['Extended Summary'] + [''] + + def _str_returns(self, name='Returns'): + out = [] + if self[name]: + out += self._str_field_list(name) + out += [''] + for param, param_type, desc in self[name]: + if param_type: + out += self._str_indent(['**%s** : %s' % (param.strip(), + param_type)]) + else: + out += self._str_indent([param.strip()]) + if desc: + out += [''] + out += self._str_indent(desc, 8) + out += [''] + return out + + def _str_param_list(self, name): + out = [] + if self[name]: + out += self._str_field_list(name) + out += [''] + for param, param_type, desc in self[name]: + if param_type: + out += self._str_indent(['**%s** : %s' % (param.strip(), + param_type)]) + else: + out += self._str_indent(['**%s**' % param.strip()]) + if desc: + out += [''] + out += self._str_indent(desc, 8) + out += [''] + return out + + @property + def _obj(self): + if hasattr(self, '_cls'): + return self._cls + elif hasattr(self, '_f'): + return self._f + return None + + def _str_member_list(self, name): + """ + Generate a member listing, autosummary:: table where possible, + and a table where not. + + """ + out = [] + if self[name]: + out += ['.. rubric:: %s' % name, ''] + prefix = getattr(self, '_name', '') + + if prefix: + prefix = '~%s.' % prefix + + autosum = [] + others = [] + for param, param_type, desc in self[name]: + param = param.strip() + + # Check if the referenced member can have a docstring or not + param_obj = getattr(self._obj, param, None) + if not (callable(param_obj) + or isinstance(param_obj, property) + or inspect.isgetsetdescriptor(param_obj)): + param_obj = None + + if param_obj and (pydoc.getdoc(param_obj) or not desc): + # Referenced object has a docstring + autosum += [" %s%s" % (prefix, param)] + else: + others.append((param, param_type, desc)) + + if autosum: + out += ['.. autosummary::'] + if self.class_members_toctree: + out += [' :toctree:'] + out += [''] + autosum + + if others: + maxlen_0 = max(3, max([len(x[0]) + 4 for x in others])) + hdr = sixu("=") * maxlen_0 + sixu(" ") + sixu("=") * 10 + fmt = sixu('%%%ds %%s ') % (maxlen_0,) + out += ['', '', hdr] + for param, param_type, desc in others: + desc = sixu(" ").join(x.strip() for x in desc).strip() + if param_type: + desc = "(%s) %s" % (param_type, desc) + out += [fmt % ("**" + param.strip() + "**", desc)] + out += [hdr] + out += [''] + return out + + def _str_section(self, name): + out = [] + if self[name]: + out += self._str_header(name) + out += [''] + content = textwrap.dedent("\n".join(self[name])).split("\n") + out += content + out += [''] + return out + + def _str_see_also(self, func_role): + out = [] + if self['See Also']: + see_also = super(SphinxDocString, self)._str_see_also(func_role) + out = ['.. seealso::', ''] + out += self._str_indent(see_also[2:]) + return out + + def _str_warnings(self): + out = [] + if self['Warnings']: + out = ['.. warning::', ''] + out += self._str_indent(self['Warnings']) + return out + + def _str_index(self): + idx = self['index'] + out = [] + if len(idx) == 0: + return out + + out += ['.. index:: %s' % idx.get('default', '')] + for section, references in idx.items(): + if section == 'default': + continue + elif section == 'refguide': + out += [' single: %s' % (', '.join(references))] + else: + out += [' %s: %s' % (section, ','.join(references))] + return out + + def _str_references(self): + out = [] + if self['References']: + out += self._str_header('References') + if isinstance(self['References'], str): + self['References'] = [self['References']] + out.extend(self['References']) + out += [''] + # Latex collects all references to a separate bibliography, + # so we need to insert links to it + if sphinx.__version__ >= "0.6": + out += ['.. only:: latex', ''] + else: + out += ['.. latexonly::', ''] + items = [] + for line in self['References']: + m = re.match(r'.. \[([a-z0-9._-]+)\]', line, re.I) + if m: + items.append(m.group(1)) + out += [' ' + ", ".join(["[%s]_" % item for item in items]), ''] + return out + + def _str_examples(self): + examples_str = "\n".join(self['Examples']) + + if (self.use_plots and 'import matplotlib' in examples_str + and 'plot::' not in examples_str): + out = [] + out += self._str_header('Examples') + out += ['.. plot::', ''] + out += self._str_indent(self['Examples']) + out += [''] + return out + else: + return self._str_section('Examples') + + def __str__(self, indent=0, func_role="obj"): + ns = { + 'signature': self._str_signature(), + 'index': self._str_index(), + 'summary': self._str_summary(), + 'extended_summary': self._str_extended_summary(), + 'parameters': self._str_param_list('Parameters'), + 'returns': self._str_returns('Returns'), + 'yields': self._str_returns('Yields'), + 'other_parameters': self._str_param_list('Other Parameters'), + 'raises': self._str_param_list('Raises'), + 'warns': self._str_param_list('Warns'), + 'warnings': self._str_warnings(), + 'see_also': self._str_see_also(func_role), + 'notes': self._str_section('Notes'), + 'references': self._str_references(), + 'examples': self._str_examples(), + 'attributes': self._str_member_list('Attributes'), + 'methods': self._str_member_list('Methods'), + } + ns = dict((k, '\n'.join(v)) for k, v in ns.items()) + + rendered = self.template.render(**ns) + return '\n'.join(self._str_indent(rendered.split('\n'), indent)) + + +class SphinxFunctionDoc(SphinxDocString, FunctionDoc): + def __init__(self, obj, doc=None, config={}): + self.load_config(config) + FunctionDoc.__init__(self, obj, doc=doc, config=config) + + +class SphinxClassDoc(SphinxDocString, ClassDoc): + def __init__(self, obj, doc=None, func_doc=None, config={}): + self.load_config(config) + ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config) + + +class SphinxObjDoc(SphinxDocString): + def __init__(self, obj, doc=None, config={}): + self._f = obj + self.load_config(config) + SphinxDocString.__init__(self, doc, config=config) + + +def get_doc_object(obj, what=None, doc=None, config={}, builder=None): + if what is None: + if inspect.isclass(obj): + what = 'class' + elif inspect.ismodule(obj): + what = 'module' + elif isinstance(obj, collections.Callable): + what = 'function' + else: + what = 'object' + + template_dirs = [os.path.join(os.path.dirname(__file__), 'templates')] + if builder is not None: + template_loader = BuiltinTemplateLoader() + template_loader.init(builder, dirs=template_dirs) + else: + template_loader = FileSystemLoader(template_dirs) + template_env = SandboxedEnvironment(loader=template_loader) + config['template'] = template_env.get_template('numpydoc_docstring.rst') + + if what == 'class': + return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc, + config=config) + elif what in ('function', 'method'): + return SphinxFunctionDoc(obj, doc=doc, config=config) + else: + if doc is None: + doc = pydoc.getdoc(obj) + return SphinxObjDoc(obj, doc, config=config) diff --git a/doc/sphinxext/numpydoc/numpydoc.py b/doc/sphinxext/numpydoc/numpydoc.py new file mode 100644 index 0000000..7deecc5 --- /dev/null +++ b/doc/sphinxext/numpydoc/numpydoc.py @@ -0,0 +1,271 @@ +""" +======== +numpydoc +======== + +Sphinx extension that handles docstrings in the Numpy standard format. [1] + +It will: + +- Convert Parameters etc. sections to field lists. +- Convert See Also section to a See also entry. +- Renumber references. +- Extract the signature from the docstring, if it can't be determined + otherwise. + +.. [1] https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt + +""" +from __future__ import division, absolute_import, print_function + +import sys +import re +import pydoc +import sphinx +import inspect +import collections + +if sphinx.__version__ < '1.0.1': + raise RuntimeError("Sphinx 1.0.1 or newer is required") + +from .docscrape_sphinx import get_doc_object, SphinxDocString + +if sys.version_info[0] >= 3: + sixu = lambda s: s +else: + sixu = lambda s: unicode(s, 'unicode_escape') + + +def rename_references(app, what, name, obj, options, lines, + reference_offset=[0]): + # replace reference numbers so that there are no duplicates + references = [] + for line in lines: + line = line.strip() + m = re.match(sixu('^.. \\[(%s)\\]') % app.config.numpydoc_citation_re, + line, re.I) + if m: + references.append(m.group(1)) + + if references: + for i, line in enumerate(lines): + for r in references: + if re.match(sixu('^\\d+$'), r): + new_r = sixu("R%d") % (reference_offset[0] + int(r)) + else: + new_r = sixu("%s%d") % (r, reference_offset[0]) + lines[i] = lines[i].replace(sixu('[%s]_') % r, + sixu('[%s]_') % new_r) + lines[i] = lines[i].replace(sixu('.. [%s]') % r, + sixu('.. [%s]') % new_r) + + reference_offset[0] += len(references) + + +def mangle_docstrings(app, what, name, obj, options, lines): + + cfg = {'use_plots': app.config.numpydoc_use_plots, + 'show_class_members': app.config.numpydoc_show_class_members, + 'show_inherited_class_members': + app.config.numpydoc_show_inherited_class_members, + 'class_members_toctree': app.config.numpydoc_class_members_toctree} + + u_NL = sixu('\n') + if what == 'module': + # Strip top title + pattern = '^\\s*[#*=]{4,}\\n[a-z0-9 -]+\\n[#*=]{4,}\\s*' + title_re = re.compile(sixu(pattern), re.I | re.S) + lines[:] = title_re.sub(sixu(''), u_NL.join(lines)).split(u_NL) + else: + doc = get_doc_object(obj, what, u_NL.join(lines), config=cfg, + builder=app.builder) + if sys.version_info[0] >= 3: + doc = str(doc) + else: + doc = unicode(doc) + lines[:] = doc.split(u_NL) + + if (app.config.numpydoc_edit_link and hasattr(obj, '__name__') and + obj.__name__): + if hasattr(obj, '__module__'): + v = dict(full_name=sixu("%s.%s") % (obj.__module__, obj.__name__)) + else: + v = dict(full_name=obj.__name__) + lines += [sixu(''), sixu('.. htmlonly::'), sixu('')] + lines += [sixu(' %s') % x for x in + (app.config.numpydoc_edit_link % v).split("\n")] + + # call function to replace reference numbers so that there are no + # duplicates + rename_references(app, what, name, obj, options, lines) + + +def mangle_signature(app, what, name, obj, options, sig, retann): + # Do not try to inspect classes that don't define `__init__` + if (inspect.isclass(obj) and + (not hasattr(obj, '__init__') or + 'initializes x; see ' in pydoc.getdoc(obj.__init__))): + return '', '' + + if not (isinstance(obj, collections.Callable) or + hasattr(obj, '__argspec_is_invalid_')): + return + + if not hasattr(obj, '__doc__'): + return + doc = SphinxDocString(pydoc.getdoc(obj)) + sig = doc['Signature'] or getattr(obj, '__text_signature__', None) + if sig: + sig = re.sub(sixu("^[^(]*"), sixu(""), sig) + return sig, sixu('') + + +def setup(app, get_doc_object_=get_doc_object): + if not hasattr(app, 'add_config_value'): + return # probably called by nose, better bail out + + global get_doc_object + get_doc_object = get_doc_object_ + + app.connect('autodoc-process-docstring', mangle_docstrings) + app.connect('autodoc-process-signature', mangle_signature) + app.add_config_value('numpydoc_edit_link', None, False) + app.add_config_value('numpydoc_use_plots', None, False) + app.add_config_value('numpydoc_show_class_members', True, True) + app.add_config_value('numpydoc_show_inherited_class_members', True, True) + app.add_config_value('numpydoc_class_members_toctree', True, True) + app.add_config_value('numpydoc_citation_re', '[a-z0-9_.-]+', True) + + # Extra mangling domains + app.add_domain(NumpyPythonDomain) + app.add_domain(NumpyCDomain) + + metadata = {'parallel_read_safe': True} + return metadata + +# ------------------------------------------------------------------------------ +# Docstring-mangling domains +# ------------------------------------------------------------------------------ + +from docutils.statemachine import ViewList +from sphinx.domains.c import CDomain +from sphinx.domains.python import PythonDomain + + +class ManglingDomainBase(object): + directive_mangling_map = {} + + def __init__(self, *a, **kw): + super(ManglingDomainBase, self).__init__(*a, **kw) + self.wrap_mangling_directives() + + def wrap_mangling_directives(self): + for name, objtype in list(self.directive_mangling_map.items()): + self.directives[name] = wrap_mangling_directive( + self.directives[name], objtype) + + +class NumpyPythonDomain(ManglingDomainBase, PythonDomain): + name = 'np' + directive_mangling_map = { + 'function': 'function', + 'class': 'class', + 'exception': 'class', + 'method': 'function', + 'classmethod': 'function', + 'staticmethod': 'function', + 'attribute': 'attribute', + } + indices = [] + + +class NumpyCDomain(ManglingDomainBase, CDomain): + name = 'np-c' + directive_mangling_map = { + 'function': 'function', + 'member': 'attribute', + 'macro': 'function', + 'type': 'class', + 'var': 'object', + } + + +def match_items(lines, content_old): + """Create items for mangled lines. + + This function tries to match the lines in ``lines`` with the items (source + file references and line numbers) in ``content_old``. The + ``mangle_docstrings`` function changes the actual docstrings, but doesn't + keep track of where each line came from. The manging does many operations + on the original lines, which are hard to track afterwards. + + Many of the line changes come from deleting or inserting blank lines. This + function tries to match lines by ignoring blank lines. All other changes + (such as inserting figures or changes in the references) are completely + ignored, so the generated line numbers will be off if ``mangle_docstrings`` + does anything non-trivial. + + This is a best-effort function and the real fix would be to make + ``mangle_docstrings`` actually keep track of the ``items`` together with + the ``lines``. + + Examples + -------- + >>> lines = ['', 'A', '', 'B', ' ', '', 'C', 'D'] + >>> lines_old = ['a', '', '', 'b', '', 'c'] + >>> items_old = [('file1.py', 0), ('file1.py', 1), ('file1.py', 2), + ... ('file2.py', 0), ('file2.py', 1), ('file2.py', 2)] + >>> content_old = ViewList(lines_old, items=items_old) + >>> match_items(lines, content_old) # doctest: +NORMALIZE_WHITESPACE + [('file1.py', 0), ('file1.py', 0), ('file2.py', 0), ('file2.py', 0), + ('file2.py', 2), ('file2.py', 2), ('file2.py', 2), ('file2.py', 2)] + >>> # first 2 ``lines`` are matched to 'a', second 2 to 'b', rest to 'c' + >>> # actual content is completely ignored. + + Notes + ----- + The algorithm tries to match any line in ``lines`` with one in + ``lines_old``. It skips over all empty lines in ``lines_old`` and assigns + this line number to all lines in ``lines``, unless a non-empty line is + found in ``lines`` in which case it goes to the next line in ``lines_old``. + + """ + items_new = [] + lines_old = content_old.data + items_old = content_old.items + j = 0 + for i, line in enumerate(lines): + # go to next non-empty line in old: + # line.strip() checks whether the string is all whitespace + while j < len(lines_old) - 1 and not lines_old[j].strip(): + j += 1 + items_new.append(items_old[j]) + if line.strip() and j < len(lines_old) - 1: + j += 1 + assert(len(items_new) == len(lines)) + return items_new + + +def wrap_mangling_directive(base_directive, objtype): + class directive(base_directive): + def run(self): + env = self.state.document.settings.env + + name = None + if self.arguments: + m = re.match(r'^(.*\s+)?(.*?)(\(.*)?', self.arguments[0]) + name = m.group(2).strip() + + if not name: + name = self.arguments[0] + + lines = list(self.content) + mangle_docstrings(env.app, objtype, name, None, None, lines) + if self.content: + items = match_items(lines, self.content) + self.content = ViewList(lines, items=items, + parent=self.content.parent) + + return base_directive.run(self) + + return directive diff --git a/doc/sphinxext/numpydoc/templates/numpydoc_docstring.rst b/doc/sphinxext/numpydoc/templates/numpydoc_docstring.rst new file mode 100644 index 0000000..1900db5 --- /dev/null +++ b/doc/sphinxext/numpydoc/templates/numpydoc_docstring.rst @@ -0,0 +1,16 @@ +{{index}} +{{summary}} +{{extended_summary}} +{{parameters}} +{{returns}} +{{yields}} +{{other_parameters}} +{{raises}} +{{warns}} +{{warnings}} +{{see_also}} +{{notes}} +{{references}} +{{examples}} +{{attributes}} +{{methods}} diff --git a/doc/sphinxext/numpydoc/tests/test_docscrape.py b/doc/sphinxext/numpydoc/tests/test_docscrape.py new file mode 100644 index 0000000..297a0ac --- /dev/null +++ b/doc/sphinxext/numpydoc/tests/test_docscrape.py @@ -0,0 +1,1027 @@ +# -*- encoding:utf-8 -*- +from __future__ import division, absolute_import, print_function + +import sys +import textwrap + +import jinja2 + +from numpydoc.docscrape import ( + NumpyDocString, + FunctionDoc, + ClassDoc, + ParseError +) +from numpydoc.docscrape_sphinx import (SphinxDocString, SphinxClassDoc, + SphinxFunctionDoc) +from nose.tools import (assert_equal, assert_raises, assert_list_equal, + assert_true) + +if sys.version_info[0] >= 3: + sixu = lambda s: s +else: + sixu = lambda s: unicode(s, 'unicode_escape') + + +doc_txt = '''\ + numpy.multivariate_normal(mean, cov, shape=None, spam=None) + + Draw values from a multivariate normal distribution with specified + mean and covariance. + + The multivariate normal or Gaussian distribution is a generalisation + of the one-dimensional normal distribution to higher dimensions. + + Parameters + ---------- + mean : (N,) ndarray + Mean of the N-dimensional distribution. + + .. math:: + + (1+2+3)/3 + + cov : (N, N) ndarray + Covariance matrix of the distribution. + shape : tuple of ints + Given a shape of, for example, (m,n,k), m*n*k samples are + generated, and packed in an m-by-n-by-k arrangement. Because + each sample is N-dimensional, the output shape is (m,n,k,N). + + Returns + ------- + out : ndarray + The drawn samples, arranged according to `shape`. If the + shape given is (m,n,...), then the shape of `out` is is + (m,n,...,N). + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + list of str + This is not a real return value. It exists to test + anonymous return values. + + Other Parameters + ---------------- + spam : parrot + A parrot off its mortal coil. + + Raises + ------ + RuntimeError + Some error + + Warns + ----- + RuntimeWarning + Some warning + + Warnings + -------- + Certain warnings apply. + + Notes + ----- + Instead of specifying the full covariance matrix, popular + approximations include: + + - Spherical covariance (`cov` is a multiple of the identity matrix) + - Diagonal covariance (`cov` has non-negative elements only on the diagonal) + + This geometrical property can be seen in two dimensions by plotting + generated data-points: + + >>> mean = [0,0] + >>> cov = [[1,0],[0,100]] # diagonal covariance, points lie on x or y-axis + + >>> x,y = multivariate_normal(mean,cov,5000).T + >>> plt.plot(x,y,'x'); plt.axis('equal'); plt.show() + + Note that the covariance matrix must be symmetric and non-negative + definite. + + References + ---------- + .. [1] A. Papoulis, "Probability, Random Variables, and Stochastic + Processes," 3rd ed., McGraw-Hill Companies, 1991 + .. [2] R.O. Duda, P.E. Hart, and D.G. Stork, "Pattern Classification," + 2nd ed., Wiley, 2001. + + See Also + -------- + some, other, funcs + otherfunc : relationship + + Examples + -------- + >>> mean = (1,2) + >>> cov = [[1,0],[1,0]] + >>> x = multivariate_normal(mean,cov,(3,3)) + >>> print x.shape + (3, 3, 2) + + The following is probably true, given that 0.6 is roughly twice the + standard deviation: + + >>> print list( (x[0,0,:] - mean) < 0.6 ) + [True, True] + + .. index:: random + :refguide: random;distributions, random;gauss + + ''' +doc = NumpyDocString(doc_txt) + +doc_yields_txt = """ +Test generator + +Yields +------ +a : int + The number of apples. +b : int + The number of bananas. +int + The number of unknowns. +""" +doc_yields = NumpyDocString(doc_yields_txt) + + +def test_signature(): + assert doc['Signature'].startswith('numpy.multivariate_normal(') + assert doc['Signature'].endswith('spam=None)') + +def test_summary(): + assert doc['Summary'][0].startswith('Draw values') + assert doc['Summary'][-1].endswith('covariance.') + +def test_extended_summary(): + assert doc['Extended Summary'][0].startswith('The multivariate normal') + +def test_parameters(): + assert_equal(len(doc['Parameters']), 3) + assert_equal([n for n,_,_ in doc['Parameters']], ['mean','cov','shape']) + + arg, arg_type, desc = doc['Parameters'][1] + assert_equal(arg_type, '(N, N) ndarray') + assert desc[0].startswith('Covariance matrix') + assert doc['Parameters'][0][-1][-2] == ' (1+2+3)/3' + +def test_other_parameters(): + assert_equal(len(doc['Other Parameters']), 1) + assert_equal([n for n,_,_ in doc['Other Parameters']], ['spam']) + arg, arg_type, desc = doc['Other Parameters'][0] + assert_equal(arg_type, 'parrot') + assert desc[0].startswith('A parrot off its mortal coil') + +def test_returns(): + assert_equal(len(doc['Returns']), 2) + arg, arg_type, desc = doc['Returns'][0] + assert_equal(arg, 'out') + assert_equal(arg_type, 'ndarray') + assert desc[0].startswith('The drawn samples') + assert desc[-1].endswith('distribution.') + + arg, arg_type, desc = doc['Returns'][1] + assert_equal(arg, 'list of str') + assert_equal(arg_type, '') + assert desc[0].startswith('This is not a real') + assert desc[-1].endswith('anonymous return values.') + +def test_yields(): + section = doc_yields['Yields'] + assert_equal(len(section), 3) + truth = [('a', 'int', 'apples.'), + ('b', 'int', 'bananas.'), + ('int', '', 'unknowns.')] + for (arg, arg_type, desc), (arg_, arg_type_, end) in zip(section, truth): + assert_equal(arg, arg_) + assert_equal(arg_type, arg_type_) + assert desc[0].startswith('The number of') + assert desc[0].endswith(end) + +def test_returnyield(): + doc_text = """ +Test having returns and yields. + +Returns +------- +int + The number of apples. + +Yields +------ +a : int + The number of apples. +b : int + The number of bananas. + +""" + assert_raises(ValueError, NumpyDocString, doc_text) + + +def test_section_twice(): + doc_text = """ +Test having a section Notes twice + +Notes +----- +See the next note for more information + +Notes +----- +That should break... +""" + assert_raises(ValueError, NumpyDocString, doc_text) + + # if we have a numpydoc object, we know where the error came from + class Dummy(object): + """ + Dummy class. + + Notes + ----- + First note. + + Notes + ----- + Second note. + + """ + def spam(self, a, b): + """Spam\n\nSpam spam.""" + pass + + def ham(self, c, d): + """Cheese\n\nNo cheese.""" + pass + + def dummy_func(arg): + """ + Dummy function. + + Notes + ----- + First note. + + Notes + ----- + Second note. + """ + + try: + SphinxClassDoc(Dummy) + except ValueError as e: + # python 3 version or python 2 version + assert_true("test_section_twice..Dummy" in str(e) + or 'test_docscrape.Dummy' in str(e)) + + try: + SphinxFunctionDoc(dummy_func) + except ValueError as e: + # python 3 version or python 2 version + assert_true("test_section_twice..dummy_func" in str(e) + or 'function dummy_func' in str(e)) + + +def test_notes(): + assert doc['Notes'][0].startswith('Instead') + assert doc['Notes'][-1].endswith('definite.') + assert_equal(len(doc['Notes']), 17) + +def test_references(): + assert doc['References'][0].startswith('..') + assert doc['References'][-1].endswith('2001.') + +def test_examples(): + assert doc['Examples'][0].startswith('>>>') + assert doc['Examples'][-1].endswith('True]') + +def test_index(): + assert_equal(doc['index']['default'], 'random') + assert_equal(len(doc['index']), 2) + assert_equal(len(doc['index']['refguide']), 2) + +def non_blank_line_by_line_compare(a,b): + a = textwrap.dedent(a) + b = textwrap.dedent(b) + a = [l.rstrip() for l in a.split('\n') if l.strip()] + b = [l.rstrip() for l in b.split('\n') if l.strip()] + assert_list_equal(a, b) + +def test_str(): + # doc_txt has the order of Notes and See Also sections flipped. + # This should be handled automatically, and so, one thing this test does + # is to make sure that See Also precedes Notes in the output. + non_blank_line_by_line_compare(str(doc), +"""numpy.multivariate_normal(mean, cov, shape=None, spam=None) + +Draw values from a multivariate normal distribution with specified +mean and covariance. + +The multivariate normal or Gaussian distribution is a generalisation +of the one-dimensional normal distribution to higher dimensions. + +Parameters +---------- +mean : (N,) ndarray + Mean of the N-dimensional distribution. + + .. math:: + + (1+2+3)/3 + +cov : (N, N) ndarray + Covariance matrix of the distribution. +shape : tuple of ints + Given a shape of, for example, (m,n,k), m*n*k samples are + generated, and packed in an m-by-n-by-k arrangement. Because + each sample is N-dimensional, the output shape is (m,n,k,N). + +Returns +------- +out : ndarray + The drawn samples, arranged according to `shape`. If the + shape given is (m,n,...), then the shape of `out` is is + (m,n,...,N). + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. +list of str + This is not a real return value. It exists to test + anonymous return values. + +Other Parameters +---------------- +spam : parrot + A parrot off its mortal coil. + +Raises +------ +RuntimeError + Some error + +Warns +----- +RuntimeWarning + Some warning + +Warnings +-------- +Certain warnings apply. + +See Also +-------- +`some`_, `other`_, `funcs`_ + +`otherfunc`_ + relationship + +Notes +----- +Instead of specifying the full covariance matrix, popular +approximations include: + + - Spherical covariance (`cov` is a multiple of the identity matrix) + - Diagonal covariance (`cov` has non-negative elements only on the diagonal) + +This geometrical property can be seen in two dimensions by plotting +generated data-points: + +>>> mean = [0,0] +>>> cov = [[1,0],[0,100]] # diagonal covariance, points lie on x or y-axis + +>>> x,y = multivariate_normal(mean,cov,5000).T +>>> plt.plot(x,y,'x'); plt.axis('equal'); plt.show() + +Note that the covariance matrix must be symmetric and non-negative +definite. + +References +---------- +.. [1] A. Papoulis, "Probability, Random Variables, and Stochastic + Processes," 3rd ed., McGraw-Hill Companies, 1991 +.. [2] R.O. Duda, P.E. Hart, and D.G. Stork, "Pattern Classification," + 2nd ed., Wiley, 2001. + +Examples +-------- +>>> mean = (1,2) +>>> cov = [[1,0],[1,0]] +>>> x = multivariate_normal(mean,cov,(3,3)) +>>> print x.shape +(3, 3, 2) + +The following is probably true, given that 0.6 is roughly twice the +standard deviation: + +>>> print list( (x[0,0,:] - mean) < 0.6 ) +[True, True] + +.. index:: random + :refguide: random;distributions, random;gauss""") + + +def test_yield_str(): + non_blank_line_by_line_compare(str(doc_yields), +"""Test generator + +Yields +------ +a : int + The number of apples. +b : int + The number of bananas. +int + The number of unknowns. + +.. index:: """) + + +def test_sphinx_str(): + sphinx_doc = SphinxDocString(doc_txt) + non_blank_line_by_line_compare(str(sphinx_doc), +""" +.. index:: random + single: random;distributions, random;gauss + +Draw values from a multivariate normal distribution with specified +mean and covariance. + +The multivariate normal or Gaussian distribution is a generalisation +of the one-dimensional normal distribution to higher dimensions. + +:Parameters: + + **mean** : (N,) ndarray + + Mean of the N-dimensional distribution. + + .. math:: + + (1+2+3)/3 + + **cov** : (N, N) ndarray + + Covariance matrix of the distribution. + + **shape** : tuple of ints + + Given a shape of, for example, (m,n,k), m*n*k samples are + generated, and packed in an m-by-n-by-k arrangement. Because + each sample is N-dimensional, the output shape is (m,n,k,N). + +:Returns: + + **out** : ndarray + + The drawn samples, arranged according to `shape`. If the + shape given is (m,n,...), then the shape of `out` is is + (m,n,...,N). + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + + list of str + + This is not a real return value. It exists to test + anonymous return values. + +:Other Parameters: + + **spam** : parrot + + A parrot off its mortal coil. + +:Raises: + + **RuntimeError** + + Some error + +:Warns: + + **RuntimeWarning** + + Some warning + +.. warning:: + + Certain warnings apply. + +.. seealso:: + + :obj:`some`, :obj:`other`, :obj:`funcs` + + :obj:`otherfunc` + relationship + +.. rubric:: Notes + +Instead of specifying the full covariance matrix, popular +approximations include: + + - Spherical covariance (`cov` is a multiple of the identity matrix) + - Diagonal covariance (`cov` has non-negative elements only on the diagonal) + +This geometrical property can be seen in two dimensions by plotting +generated data-points: + +>>> mean = [0,0] +>>> cov = [[1,0],[0,100]] # diagonal covariance, points lie on x or y-axis + +>>> x,y = multivariate_normal(mean,cov,5000).T +>>> plt.plot(x,y,'x'); plt.axis('equal'); plt.show() + +Note that the covariance matrix must be symmetric and non-negative +definite. + +.. rubric:: References + +.. [1] A. Papoulis, "Probability, Random Variables, and Stochastic + Processes," 3rd ed., McGraw-Hill Companies, 1991 +.. [2] R.O. Duda, P.E. Hart, and D.G. Stork, "Pattern Classification," + 2nd ed., Wiley, 2001. + +.. only:: latex + + [1]_, [2]_ + +.. rubric:: Examples + +>>> mean = (1,2) +>>> cov = [[1,0],[1,0]] +>>> x = multivariate_normal(mean,cov,(3,3)) +>>> print x.shape +(3, 3, 2) + +The following is probably true, given that 0.6 is roughly twice the +standard deviation: + +>>> print list( (x[0,0,:] - mean) < 0.6 ) +[True, True] +""") + + +def test_sphinx_yields_str(): + sphinx_doc = SphinxDocString(doc_yields_txt) + non_blank_line_by_line_compare(str(sphinx_doc), +"""Test generator + +:Yields: + + **a** : int + + The number of apples. + + **b** : int + + The number of bananas. + + int + + The number of unknowns. +""") + + +doc2 = NumpyDocString(""" + Returns array of indices of the maximum values of along the given axis. + + Parameters + ---------- + a : {array_like} + Array to look in. + axis : {None, integer} + If None, the index is into the flattened array, otherwise along + the specified axis""") + +def test_parameters_without_extended_description(): + assert_equal(len(doc2['Parameters']), 2) + +doc3 = NumpyDocString(""" + my_signature(*params, **kwds) + + Return this and that. + """) + +def test_escape_stars(): + signature = str(doc3).split('\n')[0] + assert_equal(signature, 'my_signature(\*params, \*\*kwds)') + + def my_func(a, b, **kwargs): + pass + + fdoc = FunctionDoc(func=my_func) + assert_equal(fdoc['Signature'], 'my_func(a, b, \*\*kwargs)') + +doc4 = NumpyDocString( + """a.conj() + + Return an array with all complex-valued elements conjugated.""") + +def test_empty_extended_summary(): + assert_equal(doc4['Extended Summary'], []) + +doc5 = NumpyDocString( + """ + a.something() + + Raises + ------ + LinAlgException + If array is singular. + + Warns + ----- + SomeWarning + If needed + """) + +def test_raises(): + assert_equal(len(doc5['Raises']), 1) + name,_,desc = doc5['Raises'][0] + assert_equal(name,'LinAlgException') + assert_equal(desc,['If array is singular.']) + +def test_warns(): + assert_equal(len(doc5['Warns']), 1) + name,_,desc = doc5['Warns'][0] + assert_equal(name,'SomeWarning') + assert_equal(desc,['If needed']) + +def test_see_also(): + doc6 = NumpyDocString( + """ + z(x,theta) + + See Also + -------- + func_a, func_b, func_c + func_d : some equivalent func + foo.func_e : some other func over + multiple lines + func_f, func_g, :meth:`func_h`, func_j, + func_k + :obj:`baz.obj_q` + :class:`class_j`: fubar + foobar + """) + + assert len(doc6['See Also']) == 12 + for func, desc, role in doc6['See Also']: + if func in ('func_a', 'func_b', 'func_c', 'func_f', + 'func_g', 'func_h', 'func_j', 'func_k', 'baz.obj_q'): + assert(not desc) + else: + assert(desc) + + if func == 'func_h': + assert role == 'meth' + elif func == 'baz.obj_q': + assert role == 'obj' + elif func == 'class_j': + assert role == 'class' + else: + assert role is None + + if func == 'func_d': + assert desc == ['some equivalent func'] + elif func == 'foo.func_e': + assert desc == ['some other func over', 'multiple lines'] + elif func == 'class_j': + assert desc == ['fubar', 'foobar'] + + +def test_see_also_parse_error(): + text = ( + """ + z(x,theta) + + See Also + -------- + :func:`~foo` + """) + with assert_raises(ParseError) as err: + NumpyDocString(text) + assert_equal( + str(r":func:`~foo` is not a item name in '\n z(x,theta)\n\n See Also\n --------\n :func:`~foo`\n '"), + str(err.exception) + ) + +def test_see_also_print(): + class Dummy(object): + """ + See Also + -------- + func_a, func_b + func_c : some relationship + goes here + func_d + """ + pass + + obj = Dummy() + s = str(FunctionDoc(obj, role='func')) + assert(':func:`func_a`, :func:`func_b`' in s) + assert(' some relationship' in s) + assert(':func:`func_d`' in s) + +doc7 = NumpyDocString(""" + + Doc starts on second line. + + """) + +def test_empty_first_line(): + assert doc7['Summary'][0].startswith('Doc starts') + + +def test_no_summary(): + str(SphinxDocString(""" + Parameters + ----------""")) + + +def test_unicode(): + doc = SphinxDocString(""" + öäöäöäöäöåååå + + öäöäöäööäååå + + Parameters + ---------- + ååå : äää + ööö + + Returns + ------- + ååå : ööö + äää + + """) + assert isinstance(doc['Summary'][0], str) + assert doc['Summary'][0] == 'öäöäöäöäöåååå' + +def test_plot_examples(): + cfg = dict(use_plots=True) + + doc = SphinxDocString(""" + Examples + -------- + >>> import matplotlib.pyplot as plt + >>> plt.plot([1,2,3],[4,5,6]) + >>> plt.show() + """, config=cfg) + assert 'plot::' in str(doc), str(doc) + + doc = SphinxDocString(""" + Examples + -------- + .. plot:: + + import matplotlib.pyplot as plt + plt.plot([1,2,3],[4,5,6]) + plt.show() + """, config=cfg) + assert str(doc).count('plot::') == 1, str(doc) + +def test_class_members(): + + class Dummy(object): + """ + Dummy class. + + """ + def spam(self, a, b): + """Spam\n\nSpam spam.""" + pass + def ham(self, c, d): + """Cheese\n\nNo cheese.""" + pass + @property + def spammity(self): + """Spammity index""" + return 0.95 + + class Ignorable(object): + """local class, to be ignored""" + pass + + for cls in (ClassDoc, SphinxClassDoc): + doc = cls(Dummy, config=dict(show_class_members=False)) + assert 'Methods' not in str(doc), (cls, str(doc)) + assert 'spam' not in str(doc), (cls, str(doc)) + assert 'ham' not in str(doc), (cls, str(doc)) + assert 'spammity' not in str(doc), (cls, str(doc)) + assert 'Spammity index' not in str(doc), (cls, str(doc)) + + doc = cls(Dummy, config=dict(show_class_members=True)) + assert 'Methods' in str(doc), (cls, str(doc)) + assert 'spam' in str(doc), (cls, str(doc)) + assert 'ham' in str(doc), (cls, str(doc)) + assert 'spammity' in str(doc), (cls, str(doc)) + + if cls is SphinxClassDoc: + assert '.. autosummary::' in str(doc), str(doc) + else: + assert 'Spammity index' in str(doc), str(doc) + + class SubDummy(Dummy): + """ + Subclass of Dummy class. + + """ + def ham(self, c, d): + """Cheese\n\nNo cheese.\nOverloaded Dummy.ham""" + pass + + def bar(self, a, b): + """Bar\n\nNo bar""" + pass + + for cls in (ClassDoc, SphinxClassDoc): + doc = cls(SubDummy, config=dict(show_class_members=True, + show_inherited_class_members=False)) + assert 'Methods' in str(doc), (cls, str(doc)) + assert 'spam' not in str(doc), (cls, str(doc)) + assert 'ham' in str(doc), (cls, str(doc)) + assert 'bar' in str(doc), (cls, str(doc)) + assert 'spammity' not in str(doc), (cls, str(doc)) + + if cls is SphinxClassDoc: + assert '.. autosummary::' in str(doc), str(doc) + else: + assert 'Spammity index' not in str(doc), str(doc) + + doc = cls(SubDummy, config=dict(show_class_members=True, + show_inherited_class_members=True)) + assert 'Methods' in str(doc), (cls, str(doc)) + assert 'spam' in str(doc), (cls, str(doc)) + assert 'ham' in str(doc), (cls, str(doc)) + assert 'bar' in str(doc), (cls, str(doc)) + assert 'spammity' in str(doc), (cls, str(doc)) + + if cls is SphinxClassDoc: + assert '.. autosummary::' in str(doc), str(doc) + else: + assert 'Spammity index' in str(doc), str(doc) + +def test_duplicate_signature(): + # Duplicate function signatures occur e.g. in ufuncs, when the + # automatic mechanism adds one, and a more detailed comes from the + # docstring itself. + + doc = NumpyDocString( + """ + z(x1, x2) + + z(a, theta) + """) + + assert doc['Signature'].strip() == 'z(a, theta)' + + +class_doc_txt = """ + Foo + + Parameters + ---------- + f : callable ``f(t, y, *f_args)`` + Aaa. + jac : callable ``jac(t, y, *jac_args)`` + Bbb. + + Attributes + ---------- + t : float + Current time. + y : ndarray + Current variable values. + x : float + Some parameter + + Methods + ------- + a + b + c + + Examples + -------- + For usage examples, see `ode`. +""" + +def test_class_members_doc(): + doc = ClassDoc(None, class_doc_txt) + non_blank_line_by_line_compare(str(doc), + """ + Foo + + Parameters + ---------- + f : callable ``f(t, y, *f_args)`` + Aaa. + jac : callable ``jac(t, y, *jac_args)`` + Bbb. + + Examples + -------- + For usage examples, see `ode`. + + Attributes + ---------- + t : float + Current time. + y : ndarray + Current variable values. + x : float + Some parameter + + Methods + ------- + a + + b + + c + + .. index:: + + """) + +def test_class_members_doc_sphinx(): + class Foo: + @property + def x(self): + """Test attribute""" + return None + + doc = SphinxClassDoc(Foo, class_doc_txt) + non_blank_line_by_line_compare(str(doc), + """ + Foo + + :Parameters: + + **f** : callable ``f(t, y, *f_args)`` + + Aaa. + + **jac** : callable ``jac(t, y, *jac_args)`` + + Bbb. + + .. rubric:: Examples + + For usage examples, see `ode`. + + .. rubric:: Attributes + + .. autosummary:: + :toctree: + + x + + ===== ========== + **t** (float) Current time. + **y** (ndarray) Current variable values. + ===== ========== + + .. rubric:: Methods + + ===== ========== + **a** + **b** + **c** + ===== ========== + + """) + +def test_templated_sections(): + doc = SphinxClassDoc(None, class_doc_txt, + config={'template': jinja2.Template('{{examples}}{{parameters}}')}) + non_blank_line_by_line_compare(str(doc), + """ + .. rubric:: Examples + + For usage examples, see `ode`. + + + :Parameters: + + **f** : callable ``f(t, y, *f_args)`` + + Aaa. + + **jac** : callable ``jac(t, y, *jac_args)`` + + Bbb. + + """) + + + + +if __name__ == "__main__": + import nose + nose.run() diff --git a/doc/sphinxext/setup.py b/doc/sphinxext/setup.py new file mode 100644 index 0000000..b21e82b --- /dev/null +++ b/doc/sphinxext/setup.py @@ -0,0 +1,44 @@ +from __future__ import division, print_function + +import sys + +from distutils.command.sdist import sdist +import setuptools +from distutils.core import setup + +if sys.version_info[:2] < (2, 7) or (3, 0) <= sys.version_info[0:2] < (3, 4): + raise RuntimeError("Python version 2.7 or >= 3.4 required.") + +with open('numpydoc/__init__.py') as fid: + for line in fid: + if line.startswith('__version__'): + version = line.strip().split()[-1][1:-1] + break + +setup( + name="numpydoc", + packages=["numpydoc"], + version=version, + description="Sphinx extension to support docstrings in Numpy format", + # classifiers from http://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=["Development Status :: 4 - Beta", + "Environment :: Plugins", + "License :: OSI Approved :: BSD License", + "Topic :: Documentation", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6"], + keywords="sphinx numpy", + author="Pauli Virtanen and others", + author_email="pav@iki.fi", + url="https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt", + license="BSD", + install_requires=["sphinx >= 1.2.3", 'Jinja2>=2.3'], + package_data={'numpydoc': ['tests/test_*.py', 'templates/*.rst']}, + test_suite = 'nose.collector', + cmdclass={"sdist": sdist}, +) diff --git a/numpy/__init__.py b/numpy/__init__.py new file mode 100644 index 0000000..db99294 --- /dev/null +++ b/numpy/__init__.py @@ -0,0 +1,199 @@ +""" +NumPy +===== + +Provides + 1. An array object of arbitrary homogeneous items + 2. Fast mathematical operations over arrays + 3. Linear Algebra, Fourier Transforms, Random Number Generation + +How to use the documentation +---------------------------- +Documentation is available in two forms: docstrings provided +with the code, and a loose standing reference guide, available from +`the NumPy homepage `_. + +We recommend exploring the docstrings using +`IPython `_, an advanced Python shell with +TAB-completion and introspection capabilities. See below for further +instructions. + +The docstring examples assume that `numpy` has been imported as `np`:: + + >>> import numpy as np + +Code snippets are indicated by three greater-than signs:: + + >>> x = 42 + >>> x = x + 1 + +Use the built-in ``help`` function to view a function's docstring:: + + >>> help(np.sort) + ... # doctest: +SKIP + +For some objects, ``np.info(obj)`` may provide additional help. This is +particularly true if you see the line "Help on ufunc object:" at the top +of the help() page. Ufuncs are implemented in C, not Python, for speed. +The native Python help() does not know how to view their help, but our +np.info() function does. + +To search for documents containing a keyword, do:: + + >>> np.lookfor('keyword') + ... # doctest: +SKIP + +General-purpose documents like a glossary and help on the basic concepts +of numpy are available under the ``doc`` sub-module:: + + >>> from numpy import doc + >>> help(doc) + ... # doctest: +SKIP + +Available subpackages +--------------------- +doc + Topical documentation on broadcasting, indexing, etc. +lib + Basic functions used by several sub-packages. +random + Core Random Tools +linalg + Core Linear Algebra Tools +fft + Core FFT routines +polynomial + Polynomial tools +testing + NumPy testing tools +f2py + Fortran to Python Interface Generator. +distutils + Enhancements to distutils with support for + Fortran compilers support and more. + +Utilities +--------- +test + Run numpy unittests +show_config + Show numpy build configuration +dual + Overwrite certain functions with high-performance Scipy tools +matlib + Make everything matrices. +__version__ + NumPy version string + +Viewing documentation using IPython +----------------------------------- +Start IPython with the NumPy profile (``ipython -p numpy``), which will +import `numpy` under the alias `np`. Then, use the ``cpaste`` command to +paste examples into the shell. To see which functions are available in +`numpy`, type ``np.`` (where ```` refers to the TAB key), or use +``np.*cos*?`` (where ```` refers to the ENTER key) to narrow +down the list. To view the docstring for a function, use +``np.cos?`` (to view the docstring) and ``np.cos??`` (to view +the source code). + +Copies vs. in-place operation +----------------------------- +Most of the functions in `numpy` return a copy of the array argument +(e.g., `np.sort`). In-place versions of these functions are often +available as array methods, i.e. ``x = np.array([1,2,3]); x.sort()``. +Exceptions to this rule are documented. + +""" +from __future__ import division, absolute_import, print_function + +import sys +import warnings + +from ._globals import ModuleDeprecationWarning, VisibleDeprecationWarning +from ._globals import _NoValue + +# We first need to detect if we're being called as part of the numpy setup +# procedure itself in a reliable manner. +try: + __NUMPY_SETUP__ +except NameError: + __NUMPY_SETUP__ = False + +if __NUMPY_SETUP__: + sys.stderr.write('Running from numpy source directory.\n') +else: + try: + from numpy.__config__ import show as show_config + except ImportError: + msg = """Error importing numpy: you should not try to import numpy from + its source directory; please exit the numpy source tree, and relaunch + your python interpreter from there.""" + raise ImportError(msg) + + from .version import git_revision as __git_revision__ + from .version import version as __version__ + + from ._import_tools import PackageLoader + + def pkgload(*packages, **options): + loader = PackageLoader(infunc=True) + return loader(*packages, **options) + + from . import add_newdocs + __all__ = ['add_newdocs', + 'ModuleDeprecationWarning', + 'VisibleDeprecationWarning'] + + pkgload.__doc__ = PackageLoader.__call__.__doc__ + + # We don't actually use this ourselves anymore, but I'm not 100% sure that + # no-one else in the world is using it (though I hope not) + from .testing import Tester, _numpy_tester + test = _numpy_tester().test + bench = _numpy_tester().bench + + # Allow distributors to run custom init code + from . import _distributor_init + + from . import core + from .core import * + from . import compat + from . import lib + from .lib import * + from . import linalg + from . import fft + from . import polynomial + from . import random + from . import ctypeslib + from . import ma + from . import matrixlib as _mat + from .matrixlib import * + from .compat import long + + # Make these accessible from numpy name-space + # but not imported in from numpy import * + 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 + + from .core import round, abs, max, min + + __all__.extend(['__version__', 'pkgload', 'PackageLoader', + 'show_config']) + __all__.extend(core.__all__) + __all__.extend(_mat.__all__) + __all__.extend(lib.__all__) + __all__.extend(['linalg', 'fft', 'random', 'ctypeslib', 'ma']) + + + # Filter annoying Cython warnings that serve no good purpose. + warnings.filterwarnings("ignore", message="numpy.dtype size changed") + warnings.filterwarnings("ignore", message="numpy.ufunc size changed") + warnings.filterwarnings("ignore", message="numpy.ndarray size changed") + + # oldnumeric and numarray were removed in 1.9. In case some packages import + # but do not use them, we define them here for backward compatibility. + oldnumeric = 'removed' + numarray = 'removed' diff --git a/numpy/_build_utils/README b/numpy/_build_utils/README new file mode 100644 index 0000000..6976e02 --- /dev/null +++ b/numpy/_build_utils/README @@ -0,0 +1,8 @@ +======= +WARNING +======= + +This directory (numpy/_build_utils) is *not* part of the public numpy API, + - it is internal build support for numpy. + - it is only present in source distributions or during an in place build + - it is *not* installed with the rest of numpy diff --git a/numpy/_build_utils/__init__.py b/numpy/_build_utils/__init__.py new file mode 100644 index 0000000..1d0f69b --- /dev/null +++ b/numpy/_build_utils/__init__.py @@ -0,0 +1 @@ +from __future__ import division, absolute_import, print_function diff --git a/numpy/_build_utils/apple_accelerate.py b/numpy/_build_utils/apple_accelerate.py new file mode 100644 index 0000000..2d5bbab --- /dev/null +++ b/numpy/_build_utils/apple_accelerate.py @@ -0,0 +1,23 @@ +from __future__ import division, absolute_import, print_function + +import os +import sys +import re + +__all__ = ['uses_accelerate_framework', 'get_sgemv_fix'] + +def uses_accelerate_framework(info): + """ Returns True if Accelerate framework is used for BLAS/LAPACK """ + if sys.platform != "darwin": + return False + r_accelerate = re.compile("Accelerate") + extra_link_args = info.get('extra_link_args', '') + for arg in extra_link_args: + if r_accelerate.search(arg): + return True + return False + +def get_sgemv_fix(): + """ Returns source file needed to correct SGEMV """ + path = os.path.abspath(os.path.dirname(__file__)) + return [os.path.join(path, 'src', 'apple_sgemv_fix.c')] diff --git a/numpy/_build_utils/common.py b/numpy/_build_utils/common.py new file mode 100644 index 0000000..8435c46 --- /dev/null +++ b/numpy/_build_utils/common.py @@ -0,0 +1,138 @@ +from __future__ import division, absolute_import, print_function + +import sys +import copy +import binascii + +LONG_DOUBLE_REPRESENTATION_SRC = r""" +/* "before" is 16 bytes to ensure there's no padding between it and "x". + * We're not expecting any "long double" bigger than 16 bytes or with + * alignment requirements stricter than 16 bytes. */ +typedef %(type)s test_type; + +struct { + char before[16]; + test_type x; + char after[8]; +} foo = { + { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\001', '\043', '\105', '\147', '\211', '\253', '\315', '\357' }, + -123456789.0, + { '\376', '\334', '\272', '\230', '\166', '\124', '\062', '\020' } +}; +""" + +def pyod(filename): + """Python implementation of the od UNIX utility (od -b, more exactly). + + Parameters + ---------- + filename : str + name of the file to get the dump from. + + Returns + ------- + out : seq + list of lines of od output + + Note + ---- + We only implement enough to get the necessary information for long double + representation, this is not intended as a compatible replacement for od. + """ + def _pyod2(): + out = [] + + fid = open(filename, 'r') + try: + yo = [int(oct(int(binascii.b2a_hex(o), 16))) for o in fid.read()] + for i in range(0, len(yo), 16): + line = ['%07d' % int(oct(i))] + line.extend(['%03d' % c for c in yo[i:i+16]]) + out.append(" ".join(line)) + return out + finally: + fid.close() + + def _pyod3(): + out = [] + + fid = open(filename, 'rb') + try: + yo2 = [oct(o)[2:] for o in fid.read()] + for i in range(0, len(yo2), 16): + line = ['%07d' % int(oct(i)[2:])] + line.extend(['%03d' % int(c) for c in yo2[i:i+16]]) + out.append(" ".join(line)) + return out + finally: + fid.close() + + if sys.version_info[0] < 3: + return _pyod2() + else: + return _pyod3() + +_BEFORE_SEQ = ['000', '000', '000', '000', '000', '000', '000', '000', + '001', '043', '105', '147', '211', '253', '315', '357'] +_AFTER_SEQ = ['376', '334', '272', '230', '166', '124', '062', '020'] + +_IEEE_DOUBLE_BE = ['301', '235', '157', '064', '124', '000', '000', '000'] +_IEEE_DOUBLE_LE = _IEEE_DOUBLE_BE[::-1] +_INTEL_EXTENDED_12B = ['000', '000', '000', '000', '240', '242', '171', '353', + '031', '300', '000', '000'] +_INTEL_EXTENDED_16B = ['000', '000', '000', '000', '240', '242', '171', '353', + '031', '300', '000', '000', '000', '000', '000', '000'] +_IEEE_QUAD_PREC_BE = ['300', '031', '326', '363', '105', '100', '000', '000', + '000', '000', '000', '000', '000', '000', '000', '000'] +_IEEE_QUAD_PREC_LE = _IEEE_QUAD_PREC_BE[::-1] +_DOUBLE_DOUBLE_BE = ['301', '235', '157', '064', '124', '000', '000', '000'] + \ + ['000'] * 8 + +def long_double_representation(lines): + """Given a binary dump as given by GNU od -b, look for long double + representation.""" + + # Read contains a list of 32 items, each item is a byte (in octal + # representation, as a string). We 'slide' over the output until read is of + # the form before_seq + content + after_sequence, where content is the long double + # representation: + # - content is 12 bytes: 80 bits Intel representation + # - content is 16 bytes: 80 bits Intel representation (64 bits) or quad precision + # - content is 8 bytes: same as double (not implemented yet) + read = [''] * 32 + saw = None + for line in lines: + # we skip the first word, as od -b output an index at the beginning of + # each line + for w in line.split()[1:]: + read.pop(0) + read.append(w) + + # If the end of read is equal to the after_sequence, read contains + # the long double + if read[-8:] == _AFTER_SEQ: + saw = copy.copy(read) + if read[:12] == _BEFORE_SEQ[4:]: + if read[12:-8] == _INTEL_EXTENDED_12B: + return 'INTEL_EXTENDED_12_BYTES_LE' + elif read[:8] == _BEFORE_SEQ[8:]: + if read[8:-8] == _INTEL_EXTENDED_16B: + return 'INTEL_EXTENDED_16_BYTES_LE' + elif read[8:-8] == _IEEE_QUAD_PREC_BE: + return 'IEEE_QUAD_BE' + elif read[8:-8] == _IEEE_QUAD_PREC_LE: + return 'IEEE_QUAD_LE' + elif read[8:-8] == _DOUBLE_DOUBLE_BE: + return 'DOUBLE_DOUBLE_BE' + elif read[:16] == _BEFORE_SEQ: + if read[16:-8] == _IEEE_DOUBLE_LE: + return 'IEEE_DOUBLE_LE' + elif read[16:-8] == _IEEE_DOUBLE_BE: + return 'IEEE_DOUBLE_BE' + + if saw is not None: + raise ValueError("Unrecognized format (%s)" % saw) + else: + # We never detected the after_sequence + raise ValueError("Could not lock sequences (%s)" % saw) diff --git a/numpy/_build_utils/src/apple_sgemv_fix.c b/numpy/_build_utils/src/apple_sgemv_fix.c new file mode 100644 index 0000000..4c9c82e --- /dev/null +++ b/numpy/_build_utils/src/apple_sgemv_fix.c @@ -0,0 +1,227 @@ +/* This is a collection of ugly hacks to circumvent a bug in + * Apple Accelerate framework's SGEMV subroutine. + * + * See: https://github.com/numpy/numpy/issues/4007 + * + * SGEMV in Accelerate framework will segfault on MacOS X version 10.9 + * (aka Mavericks) if arrays are not aligned to 32 byte boundaries + * and the CPU supports AVX instructions. This can produce segfaults + * in np.dot. + * + * This patch overshadows the symbols cblas_sgemv, sgemv_ and sgemv + * exported by Accelerate to produce the correct behavior. The MacOS X + * version and CPU specs are checked on module import. If Mavericks and + * AVX are detected the call to SGEMV is emulated with a call to SGEMM + * if the arrays are not 32 byte aligned. If the exported symbols cannot + * be overshadowed on module import, a fatal error is produced and the + * process aborts. All the fixes are in a self-contained C file + * and do not alter the multiarray C code. The patch is not applied + * unless NumPy is configured to link with Apple's Accelerate + * framework. + * + */ + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#include "Python.h" +#include "numpy/arrayobject.h" + +#include +#include +#include +#include + +/* ----------------------------------------------------------------- */ +/* Original cblas_sgemv */ + +#define VECLIB_FILE "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/vecLib" + +enum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102}; +enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113}; +extern void cblas_xerbla(int info, const char *rout, const char *form, ...); + +typedef void cblas_sgemv_t(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const float alpha, const float *A, const int lda, + const float *X, const int incX, + const float beta, float *Y, const int incY); + +typedef void cblas_sgemm_t(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, + const int M, const int N, const int K, + const float alpha, const float *A, const int lda, + const float *B, const int ldb, + const float beta, float *C, const int incC); + +typedef void fortran_sgemv_t( const char* trans, const int* m, const int* n, + const float* alpha, const float* A, const int* ldA, + const float* X, const int* incX, + const float* beta, float* Y, const int* incY ); + +static void *veclib = NULL; +static cblas_sgemv_t *accelerate_cblas_sgemv = NULL; +static cblas_sgemm_t *accelerate_cblas_sgemm = NULL; +static fortran_sgemv_t *accelerate_sgemv = NULL; +static int AVX_and_10_9 = 0; + +/* Dynamic check for AVX support + * __builtin_cpu_supports("avx") is available in gcc 4.8, + * but clang and icc do not currently support it. */ +#define cpu_supports_avx()\ +(system("sysctl -n machdep.cpu.features | grep -q AVX") == 0) + +/* Check if we are using MacOS X version 10.9 */ +#define using_mavericks()\ +(system("sw_vers -productVersion | grep -q 10\\.9\\.") == 0) + +__attribute__((destructor)) +static void unloadlib(void) +{ + if (veclib) dlclose(veclib); +} + +__attribute__((constructor)) +static void loadlib() +/* automatically executed on module import */ +{ + char errormsg[1024]; + int AVX, MAVERICKS; + memset((void*)errormsg, 0, sizeof(errormsg)); + /* check if the CPU supports AVX */ + AVX = cpu_supports_avx(); + /* check if the OS is MacOS X Mavericks */ + MAVERICKS = using_mavericks(); + /* we need the workaround when the CPU supports + * AVX and the OS version is Mavericks */ + AVX_and_10_9 = AVX && MAVERICKS; + /* load vecLib */ + veclib = dlopen(VECLIB_FILE, RTLD_LOCAL | RTLD_FIRST); + if (!veclib) { + veclib = NULL; + snprintf(errormsg, sizeof(errormsg), + "Failed to open vecLib from location '%s'.", VECLIB_FILE); + Py_FatalError(errormsg); /* calls abort() and dumps core */ + } + /* resolve Fortran SGEMV from Accelerate */ + accelerate_sgemv = (fortran_sgemv_t*) dlsym(veclib, "sgemv_"); + if (!accelerate_sgemv) { + unloadlib(); + Py_FatalError("Failed to resolve symbol 'sgemv_'."); + } + /* resolve cblas_sgemv from Accelerate */ + accelerate_cblas_sgemv = (cblas_sgemv_t*) dlsym(veclib, "cblas_sgemv"); + if (!accelerate_cblas_sgemv) { + unloadlib(); + Py_FatalError("Failed to resolve symbol 'cblas_sgemv'."); + } + /* resolve cblas_sgemm from Accelerate */ + accelerate_cblas_sgemm = (cblas_sgemm_t*) dlsym(veclib, "cblas_sgemm"); + if (!accelerate_cblas_sgemm) { + unloadlib(); + Py_FatalError("Failed to resolve symbol 'cblas_sgemm'."); + } +} + +/* ----------------------------------------------------------------- */ +/* Fortran SGEMV override */ + +void sgemv_( const char* trans, const int* m, const int* n, + const float* alpha, const float* A, const int* ldA, + const float* X, const int* incX, + const float* beta, float* Y, const int* incY ) +{ + /* It is safe to use the original SGEMV if we are not using AVX on Mavericks + * or the input arrays A, X and Y are all aligned on 32 byte boundaries. */ + #define BADARRAY(x) (((npy_intp)(void*)x) % 32) + const int use_sgemm = AVX_and_10_9 && (BADARRAY(A) || BADARRAY(X) || BADARRAY(Y)); + if (!use_sgemm) { + accelerate_sgemv(trans,m,n,alpha,A,ldA,X,incX,beta,Y,incY); + return; + } + + /* Arrays are misaligned, the CPU supports AVX, and we are running + * Mavericks. + * + * Emulation of SGEMV with SGEMM: + * + * SGEMV allows vectors to be strided. SGEMM requires all arrays to be + * contiguous along the leading dimension. To emulate striding in SGEMV + * with the leading dimension arguments in SGEMM we compute + * + * Y = alpha * op(A) @ X + beta * Y + * + * as + * + * Y.T = alpha * X.T @ op(A).T + beta * Y.T + * + * Because Fortran uses column major order and X.T and Y.T are row vectors, + * the leading dimensions of X.T and Y.T in SGEMM become equal to the + * strides of the column vectors X and Y in SGEMV. */ + + switch (*trans) { + case 'T': + case 't': + case 'C': + case 'c': + accelerate_cblas_sgemm( CblasColMajor, CblasNoTrans, CblasNoTrans, + 1, *n, *m, *alpha, X, *incX, A, *ldA, *beta, Y, *incY ); + break; + case 'N': + case 'n': + accelerate_cblas_sgemm( CblasColMajor, CblasNoTrans, CblasTrans, + 1, *m, *n, *alpha, X, *incX, A, *ldA, *beta, Y, *incY ); + break; + default: + cblas_xerbla(1, "SGEMV", "Illegal transpose setting: %c\n", *trans); + } +} + +/* ----------------------------------------------------------------- */ +/* Override for an alias symbol for sgemv_ in Accelerate */ + +void sgemv (char *trans, + const int *m, const int *n, + const float *alpha, + const float *A, const int *lda, + const float *B, const int *incB, + const float *beta, + float *C, const int *incC) +{ + sgemv_(trans,m,n,alpha,A,lda,B,incB,beta,C,incC); +} + +/* ----------------------------------------------------------------- */ +/* cblas_sgemv override, based on Netlib CBLAS code */ + +void cblas_sgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const float alpha, const float *A, const int lda, + const float *X, const int incX, const float beta, + float *Y, const int incY) +{ + char TA; + if (order == CblasColMajor) + { + if (TransA == CblasNoTrans) TA = 'N'; + else if (TransA == CblasTrans) TA = 'T'; + else if (TransA == CblasConjTrans) TA = 'C'; + else + { + cblas_xerbla(2, "cblas_sgemv","Illegal TransA setting, %d\n", TransA); + } + sgemv_(&TA, &M, &N, &alpha, A, &lda, X, &incX, &beta, Y, &incY); + } + else if (order == CblasRowMajor) + { + if (TransA == CblasNoTrans) TA = 'T'; + else if (TransA == CblasTrans) TA = 'N'; + else if (TransA == CblasConjTrans) TA = 'N'; + else + { + cblas_xerbla(2, "cblas_sgemv", "Illegal TransA setting, %d\n", TransA); + return; + } + sgemv_(&TA, &N, &M, &alpha, A, &lda, X, &incX, &beta, Y, &incY); + } + else + cblas_xerbla(1, "cblas_sgemv", "Illegal Order setting, %d\n", order); +} diff --git a/numpy/_distributor_init.py b/numpy/_distributor_init.py new file mode 100644 index 0000000..d893ba3 --- /dev/null +++ b/numpy/_distributor_init.py @@ -0,0 +1,10 @@ +""" Distributor init file + +Distributors: you can add custom code here to support particular distributions +of numpy. + +For example, this is a good place to put any checks for hardware requirements. + +The numpy standard source distribution will not put code in this file, so you +can safely replace this file with your own version. +""" diff --git a/numpy/_globals.py b/numpy/_globals.py new file mode 100644 index 0000000..2d7b69b --- /dev/null +++ b/numpy/_globals.py @@ -0,0 +1,62 @@ +""" +Module defining global singleton classes. + +This module raises a RuntimeError if an attempt to reload it is made. In that +way the identities of the classes defined here are fixed and will remain so +even if numpy itself is reloaded. In particular, a function like the following +will still work correctly after numpy is reloaded:: + + def foo(arg=np._NoValue): + if arg is np._NoValue: + ... + +That was not the case when the singleton classes were defined in the numpy +``__init__.py`` file. See gh-7844 for a discussion of the reload problem that +motivated this module. + +""" +from __future__ import division, absolute_import, print_function + + +__ALL__ = [ + 'ModuleDeprecationWarning', 'VisibleDeprecationWarning', '_NoValue' + ] + + +# Disallow reloading this module so as to preserve the identities of the +# classes defined here. +if '_is_loaded' in globals(): + raise RuntimeError('Reloading numpy._globals is not allowed') +_is_loaded = True + + +class ModuleDeprecationWarning(DeprecationWarning): + """Module deprecation warning. + + The nose tester turns ordinary Deprecation warnings into test failures. + That makes it hard to deprecate whole modules, because they get + imported by default. So this is a special Deprecation warning that the + nose tester will let pass without making tests fail. + + """ + pass + + +class VisibleDeprecationWarning(UserWarning): + """Visible deprecation warning. + + By default, python will not show deprecation warnings, so this class + can be used when a very visible warning is helpful, for example because + the usage is most likely a user bug. + + """ + pass + + +class _NoValue(object): + """Special keyword value. + + This class may be used as the default value assigned to a deprecated + keyword in order to check if it has been given a user defined value. + """ + pass diff --git a/numpy/_import_tools.py b/numpy/_import_tools.py new file mode 100644 index 0000000..cb8bc47 --- /dev/null +++ b/numpy/_import_tools.py @@ -0,0 +1,351 @@ +from __future__ import division, absolute_import, print_function + +import os +import sys +import warnings + +__all__ = ['PackageLoader'] + +class PackageLoader(object): + def __init__(self, verbose=False, infunc=False): + """ Manages loading packages. + """ + + if infunc: + _level = 2 + else: + _level = 1 + self.parent_frame = frame = sys._getframe(_level) + self.parent_name = eval('__name__', frame.f_globals, frame.f_locals) + parent_path = eval('__path__', frame.f_globals, frame.f_locals) + if isinstance(parent_path, str): + parent_path = [parent_path] + self.parent_path = parent_path + if '__all__' not in frame.f_locals: + exec('__all__ = []', frame.f_globals, frame.f_locals) + self.parent_export_names = eval('__all__', frame.f_globals, frame.f_locals) + + self.info_modules = {} + self.imported_packages = [] + self.verbose = None + + def _get_info_files(self, package_dir, parent_path, parent_package=None): + """ Return list of (package name,info.py file) from parent_path subdirectories. + """ + from glob import glob + files = glob(os.path.join(parent_path, package_dir, 'info.py')) + for info_file in glob(os.path.join(parent_path, package_dir, 'info.pyc')): + if info_file[:-1] not in files: + files.append(info_file) + info_files = [] + for info_file in files: + package_name = os.path.dirname(info_file[len(parent_path)+1:])\ + .replace(os.sep, '.') + if parent_package: + package_name = parent_package + '.' + package_name + info_files.append((package_name, info_file)) + info_files.extend(self._get_info_files('*', + os.path.dirname(info_file), + package_name)) + return info_files + + def _init_info_modules(self, packages=None): + """Initialize info_modules = {: }. + """ + from numpy.compat import npy_load_module + info_files = [] + info_modules = self.info_modules + + if packages is None: + for path in self.parent_path: + info_files.extend(self._get_info_files('*', path)) + else: + for package_name in packages: + package_dir = os.path.join(*package_name.split('.')) + for path in self.parent_path: + names_files = self._get_info_files(package_dir, path) + if names_files: + info_files.extend(names_files) + break + else: + try: + exec('import %s.info as info' % (package_name)) + info_modules[package_name] = info + except ImportError as msg: + self.warn('No scipy-style subpackage %r found in %s. '\ + 'Ignoring: %s'\ + % (package_name, ':'.join(self.parent_path), msg)) + + for package_name, info_file in info_files: + if package_name in info_modules: + continue + fullname = self.parent_name +'.'+ package_name + if info_file[-1]=='c': + filedescriptor = ('.pyc', 'rb', 2) + else: + filedescriptor = ('.py', 'U', 1) + + try: + info_module = npy_load_module(fullname + '.info', + info_file, + filedescriptor) + except Exception as msg: + self.error(msg) + info_module = None + + if info_module is None or getattr(info_module, 'ignore', False): + info_modules.pop(package_name, None) + else: + self._init_info_modules(getattr(info_module, 'depends', [])) + info_modules[package_name] = info_module + + return + + def _get_sorted_names(self): + """ Return package names sorted in the order as they should be + imported due to dependence relations between packages. + """ + + depend_dict = {} + for name, info_module in self.info_modules.items(): + depend_dict[name] = getattr(info_module, 'depends', []) + package_names = [] + + for name in list(depend_dict.keys()): + if not depend_dict[name]: + package_names.append(name) + del depend_dict[name] + + while depend_dict: + for name, lst in list(depend_dict.items()): + new_lst = [n for n in lst if n in depend_dict] + if not new_lst: + package_names.append(name) + del depend_dict[name] + else: + depend_dict[name] = new_lst + + return package_names + + def __call__(self,*packages, **options): + """Load one or more packages into parent package top-level namespace. + + This function is intended to shorten the need to import many + subpackages, say of scipy, constantly with statements such as + + import scipy.linalg, scipy.fftpack, scipy.etc... + + Instead, you can say: + + import scipy + scipy.pkgload('linalg','fftpack',...) + + or + + scipy.pkgload() + + to load all of them in one call. + + If a name which doesn't exist in scipy's namespace is + given, a warning is shown. + + Parameters + ---------- + *packages : arg-tuple + the names (one or more strings) of all the modules one + wishes to load into the top-level namespace. + verbose= : integer + verbosity level [default: -1]. + verbose=-1 will suspend also warnings. + force= : bool + when True, force reloading loaded packages [default: False]. + postpone= : bool + when True, don't load packages [default: False] + + """ + # 2014-10-29, 1.10 + warnings.warn('pkgload and PackageLoader are obsolete ' + 'and will be removed in a future version of numpy', + DeprecationWarning, stacklevel=2) + frame = self.parent_frame + self.info_modules = {} + if options.get('force', False): + self.imported_packages = [] + self.verbose = verbose = options.get('verbose', -1) + postpone = options.get('postpone', None) + self._init_info_modules(packages or None) + + self.log('Imports to %r namespace\n----------------------------'\ + % self.parent_name) + + for package_name in self._get_sorted_names(): + if package_name in self.imported_packages: + continue + info_module = self.info_modules[package_name] + global_symbols = getattr(info_module, 'global_symbols', []) + postpone_import = getattr(info_module, 'postpone_import', False) + if (postpone and not global_symbols) \ + or (postpone_import and postpone is not None): + continue + + old_object = frame.f_locals.get(package_name, None) + + cmdstr = 'import '+package_name + if self._execcmd(cmdstr): + continue + self.imported_packages.append(package_name) + + if verbose!=-1: + new_object = frame.f_locals.get(package_name) + if old_object is not None and old_object is not new_object: + self.warn('Overwriting %s=%s (was %s)' \ + % (package_name, self._obj2repr(new_object), + self._obj2repr(old_object))) + + if '.' not in package_name: + self.parent_export_names.append(package_name) + + for symbol in global_symbols: + if symbol=='*': + symbols = eval('getattr(%s,"__all__",None)'\ + % (package_name), + frame.f_globals, frame.f_locals) + if symbols is None: + symbols = eval('dir(%s)' % (package_name), + frame.f_globals, frame.f_locals) + symbols = [s for s in symbols if not s.startswith('_')] + else: + symbols = [symbol] + + if verbose!=-1: + old_objects = {} + for s in symbols: + if s in frame.f_locals: + old_objects[s] = frame.f_locals[s] + + cmdstr = 'from '+package_name+' import '+symbol + if self._execcmd(cmdstr): + continue + + if verbose!=-1: + for s, old_object in old_objects.items(): + new_object = frame.f_locals[s] + if new_object is not old_object: + self.warn('Overwriting %s=%s (was %s)' \ + % (s, self._obj2repr(new_object), + self._obj2repr(old_object))) + + if symbol=='*': + self.parent_export_names.extend(symbols) + else: + self.parent_export_names.append(symbol) + + return + + def _execcmd(self, cmdstr): + """ Execute command in parent_frame.""" + frame = self.parent_frame + try: + exec (cmdstr, frame.f_globals, frame.f_locals) + except Exception as msg: + self.error('%s -> failed: %s' % (cmdstr, msg)) + return True + else: + self.log('%s -> success' % (cmdstr)) + return + + def _obj2repr(self, obj): + """ Return repr(obj) with""" + module = getattr(obj, '__module__', None) + file = getattr(obj, '__file__', None) + if module is not None: + return repr(obj) + ' from ' + module + if file is not None: + return repr(obj) + ' from ' + file + return repr(obj) + + def log(self, mess): + if self.verbose>1: + print(str(mess), file=sys.stderr) + def warn(self, mess): + if self.verbose>=0: + print(str(mess), file=sys.stderr) + def error(self, mess): + if self.verbose!=-1: + print(str(mess), file=sys.stderr) + + def _get_doc_title(self, info_module): + """ Get the title from a package info.py file. + """ + title = getattr(info_module, '__doc_title__', None) + if title is not None: + return title + title = getattr(info_module, '__doc__', None) + if title is not None: + title = title.lstrip().split('\n', 1)[0] + return title + return '* Not Available *' + + def _format_titles(self,titles,colsep='---'): + display_window_width = 70 # How to determine the correct value in runtime?? + lengths = [len(name)-name.find('.')-1 for (name, title) in titles]+[0] + max_length = max(lengths) + lines = [] + for (name, title) in titles: + name = name[name.find('.')+1:] + w = max_length - len(name) + words = title.split() + line = '%s%s %s' % (name, w*' ', colsep) + tab = len(line) * ' ' + while words: + word = words.pop(0) + if len(line)+len(word)>display_window_width: + lines.append(line) + line = tab + line += ' ' + word + lines.append(line) + return '\n'.join(lines) + + def get_pkgdocs(self): + """ Return documentation summary of subpackages. + """ + import sys + self.info_modules = {} + self._init_info_modules(None) + + titles = [] + symbols = [] + for package_name, info_module in self.info_modules.items(): + global_symbols = getattr(info_module, 'global_symbols', []) + fullname = self.parent_name +'.'+ package_name + note = '' + if fullname not in sys.modules: + note = ' [*]' + titles.append((fullname, self._get_doc_title(info_module) + note)) + if global_symbols: + symbols.append((package_name, ', '.join(global_symbols))) + + retstr = self._format_titles(titles) +\ + '\n [*] - using a package requires explicit import (see pkgload)' + + + if symbols: + retstr += """\n\nGlobal symbols from subpackages"""\ + """\n-------------------------------\n""" +\ + self._format_titles(symbols, '-->') + + return retstr + +class PackageLoaderDebug(PackageLoader): + def _execcmd(self, cmdstr): + """ Execute command in parent_frame.""" + frame = self.parent_frame + print('Executing', repr(cmdstr), '...', end=' ') + sys.stdout.flush() + exec (cmdstr, frame.f_globals, frame.f_locals) + print('ok') + sys.stdout.flush() + return + +if int(os.environ.get('NUMPY_IMPORT_DEBUG', '0')): + PackageLoader = PackageLoaderDebug diff --git a/numpy/add_newdocs.py b/numpy/add_newdocs.py new file mode 100644 index 0000000..d0c7c61 --- /dev/null +++ b/numpy/add_newdocs.py @@ -0,0 +1,7936 @@ +""" +This is only meant to add docs to objects defined in C-extension modules. +The purpose is to allow easier editing of the docstrings without +requiring a re-compile. + +NOTE: Many of the methods of ndarray have corresponding functions. + If you update these docstrings, please keep also the ones in + core/fromnumeric.py, core/defmatrix.py up-to-date. + +""" +from __future__ import division, absolute_import, print_function + +from numpy.lib import add_newdoc + +############################################################################### +# +# flatiter +# +# flatiter needs a toplevel description +# +############################################################################### + +add_newdoc('numpy.core', 'flatiter', + """ + Flat iterator object to iterate over arrays. + + A `flatiter` iterator is returned by ``x.flat`` for any array `x`. + It allows iterating over the array as if it were a 1-D array, + either in a for-loop or by calling its `next` method. + + Iteration is done in row-major, C-style order (the last + index varying the fastest). The iterator can also be indexed using + basic slicing or advanced indexing. + + See Also + -------- + ndarray.flat : Return a flat iterator over an array. + ndarray.flatten : Returns a flattened copy of an array. + + Notes + ----- + A `flatiter` iterator can not be constructed directly from Python code + by calling the `flatiter` constructor. + + Examples + -------- + >>> x = np.arange(6).reshape(2, 3) + >>> fl = x.flat + >>> type(fl) + + >>> for item in fl: + ... print(item) + ... + 0 + 1 + 2 + 3 + 4 + 5 + + >>> fl[2:4] + array([2, 3]) + + """) + +# flatiter attributes + +add_newdoc('numpy.core', 'flatiter', ('base', + """ + A reference to the array that is iterated over. + + Examples + -------- + >>> x = np.arange(5) + >>> fl = x.flat + >>> fl.base is x + True + + """)) + + + +add_newdoc('numpy.core', 'flatiter', ('coords', + """ + An N-dimensional tuple of current coordinates. + + Examples + -------- + >>> x = np.arange(6).reshape(2, 3) + >>> fl = x.flat + >>> fl.coords + (0, 0) + >>> fl.next() + 0 + >>> fl.coords + (0, 1) + + """)) + + + +add_newdoc('numpy.core', 'flatiter', ('index', + """ + Current flat index into the array. + + Examples + -------- + >>> x = np.arange(6).reshape(2, 3) + >>> fl = x.flat + >>> fl.index + 0 + >>> fl.next() + 0 + >>> fl.index + 1 + + """)) + +# flatiter functions + +add_newdoc('numpy.core', 'flatiter', ('__array__', + """__array__(type=None) Get array from iterator + + """)) + + +add_newdoc('numpy.core', 'flatiter', ('copy', + """ + copy() + + Get a copy of the iterator as a 1-D array. + + Examples + -------- + >>> x = np.arange(6).reshape(2, 3) + >>> x + array([[0, 1, 2], + [3, 4, 5]]) + >>> fl = x.flat + >>> fl.copy() + array([0, 1, 2, 3, 4, 5]) + + """)) + + +############################################################################### +# +# nditer +# +############################################################################### + +add_newdoc('numpy.core', 'nditer', + """ + Efficient multi-dimensional iterator object to iterate over arrays. + To get started using this object, see the + :ref:`introductory guide to array iteration `. + + Parameters + ---------- + op : ndarray or sequence of array_like + The array(s) to iterate over. + flags : sequence of str, optional + Flags to control the behavior of the iterator. + + * "buffered" enables buffering when required. + * "c_index" causes a C-order index to be tracked. + * "f_index" causes a Fortran-order index to be tracked. + * "multi_index" causes a multi-index, or a tuple of indices + with one per iteration dimension, to be tracked. + * "common_dtype" causes all the operands to be converted to + a common data type, with copying or buffering as necessary. + * "copy_if_overlap" causes the iterator to determine if read + operands have overlap with write operands, and make temporary + copies as necessary to avoid overlap. False positives (needless + copying) are possible in some cases. + * "delay_bufalloc" delays allocation of the buffers until + a reset() call is made. Allows "allocate" operands to + be initialized before their values are copied into the buffers. + * "external_loop" causes the `values` given to be + one-dimensional arrays with multiple values instead of + zero-dimensional arrays. + * "grow_inner" allows the `value` array sizes to be made + larger than the buffer size when both "buffered" and + "external_loop" is used. + * "ranged" allows the iterator to be restricted to a sub-range + of the iterindex values. + * "refs_ok" enables iteration of reference types, such as + object arrays. + * "reduce_ok" enables iteration of "readwrite" operands + which are broadcasted, also known as reduction operands. + * "zerosize_ok" allows `itersize` to be zero. + op_flags : list of list of str, optional + This is a list of flags for each operand. At minimum, one of + "readonly", "readwrite", or "writeonly" must be specified. + + * "readonly" indicates the operand will only be read from. + * "readwrite" indicates the operand will be read from and written to. + * "writeonly" indicates the operand will only be written to. + * "no_broadcast" prevents the operand from being broadcasted. + * "contig" forces the operand data to be contiguous. + * "aligned" forces the operand data to be aligned. + * "nbo" forces the operand data to be in native byte order. + * "copy" allows a temporary read-only copy if required. + * "updateifcopy" allows a temporary read-write copy if required. + * "allocate" causes the array to be allocated if it is None + in the `op` parameter. + * "no_subtype" prevents an "allocate" operand from using a subtype. + * "arraymask" indicates that this operand is the mask to use + for selecting elements when writing to operands with the + 'writemasked' flag set. The iterator does not enforce this, + but when writing from a buffer back to the array, it only + copies those elements indicated by this mask. + * 'writemasked' indicates that only elements where the chosen + 'arraymask' operand is True will be written to. + * "overlap_assume_elementwise" can be used to mark operands that are + accessed only in the iterator order, to allow less conservative + copying when "copy_if_overlap" is present. + op_dtypes : dtype or tuple of dtype(s), optional + The required data type(s) of the operands. If copying or buffering + is enabled, the data will be converted to/from their original types. + order : {'C', 'F', 'A', 'K'}, optional + Controls the iteration order. 'C' means C order, 'F' means + Fortran order, 'A' means 'F' order if all the arrays are Fortran + contiguous, 'C' order otherwise, and 'K' means as close to the + order the array elements appear in memory as possible. This also + affects the element memory order of "allocate" operands, as they + are allocated to be compatible with iteration order. + Default is 'K'. + casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional + Controls what kind of data casting may occur when making a copy + or buffering. Setting this to 'unsafe' is not recommended, + as it can adversely affect accumulations. + + * 'no' means the data types should not be cast at all. + * 'equiv' means only byte-order changes are allowed. + * 'safe' means only casts which can preserve values are allowed. + * 'same_kind' means only safe casts or casts within a kind, + like float64 to float32, are allowed. + * 'unsafe' means any data conversions may be done. + op_axes : list of list of ints, optional + If provided, is a list of ints or None for each operands. + The list of axes for an operand is a mapping from the dimensions + of the iterator to the dimensions of the operand. A value of + -1 can be placed for entries, causing that dimension to be + treated as "newaxis". + itershape : tuple of ints, optional + The desired shape of the iterator. This allows "allocate" operands + with a dimension mapped by op_axes not corresponding to a dimension + of a different operand to get a value not equal to 1 for that + dimension. + buffersize : int, optional + When buffering is enabled, controls the size of the temporary + buffers. Set to 0 for the default value. + + Attributes + ---------- + dtypes : tuple of dtype(s) + The data types of the values provided in `value`. This may be + different from the operand data types if buffering is enabled. + finished : bool + Whether the iteration over the operands is finished or not. + has_delayed_bufalloc : bool + If True, the iterator was created with the "delay_bufalloc" flag, + and no reset() function was called on it yet. + has_index : bool + If True, the iterator was created with either the "c_index" or + the "f_index" flag, and the property `index` can be used to + retrieve it. + has_multi_index : bool + If True, the iterator was created with the "multi_index" flag, + and the property `multi_index` can be used to retrieve it. + index + When the "c_index" or "f_index" flag was used, this property + provides access to the index. Raises a ValueError if accessed + and `has_index` is False. + iterationneedsapi : bool + Whether iteration requires access to the Python API, for example + if one of the operands is an object array. + iterindex : int + An index which matches the order of iteration. + itersize : int + Size of the iterator. + itviews + Structured view(s) of `operands` in memory, matching the reordered + and optimized iterator access pattern. + multi_index + When the "multi_index" flag was used, this property + provides access to the index. Raises a ValueError if accessed + accessed and `has_multi_index` is False. + ndim : int + The iterator's dimension. + nop : int + The number of iterator operands. + operands : tuple of operand(s) + The array(s) to be iterated over. + shape : tuple of ints + Shape tuple, the shape of the iterator. + value + Value of `operands` at current iteration. Normally, this is a + tuple of array scalars, but if the flag "external_loop" is used, + it is a tuple of one dimensional arrays. + + Notes + ----- + `nditer` supersedes `flatiter`. The iterator implementation behind + `nditer` is also exposed by the NumPy C API. + + The Python exposure supplies two iteration interfaces, one which follows + the Python iterator protocol, and another which mirrors the C-style + do-while pattern. The native Python approach is better in most cases, but + if you need the iterator's coordinates or index, use the C-style pattern. + + Examples + -------- + Here is how we might write an ``iter_add`` function, using the + Python iterator protocol:: + + def iter_add_py(x, y, out=None): + addop = np.add + it = np.nditer([x, y, out], [], + [['readonly'], ['readonly'], ['writeonly','allocate']]) + for (a, b, c) in it: + addop(a, b, out=c) + return it.operands[2] + + Here is the same function, but following the C-style pattern:: + + def iter_add(x, y, out=None): + addop = np.add + + it = np.nditer([x, y, out], [], + [['readonly'], ['readonly'], ['writeonly','allocate']]) + + while not it.finished: + addop(it[0], it[1], out=it[2]) + it.iternext() + + return it.operands[2] + + Here is an example outer product function:: + + def outer_it(x, y, out=None): + mulop = np.multiply + + it = np.nditer([x, y, out], ['external_loop'], + [['readonly'], ['readonly'], ['writeonly', 'allocate']], + op_axes=[range(x.ndim)+[-1]*y.ndim, + [-1]*x.ndim+range(y.ndim), + None]) + + for (a, b, c) in it: + mulop(a, b, out=c) + + return it.operands[2] + + >>> a = np.arange(2)+1 + >>> b = np.arange(3)+1 + >>> outer_it(a,b) + array([[1, 2, 3], + [2, 4, 6]]) + + Here is an example function which operates like a "lambda" ufunc:: + + def luf(lamdaexpr, *args, **kwargs): + "luf(lambdaexpr, op1, ..., opn, out=None, order='K', casting='safe', buffersize=0)" + nargs = len(args) + op = (kwargs.get('out',None),) + args + it = np.nditer(op, ['buffered','external_loop'], + [['writeonly','allocate','no_broadcast']] + + [['readonly','nbo','aligned']]*nargs, + order=kwargs.get('order','K'), + casting=kwargs.get('casting','safe'), + buffersize=kwargs.get('buffersize',0)) + while not it.finished: + it[0] = lamdaexpr(*it[1:]) + it.iternext() + return it.operands[0] + + >>> a = np.arange(5) + >>> b = np.ones(5) + >>> luf(lambda i,j:i*i + j/2, a, b) + array([ 0.5, 1.5, 4.5, 9.5, 16.5]) + + """) + +# nditer methods + +add_newdoc('numpy.core', 'nditer', ('copy', + """ + copy() + + Get a copy of the iterator in its current state. + + Examples + -------- + >>> x = np.arange(10) + >>> y = x + 1 + >>> it = np.nditer([x, y]) + >>> it.next() + (array(0), array(1)) + >>> it2 = it.copy() + >>> it2.next() + (array(1), array(2)) + + """)) + +add_newdoc('numpy.core', 'nditer', ('debug_print', + """ + debug_print() + + Print the current state of the `nditer` instance and debug info to stdout. + + """)) + +add_newdoc('numpy.core', 'nditer', ('enable_external_loop', + """ + enable_external_loop() + + When the "external_loop" was not used during construction, but + is desired, this modifies the iterator to behave as if the flag + was specified. + + """)) + +add_newdoc('numpy.core', 'nditer', ('iternext', + """ + iternext() + + Check whether iterations are left, and perform a single internal iteration + without returning the result. Used in the C-style pattern do-while + pattern. For an example, see `nditer`. + + Returns + ------- + iternext : bool + Whether or not there are iterations left. + + """)) + +add_newdoc('numpy.core', 'nditer', ('remove_axis', + """ + remove_axis(i) + + Removes axis `i` from the iterator. Requires that the flag "multi_index" + be enabled. + + """)) + +add_newdoc('numpy.core', 'nditer', ('remove_multi_index', + """ + remove_multi_index() + + When the "multi_index" flag was specified, this removes it, allowing + the internal iteration structure to be optimized further. + + """)) + +add_newdoc('numpy.core', 'nditer', ('reset', + """ + reset() + + Reset the iterator to its initial state. + + """)) + + + +############################################################################### +# +# broadcast +# +############################################################################### + +add_newdoc('numpy.core', 'broadcast', + """ + Produce an object that mimics broadcasting. + + Parameters + ---------- + in1, in2, ... : array_like + Input parameters. + + Returns + ------- + b : broadcast object + Broadcast the input parameters against one another, and + return an object that encapsulates the result. + Amongst others, it has ``shape`` and ``nd`` properties, and + may be used as an iterator. + + See Also + -------- + broadcast_arrays + broadcast_to + + Examples + -------- + Manually adding two vectors, using broadcasting: + + >>> x = np.array([[1], [2], [3]]) + >>> y = np.array([4, 5, 6]) + >>> b = np.broadcast(x, y) + + >>> out = np.empty(b.shape) + >>> out.flat = [u+v for (u,v) in b] + >>> out + array([[ 5., 6., 7.], + [ 6., 7., 8.], + [ 7., 8., 9.]]) + + Compare against built-in broadcasting: + + >>> x + y + array([[5, 6, 7], + [6, 7, 8], + [7, 8, 9]]) + + """) + +# attributes + +add_newdoc('numpy.core', 'broadcast', ('index', + """ + current index in broadcasted result + + Examples + -------- + >>> x = np.array([[1], [2], [3]]) + >>> y = np.array([4, 5, 6]) + >>> b = np.broadcast(x, y) + >>> b.index + 0 + >>> b.next(), b.next(), b.next() + ((1, 4), (1, 5), (1, 6)) + >>> b.index + 3 + + """)) + +add_newdoc('numpy.core', 'broadcast', ('iters', + """ + tuple of iterators along ``self``'s "components." + + Returns a tuple of `numpy.flatiter` objects, one for each "component" + of ``self``. + + See Also + -------- + numpy.flatiter + + Examples + -------- + >>> x = np.array([1, 2, 3]) + >>> y = np.array([[4], [5], [6]]) + >>> b = np.broadcast(x, y) + >>> row, col = b.iters + >>> row.next(), col.next() + (1, 4) + + """)) + +add_newdoc('numpy.core', 'broadcast', ('ndim', + """ + Number of dimensions of broadcasted result. Alias for `nd`. + + .. versionadded:: 1.12.0 + + Examples + -------- + >>> x = np.array([1, 2, 3]) + >>> y = np.array([[4], [5], [6]]) + >>> b = np.broadcast(x, y) + >>> b.ndim + 2 + + """)) + +add_newdoc('numpy.core', 'broadcast', ('nd', + """ + Number of dimensions of broadcasted result. For code intended for NumPy + 1.12.0 and later the more consistent `ndim` is preferred. + + Examples + -------- + >>> x = np.array([1, 2, 3]) + >>> y = np.array([[4], [5], [6]]) + >>> b = np.broadcast(x, y) + >>> b.nd + 2 + + """)) + +add_newdoc('numpy.core', 'broadcast', ('numiter', + """ + Number of iterators possessed by the broadcasted result. + + Examples + -------- + >>> x = np.array([1, 2, 3]) + >>> y = np.array([[4], [5], [6]]) + >>> b = np.broadcast(x, y) + >>> b.numiter + 2 + + """)) + +add_newdoc('numpy.core', 'broadcast', ('shape', + """ + Shape of broadcasted result. + + Examples + -------- + >>> x = np.array([1, 2, 3]) + >>> y = np.array([[4], [5], [6]]) + >>> b = np.broadcast(x, y) + >>> b.shape + (3, 3) + + """)) + +add_newdoc('numpy.core', 'broadcast', ('size', + """ + Total size of broadcasted result. + + Examples + -------- + >>> x = np.array([1, 2, 3]) + >>> y = np.array([[4], [5], [6]]) + >>> b = np.broadcast(x, y) + >>> b.size + 9 + + """)) + +add_newdoc('numpy.core', 'broadcast', ('reset', + """ + reset() + + Reset the broadcasted result's iterator(s). + + Parameters + ---------- + None + + Returns + ------- + None + + Examples + -------- + >>> x = np.array([1, 2, 3]) + >>> y = np.array([[4], [5], [6]] + >>> b = np.broadcast(x, y) + >>> b.index + 0 + >>> b.next(), b.next(), b.next() + ((1, 4), (2, 4), (3, 4)) + >>> b.index + 3 + >>> b.reset() + >>> b.index + 0 + + """)) + +############################################################################### +# +# numpy functions +# +############################################################################### + +add_newdoc('numpy.core.multiarray', 'array', + """ + array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0) + + Create an array. + + Parameters + ---------- + object : array_like + An array, any object exposing the array interface, an object whose + __array__ method returns an array, or any (nested) sequence. + dtype : data-type, optional + The desired data-type for the array. If not given, then the type will + be determined as the minimum type required to hold the objects in the + sequence. This argument can only be used to 'upcast' the array. For + downcasting, use the .astype(t) method. + copy : bool, optional + If true (default), then the object is copied. Otherwise, a copy will + only be made if __array__ returns a copy, if obj is a nested sequence, + or if a copy is needed to satisfy any of the other requirements + (`dtype`, `order`, etc.). + order : {'K', 'A', 'C', 'F'}, optional + Specify the memory layout of the array. If object is not an array, the + newly created array will be in C order (row major) unless 'F' is + specified, in which case it will be in Fortran order (column major). + If object is an array the following holds. + + ===== ========= =================================================== + order no copy copy=True + ===== ========= =================================================== + 'K' unchanged F & C order preserved, otherwise most similar order + 'A' unchanged F order if input is F and not C, otherwise C order + 'C' C order C order + 'F' F order F order + ===== ========= =================================================== + + When ``copy=False`` and a copy is made for other reasons, the result is + the same as if ``copy=True``, with some exceptions for `A`, see the + Notes section. The default order is 'K'. + 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). + ndmin : int, optional + Specifies the minimum number of dimensions that the resulting + array should have. Ones will be pre-pended to the shape as + needed to meet this requirement. + + Returns + ------- + out : ndarray + An array object satisfying the specified requirements. + + See Also + -------- + empty, empty_like, zeros, zeros_like, ones, ones_like, full, full_like + + Notes + ----- + When order is 'A' and `object` is an array in neither 'C' nor 'F' order, + and a copy is forced by a change in dtype, then the order of the result is + not necessarily 'C' as expected. This is likely a bug. + + Examples + -------- + >>> np.array([1, 2, 3]) + array([1, 2, 3]) + + Upcasting: + + >>> np.array([1, 2, 3.0]) + array([ 1., 2., 3.]) + + More than one dimension: + + >>> np.array([[1, 2], [3, 4]]) + array([[1, 2], + [3, 4]]) + + Minimum dimensions 2: + + >>> np.array([1, 2, 3], ndmin=2) + array([[1, 2, 3]]) + + Type provided: + + >>> np.array([1, 2, 3], dtype=complex) + array([ 1.+0.j, 2.+0.j, 3.+0.j]) + + Data-type consisting of more than one element: + + >>> x = np.array([(1,2),(3,4)],dtype=[('a','>> x['a'] + array([1, 3]) + + Creating an array from sub-classes: + + >>> np.array(np.mat('1 2; 3 4')) + array([[1, 2], + [3, 4]]) + + >>> np.array(np.mat('1 2; 3 4'), subok=True) + matrix([[1, 2], + [3, 4]]) + + """) + +add_newdoc('numpy.core.multiarray', 'empty', + """ + empty(shape, dtype=float, order='C') + + Return a new array of given shape and type, without initializing entries. + + Parameters + ---------- + shape : int or tuple of int + Shape of the empty array + dtype : data-type, optional + Desired output data-type. + order : {'C', 'F'}, optional + Whether to store multi-dimensional data in row-major + (C-style) or column-major (Fortran-style) order in + memory. + + Returns + ------- + out : ndarray + Array of uninitialized (arbitrary) data of the given shape, dtype, and + order. Object arrays will be initialized to None. + + See Also + -------- + empty_like, zeros, ones + + Notes + ----- + `empty`, unlike `zeros`, does not set the array values to zero, + and may therefore be marginally faster. On the other hand, it requires + the user to manually set all the values in the array, and should be + used with caution. + + Examples + -------- + >>> np.empty([2, 2]) + array([[ -9.74499359e+001, 6.69583040e-309], + [ 2.13182611e-314, 3.06959433e-309]]) #random + + >>> np.empty([2, 2], dtype=int) + array([[-1073741821, -1067949133], + [ 496041986, 19249760]]) #random + + """) + +add_newdoc('numpy.core.multiarray', 'empty_like', + """ + empty_like(a, dtype=None, order='K', subok=True) + + Return a new array with the same shape and type as a given array. + + Parameters + ---------- + a : array_like + The shape and data-type of `a` define these same attributes of the + returned array. + dtype : data-type, optional + Overrides the data type of the result. + + .. versionadded:: 1.6.0 + order : {'C', 'F', 'A', or 'K'}, optional + Overrides the memory layout of the result. 'C' means C-order, + 'F' means F-order, 'A' means 'F' if ``a`` is Fortran contiguous, + 'C' otherwise. 'K' means match the layout of ``a`` as closely + as possible. + + .. versionadded:: 1.6.0 + subok : bool, optional. + If True, then the newly created array will use the sub-class + type of 'a', otherwise it will be a base-class array. Defaults + to True. + + Returns + ------- + out : ndarray + Array of uninitialized (arbitrary) data with the same + shape and type as `a`. + + See Also + -------- + ones_like : Return an array of ones with shape and type of input. + zeros_like : Return an array of zeros with shape and type of input. + empty : Return a new uninitialized array. + ones : Return a new array setting values to one. + zeros : Return a new array setting values to zero. + + Notes + ----- + This function does *not* initialize the returned array; to do that use + `zeros_like` or `ones_like` instead. It may be marginally faster than + the functions that do set the array values. + + Examples + -------- + >>> a = ([1,2,3], [4,5,6]) # a is array-like + >>> np.empty_like(a) + array([[-1073741821, -1073741821, 3], #random + [ 0, 0, -1073741821]]) + >>> a = np.array([[1., 2., 3.],[4.,5.,6.]]) + >>> np.empty_like(a) + array([[ -2.00000715e+000, 1.48219694e-323, -2.00000572e+000],#random + [ 4.38791518e-305, -2.00000715e+000, 4.17269252e-309]]) + + """) + + +add_newdoc('numpy.core.multiarray', 'scalar', + """ + scalar(dtype, obj) + + Return a new scalar array of the given type initialized with obj. + + This function is meant mainly for pickle support. `dtype` must be a + valid data-type descriptor. If `dtype` corresponds to an object + descriptor, then `obj` can be any object, otherwise `obj` must be a + string. If `obj` is not given, it will be interpreted as None for object + type and as zeros for all other types. + + """) + +add_newdoc('numpy.core.multiarray', 'zeros', + """ + zeros(shape, dtype=float, order='C') + + Return a new array of given shape and type, filled with zeros. + + Parameters + ---------- + shape : int or sequence of ints + Shape of the new array, e.g., ``(2, 3)`` or ``2``. + dtype : data-type, optional + The desired data-type for the array, e.g., `numpy.int8`. Default is + `numpy.float64`. + order : {'C', 'F'}, optional + Whether to store multidimensional data in C- or Fortran-contiguous + (row- or column-wise) order in memory. + + Returns + ------- + out : ndarray + Array of zeros with the given shape, dtype, and order. + + See Also + -------- + zeros_like : Return an array of zeros with shape and type of input. + ones_like : Return an array of ones with shape and type of input. + empty_like : Return an empty array with shape and type of input. + ones : Return a new array setting values to one. + empty : Return a new uninitialized array. + + Examples + -------- + >>> np.zeros(5) + array([ 0., 0., 0., 0., 0.]) + + >>> np.zeros((5,), dtype=int) + array([0, 0, 0, 0, 0]) + + >>> np.zeros((2, 1)) + array([[ 0.], + [ 0.]]) + + >>> s = (2,2) + >>> np.zeros(s) + array([[ 0., 0.], + [ 0., 0.]]) + + >>> np.zeros((2,), dtype=[('x', 'i4'), ('y', 'i4')]) # custom dtype + array([(0, 0), (0, 0)], + dtype=[('x', '>> np.fromstring('1 2', dtype=int, sep=' ') + array([1, 2]) + >>> np.fromstring('1, 2', dtype=int, sep=',') + array([1, 2]) + + """) + +add_newdoc('numpy.core.multiarray', 'fromiter', + """ + fromiter(iterable, dtype, count=-1) + + Create a new 1-dimensional array from an iterable object. + + Parameters + ---------- + iterable : iterable object + An iterable object providing data for the array. + dtype : data-type + The data-type of the returned array. + count : int, optional + The number of items to read from *iterable*. The default is -1, + which means all data is read. + + Returns + ------- + out : ndarray + The output array. + + Notes + ----- + Specify `count` to improve performance. It allows ``fromiter`` to + pre-allocate the output array, instead of resizing it on demand. + + Examples + -------- + >>> iterable = (x*x for x in range(5)) + >>> np.fromiter(iterable, float) + array([ 0., 1., 4., 9., 16.]) + + """) + +add_newdoc('numpy.core.multiarray', 'fromfile', + """ + fromfile(file, dtype=float, count=-1, sep='') + + Construct an array from data in a text or binary file. + + A highly efficient way of reading binary data with a known data-type, + as well as parsing simply formatted text files. Data written using the + `tofile` method can be read using this function. + + Parameters + ---------- + file : file or str + Open file object or filename. + dtype : data-type + Data type of the returned array. + For binary files, it is used to determine the size and byte-order + of the items in the file. + count : int + Number of items to read. ``-1`` means all items (i.e., the complete + file). + sep : str + Separator between items if file is a text file. + Empty ("") separator means the file should be treated as binary. + Spaces (" ") in the separator match zero or more whitespace characters. + A separator consisting only of spaces must match at least one + whitespace. + + See also + -------- + load, save + ndarray.tofile + loadtxt : More flexible way of loading data from a text file. + + Notes + ----- + Do not rely on the combination of `tofile` and `fromfile` for + data storage, as the binary files generated are are not platform + independent. In particular, no byte-order or data-type information is + saved. Data can be stored in the platform independent ``.npy`` format + using `save` and `load` instead. + + Examples + -------- + Construct an ndarray: + + >>> dt = np.dtype([('time', [('min', int), ('sec', int)]), + ... ('temp', float)]) + >>> x = np.zeros((1,), dtype=dt) + >>> x['time']['min'] = 10; x['temp'] = 98.25 + >>> x + array([((10, 0), 98.25)], + dtype=[('time', [('min', '>> import os + >>> fname = os.tmpnam() + >>> x.tofile(fname) + + Read the raw data from disk: + + >>> np.fromfile(fname, dtype=dt) + array([((10, 0), 98.25)], + dtype=[('time', [('min', '>> np.save(fname, x) + >>> np.load(fname + '.npy') + array([((10, 0), 98.25)], + dtype=[('time', [('min', '>> dt = np.dtype(int) + >>> dt = dt.newbyteorder('>') + >>> np.frombuffer(buf, dtype=dt) + + The data of the resulting array will not be byteswapped, but will be + interpreted correctly. + + Examples + -------- + >>> s = 'hello world' + >>> np.frombuffer(s, dtype='S1', count=5, offset=6) + array(['w', 'o', 'r', 'l', 'd'], + dtype='|S1') + + >>> np.frombuffer(b'\\x01\\x02', dtype=np.uint8) + array([1, 2], dtype=uint8) + >>> np.frombuffer(b'\\x01\\x02\\x03\\x04\\x05', dtype=np.uint8, count=3) + array([1, 2, 3], dtype=uint8) + + """) + +add_newdoc('numpy.core.multiarray', 'concatenate', + """ + concatenate((a1, a2, ...), axis=0, out=None) + + Join a sequence of arrays along an existing axis. + + Parameters + ---------- + a1, a2, ... : sequence of array_like + The arrays must have the same shape, except in the dimension + corresponding to `axis` (the first, by default). + axis : int, optional + The axis along which the arrays will be joined. Default is 0. + out : ndarray, optional + If provided, the destination to place the result. The shape must be + correct, matching that of what concatenate would have returned if no + out argument were specified. + + Returns + ------- + res : ndarray + The concatenated array. + + See Also + -------- + ma.concatenate : Concatenate function that preserves input masks. + array_split : Split an array into multiple sub-arrays of equal or + near-equal size. + split : Split array into a list of multiple sub-arrays of equal size. + hsplit : Split array into multiple sub-arrays horizontally (column wise) + vsplit : Split array into multiple sub-arrays vertically (row wise) + dsplit : Split array into multiple sub-arrays along the 3rd axis (depth). + stack : Stack a sequence of arrays along a new axis. + hstack : Stack arrays in sequence horizontally (column wise) + vstack : Stack arrays in sequence vertically (row wise) + dstack : Stack arrays in sequence depth wise (along third dimension) + + Notes + ----- + When one or more of the arrays to be concatenated is a MaskedArray, + this function will return a MaskedArray object instead of an ndarray, + but the input masks are *not* preserved. In cases where a MaskedArray + is expected as input, use the ma.concatenate function from the masked + array module instead. + + Examples + -------- + >>> a = np.array([[1, 2], [3, 4]]) + >>> b = np.array([[5, 6]]) + >>> np.concatenate((a, b), axis=0) + array([[1, 2], + [3, 4], + [5, 6]]) + >>> np.concatenate((a, b.T), axis=1) + array([[1, 2, 5], + [3, 4, 6]]) + + This function will not preserve masking of MaskedArray inputs. + + >>> a = np.ma.arange(3) + >>> a[1] = np.ma.masked + >>> b = np.arange(2, 5) + >>> a + masked_array(data = [0 -- 2], + mask = [False True False], + fill_value = 999999) + >>> b + array([2, 3, 4]) + >>> np.concatenate([a, b]) + masked_array(data = [0 1 2 2 3 4], + mask = False, + fill_value = 999999) + >>> np.ma.concatenate([a, b]) + masked_array(data = [0 -- 2 2 3 4], + mask = [False True False False False False], + fill_value = 999999) + + """) + +add_newdoc('numpy.core', 'inner', + """ + inner(a, b) + + Inner product of two arrays. + + Ordinary inner product of vectors for 1-D arrays (without complex + conjugation), in higher dimensions a sum product over the last axes. + + Parameters + ---------- + a, b : array_like + If `a` and `b` are nonscalar, their last dimensions must match. + + Returns + ------- + out : ndarray + `out.shape = a.shape[:-1] + b.shape[:-1]` + + Raises + ------ + ValueError + If the last dimension of `a` and `b` has different size. + + See Also + -------- + tensordot : Sum products over arbitrary axes. + dot : Generalised matrix product, using second last dimension of `b`. + einsum : Einstein summation convention. + + Notes + ----- + For vectors (1-D arrays) it computes the ordinary inner-product:: + + np.inner(a, b) = sum(a[:]*b[:]) + + More generally, if `ndim(a) = r > 0` and `ndim(b) = s > 0`:: + + np.inner(a, b) = np.tensordot(a, b, axes=(-1,-1)) + + or explicitly:: + + np.inner(a, b)[i0,...,ir-1,j0,...,js-1] + = sum(a[i0,...,ir-1,:]*b[j0,...,js-1,:]) + + In addition `a` or `b` may be scalars, in which case:: + + np.inner(a,b) = a*b + + Examples + -------- + Ordinary inner product for vectors: + + >>> a = np.array([1,2,3]) + >>> b = np.array([0,1,0]) + >>> np.inner(a, b) + 2 + + A multidimensional example: + + >>> a = np.arange(24).reshape((2,3,4)) + >>> b = np.arange(4) + >>> np.inner(a, b) + array([[ 14, 38, 62], + [ 86, 110, 134]]) + + An example where `b` is a scalar: + + >>> np.inner(np.eye(2), 7) + array([[ 7., 0.], + [ 0., 7.]]) + + """) + +add_newdoc('numpy.core', 'fastCopyAndTranspose', + """_fastCopyAndTranspose(a)""") + +add_newdoc('numpy.core.multiarray', 'correlate', + """cross_correlate(a,v, mode=0)""") + +add_newdoc('numpy.core.multiarray', 'arange', + """ + arange([start,] stop[, step,], dtype=None) + + Return evenly spaced values within a given interval. + + Values are generated within the half-open interval ``[start, stop)`` + (in other words, the interval including `start` but excluding `stop`). + For integer arguments the function is equivalent to the Python built-in + `range `_ function, + but returns an ndarray rather than a list. + + When using a non-integer step, such as 0.1, the results will often not + be consistent. It is better to use ``linspace`` for these cases. + + Parameters + ---------- + start : number, optional + Start of interval. The interval includes this value. The default + start value is 0. + stop : number + End of interval. The interval does not include this value, except + in some cases where `step` is not an integer and floating point + round-off affects the length of `out`. + step : number, optional + Spacing between values. For any output `out`, this is the distance + between two adjacent values, ``out[i+1] - out[i]``. The default + step size is 1. If `step` is specified as a position argument, + `start` must also be given. + dtype : dtype + The type of the output array. If `dtype` is not given, infer the data + type from the other input arguments. + + Returns + ------- + arange : ndarray + Array of evenly spaced values. + + For floating point arguments, the length of the result is + ``ceil((stop - start)/step)``. Because of floating point overflow, + this rule may result in the last element of `out` being greater + than `stop`. + + See Also + -------- + linspace : Evenly spaced numbers with careful handling of endpoints. + ogrid: Arrays of evenly spaced numbers in N-dimensions. + mgrid: Grid-shaped arrays of evenly spaced numbers in N-dimensions. + + Examples + -------- + >>> np.arange(3) + array([0, 1, 2]) + >>> np.arange(3.0) + array([ 0., 1., 2.]) + >>> np.arange(3,7) + array([3, 4, 5, 6]) + >>> np.arange(3,7,2) + array([3, 5]) + + """) + +add_newdoc('numpy.core.multiarray', '_get_ndarray_c_version', + """_get_ndarray_c_version() + + Return the compile time NDARRAY_VERSION number. + + """) + +add_newdoc('numpy.core.multiarray', '_reconstruct', + """_reconstruct(subtype, shape, dtype) + + Construct an empty array. Used by Pickles. + + """) + + +add_newdoc('numpy.core.multiarray', 'set_string_function', + """ + set_string_function(f, repr=1) + + Internal method to set a function to be used when pretty printing arrays. + + """) + +add_newdoc('numpy.core.multiarray', 'set_numeric_ops', + """ + set_numeric_ops(op1=func1, op2=func2, ...) + + Set numerical operators for array objects. + + Parameters + ---------- + op1, op2, ... : callable + Each ``op = func`` pair describes an operator to be replaced. + For example, ``add = lambda x, y: np.add(x, y) % 5`` would replace + addition by modulus 5 addition. + + Returns + ------- + saved_ops : list of callables + A list of all operators, stored before making replacements. + + Notes + ----- + .. WARNING:: + Use with care! Incorrect usage may lead to memory errors. + + A function replacing an operator cannot make use of that operator. + For example, when replacing add, you may not use ``+``. Instead, + directly call ufuncs. + + Examples + -------- + >>> def add_mod5(x, y): + ... return np.add(x, y) % 5 + ... + >>> old_funcs = np.set_numeric_ops(add=add_mod5) + + >>> x = np.arange(12).reshape((3, 4)) + >>> x + x + array([[0, 2, 4, 1], + [3, 0, 2, 4], + [1, 3, 0, 2]]) + + >>> ignore = np.set_numeric_ops(**old_funcs) # restore operators + + """) + +add_newdoc('numpy.core.multiarray', 'where', + """ + where(condition, [x, y]) + + Return elements, either from `x` or `y`, depending on `condition`. + + If only `condition` is given, return ``condition.nonzero()``. + + Parameters + ---------- + condition : array_like, bool + When True, yield `x`, otherwise yield `y`. + x, y : array_like, optional + Values from which to choose. `x`, `y` and `condition` need to be + broadcastable to some shape. + + Returns + ------- + out : ndarray or tuple of ndarrays + If both `x` and `y` are specified, the output array contains + elements of `x` where `condition` is True, and elements from + `y` elsewhere. + + If only `condition` is given, return the tuple + ``condition.nonzero()``, the indices where `condition` is True. + + See Also + -------- + nonzero, choose + + Notes + ----- + If `x` and `y` are given and input arrays are 1-D, `where` is + equivalent to:: + + [xv if c else yv for (c,xv,yv) in zip(condition,x,y)] + + Examples + -------- + >>> np.where([[True, False], [True, True]], + ... [[1, 2], [3, 4]], + ... [[9, 8], [7, 6]]) + array([[1, 8], + [3, 4]]) + + >>> np.where([[0, 1], [1, 0]]) + (array([0, 1]), array([1, 0])) + + >>> x = np.arange(9.).reshape(3, 3) + >>> np.where( x > 5 ) + (array([2, 2, 2]), array([0, 1, 2])) + >>> x[np.where( x > 3.0 )] # Note: result is 1D. + array([ 4., 5., 6., 7., 8.]) + >>> np.where(x < 5, x, -1) # Note: broadcasting. + array([[ 0., 1., 2.], + [ 3., 4., -1.], + [-1., -1., -1.]]) + + Find the indices of elements of `x` that are in `goodvalues`. + + >>> goodvalues = [3, 4, 7] + >>> ix = np.isin(x, goodvalues) + >>> ix + array([[False, False, False], + [ True, True, False], + [False, True, False]]) + >>> np.where(ix) + (array([1, 1, 2]), array([0, 1, 1])) + + """) + + +add_newdoc('numpy.core.multiarray', 'lexsort', + """ + lexsort(keys, axis=-1) + + Perform an indirect sort using a sequence of keys. + + Given multiple sorting keys, which can be interpreted as columns in a + spreadsheet, lexsort returns an array of integer indices that describes + the sort order by multiple columns. The last key in the sequence is used + for the primary sort order, the second-to-last key for the secondary sort + order, and so on. The keys argument must be a sequence of objects that + can be converted to arrays of the same shape. If a 2D array is provided + for the keys argument, it's rows are interpreted as the sorting keys and + sorting is according to the last row, second last row etc. + + Parameters + ---------- + keys : (k, N) array or tuple containing k (N,)-shaped sequences + The `k` different "columns" to be sorted. The last column (or row if + `keys` is a 2D array) is the primary sort key. + axis : int, optional + Axis to be indirectly sorted. By default, sort over the last axis. + + Returns + ------- + indices : (N,) ndarray of ints + Array of indices that sort the keys along the specified axis. + + See Also + -------- + argsort : Indirect sort. + ndarray.sort : In-place sort. + sort : Return a sorted copy of an array. + + Examples + -------- + Sort names: first by surname, then by name. + + >>> surnames = ('Hertz', 'Galilei', 'Hertz') + >>> first_names = ('Heinrich', 'Galileo', 'Gustav') + >>> ind = np.lexsort((first_names, surnames)) + >>> ind + array([1, 2, 0]) + + >>> [surnames[i] + ", " + first_names[i] for i in ind] + ['Galilei, Galileo', 'Hertz, Gustav', 'Hertz, Heinrich'] + + Sort two columns of numbers: + + >>> a = [1,5,1,4,3,4,4] # First column + >>> b = [9,4,0,4,0,2,1] # Second column + >>> ind = np.lexsort((b,a)) # Sort by a, then by b + >>> print(ind) + [2 0 4 6 5 3 1] + + >>> [(a[i],b[i]) for i in ind] + [(1, 0), (1, 9), (3, 0), (4, 1), (4, 2), (4, 4), (5, 4)] + + Note that sorting is first according to the elements of ``a``. + Secondary sorting is according to the elements of ``b``. + + A normal ``argsort`` would have yielded: + + >>> [(a[i],b[i]) for i in np.argsort(a)] + [(1, 9), (1, 0), (3, 0), (4, 4), (4, 2), (4, 1), (5, 4)] + + Structured arrays are sorted lexically by ``argsort``: + + >>> x = np.array([(1,9), (5,4), (1,0), (4,4), (3,0), (4,2), (4,1)], + ... dtype=np.dtype([('x', int), ('y', int)])) + + >>> np.argsort(x) # or np.argsort(x, order=('x', 'y')) + array([2, 0, 4, 6, 5, 3, 1]) + + """) + +add_newdoc('numpy.core.multiarray', 'can_cast', + """ + can_cast(from_, to, casting='safe') + + Returns True if cast between data types can occur according to the + casting rule. If from is a scalar or array scalar, also returns + True if the scalar value can be cast without overflow or truncation + to an integer. + + Parameters + ---------- + from_ : dtype, dtype specifier, scalar, or array + Data type, scalar, or array to cast from. + to : dtype or dtype specifier + Data type to cast to. + casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional + Controls what kind of data casting may occur. + + * 'no' means the data types should not be cast at all. + * 'equiv' means only byte-order changes are allowed. + * 'safe' means only casts which can preserve values are allowed. + * 'same_kind' means only safe casts or casts within a kind, + like float64 to float32, are allowed. + * 'unsafe' means any data conversions may be done. + + Returns + ------- + out : bool + True if cast can occur according to the casting rule. + + Notes + ----- + Starting in NumPy 1.9, can_cast function now returns False in 'safe' + casting mode for integer/float dtype and string dtype if the string dtype + length is not long enough to store the max integer/float value converted + to a string. Previously can_cast in 'safe' mode returned True for + integer/float dtype and a string dtype of any length. + + See also + -------- + dtype, result_type + + Examples + -------- + Basic examples + + >>> np.can_cast(np.int32, np.int64) + True + >>> np.can_cast(np.float64, complex) + True + >>> np.can_cast(complex, float) + False + + >>> np.can_cast('i8', 'f8') + True + >>> np.can_cast('i8', 'f4') + False + >>> np.can_cast('i4', 'S4') + False + + Casting scalars + + >>> np.can_cast(100, 'i1') + True + >>> np.can_cast(150, 'i1') + False + >>> np.can_cast(150, 'u1') + True + + >>> np.can_cast(3.5e100, np.float32) + False + >>> np.can_cast(1000.0, np.float32) + True + + Array scalar checks the value, array does not + + >>> np.can_cast(np.array(1000.0), np.float32) + True + >>> np.can_cast(np.array([1000.0]), np.float32) + False + + Using the casting rules + + >>> np.can_cast('i8', 'i8', 'no') + True + >>> np.can_cast('i8', 'no') + False + + >>> np.can_cast('i8', 'equiv') + True + >>> np.can_cast('i8', 'equiv') + False + + >>> np.can_cast('i8', 'safe') + True + >>> np.can_cast('i4', 'safe') + False + + >>> np.can_cast('i4', 'same_kind') + True + >>> np.can_cast('u4', 'same_kind') + False + + >>> np.can_cast('u4', 'unsafe') + True + + """) + +add_newdoc('numpy.core.multiarray', 'promote_types', + """ + promote_types(type1, type2) + + Returns the data type with the smallest size and smallest scalar + kind to which both ``type1`` and ``type2`` may be safely cast. + The returned data type is always in native byte order. + + This function is symmetric and associative. + + Parameters + ---------- + type1 : dtype or dtype specifier + First data type. + type2 : dtype or dtype specifier + Second data type. + + Returns + ------- + out : dtype + The promoted data type. + + Notes + ----- + .. versionadded:: 1.6.0 + + Starting in NumPy 1.9, promote_types function now returns a valid string + length when given an integer or float dtype as one argument and a string + dtype as another argument. Previously it always returned the input string + dtype, even if it wasn't long enough to store the max integer/float value + converted to a string. + + See Also + -------- + result_type, dtype, can_cast + + Examples + -------- + >>> np.promote_types('f4', 'f8') + dtype('float64') + + >>> np.promote_types('i8', 'f4') + dtype('float64') + + >>> np.promote_types('>i8', '>> np.promote_types('i4', 'S8') + dtype('S11') + + """) + +add_newdoc('numpy.core.multiarray', 'min_scalar_type', + """ + min_scalar_type(a) + + For scalar ``a``, returns the data type with the smallest size + and smallest scalar kind which can hold its value. For non-scalar + array ``a``, returns the vector's dtype unmodified. + + Floating point values are not demoted to integers, + and complex values are not demoted to floats. + + Parameters + ---------- + a : scalar or array_like + The value whose minimal data type is to be found. + + Returns + ------- + out : dtype + The minimal data type. + + Notes + ----- + .. versionadded:: 1.6.0 + + See Also + -------- + result_type, promote_types, dtype, can_cast + + Examples + -------- + >>> np.min_scalar_type(10) + dtype('uint8') + + >>> np.min_scalar_type(-260) + dtype('int16') + + >>> np.min_scalar_type(3.1) + dtype('float16') + + >>> np.min_scalar_type(1e50) + dtype('float64') + + >>> np.min_scalar_type(np.arange(4,dtype='f8')) + dtype('float64') + + """) + +add_newdoc('numpy.core.multiarray', 'result_type', + """ + result_type(*arrays_and_dtypes) + + Returns the type that results from applying the NumPy + type promotion rules to the arguments. + + Type promotion in NumPy works similarly to the rules in languages + like C++, with some slight differences. When both scalars and + arrays are used, the array's type takes precedence and the actual value + of the scalar is taken into account. + + For example, calculating 3*a, where a is an array of 32-bit floats, + intuitively should result in a 32-bit float output. If the 3 is a + 32-bit integer, the NumPy rules indicate it can't convert losslessly + into a 32-bit float, so a 64-bit float should be the result type. + By examining the value of the constant, '3', we see that it fits in + an 8-bit integer, which can be cast losslessly into the 32-bit float. + + Parameters + ---------- + arrays_and_dtypes : list of arrays and dtypes + The operands of some operation whose result type is needed. + + Returns + ------- + out : dtype + The result type. + + See also + -------- + dtype, promote_types, min_scalar_type, can_cast + + Notes + ----- + .. versionadded:: 1.6.0 + + The specific algorithm used is as follows. + + Categories are determined by first checking which of boolean, + integer (int/uint), or floating point (float/complex) the maximum + kind of all the arrays and the scalars are. + + If there are only scalars or the maximum category of the scalars + is higher than the maximum category of the arrays, + the data types are combined with :func:`promote_types` + to produce the return value. + + Otherwise, `min_scalar_type` is called on each array, and + the resulting data types are all combined with :func:`promote_types` + to produce the return value. + + The set of int values is not a subset of the uint values for types + with the same number of bits, something not reflected in + :func:`min_scalar_type`, but handled as a special case in `result_type`. + + Examples + -------- + >>> np.result_type(3, np.arange(7, dtype='i1')) + dtype('int8') + + >>> np.result_type('i4', 'c8') + dtype('complex128') + + >>> np.result_type(3.0, -2) + dtype('float64') + + """) + +add_newdoc('numpy.core.multiarray', 'newbuffer', + """ + newbuffer(size) + + Return a new uninitialized buffer object. + + Parameters + ---------- + size : int + Size in bytes of returned buffer object. + + Returns + ------- + newbuffer : buffer object + Returned, uninitialized buffer object of `size` bytes. + + """) + +add_newdoc('numpy.core.multiarray', 'getbuffer', + """ + getbuffer(obj [,offset[, size]]) + + Create a buffer object from the given object referencing a slice of + length size starting at offset. + + Default is the entire buffer. A read-write buffer is attempted followed + by a read-only buffer. + + Parameters + ---------- + obj : object + + offset : int, optional + + size : int, optional + + Returns + ------- + buffer_obj : buffer + + Examples + -------- + >>> buf = np.getbuffer(np.ones(5), 1, 3) + >>> len(buf) + 3 + >>> buf[0] + '\\x00' + >>> buf + + + """) + +add_newdoc('numpy.core', 'dot', + """ + dot(a, b, out=None) + + Dot product of two arrays. Specifically, + + - If both `a` and `b` are 1-D arrays, it is inner product of vectors + (without complex conjugation). + + - If both `a` and `b` are 2-D arrays, it is matrix multiplication, + but using :func:`matmul` or ``a @ b`` is preferred. + + - If either `a` or `b` is 0-D (scalar), it is equivalent to :func:`multiply` + and using ``numpy.multiply(a, b)`` or ``a * b`` is preferred. + + - If `a` is an N-D array and `b` is a 1-D array, it is a sum product over + the last axis of `a` and `b`. + + - If `a` is an N-D array and `b` is an M-D array (where ``M>=2``), it is a + sum product over the last axis of `a` and the second-to-last axis of `b`:: + + dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m]) + + Parameters + ---------- + a : array_like + First argument. + b : array_like + Second argument. + out : ndarray, optional + Output argument. This must have the exact kind that would be returned + if it was not used. In particular, it must have the right type, must be + C-contiguous, and its dtype must be the dtype that would be returned + for `dot(a,b)`. This is a performance feature. Therefore, if these + conditions are not met, an exception is raised, instead of attempting + to be flexible. + + Returns + ------- + output : ndarray + Returns the dot product of `a` and `b`. If `a` and `b` are both + scalars or both 1-D arrays then a scalar is returned; otherwise + an array is returned. + If `out` is given, then it is returned. + + Raises + ------ + ValueError + If the last dimension of `a` is not the same size as + the second-to-last dimension of `b`. + + See Also + -------- + vdot : Complex-conjugating dot product. + tensordot : Sum products over arbitrary axes. + einsum : Einstein summation convention. + matmul : '@' operator as method with out parameter. + + Examples + -------- + >>> np.dot(3, 4) + 12 + + Neither argument is complex-conjugated: + + >>> np.dot([2j, 3j], [2j, 3j]) + (-13+0j) + + For 2-D arrays it is the matrix product: + + >>> a = [[1, 0], [0, 1]] + >>> b = [[4, 1], [2, 2]] + >>> np.dot(a, b) + array([[4, 1], + [2, 2]]) + + >>> a = np.arange(3*4*5*6).reshape((3,4,5,6)) + >>> b = np.arange(3*4*5*6)[::-1].reshape((5,4,6,3)) + >>> np.dot(a, b)[2,3,2,1,2,2] + 499128 + >>> sum(a[2,3,2,:] * b[1,2,:,2]) + 499128 + + """) + +add_newdoc('numpy.core', 'matmul', + """ + matmul(a, b, out=None) + + Matrix product of two arrays. + + The behavior depends on the arguments in the following way. + + - If both arguments are 2-D they are multiplied like conventional + matrices. + - If either argument is N-D, N > 2, it is treated as a stack of + matrices residing in the last two indexes and broadcast accordingly. + - If the first argument is 1-D, it is promoted to a matrix by + prepending a 1 to its dimensions. After matrix multiplication + the prepended 1 is removed. + - If the second argument is 1-D, it is promoted to a matrix by + appending a 1 to its dimensions. After matrix multiplication + the appended 1 is removed. + + Multiplication by a scalar is not allowed, use ``*`` instead. Note that + multiplying a stack of matrices with a vector will result in a stack of + vectors, but matmul will not recognize it as such. + + ``matmul`` differs from ``dot`` in two important ways. + + - Multiplication by scalars is not allowed. + - Stacks of matrices are broadcast together as if the matrices + were elements. + + .. warning:: + This function is preliminary and included in NumPy 1.10.0 for testing + and documentation. Its semantics will not change, but the number and + order of the optional arguments will. + + .. versionadded:: 1.10.0 + + Parameters + ---------- + a : array_like + First argument. + b : array_like + Second argument. + out : ndarray, optional + Output argument. This must have the exact kind that would be returned + if it was not used. In particular, it must have the right type, must be + C-contiguous, and its dtype must be the dtype that would be returned + for `dot(a,b)`. This is a performance feature. Therefore, if these + conditions are not met, an exception is raised, instead of attempting + to be flexible. + + Returns + ------- + output : ndarray + Returns the dot product of `a` and `b`. If `a` and `b` are both + 1-D arrays then a scalar is returned; otherwise an array is + returned. If `out` is given, then it is returned. + + Raises + ------ + ValueError + If the last dimension of `a` is not the same size as + the second-to-last dimension of `b`. + + If scalar value is passed. + + See Also + -------- + vdot : Complex-conjugating dot product. + tensordot : Sum products over arbitrary axes. + einsum : Einstein summation convention. + dot : alternative matrix product with different broadcasting rules. + + Notes + ----- + The matmul function implements the semantics of the `@` operator introduced + in Python 3.5 following PEP465. + + Examples + -------- + For 2-D arrays it is the matrix product: + + >>> a = [[1, 0], [0, 1]] + >>> b = [[4, 1], [2, 2]] + >>> np.matmul(a, b) + array([[4, 1], + [2, 2]]) + + For 2-D mixed with 1-D, the result is the usual. + + >>> a = [[1, 0], [0, 1]] + >>> b = [1, 2] + >>> np.matmul(a, b) + array([1, 2]) + >>> np.matmul(b, a) + array([1, 2]) + + + Broadcasting is conventional for stacks of arrays + + >>> a = np.arange(2*2*4).reshape((2,2,4)) + >>> b = np.arange(2*2*4).reshape((2,4,2)) + >>> np.matmul(a,b).shape + (2, 2, 2) + >>> np.matmul(a,b)[0,1,1] + 98 + >>> sum(a[0,1,:] * b[0,:,1]) + 98 + + Vector, vector returns the scalar inner product, but neither argument + is complex-conjugated: + + >>> np.matmul([2j, 3j], [2j, 3j]) + (-13+0j) + + Scalar multiplication raises an error. + + >>> np.matmul([1,2], 3) + Traceback (most recent call last): + ... + ValueError: Scalar operands are not allowed, use '*' instead + + """) + + +add_newdoc('numpy.core', 'c_einsum', + """ + c_einsum(subscripts, *operands, out=None, dtype=None, order='K', casting='safe') + + Evaluates the Einstein summation convention on the operands. + + Using the Einstein summation convention, many common multi-dimensional + array operations can be represented in a simple fashion. This function + provides a way to compute such summations. The best way to understand this + function is to try the examples below, which show how many common NumPy + functions can be implemented as calls to `einsum`. + + This is the core C function. + + Parameters + ---------- + subscripts : str + Specifies the subscripts for summation. + operands : list of array_like + These are the arrays for the operation. + out : ndarray, optional + If provided, the calculation is done into this array. + dtype : {data-type, None}, optional + If provided, forces the calculation to use the data type specified. + Note that you may have to also give a more liberal `casting` + parameter to allow the conversions. Default is None. + order : {'C', 'F', 'A', 'K'}, optional + Controls the memory layout of the output. 'C' means it should + be C contiguous. 'F' means it should be Fortran contiguous, + 'A' means it should be 'F' if the inputs are all 'F', 'C' otherwise. + 'K' means it should be as close to the layout as the inputs as + is possible, including arbitrarily permuted axes. + Default is 'K'. + casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional + Controls what kind of data casting may occur. Setting this to + 'unsafe' is not recommended, as it can adversely affect accumulations. + + * 'no' means the data types should not be cast at all. + * 'equiv' means only byte-order changes are allowed. + * 'safe' means only casts which can preserve values are allowed. + * 'same_kind' means only safe casts or casts within a kind, + like float64 to float32, are allowed. + * 'unsafe' means any data conversions may be done. + + Default is 'safe'. + + Returns + ------- + output : ndarray + The calculation based on the Einstein summation convention. + + See Also + -------- + einsum, dot, inner, outer, tensordot + + Notes + ----- + .. versionadded:: 1.6.0 + + The subscripts string is a comma-separated list of subscript labels, + where each label refers to a dimension of the corresponding operand. + Repeated subscripts labels in one operand take the diagonal. For example, + ``np.einsum('ii', a)`` is equivalent to ``np.trace(a)``. + + Whenever a label is repeated, it is summed, so ``np.einsum('i,i', a, b)`` + is equivalent to ``np.inner(a,b)``. If a label appears only once, + it is not summed, so ``np.einsum('i', a)`` produces a view of ``a`` + with no changes. + + The order of labels in the output is by default alphabetical. This + means that ``np.einsum('ij', a)`` doesn't affect a 2D array, while + ``np.einsum('ji', a)`` takes its transpose. + + The output can be controlled by specifying output subscript labels + as well. This specifies the label order, and allows summing to + be disallowed or forced when desired. The call ``np.einsum('i->', a)`` + is like ``np.sum(a, axis=-1)``, and ``np.einsum('ii->i', a)`` + is like ``np.diag(a)``. The difference is that `einsum` does not + allow broadcasting by default. + + To enable and control broadcasting, use an ellipsis. Default + NumPy-style broadcasting is done by adding an ellipsis + to the left of each term, like ``np.einsum('...ii->...i', a)``. + To take the trace along the first and last axes, + you can do ``np.einsum('i...i', a)``, or to do a matrix-matrix + product with the left-most indices instead of rightmost, you can do + ``np.einsum('ij...,jk...->ik...', a, b)``. + + When there is only one operand, no axes are summed, and no output + parameter is provided, a view into the operand is returned instead + of a new array. Thus, taking the diagonal as ``np.einsum('ii->i', a)`` + produces a view. + + An alternative way to provide the subscripts and operands is as + ``einsum(op0, sublist0, op1, sublist1, ..., [sublistout])``. The examples + below have corresponding `einsum` calls with the two parameter methods. + + .. versionadded:: 1.10.0 + + Views returned from einsum are now writeable whenever the input array + is writeable. For example, ``np.einsum('ijk...->kji...', a)`` will now + have the same effect as ``np.swapaxes(a, 0, 2)`` and + ``np.einsum('ii->i', a)`` will return a writeable view of the diagonal + of a 2D array. + + Examples + -------- + >>> a = np.arange(25).reshape(5,5) + >>> b = np.arange(5) + >>> c = np.arange(6).reshape(2,3) + + >>> np.einsum('ii', a) + 60 + >>> np.einsum(a, [0,0]) + 60 + >>> np.trace(a) + 60 + + >>> np.einsum('ii->i', a) + array([ 0, 6, 12, 18, 24]) + >>> np.einsum(a, [0,0], [0]) + array([ 0, 6, 12, 18, 24]) + >>> np.diag(a) + array([ 0, 6, 12, 18, 24]) + + >>> np.einsum('ij,j', a, b) + array([ 30, 80, 130, 180, 230]) + >>> np.einsum(a, [0,1], b, [1]) + array([ 30, 80, 130, 180, 230]) + >>> np.dot(a, b) + array([ 30, 80, 130, 180, 230]) + >>> np.einsum('...j,j', a, b) + array([ 30, 80, 130, 180, 230]) + + >>> np.einsum('ji', c) + array([[0, 3], + [1, 4], + [2, 5]]) + >>> np.einsum(c, [1,0]) + array([[0, 3], + [1, 4], + [2, 5]]) + >>> c.T + array([[0, 3], + [1, 4], + [2, 5]]) + + >>> np.einsum('..., ...', 3, c) + array([[ 0, 3, 6], + [ 9, 12, 15]]) + >>> np.einsum(3, [Ellipsis], c, [Ellipsis]) + array([[ 0, 3, 6], + [ 9, 12, 15]]) + >>> np.multiply(3, c) + array([[ 0, 3, 6], + [ 9, 12, 15]]) + + >>> np.einsum('i,i', b, b) + 30 + >>> np.einsum(b, [0], b, [0]) + 30 + >>> np.inner(b,b) + 30 + + >>> np.einsum('i,j', np.arange(2)+1, b) + array([[0, 1, 2, 3, 4], + [0, 2, 4, 6, 8]]) + >>> np.einsum(np.arange(2)+1, [0], b, [1]) + array([[0, 1, 2, 3, 4], + [0, 2, 4, 6, 8]]) + >>> np.outer(np.arange(2)+1, b) + array([[0, 1, 2, 3, 4], + [0, 2, 4, 6, 8]]) + + >>> np.einsum('i...->...', a) + array([50, 55, 60, 65, 70]) + >>> np.einsum(a, [0,Ellipsis], [Ellipsis]) + array([50, 55, 60, 65, 70]) + >>> np.sum(a, axis=0) + array([50, 55, 60, 65, 70]) + + >>> a = np.arange(60.).reshape(3,4,5) + >>> b = np.arange(24.).reshape(4,3,2) + >>> np.einsum('ijk,jil->kl', a, b) + array([[ 4400., 4730.], + [ 4532., 4874.], + [ 4664., 5018.], + [ 4796., 5162.], + [ 4928., 5306.]]) + >>> np.einsum(a, [0,1,2], b, [1,0,3], [2,3]) + array([[ 4400., 4730.], + [ 4532., 4874.], + [ 4664., 5018.], + [ 4796., 5162.], + [ 4928., 5306.]]) + >>> np.tensordot(a,b, axes=([1,0],[0,1])) + array([[ 4400., 4730.], + [ 4532., 4874.], + [ 4664., 5018.], + [ 4796., 5162.], + [ 4928., 5306.]]) + + >>> a = np.arange(6).reshape((3,2)) + >>> b = np.arange(12).reshape((4,3)) + >>> np.einsum('ki,jk->ij', a, b) + array([[10, 28, 46, 64], + [13, 40, 67, 94]]) + >>> np.einsum('ki,...k->i...', a, b) + array([[10, 28, 46, 64], + [13, 40, 67, 94]]) + >>> np.einsum('k...,jk', a, b) + array([[10, 28, 46, 64], + [13, 40, 67, 94]]) + + >>> # since version 1.10.0 + >>> a = np.zeros((3, 3)) + >>> np.einsum('ii->i', a)[:] = 1 + >>> a + array([[ 1., 0., 0.], + [ 0., 1., 0.], + [ 0., 0., 1.]]) + + """) + +add_newdoc('numpy.core', 'vdot', + """ + vdot(a, b) + + Return the dot product of two vectors. + + The vdot(`a`, `b`) function handles complex numbers differently than + dot(`a`, `b`). If the first argument is complex the complex conjugate + of the first argument is used for the calculation of the dot product. + + Note that `vdot` handles multidimensional arrays differently than `dot`: + it does *not* perform a matrix product, but flattens input arguments + to 1-D vectors first. Consequently, it should only be used for vectors. + + Parameters + ---------- + a : array_like + If `a` is complex the complex conjugate is taken before calculation + of the dot product. + b : array_like + Second argument to the dot product. + + Returns + ------- + output : ndarray + Dot product of `a` and `b`. Can be an int, float, or + complex depending on the types of `a` and `b`. + + See Also + -------- + dot : Return the dot product without using the complex conjugate of the + first argument. + + Examples + -------- + >>> a = np.array([1+2j,3+4j]) + >>> b = np.array([5+6j,7+8j]) + >>> np.vdot(a, b) + (70-8j) + >>> np.vdot(b, a) + (70+8j) + + Note that higher-dimensional arrays are flattened! + + >>> a = np.array([[1, 4], [5, 6]]) + >>> b = np.array([[4, 1], [2, 2]]) + >>> np.vdot(a, b) + 30 + >>> np.vdot(b, a) + 30 + >>> 1*4 + 4*1 + 5*2 + 6*2 + 30 + + """) + + +############################################################################## +# +# Documentation for ndarray attributes and methods +# +############################################################################## + + +############################################################################## +# +# ndarray object +# +############################################################################## + + +add_newdoc('numpy.core.multiarray', 'ndarray', + """ + ndarray(shape, dtype=float, buffer=None, offset=0, + strides=None, order=None) + + An array object represents a multidimensional, homogeneous array + of fixed-size items. An associated data-type object describes the + format of each element in the array (its byte-order, how many bytes it + occupies in memory, whether it is an integer, a floating point number, + or something else, etc.) + + Arrays should be constructed using `array`, `zeros` or `empty` (refer + to the See Also section below). The parameters given here refer to + a low-level method (`ndarray(...)`) for instantiating an array. + + For more information, refer to the `numpy` module and examine the + methods and attributes of an array. + + Parameters + ---------- + (for the __new__ method; see Notes below) + + shape : tuple of ints + Shape of created array. + dtype : data-type, optional + Any object that can be interpreted as a numpy data type. + buffer : object exposing buffer interface, optional + Used to fill the array with data. + offset : int, optional + Offset of array data in buffer. + strides : tuple of ints, optional + Strides of data in memory. + order : {'C', 'F'}, optional + Row-major (C-style) or column-major (Fortran-style) order. + + Attributes + ---------- + T : ndarray + Transpose of the array. + data : buffer + The array's elements, in memory. + dtype : dtype object + Describes the format of the elements in the array. + flags : dict + Dictionary containing information related to memory use, e.g., + 'C_CONTIGUOUS', 'OWNDATA', 'WRITEABLE', etc. + flat : numpy.flatiter object + Flattened version of the array as an iterator. The iterator + allows assignments, e.g., ``x.flat = 3`` (See `ndarray.flat` for + assignment examples; TODO). + imag : ndarray + Imaginary part of the array. + real : ndarray + Real part of the array. + size : int + Number of elements in the array. + itemsize : int + The memory use of each array element in bytes. + nbytes : int + The total number of bytes required to store the array data, + i.e., ``itemsize * size``. + ndim : int + The array's number of dimensions. + shape : tuple of ints + Shape of the array. + strides : tuple of ints + The step-size required to move from one element to the next in + memory. For example, a contiguous ``(3, 4)`` array of type + ``int16`` in C-order has strides ``(8, 2)``. This implies that + to move from element to element in memory requires jumps of 2 bytes. + To move from row-to-row, one needs to jump 8 bytes at a time + (``2 * 4``). + ctypes : ctypes object + Class containing properties of the array needed for interaction + with ctypes. + base : ndarray + If the array is a view into another array, that array is its `base` + (unless that array is also a view). The `base` array is where the + array data is actually stored. + + See Also + -------- + array : Construct an array. + zeros : Create an array, each element of which is zero. + empty : Create an array, but leave its allocated memory unchanged (i.e., + it contains "garbage"). + dtype : Create a data-type. + + Notes + ----- + There are two modes of creating an array using ``__new__``: + + 1. If `buffer` is None, then only `shape`, `dtype`, and `order` + are used. + 2. If `buffer` is an object exposing the buffer interface, then + all keywords are interpreted. + + No ``__init__`` method is needed because the array is fully initialized + after the ``__new__`` method. + + Examples + -------- + These examples illustrate the low-level `ndarray` constructor. Refer + to the `See Also` section above for easier ways of constructing an + ndarray. + + First mode, `buffer` is None: + + >>> np.ndarray(shape=(2,2), dtype=float, order='F') + array([[ -1.13698227e+002, 4.25087011e-303], + [ 2.88528414e-306, 3.27025015e-309]]) #random + + Second mode: + + >>> np.ndarray((2,), buffer=np.array([1,2,3]), + ... offset=np.int_().itemsize, + ... dtype=int) # offset = 1*itemsize, i.e. skip first element + array([2, 3]) + + """) + + +############################################################################## +# +# ndarray attributes +# +############################################################################## + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_interface__', + """Array protocol: Python side.""")) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_finalize__', + """None.""")) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_priority__', + """Array priority.""")) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_struct__', + """Array protocol: C-struct side.""")) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('_as_parameter_', + """Allow the array to be interpreted as a ctypes object by returning the + data-memory location as an integer + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('base', + """ + Base object if memory is from some other object. + + Examples + -------- + The base of an array that owns its memory is None: + + >>> x = np.array([1,2,3,4]) + >>> x.base is None + True + + Slicing creates a view, whose memory is shared with x: + + >>> y = x[2:] + >>> y.base is x + True + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('ctypes', + """ + An object to simplify the interaction of the array with the ctypes + module. + + This attribute creates an object that makes it easier to use arrays + when calling shared libraries with the ctypes module. The returned + object has, among others, data, shape, and strides attributes (see + Notes below) which themselves return ctypes objects that can be used + as arguments to a shared library. + + Parameters + ---------- + None + + Returns + ------- + c : Python object + Possessing attributes data, shape, strides, etc. + + See Also + -------- + numpy.ctypeslib + + Notes + ----- + Below are the public attributes of this object which were documented + in "Guide to NumPy" (we have omitted undocumented public attributes, + as well as documented private attributes): + + * data: A pointer to the memory area of the array as a Python integer. + This memory area may contain data that is not aligned, or not in correct + byte-order. The memory area may not even be writeable. The array + flags and data-type of this array should be respected when passing this + attribute to arbitrary C-code to avoid trouble that can include Python + crashing. User Beware! The value of this attribute is exactly the same + as self._array_interface_['data'][0]. + + * shape (c_intp*self.ndim): A ctypes array of length self.ndim where + the basetype is the C-integer corresponding to dtype('p') on this + platform. This base-type could be c_int, c_long, or c_longlong + depending on the platform. The c_intp type is defined accordingly in + numpy.ctypeslib. The ctypes array contains the shape of the underlying + array. + + * strides (c_intp*self.ndim): A ctypes array of length self.ndim where + the basetype is the same as for the shape attribute. This ctypes array + contains the strides information from the underlying array. This strides + information is important for showing how many bytes must be jumped to + get to the next element in the array. + + * data_as(obj): Return the data pointer cast to a particular c-types object. + For example, calling self._as_parameter_ is equivalent to + self.data_as(ctypes.c_void_p). Perhaps you want to use the data as a + pointer to a ctypes array of floating-point data: + self.data_as(ctypes.POINTER(ctypes.c_double)). + + * shape_as(obj): Return the shape tuple as an array of some other c-types + type. For example: self.shape_as(ctypes.c_short). + + * strides_as(obj): Return the strides tuple as an array of some other + c-types type. For example: self.strides_as(ctypes.c_longlong). + + Be careful using the ctypes attribute - especially on temporary + arrays or arrays constructed on the fly. For example, calling + ``(a+b).ctypes.data_as(ctypes.c_void_p)`` returns a pointer to memory + that is invalid because the array created as (a+b) is deallocated + before the next Python statement. You can avoid this problem using + either ``c=a+b`` or ``ct=(a+b).ctypes``. In the latter case, ct will + hold a reference to the array until ct is deleted or re-assigned. + + If the ctypes module is not available, then the ctypes attribute + of array objects still returns something useful, but ctypes objects + are not returned and errors may be raised instead. In particular, + the object will still have the as parameter attribute which will + return an integer equal to the data attribute. + + Examples + -------- + >>> import ctypes + >>> x + array([[0, 1], + [2, 3]]) + >>> x.ctypes.data + 30439712 + >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)) + + >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_long)).contents + c_long(0) + >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_longlong)).contents + c_longlong(4294967296L) + >>> x.ctypes.shape + + >>> x.ctypes.shape_as(ctypes.c_long) + + >>> x.ctypes.strides + + >>> x.ctypes.strides_as(ctypes.c_longlong) + + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('data', + """Python buffer object pointing to the start of the array's data.""")) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('dtype', + """ + Data-type of the array's elements. + + Parameters + ---------- + None + + Returns + ------- + d : numpy dtype object + + See Also + -------- + numpy.dtype + + Examples + -------- + >>> x + array([[0, 1], + [2, 3]]) + >>> x.dtype + dtype('int32') + >>> type(x.dtype) + + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('imag', + """ + The imaginary part of the array. + + Examples + -------- + >>> x = np.sqrt([1+0j, 0+1j]) + >>> x.imag + array([ 0. , 0.70710678]) + >>> x.imag.dtype + dtype('float64') + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('itemsize', + """ + Length of one array element in bytes. + + Examples + -------- + >>> x = np.array([1,2,3], dtype=np.float64) + >>> x.itemsize + 8 + >>> x = np.array([1,2,3], dtype=np.complex128) + >>> x.itemsize + 16 + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('flags', + """ + Information about the memory layout of the array. + + Attributes + ---------- + C_CONTIGUOUS (C) + The data is in a single, C-style contiguous segment. + F_CONTIGUOUS (F) + The data is in a single, Fortran-style contiguous segment. + OWNDATA (O) + The array owns the memory it uses or borrows it from another object. + WRITEABLE (W) + The data area can be written to. Setting this to False locks + the data, making it read-only. A view (slice, etc.) inherits WRITEABLE + from its base array at creation time, but a view of a writeable + array may be subsequently locked while the base array remains writeable. + (The opposite is not true, in that a view of a locked array may not + be made writeable. However, currently, locking a base object does not + lock any views that already reference it, so under that circumstance it + is possible to alter the contents of a locked array via a previously + created writeable view onto it.) Attempting to change a non-writeable + array raises a RuntimeError exception. + ALIGNED (A) + The data and all elements are aligned appropriately for the hardware. + WRITEBACKIFCOPY (X) + This array is a copy of some other array. The C-API function + PyArray_ResolveWritebackIfCopy must be called before deallocating + to the base array will be updated with the contents of this array. + UPDATEIFCOPY (U) + (Deprecated, use WRITEBACKIFCOPY) This array is a copy of some other array. + When this array is + deallocated, the base array will be updated with the contents of + this array. + FNC + F_CONTIGUOUS and not C_CONTIGUOUS. + FORC + F_CONTIGUOUS or C_CONTIGUOUS (one-segment test). + BEHAVED (B) + ALIGNED and WRITEABLE. + CARRAY (CA) + BEHAVED and C_CONTIGUOUS. + FARRAY (FA) + BEHAVED and F_CONTIGUOUS and not C_CONTIGUOUS. + + Notes + ----- + The `flags` object can be accessed dictionary-like (as in ``a.flags['WRITEABLE']``), + or by using lowercased attribute names (as in ``a.flags.writeable``). Short flag + names are only supported in dictionary access. + + Only the WRITEBACKIFCOPY, UPDATEIFCOPY, WRITEABLE, and ALIGNED flags can be + changed by the user, via direct assignment to the attribute or dictionary + entry, or by calling `ndarray.setflags`. + + The array flags cannot be set arbitrarily: + + - UPDATEIFCOPY can only be set ``False``. + - WRITEBACKIFCOPY can only be set ``False``. + - ALIGNED can only be set ``True`` if the data is truly aligned. + - WRITEABLE can only be set ``True`` if the array owns its own memory + or the ultimate owner of the memory exposes a writeable buffer + interface or is a string. + + Arrays can be both C-style and Fortran-style contiguous simultaneously. + This is clear for 1-dimensional arrays, but can also be true for higher + dimensional arrays. + + Even for contiguous arrays a stride for a given dimension + ``arr.strides[dim]`` may be *arbitrary* if ``arr.shape[dim] == 1`` + or the array has no elements. + It does *not* generally hold that ``self.strides[-1] == self.itemsize`` + for C-style contiguous arrays or ``self.strides[0] == self.itemsize`` for + Fortran-style contiguous arrays is true. + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('flat', + """ + A 1-D iterator over the array. + + This is a `numpy.flatiter` instance, which acts similarly to, but is not + a subclass of, Python's built-in iterator object. + + See Also + -------- + flatten : Return a copy of the array collapsed into one dimension. + + flatiter + + Examples + -------- + >>> x = np.arange(1, 7).reshape(2, 3) + >>> x + array([[1, 2, 3], + [4, 5, 6]]) + >>> x.flat[3] + 4 + >>> x.T + array([[1, 4], + [2, 5], + [3, 6]]) + >>> x.T.flat[3] + 5 + >>> type(x.flat) + + + An assignment example: + + >>> x.flat = 3; x + array([[3, 3, 3], + [3, 3, 3]]) + >>> x.flat[[1,4]] = 1; x + array([[3, 1, 3], + [3, 1, 3]]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('nbytes', + """ + Total bytes consumed by the elements of the array. + + Notes + ----- + Does not include memory consumed by non-element attributes of the + array object. + + Examples + -------- + >>> x = np.zeros((3,5,2), dtype=np.complex128) + >>> x.nbytes + 480 + >>> np.prod(x.shape) * x.itemsize + 480 + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('ndim', + """ + Number of array dimensions. + + Examples + -------- + >>> x = np.array([1, 2, 3]) + >>> x.ndim + 1 + >>> y = np.zeros((2, 3, 4)) + >>> y.ndim + 3 + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('real', + """ + The real part of the array. + + Examples + -------- + >>> x = np.sqrt([1+0j, 0+1j]) + >>> x.real + array([ 1. , 0.70710678]) + >>> x.real.dtype + dtype('float64') + + See Also + -------- + numpy.real : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('shape', + """ + Tuple of array dimensions. + + The shape property is usually used to get the current shape of an array, + but may also be used to reshape the array in-place by assigning a tuple of + array dimensions to it. As with `numpy.reshape`, one of the new shape + dimensions can be -1, in which case its value is inferred from the size of + the array and the remaining dimensions. Reshaping an array in-place will + fail if a copy is required. + + Examples + -------- + >>> x = np.array([1, 2, 3, 4]) + >>> x.shape + (4,) + >>> y = np.zeros((2, 3, 4)) + >>> y.shape + (2, 3, 4) + >>> y.shape = (3, 8) + >>> y + array([[ 0., 0., 0., 0., 0., 0., 0., 0.], + [ 0., 0., 0., 0., 0., 0., 0., 0.], + [ 0., 0., 0., 0., 0., 0., 0., 0.]]) + >>> y.shape = (3, 6) + Traceback (most recent call last): + File "", line 1, in + ValueError: total size of new array must be unchanged + >>> np.zeros((4,2))[::2].shape = (-1,) + Traceback (most recent call last): + File "", line 1, in + AttributeError: incompatible shape for a non-contiguous array + + See Also + -------- + numpy.reshape : similar function + ndarray.reshape : similar method + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('size', + """ + Number of elements in the array. + + Equivalent to ``np.prod(a.shape)``, i.e., the product of the array's + dimensions. + + Examples + -------- + >>> x = np.zeros((3, 5, 2), dtype=np.complex128) + >>> x.size + 30 + >>> np.prod(x.shape) + 30 + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('strides', + """ + Tuple of bytes to step in each dimension when traversing an array. + + The byte offset of element ``(i[0], i[1], ..., i[n])`` in an array `a` + is:: + + offset = sum(np.array(i) * a.strides) + + A more detailed explanation of strides can be found in the + "ndarray.rst" file in the NumPy reference guide. + + Notes + ----- + Imagine an array of 32-bit integers (each 4 bytes):: + + x = np.array([[0, 1, 2, 3, 4], + [5, 6, 7, 8, 9]], dtype=np.int32) + + This array is stored in memory as 40 bytes, one after the other + (known as a contiguous block of memory). The strides of an array tell + us how many bytes we have to skip in memory to move to the next position + along a certain axis. For example, we have to skip 4 bytes (1 value) to + move to the next column, but 20 bytes (5 values) to get to the same + position in the next row. As such, the strides for the array `x` will be + ``(20, 4)``. + + See Also + -------- + numpy.lib.stride_tricks.as_strided + + Examples + -------- + >>> y = np.reshape(np.arange(2*3*4), (2,3,4)) + >>> y + array([[[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]], + [[12, 13, 14, 15], + [16, 17, 18, 19], + [20, 21, 22, 23]]]) + >>> y.strides + (48, 16, 4) + >>> y[1,1,1] + 17 + >>> offset=sum(y.strides * np.array((1,1,1))) + >>> offset/y.itemsize + 17 + + >>> x = np.reshape(np.arange(5*6*7*8), (5,6,7,8)).transpose(2,3,1,0) + >>> x.strides + (32, 4, 224, 1344) + >>> i = np.array([3,5,2,2]) + >>> offset = sum(i * x.strides) + >>> x[3,5,2,2] + 813 + >>> offset / x.itemsize + 813 + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('T', + """ + Same as self.transpose(), except that self is returned if + self.ndim < 2. + + Examples + -------- + >>> x = np.array([[1.,2.],[3.,4.]]) + >>> x + array([[ 1., 2.], + [ 3., 4.]]) + >>> x.T + array([[ 1., 3.], + [ 2., 4.]]) + >>> x = np.array([1.,2.,3.,4.]) + >>> x + array([ 1., 2., 3., 4.]) + >>> x.T + array([ 1., 2., 3., 4.]) + + """)) + + +############################################################################## +# +# ndarray methods +# +############################################################################## + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__array__', + """ a.__array__(|dtype) -> reference if type unchanged, copy otherwise. + + Returns either a new reference to self if dtype is not given or a new array + of provided data type if dtype is different from the current dtype of the + array. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_prepare__', + """a.__array_prepare__(obj) -> Object of same type as ndarray object obj. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_wrap__', + """a.__array_wrap__(obj) -> Object of same type as ndarray object a. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__copy__', + """a.__copy__() + + Used if :func:`copy.copy` is called on an array. Returns a copy of the array. + + Equivalent to ``a.copy(order='K')``. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__deepcopy__', + """a.__deepcopy__(memo, /) -> Deep copy of array. + + Used if :func:`copy.deepcopy` is called on an array. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__reduce__', + """a.__reduce__() + + For pickling. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('__setstate__', + """a.__setstate__(state, /) + + For unpickling. + + The `state` argument must be a sequence that contains the following + elements: + + Parameters + ---------- + version : int + optional pickle version. If omitted defaults to 0. + shape : tuple + dtype : data-type + isFortran : bool + rawdata : string or list + a binary string with the data (or a list if 'a' is an object array) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('all', + """ + a.all(axis=None, out=None, keepdims=False) + + Returns True if all elements evaluate to True. + + Refer to `numpy.all` for full documentation. + + See Also + -------- + numpy.all : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('any', + """ + a.any(axis=None, out=None, keepdims=False) + + Returns True if any of the elements of `a` evaluate to True. + + Refer to `numpy.any` for full documentation. + + See Also + -------- + numpy.any : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('argmax', + """ + a.argmax(axis=None, out=None) + + Return indices of the maximum values along the given axis. + + Refer to `numpy.argmax` for full documentation. + + See Also + -------- + numpy.argmax : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('argmin', + """ + a.argmin(axis=None, out=None) + + Return indices of the minimum values along the given axis of `a`. + + Refer to `numpy.argmin` for detailed documentation. + + See Also + -------- + numpy.argmin : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('argsort', + """ + a.argsort(axis=-1, kind='quicksort', order=None) + + Returns the indices that would sort this array. + + Refer to `numpy.argsort` for full documentation. + + See Also + -------- + numpy.argsort : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('argpartition', + """ + a.argpartition(kth, axis=-1, kind='introselect', order=None) + + Returns the indices that would partition this array. + + Refer to `numpy.argpartition` for full documentation. + + .. versionadded:: 1.8.0 + + See Also + -------- + numpy.argpartition : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('astype', + """ + a.astype(dtype, order='K', casting='unsafe', subok=True, copy=True) + + Copy of the array, cast to a specified type. + + Parameters + ---------- + dtype : str or dtype + Typecode or data-type to which the array is cast. + order : {'C', 'F', 'A', 'K'}, optional + Controls the memory layout order of the result. + 'C' means C order, 'F' means Fortran order, 'A' + means 'F' order if all the arrays are Fortran contiguous, + 'C' order otherwise, and 'K' means as close to the + order the array elements appear in memory as possible. + Default is 'K'. + casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional + Controls what kind of data casting may occur. Defaults to 'unsafe' + for backwards compatibility. + + * 'no' means the data types should not be cast at all. + * 'equiv' means only byte-order changes are allowed. + * 'safe' means only casts which can preserve values are allowed. + * 'same_kind' means only safe casts or casts within a kind, + like float64 to float32, are allowed. + * 'unsafe' means any data conversions may be done. + subok : bool, optional + If True, then sub-classes will be passed-through (default), otherwise + the returned array will be forced to be a base-class array. + copy : bool, optional + By default, astype always returns a newly allocated array. If this + is set to false, and the `dtype`, `order`, and `subok` + requirements are satisfied, the input array is returned instead + of a copy. + + Returns + ------- + arr_t : ndarray + Unless `copy` is False and the other conditions for returning the input + array are satisfied (see description for `copy` input parameter), `arr_t` + is a new array of the same shape as the input array, with dtype, order + given by `dtype`, `order`. + + Notes + ----- + Starting in NumPy 1.9, astype method now returns an error if the string + dtype to cast to is not long enough in 'safe' casting mode to hold the max + value of integer/float array that is being casted. Previously the casting + was allowed even if the result was truncated. + + Raises + ------ + ComplexWarning + When casting from complex to float or int. To avoid this, + one should use ``a.real.astype(t)``. + + Examples + -------- + >>> x = np.array([1, 2, 2.5]) + >>> x + array([ 1. , 2. , 2.5]) + + >>> x.astype(int) + array([1, 2, 2]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('byteswap', + """ + a.byteswap(inplace=False) + + Swap the bytes of the array elements + + Toggle between low-endian and big-endian data representation by + returning a byteswapped array, optionally swapped in-place. + + Parameters + ---------- + inplace : bool, optional + If ``True``, swap bytes in-place, default is ``False``. + + Returns + ------- + out : ndarray + The byteswapped array. If `inplace` is ``True``, this is + a view to self. + + Examples + -------- + >>> A = np.array([1, 256, 8755], dtype=np.int16) + >>> map(hex, A) + ['0x1', '0x100', '0x2233'] + >>> A.byteswap(inplace=True) + array([ 256, 1, 13090], dtype=int16) + >>> map(hex, A) + ['0x100', '0x1', '0x3322'] + + Arrays of strings are not swapped + + >>> A = np.array(['ceg', 'fac']) + >>> A.byteswap() + array(['ceg', 'fac'], + dtype='|S3') + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('choose', + """ + a.choose(choices, out=None, mode='raise') + + Use an index array to construct a new array from a set of choices. + + Refer to `numpy.choose` for full documentation. + + See Also + -------- + numpy.choose : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('clip', + """ + a.clip(min=None, max=None, out=None) + + Return an array whose values are limited to ``[min, max]``. + One of max or min must be given. + + Refer to `numpy.clip` for full documentation. + + See Also + -------- + numpy.clip : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('compress', + """ + a.compress(condition, axis=None, out=None) + + Return selected slices of this array along given axis. + + Refer to `numpy.compress` for full documentation. + + See Also + -------- + numpy.compress : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('conj', + """ + a.conj() + + Complex-conjugate all elements. + + Refer to `numpy.conjugate` for full documentation. + + See Also + -------- + numpy.conjugate : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('conjugate', + """ + a.conjugate() + + Return the complex conjugate, element-wise. + + Refer to `numpy.conjugate` for full documentation. + + See Also + -------- + numpy.conjugate : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('copy', + """ + a.copy(order='C') + + Return a copy of the array. + + Parameters + ---------- + order : {'C', 'F', 'A', 'K'}, optional + Controls the memory layout of the copy. 'C' means C-order, + 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, + 'C' otherwise. 'K' means match the layout of `a` as closely + as possible. (Note that this function and :func:`numpy.copy` are very + similar, but have different default values for their order= + arguments.) + + See also + -------- + numpy.copy + numpy.copyto + + Examples + -------- + >>> x = np.array([[1,2,3],[4,5,6]], order='F') + + >>> y = x.copy() + + >>> x.fill(0) + + >>> x + array([[0, 0, 0], + [0, 0, 0]]) + + >>> y + array([[1, 2, 3], + [4, 5, 6]]) + + >>> y.flags['C_CONTIGUOUS'] + True + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('cumprod', + """ + a.cumprod(axis=None, dtype=None, out=None) + + Return the cumulative product of the elements along the given axis. + + Refer to `numpy.cumprod` for full documentation. + + See Also + -------- + numpy.cumprod : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('cumsum', + """ + a.cumsum(axis=None, dtype=None, out=None) + + Return the cumulative sum of the elements along the given axis. + + Refer to `numpy.cumsum` for full documentation. + + See Also + -------- + numpy.cumsum : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('diagonal', + """ + a.diagonal(offset=0, axis1=0, axis2=1) + + Return specified diagonals. In NumPy 1.9 the returned array is a + read-only view instead of a copy as in previous NumPy versions. In + a future version the read-only restriction will be removed. + + Refer to :func:`numpy.diagonal` for full documentation. + + See Also + -------- + numpy.diagonal : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('dot', + """ + a.dot(b, out=None) + + Dot product of two arrays. + + Refer to `numpy.dot` for full documentation. + + See Also + -------- + numpy.dot : equivalent function + + Examples + -------- + >>> a = np.eye(2) + >>> b = np.ones((2, 2)) * 2 + >>> a.dot(b) + array([[ 2., 2.], + [ 2., 2.]]) + + This array method can be conveniently chained: + + >>> a.dot(b).dot(b) + array([[ 8., 8.], + [ 8., 8.]]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('dump', + """a.dump(file) + + Dump a pickle of the array to the specified file. + The array can be read back with pickle.load or numpy.load. + + Parameters + ---------- + file : str + A string naming the dump file. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('dumps', + """ + a.dumps() + + Returns the pickle of the array as a string. + pickle.loads or numpy.loads will convert the string back to an array. + + Parameters + ---------- + None + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('fill', + """ + a.fill(value) + + Fill the array with a scalar value. + + Parameters + ---------- + value : scalar + All elements of `a` will be assigned this value. + + Examples + -------- + >>> a = np.array([1, 2]) + >>> a.fill(0) + >>> a + array([0, 0]) + >>> a = np.empty(2) + >>> a.fill(1) + >>> a + array([ 1., 1.]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('flatten', + """ + a.flatten(order='C') + + Return a copy of the array collapsed into one dimension. + + Parameters + ---------- + order : {'C', 'F', 'A', 'K'}, optional + 'C' means to flatten in row-major (C-style) order. + 'F' means to flatten in column-major (Fortran- + style) order. 'A' means to flatten in column-major + order if `a` is Fortran *contiguous* in memory, + row-major order otherwise. 'K' means to flatten + `a` in the order the elements occur in memory. + The default is 'C'. + + Returns + ------- + y : ndarray + A copy of the input array, flattened to one dimension. + + See Also + -------- + ravel : Return a flattened array. + flat : A 1-D flat iterator over the array. + + Examples + -------- + >>> a = np.array([[1,2], [3,4]]) + >>> a.flatten() + array([1, 2, 3, 4]) + >>> a.flatten('F') + array([1, 3, 2, 4]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('getfield', + """ + a.getfield(dtype, offset=0) + + Returns a field of the given array as a certain type. + + A field is a view of the array data with a given data-type. The values in + the view are determined by the given type and the offset into the current + array in bytes. The offset needs to be such that the view dtype fits in the + array dtype; for example an array of dtype complex128 has 16-byte elements. + If taking a view with a 32-bit integer (4 bytes), the offset needs to be + between 0 and 12 bytes. + + Parameters + ---------- + dtype : str or dtype + The data type of the view. The dtype size of the view can not be larger + than that of the array itself. + offset : int + Number of bytes to skip before beginning the element view. + + Examples + -------- + >>> x = np.diag([1.+1.j]*2) + >>> x[1, 1] = 2 + 4.j + >>> x + array([[ 1.+1.j, 0.+0.j], + [ 0.+0.j, 2.+4.j]]) + >>> x.getfield(np.float64) + array([[ 1., 0.], + [ 0., 2.]]) + + By choosing an offset of 8 bytes we can select the complex part of the + array for our view: + + >>> x.getfield(np.float64, offset=8) + array([[ 1., 0.], + [ 0., 4.]]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('item', + """ + a.item(*args) + + Copy an element of an array to a standard Python scalar and return it. + + Parameters + ---------- + \\*args : Arguments (variable number and type) + + * none: in this case, the method only works for arrays + with one element (`a.size == 1`), which element is + copied into a standard Python scalar object and returned. + + * int_type: this argument is interpreted as a flat index into + the array, specifying which element to copy and return. + + * tuple of int_types: functions as does a single int_type argument, + except that the argument is interpreted as an nd-index into the + array. + + Returns + ------- + z : Standard Python scalar object + A copy of the specified element of the array as a suitable + Python scalar + + Notes + ----- + When the data type of `a` is longdouble or clongdouble, item() returns + a scalar array object because there is no available Python scalar that + would not lose information. Void arrays return a buffer object for item(), + unless fields are defined, in which case a tuple is returned. + + `item` is very similar to a[args], except, instead of an array scalar, + a standard Python scalar is returned. This can be useful for speeding up + access to elements of the array and doing arithmetic on elements of the + array using Python's optimized math. + + Examples + -------- + >>> x = np.random.randint(9, size=(3, 3)) + >>> x + array([[3, 1, 7], + [2, 8, 3], + [8, 5, 3]]) + >>> x.item(3) + 2 + >>> x.item(7) + 5 + >>> x.item((0, 1)) + 1 + >>> x.item((2, 2)) + 3 + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('itemset', + """ + a.itemset(*args) + + Insert scalar into an array (scalar is cast to array's dtype, if possible) + + There must be at least 1 argument, and define the last argument + as *item*. Then, ``a.itemset(*args)`` is equivalent to but faster + than ``a[args] = item``. The item should be a scalar value and `args` + must select a single item in the array `a`. + + Parameters + ---------- + \\*args : Arguments + If one argument: a scalar, only used in case `a` is of size 1. + If two arguments: the last argument is the value to be set + and must be a scalar, the first argument specifies a single array + element location. It is either an int or a tuple. + + Notes + ----- + Compared to indexing syntax, `itemset` provides some speed increase + for placing a scalar into a particular location in an `ndarray`, + if you must do this. However, generally this is discouraged: + among other problems, it complicates the appearance of the code. + Also, when using `itemset` (and `item`) inside a loop, be sure + to assign the methods to a local variable to avoid the attribute + look-up at each loop iteration. + + Examples + -------- + >>> x = np.random.randint(9, size=(3, 3)) + >>> x + array([[3, 1, 7], + [2, 8, 3], + [8, 5, 3]]) + >>> x.itemset(4, 0) + >>> x.itemset((2, 2), 9) + >>> x + array([[3, 1, 7], + [2, 0, 3], + [8, 5, 9]]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('max', + """ + a.max(axis=None, out=None, keepdims=False) + + Return the maximum along a given axis. + + Refer to `numpy.amax` for full documentation. + + See Also + -------- + numpy.amax : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('mean', + """ + a.mean(axis=None, dtype=None, out=None, keepdims=False) + + Returns the average of the array elements along given axis. + + Refer to `numpy.mean` for full documentation. + + See Also + -------- + numpy.mean : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('min', + """ + a.min(axis=None, out=None, keepdims=False) + + Return the minimum along a given axis. + + Refer to `numpy.amin` for full documentation. + + See Also + -------- + numpy.amin : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'shares_memory', + """ + shares_memory(a, b, max_work=None) + + Determine if two arrays share memory + + Parameters + ---------- + a, b : ndarray + Input arrays + max_work : int, optional + Effort to spend on solving the overlap problem (maximum number + of candidate solutions to consider). The following special + values are recognized: + + max_work=MAY_SHARE_EXACT (default) + The problem is solved exactly. In this case, the function returns + True only if there is an element shared between the arrays. + max_work=MAY_SHARE_BOUNDS + Only the memory bounds of a and b are checked. + + Raises + ------ + numpy.TooHardError + Exceeded max_work. + + Returns + ------- + out : bool + + See Also + -------- + may_share_memory + + Examples + -------- + >>> np.may_share_memory(np.array([1,2]), np.array([5,8,9])) + False + + """) + + +add_newdoc('numpy.core.multiarray', 'may_share_memory', + """ + may_share_memory(a, b, max_work=None) + + Determine if two arrays might share memory + + A return of True does not necessarily mean that the two arrays + share any element. It just means that they *might*. + + Only the memory bounds of a and b are checked by default. + + Parameters + ---------- + a, b : ndarray + Input arrays + max_work : int, optional + Effort to spend on solving the overlap problem. See + `shares_memory` for details. Default for ``may_share_memory`` + is to do a bounds check. + + Returns + ------- + out : bool + + See Also + -------- + shares_memory + + Examples + -------- + >>> np.may_share_memory(np.array([1,2]), np.array([5,8,9])) + False + >>> x = np.zeros([3, 4]) + >>> np.may_share_memory(x[:,0], x[:,1]) + True + + """) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('newbyteorder', + """ + arr.newbyteorder(new_order='S') + + Return the array with the same data viewed with a different byte order. + + Equivalent to:: + + arr.view(arr.dtype.newbytorder(new_order)) + + Changes are also made in all fields and sub-arrays of the array data + type. + + + + Parameters + ---------- + new_order : string, optional + Byte order to force; a value from the byte order specifications + below. `new_order` codes can be any of: + + * 'S' - swap dtype from current to opposite endian + * {'<', 'L'} - little endian + * {'>', 'B'} - big endian + * {'=', 'N'} - native order + * {'|', 'I'} - ignore (no change to byte order) + + The default value ('S') results in swapping the current + byte order. The code does a case-insensitive check on the first + letter of `new_order` for the alternatives above. For example, + any of 'B' or 'b' or 'biggish' are valid to specify big-endian. + + + Returns + ------- + new_arr : array + New array object with the dtype reflecting given change to the + byte order. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('nonzero', + """ + a.nonzero() + + Return the indices of the elements that are non-zero. + + Refer to `numpy.nonzero` for full documentation. + + See Also + -------- + numpy.nonzero : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('prod', + """ + a.prod(axis=None, dtype=None, out=None, keepdims=False) + + Return the product of the array elements over the given axis + + Refer to `numpy.prod` for full documentation. + + See Also + -------- + numpy.prod : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('ptp', + """ + a.ptp(axis=None, out=None) + + Peak to peak (maximum - minimum) value along a given axis. + + Refer to `numpy.ptp` for full documentation. + + See Also + -------- + numpy.ptp : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('put', + """ + a.put(indices, values, mode='raise') + + Set ``a.flat[n] = values[n]`` for all `n` in indices. + + Refer to `numpy.put` for full documentation. + + See Also + -------- + numpy.put : equivalent function + + """)) + +add_newdoc('numpy.core.multiarray', 'copyto', + """ + copyto(dst, src, casting='same_kind', where=True) + + Copies values from one array to another, broadcasting as necessary. + + Raises a TypeError if the `casting` rule is violated, and if + `where` is provided, it selects which elements to copy. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + dst : ndarray + The array into which values are copied. + src : array_like + The array from which values are copied. + casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional + Controls what kind of data casting may occur when copying. + + * 'no' means the data types should not be cast at all. + * 'equiv' means only byte-order changes are allowed. + * 'safe' means only casts which can preserve values are allowed. + * 'same_kind' means only safe casts or casts within a kind, + like float64 to float32, are allowed. + * 'unsafe' means any data conversions may be done. + where : array_like of bool, optional + A boolean array which is broadcasted to match the dimensions + of `dst`, and selects elements to copy from `src` to `dst` + wherever it contains the value True. + + """) + +add_newdoc('numpy.core.multiarray', 'putmask', + """ + putmask(a, mask, values) + + Changes elements of an array based on conditional and input values. + + Sets ``a.flat[n] = values[n]`` for each n where ``mask.flat[n]==True``. + + If `values` is not the same size as `a` and `mask` then it will repeat. + This gives behavior different from ``a[mask] = values``. + + Parameters + ---------- + a : array_like + Target array. + mask : array_like + Boolean mask array. It has to be the same shape as `a`. + values : array_like + Values to put into `a` where `mask` is True. If `values` is smaller + than `a` it will be repeated. + + See Also + -------- + place, put, take, copyto + + Examples + -------- + >>> x = np.arange(6).reshape(2, 3) + >>> np.putmask(x, x>2, x**2) + >>> x + array([[ 0, 1, 2], + [ 9, 16, 25]]) + + If `values` is smaller than `a` it is repeated: + + >>> x = np.arange(5) + >>> np.putmask(x, x>1, [-33, -44]) + >>> x + array([ 0, 1, -33, -44, -33]) + + """) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('ravel', + """ + a.ravel([order]) + + Return a flattened array. + + Refer to `numpy.ravel` for full documentation. + + See Also + -------- + numpy.ravel : equivalent function + + ndarray.flat : a flat iterator on the array. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('repeat', + """ + a.repeat(repeats, axis=None) + + Repeat elements of an array. + + Refer to `numpy.repeat` for full documentation. + + See Also + -------- + numpy.repeat : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('reshape', + """ + a.reshape(shape, order='C') + + Returns an array containing the same data with a new shape. + + Refer to `numpy.reshape` for full documentation. + + See Also + -------- + numpy.reshape : equivalent function + + Notes + ----- + Unlike the free function `numpy.reshape`, this method on `ndarray` allows + the elements of the shape parameter to be passed in as separate arguments. + For example, ``a.reshape(10, 11)`` is equivalent to + ``a.reshape((10, 11))``. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('resize', + """ + a.resize(new_shape, refcheck=True) + + Change shape and size of array in-place. + + Parameters + ---------- + new_shape : tuple of ints, or `n` ints + Shape of resized array. + refcheck : bool, optional + If False, reference count will not be checked. Default is True. + + Returns + ------- + None + + Raises + ------ + ValueError + If `a` does not own its own data or references or views to it exist, + and the data memory must be changed. + PyPy only: will always raise if the data memory must be changed, since + there is no reliable way to determine if references or views to it + exist. + + SystemError + If the `order` keyword argument is specified. This behaviour is a + bug in NumPy. + + See Also + -------- + resize : Return a new array with the specified shape. + + Notes + ----- + This reallocates space for the data area if necessary. + + Only contiguous arrays (data elements consecutive in memory) can be + resized. + + The purpose of the reference count check is to make sure you + do not use this array as a buffer for another Python object and then + reallocate the memory. However, reference counts can increase in + other ways so if you are sure that you have not shared the memory + for this array with another Python object, then you may safely set + `refcheck` to False. + + Examples + -------- + Shrinking an array: array is flattened (in the order that the data are + stored in memory), resized, and reshaped: + + >>> a = np.array([[0, 1], [2, 3]], order='C') + >>> a.resize((2, 1)) + >>> a + array([[0], + [1]]) + + >>> a = np.array([[0, 1], [2, 3]], order='F') + >>> a.resize((2, 1)) + >>> a + array([[0], + [2]]) + + Enlarging an array: as above, but missing entries are filled with zeros: + + >>> b = np.array([[0, 1], [2, 3]]) + >>> b.resize(2, 3) # new_shape parameter doesn't have to be a tuple + >>> b + array([[0, 1, 2], + [3, 0, 0]]) + + Referencing an array prevents resizing... + + >>> c = a + >>> a.resize((1, 1)) + Traceback (most recent call last): + ... + ValueError: cannot resize an array that has been referenced ... + + Unless `refcheck` is False: + + >>> a.resize((1, 1), refcheck=False) + >>> a + array([[0]]) + >>> c + array([[0]]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('round', + """ + a.round(decimals=0, out=None) + + Return `a` with each element rounded to the given number of decimals. + + Refer to `numpy.around` for full documentation. + + See Also + -------- + numpy.around : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('searchsorted', + """ + a.searchsorted(v, side='left', sorter=None) + + Find indices where elements of v should be inserted in a to maintain order. + + For full documentation, see `numpy.searchsorted` + + See Also + -------- + numpy.searchsorted : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('setfield', + """ + a.setfield(val, dtype, offset=0) + + Put a value into a specified place in a field defined by a data-type. + + Place `val` into `a`'s field defined by `dtype` and beginning `offset` + bytes into the field. + + Parameters + ---------- + val : object + Value to be placed in field. + dtype : dtype object + Data-type of the field in which to place `val`. + offset : int, optional + The number of bytes into the field at which to place `val`. + + Returns + ------- + None + + See Also + -------- + getfield + + Examples + -------- + >>> x = np.eye(3) + >>> x.getfield(np.float64) + array([[ 1., 0., 0.], + [ 0., 1., 0.], + [ 0., 0., 1.]]) + >>> x.setfield(3, np.int32) + >>> x.getfield(np.int32) + array([[3, 3, 3], + [3, 3, 3], + [3, 3, 3]]) + >>> x + array([[ 1.00000000e+000, 1.48219694e-323, 1.48219694e-323], + [ 1.48219694e-323, 1.00000000e+000, 1.48219694e-323], + [ 1.48219694e-323, 1.48219694e-323, 1.00000000e+000]]) + >>> x.setfield(np.eye(3), np.int32) + >>> x + array([[ 1., 0., 0.], + [ 0., 1., 0.], + [ 0., 0., 1.]]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('setflags', + """ + a.setflags(write=None, align=None, uic=None) + + Set array flags WRITEABLE, ALIGNED, (WRITEBACKIFCOPY and UPDATEIFCOPY), + respectively. + + These Boolean-valued flags affect how numpy interprets the memory + area used by `a` (see Notes below). The ALIGNED flag can only + be set to True if the data is actually aligned according to the type. + The WRITEBACKIFCOPY and (deprecated) UPDATEIFCOPY flags can never be set + to True. The flag WRITEABLE can only be set to True if the array owns its + own memory, or the ultimate owner of the memory exposes a writeable buffer + interface, or is a string. (The exception for string is made so that + unpickling can be done without copying memory.) + + Parameters + ---------- + write : bool, optional + Describes whether or not `a` can be written to. + align : bool, optional + Describes whether or not `a` is aligned properly for its type. + uic : bool, optional + Describes whether or not `a` is a copy of another "base" array. + + Notes + ----- + Array flags provide information about how the memory area used + for the array is to be interpreted. There are 7 Boolean flags + in use, only four of which can be changed by the user: + WRITEBACKIFCOPY, UPDATEIFCOPY, WRITEABLE, and ALIGNED. + + WRITEABLE (W) the data area can be written to; + + ALIGNED (A) the data and strides are aligned appropriately for the hardware + (as determined by the compiler); + + UPDATEIFCOPY (U) (deprecated), replaced by WRITEBACKIFCOPY; + + WRITEBACKIFCOPY (X) this array is a copy of some other array (referenced + by .base). When the C-API function PyArray_ResolveWritebackIfCopy is + called, the base array will be updated with the contents of this array. + + All flags can be accessed using the single (upper case) letter as well + as the full name. + + Examples + -------- + >>> y + array([[3, 1, 7], + [2, 0, 0], + [8, 5, 9]]) + >>> y.flags + C_CONTIGUOUS : True + F_CONTIGUOUS : False + OWNDATA : True + WRITEABLE : True + ALIGNED : True + WRITEBACKIFCOPY : False + UPDATEIFCOPY : False + >>> y.setflags(write=0, align=0) + >>> y.flags + C_CONTIGUOUS : True + F_CONTIGUOUS : False + OWNDATA : True + WRITEABLE : False + ALIGNED : False + WRITEBACKIFCOPY : False + UPDATEIFCOPY : False + >>> y.setflags(uic=1) + Traceback (most recent call last): + File "", line 1, in + ValueError: cannot set WRITEBACKIFCOPY flag to True + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('sort', + """ + a.sort(axis=-1, kind='quicksort', order=None) + + Sort an array, in-place. + + Parameters + ---------- + axis : int, optional + Axis along which to sort. Default is -1, which means sort along the + last axis. + kind : {'quicksort', 'mergesort', 'heapsort'}, optional + Sorting algorithm. Default is 'quicksort'. + order : str or list of str, optional + When `a` is an array with fields defined, this argument specifies + which fields to compare first, second, etc. A single field can + be specified as a string, and not all fields need be specified, + but unspecified fields will still be used, in the order in which + they come up in the dtype, to break ties. + + See Also + -------- + numpy.sort : Return a sorted copy of an array. + argsort : Indirect sort. + lexsort : Indirect stable sort on multiple keys. + searchsorted : Find elements in sorted array. + partition: Partial sort. + + Notes + ----- + See ``sort`` for notes on the different sorting algorithms. + + Examples + -------- + >>> a = np.array([[1,4], [3,1]]) + >>> a.sort(axis=1) + >>> a + array([[1, 4], + [1, 3]]) + >>> a.sort(axis=0) + >>> a + array([[1, 3], + [1, 4]]) + + Use the `order` keyword to specify a field to use when sorting a + structured array: + + >>> a = np.array([('a', 2), ('c', 1)], dtype=[('x', 'S1'), ('y', int)]) + >>> a.sort(order='y') + >>> a + array([('c', 1), ('a', 2)], + dtype=[('x', '|S1'), ('y', '>> a = np.array([3, 4, 2, 1]) + >>> a.partition(3) + >>> a + array([2, 1, 3, 4]) + + >>> a.partition((1, 3)) + array([1, 2, 3, 4]) + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('squeeze', + """ + a.squeeze(axis=None) + + Remove single-dimensional entries from the shape of `a`. + + Refer to `numpy.squeeze` for full documentation. + + See Also + -------- + numpy.squeeze : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('std', + """ + a.std(axis=None, dtype=None, out=None, ddof=0, keepdims=False) + + Returns the standard deviation of the array elements along given axis. + + Refer to `numpy.std` for full documentation. + + See Also + -------- + numpy.std : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('sum', + """ + a.sum(axis=None, dtype=None, out=None, keepdims=False) + + Return the sum of the array elements over the given axis. + + Refer to `numpy.sum` for full documentation. + + See Also + -------- + numpy.sum : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('swapaxes', + """ + a.swapaxes(axis1, axis2) + + Return a view of the array with `axis1` and `axis2` interchanged. + + Refer to `numpy.swapaxes` for full documentation. + + See Also + -------- + numpy.swapaxes : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('take', + """ + a.take(indices, axis=None, out=None, mode='raise') + + Return an array formed from the elements of `a` at the given indices. + + Refer to `numpy.take` for full documentation. + + See Also + -------- + numpy.take : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('tofile', + """ + a.tofile(fid, sep="", format="%s") + + Write array to a file as text or binary (default). + + Data is always written in 'C' order, independent of the order of `a`. + The data produced by this method can be recovered using the function + fromfile(). + + Parameters + ---------- + fid : file or str + An open file object, or a string containing a filename. + sep : str + Separator between array items for text output. + If "" (empty), a binary file is written, equivalent to + ``file.write(a.tobytes())``. + format : str + Format string for text file output. + Each entry in the array is formatted to text by first converting + it to the closest Python type, and then using "format" % item. + + Notes + ----- + This is a convenience function for quick storage of array data. + Information on endianness and precision is lost, so this method is not a + good choice for files intended to archive data or transport data between + machines with different endianness. Some of these problems can be overcome + by outputting the data as text files, at the expense of speed and file + size. + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('tolist', + """ + a.tolist() + + Return the array as a (possibly nested) list. + + Return a copy of the array data as a (nested) Python list. + Data items are converted to the nearest compatible Python type. + + Parameters + ---------- + none + + Returns + ------- + y : list + The possibly nested list of array elements. + + Notes + ----- + The array may be recreated, ``a = np.array(a.tolist())``. + + Examples + -------- + >>> a = np.array([1, 2]) + >>> a.tolist() + [1, 2] + >>> a = np.array([[1, 2], [3, 4]]) + >>> list(a) + [array([1, 2]), array([3, 4])] + >>> a.tolist() + [[1, 2], [3, 4]] + + """)) + + +tobytesdoc = """ + a.{name}(order='C') + + Construct Python bytes containing the raw data bytes in the array. + + Constructs Python bytes showing a copy of the raw contents of + data memory. The bytes object can be produced in either 'C' or 'Fortran', + or 'Any' order (the default is 'C'-order). 'Any' order means C-order + unless the F_CONTIGUOUS flag in the array is set, in which case it + means 'Fortran' order. + + {deprecated} + + Parameters + ---------- + order : {{'C', 'F', None}}, optional + Order of the data for multidimensional arrays: + C, Fortran, or the same as for the original array. + + Returns + ------- + s : bytes + Python bytes exhibiting a copy of `a`'s raw data. + + Examples + -------- + >>> x = np.array([[0, 1], [2, 3]]) + >>> x.tobytes() + b'\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x03\\x00\\x00\\x00' + >>> x.tobytes('C') == x.tobytes() + True + >>> x.tobytes('F') + b'\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x03\\x00\\x00\\x00' + + """ + +add_newdoc('numpy.core.multiarray', 'ndarray', + ('tostring', tobytesdoc.format(name='tostring', + deprecated= + 'This function is a compatibility ' + 'alias for tobytes. Despite its ' + 'name it returns bytes not ' + 'strings.'))) +add_newdoc('numpy.core.multiarray', 'ndarray', + ('tobytes', tobytesdoc.format(name='tobytes', + deprecated='.. versionadded:: 1.9.0'))) + +add_newdoc('numpy.core.multiarray', 'ndarray', ('trace', + """ + a.trace(offset=0, axis1=0, axis2=1, dtype=None, out=None) + + Return the sum along diagonals of the array. + + Refer to `numpy.trace` for full documentation. + + See Also + -------- + numpy.trace : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('transpose', + """ + a.transpose(*axes) + + Returns a view of the array with axes transposed. + + For a 1-D array, this has no effect. (To change between column and + row vectors, first cast the 1-D array into a matrix object.) + For a 2-D array, this is the usual matrix transpose. + For an n-D array, if axes are given, their order indicates how the + axes are permuted (see Examples). If axes are not provided and + ``a.shape = (i[0], i[1], ... i[n-2], i[n-1])``, then + ``a.transpose().shape = (i[n-1], i[n-2], ... i[1], i[0])``. + + Parameters + ---------- + axes : None, tuple of ints, or `n` ints + + * None or no argument: reverses the order of the axes. + + * tuple of ints: `i` in the `j`-th place in the tuple means `a`'s + `i`-th axis becomes `a.transpose()`'s `j`-th axis. + + * `n` ints: same as an n-tuple of the same ints (this form is + intended simply as a "convenience" alternative to the tuple form) + + Returns + ------- + out : ndarray + View of `a`, with axes suitably permuted. + + See Also + -------- + ndarray.T : Array property returning the array transposed. + + Examples + -------- + >>> a = np.array([[1, 2], [3, 4]]) + >>> a + array([[1, 2], + [3, 4]]) + >>> a.transpose() + array([[1, 3], + [2, 4]]) + >>> a.transpose((1, 0)) + array([[1, 3], + [2, 4]]) + >>> a.transpose(1, 0) + array([[1, 3], + [2, 4]]) + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('var', + """ + a.var(axis=None, dtype=None, out=None, ddof=0, keepdims=False) + + Returns the variance of the array elements, along given axis. + + Refer to `numpy.var` for full documentation. + + See Also + -------- + numpy.var : equivalent function + + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('view', + """ + a.view(dtype=None, type=None) + + New view of array with the same data. + + Parameters + ---------- + dtype : data-type or ndarray sub-class, optional + Data-type descriptor of the returned view, e.g., float32 or int16. The + default, None, results in the view having the same data-type as `a`. + This argument can also be specified as an ndarray sub-class, which + then specifies the type of the returned object (this is equivalent to + setting the ``type`` parameter). + type : Python type, optional + Type of the returned view, e.g., ndarray or matrix. Again, the + default None results in type preservation. + + Notes + ----- + ``a.view()`` is used two different ways: + + ``a.view(some_dtype)`` or ``a.view(dtype=some_dtype)`` constructs a view + of the array's memory with a different data-type. This can cause a + reinterpretation of the bytes of memory. + + ``a.view(ndarray_subclass)`` or ``a.view(type=ndarray_subclass)`` just + returns an instance of `ndarray_subclass` that looks at the same array + (same shape, dtype, etc.) This does not cause a reinterpretation of the + memory. + + For ``a.view(some_dtype)``, if ``some_dtype`` has a different number of + bytes per entry than the previous dtype (for example, converting a + regular array to a structured array), then the behavior of the view + cannot be predicted just from the superficial appearance of ``a`` (shown + by ``print(a)``). It also depends on exactly how ``a`` is stored in + memory. Therefore if ``a`` is C-ordered versus fortran-ordered, versus + defined as a slice or transpose, etc., the view may give different + results. + + + Examples + -------- + >>> x = np.array([(1, 2)], dtype=[('a', np.int8), ('b', np.int8)]) + + Viewing array data using a different type and dtype: + + >>> y = x.view(dtype=np.int16, type=np.matrix) + >>> y + matrix([[513]], dtype=int16) + >>> print(type(y)) + + + Creating a view on a structured array so it can be used in calculations + + >>> x = np.array([(1, 2),(3,4)], dtype=[('a', np.int8), ('b', np.int8)]) + >>> xv = x.view(dtype=np.int8).reshape(-1,2) + >>> xv + array([[1, 2], + [3, 4]], dtype=int8) + >>> xv.mean(0) + array([ 2., 3.]) + + Making changes to the view changes the underlying array + + >>> xv[0,1] = 20 + >>> print(x) + [(1, 20) (3, 4)] + + Using a view to convert an array to a recarray: + + >>> z = x.view(np.recarray) + >>> z.a + array([1], dtype=int8) + + Views share data: + + >>> x[0] = (9, 10) + >>> z[0] + (9, 10) + + Views that change the dtype size (bytes per entry) should normally be + avoided on arrays defined by slices, transposes, fortran-ordering, etc.: + + >>> x = np.array([[1,2,3],[4,5,6]], dtype=np.int16) + >>> y = x[:, 0:2] + >>> y + array([[1, 2], + [4, 5]], dtype=int16) + >>> y.view(dtype=[('width', np.int16), ('length', np.int16)]) + Traceback (most recent call last): + File "", line 1, in + ValueError: new type not compatible with array. + >>> z = y.copy() + >>> z.view(dtype=[('width', np.int16), ('length', np.int16)]) + array([[(1, 2)], + [(4, 5)]], dtype=[('width', '>> oct_array = np.frompyfunc(oct, 1, 1) + >>> oct_array(np.array((10, 30, 100))) + array([012, 036, 0144], dtype=object) + >>> np.array((oct(10), oct(30), oct(100))) # for comparison + array(['012', '036', '0144'], + dtype='|S4') + + """) + +add_newdoc('numpy.core.umath', 'geterrobj', + """ + geterrobj() + + Return the current object that defines floating-point error handling. + + The error object contains all information that defines the error handling + behavior in NumPy. `geterrobj` is used internally by the other + functions that get and set error handling behavior (`geterr`, `seterr`, + `geterrcall`, `seterrcall`). + + Returns + ------- + errobj : list + The error object, a list containing three elements: + [internal numpy buffer size, error mask, error callback function]. + + The error mask is a single integer that holds the treatment information + on all four floating point errors. The information for each error type + is contained in three bits of the integer. If we print it in base 8, we + can see what treatment is set for "invalid", "under", "over", and + "divide" (in that order). The printed string can be interpreted with + + * 0 : 'ignore' + * 1 : 'warn' + * 2 : 'raise' + * 3 : 'call' + * 4 : 'print' + * 5 : 'log' + + See Also + -------- + seterrobj, seterr, geterr, seterrcall, geterrcall + getbufsize, setbufsize + + Notes + ----- + For complete documentation of the types of floating-point exceptions and + treatment options, see `seterr`. + + Examples + -------- + >>> np.geterrobj() # first get the defaults + [10000, 0, None] + + >>> def err_handler(type, flag): + ... print("Floating point error (%s), with flag %s" % (type, flag)) + ... + >>> old_bufsize = np.setbufsize(20000) + >>> old_err = np.seterr(divide='raise') + >>> old_handler = np.seterrcall(err_handler) + >>> np.geterrobj() + [20000, 2, ] + + >>> old_err = np.seterr(all='ignore') + >>> np.base_repr(np.geterrobj()[1], 8) + '0' + >>> old_err = np.seterr(divide='warn', over='log', under='call', + invalid='print') + >>> np.base_repr(np.geterrobj()[1], 8) + '4351' + + """) + +add_newdoc('numpy.core.umath', 'seterrobj', + """ + seterrobj(errobj) + + Set the object that defines floating-point error handling. + + The error object contains all information that defines the error handling + behavior in NumPy. `seterrobj` is used internally by the other + functions that set error handling behavior (`seterr`, `seterrcall`). + + Parameters + ---------- + errobj : list + The error object, a list containing three elements: + [internal numpy buffer size, error mask, error callback function]. + + The error mask is a single integer that holds the treatment information + on all four floating point errors. The information for each error type + is contained in three bits of the integer. If we print it in base 8, we + can see what treatment is set for "invalid", "under", "over", and + "divide" (in that order). The printed string can be interpreted with + + * 0 : 'ignore' + * 1 : 'warn' + * 2 : 'raise' + * 3 : 'call' + * 4 : 'print' + * 5 : 'log' + + See Also + -------- + geterrobj, seterr, geterr, seterrcall, geterrcall + getbufsize, setbufsize + + Notes + ----- + For complete documentation of the types of floating-point exceptions and + treatment options, see `seterr`. + + Examples + -------- + >>> old_errobj = np.geterrobj() # first get the defaults + >>> old_errobj + [10000, 0, None] + + >>> def err_handler(type, flag): + ... print("Floating point error (%s), with flag %s" % (type, flag)) + ... + >>> new_errobj = [20000, 12, err_handler] + >>> np.seterrobj(new_errobj) + >>> np.base_repr(12, 8) # int for divide=4 ('print') and over=1 ('warn') + '14' + >>> np.geterr() + {'over': 'warn', 'divide': 'print', 'invalid': 'ignore', 'under': 'ignore'} + >>> np.geterrcall() is err_handler + True + + """) + + +############################################################################## +# +# compiled_base functions +# +############################################################################## + +add_newdoc('numpy.core.multiarray', 'digitize', + """ + digitize(x, bins, right=False) + + Return the indices of the bins to which each value in input array belongs. + + Each index ``i`` returned is such that ``bins[i-1] <= x < bins[i]`` if + `bins` is monotonically increasing, or ``bins[i-1] > x >= bins[i]`` if + `bins` is monotonically decreasing. If values in `x` are beyond the + bounds of `bins`, 0 or ``len(bins)`` is returned as appropriate. If right + is True, then the right bin is closed so that the index ``i`` is such + that ``bins[i-1] < x <= bins[i]`` or ``bins[i-1] >= x > bins[i]`` if `bins` + is monotonically increasing or decreasing, respectively. + + Parameters + ---------- + x : array_like + Input array to be binned. Prior to NumPy 1.10.0, this array had to + be 1-dimensional, but can now have any shape. + bins : array_like + Array of bins. It has to be 1-dimensional and monotonic. + right : bool, optional + Indicating whether the intervals include the right or the left bin + edge. Default behavior is (right==False) indicating that the interval + does not include the right edge. The left bin end is open in this + case, i.e., bins[i-1] <= x < bins[i] is the default behavior for + monotonically increasing bins. + + Returns + ------- + out : ndarray of ints + Output array of indices, of same shape as `x`. + + Raises + ------ + ValueError + If `bins` is not monotonic. + TypeError + If the type of the input is complex. + + See Also + -------- + bincount, histogram, unique, searchsorted + + Notes + ----- + If values in `x` are such that they fall outside the bin range, + attempting to index `bins` with the indices that `digitize` returns + will result in an IndexError. + + .. versionadded:: 1.10.0 + + `np.digitize` is implemented in terms of `np.searchsorted`. This means + that a binary search is used to bin the values, which scales much better + for larger number of bins than the previous linear search. It also removes + the requirement for the input array to be 1-dimensional. + + Examples + -------- + >>> x = np.array([0.2, 6.4, 3.0, 1.6]) + >>> bins = np.array([0.0, 1.0, 2.5, 4.0, 10.0]) + >>> inds = np.digitize(x, bins) + >>> inds + array([1, 4, 3, 2]) + >>> for n in range(x.size): + ... print(bins[inds[n]-1], "<=", x[n], "<", bins[inds[n]]) + ... + 0.0 <= 0.2 < 1.0 + 4.0 <= 6.4 < 10.0 + 2.5 <= 3.0 < 4.0 + 1.0 <= 1.6 < 2.5 + + >>> x = np.array([1.2, 10.0, 12.4, 15.5, 20.]) + >>> bins = np.array([0, 5, 10, 15, 20]) + >>> np.digitize(x,bins,right=True) + array([1, 2, 3, 4, 4]) + >>> np.digitize(x,bins,right=False) + array([1, 3, 3, 4, 5]) + """) + +add_newdoc('numpy.core.multiarray', 'bincount', + """ + bincount(x, weights=None, minlength=0) + + Count number of occurrences of each value in array of non-negative ints. + + The number of bins (of size 1) is one larger than the largest value in + `x`. If `minlength` is specified, there will be at least this number + of bins in the output array (though it will be longer if necessary, + depending on the contents of `x`). + Each bin gives the number of occurrences of its index value in `x`. + If `weights` is specified the input array is weighted by it, i.e. if a + value ``n`` is found at position ``i``, ``out[n] += weight[i]`` instead + of ``out[n] += 1``. + + Parameters + ---------- + x : array_like, 1 dimension, nonnegative ints + Input array. + weights : array_like, optional + Weights, array of the same shape as `x`. + minlength : int, optional + A minimum number of bins for the output array. + + .. versionadded:: 1.6.0 + + Returns + ------- + out : ndarray of ints + The result of binning the input array. + The length of `out` is equal to ``np.amax(x)+1``. + + Raises + ------ + ValueError + If the input is not 1-dimensional, or contains elements with negative + values, or if `minlength` is negative. + TypeError + If the type of the input is float or complex. + + See Also + -------- + histogram, digitize, unique + + Examples + -------- + >>> np.bincount(np.arange(5)) + array([1, 1, 1, 1, 1]) + >>> np.bincount(np.array([0, 1, 1, 3, 2, 1, 7])) + array([1, 3, 1, 1, 0, 0, 0, 1]) + + >>> x = np.array([0, 1, 1, 3, 2, 1, 7, 23]) + >>> np.bincount(x).size == np.amax(x)+1 + True + + The input array needs to be of integer dtype, otherwise a + TypeError is raised: + + >>> np.bincount(np.arange(5, dtype=float)) + Traceback (most recent call last): + File "", line 1, in + TypeError: array cannot be safely cast to required type + + A possible use of ``bincount`` is to perform sums over + variable-size chunks of an array, using the ``weights`` keyword. + + >>> w = np.array([0.3, 0.5, 0.2, 0.7, 1., -0.6]) # weights + >>> x = np.array([0, 1, 1, 2, 2, 2]) + >>> np.bincount(x, weights=w) + array([ 0.3, 0.7, 1.1]) + + """) + +add_newdoc('numpy.core.multiarray', 'ravel_multi_index', + """ + ravel_multi_index(multi_index, dims, mode='raise', order='C') + + Converts a tuple of index arrays into an array of flat + indices, applying boundary modes to the multi-index. + + Parameters + ---------- + multi_index : tuple of array_like + A tuple of integer arrays, one array for each dimension. + dims : tuple of ints + The shape of array into which the indices from ``multi_index`` apply. + mode : {'raise', 'wrap', 'clip'}, optional + Specifies how out-of-bounds indices are handled. Can specify + either one mode or a tuple of modes, one mode per index. + + * 'raise' -- raise an error (default) + * 'wrap' -- wrap around + * 'clip' -- clip to the range + + In 'clip' mode, a negative index which would normally + wrap will clip to 0 instead. + order : {'C', 'F'}, optional + Determines whether the multi-index should be viewed as + indexing in row-major (C-style) or column-major + (Fortran-style) order. + + Returns + ------- + raveled_indices : ndarray + An array of indices into the flattened version of an array + of dimensions ``dims``. + + See Also + -------- + unravel_index + + Notes + ----- + .. versionadded:: 1.6.0 + + Examples + -------- + >>> arr = np.array([[3,6,6],[4,5,1]]) + >>> np.ravel_multi_index(arr, (7,6)) + array([22, 41, 37]) + >>> np.ravel_multi_index(arr, (7,6), order='F') + array([31, 41, 13]) + >>> np.ravel_multi_index(arr, (4,6), mode='clip') + array([22, 23, 19]) + >>> np.ravel_multi_index(arr, (4,4), mode=('clip','wrap')) + array([12, 13, 13]) + + >>> np.ravel_multi_index((3,1,4,1), (6,7,8,9)) + 1621 + """) + +add_newdoc('numpy.core.multiarray', 'unravel_index', + """ + unravel_index(indices, dims, order='C') + + Converts a flat index or array of flat indices into a tuple + of coordinate arrays. + + Parameters + ---------- + indices : array_like + An integer array whose elements are indices into the flattened + version of an array of dimensions ``dims``. Before version 1.6.0, + this function accepted just one index value. + dims : tuple of ints + The shape of the array to use for unraveling ``indices``. + order : {'C', 'F'}, optional + Determines whether the indices should be viewed as indexing in + row-major (C-style) or column-major (Fortran-style) order. + + .. versionadded:: 1.6.0 + + Returns + ------- + unraveled_coords : tuple of ndarray + Each array in the tuple has the same shape as the ``indices`` + array. + + See Also + -------- + ravel_multi_index + + Examples + -------- + >>> np.unravel_index([22, 41, 37], (7,6)) + (array([3, 6, 6]), array([4, 5, 1])) + >>> np.unravel_index([31, 41, 13], (7,6), order='F') + (array([3, 6, 6]), array([4, 5, 1])) + + >>> np.unravel_index(1621, (6,7,8,9)) + (3, 1, 4, 1) + + """) + +add_newdoc('numpy.core.multiarray', 'add_docstring', + """ + add_docstring(obj, docstring) + + Add a docstring to a built-in obj if possible. + If the obj already has a docstring raise a RuntimeError + If this routine does not know how to add a docstring to the object + raise a TypeError + """) + +add_newdoc('numpy.core.umath', '_add_newdoc_ufunc', + """ + add_ufunc_docstring(ufunc, new_docstring) + + Replace the docstring for a ufunc with new_docstring. + This method will only work if the current docstring for + the ufunc is NULL. (At the C level, i.e. when ufunc->doc is NULL.) + + Parameters + ---------- + ufunc : numpy.ufunc + A ufunc whose current doc is NULL. + new_docstring : string + The new docstring for the ufunc. + + Notes + ----- + This method allocates memory for new_docstring on + the heap. Technically this creates a mempory leak, since this + memory will not be reclaimed until the end of the program + even if the ufunc itself is removed. However this will only + be a problem if the user is repeatedly creating ufuncs with + no documentation, adding documentation via add_newdoc_ufunc, + and then throwing away the ufunc. + """) + +add_newdoc('numpy.core.multiarray', 'packbits', + """ + packbits(myarray, axis=None) + + Packs the elements of a binary-valued array into bits in a uint8 array. + + The result is padded to full bytes by inserting zero bits at the end. + + Parameters + ---------- + myarray : array_like + An array of integers or booleans whose elements should be packed to + bits. + axis : int, optional + The dimension over which bit-packing is done. + ``None`` implies packing the flattened array. + + Returns + ------- + packed : ndarray + Array of type uint8 whose elements represent bits corresponding to the + logical (0 or nonzero) value of the input elements. The shape of + `packed` has the same number of dimensions as the input (unless `axis` + is None, in which case the output is 1-D). + + See Also + -------- + unpackbits: Unpacks elements of a uint8 array into a binary-valued output + array. + + Examples + -------- + >>> a = np.array([[[1,0,1], + ... [0,1,0]], + ... [[1,1,0], + ... [0,0,1]]]) + >>> b = np.packbits(a, axis=-1) + >>> b + array([[[160],[64]],[[192],[32]]], dtype=uint8) + + Note that in binary 160 = 1010 0000, 64 = 0100 0000, 192 = 1100 0000, + and 32 = 0010 0000. + + """) + +add_newdoc('numpy.core.multiarray', 'unpackbits', + """ + unpackbits(myarray, axis=None) + + Unpacks elements of a uint8 array into a binary-valued output array. + + Each element of `myarray` represents a bit-field that should be unpacked + into a binary-valued output array. The shape of the output array is either + 1-D (if `axis` is None) or the same shape as the input array with unpacking + done along the axis specified. + + Parameters + ---------- + myarray : ndarray, uint8 type + Input array. + axis : int, optional + The dimension over which bit-unpacking is done. + ``None`` implies unpacking the flattened array. + + Returns + ------- + unpacked : ndarray, uint8 type + The elements are binary-valued (0 or 1). + + See Also + -------- + packbits : Packs the elements of a binary-valued array into bits in a uint8 + array. + + Examples + -------- + >>> a = np.array([[2], [7], [23]], dtype=np.uint8) + >>> a + array([[ 2], + [ 7], + [23]], dtype=uint8) + >>> b = np.unpackbits(a, axis=1) + >>> b + 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]], dtype=uint8) + + """) + + +############################################################################## +# +# Documentation for ufunc attributes and methods +# +############################################################################## + + +############################################################################## +# +# ufunc object +# +############################################################################## + +add_newdoc('numpy.core', 'ufunc', + """ + Functions that operate element by element on whole arrays. + + To see the documentation for a specific ufunc, use `info`. For + example, ``np.info(np.sin)``. Because ufuncs are written in C + (for speed) and linked into Python with NumPy's ufunc facility, + Python's help() function finds this page whenever help() is called + on a ufunc. + + A detailed explanation of ufuncs can be found in the docs for :ref:`ufuncs`. + + Calling ufuncs: + =============== + + op(*x[, out], where=True, **kwargs) + Apply `op` to the arguments `*x` elementwise, broadcasting the arguments. + + The broadcasting rules are: + + * Dimensions of length 1 may be prepended to either array. + * Arrays may be repeated along dimensions of length 1. + + Parameters + ---------- + *x : array_like + Input arrays. + out : ndarray, None, or tuple of ndarray and None, optional + Alternate array object(s) in which to put the result; if provided, it + must have a shape that the inputs broadcast to. A tuple of arrays + (possible only as a keyword argument) must have length equal to the + number of outputs; use `None` for outputs to be allocated by the ufunc. + where : array_like, optional + Values of True indicate to calculate the ufunc at that position, values + of False indicate to leave the value in the output alone. + **kwargs + For other keyword-only arguments, see the :ref:`ufunc docs `. + + Returns + ------- + r : ndarray or tuple of ndarray + `r` will have the shape that the arrays in `x` broadcast to; if `out` is + provided, `r` will be equal to `out`. If the function has more than one + output, then the result will be a tuple of arrays. + + """) + + +############################################################################## +# +# ufunc attributes +# +############################################################################## + +add_newdoc('numpy.core', 'ufunc', ('identity', + """ + The identity value. + + Data attribute containing the identity element for the ufunc, if it has one. + If it does not, the attribute value is None. + + Examples + -------- + >>> np.add.identity + 0 + >>> np.multiply.identity + 1 + >>> np.power.identity + 1 + >>> print(np.exp.identity) + None + """)) + +add_newdoc('numpy.core', 'ufunc', ('nargs', + """ + The number of arguments. + + Data attribute containing the number of arguments the ufunc takes, including + optional ones. + + Notes + ----- + Typically this value will be one more than what you might expect because all + ufuncs take the optional "out" argument. + + Examples + -------- + >>> np.add.nargs + 3 + >>> np.multiply.nargs + 3 + >>> np.power.nargs + 3 + >>> np.exp.nargs + 2 + """)) + +add_newdoc('numpy.core', 'ufunc', ('nin', + """ + The number of inputs. + + Data attribute containing the number of arguments the ufunc treats as input. + + Examples + -------- + >>> np.add.nin + 2 + >>> np.multiply.nin + 2 + >>> np.power.nin + 2 + >>> np.exp.nin + 1 + """)) + +add_newdoc('numpy.core', 'ufunc', ('nout', + """ + The number of outputs. + + Data attribute containing the number of arguments the ufunc treats as output. + + Notes + ----- + Since all ufuncs can take output arguments, this will always be (at least) 1. + + Examples + -------- + >>> np.add.nout + 1 + >>> np.multiply.nout + 1 + >>> np.power.nout + 1 + >>> np.exp.nout + 1 + + """)) + +add_newdoc('numpy.core', 'ufunc', ('ntypes', + """ + The number of types. + + The number of numerical NumPy types - of which there are 18 total - on which + the ufunc can operate. + + See Also + -------- + numpy.ufunc.types + + Examples + -------- + >>> np.add.ntypes + 18 + >>> np.multiply.ntypes + 18 + >>> np.power.ntypes + 17 + >>> np.exp.ntypes + 7 + >>> np.remainder.ntypes + 14 + + """)) + +add_newdoc('numpy.core', 'ufunc', ('types', + """ + Returns a list with types grouped input->output. + + Data attribute listing the data-type "Domain-Range" groupings the ufunc can + deliver. The data-types are given using the character codes. + + See Also + -------- + numpy.ufunc.ntypes + + Examples + -------- + >>> np.add.types + ['??->?', 'bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', + 'LL->L', 'qq->q', 'QQ->Q', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D', + 'GG->G', 'OO->O'] + + >>> np.multiply.types + ['??->?', 'bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', + 'LL->L', 'qq->q', 'QQ->Q', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D', + 'GG->G', 'OO->O'] + + >>> np.power.types + ['bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', 'LL->L', + 'qq->q', 'QQ->Q', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D', 'GG->G', + 'OO->O'] + + >>> np.exp.types + ['f->f', 'd->d', 'g->g', 'F->F', 'D->D', 'G->G', 'O->O'] + + >>> np.remainder.types + ['bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', 'LL->L', + 'qq->q', 'QQ->Q', 'ff->f', 'dd->d', 'gg->g', 'OO->O'] + + """)) + +add_newdoc('numpy.core', 'ufunc', ('signature', + """ + Definition of the core elements a generalized ufunc operates on. + + The signature determines how the dimensions of each input/output array + are split into core and loop dimensions: + + 1. Each dimension in the signature is matched to a dimension of the + corresponding passed-in array, starting from the end of the shape tuple. + 2. Core dimensions assigned to the same label in the signature must have + exactly matching sizes, no broadcasting is performed. + 3. The core dimensions are removed from all inputs and the remaining + dimensions are broadcast together, defining the loop dimensions. + + Notes + ----- + Generalized ufuncs are used internally in many linalg functions, and in + the testing suite; the examples below are taken from these. + For ufuncs that operate on scalars, the signature is `None`, which is + equivalent to '()' for every argument. + + Examples + -------- + >>> np.core.umath_tests.matrix_multiply.signature + '(m,n),(n,p)->(m,p)' + >>> np.linalg._umath_linalg.det.signature + '(m,m)->()' + >>> np.add.signature is None + True # equivalent to '(),()->()' + """)) + +############################################################################## +# +# ufunc methods +# +############################################################################## + +add_newdoc('numpy.core', 'ufunc', ('reduce', + """ + reduce(a, axis=0, dtype=None, out=None, keepdims=False) + + Reduces `a`'s dimension by one, by applying ufunc along one axis. + + Let :math:`a.shape = (N_0, ..., N_i, ..., N_{M-1})`. Then + :math:`ufunc.reduce(a, axis=i)[k_0, ..,k_{i-1}, k_{i+1}, .., k_{M-1}]` = + the result of iterating `j` over :math:`range(N_i)`, cumulatively applying + ufunc to each :math:`a[k_0, ..,k_{i-1}, j, k_{i+1}, .., k_{M-1}]`. + For a one-dimensional array, reduce produces results equivalent to: + :: + + r = op.identity # op = ufunc + for i in range(len(A)): + r = op(r, A[i]) + return r + + For example, add.reduce() is equivalent to sum(). + + Parameters + ---------- + a : array_like + The array to act on. + axis : None or int or tuple of ints, optional + Axis or axes along which a reduction is performed. + The default (`axis` = 0) is perform a reduction over the first + dimension of the input array. `axis` may be negative, in + which case it counts from the last to the first axis. + + .. versionadded:: 1.7.0 + + If this is `None`, a reduction is performed over all the axes. + If this is a tuple of ints, a reduction is performed on multiple + axes, instead of a single axis or all the axes as before. + + For operations which are either not commutative or not associative, + doing a reduction over multiple axes is not well-defined. The + ufuncs do not currently raise an exception in this case, but will + likely do so in the future. + dtype : data-type code, optional + The type used to represent the intermediate results. Defaults + to the data-type of the output array if this is provided, or + the data-type of the input array if no output array is provided. + out : ndarray, None, or tuple of ndarray and None, optional + A location into which the result is stored. If not provided or `None`, + a freshly-allocated array is returned. For consistency with + :ref:`ufunc.__call__`, if given as a keyword, this may be wrapped in a + 1-element tuple. + + .. versionchanged:: 1.13.0 + Tuples are allowed for keyword argument. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `arr`. + + .. versionadded:: 1.7.0 + + Returns + ------- + r : ndarray + The reduced array. If `out` was supplied, `r` is a reference to it. + + Examples + -------- + >>> np.multiply.reduce([2,3,5]) + 30 + + A multi-dimensional array example: + + >>> X = np.arange(8).reshape((2,2,2)) + >>> X + array([[[0, 1], + [2, 3]], + [[4, 5], + [6, 7]]]) + >>> np.add.reduce(X, 0) + array([[ 4, 6], + [ 8, 10]]) + >>> np.add.reduce(X) # confirm: default axis value is 0 + array([[ 4, 6], + [ 8, 10]]) + >>> np.add.reduce(X, 1) + array([[ 2, 4], + [10, 12]]) + >>> np.add.reduce(X, 2) + array([[ 1, 5], + [ 9, 13]]) + + """)) + +add_newdoc('numpy.core', 'ufunc', ('accumulate', + """ + accumulate(array, axis=0, dtype=None, out=None) + + Accumulate the result of applying the operator to all elements. + + For a one-dimensional array, accumulate produces results equivalent to:: + + r = np.empty(len(A)) + t = op.identity # op = the ufunc being applied to A's elements + for i in range(len(A)): + t = op(t, A[i]) + r[i] = t + return r + + For example, add.accumulate() is equivalent to np.cumsum(). + + For a multi-dimensional array, accumulate is applied along only one + axis (axis zero by default; see Examples below) so repeated use is + necessary if one wants to accumulate over multiple axes. + + Parameters + ---------- + array : array_like + The array to act on. + axis : int, optional + The axis along which to apply the accumulation; default is zero. + dtype : data-type code, optional + The data-type used to represent the intermediate results. Defaults + to the data-type of the output array if such is provided, or the + the data-type of the input array if no output array is provided. + out : ndarray, None, or tuple of ndarray and None, optional + A location into which the result is stored. If not provided or `None`, + a freshly-allocated array is returned. For consistency with + :ref:`ufunc.__call__`, if given as a keyword, this may be wrapped in a + 1-element tuple. + + .. versionchanged:: 1.13.0 + Tuples are allowed for keyword argument. + + Returns + ------- + r : ndarray + The accumulated values. If `out` was supplied, `r` is a reference to + `out`. + + Examples + -------- + 1-D array examples: + + >>> np.add.accumulate([2, 3, 5]) + array([ 2, 5, 10]) + >>> np.multiply.accumulate([2, 3, 5]) + array([ 2, 6, 30]) + + 2-D array examples: + + >>> I = np.eye(2) + >>> I + array([[ 1., 0.], + [ 0., 1.]]) + + Accumulate along axis 0 (rows), down columns: + + >>> np.add.accumulate(I, 0) + array([[ 1., 0.], + [ 1., 1.]]) + >>> np.add.accumulate(I) # no axis specified = axis zero + array([[ 1., 0.], + [ 1., 1.]]) + + Accumulate along axis 1 (columns), through rows: + + >>> np.add.accumulate(I, 1) + array([[ 1., 1.], + [ 0., 1.]]) + + """)) + +add_newdoc('numpy.core', 'ufunc', ('reduceat', + """ + reduceat(a, indices, axis=0, dtype=None, out=None) + + Performs a (local) reduce with specified slices over a single axis. + + For i in ``range(len(indices))``, `reduceat` computes + ``ufunc.reduce(a[indices[i]:indices[i+1]])``, which becomes the i-th + generalized "row" parallel to `axis` in the final result (i.e., in a + 2-D array, for example, if `axis = 0`, it becomes the i-th row, but if + `axis = 1`, it becomes the i-th column). There are three exceptions to this: + + * when ``i = len(indices) - 1`` (so for the last index), + ``indices[i+1] = a.shape[axis]``. + * if ``indices[i] >= indices[i + 1]``, the i-th generalized "row" is + simply ``a[indices[i]]``. + * if ``indices[i] >= len(a)`` or ``indices[i] < 0``, an error is raised. + + The shape of the output depends on the size of `indices`, and may be + larger than `a` (this happens if ``len(indices) > a.shape[axis]``). + + Parameters + ---------- + a : array_like + The array to act on. + indices : array_like + Paired indices, comma separated (not colon), specifying slices to + reduce. + axis : int, optional + The axis along which to apply the reduceat. + dtype : data-type code, optional + The type used to represent the intermediate results. Defaults + to the data type of the output array if this is provided, or + the data type of the input array if no output array is provided. + out : ndarray, None, or tuple of ndarray and None, optional + A location into which the result is stored. If not provided or `None`, + a freshly-allocated array is returned. For consistency with + :ref:`ufunc.__call__`, if given as a keyword, this may be wrapped in a + 1-element tuple. + + .. versionchanged:: 1.13.0 + Tuples are allowed for keyword argument. + + Returns + ------- + r : ndarray + The reduced values. If `out` was supplied, `r` is a reference to + `out`. + + Notes + ----- + A descriptive example: + + If `a` is 1-D, the function `ufunc.accumulate(a)` is the same as + ``ufunc.reduceat(a, indices)[::2]`` where `indices` is + ``range(len(array) - 1)`` with a zero placed + in every other element: + ``indices = zeros(2 * len(a) - 1)``, ``indices[1::2] = range(1, len(a))``. + + Don't be fooled by this attribute's name: `reduceat(a)` is not + necessarily smaller than `a`. + + Examples + -------- + To take the running sum of four successive values: + + >>> np.add.reduceat(np.arange(8),[0,4, 1,5, 2,6, 3,7])[::2] + array([ 6, 10, 14, 18]) + + A 2-D example: + + >>> x = np.linspace(0, 15, 16).reshape(4,4) + >>> x + array([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.], + [ 12., 13., 14., 15.]]) + + :: + + # reduce such that the result has the following five rows: + # [row1 + row2 + row3] + # [row4] + # [row2] + # [row3] + # [row1 + row2 + row3 + row4] + + >>> np.add.reduceat(x, [0, 3, 1, 2, 0]) + array([[ 12., 15., 18., 21.], + [ 12., 13., 14., 15.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.], + [ 24., 28., 32., 36.]]) + + :: + + # reduce such that result has the following two columns: + # [col1 * col2 * col3, col4] + + >>> np.multiply.reduceat(x, [0, 3], 1) + array([[ 0., 3.], + [ 120., 7.], + [ 720., 11.], + [ 2184., 15.]]) + + """)) + +add_newdoc('numpy.core', 'ufunc', ('outer', + """ + outer(A, B, **kwargs) + + Apply the ufunc `op` to all pairs (a, b) with a in `A` and b in `B`. + + Let ``M = A.ndim``, ``N = B.ndim``. Then the result, `C`, of + ``op.outer(A, B)`` is an array of dimension M + N such that: + + .. math:: C[i_0, ..., i_{M-1}, j_0, ..., j_{N-1}] = + op(A[i_0, ..., i_{M-1}], B[j_0, ..., j_{N-1}]) + + For `A` and `B` one-dimensional, this is equivalent to:: + + r = empty(len(A),len(B)) + for i in range(len(A)): + for j in range(len(B)): + r[i,j] = op(A[i], B[j]) # op = ufunc in question + + Parameters + ---------- + A : array_like + First array + B : array_like + Second array + kwargs : any + Arguments to pass on to the ufunc. Typically `dtype` or `out`. + + Returns + ------- + r : ndarray + Output array + + See Also + -------- + numpy.outer + + Examples + -------- + >>> np.multiply.outer([1, 2, 3], [4, 5, 6]) + array([[ 4, 5, 6], + [ 8, 10, 12], + [12, 15, 18]]) + + A multi-dimensional example: + + >>> A = np.array([[1, 2, 3], [4, 5, 6]]) + >>> A.shape + (2, 3) + >>> B = np.array([[1, 2, 3, 4]]) + >>> B.shape + (1, 4) + >>> C = np.multiply.outer(A, B) + >>> C.shape; C + (2, 3, 1, 4) + array([[[[ 1, 2, 3, 4]], + [[ 2, 4, 6, 8]], + [[ 3, 6, 9, 12]]], + [[[ 4, 8, 12, 16]], + [[ 5, 10, 15, 20]], + [[ 6, 12, 18, 24]]]]) + + """)) + +add_newdoc('numpy.core', 'ufunc', ('at', + """ + at(a, indices, b=None) + + Performs unbuffered in place operation on operand 'a' for elements + specified by 'indices'. For addition ufunc, this method is equivalent to + `a[indices] += b`, except that results are accumulated for elements that + are indexed more than once. For example, `a[[0,0]] += 1` will only + increment the first element once because of buffering, whereas + `add.at(a, [0,0], 1)` will increment the first element twice. + + .. versionadded:: 1.8.0 + + Parameters + ---------- + a : array_like + The array to perform in place operation on. + indices : array_like or tuple + Array like index object or slice object for indexing into first + operand. If first operand has multiple dimensions, indices can be a + tuple of array like index objects or slice objects. + b : array_like + Second operand for ufuncs requiring two operands. Operand must be + broadcastable over first operand after indexing or slicing. + + Examples + -------- + Set items 0 and 1 to their negative values: + + >>> a = np.array([1, 2, 3, 4]) + >>> np.negative.at(a, [0, 1]) + >>> print(a) + array([-1, -2, 3, 4]) + + :: + + Increment items 0 and 1, and increment item 2 twice: + + >>> a = np.array([1, 2, 3, 4]) + >>> np.add.at(a, [0, 1, 2, 2], 1) + >>> print(a) + array([2, 3, 5, 4]) + + :: + + Add items 0 and 1 in first array to second array, + and store results in first array: + + >>> a = np.array([1, 2, 3, 4]) + >>> b = np.array([1, 2]) + >>> np.add.at(a, [0, 1], b) + >>> print(a) + array([2, 4, 3, 4]) + + """)) + +############################################################################## +# +# Documentation for dtype attributes and methods +# +############################################################################## + +############################################################################## +# +# dtype object +# +############################################################################## + +add_newdoc('numpy.core.multiarray', 'dtype', + """ + dtype(obj, align=False, copy=False) + + Create a data type object. + + A numpy array is homogeneous, and contains elements described by a + dtype object. A dtype object can be constructed from different + combinations of fundamental numeric types. + + Parameters + ---------- + obj + Object to be converted to a data type object. + align : bool, optional + Add padding to the fields to match what a C compiler would output + for a similar C-struct. Can be ``True`` only if `obj` is a dictionary + or a comma-separated string. If a struct dtype is being created, + this also sets a sticky alignment flag ``isalignedstruct``. + copy : bool, optional + Make a new copy of the data-type object. If ``False``, the result + may just be a reference to a built-in data-type object. + + See also + -------- + result_type + + Examples + -------- + Using array-scalar type: + + >>> np.dtype(np.int16) + dtype('int16') + + Structured type, one field name 'f1', containing int16: + + >>> np.dtype([('f1', np.int16)]) + dtype([('f1', '>> np.dtype([('f1', [('f1', np.int16)])]) + dtype([('f1', [('f1', '>> np.dtype([('f1', np.uint), ('f2', np.int32)]) + dtype([('f1', '>> np.dtype([('a','f8'),('b','S10')]) + dtype([('a', '>> np.dtype("i4, (2,3)f8") + dtype([('f0', '>> np.dtype([('hello',(int,3)),('world',np.void,10)]) + dtype([('hello', '>> np.dtype((np.int16, {'x':(np.int8,0), 'y':(np.int8,1)})) + dtype(('>> np.dtype({'names':['gender','age'], 'formats':['S1',np.uint8]}) + dtype([('gender', '|S1'), ('age', '|u1')]) + + Offsets in bytes, here 0 and 25: + + >>> np.dtype({'surname':('S25',0),'age':(np.uint8,25)}) + dtype([('surname', '|S25'), ('age', '|u1')]) + + """) + +############################################################################## +# +# dtype attributes +# +############################################################################## + +add_newdoc('numpy.core.multiarray', 'dtype', ('alignment', + """ + The required alignment (bytes) of this data-type according to the compiler. + + More information is available in the C-API section of the manual. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('byteorder', + """ + A character indicating the byte-order of this data-type object. + + One of: + + === ============== + '=' native + '<' little-endian + '>' big-endian + '|' not applicable + === ============== + + All built-in data-type objects have byteorder either '=' or '|'. + + Examples + -------- + + >>> dt = np.dtype('i2') + >>> dt.byteorder + '=' + >>> # endian is not relevant for 8 bit numbers + >>> np.dtype('i1').byteorder + '|' + >>> # or ASCII strings + >>> np.dtype('S2').byteorder + '|' + >>> # Even if specific code is given, and it is native + >>> # '=' is the byteorder + >>> import sys + >>> sys_is_le = sys.byteorder == 'little' + >>> native_code = sys_is_le and '<' or '>' + >>> swapped_code = sys_is_le and '>' or '<' + >>> dt = np.dtype(native_code + 'i2') + >>> dt.byteorder + '=' + >>> # Swapped code shows up as itself + >>> dt = np.dtype(swapped_code + 'i2') + >>> dt.byteorder == swapped_code + True + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('char', + """A unique character code for each of the 21 different built-in types.""")) + +add_newdoc('numpy.core.multiarray', 'dtype', ('descr', + """ + PEP3118 interface description of the data-type. + + The format is that required by the 'descr' key in the + PEP3118 `__array_interface__` attribute. + + Warning: This attribute exists specifically for PEP3118 compliance, and + is not a datatype description compatible with `np.dtype`. + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('fields', + """ + Dictionary of named fields defined for this data type, or ``None``. + + The dictionary is indexed by keys that are the names of the fields. + Each entry in the dictionary is a tuple fully describing the field:: + + (dtype, offset[, title]) + + If present, the optional title can be any object (if it is a string + or unicode then it will also be a key in the fields dictionary, + otherwise it's meta-data). Notice also that the first two elements + of the tuple can be passed directly as arguments to the ``ndarray.getfield`` + and ``ndarray.setfield`` methods. + + See Also + -------- + ndarray.getfield, ndarray.setfield + + Examples + -------- + >>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))]) + >>> print(dt.fields) + {'grades': (dtype(('float64',(2,))), 16), 'name': (dtype('|S16'), 0)} + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('flags', + """ + Bit-flags describing how this data type is to be interpreted. + + Bit-masks are in `numpy.core.multiarray` as the constants + `ITEM_HASOBJECT`, `LIST_PICKLE`, `ITEM_IS_POINTER`, `NEEDS_INIT`, + `NEEDS_PYAPI`, `USE_GETITEM`, `USE_SETITEM`. A full explanation + of these flags is in C-API documentation; they are largely useful + for user-defined data-types. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('hasobject', + """ + Boolean indicating whether this dtype contains any reference-counted + objects in any fields or sub-dtypes. + + Recall that what is actually in the ndarray memory representing + the Python object is the memory address of that object (a pointer). + Special handling may be required, and this attribute is useful for + distinguishing data types that may contain arbitrary Python objects + and data-types that won't. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('isbuiltin', + """ + Integer indicating how this dtype relates to the built-in dtypes. + + Read-only. + + = ======================================================================== + 0 if this is a structured array type, with fields + 1 if this is a dtype compiled into numpy (such as ints, floats etc) + 2 if the dtype is for a user-defined numpy type + A user-defined type uses the numpy C-API machinery to extend + numpy to handle a new array type. See + :ref:`user.user-defined-data-types` in the NumPy manual. + = ======================================================================== + + Examples + -------- + >>> dt = np.dtype('i2') + >>> dt.isbuiltin + 1 + >>> dt = np.dtype('f8') + >>> dt.isbuiltin + 1 + >>> dt = np.dtype([('field1', 'f8')]) + >>> dt.isbuiltin + 0 + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('isnative', + """ + Boolean indicating whether the byte order of this dtype is native + to the platform. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('isalignedstruct', + """ + Boolean indicating whether the dtype is a struct which maintains + field alignment. This flag is sticky, so when combining multiple + structs together, it is preserved and produces new dtypes which + are also aligned. + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('itemsize', + """ + The element size of this data-type object. + + For 18 of the 21 types this number is fixed by the data-type. + For the flexible data-types, this number can be anything. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('kind', + """ + A character code (one of 'biufcmMOSUV') identifying the general kind of data. + + = ====================== + b boolean + i signed integer + u unsigned integer + f floating-point + c complex floating-point + m timedelta + M datetime + O object + S (byte-)string + U Unicode + V void + = ====================== + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('name', + """ + A bit-width name for this data-type. + + Un-sized flexible data-type objects do not have this attribute. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('names', + """ + Ordered list of field names, or ``None`` if there are no fields. + + The names are ordered according to increasing byte offset. This can be + used, for example, to walk through all of the named fields in offset order. + + Examples + -------- + >>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))]) + >>> dt.names + ('name', 'grades') + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('num', + """ + A unique number for each of the 21 different built-in types. + + These are roughly ordered from least-to-most precision. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('shape', + """ + Shape tuple of the sub-array if this data type describes a sub-array, + and ``()`` otherwise. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('ndim', + """ + Number of dimensions of the sub-array if this data type describes a + sub-array, and ``0`` otherwise. + + .. versionadded:: 1.13.0 + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('str', + """The array-protocol typestring of this data-type object.""")) + +add_newdoc('numpy.core.multiarray', 'dtype', ('subdtype', + """ + Tuple ``(item_dtype, shape)`` if this `dtype` describes a sub-array, and + None otherwise. + + The *shape* is the fixed shape of the sub-array described by this + data type, and *item_dtype* the data type of the array. + + If a field whose dtype object has this attribute is retrieved, + then the extra dimensions implied by *shape* are tacked on to + the end of the retrieved array. + + """)) + +add_newdoc('numpy.core.multiarray', 'dtype', ('type', + """The type object used to instantiate a scalar of this data-type.""")) + +############################################################################## +# +# dtype methods +# +############################################################################## + +add_newdoc('numpy.core.multiarray', 'dtype', ('newbyteorder', + """ + newbyteorder(new_order='S') + + Return a new dtype with a different byte order. + + Changes are also made in all fields and sub-arrays of the data type. + + Parameters + ---------- + new_order : string, optional + Byte order to force; a value from the byte order specifications + below. The default value ('S') results in swapping the current + byte order. `new_order` codes can be any of: + + * 'S' - swap dtype from current to opposite endian + * {'<', 'L'} - little endian + * {'>', 'B'} - big endian + * {'=', 'N'} - native order + * {'|', 'I'} - ignore (no change to byte order) + + The code does a case-insensitive check on the first letter of + `new_order` for these alternatives. For example, any of '>' + or 'B' or 'b' or 'brian' are valid to specify big-endian. + + Returns + ------- + new_dtype : dtype + New dtype object with the given change to the byte order. + + Notes + ----- + Changes are also made in all fields and sub-arrays of the data type. + + Examples + -------- + >>> import sys + >>> sys_is_le = sys.byteorder == 'little' + >>> native_code = sys_is_le and '<' or '>' + >>> swapped_code = sys_is_le and '>' or '<' + >>> native_dt = np.dtype(native_code+'i2') + >>> swapped_dt = np.dtype(swapped_code+'i2') + >>> native_dt.newbyteorder('S') == swapped_dt + True + >>> native_dt.newbyteorder() == swapped_dt + True + >>> native_dt == swapped_dt.newbyteorder('S') + True + >>> native_dt == swapped_dt.newbyteorder('=') + True + >>> native_dt == swapped_dt.newbyteorder('N') + True + >>> native_dt == native_dt.newbyteorder('|') + True + >>> np.dtype('>> np.dtype('>> np.dtype('>i2') == native_dt.newbyteorder('>') + True + >>> np.dtype('>i2') == native_dt.newbyteorder('B') + True + + """)) + + +############################################################################## +# +# Datetime-related Methods +# +############################################################################## + +add_newdoc('numpy.core.multiarray', 'busdaycalendar', + """ + busdaycalendar(weekmask='1111100', holidays=None) + + A business day calendar object that efficiently stores information + defining valid days for the busday family of functions. + + The default valid days are Monday through Friday ("business days"). + A busdaycalendar object can be specified with any set of weekly + valid days, plus an optional "holiday" dates that always will be invalid. + + Once a busdaycalendar object is created, the weekmask and holidays + cannot be modified. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + weekmask : str or array_like of bool, optional + A seven-element array indicating which of Monday through Sunday are + valid days. May be specified as a length-seven list or array, like + [1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string + like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for + weekdays, optionally separated by white space. Valid abbreviations + are: Mon Tue Wed Thu Fri Sat Sun + holidays : array_like of datetime64[D], optional + An array of dates to consider as invalid dates, no matter which + weekday they fall upon. Holiday dates may be specified in any + order, and NaT (not-a-time) dates are ignored. This list is + saved in a normalized form that is suited for fast calculations + of valid days. + + Returns + ------- + out : busdaycalendar + A business day calendar object containing the specified + weekmask and holidays values. + + See Also + -------- + is_busday : Returns a boolean array indicating valid days. + busday_offset : Applies an offset counted in valid days. + busday_count : Counts how many valid days are in a half-open date range. + + Attributes + ---------- + Note: once a busdaycalendar object is created, you cannot modify the + weekmask or holidays. The attributes return copies of internal data. + weekmask : (copy) seven-element array of bool + holidays : (copy) sorted array of datetime64[D] + + Examples + -------- + >>> # Some important days in July + ... bdd = np.busdaycalendar( + ... holidays=['2011-07-01', '2011-07-04', '2011-07-17']) + >>> # Default is Monday to Friday weekdays + ... bdd.weekmask + array([ True, True, True, True, True, False, False], dtype='bool') + >>> # Any holidays already on the weekend are removed + ... bdd.holidays + array(['2011-07-01', '2011-07-04'], dtype='datetime64[D]') + """) + +add_newdoc('numpy.core.multiarray', 'busdaycalendar', ('weekmask', + """A copy of the seven-element boolean mask indicating valid days.""")) + +add_newdoc('numpy.core.multiarray', 'busdaycalendar', ('holidays', + """A copy of the holiday array indicating additional invalid days.""")) + +add_newdoc('numpy.core.multiarray', 'is_busday', + """ + is_busday(dates, weekmask='1111100', holidays=None, busdaycal=None, out=None) + + Calculates which of the given dates are valid days, and which are not. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + dates : array_like of datetime64[D] + The array of dates to process. + weekmask : str or array_like of bool, optional + A seven-element array indicating which of Monday through Sunday are + valid days. May be specified as a length-seven list or array, like + [1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string + like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for + weekdays, optionally separated by white space. Valid abbreviations + are: Mon Tue Wed Thu Fri Sat Sun + holidays : array_like of datetime64[D], optional + An array of dates to consider as invalid dates. They may be + specified in any order, and NaT (not-a-time) dates are ignored. + This list is saved in a normalized form that is suited for + fast calculations of valid days. + busdaycal : busdaycalendar, optional + A `busdaycalendar` object which specifies the valid days. If this + parameter is provided, neither weekmask nor holidays may be + provided. + out : array of bool, optional + If provided, this array is filled with the result. + + Returns + ------- + out : array of bool + An array with the same shape as ``dates``, containing True for + each valid day, and False for each invalid day. + + See Also + -------- + busdaycalendar: An object that specifies a custom set of valid days. + busday_offset : Applies an offset counted in valid days. + busday_count : Counts how many valid days are in a half-open date range. + + Examples + -------- + >>> # The weekdays are Friday, Saturday, and Monday + ... np.is_busday(['2011-07-01', '2011-07-02', '2011-07-18'], + ... holidays=['2011-07-01', '2011-07-04', '2011-07-17']) + array([False, False, True], dtype='bool') + """) + +add_newdoc('numpy.core.multiarray', 'busday_offset', + """ + busday_offset(dates, offsets, roll='raise', weekmask='1111100', holidays=None, busdaycal=None, out=None) + + First adjusts the date to fall on a valid day according to + the ``roll`` rule, then applies offsets to the given dates + counted in valid days. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + dates : array_like of datetime64[D] + The array of dates to process. + offsets : array_like of int + The array of offsets, which is broadcast with ``dates``. + roll : {'raise', 'nat', 'forward', 'following', 'backward', 'preceding', 'modifiedfollowing', 'modifiedpreceding'}, optional + How to treat dates that do not fall on a valid day. The default + is 'raise'. + + * 'raise' means to raise an exception for an invalid day. + * 'nat' means to return a NaT (not-a-time) for an invalid day. + * 'forward' and 'following' mean to take the first valid day + later in time. + * 'backward' and 'preceding' mean to take the first valid day + earlier in time. + * 'modifiedfollowing' means to take the first valid day + later in time unless it is across a Month boundary, in which + case to take the first valid day earlier in time. + * 'modifiedpreceding' means to take the first valid day + earlier in time unless it is across a Month boundary, in which + case to take the first valid day later in time. + weekmask : str or array_like of bool, optional + A seven-element array indicating which of Monday through Sunday are + valid days. May be specified as a length-seven list or array, like + [1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string + like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for + weekdays, optionally separated by white space. Valid abbreviations + are: Mon Tue Wed Thu Fri Sat Sun + holidays : array_like of datetime64[D], optional + An array of dates to consider as invalid dates. They may be + specified in any order, and NaT (not-a-time) dates are ignored. + This list is saved in a normalized form that is suited for + fast calculations of valid days. + busdaycal : busdaycalendar, optional + A `busdaycalendar` object which specifies the valid days. If this + parameter is provided, neither weekmask nor holidays may be + provided. + out : array of datetime64[D], optional + If provided, this array is filled with the result. + + Returns + ------- + out : array of datetime64[D] + An array with a shape from broadcasting ``dates`` and ``offsets`` + together, containing the dates with offsets applied. + + See Also + -------- + busdaycalendar: An object that specifies a custom set of valid days. + is_busday : Returns a boolean array indicating valid days. + busday_count : Counts how many valid days are in a half-open date range. + + Examples + -------- + >>> # First business day in October 2011 (not accounting for holidays) + ... np.busday_offset('2011-10', 0, roll='forward') + numpy.datetime64('2011-10-03','D') + >>> # Last business day in February 2012 (not accounting for holidays) + ... np.busday_offset('2012-03', -1, roll='forward') + numpy.datetime64('2012-02-29','D') + >>> # Third Wednesday in January 2011 + ... np.busday_offset('2011-01', 2, roll='forward', weekmask='Wed') + numpy.datetime64('2011-01-19','D') + >>> # 2012 Mother's Day in Canada and the U.S. + ... np.busday_offset('2012-05', 1, roll='forward', weekmask='Sun') + numpy.datetime64('2012-05-13','D') + + >>> # First business day on or after a date + ... np.busday_offset('2011-03-20', 0, roll='forward') + numpy.datetime64('2011-03-21','D') + >>> np.busday_offset('2011-03-22', 0, roll='forward') + numpy.datetime64('2011-03-22','D') + >>> # First business day after a date + ... np.busday_offset('2011-03-20', 1, roll='backward') + numpy.datetime64('2011-03-21','D') + >>> np.busday_offset('2011-03-22', 1, roll='backward') + numpy.datetime64('2011-03-23','D') + """) + +add_newdoc('numpy.core.multiarray', 'busday_count', + """ + busday_count(begindates, enddates, weekmask='1111100', holidays=[], busdaycal=None, out=None) + + Counts the number of valid days between `begindates` and + `enddates`, not including the day of `enddates`. + + If ``enddates`` specifies a date value that is earlier than the + corresponding ``begindates`` date value, the count will be negative. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + begindates : array_like of datetime64[D] + The array of the first dates for counting. + enddates : array_like of datetime64[D] + The array of the end dates for counting, which are excluded + from the count themselves. + weekmask : str or array_like of bool, optional + A seven-element array indicating which of Monday through Sunday are + valid days. May be specified as a length-seven list or array, like + [1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string + like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for + weekdays, optionally separated by white space. Valid abbreviations + are: Mon Tue Wed Thu Fri Sat Sun + holidays : array_like of datetime64[D], optional + An array of dates to consider as invalid dates. They may be + specified in any order, and NaT (not-a-time) dates are ignored. + This list is saved in a normalized form that is suited for + fast calculations of valid days. + busdaycal : busdaycalendar, optional + A `busdaycalendar` object which specifies the valid days. If this + parameter is provided, neither weekmask nor holidays may be + provided. + out : array of int, optional + If provided, this array is filled with the result. + + Returns + ------- + out : array of int + An array with a shape from broadcasting ``begindates`` and ``enddates`` + together, containing the number of valid days between + the begin and end dates. + + See Also + -------- + busdaycalendar: An object that specifies a custom set of valid days. + is_busday : Returns a boolean array indicating valid days. + busday_offset : Applies an offset counted in valid days. + + Examples + -------- + >>> # Number of weekdays in January 2011 + ... np.busday_count('2011-01', '2011-02') + 21 + >>> # Number of weekdays in 2011 + ... np.busday_count('2011', '2012') + 260 + >>> # Number of Saturdays in 2011 + ... np.busday_count('2011', '2012', weekmask='Sat') + 53 + """) + +add_newdoc('numpy.core.multiarray', 'normalize_axis_index', + """ + normalize_axis_index(axis, ndim, msg_prefix=None) + + Normalizes an axis index, `axis`, such that is a valid positive index into + the shape of array with `ndim` dimensions. Raises an AxisError with an + appropriate message if this is not possible. + + Used internally by all axis-checking logic. + + .. versionadded:: 1.13.0 + + Parameters + ---------- + axis : int + The un-normalized index of the axis. Can be negative + ndim : int + The number of dimensions of the array that `axis` should be normalized + against + msg_prefix : str + A prefix to put before the message, typically the name of the argument + + Returns + ------- + normalized_axis : int + The normalized axis index, such that `0 <= normalized_axis < ndim` + + Raises + ------ + AxisError + If the axis index is invalid, when `-ndim <= axis < ndim` is false. + + Examples + -------- + >>> normalize_axis_index(0, ndim=3) + 0 + >>> normalize_axis_index(1, ndim=3) + 1 + >>> normalize_axis_index(-1, ndim=3) + 2 + + >>> normalize_axis_index(3, ndim=3) + Traceback (most recent call last): + ... + AxisError: axis 3 is out of bounds for array of dimension 3 + >>> normalize_axis_index(-4, ndim=3, msg_prefix='axes_arg') + Traceback (most recent call last): + ... + AxisError: axes_arg: axis -4 is out of bounds for array of dimension 3 + """) + +add_newdoc('numpy.core.multiarray', 'datetime_as_string', + """ + datetime_as_string(arr, unit=None, timezone='naive', casting='same_kind') + + Convert an array of datetimes into an array of strings. + + Parameters + ---------- + arr : array_like of datetime64 + The array of UTC timestamps to format. + unit : str + One of None, 'auto', or a datetime unit. + timezone : {'naive', 'UTC', 'local'} or tzinfo + Timezone information to use when displaying the datetime. If 'UTC', end + with a Z to indicate UTC time. If 'local', convert to the local timezone + first, and suffix with a +-#### timezone offset. If a tzinfo object, + then do as with 'local', but use the specified timezone. + casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'} + Casting to allow when changing between datetime units. + + Returns + ------- + str_arr : ndarray + An array of strings the same shape as `arr`. + + Examples + -------- + >>> d = np.arange('2002-10-27T04:30', 4*60, 60, dtype='M8[m]') + >>> d + array(['2002-10-27T04:30', '2002-10-27T05:30', '2002-10-27T06:30', + '2002-10-27T07:30'], dtype='datetime64[m]') + + Setting the timezone to UTC shows the same information, but with a Z suffix + + >>> np.datetime_as_string(d, timezone='UTC') + array(['2002-10-27T04:30Z', '2002-10-27T05:30Z', '2002-10-27T06:30Z', + '2002-10-27T07:30Z'], dtype='>> np.datetime_as_string(d, timezone=pytz.timezone('US/Eastern')) + array(['2002-10-27T00:30-0400', '2002-10-27T01:30-0400', + '2002-10-27T01:30-0500', '2002-10-27T02:30-0500'], dtype='>> np.datetime_as_string(d, unit='h') + array(['2002-10-27T04', '2002-10-27T05', '2002-10-27T06', '2002-10-27T07'], + dtype='>> np.datetime_as_string(d, unit='s') + array(['2002-10-27T04:30:00', '2002-10-27T05:30:00', '2002-10-27T06:30:00', + '2002-10-27T07:30:00'], dtype='>> np.datetime_as_string(d, unit='h', casting='safe') + TypeError: Cannot create a datetime string as units 'h' from a NumPy + datetime with units 'm' according to the rule 'safe' + """) + +add_newdoc('numpy.core.multiarray', 'datetime_data', + """ + datetime_data(dtype, /) + + Get information about the step size of a date or time type. + + The returned tuple can be passed as the second argument of `datetime64` and + `timedelta64`. + + Parameters + ---------- + dtype : dtype + The dtype object, which must be a `datetime64` or `timedelta64` type. + + Returns + ------- + unit : str + The :ref:`datetime unit ` on which this dtype + is based. + count : int + The number of base units in a step. + + Examples + -------- + >>> dt_25s = np.dtype('timedelta64[25s]') + >>> np.datetime_data(dt_25s) + ('s', 25) + >>> np.array(10, dt_25s).astype('timedelta64[s]') + array(250, dtype='timedelta64[s]') + + The result can be used to construct a datetime that uses the same units + as a timedelta:: + + >>> np.datetime64('2010', np.datetime_data(dt_25s)) + numpy.datetime64('2010-01-01T00:00:00','25s') + """) + +############################################################################## +# +# nd_grid instances +# +############################################################################## + +add_newdoc('numpy.lib.index_tricks', 'mgrid', + """ + `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. ]) + + """) + +add_newdoc('numpy.lib.index_tricks', 'ogrid', + """ + `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]])] + + """) + + +############################################################################## +# +# Documentation for `generic` attributes and methods +# +############################################################################## + +add_newdoc('numpy.core.numerictypes', 'generic', + """ + Base class for numpy scalar types. + + Class from which most (all?) numpy scalar types are derived. For + consistency, exposes the same API as `ndarray`, despite many + consequent attributes being either "get-only," or completely irrelevant. + This is the class from which it is strongly suggested users should derive + custom scalar types. + + """) + +# Attributes + +add_newdoc('numpy.core.numerictypes', 'generic', ('T', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class so as to + provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('base', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class so as to + a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('data', + """Pointer to start of data.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('dtype', + """Get array data-descriptor.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('flags', + """The integer value of flags.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('flat', + """A 1-D view of the scalar.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('imag', + """The imaginary part of the scalar.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('itemsize', + """The length of one element in bytes.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('nbytes', + """The length of the scalar in bytes.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('ndim', + """The number of array dimensions.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('real', + """The real part of the scalar.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('shape', + """Tuple of array dimensions.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('size', + """The number of elements in the gentype.""")) + +add_newdoc('numpy.core.numerictypes', 'generic', ('strides', + """Tuple of bytes steps in each dimension.""")) + +# Methods + +add_newdoc('numpy.core.numerictypes', 'generic', ('all', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('any', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('argmax', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('argmin', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('argsort', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('astype', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('byteswap', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class so as to + provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('choose', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('clip', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('compress', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('conjugate', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('copy', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('cumprod', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('cumsum', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('diagonal', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('dump', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('dumps', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('fill', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('flatten', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('getfield', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('item', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('itemset', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('max', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('mean', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('min', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('newbyteorder', + """ + newbyteorder(new_order='S') + + Return a new `dtype` with a different byte order. + + Changes are also made in all fields and sub-arrays of the data type. + + The `new_order` code can be any from the following: + + * 'S' - swap dtype from current to opposite endian + * {'<', 'L'} - little endian + * {'>', 'B'} - big endian + * {'=', 'N'} - native order + * {'|', 'I'} - ignore (no change to byte order) + + Parameters + ---------- + new_order : str, optional + Byte order to force; a value from the byte order specifications + above. The default value ('S') results in swapping the current + byte order. The code does a case-insensitive check on the first + letter of `new_order` for the alternatives above. For example, + any of 'B' or 'b' or 'biggish' are valid to specify big-endian. + + + Returns + ------- + new_dtype : dtype + New `dtype` object with the given change to the byte order. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('nonzero', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('prod', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('ptp', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('put', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('ravel', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('repeat', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('reshape', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('resize', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('round', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('searchsorted', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('setfield', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('setflags', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class so as to + provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('sort', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('squeeze', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('std', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('sum', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('swapaxes', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('take', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('tofile', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('tolist', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('tostring', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('trace', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('transpose', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('var', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + +add_newdoc('numpy.core.numerictypes', 'generic', ('view', + """ + Not implemented (virtual attribute) + + Class generic exists solely to derive numpy scalars from, and possesses, + albeit unimplemented, all the attributes of the ndarray class + so as to provide a uniform API. + + See Also + -------- + The corresponding attribute of the derived class of interest. + + """)) + + +############################################################################## +# +# Documentation for other scalar classes +# +############################################################################## + +add_newdoc('numpy.core.numerictypes', 'bool_', + """NumPy's Boolean type. Character code: ``?``. Alias: bool8""") + +add_newdoc('numpy.core.numerictypes', 'complex64', + """ + Complex number type composed of two 32 bit floats. Character code: 'F'. + + """) + +add_newdoc('numpy.core.numerictypes', 'complex128', + """ + Complex number type composed of two 64 bit floats. Character code: 'D'. + Python complex compatible. + + """) + +add_newdoc('numpy.core.numerictypes', 'complex256', + """ + Complex number type composed of two 128-bit floats. Character code: 'G'. + + """) + +add_newdoc('numpy.core.numerictypes', 'float32', + """ + 32-bit floating-point number. Character code 'f'. C float compatible. + + """) + +add_newdoc('numpy.core.numerictypes', 'float64', + """ + 64-bit floating-point number. Character code 'd'. Python float compatible. + + """) + +add_newdoc('numpy.core.numerictypes', 'float96', + """ + """) + +add_newdoc('numpy.core.numerictypes', 'float128', + """ + 128-bit floating-point number. Character code: 'g'. C long float + compatible. + + """) + +add_newdoc('numpy.core.numerictypes', 'int8', + """8-bit integer. Character code ``b``. C char compatible.""") + +add_newdoc('numpy.core.numerictypes', 'int16', + """16-bit integer. Character code ``h``. C short compatible.""") + +add_newdoc('numpy.core.numerictypes', 'int32', + """32-bit integer. Character code 'i'. C int compatible.""") + +add_newdoc('numpy.core.numerictypes', 'int64', + """64-bit integer. Character code 'l'. Python int compatible.""") + +add_newdoc('numpy.core.numerictypes', 'object_', + """Any Python object. Character code: 'O'.""") diff --git a/numpy/compat/__init__.py b/numpy/compat/__init__.py new file mode 100644 index 0000000..5b371f5 --- /dev/null +++ b/numpy/compat/__init__.py @@ -0,0 +1,20 @@ +""" +Compatibility module. + +This module contains duplicated code from Python itself or 3rd party +extensions, which may be included for the following reasons: + + * compatibility + * we may only need a small subset of the copied library/module + +""" +from __future__ import division, absolute_import, print_function + +from . import _inspect +from . import py3k +from ._inspect import getargspec, formatargspec +from .py3k import * + +__all__ = [] +__all__.extend(_inspect.__all__) +__all__.extend(py3k.__all__) diff --git a/numpy/compat/_inspect.py b/numpy/compat/_inspect.py new file mode 100644 index 0000000..76bf544 --- /dev/null +++ b/numpy/compat/_inspect.py @@ -0,0 +1,194 @@ +"""Subset of inspect module from upstream python + +We use this instead of upstream because upstream inspect is slow to import, and +significantly contributes to numpy import times. Importing this copy has almost +no overhead. + +""" +from __future__ import division, absolute_import, print_function + +import types + +__all__ = ['getargspec', 'formatargspec'] + +# ----------------------------------------------------------- type-checking +def ismethod(object): + """Return true if the object is an instance method. + + Instance method objects provide these attributes: + __doc__ documentation string + __name__ name with which this method was defined + im_class class object in which this method belongs + im_func function object containing implementation of method + im_self instance to which this method is bound, or None + + """ + return isinstance(object, types.MethodType) + +def isfunction(object): + """Return true if the object is a user-defined function. + + Function objects provide these attributes: + __doc__ documentation string + __name__ name with which this function was defined + func_code code object containing compiled function bytecode + func_defaults tuple of any default values for arguments + func_doc (same as __doc__) + func_globals global namespace in which this function was defined + func_name (same as __name__) + + """ + return isinstance(object, types.FunctionType) + +def iscode(object): + """Return true if the object is a code object. + + Code objects provide these attributes: + co_argcount number of arguments (not including * or ** args) + co_code string of raw compiled bytecode + co_consts tuple of constants used in the bytecode + co_filename name of file in which this code object was created + co_firstlineno number of first line in Python source code + co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg + co_lnotab encoded mapping of line numbers to bytecode indices + co_name name with which this code object was defined + co_names tuple of names of local variables + co_nlocals number of local variables + co_stacksize virtual machine stack space required + co_varnames tuple of names of arguments and local variables + + """ + return isinstance(object, types.CodeType) + +# ------------------------------------------------ argument list extraction +# These constants are from Python's compile.h. +CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8 + +def getargs(co): + """Get information about the arguments accepted by a code object. + + Three things are returned: (args, varargs, varkw), where 'args' is + a list of argument names (possibly containing nested lists), and + 'varargs' and 'varkw' are the names of the * and ** arguments or None. + + """ + + if not iscode(co): + raise TypeError('arg is not a code object') + + nargs = co.co_argcount + names = co.co_varnames + args = list(names[:nargs]) + + # The following acrobatics are for anonymous (tuple) arguments. + # Which we do not need to support, so remove to avoid importing + # the dis module. + for i in range(nargs): + if args[i][:1] in ['', '.']: + raise TypeError("tuple function arguments are not supported") + varargs = None + if co.co_flags & CO_VARARGS: + varargs = co.co_varnames[nargs] + nargs = nargs + 1 + varkw = None + if co.co_flags & CO_VARKEYWORDS: + varkw = co.co_varnames[nargs] + return args, varargs, varkw + +def getargspec(func): + """Get the names and default values of a function's arguments. + + A tuple of four things is returned: (args, varargs, varkw, defaults). + 'args' is a list of the argument names (it may contain nested lists). + 'varargs' and 'varkw' are the names of the * and ** arguments or None. + 'defaults' is an n-tuple of the default values of the last n arguments. + + """ + + if ismethod(func): + func = func.__func__ + if not isfunction(func): + raise TypeError('arg is not a Python function') + args, varargs, varkw = getargs(func.__code__) + return args, varargs, varkw, func.__defaults__ + +def getargvalues(frame): + """Get information about arguments passed into a particular frame. + + A tuple of four things is returned: (args, varargs, varkw, locals). + 'args' is a list of the argument names (it may contain nested lists). + 'varargs' and 'varkw' are the names of the * and ** arguments or None. + 'locals' is the locals dictionary of the given frame. + + """ + args, varargs, varkw = getargs(frame.f_code) + return args, varargs, varkw, frame.f_locals + +def joinseq(seq): + if len(seq) == 1: + return '(' + seq[0] + ',)' + else: + return '(' + ', '.join(seq) + ')' + +def strseq(object, convert, join=joinseq): + """Recursively walk a sequence, stringifying each element. + + """ + if type(object) in [list, tuple]: + return join([strseq(_o, convert, join) for _o in object]) + else: + return convert(object) + +def formatargspec(args, varargs=None, varkw=None, defaults=None, + formatarg=str, + formatvarargs=lambda name: '*' + name, + formatvarkw=lambda name: '**' + name, + formatvalue=lambda value: '=' + repr(value), + join=joinseq): + """Format an argument spec from the 4 values returned by getargspec. + + The first four arguments are (args, varargs, varkw, defaults). The + other four arguments are the corresponding optional formatting functions + that are called to turn names and values into strings. The ninth + argument is an optional function to format the sequence of arguments. + + """ + specs = [] + if defaults: + firstdefault = len(args) - len(defaults) + for i in range(len(args)): + spec = strseq(args[i], formatarg, join) + if defaults and i >= firstdefault: + spec = spec + formatvalue(defaults[i - firstdefault]) + specs.append(spec) + if varargs is not None: + specs.append(formatvarargs(varargs)) + if varkw is not None: + specs.append(formatvarkw(varkw)) + return '(' + ', '.join(specs) + ')' + +def formatargvalues(args, varargs, varkw, locals, + formatarg=str, + formatvarargs=lambda name: '*' + name, + formatvarkw=lambda name: '**' + name, + formatvalue=lambda value: '=' + repr(value), + join=joinseq): + """Format an argument spec from the 4 values returned by getargvalues. + + The first four arguments are (args, varargs, varkw, locals). The + next four arguments are the corresponding optional formatting functions + that are called to turn names and values into strings. The ninth + argument is an optional function to format the sequence of arguments. + + """ + def convert(name, locals=locals, + formatarg=formatarg, formatvalue=formatvalue): + return formatarg(name) + formatvalue(locals[name]) + specs = [] + for i in range(len(args)): + specs.append(strseq(args[i], convert, join)) + if varargs: + specs.append(formatvarargs(varargs) + formatvalue(locals[varargs])) + if varkw: + specs.append(formatvarkw(varkw) + formatvalue(locals[varkw])) + return '(' + ', '.join(specs) + ')' diff --git a/numpy/compat/py3k.py b/numpy/compat/py3k.py new file mode 100644 index 0000000..d5bb2e4 --- /dev/null +++ b/numpy/compat/py3k.py @@ -0,0 +1,156 @@ +""" +Python 3 compatibility tools. + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['bytes', 'asbytes', 'isfileobj', 'getexception', 'strchar', + 'unicode', 'asunicode', 'asbytes_nested', 'asunicode_nested', + 'asstr', 'open_latin1', 'long', 'basestring', 'sixu', + 'integer_types', 'is_pathlib_path', 'npy_load_module', 'Path'] + +import sys +try: + from pathlib import Path +except ImportError: + Path = None + +if sys.version_info[0] >= 3: + import io + + long = int + integer_types = (int,) + basestring = str + unicode = str + bytes = bytes + + def asunicode(s): + if isinstance(s, bytes): + return s.decode('latin1') + return str(s) + + def asbytes(s): + if isinstance(s, bytes): + return s + return str(s).encode('latin1') + + def asstr(s): + if isinstance(s, bytes): + return s.decode('latin1') + return str(s) + + def isfileobj(f): + return isinstance(f, (io.FileIO, io.BufferedReader, io.BufferedWriter)) + + def open_latin1(filename, mode='r'): + return open(filename, mode=mode, encoding='iso-8859-1') + + def sixu(s): + return s + + strchar = 'U' + + +else: + bytes = str + long = long + basestring = basestring + unicode = unicode + integer_types = (int, long) + asbytes = str + asstr = str + strchar = 'S' + + def isfileobj(f): + return isinstance(f, file) + + def asunicode(s): + if isinstance(s, unicode): + return s + return str(s).decode('ascii') + + def open_latin1(filename, mode='r'): + return open(filename, mode=mode) + + def sixu(s): + return unicode(s, 'unicode_escape') + + +def getexception(): + return sys.exc_info()[1] + +def asbytes_nested(x): + if hasattr(x, '__iter__') and not isinstance(x, (bytes, unicode)): + return [asbytes_nested(y) for y in x] + else: + return asbytes(x) + +def asunicode_nested(x): + if hasattr(x, '__iter__') and not isinstance(x, (bytes, unicode)): + return [asunicode_nested(y) for y in x] + else: + return asunicode(x) + +def is_pathlib_path(obj): + """ + Check whether obj is a pathlib.Path object. + """ + return Path is not None and isinstance(obj, Path) + +if sys.version_info[0] >= 3 and sys.version_info[1] >= 4: + def npy_load_module(name, fn, info=None): + """ + Load a module. + + .. versionadded:: 1.11.2 + + Parameters + ---------- + name : str + Full module name. + fn : str + Path to module file. + info : tuple, optional + Only here for backward compatibility with Python 2.*. + + Returns + ------- + mod : module + + """ + import importlib.machinery + return importlib.machinery.SourceFileLoader(name, fn).load_module() +else: + def npy_load_module(name, fn, info=None): + """ + Load a module. + + .. versionadded:: 1.11.2 + + Parameters + ---------- + name : str + Full module name. + fn : str + Path to module file. + info : tuple, optional + Information as returned by `imp.find_module` + (suffix, mode, type). + + Returns + ------- + mod : module + + """ + import imp + import os + if info is None: + path = os.path.dirname(fn) + fo, fn, info = imp.find_module(name, [path]) + else: + fo = open(fn, info[1]) + try: + mod = imp.load_module(name, fo, fn, info) + finally: + fo.close() + return mod diff --git a/numpy/compat/setup.py b/numpy/compat/setup.py new file mode 100644 index 0000000..26161f3 --- /dev/null +++ b/numpy/compat/setup.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +from __future__ import division, print_function + + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('compat', parent_package, top_path) + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/conftest.py b/numpy/conftest.py new file mode 100644 index 0000000..ea41970 --- /dev/null +++ b/numpy/conftest.py @@ -0,0 +1,54 @@ +""" +Pytest configuration and fixtures for the Numpy test suite. +""" +from __future__ import division, absolute_import, print_function + +import warnings +import pytest + +from numpy.core.multiarray_tests import get_fpu_mode + + +_old_fpu_mode = None +_collect_results = {} + + +@pytest.hookimpl() +def pytest_itemcollected(item): + """ + Check FPU precision mode was not changed during test collection. + + The clumsy way we do it here is mainly necessary because numpy + still uses yield tests, which can execute code at test collection + time. + """ + global _old_fpu_mode + + mode = get_fpu_mode() + + if _old_fpu_mode is None: + _old_fpu_mode = mode + elif mode != _old_fpu_mode: + _collect_results[item] = (_old_fpu_mode, mode) + _old_fpu_mode = mode + + +@pytest.fixture(scope="function", autouse=True) +def check_fpu_mode(request): + """ + Check FPU precision mode was not changed during the test. + """ + old_mode = get_fpu_mode() + yield + new_mode = get_fpu_mode() + + if old_mode != new_mode: + raise AssertionError("FPU precision mode changed from {0:#x} to {1:#x}" + " during the test".format(old_mode, new_mode)) + + collect_result = _collect_results.get(request.node) + if collect_result is not None: + old_mode, new_mode = collect_result + raise AssertionError("FPU precision mode changed from {0:#x} to {1:#x}" + " when collecting the test".format(old_mode, + new_mode)) diff --git a/numpy/core/__init__.py b/numpy/core/__init__.py new file mode 100644 index 0000000..6db484d --- /dev/null +++ b/numpy/core/__init__.py @@ -0,0 +1,106 @@ +from __future__ import division, absolute_import, print_function + +from .info import __doc__ +from numpy.version import version as __version__ + +# disables OpenBLAS affinity setting of the main thread that limits +# python threads or processes to one core +import os +env_added = [] +for envkey in ['OPENBLAS_MAIN_FREE', 'GOTOBLAS_MAIN_FREE']: + if envkey not in os.environ: + os.environ[envkey] = '1' + env_added.append(envkey) + +try: + from . import multiarray +except ImportError as exc: + msg = """ +Importing the multiarray numpy extension module failed. Most +likely you are trying to import a failed build of numpy. +If you're working with a numpy git repo, try `git clean -xdf` (removes all +files not under version control). Otherwise reinstall numpy. + +Original error was: %s +""" % (exc,) + raise ImportError(msg) +finally: + for envkey in env_added: + del os.environ[envkey] +del envkey +del env_added +del os + +from . import umath +from . import _internal # for freeze programs +from . import numerictypes as nt +multiarray.set_typeDict(nt.sctypeDict) +from . import numeric +from .numeric import * +from . import fromnumeric +from .fromnumeric import * +from . import defchararray as char +from . import records as rec +from .records import * +from .memmap import * +from .defchararray import chararray +from . import function_base +from .function_base import * +from . import machar +from .machar import * +from . import getlimits +from .getlimits import * +from . import shape_base +from .shape_base import * +from . import einsumfunc +from .einsumfunc import * +del nt + +from .fromnumeric import amax as max, amin as min, round_ as round +from .numeric import absolute as abs + +__all__ = ['char', 'rec', 'memmap'] +__all__ += numeric.__all__ +__all__ += fromnumeric.__all__ +__all__ += rec.__all__ +__all__ += ['chararray'] +__all__ += function_base.__all__ +__all__ += machar.__all__ +__all__ += getlimits.__all__ +__all__ += shape_base.__all__ +__all__ += einsumfunc.__all__ + + +from numpy.testing import _numpy_tester +test = _numpy_tester().test +bench = _numpy_tester().bench + +# Make it possible so that ufuncs can be pickled +# Here are the loading and unloading functions +# The name numpy.core._ufunc_reconstruct must be +# available for unpickling to work. +def _ufunc_reconstruct(module, name): + # The `fromlist` kwarg is required to ensure that `mod` points to the + # inner-most module rather than the parent package when module name is + # nested. This makes it possible to pickle non-toplevel ufuncs such as + # scipy.special.expit for instance. + mod = __import__(module, fromlist=[name]) + return getattr(mod, name) + +def _ufunc_reduce(func): + from pickle import whichmodule + name = func.__name__ + return _ufunc_reconstruct, (whichmodule(func, name), name) + + +import sys +if sys.version_info[0] >= 3: + import copyreg +else: + import copy_reg as copyreg + +copyreg.pickle(ufunc, _ufunc_reduce, _ufunc_reconstruct) +# Unclutter namespace (must keep _ufunc_reconstruct for unpickling) +del copyreg +del sys +del _ufunc_reduce diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py new file mode 100644 index 0000000..8c6596d --- /dev/null +++ b/numpy/core/_internal.py @@ -0,0 +1,758 @@ +""" +A place for code to be called from core C-code. + +Some things are more easily handled Python. + +""" +from __future__ import division, absolute_import, print_function + +import re +import sys + +from numpy.compat import basestring +from .multiarray import dtype, array, ndarray +try: + import ctypes +except ImportError: + ctypes = None +from .numerictypes import object_ + +if (sys.byteorder == 'little'): + _nbo = b'<' +else: + _nbo = b'>' + +def _makenames_list(adict, align): + allfields = [] + fnames = list(adict.keys()) + for fname in fnames: + obj = adict[fname] + n = len(obj) + if not isinstance(obj, tuple) or n not in [2, 3]: + raise ValueError("entry not a 2- or 3- tuple") + if (n > 2) and (obj[2] == fname): + continue + num = int(obj[1]) + if (num < 0): + raise ValueError("invalid offset.") + format = dtype(obj[0], align=align) + if (n > 2): + title = obj[2] + else: + title = None + allfields.append((fname, format, num, title)) + # sort by offsets + allfields.sort(key=lambda x: x[2]) + names = [x[0] for x in allfields] + formats = [x[1] for x in allfields] + offsets = [x[2] for x in allfields] + titles = [x[3] for x in allfields] + + return names, formats, offsets, titles + +# Called in PyArray_DescrConverter function when +# a dictionary without "names" and "formats" +# fields is used as a data-type descriptor. +def _usefields(adict, align): + try: + names = adict[-1] + except KeyError: + names = None + if names is None: + names, formats, offsets, titles = _makenames_list(adict, align) + else: + formats = [] + offsets = [] + titles = [] + for name in names: + res = adict[name] + formats.append(res[0]) + offsets.append(res[1]) + if (len(res) > 2): + titles.append(res[2]) + else: + titles.append(None) + + return dtype({"names": names, + "formats": formats, + "offsets": offsets, + "titles": titles}, align) + + +# construct an array_protocol descriptor list +# from the fields attribute of a descriptor +# This calls itself recursively but should eventually hit +# a descriptor that has no fields and then return +# a simple typestring + +def _array_descr(descriptor): + fields = descriptor.fields + if fields is None: + subdtype = descriptor.subdtype + if subdtype is None: + if descriptor.metadata is None: + return descriptor.str + else: + new = descriptor.metadata.copy() + if new: + return (descriptor.str, new) + else: + return descriptor.str + else: + return (_array_descr(subdtype[0]), subdtype[1]) + + names = descriptor.names + ordered_fields = [fields[x] + (x,) for x in names] + result = [] + offset = 0 + for field in ordered_fields: + if field[1] > offset: + num = field[1] - offset + result.append(('', '|V%d' % num)) + offset += num + elif field[1] < offset: + raise ValueError( + "dtype.descr is not defined for types with overlapping or " + "out-of-order fields") + if len(field) > 3: + name = (field[2], field[3]) + else: + name = field[2] + if field[0].subdtype: + tup = (name, _array_descr(field[0].subdtype[0]), + field[0].subdtype[1]) + else: + tup = (name, _array_descr(field[0])) + offset += field[0].itemsize + result.append(tup) + + if descriptor.itemsize > offset: + num = descriptor.itemsize - offset + result.append(('', '|V%d' % num)) + + return result + +# Build a new array from the information in a pickle. +# Note that the name numpy.core._internal._reconstruct is embedded in +# pickles of ndarrays made with NumPy before release 1.0 +# so don't remove the name here, or you'll +# break backward compatibility. +def _reconstruct(subtype, shape, dtype): + return ndarray.__new__(subtype, shape, dtype) + + +# format_re was originally from numarray by J. Todd Miller + +format_re = re.compile(br'(?P[<>|=]?)' + br'(?P *[(]?[ ,0-9L]*[)]? *)' + br'(?P[<>|=]?)' + br'(?P[A-Za-z0-9.?]*(?:\[[a-zA-Z0-9,.]+\])?)') +sep_re = re.compile(br'\s*,\s*') +space_re = re.compile(br'\s+$') + +# astr is a string (perhaps comma separated) + +_convorder = {b'=': _nbo} + +def _commastring(astr): + startindex = 0 + result = [] + while startindex < len(astr): + mo = format_re.match(astr, pos=startindex) + try: + (order1, repeats, order2, dtype) = mo.groups() + except (TypeError, AttributeError): + raise ValueError('format number %d of "%s" is not recognized' % + (len(result)+1, astr)) + startindex = mo.end() + # Separator or ending padding + if startindex < len(astr): + if space_re.match(astr, pos=startindex): + startindex = len(astr) + else: + mo = sep_re.match(astr, pos=startindex) + if not mo: + raise ValueError( + 'format number %d of "%s" is not recognized' % + (len(result)+1, astr)) + startindex = mo.end() + + if order2 == b'': + order = order1 + elif order1 == b'': + order = order2 + else: + order1 = _convorder.get(order1, order1) + order2 = _convorder.get(order2, order2) + if (order1 != order2): + raise ValueError( + 'inconsistent byte-order specification %s and %s' % + (order1, order2)) + order = order1 + + if order in [b'|', b'=', _nbo]: + order = b'' + dtype = order + dtype + if (repeats == b''): + newitem = dtype + else: + newitem = (dtype, eval(repeats)) + result.append(newitem) + + return result + +class dummy_ctype(object): + def __init__(self, cls): + self._cls = cls + def __mul__(self, other): + return self + def __call__(self, *other): + return self._cls(other) + def __eq__(self, other): + return self._cls == other._cls + def __ne__(self, other): + return self._cls != other._cls + +def _getintp_ctype(): + val = _getintp_ctype.cache + if val is not None: + return val + if ctypes is None: + import numpy as np + val = dummy_ctype(np.intp) + else: + char = dtype('p').char + if (char == 'i'): + val = ctypes.c_int + elif char == 'l': + val = ctypes.c_long + elif char == 'q': + val = ctypes.c_longlong + else: + val = ctypes.c_long + _getintp_ctype.cache = val + return val +_getintp_ctype.cache = None + +# Used for .ctypes attribute of ndarray + +class _missing_ctypes(object): + def cast(self, num, obj): + return num + + def c_void_p(self, num): + return num + +class _ctypes(object): + def __init__(self, array, ptr=None): + if ctypes: + self._ctypes = ctypes + else: + self._ctypes = _missing_ctypes() + self._arr = array + self._data = ptr + if self._arr.ndim == 0: + self._zerod = True + else: + self._zerod = False + + def data_as(self, obj): + return self._ctypes.cast(self._data, obj) + + def shape_as(self, obj): + if self._zerod: + return None + return (obj*self._arr.ndim)(*self._arr.shape) + + def strides_as(self, obj): + if self._zerod: + return None + return (obj*self._arr.ndim)(*self._arr.strides) + + def get_data(self): + return self._data + + def get_shape(self): + return self.shape_as(_getintp_ctype()) + + def get_strides(self): + return self.strides_as(_getintp_ctype()) + + def get_as_parameter(self): + return self._ctypes.c_void_p(self._data) + + data = property(get_data, None, doc="c-types data") + shape = property(get_shape, None, doc="c-types shape") + strides = property(get_strides, None, doc="c-types strides") + _as_parameter_ = property(get_as_parameter, None, doc="_as parameter_") + + +def _newnames(datatype, order): + """ + Given a datatype and an order object, return a new names tuple, with the + order indicated + """ + oldnames = datatype.names + nameslist = list(oldnames) + if isinstance(order, str): + order = [order] + seen = set() + if isinstance(order, (list, tuple)): + for name in order: + try: + nameslist.remove(name) + except ValueError: + if name in seen: + raise ValueError("duplicate field name: %s" % (name,)) + else: + raise ValueError("unknown field name: %s" % (name,)) + seen.add(name) + return tuple(list(order) + nameslist) + raise ValueError("unsupported order value: %s" % (order,)) + +def _copy_fields(ary): + """Return copy of structured array with padding between fields removed. + + Parameters + ---------- + ary : ndarray + Structured array from which to remove padding bytes + + Returns + ------- + ary_copy : ndarray + Copy of ary with padding bytes removed + """ + dt = ary.dtype + copy_dtype = {'names': dt.names, + 'formats': [dt.fields[name][0] for name in dt.names]} + return array(ary, dtype=copy_dtype, copy=True) + +def _getfield_is_safe(oldtype, newtype, offset): + """ Checks safety of getfield for object arrays. + + As in _view_is_safe, we need to check that memory containing objects is not + reinterpreted as a non-object datatype and vice versa. + + Parameters + ---------- + oldtype : data-type + Data type of the original ndarray. + newtype : data-type + Data type of the field being accessed by ndarray.getfield + offset : int + Offset of the field being accessed by ndarray.getfield + + Raises + ------ + TypeError + If the field access is invalid + + """ + if newtype.hasobject or oldtype.hasobject: + if offset == 0 and newtype == oldtype: + return + if oldtype.names: + for name in oldtype.names: + if (oldtype.fields[name][1] == offset and + oldtype.fields[name][0] == newtype): + return + raise TypeError("Cannot get/set field of an object array") + return + +def _view_is_safe(oldtype, newtype): + """ Checks safety of a view involving object arrays, for example when + doing:: + + np.zeros(10, dtype=oldtype).view(newtype) + + Parameters + ---------- + oldtype : data-type + Data type of original ndarray + newtype : data-type + Data type of the view + + Raises + ------ + TypeError + If the new type is incompatible with the old type. + + """ + + # if the types are equivalent, there is no problem. + # for example: dtype((np.record, 'i4,i4')) == dtype((np.void, 'i4,i4')) + if oldtype == newtype: + return + + if newtype.hasobject or oldtype.hasobject: + raise TypeError("Cannot change data-type for object array.") + return + +# Given a string containing a PEP 3118 format specifier, +# construct a NumPy dtype + +_pep3118_native_map = { + '?': '?', + 'c': 'S1', + 'b': 'b', + 'B': 'B', + 'h': 'h', + 'H': 'H', + 'i': 'i', + 'I': 'I', + 'l': 'l', + 'L': 'L', + 'q': 'q', + 'Q': 'Q', + 'e': 'e', + 'f': 'f', + 'd': 'd', + 'g': 'g', + 'Zf': 'F', + 'Zd': 'D', + 'Zg': 'G', + 's': 'S', + 'w': 'U', + 'O': 'O', + 'x': 'V', # padding +} +_pep3118_native_typechars = ''.join(_pep3118_native_map.keys()) + +_pep3118_standard_map = { + '?': '?', + 'c': 'S1', + 'b': 'b', + 'B': 'B', + 'h': 'i2', + 'H': 'u2', + 'i': 'i4', + 'I': 'u4', + 'l': 'i4', + 'L': 'u4', + 'q': 'i8', + 'Q': 'u8', + 'e': 'f2', + 'f': 'f', + 'd': 'd', + 'Zf': 'F', + 'Zd': 'D', + 's': 'S', + 'w': 'U', + 'O': 'O', + 'x': 'V', # padding +} +_pep3118_standard_typechars = ''.join(_pep3118_standard_map.keys()) + +def _dtype_from_pep3118(spec): + + class Stream(object): + def __init__(self, s): + self.s = s + self.byteorder = '@' + + def advance(self, n): + res = self.s[:n] + self.s = self.s[n:] + return res + + def consume(self, c): + if self.s[:len(c)] == c: + self.advance(len(c)) + return True + return False + + def consume_until(self, c): + if callable(c): + i = 0 + while i < len(self.s) and not c(self.s[i]): + i = i + 1 + return self.advance(i) + else: + i = self.s.index(c) + res = self.advance(i) + self.advance(len(c)) + return res + + @property + def next(self): + return self.s[0] + + def __bool__(self): + return bool(self.s) + __nonzero__ = __bool__ + + stream = Stream(spec) + + dtype, align = __dtype_from_pep3118(stream, is_subdtype=False) + return dtype + +def __dtype_from_pep3118(stream, is_subdtype): + field_spec = dict( + names=[], + formats=[], + offsets=[], + itemsize=0 + ) + offset = 0 + common_alignment = 1 + is_padding = False + + # Parse spec + while stream: + value = None + + # End of structure, bail out to upper level + if stream.consume('}'): + break + + # Sub-arrays (1) + shape = None + if stream.consume('('): + shape = stream.consume_until(')') + shape = tuple(map(int, shape.split(','))) + + # Byte order + if stream.next in ('@', '=', '<', '>', '^', '!'): + byteorder = stream.advance(1) + if byteorder == '!': + byteorder = '>' + stream.byteorder = byteorder + + # Byte order characters also control native vs. standard type sizes + if stream.byteorder in ('@', '^'): + type_map = _pep3118_native_map + type_map_chars = _pep3118_native_typechars + else: + type_map = _pep3118_standard_map + type_map_chars = _pep3118_standard_typechars + + # Item sizes + itemsize_str = stream.consume_until(lambda c: not c.isdigit()) + if itemsize_str: + itemsize = int(itemsize_str) + else: + itemsize = 1 + + # Data types + is_padding = False + + if stream.consume('T{'): + value, align = __dtype_from_pep3118( + stream, is_subdtype=True) + elif stream.next in type_map_chars: + if stream.next == 'Z': + typechar = stream.advance(2) + else: + typechar = stream.advance(1) + + is_padding = (typechar == 'x') + dtypechar = type_map[typechar] + if dtypechar in 'USV': + dtypechar += '%d' % itemsize + itemsize = 1 + numpy_byteorder = {'@': '=', '^': '='}.get( + stream.byteorder, stream.byteorder) + value = dtype(numpy_byteorder + dtypechar) + align = value.alignment + else: + raise ValueError("Unknown PEP 3118 data type specifier %r" % stream.s) + + # + # Native alignment may require padding + # + # Here we assume that the presence of a '@' character implicitly implies + # that the start of the array is *already* aligned. + # + extra_offset = 0 + if stream.byteorder == '@': + start_padding = (-offset) % align + intra_padding = (-value.itemsize) % align + + offset += start_padding + + if intra_padding != 0: + if itemsize > 1 or (shape is not None and _prod(shape) > 1): + # Inject internal padding to the end of the sub-item + value = _add_trailing_padding(value, intra_padding) + else: + # We can postpone the injection of internal padding, + # as the item appears at most once + extra_offset += intra_padding + + # Update common alignment + common_alignment = _lcm(align, common_alignment) + + # Convert itemsize to sub-array + if itemsize != 1: + value = dtype((value, (itemsize,))) + + # Sub-arrays (2) + if shape is not None: + value = dtype((value, shape)) + + # Field name + if stream.consume(':'): + name = stream.consume_until(':') + else: + name = None + + if not (is_padding and name is None): + if name is not None and name in field_spec['names']: + raise RuntimeError("Duplicate field name '%s' in PEP3118 format" + % name) + field_spec['names'].append(name) + field_spec['formats'].append(value) + field_spec['offsets'].append(offset) + + offset += value.itemsize + offset += extra_offset + + field_spec['itemsize'] = offset + + # extra final padding for aligned types + if stream.byteorder == '@': + field_spec['itemsize'] += (-offset) % common_alignment + + # Check if this was a simple 1-item type, and unwrap it + if (field_spec['names'] == [None] + and field_spec['offsets'][0] == 0 + and field_spec['itemsize'] == field_spec['formats'][0].itemsize + and not is_subdtype): + ret = field_spec['formats'][0] + else: + _fix_names(field_spec) + ret = dtype(field_spec) + + # Finished + return ret, common_alignment + +def _fix_names(field_spec): + """ Replace names which are None with the next unused f%d name """ + names = field_spec['names'] + for i, name in enumerate(names): + if name is not None: + continue + + j = 0 + while True: + name = 'f{}'.format(j) + if name not in names: + break + j = j + 1 + names[i] = name + +def _add_trailing_padding(value, padding): + """Inject the specified number of padding bytes at the end of a dtype""" + if value.fields is None: + field_spec = dict( + names=['f0'], + formats=[value], + offsets=[0], + itemsize=value.itemsize + ) + else: + fields = value.fields + names = value.names + field_spec = dict( + names=names, + formats=[fields[name][0] for name in names], + offsets=[fields[name][1] for name in names], + itemsize=value.itemsize + ) + + field_spec['itemsize'] += padding + return dtype(field_spec) + +def _prod(a): + p = 1 + for x in a: + p *= x + return p + +def _gcd(a, b): + """Calculate the greatest common divisor of a and b""" + while b: + a, b = b, a % b + return a + +def _lcm(a, b): + return a // _gcd(a, b) * b + +# Exception used in shares_memory() +class TooHardError(RuntimeError): + pass + +class AxisError(ValueError, IndexError): + """ Axis supplied was invalid. """ + def __init__(self, axis, ndim=None, msg_prefix=None): + # single-argument form just delegates to base class + if ndim is None and msg_prefix is None: + msg = axis + + # do the string formatting here, to save work in the C code + else: + msg = ("axis {} is out of bounds for array of dimension {}" + .format(axis, ndim)) + if msg_prefix is not None: + msg = "{}: {}".format(msg_prefix, msg) + + super(AxisError, self).__init__(msg) + + +def array_ufunc_errmsg_formatter(dummy, ufunc, method, *inputs, **kwargs): + """ Format the error message for when __array_ufunc__ gives up. """ + args_string = ', '.join(['{!r}'.format(arg) for arg in inputs] + + ['{}={!r}'.format(k, v) + for k, v in kwargs.items()]) + args = inputs + kwargs.get('out', ()) + types_string = ', '.join(repr(type(arg).__name__) for arg in args) + return ('operand type(s) all returned NotImplemented from ' + '__array_ufunc__({!r}, {!r}, {}): {}' + .format(ufunc, method, args_string, types_string)) + + +def _ufunc_doc_signature_formatter(ufunc): + """ + Builds a signature string which resembles PEP 457 + + This is used to construct the first line of the docstring + """ + + # input arguments are simple + if ufunc.nin == 1: + in_args = 'x' + else: + in_args = ', '.join('x{}'.format(i+1) for i in range(ufunc.nin)) + + # output arguments are both keyword or positional + if ufunc.nout == 0: + out_args = ', /, out=()' + elif ufunc.nout == 1: + out_args = ', /, out=None' + else: + out_args = '[, {positional}], / [, out={default}]'.format( + positional=', '.join( + 'out{}'.format(i+1) for i in range(ufunc.nout)), + default=repr((None,)*ufunc.nout) + ) + + # keyword only args depend on whether this is a gufunc + kwargs = ( + ", casting='same_kind'" + ", order='K'" + ", dtype=None" + ", subok=True" + "[, signature" + ", extobj]" + ) + if ufunc.signature is None: + kwargs = ", where=True" + kwargs + + # join all the parts together + return '{name}({in_args}{out_args}, *{kwargs})'.format( + name=ufunc.__name__, + in_args=in_args, + out_args=out_args, + kwargs=kwargs + ) diff --git a/numpy/core/_methods.py b/numpy/core/_methods.py new file mode 100644 index 0000000..c05316d --- /dev/null +++ b/numpy/core/_methods.py @@ -0,0 +1,144 @@ +""" +Array methods which are called by both the C-code for the method +and the Python code for the NumPy-namespace function + +""" +from __future__ import division, absolute_import, print_function + +import warnings + +from numpy.core import multiarray as mu +from numpy.core import umath as um +from numpy.core.numeric import asanyarray +from numpy.core import numerictypes as nt + +# save those O(100) nanoseconds! +umr_maximum = um.maximum.reduce +umr_minimum = um.minimum.reduce +umr_sum = um.add.reduce +umr_prod = um.multiply.reduce +umr_any = um.logical_or.reduce +umr_all = um.logical_and.reduce + +# avoid keyword arguments to speed up parsing, saves about 15%-20% for very +# small reductions +def _amax(a, axis=None, out=None, keepdims=False): + return umr_maximum(a, axis, None, out, keepdims) + +def _amin(a, axis=None, out=None, keepdims=False): + return umr_minimum(a, axis, None, out, keepdims) + +def _sum(a, axis=None, dtype=None, out=None, keepdims=False): + return umr_sum(a, axis, dtype, out, keepdims) + +def _prod(a, axis=None, dtype=None, out=None, keepdims=False): + return umr_prod(a, axis, dtype, out, keepdims) + +def _any(a, axis=None, dtype=None, out=None, keepdims=False): + return umr_any(a, axis, dtype, out, keepdims) + +def _all(a, axis=None, dtype=None, out=None, keepdims=False): + return umr_all(a, axis, dtype, out, keepdims) + +def _count_reduce_items(arr, axis): + if axis is None: + axis = tuple(range(arr.ndim)) + if not isinstance(axis, tuple): + axis = (axis,) + items = 1 + for ax in axis: + items *= arr.shape[ax] + return items + +def _mean(a, axis=None, dtype=None, out=None, keepdims=False): + arr = asanyarray(a) + + is_float16_result = False + rcount = _count_reduce_items(arr, axis) + # Make this warning show up first + if rcount == 0: + warnings.warn("Mean of empty slice.", RuntimeWarning, stacklevel=2) + + # Cast bool, unsigned int, and int to float64 by default + if dtype is None: + if issubclass(arr.dtype.type, (nt.integer, nt.bool_)): + dtype = mu.dtype('f8') + elif issubclass(arr.dtype.type, nt.float16): + dtype = mu.dtype('f4') + is_float16_result = True + + ret = umr_sum(arr, axis, dtype, out, keepdims) + if isinstance(ret, mu.ndarray): + ret = um.true_divide( + ret, rcount, out=ret, casting='unsafe', subok=False) + if is_float16_result and out is None: + ret = arr.dtype.type(ret) + elif hasattr(ret, 'dtype'): + if is_float16_result: + ret = arr.dtype.type(ret / rcount) + else: + ret = ret.dtype.type(ret / rcount) + else: + ret = ret / rcount + + return ret + +def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False): + arr = asanyarray(a) + + rcount = _count_reduce_items(arr, axis) + # Make this warning show up on top. + if ddof >= rcount: + warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning, + stacklevel=2) + + # Cast bool, unsigned int, and int to float64 by default + if dtype is None and issubclass(arr.dtype.type, (nt.integer, nt.bool_)): + dtype = mu.dtype('f8') + + # Compute the mean. + # Note that if dtype is not of inexact type then arraymean will + # not be either. + arrmean = umr_sum(arr, axis, dtype, keepdims=True) + if isinstance(arrmean, mu.ndarray): + arrmean = um.true_divide( + arrmean, rcount, out=arrmean, casting='unsafe', subok=False) + else: + arrmean = arrmean.dtype.type(arrmean / rcount) + + # Compute sum of squared deviations from mean + # Note that x may not be inexact and that we need it to be an array, + # not a scalar. + x = asanyarray(arr - arrmean) + if issubclass(arr.dtype.type, nt.complexfloating): + x = um.multiply(x, um.conjugate(x), out=x).real + else: + x = um.multiply(x, x, out=x) + ret = umr_sum(x, axis, dtype, out, keepdims) + + # Compute degrees of freedom and make sure it is not negative. + rcount = max([rcount - ddof, 0]) + + # divide by degrees of freedom + if isinstance(ret, mu.ndarray): + ret = um.true_divide( + ret, rcount, out=ret, casting='unsafe', subok=False) + elif hasattr(ret, 'dtype'): + ret = ret.dtype.type(ret / rcount) + else: + ret = ret / rcount + + return ret + +def _std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False): + ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof, + keepdims=keepdims) + + if isinstance(ret, mu.ndarray): + ret = um.sqrt(ret, out=ret) + elif hasattr(ret, 'dtype'): + ret = ret.dtype.type(um.sqrt(ret)) + else: + ret = um.sqrt(ret) + + return ret diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py new file mode 100644 index 0000000..4f29d75 --- /dev/null +++ b/numpy/core/arrayprint.py @@ -0,0 +1,1529 @@ +"""Array printing function + +$Id: arrayprint.py,v 1.9 2005/09/13 13:58:44 teoliphant Exp $ + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ["array2string", "array_str", "array_repr", "set_string_function", + "set_printoptions", "get_printoptions", "format_float_positional", + "format_float_scientific"] +__docformat__ = 'restructuredtext' + +# +# Written by Konrad Hinsen +# last revision: 1996-3-13 +# modified by Jim Hugunin 1997-3-3 for repr's and str's (and other details) +# and by Perry Greenfield 2000-4-1 for numarray +# and by Travis Oliphant 2005-8-22 for numpy + + +# Note: Both scalartypes.c.src and arrayprint.py implement strs for numpy +# scalars but for different purposes. scalartypes.c.src has str/reprs for when +# the scalar is printed on its own, while arrayprint.py has strs for when +# scalars are printed inside an ndarray. Only the latter strs are currently +# user-customizable. + +import sys +import functools +if sys.version_info[0] >= 3: + try: + from _thread import get_ident + except ImportError: + from _dummy_thread import get_ident +else: + try: + from thread import get_ident + except ImportError: + from dummy_thread import get_ident + +import numpy as np +from . import numerictypes as _nt +from .umath import absolute, not_equal, isnan, isinf, isfinite, isnat +from . import multiarray +from .multiarray import (array, dragon4_positional, dragon4_scientific, + datetime_as_string, datetime_data, dtype, ndarray, + set_legacy_print_mode) +from .fromnumeric import ravel, any +from .numeric import concatenate, asarray, errstate +from .numerictypes import (longlong, intc, int_, float_, complex_, bool_, + flexible) +import warnings + + +_format_options = { + 'edgeitems': 3, # repr N leading and trailing items of each dimension + 'threshold': 1000, # total items > triggers array summarization + 'floatmode': 'maxprec', + 'precision': 8, # precision of floating point representations + 'suppress': False, # suppress printing small floating values in exp format + 'linewidth': 75, + 'nanstr': 'nan', + 'infstr': 'inf', + 'sign': '-', + 'formatter': None, + 'legacy': False} + +def _make_options_dict(precision=None, threshold=None, edgeitems=None, + linewidth=None, suppress=None, nanstr=None, infstr=None, + sign=None, formatter=None, floatmode=None, legacy=None): + """ make a dictionary out of the non-None arguments, plus sanity checks """ + + options = {k: v for k, v in locals().items() if v is not None} + + if suppress is not None: + options['suppress'] = bool(suppress) + + modes = ['fixed', 'unique', 'maxprec', 'maxprec_equal'] + if floatmode not in modes + [None]: + raise ValueError("floatmode option must be one of " + + ", ".join('"{}"'.format(m) for m in modes)) + + if sign not in [None, '-', '+', ' ']: + raise ValueError("sign option must be one of ' ', '+', or '-'") + + if legacy not in [None, False, '1.13']: + warnings.warn("legacy printing option can currently only be '1.13' or " + "`False`", stacklevel=3) + + return options + +def set_printoptions(precision=None, threshold=None, edgeitems=None, + linewidth=None, suppress=None, nanstr=None, infstr=None, + formatter=None, sign=None, floatmode=None, **kwarg): + """ + Set printing options. + + These options determine the way floating point numbers, arrays and + other NumPy objects are displayed. + + Parameters + ---------- + precision : int or None, optional + Number of digits of precision for floating point output (default 8). + May be `None` if `floatmode` is not `fixed`, to print as many digits as + necessary to uniquely specify the value. + threshold : int, optional + Total number of array elements which trigger summarization + rather than full repr (default 1000). + edgeitems : int, optional + Number of array items in summary at beginning and end of + each dimension (default 3). + linewidth : int, optional + The number of characters per line for the purpose of inserting + line breaks (default 75). + suppress : bool, optional + If True, always print floating point numbers using fixed point + notation, in which case numbers equal to zero in the current precision + will print as zero. If False, then scientific notation is used when + absolute value of the smallest number is < 1e-4 or the ratio of the + maximum absolute value to the minimum is > 1e3. The default is False. + nanstr : str, optional + String representation of floating point not-a-number (default nan). + infstr : str, optional + String representation of floating point infinity (default inf). + sign : string, either '-', '+', or ' ', optional + Controls printing of the sign of floating-point types. If '+', always + print the sign of positive values. If ' ', always prints a space + (whitespace character) in the sign position of positive values. If + '-', omit the sign character of positive values. (default '-') + formatter : dict of callables, optional + If not None, the keys should indicate the type(s) that the respective + formatting function applies to. Callables should return a string. + Types that are not specified (by their corresponding keys) are handled + by the default formatters. Individual types for which a formatter + can be set are:: + + - 'bool' + - 'int' + - 'timedelta' : a `numpy.timedelta64` + - 'datetime' : a `numpy.datetime64` + - 'float' + - 'longfloat' : 128-bit floats + - 'complexfloat' + - 'longcomplexfloat' : composed of two 128-bit floats + - 'numpystr' : types `numpy.string_` and `numpy.unicode_` + - 'object' : `np.object_` arrays + - 'str' : all other strings + + Other keys that can be used to set a group of types at once are:: + + - 'all' : sets all types + - 'int_kind' : sets 'int' + - 'float_kind' : sets 'float' and 'longfloat' + - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat' + - 'str_kind' : sets 'str' and 'numpystr' + floatmode : str, optional + Controls the interpretation of the `precision` option for + floating-point types. Can take the following values: + - 'fixed' : Always print exactly `precision` fractional digits, + even if this would print more or fewer digits than + necessary to specify the value uniquely. + - 'unique : Print the minimum number of fractional digits necessary + to represent each value uniquely. Different elements may + have a different number of digits. The value of the + `precision` option is ignored. + - 'maxprec' : Print at most `precision` fractional digits, but if + an element can be uniquely represented with fewer digits + only print it with that many. + - 'maxprec_equal' : Print at most `precision` fractional digits, + but if every element in the array can be uniquely + represented with an equal number of fewer digits, use that + many digits for all elements. + legacy : string or `False`, optional + If set to the string `'1.13'` enables 1.13 legacy printing mode. This + approximates numpy 1.13 print output by including a space in the sign + position of floats and different behavior for 0d arrays. If set to + `False`, disables legacy mode. Unrecognized strings will be ignored + with a warning for forward compatibility. + + .. versionadded:: 1.14.0 + + See Also + -------- + get_printoptions, set_string_function, array2string + + Notes + ----- + `formatter` is always reset with a call to `set_printoptions`. + + Examples + -------- + Floating point precision can be set: + + >>> np.set_printoptions(precision=4) + >>> print(np.array([1.123456789])) + [ 1.1235] + + Long arrays can be summarised: + + >>> np.set_printoptions(threshold=5) + >>> print(np.arange(10)) + [0 1 2 ..., 7 8 9] + + Small results can be suppressed: + + >>> eps = np.finfo(float).eps + >>> x = np.arange(4.) + >>> x**2 - (x + eps)**2 + array([ -4.9304e-32, -4.4409e-16, 0.0000e+00, 0.0000e+00]) + >>> np.set_printoptions(suppress=True) + >>> x**2 - (x + eps)**2 + array([-0., -0., 0., 0.]) + + A custom formatter can be used to display array elements as desired: + + >>> np.set_printoptions(formatter={'all':lambda x: 'int: '+str(-x)}) + >>> x = np.arange(3) + >>> x + array([int: 0, int: -1, int: -2]) + >>> np.set_printoptions() # formatter gets reset + >>> x + array([0, 1, 2]) + + To put back the default options, you can use: + + >>> np.set_printoptions(edgeitems=3,infstr='inf', + ... linewidth=75, nanstr='nan', precision=8, + ... suppress=False, threshold=1000, formatter=None) + """ + legacy = kwarg.pop('legacy', None) + if kwarg: + msg = "set_printoptions() got unexpected keyword argument '{}'" + raise TypeError(msg.format(kwarg.popitem()[0])) + + opt = _make_options_dict(precision, threshold, edgeitems, linewidth, + suppress, nanstr, infstr, sign, formatter, + floatmode, legacy) + # formatter is always reset + opt['formatter'] = formatter + _format_options.update(opt) + + # set the C variable for legacy mode + if _format_options['legacy'] == '1.13': + set_legacy_print_mode(113) + # reset the sign option in legacy mode to avoid confusion + _format_options['sign'] = '-' + elif _format_options['legacy'] is False: + set_legacy_print_mode(0) + + +def get_printoptions(): + """ + Return the current print options. + + Returns + ------- + print_opts : dict + Dictionary of current print options with keys + + - precision : int + - threshold : int + - edgeitems : int + - linewidth : int + - suppress : bool + - nanstr : str + - infstr : str + - formatter : dict of callables + - sign : str + + For a full description of these options, see `set_printoptions`. + + See Also + -------- + set_printoptions, set_string_function + + """ + return _format_options.copy() + + +def _leading_trailing(a, edgeitems, index=()): + """ + Keep only the N-D corners (leading and trailing edges) of an array. + + Should be passed a base-class ndarray, since it makes no guarantees about + preserving subclasses. + """ + axis = len(index) + if axis == a.ndim: + return a[index] + + if a.shape[axis] > 2*edgeitems: + return concatenate(( + _leading_trailing(a, edgeitems, index + np.index_exp[ :edgeitems]), + _leading_trailing(a, edgeitems, index + np.index_exp[-edgeitems:]) + ), axis=axis) + else: + return _leading_trailing(a, edgeitems, index + np.index_exp[:]) + + +def _object_format(o): + """ Object arrays containing lists should be printed unambiguously """ + if type(o) is list: + fmt = 'list({!r})' + else: + fmt = '{!r}' + return fmt.format(o) + +def repr_format(x): + return repr(x) + +def str_format(x): + return str(x) + +def _get_formatdict(data, **opt): + prec, fmode = opt['precision'], opt['floatmode'] + supp, sign = opt['suppress'], opt['sign'] + legacy = opt['legacy'] + + # wrapped in lambdas to avoid taking a code path with the wrong type of data + formatdict = { + 'bool': lambda: BoolFormat(data), + 'int': lambda: IntegerFormat(data), + 'float': lambda: + FloatingFormat(data, prec, fmode, supp, sign, legacy=legacy), + 'longfloat': lambda: + FloatingFormat(data, prec, fmode, supp, sign, legacy=legacy), + 'complexfloat': lambda: + ComplexFloatingFormat(data, prec, fmode, supp, sign, legacy=legacy), + 'longcomplexfloat': lambda: + ComplexFloatingFormat(data, prec, fmode, supp, sign, legacy=legacy), + 'datetime': lambda: DatetimeFormat(data, legacy=legacy), + 'timedelta': lambda: TimedeltaFormat(data), + 'object': lambda: _object_format, + 'void': lambda: str_format, + 'numpystr': lambda: repr_format, + 'str': lambda: str} + + # we need to wrap values in `formatter` in a lambda, so that the interface + # is the same as the above values. + def indirect(x): + return lambda: x + + formatter = opt['formatter'] + if formatter is not None: + fkeys = [k for k in formatter.keys() if formatter[k] is not None] + if 'all' in fkeys: + for key in formatdict.keys(): + formatdict[key] = indirect(formatter['all']) + if 'int_kind' in fkeys: + for key in ['int']: + formatdict[key] = indirect(formatter['int_kind']) + if 'float_kind' in fkeys: + for key in ['float', 'longfloat']: + formatdict[key] = indirect(formatter['float_kind']) + if 'complex_kind' in fkeys: + for key in ['complexfloat', 'longcomplexfloat']: + formatdict[key] = indirect(formatter['complex_kind']) + if 'str_kind' in fkeys: + for key in ['numpystr', 'str']: + formatdict[key] = indirect(formatter['str_kind']) + for key in formatdict.keys(): + if key in fkeys: + formatdict[key] = indirect(formatter[key]) + + return formatdict + +def _get_format_function(data, **options): + """ + find the right formatting function for the dtype_ + """ + dtype_ = data.dtype + dtypeobj = dtype_.type + formatdict = _get_formatdict(data, **options) + if issubclass(dtypeobj, _nt.bool_): + return formatdict['bool']() + elif issubclass(dtypeobj, _nt.integer): + if issubclass(dtypeobj, _nt.timedelta64): + return formatdict['timedelta']() + else: + return formatdict['int']() + elif issubclass(dtypeobj, _nt.floating): + if issubclass(dtypeobj, _nt.longfloat): + return formatdict['longfloat']() + else: + return formatdict['float']() + elif issubclass(dtypeobj, _nt.complexfloating): + if issubclass(dtypeobj, _nt.clongfloat): + return formatdict['longcomplexfloat']() + else: + return formatdict['complexfloat']() + elif issubclass(dtypeobj, (_nt.unicode_, _nt.string_)): + return formatdict['numpystr']() + elif issubclass(dtypeobj, _nt.datetime64): + return formatdict['datetime']() + elif issubclass(dtypeobj, _nt.object_): + return formatdict['object']() + elif issubclass(dtypeobj, _nt.void): + if dtype_.names is not None: + return StructuredVoidFormat.from_data(data, **options) + else: + return formatdict['void']() + else: + return formatdict['numpystr']() + + +def _recursive_guard(fillvalue='...'): + """ + Like the python 3.2 reprlib.recursive_repr, but forwards *args and **kwargs + + Decorates a function such that if it calls itself with the same first + argument, it returns `fillvalue` instead of recursing. + + Largely copied from reprlib.recursive_repr + """ + + def decorating_function(f): + repr_running = set() + + @functools.wraps(f) + def wrapper(self, *args, **kwargs): + key = id(self), get_ident() + if key in repr_running: + return fillvalue + repr_running.add(key) + try: + return f(self, *args, **kwargs) + finally: + repr_running.discard(key) + + return wrapper + + return decorating_function + + +# gracefully handle recursive calls, when object arrays contain themselves +@_recursive_guard() +def _array2string(a, options, separator=' ', prefix=""): + # The formatter __init__s in _get_format_function cannot deal with + # subclasses yet, and we also need to avoid recursion issues in + # _formatArray with subclasses which return 0d arrays in place of scalars + data = asarray(a) + if a.shape == (): + a = data + + if a.size > options['threshold']: + summary_insert = "..." + data = _leading_trailing(data, options['edgeitems']) + else: + summary_insert = "" + + # find the right formatting function for the array + format_function = _get_format_function(data, **options) + + # skip over "[" + next_line_prefix = " " + # skip over array( + next_line_prefix += " "*len(prefix) + + lst = _formatArray(a, format_function, options['linewidth'], + next_line_prefix, separator, options['edgeitems'], + summary_insert, options['legacy']) + return lst + + +def array2string(a, max_line_width=None, precision=None, + suppress_small=None, separator=' ', prefix="", + style=np._NoValue, formatter=None, threshold=None, + edgeitems=None, sign=None, floatmode=None, suffix="", + **kwarg): + """ + Return a string representation of an array. + + Parameters + ---------- + a : array_like + Input array. + max_line_width : int, optional + The maximum number of columns the string should span. Newline + characters splits the string appropriately after array elements. + precision : int or None, optional + Floating point precision. Default is the current printing + precision (usually 8), which can be altered using `set_printoptions`. + suppress_small : bool, optional + Represent very small numbers as zero. A number is "very small" if it + is smaller than the current printing precision. + separator : str, optional + Inserted between elements. + prefix : str, optional + suffix: str, optional + The length of the prefix and suffix strings are used to respectively + align and wrap the output. An array is typically printed as:: + + prefix + array2string(a) + suffix + + The output is left-padded by the length of the prefix string, and + wrapping is forced at the column ``max_line_width - len(suffix)``. + style : _NoValue, optional + Has no effect, do not use. + + .. deprecated:: 1.14.0 + formatter : dict of callables, optional + If not None, the keys should indicate the type(s) that the respective + formatting function applies to. Callables should return a string. + Types that are not specified (by their corresponding keys) are handled + by the default formatters. Individual types for which a formatter + can be set are:: + + - 'bool' + - 'int' + - 'timedelta' : a `numpy.timedelta64` + - 'datetime' : a `numpy.datetime64` + - 'float' + - 'longfloat' : 128-bit floats + - 'complexfloat' + - 'longcomplexfloat' : composed of two 128-bit floats + - 'void' : type `numpy.void` + - 'numpystr' : types `numpy.string_` and `numpy.unicode_` + - 'str' : all other strings + + Other keys that can be used to set a group of types at once are:: + + - 'all' : sets all types + - 'int_kind' : sets 'int' + - 'float_kind' : sets 'float' and 'longfloat' + - 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat' + - 'str_kind' : sets 'str' and 'numpystr' + threshold : int, optional + Total number of array elements which trigger summarization + rather than full repr. + edgeitems : int, optional + Number of array items in summary at beginning and end of + each dimension. + sign : string, either '-', '+', or ' ', optional + Controls printing of the sign of floating-point types. If '+', always + print the sign of positive values. If ' ', always prints a space + (whitespace character) in the sign position of positive values. If + '-', omit the sign character of positive values. + floatmode : str, optional + Controls the interpretation of the `precision` option for + floating-point types. Can take the following values: + - 'fixed' : Always print exactly `precision` fractional digits, + even if this would print more or fewer digits than + necessary to specify the value uniquely. + - 'unique : Print the minimum number of fractional digits necessary + to represent each value uniquely. Different elements may + have a different number of digits. The value of the + `precision` option is ignored. + - 'maxprec' : Print at most `precision` fractional digits, but if + an element can be uniquely represented with fewer digits + only print it with that many. + - 'maxprec_equal' : Print at most `precision` fractional digits, + but if every element in the array can be uniquely + represented with an equal number of fewer digits, use that + many digits for all elements. + legacy : string or `False`, optional + If set to the string `'1.13'` enables 1.13 legacy printing mode. This + approximates numpy 1.13 print output by including a space in the sign + position of floats and different behavior for 0d arrays. If set to + `False`, disables legacy mode. Unrecognized strings will be ignored + with a warning for forward compatibility. + + .. versionadded:: 1.14.0 + + Returns + ------- + array_str : str + String representation of the array. + + Raises + ------ + TypeError + if a callable in `formatter` does not return a string. + + See Also + -------- + array_str, array_repr, set_printoptions, get_printoptions + + Notes + ----- + If a formatter is specified for a certain type, the `precision` keyword is + ignored for that type. + + This is a very flexible function; `array_repr` and `array_str` are using + `array2string` internally so keywords with the same name should work + identically in all three functions. + + Examples + -------- + >>> x = np.array([1e-16,1,2,3]) + >>> print(np.array2string(x, precision=2, separator=',', + ... suppress_small=True)) + [ 0., 1., 2., 3.] + + >>> x = np.arange(3.) + >>> np.array2string(x, formatter={'float_kind':lambda x: "%.2f" % x}) + '[0.00 1.00 2.00]' + + >>> x = np.arange(3) + >>> np.array2string(x, formatter={'int':lambda x: hex(x)}) + '[0x0L 0x1L 0x2L]' + + """ + legacy = kwarg.pop('legacy', None) + if kwarg: + msg = "array2string() got unexpected keyword argument '{}'" + raise TypeError(msg.format(kwarg.popitem()[0])) + + overrides = _make_options_dict(precision, threshold, edgeitems, + max_line_width, suppress_small, None, None, + sign, formatter, floatmode, legacy) + options = _format_options.copy() + options.update(overrides) + + if options['legacy'] == '1.13': + if style is np._NoValue: + style = repr + + if a.shape == () and not a.dtype.names: + return style(a.item()) + elif style is not np._NoValue: + # Deprecation 11-9-2017 v1.14 + warnings.warn("'style' argument is deprecated and no longer functional" + " except in 1.13 'legacy' mode", + DeprecationWarning, stacklevel=3) + + if options['legacy'] != '1.13': + options['linewidth'] -= len(suffix) + + # treat as a null array if any of shape elements == 0 + if a.size == 0: + return "[]" + + return _array2string(a, options, separator, prefix) + + +def _extendLine(s, line, word, line_width, next_line_prefix, legacy): + needs_wrap = len(line) + len(word) > line_width + if legacy != '1.13': + s# don't wrap lines if it won't help + if len(line) <= len(next_line_prefix): + needs_wrap = False + + if needs_wrap: + s += line.rstrip() + "\n" + line = next_line_prefix + line += word + return s, line + + +def _formatArray(a, format_function, line_width, next_line_prefix, + separator, edge_items, summary_insert, legacy): + """formatArray is designed for two modes of operation: + + 1. Full output + + 2. Summarized output + + """ + def recurser(index, hanging_indent, curr_width): + """ + By using this local function, we don't need to recurse with all the + arguments. Since this function is not created recursively, the cost is + not significant + """ + axis = len(index) + axes_left = a.ndim - axis + + if axes_left == 0: + return format_function(a[index]) + + # when recursing, add a space to align with the [ added, and reduce the + # length of the line by 1 + next_hanging_indent = hanging_indent + ' ' + if legacy == '1.13': + next_width = curr_width + else: + next_width = curr_width - len(']') + + a_len = a.shape[axis] + show_summary = summary_insert and 2*edge_items < a_len + if show_summary: + leading_items = edge_items + trailing_items = edge_items + else: + leading_items = 0 + trailing_items = a_len + + # stringify the array with the hanging indent on the first line too + s = '' + + # last axis (rows) - wrap elements if they would not fit on one line + if axes_left == 1: + # the length up until the beginning of the separator / bracket + if legacy == '1.13': + elem_width = curr_width - len(separator.rstrip()) + else: + elem_width = curr_width - max(len(separator.rstrip()), len(']')) + + line = hanging_indent + for i in range(leading_items): + word = recurser(index + (i,), next_hanging_indent, next_width) + s, line = _extendLine( + s, line, word, elem_width, hanging_indent, legacy) + line += separator + + if show_summary: + s, line = _extendLine( + s, line, summary_insert, elem_width, hanging_indent, legacy) + if legacy == '1.13': + line += ", " + else: + line += separator + + for i in range(trailing_items, 1, -1): + word = recurser(index + (-i,), next_hanging_indent, next_width) + s, line = _extendLine( + s, line, word, elem_width, hanging_indent, legacy) + line += separator + + if legacy == '1.13': + # width of the seperator is not considered on 1.13 + elem_width = curr_width + word = recurser(index + (-1,), next_hanging_indent, next_width) + s, line = _extendLine( + s, line, word, elem_width, hanging_indent, legacy) + + s += line + + # other axes - insert newlines between rows + else: + s = '' + line_sep = separator.rstrip() + '\n'*(axes_left - 1) + + for i in range(leading_items): + nested = recurser(index + (i,), next_hanging_indent, next_width) + s += hanging_indent + nested + line_sep + + if show_summary: + if legacy == '1.13': + # trailing space, fixed nbr of newlines, and fixed separator + s += hanging_indent + summary_insert + ", \n" + else: + s += hanging_indent + summary_insert + line_sep + + for i in range(trailing_items, 1, -1): + nested = recurser(index + (-i,), next_hanging_indent, + next_width) + s += hanging_indent + nested + line_sep + + nested = recurser(index + (-1,), next_hanging_indent, next_width) + s += hanging_indent + nested + + # remove the hanging indent, and wrap in [] + s = '[' + s[len(hanging_indent):] + ']' + return s + + try: + # invoke the recursive part with an initial index and prefix + return recurser(index=(), + hanging_indent=next_line_prefix, + curr_width=line_width) + finally: + # recursive closures have a cyclic reference to themselves, which + # requires gc to collect (gh-10620). To avoid this problem, for + # performance and PyPy friendliness, we break the cycle: + recurser = None + +def _none_or_positive_arg(x, name): + if x is None: + return -1 + if x < 0: + raise ValueError("{} must be >= 0".format(name)) + return x + +class FloatingFormat(object): + """ Formatter for subtypes of np.floating """ + def __init__(self, data, precision, floatmode, suppress_small, sign=False, + **kwarg): + # for backcompatibility, accept bools + if isinstance(sign, bool): + sign = '+' if sign else '-' + + self._legacy = kwarg.get('legacy', False) + if self._legacy == '1.13': + # when not 0d, legacy does not support '-' + if data.shape != () and sign == '-': + sign = ' ' + + self.floatmode = floatmode + if floatmode == 'unique': + self.precision = None + else: + self.precision = precision + + self.precision = _none_or_positive_arg(self.precision, 'precision') + + self.suppress_small = suppress_small + self.sign = sign + self.exp_format = False + self.large_exponent = False + + self.fillFormat(data) + + def fillFormat(self, data): + # only the finite values are used to compute the number of digits + finite_vals = data[isfinite(data)] + + # choose exponential mode based on the non-zero finite values: + abs_non_zero = absolute(finite_vals[finite_vals != 0]) + if len(abs_non_zero) != 0: + max_val = np.max(abs_non_zero) + min_val = np.min(abs_non_zero) + with errstate(over='ignore'): # division can overflow + if max_val >= 1.e8 or (not self.suppress_small and + (min_val < 0.0001 or max_val/min_val > 1000.)): + self.exp_format = True + + # do a first pass of printing all the numbers, to determine sizes + if len(finite_vals) == 0: + self.pad_left = 0 + self.pad_right = 0 + self.trim = '.' + self.exp_size = -1 + self.unique = True + elif self.exp_format: + trim, unique = '.', True + if self.floatmode == 'fixed' or self._legacy == '1.13': + trim, unique = 'k', False + strs = (dragon4_scientific(x, precision=self.precision, + unique=unique, trim=trim, sign=self.sign == '+') + for x in finite_vals) + frac_strs, _, exp_strs = zip(*(s.partition('e') for s in strs)) + int_part, frac_part = zip(*(s.split('.') for s in frac_strs)) + self.exp_size = max(len(s) for s in exp_strs) - 1 + + self.trim = 'k' + self.precision = max(len(s) for s in frac_part) + + # for back-compat with np 1.13, use 2 spaces & sign and full prec + if self._legacy == '1.13': + self.pad_left = 3 + else: + # this should be only 1 or 2. Can be calculated from sign. + self.pad_left = max(len(s) for s in int_part) + # pad_right is only needed for nan length calculation + self.pad_right = self.exp_size + 2 + self.precision + + self.unique = False + else: + # first pass printing to determine sizes + trim, unique = '.', True + if self.floatmode == 'fixed': + trim, unique = 'k', False + strs = (dragon4_positional(x, precision=self.precision, + fractional=True, + unique=unique, trim=trim, + sign=self.sign == '+') + for x in finite_vals) + int_part, frac_part = zip(*(s.split('.') for s in strs)) + if self._legacy == '1.13': + self.pad_left = 1 + max(len(s.lstrip('-+')) for s in int_part) + else: + self.pad_left = max(len(s) for s in int_part) + self.pad_right = max(len(s) for s in frac_part) + self.exp_size = -1 + + if self.floatmode in ['fixed', 'maxprec_equal']: + self.precision = self.pad_right + self.unique = False + self.trim = 'k' + else: + self.unique = True + self.trim = '.' + + if self._legacy != '1.13': + # account for sign = ' ' by adding one to pad_left + if self.sign == ' ' and not any(np.signbit(finite_vals)): + self.pad_left += 1 + + # if there are non-finite values, may need to increase pad_left + if data.size != finite_vals.size: + neginf = self.sign != '-' or any(data[isinf(data)] < 0) + nanlen = len(_format_options['nanstr']) + inflen = len(_format_options['infstr']) + neginf + offset = self.pad_right + 1 # +1 for decimal pt + self.pad_left = max(self.pad_left, nanlen - offset, inflen - offset) + + def __call__(self, x): + if not np.isfinite(x): + with errstate(invalid='ignore'): + if np.isnan(x): + sign = '+' if self.sign == '+' else '' + ret = sign + _format_options['nanstr'] + else: # isinf + sign = '-' if x < 0 else '+' if self.sign == '+' else '' + ret = sign + _format_options['infstr'] + return ' '*(self.pad_left + self.pad_right + 1 - len(ret)) + ret + + if self.exp_format: + return dragon4_scientific(x, + precision=self.precision, + unique=self.unique, + trim=self.trim, + sign=self.sign == '+', + pad_left=self.pad_left, + exp_digits=self.exp_size) + else: + return dragon4_positional(x, + precision=self.precision, + unique=self.unique, + fractional=True, + trim=self.trim, + sign=self.sign == '+', + pad_left=self.pad_left, + pad_right=self.pad_right) + +# for back-compatibility, we keep the classes for each float type too +class FloatFormat(FloatingFormat): + def __init__(self, *args, **kwargs): + warnings.warn("FloatFormat has been replaced by FloatingFormat", + DeprecationWarning, stacklevel=2) + super(FloatFormat, self).__init__(*args, **kwargs) + + +class LongFloatFormat(FloatingFormat): + def __init__(self, *args, **kwargs): + warnings.warn("LongFloatFormat has been replaced by FloatingFormat", + DeprecationWarning, stacklevel=2) + super(LongFloatFormat, self).__init__(*args, **kwargs) + +def format_float_scientific(x, precision=None, unique=True, trim='k', + sign=False, pad_left=None, exp_digits=None): + """ + Format a floating-point scalar as a decimal string in scientific notation. + + Provides control over rounding, trimming and padding. Uses and assumes + IEEE unbiased rounding. Uses the "Dragon4" algorithm. + + Parameters + ---------- + x : python float or numpy floating scalar + Value to format. + precision : non-negative integer or None, optional + Maximum number of digits to print. May be None if `unique` is + `True`, but must be an integer if unique is `False`. + unique : boolean, optional + If `True`, use a digit-generation strategy which gives the shortest + representation which uniquely identifies the floating-point number from + other values of the same type, by judicious rounding. If `precision` + was omitted, print all necessary digits, otherwise digit generation is + cut off after `precision` digits and the remaining value is rounded. + If `False`, digits are generated as if printing an infinite-precision + value and stopping after `precision` digits, rounding the remaining + value. + trim : one of 'k', '.', '0', '-', optional + Controls post-processing trimming of trailing digits, as follows: + k : keep trailing zeros, keep decimal point (no trimming) + . : trim all trailing zeros, leave decimal point + 0 : trim all but the zero before the decimal point. Insert the + zero if it is missing. + - : trim trailing zeros and any trailing decimal point + sign : boolean, optional + Whether to show the sign for positive values. + pad_left : non-negative integer, optional + Pad the left side of the string with whitespace until at least that + many characters are to the left of the decimal point. + exp_digits : non-negative integer, optional + Pad the exponent with zeros until it contains at least this many digits. + If omitted, the exponent will be at least 2 digits. + + Returns + ------- + rep : string + The string representation of the floating point value + + See Also + -------- + format_float_positional + + Examples + -------- + >>> np.format_float_scientific(np.float32(np.pi)) + '3.1415927e+00' + >>> s = np.float32(1.23e24) + >>> np.format_float_scientific(s, unique=False, precision=15) + '1.230000071797338e+24' + >>> np.format_float_scientific(s, exp_digits=4) + '1.23e+0024' + """ + precision = _none_or_positive_arg(precision, 'precision') + pad_left = _none_or_positive_arg(pad_left, 'pad_left') + exp_digits = _none_or_positive_arg(exp_digits, 'exp_digits') + return dragon4_scientific(x, precision=precision, unique=unique, + trim=trim, sign=sign, pad_left=pad_left, + exp_digits=exp_digits) + +def format_float_positional(x, precision=None, unique=True, + fractional=True, trim='k', sign=False, + pad_left=None, pad_right=None): + """ + Format a floating-point scalar as a decimal string in positional notation. + + Provides control over rounding, trimming and padding. Uses and assumes + IEEE unbiased rounding. Uses the "Dragon4" algorithm. + + Parameters + ---------- + x : python float or numpy floating scalar + Value to format. + precision : non-negative integer or None, optional + Maximum number of digits to print. May be None if `unique` is + `True`, but must be an integer if unique is `False`. + unique : boolean, optional + If `True`, use a digit-generation strategy which gives the shortest + representation which uniquely identifies the floating-point number from + other values of the same type, by judicious rounding. If `precision` + was omitted, print out all necessary digits, otherwise digit generation + is cut off after `precision` digits and the remaining value is rounded. + If `False`, digits are generated as if printing an infinite-precision + value and stopping after `precision` digits, rounding the remaining + value. + fractional : boolean, optional + If `True`, the cutoff of `precision` digits refers to the total number + of digits after the decimal point, including leading zeros. + If `False`, `precision` refers to the total number of significant + digits, before or after the decimal point, ignoring leading zeros. + trim : one of 'k', '.', '0', '-', optional + Controls post-processing trimming of trailing digits, as follows: + k : keep trailing zeros, keep decimal point (no trimming) + . : trim all trailing zeros, leave decimal point + 0 : trim all but the zero before the decimal point. Insert the + zero if it is missing. + - : trim trailing zeros and any trailing decimal point + sign : boolean, optional + Whether to show the sign for positive values. + pad_left : non-negative integer, optional + Pad the left side of the string with whitespace until at least that + many characters are to the left of the decimal point. + pad_right : non-negative integer, optional + Pad the right side of the string with whitespace until at least that + many characters are to the right of the decimal point. + + Returns + ------- + rep : string + The string representation of the floating point value + + See Also + -------- + format_float_scientific + + Examples + -------- + >>> np.format_float_scientific(np.float32(np.pi)) + '3.1415927' + >>> np.format_float_positional(np.float16(np.pi)) + '3.14' + >>> np.format_float_positional(np.float16(0.3)) + '0.3' + >>> np.format_float_positional(np.float16(0.3), unique=False, precision=10) + '0.3000488281' + """ + precision = _none_or_positive_arg(precision, 'precision') + pad_left = _none_or_positive_arg(pad_left, 'pad_left') + pad_right = _none_or_positive_arg(pad_right, 'pad_right') + return dragon4_positional(x, precision=precision, unique=unique, + fractional=fractional, trim=trim, + sign=sign, pad_left=pad_left, + pad_right=pad_right) + + +class IntegerFormat(object): + def __init__(self, data): + if data.size > 0: + max_str_len = max(len(str(np.max(data))), + len(str(np.min(data)))) + else: + max_str_len = 0 + self.format = '%{}d'.format(max_str_len) + + def __call__(self, x): + return self.format % x + + +class BoolFormat(object): + def __init__(self, data, **kwargs): + # add an extra space so " True" and "False" have the same length and + # array elements align nicely when printed, except in 0d arrays + self.truestr = ' True' if data.shape != () else 'True' + + def __call__(self, x): + return self.truestr if x else "False" + + +class ComplexFloatingFormat(object): + """ Formatter for subtypes of np.complexfloating """ + def __init__(self, x, precision, floatmode, suppress_small, + sign=False, **kwarg): + # for backcompatibility, accept bools + if isinstance(sign, bool): + sign = '+' if sign else '-' + + floatmode_real = floatmode_imag = floatmode + if kwarg.get('legacy', False) == '1.13': + floatmode_real = 'maxprec_equal' + floatmode_imag = 'maxprec' + + self.real_format = FloatingFormat(x.real, precision, floatmode_real, + suppress_small, sign=sign, **kwarg) + self.imag_format = FloatingFormat(x.imag, precision, floatmode_imag, + suppress_small, sign='+', **kwarg) + + def __call__(self, x): + r = self.real_format(x.real) + i = self.imag_format(x.imag) + + # add the 'j' before the terminal whitespace in i + sp = len(i.rstrip()) + i = i[:sp] + 'j' + i[sp:] + + return r + i + +# for back-compatibility, we keep the classes for each complex type too +class ComplexFormat(ComplexFloatingFormat): + def __init__(self, *args, **kwargs): + warnings.warn( + "ComplexFormat has been replaced by ComplexFloatingFormat", + DeprecationWarning, stacklevel=2) + super(ComplexFormat, self).__init__(*args, **kwargs) + +class LongComplexFormat(ComplexFloatingFormat): + def __init__(self, *args, **kwargs): + warnings.warn( + "LongComplexFormat has been replaced by ComplexFloatingFormat", + DeprecationWarning, stacklevel=2) + super(LongComplexFormat, self).__init__(*args, **kwargs) + + +class _TimelikeFormat(object): + def __init__(self, data): + non_nat = data[~isnat(data)] + if len(non_nat) > 0: + # Max str length of non-NaT elements + max_str_len = max(len(self._format_non_nat(np.max(non_nat))), + len(self._format_non_nat(np.min(non_nat)))) + else: + max_str_len = 0 + if len(non_nat) < data.size: + # data contains a NaT + max_str_len = max(max_str_len, 5) + self._format = '%{}s'.format(max_str_len) + self._nat = "'NaT'".rjust(max_str_len) + + def _format_non_nat(self, x): + # override in subclass + raise NotImplementedError + + def __call__(self, x): + if isnat(x): + return self._nat + else: + return self._format % self._format_non_nat(x) + + +class DatetimeFormat(_TimelikeFormat): + def __init__(self, x, unit=None, timezone=None, casting='same_kind', + legacy=False): + # Get the unit from the dtype + if unit is None: + if x.dtype.kind == 'M': + unit = datetime_data(x.dtype)[0] + else: + unit = 's' + + if timezone is None: + timezone = 'naive' + self.timezone = timezone + self.unit = unit + self.casting = casting + self.legacy = legacy + + # must be called after the above are configured + super(DatetimeFormat, self).__init__(x) + + def __call__(self, x): + if self.legacy == '1.13': + return self._format_non_nat(x) + return super(DatetimeFormat, self).__call__(x) + + def _format_non_nat(self, x): + return "'%s'" % datetime_as_string(x, + unit=self.unit, + timezone=self.timezone, + casting=self.casting) + + +class TimedeltaFormat(_TimelikeFormat): + def _format_non_nat(self, x): + return str(x.astype('i8')) + + +class SubArrayFormat(object): + def __init__(self, format_function): + self.format_function = format_function + + def __call__(self, arr): + if arr.ndim <= 1: + return "[" + ", ".join(self.format_function(a) for a in arr) + "]" + return "[" + ", ".join(self.__call__(a) for a in arr) + "]" + + +class StructuredVoidFormat(object): + """ + Formatter for structured np.void objects. + + This does not work on structured alias types like np.dtype(('i4', 'i2,i2')), + as alias scalars lose their field information, and the implementation + relies upon np.void.__getitem__. + """ + def __init__(self, format_functions): + self.format_functions = format_functions + + @classmethod + def from_data(cls, data, **options): + """ + This is a second way to initialize StructuredVoidFormat, using the raw data + as input. Added to avoid changing the signature of __init__. + """ + format_functions = [] + for field_name in data.dtype.names: + format_function = _get_format_function(data[field_name], **options) + if data.dtype[field_name].shape != (): + format_function = SubArrayFormat(format_function) + format_functions.append(format_function) + return cls(format_functions) + + def __call__(self, x): + str_fields = [ + format_function(field) + for field, format_function in zip(x, self.format_functions) + ] + if len(str_fields) == 1: + return "({},)".format(str_fields[0]) + else: + return "({})".format(", ".join(str_fields)) + + +# for backwards compatibility +class StructureFormat(StructuredVoidFormat): + def __init__(self, *args, **kwargs): + # NumPy 1.14, 2018-02-14 + warnings.warn( + "StructureFormat has been replaced by StructuredVoidFormat", + DeprecationWarning, stacklevel=2) + super(StructureFormat, self).__init__(*args, **kwargs) + + +def _void_scalar_repr(x): + """ + Implements the repr for structured-void scalars. It is called from the + scalartypes.c.src code, and is placed here because it uses the elementwise + formatters defined above. + """ + return StructuredVoidFormat.from_data(array(x), **_format_options)(x) + + +_typelessdata = [int_, float_, complex_, bool_] +if issubclass(intc, int): + _typelessdata.append(intc) +if issubclass(longlong, int): + _typelessdata.append(longlong) + + +def dtype_is_implied(dtype): + """ + Determine if the given dtype is implied by the representation of its values. + + Parameters + ---------- + dtype : dtype + Data type + + Returns + ------- + implied : bool + True if the dtype is implied by the representation of its values. + + Examples + -------- + >>> np.core.arrayprint.dtype_is_implied(int) + True + >>> np.array([1, 2, 3], int) + array([1, 2, 3]) + >>> np.core.arrayprint.dtype_is_implied(np.int8) + False + >>> np.array([1, 2, 3], np.int8) + array([1, 2, 3], dtype=np.int8) + """ + dtype = np.dtype(dtype) + if _format_options['legacy'] == '1.13' and dtype.type == bool_: + return False + + # not just void types can be structured, and names are not part of the repr + if dtype.names is not None: + return False + + return dtype.type in _typelessdata + + +def dtype_short_repr(dtype): + """ + Convert a dtype to a short form which evaluates to the same dtype. + + The intent is roughly that the following holds + + >>> from numpy import * + >>> assert eval(dtype_short_repr(dt)) == dt + """ + if dtype.names is not None: + # structured dtypes give a list or tuple repr + return str(dtype) + elif issubclass(dtype.type, flexible): + # handle these separately so they don't give garbage like str256 + return "'%s'" % str(dtype) + + typename = dtype.name + # quote typenames which can't be represented as python variable names + if typename and not (typename[0].isalpha() and typename.isalnum()): + typename = repr(typename) + + return typename + + +def array_repr(arr, max_line_width=None, precision=None, suppress_small=None): + """ + Return the string representation of an array. + + Parameters + ---------- + arr : ndarray + Input array. + max_line_width : int, optional + The maximum number of columns the string should span. Newline + characters split the string appropriately after array elements. + precision : int, optional + Floating point precision. Default is the current printing precision + (usually 8), which can be altered using `set_printoptions`. + suppress_small : bool, optional + Represent very small numbers as zero, default is False. Very small + is defined by `precision`, if the precision is 8 then + numbers smaller than 5e-9 are represented as zero. + + Returns + ------- + string : str + The string representation of an array. + + See Also + -------- + array_str, array2string, set_printoptions + + Examples + -------- + >>> np.array_repr(np.array([1,2])) + 'array([1, 2])' + >>> np.array_repr(np.ma.array([0.])) + 'MaskedArray([ 0.])' + >>> np.array_repr(np.array([], np.int32)) + 'array([], dtype=int32)' + + >>> x = np.array([1e-6, 4e-7, 2, 3]) + >>> np.array_repr(x, precision=6, suppress_small=True) + 'array([ 0.000001, 0. , 2. , 3. ])' + + """ + if max_line_width is None: + max_line_width = _format_options['linewidth'] + + if type(arr) is not ndarray: + class_name = type(arr).__name__ + else: + class_name = "array" + + skipdtype = dtype_is_implied(arr.dtype) and arr.size > 0 + + prefix = class_name + "(" + suffix = ")" if skipdtype else "," + + if (_format_options['legacy'] == '1.13' and + arr.shape == () and not arr.dtype.names): + lst = repr(arr.item()) + elif arr.size > 0 or arr.shape == (0,): + lst = array2string(arr, max_line_width, precision, suppress_small, + ', ', prefix, suffix=suffix) + else: # show zero-length shape unless it is (0,) + lst = "[], shape=%s" % (repr(arr.shape),) + + arr_str = prefix + lst + suffix + + if skipdtype: + return arr_str + + dtype_str = "dtype={})".format(dtype_short_repr(arr.dtype)) + + # compute whether we should put dtype on a new line: Do so if adding the + # dtype would extend the last line past max_line_width. + # Note: This line gives the correct result even when rfind returns -1. + last_line_len = len(arr_str) - (arr_str.rfind('\n') + 1) + spacer = " " + if _format_options['legacy'] == '1.13': + if issubclass(arr.dtype.type, flexible): + spacer = '\n' + ' '*len(class_name + "(") + elif last_line_len + len(dtype_str) + 1 > max_line_width: + spacer = '\n' + ' '*len(class_name + "(") + + return arr_str + spacer + dtype_str + +_guarded_str = _recursive_guard()(str) + +def array_str(a, max_line_width=None, precision=None, suppress_small=None): + """ + Return a string representation of the data in an array. + + The data in the array is returned as a single string. This function is + similar to `array_repr`, the difference being that `array_repr` also + returns information on the kind of array and its data type. + + Parameters + ---------- + a : ndarray + Input array. + max_line_width : int, optional + Inserts newlines if text is longer than `max_line_width`. The + default is, indirectly, 75. + precision : int, optional + Floating point precision. Default is the current printing precision + (usually 8), which can be altered using `set_printoptions`. + suppress_small : bool, optional + Represent numbers "very close" to zero as zero; default is False. + Very close is defined by precision: if the precision is 8, e.g., + numbers smaller (in absolute value) than 5e-9 are represented as + zero. + + See Also + -------- + array2string, array_repr, set_printoptions + + Examples + -------- + >>> np.array_str(np.arange(3)) + '[0 1 2]' + + """ + if (_format_options['legacy'] == '1.13' and + a.shape == () and not a.dtype.names): + return str(a.item()) + + # the str of 0d arrays is a special case: It should appear like a scalar, + # so floats are not truncated by `precision`, and strings are not wrapped + # in quotes. So we return the str of the scalar value. + if a.shape == (): + # obtain a scalar and call str on it, avoiding problems for subclasses + # for which indexing with () returns a 0d instead of a scalar by using + # ndarray's getindex. Also guard against recursive 0d object arrays. + return _guarded_str(np.ndarray.__getitem__(a, ())) + + return array2string(a, max_line_width, precision, suppress_small, ' ', "") + +def set_string_function(f, repr=True): + """ + Set a Python function to be used when pretty printing arrays. + + Parameters + ---------- + f : function or None + Function to be used to pretty print arrays. The function should expect + a single array argument and return a string of the representation of + the array. If None, the function is reset to the default NumPy function + to print arrays. + repr : bool, optional + If True (default), the function for pretty printing (``__repr__``) + is set, if False the function that returns the default string + representation (``__str__``) is set. + + See Also + -------- + set_printoptions, get_printoptions + + Examples + -------- + >>> def pprint(arr): + ... return 'HA! - What are you going to do now?' + ... + >>> np.set_string_function(pprint) + >>> a = np.arange(10) + >>> a + HA! - What are you going to do now? + >>> print(a) + [0 1 2 3 4 5 6 7 8 9] + + We can reset the function to the default: + + >>> np.set_string_function(None) + >>> a + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + + `repr` affects either pretty printing or normal string representation. + Note that ``__repr__`` is still affected by setting ``__str__`` + because the width of each array element in the returned string becomes + equal to the length of the result of ``__str__()``. + + >>> x = np.arange(4) + >>> np.set_string_function(lambda x:'random', repr=False) + >>> x.__str__() + 'random' + >>> x.__repr__() + 'array([ 0, 1, 2, 3])' + + """ + if f is None: + if repr: + return multiarray.set_string_function(array_repr, 1) + else: + return multiarray.set_string_function(array_str, 0) + else: + return multiarray.set_string_function(f, repr) + +set_string_function(array_str, 0) +set_string_function(array_repr, 1) diff --git a/numpy/core/code_generators/__init__.py b/numpy/core/code_generators/__init__.py new file mode 100644 index 0000000..1d0f69b --- /dev/null +++ b/numpy/core/code_generators/__init__.py @@ -0,0 +1 @@ +from __future__ import division, absolute_import, print_function diff --git a/numpy/core/code_generators/cversions.txt b/numpy/core/code_generators/cversions.txt new file mode 100644 index 0000000..68ac510 --- /dev/null +++ b/numpy/core/code_generators/cversions.txt @@ -0,0 +1,43 @@ +# Hash below were defined from numpy_api_order.txt and ufunc_api_order.txt +# When adding a new version here for a new minor release, also add the same +# version as NPY_x_y_API_VERSION in numpyconfig.h +0x00000001 = 603580d224763e58c5e7147f804dc0f5 +0x00000002 = 8ecb29306758515ae69749c803a75da1 +0x00000003 = bf22c0d05b31625d2a7015988d61ce5a + +# Starting from here, the hash is defined from numpy_api.full_api dict +# version 4 added neighborhood iterators and PyArray_Correlate2 +0x00000004 = 3d8940bf7b0d2a4e25be4338c14c3c85 +0x00000005 = 77e2e846db87f25d7cf99f9d812076f0 + +# Version 6 (NumPy 1.6) added new iterator, half float and casting functions, +# PyArray_CountNonzero, PyArray_NewLikeArray and PyArray_MatrixProduct2. +0x00000006 = e61d5dc51fa1c6459328266e215d6987 + +# Version 7 (NumPy 1.7) improved datetime64, misc utilities. +0x00000007 = e396ba3912dcf052eaee1b0b203a7724 + +# Version 8 Added interface to MapIterObject +0x00000008 = 17321775fc884de0b1eda478cd61c74b + +# Version 9 (NumPy 1.8) Added interface for partition functions, +# PyArray_NEW_ZEROED, commented out as the hash changed in +# NumPy 1.9.0 due to annotation. +#0x00000009 = 327bd114df09c2eb7a0bcc6901e2a3ed + +# Version 9 (NumPy 1.9) Added function annotations. +# The interface has not changed, but the hash is different due to +# the annotations, so keep the previous version number. +0x00000009 = 982c4ebb6e7e4c194bf46b1535b4ef1b + +# Version 10 (NumPy 1.10) Added PyArray_CheckAnyScalarExact +# Version 10 (NumPy 1.11) No change. +# Version 10 (NumPy 1.12) No change. +0x0000000a = 9b8bce614655d3eb02acddcb508203cb + +# Version 11 (NumPy 1.13) Added PyArray_MapIterArrayCopyIfOverlap +0x0000000b = edb1ba83730c650fd9bc5772a919cda7 + +# Version 12 (NumPy 1.14) Added PyArray_ResolveWritebackIfCopy, +# PyArray_SetWritebackIfCopyBase and deprecated PyArray_SetUpdateIfCopyBase. +0x0000000c = a1bc756c5782853ec2e3616cf66869d8 diff --git a/numpy/core/code_generators/genapi.py b/numpy/core/code_generators/genapi.py new file mode 100644 index 0000000..42c564a --- /dev/null +++ b/numpy/core/code_generators/genapi.py @@ -0,0 +1,516 @@ +""" +Get API information encoded in C files. + +See ``find_function`` for how functions should be formatted, and +``read_order`` for how the order of the functions should be +specified. + +""" +from __future__ import division, absolute_import, print_function + +import sys, os, re +import hashlib + +import textwrap + +from os.path import join + +__docformat__ = 'restructuredtext' + +# The files under src/ that are scanned for API functions +API_FILES = [join('multiarray', 'alloc.c'), + join('multiarray', 'array_assign_array.c'), + join('multiarray', 'array_assign_scalar.c'), + join('multiarray', 'arrayobject.c'), + join('multiarray', 'arraytypes.c.src'), + join('multiarray', 'buffer.c'), + join('multiarray', 'calculation.c'), + join('multiarray', 'conversion_utils.c'), + join('multiarray', 'convert.c'), + join('multiarray', 'convert_datatype.c'), + join('multiarray', 'ctors.c'), + join('multiarray', 'datetime.c'), + join('multiarray', 'datetime_busday.c'), + join('multiarray', 'datetime_busdaycal.c'), + join('multiarray', 'datetime_strings.c'), + join('multiarray', 'descriptor.c'), + join('multiarray', 'einsum.c.src'), + join('multiarray', 'flagsobject.c'), + join('multiarray', 'getset.c'), + join('multiarray', 'item_selection.c'), + join('multiarray', 'iterators.c'), + join('multiarray', 'mapping.c'), + join('multiarray', 'methods.c'), + join('multiarray', 'multiarraymodule.c'), + join('multiarray', 'nditer_api.c'), + join('multiarray', 'nditer_constr.c'), + join('multiarray', 'nditer_pywrap.c'), + join('multiarray', 'nditer_templ.c.src'), + join('multiarray', 'number.c'), + join('multiarray', 'refcount.c'), + join('multiarray', 'scalartypes.c.src'), + join('multiarray', 'scalarapi.c'), + join('multiarray', 'sequence.c'), + join('multiarray', 'shape.c'), + join('multiarray', 'strfuncs.c'), + join('multiarray', 'usertypes.c'), + join('umath', 'loops.c.src'), + join('umath', 'ufunc_object.c'), + join('umath', 'ufunc_type_resolution.c'), + join('umath', 'reduction.c'), + ] +THIS_DIR = os.path.dirname(__file__) +API_FILES = [os.path.join(THIS_DIR, '..', 'src', a) for a in API_FILES] + +def file_in_this_dir(filename): + return os.path.join(THIS_DIR, filename) + +def remove_whitespace(s): + return ''.join(s.split()) + +def _repl(str): + return str.replace('Bool', 'npy_bool') + + +class StealRef(object): + def __init__(self, arg): + self.arg = arg # counting from 1 + + def __str__(self): + try: + return ' '.join('NPY_STEALS_REF_TO_ARG(%d)' % x for x in self.arg) + except TypeError: + return 'NPY_STEALS_REF_TO_ARG(%d)' % self.arg + + +class NonNull(object): + def __init__(self, arg): + self.arg = arg # counting from 1 + + def __str__(self): + try: + return ' '.join('NPY_GCC_NONNULL(%d)' % x for x in self.arg) + except TypeError: + return 'NPY_GCC_NONNULL(%d)' % self.arg + + +class Function(object): + def __init__(self, name, return_type, args, doc=''): + self.name = name + self.return_type = _repl(return_type) + self.args = args + self.doc = doc + + def _format_arg(self, typename, name): + if typename.endswith('*'): + return typename + name + else: + return typename + ' ' + name + + def __str__(self): + argstr = ', '.join([self._format_arg(*a) for a in self.args]) + if self.doc: + doccomment = '/* %s */\n' % self.doc + else: + doccomment = '' + return '%s%s %s(%s)' % (doccomment, self.return_type, self.name, argstr) + + def to_ReST(self): + lines = ['::', '', ' ' + self.return_type] + argstr = ',\000'.join([self._format_arg(*a) for a in self.args]) + name = ' %s' % (self.name,) + s = textwrap.wrap('(%s)' % (argstr,), width=72, + initial_indent=name, + subsequent_indent=' ' * (len(name)+1), + break_long_words=False) + for l in s: + lines.append(l.replace('\000', ' ').rstrip()) + lines.append('') + if self.doc: + lines.append(textwrap.dedent(self.doc)) + return '\n'.join(lines) + + def api_hash(self): + m = hashlib.md5() + m.update(remove_whitespace(self.return_type)) + m.update('\000') + m.update(self.name) + m.update('\000') + for typename, name in self.args: + m.update(remove_whitespace(typename)) + m.update('\000') + return m.hexdigest()[:8] + +class ParseError(Exception): + def __init__(self, filename, lineno, msg): + self.filename = filename + self.lineno = lineno + self.msg = msg + + def __str__(self): + return '%s:%s:%s' % (self.filename, self.lineno, self.msg) + +def skip_brackets(s, lbrac, rbrac): + count = 0 + for i, c in enumerate(s): + if c == lbrac: + count += 1 + elif c == rbrac: + count -= 1 + if count == 0: + return i + raise ValueError("no match '%s' for '%s' (%r)" % (lbrac, rbrac, s)) + +def split_arguments(argstr): + arguments = [] + bracket_counts = {'(': 0, '[': 0} + current_argument = [] + state = 0 + i = 0 + def finish_arg(): + if current_argument: + argstr = ''.join(current_argument).strip() + m = re.match(r'(.*(\s+|[*]))(\w+)$', argstr) + if m: + typename = m.group(1).strip() + name = m.group(3) + else: + typename = argstr + name = '' + arguments.append((typename, name)) + del current_argument[:] + while i < len(argstr): + c = argstr[i] + if c == ',': + finish_arg() + elif c == '(': + p = skip_brackets(argstr[i:], '(', ')') + current_argument += argstr[i:i+p] + i += p-1 + else: + current_argument += c + i += 1 + finish_arg() + return arguments + + +def find_functions(filename, tag='API'): + """ + Scan the file, looking for tagged functions. + + Assuming ``tag=='API'``, a tagged function looks like:: + + /*API*/ + static returntype* + function_name(argtype1 arg1, argtype2 arg2) + { + } + + where the return type must be on a separate line, the function + name must start the line, and the opening ``{`` must start the line. + + An optional documentation comment in ReST format may follow the tag, + as in:: + + /*API + This function does foo... + */ + """ + fo = open(filename, 'r') + functions = [] + return_type = None + function_name = None + function_args = [] + doclist = [] + SCANNING, STATE_DOC, STATE_RETTYPE, STATE_NAME, STATE_ARGS = list(range(5)) + state = SCANNING + tagcomment = '/*' + tag + for lineno, line in enumerate(fo): + try: + line = line.strip() + if state == SCANNING: + if line.startswith(tagcomment): + if line.endswith('*/'): + state = STATE_RETTYPE + else: + state = STATE_DOC + elif state == STATE_DOC: + if line.startswith('*/'): + state = STATE_RETTYPE + else: + line = line.lstrip(' *') + doclist.append(line) + elif state == STATE_RETTYPE: + # first line of declaration with return type + m = re.match(r'NPY_NO_EXPORT\s+(.*)$', line) + if m: + line = m.group(1) + return_type = line + state = STATE_NAME + elif state == STATE_NAME: + # second line, with function name + m = re.match(r'(\w+)\s*\(', line) + if m: + function_name = m.group(1) + else: + raise ParseError(filename, lineno+1, + 'could not find function name') + function_args.append(line[m.end():]) + state = STATE_ARGS + elif state == STATE_ARGS: + if line.startswith('{'): + # finished + fargs_str = ' '.join(function_args).rstrip(' )') + fargs = split_arguments(fargs_str) + f = Function(function_name, return_type, fargs, + '\n'.join(doclist)) + functions.append(f) + return_type = None + function_name = None + function_args = [] + doclist = [] + state = SCANNING + else: + function_args.append(line) + except Exception: + print(filename, lineno + 1) + raise + fo.close() + return functions + +def should_rebuild(targets, source_files): + from distutils.dep_util import newer_group + for t in targets: + if not os.path.exists(t): + return True + sources = API_FILES + list(source_files) + [__file__] + if newer_group(sources, targets[0], missing='newer'): + return True + return False + +def write_file(filename, data): + """ + Write data to filename + Only write changed data to avoid updating timestamps unnecessarily + """ + if os.path.exists(filename): + with open(filename) as f: + if data == f.read(): + return + + with open(filename, 'w') as fid: + fid.write(data) + + +# Those *Api classes instances know how to output strings for the generated code +class TypeApi(object): + def __init__(self, name, index, ptr_cast, api_name): + self.index = index + self.name = name + self.ptr_cast = ptr_cast + self.api_name = api_name + + def define_from_array_api_string(self): + return "#define %s (*(%s *)%s[%d])" % (self.name, + self.ptr_cast, + self.api_name, + self.index) + + def array_api_define(self): + return " (void *) &%s" % self.name + + def internal_define(self): + astr = """\ +extern NPY_NO_EXPORT PyTypeObject %(type)s; +""" % {'type': self.name} + return astr + +class GlobalVarApi(object): + def __init__(self, name, index, type, api_name): + self.name = name + self.index = index + self.type = type + self.api_name = api_name + + def define_from_array_api_string(self): + return "#define %s (*(%s *)%s[%d])" % (self.name, + self.type, + self.api_name, + self.index) + + def array_api_define(self): + return " (%s *) &%s" % (self.type, self.name) + + def internal_define(self): + astr = """\ +extern NPY_NO_EXPORT %(type)s %(name)s; +""" % {'type': self.type, 'name': self.name} + return astr + +# Dummy to be able to consistently use *Api instances for all items in the +# array api +class BoolValuesApi(object): + def __init__(self, name, index, api_name): + self.name = name + self.index = index + self.type = 'PyBoolScalarObject' + self.api_name = api_name + + def define_from_array_api_string(self): + return "#define %s ((%s *)%s[%d])" % (self.name, + self.type, + self.api_name, + self.index) + + def array_api_define(self): + return " (void *) &%s" % self.name + + def internal_define(self): + astr = """\ +extern NPY_NO_EXPORT PyBoolScalarObject _PyArrayScalar_BoolValues[2]; +""" + return astr + +class FunctionApi(object): + def __init__(self, name, index, annotations, return_type, args, api_name): + self.name = name + self.index = index + self.annotations = annotations + self.return_type = return_type + self.args = args + self.api_name = api_name + + def _argtypes_string(self): + if not self.args: + return 'void' + argstr = ', '.join([_repl(a[0]) for a in self.args]) + return argstr + + def define_from_array_api_string(self): + define = """\ +#define %s \\\n (*(%s (*)(%s)) \\ + %s[%d])""" % (self.name, + self.return_type, + self._argtypes_string(), + self.api_name, + self.index) + return define + + def array_api_define(self): + return " (void *) %s" % self.name + + def internal_define(self): + annstr = [] + for a in self.annotations: + annstr.append(str(a)) + annstr = ' '.join(annstr) + astr = """\ +NPY_NO_EXPORT %s %s %s \\\n (%s);""" % (annstr, self.return_type, + self.name, + self._argtypes_string()) + return astr + +def order_dict(d): + """Order dict by its values.""" + o = list(d.items()) + def _key(x): + return x[1] + (x[0],) + return sorted(o, key=_key) + +def merge_api_dicts(dicts): + ret = {} + for d in dicts: + for k, v in d.items(): + ret[k] = v + + return ret + +def check_api_dict(d): + """Check that an api dict is valid (does not use the same index twice).""" + # remove the extra value fields that aren't the index + index_d = {k: v[0] for k, v in d.items()} + + # We have if a same index is used twice: we 'revert' the dict so that index + # become keys. If the length is different, it means one index has been used + # at least twice + revert_dict = {v: k for k, v in index_d.items()} + if not len(revert_dict) == len(index_d): + # We compute a dict index -> list of associated items + doubled = {} + for name, index in index_d.items(): + try: + doubled[index].append(name) + except KeyError: + doubled[index] = [name] + fmt = "Same index has been used twice in api definition: {}" + val = ''.join( + '\n\tindex {} -> {}'.format(index, names) + for index, names in doubled.items() if len(names) != 1 + ) + raise ValueError(fmt.format(val)) + + # No 'hole' in the indexes may be allowed, and it must starts at 0 + indexes = set(index_d.values()) + expected = set(range(len(indexes))) + if indexes != expected: + diff = expected.symmetric_difference(indexes) + msg = "There are some holes in the API indexing: " \ + "(symmetric diff is %s)" % diff + raise ValueError(msg) + +def get_api_functions(tagname, api_dict): + """Parse source files to get functions tagged by the given tag.""" + functions = [] + for f in API_FILES: + functions.extend(find_functions(f, tagname)) + dfunctions = [] + for func in functions: + o = api_dict[func.name][0] + dfunctions.append( (o, func) ) + dfunctions.sort() + return [a[1] for a in dfunctions] + +def fullapi_hash(api_dicts): + """Given a list of api dicts defining the numpy C API, compute a checksum + of the list of items in the API (as a string).""" + a = [] + for d in api_dicts: + for name, data in order_dict(d): + a.extend(name) + a.extend(','.join(map(str, data))) + + return hashlib.md5(''.join(a).encode('ascii')).hexdigest() + +# To parse strings like 'hex = checksum' where hex is e.g. 0x1234567F and +# checksum a 128 bits md5 checksum (hex format as well) +VERRE = re.compile(r'(^0x[\da-f]{8})\s*=\s*([\da-f]{32})') + +def get_versions_hash(): + d = [] + + file = os.path.join(os.path.dirname(__file__), 'cversions.txt') + fid = open(file, 'r') + try: + for line in fid: + m = VERRE.match(line) + if m: + d.append((int(m.group(1), 16), m.group(2))) + finally: + fid.close() + + return dict(d) + +def main(): + tagname = sys.argv[1] + order_file = sys.argv[2] + functions = get_api_functions(tagname, order_file) + m = hashlib.md5(tagname) + for func in functions: + print(func) + ah = func.api_hash() + m.update(ah) + print(hex(int(ah, 16))) + print(hex(int(m.hexdigest()[:8], 16))) + +if __name__ == '__main__': + main() diff --git a/numpy/core/code_generators/generate_numpy_api.py b/numpy/core/code_generators/generate_numpy_api.py new file mode 100644 index 0000000..b4aeaa2 --- /dev/null +++ b/numpy/core/code_generators/generate_numpy_api.py @@ -0,0 +1,253 @@ +from __future__ import division, print_function + +import os +import genapi + +from genapi import \ + TypeApi, GlobalVarApi, FunctionApi, BoolValuesApi + +import numpy_api + +# use annotated api when running under cpychecker +h_template = r""" +#if defined(_MULTIARRAYMODULE) || defined(WITH_CPYCHECKER_STEALS_REFERENCE_TO_ARG_ATTRIBUTE) + +typedef struct { + PyObject_HEAD + npy_bool obval; +} PyBoolScalarObject; + +extern NPY_NO_EXPORT PyTypeObject PyArrayMapIter_Type; +extern NPY_NO_EXPORT PyTypeObject PyArrayNeighborhoodIter_Type; +extern NPY_NO_EXPORT PyBoolScalarObject _PyArrayScalar_BoolValues[2]; + +%s + +#else + +#if defined(PY_ARRAY_UNIQUE_SYMBOL) +#define PyArray_API PY_ARRAY_UNIQUE_SYMBOL +#endif + +#if defined(NO_IMPORT) || defined(NO_IMPORT_ARRAY) +extern void **PyArray_API; +#else +#if defined(PY_ARRAY_UNIQUE_SYMBOL) +void **PyArray_API; +#else +static void **PyArray_API=NULL; +#endif +#endif + +%s + +#if !defined(NO_IMPORT_ARRAY) && !defined(NO_IMPORT) +static int +_import_array(void) +{ + int st; + PyObject *numpy = PyImport_ImportModule("numpy.core.multiarray"); + PyObject *c_api = NULL; + + if (numpy == NULL) { + PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); + return -1; + } + c_api = PyObject_GetAttrString(numpy, "_ARRAY_API"); + Py_DECREF(numpy); + if (c_api == NULL) { + PyErr_SetString(PyExc_AttributeError, "_ARRAY_API not found"); + return -1; + } + +#if PY_VERSION_HEX >= 0x03000000 + if (!PyCapsule_CheckExact(c_api)) { + PyErr_SetString(PyExc_RuntimeError, "_ARRAY_API is not PyCapsule object"); + Py_DECREF(c_api); + return -1; + } + PyArray_API = (void **)PyCapsule_GetPointer(c_api, NULL); +#else + if (!PyCObject_Check(c_api)) { + PyErr_SetString(PyExc_RuntimeError, "_ARRAY_API is not PyCObject object"); + Py_DECREF(c_api); + return -1; + } + PyArray_API = (void **)PyCObject_AsVoidPtr(c_api); +#endif + Py_DECREF(c_api); + if (PyArray_API == NULL) { + PyErr_SetString(PyExc_RuntimeError, "_ARRAY_API is NULL pointer"); + return -1; + } + + /* Perform runtime check of C API version */ + if (NPY_VERSION != PyArray_GetNDArrayCVersion()) { + PyErr_Format(PyExc_RuntimeError, "module compiled against "\ + "ABI version 0x%%x but this version of numpy is 0x%%x", \ + (int) NPY_VERSION, (int) PyArray_GetNDArrayCVersion()); + return -1; + } + if (NPY_FEATURE_VERSION > PyArray_GetNDArrayCFeatureVersion()) { + PyErr_Format(PyExc_RuntimeError, "module compiled against "\ + "API version 0x%%x but this version of numpy is 0x%%x", \ + (int) NPY_FEATURE_VERSION, (int) PyArray_GetNDArrayCFeatureVersion()); + return -1; + } + + /* + * Perform runtime check of endianness and check it matches the one set by + * the headers (npy_endian.h) as a safeguard + */ + st = PyArray_GetEndianness(); + if (st == NPY_CPU_UNKNOWN_ENDIAN) { + PyErr_Format(PyExc_RuntimeError, "FATAL: module compiled as unknown endian"); + return -1; + } +#if NPY_BYTE_ORDER == NPY_BIG_ENDIAN + if (st != NPY_CPU_BIG) { + PyErr_Format(PyExc_RuntimeError, "FATAL: module compiled as "\ + "big endian, but detected different endianness at runtime"); + return -1; + } +#elif NPY_BYTE_ORDER == NPY_LITTLE_ENDIAN + if (st != NPY_CPU_LITTLE) { + PyErr_Format(PyExc_RuntimeError, "FATAL: module compiled as "\ + "little endian, but detected different endianness at runtime"); + return -1; + } +#endif + + return 0; +} + +#if PY_VERSION_HEX >= 0x03000000 +#define NUMPY_IMPORT_ARRAY_RETVAL NULL +#else +#define NUMPY_IMPORT_ARRAY_RETVAL +#endif + +#define import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); return NUMPY_IMPORT_ARRAY_RETVAL; } } + +#define import_array1(ret) {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); return ret; } } + +#define import_array2(msg, ret) {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, msg); return ret; } } + +#endif + +#endif +""" + + +c_template = r""" +/* These pointers will be stored in the C-object for use in other + extension modules +*/ + +void *PyArray_API[] = { +%s +}; +""" + +c_api_header = """ +=========== +NumPy C-API +=========== +""" + +def generate_api(output_dir, force=False): + basename = 'multiarray_api' + + h_file = os.path.join(output_dir, '__%s.h' % basename) + c_file = os.path.join(output_dir, '__%s.c' % basename) + d_file = os.path.join(output_dir, '%s.txt' % basename) + targets = (h_file, c_file, d_file) + + sources = numpy_api.multiarray_api + + if (not force and not genapi.should_rebuild(targets, [numpy_api.__file__, __file__])): + return targets + else: + do_generate_api(targets, sources) + + return targets + +def do_generate_api(targets, sources): + header_file = targets[0] + c_file = targets[1] + doc_file = targets[2] + + global_vars = sources[0] + scalar_bool_values = sources[1] + types_api = sources[2] + multiarray_funcs = sources[3] + + multiarray_api = sources[:] + + module_list = [] + extension_list = [] + init_list = [] + + # Check multiarray api indexes + multiarray_api_index = genapi.merge_api_dicts(multiarray_api) + genapi.check_api_dict(multiarray_api_index) + + numpyapi_list = genapi.get_api_functions('NUMPY_API', + multiarray_funcs) + ordered_funcs_api = genapi.order_dict(multiarray_funcs) + + # Create dict name -> *Api instance + api_name = 'PyArray_API' + multiarray_api_dict = {} + for f in numpyapi_list: + name = f.name + index = multiarray_funcs[name][0] + annotations = multiarray_funcs[name][1:] + multiarray_api_dict[f.name] = FunctionApi(f.name, index, annotations, + f.return_type, + f.args, api_name) + + for name, val in global_vars.items(): + index, type = val + multiarray_api_dict[name] = GlobalVarApi(name, index, type, api_name) + + for name, val in scalar_bool_values.items(): + index = val[0] + multiarray_api_dict[name] = BoolValuesApi(name, index, api_name) + + for name, val in types_api.items(): + index = val[0] + multiarray_api_dict[name] = TypeApi(name, index, 'PyTypeObject', api_name) + + if len(multiarray_api_dict) != len(multiarray_api_index): + keys_dict = set(multiarray_api_dict.keys()) + keys_index = set(multiarray_api_index.keys()) + raise AssertionError( + "Multiarray API size mismatch - " + "index has extra keys {}, dict has extra keys {}" + .format(keys_index - keys_dict, keys_dict - keys_index) + ) + + extension_list = [] + for name, index in genapi.order_dict(multiarray_api_index): + api_item = multiarray_api_dict[name] + extension_list.append(api_item.define_from_array_api_string()) + init_list.append(api_item.array_api_define()) + module_list.append(api_item.internal_define()) + + # Write to header + s = h_template % ('\n'.join(module_list), '\n'.join(extension_list)) + genapi.write_file(header_file, s) + + # Write to c-code + s = c_template % ',\n'.join(init_list) + genapi.write_file(c_file, s) + + # write to documentation + s = c_api_header + for func in numpyapi_list: + s += func.to_ReST() + s += '\n\n' + genapi.write_file(doc_file, s) + + return targets diff --git a/numpy/core/code_generators/generate_ufunc_api.py b/numpy/core/code_generators/generate_ufunc_api.py new file mode 100644 index 0000000..3bcf137 --- /dev/null +++ b/numpy/core/code_generators/generate_ufunc_api.py @@ -0,0 +1,210 @@ +from __future__ import division, print_function + +import os +import genapi + +import numpy_api + +from genapi import \ + TypeApi, GlobalVarApi, FunctionApi, BoolValuesApi + +h_template = r""" +#ifdef _UMATHMODULE + +extern NPY_NO_EXPORT PyTypeObject PyUFunc_Type; + +%s + +#else + +#if defined(PY_UFUNC_UNIQUE_SYMBOL) +#define PyUFunc_API PY_UFUNC_UNIQUE_SYMBOL +#endif + +#if defined(NO_IMPORT) || defined(NO_IMPORT_UFUNC) +extern void **PyUFunc_API; +#else +#if defined(PY_UFUNC_UNIQUE_SYMBOL) +void **PyUFunc_API; +#else +static void **PyUFunc_API=NULL; +#endif +#endif + +%s + +static NPY_INLINE int +_import_umath(void) +{ + PyObject *numpy = PyImport_ImportModule("numpy.core.umath"); + PyObject *c_api = NULL; + + if (numpy == NULL) { + PyErr_SetString(PyExc_ImportError, "numpy.core.umath failed to import"); + return -1; + } + c_api = PyObject_GetAttrString(numpy, "_UFUNC_API"); + Py_DECREF(numpy); + if (c_api == NULL) { + PyErr_SetString(PyExc_AttributeError, "_UFUNC_API not found"); + return -1; + } + +#if PY_VERSION_HEX >= 0x03000000 + if (!PyCapsule_CheckExact(c_api)) { + PyErr_SetString(PyExc_RuntimeError, "_UFUNC_API is not PyCapsule object"); + Py_DECREF(c_api); + return -1; + } + PyUFunc_API = (void **)PyCapsule_GetPointer(c_api, NULL); +#else + if (!PyCObject_Check(c_api)) { + PyErr_SetString(PyExc_RuntimeError, "_UFUNC_API is not PyCObject object"); + Py_DECREF(c_api); + return -1; + } + PyUFunc_API = (void **)PyCObject_AsVoidPtr(c_api); +#endif + Py_DECREF(c_api); + if (PyUFunc_API == NULL) { + PyErr_SetString(PyExc_RuntimeError, "_UFUNC_API is NULL pointer"); + return -1; + } + return 0; +} + +#if PY_VERSION_HEX >= 0x03000000 +#define NUMPY_IMPORT_UMATH_RETVAL NULL +#else +#define NUMPY_IMPORT_UMATH_RETVAL +#endif + +#define import_umath() \ + do {\ + UFUNC_NOFPE\ + if (_import_umath() < 0) {\ + PyErr_Print();\ + PyErr_SetString(PyExc_ImportError,\ + "numpy.core.umath failed to import");\ + return NUMPY_IMPORT_UMATH_RETVAL;\ + }\ + } while(0) + +#define import_umath1(ret) \ + do {\ + UFUNC_NOFPE\ + if (_import_umath() < 0) {\ + PyErr_Print();\ + PyErr_SetString(PyExc_ImportError,\ + "numpy.core.umath failed to import");\ + return ret;\ + }\ + } while(0) + +#define import_umath2(ret, msg) \ + do {\ + UFUNC_NOFPE\ + if (_import_umath() < 0) {\ + PyErr_Print();\ + PyErr_SetString(PyExc_ImportError, msg);\ + return ret;\ + }\ + } while(0) + +#define import_ufunc() \ + do {\ + UFUNC_NOFPE\ + if (_import_umath() < 0) {\ + PyErr_Print();\ + PyErr_SetString(PyExc_ImportError,\ + "numpy.core.umath failed to import");\ + }\ + } while(0) + +#endif +""" + +c_template = r""" +/* These pointers will be stored in the C-object for use in other + extension modules +*/ + +void *PyUFunc_API[] = { +%s +}; +""" + +def generate_api(output_dir, force=False): + basename = 'ufunc_api' + + h_file = os.path.join(output_dir, '__%s.h' % basename) + c_file = os.path.join(output_dir, '__%s.c' % basename) + d_file = os.path.join(output_dir, '%s.txt' % basename) + targets = (h_file, c_file, d_file) + + sources = ['ufunc_api_order.txt'] + + if (not force and not genapi.should_rebuild(targets, sources + [__file__])): + return targets + else: + do_generate_api(targets, sources) + + return targets + +def do_generate_api(targets, sources): + header_file = targets[0] + c_file = targets[1] + doc_file = targets[2] + + ufunc_api_index = genapi.merge_api_dicts(( + numpy_api.ufunc_funcs_api, + numpy_api.ufunc_types_api)) + genapi.check_api_dict(ufunc_api_index) + + ufunc_api_list = genapi.get_api_functions('UFUNC_API', numpy_api.ufunc_funcs_api) + + # Create dict name -> *Api instance + ufunc_api_dict = {} + api_name = 'PyUFunc_API' + for f in ufunc_api_list: + name = f.name + index = ufunc_api_index[name][0] + annotations = ufunc_api_index[name][1:] + ufunc_api_dict[name] = FunctionApi(f.name, index, annotations, + f.return_type, f.args, api_name) + + for name, val in numpy_api.ufunc_types_api.items(): + index = val[0] + ufunc_api_dict[name] = TypeApi(name, index, 'PyTypeObject', api_name) + + # set up object API + module_list = [] + extension_list = [] + init_list = [] + + for name, index in genapi.order_dict(ufunc_api_index): + api_item = ufunc_api_dict[name] + extension_list.append(api_item.define_from_array_api_string()) + init_list.append(api_item.array_api_define()) + module_list.append(api_item.internal_define()) + + # Write to header + s = h_template % ('\n'.join(module_list), '\n'.join(extension_list)) + genapi.write_file(header_file, s) + + # Write to c-code + s = c_template % ',\n'.join(init_list) + genapi.write_file(c_file, s) + + # Write to documentation + s = ''' +================= +NumPy Ufunc C-API +================= +''' + for func in ufunc_api_list: + s += func.to_ReST() + s += '\n\n' + genapi.write_file(doc_file, s) + + return targets diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py new file mode 100644 index 0000000..af058b4 --- /dev/null +++ b/numpy/core/code_generators/generate_umath.py @@ -0,0 +1,1068 @@ +from __future__ import division, print_function + +import os +import re +import struct +import sys +import textwrap + +sys.path.insert(0, os.path.dirname(__file__)) +import ufunc_docstrings as docstrings +sys.path.pop(0) + +Zero = "PyUFunc_Zero" +One = "PyUFunc_One" +None_ = "PyUFunc_None" +AllOnes = "PyUFunc_MinusOne" +ReorderableNone = "PyUFunc_ReorderableNone" + +# Sentinel value to specify using the full type description in the +# function name +class FullTypeDescr(object): + pass + +class FuncNameSuffix(object): + """Stores the suffix to append when generating functions names. + """ + def __init__(self, suffix): + self.suffix = suffix + +class TypeDescription(object): + """Type signature for a ufunc. + + Attributes + ---------- + type : str + Character representing the nominal type. + func_data : str or None or FullTypeDescr or FuncNameSuffix, optional + The string representing the expression to insert into the data + array, if any. + in_ : str or None, optional + The typecode(s) of the inputs. + out : str or None, optional + The typecode(s) of the outputs. + astype : dict or None, optional + If astype['x'] is 'y', uses PyUFunc_x_x_As_y_y/PyUFunc_xx_x_As_yy_y + instead of PyUFunc_x_x/PyUFunc_xx_x. + simd: list + Available SIMD ufunc loops, dispatched at runtime in specified order + Currently only supported for simples types (see make_arrays) + """ + def __init__(self, type, f=None, in_=None, out=None, astype=None, simd=None): + self.type = type + self.func_data = f + if astype is None: + astype = {} + self.astype_dict = astype + if in_ is not None: + in_ = in_.replace('P', type) + self.in_ = in_ + if out is not None: + out = out.replace('P', type) + self.out = out + self.simd = simd + + def finish_signature(self, nin, nout): + if self.in_ is None: + self.in_ = self.type * nin + assert len(self.in_) == nin + if self.out is None: + self.out = self.type * nout + assert len(self.out) == nout + self.astype = self.astype_dict.get(self.type, None) + +_fdata_map = dict(e='npy_%sf', f='npy_%sf', d='npy_%s', g='npy_%sl', + F='nc_%sf', D='nc_%s', G='nc_%sl') +def build_func_data(types, f): + func_data = [] + for t in types: + d = _fdata_map.get(t, '%s') % (f,) + func_data.append(d) + return func_data + +def TD(types, f=None, astype=None, in_=None, out=None, simd=None): + if f is not None: + if isinstance(f, str): + func_data = build_func_data(types, f) + else: + assert len(f) == len(types) + func_data = f + else: + func_data = (None,) * len(types) + if isinstance(in_, str): + in_ = (in_,) * len(types) + elif in_ is None: + in_ = (None,) * len(types) + if isinstance(out, str): + out = (out,) * len(types) + elif out is None: + out = (None,) * len(types) + tds = [] + for t, fd, i, o in zip(types, func_data, in_, out): + # [(simd-name, list of types)] + if simd is not None: + simdt = [k for k, v in simd if t in v] + else: + simdt = [] + tds.append(TypeDescription(t, f=fd, in_=i, out=o, astype=astype, simd=simdt)) + return tds + +class Ufunc(object): + """Description of a ufunc. + + Attributes + ---------- + nin : number of input arguments + nout : number of output arguments + identity : identity element for a two-argument function + docstring : docstring for the ufunc + type_descriptions : list of TypeDescription objects + """ + def __init__(self, nin, nout, identity, docstring, typereso, + *type_descriptions): + self.nin = nin + self.nout = nout + if identity is None: + identity = None_ + self.identity = identity + self.docstring = docstring + self.typereso = typereso + self.type_descriptions = [] + for td in type_descriptions: + self.type_descriptions.extend(td) + for td in self.type_descriptions: + td.finish_signature(self.nin, self.nout) + +# String-handling utilities to avoid locale-dependence. + +import string +if sys.version_info[0] < 3: + UPPER_TABLE = string.maketrans(string.ascii_lowercase, + string.ascii_uppercase) +else: + UPPER_TABLE = bytes.maketrans(bytes(string.ascii_lowercase, "ascii"), + bytes(string.ascii_uppercase, "ascii")) + +def english_upper(s): + """ Apply English case rules to convert ASCII strings to all upper case. + + This is an internal utility function to replace calls to str.upper() such + that we can avoid changing behavior with changing locales. In particular, + Turkish has distinct dotted and dotless variants of the Latin letter "I" in + both lowercase and uppercase. Thus, "i".upper() != "I" in a "tr" locale. + + Parameters + ---------- + s : str + + Returns + ------- + uppered : str + + Examples + -------- + >>> from numpy.lib.utils import english_upper + >>> s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_' + >>> english_upper(s) + 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' + >>> english_upper('') + '' + """ + uppered = s.translate(UPPER_TABLE) + return uppered + + +#each entry in defdict is a Ufunc object. + +#name: [string of chars for which it is defined, +# string of characters using func interface, +# tuple of strings giving funcs for data, +# (in, out), or (instr, outstr) giving the signature as character codes, +# identity, +# docstring, +# output specification (optional) +# ] + +chartoname = {'?': 'bool', + 'b': 'byte', + 'B': 'ubyte', + 'h': 'short', + 'H': 'ushort', + 'i': 'int', + 'I': 'uint', + 'l': 'long', + 'L': 'ulong', + 'q': 'longlong', + 'Q': 'ulonglong', + 'e': 'half', + 'f': 'float', + 'd': 'double', + 'g': 'longdouble', + 'F': 'cfloat', + 'D': 'cdouble', + 'G': 'clongdouble', + 'M': 'datetime', + 'm': 'timedelta', + 'O': 'OBJECT', + # '.' is like 'O', but calls a method of the object instead + # of a function + 'P': 'OBJECT', + } + +all = '?bBhHiIlLqQefdgFDGOMm' +O = 'O' +P = 'P' +ints = 'bBhHiIlLqQ' +times = 'Mm' +timedeltaonly = 'm' +intsO = ints + O +bints = '?' + ints +bintsO = bints + O +flts = 'efdg' +fltsO = flts + O +fltsP = flts + P +cmplx = 'FDG' +cmplxO = cmplx + O +cmplxP = cmplx + P +inexact = flts + cmplx +inexactvec = 'fd' +noint = inexact+O +nointP = inexact+P +allP = bints+times+flts+cmplxP +nobool = all[1:] +noobj = all[:-3]+all[-2:] +nobool_or_obj = all[1:-3]+all[-2:] +nobool_or_datetime = all[1:-2]+all[-1:] +intflt = ints+flts +intfltcmplx = ints+flts+cmplx +nocmplx = bints+times+flts +nocmplxO = nocmplx+O +nocmplxP = nocmplx+P +notimes_or_obj = bints + inexact +nodatetime_or_obj = bints + inexact + +# Find which code corresponds to int64. +int64 = '' +uint64 = '' +for code in 'bhilq': + if struct.calcsize(code) == 8: + int64 = code + uint64 = english_upper(code) + break + +# This dictionary describes all the ufunc implementations, generating +# all the function names and their corresponding ufunc signatures. TD is +# an object which expands a list of character codes into an array of +# TypeDescriptions. +defdict = { +'add': + Ufunc(2, 1, Zero, + docstrings.get('numpy.core.umath.add'), + 'PyUFunc_AdditionTypeResolver', + TD(notimes_or_obj, simd=[('avx2', ints)]), + [TypeDescription('M', FullTypeDescr, 'Mm', 'M'), + TypeDescription('m', FullTypeDescr, 'mm', 'm'), + TypeDescription('M', FullTypeDescr, 'mM', 'M'), + ], + TD(O, f='PyNumber_Add'), + ), +'subtract': + Ufunc(2, 1, None, # Zero is only a unit to the right, not the left + docstrings.get('numpy.core.umath.subtract'), + 'PyUFunc_SubtractionTypeResolver', + TD(notimes_or_obj, simd=[('avx2', ints)]), + [TypeDescription('M', FullTypeDescr, 'Mm', 'M'), + TypeDescription('m', FullTypeDescr, 'mm', 'm'), + TypeDescription('M', FullTypeDescr, 'MM', 'm'), + ], + TD(O, f='PyNumber_Subtract'), + ), +'multiply': + Ufunc(2, 1, One, + docstrings.get('numpy.core.umath.multiply'), + 'PyUFunc_MultiplicationTypeResolver', + TD(notimes_or_obj, simd=[('avx2', ints)]), + [TypeDescription('m', FullTypeDescr, 'mq', 'm'), + TypeDescription('m', FullTypeDescr, 'qm', 'm'), + TypeDescription('m', FullTypeDescr, 'md', 'm'), + TypeDescription('m', FullTypeDescr, 'dm', 'm'), + ], + TD(O, f='PyNumber_Multiply'), + ), +'divide': + Ufunc(2, 1, None, # One is only a unit to the right, not the left + docstrings.get('numpy.core.umath.divide'), + 'PyUFunc_MixedDivisionTypeResolver', + TD(intfltcmplx), + [TypeDescription('m', FullTypeDescr, 'mq', 'm'), + TypeDescription('m', FullTypeDescr, 'md', 'm'), + TypeDescription('m', FullTypeDescr, 'mm', 'd'), + ], + TD(O, f='PyNumber_Divide'), + ), +'floor_divide': + Ufunc(2, 1, None, # One is only a unit to the right, not the left + docstrings.get('numpy.core.umath.floor_divide'), + 'PyUFunc_DivisionTypeResolver', + TD(intfltcmplx), + [TypeDescription('m', FullTypeDescr, 'mq', 'm'), + TypeDescription('m', FullTypeDescr, 'md', 'm'), + #TypeDescription('m', FullTypeDescr, 'mm', 'd'), + ], + TD(O, f='PyNumber_FloorDivide'), + ), +'true_divide': + Ufunc(2, 1, None, # One is only a unit to the right, not the left + docstrings.get('numpy.core.umath.true_divide'), + 'PyUFunc_TrueDivisionTypeResolver', + TD(flts+cmplx), + [TypeDescription('m', FullTypeDescr, 'mq', 'm'), + TypeDescription('m', FullTypeDescr, 'md', 'm'), + TypeDescription('m', FullTypeDescr, 'mm', 'd'), + ], + TD(O, f='PyNumber_TrueDivide'), + ), +'conjugate': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.conjugate'), + None, + TD(ints+flts+cmplx, simd=[('avx2', ints)]), + TD(P, f='conjugate'), + ), +'fmod': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.fmod'), + None, + TD(ints), + TD(flts, f='fmod', astype={'e':'f'}), + TD(P, f='fmod'), + ), +'square': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.square'), + None, + TD(ints+inexact, simd=[('avx2', ints)]), + TD(O, f='Py_square'), + ), +'reciprocal': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.reciprocal'), + None, + TD(ints+inexact, simd=[('avx2', ints)]), + TD(O, f='Py_reciprocal'), + ), +# This is no longer used as numpy.ones_like, however it is +# still used by some internal calls. +'_ones_like': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath._ones_like'), + 'PyUFunc_OnesLikeTypeResolver', + TD(noobj), + TD(O, f='Py_get_one'), + ), +'power': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.power'), + None, + TD(ints), + TD(inexact, f='pow', astype={'e':'f'}), + TD(O, f='npy_ObjectPower'), + ), +'float_power': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.float_power'), + None, + TD('dgDG', f='pow'), + ), +'absolute': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.absolute'), + 'PyUFunc_AbsoluteTypeResolver', + TD(bints+flts+timedeltaonly), + TD(cmplx, out=('f', 'd', 'g')), + TD(O, f='PyNumber_Absolute'), + ), +'_arg': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath._arg'), + None, + TD(cmplx, out=('f', 'd', 'g')), + ), +'negative': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.negative'), + 'PyUFunc_NegativeTypeResolver', + TD(bints+flts+timedeltaonly, simd=[('avx2', ints)]), + TD(cmplx, f='neg'), + TD(O, f='PyNumber_Negative'), + ), +'positive': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.positive'), + 'PyUFunc_SimpleUnaryOperationTypeResolver', + TD(ints+flts+timedeltaonly), + TD(cmplx, f='pos'), + TD(O, f='PyNumber_Positive'), + ), +'sign': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.sign'), + 'PyUFunc_SimpleUnaryOperationTypeResolver', + TD(nobool_or_datetime), + ), +'greater': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.greater'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(all, out='?', simd=[('avx2', ints)]), + ), +'greater_equal': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.greater_equal'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(all, out='?', simd=[('avx2', ints)]), + ), +'less': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.less'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(all, out='?', simd=[('avx2', ints)]), + ), +'less_equal': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.less_equal'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(all, out='?', simd=[('avx2', ints)]), + ), +'equal': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.equal'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(all, out='?', simd=[('avx2', ints)]), + ), +'not_equal': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.not_equal'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(all, out='?', simd=[('avx2', ints)]), + ), +'logical_and': + Ufunc(2, 1, One, + docstrings.get('numpy.core.umath.logical_and'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(nodatetime_or_obj, out='?', simd=[('avx2', ints)]), + TD(O, f='npy_ObjectLogicalAnd'), + ), +'logical_not': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.logical_not'), + None, + TD(nodatetime_or_obj, out='?', simd=[('avx2', ints)]), + TD(O, f='npy_ObjectLogicalNot'), + ), +'logical_or': + Ufunc(2, 1, Zero, + docstrings.get('numpy.core.umath.logical_or'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(nodatetime_or_obj, out='?', simd=[('avx2', ints)]), + TD(O, f='npy_ObjectLogicalOr'), + ), +'logical_xor': + Ufunc(2, 1, Zero, + docstrings.get('numpy.core.umath.logical_xor'), + 'PyUFunc_SimpleBinaryComparisonTypeResolver', + TD(nodatetime_or_obj, out='?'), + TD(P, f='logical_xor'), + ), +'maximum': + Ufunc(2, 1, ReorderableNone, + docstrings.get('numpy.core.umath.maximum'), + 'PyUFunc_SimpleBinaryOperationTypeResolver', + TD(noobj), + TD(O, f='npy_ObjectMax') + ), +'minimum': + Ufunc(2, 1, ReorderableNone, + docstrings.get('numpy.core.umath.minimum'), + 'PyUFunc_SimpleBinaryOperationTypeResolver', + TD(noobj), + TD(O, f='npy_ObjectMin') + ), +'fmax': + Ufunc(2, 1, ReorderableNone, + docstrings.get('numpy.core.umath.fmax'), + 'PyUFunc_SimpleBinaryOperationTypeResolver', + TD(noobj), + TD(O, f='npy_ObjectMax') + ), +'fmin': + Ufunc(2, 1, ReorderableNone, + docstrings.get('numpy.core.umath.fmin'), + 'PyUFunc_SimpleBinaryOperationTypeResolver', + TD(noobj), + TD(O, f='npy_ObjectMin') + ), +'logaddexp': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.logaddexp'), + None, + TD(flts, f="logaddexp", astype={'e':'f'}) + ), +'logaddexp2': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.logaddexp2'), + None, + TD(flts, f="logaddexp2", astype={'e':'f'}) + ), +'bitwise_and': + Ufunc(2, 1, AllOnes, + docstrings.get('numpy.core.umath.bitwise_and'), + None, + TD(bints, simd=[('avx2', ints)]), + TD(O, f='PyNumber_And'), + ), +'bitwise_or': + Ufunc(2, 1, Zero, + docstrings.get('numpy.core.umath.bitwise_or'), + None, + TD(bints, simd=[('avx2', ints)]), + TD(O, f='PyNumber_Or'), + ), +'bitwise_xor': + Ufunc(2, 1, Zero, + docstrings.get('numpy.core.umath.bitwise_xor'), + None, + TD(bints, simd=[('avx2', ints)]), + TD(O, f='PyNumber_Xor'), + ), +'invert': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.invert'), + None, + TD(bints, simd=[('avx2', ints)]), + TD(O, f='PyNumber_Invert'), + ), +'left_shift': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.left_shift'), + None, + TD(ints, simd=[('avx2', ints)]), + TD(O, f='PyNumber_Lshift'), + ), +'right_shift': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.right_shift'), + None, + TD(ints, simd=[('avx2', ints)]), + TD(O, f='PyNumber_Rshift'), + ), +'heaviside': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.heaviside'), + None, + TD(flts, f='heaviside', astype={'e':'f'}), + ), +'degrees': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.degrees'), + None, + TD(fltsP, f='degrees', astype={'e':'f'}), + ), +'rad2deg': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.rad2deg'), + None, + TD(fltsP, f='rad2deg', astype={'e':'f'}), + ), +'radians': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.radians'), + None, + TD(fltsP, f='radians', astype={'e':'f'}), + ), +'deg2rad': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.deg2rad'), + None, + TD(fltsP, f='deg2rad', astype={'e':'f'}), + ), +'arccos': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.arccos'), + None, + TD(inexact, f='acos', astype={'e':'f'}), + TD(P, f='arccos'), + ), +'arccosh': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.arccosh'), + None, + TD(inexact, f='acosh', astype={'e':'f'}), + TD(P, f='arccosh'), + ), +'arcsin': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.arcsin'), + None, + TD(inexact, f='asin', astype={'e':'f'}), + TD(P, f='arcsin'), + ), +'arcsinh': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.arcsinh'), + None, + TD(inexact, f='asinh', astype={'e':'f'}), + TD(P, f='arcsinh'), + ), +'arctan': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.arctan'), + None, + TD(inexact, f='atan', astype={'e':'f'}), + TD(P, f='arctan'), + ), +'arctanh': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.arctanh'), + None, + TD(inexact, f='atanh', astype={'e':'f'}), + TD(P, f='arctanh'), + ), +'cos': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.cos'), + None, + TD(inexact, f='cos', astype={'e':'f'}), + TD(P, f='cos'), + ), +'sin': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.sin'), + None, + TD(inexact, f='sin', astype={'e':'f'}), + TD(P, f='sin'), + ), +'tan': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.tan'), + None, + TD(inexact, f='tan', astype={'e':'f'}), + TD(P, f='tan'), + ), +'cosh': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.cosh'), + None, + TD(inexact, f='cosh', astype={'e':'f'}), + TD(P, f='cosh'), + ), +'sinh': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.sinh'), + None, + TD(inexact, f='sinh', astype={'e':'f'}), + TD(P, f='sinh'), + ), +'tanh': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.tanh'), + None, + TD(inexact, f='tanh', astype={'e':'f'}), + TD(P, f='tanh'), + ), +'exp': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.exp'), + None, + TD(inexact, f='exp', astype={'e':'f'}), + TD(P, f='exp'), + ), +'exp2': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.exp2'), + None, + TD(inexact, f='exp2', astype={'e':'f'}), + TD(P, f='exp2'), + ), +'expm1': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.expm1'), + None, + TD(inexact, f='expm1', astype={'e':'f'}), + TD(P, f='expm1'), + ), +'log': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.log'), + None, + TD(inexact, f='log', astype={'e':'f'}), + TD(P, f='log'), + ), +'log2': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.log2'), + None, + TD(inexact, f='log2', astype={'e':'f'}), + TD(P, f='log2'), + ), +'log10': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.log10'), + None, + TD(inexact, f='log10', astype={'e':'f'}), + TD(P, f='log10'), + ), +'log1p': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.log1p'), + None, + TD(inexact, f='log1p', astype={'e':'f'}), + TD(P, f='log1p'), + ), +'sqrt': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.sqrt'), + None, + TD('e', f='sqrt', astype={'e':'f'}), + TD(inexactvec), + TD(inexact, f='sqrt', astype={'e':'f'}), + TD(P, f='sqrt'), + ), +'cbrt': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.cbrt'), + None, + TD(flts, f='cbrt', astype={'e':'f'}), + TD(P, f='cbrt'), + ), +'ceil': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.ceil'), + None, + TD(flts, f='ceil', astype={'e':'f'}), + TD(P, f='ceil'), + ), +'trunc': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.trunc'), + None, + TD(flts, f='trunc', astype={'e':'f'}), + TD(P, f='trunc'), + ), +'fabs': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.fabs'), + None, + TD(flts, f='fabs', astype={'e':'f'}), + TD(P, f='fabs'), + ), +'floor': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.floor'), + None, + TD(flts, f='floor', astype={'e':'f'}), + TD(P, f='floor'), + ), +'rint': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.rint'), + None, + TD(inexact, f='rint', astype={'e':'f'}), + TD(P, f='rint'), + ), +'arctan2': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.arctan2'), + None, + TD(flts, f='atan2', astype={'e':'f'}), + TD(P, f='arctan2'), + ), +'remainder': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.remainder'), + None, + TD(intflt), + TD(O, f='PyNumber_Remainder'), + ), +'divmod': + Ufunc(2, 2, None, + docstrings.get('numpy.core.umath.divmod'), + None, + TD(intflt), + TD(O, f='PyNumber_Divmod'), + ), +'hypot': + Ufunc(2, 1, Zero, + docstrings.get('numpy.core.umath.hypot'), + None, + TD(flts, f='hypot', astype={'e':'f'}), + TD(P, f='hypot'), + ), +'isnan': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.isnan'), + None, + TD(inexact, out='?'), + ), +'isnat': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.isnat'), + 'PyUFunc_IsNaTTypeResolver', + TD(times, out='?'), + ), +'isinf': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.isinf'), + None, + TD(inexact, out='?'), + ), +'isfinite': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.isfinite'), + None, + TD(inexact, out='?'), + ), +'signbit': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.signbit'), + None, + TD(flts, out='?'), + ), +'copysign': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.copysign'), + None, + TD(flts), + ), +'nextafter': + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.nextafter'), + None, + TD(flts), + ), +'spacing': + Ufunc(1, 1, None, + docstrings.get('numpy.core.umath.spacing'), + None, + TD(flts), + ), +'modf': + Ufunc(1, 2, None, + docstrings.get('numpy.core.umath.modf'), + None, + TD(flts), + ), +'ldexp' : + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.ldexp'), + None, + [TypeDescription('e', None, 'ei', 'e'), + TypeDescription('f', None, 'fi', 'f'), + TypeDescription('e', FuncNameSuffix('long'), 'el', 'e'), + TypeDescription('f', FuncNameSuffix('long'), 'fl', 'f'), + TypeDescription('d', None, 'di', 'd'), + TypeDescription('d', FuncNameSuffix('long'), 'dl', 'd'), + TypeDescription('g', None, 'gi', 'g'), + TypeDescription('g', FuncNameSuffix('long'), 'gl', 'g'), + ], + ), +'frexp' : + Ufunc(1, 2, None, + docstrings.get('numpy.core.umath.frexp'), + None, + [TypeDescription('e', None, 'e', 'ei'), + TypeDescription('f', None, 'f', 'fi'), + TypeDescription('d', None, 'd', 'di'), + TypeDescription('g', None, 'g', 'gi'), + ], + ) +} + +if sys.version_info[0] >= 3: + # Will be aliased to true_divide in umathmodule.c.src:InitOtherOperators + del defdict['divide'] + +def indent(st, spaces): + indention = ' '*spaces + indented = indention + st.replace('\n', '\n'+indention) + # trim off any trailing spaces + indented = re.sub(r' +$', r'', indented) + return indented + +chartotype1 = {'e': 'e_e', + 'f': 'f_f', + 'd': 'd_d', + 'g': 'g_g', + 'F': 'F_F', + 'D': 'D_D', + 'G': 'G_G', + 'O': 'O_O', + 'P': 'O_O_method'} + +chartotype2 = {'e': 'ee_e', + 'f': 'ff_f', + 'd': 'dd_d', + 'g': 'gg_g', + 'F': 'FF_F', + 'D': 'DD_D', + 'G': 'GG_G', + 'O': 'OO_O', + 'P': 'OO_O_method'} +#for each name +# 1) create functions, data, and signature +# 2) fill in functions and data in InitOperators +# 3) add function. + +def make_arrays(funcdict): + # functions array contains an entry for every type implemented NULL + # should be placed where PyUfunc_ style function will be filled in + # later + code1list = [] + code2list = [] + names = sorted(funcdict.keys()) + for name in names: + uf = funcdict[name] + funclist = [] + datalist = [] + siglist = [] + k = 0 + sub = 0 + + if uf.nin > 1: + assert uf.nin == 2 + thedict = chartotype2 # two inputs and one output + else: + thedict = chartotype1 # one input and one output + + for t in uf.type_descriptions: + if (t.func_data not in (None, FullTypeDescr) and + not isinstance(t.func_data, FuncNameSuffix)): + funclist.append('NULL') + astype = '' + if not t.astype is None: + astype = '_As_%s' % thedict[t.astype] + astr = ('%s_functions[%d] = PyUFunc_%s%s;' % + (name, k, thedict[t.type], astype)) + code2list.append(astr) + if t.type == 'O': + astr = ('%s_data[%d] = (void *) %s;' % + (name, k, t.func_data)) + code2list.append(astr) + datalist.append('(void *)NULL') + elif t.type == 'P': + datalist.append('(void *)"%s"' % t.func_data) + else: + astr = ('%s_data[%d] = (void *) %s;' % + (name, k, t.func_data)) + code2list.append(astr) + datalist.append('(void *)NULL') + #datalist.append('(void *)%s' % t.func_data) + sub += 1 + elif t.func_data is FullTypeDescr: + tname = english_upper(chartoname[t.type]) + datalist.append('(void *)NULL') + funclist.append( + '%s_%s_%s_%s' % (tname, t.in_, t.out, name)) + elif isinstance(t.func_data, FuncNameSuffix): + datalist.append('(void *)NULL') + tname = english_upper(chartoname[t.type]) + funclist.append( + '%s_%s_%s' % (tname, name, t.func_data.suffix)) + else: + datalist.append('(void *)NULL') + tname = english_upper(chartoname[t.type]) + funclist.append('%s_%s' % (tname, name)) + if t.simd is not None: + for vt in t.simd: + code2list.append("""\ +#ifdef HAVE_ATTRIBUTE_TARGET_{ISA} +if (NPY_CPU_SUPPORTS_{ISA}) {{ + {fname}_functions[{idx}] = {type}_{fname}_{isa}; +}} +#endif +""".format(ISA=vt.upper(), isa=vt, fname=name, type=tname, idx=k)) + + for x in t.in_ + t.out: + siglist.append('NPY_%s' % (english_upper(chartoname[x]),)) + + k += 1 + + funcnames = ', '.join(funclist) + signames = ', '.join(siglist) + datanames = ', '.join(datalist) + code1list.append("static PyUFuncGenericFunction %s_functions[] = {%s};" + % (name, funcnames)) + code1list.append("static void * %s_data[] = {%s};" + % (name, datanames)) + code1list.append("static char %s_signatures[] = {%s};" + % (name, signames)) + return "\n".join(code1list), "\n".join(code2list) + +def make_ufuncs(funcdict): + code3list = [] + names = sorted(funcdict.keys()) + for name in names: + uf = funcdict[name] + mlist = [] + docstring = textwrap.dedent(uf.docstring).strip() + if sys.version_info[0] < 3: + docstring = docstring.encode('string-escape') + docstring = docstring.replace(r'"', r'\"') + else: + docstring = docstring.encode('unicode-escape').decode('ascii') + docstring = docstring.replace(r'"', r'\"') + # XXX: I don't understand why the following replace is not + # necessary in the python 2 case. + docstring = docstring.replace(r"'", r"\'") + # Split the docstring because some compilers (like MS) do not like big + # string literal in C code. We split at endlines because textwrap.wrap + # do not play well with \n + docstring = '\\n\"\"'.join(docstring.split(r"\n")) + mlist.append(\ +r"""f = PyUFunc_FromFuncAndData(%s_functions, %s_data, %s_signatures, %d, + %d, %d, %s, "%s", + "%s", 0);""" % (name, name, name, + len(uf.type_descriptions), + uf.nin, uf.nout, + uf.identity, + name, docstring)) + if uf.typereso is not None: + mlist.append( + r"((PyUFuncObject *)f)->type_resolver = &%s;" % uf.typereso) + mlist.append(r"""PyDict_SetItemString(dictionary, "%s", f);""" % name) + mlist.append(r"""Py_DECREF(f);""") + code3list.append('\n'.join(mlist)) + return '\n'.join(code3list) + + +def make_code(funcdict, filename): + code1, code2 = make_arrays(funcdict) + code3 = make_ufuncs(funcdict) + code2 = indent(code2, 4) + code3 = indent(code3, 4) + code = r""" + +/** Warning this file is autogenerated!!! + + Please make changes to the code generator program (%s) +**/ + +%s + +static void +InitOperators(PyObject *dictionary) { + PyObject *f; + +%s +%s +} +""" % (filename, code1, code2, code3) + return code + + +if __name__ == "__main__": + filename = __file__ + fid = open('__umath_generated.c', 'w') + code = make_code(defdict, filename) + fid.write(code) + fid.close() diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py new file mode 100644 index 0000000..a454d95 --- /dev/null +++ b/numpy/core/code_generators/numpy_api.py @@ -0,0 +1,420 @@ +"""Here we define the exported functions, types, etc... which need to be +exported through a global C pointer. + +Each dictionary contains name -> index pair. + +Whenever you change one index, you break the ABI (and the ABI version number +should be incremented). Whenever you add an item to one of the dict, the API +needs to be updated. + +When adding a function, make sure to use the next integer not used as an index +(in case you use an existing index or jump, the build will stop and raise an +exception, so it should hopefully not get unnoticed). + +""" +from __future__ import division, absolute_import, print_function + +from code_generators.genapi import StealRef, NonNull + +# index, type +multiarray_global_vars = { + 'NPY_NUMUSERTYPES': (7, 'int'), + 'NPY_DEFAULT_ASSIGN_CASTING': (292, 'NPY_CASTING'), +} + +multiarray_scalar_bool_values = { + '_PyArrayScalar_BoolValues': (9,) +} + +# index, annotations +# please mark functions that have been checked to not need any annotations +multiarray_types_api = { + 'PyBigArray_Type': (1,), + 'PyArray_Type': (2,), + 'PyArrayDescr_Type': (3,), + 'PyArrayFlags_Type': (4,), + 'PyArrayIter_Type': (5,), + 'PyArrayMultiIter_Type': (6,), + 'PyBoolArrType_Type': (8,), + 'PyGenericArrType_Type': (10,), + 'PyNumberArrType_Type': (11,), + 'PyIntegerArrType_Type': (12,), + 'PySignedIntegerArrType_Type': (13,), + 'PyUnsignedIntegerArrType_Type': (14,), + 'PyInexactArrType_Type': (15,), + 'PyFloatingArrType_Type': (16,), + 'PyComplexFloatingArrType_Type': (17,), + 'PyFlexibleArrType_Type': (18,), + 'PyCharacterArrType_Type': (19,), + 'PyByteArrType_Type': (20,), + 'PyShortArrType_Type': (21,), + 'PyIntArrType_Type': (22,), + 'PyLongArrType_Type': (23,), + 'PyLongLongArrType_Type': (24,), + 'PyUByteArrType_Type': (25,), + 'PyUShortArrType_Type': (26,), + 'PyUIntArrType_Type': (27,), + 'PyULongArrType_Type': (28,), + 'PyULongLongArrType_Type': (29,), + 'PyFloatArrType_Type': (30,), + 'PyDoubleArrType_Type': (31,), + 'PyLongDoubleArrType_Type': (32,), + 'PyCFloatArrType_Type': (33,), + 'PyCDoubleArrType_Type': (34,), + 'PyCLongDoubleArrType_Type': (35,), + 'PyObjectArrType_Type': (36,), + 'PyStringArrType_Type': (37,), + 'PyUnicodeArrType_Type': (38,), + 'PyVoidArrType_Type': (39,), + # End 1.5 API + 'PyTimeIntegerArrType_Type': (214,), + 'PyDatetimeArrType_Type': (215,), + 'PyTimedeltaArrType_Type': (216,), + 'PyHalfArrType_Type': (217,), + 'NpyIter_Type': (218,), + # End 1.6 API +} + +#define NPY_NUMUSERTYPES (*(int *)PyArray_API[6]) +#define PyBoolArrType_Type (*(PyTypeObject *)PyArray_API[7]) +#define _PyArrayScalar_BoolValues ((PyBoolScalarObject *)PyArray_API[8]) + +multiarray_funcs_api = { + 'PyArray_GetNDArrayCVersion': (0,), + 'PyArray_SetNumericOps': (40,), + 'PyArray_GetNumericOps': (41,), + 'PyArray_INCREF': (42,), + 'PyArray_XDECREF': (43,), + 'PyArray_SetStringFunction': (44,), + 'PyArray_DescrFromType': (45,), + 'PyArray_TypeObjectFromType': (46,), + 'PyArray_Zero': (47,), + 'PyArray_One': (48,), + 'PyArray_CastToType': (49, StealRef(2), NonNull(2)), + 'PyArray_CastTo': (50,), + 'PyArray_CastAnyTo': (51,), + 'PyArray_CanCastSafely': (52,), + 'PyArray_CanCastTo': (53,), + 'PyArray_ObjectType': (54,), + 'PyArray_DescrFromObject': (55,), + 'PyArray_ConvertToCommonType': (56,), + 'PyArray_DescrFromScalar': (57,), + 'PyArray_DescrFromTypeObject': (58,), + 'PyArray_Size': (59,), + 'PyArray_Scalar': (60,), + 'PyArray_FromScalar': (61, StealRef(2)), + 'PyArray_ScalarAsCtype': (62,), + 'PyArray_CastScalarToCtype': (63,), + 'PyArray_CastScalarDirect': (64,), + 'PyArray_ScalarFromObject': (65,), + 'PyArray_GetCastFunc': (66,), + 'PyArray_FromDims': (67,), + 'PyArray_FromDimsAndDataAndDescr': (68, StealRef(3)), + 'PyArray_FromAny': (69, StealRef(2)), + 'PyArray_EnsureArray': (70, StealRef(1)), + 'PyArray_EnsureAnyArray': (71, StealRef(1)), + 'PyArray_FromFile': (72,), + 'PyArray_FromString': (73,), + 'PyArray_FromBuffer': (74,), + 'PyArray_FromIter': (75, StealRef(2)), + 'PyArray_Return': (76, StealRef(1)), + 'PyArray_GetField': (77, StealRef(2), NonNull(2)), + 'PyArray_SetField': (78, StealRef(2), NonNull(2)), + 'PyArray_Byteswap': (79,), + 'PyArray_Resize': (80,), + 'PyArray_MoveInto': (81,), + 'PyArray_CopyInto': (82,), + 'PyArray_CopyAnyInto': (83,), + 'PyArray_CopyObject': (84,), + 'PyArray_NewCopy': (85, NonNull(1)), + 'PyArray_ToList': (86,), + 'PyArray_ToString': (87,), + 'PyArray_ToFile': (88,), + 'PyArray_Dump': (89,), + 'PyArray_Dumps': (90,), + 'PyArray_ValidType': (91,), + 'PyArray_UpdateFlags': (92,), + 'PyArray_New': (93, NonNull(1)), + 'PyArray_NewFromDescr': (94, StealRef(2), NonNull([1, 2])), + 'PyArray_DescrNew': (95,), + 'PyArray_DescrNewFromType': (96,), + 'PyArray_GetPriority': (97,), + 'PyArray_IterNew': (98,), + 'PyArray_MultiIterNew': (99,), + 'PyArray_PyIntAsInt': (100,), + 'PyArray_PyIntAsIntp': (101,), + 'PyArray_Broadcast': (102,), + 'PyArray_FillObjectArray': (103,), + 'PyArray_FillWithScalar': (104,), + 'PyArray_CheckStrides': (105,), + 'PyArray_DescrNewByteorder': (106,), + 'PyArray_IterAllButAxis': (107,), + 'PyArray_CheckFromAny': (108, StealRef(2)), + 'PyArray_FromArray': (109, StealRef(2)), + 'PyArray_FromInterface': (110,), + 'PyArray_FromStructInterface': (111,), + 'PyArray_FromArrayAttr': (112,), + 'PyArray_ScalarKind': (113,), + 'PyArray_CanCoerceScalar': (114,), + 'PyArray_NewFlagsObject': (115,), + 'PyArray_CanCastScalar': (116,), + 'PyArray_CompareUCS4': (117,), + 'PyArray_RemoveSmallest': (118,), + 'PyArray_ElementStrides': (119,), + 'PyArray_Item_INCREF': (120,), + 'PyArray_Item_XDECREF': (121,), + 'PyArray_FieldNames': (122,), + 'PyArray_Transpose': (123,), + 'PyArray_TakeFrom': (124,), + 'PyArray_PutTo': (125,), + 'PyArray_PutMask': (126,), + 'PyArray_Repeat': (127,), + 'PyArray_Choose': (128,), + 'PyArray_Sort': (129,), + 'PyArray_ArgSort': (130,), + 'PyArray_SearchSorted': (131,), + 'PyArray_ArgMax': (132,), + 'PyArray_ArgMin': (133,), + 'PyArray_Reshape': (134,), + 'PyArray_Newshape': (135,), + 'PyArray_Squeeze': (136,), + 'PyArray_View': (137, StealRef(2)), + 'PyArray_SwapAxes': (138,), + 'PyArray_Max': (139,), + 'PyArray_Min': (140,), + 'PyArray_Ptp': (141,), + 'PyArray_Mean': (142,), + 'PyArray_Trace': (143,), + 'PyArray_Diagonal': (144,), + 'PyArray_Clip': (145,), + 'PyArray_Conjugate': (146,), + 'PyArray_Nonzero': (147,), + 'PyArray_Std': (148,), + 'PyArray_Sum': (149,), + 'PyArray_CumSum': (150,), + 'PyArray_Prod': (151,), + 'PyArray_CumProd': (152,), + 'PyArray_All': (153,), + 'PyArray_Any': (154,), + 'PyArray_Compress': (155,), + 'PyArray_Flatten': (156,), + 'PyArray_Ravel': (157,), + 'PyArray_MultiplyList': (158,), + 'PyArray_MultiplyIntList': (159,), + 'PyArray_GetPtr': (160,), + 'PyArray_CompareLists': (161,), + 'PyArray_AsCArray': (162, StealRef(5)), + 'PyArray_As1D': (163,), + 'PyArray_As2D': (164,), + 'PyArray_Free': (165,), + 'PyArray_Converter': (166,), + 'PyArray_IntpFromSequence': (167,), + 'PyArray_Concatenate': (168,), + 'PyArray_InnerProduct': (169,), + 'PyArray_MatrixProduct': (170,), + 'PyArray_CopyAndTranspose': (171,), + 'PyArray_Correlate': (172,), + 'PyArray_TypestrConvert': (173,), + 'PyArray_DescrConverter': (174,), + 'PyArray_DescrConverter2': (175,), + 'PyArray_IntpConverter': (176,), + 'PyArray_BufferConverter': (177,), + 'PyArray_AxisConverter': (178,), + 'PyArray_BoolConverter': (179,), + 'PyArray_ByteorderConverter': (180,), + 'PyArray_OrderConverter': (181,), + 'PyArray_EquivTypes': (182,), + 'PyArray_Zeros': (183, StealRef(3)), + 'PyArray_Empty': (184, StealRef(3)), + 'PyArray_Where': (185,), + 'PyArray_Arange': (186,), + 'PyArray_ArangeObj': (187,), + 'PyArray_SortkindConverter': (188,), + 'PyArray_LexSort': (189,), + 'PyArray_Round': (190,), + 'PyArray_EquivTypenums': (191,), + 'PyArray_RegisterDataType': (192,), + 'PyArray_RegisterCastFunc': (193,), + 'PyArray_RegisterCanCast': (194,), + 'PyArray_InitArrFuncs': (195,), + 'PyArray_IntTupleFromIntp': (196,), + 'PyArray_TypeNumFromName': (197,), + 'PyArray_ClipmodeConverter': (198,), + 'PyArray_OutputConverter': (199,), + 'PyArray_BroadcastToShape': (200,), + '_PyArray_SigintHandler': (201,), + '_PyArray_GetSigintBuf': (202,), + 'PyArray_DescrAlignConverter': (203,), + 'PyArray_DescrAlignConverter2': (204,), + 'PyArray_SearchsideConverter': (205,), + 'PyArray_CheckAxis': (206,), + 'PyArray_OverflowMultiplyList': (207,), + 'PyArray_CompareString': (208,), + 'PyArray_MultiIterFromObjects': (209,), + 'PyArray_GetEndianness': (210,), + 'PyArray_GetNDArrayCFeatureVersion': (211,), + 'PyArray_Correlate2': (212,), + 'PyArray_NeighborhoodIterNew': (213,), + # End 1.5 API + 'PyArray_SetDatetimeParseFunction': (219,), + 'PyArray_DatetimeToDatetimeStruct': (220,), + 'PyArray_TimedeltaToTimedeltaStruct': (221,), + 'PyArray_DatetimeStructToDatetime': (222,), + 'PyArray_TimedeltaStructToTimedelta': (223,), + # NDIter API + 'NpyIter_New': (224,), + 'NpyIter_MultiNew': (225,), + 'NpyIter_AdvancedNew': (226,), + 'NpyIter_Copy': (227,), + 'NpyIter_Deallocate': (228,), + 'NpyIter_HasDelayedBufAlloc': (229,), + 'NpyIter_HasExternalLoop': (230,), + 'NpyIter_EnableExternalLoop': (231,), + 'NpyIter_GetInnerStrideArray': (232,), + 'NpyIter_GetInnerLoopSizePtr': (233,), + 'NpyIter_Reset': (234,), + 'NpyIter_ResetBasePointers': (235,), + 'NpyIter_ResetToIterIndexRange': (236,), + 'NpyIter_GetNDim': (237,), + 'NpyIter_GetNOp': (238,), + 'NpyIter_GetIterNext': (239,), + 'NpyIter_GetIterSize': (240,), + 'NpyIter_GetIterIndexRange': (241,), + 'NpyIter_GetIterIndex': (242,), + 'NpyIter_GotoIterIndex': (243,), + 'NpyIter_HasMultiIndex': (244,), + 'NpyIter_GetShape': (245,), + 'NpyIter_GetGetMultiIndex': (246,), + 'NpyIter_GotoMultiIndex': (247,), + 'NpyIter_RemoveMultiIndex': (248,), + 'NpyIter_HasIndex': (249,), + 'NpyIter_IsBuffered': (250,), + 'NpyIter_IsGrowInner': (251,), + 'NpyIter_GetBufferSize': (252,), + 'NpyIter_GetIndexPtr': (253,), + 'NpyIter_GotoIndex': (254,), + 'NpyIter_GetDataPtrArray': (255,), + 'NpyIter_GetDescrArray': (256,), + 'NpyIter_GetOperandArray': (257,), + 'NpyIter_GetIterView': (258,), + 'NpyIter_GetReadFlags': (259,), + 'NpyIter_GetWriteFlags': (260,), + 'NpyIter_DebugPrint': (261,), + 'NpyIter_IterationNeedsAPI': (262,), + 'NpyIter_GetInnerFixedStrideArray': (263,), + 'NpyIter_RemoveAxis': (264,), + 'NpyIter_GetAxisStrideArray': (265,), + 'NpyIter_RequiresBuffering': (266,), + 'NpyIter_GetInitialDataPtrArray': (267,), + 'NpyIter_CreateCompatibleStrides': (268,), + # + 'PyArray_CastingConverter': (269,), + 'PyArray_CountNonzero': (270,), + 'PyArray_PromoteTypes': (271,), + 'PyArray_MinScalarType': (272,), + 'PyArray_ResultType': (273,), + 'PyArray_CanCastArrayTo': (274,), + 'PyArray_CanCastTypeTo': (275,), + 'PyArray_EinsteinSum': (276,), + 'PyArray_NewLikeArray': (277, StealRef(3), NonNull(1)), + 'PyArray_GetArrayParamsFromObject': (278,), + 'PyArray_ConvertClipmodeSequence': (279,), + 'PyArray_MatrixProduct2': (280,), + # End 1.6 API + 'NpyIter_IsFirstVisit': (281,), + 'PyArray_SetBaseObject': (282, StealRef(2)), + 'PyArray_CreateSortedStridePerm': (283,), + 'PyArray_RemoveAxesInPlace': (284,), + 'PyArray_DebugPrint': (285,), + 'PyArray_FailUnlessWriteable': (286,), + 'PyArray_SetUpdateIfCopyBase': (287, StealRef(2)), + 'PyDataMem_NEW': (288,), + 'PyDataMem_FREE': (289,), + 'PyDataMem_RENEW': (290,), + 'PyDataMem_SetEventHook': (291,), + 'PyArray_MapIterSwapAxes': (293,), + 'PyArray_MapIterArray': (294,), + 'PyArray_MapIterNext': (295,), + # End 1.7 API + 'PyArray_Partition': (296,), + 'PyArray_ArgPartition': (297,), + 'PyArray_SelectkindConverter': (298,), + 'PyDataMem_NEW_ZEROED': (299,), + # End 1.8 API + # End 1.9 API + 'PyArray_CheckAnyScalarExact': (300, NonNull(1)), + # End 1.10 API + 'PyArray_MapIterArrayCopyIfOverlap': (301,), + # End 1.13 API + 'PyArray_ResolveWritebackIfCopy': (302,), + 'PyArray_SetWritebackIfCopyBase': (303,), + # End 1.14 API +} + +ufunc_types_api = { + 'PyUFunc_Type': (0,) +} + +ufunc_funcs_api = { + 'PyUFunc_FromFuncAndData': (1,), + 'PyUFunc_RegisterLoopForType': (2,), + 'PyUFunc_GenericFunction': (3,), + 'PyUFunc_f_f_As_d_d': (4,), + 'PyUFunc_d_d': (5,), + 'PyUFunc_f_f': (6,), + 'PyUFunc_g_g': (7,), + 'PyUFunc_F_F_As_D_D': (8,), + 'PyUFunc_F_F': (9,), + 'PyUFunc_D_D': (10,), + 'PyUFunc_G_G': (11,), + 'PyUFunc_O_O': (12,), + 'PyUFunc_ff_f_As_dd_d': (13,), + 'PyUFunc_ff_f': (14,), + 'PyUFunc_dd_d': (15,), + 'PyUFunc_gg_g': (16,), + 'PyUFunc_FF_F_As_DD_D': (17,), + 'PyUFunc_DD_D': (18,), + 'PyUFunc_FF_F': (19,), + 'PyUFunc_GG_G': (20,), + 'PyUFunc_OO_O': (21,), + 'PyUFunc_O_O_method': (22,), + 'PyUFunc_OO_O_method': (23,), + 'PyUFunc_On_Om': (24,), + 'PyUFunc_GetPyValues': (25,), + 'PyUFunc_checkfperr': (26,), + 'PyUFunc_clearfperr': (27,), + 'PyUFunc_getfperr': (28,), + 'PyUFunc_handlefperr': (29,), + 'PyUFunc_ReplaceLoopBySignature': (30,), + 'PyUFunc_FromFuncAndDataAndSignature': (31,), + 'PyUFunc_SetUsesArraysAsData': (32,), + # End 1.5 API + 'PyUFunc_e_e': (33,), + 'PyUFunc_e_e_As_f_f': (34,), + 'PyUFunc_e_e_As_d_d': (35,), + 'PyUFunc_ee_e': (36,), + 'PyUFunc_ee_e_As_ff_f': (37,), + 'PyUFunc_ee_e_As_dd_d': (38,), + # End 1.6 API + 'PyUFunc_DefaultTypeResolver': (39,), + 'PyUFunc_ValidateCasting': (40,), + # End 1.7 API + 'PyUFunc_RegisterLoopForDescr': (41,), + # End 1.8 API +} + +# List of all the dicts which define the C API +# XXX: DO NOT CHANGE THE ORDER OF TUPLES BELOW ! +multiarray_api = ( + multiarray_global_vars, + multiarray_scalar_bool_values, + multiarray_types_api, + multiarray_funcs_api, +) + +ufunc_api = ( + ufunc_funcs_api, + ufunc_types_api +) + +full_api = multiarray_api + ufunc_api diff --git a/numpy/core/code_generators/ufunc_docstrings.py b/numpy/core/code_generators/ufunc_docstrings.py new file mode 100644 index 0000000..5626f50 --- /dev/null +++ b/numpy/core/code_generators/ufunc_docstrings.py @@ -0,0 +1,3681 @@ +""" +Docstrings for generated ufuncs + +The syntax is designed to look like the function add_newdoc is being +called from numpy.lib, but in this file add_newdoc puts the docstrings +in a dictionary. This dictionary is used in +numpy/core/code_generators/generate_umath.py to generate the docstrings +for the ufuncs in numpy.core at the C level when the ufuncs are created +at compile time. + +""" +from __future__ import division, absolute_import, print_function +import textwrap + +docdict = {} + +def get(name): + return docdict.get(name) + +# common parameter text to all ufuncs +_params_text = textwrap.dedent(""" + out : ndarray, None, or tuple of ndarray and None, optional + A location into which the result is stored. If provided, it must have + a shape that the inputs broadcast to. If not provided or `None`, + a freshly-allocated array is returned. A tuple (possible only as a + keyword argument) must have length equal to the number of outputs. + where : array_like, optional + Values of True indicate to calculate the ufunc at that position, values + of False indicate to leave the value in the output alone. + **kwargs + For other keyword-only arguments, see the + :ref:`ufunc docs `. +""").strip() + +def add_newdoc(place, name, doc): + doc = textwrap.dedent(doc).strip() + doc = doc.replace('$PARAMS', _params_text) + + docdict['.'.join((place, name))] = doc + + +add_newdoc('numpy.core.umath', 'absolute', + """ + Calculate the absolute value element-wise. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + absolute : ndarray + An ndarray containing the absolute value of + each element in `x`. For complex input, ``a + ib``, the + absolute value is :math:`\\sqrt{ a^2 + b^2 }`. + + Examples + -------- + >>> x = np.array([-1.2, 1.2]) + >>> np.absolute(x) + array([ 1.2, 1.2]) + >>> np.absolute(1.2 + 1j) + 1.5620499351813308 + + Plot the function over ``[-10, 10]``: + + >>> import matplotlib.pyplot as plt + + >>> x = np.linspace(start=-10, stop=10, num=101) + >>> plt.plot(x, np.absolute(x)) + >>> plt.show() + + Plot the function over the complex plane: + + >>> xx = x + 1j * x[:, np.newaxis] + >>> plt.imshow(np.abs(xx), extent=[-10, 10, -10, 10], cmap='gray') + >>> plt.show() + + """) + +add_newdoc('numpy.core.umath', 'add', + """ + Add arguments element-wise. + + Parameters + ---------- + x1, x2 : array_like + The arrays to be added. If ``x1.shape != x2.shape``, they must be + broadcastable to a common shape (which may be the shape of one or + the other). + $PARAMS + + Returns + ------- + add : ndarray or scalar + The sum of `x1` and `x2`, element-wise. Returns a scalar if + both `x1` and `x2` are scalars. + + Notes + ----- + Equivalent to `x1` + `x2` in terms of array broadcasting. + + Examples + -------- + >>> np.add(1.0, 4.0) + 5.0 + >>> x1 = np.arange(9.0).reshape((3, 3)) + >>> x2 = np.arange(3.0) + >>> np.add(x1, x2) + array([[ 0., 2., 4.], + [ 3., 5., 7.], + [ 6., 8., 10.]]) + + """) + +add_newdoc('numpy.core.umath', 'arccos', + """ + Trigonometric inverse cosine, element-wise. + + The inverse of `cos` so that, if ``y = cos(x)``, then ``x = arccos(y)``. + + Parameters + ---------- + x : array_like + `x`-coordinate on the unit circle. + For real arguments, the domain is [-1, 1]. + $PARAMS + + Returns + ------- + angle : ndarray + The angle of the ray intersecting the unit circle at the given + `x`-coordinate in radians [0, pi]. If `x` is a scalar then a + scalar is returned, otherwise an array of the same shape as `x` + is returned. + + See Also + -------- + cos, arctan, arcsin, emath.arccos + + Notes + ----- + `arccos` is a multivalued function: for each `x` there are infinitely + many numbers `z` such that `cos(z) = x`. The convention is to return + the angle `z` whose real part lies in `[0, pi]`. + + For real-valued input data types, `arccos` always returns real output. + For each value that cannot be expressed as a real number or infinity, + it yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `arccos` is a complex analytic function that + has branch cuts `[-inf, -1]` and `[1, inf]` and is continuous from + above on the former and from below on the latter. + + The inverse `cos` is also known as `acos` or cos^-1. + + References + ---------- + M. Abramowitz and I.A. Stegun, "Handbook of Mathematical Functions", + 10th printing, 1964, pp. 79. http://www.math.sfu.ca/~cbm/aands/ + + Examples + -------- + We expect the arccos of 1 to be 0, and of -1 to be pi: + + >>> np.arccos([1, -1]) + array([ 0. , 3.14159265]) + + Plot arccos: + + >>> import matplotlib.pyplot as plt + >>> x = np.linspace(-1, 1, num=100) + >>> plt.plot(x, np.arccos(x)) + >>> plt.axis('tight') + >>> plt.show() + + """) + +add_newdoc('numpy.core.umath', 'arccosh', + """ + Inverse hyperbolic cosine, element-wise. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + arccosh : ndarray + Array of the same shape as `x`. + + See Also + -------- + + cosh, arcsinh, sinh, arctanh, tanh + + Notes + ----- + `arccosh` is a multivalued function: for each `x` there are infinitely + many numbers `z` such that `cosh(z) = x`. The convention is to return the + `z` whose imaginary part lies in `[-pi, pi]` and the real part in + ``[0, inf]``. + + For real-valued input data types, `arccosh` always returns real output. + For each value that cannot be expressed as a real number or infinity, it + yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `arccosh` is a complex analytical function that + has a branch cut `[-inf, 1]` and is continuous from above on it. + + References + ---------- + .. [1] M. Abramowitz and I.A. Stegun, "Handbook of Mathematical Functions", + 10th printing, 1964, pp. 86. http://www.math.sfu.ca/~cbm/aands/ + .. [2] Wikipedia, "Inverse hyperbolic function", + http://en.wikipedia.org/wiki/Arccosh + + Examples + -------- + >>> np.arccosh([np.e, 10.0]) + array([ 1.65745445, 2.99322285]) + >>> np.arccosh(1) + 0.0 + + """) + +add_newdoc('numpy.core.umath', 'arcsin', + """ + Inverse sine, element-wise. + + Parameters + ---------- + x : array_like + `y`-coordinate on the unit circle. + $PARAMS + + Returns + ------- + angle : ndarray + The inverse sine of each element in `x`, in radians and in the + closed interval ``[-pi/2, pi/2]``. If `x` is a scalar, a scalar + is returned, otherwise an array. + + See Also + -------- + sin, cos, arccos, tan, arctan, arctan2, emath.arcsin + + Notes + ----- + `arcsin` is a multivalued function: for each `x` there are infinitely + many numbers `z` such that :math:`sin(z) = x`. The convention is to + return the angle `z` whose real part lies in [-pi/2, pi/2]. + + For real-valued input data types, *arcsin* always returns real output. + For each value that cannot be expressed as a real number or infinity, + it yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `arcsin` is a complex analytic function that + has, by convention, the branch cuts [-inf, -1] and [1, inf] and is + continuous from above on the former and from below on the latter. + + The inverse sine is also known as `asin` or sin^{-1}. + + References + ---------- + Abramowitz, M. and Stegun, I. A., *Handbook of Mathematical Functions*, + 10th printing, New York: Dover, 1964, pp. 79ff. + http://www.math.sfu.ca/~cbm/aands/ + + Examples + -------- + >>> np.arcsin(1) # pi/2 + 1.5707963267948966 + >>> np.arcsin(-1) # -pi/2 + -1.5707963267948966 + >>> np.arcsin(0) + 0.0 + + """) + +add_newdoc('numpy.core.umath', 'arcsinh', + """ + Inverse hyperbolic sine element-wise. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + out : ndarray + Array of of the same shape as `x`. + + Notes + ----- + `arcsinh` is a multivalued function: for each `x` there are infinitely + many numbers `z` such that `sinh(z) = x`. The convention is to return the + `z` whose imaginary part lies in `[-pi/2, pi/2]`. + + For real-valued input data types, `arcsinh` always returns real output. + For each value that cannot be expressed as a real number or infinity, it + returns ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `arccos` is a complex analytical function that + has branch cuts `[1j, infj]` and `[-1j, -infj]` and is continuous from + the right on the former and from the left on the latter. + + The inverse hyperbolic sine is also known as `asinh` or ``sinh^-1``. + + References + ---------- + .. [1] M. Abramowitz and I.A. Stegun, "Handbook of Mathematical Functions", + 10th printing, 1964, pp. 86. http://www.math.sfu.ca/~cbm/aands/ + .. [2] Wikipedia, "Inverse hyperbolic function", + http://en.wikipedia.org/wiki/Arcsinh + + Examples + -------- + >>> np.arcsinh(np.array([np.e, 10.0])) + array([ 1.72538256, 2.99822295]) + + """) + +add_newdoc('numpy.core.umath', 'arctan', + """ + Trigonometric inverse tangent, element-wise. + + The inverse of tan, so that if ``y = tan(x)`` then ``x = arctan(y)``. + + Parameters + ---------- + x : array_like + $PARAMS + + Returns + ------- + out : ndarray + Out has the same shape as `x`. Its real part is in + ``[-pi/2, pi/2]`` (``arctan(+/-inf)`` returns ``+/-pi/2``). + It is a scalar if `x` is a scalar. + + See Also + -------- + arctan2 : The "four quadrant" arctan of the angle formed by (`x`, `y`) + and the positive `x`-axis. + angle : Argument of complex values. + + Notes + ----- + `arctan` is a multi-valued function: for each `x` there are infinitely + many numbers `z` such that tan(`z`) = `x`. The convention is to return + the angle `z` whose real part lies in [-pi/2, pi/2]. + + For real-valued input data types, `arctan` always returns real output. + For each value that cannot be expressed as a real number or infinity, + it yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `arctan` is a complex analytic function that + has [`1j, infj`] and [`-1j, -infj`] as branch cuts, and is continuous + from the left on the former and from the right on the latter. + + The inverse tangent is also known as `atan` or tan^{-1}. + + References + ---------- + Abramowitz, M. and Stegun, I. A., *Handbook of Mathematical Functions*, + 10th printing, New York: Dover, 1964, pp. 79. + http://www.math.sfu.ca/~cbm/aands/ + + Examples + -------- + We expect the arctan of 0 to be 0, and of 1 to be pi/4: + + >>> np.arctan([0, 1]) + array([ 0. , 0.78539816]) + + >>> np.pi/4 + 0.78539816339744828 + + Plot arctan: + + >>> import matplotlib.pyplot as plt + >>> x = np.linspace(-10, 10) + >>> plt.plot(x, np.arctan(x)) + >>> plt.axis('tight') + >>> plt.show() + + """) + +add_newdoc('numpy.core.umath', 'arctan2', + """ + Element-wise arc tangent of ``x1/x2`` choosing the quadrant correctly. + + The quadrant (i.e., branch) is chosen so that ``arctan2(x1, x2)`` is + the signed angle in radians between the ray ending at the origin and + passing through the point (1,0), and the ray ending at the origin and + passing through the point (`x2`, `x1`). (Note the role reversal: the + "`y`-coordinate" is the first function parameter, the "`x`-coordinate" + is the second.) By IEEE convention, this function is defined for + `x2` = +/-0 and for either or both of `x1` and `x2` = +/-inf (see + Notes for specific values). + + This function is not defined for complex-valued arguments; for the + so-called argument of complex values, use `angle`. + + Parameters + ---------- + x1 : array_like, real-valued + `y`-coordinates. + x2 : array_like, real-valued + `x`-coordinates. `x2` must be broadcastable to match the shape of + `x1` or vice versa. + $PARAMS + + Returns + ------- + angle : ndarray + Array of angles in radians, in the range ``[-pi, pi]``. + + See Also + -------- + arctan, tan, angle + + Notes + ----- + *arctan2* is identical to the `atan2` function of the underlying + C library. The following special values are defined in the C + standard: [1]_ + + ====== ====== ================ + `x1` `x2` `arctan2(x1,x2)` + ====== ====== ================ + +/- 0 +0 +/- 0 + +/- 0 -0 +/- pi + > 0 +/-inf +0 / +pi + < 0 +/-inf -0 / -pi + +/-inf +inf +/- (pi/4) + +/-inf -inf +/- (3*pi/4) + ====== ====== ================ + + Note that +0 and -0 are distinct floating point numbers, as are +inf + and -inf. + + References + ---------- + .. [1] ISO/IEC standard 9899:1999, "Programming language C." + + Examples + -------- + Consider four points in different quadrants: + + >>> x = np.array([-1, +1, +1, -1]) + >>> y = np.array([-1, -1, +1, +1]) + >>> np.arctan2(y, x) * 180 / np.pi + array([-135., -45., 45., 135.]) + + Note the order of the parameters. `arctan2` is defined also when `x2` = 0 + and at several other special points, obtaining values in + the range ``[-pi, pi]``: + + >>> np.arctan2([1., -1.], [0., 0.]) + array([ 1.57079633, -1.57079633]) + >>> np.arctan2([0., 0., np.inf], [+0., -0., np.inf]) + array([ 0. , 3.14159265, 0.78539816]) + + """) + +add_newdoc('numpy.core.umath', '_arg', + """ + DO NOT USE, ONLY FOR TESTING + """) + +add_newdoc('numpy.core.umath', 'arctanh', + """ + Inverse hyperbolic tangent element-wise. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + out : ndarray + Array of the same shape as `x`. + + See Also + -------- + emath.arctanh + + Notes + ----- + `arctanh` is a multivalued function: for each `x` there are infinitely + many numbers `z` such that `tanh(z) = x`. The convention is to return + the `z` whose imaginary part lies in `[-pi/2, pi/2]`. + + For real-valued input data types, `arctanh` always returns real output. + For each value that cannot be expressed as a real number or infinity, + it yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `arctanh` is a complex analytical function + that has branch cuts `[-1, -inf]` and `[1, inf]` and is continuous from + above on the former and from below on the latter. + + The inverse hyperbolic tangent is also known as `atanh` or ``tanh^-1``. + + References + ---------- + .. [1] M. Abramowitz and I.A. Stegun, "Handbook of Mathematical Functions", + 10th printing, 1964, pp. 86. http://www.math.sfu.ca/~cbm/aands/ + .. [2] Wikipedia, "Inverse hyperbolic function", + http://en.wikipedia.org/wiki/Arctanh + + Examples + -------- + >>> np.arctanh([0, -0.5]) + array([ 0. , -0.54930614]) + + """) + +add_newdoc('numpy.core.umath', 'bitwise_and', + """ + Compute the bit-wise AND of two arrays element-wise. + + Computes the bit-wise AND of the underlying binary representation of + the integers in the input arrays. This ufunc implements the C/Python + operator ``&``. + + Parameters + ---------- + x1, x2 : array_like + Only integer and boolean types are handled. + $PARAMS + + Returns + ------- + out : array_like + Result. + + See Also + -------- + logical_and + bitwise_or + bitwise_xor + binary_repr : + Return the binary representation of the input number as a string. + + Examples + -------- + The number 13 is represented by ``00001101``. Likewise, 17 is + represented by ``00010001``. The bit-wise AND of 13 and 17 is + therefore ``000000001``, or 1: + + >>> np.bitwise_and(13, 17) + 1 + + >>> np.bitwise_and(14, 13) + 12 + >>> np.binary_repr(12) + '1100' + >>> np.bitwise_and([14,3], 13) + array([12, 1]) + + >>> np.bitwise_and([11,7], [4,25]) + array([0, 1]) + >>> np.bitwise_and(np.array([2,5,255]), np.array([3,14,16])) + array([ 2, 4, 16]) + >>> np.bitwise_and([True, True], [False, True]) + array([False, True]) + + """) + +add_newdoc('numpy.core.umath', 'bitwise_or', + """ + Compute the bit-wise OR of two arrays element-wise. + + Computes the bit-wise OR of the underlying binary representation of + the integers in the input arrays. This ufunc implements the C/Python + operator ``|``. + + Parameters + ---------- + x1, x2 : array_like + Only integer and boolean types are handled. + $PARAMS + + Returns + ------- + out : array_like + Result. + + See Also + -------- + logical_or + bitwise_and + bitwise_xor + binary_repr : + Return the binary representation of the input number as a string. + + Examples + -------- + The number 13 has the binaray representation ``00001101``. Likewise, + 16 is represented by ``00010000``. The bit-wise OR of 13 and 16 is + then ``000111011``, or 29: + + >>> np.bitwise_or(13, 16) + 29 + >>> np.binary_repr(29) + '11101' + + >>> np.bitwise_or(32, 2) + 34 + >>> np.bitwise_or([33, 4], 1) + array([33, 5]) + >>> np.bitwise_or([33, 4], [1, 2]) + array([33, 6]) + + >>> np.bitwise_or(np.array([2, 5, 255]), np.array([4, 4, 4])) + array([ 6, 5, 255]) + >>> np.array([2, 5, 255]) | np.array([4, 4, 4]) + array([ 6, 5, 255]) + >>> np.bitwise_or(np.array([2, 5, 255, 2147483647L], dtype=np.int32), + ... np.array([4, 4, 4, 2147483647L], dtype=np.int32)) + array([ 6, 5, 255, 2147483647]) + >>> np.bitwise_or([True, True], [False, True]) + array([ True, True]) + + """) + +add_newdoc('numpy.core.umath', 'bitwise_xor', + """ + Compute the bit-wise XOR of two arrays element-wise. + + Computes the bit-wise XOR of the underlying binary representation of + the integers in the input arrays. This ufunc implements the C/Python + operator ``^``. + + Parameters + ---------- + x1, x2 : array_like + Only integer and boolean types are handled. + $PARAMS + + Returns + ------- + out : array_like + Result. + + See Also + -------- + logical_xor + bitwise_and + bitwise_or + binary_repr : + Return the binary representation of the input number as a string. + + Examples + -------- + The number 13 is represented by ``00001101``. Likewise, 17 is + represented by ``00010001``. The bit-wise XOR of 13 and 17 is + therefore ``00011100``, or 28: + + >>> np.bitwise_xor(13, 17) + 28 + >>> np.binary_repr(28) + '11100' + + >>> np.bitwise_xor(31, 5) + 26 + >>> np.bitwise_xor([31,3], 5) + array([26, 6]) + + >>> np.bitwise_xor([31,3], [5,6]) + array([26, 5]) + >>> np.bitwise_xor([True, True], [False, True]) + array([ True, False]) + + """) + +add_newdoc('numpy.core.umath', 'ceil', + """ + Return the ceiling of the input, element-wise. + + The ceil of the scalar `x` is the smallest integer `i`, such that + `i >= x`. It is often denoted as :math:`\\lceil x \\rceil`. + + Parameters + ---------- + x : array_like + Input data. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The ceiling of each element in `x`, with `float` dtype. + + See Also + -------- + floor, trunc, rint + + Examples + -------- + >>> a = np.array([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]) + >>> np.ceil(a) + array([-1., -1., -0., 1., 2., 2., 2.]) + + """) + +add_newdoc('numpy.core.umath', 'trunc', + """ + Return the truncated value of the input, element-wise. + + The truncated value of the scalar `x` is the nearest integer `i` which + is closer to zero than `x` is. In short, the fractional part of the + signed number `x` is discarded. + + Parameters + ---------- + x : array_like + Input data. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The truncated value of each element in `x`. + + See Also + -------- + ceil, floor, rint + + Notes + ----- + .. versionadded:: 1.3.0 + + Examples + -------- + >>> a = np.array([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]) + >>> np.trunc(a) + array([-1., -1., -0., 0., 1., 1., 2.]) + + """) + +add_newdoc('numpy.core.umath', 'conjugate', + """ + Return the complex conjugate, element-wise. + + The complex conjugate of a complex number is obtained by changing the + sign of its imaginary part. + + Parameters + ---------- + x : array_like + Input value. + $PARAMS + + Returns + ------- + y : ndarray + The complex conjugate of `x`, with same dtype as `y`. + + Examples + -------- + >>> np.conjugate(1+2j) + (1-2j) + + >>> x = np.eye(2) + 1j * np.eye(2) + >>> np.conjugate(x) + array([[ 1.-1.j, 0.-0.j], + [ 0.-0.j, 1.-1.j]]) + + """) + +add_newdoc('numpy.core.umath', 'cos', + """ + Cosine element-wise. + + Parameters + ---------- + x : array_like + Input array in radians. + $PARAMS + + Returns + ------- + y : ndarray + The corresponding cosine values. + + Notes + ----- + If `out` is provided, the function writes the result into it, + and returns a reference to `out`. (See Examples) + + References + ---------- + M. Abramowitz and I. A. Stegun, Handbook of Mathematical Functions. + New York, NY: Dover, 1972. + + Examples + -------- + >>> np.cos(np.array([0, np.pi/2, np.pi])) + array([ 1.00000000e+00, 6.12303177e-17, -1.00000000e+00]) + >>> + >>> # Example of providing the optional output parameter + >>> out2 = np.cos([0.1], out1) + >>> out2 is out1 + True + >>> + >>> # Example of ValueError due to provision of shape mis-matched `out` + >>> np.cos(np.zeros((3,3)),np.zeros((2,2))) + Traceback (most recent call last): + File "", line 1, in + ValueError: invalid return array shape + + """) + +add_newdoc('numpy.core.umath', 'cosh', + """ + Hyperbolic cosine, element-wise. + + Equivalent to ``1/2 * (np.exp(x) + np.exp(-x))`` and ``np.cos(1j*x)``. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + out : ndarray + Output array of same shape as `x`. + + Examples + -------- + >>> np.cosh(0) + 1.0 + + The hyperbolic cosine describes the shape of a hanging cable: + + >>> import matplotlib.pyplot as plt + >>> x = np.linspace(-4, 4, 1000) + >>> plt.plot(x, np.cosh(x)) + >>> plt.show() + + """) + +add_newdoc('numpy.core.umath', 'degrees', + """ + Convert angles from radians to degrees. + + Parameters + ---------- + x : array_like + Input array in radians. + $PARAMS + + Returns + ------- + y : ndarray of floats + The corresponding degree values; if `out` was supplied this is a + reference to it. + + See Also + -------- + rad2deg : equivalent function + + Examples + -------- + Convert a radian array to degrees + + >>> rad = np.arange(12.)*np.pi/6 + >>> np.degrees(rad) + array([ 0., 30., 60., 90., 120., 150., 180., 210., 240., + 270., 300., 330.]) + + >>> out = np.zeros((rad.shape)) + >>> r = degrees(rad, out) + >>> np.all(r == out) + True + + """) + +add_newdoc('numpy.core.umath', 'rad2deg', + """ + Convert angles from radians to degrees. + + Parameters + ---------- + x : array_like + Angle in radians. + $PARAMS + + Returns + ------- + y : ndarray + The corresponding angle in degrees. + + See Also + -------- + deg2rad : Convert angles from degrees to radians. + unwrap : Remove large jumps in angle by wrapping. + + Notes + ----- + .. versionadded:: 1.3.0 + + rad2deg(x) is ``180 * x / pi``. + + Examples + -------- + >>> np.rad2deg(np.pi/2) + 90.0 + + """) + +add_newdoc('numpy.core.umath', 'heaviside', + """ + Compute the Heaviside step function. + + The Heaviside step function is defined as:: + + 0 if x1 < 0 + heaviside(x1, x2) = x2 if x1 == 0 + 1 if x1 > 0 + + where `x2` is often taken to be 0.5, but 0 and 1 are also sometimes used. + + Parameters + ---------- + x1 : array_like + Input values. + x2 : array_like + The value of the function when x1 is 0. + $PARAMS + + Returns + ------- + out : ndarray + The output array, element-wise Heaviside step function of `x1`. + + Notes + ----- + .. versionadded:: 1.13.0 + + References + ---------- + .. Wikipedia, "Heaviside step function", + https://en.wikipedia.org/wiki/Heaviside_step_function + + Examples + -------- + >>> np.heaviside([-1.5, 0, 2.0], 0.5) + array([ 0. , 0.5, 1. ]) + >>> np.heaviside([-1.5, 0, 2.0], 1) + array([ 0., 1., 1.]) + """) + +add_newdoc('numpy.core.umath', 'divide', + """ + Divide arguments element-wise. + + Parameters + ---------- + x1 : array_like + Dividend array. + x2 : array_like + Divisor array. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The quotient ``x1/x2``, element-wise. Returns a scalar if + both ``x1`` and ``x2`` are scalars. + + See Also + -------- + seterr : Set whether to raise or warn on overflow, underflow and + division by zero. + + Notes + ----- + Equivalent to ``x1`` / ``x2`` in terms of array-broadcasting. + + Behavior on division by zero can be changed using ``seterr``. + + In Python 2, when both ``x1`` and ``x2`` are of an integer type, + ``divide`` will behave like ``floor_divide``. In Python 3, it behaves + like ``true_divide``. + + Examples + -------- + >>> np.divide(2.0, 4.0) + 0.5 + >>> x1 = np.arange(9.0).reshape((3, 3)) + >>> x2 = np.arange(3.0) + >>> np.divide(x1, x2) + array([[ NaN, 1. , 1. ], + [ Inf, 4. , 2.5], + [ Inf, 7. , 4. ]]) + + Note the behavior with integer types (Python 2 only): + + >>> np.divide(2, 4) + 0 + >>> np.divide(2, 4.) + 0.5 + + Division by zero always yields zero in integer arithmetic (again, + Python 2 only), and does not raise an exception or a warning: + + >>> np.divide(np.array([0, 1], dtype=int), np.array([0, 0], dtype=int)) + array([0, 0]) + + Division by zero can, however, be caught using ``seterr``: + + >>> old_err_state = np.seterr(divide='raise') + >>> np.divide(1, 0) + Traceback (most recent call last): + File "", line 1, in + FloatingPointError: divide by zero encountered in divide + + >>> ignored_states = np.seterr(**old_err_state) + >>> np.divide(1, 0) + 0 + + """) + +add_newdoc('numpy.core.umath', 'equal', + """ + Return (x1 == x2) element-wise. + + Parameters + ---------- + x1, x2 : array_like + Input arrays of the same shape. + $PARAMS + + Returns + ------- + out : ndarray or bool + Output array of bools, or a single bool if x1 and x2 are scalars. + + See Also + -------- + not_equal, greater_equal, less_equal, greater, less + + Examples + -------- + >>> np.equal([0, 1, 3], np.arange(3)) + array([ True, True, False]) + + What is compared are values, not types. So an int (1) and an array of + length one can evaluate as True: + + >>> np.equal(1, np.ones(1)) + array([ True]) + + """) + +add_newdoc('numpy.core.umath', 'exp', + """ + Calculate the exponential of all elements in the input array. + + Parameters + ---------- + x : array_like + Input values. + $PARAMS + + Returns + ------- + out : ndarray + Output array, element-wise exponential of `x`. + + See Also + -------- + expm1 : Calculate ``exp(x) - 1`` for all elements in the array. + exp2 : Calculate ``2**x`` for all elements in the array. + + Notes + ----- + The irrational number ``e`` is also known as Euler's number. It is + approximately 2.718281, and is the base of the natural logarithm, + ``ln`` (this means that, if :math:`x = \\ln y = \\log_e y`, + then :math:`e^x = y`. For real input, ``exp(x)`` is always positive. + + For complex arguments, ``x = a + ib``, we can write + :math:`e^x = e^a e^{ib}`. The first term, :math:`e^a`, is already + known (it is the real argument, described above). The second term, + :math:`e^{ib}`, is :math:`\\cos b + i \\sin b`, a function with + magnitude 1 and a periodic phase. + + References + ---------- + .. [1] Wikipedia, "Exponential function", + http://en.wikipedia.org/wiki/Exponential_function + .. [2] M. Abramovitz and I. A. Stegun, "Handbook of Mathematical Functions + with Formulas, Graphs, and Mathematical Tables," Dover, 1964, p. 69, + http://www.math.sfu.ca/~cbm/aands/page_69.htm + + Examples + -------- + Plot the magnitude and phase of ``exp(x)`` in the complex plane: + + >>> import matplotlib.pyplot as plt + + >>> x = np.linspace(-2*np.pi, 2*np.pi, 100) + >>> xx = x + 1j * x[:, np.newaxis] # a + ib over complex plane + >>> out = np.exp(xx) + + >>> plt.subplot(121) + >>> plt.imshow(np.abs(out), + ... extent=[-2*np.pi, 2*np.pi, -2*np.pi, 2*np.pi], cmap='gray') + >>> plt.title('Magnitude of exp(x)') + + >>> plt.subplot(122) + >>> plt.imshow(np.angle(out), + ... extent=[-2*np.pi, 2*np.pi, -2*np.pi, 2*np.pi], cmap='hsv') + >>> plt.title('Phase (angle) of exp(x)') + >>> plt.show() + + """) + +add_newdoc('numpy.core.umath', 'exp2', + """ + Calculate `2**p` for all `p` in the input array. + + Parameters + ---------- + x : array_like + Input values. + $PARAMS + + Returns + ------- + out : ndarray + Element-wise 2 to the power `x`. + + See Also + -------- + power + + Notes + ----- + .. versionadded:: 1.3.0 + + + + Examples + -------- + >>> np.exp2([2, 3]) + array([ 4., 8.]) + + """) + +add_newdoc('numpy.core.umath', 'expm1', + """ + Calculate ``exp(x) - 1`` for all elements in the array. + + Parameters + ---------- + x : array_like + Input values. + $PARAMS + + Returns + ------- + out : ndarray + Element-wise exponential minus one: ``out = exp(x) - 1``. + + See Also + -------- + log1p : ``log(1 + x)``, the inverse of expm1. + + + Notes + ----- + This function provides greater precision than ``exp(x) - 1`` + for small values of ``x``. + + Examples + -------- + The true value of ``exp(1e-10) - 1`` is ``1.00000000005e-10`` to + about 32 significant digits. This example shows the superiority of + expm1 in this case. + + >>> np.expm1(1e-10) + 1.00000000005e-10 + >>> np.exp(1e-10) - 1 + 1.000000082740371e-10 + + """) + +add_newdoc('numpy.core.umath', 'fabs', + """ + Compute the absolute values element-wise. + + This function returns the absolute values (positive magnitude) of the + data in `x`. Complex values are not handled, use `absolute` to find the + absolute values of complex data. + + Parameters + ---------- + x : array_like + The array of numbers for which the absolute values are required. If + `x` is a scalar, the result `y` will also be a scalar. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The absolute values of `x`, the returned values are always floats. + + See Also + -------- + absolute : Absolute values including `complex` types. + + Examples + -------- + >>> np.fabs(-1) + 1.0 + >>> np.fabs([-1.2, 1.2]) + array([ 1.2, 1.2]) + + """) + +add_newdoc('numpy.core.umath', 'floor', + """ + Return the floor of the input, element-wise. + + The floor of the scalar `x` is the largest integer `i`, such that + `i <= x`. It is often denoted as :math:`\\lfloor x \\rfloor`. + + Parameters + ---------- + x : array_like + Input data. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The floor of each element in `x`. + + See Also + -------- + ceil, trunc, rint + + Notes + ----- + Some spreadsheet programs calculate the "floor-towards-zero", in other + words ``floor(-2.5) == -2``. NumPy instead uses the definition of + `floor` where `floor(-2.5) == -3`. + + Examples + -------- + >>> a = np.array([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]) + >>> np.floor(a) + array([-2., -2., -1., 0., 1., 1., 2.]) + + """) + +add_newdoc('numpy.core.umath', 'floor_divide', + """ + Return the largest integer smaller or equal to the division of the inputs. + It is equivalent to the Python ``//`` operator and pairs with the + Python ``%`` (`remainder`), function so that ``b = a % b + b * (a // b)`` + up to roundoff. + + Parameters + ---------- + x1 : array_like + Numerator. + x2 : array_like + Denominator. + $PARAMS + + Returns + ------- + y : ndarray + y = floor(`x1`/`x2`) + + + See Also + -------- + remainder : Remainder complementary to floor_divide. + divmod : Simultaneous floor division and remainder. + divide : Standard division. + floor : Round a number to the nearest integer toward minus infinity. + ceil : Round a number to the nearest integer toward infinity. + + Examples + -------- + >>> np.floor_divide(7,3) + 2 + >>> np.floor_divide([1., 2., 3., 4.], 2.5) + array([ 0., 0., 1., 1.]) + + """) + +add_newdoc('numpy.core.umath', 'fmod', + """ + Return the element-wise remainder of division. + + This is the NumPy implementation of the C library function fmod, the + remainder has the same sign as the dividend `x1`. It is equivalent to + the Matlab(TM) ``rem`` function and should not be confused with the + Python modulus operator ``x1 % x2``. + + Parameters + ---------- + x1 : array_like + Dividend. + x2 : array_like + Divisor. + $PARAMS + + Returns + ------- + y : array_like + The remainder of the division of `x1` by `x2`. + + See Also + -------- + remainder : Equivalent to the Python ``%`` operator. + divide + + Notes + ----- + The result of the modulo operation for negative dividend and divisors + is bound by conventions. For `fmod`, the sign of result is the sign of + the dividend, while for `remainder` the sign of the result is the sign + of the divisor. The `fmod` function is equivalent to the Matlab(TM) + ``rem`` function. + + Examples + -------- + >>> np.fmod([-3, -2, -1, 1, 2, 3], 2) + array([-1, 0, -1, 1, 0, 1]) + >>> np.remainder([-3, -2, -1, 1, 2, 3], 2) + array([1, 0, 1, 1, 0, 1]) + + >>> np.fmod([5, 3], [2, 2.]) + array([ 1., 1.]) + >>> a = np.arange(-3, 3).reshape(3, 2) + >>> a + array([[-3, -2], + [-1, 0], + [ 1, 2]]) + >>> np.fmod(a, [2,2]) + array([[-1, 0], + [-1, 0], + [ 1, 0]]) + + """) + +add_newdoc('numpy.core.umath', 'greater', + """ + Return the truth value of (x1 > x2) element-wise. + + Parameters + ---------- + x1, x2 : array_like + Input arrays. If ``x1.shape != x2.shape``, they must be + broadcastable to a common shape (which may be the shape of one or + the other). + $PARAMS + + Returns + ------- + out : bool or ndarray of bool + Array of bools, or a single bool if `x1` and `x2` are scalars. + + + See Also + -------- + greater_equal, less, less_equal, equal, not_equal + + Examples + -------- + >>> np.greater([4,2],[2,2]) + array([ True, False]) + + If the inputs are ndarrays, then np.greater is equivalent to '>'. + + >>> a = np.array([4,2]) + >>> b = np.array([2,2]) + >>> a > b + array([ True, False]) + + """) + +add_newdoc('numpy.core.umath', 'greater_equal', + """ + Return the truth value of (x1 >= x2) element-wise. + + Parameters + ---------- + x1, x2 : array_like + Input arrays. If ``x1.shape != x2.shape``, they must be + broadcastable to a common shape (which may be the shape of one or + the other). + $PARAMS + + Returns + ------- + out : bool or ndarray of bool + Array of bools, or a single bool if `x1` and `x2` are scalars. + + See Also + -------- + greater, less, less_equal, equal, not_equal + + Examples + -------- + >>> np.greater_equal([4, 2, 1], [2, 2, 2]) + array([ True, True, False]) + + """) + +add_newdoc('numpy.core.umath', 'hypot', + """ + Given the "legs" of a right triangle, return its hypotenuse. + + Equivalent to ``sqrt(x1**2 + x2**2)``, element-wise. If `x1` or + `x2` is scalar_like (i.e., unambiguously cast-able to a scalar type), + it is broadcast for use with each element of the other argument. + (See Examples) + + Parameters + ---------- + x1, x2 : array_like + Leg of the triangle(s). + $PARAMS + + Returns + ------- + z : ndarray + The hypotenuse of the triangle(s). + + Examples + -------- + >>> np.hypot(3*np.ones((3, 3)), 4*np.ones((3, 3))) + array([[ 5., 5., 5.], + [ 5., 5., 5.], + [ 5., 5., 5.]]) + + Example showing broadcast of scalar_like argument: + + >>> np.hypot(3*np.ones((3, 3)), [4]) + array([[ 5., 5., 5.], + [ 5., 5., 5.], + [ 5., 5., 5.]]) + + """) + +add_newdoc('numpy.core.umath', 'invert', + """ + Compute bit-wise inversion, or bit-wise NOT, element-wise. + + Computes the bit-wise NOT of the underlying binary representation of + the integers in the input arrays. This ufunc implements the C/Python + operator ``~``. + + For signed integer inputs, the two's complement is returned. In a + two's-complement system negative numbers are represented by the two's + complement of the absolute value. This is the most common method of + representing signed integers on computers [1]_. A N-bit + two's-complement system can represent every integer in the range + :math:`-2^{N-1}` to :math:`+2^{N-1}-1`. + + Parameters + ---------- + x : array_like + Only integer and boolean types are handled. + $PARAMS + + Returns + ------- + out : array_like + Result. + + See Also + -------- + bitwise_and, bitwise_or, bitwise_xor + logical_not + binary_repr : + Return the binary representation of the input number as a string. + + Notes + ----- + `bitwise_not` is an alias for `invert`: + + >>> np.bitwise_not is np.invert + True + + References + ---------- + .. [1] Wikipedia, "Two's complement", + http://en.wikipedia.org/wiki/Two's_complement + + Examples + -------- + We've seen that 13 is represented by ``00001101``. + The invert or bit-wise NOT of 13 is then: + + >>> np.invert(np.array([13], dtype=uint8)) + array([242], dtype=uint8) + >>> np.binary_repr(x, width=8) + '00001101' + >>> np.binary_repr(242, width=8) + '11110010' + + The result depends on the bit-width: + + >>> np.invert(np.array([13], dtype=uint16)) + array([65522], dtype=uint16) + >>> np.binary_repr(x, width=16) + '0000000000001101' + >>> np.binary_repr(65522, width=16) + '1111111111110010' + + When using signed integer types the result is the two's complement of + the result for the unsigned type: + + >>> np.invert(np.array([13], dtype=int8)) + array([-14], dtype=int8) + >>> np.binary_repr(-14, width=8) + '11110010' + + Booleans are accepted as well: + + >>> np.invert(array([True, False])) + array([False, True]) + + """) + +add_newdoc('numpy.core.umath', 'isfinite', + """ + Test element-wise for finiteness (not infinity or not Not a Number). + + The result is returned as a boolean array. + + Parameters + ---------- + x : array_like + Input values. + $PARAMS + + Returns + ------- + y : ndarray, bool + For scalar input, the result is a new boolean with value True + if the input is finite; otherwise the value is False (input is + either positive infinity, negative infinity or Not a Number). + + For array input, the result is a boolean array with the same + dimensions as the input and the values are True if the + corresponding element of the input is finite; otherwise the values + are False (element is either positive infinity, negative infinity + or Not a Number). + + See Also + -------- + isinf, isneginf, isposinf, isnan + + Notes + ----- + Not a Number, positive infinity and negative infinity are considered + to be non-finite. + + NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic + (IEEE 754). This means that Not a Number is not equivalent to infinity. + Also that positive infinity is not equivalent to negative infinity. But + infinity is equivalent to positive infinity. Errors result if the + second argument is also supplied when `x` is a scalar input, or if + first and second arguments have different shapes. + + Examples + -------- + >>> np.isfinite(1) + True + >>> np.isfinite(0) + True + >>> np.isfinite(np.nan) + False + >>> np.isfinite(np.inf) + False + >>> np.isfinite(np.NINF) + False + >>> np.isfinite([np.log(-1.),1.,np.log(0)]) + array([False, True, False]) + + >>> x = np.array([-np.inf, 0., np.inf]) + >>> y = np.array([2, 2, 2]) + >>> np.isfinite(x, y) + array([0, 1, 0]) + >>> y + array([0, 1, 0]) + + """) + +add_newdoc('numpy.core.umath', 'isinf', + """ + Test element-wise for positive or negative infinity. + + Returns a boolean array of the same shape as `x`, True where ``x == + +/-inf``, otherwise False. + + Parameters + ---------- + x : array_like + Input values + $PARAMS + + Returns + ------- + y : bool (scalar) or boolean ndarray + For scalar input, the result is a new boolean with value True if + the input is positive or negative infinity; otherwise the value is + False. + + For array input, the result is a boolean array with the same shape + as the input and the values are True where the corresponding + element of the input is positive or negative infinity; elsewhere + the values are False. If a second argument was 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, respectively. The return value `y` is then + a reference to that array. + + See Also + -------- + isneginf, isposinf, isnan, isfinite + + Notes + ----- + NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic + (IEEE 754). + + Errors result if the second argument is supplied when the first + argument is a scalar, or if the first and second arguments have + different shapes. + + Examples + -------- + >>> np.isinf(np.inf) + True + >>> np.isinf(np.nan) + False + >>> np.isinf(np.NINF) + True + >>> np.isinf([np.inf, -np.inf, 1.0, np.nan]) + array([ True, True, False, False]) + + >>> x = np.array([-np.inf, 0., np.inf]) + >>> y = np.array([2, 2, 2]) + >>> np.isinf(x, y) + array([1, 0, 1]) + >>> y + array([1, 0, 1]) + + """) + +add_newdoc('numpy.core.umath', 'isnan', + """ + Test element-wise for NaN and return result as a boolean array. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + y : ndarray or bool + For scalar input, the result is a new boolean with value True if + the input is NaN; otherwise the value is False. + + For array input, the result is a boolean array of the same + dimensions as the input and the values are True if the + corresponding element of the input is NaN; otherwise the values are + False. + + See Also + -------- + isinf, isneginf, isposinf, isfinite, isnat + + 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.isnan(np.nan) + True + >>> np.isnan(np.inf) + False + >>> np.isnan([np.log(-1.),1.,np.log(0)]) + array([ True, False, False]) + + """) + +add_newdoc('numpy.core.umath', 'isnat', + """ + Test element-wise for NaT (not a time) and return result as a boolean array. + + Parameters + ---------- + x : array_like + Input array with datetime or timedelta data type. + $PARAMS + + Returns + ------- + y : ndarray or bool + For scalar input, the result is a new boolean with value True if + the input is NaT; otherwise the value is False. + + For array input, the result is a boolean array of the same + dimensions as the input and the values are True if the + corresponding element of the input is NaT; otherwise the values are + False. + + See Also + -------- + isnan, isinf, isneginf, isposinf, isfinite + + Examples + -------- + >>> np.isnat(np.datetime64("NaT")) + True + >>> np.isnat(np.datetime64("2016-01-01")) + False + >>> np.isnat(np.array(["NaT", "2016-01-01"], dtype="datetime64[ns]")) + array([ True, False]) + + """) + +add_newdoc('numpy.core.umath', 'left_shift', + """ + Shift the bits of an integer to the left. + + Bits are shifted to the left by appending `x2` 0s at the right of `x1`. + Since the internal representation of numbers is in binary format, this + operation is equivalent to multiplying `x1` by ``2**x2``. + + Parameters + ---------- + x1 : array_like of integer type + Input values. + x2 : array_like of integer type + Number of zeros to append to `x1`. Has to be non-negative. + $PARAMS + + Returns + ------- + out : array of integer type + Return `x1` with bits shifted `x2` times to the left. + + See Also + -------- + right_shift : Shift the bits of an integer to the right. + binary_repr : Return the binary representation of the input number + as a string. + + Examples + -------- + >>> np.binary_repr(5) + '101' + >>> np.left_shift(5, 2) + 20 + >>> np.binary_repr(20) + '10100' + + >>> np.left_shift(5, [1,2,3]) + array([10, 20, 40]) + + """) + +add_newdoc('numpy.core.umath', 'less', + """ + Return the truth value of (x1 < x2) element-wise. + + Parameters + ---------- + x1, x2 : array_like + Input arrays. If ``x1.shape != x2.shape``, they must be + broadcastable to a common shape (which may be the shape of one or + the other). + $PARAMS + + Returns + ------- + out : bool or ndarray of bool + Array of bools, or a single bool if `x1` and `x2` are scalars. + + See Also + -------- + greater, less_equal, greater_equal, equal, not_equal + + Examples + -------- + >>> np.less([1, 2], [2, 2]) + array([ True, False]) + + """) + +add_newdoc('numpy.core.umath', 'less_equal', + """ + Return the truth value of (x1 =< x2) element-wise. + + Parameters + ---------- + x1, x2 : array_like + Input arrays. If ``x1.shape != x2.shape``, they must be + broadcastable to a common shape (which may be the shape of one or + the other). + $PARAMS + + Returns + ------- + out : bool or ndarray of bool + Array of bools, or a single bool if `x1` and `x2` are scalars. + + See Also + -------- + greater, less, greater_equal, equal, not_equal + + Examples + -------- + >>> np.less_equal([4, 2, 1], [2, 2, 2]) + array([False, True, True]) + + """) + +add_newdoc('numpy.core.umath', 'log', + """ + Natural logarithm, element-wise. + + The natural logarithm `log` is the inverse of the exponential function, + so that `log(exp(x)) = x`. The natural logarithm is logarithm in base + `e`. + + Parameters + ---------- + x : array_like + Input value. + $PARAMS + + Returns + ------- + y : ndarray + The natural logarithm of `x`, element-wise. + + See Also + -------- + log10, log2, log1p, emath.log + + Notes + ----- + Logarithm is a multivalued function: for each `x` there is an infinite + number of `z` such that `exp(z) = x`. The convention is to return the + `z` whose imaginary part lies in `[-pi, pi]`. + + For real-valued input data types, `log` always returns real output. For + each value that cannot be expressed as a real number or infinity, it + yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `log` is a complex analytical function that + has a branch cut `[-inf, 0]` and is continuous from above on it. `log` + handles the floating-point negative zero as an infinitesimal negative + number, conforming to the C99 standard. + + References + ---------- + .. [1] M. Abramowitz and I.A. Stegun, "Handbook of Mathematical Functions", + 10th printing, 1964, pp. 67. http://www.math.sfu.ca/~cbm/aands/ + .. [2] Wikipedia, "Logarithm". http://en.wikipedia.org/wiki/Logarithm + + Examples + -------- + >>> np.log([1, np.e, np.e**2, 0]) + array([ 0., 1., 2., -Inf]) + + """) + +add_newdoc('numpy.core.umath', 'log10', + """ + Return the base 10 logarithm of the input array, element-wise. + + Parameters + ---------- + x : array_like + Input values. + $PARAMS + + Returns + ------- + y : ndarray + The logarithm to the base 10 of `x`, element-wise. NaNs are + returned where x is negative. + + See Also + -------- + emath.log10 + + Notes + ----- + Logarithm is a multivalued function: for each `x` there is an infinite + number of `z` such that `10**z = x`. The convention is to return the + `z` whose imaginary part lies in `[-pi, pi]`. + + For real-valued input data types, `log10` always returns real output. + For each value that cannot be expressed as a real number or infinity, + it yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `log10` is a complex analytical function that + has a branch cut `[-inf, 0]` and is continuous from above on it. + `log10` handles the floating-point negative zero as an infinitesimal + negative number, conforming to the C99 standard. + + References + ---------- + .. [1] M. Abramowitz and I.A. Stegun, "Handbook of Mathematical Functions", + 10th printing, 1964, pp. 67. http://www.math.sfu.ca/~cbm/aands/ + .. [2] Wikipedia, "Logarithm". http://en.wikipedia.org/wiki/Logarithm + + Examples + -------- + >>> np.log10([1e-15, -3.]) + array([-15., NaN]) + + """) + +add_newdoc('numpy.core.umath', 'log2', + """ + Base-2 logarithm of `x`. + + Parameters + ---------- + x : array_like + Input values. + $PARAMS + + Returns + ------- + y : ndarray + Base-2 logarithm of `x`. + + See Also + -------- + log, log10, log1p, emath.log2 + + Notes + ----- + .. versionadded:: 1.3.0 + + Logarithm is a multivalued function: for each `x` there is an infinite + number of `z` such that `2**z = x`. The convention is to return the `z` + whose imaginary part lies in `[-pi, pi]`. + + For real-valued input data types, `log2` always returns real output. + For each value that cannot be expressed as a real number or infinity, + it yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `log2` is a complex analytical function that + has a branch cut `[-inf, 0]` and is continuous from above on it. `log2` + handles the floating-point negative zero as an infinitesimal negative + number, conforming to the C99 standard. + + Examples + -------- + >>> x = np.array([0, 1, 2, 2**4]) + >>> np.log2(x) + array([-Inf, 0., 1., 4.]) + + >>> xi = np.array([0+1.j, 1, 2+0.j, 4.j]) + >>> np.log2(xi) + array([ 0.+2.26618007j, 0.+0.j , 1.+0.j , 2.+2.26618007j]) + + """) + +add_newdoc('numpy.core.umath', 'logaddexp', + """ + Logarithm of the sum of exponentiations of the inputs. + + Calculates ``log(exp(x1) + exp(x2))``. This function is useful in + statistics where the calculated probabilities of events may be so small + as to exceed the range of normal floating point numbers. In such cases + the logarithm of the calculated probability is stored. This function + allows adding probabilities stored in such a fashion. + + Parameters + ---------- + x1, x2 : array_like + Input values. + $PARAMS + + Returns + ------- + result : ndarray + Logarithm of ``exp(x1) + exp(x2)``. + + See Also + -------- + logaddexp2: Logarithm of the sum of exponentiations of inputs in base 2. + + Notes + ----- + .. versionadded:: 1.3.0 + + Examples + -------- + >>> prob1 = np.log(1e-50) + >>> prob2 = np.log(2.5e-50) + >>> prob12 = np.logaddexp(prob1, prob2) + >>> prob12 + -113.87649168120691 + >>> np.exp(prob12) + 3.5000000000000057e-50 + + """) + +add_newdoc('numpy.core.umath', 'logaddexp2', + """ + Logarithm of the sum of exponentiations of the inputs in base-2. + + Calculates ``log2(2**x1 + 2**x2)``. This function is useful in machine + learning when the calculated probabilities of events may be so small as + to exceed the range of normal floating point numbers. In such cases + the base-2 logarithm of the calculated probability can be used instead. + This function allows adding probabilities stored in such a fashion. + + Parameters + ---------- + x1, x2 : array_like + Input values. + $PARAMS + + Returns + ------- + result : ndarray + Base-2 logarithm of ``2**x1 + 2**x2``. + + See Also + -------- + logaddexp: Logarithm of the sum of exponentiations of the inputs. + + Notes + ----- + .. versionadded:: 1.3.0 + + Examples + -------- + >>> prob1 = np.log2(1e-50) + >>> prob2 = np.log2(2.5e-50) + >>> prob12 = np.logaddexp2(prob1, prob2) + >>> prob1, prob2, prob12 + (-166.09640474436813, -164.77447664948076, -164.28904982231052) + >>> 2**prob12 + 3.4999999999999914e-50 + + """) + +add_newdoc('numpy.core.umath', 'log1p', + """ + Return the natural logarithm of one plus the input array, element-wise. + + Calculates ``log(1 + x)``. + + Parameters + ---------- + x : array_like + Input values. + $PARAMS + + Returns + ------- + y : ndarray + Natural logarithm of `1 + x`, element-wise. + + See Also + -------- + expm1 : ``exp(x) - 1``, the inverse of `log1p`. + + Notes + ----- + For real-valued input, `log1p` is accurate also for `x` so small + that `1 + x == 1` in floating-point accuracy. + + Logarithm is a multivalued function: for each `x` there is an infinite + number of `z` such that `exp(z) = 1 + x`. The convention is to return + the `z` whose imaginary part lies in `[-pi, pi]`. + + For real-valued input data types, `log1p` always returns real output. + For each value that cannot be expressed as a real number or infinity, + it yields ``nan`` and sets the `invalid` floating point error flag. + + For complex-valued input, `log1p` is a complex analytical function that + has a branch cut `[-inf, -1]` and is continuous from above on it. + `log1p` handles the floating-point negative zero as an infinitesimal + negative number, conforming to the C99 standard. + + References + ---------- + .. [1] M. Abramowitz and I.A. Stegun, "Handbook of Mathematical Functions", + 10th printing, 1964, pp. 67. http://www.math.sfu.ca/~cbm/aands/ + .. [2] Wikipedia, "Logarithm". http://en.wikipedia.org/wiki/Logarithm + + Examples + -------- + >>> np.log1p(1e-99) + 1e-99 + >>> np.log(1 + 1e-99) + 0.0 + + """) + +add_newdoc('numpy.core.umath', 'logical_and', + """ + Compute the truth value of x1 AND x2 element-wise. + + Parameters + ---------- + x1, x2 : array_like + Input arrays. `x1` and `x2` must be of the same shape. + $PARAMS + + Returns + ------- + y : ndarray or bool + Boolean result with the same shape as `x1` and `x2` of the logical + AND operation on corresponding elements of `x1` and `x2`. + + See Also + -------- + logical_or, logical_not, logical_xor + bitwise_and + + Examples + -------- + >>> np.logical_and(True, False) + False + >>> np.logical_and([True, False], [False, False]) + array([False, False]) + + >>> x = np.arange(5) + >>> np.logical_and(x>1, x<4) + array([False, False, True, True, False]) + + """) + +add_newdoc('numpy.core.umath', 'logical_not', + """ + Compute the truth value of NOT x element-wise. + + Parameters + ---------- + x : array_like + Logical NOT is applied to the elements of `x`. + $PARAMS + + Returns + ------- + y : bool or ndarray of bool + Boolean result with the same shape as `x` of the NOT operation + on elements of `x`. + + See Also + -------- + logical_and, logical_or, logical_xor + + Examples + -------- + >>> np.logical_not(3) + False + >>> np.logical_not([True, False, 0, 1]) + array([False, True, True, False]) + + >>> x = np.arange(5) + >>> np.logical_not(x<3) + array([False, False, False, True, True]) + + """) + +add_newdoc('numpy.core.umath', 'logical_or', + """ + Compute the truth value of x1 OR x2 element-wise. + + Parameters + ---------- + x1, x2 : array_like + Logical OR is applied to the elements of `x1` and `x2`. + They have to be of the same shape. + $PARAMS + + Returns + ------- + y : ndarray or bool + Boolean result with the same shape as `x1` and `x2` of the logical + OR operation on elements of `x1` and `x2`. + + See Also + -------- + logical_and, logical_not, logical_xor + bitwise_or + + Examples + -------- + >>> np.logical_or(True, False) + True + >>> np.logical_or([True, False], [False, False]) + array([ True, False]) + + >>> x = np.arange(5) + >>> np.logical_or(x < 1, x > 3) + array([ True, False, False, False, True]) + + """) + +add_newdoc('numpy.core.umath', 'logical_xor', + """ + Compute the truth value of x1 XOR x2, element-wise. + + Parameters + ---------- + x1, x2 : array_like + Logical XOR is applied to the elements of `x1` and `x2`. They must + be broadcastable to the same shape. + $PARAMS + + Returns + ------- + y : bool or ndarray of bool + Boolean result of the logical XOR operation applied to the elements + of `x1` and `x2`; the shape is determined by whether or not + broadcasting of one or both arrays was required. + + See Also + -------- + logical_and, logical_or, logical_not, bitwise_xor + + Examples + -------- + >>> np.logical_xor(True, False) + True + >>> np.logical_xor([True, True, False, False], [True, False, True, False]) + array([False, True, True, False]) + + >>> x = np.arange(5) + >>> np.logical_xor(x < 1, x > 3) + array([ True, False, False, False, True]) + + Simple example showing support of broadcasting + + >>> np.logical_xor(0, np.eye(2)) + array([[ True, False], + [False, True]]) + + """) + +add_newdoc('numpy.core.umath', 'maximum', + """ + Element-wise maximum of array elements. + + Compare two arrays and returns a new array containing the element-wise + maxima. If one of the elements being compared is a NaN, then that + element is returned. If both elements are NaNs then the first is + returned. The latter distinction is important for complex NaNs, which + are defined as at least one of the real or imaginary parts being a NaN. + The net effect is that NaNs are propagated. + + Parameters + ---------- + x1, x2 : array_like + The arrays holding the elements to be compared. They must have + the same shape, or shapes that can be broadcast to a single shape. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The maximum of `x1` and `x2`, element-wise. Returns scalar if + both `x1` and `x2` are scalars. + + See Also + -------- + minimum : + Element-wise minimum of two arrays, propagates NaNs. + fmax : + Element-wise maximum of two arrays, ignores NaNs. + amax : + The maximum value of an array along a given axis, propagates NaNs. + nanmax : + The maximum value of an array along a given axis, ignores NaNs. + + fmin, amin, nanmin + + Notes + ----- + The maximum is equivalent to ``np.where(x1 >= x2, x1, x2)`` when + neither x1 nor x2 are nans, but it is faster and does proper + broadcasting. + + Examples + -------- + >>> np.maximum([2, 3, 4], [1, 5, 2]) + array([2, 5, 4]) + + >>> np.maximum(np.eye(2), [0.5, 2]) # broadcasting + array([[ 1. , 2. ], + [ 0.5, 2. ]]) + + >>> np.maximum([np.nan, 0, np.nan], [0, np.nan, np.nan]) + array([ NaN, NaN, NaN]) + >>> np.maximum(np.Inf, 1) + inf + + """) + +add_newdoc('numpy.core.umath', 'minimum', + """ + Element-wise minimum of array elements. + + Compare two arrays and returns a new array containing the element-wise + minima. If one of the elements being compared is a NaN, then that + element is returned. If both elements are NaNs then the first is + returned. The latter distinction is important for complex NaNs, which + are defined as at least one of the real or imaginary parts being a NaN. + The net effect is that NaNs are propagated. + + Parameters + ---------- + x1, x2 : array_like + The arrays holding the elements to be compared. They must have + the same shape, or shapes that can be broadcast to a single shape. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The minimum of `x1` and `x2`, element-wise. Returns scalar if + both `x1` and `x2` are scalars. + + See Also + -------- + maximum : + Element-wise maximum of two arrays, propagates NaNs. + fmin : + Element-wise minimum of two arrays, ignores NaNs. + amin : + The minimum value of an array along a given axis, propagates NaNs. + nanmin : + The minimum value of an array along a given axis, ignores NaNs. + + fmax, amax, nanmax + + Notes + ----- + The minimum is equivalent to ``np.where(x1 <= x2, x1, x2)`` when + neither x1 nor x2 are NaNs, but it is faster and does proper + broadcasting. + + Examples + -------- + >>> np.minimum([2, 3, 4], [1, 5, 2]) + array([1, 3, 2]) + + >>> np.minimum(np.eye(2), [0.5, 2]) # broadcasting + array([[ 0.5, 0. ], + [ 0. , 1. ]]) + + >>> np.minimum([np.nan, 0, np.nan],[0, np.nan, np.nan]) + array([ NaN, NaN, NaN]) + >>> np.minimum(-np.Inf, 1) + -inf + + """) + +add_newdoc('numpy.core.umath', 'fmax', + """ + Element-wise maximum of array elements. + + Compare two arrays and returns a new array containing the element-wise + maxima. If one of the elements being compared is a NaN, then the + non-nan element is returned. If both elements are NaNs then the first + is returned. The latter distinction is important for complex NaNs, + which are defined as at least one of the real or imaginary parts being + a NaN. The net effect is that NaNs are ignored when possible. + + Parameters + ---------- + x1, x2 : array_like + The arrays holding the elements to be compared. They must have + the same shape. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The maximum of `x1` and `x2`, element-wise. Returns scalar if + both `x1` and `x2` are scalars. + + See Also + -------- + fmin : + Element-wise minimum of two arrays, ignores NaNs. + maximum : + Element-wise maximum of two arrays, propagates NaNs. + amax : + The maximum value of an array along a given axis, propagates NaNs. + nanmax : + The maximum value of an array along a given axis, ignores NaNs. + + minimum, amin, nanmin + + Notes + ----- + .. versionadded:: 1.3.0 + + The fmax is equivalent to ``np.where(x1 >= x2, x1, x2)`` when neither + x1 nor x2 are NaNs, but it is faster and does proper broadcasting. + + Examples + -------- + >>> np.fmax([2, 3, 4], [1, 5, 2]) + array([ 2., 5., 4.]) + + >>> np.fmax(np.eye(2), [0.5, 2]) + array([[ 1. , 2. ], + [ 0.5, 2. ]]) + + >>> np.fmax([np.nan, 0, np.nan],[0, np.nan, np.nan]) + array([ 0., 0., NaN]) + + """) + +add_newdoc('numpy.core.umath', 'fmin', + """ + Element-wise minimum of array elements. + + Compare two arrays and returns a new array containing the element-wise + minima. If one of the elements being compared is a NaN, then the + non-nan element is returned. If both elements are NaNs then the first + is returned. The latter distinction is important for complex NaNs, + which are defined as at least one of the real or imaginary parts being + a NaN. The net effect is that NaNs are ignored when possible. + + Parameters + ---------- + x1, x2 : array_like + The arrays holding the elements to be compared. They must have + the same shape. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The minimum of `x1` and `x2`, element-wise. Returns scalar if + both `x1` and `x2` are scalars. + + See Also + -------- + fmax : + Element-wise maximum of two arrays, ignores NaNs. + minimum : + Element-wise minimum of two arrays, propagates NaNs. + amin : + The minimum value of an array along a given axis, propagates NaNs. + nanmin : + The minimum value of an array along a given axis, ignores NaNs. + + maximum, amax, nanmax + + Notes + ----- + .. versionadded:: 1.3.0 + + The fmin is equivalent to ``np.where(x1 <= x2, x1, x2)`` when neither + x1 nor x2 are NaNs, but it is faster and does proper broadcasting. + + Examples + -------- + >>> np.fmin([2, 3, 4], [1, 5, 2]) + array([1, 3, 2]) + + >>> np.fmin(np.eye(2), [0.5, 2]) + array([[ 0.5, 0. ], + [ 0. , 1. ]]) + + >>> np.fmin([np.nan, 0, np.nan],[0, np.nan, np.nan]) + array([ 0., 0., NaN]) + + """) + +add_newdoc('numpy.core.umath', 'modf', + """ + Return the fractional and integral parts of an array, element-wise. + + The fractional and integral parts are negative if the given number is + negative. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + y1 : ndarray + Fractional part of `x`. + y2 : ndarray + Integral part of `x`. + + Notes + ----- + For integer input the return values are floats. + + See Also + -------- + divmod : ``divmod(x, 1)`` is equivalent to ``modf`` with the return values + switched, except it always has a positive remainder. + + Examples + -------- + >>> np.modf([0, 3.5]) + (array([ 0. , 0.5]), array([ 0., 3.])) + >>> np.modf(-0.5) + (-0.5, -0) + + """) + +add_newdoc('numpy.core.umath', 'multiply', + """ + Multiply arguments element-wise. + + Parameters + ---------- + x1, x2 : array_like + Input arrays to be multiplied. + $PARAMS + + Returns + ------- + y : ndarray + The product of `x1` and `x2`, element-wise. Returns a scalar if + both `x1` and `x2` are scalars. + + Notes + ----- + Equivalent to `x1` * `x2` in terms of array broadcasting. + + Examples + -------- + >>> np.multiply(2.0, 4.0) + 8.0 + + >>> x1 = np.arange(9.0).reshape((3, 3)) + >>> x2 = np.arange(3.0) + >>> np.multiply(x1, x2) + array([[ 0., 1., 4.], + [ 0., 4., 10.], + [ 0., 7., 16.]]) + + """) + +add_newdoc('numpy.core.umath', 'negative', + """ + Numerical negative, element-wise. + + Parameters + ---------- + x : array_like or scalar + Input array. + $PARAMS + + Returns + ------- + y : ndarray or scalar + Returned array or scalar: `y = -x`. + + Examples + -------- + >>> np.negative([1.,-1.]) + array([-1., 1.]) + + """) + +add_newdoc('numpy.core.umath', 'positive', + """ + Numerical positive, element-wise. + + .. versionadded:: 1.13.0 + + Parameters + ---------- + x : array_like or scalar + Input array. + + Returns + ------- + y : ndarray or scalar + Returned array or scalar: `y = +x`. + + Notes + ----- + Equivalent to `x.copy()`, but only defined for types that support + arithmetic. + + """) + +add_newdoc('numpy.core.umath', 'not_equal', + """ + Return (x1 != x2) element-wise. + + Parameters + ---------- + x1, x2 : array_like + Input arrays. + $PARAMS + + Returns + ------- + not_equal : ndarray bool, scalar bool + For each element in `x1, x2`, return True if `x1` is not equal + to `x2` and False otherwise. + + + See Also + -------- + equal, greater, greater_equal, less, less_equal + + Examples + -------- + >>> np.not_equal([1.,2.], [1., 3.]) + array([False, True]) + >>> np.not_equal([1, 2], [[1, 3],[1, 4]]) + array([[False, True], + [False, True]]) + + """) + +add_newdoc('numpy.core.umath', '_ones_like', + """ + This function used to be the numpy.ones_like, but now a specific + function for that has been written for consistency with the other + *_like functions. It is only used internally in a limited fashion now. + + See Also + -------- + ones_like + + """) + +add_newdoc('numpy.core.umath', 'power', + """ + First array elements raised to powers from second array, element-wise. + + Raise each base in `x1` to the positionally-corresponding power in + `x2`. `x1` and `x2` must be broadcastable to the same shape. Note that an + integer type raised to a negative integer power will raise a ValueError. + + Parameters + ---------- + x1 : array_like + The bases. + x2 : array_like + The exponents. + $PARAMS + + Returns + ------- + y : ndarray + The bases in `x1` raised to the exponents in `x2`. + + See Also + -------- + float_power : power function that promotes integers to float + + Examples + -------- + Cube each element in a list. + + >>> x1 = range(6) + >>> x1 + [0, 1, 2, 3, 4, 5] + >>> np.power(x1, 3) + array([ 0, 1, 8, 27, 64, 125]) + + Raise the bases to different exponents. + + >>> x2 = [1.0, 2.0, 3.0, 3.0, 2.0, 1.0] + >>> np.power(x1, x2) + array([ 0., 1., 8., 27., 16., 5.]) + + The effect of broadcasting. + + >>> x2 = np.array([[1, 2, 3, 3, 2, 1], [1, 2, 3, 3, 2, 1]]) + >>> x2 + array([[1, 2, 3, 3, 2, 1], + [1, 2, 3, 3, 2, 1]]) + >>> np.power(x1, x2) + array([[ 0, 1, 8, 27, 16, 5], + [ 0, 1, 8, 27, 16, 5]]) + + """) + +add_newdoc('numpy.core.umath', 'float_power', + """ + First array elements raised to powers from second array, element-wise. + + Raise each base in `x1` to the positionally-corresponding power in `x2`. + `x1` and `x2` must be broadcastable to the same shape. This differs from + the power function in that integers, float16, and float32 are promoted to + floats with a minimum precision of float64 so that the result is always + inexact. The intent is that the function will return a usable result for + negative powers and seldom overflow for positive powers. + + .. versionadded:: 1.12.0 + + Parameters + ---------- + x1 : array_like + The bases. + x2 : array_like + The exponents. + $PARAMS + + Returns + ------- + y : ndarray + The bases in `x1` raised to the exponents in `x2`. + + See Also + -------- + power : power function that preserves type + + Examples + -------- + Cube each element in a list. + + >>> x1 = range(6) + >>> x1 + [0, 1, 2, 3, 4, 5] + >>> np.float_power(x1, 3) + array([ 0., 1., 8., 27., 64., 125.]) + + Raise the bases to different exponents. + + >>> x2 = [1.0, 2.0, 3.0, 3.0, 2.0, 1.0] + >>> np.float_power(x1, x2) + array([ 0., 1., 8., 27., 16., 5.]) + + The effect of broadcasting. + + >>> x2 = np.array([[1, 2, 3, 3, 2, 1], [1, 2, 3, 3, 2, 1]]) + >>> x2 + array([[1, 2, 3, 3, 2, 1], + [1, 2, 3, 3, 2, 1]]) + >>> np.float_power(x1, x2) + array([[ 0., 1., 8., 27., 16., 5.], + [ 0., 1., 8., 27., 16., 5.]]) + + """) + +add_newdoc('numpy.core.umath', 'radians', + """ + Convert angles from degrees to radians. + + Parameters + ---------- + x : array_like + Input array in degrees. + $PARAMS + + Returns + ------- + y : ndarray + The corresponding radian values. + + See Also + -------- + deg2rad : equivalent function + + Examples + -------- + Convert a degree array to radians + + >>> deg = np.arange(12.) * 30. + >>> np.radians(deg) + array([ 0. , 0.52359878, 1.04719755, 1.57079633, 2.0943951 , + 2.61799388, 3.14159265, 3.66519143, 4.1887902 , 4.71238898, + 5.23598776, 5.75958653]) + + >>> out = np.zeros((deg.shape)) + >>> ret = np.radians(deg, out) + >>> ret is out + True + + """) + +add_newdoc('numpy.core.umath', 'deg2rad', + """ + Convert angles from degrees to radians. + + Parameters + ---------- + x : array_like + Angles in degrees. + $PARAMS + + Returns + ------- + y : ndarray + The corresponding angle in radians. + + See Also + -------- + rad2deg : Convert angles from radians to degrees. + unwrap : Remove large jumps in angle by wrapping. + + Notes + ----- + .. versionadded:: 1.3.0 + + ``deg2rad(x)`` is ``x * pi / 180``. + + Examples + -------- + >>> np.deg2rad(180) + 3.1415926535897931 + + """) + +add_newdoc('numpy.core.umath', 'reciprocal', + """ + Return the reciprocal of the argument, element-wise. + + Calculates ``1/x``. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + y : ndarray + Return array. + + Notes + ----- + .. note:: + This function is not designed to work with integers. + + For integer arguments with absolute value larger than 1 the result is + always zero because of the way Python handles integer division. For + integer zero the result is an overflow. + + Examples + -------- + >>> np.reciprocal(2.) + 0.5 + >>> np.reciprocal([1, 2., 3.33]) + array([ 1. , 0.5 , 0.3003003]) + + """) + +add_newdoc('numpy.core.umath', 'remainder', + """ + Return element-wise remainder of division. + + Computes the remainder complementary to the `floor_divide` function. It is + equivalent to the Python modulus operator``x1 % x2`` and has the same sign + as the divisor `x2`. The MATLAB function equivalent to ``np.remainder`` + is ``mod``. + + .. warning:: + + This should not be confused with: + + * Python 3.7's `math.remainder` and C's ``remainder``, which + computes the IEEE remainder, which are the complement to + ``round(x1 / x2)``. + * The MATLAB ``rem`` function and or the C ``%`` operator which is the + complement to ``int(x1 / x2)``. + + Parameters + ---------- + x1 : array_like + Dividend array. + x2 : array_like + Divisor array. + $PARAMS + + Returns + ------- + y : ndarray + The element-wise remainder of the quotient ``floor_divide(x1, x2)``. + Returns a scalar if both `x1` and `x2` are scalars. + + See Also + -------- + floor_divide : Equivalent of Python ``//`` operator. + divmod : Simultaneous floor division and remainder. + fmod : Equivalent of the MATLAB ``rem`` function. + divide, floor + + Notes + ----- + Returns 0 when `x2` is 0 and both `x1` and `x2` are (arrays of) + integers. + + Examples + -------- + >>> np.remainder([4, 7], [2, 3]) + array([0, 1]) + >>> np.remainder(np.arange(7), 5) + array([0, 1, 2, 3, 4, 0, 1]) + + """) + +add_newdoc('numpy.core.umath', 'divmod', + """ + Return element-wise quotient and remainder simultaneously. + + .. versionadded:: 1.13.0 + + ``np.divmod(x, y)`` is equivalent to ``(x // y, x % y)``, but faster + because it avoids redundant work. It is used to implement the Python + built-in function ``divmod`` on NumPy arrays. + + Parameters + ---------- + x1 : array_like + Dividend array. + x2 : array_like + Divisor array. + $PARAMS + + Returns + ------- + out1 : ndarray + Element-wise quotient resulting from floor division. + out2 : ndarray + Element-wise remainder from floor division. + + See Also + -------- + floor_divide : Equivalent to Python's ``//`` operator. + remainder : Equivalent to Python's ``%`` operator. + modf : Equivalent to ``divmod(x, 1)`` for positive ``x`` with the return + values switched. + + Examples + -------- + >>> np.divmod(np.arange(5), 3) + (array([0, 0, 0, 1, 1]), array([0, 1, 2, 0, 1])) + + """) + +add_newdoc('numpy.core.umath', 'right_shift', + """ + Shift the bits of an integer to the right. + + Bits are shifted to the right `x2`. Because the internal + representation of numbers is in binary format, this operation is + equivalent to dividing `x1` by ``2**x2``. + + Parameters + ---------- + x1 : array_like, int + Input values. + x2 : array_like, int + Number of bits to remove at the right of `x1`. + $PARAMS + + Returns + ------- + out : ndarray, int + Return `x1` with bits shifted `x2` times to the right. + + See Also + -------- + left_shift : Shift the bits of an integer to the left. + binary_repr : Return the binary representation of the input number + as a string. + + Examples + -------- + >>> np.binary_repr(10) + '1010' + >>> np.right_shift(10, 1) + 5 + >>> np.binary_repr(5) + '101' + + >>> np.right_shift(10, [1,2,3]) + array([5, 2, 1]) + + """) + +add_newdoc('numpy.core.umath', 'rint', + """ + Round elements of the array to the nearest integer. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + out : ndarray or scalar + Output array is same shape and type as `x`. + + See Also + -------- + ceil, floor, trunc + + Examples + -------- + >>> a = np.array([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]) + >>> np.rint(a) + array([-2., -2., -0., 0., 2., 2., 2.]) + + """) + +add_newdoc('numpy.core.umath', 'sign', + """ + Returns an element-wise indication of the sign of a number. + + The `sign` function returns ``-1 if x < 0, 0 if x==0, 1 if x > 0``. nan + is returned for nan inputs. + + For complex inputs, the `sign` function returns + ``sign(x.real) + 0j if x.real != 0 else sign(x.imag) + 0j``. + + complex(nan, 0) is returned for complex nan inputs. + + Parameters + ---------- + x : array_like + Input values. + $PARAMS + + Returns + ------- + y : ndarray + The sign of `x`. + + Notes + ----- + There is more than one definition of sign in common use for complex + numbers. The definition used here is equivalent to :math:`x/\\sqrt{x*x}` + which is different from a common alternative, :math:`x/|x|`. + + Examples + -------- + >>> np.sign([-5., 4.5]) + array([-1., 1.]) + >>> np.sign(0) + 0 + >>> np.sign(5-2j) + (1+0j) + + """) + +add_newdoc('numpy.core.umath', 'signbit', + """ + Returns element-wise True where signbit is set (less than zero). + + Parameters + ---------- + x : array_like + The input value(s). + $PARAMS + + Returns + ------- + result : ndarray of bool + Output array, or reference to `out` if that was supplied. + + Examples + -------- + >>> np.signbit(-1.2) + True + >>> np.signbit(np.array([1, -2.3, 2.1])) + array([False, True, False]) + + """) + +add_newdoc('numpy.core.umath', 'copysign', + """ + Change the sign of x1 to that of x2, element-wise. + + If both arguments are arrays or sequences, they have to be of the same + length. If `x2` is a scalar, its sign will be copied to all elements of + `x1`. + + Parameters + ---------- + x1 : array_like + Values to change the sign of. + x2 : array_like + The sign of `x2` is copied to `x1`. + $PARAMS + + Returns + ------- + out : array_like + The values of `x1` with the sign of `x2`. + + Examples + -------- + >>> np.copysign(1.3, -1) + -1.3 + >>> 1/np.copysign(0, 1) + inf + >>> 1/np.copysign(0, -1) + -inf + + >>> np.copysign([-1, 0, 1], -1.1) + array([-1., -0., -1.]) + >>> np.copysign([-1, 0, 1], np.arange(3)-1) + array([-1., 0., 1.]) + + """) + +add_newdoc('numpy.core.umath', 'nextafter', + """ + Return the next floating-point value after x1 towards x2, element-wise. + + Parameters + ---------- + x1 : array_like + Values to find the next representable value of. + x2 : array_like + The direction where to look for the next representable value of `x1`. + $PARAMS + + Returns + ------- + out : array_like + The next representable values of `x1` in the direction of `x2`. + + Examples + -------- + >>> eps = np.finfo(np.float64).eps + >>> np.nextafter(1, 2) == eps + 1 + True + >>> np.nextafter([1, 2], [2, 1]) == [eps + 1, 2 - eps] + array([ True, True]) + + """) + +add_newdoc('numpy.core.umath', 'spacing', + """ + Return the distance between x and the nearest adjacent number. + + Parameters + ---------- + x : array_like + Values to find the spacing of. + $PARAMS + + Returns + ------- + out : array_like + The spacing of values of `x1`. + + Notes + ----- + It can be considered as a generalization of EPS: + ``spacing(np.float64(1)) == np.finfo(np.float64).eps``, and there + should not be any representable number between ``x + spacing(x)`` and + x for any finite x. + + Spacing of +- inf and NaN is NaN. + + Examples + -------- + >>> np.spacing(1) == np.finfo(np.float64).eps + True + + """) + +add_newdoc('numpy.core.umath', 'sin', + """ + Trigonometric sine, element-wise. + + Parameters + ---------- + x : array_like + Angle, in radians (:math:`2 \\pi` rad equals 360 degrees). + $PARAMS + + Returns + ------- + y : array_like + The sine of each element of x. + + See Also + -------- + arcsin, sinh, cos + + Notes + ----- + The sine is one of the fundamental functions of trigonometry (the + mathematical study of triangles). Consider a circle of radius 1 + centered on the origin. A ray comes in from the :math:`+x` axis, makes + an angle at the origin (measured counter-clockwise from that axis), and + departs from the origin. The :math:`y` coordinate of the outgoing + ray's intersection with the unit circle is the sine of that angle. It + ranges from -1 for :math:`x=3\\pi / 2` to +1 for :math:`\\pi / 2.` The + function has zeroes where the angle is a multiple of :math:`\\pi`. + Sines of angles between :math:`\\pi` and :math:`2\\pi` are negative. + The numerous properties of the sine and related functions are included + in any standard trigonometry text. + + Examples + -------- + Print sine of one angle: + + >>> np.sin(np.pi/2.) + 1.0 + + Print sines of an array of angles given in degrees: + + >>> np.sin(np.array((0., 30., 45., 60., 90.)) * np.pi / 180. ) + array([ 0. , 0.5 , 0.70710678, 0.8660254 , 1. ]) + + Plot the sine function: + + >>> import matplotlib.pylab as plt + >>> x = np.linspace(-np.pi, np.pi, 201) + >>> plt.plot(x, np.sin(x)) + >>> plt.xlabel('Angle [rad]') + >>> plt.ylabel('sin(x)') + >>> plt.axis('tight') + >>> plt.show() + + """) + +add_newdoc('numpy.core.umath', 'sinh', + """ + Hyperbolic sine, element-wise. + + Equivalent to ``1/2 * (np.exp(x) - np.exp(-x))`` or + ``-1j * np.sin(1j*x)``. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + y : ndarray + The corresponding hyperbolic sine values. + + Notes + ----- + If `out` is provided, the function writes the result into it, + and returns a reference to `out`. (See Examples) + + References + ---------- + M. Abramowitz and I. A. Stegun, Handbook of Mathematical Functions. + New York, NY: Dover, 1972, pg. 83. + + Examples + -------- + >>> np.sinh(0) + 0.0 + >>> np.sinh(np.pi*1j/2) + 1j + >>> np.sinh(np.pi*1j) # (exact value is 0) + 1.2246063538223773e-016j + >>> # Discrepancy due to vagaries of floating point arithmetic. + + >>> # Example of providing the optional output parameter + >>> out2 = np.sinh([0.1], out1) + >>> out2 is out1 + True + + >>> # Example of ValueError due to provision of shape mis-matched `out` + >>> np.sinh(np.zeros((3,3)),np.zeros((2,2))) + Traceback (most recent call last): + File "", line 1, in + ValueError: invalid return array shape + + """) + +add_newdoc('numpy.core.umath', 'sqrt', + """ + Return the positive square-root of an array, element-wise. + + Parameters + ---------- + x : array_like + The values whose square-roots are required. + $PARAMS + + Returns + ------- + y : ndarray + An array of the same shape as `x`, containing the positive + square-root of each element in `x`. If any element in `x` is + complex, a complex array is returned (and the square-roots of + negative reals are calculated). If all of the elements in `x` + are real, so is `y`, with negative elements returning ``nan``. + If `out` was provided, `y` is a reference to it. + + See Also + -------- + lib.scimath.sqrt + A version which returns complex numbers when given negative reals. + + Notes + ----- + *sqrt* has--consistent with common convention--as its branch cut the + real "interval" [`-inf`, 0), and is continuous from above on it. + A branch cut is a curve in the complex plane across which a given + complex function fails to be continuous. + + Examples + -------- + >>> np.sqrt([1,4,9]) + array([ 1., 2., 3.]) + + >>> np.sqrt([4, -1, -3+4J]) + array([ 2.+0.j, 0.+1.j, 1.+2.j]) + + >>> np.sqrt([4, -1, numpy.inf]) + array([ 2., NaN, Inf]) + + """) + +add_newdoc('numpy.core.umath', 'cbrt', + """ + Return the cube-root of an array, element-wise. + + .. versionadded:: 1.10.0 + + Parameters + ---------- + x : array_like + The values whose cube-roots are required. + $PARAMS + + Returns + ------- + y : ndarray + An array of the same shape as `x`, containing the cube + cube-root of each element in `x`. + If `out` was provided, `y` is a reference to it. + + + Examples + -------- + >>> np.cbrt([1,8,27]) + array([ 1., 2., 3.]) + + """) + +add_newdoc('numpy.core.umath', 'square', + """ + Return the element-wise square of the input. + + Parameters + ---------- + x : array_like + Input data. + $PARAMS + + Returns + ------- + out : ndarray + Element-wise `x*x`, of the same shape and dtype as `x`. + Returns scalar if `x` is a scalar. + + See Also + -------- + numpy.linalg.matrix_power + sqrt + power + + Examples + -------- + >>> np.square([-1j, 1]) + array([-1.-0.j, 1.+0.j]) + + """) + +add_newdoc('numpy.core.umath', 'subtract', + """ + Subtract arguments, element-wise. + + Parameters + ---------- + x1, x2 : array_like + The arrays to be subtracted from each other. + $PARAMS + + Returns + ------- + y : ndarray + The difference of `x1` and `x2`, element-wise. Returns a scalar if + both `x1` and `x2` are scalars. + + Notes + ----- + Equivalent to ``x1 - x2`` in terms of array broadcasting. + + Examples + -------- + >>> np.subtract(1.0, 4.0) + -3.0 + + >>> x1 = np.arange(9.0).reshape((3, 3)) + >>> x2 = np.arange(3.0) + >>> np.subtract(x1, x2) + array([[ 0., 0., 0.], + [ 3., 3., 3.], + [ 6., 6., 6.]]) + + """) + +add_newdoc('numpy.core.umath', 'tan', + """ + Compute tangent element-wise. + + Equivalent to ``np.sin(x)/np.cos(x)`` element-wise. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + y : ndarray + The corresponding tangent values. + + Notes + ----- + If `out` is provided, the function writes the result into it, + and returns a reference to `out`. (See Examples) + + References + ---------- + M. Abramowitz and I. A. Stegun, Handbook of Mathematical Functions. + New York, NY: Dover, 1972. + + Examples + -------- + >>> from math import pi + >>> np.tan(np.array([-pi,pi/2,pi])) + array([ 1.22460635e-16, 1.63317787e+16, -1.22460635e-16]) + >>> + >>> # Example of providing the optional output parameter illustrating + >>> # that what is returned is a reference to said parameter + >>> out2 = np.cos([0.1], out1) + >>> out2 is out1 + True + >>> + >>> # Example of ValueError due to provision of shape mis-matched `out` + >>> np.cos(np.zeros((3,3)),np.zeros((2,2))) + Traceback (most recent call last): + File "", line 1, in + ValueError: invalid return array shape + + """) + +add_newdoc('numpy.core.umath', 'tanh', + """ + Compute hyperbolic tangent element-wise. + + Equivalent to ``np.sinh(x)/np.cosh(x)`` or ``-1j * np.tan(1j*x)``. + + Parameters + ---------- + x : array_like + Input array. + $PARAMS + + Returns + ------- + y : ndarray + The corresponding hyperbolic tangent values. + + Notes + ----- + If `out` is provided, the function writes the result into it, + and returns a reference to `out`. (See Examples) + + References + ---------- + .. [1] M. Abramowitz and I. A. Stegun, Handbook of Mathematical Functions. + New York, NY: Dover, 1972, pg. 83. + http://www.math.sfu.ca/~cbm/aands/ + + .. [2] Wikipedia, "Hyperbolic function", + http://en.wikipedia.org/wiki/Hyperbolic_function + + Examples + -------- + >>> np.tanh((0, np.pi*1j, np.pi*1j/2)) + array([ 0. +0.00000000e+00j, 0. -1.22460635e-16j, 0. +1.63317787e+16j]) + + >>> # Example of providing the optional output parameter illustrating + >>> # that what is returned is a reference to said parameter + >>> out2 = np.tanh([0.1], out1) + >>> out2 is out1 + True + + >>> # Example of ValueError due to provision of shape mis-matched `out` + >>> np.tanh(np.zeros((3,3)),np.zeros((2,2))) + Traceback (most recent call last): + File "", line 1, in + ValueError: invalid return array shape + + """) + +add_newdoc('numpy.core.umath', 'true_divide', + """ + Returns a true division of the inputs, element-wise. + + Instead of the Python traditional 'floor division', this returns a true + division. True division adjusts the output type to present the best + answer, regardless of input types. + + Parameters + ---------- + x1 : array_like + Dividend array. + x2 : array_like + Divisor array. + $PARAMS + + Returns + ------- + out : ndarray + Result is scalar if both inputs are scalar, ndarray otherwise. + + Notes + ----- + The floor division operator ``//`` was added in Python 2.2 making + ``//`` and ``/`` equivalent operators. The default floor division + operation of ``/`` can be replaced by true division with ``from + __future__ import division``. + + In Python 3.0, ``//`` is the floor division operator and ``/`` the + true division operator. The ``true_divide(x1, x2)`` function is + equivalent to true division in Python. + + Examples + -------- + >>> x = np.arange(5) + >>> np.true_divide(x, 4) + array([ 0. , 0.25, 0.5 , 0.75, 1. ]) + + >>> x/4 + array([0, 0, 0, 0, 1]) + >>> x//4 + array([0, 0, 0, 0, 1]) + + >>> from __future__ import division + >>> x/4 + array([ 0. , 0.25, 0.5 , 0.75, 1. ]) + >>> x//4 + array([0, 0, 0, 0, 1]) + + """) + +add_newdoc('numpy.core.umath', 'frexp', + """ + Decompose the elements of x into mantissa and twos exponent. + + Returns (`mantissa`, `exponent`), where `x = mantissa * 2**exponent``. + The mantissa is lies in the open interval(-1, 1), while the twos + exponent is a signed integer. + + Parameters + ---------- + x : array_like + Array of numbers to be decomposed. + out1 : ndarray, optional + Output array for the mantissa. Must have the same shape as `x`. + out2 : ndarray, optional + Output array for the exponent. Must have the same shape as `x`. + $PARAMS + + Returns + ------- + (mantissa, exponent) : tuple of ndarrays, (float, int) + `mantissa` is a float array with values between -1 and 1. + `exponent` is an int array which represents the exponent of 2. + + See Also + -------- + ldexp : Compute ``y = x1 * 2**x2``, the inverse of `frexp`. + + Notes + ----- + Complex dtypes are not supported, they will raise a TypeError. + + Examples + -------- + >>> x = np.arange(9) + >>> y1, y2 = np.frexp(x) + >>> y1 + array([ 0. , 0.5 , 0.5 , 0.75 , 0.5 , 0.625, 0.75 , 0.875, + 0.5 ]) + >>> y2 + array([0, 1, 2, 2, 3, 3, 3, 3, 4]) + >>> y1 * 2**y2 + array([ 0., 1., 2., 3., 4., 5., 6., 7., 8.]) + + """) + +add_newdoc('numpy.core.umath', 'ldexp', + """ + Returns x1 * 2**x2, element-wise. + + The mantissas `x1` and twos exponents `x2` are used to construct + floating point numbers ``x1 * 2**x2``. + + Parameters + ---------- + x1 : array_like + Array of multipliers. + x2 : array_like, int + Array of twos exponents. + $PARAMS + + Returns + ------- + y : ndarray or scalar + The result of ``x1 * 2**x2``. + + See Also + -------- + frexp : Return (y1, y2) from ``x = y1 * 2**y2``, inverse to `ldexp`. + + Notes + ----- + Complex dtypes are not supported, they will raise a TypeError. + + `ldexp` is useful as the inverse of `frexp`, if used by itself it is + more clear to simply use the expression ``x1 * 2**x2``. + + Examples + -------- + >>> np.ldexp(5, np.arange(4)) + array([ 5., 10., 20., 40.], dtype=float32) + + >>> x = np.arange(6) + >>> np.ldexp(*np.frexp(x)) + array([ 0., 1., 2., 3., 4., 5.]) + + """) diff --git a/numpy/core/cversions.py b/numpy/core/cversions.py new file mode 100644 index 0000000..7995dd9 --- /dev/null +++ b/numpy/core/cversions.py @@ -0,0 +1,15 @@ +"""Simple script to compute the api hash of the current API. + +The API has is defined by numpy_api_order and ufunc_api_order. + +""" +from __future__ import division, absolute_import, print_function + +from os.path import dirname + +from code_generators.genapi import fullapi_hash +from code_generators.numpy_api import full_api + +if __name__ == '__main__': + curdir = dirname(__file__) + print(fullapi_hash(full_api)) diff --git a/numpy/core/defchararray.py b/numpy/core/defchararray.py new file mode 100644 index 0000000..6d0a0ad --- /dev/null +++ b/numpy/core/defchararray.py @@ -0,0 +1,2679 @@ +""" +This module contains a set of functions for vectorized string +operations and methods. + +.. note:: + The `chararray` class exists for backwards compatibility with + Numarray, it is not recommended for new development. Starting from numpy + 1.4, if one needs arrays of strings, it is recommended to use arrays of + `dtype` `object_`, `string_` or `unicode_`, and use the free functions + in the `numpy.char` module for fast vectorized string operations. + +Some methods will only be available if the corresponding string method is +available in your version of Python. + +The preferred alias for `defchararray` is `numpy.char`. + +""" +from __future__ import division, absolute_import, print_function + +import sys +from .numerictypes import string_, unicode_, integer, object_, bool_, character +from .numeric import ndarray, compare_chararrays +from .numeric import array as narray +from numpy.core.multiarray import _vec_string +from numpy.compat import asbytes, long +import numpy + +__all__ = [ + 'chararray', 'equal', 'not_equal', 'greater_equal', 'less_equal', + 'greater', 'less', 'str_len', 'add', 'multiply', 'mod', 'capitalize', + 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', + 'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', + 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', + 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', + 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', + 'title', 'translate', 'upper', 'zfill', 'isnumeric', 'isdecimal', + 'array', 'asarray' + ] + + +_globalvar = 0 +if sys.version_info[0] >= 3: + _unicode = str + _bytes = bytes +else: + _unicode = unicode + _bytes = str +_len = len + +def _use_unicode(*args): + """ + Helper function for determining the output type of some string + operations. + + For an operation on two ndarrays, if at least one is unicode, the + result should be unicode. + """ + for x in args: + if (isinstance(x, _unicode) or + issubclass(numpy.asarray(x).dtype.type, unicode_)): + return unicode_ + return string_ + +def _to_string_or_unicode_array(result): + """ + Helper function to cast a result back into a string or unicode array + if an object array must be used as an intermediary. + """ + return numpy.asarray(result.tolist()) + +def _clean_args(*args): + """ + Helper function for delegating arguments to Python string + functions. + + Many of the Python string operations that have optional arguments + do not use 'None' to indicate a default value. In these cases, + we need to remove all `None` arguments, and those following them. + """ + newargs = [] + for chk in args: + if chk is None: + break + newargs.append(chk) + return newargs + +def _get_num_chars(a): + """ + Helper function that returns the number of characters per field in + a string or unicode array. This is to abstract out the fact that + for a unicode array this is itemsize / 4. + """ + if issubclass(a.dtype.type, unicode_): + return a.itemsize // 4 + return a.itemsize + + +def equal(x1, x2): + """ + Return (x1 == x2) element-wise. + + Unlike `numpy.equal`, this comparison is performed by first + stripping whitespace characters from the end of the string. This + behavior is provided for backward-compatibility with numarray. + + Parameters + ---------- + x1, x2 : array_like of str or unicode + Input arrays of the same shape. + + Returns + ------- + out : ndarray or bool + Output array of bools, or a single bool if x1 and x2 are scalars. + + See Also + -------- + not_equal, greater_equal, less_equal, greater, less + """ + return compare_chararrays(x1, x2, '==', True) + +def not_equal(x1, x2): + """ + Return (x1 != x2) element-wise. + + Unlike `numpy.not_equal`, this comparison is performed by first + stripping whitespace characters from the end of the string. This + behavior is provided for backward-compatibility with numarray. + + Parameters + ---------- + x1, x2 : array_like of str or unicode + Input arrays of the same shape. + + Returns + ------- + out : ndarray or bool + Output array of bools, or a single bool if x1 and x2 are scalars. + + See Also + -------- + equal, greater_equal, less_equal, greater, less + """ + return compare_chararrays(x1, x2, '!=', True) + +def greater_equal(x1, x2): + """ + Return (x1 >= x2) element-wise. + + Unlike `numpy.greater_equal`, this comparison is performed by + first stripping whitespace characters from the end of the string. + This behavior is provided for backward-compatibility with + numarray. + + Parameters + ---------- + x1, x2 : array_like of str or unicode + Input arrays of the same shape. + + Returns + ------- + out : ndarray or bool + Output array of bools, or a single bool if x1 and x2 are scalars. + + See Also + -------- + equal, not_equal, less_equal, greater, less + """ + return compare_chararrays(x1, x2, '>=', True) + +def less_equal(x1, x2): + """ + Return (x1 <= x2) element-wise. + + Unlike `numpy.less_equal`, this comparison is performed by first + stripping whitespace characters from the end of the string. This + behavior is provided for backward-compatibility with numarray. + + Parameters + ---------- + x1, x2 : array_like of str or unicode + Input arrays of the same shape. + + Returns + ------- + out : ndarray or bool + Output array of bools, or a single bool if x1 and x2 are scalars. + + See Also + -------- + equal, not_equal, greater_equal, greater, less + """ + return compare_chararrays(x1, x2, '<=', True) + +def greater(x1, x2): + """ + Return (x1 > x2) element-wise. + + Unlike `numpy.greater`, this comparison is performed by first + stripping whitespace characters from the end of the string. This + behavior is provided for backward-compatibility with numarray. + + Parameters + ---------- + x1, x2 : array_like of str or unicode + Input arrays of the same shape. + + Returns + ------- + out : ndarray or bool + Output array of bools, or a single bool if x1 and x2 are scalars. + + See Also + -------- + equal, not_equal, greater_equal, less_equal, less + """ + return compare_chararrays(x1, x2, '>', True) + +def less(x1, x2): + """ + Return (x1 < x2) element-wise. + + Unlike `numpy.greater`, this comparison is performed by first + stripping whitespace characters from the end of the string. This + behavior is provided for backward-compatibility with numarray. + + Parameters + ---------- + x1, x2 : array_like of str or unicode + Input arrays of the same shape. + + Returns + ------- + out : ndarray or bool + Output array of bools, or a single bool if x1 and x2 are scalars. + + See Also + -------- + equal, not_equal, greater_equal, less_equal, greater + """ + return compare_chararrays(x1, x2, '<', True) + +def str_len(a): + """ + Return len(a) element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of integers + + See also + -------- + __builtin__.len + """ + return _vec_string(a, integer, '__len__') + +def add(x1, x2): + """ + Return element-wise string concatenation for two arrays of str or unicode. + + Arrays `x1` and `x2` must have the same shape. + + Parameters + ---------- + x1 : array_like of str or unicode + Input array. + x2 : array_like of str or unicode + Input array. + + Returns + ------- + add : ndarray + Output array of `string_` or `unicode_`, depending on input types + of the same shape as `x1` and `x2`. + + """ + arr1 = numpy.asarray(x1) + arr2 = numpy.asarray(x2) + out_size = _get_num_chars(arr1) + _get_num_chars(arr2) + dtype = _use_unicode(arr1, arr2) + return _vec_string(arr1, (dtype, out_size), '__add__', (arr2,)) + +def multiply(a, i): + """ + Return (a * i), that is string multiple concatenation, + element-wise. + + Values in `i` of less than 0 are treated as 0 (which yields an + empty string). + + Parameters + ---------- + a : array_like of str or unicode + + i : array_like of ints + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input types + + """ + a_arr = numpy.asarray(a) + i_arr = numpy.asarray(i) + if not issubclass(i_arr.dtype.type, integer): + raise ValueError("Can only multiply by integers") + out_size = _get_num_chars(a_arr) * max(long(i_arr.max()), 0) + return _vec_string( + a_arr, (a_arr.dtype.type, out_size), '__mul__', (i_arr,)) + +def mod(a, values): + """ + Return (a % i), that is pre-Python 2.6 string formatting + (iterpolation), element-wise for a pair of array_likes of str + or unicode. + + Parameters + ---------- + a : array_like of str or unicode + + values : array_like of values + These values will be element-wise interpolated into the string. + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input types + + See also + -------- + str.__mod__ + + """ + return _to_string_or_unicode_array( + _vec_string(a, object_, '__mod__', (values,))) + +def capitalize(a): + """ + Return a copy of `a` with only the first character of each element + capitalized. + + Calls `str.capitalize` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like of str or unicode + Input array of strings to capitalize. + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input + types + + See also + -------- + str.capitalize + + Examples + -------- + >>> c = np.array(['a1b2','1b2a','b2a1','2a1b'],'S4'); c + array(['a1b2', '1b2a', 'b2a1', '2a1b'], + dtype='|S4') + >>> np.char.capitalize(c) + array(['A1b2', '1b2a', 'B2a1', '2a1b'], + dtype='|S4') + + """ + a_arr = numpy.asarray(a) + return _vec_string(a_arr, a_arr.dtype, 'capitalize') + + +def center(a, width, fillchar=' '): + """ + Return a copy of `a` with its elements centered in a string of + length `width`. + + Calls `str.center` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + width : int + The length of the resulting strings + fillchar : str or unicode, optional + The padding character to use (default is space). + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input + types + + See also + -------- + str.center + + """ + a_arr = numpy.asarray(a) + width_arr = numpy.asarray(width) + size = long(numpy.max(width_arr.flat)) + if numpy.issubdtype(a_arr.dtype, numpy.string_): + fillchar = asbytes(fillchar) + return _vec_string( + a_arr, (a_arr.dtype.type, size), 'center', (width_arr, fillchar)) + + +def count(a, sub, start=0, end=None): + """ + Returns an array with the number of non-overlapping occurrences of + substring `sub` in the range [`start`, `end`]. + + Calls `str.count` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + sub : str or unicode + The substring to search for. + + start, end : int, optional + Optional arguments `start` and `end` are interpreted as slice + notation to specify the range in which to count. + + Returns + ------- + out : ndarray + Output array of ints. + + See also + -------- + str.count + + Examples + -------- + >>> c = np.array(['aAaAaA', ' aA ', 'abBABba']) + >>> c + array(['aAaAaA', ' aA ', 'abBABba'], + dtype='|S7') + >>> np.char.count(c, 'A') + array([3, 1, 1]) + >>> np.char.count(c, 'aA') + array([3, 1, 0]) + >>> np.char.count(c, 'A', start=1, end=4) + array([2, 1, 1]) + >>> np.char.count(c, 'A', start=1, end=3) + array([1, 0, 0]) + + """ + return _vec_string(a, integer, 'count', [sub, start] + _clean_args(end)) + + +def decode(a, encoding=None, errors=None): + """ + Calls `str.decode` element-wise. + + The set of available codecs comes from the Python standard library, + and may be extended at runtime. For more information, see the + :mod:`codecs` module. + + Parameters + ---------- + a : array_like of str or unicode + + encoding : str, optional + The name of an encoding + + errors : str, optional + Specifies how to handle encoding errors + + Returns + ------- + out : ndarray + + See also + -------- + str.decode + + Notes + ----- + The type of the result will depend on the encoding specified. + + Examples + -------- + >>> c = np.array(['aAaAaA', ' aA ', 'abBABba']) + >>> c + array(['aAaAaA', ' aA ', 'abBABba'], + dtype='|S7') + >>> np.char.encode(c, encoding='cp037') + array(['\\x81\\xc1\\x81\\xc1\\x81\\xc1', '@@\\x81\\xc1@@', + '\\x81\\x82\\xc2\\xc1\\xc2\\x82\\x81'], + dtype='|S7') + + """ + return _to_string_or_unicode_array( + _vec_string(a, object_, 'decode', _clean_args(encoding, errors))) + + +def encode(a, encoding=None, errors=None): + """ + Calls `str.encode` element-wise. + + The set of available codecs comes from the Python standard library, + and may be extended at runtime. For more information, see the codecs + module. + + Parameters + ---------- + a : array_like of str or unicode + + encoding : str, optional + The name of an encoding + + errors : str, optional + Specifies how to handle encoding errors + + Returns + ------- + out : ndarray + + See also + -------- + str.encode + + Notes + ----- + The type of the result will depend on the encoding specified. + + """ + return _to_string_or_unicode_array( + _vec_string(a, object_, 'encode', _clean_args(encoding, errors))) + + +def endswith(a, suffix, start=0, end=None): + """ + Returns a boolean array which is `True` where the string element + in `a` ends with `suffix`, otherwise `False`. + + Calls `str.endswith` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + suffix : str + + start, end : int, optional + With optional `start`, test beginning at that position. With + optional `end`, stop comparing at that position. + + Returns + ------- + out : ndarray + Outputs an array of bools. + + See also + -------- + str.endswith + + Examples + -------- + >>> s = np.array(['foo', 'bar']) + >>> s[0] = 'foo' + >>> s[1] = 'bar' + >>> s + array(['foo', 'bar'], + dtype='|S3') + >>> np.char.endswith(s, 'ar') + array([False, True]) + >>> np.char.endswith(s, 'a', start=1, end=2) + array([False, True]) + + """ + return _vec_string( + a, bool_, 'endswith', [suffix, start] + _clean_args(end)) + + +def expandtabs(a, tabsize=8): + """ + Return a copy of each string element where all tab characters are + replaced by one or more spaces. + + Calls `str.expandtabs` element-wise. + + Return a copy of each string element where all tab characters are + replaced by one or more spaces, depending on the current column + and the given `tabsize`. The column number is reset to zero after + each newline occurring in the string. This doesn't understand other + non-printing characters or escape sequences. + + Parameters + ---------- + a : array_like of str or unicode + Input array + tabsize : int, optional + Replace tabs with `tabsize` number of spaces. If not given defaults + to 8 spaces. + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.expandtabs + + """ + return _to_string_or_unicode_array( + _vec_string(a, object_, 'expandtabs', (tabsize,))) + + +def find(a, sub, start=0, end=None): + """ + For each element, return the lowest index in the string where + substring `sub` is found. + + Calls `str.find` element-wise. + + For each element, return the lowest index in the string where + substring `sub` is found, such that `sub` is contained in the + range [`start`, `end`]. + + Parameters + ---------- + a : array_like of str or unicode + + sub : str or unicode + + start, end : int, optional + Optional arguments `start` and `end` are interpreted as in + slice notation. + + Returns + ------- + out : ndarray or int + Output array of ints. Returns -1 if `sub` is not found. + + See also + -------- + str.find + + """ + return _vec_string( + a, integer, 'find', [sub, start] + _clean_args(end)) + + +def index(a, sub, start=0, end=None): + """ + Like `find`, but raises `ValueError` when the substring is not found. + + Calls `str.index` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + sub : str or unicode + + start, end : int, optional + + Returns + ------- + out : ndarray + Output array of ints. Returns -1 if `sub` is not found. + + See also + -------- + find, str.find + + """ + return _vec_string( + a, integer, 'index', [sub, start] + _clean_args(end)) + +def isalnum(a): + """ + Returns true for each element if all characters in the string are + alphanumeric and there is at least one character, false otherwise. + + Calls `str.isalnum` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.isalnum + """ + return _vec_string(a, bool_, 'isalnum') + +def isalpha(a): + """ + Returns true for each element if all characters in the string are + alphabetic and there is at least one character, false otherwise. + + Calls `str.isalpha` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of bools + + See also + -------- + str.isalpha + """ + return _vec_string(a, bool_, 'isalpha') + +def isdigit(a): + """ + Returns true for each element if all characters in the string are + digits and there is at least one character, false otherwise. + + Calls `str.isdigit` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of bools + + See also + -------- + str.isdigit + """ + return _vec_string(a, bool_, 'isdigit') + +def islower(a): + """ + Returns true for each element if all cased characters in the + string are lowercase and there is at least one cased character, + false otherwise. + + Calls `str.islower` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of bools + + See also + -------- + str.islower + """ + return _vec_string(a, bool_, 'islower') + +def isspace(a): + """ + Returns true for each element if there are only whitespace + characters in the string and there is at least one character, + false otherwise. + + Calls `str.isspace` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of bools + + See also + -------- + str.isspace + """ + return _vec_string(a, bool_, 'isspace') + +def istitle(a): + """ + Returns true for each element if the element is a titlecased + string and there is at least one character, false otherwise. + + Call `str.istitle` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of bools + + See also + -------- + str.istitle + """ + return _vec_string(a, bool_, 'istitle') + +def isupper(a): + """ + Returns true for each element if all cased characters in the + string are uppercase and there is at least one character, false + otherwise. + + Call `str.isupper` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of bools + + See also + -------- + str.isupper + """ + return _vec_string(a, bool_, 'isupper') + +def join(sep, seq): + """ + Return a string which is the concatenation of the strings in the + sequence `seq`. + + Calls `str.join` element-wise. + + Parameters + ---------- + sep : array_like of str or unicode + seq : array_like of str or unicode + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input types + + See also + -------- + str.join + """ + return _to_string_or_unicode_array( + _vec_string(sep, object_, 'join', (seq,))) + + +def ljust(a, width, fillchar=' '): + """ + Return an array with the elements of `a` left-justified in a + string of length `width`. + + Calls `str.ljust` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + width : int + The length of the resulting strings + fillchar : str or unicode, optional + The character to use for padding + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.ljust + + """ + a_arr = numpy.asarray(a) + width_arr = numpy.asarray(width) + size = long(numpy.max(width_arr.flat)) + if numpy.issubdtype(a_arr.dtype, numpy.string_): + fillchar = asbytes(fillchar) + return _vec_string( + a_arr, (a_arr.dtype.type, size), 'ljust', (width_arr, fillchar)) + + +def lower(a): + """ + Return an array with the elements converted to lowercase. + + Call `str.lower` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like, {str, unicode} + Input array. + + Returns + ------- + out : ndarray, {str, unicode} + Output array of str or unicode, depending on input type + + See also + -------- + str.lower + + Examples + -------- + >>> c = np.array(['A1B C', '1BCA', 'BCA1']); c + array(['A1B C', '1BCA', 'BCA1'], + dtype='|S5') + >>> np.char.lower(c) + array(['a1b c', '1bca', 'bca1'], + dtype='|S5') + + """ + a_arr = numpy.asarray(a) + return _vec_string(a_arr, a_arr.dtype, 'lower') + + +def lstrip(a, chars=None): + """ + For each element in `a`, return a copy with the leading characters + removed. + + Calls `str.lstrip` element-wise. + + Parameters + ---------- + a : array-like, {str, unicode} + Input array. + + chars : {str, unicode}, optional + The `chars` argument is a string specifying the set of + characters to be removed. If omitted or None, the `chars` + argument defaults to removing whitespace. The `chars` argument + is not a prefix; rather, all combinations of its values are + stripped. + + Returns + ------- + out : ndarray, {str, unicode} + Output array of str or unicode, depending on input type + + See also + -------- + str.lstrip + + Examples + -------- + >>> c = np.array(['aAaAaA', ' aA ', 'abBABba']) + >>> c + array(['aAaAaA', ' aA ', 'abBABba'], + dtype='|S7') + + The 'a' variable is unstripped from c[1] because whitespace leading. + + >>> np.char.lstrip(c, 'a') + array(['AaAaA', ' aA ', 'bBABba'], + dtype='|S7') + + + >>> np.char.lstrip(c, 'A') # leaves c unchanged + array(['aAaAaA', ' aA ', 'abBABba'], + dtype='|S7') + >>> (np.char.lstrip(c, ' ') == np.char.lstrip(c, '')).all() + ... # XXX: is this a regression? this line now returns False + ... # np.char.lstrip(c,'') does not modify c at all. + True + >>> (np.char.lstrip(c, ' ') == np.char.lstrip(c, None)).all() + True + + """ + a_arr = numpy.asarray(a) + return _vec_string(a_arr, a_arr.dtype, 'lstrip', (chars,)) + + +def partition(a, sep): + """ + Partition each element in `a` around `sep`. + + Calls `str.partition` element-wise. + + For each element in `a`, split the element as the first + occurrence of `sep`, and return 3 strings containing the part + before the separator, the separator itself, and the part after + the separator. If the separator is not found, return 3 strings + containing the string itself, followed by two empty strings. + + Parameters + ---------- + a : array_like, {str, unicode} + Input array + sep : {str, unicode} + Separator to split each string element in `a`. + + Returns + ------- + out : ndarray, {str, unicode} + Output array of str or unicode, depending on input type. + The output array will have an extra dimension with 3 + elements per input element. + + See also + -------- + str.partition + + """ + return _to_string_or_unicode_array( + _vec_string(a, object_, 'partition', (sep,))) + + +def replace(a, old, new, count=None): + """ + For each element in `a`, return a copy of the string with all + occurrences of substring `old` replaced by `new`. + + Calls `str.replace` element-wise. + + Parameters + ---------- + a : array-like of str or unicode + + old, new : str or unicode + + count : int, optional + If the optional argument `count` is given, only the first + `count` occurrences are replaced. + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.replace + + """ + return _to_string_or_unicode_array( + _vec_string( + a, object_, 'replace', [old, new] + _clean_args(count))) + + +def rfind(a, sub, start=0, end=None): + """ + For each element in `a`, return the highest index in the string + where substring `sub` is found, such that `sub` is contained + within [`start`, `end`]. + + Calls `str.rfind` element-wise. + + Parameters + ---------- + a : array-like of str or unicode + + sub : str or unicode + + start, end : int, optional + Optional arguments `start` and `end` are interpreted as in + slice notation. + + Returns + ------- + out : ndarray + Output array of ints. Return -1 on failure. + + See also + -------- + str.rfind + + """ + return _vec_string( + a, integer, 'rfind', [sub, start] + _clean_args(end)) + + +def rindex(a, sub, start=0, end=None): + """ + Like `rfind`, but raises `ValueError` when the substring `sub` is + not found. + + Calls `str.rindex` element-wise. + + Parameters + ---------- + a : array-like of str or unicode + + sub : str or unicode + + start, end : int, optional + + Returns + ------- + out : ndarray + Output array of ints. + + See also + -------- + rfind, str.rindex + + """ + return _vec_string( + a, integer, 'rindex', [sub, start] + _clean_args(end)) + + +def rjust(a, width, fillchar=' '): + """ + Return an array with the elements of `a` right-justified in a + string of length `width`. + + Calls `str.rjust` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + width : int + The length of the resulting strings + fillchar : str or unicode, optional + The character to use for padding + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.rjust + + """ + a_arr = numpy.asarray(a) + width_arr = numpy.asarray(width) + size = long(numpy.max(width_arr.flat)) + if numpy.issubdtype(a_arr.dtype, numpy.string_): + fillchar = asbytes(fillchar) + return _vec_string( + a_arr, (a_arr.dtype.type, size), 'rjust', (width_arr, fillchar)) + + +def rpartition(a, sep): + """ + Partition (split) each element around the right-most separator. + + Calls `str.rpartition` element-wise. + + For each element in `a`, split the element as the last + occurrence of `sep`, and return 3 strings containing the part + before the separator, the separator itself, and the part after + the separator. If the separator is not found, return 3 strings + containing the string itself, followed by two empty strings. + + Parameters + ---------- + a : array_like of str or unicode + Input array + sep : str or unicode + Right-most separator to split each element in array. + + Returns + ------- + out : ndarray + Output array of string or unicode, depending on input + type. The output array will have an extra dimension with + 3 elements per input element. + + See also + -------- + str.rpartition + + """ + return _to_string_or_unicode_array( + _vec_string(a, object_, 'rpartition', (sep,))) + + +def rsplit(a, sep=None, maxsplit=None): + """ + For each element in `a`, return a list of the words in the + string, using `sep` as the delimiter string. + + Calls `str.rsplit` element-wise. + + Except for splitting from the right, `rsplit` + behaves like `split`. + + Parameters + ---------- + a : array_like of str or unicode + + sep : str or unicode, optional + If `sep` is not specified or `None`, any whitespace string + is a separator. + maxsplit : int, optional + If `maxsplit` is given, at most `maxsplit` splits are done, + the rightmost ones. + + Returns + ------- + out : ndarray + Array of list objects + + See also + -------- + str.rsplit, split + + """ + # This will return an array of lists of different sizes, so we + # leave it as an object array + return _vec_string( + a, object_, 'rsplit', [sep] + _clean_args(maxsplit)) + + +def rstrip(a, chars=None): + """ + For each element in `a`, return a copy with the trailing + characters removed. + + Calls `str.rstrip` element-wise. + + Parameters + ---------- + a : array-like of str or unicode + + chars : str or unicode, optional + The `chars` argument is a string specifying the set of + characters to be removed. If omitted or None, the `chars` + argument defaults to removing whitespace. The `chars` argument + is not a suffix; rather, all combinations of its values are + stripped. + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.rstrip + + Examples + -------- + >>> c = np.array(['aAaAaA', 'abBABba'], dtype='S7'); c + array(['aAaAaA', 'abBABba'], + dtype='|S7') + >>> np.char.rstrip(c, 'a') + array(['aAaAaA', 'abBABb'], + dtype='|S7') + >>> np.char.rstrip(c, 'A') + array(['aAaAa', 'abBABba'], + dtype='|S7') + + """ + a_arr = numpy.asarray(a) + return _vec_string(a_arr, a_arr.dtype, 'rstrip', (chars,)) + + +def split(a, sep=None, maxsplit=None): + """ + For each element in `a`, return a list of the words in the + string, using `sep` as the delimiter string. + + Calls `str.split` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + sep : str or unicode, optional + If `sep` is not specified or `None`, any whitespace string is a + separator. + + maxsplit : int, optional + If `maxsplit` is given, at most `maxsplit` splits are done. + + Returns + ------- + out : ndarray + Array of list objects + + See also + -------- + str.split, rsplit + + """ + # This will return an array of lists of different sizes, so we + # leave it as an object array + return _vec_string( + a, object_, 'split', [sep] + _clean_args(maxsplit)) + + +def splitlines(a, keepends=None): + """ + For each element in `a`, return a list of the lines in the + element, breaking at line boundaries. + + Calls `str.splitlines` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + keepends : bool, optional + Line breaks are not included in the resulting list unless + keepends is given and true. + + Returns + ------- + out : ndarray + Array of list objects + + See also + -------- + str.splitlines + + """ + return _vec_string( + a, object_, 'splitlines', _clean_args(keepends)) + + +def startswith(a, prefix, start=0, end=None): + """ + Returns a boolean array which is `True` where the string element + in `a` starts with `prefix`, otherwise `False`. + + Calls `str.startswith` element-wise. + + Parameters + ---------- + a : array_like of str or unicode + + prefix : str + + start, end : int, optional + With optional `start`, test beginning at that position. With + optional `end`, stop comparing at that position. + + Returns + ------- + out : ndarray + Array of booleans + + See also + -------- + str.startswith + + """ + return _vec_string( + a, bool_, 'startswith', [prefix, start] + _clean_args(end)) + + +def strip(a, chars=None): + """ + For each element in `a`, return a copy with the leading and + trailing characters removed. + + Calls `str.strip` element-wise. + + Parameters + ---------- + a : array-like of str or unicode + + chars : str or unicode, optional + The `chars` argument is a string specifying the set of + characters to be removed. If omitted or None, the `chars` + argument defaults to removing whitespace. The `chars` argument + is not a prefix or suffix; rather, all combinations of its + values are stripped. + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.strip + + Examples + -------- + >>> c = np.array(['aAaAaA', ' aA ', 'abBABba']) + >>> c + array(['aAaAaA', ' aA ', 'abBABba'], + dtype='|S7') + >>> np.char.strip(c) + array(['aAaAaA', 'aA', 'abBABba'], + dtype='|S7') + >>> np.char.strip(c, 'a') # 'a' unstripped from c[1] because whitespace leads + array(['AaAaA', ' aA ', 'bBABb'], + dtype='|S7') + >>> np.char.strip(c, 'A') # 'A' unstripped from c[1] because (unprinted) ws trails + array(['aAaAa', ' aA ', 'abBABba'], + dtype='|S7') + + """ + a_arr = numpy.asarray(a) + return _vec_string(a_arr, a_arr.dtype, 'strip', _clean_args(chars)) + + +def swapcase(a): + """ + Return element-wise a copy of the string with + uppercase characters converted to lowercase and vice versa. + + Calls `str.swapcase` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like, {str, unicode} + Input array. + + Returns + ------- + out : ndarray, {str, unicode} + Output array of str or unicode, depending on input type + + See also + -------- + str.swapcase + + Examples + -------- + >>> c=np.array(['a1B c','1b Ca','b Ca1','cA1b'],'S5'); c + array(['a1B c', '1b Ca', 'b Ca1', 'cA1b'], + dtype='|S5') + >>> np.char.swapcase(c) + array(['A1b C', '1B cA', 'B cA1', 'Ca1B'], + dtype='|S5') + + """ + a_arr = numpy.asarray(a) + return _vec_string(a_arr, a_arr.dtype, 'swapcase') + + +def title(a): + """ + Return element-wise title cased version of string or unicode. + + Title case words start with uppercase characters, all remaining cased + characters are lowercase. + + Calls `str.title` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like, {str, unicode} + Input array. + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.title + + Examples + -------- + >>> c=np.array(['a1b c','1b ca','b ca1','ca1b'],'S5'); c + array(['a1b c', '1b ca', 'b ca1', 'ca1b'], + dtype='|S5') + >>> np.char.title(c) + array(['A1B C', '1B Ca', 'B Ca1', 'Ca1B'], + dtype='|S5') + + """ + a_arr = numpy.asarray(a) + return _vec_string(a_arr, a_arr.dtype, 'title') + + +def translate(a, table, deletechars=None): + """ + For each element in `a`, return a copy of the string where all + characters occurring in the optional argument `deletechars` are + removed, and the remaining characters have been mapped through the + given translation table. + + Calls `str.translate` element-wise. + + Parameters + ---------- + a : array-like of str or unicode + + table : str of length 256 + + deletechars : str + + Returns + ------- + out : ndarray + Output array of str or unicode, depending on input type + + See also + -------- + str.translate + + """ + a_arr = numpy.asarray(a) + if issubclass(a_arr.dtype.type, unicode_): + return _vec_string( + a_arr, a_arr.dtype, 'translate', (table,)) + else: + return _vec_string( + a_arr, a_arr.dtype, 'translate', [table] + _clean_args(deletechars)) + + +def upper(a): + """ + Return an array with the elements converted to uppercase. + + Calls `str.upper` element-wise. + + For 8-bit strings, this method is locale-dependent. + + Parameters + ---------- + a : array_like, {str, unicode} + Input array. + + Returns + ------- + out : ndarray, {str, unicode} + Output array of str or unicode, depending on input type + + See also + -------- + str.upper + + Examples + -------- + >>> c = np.array(['a1b c', '1bca', 'bca1']); c + array(['a1b c', '1bca', 'bca1'], + dtype='|S5') + >>> np.char.upper(c) + array(['A1B C', '1BCA', 'BCA1'], + dtype='|S5') + + """ + a_arr = numpy.asarray(a) + return _vec_string(a_arr, a_arr.dtype, 'upper') + + +def zfill(a, width): + """ + Return the numeric string left-filled with zeros + + Calls `str.zfill` element-wise. + + Parameters + ---------- + a : array_like, {str, unicode} + Input array. + width : int + Width of string to left-fill elements in `a`. + + Returns + ------- + out : ndarray, {str, unicode} + Output array of str or unicode, depending on input type + + See also + -------- + str.zfill + + """ + a_arr = numpy.asarray(a) + width_arr = numpy.asarray(width) + size = long(numpy.max(width_arr.flat)) + return _vec_string( + a_arr, (a_arr.dtype.type, size), 'zfill', (width_arr,)) + + +def isnumeric(a): + """ + For each element, return True if there are only numeric + characters in the element. + + Calls `unicode.isnumeric` element-wise. + + Numeric characters include digit characters, and all characters + that have the Unicode numeric value property, e.g. ``U+2155, + VULGAR FRACTION ONE FIFTH``. + + Parameters + ---------- + a : array_like, unicode + Input array. + + Returns + ------- + out : ndarray, bool + Array of booleans of same shape as `a`. + + See also + -------- + unicode.isnumeric + + """ + if _use_unicode(a) != unicode_: + raise TypeError("isnumeric is only available for Unicode strings and arrays") + return _vec_string(a, bool_, 'isnumeric') + + +def isdecimal(a): + """ + For each element, return True if there are only decimal + characters in the element. + + Calls `unicode.isdecimal` element-wise. + + Decimal characters include digit characters, and all characters + that that can be used to form decimal-radix numbers, + e.g. ``U+0660, ARABIC-INDIC DIGIT ZERO``. + + Parameters + ---------- + a : array_like, unicode + Input array. + + Returns + ------- + out : ndarray, bool + Array of booleans identical in shape to `a`. + + See also + -------- + unicode.isdecimal + + """ + if _use_unicode(a) != unicode_: + raise TypeError("isnumeric is only available for Unicode strings and arrays") + return _vec_string(a, bool_, 'isdecimal') + + +class chararray(ndarray): + """ + chararray(shape, itemsize=1, unicode=False, buffer=None, offset=0, + strides=None, order=None) + + Provides a convenient view on arrays of string and unicode values. + + .. note:: + The `chararray` class exists for backwards compatibility with + Numarray, it is not recommended for new development. Starting from numpy + 1.4, if one needs arrays of strings, it is recommended to use arrays of + `dtype` `object_`, `string_` or `unicode_`, and use the free functions + in the `numpy.char` module for fast vectorized string operations. + + Versus a regular NumPy array of type `str` or `unicode`, this + class adds the following functionality: + + 1) values automatically have whitespace removed from the end + when indexed + + 2) comparison operators automatically remove whitespace from the + end when comparing values + + 3) vectorized string operations are provided as methods + (e.g. `.endswith`) and infix operators (e.g. ``"+", "*", "%"``) + + chararrays should be created using `numpy.char.array` or + `numpy.char.asarray`, rather than this constructor directly. + + This constructor creates the array, using `buffer` (with `offset` + and `strides`) if it is not ``None``. If `buffer` is ``None``, then + constructs a new array with `strides` in "C order", unless both + ``len(shape) >= 2`` and ``order='Fortran'``, in which case `strides` + is in "Fortran order". + + Methods + ------- + astype + argsort + copy + count + decode + dump + dumps + encode + endswith + expandtabs + fill + find + flatten + getfield + index + isalnum + isalpha + isdecimal + isdigit + islower + isnumeric + isspace + istitle + isupper + item + join + ljust + lower + lstrip + nonzero + put + ravel + repeat + replace + reshape + resize + rfind + rindex + rjust + rsplit + rstrip + searchsorted + setfield + setflags + sort + split + splitlines + squeeze + startswith + strip + swapaxes + swapcase + take + title + tofile + tolist + tostring + translate + transpose + upper + view + zfill + + Parameters + ---------- + shape : tuple + Shape of the array. + itemsize : int, optional + Length of each array element, in number of characters. Default is 1. + unicode : bool, optional + Are the array elements of type unicode (True) or string (False). + Default is False. + buffer : int, optional + Memory address of the start of the array data. Default is None, + in which case a new array is created. + offset : int, optional + Fixed stride displacement from the beginning of an axis? + Default is 0. Needs to be >=0. + strides : array_like of ints, optional + Strides for the array (see `ndarray.strides` for full description). + Default is None. + order : {'C', 'F'}, optional + The order in which the array data is stored in memory: 'C' -> + "row major" order (the default), 'F' -> "column major" + (Fortran) order. + + Examples + -------- + >>> charar = np.chararray((3, 3)) + >>> charar[:] = 'a' + >>> charar + chararray([['a', 'a', 'a'], + ['a', 'a', 'a'], + ['a', 'a', 'a']], + dtype='|S1') + + >>> charar = np.chararray(charar.shape, itemsize=5) + >>> charar[:] = 'abc' + >>> charar + chararray([['abc', 'abc', 'abc'], + ['abc', 'abc', 'abc'], + ['abc', 'abc', 'abc']], + dtype='|S5') + + """ + def __new__(subtype, shape, itemsize=1, unicode=False, buffer=None, + offset=0, strides=None, order='C'): + global _globalvar + + if unicode: + dtype = unicode_ + else: + dtype = string_ + + # force itemsize to be a Python long, since using NumPy integer + # types results in itemsize.itemsize being used as the size of + # strings in the new array. + itemsize = long(itemsize) + + if sys.version_info[0] >= 3 and isinstance(buffer, _unicode): + # On Py3, unicode objects do not have the buffer interface + filler = buffer + buffer = None + else: + filler = None + + _globalvar = 1 + if buffer is None: + self = ndarray.__new__(subtype, shape, (dtype, itemsize), + order=order) + else: + self = ndarray.__new__(subtype, shape, (dtype, itemsize), + buffer=buffer, + offset=offset, strides=strides, + order=order) + if filler is not None: + self[...] = filler + _globalvar = 0 + return self + + def __array_finalize__(self, obj): + # The b is a special case because it is used for reconstructing. + if not _globalvar and self.dtype.char not in 'SUbc': + raise ValueError("Can only create a chararray from string data.") + + def __getitem__(self, obj): + val = ndarray.__getitem__(self, obj) + + if isinstance(val, character): + temp = val.rstrip() + if _len(temp) == 0: + val = '' + else: + val = temp + + return val + + # IMPLEMENTATION NOTE: Most of the methods of this class are + # direct delegations to the free functions in this module. + # However, those that return an array of strings should instead + # return a chararray, so some extra wrapping is required. + + def __eq__(self, other): + """ + Return (self == other) element-wise. + + See also + -------- + equal + """ + return equal(self, other) + + def __ne__(self, other): + """ + Return (self != other) element-wise. + + See also + -------- + not_equal + """ + return not_equal(self, other) + + def __ge__(self, other): + """ + Return (self >= other) element-wise. + + See also + -------- + greater_equal + """ + return greater_equal(self, other) + + def __le__(self, other): + """ + Return (self <= other) element-wise. + + See also + -------- + less_equal + """ + return less_equal(self, other) + + def __gt__(self, other): + """ + Return (self > other) element-wise. + + See also + -------- + greater + """ + return greater(self, other) + + def __lt__(self, other): + """ + Return (self < other) element-wise. + + See also + -------- + less + """ + return less(self, other) + + def __add__(self, other): + """ + Return (self + other), that is string concatenation, + element-wise for a pair of array_likes of str or unicode. + + See also + -------- + add + """ + return asarray(add(self, other)) + + def __radd__(self, other): + """ + Return (other + self), that is string concatenation, + element-wise for a pair of array_likes of `string_` or `unicode_`. + + See also + -------- + add + """ + return asarray(add(numpy.asarray(other), self)) + + def __mul__(self, i): + """ + Return (self * i), that is string multiple concatenation, + element-wise. + + See also + -------- + multiply + """ + return asarray(multiply(self, i)) + + def __rmul__(self, i): + """ + Return (self * i), that is string multiple concatenation, + element-wise. + + See also + -------- + multiply + """ + return asarray(multiply(self, i)) + + def __mod__(self, i): + """ + Return (self % i), that is pre-Python 2.6 string formatting + (iterpolation), element-wise for a pair of array_likes of `string_` + or `unicode_`. + + See also + -------- + mod + """ + return asarray(mod(self, i)) + + def __rmod__(self, other): + return NotImplemented + + def argsort(self, axis=-1, kind='quicksort', order=None): + """ + Return the indices that sort the array lexicographically. + + For full documentation see `numpy.argsort`, for which this method is + in fact merely a "thin wrapper." + + Examples + -------- + >>> c = np.array(['a1b c', '1b ca', 'b ca1', 'Ca1b'], 'S5') + >>> c = c.view(np.chararray); c + chararray(['a1b c', '1b ca', 'b ca1', 'Ca1b'], + dtype='|S5') + >>> c[c.argsort()] + chararray(['1b ca', 'Ca1b', 'a1b c', 'b ca1'], + dtype='|S5') + + """ + return self.__array__().argsort(axis, kind, order) + argsort.__doc__ = ndarray.argsort.__doc__ + + def capitalize(self): + """ + Return a copy of `self` with only the first character of each element + capitalized. + + See also + -------- + char.capitalize + + """ + return asarray(capitalize(self)) + + def center(self, width, fillchar=' '): + """ + Return a copy of `self` with its elements centered in a + string of length `width`. + + See also + -------- + center + """ + return asarray(center(self, width, fillchar)) + + def count(self, sub, start=0, end=None): + """ + Returns an array with the number of non-overlapping occurrences of + substring `sub` in the range [`start`, `end`]. + + See also + -------- + char.count + + """ + return count(self, sub, start, end) + + def decode(self, encoding=None, errors=None): + """ + Calls `str.decode` element-wise. + + See also + -------- + char.decode + + """ + return decode(self, encoding, errors) + + def encode(self, encoding=None, errors=None): + """ + Calls `str.encode` element-wise. + + See also + -------- + char.encode + + """ + return encode(self, encoding, errors) + + def endswith(self, suffix, start=0, end=None): + """ + Returns a boolean array which is `True` where the string element + in `self` ends with `suffix`, otherwise `False`. + + See also + -------- + char.endswith + + """ + return endswith(self, suffix, start, end) + + def expandtabs(self, tabsize=8): + """ + Return a copy of each string element where all tab characters are + replaced by one or more spaces. + + See also + -------- + char.expandtabs + + """ + return asarray(expandtabs(self, tabsize)) + + def find(self, sub, start=0, end=None): + """ + For each element, return the lowest index in the string where + substring `sub` is found. + + See also + -------- + char.find + + """ + return find(self, sub, start, end) + + def index(self, sub, start=0, end=None): + """ + Like `find`, but raises `ValueError` when the substring is not found. + + See also + -------- + char.index + + """ + return index(self, sub, start, end) + + def isalnum(self): + """ + Returns true for each element if all characters in the string + are alphanumeric and there is at least one character, false + otherwise. + + See also + -------- + char.isalnum + + """ + return isalnum(self) + + def isalpha(self): + """ + Returns true for each element if all characters in the string + are alphabetic and there is at least one character, false + otherwise. + + See also + -------- + char.isalpha + + """ + return isalpha(self) + + def isdigit(self): + """ + Returns true for each element if all characters in the string are + digits and there is at least one character, false otherwise. + + See also + -------- + char.isdigit + + """ + return isdigit(self) + + def islower(self): + """ + Returns true for each element if all cased characters in the + string are lowercase and there is at least one cased character, + false otherwise. + + See also + -------- + char.islower + + """ + return islower(self) + + def isspace(self): + """ + Returns true for each element if there are only whitespace + characters in the string and there is at least one character, + false otherwise. + + See also + -------- + char.isspace + + """ + return isspace(self) + + def istitle(self): + """ + Returns true for each element if the element is a titlecased + string and there is at least one character, false otherwise. + + See also + -------- + char.istitle + + """ + return istitle(self) + + def isupper(self): + """ + Returns true for each element if all cased characters in the + string are uppercase and there is at least one character, false + otherwise. + + See also + -------- + char.isupper + + """ + return isupper(self) + + def join(self, seq): + """ + Return a string which is the concatenation of the strings in the + sequence `seq`. + + See also + -------- + char.join + + """ + return join(self, seq) + + def ljust(self, width, fillchar=' '): + """ + Return an array with the elements of `self` left-justified in a + string of length `width`. + + See also + -------- + char.ljust + + """ + return asarray(ljust(self, width, fillchar)) + + def lower(self): + """ + Return an array with the elements of `self` converted to + lowercase. + + See also + -------- + char.lower + + """ + return asarray(lower(self)) + + def lstrip(self, chars=None): + """ + For each element in `self`, return a copy with the leading characters + removed. + + See also + -------- + char.lstrip + + """ + return asarray(lstrip(self, chars)) + + def partition(self, sep): + """ + Partition each element in `self` around `sep`. + + See also + -------- + partition + """ + return asarray(partition(self, sep)) + + def replace(self, old, new, count=None): + """ + For each element in `self`, return a copy of the string with all + occurrences of substring `old` replaced by `new`. + + See also + -------- + char.replace + + """ + return asarray(replace(self, old, new, count)) + + def rfind(self, sub, start=0, end=None): + """ + For each element in `self`, return the highest index in the string + where substring `sub` is found, such that `sub` is contained + within [`start`, `end`]. + + See also + -------- + char.rfind + + """ + return rfind(self, sub, start, end) + + def rindex(self, sub, start=0, end=None): + """ + Like `rfind`, but raises `ValueError` when the substring `sub` is + not found. + + See also + -------- + char.rindex + + """ + return rindex(self, sub, start, end) + + def rjust(self, width, fillchar=' '): + """ + Return an array with the elements of `self` + right-justified in a string of length `width`. + + See also + -------- + char.rjust + + """ + return asarray(rjust(self, width, fillchar)) + + def rpartition(self, sep): + """ + Partition each element in `self` around `sep`. + + See also + -------- + rpartition + """ + return asarray(rpartition(self, sep)) + + def rsplit(self, sep=None, maxsplit=None): + """ + For each element in `self`, return a list of the words in + the string, using `sep` as the delimiter string. + + See also + -------- + char.rsplit + + """ + return rsplit(self, sep, maxsplit) + + def rstrip(self, chars=None): + """ + For each element in `self`, return a copy with the trailing + characters removed. + + See also + -------- + char.rstrip + + """ + return asarray(rstrip(self, chars)) + + def split(self, sep=None, maxsplit=None): + """ + For each element in `self`, return a list of the words in the + string, using `sep` as the delimiter string. + + See also + -------- + char.split + + """ + return split(self, sep, maxsplit) + + def splitlines(self, keepends=None): + """ + For each element in `self`, return a list of the lines in the + element, breaking at line boundaries. + + See also + -------- + char.splitlines + + """ + return splitlines(self, keepends) + + def startswith(self, prefix, start=0, end=None): + """ + Returns a boolean array which is `True` where the string element + in `self` starts with `prefix`, otherwise `False`. + + See also + -------- + char.startswith + + """ + return startswith(self, prefix, start, end) + + def strip(self, chars=None): + """ + For each element in `self`, return a copy with the leading and + trailing characters removed. + + See also + -------- + char.strip + + """ + return asarray(strip(self, chars)) + + def swapcase(self): + """ + For each element in `self`, return a copy of the string with + uppercase characters converted to lowercase and vice versa. + + See also + -------- + char.swapcase + + """ + return asarray(swapcase(self)) + + def title(self): + """ + For each element in `self`, return a titlecased version of the + string: words start with uppercase characters, all remaining cased + characters are lowercase. + + See also + -------- + char.title + + """ + return asarray(title(self)) + + def translate(self, table, deletechars=None): + """ + For each element in `self`, return a copy of the string where + all characters occurring in the optional argument + `deletechars` are removed, and the remaining characters have + been mapped through the given translation table. + + See also + -------- + char.translate + + """ + return asarray(translate(self, table, deletechars)) + + def upper(self): + """ + Return an array with the elements of `self` converted to + uppercase. + + See also + -------- + char.upper + + """ + return asarray(upper(self)) + + def zfill(self, width): + """ + Return the numeric string left-filled with zeros in a string of + length `width`. + + See also + -------- + char.zfill + + """ + return asarray(zfill(self, width)) + + def isnumeric(self): + """ + For each element in `self`, return True if there are only + numeric characters in the element. + + See also + -------- + char.isnumeric + + """ + return isnumeric(self) + + def isdecimal(self): + """ + For each element in `self`, return True if there are only + decimal characters in the element. + + See also + -------- + char.isdecimal + + """ + return isdecimal(self) + + +def array(obj, itemsize=None, copy=True, unicode=None, order=None): + """ + Create a `chararray`. + + .. note:: + This class is provided for numarray backward-compatibility. + New code (not concerned with numarray compatibility) should use + arrays of type `string_` or `unicode_` and use the free functions + in :mod:`numpy.char ` for fast + vectorized string operations instead. + + Versus a regular NumPy array of type `str` or `unicode`, this + class adds the following functionality: + + 1) values automatically have whitespace removed from the end + when indexed + + 2) comparison operators automatically remove whitespace from the + end when comparing values + + 3) vectorized string operations are provided as methods + (e.g. `str.endswith`) and infix operators (e.g. ``+, *, %``) + + Parameters + ---------- + obj : array of str or unicode-like + + itemsize : int, optional + `itemsize` is the number of characters per scalar in the + resulting array. If `itemsize` is None, and `obj` is an + object array or a Python list, the `itemsize` will be + automatically determined. If `itemsize` is provided and `obj` + is of type str or unicode, then the `obj` string will be + chunked into `itemsize` pieces. + + copy : bool, optional + If true (default), then the object is copied. Otherwise, a copy + will only be made if __array__ returns a copy, if obj is a + nested sequence, or if a copy is needed to satisfy any of the other + requirements (`itemsize`, unicode, `order`, etc.). + + unicode : bool, optional + When true, the resulting `chararray` can contain Unicode + characters, when false only 8-bit characters. If unicode is + `None` and `obj` is one of the following: + + - a `chararray`, + - an ndarray of type `str` or `unicode` + - a Python str or unicode object, + + then the unicode setting of the output array will be + automatically determined. + + order : {'C', 'F', 'A'}, optional + Specify the order of the array. If order is 'C' (default), then the + array will be in C-contiguous order (last-index varies the + fastest). If order is 'F', then the returned array + will be in Fortran-contiguous order (first-index varies the + fastest). If order is 'A', then the returned array may + be in any order (either C-, Fortran-contiguous, or even + discontiguous). + """ + if isinstance(obj, (_bytes, _unicode)): + if unicode is None: + if isinstance(obj, _unicode): + unicode = True + else: + unicode = False + + if itemsize is None: + itemsize = _len(obj) + shape = _len(obj) // itemsize + + if unicode: + if sys.maxunicode == 0xffff: + # On a narrow Python build, the buffer for Unicode + # strings is UCS2, which doesn't match the buffer for + # NumPy Unicode types, which is ALWAYS UCS4. + # Therefore, we need to convert the buffer. On Python + # 2.6 and later, we can use the utf_32 codec. Earlier + # versions don't have that codec, so we convert to a + # numerical array that matches the input buffer, and + # then use NumPy to convert it to UCS4. All of this + # should happen in native endianness. + obj = obj.encode('utf_32') + else: + obj = _unicode(obj) + else: + # Let the default Unicode -> string encoding (if any) take + # precedence. + obj = _bytes(obj) + + return chararray(shape, itemsize=itemsize, unicode=unicode, + buffer=obj, order=order) + + if isinstance(obj, (list, tuple)): + obj = numpy.asarray(obj) + + if isinstance(obj, ndarray) and issubclass(obj.dtype.type, character): + # If we just have a vanilla chararray, create a chararray + # view around it. + if not isinstance(obj, chararray): + obj = obj.view(chararray) + + if itemsize is None: + itemsize = obj.itemsize + # itemsize is in 8-bit chars, so for Unicode, we need + # to divide by the size of a single Unicode character, + # which for NumPy is always 4 + if issubclass(obj.dtype.type, unicode_): + itemsize //= 4 + + if unicode is None: + if issubclass(obj.dtype.type, unicode_): + unicode = True + else: + unicode = False + + if unicode: + dtype = unicode_ + else: + dtype = string_ + + if order is not None: + obj = numpy.asarray(obj, order=order) + if (copy or + (itemsize != obj.itemsize) or + (not unicode and isinstance(obj, unicode_)) or + (unicode and isinstance(obj, string_))): + obj = obj.astype((dtype, long(itemsize))) + return obj + + if isinstance(obj, ndarray) and issubclass(obj.dtype.type, object): + if itemsize is None: + # Since no itemsize was specified, convert the input array to + # a list so the ndarray constructor will automatically + # determine the itemsize for us. + obj = obj.tolist() + # Fall through to the default case + + if unicode: + dtype = unicode_ + else: + dtype = string_ + + if itemsize is None: + val = narray(obj, dtype=dtype, order=order, subok=True) + else: + val = narray(obj, dtype=(dtype, itemsize), order=order, subok=True) + return val.view(chararray) + + +def asarray(obj, itemsize=None, unicode=None, order=None): + """ + Convert the input to a `chararray`, copying the data only if + necessary. + + Versus a regular NumPy array of type `str` or `unicode`, this + class adds the following functionality: + + 1) values automatically have whitespace removed from the end + when indexed + + 2) comparison operators automatically remove whitespace from the + end when comparing values + + 3) vectorized string operations are provided as methods + (e.g. `str.endswith`) and infix operators (e.g. ``+``, ``*``,``%``) + + Parameters + ---------- + obj : array of str or unicode-like + + itemsize : int, optional + `itemsize` is the number of characters per scalar in the + resulting array. If `itemsize` is None, and `obj` is an + object array or a Python list, the `itemsize` will be + automatically determined. If `itemsize` is provided and `obj` + is of type str or unicode, then the `obj` string will be + chunked into `itemsize` pieces. + + unicode : bool, optional + When true, the resulting `chararray` can contain Unicode + characters, when false only 8-bit characters. If unicode is + `None` and `obj` is one of the following: + + - a `chararray`, + - an ndarray of type `str` or 'unicode` + - a Python str or unicode object, + + then the unicode setting of the output array will be + automatically determined. + + order : {'C', 'F'}, optional + Specify the order of the array. If order is 'C' (default), then the + array will be in C-contiguous order (last-index varies the + fastest). If order is 'F', then the returned array + will be in Fortran-contiguous order (first-index varies the + fastest). + """ + return array(obj, itemsize, copy=False, + unicode=unicode, order=order) diff --git a/numpy/core/einsumfunc.py b/numpy/core/einsumfunc.py new file mode 100644 index 0000000..da78748 --- /dev/null +++ b/numpy/core/einsumfunc.py @@ -0,0 +1,1158 @@ +""" +Implementation of optimized einsum. + +""" +from __future__ import division, absolute_import, print_function + +from numpy.compat import basestring +from numpy.core.multiarray import c_einsum +from numpy.core.numeric import asarray, asanyarray, result_type, tensordot, dot + +__all__ = ['einsum', 'einsum_path'] + +einsum_symbols = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' +einsum_symbols_set = set(einsum_symbols) + + +def _compute_size_by_dict(indices, idx_dict): + """ + Computes the product of the elements in indices based on the dictionary + idx_dict. + + Parameters + ---------- + indices : iterable + Indices to base the product on. + idx_dict : dictionary + Dictionary of index sizes + + Returns + ------- + ret : int + The resulting product. + + Examples + -------- + >>> _compute_size_by_dict('abbc', {'a': 2, 'b':3, 'c':5}) + 90 + + """ + ret = 1 + for i in indices: + ret *= idx_dict[i] + return ret + + +def _find_contraction(positions, input_sets, output_set): + """ + Finds the contraction for a given set of input and output sets. + + Parameters + ---------- + positions : iterable + Integer positions of terms used in the contraction. + input_sets : list + List of sets that represent the lhs side of the einsum subscript + output_set : set + Set that represents the rhs side of the overall einsum subscript + + Returns + ------- + new_result : set + The indices of the resulting contraction + remaining : list + List of sets that have not been contracted, the new set is appended to + the end of this list + idx_removed : set + Indices removed from the entire contraction + idx_contraction : set + The indices used in the current contraction + + Examples + -------- + + # A simple dot product test case + >>> pos = (0, 1) + >>> isets = [set('ab'), set('bc')] + >>> oset = set('ac') + >>> _find_contraction(pos, isets, oset) + ({'a', 'c'}, [{'a', 'c'}], {'b'}, {'a', 'b', 'c'}) + + # A more complex case with additional terms in the contraction + >>> pos = (0, 2) + >>> isets = [set('abd'), set('ac'), set('bdc')] + >>> oset = set('ac') + >>> _find_contraction(pos, isets, oset) + ({'a', 'c'}, [{'a', 'c'}, {'a', 'c'}], {'b', 'd'}, {'a', 'b', 'c', 'd'}) + """ + + idx_contract = set() + idx_remain = output_set.copy() + remaining = [] + for ind, value in enumerate(input_sets): + if ind in positions: + idx_contract |= value + else: + remaining.append(value) + idx_remain |= value + + new_result = idx_remain & idx_contract + idx_removed = (idx_contract - new_result) + remaining.append(new_result) + + return (new_result, remaining, idx_removed, idx_contract) + + +def _optimal_path(input_sets, output_set, idx_dict, memory_limit): + """ + Computes all possible pair contractions, sieves the results based + on ``memory_limit`` and returns the lowest cost path. This algorithm + scales factorial with respect to the elements in the list ``input_sets``. + + Parameters + ---------- + input_sets : list + List of sets that represent the lhs side of the einsum subscript + output_set : set + Set that represents the rhs side of the overall einsum subscript + idx_dict : dictionary + Dictionary of index sizes + memory_limit : int + The maximum number of elements in a temporary array + + Returns + ------- + path : list + The optimal contraction order within the memory limit constraint. + + Examples + -------- + >>> isets = [set('abd'), set('ac'), set('bdc')] + >>> oset = set('') + >>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4} + >>> _path__optimal_path(isets, oset, idx_sizes, 5000) + [(0, 2), (0, 1)] + """ + + full_results = [(0, [], input_sets)] + for iteration in range(len(input_sets) - 1): + iter_results = [] + + # Compute all unique pairs + comb_iter = [] + for x in range(len(input_sets) - iteration): + for y in range(x + 1, len(input_sets) - iteration): + comb_iter.append((x, y)) + + for curr in full_results: + cost, positions, remaining = curr + for con in comb_iter: + + # Find the contraction + cont = _find_contraction(con, remaining, output_set) + new_result, new_input_sets, idx_removed, idx_contract = cont + + # Sieve the results based on memory_limit + new_size = _compute_size_by_dict(new_result, idx_dict) + if new_size > memory_limit: + continue + + # Find cost + new_cost = _compute_size_by_dict(idx_contract, idx_dict) + if idx_removed: + new_cost *= 2 + + # Build (total_cost, positions, indices_remaining) + new_cost += cost + new_pos = positions + [con] + iter_results.append((new_cost, new_pos, new_input_sets)) + + # Update combinatorial list, if we did not find anything return best + # path + remaining contractions + if iter_results: + full_results = iter_results + else: + path = min(full_results, key=lambda x: x[0])[1] + path += [tuple(range(len(input_sets) - iteration))] + return path + + # If we have not found anything return single einsum contraction + if len(full_results) == 0: + return [tuple(range(len(input_sets)))] + + path = min(full_results, key=lambda x: x[0])[1] + return path + + +def _greedy_path(input_sets, output_set, idx_dict, memory_limit): + """ + Finds the path by contracting the best pair until the input list is + exhausted. The best pair is found by minimizing the tuple + ``(-prod(indices_removed), cost)``. What this amounts to is prioritizing + matrix multiplication or inner product operations, then Hadamard like + operations, and finally outer operations. Outer products are limited by + ``memory_limit``. This algorithm scales cubically with respect to the + number of elements in the list ``input_sets``. + + Parameters + ---------- + input_sets : list + List of sets that represent the lhs side of the einsum subscript + output_set : set + Set that represents the rhs side of the overall einsum subscript + idx_dict : dictionary + Dictionary of index sizes + memory_limit_limit : int + The maximum number of elements in a temporary array + + Returns + ------- + path : list + The greedy contraction order within the memory limit constraint. + + Examples + -------- + >>> isets = [set('abd'), set('ac'), set('bdc')] + >>> oset = set('') + >>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4} + >>> _path__greedy_path(isets, oset, idx_sizes, 5000) + [(0, 2), (0, 1)] + """ + + if len(input_sets) == 1: + return [(0,)] + + path = [] + for iteration in range(len(input_sets) - 1): + iteration_results = [] + comb_iter = [] + + # Compute all unique pairs + for x in range(len(input_sets)): + for y in range(x + 1, len(input_sets)): + comb_iter.append((x, y)) + + for positions in comb_iter: + + # Find the contraction + contract = _find_contraction(positions, input_sets, output_set) + idx_result, new_input_sets, idx_removed, idx_contract = contract + + # Sieve the results based on memory_limit + if _compute_size_by_dict(idx_result, idx_dict) > memory_limit: + continue + + # Build sort tuple + removed_size = _compute_size_by_dict(idx_removed, idx_dict) + cost = _compute_size_by_dict(idx_contract, idx_dict) + sort = (-removed_size, cost) + + # Add contraction to possible choices + iteration_results.append([sort, positions, new_input_sets]) + + # If we did not find a new contraction contract remaining + if len(iteration_results) == 0: + path.append(tuple(range(len(input_sets)))) + break + + # Sort based on first index + best = min(iteration_results, key=lambda x: x[0]) + path.append(best[1]) + input_sets = best[2] + + return path + + +def _can_dot(inputs, result, idx_removed): + """ + Checks if we can use BLAS (np.tensordot) call and its beneficial to do so. + + Parameters + ---------- + inputs : list of str + Specifies the subscripts for summation. + result : str + Resulting summation. + idx_removed : set + Indices that are removed in the summation + + + Returns + ------- + type : bool + Returns true if BLAS should and can be used, else False + + Notes + ----- + If the operations is BLAS level 1 or 2 and is not already aligned + we default back to einsum as the memory movement to copy is more + costly than the operation itself. + + + Examples + -------- + + # Standard GEMM operation + >>> _can_dot(['ij', 'jk'], 'ik', set('j')) + True + + # Can use the standard BLAS, but requires odd data movement + >>> _can_dot(['ijj', 'jk'], 'ik', set('j')) + False + + # DDOT where the memory is not aligned + >>> _can_dot(['ijk', 'ikj'], '', set('ijk')) + False + + """ + + # All `dot` calls remove indices + if len(idx_removed) == 0: + return False + + # BLAS can only handle two operands + if len(inputs) != 2: + return False + + # Build a few temporaries + input_left, input_right = inputs + set_left = set(input_left) + set_right = set(input_right) + keep_left = set_left - idx_removed + keep_right = set_right - idx_removed + rs = len(idx_removed) + + # Indices must overlap between the two operands + if not len(set_left & set_right): + return False + + # We cannot have duplicate indices ("ijj, jk -> ik") + if (len(set_left) != len(input_left)) or (len(set_right) != len(input_right)): + return False + + # Cannot handle partial inner ("ij, ji -> i") + if len(keep_left & keep_right): + return False + + # At this point we are a DOT, GEMV, or GEMM operation + + # Handle inner products + + # DDOT with aligned data + if input_left == input_right: + return True + + # DDOT without aligned data (better to use einsum) + if set_left == set_right: + return False + + # Handle the 4 possible (aligned) GEMV or GEMM cases + + # GEMM or GEMV no transpose + if input_left[-rs:] == input_right[:rs]: + return True + + # GEMM or GEMV transpose both + if input_left[:rs] == input_right[-rs:]: + return True + + # GEMM or GEMV transpose right + if input_left[-rs:] == input_right[-rs:]: + return True + + # GEMM or GEMV transpose left + if input_left[:rs] == input_right[:rs]: + return True + + # Einsum is faster than GEMV if we have to copy data + if not keep_left or not keep_right: + return False + + # We are a matrix-matrix product, but we need to copy data + return True + +def _parse_einsum_input(operands): + """ + A reproduction of einsum c side einsum parsing in python. + + Returns + ------- + input_strings : str + Parsed input strings + output_string : str + Parsed output string + operands : list of array_like + The operands to use in the numpy contraction + + Examples + -------- + The operand list is simplified to reduce printing: + + >>> a = np.random.rand(4, 4) + >>> b = np.random.rand(4, 4, 4) + >>> __parse_einsum_input(('...a,...a->...', a, b)) + ('za,xza', 'xz', [a, b]) + + >>> __parse_einsum_input((a, [Ellipsis, 0], b, [Ellipsis, 0])) + ('za,xza', 'xz', [a, b]) + """ + + if len(operands) == 0: + raise ValueError("No input operands") + + if isinstance(operands[0], basestring): + subscripts = operands[0].replace(" ", "") + operands = [asanyarray(v) for v in operands[1:]] + + # Ensure all characters are valid + for s in subscripts: + if s in '.,->': + continue + if s not in einsum_symbols: + raise ValueError("Character %s is not a valid symbol." % s) + + else: + tmp_operands = list(operands) + operand_list = [] + subscript_list = [] + for p in range(len(operands) // 2): + operand_list.append(tmp_operands.pop(0)) + subscript_list.append(tmp_operands.pop(0)) + + output_list = tmp_operands[-1] if len(tmp_operands) else None + operands = [asanyarray(v) for v in operand_list] + subscripts = "" + last = len(subscript_list) - 1 + for num, sub in enumerate(subscript_list): + for s in sub: + if s is Ellipsis: + subscripts += "..." + elif isinstance(s, int): + subscripts += einsum_symbols[s] + else: + raise TypeError("For this input type lists must contain " + "either int or Ellipsis") + if num != last: + subscripts += "," + + if output_list is not None: + subscripts += "->" + for s in output_list: + if s is Ellipsis: + subscripts += "..." + elif isinstance(s, int): + subscripts += einsum_symbols[s] + else: + raise TypeError("For this input type lists must contain " + "either int or Ellipsis") + # Check for proper "->" + if ("-" in subscripts) or (">" in subscripts): + invalid = (subscripts.count("-") > 1) or (subscripts.count(">") > 1) + if invalid or (subscripts.count("->") != 1): + raise ValueError("Subscripts can only contain one '->'.") + + # Parse ellipses + if "." in subscripts: + used = subscripts.replace(".", "").replace(",", "").replace("->", "") + unused = list(einsum_symbols_set - set(used)) + ellipse_inds = "".join(unused) + longest = 0 + + if "->" in subscripts: + input_tmp, output_sub = subscripts.split("->") + split_subscripts = input_tmp.split(",") + out_sub = True + else: + split_subscripts = subscripts.split(',') + out_sub = False + + for num, sub in enumerate(split_subscripts): + if "." in sub: + if (sub.count(".") != 3) or (sub.count("...") != 1): + raise ValueError("Invalid Ellipses.") + + # Take into account numerical values + if operands[num].shape == (): + ellipse_count = 0 + else: + ellipse_count = max(operands[num].ndim, 1) + ellipse_count -= (len(sub) - 3) + + if ellipse_count > longest: + longest = ellipse_count + + if ellipse_count < 0: + raise ValueError("Ellipses lengths do not match.") + elif ellipse_count == 0: + split_subscripts[num] = sub.replace('...', '') + else: + rep_inds = ellipse_inds[-ellipse_count:] + split_subscripts[num] = sub.replace('...', rep_inds) + + subscripts = ",".join(split_subscripts) + if longest == 0: + out_ellipse = "" + else: + out_ellipse = ellipse_inds[-longest:] + + if out_sub: + subscripts += "->" + output_sub.replace("...", out_ellipse) + else: + # Special care for outputless ellipses + output_subscript = "" + tmp_subscripts = subscripts.replace(",", "") + for s in sorted(set(tmp_subscripts)): + if s not in (einsum_symbols): + raise ValueError("Character %s is not a valid symbol." % s) + if tmp_subscripts.count(s) == 1: + output_subscript += s + normal_inds = ''.join(sorted(set(output_subscript) - + set(out_ellipse))) + + subscripts += "->" + out_ellipse + normal_inds + + # Build output string if does not exist + if "->" in subscripts: + input_subscripts, output_subscript = subscripts.split("->") + else: + input_subscripts = subscripts + # Build output subscripts + tmp_subscripts = subscripts.replace(",", "") + output_subscript = "" + for s in sorted(set(tmp_subscripts)): + if s not in einsum_symbols: + raise ValueError("Character %s is not a valid symbol." % s) + if tmp_subscripts.count(s) == 1: + output_subscript += s + + # Make sure output subscripts are in the input + for char in output_subscript: + if char not in input_subscripts: + raise ValueError("Output character %s did not appear in the input" + % char) + + # Make sure number operands is equivalent to the number of terms + if len(input_subscripts.split(',')) != len(operands): + raise ValueError("Number of einsum subscripts must be equal to the " + "number of operands.") + + return (input_subscripts, output_subscript, operands) + + +def einsum_path(*operands, **kwargs): + """ + einsum_path(subscripts, *operands, optimize='greedy') + + Evaluates the lowest cost contraction order for an einsum expression by + considering the creation of intermediate arrays. + + Parameters + ---------- + subscripts : str + Specifies the subscripts for summation. + *operands : list of array_like + These are the arrays for the operation. + optimize : {bool, list, tuple, 'greedy', 'optimal'} + Choose the type of path. If a tuple is provided, the second argument is + assumed to be the maximum intermediate size created. If only a single + argument is provided the largest input or output array size is used + as a maximum intermediate size. + + * if a list is given that starts with ``einsum_path``, uses this as the + contraction path + * if False no optimization is taken + * if True defaults to the 'greedy' algorithm + * 'optimal' An algorithm that combinatorially explores all possible + ways of contracting the listed tensors and choosest the least costly + path. Scales exponentially with the number of terms in the + contraction. + * 'greedy' An algorithm that chooses the best pair contraction + at each step. Effectively, this algorithm searches the largest inner, + Hadamard, and then outer products at each step. Scales cubically with + the number of terms in the contraction. Equivalent to the 'optimal' + path for most contractions. + + Default is 'greedy'. + + Returns + ------- + path : list of tuples + A list representation of the einsum path. + string_repr : str + A printable representation of the einsum path. + + Notes + ----- + The resulting path indicates which terms of the input contraction should be + contracted first, the result of this contraction is then appended to the + end of the contraction list. This list can then be iterated over until all + intermediate contractions are complete. + + See Also + -------- + einsum, linalg.multi_dot + + Examples + -------- + + We can begin with a chain dot example. In this case, it is optimal to + contract the ``b`` and ``c`` tensors first as reprsented by the first + element of the path ``(1, 2)``. The resulting tensor is added to the end + of the contraction and the remaining contraction ``(0, 1)`` is then + completed. + + >>> a = np.random.rand(2, 2) + >>> b = np.random.rand(2, 5) + >>> c = np.random.rand(5, 2) + >>> path_info = np.einsum_path('ij,jk,kl->il', a, b, c, optimize='greedy') + >>> print(path_info[0]) + ['einsum_path', (1, 2), (0, 1)] + >>> print(path_info[1]) + Complete contraction: ij,jk,kl->il + Naive scaling: 4 + Optimized scaling: 3 + Naive FLOP count: 1.600e+02 + Optimized FLOP count: 5.600e+01 + Theoretical speedup: 2.857 + Largest intermediate: 4.000e+00 elements + ------------------------------------------------------------------------- + scaling current remaining + ------------------------------------------------------------------------- + 3 kl,jk->jl ij,jl->il + 3 jl,ij->il il->il + + + A more complex index transformation example. + + >>> I = np.random.rand(10, 10, 10, 10) + >>> C = np.random.rand(10, 10) + >>> path_info = np.einsum_path('ea,fb,abcd,gc,hd->efgh', C, C, I, C, C, + optimize='greedy') + + >>> print(path_info[0]) + ['einsum_path', (0, 2), (0, 3), (0, 2), (0, 1)] + >>> print(path_info[1]) + Complete contraction: ea,fb,abcd,gc,hd->efgh + Naive scaling: 8 + Optimized scaling: 5 + Naive FLOP count: 8.000e+08 + Optimized FLOP count: 8.000e+05 + Theoretical speedup: 1000.000 + Largest intermediate: 1.000e+04 elements + -------------------------------------------------------------------------- + scaling current remaining + -------------------------------------------------------------------------- + 5 abcd,ea->bcde fb,gc,hd,bcde->efgh + 5 bcde,fb->cdef gc,hd,cdef->efgh + 5 cdef,gc->defg hd,defg->efgh + 5 defg,hd->efgh efgh->efgh + """ + + # Make sure all keywords are valid + valid_contract_kwargs = ['optimize', 'einsum_call'] + unknown_kwargs = [k for (k, v) in kwargs.items() if k + not in valid_contract_kwargs] + if len(unknown_kwargs): + raise TypeError("Did not understand the following kwargs:" + " %s" % unknown_kwargs) + + # Figure out what the path really is + path_type = kwargs.pop('optimize', True) + if path_type is True: + path_type = 'greedy' + if path_type is None: + path_type = False + + memory_limit = None + + # No optimization or a named path algorithm + if (path_type is False) or isinstance(path_type, basestring): + pass + + # Given an explicit path + elif len(path_type) and (path_type[0] == 'einsum_path'): + pass + + # Path tuple with memory limit + elif ((len(path_type) == 2) and isinstance(path_type[0], basestring) and + isinstance(path_type[1], (int, float))): + memory_limit = int(path_type[1]) + path_type = path_type[0] + + else: + raise TypeError("Did not understand the path: %s" % str(path_type)) + + # Hidden option, only einsum should call this + einsum_call_arg = kwargs.pop("einsum_call", False) + + # Python side parsing + input_subscripts, output_subscript, operands = _parse_einsum_input(operands) + subscripts = input_subscripts + '->' + output_subscript + + # Build a few useful list and sets + input_list = input_subscripts.split(',') + input_sets = [set(x) for x in input_list] + output_set = set(output_subscript) + indices = set(input_subscripts.replace(',', '')) + + # Get length of each unique dimension and ensure all dimensions are correct + dimension_dict = {} + for tnum, term in enumerate(input_list): + sh = operands[tnum].shape + if len(sh) != len(term): + raise ValueError("Einstein sum subscript %s does not contain the " + "correct number of indices for operand %d." + % (input_subscripts[tnum], tnum)) + for cnum, char in enumerate(term): + dim = sh[cnum] + if char in dimension_dict.keys(): + # For broadcasting cases we always want the largest dim size + if dimension_dict[char] == 1: + dimension_dict[char] = dim + elif dim not in (1, dimension_dict[char]): + raise ValueError("Size of label '%s' for operand %d (%d) " + "does not match previous terms (%d)." + % (char, tnum, dimension_dict[char], dim)) + else: + dimension_dict[char] = dim + + # Compute size of each input array plus the output array + size_list = [] + for term in input_list + [output_subscript]: + size_list.append(_compute_size_by_dict(term, dimension_dict)) + max_size = max(size_list) + + if memory_limit is None: + memory_arg = max_size + else: + memory_arg = memory_limit + + # Compute naive cost + # This isnt quite right, need to look into exactly how einsum does this + naive_cost = _compute_size_by_dict(indices, dimension_dict) + indices_in_input = input_subscripts.replace(',', '') + mult = max(len(input_list) - 1, 1) + if (len(indices_in_input) - len(set(indices_in_input))): + mult *= 2 + naive_cost *= mult + + # Compute the path + if (path_type is False) or (len(input_list) in [1, 2]) or (indices == output_set): + # Nothing to be optimized, leave it to einsum + path = [tuple(range(len(input_list)))] + elif path_type == "greedy": + # Maximum memory should be at most out_size for this algorithm + memory_arg = min(memory_arg, max_size) + path = _greedy_path(input_sets, output_set, dimension_dict, memory_arg) + elif path_type == "optimal": + path = _optimal_path(input_sets, output_set, dimension_dict, memory_arg) + elif path_type[0] == 'einsum_path': + path = path_type[1:] + else: + raise KeyError("Path name %s not found", path_type) + + cost_list, scale_list, size_list, contraction_list = [], [], [], [] + + # Build contraction tuple (positions, gemm, einsum_str, remaining) + for cnum, contract_inds in enumerate(path): + # Make sure we remove inds from right to left + contract_inds = tuple(sorted(list(contract_inds), reverse=True)) + + contract = _find_contraction(contract_inds, input_sets, output_set) + out_inds, input_sets, idx_removed, idx_contract = contract + + cost = _compute_size_by_dict(idx_contract, dimension_dict) + if idx_removed: + cost *= 2 + cost_list.append(cost) + scale_list.append(len(idx_contract)) + size_list.append(_compute_size_by_dict(out_inds, dimension_dict)) + + tmp_inputs = [] + for x in contract_inds: + tmp_inputs.append(input_list.pop(x)) + + do_blas = _can_dot(tmp_inputs, out_inds, idx_removed) + + # Last contraction + if (cnum - len(path)) == -1: + idx_result = output_subscript + else: + sort_result = [(dimension_dict[ind], ind) for ind in out_inds] + idx_result = "".join([x[1] for x in sorted(sort_result)]) + + input_list.append(idx_result) + einsum_str = ",".join(tmp_inputs) + "->" + idx_result + + contraction = (contract_inds, idx_removed, einsum_str, input_list[:], do_blas) + contraction_list.append(contraction) + + opt_cost = sum(cost_list) + 1 + + if einsum_call_arg: + return (operands, contraction_list) + + # Return the path along with a nice string representation + overall_contraction = input_subscripts + "->" + output_subscript + header = ("scaling", "current", "remaining") + + speedup = naive_cost / opt_cost + max_i = max(size_list) + + path_print = " Complete contraction: %s\n" % overall_contraction + path_print += " Naive scaling: %d\n" % len(indices) + path_print += " Optimized scaling: %d\n" % max(scale_list) + path_print += " Naive FLOP count: %.3e\n" % naive_cost + path_print += " Optimized FLOP count: %.3e\n" % opt_cost + path_print += " Theoretical speedup: %3.3f\n" % speedup + path_print += " Largest intermediate: %.3e elements\n" % max_i + path_print += "-" * 74 + "\n" + path_print += "%6s %24s %40s\n" % header + path_print += "-" * 74 + + for n, contraction in enumerate(contraction_list): + inds, idx_rm, einsum_str, remaining, blas = contraction + remaining_str = ",".join(remaining) + "->" + output_subscript + path_run = (scale_list[n], einsum_str, remaining_str) + path_print += "\n%4d %24s %40s" % path_run + + path = ['einsum_path'] + path + return (path, path_print) + + +# Rewrite einsum to handle different cases +def einsum(*operands, **kwargs): + """ + einsum(subscripts, *operands, out=None, dtype=None, order='K', + casting='safe', optimize=False) + + Evaluates the Einstein summation convention on the operands. + + Using the Einstein summation convention, many common multi-dimensional + array operations can be represented in a simple fashion. This function + provides a way to compute such summations. The best way to understand this + function is to try the examples below, which show how many common NumPy + functions can be implemented as calls to `einsum`. + + Parameters + ---------- + subscripts : str + Specifies the subscripts for summation. + operands : list of array_like + These are the arrays for the operation. + out : {ndarray, None}, optional + If provided, the calculation is done into this array. + dtype : {data-type, None}, optional + If provided, forces the calculation to use the data type specified. + Note that you may have to also give a more liberal `casting` + parameter to allow the conversions. Default is None. + order : {'C', 'F', 'A', 'K'}, optional + Controls the memory layout of the output. 'C' means it should + be C contiguous. 'F' means it should be Fortran contiguous, + 'A' means it should be 'F' if the inputs are all 'F', 'C' otherwise. + 'K' means it should be as close to the layout as the inputs as + is possible, including arbitrarily permuted axes. + Default is 'K'. + casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional + Controls what kind of data casting may occur. Setting this to + 'unsafe' is not recommended, as it can adversely affect accumulations. + + * 'no' means the data types should not be cast at all. + * 'equiv' means only byte-order changes are allowed. + * 'safe' means only casts which can preserve values are allowed. + * 'same_kind' means only safe casts or casts within a kind, + like float64 to float32, are allowed. + * 'unsafe' means any data conversions may be done. + + Default is 'safe'. + optimize : {False, True, 'greedy', 'optimal'}, optional + Controls if intermediate optimization should occur. No optimization + will occur if False and True will default to the 'greedy' algorithm. + Also accepts an explicit contraction list from the ``np.einsum_path`` + function. See ``np.einsum_path`` for more details. Default is False. + + Returns + ------- + output : ndarray + The calculation based on the Einstein summation convention. + + See Also + -------- + einsum_path, dot, inner, outer, tensordot, linalg.multi_dot + + Notes + ----- + .. versionadded:: 1.6.0 + + The subscripts string is a comma-separated list of subscript labels, + where each label refers to a dimension of the corresponding operand. + Repeated subscripts labels in one operand take the diagonal. For example, + ``np.einsum('ii', a)`` is equivalent to ``np.trace(a)``. + + Whenever a label is repeated, it is summed, so ``np.einsum('i,i', a, b)`` + is equivalent to ``np.inner(a,b)``. If a label appears only once, + it is not summed, so ``np.einsum('i', a)`` produces a view of ``a`` + with no changes. + + The order of labels in the output is by default alphabetical. This + means that ``np.einsum('ij', a)`` doesn't affect a 2D array, while + ``np.einsum('ji', a)`` takes its transpose. + + The output can be controlled by specifying output subscript labels + as well. This specifies the label order, and allows summing to + be disallowed or forced when desired. The call ``np.einsum('i->', a)`` + is like ``np.sum(a, axis=-1)``, and ``np.einsum('ii->i', a)`` + is like ``np.diag(a)``. The difference is that `einsum` does not + allow broadcasting by default. + + To enable and control broadcasting, use an ellipsis. Default + NumPy-style broadcasting is done by adding an ellipsis + to the left of each term, like ``np.einsum('...ii->...i', a)``. + To take the trace along the first and last axes, + you can do ``np.einsum('i...i', a)``, or to do a matrix-matrix + product with the left-most indices instead of rightmost, you can do + ``np.einsum('ij...,jk...->ik...', a, b)``. + + When there is only one operand, no axes are summed, and no output + parameter is provided, a view into the operand is returned instead + of a new array. Thus, taking the diagonal as ``np.einsum('ii->i', a)`` + produces a view. + + An alternative way to provide the subscripts and operands is as + ``einsum(op0, sublist0, op1, sublist1, ..., [sublistout])``. The examples + below have corresponding `einsum` calls with the two parameter methods. + + .. versionadded:: 1.10.0 + + Views returned from einsum are now writeable whenever the input array + is writeable. For example, ``np.einsum('ijk...->kji...', a)`` will now + have the same effect as ``np.swapaxes(a, 0, 2)`` and + ``np.einsum('ii->i', a)`` will return a writeable view of the diagonal + of a 2D array. + + .. versionadded:: 1.12.0 + + Added the ``optimize`` argument which will optimize the contraction order + of an einsum expression. For a contraction with three or more operands this + can greatly increase the computational efficiency at the cost of a larger + memory footprint during computation. + + See ``np.einsum_path`` for more details. + + Examples + -------- + >>> a = np.arange(25).reshape(5,5) + >>> b = np.arange(5) + >>> c = np.arange(6).reshape(2,3) + + >>> np.einsum('ii', a) + 60 + >>> np.einsum(a, [0,0]) + 60 + >>> np.trace(a) + 60 + + >>> np.einsum('ii->i', a) + array([ 0, 6, 12, 18, 24]) + >>> np.einsum(a, [0,0], [0]) + array([ 0, 6, 12, 18, 24]) + >>> np.diag(a) + array([ 0, 6, 12, 18, 24]) + + >>> np.einsum('ij,j', a, b) + array([ 30, 80, 130, 180, 230]) + >>> np.einsum(a, [0,1], b, [1]) + array([ 30, 80, 130, 180, 230]) + >>> np.dot(a, b) + array([ 30, 80, 130, 180, 230]) + >>> np.einsum('...j,j', a, b) + array([ 30, 80, 130, 180, 230]) + + >>> np.einsum('ji', c) + array([[0, 3], + [1, 4], + [2, 5]]) + >>> np.einsum(c, [1,0]) + array([[0, 3], + [1, 4], + [2, 5]]) + >>> c.T + array([[0, 3], + [1, 4], + [2, 5]]) + + >>> np.einsum('..., ...', 3, c) + array([[ 0, 3, 6], + [ 9, 12, 15]]) + >>> np.einsum(',ij', 3, C) + array([[ 0, 3, 6], + [ 9, 12, 15]]) + >>> np.einsum(3, [Ellipsis], c, [Ellipsis]) + array([[ 0, 3, 6], + [ 9, 12, 15]]) + >>> np.multiply(3, c) + array([[ 0, 3, 6], + [ 9, 12, 15]]) + + >>> np.einsum('i,i', b, b) + 30 + >>> np.einsum(b, [0], b, [0]) + 30 + >>> np.inner(b,b) + 30 + + >>> np.einsum('i,j', np.arange(2)+1, b) + array([[0, 1, 2, 3, 4], + [0, 2, 4, 6, 8]]) + >>> np.einsum(np.arange(2)+1, [0], b, [1]) + array([[0, 1, 2, 3, 4], + [0, 2, 4, 6, 8]]) + >>> np.outer(np.arange(2)+1, b) + array([[0, 1, 2, 3, 4], + [0, 2, 4, 6, 8]]) + + >>> np.einsum('i...->...', a) + array([50, 55, 60, 65, 70]) + >>> np.einsum(a, [0,Ellipsis], [Ellipsis]) + array([50, 55, 60, 65, 70]) + >>> np.sum(a, axis=0) + array([50, 55, 60, 65, 70]) + + >>> a = np.arange(60.).reshape(3,4,5) + >>> b = np.arange(24.).reshape(4,3,2) + >>> np.einsum('ijk,jil->kl', a, b) + array([[ 4400., 4730.], + [ 4532., 4874.], + [ 4664., 5018.], + [ 4796., 5162.], + [ 4928., 5306.]]) + >>> np.einsum(a, [0,1,2], b, [1,0,3], [2,3]) + array([[ 4400., 4730.], + [ 4532., 4874.], + [ 4664., 5018.], + [ 4796., 5162.], + [ 4928., 5306.]]) + >>> np.tensordot(a,b, axes=([1,0],[0,1])) + array([[ 4400., 4730.], + [ 4532., 4874.], + [ 4664., 5018.], + [ 4796., 5162.], + [ 4928., 5306.]]) + + >>> a = np.arange(6).reshape((3,2)) + >>> b = np.arange(12).reshape((4,3)) + >>> np.einsum('ki,jk->ij', a, b) + array([[10, 28, 46, 64], + [13, 40, 67, 94]]) + >>> np.einsum('ki,...k->i...', a, b) + array([[10, 28, 46, 64], + [13, 40, 67, 94]]) + >>> np.einsum('k...,jk', a, b) + array([[10, 28, 46, 64], + [13, 40, 67, 94]]) + + >>> # since version 1.10.0 + >>> a = np.zeros((3, 3)) + >>> np.einsum('ii->i', a)[:] = 1 + >>> a + array([[ 1., 0., 0.], + [ 0., 1., 0.], + [ 0., 0., 1.]]) + + """ + + # Grab non-einsum kwargs + optimize_arg = kwargs.pop('optimize', False) + + # If no optimization, run pure einsum + if optimize_arg is False: + return c_einsum(*operands, **kwargs) + + valid_einsum_kwargs = ['out', 'dtype', 'order', 'casting'] + einsum_kwargs = {k: v for (k, v) in kwargs.items() if + k in valid_einsum_kwargs} + + # Make sure all keywords are valid + valid_contract_kwargs = ['optimize'] + valid_einsum_kwargs + unknown_kwargs = [k for (k, v) in kwargs.items() if + k not in valid_contract_kwargs] + + if len(unknown_kwargs): + raise TypeError("Did not understand the following kwargs: %s" + % unknown_kwargs) + + # Special handeling if out is specified + specified_out = False + out_array = einsum_kwargs.pop('out', None) + if out_array is not None: + specified_out = True + + # Build the contraction list and operand + operands, contraction_list = einsum_path(*operands, optimize=optimize_arg, + einsum_call=True) + + handle_out = False + + # Start contraction loop + for num, contraction in enumerate(contraction_list): + inds, idx_rm, einsum_str, remaining, blas = contraction + tmp_operands = [] + for x in inds: + tmp_operands.append(operands.pop(x)) + + # Do we need to deal with the output? + if specified_out and ((num + 1) == len(contraction_list)): + handle_out = True + + # Handle broadcasting vs BLAS cases + if blas: + # Checks have already been handled + input_str, results_index = einsum_str.split('->') + input_left, input_right = input_str.split(',') + if 1 in tmp_operands[0] or 1 in tmp_operands[1]: + left_dims = {dim: size for dim, size in + zip(input_left, tmp_operands[0].shape)} + right_dims = {dim: size for dim, size in + zip(input_right, tmp_operands[1].shape)} + # If dims do not match we are broadcasting, BLAS off + if any(left_dims[ind] != right_dims[ind] for ind in idx_rm): + blas = False + + # Call tensordot if still possible + if blas: + tensor_result = input_left + input_right + for s in idx_rm: + tensor_result = tensor_result.replace(s, "") + + # Find indices to contract over + left_pos, right_pos = [], [] + for s in idx_rm: + left_pos.append(input_left.find(s)) + right_pos.append(input_right.find(s)) + + # Contract! + new_view = tensordot(*tmp_operands, axes=(tuple(left_pos), tuple(right_pos))) + + # Build a new view if needed + if (tensor_result != results_index) or handle_out: + if handle_out: + einsum_kwargs["out"] = out_array + new_view = c_einsum(tensor_result + '->' + results_index, new_view, **einsum_kwargs) + + # Call einsum + else: + # If out was specified + if handle_out: + einsum_kwargs["out"] = out_array + + # Do the contraction + new_view = c_einsum(einsum_str, *tmp_operands, **einsum_kwargs) + + # Append new items and derefernce what we can + operands.append(new_view) + del tmp_operands, new_view + + if specified_out: + return out_array + else: + return operands[0] diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py new file mode 100644 index 0000000..a5b16b8 --- /dev/null +++ b/numpy/core/fromnumeric.py @@ -0,0 +1,3194 @@ +"""Module containing non-deprecated functions borrowed from Numeric. + +""" +from __future__ import division, absolute_import, print_function + +import types +import warnings + +import numpy as np +from .. import VisibleDeprecationWarning +from . import multiarray as mu +from . import umath as um +from . import numerictypes as nt +from .numeric import asarray, array, asanyarray, concatenate +from . import _methods + + +_dt_ = nt.sctype2char + +# functions that are methods +__all__ = [ + 'alen', 'all', 'alltrue', 'amax', 'amin', 'any', 'argmax', + 'argmin', 'argpartition', 'argsort', 'around', 'choose', 'clip', + 'compress', 'cumprod', 'cumproduct', 'cumsum', 'diagonal', 'mean', + 'ndim', 'nonzero', 'partition', 'prod', 'product', 'ptp', 'put', + 'rank', 'ravel', 'repeat', 'reshape', 'resize', 'round_', + 'searchsorted', 'shape', 'size', 'sometrue', 'sort', 'squeeze', + 'std', 'sum', 'swapaxes', 'take', 'trace', 'transpose', 'var', + ] + +_gentype = types.GeneratorType +# save away Python sum +_sum_ = sum + + +# functions that are now methods +def _wrapit(obj, method, *args, **kwds): + try: + wrap = obj.__array_wrap__ + except AttributeError: + wrap = None + result = getattr(asarray(obj), method)(*args, **kwds) + if wrap: + if not isinstance(result, mu.ndarray): + result = asarray(result) + result = wrap(result) + return result + + +def _wrapfunc(obj, method, *args, **kwds): + try: + return getattr(obj, method)(*args, **kwds) + + # An AttributeError occurs if the object does not have + # such a method in its class. + + # A TypeError occurs if the object does have such a method + # in its class, but its signature is not identical to that + # of NumPy's. This situation has occurred in the case of + # a downstream library like 'pandas'. + except (AttributeError, TypeError): + return _wrapit(obj, method, *args, **kwds) + + +def take(a, indices, axis=None, out=None, mode='raise'): + """ + Take elements from an array along an axis. + + When axis is not None, this function does the same thing as "fancy" + indexing (indexing arrays using arrays); however, it can be easier to use + if you need elements along a given axis. A call such as + ``np.take(arr, indices, axis=3)`` is equivalent to + ``arr[:,:,:,indices,...]``. + + Explained without fancy indexing, this is equivalent to the following use + of `ndindex`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of + indices:: + + Ni, Nk = a.shape[:axis], a.shape[axis+1:] + Nj = indices.shape + for ii in ndindex(Ni): + for jj in ndindex(Nj): + for kk in ndindex(Nk): + out[ii + jj + kk] = a[ii + (indices[jj],) + kk] + + Parameters + ---------- + a : array_like (Ni..., M, Nk...) + The source array. + indices : array_like (Nj...) + The indices of the values to extract. + + .. versionadded:: 1.8.0 + + Also allow scalars for indices. + axis : int, optional + The axis over which to select values. By default, the flattened + input array is used. + out : ndarray, optional (Ni..., Nj..., Nk...) + If provided, the result will be placed in this array. It should + be of the appropriate shape and dtype. + mode : {'raise', 'wrap', 'clip'}, optional + Specifies how out-of-bounds indices will behave. + + * 'raise' -- raise an error (default) + * 'wrap' -- wrap around + * 'clip' -- clip to the range + + 'clip' mode means that all indices that are too large are replaced + by the index that addresses the last element along that axis. Note + that this disables indexing with negative numbers. + + Returns + ------- + out : ndarray (Ni..., Nj..., Nk...) + The returned array has the same type as `a`. + + See Also + -------- + compress : Take elements using a boolean mask + ndarray.take : equivalent method + + Notes + ----- + + By eliminating the inner loop in the description above, and using `s_` to + build simple slice objects, `take` can be expressed in terms of applying + fancy indexing to each 1-d slice:: + + Ni, Nk = a.shape[:axis], a.shape[axis+1:] + for ii in ndindex(Ni): + for kk in ndindex(Nj): + out[ii + s_[...,] + kk] = a[ii + s_[:,] + kk][indices] + + For this reason, it is equivalent to (but faster than) the following use + of `apply_along_axis`:: + + out = np.apply_along_axis(lambda a_1d: a_1d[indices], axis, a) + + Examples + -------- + >>> a = [4, 3, 5, 7, 6, 8] + >>> indices = [0, 1, 4] + >>> np.take(a, indices) + array([4, 3, 6]) + + In this example if `a` is an ndarray, "fancy" indexing can be used. + + >>> a = np.array(a) + >>> a[indices] + array([4, 3, 6]) + + If `indices` is not one dimensional, the output also has these dimensions. + + >>> np.take(a, [[0, 1], [2, 3]]) + array([[4, 3], + [5, 7]]) + """ + return _wrapfunc(a, 'take', indices, axis=axis, out=out, mode=mode) + + +# not deprecated --- copy if necessary, view otherwise +def reshape(a, newshape, order='C'): + """ + Gives a new shape to an array without changing its data. + + Parameters + ---------- + a : array_like + Array to be reshaped. + newshape : int or tuple of ints + The new shape should be compatible with the original shape. If + an integer, then the result will be a 1-D array of that length. + One shape dimension can be -1. In this case, the value is + inferred from the length of the array and remaining dimensions. + order : {'C', 'F', 'A'}, optional + Read the elements of `a` using this index order, and place the + elements into the reshaped array using this index order. 'C' + means to read / write the elements using C-like index order, + with the last axis index changing fastest, back to the first + axis index changing slowest. 'F' means to read / write the + elements using Fortran-like index order, with the first index + changing fastest, and the last index changing slowest. Note that + the 'C' and 'F' options take no account of the memory layout of + the underlying array, and only refer to the order of indexing. + 'A' means to read / write the elements in Fortran-like index + order if `a` is Fortran *contiguous* in memory, C-like order + otherwise. + + Returns + ------- + reshaped_array : ndarray + This will be a new view object if possible; otherwise, it will + be a copy. Note there is no guarantee of the *memory layout* (C- or + Fortran- contiguous) of the returned array. + + See Also + -------- + ndarray.reshape : Equivalent method. + + Notes + ----- + It is not always possible to change the shape of an array without + copying the data. If you want an error to be raised when the data is copied, + you should assign the new shape to the shape attribute of the array:: + + >>> a = np.zeros((10, 2)) + # A transpose makes the array non-contiguous + >>> b = a.T + # Taking a view makes it possible to modify the shape without modifying + # the initial object. + >>> c = b.view() + >>> c.shape = (20) + AttributeError: incompatible shape for a non-contiguous array + + The `order` keyword gives the index ordering both for *fetching* the values + from `a`, and then *placing* the values into the output array. + For example, let's say you have an array: + + >>> a = np.arange(6).reshape((3, 2)) + >>> a + array([[0, 1], + [2, 3], + [4, 5]]) + + You can think of reshaping as first raveling the array (using the given + index order), then inserting the elements from the raveled array into the + new array using the same kind of index ordering as was used for the + raveling. + + >>> np.reshape(a, (2, 3)) # C-like index ordering + array([[0, 1, 2], + [3, 4, 5]]) + >>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape + array([[0, 1, 2], + [3, 4, 5]]) + >>> np.reshape(a, (2, 3), order='F') # Fortran-like index ordering + array([[0, 4, 3], + [2, 1, 5]]) + >>> np.reshape(np.ravel(a, order='F'), (2, 3), order='F') + array([[0, 4, 3], + [2, 1, 5]]) + + Examples + -------- + >>> a = np.array([[1,2,3], [4,5,6]]) + >>> np.reshape(a, 6) + array([1, 2, 3, 4, 5, 6]) + >>> np.reshape(a, 6, order='F') + array([1, 4, 2, 5, 3, 6]) + + >>> np.reshape(a, (3,-1)) # the unspecified value is inferred to be 2 + array([[1, 2], + [3, 4], + [5, 6]]) + """ + return _wrapfunc(a, 'reshape', newshape, order=order) + + +def choose(a, choices, out=None, mode='raise'): + """ + Construct an array from an index array and a set of arrays to choose from. + + First of all, if confused or uncertain, definitely look at the Examples - + in its full generality, this function is less simple than it might + seem from the following code description (below ndi = + `numpy.lib.index_tricks`): + + ``np.choose(a,c) == np.array([c[a[I]][I] for I in ndi.ndindex(a.shape)])``. + + But this omits some subtleties. Here is a fully general summary: + + Given an "index" array (`a`) of integers and a sequence of `n` arrays + (`choices`), `a` and each choice array are first broadcast, as necessary, + to arrays of a common shape; calling these *Ba* and *Bchoices[i], i = + 0,...,n-1* we have that, necessarily, ``Ba.shape == Bchoices[i].shape`` + for each `i`. Then, a new array with shape ``Ba.shape`` is created as + follows: + + * if ``mode=raise`` (the default), then, first of all, each element of + `a` (and thus `Ba`) must be in the range `[0, n-1]`; now, suppose that + `i` (in that range) is the value at the `(j0, j1, ..., jm)` position + in `Ba` - then the value at the same position in the new array is the + value in `Bchoices[i]` at that same position; + + * if ``mode=wrap``, values in `a` (and thus `Ba`) may be any (signed) + integer; modular arithmetic is used to map integers outside the range + `[0, n-1]` back into that range; and then the new array is constructed + as above; + + * if ``mode=clip``, values in `a` (and thus `Ba`) may be any (signed) + integer; negative integers are mapped to 0; values greater than `n-1` + are mapped to `n-1`; and then the new array is constructed as above. + + Parameters + ---------- + a : int array + This array must contain integers in `[0, n-1]`, where `n` is the number + of choices, unless ``mode=wrap`` or ``mode=clip``, in which cases any + integers are permissible. + choices : sequence of arrays + Choice arrays. `a` and all of the choices must be broadcastable to the + same shape. If `choices` is itself an array (not recommended), then + its outermost dimension (i.e., the one corresponding to + ``choices.shape[0]``) is taken as defining the "sequence". + out : array, optional + If provided, the result will be inserted into this array. It should + be of the appropriate shape and dtype. + mode : {'raise' (default), 'wrap', 'clip'}, optional + Specifies how indices outside `[0, n-1]` will be treated: + + * 'raise' : an exception is raised + * 'wrap' : value becomes value mod `n` + * 'clip' : values < 0 are mapped to 0, values > n-1 are mapped to n-1 + + Returns + ------- + merged_array : array + The merged result. + + Raises + ------ + ValueError: shape mismatch + If `a` and each choice array are not all broadcastable to the same + shape. + + See Also + -------- + ndarray.choose : equivalent method + + Notes + ----- + To reduce the chance of misinterpretation, even though the following + "abuse" is nominally supported, `choices` should neither be, nor be + thought of as, a single array, i.e., the outermost sequence-like container + should be either a list or a tuple. + + Examples + -------- + + >>> choices = [[0, 1, 2, 3], [10, 11, 12, 13], + ... [20, 21, 22, 23], [30, 31, 32, 33]] + >>> np.choose([2, 3, 1, 0], choices + ... # the first element of the result will be the first element of the + ... # third (2+1) "array" in choices, namely, 20; the second element + ... # will be the second element of the fourth (3+1) choice array, i.e., + ... # 31, etc. + ... ) + array([20, 31, 12, 3]) + >>> np.choose([2, 4, 1, 0], choices, mode='clip') # 4 goes to 3 (4-1) + array([20, 31, 12, 3]) + >>> # because there are 4 choice arrays + >>> np.choose([2, 4, 1, 0], choices, mode='wrap') # 4 goes to (4 mod 4) + array([20, 1, 12, 3]) + >>> # i.e., 0 + + A couple examples illustrating how choose broadcasts: + + >>> a = [[1, 0, 1], [0, 1, 0], [1, 0, 1]] + >>> choices = [-10, 10] + >>> np.choose(a, choices) + array([[ 10, -10, 10], + [-10, 10, -10], + [ 10, -10, 10]]) + + >>> # With thanks to Anne Archibald + >>> a = np.array([0, 1]).reshape((2,1,1)) + >>> c1 = np.array([1, 2, 3]).reshape((1,3,1)) + >>> c2 = np.array([-1, -2, -3, -4, -5]).reshape((1,1,5)) + >>> np.choose(a, (c1, c2)) # result is 2x3x5, res[0,:,:]=c1, res[1,:,:]=c2 + array([[[ 1, 1, 1, 1, 1], + [ 2, 2, 2, 2, 2], + [ 3, 3, 3, 3, 3]], + [[-1, -2, -3, -4, -5], + [-1, -2, -3, -4, -5], + [-1, -2, -3, -4, -5]]]) + + """ + return _wrapfunc(a, 'choose', choices, out=out, mode=mode) + + +def repeat(a, repeats, axis=None): + """ + Repeat elements of an array. + + Parameters + ---------- + a : array_like + Input array. + repeats : int or array of ints + The number of repetitions for each element. `repeats` is broadcasted + to fit the shape of the given axis. + axis : int, optional + The axis along which to repeat values. By default, use the + flattened input array, and return a flat output array. + + Returns + ------- + repeated_array : ndarray + Output array which has the same shape as `a`, except along + the given axis. + + See Also + -------- + tile : Tile an array. + + Examples + -------- + >>> np.repeat(3, 4) + array([3, 3, 3, 3]) + >>> x = np.array([[1,2],[3,4]]) + >>> np.repeat(x, 2) + array([1, 1, 2, 2, 3, 3, 4, 4]) + >>> np.repeat(x, 3, axis=1) + array([[1, 1, 1, 2, 2, 2], + [3, 3, 3, 4, 4, 4]]) + >>> np.repeat(x, [1, 2], axis=0) + array([[1, 2], + [3, 4], + [3, 4]]) + + """ + return _wrapfunc(a, 'repeat', repeats, axis=axis) + + +def put(a, ind, v, mode='raise'): + """ + Replaces specified elements of an array with given values. + + The indexing works on the flattened target array. `put` is roughly + equivalent to: + + :: + + a.flat[ind] = v + + Parameters + ---------- + a : ndarray + Target array. + ind : array_like + Target indices, interpreted as integers. + v : array_like + Values to place in `a` at target indices. If `v` is shorter than + `ind` it will be repeated as necessary. + mode : {'raise', 'wrap', 'clip'}, optional + Specifies how out-of-bounds indices will behave. + + * 'raise' -- raise an error (default) + * 'wrap' -- wrap around + * 'clip' -- clip to the range + + 'clip' mode means that all indices that are too large are replaced + by the index that addresses the last element along that axis. Note + that this disables indexing with negative numbers. + + See Also + -------- + putmask, place + + Examples + -------- + >>> a = np.arange(5) + >>> np.put(a, [0, 2], [-44, -55]) + >>> a + array([-44, 1, -55, 3, 4]) + + >>> a = np.arange(5) + >>> np.put(a, 22, -5, mode='clip') + >>> a + array([ 0, 1, 2, 3, -5]) + + """ + try: + put = a.put + except AttributeError: + raise TypeError("argument 1 must be numpy.ndarray, " + "not {name}".format(name=type(a).__name__)) + + return put(ind, v, mode=mode) + + +def swapaxes(a, axis1, axis2): + """ + Interchange two axes of an array. + + Parameters + ---------- + a : array_like + Input array. + axis1 : int + First axis. + axis2 : int + Second axis. + + Returns + ------- + a_swapped : ndarray + For NumPy >= 1.10.0, if `a` is an ndarray, then a view of `a` is + returned; otherwise a new array is created. For earlier NumPy + versions a view of `a` is returned only if the order of the + axes is changed, otherwise the input array is returned. + + Examples + -------- + >>> x = np.array([[1,2,3]]) + >>> np.swapaxes(x,0,1) + array([[1], + [2], + [3]]) + + >>> x = np.array([[[0,1],[2,3]],[[4,5],[6,7]]]) + >>> x + array([[[0, 1], + [2, 3]], + [[4, 5], + [6, 7]]]) + + >>> np.swapaxes(x,0,2) + array([[[0, 4], + [2, 6]], + [[1, 5], + [3, 7]]]) + + """ + return _wrapfunc(a, 'swapaxes', axis1, axis2) + + +def transpose(a, axes=None): + """ + Permute the dimensions of an array. + + Parameters + ---------- + a : array_like + Input array. + axes : list of ints, optional + By default, reverse the dimensions, otherwise permute the axes + according to the values given. + + Returns + ------- + p : ndarray + `a` with its axes permuted. A view is returned whenever + possible. + + See Also + -------- + moveaxis + argsort + + Notes + ----- + Use `transpose(a, argsort(axes))` to invert the transposition of tensors + when using the `axes` keyword argument. + + Transposing a 1-D array returns an unchanged view of the original array. + + Examples + -------- + >>> x = np.arange(4).reshape((2,2)) + >>> x + array([[0, 1], + [2, 3]]) + + >>> np.transpose(x) + array([[0, 2], + [1, 3]]) + + >>> x = np.ones((1, 2, 3)) + >>> np.transpose(x, (1, 0, 2)).shape + (2, 1, 3) + + """ + return _wrapfunc(a, 'transpose', axes) + + +def partition(a, kth, axis=-1, kind='introselect', order=None): + """ + Return a partitioned copy of an array. + + Creates a copy of the array with its elements rearranged in such a + way that the value of the element in k-th position is in the + position it would be in a sorted array. All elements smaller than + the k-th element are moved before this element and all equal or + greater are moved behind it. The ordering of the elements in the two + partitions is undefined. + + .. versionadded:: 1.8.0 + + Parameters + ---------- + a : array_like + Array to be sorted. + kth : int or sequence of ints + Element index to partition by. The k-th value of the element + will be in its final sorted position and all smaller elements + will be moved before it and all equal or greater elements behind + it. The order all elements in the partitions is undefined. If + provided with a sequence of k-th it will partition all elements + indexed by k-th of them into their sorted position at once. + axis : int or None, optional + Axis along which to sort. If None, the array is flattened before + sorting. The default is -1, which sorts along the last axis. + kind : {'introselect'}, optional + Selection algorithm. Default is 'introselect'. + order : str or list of str, optional + When `a` is an array with fields defined, this argument + specifies which fields to compare first, second, etc. A single + field can be specified as a string. Not all fields need be + specified, but unspecified fields will still be used, in the + order in which they come up in the dtype, to break ties. + + Returns + ------- + partitioned_array : ndarray + Array of the same type and shape as `a`. + + See Also + -------- + ndarray.partition : Method to sort an array in-place. + argpartition : Indirect partition. + sort : Full sorting + + Notes + ----- + The various selection algorithms are characterized by their average + speed, worst case performance, work space size, and whether they are + stable. A stable sort keeps items with the same key in the same + relative order. The available algorithms have the following + properties: + + ================= ======= ============= ============ ======= + kind speed worst case work space stable + ================= ======= ============= ============ ======= + 'introselect' 1 O(n) 0 no + ================= ======= ============= ============ ======= + + All the partition algorithms make temporary copies of the data when + partitioning along any but the last axis. Consequently, + partitioning along the last axis is faster and uses less space than + partitioning along any other axis. + + The sort order for complex numbers is lexicographic. If both the + real and imaginary parts are non-nan then the order is determined by + the real parts except when they are equal, in which case the order + is determined by the imaginary parts. + + Examples + -------- + >>> a = np.array([3, 4, 2, 1]) + >>> np.partition(a, 3) + array([2, 1, 3, 4]) + + >>> np.partition(a, (1, 3)) + array([1, 2, 3, 4]) + + """ + if axis is None: + a = asanyarray(a).flatten() + axis = 0 + else: + a = asanyarray(a).copy(order="K") + a.partition(kth, axis=axis, kind=kind, order=order) + return a + + +def argpartition(a, kth, axis=-1, kind='introselect', order=None): + """ + Perform an indirect partition along the given axis using the + algorithm specified by the `kind` keyword. It returns an array of + indices of the same shape as `a` that index data along the given + axis in partitioned order. + + .. versionadded:: 1.8.0 + + Parameters + ---------- + a : array_like + Array to sort. + kth : int or sequence of ints + Element index to partition by. The k-th element will be in its + final sorted position and all smaller elements will be moved + before it and all larger elements behind it. The order all + elements in the partitions is undefined. If provided with a + sequence of k-th it will partition all of them into their sorted + position at once. + axis : int or None, optional + Axis along which to sort. The default is -1 (the last axis). If + None, the flattened array is used. + kind : {'introselect'}, optional + Selection algorithm. Default is 'introselect' + order : str or list of str, optional + When `a` is an array with fields defined, this argument + specifies which fields to compare first, second, etc. A single + field can be specified as a string, and not all fields need be + specified, but unspecified fields will still be used, in the + order in which they come up in the dtype, to break ties. + + Returns + ------- + index_array : ndarray, int + Array of indices that partition `a` along the specified axis. + In other words, ``a[index_array]`` yields a partitioned `a`. + + See Also + -------- + partition : Describes partition algorithms used. + ndarray.partition : Inplace partition. + argsort : Full indirect sort + + Notes + ----- + See `partition` for notes on the different selection algorithms. + + Examples + -------- + One dimensional array: + + >>> x = np.array([3, 4, 2, 1]) + >>> x[np.argpartition(x, 3)] + array([2, 1, 3, 4]) + >>> x[np.argpartition(x, (1, 3))] + array([1, 2, 3, 4]) + + >>> x = [3, 4, 2, 1] + >>> np.array(x)[np.argpartition(x, 3)] + array([2, 1, 3, 4]) + + """ + return _wrapfunc(a, 'argpartition', kth, axis=axis, kind=kind, order=order) + + +def sort(a, axis=-1, kind='quicksort', order=None): + """ + Return a sorted copy of an array. + + Parameters + ---------- + a : array_like + Array to be sorted. + axis : int or None, optional + Axis along which to sort. If None, the array is flattened before + sorting. The default is -1, which sorts along the last axis. + kind : {'quicksort', 'mergesort', 'heapsort'}, optional + Sorting algorithm. Default is 'quicksort'. + order : str or list of str, optional + When `a` is an array with fields defined, this argument specifies + which fields to compare first, second, etc. A single field can + be specified as a string, and not all fields need be specified, + but unspecified fields will still be used, in the order in which + they come up in the dtype, to break ties. + + Returns + ------- + sorted_array : ndarray + Array of the same type and shape as `a`. + + See Also + -------- + ndarray.sort : Method to sort an array in-place. + argsort : Indirect sort. + lexsort : Indirect stable sort on multiple keys. + searchsorted : Find elements in a sorted array. + partition : Partial sort. + + Notes + ----- + The various sorting algorithms are characterized by their average speed, + worst case performance, work space size, and whether they are stable. A + stable sort keeps items with the same key in the same relative + order. The three available algorithms have the following + properties: + + =========== ======= ============= ============ ======= + kind speed worst case work space stable + =========== ======= ============= ============ ======= + 'quicksort' 1 O(n^2) 0 no + 'mergesort' 2 O(n*log(n)) ~n/2 yes + 'heapsort' 3 O(n*log(n)) 0 no + =========== ======= ============= ============ ======= + + All the sort algorithms make temporary copies of the data when + sorting along any but the last axis. Consequently, sorting along + the last axis is faster and uses less space than sorting along + any other axis. + + The sort order for complex numbers is lexicographic. If both the real + and imaginary parts are non-nan then the order is determined by the + real parts except when they are equal, in which case the order is + determined by the imaginary parts. + + Previous to numpy 1.4.0 sorting real and complex arrays containing nan + values led to undefined behaviour. In numpy versions >= 1.4.0 nan + values are sorted to the end. The extended sort order is: + + * Real: [R, nan] + * Complex: [R + Rj, R + nanj, nan + Rj, nan + nanj] + + where R is a non-nan real value. Complex values with the same nan + placements are sorted according to the non-nan part if it exists. + Non-nan values are sorted as before. + + .. versionadded:: 1.12.0 + + quicksort has been changed to an introsort which will switch + heapsort when it does not make enough progress. This makes its + worst case O(n*log(n)). + + Examples + -------- + >>> a = np.array([[1,4],[3,1]]) + >>> np.sort(a) # sort along the last axis + array([[1, 4], + [1, 3]]) + >>> np.sort(a, axis=None) # sort the flattened array + array([1, 1, 3, 4]) + >>> np.sort(a, axis=0) # sort along the first axis + array([[1, 1], + [3, 4]]) + + Use the `order` keyword to specify a field to use when sorting a + structured array: + + >>> dtype = [('name', 'S10'), ('height', float), ('age', int)] + >>> values = [('Arthur', 1.8, 41), ('Lancelot', 1.9, 38), + ... ('Galahad', 1.7, 38)] + >>> a = np.array(values, dtype=dtype) # create a structured array + >>> np.sort(a, order='height') # doctest: +SKIP + array([('Galahad', 1.7, 38), ('Arthur', 1.8, 41), + ('Lancelot', 1.8999999999999999, 38)], + dtype=[('name', '|S10'), ('height', '>> np.sort(a, order=['age', 'height']) # doctest: +SKIP + array([('Galahad', 1.7, 38), ('Lancelot', 1.8999999999999999, 38), + ('Arthur', 1.8, 41)], + dtype=[('name', '|S10'), ('height', '>> x = np.array([3, 1, 2]) + >>> np.argsort(x) + array([1, 2, 0]) + + Two-dimensional array: + + >>> x = np.array([[0, 3], [2, 2]]) + >>> x + array([[0, 3], + [2, 2]]) + + >>> np.argsort(x, axis=0) # sorts along first axis (down) + array([[0, 1], + [1, 0]]) + + >>> np.argsort(x, axis=1) # sorts along last axis (across) + array([[0, 1], + [0, 1]]) + + Indices of the sorted elements of a N-dimensional array: + + >>> ind = np.unravel_index(np.argsort(x, axis=None), x.shape) + >>> ind + (array([0, 1, 1, 0]), array([0, 0, 1, 1])) + >>> x[ind] # same as np.sort(x, axis=None) + array([0, 2, 2, 3]) + + Sorting with keys: + + >>> x = np.array([(1, 0), (0, 1)], dtype=[('x', '>> x + array([(1, 0), (0, 1)], + dtype=[('x', '>> np.argsort(x, order=('x','y')) + array([1, 0]) + + >>> np.argsort(x, order=('y','x')) + array([0, 1]) + + """ + return _wrapfunc(a, 'argsort', axis=axis, kind=kind, order=order) + + +def argmax(a, axis=None, out=None): + """ + Returns the indices of the maximum values along an axis. + + Parameters + ---------- + a : array_like + Input array. + axis : int, optional + By default, the index is into the flattened array, otherwise + along the specified axis. + out : array, optional + If provided, the result will be inserted into this array. It should + be of the appropriate shape and dtype. + + Returns + ------- + index_array : ndarray of ints + Array of indices into the array. It has the same shape as `a.shape` + with the dimension along `axis` removed. + + See Also + -------- + ndarray.argmax, argmin + amax : The maximum value along a given axis. + unravel_index : Convert a flat index into an index tuple. + + Notes + ----- + In case of multiple occurrences of the maximum values, the indices + corresponding to the first occurrence are returned. + + Examples + -------- + >>> a = np.arange(6).reshape(2,3) + >>> a + array([[0, 1, 2], + [3, 4, 5]]) + >>> np.argmax(a) + 5 + >>> np.argmax(a, axis=0) + array([1, 1, 1]) + >>> np.argmax(a, axis=1) + array([2, 2]) + + Indexes of the maximal elements of a N-dimensional array: + + >>> ind = np.unravel_index(np.argmax(a, axis=None), a.shape) + >>> ind + (1, 2) + >>> a[ind] + 5 + + >>> b = np.arange(6) + >>> b[1] = 5 + >>> b + array([0, 5, 2, 3, 4, 5]) + >>> np.argmax(b) # Only the first occurrence is returned. + 1 + + """ + return _wrapfunc(a, 'argmax', axis=axis, out=out) + + +def argmin(a, axis=None, out=None): + """ + Returns the indices of the minimum values along an axis. + + Parameters + ---------- + a : array_like + Input array. + axis : int, optional + By default, the index is into the flattened array, otherwise + along the specified axis. + out : array, optional + If provided, the result will be inserted into this array. It should + be of the appropriate shape and dtype. + + Returns + ------- + index_array : ndarray of ints + Array of indices into the array. It has the same shape as `a.shape` + with the dimension along `axis` removed. + + See Also + -------- + ndarray.argmin, argmax + amin : The minimum value along a given axis. + unravel_index : Convert a flat index into an index tuple. + + Notes + ----- + In case of multiple occurrences of the minimum values, the indices + corresponding to the first occurrence are returned. + + Examples + -------- + >>> a = np.arange(6).reshape(2,3) + >>> a + array([[0, 1, 2], + [3, 4, 5]]) + >>> np.argmin(a) + 0 + >>> np.argmin(a, axis=0) + array([0, 0, 0]) + >>> np.argmin(a, axis=1) + array([0, 0]) + + Indices of the minimum elements of a N-dimensional array: + + >>> ind = np.unravel_index(np.argmin(a, axis=None), a.shape) + >>> ind + (0, 0) + >>> a[ind] + 0 + + >>> b = np.arange(6) + >>> b[4] = 0 + >>> b + array([0, 1, 2, 3, 0, 5]) + >>> np.argmin(b) # Only the first occurrence is returned. + 0 + + """ + return _wrapfunc(a, 'argmin', axis=axis, out=out) + + +def searchsorted(a, v, side='left', sorter=None): + """ + Find indices where elements should be inserted to maintain order. + + Find the indices into a sorted array `a` such that, if the + corresponding elements in `v` were inserted before the indices, the + order of `a` would be preserved. + + Parameters + ---------- + a : 1-D array_like + Input array. If `sorter` is None, then it must be sorted in + ascending order, otherwise `sorter` must be an array of indices + that sort it. + v : array_like + Values to insert into `a`. + side : {'left', 'right'}, optional + If 'left', the index of the first suitable location found is given. + If 'right', return the last such index. If there is no suitable + index, return either 0 or N (where N is the length of `a`). + sorter : 1-D array_like, optional + Optional array of integer indices that sort array a into ascending + order. They are typically the result of argsort. + + .. versionadded:: 1.7.0 + + Returns + ------- + indices : array of ints + Array of insertion points with the same shape as `v`. + + See Also + -------- + sort : Return a sorted copy of an array. + histogram : Produce histogram from 1-D data. + + Notes + ----- + Binary search is used to find the required insertion points. + + As of NumPy 1.4.0 `searchsorted` works with real/complex arrays containing + `nan` values. The enhanced sort order is documented in `sort`. + + Examples + -------- + >>> np.searchsorted([1,2,3,4,5], 3) + 2 + >>> np.searchsorted([1,2,3,4,5], 3, side='right') + 3 + >>> np.searchsorted([1,2,3,4,5], [-10, 10, 2, 3]) + array([0, 5, 1, 2]) + + """ + return _wrapfunc(a, 'searchsorted', v, side=side, sorter=sorter) + + +def resize(a, new_shape): + """ + Return a new array with the specified shape. + + If the new array is larger than the original array, then the new + array is filled with repeated copies of `a`. Note that this behavior + is different from a.resize(new_shape) which fills with zeros instead + of repeated copies of `a`. + + Parameters + ---------- + a : array_like + Array to be resized. + + new_shape : int or tuple of int + Shape of resized array. + + Returns + ------- + reshaped_array : ndarray + The new array is formed from the data in the old array, repeated + if necessary to fill out the required number of elements. The + data are repeated in the order that they are stored in memory. + + See Also + -------- + ndarray.resize : resize an array in-place. + + Examples + -------- + >>> a=np.array([[0,1],[2,3]]) + >>> np.resize(a,(2,3)) + array([[0, 1, 2], + [3, 0, 1]]) + >>> np.resize(a,(1,4)) + array([[0, 1, 2, 3]]) + >>> np.resize(a,(2,4)) + array([[0, 1, 2, 3], + [0, 1, 2, 3]]) + + """ + if isinstance(new_shape, (int, nt.integer)): + new_shape = (new_shape,) + a = ravel(a) + Na = len(a) + total_size = um.multiply.reduce(new_shape) + if Na == 0 or total_size == 0: + return mu.zeros(new_shape, a.dtype) + + n_copies = int(total_size / Na) + extra = total_size % Na + + if extra != 0: + n_copies = n_copies + 1 + extra = Na - extra + + a = concatenate((a,)*n_copies) + if extra > 0: + a = a[:-extra] + + return reshape(a, new_shape) + + +def squeeze(a, axis=None): + """ + Remove single-dimensional entries from the shape of an array. + + Parameters + ---------- + a : array_like + Input data. + axis : None or int or tuple of ints, optional + .. versionadded:: 1.7.0 + + Selects a subset of the single-dimensional entries in the + shape. If an axis is selected with shape entry greater than + one, an error is raised. + + Returns + ------- + squeezed : ndarray + The input array, but with all or a subset of the + dimensions of length 1 removed. This is always `a` itself + or a view into `a`. + + Raises + ------ + ValueError + If `axis` is not `None`, and an axis being squeezed is not of length 1 + + See Also + -------- + expand_dims : The inverse operation, adding singleton dimensions + reshape : Insert, remove, and combine dimensions, and resize existing ones + + Examples + -------- + >>> x = np.array([[[0], [1], [2]]]) + >>> x.shape + (1, 3, 1) + >>> np.squeeze(x).shape + (3,) + >>> np.squeeze(x, axis=0).shape + (3, 1) + >>> np.squeeze(x, axis=1).shape + Traceback (most recent call last): + ... + ValueError: cannot select an axis to squeeze out which has size not equal to one + >>> np.squeeze(x, axis=2).shape + (1, 3) + + """ + try: + squeeze = a.squeeze + except AttributeError: + return _wrapit(a, 'squeeze') + try: + # First try to use the new axis= parameter + return squeeze(axis=axis) + except TypeError: + # For backwards compatibility + return squeeze() + + +def diagonal(a, offset=0, axis1=0, axis2=1): + """ + Return specified diagonals. + + If `a` is 2-D, returns the diagonal of `a` with the given offset, + i.e., the collection of elements of the form ``a[i, i+offset]``. If + `a` has more than two dimensions, then the axes specified by `axis1` + and `axis2` are used to determine the 2-D sub-array whose diagonal is + returned. The shape of the resulting array can be determined by + removing `axis1` and `axis2` and appending an index to the right equal + to the size of the resulting diagonals. + + In versions of NumPy prior to 1.7, this function always returned a new, + independent array containing a copy of the values in the diagonal. + + In NumPy 1.7 and 1.8, it continues to return a copy of the diagonal, + but depending on this fact is deprecated. Writing to the resulting + array continues to work as it used to, but a FutureWarning is issued. + + Starting in NumPy 1.9 it returns a read-only view on the original array. + Attempting to write to the resulting array will produce an error. + + In some future release, it will return a read/write view and writing to + the returned array will alter your original array. The returned array + will have the same type as the input array. + + If you don't write to the array returned by this function, then you can + just ignore all of the above. + + If you depend on the current behavior, then we suggest copying the + returned array explicitly, i.e., use ``np.diagonal(a).copy()`` instead + of just ``np.diagonal(a)``. This will work with both past and future + versions of NumPy. + + Parameters + ---------- + a : array_like + Array from which the diagonals are taken. + offset : int, optional + Offset of the diagonal from the main diagonal. Can be positive or + negative. Defaults to main diagonal (0). + axis1 : int, optional + Axis to be used as the first axis of the 2-D sub-arrays from which + the diagonals should be taken. Defaults to first axis (0). + axis2 : int, optional + Axis to be used as the second axis of the 2-D sub-arrays from + which the diagonals should be taken. Defaults to second axis (1). + + Returns + ------- + array_of_diagonals : ndarray + If `a` is 2-D and not a `matrix`, a 1-D array of the same type as `a` + containing the diagonal is returned. If `a` is a `matrix`, a 1-D + array containing the diagonal is returned in order to maintain + backward compatibility. + If ``a.ndim > 2``, then the dimensions specified by `axis1` and `axis2` + are removed, and a new axis inserted at the end corresponding to the + diagonal. + + Raises + ------ + ValueError + If the dimension of `a` is less than 2. + + See Also + -------- + diag : MATLAB work-a-like for 1-D and 2-D arrays. + diagflat : Create diagonal arrays. + trace : Sum along diagonals. + + Examples + -------- + >>> a = np.arange(4).reshape(2,2) + >>> a + array([[0, 1], + [2, 3]]) + >>> a.diagonal() + array([0, 3]) + >>> a.diagonal(1) + array([1]) + + A 3-D example: + + >>> a = np.arange(8).reshape(2,2,2); a + array([[[0, 1], + [2, 3]], + [[4, 5], + [6, 7]]]) + >>> a.diagonal(0, # Main diagonals of two arrays created by skipping + ... 0, # across the outer(left)-most axis last and + ... 1) # the "middle" (row) axis first. + array([[0, 6], + [1, 7]]) + + The sub-arrays whose main diagonals we just obtained; note that each + corresponds to fixing the right-most (column) axis, and that the + diagonals are "packed" in rows. + + >>> a[:,:,0] # main diagonal is [0 6] + array([[0, 2], + [4, 6]]) + >>> a[:,:,1] # main diagonal is [1 7] + array([[1, 3], + [5, 7]]) + + """ + if isinstance(a, np.matrix): + # Make diagonal of matrix 1-D to preserve backward compatibility. + return asarray(a).diagonal(offset=offset, axis1=axis1, axis2=axis2) + else: + return asanyarray(a).diagonal(offset=offset, axis1=axis1, axis2=axis2) + + +def trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None): + """ + Return the sum along diagonals of the array. + + If `a` is 2-D, the sum along its diagonal with the given offset + is returned, i.e., the sum of elements ``a[i,i+offset]`` for all i. + + If `a` has more than two dimensions, then the axes specified by axis1 and + axis2 are used to determine the 2-D sub-arrays whose traces are returned. + The shape of the resulting array is the same as that of `a` with `axis1` + and `axis2` removed. + + Parameters + ---------- + a : array_like + Input array, from which the diagonals are taken. + offset : int, optional + Offset of the diagonal from the main diagonal. Can be both positive + and negative. Defaults to 0. + axis1, axis2 : int, optional + Axes to be used as the first and second axis of the 2-D sub-arrays + from which the diagonals should be taken. Defaults are the first two + axes of `a`. + dtype : dtype, optional + Determines the data-type of the returned array and of the accumulator + where the elements are summed. If dtype has the value None and `a` is + of integer type of precision less than the default integer + precision, then the default integer precision is used. Otherwise, + the precision is the same as that of `a`. + out : ndarray, optional + Array into which the output is placed. Its type is preserved and + it must be of the right shape to hold the output. + + Returns + ------- + sum_along_diagonals : ndarray + If `a` is 2-D, the sum along the diagonal is returned. If `a` has + larger dimensions, then an array of sums along diagonals is returned. + + See Also + -------- + diag, diagonal, diagflat + + Examples + -------- + >>> np.trace(np.eye(3)) + 3.0 + >>> a = np.arange(8).reshape((2,2,2)) + >>> np.trace(a) + array([6, 8]) + + >>> a = np.arange(24).reshape((2,2,2,3)) + >>> np.trace(a).shape + (2, 3) + + """ + if isinstance(a, np.matrix): + # Get trace of matrix via an array to preserve backward compatibility. + return asarray(a).trace(offset=offset, axis1=axis1, axis2=axis2, dtype=dtype, out=out) + else: + return asanyarray(a).trace(offset=offset, axis1=axis1, axis2=axis2, dtype=dtype, out=out) + + +def ravel(a, order='C'): + """Return a contiguous flattened array. + + A 1-D array, containing the elements of the input, is returned. A copy is + made only if needed. + + As of NumPy 1.10, the returned array will have the same type as the input + array. (for example, a masked array will be returned for a masked array + input) + + Parameters + ---------- + a : array_like + Input array. The elements in `a` are read in the order specified by + `order`, and packed as a 1-D array. + order : {'C','F', 'A', 'K'}, optional + + The elements of `a` are read using this index order. 'C' means + to index the elements in row-major, C-style order, + with the last axis index changing fastest, back to the first + axis index changing slowest. 'F' means to index the elements + in column-major, Fortran-style order, with the + first index changing fastest, and the last index changing + slowest. Note that the 'C' and 'F' options take no account of + the memory layout of the underlying array, and only refer to + the order of axis indexing. 'A' means to read the elements in + Fortran-like index order if `a` is Fortran *contiguous* in + memory, C-like order otherwise. 'K' means to read the + elements in the order they occur in memory, except for + reversing the data when strides are negative. By default, 'C' + index order is used. + + Returns + ------- + y : array_like + If `a` is a matrix, y is a 1-D ndarray, otherwise y is an array of + the same subtype as `a`. The shape of the returned array is + ``(a.size,)``. Matrices are special cased for backward + compatibility. + + See Also + -------- + ndarray.flat : 1-D iterator over an array. + ndarray.flatten : 1-D array copy of the elements of an array + in row-major order. + ndarray.reshape : Change the shape of an array without changing its data. + + Notes + ----- + In row-major, C-style order, in two dimensions, the row index + varies the slowest, and the column index the quickest. This can + be generalized to multiple dimensions, where row-major order + implies that the index along the first axis varies slowest, and + the index along the last quickest. The opposite holds for + column-major, Fortran-style index ordering. + + When a view is desired in as many cases as possible, ``arr.reshape(-1)`` + may be preferable. + + Examples + -------- + It is equivalent to ``reshape(-1, order=order)``. + + >>> x = np.array([[1, 2, 3], [4, 5, 6]]) + >>> print(np.ravel(x)) + [1 2 3 4 5 6] + + >>> print(x.reshape(-1)) + [1 2 3 4 5 6] + + >>> print(np.ravel(x, order='F')) + [1 4 2 5 3 6] + + When ``order`` is 'A', it will preserve the array's 'C' or 'F' ordering: + + >>> print(np.ravel(x.T)) + [1 4 2 5 3 6] + >>> print(np.ravel(x.T, order='A')) + [1 2 3 4 5 6] + + When ``order`` is 'K', it will preserve orderings that are neither 'C' + nor 'F', but won't reverse axes: + + >>> a = np.arange(3)[::-1]; a + array([2, 1, 0]) + >>> a.ravel(order='C') + array([2, 1, 0]) + >>> a.ravel(order='K') + array([2, 1, 0]) + + >>> a = np.arange(12).reshape(2,3,2).swapaxes(1,2); a + array([[[ 0, 2, 4], + [ 1, 3, 5]], + [[ 6, 8, 10], + [ 7, 9, 11]]]) + >>> a.ravel(order='C') + array([ 0, 2, 4, 1, 3, 5, 6, 8, 10, 7, 9, 11]) + >>> a.ravel(order='K') + array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) + + """ + if isinstance(a, np.matrix): + return asarray(a).ravel(order=order) + else: + return asanyarray(a).ravel(order=order) + + +def nonzero(a): + """ + Return the indices of the elements that are non-zero. + + Returns a tuple of arrays, one for each dimension of `a`, + containing the indices of the non-zero elements in that + dimension. The values in `a` are always tested and returned in + row-major, C-style order. The corresponding non-zero + values can be obtained with:: + + a[nonzero(a)] + + To group the indices by element, rather than dimension, use:: + + transpose(nonzero(a)) + + The result of this is always a 2-D array, with a row for + each non-zero element. + + Parameters + ---------- + a : array_like + Input array. + + Returns + ------- + tuple_of_arrays : tuple + Indices of elements that are non-zero. + + See Also + -------- + flatnonzero : + Return indices that are non-zero in the flattened version of the input + array. + ndarray.nonzero : + Equivalent ndarray method. + count_nonzero : + Counts the number of non-zero elements in the input array. + + Examples + -------- + >>> x = np.array([[1,0,0], [0,2,0], [1,1,0]]) + >>> x + array([[1, 0, 0], + [0, 2, 0], + [1, 1, 0]]) + >>> np.nonzero(x) + (array([0, 1, 2, 2]), array([0, 1, 0, 1])) + + >>> x[np.nonzero(x)] + array([1, 2, 1, 1]) + >>> np.transpose(np.nonzero(x)) + array([[0, 0], + [1, 1], + [2, 0], + [2, 1]) + + A common use for ``nonzero`` is to find the indices of an array, where + a condition is True. Given an array `a`, the condition `a` > 3 is a + boolean array and since False is interpreted as 0, np.nonzero(a > 3) + yields the indices of the `a` where the condition is true. + + >>> a = np.array([[1,2,3],[4,5,6],[7,8,9]]) + >>> a > 3 + array([[False, False, False], + [ True, True, True], + [ True, True, True]]) + >>> np.nonzero(a > 3) + (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2])) + + The ``nonzero`` method of the boolean array can also be called. + + >>> (a > 3).nonzero() + (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2])) + + """ + return _wrapfunc(a, 'nonzero') + + +def shape(a): + """ + Return the shape of an array. + + Parameters + ---------- + a : array_like + Input array. + + Returns + ------- + shape : tuple of ints + The elements of the shape tuple give the lengths of the + corresponding array dimensions. + + See Also + -------- + alen + ndarray.shape : Equivalent array method. + + Examples + -------- + >>> np.shape(np.eye(3)) + (3, 3) + >>> np.shape([[1, 2]]) + (1, 2) + >>> np.shape([0]) + (1,) + >>> np.shape(0) + () + + >>> a = np.array([(1, 2), (3, 4)], dtype=[('x', 'i4'), ('y', 'i4')]) + >>> np.shape(a) + (2,) + >>> a.shape + (2,) + + """ + try: + result = a.shape + except AttributeError: + result = asarray(a).shape + return result + + +def compress(condition, a, axis=None, out=None): + """ + Return selected slices of an array along given axis. + + When working along a given axis, a slice along that axis is returned in + `output` for each index where `condition` evaluates to True. When + working on a 1-D array, `compress` is equivalent to `extract`. + + Parameters + ---------- + condition : 1-D array of bools + Array that selects which entries to return. If len(condition) + is less than the size of `a` along the given axis, then output is + truncated to the length of the condition array. + a : array_like + Array from which to extract a part. + axis : int, optional + Axis along which to take slices. If None (default), work on the + flattened array. + out : ndarray, optional + Output array. Its type is preserved and it must be of the right + shape to hold the output. + + Returns + ------- + compressed_array : ndarray + A copy of `a` without the slices along axis for which `condition` + is false. + + See Also + -------- + take, choose, diag, diagonal, select + ndarray.compress : Equivalent method in ndarray + np.extract: Equivalent method when working on 1-D arrays + numpy.doc.ufuncs : Section "Output arguments" + + Examples + -------- + >>> a = np.array([[1, 2], [3, 4], [5, 6]]) + >>> a + array([[1, 2], + [3, 4], + [5, 6]]) + >>> np.compress([0, 1], a, axis=0) + array([[3, 4]]) + >>> np.compress([False, True, True], a, axis=0) + array([[3, 4], + [5, 6]]) + >>> np.compress([False, True], a, axis=1) + array([[2], + [4], + [6]]) + + Working on the flattened array does not return slices along an axis but + selects elements. + + >>> np.compress([False, True], a) + array([2]) + + """ + return _wrapfunc(a, 'compress', condition, axis=axis, out=out) + + +def clip(a, a_min, a_max, out=None): + """ + Clip (limit) the values in an array. + + Given an interval, values outside the interval are clipped to + the interval edges. For example, if an interval of ``[0, 1]`` + is specified, values smaller than 0 become 0, and values larger + than 1 become 1. + + Parameters + ---------- + a : array_like + Array containing elements to clip. + a_min : scalar or array_like or `None` + Minimum value. If `None`, clipping is not performed on lower + interval edge. Not more than one of `a_min` and `a_max` may be + `None`. + a_max : scalar or array_like or `None` + Maximum value. If `None`, clipping is not performed on upper + interval edge. Not more than one of `a_min` and `a_max` may be + `None`. If `a_min` or `a_max` are array_like, then the three + arrays will be broadcasted to match their shapes. + out : ndarray, optional + The results will be placed in this array. It may be the input + array for in-place clipping. `out` must be of the right shape + to hold the output. Its type is preserved. + + Returns + ------- + clipped_array : ndarray + An array with the elements of `a`, but where values + < `a_min` are replaced with `a_min`, and those > `a_max` + with `a_max`. + + See Also + -------- + numpy.doc.ufuncs : Section "Output arguments" + + Examples + -------- + >>> a = np.arange(10) + >>> np.clip(a, 1, 8) + array([1, 1, 2, 3, 4, 5, 6, 7, 8, 8]) + >>> a + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> np.clip(a, 3, 6, out=a) + array([3, 3, 3, 3, 4, 5, 6, 6, 6, 6]) + >>> a = np.arange(10) + >>> a + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> np.clip(a, [3, 4, 1, 1, 1, 4, 4, 4, 4, 4], 8) + array([3, 4, 2, 3, 4, 5, 6, 7, 8, 8]) + + """ + return _wrapfunc(a, 'clip', a_min, a_max, out=out) + + +def sum(a, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Sum of array elements over a given axis. + + Parameters + ---------- + a : array_like + Elements to sum. + axis : None or int or tuple of ints, optional + Axis or axes along which a sum is performed. The default, + axis=None, will sum all of the elements of the input array. If + axis is negative it counts from the last to the first axis. + + .. versionadded:: 1.7.0 + + If axis is a tuple of ints, a sum is performed on all of the axes + specified in the tuple instead of a single axis or all the axes as + before. + dtype : dtype, optional + The type of the returned array and of the accumulator in which the + elements are summed. The dtype of `a` is used by default unless `a` + has an integer dtype of less precision than the default platform + integer. In that case, if `a` is signed then the platform integer + is used while if `a` is unsigned then an unsigned integer of the + same precision as the platform integer is used. + out : ndarray, optional + Alternative output array in which to place the result. It must have + the same shape as the expected output, but the type of the output + values will be cast if necessary. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `sum` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + sum_along_axis : ndarray + An array with the same shape as `a`, with the specified + axis removed. If `a` is a 0-d array, or if `axis` is None, a scalar + is returned. If an output array is specified, a reference to + `out` is returned. + + See Also + -------- + ndarray.sum : Equivalent method. + + cumsum : Cumulative sum of array elements. + + trapz : Integration of array values using the composite trapezoidal rule. + + mean, average + + Notes + ----- + Arithmetic is modular when using integer types, and no error is + raised on overflow. + + The sum of an empty array is the neutral element 0: + + >>> np.sum([]) + 0.0 + + Examples + -------- + >>> np.sum([0.5, 1.5]) + 2.0 + >>> np.sum([0.5, 0.7, 0.2, 1.5], dtype=np.int32) + 1 + >>> np.sum([[0, 1], [0, 5]]) + 6 + >>> np.sum([[0, 1], [0, 5]], axis=0) + array([0, 6]) + >>> np.sum([[0, 1], [0, 5]], axis=1) + array([1, 5]) + + If the accumulator is too small, overflow occurs: + + >>> np.ones(128, dtype=np.int8).sum(dtype=np.int8) + -128 + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + if isinstance(a, _gentype): + res = _sum_(a) + if out is not None: + out[...] = res + return out + return res + if type(a) is not mu.ndarray: + try: + sum = a.sum + except AttributeError: + pass + else: + return sum(axis=axis, dtype=dtype, out=out, **kwargs) + return _methods._sum(a, axis=axis, dtype=dtype, + out=out, **kwargs) + + +def product(a, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Return the product of array elements over a given axis. + + See Also + -------- + prod : equivalent function; see for details. + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + return um.multiply.reduce(a, axis=axis, dtype=dtype, out=out, **kwargs) + + +def sometrue(a, axis=None, out=None, keepdims=np._NoValue): + """ + Check whether some values are true. + + Refer to `any` for full documentation. + + See Also + -------- + any : equivalent function + + """ + arr = asanyarray(a) + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + return arr.any(axis=axis, out=out, **kwargs) + + +def alltrue(a, axis=None, out=None, keepdims=np._NoValue): + """ + Check if all elements of input array are true. + + See Also + -------- + numpy.all : Equivalent function; see for details. + + """ + arr = asanyarray(a) + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + return arr.all(axis=axis, out=out, **kwargs) + + +def any(a, axis=None, out=None, keepdims=np._NoValue): + """ + Test whether any array element along a given axis evaluates to True. + + Returns single boolean unless `axis` is not ``None`` + + Parameters + ---------- + a : array_like + Input array or object that can be converted to an array. + axis : None or int or tuple of ints, optional + Axis or axes along which a logical OR reduction is performed. + The default (`axis` = `None`) is to perform a logical OR over all + the dimensions of the input array. `axis` may be negative, in + which case it counts from the last to the first axis. + + .. versionadded:: 1.7.0 + + If this is a tuple of ints, a reduction is performed on multiple + axes, instead of a single axis or all the axes as before. + out : ndarray, optional + Alternate output array in which to place the result. It must have + the same shape as the expected output and its type is preserved + (e.g., if it is of type float, then it will remain so, returning + 1.0 for True and 0.0 for False, regardless of the type of `a`). + See `doc.ufuncs` (Section "Output arguments") for details. + + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `any` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + any : bool or ndarray + A new boolean or `ndarray` is returned unless `out` is specified, + in which case a reference to `out` is returned. + + See Also + -------- + ndarray.any : equivalent method + + all : Test whether all elements along a given axis evaluate to True. + + Notes + ----- + Not a Number (NaN), positive infinity and negative infinity evaluate + to `True` because these are not equal to zero. + + Examples + -------- + >>> np.any([[True, False], [True, True]]) + True + + >>> np.any([[True, False], [False, False]], axis=0) + array([ True, False]) + + >>> np.any([-1, 0, 5]) + True + + >>> np.any(np.nan) + True + + >>> o=np.array([False]) + >>> z=np.any([-1, 4, 5], out=o) + >>> z, o + (array([ True]), array([ True])) + >>> # Check now that z is a reference to o + >>> z is o + True + >>> id(z), id(o) # identity of z and o # doctest: +SKIP + (191614240, 191614240) + + """ + arr = asanyarray(a) + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + return arr.any(axis=axis, out=out, **kwargs) + + +def all(a, axis=None, out=None, keepdims=np._NoValue): + """ + Test whether all array elements along a given axis evaluate to True. + + Parameters + ---------- + a : array_like + Input array or object that can be converted to an array. + axis : None or int or tuple of ints, optional + Axis or axes along which a logical AND reduction is performed. + The default (`axis` = `None`) is to perform a logical AND over all + the dimensions of the input array. `axis` may be negative, in + which case it counts from the last to the first axis. + + .. versionadded:: 1.7.0 + + If this is a tuple of ints, a reduction is performed on multiple + axes, instead of a single axis or all the axes as before. + out : ndarray, optional + Alternate output array in which to place the result. + It must have the same shape as the expected output and its + type is preserved (e.g., if ``dtype(out)`` is float, the result + will consist of 0.0's and 1.0's). See `doc.ufuncs` (Section + "Output arguments") for more details. + + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `all` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + all : ndarray, bool + A new boolean or array is returned unless `out` is specified, + in which case a reference to `out` is returned. + + See Also + -------- + ndarray.all : equivalent method + + any : Test whether any element along a given axis evaluates to True. + + Notes + ----- + Not a Number (NaN), positive infinity and negative infinity + evaluate to `True` because these are not equal to zero. + + Examples + -------- + >>> np.all([[True,False],[True,True]]) + False + + >>> np.all([[True,False],[True,True]], axis=0) + array([ True, False]) + + >>> np.all([-1, 4, 5]) + True + + >>> np.all([1.0, np.nan]) + True + + >>> o=np.array([False]) + >>> z=np.all([-1, 4, 5], out=o) + >>> id(z), id(o), z # doctest: +SKIP + (28293632, 28293632, array([ True])) + + """ + arr = asanyarray(a) + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + return arr.all(axis=axis, out=out, **kwargs) + + +def cumsum(a, axis=None, dtype=None, out=None): + """ + Return the cumulative sum of the elements along a given axis. + + Parameters + ---------- + a : array_like + Input array. + axis : int, optional + Axis along which the cumulative sum is computed. The default + (None) is to compute the cumsum over the flattened array. + dtype : dtype, optional + Type of the returned array and of the accumulator in which the + elements are summed. If `dtype` is not specified, it defaults + to the dtype of `a`, unless `a` has an integer dtype with a + precision less than that of the default platform integer. In + that case, the default platform integer is used. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output + but the type will be cast if necessary. See `doc.ufuncs` + (Section "Output arguments") for more details. + + Returns + ------- + cumsum_along_axis : ndarray. + A new array holding the result is returned unless `out` is + specified, in which case a reference to `out` is returned. The + result has the same size as `a`, and the same shape as `a` if + `axis` is not None or `a` is a 1-d array. + + + See Also + -------- + sum : Sum array elements. + + trapz : Integration of array values using the composite trapezoidal rule. + + diff : Calculate the n-th discrete difference along given axis. + + Notes + ----- + Arithmetic is modular when using integer types, and no error is + raised on overflow. + + Examples + -------- + >>> a = np.array([[1,2,3], [4,5,6]]) + >>> a + array([[1, 2, 3], + [4, 5, 6]]) + >>> np.cumsum(a) + array([ 1, 3, 6, 10, 15, 21]) + >>> np.cumsum(a, dtype=float) # specifies type of output value(s) + array([ 1., 3., 6., 10., 15., 21.]) + + >>> np.cumsum(a,axis=0) # sum over rows for each of the 3 columns + array([[1, 2, 3], + [5, 7, 9]]) + >>> np.cumsum(a,axis=1) # sum over columns for each of the 2 rows + array([[ 1, 3, 6], + [ 4, 9, 15]]) + + """ + return _wrapfunc(a, 'cumsum', axis=axis, dtype=dtype, out=out) + + +def cumproduct(a, axis=None, dtype=None, out=None): + """ + Return the cumulative product over the given axis. + + + See Also + -------- + cumprod : equivalent function; see for details. + + """ + return _wrapfunc(a, 'cumprod', axis=axis, dtype=dtype, out=out) + + +def ptp(a, axis=None, out=None): + """ + Range of values (maximum - minimum) along an axis. + + The name of the function comes from the acronym for 'peak to peak'. + + Parameters + ---------- + a : array_like + Input values. + axis : int, optional + Axis along which to find the peaks. By default, flatten the + array. + out : array_like + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output, + but the type of the output values will be cast if necessary. + + Returns + ------- + ptp : ndarray + A new array holding the result, unless `out` was + specified, in which case a reference to `out` is returned. + + Examples + -------- + >>> x = np.arange(4).reshape((2,2)) + >>> x + array([[0, 1], + [2, 3]]) + + >>> np.ptp(x, axis=0) + array([2, 2]) + + >>> np.ptp(x, axis=1) + array([1, 1]) + + """ + return _wrapfunc(a, 'ptp', axis=axis, out=out) + + +def amax(a, axis=None, out=None, keepdims=np._NoValue): + """ + Return the maximum of an array or maximum along an axis. + + Parameters + ---------- + a : array_like + Input data. + axis : None or int or tuple of ints, optional + Axis or axes along which to operate. By default, flattened input is + used. + + .. versionadded:: 1.7.0 + + If this is a tuple of ints, the maximum is selected over multiple axes, + instead of a single axis or all the axes as before. + out : ndarray, optional + Alternative output array in which to place the result. Must + be of the same shape and buffer length as the expected output. + See `doc.ufuncs` (Section "Output arguments") for more details. + + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `amax` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + amax : ndarray or scalar + Maximum of `a`. If `axis` is None, the result is a scalar value. + If `axis` is given, the result is an array of dimension + ``a.ndim - 1``. + + See Also + -------- + amin : + The minimum value of an array along a given axis, propagating any NaNs. + nanmax : + The maximum value of an array along a given axis, ignoring any NaNs. + maximum : + Element-wise maximum of two arrays, propagating any NaNs. + fmax : + Element-wise maximum of two arrays, ignoring any NaNs. + argmax : + Return the indices of the maximum values. + + nanmin, minimum, fmin + + Notes + ----- + NaN values are propagated, that is if at least one item is NaN, the + corresponding max value will be NaN as well. To ignore NaN values + (MATLAB behavior), please use nanmax. + + Don't use `amax` for element-wise comparison of 2 arrays; when + ``a.shape[0]`` is 2, ``maximum(a[0], a[1])`` is faster than + ``amax(a, axis=0)``. + + Examples + -------- + >>> a = np.arange(4).reshape((2,2)) + >>> a + array([[0, 1], + [2, 3]]) + >>> np.amax(a) # Maximum of the flattened array + 3 + >>> np.amax(a, axis=0) # Maxima along the first axis + array([2, 3]) + >>> np.amax(a, axis=1) # Maxima along the second axis + array([1, 3]) + + >>> b = np.arange(5, dtype=float) + >>> b[2] = np.NaN + >>> np.amax(b) + nan + >>> np.nanmax(b) + 4.0 + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + + if type(a) is not mu.ndarray: + try: + amax = a.max + except AttributeError: + pass + else: + return amax(axis=axis, out=out, **kwargs) + + return _methods._amax(a, axis=axis, + out=out, **kwargs) + + +def amin(a, axis=None, out=None, keepdims=np._NoValue): + """ + Return the minimum of an array or minimum along an axis. + + Parameters + ---------- + a : array_like + Input data. + axis : None or int or tuple of ints, optional + Axis or axes along which to operate. By default, flattened input is + used. + + .. versionadded:: 1.7.0 + + If this is a tuple of ints, the minimum is selected over multiple axes, + instead of a single axis or all the axes as before. + out : ndarray, optional + Alternative output array in which to place the result. Must + be of the same shape and buffer length as the expected output. + See `doc.ufuncs` (Section "Output arguments") for more details. + + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `amin` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + amin : ndarray or scalar + Minimum of `a`. If `axis` is None, the result is a scalar value. + If `axis` is given, the result is an array of dimension + ``a.ndim - 1``. + + See Also + -------- + amax : + The maximum value of an array along a given axis, propagating any NaNs. + nanmin : + The minimum value of an array along a given axis, ignoring any NaNs. + minimum : + Element-wise minimum of two arrays, propagating any NaNs. + fmin : + Element-wise minimum of two arrays, ignoring any NaNs. + argmin : + Return the indices of the minimum values. + + nanmax, maximum, fmax + + Notes + ----- + NaN values are propagated, that is if at least one item is NaN, the + corresponding min value will be NaN as well. To ignore NaN values + (MATLAB behavior), please use nanmin. + + Don't use `amin` for element-wise comparison of 2 arrays; when + ``a.shape[0]`` is 2, ``minimum(a[0], a[1])`` is faster than + ``amin(a, axis=0)``. + + Examples + -------- + >>> a = np.arange(4).reshape((2,2)) + >>> a + array([[0, 1], + [2, 3]]) + >>> np.amin(a) # Minimum of the flattened array + 0 + >>> np.amin(a, axis=0) # Minima along the first axis + array([0, 1]) + >>> np.amin(a, axis=1) # Minima along the second axis + array([0, 2]) + + >>> b = np.arange(5, dtype=float) + >>> b[2] = np.NaN + >>> np.amin(b) + nan + >>> np.nanmin(b) + 0.0 + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + if type(a) is not mu.ndarray: + try: + amin = a.min + except AttributeError: + pass + else: + return amin(axis=axis, out=out, **kwargs) + + return _methods._amin(a, axis=axis, + out=out, **kwargs) + + +def alen(a): + """ + Return the length of the first dimension of the input array. + + Parameters + ---------- + a : array_like + Input array. + + Returns + ------- + alen : int + Length of the first dimension of `a`. + + See Also + -------- + shape, size + + Examples + -------- + >>> a = np.zeros((7,4,5)) + >>> a.shape[0] + 7 + >>> np.alen(a) + 7 + + """ + try: + return len(a) + except TypeError: + return len(array(a, ndmin=1)) + + +def prod(a, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Return the product of array elements over a given axis. + + Parameters + ---------- + a : array_like + Input data. + axis : None or int or tuple of ints, optional + Axis or axes along which a product is performed. The default, + axis=None, will calculate the product of all the elements in the + input array. If axis is negative it counts from the last to the + first axis. + + .. versionadded:: 1.7.0 + + If axis is a tuple of ints, a product is performed on all of the + axes specified in the tuple instead of a single axis or all the + axes as before. + dtype : dtype, optional + The type of the returned array, as well as of the accumulator in + which the elements are multiplied. The dtype of `a` is used by + default unless `a` has an integer dtype of less precision than the + default platform integer. In that case, if `a` is signed then the + platform integer is used while if `a` is unsigned then an unsigned + integer of the same precision as the platform integer is used. + out : ndarray, optional + Alternative output array in which to place the result. It must have + the same shape as the expected output, but the type of the output + values will be cast if necessary. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left in the + result as dimensions with size one. With this option, the result + will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `prod` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + product_along_axis : ndarray, see `dtype` parameter above. + An array shaped as `a` but with the specified axis removed. + Returns a reference to `out` if specified. + + See Also + -------- + ndarray.prod : equivalent method + numpy.doc.ufuncs : Section "Output arguments" + + Notes + ----- + Arithmetic is modular when using integer types, and no error is + raised on overflow. That means that, on a 32-bit platform: + + >>> x = np.array([536870910, 536870910, 536870910, 536870910]) + >>> np.prod(x) # random + 16 + + The product of an empty array is the neutral element 1: + + >>> np.prod([]) + 1.0 + + Examples + -------- + By default, calculate the product of all elements: + + >>> np.prod([1.,2.]) + 2.0 + + Even when the input array is two-dimensional: + + >>> np.prod([[1.,2.],[3.,4.]]) + 24.0 + + But we can also specify the axis over which to multiply: + + >>> np.prod([[1.,2.],[3.,4.]], axis=1) + array([ 2., 12.]) + + If the type of `x` is unsigned, then the output type is + the unsigned platform integer: + + >>> x = np.array([1, 2, 3], dtype=np.uint8) + >>> np.prod(x).dtype == np.uint + True + + If `x` is of a signed integer type, then the output type + is the default platform integer: + + >>> x = np.array([1, 2, 3], dtype=np.int8) + >>> np.prod(x).dtype == int + True + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + if type(a) is not mu.ndarray: + try: + prod = a.prod + except AttributeError: + pass + else: + return prod(axis=axis, dtype=dtype, out=out, **kwargs) + + return _methods._prod(a, axis=axis, dtype=dtype, + out=out, **kwargs) + + +def cumprod(a, axis=None, dtype=None, out=None): + """ + Return the cumulative product of elements along a given axis. + + Parameters + ---------- + a : array_like + Input array. + axis : int, optional + Axis along which the cumulative product is computed. By default + the input is flattened. + dtype : dtype, optional + Type of the returned array, as well as of the accumulator in which + the elements are multiplied. If *dtype* is not specified, it + defaults to the dtype of `a`, unless `a` has an integer dtype with + a precision less than that of the default platform integer. In + that case, the default platform integer is used instead. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output + but the type of the resulting values will be cast if necessary. + + Returns + ------- + cumprod : ndarray + A new array holding the result is returned unless `out` is + specified, in which case a reference to out is returned. + + See Also + -------- + numpy.doc.ufuncs : Section "Output arguments" + + Notes + ----- + Arithmetic is modular when using integer types, and no error is + raised on overflow. + + Examples + -------- + >>> a = np.array([1,2,3]) + >>> np.cumprod(a) # intermediate results 1, 1*2 + ... # total product 1*2*3 = 6 + array([1, 2, 6]) + >>> a = np.array([[1, 2, 3], [4, 5, 6]]) + >>> np.cumprod(a, dtype=float) # specify type of output + array([ 1., 2., 6., 24., 120., 720.]) + + The cumulative product for each column (i.e., over the rows) of `a`: + + >>> np.cumprod(a, axis=0) + array([[ 1, 2, 3], + [ 4, 10, 18]]) + + The cumulative product for each row (i.e. over the columns) of `a`: + + >>> np.cumprod(a,axis=1) + array([[ 1, 2, 6], + [ 4, 20, 120]]) + + """ + return _wrapfunc(a, 'cumprod', axis=axis, dtype=dtype, out=out) + + +def ndim(a): + """ + Return the number of dimensions of an array. + + Parameters + ---------- + a : array_like + Input array. If it is not already an ndarray, a conversion is + attempted. + + Returns + ------- + number_of_dimensions : int + The number of dimensions in `a`. Scalars are zero-dimensional. + + See Also + -------- + ndarray.ndim : equivalent method + shape : dimensions of array + ndarray.shape : dimensions of array + + Examples + -------- + >>> np.ndim([[1,2,3],[4,5,6]]) + 2 + >>> np.ndim(np.array([[1,2,3],[4,5,6]])) + 2 + >>> np.ndim(1) + 0 + + """ + try: + return a.ndim + except AttributeError: + return asarray(a).ndim + + +def rank(a): + """ + Return the number of dimensions of an array. + + If `a` is not already an array, a conversion is attempted. + Scalars are zero dimensional. + + .. note:: + This function is deprecated in NumPy 1.9 to avoid confusion with + `numpy.linalg.matrix_rank`. The ``ndim`` attribute or function + should be used instead. + + Parameters + ---------- + a : array_like + Array whose number of dimensions is desired. If `a` is not an array, + a conversion is attempted. + + Returns + ------- + number_of_dimensions : int + The number of dimensions in the array. + + See Also + -------- + ndim : equivalent function + ndarray.ndim : equivalent property + shape : dimensions of array + ndarray.shape : dimensions of array + + Notes + ----- + In the old Numeric package, `rank` was the term used for the number of + dimensions, but in NumPy `ndim` is used instead. + + Examples + -------- + >>> np.rank([1,2,3]) + 1 + >>> np.rank(np.array([[1,2,3],[4,5,6]])) + 2 + >>> np.rank(1) + 0 + + """ + # 2014-04-12, 1.9 + warnings.warn( + "`rank` is deprecated; use the `ndim` attribute or function instead. " + "To find the rank of a matrix see `numpy.linalg.matrix_rank`.", + VisibleDeprecationWarning, stacklevel=2) + try: + return a.ndim + except AttributeError: + return asarray(a).ndim + + +def size(a, axis=None): + """ + Return the number of elements along a given axis. + + Parameters + ---------- + a : array_like + Input data. + axis : int, optional + Axis along which the elements are counted. By default, give + the total number of elements. + + Returns + ------- + element_count : int + Number of elements along the specified axis. + + See Also + -------- + shape : dimensions of array + ndarray.shape : dimensions of array + ndarray.size : number of elements in array + + Examples + -------- + >>> a = np.array([[1,2,3],[4,5,6]]) + >>> np.size(a) + 6 + >>> np.size(a,1) + 3 + >>> np.size(a,0) + 2 + + """ + if axis is None: + try: + return a.size + except AttributeError: + return asarray(a).size + else: + try: + return a.shape[axis] + except AttributeError: + return asarray(a).shape[axis] + + +def around(a, decimals=0, out=None): + """ + Evenly round to the given number of decimals. + + Parameters + ---------- + a : array_like + Input data. + decimals : int, optional + Number of decimal places to round to (default: 0). If + decimals is negative, it specifies the number of positions to + the left of the decimal point. + out : ndarray, optional + Alternative output array in which to place the result. It must have + the same shape as the expected output, but the type of the output + values will be cast if necessary. See `doc.ufuncs` (Section + "Output arguments") for details. + + Returns + ------- + rounded_array : ndarray + An array of the same type as `a`, containing the rounded values. + Unless `out` was specified, a new array is created. A reference to + the result is returned. + + The real and imaginary parts of complex numbers are rounded + separately. The result of rounding a float is a float. + + See Also + -------- + ndarray.round : equivalent method + + ceil, fix, floor, rint, trunc + + + Notes + ----- + For values exactly halfway between rounded decimal values, NumPy + rounds to the nearest even value. Thus 1.5 and 2.5 round to 2.0, + -0.5 and 0.5 round to 0.0, etc. Results may also be surprising due + to the inexact representation of decimal fractions in the IEEE + floating point standard [1]_ and errors introduced when scaling + by powers of ten. + + References + ---------- + .. [1] "Lecture Notes on the Status of IEEE 754", William Kahan, + http://www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF + .. [2] "How Futile are Mindless Assessments of + Roundoff in Floating-Point Computation?", William Kahan, + http://www.cs.berkeley.edu/~wkahan/Mindless.pdf + + Examples + -------- + >>> np.around([0.37, 1.64]) + array([ 0., 2.]) + >>> np.around([0.37, 1.64], decimals=1) + array([ 0.4, 1.6]) + >>> np.around([.5, 1.5, 2.5, 3.5, 4.5]) # rounds to nearest even value + array([ 0., 2., 2., 4., 4.]) + >>> np.around([1,2,3,11], decimals=1) # ndarray of ints is returned + array([ 1, 2, 3, 11]) + >>> np.around([1,2,3,11], decimals=-1) + array([ 0, 0, 0, 10]) + + """ + return _wrapfunc(a, 'round', decimals=decimals, out=out) + + +def round_(a, decimals=0, out=None): + """ + Round an array to the given number of decimals. + + Refer to `around` for full documentation. + + See Also + -------- + around : equivalent function + + """ + return around(a, decimals=decimals, out=out) + + +def mean(a, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Compute the arithmetic mean along the specified axis. + + Returns the average of the array elements. The average is taken over + the flattened array by default, otherwise over the specified axis. + `float64` intermediate and return values are used for integer inputs. + + Parameters + ---------- + a : array_like + Array containing numbers whose mean is desired. If `a` is not an + array, a conversion is attempted. + axis : None or int or tuple of ints, optional + Axis or axes along which the means are computed. The default is to + compute the mean of the flattened array. + + .. versionadded:: 1.7.0 + + If this is a tuple of ints, a mean is performed over multiple axes, + instead of a single axis or all the axes as before. + dtype : data-type, optional + Type to use in computing the mean. For integer inputs, the default + is `float64`; for floating point inputs, it is the same as the + input dtype. + out : ndarray, optional + Alternate output array in which to place the result. The default + is ``None``; if provided, it must have the same shape as the + expected output, but the type will be cast if necessary. + See `doc.ufuncs` for details. + + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `mean` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + m : ndarray, see dtype parameter above + If `out=None`, returns a new array containing the mean values, + otherwise a reference to the output array is returned. + + See Also + -------- + average : Weighted average + std, var, nanmean, nanstd, nanvar + + Notes + ----- + The arithmetic mean is the sum of the elements along the axis divided + by the number of elements. + + Note that for floating-point input, the mean is computed using the + same precision the input has. Depending on the input data, this can + cause the results to be inaccurate, especially for `float32` (see + example below). Specifying a higher-precision accumulator using the + `dtype` keyword can alleviate this issue. + + By default, `float16` results are computed using `float32` intermediates + for extra precision. + + Examples + -------- + >>> a = np.array([[1, 2], [3, 4]]) + >>> np.mean(a) + 2.5 + >>> np.mean(a, axis=0) + array([ 2., 3.]) + >>> np.mean(a, axis=1) + array([ 1.5, 3.5]) + + In single precision, `mean` can be inaccurate: + + >>> a = np.zeros((2, 512*512), dtype=np.float32) + >>> a[0, :] = 1.0 + >>> a[1, :] = 0.1 + >>> np.mean(a) + 0.54999924 + + Computing the mean in float64 is more accurate: + + >>> np.mean(a, dtype=np.float64) + 0.55000000074505806 + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + if type(a) is not mu.ndarray: + try: + mean = a.mean + except AttributeError: + pass + else: + return mean(axis=axis, dtype=dtype, out=out, **kwargs) + + return _methods._mean(a, axis=axis, dtype=dtype, + out=out, **kwargs) + + +def std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue): + """ + Compute the standard deviation along the specified axis. + + Returns the standard deviation, a measure of the spread of a distribution, + of the array elements. The standard deviation is computed for the + flattened array by default, otherwise over the specified axis. + + Parameters + ---------- + a : array_like + Calculate the standard deviation of these values. + axis : None or int or tuple of ints, optional + Axis or axes along which the standard deviation is computed. The + default is to compute the standard deviation of the flattened array. + + .. versionadded:: 1.7.0 + + If this is a tuple of ints, a standard deviation is performed over + multiple axes, instead of a single axis or all the axes as before. + dtype : dtype, optional + Type to use in computing the standard deviation. For arrays of + integer type the default is float64, for arrays of float types it is + the same as the array type. + out : ndarray, optional + Alternative output array in which to place the result. It must have + the same shape as the expected output but the type (of the calculated + values) will be cast if necessary. + ddof : int, optional + Means Delta Degrees of Freedom. The divisor used in calculations + is ``N - ddof``, where ``N`` represents the number of elements. + By default `ddof` is zero. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `std` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + standard_deviation : ndarray, see dtype parameter above. + If `out` is None, return a new array containing the standard deviation, + otherwise return a reference to the output array. + + See Also + -------- + var, mean, nanmean, nanstd, nanvar + numpy.doc.ufuncs : Section "Output arguments" + + Notes + ----- + The standard deviation is the square root of the average of the squared + deviations from the mean, i.e., ``std = sqrt(mean(abs(x - x.mean())**2))``. + + The average squared deviation is normally calculated as + ``x.sum() / N``, where ``N = len(x)``. If, however, `ddof` is specified, + the divisor ``N - ddof`` is used instead. In standard statistical + practice, ``ddof=1`` provides an unbiased estimator of the variance + of the infinite population. ``ddof=0`` provides a maximum likelihood + estimate of the variance for normally distributed variables. The + standard deviation computed in this function is the square root of + the estimated variance, so even with ``ddof=1``, it will not be an + unbiased estimate of the standard deviation per se. + + Note that, for complex numbers, `std` takes the absolute + value before squaring, so that the result is always real and nonnegative. + + For floating-point input, the *std* is computed using the same + precision the input has. Depending on the input data, this can cause + the results to be inaccurate, especially for float32 (see example below). + Specifying a higher-accuracy accumulator using the `dtype` keyword can + alleviate this issue. + + Examples + -------- + >>> a = np.array([[1, 2], [3, 4]]) + >>> np.std(a) + 1.1180339887498949 + >>> np.std(a, axis=0) + array([ 1., 1.]) + >>> np.std(a, axis=1) + array([ 0.5, 0.5]) + + In single precision, std() can be inaccurate: + + >>> a = np.zeros((2, 512*512), dtype=np.float32) + >>> a[0, :] = 1.0 + >>> a[1, :] = 0.1 + >>> np.std(a) + 0.45000005 + + Computing the standard deviation in float64 is more accurate: + + >>> np.std(a, dtype=np.float64) + 0.44999999925494177 + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + + if type(a) is not mu.ndarray: + try: + std = a.std + except AttributeError: + pass + else: + return std(axis=axis, dtype=dtype, out=out, ddof=ddof, **kwargs) + + return _methods._std(a, axis=axis, dtype=dtype, out=out, ddof=ddof, + **kwargs) + + +def var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue): + """ + Compute the variance along the specified axis. + + Returns the variance of the array elements, a measure of the spread of a + distribution. The variance is computed for the flattened array by + default, otherwise over the specified axis. + + Parameters + ---------- + a : array_like + Array containing numbers whose variance is desired. If `a` is not an + array, a conversion is attempted. + axis : None or int or tuple of ints, optional + Axis or axes along which the variance is computed. The default is to + compute the variance of the flattened array. + + .. versionadded:: 1.7.0 + + If this is a tuple of ints, a variance is performed over multiple axes, + instead of a single axis or all the axes as before. + dtype : data-type, optional + Type to use in computing the variance. For arrays of integer type + the default is `float32`; for arrays of float types it is the same as + the array type. + out : ndarray, optional + Alternate output array in which to place the result. It must have + the same shape as the expected output, but the type is cast if + necessary. + ddof : int, optional + "Delta Degrees of Freedom": the divisor used in the calculation is + ``N - ddof``, where ``N`` represents the number of elements. By + default `ddof` is zero. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + If the default value is passed, then `keepdims` will not be + passed through to the `var` method of sub-classes of + `ndarray`, however any non-default value will be. If the + sub-classes `sum` method does not implement `keepdims` any + exceptions will be raised. + + Returns + ------- + variance : ndarray, see dtype parameter above + If ``out=None``, returns a new array containing the variance; + otherwise, a reference to the output array is returned. + + See Also + -------- + std , mean, nanmean, nanstd, nanvar + numpy.doc.ufuncs : Section "Output arguments" + + Notes + ----- + The variance is the average of the squared deviations from the mean, + i.e., ``var = mean(abs(x - x.mean())**2)``. + + The mean is normally calculated as ``x.sum() / N``, where ``N = len(x)``. + If, however, `ddof` is specified, the divisor ``N - ddof`` is used + instead. In standard statistical practice, ``ddof=1`` provides an + unbiased estimator of the variance of a hypothetical infinite population. + ``ddof=0`` provides a maximum likelihood estimate of the variance for + normally distributed variables. + + Note that for complex numbers, the absolute value is taken before + squaring, so that the result is always real and nonnegative. + + For floating-point input, the variance is computed using the same + precision the input has. Depending on the input data, this can cause + the results to be inaccurate, especially for `float32` (see example + below). Specifying a higher-accuracy accumulator using the ``dtype`` + keyword can alleviate this issue. + + Examples + -------- + >>> a = np.array([[1, 2], [3, 4]]) + >>> np.var(a) + 1.25 + >>> np.var(a, axis=0) + array([ 1., 1.]) + >>> np.var(a, axis=1) + array([ 0.25, 0.25]) + + In single precision, var() can be inaccurate: + + >>> a = np.zeros((2, 512*512), dtype=np.float32) + >>> a[0, :] = 1.0 + >>> a[1, :] = 0.1 + >>> np.var(a) + 0.20250003 + + Computing the variance in float64 is more accurate: + + >>> np.var(a, dtype=np.float64) + 0.20249999932944759 + >>> ((1-0.55)**2 + (0.1-0.55)**2)/2 + 0.2025 + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + + if type(a) is not mu.ndarray: + try: + var = a.var + + except AttributeError: + pass + else: + return var(axis=axis, dtype=dtype, out=out, ddof=ddof, **kwargs) + + return _methods._var(a, axis=axis, dtype=dtype, out=out, ddof=ddof, + **kwargs) diff --git a/numpy/core/function_base.py b/numpy/core/function_base.py new file mode 100644 index 0000000..82de1a3 --- /dev/null +++ b/numpy/core/function_base.py @@ -0,0 +1,358 @@ +from __future__ import division, absolute_import, print_function + +import warnings +import operator + +from . import numeric as _nx +from .numeric import (result_type, NaN, shares_memory, MAY_SHARE_BOUNDS, + TooHardError,asanyarray) + +__all__ = ['logspace', 'linspace', 'geomspace'] + + +def _index_deprecate(i, stacklevel=2): + try: + i = operator.index(i) + except TypeError: + msg = ("object of type {} cannot be safely interpreted as " + "an integer.".format(type(i))) + i = int(i) + stacklevel += 1 + warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel) + return i + + +def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None): + """ + Return evenly spaced numbers over a specified interval. + + Returns `num` evenly spaced samples, calculated over the + interval [`start`, `stop`]. + + The endpoint of the interval can optionally be excluded. + + Parameters + ---------- + start : scalar + The starting value of the sequence. + stop : scalar + The end value of the sequence, unless `endpoint` is set to False. + In that case, the sequence consists of all but the last of ``num + 1`` + evenly spaced samples, so that `stop` is excluded. Note that the step + size changes when `endpoint` is False. + num : int, optional + Number of samples to generate. Default is 50. Must be non-negative. + endpoint : bool, optional + If True, `stop` is the last sample. Otherwise, it is not included. + Default is True. + retstep : bool, optional + If True, return (`samples`, `step`), where `step` is the spacing + between samples. + dtype : dtype, optional + The type of the output array. If `dtype` is not given, infer the data + type from the other input arguments. + + .. versionadded:: 1.9.0 + + Returns + ------- + samples : ndarray + There are `num` equally spaced samples in the closed interval + ``[start, stop]`` or the half-open interval ``[start, stop)`` + (depending on whether `endpoint` is True or False). + step : float, optional + Only returned if `retstep` is True + + Size of spacing between samples. + + + See Also + -------- + arange : Similar to `linspace`, but uses a step size (instead of the + number of samples). + logspace : Samples uniformly distributed in log space. + + Examples + -------- + >>> np.linspace(2.0, 3.0, num=5) + array([ 2. , 2.25, 2.5 , 2.75, 3. ]) + >>> np.linspace(2.0, 3.0, num=5, endpoint=False) + array([ 2. , 2.2, 2.4, 2.6, 2.8]) + >>> np.linspace(2.0, 3.0, num=5, retstep=True) + (array([ 2. , 2.25, 2.5 , 2.75, 3. ]), 0.25) + + Graphical illustration: + + >>> import matplotlib.pyplot as plt + >>> N = 8 + >>> y = np.zeros(N) + >>> x1 = np.linspace(0, 10, N, endpoint=True) + >>> x2 = np.linspace(0, 10, N, endpoint=False) + >>> plt.plot(x1, y, 'o') + [] + >>> plt.plot(x2, y + 0.5, 'o') + [] + >>> plt.ylim([-0.5, 1]) + (-0.5, 1) + >>> plt.show() + + """ + # 2016-02-25, 1.12 + num = _index_deprecate(num) + if num < 0: + raise ValueError("Number of samples, %s, must be non-negative." % num) + div = (num - 1) if endpoint else num + + # Convert float/complex array scalars to float, gh-3504 + # and make sure one can use variables that have an __array_interface__, gh-6634 + start = asanyarray(start) * 1.0 + stop = asanyarray(stop) * 1.0 + + dt = result_type(start, stop, float(num)) + if dtype is None: + dtype = dt + + y = _nx.arange(0, num, dtype=dt) + + delta = stop - start + # In-place multiplication y *= delta/div is faster, but prevents the multiplicant + # from overriding what class is produced, and thus prevents, e.g. use of Quantities, + # see gh-7142. Hence, we multiply in place only for standard scalar types. + _mult_inplace = _nx.isscalar(delta) + if num > 1: + step = delta / div + if step == 0: + # Special handling for denormal numbers, gh-5437 + y /= div + if _mult_inplace: + y *= delta + else: + y = y * delta + else: + if _mult_inplace: + y *= step + else: + y = y * step + else: + # 0 and 1 item long sequences have an undefined step + step = NaN + # Multiply with delta to allow possible override of output class. + y = y * delta + + y += start + + if endpoint and num > 1: + y[-1] = stop + + if retstep: + return y.astype(dtype, copy=False), step + else: + return y.astype(dtype, copy=False) + + +def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None): + """ + Return numbers spaced evenly on a log scale. + + In linear space, the sequence starts at ``base ** start`` + (`base` to the power of `start`) and ends with ``base ** stop`` + (see `endpoint` below). + + Parameters + ---------- + start : float + ``base ** start`` is the starting value of the sequence. + stop : float + ``base ** stop`` is the final value of the sequence, unless `endpoint` + is False. In that case, ``num + 1`` values are spaced over the + interval in log-space, of which all but the last (a sequence of + length `num`) are returned. + num : integer, optional + Number of samples to generate. Default is 50. + endpoint : boolean, optional + If true, `stop` is the last sample. Otherwise, it is not included. + Default is True. + base : float, optional + The base of the log space. The step size between the elements in + ``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform. + Default is 10.0. + dtype : dtype + The type of the output array. If `dtype` is not given, infer the data + type from the other input arguments. + + Returns + ------- + samples : ndarray + `num` samples, equally spaced on a log scale. + + See Also + -------- + arange : Similar to linspace, with the step size specified instead of the + number of samples. Note that, when used with a float endpoint, the + endpoint may or may not be included. + linspace : Similar to logspace, but with the samples uniformly distributed + in linear space, instead of log space. + geomspace : Similar to logspace, but with endpoints specified directly. + + Notes + ----- + Logspace is equivalent to the code + + >>> y = np.linspace(start, stop, num=num, endpoint=endpoint) + ... # doctest: +SKIP + >>> power(base, y).astype(dtype) + ... # doctest: +SKIP + + Examples + -------- + >>> np.logspace(2.0, 3.0, num=4) + array([ 100. , 215.443469 , 464.15888336, 1000. ]) + >>> np.logspace(2.0, 3.0, num=4, endpoint=False) + array([ 100. , 177.827941 , 316.22776602, 562.34132519]) + >>> np.logspace(2.0, 3.0, num=4, base=2.0) + array([ 4. , 5.0396842 , 6.34960421, 8. ]) + + Graphical illustration: + + >>> import matplotlib.pyplot as plt + >>> N = 10 + >>> x1 = np.logspace(0.1, 1, N, endpoint=True) + >>> x2 = np.logspace(0.1, 1, N, endpoint=False) + >>> y = np.zeros(N) + >>> plt.plot(x1, y, 'o') + [] + >>> plt.plot(x2, y + 0.5, 'o') + [] + >>> plt.ylim([-0.5, 1]) + (-0.5, 1) + >>> plt.show() + + """ + y = linspace(start, stop, num=num, endpoint=endpoint) + if dtype is None: + return _nx.power(base, y) + return _nx.power(base, y).astype(dtype) + + +def geomspace(start, stop, num=50, endpoint=True, dtype=None): + """ + Return numbers spaced evenly on a log scale (a geometric progression). + + This is similar to `logspace`, but with endpoints specified directly. + Each output sample is a constant multiple of the previous. + + Parameters + ---------- + start : scalar + The starting value of the sequence. + stop : scalar + The final value of the sequence, unless `endpoint` is False. + In that case, ``num + 1`` values are spaced over the + interval in log-space, of which all but the last (a sequence of + length `num`) are returned. + num : integer, optional + Number of samples to generate. Default is 50. + endpoint : boolean, optional + If true, `stop` is the last sample. Otherwise, it is not included. + Default is True. + dtype : dtype + The type of the output array. If `dtype` is not given, infer the data + type from the other input arguments. + + Returns + ------- + samples : ndarray + `num` samples, equally spaced on a log scale. + + See Also + -------- + logspace : Similar to geomspace, but with endpoints specified using log + and base. + linspace : Similar to geomspace, but with arithmetic instead of geometric + progression. + arange : Similar to linspace, with the step size specified instead of the + number of samples. + + Notes + ----- + If the inputs or dtype are complex, the output will follow a logarithmic + spiral in the complex plane. (There are an infinite number of spirals + passing through two points; the output will follow the shortest such path.) + + Examples + -------- + >>> np.geomspace(1, 1000, num=4) + array([ 1., 10., 100., 1000.]) + >>> np.geomspace(1, 1000, num=3, endpoint=False) + array([ 1., 10., 100.]) + >>> np.geomspace(1, 1000, num=4, endpoint=False) + array([ 1. , 5.62341325, 31.6227766 , 177.827941 ]) + >>> np.geomspace(1, 256, num=9) + array([ 1., 2., 4., 8., 16., 32., 64., 128., 256.]) + + Note that the above may not produce exact integers: + + >>> np.geomspace(1, 256, num=9, dtype=int) + array([ 1, 2, 4, 7, 16, 32, 63, 127, 256]) + >>> np.around(np.geomspace(1, 256, num=9)).astype(int) + array([ 1, 2, 4, 8, 16, 32, 64, 128, 256]) + + Negative, decreasing, and complex inputs are allowed: + + >>> np.geomspace(1000, 1, num=4) + array([ 1000., 100., 10., 1.]) + >>> np.geomspace(-1000, -1, num=4) + array([-1000., -100., -10., -1.]) + >>> np.geomspace(1j, 1000j, num=4) # Straight line + array([ 0. +1.j, 0. +10.j, 0. +100.j, 0.+1000.j]) + >>> np.geomspace(-1+0j, 1+0j, num=5) # Circle + array([-1.00000000+0.j , -0.70710678+0.70710678j, + 0.00000000+1.j , 0.70710678+0.70710678j, + 1.00000000+0.j ]) + + Graphical illustration of ``endpoint`` parameter: + + >>> import matplotlib.pyplot as plt + >>> N = 10 + >>> y = np.zeros(N) + >>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=True), y + 1, 'o') + >>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=False), y + 2, 'o') + >>> plt.axis([0.5, 2000, 0, 3]) + >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both') + >>> plt.show() + + """ + if start == 0 or stop == 0: + raise ValueError('Geometric sequence cannot include zero') + + dt = result_type(start, stop, float(num)) + if dtype is None: + dtype = dt + else: + # complex to dtype('complex128'), for instance + dtype = _nx.dtype(dtype) + + # Avoid negligible real or imaginary parts in output by rotating to + # positive real, calculating, then undoing rotation + out_sign = 1 + if start.real == stop.real == 0: + start, stop = start.imag, stop.imag + out_sign = 1j * out_sign + if _nx.sign(start) == _nx.sign(stop) == -1: + start, stop = -start, -stop + out_sign = -out_sign + + # Promote both arguments to the same dtype in case, for instance, one is + # complex and another is negative and log would produce NaN otherwise + start = start + (stop - stop) + stop = stop + (start - start) + if _nx.issubdtype(dtype, _nx.complexfloating): + start = start + 0j + stop = stop + 0j + + log_start = _nx.log10(start) + log_stop = _nx.log10(stop) + result = out_sign * logspace(log_start, log_stop, num=num, + endpoint=endpoint, base=10.0, dtype=dtype) + + return result.astype(dtype) diff --git a/numpy/core/getlimits.py b/numpy/core/getlimits.py new file mode 100644 index 0000000..e450a66 --- /dev/null +++ b/numpy/core/getlimits.py @@ -0,0 +1,560 @@ +"""Machine limits for Float32 and Float64 and (long double) if available... + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['finfo', 'iinfo'] + +import warnings + +from .machar import MachAr +from . import numeric +from . import numerictypes as ntypes +from .numeric import array, inf +from .umath import log10, exp2 +from . import umath + + +def _fr0(a): + """fix rank-0 --> rank-1""" + if a.ndim == 0: + a = a.copy() + a.shape = (1,) + return a + + +def _fr1(a): + """fix rank > 0 --> rank-0""" + if a.size == 1: + a = a.copy() + a.shape = () + return a + + +_convert_to_float = { + ntypes.csingle: ntypes.single, + ntypes.complex_: ntypes.float_, + ntypes.clongfloat: ntypes.longfloat + } + + +# Parameters for creating MachAr / MachAr-like objects +_title_fmt = 'numpy {} precision floating point number' +_MACHAR_PARAMS = { + ntypes.double: dict( + itype = ntypes.int64, + fmt = '%24.16e', + title = _title_fmt.format('double')), + ntypes.single: dict( + itype = ntypes.int32, + fmt = '%15.7e', + title = _title_fmt.format('single')), + ntypes.longdouble: dict( + itype = ntypes.longlong, + fmt = '%s', + title = _title_fmt.format('long double')), + ntypes.half: dict( + itype = ntypes.int16, + fmt = '%12.5e', + title = _title_fmt.format('half'))} + + +class MachArLike(object): + """ Object to simulate MachAr instance """ + + def __init__(self, + ftype, + **kwargs): + params = _MACHAR_PARAMS[ftype] + float_conv = lambda v: array([v], ftype) + float_to_float = lambda v : _fr1(float_conv(v)) + self._float_to_str = lambda v: (params['fmt'] % + array(_fr0(v)[0], ftype)) + self.title = params['title'] + # Parameter types same as for discovered MachAr object. + self.epsilon = self.eps = float_to_float(kwargs.pop('eps')) + self.epsneg = float_to_float(kwargs.pop('epsneg')) + self.xmax = self.huge = float_to_float(kwargs.pop('huge')) + self.xmin = self.tiny = float_to_float(kwargs.pop('tiny')) + self.ibeta = params['itype'](kwargs.pop('ibeta')) + self.__dict__.update(kwargs) + self.precision = int(-log10(self.eps)) + self.resolution = float_to_float(float_conv(10) ** (-self.precision)) + + # Properties below to delay need for float_to_str, and thus avoid circular + # imports during early numpy module loading. + # See: https://github.com/numpy/numpy/pull/8983#discussion_r115838683 + + @property + def _str_eps(self): + return self._float_to_str(self.eps) + + @property + def _str_epsneg(self): + return self._float_to_str(self.epsneg) + + @property + def _str_xmin(self): + return self._float_to_str(self.xmin) + + @property + def _str_xmax(self): + return self._float_to_str(self.xmax) + + @property + def _str_resolution(self): + return self._float_to_str(self.resolution) + + +# Known parameters for float16 +# See docstring of MachAr class for description of parameters. +_f16 = ntypes.float16 +_float16_ma = MachArLike(_f16, + machep=-10, + negep=-11, + minexp=-14, + maxexp=16, + it=10, + iexp=5, + ibeta=2, + irnd=5, + ngrd=0, + eps=exp2(_f16(-10)), + epsneg=exp2(_f16(-11)), + huge=_f16(65504), + tiny=_f16(2 ** -14)) + +# Known parameters for float32 +_f32 = ntypes.float32 +_float32_ma = MachArLike(_f32, + machep=-23, + negep=-24, + minexp=-126, + maxexp=128, + it=23, + iexp=8, + ibeta=2, + irnd=5, + ngrd=0, + eps=exp2(_f32(-23)), + epsneg=exp2(_f32(-24)), + huge=_f32((1 - 2 ** -24) * 2**128), + tiny=exp2(_f32(-126))) + +# Known parameters for float64 +_f64 = ntypes.float64 +_epsneg_f64 = 2.0 ** -53.0 +_tiny_f64 = 2.0 ** -1022.0 +_float64_ma = MachArLike(_f64, + machep=-52, + negep=-53, + minexp=-1022, + maxexp=1024, + it=52, + iexp=11, + ibeta=2, + irnd=5, + ngrd=0, + eps=2.0 ** -52.0, + epsneg=_epsneg_f64, + huge=(1.0 - _epsneg_f64) / _tiny_f64 * _f64(4), + tiny=_tiny_f64) + +# Known parameters for IEEE 754 128-bit binary float +_ld = ntypes.longdouble +_epsneg_f128 = exp2(_ld(-113)) +_tiny_f128 = exp2(_ld(-16382)) +# Ignore runtime error when this is not f128 +with numeric.errstate(all='ignore'): + _huge_f128 = (_ld(1) - _epsneg_f128) / _tiny_f128 * _ld(4) +_float128_ma = MachArLike(_ld, + machep=-112, + negep=-113, + minexp=-16382, + maxexp=16384, + it=112, + iexp=15, + ibeta=2, + irnd=5, + ngrd=0, + eps=exp2(_ld(-112)), + epsneg=_epsneg_f128, + huge=_huge_f128, + tiny=_tiny_f128) + +# Known parameters for float80 (Intel 80-bit extended precision) +_epsneg_f80 = exp2(_ld(-64)) +_tiny_f80 = exp2(_ld(-16382)) +# Ignore runtime error when this is not f80 +with numeric.errstate(all='ignore'): + _huge_f80 = (_ld(1) - _epsneg_f80) / _tiny_f80 * _ld(4) +_float80_ma = MachArLike(_ld, + machep=-63, + negep=-64, + minexp=-16382, + maxexp=16384, + it=63, + iexp=15, + ibeta=2, + irnd=5, + ngrd=0, + eps=exp2(_ld(-63)), + epsneg=_epsneg_f80, + huge=_huge_f80, + tiny=_tiny_f80) + +# Guessed / known parameters for double double; see: +# https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format#Double-double_arithmetic +# These numbers have the same exponent range as float64, but extended number of +# digits in the significand. +_huge_dd = (umath.nextafter(_ld(inf), _ld(0)) + if hasattr(umath, 'nextafter') # Missing on some platforms? + else _float64_ma.huge) +_float_dd_ma = MachArLike(_ld, + machep=-105, + negep=-106, + minexp=-1022, + maxexp=1024, + it=105, + iexp=11, + ibeta=2, + irnd=5, + ngrd=0, + eps=exp2(_ld(-105)), + epsneg= exp2(_ld(-106)), + huge=_huge_dd, + tiny=exp2(_ld(-1022))) + + +# Key to identify the floating point type. Key is result of +# ftype('-0.1').newbyteorder('<').tobytes() +# See: +# https://perl5.git.perl.org/perl.git/blob/3118d7d684b56cbeb702af874f4326683c45f045:/Configure +_KNOWN_TYPES = { + b'\x9a\x99\x99\x99\x99\x99\xb9\xbf' : _float64_ma, + b'\xcd\xcc\xcc\xbd' : _float32_ma, + b'f\xae' : _float16_ma, + # float80, first 10 bytes containing actual storage + b'\xcd\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xfb\xbf' : _float80_ma, + # double double; low, high order (e.g. PPC 64) + b'\x9a\x99\x99\x99\x99\x99Y<\x9a\x99\x99\x99\x99\x99\xb9\xbf' : + _float_dd_ma, + # double double; high, low order (e.g. PPC 64 le) + b'\x9a\x99\x99\x99\x99\x99\xb9\xbf\x9a\x99\x99\x99\x99\x99Y<' : + _float_dd_ma, + # IEEE 754 128-bit binary float + b'\x9a\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xfb\xbf' : + _float128_ma, +} + + +def _get_machar(ftype): + """ Get MachAr instance or MachAr-like instance + + Get parameters for floating point type, by first trying signatures of + various known floating point types, then, if none match, attempting to + identify parameters by analysis. + + Parameters + ---------- + ftype : class + Numpy floating point type class (e.g. ``np.float64``) + + Returns + ------- + ma_like : instance of :class:`MachAr` or :class:`MachArLike` + Object giving floating point parameters for `ftype`. + + Warns + ----- + UserWarning + If the binary signature of the float type is not in the dictionary of + known float types. + """ + params = _MACHAR_PARAMS.get(ftype) + if params is None: + raise ValueError(repr(ftype)) + # Detect known / suspected types + key = ftype('-0.1').newbyteorder('<').tobytes() + ma_like = _KNOWN_TYPES.get(key) + # Could be 80 bit == 10 byte extended precision, where last bytes can be + # random garbage. Try comparing first 10 bytes to pattern. + if ma_like is None and ftype == ntypes.longdouble: + ma_like = _KNOWN_TYPES.get(key[:10]) + if ma_like is not None: + return ma_like + # Fall back to parameter discovery + warnings.warn( + 'Signature {} for {} does not match any known type: ' + 'falling back to type probe function'.format(key, ftype), + UserWarning, stacklevel=2) + return _discovered_machar(ftype) + + +def _discovered_machar(ftype): + """ Create MachAr instance with found information on float types + """ + params = _MACHAR_PARAMS[ftype] + return MachAr(lambda v: array([v], ftype), + lambda v:_fr0(v.astype(params['itype']))[0], + lambda v:array(_fr0(v)[0], ftype), + lambda v: params['fmt'] % array(_fr0(v)[0], ftype), + params['title']) + + +class finfo(object): + """ + finfo(dtype) + + Machine limits for floating point types. + + Attributes + ---------- + bits : int + The number of bits occupied by the type. + eps : float + The smallest representable positive number such that + ``1.0 + eps != 1.0``. Type of `eps` is an appropriate floating + point type. + epsneg : floating point number of the appropriate type + The smallest representable positive number such that + ``1.0 - epsneg != 1.0``. + iexp : int + The number of bits in the exponent portion of the floating point + representation. + machar : MachAr + The object which calculated these parameters and holds more + detailed information. + machep : int + The exponent that yields `eps`. + max : floating point number of the appropriate type + The largest representable number. + maxexp : int + The smallest positive power of the base (2) that causes overflow. + min : floating point number of the appropriate type + The smallest representable number, typically ``-max``. + minexp : int + The most negative power of the base (2) consistent with there + being no leading 0's in the mantissa. + negep : int + The exponent that yields `epsneg`. + nexp : int + The number of bits in the exponent including its sign and bias. + nmant : int + The number of bits in the mantissa. + precision : int + The approximate number of decimal digits to which this kind of + float is precise. + resolution : floating point number of the appropriate type + The approximate decimal resolution of this type, i.e., + ``10**-precision``. + tiny : float + The smallest positive usable number. Type of `tiny` is an + appropriate floating point type. + + Parameters + ---------- + dtype : float, dtype, or instance + Kind of floating point data-type about which to get information. + + See Also + -------- + MachAr : The implementation of the tests that produce this information. + iinfo : The equivalent for integer data types. + + Notes + ----- + For developers of NumPy: do not instantiate this at the module level. + The initial calculation of these parameters is expensive and negatively + impacts import times. These objects are cached, so calling ``finfo()`` + repeatedly inside your functions is not a problem. + + """ + + _finfo_cache = {} + + def __new__(cls, dtype): + try: + dtype = numeric.dtype(dtype) + except TypeError: + # In case a float instance was given + dtype = numeric.dtype(type(dtype)) + + obj = cls._finfo_cache.get(dtype, None) + if obj is not None: + return obj + dtypes = [dtype] + newdtype = numeric.obj2sctype(dtype) + if newdtype is not dtype: + dtypes.append(newdtype) + dtype = newdtype + if not issubclass(dtype, numeric.inexact): + raise ValueError("data type %r not inexact" % (dtype)) + obj = cls._finfo_cache.get(dtype, None) + if obj is not None: + return obj + if not issubclass(dtype, numeric.floating): + newdtype = _convert_to_float[dtype] + if newdtype is not dtype: + dtypes.append(newdtype) + dtype = newdtype + obj = cls._finfo_cache.get(dtype, None) + if obj is not None: + return obj + obj = object.__new__(cls)._init(dtype) + for dt in dtypes: + cls._finfo_cache[dt] = obj + return obj + + def _init(self, dtype): + self.dtype = numeric.dtype(dtype) + machar = _get_machar(dtype) + + for word in ['precision', 'iexp', + 'maxexp', 'minexp', 'negep', + 'machep']: + setattr(self, word, getattr(machar, word)) + for word in ['tiny', 'resolution', 'epsneg']: + setattr(self, word, getattr(machar, word).flat[0]) + self.bits = self.dtype.itemsize * 8 + self.max = machar.huge.flat[0] + self.min = -self.max + self.eps = machar.eps.flat[0] + self.nexp = machar.iexp + self.nmant = machar.it + self.machar = machar + self._str_tiny = machar._str_xmin.strip() + self._str_max = machar._str_xmax.strip() + self._str_epsneg = machar._str_epsneg.strip() + self._str_eps = machar._str_eps.strip() + self._str_resolution = machar._str_resolution.strip() + return self + + def __str__(self): + fmt = ( + 'Machine parameters for %(dtype)s\n' + '---------------------------------------------------------------\n' + 'precision = %(precision)3s resolution = %(_str_resolution)s\n' + 'machep = %(machep)6s eps = %(_str_eps)s\n' + 'negep = %(negep)6s epsneg = %(_str_epsneg)s\n' + 'minexp = %(minexp)6s tiny = %(_str_tiny)s\n' + 'maxexp = %(maxexp)6s max = %(_str_max)s\n' + 'nexp = %(nexp)6s min = -max\n' + '---------------------------------------------------------------\n' + ) + return fmt % self.__dict__ + + def __repr__(self): + c = self.__class__.__name__ + d = self.__dict__.copy() + d['klass'] = c + return (("%(klass)s(resolution=%(resolution)s, min=-%(_str_max)s," + " max=%(_str_max)s, dtype=%(dtype)s)") % d) + + +class iinfo(object): + """ + iinfo(type) + + Machine limits for integer types. + + Attributes + ---------- + bits : int + The number of bits occupied by the type. + min : int + The smallest integer expressible by the type. + max : int + The largest integer expressible by the type. + + Parameters + ---------- + int_type : integer type, dtype, or instance + The kind of integer data type to get information about. + + See Also + -------- + finfo : The equivalent for floating point data types. + + Examples + -------- + With types: + + >>> ii16 = np.iinfo(np.int16) + >>> ii16.min + -32768 + >>> ii16.max + 32767 + >>> ii32 = np.iinfo(np.int32) + >>> ii32.min + -2147483648 + >>> ii32.max + 2147483647 + + With instances: + + >>> ii32 = np.iinfo(np.int32(10)) + >>> ii32.min + -2147483648 + >>> ii32.max + 2147483647 + + """ + + _min_vals = {} + _max_vals = {} + + def __init__(self, int_type): + try: + self.dtype = numeric.dtype(int_type) + except TypeError: + self.dtype = numeric.dtype(type(int_type)) + self.kind = self.dtype.kind + self.bits = self.dtype.itemsize * 8 + self.key = "%s%d" % (self.kind, self.bits) + if self.kind not in 'iu': + raise ValueError("Invalid integer data type.") + + def min(self): + """Minimum value of given dtype.""" + if self.kind == 'u': + return 0 + else: + try: + val = iinfo._min_vals[self.key] + except KeyError: + val = int(-(1 << (self.bits-1))) + iinfo._min_vals[self.key] = val + return val + + min = property(min) + + def max(self): + """Maximum value of given dtype.""" + try: + val = iinfo._max_vals[self.key] + except KeyError: + if self.kind == 'u': + val = int((1 << self.bits) - 1) + else: + val = int((1 << (self.bits-1)) - 1) + iinfo._max_vals[self.key] = val + return val + + max = property(max) + + def __str__(self): + """String representation.""" + fmt = ( + 'Machine parameters for %(dtype)s\n' + '---------------------------------------------------------------\n' + 'min = %(min)s\n' + 'max = %(max)s\n' + '---------------------------------------------------------------\n' + ) + return fmt % {'dtype': self.dtype, 'min': self.min, 'max': self.max} + + def __repr__(self): + return "%s(min=%s, max=%s, dtype=%s)" % (self.__class__.__name__, + self.min, self.max, self.dtype) + diff --git a/numpy/core/include/numpy/_neighborhood_iterator_imp.h b/numpy/core/include/numpy/_neighborhood_iterator_imp.h new file mode 100644 index 0000000..e8860cb --- /dev/null +++ b/numpy/core/include/numpy/_neighborhood_iterator_imp.h @@ -0,0 +1,90 @@ +#ifndef _NPY_INCLUDE_NEIGHBORHOOD_IMP +#error You should not include this header directly +#endif +/* + * Private API (here for inline) + */ +static NPY_INLINE int +_PyArrayNeighborhoodIter_IncrCoord(PyArrayNeighborhoodIterObject* iter); + +/* + * Update to next item of the iterator + * + * Note: this simply increment the coordinates vector, last dimension + * incremented first , i.e, for dimension 3 + * ... + * -1, -1, -1 + * -1, -1, 0 + * -1, -1, 1 + * .... + * -1, 0, -1 + * -1, 0, 0 + * .... + * 0, -1, -1 + * 0, -1, 0 + * .... + */ +#define _UPDATE_COORD_ITER(c) \ + wb = iter->coordinates[c] < iter->bounds[c][1]; \ + if (wb) { \ + iter->coordinates[c] += 1; \ + return 0; \ + } \ + else { \ + iter->coordinates[c] = iter->bounds[c][0]; \ + } + +static NPY_INLINE int +_PyArrayNeighborhoodIter_IncrCoord(PyArrayNeighborhoodIterObject* iter) +{ + npy_intp i, wb; + + for (i = iter->nd - 1; i >= 0; --i) { + _UPDATE_COORD_ITER(i) + } + + return 0; +} + +/* + * Version optimized for 2d arrays, manual loop unrolling + */ +static NPY_INLINE int +_PyArrayNeighborhoodIter_IncrCoord2D(PyArrayNeighborhoodIterObject* iter) +{ + npy_intp wb; + + _UPDATE_COORD_ITER(1) + _UPDATE_COORD_ITER(0) + + return 0; +} +#undef _UPDATE_COORD_ITER + +/* + * Advance to the next neighbour + */ +static NPY_INLINE int +PyArrayNeighborhoodIter_Next(PyArrayNeighborhoodIterObject* iter) +{ + _PyArrayNeighborhoodIter_IncrCoord (iter); + iter->dataptr = iter->translate((PyArrayIterObject*)iter, iter->coordinates); + + return 0; +} + +/* + * Reset functions + */ +static NPY_INLINE int +PyArrayNeighborhoodIter_Reset(PyArrayNeighborhoodIterObject* iter) +{ + npy_intp i; + + for (i = 0; i < iter->nd; ++i) { + iter->coordinates[i] = iter->bounds[i][0]; + } + iter->dataptr = iter->translate((PyArrayIterObject*)iter, iter->coordinates); + + return 0; +} diff --git a/numpy/core/include/numpy/arrayobject.h b/numpy/core/include/numpy/arrayobject.h new file mode 100644 index 0000000..4f46d6b --- /dev/null +++ b/numpy/core/include/numpy/arrayobject.h @@ -0,0 +1,11 @@ +#ifndef Py_ARRAYOBJECT_H +#define Py_ARRAYOBJECT_H + +#include "ndarrayobject.h" +#include "npy_interrupt.h" + +#ifdef NPY_NO_PREFIX +#include "noprefix.h" +#endif + +#endif diff --git a/numpy/core/include/numpy/arrayscalars.h b/numpy/core/include/numpy/arrayscalars.h new file mode 100644 index 0000000..64450e7 --- /dev/null +++ b/numpy/core/include/numpy/arrayscalars.h @@ -0,0 +1,175 @@ +#ifndef _NPY_ARRAYSCALARS_H_ +#define _NPY_ARRAYSCALARS_H_ + +#ifndef _MULTIARRAYMODULE +typedef struct { + PyObject_HEAD + npy_bool obval; +} PyBoolScalarObject; +#endif + + +typedef struct { + PyObject_HEAD + signed char obval; +} PyByteScalarObject; + + +typedef struct { + PyObject_HEAD + short obval; +} PyShortScalarObject; + + +typedef struct { + PyObject_HEAD + int obval; +} PyIntScalarObject; + + +typedef struct { + PyObject_HEAD + long obval; +} PyLongScalarObject; + + +typedef struct { + PyObject_HEAD + npy_longlong obval; +} PyLongLongScalarObject; + + +typedef struct { + PyObject_HEAD + unsigned char obval; +} PyUByteScalarObject; + + +typedef struct { + PyObject_HEAD + unsigned short obval; +} PyUShortScalarObject; + + +typedef struct { + PyObject_HEAD + unsigned int obval; +} PyUIntScalarObject; + + +typedef struct { + PyObject_HEAD + unsigned long obval; +} PyULongScalarObject; + + +typedef struct { + PyObject_HEAD + npy_ulonglong obval; +} PyULongLongScalarObject; + + +typedef struct { + PyObject_HEAD + npy_half obval; +} PyHalfScalarObject; + + +typedef struct { + PyObject_HEAD + float obval; +} PyFloatScalarObject; + + +typedef struct { + PyObject_HEAD + double obval; +} PyDoubleScalarObject; + + +typedef struct { + PyObject_HEAD + npy_longdouble obval; +} PyLongDoubleScalarObject; + + +typedef struct { + PyObject_HEAD + npy_cfloat obval; +} PyCFloatScalarObject; + + +typedef struct { + PyObject_HEAD + npy_cdouble obval; +} PyCDoubleScalarObject; + + +typedef struct { + PyObject_HEAD + npy_clongdouble obval; +} PyCLongDoubleScalarObject; + + +typedef struct { + PyObject_HEAD + PyObject * obval; +} PyObjectScalarObject; + +typedef struct { + PyObject_HEAD + npy_datetime obval; + PyArray_DatetimeMetaData obmeta; +} PyDatetimeScalarObject; + +typedef struct { + PyObject_HEAD + npy_timedelta obval; + PyArray_DatetimeMetaData obmeta; +} PyTimedeltaScalarObject; + + +typedef struct { + PyObject_HEAD + char obval; +} PyScalarObject; + +#define PyStringScalarObject PyStringObject +#define PyUnicodeScalarObject PyUnicodeObject + +typedef struct { + PyObject_VAR_HEAD + char *obval; + PyArray_Descr *descr; + int flags; + PyObject *base; +} PyVoidScalarObject; + +/* Macros + PyScalarObject + PyArrType_Type + are defined in ndarrayobject.h +*/ + +#define PyArrayScalar_False ((PyObject *)(&(_PyArrayScalar_BoolValues[0]))) +#define PyArrayScalar_True ((PyObject *)(&(_PyArrayScalar_BoolValues[1]))) +#define PyArrayScalar_FromLong(i) \ + ((PyObject *)(&(_PyArrayScalar_BoolValues[((i)!=0)]))) +#define PyArrayScalar_RETURN_BOOL_FROM_LONG(i) \ + return Py_INCREF(PyArrayScalar_FromLong(i)), \ + PyArrayScalar_FromLong(i) +#define PyArrayScalar_RETURN_FALSE \ + return Py_INCREF(PyArrayScalar_False), \ + PyArrayScalar_False +#define PyArrayScalar_RETURN_TRUE \ + return Py_INCREF(PyArrayScalar_True), \ + PyArrayScalar_True + +#define PyArrayScalar_New(cls) \ + Py##cls##ArrType_Type.tp_alloc(&Py##cls##ArrType_Type, 0) +#define PyArrayScalar_VAL(obj, cls) \ + ((Py##cls##ScalarObject *)obj)->obval +#define PyArrayScalar_ASSIGN(obj, cls, val) \ + PyArrayScalar_VAL(obj, cls) = val + +#endif diff --git a/numpy/core/include/numpy/halffloat.h b/numpy/core/include/numpy/halffloat.h new file mode 100644 index 0000000..ab0d221 --- /dev/null +++ b/numpy/core/include/numpy/halffloat.h @@ -0,0 +1,70 @@ +#ifndef __NPY_HALFFLOAT_H__ +#define __NPY_HALFFLOAT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Half-precision routines + */ + +/* Conversions */ +float npy_half_to_float(npy_half h); +double npy_half_to_double(npy_half h); +npy_half npy_float_to_half(float f); +npy_half npy_double_to_half(double d); +/* Comparisons */ +int npy_half_eq(npy_half h1, npy_half h2); +int npy_half_ne(npy_half h1, npy_half h2); +int npy_half_le(npy_half h1, npy_half h2); +int npy_half_lt(npy_half h1, npy_half h2); +int npy_half_ge(npy_half h1, npy_half h2); +int npy_half_gt(npy_half h1, npy_half h2); +/* faster *_nonan variants for when you know h1 and h2 are not NaN */ +int npy_half_eq_nonan(npy_half h1, npy_half h2); +int npy_half_lt_nonan(npy_half h1, npy_half h2); +int npy_half_le_nonan(npy_half h1, npy_half h2); +/* Miscellaneous functions */ +int npy_half_iszero(npy_half h); +int npy_half_isnan(npy_half h); +int npy_half_isinf(npy_half h); +int npy_half_isfinite(npy_half h); +int npy_half_signbit(npy_half h); +npy_half npy_half_copysign(npy_half x, npy_half y); +npy_half npy_half_spacing(npy_half h); +npy_half npy_half_nextafter(npy_half x, npy_half y); +npy_half npy_half_divmod(npy_half x, npy_half y, npy_half *modulus); + +/* + * Half-precision constants + */ + +#define NPY_HALF_ZERO (0x0000u) +#define NPY_HALF_PZERO (0x0000u) +#define NPY_HALF_NZERO (0x8000u) +#define NPY_HALF_ONE (0x3c00u) +#define NPY_HALF_NEGONE (0xbc00u) +#define NPY_HALF_PINF (0x7c00u) +#define NPY_HALF_NINF (0xfc00u) +#define NPY_HALF_NAN (0x7e00u) + +#define NPY_MAX_HALF (0x7bffu) + +/* + * Bit-level conversions + */ + +npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f); +npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d); +npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h); +npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/numpy/core/include/numpy/ndarrayobject.h b/numpy/core/include/numpy/ndarrayobject.h new file mode 100644 index 0000000..12fc709 --- /dev/null +++ b/numpy/core/include/numpy/ndarrayobject.h @@ -0,0 +1,291 @@ +/* + * DON'T INCLUDE THIS DIRECTLY. + */ + +#ifndef NPY_NDARRAYOBJECT_H +#define NPY_NDARRAYOBJECT_H +#ifdef __cplusplus +#define CONFUSE_EMACS { +#define CONFUSE_EMACS2 } +extern "C" CONFUSE_EMACS +#undef CONFUSE_EMACS +#undef CONFUSE_EMACS2 +/* ... otherwise a semi-smart identer (like emacs) tries to indent + everything when you're typing */ +#endif + +#include +#include "ndarraytypes.h" + +/* Includes the "function" C-API -- these are all stored in a + list of pointers --- one for each file + The two lists are concatenated into one in multiarray. + + They are available as import_array() +*/ + +#include "__multiarray_api.h" + + +/* C-API that requires previous API to be defined */ + +#define PyArray_DescrCheck(op) (((PyObject*)(op))->ob_type==&PyArrayDescr_Type) + +#define PyArray_Check(op) PyObject_TypeCheck(op, &PyArray_Type) +#define PyArray_CheckExact(op) (((PyObject*)(op))->ob_type == &PyArray_Type) + +#define PyArray_HasArrayInterfaceType(op, type, context, out) \ + ((((out)=PyArray_FromStructInterface(op)) != Py_NotImplemented) || \ + (((out)=PyArray_FromInterface(op)) != Py_NotImplemented) || \ + (((out)=PyArray_FromArrayAttr(op, type, context)) != \ + Py_NotImplemented)) + +#define PyArray_HasArrayInterface(op, out) \ + PyArray_HasArrayInterfaceType(op, NULL, NULL, out) + +#define PyArray_IsZeroDim(op) (PyArray_Check(op) && \ + (PyArray_NDIM((PyArrayObject *)op) == 0)) + +#define PyArray_IsScalar(obj, cls) \ + (PyObject_TypeCheck(obj, &Py##cls##ArrType_Type)) + +#define PyArray_CheckScalar(m) (PyArray_IsScalar(m, Generic) || \ + PyArray_IsZeroDim(m)) +#if PY_MAJOR_VERSION >= 3 +#define PyArray_IsPythonNumber(obj) \ + (PyFloat_Check(obj) || PyComplex_Check(obj) || \ + PyLong_Check(obj) || PyBool_Check(obj)) +#define PyArray_IsIntegerScalar(obj) (PyLong_Check(obj) \ + || PyArray_IsScalar((obj), Integer)) +#define PyArray_IsPythonScalar(obj) \ + (PyArray_IsPythonNumber(obj) || PyBytes_Check(obj) || \ + PyUnicode_Check(obj)) +#else +#define PyArray_IsPythonNumber(obj) \ + (PyInt_Check(obj) || PyFloat_Check(obj) || PyComplex_Check(obj) || \ + PyLong_Check(obj) || PyBool_Check(obj)) +#define PyArray_IsIntegerScalar(obj) (PyInt_Check(obj) \ + || PyLong_Check(obj) \ + || PyArray_IsScalar((obj), Integer)) +#define PyArray_IsPythonScalar(obj) \ + (PyArray_IsPythonNumber(obj) || PyString_Check(obj) || \ + PyUnicode_Check(obj)) +#endif + +#define PyArray_IsAnyScalar(obj) \ + (PyArray_IsScalar(obj, Generic) || PyArray_IsPythonScalar(obj)) + +#define PyArray_CheckAnyScalar(obj) (PyArray_IsPythonScalar(obj) || \ + PyArray_CheckScalar(obj)) + + +#define PyArray_GETCONTIGUOUS(m) (PyArray_ISCONTIGUOUS(m) ? \ + Py_INCREF(m), (m) : \ + (PyArrayObject *)(PyArray_Copy(m))) + +#define PyArray_SAMESHAPE(a1,a2) ((PyArray_NDIM(a1) == PyArray_NDIM(a2)) && \ + PyArray_CompareLists(PyArray_DIMS(a1), \ + PyArray_DIMS(a2), \ + PyArray_NDIM(a1))) + +#define PyArray_SIZE(m) PyArray_MultiplyList(PyArray_DIMS(m), PyArray_NDIM(m)) +#define PyArray_NBYTES(m) (PyArray_ITEMSIZE(m) * PyArray_SIZE(m)) +#define PyArray_FROM_O(m) PyArray_FromAny(m, NULL, 0, 0, 0, NULL) + +#define PyArray_FROM_OF(m,flags) PyArray_CheckFromAny(m, NULL, 0, 0, flags, \ + NULL) + +#define PyArray_FROM_OT(m,type) PyArray_FromAny(m, \ + PyArray_DescrFromType(type), 0, 0, 0, NULL) + +#define PyArray_FROM_OTF(m, type, flags) \ + PyArray_FromAny(m, PyArray_DescrFromType(type), 0, 0, \ + (((flags) & NPY_ARRAY_ENSURECOPY) ? \ + ((flags) | NPY_ARRAY_DEFAULT) : (flags)), NULL) + +#define PyArray_FROMANY(m, type, min, max, flags) \ + PyArray_FromAny(m, PyArray_DescrFromType(type), min, max, \ + (((flags) & NPY_ARRAY_ENSURECOPY) ? \ + (flags) | NPY_ARRAY_DEFAULT : (flags)), NULL) + +#define PyArray_ZEROS(m, dims, type, is_f_order) \ + PyArray_Zeros(m, dims, PyArray_DescrFromType(type), is_f_order) + +#define PyArray_EMPTY(m, dims, type, is_f_order) \ + PyArray_Empty(m, dims, PyArray_DescrFromType(type), is_f_order) + +#define PyArray_FILLWBYTE(obj, val) memset(PyArray_DATA(obj), val, \ + PyArray_NBYTES(obj)) +#ifndef PYPY_VERSION +#define PyArray_REFCOUNT(obj) (((PyObject *)(obj))->ob_refcnt) +#define NPY_REFCOUNT PyArray_REFCOUNT +#endif +#define NPY_MAX_ELSIZE (2 * NPY_SIZEOF_LONGDOUBLE) + +#define PyArray_ContiguousFromAny(op, type, min_depth, max_depth) \ + PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth, \ + max_depth, NPY_ARRAY_DEFAULT, NULL) + +#define PyArray_EquivArrTypes(a1, a2) \ + PyArray_EquivTypes(PyArray_DESCR(a1), PyArray_DESCR(a2)) + +#define PyArray_EquivByteorders(b1, b2) \ + (((b1) == (b2)) || (PyArray_ISNBO(b1) == PyArray_ISNBO(b2))) + +#define PyArray_SimpleNew(nd, dims, typenum) \ + PyArray_New(&PyArray_Type, nd, dims, typenum, NULL, NULL, 0, 0, NULL) + +#define PyArray_SimpleNewFromData(nd, dims, typenum, data) \ + PyArray_New(&PyArray_Type, nd, dims, typenum, NULL, \ + data, 0, NPY_ARRAY_CARRAY, NULL) + +#define PyArray_SimpleNewFromDescr(nd, dims, descr) \ + PyArray_NewFromDescr(&PyArray_Type, descr, nd, dims, \ + NULL, NULL, 0, NULL) + +#define PyArray_ToScalar(data, arr) \ + PyArray_Scalar(data, PyArray_DESCR(arr), (PyObject *)arr) + + +/* These might be faster without the dereferencing of obj + going on inside -- of course an optimizing compiler should + inline the constants inside a for loop making it a moot point +*/ + +#define PyArray_GETPTR1(obj, i) ((void *)(PyArray_BYTES(obj) + \ + (i)*PyArray_STRIDES(obj)[0])) + +#define PyArray_GETPTR2(obj, i, j) ((void *)(PyArray_BYTES(obj) + \ + (i)*PyArray_STRIDES(obj)[0] + \ + (j)*PyArray_STRIDES(obj)[1])) + +#define PyArray_GETPTR3(obj, i, j, k) ((void *)(PyArray_BYTES(obj) + \ + (i)*PyArray_STRIDES(obj)[0] + \ + (j)*PyArray_STRIDES(obj)[1] + \ + (k)*PyArray_STRIDES(obj)[2])) + +#define PyArray_GETPTR4(obj, i, j, k, l) ((void *)(PyArray_BYTES(obj) + \ + (i)*PyArray_STRIDES(obj)[0] + \ + (j)*PyArray_STRIDES(obj)[1] + \ + (k)*PyArray_STRIDES(obj)[2] + \ + (l)*PyArray_STRIDES(obj)[3])) + +/* Move to arrayobject.c once PyArray_XDECREF_ERR is removed */ +static NPY_INLINE void +PyArray_DiscardWritebackIfCopy(PyArrayObject *arr) +{ + PyArrayObject_fields *fa = (PyArrayObject_fields *)arr; + if (fa && fa->base) { + if ((fa->flags & NPY_ARRAY_UPDATEIFCOPY) || + (fa->flags & NPY_ARRAY_WRITEBACKIFCOPY)) { + PyArray_ENABLEFLAGS((PyArrayObject*)fa->base, NPY_ARRAY_WRITEABLE); + Py_DECREF(fa->base); + fa->base = NULL; + PyArray_CLEARFLAGS(arr, NPY_ARRAY_WRITEBACKIFCOPY); + PyArray_CLEARFLAGS(arr, NPY_ARRAY_UPDATEIFCOPY); + } + } +} + +#define PyArray_DESCR_REPLACE(descr) do { \ + PyArray_Descr *_new_; \ + _new_ = PyArray_DescrNew(descr); \ + Py_XDECREF(descr); \ + descr = _new_; \ + } while(0) + +/* Copy should always return contiguous array */ +#define PyArray_Copy(obj) PyArray_NewCopy(obj, NPY_CORDER) + +#define PyArray_FromObject(op, type, min_depth, max_depth) \ + PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth, \ + max_depth, NPY_ARRAY_BEHAVED | \ + NPY_ARRAY_ENSUREARRAY, NULL) + +#define PyArray_ContiguousFromObject(op, type, min_depth, max_depth) \ + PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth, \ + max_depth, NPY_ARRAY_DEFAULT | \ + NPY_ARRAY_ENSUREARRAY, NULL) + +#define PyArray_CopyFromObject(op, type, min_depth, max_depth) \ + PyArray_FromAny(op, PyArray_DescrFromType(type), min_depth, \ + max_depth, NPY_ARRAY_ENSURECOPY | \ + NPY_ARRAY_DEFAULT | \ + NPY_ARRAY_ENSUREARRAY, NULL) + +#define PyArray_Cast(mp, type_num) \ + PyArray_CastToType(mp, PyArray_DescrFromType(type_num), 0) + +#define PyArray_Take(ap, items, axis) \ + PyArray_TakeFrom(ap, items, axis, NULL, NPY_RAISE) + +#define PyArray_Put(ap, items, values) \ + PyArray_PutTo(ap, items, values, NPY_RAISE) + +/* Compatibility with old Numeric stuff -- don't use in new code */ + +#define PyArray_FromDimsAndData(nd, d, type, data) \ + PyArray_FromDimsAndDataAndDescr(nd, d, PyArray_DescrFromType(type), \ + data) + + +/* + Check to see if this key in the dictionary is the "title" + entry of the tuple (i.e. a duplicate dictionary entry in the fields + dict. +*/ + +static NPY_INLINE int +NPY_TITLE_KEY_check(PyObject *key, PyObject *value) +{ + PyObject *title; + if (PyTuple_GET_SIZE(value) != 3) { + return 0; + } + title = PyTuple_GET_ITEM(value, 2); + if (key == title) { + return 1; + } +#ifdef PYPY_VERSION + /* + * On PyPy, dictionary keys do not always preserve object identity. + * Fall back to comparison by value. + */ + if (PyUnicode_Check(title) && PyUnicode_Check(key)) { + return PyUnicode_Compare(title, key) == 0 ? 1 : 0; + } +#if PY_VERSION_HEX < 0x03000000 + if (PyString_Check(title) && PyString_Check(key)) { + return PyObject_Compare(title, key) == 0 ? 1 : 0; + } +#endif +#endif + return 0; +} + +/* Macro, for backward compat with "if NPY_TITLE_KEY(key, value) { ..." */ +#define NPY_TITLE_KEY(key, value) (NPY_TITLE_KEY_check((key), (value))) + +#define DEPRECATE(msg) PyErr_WarnEx(PyExc_DeprecationWarning,msg,1) +#define DEPRECATE_FUTUREWARNING(msg) PyErr_WarnEx(PyExc_FutureWarning,msg,1) + +#if !defined(NPY_NO_DEPRECATED_API) || \ + (NPY_NO_DEPRECATED_API < NPY_1_14_API_VERSION) +static NPY_INLINE void +PyArray_XDECREF_ERR(PyArrayObject *arr) +{ + /* 2017-Nov-10 1.14 */ + DEPRECATE("PyArray_XDECREF_ERR is deprecated, call " + "PyArray_DiscardWritebackIfCopy then Py_XDECREF instead"); + PyArray_DiscardWritebackIfCopy(arr); + Py_XDECREF(arr); +} +#endif + + +#ifdef __cplusplus +} +#endif + + +#endif /* NPY_NDARRAYOBJECT_H */ diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h new file mode 100644 index 0000000..19bbc74 --- /dev/null +++ b/numpy/core/include/numpy/ndarraytypes.h @@ -0,0 +1,1832 @@ +#ifndef NDARRAYTYPES_H +#define NDARRAYTYPES_H + +#include "npy_common.h" +#include "npy_endian.h" +#include "npy_cpu.h" +#include "utils.h" + +#define NPY_NO_EXPORT NPY_VISIBILITY_HIDDEN + +/* Only use thread if configured in config and python supports it */ +#if defined WITH_THREAD && !NPY_NO_SMP + #define NPY_ALLOW_THREADS 1 +#else + #define NPY_ALLOW_THREADS 0 +#endif + +#ifndef __has_extension +#define __has_extension(x) 0 +#endif + +#if !defined(_NPY_NO_DEPRECATIONS) && \ + ((defined(__GNUC__)&& __GNUC__ >= 6) || \ + __has_extension(attribute_deprecated_with_message)) +#define NPY_ATTR_DEPRECATE(text) __attribute__ ((deprecated (text))) +#else +#define NPY_ATTR_DEPRECATE(text) +#endif + +/* + * There are several places in the code where an array of dimensions + * is allocated statically. This is the size of that static + * allocation. + * + * The array creation itself could have arbitrary dimensions but all + * the places where static allocation is used would need to be changed + * to dynamic (including inside of several structures) + */ + +#define NPY_MAXDIMS 32 +#define NPY_MAXARGS 32 + +/* Used for Converter Functions "O&" code in ParseTuple */ +#define NPY_FAIL 0 +#define NPY_SUCCEED 1 + +/* + * Binary compatibility version number. This number is increased + * whenever the C-API is changed such that binary compatibility is + * broken, i.e. whenever a recompile of extension modules is needed. + */ +#define NPY_VERSION NPY_ABI_VERSION + +/* + * Minor API version. This number is increased whenever a change is + * made to the C-API -- whether it breaks binary compatibility or not. + * Some changes, such as adding a function pointer to the end of the + * function table, can be made without breaking binary compatibility. + * In this case, only the NPY_FEATURE_VERSION (*not* NPY_VERSION) + * would be increased. Whenever binary compatibility is broken, both + * NPY_VERSION and NPY_FEATURE_VERSION should be increased. + */ +#define NPY_FEATURE_VERSION NPY_API_VERSION + +enum NPY_TYPES { NPY_BOOL=0, + NPY_BYTE, NPY_UBYTE, + NPY_SHORT, NPY_USHORT, + NPY_INT, NPY_UINT, + NPY_LONG, NPY_ULONG, + NPY_LONGLONG, NPY_ULONGLONG, + NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, + NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE, + NPY_OBJECT=17, + NPY_STRING, NPY_UNICODE, + NPY_VOID, + /* + * New 1.6 types appended, may be integrated + * into the above in 2.0. + */ + NPY_DATETIME, NPY_TIMEDELTA, NPY_HALF, + + NPY_NTYPES, + NPY_NOTYPE, + NPY_CHAR NPY_ATTR_DEPRECATE("Use NPY_STRING"), + NPY_USERDEF=256, /* leave room for characters */ + + /* The number of types not including the new 1.6 types */ + NPY_NTYPES_ABI_COMPATIBLE=21 +}; +#ifdef _MSC_VER +#pragma deprecated(NPY_CHAR) +#endif + +/* basetype array priority */ +#define NPY_PRIORITY 0.0 + +/* default subtype priority */ +#define NPY_SUBTYPE_PRIORITY 1.0 + +/* default scalar priority */ +#define NPY_SCALAR_PRIORITY -1000000.0 + +/* How many floating point types are there (excluding half) */ +#define NPY_NUM_FLOATTYPE 3 + +/* + * These characters correspond to the array type and the struct + * module + */ + +enum NPY_TYPECHAR { + NPY_BOOLLTR = '?', + NPY_BYTELTR = 'b', + NPY_UBYTELTR = 'B', + NPY_SHORTLTR = 'h', + NPY_USHORTLTR = 'H', + NPY_INTLTR = 'i', + NPY_UINTLTR = 'I', + NPY_LONGLTR = 'l', + NPY_ULONGLTR = 'L', + NPY_LONGLONGLTR = 'q', + NPY_ULONGLONGLTR = 'Q', + NPY_HALFLTR = 'e', + NPY_FLOATLTR = 'f', + NPY_DOUBLELTR = 'd', + NPY_LONGDOUBLELTR = 'g', + NPY_CFLOATLTR = 'F', + NPY_CDOUBLELTR = 'D', + NPY_CLONGDOUBLELTR = 'G', + NPY_OBJECTLTR = 'O', + NPY_STRINGLTR = 'S', + NPY_STRINGLTR2 = 'a', + NPY_UNICODELTR = 'U', + NPY_VOIDLTR = 'V', + NPY_DATETIMELTR = 'M', + NPY_TIMEDELTALTR = 'm', + NPY_CHARLTR = 'c', + + /* + * No Descriptor, just a define -- this let's + * Python users specify an array of integers + * large enough to hold a pointer on the + * platform + */ + NPY_INTPLTR = 'p', + NPY_UINTPLTR = 'P', + + /* + * These are for dtype 'kinds', not dtype 'typecodes' + * as the above are for. + */ + NPY_GENBOOLLTR ='b', + NPY_SIGNEDLTR = 'i', + NPY_UNSIGNEDLTR = 'u', + NPY_FLOATINGLTR = 'f', + NPY_COMPLEXLTR = 'c' +}; + +typedef enum { + NPY_QUICKSORT=0, + NPY_HEAPSORT=1, + NPY_MERGESORT=2 +} NPY_SORTKIND; +#define NPY_NSORTS (NPY_MERGESORT + 1) + + +typedef enum { + NPY_INTROSELECT=0 +} NPY_SELECTKIND; +#define NPY_NSELECTS (NPY_INTROSELECT + 1) + + +typedef enum { + NPY_SEARCHLEFT=0, + NPY_SEARCHRIGHT=1 +} NPY_SEARCHSIDE; +#define NPY_NSEARCHSIDES (NPY_SEARCHRIGHT + 1) + + +typedef enum { + NPY_NOSCALAR=-1, + NPY_BOOL_SCALAR, + NPY_INTPOS_SCALAR, + NPY_INTNEG_SCALAR, + NPY_FLOAT_SCALAR, + NPY_COMPLEX_SCALAR, + NPY_OBJECT_SCALAR +} NPY_SCALARKIND; +#define NPY_NSCALARKINDS (NPY_OBJECT_SCALAR + 1) + +/* For specifying array memory layout or iteration order */ +typedef enum { + /* Fortran order if inputs are all Fortran, C otherwise */ + NPY_ANYORDER=-1, + /* C order */ + NPY_CORDER=0, + /* Fortran order */ + NPY_FORTRANORDER=1, + /* An order as close to the inputs as possible */ + NPY_KEEPORDER=2 +} NPY_ORDER; + +/* For specifying allowed casting in operations which support it */ +typedef enum { + /* Only allow identical types */ + NPY_NO_CASTING=0, + /* Allow identical and byte swapped types */ + NPY_EQUIV_CASTING=1, + /* Only allow safe casts */ + NPY_SAFE_CASTING=2, + /* Allow safe casts or casts within the same kind */ + NPY_SAME_KIND_CASTING=3, + /* Allow any casts */ + NPY_UNSAFE_CASTING=4 +} NPY_CASTING; + +typedef enum { + NPY_CLIP=0, + NPY_WRAP=1, + NPY_RAISE=2 +} NPY_CLIPMODE; + +/* The special not-a-time (NaT) value */ +#define NPY_DATETIME_NAT NPY_MIN_INT64 + +/* + * Upper bound on the length of a DATETIME ISO 8601 string + * YEAR: 21 (64-bit year) + * MONTH: 3 + * DAY: 3 + * HOURS: 3 + * MINUTES: 3 + * SECONDS: 3 + * ATTOSECONDS: 1 + 3*6 + * TIMEZONE: 5 + * NULL TERMINATOR: 1 + */ +#define NPY_DATETIME_MAX_ISO8601_STRLEN (21+3*5+1+3*6+6+1) + +typedef enum { + NPY_FR_Y = 0, /* Years */ + NPY_FR_M = 1, /* Months */ + NPY_FR_W = 2, /* Weeks */ + /* Gap where 1.6 NPY_FR_B (value 3) was */ + NPY_FR_D = 4, /* Days */ + NPY_FR_h = 5, /* hours */ + NPY_FR_m = 6, /* minutes */ + NPY_FR_s = 7, /* seconds */ + NPY_FR_ms = 8, /* milliseconds */ + NPY_FR_us = 9, /* microseconds */ + NPY_FR_ns = 10,/* nanoseconds */ + NPY_FR_ps = 11,/* picoseconds */ + NPY_FR_fs = 12,/* femtoseconds */ + NPY_FR_as = 13,/* attoseconds */ + NPY_FR_GENERIC = 14 /* Generic, unbound units, can convert to anything */ +} NPY_DATETIMEUNIT; + +/* + * NOTE: With the NPY_FR_B gap for 1.6 ABI compatibility, NPY_DATETIME_NUMUNITS + * is technically one more than the actual number of units. + */ +#define NPY_DATETIME_NUMUNITS (NPY_FR_GENERIC + 1) +#define NPY_DATETIME_DEFAULTUNIT NPY_FR_GENERIC + +/* + * Business day conventions for mapping invalid business + * days to valid business days. + */ +typedef enum { + /* Go forward in time to the following business day. */ + NPY_BUSDAY_FORWARD, + NPY_BUSDAY_FOLLOWING = NPY_BUSDAY_FORWARD, + /* Go backward in time to the preceding business day. */ + NPY_BUSDAY_BACKWARD, + NPY_BUSDAY_PRECEDING = NPY_BUSDAY_BACKWARD, + /* + * Go forward in time to the following business day, unless it + * crosses a month boundary, in which case go backward + */ + NPY_BUSDAY_MODIFIEDFOLLOWING, + /* + * Go backward in time to the preceding business day, unless it + * crosses a month boundary, in which case go forward. + */ + NPY_BUSDAY_MODIFIEDPRECEDING, + /* Produce a NaT for non-business days. */ + NPY_BUSDAY_NAT, + /* Raise an exception for non-business days. */ + NPY_BUSDAY_RAISE +} NPY_BUSDAY_ROLL; + +/************************************************************ + * NumPy Auxiliary Data for inner loops, sort functions, etc. + ************************************************************/ + +/* + * When creating an auxiliary data struct, this should always appear + * as the first member, like this: + * + * typedef struct { + * NpyAuxData base; + * double constant; + * } constant_multiplier_aux_data; + */ +typedef struct NpyAuxData_tag NpyAuxData; + +/* Function pointers for freeing or cloning auxiliary data */ +typedef void (NpyAuxData_FreeFunc) (NpyAuxData *); +typedef NpyAuxData *(NpyAuxData_CloneFunc) (NpyAuxData *); + +struct NpyAuxData_tag { + NpyAuxData_FreeFunc *free; + NpyAuxData_CloneFunc *clone; + /* To allow for a bit of expansion without breaking the ABI */ + void *reserved[2]; +}; + +/* Macros to use for freeing and cloning auxiliary data */ +#define NPY_AUXDATA_FREE(auxdata) \ + do { \ + if ((auxdata) != NULL) { \ + (auxdata)->free(auxdata); \ + } \ + } while(0) +#define NPY_AUXDATA_CLONE(auxdata) \ + ((auxdata)->clone(auxdata)) + +#define NPY_ERR(str) fprintf(stderr, #str); fflush(stderr); +#define NPY_ERR2(str) fprintf(stderr, str); fflush(stderr); + +#define NPY_STRINGIFY(x) #x +#define NPY_TOSTRING(x) NPY_STRINGIFY(x) + + /* + * Macros to define how array, and dimension/strides data is + * allocated. + */ + + /* Data buffer - PyDataMem_NEW/FREE/RENEW are in multiarraymodule.c */ + +#define NPY_USE_PYMEM 1 + +#if NPY_USE_PYMEM == 1 + /* numpy sometimes calls PyArray_malloc() with the GIL released. On Python + 3.3 and older, it was safe to call PyMem_Malloc() with the GIL released. + On Python 3.4 and newer, it's better to use PyMem_RawMalloc() to be able + to use tracemalloc. On Python 3.6, calling PyMem_Malloc() with the GIL + released is now a fatal error in debug mode. */ +# if PY_VERSION_HEX >= 0x03040000 +# define PyArray_malloc PyMem_RawMalloc +# define PyArray_free PyMem_RawFree +# define PyArray_realloc PyMem_RawRealloc +# else +# define PyArray_malloc PyMem_Malloc +# define PyArray_free PyMem_Free +# define PyArray_realloc PyMem_Realloc +# endif +#else +#define PyArray_malloc malloc +#define PyArray_free free +#define PyArray_realloc realloc +#endif + +/* Dimensions and strides */ +#define PyDimMem_NEW(size) \ + ((npy_intp *)PyArray_malloc(size*sizeof(npy_intp))) + +#define PyDimMem_FREE(ptr) PyArray_free(ptr) + +#define PyDimMem_RENEW(ptr,size) \ + ((npy_intp *)PyArray_realloc(ptr,size*sizeof(npy_intp))) + +/* forward declaration */ +struct _PyArray_Descr; + +/* These must deal with unaligned and swapped data if necessary */ +typedef PyObject * (PyArray_GetItemFunc) (void *, void *); +typedef int (PyArray_SetItemFunc)(PyObject *, void *, void *); + +typedef void (PyArray_CopySwapNFunc)(void *, npy_intp, void *, npy_intp, + npy_intp, int, void *); + +typedef void (PyArray_CopySwapFunc)(void *, void *, int, void *); +typedef npy_bool (PyArray_NonzeroFunc)(void *, void *); + + +/* + * These assume aligned and notswapped data -- a buffer will be used + * before or contiguous data will be obtained + */ + +typedef int (PyArray_CompareFunc)(const void *, const void *, void *); +typedef int (PyArray_ArgFunc)(void*, npy_intp, npy_intp*, void *); + +typedef void (PyArray_DotFunc)(void *, npy_intp, void *, npy_intp, void *, + npy_intp, void *); + +typedef void (PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *, + void *); + +/* + * XXX the ignore argument should be removed next time the API version + * is bumped. It used to be the separator. + */ +typedef int (PyArray_ScanFunc)(FILE *fp, void *dptr, + char *ignore, struct _PyArray_Descr *); +typedef int (PyArray_FromStrFunc)(char *s, void *dptr, char **endptr, + struct _PyArray_Descr *); + +typedef int (PyArray_FillFunc)(void *, npy_intp, void *); + +typedef int (PyArray_SortFunc)(void *, npy_intp, void *); +typedef int (PyArray_ArgSortFunc)(void *, npy_intp *, npy_intp, void *); +typedef int (PyArray_PartitionFunc)(void *, npy_intp, npy_intp, + npy_intp *, npy_intp *, + void *); +typedef int (PyArray_ArgPartitionFunc)(void *, npy_intp *, npy_intp, npy_intp, + npy_intp *, npy_intp *, + void *); + +typedef int (PyArray_FillWithScalarFunc)(void *, npy_intp, void *, void *); + +typedef int (PyArray_ScalarKindFunc)(void *); + +typedef void (PyArray_FastClipFunc)(void *in, npy_intp n_in, void *min, + void *max, void *out); +typedef void (PyArray_FastPutmaskFunc)(void *in, void *mask, npy_intp n_in, + void *values, npy_intp nv); +typedef int (PyArray_FastTakeFunc)(void *dest, void *src, npy_intp *indarray, + npy_intp nindarray, npy_intp n_outer, + npy_intp m_middle, npy_intp nelem, + NPY_CLIPMODE clipmode); + +typedef struct { + npy_intp *ptr; + int len; +} PyArray_Dims; + +typedef struct { + /* + * Functions to cast to most other standard types + * Can have some NULL entries. The types + * DATETIME, TIMEDELTA, and HALF go into the castdict + * even though they are built-in. + */ + PyArray_VectorUnaryFunc *cast[NPY_NTYPES_ABI_COMPATIBLE]; + + /* The next four functions *cannot* be NULL */ + + /* + * Functions to get and set items with standard Python types + * -- not array scalars + */ + PyArray_GetItemFunc *getitem; + PyArray_SetItemFunc *setitem; + + /* + * Copy and/or swap data. Memory areas may not overlap + * Use memmove first if they might + */ + PyArray_CopySwapNFunc *copyswapn; + PyArray_CopySwapFunc *copyswap; + + /* + * Function to compare items + * Can be NULL + */ + PyArray_CompareFunc *compare; + + /* + * Function to select largest + * Can be NULL + */ + PyArray_ArgFunc *argmax; + + /* + * Function to compute dot product + * Can be NULL + */ + PyArray_DotFunc *dotfunc; + + /* + * Function to scan an ASCII file and + * place a single value plus possible separator + * Can be NULL + */ + PyArray_ScanFunc *scanfunc; + + /* + * Function to read a single value from a string + * and adjust the pointer; Can be NULL + */ + PyArray_FromStrFunc *fromstr; + + /* + * Function to determine if data is zero or not + * If NULL a default version is + * used at Registration time. + */ + PyArray_NonzeroFunc *nonzero; + + /* + * Used for arange. + * Can be NULL. + */ + PyArray_FillFunc *fill; + + /* + * Function to fill arrays with scalar values + * Can be NULL + */ + PyArray_FillWithScalarFunc *fillwithscalar; + + /* + * Sorting functions + * Can be NULL + */ + PyArray_SortFunc *sort[NPY_NSORTS]; + PyArray_ArgSortFunc *argsort[NPY_NSORTS]; + + /* + * Dictionary of additional casting functions + * PyArray_VectorUnaryFuncs + * which can be populated to support casting + * to other registered types. Can be NULL + */ + PyObject *castdict; + + /* + * Functions useful for generalizing + * the casting rules. + * Can be NULL; + */ + PyArray_ScalarKindFunc *scalarkind; + int **cancastscalarkindto; + int *cancastto; + + PyArray_FastClipFunc *fastclip; + PyArray_FastPutmaskFunc *fastputmask; + PyArray_FastTakeFunc *fasttake; + + /* + * Function to select smallest + * Can be NULL + */ + PyArray_ArgFunc *argmin; + +} PyArray_ArrFuncs; + +/* The item must be reference counted when it is inserted or extracted. */ +#define NPY_ITEM_REFCOUNT 0x01 +/* Same as needing REFCOUNT */ +#define NPY_ITEM_HASOBJECT 0x01 +/* Convert to list for pickling */ +#define NPY_LIST_PICKLE 0x02 +/* The item is a POINTER */ +#define NPY_ITEM_IS_POINTER 0x04 +/* memory needs to be initialized for this data-type */ +#define NPY_NEEDS_INIT 0x08 +/* operations need Python C-API so don't give-up thread. */ +#define NPY_NEEDS_PYAPI 0x10 +/* Use f.getitem when extracting elements of this data-type */ +#define NPY_USE_GETITEM 0x20 +/* Use f.setitem when setting creating 0-d array from this data-type.*/ +#define NPY_USE_SETITEM 0x40 +/* A sticky flag specifically for structured arrays */ +#define NPY_ALIGNED_STRUCT 0x80 + +/* + *These are inherited for global data-type if any data-types in the + * field have them + */ +#define NPY_FROM_FIELDS (NPY_NEEDS_INIT | NPY_LIST_PICKLE | \ + NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI) + +#define NPY_OBJECT_DTYPE_FLAGS (NPY_LIST_PICKLE | NPY_USE_GETITEM | \ + NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | \ + NPY_NEEDS_INIT | NPY_NEEDS_PYAPI) + +#define PyDataType_FLAGCHK(dtype, flag) \ + (((dtype)->flags & (flag)) == (flag)) + +#define PyDataType_REFCHK(dtype) \ + PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT) + +typedef struct _PyArray_Descr { + PyObject_HEAD + /* + * the type object representing an + * instance of this type -- should not + * be two type_numbers with the same type + * object. + */ + PyTypeObject *typeobj; + /* kind for this type */ + char kind; + /* unique-character representing this type */ + char type; + /* + * '>' (big), '<' (little), '|' + * (not-applicable), or '=' (native). + */ + char byteorder; + /* flags describing data type */ + char flags; + /* number representing this type */ + int type_num; + /* element size (itemsize) for this type */ + int elsize; + /* alignment needed for this type */ + int alignment; + /* + * Non-NULL if this type is + * is an array (C-contiguous) + * of some other type + */ + struct _arr_descr *subarray; + /* + * The fields dictionary for this type + * For statically defined descr this + * is always Py_None + */ + PyObject *fields; + /* + * An ordered tuple of field names or NULL + * if no fields are defined + */ + PyObject *names; + /* + * a table of functions specific for each + * basic data descriptor + */ + PyArray_ArrFuncs *f; + /* Metadata about this dtype */ + PyObject *metadata; + /* + * Metadata specific to the C implementation + * of the particular dtype. This was added + * for NumPy 1.7.0. + */ + NpyAuxData *c_metadata; + /* Cached hash value (-1 if not yet computed). + * This was added for NumPy 2.0.0. + */ + npy_hash_t hash; +} PyArray_Descr; + +typedef struct _arr_descr { + PyArray_Descr *base; + PyObject *shape; /* a tuple */ +} PyArray_ArrayDescr; + +/* + * The main array object structure. + * + * It has been recommended to use the inline functions defined below + * (PyArray_DATA and friends) to access fields here for a number of + * releases. Direct access to the members themselves is deprecated. + * To ensure that your code does not use deprecated access, + * #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION + * (or NPY_1_8_API_VERSION or higher as required). + */ +/* This struct will be moved to a private header in a future release */ +typedef struct tagPyArrayObject_fields { + PyObject_HEAD + /* Pointer to the raw data buffer */ + char *data; + /* The number of dimensions, also called 'ndim' */ + int nd; + /* The size in each dimension, also called 'shape' */ + npy_intp *dimensions; + /* + * Number of bytes to jump to get to the + * next element in each dimension + */ + npy_intp *strides; + /* + * This object is decref'd upon + * deletion of array. Except in the + * case of WRITEBACKIFCOPY which has + * special handling. + * + * For views it points to the original + * array, collapsed so no chains of + * views occur. + * + * For creation from buffer object it + * points to an object that should be + * decref'd on deletion + * + * For WRITEBACKIFCOPY flag this is an + * array to-be-updated upon calling + * PyArray_ResolveWritebackIfCopy + */ + PyObject *base; + /* Pointer to type structure */ + PyArray_Descr *descr; + /* Flags describing array -- see below */ + int flags; + /* For weak references */ + PyObject *weakreflist; +} PyArrayObject_fields; + +/* + * To hide the implementation details, we only expose + * the Python struct HEAD. + */ +#if !defined(NPY_NO_DEPRECATED_API) || \ + (NPY_NO_DEPRECATED_API < NPY_1_7_API_VERSION) +/* + * Can't put this in npy_deprecated_api.h like the others. + * PyArrayObject field access is deprecated as of NumPy 1.7. + */ +typedef PyArrayObject_fields PyArrayObject; +#else +typedef struct tagPyArrayObject { + PyObject_HEAD +} PyArrayObject; +#endif + +#define NPY_SIZEOF_PYARRAYOBJECT (sizeof(PyArrayObject_fields)) + +/* Array Flags Object */ +typedef struct PyArrayFlagsObject { + PyObject_HEAD + PyObject *arr; + int flags; +} PyArrayFlagsObject; + +/* Mirrors buffer object to ptr */ + +typedef struct { + PyObject_HEAD + PyObject *base; + void *ptr; + npy_intp len; + int flags; +} PyArray_Chunk; + +typedef struct { + NPY_DATETIMEUNIT base; + int num; +} PyArray_DatetimeMetaData; + +typedef struct { + NpyAuxData base; + PyArray_DatetimeMetaData meta; +} PyArray_DatetimeDTypeMetaData; + +/* + * This structure contains an exploded view of a date-time value. + * NaT is represented by year == NPY_DATETIME_NAT. + */ +typedef struct { + npy_int64 year; + npy_int32 month, day, hour, min, sec, us, ps, as; +} npy_datetimestruct; + +/* This is not used internally. */ +typedef struct { + npy_int64 day; + npy_int32 sec, us, ps, as; +} npy_timedeltastruct; + +typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *); + +/* + * Means c-style contiguous (last index varies the fastest). The data + * elements right after each other. + * + * This flag may be requested in constructor functions. + * This flag may be tested for in PyArray_FLAGS(arr). + */ +#define NPY_ARRAY_C_CONTIGUOUS 0x0001 + +/* + * Set if array is a contiguous Fortran array: the first index varies + * the fastest in memory (strides array is reverse of C-contiguous + * array) + * + * This flag may be requested in constructor functions. + * This flag may be tested for in PyArray_FLAGS(arr). + */ +#define NPY_ARRAY_F_CONTIGUOUS 0x0002 + +/* + * Note: all 0-d arrays are C_CONTIGUOUS and F_CONTIGUOUS. If a + * 1-d array is C_CONTIGUOUS it is also F_CONTIGUOUS. Arrays with + * more then one dimension can be C_CONTIGUOUS and F_CONTIGUOUS + * at the same time if they have either zero or one element. + * If NPY_RELAXED_STRIDES_CHECKING is set, a higher dimensional + * array is always C_CONTIGUOUS and F_CONTIGUOUS if it has zero elements + * and the array is contiguous if ndarray.squeeze() is contiguous. + * I.e. dimensions for which `ndarray.shape[dimension] == 1` are + * ignored. + */ + +/* + * If set, the array owns the data: it will be free'd when the array + * is deleted. + * + * This flag may be tested for in PyArray_FLAGS(arr). + */ +#define NPY_ARRAY_OWNDATA 0x0004 + +/* + * An array never has the next four set; they're only used as parameter + * flags to the various FromAny functions + * + * This flag may be requested in constructor functions. + */ + +/* Cause a cast to occur regardless of whether or not it is safe. */ +#define NPY_ARRAY_FORCECAST 0x0010 + +/* + * Always copy the array. Returned arrays are always CONTIGUOUS, + * ALIGNED, and WRITEABLE. + * + * This flag may be requested in constructor functions. + */ +#define NPY_ARRAY_ENSURECOPY 0x0020 + +/* + * Make sure the returned array is a base-class ndarray + * + * This flag may be requested in constructor functions. + */ +#define NPY_ARRAY_ENSUREARRAY 0x0040 + +/* + * Make sure that the strides are in units of the element size Needed + * for some operations with record-arrays. + * + * This flag may be requested in constructor functions. + */ +#define NPY_ARRAY_ELEMENTSTRIDES 0x0080 + +/* + * Array data is aligned on the appropriate memory address for the type + * stored according to how the compiler would align things (e.g., an + * array of integers (4 bytes each) starts on a memory address that's + * a multiple of 4) + * + * This flag may be requested in constructor functions. + * This flag may be tested for in PyArray_FLAGS(arr). + */ +#define NPY_ARRAY_ALIGNED 0x0100 + +/* + * Array data has the native endianness + * + * This flag may be requested in constructor functions. + */ +#define NPY_ARRAY_NOTSWAPPED 0x0200 + +/* + * Array data is writeable + * + * This flag may be requested in constructor functions. + * This flag may be tested for in PyArray_FLAGS(arr). + */ +#define NPY_ARRAY_WRITEABLE 0x0400 + +/* + * If this flag is set, then base contains a pointer to an array of + * the same size that should be updated with the current contents of + * this array when PyArray_ResolveWritebackIfCopy is called. + * + * This flag may be requested in constructor functions. + * This flag may be tested for in PyArray_FLAGS(arr). + */ +#define NPY_ARRAY_UPDATEIFCOPY 0x1000 /* Deprecated in 1.14 */ +#define NPY_ARRAY_WRITEBACKIFCOPY 0x2000 + +/* + * NOTE: there are also internal flags defined in multiarray/arrayobject.h, + * which start at bit 31 and work down. + */ + +#define NPY_ARRAY_BEHAVED (NPY_ARRAY_ALIGNED | \ + NPY_ARRAY_WRITEABLE) +#define NPY_ARRAY_BEHAVED_NS (NPY_ARRAY_ALIGNED | \ + NPY_ARRAY_WRITEABLE | \ + NPY_ARRAY_NOTSWAPPED) +#define NPY_ARRAY_CARRAY (NPY_ARRAY_C_CONTIGUOUS | \ + NPY_ARRAY_BEHAVED) +#define NPY_ARRAY_CARRAY_RO (NPY_ARRAY_C_CONTIGUOUS | \ + NPY_ARRAY_ALIGNED) +#define NPY_ARRAY_FARRAY (NPY_ARRAY_F_CONTIGUOUS | \ + NPY_ARRAY_BEHAVED) +#define NPY_ARRAY_FARRAY_RO (NPY_ARRAY_F_CONTIGUOUS | \ + NPY_ARRAY_ALIGNED) +#define NPY_ARRAY_DEFAULT (NPY_ARRAY_CARRAY) +#define NPY_ARRAY_IN_ARRAY (NPY_ARRAY_CARRAY_RO) +#define NPY_ARRAY_OUT_ARRAY (NPY_ARRAY_CARRAY) +#define NPY_ARRAY_INOUT_ARRAY (NPY_ARRAY_CARRAY | \ + NPY_ARRAY_UPDATEIFCOPY) +#define NPY_ARRAY_INOUT_ARRAY2 (NPY_ARRAY_CARRAY | \ + NPY_ARRAY_WRITEBACKIFCOPY) +#define NPY_ARRAY_IN_FARRAY (NPY_ARRAY_FARRAY_RO) +#define NPY_ARRAY_OUT_FARRAY (NPY_ARRAY_FARRAY) +#define NPY_ARRAY_INOUT_FARRAY (NPY_ARRAY_FARRAY | \ + NPY_ARRAY_UPDATEIFCOPY) +#define NPY_ARRAY_INOUT_FARRAY2 (NPY_ARRAY_FARRAY | \ + NPY_ARRAY_WRITEBACKIFCOPY) + +#define NPY_ARRAY_UPDATE_ALL (NPY_ARRAY_C_CONTIGUOUS | \ + NPY_ARRAY_F_CONTIGUOUS | \ + NPY_ARRAY_ALIGNED) + +/* This flag is for the array interface, not PyArrayObject */ +#define NPY_ARR_HAS_DESCR 0x0800 + + + + +/* + * Size of internal buffers used for alignment Make BUFSIZE a multiple + * of sizeof(npy_cdouble) -- usually 16 so that ufunc buffers are aligned + */ +#define NPY_MIN_BUFSIZE ((int)sizeof(npy_cdouble)) +#define NPY_MAX_BUFSIZE (((int)sizeof(npy_cdouble))*1000000) +#define NPY_BUFSIZE 8192 +/* buffer stress test size: */ +/*#define NPY_BUFSIZE 17*/ + +#define PyArray_MAX(a,b) (((a)>(b))?(a):(b)) +#define PyArray_MIN(a,b) (((a)<(b))?(a):(b)) +#define PyArray_CLT(p,q) ((((p).real==(q).real) ? ((p).imag < (q).imag) : \ + ((p).real < (q).real))) +#define PyArray_CGT(p,q) ((((p).real==(q).real) ? ((p).imag > (q).imag) : \ + ((p).real > (q).real))) +#define PyArray_CLE(p,q) ((((p).real==(q).real) ? ((p).imag <= (q).imag) : \ + ((p).real <= (q).real))) +#define PyArray_CGE(p,q) ((((p).real==(q).real) ? ((p).imag >= (q).imag) : \ + ((p).real >= (q).real))) +#define PyArray_CEQ(p,q) (((p).real==(q).real) && ((p).imag == (q).imag)) +#define PyArray_CNE(p,q) (((p).real!=(q).real) || ((p).imag != (q).imag)) + +/* + * C API: consists of Macros and functions. The MACROS are defined + * here. + */ + + +#define PyArray_ISCONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS) +#define PyArray_ISWRITEABLE(m) PyArray_CHKFLAGS(m, NPY_ARRAY_WRITEABLE) +#define PyArray_ISALIGNED(m) PyArray_CHKFLAGS(m, NPY_ARRAY_ALIGNED) + +#define PyArray_IS_C_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS) +#define PyArray_IS_F_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS) + +/* the variable is used in some places, so always define it */ +#define NPY_BEGIN_THREADS_DEF PyThreadState *_save=NULL; +#if NPY_ALLOW_THREADS +#define NPY_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS +#define NPY_END_ALLOW_THREADS Py_END_ALLOW_THREADS +#define NPY_BEGIN_THREADS do {_save = PyEval_SaveThread();} while (0); +#define NPY_END_THREADS do { if (_save) \ + { PyEval_RestoreThread(_save); _save = NULL;} } while (0); +#define NPY_BEGIN_THREADS_THRESHOLDED(loop_size) do { if (loop_size > 500) \ + { _save = PyEval_SaveThread();} } while (0); + +#define NPY_BEGIN_THREADS_DESCR(dtype) \ + do {if (!(PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI))) \ + NPY_BEGIN_THREADS;} while (0); + +#define NPY_END_THREADS_DESCR(dtype) \ + do {if (!(PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI))) \ + NPY_END_THREADS; } while (0); + +#define NPY_ALLOW_C_API_DEF PyGILState_STATE __save__; +#define NPY_ALLOW_C_API do {__save__ = PyGILState_Ensure();} while (0); +#define NPY_DISABLE_C_API do {PyGILState_Release(__save__);} while (0); +#else +#define NPY_BEGIN_ALLOW_THREADS +#define NPY_END_ALLOW_THREADS +#define NPY_BEGIN_THREADS +#define NPY_END_THREADS +#define NPY_BEGIN_THREADS_THRESHOLDED(loop_size) +#define NPY_BEGIN_THREADS_DESCR(dtype) +#define NPY_END_THREADS_DESCR(dtype) +#define NPY_ALLOW_C_API_DEF +#define NPY_ALLOW_C_API +#define NPY_DISABLE_C_API +#endif + +/********************************** + * The nditer object, added in 1.6 + **********************************/ + +/* The actual structure of the iterator is an internal detail */ +typedef struct NpyIter_InternalOnly NpyIter; + +/* Iterator function pointers that may be specialized */ +typedef int (NpyIter_IterNextFunc)(NpyIter *iter); +typedef void (NpyIter_GetMultiIndexFunc)(NpyIter *iter, + npy_intp *outcoords); + +/*** Global flags that may be passed to the iterator constructors ***/ + +/* Track an index representing C order */ +#define NPY_ITER_C_INDEX 0x00000001 +/* Track an index representing Fortran order */ +#define NPY_ITER_F_INDEX 0x00000002 +/* Track a multi-index */ +#define NPY_ITER_MULTI_INDEX 0x00000004 +/* User code external to the iterator does the 1-dimensional innermost loop */ +#define NPY_ITER_EXTERNAL_LOOP 0x00000008 +/* Convert all the operands to a common data type */ +#define NPY_ITER_COMMON_DTYPE 0x00000010 +/* Operands may hold references, requiring API access during iteration */ +#define NPY_ITER_REFS_OK 0x00000020 +/* Zero-sized operands should be permitted, iteration checks IterSize for 0 */ +#define NPY_ITER_ZEROSIZE_OK 0x00000040 +/* Permits reductions (size-0 stride with dimension size > 1) */ +#define NPY_ITER_REDUCE_OK 0x00000080 +/* Enables sub-range iteration */ +#define NPY_ITER_RANGED 0x00000100 +/* Enables buffering */ +#define NPY_ITER_BUFFERED 0x00000200 +/* When buffering is enabled, grows the inner loop if possible */ +#define NPY_ITER_GROWINNER 0x00000400 +/* Delay allocation of buffers until first Reset* call */ +#define NPY_ITER_DELAY_BUFALLOC 0x00000800 +/* When NPY_KEEPORDER is specified, disable reversing negative-stride axes */ +#define NPY_ITER_DONT_NEGATE_STRIDES 0x00001000 +/* + * If output operands overlap with other operands (based on heuristics that + * has false positives but no false negatives), make temporary copies to + * eliminate overlap. + */ +#define NPY_ITER_COPY_IF_OVERLAP 0x00002000 + +/*** Per-operand flags that may be passed to the iterator constructors ***/ + +/* The operand will be read from and written to */ +#define NPY_ITER_READWRITE 0x00010000 +/* The operand will only be read from */ +#define NPY_ITER_READONLY 0x00020000 +/* The operand will only be written to */ +#define NPY_ITER_WRITEONLY 0x00040000 +/* The operand's data must be in native byte order */ +#define NPY_ITER_NBO 0x00080000 +/* The operand's data must be aligned */ +#define NPY_ITER_ALIGNED 0x00100000 +/* The operand's data must be contiguous (within the inner loop) */ +#define NPY_ITER_CONTIG 0x00200000 +/* The operand may be copied to satisfy requirements */ +#define NPY_ITER_COPY 0x00400000 +/* The operand may be copied with WRITEBACKIFCOPY to satisfy requirements */ +#define NPY_ITER_UPDATEIFCOPY 0x00800000 +/* Allocate the operand if it is NULL */ +#define NPY_ITER_ALLOCATE 0x01000000 +/* If an operand is allocated, don't use any subtype */ +#define NPY_ITER_NO_SUBTYPE 0x02000000 +/* This is a virtual array slot, operand is NULL but temporary data is there */ +#define NPY_ITER_VIRTUAL 0x04000000 +/* Require that the dimension match the iterator dimensions exactly */ +#define NPY_ITER_NO_BROADCAST 0x08000000 +/* A mask is being used on this array, affects buffer -> array copy */ +#define NPY_ITER_WRITEMASKED 0x10000000 +/* This array is the mask for all WRITEMASKED operands */ +#define NPY_ITER_ARRAYMASK 0x20000000 +/* Assume iterator order data access for COPY_IF_OVERLAP */ +#define NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE 0x40000000 + +#define NPY_ITER_GLOBAL_FLAGS 0x0000ffff +#define NPY_ITER_PER_OP_FLAGS 0xffff0000 + + +/***************************** + * Basic iterator object + *****************************/ + +/* FWD declaration */ +typedef struct PyArrayIterObject_tag PyArrayIterObject; + +/* + * type of the function which translates a set of coordinates to a + * pointer to the data + */ +typedef char* (*npy_iter_get_dataptr_t)(PyArrayIterObject* iter, npy_intp*); + +struct PyArrayIterObject_tag { + PyObject_HEAD + int nd_m1; /* number of dimensions - 1 */ + npy_intp index, size; + npy_intp coordinates[NPY_MAXDIMS];/* N-dimensional loop */ + npy_intp dims_m1[NPY_MAXDIMS]; /* ao->dimensions - 1 */ + npy_intp strides[NPY_MAXDIMS]; /* ao->strides or fake */ + npy_intp backstrides[NPY_MAXDIMS];/* how far to jump back */ + npy_intp factors[NPY_MAXDIMS]; /* shape factors */ + PyArrayObject *ao; + char *dataptr; /* pointer to current item*/ + npy_bool contiguous; + + npy_intp bounds[NPY_MAXDIMS][2]; + npy_intp limits[NPY_MAXDIMS][2]; + npy_intp limits_sizes[NPY_MAXDIMS]; + npy_iter_get_dataptr_t translate; +} ; + + +/* Iterator API */ +#define PyArrayIter_Check(op) PyObject_TypeCheck(op, &PyArrayIter_Type) + +#define _PyAIT(it) ((PyArrayIterObject *)(it)) +#define PyArray_ITER_RESET(it) do { \ + _PyAIT(it)->index = 0; \ + _PyAIT(it)->dataptr = PyArray_BYTES(_PyAIT(it)->ao); \ + memset(_PyAIT(it)->coordinates, 0, \ + (_PyAIT(it)->nd_m1+1)*sizeof(npy_intp)); \ +} while (0) + +#define _PyArray_ITER_NEXT1(it) do { \ + (it)->dataptr += _PyAIT(it)->strides[0]; \ + (it)->coordinates[0]++; \ +} while (0) + +#define _PyArray_ITER_NEXT2(it) do { \ + if ((it)->coordinates[1] < (it)->dims_m1[1]) { \ + (it)->coordinates[1]++; \ + (it)->dataptr += (it)->strides[1]; \ + } \ + else { \ + (it)->coordinates[1] = 0; \ + (it)->coordinates[0]++; \ + (it)->dataptr += (it)->strides[0] - \ + (it)->backstrides[1]; \ + } \ +} while (0) + +#define PyArray_ITER_NEXT(it) do { \ + _PyAIT(it)->index++; \ + if (_PyAIT(it)->nd_m1 == 0) { \ + _PyArray_ITER_NEXT1(_PyAIT(it)); \ + } \ + else if (_PyAIT(it)->contiguous) \ + _PyAIT(it)->dataptr += PyArray_DESCR(_PyAIT(it)->ao)->elsize; \ + else if (_PyAIT(it)->nd_m1 == 1) { \ + _PyArray_ITER_NEXT2(_PyAIT(it)); \ + } \ + else { \ + int __npy_i; \ + for (__npy_i=_PyAIT(it)->nd_m1; __npy_i >= 0; __npy_i--) { \ + if (_PyAIT(it)->coordinates[__npy_i] < \ + _PyAIT(it)->dims_m1[__npy_i]) { \ + _PyAIT(it)->coordinates[__npy_i]++; \ + _PyAIT(it)->dataptr += \ + _PyAIT(it)->strides[__npy_i]; \ + break; \ + } \ + else { \ + _PyAIT(it)->coordinates[__npy_i] = 0; \ + _PyAIT(it)->dataptr -= \ + _PyAIT(it)->backstrides[__npy_i]; \ + } \ + } \ + } \ +} while (0) + +#define PyArray_ITER_GOTO(it, destination) do { \ + int __npy_i; \ + _PyAIT(it)->index = 0; \ + _PyAIT(it)->dataptr = PyArray_BYTES(_PyAIT(it)->ao); \ + for (__npy_i = _PyAIT(it)->nd_m1; __npy_i>=0; __npy_i--) { \ + if (destination[__npy_i] < 0) { \ + destination[__npy_i] += \ + _PyAIT(it)->dims_m1[__npy_i]+1; \ + } \ + _PyAIT(it)->dataptr += destination[__npy_i] * \ + _PyAIT(it)->strides[__npy_i]; \ + _PyAIT(it)->coordinates[__npy_i] = \ + destination[__npy_i]; \ + _PyAIT(it)->index += destination[__npy_i] * \ + ( __npy_i==_PyAIT(it)->nd_m1 ? 1 : \ + _PyAIT(it)->dims_m1[__npy_i+1]+1) ; \ + } \ +} while (0) + +#define PyArray_ITER_GOTO1D(it, ind) do { \ + int __npy_i; \ + npy_intp __npy_ind = (npy_intp) (ind); \ + if (__npy_ind < 0) __npy_ind += _PyAIT(it)->size; \ + _PyAIT(it)->index = __npy_ind; \ + if (_PyAIT(it)->nd_m1 == 0) { \ + _PyAIT(it)->dataptr = PyArray_BYTES(_PyAIT(it)->ao) + \ + __npy_ind * _PyAIT(it)->strides[0]; \ + } \ + else if (_PyAIT(it)->contiguous) \ + _PyAIT(it)->dataptr = PyArray_BYTES(_PyAIT(it)->ao) + \ + __npy_ind * PyArray_DESCR(_PyAIT(it)->ao)->elsize; \ + else { \ + _PyAIT(it)->dataptr = PyArray_BYTES(_PyAIT(it)->ao); \ + for (__npy_i = 0; __npy_i<=_PyAIT(it)->nd_m1; \ + __npy_i++) { \ + _PyAIT(it)->dataptr += \ + (__npy_ind / _PyAIT(it)->factors[__npy_i]) \ + * _PyAIT(it)->strides[__npy_i]; \ + __npy_ind %= _PyAIT(it)->factors[__npy_i]; \ + } \ + } \ +} while (0) + +#define PyArray_ITER_DATA(it) ((void *)(_PyAIT(it)->dataptr)) + +#define PyArray_ITER_NOTDONE(it) (_PyAIT(it)->index < _PyAIT(it)->size) + + +/* + * Any object passed to PyArray_Broadcast must be binary compatible + * with this structure. + */ + +typedef struct { + PyObject_HEAD + int numiter; /* number of iters */ + npy_intp size; /* broadcasted size */ + npy_intp index; /* current index */ + int nd; /* number of dims */ + npy_intp dimensions[NPY_MAXDIMS]; /* dimensions */ + PyArrayIterObject *iters[NPY_MAXARGS]; /* iterators */ +} PyArrayMultiIterObject; + +#define _PyMIT(m) ((PyArrayMultiIterObject *)(m)) +#define PyArray_MultiIter_RESET(multi) do { \ + int __npy_mi; \ + _PyMIT(multi)->index = 0; \ + for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter; __npy_mi++) { \ + PyArray_ITER_RESET(_PyMIT(multi)->iters[__npy_mi]); \ + } \ +} while (0) + +#define PyArray_MultiIter_NEXT(multi) do { \ + int __npy_mi; \ + _PyMIT(multi)->index++; \ + for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter; __npy_mi++) { \ + PyArray_ITER_NEXT(_PyMIT(multi)->iters[__npy_mi]); \ + } \ +} while (0) + +#define PyArray_MultiIter_GOTO(multi, dest) do { \ + int __npy_mi; \ + for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter; __npy_mi++) { \ + PyArray_ITER_GOTO(_PyMIT(multi)->iters[__npy_mi], dest); \ + } \ + _PyMIT(multi)->index = _PyMIT(multi)->iters[0]->index; \ +} while (0) + +#define PyArray_MultiIter_GOTO1D(multi, ind) do { \ + int __npy_mi; \ + for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter; __npy_mi++) { \ + PyArray_ITER_GOTO1D(_PyMIT(multi)->iters[__npy_mi], ind); \ + } \ + _PyMIT(multi)->index = _PyMIT(multi)->iters[0]->index; \ +} while (0) + +#define PyArray_MultiIter_DATA(multi, i) \ + ((void *)(_PyMIT(multi)->iters[i]->dataptr)) + +#define PyArray_MultiIter_NEXTi(multi, i) \ + PyArray_ITER_NEXT(_PyMIT(multi)->iters[i]) + +#define PyArray_MultiIter_NOTDONE(multi) \ + (_PyMIT(multi)->index < _PyMIT(multi)->size) + + +/* + * Store the information needed for fancy-indexing over an array. The + * fields are slightly unordered to keep consec, dataptr and subspace + * where they were originally. + */ +typedef struct { + PyObject_HEAD + /* + * Multi-iterator portion --- needs to be present in this + * order to work with PyArray_Broadcast + */ + + int numiter; /* number of index-array + iterators */ + npy_intp size; /* size of broadcasted + result */ + npy_intp index; /* current index */ + int nd; /* number of dims */ + npy_intp dimensions[NPY_MAXDIMS]; /* dimensions */ + NpyIter *outer; /* index objects + iterator */ + void *unused[NPY_MAXDIMS - 2]; + PyArrayObject *array; + /* Flat iterator for the indexed array. For compatibility solely. */ + PyArrayIterObject *ait; + + /* + * Subspace array. For binary compatibility (was an iterator, + * but only the check for NULL should be used). + */ + PyArrayObject *subspace; + + /* + * if subspace iteration, then this is the array of axes in + * the underlying array represented by the index objects + */ + int iteraxes[NPY_MAXDIMS]; + npy_intp fancy_strides[NPY_MAXDIMS]; + + /* pointer when all fancy indices are 0 */ + char *baseoffset; + + /* + * after binding consec denotes at which axis the fancy axes + * are inserted. + */ + int consec; + char *dataptr; + + int nd_fancy; + npy_intp fancy_dims[NPY_MAXDIMS]; + + /* Whether the iterator (any of the iterators) requires API */ + int needs_api; + + /* + * Extra op information. + */ + PyArrayObject *extra_op; + PyArray_Descr *extra_op_dtype; /* desired dtype */ + npy_uint32 *extra_op_flags; /* Iterator flags */ + + NpyIter *extra_op_iter; + NpyIter_IterNextFunc *extra_op_next; + char **extra_op_ptrs; + + /* + * Information about the iteration state. + */ + NpyIter_IterNextFunc *outer_next; + char **outer_ptrs; + npy_intp *outer_strides; + + /* + * Information about the subspace iterator. + */ + NpyIter *subspace_iter; + NpyIter_IterNextFunc *subspace_next; + char **subspace_ptrs; + npy_intp *subspace_strides; + + /* Count for the external loop (which ever it is) for API iteration */ + npy_intp iter_count; + +} PyArrayMapIterObject; + +enum { + NPY_NEIGHBORHOOD_ITER_ZERO_PADDING, + NPY_NEIGHBORHOOD_ITER_ONE_PADDING, + NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING, + NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING, + NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING +}; + +typedef struct { + PyObject_HEAD + + /* + * PyArrayIterObject part: keep this in this exact order + */ + int nd_m1; /* number of dimensions - 1 */ + npy_intp index, size; + npy_intp coordinates[NPY_MAXDIMS];/* N-dimensional loop */ + npy_intp dims_m1[NPY_MAXDIMS]; /* ao->dimensions - 1 */ + npy_intp strides[NPY_MAXDIMS]; /* ao->strides or fake */ + npy_intp backstrides[NPY_MAXDIMS];/* how far to jump back */ + npy_intp factors[NPY_MAXDIMS]; /* shape factors */ + PyArrayObject *ao; + char *dataptr; /* pointer to current item*/ + npy_bool contiguous; + + npy_intp bounds[NPY_MAXDIMS][2]; + npy_intp limits[NPY_MAXDIMS][2]; + npy_intp limits_sizes[NPY_MAXDIMS]; + npy_iter_get_dataptr_t translate; + + /* + * New members + */ + npy_intp nd; + + /* Dimensions is the dimension of the array */ + npy_intp dimensions[NPY_MAXDIMS]; + + /* + * Neighborhood points coordinates are computed relatively to the + * point pointed by _internal_iter + */ + PyArrayIterObject* _internal_iter; + /* + * To keep a reference to the representation of the constant value + * for constant padding + */ + char* constant; + + int mode; +} PyArrayNeighborhoodIterObject; + +/* + * Neighborhood iterator API + */ + +/* General: those work for any mode */ +static NPY_INLINE int +PyArrayNeighborhoodIter_Reset(PyArrayNeighborhoodIterObject* iter); +static NPY_INLINE int +PyArrayNeighborhoodIter_Next(PyArrayNeighborhoodIterObject* iter); +#if 0 +static NPY_INLINE int +PyArrayNeighborhoodIter_Next2D(PyArrayNeighborhoodIterObject* iter); +#endif + +/* + * Include inline implementations - functions defined there are not + * considered public API + */ +#define _NPY_INCLUDE_NEIGHBORHOOD_IMP +#include "_neighborhood_iterator_imp.h" +#undef _NPY_INCLUDE_NEIGHBORHOOD_IMP + +/* The default array type */ +#define NPY_DEFAULT_TYPE NPY_DOUBLE + +/* + * All sorts of useful ways to look into a PyArrayObject. It is recommended + * to use PyArrayObject * objects instead of always casting from PyObject *, + * for improved type checking. + * + * In many cases here the macro versions of the accessors are deprecated, + * but can't be immediately changed to inline functions because the + * preexisting macros accept PyObject * and do automatic casts. Inline + * functions accepting PyArrayObject * provides for some compile-time + * checking of correctness when working with these objects in C. + */ + +#define PyArray_ISONESEGMENT(m) (PyArray_NDIM(m) == 0 || \ + PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS) || \ + PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS)) + +#define PyArray_ISFORTRAN(m) (PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS) && \ + (!PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS))) + +#define PyArray_FORTRAN_IF(m) ((PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS) ? \ + NPY_ARRAY_F_CONTIGUOUS : 0)) + +#if (defined(NPY_NO_DEPRECATED_API) && (NPY_1_7_API_VERSION <= NPY_NO_DEPRECATED_API)) +/* + * Changing access macros into functions, to allow for future hiding + * of the internal memory layout. This later hiding will allow the 2.x series + * to change the internal representation of arrays without affecting + * ABI compatibility. + */ + +static NPY_INLINE int +PyArray_NDIM(const PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->nd; +} + +static NPY_INLINE void * +PyArray_DATA(PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->data; +} + +static NPY_INLINE char * +PyArray_BYTES(PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->data; +} + +static NPY_INLINE npy_intp * +PyArray_DIMS(PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->dimensions; +} + +static NPY_INLINE npy_intp * +PyArray_STRIDES(PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->strides; +} + +static NPY_INLINE npy_intp +PyArray_DIM(const PyArrayObject *arr, int idim) +{ + return ((PyArrayObject_fields *)arr)->dimensions[idim]; +} + +static NPY_INLINE npy_intp +PyArray_STRIDE(const PyArrayObject *arr, int istride) +{ + return ((PyArrayObject_fields *)arr)->strides[istride]; +} + +static NPY_INLINE NPY_RETURNS_BORROWED_REF PyObject * +PyArray_BASE(PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->base; +} + +static NPY_INLINE NPY_RETURNS_BORROWED_REF PyArray_Descr * +PyArray_DESCR(PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->descr; +} + +static NPY_INLINE int +PyArray_FLAGS(const PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->flags; +} + +static NPY_INLINE npy_intp +PyArray_ITEMSIZE(const PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->descr->elsize; +} + +static NPY_INLINE int +PyArray_TYPE(const PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->descr->type_num; +} + +static NPY_INLINE int +PyArray_CHKFLAGS(const PyArrayObject *arr, int flags) +{ + return (PyArray_FLAGS(arr) & flags) == flags; +} + +static NPY_INLINE PyObject * +PyArray_GETITEM(const PyArrayObject *arr, const char *itemptr) +{ + return ((PyArrayObject_fields *)arr)->descr->f->getitem( + (void *)itemptr, (PyArrayObject *)arr); +} + +static NPY_INLINE int +PyArray_SETITEM(PyArrayObject *arr, char *itemptr, PyObject *v) +{ + return ((PyArrayObject_fields *)arr)->descr->f->setitem( + v, itemptr, arr); +} + +#else + +/* These macros are deprecated as of NumPy 1.7. */ +#define PyArray_NDIM(obj) (((PyArrayObject_fields *)(obj))->nd) +#define PyArray_BYTES(obj) (((PyArrayObject_fields *)(obj))->data) +#define PyArray_DATA(obj) ((void *)((PyArrayObject_fields *)(obj))->data) +#define PyArray_DIMS(obj) (((PyArrayObject_fields *)(obj))->dimensions) +#define PyArray_STRIDES(obj) (((PyArrayObject_fields *)(obj))->strides) +#define PyArray_DIM(obj,n) (PyArray_DIMS(obj)[n]) +#define PyArray_STRIDE(obj,n) (PyArray_STRIDES(obj)[n]) +#define PyArray_BASE(obj) (((PyArrayObject_fields *)(obj))->base) +#define PyArray_DESCR(obj) (((PyArrayObject_fields *)(obj))->descr) +#define PyArray_FLAGS(obj) (((PyArrayObject_fields *)(obj))->flags) +#define PyArray_CHKFLAGS(m, FLAGS) \ + ((((PyArrayObject_fields *)(m))->flags & (FLAGS)) == (FLAGS)) +#define PyArray_ITEMSIZE(obj) \ + (((PyArrayObject_fields *)(obj))->descr->elsize) +#define PyArray_TYPE(obj) \ + (((PyArrayObject_fields *)(obj))->descr->type_num) +#define PyArray_GETITEM(obj,itemptr) \ + PyArray_DESCR(obj)->f->getitem((char *)(itemptr), \ + (PyArrayObject *)(obj)) + +#define PyArray_SETITEM(obj,itemptr,v) \ + PyArray_DESCR(obj)->f->setitem((PyObject *)(v), \ + (char *)(itemptr), \ + (PyArrayObject *)(obj)) +#endif + +static NPY_INLINE PyArray_Descr * +PyArray_DTYPE(PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->descr; +} + +static NPY_INLINE npy_intp * +PyArray_SHAPE(PyArrayObject *arr) +{ + return ((PyArrayObject_fields *)arr)->dimensions; +} + +/* + * Enables the specified array flags. Does no checking, + * assumes you know what you're doing. + */ +static NPY_INLINE void +PyArray_ENABLEFLAGS(PyArrayObject *arr, int flags) +{ + ((PyArrayObject_fields *)arr)->flags |= flags; +} + +/* + * Clears the specified array flags. Does no checking, + * assumes you know what you're doing. + */ +static NPY_INLINE void +PyArray_CLEARFLAGS(PyArrayObject *arr, int flags) +{ + ((PyArrayObject_fields *)arr)->flags &= ~flags; +} + +#define PyTypeNum_ISBOOL(type) ((type) == NPY_BOOL) + +#define PyTypeNum_ISUNSIGNED(type) (((type) == NPY_UBYTE) || \ + ((type) == NPY_USHORT) || \ + ((type) == NPY_UINT) || \ + ((type) == NPY_ULONG) || \ + ((type) == NPY_ULONGLONG)) + +#define PyTypeNum_ISSIGNED(type) (((type) == NPY_BYTE) || \ + ((type) == NPY_SHORT) || \ + ((type) == NPY_INT) || \ + ((type) == NPY_LONG) || \ + ((type) == NPY_LONGLONG)) + +#define PyTypeNum_ISINTEGER(type) (((type) >= NPY_BYTE) && \ + ((type) <= NPY_ULONGLONG)) + +#define PyTypeNum_ISFLOAT(type) ((((type) >= NPY_FLOAT) && \ + ((type) <= NPY_LONGDOUBLE)) || \ + ((type) == NPY_HALF)) + +#define PyTypeNum_ISNUMBER(type) (((type) <= NPY_CLONGDOUBLE) || \ + ((type) == NPY_HALF)) + +#define PyTypeNum_ISSTRING(type) (((type) == NPY_STRING) || \ + ((type) == NPY_UNICODE)) + +#define PyTypeNum_ISCOMPLEX(type) (((type) >= NPY_CFLOAT) && \ + ((type) <= NPY_CLONGDOUBLE)) + +#define PyTypeNum_ISPYTHON(type) (((type) == NPY_LONG) || \ + ((type) == NPY_DOUBLE) || \ + ((type) == NPY_CDOUBLE) || \ + ((type) == NPY_BOOL) || \ + ((type) == NPY_OBJECT )) + +#define PyTypeNum_ISFLEXIBLE(type) (((type) >=NPY_STRING) && \ + ((type) <=NPY_VOID)) + +#define PyTypeNum_ISDATETIME(type) (((type) >=NPY_DATETIME) && \ + ((type) <=NPY_TIMEDELTA)) + +#define PyTypeNum_ISUSERDEF(type) (((type) >= NPY_USERDEF) && \ + ((type) < NPY_USERDEF+ \ + NPY_NUMUSERTYPES)) + +#define PyTypeNum_ISEXTENDED(type) (PyTypeNum_ISFLEXIBLE(type) || \ + PyTypeNum_ISUSERDEF(type)) + +#define PyTypeNum_ISOBJECT(type) ((type) == NPY_OBJECT) + + +#define PyDataType_ISBOOL(obj) PyTypeNum_ISBOOL(_PyADt(obj)) +#define PyDataType_ISUNSIGNED(obj) PyTypeNum_ISUNSIGNED(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISSIGNED(obj) PyTypeNum_ISSIGNED(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISINTEGER(obj) PyTypeNum_ISINTEGER(((PyArray_Descr*)(obj))->type_num ) +#define PyDataType_ISFLOAT(obj) PyTypeNum_ISFLOAT(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISNUMBER(obj) PyTypeNum_ISNUMBER(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISSTRING(obj) PyTypeNum_ISSTRING(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISCOMPLEX(obj) PyTypeNum_ISCOMPLEX(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISPYTHON(obj) PyTypeNum_ISPYTHON(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISFLEXIBLE(obj) PyTypeNum_ISFLEXIBLE(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISDATETIME(obj) PyTypeNum_ISDATETIME(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISUSERDEF(obj) PyTypeNum_ISUSERDEF(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISEXTENDED(obj) PyTypeNum_ISEXTENDED(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_ISOBJECT(obj) PyTypeNum_ISOBJECT(((PyArray_Descr*)(obj))->type_num) +#define PyDataType_HASFIELDS(obj) (((PyArray_Descr *)(obj))->names != NULL) +#define PyDataType_HASSUBARRAY(dtype) ((dtype)->subarray != NULL) +#define PyDataType_ISUNSIZED(dtype) ((dtype)->elsize == 0) +#define PyDataType_MAKEUNSIZED(dtype) ((dtype)->elsize = 0) + +#define PyArray_ISBOOL(obj) PyTypeNum_ISBOOL(PyArray_TYPE(obj)) +#define PyArray_ISUNSIGNED(obj) PyTypeNum_ISUNSIGNED(PyArray_TYPE(obj)) +#define PyArray_ISSIGNED(obj) PyTypeNum_ISSIGNED(PyArray_TYPE(obj)) +#define PyArray_ISINTEGER(obj) PyTypeNum_ISINTEGER(PyArray_TYPE(obj)) +#define PyArray_ISFLOAT(obj) PyTypeNum_ISFLOAT(PyArray_TYPE(obj)) +#define PyArray_ISNUMBER(obj) PyTypeNum_ISNUMBER(PyArray_TYPE(obj)) +#define PyArray_ISSTRING(obj) PyTypeNum_ISSTRING(PyArray_TYPE(obj)) +#define PyArray_ISCOMPLEX(obj) PyTypeNum_ISCOMPLEX(PyArray_TYPE(obj)) +#define PyArray_ISPYTHON(obj) PyTypeNum_ISPYTHON(PyArray_TYPE(obj)) +#define PyArray_ISFLEXIBLE(obj) PyTypeNum_ISFLEXIBLE(PyArray_TYPE(obj)) +#define PyArray_ISDATETIME(obj) PyTypeNum_ISDATETIME(PyArray_TYPE(obj)) +#define PyArray_ISUSERDEF(obj) PyTypeNum_ISUSERDEF(PyArray_TYPE(obj)) +#define PyArray_ISEXTENDED(obj) PyTypeNum_ISEXTENDED(PyArray_TYPE(obj)) +#define PyArray_ISOBJECT(obj) PyTypeNum_ISOBJECT(PyArray_TYPE(obj)) +#define PyArray_HASFIELDS(obj) PyDataType_HASFIELDS(PyArray_DESCR(obj)) + + /* + * FIXME: This should check for a flag on the data-type that + * states whether or not it is variable length. Because the + * ISFLEXIBLE check is hard-coded to the built-in data-types. + */ +#define PyArray_ISVARIABLE(obj) PyTypeNum_ISFLEXIBLE(PyArray_TYPE(obj)) + +#define PyArray_SAFEALIGNEDCOPY(obj) (PyArray_ISALIGNED(obj) && !PyArray_ISVARIABLE(obj)) + + +#define NPY_LITTLE '<' +#define NPY_BIG '>' +#define NPY_NATIVE '=' +#define NPY_SWAP 's' +#define NPY_IGNORE '|' + +#if NPY_BYTE_ORDER == NPY_BIG_ENDIAN +#define NPY_NATBYTE NPY_BIG +#define NPY_OPPBYTE NPY_LITTLE +#else +#define NPY_NATBYTE NPY_LITTLE +#define NPY_OPPBYTE NPY_BIG +#endif + +#define PyArray_ISNBO(arg) ((arg) != NPY_OPPBYTE) +#define PyArray_IsNativeByteOrder PyArray_ISNBO +#define PyArray_ISNOTSWAPPED(m) PyArray_ISNBO(PyArray_DESCR(m)->byteorder) +#define PyArray_ISBYTESWAPPED(m) (!PyArray_ISNOTSWAPPED(m)) + +#define PyArray_FLAGSWAP(m, flags) (PyArray_CHKFLAGS(m, flags) && \ + PyArray_ISNOTSWAPPED(m)) + +#define PyArray_ISCARRAY(m) PyArray_FLAGSWAP(m, NPY_ARRAY_CARRAY) +#define PyArray_ISCARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_CARRAY_RO) +#define PyArray_ISFARRAY(m) PyArray_FLAGSWAP(m, NPY_ARRAY_FARRAY) +#define PyArray_ISFARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_FARRAY_RO) +#define PyArray_ISBEHAVED(m) PyArray_FLAGSWAP(m, NPY_ARRAY_BEHAVED) +#define PyArray_ISBEHAVED_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_ALIGNED) + + +#define PyDataType_ISNOTSWAPPED(d) PyArray_ISNBO(((PyArray_Descr *)(d))->byteorder) +#define PyDataType_ISBYTESWAPPED(d) (!PyDataType_ISNOTSWAPPED(d)) + +/************************************************************ + * A struct used by PyArray_CreateSortedStridePerm, new in 1.7. + ************************************************************/ + +typedef struct { + npy_intp perm, stride; +} npy_stride_sort_item; + +/************************************************************ + * This is the form of the struct that's returned pointed by the + * PyCObject attribute of an array __array_struct__. See + * http://docs.scipy.org/doc/numpy/reference/arrays.interface.html for the full + * documentation. + ************************************************************/ +typedef struct { + int two; /* + * contains the integer 2 as a sanity + * check + */ + + int nd; /* number of dimensions */ + + char typekind; /* + * kind in array --- character code of + * typestr + */ + + int itemsize; /* size of each element */ + + int flags; /* + * how should be data interpreted. Valid + * flags are CONTIGUOUS (1), F_CONTIGUOUS (2), + * ALIGNED (0x100), NOTSWAPPED (0x200), and + * WRITEABLE (0x400). ARR_HAS_DESCR (0x800) + * states that arrdescr field is present in + * structure + */ + + npy_intp *shape; /* + * A length-nd array of shape + * information + */ + + npy_intp *strides; /* A length-nd array of stride information */ + + void *data; /* A pointer to the first element of the array */ + + PyObject *descr; /* + * A list of fields or NULL (ignored if flags + * does not have ARR_HAS_DESCR flag set) + */ +} PyArrayInterface; + +/* + * This is a function for hooking into the PyDataMem_NEW/FREE/RENEW functions. + * See the documentation for PyDataMem_SetEventHook. + */ +typedef void (PyDataMem_EventHookFunc)(void *inp, void *outp, size_t size, + void *user_data); + +/* + * Use the keyword NPY_DEPRECATED_INCLUDES to ensure that the header files + * npy_*_*_deprecated_api.h are only included from here and nowhere else. + */ +#ifdef NPY_DEPRECATED_INCLUDES +#error "Do not use the reserved keyword NPY_DEPRECATED_INCLUDES." +#endif +#define NPY_DEPRECATED_INCLUDES +#if !defined(NPY_NO_DEPRECATED_API) || \ + (NPY_NO_DEPRECATED_API < NPY_1_7_API_VERSION) +#include "npy_1_7_deprecated_api.h" +#endif +/* + * There is no file npy_1_8_deprecated_api.h since there are no additional + * deprecated API features in NumPy 1.8. + * + * Note to maintainers: insert code like the following in future NumPy + * versions. + * + * #if !defined(NPY_NO_DEPRECATED_API) || \ + * (NPY_NO_DEPRECATED_API < NPY_1_9_API_VERSION) + * #include "npy_1_9_deprecated_api.h" + * #endif + */ +#undef NPY_DEPRECATED_INCLUDES + +#endif /* NPY_ARRAYTYPES_H */ diff --git a/numpy/core/include/numpy/noprefix.h b/numpy/core/include/numpy/noprefix.h new file mode 100644 index 0000000..041f301 --- /dev/null +++ b/numpy/core/include/numpy/noprefix.h @@ -0,0 +1,212 @@ +#ifndef NPY_NOPREFIX_H +#define NPY_NOPREFIX_H + +/* + * You can directly include noprefix.h as a backward + * compatibility measure + */ +#ifndef NPY_NO_PREFIX +#include "ndarrayobject.h" +#include "npy_interrupt.h" +#endif + +#define SIGSETJMP NPY_SIGSETJMP +#define SIGLONGJMP NPY_SIGLONGJMP +#define SIGJMP_BUF NPY_SIGJMP_BUF + +#define MAX_DIMS NPY_MAXDIMS + +#define longlong npy_longlong +#define ulonglong npy_ulonglong +#define Bool npy_bool +#define longdouble npy_longdouble +#define byte npy_byte + +#ifndef _BSD_SOURCE +#define ushort npy_ushort +#define uint npy_uint +#define ulong npy_ulong +#endif + +#define ubyte npy_ubyte +#define ushort npy_ushort +#define uint npy_uint +#define ulong npy_ulong +#define cfloat npy_cfloat +#define cdouble npy_cdouble +#define clongdouble npy_clongdouble +#define Int8 npy_int8 +#define UInt8 npy_uint8 +#define Int16 npy_int16 +#define UInt16 npy_uint16 +#define Int32 npy_int32 +#define UInt32 npy_uint32 +#define Int64 npy_int64 +#define UInt64 npy_uint64 +#define Int128 npy_int128 +#define UInt128 npy_uint128 +#define Int256 npy_int256 +#define UInt256 npy_uint256 +#define Float16 npy_float16 +#define Complex32 npy_complex32 +#define Float32 npy_float32 +#define Complex64 npy_complex64 +#define Float64 npy_float64 +#define Complex128 npy_complex128 +#define Float80 npy_float80 +#define Complex160 npy_complex160 +#define Float96 npy_float96 +#define Complex192 npy_complex192 +#define Float128 npy_float128 +#define Complex256 npy_complex256 +#define intp npy_intp +#define uintp npy_uintp +#define datetime npy_datetime +#define timedelta npy_timedelta + +#define SIZEOF_LONGLONG NPY_SIZEOF_LONGLONG +#define SIZEOF_INTP NPY_SIZEOF_INTP +#define SIZEOF_UINTP NPY_SIZEOF_UINTP +#define SIZEOF_HALF NPY_SIZEOF_HALF +#define SIZEOF_LONGDOUBLE NPY_SIZEOF_LONGDOUBLE +#define SIZEOF_DATETIME NPY_SIZEOF_DATETIME +#define SIZEOF_TIMEDELTA NPY_SIZEOF_TIMEDELTA + +#define LONGLONG_FMT NPY_LONGLONG_FMT +#define ULONGLONG_FMT NPY_ULONGLONG_FMT +#define LONGLONG_SUFFIX NPY_LONGLONG_SUFFIX +#define ULONGLONG_SUFFIX NPY_ULONGLONG_SUFFIX + +#define MAX_INT8 127 +#define MIN_INT8 -128 +#define MAX_UINT8 255 +#define MAX_INT16 32767 +#define MIN_INT16 -32768 +#define MAX_UINT16 65535 +#define MAX_INT32 2147483647 +#define MIN_INT32 (-MAX_INT32 - 1) +#define MAX_UINT32 4294967295U +#define MAX_INT64 LONGLONG_SUFFIX(9223372036854775807) +#define MIN_INT64 (-MAX_INT64 - LONGLONG_SUFFIX(1)) +#define MAX_UINT64 ULONGLONG_SUFFIX(18446744073709551615) +#define MAX_INT128 LONGLONG_SUFFIX(85070591730234615865843651857942052864) +#define MIN_INT128 (-MAX_INT128 - LONGLONG_SUFFIX(1)) +#define MAX_UINT128 ULONGLONG_SUFFIX(170141183460469231731687303715884105728) +#define MAX_INT256 LONGLONG_SUFFIX(57896044618658097711785492504343953926634992332820282019728792003956564819967) +#define MIN_INT256 (-MAX_INT256 - LONGLONG_SUFFIX(1)) +#define MAX_UINT256 ULONGLONG_SUFFIX(115792089237316195423570985008687907853269984665640564039457584007913129639935) + +#define MAX_BYTE NPY_MAX_BYTE +#define MIN_BYTE NPY_MIN_BYTE +#define MAX_UBYTE NPY_MAX_UBYTE +#define MAX_SHORT NPY_MAX_SHORT +#define MIN_SHORT NPY_MIN_SHORT +#define MAX_USHORT NPY_MAX_USHORT +#define MAX_INT NPY_MAX_INT +#define MIN_INT NPY_MIN_INT +#define MAX_UINT NPY_MAX_UINT +#define MAX_LONG NPY_MAX_LONG +#define MIN_LONG NPY_MIN_LONG +#define MAX_ULONG NPY_MAX_ULONG +#define MAX_LONGLONG NPY_MAX_LONGLONG +#define MIN_LONGLONG NPY_MIN_LONGLONG +#define MAX_ULONGLONG NPY_MAX_ULONGLONG +#define MIN_DATETIME NPY_MIN_DATETIME +#define MAX_DATETIME NPY_MAX_DATETIME +#define MIN_TIMEDELTA NPY_MIN_TIMEDELTA +#define MAX_TIMEDELTA NPY_MAX_TIMEDELTA + +#define BITSOF_BOOL NPY_BITSOF_BOOL +#define BITSOF_CHAR NPY_BITSOF_CHAR +#define BITSOF_SHORT NPY_BITSOF_SHORT +#define BITSOF_INT NPY_BITSOF_INT +#define BITSOF_LONG NPY_BITSOF_LONG +#define BITSOF_LONGLONG NPY_BITSOF_LONGLONG +#define BITSOF_HALF NPY_BITSOF_HALF +#define BITSOF_FLOAT NPY_BITSOF_FLOAT +#define BITSOF_DOUBLE NPY_BITSOF_DOUBLE +#define BITSOF_LONGDOUBLE NPY_BITSOF_LONGDOUBLE +#define BITSOF_DATETIME NPY_BITSOF_DATETIME +#define BITSOF_TIMEDELTA NPY_BITSOF_TIMEDELTA + +#define _pya_malloc PyArray_malloc +#define _pya_free PyArray_free +#define _pya_realloc PyArray_realloc + +#define BEGIN_THREADS_DEF NPY_BEGIN_THREADS_DEF +#define BEGIN_THREADS NPY_BEGIN_THREADS +#define END_THREADS NPY_END_THREADS +#define ALLOW_C_API_DEF NPY_ALLOW_C_API_DEF +#define ALLOW_C_API NPY_ALLOW_C_API +#define DISABLE_C_API NPY_DISABLE_C_API + +#define PY_FAIL NPY_FAIL +#define PY_SUCCEED NPY_SUCCEED + +#ifndef TRUE +#define TRUE NPY_TRUE +#endif + +#ifndef FALSE +#define FALSE NPY_FALSE +#endif + +#define LONGDOUBLE_FMT NPY_LONGDOUBLE_FMT + +#define CONTIGUOUS NPY_CONTIGUOUS +#define C_CONTIGUOUS NPY_C_CONTIGUOUS +#define FORTRAN NPY_FORTRAN +#define F_CONTIGUOUS NPY_F_CONTIGUOUS +#define OWNDATA NPY_OWNDATA +#define FORCECAST NPY_FORCECAST +#define ENSURECOPY NPY_ENSURECOPY +#define ENSUREARRAY NPY_ENSUREARRAY +#define ELEMENTSTRIDES NPY_ELEMENTSTRIDES +#define ALIGNED NPY_ALIGNED +#define NOTSWAPPED NPY_NOTSWAPPED +#define WRITEABLE NPY_WRITEABLE +#define UPDATEIFCOPY NPY_UPDATEIFCOPY +#define WRITEBACKIFCOPY NPY_ARRAY_WRITEBACKIFCOPY +#define ARR_HAS_DESCR NPY_ARR_HAS_DESCR +#define BEHAVED NPY_BEHAVED +#define BEHAVED_NS NPY_BEHAVED_NS +#define CARRAY NPY_CARRAY +#define CARRAY_RO NPY_CARRAY_RO +#define FARRAY NPY_FARRAY +#define FARRAY_RO NPY_FARRAY_RO +#define DEFAULT NPY_DEFAULT +#define IN_ARRAY NPY_IN_ARRAY +#define OUT_ARRAY NPY_OUT_ARRAY +#define INOUT_ARRAY NPY_INOUT_ARRAY +#define IN_FARRAY NPY_IN_FARRAY +#define OUT_FARRAY NPY_OUT_FARRAY +#define INOUT_FARRAY NPY_INOUT_FARRAY +#define UPDATE_ALL NPY_UPDATE_ALL + +#define OWN_DATA NPY_OWNDATA +#define BEHAVED_FLAGS NPY_BEHAVED +#define BEHAVED_FLAGS_NS NPY_BEHAVED_NS +#define CARRAY_FLAGS_RO NPY_CARRAY_RO +#define CARRAY_FLAGS NPY_CARRAY +#define FARRAY_FLAGS NPY_FARRAY +#define FARRAY_FLAGS_RO NPY_FARRAY_RO +#define DEFAULT_FLAGS NPY_DEFAULT +#define UPDATE_ALL_FLAGS NPY_UPDATE_ALL_FLAGS + +#ifndef MIN +#define MIN PyArray_MIN +#endif +#ifndef MAX +#define MAX PyArray_MAX +#endif +#define MAX_INTP NPY_MAX_INTP +#define MIN_INTP NPY_MIN_INTP +#define MAX_UINTP NPY_MAX_UINTP +#define INTP_FMT NPY_INTP_FMT + +#ifndef PYPY_VERSION +#define REFCOUNT PyArray_REFCOUNT +#define MAX_ELSIZE NPY_MAX_ELSIZE +#endif + +#endif diff --git a/numpy/core/include/numpy/npy_1_7_deprecated_api.h b/numpy/core/include/numpy/npy_1_7_deprecated_api.h new file mode 100644 index 0000000..4c318bc --- /dev/null +++ b/numpy/core/include/numpy/npy_1_7_deprecated_api.h @@ -0,0 +1,130 @@ +#ifndef _NPY_1_7_DEPRECATED_API_H +#define _NPY_1_7_DEPRECATED_API_H + +#ifndef NPY_DEPRECATED_INCLUDES +#error "Should never include npy_*_*_deprecated_api directly." +#endif + +#if defined(_WIN32) +#define _WARN___STR2__(x) #x +#define _WARN___STR1__(x) _WARN___STR2__(x) +#define _WARN___LOC__ __FILE__ "(" _WARN___STR1__(__LINE__) ") : Warning Msg: " +#pragma message(_WARN___LOC__"Using deprecated NumPy API, disable it by " \ + "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION") +#elif defined(__GNUC__) +#warning "Using deprecated NumPy API, disable it by " \ + "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" +#endif +/* TODO: How to do this warning message for other compilers? */ + +/* + * This header exists to collect all dangerous/deprecated NumPy API + * as of NumPy 1.7. + * + * This is an attempt to remove bad API, the proliferation of macros, + * and namespace pollution currently produced by the NumPy headers. + */ + +/* These array flags are deprecated as of NumPy 1.7 */ +#define NPY_CONTIGUOUS NPY_ARRAY_C_CONTIGUOUS +#define NPY_FORTRAN NPY_ARRAY_F_CONTIGUOUS + +/* + * The consistent NPY_ARRAY_* names which don't pollute the NPY_* + * namespace were added in NumPy 1.7. + * + * These versions of the carray flags are deprecated, but + * probably should only be removed after two releases instead of one. + */ +#define NPY_C_CONTIGUOUS NPY_ARRAY_C_CONTIGUOUS +#define NPY_F_CONTIGUOUS NPY_ARRAY_F_CONTIGUOUS +#define NPY_OWNDATA NPY_ARRAY_OWNDATA +#define NPY_FORCECAST NPY_ARRAY_FORCECAST +#define NPY_ENSURECOPY NPY_ARRAY_ENSURECOPY +#define NPY_ENSUREARRAY NPY_ARRAY_ENSUREARRAY +#define NPY_ELEMENTSTRIDES NPY_ARRAY_ELEMENTSTRIDES +#define NPY_ALIGNED NPY_ARRAY_ALIGNED +#define NPY_NOTSWAPPED NPY_ARRAY_NOTSWAPPED +#define NPY_WRITEABLE NPY_ARRAY_WRITEABLE +#define NPY_UPDATEIFCOPY NPY_ARRAY_UPDATEIFCOPY +#define NPY_BEHAVED NPY_ARRAY_BEHAVED +#define NPY_BEHAVED_NS NPY_ARRAY_BEHAVED_NS +#define NPY_CARRAY NPY_ARRAY_CARRAY +#define NPY_CARRAY_RO NPY_ARRAY_CARRAY_RO +#define NPY_FARRAY NPY_ARRAY_FARRAY +#define NPY_FARRAY_RO NPY_ARRAY_FARRAY_RO +#define NPY_DEFAULT NPY_ARRAY_DEFAULT +#define NPY_IN_ARRAY NPY_ARRAY_IN_ARRAY +#define NPY_OUT_ARRAY NPY_ARRAY_OUT_ARRAY +#define NPY_INOUT_ARRAY NPY_ARRAY_INOUT_ARRAY +#define NPY_IN_FARRAY NPY_ARRAY_IN_FARRAY +#define NPY_OUT_FARRAY NPY_ARRAY_OUT_FARRAY +#define NPY_INOUT_FARRAY NPY_ARRAY_INOUT_FARRAY +#define NPY_UPDATE_ALL NPY_ARRAY_UPDATE_ALL + +/* This way of accessing the default type is deprecated as of NumPy 1.7 */ +#define PyArray_DEFAULT NPY_DEFAULT_TYPE + +/* These DATETIME bits aren't used internally */ +#if PY_VERSION_HEX >= 0x03000000 +#define PyDataType_GetDatetimeMetaData(descr) \ + ((descr->metadata == NULL) ? NULL : \ + ((PyArray_DatetimeMetaData *)(PyCapsule_GetPointer( \ + PyDict_GetItemString( \ + descr->metadata, NPY_METADATA_DTSTR), NULL)))) +#else +#define PyDataType_GetDatetimeMetaData(descr) \ + ((descr->metadata == NULL) ? NULL : \ + ((PyArray_DatetimeMetaData *)(PyCObject_AsVoidPtr( \ + PyDict_GetItemString(descr->metadata, NPY_METADATA_DTSTR))))) +#endif + +/* + * Deprecated as of NumPy 1.7, this kind of shortcut doesn't + * belong in the public API. + */ +#define NPY_AO PyArrayObject + +/* + * Deprecated as of NumPy 1.7, an all-lowercase macro doesn't + * belong in the public API. + */ +#define fortran fortran_ + +/* + * Deprecated as of NumPy 1.7, as it is a namespace-polluting + * macro. + */ +#define FORTRAN_IF PyArray_FORTRAN_IF + +/* Deprecated as of NumPy 1.7, datetime64 uses c_metadata instead */ +#define NPY_METADATA_DTSTR "__timeunit__" + +/* + * Deprecated as of NumPy 1.7. + * The reasoning: + * - These are for datetime, but there's no datetime "namespace". + * - They just turn NPY_STR_ into "", which is just + * making something simple be indirected. + */ +#define NPY_STR_Y "Y" +#define NPY_STR_M "M" +#define NPY_STR_W "W" +#define NPY_STR_D "D" +#define NPY_STR_h "h" +#define NPY_STR_m "m" +#define NPY_STR_s "s" +#define NPY_STR_ms "ms" +#define NPY_STR_us "us" +#define NPY_STR_ns "ns" +#define NPY_STR_ps "ps" +#define NPY_STR_fs "fs" +#define NPY_STR_as "as" + +/* + * The macros in old_defines.h are Deprecated as of NumPy 1.7 and will be + * removed in the next major release. + */ +#include "old_defines.h" + +#endif diff --git a/numpy/core/include/numpy/npy_3kcompat.h b/numpy/core/include/numpy/npy_3kcompat.h new file mode 100644 index 0000000..56fbd99 --- /dev/null +++ b/numpy/core/include/numpy/npy_3kcompat.h @@ -0,0 +1,502 @@ +/* + * This is a convenience header file providing compatibility utilities + * for supporting Python 2 and Python 3 in the same code base. + * + * If you want to use this for your own projects, it's recommended to make a + * copy of it. Although the stuff below is unlikely to change, we don't provide + * strong backwards compatibility guarantees at the moment. + */ + +#ifndef _NPY_3KCOMPAT_H_ +#define _NPY_3KCOMPAT_H_ + +#include +#include + +#if PY_VERSION_HEX >= 0x03000000 +#ifndef NPY_PY3K +#define NPY_PY3K 1 +#endif +#endif + +#include "numpy/npy_common.h" +#include "numpy/ndarrayobject.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * PyInt -> PyLong + */ + +#if defined(NPY_PY3K) +/* Return True only if the long fits in a C long */ +static NPY_INLINE int PyInt_Check(PyObject *op) { + int overflow = 0; + if (!PyLong_Check(op)) { + return 0; + } + PyLong_AsLongAndOverflow(op, &overflow); + return (overflow == 0); +} + +#define PyInt_FromLong PyLong_FromLong +#define PyInt_AsLong PyLong_AsLong +#define PyInt_AS_LONG PyLong_AsLong +#define PyInt_AsSsize_t PyLong_AsSsize_t + +/* NOTE: + * + * Since the PyLong type is very different from the fixed-range PyInt, + * we don't define PyInt_Type -> PyLong_Type. + */ +#endif /* NPY_PY3K */ + +/* Py3 changes PySlice_GetIndicesEx' first argument's type to PyObject* */ +#ifdef NPY_PY3K +# define NpySlice_GetIndicesEx PySlice_GetIndicesEx +#else +# define NpySlice_GetIndicesEx(op, nop, start, end, step, slicelength) \ + PySlice_GetIndicesEx((PySliceObject *)op, nop, start, end, step, slicelength) +#endif + +/* + * PyString -> PyBytes + */ + +#if defined(NPY_PY3K) + +#define PyString_Type PyBytes_Type +#define PyString_Check PyBytes_Check +#define PyStringObject PyBytesObject +#define PyString_FromString PyBytes_FromString +#define PyString_FromStringAndSize PyBytes_FromStringAndSize +#define PyString_AS_STRING PyBytes_AS_STRING +#define PyString_AsStringAndSize PyBytes_AsStringAndSize +#define PyString_FromFormat PyBytes_FromFormat +#define PyString_Concat PyBytes_Concat +#define PyString_ConcatAndDel PyBytes_ConcatAndDel +#define PyString_AsString PyBytes_AsString +#define PyString_GET_SIZE PyBytes_GET_SIZE +#define PyString_Size PyBytes_Size + +#define PyUString_Type PyUnicode_Type +#define PyUString_Check PyUnicode_Check +#define PyUStringObject PyUnicodeObject +#define PyUString_FromString PyUnicode_FromString +#define PyUString_FromStringAndSize PyUnicode_FromStringAndSize +#define PyUString_FromFormat PyUnicode_FromFormat +#define PyUString_Concat PyUnicode_Concat2 +#define PyUString_ConcatAndDel PyUnicode_ConcatAndDel +#define PyUString_GET_SIZE PyUnicode_GET_SIZE +#define PyUString_Size PyUnicode_Size +#define PyUString_InternFromString PyUnicode_InternFromString +#define PyUString_Format PyUnicode_Format + +#define PyBaseString_Check(obj) (PyUnicode_Check(obj)) + +#else + +#define PyBytes_Type PyString_Type +#define PyBytes_Check PyString_Check +#define PyBytesObject PyStringObject +#define PyBytes_FromString PyString_FromString +#define PyBytes_FromStringAndSize PyString_FromStringAndSize +#define PyBytes_AS_STRING PyString_AS_STRING +#define PyBytes_AsStringAndSize PyString_AsStringAndSize +#define PyBytes_FromFormat PyString_FromFormat +#define PyBytes_Concat PyString_Concat +#define PyBytes_ConcatAndDel PyString_ConcatAndDel +#define PyBytes_AsString PyString_AsString +#define PyBytes_GET_SIZE PyString_GET_SIZE +#define PyBytes_Size PyString_Size + +#define PyUString_Type PyString_Type +#define PyUString_Check PyString_Check +#define PyUStringObject PyStringObject +#define PyUString_FromString PyString_FromString +#define PyUString_FromStringAndSize PyString_FromStringAndSize +#define PyUString_FromFormat PyString_FromFormat +#define PyUString_Concat PyString_Concat +#define PyUString_ConcatAndDel PyString_ConcatAndDel +#define PyUString_GET_SIZE PyString_GET_SIZE +#define PyUString_Size PyString_Size +#define PyUString_InternFromString PyString_InternFromString +#define PyUString_Format PyString_Format + +#define PyBaseString_Check(obj) (PyBytes_Check(obj) || PyUnicode_Check(obj)) + +#endif /* NPY_PY3K */ + + +static NPY_INLINE void +PyUnicode_ConcatAndDel(PyObject **left, PyObject *right) +{ + PyObject *newobj; + newobj = PyUnicode_Concat(*left, right); + Py_DECREF(*left); + Py_DECREF(right); + *left = newobj; +} + +static NPY_INLINE void +PyUnicode_Concat2(PyObject **left, PyObject *right) +{ + PyObject *newobj; + newobj = PyUnicode_Concat(*left, right); + Py_DECREF(*left); + *left = newobj; +} + +/* + * PyFile_* compatibility + */ + +/* + * Get a FILE* handle to the file represented by the Python object + */ +static NPY_INLINE FILE* +npy_PyFile_Dup2(PyObject *file, char *mode, npy_off_t *orig_pos) +{ + int fd, fd2, unbuf; + PyObject *ret, *os, *io, *io_raw; + npy_off_t pos; + FILE *handle; + + /* For Python 2 PyFileObject, use PyFile_AsFile */ +#if !defined(NPY_PY3K) + if (PyFile_Check(file)) { + return PyFile_AsFile(file); + } +#endif + + /* Flush first to ensure things end up in the file in the correct order */ + ret = PyObject_CallMethod(file, "flush", ""); + if (ret == NULL) { + return NULL; + } + Py_DECREF(ret); + fd = PyObject_AsFileDescriptor(file); + if (fd == -1) { + return NULL; + } + + /* + * The handle needs to be dup'd because we have to call fclose + * at the end + */ + os = PyImport_ImportModule("os"); + if (os == NULL) { + return NULL; + } + ret = PyObject_CallMethod(os, "dup", "i", fd); + Py_DECREF(os); + if (ret == NULL) { + return NULL; + } + fd2 = PyNumber_AsSsize_t(ret, NULL); + Py_DECREF(ret); + + /* Convert to FILE* handle */ +#ifdef _WIN32 + handle = _fdopen(fd2, mode); +#else + handle = fdopen(fd2, mode); +#endif + if (handle == NULL) { + PyErr_SetString(PyExc_IOError, + "Getting a FILE* from a Python file object failed"); + } + + /* Record the original raw file handle position */ + *orig_pos = npy_ftell(handle); + if (*orig_pos == -1) { + /* The io module is needed to determine if buffering is used */ + io = PyImport_ImportModule("io"); + if (io == NULL) { + fclose(handle); + return NULL; + } + /* File object instances of RawIOBase are unbuffered */ + io_raw = PyObject_GetAttrString(io, "RawIOBase"); + Py_DECREF(io); + if (io_raw == NULL) { + fclose(handle); + return NULL; + } + unbuf = PyObject_IsInstance(file, io_raw); + Py_DECREF(io_raw); + if (unbuf == 1) { + /* Succeed if the IO is unbuffered */ + return handle; + } + else { + PyErr_SetString(PyExc_IOError, "obtaining file position failed"); + fclose(handle); + return NULL; + } + } + + /* Seek raw handle to the Python-side position */ + ret = PyObject_CallMethod(file, "tell", ""); + if (ret == NULL) { + fclose(handle); + return NULL; + } + pos = PyLong_AsLongLong(ret); + Py_DECREF(ret); + if (PyErr_Occurred()) { + fclose(handle); + return NULL; + } + if (npy_fseek(handle, pos, SEEK_SET) == -1) { + PyErr_SetString(PyExc_IOError, "seeking file failed"); + fclose(handle); + return NULL; + } + return handle; +} + +/* + * Close the dup-ed file handle, and seek the Python one to the current position + */ +static NPY_INLINE int +npy_PyFile_DupClose2(PyObject *file, FILE* handle, npy_off_t orig_pos) +{ + int fd, unbuf; + PyObject *ret, *io, *io_raw; + npy_off_t position; + + /* For Python 2 PyFileObject, do nothing */ +#if !defined(NPY_PY3K) + if (PyFile_Check(file)) { + return 0; + } +#endif + + position = npy_ftell(handle); + + /* Close the FILE* handle */ + fclose(handle); + + /* + * Restore original file handle position, in order to not confuse + * Python-side data structures + */ + fd = PyObject_AsFileDescriptor(file); + if (fd == -1) { + return -1; + } + + if (npy_lseek(fd, orig_pos, SEEK_SET) == -1) { + + /* The io module is needed to determine if buffering is used */ + io = PyImport_ImportModule("io"); + if (io == NULL) { + return -1; + } + /* File object instances of RawIOBase are unbuffered */ + io_raw = PyObject_GetAttrString(io, "RawIOBase"); + Py_DECREF(io); + if (io_raw == NULL) { + return -1; + } + unbuf = PyObject_IsInstance(file, io_raw); + Py_DECREF(io_raw); + if (unbuf == 1) { + /* Succeed if the IO is unbuffered */ + return 0; + } + else { + PyErr_SetString(PyExc_IOError, "seeking file failed"); + return -1; + } + } + + if (position == -1) { + PyErr_SetString(PyExc_IOError, "obtaining file position failed"); + return -1; + } + + /* Seek Python-side handle to the FILE* handle position */ + ret = PyObject_CallMethod(file, "seek", NPY_OFF_T_PYFMT "i", position, 0); + if (ret == NULL) { + return -1; + } + Py_DECREF(ret); + return 0; +} + +static NPY_INLINE int +npy_PyFile_Check(PyObject *file) +{ + int fd; + /* For Python 2, check if it is a PyFileObject */ +#if !defined(NPY_PY3K) + if (PyFile_Check(file)) { + return 1; + } +#endif + fd = PyObject_AsFileDescriptor(file); + if (fd == -1) { + PyErr_Clear(); + return 0; + } + return 1; +} + +static NPY_INLINE PyObject* +npy_PyFile_OpenFile(PyObject *filename, const char *mode) +{ + PyObject *open; + open = PyDict_GetItemString(PyEval_GetBuiltins(), "open"); + if (open == NULL) { + return NULL; + } + return PyObject_CallFunction(open, "Os", filename, mode); +} + +static NPY_INLINE int +npy_PyFile_CloseFile(PyObject *file) +{ + PyObject *ret; + + ret = PyObject_CallMethod(file, "close", NULL); + if (ret == NULL) { + return -1; + } + Py_DECREF(ret); + return 0; +} + +/* + * PyObject_Cmp + */ +#if defined(NPY_PY3K) +static NPY_INLINE int +PyObject_Cmp(PyObject *i1, PyObject *i2, int *cmp) +{ + int v; + v = PyObject_RichCompareBool(i1, i2, Py_LT); + if (v == 1) { + *cmp = -1; + return 1; + } + else if (v == -1) { + return -1; + } + + v = PyObject_RichCompareBool(i1, i2, Py_GT); + if (v == 1) { + *cmp = 1; + return 1; + } + else if (v == -1) { + return -1; + } + + v = PyObject_RichCompareBool(i1, i2, Py_EQ); + if (v == 1) { + *cmp = 0; + return 1; + } + else { + *cmp = 0; + return -1; + } +} +#endif + +/* + * PyCObject functions adapted to PyCapsules. + * + * The main job here is to get rid of the improved error handling + * of PyCapsules. It's a shame... + */ +#if PY_VERSION_HEX >= 0x03000000 + +static NPY_INLINE PyObject * +NpyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *)) +{ + PyObject *ret = PyCapsule_New(ptr, NULL, dtor); + if (ret == NULL) { + PyErr_Clear(); + } + return ret; +} + +static NPY_INLINE PyObject * +NpyCapsule_FromVoidPtrAndDesc(void *ptr, void* context, void (*dtor)(PyObject *)) +{ + PyObject *ret = NpyCapsule_FromVoidPtr(ptr, dtor); + if (ret != NULL && PyCapsule_SetContext(ret, context) != 0) { + PyErr_Clear(); + Py_DECREF(ret); + ret = NULL; + } + return ret; +} + +static NPY_INLINE void * +NpyCapsule_AsVoidPtr(PyObject *obj) +{ + void *ret = PyCapsule_GetPointer(obj, NULL); + if (ret == NULL) { + PyErr_Clear(); + } + return ret; +} + +static NPY_INLINE void * +NpyCapsule_GetDesc(PyObject *obj) +{ + return PyCapsule_GetContext(obj); +} + +static NPY_INLINE int +NpyCapsule_Check(PyObject *ptr) +{ + return PyCapsule_CheckExact(ptr); +} + +#else + +static NPY_INLINE PyObject * +NpyCapsule_FromVoidPtr(void *ptr, void (*dtor)(void *)) +{ + return PyCObject_FromVoidPtr(ptr, dtor); +} + +static NPY_INLINE PyObject * +NpyCapsule_FromVoidPtrAndDesc(void *ptr, void* context, + void (*dtor)(void *, void *)) +{ + return PyCObject_FromVoidPtrAndDesc(ptr, context, dtor); +} + +static NPY_INLINE void * +NpyCapsule_AsVoidPtr(PyObject *ptr) +{ + return PyCObject_AsVoidPtr(ptr); +} + +static NPY_INLINE void * +NpyCapsule_GetDesc(PyObject *obj) +{ + return PyCObject_GetDesc(obj); +} + +static NPY_INLINE int +NpyCapsule_Check(PyObject *ptr) +{ + return PyCObject_Check(ptr); +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _NPY_3KCOMPAT_H_ */ diff --git a/numpy/core/include/numpy/npy_common.h b/numpy/core/include/numpy/npy_common.h new file mode 100644 index 0000000..a1a30f7 --- /dev/null +++ b/numpy/core/include/numpy/npy_common.h @@ -0,0 +1,1099 @@ +#ifndef _NPY_COMMON_H_ +#define _NPY_COMMON_H_ + +/* numpconfig.h is auto-generated */ +#include "numpyconfig.h" +#ifdef HAVE_NPY_CONFIG_H +#include +#endif + +/* need Python.h for npy_intp, npy_uintp */ +#include + +/* + * using static inline modifiers when defining npy_math functions + * allows the compiler to make optimizations when possible + */ +#if NPY_INTERNAL_BUILD +#ifndef NPY_INLINE_MATH +#define NPY_INLINE_MATH 1 +#endif +#endif + +/* + * gcc does not unroll even with -O3 + * use with care, unrolling on modern cpus rarely speeds things up + */ +#ifdef HAVE_ATTRIBUTE_OPTIMIZE_UNROLL_LOOPS +#define NPY_GCC_UNROLL_LOOPS \ + __attribute__((optimize("unroll-loops"))) +#else +#define NPY_GCC_UNROLL_LOOPS +#endif + +/* highest gcc optimization level, enabled autovectorizer */ +#ifdef HAVE_ATTRIBUTE_OPTIMIZE_OPT_3 +#define NPY_GCC_OPT_3 __attribute__((optimize("O3"))) +#else +#define NPY_GCC_OPT_3 +#endif + +/* compile target attributes */ +#if defined HAVE_ATTRIBUTE_TARGET_AVX && defined HAVE_LINK_AVX +#define NPY_GCC_TARGET_AVX __attribute__((target("avx"))) +#else +#define NPY_GCC_TARGET_AVX +#endif +#if defined HAVE_ATTRIBUTE_TARGET_AVX2 && defined HAVE_LINK_AVX2 +#define NPY_GCC_TARGET_AVX2 __attribute__((target("avx2"))) +#else +#define NPY_GCC_TARGET_AVX2 +#endif + +/* + * mark an argument (starting from 1) that must not be NULL and is not checked + * DO NOT USE IF FUNCTION CHECKS FOR NULL!! the compiler will remove the check + */ +#ifdef HAVE_ATTRIBUTE_NONNULL +#define NPY_GCC_NONNULL(n) __attribute__((nonnull(n))) +#else +#define NPY_GCC_NONNULL(n) +#endif + +#if defined HAVE_XMMINTRIN_H && defined HAVE__MM_LOAD_PS +#define NPY_HAVE_SSE_INTRINSICS +#endif + +#if defined HAVE_EMMINTRIN_H && defined HAVE__MM_LOAD_PD +#define NPY_HAVE_SSE2_INTRINSICS +#endif + +/* + * give a hint to the compiler which branch is more likely or unlikely + * to occur, e.g. rare error cases: + * + * if (NPY_UNLIKELY(failure == 0)) + * return NULL; + * + * the double !! is to cast the expression (e.g. NULL) to a boolean required by + * the intrinsic + */ +#ifdef HAVE___BUILTIN_EXPECT +#define NPY_LIKELY(x) __builtin_expect(!!(x), 1) +#define NPY_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define NPY_LIKELY(x) (x) +#define NPY_UNLIKELY(x) (x) +#endif + +#ifdef HAVE___BUILTIN_PREFETCH +/* unlike _mm_prefetch also works on non-x86 */ +#define NPY_PREFETCH(x, rw, loc) __builtin_prefetch((x), (rw), (loc)) +#else +#ifdef HAVE__MM_PREFETCH +/* _MM_HINT_ET[01] (rw = 1) unsupported, only available in gcc >= 4.9 */ +#define NPY_PREFETCH(x, rw, loc) _mm_prefetch((x), loc == 0 ? _MM_HINT_NTA : \ + (loc == 1 ? _MM_HINT_T2 : \ + (loc == 2 ? _MM_HINT_T1 : \ + (loc == 3 ? _MM_HINT_T0 : -1)))) +#else +#define NPY_PREFETCH(x, rw,loc) +#endif +#endif + +#ifdef HAVE___BUILTIN_CPU_SUPPORTS + #ifdef HAVE_ATTRIBUTE_TARGET_AVX2 + #define NPY_CPU_SUPPORTS_AVX2 __builtin_cpu_supports("avx2") + #else + #define NPY_CPU_SUPPORTS_AVX2 0 + #endif + #ifdef HAVE_ATTRIBUTE_TARGET_AVX + #define NPY_CPU_SUPPORTS_AVX __builtin_cpu_supports("avx") + #else + #define NPY_CPU_SUPPORTS_AVX 0 + #endif +#else + #define NPY_CPU_SUPPORTS_AVX 0 + #define NPY_CPU_SUPPORTS_AVX2 0 +#endif + +#if defined(_MSC_VER) + #define NPY_INLINE __inline +#elif defined(__GNUC__) + #if defined(__STRICT_ANSI__) + #define NPY_INLINE __inline__ + #else + #define NPY_INLINE inline + #endif +#else + #define NPY_INLINE +#endif + +#ifdef HAVE___THREAD + #define NPY_TLS __thread +#else + #ifdef HAVE___DECLSPEC_THREAD_ + #define NPY_TLS __declspec(thread) + #else + #define NPY_TLS + #endif +#endif + +#ifdef WITH_CPYCHECKER_RETURNS_BORROWED_REF_ATTRIBUTE + #define NPY_RETURNS_BORROWED_REF \ + __attribute__((cpychecker_returns_borrowed_ref)) +#else + #define NPY_RETURNS_BORROWED_REF +#endif + +#ifdef WITH_CPYCHECKER_STEALS_REFERENCE_TO_ARG_ATTRIBUTE + #define NPY_STEALS_REF_TO_ARG(n) \ + __attribute__((cpychecker_steals_reference_to_arg(n))) +#else + #define NPY_STEALS_REF_TO_ARG(n) +#endif + +/* 64 bit file position support, also on win-amd64. Ticket #1660 */ +#if defined(_MSC_VER) && defined(_WIN64) && (_MSC_VER > 1400) || \ + defined(__MINGW32__) || defined(__MINGW64__) + #include + +/* mingw based on 3.4.5 has lseek but not ftell/fseek */ +#if defined(__MINGW32__) || defined(__MINGW64__) +extern int __cdecl _fseeki64(FILE *, long long, int); +extern long long __cdecl _ftelli64(FILE *); +#endif + + #define npy_fseek _fseeki64 + #define npy_ftell _ftelli64 + #define npy_lseek _lseeki64 + #define npy_off_t npy_int64 + + #if NPY_SIZEOF_INT == 8 + #define NPY_OFF_T_PYFMT "i" + #elif NPY_SIZEOF_LONG == 8 + #define NPY_OFF_T_PYFMT "l" + #elif NPY_SIZEOF_LONGLONG == 8 + #define NPY_OFF_T_PYFMT "L" + #else + #error Unsupported size for type off_t + #endif +#else +#ifdef HAVE_FSEEKO + #define npy_fseek fseeko +#else + #define npy_fseek fseek +#endif +#ifdef HAVE_FTELLO + #define npy_ftell ftello +#else + #define npy_ftell ftell +#endif + #include + #define npy_lseek lseek + #define npy_off_t off_t + + #if NPY_SIZEOF_OFF_T == NPY_SIZEOF_SHORT + #define NPY_OFF_T_PYFMT "h" + #elif NPY_SIZEOF_OFF_T == NPY_SIZEOF_INT + #define NPY_OFF_T_PYFMT "i" + #elif NPY_SIZEOF_OFF_T == NPY_SIZEOF_LONG + #define NPY_OFF_T_PYFMT "l" + #elif NPY_SIZEOF_OFF_T == NPY_SIZEOF_LONGLONG + #define NPY_OFF_T_PYFMT "L" + #else + #error Unsupported size for type off_t + #endif +#endif + +/* enums for detected endianness */ +enum { + NPY_CPU_UNKNOWN_ENDIAN, + NPY_CPU_LITTLE, + NPY_CPU_BIG +}; + +/* + * This is to typedef npy_intp to the appropriate pointer size for this + * platform. Py_intptr_t, Py_uintptr_t are defined in pyport.h. + */ +typedef Py_intptr_t npy_intp; +typedef Py_uintptr_t npy_uintp; + +/* + * Define sizes that were not defined in numpyconfig.h. + */ +#define NPY_SIZEOF_CHAR 1 +#define NPY_SIZEOF_BYTE 1 +#define NPY_SIZEOF_DATETIME 8 +#define NPY_SIZEOF_TIMEDELTA 8 +#define NPY_SIZEOF_INTP NPY_SIZEOF_PY_INTPTR_T +#define NPY_SIZEOF_UINTP NPY_SIZEOF_PY_INTPTR_T +#define NPY_SIZEOF_HALF 2 +#define NPY_SIZEOF_CFLOAT NPY_SIZEOF_COMPLEX_FLOAT +#define NPY_SIZEOF_CDOUBLE NPY_SIZEOF_COMPLEX_DOUBLE +#define NPY_SIZEOF_CLONGDOUBLE NPY_SIZEOF_COMPLEX_LONGDOUBLE + +#ifdef constchar +#undef constchar +#endif + +#define NPY_SSIZE_T_PYFMT "n" +#define constchar char + +/* NPY_INTP_FMT Note: + * Unlike the other NPY_*_FMT macros which are used with + * PyOS_snprintf, NPY_INTP_FMT is used with PyErr_Format and + * PyString_Format. These functions use different formatting + * codes which are portably specified according to the Python + * documentation. See ticket #1795. + */ +#if NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_INT + #define NPY_INTP NPY_INT + #define NPY_UINTP NPY_UINT + #define PyIntpArrType_Type PyIntArrType_Type + #define PyUIntpArrType_Type PyUIntArrType_Type + #define NPY_MAX_INTP NPY_MAX_INT + #define NPY_MIN_INTP NPY_MIN_INT + #define NPY_MAX_UINTP NPY_MAX_UINT + #define NPY_INTP_FMT "d" +#elif NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_LONG + #define NPY_INTP NPY_LONG + #define NPY_UINTP NPY_ULONG + #define PyIntpArrType_Type PyLongArrType_Type + #define PyUIntpArrType_Type PyULongArrType_Type + #define NPY_MAX_INTP NPY_MAX_LONG + #define NPY_MIN_INTP NPY_MIN_LONG + #define NPY_MAX_UINTP NPY_MAX_ULONG + #define NPY_INTP_FMT "ld" +#elif defined(PY_LONG_LONG) && (NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_LONGLONG) + #define NPY_INTP NPY_LONGLONG + #define NPY_UINTP NPY_ULONGLONG + #define PyIntpArrType_Type PyLongLongArrType_Type + #define PyUIntpArrType_Type PyULongLongArrType_Type + #define NPY_MAX_INTP NPY_MAX_LONGLONG + #define NPY_MIN_INTP NPY_MIN_LONGLONG + #define NPY_MAX_UINTP NPY_MAX_ULONGLONG + #define NPY_INTP_FMT "lld" +#endif + +/* + * We can only use C99 formats for npy_int_p if it is the same as + * intp_t, hence the condition on HAVE_UNITPTR_T + */ +#if (NPY_USE_C99_FORMATS) == 1 \ + && (defined HAVE_UINTPTR_T) \ + && (defined HAVE_INTTYPES_H) + #include + #undef NPY_INTP_FMT + #define NPY_INTP_FMT PRIdPTR +#endif + + +/* + * Some platforms don't define bool, long long, or long double. + * Handle that here. + */ +#define NPY_BYTE_FMT "hhd" +#define NPY_UBYTE_FMT "hhu" +#define NPY_SHORT_FMT "hd" +#define NPY_USHORT_FMT "hu" +#define NPY_INT_FMT "d" +#define NPY_UINT_FMT "u" +#define NPY_LONG_FMT "ld" +#define NPY_ULONG_FMT "lu" +#define NPY_HALF_FMT "g" +#define NPY_FLOAT_FMT "g" +#define NPY_DOUBLE_FMT "g" + + +#ifdef PY_LONG_LONG +typedef PY_LONG_LONG npy_longlong; +typedef unsigned PY_LONG_LONG npy_ulonglong; +# ifdef _MSC_VER +# define NPY_LONGLONG_FMT "I64d" +# define NPY_ULONGLONG_FMT "I64u" +# else +# define NPY_LONGLONG_FMT "lld" +# define NPY_ULONGLONG_FMT "llu" +# endif +# ifdef _MSC_VER +# define NPY_LONGLONG_SUFFIX(x) (x##i64) +# define NPY_ULONGLONG_SUFFIX(x) (x##Ui64) +# else +# define NPY_LONGLONG_SUFFIX(x) (x##LL) +# define NPY_ULONGLONG_SUFFIX(x) (x##ULL) +# endif +#else +typedef long npy_longlong; +typedef unsigned long npy_ulonglong; +# define NPY_LONGLONG_SUFFIX(x) (x##L) +# define NPY_ULONGLONG_SUFFIX(x) (x##UL) +#endif + + +typedef unsigned char npy_bool; +#define NPY_FALSE 0 +#define NPY_TRUE 1 + + +#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE + typedef double npy_longdouble; + #define NPY_LONGDOUBLE_FMT "g" +#else + typedef long double npy_longdouble; + #define NPY_LONGDOUBLE_FMT "Lg" +#endif + +#ifndef Py_USING_UNICODE +#error Must use Python with unicode enabled. +#endif + + +typedef signed char npy_byte; +typedef unsigned char npy_ubyte; +typedef unsigned short npy_ushort; +typedef unsigned int npy_uint; +typedef unsigned long npy_ulong; + +/* These are for completeness */ +typedef char npy_char; +typedef short npy_short; +typedef int npy_int; +typedef long npy_long; +typedef float npy_float; +typedef double npy_double; + +/* + * Hash value compatibility. + * As of Python 3.2 hash values are of type Py_hash_t. + * Previous versions use C long. + */ +#if PY_VERSION_HEX < 0x03020000 +typedef long npy_hash_t; +#define NPY_SIZEOF_HASH_T NPY_SIZEOF_LONG +#else +typedef Py_hash_t npy_hash_t; +#define NPY_SIZEOF_HASH_T NPY_SIZEOF_INTP +#endif + +/* + * Disabling C99 complex usage: a lot of C code in numpy/scipy rely on being + * able to do .real/.imag. Will have to convert code first. + */ +#if 0 +#if defined(NPY_USE_C99_COMPLEX) && defined(NPY_HAVE_COMPLEX_DOUBLE) +typedef complex npy_cdouble; +#else +typedef struct { double real, imag; } npy_cdouble; +#endif + +#if defined(NPY_USE_C99_COMPLEX) && defined(NPY_HAVE_COMPLEX_FLOAT) +typedef complex float npy_cfloat; +#else +typedef struct { float real, imag; } npy_cfloat; +#endif + +#if defined(NPY_USE_C99_COMPLEX) && defined(NPY_HAVE_COMPLEX_LONG_DOUBLE) +typedef complex long double npy_clongdouble; +#else +typedef struct {npy_longdouble real, imag;} npy_clongdouble; +#endif +#endif +#if NPY_SIZEOF_COMPLEX_DOUBLE != 2 * NPY_SIZEOF_DOUBLE +#error npy_cdouble definition is not compatible with C99 complex definition ! \ + Please contact NumPy maintainers and give detailed information about your \ + compiler and platform +#endif +typedef struct { double real, imag; } npy_cdouble; + +#if NPY_SIZEOF_COMPLEX_FLOAT != 2 * NPY_SIZEOF_FLOAT +#error npy_cfloat definition is not compatible with C99 complex definition ! \ + Please contact NumPy maintainers and give detailed information about your \ + compiler and platform +#endif +typedef struct { float real, imag; } npy_cfloat; + +#if NPY_SIZEOF_COMPLEX_LONGDOUBLE != 2 * NPY_SIZEOF_LONGDOUBLE +#error npy_clongdouble definition is not compatible with C99 complex definition ! \ + Please contact NumPy maintainers and give detailed information about your \ + compiler and platform +#endif +typedef struct { npy_longdouble real, imag; } npy_clongdouble; + +/* + * numarray-style bit-width typedefs + */ +#define NPY_MAX_INT8 127 +#define NPY_MIN_INT8 -128 +#define NPY_MAX_UINT8 255 +#define NPY_MAX_INT16 32767 +#define NPY_MIN_INT16 -32768 +#define NPY_MAX_UINT16 65535 +#define NPY_MAX_INT32 2147483647 +#define NPY_MIN_INT32 (-NPY_MAX_INT32 - 1) +#define NPY_MAX_UINT32 4294967295U +#define NPY_MAX_INT64 NPY_LONGLONG_SUFFIX(9223372036854775807) +#define NPY_MIN_INT64 (-NPY_MAX_INT64 - NPY_LONGLONG_SUFFIX(1)) +#define NPY_MAX_UINT64 NPY_ULONGLONG_SUFFIX(18446744073709551615) +#define NPY_MAX_INT128 NPY_LONGLONG_SUFFIX(85070591730234615865843651857942052864) +#define NPY_MIN_INT128 (-NPY_MAX_INT128 - NPY_LONGLONG_SUFFIX(1)) +#define NPY_MAX_UINT128 NPY_ULONGLONG_SUFFIX(170141183460469231731687303715884105728) +#define NPY_MAX_INT256 NPY_LONGLONG_SUFFIX(57896044618658097711785492504343953926634992332820282019728792003956564819967) +#define NPY_MIN_INT256 (-NPY_MAX_INT256 - NPY_LONGLONG_SUFFIX(1)) +#define NPY_MAX_UINT256 NPY_ULONGLONG_SUFFIX(115792089237316195423570985008687907853269984665640564039457584007913129639935) +#define NPY_MIN_DATETIME NPY_MIN_INT64 +#define NPY_MAX_DATETIME NPY_MAX_INT64 +#define NPY_MIN_TIMEDELTA NPY_MIN_INT64 +#define NPY_MAX_TIMEDELTA NPY_MAX_INT64 + + /* Need to find the number of bits for each type and + make definitions accordingly. + + C states that sizeof(char) == 1 by definition + + So, just using the sizeof keyword won't help. + + It also looks like Python itself uses sizeof(char) quite a + bit, which by definition should be 1 all the time. + + Idea: Make Use of CHAR_BIT which should tell us how many + BITS per CHARACTER + */ + + /* Include platform definitions -- These are in the C89/90 standard */ +#include +#define NPY_MAX_BYTE SCHAR_MAX +#define NPY_MIN_BYTE SCHAR_MIN +#define NPY_MAX_UBYTE UCHAR_MAX +#define NPY_MAX_SHORT SHRT_MAX +#define NPY_MIN_SHORT SHRT_MIN +#define NPY_MAX_USHORT USHRT_MAX +#define NPY_MAX_INT INT_MAX +#ifndef INT_MIN +#define INT_MIN (-INT_MAX - 1) +#endif +#define NPY_MIN_INT INT_MIN +#define NPY_MAX_UINT UINT_MAX +#define NPY_MAX_LONG LONG_MAX +#define NPY_MIN_LONG LONG_MIN +#define NPY_MAX_ULONG ULONG_MAX + +#define NPY_BITSOF_BOOL (sizeof(npy_bool) * CHAR_BIT) +#define NPY_BITSOF_CHAR CHAR_BIT +#define NPY_BITSOF_BYTE (NPY_SIZEOF_BYTE * CHAR_BIT) +#define NPY_BITSOF_SHORT (NPY_SIZEOF_SHORT * CHAR_BIT) +#define NPY_BITSOF_INT (NPY_SIZEOF_INT * CHAR_BIT) +#define NPY_BITSOF_LONG (NPY_SIZEOF_LONG * CHAR_BIT) +#define NPY_BITSOF_LONGLONG (NPY_SIZEOF_LONGLONG * CHAR_BIT) +#define NPY_BITSOF_INTP (NPY_SIZEOF_INTP * CHAR_BIT) +#define NPY_BITSOF_HALF (NPY_SIZEOF_HALF * CHAR_BIT) +#define NPY_BITSOF_FLOAT (NPY_SIZEOF_FLOAT * CHAR_BIT) +#define NPY_BITSOF_DOUBLE (NPY_SIZEOF_DOUBLE * CHAR_BIT) +#define NPY_BITSOF_LONGDOUBLE (NPY_SIZEOF_LONGDOUBLE * CHAR_BIT) +#define NPY_BITSOF_CFLOAT (NPY_SIZEOF_CFLOAT * CHAR_BIT) +#define NPY_BITSOF_CDOUBLE (NPY_SIZEOF_CDOUBLE * CHAR_BIT) +#define NPY_BITSOF_CLONGDOUBLE (NPY_SIZEOF_CLONGDOUBLE * CHAR_BIT) +#define NPY_BITSOF_DATETIME (NPY_SIZEOF_DATETIME * CHAR_BIT) +#define NPY_BITSOF_TIMEDELTA (NPY_SIZEOF_TIMEDELTA * CHAR_BIT) + +#if NPY_BITSOF_LONG == 8 +#define NPY_INT8 NPY_LONG +#define NPY_UINT8 NPY_ULONG + typedef long npy_int8; + typedef unsigned long npy_uint8; +#define PyInt8ScalarObject PyLongScalarObject +#define PyInt8ArrType_Type PyLongArrType_Type +#define PyUInt8ScalarObject PyULongScalarObject +#define PyUInt8ArrType_Type PyULongArrType_Type +#define NPY_INT8_FMT NPY_LONG_FMT +#define NPY_UINT8_FMT NPY_ULONG_FMT +#elif NPY_BITSOF_LONG == 16 +#define NPY_INT16 NPY_LONG +#define NPY_UINT16 NPY_ULONG + typedef long npy_int16; + typedef unsigned long npy_uint16; +#define PyInt16ScalarObject PyLongScalarObject +#define PyInt16ArrType_Type PyLongArrType_Type +#define PyUInt16ScalarObject PyULongScalarObject +#define PyUInt16ArrType_Type PyULongArrType_Type +#define NPY_INT16_FMT NPY_LONG_FMT +#define NPY_UINT16_FMT NPY_ULONG_FMT +#elif NPY_BITSOF_LONG == 32 +#define NPY_INT32 NPY_LONG +#define NPY_UINT32 NPY_ULONG + typedef long npy_int32; + typedef unsigned long npy_uint32; + typedef unsigned long npy_ucs4; +#define PyInt32ScalarObject PyLongScalarObject +#define PyInt32ArrType_Type PyLongArrType_Type +#define PyUInt32ScalarObject PyULongScalarObject +#define PyUInt32ArrType_Type PyULongArrType_Type +#define NPY_INT32_FMT NPY_LONG_FMT +#define NPY_UINT32_FMT NPY_ULONG_FMT +#elif NPY_BITSOF_LONG == 64 +#define NPY_INT64 NPY_LONG +#define NPY_UINT64 NPY_ULONG + typedef long npy_int64; + typedef unsigned long npy_uint64; +#define PyInt64ScalarObject PyLongScalarObject +#define PyInt64ArrType_Type PyLongArrType_Type +#define PyUInt64ScalarObject PyULongScalarObject +#define PyUInt64ArrType_Type PyULongArrType_Type +#define NPY_INT64_FMT NPY_LONG_FMT +#define NPY_UINT64_FMT NPY_ULONG_FMT +#define MyPyLong_FromInt64 PyLong_FromLong +#define MyPyLong_AsInt64 PyLong_AsLong +#elif NPY_BITSOF_LONG == 128 +#define NPY_INT128 NPY_LONG +#define NPY_UINT128 NPY_ULONG + typedef long npy_int128; + typedef unsigned long npy_uint128; +#define PyInt128ScalarObject PyLongScalarObject +#define PyInt128ArrType_Type PyLongArrType_Type +#define PyUInt128ScalarObject PyULongScalarObject +#define PyUInt128ArrType_Type PyULongArrType_Type +#define NPY_INT128_FMT NPY_LONG_FMT +#define NPY_UINT128_FMT NPY_ULONG_FMT +#endif + +#if NPY_BITSOF_LONGLONG == 8 +# ifndef NPY_INT8 +# define NPY_INT8 NPY_LONGLONG +# define NPY_UINT8 NPY_ULONGLONG + typedef npy_longlong npy_int8; + typedef npy_ulonglong npy_uint8; +# define PyInt8ScalarObject PyLongLongScalarObject +# define PyInt8ArrType_Type PyLongLongArrType_Type +# define PyUInt8ScalarObject PyULongLongScalarObject +# define PyUInt8ArrType_Type PyULongLongArrType_Type +#define NPY_INT8_FMT NPY_LONGLONG_FMT +#define NPY_UINT8_FMT NPY_ULONGLONG_FMT +# endif +# define NPY_MAX_LONGLONG NPY_MAX_INT8 +# define NPY_MIN_LONGLONG NPY_MIN_INT8 +# define NPY_MAX_ULONGLONG NPY_MAX_UINT8 +#elif NPY_BITSOF_LONGLONG == 16 +# ifndef NPY_INT16 +# define NPY_INT16 NPY_LONGLONG +# define NPY_UINT16 NPY_ULONGLONG + typedef npy_longlong npy_int16; + typedef npy_ulonglong npy_uint16; +# define PyInt16ScalarObject PyLongLongScalarObject +# define PyInt16ArrType_Type PyLongLongArrType_Type +# define PyUInt16ScalarObject PyULongLongScalarObject +# define PyUInt16ArrType_Type PyULongLongArrType_Type +#define NPY_INT16_FMT NPY_LONGLONG_FMT +#define NPY_UINT16_FMT NPY_ULONGLONG_FMT +# endif +# define NPY_MAX_LONGLONG NPY_MAX_INT16 +# define NPY_MIN_LONGLONG NPY_MIN_INT16 +# define NPY_MAX_ULONGLONG NPY_MAX_UINT16 +#elif NPY_BITSOF_LONGLONG == 32 +# ifndef NPY_INT32 +# define NPY_INT32 NPY_LONGLONG +# define NPY_UINT32 NPY_ULONGLONG + typedef npy_longlong npy_int32; + typedef npy_ulonglong npy_uint32; + typedef npy_ulonglong npy_ucs4; +# define PyInt32ScalarObject PyLongLongScalarObject +# define PyInt32ArrType_Type PyLongLongArrType_Type +# define PyUInt32ScalarObject PyULongLongScalarObject +# define PyUInt32ArrType_Type PyULongLongArrType_Type +#define NPY_INT32_FMT NPY_LONGLONG_FMT +#define NPY_UINT32_FMT NPY_ULONGLONG_FMT +# endif +# define NPY_MAX_LONGLONG NPY_MAX_INT32 +# define NPY_MIN_LONGLONG NPY_MIN_INT32 +# define NPY_MAX_ULONGLONG NPY_MAX_UINT32 +#elif NPY_BITSOF_LONGLONG == 64 +# ifndef NPY_INT64 +# define NPY_INT64 NPY_LONGLONG +# define NPY_UINT64 NPY_ULONGLONG + typedef npy_longlong npy_int64; + typedef npy_ulonglong npy_uint64; +# define PyInt64ScalarObject PyLongLongScalarObject +# define PyInt64ArrType_Type PyLongLongArrType_Type +# define PyUInt64ScalarObject PyULongLongScalarObject +# define PyUInt64ArrType_Type PyULongLongArrType_Type +#define NPY_INT64_FMT NPY_LONGLONG_FMT +#define NPY_UINT64_FMT NPY_ULONGLONG_FMT +# define MyPyLong_FromInt64 PyLong_FromLongLong +# define MyPyLong_AsInt64 PyLong_AsLongLong +# endif +# define NPY_MAX_LONGLONG NPY_MAX_INT64 +# define NPY_MIN_LONGLONG NPY_MIN_INT64 +# define NPY_MAX_ULONGLONG NPY_MAX_UINT64 +#elif NPY_BITSOF_LONGLONG == 128 +# ifndef NPY_INT128 +# define NPY_INT128 NPY_LONGLONG +# define NPY_UINT128 NPY_ULONGLONG + typedef npy_longlong npy_int128; + typedef npy_ulonglong npy_uint128; +# define PyInt128ScalarObject PyLongLongScalarObject +# define PyInt128ArrType_Type PyLongLongArrType_Type +# define PyUInt128ScalarObject PyULongLongScalarObject +# define PyUInt128ArrType_Type PyULongLongArrType_Type +#define NPY_INT128_FMT NPY_LONGLONG_FMT +#define NPY_UINT128_FMT NPY_ULONGLONG_FMT +# endif +# define NPY_MAX_LONGLONG NPY_MAX_INT128 +# define NPY_MIN_LONGLONG NPY_MIN_INT128 +# define NPY_MAX_ULONGLONG NPY_MAX_UINT128 +#elif NPY_BITSOF_LONGLONG == 256 +# define NPY_INT256 NPY_LONGLONG +# define NPY_UINT256 NPY_ULONGLONG + typedef npy_longlong npy_int256; + typedef npy_ulonglong npy_uint256; +# define PyInt256ScalarObject PyLongLongScalarObject +# define PyInt256ArrType_Type PyLongLongArrType_Type +# define PyUInt256ScalarObject PyULongLongScalarObject +# define PyUInt256ArrType_Type PyULongLongArrType_Type +#define NPY_INT256_FMT NPY_LONGLONG_FMT +#define NPY_UINT256_FMT NPY_ULONGLONG_FMT +# define NPY_MAX_LONGLONG NPY_MAX_INT256 +# define NPY_MIN_LONGLONG NPY_MIN_INT256 +# define NPY_MAX_ULONGLONG NPY_MAX_UINT256 +#endif + +#if NPY_BITSOF_INT == 8 +#ifndef NPY_INT8 +#define NPY_INT8 NPY_INT +#define NPY_UINT8 NPY_UINT + typedef int npy_int8; + typedef unsigned int npy_uint8; +# define PyInt8ScalarObject PyIntScalarObject +# define PyInt8ArrType_Type PyIntArrType_Type +# define PyUInt8ScalarObject PyUIntScalarObject +# define PyUInt8ArrType_Type PyUIntArrType_Type +#define NPY_INT8_FMT NPY_INT_FMT +#define NPY_UINT8_FMT NPY_UINT_FMT +#endif +#elif NPY_BITSOF_INT == 16 +#ifndef NPY_INT16 +#define NPY_INT16 NPY_INT +#define NPY_UINT16 NPY_UINT + typedef int npy_int16; + typedef unsigned int npy_uint16; +# define PyInt16ScalarObject PyIntScalarObject +# define PyInt16ArrType_Type PyIntArrType_Type +# define PyUInt16ScalarObject PyIntUScalarObject +# define PyUInt16ArrType_Type PyIntUArrType_Type +#define NPY_INT16_FMT NPY_INT_FMT +#define NPY_UINT16_FMT NPY_UINT_FMT +#endif +#elif NPY_BITSOF_INT == 32 +#ifndef NPY_INT32 +#define NPY_INT32 NPY_INT +#define NPY_UINT32 NPY_UINT + typedef int npy_int32; + typedef unsigned int npy_uint32; + typedef unsigned int npy_ucs4; +# define PyInt32ScalarObject PyIntScalarObject +# define PyInt32ArrType_Type PyIntArrType_Type +# define PyUInt32ScalarObject PyUIntScalarObject +# define PyUInt32ArrType_Type PyUIntArrType_Type +#define NPY_INT32_FMT NPY_INT_FMT +#define NPY_UINT32_FMT NPY_UINT_FMT +#endif +#elif NPY_BITSOF_INT == 64 +#ifndef NPY_INT64 +#define NPY_INT64 NPY_INT +#define NPY_UINT64 NPY_UINT + typedef int npy_int64; + typedef unsigned int npy_uint64; +# define PyInt64ScalarObject PyIntScalarObject +# define PyInt64ArrType_Type PyIntArrType_Type +# define PyUInt64ScalarObject PyUIntScalarObject +# define PyUInt64ArrType_Type PyUIntArrType_Type +#define NPY_INT64_FMT NPY_INT_FMT +#define NPY_UINT64_FMT NPY_UINT_FMT +# define MyPyLong_FromInt64 PyLong_FromLong +# define MyPyLong_AsInt64 PyLong_AsLong +#endif +#elif NPY_BITSOF_INT == 128 +#ifndef NPY_INT128 +#define NPY_INT128 NPY_INT +#define NPY_UINT128 NPY_UINT + typedef int npy_int128; + typedef unsigned int npy_uint128; +# define PyInt128ScalarObject PyIntScalarObject +# define PyInt128ArrType_Type PyIntArrType_Type +# define PyUInt128ScalarObject PyUIntScalarObject +# define PyUInt128ArrType_Type PyUIntArrType_Type +#define NPY_INT128_FMT NPY_INT_FMT +#define NPY_UINT128_FMT NPY_UINT_FMT +#endif +#endif + +#if NPY_BITSOF_SHORT == 8 +#ifndef NPY_INT8 +#define NPY_INT8 NPY_SHORT +#define NPY_UINT8 NPY_USHORT + typedef short npy_int8; + typedef unsigned short npy_uint8; +# define PyInt8ScalarObject PyShortScalarObject +# define PyInt8ArrType_Type PyShortArrType_Type +# define PyUInt8ScalarObject PyUShortScalarObject +# define PyUInt8ArrType_Type PyUShortArrType_Type +#define NPY_INT8_FMT NPY_SHORT_FMT +#define NPY_UINT8_FMT NPY_USHORT_FMT +#endif +#elif NPY_BITSOF_SHORT == 16 +#ifndef NPY_INT16 +#define NPY_INT16 NPY_SHORT +#define NPY_UINT16 NPY_USHORT + typedef short npy_int16; + typedef unsigned short npy_uint16; +# define PyInt16ScalarObject PyShortScalarObject +# define PyInt16ArrType_Type PyShortArrType_Type +# define PyUInt16ScalarObject PyUShortScalarObject +# define PyUInt16ArrType_Type PyUShortArrType_Type +#define NPY_INT16_FMT NPY_SHORT_FMT +#define NPY_UINT16_FMT NPY_USHORT_FMT +#endif +#elif NPY_BITSOF_SHORT == 32 +#ifndef NPY_INT32 +#define NPY_INT32 NPY_SHORT +#define NPY_UINT32 NPY_USHORT + typedef short npy_int32; + typedef unsigned short npy_uint32; + typedef unsigned short npy_ucs4; +# define PyInt32ScalarObject PyShortScalarObject +# define PyInt32ArrType_Type PyShortArrType_Type +# define PyUInt32ScalarObject PyUShortScalarObject +# define PyUInt32ArrType_Type PyUShortArrType_Type +#define NPY_INT32_FMT NPY_SHORT_FMT +#define NPY_UINT32_FMT NPY_USHORT_FMT +#endif +#elif NPY_BITSOF_SHORT == 64 +#ifndef NPY_INT64 +#define NPY_INT64 NPY_SHORT +#define NPY_UINT64 NPY_USHORT + typedef short npy_int64; + typedef unsigned short npy_uint64; +# define PyInt64ScalarObject PyShortScalarObject +# define PyInt64ArrType_Type PyShortArrType_Type +# define PyUInt64ScalarObject PyUShortScalarObject +# define PyUInt64ArrType_Type PyUShortArrType_Type +#define NPY_INT64_FMT NPY_SHORT_FMT +#define NPY_UINT64_FMT NPY_USHORT_FMT +# define MyPyLong_FromInt64 PyLong_FromLong +# define MyPyLong_AsInt64 PyLong_AsLong +#endif +#elif NPY_BITSOF_SHORT == 128 +#ifndef NPY_INT128 +#define NPY_INT128 NPY_SHORT +#define NPY_UINT128 NPY_USHORT + typedef short npy_int128; + typedef unsigned short npy_uint128; +# define PyInt128ScalarObject PyShortScalarObject +# define PyInt128ArrType_Type PyShortArrType_Type +# define PyUInt128ScalarObject PyUShortScalarObject +# define PyUInt128ArrType_Type PyUShortArrType_Type +#define NPY_INT128_FMT NPY_SHORT_FMT +#define NPY_UINT128_FMT NPY_USHORT_FMT +#endif +#endif + + +#if NPY_BITSOF_CHAR == 8 +#ifndef NPY_INT8 +#define NPY_INT8 NPY_BYTE +#define NPY_UINT8 NPY_UBYTE + typedef signed char npy_int8; + typedef unsigned char npy_uint8; +# define PyInt8ScalarObject PyByteScalarObject +# define PyInt8ArrType_Type PyByteArrType_Type +# define PyUInt8ScalarObject PyUByteScalarObject +# define PyUInt8ArrType_Type PyUByteArrType_Type +#define NPY_INT8_FMT NPY_BYTE_FMT +#define NPY_UINT8_FMT NPY_UBYTE_FMT +#endif +#elif NPY_BITSOF_CHAR == 16 +#ifndef NPY_INT16 +#define NPY_INT16 NPY_BYTE +#define NPY_UINT16 NPY_UBYTE + typedef signed char npy_int16; + typedef unsigned char npy_uint16; +# define PyInt16ScalarObject PyByteScalarObject +# define PyInt16ArrType_Type PyByteArrType_Type +# define PyUInt16ScalarObject PyUByteScalarObject +# define PyUInt16ArrType_Type PyUByteArrType_Type +#define NPY_INT16_FMT NPY_BYTE_FMT +#define NPY_UINT16_FMT NPY_UBYTE_FMT +#endif +#elif NPY_BITSOF_CHAR == 32 +#ifndef NPY_INT32 +#define NPY_INT32 NPY_BYTE +#define NPY_UINT32 NPY_UBYTE + typedef signed char npy_int32; + typedef unsigned char npy_uint32; + typedef unsigned char npy_ucs4; +# define PyInt32ScalarObject PyByteScalarObject +# define PyInt32ArrType_Type PyByteArrType_Type +# define PyUInt32ScalarObject PyUByteScalarObject +# define PyUInt32ArrType_Type PyUByteArrType_Type +#define NPY_INT32_FMT NPY_BYTE_FMT +#define NPY_UINT32_FMT NPY_UBYTE_FMT +#endif +#elif NPY_BITSOF_CHAR == 64 +#ifndef NPY_INT64 +#define NPY_INT64 NPY_BYTE +#define NPY_UINT64 NPY_UBYTE + typedef signed char npy_int64; + typedef unsigned char npy_uint64; +# define PyInt64ScalarObject PyByteScalarObject +# define PyInt64ArrType_Type PyByteArrType_Type +# define PyUInt64ScalarObject PyUByteScalarObject +# define PyUInt64ArrType_Type PyUByteArrType_Type +#define NPY_INT64_FMT NPY_BYTE_FMT +#define NPY_UINT64_FMT NPY_UBYTE_FMT +# define MyPyLong_FromInt64 PyLong_FromLong +# define MyPyLong_AsInt64 PyLong_AsLong +#endif +#elif NPY_BITSOF_CHAR == 128 +#ifndef NPY_INT128 +#define NPY_INT128 NPY_BYTE +#define NPY_UINT128 NPY_UBYTE + typedef signed char npy_int128; + typedef unsigned char npy_uint128; +# define PyInt128ScalarObject PyByteScalarObject +# define PyInt128ArrType_Type PyByteArrType_Type +# define PyUInt128ScalarObject PyUByteScalarObject +# define PyUInt128ArrType_Type PyUByteArrType_Type +#define NPY_INT128_FMT NPY_BYTE_FMT +#define NPY_UINT128_FMT NPY_UBYTE_FMT +#endif +#endif + + + +#if NPY_BITSOF_DOUBLE == 32 +#ifndef NPY_FLOAT32 +#define NPY_FLOAT32 NPY_DOUBLE +#define NPY_COMPLEX64 NPY_CDOUBLE + typedef double npy_float32; + typedef npy_cdouble npy_complex64; +# define PyFloat32ScalarObject PyDoubleScalarObject +# define PyComplex64ScalarObject PyCDoubleScalarObject +# define PyFloat32ArrType_Type PyDoubleArrType_Type +# define PyComplex64ArrType_Type PyCDoubleArrType_Type +#define NPY_FLOAT32_FMT NPY_DOUBLE_FMT +#define NPY_COMPLEX64_FMT NPY_CDOUBLE_FMT +#endif +#elif NPY_BITSOF_DOUBLE == 64 +#ifndef NPY_FLOAT64 +#define NPY_FLOAT64 NPY_DOUBLE +#define NPY_COMPLEX128 NPY_CDOUBLE + typedef double npy_float64; + typedef npy_cdouble npy_complex128; +# define PyFloat64ScalarObject PyDoubleScalarObject +# define PyComplex128ScalarObject PyCDoubleScalarObject +# define PyFloat64ArrType_Type PyDoubleArrType_Type +# define PyComplex128ArrType_Type PyCDoubleArrType_Type +#define NPY_FLOAT64_FMT NPY_DOUBLE_FMT +#define NPY_COMPLEX128_FMT NPY_CDOUBLE_FMT +#endif +#elif NPY_BITSOF_DOUBLE == 80 +#ifndef NPY_FLOAT80 +#define NPY_FLOAT80 NPY_DOUBLE +#define NPY_COMPLEX160 NPY_CDOUBLE + typedef double npy_float80; + typedef npy_cdouble npy_complex160; +# define PyFloat80ScalarObject PyDoubleScalarObject +# define PyComplex160ScalarObject PyCDoubleScalarObject +# define PyFloat80ArrType_Type PyDoubleArrType_Type +# define PyComplex160ArrType_Type PyCDoubleArrType_Type +#define NPY_FLOAT80_FMT NPY_DOUBLE_FMT +#define NPY_COMPLEX160_FMT NPY_CDOUBLE_FMT +#endif +#elif NPY_BITSOF_DOUBLE == 96 +#ifndef NPY_FLOAT96 +#define NPY_FLOAT96 NPY_DOUBLE +#define NPY_COMPLEX192 NPY_CDOUBLE + typedef double npy_float96; + typedef npy_cdouble npy_complex192; +# define PyFloat96ScalarObject PyDoubleScalarObject +# define PyComplex192ScalarObject PyCDoubleScalarObject +# define PyFloat96ArrType_Type PyDoubleArrType_Type +# define PyComplex192ArrType_Type PyCDoubleArrType_Type +#define NPY_FLOAT96_FMT NPY_DOUBLE_FMT +#define NPY_COMPLEX192_FMT NPY_CDOUBLE_FMT +#endif +#elif NPY_BITSOF_DOUBLE == 128 +#ifndef NPY_FLOAT128 +#define NPY_FLOAT128 NPY_DOUBLE +#define NPY_COMPLEX256 NPY_CDOUBLE + typedef double npy_float128; + typedef npy_cdouble npy_complex256; +# define PyFloat128ScalarObject PyDoubleScalarObject +# define PyComplex256ScalarObject PyCDoubleScalarObject +# define PyFloat128ArrType_Type PyDoubleArrType_Type +# define PyComplex256ArrType_Type PyCDoubleArrType_Type +#define NPY_FLOAT128_FMT NPY_DOUBLE_FMT +#define NPY_COMPLEX256_FMT NPY_CDOUBLE_FMT +#endif +#endif + + + +#if NPY_BITSOF_FLOAT == 32 +#ifndef NPY_FLOAT32 +#define NPY_FLOAT32 NPY_FLOAT +#define NPY_COMPLEX64 NPY_CFLOAT + typedef float npy_float32; + typedef npy_cfloat npy_complex64; +# define PyFloat32ScalarObject PyFloatScalarObject +# define PyComplex64ScalarObject PyCFloatScalarObject +# define PyFloat32ArrType_Type PyFloatArrType_Type +# define PyComplex64ArrType_Type PyCFloatArrType_Type +#define NPY_FLOAT32_FMT NPY_FLOAT_FMT +#define NPY_COMPLEX64_FMT NPY_CFLOAT_FMT +#endif +#elif NPY_BITSOF_FLOAT == 64 +#ifndef NPY_FLOAT64 +#define NPY_FLOAT64 NPY_FLOAT +#define NPY_COMPLEX128 NPY_CFLOAT + typedef float npy_float64; + typedef npy_cfloat npy_complex128; +# define PyFloat64ScalarObject PyFloatScalarObject +# define PyComplex128ScalarObject PyCFloatScalarObject +# define PyFloat64ArrType_Type PyFloatArrType_Type +# define PyComplex128ArrType_Type PyCFloatArrType_Type +#define NPY_FLOAT64_FMT NPY_FLOAT_FMT +#define NPY_COMPLEX128_FMT NPY_CFLOAT_FMT +#endif +#elif NPY_BITSOF_FLOAT == 80 +#ifndef NPY_FLOAT80 +#define NPY_FLOAT80 NPY_FLOAT +#define NPY_COMPLEX160 NPY_CFLOAT + typedef float npy_float80; + typedef npy_cfloat npy_complex160; +# define PyFloat80ScalarObject PyFloatScalarObject +# define PyComplex160ScalarObject PyCFloatScalarObject +# define PyFloat80ArrType_Type PyFloatArrType_Type +# define PyComplex160ArrType_Type PyCFloatArrType_Type +#define NPY_FLOAT80_FMT NPY_FLOAT_FMT +#define NPY_COMPLEX160_FMT NPY_CFLOAT_FMT +#endif +#elif NPY_BITSOF_FLOAT == 96 +#ifndef NPY_FLOAT96 +#define NPY_FLOAT96 NPY_FLOAT +#define NPY_COMPLEX192 NPY_CFLOAT + typedef float npy_float96; + typedef npy_cfloat npy_complex192; +# define PyFloat96ScalarObject PyFloatScalarObject +# define PyComplex192ScalarObject PyCFloatScalarObject +# define PyFloat96ArrType_Type PyFloatArrType_Type +# define PyComplex192ArrType_Type PyCFloatArrType_Type +#define NPY_FLOAT96_FMT NPY_FLOAT_FMT +#define NPY_COMPLEX192_FMT NPY_CFLOAT_FMT +#endif +#elif NPY_BITSOF_FLOAT == 128 +#ifndef NPY_FLOAT128 +#define NPY_FLOAT128 NPY_FLOAT +#define NPY_COMPLEX256 NPY_CFLOAT + typedef float npy_float128; + typedef npy_cfloat npy_complex256; +# define PyFloat128ScalarObject PyFloatScalarObject +# define PyComplex256ScalarObject PyCFloatScalarObject +# define PyFloat128ArrType_Type PyFloatArrType_Type +# define PyComplex256ArrType_Type PyCFloatArrType_Type +#define NPY_FLOAT128_FMT NPY_FLOAT_FMT +#define NPY_COMPLEX256_FMT NPY_CFLOAT_FMT +#endif +#endif + +/* half/float16 isn't a floating-point type in C */ +#define NPY_FLOAT16 NPY_HALF +typedef npy_uint16 npy_half; +typedef npy_half npy_float16; + +#if NPY_BITSOF_LONGDOUBLE == 32 +#ifndef NPY_FLOAT32 +#define NPY_FLOAT32 NPY_LONGDOUBLE +#define NPY_COMPLEX64 NPY_CLONGDOUBLE + typedef npy_longdouble npy_float32; + typedef npy_clongdouble npy_complex64; +# define PyFloat32ScalarObject PyLongDoubleScalarObject +# define PyComplex64ScalarObject PyCLongDoubleScalarObject +# define PyFloat32ArrType_Type PyLongDoubleArrType_Type +# define PyComplex64ArrType_Type PyCLongDoubleArrType_Type +#define NPY_FLOAT32_FMT NPY_LONGDOUBLE_FMT +#define NPY_COMPLEX64_FMT NPY_CLONGDOUBLE_FMT +#endif +#elif NPY_BITSOF_LONGDOUBLE == 64 +#ifndef NPY_FLOAT64 +#define NPY_FLOAT64 NPY_LONGDOUBLE +#define NPY_COMPLEX128 NPY_CLONGDOUBLE + typedef npy_longdouble npy_float64; + typedef npy_clongdouble npy_complex128; +# define PyFloat64ScalarObject PyLongDoubleScalarObject +# define PyComplex128ScalarObject PyCLongDoubleScalarObject +# define PyFloat64ArrType_Type PyLongDoubleArrType_Type +# define PyComplex128ArrType_Type PyCLongDoubleArrType_Type +#define NPY_FLOAT64_FMT NPY_LONGDOUBLE_FMT +#define NPY_COMPLEX128_FMT NPY_CLONGDOUBLE_FMT +#endif +#elif NPY_BITSOF_LONGDOUBLE == 80 +#ifndef NPY_FLOAT80 +#define NPY_FLOAT80 NPY_LONGDOUBLE +#define NPY_COMPLEX160 NPY_CLONGDOUBLE + typedef npy_longdouble npy_float80; + typedef npy_clongdouble npy_complex160; +# define PyFloat80ScalarObject PyLongDoubleScalarObject +# define PyComplex160ScalarObject PyCLongDoubleScalarObject +# define PyFloat80ArrType_Type PyLongDoubleArrType_Type +# define PyComplex160ArrType_Type PyCLongDoubleArrType_Type +#define NPY_FLOAT80_FMT NPY_LONGDOUBLE_FMT +#define NPY_COMPLEX160_FMT NPY_CLONGDOUBLE_FMT +#endif +#elif NPY_BITSOF_LONGDOUBLE == 96 +#ifndef NPY_FLOAT96 +#define NPY_FLOAT96 NPY_LONGDOUBLE +#define NPY_COMPLEX192 NPY_CLONGDOUBLE + typedef npy_longdouble npy_float96; + typedef npy_clongdouble npy_complex192; +# define PyFloat96ScalarObject PyLongDoubleScalarObject +# define PyComplex192ScalarObject PyCLongDoubleScalarObject +# define PyFloat96ArrType_Type PyLongDoubleArrType_Type +# define PyComplex192ArrType_Type PyCLongDoubleArrType_Type +#define NPY_FLOAT96_FMT NPY_LONGDOUBLE_FMT +#define NPY_COMPLEX192_FMT NPY_CLONGDOUBLE_FMT +#endif +#elif NPY_BITSOF_LONGDOUBLE == 128 +#ifndef NPY_FLOAT128 +#define NPY_FLOAT128 NPY_LONGDOUBLE +#define NPY_COMPLEX256 NPY_CLONGDOUBLE + typedef npy_longdouble npy_float128; + typedef npy_clongdouble npy_complex256; +# define PyFloat128ScalarObject PyLongDoubleScalarObject +# define PyComplex256ScalarObject PyCLongDoubleScalarObject +# define PyFloat128ArrType_Type PyLongDoubleArrType_Type +# define PyComplex256ArrType_Type PyCLongDoubleArrType_Type +#define NPY_FLOAT128_FMT NPY_LONGDOUBLE_FMT +#define NPY_COMPLEX256_FMT NPY_CLONGDOUBLE_FMT +#endif +#elif NPY_BITSOF_LONGDOUBLE == 256 +#define NPY_FLOAT256 NPY_LONGDOUBLE +#define NPY_COMPLEX512 NPY_CLONGDOUBLE + typedef npy_longdouble npy_float256; + typedef npy_clongdouble npy_complex512; +# define PyFloat256ScalarObject PyLongDoubleScalarObject +# define PyComplex512ScalarObject PyCLongDoubleScalarObject +# define PyFloat256ArrType_Type PyLongDoubleArrType_Type +# define PyComplex512ArrType_Type PyCLongDoubleArrType_Type +#define NPY_FLOAT256_FMT NPY_LONGDOUBLE_FMT +#define NPY_COMPLEX512_FMT NPY_CLONGDOUBLE_FMT +#endif + +/* datetime typedefs */ +typedef npy_int64 npy_timedelta; +typedef npy_int64 npy_datetime; +#define NPY_DATETIME_FMT NPY_INT64_FMT +#define NPY_TIMEDELTA_FMT NPY_INT64_FMT + +/* End of typedefs for numarray style bit-width names */ + +#endif diff --git a/numpy/core/include/numpy/npy_cpu.h b/numpy/core/include/numpy/npy_cpu.h new file mode 100644 index 0000000..84653ea --- /dev/null +++ b/numpy/core/include/numpy/npy_cpu.h @@ -0,0 +1,98 @@ +/* + * This set (target) cpu specific macros: + * - Possible values: + * NPY_CPU_X86 + * NPY_CPU_AMD64 + * NPY_CPU_PPC + * NPY_CPU_PPC64 + * NPY_CPU_PPC64LE + * NPY_CPU_SPARC + * NPY_CPU_S390 + * NPY_CPU_IA64 + * NPY_CPU_HPPA + * NPY_CPU_ALPHA + * NPY_CPU_ARMEL + * NPY_CPU_ARMEB + * NPY_CPU_SH_LE + * NPY_CPU_SH_BE + * NPY_CPU_ARCEL + * NPY_CPU_ARCEB + */ +#ifndef _NPY_CPUARCH_H_ +#define _NPY_CPUARCH_H_ + +#include "numpyconfig.h" +#include /* for memcpy */ + +#if defined( __i386__ ) || defined(i386) || defined(_M_IX86) + /* + * __i386__ is defined by gcc and Intel compiler on Linux, + * _M_IX86 by VS compiler, + * i386 by Sun compilers on opensolaris at least + */ + #define NPY_CPU_X86 +#elif defined(__x86_64__) || defined(__amd64__) || defined(__x86_64) || defined(_M_AMD64) + /* + * both __x86_64__ and __amd64__ are defined by gcc + * __x86_64 defined by sun compiler on opensolaris at least + * _M_AMD64 defined by MS compiler + */ + #define NPY_CPU_AMD64 +#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) + /* + * __ppc__ is defined by gcc, I remember having seen __powerpc__ once, + * but can't find it ATM + * _ARCH_PPC is used by at least gcc on AIX + */ + #define NPY_CPU_PPC +#elif defined(__ppc64le__) + #define NPY_CPU_PPC64LE +#elif defined(__ppc64__) + #define NPY_CPU_PPC64 +#elif defined(__sparc__) || defined(__sparc) + /* __sparc__ is defined by gcc and Forte (e.g. Sun) compilers */ + #define NPY_CPU_SPARC +#elif defined(__s390__) + #define NPY_CPU_S390 +#elif defined(__ia64) + #define NPY_CPU_IA64 +#elif defined(__hppa) + #define NPY_CPU_HPPA +#elif defined(__alpha__) + #define NPY_CPU_ALPHA +#elif defined(__arm__) && defined(__ARMEL__) + #define NPY_CPU_ARMEL +#elif defined(__arm__) && defined(__ARMEB__) + #define NPY_CPU_ARMEB +#elif defined(__sh__) && defined(__LITTLE_ENDIAN__) + #define NPY_CPU_SH_LE +#elif defined(__sh__) && defined(__BIG_ENDIAN__) + #define NPY_CPU_SH_BE +#elif defined(__MIPSEL__) + #define NPY_CPU_MIPSEL +#elif defined(__MIPSEB__) + #define NPY_CPU_MIPSEB +#elif defined(__or1k__) + #define NPY_CPU_OR1K +#elif defined(__aarch64__) + #define NPY_CPU_AARCH64 +#elif defined(__mc68000__) + #define NPY_CPU_M68K +#elif defined(__arc__) && defined(__LITTLE_ENDIAN__) + #define NPY_CPU_ARCEL +#elif defined(__arc__) && defined(__BIG_ENDIAN__) + #define NPY_CPU_ARCEB +#else + #error Unknown CPU, please report this to numpy maintainers with \ + information about your platform (OS, CPU and compiler) +#endif + +#define NPY_COPY_PYOBJECT_PTR(dst, src) memcpy(dst, src, sizeof(PyObject *)) + +#if (defined(NPY_CPU_X86) || defined(NPY_CPU_AMD64)) +#define NPY_CPU_HAVE_UNALIGNED_ACCESS 1 +#else +#define NPY_CPU_HAVE_UNALIGNED_ACCESS 0 +#endif + +#endif diff --git a/numpy/core/include/numpy/npy_endian.h b/numpy/core/include/numpy/npy_endian.h new file mode 100644 index 0000000..1a42121 --- /dev/null +++ b/numpy/core/include/numpy/npy_endian.h @@ -0,0 +1,68 @@ +#ifndef _NPY_ENDIAN_H_ +#define _NPY_ENDIAN_H_ + +/* + * NPY_BYTE_ORDER is set to the same value as BYTE_ORDER set by glibc in + * endian.h + */ + +#if defined(NPY_HAVE_ENDIAN_H) || defined(NPY_HAVE_SYS_ENDIAN_H) + /* Use endian.h if available */ + + #if defined(NPY_HAVE_ENDIAN_H) + #include + #elif defined(NPY_HAVE_SYS_ENDIAN_H) + #include + #endif + + #if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN) + #define NPY_BYTE_ORDER BYTE_ORDER + #define NPY_LITTLE_ENDIAN LITTLE_ENDIAN + #define NPY_BIG_ENDIAN BIG_ENDIAN + #elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) + #define NPY_BYTE_ORDER _BYTE_ORDER + #define NPY_LITTLE_ENDIAN _LITTLE_ENDIAN + #define NPY_BIG_ENDIAN _BIG_ENDIAN + #elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) + #define NPY_BYTE_ORDER __BYTE_ORDER + #define NPY_LITTLE_ENDIAN __LITTLE_ENDIAN + #define NPY_BIG_ENDIAN __BIG_ENDIAN + #endif +#endif + +#ifndef NPY_BYTE_ORDER + /* Set endianness info using target CPU */ + #include "npy_cpu.h" + + #define NPY_LITTLE_ENDIAN 1234 + #define NPY_BIG_ENDIAN 4321 + + #if defined(NPY_CPU_X86) \ + || defined(NPY_CPU_AMD64) \ + || defined(NPY_CPU_IA64) \ + || defined(NPY_CPU_ALPHA) \ + || defined(NPY_CPU_ARMEL) \ + || defined(NPY_CPU_AARCH64) \ + || defined(NPY_CPU_SH_LE) \ + || defined(NPY_CPU_MIPSEL) \ + || defined(NPY_CPU_PPC64LE) \ + || defined(NPY_CPU_ARCEL) + #define NPY_BYTE_ORDER NPY_LITTLE_ENDIAN + #elif defined(NPY_CPU_PPC) \ + || defined(NPY_CPU_SPARC) \ + || defined(NPY_CPU_S390) \ + || defined(NPY_CPU_HPPA) \ + || defined(NPY_CPU_PPC64) \ + || defined(NPY_CPU_ARMEB) \ + || defined(NPY_CPU_SH_BE) \ + || defined(NPY_CPU_MIPSEB) \ + || defined(NPY_CPU_OR1K) \ + || defined(NPY_CPU_M68K) \ + || defined(NPY_CPU_ARCEB) + #define NPY_BYTE_ORDER NPY_BIG_ENDIAN + #else + #error Unknown CPU: can not set endianness + #endif +#endif + +#endif diff --git a/numpy/core/include/numpy/npy_interrupt.h b/numpy/core/include/numpy/npy_interrupt.h new file mode 100644 index 0000000..f71fd68 --- /dev/null +++ b/numpy/core/include/numpy/npy_interrupt.h @@ -0,0 +1,117 @@ + +/* Signal handling: + +This header file defines macros that allow your code to handle +interrupts received during processing. Interrupts that +could reasonably be handled: + +SIGINT, SIGABRT, SIGALRM, SIGSEGV + +****Warning*************** + +Do not allow code that creates temporary memory or increases reference +counts of Python objects to be interrupted unless you handle it +differently. + +************************** + +The mechanism for handling interrupts is conceptually simple: + + - replace the signal handler with our own home-grown version + and store the old one. + - run the code to be interrupted -- if an interrupt occurs + the handler should basically just cause a return to the + calling function for finish work. + - restore the old signal handler + +Of course, every code that allows interrupts must account for +returning via the interrupt and handle clean-up correctly. But, +even still, the simple paradigm is complicated by at least three +factors. + + 1) platform portability (i.e. Microsoft says not to use longjmp + to return from signal handling. They have a __try and __except + extension to C instead but what about mingw?). + + 2) how to handle threads: apparently whether signals are delivered to + every thread of the process or the "invoking" thread is platform + dependent. --- we don't handle threads for now. + + 3) do we need to worry about re-entrance. For now, assume the + code will not call-back into itself. + +Ideas: + + 1) Start by implementing an approach that works on platforms that + can use setjmp and longjmp functionality and does nothing + on other platforms. + + 2) Ignore threads --- i.e. do not mix interrupt handling and threads + + 3) Add a default signal_handler function to the C-API but have the rest + use macros. + + +Simple Interface: + + +In your C-extension: around a block of code you want to be interruptable +with a SIGINT + +NPY_SIGINT_ON +[code] +NPY_SIGINT_OFF + +In order for this to work correctly, the +[code] block must not allocate any memory or alter the reference count of any +Python objects. In other words [code] must be interruptible so that continuation +after NPY_SIGINT_OFF will only be "missing some computations" + +Interrupt handling does not work well with threads. + +*/ + +/* Add signal handling macros + Make the global variable and signal handler part of the C-API +*/ + +#ifndef NPY_INTERRUPT_H +#define NPY_INTERRUPT_H + +#ifndef NPY_NO_SIGNAL + +#include +#include + +#ifndef sigsetjmp + +#define NPY_SIGSETJMP(arg1, arg2) setjmp(arg1) +#define NPY_SIGLONGJMP(arg1, arg2) longjmp(arg1, arg2) +#define NPY_SIGJMP_BUF jmp_buf + +#else + +#define NPY_SIGSETJMP(arg1, arg2) sigsetjmp(arg1, arg2) +#define NPY_SIGLONGJMP(arg1, arg2) siglongjmp(arg1, arg2) +#define NPY_SIGJMP_BUF sigjmp_buf + +#endif + +# define NPY_SIGINT_ON { \ + PyOS_sighandler_t _npy_sig_save; \ + _npy_sig_save = PyOS_setsig(SIGINT, _PyArray_SigintHandler); \ + if (NPY_SIGSETJMP(*((NPY_SIGJMP_BUF *)_PyArray_GetSigintBuf()), \ + 1) == 0) { \ + +# define NPY_SIGINT_OFF } \ + PyOS_setsig(SIGINT, _npy_sig_save); \ + } + +#else /* NPY_NO_SIGNAL */ + +#define NPY_SIGINT_ON +#define NPY_SIGINT_OFF + +#endif /* HAVE_SIGSETJMP */ + +#endif /* NPY_INTERRUPT_H */ diff --git a/numpy/core/include/numpy/npy_math.h b/numpy/core/include/numpy/npy_math.h new file mode 100644 index 0000000..ba32bcd --- /dev/null +++ b/numpy/core/include/numpy/npy_math.h @@ -0,0 +1,542 @@ +#ifndef __NPY_MATH_C99_H_ +#define __NPY_MATH_C99_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef __SUNPRO_CC +#include +#endif +#ifdef HAVE_NPY_CONFIG_H +#include +#endif +#include + +/* By adding static inline specifiers to npy_math function definitions when + appropriate, compiler is given the opportunity to optimize */ +#if NPY_INLINE_MATH +#define NPY_INPLACE NPY_INLINE static +#else +#define NPY_INPLACE +#endif + + +/* + * NAN and INFINITY like macros (same behavior as glibc for NAN, same as C99 + * for INFINITY) + * + * XXX: I should test whether INFINITY and NAN are available on the platform + */ +NPY_INLINE static float __npy_inff(void) +{ + const union { npy_uint32 __i; float __f;} __bint = {0x7f800000UL}; + return __bint.__f; +} + +NPY_INLINE static float __npy_nanf(void) +{ + const union { npy_uint32 __i; float __f;} __bint = {0x7fc00000UL}; + return __bint.__f; +} + +NPY_INLINE static float __npy_pzerof(void) +{ + const union { npy_uint32 __i; float __f;} __bint = {0x00000000UL}; + return __bint.__f; +} + +NPY_INLINE static float __npy_nzerof(void) +{ + const union { npy_uint32 __i; float __f;} __bint = {0x80000000UL}; + return __bint.__f; +} + +#define NPY_INFINITYF __npy_inff() +#define NPY_NANF __npy_nanf() +#define NPY_PZEROF __npy_pzerof() +#define NPY_NZEROF __npy_nzerof() + +#define NPY_INFINITY ((npy_double)NPY_INFINITYF) +#define NPY_NAN ((npy_double)NPY_NANF) +#define NPY_PZERO ((npy_double)NPY_PZEROF) +#define NPY_NZERO ((npy_double)NPY_NZEROF) + +#define NPY_INFINITYL ((npy_longdouble)NPY_INFINITYF) +#define NPY_NANL ((npy_longdouble)NPY_NANF) +#define NPY_PZEROL ((npy_longdouble)NPY_PZEROF) +#define NPY_NZEROL ((npy_longdouble)NPY_NZEROF) + +/* + * Useful constants + */ +#define NPY_E 2.718281828459045235360287471352662498 /* e */ +#define NPY_LOG2E 1.442695040888963407359924681001892137 /* log_2 e */ +#define NPY_LOG10E 0.434294481903251827651128918916605082 /* log_10 e */ +#define NPY_LOGE2 0.693147180559945309417232121458176568 /* log_e 2 */ +#define NPY_LOGE10 2.302585092994045684017991454684364208 /* log_e 10 */ +#define NPY_PI 3.141592653589793238462643383279502884 /* pi */ +#define NPY_PI_2 1.570796326794896619231321691639751442 /* pi/2 */ +#define NPY_PI_4 0.785398163397448309615660845819875721 /* pi/4 */ +#define NPY_1_PI 0.318309886183790671537767526745028724 /* 1/pi */ +#define NPY_2_PI 0.636619772367581343075535053490057448 /* 2/pi */ +#define NPY_EULER 0.577215664901532860606512090082402431 /* Euler constant */ +#define NPY_SQRT2 1.414213562373095048801688724209698079 /* sqrt(2) */ +#define NPY_SQRT1_2 0.707106781186547524400844362104849039 /* 1/sqrt(2) */ + +#define NPY_Ef 2.718281828459045235360287471352662498F /* e */ +#define NPY_LOG2Ef 1.442695040888963407359924681001892137F /* log_2 e */ +#define NPY_LOG10Ef 0.434294481903251827651128918916605082F /* log_10 e */ +#define NPY_LOGE2f 0.693147180559945309417232121458176568F /* log_e 2 */ +#define NPY_LOGE10f 2.302585092994045684017991454684364208F /* log_e 10 */ +#define NPY_PIf 3.141592653589793238462643383279502884F /* pi */ +#define NPY_PI_2f 1.570796326794896619231321691639751442F /* pi/2 */ +#define NPY_PI_4f 0.785398163397448309615660845819875721F /* pi/4 */ +#define NPY_1_PIf 0.318309886183790671537767526745028724F /* 1/pi */ +#define NPY_2_PIf 0.636619772367581343075535053490057448F /* 2/pi */ +#define NPY_EULERf 0.577215664901532860606512090082402431F /* Euler constant */ +#define NPY_SQRT2f 1.414213562373095048801688724209698079F /* sqrt(2) */ +#define NPY_SQRT1_2f 0.707106781186547524400844362104849039F /* 1/sqrt(2) */ + +#define NPY_El 2.718281828459045235360287471352662498L /* e */ +#define NPY_LOG2El 1.442695040888963407359924681001892137L /* log_2 e */ +#define NPY_LOG10El 0.434294481903251827651128918916605082L /* log_10 e */ +#define NPY_LOGE2l 0.693147180559945309417232121458176568L /* log_e 2 */ +#define NPY_LOGE10l 2.302585092994045684017991454684364208L /* log_e 10 */ +#define NPY_PIl 3.141592653589793238462643383279502884L /* pi */ +#define NPY_PI_2l 1.570796326794896619231321691639751442L /* pi/2 */ +#define NPY_PI_4l 0.785398163397448309615660845819875721L /* pi/4 */ +#define NPY_1_PIl 0.318309886183790671537767526745028724L /* 1/pi */ +#define NPY_2_PIl 0.636619772367581343075535053490057448L /* 2/pi */ +#define NPY_EULERl 0.577215664901532860606512090082402431L /* Euler constant */ +#define NPY_SQRT2l 1.414213562373095048801688724209698079L /* sqrt(2) */ +#define NPY_SQRT1_2l 0.707106781186547524400844362104849039L /* 1/sqrt(2) */ + +/* + * C99 double math funcs + */ +NPY_INPLACE double npy_sin(double x); +NPY_INPLACE double npy_cos(double x); +NPY_INPLACE double npy_tan(double x); +NPY_INPLACE double npy_sinh(double x); +NPY_INPLACE double npy_cosh(double x); +NPY_INPLACE double npy_tanh(double x); + +NPY_INPLACE double npy_asin(double x); +NPY_INPLACE double npy_acos(double x); +NPY_INPLACE double npy_atan(double x); + +NPY_INPLACE double npy_log(double x); +NPY_INPLACE double npy_log10(double x); +NPY_INPLACE double npy_exp(double x); +NPY_INPLACE double npy_sqrt(double x); +NPY_INPLACE double npy_cbrt(double x); + +NPY_INPLACE double npy_fabs(double x); +NPY_INPLACE double npy_ceil(double x); +NPY_INPLACE double npy_fmod(double x, double y); +NPY_INPLACE double npy_floor(double x); + +NPY_INPLACE double npy_expm1(double x); +NPY_INPLACE double npy_log1p(double x); +NPY_INPLACE double npy_hypot(double x, double y); +NPY_INPLACE double npy_acosh(double x); +NPY_INPLACE double npy_asinh(double xx); +NPY_INPLACE double npy_atanh(double x); +NPY_INPLACE double npy_rint(double x); +NPY_INPLACE double npy_trunc(double x); +NPY_INPLACE double npy_exp2(double x); +NPY_INPLACE double npy_log2(double x); + +NPY_INPLACE double npy_atan2(double x, double y); +NPY_INPLACE double npy_pow(double x, double y); +NPY_INPLACE double npy_modf(double x, double* y); +NPY_INPLACE double npy_frexp(double x, int* y); +NPY_INPLACE double npy_ldexp(double n, int y); + +NPY_INPLACE double npy_copysign(double x, double y); +double npy_nextafter(double x, double y); +double npy_spacing(double x); + +/* + * IEEE 754 fpu handling. Those are guaranteed to be macros + */ + +/* use builtins to avoid function calls in tight loops + * only available if npy_config.h is available (= numpys own build) */ +#if HAVE___BUILTIN_ISNAN + #define npy_isnan(x) __builtin_isnan(x) +#else + #ifndef NPY_HAVE_DECL_ISNAN + #define npy_isnan(x) ((x) != (x)) + #else + #if defined(_MSC_VER) && (_MSC_VER < 1900) + #define npy_isnan(x) _isnan((x)) + #else + #define npy_isnan(x) isnan(x) + #endif + #endif +#endif + + +/* only available if npy_config.h is available (= numpys own build) */ +#if HAVE___BUILTIN_ISFINITE + #define npy_isfinite(x) __builtin_isfinite(x) +#else + #ifndef NPY_HAVE_DECL_ISFINITE + #ifdef _MSC_VER + #define npy_isfinite(x) _finite((x)) + #else + #define npy_isfinite(x) !npy_isnan((x) + (-x)) + #endif + #else + #define npy_isfinite(x) isfinite((x)) + #endif +#endif + +/* only available if npy_config.h is available (= numpys own build) */ +#if HAVE___BUILTIN_ISINF + #define npy_isinf(x) __builtin_isinf(x) +#else + #ifndef NPY_HAVE_DECL_ISINF + #define npy_isinf(x) (!npy_isfinite(x) && !npy_isnan(x)) + #else + #if defined(_MSC_VER) && (_MSC_VER < 1900) + #define npy_isinf(x) (!_finite((x)) && !_isnan((x))) + #else + #define npy_isinf(x) isinf((x)) + #endif + #endif +#endif + +#ifndef NPY_HAVE_DECL_SIGNBIT + int _npy_signbit_f(float x); + int _npy_signbit_d(double x); + int _npy_signbit_ld(long double x); + #define npy_signbit(x) \ + (sizeof (x) == sizeof (long double) ? _npy_signbit_ld (x) \ + : sizeof (x) == sizeof (double) ? _npy_signbit_d (x) \ + : _npy_signbit_f (x)) +#else + #define npy_signbit(x) signbit((x)) +#endif + +/* + * float C99 math functions + */ +NPY_INPLACE float npy_sinf(float x); +NPY_INPLACE float npy_cosf(float x); +NPY_INPLACE float npy_tanf(float x); +NPY_INPLACE float npy_sinhf(float x); +NPY_INPLACE float npy_coshf(float x); +NPY_INPLACE float npy_tanhf(float x); +NPY_INPLACE float npy_fabsf(float x); +NPY_INPLACE float npy_floorf(float x); +NPY_INPLACE float npy_ceilf(float x); +NPY_INPLACE float npy_rintf(float x); +NPY_INPLACE float npy_truncf(float x); +NPY_INPLACE float npy_sqrtf(float x); +NPY_INPLACE float npy_cbrtf(float x); +NPY_INPLACE float npy_log10f(float x); +NPY_INPLACE float npy_logf(float x); +NPY_INPLACE float npy_expf(float x); +NPY_INPLACE float npy_expm1f(float x); +NPY_INPLACE float npy_asinf(float x); +NPY_INPLACE float npy_acosf(float x); +NPY_INPLACE float npy_atanf(float x); +NPY_INPLACE float npy_asinhf(float x); +NPY_INPLACE float npy_acoshf(float x); +NPY_INPLACE float npy_atanhf(float x); +NPY_INPLACE float npy_log1pf(float x); +NPY_INPLACE float npy_exp2f(float x); +NPY_INPLACE float npy_log2f(float x); + +NPY_INPLACE float npy_atan2f(float x, float y); +NPY_INPLACE float npy_hypotf(float x, float y); +NPY_INPLACE float npy_powf(float x, float y); +NPY_INPLACE float npy_fmodf(float x, float y); + +NPY_INPLACE float npy_modff(float x, float* y); +NPY_INPLACE float npy_frexpf(float x, int* y); +NPY_INPLACE float npy_ldexpf(float x, int y); + +NPY_INPLACE float npy_copysignf(float x, float y); +float npy_nextafterf(float x, float y); +float npy_spacingf(float x); + +/* + * long double C99 math functions + */ +NPY_INPLACE npy_longdouble npy_sinl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_cosl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_tanl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_sinhl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_coshl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_tanhl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_fabsl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_floorl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_ceill(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_rintl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_truncl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_sqrtl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_cbrtl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_log10l(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_logl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_expl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_expm1l(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_asinl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_acosl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_atanl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_asinhl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_acoshl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_atanhl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_log1pl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_exp2l(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_log2l(npy_longdouble x); + +NPY_INPLACE npy_longdouble npy_atan2l(npy_longdouble x, npy_longdouble y); +NPY_INPLACE npy_longdouble npy_hypotl(npy_longdouble x, npy_longdouble y); +NPY_INPLACE npy_longdouble npy_powl(npy_longdouble x, npy_longdouble y); +NPY_INPLACE npy_longdouble npy_fmodl(npy_longdouble x, npy_longdouble y); + +NPY_INPLACE npy_longdouble npy_modfl(npy_longdouble x, npy_longdouble* y); +NPY_INPLACE npy_longdouble npy_frexpl(npy_longdouble x, int* y); +NPY_INPLACE npy_longdouble npy_ldexpl(npy_longdouble x, int y); + +NPY_INPLACE npy_longdouble npy_copysignl(npy_longdouble x, npy_longdouble y); +npy_longdouble npy_nextafterl(npy_longdouble x, npy_longdouble y); +npy_longdouble npy_spacingl(npy_longdouble x); + +/* + * Non standard functions + */ +NPY_INPLACE double npy_deg2rad(double x); +NPY_INPLACE double npy_rad2deg(double x); +NPY_INPLACE double npy_logaddexp(double x, double y); +NPY_INPLACE double npy_logaddexp2(double x, double y); +NPY_INPLACE double npy_divmod(double x, double y, double *modulus); +NPY_INPLACE double npy_heaviside(double x, double h0); + +NPY_INPLACE float npy_deg2radf(float x); +NPY_INPLACE float npy_rad2degf(float x); +NPY_INPLACE float npy_logaddexpf(float x, float y); +NPY_INPLACE float npy_logaddexp2f(float x, float y); +NPY_INPLACE float npy_divmodf(float x, float y, float *modulus); +NPY_INPLACE float npy_heavisidef(float x, float h0); + +NPY_INPLACE npy_longdouble npy_deg2radl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_rad2degl(npy_longdouble x); +NPY_INPLACE npy_longdouble npy_logaddexpl(npy_longdouble x, npy_longdouble y); +NPY_INPLACE npy_longdouble npy_logaddexp2l(npy_longdouble x, npy_longdouble y); +NPY_INPLACE npy_longdouble npy_divmodl(npy_longdouble x, npy_longdouble y, + npy_longdouble *modulus); +NPY_INPLACE npy_longdouble npy_heavisidel(npy_longdouble x, npy_longdouble h0); + +#define npy_degrees npy_rad2deg +#define npy_degreesf npy_rad2degf +#define npy_degreesl npy_rad2degl + +#define npy_radians npy_deg2rad +#define npy_radiansf npy_deg2radf +#define npy_radiansl npy_deg2radl + +/* + * Complex declarations + */ + +/* + * C99 specifies that complex numbers have the same representation as + * an array of two elements, where the first element is the real part + * and the second element is the imaginary part. + */ +#define __NPY_CPACK_IMP(x, y, type, ctype) \ + union { \ + ctype z; \ + type a[2]; \ + } z1;; \ + \ + z1.a[0] = (x); \ + z1.a[1] = (y); \ + \ + return z1.z; + +static NPY_INLINE npy_cdouble npy_cpack(double x, double y) +{ + __NPY_CPACK_IMP(x, y, double, npy_cdouble); +} + +static NPY_INLINE npy_cfloat npy_cpackf(float x, float y) +{ + __NPY_CPACK_IMP(x, y, float, npy_cfloat); +} + +static NPY_INLINE npy_clongdouble npy_cpackl(npy_longdouble x, npy_longdouble y) +{ + __NPY_CPACK_IMP(x, y, npy_longdouble, npy_clongdouble); +} +#undef __NPY_CPACK_IMP + +/* + * Same remark as above, but in the other direction: extract first/second + * member of complex number, assuming a C99-compatible representation + * + * Those are defineds as static inline, and such as a reasonable compiler would + * most likely compile this to one or two instructions (on CISC at least) + */ +#define __NPY_CEXTRACT_IMP(z, index, type, ctype) \ + union { \ + ctype z; \ + type a[2]; \ + } __z_repr; \ + __z_repr.z = z; \ + \ + return __z_repr.a[index]; + +static NPY_INLINE double npy_creal(npy_cdouble z) +{ + __NPY_CEXTRACT_IMP(z, 0, double, npy_cdouble); +} + +static NPY_INLINE double npy_cimag(npy_cdouble z) +{ + __NPY_CEXTRACT_IMP(z, 1, double, npy_cdouble); +} + +static NPY_INLINE float npy_crealf(npy_cfloat z) +{ + __NPY_CEXTRACT_IMP(z, 0, float, npy_cfloat); +} + +static NPY_INLINE float npy_cimagf(npy_cfloat z) +{ + __NPY_CEXTRACT_IMP(z, 1, float, npy_cfloat); +} + +static NPY_INLINE npy_longdouble npy_creall(npy_clongdouble z) +{ + __NPY_CEXTRACT_IMP(z, 0, npy_longdouble, npy_clongdouble); +} + +static NPY_INLINE npy_longdouble npy_cimagl(npy_clongdouble z) +{ + __NPY_CEXTRACT_IMP(z, 1, npy_longdouble, npy_clongdouble); +} +#undef __NPY_CEXTRACT_IMP + +/* + * Double precision complex functions + */ +double npy_cabs(npy_cdouble z); +double npy_carg(npy_cdouble z); + +npy_cdouble npy_cexp(npy_cdouble z); +npy_cdouble npy_clog(npy_cdouble z); +npy_cdouble npy_cpow(npy_cdouble x, npy_cdouble y); + +npy_cdouble npy_csqrt(npy_cdouble z); + +npy_cdouble npy_ccos(npy_cdouble z); +npy_cdouble npy_csin(npy_cdouble z); +npy_cdouble npy_ctan(npy_cdouble z); + +npy_cdouble npy_ccosh(npy_cdouble z); +npy_cdouble npy_csinh(npy_cdouble z); +npy_cdouble npy_ctanh(npy_cdouble z); + +npy_cdouble npy_cacos(npy_cdouble z); +npy_cdouble npy_casin(npy_cdouble z); +npy_cdouble npy_catan(npy_cdouble z); + +npy_cdouble npy_cacosh(npy_cdouble z); +npy_cdouble npy_casinh(npy_cdouble z); +npy_cdouble npy_catanh(npy_cdouble z); + +/* + * Single precision complex functions + */ +float npy_cabsf(npy_cfloat z); +float npy_cargf(npy_cfloat z); + +npy_cfloat npy_cexpf(npy_cfloat z); +npy_cfloat npy_clogf(npy_cfloat z); +npy_cfloat npy_cpowf(npy_cfloat x, npy_cfloat y); + +npy_cfloat npy_csqrtf(npy_cfloat z); + +npy_cfloat npy_ccosf(npy_cfloat z); +npy_cfloat npy_csinf(npy_cfloat z); +npy_cfloat npy_ctanf(npy_cfloat z); + +npy_cfloat npy_ccoshf(npy_cfloat z); +npy_cfloat npy_csinhf(npy_cfloat z); +npy_cfloat npy_ctanhf(npy_cfloat z); + +npy_cfloat npy_cacosf(npy_cfloat z); +npy_cfloat npy_casinf(npy_cfloat z); +npy_cfloat npy_catanf(npy_cfloat z); + +npy_cfloat npy_cacoshf(npy_cfloat z); +npy_cfloat npy_casinhf(npy_cfloat z); +npy_cfloat npy_catanhf(npy_cfloat z); + + +/* + * Extended precision complex functions + */ +npy_longdouble npy_cabsl(npy_clongdouble z); +npy_longdouble npy_cargl(npy_clongdouble z); + +npy_clongdouble npy_cexpl(npy_clongdouble z); +npy_clongdouble npy_clogl(npy_clongdouble z); +npy_clongdouble npy_cpowl(npy_clongdouble x, npy_clongdouble y); + +npy_clongdouble npy_csqrtl(npy_clongdouble z); + +npy_clongdouble npy_ccosl(npy_clongdouble z); +npy_clongdouble npy_csinl(npy_clongdouble z); +npy_clongdouble npy_ctanl(npy_clongdouble z); + +npy_clongdouble npy_ccoshl(npy_clongdouble z); +npy_clongdouble npy_csinhl(npy_clongdouble z); +npy_clongdouble npy_ctanhl(npy_clongdouble z); + +npy_clongdouble npy_cacosl(npy_clongdouble z); +npy_clongdouble npy_casinl(npy_clongdouble z); +npy_clongdouble npy_catanl(npy_clongdouble z); + +npy_clongdouble npy_cacoshl(npy_clongdouble z); +npy_clongdouble npy_casinhl(npy_clongdouble z); +npy_clongdouble npy_catanhl(npy_clongdouble z); + + +/* + * Functions that set the floating point error + * status word. + */ + +/* + * platform-dependent code translates floating point + * status to an integer sum of these values + */ +#define NPY_FPE_DIVIDEBYZERO 1 +#define NPY_FPE_OVERFLOW 2 +#define NPY_FPE_UNDERFLOW 4 +#define NPY_FPE_INVALID 8 + +int npy_get_floatstatus(void); +int npy_clear_floatstatus(void); +void npy_set_floatstatus_divbyzero(void); +void npy_set_floatstatus_overflow(void); +void npy_set_floatstatus_underflow(void); +void npy_set_floatstatus_invalid(void); + +#ifdef __cplusplus +} +#endif + +#if NPY_INLINE_MATH +#include "npy_math_internal.h" +#endif + +#endif diff --git a/numpy/core/include/numpy/npy_no_deprecated_api.h b/numpy/core/include/numpy/npy_no_deprecated_api.h new file mode 100644 index 0000000..6183dc2 --- /dev/null +++ b/numpy/core/include/numpy/npy_no_deprecated_api.h @@ -0,0 +1,19 @@ +/* + * This include file is provided for inclusion in Cython *.pyd files where + * one would like to define the NPY_NO_DEPRECATED_API macro. It can be + * included by + * + * cdef extern from "npy_no_deprecated_api.h": pass + * + */ +#ifndef NPY_NO_DEPRECATED_API + +/* put this check here since there may be multiple includes in C extensions. */ +#if defined(NDARRAYTYPES_H) || defined(_NPY_DEPRECATED_API_H) || \ + defined(OLD_DEFINES_H) +#error "npy_no_deprecated_api.h" must be first among numpy includes. +#else +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#endif + +#endif diff --git a/numpy/core/include/numpy/npy_os.h b/numpy/core/include/numpy/npy_os.h new file mode 100644 index 0000000..9228c39 --- /dev/null +++ b/numpy/core/include/numpy/npy_os.h @@ -0,0 +1,30 @@ +#ifndef _NPY_OS_H_ +#define _NPY_OS_H_ + +#if defined(linux) || defined(__linux) || defined(__linux__) + #define NPY_OS_LINUX +#elif defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__OpenBSD__) || defined(__DragonFly__) + #define NPY_OS_BSD + #ifdef __FreeBSD__ + #define NPY_OS_FREEBSD + #elif defined(__NetBSD__) + #define NPY_OS_NETBSD + #elif defined(__OpenBSD__) + #define NPY_OS_OPENBSD + #elif defined(__DragonFly__) + #define NPY_OS_DRAGONFLY + #endif +#elif defined(sun) || defined(__sun) + #define NPY_OS_SOLARIS +#elif defined(__CYGWIN__) + #define NPY_OS_CYGWIN +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define NPY_OS_WIN32 +#elif defined(__APPLE__) + #define NPY_OS_DARWIN +#else + #define NPY_OS_UNKNOWN +#endif + +#endif diff --git a/numpy/core/include/numpy/numpyconfig.h b/numpy/core/include/numpy/numpyconfig.h new file mode 100644 index 0000000..04a3738 --- /dev/null +++ b/numpy/core/include/numpy/numpyconfig.h @@ -0,0 +1,40 @@ +#ifndef _NPY_NUMPYCONFIG_H_ +#define _NPY_NUMPYCONFIG_H_ + +#include "_numpyconfig.h" + +/* + * On Mac OS X, because there is only one configuration stage for all the archs + * in universal builds, any macro which depends on the arch needs to be + * hardcoded + */ +#ifdef __APPLE__ + #undef NPY_SIZEOF_LONG + #undef NPY_SIZEOF_PY_INTPTR_T + + #ifdef __LP64__ + #define NPY_SIZEOF_LONG 8 + #define NPY_SIZEOF_PY_INTPTR_T 8 + #else + #define NPY_SIZEOF_LONG 4 + #define NPY_SIZEOF_PY_INTPTR_T 4 + #endif +#endif + +/** + * To help with the NPY_NO_DEPRECATED_API macro, we include API version + * numbers for specific versions of NumPy. To exclude all API that was + * deprecated as of 1.7, add the following before #including any NumPy + * headers: + * #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION + */ +#define NPY_1_7_API_VERSION 0x00000007 +#define NPY_1_8_API_VERSION 0x00000008 +#define NPY_1_9_API_VERSION 0x00000008 +#define NPY_1_10_API_VERSION 0x00000008 +#define NPY_1_11_API_VERSION 0x00000008 +#define NPY_1_12_API_VERSION 0x00000008 +#define NPY_1_13_API_VERSION 0x00000008 +#define NPY_1_14_API_VERSION 0x00000008 + +#endif diff --git a/numpy/core/include/numpy/old_defines.h b/numpy/core/include/numpy/old_defines.h new file mode 100644 index 0000000..abf8159 --- /dev/null +++ b/numpy/core/include/numpy/old_defines.h @@ -0,0 +1,187 @@ +/* This header is deprecated as of NumPy 1.7 */ +#ifndef OLD_DEFINES_H +#define OLD_DEFINES_H + +#if defined(NPY_NO_DEPRECATED_API) && NPY_NO_DEPRECATED_API >= NPY_1_7_API_VERSION +#error The header "old_defines.h" is deprecated as of NumPy 1.7. +#endif + +#define NDARRAY_VERSION NPY_VERSION + +#define PyArray_MIN_BUFSIZE NPY_MIN_BUFSIZE +#define PyArray_MAX_BUFSIZE NPY_MAX_BUFSIZE +#define PyArray_BUFSIZE NPY_BUFSIZE + +#define PyArray_PRIORITY NPY_PRIORITY +#define PyArray_SUBTYPE_PRIORITY NPY_PRIORITY +#define PyArray_NUM_FLOATTYPE NPY_NUM_FLOATTYPE + +#define NPY_MAX PyArray_MAX +#define NPY_MIN PyArray_MIN + +#define PyArray_TYPES NPY_TYPES +#define PyArray_BOOL NPY_BOOL +#define PyArray_BYTE NPY_BYTE +#define PyArray_UBYTE NPY_UBYTE +#define PyArray_SHORT NPY_SHORT +#define PyArray_USHORT NPY_USHORT +#define PyArray_INT NPY_INT +#define PyArray_UINT NPY_UINT +#define PyArray_LONG NPY_LONG +#define PyArray_ULONG NPY_ULONG +#define PyArray_LONGLONG NPY_LONGLONG +#define PyArray_ULONGLONG NPY_ULONGLONG +#define PyArray_HALF NPY_HALF +#define PyArray_FLOAT NPY_FLOAT +#define PyArray_DOUBLE NPY_DOUBLE +#define PyArray_LONGDOUBLE NPY_LONGDOUBLE +#define PyArray_CFLOAT NPY_CFLOAT +#define PyArray_CDOUBLE NPY_CDOUBLE +#define PyArray_CLONGDOUBLE NPY_CLONGDOUBLE +#define PyArray_OBJECT NPY_OBJECT +#define PyArray_STRING NPY_STRING +#define PyArray_UNICODE NPY_UNICODE +#define PyArray_VOID NPY_VOID +#define PyArray_DATETIME NPY_DATETIME +#define PyArray_TIMEDELTA NPY_TIMEDELTA +#define PyArray_NTYPES NPY_NTYPES +#define PyArray_NOTYPE NPY_NOTYPE +#define PyArray_CHAR NPY_CHAR +#define PyArray_USERDEF NPY_USERDEF +#define PyArray_NUMUSERTYPES NPY_NUMUSERTYPES + +#define PyArray_INTP NPY_INTP +#define PyArray_UINTP NPY_UINTP + +#define PyArray_INT8 NPY_INT8 +#define PyArray_UINT8 NPY_UINT8 +#define PyArray_INT16 NPY_INT16 +#define PyArray_UINT16 NPY_UINT16 +#define PyArray_INT32 NPY_INT32 +#define PyArray_UINT32 NPY_UINT32 + +#ifdef NPY_INT64 +#define PyArray_INT64 NPY_INT64 +#define PyArray_UINT64 NPY_UINT64 +#endif + +#ifdef NPY_INT128 +#define PyArray_INT128 NPY_INT128 +#define PyArray_UINT128 NPY_UINT128 +#endif + +#ifdef NPY_FLOAT16 +#define PyArray_FLOAT16 NPY_FLOAT16 +#define PyArray_COMPLEX32 NPY_COMPLEX32 +#endif + +#ifdef NPY_FLOAT80 +#define PyArray_FLOAT80 NPY_FLOAT80 +#define PyArray_COMPLEX160 NPY_COMPLEX160 +#endif + +#ifdef NPY_FLOAT96 +#define PyArray_FLOAT96 NPY_FLOAT96 +#define PyArray_COMPLEX192 NPY_COMPLEX192 +#endif + +#ifdef NPY_FLOAT128 +#define PyArray_FLOAT128 NPY_FLOAT128 +#define PyArray_COMPLEX256 NPY_COMPLEX256 +#endif + +#define PyArray_FLOAT32 NPY_FLOAT32 +#define PyArray_COMPLEX64 NPY_COMPLEX64 +#define PyArray_FLOAT64 NPY_FLOAT64 +#define PyArray_COMPLEX128 NPY_COMPLEX128 + + +#define PyArray_TYPECHAR NPY_TYPECHAR +#define PyArray_BOOLLTR NPY_BOOLLTR +#define PyArray_BYTELTR NPY_BYTELTR +#define PyArray_UBYTELTR NPY_UBYTELTR +#define PyArray_SHORTLTR NPY_SHORTLTR +#define PyArray_USHORTLTR NPY_USHORTLTR +#define PyArray_INTLTR NPY_INTLTR +#define PyArray_UINTLTR NPY_UINTLTR +#define PyArray_LONGLTR NPY_LONGLTR +#define PyArray_ULONGLTR NPY_ULONGLTR +#define PyArray_LONGLONGLTR NPY_LONGLONGLTR +#define PyArray_ULONGLONGLTR NPY_ULONGLONGLTR +#define PyArray_HALFLTR NPY_HALFLTR +#define PyArray_FLOATLTR NPY_FLOATLTR +#define PyArray_DOUBLELTR NPY_DOUBLELTR +#define PyArray_LONGDOUBLELTR NPY_LONGDOUBLELTR +#define PyArray_CFLOATLTR NPY_CFLOATLTR +#define PyArray_CDOUBLELTR NPY_CDOUBLELTR +#define PyArray_CLONGDOUBLELTR NPY_CLONGDOUBLELTR +#define PyArray_OBJECTLTR NPY_OBJECTLTR +#define PyArray_STRINGLTR NPY_STRINGLTR +#define PyArray_STRINGLTR2 NPY_STRINGLTR2 +#define PyArray_UNICODELTR NPY_UNICODELTR +#define PyArray_VOIDLTR NPY_VOIDLTR +#define PyArray_DATETIMELTR NPY_DATETIMELTR +#define PyArray_TIMEDELTALTR NPY_TIMEDELTALTR +#define PyArray_CHARLTR NPY_CHARLTR +#define PyArray_INTPLTR NPY_INTPLTR +#define PyArray_UINTPLTR NPY_UINTPLTR +#define PyArray_GENBOOLLTR NPY_GENBOOLLTR +#define PyArray_SIGNEDLTR NPY_SIGNEDLTR +#define PyArray_UNSIGNEDLTR NPY_UNSIGNEDLTR +#define PyArray_FLOATINGLTR NPY_FLOATINGLTR +#define PyArray_COMPLEXLTR NPY_COMPLEXLTR + +#define PyArray_QUICKSORT NPY_QUICKSORT +#define PyArray_HEAPSORT NPY_HEAPSORT +#define PyArray_MERGESORT NPY_MERGESORT +#define PyArray_SORTKIND NPY_SORTKIND +#define PyArray_NSORTS NPY_NSORTS + +#define PyArray_NOSCALAR NPY_NOSCALAR +#define PyArray_BOOL_SCALAR NPY_BOOL_SCALAR +#define PyArray_INTPOS_SCALAR NPY_INTPOS_SCALAR +#define PyArray_INTNEG_SCALAR NPY_INTNEG_SCALAR +#define PyArray_FLOAT_SCALAR NPY_FLOAT_SCALAR +#define PyArray_COMPLEX_SCALAR NPY_COMPLEX_SCALAR +#define PyArray_OBJECT_SCALAR NPY_OBJECT_SCALAR +#define PyArray_SCALARKIND NPY_SCALARKIND +#define PyArray_NSCALARKINDS NPY_NSCALARKINDS + +#define PyArray_ANYORDER NPY_ANYORDER +#define PyArray_CORDER NPY_CORDER +#define PyArray_FORTRANORDER NPY_FORTRANORDER +#define PyArray_ORDER NPY_ORDER + +#define PyDescr_ISBOOL PyDataType_ISBOOL +#define PyDescr_ISUNSIGNED PyDataType_ISUNSIGNED +#define PyDescr_ISSIGNED PyDataType_ISSIGNED +#define PyDescr_ISINTEGER PyDataType_ISINTEGER +#define PyDescr_ISFLOAT PyDataType_ISFLOAT +#define PyDescr_ISNUMBER PyDataType_ISNUMBER +#define PyDescr_ISSTRING PyDataType_ISSTRING +#define PyDescr_ISCOMPLEX PyDataType_ISCOMPLEX +#define PyDescr_ISPYTHON PyDataType_ISPYTHON +#define PyDescr_ISFLEXIBLE PyDataType_ISFLEXIBLE +#define PyDescr_ISUSERDEF PyDataType_ISUSERDEF +#define PyDescr_ISEXTENDED PyDataType_ISEXTENDED +#define PyDescr_ISOBJECT PyDataType_ISOBJECT +#define PyDescr_HASFIELDS PyDataType_HASFIELDS + +#define PyArray_LITTLE NPY_LITTLE +#define PyArray_BIG NPY_BIG +#define PyArray_NATIVE NPY_NATIVE +#define PyArray_SWAP NPY_SWAP +#define PyArray_IGNORE NPY_IGNORE + +#define PyArray_NATBYTE NPY_NATBYTE +#define PyArray_OPPBYTE NPY_OPPBYTE + +#define PyArray_MAX_ELSIZE NPY_MAX_ELSIZE + +#define PyArray_USE_PYMEM NPY_USE_PYMEM + +#define PyArray_RemoveLargest PyArray_RemoveSmallest + +#define PyArray_UCS4 npy_ucs4 + +#endif diff --git a/numpy/core/include/numpy/oldnumeric.h b/numpy/core/include/numpy/oldnumeric.h new file mode 100644 index 0000000..38530fa --- /dev/null +++ b/numpy/core/include/numpy/oldnumeric.h @@ -0,0 +1,25 @@ +#include "arrayobject.h" + +#ifndef PYPY_VERSION +#ifndef REFCOUNT +# define REFCOUNT NPY_REFCOUNT +# define MAX_ELSIZE 16 +#endif +#endif + +#define PyArray_UNSIGNED_TYPES +#define PyArray_SBYTE NPY_BYTE +#define PyArray_CopyArray PyArray_CopyInto +#define _PyArray_multiply_list PyArray_MultiplyIntList +#define PyArray_ISSPACESAVER(m) NPY_FALSE +#define PyScalarArray_Check PyArray_CheckScalar + +#define CONTIGUOUS NPY_CONTIGUOUS +#define OWN_DIMENSIONS 0 +#define OWN_STRIDES 0 +#define OWN_DATA NPY_OWNDATA +#define SAVESPACE 0 +#define SAVESPACEBIT 0 + +#undef import_array +#define import_array() { if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); } } diff --git a/numpy/core/include/numpy/ufuncobject.h b/numpy/core/include/numpy/ufuncobject.h new file mode 100644 index 0000000..d0ac1fd --- /dev/null +++ b/numpy/core/include/numpy/ufuncobject.h @@ -0,0 +1,363 @@ +#ifndef Py_UFUNCOBJECT_H +#define Py_UFUNCOBJECT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The legacy generic inner loop for a standard element-wise or + * generalized ufunc. + */ +typedef void (*PyUFuncGenericFunction) + (char **args, + npy_intp *dimensions, + npy_intp *strides, + void *innerloopdata); + +/* + * The most generic one-dimensional inner loop for + * a masked standard element-wise ufunc. "Masked" here means that it skips + * doing calculations on any items for which the maskptr array has a true + * value. + */ +typedef void (PyUFunc_MaskedStridedInnerLoopFunc)( + char **dataptrs, npy_intp *strides, + char *maskptr, npy_intp mask_stride, + npy_intp count, + NpyAuxData *innerloopdata); + +/* Forward declaration for the type resolver and loop selector typedefs */ +struct _tagPyUFuncObject; + +/* + * Given the operands for calling a ufunc, should determine the + * calculation input and output data types and return an inner loop function. + * This function should validate that the casting rule is being followed, + * and fail if it is not. + * + * For backwards compatibility, the regular type resolution function does not + * support auxiliary data with object semantics. The type resolution call + * which returns a masked generic function returns a standard NpyAuxData + * object, for which the NPY_AUXDATA_FREE and NPY_AUXDATA_CLONE macros + * work. + * + * ufunc: The ufunc object. + * casting: The 'casting' parameter provided to the ufunc. + * operands: An array of length (ufunc->nin + ufunc->nout), + * with the output parameters possibly NULL. + * type_tup: Either NULL, or the type_tup passed to the ufunc. + * out_dtypes: An array which should be populated with new + * references to (ufunc->nin + ufunc->nout) new + * dtypes, one for each input and output. These + * dtypes should all be in native-endian format. + * + * Should return 0 on success, -1 on failure (with exception set), + * or -2 if Py_NotImplemented should be returned. + */ +typedef int (PyUFunc_TypeResolutionFunc)( + struct _tagPyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +/* + * Given an array of DTypes as returned by the PyUFunc_TypeResolutionFunc, + * and an array of fixed strides (the array will contain NPY_MAX_INTP for + * strides which are not necessarily fixed), returns an inner loop + * with associated auxiliary data. + * + * For backwards compatibility, there is a variant of the inner loop + * selection which returns an inner loop irrespective of the strides, + * and with a void* static auxiliary data instead of an NpyAuxData * + * dynamically allocatable auxiliary data. + * + * ufunc: The ufunc object. + * dtypes: An array which has been populated with dtypes, + * in most cases by the type resolution function + * for the same ufunc. + * fixed_strides: For each input/output, either the stride that + * will be used every time the function is called + * or NPY_MAX_INTP if the stride might change or + * is not known ahead of time. The loop selection + * function may use this stride to pick inner loops + * which are optimized for contiguous or 0-stride + * cases. + * out_innerloop: Should be populated with the correct ufunc inner + * loop for the given type. + * out_innerloopdata: Should be populated with the void* data to + * be passed into the out_innerloop function. + * out_needs_api: If the inner loop needs to use the Python API, + * should set the to 1, otherwise should leave + * this untouched. + */ +typedef int (PyUFunc_LegacyInnerLoopSelectionFunc)( + struct _tagPyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyUFuncGenericFunction *out_innerloop, + void **out_innerloopdata, + int *out_needs_api); +typedef int (PyUFunc_MaskedInnerLoopSelectionFunc)( + struct _tagPyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyArray_Descr *mask_dtype, + npy_intp *fixed_strides, + npy_intp fixed_mask_stride, + PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop, + NpyAuxData **out_innerloopdata, + int *out_needs_api); + +typedef struct _tagPyUFuncObject { + PyObject_HEAD + /* + * nin: Number of inputs + * nout: Number of outputs + * nargs: Always nin + nout (Why is it stored?) + */ + int nin, nout, nargs; + + /* Identity for reduction, either PyUFunc_One or PyUFunc_Zero */ + int identity; + + /* Array of one-dimensional core loops */ + PyUFuncGenericFunction *functions; + /* Array of funcdata that gets passed into the functions */ + void **data; + /* The number of elements in 'functions' and 'data' */ + int ntypes; + + /* Used to be unused field 'check_return' */ + int reserved1; + + /* The name of the ufunc */ + const char *name; + + /* Array of type numbers, of size ('nargs' * 'ntypes') */ + char *types; + + /* Documentation string */ + const char *doc; + + void *ptr; + PyObject *obj; + PyObject *userloops; + + /* generalized ufunc parameters */ + + /* 0 for scalar ufunc; 1 for generalized ufunc */ + int core_enabled; + /* number of distinct dimension names in signature */ + int core_num_dim_ix; + + /* + * dimension indices of input/output argument k are stored in + * core_dim_ixs[core_offsets[k]..core_offsets[k]+core_num_dims[k]-1] + */ + + /* numbers of core dimensions of each argument */ + int *core_num_dims; + /* + * dimension indices in a flatted form; indices + * are in the range of [0,core_num_dim_ix) + */ + int *core_dim_ixs; + /* + * positions of 1st core dimensions of each + * argument in core_dim_ixs + */ + int *core_offsets; + /* signature string for printing purpose */ + char *core_signature; + + /* + * A function which resolves the types and fills an array + * with the dtypes for the inputs and outputs. + */ + PyUFunc_TypeResolutionFunc *type_resolver; + /* + * A function which returns an inner loop written for + * NumPy 1.6 and earlier ufuncs. This is for backwards + * compatibility, and may be NULL if inner_loop_selector + * is specified. + */ + PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector; + /* + * This was blocked off to be the "new" inner loop selector in 1.7, + * but this was never implemented. (This is also why the above + * selector is called the "legacy" selector.) + */ + void *reserved2; + /* + * A function which returns a masked inner loop for the ufunc. + */ + PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector; + + /* + * List of flags for each operand when ufunc is called by nditer object. + * These flags will be used in addition to the default flags for each + * operand set by nditer object. + */ + npy_uint32 *op_flags; + + /* + * List of global flags used when ufunc is called by nditer object. + * These flags will be used in addition to the default global flags + * set by nditer object. + */ + npy_uint32 iter_flags; +} PyUFuncObject; + +#include "arrayobject.h" + +#define UFUNC_ERR_IGNORE 0 +#define UFUNC_ERR_WARN 1 +#define UFUNC_ERR_RAISE 2 +#define UFUNC_ERR_CALL 3 +#define UFUNC_ERR_PRINT 4 +#define UFUNC_ERR_LOG 5 + + /* Python side integer mask */ + +#define UFUNC_MASK_DIVIDEBYZERO 0x07 +#define UFUNC_MASK_OVERFLOW 0x3f +#define UFUNC_MASK_UNDERFLOW 0x1ff +#define UFUNC_MASK_INVALID 0xfff + +#define UFUNC_SHIFT_DIVIDEBYZERO 0 +#define UFUNC_SHIFT_OVERFLOW 3 +#define UFUNC_SHIFT_UNDERFLOW 6 +#define UFUNC_SHIFT_INVALID 9 + + +#define UFUNC_OBJ_ISOBJECT 1 +#define UFUNC_OBJ_NEEDS_API 2 + + /* Default user error mode */ +#define UFUNC_ERR_DEFAULT \ + (UFUNC_ERR_WARN << UFUNC_SHIFT_DIVIDEBYZERO) + \ + (UFUNC_ERR_WARN << UFUNC_SHIFT_OVERFLOW) + \ + (UFUNC_ERR_WARN << UFUNC_SHIFT_INVALID) + +#if NPY_ALLOW_THREADS +#define NPY_LOOP_BEGIN_THREADS do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) _save = PyEval_SaveThread();} while (0); +#define NPY_LOOP_END_THREADS do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) PyEval_RestoreThread(_save);} while (0); +#else +#define NPY_LOOP_BEGIN_THREADS +#define NPY_LOOP_END_THREADS +#endif + +/* + * UFunc has unit of 0, and the order of operations can be reordered + * This case allows reduction with multiple axes at once. + */ +#define PyUFunc_Zero 0 +/* + * UFunc has unit of 1, and the order of operations can be reordered + * This case allows reduction with multiple axes at once. + */ +#define PyUFunc_One 1 +/* + * UFunc has unit of -1, and the order of operations can be reordered + * This case allows reduction with multiple axes at once. Intended for + * bitwise_and reduction. + */ +#define PyUFunc_MinusOne 2 +/* + * UFunc has no unit, and the order of operations cannot be reordered. + * This case does not allow reduction with multiple axes at once. + */ +#define PyUFunc_None -1 +/* + * UFunc has no unit, and the order of operations can be reordered + * This case allows reduction with multiple axes at once. + */ +#define PyUFunc_ReorderableNone -2 + +#define UFUNC_REDUCE 0 +#define UFUNC_ACCUMULATE 1 +#define UFUNC_REDUCEAT 2 +#define UFUNC_OUTER 3 + + +typedef struct { + int nin; + int nout; + PyObject *callable; +} PyUFunc_PyFuncData; + +/* A linked-list of function information for + user-defined 1-d loops. + */ +typedef struct _loop1d_info { + PyUFuncGenericFunction func; + void *data; + int *arg_types; + struct _loop1d_info *next; + int nargs; + PyArray_Descr **arg_dtypes; +} PyUFunc_Loop1d; + + +#include "__ufunc_api.h" + +#define UFUNC_PYVALS_NAME "UFUNC_PYVALS" + +#define UFUNC_CHECK_ERROR(arg) \ + do {if ((((arg)->obj & UFUNC_OBJ_NEEDS_API) && PyErr_Occurred()) || \ + ((arg)->errormask && \ + PyUFunc_checkfperr((arg)->errormask, \ + (arg)->errobj, \ + &(arg)->first))) \ + goto fail;} while (0) + + +/* keep in sync with ieee754.c.src */ +#if defined(sun) || defined(__BSD__) || defined(__OpenBSD__) || \ + (defined(__FreeBSD__) && (__FreeBSD_version < 502114)) || \ + defined(__NetBSD__) || \ + defined(__GLIBC__) || defined(__APPLE__) || \ + defined(__CYGWIN__) || defined(__MINGW32__) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 502114)) || \ + defined(_AIX) || \ + defined(_MSC_VER) || \ + defined(__osf__) && defined(__alpha) +#else +#define NO_FLOATING_POINT_SUPPORT +#endif + + +/* + * THESE MACROS ARE DEPRECATED. + * Use npy_set_floatstatus_* in the npymath library. + */ +#define UFUNC_FPE_DIVIDEBYZERO NPY_FPE_DIVIDEBYZERO +#define UFUNC_FPE_OVERFLOW NPY_FPE_OVERFLOW +#define UFUNC_FPE_UNDERFLOW NPY_FPE_UNDERFLOW +#define UFUNC_FPE_INVALID NPY_FPE_INVALID + +#define UFUNC_CHECK_STATUS(ret) \ + { \ + ret = npy_clear_floatstatus(); \ + } +#define generate_divbyzero_error() npy_set_floatstatus_divbyzero() +#define generate_overflow_error() npy_set_floatstatus_overflow() + + /* Make sure it gets defined if it isn't already */ +#ifndef UFUNC_NOFPE +/* Clear the floating point exception default of Borland C++ */ +#if defined(__BORLANDC__) +#define UFUNC_NOFPE _control87(MCW_EM, MCW_EM); +#else +#define UFUNC_NOFPE +#endif +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_UFUNCOBJECT_H */ diff --git a/numpy/core/include/numpy/utils.h b/numpy/core/include/numpy/utils.h new file mode 100644 index 0000000..cc968a3 --- /dev/null +++ b/numpy/core/include/numpy/utils.h @@ -0,0 +1,19 @@ +#ifndef __NUMPY_UTILS_HEADER__ +#define __NUMPY_UTILS_HEADER__ + +#ifndef __COMP_NPY_UNUSED + #if defined(__GNUC__) + #define __COMP_NPY_UNUSED __attribute__ ((__unused__)) + # elif defined(__ICC) + #define __COMP_NPY_UNUSED __attribute__ ((__unused__)) + #else + #define __COMP_NPY_UNUSED + #endif +#endif + +/* Use this to tag a variable as not used. It will remove unused variable + * warning on support platforms (see __COM_NPY_UNUSED) and mangle the variable + * to avoid accidental use */ +#define NPY_UNUSED(x) (__NPY_UNUSED_TAGGED ## x) __COMP_NPY_UNUSED + +#endif diff --git a/numpy/core/info.py b/numpy/core/info.py new file mode 100644 index 0000000..c6f7bbc --- /dev/null +++ b/numpy/core/info.py @@ -0,0 +1,87 @@ +"""Defines a multi-dimensional array and useful procedures for Numerical computation. + +Functions + +- array - NumPy Array construction +- zeros - Return an array of all zeros +- empty - Return an uninitialized array +- shape - Return shape of sequence or array +- rank - Return number of dimensions +- size - Return number of elements in entire array or a + certain dimension +- fromstring - Construct array from (byte) string +- take - Select sub-arrays using sequence of indices +- put - Set sub-arrays using sequence of 1-D indices +- putmask - Set portion of arrays using a mask +- reshape - Return array with new shape +- repeat - Repeat elements of array +- choose - Construct new array from indexed array tuple +- correlate - Correlate two 1-d arrays +- searchsorted - Search for element in 1-d array +- sum - Total sum over a specified dimension +- average - Average, possibly weighted, over axis or array. +- cumsum - Cumulative sum over a specified dimension +- product - Total product over a specified dimension +- cumproduct - Cumulative product over a specified dimension +- alltrue - Logical and over an entire axis +- sometrue - Logical or over an entire axis +- allclose - Tests if sequences are essentially equal + +More Functions: + +- arange - Return regularly spaced array +- asarray - Guarantee NumPy array +- convolve - Convolve two 1-d arrays +- swapaxes - Exchange axes +- concatenate - Join arrays together +- transpose - Permute axes +- sort - Sort elements of array +- argsort - Indices of sorted array +- argmax - Index of largest value +- argmin - Index of smallest value +- inner - Innerproduct of two arrays +- dot - Dot product (matrix multiplication) +- outer - Outerproduct of two arrays +- resize - Return array with arbitrary new shape +- indices - Tuple of indices +- fromfunction - Construct array from universal function +- diagonal - Return diagonal array +- trace - Trace of array +- dump - Dump array to file object (pickle) +- dumps - Return pickled string representing data +- load - Return array stored in file object +- loads - Return array from pickled string +- ravel - Return array as 1-D +- nonzero - Indices of nonzero elements for 1-D array +- shape - Shape of array +- where - Construct array from binary result +- compress - Elements of array where condition is true +- clip - Clip array between two values +- ones - Array of all ones +- identity - 2-D identity array (matrix) + +(Universal) Math Functions + + add logical_or exp + subtract logical_xor log + multiply logical_not log10 + divide maximum sin + divide_safe minimum sinh + conjugate bitwise_and sqrt + power bitwise_or tan + absolute bitwise_xor tanh + negative invert ceil + greater left_shift fabs + greater_equal right_shift floor + less arccos arctan2 + less_equal arcsin fmod + equal arctan hypot + not_equal cos around + logical_and cosh sign + arccosh arcsinh arctanh + +""" +from __future__ import division, absolute_import, print_function + +depends = ['testing'] +global_symbols = ['*'] diff --git a/numpy/core/machar.py b/numpy/core/machar.py new file mode 100644 index 0000000..7578544 --- /dev/null +++ b/numpy/core/machar.py @@ -0,0 +1,342 @@ +""" +Machine arithmetics - determine the parameters of the +floating-point arithmetic system + +Author: Pearu Peterson, September 2003 + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['MachAr'] + +from numpy.core.fromnumeric import any +from numpy.core.numeric import errstate + +# Need to speed this up...especially for longfloat + +class MachAr(object): + """ + Diagnosing machine parameters. + + Attributes + ---------- + ibeta : int + Radix in which numbers are represented. + it : int + Number of base-`ibeta` digits in the floating point mantissa M. + machep : int + Exponent of the smallest (most negative) power of `ibeta` that, + added to 1.0, gives something different from 1.0 + eps : float + Floating-point number ``beta**machep`` (floating point precision) + negep : int + Exponent of the smallest power of `ibeta` that, subtracted + from 1.0, gives something different from 1.0. + epsneg : float + Floating-point number ``beta**negep``. + iexp : int + Number of bits in the exponent (including its sign and bias). + minexp : int + Smallest (most negative) power of `ibeta` consistent with there + being no leading zeros in the mantissa. + xmin : float + Floating point number ``beta**minexp`` (the smallest [in + magnitude] usable floating value). + maxexp : int + Smallest (positive) power of `ibeta` that causes overflow. + xmax : float + ``(1-epsneg) * beta**maxexp`` (the largest [in magnitude] + usable floating value). + irnd : int + In ``range(6)``, information on what kind of rounding is done + in addition, and on how underflow is handled. + ngrd : int + Number of 'guard digits' used when truncating the product + of two mantissas to fit the representation. + epsilon : float + Same as `eps`. + tiny : float + Same as `xmin`. + huge : float + Same as `xmax`. + precision : float + ``- int(-log10(eps))`` + resolution : float + ``- 10**(-precision)`` + + Parameters + ---------- + float_conv : function, optional + Function that converts an integer or integer array to a float + or float array. Default is `float`. + int_conv : function, optional + Function that converts a float or float array to an integer or + integer array. Default is `int`. + float_to_float : function, optional + Function that converts a float array to float. Default is `float`. + Note that this does not seem to do anything useful in the current + implementation. + float_to_str : function, optional + Function that converts a single float to a string. Default is + ``lambda v:'%24.16e' %v``. + title : str, optional + Title that is printed in the string representation of `MachAr`. + + See Also + -------- + finfo : Machine limits for floating point types. + iinfo : Machine limits for integer types. + + References + ---------- + .. [1] Press, Teukolsky, Vetterling and Flannery, + "Numerical Recipes in C++," 2nd ed, + Cambridge University Press, 2002, p. 31. + + """ + + def __init__(self, float_conv=float,int_conv=int, + float_to_float=float, + float_to_str=lambda v:'%24.16e' % v, + title='Python floating point number'): + """ + + float_conv - convert integer to float (array) + int_conv - convert float (array) to integer + float_to_float - convert float array to float + float_to_str - convert array float to str + title - description of used floating point numbers + + """ + # We ignore all errors here because we are purposely triggering + # underflow to detect the properties of the runninng arch. + with errstate(under='ignore'): + self._do_init(float_conv, int_conv, float_to_float, float_to_str, title) + + def _do_init(self, float_conv, int_conv, float_to_float, float_to_str, title): + max_iterN = 10000 + msg = "Did not converge after %d tries with %s" + one = float_conv(1) + two = one + one + zero = one - one + + # Do we really need to do this? Aren't they 2 and 2.0? + # Determine ibeta and beta + a = one + for _ in range(max_iterN): + a = a + a + temp = a + one + temp1 = temp - a + if any(temp1 - one != zero): + break + else: + raise RuntimeError(msg % (_, one.dtype)) + b = one + for _ in range(max_iterN): + b = b + b + temp = a + b + itemp = int_conv(temp-a) + if any(itemp != 0): + break + else: + raise RuntimeError(msg % (_, one.dtype)) + ibeta = itemp + beta = float_conv(ibeta) + + # Determine it and irnd + it = -1 + b = one + for _ in range(max_iterN): + it = it + 1 + b = b * beta + temp = b + one + temp1 = temp - b + if any(temp1 - one != zero): + break + else: + raise RuntimeError(msg % (_, one.dtype)) + + betah = beta / two + a = one + for _ in range(max_iterN): + a = a + a + temp = a + one + temp1 = temp - a + if any(temp1 - one != zero): + break + else: + raise RuntimeError(msg % (_, one.dtype)) + temp = a + betah + irnd = 0 + if any(temp-a != zero): + irnd = 1 + tempa = a + beta + temp = tempa + betah + if irnd == 0 and any(temp-tempa != zero): + irnd = 2 + + # Determine negep and epsneg + negep = it + 3 + betain = one / beta + a = one + for i in range(negep): + a = a * betain + b = a + for _ in range(max_iterN): + temp = one - a + if any(temp-one != zero): + break + a = a * beta + negep = negep - 1 + # Prevent infinite loop on PPC with gcc 4.0: + if negep < 0: + raise RuntimeError("could not determine machine tolerance " + "for 'negep', locals() -> %s" % (locals())) + else: + raise RuntimeError(msg % (_, one.dtype)) + negep = -negep + epsneg = a + + # Determine machep and eps + machep = - it - 3 + a = b + + for _ in range(max_iterN): + temp = one + a + if any(temp-one != zero): + break + a = a * beta + machep = machep + 1 + else: + raise RuntimeError(msg % (_, one.dtype)) + eps = a + + # Determine ngrd + ngrd = 0 + temp = one + eps + if irnd == 0 and any(temp*one - one != zero): + ngrd = 1 + + # Determine iexp + i = 0 + k = 1 + z = betain + t = one + eps + nxres = 0 + for _ in range(max_iterN): + y = z + z = y*y + a = z*one # Check here for underflow + temp = z*t + if any(a+a == zero) or any(abs(z) >= y): + break + temp1 = temp * betain + if any(temp1*beta == z): + break + i = i + 1 + k = k + k + else: + raise RuntimeError(msg % (_, one.dtype)) + if ibeta != 10: + iexp = i + 1 + mx = k + k + else: + iexp = 2 + iz = ibeta + while k >= iz: + iz = iz * ibeta + iexp = iexp + 1 + mx = iz + iz - 1 + + # Determine minexp and xmin + for _ in range(max_iterN): + xmin = y + y = y * betain + a = y * one + temp = y * t + if any((a + a) != zero) and any(abs(y) < xmin): + k = k + 1 + temp1 = temp * betain + if any(temp1*beta == y) and any(temp != y): + nxres = 3 + xmin = y + break + else: + break + else: + raise RuntimeError(msg % (_, one.dtype)) + minexp = -k + + # Determine maxexp, xmax + if mx <= k + k - 3 and ibeta != 10: + mx = mx + mx + iexp = iexp + 1 + maxexp = mx + minexp + irnd = irnd + nxres + if irnd >= 2: + maxexp = maxexp - 2 + i = maxexp + minexp + if ibeta == 2 and not i: + maxexp = maxexp - 1 + if i > 20: + maxexp = maxexp - 1 + if any(a != y): + maxexp = maxexp - 2 + xmax = one - epsneg + if any(xmax*one != xmax): + xmax = one - beta*epsneg + xmax = xmax / (xmin*beta*beta*beta) + i = maxexp + minexp + 3 + for j in range(i): + if ibeta == 2: + xmax = xmax + xmax + else: + xmax = xmax * beta + + self.ibeta = ibeta + self.it = it + self.negep = negep + self.epsneg = float_to_float(epsneg) + self._str_epsneg = float_to_str(epsneg) + self.machep = machep + self.eps = float_to_float(eps) + self._str_eps = float_to_str(eps) + self.ngrd = ngrd + self.iexp = iexp + self.minexp = minexp + self.xmin = float_to_float(xmin) + self._str_xmin = float_to_str(xmin) + self.maxexp = maxexp + self.xmax = float_to_float(xmax) + self._str_xmax = float_to_str(xmax) + self.irnd = irnd + + self.title = title + # Commonly used parameters + self.epsilon = self.eps + self.tiny = self.xmin + self.huge = self.xmax + + import math + self.precision = int(-math.log10(float_to_float(self.eps))) + ten = two + two + two + two + two + resolution = ten ** (-self.precision) + self.resolution = float_to_float(resolution) + self._str_resolution = float_to_str(resolution) + + def __str__(self): + fmt = ( + 'Machine parameters for %(title)s\n' + '---------------------------------------------------------------------\n' + 'ibeta=%(ibeta)s it=%(it)s iexp=%(iexp)s ngrd=%(ngrd)s irnd=%(irnd)s\n' + 'machep=%(machep)s eps=%(_str_eps)s (beta**machep == epsilon)\n' + 'negep =%(negep)s epsneg=%(_str_epsneg)s (beta**epsneg)\n' + 'minexp=%(minexp)s xmin=%(_str_xmin)s (beta**minexp == tiny)\n' + 'maxexp=%(maxexp)s xmax=%(_str_xmax)s ((1-epsneg)*beta**maxexp == huge)\n' + '---------------------------------------------------------------------\n' + ) + return fmt % self.__dict__ + + +if __name__ == '__main__': + print(MachAr()) diff --git a/numpy/core/memmap.py b/numpy/core/memmap.py new file mode 100644 index 0000000..4604cc7 --- /dev/null +++ b/numpy/core/memmap.py @@ -0,0 +1,338 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +from .numeric import uint8, ndarray, dtype +from numpy.compat import long, basestring, is_pathlib_path + +__all__ = ['memmap'] + +dtypedescr = dtype +valid_filemodes = ["r", "c", "r+", "w+"] +writeable_filemodes = ["r+", "w+"] + +mode_equivalents = { + "readonly":"r", + "copyonwrite":"c", + "readwrite":"r+", + "write":"w+" + } + +class memmap(ndarray): + """Create a memory-map to an array stored in a *binary* file on disk. + + Memory-mapped files are used for accessing small segments of large files + on disk, without reading the entire file into memory. NumPy's + memmap's are array-like objects. This differs from Python's ``mmap`` + module, which uses file-like objects. + + This subclass of ndarray has some unpleasant interactions with + some operations, because it doesn't quite fit properly as a subclass. + An alternative to using this subclass is to create the ``mmap`` + object yourself, then create an ndarray with ndarray.__new__ directly, + passing the object created in its 'buffer=' parameter. + + This class may at some point be turned into a factory function + which returns a view into an mmap buffer. + + Delete the memmap instance to close. + + + Parameters + ---------- + filename : str, file-like object, or pathlib.Path instance + The file name or file object to be used as the array data buffer. + dtype : data-type, optional + The data-type used to interpret the file contents. + Default is `uint8`. + mode : {'r+', 'r', 'w+', 'c'}, optional + The file is opened in this mode: + + +------+-------------------------------------------------------------+ + | 'r' | Open existing file for reading only. | + +------+-------------------------------------------------------------+ + | 'r+' | Open existing file for reading and writing. | + +------+-------------------------------------------------------------+ + | 'w+' | Create or overwrite existing file for reading and writing. | + +------+-------------------------------------------------------------+ + | 'c' | Copy-on-write: assignments affect data in memory, but | + | | changes are not saved to disk. The file on disk is | + | | read-only. | + +------+-------------------------------------------------------------+ + + Default is 'r+'. + offset : int, optional + In the file, array data starts at this offset. Since `offset` is + measured in bytes, it should normally be a multiple of the byte-size + of `dtype`. When ``mode != 'r'``, even positive offsets beyond end of + file are valid; The file will be extended to accommodate the + additional data. By default, ``memmap`` will start at the beginning of + the file, even if ``filename`` is a file pointer ``fp`` and + ``fp.tell() != 0``. + shape : tuple, optional + The desired shape of the array. If ``mode == 'r'`` and the number + of remaining bytes after `offset` is not a multiple of the byte-size + of `dtype`, you must specify `shape`. By default, the returned array + will be 1-D with the number of elements determined by file size + and data-type. + order : {'C', 'F'}, optional + Specify the order of the ndarray memory layout: + :term:`row-major`, C-style or :term:`column-major`, + Fortran-style. This only has an effect if the shape is + greater than 1-D. The default order is 'C'. + + Attributes + ---------- + filename : str or pathlib.Path instance + Path to the mapped file. + offset : int + Offset position in the file. + mode : str + File mode. + + Methods + ------- + flush + Flush any changes in memory to file on disk. + When you delete a memmap object, flush is called first to write + changes to disk before removing the object. + + + See also + -------- + lib.format.open_memmap : Create or load a memory-mapped ``.npy`` file. + + Notes + ----- + The memmap object can be used anywhere an ndarray is accepted. + Given a memmap ``fp``, ``isinstance(fp, numpy.ndarray)`` returns + ``True``. + + Memory-mapped files cannot be larger than 2GB on 32-bit systems. + + When a memmap causes a file to be created or extended beyond its + current size in the filesystem, the contents of the new part are + unspecified. On systems with POSIX filesystem semantics, the extended + part will be filled with zero bytes. + + Examples + -------- + >>> data = np.arange(12, dtype='float32') + >>> data.resize((3,4)) + + This example uses a temporary file so that doctest doesn't write + files to your directory. You would use a 'normal' filename. + + >>> from tempfile import mkdtemp + >>> import os.path as path + >>> filename = path.join(mkdtemp(), 'newfile.dat') + + Create a memmap with dtype and shape that matches our data: + + >>> fp = np.memmap(filename, dtype='float32', mode='w+', shape=(3,4)) + >>> fp + memmap([[ 0., 0., 0., 0.], + [ 0., 0., 0., 0.], + [ 0., 0., 0., 0.]], dtype=float32) + + Write data to memmap array: + + >>> fp[:] = data[:] + >>> fp + memmap([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.]], dtype=float32) + + >>> fp.filename == path.abspath(filename) + True + + Deletion flushes memory changes to disk before removing the object: + + >>> del fp + + Load the memmap and verify data was stored: + + >>> newfp = np.memmap(filename, dtype='float32', mode='r', shape=(3,4)) + >>> newfp + memmap([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.]], dtype=float32) + + Read-only memmap: + + >>> fpr = np.memmap(filename, dtype='float32', mode='r', shape=(3,4)) + >>> fpr.flags.writeable + False + + Copy-on-write memmap: + + >>> fpc = np.memmap(filename, dtype='float32', mode='c', shape=(3,4)) + >>> fpc.flags.writeable + True + + It's possible to assign to copy-on-write array, but values are only + written into the memory copy of the array, and not written to disk: + + >>> fpc + memmap([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.]], dtype=float32) + >>> fpc[0,:] = 0 + >>> fpc + memmap([[ 0., 0., 0., 0.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.]], dtype=float32) + + File on disk is unchanged: + + >>> fpr + memmap([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.]], dtype=float32) + + Offset into a memmap: + + >>> fpo = np.memmap(filename, dtype='float32', mode='r', offset=16) + >>> fpo + memmap([ 4., 5., 6., 7., 8., 9., 10., 11.], dtype=float32) + + """ + + __array_priority__ = -100.0 + + def __new__(subtype, filename, dtype=uint8, mode='r+', offset=0, + shape=None, order='C'): + # Import here to minimize 'import numpy' overhead + import mmap + import os.path + try: + mode = mode_equivalents[mode] + except KeyError: + if mode not in valid_filemodes: + raise ValueError("mode must be one of %s" % + (valid_filemodes + list(mode_equivalents.keys()))) + + if hasattr(filename, 'read'): + fid = filename + own_file = False + elif is_pathlib_path(filename): + fid = filename.open((mode == 'c' and 'r' or mode)+'b') + own_file = True + else: + fid = open(filename, (mode == 'c' and 'r' or mode)+'b') + own_file = True + + if (mode == 'w+') and shape is None: + raise ValueError("shape must be given") + + fid.seek(0, 2) + flen = fid.tell() + descr = dtypedescr(dtype) + _dbytes = descr.itemsize + + if shape is None: + bytes = flen - offset + if (bytes % _dbytes): + fid.close() + raise ValueError("Size of available data is not a " + "multiple of the data-type size.") + size = bytes // _dbytes + shape = (size,) + else: + if not isinstance(shape, tuple): + shape = (shape,) + size = 1 + for k in shape: + size *= k + + bytes = long(offset + size*_dbytes) + + if mode == 'w+' or (mode == 'r+' and flen < bytes): + fid.seek(bytes - 1, 0) + fid.write(b'\0') + fid.flush() + + if mode == 'c': + acc = mmap.ACCESS_COPY + elif mode == 'r': + acc = mmap.ACCESS_READ + else: + acc = mmap.ACCESS_WRITE + + start = offset - offset % mmap.ALLOCATIONGRANULARITY + bytes -= start + array_offset = offset - start + mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start) + + self = ndarray.__new__(subtype, shape, dtype=descr, buffer=mm, + offset=array_offset, order=order) + self._mmap = mm + self.offset = offset + self.mode = mode + + if isinstance(filename, basestring): + self.filename = os.path.abspath(filename) + elif is_pathlib_path(filename): + self.filename = filename.resolve() + # py3 returns int for TemporaryFile().name + elif (hasattr(filename, "name") and + isinstance(filename.name, basestring)): + self.filename = os.path.abspath(filename.name) + # same as memmap copies (e.g. memmap + 1) + else: + self.filename = None + + if own_file: + fid.close() + + return self + + def __array_finalize__(self, obj): + if hasattr(obj, '_mmap') and np.may_share_memory(self, obj): + self._mmap = obj._mmap + self.filename = obj.filename + self.offset = obj.offset + self.mode = obj.mode + else: + self._mmap = None + self.filename = None + self.offset = None + self.mode = None + + def flush(self): + """ + Write any changes in the array to the file on disk. + + For further information, see `memmap`. + + Parameters + ---------- + None + + See Also + -------- + memmap + + """ + if self.base is not None and hasattr(self.base, 'flush'): + self.base.flush() + + def __array_wrap__(self, arr, context=None): + arr = super(memmap, self).__array_wrap__(arr, context) + + # Return a memmap if a memmap was given as the output of the + # ufunc. Leave the arr class unchanged if self is not a memmap + # to keep original memmap subclasses behavior + if self is arr or type(self) is not memmap: + return arr + # Return scalar instead of 0d memmap, e.g. for np.sum with + # axis=None + if arr.shape == (): + return arr[()] + # Return ndarray otherwise + return arr.view(np.ndarray) + + def __getitem__(self, index): + res = super(memmap, self).__getitem__(index) + if type(res) is memmap and res._mmap is None: + return res.view(type=ndarray) + return res diff --git a/numpy/core/mlib.ini.in b/numpy/core/mlib.ini.in new file mode 100644 index 0000000..badaa2a --- /dev/null +++ b/numpy/core/mlib.ini.in @@ -0,0 +1,12 @@ +[meta] +Name = mlib +Description = Math library used with this version of numpy +Version = 1.0 + +[default] +Libs=@posix_mathlib@ +Cflags= + +[msvc] +Libs=@msvc_mathlib@ +Cflags= diff --git a/numpy/core/npymath.ini.in b/numpy/core/npymath.ini.in new file mode 100644 index 0000000..a233b8f --- /dev/null +++ b/numpy/core/npymath.ini.in @@ -0,0 +1,20 @@ +[meta] +Name=npymath +Description=Portable, core math library implementing C99 standard +Version=0.1 + +[variables] +pkgname=@pkgname@ +prefix=${pkgdir} +libdir=${prefix}@sep@lib +includedir=${prefix}@sep@include + +[default] +Libs=-L${libdir} -lnpymath +Cflags=-I${includedir} +Requires=mlib + +[msvc] +Libs=/LIBPATH:${libdir} npymath.lib +Cflags=/INCLUDE:${includedir} +Requires=mlib diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py new file mode 100644 index 0000000..ac64b05 --- /dev/null +++ b/numpy/core/numeric.py @@ -0,0 +1,2903 @@ +from __future__ import division, absolute_import, print_function + +import collections +import itertools +import operator +import sys +import warnings +import numbers + +import numpy as np +from . import multiarray +from .multiarray import ( + _fastCopyAndTranspose as fastCopyAndTranspose, ALLOW_THREADS, + BUFSIZE, CLIP, MAXDIMS, MAY_SHARE_BOUNDS, MAY_SHARE_EXACT, RAISE, + WRAP, arange, array, broadcast, can_cast, compare_chararrays, + concatenate, copyto, count_nonzero, dot, dtype, empty, + empty_like, flatiter, frombuffer, fromfile, fromiter, fromstring, + inner, int_asbuffer, lexsort, matmul, may_share_memory, + min_scalar_type, ndarray, nditer, nested_iters, promote_types, + putmask, result_type, set_numeric_ops, shares_memory, vdot, where, + zeros, normalize_axis_index) +if sys.version_info[0] < 3: + from .multiarray import newbuffer, getbuffer + +from . import umath +from .umath import (multiply, invert, sin, UFUNC_BUFSIZE_DEFAULT, + ERR_IGNORE, ERR_WARN, ERR_RAISE, ERR_CALL, ERR_PRINT, + ERR_LOG, ERR_DEFAULT, PINF, NAN) +from . import numerictypes +from .numerictypes import longlong, intc, int_, float_, complex_, bool_ +from ._internal import TooHardError, AxisError + +bitwise_not = invert +ufunc = type(sin) +newaxis = None + +if sys.version_info[0] >= 3: + import pickle + basestring = str + import builtins +else: + import cPickle as pickle + import __builtin__ as builtins + +loads = pickle.loads + + +__all__ = [ + 'newaxis', 'ndarray', 'flatiter', 'nditer', 'nested_iters', 'ufunc', + 'arange', 'array', 'zeros', 'count_nonzero', 'empty', 'broadcast', 'dtype', + 'fromstring', 'fromfile', 'frombuffer', 'int_asbuffer', 'where', + 'argwhere', 'copyto', 'concatenate', 'fastCopyAndTranspose', 'lexsort', + 'set_numeric_ops', 'can_cast', 'promote_types', 'min_scalar_type', + 'result_type', 'asarray', 'asanyarray', 'ascontiguousarray', + 'asfortranarray', 'isfortran', 'empty_like', 'zeros_like', 'ones_like', + 'correlate', 'convolve', 'inner', 'dot', 'outer', 'vdot', 'roll', + 'rollaxis', 'moveaxis', 'cross', 'tensordot', 'little_endian', 'require', + 'fromiter', 'array_equal', 'array_equiv', 'indices', 'fromfunction', + 'isclose', 'load', 'loads', 'isscalar', 'binary_repr', 'base_repr', 'ones', + 'identity', 'allclose', 'compare_chararrays', 'putmask', 'seterr', + 'geterr', 'setbufsize', 'getbufsize', 'seterrcall', 'geterrcall', + 'errstate', 'flatnonzero', 'Inf', 'inf', 'infty', 'Infinity', 'nan', 'NaN', + 'False_', 'True_', 'bitwise_not', 'CLIP', 'RAISE', 'WRAP', 'MAXDIMS', + 'BUFSIZE', 'ALLOW_THREADS', 'ComplexWarning', 'full', 'full_like', + 'matmul', 'shares_memory', 'may_share_memory', 'MAY_SHARE_BOUNDS', + 'MAY_SHARE_EXACT', 'TooHardError', 'AxisError' ] + +if sys.version_info[0] < 3: + __all__.extend(['getbuffer', 'newbuffer']) + + +class ComplexWarning(RuntimeWarning): + """ + The warning raised when casting a complex dtype to a real dtype. + + As implemented, casting a complex number to a real discards its imaginary + part, but this behavior may not be what the user actually wants. + + """ + pass + + +def zeros_like(a, dtype=None, order='K', subok=True): + """ + Return an array of zeros with the same shape and type as a given array. + + Parameters + ---------- + a : array_like + The shape and data-type of `a` define these same attributes of + the returned array. + dtype : data-type, optional + Overrides the data type of the result. + + .. versionadded:: 1.6.0 + order : {'C', 'F', 'A', or 'K'}, optional + Overrides the memory layout of the result. 'C' means C-order, + 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, + 'C' otherwise. 'K' means match the layout of `a` as closely + as possible. + + .. versionadded:: 1.6.0 + subok : bool, optional. + If True, then the newly created array will use the sub-class + type of 'a', otherwise it will be a base-class array. Defaults + to True. + + Returns + ------- + out : ndarray + Array of zeros with the same shape and type as `a`. + + See Also + -------- + ones_like : Return an array of ones with shape and type of input. + empty_like : Return an empty array with shape and type of input. + zeros : Return a new array setting values to zero. + ones : Return a new array setting values to one. + empty : Return a new uninitialized array. + + Examples + -------- + >>> x = np.arange(6) + >>> x = x.reshape((2, 3)) + >>> x + array([[0, 1, 2], + [3, 4, 5]]) + >>> np.zeros_like(x) + array([[0, 0, 0], + [0, 0, 0]]) + + >>> y = np.arange(3, dtype=float) + >>> y + array([ 0., 1., 2.]) + >>> np.zeros_like(y) + array([ 0., 0., 0.]) + + """ + res = empty_like(a, dtype=dtype, order=order, subok=subok) + # needed instead of a 0 to get same result as zeros for for string dtypes + z = zeros(1, dtype=res.dtype) + multiarray.copyto(res, z, casting='unsafe') + return res + + +def ones(shape, dtype=None, order='C'): + """ + Return a new array of given shape and type, filled with ones. + + Parameters + ---------- + shape : int or sequence of ints + Shape of the new array, e.g., ``(2, 3)`` or ``2``. + dtype : data-type, optional + The desired data-type for the array, e.g., `numpy.int8`. Default is + `numpy.float64`. + order : {'C', 'F'}, optional + Whether to store multidimensional data in C- or Fortran-contiguous + (row- or column-wise) order in memory. + + Returns + ------- + out : ndarray + Array of ones with the given shape, dtype, and order. + + See Also + -------- + zeros, ones_like + + Examples + -------- + >>> np.ones(5) + array([ 1., 1., 1., 1., 1.]) + + >>> np.ones((5,), dtype=int) + array([1, 1, 1, 1, 1]) + + >>> np.ones((2, 1)) + array([[ 1.], + [ 1.]]) + + >>> s = (2,2) + >>> np.ones(s) + array([[ 1., 1.], + [ 1., 1.]]) + + """ + a = empty(shape, dtype, order) + multiarray.copyto(a, 1, casting='unsafe') + return a + + +def ones_like(a, dtype=None, order='K', subok=True): + """ + Return an array of ones with the same shape and type as a given array. + + Parameters + ---------- + a : array_like + The shape and data-type of `a` define these same attributes of + the returned array. + dtype : data-type, optional + Overrides the data type of the result. + + .. versionadded:: 1.6.0 + order : {'C', 'F', 'A', or 'K'}, optional + Overrides the memory layout of the result. 'C' means C-order, + 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, + 'C' otherwise. 'K' means match the layout of `a` as closely + as possible. + + .. versionadded:: 1.6.0 + subok : bool, optional. + If True, then the newly created array will use the sub-class + type of 'a', otherwise it will be a base-class array. Defaults + to True. + + Returns + ------- + out : ndarray + Array of ones with the same shape and type as `a`. + + See Also + -------- + zeros_like : Return an array of zeros with shape and type of input. + empty_like : Return an empty array with shape and type of input. + zeros : Return a new array setting values to zero. + ones : Return a new array setting values to one. + empty : Return a new uninitialized array. + + Examples + -------- + >>> x = np.arange(6) + >>> x = x.reshape((2, 3)) + >>> x + array([[0, 1, 2], + [3, 4, 5]]) + >>> np.ones_like(x) + array([[1, 1, 1], + [1, 1, 1]]) + + >>> y = np.arange(3, dtype=float) + >>> y + array([ 0., 1., 2.]) + >>> np.ones_like(y) + array([ 1., 1., 1.]) + + """ + res = empty_like(a, dtype=dtype, order=order, subok=subok) + multiarray.copyto(res, 1, casting='unsafe') + return res + + +def full(shape, fill_value, dtype=None, order='C'): + """ + Return a new array of given shape and type, filled with `fill_value`. + + Parameters + ---------- + shape : int or sequence of ints + Shape of the new array, e.g., ``(2, 3)`` or ``2``. + fill_value : scalar + Fill value. + dtype : data-type, optional + The desired data-type for the array The default, `None`, means + `np.array(fill_value).dtype`. + order : {'C', 'F'}, optional + Whether to store multidimensional data in C- or Fortran-contiguous + (row- or column-wise) order in memory. + + Returns + ------- + out : ndarray + Array of `fill_value` with the given shape, dtype, and order. + + See Also + -------- + zeros_like : Return an array of zeros with shape and type of input. + ones_like : Return an array of ones with shape and type of input. + empty_like : Return an empty array with shape and type of input. + full_like : Fill an array with shape and type of input. + zeros : Return a new array setting values to zero. + ones : Return a new array setting values to one. + empty : Return a new uninitialized array. + + Examples + -------- + >>> np.full((2, 2), np.inf) + array([[ inf, inf], + [ inf, inf]]) + >>> np.full((2, 2), 10) + array([[10, 10], + [10, 10]]) + + """ + if dtype is None: + dtype = array(fill_value).dtype + a = empty(shape, dtype, order) + multiarray.copyto(a, fill_value, casting='unsafe') + return a + + +def full_like(a, fill_value, dtype=None, order='K', subok=True): + """ + Return a full array with the same shape and type as a given array. + + Parameters + ---------- + a : array_like + The shape and data-type of `a` define these same attributes of + the returned array. + fill_value : scalar + Fill value. + dtype : data-type, optional + Overrides the data type of the result. + order : {'C', 'F', 'A', or 'K'}, optional + Overrides the memory layout of the result. 'C' means C-order, + 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, + 'C' otherwise. 'K' means match the layout of `a` as closely + as possible. + subok : bool, optional. + If True, then the newly created array will use the sub-class + type of 'a', otherwise it will be a base-class array. Defaults + to True. + + Returns + ------- + out : ndarray + Array of `fill_value` with the same shape and type as `a`. + + See Also + -------- + zeros_like : Return an array of zeros with shape and type of input. + ones_like : Return an array of ones with shape and type of input. + empty_like : Return an empty array with shape and type of input. + zeros : Return a new array setting values to zero. + ones : Return a new array setting values to one. + empty : Return a new uninitialized array. + full : Fill a new array. + + Examples + -------- + >>> x = np.arange(6, dtype=int) + >>> np.full_like(x, 1) + array([1, 1, 1, 1, 1, 1]) + >>> np.full_like(x, 0.1) + array([0, 0, 0, 0, 0, 0]) + >>> np.full_like(x, 0.1, dtype=np.double) + array([ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) + >>> np.full_like(x, np.nan, dtype=np.double) + array([ nan, nan, nan, nan, nan, nan]) + + >>> y = np.arange(6, dtype=np.double) + >>> np.full_like(y, 0.1) + array([ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) + + """ + res = empty_like(a, dtype=dtype, order=order, subok=subok) + multiarray.copyto(res, fill_value, casting='unsafe') + return res + +def count_nonzero(a, axis=None): + """ + Counts the number of non-zero values in the array ``a``. + + The word "non-zero" is in reference to the Python 2.x + built-in method ``__nonzero__()`` (renamed ``__bool__()`` + in Python 3.x) of Python objects that tests an object's + "truthfulness". For example, any number is considered + truthful if it is nonzero, whereas any string is considered + truthful if it is not the empty string. Thus, this function + (recursively) counts how many elements in ``a`` (and in + sub-arrays thereof) have their ``__nonzero__()`` or ``__bool__()`` + method evaluated to ``True``. + + Parameters + ---------- + a : array_like + The array for which to count non-zeros. + axis : int or tuple, optional + Axis or tuple of axes along which to count non-zeros. + Default is None, meaning that non-zeros will be counted + along a flattened version of ``a``. + + .. versionadded:: 1.12.0 + + Returns + ------- + count : int or array of int + Number of non-zero values in the array along a given axis. + Otherwise, the total number of non-zero values in the array + is returned. + + See Also + -------- + nonzero : Return the coordinates of all the non-zero values. + + Examples + -------- + >>> np.count_nonzero(np.eye(4)) + 4 + >>> np.count_nonzero([[0,1,7,0,0],[3,0,0,2,19]]) + 5 + >>> np.count_nonzero([[0,1,7,0,0],[3,0,0,2,19]], axis=0) + array([1, 1, 1, 1, 1]) + >>> np.count_nonzero([[0,1,7,0,0],[3,0,0,2,19]], axis=1) + array([2, 3]) + + """ + if axis is None: + return multiarray.count_nonzero(a) + + a = asanyarray(a) + + # TODO: this works around .astype(bool) not working properly (gh-9847) + if np.issubdtype(a.dtype, np.character): + a_bool = a != a.dtype.type() + else: + a_bool = a.astype(np.bool_, copy=False) + + return a_bool.sum(axis=axis, dtype=np.intp) + + +def asarray(a, dtype=None, order=None): + """Convert the input to an array. + + Parameters + ---------- + a : array_like + Input data, in any form that can be converted to an array. This + includes lists, lists of tuples, tuples, tuples of tuples, tuples + of lists and ndarrays. + dtype : data-type, optional + By default, the data-type is inferred from the input data. + order : {'C', 'F'}, optional + Whether to use row-major (C-style) or + column-major (Fortran-style) memory representation. + Defaults to 'C'. + + Returns + ------- + out : ndarray + Array interpretation of `a`. No copy is performed if the input + is already an ndarray with matching dtype and order. If `a` is a + subclass of ndarray, a base class ndarray is returned. + + See Also + -------- + asanyarray : Similar function which passes through subclasses. + ascontiguousarray : Convert input to a contiguous array. + asfarray : Convert input to a floating point ndarray. + asfortranarray : Convert input to an ndarray with column-major + memory order. + asarray_chkfinite : Similar function which checks input for NaNs and Infs. + fromiter : Create an array from an iterator. + fromfunction : Construct an array by executing a function on grid + positions. + + Examples + -------- + Convert a list into an array: + + >>> a = [1, 2] + >>> np.asarray(a) + array([1, 2]) + + Existing arrays are not copied: + + >>> a = np.array([1, 2]) + >>> np.asarray(a) is a + True + + If `dtype` is set, array is copied only if dtype does not match: + + >>> a = np.array([1, 2], dtype=np.float32) + >>> np.asarray(a, dtype=np.float32) is a + True + >>> np.asarray(a, dtype=np.float64) is a + False + + Contrary to `asanyarray`, ndarray subclasses are not passed through: + + >>> issubclass(np.matrix, np.ndarray) + True + >>> a = np.matrix([[1, 2]]) + >>> np.asarray(a) is a + False + >>> np.asanyarray(a) is a + True + + """ + return array(a, dtype, copy=False, order=order) + + +def asanyarray(a, dtype=None, order=None): + """Convert the input to an ndarray, but pass ndarray subclasses through. + + Parameters + ---------- + a : array_like + Input data, in any form that can be converted to an array. This + includes scalars, lists, lists of tuples, tuples, tuples of tuples, + tuples of lists, and ndarrays. + dtype : data-type, optional + By default, the data-type is inferred from the input data. + order : {'C', 'F'}, optional + Whether to use row-major (C-style) or column-major + (Fortran-style) memory representation. Defaults to 'C'. + + Returns + ------- + out : ndarray or an ndarray subclass + Array interpretation of `a`. If `a` is an ndarray or a subclass + of ndarray, it is returned as-is and no copy is performed. + + See Also + -------- + asarray : Similar function which always returns ndarrays. + ascontiguousarray : Convert input to a contiguous array. + asfarray : Convert input to a floating point ndarray. + asfortranarray : Convert input to an ndarray with column-major + memory order. + asarray_chkfinite : Similar function which checks input for NaNs and + Infs. + fromiter : Create an array from an iterator. + fromfunction : Construct an array by executing a function on grid + positions. + + Examples + -------- + Convert a list into an array: + + >>> a = [1, 2] + >>> np.asanyarray(a) + array([1, 2]) + + Instances of `ndarray` subclasses are passed through as-is: + + >>> a = np.matrix([1, 2]) + >>> np.asanyarray(a) is a + True + + """ + return array(a, dtype, copy=False, order=order, subok=True) + + +def ascontiguousarray(a, dtype=None): + """ + Return a contiguous array in memory (C order). + + Parameters + ---------- + a : array_like + Input array. + dtype : str or dtype object, optional + Data-type of returned array. + + Returns + ------- + out : ndarray + Contiguous array of same shape and content as `a`, with type `dtype` + if specified. + + See Also + -------- + asfortranarray : Convert input to an ndarray with column-major + memory order. + require : Return an ndarray that satisfies requirements. + ndarray.flags : Information about the memory layout of the array. + + Examples + -------- + >>> x = np.arange(6).reshape(2,3) + >>> np.ascontiguousarray(x, dtype=np.float32) + array([[ 0., 1., 2.], + [ 3., 4., 5.]], dtype=float32) + >>> x.flags['C_CONTIGUOUS'] + True + + """ + return array(a, dtype, copy=False, order='C', ndmin=1) + + +def asfortranarray(a, dtype=None): + """ + Return an array laid out in Fortran order in memory. + + Parameters + ---------- + a : array_like + Input array. + dtype : str or dtype object, optional + By default, the data-type is inferred from the input data. + + Returns + ------- + out : ndarray + The input `a` in Fortran, or column-major, order. + + See Also + -------- + ascontiguousarray : Convert input to a contiguous (C order) array. + asanyarray : Convert input to an ndarray with either row or + column-major memory order. + require : Return an ndarray that satisfies requirements. + ndarray.flags : Information about the memory layout of the array. + + Examples + -------- + >>> x = np.arange(6).reshape(2,3) + >>> y = np.asfortranarray(x) + >>> x.flags['F_CONTIGUOUS'] + False + >>> y.flags['F_CONTIGUOUS'] + True + + """ + return array(a, dtype, copy=False, order='F', ndmin=1) + + +def require(a, dtype=None, requirements=None): + """ + Return an ndarray of the provided type that satisfies requirements. + + This function is useful to be sure that an array with the correct flags + is returned for passing to compiled code (perhaps through ctypes). + + Parameters + ---------- + a : array_like + The object to be converted to a type-and-requirement-satisfying array. + dtype : data-type + The required data-type. If None preserve the current dtype. If your + application requires the data to be in native byteorder, include + a byteorder specification as a part of the dtype specification. + requirements : str or list of str + The requirements list can be any of the following + + * 'F_CONTIGUOUS' ('F') - ensure a Fortran-contiguous array + * 'C_CONTIGUOUS' ('C') - ensure a C-contiguous array + * 'ALIGNED' ('A') - ensure a data-type aligned array + * 'WRITEABLE' ('W') - ensure a writable array + * 'OWNDATA' ('O') - ensure an array that owns its own data + * 'ENSUREARRAY', ('E') - ensure a base array, instead of a subclass + + See Also + -------- + asarray : Convert input to an ndarray. + asanyarray : Convert to an ndarray, but pass through ndarray subclasses. + ascontiguousarray : Convert input to a contiguous array. + asfortranarray : Convert input to an ndarray with column-major + memory order. + ndarray.flags : Information about the memory layout of the array. + + Notes + ----- + The returned array will be guaranteed to have the listed requirements + by making a copy if needed. + + Examples + -------- + >>> x = np.arange(6).reshape(2,3) + >>> x.flags + C_CONTIGUOUS : True + F_CONTIGUOUS : False + OWNDATA : False + WRITEABLE : True + ALIGNED : True + WRITEBACKIFCOPY : False + UPDATEIFCOPY : False + + >>> y = np.require(x, dtype=np.float32, requirements=['A', 'O', 'W', 'F']) + >>> y.flags + C_CONTIGUOUS : False + F_CONTIGUOUS : True + OWNDATA : True + WRITEABLE : True + ALIGNED : True + WRITEBACKIFCOPY : False + UPDATEIFCOPY : False + + """ + possible_flags = {'C':'C', 'C_CONTIGUOUS':'C', 'CONTIGUOUS':'C', + 'F':'F', 'F_CONTIGUOUS':'F', 'FORTRAN':'F', + 'A':'A', 'ALIGNED':'A', + 'W':'W', 'WRITEABLE':'W', + 'O':'O', 'OWNDATA':'O', + 'E':'E', 'ENSUREARRAY':'E'} + if not requirements: + return asanyarray(a, dtype=dtype) + else: + requirements = set(possible_flags[x.upper()] for x in requirements) + + if 'E' in requirements: + requirements.remove('E') + subok = False + else: + subok = True + + order = 'A' + if requirements >= set(['C', 'F']): + raise ValueError('Cannot specify both "C" and "F" order') + elif 'F' in requirements: + order = 'F' + requirements.remove('F') + elif 'C' in requirements: + order = 'C' + requirements.remove('C') + + arr = array(a, dtype=dtype, order=order, copy=False, subok=subok) + + for prop in requirements: + if not arr.flags[prop]: + arr = arr.copy(order) + break + return arr + + +def isfortran(a): + """ + Returns True if the array is Fortran contiguous but *not* C contiguous. + + This function is obsolete and, because of changes due to relaxed stride + checking, its return value for the same array may differ for versions + of NumPy >= 1.10.0 and previous versions. If you only want to check if an + array is Fortran contiguous use ``a.flags.f_contiguous`` instead. + + Parameters + ---------- + a : ndarray + Input array. + + + Examples + -------- + + np.array allows to specify whether the array is written in C-contiguous + order (last index varies the fastest), or FORTRAN-contiguous order in + memory (first index varies the fastest). + + >>> a = np.array([[1, 2, 3], [4, 5, 6]], order='C') + >>> a + array([[1, 2, 3], + [4, 5, 6]]) + >>> np.isfortran(a) + False + + >>> b = np.array([[1, 2, 3], [4, 5, 6]], order='FORTRAN') + >>> b + array([[1, 2, 3], + [4, 5, 6]]) + >>> np.isfortran(b) + True + + + The transpose of a C-ordered array is a FORTRAN-ordered array. + + >>> a = np.array([[1, 2, 3], [4, 5, 6]], order='C') + >>> a + array([[1, 2, 3], + [4, 5, 6]]) + >>> np.isfortran(a) + False + >>> b = a.T + >>> b + array([[1, 4], + [2, 5], + [3, 6]]) + >>> np.isfortran(b) + True + + C-ordered arrays evaluate as False even if they are also FORTRAN-ordered. + + >>> np.isfortran(np.array([1, 2], order='FORTRAN')) + False + + """ + return a.flags.fnc + + +def argwhere(a): + """ + Find the indices of array elements that are non-zero, grouped by element. + + Parameters + ---------- + a : array_like + Input data. + + Returns + ------- + index_array : ndarray + Indices of elements that are non-zero. Indices are grouped by element. + + See Also + -------- + where, nonzero + + Notes + ----- + ``np.argwhere(a)`` is the same as ``np.transpose(np.nonzero(a))``. + + The output of ``argwhere`` is not suitable for indexing arrays. + For this purpose use ``nonzero(a)`` instead. + + Examples + -------- + >>> x = np.arange(6).reshape(2,3) + >>> x + array([[0, 1, 2], + [3, 4, 5]]) + >>> np.argwhere(x>1) + array([[0, 2], + [1, 0], + [1, 1], + [1, 2]]) + + """ + return transpose(nonzero(a)) + + +def flatnonzero(a): + """ + Return indices that are non-zero in the flattened version of a. + + This is equivalent to a.ravel().nonzero()[0]. + + Parameters + ---------- + a : ndarray + Input array. + + Returns + ------- + res : ndarray + Output array, containing the indices of the elements of `a.ravel()` + that are non-zero. + + See Also + -------- + nonzero : Return the indices of the non-zero elements of the input array. + ravel : Return a 1-D array containing the elements of the input array. + + Examples + -------- + >>> x = np.arange(-2, 3) + >>> x + array([-2, -1, 0, 1, 2]) + >>> np.flatnonzero(x) + array([0, 1, 3, 4]) + + Use the indices of the non-zero elements as an index array to extract + these elements: + + >>> x.ravel()[np.flatnonzero(x)] + array([-2, -1, 1, 2]) + + """ + return a.ravel().nonzero()[0] + + +_mode_from_name_dict = {'v': 0, + 's': 1, + 'f': 2} + + +def _mode_from_name(mode): + if isinstance(mode, basestring): + return _mode_from_name_dict[mode.lower()[0]] + return mode + + +def correlate(a, v, mode='valid'): + """ + Cross-correlation of two 1-dimensional sequences. + + This function computes the correlation as generally defined in signal + processing texts:: + + c_{av}[k] = sum_n a[n+k] * conj(v[n]) + + with a and v sequences being zero-padded where necessary and conj being + the conjugate. + + Parameters + ---------- + a, v : array_like + Input sequences. + mode : {'valid', 'same', 'full'}, optional + Refer to the `convolve` docstring. Note that the default + is 'valid', unlike `convolve`, which uses 'full'. + old_behavior : bool + `old_behavior` was removed in NumPy 1.10. If you need the old + behavior, use `multiarray.correlate`. + + Returns + ------- + out : ndarray + Discrete cross-correlation of `a` and `v`. + + See Also + -------- + convolve : Discrete, linear convolution of two one-dimensional sequences. + multiarray.correlate : Old, no conjugate, version of correlate. + + Notes + ----- + The definition of correlation above is not unique and sometimes correlation + may be defined differently. Another common definition is:: + + c'_{av}[k] = sum_n a[n] conj(v[n+k]) + + which is related to ``c_{av}[k]`` by ``c'_{av}[k] = c_{av}[-k]``. + + Examples + -------- + >>> np.correlate([1, 2, 3], [0, 1, 0.5]) + array([ 3.5]) + >>> np.correlate([1, 2, 3], [0, 1, 0.5], "same") + array([ 2. , 3.5, 3. ]) + >>> np.correlate([1, 2, 3], [0, 1, 0.5], "full") + array([ 0.5, 2. , 3.5, 3. , 0. ]) + + Using complex sequences: + + >>> np.correlate([1+1j, 2, 3-1j], [0, 1, 0.5j], 'full') + array([ 0.5-0.5j, 1.0+0.j , 1.5-1.5j, 3.0-1.j , 0.0+0.j ]) + + Note that you get the time reversed, complex conjugated result + when the two input sequences change places, i.e., + ``c_{va}[k] = c^{*}_{av}[-k]``: + + >>> np.correlate([0, 1, 0.5j], [1+1j, 2, 3-1j], 'full') + array([ 0.0+0.j , 3.0+1.j , 1.5+1.5j, 1.0+0.j , 0.5+0.5j]) + + """ + mode = _mode_from_name(mode) + return multiarray.correlate2(a, v, mode) + + +def convolve(a, v, mode='full'): + """ + Returns the discrete, linear convolution of two one-dimensional sequences. + + The convolution operator is often seen in signal processing, where it + models the effect of a linear time-invariant system on a signal [1]_. In + probability theory, the sum of two independent random variables is + distributed according to the convolution of their individual + distributions. + + If `v` is longer than `a`, the arrays are swapped before computation. + + Parameters + ---------- + a : (N,) array_like + First one-dimensional input array. + v : (M,) array_like + Second one-dimensional input array. + mode : {'full', 'valid', 'same'}, optional + 'full': + By default, mode is 'full'. This returns the convolution + at each point of overlap, with an output shape of (N+M-1,). At + the end-points of the convolution, the signals do not overlap + completely, and boundary effects may be seen. + + 'same': + Mode 'same' returns output of length ``max(M, N)``. Boundary + effects are still visible. + + 'valid': + Mode 'valid' returns output of length + ``max(M, N) - min(M, N) + 1``. The convolution product is only given + for points where the signals overlap completely. Values outside + the signal boundary have no effect. + + Returns + ------- + out : ndarray + Discrete, linear convolution of `a` and `v`. + + See Also + -------- + scipy.signal.fftconvolve : Convolve two arrays using the Fast Fourier + Transform. + scipy.linalg.toeplitz : Used to construct the convolution operator. + polymul : Polynomial multiplication. Same output as convolve, but also + accepts poly1d objects as input. + + Notes + ----- + The discrete convolution operation is defined as + + .. math:: (a * v)[n] = \\sum_{m = -\\infty}^{\\infty} a[m] v[n - m] + + It can be shown that a convolution :math:`x(t) * y(t)` in time/space + is equivalent to the multiplication :math:`X(f) Y(f)` in the Fourier + domain, after appropriate padding (padding is necessary to prevent + circular convolution). Since multiplication is more efficient (faster) + than convolution, the function `scipy.signal.fftconvolve` exploits the + FFT to calculate the convolution of large data-sets. + + References + ---------- + .. [1] Wikipedia, "Convolution", http://en.wikipedia.org/wiki/Convolution. + + Examples + -------- + Note how the convolution operator flips the second array + before "sliding" the two across one another: + + >>> np.convolve([1, 2, 3], [0, 1, 0.5]) + array([ 0. , 1. , 2.5, 4. , 1.5]) + + Only return the middle values of the convolution. + Contains boundary effects, where zeros are taken + into account: + + >>> np.convolve([1,2,3],[0,1,0.5], 'same') + array([ 1. , 2.5, 4. ]) + + The two arrays are of the same length, so there + is only one position where they completely overlap: + + >>> np.convolve([1,2,3],[0,1,0.5], 'valid') + array([ 2.5]) + + """ + a, v = array(a, copy=False, ndmin=1), array(v, copy=False, ndmin=1) + if (len(v) > len(a)): + a, v = v, a + if len(a) == 0: + raise ValueError('a cannot be empty') + if len(v) == 0: + raise ValueError('v cannot be empty') + mode = _mode_from_name(mode) + return multiarray.correlate(a, v[::-1], mode) + + +def outer(a, b, out=None): + """ + Compute the outer product of two vectors. + + Given two vectors, ``a = [a0, a1, ..., aM]`` and + ``b = [b0, b1, ..., bN]``, + the outer product [1]_ is:: + + [[a0*b0 a0*b1 ... a0*bN ] + [a1*b0 . + [ ... . + [aM*b0 aM*bN ]] + + Parameters + ---------- + a : (M,) array_like + First input vector. Input is flattened if + not already 1-dimensional. + b : (N,) array_like + Second input vector. Input is flattened if + not already 1-dimensional. + out : (M, N) ndarray, optional + A location where the result is stored + + .. versionadded:: 1.9.0 + + Returns + ------- + out : (M, N) ndarray + ``out[i, j] = a[i] * b[j]`` + + See also + -------- + inner + einsum : ``einsum('i,j->ij', a.ravel(), b.ravel())`` is the equivalent. + ufunc.outer : A generalization to N dimensions and other operations. + ``np.multiply.outer(a.ravel(), b.ravel())`` is the equivalent. + + References + ---------- + .. [1] : G. H. Golub and C. F. van Loan, *Matrix Computations*, 3rd + ed., Baltimore, MD, Johns Hopkins University Press, 1996, + pg. 8. + + Examples + -------- + Make a (*very* coarse) grid for computing a Mandelbrot set: + + >>> rl = np.outer(np.ones((5,)), np.linspace(-2, 2, 5)) + >>> rl + array([[-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.], + [-2., -1., 0., 1., 2.]]) + >>> im = np.outer(1j*np.linspace(2, -2, 5), np.ones((5,))) + >>> im + array([[ 0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j], + [ 0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j], + [ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j], + [ 0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j]]) + >>> grid = rl + im + >>> grid + array([[-2.+2.j, -1.+2.j, 0.+2.j, 1.+2.j, 2.+2.j], + [-2.+1.j, -1.+1.j, 0.+1.j, 1.+1.j, 2.+1.j], + [-2.+0.j, -1.+0.j, 0.+0.j, 1.+0.j, 2.+0.j], + [-2.-1.j, -1.-1.j, 0.-1.j, 1.-1.j, 2.-1.j], + [-2.-2.j, -1.-2.j, 0.-2.j, 1.-2.j, 2.-2.j]]) + + An example using a "vector" of letters: + + >>> x = np.array(['a', 'b', 'c'], dtype=object) + >>> np.outer(x, [1, 2, 3]) + array([[a, aa, aaa], + [b, bb, bbb], + [c, cc, ccc]], dtype=object) + + """ + a = asarray(a) + b = asarray(b) + return multiply(a.ravel()[:, newaxis], b.ravel()[newaxis,:], out) + + +def tensordot(a, b, axes=2): + """ + Compute tensor dot product along specified axes for arrays >= 1-D. + + Given two tensors (arrays of dimension greater than or equal to one), + `a` and `b`, and an array_like object containing two array_like + objects, ``(a_axes, b_axes)``, sum the products of `a`'s and `b`'s + elements (components) over the axes specified by ``a_axes`` and + ``b_axes``. The third argument can be a single non-negative + integer_like scalar, ``N``; if it is such, then the last ``N`` + dimensions of `a` and the first ``N`` dimensions of `b` are summed + over. + + Parameters + ---------- + a, b : array_like, len(shape) >= 1 + Tensors to "dot". + + axes : int or (2,) array_like + * integer_like + If an int N, sum over the last N axes of `a` and the first N axes + of `b` in order. The sizes of the corresponding axes must match. + * (2,) array_like + Or, a list of axes to be summed over, first sequence applying to `a`, + second to `b`. Both elements array_like must be of the same length. + + See Also + -------- + dot, einsum + + Notes + ----- + Three common use cases are: + * ``axes = 0`` : tensor product :math:`a\\otimes b` + * ``axes = 1`` : tensor dot product :math:`a\\cdot b` + * ``axes = 2`` : (default) tensor double contraction :math:`a:b` + + When `axes` is integer_like, the sequence for evaluation will be: first + the -Nth axis in `a` and 0th axis in `b`, and the -1th axis in `a` and + Nth axis in `b` last. + + When there is more than one axis to sum over - and they are not the last + (first) axes of `a` (`b`) - the argument `axes` should consist of + two sequences of the same length, with the first axis to sum over given + first in both sequences, the second axis second, and so forth. + + Examples + -------- + A "traditional" example: + + >>> a = np.arange(60.).reshape(3,4,5) + >>> b = np.arange(24.).reshape(4,3,2) + >>> c = np.tensordot(a,b, axes=([1,0],[0,1])) + >>> c.shape + (5, 2) + >>> c + array([[ 4400., 4730.], + [ 4532., 4874.], + [ 4664., 5018.], + [ 4796., 5162.], + [ 4928., 5306.]]) + >>> # A slower but equivalent way of computing the same... + >>> d = np.zeros((5,2)) + >>> for i in range(5): + ... for j in range(2): + ... for k in range(3): + ... for n in range(4): + ... d[i,j] += a[k,n,i] * b[n,k,j] + >>> c == d + array([[ True, True], + [ True, True], + [ True, True], + [ True, True], + [ True, True]]) + + An extended example taking advantage of the overloading of + and \\*: + + >>> a = np.array(range(1, 9)) + >>> a.shape = (2, 2, 2) + >>> A = np.array(('a', 'b', 'c', 'd'), dtype=object) + >>> A.shape = (2, 2) + >>> a; A + array([[[1, 2], + [3, 4]], + [[5, 6], + [7, 8]]]) + array([[a, b], + [c, d]], dtype=object) + + >>> np.tensordot(a, A) # third argument default is 2 for double-contraction + array([abbcccdddd, aaaaabbbbbbcccccccdddddddd], dtype=object) + + >>> np.tensordot(a, A, 1) + array([[[acc, bdd], + [aaacccc, bbbdddd]], + [[aaaaacccccc, bbbbbdddddd], + [aaaaaaacccccccc, bbbbbbbdddddddd]]], dtype=object) + + >>> np.tensordot(a, A, 0) # tensor product (result too long to incl.) + array([[[[[a, b], + [c, d]], + ... + + >>> np.tensordot(a, A, (0, 1)) + array([[[abbbbb, cddddd], + [aabbbbbb, ccdddddd]], + [[aaabbbbbbb, cccddddddd], + [aaaabbbbbbbb, ccccdddddddd]]], dtype=object) + + >>> np.tensordot(a, A, (2, 1)) + array([[[abb, cdd], + [aaabbbb, cccdddd]], + [[aaaaabbbbbb, cccccdddddd], + [aaaaaaabbbbbbbb, cccccccdddddddd]]], dtype=object) + + >>> np.tensordot(a, A, ((0, 1), (0, 1))) + array([abbbcccccddddddd, aabbbbccccccdddddddd], dtype=object) + + >>> np.tensordot(a, A, ((2, 1), (1, 0))) + array([acccbbdddd, aaaaacccccccbbbbbbdddddddd], dtype=object) + + """ + try: + iter(axes) + except Exception: + axes_a = list(range(-axes, 0)) + axes_b = list(range(0, axes)) + else: + axes_a, axes_b = axes + try: + na = len(axes_a) + axes_a = list(axes_a) + except TypeError: + axes_a = [axes_a] + na = 1 + try: + nb = len(axes_b) + axes_b = list(axes_b) + except TypeError: + axes_b = [axes_b] + nb = 1 + + a, b = asarray(a), asarray(b) + as_ = a.shape + nda = a.ndim + bs = b.shape + ndb = b.ndim + equal = True + if na != nb: + equal = False + else: + for k in range(na): + if as_[axes_a[k]] != bs[axes_b[k]]: + equal = False + break + if axes_a[k] < 0: + axes_a[k] += nda + if axes_b[k] < 0: + axes_b[k] += ndb + if not equal: + raise ValueError("shape-mismatch for sum") + + # Move the axes to sum over to the end of "a" + # and to the front of "b" + notin = [k for k in range(nda) if k not in axes_a] + newaxes_a = notin + axes_a + N2 = 1 + for axis in axes_a: + N2 *= as_[axis] + newshape_a = (int(multiply.reduce([as_[ax] for ax in notin])), N2) + olda = [as_[axis] for axis in notin] + + notin = [k for k in range(ndb) if k not in axes_b] + newaxes_b = axes_b + notin + N2 = 1 + for axis in axes_b: + N2 *= bs[axis] + newshape_b = (N2, int(multiply.reduce([bs[ax] for ax in notin]))) + oldb = [bs[axis] for axis in notin] + + at = a.transpose(newaxes_a).reshape(newshape_a) + bt = b.transpose(newaxes_b).reshape(newshape_b) + res = dot(at, bt) + return res.reshape(olda + oldb) + + +def roll(a, shift, axis=None): + """ + Roll array elements along a given axis. + + Elements that roll beyond the last position are re-introduced at + the first. + + Parameters + ---------- + a : array_like + Input array. + shift : int or tuple of ints + The number of places by which elements are shifted. If a tuple, + then `axis` must be a tuple of the same size, and each of the + given axes is shifted by the corresponding number. If an int + while `axis` is a tuple of ints, then the same value is used for + all given axes. + axis : int or tuple of ints, optional + Axis or axes along which elements are shifted. By default, the + array is flattened before shifting, after which the original + shape is restored. + + Returns + ------- + res : ndarray + Output array, with the same shape as `a`. + + See Also + -------- + rollaxis : Roll the specified axis backwards, until it lies in a + given position. + + Notes + ----- + .. versionadded:: 1.12.0 + + Supports rolling over multiple dimensions simultaneously. + + Examples + -------- + >>> x = np.arange(10) + >>> np.roll(x, 2) + array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7]) + + >>> x2 = np.reshape(x, (2,5)) + >>> x2 + array([[0, 1, 2, 3, 4], + [5, 6, 7, 8, 9]]) + >>> np.roll(x2, 1) + array([[9, 0, 1, 2, 3], + [4, 5, 6, 7, 8]]) + >>> np.roll(x2, 1, axis=0) + array([[5, 6, 7, 8, 9], + [0, 1, 2, 3, 4]]) + >>> np.roll(x2, 1, axis=1) + array([[4, 0, 1, 2, 3], + [9, 5, 6, 7, 8]]) + + """ + a = asanyarray(a) + if axis is None: + return roll(a.ravel(), shift, 0).reshape(a.shape) + + else: + axis = normalize_axis_tuple(axis, a.ndim, allow_duplicate=True) + broadcasted = broadcast(shift, axis) + if broadcasted.ndim > 1: + raise ValueError( + "'shift' and 'axis' should be scalars or 1D sequences") + shifts = {ax: 0 for ax in range(a.ndim)} + for sh, ax in broadcasted: + shifts[ax] += sh + + rolls = [((slice(None), slice(None)),)] * a.ndim + for ax, offset in shifts.items(): + offset %= a.shape[ax] or 1 # If `a` is empty, nothing matters. + if offset: + # (original, result), (original, result) + rolls[ax] = ((slice(None, -offset), slice(offset, None)), + (slice(-offset, None), slice(None, offset))) + + result = empty_like(a) + for indices in itertools.product(*rolls): + arr_index, res_index = zip(*indices) + result[res_index] = a[arr_index] + + return result + + +def rollaxis(a, axis, start=0): + """ + Roll the specified axis backwards, until it lies in a given position. + + This function continues to be supported for backward compatibility, but you + should prefer `moveaxis`. The `moveaxis` function was added in NumPy + 1.11. + + Parameters + ---------- + a : ndarray + Input array. + axis : int + The axis to roll backwards. The positions of the other axes do not + change relative to one another. + start : int, optional + The axis is rolled until it lies before this position. The default, + 0, results in a "complete" roll. + + Returns + ------- + res : ndarray + For NumPy >= 1.10.0 a view of `a` is always returned. For earlier + NumPy versions a view of `a` is returned only if the order of the + axes is changed, otherwise the input array is returned. + + See Also + -------- + moveaxis : Move array axes to new positions. + roll : Roll the elements of an array by a number of positions along a + given axis. + + Examples + -------- + >>> a = np.ones((3,4,5,6)) + >>> np.rollaxis(a, 3, 1).shape + (3, 6, 4, 5) + >>> np.rollaxis(a, 2).shape + (5, 3, 4, 6) + >>> np.rollaxis(a, 1, 4).shape + (3, 5, 6, 4) + + """ + n = a.ndim + axis = normalize_axis_index(axis, n) + if start < 0: + start += n + msg = "'%s' arg requires %d <= %s < %d, but %d was passed in" + if not (0 <= start < n + 1): + raise AxisError(msg % ('start', -n, 'start', n + 1, start)) + if axis < start: + # it's been removed + start -= 1 + if axis == start: + return a[...] + axes = list(range(0, n)) + axes.remove(axis) + axes.insert(start, axis) + return a.transpose(axes) + + +def normalize_axis_tuple(axis, ndim, argname=None, allow_duplicate=False): + """ + Normalizes an axis argument into a tuple of non-negative integer axes. + + This handles shorthands such as ``1`` and converts them to ``(1,)``, + as well as performing the handling of negative indices covered by + `normalize_axis_index`. + + By default, this forbids axes from being specified multiple times. + + Used internally by multi-axis-checking logic. + + .. versionadded:: 1.13.0 + + Parameters + ---------- + axis : int, iterable of int + The un-normalized index or indices of the axis. + ndim : int + The number of dimensions of the array that `axis` should be normalized + against. + argname : str, optional + A prefix to put before the error message, typically the name of the + argument. + allow_duplicate : bool, optional + If False, the default, disallow an axis from being specified twice. + + Returns + ------- + normalized_axes : tuple of int + The normalized axis index, such that `0 <= normalized_axis < ndim` + + Raises + ------ + AxisError + If any axis provided is out of range + ValueError + If an axis is repeated + + See also + -------- + normalize_axis_index : normalizing a single scalar axis + """ + try: + axis = [operator.index(axis)] + except TypeError: + axis = tuple(axis) + axis = tuple(normalize_axis_index(ax, ndim, argname) for ax in axis) + if not allow_duplicate and len(set(axis)) != len(axis): + if argname: + raise ValueError('repeated axis in `{}` argument'.format(argname)) + else: + raise ValueError('repeated axis') + return axis + + +def moveaxis(a, source, destination): + """ + Move axes of an array to new positions. + + Other axes remain in their original order. + + .. versionadded:: 1.11.0 + + Parameters + ---------- + a : np.ndarray + The array whose axes should be reordered. + source : int or sequence of int + Original positions of the axes to move. These must be unique. + destination : int or sequence of int + Destination positions for each of the original axes. These must also be + unique. + + Returns + ------- + result : np.ndarray + Array with moved axes. This array is a view of the input array. + + See Also + -------- + transpose: Permute the dimensions of an array. + swapaxes: Interchange two axes of an array. + + Examples + -------- + + >>> x = np.zeros((3, 4, 5)) + >>> np.moveaxis(x, 0, -1).shape + (4, 5, 3) + >>> np.moveaxis(x, -1, 0).shape + (5, 3, 4) + + These all achieve the same result: + + >>> np.transpose(x).shape + (5, 4, 3) + >>> np.swapaxes(x, 0, -1).shape + (5, 4, 3) + >>> np.moveaxis(x, [0, 1], [-1, -2]).shape + (5, 4, 3) + >>> np.moveaxis(x, [0, 1, 2], [-1, -2, -3]).shape + (5, 4, 3) + + """ + try: + # allow duck-array types if they define transpose + transpose = a.transpose + except AttributeError: + a = asarray(a) + transpose = a.transpose + + source = normalize_axis_tuple(source, a.ndim, 'source') + destination = normalize_axis_tuple(destination, a.ndim, 'destination') + if len(source) != len(destination): + raise ValueError('`source` and `destination` arguments must have ' + 'the same number of elements') + + order = [n for n in range(a.ndim) if n not in source] + + for dest, src in sorted(zip(destination, source)): + order.insert(dest, src) + + result = transpose(order) + return result + + +# fix hack in scipy which imports this function +def _move_axis_to_0(a, axis): + return moveaxis(a, axis, 0) + + +def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None): + """ + Return the cross product of two (arrays of) vectors. + + The cross product of `a` and `b` in :math:`R^3` is a vector perpendicular + to both `a` and `b`. If `a` and `b` are arrays of vectors, the vectors + are defined by the last axis of `a` and `b` by default, and these axes + can have dimensions 2 or 3. Where the dimension of either `a` or `b` is + 2, the third component of the input vector is assumed to be zero and the + cross product calculated accordingly. In cases where both input vectors + have dimension 2, the z-component of the cross product is returned. + + Parameters + ---------- + a : array_like + Components of the first vector(s). + b : array_like + Components of the second vector(s). + axisa : int, optional + Axis of `a` that defines the vector(s). By default, the last axis. + axisb : int, optional + Axis of `b` that defines the vector(s). By default, the last axis. + axisc : int, optional + Axis of `c` containing the cross product vector(s). Ignored if + both input vectors have dimension 2, as the return is scalar. + By default, the last axis. + axis : int, optional + If defined, the axis of `a`, `b` and `c` that defines the vector(s) + and cross product(s). Overrides `axisa`, `axisb` and `axisc`. + + Returns + ------- + c : ndarray + Vector cross product(s). + + Raises + ------ + ValueError + When the dimension of the vector(s) in `a` and/or `b` does not + equal 2 or 3. + + See Also + -------- + inner : Inner product + outer : Outer product. + ix_ : Construct index arrays. + + Notes + ----- + .. versionadded:: 1.9.0 + + Supports full broadcasting of the inputs. + + Examples + -------- + Vector cross-product. + + >>> x = [1, 2, 3] + >>> y = [4, 5, 6] + >>> np.cross(x, y) + array([-3, 6, -3]) + + One vector with dimension 2. + + >>> x = [1, 2] + >>> y = [4, 5, 6] + >>> np.cross(x, y) + array([12, -6, -3]) + + Equivalently: + + >>> x = [1, 2, 0] + >>> y = [4, 5, 6] + >>> np.cross(x, y) + array([12, -6, -3]) + + Both vectors with dimension 2. + + >>> x = [1,2] + >>> y = [4,5] + >>> np.cross(x, y) + -3 + + Multiple vector cross-products. Note that the direction of the cross + product vector is defined by the `right-hand rule`. + + >>> x = np.array([[1,2,3], [4,5,6]]) + >>> y = np.array([[4,5,6], [1,2,3]]) + >>> np.cross(x, y) + array([[-3, 6, -3], + [ 3, -6, 3]]) + + The orientation of `c` can be changed using the `axisc` keyword. + + >>> np.cross(x, y, axisc=0) + array([[-3, 3], + [ 6, -6], + [-3, 3]]) + + Change the vector definition of `x` and `y` using `axisa` and `axisb`. + + >>> x = np.array([[1,2,3], [4,5,6], [7, 8, 9]]) + >>> y = np.array([[7, 8, 9], [4,5,6], [1,2,3]]) + >>> np.cross(x, y) + array([[ -6, 12, -6], + [ 0, 0, 0], + [ 6, -12, 6]]) + >>> np.cross(x, y, axisa=0, axisb=0) + array([[-24, 48, -24], + [-30, 60, -30], + [-36, 72, -36]]) + + """ + if axis is not None: + axisa, axisb, axisc = (axis,) * 3 + a = asarray(a) + b = asarray(b) + # Check axisa and axisb are within bounds + axisa = normalize_axis_index(axisa, a.ndim, msg_prefix='axisa') + axisb = normalize_axis_index(axisb, b.ndim, msg_prefix='axisb') + + # Move working axis to the end of the shape + a = moveaxis(a, axisa, -1) + b = moveaxis(b, axisb, -1) + msg = ("incompatible dimensions for cross product\n" + "(dimension must be 2 or 3)") + if a.shape[-1] not in (2, 3) or b.shape[-1] not in (2, 3): + raise ValueError(msg) + + # Create the output array + shape = broadcast(a[..., 0], b[..., 0]).shape + if a.shape[-1] == 3 or b.shape[-1] == 3: + shape += (3,) + # Check axisc is within bounds + axisc = normalize_axis_index(axisc, len(shape), msg_prefix='axisc') + dtype = promote_types(a.dtype, b.dtype) + cp = empty(shape, dtype) + + # create local aliases for readability + a0 = a[..., 0] + a1 = a[..., 1] + if a.shape[-1] == 3: + a2 = a[..., 2] + b0 = b[..., 0] + b1 = b[..., 1] + if b.shape[-1] == 3: + b2 = b[..., 2] + if cp.ndim != 0 and cp.shape[-1] == 3: + cp0 = cp[..., 0] + cp1 = cp[..., 1] + cp2 = cp[..., 2] + + if a.shape[-1] == 2: + if b.shape[-1] == 2: + # a0 * b1 - a1 * b0 + multiply(a0, b1, out=cp) + cp -= a1 * b0 + return cp + else: + assert b.shape[-1] == 3 + # cp0 = a1 * b2 - 0 (a2 = 0) + # cp1 = 0 - a0 * b2 (a2 = 0) + # cp2 = a0 * b1 - a1 * b0 + multiply(a1, b2, out=cp0) + multiply(a0, b2, out=cp1) + negative(cp1, out=cp1) + multiply(a0, b1, out=cp2) + cp2 -= a1 * b0 + else: + assert a.shape[-1] == 3 + if b.shape[-1] == 3: + # cp0 = a1 * b2 - a2 * b1 + # cp1 = a2 * b0 - a0 * b2 + # cp2 = a0 * b1 - a1 * b0 + multiply(a1, b2, out=cp0) + tmp = array(a2 * b1) + cp0 -= tmp + multiply(a2, b0, out=cp1) + multiply(a0, b2, out=tmp) + cp1 -= tmp + multiply(a0, b1, out=cp2) + multiply(a1, b0, out=tmp) + cp2 -= tmp + else: + assert b.shape[-1] == 2 + # cp0 = 0 - a2 * b1 (b2 = 0) + # cp1 = a2 * b0 - 0 (b2 = 0) + # cp2 = a0 * b1 - a1 * b0 + multiply(a2, b1, out=cp0) + negative(cp0, out=cp0) + multiply(a2, b0, out=cp1) + multiply(a0, b1, out=cp2) + cp2 -= a1 * b0 + + return moveaxis(cp, -1, axisc) + +little_endian = (sys.byteorder == 'little') + + +def indices(dimensions, dtype=int): + """ + Return an array representing the indices of a grid. + + Compute an array where the subarrays contain index values 0,1,... + varying only along the corresponding axis. + + Parameters + ---------- + dimensions : sequence of ints + The shape of the grid. + dtype : dtype, optional + Data type of the result. + + Returns + ------- + grid : ndarray + The array of grid indices, + ``grid.shape = (len(dimensions),) + tuple(dimensions)``. + + See Also + -------- + mgrid, meshgrid + + Notes + ----- + The output shape is obtained by prepending the number of dimensions + in front of the tuple of dimensions, i.e. if `dimensions` is a tuple + ``(r0, ..., rN-1)`` of length ``N``, the output shape is + ``(N,r0,...,rN-1)``. + + The subarrays ``grid[k]`` contains the N-D array of indices along the + ``k-th`` axis. Explicitly:: + + grid[k,i0,i1,...,iN-1] = ik + + Examples + -------- + >>> grid = np.indices((2, 3)) + >>> grid.shape + (2, 2, 3) + >>> grid[0] # row indices + array([[0, 0, 0], + [1, 1, 1]]) + >>> grid[1] # column indices + array([[0, 1, 2], + [0, 1, 2]]) + + The indices can be used as an index into an array. + + >>> x = np.arange(20).reshape(5, 4) + >>> row, col = np.indices((2, 3)) + >>> x[row, col] + array([[0, 1, 2], + [4, 5, 6]]) + + Note that it would be more straightforward in the above example to + extract the required elements directly with ``x[:2, :3]``. + + """ + dimensions = tuple(dimensions) + N = len(dimensions) + shape = (1,)*N + res = empty((N,)+dimensions, dtype=dtype) + for i, dim in enumerate(dimensions): + res[i] = arange(dim, dtype=dtype).reshape( + shape[:i] + (dim,) + shape[i+1:] + ) + return res + + +def fromfunction(function, shape, **kwargs): + """ + Construct an array by executing a function over each coordinate. + + The resulting array therefore has a value ``fn(x, y, z)`` at + coordinate ``(x, y, z)``. + + Parameters + ---------- + function : callable + The function is called with N parameters, where N is the rank of + `shape`. Each parameter represents the coordinates of the array + varying along a specific axis. For example, if `shape` + were ``(2, 2)``, then the parameters would be + ``array([[0, 0], [1, 1]])`` and ``array([[0, 1], [0, 1]])`` + shape : (N,) tuple of ints + Shape of the output array, which also determines the shape of + the coordinate arrays passed to `function`. + dtype : data-type, optional + Data-type of the coordinate arrays passed to `function`. + By default, `dtype` is float. + + Returns + ------- + fromfunction : any + The result of the call to `function` is passed back directly. + Therefore the shape of `fromfunction` is completely determined by + `function`. If `function` returns a scalar value, the shape of + `fromfunction` would match the `shape` parameter. + + See Also + -------- + indices, meshgrid + + Notes + ----- + Keywords other than `dtype` are passed to `function`. + + Examples + -------- + >>> np.fromfunction(lambda i, j: i == j, (3, 3), dtype=int) + array([[ True, False, False], + [False, True, False], + [False, False, True]]) + + >>> np.fromfunction(lambda i, j: i + j, (3, 3), dtype=int) + array([[0, 1, 2], + [1, 2, 3], + [2, 3, 4]]) + + """ + dtype = kwargs.pop('dtype', float) + args = indices(shape, dtype=dtype) + return function(*args, **kwargs) + + +def isscalar(num): + """ + Returns True if the type of `num` is a scalar type. + + Parameters + ---------- + num : any + Input argument, can be of any type and shape. + + Returns + ------- + val : bool + True if `num` is a scalar type, False if it is not. + + Examples + -------- + >>> np.isscalar(3.1) + True + >>> np.isscalar([3.1]) + False + >>> np.isscalar(False) + True + >>> np.isscalar('numpy') + True + + NumPy supports PEP 3141 numbers: + + >>> from fractions import Fraction + >>> isscalar(Fraction(5, 17)) + True + >>> from numbers import Number + >>> isscalar(Number()) + True + + """ + return (isinstance(num, generic) + or type(num) in ScalarType + or isinstance(num, numbers.Number)) + + +def binary_repr(num, width=None): + """ + Return the binary representation of the input number as a string. + + For negative numbers, if width is not given, a minus sign is added to the + front. If width is given, the two's complement of the number is + returned, with respect to that width. + + In a two's-complement system negative numbers are represented by the two's + complement of the absolute value. This is the most common method of + representing signed integers on computers [1]_. A N-bit two's-complement + system can represent every integer in the range + :math:`-2^{N-1}` to :math:`+2^{N-1}-1`. + + Parameters + ---------- + num : int + Only an integer decimal number can be used. + width : int, optional + The length of the returned string if `num` is positive, or the length + of the two's complement if `num` is negative, provided that `width` is + at least a sufficient number of bits for `num` to be represented in the + designated form. + + If the `width` value is insufficient, it will be ignored, and `num` will + be returned in binary (`num` > 0) or two's complement (`num` < 0) form + with its width equal to the minimum number of bits needed to represent + the number in the designated form. This behavior is deprecated and will + later raise an error. + + .. deprecated:: 1.12.0 + + Returns + ------- + bin : str + Binary representation of `num` or two's complement of `num`. + + See Also + -------- + base_repr: Return a string representation of a number in the given base + system. + bin: Python's built-in binary representation generator of an integer. + + Notes + ----- + `binary_repr` is equivalent to using `base_repr` with base 2, but about 25x + faster. + + References + ---------- + .. [1] Wikipedia, "Two's complement", + http://en.wikipedia.org/wiki/Two's_complement + + Examples + -------- + >>> np.binary_repr(3) + '11' + >>> np.binary_repr(-3) + '-11' + >>> np.binary_repr(3, width=4) + '0011' + + The two's complement is returned when the input number is negative and + width is specified: + + >>> np.binary_repr(-3, width=3) + '101' + >>> np.binary_repr(-3, width=5) + '11101' + + """ + def warn_if_insufficient(width, binwdith): + if width is not None and width < binwidth: + warnings.warn( + "Insufficient bit width provided. This behavior " + "will raise an error in the future.", DeprecationWarning, + stacklevel=3) + + if num == 0: + return '0' * (width or 1) + + elif num > 0: + binary = bin(num)[2:] + binwidth = len(binary) + outwidth = (binwidth if width is None + else max(binwidth, width)) + warn_if_insufficient(width, binwidth) + return binary.zfill(outwidth) + + else: + if width is None: + return '-' + bin(-num)[2:] + + else: + poswidth = len(bin(-num)[2:]) + + # See gh-8679: remove extra digit + # for numbers at boundaries. + if 2**(poswidth - 1) == -num: + poswidth -= 1 + + twocomp = 2**(poswidth + 1) + num + binary = bin(twocomp)[2:] + binwidth = len(binary) + + outwidth = max(binwidth, width) + warn_if_insufficient(width, binwidth) + return '1' * (outwidth - binwidth) + binary + + +def base_repr(number, base=2, padding=0): + """ + Return a string representation of a number in the given base system. + + Parameters + ---------- + number : int + The value to convert. Positive and negative values are handled. + base : int, optional + Convert `number` to the `base` number system. The valid range is 2-36, + the default value is 2. + padding : int, optional + Number of zeros padded on the left. Default is 0 (no padding). + + Returns + ------- + out : str + String representation of `number` in `base` system. + + See Also + -------- + binary_repr : Faster version of `base_repr` for base 2. + + Examples + -------- + >>> np.base_repr(5) + '101' + >>> np.base_repr(6, 5) + '11' + >>> np.base_repr(7, base=5, padding=3) + '00012' + + >>> np.base_repr(10, base=16) + 'A' + >>> np.base_repr(32, base=16) + '20' + + """ + digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + if base > len(digits): + raise ValueError("Bases greater than 36 not handled in base_repr.") + elif base < 2: + raise ValueError("Bases less than 2 not handled in base_repr.") + + num = abs(number) + res = [] + while num: + res.append(digits[num % base]) + num //= base + if padding: + res.append('0' * padding) + if number < 0: + res.append('-') + return ''.join(reversed(res or '0')) + + +def load(file): + """ + Wrapper around cPickle.load which accepts either a file-like object or + a filename. + + Note that the NumPy binary format is not based on pickle/cPickle anymore. + For details on the preferred way of loading and saving files, see `load` + and `save`. + + See Also + -------- + load, save + + """ + if isinstance(file, type("")): + file = open(file, "rb") + return pickle.load(file) + + +# These are all essentially abbreviations +# These might wind up in a special abbreviations module + + +def _maketup(descr, val): + dt = dtype(descr) + # Place val in all scalar tuples: + fields = dt.fields + if fields is None: + return val + else: + res = [_maketup(fields[name][0], val) for name in dt.names] + return tuple(res) + + +def identity(n, dtype=None): + """ + Return the identity array. + + The identity array is a square array with ones on + the main diagonal. + + Parameters + ---------- + n : int + Number of rows (and columns) in `n` x `n` output. + dtype : data-type, optional + Data-type of the output. Defaults to ``float``. + + Returns + ------- + out : ndarray + `n` x `n` array with its main diagonal set to one, + and all other elements 0. + + Examples + -------- + >>> np.identity(3) + array([[ 1., 0., 0.], + [ 0., 1., 0.], + [ 0., 0., 1.]]) + + """ + from numpy import eye + return eye(n, dtype=dtype) + + +def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): + """ + Returns True if two arrays are element-wise equal within a tolerance. + + The tolerance values are positive, typically very small numbers. The + relative difference (`rtol` * abs(`b`)) and the absolute difference + `atol` are added together to compare against the absolute difference + between `a` and `b`. + + If either array contains one or more NaNs, False is returned. + Infs are treated as equal if they are in the same place and of the same + sign in both arrays. + + Parameters + ---------- + a, b : array_like + Input arrays to compare. + rtol : float + The relative tolerance parameter (see Notes). + atol : float + The absolute tolerance parameter (see Notes). + equal_nan : bool + Whether to compare NaN's as equal. If True, NaN's in `a` will be + considered equal to NaN's in `b` in the output array. + + .. versionadded:: 1.10.0 + + Returns + ------- + allclose : bool + Returns True if the two arrays are equal within the given + tolerance; False otherwise. + + See Also + -------- + isclose, all, any, equal + + Notes + ----- + If the following equation is element-wise True, then allclose returns + True. + + absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`)) + + The above equation is not symmetric in `a` and `b`, so that + ``allclose(a, b)`` might be different from ``allclose(b, a)`` in + some rare cases. + + The comparison of `a` and `b` uses standard broadcasting, which + means that `a` and `b` need not have the same shape in order for + ``allclose(a, b)`` to evaluate to True. The same is true for + `equal` but not `array_equal`. + + Examples + -------- + >>> np.allclose([1e10,1e-7], [1.00001e10,1e-8]) + False + >>> np.allclose([1e10,1e-8], [1.00001e10,1e-9]) + True + >>> np.allclose([1e10,1e-8], [1.0001e10,1e-9]) + False + >>> np.allclose([1.0, np.nan], [1.0, np.nan]) + False + >>> np.allclose([1.0, np.nan], [1.0, np.nan], equal_nan=True) + True + + """ + res = all(isclose(a, b, rtol=rtol, atol=atol, equal_nan=equal_nan)) + return bool(res) + + +def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): + """ + Returns a boolean array where two arrays are element-wise equal within a + tolerance. + + The tolerance values are positive, typically very small numbers. The + relative difference (`rtol` * abs(`b`)) and the absolute difference + `atol` are added together to compare against the absolute difference + between `a` and `b`. + + Parameters + ---------- + a, b : array_like + Input arrays to compare. + rtol : float + The relative tolerance parameter (see Notes). + atol : float + The absolute tolerance parameter (see Notes). + equal_nan : bool + Whether to compare NaN's as equal. If True, NaN's in `a` will be + considered equal to NaN's in `b` in the output array. + + Returns + ------- + y : array_like + Returns a boolean array of where `a` and `b` are equal within the + given tolerance. If both `a` and `b` are scalars, returns a single + boolean value. + + See Also + -------- + allclose + + Notes + ----- + .. versionadded:: 1.7.0 + + For finite values, isclose uses the following equation to test whether + two floating point values are equivalent. + + absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`)) + + The above equation is not symmetric in `a` and `b`, so that + `isclose(a, b)` might be different from `isclose(b, a)` in + some rare cases. + + Examples + -------- + >>> np.isclose([1e10,1e-7], [1.00001e10,1e-8]) + array([True, False]) + >>> np.isclose([1e10,1e-8], [1.00001e10,1e-9]) + array([True, True]) + >>> np.isclose([1e10,1e-8], [1.0001e10,1e-9]) + array([False, True]) + >>> np.isclose([1.0, np.nan], [1.0, np.nan]) + array([True, False]) + >>> np.isclose([1.0, np.nan], [1.0, np.nan], equal_nan=True) + array([True, True]) + """ + def within_tol(x, y, atol, rtol): + with errstate(invalid='ignore'): + return less_equal(abs(x-y), atol + rtol * abs(y)) + + x = asanyarray(a) + y = asanyarray(b) + + # Make sure y is an inexact type to avoid bad behavior on abs(MIN_INT). + # This will cause casting of x later. Also, make sure to allow subclasses + # (e.g., for numpy.ma). + dt = multiarray.result_type(y, 1.) + y = array(y, dtype=dt, copy=False, subok=True) + + xfin = isfinite(x) + yfin = isfinite(y) + if all(xfin) and all(yfin): + return within_tol(x, y, atol, rtol) + else: + finite = xfin & yfin + cond = zeros_like(finite, subok=True) + # Because we're using boolean indexing, x & y must be the same shape. + # Ideally, we'd just do x, y = broadcast_arrays(x, y). It's in + # lib.stride_tricks, though, so we can't import it here. + x = x * ones_like(cond) + y = y * ones_like(cond) + # Avoid subtraction with infinite/nan values... + cond[finite] = within_tol(x[finite], y[finite], atol, rtol) + # Check for equality of infinite values... + cond[~finite] = (x[~finite] == y[~finite]) + if equal_nan: + # Make NaN == NaN + both_nan = isnan(x) & isnan(y) + + # Needed to treat masked arrays correctly. = True would not work. + cond[both_nan] = both_nan[both_nan] + + return cond[()] # Flatten 0d arrays to scalars + + +def array_equal(a1, a2): + """ + True if two arrays have the same shape and elements, False otherwise. + + Parameters + ---------- + a1, a2 : array_like + Input arrays. + + Returns + ------- + b : bool + Returns True if the arrays are equal. + + See Also + -------- + allclose: Returns True if two arrays are element-wise equal within a + tolerance. + array_equiv: Returns True if input arrays are shape consistent and all + elements equal. + + Examples + -------- + >>> np.array_equal([1, 2], [1, 2]) + True + >>> np.array_equal(np.array([1, 2]), np.array([1, 2])) + True + >>> np.array_equal([1, 2], [1, 2, 3]) + False + >>> np.array_equal([1, 2], [1, 4]) + False + + """ + try: + a1, a2 = asarray(a1), asarray(a2) + except Exception: + return False + if a1.shape != a2.shape: + return False + return bool(asarray(a1 == a2).all()) + + +def array_equiv(a1, a2): + """ + Returns True if input arrays are shape consistent and all elements equal. + + Shape consistent means they are either the same shape, or one input array + can be broadcasted to create the same shape as the other one. + + Parameters + ---------- + a1, a2 : array_like + Input arrays. + + Returns + ------- + out : bool + True if equivalent, False otherwise. + + Examples + -------- + >>> np.array_equiv([1, 2], [1, 2]) + True + >>> np.array_equiv([1, 2], [1, 3]) + False + + Showing the shape equivalence: + + >>> np.array_equiv([1, 2], [[1, 2], [1, 2]]) + True + >>> np.array_equiv([1, 2], [[1, 2, 1, 2], [1, 2, 1, 2]]) + False + + >>> np.array_equiv([1, 2], [[1, 2], [1, 3]]) + False + + """ + try: + a1, a2 = asarray(a1), asarray(a2) + except Exception: + return False + try: + multiarray.broadcast(a1, a2) + except Exception: + return False + + return bool(asarray(a1 == a2).all()) + + +_errdict = {"ignore":ERR_IGNORE, + "warn":ERR_WARN, + "raise":ERR_RAISE, + "call":ERR_CALL, + "print":ERR_PRINT, + "log":ERR_LOG} + +_errdict_rev = {} +for key in _errdict.keys(): + _errdict_rev[_errdict[key]] = key +del key + + +def seterr(all=None, divide=None, over=None, under=None, invalid=None): + """ + Set how floating-point errors are handled. + + Note that operations on integer scalar types (such as `int16`) are + handled like floating point, and are affected by these settings. + + Parameters + ---------- + all : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional + Set treatment for all types of floating-point errors at once: + + - ignore: Take no action when the exception occurs. + - warn: Print a `RuntimeWarning` (via the Python `warnings` module). + - raise: Raise a `FloatingPointError`. + - call: Call a function specified using the `seterrcall` function. + - print: Print a warning directly to ``stdout``. + - log: Record error in a Log object specified by `seterrcall`. + + The default is not to change the current behavior. + divide : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional + Treatment for division by zero. + over : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional + Treatment for floating-point overflow. + under : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional + Treatment for floating-point underflow. + invalid : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional + Treatment for invalid floating-point operation. + + Returns + ------- + old_settings : dict + Dictionary containing the old settings. + + See also + -------- + seterrcall : Set a callback function for the 'call' mode. + geterr, geterrcall, errstate + + Notes + ----- + The floating-point exceptions are defined in the IEEE 754 standard [1]: + + - Division by zero: infinite result obtained from finite numbers. + - Overflow: result too large to be expressed. + - Underflow: result so close to zero that some precision + was lost. + - Invalid operation: result is not an expressible number, typically + indicates that a NaN was produced. + + .. [1] http://en.wikipedia.org/wiki/IEEE_754 + + Examples + -------- + >>> old_settings = np.seterr(all='ignore') #seterr to known value + >>> np.seterr(over='raise') + {'over': 'ignore', 'divide': 'ignore', 'invalid': 'ignore', + 'under': 'ignore'} + >>> np.seterr(**old_settings) # reset to default + {'over': 'raise', 'divide': 'ignore', 'invalid': 'ignore', 'under': 'ignore'} + + >>> np.int16(32000) * np.int16(3) + 30464 + >>> old_settings = np.seterr(all='warn', over='raise') + >>> np.int16(32000) * np.int16(3) + Traceback (most recent call last): + File "", line 1, in + FloatingPointError: overflow encountered in short_scalars + + >>> old_settings = np.seterr(all='print') + >>> np.geterr() + {'over': 'print', 'divide': 'print', 'invalid': 'print', 'under': 'print'} + >>> np.int16(32000) * np.int16(3) + Warning: overflow encountered in short_scalars + 30464 + + """ + + pyvals = umath.geterrobj() + old = geterr() + + if divide is None: + divide = all or old['divide'] + if over is None: + over = all or old['over'] + if under is None: + under = all or old['under'] + if invalid is None: + invalid = all or old['invalid'] + + maskvalue = ((_errdict[divide] << SHIFT_DIVIDEBYZERO) + + (_errdict[over] << SHIFT_OVERFLOW) + + (_errdict[under] << SHIFT_UNDERFLOW) + + (_errdict[invalid] << SHIFT_INVALID)) + + pyvals[1] = maskvalue + umath.seterrobj(pyvals) + return old + + +def geterr(): + """ + Get the current way of handling floating-point errors. + + Returns + ------- + res : dict + A dictionary with keys "divide", "over", "under", and "invalid", + whose values are from the strings "ignore", "print", "log", "warn", + "raise", and "call". The keys represent possible floating-point + exceptions, and the values define how these exceptions are handled. + + See Also + -------- + geterrcall, seterr, seterrcall + + Notes + ----- + For complete documentation of the types of floating-point exceptions and + treatment options, see `seterr`. + + Examples + -------- + >>> np.geterr() + {'over': 'warn', 'divide': 'warn', 'invalid': 'warn', + 'under': 'ignore'} + >>> np.arange(3.) / np.arange(3.) + array([ NaN, 1., 1.]) + + >>> oldsettings = np.seterr(all='warn', over='raise') + >>> np.geterr() + {'over': 'raise', 'divide': 'warn', 'invalid': 'warn', 'under': 'warn'} + >>> np.arange(3.) / np.arange(3.) + __main__:1: RuntimeWarning: invalid value encountered in divide + array([ NaN, 1., 1.]) + + """ + maskvalue = umath.geterrobj()[1] + mask = 7 + res = {} + val = (maskvalue >> SHIFT_DIVIDEBYZERO) & mask + res['divide'] = _errdict_rev[val] + val = (maskvalue >> SHIFT_OVERFLOW) & mask + res['over'] = _errdict_rev[val] + val = (maskvalue >> SHIFT_UNDERFLOW) & mask + res['under'] = _errdict_rev[val] + val = (maskvalue >> SHIFT_INVALID) & mask + res['invalid'] = _errdict_rev[val] + return res + + +def setbufsize(size): + """ + Set the size of the buffer used in ufuncs. + + Parameters + ---------- + size : int + Size of buffer. + + """ + if size > 10e6: + raise ValueError("Buffer size, %s, is too big." % size) + if size < 5: + raise ValueError("Buffer size, %s, is too small." % size) + if size % 16 != 0: + raise ValueError("Buffer size, %s, is not a multiple of 16." % size) + + pyvals = umath.geterrobj() + old = getbufsize() + pyvals[0] = size + umath.seterrobj(pyvals) + return old + + +def getbufsize(): + """ + Return the size of the buffer used in ufuncs. + + Returns + ------- + getbufsize : int + Size of ufunc buffer in bytes. + + """ + return umath.geterrobj()[0] + + +def seterrcall(func): + """ + Set the floating-point error callback function or log object. + + There are two ways to capture floating-point error messages. The first + is to set the error-handler to 'call', using `seterr`. Then, set + the function to call using this function. + + The second is to set the error-handler to 'log', using `seterr`. + Floating-point errors then trigger a call to the 'write' method of + the provided object. + + Parameters + ---------- + func : callable f(err, flag) or object with write method + Function to call upon floating-point errors ('call'-mode) or + object whose 'write' method is used to log such message ('log'-mode). + + The call function takes two arguments. The first is a string describing the + type of error (such as "divide by zero", "overflow", "underflow", or "invalid value"), + and the second is the status flag. The flag is a byte, whose four + least-significant bits indicate the type of error, one of "divide", "over", + "under", "invalid":: + + [0 0 0 0 divide over under invalid] + + In other words, ``flags = divide + 2*over + 4*under + 8*invalid``. + + If an object is provided, its write method should take one argument, + a string. + + Returns + ------- + h : callable, log instance or None + The old error handler. + + See Also + -------- + seterr, geterr, geterrcall + + Examples + -------- + Callback upon error: + + >>> def err_handler(type, flag): + ... print("Floating point error (%s), with flag %s" % (type, flag)) + ... + + >>> saved_handler = np.seterrcall(err_handler) + >>> save_err = np.seterr(all='call') + + >>> np.array([1, 2, 3]) / 0.0 + Floating point error (divide by zero), with flag 1 + array([ Inf, Inf, Inf]) + + >>> np.seterrcall(saved_handler) + + >>> np.seterr(**save_err) + {'over': 'call', 'divide': 'call', 'invalid': 'call', 'under': 'call'} + + Log error message: + + >>> class Log(object): + ... def write(self, msg): + ... print("LOG: %s" % msg) + ... + + >>> log = Log() + >>> saved_handler = np.seterrcall(log) + >>> save_err = np.seterr(all='log') + + >>> np.array([1, 2, 3]) / 0.0 + LOG: Warning: divide by zero encountered in divide + + array([ Inf, Inf, Inf]) + + >>> np.seterrcall(saved_handler) + <__main__.Log object at 0x...> + >>> np.seterr(**save_err) + {'over': 'log', 'divide': 'log', 'invalid': 'log', 'under': 'log'} + + """ + if func is not None and not isinstance(func, collections.Callable): + if not hasattr(func, 'write') or not isinstance(func.write, collections.Callable): + raise ValueError("Only callable can be used as callback") + pyvals = umath.geterrobj() + old = geterrcall() + pyvals[2] = func + umath.seterrobj(pyvals) + return old + + +def geterrcall(): + """ + Return the current callback function used on floating-point errors. + + When the error handling for a floating-point error (one of "divide", + "over", "under", or "invalid") is set to 'call' or 'log', the function + that is called or the log instance that is written to is returned by + `geterrcall`. This function or log instance has been set with + `seterrcall`. + + Returns + ------- + errobj : callable, log instance or None + The current error handler. If no handler was set through `seterrcall`, + ``None`` is returned. + + See Also + -------- + seterrcall, seterr, geterr + + Notes + ----- + For complete documentation of the types of floating-point exceptions and + treatment options, see `seterr`. + + Examples + -------- + >>> np.geterrcall() # we did not yet set a handler, returns None + + >>> oldsettings = np.seterr(all='call') + >>> def err_handler(type, flag): + ... print("Floating point error (%s), with flag %s" % (type, flag)) + >>> oldhandler = np.seterrcall(err_handler) + >>> np.array([1, 2, 3]) / 0.0 + Floating point error (divide by zero), with flag 1 + array([ Inf, Inf, Inf]) + + >>> cur_handler = np.geterrcall() + >>> cur_handler is err_handler + True + + """ + return umath.geterrobj()[2] + + +class _unspecified(object): + pass +_Unspecified = _unspecified() + + +class errstate(object): + """ + errstate(**kwargs) + + Context manager for floating-point error handling. + + Using an instance of `errstate` as a context manager allows statements in + that context to execute with a known error handling behavior. Upon entering + the context the error handling is set with `seterr` and `seterrcall`, and + upon exiting it is reset to what it was before. + + Parameters + ---------- + kwargs : {divide, over, under, invalid} + Keyword arguments. The valid keywords are the possible floating-point + exceptions. Each keyword should have a string value that defines the + treatment for the particular error. Possible values are + {'ignore', 'warn', 'raise', 'call', 'print', 'log'}. + + See Also + -------- + seterr, geterr, seterrcall, geterrcall + + Notes + ----- + The ``with`` statement was introduced in Python 2.5, and can only be used + there by importing it: ``from __future__ import with_statement``. In + earlier Python versions the ``with`` statement is not available. + + For complete documentation of the types of floating-point exceptions and + treatment options, see `seterr`. + + Examples + -------- + >>> from __future__ import with_statement # use 'with' in Python 2.5 + >>> olderr = np.seterr(all='ignore') # Set error handling to known state. + + >>> np.arange(3) / 0. + array([ NaN, Inf, Inf]) + >>> with np.errstate(divide='warn'): + ... np.arange(3) / 0. + ... + __main__:2: RuntimeWarning: divide by zero encountered in divide + array([ NaN, Inf, Inf]) + + >>> np.sqrt(-1) + nan + >>> with np.errstate(invalid='raise'): + ... np.sqrt(-1) + Traceback (most recent call last): + File "", line 2, in + FloatingPointError: invalid value encountered in sqrt + + Outside the context the error handling behavior has not changed: + + >>> np.geterr() + {'over': 'warn', 'divide': 'warn', 'invalid': 'warn', + 'under': 'ignore'} + + """ + # Note that we don't want to run the above doctests because they will fail + # without a from __future__ import with_statement + + def __init__(self, **kwargs): + self.call = kwargs.pop('call', _Unspecified) + self.kwargs = kwargs + + def __enter__(self): + self.oldstate = seterr(**self.kwargs) + if self.call is not _Unspecified: + self.oldcall = seterrcall(self.call) + + def __exit__(self, *exc_info): + seterr(**self.oldstate) + if self.call is not _Unspecified: + seterrcall(self.oldcall) + + +def _setdef(): + defval = [UFUNC_BUFSIZE_DEFAULT, ERR_DEFAULT, None] + umath.seterrobj(defval) + + +# set the default values +_setdef() + +Inf = inf = infty = Infinity = PINF +nan = NaN = NAN +False_ = bool_(False) +True_ = bool_(True) + + +def extend_all(module): + adict = {} + for a in __all__: + adict[a] = 1 + try: + mall = getattr(module, '__all__') + except AttributeError: + mall = [k for k in module.__dict__.keys() if not k.startswith('_')] + for a in mall: + if a not in adict: + __all__.append(a) + +from .umath import * +from .numerictypes import * +from . import fromnumeric +from .fromnumeric import * +from . import arrayprint +from .arrayprint import * +extend_all(fromnumeric) +extend_all(umath) +extend_all(numerictypes) +extend_all(arrayprint) diff --git a/numpy/core/numerictypes.py b/numpy/core/numerictypes.py new file mode 100644 index 0000000..b61f5e7 --- /dev/null +++ b/numpy/core/numerictypes.py @@ -0,0 +1,1034 @@ +""" +numerictypes: Define the numeric type objects + +This module is designed so "from numerictypes import \\*" is safe. +Exported symbols include: + + Dictionary with all registered number types (including aliases): + typeDict + + Type objects (not all will be available, depends on platform): + see variable sctypes for which ones you have + + Bit-width names + + int8 int16 int32 int64 int128 + uint8 uint16 uint32 uint64 uint128 + float16 float32 float64 float96 float128 float256 + complex32 complex64 complex128 complex192 complex256 complex512 + datetime64 timedelta64 + + c-based names + + bool_ + + object_ + + void, str_, unicode_ + + byte, ubyte, + short, ushort + intc, uintc, + intp, uintp, + int_, uint, + longlong, ulonglong, + + single, csingle, + float_, complex_, + longfloat, clongfloat, + + As part of the type-hierarchy: xx -- is bit-width + + generic + +-> bool_ (kind=b) + +-> number (kind=i) + | integer + | signedinteger (intxx) + | byte + | short + | intc + | intp int0 + | int_ + | longlong + +-> unsignedinteger (uintxx) (kind=u) + | ubyte + | ushort + | uintc + | uintp uint0 + | uint_ + | ulonglong + +-> inexact + | +-> floating (floatxx) (kind=f) + | | half + | | single + | | float_ (double) + | | longfloat + | \\-> complexfloating (complexxx) (kind=c) + | csingle (singlecomplex) + | complex_ (cfloat, cdouble) + | clongfloat (longcomplex) + +-> flexible + | character + | void (kind=V) + | + | str_ (string_, bytes_) (kind=S) [Python 2] + | unicode_ (kind=U) [Python 2] + | + | bytes_ (string_) (kind=S) [Python 3] + | str_ (unicode_) (kind=U) [Python 3] + | + \\-> object_ (not used much) (kind=O) + +""" +from __future__ import division, absolute_import, print_function + +import types as _types +import sys +import numbers +import warnings + +from numpy.compat import bytes, long +from numpy.core.multiarray import ( + typeinfo, ndarray, array, empty, dtype, datetime_data, + datetime_as_string, busday_offset, busday_count, is_busday, + busdaycalendar + ) + + +# we add more at the bottom +__all__ = ['sctypeDict', 'sctypeNA', 'typeDict', 'typeNA', 'sctypes', + 'ScalarType', 'obj2sctype', 'cast', 'nbytes', 'sctype2char', + 'maximum_sctype', 'issctype', 'typecodes', 'find_common_type', + 'issubdtype', 'datetime_data', 'datetime_as_string', + 'busday_offset', 'busday_count', 'is_busday', 'busdaycalendar', + ] + + +# we don't export these for import *, but we do want them accessible +# as numerictypes.bool, etc. +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 + + +# String-handling utilities to avoid locale-dependence. + +# "import string" is costly to import! +# Construct the translation tables directly +# "A" = chr(65), "a" = chr(97) +_all_chars = [chr(_m) for _m in range(256)] +_ascii_upper = _all_chars[65:65+26] +_ascii_lower = _all_chars[97:97+26] +LOWER_TABLE = "".join(_all_chars[:65] + _ascii_lower + _all_chars[65+26:]) +UPPER_TABLE = "".join(_all_chars[:97] + _ascii_upper + _all_chars[97+26:]) + + +def english_lower(s): + """ Apply English case rules to convert ASCII strings to all lower case. + + This is an internal utility function to replace calls to str.lower() such + that we can avoid changing behavior with changing locales. In particular, + Turkish has distinct dotted and dotless variants of the Latin letter "I" in + both lowercase and uppercase. Thus, "I".lower() != "i" in a "tr" locale. + + Parameters + ---------- + s : str + + Returns + ------- + lowered : str + + Examples + -------- + >>> from numpy.core.numerictypes import english_lower + >>> english_lower('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_') + 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789_' + >>> english_lower('') + '' + """ + lowered = s.translate(LOWER_TABLE) + return lowered + +def english_upper(s): + """ Apply English case rules to convert ASCII strings to all upper case. + + This is an internal utility function to replace calls to str.upper() such + that we can avoid changing behavior with changing locales. In particular, + Turkish has distinct dotted and dotless variants of the Latin letter "I" in + both lowercase and uppercase. Thus, "i".upper() != "I" in a "tr" locale. + + Parameters + ---------- + s : str + + Returns + ------- + uppered : str + + Examples + -------- + >>> from numpy.core.numerictypes import english_upper + >>> english_upper('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_') + 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' + >>> english_upper('') + '' + """ + uppered = s.translate(UPPER_TABLE) + return uppered + +def english_capitalize(s): + """ Apply English case rules to convert the first character of an ASCII + string to upper case. + + This is an internal utility function to replace calls to str.capitalize() + such that we can avoid changing behavior with changing locales. + + Parameters + ---------- + s : str + + Returns + ------- + capitalized : str + + Examples + -------- + >>> from numpy.core.numerictypes import english_capitalize + >>> english_capitalize('int8') + 'Int8' + >>> english_capitalize('Int8') + 'Int8' + >>> english_capitalize('') + '' + """ + if s: + return english_upper(s[0]) + s[1:] + else: + return s + + +sctypeDict = {} # Contains all leaf-node scalar types with aliases +sctypeNA = {} # Contails all leaf-node types -> numarray type equivalences +allTypes = {} # Collect the types we will add to the module here + +def _evalname(name): + k = 0 + for ch in name: + if ch in '0123456789': + break + k += 1 + try: + bits = int(name[k:]) + except ValueError: + bits = 0 + base = name[:k] + return base, bits + +def bitname(obj): + """Return a bit-width name for a given type object""" + name = obj.__name__ + base = '' + char = '' + try: + if name[-1] == '_': + newname = name[:-1] + else: + newname = name + info = typeinfo[english_upper(newname)] + assert(info[-1] == obj) # sanity check + bits = info[2] + + except KeyError: # bit-width name + base, bits = _evalname(name) + char = base[0] + + if name == 'bool_': + char = 'b' + base = 'bool' + elif name == 'void': + char = 'V' + base = 'void' + elif name == 'object_': + char = 'O' + base = 'object' + bits = 0 + elif name == 'datetime64': + char = 'M' + elif name == 'timedelta64': + char = 'm' + + if sys.version_info[0] >= 3: + if name == 'bytes_': + char = 'S' + base = 'bytes' + elif name == 'str_': + char = 'U' + base = 'str' + else: + if name == 'string_': + char = 'S' + base = 'string' + elif name == 'unicode_': + char = 'U' + base = 'unicode' + + bytes = bits // 8 + + if char != '' and bytes != 0: + char = "%s%d" % (char, bytes) + + return base, bits, char + + +def _add_types(): + for a in typeinfo.keys(): + name = english_lower(a) + if isinstance(typeinfo[a], tuple): + typeobj = typeinfo[a][-1] + + # define C-name and insert typenum and typechar references also + allTypes[name] = typeobj + sctypeDict[name] = typeobj + sctypeDict[typeinfo[a][0]] = typeobj + sctypeDict[typeinfo[a][1]] = typeobj + + else: # generic class + allTypes[name] = typeinfo[a] +_add_types() + +def _add_aliases(): + for a in typeinfo.keys(): + name = english_lower(a) + if not isinstance(typeinfo[a], tuple): + continue + typeobj = typeinfo[a][-1] + # insert bit-width version for this class (if relevant) + base, bit, char = bitname(typeobj) + if base[-3:] == 'int' or char[0] in 'ui': + continue + if base != '': + myname = "%s%d" % (base, bit) + if ((name != 'longdouble' and name != 'clongdouble') or + myname not in allTypes.keys()): + allTypes[myname] = typeobj + sctypeDict[myname] = typeobj + if base == 'complex': + na_name = '%s%d' % (english_capitalize(base), bit//2) + elif base == 'bool': + na_name = english_capitalize(base) + sctypeDict[na_name] = typeobj + else: + na_name = "%s%d" % (english_capitalize(base), bit) + sctypeDict[na_name] = typeobj + sctypeNA[na_name] = typeobj + sctypeDict[na_name] = typeobj + sctypeNA[typeobj] = na_name + sctypeNA[typeinfo[a][0]] = na_name + if char != '': + sctypeDict[char] = typeobj + sctypeNA[char] = na_name +_add_aliases() + +# Integers are handled so that the int32 and int64 types should agree +# exactly with NPY_INT32, NPY_INT64. We need to enforce the same checking +# as is done in arrayobject.h where the order of getting a bit-width match +# is long, longlong, int, short, char. +def _add_integer_aliases(): + _ctypes = ['LONG', 'LONGLONG', 'INT', 'SHORT', 'BYTE'] + for ctype in _ctypes: + val = typeinfo[ctype] + bits = val[2] + charname = 'i%d' % (bits//8,) + ucharname = 'u%d' % (bits//8,) + intname = 'int%d' % bits + UIntname = 'UInt%d' % bits + Intname = 'Int%d' % bits + uval = typeinfo['U'+ctype] + typeobj = val[-1] + utypeobj = uval[-1] + if intname not in allTypes.keys(): + uintname = 'uint%d' % bits + allTypes[intname] = typeobj + allTypes[uintname] = utypeobj + sctypeDict[intname] = typeobj + sctypeDict[uintname] = utypeobj + sctypeDict[Intname] = typeobj + sctypeDict[UIntname] = utypeobj + sctypeDict[charname] = typeobj + sctypeDict[ucharname] = utypeobj + sctypeNA[Intname] = typeobj + sctypeNA[UIntname] = utypeobj + sctypeNA[charname] = typeobj + sctypeNA[ucharname] = utypeobj + sctypeNA[typeobj] = Intname + sctypeNA[utypeobj] = UIntname + sctypeNA[val[0]] = Intname + sctypeNA[uval[0]] = UIntname +_add_integer_aliases() + +# We use these later +void = allTypes['void'] +generic = allTypes['generic'] + +# +# Rework the Python names (so that float and complex and int are consistent +# with Python usage) +# +def _set_up_aliases(): + type_pairs = [('complex_', 'cdouble'), + ('int0', 'intp'), + ('uint0', 'uintp'), + ('single', 'float'), + ('csingle', 'cfloat'), + ('singlecomplex', 'cfloat'), + ('float_', 'double'), + ('intc', 'int'), + ('uintc', 'uint'), + ('int_', 'long'), + ('uint', 'ulong'), + ('cfloat', 'cdouble'), + ('longfloat', 'longdouble'), + ('clongfloat', 'clongdouble'), + ('longcomplex', 'clongdouble'), + ('bool_', 'bool'), + ('unicode_', 'unicode'), + ('object_', 'object')] + if sys.version_info[0] >= 3: + type_pairs.extend([('bytes_', 'string'), + ('str_', 'unicode'), + ('string_', 'string')]) + else: + type_pairs.extend([('str_', 'string'), + ('string_', 'string'), + ('bytes_', 'string')]) + for alias, t in type_pairs: + allTypes[alias] = allTypes[t] + sctypeDict[alias] = sctypeDict[t] + # Remove aliases overriding python types and modules + to_remove = ['ulong', 'object', 'unicode', 'int', 'long', 'float', + 'complex', 'bool', 'string', 'datetime', 'timedelta'] + if sys.version_info[0] >= 3: + # Py3K + to_remove.append('bytes') + to_remove.append('str') + to_remove.remove('unicode') + to_remove.remove('long') + for t in to_remove: + try: + del allTypes[t] + del sctypeDict[t] + except KeyError: + pass +_set_up_aliases() + +# Now, construct dictionary to lookup character codes from types +_sctype2char_dict = {} +def _construct_char_code_lookup(): + for name in typeinfo.keys(): + tup = typeinfo[name] + if isinstance(tup, tuple): + if tup[0] not in ['p', 'P']: + _sctype2char_dict[tup[-1]] = tup[0] +_construct_char_code_lookup() + + +sctypes = {'int': [], + 'uint':[], + 'float':[], + 'complex':[], + 'others':[bool, object, bytes, unicode, void]} + +def _add_array_type(typename, bits): + try: + t = allTypes['%s%d' % (typename, bits)] + except KeyError: + pass + else: + sctypes[typename].append(t) + +def _set_array_types(): + ibytes = [1, 2, 4, 8, 16, 32, 64] + fbytes = [2, 4, 8, 10, 12, 16, 32, 64] + for bytes in ibytes: + bits = 8*bytes + _add_array_type('int', bits) + _add_array_type('uint', bits) + for bytes in fbytes: + bits = 8*bytes + _add_array_type('float', bits) + _add_array_type('complex', 2*bits) + _gi = dtype('p') + if _gi.type not in sctypes['int']: + indx = 0 + sz = _gi.itemsize + _lst = sctypes['int'] + while (indx < len(_lst) and sz >= _lst[indx](0).itemsize): + indx += 1 + sctypes['int'].insert(indx, _gi.type) + sctypes['uint'].insert(indx, dtype('P').type) +_set_array_types() + + +genericTypeRank = ['bool', 'int8', 'uint8', 'int16', 'uint16', + 'int32', 'uint32', 'int64', 'uint64', 'int128', + 'uint128', 'float16', + 'float32', 'float64', 'float80', 'float96', 'float128', + 'float256', + 'complex32', 'complex64', 'complex128', 'complex160', + 'complex192', 'complex256', 'complex512', 'object'] + +def maximum_sctype(t): + """ + Return the scalar type of highest precision of the same kind as the input. + + Parameters + ---------- + t : dtype or dtype specifier + The input data type. This can be a `dtype` object or an object that + is convertible to a `dtype`. + + Returns + ------- + out : dtype + The highest precision data type of the same kind (`dtype.kind`) as `t`. + + See Also + -------- + obj2sctype, mintypecode, sctype2char + dtype + + Examples + -------- + >>> np.maximum_sctype(int) + + >>> np.maximum_sctype(np.uint8) + + >>> np.maximum_sctype(complex) + + + >>> np.maximum_sctype(str) + + + >>> np.maximum_sctype('i2') + + >>> np.maximum_sctype('f4') + + + """ + g = obj2sctype(t) + if g is None: + return t + t = g + name = t.__name__ + base, bits = _evalname(name) + if bits == 0: + return t + else: + return sctypes[base][-1] + + +def issctype(rep): + """ + Determines whether the given object represents a scalar data-type. + + Parameters + ---------- + rep : any + If `rep` is an instance of a scalar dtype, True is returned. If not, + False is returned. + + Returns + ------- + out : bool + Boolean result of check whether `rep` is a scalar dtype. + + See Also + -------- + issubsctype, issubdtype, obj2sctype, sctype2char + + Examples + -------- + >>> np.issctype(np.int32) + True + >>> np.issctype(list) + False + >>> np.issctype(1.1) + False + + Strings are also a scalar type: + + >>> np.issctype(np.dtype('str')) + True + + """ + if not isinstance(rep, (type, dtype)): + return False + try: + res = obj2sctype(rep) + if res and res != object_: + return True + return False + except Exception: + return False + +def obj2sctype(rep, default=None): + """ + Return the scalar dtype or NumPy equivalent of Python type of an object. + + Parameters + ---------- + rep : any + The object of which the type is returned. + default : any, optional + If given, this is returned for objects whose types can not be + determined. If not given, None is returned for those objects. + + Returns + ------- + dtype : dtype or Python type + The data type of `rep`. + + See Also + -------- + sctype2char, issctype, issubsctype, issubdtype, maximum_sctype + + Examples + -------- + >>> np.obj2sctype(np.int32) + + >>> np.obj2sctype(np.array([1., 2.])) + + >>> np.obj2sctype(np.array([1.j])) + + + >>> np.obj2sctype(dict) + + >>> np.obj2sctype('string') + + + >>> np.obj2sctype(1, default=list) + + + """ + # prevent abtract classes being upcast + if isinstance(rep, type) and issubclass(rep, generic): + return rep + # extract dtype from arrays + if isinstance(rep, ndarray): + return rep.dtype.type + # fall back on dtype to convert + try: + res = dtype(rep) + except Exception: + return default + else: + return res.type + + +def issubclass_(arg1, arg2): + """ + Determine if a class is a subclass of a second class. + + `issubclass_` is equivalent to the Python built-in ``issubclass``, + except that it returns False instead of raising a TypeError if one + of the arguments is not a class. + + Parameters + ---------- + arg1 : class + Input class. True is returned if `arg1` is a subclass of `arg2`. + arg2 : class or tuple of classes. + Input class. If a tuple of classes, True is returned if `arg1` is a + subclass of any of the tuple elements. + + Returns + ------- + out : bool + Whether `arg1` is a subclass of `arg2` or not. + + See Also + -------- + issubsctype, issubdtype, issctype + + Examples + -------- + >>> np.issubclass_(np.int32, int) + True + >>> np.issubclass_(np.int32, float) + False + + """ + try: + return issubclass(arg1, arg2) + except TypeError: + return False + +def issubsctype(arg1, arg2): + """ + Determine if the first argument is a subclass of the second argument. + + Parameters + ---------- + arg1, arg2 : dtype or dtype specifier + Data-types. + + Returns + ------- + out : bool + The result. + + See Also + -------- + issctype, issubdtype,obj2sctype + + Examples + -------- + >>> np.issubsctype('S8', str) + True + >>> np.issubsctype(np.array([1]), int) + True + >>> np.issubsctype(np.array([1]), float) + False + + """ + return issubclass(obj2sctype(arg1), obj2sctype(arg2)) + +def issubdtype(arg1, arg2): + """ + Returns True if first argument is a typecode lower/equal in type hierarchy. + + Parameters + ---------- + arg1, arg2 : dtype_like + dtype or string representing a typecode. + + Returns + ------- + out : bool + + See Also + -------- + issubsctype, issubclass_ + numpy.core.numerictypes : Overview of numpy type hierarchy. + + Examples + -------- + >>> np.issubdtype('S1', np.string_) + True + >>> np.issubdtype(np.float64, np.float32) + False + + """ + if not issubclass_(arg1, generic): + arg1 = dtype(arg1).type + if not issubclass_(arg2, generic): + arg2_orig = arg2 + arg2 = dtype(arg2).type + if not isinstance(arg2_orig, dtype): + # weird deprecated behaviour, that tried to infer np.floating from + # float, and similar less obvious things, such as np.generic from + # basestring + mro = arg2.mro() + arg2 = mro[1] if len(mro) > 1 else mro[0] + + def type_repr(x): + """ Helper to produce clear error messages """ + if not isinstance(x, type): + return repr(x) + elif issubclass(x, generic): + return "np.{}".format(x.__name__) + else: + return x.__name__ + + # 1.14, 2017-08-01 + warnings.warn( + "Conversion of the second argument of issubdtype from `{raw}` " + "to `{abstract}` is deprecated. In future, it will be treated " + "as `{concrete} == np.dtype({raw}).type`.".format( + raw=type_repr(arg2_orig), + abstract=type_repr(arg2), + concrete=type_repr(dtype(arg2_orig).type) + ), + FutureWarning, stacklevel=2 + ) + + return issubclass(arg1, arg2) + + +# This dictionary allows look up based on any alias for an array data-type +class _typedict(dict): + """ + Base object for a dictionary for look-up with any alias for an array dtype. + + Instances of `_typedict` can not be used as dictionaries directly, + first they have to be populated. + + """ + + def __getitem__(self, obj): + return dict.__getitem__(self, obj2sctype(obj)) + +nbytes = _typedict() +_alignment = _typedict() +_maxvals = _typedict() +_minvals = _typedict() +def _construct_lookups(): + for name, val in typeinfo.items(): + if not isinstance(val, tuple): + continue + obj = val[-1] + nbytes[obj] = val[2] // 8 + _alignment[obj] = val[3] + if (len(val) > 5): + _maxvals[obj] = val[4] + _minvals[obj] = val[5] + else: + _maxvals[obj] = None + _minvals[obj] = None + +_construct_lookups() + +def sctype2char(sctype): + """ + Return the string representation of a scalar dtype. + + Parameters + ---------- + sctype : scalar dtype or object + If a scalar dtype, the corresponding string character is + returned. If an object, `sctype2char` tries to infer its scalar type + and then return the corresponding string character. + + Returns + ------- + typechar : str + The string character corresponding to the scalar type. + + Raises + ------ + ValueError + If `sctype` is an object for which the type can not be inferred. + + See Also + -------- + obj2sctype, issctype, issubsctype, mintypecode + + Examples + -------- + >>> for sctype in [np.int32, float, complex, np.string_, np.ndarray]: + ... print(np.sctype2char(sctype)) + l + d + D + S + O + + >>> x = np.array([1., 2-1.j]) + >>> np.sctype2char(x) + 'D' + >>> np.sctype2char(list) + 'O' + + """ + sctype = obj2sctype(sctype) + if sctype is None: + raise ValueError("unrecognized type") + return _sctype2char_dict[sctype] + +# Create dictionary of casting functions that wrap sequences +# indexed by type or type character + + +cast = _typedict() +try: + ScalarType = [_types.IntType, _types.FloatType, _types.ComplexType, + _types.LongType, _types.BooleanType, + _types.StringType, _types.UnicodeType, _types.BufferType] +except AttributeError: + # Py3K + ScalarType = [int, float, complex, int, bool, bytes, str, memoryview] + +ScalarType.extend(_sctype2char_dict.keys()) +ScalarType = tuple(ScalarType) +for key in _sctype2char_dict.keys(): + cast[key] = lambda x, k=key: array(x, copy=False).astype(k) + +# Create the typestring lookup dictionary +_typestr = _typedict() +for key in _sctype2char_dict.keys(): + if issubclass(key, allTypes['flexible']): + _typestr[key] = _sctype2char_dict[key] + else: + _typestr[key] = empty((1,), key).dtype.str[1:] + +# Make sure all typestrings are in sctypeDict +for key, val in _typestr.items(): + if val not in sctypeDict: + sctypeDict[val] = key + +# Add additional strings to the sctypeDict + +if sys.version_info[0] >= 3: + _toadd = ['int', 'float', 'complex', 'bool', 'object', + 'str', 'bytes', 'object', ('a', allTypes['bytes_'])] +else: + _toadd = ['int', 'float', 'complex', 'bool', 'object', 'string', + ('str', allTypes['string_']), + 'unicode', 'object', ('a', allTypes['string_'])] + +for name in _toadd: + if isinstance(name, tuple): + sctypeDict[name[0]] = name[1] + else: + sctypeDict[name] = allTypes['%s_' % name] + +del _toadd, name + +# Now add the types we've determined to this module +for key in allTypes: + globals()[key] = allTypes[key] + __all__.append(key) + +del key + +typecodes = {'Character':'c', + 'Integer':'bhilqp', + 'UnsignedInteger':'BHILQP', + 'Float':'efdg', + 'Complex':'FDG', + 'AllInteger':'bBhHiIlLqQpP', + 'AllFloat':'efdgFDG', + 'Datetime': 'Mm', + 'All':'?bhilqpBHILQPefdgFDGSUVOMm'} + +# backwards compatibility --- deprecated name +typeDict = sctypeDict +typeNA = sctypeNA + +# b -> boolean +# u -> unsigned integer +# i -> signed integer +# f -> floating point +# c -> complex +# M -> datetime +# m -> timedelta +# S -> string +# U -> Unicode string +# V -> record +# O -> Python object +_kind_list = ['b', 'u', 'i', 'f', 'c', 'S', 'U', 'V', 'O', 'M', 'm'] + +__test_types = '?'+typecodes['AllInteger'][:-2]+typecodes['AllFloat']+'O' +__len_test_types = len(__test_types) + +# Keep incrementing until a common type both can be coerced to +# is found. Otherwise, return None +def _find_common_coerce(a, b): + if a > b: + return a + try: + thisind = __test_types.index(a.char) + except ValueError: + return None + return _can_coerce_all([a, b], start=thisind) + +# Find a data-type that all data-types in a list can be coerced to +def _can_coerce_all(dtypelist, start=0): + N = len(dtypelist) + if N == 0: + return None + if N == 1: + return dtypelist[0] + thisind = start + while thisind < __len_test_types: + newdtype = dtype(__test_types[thisind]) + numcoerce = len([x for x in dtypelist if newdtype >= x]) + if numcoerce == N: + return newdtype + thisind += 1 + return None + +def _register_types(): + numbers.Integral.register(integer) + numbers.Complex.register(inexact) + numbers.Real.register(floating) + numbers.Number.register(number) + +_register_types() + +def find_common_type(array_types, scalar_types): + """ + Determine common type following standard coercion rules. + + Parameters + ---------- + array_types : sequence + A list of dtypes or dtype convertible objects representing arrays. + scalar_types : sequence + A list of dtypes or dtype convertible objects representing scalars. + + Returns + ------- + datatype : dtype + The common data type, which is the maximum of `array_types` ignoring + `scalar_types`, unless the maximum of `scalar_types` is of a + different kind (`dtype.kind`). If the kind is not understood, then + None is returned. + + See Also + -------- + dtype, common_type, can_cast, mintypecode + + Examples + -------- + >>> np.find_common_type([], [np.int64, np.float32, complex]) + dtype('complex128') + >>> np.find_common_type([np.int64, np.float32], []) + dtype('float64') + + The standard casting rules ensure that a scalar cannot up-cast an + array unless the scalar is of a fundamentally different kind of data + (i.e. under a different hierarchy in the data type hierarchy) then + the array: + + >>> np.find_common_type([np.float32], [np.int64, np.float64]) + dtype('float32') + + Complex is of a different type, so it up-casts the float in the + `array_types` argument: + + >>> np.find_common_type([np.float32], [complex]) + dtype('complex128') + + Type specifier strings are convertible to dtypes and can therefore + be used instead of dtypes: + + >>> np.find_common_type(['f4', 'f4', 'i4'], ['c8']) + dtype('complex128') + + """ + array_types = [dtype(x) for x in array_types] + scalar_types = [dtype(x) for x in scalar_types] + + maxa = _can_coerce_all(array_types) + maxsc = _can_coerce_all(scalar_types) + + if maxa is None: + return maxsc + + if maxsc is None: + return maxa + + try: + index_a = _kind_list.index(maxa.kind) + index_sc = _kind_list.index(maxsc.kind) + except ValueError: + return None + + if index_sc > index_a: + return _find_common_coerce(maxsc, maxa) + else: + return maxa diff --git a/numpy/core/records.py b/numpy/core/records.py new file mode 100644 index 0000000..b3f2855 --- /dev/null +++ b/numpy/core/records.py @@ -0,0 +1,879 @@ +""" +Record Arrays +============= +Record arrays expose the fields of structured arrays as properties. + +Most commonly, ndarrays contain elements of a single type, e.g. floats, +integers, bools etc. However, it is possible for elements to be combinations +of these using structured types, such as:: + + >>> a = np.array([(1, 2.0), (1, 2.0)], dtype=[('x', int), ('y', float)]) + >>> a + array([(1, 2.0), (1, 2.0)], + dtype=[('x', '>> a['x'] + array([1, 1]) + + >>> a['y'] + array([ 2., 2.]) + +Record arrays allow us to access fields as properties:: + + >>> ar = np.rec.array(a) + + >>> ar.x + array([1, 1]) + + >>> ar.y + array([ 2., 2.]) + +""" +from __future__ import division, absolute_import, print_function + +import sys +import os +import warnings + +from . import numeric as sb +from . import numerictypes as nt +from numpy.compat import isfileobj, bytes, long +from .arrayprint import get_printoptions + +# All of the functions allow formats to be a dtype +__all__ = ['record', 'recarray', 'format_parser'] + + +ndarray = sb.ndarray + +_byteorderconv = {'b':'>', + 'l':'<', + 'n':'=', + 'B':'>', + 'L':'<', + 'N':'=', + 'S':'s', + 's':'s', + '>':'>', + '<':'<', + '=':'=', + '|':'|', + 'I':'|', + 'i':'|'} + +# formats regular expression +# allows multidimension spec with a tuple syntax in front +# of the letter code '(2,3)f4' and ' ( 2 , 3 ) f4 ' +# are equally allowed + +numfmt = nt.typeDict + +def find_duplicate(list): + """Find duplication in a list, return a list of duplicated elements""" + dup = [] + for i in range(len(list)): + if (list[i] in list[i + 1:]): + if (list[i] not in dup): + dup.append(list[i]) + return dup + +class format_parser(object): + """ + Class to convert formats, names, titles description to a dtype. + + After constructing the format_parser object, the dtype attribute is + the converted data-type: + ``dtype = format_parser(formats, names, titles).dtype`` + + Attributes + ---------- + dtype : dtype + The converted data-type. + + Parameters + ---------- + formats : str or list of str + The format description, either specified as a string with + comma-separated format descriptions in the form ``'f8, i4, a5'``, or + a list of format description strings in the form + ``['f8', 'i4', 'a5']``. + names : str or list/tuple of str + The field names, either specified as a comma-separated string in the + form ``'col1, col2, col3'``, or as a list or tuple of strings in the + form ``['col1', 'col2', 'col3']``. + An empty list can be used, in that case default field names + ('f0', 'f1', ...) are used. + titles : sequence + Sequence of title strings. An empty list can be used to leave titles + out. + aligned : bool, optional + If True, align the fields by padding as the C-compiler would. + Default is False. + byteorder : str, optional + If specified, all the fields will be changed to the + provided byte-order. Otherwise, the default byte-order is + used. For all available string specifiers, see `dtype.newbyteorder`. + + See Also + -------- + dtype, typename, sctype2char + + Examples + -------- + >>> np.format_parser(['f8', 'i4', 'a5'], ['col1', 'col2', 'col3'], + ... ['T1', 'T2', 'T3']).dtype + dtype([(('T1', 'col1'), '>> np.format_parser(['f8', 'i4', 'a5'], ['col1', 'col2', 'col3'], + ... []).dtype + dtype([('col1', '>> np.format_parser(['f8', 'i4', 'a5'], [], []).dtype + dtype([('f0', ' len(titles)): + self._titles += [None] * (self._nfields - len(titles)) + + def _createdescr(self, byteorder): + descr = sb.dtype({'names':self._names, + 'formats':self._f_formats, + 'offsets':self._offsets, + 'titles':self._titles}) + if (byteorder is not None): + byteorder = _byteorderconv[byteorder[0]] + descr = descr.newbyteorder(byteorder) + + self._descr = descr + +class record(nt.void): + """A data-type scalar that allows field access as attribute lookup. + """ + + # manually set name and module so that this class's type shows up + # as numpy.record when printed + __name__ = 'record' + __module__ = 'numpy' + + def __repr__(self): + if get_printoptions()['legacy'] == '1.13': + return self.__str__() + return super(record, self).__repr__() + + def __str__(self): + if get_printoptions()['legacy'] == '1.13': + return str(self.item()) + return super(record, self).__str__() + + def __getattribute__(self, attr): + if attr in ['setfield', 'getfield', 'dtype']: + return nt.void.__getattribute__(self, attr) + try: + return nt.void.__getattribute__(self, attr) + except AttributeError: + pass + fielddict = nt.void.__getattribute__(self, 'dtype').fields + res = fielddict.get(attr, None) + if res: + obj = self.getfield(*res[:2]) + # if it has fields return a record, + # otherwise return the object + try: + dt = obj.dtype + except AttributeError: + #happens if field is Object type + return obj + if dt.fields: + return obj.view((self.__class__, obj.dtype.fields)) + return obj + else: + raise AttributeError("'record' object has no " + "attribute '%s'" % attr) + + def __setattr__(self, attr, val): + if attr in ['setfield', 'getfield', 'dtype']: + raise AttributeError("Cannot set '%s' attribute" % attr) + fielddict = nt.void.__getattribute__(self, 'dtype').fields + res = fielddict.get(attr, None) + if res: + return self.setfield(val, *res[:2]) + else: + if getattr(self, attr, None): + return nt.void.__setattr__(self, attr, val) + else: + raise AttributeError("'record' object has no " + "attribute '%s'" % attr) + + def __getitem__(self, indx): + obj = nt.void.__getitem__(self, indx) + + # copy behavior of record.__getattribute__, + if isinstance(obj, nt.void) and obj.dtype.fields: + return obj.view((self.__class__, obj.dtype.fields)) + else: + # return a single element + return obj + + def pprint(self): + """Pretty-print all fields.""" + # pretty-print all fields + names = self.dtype.names + maxlen = max(len(name) for name in names) + rows = [] + fmt = '%% %ds: %%s' % maxlen + for name in names: + rows.append(fmt % (name, getattr(self, name))) + return "\n".join(rows) + +# The recarray is almost identical to a standard array (which supports +# named fields already) The biggest difference is that it can use +# attribute-lookup to find the fields and it is constructed using +# a record. + +# If byteorder is given it forces a particular byteorder on all +# the fields (and any subfields) + +class recarray(ndarray): + """Construct an ndarray that allows field access using attributes. + + Arrays may have a data-types containing fields, analogous + to columns in a spread sheet. An example is ``[(x, int), (y, float)]``, + where each entry in the array is a pair of ``(int, float)``. Normally, + these attributes are accessed using dictionary lookups such as ``arr['x']`` + and ``arr['y']``. Record arrays allow the fields to be accessed as members + of the array, using ``arr.x`` and ``arr.y``. + + Parameters + ---------- + shape : tuple + Shape of output array. + dtype : data-type, optional + The desired data-type. By default, the data-type is determined + from `formats`, `names`, `titles`, `aligned` and `byteorder`. + formats : list of data-types, optional + A list containing the data-types for the different columns, e.g. + ``['i4', 'f8', 'i4']``. `formats` does *not* support the new + convention of using types directly, i.e. ``(int, float, int)``. + Note that `formats` must be a list, not a tuple. + Given that `formats` is somewhat limited, we recommend specifying + `dtype` instead. + names : tuple of str, optional + The name of each column, e.g. ``('x', 'y', 'z')``. + buf : buffer, optional + By default, a new array is created of the given shape and data-type. + If `buf` is specified and is an object exposing the buffer interface, + the array will use the memory from the existing buffer. In this case, + the `offset` and `strides` keywords are available. + + Other Parameters + ---------------- + titles : tuple of str, optional + Aliases for column names. For example, if `names` were + ``('x', 'y', 'z')`` and `titles` is + ``('x_coordinate', 'y_coordinate', 'z_coordinate')``, then + ``arr['x']`` is equivalent to both ``arr.x`` and ``arr.x_coordinate``. + byteorder : {'<', '>', '='}, optional + Byte-order for all fields. + aligned : bool, optional + Align the fields in memory as the C-compiler would. + strides : tuple of ints, optional + Buffer (`buf`) is interpreted according to these strides (strides + define how many bytes each array element, row, column, etc. + occupy in memory). + offset : int, optional + Start reading buffer (`buf`) from this offset onwards. + order : {'C', 'F'}, optional + Row-major (C-style) or column-major (Fortran-style) order. + + Returns + ------- + rec : recarray + Empty array of the given shape and type. + + See Also + -------- + rec.fromrecords : Construct a record array from data. + record : fundamental data-type for `recarray`. + format_parser : determine a data-type from formats, names, titles. + + Notes + ----- + This constructor can be compared to ``empty``: it creates a new record + array but does not fill it with data. To create a record array from data, + use one of the following methods: + + 1. Create a standard ndarray and convert it to a record array, + using ``arr.view(np.recarray)`` + 2. Use the `buf` keyword. + 3. Use `np.rec.fromrecords`. + + Examples + -------- + Create an array with two fields, ``x`` and ``y``: + + >>> x = np.array([(1.0, 2), (3.0, 4)], dtype=[('x', float), ('y', int)]) + >>> x + array([(1.0, 2), (3.0, 4)], + dtype=[('x', '>> x['x'] + array([ 1., 3.]) + + View the array as a record array: + + >>> x = x.view(np.recarray) + + >>> x.x + array([ 1., 3.]) + + >>> x.y + array([2, 4]) + + Create a new, empty record array: + + >>> np.recarray((2,), + ... dtype=[('x', int), ('y', float), ('z', int)]) #doctest: +SKIP + rec.array([(-1073741821, 1.2249118382103472e-301, 24547520), + (3471280, 1.2134086255804012e-316, 0)], + dtype=[('x', ' 0 or self.shape == (0,): + lst = sb.array2string( + self, separator=', ', prefix=prefix, suffix=',') + else: + # show zero-length shape unless it is (0,) + lst = "[], shape=%s" % (repr(self.shape),) + + lf = '\n'+' '*len(prefix) + if get_printoptions()['legacy'] == '1.13': + lf = ' ' + lf # trailing space + return fmt % (lst, lf, repr_dtype) + + def field(self, attr, val=None): + if isinstance(attr, int): + names = ndarray.__getattribute__(self, 'dtype').names + attr = names[attr] + + fielddict = ndarray.__getattribute__(self, 'dtype').fields + + res = fielddict[attr][:2] + + if val is None: + obj = self.getfield(*res) + if obj.dtype.fields: + return obj + return obj.view(ndarray) + else: + return self.setfield(val, *res) + + +def fromarrays(arrayList, dtype=None, shape=None, formats=None, + names=None, titles=None, aligned=False, byteorder=None): + """ create a record array from a (flat) list of arrays + + >>> x1=np.array([1,2,3,4]) + >>> x2=np.array(['a','dd','xyz','12']) + >>> x3=np.array([1.1,2,3,4]) + >>> r = np.core.records.fromarrays([x1,x2,x3],names='a,b,c') + >>> print(r[1]) + (2, 'dd', 2.0) + >>> x1[1]=34 + >>> r.a + array([1, 2, 3, 4]) + """ + + arrayList = [sb.asarray(x) for x in arrayList] + + if shape is None or shape == 0: + shape = arrayList[0].shape + + if isinstance(shape, int): + shape = (shape,) + + if formats is None and dtype is None: + # go through each object in the list to see if it is an ndarray + # and determine the formats. + formats = [] + for obj in arrayList: + if not isinstance(obj, ndarray): + raise ValueError("item in the array list must be an ndarray.") + formats.append(obj.dtype.str) + formats = ','.join(formats) + + if dtype is not None: + descr = sb.dtype(dtype) + _names = descr.names + else: + parsed = format_parser(formats, names, titles, aligned, byteorder) + _names = parsed._names + descr = parsed._descr + + # Determine shape from data-type. + if len(descr) != len(arrayList): + raise ValueError("mismatch between the number of fields " + "and the number of arrays") + + d0 = descr[0].shape + nn = len(d0) + if nn > 0: + shape = shape[:-nn] + + for k, obj in enumerate(arrayList): + nn = descr[k].ndim + testshape = obj.shape[:obj.ndim - nn] + if testshape != shape: + raise ValueError("array-shape mismatch in array %d" % k) + + _array = recarray(shape, descr) + + # populate the record array (makes a copy) + for i in range(len(arrayList)): + _array[_names[i]] = arrayList[i] + + return _array + +def fromrecords(recList, dtype=None, shape=None, formats=None, names=None, + titles=None, aligned=False, byteorder=None): + """ create a recarray from a list of records in text form + + The data in the same field can be heterogeneous, they will be promoted + to the highest data type. This method is intended for creating + smaller record arrays. If used to create large array without formats + defined + + r=fromrecords([(2,3.,'abc')]*100000) + + it can be slow. + + If formats is None, then this will auto-detect formats. Use list of + tuples rather than list of lists for faster processing. + + >>> r=np.core.records.fromrecords([(456,'dbe',1.2),(2,'de',1.3)], + ... names='col1,col2,col3') + >>> print(r[0]) + (456, 'dbe', 1.2) + >>> r.col1 + array([456, 2]) + >>> r.col2 + array(['dbe', 'de'], + dtype='|S3') + >>> import pickle + >>> print(pickle.loads(pickle.dumps(r))) + [(456, 'dbe', 1.2) (2, 'de', 1.3)] + """ + + if formats is None and dtype is None: # slower + obj = sb.array(recList, dtype=object) + arrlist = [sb.array(obj[..., i].tolist()) for i in range(obj.shape[-1])] + return fromarrays(arrlist, formats=formats, shape=shape, names=names, + titles=titles, aligned=aligned, byteorder=byteorder) + + if dtype is not None: + descr = sb.dtype((record, dtype)) + else: + descr = format_parser(formats, names, titles, aligned, byteorder)._descr + + # deprecated back-compat block for numpy 1.14, to be removed in a later + # release. This converts list-of-list input to list-of-tuples in some + # cases, as done in numpy <= 1.13. In the future we will require tuples. + if (isinstance(recList, list) and len(recList) > 0 + and isinstance(recList[0], list) and len(recList[0]) > 0 + and not isinstance(recList[0][0], (list, tuple))): + + try: + memoryview(recList[0][0]) + except: + if (shape is None or shape == 0): + shape = len(recList) + if isinstance(shape, (int, long)): + shape = (shape,) + if len(shape) > 1: + raise ValueError("Can only deal with 1-d array.") + _array = recarray(shape, descr) + for k in range(_array.size): + _array[k] = tuple(recList[k]) + # list of lists instead of list of tuples ? + # 2018-02-07, 1.14.1 + warnings.warn( + "fromrecords expected a list of tuples, may have received a " + "list of lists instead. In the future that will raise an error", + FutureWarning, stacklevel=2) + return _array + else: + pass + + retval = sb.array(recList, dtype=descr) + if shape is not None and retval.shape != shape: + retval.shape = shape + + return retval.view(recarray) + + +def fromstring(datastring, dtype=None, shape=None, offset=0, formats=None, + names=None, titles=None, aligned=False, byteorder=None): + """ create a (read-only) record array from binary data contained in + a string""" + + if dtype is None and formats is None: + raise ValueError("Must have dtype= or formats=") + + if dtype is not None: + descr = sb.dtype(dtype) + else: + descr = format_parser(formats, names, titles, aligned, byteorder)._descr + + itemsize = descr.itemsize + if (shape is None or shape == 0 or shape == -1): + shape = (len(datastring) - offset) // itemsize + + _array = recarray(shape, descr, buf=datastring, offset=offset) + return _array + +def get_remaining_size(fd): + try: + fn = fd.fileno() + except AttributeError: + return os.path.getsize(fd.name) - fd.tell() + st = os.fstat(fn) + size = st.st_size - fd.tell() + return size + +def fromfile(fd, dtype=None, shape=None, offset=0, formats=None, + names=None, titles=None, aligned=False, byteorder=None): + """Create an array from binary file data + + If file is a string then that file is opened, else it is assumed + to be a file object. The file object must support random access + (i.e. it must have tell and seek methods). + + >>> from tempfile import TemporaryFile + >>> a = np.empty(10,dtype='f8,i4,a5') + >>> a[5] = (0.5,10,'abcde') + >>> + >>> fd=TemporaryFile() + >>> a = a.newbyteorder('<') + >>> a.tofile(fd) + >>> + >>> fd.seek(0) + >>> r=np.core.records.fromfile(fd, formats='f8,i4,a5', shape=10, + ... byteorder='<') + >>> print(r[5]) + (0.5, 10, 'abcde') + >>> r.shape + (10,) + """ + + if (shape is None or shape == 0): + shape = (-1,) + elif isinstance(shape, (int, long)): + shape = (shape,) + + name = 0 + if isinstance(fd, str): + name = 1 + fd = open(fd, 'rb') + if (offset > 0): + fd.seek(offset, 1) + size = get_remaining_size(fd) + + if dtype is not None: + descr = sb.dtype(dtype) + else: + descr = format_parser(formats, names, titles, aligned, byteorder)._descr + + itemsize = descr.itemsize + + shapeprod = sb.array(shape).prod() + shapesize = shapeprod * itemsize + if shapesize < 0: + shape = list(shape) + shape[shape.index(-1)] = size / -shapesize + shape = tuple(shape) + shapeprod = sb.array(shape).prod() + + nbytes = shapeprod * itemsize + + if nbytes > size: + raise ValueError( + "Not enough bytes left in file for specified shape and type") + + # create the array + _array = recarray(shape, descr) + nbytesread = fd.readinto(_array.data) + if nbytesread != nbytes: + raise IOError("Didn't read as many bytes as expected") + if name: + fd.close() + + return _array + +def array(obj, dtype=None, shape=None, offset=0, strides=None, formats=None, + names=None, titles=None, aligned=False, byteorder=None, copy=True): + """Construct a record array from a wide-variety of objects. + """ + + if ((isinstance(obj, (type(None), str)) or isfileobj(obj)) and + (formats is None) and (dtype is None)): + raise ValueError("Must define formats (or dtype) if object is " + "None, string, or an open file") + + kwds = {} + if dtype is not None: + dtype = sb.dtype(dtype) + elif formats is not None: + dtype = format_parser(formats, names, titles, + aligned, byteorder)._descr + else: + kwds = {'formats': formats, + 'names': names, + 'titles': titles, + 'aligned': aligned, + 'byteorder': byteorder + } + + if obj is None: + if shape is None: + raise ValueError("Must define a shape if obj is None") + return recarray(shape, dtype, buf=obj, offset=offset, strides=strides) + + elif isinstance(obj, bytes): + return fromstring(obj, dtype, shape=shape, offset=offset, **kwds) + + elif isinstance(obj, (list, tuple)): + if isinstance(obj[0], (tuple, list)): + return fromrecords(obj, dtype=dtype, shape=shape, **kwds) + else: + return fromarrays(obj, dtype=dtype, shape=shape, **kwds) + + elif isinstance(obj, recarray): + if dtype is not None and (obj.dtype != dtype): + new = obj.view(dtype) + else: + new = obj + if copy: + new = new.copy() + return new + + elif isfileobj(obj): + return fromfile(obj, dtype=dtype, shape=shape, offset=offset) + + elif isinstance(obj, ndarray): + if dtype is not None and (obj.dtype != dtype): + new = obj.view(dtype) + else: + new = obj + if copy: + new = new.copy() + return new.view(recarray) + + else: + interface = getattr(obj, "__array_interface__", None) + if interface is None or not isinstance(interface, dict): + raise ValueError("Unknown input type") + obj = sb.array(obj) + if dtype is not None and (obj.dtype != dtype): + obj = obj.view(dtype) + return obj.view(recarray) diff --git a/numpy/core/setup.py b/numpy/core/setup.py new file mode 100644 index 0000000..371df5b --- /dev/null +++ b/numpy/core/setup.py @@ -0,0 +1,969 @@ +from __future__ import division, print_function + +import os +import sys +import pickle +import copy +import sysconfig +import warnings +import platform +from os.path import join +from numpy.distutils import log +from distutils.dep_util import newer +from distutils.sysconfig import get_config_var +from numpy._build_utils.apple_accelerate import ( + uses_accelerate_framework, get_sgemv_fix + ) +from numpy.compat import npy_load_module +from setup_common import * + +# Set to True to enable relaxed strides checking. This (mostly) means +# that `strides[dim]` is ignored if `shape[dim] == 1` when setting flags. +NPY_RELAXED_STRIDES_CHECKING = (os.environ.get('NPY_RELAXED_STRIDES_CHECKING', "1") != "0") + +# Put NPY_RELAXED_STRIDES_DEBUG=1 in the environment if you want numpy to use a +# bogus value for affected strides in order to help smoke out bad stride usage +# when relaxed stride checking is enabled. +NPY_RELAXED_STRIDES_DEBUG = (os.environ.get('NPY_RELAXED_STRIDES_DEBUG', "0") != "0") +NPY_RELAXED_STRIDES_DEBUG = NPY_RELAXED_STRIDES_DEBUG and NPY_RELAXED_STRIDES_CHECKING + +# XXX: ugly, we use a class to avoid calling twice some expensive functions in +# config.h/numpyconfig.h. I don't see a better way because distutils force +# config.h generation inside an Extension class, and as such sharing +# configuration informations between extensions is not easy. +# Using a pickled-based memoize does not work because config_cmd is an instance +# method, which cPickle does not like. +# +# Use pickle in all cases, as cPickle is gone in python3 and the difference +# in time is only in build. -- Charles Harris, 2013-03-30 + +class CallOnceOnly(object): + def __init__(self): + self._check_types = None + self._check_ieee_macros = None + self._check_complex = None + + def check_types(self, *a, **kw): + if self._check_types is None: + out = check_types(*a, **kw) + self._check_types = pickle.dumps(out) + else: + out = copy.deepcopy(pickle.loads(self._check_types)) + return out + + def check_ieee_macros(self, *a, **kw): + if self._check_ieee_macros is None: + out = check_ieee_macros(*a, **kw) + self._check_ieee_macros = pickle.dumps(out) + else: + out = copy.deepcopy(pickle.loads(self._check_ieee_macros)) + return out + + def check_complex(self, *a, **kw): + if self._check_complex is None: + out = check_complex(*a, **kw) + self._check_complex = pickle.dumps(out) + else: + out = copy.deepcopy(pickle.loads(self._check_complex)) + return out + +def pythonlib_dir(): + """return path where libpython* is.""" + if sys.platform == 'win32': + return os.path.join(sys.prefix, "libs") + else: + return get_config_var('LIBDIR') + +def is_npy_no_signal(): + """Return True if the NPY_NO_SIGNAL symbol must be defined in configuration + header.""" + return sys.platform == 'win32' + +def is_npy_no_smp(): + """Return True if the NPY_NO_SMP symbol must be defined in public + header (when SMP support cannot be reliably enabled).""" + # Perhaps a fancier check is in order here. + # so that threads are only enabled if there + # are actually multiple CPUS? -- but + # threaded code can be nice even on a single + # CPU so that long-calculating code doesn't + # block. + return 'NPY_NOSMP' in os.environ + +def win32_checks(deflist): + from numpy.distutils.misc_util import get_build_architecture + a = get_build_architecture() + + # Distutils hack on AMD64 on windows + print('BUILD_ARCHITECTURE: %r, os.name=%r, sys.platform=%r' % + (a, os.name, sys.platform)) + if a == 'AMD64': + deflist.append('DISTUTILS_USE_SDK') + + # On win32, force long double format string to be 'g', not + # 'Lg', since the MS runtime does not support long double whose + # size is > sizeof(double) + if a == "Intel" or a == "AMD64": + deflist.append('FORCE_NO_LONG_DOUBLE_FORMATTING') + +def check_math_capabilities(config, moredefs, mathlibs): + def check_func(func_name): + return config.check_func(func_name, libraries=mathlibs, + decl=True, call=True) + + def check_funcs_once(funcs_name): + decl = dict([(f, True) for f in funcs_name]) + st = config.check_funcs_once(funcs_name, libraries=mathlibs, + decl=decl, call=decl) + if st: + moredefs.extend([(fname2def(f), 1) for f in funcs_name]) + return st + + def check_funcs(funcs_name): + # Use check_funcs_once first, and if it does not work, test func per + # func. Return success only if all the functions are available + if not check_funcs_once(funcs_name): + # Global check failed, check func per func + for f in funcs_name: + if check_func(f): + moredefs.append((fname2def(f), 1)) + return 0 + else: + return 1 + + #use_msvc = config.check_decl("_MSC_VER") + + if not check_funcs_once(MANDATORY_FUNCS): + raise SystemError("One of the required function to build numpy is not" + " available (the list is %s)." % str(MANDATORY_FUNCS)) + + # Standard functions which may not be available and for which we have a + # replacement implementation. Note that some of these are C99 functions. + + # XXX: hack to circumvent cpp pollution from python: python put its + # config.h in the public namespace, so we have a clash for the common + # functions we test. We remove every function tested by python's + # autoconf, hoping their own test are correct + for f in OPTIONAL_STDFUNCS_MAYBE: + if config.check_decl(fname2def(f), + headers=["Python.h", "math.h"]): + OPTIONAL_STDFUNCS.remove(f) + + check_funcs(OPTIONAL_STDFUNCS) + + for h in OPTIONAL_HEADERS: + if config.check_func("", decl=False, call=False, headers=[h]): + moredefs.append((fname2def(h).replace(".", "_"), 1)) + + for tup in OPTIONAL_INTRINSICS: + headers = None + if len(tup) == 2: + f, args, m = tup[0], tup[1], fname2def(tup[0]) + elif len(tup) == 3: + f, args, headers, m = tup[0], tup[1], [tup[2]], fname2def(tup[0]) + else: + f, args, headers, m = tup[0], tup[1], [tup[2]], fname2def(tup[3]) + if config.check_func(f, decl=False, call=True, call_args=args, + headers=headers): + moredefs.append((m, 1)) + + for dec, fn in OPTIONAL_FUNCTION_ATTRIBUTES: + if config.check_gcc_function_attribute(dec, fn): + moredefs.append((fname2def(fn), 1)) + + for fn in OPTIONAL_VARIABLE_ATTRIBUTES: + if config.check_gcc_variable_attribute(fn): + m = fn.replace("(", "_").replace(")", "_") + moredefs.append((fname2def(m), 1)) + + # C99 functions: float and long double versions + check_funcs(C99_FUNCS_SINGLE) + check_funcs(C99_FUNCS_EXTENDED) + +def check_complex(config, mathlibs): + priv = [] + pub = [] + + try: + if os.uname()[0] == "Interix": + warnings.warn("Disabling broken complex support. See #1365", stacklevel=2) + return priv, pub + except Exception: + # os.uname not available on all platforms. blanket except ugly but safe + pass + + # Check for complex support + st = config.check_header('complex.h') + if st: + priv.append(('HAVE_COMPLEX_H', 1)) + pub.append(('NPY_USE_C99_COMPLEX', 1)) + + for t in C99_COMPLEX_TYPES: + st = config.check_type(t, headers=["complex.h"]) + if st: + pub.append(('NPY_HAVE_%s' % type2def(t), 1)) + + def check_prec(prec): + flist = [f + prec for f in C99_COMPLEX_FUNCS] + decl = dict([(f, True) for f in flist]) + if not config.check_funcs_once(flist, call=decl, decl=decl, + libraries=mathlibs): + for f in flist: + if config.check_func(f, call=True, decl=True, + libraries=mathlibs): + priv.append((fname2def(f), 1)) + else: + priv.extend([(fname2def(f), 1) for f in flist]) + + check_prec('') + check_prec('f') + check_prec('l') + + return priv, pub + +def check_ieee_macros(config): + priv = [] + pub = [] + + macros = [] + + def _add_decl(f): + priv.append(fname2def("decl_%s" % f)) + pub.append('NPY_%s' % fname2def("decl_%s" % f)) + + # XXX: hack to circumvent cpp pollution from python: python put its + # config.h in the public namespace, so we have a clash for the common + # functions we test. We remove every function tested by python's + # autoconf, hoping their own test are correct + _macros = ["isnan", "isinf", "signbit", "isfinite"] + for f in _macros: + py_symbol = fname2def("decl_%s" % f) + already_declared = config.check_decl(py_symbol, + headers=["Python.h", "math.h"]) + if already_declared: + if config.check_macro_true(py_symbol, + headers=["Python.h", "math.h"]): + pub.append('NPY_%s' % fname2def("decl_%s" % f)) + else: + macros.append(f) + # Normally, isnan and isinf are macro (C99), but some platforms only have + # func, or both func and macro version. Check for macro only, and define + # replacement ones if not found. + # Note: including Python.h is necessary because it modifies some math.h + # definitions + for f in macros: + st = config.check_decl(f, headers=["Python.h", "math.h"]) + if st: + _add_decl(f) + + return priv, pub + +def check_types(config_cmd, ext, build_dir): + private_defines = [] + public_defines = [] + + # Expected size (in number of bytes) for each type. This is an + # optimization: those are only hints, and an exhaustive search for the size + # is done if the hints are wrong. + expected = {'short': [2], 'int': [4], 'long': [8, 4], + 'float': [4], 'double': [8], 'long double': [16, 12, 8], + 'Py_intptr_t': [8, 4], 'PY_LONG_LONG': [8], 'long long': [8], + 'off_t': [8, 4]} + + # Check we have the python header (-dev* packages on Linux) + result = config_cmd.check_header('Python.h') + if not result: + python = 'python' + if '__pypy__' in sys.builtin_module_names: + python = 'pypy' + raise SystemError( + "Cannot compile 'Python.h'. Perhaps you need to " + "install {0}-dev|{0}-devel.".format(python)) + res = config_cmd.check_header("endian.h") + if res: + private_defines.append(('HAVE_ENDIAN_H', 1)) + public_defines.append(('NPY_HAVE_ENDIAN_H', 1)) + res = config_cmd.check_header("sys/endian.h") + if res: + private_defines.append(('HAVE_SYS_ENDIAN_H', 1)) + public_defines.append(('NPY_HAVE_SYS_ENDIAN_H', 1)) + + # Check basic types sizes + for type in ('short', 'int', 'long'): + res = config_cmd.check_decl("SIZEOF_%s" % sym2def(type), headers=["Python.h"]) + if res: + public_defines.append(('NPY_SIZEOF_%s' % sym2def(type), "SIZEOF_%s" % sym2def(type))) + else: + res = config_cmd.check_type_size(type, expected=expected[type]) + if res >= 0: + public_defines.append(('NPY_SIZEOF_%s' % sym2def(type), '%d' % res)) + else: + raise SystemError("Checking sizeof (%s) failed !" % type) + + for type in ('float', 'double', 'long double'): + already_declared = config_cmd.check_decl("SIZEOF_%s" % sym2def(type), + headers=["Python.h"]) + res = config_cmd.check_type_size(type, expected=expected[type]) + if res >= 0: + public_defines.append(('NPY_SIZEOF_%s' % sym2def(type), '%d' % res)) + if not already_declared and not type == 'long double': + private_defines.append(('SIZEOF_%s' % sym2def(type), '%d' % res)) + else: + raise SystemError("Checking sizeof (%s) failed !" % type) + + # Compute size of corresponding complex type: used to check that our + # definition is binary compatible with C99 complex type (check done at + # build time in npy_common.h) + complex_def = "struct {%s __x; %s __y;}" % (type, type) + res = config_cmd.check_type_size(complex_def, + expected=[2 * x for x in expected[type]]) + if res >= 0: + public_defines.append(('NPY_SIZEOF_COMPLEX_%s' % sym2def(type), '%d' % res)) + else: + raise SystemError("Checking sizeof (%s) failed !" % complex_def) + + for type in ('Py_intptr_t', 'off_t'): + res = config_cmd.check_type_size(type, headers=["Python.h"], + library_dirs=[pythonlib_dir()], + expected=expected[type]) + + if res >= 0: + private_defines.append(('SIZEOF_%s' % sym2def(type), '%d' % res)) + public_defines.append(('NPY_SIZEOF_%s' % sym2def(type), '%d' % res)) + else: + raise SystemError("Checking sizeof (%s) failed !" % type) + + # We check declaration AND type because that's how distutils does it. + if config_cmd.check_decl('PY_LONG_LONG', headers=['Python.h']): + res = config_cmd.check_type_size('PY_LONG_LONG', headers=['Python.h'], + library_dirs=[pythonlib_dir()], + expected=expected['PY_LONG_LONG']) + if res >= 0: + private_defines.append(('SIZEOF_%s' % sym2def('PY_LONG_LONG'), '%d' % res)) + public_defines.append(('NPY_SIZEOF_%s' % sym2def('PY_LONG_LONG'), '%d' % res)) + else: + raise SystemError("Checking sizeof (%s) failed !" % 'PY_LONG_LONG') + + res = config_cmd.check_type_size('long long', + expected=expected['long long']) + if res >= 0: + #private_defines.append(('SIZEOF_%s' % sym2def('long long'), '%d' % res)) + public_defines.append(('NPY_SIZEOF_%s' % sym2def('long long'), '%d' % res)) + else: + raise SystemError("Checking sizeof (%s) failed !" % 'long long') + + if not config_cmd.check_decl('CHAR_BIT', headers=['Python.h']): + raise RuntimeError( + "Config wo CHAR_BIT is not supported" + ", please contact the maintainers") + + return private_defines, public_defines + +def check_mathlib(config_cmd): + # Testing the C math library + mathlibs = [] + mathlibs_choices = [[], ['m'], ['cpml']] + mathlib = os.environ.get('MATHLIB') + if mathlib: + mathlibs_choices.insert(0, mathlib.split(',')) + for libs in mathlibs_choices: + if config_cmd.check_func("exp", libraries=libs, decl=True, call=True): + mathlibs = libs + break + else: + raise EnvironmentError("math library missing; rerun " + "setup.py after setting the " + "MATHLIB env variable") + return mathlibs + +def visibility_define(config): + """Return the define value to use for NPY_VISIBILITY_HIDDEN (may be empty + string).""" + if config.check_compiler_gcc4(): + return '__attribute__((visibility("hidden")))' + else: + return '' + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration, dot_join + from numpy.distutils.system_info import get_info + + config = Configuration('core', parent_package, top_path) + local_dir = config.local_path + codegen_dir = join(local_dir, 'code_generators') + + if is_released(config): + warnings.simplefilter('error', MismatchCAPIWarning) + + # Check whether we have a mismatch between the set C API VERSION and the + # actual C API VERSION + check_api_version(C_API_VERSION, codegen_dir) + + generate_umath_py = join(codegen_dir, 'generate_umath.py') + n = dot_join(config.name, 'generate_umath') + generate_umath = npy_load_module('_'.join(n.split('.')), + generate_umath_py, ('.py', 'U', 1)) + + header_dir = 'include/numpy' # this is relative to config.path_in_package + + cocache = CallOnceOnly() + + def generate_config_h(ext, build_dir): + target = join(build_dir, header_dir, 'config.h') + d = os.path.dirname(target) + if not os.path.exists(d): + os.makedirs(d) + + if newer(__file__, target): + config_cmd = config.get_config_cmd() + log.info('Generating %s', target) + + # Check sizeof + moredefs, ignored = cocache.check_types(config_cmd, ext, build_dir) + + # Check math library and C99 math funcs availability + mathlibs = check_mathlib(config_cmd) + moredefs.append(('MATHLIB', ','.join(mathlibs))) + + check_math_capabilities(config_cmd, moredefs, mathlibs) + moredefs.extend(cocache.check_ieee_macros(config_cmd)[0]) + moredefs.extend(cocache.check_complex(config_cmd, mathlibs)[0]) + + # Signal check + if is_npy_no_signal(): + moredefs.append('__NPY_PRIVATE_NO_SIGNAL') + + # Windows checks + if sys.platform == 'win32' or os.name == 'nt': + win32_checks(moredefs) + + # C99 restrict keyword + moredefs.append(('NPY_RESTRICT', config_cmd.check_restrict())) + + # Inline check + inline = config_cmd.check_inline() + + # Use relaxed stride checking + if NPY_RELAXED_STRIDES_CHECKING: + moredefs.append(('NPY_RELAXED_STRIDES_CHECKING', 1)) + + # Use bogus stride debug aid when relaxed strides are enabled + if NPY_RELAXED_STRIDES_DEBUG: + moredefs.append(('NPY_RELAXED_STRIDES_DEBUG', 1)) + + # Get long double representation + if sys.platform != 'darwin': + rep = check_long_double_representation(config_cmd) + if rep in ['INTEL_EXTENDED_12_BYTES_LE', + 'INTEL_EXTENDED_16_BYTES_LE', + 'MOTOROLA_EXTENDED_12_BYTES_BE', + 'IEEE_QUAD_LE', 'IEEE_QUAD_BE', + 'IEEE_DOUBLE_LE', 'IEEE_DOUBLE_BE', + 'DOUBLE_DOUBLE_BE', 'DOUBLE_DOUBLE_LE']: + moredefs.append(('HAVE_LDOUBLE_%s' % rep, 1)) + else: + raise ValueError("Unrecognized long double format: %s" % rep) + + # Py3K check + if sys.version_info[0] == 3: + moredefs.append(('NPY_PY3K', 1)) + + # Generate the config.h file from moredefs + target_f = open(target, 'w') + for d in moredefs: + if isinstance(d, str): + target_f.write('#define %s\n' % (d)) + else: + target_f.write('#define %s %s\n' % (d[0], d[1])) + + # define inline to our keyword, or nothing + target_f.write('#ifndef __cplusplus\n') + if inline == 'inline': + target_f.write('/* #undef inline */\n') + else: + target_f.write('#define inline %s\n' % inline) + target_f.write('#endif\n') + + # add the guard to make sure config.h is never included directly, + # but always through npy_config.h + target_f.write(""" +#ifndef _NPY_NPY_CONFIG_H_ +#error config.h should never be included directly, include npy_config.h instead +#endif +""") + + target_f.close() + print('File:', target) + target_f = open(target) + print(target_f.read()) + target_f.close() + print('EOF') + else: + mathlibs = [] + target_f = open(target) + for line in target_f: + s = '#define MATHLIB' + if line.startswith(s): + value = line[len(s):].strip() + if value: + mathlibs.extend(value.split(',')) + target_f.close() + + # Ugly: this can be called within a library and not an extension, + # in which case there is no libraries attributes (and none is + # needed). + if hasattr(ext, 'libraries'): + ext.libraries.extend(mathlibs) + + incl_dir = os.path.dirname(target) + if incl_dir not in config.numpy_include_dirs: + config.numpy_include_dirs.append(incl_dir) + + return target + + def generate_numpyconfig_h(ext, build_dir): + """Depends on config.h: generate_config_h has to be called before !""" + # put private include directory in build_dir on search path + # allows using code generation in headers headers + config.add_include_dirs(join(build_dir, "src", "private")) + config.add_include_dirs(join(build_dir, "src", "npymath")) + + target = join(build_dir, header_dir, '_numpyconfig.h') + d = os.path.dirname(target) + if not os.path.exists(d): + os.makedirs(d) + if newer(__file__, target): + config_cmd = config.get_config_cmd() + log.info('Generating %s', target) + + # Check sizeof + ignored, moredefs = cocache.check_types(config_cmd, ext, build_dir) + + if is_npy_no_signal(): + moredefs.append(('NPY_NO_SIGNAL', 1)) + + if is_npy_no_smp(): + moredefs.append(('NPY_NO_SMP', 1)) + else: + moredefs.append(('NPY_NO_SMP', 0)) + + mathlibs = check_mathlib(config_cmd) + moredefs.extend(cocache.check_ieee_macros(config_cmd)[1]) + moredefs.extend(cocache.check_complex(config_cmd, mathlibs)[1]) + + if NPY_RELAXED_STRIDES_CHECKING: + moredefs.append(('NPY_RELAXED_STRIDES_CHECKING', 1)) + + if NPY_RELAXED_STRIDES_DEBUG: + moredefs.append(('NPY_RELAXED_STRIDES_DEBUG', 1)) + + # Check wether we can use inttypes (C99) formats + if config_cmd.check_decl('PRIdPTR', headers=['inttypes.h']): + moredefs.append(('NPY_USE_C99_FORMATS', 1)) + + # visibility check + hidden_visibility = visibility_define(config_cmd) + moredefs.append(('NPY_VISIBILITY_HIDDEN', hidden_visibility)) + + # Add the C API/ABI versions + moredefs.append(('NPY_ABI_VERSION', '0x%.8X' % C_ABI_VERSION)) + moredefs.append(('NPY_API_VERSION', '0x%.8X' % C_API_VERSION)) + + # Add moredefs to header + target_f = open(target, 'w') + for d in moredefs: + if isinstance(d, str): + target_f.write('#define %s\n' % (d)) + else: + target_f.write('#define %s %s\n' % (d[0], d[1])) + + # Define __STDC_FORMAT_MACROS + target_f.write(""" +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS 1 +#endif +""") + target_f.close() + + # Dump the numpyconfig.h header to stdout + print('File: %s' % target) + target_f = open(target) + print(target_f.read()) + target_f.close() + print('EOF') + config.add_data_files((header_dir, target)) + return target + + def generate_api_func(module_name): + def generate_api(ext, build_dir): + script = join(codegen_dir, module_name + '.py') + sys.path.insert(0, codegen_dir) + try: + m = __import__(module_name) + log.info('executing %s', script) + h_file, c_file, doc_file = m.generate_api(os.path.join(build_dir, header_dir)) + finally: + del sys.path[0] + config.add_data_files((header_dir, h_file), + (header_dir, doc_file)) + return (h_file,) + return generate_api + + generate_numpy_api = generate_api_func('generate_numpy_api') + generate_ufunc_api = generate_api_func('generate_ufunc_api') + + config.add_include_dirs(join(local_dir, "src", "private")) + config.add_include_dirs(join(local_dir, "src")) + config.add_include_dirs(join(local_dir)) + + config.add_data_files('include/numpy/*.h') + config.add_include_dirs(join('src', 'npymath')) + config.add_include_dirs(join('src', 'multiarray')) + config.add_include_dirs(join('src', 'umath')) + config.add_include_dirs(join('src', 'npysort')) + + config.add_define_macros([("NPY_INTERNAL_BUILD", "1")]) # this macro indicates that Numpy build is in process + config.add_define_macros([("HAVE_NPY_CONFIG_H", "1")]) + if sys.platform[:3] == "aix": + config.add_define_macros([("_LARGE_FILES", None)]) + else: + config.add_define_macros([("_FILE_OFFSET_BITS", "64")]) + config.add_define_macros([('_LARGEFILE_SOURCE', '1')]) + config.add_define_macros([('_LARGEFILE64_SOURCE', '1')]) + + config.numpy_include_dirs.extend(config.paths('include')) + + deps = [join('src', 'npymath', '_signbit.c'), + join('include', 'numpy', '*object.h'), + join(codegen_dir, 'genapi.py'), + ] + + ####################################################################### + # dummy module # + ####################################################################### + + # npymath needs the config.h and numpyconfig.h files to be generated, but + # build_clib cannot handle generate_config_h and generate_numpyconfig_h + # (don't ask). Because clib are generated before extensions, we have to + # explicitly add an extension which has generate_config_h and + # generate_numpyconfig_h as sources *before* adding npymath. + + config.add_extension('_dummy', + sources=[join('src', 'dummymodule.c'), + generate_config_h, + generate_numpyconfig_h, + generate_numpy_api] + ) + + ####################################################################### + # npymath library # + ####################################################################### + + subst_dict = dict([("sep", os.path.sep), ("pkgname", "numpy.core")]) + + def get_mathlib_info(*args): + # Another ugly hack: the mathlib info is known once build_src is run, + # but we cannot use add_installed_pkg_config here either, so we only + # update the substition dictionary during npymath build + config_cmd = config.get_config_cmd() + + # Check that the toolchain works, to fail early if it doesn't + # (avoid late errors with MATHLIB which are confusing if the + # compiler does not work). + st = config_cmd.try_link('int main(void) { return 0;}') + if not st: + raise RuntimeError("Broken toolchain: cannot link a simple C program") + mlibs = check_mathlib(config_cmd) + + posix_mlib = ' '.join(['-l%s' % l for l in mlibs]) + msvc_mlib = ' '.join(['%s.lib' % l for l in mlibs]) + subst_dict["posix_mathlib"] = posix_mlib + subst_dict["msvc_mathlib"] = msvc_mlib + + npymath_sources = [join('src', 'npymath', 'npy_math_internal.h.src'), + join('src', 'npymath', 'npy_math.c'), + join('src', 'npymath', 'ieee754.c.src'), + join('src', 'npymath', 'npy_math_complex.c.src'), + join('src', 'npymath', 'halffloat.c') + ] + + # Must be true for CRT compilers but not MinGW/cygwin. See gh-9977. + is_msvc = platform.system() == 'Windows' + config.add_installed_library('npymath', + sources=npymath_sources + [get_mathlib_info], + install_dir='lib', + build_info={ + 'include_dirs' : [], # empty list required for creating npy_math_internal.h + 'extra_compiler_args' : (['/GL-'] if is_msvc else []), + }) + config.add_npy_pkg_config("npymath.ini.in", "lib/npy-pkg-config", + subst_dict) + config.add_npy_pkg_config("mlib.ini.in", "lib/npy-pkg-config", + subst_dict) + + ####################################################################### + # npysort library # + ####################################################################### + + # This library is created for the build but it is not installed + npysort_sources = [join('src', 'npysort', 'quicksort.c.src'), + join('src', 'npysort', 'mergesort.c.src'), + join('src', 'npysort', 'heapsort.c.src'), + join('src', 'private', 'npy_partition.h.src'), + join('src', 'npysort', 'selection.c.src'), + join('src', 'private', 'npy_binsearch.h.src'), + join('src', 'npysort', 'binsearch.c.src'), + ] + config.add_library('npysort', + sources=npysort_sources, + include_dirs=[]) + + ####################################################################### + # multiarray module # + ####################################################################### + + multiarray_deps = [ + join('src', 'multiarray', 'arrayobject.h'), + join('src', 'multiarray', 'arraytypes.h'), + join('src', 'multiarray', 'array_assign.h'), + join('src', 'multiarray', 'buffer.h'), + join('src', 'multiarray', 'calculation.h'), + join('src', 'multiarray', 'cblasfuncs.h'), + join('src', 'multiarray', 'common.h'), + join('src', 'multiarray', 'convert_datatype.h'), + join('src', 'multiarray', 'convert.h'), + join('src', 'multiarray', 'conversion_utils.h'), + join('src', 'multiarray', 'ctors.h'), + join('src', 'multiarray', 'descriptor.h'), + join('src', 'multiarray', 'dragon4.h'), + join('src', 'multiarray', 'getset.h'), + join('src', 'multiarray', 'hashdescr.h'), + join('src', 'multiarray', 'iterators.h'), + join('src', 'multiarray', 'mapping.h'), + join('src', 'multiarray', 'methods.h'), + join('src', 'multiarray', 'multiarraymodule.h'), + join('src', 'multiarray', 'nditer_impl.h'), + join('src', 'multiarray', 'number.h'), + join('src', 'multiarray', 'numpyos.h'), + join('src', 'multiarray', 'refcount.h'), + join('src', 'multiarray', 'scalartypes.h'), + join('src', 'multiarray', 'sequence.h'), + join('src', 'multiarray', 'shape.h'), + join('src', 'multiarray', 'strfuncs.h'), + join('src', 'multiarray', 'ucsnarrow.h'), + join('src', 'multiarray', 'usertypes.h'), + join('src', 'multiarray', 'vdot.h'), + join('src', 'private', 'npy_config.h'), + join('src', 'private', 'templ_common.h.src'), + join('src', 'private', 'lowlevel_strided_loops.h'), + join('src', 'private', 'mem_overlap.h'), + join('src', 'private', 'npy_longdouble.h'), + join('src', 'private', 'ufunc_override.h'), + join('src', 'private', 'binop_override.h'), + join('src', 'private', 'npy_extint128.h'), + join('include', 'numpy', 'arrayobject.h'), + join('include', 'numpy', '_neighborhood_iterator_imp.h'), + join('include', 'numpy', 'npy_endian.h'), + join('include', 'numpy', 'arrayscalars.h'), + join('include', 'numpy', 'noprefix.h'), + join('include', 'numpy', 'npy_interrupt.h'), + join('include', 'numpy', 'npy_3kcompat.h'), + join('include', 'numpy', 'npy_math.h'), + join('include', 'numpy', 'halffloat.h'), + join('include', 'numpy', 'npy_common.h'), + join('include', 'numpy', 'npy_os.h'), + join('include', 'numpy', 'utils.h'), + join('include', 'numpy', 'ndarrayobject.h'), + join('include', 'numpy', 'npy_cpu.h'), + join('include', 'numpy', 'numpyconfig.h'), + join('include', 'numpy', 'ndarraytypes.h'), + join('include', 'numpy', 'npy_1_7_deprecated_api.h'), + # add library sources as distuils does not consider libraries + # dependencies + ] + npysort_sources + npymath_sources + + multiarray_src = [ + join('src', 'multiarray', 'alloc.c'), + join('src', 'multiarray', 'arrayobject.c'), + join('src', 'multiarray', 'arraytypes.c.src'), + join('src', 'multiarray', 'array_assign.c'), + join('src', 'multiarray', 'array_assign_scalar.c'), + join('src', 'multiarray', 'array_assign_array.c'), + join('src', 'multiarray', 'buffer.c'), + join('src', 'multiarray', 'calculation.c'), + join('src', 'multiarray', 'compiled_base.c'), + join('src', 'multiarray', 'common.c'), + join('src', 'multiarray', 'convert.c'), + join('src', 'multiarray', 'convert_datatype.c'), + join('src', 'multiarray', 'conversion_utils.c'), + join('src', 'multiarray', 'ctors.c'), + join('src', 'multiarray', 'datetime.c'), + join('src', 'multiarray', 'datetime_strings.c'), + join('src', 'multiarray', 'datetime_busday.c'), + join('src', 'multiarray', 'datetime_busdaycal.c'), + join('src', 'multiarray', 'descriptor.c'), + join('src', 'multiarray', 'dragon4.c'), + join('src', 'multiarray', 'dtype_transfer.c'), + join('src', 'multiarray', 'einsum.c.src'), + join('src', 'multiarray', 'flagsobject.c'), + join('src', 'multiarray', 'getset.c'), + join('src', 'multiarray', 'hashdescr.c'), + join('src', 'multiarray', 'item_selection.c'), + join('src', 'multiarray', 'iterators.c'), + join('src', 'multiarray', 'lowlevel_strided_loops.c.src'), + join('src', 'multiarray', 'mapping.c'), + join('src', 'multiarray', 'methods.c'), + join('src', 'multiarray', 'multiarraymodule.c'), + join('src', 'multiarray', 'nditer_templ.c.src'), + join('src', 'multiarray', 'nditer_api.c'), + join('src', 'multiarray', 'nditer_constr.c'), + join('src', 'multiarray', 'nditer_pywrap.c'), + join('src', 'multiarray', 'number.c'), + join('src', 'multiarray', 'numpyos.c'), + join('src', 'multiarray', 'refcount.c'), + join('src', 'multiarray', 'sequence.c'), + join('src', 'multiarray', 'shape.c'), + join('src', 'multiarray', 'scalarapi.c'), + join('src', 'multiarray', 'scalartypes.c.src'), + join('src', 'multiarray', 'strfuncs.c'), + join('src', 'multiarray', 'temp_elide.c'), + join('src', 'multiarray', 'usertypes.c'), + join('src', 'multiarray', 'ucsnarrow.c'), + join('src', 'multiarray', 'vdot.c'), + join('src', 'private', 'templ_common.h.src'), + join('src', 'private', 'mem_overlap.c'), + join('src', 'private', 'npy_longdouble.c'), + join('src', 'private', 'ufunc_override.c'), + ] + + blas_info = get_info('blas_opt', 0) + if blas_info and ('HAVE_CBLAS', None) in blas_info.get('define_macros', []): + extra_info = blas_info + # These files are also in MANIFEST.in so that they are always in + # the source distribution independently of HAVE_CBLAS. + multiarray_src.extend([join('src', 'multiarray', 'cblasfuncs.c'), + join('src', 'multiarray', 'python_xerbla.c'), + ]) + if uses_accelerate_framework(blas_info): + multiarray_src.extend(get_sgemv_fix()) + else: + extra_info = {} + + config.add_extension('multiarray', + sources=multiarray_src + + [generate_config_h, + generate_numpyconfig_h, + generate_numpy_api, + join(codegen_dir, 'generate_numpy_api.py'), + join('*.py')], + depends=deps + multiarray_deps, + libraries=['npymath', 'npysort'], + extra_info=extra_info) + + ####################################################################### + # umath module # + ####################################################################### + + def generate_umath_c(ext, build_dir): + target = join(build_dir, header_dir, '__umath_generated.c') + dir = os.path.dirname(target) + if not os.path.exists(dir): + os.makedirs(dir) + script = generate_umath_py + if newer(script, target): + f = open(target, 'w') + f.write(generate_umath.make_code(generate_umath.defdict, + generate_umath.__file__)) + f.close() + return [] + + umath_src = [ + join('src', 'umath', 'umathmodule.c'), + join('src', 'umath', 'reduction.c'), + join('src', 'umath', 'funcs.inc.src'), + join('src', 'umath', 'simd.inc.src'), + join('src', 'umath', 'loops.h.src'), + join('src', 'umath', 'loops.c.src'), + join('src', 'umath', 'ufunc_object.c'), + join('src', 'umath', 'extobj.c'), + join('src', 'umath', 'scalarmath.c.src'), + join('src', 'umath', 'ufunc_type_resolution.c'), + join('src', 'umath', 'override.c'), + join('src', 'private', 'mem_overlap.c'), + join('src', 'private', 'npy_longdouble.c'), + join('src', 'private', 'ufunc_override.c')] + + umath_deps = [ + generate_umath_py, + join('include', 'numpy', 'npy_math.h'), + join('include', 'numpy', 'halffloat.h'), + join('src', 'multiarray', 'common.h'), + join('src', 'private', 'templ_common.h.src'), + join('src', 'umath', 'simd.inc.src'), + join('src', 'umath', 'override.h'), + join(codegen_dir, 'generate_ufunc_api.py'), + join('src', 'private', 'lowlevel_strided_loops.h'), + join('src', 'private', 'mem_overlap.h'), + join('src', 'private', 'npy_longdouble.h'), + join('src', 'private', 'ufunc_override.h'), + join('src', 'private', 'binop_override.h')] + npymath_sources + + config.add_extension('umath', + sources=umath_src + + [generate_config_h, + generate_numpyconfig_h, + generate_umath_c, + generate_ufunc_api], + depends=deps + umath_deps, + libraries=['npymath'], + ) + + ####################################################################### + # umath_tests module # + ####################################################################### + + config.add_extension('umath_tests', + sources=[join('src', 'umath', 'umath_tests.c.src')]) + + ####################################################################### + # custom rational dtype module # + ####################################################################### + + config.add_extension('test_rational', + sources=[join('src', 'umath', 'test_rational.c.src')]) + + ####################################################################### + # struct_ufunc_test module # + ####################################################################### + + config.add_extension('struct_ufunc_test', + sources=[join('src', 'umath', 'struct_ufunc_test.c.src')]) + + ####################################################################### + # multiarray_tests module # + ####################################################################### + + config.add_extension('multiarray_tests', + sources=[join('src', 'multiarray', 'multiarray_tests.c.src'), + join('src', 'private', 'mem_overlap.c')], + depends=[join('src', 'private', 'mem_overlap.h'), + join('src', 'private', 'npy_extint128.h')], + libraries=['npymath']) + + ####################################################################### + # operand_flag_tests module # + ####################################################################### + + config.add_extension('operand_flag_tests', + sources=[join('src', 'umath', 'operand_flag_tests.c.src')]) + + config.add_data_dir('tests') + config.add_data_dir('tests/data') + + config.make_svn_version_py() + + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py new file mode 100644 index 0000000..bd093c5 --- /dev/null +++ b/numpy/core/setup_common.py @@ -0,0 +1,391 @@ +from __future__ import division, absolute_import, print_function + +# Code common to build tools +import sys +import warnings +import copy +import binascii + +from numpy.distutils.misc_util import mingw32 + + +#------------------- +# Versioning support +#------------------- +# How to change C_API_VERSION ? +# - increase C_API_VERSION value +# - record the hash for the new C API with the script cversions.py +# and add the hash to cversions.txt +# The hash values are used to remind developers when the C API number was not +# updated - generates a MismatchCAPIWarning warning which is turned into an +# exception for released version. + +# Binary compatibility version number. This number is increased whenever the +# C-API is changed such that binary compatibility is broken, i.e. whenever a +# recompile of extension modules is needed. +C_ABI_VERSION = 0x01000009 + +# Minor API version. This number is increased whenever a change is made to the +# C-API -- whether it breaks binary compatibility or not. Some changes, such +# as adding a function pointer to the end of the function table, can be made +# without breaking binary compatibility. In this case, only the C_API_VERSION +# (*not* C_ABI_VERSION) would be increased. Whenever binary compatibility is +# broken, both C_API_VERSION and C_ABI_VERSION should be increased. +# +# 0x00000008 - 1.7.x +# 0x00000009 - 1.8.x +# 0x00000009 - 1.9.x +# 0x0000000a - 1.10.x +# 0x0000000a - 1.11.x +# 0x0000000a - 1.12.x +# 0x0000000b - 1.13.x +# 0x0000000c - 1.14.x +C_API_VERSION = 0x0000000c + +class MismatchCAPIWarning(Warning): + pass + +def is_released(config): + """Return True if a released version of numpy is detected.""" + from distutils.version import LooseVersion + + v = config.get_version('../version.py') + if v is None: + raise ValueError("Could not get version") + pv = LooseVersion(vstring=v).version + if len(pv) > 3: + return False + return True + +def get_api_versions(apiversion, codegen_dir): + """ + Return current C API checksum and the recorded checksum. + + Return current C API checksum and the recorded checksum for the given + version of the C API version. + + """ + # Compute the hash of the current API as defined in the .txt files in + # code_generators + sys.path.insert(0, codegen_dir) + try: + m = __import__('genapi') + numpy_api = __import__('numpy_api') + curapi_hash = m.fullapi_hash(numpy_api.full_api) + apis_hash = m.get_versions_hash() + finally: + del sys.path[0] + + return curapi_hash, apis_hash[apiversion] + +def check_api_version(apiversion, codegen_dir): + """Emits a MismacthCAPIWarning if the C API version needs updating.""" + curapi_hash, api_hash = get_api_versions(apiversion, codegen_dir) + + # If different hash, it means that the api .txt files in + # codegen_dir have been updated without the API version being + # updated. Any modification in those .txt files should be reflected + # in the api and eventually abi versions. + # To compute the checksum of the current API, use + # code_generators/cversions.py script + if not curapi_hash == api_hash: + msg = ("API mismatch detected, the C API version " + "numbers have to be updated. Current C api version is %d, " + "with checksum %s, but recorded checksum for C API version %d in " + "codegen_dir/cversions.txt is %s. If functions were added in the " + "C API, you have to update C_API_VERSION in %s." + ) + warnings.warn(msg % (apiversion, curapi_hash, apiversion, api_hash, + __file__), + MismatchCAPIWarning, stacklevel=2) +# Mandatory functions: if not found, fail the build +MANDATORY_FUNCS = ["sin", "cos", "tan", "sinh", "cosh", "tanh", "fabs", + "floor", "ceil", "sqrt", "log10", "log", "exp", "asin", + "acos", "atan", "fmod", 'modf', 'frexp', 'ldexp'] + +# Standard functions which may not be available and for which we have a +# replacement implementation. Note that some of these are C99 functions. +OPTIONAL_STDFUNCS = ["expm1", "log1p", "acosh", "asinh", "atanh", + "rint", "trunc", "exp2", "log2", "hypot", "atan2", "pow", + "copysign", "nextafter", "ftello", "fseeko", + "strtoll", "strtoull", "cbrt", "strtold_l", "fallocate", + "backtrace"] + + +OPTIONAL_HEADERS = [ +# sse headers only enabled automatically on amd64/x32 builds + "xmmintrin.h", # SSE + "emmintrin.h", # SSE2 + "features.h", # for glibc version linux + "xlocale.h", # see GH#8367 + "dlfcn.h", # dladdr +] + +# optional gcc compiler builtins and their call arguments and optional a +# required header and definition name (HAVE_ prepended) +# call arguments are required as the compiler will do strict signature checking +OPTIONAL_INTRINSICS = [("__builtin_isnan", '5.'), + ("__builtin_isinf", '5.'), + ("__builtin_isfinite", '5.'), + ("__builtin_bswap32", '5u'), + ("__builtin_bswap64", '5u'), + ("__builtin_expect", '5, 0'), + ("__builtin_mul_overflow", '5, 5, (int*)5'), + # broken on OSX 10.11, make sure its not optimized away + ("volatile int r = __builtin_cpu_supports", '"sse"', + "stdio.h", "__BUILTIN_CPU_SUPPORTS"), + # MMX only needed for icc, but some clangs don't have it + ("_m_from_int64", '0', "emmintrin.h"), + ("_mm_load_ps", '(float*)0', "xmmintrin.h"), # SSE + ("_mm_prefetch", '(float*)0, _MM_HINT_NTA', + "xmmintrin.h"), # SSE + ("_mm_load_pd", '(double*)0', "emmintrin.h"), # SSE2 + ("__builtin_prefetch", "(float*)0, 0, 3"), + # check that the linker can handle avx + ("__asm__ volatile", '"vpand %xmm1, %xmm2, %xmm3"', + "stdio.h", "LINK_AVX"), + ("__asm__ volatile", '"vpand %ymm1, %ymm2, %ymm3"', + "stdio.h", "LINK_AVX2"), + ] + +# function attributes +# tested via "int %s %s(void *);" % (attribute, name) +# function name will be converted to HAVE_ preprocessor macro +OPTIONAL_FUNCTION_ATTRIBUTES = [('__attribute__((optimize("unroll-loops")))', + 'attribute_optimize_unroll_loops'), + ('__attribute__((optimize("O3")))', + 'attribute_optimize_opt_3'), + ('__attribute__((nonnull (1)))', + 'attribute_nonnull'), + ('__attribute__((target ("avx")))', + 'attribute_target_avx'), + ('__attribute__((target ("avx2")))', + 'attribute_target_avx2'), + ] + +# variable attributes tested via "int %s a" % attribute +OPTIONAL_VARIABLE_ATTRIBUTES = ["__thread", "__declspec(thread)"] + +# Subset of OPTIONAL_STDFUNCS which may alreay have HAVE_* defined by Python.h +OPTIONAL_STDFUNCS_MAYBE = [ + "expm1", "log1p", "acosh", "atanh", "asinh", "hypot", "copysign", + "ftello", "fseeko" + ] + +# C99 functions: float and long double versions +C99_FUNCS = [ + "sin", "cos", "tan", "sinh", "cosh", "tanh", "fabs", "floor", "ceil", + "rint", "trunc", "sqrt", "log10", "log", "log1p", "exp", "expm1", + "asin", "acos", "atan", "asinh", "acosh", "atanh", "hypot", "atan2", + "pow", "fmod", "modf", 'frexp', 'ldexp', "exp2", "log2", "copysign", + "nextafter", "cbrt" + ] +C99_FUNCS_SINGLE = [f + 'f' for f in C99_FUNCS] +C99_FUNCS_EXTENDED = [f + 'l' for f in C99_FUNCS] +C99_COMPLEX_TYPES = [ + 'complex double', 'complex float', 'complex long double' + ] +C99_COMPLEX_FUNCS = [ + "cabs", "cacos", "cacosh", "carg", "casin", "casinh", "catan", + "catanh", "ccos", "ccosh", "cexp", "cimag", "clog", "conj", "cpow", + "cproj", "creal", "csin", "csinh", "csqrt", "ctan", "ctanh" + ] + +def fname2def(name): + return "HAVE_%s" % name.upper() + +def sym2def(symbol): + define = symbol.replace(' ', '') + return define.upper() + +def type2def(symbol): + define = symbol.replace(' ', '_') + return define.upper() + +# Code to detect long double representation taken from MPFR m4 macro +def check_long_double_representation(cmd): + cmd._check_compiler() + body = LONG_DOUBLE_REPRESENTATION_SRC % {'type': 'long double'} + + # Disable whole program optimization (the default on vs2015, with python 3.5+) + # which generates intermediary object files and prevents checking the + # float representation. + if sys.platform == "win32" and not mingw32(): + try: + cmd.compiler.compile_options.remove("/GL") + except (AttributeError, ValueError): + pass + + # Disable multi-file interprocedural optimization in the Intel compiler on Linux + # which generates intermediary object files and prevents checking the + # float representation. + elif (sys.platform != "win32" + and cmd.compiler.compiler_type.startswith('intel') + and '-ipo' in cmd.compiler.cc_exe): + newcompiler = cmd.compiler.cc_exe.replace(' -ipo', '') + cmd.compiler.set_executables( + compiler=newcompiler, + compiler_so=newcompiler, + compiler_cxx=newcompiler, + linker_exe=newcompiler, + linker_so=newcompiler + ' -shared' + ) + + # We need to use _compile because we need the object filename + src, obj = cmd._compile(body, None, None, 'c') + try: + ltype = long_double_representation(pyod(obj)) + return ltype + except ValueError: + # try linking to support CC="gcc -flto" or icc -ipo + # struct needs to be volatile so it isn't optimized away + body = body.replace('struct', 'volatile struct') + body += "int main(void) { return 0; }\n" + src, obj = cmd._compile(body, None, None, 'c') + cmd.temp_files.append("_configtest") + cmd.compiler.link_executable([obj], "_configtest") + ltype = long_double_representation(pyod("_configtest")) + return ltype + finally: + cmd._clean() + +LONG_DOUBLE_REPRESENTATION_SRC = r""" +/* "before" is 16 bytes to ensure there's no padding between it and "x". + * We're not expecting any "long double" bigger than 16 bytes or with + * alignment requirements stricter than 16 bytes. */ +typedef %(type)s test_type; + +struct { + char before[16]; + test_type x; + char after[8]; +} foo = { + { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\001', '\043', '\105', '\147', '\211', '\253', '\315', '\357' }, + -123456789.0, + { '\376', '\334', '\272', '\230', '\166', '\124', '\062', '\020' } +}; +""" + +def pyod(filename): + """Python implementation of the od UNIX utility (od -b, more exactly). + + Parameters + ---------- + filename : str + name of the file to get the dump from. + + Returns + ------- + out : seq + list of lines of od output + + Note + ---- + We only implement enough to get the necessary information for long double + representation, this is not intended as a compatible replacement for od. + """ + def _pyod2(): + out = [] + + fid = open(filename, 'rb') + try: + yo = [int(oct(int(binascii.b2a_hex(o), 16))) for o in fid.read()] + for i in range(0, len(yo), 16): + line = ['%07d' % int(oct(i))] + line.extend(['%03d' % c for c in yo[i:i+16]]) + out.append(" ".join(line)) + return out + finally: + fid.close() + + def _pyod3(): + out = [] + + fid = open(filename, 'rb') + try: + yo2 = [oct(o)[2:] for o in fid.read()] + for i in range(0, len(yo2), 16): + line = ['%07d' % int(oct(i)[2:])] + line.extend(['%03d' % int(c) for c in yo2[i:i+16]]) + out.append(" ".join(line)) + return out + finally: + fid.close() + + if sys.version_info[0] < 3: + return _pyod2() + else: + return _pyod3() + +_BEFORE_SEQ = ['000', '000', '000', '000', '000', '000', '000', '000', + '001', '043', '105', '147', '211', '253', '315', '357'] +_AFTER_SEQ = ['376', '334', '272', '230', '166', '124', '062', '020'] + +_IEEE_DOUBLE_BE = ['301', '235', '157', '064', '124', '000', '000', '000'] +_IEEE_DOUBLE_LE = _IEEE_DOUBLE_BE[::-1] +_INTEL_EXTENDED_12B = ['000', '000', '000', '000', '240', '242', '171', '353', + '031', '300', '000', '000'] +_INTEL_EXTENDED_16B = ['000', '000', '000', '000', '240', '242', '171', '353', + '031', '300', '000', '000', '000', '000', '000', '000'] +_MOTOROLA_EXTENDED_12B = ['300', '031', '000', '000', '353', '171', + '242', '240', '000', '000', '000', '000'] +_IEEE_QUAD_PREC_BE = ['300', '031', '326', '363', '105', '100', '000', '000', + '000', '000', '000', '000', '000', '000', '000', '000'] +_IEEE_QUAD_PREC_LE = _IEEE_QUAD_PREC_BE[::-1] +_DOUBLE_DOUBLE_BE = (['301', '235', '157', '064', '124', '000', '000', '000'] + + ['000'] * 8) +_DOUBLE_DOUBLE_LE = (['000', '000', '000', '124', '064', '157', '235', '301'] + + ['000'] * 8) + +def long_double_representation(lines): + """Given a binary dump as given by GNU od -b, look for long double + representation.""" + + # Read contains a list of 32 items, each item is a byte (in octal + # representation, as a string). We 'slide' over the output until read is of + # the form before_seq + content + after_sequence, where content is the long double + # representation: + # - content is 12 bytes: 80 bits Intel representation + # - content is 16 bytes: 80 bits Intel representation (64 bits) or quad precision + # - content is 8 bytes: same as double (not implemented yet) + read = [''] * 32 + saw = None + for line in lines: + # we skip the first word, as od -b output an index at the beginning of + # each line + for w in line.split()[1:]: + read.pop(0) + read.append(w) + + # If the end of read is equal to the after_sequence, read contains + # the long double + if read[-8:] == _AFTER_SEQ: + saw = copy.copy(read) + if read[:12] == _BEFORE_SEQ[4:]: + if read[12:-8] == _INTEL_EXTENDED_12B: + return 'INTEL_EXTENDED_12_BYTES_LE' + if read[12:-8] == _MOTOROLA_EXTENDED_12B: + return 'MOTOROLA_EXTENDED_12_BYTES_BE' + elif read[:8] == _BEFORE_SEQ[8:]: + if read[8:-8] == _INTEL_EXTENDED_16B: + return 'INTEL_EXTENDED_16_BYTES_LE' + elif read[8:-8] == _IEEE_QUAD_PREC_BE: + return 'IEEE_QUAD_BE' + elif read[8:-8] == _IEEE_QUAD_PREC_LE: + return 'IEEE_QUAD_LE' + elif read[8:-8] == _DOUBLE_DOUBLE_BE: + return 'DOUBLE_DOUBLE_BE' + elif read[8:-8] == _DOUBLE_DOUBLE_LE: + return 'DOUBLE_DOUBLE_LE' + elif read[:16] == _BEFORE_SEQ: + if read[16:-8] == _IEEE_DOUBLE_LE: + return 'IEEE_DOUBLE_LE' + elif read[16:-8] == _IEEE_DOUBLE_BE: + return 'IEEE_DOUBLE_BE' + + if saw is not None: + raise ValueError("Unrecognized format (%s)" % saw) + else: + # We never detected the after_sequence + raise ValueError("Could not lock sequences (%s)" % saw) diff --git a/numpy/core/shape_base.py b/numpy/core/shape_base.py new file mode 100644 index 0000000..319c250 --- /dev/null +++ b/numpy/core/shape_base.py @@ -0,0 +1,608 @@ +from __future__ import division, absolute_import, print_function + +__all__ = ['atleast_1d', 'atleast_2d', 'atleast_3d', 'block', 'hstack', + 'stack', 'vstack'] + + +from . import numeric as _nx +from .numeric import array, asanyarray, newaxis +from .multiarray import normalize_axis_index + +def atleast_1d(*arys): + """ + Convert inputs to arrays with at least one dimension. + + Scalar inputs are converted to 1-dimensional arrays, whilst + higher-dimensional inputs are preserved. + + Parameters + ---------- + arys1, arys2, ... : array_like + One or more input arrays. + + Returns + ------- + ret : ndarray + An array, or list of arrays, each with ``a.ndim >= 1``. + Copies are made only if necessary. + + See Also + -------- + atleast_2d, atleast_3d + + Examples + -------- + >>> np.atleast_1d(1.0) + array([ 1.]) + + >>> x = np.arange(9.0).reshape(3,3) + >>> np.atleast_1d(x) + array([[ 0., 1., 2.], + [ 3., 4., 5.], + [ 6., 7., 8.]]) + >>> np.atleast_1d(x) is x + True + + >>> np.atleast_1d(1, [3, 4]) + [array([1]), array([3, 4])] + + """ + res = [] + for ary in arys: + ary = asanyarray(ary) + if ary.ndim == 0: + result = ary.reshape(1) + else: + result = ary + res.append(result) + if len(res) == 1: + return res[0] + else: + return res + +def atleast_2d(*arys): + """ + View inputs as arrays with at least two dimensions. + + Parameters + ---------- + arys1, arys2, ... : array_like + One or more array-like sequences. Non-array inputs are converted + to arrays. Arrays that already have two or more dimensions are + preserved. + + Returns + ------- + res, res2, ... : ndarray + An array, or list of arrays, each with ``a.ndim >= 2``. + Copies are avoided where possible, and views with two or more + dimensions are returned. + + See Also + -------- + atleast_1d, atleast_3d + + Examples + -------- + >>> np.atleast_2d(3.0) + array([[ 3.]]) + + >>> x = np.arange(3.0) + >>> np.atleast_2d(x) + array([[ 0., 1., 2.]]) + >>> np.atleast_2d(x).base is x + True + + >>> np.atleast_2d(1, [1, 2], [[1, 2]]) + [array([[1]]), array([[1, 2]]), array([[1, 2]])] + + """ + res = [] + for ary in arys: + ary = asanyarray(ary) + if ary.ndim == 0: + result = ary.reshape(1, 1) + elif ary.ndim == 1: + result = ary[newaxis,:] + else: + result = ary + res.append(result) + if len(res) == 1: + return res[0] + else: + return res + +def atleast_3d(*arys): + """ + View inputs as arrays with at least three dimensions. + + Parameters + ---------- + arys1, arys2, ... : array_like + One or more array-like sequences. Non-array inputs are converted to + arrays. Arrays that already have three or more dimensions are + preserved. + + Returns + ------- + res1, res2, ... : ndarray + An array, or list of arrays, each with ``a.ndim >= 3``. Copies are + avoided where possible, and views with three or more dimensions are + returned. For example, a 1-D array of shape ``(N,)`` becomes a view + of shape ``(1, N, 1)``, and a 2-D array of shape ``(M, N)`` becomes a + view of shape ``(M, N, 1)``. + + See Also + -------- + atleast_1d, atleast_2d + + Examples + -------- + >>> np.atleast_3d(3.0) + array([[[ 3.]]]) + + >>> x = np.arange(3.0) + >>> np.atleast_3d(x).shape + (1, 3, 1) + + >>> x = np.arange(12.0).reshape(4,3) + >>> np.atleast_3d(x).shape + (4, 3, 1) + >>> np.atleast_3d(x).base is x.base # x is a reshape, so not base itself + True + + >>> for arr in np.atleast_3d([1, 2], [[1, 2]], [[[1, 2]]]): + ... print(arr, arr.shape) + ... + [[[1] + [2]]] (1, 2, 1) + [[[1] + [2]]] (1, 2, 1) + [[[1 2]]] (1, 1, 2) + + """ + res = [] + for ary in arys: + ary = asanyarray(ary) + if ary.ndim == 0: + result = ary.reshape(1, 1, 1) + elif ary.ndim == 1: + result = ary[newaxis,:, newaxis] + elif ary.ndim == 2: + result = ary[:,:, newaxis] + else: + result = ary + res.append(result) + if len(res) == 1: + return res[0] + else: + return res + + +def vstack(tup): + """ + Stack arrays in sequence vertically (row wise). + + This is equivalent to concatenation along the first axis after 1-D arrays + of shape `(N,)` have been reshaped to `(1,N)`. Rebuilds arrays divided by + `vsplit`. + + This function makes most sense for arrays with up to 3 dimensions. For + instance, for pixel-data with a height (first axis), width (second axis), + and r/g/b channels (third axis). The functions `concatenate`, `stack` and + `block` provide more general stacking and concatenation operations. + + Parameters + ---------- + tup : sequence of ndarrays + The arrays must have the same shape along all but the first axis. + 1-D arrays must have the same length. + + Returns + ------- + stacked : ndarray + The array formed by stacking the given arrays, will be at least 2-D. + + See Also + -------- + stack : Join a sequence of arrays along a new axis. + hstack : Stack arrays in sequence horizontally (column wise). + dstack : Stack arrays in sequence depth wise (along third dimension). + concatenate : Join a sequence of arrays along an existing axis. + vsplit : Split array into a list of multiple sub-arrays vertically. + block : Assemble arrays from blocks. + + Examples + -------- + >>> a = np.array([1, 2, 3]) + >>> b = np.array([2, 3, 4]) + >>> np.vstack((a,b)) + array([[1, 2, 3], + [2, 3, 4]]) + + >>> a = np.array([[1], [2], [3]]) + >>> b = np.array([[2], [3], [4]]) + >>> np.vstack((a,b)) + array([[1], + [2], + [3], + [2], + [3], + [4]]) + + """ + return _nx.concatenate([atleast_2d(_m) for _m in tup], 0) + +def hstack(tup): + """ + Stack arrays in sequence horizontally (column wise). + + This is equivalent to concatenation along the second axis, except for 1-D + arrays where it concatenates along the first axis. Rebuilds arrays divided + by `hsplit`. + + This function makes most sense for arrays with up to 3 dimensions. For + instance, for pixel-data with a height (first axis), width (second axis), + and r/g/b channels (third axis). The functions `concatenate`, `stack` and + `block` provide more general stacking and concatenation operations. + + Parameters + ---------- + tup : sequence of ndarrays + The arrays must have the same shape along all but the second axis, + except 1-D arrays which can be any length. + + Returns + ------- + stacked : ndarray + The array formed by stacking the given arrays. + + See Also + -------- + stack : Join a sequence of arrays along a new axis. + vstack : Stack arrays in sequence vertically (row wise). + dstack : Stack arrays in sequence depth wise (along third axis). + concatenate : Join a sequence of arrays along an existing axis. + hsplit : Split array along second axis. + block : Assemble arrays from blocks. + + Examples + -------- + >>> a = np.array((1,2,3)) + >>> b = np.array((2,3,4)) + >>> np.hstack((a,b)) + array([1, 2, 3, 2, 3, 4]) + >>> a = np.array([[1],[2],[3]]) + >>> b = np.array([[2],[3],[4]]) + >>> np.hstack((a,b)) + array([[1, 2], + [2, 3], + [3, 4]]) + + """ + arrs = [atleast_1d(_m) for _m in tup] + # As a special case, dimension 0 of 1-dimensional arrays is "horizontal" + if arrs and arrs[0].ndim == 1: + return _nx.concatenate(arrs, 0) + else: + return _nx.concatenate(arrs, 1) + + +def stack(arrays, axis=0, out=None): + """ + Join a sequence of arrays along a new axis. + + The `axis` parameter specifies the index of the new axis in the dimensions + of the result. For example, if ``axis=0`` it will be the first dimension + and if ``axis=-1`` it will be the last dimension. + + .. versionadded:: 1.10.0 + + Parameters + ---------- + arrays : sequence of array_like + Each array must have the same shape. + axis : int, optional + The axis in the result array along which the input arrays are stacked. + out : ndarray, optional + If provided, the destination to place the result. The shape must be + correct, matching that of what stack would have returned if no + out argument were specified. + + Returns + ------- + stacked : ndarray + The stacked array has one more dimension than the input arrays. + + See Also + -------- + concatenate : Join a sequence of arrays along an existing axis. + split : Split array into a list of multiple sub-arrays of equal size. + block : Assemble arrays from blocks. + + Examples + -------- + >>> arrays = [np.random.randn(3, 4) for _ in range(10)] + >>> np.stack(arrays, axis=0).shape + (10, 3, 4) + + >>> np.stack(arrays, axis=1).shape + (3, 10, 4) + + >>> np.stack(arrays, axis=2).shape + (3, 4, 10) + + >>> a = np.array([1, 2, 3]) + >>> b = np.array([2, 3, 4]) + >>> np.stack((a, b)) + array([[1, 2, 3], + [2, 3, 4]]) + + >>> np.stack((a, b), axis=-1) + array([[1, 2], + [2, 3], + [3, 4]]) + + """ + arrays = [asanyarray(arr) for arr in arrays] + if not arrays: + raise ValueError('need at least one array to stack') + + shapes = set(arr.shape for arr in arrays) + if len(shapes) != 1: + raise ValueError('all input arrays must have the same shape') + + result_ndim = arrays[0].ndim + 1 + axis = normalize_axis_index(axis, result_ndim) + + sl = (slice(None),) * axis + (_nx.newaxis,) + expanded_arrays = [arr[sl] for arr in arrays] + return _nx.concatenate(expanded_arrays, axis=axis, out=out) + + +def _block_check_depths_match(arrays, parent_index=[]): + """ + Recursive function checking that the depths of nested lists in `arrays` + all match. Mismatch raises a ValueError as described in the block + docstring below. + + The entire index (rather than just the depth) needs to be calculated + for each innermost list, in case an error needs to be raised, so that + the index of the offending list can be printed as part of the error. + + The parameter `parent_index` is the full index of `arrays` within the + nested lists passed to _block_check_depths_match at the top of the + recursion. + The return value is a pair. The first item returned is the full index + of an element (specifically the first element) from the bottom of the + nesting in `arrays`. An empty list at the bottom of the nesting is + represented by a `None` index. + The second item is the maximum of the ndims of the arrays nested in + `arrays`. + """ + def format_index(index): + idx_str = ''.join('[{}]'.format(i) for i in index if i is not None) + return 'arrays' + idx_str + if type(arrays) is tuple: + # not strictly necessary, but saves us from: + # - more than one way to do things - no point treating tuples like + # lists + # - horribly confusing behaviour that results when tuples are + # treated like ndarray + raise TypeError( + '{} is a tuple. ' + 'Only lists can be used to arrange blocks, and np.block does ' + 'not allow implicit conversion from tuple to ndarray.'.format( + format_index(parent_index) + ) + ) + elif type(arrays) is list and len(arrays) > 0: + idxs_ndims = (_block_check_depths_match(arr, parent_index + [i]) + for i, arr in enumerate(arrays)) + + first_index, max_arr_ndim = next(idxs_ndims) + for index, ndim in idxs_ndims: + if ndim > max_arr_ndim: + max_arr_ndim = ndim + if len(index) != len(first_index): + raise ValueError( + "List depths are mismatched. First element was at depth " + "{}, but there is an element at depth {} ({})".format( + len(first_index), + len(index), + format_index(index) + ) + ) + return first_index, max_arr_ndim + elif type(arrays) is list and len(arrays) == 0: + # We've 'bottomed out' on an empty list + return parent_index + [None], 0 + else: + # We've 'bottomed out' - arrays is either a scalar or an array + return parent_index, _nx.ndim(arrays) + + +def _block(arrays, max_depth, result_ndim): + """ + Internal implementation of block. `arrays` is the argument passed to + block. `max_depth` is the depth of nested lists within `arrays` and + `result_ndim` is the greatest of the dimensions of the arrays in + `arrays` and the depth of the lists in `arrays` (see block docstring + for details). + """ + def atleast_nd(a, ndim): + # Ensures `a` has at least `ndim` dimensions by prepending + # ones to `a.shape` as necessary + return array(a, ndmin=ndim, copy=False, subok=True) + + def block_recursion(arrays, depth=0): + if depth < max_depth: + if len(arrays) == 0: + raise ValueError('Lists cannot be empty') + arrs = [block_recursion(arr, depth+1) for arr in arrays] + return _nx.concatenate(arrs, axis=-(max_depth-depth)) + else: + # We've 'bottomed out' - arrays is either a scalar or an array + # type(arrays) is not list + return atleast_nd(arrays, result_ndim) + + try: + return block_recursion(arrays) + finally: + # recursive closures have a cyclic reference to themselves, which + # requires gc to collect (gh-10620). To avoid this problem, for + # performance and PyPy friendliness, we break the cycle: + block_recursion = None + + +def block(arrays): + """ + Assemble an nd-array from nested lists of blocks. + + Blocks in the innermost lists are concatenated (see `concatenate`) along + the last dimension (-1), then these are concatenated along the + second-last dimension (-2), and so on until the outermost list is reached. + + Blocks can be of any dimension, but will not be broadcasted using the normal + rules. Instead, leading axes of size 1 are inserted, to make ``block.ndim`` + the same for all blocks. This is primarily useful for working with scalars, + and means that code like ``np.block([v, 1])`` is valid, where + ``v.ndim == 1``. + + When the nested list is two levels deep, this allows block matrices to be + constructed from their components. + + .. versionadded:: 1.13.0 + + Parameters + ---------- + arrays : nested list of array_like or scalars (but not tuples) + If passed a single ndarray or scalar (a nested list of depth 0), this + is returned unmodified (and not copied). + + Elements shapes must match along the appropriate axes (without + broadcasting), but leading 1s will be prepended to the shape as + necessary to make the dimensions match. + + Returns + ------- + block_array : ndarray + The array assembled from the given blocks. + + The dimensionality of the output is equal to the greatest of: + * the dimensionality of all the inputs + * the depth to which the input list is nested + + Raises + ------ + ValueError + * If list depths are mismatched - for instance, ``[[a, b], c]`` is + illegal, and should be spelt ``[[a, b], [c]]`` + * If lists are empty - for instance, ``[[a, b], []]`` + + See Also + -------- + concatenate : Join a sequence of arrays together. + stack : Stack arrays in sequence along a new dimension. + hstack : Stack arrays in sequence horizontally (column wise). + vstack : Stack arrays in sequence vertically (row wise). + dstack : Stack arrays in sequence depth wise (along third dimension). + vsplit : Split array into a list of multiple sub-arrays vertically. + + Notes + ----- + + When called with only scalars, ``np.block`` is equivalent to an ndarray + call. So ``np.block([[1, 2], [3, 4]])`` is equivalent to + ``np.array([[1, 2], [3, 4]])``. + + This function does not enforce that the blocks lie on a fixed grid. + ``np.block([[a, b], [c, d]])`` is not restricted to arrays of the form:: + + AAAbb + AAAbb + cccDD + + But is also allowed to produce, for some ``a, b, c, d``:: + + AAAbb + AAAbb + cDDDD + + Since concatenation happens along the last axis first, `block` is _not_ + capable of producing the following directly:: + + AAAbb + cccbb + cccDD + + Matlab's "square bracket stacking", ``[A, B, ...; p, q, ...]``, is + equivalent to ``np.block([[A, B, ...], [p, q, ...]])``. + + Examples + -------- + The most common use of this function is to build a block matrix + + >>> A = np.eye(2) * 2 + >>> B = np.eye(3) * 3 + >>> np.block([ + ... [A, np.zeros((2, 3))], + ... [np.ones((3, 2)), B ] + ... ]) + array([[ 2., 0., 0., 0., 0.], + [ 0., 2., 0., 0., 0.], + [ 1., 1., 3., 0., 0.], + [ 1., 1., 0., 3., 0.], + [ 1., 1., 0., 0., 3.]]) + + With a list of depth 1, `block` can be used as `hstack` + + >>> np.block([1, 2, 3]) # hstack([1, 2, 3]) + array([1, 2, 3]) + + >>> a = np.array([1, 2, 3]) + >>> b = np.array([2, 3, 4]) + >>> np.block([a, b, 10]) # hstack([a, b, 10]) + array([1, 2, 3, 2, 3, 4, 10]) + + >>> A = np.ones((2, 2), int) + >>> B = 2 * A + >>> np.block([A, B]) # hstack([A, B]) + array([[1, 1, 2, 2], + [1, 1, 2, 2]]) + + With a list of depth 2, `block` can be used in place of `vstack`: + + >>> a = np.array([1, 2, 3]) + >>> b = np.array([2, 3, 4]) + >>> np.block([[a], [b]]) # vstack([a, b]) + array([[1, 2, 3], + [2, 3, 4]]) + + >>> A = np.ones((2, 2), int) + >>> B = 2 * A + >>> np.block([[A], [B]]) # vstack([A, B]) + array([[1, 1], + [1, 1], + [2, 2], + [2, 2]]) + + It can also be used in places of `atleast_1d` and `atleast_2d` + + >>> a = np.array(0) + >>> b = np.array([1]) + >>> np.block([a]) # atleast_1d(a) + array([0]) + >>> np.block([b]) # atleast_1d(b) + array([1]) + + >>> np.block([[a]]) # atleast_2d(a) + array([[0]]) + >>> np.block([[b]]) # atleast_2d(b) + array([[1]]) + + + """ + bottom_index, arr_ndim = _block_check_depths_match(arrays) + list_ndim = len(bottom_index) + return _block(arrays, list_ndim, max(arr_ndim, list_ndim)) diff --git a/numpy/core/src/dummymodule.c b/numpy/core/src/dummymodule.c new file mode 100644 index 0000000..718199f --- /dev/null +++ b/numpy/core/src/dummymodule.c @@ -0,0 +1,48 @@ +/* -*- c -*- */ + +/* + * This is a dummy module whose purpose is to get distutils to generate the + * configuration files before the libraries are made. + */ + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define NO_IMPORT_ARRAY + +#include +#include + +static struct PyMethodDef methods[] = { + {NULL, NULL, 0, NULL} +}; + + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "dummy", + NULL, + -1, + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +/* Initialization function for the module */ +#if defined(NPY_PY3K) +PyMODINIT_FUNC PyInit__dummy(void) { + PyObject *m; + m = PyModule_Create(&moduledef); + if (!m) { + return NULL; + } + return m; +} +#else +PyMODINIT_FUNC +init_dummy(void) { + Py_InitModule("_dummy", methods); +} +#endif diff --git a/numpy/core/src/multiarray/_datetime.h b/numpy/core/src/multiarray/_datetime.h new file mode 100644 index 0000000..3db1254 --- /dev/null +++ b/numpy/core/src/multiarray/_datetime.h @@ -0,0 +1,374 @@ +#ifndef _NPY_PRIVATE__DATETIME_H_ +#define _NPY_PRIVATE__DATETIME_H_ + +extern NPY_NO_EXPORT char *_datetime_strings[NPY_DATETIME_NUMUNITS]; +extern NPY_NO_EXPORT int _days_per_month_table[2][12]; + +NPY_NO_EXPORT void +numpy_pydatetime_import(void); + +/* + * Returns 1 if the given year is a leap year, 0 otherwise. + */ +NPY_NO_EXPORT int +is_leapyear(npy_int64 year); + +/* + * Calculates the days offset from the 1970 epoch. + */ +NPY_NO_EXPORT npy_int64 +get_datetimestruct_days(const npy_datetimestruct *dts); + +/* + * Creates a datetime or timedelta dtype using a copy of the provided metadata. + */ +NPY_NO_EXPORT PyArray_Descr * +create_datetime_dtype(int type_num, PyArray_DatetimeMetaData *meta); + +/* + * Creates a datetime or timedelta dtype using the given unit. + */ +NPY_NO_EXPORT PyArray_Descr * +create_datetime_dtype_with_unit(int type_num, NPY_DATETIMEUNIT unit); + +/* + * This function returns a pointer to the DateTimeMetaData + * contained within the provided datetime dtype. + */ +NPY_NO_EXPORT PyArray_DatetimeMetaData * +get_datetime_metadata_from_dtype(PyArray_Descr *dtype); + +/* + * Both type1 and type2 must be either NPY_DATETIME or NPY_TIMEDELTA. + * Applies the type promotion rules between the two types, returning + * the promoted type. + */ +NPY_NO_EXPORT PyArray_Descr * +datetime_type_promotion(PyArray_Descr *type1, PyArray_Descr *type2); + +/* + * Converts a datetime from a datetimestruct to a datetime based + * on some metadata. + */ +NPY_NO_EXPORT int +convert_datetimestruct_to_datetime(PyArray_DatetimeMetaData *meta, + const npy_datetimestruct *dts, + npy_datetime *out); + +/* + * Extracts the month number, within the current year, + * from a 'datetime64[D]' value. January is 1, etc. + */ +NPY_NO_EXPORT int +days_to_month_number(npy_datetime days); + +/* + * Parses the metadata string into the metadata C structure. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +parse_datetime_metadata_from_metastr(char *metastr, Py_ssize_t len, + PyArray_DatetimeMetaData *out_meta); + + +/* + * Converts a datetype dtype string into a dtype descr object. + * The "type" string should be NULL-terminated, and len should + * contain its string length. + */ +NPY_NO_EXPORT PyArray_Descr * +parse_dtype_from_datetime_typestr(char *typestr, Py_ssize_t len); + +/* + * Converts a substring given by 'str' and 'len' into + * a date time unit enum value. The 'metastr' parameter + * is used for error messages, and may be NULL. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT NPY_DATETIMEUNIT +parse_datetime_unit_from_string(char *str, Py_ssize_t len, char *metastr); + +/* + * Translate divisors into multiples of smaller units. + * 'metastr' is used for the error message if the divisor doesn't work, + * and can be NULL if the metadata didn't come from a string. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_datetime_divisor_to_multiple(PyArray_DatetimeMetaData *meta, + int den, char *metastr); + +/* + * Determines whether the 'divisor' metadata divides evenly into + * the 'dividend' metadata. + */ +NPY_NO_EXPORT npy_bool +datetime_metadata_divides( + PyArray_DatetimeMetaData *dividend, + PyArray_DatetimeMetaData *divisor, + int strict_with_nonlinear_units); + +/* + * This provides the casting rules for the DATETIME data type units. + * + * Notably, there is a barrier between 'date units' and 'time units' + * for all but 'unsafe' casting. + */ +NPY_NO_EXPORT npy_bool +can_cast_datetime64_units(NPY_DATETIMEUNIT src_unit, + NPY_DATETIMEUNIT dst_unit, + NPY_CASTING casting); + +/* + * This provides the casting rules for the DATETIME data type metadata. + */ +NPY_NO_EXPORT npy_bool +can_cast_datetime64_metadata(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + NPY_CASTING casting); + +/* + * This provides the casting rules for the TIMEDELTA data type units. + * + * Notably, there is a barrier between the nonlinear years and + * months units, and all the other units. + */ +NPY_NO_EXPORT npy_bool +can_cast_timedelta64_units(NPY_DATETIMEUNIT src_unit, + NPY_DATETIMEUNIT dst_unit, + NPY_CASTING casting); + +/* + * This provides the casting rules for the TIMEDELTA data type metadata. + */ +NPY_NO_EXPORT npy_bool +can_cast_timedelta64_metadata(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + NPY_CASTING casting); + +/* + * Computes the conversion factor to convert data with 'src_meta' metadata + * into data with 'dst_meta' metadata. + * + * If overflow occurs, both out_num and out_denom are set to 0, but + * no error is set. + */ +NPY_NO_EXPORT void +get_datetime_conversion_factor(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + npy_int64 *out_num, npy_int64 *out_denom); + +/* + * Given a pointer to datetime metadata, + * returns a tuple for pickling and other purposes. + */ +NPY_NO_EXPORT PyObject * +convert_datetime_metadata_to_tuple(PyArray_DatetimeMetaData *meta); + +/* + * Converts a metadata tuple into a datetime metadata C struct. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_datetime_metadata_tuple_to_datetime_metadata(PyObject *tuple, + PyArray_DatetimeMetaData *out_meta, + npy_bool from_pickle); + +/* + * Gets a tzoffset in minutes by calling the fromutc() function on + * the Python datetime.tzinfo object. + */ +NPY_NO_EXPORT int +get_tzoffset_from_pytzinfo(PyObject *timezone, npy_datetimestruct *dts); + +/* + * Converts an input object into datetime metadata. The input + * may be either a string or a tuple. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_pyobject_to_datetime_metadata(PyObject *obj, + PyArray_DatetimeMetaData *out_meta); + +/* + * 'ret' is a PyUString containing the datetime string, and this + * function appends the metadata string to it. + * + * If 'skip_brackets' is true, skips the '[]'. + * + * This function steals the reference 'ret' + */ +NPY_NO_EXPORT PyObject * +append_metastr_to_string(PyArray_DatetimeMetaData *meta, + int skip_brackets, + PyObject *ret); + +/* + * Tests for and converts a Python datetime.datetime or datetime.date + * object into a NumPy npy_datetimestruct. + * + * 'out_bestunit' gives a suggested unit based on whether the object + * was a datetime.date or datetime.datetime object. + * + * If 'apply_tzinfo' is 1, this function uses the tzinfo to convert + * to UTC time, otherwise it returns the struct with the local time. + * + * Returns -1 on error, 0 on success, and 1 (with no error set) + * if obj doesn't have the needed date or datetime attributes. + */ +NPY_NO_EXPORT int +convert_pydatetime_to_datetimestruct(PyObject *obj, npy_datetimestruct *out, + NPY_DATETIMEUNIT *out_bestunit, + int apply_tzinfo); + +/* + * Converts a PyObject * into a datetime, in any of the forms supported. + * + * If the units metadata isn't known ahead of time, set meta->base + * to -1, and this function will populate meta with either default + * values or values from the input object. + * + * The 'casting' parameter is used to control what kinds of inputs + * are accepted, and what happens. For example, with 'unsafe' casting, + * unrecognized inputs are converted to 'NaT' instead of throwing an error, + * while with 'safe' casting an error will be thrown if any precision + * from the input will be thrown away. + * + * Returns -1 on error, 0 on success. + */ +NPY_NO_EXPORT int +convert_pyobject_to_datetime(PyArray_DatetimeMetaData *meta, PyObject *obj, + NPY_CASTING casting, npy_datetime *out); + +/* + * Converts a PyObject * into a timedelta, in any of the forms supported + * + * If the units metadata isn't known ahead of time, set meta->base + * to -1, and this function will populate meta with either default + * values or values from the input object. + * + * The 'casting' parameter is used to control what kinds of inputs + * are accepted, and what happens. For example, with 'unsafe' casting, + * unrecognized inputs are converted to 'NaT' instead of throwing an error, + * while with 'safe' casting an error will be thrown if any precision + * from the input will be thrown away. + * + * Returns -1 on error, 0 on success. + */ +NPY_NO_EXPORT int +convert_pyobject_to_timedelta(PyArray_DatetimeMetaData *meta, PyObject *obj, + NPY_CASTING casting, npy_timedelta *out); + +/* + * Converts a datetime into a PyObject *. + * + * For days or coarser, returns a datetime.date. + * For microseconds or coarser, returns a datetime.datetime. + * For units finer than microseconds, returns an integer. + */ +NPY_NO_EXPORT PyObject * +convert_datetime_to_pyobject(npy_datetime dt, PyArray_DatetimeMetaData *meta); + +/* + * Converts a timedelta into a PyObject *. + * + * Not-a-time is returned as the string "NaT". + * For microseconds or coarser, returns a datetime.timedelta. + * For units finer than microseconds, returns an integer. + */ +NPY_NO_EXPORT PyObject * +convert_timedelta_to_pyobject(npy_timedelta td, PyArray_DatetimeMetaData *meta); + +/* + * Converts a datetime based on the given metadata into a datetimestruct + */ +NPY_NO_EXPORT int +convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta, + npy_datetime dt, + npy_datetimestruct *out); + +/* + * Converts a datetime from a datetimestruct to a datetime based + * on some metadata. The date is assumed to be valid. + * + * TODO: If meta->num is really big, there could be overflow + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_datetimestruct_to_datetime(PyArray_DatetimeMetaData *meta, + const npy_datetimestruct *dts, + npy_datetime *out); + +/* + * Adjusts a datetimestruct based on a seconds offset. Assumes + * the current values are valid. + */ +NPY_NO_EXPORT void +add_seconds_to_datetimestruct(npy_datetimestruct *dts, int seconds); + +/* + * Adjusts a datetimestruct based on a minutes offset. Assumes + * the current values are valid. + */ +NPY_NO_EXPORT void +add_minutes_to_datetimestruct(npy_datetimestruct *dts, int minutes); + +/* + * Returns true if the datetime metadata matches + */ +NPY_NO_EXPORT npy_bool +has_equivalent_datetime_metadata(PyArray_Descr *type1, PyArray_Descr *type2); + +/* + * Casts a single datetime from having src_meta metadata into + * dst_meta metadata. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +cast_datetime_to_datetime(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + npy_datetime src_dt, + npy_datetime *dst_dt); + +/* + * Casts a single timedelta from having src_meta metadata into + * dst_meta metadata. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +cast_timedelta_to_timedelta(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + npy_timedelta src_dt, + npy_timedelta *dst_dt); + +/* + * Returns true if the object is something that is best considered + * a Datetime or Timedelta, false otherwise. + */ +NPY_NO_EXPORT npy_bool +is_any_numpy_datetime_or_timedelta(PyObject *obj); + +/* + * Implements a datetime-specific arange + */ +NPY_NO_EXPORT PyArrayObject * +datetime_arange(PyObject *start, PyObject *stop, PyObject *step, + PyArray_Descr *dtype); + +/* + * Examines all the objects in the given Python object by + * recursively descending the sequence structure. Returns a + * datetime or timedelta type with metadata based on the data. + */ +NPY_NO_EXPORT PyArray_Descr * +find_object_datetime_type(PyObject *obj, int type_num); + +#endif diff --git a/numpy/core/src/multiarray/alloc.c b/numpy/core/src/multiarray/alloc.c new file mode 100644 index 0000000..f8305d1 --- /dev/null +++ b/numpy/core/src/multiarray/alloc.c @@ -0,0 +1,279 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#if PY_VERSION_HEX >= 0x03060000 +#include +/* public api in 3.7 */ +#if PY_VERSION_HEX < 0x03070000 +#define PyTraceMalloc_Track _PyTraceMalloc_Track +#define PyTraceMalloc_Untrack _PyTraceMalloc_Untrack +#endif +#else +#define PyTraceMalloc_Track(...) +#define PyTraceMalloc_Untrack(...) +#endif + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include +#include "numpy/arrayobject.h" +#include +#include "npy_config.h" +#include "alloc.h" + +#include + +#define NBUCKETS 1024 /* number of buckets for data*/ +#define NBUCKETS_DIM 16 /* number of buckets for dimensions/strides */ +#define NCACHE 7 /* number of cache entries per bucket */ +/* this structure fits neatly into a cacheline */ +typedef struct { + npy_uintp available; /* number of cached pointers */ + void * ptrs[NCACHE]; +} cache_bucket; +static cache_bucket datacache[NBUCKETS]; +static cache_bucket dimcache[NBUCKETS_DIM]; + +/* + * very simplistic small memory block cache to avoid more expensive libc + * allocations + * base function for data cache with 1 byte buckets and dimension cache with + * sizeof(npy_intp) byte buckets + */ +static NPY_INLINE void * +_npy_alloc_cache(npy_uintp nelem, npy_uintp esz, npy_uint msz, + cache_bucket * cache, void * (*alloc)(size_t)) +{ + assert((esz == 1 && cache == datacache) || + (esz == sizeof(npy_intp) && cache == dimcache)); + if (nelem < msz) { + if (cache[nelem].available > 0) { + return cache[nelem].ptrs[--(cache[nelem].available)]; + } + } +#ifdef _PyPyGC_AddMemoryPressure + { + size_t size = nelem * esz; + void * ret = alloc(size); + if (ret != NULL) + { + _PyPyPyGC_AddMemoryPressure(size); + } + return ret; + } +#else + return alloc(nelem * esz); +#endif +} + +/* + * return pointer p to cache, nelem is number of elements of the cache bucket + * size (1 or sizeof(npy_intp)) of the block pointed too + */ +static NPY_INLINE void +_npy_free_cache(void * p, npy_uintp nelem, npy_uint msz, + cache_bucket * cache, void (*dealloc)(void *)) +{ + if (p != NULL && nelem < msz) { + if (cache[nelem].available < NCACHE) { + cache[nelem].ptrs[cache[nelem].available++] = p; + return; + } + } + dealloc(p); +} + + +/* + * array data cache, sz is number of bytes to allocate + */ +NPY_NO_EXPORT void * +npy_alloc_cache(npy_uintp sz) +{ + return _npy_alloc_cache(sz, 1, NBUCKETS, datacache, &PyDataMem_NEW); +} + +/* zero initialized data, sz is number of bytes to allocate */ +NPY_NO_EXPORT void * +npy_alloc_cache_zero(npy_uintp sz) +{ + void * p; + NPY_BEGIN_THREADS_DEF; + if (sz < NBUCKETS) { + p = _npy_alloc_cache(sz, 1, NBUCKETS, datacache, &PyDataMem_NEW); + if (p) { + memset(p, 0, sz); + } + return p; + } + NPY_BEGIN_THREADS; + p = PyDataMem_NEW_ZEROED(sz, 1); + NPY_END_THREADS; + return p; +} + +NPY_NO_EXPORT void +npy_free_cache(void * p, npy_uintp sz) +{ + _npy_free_cache(p, sz, NBUCKETS, datacache, &PyDataMem_FREE); +} + +/* + * dimension/stride cache, uses a different allocator and is always a multiple + * of npy_intp + */ +NPY_NO_EXPORT void * +npy_alloc_cache_dim(npy_uintp sz) +{ + /* + * make sure any temporary allocation can be used for array metadata which + * uses one memory block for both dimensions and strides + */ + if (sz < 2) { + sz = 2; + } + return _npy_alloc_cache(sz, sizeof(npy_intp), NBUCKETS_DIM, dimcache, + &PyArray_malloc); +} + +NPY_NO_EXPORT void +npy_free_cache_dim(void * p, npy_uintp sz) +{ + /* see npy_alloc_cache_dim */ + if (sz < 2) { + sz = 2; + } + _npy_free_cache(p, sz, NBUCKETS_DIM, dimcache, + &PyArray_free); +} + + +/* malloc/free/realloc hook */ +NPY_NO_EXPORT PyDataMem_EventHookFunc *_PyDataMem_eventhook; +NPY_NO_EXPORT void *_PyDataMem_eventhook_user_data; + +/*NUMPY_API + * Sets the allocation event hook for numpy array data. + * Takes a PyDataMem_EventHookFunc *, which has the signature: + * void hook(void *old, void *new, size_t size, void *user_data). + * Also takes a void *user_data, and void **old_data. + * + * Returns a pointer to the previous hook or NULL. If old_data is + * non-NULL, the previous user_data pointer will be copied to it. + * + * If not NULL, hook will be called at the end of each PyDataMem_NEW/FREE/RENEW: + * result = PyDataMem_NEW(size) -> (*hook)(NULL, result, size, user_data) + * PyDataMem_FREE(ptr) -> (*hook)(ptr, NULL, 0, user_data) + * result = PyDataMem_RENEW(ptr, size) -> (*hook)(ptr, result, size, user_data) + * + * When the hook is called, the GIL will be held by the calling + * thread. The hook should be written to be reentrant, if it performs + * operations that might cause new allocation events (such as the + * creation/destruction numpy objects, or creating/destroying Python + * objects which might cause a gc) + */ +NPY_NO_EXPORT PyDataMem_EventHookFunc * +PyDataMem_SetEventHook(PyDataMem_EventHookFunc *newhook, + void *user_data, void **old_data) +{ + PyDataMem_EventHookFunc *temp; + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API + temp = _PyDataMem_eventhook; + _PyDataMem_eventhook = newhook; + if (old_data != NULL) { + *old_data = _PyDataMem_eventhook_user_data; + } + _PyDataMem_eventhook_user_data = user_data; + NPY_DISABLE_C_API + return temp; +} + +/*NUMPY_API + * Allocates memory for array data. + */ +NPY_NO_EXPORT void * +PyDataMem_NEW(size_t size) +{ + void *result; + + result = malloc(size); + if (_PyDataMem_eventhook != NULL) { + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API + if (_PyDataMem_eventhook != NULL) { + (*_PyDataMem_eventhook)(NULL, result, size, + _PyDataMem_eventhook_user_data); + } + NPY_DISABLE_C_API + } + PyTraceMalloc_Track(NPY_TRACE_DOMAIN, (npy_uintp)result, size); + return result; +} + +/*NUMPY_API + * Allocates zeroed memory for array data. + */ +NPY_NO_EXPORT void * +PyDataMem_NEW_ZEROED(size_t size, size_t elsize) +{ + void *result; + + result = calloc(size, elsize); + if (_PyDataMem_eventhook != NULL) { + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API + if (_PyDataMem_eventhook != NULL) { + (*_PyDataMem_eventhook)(NULL, result, size * elsize, + _PyDataMem_eventhook_user_data); + } + NPY_DISABLE_C_API + } + PyTraceMalloc_Track(NPY_TRACE_DOMAIN, (npy_uintp)result, size); + return result; +} + +/*NUMPY_API + * Free memory for array data. + */ +NPY_NO_EXPORT void +PyDataMem_FREE(void *ptr) +{ + PyTraceMalloc_Untrack(NPY_TRACE_DOMAIN, (npy_uintp)ptr); + free(ptr); + if (_PyDataMem_eventhook != NULL) { + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API + if (_PyDataMem_eventhook != NULL) { + (*_PyDataMem_eventhook)(ptr, NULL, 0, + _PyDataMem_eventhook_user_data); + } + NPY_DISABLE_C_API + } +} + +/*NUMPY_API + * Reallocate/resize memory for array data. + */ +NPY_NO_EXPORT void * +PyDataMem_RENEW(void *ptr, size_t size) +{ + void *result; + + result = realloc(ptr, size); + if (result != ptr) { + PyTraceMalloc_Untrack(NPY_TRACE_DOMAIN, (npy_uintp)ptr); + } + PyTraceMalloc_Track(NPY_TRACE_DOMAIN, (npy_uintp)result, size); + if (_PyDataMem_eventhook != NULL) { + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API + if (_PyDataMem_eventhook != NULL) { + (*_PyDataMem_eventhook)(ptr, result, size, + _PyDataMem_eventhook_user_data); + } + NPY_DISABLE_C_API + } + return result; +} diff --git a/numpy/core/src/multiarray/alloc.h b/numpy/core/src/multiarray/alloc.h new file mode 100644 index 0000000..2b69efc --- /dev/null +++ b/numpy/core/src/multiarray/alloc.h @@ -0,0 +1,36 @@ +#ifndef _NPY_ARRAY_ALLOC_H_ +#define _NPY_ARRAY_ALLOC_H_ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#define NPY_TRACE_DOMAIN 389047 + +NPY_NO_EXPORT void * +npy_alloc_cache(npy_uintp sz); + +NPY_NO_EXPORT void * +npy_alloc_cache_zero(npy_uintp sz); + +NPY_NO_EXPORT void +npy_free_cache(void * p, npy_uintp sd); + +NPY_NO_EXPORT void * +npy_alloc_cache_dim(npy_uintp sz); + +NPY_NO_EXPORT void +npy_free_cache_dim(void * p, npy_uintp sd); + +static NPY_INLINE void +npy_free_cache_dim_obj(PyArray_Dims dims) +{ + npy_free_cache_dim(dims.ptr, dims.len); +} + +static NPY_INLINE void +npy_free_cache_dim_array(PyArrayObject * arr) +{ + npy_free_cache_dim(PyArray_DIMS(arr), PyArray_NDIM(arr)); +} + +#endif diff --git a/numpy/core/src/multiarray/array_assign.c b/numpy/core/src/multiarray/array_assign.c new file mode 100644 index 0000000..a48e245 --- /dev/null +++ b/numpy/core/src/multiarray/array_assign.c @@ -0,0 +1,118 @@ +/* + * This file implements some helper functions for the array assignment + * routines. The actual assignment routines are in array_assign_*.c + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "shape.h" + +#include "array_assign.h" +#include "common.h" +#include "lowlevel_strided_loops.h" +#include "mem_overlap.h" + +/* See array_assign.h for parameter documentation */ +NPY_NO_EXPORT int +broadcast_strides(int ndim, npy_intp *shape, + int strides_ndim, npy_intp *strides_shape, npy_intp *strides, + char *strides_name, + npy_intp *out_strides) +{ + int idim, idim_start = ndim - strides_ndim; + + /* Can't broadcast to fewer dimensions */ + if (idim_start < 0) { + goto broadcast_error; + } + + /* + * Process from the end to the start, so that 'strides' and 'out_strides' + * can point to the same memory. + */ + for (idim = ndim - 1; idim >= idim_start; --idim) { + npy_intp strides_shape_value = strides_shape[idim - idim_start]; + /* If it doesn't have dimension one, it must match */ + if (strides_shape_value == 1) { + out_strides[idim] = 0; + } + else if (strides_shape_value != shape[idim]) { + goto broadcast_error; + } + else { + out_strides[idim] = strides[idim - idim_start]; + } + } + + /* New dimensions get a zero stride */ + for (idim = 0; idim < idim_start; ++idim) { + out_strides[idim] = 0; + } + + return 0; + +broadcast_error: { + PyObject *errmsg; + + errmsg = PyUString_FromFormat("could not broadcast %s from shape ", + strides_name); + PyUString_ConcatAndDel(&errmsg, + build_shape_string(strides_ndim, strides_shape)); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" into shape ")); + PyUString_ConcatAndDel(&errmsg, + build_shape_string(ndim, shape)); + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + + return -1; + } +} + +/* See array_assign.h for parameter documentation */ +NPY_NO_EXPORT int +raw_array_is_aligned(int ndim, char *data, npy_intp *strides, int alignment) +{ + if (alignment > 1) { + npy_intp align_check = (npy_intp)data; + int idim; + + for (idim = 0; idim < ndim; ++idim) { + align_check |= strides[idim]; + } + + return npy_is_aligned((void *)align_check, alignment); + } + else { + return 1; + } +} + + +/* Returns 1 if the arrays have overlapping data, 0 otherwise */ +NPY_NO_EXPORT int +arrays_overlap(PyArrayObject *arr1, PyArrayObject *arr2) +{ + mem_overlap_t result; + + result = solve_may_share_memory(arr1, arr2, NPY_MAY_SHARE_BOUNDS); + if (result == MEM_OVERLAP_NO) { + return 0; + } + else { + return 1; + } +} diff --git a/numpy/core/src/multiarray/array_assign.h b/numpy/core/src/multiarray/array_assign.h new file mode 100644 index 0000000..3fecff0 --- /dev/null +++ b/numpy/core/src/multiarray/array_assign.h @@ -0,0 +1,100 @@ +#ifndef _NPY_PRIVATE__ARRAY_ASSIGN_H_ +#define _NPY_PRIVATE__ARRAY_ASSIGN_H_ + +/* + * An array assignment function for copying arrays, treating the + * arrays as flat according to their respective ordering rules. + * This function makes a temporary copy of 'src' if 'src' and + * 'dst' overlap, to be able to handle views of the same data with + * different strides. + * + * dst: The destination array. + * dst_order: The rule for how 'dst' is to be made flat. + * src: The source array. + * src_order: The rule for how 'src' is to be made flat. + * casting: An exception is raised if the copy violates this + * casting rule. + * + * Returns 0 on success, -1 on failure. + */ +/* Not yet implemented +NPY_NO_EXPORT int +PyArray_AssignArrayAsFlat(PyArrayObject *dst, NPY_ORDER dst_order, + PyArrayObject *src, NPY_ORDER src_order, + NPY_CASTING casting, + npy_bool preservena, npy_bool *preservewhichna); +*/ + +NPY_NO_EXPORT int +PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src, + PyArrayObject *wheremask, + NPY_CASTING casting); + +NPY_NO_EXPORT int +PyArray_AssignRawScalar(PyArrayObject *dst, + PyArray_Descr *src_dtype, char *src_data, + PyArrayObject *wheremask, + NPY_CASTING casting); + +/******** LOW-LEVEL SCALAR TO ARRAY ASSIGNMENT ********/ + +/* + * Assigns the scalar value to every element of the destination raw array. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +raw_array_assign_scalar(int ndim, npy_intp *shape, + PyArray_Descr *dst_dtype, char *dst_data, npy_intp *dst_strides, + PyArray_Descr *src_dtype, char *src_data); + +/* + * Assigns the scalar value to every element of the destination raw array + * where the 'wheremask' value is True. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +raw_array_wheremasked_assign_scalar(int ndim, npy_intp *shape, + PyArray_Descr *dst_dtype, char *dst_data, npy_intp *dst_strides, + PyArray_Descr *src_dtype, char *src_data, + PyArray_Descr *wheremask_dtype, char *wheremask_data, + npy_intp *wheremask_strides); + +/******** LOW-LEVEL ARRAY MANIPULATION HELPERS ********/ + +/* + * Internal detail of how much to buffer during array assignments which + * need it. This is for more complex NA masking operations where masks + * need to be inverted or combined together. + */ +#define NPY_ARRAY_ASSIGN_BUFFERSIZE 8192 + +/* + * Broadcasts strides to match the given dimensions. Can be used, + * for instance, to set up a raw iteration. + * + * 'strides_name' is used to produce an error message if the strides + * cannot be broadcast. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +broadcast_strides(int ndim, npy_intp *shape, + int strides_ndim, npy_intp *strides_shape, npy_intp *strides, + char *strides_name, + npy_intp *out_strides); + +/* + * Checks whether a data pointer + set of strides refers to a raw + * array which is fully aligned data. + */ +NPY_NO_EXPORT int +raw_array_is_aligned(int ndim, char *data, npy_intp *strides, int alignment); + +/* Returns 1 if the arrays have overlapping data, 0 otherwise */ +NPY_NO_EXPORT int +arrays_overlap(PyArrayObject *arr1, PyArrayObject *arr2); + + +#endif diff --git a/numpy/core/src/multiarray/array_assign_array.c b/numpy/core/src/multiarray/array_assign_array.c new file mode 100644 index 0000000..74fbb88 --- /dev/null +++ b/numpy/core/src/multiarray/array_assign_array.c @@ -0,0 +1,406 @@ +/* + * This file implements assignment from an ndarray to another ndarray. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "convert_datatype.h" +#include "methods.h" +#include "shape.h" +#include "lowlevel_strided_loops.h" + +#include "array_assign.h" + +/* + * Assigns the array from 'src' to 'dst'. The strides must already have + * been broadcast. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +raw_array_assign_array(int ndim, npy_intp *shape, + PyArray_Descr *dst_dtype, char *dst_data, npy_intp *dst_strides, + PyArray_Descr *src_dtype, char *src_data, npy_intp *src_strides) +{ + int idim; + npy_intp shape_it[NPY_MAXDIMS]; + npy_intp dst_strides_it[NPY_MAXDIMS]; + npy_intp src_strides_it[NPY_MAXDIMS]; + npy_intp coord[NPY_MAXDIMS]; + + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + int aligned, needs_api = 0; + npy_intp src_itemsize = src_dtype->elsize; + + NPY_BEGIN_THREADS_DEF; + + /* Check alignment */ + aligned = raw_array_is_aligned(ndim, + dst_data, dst_strides, dst_dtype->alignment) && + raw_array_is_aligned(ndim, + src_data, src_strides, src_dtype->alignment); + + /* Use raw iteration with no heap allocation */ + if (PyArray_PrepareTwoRawArrayIter( + ndim, shape, + dst_data, dst_strides, + src_data, src_strides, + &ndim, shape_it, + &dst_data, dst_strides_it, + &src_data, src_strides_it) < 0) { + return -1; + } + + /* + * Overlap check for the 1D case. Higher dimensional arrays and + * opposite strides cause a temporary copy before getting here. + */ + if (ndim == 1 && src_data < dst_data && + src_data + shape_it[0] * src_strides_it[0] > dst_data) { + src_data += (shape_it[0] - 1) * src_strides_it[0]; + dst_data += (shape_it[0] - 1) * dst_strides_it[0]; + src_strides_it[0] = -src_strides_it[0]; + dst_strides_it[0] = -dst_strides_it[0]; + } + + /* Get the function to do the casting */ + if (PyArray_GetDTypeTransferFunction(aligned, + src_strides_it[0], dst_strides_it[0], + src_dtype, dst_dtype, + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + return -1; + } + + if (!needs_api) { + NPY_BEGIN_THREADS; + } + + NPY_RAW_ITER_START(idim, ndim, coord, shape_it) { + /* Process the innermost dimension */ + stransfer(dst_data, dst_strides_it[0], src_data, src_strides_it[0], + shape_it[0], src_itemsize, transferdata); + } NPY_RAW_ITER_TWO_NEXT(idim, ndim, coord, shape_it, + dst_data, dst_strides_it, + src_data, src_strides_it); + + NPY_END_THREADS; + + NPY_AUXDATA_FREE(transferdata); + + return (needs_api && PyErr_Occurred()) ? -1 : 0; +} + +/* + * Assigns the array from 'src' to 'dst, wherever the 'wheremask' + * value is True. The strides must already have been broadcast. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +raw_array_wheremasked_assign_array(int ndim, npy_intp *shape, + PyArray_Descr *dst_dtype, char *dst_data, npy_intp *dst_strides, + PyArray_Descr *src_dtype, char *src_data, npy_intp *src_strides, + PyArray_Descr *wheremask_dtype, char *wheremask_data, + npy_intp *wheremask_strides) +{ + int idim; + npy_intp shape_it[NPY_MAXDIMS]; + npy_intp dst_strides_it[NPY_MAXDIMS]; + npy_intp src_strides_it[NPY_MAXDIMS]; + npy_intp wheremask_strides_it[NPY_MAXDIMS]; + npy_intp coord[NPY_MAXDIMS]; + + PyArray_MaskedStridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + int aligned, needs_api = 0; + npy_intp src_itemsize = src_dtype->elsize; + + NPY_BEGIN_THREADS_DEF; + + /* Check alignment */ + aligned = raw_array_is_aligned(ndim, + dst_data, dst_strides, dst_dtype->alignment) && + raw_array_is_aligned(ndim, + src_data, src_strides, src_dtype->alignment); + + /* Use raw iteration with no heap allocation */ + if (PyArray_PrepareThreeRawArrayIter( + ndim, shape, + dst_data, dst_strides, + src_data, src_strides, + wheremask_data, wheremask_strides, + &ndim, shape_it, + &dst_data, dst_strides_it, + &src_data, src_strides_it, + &wheremask_data, wheremask_strides_it) < 0) { + return -1; + } + + /* + * Overlap check for the 1D case. Higher dimensional arrays cause + * a temporary copy before getting here. + */ + if (ndim == 1 && src_data < dst_data && + src_data + shape_it[0] * src_strides_it[0] > dst_data) { + src_data += (shape_it[0] - 1) * src_strides_it[0]; + dst_data += (shape_it[0] - 1) * dst_strides_it[0]; + wheremask_data += (shape_it[0] - 1) * wheremask_strides_it[0]; + src_strides_it[0] = -src_strides_it[0]; + dst_strides_it[0] = -dst_strides_it[0]; + wheremask_strides_it[0] = -wheremask_strides_it[0]; + } + + /* Get the function to do the casting */ + if (PyArray_GetMaskedDTypeTransferFunction(aligned, + src_strides_it[0], + dst_strides_it[0], + wheremask_strides_it[0], + src_dtype, dst_dtype, wheremask_dtype, + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + return -1; + } + + if (!needs_api) { + NPY_BEGIN_THREADS; + } + + NPY_RAW_ITER_START(idim, ndim, coord, shape_it) { + /* Process the innermost dimension */ + stransfer(dst_data, dst_strides_it[0], src_data, src_strides_it[0], + (npy_bool *)wheremask_data, wheremask_strides_it[0], + shape_it[0], src_itemsize, transferdata); + } NPY_RAW_ITER_THREE_NEXT(idim, ndim, coord, shape_it, + dst_data, dst_strides_it, + src_data, src_strides_it, + wheremask_data, wheremask_strides_it); + + NPY_END_THREADS; + + NPY_AUXDATA_FREE(transferdata); + + return (needs_api && PyErr_Occurred()) ? -1 : 0; +} + +/* + * An array assignment function for copying arrays, broadcasting 'src' into + * 'dst'. This function makes a temporary copy of 'src' if 'src' and + * 'dst' overlap, to be able to handle views of the same data with + * different strides. + * + * dst: The destination array. + * src: The source array. + * wheremask: If non-NULL, a boolean mask specifying where to copy. + * casting: An exception is raised if the copy violates this + * casting rule. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src, + PyArrayObject *wheremask, + NPY_CASTING casting) +{ + int copied_src = 0; + + npy_intp src_strides[NPY_MAXDIMS]; + + /* Use array_assign_scalar if 'src' NDIM is 0 */ + if (PyArray_NDIM(src) == 0) { + return PyArray_AssignRawScalar( + dst, PyArray_DESCR(src), PyArray_DATA(src), + wheremask, casting); + } + + /* + * Performance fix for expressions like "a[1000:6000] += x". In this + * case, first an in-place add is done, followed by an assignment, + * equivalently expressed like this: + * + * tmp = a[1000:6000] # Calls array_subscript in mapping.c + * np.add(tmp, x, tmp) + * a[1000:6000] = tmp # Calls array_assign_subscript in mapping.c + * + * In the assignment the underlying data type, shape, strides, and + * data pointers are identical, but src != dst because they are separately + * generated slices. By detecting this and skipping the redundant + * copy of values to themselves, we potentially give a big speed boost. + * + * Note that we don't call EquivTypes, because usually the exact same + * dtype object will appear, and we don't want to slow things down + * with a complicated comparison. The comparisons are ordered to + * try and reject this with as little work as possible. + */ + if (PyArray_DATA(src) == PyArray_DATA(dst) && + PyArray_DESCR(src) == PyArray_DESCR(dst) && + PyArray_NDIM(src) == PyArray_NDIM(dst) && + PyArray_CompareLists(PyArray_DIMS(src), + PyArray_DIMS(dst), + PyArray_NDIM(src)) && + PyArray_CompareLists(PyArray_STRIDES(src), + PyArray_STRIDES(dst), + PyArray_NDIM(src))) { + /*printf("Redundant copy operation detected\n");*/ + return 0; + } + + if (PyArray_FailUnlessWriteable(dst, "assignment destination") < 0) { + goto fail; + } + + /* Check the casting rule */ + if (!PyArray_CanCastTypeTo(PyArray_DESCR(src), + PyArray_DESCR(dst), casting)) { + PyObject *errmsg; + errmsg = PyUString_FromString("Cannot cast scalar from "); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(src))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(dst))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" according to the rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + goto fail; + } + + /* + * When ndim is 1 and the strides point in the same direction, + * the lower-level inner loop handles copying + * of overlapping data. For bigger ndim and opposite-strided 1D + * data, we make a temporary copy of 'src' if 'src' and 'dst' overlap.' + */ + if (((PyArray_NDIM(dst) == 1 && PyArray_NDIM(src) >= 1 && + PyArray_STRIDES(dst)[0] * + PyArray_STRIDES(src)[PyArray_NDIM(src) - 1] < 0) || + PyArray_NDIM(dst) > 1 || PyArray_HASFIELDS(dst)) && + arrays_overlap(src, dst)) { + PyArrayObject *tmp; + + /* + * Allocate a temporary copy array. + */ + tmp = (PyArrayObject *)PyArray_NewLikeArray(dst, + NPY_KEEPORDER, NULL, 0); + if (tmp == NULL) { + goto fail; + } + + if (PyArray_AssignArray(tmp, src, NULL, NPY_UNSAFE_CASTING) < 0) { + Py_DECREF(tmp); + goto fail; + } + + src = tmp; + copied_src = 1; + } + + /* Broadcast 'src' to 'dst' for raw iteration */ + if (PyArray_NDIM(src) > PyArray_NDIM(dst)) { + int ndim_tmp = PyArray_NDIM(src); + npy_intp *src_shape_tmp = PyArray_DIMS(src); + npy_intp *src_strides_tmp = PyArray_STRIDES(src); + /* + * As a special case for backwards compatibility, strip + * away unit dimensions from the left of 'src' + */ + while (ndim_tmp > PyArray_NDIM(dst) && src_shape_tmp[0] == 1) { + --ndim_tmp; + ++src_shape_tmp; + ++src_strides_tmp; + } + + if (broadcast_strides(PyArray_NDIM(dst), PyArray_DIMS(dst), + ndim_tmp, src_shape_tmp, + src_strides_tmp, "input array", + src_strides) < 0) { + goto fail; + } + } + else { + if (broadcast_strides(PyArray_NDIM(dst), PyArray_DIMS(dst), + PyArray_NDIM(src), PyArray_DIMS(src), + PyArray_STRIDES(src), "input array", + src_strides) < 0) { + goto fail; + } + } + + /* optimization: scalar boolean mask */ + if (wheremask != NULL && + PyArray_NDIM(wheremask) == 0 && + PyArray_DESCR(wheremask)->type_num == NPY_BOOL) { + npy_bool value = *(npy_bool *)PyArray_DATA(wheremask); + if (value) { + /* where=True is the same as no where at all */ + wheremask = NULL; + } + else { + /* where=False copies nothing */ + return 0; + } + } + + if (wheremask == NULL) { + /* A straightforward value assignment */ + /* Do the assignment with raw array iteration */ + if (raw_array_assign_array(PyArray_NDIM(dst), PyArray_DIMS(dst), + PyArray_DESCR(dst), PyArray_DATA(dst), PyArray_STRIDES(dst), + PyArray_DESCR(src), PyArray_DATA(src), src_strides) < 0) { + goto fail; + } + } + else { + npy_intp wheremask_strides[NPY_MAXDIMS]; + + /* Broadcast the wheremask to 'dst' for raw iteration */ + if (broadcast_strides(PyArray_NDIM(dst), PyArray_DIMS(dst), + PyArray_NDIM(wheremask), PyArray_DIMS(wheremask), + PyArray_STRIDES(wheremask), "where mask", + wheremask_strides) < 0) { + goto fail; + } + + /* A straightforward where-masked assignment */ + /* Do the masked assignment with raw array iteration */ + if (raw_array_wheremasked_assign_array( + PyArray_NDIM(dst), PyArray_DIMS(dst), + PyArray_DESCR(dst), PyArray_DATA(dst), PyArray_STRIDES(dst), + PyArray_DESCR(src), PyArray_DATA(src), src_strides, + PyArray_DESCR(wheremask), PyArray_DATA(wheremask), + wheremask_strides) < 0) { + goto fail; + } + } + + if (copied_src) { + Py_DECREF(src); + } + return 0; + +fail: + if (copied_src) { + Py_DECREF(src); + } + return -1; +} diff --git a/numpy/core/src/multiarray/array_assign_scalar.c b/numpy/core/src/multiarray/array_assign_scalar.c new file mode 100644 index 0000000..7c1b1f1 --- /dev/null +++ b/numpy/core/src/multiarray/array_assign_scalar.c @@ -0,0 +1,302 @@ +/* + * This file implements assignment from a scalar to an ndarray. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "convert_datatype.h" +#include "methods.h" +#include "shape.h" +#include "lowlevel_strided_loops.h" + +#include "array_assign.h" + +/* + * Assigns the scalar value to every element of the destination raw array. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +raw_array_assign_scalar(int ndim, npy_intp *shape, + PyArray_Descr *dst_dtype, char *dst_data, npy_intp *dst_strides, + PyArray_Descr *src_dtype, char *src_data) +{ + int idim; + npy_intp shape_it[NPY_MAXDIMS], dst_strides_it[NPY_MAXDIMS]; + npy_intp coord[NPY_MAXDIMS]; + + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + int aligned, needs_api = 0; + npy_intp src_itemsize = src_dtype->elsize; + + NPY_BEGIN_THREADS_DEF; + + /* Check alignment */ + aligned = raw_array_is_aligned(ndim, dst_data, dst_strides, + dst_dtype->alignment); + if (!npy_is_aligned(src_data, src_dtype->alignment)) { + aligned = 0; + } + + /* Use raw iteration with no heap allocation */ + if (PyArray_PrepareOneRawArrayIter( + ndim, shape, + dst_data, dst_strides, + &ndim, shape_it, + &dst_data, dst_strides_it) < 0) { + return -1; + } + + /* Get the function to do the casting */ + if (PyArray_GetDTypeTransferFunction(aligned, + 0, dst_strides_it[0], + src_dtype, dst_dtype, + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + return -1; + } + + if (!needs_api) { + npy_intp nitems = 1, i; + for (i = 0; i < ndim; i++) { + nitems *= shape_it[i]; + } + NPY_BEGIN_THREADS_THRESHOLDED(nitems); + } + + NPY_RAW_ITER_START(idim, ndim, coord, shape_it) { + /* Process the innermost dimension */ + stransfer(dst_data, dst_strides_it[0], src_data, 0, + shape_it[0], src_itemsize, transferdata); + } NPY_RAW_ITER_ONE_NEXT(idim, ndim, coord, + shape_it, dst_data, dst_strides_it); + + NPY_END_THREADS; + + NPY_AUXDATA_FREE(transferdata); + + return (needs_api && PyErr_Occurred()) ? -1 : 0; +} + +/* + * Assigns the scalar value to every element of the destination raw array + * where the 'wheremask' value is True. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +raw_array_wheremasked_assign_scalar(int ndim, npy_intp *shape, + PyArray_Descr *dst_dtype, char *dst_data, npy_intp *dst_strides, + PyArray_Descr *src_dtype, char *src_data, + PyArray_Descr *wheremask_dtype, char *wheremask_data, + npy_intp *wheremask_strides) +{ + int idim; + npy_intp shape_it[NPY_MAXDIMS], dst_strides_it[NPY_MAXDIMS]; + npy_intp wheremask_strides_it[NPY_MAXDIMS]; + npy_intp coord[NPY_MAXDIMS]; + + PyArray_MaskedStridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + int aligned, needs_api = 0; + npy_intp src_itemsize = src_dtype->elsize; + + NPY_BEGIN_THREADS_DEF; + + /* Check alignment */ + aligned = raw_array_is_aligned(ndim, dst_data, dst_strides, + dst_dtype->alignment); + if (!npy_is_aligned(src_data, src_dtype->alignment)) { + aligned = 0; + } + + /* Use raw iteration with no heap allocation */ + if (PyArray_PrepareTwoRawArrayIter( + ndim, shape, + dst_data, dst_strides, + wheremask_data, wheremask_strides, + &ndim, shape_it, + &dst_data, dst_strides_it, + &wheremask_data, wheremask_strides_it) < 0) { + return -1; + } + + /* Get the function to do the casting */ + if (PyArray_GetMaskedDTypeTransferFunction(aligned, + 0, dst_strides_it[0], wheremask_strides_it[0], + src_dtype, dst_dtype, wheremask_dtype, + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + return -1; + } + + if (!needs_api) { + npy_intp nitems = 1, i; + for (i = 0; i < ndim; i++) { + nitems *= shape_it[i]; + } + NPY_BEGIN_THREADS_THRESHOLDED(nitems); + } + + NPY_RAW_ITER_START(idim, ndim, coord, shape_it) { + /* Process the innermost dimension */ + stransfer(dst_data, dst_strides_it[0], src_data, 0, + (npy_bool *)wheremask_data, wheremask_strides_it[0], + shape_it[0], src_itemsize, transferdata); + } NPY_RAW_ITER_TWO_NEXT(idim, ndim, coord, shape_it, + dst_data, dst_strides_it, + wheremask_data, wheremask_strides_it); + + NPY_END_THREADS; + + NPY_AUXDATA_FREE(transferdata); + + return (needs_api && PyErr_Occurred()) ? -1 : 0; +} + +/* + * Assigns a scalar value specified by 'src_dtype' and 'src_data' + * to elements of 'dst'. + * + * dst: The destination array. + * src_dtype: The data type of the source scalar. + * src_data: The memory element of the source scalar. + * wheremask: If non-NULL, a boolean mask specifying where to copy. + * casting: An exception is raised if the assignment violates this + * casting rule. + * + * This function is implemented in array_assign_scalar.c. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_AssignRawScalar(PyArrayObject *dst, + PyArray_Descr *src_dtype, char *src_data, + PyArrayObject *wheremask, + NPY_CASTING casting) +{ + int allocated_src_data = 0; + npy_longlong scalarbuffer[4]; + + if (PyArray_FailUnlessWriteable(dst, "assignment destination") < 0) { + return -1; + } + + /* Check the casting rule */ + if (!can_cast_scalar_to(src_dtype, src_data, + PyArray_DESCR(dst), casting)) { + PyObject *errmsg; + errmsg = PyUString_FromString("Cannot cast scalar from "); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)src_dtype)); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(dst))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" according to the rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } + + /* + * Make a copy of the src data if it's a different dtype than 'dst' + * or isn't aligned, and the destination we're copying to has + * more than one element. To avoid having to manage object lifetimes, + * we also skip this if 'dst' has an object dtype. + */ + if ((!PyArray_EquivTypes(PyArray_DESCR(dst), src_dtype) || + !npy_is_aligned(src_data, src_dtype->alignment)) && + PyArray_SIZE(dst) > 1 && + !PyDataType_REFCHK(PyArray_DESCR(dst))) { + char *tmp_src_data; + + /* + * Use a static buffer to store the aligned/cast version, + * or allocate some memory if more space is needed. + */ + if (sizeof(scalarbuffer) >= PyArray_DESCR(dst)->elsize) { + tmp_src_data = (char *)&scalarbuffer[0]; + } + else { + tmp_src_data = PyArray_malloc(PyArray_DESCR(dst)->elsize); + if (tmp_src_data == NULL) { + PyErr_NoMemory(); + goto fail; + } + allocated_src_data = 1; + } + + if (PyArray_CastRawArrays(1, src_data, tmp_src_data, 0, 0, + src_dtype, PyArray_DESCR(dst), 0) != NPY_SUCCEED) { + src_data = tmp_src_data; + goto fail; + } + + /* Replace src_data/src_dtype */ + src_data = tmp_src_data; + src_dtype = PyArray_DESCR(dst); + } + + if (wheremask == NULL) { + /* A straightforward value assignment */ + /* Do the assignment with raw array iteration */ + if (raw_array_assign_scalar(PyArray_NDIM(dst), PyArray_DIMS(dst), + PyArray_DESCR(dst), PyArray_DATA(dst), PyArray_STRIDES(dst), + src_dtype, src_data) < 0) { + goto fail; + } + } + else { + npy_intp wheremask_strides[NPY_MAXDIMS]; + + /* Broadcast the wheremask to 'dst' for raw iteration */ + if (broadcast_strides(PyArray_NDIM(dst), PyArray_DIMS(dst), + PyArray_NDIM(wheremask), PyArray_DIMS(wheremask), + PyArray_STRIDES(wheremask), "where mask", + wheremask_strides) < 0) { + goto fail; + } + + /* Do the masked assignment with raw array iteration */ + if (raw_array_wheremasked_assign_scalar( + PyArray_NDIM(dst), PyArray_DIMS(dst), + PyArray_DESCR(dst), PyArray_DATA(dst), PyArray_STRIDES(dst), + src_dtype, src_data, + PyArray_DESCR(wheremask), PyArray_DATA(wheremask), + wheremask_strides) < 0) { + goto fail; + } + } + + if (allocated_src_data) { + PyArray_free(src_data); + } + + return 0; + +fail: + if (allocated_src_data) { + PyArray_free(src_data); + } + + return -1; +} diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c new file mode 100644 index 0000000..424c669 --- /dev/null +++ b/numpy/core/src/multiarray/arrayobject.c @@ -0,0 +1,1721 @@ +/* + Provide multidimensional arrays as a basic object type in python. + + Based on Original Numeric implementation + Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu + + with contributions from many Numeric Python developers 1995-2004 + + Heavily modified in 2005 with inspiration from Numarray + + by + + Travis Oliphant, oliphant@ee.byu.edu + Brigham Young University + + +maintainer email: oliphant.travis@ieee.org + + Numarray design (which provided guidance) by + Space Science Telescope Institute + (J. Todd Miller, Perry Greenfield, Rick White) +*/ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +/*#include */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "common.h" + +#include "number.h" +#include "usertypes.h" +#include "arraytypes.h" +#include "scalartypes.h" +#include "arrayobject.h" +#include "ctors.h" +#include "methods.h" +#include "descriptor.h" +#include "iterators.h" +#include "mapping.h" +#include "getset.h" +#include "sequence.h" +#include "buffer.h" +#include "array_assign.h" +#include "alloc.h" +#include "mem_overlap.h" +#include "numpyos.h" +#include "strfuncs.h" + +#include "binop_override.h" + +/*NUMPY_API + Compute the size of an array (in number of items) +*/ +NPY_NO_EXPORT npy_intp +PyArray_Size(PyObject *op) +{ + if (PyArray_Check(op)) { + return PyArray_SIZE((PyArrayObject *)op); + } + else { + return 0; + } +} + +/*NUMPY_API + * + * Precondition: 'arr' is a copy of 'base' (though possibly with different + * strides, ordering, etc.). This function sets the UPDATEIFCOPY flag and the + * ->base pointer on 'arr', so that when 'arr' is destructed, it will copy any + * changes back to 'base'. DEPRECATED, use PyArray_SetWritebackIfCopyBase + * + * Steals a reference to 'base'. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_SetUpdateIfCopyBase(PyArrayObject *arr, PyArrayObject *base) +{ + int ret; +#ifdef PYPY_VERSION + #ifndef DEPRECATE_UPDATEIFCOPY + #define DEPRECATE_UPDATEIFCOPY + #endif +#endif + +#ifdef DEPRECATE_UPDATEIFCOPY + /* TODO: enable this once a solution for UPDATEIFCOPY + * and nditer are resolved, also pending the fix for GH7054 + */ + /* 2017-Nov-10 1.14 */ + if (DEPRECATE("PyArray_SetUpdateIfCopyBase is deprecated, use " + "PyArray_SetWritebackIfCopyBase instead, and be sure to call " + "PyArray_ResolveWritebackIfCopy before the array is deallocated, " + "i.e. before the last call to Py_DECREF. If cleaning up from an " + "error, PyArray_DiscardWritebackIfCopy may be called instead to " + "throw away the scratch buffer.") < 0) + return -1; +#endif + ret = PyArray_SetWritebackIfCopyBase(arr, base); + if (ret >=0) { + PyArray_ENABLEFLAGS(arr, NPY_ARRAY_UPDATEIFCOPY); + PyArray_CLEARFLAGS(arr, NPY_ARRAY_WRITEBACKIFCOPY); + } + return ret; +} + +/*NUMPY_API + * + * Precondition: 'arr' is a copy of 'base' (though possibly with different + * strides, ordering, etc.). This function sets the WRITEBACKIFCOPY flag and the + * ->base pointer on 'arr', call PyArray_ResolveWritebackIfCopy to copy any + * changes back to 'base' before deallocating the array. + * + * Steals a reference to 'base'. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_SetWritebackIfCopyBase(PyArrayObject *arr, PyArrayObject *base) +{ + if (base == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot WRITEBACKIFCOPY to NULL array"); + return -1; + } + if (PyArray_BASE(arr) != NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot set array with existing base to WRITEBACKIFCOPY"); + goto fail; + } + if (PyArray_FailUnlessWriteable(base, "WRITEBACKIFCOPY base") < 0) { + goto fail; + } + + /* + * Any writes to 'arr' will magically turn into writes to 'base', so we + * should warn if necessary. + */ + if (PyArray_FLAGS(base) & NPY_ARRAY_WARN_ON_WRITE) { + PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WARN_ON_WRITE); + } + + /* + * Unlike PyArray_SetBaseObject, we do not compress the chain of base + * references. + */ + ((PyArrayObject_fields *)arr)->base = (PyObject *)base; + PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WRITEBACKIFCOPY); + PyArray_CLEARFLAGS(base, NPY_ARRAY_WRITEABLE); + + return 0; + + fail: + Py_DECREF(base); + return -1; +} + +/*NUMPY_API + * Sets the 'base' attribute of the array. This steals a reference + * to 'obj'. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_SetBaseObject(PyArrayObject *arr, PyObject *obj) +{ + if (obj == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot set the NumPy array 'base' " + "dependency to NULL after initialization"); + return -1; + } + /* + * Allow the base to be set only once. Once the object which + * owns the data is set, it doesn't make sense to change it. + */ + if (PyArray_BASE(arr) != NULL) { + Py_DECREF(obj); + PyErr_SetString(PyExc_ValueError, + "Cannot set the NumPy array 'base' " + "dependency more than once"); + return -1; + } + + /* + * Don't allow infinite chains of views, always set the base + * to the first owner of the data. + * That is, either the first object which isn't an array, + * or the first object which owns its own data. + */ + + while (PyArray_Check(obj) && (PyObject *)arr != obj) { + PyArrayObject *obj_arr = (PyArrayObject *)obj; + PyObject *tmp; + + /* Propagate WARN_ON_WRITE through views. */ + if (PyArray_FLAGS(obj_arr) & NPY_ARRAY_WARN_ON_WRITE) { + PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WARN_ON_WRITE); + } + + /* If this array owns its own data, stop collapsing */ + if (PyArray_CHKFLAGS(obj_arr, NPY_ARRAY_OWNDATA)) { + break; + } + + tmp = PyArray_BASE(obj_arr); + /* If there's no base, stop collapsing */ + if (tmp == NULL) { + break; + } + /* Stop the collapse new base when the would not be of the same + * type (i.e. different subclass). + */ + if (Py_TYPE(tmp) != Py_TYPE(arr)) { + break; + } + + + Py_INCREF(tmp); + Py_DECREF(obj); + obj = tmp; + } + + /* Disallow circular references */ + if ((PyObject *)arr == obj) { + Py_DECREF(obj); + PyErr_SetString(PyExc_ValueError, + "Cannot create a circular NumPy array 'base' dependency"); + return -1; + } + + ((PyArrayObject_fields *)arr)->base = obj; + + return 0; +} + + +/*NUMPY_API*/ +NPY_NO_EXPORT int +PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object) +{ + int ret = 0; + PyArrayObject *src; + PyArray_Descr *dtype = NULL; + int ndim = 0; + npy_intp dims[NPY_MAXDIMS]; + + Py_INCREF(src_object); + /* + * Special code to mimic Numeric behavior for + * character arrays. + */ + if (PyArray_DESCR(dest)->type == NPY_CHARLTR && + PyArray_NDIM(dest) > 0 && + PyString_Check(src_object)) { + npy_intp n_new, n_old; + char *new_string; + PyObject *tmp; + + n_new = PyArray_DIMS(dest)[PyArray_NDIM(dest)-1]; + n_old = PyString_Size(src_object); + if (n_new > n_old) { + new_string = malloc(n_new); + if (new_string == NULL) { + Py_DECREF(src_object); + PyErr_NoMemory(); + return -1; + } + memcpy(new_string, PyString_AS_STRING(src_object), n_old); + memset(new_string + n_old, ' ', n_new - n_old); + tmp = PyString_FromStringAndSize(new_string, n_new); + free(new_string); + Py_DECREF(src_object); + src_object = tmp; + } + } + + /* + * Get either an array object we can copy from, or its parameters + * if there isn't a convenient array available. + */ + if (PyArray_GetArrayParamsFromObject(src_object, PyArray_DESCR(dest), + 0, &dtype, &ndim, dims, &src, NULL) < 0) { + Py_DECREF(src_object); + return -1; + } + + /* If it's not an array, either assign from a sequence or as a scalar */ + if (src == NULL) { + /* If the input is scalar */ + if (ndim == 0) { + /* If there's one dest element and src is a Python scalar */ + if (PyArray_IsScalar(src_object, Generic)) { + char *value; + int retcode; + + value = scalar_value(src_object, dtype); + if (value == NULL) { + Py_DECREF(dtype); + Py_DECREF(src_object); + return -1; + } + + /* TODO: switch to SAME_KIND casting */ + retcode = PyArray_AssignRawScalar(dest, dtype, value, + NULL, NPY_UNSAFE_CASTING); + Py_DECREF(dtype); + Py_DECREF(src_object); + return retcode; + } + /* Otherwise use the dtype's setitem function */ + else { + if (PyArray_SIZE(dest) == 1) { + Py_DECREF(dtype); + Py_DECREF(src_object); + ret = PyArray_SETITEM(dest, PyArray_DATA(dest), src_object); + return ret; + } + else { + src = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + dtype, 0, NULL, NULL, + NULL, 0, NULL); + if (src == NULL) { + Py_DECREF(src_object); + return -1; + } + if (PyArray_SETITEM(src, PyArray_DATA(src), src_object) < 0) { + Py_DECREF(src_object); + Py_DECREF(src); + return -1; + } + } + } + } + else { + /* + * If there are more than enough dims, use AssignFromSequence + * because it can handle this style of broadcasting. + */ + if (ndim >= PyArray_NDIM(dest)) { + int res; + Py_DECREF(dtype); + res = PyArray_AssignFromSequence(dest, src_object); + Py_DECREF(src_object); + return res; + } + /* Otherwise convert to an array and do an array-based copy */ + src = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + dtype, ndim, dims, NULL, NULL, + PyArray_ISFORTRAN(dest), NULL); + if (src == NULL) { + Py_DECREF(src_object); + return -1; + } + if (PyArray_AssignFromSequence(src, src_object) < 0) { + Py_DECREF(src); + Py_DECREF(src_object); + return -1; + } + } + } + + /* If it's an array, do a move (handling possible overlapping data) */ + ret = PyArray_MoveInto(dest, src); + Py_DECREF(src); + Py_DECREF(src_object); + return ret; +} + + +/* returns an Array-Scalar Object of the type of arr + from the given pointer to memory -- main Scalar creation function + default new method calls this. +*/ + +/* Ideally, here the descriptor would contain all the information needed. + So, that we simply need the data and the descriptor, and perhaps + a flag +*/ + + +/* + Given a string return the type-number for + the data-type with that string as the type-object name. + Returns NPY_NOTYPE without setting an error if no type can be + found. Only works for user-defined data-types. +*/ + +/*NUMPY_API + */ +NPY_NO_EXPORT int +PyArray_TypeNumFromName(char *str) +{ + int i; + PyArray_Descr *descr; + + for (i = 0; i < NPY_NUMUSERTYPES; i++) { + descr = userdescrs[i]; + if (strcmp(descr->typeobj->tp_name, str) == 0) { + return descr->type_num; + } + } + return NPY_NOTYPE; +} + +/*NUMPY_API + * + * If WRITEBACKIFCOPY and self has data, reset the base WRITEABLE flag, + * copy the local data to base, release the local data, and set flags + * appropriately. Return 0 if not relevant, 1 if success, < 0 on failure + */ +NPY_NO_EXPORT int +PyArray_ResolveWritebackIfCopy(PyArrayObject * self) +{ + PyArrayObject_fields *fa = (PyArrayObject_fields *)self; + if (fa && fa->base) { + if ((fa->flags & NPY_ARRAY_UPDATEIFCOPY) || (fa->flags & NPY_ARRAY_WRITEBACKIFCOPY)) { + /* + * UPDATEIFCOPY or WRITEBACKIFCOPY means that fa->base's data + * should be updated with the contents + * of self. + * fa->base->flags is not WRITEABLE to protect the relationship + * unlock it. + */ + int retval = 0; + PyArray_ENABLEFLAGS(((PyArrayObject *)fa->base), + NPY_ARRAY_WRITEABLE); + PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY); + PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY); + retval = PyArray_CopyAnyInto((PyArrayObject *)fa->base, self); + Py_DECREF(fa->base); + fa->base = NULL; + if (retval < 0) { + /* this should never happen, how did the two copies of data + * get out of sync? + */ + return retval; + } + return 1; + } + } + return 0; +} + +/*********************** end C-API functions **********************/ + +/* array object functions */ + +static void +array_dealloc(PyArrayObject *self) +{ + PyArrayObject_fields *fa = (PyArrayObject_fields *)self; + + _array_dealloc_buffer_info(self); + + if (fa->weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *)self); + } + if (fa->base) { + int retval; + if (PyArray_FLAGS(self) & NPY_ARRAY_WRITEBACKIFCOPY) + { + char * msg = "WRITEBACKIFCOPY requires a call to " + "PyArray_ResolveWritebackIfCopy or " + "PyArray_DiscardWritebackIfCopy before array_dealloc is " + "called."; + /* 2017-Nov-10 1.14 */ + if (DEPRECATE(msg) < 0) { + /* dealloc cannot raise an error, best effort try to write + to stderr and clear the error + */ + PyErr_WriteUnraisable((PyObject *)&PyArray_Type); + } + retval = PyArray_ResolveWritebackIfCopy(self); + if (retval < 0) + { + PyErr_Print(); + PyErr_Clear(); + } + } + if (PyArray_FLAGS(self) & NPY_ARRAY_UPDATEIFCOPY) { + /* DEPRECATED, remove once the flag is removed */ + Py_INCREF(self); /* hold on to self in next call since if + * refcount == 0 it will recurse back into + *array_dealloc + */ + retval = PyArray_ResolveWritebackIfCopy(self); + if (retval < 0) + { + PyErr_Print(); + PyErr_Clear(); + } + } + /* + * In any case base is pointing to something that we need + * to DECREF -- either a view or a buffer object + */ + Py_XDECREF(fa->base); + } + + if ((fa->flags & NPY_ARRAY_OWNDATA) && fa->data) { + /* Free internal references if an Object array */ + if (PyDataType_FLAGCHK(fa->descr, NPY_ITEM_REFCOUNT)) { + Py_INCREF(self); /*hold on to self */ + PyArray_XDECREF(self); + /* + * Don't need to DECREF -- because we are deleting + * self already... + */ + } + npy_free_cache(fa->data, PyArray_NBYTES(self)); + } + + /* must match allocation in PyArray_NewFromDescr */ + npy_free_cache_dim(fa->dimensions, 2 * fa->nd); + Py_DECREF(fa->descr); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +/*NUMPY_API + * Prints the raw data of the ndarray in a form useful for debugging + * low-level C issues. + */ +NPY_NO_EXPORT void +PyArray_DebugPrint(PyArrayObject *obj) +{ + int i; + PyArrayObject_fields *fobj = (PyArrayObject_fields *)obj; + + printf("-------------------------------------------------------\n"); + printf(" Dump of NumPy ndarray at address %p\n", obj); + if (obj == NULL) { + printf(" It's NULL!\n"); + printf("-------------------------------------------------------\n"); + fflush(stdout); + return; + } + printf(" ndim : %d\n", fobj->nd); + printf(" shape :"); + for (i = 0; i < fobj->nd; ++i) { + printf(" %d", (int)fobj->dimensions[i]); + } + printf("\n"); + + printf(" dtype : "); + PyObject_Print((PyObject *)fobj->descr, stdout, 0); + printf("\n"); + printf(" data : %p\n", fobj->data); + printf(" strides:"); + for (i = 0; i < fobj->nd; ++i) { + printf(" %d", (int)fobj->strides[i]); + } + printf("\n"); + + printf(" base : %p\n", fobj->base); + + printf(" flags :"); + if (fobj->flags & NPY_ARRAY_C_CONTIGUOUS) + printf(" NPY_C_CONTIGUOUS"); + if (fobj->flags & NPY_ARRAY_F_CONTIGUOUS) + printf(" NPY_F_CONTIGUOUS"); + if (fobj->flags & NPY_ARRAY_OWNDATA) + printf(" NPY_OWNDATA"); + if (fobj->flags & NPY_ARRAY_ALIGNED) + printf(" NPY_ALIGNED"); + if (fobj->flags & NPY_ARRAY_WRITEABLE) + printf(" NPY_WRITEABLE"); + if (fobj->flags & NPY_ARRAY_UPDATEIFCOPY) + printf(" NPY_UPDATEIFCOPY"); + if (fobj->flags & NPY_ARRAY_WRITEBACKIFCOPY) + printf(" NPY_WRITEBACKIFCOPY"); + printf("\n"); + + if (fobj->base != NULL && PyArray_Check(fobj->base)) { + printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + printf("Dump of array's BASE:\n"); + PyArray_DebugPrint((PyArrayObject *)fobj->base); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + printf("-------------------------------------------------------\n"); + fflush(stdout); +} + + +/*NUMPY_API + * This function is scheduled to be removed + * + * TO BE REMOVED - NOT USED INTERNALLY. + */ +NPY_NO_EXPORT void +PyArray_SetDatetimeParseFunction(PyObject *op) +{ +} + +/*NUMPY_API + */ +NPY_NO_EXPORT int +PyArray_CompareUCS4(npy_ucs4 *s1, npy_ucs4 *s2, size_t len) +{ + npy_ucs4 c1, c2; + while(len-- > 0) { + c1 = *s1++; + c2 = *s2++; + if (c1 != c2) { + return (c1 < c2) ? -1 : 1; + } + } + return 0; +} + +/*NUMPY_API + */ +NPY_NO_EXPORT int +PyArray_CompareString(char *s1, char *s2, size_t len) +{ + const unsigned char *c1 = (unsigned char *)s1; + const unsigned char *c2 = (unsigned char *)s2; + size_t i; + + for(i = 0; i < len; ++i) { + if (c1[i] != c2[i]) { + return (c1[i] > c2[i]) ? 1 : -1; + } + } + return 0; +} + + +/* Call this from contexts where an array might be written to, but we have no + * way to tell. (E.g., when converting to a read-write buffer.) + */ +NPY_NO_EXPORT int +array_might_be_written(PyArrayObject *obj) +{ + const char *msg = + "Numpy has detected that you (may be) writing to an array returned\n" + "by numpy.diagonal or by selecting multiple fields in a structured\n" + "array. This code will likely break in a future numpy release --\n" + "see numpy.diagonal or arrays.indexing reference docs for details.\n" + "The quick fix is to make an explicit copy (e.g., do\n" + "arr.diagonal().copy() or arr[['f0','f1']].copy())."; + if (PyArray_FLAGS(obj) & NPY_ARRAY_WARN_ON_WRITE) { + /* 2012-07-17, 1.7 */ + if (DEPRECATE_FUTUREWARNING(msg) < 0) { + return -1; + } + /* Only warn once per array */ + while (1) { + PyArray_CLEARFLAGS(obj, NPY_ARRAY_WARN_ON_WRITE); + if (!PyArray_BASE(obj) || !PyArray_Check(PyArray_BASE(obj))) { + break; + } + obj = (PyArrayObject *)PyArray_BASE(obj); + } + } + return 0; +} + +/*NUMPY_API + * + * This function does nothing if obj is writeable, and raises an exception + * (and returns -1) if obj is not writeable. It may also do other + * house-keeping, such as issuing warnings on arrays which are transitioning + * to become views. Always call this function at some point before writing to + * an array. + * + * 'name' is a name for the array, used to give better error + * messages. Something like "assignment destination", "output array", or even + * just "array". + */ +NPY_NO_EXPORT int +PyArray_FailUnlessWriteable(PyArrayObject *obj, const char *name) +{ + if (!PyArray_ISWRITEABLE(obj)) { + PyErr_Format(PyExc_ValueError, "%s is read-only", name); + return -1; + } + if (array_might_be_written(obj) < 0) { + return -1; + } + return 0; +} + +/* This also handles possibly mis-aligned data */ +/* Compare s1 and s2 which are not necessarily NULL-terminated. + s1 is of length len1 + s2 is of length len2 + If they are NULL terminated, then stop comparison. +*/ +static int +_myunincmp(npy_ucs4 *s1, npy_ucs4 *s2, int len1, int len2) +{ + npy_ucs4 *sptr; + npy_ucs4 *s1t=s1, *s2t=s2; + int val; + npy_intp size; + int diff; + + if ((npy_intp)s1 % sizeof(npy_ucs4) != 0) { + size = len1*sizeof(npy_ucs4); + s1t = malloc(size); + memcpy(s1t, s1, size); + } + if ((npy_intp)s2 % sizeof(npy_ucs4) != 0) { + size = len2*sizeof(npy_ucs4); + s2t = malloc(size); + memcpy(s2t, s2, size); + } + val = PyArray_CompareUCS4(s1t, s2t, PyArray_MIN(len1,len2)); + if ((val != 0) || (len1 == len2)) { + goto finish; + } + if (len2 > len1) { + sptr = s2t+len1; + val = -1; + diff = len2-len1; + } + else { + sptr = s1t+len2; + val = 1; + diff=len1-len2; + } + while (diff--) { + if (*sptr != 0) { + goto finish; + } + sptr++; + } + val = 0; + + finish: + if (s1t != s1) { + free(s1t); + } + if (s2t != s2) { + free(s2t); + } + return val; +} + + + + +/* + * Compare s1 and s2 which are not necessarily NULL-terminated. + * s1 is of length len1 + * s2 is of length len2 + * If they are NULL terminated, then stop comparison. + */ +static int +_mystrncmp(char *s1, char *s2, int len1, int len2) +{ + char *sptr; + int val; + int diff; + + val = memcmp(s1, s2, PyArray_MIN(len1, len2)); + if ((val != 0) || (len1 == len2)) { + return val; + } + if (len2 > len1) { + sptr = s2 + len1; + val = -1; + diff = len2 - len1; + } + else { + sptr = s1 + len2; + val = 1; + diff = len1 - len2; + } + while (diff--) { + if (*sptr != 0) { + return val; + } + sptr++; + } + return 0; /* Only happens if NULLs are everywhere */ +} + +/* Borrowed from Numarray */ + +#define SMALL_STRING 2048 + +static void _rstripw(char *s, int n) +{ + int i; + for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */ + int c = s[i]; + + if (!c || NumPyOS_ascii_isspace((int)c)) { + s[i] = 0; + } + else { + break; + } + } +} + +static void _unistripw(npy_ucs4 *s, int n) +{ + int i; + for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */ + npy_ucs4 c = s[i]; + if (!c || NumPyOS_ascii_isspace((int)c)) { + s[i] = 0; + } + else { + break; + } + } +} + + +static char * +_char_copy_n_strip(char *original, char *temp, int nc) +{ + if (nc > SMALL_STRING) { + temp = malloc(nc); + if (!temp) { + PyErr_NoMemory(); + return NULL; + } + } + memcpy(temp, original, nc); + _rstripw(temp, nc); + return temp; +} + +static void +_char_release(char *ptr, int nc) +{ + if (nc > SMALL_STRING) { + free(ptr); + } +} + +static char * +_uni_copy_n_strip(char *original, char *temp, int nc) +{ + if (nc*sizeof(npy_ucs4) > SMALL_STRING) { + temp = malloc(nc*sizeof(npy_ucs4)); + if (!temp) { + PyErr_NoMemory(); + return NULL; + } + } + memcpy(temp, original, nc*sizeof(npy_ucs4)); + _unistripw((npy_ucs4 *)temp, nc); + return temp; +} + +static void +_uni_release(char *ptr, int nc) +{ + if (nc*sizeof(npy_ucs4) > SMALL_STRING) { + free(ptr); + } +} + + +/* End borrowed from numarray */ + +#define _rstrip_loop(CMP) { \ + void *aptr, *bptr; \ + char atemp[SMALL_STRING], btemp[SMALL_STRING]; \ + while(size--) { \ + aptr = stripfunc(iself->dataptr, atemp, N1); \ + if (!aptr) return -1; \ + bptr = stripfunc(iother->dataptr, btemp, N2); \ + if (!bptr) { \ + relfunc(aptr, N1); \ + return -1; \ + } \ + val = compfunc(aptr, bptr, N1, N2); \ + *dptr = (val CMP 0); \ + PyArray_ITER_NEXT(iself); \ + PyArray_ITER_NEXT(iother); \ + dptr += 1; \ + relfunc(aptr, N1); \ + relfunc(bptr, N2); \ + } \ + } + +#define _reg_loop(CMP) { \ + while(size--) { \ + val = compfunc((void *)iself->dataptr, \ + (void *)iother->dataptr, \ + N1, N2); \ + *dptr = (val CMP 0); \ + PyArray_ITER_NEXT(iself); \ + PyArray_ITER_NEXT(iother); \ + dptr += 1; \ + } \ + } + +static int +_compare_strings(PyArrayObject *result, PyArrayMultiIterObject *multi, + int cmp_op, void *func, int rstrip) +{ + PyArrayIterObject *iself, *iother; + npy_bool *dptr; + npy_intp size; + int val; + int N1, N2; + int (*compfunc)(void *, void *, int, int); + void (*relfunc)(char *, int); + char* (*stripfunc)(char *, char *, int); + + compfunc = func; + dptr = (npy_bool *)PyArray_DATA(result); + iself = multi->iters[0]; + iother = multi->iters[1]; + size = multi->size; + N1 = PyArray_DESCR(iself->ao)->elsize; + N2 = PyArray_DESCR(iother->ao)->elsize; + if ((void *)compfunc == (void *)_myunincmp) { + N1 >>= 2; + N2 >>= 2; + stripfunc = _uni_copy_n_strip; + relfunc = _uni_release; + } + else { + stripfunc = _char_copy_n_strip; + relfunc = _char_release; + } + switch (cmp_op) { + case Py_EQ: + if (rstrip) { + _rstrip_loop(==); + } else { + _reg_loop(==); + } + break; + case Py_NE: + if (rstrip) { + _rstrip_loop(!=); + } else { + _reg_loop(!=); + } + break; + case Py_LT: + if (rstrip) { + _rstrip_loop(<); + } else { + _reg_loop(<); + } + break; + case Py_LE: + if (rstrip) { + _rstrip_loop(<=); + } else { + _reg_loop(<=); + } + break; + case Py_GT: + if (rstrip) { + _rstrip_loop(>); + } else { + _reg_loop(>); + } + break; + case Py_GE: + if (rstrip) { + _rstrip_loop(>=); + } else { + _reg_loop(>=); + } + break; + default: + PyErr_SetString(PyExc_RuntimeError, "bad comparison operator"); + return -1; + } + return 0; +} + +#undef _reg_loop +#undef _rstrip_loop +#undef SMALL_STRING + +NPY_NO_EXPORT PyObject * +_strings_richcompare(PyArrayObject *self, PyArrayObject *other, int cmp_op, + int rstrip) +{ + PyArrayObject *result; + PyArrayMultiIterObject *mit; + int val, cast = 0; + + /* Cast arrays to a common type */ + if (PyArray_TYPE(self) != PyArray_DESCR(other)->type_num) { +#if defined(NPY_PY3K) + /* + * Comparison between Bytes and Unicode is not defined in Py3K; + * we follow. + */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +#else + cast = 1; +#endif /* define(NPY_PY3K) */ + } + if (cast || (PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(other))) { + PyObject *new; + if (PyArray_TYPE(self) == NPY_STRING && + PyArray_DESCR(other)->type_num == NPY_UNICODE) { + PyArray_Descr* unicode = PyArray_DescrNew(PyArray_DESCR(other)); + unicode->elsize = PyArray_DESCR(self)->elsize << 2; + new = PyArray_FromAny((PyObject *)self, unicode, + 0, 0, 0, NULL); + if (new == NULL) { + return NULL; + } + Py_INCREF(other); + self = (PyArrayObject *)new; + } + else if ((PyArray_TYPE(self) == NPY_UNICODE) && + ((PyArray_DESCR(other)->type_num == NPY_STRING) || + (PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(other)))) { + PyArray_Descr* unicode = PyArray_DescrNew(PyArray_DESCR(self)); + + if (PyArray_DESCR(other)->type_num == NPY_STRING) { + unicode->elsize = PyArray_DESCR(other)->elsize << 2; + } + else { + unicode->elsize = PyArray_DESCR(other)->elsize; + } + new = PyArray_FromAny((PyObject *)other, unicode, + 0, 0, 0, NULL); + if (new == NULL) { + return NULL; + } + Py_INCREF(self); + other = (PyArrayObject *)new; + } + else { + PyErr_SetString(PyExc_TypeError, + "invalid string data-types " + "in comparison"); + return NULL; + } + } + else { + Py_INCREF(self); + Py_INCREF(other); + } + + /* Broad-cast the arrays to a common shape */ + mit = (PyArrayMultiIterObject *)PyArray_MultiIterNew(2, self, other); + Py_DECREF(self); + Py_DECREF(other); + if (mit == NULL) { + return NULL; + } + + result = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + PyArray_DescrFromType(NPY_BOOL), + mit->nd, + mit->dimensions, + NULL, NULL, 0, + NULL); + if (result == NULL) { + goto finish; + } + + if (PyArray_TYPE(self) == NPY_UNICODE) { + val = _compare_strings(result, mit, cmp_op, _myunincmp, rstrip); + } + else { + val = _compare_strings(result, mit, cmp_op, _mystrncmp, rstrip); + } + + if (val < 0) { + Py_DECREF(result); + result = NULL; + } + + finish: + Py_DECREF(mit); + return (PyObject *)result; +} + +/* + * VOID-type arrays can only be compared equal and not-equal + * in which case the fields are all compared by extracting the fields + * and testing one at a time... + * equality testing is performed using logical_ands on all the fields. + * in-equality testing is performed using logical_ors on all the fields. + * + * VOID-type arrays without fields are compared for equality by comparing their + * memory at each location directly (using string-code). + */ +static PyObject * +_void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op) +{ + if (!(cmp_op == Py_EQ || cmp_op == Py_NE)) { + PyErr_SetString(PyExc_ValueError, + "Void-arrays can only be compared for equality."); + return NULL; + } + if (PyArray_HASFIELDS(self)) { + PyObject *res = NULL, *temp, *a, *b; + PyObject *key, *value, *temp2; + PyObject *op; + Py_ssize_t pos = 0; + npy_intp result_ndim = PyArray_NDIM(self) > PyArray_NDIM(other) ? + PyArray_NDIM(self) : PyArray_NDIM(other); + + op = (cmp_op == Py_EQ ? n_ops.logical_and : n_ops.logical_or); + while (PyDict_Next(PyArray_DESCR(self)->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + a = array_subscript_asarray(self, key); + if (a == NULL) { + Py_XDECREF(res); + return NULL; + } + b = array_subscript_asarray(other, key); + if (b == NULL) { + Py_XDECREF(res); + Py_DECREF(a); + return NULL; + } + temp = array_richcompare((PyArrayObject *)a,b,cmp_op); + Py_DECREF(a); + Py_DECREF(b); + if (temp == NULL) { + Py_XDECREF(res); + return NULL; + } + + /* + * If the field type has a non-trivial shape, additional + * dimensions will have been appended to `a` and `b`. + * In that case, reduce them using `op`. + */ + if (PyArray_Check(temp) && + PyArray_NDIM((PyArrayObject *)temp) > result_ndim) { + /* If the type was multidimensional, collapse that part to 1-D + */ + if (PyArray_NDIM((PyArrayObject *)temp) != result_ndim+1) { + npy_intp dimensions[NPY_MAXDIMS]; + PyArray_Dims newdims; + + newdims.ptr = dimensions; + newdims.len = result_ndim+1; + memcpy(dimensions, PyArray_DIMS((PyArrayObject *)temp), + sizeof(npy_intp)*result_ndim); + dimensions[result_ndim] = -1; + temp2 = PyArray_Newshape((PyArrayObject *)temp, + &newdims, NPY_ANYORDER); + if (temp2 == NULL) { + Py_DECREF(temp); + Py_XDECREF(res); + return NULL; + } + Py_DECREF(temp); + temp = temp2; + } + /* Reduce the extra dimension of `temp` using `op` */ + temp2 = PyArray_GenericReduceFunction((PyArrayObject *)temp, + op, result_ndim, + NPY_BOOL, NULL); + if (temp2 == NULL) { + Py_DECREF(temp); + Py_XDECREF(res); + return NULL; + } + Py_DECREF(temp); + temp = temp2; + } + + if (res == NULL) { + res = temp; + } + else { + temp2 = PyObject_CallFunction(op, "OO", res, temp); + Py_DECREF(temp); + Py_DECREF(res); + if (temp2 == NULL) { + return NULL; + } + res = temp2; + } + } + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "No fields found."); + } + return res; + } + else { + /* + * compare as a string. Assumes self and + * other have same descr->type + */ + return _strings_richcompare(self, other, cmp_op, 0); + } +} + +NPY_NO_EXPORT PyObject * +array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) +{ + PyArrayObject *array_other; + PyObject *obj_self = (PyObject *)self; + PyObject *result = NULL; + + /* Special case for string arrays (which don't and currently can't have + * ufunc loops defined, so there's no point in trying). + */ + if (PyArray_ISSTRING(self)) { + array_other = (PyArrayObject *)PyArray_FromObject(other, + NPY_NOTYPE, 0, 0); + if (array_other == NULL) { + PyErr_Clear(); + /* Never mind, carry on, see what happens */ + } + else if (!PyArray_ISSTRING(array_other)) { + Py_DECREF(array_other); + /* Never mind, carry on, see what happens */ + } + else { + result = _strings_richcompare(self, array_other, cmp_op, 0); + Py_DECREF(array_other); + return result; + } + /* If we reach this point, it means that we are not comparing + * string-to-string. It's possible that this will still work out, + * e.g. if the other array is an object array, then both will be cast + * to object or something? I don't know how that works actually, but + * it does, b/c this works: + * l = ["a", "b"] + * assert np.array(l, dtype="S1") == np.array(l, dtype="O") + * So we fall through and see what happens. + */ + } + + switch (cmp_op) { + case Py_LT: + RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other); + result = PyArray_GenericBinaryFunction(self, other, n_ops.less); + break; + case Py_LE: + RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other); + result = PyArray_GenericBinaryFunction(self, other, n_ops.less_equal); + break; + case Py_EQ: + RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other); + /* + * The ufunc does not support void/structured types, so these + * need to be handled specifically. Only a few cases are supported. + */ + + if (PyArray_TYPE(self) == NPY_VOID) { + int _res; + + array_other = (PyArrayObject *)PyArray_FROM_O(other); + /* + * If not successful, indicate that the items cannot be compared + * this way. + */ + if (array_other == NULL) { + /* 2015-05-07, 1.10 */ + PyErr_Clear(); + if (DEPRECATE( + "elementwise == comparison failed and returning scalar " + "instead; this will raise an error in the future.") < 0) { + return NULL; + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + _res = PyArray_CanCastTypeTo(PyArray_DESCR(self), + PyArray_DESCR(array_other), + NPY_EQUIV_CASTING); + if (_res == 0) { + /* 2015-05-07, 1.10 */ + Py_DECREF(array_other); + if (DEPRECATE_FUTUREWARNING( + "elementwise == comparison failed and returning scalar " + "instead; this will raise an error or perform " + "elementwise comparison in the future.") < 0) { + return NULL; + } + Py_INCREF(Py_False); + return Py_False; + } + else { + result = _void_compare(self, array_other, cmp_op); + } + Py_DECREF(array_other); + return result; + } + + result = PyArray_GenericBinaryFunction(self, + (PyObject *)other, + n_ops.equal); + /* + * If the comparison results in NULL, then the + * two array objects can not be compared together; + * indicate that + */ + if (result == NULL) { + /* + * Comparisons should raise errors when element-wise comparison + * is not possible. + */ + /* 2015-05-14, 1.10 */ + PyErr_Clear(); + if (DEPRECATE("elementwise == comparison failed; " + "this will raise an error in the future.") < 0) { + return NULL; + } + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + break; + case Py_NE: + RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other); + /* + * The ufunc does not support void/structured types, so these + * need to be handled specifically. Only a few cases are supported. + */ + + if (PyArray_TYPE(self) == NPY_VOID) { + int _res; + + array_other = (PyArrayObject *)PyArray_FROM_O(other); + /* + * If not successful, indicate that the items cannot be compared + * this way. + */ + if (array_other == NULL) { + /* 2015-05-07, 1.10 */ + PyErr_Clear(); + if (DEPRECATE( + "elementwise != comparison failed and returning scalar " + "instead; this will raise an error in the future.") < 0) { + return NULL; + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + _res = PyArray_CanCastTypeTo(PyArray_DESCR(self), + PyArray_DESCR(array_other), + NPY_EQUIV_CASTING); + if (_res == 0) { + /* 2015-05-07, 1.10 */ + Py_DECREF(array_other); + if (DEPRECATE_FUTUREWARNING( + "elementwise != comparison failed and returning scalar " + "instead; this will raise an error or perform " + "elementwise comparison in the future.") < 0) { + return NULL; + } + Py_INCREF(Py_True); + return Py_True; + } + else { + result = _void_compare(self, array_other, cmp_op); + Py_DECREF(array_other); + } + return result; + } + + result = PyArray_GenericBinaryFunction(self, (PyObject *)other, + n_ops.not_equal); + if (result == NULL) { + /* + * Comparisons should raise errors when element-wise comparison + * is not possible. + */ + /* 2015-05-14, 1.10 */ + PyErr_Clear(); + if (DEPRECATE("elementwise != comparison failed; " + "this will raise an error in the future.") < 0) { + return NULL; + } + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + break; + case Py_GT: + RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other); + result = PyArray_GenericBinaryFunction(self, other, + n_ops.greater); + break; + case Py_GE: + RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other); + result = PyArray_GenericBinaryFunction(self, other, + n_ops.greater_equal); + break; + default: + result = Py_NotImplemented; + Py_INCREF(result); + } + return result; +} + +/*NUMPY_API + */ +NPY_NO_EXPORT int +PyArray_ElementStrides(PyObject *obj) +{ + PyArrayObject *arr; + int itemsize; + int i, ndim; + npy_intp *strides; + + if (!PyArray_Check(obj)) { + return 0; + } + + arr = (PyArrayObject *)obj; + + itemsize = PyArray_ITEMSIZE(arr); + ndim = PyArray_NDIM(arr); + strides = PyArray_STRIDES(arr); + + for (i = 0; i < ndim; i++) { + if ((strides[i] % itemsize) != 0) { + return 0; + } + } + return 1; +} + +/* + * This routine checks to see if newstrides (of length nd) will not + * ever be able to walk outside of the memory implied numbytes and offset. + * + * The available memory is assumed to start at -offset and proceed + * to numbytes-offset. The strides are checked to ensure + * that accessing memory using striding will not try to reach beyond + * this memory for any of the axes. + * + * If numbytes is 0 it will be calculated using the dimensions and + * element-size. + * + * This function checks for walking beyond the beginning and right-end + * of the buffer and therefore works for any integer stride (positive + * or negative). + */ + +/*NUMPY_API*/ +NPY_NO_EXPORT npy_bool +PyArray_CheckStrides(int elsize, int nd, npy_intp numbytes, npy_intp offset, + npy_intp *dims, npy_intp *newstrides) +{ + npy_intp begin, end; + npy_intp lower_offset; + npy_intp upper_offset; + + if (numbytes == 0) { + numbytes = PyArray_MultiplyList(dims, nd) * elsize; + } + + begin = -offset; + end = numbytes - offset; + + offset_bounds_from_strides(elsize, nd, dims, newstrides, + &lower_offset, &upper_offset); + + if ((upper_offset > end) || (lower_offset < begin)) { + return NPY_FALSE; + } + return NPY_TRUE; +} + + +static PyObject * +array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"shape", "dtype", "buffer", "offset", "strides", + "order", NULL}; + PyArray_Descr *descr = NULL; + int itemsize; + PyArray_Dims dims = {NULL, 0}; + PyArray_Dims strides = {NULL, 0}; + PyArray_Chunk buffer; + npy_longlong offset = 0; + NPY_ORDER order = NPY_CORDER; + int is_f_order = 0; + PyArrayObject *ret; + + buffer.ptr = NULL; + /* + * Usually called with shape and type but can also be called with buffer, + * strides, and swapped info For now, let's just use this to create an + * empty, contiguous array of a specific type and shape. + */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&LO&O&:ndarray", + kwlist, PyArray_IntpConverter, + &dims, + PyArray_DescrConverter, + &descr, + PyArray_BufferConverter, + &buffer, + &offset, + &PyArray_IntpConverter, + &strides, + &PyArray_OrderConverter, + &order)) { + goto fail; + } + if (order == NPY_FORTRANORDER) { + is_f_order = 1; + } + if (descr == NULL) { + descr = PyArray_DescrFromType(NPY_DEFAULT_TYPE); + } + + itemsize = descr->elsize; + + if (strides.ptr != NULL) { + npy_intp nb, off; + if (strides.len != dims.len) { + PyErr_SetString(PyExc_ValueError, + "strides, if given, must be " \ + "the same length as shape"); + goto fail; + } + + if (buffer.ptr == NULL) { + nb = 0; + off = 0; + } + else { + nb = buffer.len; + off = (npy_intp) offset; + } + + + if (!PyArray_CheckStrides(itemsize, dims.len, + nb, off, + dims.ptr, strides.ptr)) { + PyErr_SetString(PyExc_ValueError, + "strides is incompatible " \ + "with shape of requested " \ + "array and size of buffer"); + goto fail; + } + } + + if (buffer.ptr == NULL) { + ret = (PyArrayObject *) + PyArray_NewFromDescr_int(subtype, descr, + (int)dims.len, + dims.ptr, + strides.ptr, NULL, is_f_order, NULL, + 0, 1); + if (ret == NULL) { + descr = NULL; + goto fail; + } + if (PyDataType_FLAGCHK(descr, NPY_ITEM_HASOBJECT)) { + /* place Py_None in object positions */ + PyArray_FillObjectArray(ret, Py_None); + if (PyErr_Occurred()) { + descr = NULL; + goto fail; + } + } + } + else { + /* buffer given -- use it */ + if (dims.len == 1 && dims.ptr[0] == -1) { + dims.ptr[0] = (buffer.len-(npy_intp)offset) / itemsize; + } + else if ((strides.ptr == NULL) && + (buffer.len < (offset + (((npy_intp)itemsize)* + PyArray_MultiplyList(dims.ptr, + dims.len))))) { + PyErr_SetString(PyExc_TypeError, + "buffer is too small for " \ + "requested array"); + goto fail; + } + /* get writeable and aligned */ + if (is_f_order) { + buffer.flags |= NPY_ARRAY_F_CONTIGUOUS; + } + ret = (PyArrayObject *)\ + PyArray_NewFromDescr_int(subtype, descr, + dims.len, dims.ptr, + strides.ptr, + offset + (char *)buffer.ptr, + buffer.flags, NULL, 0, 1); + if (ret == NULL) { + descr = NULL; + goto fail; + } + PyArray_UpdateFlags(ret, NPY_ARRAY_UPDATE_ALL); + Py_INCREF(buffer.base); + if (PyArray_SetBaseObject(ret, buffer.base) < 0) { + Py_DECREF(ret); + ret = NULL; + goto fail; + } + } + + npy_free_cache_dim_obj(dims); + npy_free_cache_dim_obj(strides); + return (PyObject *)ret; + + fail: + Py_XDECREF(descr); + npy_free_cache_dim_obj(dims); + npy_free_cache_dim_obj(strides); + return NULL; +} + + +static PyObject * +array_iter(PyArrayObject *arr) +{ + if (PyArray_NDIM(arr) == 0) { + PyErr_SetString(PyExc_TypeError, + "iteration over a 0-d array"); + return NULL; + } + return PySeqIter_New((PyObject *)arr); +} + +static PyObject * +array_alloc(PyTypeObject *type, Py_ssize_t NPY_UNUSED(nitems)) +{ + /* nitems will always be 0 */ + PyObject *obj = PyObject_Malloc(type->tp_basicsize); + PyObject_Init(obj, type); + return obj; +} + +static void +array_free(PyObject * v) +{ + /* avoid same deallocator as PyBaseObject, see gentype_free */ + PyObject_Free(v); +} + + +NPY_NO_EXPORT PyTypeObject PyArray_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.ndarray", /* tp_name */ + NPY_SIZEOF_PYARRAYOBJECT, /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)array_dealloc, /* tp_dealloc */ + (printfunc)NULL, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + (reprfunc)array_repr, /* tp_repr */ + &array_as_number, /* tp_as_number */ + &array_as_sequence, /* tp_as_sequence */ + &array_as_mapping, /* tp_as_mapping */ + /* + * The tp_hash slot will be set PyObject_HashNotImplemented when the + * module is loaded. + */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)array_str, /* tp_str */ + (getattrofunc)0, /* tp_getattro */ + (setattrofunc)0, /* tp_setattro */ + &array_as_buffer, /* tp_as_buffer */ + (Py_TPFLAGS_DEFAULT +#if !defined(NPY_PY3K) + | Py_TPFLAGS_CHECKTYPES + | Py_TPFLAGS_HAVE_NEWBUFFER +#endif + | Py_TPFLAGS_BASETYPE), /* tp_flags */ + 0, /* tp_doc */ + + (traverseproc)0, /* tp_traverse */ + (inquiry)0, /* tp_clear */ + (richcmpfunc)array_richcompare, /* tp_richcompare */ + offsetof(PyArrayObject_fields, weakreflist), /* tp_weaklistoffset */ + (getiterfunc)array_iter, /* tp_iter */ + (iternextfunc)0, /* tp_iternext */ + array_methods, /* tp_methods */ + 0, /* tp_members */ + array_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)0, /* tp_init */ + (allocfunc)array_alloc, /* tp_alloc */ + (newfunc)array_new, /* tp_new */ + (freefunc)array_free, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; diff --git a/numpy/core/src/multiarray/arrayobject.h b/numpy/core/src/multiarray/arrayobject.h new file mode 100644 index 0000000..9b74944 --- /dev/null +++ b/numpy/core/src/multiarray/arrayobject.h @@ -0,0 +1,29 @@ +#ifndef _NPY_INTERNAL_ARRAYOBJECT_H_ +#define _NPY_INTERNAL_ARRAYOBJECT_H_ + +#ifndef _MULTIARRAYMODULE +#error You should not include this +#endif + +NPY_NO_EXPORT PyObject * +_strings_richcompare(PyArrayObject *self, PyArrayObject *other, int cmp_op, + int rstrip); + +NPY_NO_EXPORT PyObject * +array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op); + +NPY_NO_EXPORT int +array_might_be_written(PyArrayObject *obj); + +/* + * This flag is used to mark arrays which we would like to, in the future, + * turn into views. It causes a warning to be issued on the first attempt to + * write to the array (but the write is allowed to succeed). + * + * This flag is for internal use only, and may be removed in a future release, + * which is why the #define is not exposed to user code. Currently it is set + * on arrays returned by ndarray.diagonal. + */ +static const int NPY_ARRAY_WARN_ON_WRITE = (1 << 31); + +#endif diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src new file mode 100644 index 0000000..d0370fe --- /dev/null +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -0,0 +1,4961 @@ +/* -*- c -*- */ +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#define _NPY_NO_DEPRECATIONS /* for NPY_CHAR */ + +#include "numpy/npy_common.h" +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" +#include "npy_pycompat.h" +#include "numpy/npy_math.h" +#include "numpy/halffloat.h" + +#include "npy_config.h" +#include "npy_sort.h" +#include "common.h" +#include "ctors.h" +#include "lowlevel_strided_loops.h" +#include "usertypes.h" +#include "_datetime.h" +#include "arrayobject.h" +#include "alloc.h" +#ifdef NPY_HAVE_SSE2_INTRINSICS +#include +#endif + +#include "numpyos.h" +#include + +#include "cblasfuncs.h" +#include "npy_cblas.h" +#include +#include + +/* check for sequences, but ignore the types numpy considers scalars */ +static NPY_INLINE npy_bool +PySequence_NoString_Check(PyObject *op) { + return + PySequence_Check(op) && + !PyString_Check(op) && + !PyUnicode_Check(op) && + !PyArray_IsZeroDim(op); +} + +/* + ***************************************************************************** + ** PYTHON TYPES TO C TYPES ** + ***************************************************************************** + */ + +static double +MyPyFloat_AsDouble(PyObject *obj) +{ + double ret = 0; + PyObject *num; + + if (obj == Py_None) { + return NPY_NAN; + } + num = PyNumber_Float(obj); + if (num == NULL) { + return NPY_NAN; + } + ret = PyFloat_AsDouble(num); + Py_DECREF(num); + return ret; +} + +static npy_half +MyPyFloat_AsHalf(PyObject *obj) +{ + return npy_double_to_half(MyPyFloat_AsDouble(obj)); +} + +static PyObject * +MyPyFloat_FromHalf(npy_half h) +{ + return PyFloat_FromDouble(npy_half_to_double(h)); +} + +/* Handle case of assigning from an array scalar in setitem */ +static int +convert_to_scalar_and_retry(PyObject *op, void *ov, void *vap, + int (*setitem)(PyObject *op, void *ov, void *vap)) +{ + PyObject *temp; + + assert(PyArray_IsZeroDim(op)); + temp = PyArray_ToScalar(PyArray_BYTES((PyArrayObject *)op), + (PyArrayObject *)op); + if (temp == NULL) { + return -1; + } + else { + int res = setitem(temp, ov, vap); + Py_DECREF(temp); + return res; + } +} + + +/**begin repeat + * + * #Type = Long, LongLong# + * #type = npy_long, npy_longlong# + */ +static @type@ +MyPyLong_As@Type@ (PyObject *obj) +{ + @type@ ret; + PyObject *num = PyNumber_Long(obj); + + if (num == NULL) { + return -1; + } + ret = PyLong_As@Type@(num); + Py_DECREF(num); + return ret; +} + +/**end repeat**/ + +/**begin repeat + * + * #Type = Long, LongLong# + * #type = npy_ulong, npy_ulonglong# + */ +static @type@ +MyPyLong_AsUnsigned@Type@ (PyObject *obj) +{ + @type@ ret; + PyObject *num = PyNumber_Long(obj); + + if (num == NULL) { + return -1; + } + ret = PyLong_AsUnsigned@Type@(num); + if (PyErr_Occurred()) { + PyErr_Clear(); + ret = PyLong_As@Type@(num); + } + Py_DECREF(num); + return ret; +} + +/**end repeat**/ + +static npy_longlong +npy_strtoll(const char *str, char **endptr, int base) +{ +#if defined HAVE_STRTOLL + return strtoll(str, endptr, base); +#elif defined _MSC_VER + return _strtoi64(str, endptr, base); +#else + /* ok on 64 bit posix */ + return PyOS_strtol(str, endptr, base); +#endif +} + +static npy_ulonglong +npy_strtoull(const char *str, char **endptr, int base) +{ +#if defined HAVE_STRTOULL + return strtoull(str, endptr, base); +#elif defined _MSC_VER + return _strtoui64(str, endptr, base); +#else + /* ok on 64 bit posix */ + return PyOS_strtoul(str, endptr, base); +#endif +} + +/* + ***************************************************************************** + ** GETITEM AND SETITEM ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, LONG, UINT, ULONG, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE# + * #func1 = PyBool_FromLong, PyInt_FromLong*6, PyLong_FromUnsignedLong*2, + * PyLong_FromLongLong, PyLong_FromUnsignedLongLong, + * MyPyFloat_FromHalf, PyFloat_FromDouble*2# + * #func2 = PyObject_IsTrue, MyPyLong_AsLong*6, MyPyLong_AsUnsignedLong*2, + * MyPyLong_AsLongLong, MyPyLong_AsUnsignedLongLong, + * MyPyFloat_AsHalf, MyPyFloat_AsDouble*2# + * #type = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_long, npy_uint, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double# + * #type1 = long*7, npy_ulong*2, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double# + * #kind = Bool, Byte, UByte, Short, UShort, Int, Long, UInt, ULong, + * LongLong, ULongLong, Half, Float, Double# +*/ +static PyObject * +@TYPE@_getitem(void *input, void *vap) +{ + PyArrayObject *ap = vap; + char *ip = input; + @type@ t1; + + if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) { + t1 = *((@type@ *)ip); + return @func1@((@type1@)t1); + } + else { + PyArray_DESCR(ap)->f->copyswap(&t1, ip, PyArray_ISBYTESWAPPED(ap), ap); + return @func1@((@type1@)t1); + } +} + +static int +@TYPE@_setitem(PyObject *op, void *ov, void *vap) +{ + PyArrayObject *ap = vap; + @type@ temp; /* ensures alignment */ + + if (PyArray_IsScalar(op, @kind@)) { + temp = ((Py@kind@ScalarObject *)op)->obval; + } + else { + temp = (@type@)@func2@(op); + } + if (PyErr_Occurred()) { + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + if (PySequence_NoString_Check(op)) { + PyErr_SetString(PyExc_ValueError, + "setting an array element with a sequence."); + Py_DECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } + else { + PyErr_Restore(type, value, traceback); + } + return -1; + } + if (ap == NULL || PyArray_ISBEHAVED(ap)) + *((@type@ *)ov)=temp; + else { + PyArray_DESCR(ap)->f->copyswap(ov, &temp, PyArray_ISBYTESWAPPED(ap), + ap); + } + return 0; +} + +/**end repeat**/ + +/**begin repeat + * + * #TYPE = CFLOAT, CDOUBLE# + * #type = npy_float, npy_double# + */ +static PyObject * +@TYPE@_getitem(void *input, void *vap) +{ + PyArrayObject *ap = vap; + char *ip = input; + @type@ t1, t2; + + if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) { + return PyComplex_FromDoubles((double)((@type@ *)ip)[0], + (double)((@type@ *)ip)[1]); + } + else { + int size = sizeof(@type@); + + npy_bool swap = PyArray_ISBYTESWAPPED(ap); + copy_and_swap(&t1, ip, size, 1, 0, swap); + copy_and_swap(&t2, ip + size, size, 1, 0, swap); + return PyComplex_FromDoubles((double)t1, (double)t2); + } +} + +/**end repeat**/ + + + +/**begin repeat + * + * #NAME = CFLOAT, CDOUBLE, CLONGDOUBLE# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# + * #ftype = npy_float, npy_double, npy_longdouble# + * #kind = CFloat, CDouble, CLongDouble# + */ +static int +@NAME@_setitem(PyObject *op, void *ov, void *vap) +{ + PyArrayObject *ap = vap; + Py_complex oop; + @type@ temp; + int rsize; + + if (PyArray_IsZeroDim(op)) { + return convert_to_scalar_and_retry(op, ov, vap, @NAME@_setitem); + } + + if (PyArray_IsScalar(op, @kind@)){ + temp = ((Py@kind@ScalarObject *)op)->obval; + } + else { + if (op == Py_None) { + oop.real = NPY_NAN; + oop.imag = NPY_NAN; + } + else { + oop = PyComplex_AsCComplex (op); + if (PyErr_Occurred()) { + return -1; + } + } + temp.real = (@ftype@) oop.real; + temp.imag = (@ftype@) oop.imag; + } + + memcpy(ov, &temp, PyArray_DESCR(ap)->elsize); + if (PyArray_ISBYTESWAPPED(ap)) { + byte_swap_vector(ov, 2, sizeof(@ftype@)); + } + rsize = sizeof(@ftype@); + copy_and_swap(ov, &temp, rsize, 2, rsize, PyArray_ISBYTESWAPPED(ap)); + return 0; +} + +/**end repeat**/ + +static NPY_INLINE npy_longdouble +string_to_long_double(PyObject*op) +{ + char *s; + char *end; + npy_longdouble temp; + PyObject* b; + + if (PyUnicode_Check(op)) { + b = PyUnicode_AsUTF8String(op); + if (!b) { + return 0; + } + } + else { + b = op; + Py_XINCREF(b); + } + s = PyBytes_AsString(b); + if (s) { + errno = 0; + temp = NumPyOS_ascii_strtold(s, &end); + if (errno == ERANGE) { + if (PyErr_Warn(PyExc_RuntimeWarning, + "overflow encountered in conversion from string") < 0) { + Py_XDECREF(b); + return 0; + } + /* strtold returns INFINITY of the correct sign. */ + } + else if (errno) { + PyErr_Format(PyExc_ValueError, + "invalid literal for long double: %s (%s)", + s, + strerror(errno)); + Py_XDECREF(b); + return 0; + } + + /* Extra characters at the end of the string, or nothing parsed */ + if (end == s || *end) { + PyErr_Format(PyExc_ValueError, + "invalid literal for long double: %s", + s); + Py_XDECREF(b); + return 0; + } + Py_XDECREF(b); + } + else { + /* Probably wasn't a string, try converting it via a python double */ + PyErr_Clear(); + Py_XDECREF(b); + temp = (npy_longdouble) MyPyFloat_AsDouble(op); + } + return temp; +} + +/* + * These return array scalars which are different than other date-types. + */ + +static PyObject * +LONGDOUBLE_getitem(void *ip, void *ap) +{ + return PyArray_Scalar(ip, PyArray_DESCR((PyArrayObject *)ap), NULL); +} + +static int +LONGDOUBLE_setitem(PyObject *op, void *ov, void *vap) +{ + PyArrayObject *ap = vap; + /* ensure alignment */ + npy_longdouble temp; + + if (PyArray_IsZeroDim(op)) { + return convert_to_scalar_and_retry(op, ov, vap, LONGDOUBLE_setitem); + } + + if (PyArray_IsScalar(op, LongDouble)) { + temp = ((PyLongDoubleScalarObject *)op)->obval; + } + else { + /* In case something funny happened in PyArray_IsScalar */ + if (PyErr_Occurred()) { + return -1; + } + temp = string_to_long_double(op); + } + if (PyErr_Occurred()) { + return -1; + } + if (ap == NULL || PyArray_ISBEHAVED(ap)) { + *((npy_longdouble *)ov) = temp; + } + else { + copy_and_swap(ov, &temp, PyArray_DESCR(ap)->elsize, 1, 0, + PyArray_ISBYTESWAPPED(ap)); + } + return 0; +} + +static PyObject * +CLONGDOUBLE_getitem(void *ip, void *ap) +{ + return PyArray_Scalar(ip, PyArray_DESCR((PyArrayObject *)ap), NULL); +} + +/* UNICODE */ +static PyObject * +UNICODE_getitem(void *ip, void *vap) +{ + PyArrayObject *ap = vap; + Py_ssize_t size = PyArray_ITEMSIZE(ap); + int swap = PyArray_ISBYTESWAPPED(ap); + int align = !PyArray_ISALIGNED(ap); + + return (PyObject *)PyUnicode_FromUCS4(ip, size, swap, align); +} + +static int +UNICODE_setitem(PyObject *op, void *ov, void *vap) +{ + PyArrayObject *ap = vap; + PyObject *temp; + Py_UNICODE *ptr; + int datalen; +#ifndef Py_UNICODE_WIDE + char *buffer; +#endif + + if (PyArray_IsZeroDim(op)) { + return convert_to_scalar_and_retry(op, ov, vap, UNICODE_setitem); + } + + if (PySequence_NoString_Check(op)) { + PyErr_SetString(PyExc_ValueError, + "setting an array element with a sequence"); + return -1; + } +#if defined(NPY_PY3K) + if (PyBytes_Check(op)) { + /* Try to decode from ASCII */ + temp = PyUnicode_FromEncodedObject(op, "ASCII", "strict"); + if (temp == NULL) { + return -1; + } + } + else if ((temp=PyObject_Str(op)) == NULL) { +#else + if ((temp=PyObject_Unicode(op)) == NULL) { +#endif + return -1; + } + ptr = PyUnicode_AS_UNICODE(temp); + if ((ptr == NULL) || (PyErr_Occurred())) { + Py_DECREF(temp); + return -1; + } + datalen = PyUnicode_GET_DATA_SIZE(temp); + +#ifdef Py_UNICODE_WIDE + memcpy(ov, ptr, PyArray_MIN(PyArray_DESCR(ap)->elsize, datalen)); +#else + if (!PyArray_ISALIGNED(ap)) { + buffer = PyArray_malloc(PyArray_DESCR(ap)->elsize); + if (buffer == NULL) { + Py_DECREF(temp); + PyErr_NoMemory(); + return -1; + } + } + else { + buffer = ov; + } + datalen = PyUCS2Buffer_AsUCS4(ptr, (npy_ucs4 *)buffer, + datalen >> 1, PyArray_DESCR(ap)->elsize >> 2); + datalen <<= 2; + if (!PyArray_ISALIGNED(ap)) { + memcpy(ov, buffer, datalen); + PyArray_free(buffer); + } +#endif + /* Fill in the rest of the space with 0 */ + if (PyArray_DESCR(ap)->elsize > datalen) { + memset((char*)ov + datalen, 0, (PyArray_DESCR(ap)->elsize - datalen)); + } + if (PyArray_ISBYTESWAPPED(ap)) { + byte_swap_vector(ov, PyArray_DESCR(ap)->elsize >> 2, 4); + } + Py_DECREF(temp); + return 0; +} + +/* STRING + * + * can handle both NULL-terminated and not NULL-terminated cases + * will truncate all ending NULLs in returned string. + */ +static PyObject * +STRING_getitem(void *ip, void *vap) +{ + PyArrayObject *ap = vap; + /* Will eliminate NULLs at the end */ + char *ptr; + int size = PyArray_DESCR(ap)->elsize; + + ptr = (char *)ip + size - 1; + while (size > 0 && *ptr-- == '\0') { + size--; + } + return PyBytes_FromStringAndSize(ip,size); +} + +static int +STRING_setitem(PyObject *op, void *ov, void *vap) +{ + PyArrayObject *ap = vap; + char *ptr; + Py_ssize_t len; + PyObject *temp = NULL; + + if (PyArray_IsZeroDim(op)) { + return convert_to_scalar_and_retry(op, ov, vap, STRING_setitem); + } + + if (PySequence_NoString_Check(op)) { + PyErr_SetString(PyExc_ValueError, + "setting an array element with a sequence"); + return -1; + } +#if defined(NPY_PY3K) + if (PyUnicode_Check(op)) { + /* Assume ASCII codec -- function similarly as Python 2 */ + temp = PyUnicode_AsASCIIString(op); + if (temp == NULL) { + return -1; + } + } + else if (PyBytes_Check(op) || PyMemoryView_Check(op)) { + temp = PyObject_Bytes(op); + if (temp == NULL) { + return -1; + } + } + else { + /* Emulate similar casting behavior as on Python 2 */ + PyObject *str; + str = PyObject_Str(op); + if (str == NULL) { + return -1; + } + temp = PyUnicode_AsASCIIString(str); + Py_DECREF(str); + if (temp == NULL) { + return -1; + } + } +#else + if ((temp = PyObject_Str(op)) == NULL) { + return -1; + } +#endif + if (PyBytes_AsStringAndSize(temp, &ptr, &len) < 0) { + Py_DECREF(temp); + return -1; + } + memcpy(ov, ptr, PyArray_MIN(PyArray_DESCR(ap)->elsize,len)); + /* + * If string length is smaller than room in array + * Then fill the rest of the element size with NULL + */ + if (PyArray_DESCR(ap)->elsize > len) { + memset((char *)ov + len, 0, (PyArray_DESCR(ap)->elsize - len)); + } + Py_DECREF(temp); + return 0; +} + +/* OBJECT */ + +#define __ALIGNED(obj, sz) ((((size_t) obj) % (sz))==0) + +static PyObject * +OBJECT_getitem(void *ip, void *NPY_UNUSED(ap)) +{ + PyObject *obj; + NPY_COPY_PYOBJECT_PTR(&obj, ip); + if (obj == NULL) { + Py_RETURN_NONE; + } + else { + Py_INCREF(obj); + return obj; + } +} + + +static int +OBJECT_setitem(PyObject *op, void *ov, void *NPY_UNUSED(ap)) +{ + PyObject *obj; + + NPY_COPY_PYOBJECT_PTR(&obj, ov); + + Py_INCREF(op); + Py_XDECREF(obj); + + NPY_COPY_PYOBJECT_PTR(ov, &op); + + return PyErr_Occurred() ? -1 : 0; +} + +/* VOID */ + +static PyObject * +VOID_getitem(void *input, void *vap) +{ + PyArrayObject *ap = vap; + char *ip = input; + PyArrayObject *u = NULL; + PyArray_Descr* descr; + int itemsize; + + descr = PyArray_DESCR(ap); + if (PyDataType_HASFIELDS(descr)) { + PyObject *key; + PyObject *names; + int i, n; + PyObject *ret; + PyObject *tup; + int savedflags; + + /* get the names from the fields dictionary*/ + names = descr->names; + n = PyTuple_GET_SIZE(names); + ret = PyTuple_New(n); + savedflags = PyArray_FLAGS(ap); + for (i = 0; i < n; i++) { + npy_intp offset; + PyArray_Descr *new; + key = PyTuple_GET_ITEM(names, i); + tup = PyDict_GetItem(descr->fields, key); + if (_unpack_field(tup, &new, &offset) < 0) { + Py_DECREF(ret); + ((PyArrayObject_fields *)ap)->descr = descr; + return NULL; + } + /* + * TODO: temporarily modifying the array like this + * is bad coding style, should be changed. + */ + ((PyArrayObject_fields *)ap)->descr = new; + /* update alignment based on offset */ + if ((new->alignment > 1) + && ((((npy_intp)(ip+offset)) % new->alignment) != 0)) { + PyArray_CLEARFLAGS(ap, NPY_ARRAY_ALIGNED); + } + else { + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_ALIGNED); + } + PyTuple_SET_ITEM(ret, i, PyArray_GETITEM(ap, ip+offset)); + ((PyArrayObject_fields *)ap)->flags = savedflags; + } + ((PyArrayObject_fields *)ap)->descr = descr; + return ret; + } + + if (descr->subarray) { + /* return an array of the basic type */ + PyArray_Dims shape = {NULL, -1}; + PyArrayObject *ret; + + if (!(PyArray_IntpConverter(descr->subarray->shape, &shape))) { + npy_free_cache_dim_obj(shape); + PyErr_SetString(PyExc_ValueError, + "invalid shape in fixed-type tuple."); + return NULL; + } + Py_INCREF(descr->subarray->base); + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + descr->subarray->base, shape.len, shape.ptr, + NULL, ip, PyArray_FLAGS(ap)&(~NPY_ARRAY_F_CONTIGUOUS), NULL); + npy_free_cache_dim_obj(shape); + if (!ret) { + return NULL; + } + Py_INCREF(ap); + if (PyArray_SetBaseObject(ret, (PyObject *)ap) < 0) { + Py_DECREF(ret); + return NULL; + } + PyArray_UpdateFlags((PyArrayObject *)ret, NPY_ARRAY_UPDATE_ALL); + return (PyObject *)ret; + } + + /* 2017-11-26, 1.14 */ + if (DEPRECATE_FUTUREWARNING( + "the `.item()` method of unstructured void types will return an " + "immutable `bytes` object in the near future, the same as " + "returned by `bytes(void_obj)`, instead of the mutable memoryview " + "or integer array returned in numpy 1.13.") < 0) { + return NULL; + } + /* + * In the future all the code below will be replaced by + * + * For unstructured void types like V4, return a bytes object (copy). + * return PyBytes_FromStringAndSize(PyArray_DATA(ap), descr->elsize); + */ + + if (PyDataType_FLAGCHK(descr, NPY_ITEM_HASOBJECT) + || PyDataType_FLAGCHK(descr, NPY_ITEM_IS_POINTER)) { + PyErr_SetString(PyExc_ValueError, + "tried to get void-array with object members as buffer."); + return NULL; + } + itemsize = PyArray_DESCR(ap)->elsize; + +#if defined(NPY_PY3K) + /* + * Return a byte array; there are no plain buffer objects on Py3 + */ + { + npy_intp dims[1], strides[1]; + dims[0] = itemsize; + strides[0] = 1; + descr = PyArray_DescrNewFromType(NPY_BYTE); + u = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + descr, 1, dims, strides, ip, + PyArray_ISWRITEABLE(ap) ? NPY_ARRAY_WRITEABLE : 0, + NULL); + Py_INCREF(ap); + if (PyArray_SetBaseObject(u, (PyObject *)ap) < 0) { + Py_DECREF(u); + return NULL; + } + } +#else + /* + * default is to return buffer object pointing to + * current item a view of it + */ + if (PyArray_ISWRITEABLE(ap)) { + if (array_might_be_written(ap) < 0) { + return NULL; + } + u = (PyArrayObject *)PyBuffer_FromReadWriteMemory(ip, itemsize); + } + else { + u = (PyArrayObject *)PyBuffer_FromMemory(ip, itemsize); + } +#endif + + if (u == NULL) { + return NULL; + } + return (PyObject *)u; +} + + +NPY_NO_EXPORT int PyArray_CopyObject(PyArrayObject *, PyObject *); + +/* Given a structured PyArrayObject arr, index i and structured datatype descr, + * modify the dtype of arr to contain a single field corresponding to the ith + * field of descr, recompute the alignment flag, and return the offset of the + * field (in offset_p). This is useful in preparation for calling copyswap on + * individual fields of a numpy structure, in VOID_setitem. Compare to inner + * loops in VOID_getitem and VOID_nonzero. + * + * WARNING: Clobbers arr's dtype and alignment flag. + */ +NPY_NO_EXPORT int +_setup_field(int i, PyArray_Descr *descr, PyArrayObject *arr, + npy_intp *offset_p) +{ + PyObject *key; + PyObject *tup; + PyArray_Descr *new; + npy_intp offset; + + key = PyTuple_GET_ITEM(descr->names, i); + tup = PyDict_GetItem(descr->fields, key); + if (_unpack_field(tup, &new, &offset) < 0) { + return -1; + } + + ((PyArrayObject_fields *)(arr))->descr = new; + if ((new->alignment > 1) && ((offset % new->alignment) != 0)) { + PyArray_CLEARFLAGS(arr, NPY_ARRAY_ALIGNED); + } + else { + PyArray_ENABLEFLAGS(arr, NPY_ARRAY_ALIGNED); + } + + *offset_p = offset; + return 0; +} + +/* Helper function for VOID_setitem, which uses the copyswap or casting code to + * copy structured datatypes between numpy arrays or scalars. + */ +static int +_copy_and_return_void_setitem(PyArray_Descr *dstdescr, char *dstdata, + PyArray_Descr *srcdescr, char *srcdata){ + PyArrayObject_fields dummy_struct; + PyArrayObject *dummy = (PyArrayObject *)&dummy_struct; + npy_int names_size = PyTuple_GET_SIZE(dstdescr->names); + npy_intp offset; + npy_int i; + int ret; + + /* Fast path if dtypes are equal */ + if (PyArray_EquivTypes(srcdescr, dstdescr)) { + for (i = 0; i < names_size; i++) { + /* neither line can ever fail, in principle */ + if (_setup_field(i, dstdescr, dummy, &offset)) { + return -1; + } + PyArray_DESCR(dummy)->f->copyswap(dstdata + offset, + srcdata + offset, 0, dummy); + } + return 0; + } + + /* Slow path */ + ret = PyArray_CastRawArrays(1, srcdata, dstdata, 0, 0, + srcdescr, dstdescr, 0); + if (ret != NPY_SUCCEED) { + return -1; + } + return 0; +} + +static int +VOID_setitem(PyObject *op, void *input, void *vap) +{ + char *ip = input; + PyArrayObject *ap = vap; + PyArray_Descr *descr; + int flags; + int itemsize=PyArray_DESCR(ap)->elsize; + int res; + + descr = PyArray_DESCR(ap); + flags = PyArray_FLAGS(ap); + if (PyDataType_HASFIELDS(descr)) { + PyObject *errmsg; + npy_int i; + npy_intp offset; + int failed = 0; + + /* If op is 0d-ndarray or numpy scalar, directly get dtype & data ptr */ + if (PyArray_Check(op)) { + PyArrayObject *oparr = (PyArrayObject *)op; + if (PyArray_SIZE(oparr) != 1) { + PyErr_SetString(PyExc_ValueError, + "setting an array element with a sequence."); + return -1; + } + return _copy_and_return_void_setitem(descr, ip, + PyArray_DESCR(oparr), PyArray_DATA(oparr)); + } + else if (PyArray_IsScalar(op, Void)) { + PyArray_Descr *srcdescr = ((PyVoidScalarObject *)op)->descr; + char *srcdata = ((PyVoidScalarObject *)op)->obval; + return _copy_and_return_void_setitem(descr, ip, srcdescr, srcdata); + } + else if (PyTuple_Check(op)) { + /* if it's a tuple, copy field-by-field to ap, */ + npy_intp names_size = PyTuple_GET_SIZE(descr->names); + + if (names_size != PyTuple_Size(op)) { + errmsg = PyUString_FromFormat( + "could not assign tuple of length %zd to structure " + "with %" NPY_INTP_FMT " fields.", + PyTuple_Size(op), names_size); + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + return -1; + } + + for (i = 0; i < names_size; i++) { + PyObject *item; + + /* temporarily make ap have only this field */ + if (_setup_field(i, descr, ap, &offset) == -1) { + failed = 1; + break; + } + item = PyTuple_GetItem(op, i); + if (item == NULL) { + failed = 1; + break; + } + /* use setitem to set this field */ + if (PyArray_SETITEM(ap, ip + offset, item) < 0) { + failed = 1; + break; + } + } + } + else { + /* Otherwise must be non-void scalar. Try to assign to each field */ + npy_intp names_size = PyTuple_GET_SIZE(descr->names); + + for (i = 0; i < names_size; i++) { + /* temporarily make ap have only this field */ + if (_setup_field(i, descr, ap, &offset) == -1) { + failed = 1; + break; + } + /* use setitem to set this field */ + if (PyArray_SETITEM(ap, ip + offset, op) < 0) { + failed = 1; + break; + } + } + } + + /* reset clobbered attributes */ + ((PyArrayObject_fields *)(ap))->descr = descr; + ((PyArrayObject_fields *)(ap))->flags = flags; + + if (failed) { + return -1; + } + return 0; + } + else if (PyDataType_HASSUBARRAY(descr)) { + /* copy into an array of the same basic type */ + PyArray_Dims shape = {NULL, -1}; + PyArrayObject *ret; + if (!(PyArray_IntpConverter(descr->subarray->shape, &shape))) { + npy_free_cache_dim_obj(shape); + PyErr_SetString(PyExc_ValueError, + "invalid shape in fixed-type tuple."); + return -1; + } + Py_INCREF(descr->subarray->base); + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + descr->subarray->base, shape.len, shape.ptr, + NULL, ip, PyArray_FLAGS(ap), NULL); + npy_free_cache_dim_obj(shape); + if (!ret) { + return -1; + } + Py_INCREF(ap); + if (PyArray_SetBaseObject(ret, (PyObject *)ap) < 0) { + Py_DECREF(ret); + return -1; + } + PyArray_UpdateFlags(ret, NPY_ARRAY_UPDATE_ALL); + res = PyArray_CopyObject(ret, op); + Py_DECREF(ret); + return res; + } + + /* + * Fall through case - non-structured void datatype. This is a very + * undiscerning case: It interprets any object as a buffer + * and reads as many bytes as possible, padding with 0. + */ + { + const void *buffer; + Py_ssize_t buflen; + res = PyObject_AsReadBuffer(op, &buffer, &buflen); + if (res == -1) { + return -1; + } + memcpy(ip, buffer, PyArray_MIN(buflen, itemsize)); + if (itemsize > buflen) { + memset(ip + buflen, 0, itemsize - buflen); + } + } + return 0; +} + +static PyObject * +DATETIME_getitem(void *ip, void *vap) +{ + PyArrayObject *ap = vap; + npy_datetime dt; + PyArray_DatetimeMetaData *meta = NULL; + + /* Get the datetime units metadata */ + meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap)); + if (meta == NULL) { + return NULL; + } + + if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) { + dt = *((npy_datetime *)ip); + } + else { + PyArray_DESCR(ap)->f->copyswap(&dt, ip, PyArray_ISBYTESWAPPED(ap), ap); + } + + return convert_datetime_to_pyobject(dt, meta); +} + + +static PyObject * +TIMEDELTA_getitem(void *ip, void *vap) +{ + PyArrayObject *ap = vap; + npy_timedelta td; + PyArray_DatetimeMetaData *meta = NULL; + + /* Get the datetime units metadata */ + meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap)); + if (meta == NULL) { + return NULL; + } + + if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) { + td = *((npy_timedelta *)ip); + } + else { + PyArray_DESCR(ap)->f->copyswap(&td, ip, PyArray_ISBYTESWAPPED(ap), ap); + } + + return convert_timedelta_to_pyobject(td, meta); +} + +static int +DATETIME_setitem(PyObject *op, void *ov, void *vap) +{ + PyArrayObject *ap = vap; + /* ensure alignment */ + npy_datetime temp = 0; + PyArray_DatetimeMetaData *meta = NULL; + + /* Get the datetime units metadata */ + meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap)); + if (meta == NULL) { + return -1; + } + + /* Convert the object into a NumPy datetime */ + if (convert_pyobject_to_datetime(meta, op, + NPY_SAME_KIND_CASTING, &temp) < 0) { + return -1; + } + + /* Copy the value into the output */ + if (ap == NULL || PyArray_ISBEHAVED(ap)) { + *((npy_datetime *)ov)=temp; + } + else { + PyArray_DESCR(ap)->f->copyswap(ov, &temp, PyArray_ISBYTESWAPPED(ap), + ap); + } + + return 0; +} + +static int +TIMEDELTA_setitem(PyObject *op, void *ov, void *vap) +{ + PyArrayObject *ap = vap; + /* ensure alignment */ + npy_timedelta temp = 0; + PyArray_DatetimeMetaData *meta = NULL; + + /* Get the datetime units metadata */ + meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap)); + if (meta == NULL) { + return -1; + } + + /* Convert the object into a NumPy datetime */ + if (convert_pyobject_to_timedelta(meta, op, + NPY_SAME_KIND_CASTING, &temp) < 0) { + return -1; + } + + /* Copy the value into the output */ + if (ap == NULL || PyArray_ISBEHAVED(ap)) { + *((npy_timedelta *)ov)=temp; + } + else { + PyArray_DESCR(ap)->f->copyswap(ov, &temp, PyArray_ISBYTESWAPPED(ap), + ap); + } + + return 0; +} + + +/* + ***************************************************************************** + ** TYPE TO TYPE CONVERSIONS ** + ***************************************************************************** + */ + + +/* Assumes contiguous, and aligned, from and to */ + + +/**begin repeat + * + * #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, DATETIME, + * TIMEDELTA# + * #totype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + */ + +/**begin repeat1 + * + * #FROMTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, DATETIME, + * TIMEDELTA# + * #fromtype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + */ +static void +@FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const @fromtype@ *ip = input; + @totype@ *op = output; + + while (n--) { + *op++ = (@totype@)*ip++; + } +} +/**end repeat1**/ + +/**begin repeat1 + * + * #FROMTYPE = CFLOAT, CDOUBLE, CLONGDOUBLE# + * #fromtype = npy_float, npy_double, npy_longdouble# + */ +static void +@FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const @fromtype@ *ip = input; + @totype@ *op = output; + + while (n--) { + *op++ = (@totype@)*ip; + ip += 2; + } +} +/**end repeat1**/ + +/**end repeat**/ + + +/**begin repeat + * + * #TYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, LONGDOUBLE, DATETIME, + * TIMEDELTA# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_longdouble, + * npy_datetime, npy_timedelta# + */ + +static void +@TYPE@_to_HALF(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const @type@ *ip = input; + npy_half *op = output; + + while (n--) { + *op++ = npy_float_to_half((float)(*ip++)); + } +} + +static void +HALF_to_@TYPE@(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const npy_half *ip = input; + @type@ *op = output; + + while (n--) { + *op++ = (@type@)npy_half_to_float(*ip++); + } +} + +/**end repeat**/ +#if NPY_SIZEOF_SHORT == 2 +#define HALF_to_HALF SHORT_to_SHORT +#elif NPY_SIZEOF_INT == 2 +#define HALF_to_HALF INT_to_INT +#endif + +/**begin repeat + * + * #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + * #name = float, double, float, double# + * #itype = npy_uint32, npy_uint64, npy_uint32, npy_uint64# + * #iscomplex = 0, 0, 1, 1# + */ + +static void +@TYPE@_to_HALF(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const @itype@ *ip = input; + npy_half *op = output; + + while (n--) { + *op++ = npy_@name@bits_to_halfbits(*ip); +#if @iscomplex@ + ip += 2; +#else + ip++; +#endif + } +} + +static void +HALF_to_@TYPE@(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const npy_half *ip = input; + @itype@ *op = output; + + while (n--) { + *op++ = npy_halfbits_to_@name@bits(*ip++); +#if @iscomplex@ + *op++ = 0; +#endif + } +} + +/**end repeat**/ + +static void +CLONGDOUBLE_to_HALF(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const npy_longdouble *ip = input; + npy_half *op = output; + + while (n--) { + *op++ = npy_double_to_half((double) (*ip++)); + ip += 2; + } +} + +static void +HALF_to_CLONGDOUBLE(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const npy_half *ip = input; + npy_longdouble *op = output; + + while (n--) { + *op++ = npy_half_to_double(*ip++); + *op++ = 0; + } +} + +/**begin repeat + * + * #FROMTYPE = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * FLOAT, DOUBLE, LONGDOUBLE, + * DATETIME, TIMEDELTA# + * #fromtype = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + */ +static void +@FROMTYPE@_to_BOOL(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const @fromtype@ *ip = input; + npy_bool *op = output; + + while (n--) { + *op++ = (npy_bool)(*ip++ != NPY_FALSE); + } +} +/**end repeat**/ + +static void +HALF_to_BOOL(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const npy_half *ip = input; + npy_bool *op = output; + + while (n--) { + *op++ = (npy_bool)(!npy_half_iszero(*ip++)); + } +} + +/**begin repeat + * + * #FROMTYPE = CFLOAT, CDOUBLE, CLONGDOUBLE# + * #fromtype = npy_cfloat, npy_cdouble, npy_clongdouble# + */ +static void +@FROMTYPE@_to_BOOL(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const @fromtype@ *ip = input; + npy_bool *op = output; + + while (n--) { + *op = (npy_bool)((ip->real != NPY_FALSE) || + (ip->imag != NPY_FALSE)); + op++; + ip++; + } +} +/**end repeat**/ + +/**begin repeat + * #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * DATETIME, TIMEDELTA# + * #totype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + * #one = 1*10, NPY_HALF_ONE, 1*5# + * #zero = 0*10, NPY_HALF_ZERO, 0*5# + */ +static void +BOOL_to_@TOTYPE@(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const npy_bool *ip = input; + @totype@ *op = output; + + while (n--) { + *op++ = (@totype@)((*ip++ != NPY_FALSE) ? @one@ : @zero@); + } +} +/**end repeat**/ + +/**begin repeat + * + * #TOTYPE = CFLOAT, CDOUBLE,CLONGDOUBLE# + * #totype = npy_float, npy_double, npy_longdouble# + */ + +/**begin repeat1 + * #FROMTYPE = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * FLOAT, DOUBLE, LONGDOUBLE, + * DATETIME, TIMEDELTA# + * #fromtype = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + */ +static void +@FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const @fromtype@ *ip = input; + @totype@ *op = output; + + while (n--) { + *op++ = (@totype@)*ip++; + *op++ = 0.0; + } + +} +/**end repeat1**/ +/**end repeat**/ + +/**begin repeat + * + * #TOTYPE = CFLOAT,CDOUBLE,CLONGDOUBLE# + * #totype = npy_float, npy_double, npy_longdouble# + */ + +/**begin repeat1 + * #FROMTYPE = CFLOAT,CDOUBLE,CLONGDOUBLE# + * #fromtype = npy_float, npy_double, npy_longdouble# + */ +static void +@FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *NPY_UNUSED(aop)) +{ + const @fromtype@ *ip = input; + @totype@ *op = output; + + n <<= 1; + while (n--) { + *op++ = (@totype@)*ip++; + } +} + +/**end repeat1**/ +/**end repeat**/ + +/**begin repeat + * + * #FROMTYPE = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * STRING, UNICODE, VOID, OBJECT, + * DATETIME, TIMEDELTA# + * #fromtype = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble, + * npy_char, npy_char, npy_char, PyObject *, + * npy_datetime, npy_timedelta# + * #skip = 1*18, PyArray_DESCR(aip)->elsize*3, 1*3# + */ +static void +@FROMTYPE@_to_OBJECT(void *input, void *output, npy_intp n, + void *vaip, void *NPY_UNUSED(aop)) +{ + @fromtype@ *ip = input; + PyObject **op = output; + PyArrayObject *aip = vaip; + + npy_intp i; + int skip = @skip@; + PyObject *tmp; + for (i = 0; i < n; i++, ip +=skip, op++) { + tmp = *op; + *op = @FROMTYPE@_getitem(ip, aip); + Py_XDECREF(tmp); + } +} +/**end repeat**/ + +#define _NPY_UNUSEDBOOL NPY_UNUSED +#define _NPY_UNUSEDBYTE NPY_UNUSED +#define _NPY_UNUSEDUBYTE NPY_UNUSED +#define _NPY_UNUSEDSHORT NPY_UNUSED +#define _NPY_UNUSEDUSHORT NPY_UNUSED +#define _NPY_UNUSEDINT NPY_UNUSED +#define _NPY_UNUSEDUINT NPY_UNUSED +#define _NPY_UNUSEDLONG NPY_UNUSED +#define _NPY_UNUSEDULONG NPY_UNUSED +#define _NPY_UNUSEDLONGLONG NPY_UNUSED +#define _NPY_UNUSEDULONGLONG NPY_UNUSED +#define _NPY_UNUSEDHALF NPY_UNUSED +#define _NPY_UNUSEDFLOAT NPY_UNUSED +#define _NPY_UNUSEDDOUBLE NPY_UNUSED +#define _NPY_UNUSEDLONGDOUBLE NPY_UNUSED +#define _NPY_UNUSEDCFLOAT NPY_UNUSED +#define _NPY_UNUSEDCDOUBLE NPY_UNUSED +#define _NPY_UNUSEDCLONGDOUBLE NPY_UNUSED +#define _NPY_UNUSEDDATETIME NPY_UNUSED +#define _NPY_UNUSEDTIMEDELTA NPY_UNUSED +#define _NPY_UNUSEDHALF NPY_UNUSED +#define _NPY_UNUSEDSTRING +#define _NPY_UNUSEDVOID +#define _NPY_UNUSEDUNICODE + +/**begin repeat + * + * #TOTYPE = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * STRING, UNICODE, VOID, + * DATETIME, TIMEDELTA# + * #totype = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble, + * npy_char, npy_char, npy_char, + * npy_datetime, npy_timedelta# + * #skip = 1*18, PyArray_DESCR(aop)->elsize*3, 1*2# + */ +static void +OBJECT_to_@TOTYPE@(void *input, void *output, npy_intp n, + void *NPY_UNUSED(aip), void *aop) +{ + PyObject **ip = input; + @totype@ *op = output; + + npy_intp i; + int skip = @skip@; + + for (i = 0; i < n; i++, ip++, op += skip) { + if (*ip == NULL) { + @TOTYPE@_setitem(Py_False, op, aop); + } + else { + @TOTYPE@_setitem(*ip, op, aop); + } + } +} +/**end repeat**/ + + +/**begin repeat + * + * #from = STRING*23, UNICODE*23, VOID*23# + * #fromtyp = npy_char*69# + * #to = (BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * STRING, UNICODE, VOID, + * DATETIME, TIMEDELTA)*3# + * #totyp = (npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble, + * npy_char, npy_char, npy_char, + * npy_datetime, npy_timedelta)*3# + * #oskip = 1*18,(PyArray_DESCR(aop)->elsize)*3,1*2, + * 1*18,(PyArray_DESCR(aop)->elsize)*3,1*2, + * 1*18,(PyArray_DESCR(aop)->elsize)*3,1*2# + * #convert = 1*18, 0*3, 1*2, + * 1*18, 0*3, 1*2, + * 0*23# + * #convstr = (Int*9, Long*2, Float*4, Complex*3, Tuple*3, Long*2)*3# + */ + +#if @convert@ + +#define IS_@from@ + +static void +@from@_to_@to@(void *input, void *output, npy_intp n, + void *vaip, void *aop) +{ + @fromtyp@ *ip = input; + @totyp@ *op = output; + PyArrayObject *aip = vaip; + + npy_intp i; + int skip = PyArray_DESCR(aip)->elsize; + int oskip = @oskip@; + + for (i = 0; i < n; i++, ip+=skip, op+=oskip) { + PyObject *new; + PyObject *temp = PyArray_Scalar(ip, PyArray_DESCR(aip), (PyObject *)aip); + if (temp == NULL) { + return; + } + +#if defined(NPY_PY3K) && defined(IS_STRING) + /* Work around some Python 3K */ + new = PyUnicode_FromEncodedObject(temp, "ascii", "strict"); + Py_DECREF(temp); + temp = new; + if (temp == NULL) { + return; + } +#endif + /* convert from Python object to needed one */ + { + PyObject *args; + + /* call out to the Python builtin given by convstr */ + args = Py_BuildValue("(N)", temp); +#if defined(NPY_PY3K) +#define PyInt_Type PyLong_Type +#endif + new = Py@convstr@_Type.tp_new(&Py@convstr@_Type, args, NULL); +#if defined(NPY_PY3K) +#undef PyInt_Type +#endif + Py_DECREF(args); + temp = new; + if (temp == NULL) { + return; + } + } + + if (@to@_setitem(temp, op, aop)) { + Py_DECREF(temp); + return; + } + Py_DECREF(temp); + } +} + +#undef IS_@from@ + +#else + +static void +@from@_to_@to@(void *input, void *output, npy_intp n, + void *vaip, void *aop) +{ + @fromtyp@ *ip = input; + @totyp@ *op = output; + PyArrayObject *aip = vaip; + + npy_intp i; + int skip = PyArray_DESCR(aip)->elsize; + int oskip = @oskip@; + + for (i = 0; i < n; i++, ip+=skip, op+=oskip) { + PyObject *temp = PyArray_Scalar(ip, PyArray_DESCR(aip), (PyObject *)aip); + if (temp == NULL) { + return; + } + if (@to@_setitem(temp, op, aop)) { + Py_DECREF(temp); + return; + } + Py_DECREF(temp); + } +} + +#endif + +/**end repeat**/ + + +/**begin repeat + * + * #to = STRING*20, UNICODE*20, VOID*20# + * #totyp = npy_char*20, npy_char*20, npy_char*20# + * #from = (BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * DATETIME, TIMEDELTA)*3# + * #fromtyp = (npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble, + * npy_datetime, npy_timedelta)*3# + */ +static void +@from@_to_@to@(void *input, void *output, npy_intp n, + void *vaip, void *vaop) +{ + @fromtyp@ *ip = input; + @totyp@ *op = output; + PyArrayObject *aip = vaip; + PyArrayObject *aop = vaop; + + npy_intp i; + PyObject *temp = NULL; + int skip = 1; + int oskip = PyArray_DESCR(aop)->elsize; + for (i = 0; i < n; i++, ip += skip, op += oskip) { + temp = PyArray_Scalar(ip, PyArray_DESCR(aip), (PyObject *)aip); + if (temp == NULL) { + Py_INCREF(Py_False); + temp = Py_False; + } + if (@to@_setitem(temp, op, aop)) { + Py_DECREF(temp); + return; + } + Py_DECREF(temp); + } +} + +/**end repeat**/ + + +/* + ***************************************************************************** + ** SCAN ** + ***************************************************************************** + */ + + +/* + * The first ignore argument is for backwards compatibility. + * Should be removed when the API version is bumped up. + */ + +/**begin repeat + * #fname = SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG# + * #type = npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong# + * #format = "hd", "hu", "d", "u", + * "ld", "lu", NPY_LONGLONG_FMT, NPY_ULONGLONG_FMT# + */ +static int +@fname@_scan(FILE *fp, @type@ *ip, void *NPY_UNUSED(ignore), + PyArray_Descr *NPY_UNUSED(ignored)) +{ + return fscanf(fp, "%"@format@, ip); +} +/**end repeat**/ + +/**begin repeat + * #fname = FLOAT, DOUBLE# + * #type = npy_float, npy_double# + */ +static int +@fname@_scan(FILE *fp, @type@ *ip, void *NPY_UNUSED(ignore), + PyArray_Descr *NPY_UNUSED(ignored)) +{ + double result; + int ret; + + ret = NumPyOS_ascii_ftolf(fp, &result); + *ip = (@type@) result; + return ret; +} +/**end repeat**/ + +static int +LONGDOUBLE_scan(FILE *fp, npy_longdouble *ip, void *NPY_UNUSED(ignore), + PyArray_Descr *NPY_UNUSED(ignored)) +{ + long double result; + int ret; + + ret = NumPyOS_ascii_ftoLf(fp, &result); + *ip = (npy_longdouble) result; + return ret; +} + +static int +HALF_scan(FILE *fp, npy_half *ip, void *NPY_UNUSED(ignore), + PyArray_Descr *NPY_UNUSED(ignored)) +{ + double result; + int ret; + + ret = NumPyOS_ascii_ftolf(fp, &result); + *ip = npy_double_to_half(result); + return ret; +} + +/**begin repeat + * #fname = BYTE, UBYTE# + * #type = npy_byte, npy_ubyte# + * #btype = npy_int, npy_uint# + * #format = "d", "u"# + */ +static int +@fname@_scan(FILE *fp, @type@ *ip, void *NPY_UNUSED(ignore), + PyArray_Descr *NPY_UNUSED(ignore2)) +{ + @btype@ temp; + int num; + + num = fscanf(fp, "%"@format@, &temp); + *ip = (@type@) temp; + return num; +} +/**end repeat**/ + +static int +BOOL_scan(FILE *fp, npy_bool *ip, void *NPY_UNUSED(ignore), + PyArray_Descr *NPY_UNUSED(ignore2)) +{ + double result; + int ret; + + ret = NumPyOS_ascii_ftolf(fp, &result); + *ip = (npy_bool) (result != 0.0); + return ret; +} + +/**begin repeat + * #fname = CFLOAT, CDOUBLE, CLONGDOUBLE, + * OBJECT, STRING, UNICODE, VOID, + * DATETIME, TIMEDELTA# + */ + +#define @fname@_scan NULL + +/**end repeat**/ + + +/* + ***************************************************************************** + ** FROMSTR ** + ***************************************************************************** + */ + + +/**begin repeat + * #fname = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * DATETIME, TIMEDELTA# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_datetime, npy_timedelta# + * #func = (PyOS_strtol, PyOS_strtoul)*4, npy_strtoll, npy_strtoull, + * npy_strtoll*2# + * #btype = (npy_long, npy_ulong)*4, npy_longlong, npy_ulonglong, + * npy_longlong*2# + */ +static int +@fname@_fromstr(char *str, void *ip, char **endptr, + PyArray_Descr *NPY_UNUSED(ignore)) +{ + @btype@ result; + + result = @func@(str, endptr, 10); + *(@type@ *)ip = result; + return 0; +} +/**end repeat**/ + +/**begin repeat + * + * #fname = FLOAT, DOUBLE# + * #type = npy_float, npy_double# + */ +static int +@fname@_fromstr(char *str, void *ip, char **endptr, + PyArray_Descr *NPY_UNUSED(ignore)) +{ + double result; + + result = NumPyOS_ascii_strtod(str, endptr); + *(@type@ *)ip = result; + return 0; +} +/**end repeat**/ + +static int +LONGDOUBLE_fromstr(char *str, void *ip, char **endptr, + PyArray_Descr *NPY_UNUSED(ignore)) +{ + long double result; + + result = NumPyOS_ascii_strtold(str, endptr); + *(npy_longdouble *)ip = result; + return 0; +} + +static int +HALF_fromstr(char *str, void *ip, char **endptr, + PyArray_Descr *NPY_UNUSED(ignore)) +{ + double result; + + result = NumPyOS_ascii_strtod(str, endptr); + *(npy_half *)ip = npy_double_to_half(result); + return 0; +} + +static int +BOOL_fromstr(char *str, void *ip, char **endptr, + PyArray_Descr *NPY_UNUSED(ignore)) +{ + double result; + + result = NumPyOS_ascii_strtod(str, endptr); + *(npy_bool *)ip = (result != 0.0); + return 0; +} + +/**begin repeat + * #fname = CFLOAT, CDOUBLE, CLONGDOUBLE, + * OBJECT, STRING, UNICODE, VOID# + */ + +#define @fname@_fromstr NULL + +/**end repeat**/ + + +/* + ***************************************************************************** + ** COPYSWAPN ** + ***************************************************************************** + */ + + +static NPY_INLINE void +_basic_copyn(void *dst, npy_intp dstride, void *src, npy_intp sstride, + npy_intp n, int elsize) { + if (src == NULL) { + return; + } + if (sstride == elsize && dstride == elsize) { + memcpy(dst, src, n*elsize); + } + else { + _unaligned_strided_byte_copy(dst, dstride, src, sstride, + n, elsize); + } +} + +static NPY_INLINE void +_basic_copy(void *dst, void *src, int elsize) { + if (src == NULL) { + return; + } + memcpy(dst, src, elsize); +} + + +/**begin repeat + * + * #fname = SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * DATETIME, TIMEDELTA# + * #fsize = SHORT, SHORT, INT, INT, + * LONG, LONG, LONGLONG, LONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * DATETIME, TIMEDELTA# + * #type = npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + */ +static void +@fname@_copyswapn (void *dst, npy_intp dstride, void *src, npy_intp sstride, + npy_intp n, int swap, void *NPY_UNUSED(arr)) +{ + /* copy first if needed */ + _basic_copyn(dst, dstride, src, sstride, n, sizeof(@type@)); + if (swap) { + _strided_byte_swap(dst, dstride, n, sizeof(@type@)); + } +} + +static void +@fname@_copyswap (void *dst, void *src, int swap, void *NPY_UNUSED(arr)) +{ + /* copy first if needed */ + _basic_copy(dst, src, sizeof(@type@)); + + if (swap) { + char *a, *b, c; + + a = (char *)dst; +#if NPY_SIZEOF_@fsize@ == 2 + b = a + 1; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 4 + b = a + 3; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 8 + b = a + 7; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 10 + b = a + 9; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 12 + b = a + 11; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 16 + b = a + 15; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#else + { + int i, nn; + + b = a + (NPY_SIZEOF_@fsize@-1); + nn = NPY_SIZEOF_@fsize@ / 2; + for (i = 0; i < nn; i++) { + c = *a; + *a++ = *b; + *b-- = c; + } + } +#endif + } +} + +/**end repeat**/ + +/**begin repeat + * + * #fname = BOOL, + * BYTE, UBYTE# + * #type = npy_bool, + * npy_byte, npy_ubyte# + */ +static void +@fname@_copyswapn (void *dst, npy_intp dstride, void *src, npy_intp sstride, + npy_intp n, int NPY_UNUSED(swap), void *NPY_UNUSED(arr)) +{ + /* copy first if needed */ + _basic_copyn(dst, dstride, src, sstride, n, sizeof(@type@)); + /* ignore swap */ +} + +static void +@fname@_copyswap (void *dst, void *src, int NPY_UNUSED(swap), + void *NPY_UNUSED(arr)) +{ + /* copy first if needed */ + _basic_copy(dst, src, sizeof(@type@)); + /* ignore swap */ +} + +/**end repeat**/ + + + +/**begin repeat + * + * #fname = CFLOAT, CDOUBLE, CLONGDOUBLE# + * #fsize = FLOAT, DOUBLE, LONGDOUBLE# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# +*/ +static void +@fname@_copyswapn (void *dst, npy_intp dstride, void *src, npy_intp sstride, + npy_intp n, int swap, void *NPY_UNUSED(arr)) +{ + /* copy first if needed */ + _basic_copyn(dst, dstride, src, sstride, n, sizeof(@type@)); + + if (swap) { + _strided_byte_swap(dst, dstride, n, NPY_SIZEOF_@fsize@); + _strided_byte_swap(((char *)dst + NPY_SIZEOF_@fsize@), dstride, + n, NPY_SIZEOF_@fsize@); + } +} + +static void +@fname@_copyswap (void *dst, void *src, int swap, void *NPY_UNUSED(arr)) +{ + /* copy first if needed */ + _basic_copy(dst, src, sizeof(@type@)); + + if (swap) { + char *a, *b, c; + a = (char *)dst; +#if NPY_SIZEOF_@fsize@ == 4 + b = a + 3; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; + a += 2; + b = a + 3; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 8 + b = a + 7; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; + a += 4; + b = a + 7; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 10 + b = a + 9; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; + a += 5; + b = a + 9; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 12 + b = a + 11; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; + a += 6; + b = a + 11; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#elif NPY_SIZEOF_@fsize@ == 16 + b = a + 15; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; + a += 8; + b = a + 15; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b = c; +#else + { + int i, nn; + + b = a + (NPY_SIZEOF_@fsize@ - 1); + nn = NPY_SIZEOF_@fsize@ / 2; + for (i = 0; i < nn; i++) { + c = *a; + *a++ = *b; + *b-- = c; + } + a += nn; + b = a + (NPY_SIZEOF_@fsize@ - 1); + for (i = 0; i < nn; i++) { + c = *a; + *a++ = *b; + *b-- = c; + } + } +#endif + } +} + +/**end repeat**/ + +static void +OBJECT_copyswapn(PyObject **dst, npy_intp dstride, PyObject **src, + npy_intp sstride, npy_intp n, int NPY_UNUSED(swap), + void *NPY_UNUSED(arr)) +{ + npy_intp i; + if (src != NULL) { + if (__ALIGNED(dst, sizeof(PyObject **)) + && __ALIGNED(src, sizeof(PyObject **)) + && __ALIGNED(dstride, sizeof(PyObject **)) + && __ALIGNED(sstride, sizeof(PyObject **))) { + dstride /= sizeof(PyObject **); + sstride /= sizeof(PyObject **); + for (i = 0; i < n; i++) { + Py_XINCREF(*src); + Py_XDECREF(*dst); + *dst = *src; + dst += dstride; + src += sstride; + } + } + else { + unsigned char *dstp, *srcp; + PyObject *tmp; + dstp = (unsigned char*)dst; + srcp = (unsigned char*)src; + for (i = 0; i < n; i++) { + NPY_COPY_PYOBJECT_PTR(&tmp, srcp); + Py_XINCREF(tmp); + NPY_COPY_PYOBJECT_PTR(&tmp, dstp); + Py_XDECREF(tmp); + NPY_COPY_PYOBJECT_PTR(dstp, srcp); + dstp += dstride; + srcp += sstride; + } + } + } + /* ignore swap */ + return; +} + +static void +OBJECT_copyswap(PyObject **dst, PyObject **src, int NPY_UNUSED(swap), + void *NPY_UNUSED(arr)) +{ + + if (src != NULL) { + if (__ALIGNED(dst,sizeof(PyObject **)) && + __ALIGNED(src,sizeof(PyObject **))) { + Py_XINCREF(*src); + Py_XDECREF(*dst); + *dst = *src; + } + else { + PyObject *tmp; + NPY_COPY_PYOBJECT_PTR(&tmp, src); + Py_XINCREF(tmp); + NPY_COPY_PYOBJECT_PTR(&tmp, dst); + Py_XDECREF(tmp); + NPY_COPY_PYOBJECT_PTR(dst, src); + } + } +} + +/* ignore swap */ +static void +STRING_copyswapn (char *dst, npy_intp dstride, char *src, npy_intp sstride, + npy_intp n, int NPY_UNUSED(swap), PyArrayObject *arr) +{ + if (arr == NULL) { + return; + } + _basic_copyn(dst, dstride, src, sstride, n, PyArray_DESCR(arr)->elsize); + return; +} + +/* */ +static void +VOID_copyswapn (char *dst, npy_intp dstride, char *src, npy_intp sstride, + npy_intp n, int swap, PyArrayObject *arr) +{ + if (arr == NULL) { + return; + } + if (PyArray_HASFIELDS(arr)) { + PyObject *key, *value; + PyArray_Descr *descr; + Py_ssize_t pos = 0; + + descr = PyArray_DESCR(arr); + while (PyDict_Next(descr->fields, &pos, &key, &value)) { + npy_intp offset; + PyArray_Descr * new; + if (NPY_TITLE_KEY(key, value)) { + continue; + } + if (_unpack_field(value, &new, &offset) < 0) { + ((PyArrayObject_fields *)arr)->descr = descr; + return; + } + /* + * TODO: temporarily modifying the array like this + * is bad coding style, should be changed. + */ + ((PyArrayObject_fields *)arr)->descr = new; + new->f->copyswapn(dst+offset, dstride, + (src != NULL ? src+offset : NULL), + sstride, n, swap, arr); + } + ((PyArrayObject_fields *)arr)->descr = descr; + return; + } + if (swap && PyArray_DESCR(arr)->subarray != NULL) { + PyArray_Descr *descr, *new; + npy_intp num; + npy_intp i; + int subitemsize; + char *dstptr, *srcptr; + + descr = PyArray_DESCR(arr); + new = descr->subarray->base; + /* + * TODO: temporarily modifying the array like this + * is bad coding style, should be changed. + */ + ((PyArrayObject_fields *)arr)->descr = new; + dstptr = dst; + srcptr = src; + subitemsize = new->elsize; + num = descr->elsize / subitemsize; + for (i = 0; i < n; i++) { + new->f->copyswapn(dstptr, subitemsize, srcptr, + subitemsize, num, swap, arr); + dstptr += dstride; + if (srcptr) { + srcptr += sstride; + } + } + ((PyArrayObject_fields *)arr)->descr = descr; + return; + } + _basic_copyn(dst, dstride, src, sstride, n, PyArray_DESCR(arr)->elsize); + return; +} + +static void +VOID_copyswap (char *dst, char *src, int swap, PyArrayObject *arr) +{ + if (arr == NULL) { + return; + } + if (PyArray_HASFIELDS(arr)) { + PyObject *key, *value; + PyArray_Descr *descr; + Py_ssize_t pos = 0; + + descr = PyArray_DESCR(arr); + while (PyDict_Next(descr->fields, &pos, &key, &value)) { + npy_intp offset; + PyArray_Descr * new; + if (NPY_TITLE_KEY(key, value)) { + continue; + } + if (_unpack_field(value, &new, &offset) < 0) { + ((PyArrayObject_fields *)arr)->descr = descr; + return; + } + /* + * TODO: temporarily modifying the array like this + * is bad coding style, should be changed. + */ + ((PyArrayObject_fields *)arr)->descr = new; + new->f->copyswap(dst+offset, + (src != NULL ? src+offset : NULL), + swap, arr); + } + ((PyArrayObject_fields *)arr)->descr = descr; + return; + } + if (swap && PyArray_DESCR(arr)->subarray != NULL) { + PyArray_Descr *descr, *new; + npy_intp num; + int itemsize; + + descr = PyArray_DESCR(arr); + new = descr->subarray->base; + /* + * TODO: temporarily modifying the array like this + * is bad coding style, should be changed. + */ + ((PyArrayObject_fields *)arr)->descr = new; + itemsize = new->elsize; + num = descr->elsize / itemsize; + new->f->copyswapn(dst, itemsize, src, + itemsize, num, swap, arr); + ((PyArrayObject_fields *)arr)->descr = descr; + return; + } + + /* copy first if needed */ + _basic_copy(dst, src, PyArray_DESCR(arr)->elsize); + return; +} + + +static void +UNICODE_copyswapn (char *dst, npy_intp dstride, char *src, npy_intp sstride, + npy_intp n, int swap, PyArrayObject *arr) +{ + int itemsize; + + if (arr == NULL) { + return; + } + itemsize = PyArray_DESCR(arr)->elsize; + _basic_copyn(dst, dstride, src, sstride, n, itemsize); + + if (swap) { + int i; + char *_dst; + itemsize = itemsize / 4; + + while (n > 0) { + _dst = dst; + for (i=0; i < itemsize; i++) { + npy_bswap4_unaligned(_dst); + _dst += 4; + } + dst += dstride; + --n; + } + } +} + + +static void +STRING_copyswap(char *dst, char *src, int NPY_UNUSED(swap), PyArrayObject *arr) +{ + if (arr == NULL) { + return; + } + /* copy first if needed */ + _basic_copy(dst, src, PyArray_DESCR(arr)->elsize); +} + +static void +UNICODE_copyswap (char *dst, char *src, int swap, PyArrayObject *arr) +{ + int itemsize; + + if (arr == NULL) { + return; + } + itemsize = PyArray_DESCR(arr)->elsize; + _basic_copy(dst, src, itemsize); + + if (swap) { + int i; + char *_dst; + itemsize = itemsize / 4; + + _dst = dst; + for (i=0; i < itemsize; i++) { + npy_bswap4_unaligned(_dst); + _dst += 4; + } + } +} + + +/* + ***************************************************************************** + ** NONZERO ** + ***************************************************************************** + */ + +#define _NONZERO(a) ((a) != 0) + +/**begin repeat + * + * #fname = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * DATETIME, TIMEDELTA# + * #type = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + * #isfloat = 0*11, 1*4, 0*2# + * #nonzero = _NONZERO*11, !npy_half_iszero, _NONZERO*5# + */ +static npy_bool +@fname@_nonzero (char *ip, PyArrayObject *ap) +{ + if (ap == NULL || PyArray_ISBEHAVED_RO(ap)) { + @type@ *ptmp = (@type@ *)ip; + return (npy_bool) @nonzero@(*ptmp); + } + else { + /* + * Don't worry about swapping for integer types, + * since we are just testing for equality with 0. + * For float types, the signed zeros require us to swap. + */ + @type@ tmp; +#if @isfloat@ + PyArray_DESCR(ap)->f->copyswap(&tmp, ip, PyArray_ISBYTESWAPPED(ap), + ap); +#else + memcpy(&tmp, ip, sizeof(@type@)); +#endif + return (npy_bool) @nonzero@(tmp); + } +} +/**end repeat**/ + +/**begin repeat + * + * #fname = CFLOAT, CDOUBLE, CLONGDOUBLE# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# + */ +static npy_bool +@fname@_nonzero (char *ip, PyArrayObject *ap) +{ + if (ap == NULL || PyArray_ISBEHAVED_RO(ap)) { + @type@ *ptmp = (@type@ *)ip; + return (npy_bool) ((ptmp->real != 0) || (ptmp->imag != 0)); + } + else { + @type@ tmp; + PyArray_DESCR(ap)->f->copyswap(&tmp, ip, PyArray_ISBYTESWAPPED(ap), + ap); + return (npy_bool) ((tmp.real != 0) || (tmp.imag != 0)); + } +} +/**end repeat**/ + + +#define WHITESPACE " \t\n\r\v\f" +#define WHITELEN 6 + +static npy_bool +Py_STRING_ISSPACE(char ch) +{ + char white[] = WHITESPACE; + int j; + npy_bool space = NPY_FALSE; + + for (j = 0; j < WHITELEN; j++) { + if (ch == white[j]) { + space = NPY_TRUE; + break; + } + } + return space; +} + +static npy_bool +STRING_nonzero (char *ip, PyArrayObject *ap) +{ + int len = PyArray_DESCR(ap)->elsize; + int i; + npy_bool nonz = NPY_FALSE; + npy_bool seen_null = NPY_FALSE; + + for (i = 0; i < len; i++) { + if (*ip == '\0') { + seen_null = NPY_TRUE; + } + else if (seen_null || !Py_STRING_ISSPACE(*ip)) { + nonz = NPY_TRUE; + break; + } + ip++; + } + return nonz; +} + +#ifdef Py_UNICODE_WIDE +#define PyArray_UCS4_ISSPACE Py_UNICODE_ISSPACE +#else +#define PyArray_UCS4_ISSPACE(ch) Py_STRING_ISSPACE((char)ch) +#endif + +static npy_bool +UNICODE_nonzero (npy_ucs4 *ip, PyArrayObject *ap) +{ + int len = PyArray_DESCR(ap)->elsize >> 2; + int i; + npy_bool nonz = NPY_FALSE; + npy_bool seen_null = NPY_FALSE; + char *buffer = NULL; + + if (PyArray_ISBYTESWAPPED(ap) || !PyArray_ISALIGNED(ap)) { + buffer = PyArray_malloc(PyArray_DESCR(ap)->elsize); + if (buffer == NULL) { + return nonz; + } + memcpy(buffer, ip, PyArray_DESCR(ap)->elsize); + if (PyArray_ISBYTESWAPPED(ap)) { + byte_swap_vector(buffer, len, 4); + } + ip = (npy_ucs4 *)buffer; + } + + for (i = 0; i < len; i++) { + if (*ip == '\0') { + seen_null = NPY_TRUE; + } + else if (seen_null || !PyArray_UCS4_ISSPACE(*ip)) { + nonz = NPY_TRUE; + break; + } + ip++; + } + PyArray_free(buffer); + return nonz; +} + +static npy_bool +OBJECT_nonzero (PyObject **ip, PyArrayObject *ap) +{ + + if (PyArray_ISALIGNED(ap)) { + if (*ip == NULL) { + return NPY_FALSE; + } + return (npy_bool) PyObject_IsTrue(*ip); + } + else { + PyObject *obj; + NPY_COPY_PYOBJECT_PTR(&obj, ip); + if (obj == NULL) { + return NPY_FALSE; + } + return (npy_bool) PyObject_IsTrue(obj); + } +} + +/* + * if we have fields, then nonzero only if all sub-fields are nonzero. + */ +static npy_bool +VOID_nonzero (char *ip, PyArrayObject *ap) +{ + int i; + int len; + npy_bool nonz = NPY_FALSE; + + if (PyArray_HASFIELDS(ap)) { + PyArray_Descr *descr; + PyObject *key, *value; + int savedflags; + Py_ssize_t pos = 0; + + descr = PyArray_DESCR(ap); + savedflags = PyArray_FLAGS(ap); + while (PyDict_Next(descr->fields, &pos, &key, &value)) { + PyArray_Descr * new; + npy_intp offset; + if (NPY_TITLE_KEY(key, value)) { + continue; + } + if (_unpack_field(value, &new, &offset) < 0) { + PyErr_Clear(); + continue; + } + /* + * TODO: temporarily modifying the array like this + * is bad coding style, should be changed. + */ + ((PyArrayObject_fields *)ap)->descr = new; + ((PyArrayObject_fields *)ap)->flags = savedflags; + if ((new->alignment > 1) && !__ALIGNED(ip + offset, + new->alignment)) { + PyArray_CLEARFLAGS(ap, NPY_ARRAY_ALIGNED); + } + else { + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_ALIGNED); + } + if (new->f->nonzero(ip+offset, ap)) { + nonz = NPY_TRUE; + break; + } + } + ((PyArrayObject_fields *)ap)->descr = descr; + ((PyArrayObject_fields *)ap)->flags = savedflags; + return nonz; + } + len = PyArray_DESCR(ap)->elsize; + for (i = 0; i < len; i++) { + if (*ip != '\0') { + nonz = NPY_TRUE; + break; + } + ip++; + } + return nonz; +} + +#undef __ALIGNED + + +/* + ***************************************************************************** + ** COMPARE ** + ***************************************************************************** + */ + + +/* boolean type */ + +static int +BOOL_compare(npy_bool *ip1, npy_bool *ip2, PyArrayObject *NPY_UNUSED(ap)) +{ + return (*ip1 ? (*ip2 ? 0 : 1) : (*ip2 ? -1 : 0)); +} + + +/* integer types */ + +/**begin repeat + * #TYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * DATETIME, TIMEDELTA# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_datetime, npy_timedelta# + */ + +static int +@TYPE@_compare (@type@ *pa, @type@ *pb, PyArrayObject *NPY_UNUSED(ap)) +{ + const @type@ a = *pa; + const @type@ b = *pb; + + return a < b ? -1 : a == b ? 0 : 1; +} + +/**end repeat**/ + + +/* float types */ + +/* + * The real/complex comparison functions are compatible with the new sort + * order for nans introduced in numpy 1.4.0. All nan values now compare + * larger than non-nan values and are sorted to the end. The comparison + * order is: + * + * Real: [R, nan] + * Complex: [R + Rj, R + nanj, nan + Rj, nan + nanj] + * + * where complex values with the same nan placements are sorted according + * to the non-nan part if it exists. If both the real and imaginary parts + * of complex types are non-nan the order is the same as the real parts + * unless they happen to be equal, in which case the order is that of the + * imaginary parts. + */ + +/**begin repeat + * + * #TYPE = FLOAT, DOUBLE, LONGDOUBLE# + * #type = npy_float, npy_double, npy_longdouble# + */ + +#define LT(a,b) ((a) < (b) || ((b) != (b) && (a) ==(a))) + +static int +@TYPE@_compare(@type@ *pa, @type@ *pb) +{ + const @type@ a = *pa; + const @type@ b = *pb; + int ret; + + if (LT(a,b)) { + ret = -1; + } + else if (LT(b,a)) { + ret = 1; + } + else { + ret = 0; + } + return ret; +} + + +static int +C@TYPE@_compare(@type@ *pa, @type@ *pb) +{ + const @type@ ar = pa[0]; + const @type@ ai = pa[1]; + const @type@ br = pb[0]; + const @type@ bi = pb[1]; + int ret; + + if (ar < br) { + if (ai == ai || bi != bi) { + ret = -1; + } + else { + ret = 1; + } + } + else if (br < ar) { + if (bi == bi || ai != ai) { + ret = 1; + } + else { + ret = -1; + } + } + else if (ar == br || (ar != ar && br != br)) { + if (LT(ai,bi)) { + ret = -1; + } + else if (LT(bi,ai)) { + ret = 1; + } + else { + ret = 0; + } + } + else if (ar == ar) { + ret = -1; + } + else { + ret = 1; + } + + return ret; +} + +#undef LT + +/**end repeat**/ + +static int +HALF_compare (npy_half *pa, npy_half *pb, PyArrayObject *NPY_UNUSED(ap)) +{ + npy_half a = *pa, b = *pb; + npy_bool a_isnan, b_isnan; + int ret; + + a_isnan = npy_half_isnan(a); + b_isnan = npy_half_isnan(b); + + if (a_isnan) { + ret = b_isnan ? 0 : -1; + } + else if (b_isnan) { + ret = 1; + } + else if(npy_half_lt_nonan(a, b)) { + ret = -1; + } + else if(npy_half_lt_nonan(b, a)) { + ret = 1; + } + else { + ret = 0; + } + + return ret; +} + + +/* object type */ + +static int +OBJECT_compare(PyObject **ip1, PyObject **ip2, PyArrayObject *NPY_UNUSED(ap)) +{ + /* + * ALIGNMENT NOTE: It seems that PyArray_Sort is already handling + * the alignment of pointers, so it doesn't need to be handled + * here. + */ + + int ret; + /* + * work around gh-3879, we cannot abort an in-progress quicksort + * so at least do not raise again + */ + if (PyErr_Occurred()) { + return 0; + } + if ((*ip1 == NULL) || (*ip2 == NULL)) { + if (ip1 == ip2) { + return 1; + } + if (ip1 == NULL) { + return -1; + } + return 1; + } + + ret = PyObject_RichCompareBool(*ip1, *ip2, Py_LT); + if (ret < 0) { + /* error occurred, avoid the next call to PyObject_RichCompareBool */ + return 0; + } + if (ret == 1) { + return -1; + } + else if (PyObject_RichCompareBool(*ip1, *ip2, Py_GT) == 1) { + return 1; + } + else { + return 0; + } +} + + +/* string type */ + +static int +STRING_compare(char *ip1, char *ip2, PyArrayObject *ap) +{ + const unsigned char *c1 = (unsigned char *)ip1; + const unsigned char *c2 = (unsigned char *)ip2; + const size_t len = PyArray_DESCR(ap)->elsize; + int i; + + i = memcmp(c1, c2, len); + if (i > 0) { + return 1; + } + else if (i < 0) { + return -1; + } + return 0; +} + + +/* unicode type */ + +static int +UNICODE_compare(npy_ucs4 *ip1, npy_ucs4 *ip2, + PyArrayObject *ap) +{ + int itemsize = PyArray_DESCR(ap)->elsize; + + if (itemsize < 0) { + return 0; + } + itemsize /= sizeof(npy_ucs4); + while (itemsize-- > 0) { + npy_ucs4 c1 = *ip1++; + npy_ucs4 c2 = *ip2++; + if (c1 != c2) { + return (c1 < c2) ? -1 : 1; + } + } + return 0; +} + + +/* void type */ + +/* + * If fields are defined, then compare on first field and if equal + * compare on second field. Continue until done or comparison results + * in not_equal. + * + * Must align data passed on to sub-comparisons. + * Also must swap data based on to sub-comparisons. + */ +static int +VOID_compare(char *ip1, char *ip2, PyArrayObject *ap) +{ + PyArray_Descr *descr; + PyObject *names, *key; + PyObject *tup; + PyArrayObject_fields dummy_struct; + PyArrayObject *dummy = (PyArrayObject *)&dummy_struct; + char *nip1, *nip2; + int i, res = 0, swap = 0; + + if (!PyArray_HASFIELDS(ap)) { + return STRING_compare(ip1, ip2, ap); + } + descr = PyArray_DESCR(ap); + /* + * Compare on the first-field. If equal, then + * compare on the second-field, etc. + */ + names = descr->names; + for (i = 0; i < PyTuple_GET_SIZE(names); i++) { + PyArray_Descr *new; + npy_intp offset; + key = PyTuple_GET_ITEM(names, i); + tup = PyDict_GetItem(descr->fields, key); + if (_unpack_field(tup, &new, &offset) < 0) { + goto finish; + } + /* descr is the only field checked by compare or copyswap */ + dummy_struct.descr = new; + swap = PyArray_ISBYTESWAPPED(dummy); + nip1 = ip1 + offset; + nip2 = ip2 + offset; + if (swap || new->alignment > 1) { + if (swap || !npy_is_aligned(nip1, new->alignment)) { + /* create buffer and copy */ + nip1 = npy_alloc_cache(new->elsize); + if (nip1 == NULL) { + goto finish; + } + memcpy(nip1, ip1 + offset, new->elsize); + if (swap) + new->f->copyswap(nip1, NULL, swap, dummy); + } + if (swap || !npy_is_aligned(nip2, new->alignment)) { + /* create buffer and copy */ + nip2 = npy_alloc_cache(new->elsize); + if (nip2 == NULL) { + if (nip1 != ip1 + offset) { + npy_free_cache(nip1, new->elsize); + } + goto finish; + } + memcpy(nip2, ip2 + offset, new->elsize); + if (swap) + new->f->copyswap(nip2, NULL, swap, dummy); + } + } + res = new->f->compare(nip1, nip2, dummy); + if (swap || new->alignment > 1) { + if (nip1 != ip1 + offset) { + npy_free_cache(nip1, new->elsize); + } + if (nip2 != ip2 + offset) { + npy_free_cache(nip2, new->elsize); + } + } + if (res != 0) { + break; + } + } + +finish: + return res; +} + + +/* + ***************************************************************************** + ** ARGFUNC ** + ***************************************************************************** + */ + +#define _LESS_THAN_OR_EQUAL(a,b) ((a) <= (b)) + +static int +BOOL_argmax(npy_bool *ip, npy_intp n, npy_intp *max_ind, + PyArrayObject *NPY_UNUSED(aip)) + +{ + npy_intp i = 0; + /* memcmp like logical_and on i386 is maybe slower for small arrays */ +#ifdef NPY_HAVE_SSE2_INTRINSICS + const __m128i zero = _mm_setzero_si128(); + for (; i < n - (n % 32); i+=32) { + __m128i d1 = _mm_loadu_si128((__m128i*)&ip[i]); + __m128i d2 = _mm_loadu_si128((__m128i*)&ip[i + 16]); + d1 = _mm_cmpeq_epi8(d1, zero); + d2 = _mm_cmpeq_epi8(d2, zero); + if (_mm_movemask_epi8(_mm_min_epu8(d1, d2)) != 0xFFFF) { + break; + } + } +#endif + for (; i < n; i++) { + if (ip[i]) { + *max_ind = i; + return 0; + } + } + *max_ind = 0; + return 0; +} + +/**begin repeat + * + * #fname = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * DATETIME, TIMEDELTA# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + * #isfloat = 0*10, 1*7, 0*2# + * #isnan = nop*10, npy_half_isnan, npy_isnan*6, nop*2# + * #le = _LESS_THAN_OR_EQUAL*10, npy_half_le, _LESS_THAN_OR_EQUAL*8# + * #iscomplex = 0*14, 1*3, 0*2# + * #incr = ip++*14, ip+=2*3, ip++*2# + */ +static int +@fname@_argmax(@type@ *ip, npy_intp n, npy_intp *max_ind, + PyArrayObject *NPY_UNUSED(aip)) +{ + npy_intp i; + @type@ mp = *ip; +#if @iscomplex@ + @type@ mp_im = ip[1]; +#endif + + *max_ind = 0; + +#if @isfloat@ + if (@isnan@(mp)) { + /* nan encountered; it's maximal */ + return 0; + } +#endif +#if @iscomplex@ + if (@isnan@(mp_im)) { + /* nan encountered; it's maximal */ + return 0; + } +#endif + + for (i = 1; i < n; i++) { + @incr@; + /* + * Propagate nans, similarly as max() and min() + */ +#if @iscomplex@ + /* Lexical order for complex numbers */ + if ((ip[0] > mp) || ((ip[0] == mp) && (ip[1] > mp_im)) + || @isnan@(ip[0]) || @isnan@(ip[1])) { + mp = ip[0]; + mp_im = ip[1]; + *max_ind = i; + if (@isnan@(mp) || @isnan@(mp_im)) { + /* nan encountered, it's maximal */ + break; + } + } +#else + if (!@le@(*ip, mp)) { /* negated, for correct nan handling */ + mp = *ip; + *max_ind = i; +#if @isfloat@ + if (@isnan@(mp)) { + /* nan encountered, it's maximal */ + break; + } +#endif + } +#endif + } + return 0; +} + +/**end repeat**/ + +static int +BOOL_argmin(npy_bool *ip, npy_intp n, npy_intp *min_ind, + PyArrayObject *NPY_UNUSED(aip)) + +{ + npy_bool * p = memchr(ip, 0, n * sizeof(*ip)); + if (p == NULL) { + *min_ind = 0; + return 0; + } + *min_ind = p - ip; + return 0; +} + +/**begin repeat + * + * #fname = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_float, npy_double, npy_longdouble# + * #isfloat = 0*10, 1*7# + * #isnan = nop*10, npy_half_isnan, npy_isnan*6# + * #le = _LESS_THAN_OR_EQUAL*10, npy_half_le, _LESS_THAN_OR_EQUAL*6# + * #iscomplex = 0*14, 1*3# + * #incr = ip++*14, ip+=2*3# + */ +static int +@fname@_argmin(@type@ *ip, npy_intp n, npy_intp *min_ind, + PyArrayObject *NPY_UNUSED(aip)) +{ + npy_intp i; + @type@ mp = *ip; +#if @iscomplex@ + @type@ mp_im = ip[1]; +#endif + + *min_ind = 0; + +#if @isfloat@ + if (@isnan@(mp)) { + /* nan encountered; it's minimal */ + return 0; + } +#endif +#if @iscomplex@ + if (@isnan@(mp_im)) { + /* nan encountered; it's minimal */ + return 0; + } +#endif + + for (i = 1; i < n; i++) { + @incr@; + /* + * Propagate nans, similarly as max() and min() + */ +#if @iscomplex@ + /* Lexical order for complex numbers */ + if ((mp > ip[0]) || ((ip[0] == mp) && (mp_im > ip[1])) + || @isnan@(ip[0]) || @isnan@(ip[1])) { + mp = ip[0]; + mp_im = ip[1]; + *min_ind = i; + if (@isnan@(mp) || @isnan@(mp_im)) { + /* nan encountered, it's minimal */ + break; + } + } +#else + if (!@le@(mp, *ip)) { /* negated, for correct nan handling */ + mp = *ip; + *min_ind = i; +#if @isfloat@ + if (@isnan@(mp)) { + /* nan encountered, it's minimal */ + break; + } +#endif + } +#endif + } + return 0; +} + +/**end repeat**/ + +#undef _LESS_THAN_OR_EQUAL + +/**begin repeat + * + * #fname = DATETIME, TIMEDELTA# + * #type = npy_datetime, npy_timedelta# + */ +static int +@fname@_argmin(@type@ *ip, npy_intp n, npy_intp *min_ind, + PyArrayObject *NPY_UNUSED(aip)) +{ + /* NPY_DATETIME_NAT is smaller than every other value, we skip + * it for consistency with min(). + */ + npy_intp i; + @type@ mp = NPY_DATETIME_NAT; + + i = 0; + while (i < n && mp == NPY_DATETIME_NAT) { + mp = ip[i]; + i++; + } + if (i == n) { + /* All NaTs: return 0 */ + *min_ind = 0; + return 0; + } + *min_ind = i - 1; + for (; i < n; i++) { + if (mp > ip[i] && ip[i] != NPY_DATETIME_NAT) { + mp = ip[i]; + *min_ind = i; + } + } + return 0; +} + +/**end repeat**/ + +static int +OBJECT_argmax(PyObject **ip, npy_intp n, npy_intp *max_ind, + PyArrayObject *NPY_UNUSED(aip)) +{ + npy_intp i; + + *max_ind = 0; + /* Skip over all leading NULL entries */ + for (i = 0; i < n && ip[i] == NULL; ++i); + if (i < n) { + /* Found first non-NULL entry */ + PyObject *mp = ip[i]; + *max_ind = i; + for (i = i + 1; i < n; ++i) { + PyObject *val = ip[i]; + if (val != NULL) { + int greater_than = PyObject_RichCompareBool(val, mp, Py_GT); + + if (greater_than < 0) { + return 0; + } + if (greater_than) { + mp = val; + *max_ind = i; + } + } + } + } + + return 0; +} + +/**begin repeat + * + * #fname = STRING, UNICODE# + * #type = npy_char, npy_ucs4# + */ +static int +@fname@_argmax(@type@ *ip, npy_intp n, npy_intp *max_ind, PyArrayObject *aip) +{ + npy_intp i; + int elsize = PyArray_DESCR(aip)->elsize; + @type@ *mp = (@type@ *)PyArray_malloc(elsize); + + if (mp == NULL) { + return 0; + } + memcpy(mp, ip, elsize); + *max_ind = 0; + for (i = 1; i < n; i++) { + ip += elsize / sizeof(@type@); + if (@fname@_compare(ip, mp, aip) > 0) { + memcpy(mp, ip, elsize); + *max_ind = i; + } + } + PyArray_free(mp); + return 0; +} + +/**end repeat**/ + +#define VOID_argmax NULL + +static int +OBJECT_argmin(PyObject **ip, npy_intp n, npy_intp *min_ind, + PyArrayObject *NPY_UNUSED(aip)) +{ + npy_intp i; + + *min_ind = 0; + /* Skip over all leading NULL entries */ + for (i = 0; i < n && ip[i] == NULL; ++i); + if (i < n) { + /* Found first non-NULL entry */ + PyObject *mp = ip[i]; + *min_ind = i; + for (i = i + 1; i < n ; ++i) { + PyObject *val = ip[i]; + if (val != NULL) { + int less_than = PyObject_RichCompareBool(val, mp, Py_LT); + + if (less_than < 0) { + return 0; + } + if (less_than) { + mp = val; + *min_ind = i; + } + } + } + } + + return 0; +} + +/**begin repeat + * + * #fname = STRING, UNICODE# + * #type = npy_char, npy_ucs4# + */ +static int +@fname@_argmin(@type@ *ip, npy_intp n, npy_intp *min_ind, PyArrayObject *aip) +{ + npy_intp i; + int elsize = PyArray_DESCR(aip)->elsize; + @type@ *mp = (@type@ *)PyArray_malloc(elsize); + + if (mp==NULL) return 0; + memcpy(mp, ip, elsize); + *min_ind = 0; + for(i=1; i 0) { + memcpy(mp, ip, elsize); + *min_ind=i; + } + } + PyArray_free(mp); + return 0; +} + +/**end repeat**/ + + +#define VOID_argmin NULL + + +/* + ***************************************************************************** + ** DOT ** + ***************************************************************************** + */ + +/* + * dot means inner product + */ + +/************************** MAYBE USE CBLAS *********************************/ + + +/**begin repeat + * + * #name = FLOAT, DOUBLE# + * #type = npy_float, npy_double# + * #prefix = s, d# + */ +NPY_NO_EXPORT void +@name@_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, + npy_intp n, void *NPY_UNUSED(ignore)) +{ +#if defined(HAVE_CBLAS) + int is1b = blas_stride(is1, sizeof(@type@)); + int is2b = blas_stride(is2, sizeof(@type@)); + + if (is1b && is2b) + { + double sum = 0.; /* double for stability */ + + while (n > 0) { + int chunk = n < NPY_CBLAS_CHUNK ? n : NPY_CBLAS_CHUNK; + + sum += cblas_@prefix@dot(chunk, + (@type@ *) ip1, is1b, + (@type@ *) ip2, is2b); + /* use char strides here */ + ip1 += chunk * is1; + ip2 += chunk * is2; + n -= chunk; + } + *((@type@ *)op) = (@type@)sum; + } + else +#endif + { + @type@ sum = (@type@)0; /* could make this double */ + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + const @type@ ip1r = *((@type@ *)ip1); + const @type@ ip2r = *((@type@ *)ip2); + + sum += ip1r * ip2r; + } + *((@type@ *)op) = sum; + } +} +/**end repeat**/ + +/**begin repeat + * + * #name = CFLOAT, CDOUBLE# + * #ctype = npy_cfloat, npy_cdouble# + * #type = npy_float, npy_double# + * #prefix = c, z# + */ +NPY_NO_EXPORT void +@name@_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, + char *op, npy_intp n, void *NPY_UNUSED(ignore)) +{ +#if defined(HAVE_CBLAS) + int is1b = blas_stride(is1, sizeof(@ctype@)); + int is2b = blas_stride(is2, sizeof(@ctype@)); + + if (is1b && is2b) { + double sum[2] = {0., 0.}; /* double for stability */ + + while (n > 0) { + int chunk = n < NPY_CBLAS_CHUNK ? n : NPY_CBLAS_CHUNK; + @type@ tmp[2]; + + cblas_@prefix@dotu_sub((int)n, ip1, is1b, ip2, is2b, tmp); + sum[0] += (double)tmp[0]; + sum[1] += (double)tmp[1]; + /* use char strides here */ + ip1 += chunk * is1; + ip2 += chunk * is2; + n -= chunk; + } + ((@type@ *)op)[0] = (@type@)sum[0]; + ((@type@ *)op)[1] = (@type@)sum[1]; + } + else +#endif + { + @type@ sumr = (@type@)0.0; + @type@ sumi = (@type@)0.0; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + const @type@ ip1r = ((@type@ *)ip1)[0]; + const @type@ ip1i = ((@type@ *)ip1)[1]; + const @type@ ip2r = ((@type@ *)ip2)[0]; + const @type@ ip2i = ((@type@ *)ip2)[1]; + + sumr += ip1r * ip2r - ip1i * ip2i; + sumi += ip1r * ip2i + ip1i * ip2r; + } + ((@type@ *)op)[0] = sumr; + ((@type@ *)op)[1] = sumi; + } +} + +/**end repeat**/ + +/**************************** NO CBLAS VERSIONS *****************************/ + +static void +BOOL_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, npy_intp n, + void *NPY_UNUSED(ignore)) +{ + npy_bool tmp = NPY_FALSE; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + if ((*((npy_bool *)ip1) != 0) && (*((npy_bool *)ip2) != 0)) { + tmp = NPY_TRUE; + break; + } + } + *((npy_bool *)op) = tmp; +} + +/**begin repeat + * + * #name = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * LONGDOUBLE, DATETIME, TIMEDELTA# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_longdouble, npy_datetime, npy_timedelta# + * #out = npy_long, npy_ulong, npy_long, npy_ulong, npy_long, npy_ulong, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_longdouble, npy_datetime, npy_timedelta# + */ +static void +@name@_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, npy_intp n, + void *NPY_UNUSED(ignore)) +{ + @out@ tmp = (@out@)0; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + tmp += (@out@)(*((@type@ *)ip1)) * + (@out@)(*((@type@ *)ip2)); + } + *((@type@ *)op) = (@type@) tmp; +} +/**end repeat**/ + +static void +HALF_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, + npy_intp n, void *NPY_UNUSED(ignore)) +{ + float tmp = 0.0f; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + tmp += npy_half_to_float(*((npy_half *)ip1)) * + npy_half_to_float(*((npy_half *)ip2)); + } + *((npy_half *)op) = npy_float_to_half(tmp); +} + +static void +CLONGDOUBLE_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, + char *op, npy_intp n, void *NPY_UNUSED(ignore)) +{ + npy_longdouble tmpr = 0.0L; + npy_longdouble tmpi = 0.0L; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + const npy_longdouble ip1r = ((npy_longdouble *)ip1)[0]; + const npy_longdouble ip1i = ((npy_longdouble *)ip1)[1]; + const npy_longdouble ip2r = ((npy_longdouble *)ip2)[0]; + const npy_longdouble ip2i = ((npy_longdouble *)ip2)[1]; + + tmpr += ip1r * ip2r - ip1i * ip2i; + tmpi += ip1r * ip2i + ip1i * ip2r; + } + ((npy_longdouble *)op)[0] = tmpr; + ((npy_longdouble *)op)[1] = tmpi; +} + +static void +OBJECT_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, npy_intp n, + void *NPY_UNUSED(ignore)) +{ + /* + * ALIGNMENT NOTE: np.dot, np.inner etc. enforce that the array is + * BEHAVED before getting to this point, so unaligned pointers aren't + * handled here. + */ + npy_intp i; + PyObject *tmp1, *tmp2, *tmp = NULL; + PyObject **tmp3; + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + if ((*((PyObject **)ip1) == NULL) || (*((PyObject **)ip2) == NULL)) { + tmp1 = Py_False; + Py_INCREF(Py_False); + } + else { + tmp1 = PyNumber_Multiply(*((PyObject **)ip1), *((PyObject **)ip2)); + if (!tmp1) { + Py_XDECREF(tmp); + return; + } + } + if (i == 0) { + tmp = tmp1; + } + else { + tmp2 = PyNumber_Add(tmp, tmp1); + Py_XDECREF(tmp); + Py_XDECREF(tmp1); + if (!tmp2) { + return; + } + tmp = tmp2; + } + } + tmp3 = (PyObject**) op; + tmp2 = *tmp3; + *((PyObject **)op) = tmp; + Py_XDECREF(tmp2); +} + + +/* + ***************************************************************************** + ** FILL ** + ***************************************************************************** + */ + + +#define BOOL_fill NULL + +/* this requires buffer to be filled with objects or NULL */ +static void +OBJECT_fill(PyObject **buffer, npy_intp length, void *NPY_UNUSED(ignored)) +{ + npy_intp i; + PyObject *start = buffer[0]; + PyObject *delta = buffer[1]; + PyObject *second; + + delta = PyNumber_Subtract(delta, start); + if (!delta) { + return; + } + second = start = PyNumber_Add(start, delta); + if (!start) { + goto finish; + } + buffer += 2; + + for (i = 2; i < length; i++, buffer++) { + start = PyNumber_Add(start, delta); + if (!start) { + goto finish; + } + Py_XDECREF(*buffer); + *buffer = start; + } + +finish: + Py_XDECREF(second); + Py_DECREF(delta); + return; +} + +/**begin repeat + * + * #NAME = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * FLOAT, DOUBLE, LONGDOUBLE, + * DATETIME, TIMEDELTA# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# +*/ +static void +@NAME@_fill(@type@ *buffer, npy_intp length, void *NPY_UNUSED(ignored)) +{ + npy_intp i; + @type@ start = buffer[0]; + @type@ delta = buffer[1]; + + delta -= start; + for (i = 2; i < length; ++i) { + buffer[i] = start + i*delta; + } +} +/**end repeat**/ + +static void +HALF_fill(npy_half *buffer, npy_intp length, void *NPY_UNUSED(ignored)) +{ + npy_intp i; + float start = npy_half_to_float(buffer[0]); + float delta = npy_half_to_float(buffer[1]); + + delta -= start; + for (i = 2; i < length; ++i) { + buffer[i] = npy_float_to_half(start + i*delta); + } +} + +/**begin repeat + * + * #NAME = CFLOAT, CDOUBLE, CLONGDOUBLE# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# +*/ +static void +@NAME@_fill(@type@ *buffer, npy_intp length, void *NPY_UNUSED(ignore)) +{ + npy_intp i; + @type@ start; + @type@ delta; + + start.real = buffer->real; + start.imag = buffer->imag; + delta.real = buffer[1].real; + delta.imag = buffer[1].imag; + delta.real -= start.real; + delta.imag -= start.imag; + buffer += 2; + for (i = 2; i < length; i++, buffer++) { + buffer->real = start.real + i*delta.real; + buffer->imag = start.imag + i*delta.imag; + } +} +/**end repeat**/ + + +/* this requires buffer to be filled with objects or NULL */ +static void +OBJECT_fillwithscalar(PyObject **buffer, npy_intp length, PyObject **value, + void *NPY_UNUSED(ignored)) +{ + npy_intp i; + PyObject *val = *value; + for (i = 0; i < length; i++) { + Py_XINCREF(val); + Py_XDECREF(buffer[i]); + buffer[i] = val; + } +} +/**begin repeat + * + * #NAME = BOOL, BYTE, UBYTE# + * #type = npy_bool, npy_byte, npy_ubyte# + */ +static void +@NAME@_fillwithscalar(@type@ *buffer, npy_intp length, @type@ *value, + void *NPY_UNUSED(ignored)) +{ + memset(buffer, *value, length); +} +/**end repeat**/ + +/**begin repeat + * + * #NAME = SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * DATETIME, TIMEDELTA# + * #type = npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble, + * npy_datetime, npy_timedelta# + */ +static void +@NAME@_fillwithscalar(@type@ *buffer, npy_intp length, @type@ *value, + void *NPY_UNUSED(ignored)) +{ + npy_intp i; + @type@ val = *value; + + for (i = 0; i < length; ++i) { + buffer[i] = val; + } +} +/**end repeat**/ + + +/* + ***************************************************************************** + ** FASTCLIP ** + ***************************************************************************** + */ + +#define _LESS_THAN(a, b) ((a) < (b)) +#define _GREATER_THAN(a, b) ((a) > (b)) + +/* + * In fastclip, 'b' was already checked for NaN, so the half comparison + * only needs to check 'a' for NaN. + */ + +#define _HALF_LESS_THAN(a, b) (!npy_half_isnan(a) && npy_half_lt_nonan(a, b)) +#define _HALF_GREATER_THAN(a, b) (!npy_half_isnan(a) && npy_half_lt_nonan(b, a)) + +/**begin repeat + * + * #name = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * DATETIME, TIMEDELTA# + * #type = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_datetime, npy_timedelta# + * #isfloat = 0*11, 1*4, 0*2# + * #isnan = nop*11, npy_half_isnan, npy_isnan*3, nop*2# + * #lt = _LESS_THAN*11, _HALF_LESS_THAN, _LESS_THAN*5# + * #gt = _GREATER_THAN*11, _HALF_GREATER_THAN, _GREATER_THAN*5# + */ +static void +@name@_fastclip(@type@ *in, npy_intp ni, @type@ *min, @type@ *max, @type@ *out) +{ + npy_intp i; + @type@ max_val = 0, min_val = 0; + + if (max != NULL) { + max_val = *max; +#if @isfloat@ + /* NaNs result in no clipping, so optimize the case away */ + if (@isnan@(max_val)) { + if (min == NULL) { + memmove(out, in, ni * sizeof(@type@)); + return; + } + max = NULL; + } +#endif + } + if (min != NULL) { + min_val = *min; +#if @isfloat@ + if (@isnan@(min_val)) { + if (max == NULL) { + memmove(out, in, ni * sizeof(@type@)); + return; + } + min = NULL; + } +#endif + } + if (max == NULL) { + for (i = 0; i < ni; i++) { + if (@lt@(in[i], min_val)) { + out[i] = min_val; + } + else { + out[i] = in[i]; + } + } + } + else if (min == NULL) { + for (i = 0; i < ni; i++) { + if (@gt@(in[i], max_val)) { + out[i] = max_val; + } + else { + out[i] = in[i]; + } + } + } + else { + /* + * Visual Studio 2015 loop vectorizer handles NaN in an unexpected + * manner, see: https://github.com/numpy/numpy/issues/7601 + */ + #if (_MSC_VER == 1900) + #pragma loop( no_vector ) + #endif + for (i = 0; i < ni; i++) { + if (@lt@(in[i], min_val)) { + out[i] = min_val; + } + else if (@gt@(in[i], max_val)) { + out[i] = max_val; + } + else { + out[i] = in[i]; + } + } + } +} +/**end repeat**/ + +#undef _LESS_THAN +#undef _GREATER_THAN +#undef _HALF_LESS_THAN +#undef _HALF_GREATER_THAN + +/**begin repeat + * + * #name = CFLOAT, CDOUBLE, CLONGDOUBLE# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# + */ +static void +@name@_fastclip(@type@ *in, npy_intp ni, @type@ *min, @type@ *max, @type@ *out) +{ + npy_intp i; + @type@ max_val, min_val; + + if (max != NULL) { + max_val = *max; + } + if (min != NULL) { + min_val = *min; + } + if (max == NULL) { + for (i = 0; i < ni; i++) { + if (PyArray_CLT(in[i],min_val)) { + out[i] = min_val; + } + else { + out[i] = in[i]; + } + } + } + else if (min == NULL) { + for (i = 0; i < ni; i++) { + if (PyArray_CGT(in[i], max_val)) { + out[i] = max_val; + } + else { + out[i] = in[i]; + } + } + } + else { + for (i = 0; i < ni; i++) { + if (PyArray_CLT(in[i], min_val)) { + out[i] = min_val; + } + else if (PyArray_CGT(in[i], max_val)) { + out[i] = max_val; + } + else { + out[i] = in[i]; + } + } + } +} + +/**end repeat**/ + +#define OBJECT_fastclip NULL + + +/* + ***************************************************************************** + ** FASTPUTMASK ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #name = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * DATETIME, TIMEDELTA# + * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble, + * npy_datetime, npy_timedelta# +*/ +static void +@name@_fastputmask(@type@ *in, npy_bool *mask, npy_intp ni, @type@ *vals, + npy_intp nv) +{ + npy_intp i, j; + + if (nv == 1) { + @type@ s_val = *vals; + for (i = 0; i < ni; i++) { + if (mask[i]) { + in[i] = s_val; + } + } + } + else { + for (i = 0, j = 0; i < ni; i++, j++) { + if (j >= nv) { + j = 0; + } + if (mask[i]) { + in[i] = vals[j]; + } + } + } + return; +} +/**end repeat**/ + +#define OBJECT_fastputmask NULL + + +/* + ***************************************************************************** + ** FASTTAKE ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #name = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * DATETIME, TIMEDELTA# + * #type = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble, + * npy_datetime, npy_timedelta# +*/ +static int +@name@_fasttake(@type@ *dest, @type@ *src, npy_intp *indarray, + npy_intp nindarray, npy_intp n_outer, + npy_intp m_middle, npy_intp nelem, + NPY_CLIPMODE clipmode) +{ + npy_intp i, j, k, tmp; + NPY_BEGIN_THREADS_DEF; + + NPY_BEGIN_THREADS; + + switch(clipmode) { + case NPY_RAISE: + for (i = 0; i < n_outer; i++) { + for (j = 0; j < m_middle; j++) { + tmp = indarray[j]; + /* + * We don't know what axis we're operating on, + * so don't report it in case of an error. + */ + if (check_and_adjust_index(&tmp, nindarray, -1, _save) < 0) { + return 1; + } + if (NPY_LIKELY(nelem == 1)) { + *dest++ = *(src + tmp); + } + else { + for (k = 0; k < nelem; k++) { + *dest++ = *(src + tmp*nelem + k); + } + } + } + src += nelem*nindarray; + } + break; + case NPY_WRAP: + for (i = 0; i < n_outer; i++) { + for (j = 0; j < m_middle; j++) { + tmp = indarray[j]; + if (tmp < 0) { + while (tmp < 0) { + tmp += nindarray; + } + } + else if (tmp >= nindarray) { + while (tmp >= nindarray) { + tmp -= nindarray; + } + } + if (NPY_LIKELY(nelem == 1)) { + *dest++ = *(src+tmp); + } + else { + for (k = 0; k < nelem; k++) { + *dest++ = *(src+tmp*nelem+k); + } + } + } + src += nelem*nindarray; + } + break; + case NPY_CLIP: + for (i = 0; i < n_outer; i++) { + for (j = 0; j < m_middle; j++) { + tmp = indarray[j]; + if (tmp < 0) { + tmp = 0; + } + else if (tmp >= nindarray) { + tmp = nindarray - 1; + } + if (NPY_LIKELY(nelem == 1)) { + *dest++ = *(src + tmp); + } + else { + for (k = 0; k < nelem; k++) { + *dest++ = *(src + tmp*nelem + k); + } + } + } + src += nelem*nindarray; + } + break; + } + + NPY_END_THREADS; + return 0; +} +/**end repeat**/ + +#define OBJECT_fasttake NULL + +/* + ***************************************************************************** + ** small correlate ** + ***************************************************************************** + */ + +/* + * Compute correlation of data with with small kernels + * Calling a BLAS dot product for the inner loop of the correlation is overkill + * for small kernels. It is faster to compute it directly. + * Intended to be used by _pyarray_correlate so no input verifications is done + * especially it does not handle the boundaries, they should be handled by the + * caller. + * Returns 0 if kernel is considered too large or types are not supported, then + * the regular array dot should be used to process the data. + * + * d_, dstride, nd, dtype: data pointer, its stride in bytes, number of + * elements and type of data + * k_, kstride, nk, ktype: kernel pointer, its stride in bytes, number of + * elements and type of data + * out_, ostride: output data pointer and its stride in bytes + */ +NPY_NO_EXPORT int +small_correlate(const char * d_, npy_intp dstride, + npy_intp nd, enum NPY_TYPES dtype, + const char * k_, npy_intp kstride, + npy_intp nk, enum NPY_TYPES ktype, + char * out_, npy_intp ostride) +{ + /* only handle small kernels and uniform types */ + if (nk > 11 || dtype != ktype) { + return 0; + } + + switch (dtype) { +/**begin repeat + * Float types + * #type = npy_float, npy_double# + * #TYPE = NPY_FLOAT, NPY_DOUBLE# + */ + case @TYPE@: + { + npy_intp i; + const @type@ * d = (@type@*)d_; + const @type@ * k = (@type@*)k_; + @type@ * out = (@type@*)out_; + dstride /= sizeof(@type@); + kstride /= sizeof(@type@); + ostride /= sizeof(@type@); + /* unroll inner loop to optimize register usage of the kernel*/ + switch (nk) { +/**begin repeat1 + * #ksz_outer = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11# */ + case @ksz_outer@: + { +/**begin repeat2 + * #ksz = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11# */ +#if @ksz@ <= @ksz_outer@ + /* load kernel */ + const @type@ k@ksz@ = k[(@ksz@ - 1) * kstride]; +#endif +/**end repeat2**/ + for (i = 0; i < nd; i++) { + @type@ s = 0; +/**begin repeat2 + * #ksz = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11# */ +#if @ksz@ <= @ksz_outer@ + s += d[(i + @ksz@ - 1) * dstride] * k@ksz@; +#endif +/**end repeat2**/ + out[i * ostride] = s; + } + return 1; + } +/**end repeat1**/ + default: + return 0; + } + } +/**end repeat**/ + default: + return 0; + } +} + +/* + ***************************************************************************** + ** SETUP FUNCTION POINTERS ** + ***************************************************************************** + */ + + +#define _ALIGN(type) offsetof(struct {char c; type v;}, v) +/* + * Disable harmless compiler warning "4116: unnamed type definition in + * parentheses" which is caused by the _ALIGN macro. + */ +#if defined(_MSC_VER) +#pragma warning(disable:4116) +#endif + + +/**begin repeat + * + * #from = VOID, STRING, UNICODE# + * #suff = void, string, unicode# + * #sort = 0, 1, 1# + * #align = char, char, npy_ucs4# + * #NAME = Void, String, Unicode# + * #endian = |, |, =# + * #flags = 0, 0, NPY_NEEDS_INIT# + */ +static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = { + { + @from@_to_BOOL, + @from@_to_BYTE, + @from@_to_UBYTE, + @from@_to_SHORT, + @from@_to_USHORT, + @from@_to_INT, + @from@_to_UINT, + @from@_to_LONG, + @from@_to_ULONG, + @from@_to_LONGLONG, + @from@_to_ULONGLONG, + @from@_to_FLOAT, + @from@_to_DOUBLE, + @from@_to_LONGDOUBLE, + @from@_to_CFLOAT, + @from@_to_CDOUBLE, + @from@_to_CLONGDOUBLE, + @from@_to_OBJECT, + @from@_to_STRING, + @from@_to_UNICODE, + @from@_to_VOID + }, + @from@_getitem, + @from@_setitem, + (PyArray_CopySwapNFunc*)@from@_copyswapn, + (PyArray_CopySwapFunc*)@from@_copyswap, + (PyArray_CompareFunc*)@from@_compare, + (PyArray_ArgFunc*)@from@_argmax, + (PyArray_DotFunc*)NULL, + (PyArray_ScanFunc*)@from@_scan, + @from@_fromstr, + (PyArray_NonzeroFunc*)@from@_nonzero, + (PyArray_FillFunc*)NULL, + (PyArray_FillWithScalarFunc*)NULL, +#if @sort@ + { + quicksort_@suff@, + heapsort_@suff@, + mergesort_@suff@ + }, + { + aquicksort_@suff@, + aheapsort_@suff@, + amergesort_@suff@ + }, +#else + { + NULL, NULL, NULL + }, + { + NULL, NULL, NULL + }, +#endif + NULL, + (PyArray_ScalarKindFunc*)NULL, + NULL, + NULL, + (PyArray_FastClipFunc *)NULL, + (PyArray_FastPutmaskFunc *)NULL, + (PyArray_FastTakeFunc *)NULL, + (PyArray_ArgFunc*)@from@_argmin +}; + +/* + * FIXME: check for PY3K + */ +static PyArray_Descr @from@_Descr = { + PyObject_HEAD_INIT(&PyArrayDescr_Type) + /* typeobj */ + &Py@NAME@ArrType_Type, + /* kind */ + NPY_@from@LTR, + /* type */ + NPY_@from@LTR, + /* byteorder */ + '@endian@', + /* flags, unicode needs init as py3.3 does not like printing garbage */ + @flags@, + /* type_num */ + NPY_@from@, + /* elsize */ + 0, + /* alignment */ + _ALIGN(@align@), + /* subarray */ + NULL, + /* fields */ + NULL, + /* names */ + NULL, + /* f */ + &_Py@NAME@_ArrFuncs, + /* metadata */ + NULL, + /* c_metadata */ + NULL, + /* hash */ + -1, +}; + +/**end repeat**/ + +/**begin repeat + * + * #from = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * OBJECT, DATETIME, TIMEDELTA# + * #suff = bool, + * byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble, + * object, datetime, timedelta# + * #sort = 1*18, 0*1, 1*2# + * #num = 1*15, 2*3, 1*3# + * #fromtype = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_float, npy_double, npy_longdouble, + * PyObject *, npy_datetime, npy_timedelta# + * #NAME = Bool, + * Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong, + * Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble, + * Object, Datetime, Timedelta# + * #kind = GENBOOL, + * SIGNED, UNSIGNED, SIGNED, UNSIGNED, SIGNED, UNSIGNED, + * SIGNED, UNSIGNED, SIGNED, UNSIGNED, + * FLOATING, FLOATING, FLOATING, FLOATING, + * COMPLEX, COMPLEX, COMPLEX, + * OBJECT, DATETIME, TIMEDELTA# + * #endian = |*3, =*15, |, =*2# + * #isobject= 0*18,NPY_OBJECT_DTYPE_FLAGS,0*2# + */ + +static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = { + { + @from@_to_BOOL, + @from@_to_BYTE, + @from@_to_UBYTE, + @from@_to_SHORT, + @from@_to_USHORT, + @from@_to_INT, + @from@_to_UINT, + @from@_to_LONG, + @from@_to_ULONG, + @from@_to_LONGLONG, + @from@_to_ULONGLONG, + @from@_to_FLOAT, + @from@_to_DOUBLE, + @from@_to_LONGDOUBLE, + @from@_to_CFLOAT, + @from@_to_CDOUBLE, + @from@_to_CLONGDOUBLE, + @from@_to_OBJECT, + @from@_to_STRING, + @from@_to_UNICODE, + @from@_to_VOID + }, + @from@_getitem, + @from@_setitem, + (PyArray_CopySwapNFunc*)@from@_copyswapn, + (PyArray_CopySwapFunc*)@from@_copyswap, + (PyArray_CompareFunc*)@from@_compare, + (PyArray_ArgFunc*)@from@_argmax, + (PyArray_DotFunc*)@from@_dot, + (PyArray_ScanFunc*)@from@_scan, + @from@_fromstr, + (PyArray_NonzeroFunc*)@from@_nonzero, + (PyArray_FillFunc*)@from@_fill, + (PyArray_FillWithScalarFunc*)@from@_fillwithscalar, +#if @sort@ + { + quicksort_@suff@, + heapsort_@suff@, + mergesort_@suff@ + }, + { + aquicksort_@suff@, + aheapsort_@suff@, + amergesort_@suff@ + }, +#else + { + NULL, NULL, NULL + }, + { + NULL, NULL, NULL + }, +#endif + NULL, + (PyArray_ScalarKindFunc*)NULL, + NULL, + NULL, + (PyArray_FastClipFunc*)@from@_fastclip, + (PyArray_FastPutmaskFunc*)@from@_fastputmask, + (PyArray_FastTakeFunc*)@from@_fasttake, + (PyArray_ArgFunc*)@from@_argmin +}; + +/* + * FIXME: check for PY3K + */ +NPY_NO_EXPORT PyArray_Descr @from@_Descr = { + PyObject_HEAD_INIT(&PyArrayDescr_Type) + /* typeobj */ + &Py@NAME@ArrType_Type, + /* kind */ + NPY_@kind@LTR, + /* type */ + NPY_@from@LTR, + /* byteorder */ + '@endian@', + /* flags */ + @isobject@, + /* type_num */ + NPY_@from@, + /* elsize */ + @num@ * sizeof(@fromtype@), + /* alignment */ + @num@ * _ALIGN(@fromtype@) > NPY_MAX_COPY_ALIGNMENT ? + NPY_MAX_COPY_ALIGNMENT : @num@ * _ALIGN(@fromtype@), + /* subarray */ + NULL, + /* fields */ + NULL, + /* names */ + NULL, + /* f */ + &_Py@NAME@_ArrFuncs, + /* metadata */ + NULL, + /* c_metadata */ + NULL, + /* hash */ + -1, +}; + +/**end repeat**/ + +#define _MAX_LETTER 128 +static char _letter_to_num[_MAX_LETTER]; + +static PyArray_Descr *_builtin_descrs[] = { + &BOOL_Descr, + &BYTE_Descr, + &UBYTE_Descr, + &SHORT_Descr, + &USHORT_Descr, + &INT_Descr, + &UINT_Descr, + &LONG_Descr, + &ULONG_Descr, + &LONGLONG_Descr, + &ULONGLONG_Descr, + &FLOAT_Descr, + &DOUBLE_Descr, + &LONGDOUBLE_Descr, + &CFLOAT_Descr, + &CDOUBLE_Descr, + &CLONGDOUBLE_Descr, + &OBJECT_Descr, + &STRING_Descr, + &UNICODE_Descr, + &VOID_Descr, + &DATETIME_Descr, + &TIMEDELTA_Descr, + &HALF_Descr +}; + +/*NUMPY_API + * Get the PyArray_Descr structure for a type. + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_DescrFromType(int type) +{ + PyArray_Descr *ret = NULL; + + if (type < NPY_NTYPES) { + ret = _builtin_descrs[type]; + } + else if (type == NPY_NOTYPE) { + /* + * This needs to not raise an error so + * that PyArray_DescrFromType(NPY_NOTYPE) + * works for backwards-compatible C-API + */ + return NULL; + } + else if ((type == NPY_CHAR) || (type == NPY_CHARLTR)) { + if (type == NPY_CHAR) { + /* + * warning added 2017-04-25, 1.13 + * deprecated in 1.7 + * */ + if (DEPRECATE("The NPY_CHAR type_num is deprecated. " + "Please port your code to use " + "NPY_STRING instead.") < 0) { + return NULL; + } + } + ret = PyArray_DescrNew(_builtin_descrs[NPY_STRING]); + if (ret == NULL) { + return NULL; + } + ret->elsize = 1; + ret->type = NPY_CHARLTR; + return ret; + } + else if (PyTypeNum_ISUSERDEF(type)) { + ret = userdescrs[type - NPY_USERDEF]; + } + else { + int num = NPY_NTYPES; + if (type < _MAX_LETTER) { + num = (int) _letter_to_num[type]; + } + if (num >= NPY_NTYPES) { + ret = NULL; + } + else { + ret = _builtin_descrs[num]; + } + } + if (ret == NULL) { + PyErr_SetString(PyExc_ValueError, + "Invalid data-type for array"); + } + else { + Py_INCREF(ret); + } + + return ret; +} + +/* A clone function for the datetime dtype metadata */ +static NpyAuxData * +datetime_dtype_metadata_clone(NpyAuxData *data) +{ + PyArray_DatetimeDTypeMetaData *newdata = + (PyArray_DatetimeDTypeMetaData *)PyArray_malloc( + sizeof(PyArray_DatetimeDTypeMetaData)); + if (newdata == NULL) { + return NULL; + } + + memcpy(newdata, data, sizeof(PyArray_DatetimeDTypeMetaData)); + + return (NpyAuxData *)newdata; +} + +/* + * Initializes the c_metadata field for the _builtin_descrs DATETIME + * and TIMEDELTA. + * + * must not be static, gcc 4.1.2 on redhat 5 then miscompiles this function + * see gh-5163 + * + */ +NPY_NO_EXPORT int +initialize_builtin_datetime_metadata(void) +{ + PyArray_DatetimeDTypeMetaData *data1, *data2; + + /* Allocate memory for the metadata */ + data1 = PyArray_malloc(sizeof(PyArray_DatetimeDTypeMetaData)); + if (data1 == NULL) { + return -1; + } + data2 = PyArray_malloc(sizeof(PyArray_DatetimeDTypeMetaData)); + if (data2 == NULL) { + PyArray_free(data1); + return -1; + } + + /* Initialize the base aux data */ + memset(data1, 0, sizeof(PyArray_DatetimeDTypeMetaData)); + memset(data2, 0, sizeof(PyArray_DatetimeDTypeMetaData)); + data1->base.free = (NpyAuxData_FreeFunc *)PyArray_free; + data2->base.free = (NpyAuxData_FreeFunc *)PyArray_free; + data1->base.clone = datetime_dtype_metadata_clone; + data2->base.clone = datetime_dtype_metadata_clone; + + /* Set to the default metadata */ + data1->meta.base = NPY_DATETIME_DEFAULTUNIT; + data1->meta.num = 1; + data2->meta.base = NPY_DATETIME_DEFAULTUNIT; + data2->meta.num = 1; + + _builtin_descrs[NPY_DATETIME]->c_metadata = (NpyAuxData *)data1; + _builtin_descrs[NPY_TIMEDELTA]->c_metadata = (NpyAuxData *)data2; + + return 0; +} + +/* + ***************************************************************************** + ** SETUP TYPE INFO ** + ***************************************************************************** + */ + + +/* + * This function is called during numpy module initialization, + * and is used to initialize internal dtype tables. + */ +NPY_NO_EXPORT int +set_typeinfo(PyObject *dict) +{ + PyObject *infodict, *s; + int i; + + PyArray_Descr *dtype; + PyObject *cobj, *key; + + /* + * Add cast functions for the new types + */ + + /**begin repeat + * + * #name1 = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * OBJECT, STRING, UNICODE, VOID, + * DATETIME,TIMEDELTA# + */ + + /**begin repeat1 + * + * #name2 = HALF, DATETIME, TIMEDELTA# + */ + + dtype = _builtin_descrs[NPY_@name1@]; + if (dtype->f->castdict == NULL) { + dtype->f->castdict = PyDict_New(); + if (dtype->f->castdict == NULL) { + return -1; + } + } + key = PyInt_FromLong(NPY_@name2@); + if (key == NULL) { + return -1; + } + cobj = NpyCapsule_FromVoidPtr((void *)@name1@_to_@name2@, NULL); + if (cobj == NULL) { + Py_DECREF(key); + return -1; + } + if (PyDict_SetItem(dtype->f->castdict, key, cobj) < 0) { + Py_DECREF(key); + Py_DECREF(cobj); + return -1; + } + Py_DECREF(key); + Py_DECREF(cobj); + + /**end repeat1**/ + + /**end repeat**/ + + if (initialize_builtin_datetime_metadata() < 0) { + return -1; + } + + for (i = 0; i < _MAX_LETTER; i++) { + _letter_to_num[i] = NPY_NTYPES; + } + + /**begin repeat + * + * #name = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * INTP, UINTP, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * OBJECT, STRING, UNICODE, VOID, + * DATETIME,TIMEDELTA# + */ + + _letter_to_num[NPY_@name@LTR] = NPY_@name@; + + /**end repeat**/ + + _letter_to_num[NPY_STRINGLTR2] = NPY_STRING; + + /**begin repeat + * #name = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * OBJECT, STRING, UNICODE, VOID, + * DATETIME, TIMEDELTA# + */ + + @name@_Descr.fields = Py_None; + + /**end repeat**/ + + + /**begin repeat + * #name = STRING, UNICODE, VOID# + */ + + PyDataType_MAKEUNSIZED(&@name@_Descr); + + /**end repeat**/ + + /* Set a dictionary with type information */ + infodict = PyDict_New(); + if (infodict == NULL) return -1; + + + /**begin repeat + * + * #name = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * INTP, UINTP, + * LONG, ULONG, LONGLONG, ULONGLONG# + * #uname = BOOL, + * BYTE*2, SHORT*2, INT*2, + * INTP*2, + * LONG*2, LONGLONG*2# + * #Name = Bool, + * Byte, UByte, Short, UShort, Int, UInt, + * Intp, UIntp, + * Long, ULong, LongLong, ULongLong# + * #type = npy_bool, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_intp, npy_uintp, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong# + * #max= 1, + * NPY_MAX_BYTE, NPY_MAX_UBYTE, NPY_MAX_SHORT, + * NPY_MAX_USHORT, NPY_MAX_INT, PyLong_FromUnsignedLong(NPY_MAX_UINT), + * PyLong_FromLongLong((npy_longlong) NPY_MAX_INTP), + * PyLong_FromUnsignedLongLong((npy_ulonglong) NPY_MAX_UINTP), + * NPY_MAX_LONG, + * PyLong_FromUnsignedLong((npy_ulong) NPY_MAX_ULONG), + * PyLong_FromLongLong((npy_longlong) NPY_MAX_LONGLONG), + * PyLong_FromUnsignedLongLong((npy_ulonglong) NPY_MAX_ULONGLONG)# + * #min = 0, NPY_MIN_BYTE, 0, NPY_MIN_SHORT, 0, NPY_MIN_INT, 0, + * PyLong_FromLongLong((npy_longlong) NPY_MIN_INTP), + * 0, NPY_MIN_LONG, 0, + * PyLong_FromLongLong((npy_longlong) NPY_MIN_LONGLONG), 0# + * #cx = i*6, N, N, N, l, N, N, N# + * #cn = i*7, N, i, l, i, N, i# + */ + + PyDict_SetItemString(infodict, "@name@", +#if defined(NPY_PY3K) + s = Py_BuildValue("Ciii@cx@@cn@O", +#else + s = Py_BuildValue("ciii@cx@@cn@O", +#endif + NPY_@name@LTR, + NPY_@name@, + NPY_BITSOF_@uname@, + _ALIGN(@type@), + @max@, + @min@, + (PyObject *) &Py@Name@ArrType_Type)); + Py_DECREF(s); + + /**end repeat**/ + + + /**begin repeat + * + * #type = npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + * #name = HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #Name = Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble# + * #num = 1, 1, 1, 1, 2, 2, 2# + */ + + PyDict_SetItemString(infodict, "@name@", +#if defined(NPY_PY3K) + s = Py_BuildValue("CiiiO", NPY_@name@LTR, +#else + s = Py_BuildValue("ciiiO", NPY_@name@LTR, +#endif + NPY_@name@, + NPY_BITSOF_@name@, + @num@ * _ALIGN(@type@) > NPY_MAX_COPY_ALIGNMENT ? + NPY_MAX_COPY_ALIGNMENT : @num@ * _ALIGN(@type@), + (PyObject *) &Py@Name@ArrType_Type)); + Py_DECREF(s); + + /**end repeat**/ + + PyDict_SetItemString(infodict, "OBJECT", +#if defined(NPY_PY3K) + s = Py_BuildValue("CiiiO", NPY_OBJECTLTR, +#else + s = Py_BuildValue("ciiiO", NPY_OBJECTLTR, +#endif + NPY_OBJECT, + sizeof(PyObject *) * CHAR_BIT, + _ALIGN(PyObject *), + (PyObject *) &PyObjectArrType_Type)); + Py_DECREF(s); + PyDict_SetItemString(infodict, "STRING", +#if defined(NPY_PY3K) + s = Py_BuildValue("CiiiO", NPY_STRINGLTR, +#else + s = Py_BuildValue("ciiiO", NPY_STRINGLTR, +#endif + NPY_STRING, + 0, + _ALIGN(char), + (PyObject *) &PyStringArrType_Type)); + Py_DECREF(s); + PyDict_SetItemString(infodict, "UNICODE", +#if defined(NPY_PY3K) + s = Py_BuildValue("CiiiO", NPY_UNICODELTR, +#else + s = Py_BuildValue("ciiiO", NPY_UNICODELTR, +#endif + NPY_UNICODE, + 0, + _ALIGN(npy_ucs4), + (PyObject *) &PyUnicodeArrType_Type)); + Py_DECREF(s); + PyDict_SetItemString(infodict, "VOID", +#if defined(NPY_PY3K) + s = Py_BuildValue("CiiiO", NPY_VOIDLTR, +#else + s = Py_BuildValue("ciiiO", NPY_VOIDLTR, +#endif + NPY_VOID, + 0, + _ALIGN(char), + (PyObject *) &PyVoidArrType_Type)); + Py_DECREF(s); + PyDict_SetItemString(infodict, "DATETIME", +#if defined(NPY_PY3K) + s = Py_BuildValue("CiiiNNO", NPY_DATETIMELTR, +#else + s = Py_BuildValue("ciiiNNO", NPY_DATETIMELTR, +#endif + NPY_DATETIME, + NPY_BITSOF_DATETIME, + _ALIGN(npy_datetime), + MyPyLong_FromInt64(NPY_MAX_DATETIME), + MyPyLong_FromInt64(NPY_MIN_DATETIME), + (PyObject *) &PyDatetimeArrType_Type)); + Py_DECREF(s); + PyDict_SetItemString(infodict, "TIMEDELTA", +#if defined(NPY_PY3K) + s = Py_BuildValue("CiiiNNO", NPY_TIMEDELTALTR, +#else + s = Py_BuildValue("ciiiNNO",NPY_TIMEDELTALTR, +#endif + NPY_TIMEDELTA, + NPY_BITSOF_TIMEDELTA, + _ALIGN(npy_timedelta), + MyPyLong_FromInt64(NPY_MAX_TIMEDELTA), + MyPyLong_FromInt64(NPY_MIN_TIMEDELTA), + (PyObject *)&PyTimedeltaArrType_Type)); + Py_DECREF(s); + +#define SETTYPE(name) \ + Py_INCREF(&Py##name##ArrType_Type); \ + PyDict_SetItemString(infodict, #name, \ + (PyObject *)&Py##name##ArrType_Type) + + SETTYPE(Generic); + SETTYPE(Number); + SETTYPE(Integer); + SETTYPE(Inexact); + SETTYPE(SignedInteger); + SETTYPE(UnsignedInteger); + SETTYPE(Floating); + SETTYPE(ComplexFloating); + SETTYPE(Flexible); + SETTYPE(Character); + +#undef SETTYPE + + PyDict_SetItemString(dict, "typeinfo", infodict); + Py_DECREF(infodict); + return 0; +} + +#undef _MAX_LETTER diff --git a/numpy/core/src/multiarray/arraytypes.h b/numpy/core/src/multiarray/arraytypes.h new file mode 100644 index 0000000..d1c16cd --- /dev/null +++ b/numpy/core/src/multiarray/arraytypes.h @@ -0,0 +1,35 @@ +#ifndef _NPY_ARRAYTYPES_H_ +#define _NPY_ARRAYTYPES_H_ + +#include "common.h" + +extern NPY_NO_EXPORT PyArray_Descr LONGLONG_Descr; +extern NPY_NO_EXPORT PyArray_Descr LONG_Descr; +extern NPY_NO_EXPORT PyArray_Descr INT_Descr; + +NPY_NO_EXPORT int +set_typeinfo(PyObject *dict); + +/* needed for blasfuncs */ +NPY_NO_EXPORT void +FLOAT_dot(char *, npy_intp, char *, npy_intp, char *, npy_intp, void *); + +NPY_NO_EXPORT void +CFLOAT_dot(char *, npy_intp, char *, npy_intp, char *, npy_intp, void *); + +NPY_NO_EXPORT void +DOUBLE_dot(char *, npy_intp, char *, npy_intp, char *, npy_intp, void *); + +NPY_NO_EXPORT void +CDOUBLE_dot(char *, npy_intp, char *, npy_intp, char *, npy_intp, void *); + + +/* for _pyarray_correlate */ +NPY_NO_EXPORT int +small_correlate(const char * d_, npy_intp dstride, + npy_intp nd, enum NPY_TYPES dtype, + const char * k_, npy_intp kstride, + npy_intp nk, enum NPY_TYPES ktype, + char * out_, npy_intp ostride); + +#endif diff --git a/numpy/core/src/multiarray/buffer.c b/numpy/core/src/multiarray/buffer.c new file mode 100644 index 0000000..4aa25a1 --- /dev/null +++ b/numpy/core/src/multiarray/buffer.c @@ -0,0 +1,990 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "buffer.h" +#include "common.h" +#include "numpyos.h" +#include "arrayobject.h" + +/************************************************************************* + **************** Implement Buffer Protocol **************************** + *************************************************************************/ + +/* removed multiple segment interface */ + +#if !defined(NPY_PY3K) +static Py_ssize_t +array_getsegcount(PyArrayObject *self, Py_ssize_t *lenp) +{ + if (lenp) { + *lenp = PyArray_NBYTES(self); + } + if (PyArray_ISONESEGMENT(self)) { + return 1; + } + if (lenp) { + *lenp = 0; + } + return 0; +} + +static Py_ssize_t +array_getreadbuf(PyArrayObject *self, Py_ssize_t segment, void **ptrptr) +{ + if (segment != 0) { + PyErr_SetString(PyExc_ValueError, + "accessing non-existing array segment"); + return -1; + } + if (PyArray_ISONESEGMENT(self)) { + *ptrptr = PyArray_DATA(self); + return PyArray_NBYTES(self); + } + PyErr_SetString(PyExc_ValueError, "array is not a single segment"); + *ptrptr = NULL; + return -1; +} + + +static Py_ssize_t +array_getwritebuf(PyArrayObject *self, Py_ssize_t segment, void **ptrptr) +{ + if (PyArray_FailUnlessWriteable(self, "buffer source array") < 0) { + return -1; + } + return array_getreadbuf(self, segment, (void **) ptrptr); +} + +static Py_ssize_t +array_getcharbuf(PyArrayObject *self, Py_ssize_t segment, constchar **ptrptr) +{ + return array_getreadbuf(self, segment, (void **) ptrptr); +} +#endif /* !defined(NPY_PY3K) */ + + +/************************************************************************* + * PEP 3118 buffer protocol + * + * Implementing PEP 3118 is somewhat convoluted because of the desirata: + * + * - Don't add new members to ndarray or descr structs, to preserve binary + * compatibility. (Also, adding the items is actually not very useful, + * since mutability issues prevent an 1 to 1 relationship between arrays + * and buffer views.) + * + * - Don't use bf_releasebuffer, because it prevents PyArg_ParseTuple("s#", ... + * from working. Breaking this would cause several backward compatibility + * issues already on Python 2.6. + * + * - Behave correctly when array is reshaped in-place, or it's dtype is + * altered. + * + * The solution taken below is to manually track memory allocated for + * Py_buffers. + *************************************************************************/ + +/* + * Format string translator + * + * Translate PyArray_Descr to a PEP 3118 format string. + */ + +/* Fast string 'class' */ +typedef struct { + char *s; + size_t allocated; + size_t pos; +} _tmp_string_t; + +#define INIT_SIZE 16 + +static int +_append_char(_tmp_string_t *s, char c) +{ + if (s->pos >= s->allocated) { + char *p; + size_t to_alloc = (s->allocated == 0) ? INIT_SIZE : (2 * s->allocated); + + p = realloc(s->s, to_alloc); + if (p == NULL) { + PyErr_SetString(PyExc_MemoryError, "memory allocation failed"); + return -1; + } + s->s = p; + s->allocated = to_alloc; + } + s->s[s->pos] = c; + ++s->pos; + return 0; +} + +static int +_append_str(_tmp_string_t *s, char const *p) +{ + for (; *p != '\0'; p++) { + if (_append_char(s, *p) != 0) { + return -1; + } + } + return 0; +} + +/* + * Return non-zero if a type is aligned in each item in the given array, + * AND, the descr element size is a multiple of the alignment, + * AND, the array data is positioned to alignment granularity. + */ +static int +_is_natively_aligned_at(PyArray_Descr *descr, + PyArrayObject *arr, Py_ssize_t offset) +{ + int k; + + if ((Py_ssize_t)(PyArray_DATA(arr)) % descr->alignment != 0) { + return 0; + } + + if (offset % descr->alignment != 0) { + return 0; + } + + if (descr->elsize % descr->alignment) { + return 0; + } + + for (k = 0; k < PyArray_NDIM(arr); ++k) { + if (PyArray_DIM(arr, k) > 1) { + if (PyArray_STRIDE(arr, k) % descr->alignment != 0) { + return 0; + } + } + } + + return 1; +} + +static int +_buffer_format_string(PyArray_Descr *descr, _tmp_string_t *str, + PyArrayObject* arr, Py_ssize_t *offset, + char *active_byteorder) +{ + int k; + char _active_byteorder = '@'; + Py_ssize_t _offset = 0; + + if (active_byteorder == NULL) { + active_byteorder = &_active_byteorder; + } + if (offset == NULL) { + offset = &_offset; + } + + if (descr->subarray) { + PyObject *item, *subarray_tuple; + Py_ssize_t total_count = 1; + Py_ssize_t dim_size; + char buf[128]; + int old_offset; + int ret; + + if (PyTuple_Check(descr->subarray->shape)) { + subarray_tuple = descr->subarray->shape; + Py_INCREF(subarray_tuple); + } + else { + subarray_tuple = Py_BuildValue("(O)", descr->subarray->shape); + } + + _append_char(str, '('); + for (k = 0; k < PyTuple_GET_SIZE(subarray_tuple); ++k) { + if (k > 0) { + _append_char(str, ','); + } + item = PyTuple_GET_ITEM(subarray_tuple, k); + dim_size = PyNumber_AsSsize_t(item, NULL); + + PyOS_snprintf(buf, sizeof(buf), "%ld", (long)dim_size); + _append_str(str, buf); + total_count *= dim_size; + } + _append_char(str, ')'); + + Py_DECREF(subarray_tuple); + + old_offset = *offset; + ret = _buffer_format_string(descr->subarray->base, str, arr, offset, + active_byteorder); + *offset = old_offset + (*offset - old_offset) * total_count; + return ret; + } + else if (PyDataType_HASFIELDS(descr)) { + int base_offset = *offset; + + _append_str(str, "T{"); + for (k = 0; k < PyTuple_GET_SIZE(descr->names); ++k) { + PyObject *name, *item, *offset_obj, *tmp; + PyArray_Descr *child; + char *p; + Py_ssize_t len; + int new_offset; + + name = PyTuple_GET_ITEM(descr->names, k); + item = PyDict_GetItem(descr->fields, name); + + child = (PyArray_Descr*)PyTuple_GetItem(item, 0); + offset_obj = PyTuple_GetItem(item, 1); + new_offset = PyInt_AsLong(offset_obj); + if (error_converting(new_offset)) { + return -1; + } + new_offset += base_offset; + + /* Insert padding manually */ + if (*offset > new_offset) { + PyErr_SetString( + PyExc_ValueError, + "dtypes with overlapping or out-of-order fields are not " + "representable as buffers. Consider reordering the fields." + ); + return -1; + } + while (*offset < new_offset) { + _append_char(str, 'x'); + ++*offset; + } + + /* Insert child item */ + _buffer_format_string(child, str, arr, offset, + active_byteorder); + + /* Insert field name */ +#if defined(NPY_PY3K) + /* FIXME: XXX -- should it use UTF-8 here? */ + tmp = PyUnicode_AsUTF8String(name); +#else + tmp = name; +#endif + if (tmp == NULL || PyBytes_AsStringAndSize(tmp, &p, &len) < 0) { + PyErr_Clear(); + PyErr_SetString(PyExc_ValueError, "invalid field name"); + return -1; + } + _append_char(str, ':'); + while (len > 0) { + if (*p == ':') { + Py_DECREF(tmp); + PyErr_SetString(PyExc_ValueError, + "':' is not an allowed character in buffer " + "field names"); + return -1; + } + _append_char(str, *p); + ++p; + --len; + } + _append_char(str, ':'); +#if defined(NPY_PY3K) + Py_DECREF(tmp); +#endif + } + _append_char(str, '}'); + } + else { + int is_standard_size = 1; + int is_native_only_type = (descr->type_num == NPY_LONGDOUBLE || + descr->type_num == NPY_CLONGDOUBLE); + if (sizeof(npy_longlong) != 8) { + is_native_only_type = is_native_only_type || ( + descr->type_num == NPY_LONGLONG || + descr->type_num == NPY_ULONGLONG); + } + + *offset += descr->elsize; + + if (descr->byteorder == '=' && + _is_natively_aligned_at(descr, arr, *offset)) { + /* Prefer native types, to cater for Cython */ + is_standard_size = 0; + if (*active_byteorder != '@') { + _append_char(str, '@'); + *active_byteorder = '@'; + } + } + else if (descr->byteorder == '=' && is_native_only_type) { + /* Data types that have no standard size */ + is_standard_size = 0; + if (*active_byteorder != '^') { + _append_char(str, '^'); + *active_byteorder = '^'; + } + } + else if (descr->byteorder == '<' || descr->byteorder == '>' || + descr->byteorder == '=') { + is_standard_size = 1; + if (*active_byteorder != descr->byteorder) { + _append_char(str, descr->byteorder); + *active_byteorder = descr->byteorder; + } + + if (is_native_only_type) { + /* + * It's not possible to express native-only data types + * in non-native npy_byte orders + */ + PyErr_Format(PyExc_ValueError, + "cannot expose native-only dtype '%c' in " + "non-native byte order '%c' via buffer interface", + descr->type, descr->byteorder); + return -1; + } + } + + switch (descr->type_num) { + case NPY_BOOL: if (_append_char(str, '?')) return -1; break; + case NPY_BYTE: if (_append_char(str, 'b')) return -1; break; + case NPY_UBYTE: if (_append_char(str, 'B')) return -1; break; + case NPY_SHORT: if (_append_char(str, 'h')) return -1; break; + case NPY_USHORT: if (_append_char(str, 'H')) return -1; break; + case NPY_INT: if (_append_char(str, 'i')) return -1; break; + case NPY_UINT: if (_append_char(str, 'I')) return -1; break; + case NPY_LONG: + if (is_standard_size && (NPY_SIZEOF_LONG == 8)) { + if (_append_char(str, 'q')) return -1; + } + else { + if (_append_char(str, 'l')) return -1; + } + break; + case NPY_ULONG: + if (is_standard_size && (NPY_SIZEOF_LONG == 8)) { + if (_append_char(str, 'Q')) return -1; + } + else { + if (_append_char(str, 'L')) return -1; + } + break; + case NPY_LONGLONG: if (_append_char(str, 'q')) return -1; break; + case NPY_ULONGLONG: if (_append_char(str, 'Q')) return -1; break; + case NPY_HALF: if (_append_char(str, 'e')) return -1; break; + case NPY_FLOAT: if (_append_char(str, 'f')) return -1; break; + case NPY_DOUBLE: if (_append_char(str, 'd')) return -1; break; + case NPY_LONGDOUBLE: if (_append_char(str, 'g')) return -1; break; + case NPY_CFLOAT: if (_append_str(str, "Zf")) return -1; break; + case NPY_CDOUBLE: if (_append_str(str, "Zd")) return -1; break; + case NPY_CLONGDOUBLE: if (_append_str(str, "Zg")) return -1; break; + /* XXX: datetime */ + /* XXX: timedelta */ + case NPY_OBJECT: if (_append_char(str, 'O')) return -1; break; + case NPY_STRING: { + char buf[128]; + PyOS_snprintf(buf, sizeof(buf), "%ds", descr->elsize); + if (_append_str(str, buf)) return -1; + break; + } + case NPY_UNICODE: { + /* NumPy Unicode is always 4-byte */ + char buf[128]; + assert(descr->elsize % 4 == 0); + PyOS_snprintf(buf, sizeof(buf), "%dw", descr->elsize / 4); + if (_append_str(str, buf)) return -1; + break; + } + case NPY_VOID: { + /* Insert padding bytes */ + char buf[128]; + PyOS_snprintf(buf, sizeof(buf), "%dx", descr->elsize); + if (_append_str(str, buf)) return -1; + break; + } + default: + PyErr_Format(PyExc_ValueError, + "cannot include dtype '%c' in a buffer", + descr->type); + return -1; + } + } + + return 0; +} + + +/* + * Global information about all active buffers + * + * Note: because for backward compatibility we cannot define bf_releasebuffer, + * we must manually keep track of the additional data required by the buffers. + */ + +/* Additional per-array data required for providing the buffer interface */ +typedef struct { + char *format; + int ndim; + Py_ssize_t *strides; + Py_ssize_t *shape; +} _buffer_info_t; + +/* + * { id(array): [list of pointers to _buffer_info_t, the last one is latest] } + * + * Because shape, strides, and format can be different for different buffers, + * we may need to keep track of multiple buffer infos for each array. + * + * However, when none of them has changed, the same buffer info may be reused. + * + * Thread-safety is provided by GIL. + */ +static PyObject *_buffer_info_cache = NULL; + +/* Fill in the info structure */ +static _buffer_info_t* +_buffer_info_new(PyArrayObject *arr) +{ + _buffer_info_t *info; + _tmp_string_t fmt = {NULL, 0, 0}; + int k; + + info = malloc(sizeof(_buffer_info_t)); + if (info == NULL) { + goto fail; + } + + /* Fill in format */ + if (_buffer_format_string(PyArray_DESCR(arr), &fmt, arr, NULL, NULL) != 0) { + free(fmt.s); + goto fail; + } + _append_char(&fmt, '\0'); + info->format = fmt.s; + + /* Fill in shape and strides */ + info->ndim = PyArray_NDIM(arr); + + if (info->ndim == 0) { + info->shape = NULL; + info->strides = NULL; + } + else { + info->shape = malloc(sizeof(Py_ssize_t) * PyArray_NDIM(arr) * 2 + 1); + if (info->shape == NULL) { + goto fail; + } + info->strides = info->shape + PyArray_NDIM(arr); + for (k = 0; k < PyArray_NDIM(arr); ++k) { + info->shape[k] = PyArray_DIMS(arr)[k]; + info->strides[k] = PyArray_STRIDES(arr)[k]; + } + } + + return info; + +fail: + free(info); + return NULL; +} + +/* Compare two info structures */ +static Py_ssize_t +_buffer_info_cmp(_buffer_info_t *a, _buffer_info_t *b) +{ + Py_ssize_t c; + int k; + + c = strcmp(a->format, b->format); + if (c != 0) return c; + + c = a->ndim - b->ndim; + if (c != 0) return c; + + for (k = 0; k < a->ndim; ++k) { + c = a->shape[k] - b->shape[k]; + if (c != 0) return c; + c = a->strides[k] - b->strides[k]; + if (c != 0) return c; + } + + return 0; +} + +static void +_buffer_info_free(_buffer_info_t *info) +{ + if (info->format) { + free(info->format); + } + if (info->shape) { + free(info->shape); + } + free(info); +} + +/* Get buffer info from the global dictionary */ +static _buffer_info_t* +_buffer_get_info(PyObject *arr) +{ + PyObject *key = NULL, *item_list = NULL, *item = NULL; + _buffer_info_t *info = NULL, *old_info = NULL; + + if (_buffer_info_cache == NULL) { + _buffer_info_cache = PyDict_New(); + if (_buffer_info_cache == NULL) { + return NULL; + } + } + + /* Compute information */ + info = _buffer_info_new((PyArrayObject*)arr); + if (info == NULL) { + return NULL; + } + + /* Check if it is identical with an old one; reuse old one, if yes */ + key = PyLong_FromVoidPtr((void*)arr); + if (key == NULL) { + goto fail; + } + item_list = PyDict_GetItem(_buffer_info_cache, key); + + if (item_list != NULL) { + Py_INCREF(item_list); + if (PyList_GET_SIZE(item_list) > 0) { + item = PyList_GetItem(item_list, PyList_GET_SIZE(item_list) - 1); + old_info = (_buffer_info_t*)PyLong_AsVoidPtr(item); + + if (_buffer_info_cmp(info, old_info) == 0) { + _buffer_info_free(info); + info = old_info; + } + } + } + else { + item_list = PyList_New(0); + if (item_list == NULL) { + goto fail; + } + if (PyDict_SetItem(_buffer_info_cache, key, item_list) != 0) { + goto fail; + } + } + + if (info != old_info) { + /* Needs insertion */ + item = PyLong_FromVoidPtr((void*)info); + if (item == NULL) { + goto fail; + } + PyList_Append(item_list, item); + Py_DECREF(item); + } + + Py_DECREF(item_list); + Py_DECREF(key); + return info; + +fail: + if (info != NULL && info != old_info) { + _buffer_info_free(info); + } + Py_XDECREF(item_list); + Py_XDECREF(key); + return NULL; +} + +/* Clear buffer info from the global dictionary */ +static void +_buffer_clear_info(PyObject *arr) +{ + PyObject *key, *item_list, *item; + _buffer_info_t *info; + int k; + + if (_buffer_info_cache == NULL) { + return; + } + + key = PyLong_FromVoidPtr((void*)arr); + item_list = PyDict_GetItem(_buffer_info_cache, key); + if (item_list != NULL) { + for (k = 0; k < PyList_GET_SIZE(item_list); ++k) { + item = PyList_GET_ITEM(item_list, k); + info = (_buffer_info_t*)PyLong_AsVoidPtr(item); + _buffer_info_free(info); + } + PyDict_DelItem(_buffer_info_cache, key); + } + + Py_DECREF(key); +} + +/* + * Retrieving buffers + */ + +static int +array_getbuffer(PyObject *obj, Py_buffer *view, int flags) +{ + PyArrayObject *self; + _buffer_info_t *info = NULL; + + self = (PyArrayObject*)obj; + + /* Check whether we can provide the wanted properties */ + if ((flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS && + !PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)) { + PyErr_SetString(PyExc_ValueError, "ndarray is not C-contiguous"); + goto fail; + } + if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS && + !PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)) { + PyErr_SetString(PyExc_ValueError, "ndarray is not Fortran contiguous"); + goto fail; + } + if ((flags & PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS + && !PyArray_ISONESEGMENT(self)) { + PyErr_SetString(PyExc_ValueError, "ndarray is not contiguous"); + goto fail; + } + if ((flags & PyBUF_STRIDES) != PyBUF_STRIDES && + !PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)) { + /* Non-strided N-dim buffers must be C-contiguous */ + PyErr_SetString(PyExc_ValueError, "ndarray is not C-contiguous"); + goto fail; + } + if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { + if (PyArray_FailUnlessWriteable(self, "buffer source array") < 0) { + goto fail; + } + } + /* + * If a read-only buffer is requested on a read-write array, we return a + * read-write buffer, which is dubious behavior. But that's why this call + * is guarded by PyArray_ISWRITEABLE rather than (flags & + * PyBUF_WRITEABLE). + */ + if (PyArray_ISWRITEABLE(self)) { + if (array_might_be_written(self) < 0) { + goto fail; + } + } + + if (view == NULL) { + PyErr_SetString(PyExc_ValueError, "NULL view in getbuffer"); + goto fail; + } + + /* Fill in information */ + info = _buffer_get_info(obj); + if (info == NULL) { + goto fail; + } + + view->buf = PyArray_DATA(self); + view->suboffsets = NULL; + view->itemsize = PyArray_ITEMSIZE(self); + view->readonly = !PyArray_ISWRITEABLE(self); + view->internal = NULL; + view->len = PyArray_NBYTES(self); + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) { + view->format = info->format; + } else { + view->format = NULL; + } + if ((flags & PyBUF_ND) == PyBUF_ND) { + view->ndim = info->ndim; + view->shape = info->shape; + } + else { + view->ndim = 0; + view->shape = NULL; + } + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { + view->strides = info->strides; + +#ifdef NPY_RELAXED_STRIDES_CHECKING + /* + * If NPY_RELAXED_STRIDES_CHECKING is on, the array may be + * contiguous, but it won't look that way to Python when it + * tries to determine contiguity by looking at the strides + * (since one of the elements may be -1). In that case, just + * regenerate strides from shape. + */ + if (PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS) && + !((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS)) { + Py_ssize_t sd = view->itemsize; + int i; + + for (i = view->ndim-1; i >= 0; --i) { + view->strides[i] = sd; + sd *= view->shape[i]; + } + } + else if (PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)) { + Py_ssize_t sd = view->itemsize; + int i; + + for (i = 0; i < view->ndim; ++i) { + view->strides[i] = sd; + sd *= view->shape[i]; + } + } +#endif + } + else { + view->strides = NULL; + } + view->obj = (PyObject*)self; + + Py_INCREF(self); + return 0; + +fail: + return -1; +} + + +/* + * NOTE: for backward compatibility (esp. with PyArg_ParseTuple("s#", ...)) + * we do *not* define bf_releasebuffer at all. + * + * Instead, any extra data allocated with the buffer is released only in + * array_dealloc. + * + * Ensuring that the buffer stays in place is taken care by refcounting; + * ndarrays do not reallocate if there are references to them, and a buffer + * view holds one reference. + */ + +NPY_NO_EXPORT void +_array_dealloc_buffer_info(PyArrayObject *self) +{ + int reset_error_state = 0; + PyObject *ptype, *pvalue, *ptraceback; + + /* This function may be called when processing an exception -- + * we need to stash the error state to avoid confusing PyDict + */ + + if (PyErr_Occurred()) { + reset_error_state = 1; + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + } + + _buffer_clear_info((PyObject*)self); + + if (reset_error_state) { + PyErr_Restore(ptype, pvalue, ptraceback); + } +} + + +/*************************************************************************/ + +NPY_NO_EXPORT PyBufferProcs array_as_buffer = { +#if !defined(NPY_PY3K) + (readbufferproc)array_getreadbuf, /*bf_getreadbuffer*/ + (writebufferproc)array_getwritebuf, /*bf_getwritebuffer*/ + (segcountproc)array_getsegcount, /*bf_getsegcount*/ + (charbufferproc)array_getcharbuf, /*bf_getcharbuffer*/ +#endif + (getbufferproc)array_getbuffer, + (releasebufferproc)0, +}; + + +/************************************************************************* + * Convert PEP 3118 format string to PyArray_Descr + */ + +static int +_descriptor_from_pep3118_format_fast(char *s, PyObject **result); + +static int +_pep3118_letter_to_type(char letter, int native, int complex); + +NPY_NO_EXPORT PyArray_Descr* +_descriptor_from_pep3118_format(char *s) +{ + char *buf, *p; + int in_name = 0; + int obtained; + PyObject *descr; + PyObject *str; + PyObject *_numpy_internal; + + if (s == NULL) { + return PyArray_DescrNewFromType(NPY_BYTE); + } + + /* Fast path */ + obtained = _descriptor_from_pep3118_format_fast(s, &descr); + if (obtained) { + return (PyArray_Descr*)descr; + } + + /* Strip whitespace, except from field names */ + buf = malloc(strlen(s) + 1); + if (buf == NULL) { + PyErr_NoMemory(); + return NULL; + } + p = buf; + while (*s != '\0') { + if (*s == ':') { + in_name = !in_name; + *p = *s; + p++; + } + else if (in_name || !NumPyOS_ascii_isspace(*s)) { + *p = *s; + p++; + } + s++; + } + *p = '\0'; + + str = PyUString_FromStringAndSize(buf, strlen(buf)); + if (str == NULL) { + free(buf); + return NULL; + } + + /* Convert */ + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + Py_DECREF(str); + free(buf); + return NULL; + } + descr = PyObject_CallMethod( + _numpy_internal, "_dtype_from_pep3118", "O", str); + Py_DECREF(str); + Py_DECREF(_numpy_internal); + if (descr == NULL) { + PyErr_Format(PyExc_ValueError, + "'%s' is not a valid PEP 3118 buffer format string", buf); + free(buf); + return NULL; + } + if (!PyArray_DescrCheck(descr)) { + PyErr_Format(PyExc_RuntimeError, + "internal error: numpy.core._internal._dtype_from_pep3118 " + "did not return a valid dtype, got %s", buf); + Py_DECREF(descr); + free(buf); + return NULL; + } + free(buf); + return (PyArray_Descr*)descr; +} + +/* + * Fast path for parsing buffer strings corresponding to simple types. + * + * Currently, this deals only with single-element data types. + */ + +static int +_descriptor_from_pep3118_format_fast(char *s, PyObject **result) +{ + PyArray_Descr *descr; + + int is_standard_size = 0; + char byte_order = '='; + int is_complex = 0; + + int type_num = NPY_BYTE; + int item_seen = 0; + + for (; *s != '\0'; ++s) { + is_complex = 0; + switch (*s) { + case '@': + case '^': + /* ^ means no alignment; doesn't matter for a single element */ + byte_order = '='; + is_standard_size = 0; + break; + case '<': + byte_order = '<'; + is_standard_size = 1; + break; + case '>': + case '!': + byte_order = '>'; + is_standard_size = 1; + break; + case '=': + byte_order = '='; + is_standard_size = 1; + break; + case 'Z': + is_complex = 1; + ++s; + default: + if (item_seen) { + /* Not a single-element data type */ + return 0; + } + type_num = _pep3118_letter_to_type(*s, !is_standard_size, + is_complex); + if (type_num < 0) { + /* Something unknown */ + return 0; + } + item_seen = 1; + break; + } + } + + if (!item_seen) { + return 0; + } + + descr = PyArray_DescrFromType(type_num); + if (byte_order == '=') { + *result = (PyObject*)descr; + } + else { + *result = (PyObject*)PyArray_DescrNewByteorder(descr, byte_order); + Py_DECREF(descr); + } + + return 1; +} + +static int +_pep3118_letter_to_type(char letter, int native, int complex) +{ + switch (letter) + { + case '?': return NPY_BOOL; + case 'b': return NPY_BYTE; + case 'B': return NPY_UBYTE; + case 'h': return native ? NPY_SHORT : NPY_INT16; + case 'H': return native ? NPY_USHORT : NPY_UINT16; + case 'i': return native ? NPY_INT : NPY_INT32; + case 'I': return native ? NPY_UINT : NPY_UINT32; + case 'l': return native ? NPY_LONG : NPY_INT32; + case 'L': return native ? NPY_ULONG : NPY_UINT32; + case 'q': return native ? NPY_LONGLONG : NPY_INT64; + case 'Q': return native ? NPY_ULONGLONG : NPY_UINT64; + case 'e': return NPY_HALF; + case 'f': return complex ? NPY_CFLOAT : NPY_FLOAT; + case 'd': return complex ? NPY_CDOUBLE : NPY_DOUBLE; + case 'g': return native ? (complex ? NPY_CLONGDOUBLE : NPY_LONGDOUBLE) : -1; + default: + /* Other unhandled cases */ + return -1; + } + return -1; +} diff --git a/numpy/core/src/multiarray/buffer.h b/numpy/core/src/multiarray/buffer.h new file mode 100644 index 0000000..d2ea01b --- /dev/null +++ b/numpy/core/src/multiarray/buffer.h @@ -0,0 +1,12 @@ +#ifndef _NPY_PRIVATE_BUFFER_H_ +#define _NPY_PRIVATE_BUFFER_H_ + +extern NPY_NO_EXPORT PyBufferProcs array_as_buffer; + +NPY_NO_EXPORT void +_array_dealloc_buffer_info(PyArrayObject *self); + +NPY_NO_EXPORT PyArray_Descr* +_descriptor_from_pep3118_format(char *s); + +#endif diff --git a/numpy/core/src/multiarray/calculation.c b/numpy/core/src/multiarray/calculation.c new file mode 100644 index 0000000..e24ac2b --- /dev/null +++ b/numpy/core/src/multiarray/calculation.c @@ -0,0 +1,1233 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "common.h" +#include "number.h" + +#include "calculation.h" +#include "array_assign.h" + +static double +power_of_ten(int n) +{ + static const double p10[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8}; + double ret; + if (n < 9) { + ret = p10[n]; + } + else { + ret = 1e9; + while (n-- > 9) { + ret *= 10.; + } + } + return ret; +} + +/*NUMPY_API + * ArgMax + */ +NPY_NO_EXPORT PyObject * +PyArray_ArgMax(PyArrayObject *op, int axis, PyArrayObject *out) +{ + PyArrayObject *ap = NULL, *rp = NULL; + PyArray_ArgFunc* arg_func; + char *ip; + npy_intp *rptr; + npy_intp i, n, m; + int elsize; + NPY_BEGIN_THREADS_DEF; + + if ((ap = (PyArrayObject *)PyArray_CheckAxis(op, &axis, 0)) == NULL) { + return NULL; + } + /* + * We need to permute the array so that axis is placed at the end. + * And all other dimensions are shifted left. + */ + if (axis != PyArray_NDIM(ap)-1) { + PyArray_Dims newaxes; + npy_intp dims[NPY_MAXDIMS]; + int j; + + newaxes.ptr = dims; + newaxes.len = PyArray_NDIM(ap); + for (j = 0; j < axis; j++) { + dims[j] = j; + } + for (j = axis; j < PyArray_NDIM(ap) - 1; j++) { + dims[j] = j + 1; + } + dims[PyArray_NDIM(ap) - 1] = axis; + op = (PyArrayObject *)PyArray_Transpose(ap, &newaxes); + Py_DECREF(ap); + if (op == NULL) { + return NULL; + } + } + else { + op = ap; + } + + /* Will get native-byte order contiguous copy. */ + ap = (PyArrayObject *)PyArray_ContiguousFromAny((PyObject *)op, + PyArray_DESCR(op)->type_num, 1, 0); + Py_DECREF(op); + if (ap == NULL) { + return NULL; + } + arg_func = PyArray_DESCR(ap)->f->argmax; + if (arg_func == NULL) { + PyErr_SetString(PyExc_TypeError, + "data type not ordered"); + goto fail; + } + elsize = PyArray_DESCR(ap)->elsize; + m = PyArray_DIMS(ap)[PyArray_NDIM(ap)-1]; + if (m == 0) { + PyErr_SetString(PyExc_ValueError, + "attempt to get argmax of an empty sequence"); + goto fail; + } + + if (!out) { + rp = (PyArrayObject *)PyArray_New(Py_TYPE(ap), PyArray_NDIM(ap)-1, + PyArray_DIMS(ap), NPY_INTP, + NULL, NULL, 0, 0, + (PyObject *)ap); + if (rp == NULL) { + goto fail; + } + } + else { + if ((PyArray_NDIM(out) != PyArray_NDIM(ap) - 1) || + !PyArray_CompareLists(PyArray_DIMS(out), PyArray_DIMS(ap), + PyArray_NDIM(out))) { + PyErr_SetString(PyExc_ValueError, + "output array does not match result of np.argmax."); + goto fail; + } + rp = (PyArrayObject *)PyArray_FromArray(out, + PyArray_DescrFromType(NPY_INTP), + NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY); + if (rp == NULL) { + goto fail; + } + } + + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ap)); + n = PyArray_SIZE(ap)/m; + rptr = (npy_intp *)PyArray_DATA(rp); + for (ip = PyArray_DATA(ap), i = 0; i < n; i++, ip += elsize*m) { + arg_func(ip, m, rptr, ap); + rptr += 1; + } + NPY_END_THREADS_DESCR(PyArray_DESCR(ap)); + + Py_DECREF(ap); + /* Trigger the UPDATEIFCOPY/WRTIEBACKIFCOPY if necessary */ + if (out != NULL && out != rp) { + PyArray_ResolveWritebackIfCopy(rp); + Py_DECREF(rp); + rp = out; + Py_INCREF(rp); + } + return (PyObject *)rp; + + fail: + Py_DECREF(ap); + Py_XDECREF(rp); + return NULL; +} + +/*NUMPY_API + * ArgMin + */ +NPY_NO_EXPORT PyObject * +PyArray_ArgMin(PyArrayObject *op, int axis, PyArrayObject *out) +{ + PyArrayObject *ap = NULL, *rp = NULL; + PyArray_ArgFunc* arg_func; + char *ip; + npy_intp *rptr; + npy_intp i, n, m; + int elsize; + NPY_BEGIN_THREADS_DEF; + + if ((ap = (PyArrayObject *)PyArray_CheckAxis(op, &axis, 0)) == NULL) { + return NULL; + } + /* + * We need to permute the array so that axis is placed at the end. + * And all other dimensions are shifted left. + */ + if (axis != PyArray_NDIM(ap)-1) { + PyArray_Dims newaxes; + npy_intp dims[NPY_MAXDIMS]; + int i; + + newaxes.ptr = dims; + newaxes.len = PyArray_NDIM(ap); + for (i = 0; i < axis; i++) { + dims[i] = i; + } + for (i = axis; i < PyArray_NDIM(ap) - 1; i++) { + dims[i] = i + 1; + } + dims[PyArray_NDIM(ap) - 1] = axis; + op = (PyArrayObject *)PyArray_Transpose(ap, &newaxes); + Py_DECREF(ap); + if (op == NULL) { + return NULL; + } + } + else { + op = ap; + } + + /* Will get native-byte order contiguous copy. */ + ap = (PyArrayObject *)PyArray_ContiguousFromAny((PyObject *)op, + PyArray_DESCR(op)->type_num, 1, 0); + Py_DECREF(op); + if (ap == NULL) { + return NULL; + } + arg_func = PyArray_DESCR(ap)->f->argmin; + if (arg_func == NULL) { + PyErr_SetString(PyExc_TypeError, + "data type not ordered"); + goto fail; + } + elsize = PyArray_DESCR(ap)->elsize; + m = PyArray_DIMS(ap)[PyArray_NDIM(ap)-1]; + if (m == 0) { + PyErr_SetString(PyExc_ValueError, + "attempt to get argmin of an empty sequence"); + goto fail; + } + + if (!out) { + rp = (PyArrayObject *)PyArray_New(Py_TYPE(ap), PyArray_NDIM(ap)-1, + PyArray_DIMS(ap), NPY_INTP, + NULL, NULL, 0, 0, + (PyObject *)ap); + if (rp == NULL) { + goto fail; + } + } + else { + if ((PyArray_NDIM(out) != PyArray_NDIM(ap) - 1) || + !PyArray_CompareLists(PyArray_DIMS(out), PyArray_DIMS(ap), + PyArray_NDIM(out))) { + PyErr_SetString(PyExc_ValueError, + "output array does not match result of np.argmin."); + goto fail; + } + rp = (PyArrayObject *)PyArray_FromArray(out, + PyArray_DescrFromType(NPY_INTP), + NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY); + if (rp == NULL) { + goto fail; + } + } + + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ap)); + n = PyArray_SIZE(ap)/m; + rptr = (npy_intp *)PyArray_DATA(rp); + for (ip = PyArray_DATA(ap), i = 0; i < n; i++, ip += elsize*m) { + arg_func(ip, m, rptr, ap); + rptr += 1; + } + NPY_END_THREADS_DESCR(PyArray_DESCR(ap)); + + Py_DECREF(ap); + /* Trigger the UPDATEIFCOPY/WRITEBACKIFCOPY if necessary */ + if (out != NULL && out != rp) { + PyArray_ResolveWritebackIfCopy(rp); + Py_DECREF(rp); + rp = out; + Py_INCREF(rp); + } + return (PyObject *)rp; + + fail: + Py_DECREF(ap); + Py_XDECREF(rp); + return NULL; +} + +/*NUMPY_API + * Max + */ +NPY_NO_EXPORT PyObject * +PyArray_Max(PyArrayObject *ap, int axis, PyArrayObject *out) +{ + PyArrayObject *arr; + PyObject *ret; + + arr = (PyArrayObject *)PyArray_CheckAxis(ap, &axis, 0); + if (arr == NULL) { + return NULL; + } + ret = PyArray_GenericReduceFunction(arr, n_ops.maximum, axis, + PyArray_DESCR(arr)->type_num, out); + Py_DECREF(arr); + return ret; +} + +/*NUMPY_API + * Min + */ +NPY_NO_EXPORT PyObject * +PyArray_Min(PyArrayObject *ap, int axis, PyArrayObject *out) +{ + PyArrayObject *arr; + PyObject *ret; + + arr=(PyArrayObject *)PyArray_CheckAxis(ap, &axis, 0); + if (arr == NULL) { + return NULL; + } + ret = PyArray_GenericReduceFunction(arr, n_ops.minimum, axis, + PyArray_DESCR(arr)->type_num, out); + Py_DECREF(arr); + return ret; +} + +/*NUMPY_API + * Ptp + */ +NPY_NO_EXPORT PyObject * +PyArray_Ptp(PyArrayObject *ap, int axis, PyArrayObject *out) +{ + PyArrayObject *arr; + PyObject *ret; + PyObject *obj1 = NULL, *obj2 = NULL; + + arr=(PyArrayObject *)PyArray_CheckAxis(ap, &axis, 0); + if (arr == NULL) { + return NULL; + } + obj1 = PyArray_Max(arr, axis, out); + if (obj1 == NULL) { + goto fail; + } + obj2 = PyArray_Min(arr, axis, NULL); + if (obj2 == NULL) { + goto fail; + } + Py_DECREF(arr); + if (out) { + ret = PyObject_CallFunction(n_ops.subtract, "OOO", out, obj2, out); + } + else { + ret = PyNumber_Subtract(obj1, obj2); + } + Py_DECREF(obj1); + Py_DECREF(obj2); + return ret; + + fail: + Py_XDECREF(arr); + Py_XDECREF(obj1); + Py_XDECREF(obj2); + return NULL; +} + + + +/*NUMPY_API + * Set variance to 1 to by-pass square-root calculation and return variance + * Std + */ +NPY_NO_EXPORT PyObject * +PyArray_Std(PyArrayObject *self, int axis, int rtype, PyArrayObject *out, + int variance) +{ + return __New_PyArray_Std(self, axis, rtype, out, variance, 0); +} + +NPY_NO_EXPORT PyObject * +__New_PyArray_Std(PyArrayObject *self, int axis, int rtype, PyArrayObject *out, + int variance, int num) +{ + PyObject *obj1 = NULL, *obj2 = NULL, *obj3 = NULL; + PyArrayObject *arr1 = NULL, *arr2 = NULL, *arrnew = NULL; + PyObject *ret = NULL, *newshape = NULL; + int i, n; + npy_intp val; + + arrnew = (PyArrayObject *)PyArray_CheckAxis(self, &axis, 0); + if (arrnew == NULL) { + return NULL; + } + /* Compute and reshape mean */ + arr1 = (PyArrayObject *)PyArray_EnsureAnyArray( + PyArray_Mean(arrnew, axis, rtype, NULL)); + if (arr1 == NULL) { + Py_DECREF(arrnew); + return NULL; + } + n = PyArray_NDIM(arrnew); + newshape = PyTuple_New(n); + if (newshape == NULL) { + Py_DECREF(arr1); + Py_DECREF(arrnew); + return NULL; + } + for (i = 0; i < n; i++) { + if (i == axis) { + val = 1; + } + else { + val = PyArray_DIM(arrnew,i); + } + PyTuple_SET_ITEM(newshape, i, PyInt_FromLong((long)val)); + } + arr2 = (PyArrayObject *)PyArray_Reshape(arr1, newshape); + Py_DECREF(arr1); + Py_DECREF(newshape); + if (arr2 == NULL) { + Py_DECREF(arrnew); + return NULL; + } + + /* Compute x = x - mx */ + arr1 = (PyArrayObject *)PyArray_EnsureAnyArray( + PyNumber_Subtract((PyObject *)arrnew, (PyObject *)arr2)); + Py_DECREF(arr2); + if (arr1 == NULL) { + Py_DECREF(arrnew); + return NULL; + } + /* Compute x * x */ + if (PyArray_ISCOMPLEX(arr1)) { + obj3 = PyArray_Conjugate(arr1, NULL); + } + else { + obj3 = (PyObject *)arr1; + Py_INCREF(arr1); + } + if (obj3 == NULL) { + Py_DECREF(arrnew); + return NULL; + } + arr2 = (PyArrayObject *)PyArray_EnsureAnyArray( + PyArray_GenericBinaryFunction(arr1, obj3, n_ops.multiply)); + Py_DECREF(arr1); + Py_DECREF(obj3); + if (arr2 == NULL) { + Py_DECREF(arrnew); + return NULL; + } + if (PyArray_ISCOMPLEX(arr2)) { + obj3 = PyObject_GetAttrString((PyObject *)arr2, "real"); + switch(rtype) { + case NPY_CDOUBLE: + rtype = NPY_DOUBLE; + break; + case NPY_CFLOAT: + rtype = NPY_FLOAT; + break; + case NPY_CLONGDOUBLE: + rtype = NPY_LONGDOUBLE; + break; + } + } + else { + obj3 = (PyObject *)arr2; + Py_INCREF(arr2); + } + if (obj3 == NULL) { + Py_DECREF(arrnew); + return NULL; + } + /* Compute add.reduce(x*x,axis) */ + obj1 = PyArray_GenericReduceFunction((PyArrayObject *)obj3, n_ops.add, + axis, rtype, NULL); + Py_DECREF(obj3); + Py_DECREF(arr2); + if (obj1 == NULL) { + Py_DECREF(arrnew); + return NULL; + } + n = PyArray_DIM(arrnew,axis); + Py_DECREF(arrnew); + n = (n-num); + if (n == 0) { + n = 1; + } + obj2 = PyFloat_FromDouble(1.0/((double )n)); + if (obj2 == NULL) { + Py_DECREF(obj1); + return NULL; + } + ret = PyNumber_Multiply(obj1, obj2); + Py_DECREF(obj1); + Py_DECREF(obj2); + + if (!variance) { + arr1 = (PyArrayObject *)PyArray_EnsureAnyArray(ret); + /* sqrt() */ + ret = PyArray_GenericUnaryFunction(arr1, n_ops.sqrt); + Py_DECREF(arr1); + } + if (ret == NULL) { + return NULL; + } + if (PyArray_CheckExact(self)) { + goto finish; + } + if (PyArray_Check(self) && Py_TYPE(self) == Py_TYPE(ret)) { + goto finish; + } + arr1 = (PyArrayObject *)PyArray_EnsureArray(ret); + if (arr1 == NULL) { + return NULL; + } + ret = PyArray_View(arr1, NULL, Py_TYPE(self)); + Py_DECREF(arr1); + +finish: + if (out) { + if (PyArray_AssignArray(out, (PyArrayObject *)ret, + NULL, NPY_DEFAULT_ASSIGN_CASTING) < 0) { + Py_DECREF(ret); + return NULL; + } + Py_DECREF(ret); + Py_INCREF(out); + return (PyObject *)out; + } + return ret; +} + + +/*NUMPY_API + *Sum + */ +NPY_NO_EXPORT PyObject * +PyArray_Sum(PyArrayObject *self, int axis, int rtype, PyArrayObject *out) +{ + PyObject *arr, *ret; + + arr = PyArray_CheckAxis(self, &axis, 0); + if (arr == NULL) { + return NULL; + } + ret = PyArray_GenericReduceFunction((PyArrayObject *)arr, n_ops.add, axis, + rtype, out); + Py_DECREF(arr); + return ret; +} + +/*NUMPY_API + * Prod + */ +NPY_NO_EXPORT PyObject * +PyArray_Prod(PyArrayObject *self, int axis, int rtype, PyArrayObject *out) +{ + PyObject *arr, *ret; + + arr = PyArray_CheckAxis(self, &axis, 0); + if (arr == NULL) { + return NULL; + } + ret = PyArray_GenericReduceFunction((PyArrayObject *)arr, + n_ops.multiply, axis, + rtype, out); + Py_DECREF(arr); + return ret; +} + +/*NUMPY_API + *CumSum + */ +NPY_NO_EXPORT PyObject * +PyArray_CumSum(PyArrayObject *self, int axis, int rtype, PyArrayObject *out) +{ + PyObject *arr, *ret; + + arr = PyArray_CheckAxis(self, &axis, 0); + if (arr == NULL) { + return NULL; + } + ret = PyArray_GenericAccumulateFunction((PyArrayObject *)arr, + n_ops.add, axis, + rtype, out); + Py_DECREF(arr); + return ret; +} + +/*NUMPY_API + * CumProd + */ +NPY_NO_EXPORT PyObject * +PyArray_CumProd(PyArrayObject *self, int axis, int rtype, PyArrayObject *out) +{ + PyObject *arr, *ret; + + arr = PyArray_CheckAxis(self, &axis, 0); + if (arr == NULL) { + return NULL; + } + + ret = PyArray_GenericAccumulateFunction((PyArrayObject *)arr, + n_ops.multiply, axis, + rtype, out); + Py_DECREF(arr); + return ret; +} + +/*NUMPY_API + * Round + */ +NPY_NO_EXPORT PyObject * +PyArray_Round(PyArrayObject *a, int decimals, PyArrayObject *out) +{ + PyObject *f, *ret = NULL, *tmp, *op1, *op2; + int ret_int=0; + PyArray_Descr *my_descr; + if (out && (PyArray_SIZE(out) != PyArray_SIZE(a))) { + PyErr_SetString(PyExc_ValueError, + "invalid output shape"); + return NULL; + } + if (PyArray_ISCOMPLEX(a)) { + PyObject *part; + PyObject *round_part; + PyObject *arr; + int res; + + if (out) { + arr = (PyObject *)out; + Py_INCREF(arr); + } + else { + arr = PyArray_Copy(a); + if (arr == NULL) { + return NULL; + } + } + + /* arr.real = a.real.round(decimals) */ + part = PyObject_GetAttrString((PyObject *)a, "real"); + if (part == NULL) { + Py_DECREF(arr); + return NULL; + } + part = PyArray_EnsureAnyArray(part); + round_part = PyArray_Round((PyArrayObject *)part, + decimals, NULL); + Py_DECREF(part); + if (round_part == NULL) { + Py_DECREF(arr); + return NULL; + } + res = PyObject_SetAttrString(arr, "real", round_part); + Py_DECREF(round_part); + if (res < 0) { + Py_DECREF(arr); + return NULL; + } + + /* arr.imag = a.imag.round(decimals) */ + part = PyObject_GetAttrString((PyObject *)a, "imag"); + if (part == NULL) { + Py_DECREF(arr); + return NULL; + } + part = PyArray_EnsureAnyArray(part); + round_part = PyArray_Round((PyArrayObject *)part, + decimals, NULL); + Py_DECREF(part); + if (round_part == NULL) { + Py_DECREF(arr); + return NULL; + } + res = PyObject_SetAttrString(arr, "imag", round_part); + Py_DECREF(round_part); + if (res < 0) { + Py_DECREF(arr); + return NULL; + } + return arr; + } + /* do the most common case first */ + if (decimals >= 0) { + if (PyArray_ISINTEGER(a)) { + if (out) { + if (PyArray_AssignArray(out, a, + NULL, NPY_DEFAULT_ASSIGN_CASTING) < 0) { + return NULL; + } + Py_INCREF(out); + return (PyObject *)out; + } + else { + Py_INCREF(a); + return (PyObject *)a; + } + } + if (decimals == 0) { + if (out) { + return PyObject_CallFunction(n_ops.rint, "OO", a, out); + } + return PyObject_CallFunction(n_ops.rint, "O", a); + } + op1 = n_ops.multiply; + op2 = n_ops.true_divide; + } + else { + op1 = n_ops.true_divide; + op2 = n_ops.multiply; + decimals = -decimals; + } + if (!out) { + if (PyArray_ISINTEGER(a)) { + ret_int = 1; + my_descr = PyArray_DescrFromType(NPY_DOUBLE); + } + else { + Py_INCREF(PyArray_DESCR(a)); + my_descr = PyArray_DESCR(a); + } + out = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a), + my_descr, + PyArray_ISFORTRAN(a)); + if (out == NULL) { + return NULL; + } + } + else { + Py_INCREF(out); + } + f = PyFloat_FromDouble(power_of_ten(decimals)); + if (f == NULL) { + return NULL; + } + ret = PyObject_CallFunction(op1, "OOO", a, f, out); + if (ret == NULL) { + goto finish; + } + tmp = PyObject_CallFunction(n_ops.rint, "OO", ret, ret); + if (tmp == NULL) { + Py_DECREF(ret); + ret = NULL; + goto finish; + } + Py_DECREF(tmp); + tmp = PyObject_CallFunction(op2, "OOO", ret, f, ret); + if (tmp == NULL) { + Py_DECREF(ret); + ret = NULL; + goto finish; + } + Py_DECREF(tmp); + + finish: + Py_DECREF(f); + Py_DECREF(out); + if (ret_int) { + Py_INCREF(PyArray_DESCR(a)); + tmp = PyArray_CastToType((PyArrayObject *)ret, + PyArray_DESCR(a), PyArray_ISFORTRAN(a)); + Py_DECREF(ret); + return tmp; + } + return ret; +} + + +/*NUMPY_API + * Mean + */ +NPY_NO_EXPORT PyObject * +PyArray_Mean(PyArrayObject *self, int axis, int rtype, PyArrayObject *out) +{ + PyObject *obj1 = NULL, *obj2 = NULL, *ret; + PyArrayObject *arr; + + arr = (PyArrayObject *)PyArray_CheckAxis(self, &axis, 0); + if (arr == NULL) { + return NULL; + } + obj1 = PyArray_GenericReduceFunction(arr, n_ops.add, axis, + rtype, out); + obj2 = PyFloat_FromDouble((double)PyArray_DIM(arr,axis)); + Py_DECREF(arr); + if (obj1 == NULL || obj2 == NULL) { + Py_XDECREF(obj1); + Py_XDECREF(obj2); + return NULL; + } + if (!out) { +#if defined(NPY_PY3K) + ret = PyNumber_TrueDivide(obj1, obj2); +#else + ret = PyNumber_Divide(obj1, obj2); +#endif + } + else { + ret = PyObject_CallFunction(n_ops.divide, "OOO", out, obj2, out); + } + Py_DECREF(obj1); + Py_DECREF(obj2); + return ret; +} + +/*NUMPY_API + * Any + */ +NPY_NO_EXPORT PyObject * +PyArray_Any(PyArrayObject *self, int axis, PyArrayObject *out) +{ + PyObject *arr, *ret; + + arr = PyArray_CheckAxis(self, &axis, 0); + if (arr == NULL) { + return NULL; + } + ret = PyArray_GenericReduceFunction((PyArrayObject *)arr, + n_ops.logical_or, axis, + NPY_BOOL, out); + Py_DECREF(arr); + return ret; +} + +/*NUMPY_API + * All + */ +NPY_NO_EXPORT PyObject * +PyArray_All(PyArrayObject *self, int axis, PyArrayObject *out) +{ + PyObject *arr, *ret; + + arr = PyArray_CheckAxis(self, &axis, 0); + if (arr == NULL) { + return NULL; + } + ret = PyArray_GenericReduceFunction((PyArrayObject *)arr, + n_ops.logical_and, axis, + NPY_BOOL, out); + Py_DECREF(arr); + return ret; +} + + +static PyObject * +_GenericBinaryOutFunction(PyArrayObject *m1, PyObject *m2, PyArrayObject *out, + PyObject *op) +{ + if (out == NULL) { + return PyObject_CallFunction(op, "OO", m1, m2); + } + else { + PyObject *args, *ret; + static PyObject *kw = NULL; + + if (kw == NULL) { + kw = Py_BuildValue("{s:s}", "casting", "unsafe"); + if (kw == NULL) { + return NULL; + } + } + + args = Py_BuildValue("OOO", m1, m2, out); + if (args == NULL) { + return NULL; + } + + ret = PyObject_Call(op, args, kw); + + Py_DECREF(args); + + return ret; + } +} + +static PyObject * +_slow_array_clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *out) +{ + PyObject *res1=NULL, *res2=NULL; + + if (max != NULL) { + res1 = _GenericBinaryOutFunction(self, max, out, n_ops.minimum); + if (res1 == NULL) { + return NULL; + } + } + else { + res1 = (PyObject *)self; + Py_INCREF(res1); + } + + if (min != NULL) { + res2 = _GenericBinaryOutFunction((PyArrayObject *)res1, + min, out, n_ops.maximum); + if (res2 == NULL) { + Py_XDECREF(res1); + return NULL; + } + } + else { + res2 = res1; + Py_INCREF(res2); + } + Py_DECREF(res1); + return res2; +} + +/*NUMPY_API + * Clip + */ +NPY_NO_EXPORT PyObject * +PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *out) +{ + PyArray_FastClipFunc *func; + int outgood = 0, ingood = 0; + PyArrayObject *maxa = NULL; + PyArrayObject *mina = NULL; + PyArrayObject *newout = NULL, *newin = NULL; + PyArray_Descr *indescr = NULL, *newdescr = NULL; + char *max_data, *min_data; + PyObject *zero; + + /* Treat None the same as NULL */ + if (min == Py_None) { + min = NULL; + } + if (max == Py_None) { + max = NULL; + } + + if ((max == NULL) && (min == NULL)) { + PyErr_SetString(PyExc_ValueError, + "array_clip: must set either max or min"); + return NULL; + } + + func = PyArray_DESCR(self)->f->fastclip; + if (func == NULL + || (min != NULL && !PyArray_CheckAnyScalar(min)) + || (max != NULL && !PyArray_CheckAnyScalar(max)) + || PyArray_ISBYTESWAPPED(self) + || (out && PyArray_ISBYTESWAPPED(out))) { + return _slow_array_clip(self, min, max, out); + } + /* Use the fast scalar clip function */ + + /* First we need to figure out the correct type */ + if (min != NULL) { + indescr = PyArray_DescrFromObject(min, NULL); + if (indescr == NULL) { + goto fail; + } + } + if (max != NULL) { + newdescr = PyArray_DescrFromObject(max, indescr); + Py_XDECREF(indescr); + indescr = NULL; + if (newdescr == NULL) { + goto fail; + } + } + else { + /* Steal the reference */ + newdescr = indescr; + indescr = NULL; + } + + + /* + * Use the scalar descriptor only if it is of a bigger + * KIND than the input array (and then find the + * type that matches both). + */ + if (PyArray_ScalarKind(newdescr->type_num, NULL) > + PyArray_ScalarKind(PyArray_DESCR(self)->type_num, NULL)) { + indescr = PyArray_PromoteTypes(newdescr, PyArray_DESCR(self)); + if (indescr == NULL) { + goto fail; + } + func = indescr->f->fastclip; + if (func == NULL) { + Py_DECREF(indescr); + return _slow_array_clip(self, min, max, out); + } + } + else { + indescr = PyArray_DESCR(self); + Py_INCREF(indescr); + } + Py_DECREF(newdescr); + newdescr = NULL; + + if (!PyDataType_ISNOTSWAPPED(indescr)) { + PyArray_Descr *descr2; + descr2 = PyArray_DescrNewByteorder(indescr, '='); + Py_DECREF(indescr); + indescr = NULL; + if (descr2 == NULL) { + goto fail; + } + indescr = descr2; + } + + /* Convert max to an array */ + if (max != NULL) { + Py_INCREF(indescr); + maxa = (PyArrayObject *)PyArray_FromAny(max, indescr, 0, 0, + NPY_ARRAY_DEFAULT, NULL); + if (maxa == NULL) { + goto fail; + } + } + + /* + * If we are unsigned, then make sure min is not < 0 + * This is to match the behavior of _slow_array_clip + * + * We allow min and max to go beyond the limits + * for other data-types in which case they + * are interpreted as their modular counterparts. + */ + if (min != NULL) { + if (PyArray_ISUNSIGNED(self)) { + int cmp; + zero = PyInt_FromLong(0); + cmp = PyObject_RichCompareBool(min, zero, Py_LT); + if (cmp == -1) { + Py_DECREF(zero); + goto fail; + } + if (cmp == 1) { + min = zero; + } + else { + Py_DECREF(zero); + Py_INCREF(min); + } + } + else { + Py_INCREF(min); + } + + /* Convert min to an array */ + Py_INCREF(indescr); + mina = (PyArrayObject *)PyArray_FromAny(min, indescr, 0, 0, + NPY_ARRAY_DEFAULT, NULL); + Py_DECREF(min); + if (mina == NULL) { + goto fail; + } + } + + /* + * Check to see if input is single-segment, aligned, + * and in native byteorder + */ + if (PyArray_ISONESEGMENT(self) && + PyArray_CHKFLAGS(self, NPY_ARRAY_ALIGNED) && + PyArray_ISNOTSWAPPED(self) && + (PyArray_DESCR(self) == indescr)) { + ingood = 1; + } + if (!ingood) { + int flags; + + if (PyArray_ISFORTRAN(self)) { + flags = NPY_ARRAY_FARRAY; + } + else { + flags = NPY_ARRAY_CARRAY; + } + Py_INCREF(indescr); + newin = (PyArrayObject *)PyArray_FromArray(self, indescr, flags); + if (newin == NULL) { + goto fail; + } + } + else { + newin = self; + Py_INCREF(newin); + } + + /* + * At this point, newin is a single-segment, aligned, and correct + * byte-order array of the correct type + * + * if ingood == 0, then it is a copy, otherwise, + * it is the original input. + */ + + /* + * If we have already made a copy of the data, then use + * that as the output array + */ + if (out == NULL && !ingood) { + out = newin; + } + + /* + * Now, we know newin is a usable array for fastclip, + * we need to make sure the output array is available + * and usable + */ + if (out == NULL) { + Py_INCREF(indescr); + out = (PyArrayObject*)PyArray_NewFromDescr(Py_TYPE(self), + indescr, PyArray_NDIM(self), + PyArray_DIMS(self), + NULL, NULL, + PyArray_ISFORTRAN(self), + (PyObject *)self); + if (out == NULL) { + goto fail; + } + + outgood = 1; + } + else Py_INCREF(out); + /* Input is good at this point */ + if (out == newin) { + outgood = 1; + } + if (!outgood && PyArray_ISONESEGMENT(out) && + PyArray_CHKFLAGS(out, NPY_ARRAY_ALIGNED) && + PyArray_ISNOTSWAPPED(out) && + PyArray_EquivTypes(PyArray_DESCR(out), indescr)) { + outgood = 1; + } + + /* + * Do we still not have a suitable output array? + * Create one, now + */ + if (!outgood) { + int oflags; + if (PyArray_ISFORTRAN(out)) + oflags = NPY_ARRAY_FARRAY; + else + oflags = NPY_ARRAY_CARRAY; + oflags |= NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_FORCECAST; + Py_INCREF(indescr); + newout = (PyArrayObject*)PyArray_FromArray(out, indescr, oflags); + if (newout == NULL) { + goto fail; + } + } + else { + newout = out; + Py_INCREF(newout); + } + + /* make sure the shape of the output array is the same */ + if (!PyArray_SAMESHAPE(newin, newout)) { + PyErr_SetString(PyExc_ValueError, "clip: Output array must have the" + "same shape as the input."); + goto fail; + } + + /* Now we can call the fast-clip function */ + min_data = max_data = NULL; + if (mina != NULL) { + min_data = PyArray_DATA(mina); + } + if (maxa != NULL) { + max_data = PyArray_DATA(maxa); + } + func(PyArray_DATA(newin), PyArray_SIZE(newin), min_data, max_data, PyArray_DATA(newout)); + + /* Clean up temporary variables */ + Py_XDECREF(indescr); + Py_XDECREF(newdescr); + Py_XDECREF(mina); + Py_XDECREF(maxa); + Py_DECREF(newin); + /* Copy back into out if out was not already a nice array. */ + PyArray_ResolveWritebackIfCopy(newout); + Py_DECREF(newout); + return (PyObject *)out; + + fail: + Py_XDECREF(indescr); + Py_XDECREF(newdescr); + Py_XDECREF(maxa); + Py_XDECREF(mina); + Py_XDECREF(newin); + PyArray_DiscardWritebackIfCopy(newout); + Py_XDECREF(newout); + return NULL; +} + + +/*NUMPY_API + * Conjugate + */ +NPY_NO_EXPORT PyObject * +PyArray_Conjugate(PyArrayObject *self, PyArrayObject *out) +{ + if (PyArray_ISCOMPLEX(self) || PyArray_ISOBJECT(self) || + PyArray_ISUSERDEF(self)) { + if (out == NULL) { + return PyArray_GenericUnaryFunction(self, + n_ops.conjugate); + } + else { + return PyArray_GenericBinaryFunction(self, + (PyObject *)out, + n_ops.conjugate); + } + } + else { + PyArrayObject *ret; + if (!PyArray_ISNUMBER(self)) { + /* 2017-05-04, 1.13 */ + if (DEPRECATE("attempting to conjugate non-numeric dtype; this " + "will error in the future to match the behavior of " + "np.conjugate") < 0) { + return NULL; + } + } + if (out) { + if (PyArray_AssignArray(out, self, + NULL, NPY_DEFAULT_ASSIGN_CASTING) < 0) { + return NULL; + } + ret = out; + } + else { + ret = self; + } + Py_INCREF(ret); + return (PyObject *)ret; + } +} + +/*NUMPY_API + * Trace + */ +NPY_NO_EXPORT PyObject * +PyArray_Trace(PyArrayObject *self, int offset, int axis1, int axis2, + int rtype, PyArrayObject *out) +{ + PyObject *diag = NULL, *ret = NULL; + + diag = PyArray_Diagonal(self, offset, axis1, axis2); + if (diag == NULL) { + return NULL; + } + ret = PyArray_GenericReduceFunction((PyArrayObject *)diag, n_ops.add, -1, rtype, out); + Py_DECREF(diag); + return ret; +} diff --git a/numpy/core/src/multiarray/calculation.h b/numpy/core/src/multiarray/calculation.h new file mode 100644 index 0000000..34bc31f --- /dev/null +++ b/numpy/core/src/multiarray/calculation.h @@ -0,0 +1,64 @@ +#ifndef _NPY_CALCULATION_H_ +#define _NPY_CALCULATION_H_ + +NPY_NO_EXPORT PyObject* +PyArray_ArgMax(PyArrayObject* self, int axis, PyArrayObject *out); + +NPY_NO_EXPORT PyObject* +PyArray_ArgMin(PyArrayObject* self, int axis, PyArrayObject *out); + +NPY_NO_EXPORT PyObject* +PyArray_Max(PyArrayObject* self, int axis, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_Min(PyArrayObject* self, int axis, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_Ptp(PyArrayObject* self, int axis, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_Mean(PyArrayObject* self, int axis, int rtype, PyArrayObject* out); + +NPY_NO_EXPORT PyObject * +PyArray_Round(PyArrayObject *a, int decimals, PyArrayObject *out); + +NPY_NO_EXPORT PyObject* +PyArray_Trace(PyArrayObject* self, int offset, int axis1, int axis2, + int rtype, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_Clip(PyArrayObject* self, PyObject* min, PyObject* max, PyArrayObject *out); + +NPY_NO_EXPORT PyObject* +PyArray_Conjugate(PyArrayObject* self, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_Round(PyArrayObject* self, int decimals, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_Std(PyArrayObject* self, int axis, int rtype, PyArrayObject* out, + int variance); + +NPY_NO_EXPORT PyObject * +__New_PyArray_Std(PyArrayObject *self, int axis, int rtype, PyArrayObject *out, + int variance, int num); + +NPY_NO_EXPORT PyObject* +PyArray_Sum(PyArrayObject* self, int axis, int rtype, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_CumSum(PyArrayObject* self, int axis, int rtype, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_Prod(PyArrayObject* self, int axis, int rtype, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_CumProd(PyArrayObject* self, int axis, int rtype, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_All(PyArrayObject* self, int axis, PyArrayObject* out); + +NPY_NO_EXPORT PyObject* +PyArray_Any(PyArrayObject* self, int axis, PyArrayObject* out); + +#endif diff --git a/numpy/core/src/multiarray/cblasfuncs.c b/numpy/core/src/multiarray/cblasfuncs.c new file mode 100644 index 0000000..c941bb2 --- /dev/null +++ b/numpy/core/src/multiarray/cblasfuncs.c @@ -0,0 +1,786 @@ +/* + * This module provides a BLAS optimized matrix multiply, + * inner product and dot for numpy arrays + */ + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE + +#include +#include +#include +#include "npy_cblas.h" +#include "arraytypes.h" +#include "common.h" +#include "mem_overlap.h" + + +/* + * Helper: call appropriate BLAS dot function for typenum. + * Strides are NumPy strides. + */ +static void +blas_dot(int typenum, npy_intp n, + void *a, npy_intp stridea, void *b, npy_intp strideb, void *res) +{ + switch (typenum) { + case NPY_DOUBLE: + DOUBLE_dot(a, stridea, b, strideb, res, n, NULL); + break; + case NPY_FLOAT: + FLOAT_dot(a, stridea, b, strideb, res, n, NULL); + break; + case NPY_CDOUBLE: + CDOUBLE_dot(a, stridea, b, strideb, res, n, NULL); + break; + case NPY_CFLOAT: + CFLOAT_dot(a, stridea, b, strideb, res, n, NULL); + break; + } +} + + +static const double oneD[2] = {1.0, 0.0}, zeroD[2] = {0.0, 0.0}; +static const float oneF[2] = {1.0, 0.0}, zeroF[2] = {0.0, 0.0}; + + +/* + * Helper: dispatch to appropriate cblas_?gemm for typenum. + */ +static void +gemm(int typenum, enum CBLAS_ORDER order, + enum CBLAS_TRANSPOSE transA, enum CBLAS_TRANSPOSE transB, + int m, int n, int k, + PyArrayObject *A, int lda, PyArrayObject *B, int ldb, PyArrayObject *R) +{ + const void *Adata = PyArray_DATA(A), *Bdata = PyArray_DATA(B); + void *Rdata = PyArray_DATA(R); + int ldc = PyArray_DIM(R, 1) > 1 ? PyArray_DIM(R, 1) : 1; + + switch (typenum) { + case NPY_DOUBLE: + cblas_dgemm(order, transA, transB, m, n, k, 1., + Adata, lda, Bdata, ldb, 0., Rdata, ldc); + break; + case NPY_FLOAT: + cblas_sgemm(order, transA, transB, m, n, k, 1.f, + Adata, lda, Bdata, ldb, 0.f, Rdata, ldc); + break; + case NPY_CDOUBLE: + cblas_zgemm(order, transA, transB, m, n, k, oneD, + Adata, lda, Bdata, ldb, zeroD, Rdata, ldc); + break; + case NPY_CFLOAT: + cblas_cgemm(order, transA, transB, m, n, k, oneF, + Adata, lda, Bdata, ldb, zeroF, Rdata, ldc); + break; + } +} + + +/* + * Helper: dispatch to appropriate cblas_?gemv for typenum. + */ +static void +gemv(int typenum, enum CBLAS_ORDER order, enum CBLAS_TRANSPOSE trans, + PyArrayObject *A, int lda, PyArrayObject *X, int incX, + PyArrayObject *R) +{ + const void *Adata = PyArray_DATA(A), *Xdata = PyArray_DATA(X); + void *Rdata = PyArray_DATA(R); + + int m = PyArray_DIM(A, 0), n = PyArray_DIM(A, 1); + + switch (typenum) { + case NPY_DOUBLE: + cblas_dgemv(order, trans, m, n, 1., Adata, lda, Xdata, incX, + 0., Rdata, 1); + break; + case NPY_FLOAT: + cblas_sgemv(order, trans, m, n, 1.f, Adata, lda, Xdata, incX, + 0.f, Rdata, 1); + break; + case NPY_CDOUBLE: + cblas_zgemv(order, trans, m, n, oneD, Adata, lda, Xdata, incX, + zeroD, Rdata, 1); + break; + case NPY_CFLOAT: + cblas_cgemv(order, trans, m, n, oneF, Adata, lda, Xdata, incX, + zeroF, Rdata, 1); + break; + } +} + + +/* + * Helper: dispatch to appropriate cblas_?syrk for typenum. + */ +static void +syrk(int typenum, enum CBLAS_ORDER order, enum CBLAS_TRANSPOSE trans, + int n, int k, + PyArrayObject *A, int lda, PyArrayObject *R) +{ + const void *Adata = PyArray_DATA(A); + void *Rdata = PyArray_DATA(R); + int ldc = PyArray_DIM(R, 1) > 1 ? PyArray_DIM(R, 1) : 1; + + npy_intp i; + npy_intp j; + + switch (typenum) { + case NPY_DOUBLE: + cblas_dsyrk(order, CblasUpper, trans, n, k, 1., + Adata, lda, 0., Rdata, ldc); + + for (i = 0; i < n; i++) { + for (j = i + 1; j < n; j++) { + *((npy_double*)PyArray_GETPTR2(R, j, i)) = + *((npy_double*)PyArray_GETPTR2(R, i, j)); + } + } + break; + case NPY_FLOAT: + cblas_ssyrk(order, CblasUpper, trans, n, k, 1.f, + Adata, lda, 0.f, Rdata, ldc); + + for (i = 0; i < n; i++) { + for (j = i + 1; j < n; j++) { + *((npy_float*)PyArray_GETPTR2(R, j, i)) = + *((npy_float*)PyArray_GETPTR2(R, i, j)); + } + } + break; + case NPY_CDOUBLE: + cblas_zsyrk(order, CblasUpper, trans, n, k, oneD, + Adata, lda, zeroD, Rdata, ldc); + + for (i = 0; i < n; i++) { + for (j = i + 1; j < n; j++) { + *((npy_cdouble*)PyArray_GETPTR2(R, j, i)) = + *((npy_cdouble*)PyArray_GETPTR2(R, i, j)); + } + } + break; + case NPY_CFLOAT: + cblas_csyrk(order, CblasUpper, trans, n, k, oneF, + Adata, lda, zeroF, Rdata, ldc); + + for (i = 0; i < n; i++) { + for (j = i + 1; j < n; j++) { + *((npy_cfloat*)PyArray_GETPTR2(R, j, i)) = + *((npy_cfloat*)PyArray_GETPTR2(R, i, j)); + } + } + break; + } +} + + +typedef enum {_scalar, _column, _row, _matrix} MatrixShape; + + +static MatrixShape +_select_matrix_shape(PyArrayObject *array) +{ + switch (PyArray_NDIM(array)) { + case 0: + return _scalar; + case 1: + if (PyArray_DIM(array, 0) > 1) + return _column; + return _scalar; + case 2: + if (PyArray_DIM(array, 0) > 1) { + if (PyArray_DIM(array, 1) == 1) + return _column; + else + return _matrix; + } + if (PyArray_DIM(array, 1) == 1) + return _scalar; + return _row; + } + return _matrix; +} + + +/* + * This also makes sure that the data segment is aligned with + * an itemsize address as well by returning one if not true. + */ +static int +_bad_strides(PyArrayObject *ap) +{ + int itemsize = PyArray_ITEMSIZE(ap); + int i, N=PyArray_NDIM(ap); + npy_intp *strides = PyArray_STRIDES(ap); + + if (((npy_intp)(PyArray_DATA(ap)) % itemsize) != 0) { + return 1; + } + for (i = 0; i < N; i++) { + if ((strides[i] < 0) || (strides[i] % itemsize) != 0) { + return 1; + } + } + + return 0; +} + +/* + * dot(a,b) + * Returns the dot product of a and b for arrays of floating point types. + * Like the generic numpy equivalent the product sum is over + * the last dimension of a and the second-to-last dimension of b. + * NB: The first argument is not conjugated.; + * + * This is for use by PyArray_MatrixProduct2. It is assumed on entry that + * the arrays ap1 and ap2 have a common data type given by typenum that is + * float, double, cfloat, or cdouble and have dimension <= 2. The + * __array_ufunc__ nonsense is also assumed to have been taken care of. + */ +NPY_NO_EXPORT PyObject * +cblas_matrixproduct(int typenum, PyArrayObject *ap1, PyArrayObject *ap2, + PyArrayObject *out) +{ + PyArrayObject *result = NULL, *out_buf = NULL; + int j, lda, ldb; + npy_intp l; + int nd; + npy_intp ap1stride = 0; + npy_intp dimensions[NPY_MAXDIMS]; + npy_intp numbytes; + MatrixShape ap1shape, ap2shape; + + if (_bad_strides(ap1)) { + PyObject *op1 = PyArray_NewCopy(ap1, NPY_ANYORDER); + + Py_DECREF(ap1); + ap1 = (PyArrayObject *)op1; + if (ap1 == NULL) { + goto fail; + } + } + if (_bad_strides(ap2)) { + PyObject *op2 = PyArray_NewCopy(ap2, NPY_ANYORDER); + + Py_DECREF(ap2); + ap2 = (PyArrayObject *)op2; + if (ap2 == NULL) { + goto fail; + } + } + ap1shape = _select_matrix_shape(ap1); + ap2shape = _select_matrix_shape(ap2); + + if (ap1shape == _scalar || ap2shape == _scalar) { + PyArrayObject *oap1, *oap2; + oap1 = ap1; oap2 = ap2; + /* One of ap1 or ap2 is a scalar */ + if (ap1shape == _scalar) { + /* Make ap2 the scalar */ + PyArrayObject *t = ap1; + ap1 = ap2; + ap2 = t; + ap1shape = ap2shape; + ap2shape = _scalar; + } + + if (ap1shape == _row) { + ap1stride = PyArray_STRIDE(ap1, 1); + } + else if (PyArray_NDIM(ap1) > 0) { + ap1stride = PyArray_STRIDE(ap1, 0); + } + + if (PyArray_NDIM(ap1) == 0 || PyArray_NDIM(ap2) == 0) { + npy_intp *thisdims; + if (PyArray_NDIM(ap1) == 0) { + nd = PyArray_NDIM(ap2); + thisdims = PyArray_DIMS(ap2); + } + else { + nd = PyArray_NDIM(ap1); + thisdims = PyArray_DIMS(ap1); + } + l = 1; + for (j = 0; j < nd; j++) { + dimensions[j] = thisdims[j]; + l *= dimensions[j]; + } + } + else { + l = PyArray_DIM(oap1, PyArray_NDIM(oap1) - 1); + + if (PyArray_DIM(oap2, 0) != l) { + dot_alignment_error(oap1, PyArray_NDIM(oap1) - 1, oap2, 0); + goto fail; + } + nd = PyArray_NDIM(ap1) + PyArray_NDIM(ap2) - 2; + /* + * nd = 0 or 1 or 2. If nd == 0 do nothing ... + */ + if (nd == 1) { + /* + * Either PyArray_NDIM(ap1) is 1 dim or PyArray_NDIM(ap2) is + * 1 dim and the other is 2 dim + */ + dimensions[0] = (PyArray_NDIM(oap1) == 2) ? + PyArray_DIM(oap1, 0) : PyArray_DIM(oap2, 1); + l = dimensions[0]; + /* + * Fix it so that dot(shape=(N,1), shape=(1,)) + * and dot(shape=(1,), shape=(1,N)) both return + * an (N,) array (but use the fast scalar code) + */ + } + else if (nd == 2) { + dimensions[0] = PyArray_DIM(oap1, 0); + dimensions[1] = PyArray_DIM(oap2, 1); + /* + * We need to make sure that dot(shape=(1,1), shape=(1,N)) + * and dot(shape=(N,1),shape=(1,1)) uses + * scalar multiplication appropriately + */ + if (ap1shape == _row) { + l = dimensions[1]; + } + else { + l = dimensions[0]; + } + } + + /* Check if the summation dimension is 0-sized */ + if (PyArray_DIM(oap1, PyArray_NDIM(oap1) - 1) == 0) { + l = 0; + } + } + } + else { + /* + * (PyArray_NDIM(ap1) <= 2 && PyArray_NDIM(ap2) <= 2) + * Both ap1 and ap2 are vectors or matrices + */ + l = PyArray_DIM(ap1, PyArray_NDIM(ap1) - 1); + + if (PyArray_DIM(ap2, 0) != l) { + dot_alignment_error(ap1, PyArray_NDIM(ap1) - 1, ap2, 0); + goto fail; + } + nd = PyArray_NDIM(ap1) + PyArray_NDIM(ap2) - 2; + + if (nd == 1) { + dimensions[0] = (PyArray_NDIM(ap1) == 2) ? + PyArray_DIM(ap1, 0) : PyArray_DIM(ap2, 1); + } + else if (nd == 2) { + dimensions[0] = PyArray_DIM(ap1, 0); + dimensions[1] = PyArray_DIM(ap2, 1); + } + } + + if (out != NULL) { + int d; + + /* verify that out is usable */ + if (PyArray_NDIM(out) != nd || + PyArray_TYPE(out) != typenum || + !PyArray_ISCARRAY(out)) { + + PyErr_SetString(PyExc_ValueError, + "output array is not acceptable (must have the right datatype, " + "number of dimensions, and be a C-Array)"); + goto fail; + } + for (d = 0; d < nd; ++d) { + if (dimensions[d] != PyArray_DIM(out, d)) { + PyErr_SetString(PyExc_ValueError, + "output array has wrong dimensions"); + goto fail; + } + } + + /* check for memory overlap */ + if (!(solve_may_share_memory(out, ap1, 1) == 0 && + solve_may_share_memory(out, ap2, 1) == 0)) { + /* allocate temporary output array */ + out_buf = (PyArrayObject *)PyArray_NewLikeArray(out, NPY_CORDER, + NULL, 0); + if (out_buf == NULL) { + goto fail; + } + + /* set copy-back */ + Py_INCREF(out); + if (PyArray_SetWritebackIfCopyBase(out_buf, out) < 0) { + Py_DECREF(out); + goto fail; + } + } + else { + Py_INCREF(out); + out_buf = out; + } + Py_INCREF(out); + result = out; + } + else { + double prior1, prior2; + PyTypeObject *subtype; + PyObject *tmp; + + /* Choose which subtype to return */ + if (Py_TYPE(ap1) != Py_TYPE(ap2)) { + prior2 = PyArray_GetPriority((PyObject *)ap2, 0.0); + prior1 = PyArray_GetPriority((PyObject *)ap1, 0.0); + subtype = (prior2 > prior1 ? Py_TYPE(ap2) : Py_TYPE(ap1)); + } + else { + prior1 = prior2 = 0.0; + subtype = Py_TYPE(ap1); + } + + tmp = (PyObject *)(prior2 > prior1 ? ap2 : ap1); + + out_buf = (PyArrayObject *)PyArray_New(subtype, nd, dimensions, + typenum, NULL, NULL, 0, 0, tmp); + if (out_buf == NULL) { + goto fail; + } + + Py_INCREF(out_buf); + result = out_buf; + } + + numbytes = PyArray_NBYTES(out_buf); + memset(PyArray_DATA(out_buf), 0, numbytes); + if (numbytes == 0 || l == 0) { + Py_DECREF(ap1); + Py_DECREF(ap2); + Py_DECREF(out_buf); + return PyArray_Return(result); + } + + if (ap2shape == _scalar) { + /* + * Multiplication by a scalar -- Level 1 BLAS + * if ap1shape is a matrix and we are not contiguous, then we can't + * just blast through the entire array using a single striding factor + */ + NPY_BEGIN_ALLOW_THREADS; + + if (typenum == NPY_DOUBLE) { + if (l == 1) { + *((double *)PyArray_DATA(out_buf)) = *((double *)PyArray_DATA(ap2)) * + *((double *)PyArray_DATA(ap1)); + } + else if (ap1shape != _matrix) { + cblas_daxpy(l, + *((double *)PyArray_DATA(ap2)), + (double *)PyArray_DATA(ap1), + ap1stride/sizeof(double), + (double *)PyArray_DATA(out_buf), 1); + } + else { + int maxind, oind, i, a1s, outs; + char *ptr, *optr; + double val; + + maxind = (PyArray_DIM(ap1, 0) >= PyArray_DIM(ap1, 1) ? 0 : 1); + oind = 1 - maxind; + ptr = PyArray_DATA(ap1); + optr = PyArray_DATA(out_buf); + l = PyArray_DIM(ap1, maxind); + val = *((double *)PyArray_DATA(ap2)); + a1s = PyArray_STRIDE(ap1, maxind) / sizeof(double); + outs = PyArray_STRIDE(out_buf, maxind) / sizeof(double); + for (i = 0; i < PyArray_DIM(ap1, oind); i++) { + cblas_daxpy(l, val, (double *)ptr, a1s, + (double *)optr, outs); + ptr += PyArray_STRIDE(ap1, oind); + optr += PyArray_STRIDE(out_buf, oind); + } + } + } + else if (typenum == NPY_CDOUBLE) { + if (l == 1) { + npy_cdouble *ptr1, *ptr2, *res; + + ptr1 = (npy_cdouble *)PyArray_DATA(ap2); + ptr2 = (npy_cdouble *)PyArray_DATA(ap1); + res = (npy_cdouble *)PyArray_DATA(out_buf); + res->real = ptr1->real * ptr2->real - ptr1->imag * ptr2->imag; + res->imag = ptr1->real * ptr2->imag + ptr1->imag * ptr2->real; + } + else if (ap1shape != _matrix) { + cblas_zaxpy(l, + (double *)PyArray_DATA(ap2), + (double *)PyArray_DATA(ap1), + ap1stride/sizeof(npy_cdouble), + (double *)PyArray_DATA(out_buf), 1); + } + else { + int maxind, oind, i, a1s, outs; + char *ptr, *optr; + double *pval; + + maxind = (PyArray_DIM(ap1, 0) >= PyArray_DIM(ap1, 1) ? 0 : 1); + oind = 1 - maxind; + ptr = PyArray_DATA(ap1); + optr = PyArray_DATA(out_buf); + l = PyArray_DIM(ap1, maxind); + pval = (double *)PyArray_DATA(ap2); + a1s = PyArray_STRIDE(ap1, maxind) / sizeof(npy_cdouble); + outs = PyArray_STRIDE(out_buf, maxind) / sizeof(npy_cdouble); + for (i = 0; i < PyArray_DIM(ap1, oind); i++) { + cblas_zaxpy(l, pval, (double *)ptr, a1s, + (double *)optr, outs); + ptr += PyArray_STRIDE(ap1, oind); + optr += PyArray_STRIDE(out_buf, oind); + } + } + } + else if (typenum == NPY_FLOAT) { + if (l == 1) { + *((float *)PyArray_DATA(out_buf)) = *((float *)PyArray_DATA(ap2)) * + *((float *)PyArray_DATA(ap1)); + } + else if (ap1shape != _matrix) { + cblas_saxpy(l, + *((float *)PyArray_DATA(ap2)), + (float *)PyArray_DATA(ap1), + ap1stride/sizeof(float), + (float *)PyArray_DATA(out_buf), 1); + } + else { + int maxind, oind, i, a1s, outs; + char *ptr, *optr; + float val; + + maxind = (PyArray_DIM(ap1, 0) >= PyArray_DIM(ap1, 1) ? 0 : 1); + oind = 1 - maxind; + ptr = PyArray_DATA(ap1); + optr = PyArray_DATA(out_buf); + l = PyArray_DIM(ap1, maxind); + val = *((float *)PyArray_DATA(ap2)); + a1s = PyArray_STRIDE(ap1, maxind) / sizeof(float); + outs = PyArray_STRIDE(out_buf, maxind) / sizeof(float); + for (i = 0; i < PyArray_DIM(ap1, oind); i++) { + cblas_saxpy(l, val, (float *)ptr, a1s, + (float *)optr, outs); + ptr += PyArray_STRIDE(ap1, oind); + optr += PyArray_STRIDE(out_buf, oind); + } + } + } + else if (typenum == NPY_CFLOAT) { + if (l == 1) { + npy_cfloat *ptr1, *ptr2, *res; + + ptr1 = (npy_cfloat *)PyArray_DATA(ap2); + ptr2 = (npy_cfloat *)PyArray_DATA(ap1); + res = (npy_cfloat *)PyArray_DATA(out_buf); + res->real = ptr1->real * ptr2->real - ptr1->imag * ptr2->imag; + res->imag = ptr1->real * ptr2->imag + ptr1->imag * ptr2->real; + } + else if (ap1shape != _matrix) { + cblas_caxpy(l, + (float *)PyArray_DATA(ap2), + (float *)PyArray_DATA(ap1), + ap1stride/sizeof(npy_cfloat), + (float *)PyArray_DATA(out_buf), 1); + } + else { + int maxind, oind, i, a1s, outs; + char *ptr, *optr; + float *pval; + + maxind = (PyArray_DIM(ap1, 0) >= PyArray_DIM(ap1, 1) ? 0 : 1); + oind = 1 - maxind; + ptr = PyArray_DATA(ap1); + optr = PyArray_DATA(out_buf); + l = PyArray_DIM(ap1, maxind); + pval = (float *)PyArray_DATA(ap2); + a1s = PyArray_STRIDE(ap1, maxind) / sizeof(npy_cfloat); + outs = PyArray_STRIDE(out_buf, maxind) / sizeof(npy_cfloat); + for (i = 0; i < PyArray_DIM(ap1, oind); i++) { + cblas_caxpy(l, pval, (float *)ptr, a1s, + (float *)optr, outs); + ptr += PyArray_STRIDE(ap1, oind); + optr += PyArray_STRIDE(out_buf, oind); + } + } + } + NPY_END_ALLOW_THREADS; + } + else if ((ap2shape == _column) && (ap1shape != _matrix)) { + NPY_BEGIN_ALLOW_THREADS; + + /* Dot product between two vectors -- Level 1 BLAS */ + blas_dot(typenum, l, + PyArray_DATA(ap1), PyArray_STRIDE(ap1, (ap1shape == _row)), + PyArray_DATA(ap2), PyArray_STRIDE(ap2, 0), + PyArray_DATA(out_buf)); + NPY_END_ALLOW_THREADS; + } + else if (ap1shape == _matrix && ap2shape != _matrix) { + /* Matrix vector multiplication -- Level 2 BLAS */ + /* lda must be MAX(M,1) */ + enum CBLAS_ORDER Order; + int ap2s; + + if (!PyArray_ISONESEGMENT(ap1)) { + PyObject *new; + new = PyArray_Copy(ap1); + Py_DECREF(ap1); + ap1 = (PyArrayObject *)new; + if (new == NULL) { + goto fail; + } + } + NPY_BEGIN_ALLOW_THREADS + if (PyArray_ISCONTIGUOUS(ap1)) { + Order = CblasRowMajor; + lda = (PyArray_DIM(ap1, 1) > 1 ? PyArray_DIM(ap1, 1) : 1); + } + else { + Order = CblasColMajor; + lda = (PyArray_DIM(ap1, 0) > 1 ? PyArray_DIM(ap1, 0) : 1); + } + ap2s = PyArray_STRIDE(ap2, 0) / PyArray_ITEMSIZE(ap2); + gemv(typenum, Order, CblasNoTrans, ap1, lda, ap2, ap2s, out_buf); + NPY_END_ALLOW_THREADS; + } + else if (ap1shape != _matrix && ap2shape == _matrix) { + /* Vector matrix multiplication -- Level 2 BLAS */ + enum CBLAS_ORDER Order; + int ap1s; + + if (!PyArray_ISONESEGMENT(ap2)) { + PyObject *new; + new = PyArray_Copy(ap2); + Py_DECREF(ap2); + ap2 = (PyArrayObject *)new; + if (new == NULL) { + goto fail; + } + } + NPY_BEGIN_ALLOW_THREADS + if (PyArray_ISCONTIGUOUS(ap2)) { + Order = CblasRowMajor; + lda = (PyArray_DIM(ap2, 1) > 1 ? PyArray_DIM(ap2, 1) : 1); + } + else { + Order = CblasColMajor; + lda = (PyArray_DIM(ap2, 0) > 1 ? PyArray_DIM(ap2, 0) : 1); + } + if (ap1shape == _row) { + ap1s = PyArray_STRIDE(ap1, 1) / PyArray_ITEMSIZE(ap1); + } + else { + ap1s = PyArray_STRIDE(ap1, 0) / PyArray_ITEMSIZE(ap1); + } + gemv(typenum, Order, CblasTrans, ap2, lda, ap1, ap1s, out_buf); + NPY_END_ALLOW_THREADS; + } + else { + /* + * (PyArray_NDIM(ap1) == 2 && PyArray_NDIM(ap2) == 2) + * Matrix matrix multiplication -- Level 3 BLAS + * L x M multiplied by M x N + */ + enum CBLAS_ORDER Order; + enum CBLAS_TRANSPOSE Trans1, Trans2; + int M, N, L; + + /* Optimization possible: */ + /* + * We may be able to handle single-segment arrays here + * using appropriate values of Order, Trans1, and Trans2. + */ + if (!PyArray_IS_C_CONTIGUOUS(ap2) && !PyArray_IS_F_CONTIGUOUS(ap2)) { + PyObject *new = PyArray_Copy(ap2); + + Py_DECREF(ap2); + ap2 = (PyArrayObject *)new; + if (new == NULL) { + goto fail; + } + } + if (!PyArray_IS_C_CONTIGUOUS(ap1) && !PyArray_IS_F_CONTIGUOUS(ap1)) { + PyObject *new = PyArray_Copy(ap1); + + Py_DECREF(ap1); + ap1 = (PyArrayObject *)new; + if (new == NULL) { + goto fail; + } + } + + NPY_BEGIN_ALLOW_THREADS; + + Order = CblasRowMajor; + Trans1 = CblasNoTrans; + Trans2 = CblasNoTrans; + L = PyArray_DIM(ap1, 0); + N = PyArray_DIM(ap2, 1); + M = PyArray_DIM(ap2, 0); + lda = (PyArray_DIM(ap1, 1) > 1 ? PyArray_DIM(ap1, 1) : 1); + ldb = (PyArray_DIM(ap2, 1) > 1 ? PyArray_DIM(ap2, 1) : 1); + + /* + * Avoid temporary copies for arrays in Fortran order + */ + if (PyArray_IS_F_CONTIGUOUS(ap1)) { + Trans1 = CblasTrans; + lda = (PyArray_DIM(ap1, 0) > 1 ? PyArray_DIM(ap1, 0) : 1); + } + if (PyArray_IS_F_CONTIGUOUS(ap2)) { + Trans2 = CblasTrans; + ldb = (PyArray_DIM(ap2, 0) > 1 ? PyArray_DIM(ap2, 0) : 1); + } + + /* + * Use syrk if we have a case of a matrix times its transpose. + * Otherwise, use gemm for all other cases. + */ + if ( + (PyArray_BYTES(ap1) == PyArray_BYTES(ap2)) && + (PyArray_DIM(ap1, 0) == PyArray_DIM(ap2, 1)) && + (PyArray_DIM(ap1, 1) == PyArray_DIM(ap2, 0)) && + (PyArray_STRIDE(ap1, 0) == PyArray_STRIDE(ap2, 1)) && + (PyArray_STRIDE(ap1, 1) == PyArray_STRIDE(ap2, 0)) && + ((Trans1 == CblasTrans) ^ (Trans2 == CblasTrans)) && + ((Trans1 == CblasNoTrans) ^ (Trans2 == CblasNoTrans)) + ) { + if (Trans1 == CblasNoTrans) { + syrk(typenum, Order, Trans1, N, M, ap1, lda, out_buf); + } + else { + syrk(typenum, Order, Trans1, N, M, ap2, ldb, out_buf); + } + } + else { + gemm(typenum, Order, Trans1, Trans2, L, N, M, ap1, lda, ap2, ldb, + out_buf); + } + NPY_END_ALLOW_THREADS; + } + + + Py_DECREF(ap1); + Py_DECREF(ap2); + + /* Trigger possible copyback into `result` */ + PyArray_ResolveWritebackIfCopy(out_buf); + Py_DECREF(out_buf); + + return PyArray_Return(result); + +fail: + Py_XDECREF(ap1); + Py_XDECREF(ap2); + Py_XDECREF(out_buf); + Py_XDECREF(result); + return NULL; +} diff --git a/numpy/core/src/multiarray/cblasfuncs.h b/numpy/core/src/multiarray/cblasfuncs.h new file mode 100644 index 0000000..66ce4ca --- /dev/null +++ b/numpy/core/src/multiarray/cblasfuncs.h @@ -0,0 +1,7 @@ +#ifndef _NPY_CBLASFUNCS_H_ +#define _NPY_CBLASFUNCS_H_ + +NPY_NO_EXPORT PyObject * +cblas_matrixproduct(int, PyArrayObject *, PyArrayObject *, PyArrayObject *); + +#endif diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c new file mode 100644 index 0000000..099cc03 --- /dev/null +++ b/numpy/core/src/multiarray/common.c @@ -0,0 +1,840 @@ +#define PY_SSIZE_T_CLEAN +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" + +#include "npy_config.h" +#include "npy_pycompat.h" +#include "common.h" + +#include "usertypes.h" + +#include "common.h" +#include "buffer.h" + +#include "get_attr_string.h" + +/* + * The casting to use for implicit assignment operations resulting from + * in-place operations (like +=) and out= arguments. (Notice that this + * variable is misnamed, but it's part of the public API so I'm not sure we + * can just change it. Maybe someone should try and see if anyone notices. + */ +/* + * In numpy 1.6 and earlier, this was NPY_UNSAFE_CASTING. In a future + * release, it will become NPY_SAME_KIND_CASTING. Right now, during the + * transitional period, we continue to follow the NPY_UNSAFE_CASTING rules (to + * avoid breaking people's code), but we also check for whether the cast would + * be allowed under the NPY_SAME_KIND_CASTING rules, and if not we issue a + * warning (that people's code will be broken in a future release.) + */ + +NPY_NO_EXPORT NPY_CASTING NPY_DEFAULT_ASSIGN_CASTING = NPY_SAME_KIND_CASTING; + + +NPY_NO_EXPORT PyArray_Descr * +_array_find_python_scalar_type(PyObject *op) +{ + if (PyFloat_Check(op)) { + return PyArray_DescrFromType(NPY_DOUBLE); + } + else if (PyComplex_Check(op)) { + return PyArray_DescrFromType(NPY_CDOUBLE); + } + else if (PyInt_Check(op)) { + /* bools are a subclass of int */ + if (PyBool_Check(op)) { + return PyArray_DescrFromType(NPY_BOOL); + } + else { + return PyArray_DescrFromType(NPY_LONG); + } + } + else if (PyLong_Check(op)) { + /* check to see if integer can fit into a longlong or ulonglong + and return that --- otherwise return object */ + if ((PyLong_AsLongLong(op) == -1) && PyErr_Occurred()) { + PyErr_Clear(); + } + else { + return PyArray_DescrFromType(NPY_LONGLONG); + } + + if ((PyLong_AsUnsignedLongLong(op) == (unsigned long long) -1) + && PyErr_Occurred()){ + PyErr_Clear(); + } + else { + return PyArray_DescrFromType(NPY_ULONGLONG); + } + + return PyArray_DescrFromType(NPY_OBJECT); + } + return NULL; +} + +/* + * These constants are used to signal that the recursive dtype determination in + * PyArray_DTypeFromObject encountered a string type, and that the recursive + * search must be restarted so that string representation lengths can be + * computed for all scalar types. + */ +#define RETRY_WITH_STRING 1 +#define RETRY_WITH_UNICODE 2 + +/* + * Recursively examines the object to determine an appropriate dtype + * to use for converting to an ndarray. + * + * 'obj' is the object to be converted to an ndarray. + * + * 'maxdims' is the maximum recursion depth. + * + * 'out_dtype' should be either NULL or a minimal starting dtype when + * the function is called. It is updated with the results of type + * promotion. This dtype does not get updated when processing NA objects. + * This is reset to NULL on failure. + * + * Returns 0 on success, -1 on failure. + */ + NPY_NO_EXPORT int +PyArray_DTypeFromObject(PyObject *obj, int maxdims, PyArray_Descr **out_dtype) +{ + int res; + + res = PyArray_DTypeFromObjectHelper(obj, maxdims, out_dtype, 0); + if (res == RETRY_WITH_STRING) { + res = PyArray_DTypeFromObjectHelper(obj, maxdims, + out_dtype, NPY_STRING); + if (res == RETRY_WITH_UNICODE) { + res = PyArray_DTypeFromObjectHelper(obj, maxdims, + out_dtype, NPY_UNICODE); + } + } + else if (res == RETRY_WITH_UNICODE) { + res = PyArray_DTypeFromObjectHelper(obj, maxdims, + out_dtype, NPY_UNICODE); + } + return res; +} + +NPY_NO_EXPORT int +PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, + PyArray_Descr **out_dtype, int string_type) +{ + int i, size; + PyArray_Descr *dtype = NULL; + PyObject *ip; + Py_buffer buffer_view; + /* types for sequence handling */ + PyObject ** objects; + PyObject * seq; + PyTypeObject * common_type; + + /* Check if it's an ndarray */ + if (PyArray_Check(obj)) { + dtype = PyArray_DESCR((PyArrayObject *)obj); + Py_INCREF(dtype); + goto promote_types; + } + + /* See if it's a python None */ + if (obj == Py_None) { + dtype = PyArray_DescrFromType(NPY_OBJECT); + if (dtype == NULL) { + goto fail; + } + Py_INCREF(dtype); + goto promote_types; + } + /* Check if it's a NumPy scalar */ + else if (PyArray_IsScalar(obj, Generic)) { + if (!string_type) { + dtype = PyArray_DescrFromScalar(obj); + if (dtype == NULL) { + goto fail; + } + } + else { + int itemsize; + PyObject *temp; + + if (string_type == NPY_STRING) { + if ((temp = PyObject_Str(obj)) == NULL) { + return -1; + } +#if defined(NPY_PY3K) + #if PY_VERSION_HEX >= 0x03030000 + itemsize = PyUnicode_GetLength(temp); + #else + itemsize = PyUnicode_GET_SIZE(temp); + #endif +#else + itemsize = PyString_GET_SIZE(temp); +#endif + } + else if (string_type == NPY_UNICODE) { +#if defined(NPY_PY3K) + if ((temp = PyObject_Str(obj)) == NULL) { +#else + if ((temp = PyObject_Unicode(obj)) == NULL) { +#endif + return -1; + } + itemsize = PyUnicode_GET_DATA_SIZE(temp); +#ifndef Py_UNICODE_WIDE + itemsize <<= 1; +#endif + } + else { + goto fail; + } + Py_DECREF(temp); + if (*out_dtype != NULL && + (*out_dtype)->type_num == string_type && + (*out_dtype)->elsize >= itemsize) { + return 0; + } + dtype = PyArray_DescrNewFromType(string_type); + if (dtype == NULL) { + goto fail; + } + dtype->elsize = itemsize; + } + goto promote_types; + } + + /* Check if it's a Python scalar */ + dtype = _array_find_python_scalar_type(obj); + if (dtype != NULL) { + if (string_type) { + int itemsize; + PyObject *temp; + + if (string_type == NPY_STRING) { + if ((temp = PyObject_Str(obj)) == NULL) { + return -1; + } +#if defined(NPY_PY3K) + #if PY_VERSION_HEX >= 0x03030000 + itemsize = PyUnicode_GetLength(temp); + #else + itemsize = PyUnicode_GET_SIZE(temp); + #endif +#else + itemsize = PyString_GET_SIZE(temp); +#endif + } + else if (string_type == NPY_UNICODE) { +#if defined(NPY_PY3K) + if ((temp = PyObject_Str(obj)) == NULL) { +#else + if ((temp = PyObject_Unicode(obj)) == NULL) { +#endif + return -1; + } + itemsize = PyUnicode_GET_DATA_SIZE(temp); +#ifndef Py_UNICODE_WIDE + itemsize <<= 1; +#endif + } + else { + goto fail; + } + Py_DECREF(temp); + if (*out_dtype != NULL && + (*out_dtype)->type_num == string_type && + (*out_dtype)->elsize >= itemsize) { + return 0; + } + dtype = PyArray_DescrNewFromType(string_type); + if (dtype == NULL) { + goto fail; + } + dtype->elsize = itemsize; + } + goto promote_types; + } + + /* Check if it's an ASCII string */ + if (PyBytes_Check(obj)) { + int itemsize = PyString_GET_SIZE(obj); + + /* If it's already a big enough string, don't bother type promoting */ + if (*out_dtype != NULL && + (*out_dtype)->type_num == NPY_STRING && + (*out_dtype)->elsize >= itemsize) { + return 0; + } + dtype = PyArray_DescrNewFromType(NPY_STRING); + if (dtype == NULL) { + goto fail; + } + dtype->elsize = itemsize; + goto promote_types; + } + + /* Check if it's a Unicode string */ + if (PyUnicode_Check(obj)) { + int itemsize = PyUnicode_GET_DATA_SIZE(obj); +#ifndef Py_UNICODE_WIDE + itemsize <<= 1; +#endif + + /* + * If it's already a big enough unicode object, + * don't bother type promoting + */ + if (*out_dtype != NULL && + (*out_dtype)->type_num == NPY_UNICODE && + (*out_dtype)->elsize >= itemsize) { + return 0; + } + dtype = PyArray_DescrNewFromType(NPY_UNICODE); + if (dtype == NULL) { + goto fail; + } + dtype->elsize = itemsize; + goto promote_types; + } + + /* PEP 3118 buffer interface */ + if (PyObject_CheckBuffer(obj) == 1) { + memset(&buffer_view, 0, sizeof(Py_buffer)); + if (PyObject_GetBuffer(obj, &buffer_view, + PyBUF_FORMAT|PyBUF_STRIDES) == 0 || + PyObject_GetBuffer(obj, &buffer_view, PyBUF_FORMAT) == 0) { + + PyErr_Clear(); + dtype = _descriptor_from_pep3118_format(buffer_view.format); + PyBuffer_Release(&buffer_view); + if (dtype) { + goto promote_types; + } + } + else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 || + PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) { + + PyErr_Clear(); + dtype = PyArray_DescrNewFromType(NPY_VOID); + dtype->elsize = buffer_view.itemsize; + PyBuffer_Release(&buffer_view); + goto promote_types; + } + else { + PyErr_Clear(); + } + } + + /* The array interface */ + ip = PyArray_LookupSpecial_OnInstance(obj, "__array_interface__"); + if (ip != NULL) { + if (PyDict_Check(ip)) { + PyObject *typestr; +#if defined(NPY_PY3K) + PyObject *tmp = NULL; +#endif + typestr = PyDict_GetItemString(ip, "typestr"); +#if defined(NPY_PY3K) + /* Allow unicode type strings */ + if (PyUnicode_Check(typestr)) { + tmp = PyUnicode_AsASCIIString(typestr); + typestr = tmp; + } +#endif + if (typestr && PyBytes_Check(typestr)) { + dtype =_array_typedescr_fromstr(PyBytes_AS_STRING(typestr)); +#if defined(NPY_PY3K) + if (tmp == typestr) { + Py_DECREF(tmp); + } +#endif + Py_DECREF(ip); + if (dtype == NULL) { + goto fail; + } + goto promote_types; + } + } + Py_DECREF(ip); + } + + /* The array struct interface */ + ip = PyArray_LookupSpecial_OnInstance(obj, "__array_struct__"); + if (ip != NULL) { + PyArrayInterface *inter; + char buf[40]; + + if (NpyCapsule_Check(ip)) { + inter = (PyArrayInterface *)NpyCapsule_AsVoidPtr(ip); + if (inter->two == 2) { + PyOS_snprintf(buf, sizeof(buf), + "|%c%d", inter->typekind, inter->itemsize); + dtype = _array_typedescr_fromstr(buf); + Py_DECREF(ip); + if (dtype == NULL) { + goto fail; + } + goto promote_types; + } + } + Py_DECREF(ip); + } + + /* The old buffer interface */ +#if !defined(NPY_PY3K) + if (PyBuffer_Check(obj)) { + dtype = PyArray_DescrNewFromType(NPY_VOID); + if (dtype == NULL) { + goto fail; + } + dtype->elsize = Py_TYPE(obj)->tp_as_sequence->sq_length(obj); + PyErr_Clear(); + goto promote_types; + } +#endif + + /* The __array__ attribute */ + ip = PyArray_LookupSpecial_OnInstance(obj, "__array__"); + if (ip != NULL) { + Py_DECREF(ip); + ip = PyObject_CallMethod(obj, "__array__", NULL); + if(ip && PyArray_Check(ip)) { + dtype = PyArray_DESCR((PyArrayObject *)ip); + Py_INCREF(dtype); + Py_DECREF(ip); + goto promote_types; + } + Py_XDECREF(ip); + if (PyErr_Occurred()) { + goto fail; + } + } + + /* + * If we reached the maximum recursion depth without hitting one + * of the above cases, and obj isn't a sequence-like object, the output + * dtype should be either OBJECT or a user-defined type. + * + * Note that some libraries define sequence-like classes but want them to + * be treated as objects, and they expect numpy to treat it as an object if + * __len__ is not defined. + */ + if (maxdims == 0 || !PySequence_Check(obj) || PySequence_Size(obj) < 0) { + // clear any PySequence_Size error, which corrupts further calls to it + PyErr_Clear(); + + if (*out_dtype == NULL || (*out_dtype)->type_num != NPY_OBJECT) { + Py_XDECREF(*out_dtype); + *out_dtype = PyArray_DescrFromType(NPY_OBJECT); + if (*out_dtype == NULL) { + return -1; + } + } + return 0; + } + + /* Recursive case, first check the sequence contains only one type */ + seq = PySequence_Fast(obj, "Could not convert object to sequence"); + if (seq == NULL) { + goto fail; + } + size = PySequence_Fast_GET_SIZE(seq); + objects = PySequence_Fast_ITEMS(seq); + common_type = size > 0 ? Py_TYPE(objects[0]) : NULL; + for (i = 1; i < size; ++i) { + if (Py_TYPE(objects[i]) != common_type) { + common_type = NULL; + break; + } + } + + /* all types are the same and scalar, one recursive call is enough */ + if (common_type != NULL && !string_type && + (common_type == &PyFloat_Type || +/* TODO: we could add longs if we add a range check */ +#if !defined(NPY_PY3K) + common_type == &PyInt_Type || +#endif + common_type == &PyBool_Type || + common_type == &PyComplex_Type)) { + size = 1; + } + + /* Recursive call for each sequence item */ + for (i = 0; i < size; ++i) { + int res = PyArray_DTypeFromObjectHelper(objects[i], maxdims - 1, + out_dtype, string_type); + if (res < 0) { + Py_DECREF(seq); + goto fail; + } + else if (res > 0) { + Py_DECREF(seq); + return res; + } + } + + Py_DECREF(seq); + + return 0; + + +promote_types: + /* Set 'out_dtype' if it's NULL */ + if (*out_dtype == NULL) { + if (!string_type && dtype->type_num == NPY_STRING) { + Py_DECREF(dtype); + return RETRY_WITH_STRING; + } + if (!string_type && dtype->type_num == NPY_UNICODE) { + Py_DECREF(dtype); + return RETRY_WITH_UNICODE; + } + *out_dtype = dtype; + return 0; + } + /* Do type promotion with 'out_dtype' */ + else { + PyArray_Descr *res_dtype = PyArray_PromoteTypes(dtype, *out_dtype); + Py_DECREF(dtype); + if (res_dtype == NULL) { + return -1; + } + if (!string_type && + res_dtype->type_num == NPY_UNICODE && + (*out_dtype)->type_num != NPY_UNICODE) { + Py_DECREF(res_dtype); + return RETRY_WITH_UNICODE; + } + if (!string_type && + res_dtype->type_num == NPY_STRING && + (*out_dtype)->type_num != NPY_STRING) { + Py_DECREF(res_dtype); + return RETRY_WITH_STRING; + } + Py_DECREF(*out_dtype); + *out_dtype = res_dtype; + return 0; + } + +fail: + Py_XDECREF(*out_dtype); + *out_dtype = NULL; + return -1; +} + +#undef RETRY_WITH_STRING +#undef RETRY_WITH_UNICODE + +/* new reference */ +NPY_NO_EXPORT PyArray_Descr * +_array_typedescr_fromstr(char *c_str) +{ + PyArray_Descr *descr = NULL; + PyObject *stringobj = PyString_FromString(c_str); + + if (stringobj == NULL) { + return NULL; + } + if (PyArray_DescrConverter(stringobj, &descr) != NPY_SUCCEED) { + Py_DECREF(stringobj); + return NULL; + } + Py_DECREF(stringobj); + return descr; +} + + +NPY_NO_EXPORT char * +index2ptr(PyArrayObject *mp, npy_intp i) +{ + npy_intp dim0; + + if (PyArray_NDIM(mp) == 0) { + PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed"); + return NULL; + } + dim0 = PyArray_DIMS(mp)[0]; + if (check_and_adjust_index(&i, dim0, 0, NULL) < 0) + return NULL; + if (i == 0) { + return PyArray_DATA(mp); + } + return PyArray_BYTES(mp)+i*PyArray_STRIDES(mp)[0]; +} + +NPY_NO_EXPORT int +_zerofill(PyArrayObject *ret) +{ + if (PyDataType_REFCHK(PyArray_DESCR(ret))) { + PyObject *zero = PyInt_FromLong(0); + PyArray_FillObjectArray(ret, zero); + Py_DECREF(zero); + if (PyErr_Occurred()) { + Py_DECREF(ret); + return -1; + } + } + else { + npy_intp n = PyArray_NBYTES(ret); + memset(PyArray_DATA(ret), 0, n); + } + return 0; +} + +NPY_NO_EXPORT int +_IsAligned(PyArrayObject *ap) +{ + unsigned int i; + npy_uintp aligned; + npy_uintp alignment = PyArray_DESCR(ap)->alignment; + + /* alignment 1 types should have a efficient alignment for copy loops */ + if (PyArray_ISFLEXIBLE(ap) || PyArray_ISSTRING(ap)) { + npy_intp itemsize = PyArray_ITEMSIZE(ap); + /* power of two sizes may be loaded in larger moves */ + if (((itemsize & (itemsize - 1)) == 0)) { + alignment = itemsize > NPY_MAX_COPY_ALIGNMENT ? + NPY_MAX_COPY_ALIGNMENT : itemsize; + } + else { + /* if not power of two it will be accessed bytewise */ + alignment = 1; + } + } + + if (alignment == 1) { + return 1; + } + aligned = (npy_uintp)PyArray_DATA(ap); + + for (i = 0; i < PyArray_NDIM(ap); i++) { +#if NPY_RELAXED_STRIDES_CHECKING + /* skip dim == 1 as it is not required to have stride 0 */ + if (PyArray_DIM(ap, i) > 1) { + /* if shape[i] == 1, the stride is never used */ + aligned |= (npy_uintp)PyArray_STRIDES(ap)[i]; + } + else if (PyArray_DIM(ap, i) == 0) { + /* an array with zero elements is always aligned */ + return 1; + } +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + aligned |= (npy_uintp)PyArray_STRIDES(ap)[i]; +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ + } + return npy_is_aligned((void *)aligned, alignment); +} + +NPY_NO_EXPORT npy_bool +_IsWriteable(PyArrayObject *ap) +{ + PyObject *base=PyArray_BASE(ap); + void *dummy; + Py_ssize_t n; + + /* If we own our own data, then no-problem */ + if ((base == NULL) || (PyArray_FLAGS(ap) & NPY_ARRAY_OWNDATA)) { + return NPY_TRUE; + } + /* + * Get to the final base object + * If it is a writeable array, then return TRUE + * If we can find an array object + * or a writeable buffer object as the final base object + * or a string object (for pickling support memory savings). + * - this last could be removed if a proper pickleable + * buffer was added to Python. + * + * MW: I think it would better to disallow switching from READONLY + * to WRITEABLE like this... + */ + + while(PyArray_Check(base)) { + if (PyArray_CHKFLAGS((PyArrayObject *)base, NPY_ARRAY_OWNDATA)) { + return (npy_bool) (PyArray_ISWRITEABLE((PyArrayObject *)base)); + } + base = PyArray_BASE((PyArrayObject *)base); + } + + /* + * here so pickle support works seamlessly + * and unpickled array can be set and reset writeable + * -- could be abused -- + */ + if (PyString_Check(base)) { + return NPY_TRUE; + } + if (PyObject_AsWriteBuffer(base, &dummy, &n) < 0) { + return NPY_FALSE; + } + return NPY_TRUE; +} + + +/** + * Convert an array shape to a string such as "(1, 2)". + * + * @param Dimensionality of the shape + * @param npy_intp pointer to shape array + * @param String to append after the shape `(1, 2)%s`. + * + * @return Python unicode string + */ +NPY_NO_EXPORT PyObject * +convert_shape_to_string(npy_intp n, npy_intp *vals, char *ending) +{ + npy_intp i; + PyObject *ret, *tmp; + + /* + * Negative dimension indicates "newaxis", which can + * be discarded for printing if it's a leading dimension. + * Find the first non-"newaxis" dimension. + */ + for (i = 0; i < n && vals[i] < 0; i++); + + if (i == n) { + return PyUString_FromFormat("()%s", ending); + } + else { + ret = PyUString_FromFormat("(%" NPY_INTP_FMT, vals[i++]); + if (ret == NULL) { + return NULL; + } + } + + for (; i < n; ++i) { + if (vals[i] < 0) { + tmp = PyUString_FromString(",newaxis"); + } + else { + tmp = PyUString_FromFormat(",%" NPY_INTP_FMT, vals[i]); + } + if (tmp == NULL) { + Py_DECREF(ret); + return NULL; + } + + PyUString_ConcatAndDel(&ret, tmp); + if (ret == NULL) { + return NULL; + } + } + + if (i == 1) { + tmp = PyUString_FromFormat(",)%s", ending); + } + else { + tmp = PyUString_FromFormat(")%s", ending); + } + PyUString_ConcatAndDel(&ret, tmp); + return ret; +} + + +NPY_NO_EXPORT void +dot_alignment_error(PyArrayObject *a, int i, PyArrayObject *b, int j) +{ + PyObject *errmsg = NULL, *format = NULL, *fmt_args = NULL, + *i_obj = NULL, *j_obj = NULL, + *shape1 = NULL, *shape2 = NULL, + *shape1_i = NULL, *shape2_j = NULL; + + format = PyUString_FromString("shapes %s and %s not aligned:" + " %d (dim %d) != %d (dim %d)"); + + shape1 = convert_shape_to_string(PyArray_NDIM(a), PyArray_DIMS(a), ""); + shape2 = convert_shape_to_string(PyArray_NDIM(b), PyArray_DIMS(b), ""); + + i_obj = PyLong_FromLong(i); + j_obj = PyLong_FromLong(j); + + shape1_i = PyLong_FromSsize_t(PyArray_DIM(a, i)); + shape2_j = PyLong_FromSsize_t(PyArray_DIM(b, j)); + + if (!format || !shape1 || !shape2 || !i_obj || !j_obj || + !shape1_i || !shape2_j) { + goto end; + } + + fmt_args = PyTuple_Pack(6, shape1, shape2, + shape1_i, i_obj, shape2_j, j_obj); + if (fmt_args == NULL) { + goto end; + } + + errmsg = PyUString_Format(format, fmt_args); + if (errmsg != NULL) { + PyErr_SetObject(PyExc_ValueError, errmsg); + } + else { + PyErr_SetString(PyExc_ValueError, "shapes are not aligned"); + } + +end: + Py_XDECREF(errmsg); + Py_XDECREF(fmt_args); + Py_XDECREF(format); + Py_XDECREF(i_obj); + Py_XDECREF(j_obj); + Py_XDECREF(shape1); + Py_XDECREF(shape2); + Py_XDECREF(shape1_i); + Py_XDECREF(shape2_j); +} + +/** + * unpack tuple of dtype->fields (descr, offset, title[not-needed]) + * + * @param "value" should be the tuple. + * + * @return "descr" will be set to the field's dtype + * @return "offset" will be set to the field's offset + * + * returns -1 on failure, 0 on success. + */ +NPY_NO_EXPORT int +_unpack_field(PyObject *value, PyArray_Descr **descr, npy_intp *offset) +{ + PyObject * off; + if (PyTuple_GET_SIZE(value) < 2) { + return -1; + } + *descr = (PyArray_Descr *)PyTuple_GET_ITEM(value, 0); + off = PyTuple_GET_ITEM(value, 1); + + if (PyInt_Check(off)) { + *offset = PyInt_AsSsize_t(off); + } + else if (PyLong_Check(off)) { + *offset = PyLong_AsSsize_t(off); + } + else { + PyErr_SetString(PyExc_IndexError, "can't convert offset"); + return -1; + } + + return 0; +} + +/* + * check whether arrays with datatype dtype might have object fields. This will + * only happen for structured dtypes (which may have hidden objects even if the + * HASOBJECT flag is false), object dtypes, or subarray dtypes whose base type + * is either of these. + */ +NPY_NO_EXPORT int +_may_have_objects(PyArray_Descr *dtype) +{ + PyArray_Descr *base = dtype; + if (PyDataType_HASSUBARRAY(dtype)) { + base = dtype->subarray->base; + } + + return (PyDataType_HASFIELDS(base) || + PyDataType_FLAGCHK(base, NPY_ITEM_HASOBJECT) ); +} diff --git a/numpy/core/src/multiarray/common.h b/numpy/core/src/multiarray/common.h new file mode 100644 index 0000000..ae9b960 --- /dev/null +++ b/numpy/core/src/multiarray/common.h @@ -0,0 +1,286 @@ +#ifndef _NPY_PRIVATE_COMMON_H_ +#define _NPY_PRIVATE_COMMON_H_ +#include +#include +#include +#include + +#define error_converting(x) (((x) == -1) && PyErr_Occurred()) + +#ifdef NPY_ALLOW_THREADS +#define NPY_BEGIN_THREADS_NDITER(iter) \ + do { \ + if (!NpyIter_IterationNeedsAPI(iter)) { \ + NPY_BEGIN_THREADS_THRESHOLDED(NpyIter_GetIterSize(iter)); \ + } \ + } while(0) +#else +#define NPY_BEGIN_THREADS_NDITER(iter) +#endif + +/* + * Recursively examines the object to determine an appropriate dtype + * to use for converting to an ndarray. + * + * 'obj' is the object to be converted to an ndarray. + * + * 'maxdims' is the maximum recursion depth. + * + * 'out_dtype' should be either NULL or a minimal starting dtype when + * the function is called. It is updated with the results of type + * promotion. This dtype does not get updated when processing NA objects. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_DTypeFromObject(PyObject *obj, int maxdims, + PyArray_Descr **out_dtype); + +NPY_NO_EXPORT int +PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, + PyArray_Descr **out_dtype, int string_status); + +/* + * Returns NULL without setting an exception if no scalar is matched, a + * new dtype reference otherwise. + */ +NPY_NO_EXPORT PyArray_Descr * +_array_find_python_scalar_type(PyObject *op); + +NPY_NO_EXPORT PyArray_Descr * +_array_typedescr_fromstr(char *str); + +NPY_NO_EXPORT char * +index2ptr(PyArrayObject *mp, npy_intp i); + +NPY_NO_EXPORT int +_zerofill(PyArrayObject *ret); + +NPY_NO_EXPORT int +_IsAligned(PyArrayObject *ap); + +NPY_NO_EXPORT npy_bool +_IsWriteable(PyArrayObject *ap); + +NPY_NO_EXPORT PyObject * +convert_shape_to_string(npy_intp n, npy_intp *vals, char *ending); + +/* + * Sets ValueError with "matrices not aligned" message for np.dot and friends + * when a.shape[i] should match b.shape[j], but doesn't. + */ +NPY_NO_EXPORT void +dot_alignment_error(PyArrayObject *a, int i, PyArrayObject *b, int j); + +/** + * unpack tuple of dtype->fields (descr, offset, title[not-needed]) + * + * @param "value" should be the tuple. + * + * @return "descr" will be set to the field's dtype + * @return "offset" will be set to the field's offset + * + * returns -1 on failure, 0 on success. + */ +NPY_NO_EXPORT int +_unpack_field(PyObject *value, PyArray_Descr **descr, npy_intp *offset); + +/* + * check whether arrays with datatype dtype might have object fields. This will + * only happen for structured dtypes (which may have hidden objects even if the + * HASOBJECT flag is false), object dtypes, or subarray dtypes whose base type + * is either of these. + */ +NPY_NO_EXPORT int +_may_have_objects(PyArray_Descr *dtype); + +/* + * Returns -1 and sets an exception if *index is an invalid index for + * an array of size max_item, otherwise adjusts it in place to be + * 0 <= *index < max_item, and returns 0. + * 'axis' should be the array axis that is being indexed over, if known. If + * unknown, use -1. + * If _save is NULL it is assumed the GIL is taken + * If _save is not NULL it is assumed the GIL is not taken and it + * is acquired in the case of an error + */ +static NPY_INLINE int +check_and_adjust_index(npy_intp *index, npy_intp max_item, int axis, + PyThreadState * _save) +{ + /* Check that index is valid, taking into account negative indices */ + if (NPY_UNLIKELY((*index < -max_item) || (*index >= max_item))) { + NPY_END_THREADS; + /* Try to be as clear as possible about what went wrong. */ + if (axis >= 0) { + PyErr_Format(PyExc_IndexError, + "index %"NPY_INTP_FMT" is out of bounds " + "for axis %d with size %"NPY_INTP_FMT, + *index, axis, max_item); + } else { + PyErr_Format(PyExc_IndexError, + "index %"NPY_INTP_FMT" is out of bounds " + "for size %"NPY_INTP_FMT, *index, max_item); + } + return -1; + } + /* adjust negative indices */ + if (*index < 0) { + *index += max_item; + } + return 0; +} + +/* + * Returns -1 and sets an exception if *axis is an invalid axis for + * an array of dimension ndim, otherwise adjusts it in place to be + * 0 <= *axis < ndim, and returns 0. + * + * msg_prefix: borrowed reference, a string to prepend to the message + */ +static NPY_INLINE int +check_and_adjust_axis_msg(int *axis, int ndim, PyObject *msg_prefix) +{ + /* Check that index is valid, taking into account negative indices */ + if (NPY_UNLIKELY((*axis < -ndim) || (*axis >= ndim))) { + /* + * Load the exception type, if we don't already have it. Unfortunately + * we don't have access to npy_cache_import here + */ + static PyObject *AxisError_cls = NULL; + PyObject *exc; + + if (AxisError_cls == NULL) { + PyObject *mod = PyImport_ImportModule("numpy.core._internal"); + + if (mod != NULL) { + AxisError_cls = PyObject_GetAttrString(mod, "AxisError"); + Py_DECREF(mod); + } + } + + /* Invoke the AxisError constructor */ + exc = PyObject_CallFunction(AxisError_cls, "iiO", + *axis, ndim, msg_prefix); + if (exc == NULL) { + return -1; + } + PyErr_SetObject(AxisError_cls, exc); + Py_DECREF(exc); + + return -1; + } + /* adjust negative indices */ + if (*axis < 0) { + *axis += ndim; + } + return 0; +} +static NPY_INLINE int +check_and_adjust_axis(int *axis, int ndim) +{ + return check_and_adjust_axis_msg(axis, ndim, Py_None); +} + + +/* + * return true if pointer is aligned to 'alignment' + */ +static NPY_INLINE int +npy_is_aligned(const void * p, const npy_uintp alignment) +{ + /* + * alignment is usually a power of two + * the test is faster than a direct modulo + */ + if (NPY_LIKELY((alignment & (alignment - 1)) == 0)) { + return ((npy_uintp)(p) & ((alignment) - 1)) == 0; + } + else { + return ((npy_uintp)(p) % alignment) == 0; + } +} + +/* + * memchr with stride and invert argument + * intended for small searches where a call out to libc memchr is costly. + * stride must be a multiple of size. + * compared to memchr it returns one stride past end instead of NULL if needle + * is not found. + */ +static NPY_INLINE char * +npy_memchr(char * haystack, char needle, + npy_intp stride, npy_intp size, npy_intp * psubloopsize, int invert) +{ + char * p = haystack; + npy_intp subloopsize = 0; + + if (!invert) { + /* + * this is usually the path to determine elements to process, + * performance less important here. + * memchr has large setup cost if 0 byte is close to start. + */ + while (subloopsize < size && *p != needle) { + subloopsize++; + p += stride; + } + } + else { + /* usually find elements to skip path */ + if (NPY_CPU_HAVE_UNALIGNED_ACCESS && needle == 0 && stride == 1) { + /* iterate until last multiple of 4 */ + char * block_end = haystack + size - (size % sizeof(unsigned int)); + while (p < block_end) { + unsigned int v = *(unsigned int*)p; + if (v != 0) { + break; + } + p += sizeof(unsigned int); + } + /* handle rest */ + subloopsize = (p - haystack); + } + while (subloopsize < size && *p == needle) { + subloopsize++; + p += stride; + } + } + + *psubloopsize = subloopsize; + + return p; +} + +/* + * Convert NumPy stride to BLAS stride. Returns 0 if conversion cannot be done + * (BLAS won't handle negative or zero strides the way we want). + */ +static NPY_INLINE int +blas_stride(npy_intp stride, unsigned itemsize) +{ + /* + * Should probably check pointer alignment also, but this may cause + * problems if we require complex to be 16 byte aligned. + */ + if (stride > 0 && npy_is_aligned((void *)stride, itemsize)) { + stride /= itemsize; + if (stride <= INT_MAX) { + return stride; + } + } + return 0; +} + +/* + * Define a chunksize for CBLAS. CBLAS counts in integers. + */ +#if NPY_MAX_INTP > INT_MAX +# define NPY_CBLAS_CHUNK (INT_MAX / 2 + 1) +#else +# define NPY_CBLAS_CHUNK NPY_MAX_INTP +#endif + +#include "ucsnarrow.h" + +#endif diff --git a/numpy/core/src/multiarray/compiled_base.c b/numpy/core/src/multiarray/compiled_base.c new file mode 100644 index 0000000..951c4d3 --- /dev/null +++ b/numpy/core/src/multiarray/compiled_base.c @@ -0,0 +1,1854 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#include +#include +#include + +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/npy_3kcompat.h" +#include "numpy/npy_math.h" +#include "npy_config.h" +#include "templ_common.h" /* for npy_mul_with_overflow_intp */ +#include "lowlevel_strided_loops.h" /* for npy_bswap8 */ +#include "alloc.h" +#include "common.h" + + +/* + * Returns -1 if the array is monotonic decreasing, + * +1 if the array is monotonic increasing, + * and 0 if the array is not monotonic. + */ +static int +check_array_monotonic(const double *a, npy_int lena) +{ + npy_intp i; + double next; + double last = a[0]; + + /* Skip repeated values at the beginning of the array */ + for (i = 1; (i < lena) && (a[i] == last); i++); + + if (i == lena) { + /* all bin edges hold the same value */ + return 1; + } + + next = a[i]; + if (last < next) { + /* Possibly monotonic increasing */ + for (i += 1; i < lena; i++) { + last = next; + next = a[i]; + if (last > next) { + return 0; + } + } + return 1; + } + else { + /* last > next, possibly monotonic decreasing */ + for (i += 1; i < lena; i++) { + last = next; + next = a[i]; + if (last < next) { + return 0; + } + } + return -1; + } +} + +/* Find the minimum and maximum of an integer array */ +static void +minmax(const npy_intp *data, npy_intp data_len, npy_intp *mn, npy_intp *mx) +{ + npy_intp min = *data; + npy_intp max = *data; + + while (--data_len) { + const npy_intp val = *(++data); + if (val < min) { + min = val; + } + else if (val > max) { + max = val; + } + } + + *mn = min; + *mx = max; +} + +/* + * arr_bincount is registered as bincount. + * + * bincount accepts one, two or three arguments. The first is an array of + * non-negative integers The second, if present, is an array of weights, + * which must be promotable to double. Call these arguments list and + * weight. Both must be one-dimensional with len(weight) == len(list). If + * weight is not present then bincount(list)[i] is the number of occurrences + * of i in list. If weight is present then bincount(self,list, weight)[i] + * is the sum of all weight[j] where list [j] == i. Self is not used. + * The third argument, if present, is a minimum length desired for the + * output array. + */ +NPY_NO_EXPORT PyObject * +arr_bincount(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds) +{ + PyObject *list = NULL, *weight = Py_None, *mlength = NULL; + PyArrayObject *lst = NULL, *ans = NULL, *wts = NULL; + npy_intp *numbers, *ians, len, mx, mn, ans_size; + npy_intp minlength = 0; + npy_intp i; + double *weights , *dans; + static char *kwlist[] = {"list", "weights", "minlength", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:bincount", + kwlist, &list, &weight, &mlength)) { + goto fail; + } + + lst = (PyArrayObject *)PyArray_ContiguousFromAny(list, NPY_INTP, 1, 1); + if (lst == NULL) { + goto fail; + } + len = PyArray_SIZE(lst); + + /* + * This if/else if can be removed by changing the argspec to O|On above, + * once we retire the deprecation + */ + if (mlength == Py_None) { + /* NumPy 1.14, 2017-06-01 */ + if (DEPRECATE("0 should be passed as minlength instead of None; " + "this will error in future.") < 0) { + goto fail; + } + } + else if (mlength != NULL) { + minlength = PyArray_PyIntAsIntp(mlength); + if (error_converting(minlength)) { + goto fail; + } + } + + if (minlength < 0) { + PyErr_SetString(PyExc_ValueError, + "'minlength' must not be negative"); + goto fail; + } + + /* handle empty list */ + if (len == 0) { + ans = (PyArrayObject *)PyArray_ZEROS(1, &minlength, NPY_INTP, 0); + if (ans == NULL){ + goto fail; + } + Py_DECREF(lst); + return (PyObject *)ans; + } + + numbers = (npy_intp *)PyArray_DATA(lst); + minmax(numbers, len, &mn, &mx); + if (mn < 0) { + PyErr_SetString(PyExc_ValueError, + "'list' argument must have no negative elements"); + goto fail; + } + ans_size = mx + 1; + if (mlength != Py_None) { + if (ans_size < minlength) { + ans_size = minlength; + } + } + if (weight == Py_None) { + ans = (PyArrayObject *)PyArray_ZEROS(1, &ans_size, NPY_INTP, 0); + if (ans == NULL) { + goto fail; + } + ians = (npy_intp *)PyArray_DATA(ans); + NPY_BEGIN_ALLOW_THREADS; + for (i = 0; i < len; i++) + ians[numbers[i]] += 1; + NPY_END_ALLOW_THREADS; + Py_DECREF(lst); + } + else { + wts = (PyArrayObject *)PyArray_ContiguousFromAny( + weight, NPY_DOUBLE, 1, 1); + if (wts == NULL) { + goto fail; + } + weights = (double *)PyArray_DATA(wts); + if (PyArray_SIZE(wts) != len) { + PyErr_SetString(PyExc_ValueError, + "The weights and list don't have the same length."); + goto fail; + } + ans = (PyArrayObject *)PyArray_ZEROS(1, &ans_size, NPY_DOUBLE, 0); + if (ans == NULL) { + goto fail; + } + dans = (double *)PyArray_DATA(ans); + NPY_BEGIN_ALLOW_THREADS; + for (i = 0; i < len; i++) { + dans[numbers[i]] += weights[i]; + } + NPY_END_ALLOW_THREADS; + Py_DECREF(lst); + Py_DECREF(wts); + } + return (PyObject *)ans; + +fail: + Py_XDECREF(lst); + Py_XDECREF(wts); + Py_XDECREF(ans); + return NULL; +} + +/* + * digitize(x, bins, right=False) returns an array of integers the same length + * as x. The values i returned are such that bins[i - 1] <= x < bins[i] if + * bins is monotonically increasing, or bins[i - 1] > x >= bins[i] if bins + * is monotonically decreasing. Beyond the bounds of bins, returns either + * i = 0 or i = len(bins) as appropriate. If right == True the comparison + * is bins [i - 1] < x <= bins[i] or bins [i - 1] >= x > bins[i] + */ +NPY_NO_EXPORT PyObject * +arr_digitize(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds) +{ + PyObject *obj_x = NULL; + PyObject *obj_bins = NULL; + PyArrayObject *arr_x = NULL; + PyArrayObject *arr_bins = NULL; + PyObject *ret = NULL; + npy_intp len_bins; + int monotonic, right = 0; + NPY_BEGIN_THREADS_DEF + + static char *kwlist[] = {"x", "bins", "right", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|i:digitize", kwlist, + &obj_x, &obj_bins, &right)) { + goto fail; + } + + /* PyArray_SearchSorted will make `x` contiguous even if we don't */ + arr_x = (PyArrayObject *)PyArray_FROMANY(obj_x, NPY_DOUBLE, 0, 0, + NPY_ARRAY_CARRAY_RO); + if (arr_x == NULL) { + goto fail; + } + + /* TODO: `bins` could be strided, needs change to check_array_monotonic */ + arr_bins = (PyArrayObject *)PyArray_FROMANY(obj_bins, NPY_DOUBLE, 1, 1, + NPY_ARRAY_CARRAY_RO); + if (arr_bins == NULL) { + goto fail; + } + + len_bins = PyArray_SIZE(arr_bins); + if (len_bins == 0) { + PyErr_SetString(PyExc_ValueError, "bins must have non-zero length"); + goto fail; + } + + NPY_BEGIN_THREADS_THRESHOLDED(len_bins) + monotonic = check_array_monotonic((const double *)PyArray_DATA(arr_bins), + len_bins); + NPY_END_THREADS + + if (monotonic == 0) { + PyErr_SetString(PyExc_ValueError, + "bins must be monotonically increasing or decreasing"); + goto fail; + } + + /* PyArray_SearchSorted needs an increasing array */ + if (monotonic == - 1) { + PyArrayObject *arr_tmp = NULL; + npy_intp shape = PyArray_DIM(arr_bins, 0); + npy_intp stride = -PyArray_STRIDE(arr_bins, 0); + void *data = (void *)(PyArray_BYTES(arr_bins) - stride * (shape - 1)); + + arr_tmp = (PyArrayObject *)PyArray_New(&PyArray_Type, 1, &shape, + NPY_DOUBLE, &stride, data, 0, + PyArray_FLAGS(arr_bins), NULL); + if (!arr_tmp) { + goto fail; + } + + if (PyArray_SetBaseObject(arr_tmp, (PyObject *)arr_bins) < 0) { + + Py_DECREF(arr_tmp); + goto fail; + } + arr_bins = arr_tmp; + } + + ret = PyArray_SearchSorted(arr_bins, (PyObject *)arr_x, + right ? NPY_SEARCHLEFT : NPY_SEARCHRIGHT, NULL); + if (!ret) { + goto fail; + } + + /* If bins is decreasing, ret has bins from end, not start */ + if (monotonic == -1) { + npy_intp *ret_data = + (npy_intp *)PyArray_DATA((PyArrayObject *)ret); + npy_intp len_ret = PyArray_SIZE((PyArrayObject *)ret); + + NPY_BEGIN_THREADS_THRESHOLDED(len_ret) + while (len_ret--) { + *ret_data = len_bins - *ret_data; + ret_data++; + } + NPY_END_THREADS + } + + fail: + Py_XDECREF(arr_x); + Py_XDECREF(arr_bins); + return ret; +} + +/* + * Returns input array with values inserted sequentially into places + * indicated by the mask + */ +NPY_NO_EXPORT PyObject * +arr_insert(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict) +{ + char *src, *dest; + npy_bool *mask_data; + PyArray_Descr *dtype; + PyArray_CopySwapFunc *copyswap; + PyObject *array0, *mask0, *values0; + PyArrayObject *array, *mask, *values; + npy_intp i, j, chunk, nm, ni, nv; + + static char *kwlist[] = {"input", "mask", "vals", NULL}; + NPY_BEGIN_THREADS_DEF; + values = mask = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O!OO:place", kwlist, + &PyArray_Type, &array0, &mask0, &values0)) { + return NULL; + } + + array = (PyArrayObject *)PyArray_FromArray((PyArrayObject *)array0, NULL, + NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY); + if (array == NULL) { + goto fail; + } + + ni = PyArray_SIZE(array); + dest = PyArray_DATA(array); + chunk = PyArray_DESCR(array)->elsize; + mask = (PyArrayObject *)PyArray_FROM_OTF(mask0, NPY_BOOL, + NPY_ARRAY_CARRAY | NPY_ARRAY_FORCECAST); + if (mask == NULL) { + goto fail; + } + + nm = PyArray_SIZE(mask); + if (nm != ni) { + PyErr_SetString(PyExc_ValueError, + "place: mask and data must be " + "the same size"); + goto fail; + } + + mask_data = PyArray_DATA(mask); + dtype = PyArray_DESCR(array); + Py_INCREF(dtype); + + values = (PyArrayObject *)PyArray_FromAny(values0, dtype, + 0, 0, NPY_ARRAY_CARRAY, NULL); + if (values == NULL) { + goto fail; + } + + nv = PyArray_SIZE(values); /* zero if null array */ + if (nv <= 0) { + npy_bool allFalse = 1; + i = 0; + + while (allFalse && i < ni) { + if (mask_data[i]) { + allFalse = 0; + } else { + i++; + } + } + if (!allFalse) { + PyErr_SetString(PyExc_ValueError, + "Cannot insert from an empty array!"); + goto fail; + } else { + Py_XDECREF(values); + Py_XDECREF(mask); + Py_XDECREF(array); + Py_RETURN_NONE; + } + } + + src = PyArray_DATA(values); + j = 0; + + copyswap = PyArray_DESCR(array)->f->copyswap; + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(array)); + for (i = 0; i < ni; i++) { + if (mask_data[i]) { + if (j >= nv) { + j = 0; + } + + copyswap(dest + i*chunk, src + j*chunk, 0, array); + j++; + } + } + NPY_END_THREADS; + + Py_XDECREF(values); + Py_XDECREF(mask); + PyArray_ResolveWritebackIfCopy(array); + Py_DECREF(array); + Py_RETURN_NONE; + + fail: + Py_XDECREF(mask); + Py_XDECREF(array); + Py_XDECREF(values); + return NULL; +} + +#define LIKELY_IN_CACHE_SIZE 8 + +/** @brief find index of a sorted array such that arr[i] <= key < arr[i + 1]. + * + * If an starting index guess is in-range, the array values around this + * index are first checked. This allows for repeated calls for well-ordered + * keys (a very common case) to use the previous index as a very good guess. + * + * If the guess value is not useful, bisection of the array is used to + * find the index. If there is no such index, the return values are: + * key < arr[0] -- -1 + * key == arr[len - 1] -- len - 1 + * key > arr[len - 1] -- len + * The array is assumed contiguous and sorted in ascending order. + * + * @param key key value. + * @param arr contiguous sorted array to be searched. + * @param len length of the array. + * @param guess initial guess of index + * @return index + */ +static npy_intp +binary_search_with_guess(const npy_double key, const npy_double *arr, + npy_intp len, npy_intp guess) +{ + npy_intp imin = 0; + npy_intp imax = len; + + /* Handle keys outside of the arr range first */ + if (key > arr[len - 1]) { + return len; + } + else if (key < arr[0]) { + return -1; + } + + /* + * If len <= 4 use linear search. + * From above we know key >= arr[0] when we start. + */ + if (len <= 4) { + npy_intp i; + + for (i = 1; i < len && key >= arr[i]; ++i); + return i - 1; + } + + if (guess > len - 3) { + guess = len - 3; + } + if (guess < 1) { + guess = 1; + } + + /* check most likely values: guess - 1, guess, guess + 1 */ + if (key < arr[guess]) { + if (key < arr[guess - 1]) { + imax = guess - 1; + /* last attempt to restrict search to items in cache */ + if (guess > LIKELY_IN_CACHE_SIZE && + key >= arr[guess - LIKELY_IN_CACHE_SIZE]) { + imin = guess - LIKELY_IN_CACHE_SIZE; + } + } + else { + /* key >= arr[guess - 1] */ + return guess - 1; + } + } + else { + /* key >= arr[guess] */ + if (key < arr[guess + 1]) { + return guess; + } + else { + /* key >= arr[guess + 1] */ + if (key < arr[guess + 2]) { + return guess + 1; + } + else { + /* key >= arr[guess + 2] */ + imin = guess + 2; + /* last attempt to restrict search to items in cache */ + if (guess < len - LIKELY_IN_CACHE_SIZE - 1 && + key < arr[guess + LIKELY_IN_CACHE_SIZE]) { + imax = guess + LIKELY_IN_CACHE_SIZE; + } + } + } + } + + /* finally, find index by bisection */ + while (imin < imax) { + const npy_intp imid = imin + ((imax - imin) >> 1); + if (key >= arr[imid]) { + imin = imid + 1; + } + else { + imax = imid; + } + } + return imin - 1; +} + +#undef LIKELY_IN_CACHE_SIZE + +NPY_NO_EXPORT PyObject * +arr_interp(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict) +{ + + PyObject *fp, *xp, *x; + PyObject *left = NULL, *right = NULL; + PyArrayObject *afp = NULL, *axp = NULL, *ax = NULL, *af = NULL; + npy_intp i, lenx, lenxp; + npy_double lval, rval; + const npy_double *dy, *dx, *dz; + npy_double *dres, *slopes = NULL; + + static char *kwlist[] = {"x", "xp", "fp", "left", "right", NULL}; + + NPY_BEGIN_THREADS_DEF; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "OOO|OO:interp", kwlist, + &x, &xp, &fp, &left, &right)) { + return NULL; + } + + afp = (PyArrayObject *)PyArray_ContiguousFromAny(fp, NPY_DOUBLE, 1, 1); + if (afp == NULL) { + return NULL; + } + axp = (PyArrayObject *)PyArray_ContiguousFromAny(xp, NPY_DOUBLE, 1, 1); + if (axp == NULL) { + goto fail; + } + ax = (PyArrayObject *)PyArray_ContiguousFromAny(x, NPY_DOUBLE, 1, 0); + if (ax == NULL) { + goto fail; + } + lenxp = PyArray_SIZE(axp); + if (lenxp == 0) { + PyErr_SetString(PyExc_ValueError, + "array of sample points is empty"); + goto fail; + } + if (PyArray_SIZE(afp) != lenxp) { + PyErr_SetString(PyExc_ValueError, + "fp and xp are not of the same length."); + goto fail; + } + + af = (PyArrayObject *)PyArray_SimpleNew(PyArray_NDIM(ax), + PyArray_DIMS(ax), NPY_DOUBLE); + if (af == NULL) { + goto fail; + } + lenx = PyArray_SIZE(ax); + + dy = (const npy_double *)PyArray_DATA(afp); + dx = (const npy_double *)PyArray_DATA(axp); + dz = (const npy_double *)PyArray_DATA(ax); + dres = (npy_double *)PyArray_DATA(af); + /* Get left and right fill values. */ + if ((left == NULL) || (left == Py_None)) { + lval = dy[0]; + } + else { + lval = PyFloat_AsDouble(left); + if (error_converting(lval)) { + goto fail; + } + } + if ((right == NULL) || (right == Py_None)) { + rval = dy[lenxp - 1]; + } + else { + rval = PyFloat_AsDouble(right); + if (error_converting(rval)) { + goto fail; + } + } + + /* binary_search_with_guess needs at least a 3 item long array */ + if (lenxp == 1) { + const npy_double xp_val = dx[0]; + const npy_double fp_val = dy[0]; + + NPY_BEGIN_THREADS_THRESHOLDED(lenx); + for (i = 0; i < lenx; ++i) { + const npy_double x_val = dz[i]; + dres[i] = (x_val < xp_val) ? lval : + ((x_val > xp_val) ? rval : fp_val); + } + NPY_END_THREADS; + } + else { + npy_intp j = 0; + + /* only pre-calculate slopes if there are relatively few of them. */ + if (lenxp <= lenx) { + slopes = PyArray_malloc((lenxp - 1) * sizeof(npy_double)); + if (slopes == NULL) { + goto fail; + } + } + + NPY_BEGIN_THREADS; + + if (slopes != NULL) { + for (i = 0; i < lenxp - 1; ++i) { + slopes[i] = (dy[i+1] - dy[i]) / (dx[i+1] - dx[i]); + } + } + + for (i = 0; i < lenx; ++i) { + const npy_double x_val = dz[i]; + + if (npy_isnan(x_val)) { + dres[i] = x_val; + continue; + } + + j = binary_search_with_guess(x_val, dx, lenxp, j); + if (j == -1) { + dres[i] = lval; + } + else if (j == lenxp) { + dres[i] = rval; + } + else if (j == lenxp - 1) { + dres[i] = dy[j]; + } + else { + const npy_double slope = (slopes != NULL) ? slopes[j] : + (dy[j+1] - dy[j]) / (dx[j+1] - dx[j]); + dres[i] = slope*(x_val - dx[j]) + dy[j]; + } + } + + NPY_END_THREADS; + } + + PyArray_free(slopes); + Py_DECREF(afp); + Py_DECREF(axp); + Py_DECREF(ax); + return (PyObject *)af; + +fail: + Py_XDECREF(afp); + Py_XDECREF(axp); + Py_XDECREF(ax); + Py_XDECREF(af); + return NULL; +} + +/* As for arr_interp but for complex fp values */ +NPY_NO_EXPORT PyObject * +arr_interp_complex(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict) +{ + + PyObject *fp, *xp, *x; + PyObject *left = NULL, *right = NULL; + PyArrayObject *afp = NULL, *axp = NULL, *ax = NULL, *af = NULL; + npy_intp i, lenx, lenxp; + + const npy_double *dx, *dz; + const npy_cdouble *dy; + npy_cdouble lval, rval; + npy_cdouble *dres, *slopes = NULL; + + static char *kwlist[] = {"x", "xp", "fp", "left", "right", NULL}; + + NPY_BEGIN_THREADS_DEF; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "OOO|OO:interp_complex", + kwlist, &x, &xp, &fp, &left, &right)) { + return NULL; + } + + afp = (PyArrayObject *)PyArray_ContiguousFromAny(fp, NPY_CDOUBLE, 1, 1); + + if (afp == NULL) { + return NULL; + } + + axp = (PyArrayObject *)PyArray_ContiguousFromAny(xp, NPY_DOUBLE, 1, 1); + if (axp == NULL) { + goto fail; + } + ax = (PyArrayObject *)PyArray_ContiguousFromAny(x, NPY_DOUBLE, 1, 0); + if (ax == NULL) { + goto fail; + } + lenxp = PyArray_SIZE(axp); + if (lenxp == 0) { + PyErr_SetString(PyExc_ValueError, + "array of sample points is empty"); + goto fail; + } + if (PyArray_SIZE(afp) != lenxp) { + PyErr_SetString(PyExc_ValueError, + "fp and xp are not of the same length."); + goto fail; + } + + lenx = PyArray_SIZE(ax); + dx = (const npy_double *)PyArray_DATA(axp); + dz = (const npy_double *)PyArray_DATA(ax); + + af = (PyArrayObject *)PyArray_SimpleNew(PyArray_NDIM(ax), + PyArray_DIMS(ax), NPY_CDOUBLE); + if (af == NULL) { + goto fail; + } + + dy = (const npy_cdouble *)PyArray_DATA(afp); + dres = (npy_cdouble *)PyArray_DATA(af); + /* Get left and right fill values. */ + if ((left == NULL) || (left == Py_None)) { + lval = dy[0]; + } + else { + lval.real = PyComplex_RealAsDouble(left); + if (error_converting(lval.real)) { + goto fail; + } + lval.imag = PyComplex_ImagAsDouble(left); + if (error_converting(lval.imag)) { + goto fail; + } + } + + if ((right == NULL) || (right == Py_None)) { + rval = dy[lenxp - 1]; + } + else { + rval.real = PyComplex_RealAsDouble(right); + if (error_converting(rval.real)) { + goto fail; + } + rval.imag = PyComplex_ImagAsDouble(right); + if (error_converting(rval.imag)) { + goto fail; + } + } + + /* binary_search_with_guess needs at least a 3 item long array */ + if (lenxp == 1) { + const npy_double xp_val = dx[0]; + const npy_cdouble fp_val = dy[0]; + + NPY_BEGIN_THREADS_THRESHOLDED(lenx); + for (i = 0; i < lenx; ++i) { + const npy_double x_val = dz[i]; + dres[i] = (x_val < xp_val) ? lval : + ((x_val > xp_val) ? rval : fp_val); + } + NPY_END_THREADS; + } + else { + npy_intp j = 0; + + /* only pre-calculate slopes if there are relatively few of them. */ + if (lenxp <= lenx) { + slopes = PyArray_malloc((lenxp - 1) * sizeof(npy_cdouble)); + if (slopes == NULL) { + goto fail; + } + } + + NPY_BEGIN_THREADS; + + if (slopes != NULL) { + for (i = 0; i < lenxp - 1; ++i) { + const double inv_dx = 1.0 / (dx[i+1] - dx[i]); + slopes[i].real = (dy[i+1].real - dy[i].real) * inv_dx; + slopes[i].imag = (dy[i+1].imag - dy[i].imag) * inv_dx; + } + } + + for (i = 0; i < lenx; ++i) { + const npy_double x_val = dz[i]; + + if (npy_isnan(x_val)) { + dres[i].real = x_val; + dres[i].imag = 0.0; + continue; + } + + j = binary_search_with_guess(x_val, dx, lenxp, j); + if (j == -1) { + dres[i] = lval; + } + else if (j == lenxp) { + dres[i] = rval; + } + else if (j == lenxp - 1) { + dres[i] = dy[j]; + } + else { + if (slopes!=NULL) { + dres[i].real = slopes[j].real*(x_val - dx[j]) + dy[j].real; + dres[i].imag = slopes[j].imag*(x_val - dx[j]) + dy[j].imag; + } + else { + const npy_double inv_dx = 1.0 / (dx[j+1] - dx[j]); + dres[i].real = (dy[j+1].real - dy[j].real)*(x_val - dx[j])* + inv_dx + dy[j].real; + dres[i].imag = (dy[j+1].imag - dy[j].imag)*(x_val - dx[j])* + inv_dx + dy[j].imag; + } + } + } + + NPY_END_THREADS; + } + PyArray_free(slopes); + + Py_DECREF(afp); + Py_DECREF(axp); + Py_DECREF(ax); + return (PyObject *)af; + +fail: + Py_XDECREF(afp); + Py_XDECREF(axp); + Py_XDECREF(ax); + Py_XDECREF(af); + return NULL; +} + +/* + * Converts a Python sequence into 'count' PyArrayObjects + * + * seq - Input Python object, usually a tuple but any sequence works. + * op - Where the arrays are placed. + * count - How many arrays there should be (errors if it doesn't match). + * paramname - The name of the parameter that produced 'seq'. + */ +static int sequence_to_arrays(PyObject *seq, + PyArrayObject **op, int count, + char *paramname) +{ + int i; + + if (!PySequence_Check(seq) || PySequence_Size(seq) != count) { + PyErr_Format(PyExc_ValueError, + "parameter %s must be a sequence of length %d", + paramname, count); + return -1; + } + + for (i = 0; i < count; ++i) { + PyObject *item = PySequence_GetItem(seq, i); + if (item == NULL) { + while (--i >= 0) { + Py_DECREF(op[i]); + op[i] = NULL; + } + return -1; + } + + op[i] = (PyArrayObject *)PyArray_FROM_O(item); + if (op[i] == NULL) { + while (--i >= 0) { + Py_DECREF(op[i]); + op[i] = NULL; + } + Py_DECREF(item); + return -1; + } + + Py_DECREF(item); + } + + return 0; +} + +/* Inner loop for unravel_index */ +static int +ravel_multi_index_loop(int ravel_ndim, npy_intp *ravel_dims, + npy_intp *ravel_strides, + npy_intp count, + NPY_CLIPMODE *modes, + char **coords, npy_intp *coords_strides) +{ + int i; + char invalid; + npy_intp j, m; + + NPY_BEGIN_ALLOW_THREADS; + invalid = 0; + while (count--) { + npy_intp raveled = 0; + for (i = 0; i < ravel_ndim; ++i) { + m = ravel_dims[i]; + j = *(npy_intp *)coords[i]; + switch (modes[i]) { + case NPY_RAISE: + if (j < 0 || j >= m) { + invalid = 1; + goto end_while; + } + break; + case NPY_WRAP: + if (j < 0) { + j += m; + if (j < 0) { + j = j % m; + if (j != 0) { + j += m; + } + } + } + else if (j >= m) { + j -= m; + if (j >= m) { + j = j % m; + } + } + break; + case NPY_CLIP: + if (j < 0) { + j = 0; + } + else if (j >= m) { + j = m - 1; + } + break; + + } + raveled += j * ravel_strides[i]; + + coords[i] += coords_strides[i]; + } + *(npy_intp *)coords[ravel_ndim] = raveled; + coords[ravel_ndim] += coords_strides[ravel_ndim]; + } +end_while: + NPY_END_ALLOW_THREADS; + if (invalid) { + PyErr_SetString(PyExc_ValueError, + "invalid entry in coordinates array"); + return NPY_FAIL; + } + return NPY_SUCCEED; +} + +/* ravel_multi_index implementation - see add_newdocs.py */ +NPY_NO_EXPORT PyObject * +arr_ravel_multi_index(PyObject *self, PyObject *args, PyObject *kwds) +{ + int i; + PyObject *mode0=NULL, *coords0=NULL; + PyArrayObject *ret = NULL; + PyArray_Dims dimensions={0,0}; + npy_intp s, ravel_strides[NPY_MAXDIMS]; + NPY_ORDER order = NPY_CORDER; + NPY_CLIPMODE modes[NPY_MAXDIMS]; + + PyArrayObject *op[NPY_MAXARGS]; + PyArray_Descr *dtype[NPY_MAXARGS]; + npy_uint32 op_flags[NPY_MAXARGS]; + + NpyIter *iter = NULL; + + char *kwlist[] = {"multi_index", "dims", "mode", "order", NULL}; + + memset(op, 0, sizeof(op)); + dtype[0] = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "OO&|OO&:ravel_multi_index", kwlist, + &coords0, + PyArray_IntpConverter, &dimensions, + &mode0, + PyArray_OrderConverter, &order)) { + goto fail; + } + + if (dimensions.len+1 > NPY_MAXARGS) { + PyErr_SetString(PyExc_ValueError, + "too many dimensions passed to ravel_multi_index"); + goto fail; + } + + if (!PyArray_ConvertClipmodeSequence(mode0, modes, dimensions.len)) { + goto fail; + } + + switch (order) { + case NPY_CORDER: + s = 1; + for (i = dimensions.len-1; i >= 0; --i) { + ravel_strides[i] = s; + if (npy_mul_with_overflow_intp(&s, s, dimensions.ptr[i])) { + PyErr_SetString(PyExc_ValueError, + "invalid dims: array size defined by dims is larger " + "than the maximum possible size."); + goto fail; + } + } + break; + case NPY_FORTRANORDER: + s = 1; + for (i = 0; i < dimensions.len; ++i) { + ravel_strides[i] = s; + if (npy_mul_with_overflow_intp(&s, s, dimensions.ptr[i])) { + PyErr_SetString(PyExc_ValueError, + "invalid dims: array size defined by dims is larger " + "than the maximum possible size."); + goto fail; + } + } + break; + default: + PyErr_SetString(PyExc_ValueError, + "only 'C' or 'F' order is permitted"); + goto fail; + } + + /* Get the multi_index into op */ + if (sequence_to_arrays(coords0, op, dimensions.len, "multi_index") < 0) { + goto fail; + } + + + for (i = 0; i < dimensions.len; ++i) { + op_flags[i] = NPY_ITER_READONLY| + NPY_ITER_ALIGNED; + } + op_flags[dimensions.len] = NPY_ITER_WRITEONLY| + NPY_ITER_ALIGNED| + NPY_ITER_ALLOCATE; + dtype[0] = PyArray_DescrFromType(NPY_INTP); + for (i = 1; i <= dimensions.len; ++i) { + dtype[i] = dtype[0]; + } + + iter = NpyIter_MultiNew(dimensions.len+1, op, NPY_ITER_BUFFERED| + NPY_ITER_EXTERNAL_LOOP| + NPY_ITER_ZEROSIZE_OK, + NPY_KEEPORDER, + NPY_SAME_KIND_CASTING, + op_flags, dtype); + if (iter == NULL) { + goto fail; + } + + if (NpyIter_GetIterSize(iter) != 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strides; + npy_intp *countptr; + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strides = NpyIter_GetInnerStrideArray(iter); + countptr = NpyIter_GetInnerLoopSizePtr(iter); + + do { + if (ravel_multi_index_loop(dimensions.len, dimensions.ptr, + ravel_strides, *countptr, modes, + dataptr, strides) != NPY_SUCCEED) { + goto fail; + } + } while(iternext(iter)); + } + + ret = NpyIter_GetOperandArray(iter)[dimensions.len]; + Py_INCREF(ret); + + Py_DECREF(dtype[0]); + for (i = 0; i < dimensions.len; ++i) { + Py_XDECREF(op[i]); + } + npy_free_cache_dim_obj(dimensions); + NpyIter_Deallocate(iter); + return PyArray_Return(ret); + +fail: + Py_XDECREF(dtype[0]); + for (i = 0; i < dimensions.len; ++i) { + Py_XDECREF(op[i]); + } + npy_free_cache_dim_obj(dimensions); + NpyIter_Deallocate(iter); + return NULL; +} + +/* C-order inner loop for unravel_index */ +static int +unravel_index_loop_corder(int unravel_ndim, npy_intp *unravel_dims, + npy_intp unravel_size, npy_intp count, + char *indices, npy_intp indices_stride, + npy_intp *coords) +{ + int i; + char invalid; + npy_intp val; + + NPY_BEGIN_ALLOW_THREADS; + invalid = 0; + while (count--) { + val = *(npy_intp *)indices; + if (val < 0 || val >= unravel_size) { + invalid = 1; + break; + } + for (i = unravel_ndim-1; i >= 0; --i) { + coords[i] = val % unravel_dims[i]; + val /= unravel_dims[i]; + } + coords += unravel_ndim; + indices += indices_stride; + } + NPY_END_ALLOW_THREADS; + if (invalid) { + PyErr_Format(PyExc_ValueError, + "index %" NPY_INTP_FMT " is out of bounds for array with size " + "%" NPY_INTP_FMT, + val, unravel_size + ); + return NPY_FAIL; + } + return NPY_SUCCEED; +} + +/* Fortran-order inner loop for unravel_index */ +static int +unravel_index_loop_forder(int unravel_ndim, npy_intp *unravel_dims, + npy_intp unravel_size, npy_intp count, + char *indices, npy_intp indices_stride, + npy_intp *coords) +{ + int i; + char invalid; + npy_intp val; + + NPY_BEGIN_ALLOW_THREADS; + invalid = 0; + while (count--) { + val = *(npy_intp *)indices; + if (val < 0 || val >= unravel_size) { + invalid = 1; + break; + } + for (i = 0; i < unravel_ndim; ++i) { + *coords++ = val % unravel_dims[i]; + val /= unravel_dims[i]; + } + indices += indices_stride; + } + NPY_END_ALLOW_THREADS; + if (invalid) { + PyErr_Format(PyExc_ValueError, + "index %" NPY_INTP_FMT " is out of bounds for array with size " + "%" NPY_INTP_FMT, + val, unravel_size + ); + return NPY_FAIL; + } + return NPY_SUCCEED; +} + +/* unravel_index implementation - see add_newdocs.py */ +NPY_NO_EXPORT PyObject * +arr_unravel_index(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *indices0 = NULL, *ret_tuple = NULL; + PyArrayObject *ret_arr = NULL; + PyArrayObject *indices = NULL; + PyArray_Descr *dtype = NULL; + PyArray_Dims dimensions={0,0}; + NPY_ORDER order = NPY_CORDER; + npy_intp unravel_size; + + NpyIter *iter = NULL; + int i, ret_ndim; + npy_intp ret_dims[NPY_MAXDIMS], ret_strides[NPY_MAXDIMS]; + + char *kwlist[] = {"indices", "dims", "order", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|O&:unravel_index", + kwlist, + &indices0, + PyArray_IntpConverter, &dimensions, + PyArray_OrderConverter, &order)) { + goto fail; + } + + unravel_size = PyArray_MultiplyList(dimensions.ptr, dimensions.len); + + if (!PyArray_Check(indices0)) { + indices = (PyArrayObject*)PyArray_FROM_O(indices0); + if (indices == NULL) { + goto fail; + } + } + else { + indices = (PyArrayObject *)indices0; + Py_INCREF(indices); + } + + dtype = PyArray_DescrFromType(NPY_INTP); + if (dtype == NULL) { + goto fail; + } + + iter = NpyIter_New(indices, NPY_ITER_READONLY| + NPY_ITER_ALIGNED| + NPY_ITER_BUFFERED| + NPY_ITER_ZEROSIZE_OK| + NPY_ITER_DONT_NEGATE_STRIDES| + NPY_ITER_MULTI_INDEX, + NPY_KEEPORDER, NPY_SAME_KIND_CASTING, + dtype); + if (iter == NULL) { + goto fail; + } + + /* + * Create the return array with a layout compatible with the indices + * and with a dimension added to the end for the multi-index + */ + ret_ndim = PyArray_NDIM(indices) + 1; + if (NpyIter_GetShape(iter, ret_dims) != NPY_SUCCEED) { + goto fail; + } + ret_dims[ret_ndim-1] = dimensions.len; + if (NpyIter_CreateCompatibleStrides(iter, + dimensions.len*sizeof(npy_intp), ret_strides) != NPY_SUCCEED) { + goto fail; + } + ret_strides[ret_ndim-1] = sizeof(npy_intp); + + /* Remove the multi-index and inner loop */ + if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED) { + goto fail; + } + if (NpyIter_EnableExternalLoop(iter) != NPY_SUCCEED) { + goto fail; + } + + ret_arr = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, + ret_ndim, ret_dims, ret_strides, NULL, 0, NULL); + dtype = NULL; + if (ret_arr == NULL) { + goto fail; + } + + if (order == NPY_CORDER) { + if (NpyIter_GetIterSize(iter) != 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strides; + npy_intp *countptr, count; + npy_intp *coordsptr = (npy_intp *)PyArray_DATA(ret_arr); + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strides = NpyIter_GetInnerStrideArray(iter); + countptr = NpyIter_GetInnerLoopSizePtr(iter); + + do { + count = *countptr; + if (unravel_index_loop_corder(dimensions.len, dimensions.ptr, + unravel_size, count, *dataptr, *strides, + coordsptr) != NPY_SUCCEED) { + goto fail; + } + coordsptr += count*dimensions.len; + } while(iternext(iter)); + } + } + else if (order == NPY_FORTRANORDER) { + if (NpyIter_GetIterSize(iter) != 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strides; + npy_intp *countptr, count; + npy_intp *coordsptr = (npy_intp *)PyArray_DATA(ret_arr); + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strides = NpyIter_GetInnerStrideArray(iter); + countptr = NpyIter_GetInnerLoopSizePtr(iter); + + do { + count = *countptr; + if (unravel_index_loop_forder(dimensions.len, dimensions.ptr, + unravel_size, count, *dataptr, *strides, + coordsptr) != NPY_SUCCEED) { + goto fail; + } + coordsptr += count*dimensions.len; + } while(iternext(iter)); + } + } + else { + PyErr_SetString(PyExc_ValueError, + "only 'C' or 'F' order is permitted"); + goto fail; + } + + + if (dimensions.len == 0 && PyArray_NDIM(indices) != 0) { + /* + * There's no index meaning "take the only element 10 times" + * on a zero-d array, so we have no choice but to error. (See gh-580) + * + * Do this check after iterating, so we give a better error message + * for invalid indices. + */ + PyErr_SetString(PyExc_ValueError, + "multiple indices are not supported for 0d arrays"); + goto fail; + } + + /* Now make a tuple of views, one per index */ + ret_tuple = PyTuple_New(dimensions.len); + if (ret_tuple == NULL) { + goto fail; + } + for (i = 0; i < dimensions.len; ++i) { + PyArrayObject *view; + + view = (PyArrayObject *)PyArray_New(&PyArray_Type, ret_ndim-1, + ret_dims, NPY_INTP, + ret_strides, + PyArray_BYTES(ret_arr) + i*sizeof(npy_intp), + 0, NPY_ARRAY_WRITEABLE, NULL); + if (view == NULL) { + goto fail; + } + Py_INCREF(ret_arr); + if (PyArray_SetBaseObject(view, (PyObject *)ret_arr) < 0) { + Py_DECREF(view); + goto fail; + } + PyTuple_SET_ITEM(ret_tuple, i, PyArray_Return(view)); + } + + Py_DECREF(ret_arr); + Py_XDECREF(indices); + npy_free_cache_dim_obj(dimensions); + NpyIter_Deallocate(iter); + + return ret_tuple; + +fail: + Py_XDECREF(ret_tuple); + Py_XDECREF(ret_arr); + Py_XDECREF(dtype); + Py_XDECREF(indices); + npy_free_cache_dim_obj(dimensions); + NpyIter_Deallocate(iter); + return NULL; +} + + +/* Can only be called if doc is currently NULL */ +NPY_NO_EXPORT PyObject * +arr_add_docstring(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyObject *obj; + PyObject *str; + char *docstr; + static char *msg = "already has a docstring"; + PyObject *tp_dict = PyArrayDescr_Type.tp_dict; + PyObject *myobj; + static PyTypeObject *PyMemberDescr_TypePtr = NULL; + static PyTypeObject *PyGetSetDescr_TypePtr = NULL; + static PyTypeObject *PyMethodDescr_TypePtr = NULL; + + /* Don't add docstrings */ + if (Py_OptimizeFlag > 1) { + Py_RETURN_NONE; + } + + if (PyGetSetDescr_TypePtr == NULL) { + /* Get "subdescr" */ + myobj = PyDict_GetItemString(tp_dict, "fields"); + if (myobj != NULL) { + PyGetSetDescr_TypePtr = Py_TYPE(myobj); + } + } + if (PyMemberDescr_TypePtr == NULL) { + myobj = PyDict_GetItemString(tp_dict, "alignment"); + if (myobj != NULL) { + PyMemberDescr_TypePtr = Py_TYPE(myobj); + } + } + if (PyMethodDescr_TypePtr == NULL) { + myobj = PyDict_GetItemString(tp_dict, "newbyteorder"); + if (myobj != NULL) { + PyMethodDescr_TypePtr = Py_TYPE(myobj); + } + } + +#if defined(NPY_PY3K) + if (!PyArg_ParseTuple(args, "OO!:add_docstring", &obj, &PyUnicode_Type, &str)) { + return NULL; + } + + docstr = PyBytes_AS_STRING(PyUnicode_AsUTF8String(str)); +#else + if (!PyArg_ParseTuple(args, "OO!:add_docstring", &obj, &PyString_Type, &str)) { + return NULL; + } + + docstr = PyString_AS_STRING(str); +#endif + +#define _TESTDOC1(typebase) (Py_TYPE(obj) == &Py##typebase##_Type) +#define _TESTDOC2(typebase) (Py_TYPE(obj) == Py##typebase##_TypePtr) +#define _ADDDOC(typebase, doc, name) do { \ + Py##typebase##Object *new = (Py##typebase##Object *)obj; \ + if (!(doc)) { \ + doc = docstr; \ + } \ + else { \ + PyErr_Format(PyExc_RuntimeError, "%s method %s", name, msg); \ + return NULL; \ + } \ + } while (0) + + if (_TESTDOC1(CFunction)) { + _ADDDOC(CFunction, new->m_ml->ml_doc, new->m_ml->ml_name); + } + else if (_TESTDOC1(Type)) { + _ADDDOC(Type, new->tp_doc, new->tp_name); + } + else if (_TESTDOC2(MemberDescr)) { + _ADDDOC(MemberDescr, new->d_member->doc, new->d_member->name); + } + else if (_TESTDOC2(GetSetDescr)) { + _ADDDOC(GetSetDescr, new->d_getset->doc, new->d_getset->name); + } + else if (_TESTDOC2(MethodDescr)) { + _ADDDOC(MethodDescr, new->d_method->ml_doc, new->d_method->ml_name); + } + else { + PyObject *doc_attr; + + doc_attr = PyObject_GetAttrString(obj, "__doc__"); + if (doc_attr != NULL && doc_attr != Py_None) { + PyErr_Format(PyExc_RuntimeError, "object %s", msg); + return NULL; + } + Py_XDECREF(doc_attr); + + if (PyObject_SetAttrString(obj, "__doc__", str) < 0) { + PyErr_SetString(PyExc_TypeError, + "Cannot set a docstring for that object"); + return NULL; + } + Py_RETURN_NONE; + } + +#undef _TESTDOC1 +#undef _TESTDOC2 +#undef _ADDDOC + + Py_INCREF(str); + Py_RETURN_NONE; +} + +#if defined NPY_HAVE_SSE2_INTRINSICS +#include +#endif + +/* + * This function packs boolean values in the input array into the bits of a + * byte array. Truth values are determined as usual: 0 is false, everything + * else is true. + */ +static NPY_INLINE void +pack_inner(const char *inptr, + npy_intp element_size, /* in bytes */ + npy_intp n_in, + npy_intp in_stride, + char *outptr, + npy_intp n_out, + npy_intp out_stride) +{ + /* + * Loop through the elements of inptr. + * Determine whether or not it is nonzero. + * Yes: set corresponding bit (and adjust build value) + * No: move on + * Every 8th value, set the value of build and increment the outptr + */ + npy_intp index = 0; + int remain = n_in % 8; /* uneven bits */ + +#if defined NPY_HAVE_SSE2_INTRINSICS && defined HAVE__M_FROM_INT64 + if (in_stride == 1 && element_size == 1 && n_out > 2) { + __m128i zero = _mm_setzero_si128(); + /* don't handle non-full 8-byte remainder */ + npy_intp vn_out = n_out - (remain ? 1 : 0); + vn_out -= (vn_out & 1); + for (index = 0; index < vn_out; index += 2) { + unsigned int r; + /* swap as packbits is "big endian", note x86 can load unaligned */ + npy_uint64 a = npy_bswap8(*(npy_uint64*)inptr); + npy_uint64 b = npy_bswap8(*(npy_uint64*)(inptr + 8)); + __m128i v = _mm_set_epi64(_m_from_int64(b), _m_from_int64(a)); + /* false -> 0x00 and true -> 0xFF (there is no cmpneq) */ + v = _mm_cmpeq_epi8(v, zero); + v = _mm_cmpeq_epi8(v, zero); + /* extract msb of 16 bytes and pack it into 16 bit */ + r = _mm_movemask_epi8(v); + /* store result */ + memcpy(outptr, &r, 1); + outptr += out_stride; + memcpy(outptr, (char*)&r + 1, 1); + outptr += out_stride; + inptr += 16; + } + } +#endif + + if (remain == 0) { /* assumes n_in > 0 */ + remain = 8; + } + /* don't reset index to handle remainder of above block */ + for (; index < n_out; index++) { + char build = 0; + int i, maxi; + npy_intp j; + + maxi = (index == n_out - 1) ? remain : 8; + for (i = 0; i < maxi; i++) { + build <<= 1; + for (j = 0; j < element_size; j++) { + build |= (inptr[j] != 0); + } + inptr += in_stride; + } + if (index == n_out - 1) { + build <<= 8 - remain; + } + *outptr = build; + outptr += out_stride; + } +} + +static PyObject * +pack_bits(PyObject *input, int axis) +{ + PyArrayObject *inp; + PyArrayObject *new = NULL; + PyArrayObject *out = NULL; + npy_intp outdims[NPY_MAXDIMS]; + int i; + PyArrayIterObject *it, *ot; + NPY_BEGIN_THREADS_DEF; + + inp = (PyArrayObject *)PyArray_FROM_O(input); + + if (inp == NULL) { + return NULL; + } + if (!PyArray_ISBOOL(inp) && !PyArray_ISINTEGER(inp)) { + PyErr_SetString(PyExc_TypeError, + "Expected an input array of integer or boolean data type"); + goto fail; + } + + new = (PyArrayObject *)PyArray_CheckAxis(inp, &axis, 0); + Py_DECREF(inp); + if (new == NULL) { + return NULL; + } + + if (PyArray_NDIM(new) == 0) { + char *optr, *iptr; + + out = (PyArrayObject *)PyArray_New(Py_TYPE(new), 0, NULL, NPY_UBYTE, + NULL, NULL, 0, 0, NULL); + if (out == NULL) { + goto fail; + } + optr = PyArray_DATA(out); + iptr = PyArray_DATA(new); + *optr = 0; + for (i = 0; i < PyArray_ITEMSIZE(new); i++) { + if (*iptr != 0) { + *optr = 1; + break; + } + iptr++; + } + goto finish; + } + + + /* Setup output shape */ + for (i = 0; i < PyArray_NDIM(new); i++) { + outdims[i] = PyArray_DIM(new, i); + } + + /* + * Divide axis dimension by 8 + * 8 -> 1, 9 -> 2, 16 -> 2, 17 -> 3 etc.. + */ + outdims[axis] = ((outdims[axis] - 1) >> 3) + 1; + + /* Create output array */ + out = (PyArrayObject *)PyArray_New(Py_TYPE(new), + PyArray_NDIM(new), outdims, NPY_UBYTE, + NULL, NULL, 0, PyArray_ISFORTRAN(new), NULL); + if (out == NULL) { + goto fail; + } + /* Setup iterators to iterate over all but given axis */ + it = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)new, &axis); + ot = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)out, &axis); + if (it == NULL || ot == NULL) { + Py_XDECREF(it); + Py_XDECREF(ot); + goto fail; + } + + NPY_BEGIN_THREADS_THRESHOLDED(PyArray_DIM(out, axis)); + while (PyArray_ITER_NOTDONE(it)) { + pack_inner(PyArray_ITER_DATA(it), PyArray_ITEMSIZE(new), + PyArray_DIM(new, axis), PyArray_STRIDE(new, axis), + PyArray_ITER_DATA(ot), PyArray_DIM(out, axis), + PyArray_STRIDE(out, axis)); + PyArray_ITER_NEXT(it); + PyArray_ITER_NEXT(ot); + } + NPY_END_THREADS; + + Py_DECREF(it); + Py_DECREF(ot); + +finish: + Py_DECREF(new); + return (PyObject *)out; + +fail: + Py_XDECREF(new); + Py_XDECREF(out); + return NULL; +} + +static PyObject * +unpack_bits(PyObject *input, int axis) +{ + static int unpack_init = 0; + static char unpack_lookup[256][8]; + PyArrayObject *inp; + PyArrayObject *new = NULL; + PyArrayObject *out = NULL; + npy_intp outdims[NPY_MAXDIMS]; + int i; + PyArrayIterObject *it, *ot; + npy_intp n_in, in_stride, out_stride; + NPY_BEGIN_THREADS_DEF; + + inp = (PyArrayObject *)PyArray_FROM_O(input); + + if (inp == NULL) { + return NULL; + } + if (PyArray_TYPE(inp) != NPY_UBYTE) { + PyErr_SetString(PyExc_TypeError, + "Expected an input array of unsigned byte data type"); + goto fail; + } + + new = (PyArrayObject *)PyArray_CheckAxis(inp, &axis, 0); + Py_DECREF(inp); + if (new == NULL) { + return NULL; + } + + if (PyArray_NDIM(new) == 0) { + /* Handle 0-d array by converting it to a 1-d array */ + PyArrayObject *temp; + PyArray_Dims newdim = {NULL, 1}; + npy_intp shape = 1; + + newdim.ptr = &shape; + temp = (PyArrayObject *)PyArray_Newshape(new, &newdim, NPY_CORDER); + if (temp == NULL) { + goto fail; + } + Py_DECREF(new); + new = temp; + } + + /* Setup output shape */ + for (i=0; i>= 1; + } + inptr += in_stride; + } + } + PyArray_ITER_NEXT(it); + PyArray_ITER_NEXT(ot); + } + NPY_END_THREADS; + + Py_DECREF(it); + Py_DECREF(ot); + + Py_DECREF(new); + return (PyObject *)out; + +fail: + Py_XDECREF(new); + Py_XDECREF(out); + return NULL; +} + + +NPY_NO_EXPORT PyObject * +io_pack(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds) +{ + PyObject *obj; + int axis = NPY_MAXDIMS; + static char *kwlist[] = {"in", "axis", NULL}; + + if (!PyArg_ParseTupleAndKeywords( args, kwds, "O|O&:pack" , kwlist, + &obj, PyArray_AxisConverter, &axis)) { + return NULL; + } + return pack_bits(obj, axis); +} + +NPY_NO_EXPORT PyObject * +io_unpack(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds) +{ + PyObject *obj; + int axis = NPY_MAXDIMS; + static char *kwlist[] = {"in", "axis", NULL}; + + if (!PyArg_ParseTupleAndKeywords( args, kwds, "O|O&:unpack" , kwlist, + &obj, PyArray_AxisConverter, &axis)) { + return NULL; + } + return unpack_bits(obj, axis); +} diff --git a/numpy/core/src/multiarray/compiled_base.h b/numpy/core/src/multiarray/compiled_base.h new file mode 100644 index 0000000..5150853 --- /dev/null +++ b/numpy/core/src/multiarray/compiled_base.h @@ -0,0 +1,26 @@ +#ifndef _NPY_PRIVATE__COMPILED_BASE_H_ +#define _NPY_PRIVATE__COMPILED_BASE_H_ +#include + +NPY_NO_EXPORT PyObject * +arr_insert(PyObject *, PyObject *, PyObject *); +NPY_NO_EXPORT PyObject * +arr_bincount(PyObject *, PyObject *, PyObject *); +NPY_NO_EXPORT PyObject * +arr_digitize(PyObject *, PyObject *, PyObject *kwds); +NPY_NO_EXPORT PyObject * +arr_interp(PyObject *, PyObject *, PyObject *); +NPY_NO_EXPORT PyObject * +arr_interp_complex(PyObject *, PyObject *, PyObject *); +NPY_NO_EXPORT PyObject * +arr_ravel_multi_index(PyObject *, PyObject *, PyObject *); +NPY_NO_EXPORT PyObject * +arr_unravel_index(PyObject *, PyObject *, PyObject *); +NPY_NO_EXPORT PyObject * +arr_add_docstring(PyObject *, PyObject *); +NPY_NO_EXPORT PyObject * +io_pack(PyObject *, PyObject *, PyObject *); +NPY_NO_EXPORT PyObject * +io_unpack(PyObject *, PyObject *, PyObject *); + +#endif diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c new file mode 100644 index 0000000..2bb1cbf --- /dev/null +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -0,0 +1,1165 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" +#include "numpy/arrayobject.h" + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "common.h" +#include "arraytypes.h" + +#include "conversion_utils.h" +#include "alloc.h" + +static int +PyArray_PyIntAsInt_ErrMsg(PyObject *o, const char * msg) NPY_GCC_NONNULL(2); +static npy_intp +PyArray_PyIntAsIntp_ErrMsg(PyObject *o, const char * msg) NPY_GCC_NONNULL(2); + +/**************************************************************** +* Useful function for conversion when used with PyArg_ParseTuple +****************************************************************/ + +/*NUMPY_API + * + * Useful to pass as converter function for O& processing in PyArgs_ParseTuple. + * + * This conversion function can be used with the "O&" argument for + * PyArg_ParseTuple. It will immediately return an object of array type + * or will convert to a NPY_ARRAY_CARRAY any other object. + * + * If you use PyArray_Converter, you must DECREF the array when finished + * as you get a new reference to it. + */ +NPY_NO_EXPORT int +PyArray_Converter(PyObject *object, PyObject **address) +{ + if (PyArray_Check(object)) { + *address = object; + Py_INCREF(object); + return NPY_SUCCEED; + } + else { + *address = PyArray_FROM_OF(object, NPY_ARRAY_CARRAY); + if (*address == NULL) { + return NPY_FAIL; + } + return NPY_SUCCEED; + } +} + +/*NUMPY_API + * Useful to pass as converter function for O& processing in + * PyArgs_ParseTuple for output arrays + */ +NPY_NO_EXPORT int +PyArray_OutputConverter(PyObject *object, PyArrayObject **address) +{ + if (object == NULL || object == Py_None) { + *address = NULL; + return NPY_SUCCEED; + } + if (PyArray_Check(object)) { + *address = (PyArrayObject *)object; + return NPY_SUCCEED; + } + else { + PyErr_SetString(PyExc_TypeError, + "output must be an array"); + *address = NULL; + return NPY_FAIL; + } +} + +/*NUMPY_API + * Get intp chunk from sequence + * + * This function takes a Python sequence object and allocates and + * fills in an intp array with the converted values. + * + * Remember to free the pointer seq.ptr when done using + * PyDimMem_FREE(seq.ptr)** + */ +NPY_NO_EXPORT int +PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq) +{ + Py_ssize_t len; + int nd; + + seq->ptr = NULL; + seq->len = 0; + if (obj == Py_None) { + return NPY_SUCCEED; + } + len = PySequence_Size(obj); + if (len == -1) { + /* Check to see if it is an integer number */ + if (PyNumber_Check(obj)) { + /* + * After the deprecation the PyNumber_Check could be replaced + * by PyIndex_Check. + * FIXME 1.9 ? + */ + len = 1; + } + } + if (len < 0) { + PyErr_SetString(PyExc_TypeError, + "expected sequence object with len >= 0 or a single integer"); + return NPY_FAIL; + } + if (len > NPY_MAXDIMS) { + PyErr_Format(PyExc_ValueError, "sequence too large; " + "cannot be greater than %d", NPY_MAXDIMS); + return NPY_FAIL; + } + if (len > 0) { + seq->ptr = npy_alloc_cache_dim(len); + if (seq->ptr == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + } + seq->len = len; + nd = PyArray_IntpFromIndexSequence(obj, (npy_intp *)seq->ptr, len); + if (nd == -1 || nd != len) { + npy_free_cache_dim_obj(*seq); + seq->ptr = NULL; + return NPY_FAIL; + } + return NPY_SUCCEED; +} + +/*NUMPY_API + * Get buffer chunk from object + * + * this function takes a Python object which exposes the (single-segment) + * buffer interface and returns a pointer to the data segment + * + * You should increment the reference count by one of buf->base + * if you will hang on to a reference + * + * You only get a borrowed reference to the object. Do not free the + * memory... + */ +NPY_NO_EXPORT int +PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf) +{ +#if defined(NPY_PY3K) + Py_buffer view; +#else + Py_ssize_t buflen; +#endif + + buf->ptr = NULL; + buf->flags = NPY_ARRAY_BEHAVED; + buf->base = NULL; + if (obj == Py_None) { + return NPY_SUCCEED; + } + +#if defined(NPY_PY3K) + if (PyObject_GetBuffer(obj, &view, PyBUF_ANY_CONTIGUOUS|PyBUF_WRITABLE) != 0) { + PyErr_Clear(); + buf->flags &= ~NPY_ARRAY_WRITEABLE; + if (PyObject_GetBuffer(obj, &view, PyBUF_ANY_CONTIGUOUS) != 0) { + return NPY_FAIL; + } + } + + buf->ptr = view.buf; + buf->len = (npy_intp) view.len; + + /* + * XXX: PyObject_AsWriteBuffer does also this, but it is unsafe, as there is + * no strict guarantee that the buffer sticks around after being released. + */ + PyBuffer_Release(&view); + + /* Point to the base of the buffer object if present */ + if (PyMemoryView_Check(obj)) { + buf->base = PyMemoryView_GET_BASE(obj); + } +#else + if (PyObject_AsWriteBuffer(obj, &(buf->ptr), &buflen) < 0) { + PyErr_Clear(); + buf->flags &= ~NPY_ARRAY_WRITEABLE; + if (PyObject_AsReadBuffer(obj, (const void **)&(buf->ptr), + &buflen) < 0) { + return NPY_FAIL; + } + } + buf->len = (npy_intp) buflen; + + /* Point to the base of the buffer object if present */ + if (PyBuffer_Check(obj)) { + buf->base = ((PyArray_Chunk *)obj)->base; + } +#endif + if (buf->base == NULL) { + buf->base = obj; + } + return NPY_SUCCEED; +} + +/*NUMPY_API + * Get axis from an object (possibly None) -- a converter function, + * + * See also PyArray_ConvertMultiAxis, which also handles a tuple of axes. + */ +NPY_NO_EXPORT int +PyArray_AxisConverter(PyObject *obj, int *axis) +{ + if (obj == Py_None) { + *axis = NPY_MAXDIMS; + } + else { + *axis = PyArray_PyIntAsInt_ErrMsg(obj, + "an integer is required for the axis"); + if (error_converting(*axis)) { + return NPY_FAIL; + } + } + return NPY_SUCCEED; +} + +/* + * Converts an axis parameter into an ndim-length C-array of + * boolean flags, True for each axis specified. + * + * If obj is None or NULL, everything is set to True. If obj is a tuple, + * each axis within the tuple is set to True. If obj is an integer, + * just that axis is set to True. + */ +NPY_NO_EXPORT int +PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags) +{ + /* None means all of the axes */ + if (axis_in == Py_None || axis_in == NULL) { + memset(out_axis_flags, 1, ndim); + return NPY_SUCCEED; + } + /* A tuple of which axes */ + else if (PyTuple_Check(axis_in)) { + int i, naxes; + + memset(out_axis_flags, 0, ndim); + + naxes = PyTuple_Size(axis_in); + if (naxes < 0) { + return NPY_FAIL; + } + for (i = 0; i < naxes; ++i) { + PyObject *tmp = PyTuple_GET_ITEM(axis_in, i); + int axis = PyArray_PyIntAsInt_ErrMsg(tmp, + "integers are required for the axis tuple elements"); + if (error_converting(axis)) { + return NPY_FAIL; + } + if (check_and_adjust_axis(&axis, ndim) < 0) { + return NPY_FAIL; + } + if (out_axis_flags[axis]) { + PyErr_SetString(PyExc_ValueError, + "duplicate value in 'axis'"); + return NPY_FAIL; + } + out_axis_flags[axis] = 1; + } + + return NPY_SUCCEED; + } + /* Try to interpret axis as an integer */ + else { + int axis; + + memset(out_axis_flags, 0, ndim); + + axis = PyArray_PyIntAsInt_ErrMsg(axis_in, + "an integer is required for the axis"); + + if (error_converting(axis)) { + return NPY_FAIL; + } + /* + * Special case letting axis={-1,0} slip through for scalars, + * for backwards compatibility reasons. + */ + if (ndim == 0 && (axis == 0 || axis == -1)) { + return NPY_SUCCEED; + } + + if (check_and_adjust_axis(&axis, ndim) < 0) { + return NPY_FAIL; + } + + out_axis_flags[axis] = 1; + + return NPY_SUCCEED; + } +} + +/*NUMPY_API + * Convert an object to true / false + */ +NPY_NO_EXPORT int +PyArray_BoolConverter(PyObject *object, npy_bool *val) +{ + if (PyObject_IsTrue(object)) { + *val = NPY_TRUE; + } + else { + *val = NPY_FALSE; + } + if (PyErr_Occurred()) { + return NPY_FAIL; + } + return NPY_SUCCEED; +} + +/*NUMPY_API + * Convert object to endian + */ +NPY_NO_EXPORT int +PyArray_ByteorderConverter(PyObject *obj, char *endian) +{ + char *str; + PyObject *tmp = NULL; + + if (PyUnicode_Check(obj)) { + obj = tmp = PyUnicode_AsASCIIString(obj); + } + + *endian = NPY_SWAP; + str = PyBytes_AsString(obj); + if (!str) { + Py_XDECREF(tmp); + return NPY_FAIL; + } + if (strlen(str) < 1) { + PyErr_SetString(PyExc_ValueError, + "Byteorder string must be at least length 1"); + Py_XDECREF(tmp); + return NPY_FAIL; + } + *endian = str[0]; + if (str[0] != NPY_BIG && str[0] != NPY_LITTLE + && str[0] != NPY_NATIVE && str[0] != NPY_IGNORE) { + if (str[0] == 'b' || str[0] == 'B') { + *endian = NPY_BIG; + } + else if (str[0] == 'l' || str[0] == 'L') { + *endian = NPY_LITTLE; + } + else if (str[0] == 'n' || str[0] == 'N') { + *endian = NPY_NATIVE; + } + else if (str[0] == 'i' || str[0] == 'I') { + *endian = NPY_IGNORE; + } + else if (str[0] == 's' || str[0] == 'S') { + *endian = NPY_SWAP; + } + else { + PyErr_Format(PyExc_ValueError, + "%s is an unrecognized byteorder", + str); + Py_XDECREF(tmp); + return NPY_FAIL; + } + } + Py_XDECREF(tmp); + return NPY_SUCCEED; +} + +/*NUMPY_API + * Convert object to sort kind + */ +NPY_NO_EXPORT int +PyArray_SortkindConverter(PyObject *obj, NPY_SORTKIND *sortkind) +{ + char *str; + PyObject *tmp = NULL; + + if (PyUnicode_Check(obj)) { + obj = tmp = PyUnicode_AsASCIIString(obj); + if (obj == NULL) { + return NPY_FAIL; + } + } + + *sortkind = NPY_QUICKSORT; + str = PyBytes_AsString(obj); + if (!str) { + Py_XDECREF(tmp); + return NPY_FAIL; + } + if (strlen(str) < 1) { + PyErr_SetString(PyExc_ValueError, + "Sort kind string must be at least length 1"); + Py_XDECREF(tmp); + return NPY_FAIL; + } + if (str[0] == 'q' || str[0] == 'Q') { + *sortkind = NPY_QUICKSORT; + } + else if (str[0] == 'h' || str[0] == 'H') { + *sortkind = NPY_HEAPSORT; + } + else if (str[0] == 'm' || str[0] == 'M') { + *sortkind = NPY_MERGESORT; + } + else { + PyErr_Format(PyExc_ValueError, + "%s is an unrecognized kind of sort", + str); + Py_XDECREF(tmp); + return NPY_FAIL; + } + Py_XDECREF(tmp); + return NPY_SUCCEED; +} + +/*NUMPY_API + * Convert object to select kind + */ +NPY_NO_EXPORT int +PyArray_SelectkindConverter(PyObject *obj, NPY_SELECTKIND *selectkind) +{ + char *str; + PyObject *tmp = NULL; + + if (PyUnicode_Check(obj)) { + obj = tmp = PyUnicode_AsASCIIString(obj); + if (obj == NULL) { + return NPY_FAIL; + } + } + + *selectkind = NPY_INTROSELECT; + str = PyBytes_AsString(obj); + if (!str) { + Py_XDECREF(tmp); + return NPY_FAIL; + } + if (strlen(str) < 1) { + PyErr_SetString(PyExc_ValueError, + "Select kind string must be at least length 1"); + Py_XDECREF(tmp); + return NPY_FAIL; + } + if (strcmp(str, "introselect") == 0) { + *selectkind = NPY_INTROSELECT; + } + else { + PyErr_Format(PyExc_ValueError, + "%s is an unrecognized kind of select", + str); + Py_XDECREF(tmp); + return NPY_FAIL; + } + Py_XDECREF(tmp); + return NPY_SUCCEED; +} + +/*NUMPY_API + * Convert object to searchsorted side + */ +NPY_NO_EXPORT int +PyArray_SearchsideConverter(PyObject *obj, void *addr) +{ + NPY_SEARCHSIDE *side = (NPY_SEARCHSIDE *)addr; + char *str; + PyObject *tmp = NULL; + + if (PyUnicode_Check(obj)) { + obj = tmp = PyUnicode_AsASCIIString(obj); + } + + str = PyBytes_AsString(obj); + if (!str || strlen(str) < 1) { + PyErr_SetString(PyExc_ValueError, + "expected nonempty string for keyword 'side'"); + Py_XDECREF(tmp); + return NPY_FAIL; + } + + if (str[0] == 'l' || str[0] == 'L') { + *side = NPY_SEARCHLEFT; + } + else if (str[0] == 'r' || str[0] == 'R') { + *side = NPY_SEARCHRIGHT; + } + else { + PyErr_Format(PyExc_ValueError, + "'%s' is an invalid value for keyword 'side'", str); + Py_XDECREF(tmp); + return NPY_FAIL; + } + Py_XDECREF(tmp); + return NPY_SUCCEED; +} + +/*NUMPY_API + * Convert an object to FORTRAN / C / ANY / KEEP + */ +NPY_NO_EXPORT int +PyArray_OrderConverter(PyObject *object, NPY_ORDER *val) +{ + char *str; + /* Leave the desired default from the caller for NULL/Py_None */ + if (object == NULL || object == Py_None) { + return NPY_SUCCEED; + } + else if (PyUnicode_Check(object)) { + PyObject *tmp; + int ret; + tmp = PyUnicode_AsASCIIString(object); + if (tmp == NULL) { + PyErr_SetString(PyExc_ValueError, "Invalid unicode string passed in " + "for the array ordering. " + "Please pass in 'C', 'F', 'A' " + "or 'K' instead"); + return NPY_FAIL; + } + ret = PyArray_OrderConverter(tmp, val); + Py_DECREF(tmp); + return ret; + } + else if (!PyBytes_Check(object) || PyBytes_GET_SIZE(object) < 1) { + /* 2015-12-14, 1.11 */ + int ret = DEPRECATE("Non-string object detected for " + "the array ordering. Please pass " + "in 'C', 'F', 'A', or 'K' instead"); + + if (ret < 0) { + return -1; + } + + if (PyObject_IsTrue(object)) { + *val = NPY_FORTRANORDER; + } + else { + *val = NPY_CORDER; + } + if (PyErr_Occurred()) { + return NPY_FAIL; + } + return NPY_SUCCEED; + } + else { + str = PyBytes_AS_STRING(object); + if (strlen(str) != 1) { + /* 2015-12-14, 1.11 */ + int ret = DEPRECATE("Non length-one string passed " + "in for the array ordering. " + "Please pass in 'C', 'F', 'A', " + "or 'K' instead"); + + if (ret < 0) { + return -1; + } + } + + if (str[0] == 'C' || str[0] == 'c') { + *val = NPY_CORDER; + } + else if (str[0] == 'F' || str[0] == 'f') { + *val = NPY_FORTRANORDER; + } + else if (str[0] == 'A' || str[0] == 'a') { + *val = NPY_ANYORDER; + } + else if (str[0] == 'K' || str[0] == 'k') { + *val = NPY_KEEPORDER; + } + else { + PyErr_SetString(PyExc_TypeError, + "order not understood"); + return NPY_FAIL; + } + } + return NPY_SUCCEED; +} + +/*NUMPY_API + * Convert an object to NPY_RAISE / NPY_CLIP / NPY_WRAP + */ +NPY_NO_EXPORT int +PyArray_ClipmodeConverter(PyObject *object, NPY_CLIPMODE *val) +{ + if (object == NULL || object == Py_None) { + *val = NPY_RAISE; + } + else if (PyBytes_Check(object)) { + char *str; + str = PyBytes_AS_STRING(object); + if (str[0] == 'C' || str[0] == 'c') { + *val = NPY_CLIP; + } + else if (str[0] == 'W' || str[0] == 'w') { + *val = NPY_WRAP; + } + else if (str[0] == 'R' || str[0] == 'r') { + *val = NPY_RAISE; + } + else { + PyErr_SetString(PyExc_TypeError, + "clipmode not understood"); + return NPY_FAIL; + } + } + else if (PyUnicode_Check(object)) { + PyObject *tmp; + int ret; + tmp = PyUnicode_AsASCIIString(object); + if (tmp == NULL) { + return NPY_FAIL; + } + ret = PyArray_ClipmodeConverter(tmp, val); + Py_DECREF(tmp); + return ret; + } + else { + int number = PyArray_PyIntAsInt(object); + if (error_converting(number)) { + goto fail; + } + if (number <= (int) NPY_RAISE + && number >= (int) NPY_CLIP) { + *val = (NPY_CLIPMODE) number; + } + else { + goto fail; + } + } + return NPY_SUCCEED; + + fail: + PyErr_SetString(PyExc_TypeError, + "clipmode not understood"); + return NPY_FAIL; +} + +/*NUMPY_API + * Convert an object to an array of n NPY_CLIPMODE values. + * This is intended to be used in functions where a different mode + * could be applied to each axis, like in ravel_multi_index. + */ +NPY_NO_EXPORT int +PyArray_ConvertClipmodeSequence(PyObject *object, NPY_CLIPMODE *modes, int n) +{ + int i; + /* Get the clip mode(s) */ + if (object && (PyTuple_Check(object) || PyList_Check(object))) { + if (PySequence_Size(object) != n) { + PyErr_Format(PyExc_ValueError, + "list of clipmodes has wrong length (%d instead of %d)", + (int)PySequence_Size(object), n); + return NPY_FAIL; + } + + for (i = 0; i < n; ++i) { + PyObject *item = PySequence_GetItem(object, i); + if(item == NULL) { + return NPY_FAIL; + } + + if(PyArray_ClipmodeConverter(item, &modes[i]) != NPY_SUCCEED) { + Py_DECREF(item); + return NPY_FAIL; + } + + Py_DECREF(item); + } + } + else if (PyArray_ClipmodeConverter(object, &modes[0]) == NPY_SUCCEED) { + for (i = 1; i < n; ++i) { + modes[i] = modes[0]; + } + } + else { + return NPY_FAIL; + } + return NPY_SUCCEED; +} + +/*NUMPY_API + * Convert any Python object, *obj*, to an NPY_CASTING enum. + */ +NPY_NO_EXPORT int +PyArray_CastingConverter(PyObject *obj, NPY_CASTING *casting) +{ + char *str = NULL; + Py_ssize_t length = 0; + + if (PyUnicode_Check(obj)) { + PyObject *str_obj; + int ret; + str_obj = PyUnicode_AsASCIIString(obj); + if (str_obj == NULL) { + return 0; + } + ret = PyArray_CastingConverter(str_obj, casting); + Py_DECREF(str_obj); + return ret; + } + + if (PyBytes_AsStringAndSize(obj, &str, &length) < 0) { + return 0; + } + + if (length >= 2) switch (str[2]) { + case 0: + if (strcmp(str, "no") == 0) { + *casting = NPY_NO_CASTING; + return 1; + } + break; + case 'u': + if (strcmp(str, "equiv") == 0) { + *casting = NPY_EQUIV_CASTING; + return 1; + } + break; + case 'f': + if (strcmp(str, "safe") == 0) { + *casting = NPY_SAFE_CASTING; + return 1; + } + break; + case 'm': + if (strcmp(str, "same_kind") == 0) { + *casting = NPY_SAME_KIND_CASTING; + return 1; + } + break; + case 's': + if (strcmp(str, "unsafe") == 0) { + *casting = NPY_UNSAFE_CASTING; + return 1; + } + break; + } + + PyErr_SetString(PyExc_ValueError, + "casting must be one of 'no', 'equiv', 'safe', " + "'same_kind', or 'unsafe'"); + return 0; +} + +/***************************** +* Other conversion functions +*****************************/ + +static int +PyArray_PyIntAsInt_ErrMsg(PyObject *o, const char * msg) +{ + npy_intp long_value; + /* This assumes that NPY_SIZEOF_INTP >= NPY_SIZEOF_INT */ + long_value = PyArray_PyIntAsIntp_ErrMsg(o, msg); + +#if (NPY_SIZEOF_INTP > NPY_SIZEOF_INT) + if ((long_value < INT_MIN) || (long_value > INT_MAX)) { + PyErr_SetString(PyExc_ValueError, "integer won't fit into a C int"); + return -1; + } +#endif + return (int) long_value; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT int +PyArray_PyIntAsInt(PyObject *o) +{ + return PyArray_PyIntAsInt_ErrMsg(o, "an integer is required"); +} + +static npy_intp +PyArray_PyIntAsIntp_ErrMsg(PyObject *o, const char * msg) +{ +#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + long long long_value = -1; +#else + long long_value = -1; +#endif + PyObject *obj, *err; + + /* + * Be a bit stricter and not allow bools. + * np.bool_ is also disallowed as Boolean arrays do not currently + * support index. + */ + if (!o || PyBool_Check(o) || PyArray_IsScalar(o, Bool)) { + PyErr_SetString(PyExc_TypeError, msg); + return -1; + } + + /* + * Since it is the usual case, first check if o is an integer. This is + * an exact check, since otherwise __index__ is used. + */ +#if !defined(NPY_PY3K) + if (PyInt_CheckExact(o)) { + #if (NPY_SIZEOF_LONG <= NPY_SIZEOF_INTP) + /* No overflow is possible, so we can just return */ + return PyInt_AS_LONG(o); + #else + long_value = PyInt_AS_LONG(o); + goto overflow_check; + #endif + } + else +#endif + if (PyLong_CheckExact(o)) { +#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + long_value = PyLong_AsLongLong(o); +#else + long_value = PyLong_AsLong(o); +#endif + return (npy_intp)long_value; + } + + /* + * The most general case. PyNumber_Index(o) covers everything + * including arrays. In principle it may be possible to replace + * the whole function by PyIndex_AsSSize_t after deprecation. + */ + obj = PyNumber_Index(o); + if (obj == NULL) { + return -1; + } +#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + long_value = PyLong_AsLongLong(obj); +#else + long_value = PyLong_AsLong(obj); +#endif + Py_DECREF(obj); + + if (error_converting(long_value)) { + err = PyErr_Occurred(); + /* Only replace TypeError's here, which are the normal errors. */ + if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) { + PyErr_SetString(PyExc_TypeError, msg); + } + return -1; + } + goto overflow_check; /* silence unused warning */ + +overflow_check: +#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + #if (NPY_SIZEOF_LONGLONG > NPY_SIZEOF_INTP) + if ((long_value < NPY_MIN_INTP) || (long_value > NPY_MAX_INTP)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C numpy.intp"); + return -1; + } + #endif +#else + #if (NPY_SIZEOF_LONG > NPY_SIZEOF_INTP) + if ((long_value < NPY_MIN_INTP) || (long_value > NPY_MAX_INTP)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C numpy.intp"); + return -1; + } + #endif +#endif + return long_value; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT npy_intp +PyArray_PyIntAsIntp(PyObject *o) +{ + return PyArray_PyIntAsIntp_ErrMsg(o, "an integer is required"); +} + + +/* + * PyArray_IntpFromIndexSequence + * Returns the number of dimensions or -1 if an error occurred. + * vals must be large enough to hold maxvals. + * Opposed to PyArray_IntpFromSequence it uses and returns npy_intp + * for the number of values. + */ +NPY_NO_EXPORT npy_intp +PyArray_IntpFromIndexSequence(PyObject *seq, npy_intp *vals, npy_intp maxvals) +{ + Py_ssize_t nd; + npy_intp i; + PyObject *op, *err; + + /* + * Check to see if sequence is a single integer first. + * or, can be made into one + */ + nd = PySequence_Length(seq); + if (nd == -1) { + if (PyErr_Occurred()) { + PyErr_Clear(); + } + + vals[0] = PyArray_PyIntAsIntp(seq); + if(vals[0] == -1) { + err = PyErr_Occurred(); + if (err && + PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { + PyErr_SetString(PyExc_ValueError, + "Maximum allowed dimension exceeded"); + } + if(err != NULL) { + return -1; + } + } + nd = 1; + } + else { + for (i = 0; i < PyArray_MIN(nd,maxvals); i++) { + op = PySequence_GetItem(seq, i); + if (op == NULL) { + return -1; + } + + vals[i] = PyArray_PyIntAsIntp(op); + Py_DECREF(op); + if(vals[i] == -1) { + err = PyErr_Occurred(); + if (err && + PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { + PyErr_SetString(PyExc_ValueError, + "Maximum allowed dimension exceeded"); + } + if(err != NULL) { + return -1; + } + } + } + } + return nd; +} + +/*NUMPY_API + * PyArray_IntpFromSequence + * Returns the number of integers converted or -1 if an error occurred. + * vals must be large enough to hold maxvals + */ +NPY_NO_EXPORT int +PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals) +{ + return PyArray_IntpFromIndexSequence(seq, vals, (npy_intp)maxvals); +} + + +/** + * WARNING: This flag is a bad idea, but was the only way to both + * 1) Support unpickling legacy pickles with object types. + * 2) Deprecate (and later disable) usage of O4 and O8 + * + * The key problem is that the pickled representation unpickles by + * directly calling the dtype constructor, which has no way of knowing + * that it is in an unpickle context instead of a normal context without + * evil global state like we create here. + */ +NPY_NO_EXPORT int evil_global_disable_warn_O4O8_flag = 0; + +/*NUMPY_API + * Typestr converter + */ +NPY_NO_EXPORT int +PyArray_TypestrConvert(int itemsize, int gentype) +{ + int newtype = NPY_NOTYPE; + + switch (gentype) { + case NPY_GENBOOLLTR: + if (itemsize == 1) { + newtype = NPY_BOOL; + } + break; + + case NPY_SIGNEDLTR: + switch(itemsize) { + case 1: + newtype = NPY_INT8; + break; + case 2: + newtype = NPY_INT16; + break; + case 4: + newtype = NPY_INT32; + break; + case 8: + newtype = NPY_INT64; + break; +#ifdef NPY_INT128 + case 16: + newtype = NPY_INT128; + break; +#endif + } + break; + + case NPY_UNSIGNEDLTR: + switch(itemsize) { + case 1: + newtype = NPY_UINT8; + break; + case 2: + newtype = NPY_UINT16; + break; + case 4: + newtype = NPY_UINT32; + break; + case 8: + newtype = NPY_UINT64; + break; +#ifdef NPY_INT128 + case 16: + newtype = NPY_UINT128; + break; +#endif + } + break; + + case NPY_FLOATINGLTR: + switch(itemsize) { + case 2: + newtype = NPY_FLOAT16; + break; + case 4: + newtype = NPY_FLOAT32; + break; + case 8: + newtype = NPY_FLOAT64; + break; +#ifdef NPY_FLOAT80 + case 10: + newtype = NPY_FLOAT80; + break; +#endif +#ifdef NPY_FLOAT96 + case 12: + newtype = NPY_FLOAT96; + break; +#endif +#ifdef NPY_FLOAT128 + case 16: + newtype = NPY_FLOAT128; + break; +#endif + } + break; + + case NPY_COMPLEXLTR: + switch(itemsize) { + case 8: + newtype = NPY_COMPLEX64; + break; + case 16: + newtype = NPY_COMPLEX128; + break; +#ifdef NPY_FLOAT80 + case 20: + newtype = NPY_COMPLEX160; + break; +#endif +#ifdef NPY_FLOAT96 + case 24: + newtype = NPY_COMPLEX192; + break; +#endif +#ifdef NPY_FLOAT128 + case 32: + newtype = NPY_COMPLEX256; + break; +#endif + } + break; + + case NPY_OBJECTLTR: + /* + * For 'O4' and 'O8', let it pass, but raise a + * deprecation warning. For all other cases, raise + * an exception by leaving newtype unset. + */ + if (itemsize == 4 || itemsize == 8) { + int ret = 0; + if (evil_global_disable_warn_O4O8_flag) { + /* 2012-02-04, 1.7, not sure when this can be removed */ + ret = DEPRECATE("DType strings 'O4' and 'O8' are " + "deprecated because they are platform " + "specific. Use 'O' instead"); + } + + if (ret == 0) { + newtype = NPY_OBJECT; + } + } + break; + + case NPY_STRINGLTR: + case NPY_STRINGLTR2: + newtype = NPY_STRING; + break; + + case NPY_UNICODELTR: + newtype = NPY_UNICODE; + break; + + case NPY_VOIDLTR: + newtype = NPY_VOID; + break; + + case NPY_DATETIMELTR: + if (itemsize == 8) { + newtype = NPY_DATETIME; + } + break; + + case NPY_TIMEDELTALTR: + if (itemsize == 8) { + newtype = NPY_TIMEDELTA; + } + break; + } + + return newtype; +} + +/* Lifted from numarray */ +/* TODO: not documented */ +/*NUMPY_API + PyArray_IntTupleFromIntp +*/ +NPY_NO_EXPORT PyObject * +PyArray_IntTupleFromIntp(int len, npy_intp *vals) +{ + int i; + PyObject *intTuple = PyTuple_New(len); + + if (!intTuple) { + goto fail; + } + for (i = 0; i < len; i++) { +#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG + PyObject *o = PyInt_FromLong((long) vals[i]); +#else + PyObject *o = PyLong_FromLongLong((npy_longlong) vals[i]); +#endif + if (!o) { + Py_DECREF(intTuple); + intTuple = NULL; + goto fail; + } + PyTuple_SET_ITEM(intTuple, i, o); + } + + fail: + return intTuple; +} diff --git a/numpy/core/src/multiarray/conversion_utils.h b/numpy/core/src/multiarray/conversion_utils.h new file mode 100644 index 0000000..cd43f25 --- /dev/null +++ b/numpy/core/src/multiarray/conversion_utils.h @@ -0,0 +1,68 @@ +#ifndef _NPY_PRIVATE_CONVERSION_UTILS_H_ +#define _NPY_PRIVATE_CONVERSION_UTILS_H_ + +#include + +NPY_NO_EXPORT int +PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq); + +NPY_NO_EXPORT int +PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf); + +NPY_NO_EXPORT int +PyArray_BoolConverter(PyObject *object, npy_bool *val); + +NPY_NO_EXPORT int +PyArray_ByteorderConverter(PyObject *obj, char *endian); + +NPY_NO_EXPORT int +PyArray_SortkindConverter(PyObject *obj, NPY_SORTKIND *sortkind); + +NPY_NO_EXPORT int +PyArray_SearchsideConverter(PyObject *obj, void *addr); + +NPY_NO_EXPORT int +PyArray_PyIntAsInt(PyObject *o); + +NPY_NO_EXPORT npy_intp +PyArray_PyIntAsIntp(PyObject *o); + +NPY_NO_EXPORT npy_intp +PyArray_IntpFromIndexSequence(PyObject *seq, npy_intp *vals, npy_intp maxvals); + +NPY_NO_EXPORT int +PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals); + +NPY_NO_EXPORT int +PyArray_TypestrConvert(int itemsize, int gentype); + +NPY_NO_EXPORT PyObject * +PyArray_IntTupleFromIntp(int len, npy_intp *vals); + +NPY_NO_EXPORT int +PyArray_SelectkindConverter(PyObject *obj, NPY_SELECTKIND *selectkind); + +/* + * Converts an axis parameter into an ndim-length C-array of + * boolean flags, True for each axis specified. + * + * If obj is None, everything is set to True. If obj is a tuple, + * each axis within the tuple is set to True. If obj is an integer, + * just that axis is set to True. + */ +NPY_NO_EXPORT int +PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags); + +/** + * WARNING: This flag is a bad idea, but was the only way to both + * 1) Support unpickling legacy pickles with object types. + * 2) Deprecate (and later disable) usage of O4 and O8 + * + * The key problem is that the pickled representation unpickles by + * directly calling the dtype constructor, which has no way of knowing + * that it is in an unpickle context instead of a normal context without + * evil global state like we create here. + */ +extern NPY_NO_EXPORT int evil_global_disable_warn_O4O8_flag; + +#endif diff --git a/numpy/core/src/multiarray/convert.c b/numpy/core/src/multiarray/convert.c new file mode 100644 index 0000000..55a45f3 --- /dev/null +++ b/numpy/core/src/multiarray/convert.c @@ -0,0 +1,664 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "common.h" +#include "arrayobject.h" +#include "ctors.h" +#include "mapping.h" +#include "lowlevel_strided_loops.h" +#include "scalartypes.h" +#include "array_assign.h" + +#include "convert.h" + +int +fallocate(int fd, int mode, off_t offset, off_t len); + +/* + * allocate nbytes of diskspace for file fp + * this allows the filesystem to make smarter allocation decisions and gives a + * fast exit on not enough free space + * returns -1 and raises exception on no space, ignores all other errors + */ +static int +npy_fallocate(npy_intp nbytes, FILE * fp) +{ + /* + * unknown behavior on non-linux so don't try it + * we don't want explicit zeroing to happen + */ +#if defined(HAVE_FALLOCATE) && defined(__linux__) + int r; + /* small files not worth the system call */ + if (nbytes < 16 * 1024 * 1024) { + return 0; + } + + /* btrfs can take a while to allocate making release worthwhile */ + NPY_BEGIN_ALLOW_THREADS; + /* + * flush in case there might be some unexpected interactions between the + * fallocate call and unwritten data in the descriptor + */ + fflush(fp); + /* + * the flag "1" (=FALLOC_FL_KEEP_SIZE) is needed for the case of files + * opened in append mode (issue #8329) + */ + r = fallocate(fileno(fp), 1, npy_ftell(fp), nbytes); + NPY_END_ALLOW_THREADS; + + /* + * early exit on no space, other errors will also get found during fwrite + */ + if (r == -1 && errno == ENOSPC) { + PyErr_Format(PyExc_IOError, "Not enough free space to write " + "%"NPY_INTP_FMT" bytes", nbytes); + return -1; + } +#endif + return 0; +} + +/* + * Converts a subarray of 'self' into lists, with starting data pointer + * 'dataptr' and from dimension 'startdim' to the last dimension of 'self'. + * + * Returns a new reference. + */ +static PyObject * +recursive_tolist(PyArrayObject *self, char *dataptr, int startdim) +{ + npy_intp i, n, stride; + PyObject *ret, *item; + + /* Base case */ + if (startdim >= PyArray_NDIM(self)) { + return PyArray_GETITEM(self, dataptr); + } + + n = PyArray_DIM(self, startdim); + stride = PyArray_STRIDE(self, startdim); + + ret = PyList_New(n); + if (ret == NULL) { + return NULL; + } + + for (i = 0; i < n; ++i) { + item = recursive_tolist(self, dataptr, startdim+1); + if (item == NULL) { + Py_DECREF(ret); + return NULL; + } + PyList_SET_ITEM(ret, i, item); + + dataptr += stride; + } + + return ret; +} + +/*NUMPY_API + * To List + */ +NPY_NO_EXPORT PyObject * +PyArray_ToList(PyArrayObject *self) +{ + return recursive_tolist(self, PyArray_DATA(self), 0); +} + +/* XXX: FIXME --- add ordering argument to + Allow Fortran ordering on write + This will need the addition of a Fortran-order iterator. + */ + +/*NUMPY_API + To File +*/ +NPY_NO_EXPORT int +PyArray_ToFile(PyArrayObject *self, FILE *fp, char *sep, char *format) +{ + npy_intp size; + npy_intp n, n2; + size_t n3, n4; + PyArrayIterObject *it; + PyObject *obj, *strobj, *tupobj, *byteobj; + + n3 = (sep ? strlen((const char *)sep) : 0); + if (n3 == 0) { + /* binary data */ + if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_LIST_PICKLE)) { + PyErr_SetString(PyExc_IOError, + "cannot write object arrays to a file in binary mode"); + return -1; + } + if (PyArray_DESCR(self)->elsize == 0) { + /* For zero-width data types there's nothing to write */ + return 0; + } + if (npy_fallocate(PyArray_NBYTES(self), fp) != 0) { + return -1; + } + + if (PyArray_ISCONTIGUOUS(self)) { + size = PyArray_SIZE(self); + NPY_BEGIN_ALLOW_THREADS; + +#if defined (_MSC_VER) && defined(_WIN64) + /* Workaround Win64 fwrite() bug. Ticket #1660 */ + { + npy_intp maxsize = 2147483648 / PyArray_DESCR(self)->elsize; + npy_intp chunksize; + + n = 0; + while (size > 0) { + chunksize = (size > maxsize) ? maxsize : size; + n2 = fwrite((const void *) + ((char *)PyArray_DATA(self) + (n * PyArray_DESCR(self)->elsize)), + (size_t) PyArray_DESCR(self)->elsize, + (size_t) chunksize, fp); + if (n2 < chunksize) { + break; + } + n += n2; + size -= chunksize; + } + size = PyArray_SIZE(self); + } +#else + n = fwrite((const void *)PyArray_DATA(self), + (size_t) PyArray_DESCR(self)->elsize, + (size_t) size, fp); +#endif + NPY_END_ALLOW_THREADS; + if (n < size) { + PyErr_Format(PyExc_IOError, + "%ld requested and %ld written", + (long) size, (long) n); + return -1; + } + } + else { + NPY_BEGIN_THREADS_DEF; + + it = (PyArrayIterObject *) PyArray_IterNew((PyObject *)self); + NPY_BEGIN_THREADS; + while (it->index < it->size) { + if (fwrite((const void *)it->dataptr, + (size_t) PyArray_DESCR(self)->elsize, + 1, fp) < 1) { + NPY_END_THREADS; + PyErr_Format(PyExc_IOError, + "problem writing element %" NPY_INTP_FMT + " to file", it->index); + Py_DECREF(it); + return -1; + } + PyArray_ITER_NEXT(it); + } + NPY_END_THREADS; + Py_DECREF(it); + } + } + else { + /* + * text data + */ + + it = (PyArrayIterObject *) + PyArray_IterNew((PyObject *)self); + n4 = (format ? strlen((const char *)format) : 0); + while (it->index < it->size) { + obj = PyArray_GETITEM(self, it->dataptr); + if (obj == NULL) { + Py_DECREF(it); + return -1; + } + if (n4 == 0) { + /* + * standard writing + */ + strobj = PyObject_Repr(obj); + Py_DECREF(obj); + if (strobj == NULL) { + Py_DECREF(it); + return -1; + } + } + else { + /* + * use format string + */ + tupobj = PyTuple_New(1); + if (tupobj == NULL) { + Py_DECREF(it); + return -1; + } + PyTuple_SET_ITEM(tupobj,0,obj); + obj = PyUString_FromString((const char *)format); + if (obj == NULL) { + Py_DECREF(tupobj); + Py_DECREF(it); + return -1; + } + strobj = PyUString_Format(obj, tupobj); + Py_DECREF(obj); + Py_DECREF(tupobj); + if (strobj == NULL) { + Py_DECREF(it); + return -1; + } + } +#if defined(NPY_PY3K) + byteobj = PyUnicode_AsASCIIString(strobj); +#else + byteobj = strobj; +#endif + NPY_BEGIN_ALLOW_THREADS; + n2 = PyBytes_GET_SIZE(byteobj); + n = fwrite(PyBytes_AS_STRING(byteobj), 1, n2, fp); + NPY_END_ALLOW_THREADS; +#if defined(NPY_PY3K) + Py_DECREF(byteobj); +#endif + if (n < n2) { + PyErr_Format(PyExc_IOError, + "problem writing element %" NPY_INTP_FMT + " to file", it->index); + Py_DECREF(strobj); + Py_DECREF(it); + return -1; + } + /* write separator for all but last one */ + if (it->index != it->size-1) { + if (fwrite(sep, 1, n3, fp) < n3) { + PyErr_Format(PyExc_IOError, + "problem writing separator to file"); + Py_DECREF(strobj); + Py_DECREF(it); + return -1; + } + } + Py_DECREF(strobj); + PyArray_ITER_NEXT(it); + } + Py_DECREF(it); + } + return 0; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_ToString(PyArrayObject *self, NPY_ORDER order) +{ + npy_intp numbytes; + npy_intp i; + char *dptr; + int elsize; + PyObject *ret; + PyArrayIterObject *it; + + if (order == NPY_ANYORDER) + order = PyArray_ISFORTRAN(self); + + /* if (PyArray_TYPE(self) == NPY_OBJECT) { + PyErr_SetString(PyExc_ValueError, "a string for the data" \ + "in an object array is not appropriate"); + return NULL; + } + */ + + numbytes = PyArray_NBYTES(self); + if ((PyArray_IS_C_CONTIGUOUS(self) && (order == NPY_CORDER)) + || (PyArray_IS_F_CONTIGUOUS(self) && (order == NPY_FORTRANORDER))) { + ret = PyBytes_FromStringAndSize(PyArray_DATA(self), (Py_ssize_t) numbytes); + } + else { + PyObject *new; + if (order == NPY_FORTRANORDER) { + /* iterators are always in C-order */ + new = PyArray_Transpose(self, NULL); + if (new == NULL) { + return NULL; + } + } + else { + Py_INCREF(self); + new = (PyObject *)self; + } + it = (PyArrayIterObject *)PyArray_IterNew(new); + Py_DECREF(new); + if (it == NULL) { + return NULL; + } + ret = PyBytes_FromStringAndSize(NULL, (Py_ssize_t) numbytes); + if (ret == NULL) { + Py_DECREF(it); + return NULL; + } + dptr = PyBytes_AS_STRING(ret); + i = it->size; + elsize = PyArray_DESCR(self)->elsize; + while (i--) { + memcpy(dptr, it->dataptr, elsize); + dptr += elsize; + PyArray_ITER_NEXT(it); + } + Py_DECREF(it); + } + return ret; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT int +PyArray_FillWithScalar(PyArrayObject *arr, PyObject *obj) +{ + PyArray_Descr *dtype = NULL; + npy_longlong value_buffer[4]; + char *value = NULL; + int retcode = 0; + + /* + * If 'arr' is an object array, copy the object as is unless + * 'obj' is a zero-dimensional array, in which case we copy + * the element in that array instead. + */ + if (PyArray_DESCR(arr)->type_num == NPY_OBJECT && + !(PyArray_Check(obj) && + PyArray_NDIM((PyArrayObject *)obj) == 0)) { + value = (char *)&obj; + + dtype = PyArray_DescrFromType(NPY_OBJECT); + if (dtype == NULL) { + return -1; + } + } + /* NumPy scalar */ + else if (PyArray_IsScalar(obj, Generic)) { + dtype = PyArray_DescrFromScalar(obj); + if (dtype == NULL) { + return -1; + } + value = scalar_value(obj, dtype); + if (value == NULL) { + Py_DECREF(dtype); + return -1; + } + } + /* Python boolean */ + else if (PyBool_Check(obj)) { + value = (char *)value_buffer; + *value = (obj == Py_True); + + dtype = PyArray_DescrFromType(NPY_BOOL); + if (dtype == NULL) { + return -1; + } + } + /* Python integer */ + else if (PyLong_Check(obj) || PyInt_Check(obj)) { + /* Try long long before unsigned long long */ + npy_longlong ll_v = PyLong_AsLongLong(obj); + if (error_converting(ll_v)) { + /* Long long failed, try unsigned long long */ + npy_ulonglong ull_v; + PyErr_Clear(); + ull_v = PyLong_AsUnsignedLongLong(obj); + if (ull_v == (unsigned long long)-1 && PyErr_Occurred()) { + return -1; + } + value = (char *)value_buffer; + *(npy_ulonglong *)value = ull_v; + + dtype = PyArray_DescrFromType(NPY_ULONGLONG); + if (dtype == NULL) { + return -1; + } + } + else { + /* Long long succeeded */ + value = (char *)value_buffer; + *(npy_longlong *)value = ll_v; + + dtype = PyArray_DescrFromType(NPY_LONGLONG); + if (dtype == NULL) { + return -1; + } + } + } + /* Python float */ + else if (PyFloat_Check(obj)) { + npy_double v = PyFloat_AsDouble(obj); + if (error_converting(v)) { + return -1; + } + value = (char *)value_buffer; + *(npy_double *)value = v; + + dtype = PyArray_DescrFromType(NPY_DOUBLE); + if (dtype == NULL) { + return -1; + } + } + /* Python complex */ + else if (PyComplex_Check(obj)) { + npy_double re, im; + + re = PyComplex_RealAsDouble(obj); + if (error_converting(re)) { + return -1; + } + im = PyComplex_ImagAsDouble(obj); + if (error_converting(im)) { + return -1; + } + value = (char *)value_buffer; + ((npy_double *)value)[0] = re; + ((npy_double *)value)[1] = im; + + dtype = PyArray_DescrFromType(NPY_CDOUBLE); + if (dtype == NULL) { + return -1; + } + } + + /* Use the value pointer we got if possible */ + if (value != NULL) { + /* TODO: switch to SAME_KIND casting */ + retcode = PyArray_AssignRawScalar(arr, dtype, value, + NULL, NPY_UNSAFE_CASTING); + Py_DECREF(dtype); + return retcode; + } + /* Otherwise convert to an array to do the assignment */ + else { + PyArrayObject *src_arr; + + /** + * The dtype of the destination is used when converting + * from the pyobject, so that for example a tuple gets + * recognized as a struct scalar of the required type. + */ + Py_INCREF(PyArray_DTYPE(arr)); + src_arr = (PyArrayObject *)PyArray_FromAny(obj, + PyArray_DTYPE(arr), 0, 0, 0, NULL); + if (src_arr == NULL) { + return -1; + } + + if (PyArray_NDIM(src_arr) != 0) { + PyErr_SetString(PyExc_ValueError, + "Input object to FillWithScalar is not a scalar"); + Py_DECREF(src_arr); + return -1; + } + + retcode = PyArray_CopyInto(arr, src_arr); + + Py_DECREF(src_arr); + return retcode; + } +} + +/* + * Fills an array with zeros. + * + * dst: The destination array. + * wheremask: If non-NULL, a boolean mask specifying where to set the values. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_AssignZero(PyArrayObject *dst, + PyArrayObject *wheremask) +{ + npy_bool value; + PyArray_Descr *bool_dtype; + int retcode; + + /* Create a raw bool scalar with the value False */ + bool_dtype = PyArray_DescrFromType(NPY_BOOL); + if (bool_dtype == NULL) { + return -1; + } + value = 0; + + retcode = PyArray_AssignRawScalar(dst, bool_dtype, (char *)&value, + wheremask, NPY_SAFE_CASTING); + + Py_DECREF(bool_dtype); + return retcode; +} + +/* + * Fills an array with ones. + * + * dst: The destination array. + * wheremask: If non-NULL, a boolean mask specifying where to set the values. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_AssignOne(PyArrayObject *dst, + PyArrayObject *wheremask) +{ + npy_bool value; + PyArray_Descr *bool_dtype; + int retcode; + + /* Create a raw bool scalar with the value True */ + bool_dtype = PyArray_DescrFromType(NPY_BOOL); + if (bool_dtype == NULL) { + return -1; + } + value = 1; + + retcode = PyArray_AssignRawScalar(dst, bool_dtype, (char *)&value, + wheremask, NPY_SAFE_CASTING); + + Py_DECREF(bool_dtype); + return retcode; +} + +/*NUMPY_API + * Copy an array. + */ +NPY_NO_EXPORT PyObject * +PyArray_NewCopy(PyArrayObject *obj, NPY_ORDER order) +{ + PyArrayObject *ret; + + ret = (PyArrayObject *)PyArray_NewLikeArray(obj, order, NULL, 1); + if (ret == NULL) { + return NULL; + } + + if (PyArray_AssignArray(ret, obj, NULL, NPY_UNSAFE_CASTING) < 0) { + Py_DECREF(ret); + return NULL; + } + + return (PyObject *)ret; +} + +/*NUMPY_API + * View + * steals a reference to type -- accepts NULL + */ +NPY_NO_EXPORT PyObject * +PyArray_View(PyArrayObject *self, PyArray_Descr *type, PyTypeObject *pytype) +{ + PyArrayObject *ret = NULL; + PyArray_Descr *dtype; + PyTypeObject *subtype; + int flags; + + if (pytype) { + subtype = pytype; + } + else { + subtype = Py_TYPE(self); + } + + if (type != NULL && (PyArray_FLAGS(self) & NPY_ARRAY_WARN_ON_WRITE)) { + const char *msg = + "Numpy has detected that you may be viewing or writing to an array " + "returned by selecting multiple fields in a structured array. \n\n" + "This code may break in numpy 1.15 because this will return a view " + "instead of a copy -- see release notes for details."; + /* 2016-09-19, 1.12 */ + if (DEPRECATE_FUTUREWARNING(msg) < 0) { + return NULL; + } + /* Only warn once per array */ + PyArray_CLEARFLAGS(self, NPY_ARRAY_WARN_ON_WRITE); + } + + flags = PyArray_FLAGS(self); + + dtype = PyArray_DESCR(self); + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr_int(subtype, + dtype, + PyArray_NDIM(self), PyArray_DIMS(self), + PyArray_STRIDES(self), + PyArray_DATA(self), + flags, + (PyObject *)self, 0, 1); + if (ret == NULL) { + Py_XDECREF(type); + return NULL; + } + + /* Set the base object */ + Py_INCREF(self); + if (PyArray_SetBaseObject(ret, (PyObject *)self) < 0) { + Py_DECREF(ret); + Py_XDECREF(type); + return NULL; + } + + if (type != NULL) { + if (PyObject_SetAttrString((PyObject *)ret, "dtype", + (PyObject *)type) < 0) { + Py_DECREF(ret); + Py_DECREF(type); + return NULL; + } + Py_DECREF(type); + } + return (PyObject *)ret; +} diff --git a/numpy/core/src/multiarray/convert.h b/numpy/core/src/multiarray/convert.h new file mode 100644 index 0000000..96df197 --- /dev/null +++ b/numpy/core/src/multiarray/convert.h @@ -0,0 +1,8 @@ +#ifndef _NPY_ARRAYOBJECT_CONVERT_H_ +#define _NPY_ARRAYOBJECT_CONVERT_H_ + +NPY_NO_EXPORT int +PyArray_AssignZero(PyArrayObject *dst, + PyArrayObject *wheremask); + +#endif diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c new file mode 100644 index 0000000..9927ffb --- /dev/null +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -0,0 +1,2173 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" +#include "numpy/npy_math.h" + +#include "common.h" +#include "scalartypes.h" +#include "mapping.h" + +#include "convert_datatype.h" +#include "_datetime.h" +#include "datetime_strings.h" + + +/* + * Required length of string when converting from unsigned integer type. + * Array index is integer size in bytes. + * - 3 chars needed for cast to max value of 255 or 127 + * - 5 chars needed for cast to max value of 65535 or 32767 + * - 10 chars needed for cast to max value of 4294967295 or 2147483647 + * - 20 chars needed for cast to max value of 18446744073709551615 + * or 9223372036854775807 + */ +NPY_NO_EXPORT npy_intp REQUIRED_STR_LEN[] = {0, 3, 5, 10, 10, 20, 20, 20, 20}; + +/*NUMPY_API + * For backward compatibility + * + * Cast an array using typecode structure. + * steals reference to dtype --- cannot be NULL + * + * This function always makes a copy of arr, even if the dtype + * doesn't change. + */ +NPY_NO_EXPORT PyObject * +PyArray_CastToType(PyArrayObject *arr, PyArray_Descr *dtype, int is_f_order) +{ + PyObject *out; + + /* If the requested dtype is flexible, adapt it */ + PyArray_AdaptFlexibleDType((PyObject *)arr, PyArray_DESCR(arr), &dtype); + if (dtype == NULL) { + return NULL; + } + + out = PyArray_NewFromDescr(Py_TYPE(arr), dtype, + PyArray_NDIM(arr), + PyArray_DIMS(arr), + NULL, NULL, + is_f_order, + (PyObject *)arr); + + if (out == NULL) { + return NULL; + } + + if (PyArray_CopyInto((PyArrayObject *)out, arr) < 0) { + Py_DECREF(out); + return NULL; + } + + return out; +} + +/*NUMPY_API + * Get a cast function to cast from the input descriptor to the + * output type_number (must be a registered data-type). + * Returns NULL if un-successful. + */ +NPY_NO_EXPORT PyArray_VectorUnaryFunc * +PyArray_GetCastFunc(PyArray_Descr *descr, int type_num) +{ + PyArray_VectorUnaryFunc *castfunc = NULL; + + if (type_num < NPY_NTYPES_ABI_COMPATIBLE) { + castfunc = descr->f->cast[type_num]; + } + else { + PyObject *obj = descr->f->castdict; + if (obj && PyDict_Check(obj)) { + PyObject *key; + PyObject *cobj; + + key = PyInt_FromLong(type_num); + cobj = PyDict_GetItem(obj, key); + Py_DECREF(key); + if (cobj && NpyCapsule_Check(cobj)) { + castfunc = NpyCapsule_AsVoidPtr(cobj); + } + } + } + if (PyTypeNum_ISCOMPLEX(descr->type_num) && + !PyTypeNum_ISCOMPLEX(type_num) && + PyTypeNum_ISNUMBER(type_num) && + !PyTypeNum_ISBOOL(type_num)) { + PyObject *cls = NULL, *obj = NULL; + int ret; + obj = PyImport_ImportModule("numpy.core"); + + if (obj) { + cls = PyObject_GetAttrString(obj, "ComplexWarning"); + Py_DECREF(obj); + } + ret = PyErr_WarnEx(cls, + "Casting complex values to real discards " + "the imaginary part", 1); + Py_XDECREF(cls); + if (ret < 0) { + return NULL; + } + } + if (castfunc) { + return castfunc; + } + + PyErr_SetString(PyExc_ValueError, + "No cast function available."); + return NULL; +} + +/* + * This function calls Py_DECREF on flex_dtype, and replaces it with + * a new dtype that has been adapted based on the values in data_dtype + * and data_obj. If the flex_dtype is not flexible, it leaves it as is. + * + * Usually, if data_obj is not an array, dtype should be the result + * given by the PyArray_GetArrayParamsFromObject function. + * + * The data_obj may be NULL if just a dtype is is known for the source. + * + * If *flex_dtype is NULL, returns immediately, without setting an + * exception. This basically assumes an error was already set previously. + * + * The current flexible dtypes include NPY_STRING, NPY_UNICODE, NPY_VOID, + * and NPY_DATETIME with generic units. + */ +NPY_NO_EXPORT void +PyArray_AdaptFlexibleDType(PyObject *data_obj, PyArray_Descr *data_dtype, + PyArray_Descr **flex_dtype) +{ + PyArray_DatetimeMetaData *meta; + int flex_type_num; + PyArrayObject *arr = NULL; + PyArray_Descr *dtype = NULL; + int ndim = 0; + npy_intp dims[NPY_MAXDIMS]; + int result; + + if (*flex_dtype == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "NumPy AdaptFlexibleDType was called with NULL flex_dtype " + "but no error set"); + } + return; + } + + flex_type_num = (*flex_dtype)->type_num; + + /* Flexible types with expandable size */ + if (PyDataType_ISUNSIZED(*flex_dtype)) { + /* First replace the flex dtype */ + PyArray_DESCR_REPLACE(*flex_dtype); + if (*flex_dtype == NULL) { + return; + } + + if (data_dtype->type_num == flex_type_num || + flex_type_num == NPY_VOID) { + (*flex_dtype)->elsize = data_dtype->elsize; + } + else if (flex_type_num == NPY_STRING || flex_type_num == NPY_UNICODE) { + npy_intp size = 8; + + /* + * Get a string-size estimate of the input. These + * are generallly the size needed, rounded up to + * a multiple of eight. + */ + switch (data_dtype->type_num) { + case NPY_BOOL: + case NPY_UBYTE: + case NPY_BYTE: + case NPY_USHORT: + case NPY_SHORT: + case NPY_UINT: + case NPY_INT: + case NPY_ULONG: + case NPY_LONG: + case NPY_ULONGLONG: + case NPY_LONGLONG: + if (data_dtype->kind == 'b') { + /* 5 chars needed for cast to 'True' or 'False' */ + size = 5; + } + else if (data_dtype->elsize > 8 || + data_dtype->elsize < 0) { + /* + * Element size should never be greater than 8 or + * less than 0 for integer type, but just in case... + */ + break; + } + else if (data_dtype->kind == 'u') { + size = REQUIRED_STR_LEN[data_dtype->elsize]; + } + else if (data_dtype->kind == 'i') { + /* Add character for sign symbol */ + size = REQUIRED_STR_LEN[data_dtype->elsize] + 1; + } + break; + case NPY_HALF: + case NPY_FLOAT: + case NPY_DOUBLE: + case NPY_LONGDOUBLE: + size = 32; + break; + case NPY_CFLOAT: + case NPY_CDOUBLE: + case NPY_CLONGDOUBLE: + size = 64; + break; + case NPY_OBJECT: + size = 64; + if ((flex_type_num == NPY_STRING || + flex_type_num == NPY_UNICODE) && + data_obj != NULL) { + PyObject *list; + + if (PyArray_CheckScalar(data_obj)) { + list = PyArray_ToList((PyArrayObject *)data_obj); + if (list != NULL) { + PyObject *s = PyObject_Str(list); + if (s == NULL) { + Py_DECREF(list); + Py_DECREF(*flex_dtype); + *flex_dtype = NULL; + return; + } + else { + size = PyObject_Length(s); + Py_DECREF(s); + } + Py_DECREF(list); + } + } + else if (PyArray_Check(data_obj)) { + /* + * Convert data array to list of objects since + * GetArrayParamsFromObject won't iterate over + * array. + */ + list = PyArray_ToList((PyArrayObject *)data_obj); + result = PyArray_GetArrayParamsFromObject( + list, + *flex_dtype, + 0, &dtype, + &ndim, dims, &arr, NULL); + if (result == 0 && dtype != NULL) { + if (flex_type_num == NPY_UNICODE) { + size = dtype->elsize / 4; + } + else { + size = dtype->elsize; + } + } + Py_DECREF(list); + } + else if (PyArray_IsPythonScalar(data_obj)) { + PyObject *s = PyObject_Str(data_obj); + if (s == NULL) { + Py_DECREF(*flex_dtype); + *flex_dtype = NULL; + return; + } + else { + size = PyObject_Length(s); + Py_DECREF(s); + } + } + } + break; + case NPY_STRING: + case NPY_VOID: + size = data_dtype->elsize; + break; + case NPY_UNICODE: + size = data_dtype->elsize / 4; + break; + case NPY_DATETIME: + meta = get_datetime_metadata_from_dtype(data_dtype); + if (meta == NULL) { + Py_DECREF(*flex_dtype); + *flex_dtype = NULL; + return; + } + size = get_datetime_iso_8601_strlen(0, meta->base); + break; + case NPY_TIMEDELTA: + size = 21; + break; + } + + if (flex_type_num == NPY_STRING) { + (*flex_dtype)->elsize = size; + } + else if (flex_type_num == NPY_UNICODE) { + (*flex_dtype)->elsize = size * 4; + } + } + else { + /* + * We should never get here, but just in case someone adds + * a new flex dtype... + */ + PyErr_SetString(PyExc_TypeError, + "don't know how to adapt flex dtype"); + *flex_dtype = NULL; + return; + } + } + /* Flexible type with generic time unit that adapts */ + else if (flex_type_num == NPY_DATETIME || + flex_type_num == NPY_TIMEDELTA) { + meta = get_datetime_metadata_from_dtype(*flex_dtype); + if (meta == NULL) { + Py_DECREF(*flex_dtype); + *flex_dtype = NULL; + return; + } + + if (meta->base == NPY_FR_GENERIC) { + if (data_dtype->type_num == NPY_DATETIME || + data_dtype->type_num == NPY_TIMEDELTA) { + meta = get_datetime_metadata_from_dtype(data_dtype); + if (meta == NULL) { + Py_DECREF(*flex_dtype); + *flex_dtype = NULL; + return; + } + + Py_DECREF(*flex_dtype); + *flex_dtype = create_datetime_dtype(flex_type_num, meta); + } + else if (data_obj != NULL) { + /* Detect the unit from the input's data */ + Py_DECREF(*flex_dtype); + *flex_dtype = find_object_datetime_type(data_obj, + flex_type_num); + } + } + } +} + +/* + * Must be broadcastable. + * This code is very similar to PyArray_CopyInto/PyArray_MoveInto + * except casting is done --- NPY_BUFSIZE is used + * as the size of the casting buffer. + */ + +/*NUMPY_API + * Cast to an already created array. + */ +NPY_NO_EXPORT int +PyArray_CastTo(PyArrayObject *out, PyArrayObject *mp) +{ + /* CopyInto handles the casting now */ + return PyArray_CopyInto(out, mp); +} + +/*NUMPY_API + * Cast to an already created array. Arrays don't have to be "broadcastable" + * Only requirement is they have the same number of elements. + */ +NPY_NO_EXPORT int +PyArray_CastAnyTo(PyArrayObject *out, PyArrayObject *mp) +{ + /* CopyAnyInto handles the casting now */ + return PyArray_CopyAnyInto(out, mp); +} + +/*NUMPY_API + *Check the type coercion rules. + */ +NPY_NO_EXPORT int +PyArray_CanCastSafely(int fromtype, int totype) +{ + PyArray_Descr *from; + + /* Fast table lookup for small type numbers */ + if ((unsigned int)fromtype < NPY_NTYPES && + (unsigned int)totype < NPY_NTYPES) { + return _npy_can_cast_safely_table[fromtype][totype]; + } + + /* Identity */ + if (fromtype == totype) { + return 1; + } + /* Special-cases for some types */ + switch (fromtype) { + case NPY_DATETIME: + case NPY_TIMEDELTA: + case NPY_OBJECT: + case NPY_VOID: + return 0; + case NPY_BOOL: + return 1; + } + switch (totype) { + case NPY_BOOL: + case NPY_DATETIME: + case NPY_TIMEDELTA: + return 0; + case NPY_OBJECT: + case NPY_VOID: + return 1; + } + + from = PyArray_DescrFromType(fromtype); + /* + * cancastto is a NPY_NOTYPE terminated C-int-array of types that + * the data-type can be cast to safely. + */ + if (from->f->cancastto) { + int *curtype = from->f->cancastto; + + while (*curtype != NPY_NOTYPE) { + if (*curtype++ == totype) { + return 1; + } + } + } + return 0; +} + +/*NUMPY_API + * leaves reference count alone --- cannot be NULL + * + * PyArray_CanCastTypeTo is equivalent to this, but adds a 'casting' + * parameter. + */ +NPY_NO_EXPORT npy_bool +PyArray_CanCastTo(PyArray_Descr *from, PyArray_Descr *to) +{ + int from_type_num = from->type_num; + int to_type_num = to->type_num; + npy_bool ret; + + ret = (npy_bool) PyArray_CanCastSafely(from_type_num, to_type_num); + if (ret) { + /* Check String and Unicode more closely */ + if (from_type_num == NPY_STRING) { + if (to_type_num == NPY_STRING) { + ret = (from->elsize <= to->elsize); + } + else if (to_type_num == NPY_UNICODE) { + ret = (from->elsize << 2 <= to->elsize); + } + } + else if (from_type_num == NPY_UNICODE) { + if (to_type_num == NPY_UNICODE) { + ret = (from->elsize <= to->elsize); + } + } + /* + * For datetime/timedelta, only treat casts moving towards + * more precision as safe. + */ + else if (from_type_num == NPY_DATETIME && to_type_num == NPY_DATETIME) { + PyArray_DatetimeMetaData *meta1, *meta2; + meta1 = get_datetime_metadata_from_dtype(from); + if (meta1 == NULL) { + PyErr_Clear(); + return 0; + } + meta2 = get_datetime_metadata_from_dtype(to); + if (meta2 == NULL) { + PyErr_Clear(); + return 0; + } + + return can_cast_datetime64_metadata(meta1, meta2, + NPY_SAFE_CASTING); + } + else if (from_type_num == NPY_TIMEDELTA && + to_type_num == NPY_TIMEDELTA) { + PyArray_DatetimeMetaData *meta1, *meta2; + meta1 = get_datetime_metadata_from_dtype(from); + if (meta1 == NULL) { + PyErr_Clear(); + return 0; + } + meta2 = get_datetime_metadata_from_dtype(to); + if (meta2 == NULL) { + PyErr_Clear(); + return 0; + } + + return can_cast_timedelta64_metadata(meta1, meta2, + NPY_SAFE_CASTING); + } + /* + * If to_type_num is STRING or unicode + * see if the length is long enough to hold the + * stringified value of the object. + */ + else if (to_type_num == NPY_STRING || to_type_num == NPY_UNICODE) { + /* + * Boolean value cast to string type is 5 characters max + * for string 'False'. + */ + int char_size = 1; + if (to_type_num == NPY_UNICODE) { + char_size = 4; + } + + ret = 0; + if (PyDataType_ISUNSIZED(to)) { + ret = 1; + } + /* + * Need at least 5 characters to convert from boolean + * to 'True' or 'False'. + */ + else if (from->kind == 'b' && to->elsize >= 5 * char_size) { + ret = 1; + } + else if (from->kind == 'u') { + /* Guard against unexpected integer size */ + if (from->elsize > 8 || from->elsize < 0) { + ret = 0; + } + else if (to->elsize >= + REQUIRED_STR_LEN[from->elsize] * char_size) { + ret = 1; + } + } + else if (from->kind == 'i') { + /* Guard against unexpected integer size */ + if (from->elsize > 8 || from->elsize < 0) { + ret = 0; + } + /* Extra character needed for sign */ + else if (to->elsize >= + (REQUIRED_STR_LEN[from->elsize] + 1) * char_size) { + ret = 1; + } + } + } + } + return ret; +} + +/* Provides an ordering for the dtype 'kind' character codes */ +static int +dtype_kind_to_ordering(char kind) +{ + switch (kind) { + /* Boolean kind */ + case 'b': + return 0; + /* Unsigned int kind */ + case 'u': + return 1; + /* Signed int kind */ + case 'i': + return 2; + /* Float kind */ + case 'f': + return 4; + /* Complex kind */ + case 'c': + return 5; + /* String kind */ + case 'S': + case 'a': + return 6; + /* Unicode kind */ + case 'U': + return 7; + /* Void kind */ + case 'V': + return 8; + /* Object kind */ + case 'O': + return 9; + /* + * Anything else, like datetime, is special cased to + * not fit in this hierarchy + */ + default: + return -1; + } +} + +/* Converts a type number from unsigned to signed */ +static int +type_num_unsigned_to_signed(int type_num) +{ + switch (type_num) { + case NPY_UBYTE: + return NPY_BYTE; + case NPY_USHORT: + return NPY_SHORT; + case NPY_UINT: + return NPY_INT; + case NPY_ULONG: + return NPY_LONG; + case NPY_ULONGLONG: + return NPY_LONGLONG; + default: + return type_num; + } +} + +/* + * Compare two field dictionaries for castability. + * + * Return 1 if 'field1' can be cast to 'field2' according to the rule + * 'casting', 0 if not. + * + * Castabiliy of field dictionaries is defined recursively: 'field1' and + * 'field2' must have the same field names (possibly in different + * orders), and the corresponding field types must be castable according + * to the given casting rule. + */ +static int +can_cast_fields(PyObject *field1, PyObject *field2, NPY_CASTING casting) +{ + Py_ssize_t ppos; + PyObject *key; + PyObject *tuple1, *tuple2; + + if (field1 == field2) { + return 1; + } + if (field1 == NULL || field2 == NULL) { + return 0; + } + if (PyDict_Size(field1) != PyDict_Size(field2)) { + return 0; + } + + /* Iterate over all the fields and compare for castability */ + ppos = 0; + while (PyDict_Next(field1, &ppos, &key, &tuple1)) { + if ((tuple2 = PyDict_GetItem(field2, key)) == NULL) { + return 0; + } + /* Compare the dtype of the field for castability */ + if (!PyArray_CanCastTypeTo( + (PyArray_Descr *)PyTuple_GET_ITEM(tuple1, 0), + (PyArray_Descr *)PyTuple_GET_ITEM(tuple2, 0), + casting)) { + return 0; + } + } + + return 1; +} + +/*NUMPY_API + * Returns true if data of type 'from' may be cast to data of type + * 'to' according to the rule 'casting'. + */ +NPY_NO_EXPORT npy_bool +PyArray_CanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to, + NPY_CASTING casting) +{ + /* Fast path for unsafe casts or basic types */ + if (casting == NPY_UNSAFE_CASTING || + (NPY_LIKELY(from->type_num < NPY_OBJECT) && + NPY_LIKELY(from->type_num == to->type_num) && + NPY_LIKELY(from->byteorder == to->byteorder))) { + return 1; + } + /* Equivalent types can be cast with any value of 'casting' */ + else if (PyArray_EquivTypenums(from->type_num, to->type_num)) { + /* For complicated case, use EquivTypes (for now) */ + if (PyTypeNum_ISUSERDEF(from->type_num) || + from->subarray != NULL) { + int ret; + + /* Only NPY_NO_CASTING prevents byte order conversion */ + if ((casting != NPY_NO_CASTING) && + (!PyArray_ISNBO(from->byteorder) || + !PyArray_ISNBO(to->byteorder))) { + PyArray_Descr *nbo_from, *nbo_to; + + nbo_from = PyArray_DescrNewByteorder(from, NPY_NATIVE); + nbo_to = PyArray_DescrNewByteorder(to, NPY_NATIVE); + if (nbo_from == NULL || nbo_to == NULL) { + Py_XDECREF(nbo_from); + Py_XDECREF(nbo_to); + PyErr_Clear(); + return 0; + } + ret = PyArray_EquivTypes(nbo_from, nbo_to); + Py_DECREF(nbo_from); + Py_DECREF(nbo_to); + } + else { + ret = PyArray_EquivTypes(from, to); + } + return ret; + } + + if (PyDataType_HASFIELDS(from)) { + switch (casting) { + case NPY_EQUIV_CASTING: + case NPY_SAFE_CASTING: + case NPY_SAME_KIND_CASTING: + /* + * `from' and `to' must have the same fields, and + * corresponding fields must be (recursively) castable. + */ + return can_cast_fields(from->fields, to->fields, casting); + + case NPY_NO_CASTING: + default: + return PyArray_EquivTypes(from, to); + } + } + + switch (from->type_num) { + case NPY_DATETIME: { + PyArray_DatetimeMetaData *meta1, *meta2; + meta1 = get_datetime_metadata_from_dtype(from); + if (meta1 == NULL) { + PyErr_Clear(); + return 0; + } + meta2 = get_datetime_metadata_from_dtype(to); + if (meta2 == NULL) { + PyErr_Clear(); + return 0; + } + + if (casting == NPY_NO_CASTING) { + return PyArray_ISNBO(from->byteorder) == + PyArray_ISNBO(to->byteorder) && + can_cast_datetime64_metadata(meta1, meta2, casting); + } + else { + return can_cast_datetime64_metadata(meta1, meta2, casting); + } + } + case NPY_TIMEDELTA: { + PyArray_DatetimeMetaData *meta1, *meta2; + meta1 = get_datetime_metadata_from_dtype(from); + if (meta1 == NULL) { + PyErr_Clear(); + return 0; + } + meta2 = get_datetime_metadata_from_dtype(to); + if (meta2 == NULL) { + PyErr_Clear(); + return 0; + } + + if (casting == NPY_NO_CASTING) { + return PyArray_ISNBO(from->byteorder) == + PyArray_ISNBO(to->byteorder) && + can_cast_timedelta64_metadata(meta1, meta2, casting); + } + else { + return can_cast_timedelta64_metadata(meta1, meta2, casting); + } + } + default: + switch (casting) { + case NPY_NO_CASTING: + return PyArray_EquivTypes(from, to); + case NPY_EQUIV_CASTING: + return (from->elsize == to->elsize); + case NPY_SAFE_CASTING: + return (from->elsize <= to->elsize); + default: + return 1; + } + break; + } + } + /* If safe or same-kind casts are allowed */ + else if (casting == NPY_SAFE_CASTING || casting == NPY_SAME_KIND_CASTING) { + if (PyArray_CanCastTo(from, to)) { + return 1; + } + else if(casting == NPY_SAME_KIND_CASTING) { + /* + * Also allow casting from lower to higher kinds, according + * to the ordering provided by dtype_kind_to_ordering. + * Some kinds, like datetime, don't fit in the hierarchy, + * and are special cased as -1. + */ + int from_order, to_order; + + from_order = dtype_kind_to_ordering(from->kind); + to_order = dtype_kind_to_ordering(to->kind); + + return from_order != -1 && from_order <= to_order; + } + else { + return 0; + } + } + /* NPY_NO_CASTING or NPY_EQUIV_CASTING was specified */ + else { + return 0; + } +} + +/* CanCastArrayTo needs this function */ +static int min_scalar_type_num(char *valueptr, int type_num, + int *is_small_unsigned); + +NPY_NO_EXPORT npy_bool +can_cast_scalar_to(PyArray_Descr *scal_type, char *scal_data, + PyArray_Descr *to, NPY_CASTING casting) +{ + int swap; + int is_small_unsigned = 0, type_num; + npy_bool ret; + PyArray_Descr *dtype; + + /* An aligned memory buffer large enough to hold any type */ + npy_longlong value[4]; + + /* + * If the two dtypes are actually references to the same object + * or if casting type is forced unsafe then always OK. + */ + if (scal_type == to || casting == NPY_UNSAFE_CASTING ) { + return 1; + } + + /* + * If the scalar isn't a number, or the rule is stricter than + * NPY_SAFE_CASTING, use the straight type-based rules + */ + if (!PyTypeNum_ISNUMBER(scal_type->type_num) || + casting < NPY_SAFE_CASTING) { + return PyArray_CanCastTypeTo(scal_type, to, casting); + } + + swap = !PyArray_ISNBO(scal_type->byteorder); + scal_type->f->copyswap(&value, scal_data, swap, NULL); + + type_num = min_scalar_type_num((char *)&value, scal_type->type_num, + &is_small_unsigned); + + /* + * If we've got a small unsigned scalar, and the 'to' type + * is not unsigned, then make it signed to allow the value + * to be cast more appropriately. + */ + if (is_small_unsigned && !(PyTypeNum_ISUNSIGNED(to->type_num))) { + type_num = type_num_unsigned_to_signed(type_num); + } + + dtype = PyArray_DescrFromType(type_num); + if (dtype == NULL) { + return 0; + } +#if 0 + printf("min scalar cast "); + PyObject_Print(dtype, stdout, 0); + printf(" to "); + PyObject_Print(to, stdout, 0); + printf("\n"); +#endif + ret = PyArray_CanCastTypeTo(dtype, to, casting); + Py_DECREF(dtype); + return ret; +} + +/*NUMPY_API + * Returns 1 if the array object may be cast to the given data type using + * the casting rule, 0 otherwise. This differs from PyArray_CanCastTo in + * that it handles scalar arrays (0 dimensions) specially, by checking + * their value. + */ +NPY_NO_EXPORT npy_bool +PyArray_CanCastArrayTo(PyArrayObject *arr, PyArray_Descr *to, + NPY_CASTING casting) +{ + PyArray_Descr *from = PyArray_DESCR(arr); + + /* If it's a scalar, check the value */ + if (PyArray_NDIM(arr) == 0 && !PyArray_HASFIELDS(arr)) { + return can_cast_scalar_to(from, PyArray_DATA(arr), to, casting); + } + + /* Otherwise, use the standard rules */ + return PyArray_CanCastTypeTo(from, to, casting); +} + +/*NUMPY_API + * See if array scalars can be cast. + * + * TODO: For NumPy 2.0, add a NPY_CASTING parameter. + */ +NPY_NO_EXPORT npy_bool +PyArray_CanCastScalar(PyTypeObject *from, PyTypeObject *to) +{ + int fromtype; + int totype; + + fromtype = _typenum_fromtypeobj((PyObject *)from, 0); + totype = _typenum_fromtypeobj((PyObject *)to, 0); + if (fromtype == NPY_NOTYPE || totype == NPY_NOTYPE) { + return NPY_FALSE; + } + return (npy_bool) PyArray_CanCastSafely(fromtype, totype); +} + +/* + * Internal promote types function which handles unsigned integers which + * fit in same-sized signed integers specially. + */ +static PyArray_Descr * +promote_types(PyArray_Descr *type1, PyArray_Descr *type2, + int is_small_unsigned1, int is_small_unsigned2) +{ + if (is_small_unsigned1) { + int type_num1 = type1->type_num; + int type_num2 = type2->type_num; + int ret_type_num; + + if (type_num2 < NPY_NTYPES && !(PyTypeNum_ISBOOL(type_num2) || + PyTypeNum_ISUNSIGNED(type_num2))) { + /* Convert to the equivalent-sized signed integer */ + type_num1 = type_num_unsigned_to_signed(type_num1); + + ret_type_num = _npy_type_promotion_table[type_num1][type_num2]; + /* The table doesn't handle string/unicode/void, check the result */ + if (ret_type_num >= 0) { + return PyArray_DescrFromType(ret_type_num); + } + } + + return PyArray_PromoteTypes(type1, type2); + } + else if (is_small_unsigned2) { + int type_num1 = type1->type_num; + int type_num2 = type2->type_num; + int ret_type_num; + + if (type_num1 < NPY_NTYPES && !(PyTypeNum_ISBOOL(type_num1) || + PyTypeNum_ISUNSIGNED(type_num1))) { + /* Convert to the equivalent-sized signed integer */ + type_num2 = type_num_unsigned_to_signed(type_num2); + + ret_type_num = _npy_type_promotion_table[type_num1][type_num2]; + /* The table doesn't handle string/unicode/void, check the result */ + if (ret_type_num >= 0) { + return PyArray_DescrFromType(ret_type_num); + } + } + + return PyArray_PromoteTypes(type1, type2); + } + else { + return PyArray_PromoteTypes(type1, type2); + } + +} + +/* + * Returns a new reference to type if it is already NBO, otherwise + * returns a copy converted to NBO. + */ +static PyArray_Descr * +ensure_dtype_nbo(PyArray_Descr *type) +{ + if (PyArray_ISNBO(type->byteorder)) { + Py_INCREF(type); + return type; + } + else { + return PyArray_DescrNewByteorder(type, NPY_NATIVE); + } +} + +/*NUMPY_API + * Produces the smallest size and lowest kind type to which both + * input types can be cast. + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_PromoteTypes(PyArray_Descr *type1, PyArray_Descr *type2) +{ + int type_num1, type_num2, ret_type_num; + + type_num1 = type1->type_num; + type_num2 = type2->type_num; + + /* If they're built-in types, use the promotion table */ + if (type_num1 < NPY_NTYPES && type_num2 < NPY_NTYPES) { + ret_type_num = _npy_type_promotion_table[type_num1][type_num2]; + /* + * The table doesn't handle string/unicode/void/datetime/timedelta, + * so check the result + */ + if (ret_type_num >= 0) { + return PyArray_DescrFromType(ret_type_num); + } + } + /* If one or both are user defined, calculate it */ + else { + int skind1 = NPY_NOSCALAR, skind2 = NPY_NOSCALAR, skind; + + if (PyArray_CanCastTo(type2, type1)) { + /* Promoted types are always native byte order */ + return ensure_dtype_nbo(type1); + } + else if (PyArray_CanCastTo(type1, type2)) { + /* Promoted types are always native byte order */ + return ensure_dtype_nbo(type2); + } + + /* Convert the 'kind' char into a scalar kind */ + switch (type1->kind) { + case 'b': + skind1 = NPY_BOOL_SCALAR; + break; + case 'u': + skind1 = NPY_INTPOS_SCALAR; + break; + case 'i': + skind1 = NPY_INTNEG_SCALAR; + break; + case 'f': + skind1 = NPY_FLOAT_SCALAR; + break; + case 'c': + skind1 = NPY_COMPLEX_SCALAR; + break; + } + switch (type2->kind) { + case 'b': + skind2 = NPY_BOOL_SCALAR; + break; + case 'u': + skind2 = NPY_INTPOS_SCALAR; + break; + case 'i': + skind2 = NPY_INTNEG_SCALAR; + break; + case 'f': + skind2 = NPY_FLOAT_SCALAR; + break; + case 'c': + skind2 = NPY_COMPLEX_SCALAR; + break; + } + + /* If both are scalars, there may be a promotion possible */ + if (skind1 != NPY_NOSCALAR && skind2 != NPY_NOSCALAR) { + + /* Start with the larger scalar kind */ + skind = (skind1 > skind2) ? skind1 : skind2; + ret_type_num = _npy_smallest_type_of_kind_table[skind]; + + for (;;) { + + /* If there is no larger type of this kind, try a larger kind */ + if (ret_type_num < 0) { + ++skind; + /* Use -1 to signal no promoted type found */ + if (skind < NPY_NSCALARKINDS) { + ret_type_num = _npy_smallest_type_of_kind_table[skind]; + } + else { + break; + } + } + + /* If we found a type to which we can promote both, done! */ + if (PyArray_CanCastSafely(type_num1, ret_type_num) && + PyArray_CanCastSafely(type_num2, ret_type_num)) { + return PyArray_DescrFromType(ret_type_num); + } + + /* Try the next larger type of this kind */ + ret_type_num = _npy_next_larger_type_table[ret_type_num]; + } + + } + + PyErr_SetString(PyExc_TypeError, + "invalid type promotion with custom data type"); + return NULL; + } + + switch (type_num1) { + /* BOOL can convert to anything except datetime/void */ + case NPY_BOOL: + if (type_num2 == NPY_STRING || type_num2 == NPY_UNICODE) { + int char_size = 1; + if (type_num2 == NPY_UNICODE) { + char_size = 4; + } + if (type2->elsize < 5 * char_size) { + PyArray_Descr *ret = NULL; + PyArray_Descr *temp = PyArray_DescrNew(type2); + ret = ensure_dtype_nbo(temp); + ret->elsize = 5 * char_size; + Py_DECREF(temp); + return ret; + } + return ensure_dtype_nbo(type2); + } + else if (type_num2 != NPY_DATETIME && type_num2 != NPY_VOID) { + return ensure_dtype_nbo(type2); + } + break; + /* For strings and unicodes, take the larger size */ + case NPY_STRING: + if (type_num2 == NPY_STRING) { + if (type1->elsize > type2->elsize) { + return ensure_dtype_nbo(type1); + } + else { + return ensure_dtype_nbo(type2); + } + } + else if (type_num2 == NPY_UNICODE) { + if (type2->elsize >= type1->elsize * 4) { + return ensure_dtype_nbo(type2); + } + else { + PyArray_Descr *d = PyArray_DescrNewFromType(NPY_UNICODE); + if (d == NULL) { + return NULL; + } + d->elsize = type1->elsize * 4; + return d; + } + } + /* Allow NUMBER -> STRING */ + else if (PyTypeNum_ISNUMBER(type_num2)) { + PyArray_Descr *ret = NULL; + PyArray_Descr *temp = PyArray_DescrNew(type1); + PyDataType_MAKEUNSIZED(temp); + PyArray_AdaptFlexibleDType(NULL, type2, &temp); + if (temp->elsize > type1->elsize) { + ret = ensure_dtype_nbo(temp); + } + else { + ret = ensure_dtype_nbo(type1); + } + Py_DECREF(temp); + return ret; + } + break; + case NPY_UNICODE: + if (type_num2 == NPY_UNICODE) { + if (type1->elsize > type2->elsize) { + return ensure_dtype_nbo(type1); + } + else { + return ensure_dtype_nbo(type2); + } + } + else if (type_num2 == NPY_STRING) { + if (type1->elsize >= type2->elsize * 4) { + return ensure_dtype_nbo(type1); + } + else { + PyArray_Descr *d = PyArray_DescrNewFromType(NPY_UNICODE); + if (d == NULL) { + return NULL; + } + d->elsize = type2->elsize * 4; + return d; + } + } + /* Allow NUMBER -> UNICODE */ + else if (PyTypeNum_ISNUMBER(type_num2)) { + PyArray_Descr *ret = NULL; + PyArray_Descr *temp = PyArray_DescrNew(type1); + PyDataType_MAKEUNSIZED(temp); + PyArray_AdaptFlexibleDType(NULL, type2, &temp); + if (temp->elsize > type1->elsize) { + ret = ensure_dtype_nbo(temp); + } + else { + ret = ensure_dtype_nbo(type1); + } + Py_DECREF(temp); + return ret; + } + break; + case NPY_DATETIME: + case NPY_TIMEDELTA: + if (type_num2 == NPY_DATETIME || type_num2 == NPY_TIMEDELTA) { + return datetime_type_promotion(type1, type2); + } + break; + } + + switch (type_num2) { + /* BOOL can convert to almost anything */ + case NPY_BOOL: + if (type_num2 == NPY_STRING || type_num2 == NPY_UNICODE) { + int char_size = 1; + if (type_num2 == NPY_UNICODE) { + char_size = 4; + } + if (type2->elsize < 5 * char_size) { + PyArray_Descr *ret = NULL; + PyArray_Descr *temp = PyArray_DescrNew(type2); + ret = ensure_dtype_nbo(temp); + ret->elsize = 5 * char_size; + Py_DECREF(temp); + return ret; + } + return ensure_dtype_nbo(type2); + } + else if (type_num1 != NPY_DATETIME && type_num1 != NPY_TIMEDELTA && + type_num1 != NPY_VOID) { + return ensure_dtype_nbo(type1); + } + break; + case NPY_STRING: + /* Allow NUMBER -> STRING */ + if (PyTypeNum_ISNUMBER(type_num1)) { + PyArray_Descr *ret = NULL; + PyArray_Descr *temp = PyArray_DescrNew(type2); + PyDataType_MAKEUNSIZED(temp); + PyArray_AdaptFlexibleDType(NULL, type1, &temp); + if (temp->elsize > type2->elsize) { + ret = ensure_dtype_nbo(temp); + } + else { + ret = ensure_dtype_nbo(type2); + } + Py_DECREF(temp); + return ret; + } + break; + case NPY_UNICODE: + /* Allow NUMBER -> UNICODE */ + if (PyTypeNum_ISNUMBER(type_num1)) { + PyArray_Descr *ret = NULL; + PyArray_Descr *temp = PyArray_DescrNew(type2); + PyDataType_MAKEUNSIZED(temp); + PyArray_AdaptFlexibleDType(NULL, type1, &temp); + if (temp->elsize > type2->elsize) { + ret = ensure_dtype_nbo(temp); + } + else { + ret = ensure_dtype_nbo(type2); + } + Py_DECREF(temp); + return ret; + } + break; + case NPY_TIMEDELTA: + if (PyTypeNum_ISINTEGER(type_num1) || + PyTypeNum_ISFLOAT(type_num1)) { + return ensure_dtype_nbo(type2); + } + break; + } + + /* For types equivalent up to endianness, can return either */ + if (PyArray_CanCastTypeTo(type1, type2, NPY_EQUIV_CASTING)) { + return ensure_dtype_nbo(type1); + } + + /* TODO: Also combine fields, subarrays, strings, etc */ + + /* + printf("invalid type promotion: "); + PyObject_Print(type1, stdout, 0); + printf(" "); + PyObject_Print(type2, stdout, 0); + printf("\n"); + */ + PyErr_SetString(PyExc_TypeError, "invalid type promotion"); + return NULL; +} + +/* + * NOTE: While this is unlikely to be a performance problem, if + * it is it could be reverted to a simple positive/negative + * check as the previous system used. + * + * The is_small_unsigned output flag indicates whether it's an unsigned integer, + * and would fit in a signed integer of the same bit size. + */ +static int min_scalar_type_num(char *valueptr, int type_num, + int *is_small_unsigned) +{ + switch (type_num) { + case NPY_BOOL: { + return NPY_BOOL; + } + case NPY_UBYTE: { + npy_ubyte value = *(npy_ubyte *)valueptr; + if (value <= NPY_MAX_BYTE) { + *is_small_unsigned = 1; + } + return NPY_UBYTE; + } + case NPY_BYTE: { + npy_byte value = *(npy_byte *)valueptr; + if (value >= 0) { + *is_small_unsigned = 1; + return NPY_UBYTE; + } + break; + } + case NPY_USHORT: { + npy_ushort value = *(npy_ushort *)valueptr; + if (value <= NPY_MAX_UBYTE) { + if (value <= NPY_MAX_BYTE) { + *is_small_unsigned = 1; + } + return NPY_UBYTE; + } + + if (value <= NPY_MAX_SHORT) { + *is_small_unsigned = 1; + } + break; + } + case NPY_SHORT: { + npy_short value = *(npy_short *)valueptr; + if (value >= 0) { + return min_scalar_type_num(valueptr, NPY_USHORT, is_small_unsigned); + } + else if (value >= NPY_MIN_BYTE) { + return NPY_BYTE; + } + break; + } +#if NPY_SIZEOF_LONG == NPY_SIZEOF_INT + case NPY_ULONG: +#endif + case NPY_UINT: { + npy_uint value = *(npy_uint *)valueptr; + if (value <= NPY_MAX_UBYTE) { + if (value <= NPY_MAX_BYTE) { + *is_small_unsigned = 1; + } + return NPY_UBYTE; + } + else if (value <= NPY_MAX_USHORT) { + if (value <= NPY_MAX_SHORT) { + *is_small_unsigned = 1; + } + return NPY_USHORT; + } + + if (value <= NPY_MAX_INT) { + *is_small_unsigned = 1; + } + break; + } +#if NPY_SIZEOF_LONG == NPY_SIZEOF_INT + case NPY_LONG: +#endif + case NPY_INT: { + npy_int value = *(npy_int *)valueptr; + if (value >= 0) { + return min_scalar_type_num(valueptr, NPY_UINT, is_small_unsigned); + } + else if (value >= NPY_MIN_BYTE) { + return NPY_BYTE; + } + else if (value >= NPY_MIN_SHORT) { + return NPY_SHORT; + } + break; + } +#if NPY_SIZEOF_LONG != NPY_SIZEOF_INT && NPY_SIZEOF_LONG != NPY_SIZEOF_LONGLONG + case NPY_ULONG: { + npy_ulong value = *(npy_ulong *)valueptr; + if (value <= NPY_MAX_UBYTE) { + if (value <= NPY_MAX_BYTE) { + *is_small_unsigned = 1; + } + return NPY_UBYTE; + } + else if (value <= NPY_MAX_USHORT) { + if (value <= NPY_MAX_SHORT) { + *is_small_unsigned = 1; + } + return NPY_USHORT; + } + else if (value <= NPY_MAX_UINT) { + if (value <= NPY_MAX_INT) { + *is_small_unsigned = 1; + } + return NPY_UINT; + } + + if (value <= NPY_MAX_LONG) { + *is_small_unsigned = 1; + } + break; + } + case NPY_LONG: { + npy_long value = *(npy_long *)valueptr; + if (value >= 0) { + return min_scalar_type_num(valueptr, NPY_ULONG, is_small_unsigned); + } + else if (value >= NPY_MIN_BYTE) { + return NPY_BYTE; + } + else if (value >= NPY_MIN_SHORT) { + return NPY_SHORT; + } + else if (value >= NPY_MIN_INT) { + return NPY_INT; + } + break; + } +#endif +#if NPY_SIZEOF_LONG == NPY_SIZEOF_LONGLONG + case NPY_ULONG: +#endif + case NPY_ULONGLONG: { + npy_ulonglong value = *(npy_ulonglong *)valueptr; + if (value <= NPY_MAX_UBYTE) { + if (value <= NPY_MAX_BYTE) { + *is_small_unsigned = 1; + } + return NPY_UBYTE; + } + else if (value <= NPY_MAX_USHORT) { + if (value <= NPY_MAX_SHORT) { + *is_small_unsigned = 1; + } + return NPY_USHORT; + } + else if (value <= NPY_MAX_UINT) { + if (value <= NPY_MAX_INT) { + *is_small_unsigned = 1; + } + return NPY_UINT; + } +#if NPY_SIZEOF_LONG != NPY_SIZEOF_INT && NPY_SIZEOF_LONG != NPY_SIZEOF_LONGLONG + else if (value <= NPY_MAX_ULONG) { + if (value <= NPY_MAX_LONG) { + *is_small_unsigned = 1; + } + return NPY_ULONG; + } +#endif + + if (value <= NPY_MAX_LONGLONG) { + *is_small_unsigned = 1; + } + break; + } +#if NPY_SIZEOF_LONG == NPY_SIZEOF_LONGLONG + case NPY_LONG: +#endif + case NPY_LONGLONG: { + npy_longlong value = *(npy_longlong *)valueptr; + if (value >= 0) { + return min_scalar_type_num(valueptr, NPY_ULONGLONG, is_small_unsigned); + } + else if (value >= NPY_MIN_BYTE) { + return NPY_BYTE; + } + else if (value >= NPY_MIN_SHORT) { + return NPY_SHORT; + } + else if (value >= NPY_MIN_INT) { + return NPY_INT; + } +#if NPY_SIZEOF_LONG != NPY_SIZEOF_INT && NPY_SIZEOF_LONG != NPY_SIZEOF_LONGLONG + else if (value >= NPY_MIN_LONG) { + return NPY_LONG; + } +#endif + break; + } + /* + * Float types aren't allowed to be demoted to integer types, + * but precision loss is allowed. + */ + case NPY_HALF: { + return NPY_HALF; + } + case NPY_FLOAT: { + float value = *(float *)valueptr; + if ((value > -65000 && value < 65000) || !npy_isfinite(value)) { + return NPY_HALF; + } + break; + } + case NPY_DOUBLE: { + double value = *(double *)valueptr; + if ((value > -65000 && value < 65000) || !npy_isfinite(value)) { + return NPY_HALF; + } + else if (value > -3.4e38 && value < 3.4e38) { + return NPY_FLOAT; + } + break; + } + case NPY_LONGDOUBLE: { + npy_longdouble value = *(npy_longdouble *)valueptr; + if ((value > -65000 && value < 65000) || !npy_isfinite(value)) { + return NPY_HALF; + } + else if (value > -3.4e38 && value < 3.4e38) { + return NPY_FLOAT; + } + else if (value > -1.7e308 && value < 1.7e308) { + return NPY_DOUBLE; + } + break; + } + /* + * The code to demote complex to float is disabled for now, + * as forcing complex by adding 0j is probably desirable. + */ + case NPY_CFLOAT: { + /* + npy_cfloat value = *(npy_cfloat *)valueptr; + if (value.imag == 0) { + return min_scalar_type_num((char *)&value.real, + NPY_FLOAT, is_small_unsigned); + } + */ + break; + } + case NPY_CDOUBLE: { + npy_cdouble value = *(npy_cdouble *)valueptr; + /* + if (value.imag == 0) { + return min_scalar_type_num((char *)&value.real, + NPY_DOUBLE, is_small_unsigned); + } + */ + if (value.real > -3.4e38 && value.real < 3.4e38 && + value.imag > -3.4e38 && value.imag < 3.4e38) { + return NPY_CFLOAT; + } + break; + } + case NPY_CLONGDOUBLE: { + npy_clongdouble value = *(npy_clongdouble *)valueptr; + /* + if (value.imag == 0) { + return min_scalar_type_num((char *)&value.real, + NPY_LONGDOUBLE, is_small_unsigned); + } + */ + if (value.real > -3.4e38 && value.real < 3.4e38 && + value.imag > -3.4e38 && value.imag < 3.4e38) { + return NPY_CFLOAT; + } + else if (value.real > -1.7e308 && value.real < 1.7e308 && + value.imag > -1.7e308 && value.imag < 1.7e308) { + return NPY_CDOUBLE; + } + break; + } + } + + return type_num; +} + +/*NUMPY_API + * If arr is a scalar (has 0 dimensions) with a built-in number data type, + * finds the smallest type size/kind which can still represent its data. + * Otherwise, returns the array's data type. + * + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_MinScalarType(PyArrayObject *arr) +{ + PyArray_Descr *dtype = PyArray_DESCR(arr); + /* + * If the array isn't a numeric scalar, just return the array's dtype. + */ + if (PyArray_NDIM(arr) > 0 || !PyTypeNum_ISNUMBER(dtype->type_num)) { + Py_INCREF(dtype); + return dtype; + } + else { + char *data = PyArray_BYTES(arr); + int swap = !PyArray_ISNBO(dtype->byteorder); + int is_small_unsigned = 0; + /* An aligned memory buffer large enough to hold any type */ + npy_longlong value[4]; + dtype->f->copyswap(&value, data, swap, NULL); + + return PyArray_DescrFromType( + min_scalar_type_num((char *)&value, + dtype->type_num, &is_small_unsigned)); + + } +} + +/* + * Provides an ordering for the dtype 'kind' character codes, to help + * determine when to use the min_scalar_type function. This groups + * 'kind' into boolean, integer, floating point, and everything else. + */ +static int +dtype_kind_to_simplified_ordering(char kind) +{ + switch (kind) { + /* Boolean kind */ + case 'b': + return 0; + /* Unsigned int kind */ + case 'u': + /* Signed int kind */ + case 'i': + return 1; + /* Float kind */ + case 'f': + /* Complex kind */ + case 'c': + return 2; + /* Anything else */ + default: + return 3; + } +} + +/*NUMPY_API + * Produces the result type of a bunch of inputs, using the UFunc + * type promotion rules. Use this function when you have a set of + * input arrays, and need to determine an output array dtype. + * + * If all the inputs are scalars (have 0 dimensions) or the maximum "kind" + * of the scalars is greater than the maximum "kind" of the arrays, does + * a regular type promotion. + * + * Otherwise, does a type promotion on the MinScalarType + * of all the inputs. Data types passed directly are treated as array + * types. + * + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_ResultType(npy_intp narrs, PyArrayObject **arr, + npy_intp ndtypes, PyArray_Descr **dtypes) +{ + npy_intp i; + int use_min_scalar = 0; + PyArray_Descr *ret = NULL, *tmpret; + int ret_is_small_unsigned = 0; + + /* If there's just one type, pass it through */ + if (narrs + ndtypes == 1) { + if (narrs == 1) { + ret = PyArray_DESCR(arr[0]); + } + else { + ret = dtypes[0]; + } + Py_INCREF(ret); + return ret; + } + + /* + * Determine if there are any scalars, and if so, whether + * the maximum "kind" of the scalars surpasses the maximum + * "kind" of the arrays + */ + if (narrs > 0) { + int all_scalars, max_scalar_kind = -1, max_array_kind = -1; + int kind; + + all_scalars = (ndtypes > 0) ? 0 : 1; + + /* Compute the maximum "kinds" and whether everything is scalar */ + for (i = 0; i < narrs; ++i) { + if (PyArray_NDIM(arr[i]) == 0) { + kind = dtype_kind_to_simplified_ordering( + PyArray_DESCR(arr[i])->kind); + if (kind > max_scalar_kind) { + max_scalar_kind = kind; + } + } + else { + all_scalars = 0; + kind = dtype_kind_to_simplified_ordering( + PyArray_DESCR(arr[i])->kind); + if (kind > max_array_kind) { + max_array_kind = kind; + } + } + } + /* + * If the max scalar kind is bigger than the max array kind, + * finish computing the max array kind + */ + for (i = 0; i < ndtypes; ++i) { + kind = dtype_kind_to_simplified_ordering(dtypes[i]->kind); + if (kind > max_array_kind) { + max_array_kind = kind; + } + } + + /* Indicate whether to use the min_scalar_type function */ + if (!all_scalars && max_array_kind >= max_scalar_kind) { + use_min_scalar = 1; + } + } + + /* Loop through all the types, promoting them */ + if (!use_min_scalar) { + for (i = 0; i < narrs; ++i) { + PyArray_Descr *tmp = PyArray_DESCR(arr[i]); + /* Combine it with the existing type */ + if (ret == NULL) { + ret = tmp; + Py_INCREF(ret); + } + else { + /* Only call promote if the types aren't the same dtype */ + if (tmp != ret || !PyArray_ISNBO(ret->byteorder)) { + tmpret = PyArray_PromoteTypes(tmp, ret); + Py_DECREF(ret); + ret = tmpret; + if (ret == NULL) { + return NULL; + } + } + } + } + + for (i = 0; i < ndtypes; ++i) { + PyArray_Descr *tmp = dtypes[i]; + /* Combine it with the existing type */ + if (ret == NULL) { + ret = tmp; + Py_INCREF(ret); + } + else { + /* Only call promote if the types aren't the same dtype */ + if (tmp != ret || !PyArray_ISNBO(tmp->byteorder)) { + tmpret = PyArray_PromoteTypes(tmp, ret); + Py_DECREF(ret); + ret = tmpret; + if (ret == NULL) { + return NULL; + } + } + } + } + } + else { + for (i = 0; i < narrs; ++i) { + /* Get the min scalar type for the array */ + PyArray_Descr *tmp = PyArray_DESCR(arr[i]); + int tmp_is_small_unsigned = 0; + /* + * If it's a scalar, find the min scalar type. The function + * is expanded here so that we can flag whether we've got an + * unsigned integer which would fit an a signed integer + * of the same size, something not exposed in the public API. + */ + if (PyArray_NDIM(arr[i]) == 0 && + PyTypeNum_ISNUMBER(tmp->type_num)) { + char *data = PyArray_BYTES(arr[i]); + int swap = !PyArray_ISNBO(tmp->byteorder); + int type_num; + /* An aligned memory buffer large enough to hold any type */ + npy_longlong value[4]; + tmp->f->copyswap(&value, data, swap, NULL); + type_num = min_scalar_type_num((char *)&value, + tmp->type_num, &tmp_is_small_unsigned); + tmp = PyArray_DescrFromType(type_num); + if (tmp == NULL) { + Py_XDECREF(ret); + return NULL; + } + } + else { + Py_INCREF(tmp); + } + /* Combine it with the existing type */ + if (ret == NULL) { + ret = tmp; + ret_is_small_unsigned = tmp_is_small_unsigned; + } + else { +#if 0 + printf("promoting type "); + PyObject_Print(tmp, stdout, 0); + printf(" (%d) ", tmp_is_small_unsigned); + PyObject_Print(ret, stdout, 0); + printf(" (%d) ", ret_is_small_unsigned); + printf("\n"); +#endif + /* If they point to the same type, don't call promote */ + if (tmp == ret && PyArray_ISNBO(tmp->byteorder)) { + Py_DECREF(tmp); + } + else { + tmpret = promote_types(tmp, ret, tmp_is_small_unsigned, + ret_is_small_unsigned); + if (tmpret == NULL) { + Py_DECREF(tmp); + Py_DECREF(ret); + return NULL; + } + Py_DECREF(tmp); + Py_DECREF(ret); + ret = tmpret; + } + ret_is_small_unsigned = tmp_is_small_unsigned && + ret_is_small_unsigned; + } + } + + for (i = 0; i < ndtypes; ++i) { + PyArray_Descr *tmp = dtypes[i]; + /* Combine it with the existing type */ + if (ret == NULL) { + ret = tmp; + Py_INCREF(ret); + } + else { + /* Only call promote if the types aren't the same dtype */ + if (tmp != ret || !PyArray_ISNBO(tmp->byteorder)) { + if (ret_is_small_unsigned) { + tmpret = promote_types(tmp, ret, 0, + ret_is_small_unsigned); + if (tmpret == NULL) { + Py_DECREF(tmp); + Py_DECREF(ret); + return NULL; + } + } + else { + tmpret = PyArray_PromoteTypes(tmp, ret); + } + Py_DECREF(ret); + ret = tmpret; + if (ret == NULL) { + return NULL; + } + } + } + } + } + + if (ret == NULL) { + PyErr_SetString(PyExc_TypeError, + "no arrays or types available to calculate result type"); + } + + return ret; +} + +/*NUMPY_API + * Is the typenum valid? + */ +NPY_NO_EXPORT int +PyArray_ValidType(int type) +{ + PyArray_Descr *descr; + int res=NPY_TRUE; + + descr = PyArray_DescrFromType(type); + if (descr == NULL) { + res = NPY_FALSE; + } + Py_DECREF(descr); + return res; +} + +/* Backward compatibility only */ +/* In both Zero and One + +***You must free the memory once you are done with it +using PyDataMem_FREE(ptr) or you create a memory leak*** + +If arr is an Object array you are getting a +BORROWED reference to Zero or One. +Do not DECREF. +Please INCREF if you will be hanging on to it. + +The memory for the ptr still must be freed in any case; +*/ + +static int +_check_object_rec(PyArray_Descr *descr) +{ + if (PyDataType_HASFIELDS(descr) && PyDataType_REFCHK(descr)) { + PyErr_SetString(PyExc_TypeError, "Not supported for this data-type."); + return -1; + } + return 0; +} + +/*NUMPY_API + Get pointer to zero of correct type for array. +*/ +NPY_NO_EXPORT char * +PyArray_Zero(PyArrayObject *arr) +{ + char *zeroval; + int ret, storeflags; + static PyObject * zero_obj = NULL; + + if (_check_object_rec(PyArray_DESCR(arr)) < 0) { + return NULL; + } + zeroval = PyDataMem_NEW(PyArray_DESCR(arr)->elsize); + if (zeroval == NULL) { + PyErr_SetNone(PyExc_MemoryError); + return NULL; + } + + if (zero_obj == NULL) { + zero_obj = PyInt_FromLong((long) 0); + if (zero_obj == NULL) { + return NULL; + } + } + if (PyArray_ISOBJECT(arr)) { + /* XXX this is dangerous, the caller probably is not + aware that zeroval is actually a static PyObject* + In the best case they will only use it as-is, but + if they simply memcpy it into a ndarray without using + setitem(), refcount errors will occur + */ + memcpy(zeroval, &zero_obj, sizeof(PyObject *)); + return zeroval; + } + storeflags = PyArray_FLAGS(arr); + PyArray_ENABLEFLAGS(arr, NPY_ARRAY_BEHAVED); + ret = PyArray_SETITEM(arr, zeroval, zero_obj); + ((PyArrayObject_fields *)arr)->flags = storeflags; + if (ret < 0) { + PyDataMem_FREE(zeroval); + return NULL; + } + return zeroval; +} + +/*NUMPY_API + Get pointer to one of correct type for array +*/ +NPY_NO_EXPORT char * +PyArray_One(PyArrayObject *arr) +{ + char *oneval; + int ret, storeflags; + static PyObject * one_obj = NULL; + + if (_check_object_rec(PyArray_DESCR(arr)) < 0) { + return NULL; + } + oneval = PyDataMem_NEW(PyArray_DESCR(arr)->elsize); + if (oneval == NULL) { + PyErr_SetNone(PyExc_MemoryError); + return NULL; + } + + if (one_obj == NULL) { + one_obj = PyInt_FromLong((long) 1); + if (one_obj == NULL) { + return NULL; + } + } + if (PyArray_ISOBJECT(arr)) { + /* XXX this is dangerous, the caller probably is not + aware that oneval is actually a static PyObject* + In the best case they will only use it as-is, but + if they simply memcpy it into a ndarray without using + setitem(), refcount errors will occur + */ + memcpy(oneval, &one_obj, sizeof(PyObject *)); + return oneval; + } + + storeflags = PyArray_FLAGS(arr); + PyArray_ENABLEFLAGS(arr, NPY_ARRAY_BEHAVED); + ret = PyArray_SETITEM(arr, oneval, one_obj); + ((PyArrayObject_fields *)arr)->flags = storeflags; + if (ret < 0) { + PyDataMem_FREE(oneval); + return NULL; + } + return oneval; +} + +/* End deprecated */ + +/*NUMPY_API + * Return the typecode of the array a Python object would be converted to + * + * Returns the type number the result should have, or NPY_NOTYPE on error. + */ +NPY_NO_EXPORT int +PyArray_ObjectType(PyObject *op, int minimum_type) +{ + PyArray_Descr *dtype = NULL; + int ret; + + if (minimum_type != NPY_NOTYPE && minimum_type >= 0) { + dtype = PyArray_DescrFromType(minimum_type); + if (dtype == NULL) { + return NPY_NOTYPE; + } + } + + if (PyArray_DTypeFromObject(op, NPY_MAXDIMS, &dtype) < 0) { + return NPY_NOTYPE; + } + + if (dtype == NULL) { + ret = NPY_DEFAULT_TYPE; + } + else { + ret = dtype->type_num; + } + + Py_XDECREF(dtype); + + return ret; +} + +/* Raises error when len(op) == 0 */ + +/*NUMPY_API*/ +NPY_NO_EXPORT PyArrayObject ** +PyArray_ConvertToCommonType(PyObject *op, int *retn) +{ + int i, n, allscalars = 0; + PyArrayObject **mps = NULL; + PyObject *otmp; + PyArray_Descr *intype = NULL, *stype = NULL; + PyArray_Descr *newtype = NULL; + NPY_SCALARKIND scalarkind = NPY_NOSCALAR, intypekind = NPY_NOSCALAR; + + *retn = n = PySequence_Length(op); + if (n == 0) { + PyErr_SetString(PyExc_ValueError, "0-length sequence."); + } + if (PyErr_Occurred()) { + *retn = 0; + return NULL; + } + mps = (PyArrayObject **)PyDataMem_NEW(n*sizeof(PyArrayObject *)); + if (mps == NULL) { + *retn = 0; + return (void*)PyErr_NoMemory(); + } + + if (PyArray_Check(op)) { + for (i = 0; i < n; i++) { + mps[i] = (PyArrayObject *) array_item_asarray((PyArrayObject *)op, i); + } + if (!PyArray_ISCARRAY((PyArrayObject *)op)) { + for (i = 0; i < n; i++) { + PyObject *obj; + obj = PyArray_NewCopy(mps[i], NPY_CORDER); + Py_DECREF(mps[i]); + mps[i] = (PyArrayObject *)obj; + } + } + return mps; + } + + for (i = 0; i < n; i++) { + mps[i] = NULL; + } + + for (i = 0; i < n; i++) { + otmp = PySequence_GetItem(op, i); + if (!PyArray_CheckAnyScalar(otmp)) { + newtype = PyArray_DescrFromObject(otmp, intype); + Py_XDECREF(intype); + if (newtype == NULL) { + goto fail; + } + intype = newtype; + intypekind = PyArray_ScalarKind(intype->type_num, NULL); + } + else { + newtype = PyArray_DescrFromObject(otmp, stype); + Py_XDECREF(stype); + if (newtype == NULL) { + goto fail; + } + stype = newtype; + scalarkind = PyArray_ScalarKind(newtype->type_num, NULL); + mps[i] = (PyArrayObject *)Py_None; + Py_INCREF(Py_None); + } + Py_XDECREF(otmp); + } + if (intype == NULL) { + /* all scalars */ + allscalars = 1; + intype = stype; + Py_INCREF(intype); + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + mps[i] = NULL; + } + } + else if ((stype != NULL) && (intypekind != scalarkind)) { + /* + * we need to upconvert to type that + * handles both intype and stype + * also don't forcecast the scalars. + */ + if (!PyArray_CanCoerceScalar(stype->type_num, + intype->type_num, + scalarkind)) { + newtype = PyArray_PromoteTypes(intype, stype); + Py_XDECREF(intype); + intype = newtype; + } + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + mps[i] = NULL; + } + } + + + /* Make sure all arrays are actual array objects. */ + for (i = 0; i < n; i++) { + int flags = NPY_ARRAY_CARRAY; + + if ((otmp = PySequence_GetItem(op, i)) == NULL) { + goto fail; + } + if (!allscalars && ((PyObject *)(mps[i]) == Py_None)) { + /* forcecast scalars */ + flags |= NPY_ARRAY_FORCECAST; + Py_DECREF(Py_None); + } + Py_INCREF(intype); + mps[i] = (PyArrayObject*) + PyArray_FromAny(otmp, intype, 0, 0, flags, NULL); + Py_DECREF(otmp); + if (mps[i] == NULL) { + goto fail; + } + } + Py_DECREF(intype); + Py_XDECREF(stype); + return mps; + + fail: + Py_XDECREF(intype); + Py_XDECREF(stype); + *retn = 0; + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + } + PyDataMem_FREE(mps); + return NULL; +} diff --git a/numpy/core/src/multiarray/convert_datatype.h b/numpy/core/src/multiarray/convert_datatype.h new file mode 100644 index 0000000..bf77d69 --- /dev/null +++ b/numpy/core/src/multiarray/convert_datatype.h @@ -0,0 +1,33 @@ +#ifndef _NPY_ARRAY_CONVERT_DATATYPE_H_ +#define _NPY_ARRAY_CONVERT_DATATYPE_H_ + +NPY_NO_EXPORT PyArray_VectorUnaryFunc * +PyArray_GetCastFunc(PyArray_Descr *descr, int type_num); + +NPY_NO_EXPORT int +PyArray_ObjectType(PyObject *op, int minimum_type); + +NPY_NO_EXPORT PyArrayObject ** +PyArray_ConvertToCommonType(PyObject *op, int *retn); + +NPY_NO_EXPORT int +PyArray_ValidType(int type); + +/* Like PyArray_CanCastArrayTo */ +NPY_NO_EXPORT npy_bool +can_cast_scalar_to(PyArray_Descr *scal_type, char *scal_data, + PyArray_Descr *to, NPY_CASTING casting); + +/* + * This function calls Py_DECREF on flex_dtype, and replaces it with + * a new dtype that has been adapted based on the values in data_dtype + * and data_obj. If the flex_dtype is not flexible, it leaves it as is. + * + * The current flexible dtypes include NPY_STRING, NPY_UNICODE, NPY_VOID, + * and NPY_DATETIME with generic units. + */ +NPY_NO_EXPORT void +PyArray_AdaptFlexibleDType(PyObject *data_obj, PyArray_Descr *data_dtype, + PyArray_Descr **flex_dtype); + +#endif diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c new file mode 100644 index 0000000..f4236f3 --- /dev/null +++ b/numpy/core/src/multiarray/ctors.c @@ -0,0 +1,3929 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "numpy/npy_math.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" +#include "multiarraymodule.h" + +#include "common.h" +#include "ctors.h" +#include "convert_datatype.h" +#include "shape.h" +#include "buffer.h" +#include "lowlevel_strided_loops.h" +#include "methods.h" +#include "_datetime.h" +#include "datetime_strings.h" +#include "array_assign.h" +#include "mapping.h" /* for array_item_asarray */ +#include "templ_common.h" /* for npy_mul_with_overflow_intp */ +#include "alloc.h" +#include + +#include "get_attr_string.h" + +/* + * Reading from a file or a string. + * + * As much as possible, we try to use the same code for both files and strings, + * so the semantics for fromstring and fromfile are the same, especially with + * regards to the handling of text representations. + */ + +typedef int (*next_element)(void **, void *, PyArray_Descr *, void *); +typedef int (*skip_separator)(void **, const char *, void *); + +static int +fromstr_next_element(char **s, void *dptr, PyArray_Descr *dtype, + const char *end) +{ + char *e = *s; + int r = dtype->f->fromstr(*s, dptr, &e, dtype); + /* + * fromstr always returns 0 for basic dtypes + * s points to the end of the parsed string + * if an error occurs s is not changed + */ + if (*s == e) { + /* Nothing read */ + return -1; + } + *s = e; + if (end != NULL && *s > end) { + return -1; + } + return r; +} + +static int +fromfile_next_element(FILE **fp, void *dptr, PyArray_Descr *dtype, + void *NPY_UNUSED(stream_data)) +{ + /* the NULL argument is for backwards-compatibility */ + int r = dtype->f->scanfunc(*fp, dptr, NULL, dtype); + /* r can be EOF or the number of items read (0 or 1) */ + if (r == 1) { + return 0; + } + else { + return -1; + } +} + +/* + * Remove multiple whitespace from the separator, and add a space to the + * beginning and end. This simplifies the separator-skipping code below. + */ +static char * +swab_separator(const char *sep) +{ + int skip_space = 0; + char *s, *start; + + s = start = malloc(strlen(sep)+3); + if (s == NULL) { + return NULL; + } + /* add space to front if there isn't one */ + if (*sep != '\0' && !isspace(*sep)) { + *s = ' '; s++; + } + while (*sep != '\0') { + if (isspace(*sep)) { + if (skip_space) { + sep++; + } + else { + *s = ' '; + s++; + sep++; + skip_space = 1; + } + } + else { + *s = *sep; + s++; + sep++; + skip_space = 0; + } + } + /* add space to end if there isn't one */ + if (s != start && s[-1] == ' ') { + *s = ' '; + s++; + } + *s = '\0'; + return start; +} + +/* + * Assuming that the separator is the next bit in the string (file), skip it. + * + * Single spaces in the separator are matched to arbitrary-long sequences + * of whitespace in the input. If the separator consists only of spaces, + * it matches one or more whitespace characters. + * + * If we can't match the separator, return -2. + * If we hit the end of the string (file), return -1. + * Otherwise, return 0. + */ +static int +fromstr_skip_separator(char **s, const char *sep, const char *end) +{ + char *string = *s; + int result = 0; + while (1) { + char c = *string; + if (c == '\0' || (end != NULL && string >= end)) { + result = -1; + break; + } + else if (*sep == '\0') { + if (string != *s) { + /* matched separator */ + result = 0; + break; + } + else { + /* separator was whitespace wildcard that didn't match */ + result = -2; + break; + } + } + else if (*sep == ' ') { + /* whitespace wildcard */ + if (!isspace(c)) { + sep++; + continue; + } + } + else if (*sep != c) { + result = -2; + break; + } + else { + sep++; + } + string++; + } + *s = string; + return result; +} + +static int +fromfile_skip_separator(FILE **fp, const char *sep, void *NPY_UNUSED(stream_data)) +{ + int result = 0; + const char *sep_start = sep; + + while (1) { + int c = fgetc(*fp); + + if (c == EOF) { + result = -1; + break; + } + else if (*sep == '\0') { + ungetc(c, *fp); + if (sep != sep_start) { + /* matched separator */ + result = 0; + break; + } + else { + /* separator was whitespace wildcard that didn't match */ + result = -2; + break; + } + } + else if (*sep == ' ') { + /* whitespace wildcard */ + if (!isspace(c)) { + sep++; + sep_start++; + ungetc(c, *fp); + } + else if (sep == sep_start) { + sep_start--; + } + } + else if (*sep != c) { + ungetc(c, *fp); + result = -2; + break; + } + else { + sep++; + } + } + return result; +} + +/* + * Change a sub-array field to the base descriptor + * and update the dimensions and strides + * appropriately. Dimensions and strides are added + * to the end. + * + * Strides are only added if given (because data is given). + */ +static int +_update_descr_and_dimensions(PyArray_Descr **des, npy_intp *newdims, + npy_intp *newstrides, int oldnd) +{ + PyArray_Descr *old; + int newnd; + int numnew; + npy_intp *mydim; + int i; + int tuple; + + old = *des; + *des = old->subarray->base; + + + mydim = newdims + oldnd; + tuple = PyTuple_Check(old->subarray->shape); + if (tuple) { + numnew = PyTuple_GET_SIZE(old->subarray->shape); + } + else { + numnew = 1; + } + + + newnd = oldnd + numnew; + if (newnd > NPY_MAXDIMS) { + goto finish; + } + if (tuple) { + for (i = 0; i < numnew; i++) { + mydim[i] = (npy_intp) PyInt_AsLong( + PyTuple_GET_ITEM(old->subarray->shape, i)); + } + } + else { + mydim[0] = (npy_intp) PyInt_AsLong(old->subarray->shape); + } + + if (newstrides) { + npy_intp tempsize; + npy_intp *mystrides; + + mystrides = newstrides + oldnd; + /* Make new strides -- always C-contiguous */ + tempsize = (*des)->elsize; + for (i = numnew - 1; i >= 0; i--) { + mystrides[i] = tempsize; + tempsize *= mydim[i] ? mydim[i] : 1; + } + } + + finish: + Py_INCREF(*des); + Py_DECREF(old); + return newnd; +} + +NPY_NO_EXPORT void +_unaligned_strided_byte_copy(char *dst, npy_intp outstrides, char *src, + npy_intp instrides, npy_intp N, int elsize) +{ + npy_intp i; + char *tout = dst; + char *tin = src; + +#define _COPY_N_SIZE(size) \ + for(i=0; i 0; n--, a += stride) { + npy_uint32 * a_ = (npy_uint32 *)a; + *a_ = npy_bswap4(*a_); + } + } + else { + for (a = (char*)p; n > 0; n--, a += stride) { + npy_bswap4_unaligned(a); + } + } + break; + case 8: + if (npy_is_aligned((void*)((npy_intp)p | stride), sizeof(npy_uint64))) { + for (a = (char*)p; n > 0; n--, a += stride) { + npy_uint64 * a_ = (npy_uint64 *)a; + *a_ = npy_bswap8(*a_); + } + } + else { + for (a = (char*)p; n > 0; n--, a += stride) { + npy_bswap8_unaligned(a); + } + } + break; + case 2: + if (npy_is_aligned((void*)((npy_intp)p | stride), sizeof(npy_uint16))) { + for (a = (char*)p; n > 0; n--, a += stride) { + npy_uint16 * a_ = (npy_uint16 *)a; + *a_ = npy_bswap2(*a_); + } + } + else { + for (a = (char*)p; n > 0; n--, a += stride) { + npy_bswap2_unaligned(a); + } + } + break; + default: + m = size/2; + for (a = (char *)p; n > 0; n--, a += stride - m) { + b = a + (size - 1); + for (j = 0; j < m; j++) { + c=*a; *a++ = *b; *b-- = c; + } + } + break; + } +} + +NPY_NO_EXPORT void +byte_swap_vector(void *p, npy_intp n, int size) +{ + _strided_byte_swap(p, (npy_intp) size, n, size); + return; +} + +/* If numitems > 1, then dst must be contiguous */ +NPY_NO_EXPORT void +copy_and_swap(void *dst, void *src, int itemsize, npy_intp numitems, + npy_intp srcstrides, int swap) +{ + if ((numitems == 1) || (itemsize == srcstrides)) { + memcpy(dst, src, itemsize*numitems); + } + else { + npy_intp i; + char *s1 = (char *)src; + char *d1 = (char *)dst; + + for (i = 0; i < numitems; i++) { + memcpy(d1, s1, itemsize); + d1 += itemsize; + s1 += srcstrides; + } + } + + if (swap) { + byte_swap_vector(dst, numitems, itemsize); + } +} + +/* + * adapted from Numarray, + * a: destination array + * s: source object, array or sequence + * dim: current recursion dimension, must be 0 on first call + * dst: must be NULL on first call + * it is a view on the destination array viewing the place where to put the + * data of the current recursion + */ +static int +setArrayFromSequence(PyArrayObject *a, PyObject *s, + int dim, PyArrayObject * dst) +{ + Py_ssize_t i, slen; + int res = -1; + + /* first recursion, view equal destination */ + if (dst == NULL) + dst = a; + + /* + * This code is to ensure that the sequence access below will + * return a lower-dimensional sequence. + */ + + /* INCREF on entry DECREF on exit */ + Py_INCREF(s); + + if (PyArray_Check(s)) { + if (!(PyArray_CheckExact(s))) { + /* + * make sure a base-class array is used so that the dimensionality + * reduction assumption is correct. + */ + /* This will DECREF(s) if replaced */ + s = PyArray_EnsureArray(s); + if (s == NULL) { + goto fail; + } + } + + /* dst points to correct array subsection */ + if (PyArray_CopyInto(dst, (PyArrayObject *)s) < 0) { + goto fail; + } + + Py_DECREF(s); + return 0; + } + + if (dim > PyArray_NDIM(a)) { + PyErr_Format(PyExc_ValueError, + "setArrayFromSequence: sequence/array dimensions mismatch."); + goto fail; + } + + slen = PySequence_Length(s); + if (slen < 0) { + goto fail; + } + /* + * Either the dimensions match, or the sequence has length 1 and can + * be broadcast to the destination. + */ + if (slen != PyArray_DIMS(a)[dim] && slen != 1) { + PyErr_Format(PyExc_ValueError, + "cannot copy sequence with size %d to array axis " + "with dimension %d", (int)slen, (int)PyArray_DIMS(a)[dim]); + goto fail; + } + + /* Broadcast the one element from the sequence to all the outputs */ + if (slen == 1) { + PyObject *o; + npy_intp alen = PyArray_DIM(a, dim); + + o = PySequence_GetItem(s, 0); + if (o == NULL) { + goto fail; + } + + for (i = 0; i < alen; i++) { + if ((PyArray_NDIM(a) - dim) > 1) { + PyArrayObject * tmp = + (PyArrayObject *)array_item_asarray(dst, i); + if (tmp == NULL) { + goto fail; + } + + res = setArrayFromSequence(a, o, dim+1, tmp); + Py_DECREF(tmp); + } + else { + char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]); + res = PyArray_SETITEM(dst, b, o); + } + if (res < 0) { + Py_DECREF(o); + goto fail; + } + } + Py_DECREF(o); + } + /* Copy element by element */ + else { + PyObject * seq; + seq = PySequence_Fast(s, "Could not convert object to sequence"); + if (seq == NULL) { + goto fail; + } + for (i = 0; i < slen; i++) { + PyObject * o = PySequence_Fast_GET_ITEM(seq, i); + if ((PyArray_NDIM(a) - dim) > 1) { + PyArrayObject * tmp = + (PyArrayObject *)array_item_asarray(dst, i); + if (tmp == NULL) { + Py_DECREF(seq); + goto fail; + } + + res = setArrayFromSequence(a, o, dim+1, tmp); + Py_DECREF(tmp); + } + else { + char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]); + res = PyArray_SETITEM(dst, b, o); + } + if (res < 0) { + Py_DECREF(seq); + goto fail; + } + } + Py_DECREF(seq); + } + + Py_DECREF(s); + return 0; + + fail: + Py_DECREF(s); + return res; +} + +NPY_NO_EXPORT int +PyArray_AssignFromSequence(PyArrayObject *self, PyObject *v) +{ + if (!PySequence_Check(v)) { + PyErr_SetString(PyExc_ValueError, + "assignment from non-sequence"); + return -1; + } + if (PyArray_NDIM(self) == 0) { + PyErr_SetString(PyExc_ValueError, + "assignment to 0-d array"); + return -1; + } + return setArrayFromSequence(self, v, 0, NULL); +} + +/* + * The rest of this code is to build the right kind of array + * from a python object. + */ + +static int +discover_itemsize(PyObject *s, int nd, int *itemsize, int string_type) +{ + int r; + npy_intp n, i; + + if (PyArray_Check(s)) { + *itemsize = PyArray_MAX(*itemsize, PyArray_ITEMSIZE((PyArrayObject *)s)); + return 0; + } + + if ((nd == 0) || PyString_Check(s) || +#if defined(NPY_PY3K) + PyMemoryView_Check(s) || +#else + PyBuffer_Check(s) || +#endif + PyUnicode_Check(s)) { + + /* If an object has no length, leave it be */ + if (string_type && s != NULL && + !PyString_Check(s) && !PyUnicode_Check(s)) { + PyObject *s_string = NULL; + if (string_type == NPY_STRING) { + s_string = PyObject_Str(s); + } + else { +#if defined(NPY_PY3K) + s_string = PyObject_Str(s); +#else + s_string = PyObject_Unicode(s); +#endif + } + if (s_string) { + n = PyObject_Length(s_string); + Py_DECREF(s_string); + } + else { + n = -1; + } + } + else { + n = PyObject_Length(s); + } + if (n == -1) { + PyErr_Clear(); + } + else { + *itemsize = PyArray_MAX(*itemsize, n); + } + return 0; + } + + n = PySequence_Length(s); + for (i = 0; i < n; i++) { + PyObject *e = PySequence_GetItem(s,i); + + if (e == NULL) { + return -1; + } + + r = discover_itemsize(e, nd - 1, itemsize, string_type); + Py_DECREF(e); + if (r == -1) { + return -1; + } + } + + return 0; +} + +/* + * Take an arbitrary object and discover how many dimensions it + * has, filling in the dimensions as we go. + */ +static int +discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it, + int stop_at_string, int stop_at_tuple, + int *out_is_object) +{ + PyObject *e; + int r; + npy_intp n, i; + Py_buffer buffer_view; + PyObject * seq; + + if (*maxndim == 0) { + return 0; + } + + /* obj is an Array */ + if (PyArray_Check(obj)) { + PyArrayObject *arr = (PyArrayObject *)obj; + + if (PyArray_NDIM(arr) < *maxndim) { + *maxndim = PyArray_NDIM(arr); + } + + for (i=0; i<*maxndim; i++) { + d[i] = PyArray_DIM(arr,i); + } + return 0; + } + + /* obj is a Scalar */ + if (PyArray_IsScalar(obj, Generic)) { + *maxndim = 0; + return 0; + } + + /* obj is not a Sequence */ + if (!PySequence_Check(obj) || + PySequence_Length(obj) < 0) { + *maxndim = 0; + PyErr_Clear(); + return 0; + } + + /* obj is a String */ + if (PyString_Check(obj) || +#if defined(NPY_PY3K) +#else + PyBuffer_Check(obj) || +#endif + PyUnicode_Check(obj)) { + if (stop_at_string) { + *maxndim = 0; + } + else { + d[0] = PySequence_Length(obj); + *maxndim = 1; + } + return 0; + } + + /* obj is a Tuple, but tuples aren't expanded */ + if (stop_at_tuple && PyTuple_Check(obj)) { + *maxndim = 0; + return 0; + } + + /* obj is a PEP 3118 buffer */ + /* PEP 3118 buffer interface */ + if (PyObject_CheckBuffer(obj) == 1) { + memset(&buffer_view, 0, sizeof(Py_buffer)); + if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 || + PyObject_GetBuffer(obj, &buffer_view, PyBUF_ND) == 0) { + int nd = buffer_view.ndim; + if (nd < *maxndim) { + *maxndim = nd; + } + for (i=0; i<*maxndim; i++) { + d[i] = buffer_view.shape[i]; + } + PyBuffer_Release(&buffer_view); + return 0; + } + else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) { + d[0] = buffer_view.len; + *maxndim = 1; + PyBuffer_Release(&buffer_view); + return 0; + } + else { + PyErr_Clear(); + } + } + + /* obj has the __array_struct__ interface */ + e = PyArray_LookupSpecial_OnInstance(obj, "__array_struct__"); + if (e != NULL) { + int nd = -1; + if (NpyCapsule_Check(e)) { + PyArrayInterface *inter; + inter = (PyArrayInterface *)NpyCapsule_AsVoidPtr(e); + if (inter->two == 2) { + nd = inter->nd; + if (nd >= 0) { + if (nd < *maxndim) { + *maxndim = nd; + } + for (i=0; i<*maxndim; i++) { + d[i] = inter->shape[i]; + } + } + } + } + Py_DECREF(e); + if (nd >= 0) { + return 0; + } + } + + /* obj has the __array_interface__ interface */ + e = PyArray_LookupSpecial_OnInstance(obj, "__array_interface__"); + if (e != NULL) { + int nd = -1; + if (PyDict_Check(e)) { + PyObject *new; + new = PyDict_GetItemString(e, "shape"); + if (new && PyTuple_Check(new)) { + nd = PyTuple_GET_SIZE(new); + if (nd < *maxndim) { + *maxndim = nd; + } + for (i=0; i<*maxndim; i++) { + d[i] = PyInt_AsSsize_t(PyTuple_GET_ITEM(new, i)); + if (d[i] < 0) { + PyErr_SetString(PyExc_RuntimeError, + "Invalid shape in __array_interface__"); + Py_DECREF(e); + return -1; + } + } + } + } + Py_DECREF(e); + if (nd >= 0) { + return 0; + } + } + + seq = PySequence_Fast(obj, "Could not convert object to sequence"); + if (seq == NULL) { + /* + * PySequence_Check detects whether an old type object is a + * sequence by the presence of the __getitem__ attribute, and + * for new type objects that aren't dictionaries by the + * presence of the __len__ attribute as well. In either case it + * is possible to have an object that tests as a sequence but + * doesn't behave as a sequence and consequently, the + * PySequence_GetItem call can fail. When that happens and the + * object looks like a dictionary, we truncate the dimensions + * and set the object creation flag, otherwise we pass the + * error back up the call chain. + */ + if (PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_Clear(); + *maxndim = 0; + *out_is_object = 1; + return 0; + } + else { + return -1; + } + } + n = PySequence_Fast_GET_SIZE(seq); + + d[0] = n; + + /* 1-dimensional sequence */ + if (n == 0 || *maxndim == 1) { + *maxndim = 1; + Py_DECREF(seq); + return 0; + } + else { + npy_intp dtmp[NPY_MAXDIMS]; + int j, maxndim_m1 = *maxndim - 1; + e = PySequence_Fast_GET_ITEM(seq, 0); + + r = discover_dimensions(e, &maxndim_m1, d + 1, check_it, + stop_at_string, stop_at_tuple, + out_is_object); + if (r < 0) { + Py_DECREF(seq); + return r; + } + + /* For the dimension truncation check below */ + *maxndim = maxndim_m1 + 1; + for (i = 1; i < n; ++i) { + e = PySequence_Fast_GET_ITEM(seq, i); + /* Get the dimensions of the first item */ + r = discover_dimensions(e, &maxndim_m1, dtmp, check_it, + stop_at_string, stop_at_tuple, + out_is_object); + if (r < 0) { + Py_DECREF(seq); + return r; + } + + /* Reduce max_ndim_m1 to just items which match */ + for (j = 0; j < maxndim_m1; ++j) { + if (dtmp[j] != d[j+1]) { + maxndim_m1 = j; + break; + } + } + } + /* + * If the dimensions are truncated, need to produce + * an object array. + */ + if (maxndim_m1 + 1 < *maxndim) { + *out_is_object = 1; + *maxndim = maxndim_m1 + 1; + } + } + + Py_DECREF(seq); + + return 0; +} + +/* + * Generic new array creation routine. + * Internal variant with calloc argument for PyArray_Zeros. + * + * steals a reference to descr. On failure or descr->subarray, descr will + * be decrefed. + */ +NPY_NO_EXPORT PyObject * +PyArray_NewFromDescr_int(PyTypeObject *subtype, PyArray_Descr *descr, int nd, + npy_intp *dims, npy_intp *strides, void *data, + int flags, PyObject *obj, int zeroed, + int allow_emptystring) +{ + PyArrayObject_fields *fa; + int i, is_empty; + npy_intp nbytes; + + if (descr->subarray) { + PyObject *ret; + npy_intp newdims[2*NPY_MAXDIMS]; + npy_intp *newstrides = NULL; + memcpy(newdims, dims, nd*sizeof(npy_intp)); + if (strides) { + newstrides = newdims + NPY_MAXDIMS; + memcpy(newstrides, strides, nd*sizeof(npy_intp)); + } + nd =_update_descr_and_dimensions(&descr, newdims, + newstrides, nd); + ret = PyArray_NewFromDescr_int(subtype, descr, nd, newdims, + newstrides, + data, flags, obj, zeroed, + allow_emptystring); + return ret; + } + + if ((unsigned int)nd > (unsigned int)NPY_MAXDIMS) { + PyErr_Format(PyExc_ValueError, + "number of dimensions must be within [0, %d]", + NPY_MAXDIMS); + Py_DECREF(descr); + return NULL; + } + + /* Check datatype element size */ + nbytes = descr->elsize; + if (PyDataType_ISUNSIZED(descr)) { + if (!PyDataType_ISFLEXIBLE(descr)) { + PyErr_SetString(PyExc_TypeError, "Empty data-type"); + Py_DECREF(descr); + return NULL; + } + else if (PyDataType_ISSTRING(descr) && !allow_emptystring && + data == NULL) { + PyArray_DESCR_REPLACE(descr); + if (descr == NULL) { + return NULL; + } + if (descr->type_num == NPY_STRING) { + nbytes = descr->elsize = 1; + } + else { + nbytes = descr->elsize = sizeof(npy_ucs4); + } + } + } + + /* Check dimensions and multiply them to nbytes */ + is_empty = 0; + for (i = 0; i < nd; i++) { + npy_intp dim = dims[i]; + + if (dim == 0) { + /* + * Compare to PyArray_OverflowMultiplyList that + * returns 0 in this case. + */ + is_empty = 1; + continue; + } + + if (dim < 0) { + PyErr_SetString(PyExc_ValueError, + "negative dimensions are not allowed"); + Py_DECREF(descr); + return NULL; + } + + /* + * Care needs to be taken to avoid integer overflow when + * multiplying the dimensions together to get the total size of the + * array. + */ + if (npy_mul_with_overflow_intp(&nbytes, nbytes, dim)) { + PyErr_SetString(PyExc_ValueError, + "array is too big; `arr.size * arr.dtype.itemsize` " + "is larger than the maximum possible size."); + Py_DECREF(descr); + return NULL; + } + } + + fa = (PyArrayObject_fields *) subtype->tp_alloc(subtype, 0); + if (fa == NULL) { + Py_DECREF(descr); + return NULL; + } + fa->nd = nd; + fa->dimensions = NULL; + fa->data = NULL; + if (data == NULL) { + fa->flags = NPY_ARRAY_DEFAULT; + if (flags) { + fa->flags |= NPY_ARRAY_F_CONTIGUOUS; + if (nd > 1) { + fa->flags &= ~NPY_ARRAY_C_CONTIGUOUS; + } + flags = NPY_ARRAY_F_CONTIGUOUS; + } + } + else { + fa->flags = (flags & ~NPY_ARRAY_WRITEBACKIFCOPY); + fa->flags = (fa->flags & ~NPY_ARRAY_UPDATEIFCOPY); + } + fa->descr = descr; + fa->base = (PyObject *)NULL; + fa->weakreflist = (PyObject *)NULL; + + if (nd > 0) { + fa->dimensions = npy_alloc_cache_dim(2 * nd); + if (fa->dimensions == NULL) { + PyErr_NoMemory(); + goto fail; + } + fa->strides = fa->dimensions + nd; + memcpy(fa->dimensions, dims, sizeof(npy_intp)*nd); + if (strides == NULL) { /* fill it in */ + _array_fill_strides(fa->strides, dims, nd, descr->elsize, + flags, &(fa->flags)); + } + else { + /* + * we allow strides even when we create + * the memory, but be careful with this... + */ + memcpy(fa->strides, strides, sizeof(npy_intp)*nd); + } + } + else { + fa->dimensions = fa->strides = NULL; + fa->flags |= NPY_ARRAY_F_CONTIGUOUS; + } + + if (data == NULL) { + /* + * Allocate something even for zero-space arrays + * e.g. shape=(0,) -- otherwise buffer exposure + * (a.data) doesn't work as it should. + * Could probably just allocate a few bytes here. -- Chuck + */ + if (is_empty) { + nbytes = descr->elsize; + } + /* + * It is bad to have uninitialized OBJECT pointers + * which could also be sub-fields of a VOID array + */ + if (zeroed || PyDataType_FLAGCHK(descr, NPY_NEEDS_INIT)) { + data = npy_alloc_cache_zero(nbytes); + } + else { + data = npy_alloc_cache(nbytes); + } + if (data == NULL) { + PyErr_NoMemory(); + goto fail; + } + fa->flags |= NPY_ARRAY_OWNDATA; + + } + else { + /* + * If data is passed in, this object won't own it by default. + * Caller must arrange for this to be reset if truly desired + */ + fa->flags &= ~NPY_ARRAY_OWNDATA; + } + fa->data = data; + + /* + * always update the flags to get the right CONTIGUOUS, ALIGN properties + * not owned data and input strides may not be aligned and on some + * platforms (debian sparc) malloc does not provide enough alignment for + * long double types + */ + PyArray_UpdateFlags((PyArrayObject *)fa, NPY_ARRAY_UPDATE_ALL); + + /* + * call the __array_finalize__ + * method if a subtype. + * If obj is NULL, then call method with Py_None + */ + if ((subtype != &PyArray_Type)) { + PyObject *res, *func, *args; + + func = PyObject_GetAttr((PyObject *)fa, npy_ma_str_array_finalize); + if (func && func != Py_None) { + if (NpyCapsule_Check(func)) { + /* A C-function is stored here */ + PyArray_FinalizeFunc *cfunc; + cfunc = NpyCapsule_AsVoidPtr(func); + Py_DECREF(func); + if (cfunc((PyArrayObject *)fa, obj) < 0) { + goto fail; + } + } + else { + args = PyTuple_New(1); + if (obj == NULL) { + obj=Py_None; + } + Py_INCREF(obj); + PyTuple_SET_ITEM(args, 0, obj); + res = PyObject_Call(func, args, NULL); + Py_DECREF(args); + Py_DECREF(func); + if (res == NULL) { + goto fail; + } + else { + Py_DECREF(res); + } + } + } + else Py_XDECREF(func); + } + return (PyObject *)fa; + + fail: + Py_DECREF(fa); + return NULL; +} + + +/*NUMPY_API + * Generic new array creation routine. + * + * steals a reference to descr. On failure or when dtype->subarray is + * true, dtype will be decrefed. + */ +NPY_NO_EXPORT PyObject * +PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd, + npy_intp *dims, npy_intp *strides, void *data, + int flags, PyObject *obj) +{ + return PyArray_NewFromDescr_int(subtype, descr, nd, + dims, strides, data, + flags, obj, 0, 0); +} + +/*NUMPY_API + * Creates a new array with the same shape as the provided one, + * with possible memory layout order and data type changes. + * + * prototype - The array the new one should be like. + * order - NPY_CORDER - C-contiguous result. + * NPY_FORTRANORDER - Fortran-contiguous result. + * NPY_ANYORDER - Fortran if prototype is Fortran, C otherwise. + * NPY_KEEPORDER - Keeps the axis ordering of prototype. + * dtype - If not NULL, overrides the data type of the result. + * subok - If 1, use the prototype's array subtype, otherwise + * always create a base-class array. + * + * NOTE: If dtype is not NULL, steals the dtype reference. On failure or when + * dtype->subarray is true, dtype will be decrefed. + */ +NPY_NO_EXPORT PyObject * +PyArray_NewLikeArray(PyArrayObject *prototype, NPY_ORDER order, + PyArray_Descr *dtype, int subok) +{ + PyObject *ret = NULL; + int ndim = PyArray_NDIM(prototype); + + /* If no override data type, use the one from the prototype */ + if (dtype == NULL) { + dtype = PyArray_DESCR(prototype); + Py_INCREF(dtype); + } + + /* Handle ANYORDER and simple KEEPORDER cases */ + switch (order) { + case NPY_ANYORDER: + order = PyArray_ISFORTRAN(prototype) ? + NPY_FORTRANORDER : NPY_CORDER; + break; + case NPY_KEEPORDER: + if (PyArray_IS_C_CONTIGUOUS(prototype) || ndim <= 1) { + order = NPY_CORDER; + break; + } + else if (PyArray_IS_F_CONTIGUOUS(prototype)) { + order = NPY_FORTRANORDER; + break; + } + break; + default: + break; + } + + /* If it's not KEEPORDER, this is simple */ + if (order != NPY_KEEPORDER) { + ret = PyArray_NewFromDescr(subok ? Py_TYPE(prototype) : &PyArray_Type, + dtype, + ndim, + PyArray_DIMS(prototype), + NULL, + NULL, + order, + subok ? (PyObject *)prototype : NULL); + } + /* KEEPORDER needs some analysis of the strides */ + else { + npy_intp strides[NPY_MAXDIMS], stride; + npy_intp *shape = PyArray_DIMS(prototype); + npy_stride_sort_item strideperm[NPY_MAXDIMS]; + int idim; + + PyArray_CreateSortedStridePerm(PyArray_NDIM(prototype), + PyArray_STRIDES(prototype), + strideperm); + + /* Build the new strides */ + stride = dtype->elsize; + for (idim = ndim-1; idim >= 0; --idim) { + npy_intp i_perm = strideperm[idim].perm; + strides[i_perm] = stride; + stride *= shape[i_perm]; + } + + /* Finally, allocate the array */ + ret = PyArray_NewFromDescr(subok ? Py_TYPE(prototype) : &PyArray_Type, + dtype, + ndim, + shape, + strides, + NULL, + 0, + subok ? (PyObject *)prototype : NULL); + } + + return ret; +} + +/*NUMPY_API + * Generic new array creation routine. + */ +NPY_NO_EXPORT PyObject * +PyArray_New(PyTypeObject *subtype, int nd, npy_intp *dims, int type_num, + npy_intp *strides, void *data, int itemsize, int flags, + PyObject *obj) +{ + PyArray_Descr *descr; + PyObject *new; + + descr = PyArray_DescrFromType(type_num); + if (descr == NULL) { + return NULL; + } + if (PyDataType_ISUNSIZED(descr)) { + if (itemsize < 1) { + PyErr_SetString(PyExc_ValueError, + "data type must provide an itemsize"); + Py_DECREF(descr); + return NULL; + } + PyArray_DESCR_REPLACE(descr); + descr->elsize = itemsize; + } + new = PyArray_NewFromDescr(subtype, descr, nd, dims, strides, + data, flags, obj); + return new; +} + + +NPY_NO_EXPORT int +_array_from_buffer_3118(PyObject *obj, PyObject **out) +{ + /* PEP 3118 */ + PyObject *memoryview; + Py_buffer *view; + PyArray_Descr *descr = NULL; + PyObject *r; + int nd, flags, k; + Py_ssize_t d; + npy_intp shape[NPY_MAXDIMS], strides[NPY_MAXDIMS]; + + memoryview = PyMemoryView_FromObject(obj); + if (memoryview == NULL) { + PyErr_Clear(); + return -1; + } + + view = PyMemoryView_GET_BUFFER(memoryview); + if (view->format != NULL) { + descr = _descriptor_from_pep3118_format(view->format); + if (descr == NULL) { + PyObject *msg; + msg = PyBytes_FromFormat("Invalid PEP 3118 format string: '%s'", + view->format); + PyErr_WarnEx(PyExc_RuntimeWarning, PyBytes_AS_STRING(msg), 0); + Py_DECREF(msg); + goto fail; + } + + /* Sanity check */ + if (descr->elsize != view->itemsize) { + PyErr_WarnEx(PyExc_RuntimeWarning, + "Item size computed from the PEP 3118 buffer format " + "string does not match the actual item size.", + 0); + goto fail; + } + } + else { + descr = PyArray_DescrNewFromType(NPY_STRING); + descr->elsize = view->itemsize; + } + + nd = view->ndim; + if (view->shape != NULL) { + if (nd >= NPY_MAXDIMS || nd < 0) { + goto fail; + } + for (k = 0; k < nd; ++k) { + if (k >= NPY_MAXDIMS) { + goto fail; + } + shape[k] = view->shape[k]; + } + if (view->strides != NULL) { + for (k = 0; k < nd; ++k) { + strides[k] = view->strides[k]; + } + } + else { + d = view->len; + for (k = 0; k < nd; ++k) { + if (view->shape[k] != 0) { + d /= view->shape[k]; + } + strides[k] = d; + } + } + } + else { + if (nd == 1) { + shape[0] = view->len / view->itemsize; + strides[0] = view->itemsize; + } + else if (nd > 1) { + PyErr_WarnEx(PyExc_RuntimeWarning, + "ndim computed from the PEP 3118 buffer format " + "is greater than 1, but shape is NULL.", + 0); + goto fail; + } + } + + flags = NPY_ARRAY_BEHAVED & (view->readonly ? ~NPY_ARRAY_WRITEABLE : ~0); + r = PyArray_NewFromDescr(&PyArray_Type, descr, + nd, shape, strides, view->buf, + flags, NULL); + if (r == NULL || + PyArray_SetBaseObject((PyArrayObject *)r, memoryview) < 0) { + Py_XDECREF(r); + Py_DECREF(memoryview); + return -1; + } + PyArray_UpdateFlags((PyArrayObject *)r, NPY_ARRAY_UPDATE_ALL); + + *out = r; + return 0; + +fail: + Py_XDECREF(descr); + Py_DECREF(memoryview); + return -1; + +} + +/*NUMPY_API + * Retrieves the array parameters for viewing/converting an arbitrary + * PyObject* to a NumPy array. This allows the "innate type and shape" + * of Python list-of-lists to be discovered without + * actually converting to an array. + * + * In some cases, such as structured arrays and the __array__ interface, + * a data type needs to be used to make sense of the object. When + * this is needed, provide a Descr for 'requested_dtype', otherwise + * provide NULL. This reference is not stolen. Also, if the requested + * dtype doesn't modify the interpretation of the input, out_dtype will + * still get the "innate" dtype of the object, not the dtype passed + * in 'requested_dtype'. + * + * If writing to the value in 'op' is desired, set the boolean + * 'writeable' to 1. This raises an error when 'op' is a scalar, list + * of lists, or other non-writeable 'op'. + * + * Result: When success (0 return value) is returned, either out_arr + * is filled with a non-NULL PyArrayObject and + * the rest of the parameters are untouched, or out_arr is + * filled with NULL, and the rest of the parameters are + * filled. + * + * Typical usage: + * + * PyArrayObject *arr = NULL; + * PyArray_Descr *dtype = NULL; + * int ndim = 0; + * npy_intp dims[NPY_MAXDIMS]; + * + * if (PyArray_GetArrayParamsFromObject(op, NULL, 1, &dtype, + * &ndim, dims, &arr, NULL) < 0) { + * return NULL; + * } + * if (arr == NULL) { + * ... validate/change dtype, validate flags, ndim, etc ... + * // Could make custom strides here too + * arr = PyArray_NewFromDescr(&PyArray_Type, dtype, ndim, + * dims, NULL, + * is_f_order ? NPY_ARRAY_F_CONTIGUOUS : 0, + * NULL); + * if (arr == NULL) { + * return NULL; + * } + * if (PyArray_CopyObject(arr, op) < 0) { + * Py_DECREF(arr); + * return NULL; + * } + * } + * else { + * ... in this case the other parameters weren't filled, just + * validate and possibly copy arr itself ... + * } + * ... use arr ... + */ +NPY_NO_EXPORT int +PyArray_GetArrayParamsFromObject(PyObject *op, + PyArray_Descr *requested_dtype, + npy_bool writeable, + PyArray_Descr **out_dtype, + int *out_ndim, npy_intp *out_dims, + PyArrayObject **out_arr, PyObject *context) +{ + PyObject *tmp; + + /* If op is an array */ + if (PyArray_Check(op)) { + if (writeable + && PyArray_FailUnlessWriteable((PyArrayObject *)op, "array") < 0) { + return -1; + } + Py_INCREF(op); + *out_arr = (PyArrayObject *)op; + return 0; + } + + /* If op is a NumPy scalar */ + if (PyArray_IsScalar(op, Generic)) { + if (writeable) { + PyErr_SetString(PyExc_RuntimeError, + "cannot write to scalar"); + return -1; + } + *out_dtype = PyArray_DescrFromScalar(op); + if (*out_dtype == NULL) { + return -1; + } + *out_ndim = 0; + *out_arr = NULL; + return 0; + } + + /* If op is a Python scalar */ + *out_dtype = _array_find_python_scalar_type(op); + if (*out_dtype != NULL) { + if (writeable) { + PyErr_SetString(PyExc_RuntimeError, + "cannot write to scalar"); + Py_DECREF(*out_dtype); + return -1; + } + *out_ndim = 0; + *out_arr = NULL; + return 0; + } + + /* If op supports the PEP 3118 buffer interface */ + if (!PyBytes_Check(op) && !PyUnicode_Check(op) && + _array_from_buffer_3118(op, (PyObject **)out_arr) == 0) { + if (writeable + && PyArray_FailUnlessWriteable(*out_arr, "PEP 3118 buffer") < 0) { + Py_DECREF(*out_arr); + return -1; + } + return (*out_arr) == NULL ? -1 : 0; + } + + /* If op supports the __array_struct__ or __array_interface__ interface */ + tmp = PyArray_FromStructInterface(op); + if (tmp == NULL) { + return -1; + } + if (tmp == Py_NotImplemented) { + tmp = PyArray_FromInterface(op); + if (tmp == NULL) { + return -1; + } + } + if (tmp != Py_NotImplemented) { + if (writeable + && PyArray_FailUnlessWriteable((PyArrayObject *)tmp, + "array interface object") < 0) { + Py_DECREF(tmp); + return -1; + } + *out_arr = (PyArrayObject *)tmp; + return (*out_arr) == NULL ? -1 : 0; + } + + /* + * If op supplies the __array__ function. + * The documentation says this should produce a copy, so + * we skip this method if writeable is true, because the intent + * of writeable is to modify the operand. + * XXX: If the implementation is wrong, and/or if actual + * usage requires this behave differently, + * this should be changed! + */ + if (!writeable) { + tmp = PyArray_FromArrayAttr(op, requested_dtype, context); + if (tmp != Py_NotImplemented) { + *out_arr = (PyArrayObject *)tmp; + return (*out_arr) == NULL ? -1 : 0; + } + } + + /* Try to treat op as a list of lists */ + if (!writeable && PySequence_Check(op)) { + int check_it, stop_at_string, stop_at_tuple, is_object; + int type_num, type; + + /* + * Determine the type, using the requested data type if + * it will affect how the array is retrieved + */ + if (requested_dtype != NULL && ( + requested_dtype->type_num == NPY_STRING || + requested_dtype->type_num == NPY_UNICODE || + (requested_dtype->type_num == NPY_VOID && + (requested_dtype->names || requested_dtype->subarray)) || + requested_dtype->type == NPY_CHARLTR || + requested_dtype->type_num == NPY_OBJECT)) { + Py_INCREF(requested_dtype); + *out_dtype = requested_dtype; + } + else { + *out_dtype = NULL; + if (PyArray_DTypeFromObject(op, NPY_MAXDIMS, out_dtype) < 0) { + if (PyErr_ExceptionMatches(PyExc_MemoryError)) { + return -1; + } + /* Return NPY_OBJECT for most exceptions */ + else { + PyErr_Clear(); + *out_dtype = PyArray_DescrFromType(NPY_OBJECT); + if (*out_dtype == NULL) { + return -1; + } + } + } + if (*out_dtype == NULL) { + *out_dtype = PyArray_DescrFromType(NPY_DEFAULT_TYPE); + if (*out_dtype == NULL) { + return -1; + } + } + } + + type_num = (*out_dtype)->type_num; + type = (*out_dtype)->type; + + check_it = (type != NPY_CHARLTR); + stop_at_string = (type_num != NPY_STRING) || + (type == NPY_STRINGLTR); + stop_at_tuple = (type_num == NPY_VOID && + ((*out_dtype)->names || (*out_dtype)->subarray)); + + *out_ndim = NPY_MAXDIMS; + is_object = 0; + if (discover_dimensions(op, out_ndim, out_dims, check_it, + stop_at_string, stop_at_tuple, + &is_object) < 0) { + Py_DECREF(*out_dtype); + if (PyErr_Occurred()) { + return -1; + } + *out_dtype = PyArray_DescrFromType(NPY_OBJECT); + if (*out_dtype == NULL) { + return -1; + } + *out_ndim = 0; + *out_arr = NULL; + return 0; + } + /* If object arrays are forced */ + if (is_object) { + Py_DECREF(*out_dtype); + *out_dtype = PyArray_DescrFromType(NPY_OBJECT); + if (*out_dtype == NULL) { + return -1; + } + } + + if ((*out_dtype)->type == NPY_CHARLTR && (*out_ndim) > 0 && + out_dims[(*out_ndim) - 1] == 1) { + (*out_ndim) -= 1; + } + + /* If the type is flexible, determine its size */ + if (PyDataType_ISUNSIZED(*out_dtype) && + PyTypeNum_ISEXTENDED((*out_dtype)->type_num)) { + int itemsize = 0; + int string_type = 0; + if ((*out_dtype)->type_num == NPY_STRING || + (*out_dtype)->type_num == NPY_UNICODE) { + string_type = (*out_dtype)->type_num; + } + if (discover_itemsize(op, *out_ndim, &itemsize, string_type) < 0) { + Py_DECREF(*out_dtype); + if (PyErr_Occurred() && + PyErr_GivenExceptionMatches(PyErr_Occurred(), + PyExc_MemoryError)) { + return -1; + } + /* Say it's an OBJECT scalar if there's an error */ + PyErr_Clear(); + *out_dtype = PyArray_DescrFromType(NPY_OBJECT); + *out_ndim = 0; + *out_arr = NULL; + return 0; + } + if ((*out_dtype)->type_num == NPY_UNICODE) { + itemsize *= 4; + } + + if (itemsize != (*out_dtype)->elsize) { + PyArray_DESCR_REPLACE(*out_dtype); + (*out_dtype)->elsize = itemsize; + } + } + + *out_arr = NULL; + return 0; + } + + /* Anything can be viewed as an object, unless it needs to be writeable */ + if (!writeable) { + *out_dtype = PyArray_DescrFromType(NPY_OBJECT); + if (*out_dtype == NULL) { + return -1; + } + *out_ndim = 0; + *out_arr = NULL; + return 0; + } + + PyErr_SetString(PyExc_RuntimeError, + "object cannot be viewed as a writeable numpy array"); + return -1; +} + +/*NUMPY_API + * Does not check for NPY_ARRAY_ENSURECOPY and NPY_ARRAY_NOTSWAPPED in flags + * Steals a reference to newtype --- which can be NULL + */ +NPY_NO_EXPORT PyObject * +PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth, + int max_depth, int flags, PyObject *context) +{ + /* + * This is the main code to make a NumPy array from a Python + * Object. It is called from many different places. + */ + PyArrayObject *arr = NULL, *ret; + PyArray_Descr *dtype = NULL; + int ndim = 0; + npy_intp dims[NPY_MAXDIMS]; + + /* Get either the array or its parameters if it isn't an array */ + if (PyArray_GetArrayParamsFromObject(op, newtype, + 0, &dtype, + &ndim, dims, &arr, context) < 0) { + Py_XDECREF(newtype); + return NULL; + } + + /* If the requested dtype is flexible, adapt it */ + if (newtype != NULL) { + PyArray_AdaptFlexibleDType(op, + (dtype == NULL) ? PyArray_DESCR(arr) : dtype, + &newtype); + } + + /* If we got dimensions and dtype instead of an array */ + if (arr == NULL) { + if ((flags & NPY_ARRAY_WRITEBACKIFCOPY) || + (flags & NPY_ARRAY_UPDATEIFCOPY)) { + Py_XDECREF(newtype); + PyErr_SetString(PyExc_TypeError, + "WRITEBACKIFCOPY used for non-array input."); + return NULL; + } + else if (min_depth != 0 && ndim < min_depth) { + Py_DECREF(dtype); + Py_XDECREF(newtype); + PyErr_SetString(PyExc_ValueError, + "object of too small depth for desired array"); + ret = NULL; + } + else if (max_depth != 0 && ndim > max_depth) { + Py_DECREF(dtype); + Py_XDECREF(newtype); + PyErr_SetString(PyExc_ValueError, + "object too deep for desired array"); + ret = NULL; + } + else if (ndim == 0 && PyArray_IsScalar(op, Generic)) { + ret = (PyArrayObject *)PyArray_FromScalar(op, newtype); + Py_DECREF(dtype); + } + else { + if (newtype == NULL) { + newtype = dtype; + } + else { + /* + * TODO: would be nice to do this too, but it's + * a behavior change. It's also a bit tricky + * for downcasting to small integer and float + * types, and might be better to modify + * PyArray_AssignFromSequence and descr->f->setitem + * to have a 'casting' parameter and + * to check each value with scalar rules like + * in PyArray_MinScalarType. + */ + /* + if (!(flags&NPY_ARRAY_FORCECAST) && ndim > 0 && + !PyArray_CanCastTo(dtype, newtype)) { + Py_DECREF(dtype); + Py_XDECREF(newtype); + PyErr_SetString(PyExc_TypeError, + "object cannot be safely cast to array " + "of required type"); + return NULL; + } + */ + Py_DECREF(dtype); + } + + /* Create an array and copy the data */ + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, newtype, + ndim, dims, + NULL, NULL, + flags&NPY_ARRAY_F_CONTIGUOUS, NULL); + if (ret == NULL) { + return NULL; + } + + if (ndim > 0) { + if (PyArray_AssignFromSequence(ret, op) < 0) { + Py_DECREF(ret); + ret = NULL; + } + } + else { + if (PyArray_SETITEM(ret, PyArray_DATA(ret), op) < 0) { + Py_DECREF(ret); + ret = NULL; + } + } + } + } + else { + if (min_depth != 0 && PyArray_NDIM(arr) < min_depth) { + PyErr_SetString(PyExc_ValueError, + "object of too small depth for desired array"); + Py_DECREF(arr); + ret = NULL; + } + else if (max_depth != 0 && PyArray_NDIM(arr) > max_depth) { + PyErr_SetString(PyExc_ValueError, + "object too deep for desired array"); + Py_DECREF(arr); + ret = NULL; + } + else { + ret = (PyArrayObject *)PyArray_FromArray(arr, newtype, flags); + Py_DECREF(arr); + } + } + + return (PyObject *)ret; +} + +/* + * flags is any of + * NPY_ARRAY_C_CONTIGUOUS (formerly CONTIGUOUS), + * NPY_ARRAY_F_CONTIGUOUS (formerly FORTRAN), + * NPY_ARRAY_ALIGNED, + * NPY_ARRAY_WRITEABLE, + * NPY_ARRAY_NOTSWAPPED, + * NPY_ARRAY_ENSURECOPY, + * NPY_ARRAY_UPDATEIFCOPY, + * NPY_ARRAY_WRITEBACKIFCOPY, + * NPY_ARRAY_FORCECAST, + * NPY_ARRAY_ENSUREARRAY, + * NPY_ARRAY_ELEMENTSTRIDES + * + * or'd (|) together + * + * Any of these flags present means that the returned array should + * guarantee that aspect of the array. Otherwise the returned array + * won't guarantee it -- it will depend on the object as to whether or + * not it has such features. + * + * Note that NPY_ARRAY_ENSURECOPY is enough + * to guarantee NPY_ARRAY_C_CONTIGUOUS, NPY_ARRAY_ALIGNED and + * NPY_ARRAY_WRITEABLE and therefore it is redundant to include + * those as well. + * + * NPY_ARRAY_BEHAVED == NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE + * NPY_ARRAY_CARRAY = NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_BEHAVED + * NPY_ARRAY_FARRAY = NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_BEHAVED + * + * NPY_ARRAY_F_CONTIGUOUS can be set in the FLAGS to request a FORTRAN array. + * Fortran arrays are always behaved (aligned, + * notswapped, and writeable) and not (C) CONTIGUOUS (if > 1d). + * + * NPY_ARRAY_UPDATEIFCOPY is deprecated in favor of + * NPY_ARRAY_WRITEBACKIFCOPY in 1.14 + + * NPY_ARRAY_WRITEBACKIFCOPY flag sets this flag in the returned + * array if a copy is made and the base argument points to the (possibly) + * misbehaved array. Before returning to python, PyArray_ResolveWritebackIfCopy + * must be called to update the contents of the orignal array from the copy. + * + * NPY_ARRAY_FORCECAST will cause a cast to occur regardless of whether or not + * it is safe. + */ + +/*NUMPY_API + * steals a reference to descr -- accepts NULL + */ +NPY_NO_EXPORT PyObject * +PyArray_CheckFromAny(PyObject *op, PyArray_Descr *descr, int min_depth, + int max_depth, int requires, PyObject *context) +{ + PyObject *obj; + if (requires & NPY_ARRAY_NOTSWAPPED) { + if (!descr && PyArray_Check(op) && + PyArray_ISBYTESWAPPED((PyArrayObject* )op)) { + descr = PyArray_DescrNew(PyArray_DESCR((PyArrayObject *)op)); + } + else if (descr && !PyArray_ISNBO(descr->byteorder)) { + PyArray_DESCR_REPLACE(descr); + } + if (descr && descr->byteorder != NPY_IGNORE) { + descr->byteorder = NPY_NATIVE; + } + } + + obj = PyArray_FromAny(op, descr, min_depth, max_depth, requires, context); + if (obj == NULL) { + return NULL; + } + if ((requires & NPY_ARRAY_ELEMENTSTRIDES) && + !PyArray_ElementStrides(obj)) { + PyObject *ret; + ret = PyArray_NewCopy((PyArrayObject *)obj, NPY_ANYORDER); + Py_DECREF(obj); + obj = ret; + } + return obj; +} + +/*NUMPY_API + * steals reference to newtype --- acc. NULL + */ +NPY_NO_EXPORT PyObject * +PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) +{ + + PyArrayObject *ret = NULL; + int copy = 0; + int arrflags; + PyArray_Descr *oldtype; + NPY_CASTING casting = NPY_SAFE_CASTING; + + oldtype = PyArray_DESCR(arr); + if (newtype == NULL) { + /* + * Check if object is of array with Null newtype. + * If so return it directly instead of checking for casting. + */ + if (flags == 0) { + Py_INCREF(arr); + return (PyObject *)arr; + } + newtype = oldtype; + Py_INCREF(oldtype); + } + if (PyDataType_ISUNSIZED(newtype)) { + PyArray_DESCR_REPLACE(newtype); + if (newtype == NULL) { + return NULL; + } + newtype->elsize = oldtype->elsize; + } + + /* If the casting if forced, use the 'unsafe' casting rule */ + if (flags & NPY_ARRAY_FORCECAST) { + casting = NPY_UNSAFE_CASTING; + } + + /* Raise an error if the casting rule isn't followed */ + if (!PyArray_CanCastArrayTo(arr, newtype, casting)) { + PyObject *errmsg; + PyArray_Descr *arr_descr = NULL; + PyObject *arr_descr_repr = NULL; + PyObject *newtype_repr = NULL; + + PyErr_Clear(); + errmsg = PyUString_FromString("Cannot cast array data from "); + arr_descr = PyArray_DESCR(arr); + if (arr_descr == NULL) { + Py_DECREF(newtype); + Py_DECREF(errmsg); + return NULL; + } + arr_descr_repr = PyObject_Repr((PyObject *)arr_descr); + if (arr_descr_repr == NULL) { + Py_DECREF(newtype); + Py_DECREF(errmsg); + return NULL; + } + PyUString_ConcatAndDel(&errmsg, arr_descr_repr); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + newtype_repr = PyObject_Repr((PyObject *)newtype); + if (newtype_repr == NULL) { + Py_DECREF(newtype); + Py_DECREF(errmsg); + return NULL; + } + PyUString_ConcatAndDel(&errmsg, newtype_repr); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" according to the rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + + Py_DECREF(newtype); + return NULL; + } + + arrflags = PyArray_FLAGS(arr); + /* If a guaranteed copy was requested */ + copy = (flags & NPY_ARRAY_ENSURECOPY) || + /* If C contiguous was requested, and arr is not */ + ((flags & NPY_ARRAY_C_CONTIGUOUS) && + (!(arrflags & NPY_ARRAY_C_CONTIGUOUS))) || + /* If an aligned array was requested, and arr is not */ + ((flags & NPY_ARRAY_ALIGNED) && + (!(arrflags & NPY_ARRAY_ALIGNED))) || + /* If a Fortran contiguous array was requested, and arr is not */ + ((flags & NPY_ARRAY_F_CONTIGUOUS) && + (!(arrflags & NPY_ARRAY_F_CONTIGUOUS))) || + /* If a writeable array was requested, and arr is not */ + ((flags & NPY_ARRAY_WRITEABLE) && + (!(arrflags & NPY_ARRAY_WRITEABLE))) || + !PyArray_EquivTypes(oldtype, newtype); + + if (copy) { + NPY_ORDER order = NPY_KEEPORDER; + int subok = 1; + + /* Set the order for the copy being made based on the flags */ + if (flags & NPY_ARRAY_F_CONTIGUOUS) { + order = NPY_FORTRANORDER; + } + else if (flags & NPY_ARRAY_C_CONTIGUOUS) { + order = NPY_CORDER; + } + + if ((flags & NPY_ARRAY_ENSUREARRAY)) { + subok = 0; + } + ret = (PyArrayObject *)PyArray_NewLikeArray(arr, order, + newtype, subok); + if (ret == NULL) { + return NULL; + } + + if (PyArray_CopyInto(ret, arr) < 0) { + Py_DECREF(ret); + return NULL; + } + + if (flags & NPY_ARRAY_UPDATEIFCOPY) { + /* This is the ONLY place the NPY_ARRAY_UPDATEIFCOPY flag + * is still used. + * Can be deleted once the flag itself is removed + */ + + /* 2017-Nov-10 1.14 */ + if (DEPRECATE("NPY_ARRAY_UPDATEIFCOPY, NPY_ARRAY_INOUT_ARRAY, and " + "NPY_ARRAY_INOUT_FARRAY are deprecated, use NPY_WRITEBACKIFCOPY, " + "NPY_ARRAY_INOUT_ARRAY2, or NPY_ARRAY_INOUT_FARRAY2 respectively " + "instead, and call PyArray_ResolveWritebackIfCopy before the " + "array is deallocated, i.e. before the last call to Py_DECREF.") < 0) + return NULL; + Py_INCREF(arr); + if (PyArray_SetWritebackIfCopyBase(ret, arr) < 0) { + Py_DECREF(ret); + return NULL; + } + PyArray_ENABLEFLAGS(ret, NPY_ARRAY_UPDATEIFCOPY); + PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEBACKIFCOPY); + } + else if (flags & NPY_ARRAY_WRITEBACKIFCOPY) { + Py_INCREF(arr); + if (PyArray_SetWritebackIfCopyBase(ret, arr) < 0) { + Py_DECREF(ret); + return NULL; + } + } + } + /* + * If no copy then take an appropriate view if necessary, or + * just return a reference to ret itself. + */ + else { + int needview = ((flags & NPY_ARRAY_ENSUREARRAY) && + !PyArray_CheckExact(arr)); + + Py_DECREF(newtype); + if (needview) { + PyArray_Descr *dtype = PyArray_DESCR(arr); + PyTypeObject *subtype = NULL; + + if (flags & NPY_ARRAY_ENSUREARRAY) { + subtype = &PyArray_Type; + } + + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_View(arr, NULL, subtype); + if (ret == NULL) { + return NULL; + } + } + else { + Py_INCREF(arr); + ret = arr; + } + } + + return (PyObject *)ret; +} + +/*NUMPY_API */ +NPY_NO_EXPORT PyObject * +PyArray_FromStructInterface(PyObject *input) +{ + PyArray_Descr *thetype = NULL; + char buf[40]; + PyArrayInterface *inter; + PyObject *attr; + PyArrayObject *ret; + char endian = NPY_NATBYTE; + + attr = PyArray_LookupSpecial_OnInstance(input, "__array_struct__"); + if (attr == NULL) { + return Py_NotImplemented; + } + if (!NpyCapsule_Check(attr)) { + goto fail; + } + inter = NpyCapsule_AsVoidPtr(attr); + if (inter->two != 2) { + goto fail; + } + if ((inter->flags & NPY_ARRAY_NOTSWAPPED) != NPY_ARRAY_NOTSWAPPED) { + endian = NPY_OPPBYTE; + inter->flags &= ~NPY_ARRAY_NOTSWAPPED; + } + + if (inter->flags & NPY_ARR_HAS_DESCR) { + if (PyArray_DescrConverter(inter->descr, &thetype) == NPY_FAIL) { + thetype = NULL; + PyErr_Clear(); + } + } + + if (thetype == NULL) { + PyOS_snprintf(buf, sizeof(buf), + "%c%c%d", endian, inter->typekind, inter->itemsize); + if (!(thetype=_array_typedescr_fromstr(buf))) { + Py_DECREF(attr); + return NULL; + } + } + + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, thetype, + inter->nd, inter->shape, + inter->strides, inter->data, + inter->flags, NULL); + Py_INCREF(input); + if (PyArray_SetBaseObject(ret, input) < 0) { + Py_DECREF(ret); + return NULL; + } + Py_DECREF(attr); + PyArray_UpdateFlags(ret, NPY_ARRAY_UPDATE_ALL); + return (PyObject *)ret; + + fail: + PyErr_SetString(PyExc_ValueError, "invalid __array_struct__"); + Py_DECREF(attr); + return NULL; +} + +/* + * Checks if the object in descr is the default 'descr' member for the + * __array_interface__ dictionary with 'typestr' member typestr. + */ +NPY_NO_EXPORT int +_is_default_descr(PyObject *descr, PyObject *typestr) { + PyObject *tuple, *name, *typestr2; +#if defined(NPY_PY3K) + PyObject *tmp = NULL; +#endif + int ret = 0; + + if (!PyList_Check(descr) || PyList_GET_SIZE(descr) != 1) { + return 0; + } + tuple = PyList_GET_ITEM(descr, 0); + if (!(PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2)) { + return 0; + } + name = PyTuple_GET_ITEM(tuple, 0); + if (!(PyUString_Check(name) && PyUString_GET_SIZE(name) == 0)) { + return 0; + } + typestr2 = PyTuple_GET_ITEM(tuple, 1); +#if defined(NPY_PY3K) + /* Allow unicode type strings */ + if (PyUnicode_Check(typestr2)) { + tmp = PyUnicode_AsASCIIString(typestr2); + if (tmp == NULL) { + return 0; + } + typestr2 = tmp; + } +#endif + if (PyBytes_Check(typestr2) && + PyObject_RichCompareBool(typestr, typestr2, Py_EQ)) { + ret = 1; + } +#if defined(NPY_PY3K) + Py_XDECREF(tmp); +#endif + + return ret; +} + +#define PyIntOrLong_Check(obj) (PyInt_Check(obj) || PyLong_Check(obj)) + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_FromInterface(PyObject *origin) +{ + PyObject *tmp = NULL; + PyObject *iface = NULL; + PyObject *attr = NULL; + PyObject *base = NULL; + PyArrayObject *ret; + PyArray_Descr *dtype = NULL; + char *data = NULL; + Py_ssize_t buffer_len; + int res, i, n; + npy_intp dims[NPY_MAXDIMS], strides[NPY_MAXDIMS]; + int dataflags = NPY_ARRAY_BEHAVED; + + iface = PyArray_LookupSpecial_OnInstance(origin, + "__array_interface__"); + if (iface == NULL) { + return Py_NotImplemented; + } + if (!PyDict_Check(iface)) { + Py_DECREF(iface); + PyErr_SetString(PyExc_ValueError, + "Invalid __array_interface__ value, must be a dict"); + return NULL; + } + + /* Get type string from interface specification */ + attr = PyDict_GetItemString(iface, "typestr"); + if (attr == NULL) { + Py_DECREF(iface); + PyErr_SetString(PyExc_ValueError, + "Missing __array_interface__ typestr"); + return NULL; + } +#if defined(NPY_PY3K) + /* Allow unicode type strings */ + if (PyUnicode_Check(attr)) { + tmp = PyUnicode_AsASCIIString(attr); + attr = tmp; + } +#endif + if (!PyBytes_Check(attr)) { + PyErr_SetString(PyExc_TypeError, + "__array_interface__ typestr must be a string"); + goto fail; + } + /* Get dtype from type string */ + dtype = _array_typedescr_fromstr(PyString_AS_STRING(attr)); +#if defined(NPY_PY3K) + if (tmp == attr) { + Py_DECREF(tmp); + } +#endif + if (dtype == NULL) { + goto fail; + } + + /* + * If the dtype is NPY_VOID, see if there is extra information in + * the 'descr' attribute. + */ + if (dtype->type_num == NPY_VOID) { + PyObject *descr = PyDict_GetItemString(iface, "descr"); + PyArray_Descr *new_dtype = NULL; + + if (descr != NULL && !_is_default_descr(descr, attr) && + PyArray_DescrConverter2(descr, &new_dtype) == NPY_SUCCEED && + new_dtype != NULL) { + Py_DECREF(dtype); + dtype = new_dtype; + } + } + + /* Get shape tuple from interface specification */ + attr = PyDict_GetItemString(iface, "shape"); + if (attr == NULL) { + /* Shape must be specified when 'data' is specified */ + if (PyDict_GetItemString(iface, "data") != NULL) { + Py_DECREF(iface); + PyErr_SetString(PyExc_ValueError, + "Missing __array_interface__ shape"); + return NULL; + } + /* Assume shape as scalar otherwise */ + else { + /* NOTE: pointers to data and base should be NULL */ + n = dims[0] = 0; + } + } + /* Make sure 'shape' is a tuple */ + else if (!PyTuple_Check(attr)) { + PyErr_SetString(PyExc_TypeError, + "shape must be a tuple"); + goto fail; + } + /* Get dimensions from shape tuple */ + else { + n = PyTuple_GET_SIZE(attr); + for (i = 0; i < n; i++) { + tmp = PyTuple_GET_ITEM(attr, i); + dims[i] = PyArray_PyIntAsIntp(tmp); + if (error_converting(dims[i])) { + goto fail; + } + } + } + + /* Get data buffer from interface specification */ + attr = PyDict_GetItemString(iface, "data"); + + /* Case for data access through pointer */ + if (attr && PyTuple_Check(attr)) { + PyObject *dataptr; + if (PyTuple_GET_SIZE(attr) != 2) { + PyErr_SetString(PyExc_TypeError, + "__array_interface__ data must be a 2-tuple with " + "(data pointer integer, read-only flag)"); + goto fail; + } + dataptr = PyTuple_GET_ITEM(attr, 0); + if (PyString_Check(dataptr)) { + res = sscanf(PyString_AsString(dataptr), + "%p", (void **)&data); + if (res < 1) { + PyErr_SetString(PyExc_TypeError, + "__array_interface__ data string cannot be converted"); + goto fail; + } + } + else if (PyIntOrLong_Check(dataptr)) { + data = PyLong_AsVoidPtr(dataptr); + } + else { + PyErr_SetString(PyExc_TypeError, + "first element of __array_interface__ data tuple " + "must be integer or string."); + goto fail; + } + if (PyObject_IsTrue(PyTuple_GET_ITEM(attr,1))) { + dataflags &= ~NPY_ARRAY_WRITEABLE; + } + base = origin; + } + + /* Case for data access through buffer */ + else if (attr) { + if (attr != Py_None) { + base = attr; + } + else { + base = origin; + } + res = PyObject_AsWriteBuffer(base, (void **)&data, &buffer_len); + if (res < 0) { + PyErr_Clear(); + res = PyObject_AsReadBuffer( + base, (const void **)&data, &buffer_len); + if (res < 0) { + goto fail; + } + dataflags &= ~NPY_ARRAY_WRITEABLE; + } + /* Get offset number from interface specification */ + attr = PyDict_GetItemString(origin, "offset"); + if (attr) { + npy_longlong num = PyLong_AsLongLong(attr); + if (error_converting(num)) { + PyErr_SetString(PyExc_TypeError, + "__array_interface__ offset must be an integer"); + goto fail; + } + data += num; + } + } + + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, + n, dims, + NULL, data, + dataflags, NULL); + if (ret == NULL) { + goto fail; + } + if (data == NULL) { + if (PyArray_SIZE(ret) > 1) { + PyErr_SetString(PyExc_ValueError, + "cannot coerce scalar to array with size > 1"); + Py_DECREF(ret); + goto fail; + } + if (PyArray_SETITEM(ret, PyArray_DATA(ret), origin) < 0) { + Py_DECREF(ret); + goto fail; + } + } + if (base) { + Py_INCREF(base); + if (PyArray_SetBaseObject(ret, base) < 0) { + Py_DECREF(ret); + goto fail; + } + } + attr = PyDict_GetItemString(iface, "strides"); + if (attr != NULL && attr != Py_None) { + if (!PyTuple_Check(attr)) { + PyErr_SetString(PyExc_TypeError, + "strides must be a tuple"); + Py_DECREF(ret); + goto fail; + } + if (n != PyTuple_GET_SIZE(attr)) { + PyErr_SetString(PyExc_ValueError, + "mismatch in length of strides and shape"); + Py_DECREF(ret); + goto fail; + } + for (i = 0; i < n; i++) { + tmp = PyTuple_GET_ITEM(attr, i); + strides[i] = PyArray_PyIntAsIntp(tmp); + if (error_converting(strides[i])) { + Py_DECREF(ret); + goto fail; + } + } + memcpy(PyArray_STRIDES(ret), strides, n*sizeof(npy_intp)); + } + PyArray_UpdateFlags(ret, NPY_ARRAY_UPDATE_ALL); + Py_DECREF(iface); + return (PyObject *)ret; + + fail: + Py_XDECREF(dtype); + Py_XDECREF(iface); + return NULL; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) +{ + PyObject *new; + PyObject *array_meth; + + array_meth = PyArray_LookupSpecial_OnInstance(op, "__array__"); + if (array_meth == NULL) { + return Py_NotImplemented; + } + if (context == NULL) { + if (typecode == NULL) { + new = PyObject_CallFunction(array_meth, NULL); + } + else { + new = PyObject_CallFunction(array_meth, "O", typecode); + } + } + else { + if (typecode == NULL) { + new = PyObject_CallFunction(array_meth, "OO", Py_None, context); + if (new == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + new = PyObject_CallFunction(array_meth, ""); + } + } + else { + new = PyObject_CallFunction(array_meth, "OO", typecode, context); + if (new == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + new = PyObject_CallFunction(array_meth, "O", typecode); + } + } + } + Py_DECREF(array_meth); + if (new == NULL) { + return NULL; + } + if (!PyArray_Check(new)) { + PyErr_SetString(PyExc_ValueError, + "object __array__ method not " \ + "producing an array"); + Py_DECREF(new); + return NULL; + } + return new; +} + +/*NUMPY_API +* new reference -- accepts NULL for mintype +*/ +NPY_NO_EXPORT PyArray_Descr * +PyArray_DescrFromObject(PyObject *op, PyArray_Descr *mintype) +{ + PyArray_Descr *dtype; + + dtype = mintype; + Py_XINCREF(dtype); + + if (PyArray_DTypeFromObject(op, NPY_MAXDIMS, &dtype) < 0) { + return NULL; + } + + if (dtype == NULL) { + return PyArray_DescrFromType(NPY_DEFAULT_TYPE); + } + else { + return dtype; + } +} + +/* These are also old calls (should use PyArray_NewFromDescr) */ + +/* They all zero-out the memory as previously done */ + +/* steals reference to descr -- and enforces native byteorder on it.*/ +/*NUMPY_API + Like FromDimsAndData but uses the Descr structure instead of typecode + as input. +*/ +NPY_NO_EXPORT PyObject * +PyArray_FromDimsAndDataAndDescr(int nd, int *d, + PyArray_Descr *descr, + char *data) +{ + PyObject *ret; + int i; + npy_intp newd[NPY_MAXDIMS]; + char msg[] = "PyArray_FromDimsAndDataAndDescr: use PyArray_NewFromDescr."; + + if (DEPRECATE(msg) < 0) { + /* 2009-04-30, 1.5 */ + return NULL; + } + if (!PyArray_ISNBO(descr->byteorder)) + descr->byteorder = '='; + for (i = 0; i < nd; i++) { + newd[i] = (npy_intp) d[i]; + } + ret = PyArray_NewFromDescr(&PyArray_Type, descr, + nd, newd, + NULL, data, + (data ? NPY_ARRAY_CARRAY : 0), NULL); + return ret; +} + +/*NUMPY_API + Construct an empty array from dimensions and typenum +*/ +NPY_NO_EXPORT PyObject * +PyArray_FromDims(int nd, int *d, int type) +{ + PyArrayObject *ret; + char msg[] = "PyArray_FromDims: use PyArray_SimpleNew."; + + if (DEPRECATE(msg) < 0) { + /* 2009-04-30, 1.5 */ + return NULL; + } + ret = (PyArrayObject *)PyArray_FromDimsAndDataAndDescr(nd, d, + PyArray_DescrFromType(type), + NULL); + /* + * Old FromDims set memory to zero --- some algorithms + * relied on that. Better keep it the same. If + * Object type, then it's already been set to zero, though. + */ + if (ret && (PyArray_DESCR(ret)->type_num != NPY_OBJECT)) { + memset(PyArray_DATA(ret), 0, PyArray_NBYTES(ret)); + } + return (PyObject *)ret; +} + +/* end old calls */ + +/*NUMPY_API + * This is a quick wrapper around + * PyArray_FromAny(op, NULL, 0, 0, NPY_ARRAY_ENSUREARRAY, NULL) + * that special cases Arrays and PyArray_Scalars up front + * It *steals a reference* to the object + * It also guarantees that the result is PyArray_Type + * Because it decrefs op if any conversion needs to take place + * so it can be used like PyArray_EnsureArray(some_function(...)) + */ +NPY_NO_EXPORT PyObject * +PyArray_EnsureArray(PyObject *op) +{ + PyObject *new; + + if ((op == NULL) || (PyArray_CheckExact(op))) { + new = op; + Py_XINCREF(new); + } + else if (PyArray_Check(op)) { + new = PyArray_View((PyArrayObject *)op, NULL, &PyArray_Type); + } + else if (PyArray_IsScalar(op, Generic)) { + new = PyArray_FromScalar(op, NULL); + } + else { + new = PyArray_FROM_OF(op, NPY_ARRAY_ENSUREARRAY); + } + Py_XDECREF(op); + return new; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_EnsureAnyArray(PyObject *op) +{ + if (op && PyArray_Check(op)) { + return op; + } + return PyArray_EnsureArray(op); +} + +/* TODO: Put the order parameter in PyArray_CopyAnyInto and remove this */ +NPY_NO_EXPORT int +PyArray_CopyAsFlat(PyArrayObject *dst, PyArrayObject *src, NPY_ORDER order) +{ + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + NpyIter *dst_iter, *src_iter; + + NpyIter_IterNextFunc *dst_iternext, *src_iternext; + char **dst_dataptr, **src_dataptr; + npy_intp dst_stride, src_stride; + npy_intp *dst_countptr, *src_countptr; + npy_uint32 baseflags; + + char *dst_data, *src_data; + npy_intp dst_count, src_count, count; + npy_intp src_itemsize; + npy_intp dst_size, src_size; + int needs_api; + + NPY_BEGIN_THREADS_DEF; + + if (PyArray_FailUnlessWriteable(dst, "destination array") < 0) { + return -1; + } + + /* + * If the shapes match and a particular order is forced + * for both, use the more efficient CopyInto + */ + if (order != NPY_ANYORDER && order != NPY_KEEPORDER && + PyArray_NDIM(dst) == PyArray_NDIM(src) && + PyArray_CompareLists(PyArray_DIMS(dst), PyArray_DIMS(src), + PyArray_NDIM(dst))) { + return PyArray_CopyInto(dst, src); + } + + dst_size = PyArray_SIZE(dst); + src_size = PyArray_SIZE(src); + if (dst_size != src_size) { + PyErr_Format(PyExc_ValueError, + "cannot copy from array of size %d into an array " + "of size %d", (int)src_size, (int)dst_size); + return -1; + } + + /* Zero-sized arrays require nothing be done */ + if (dst_size == 0) { + return 0; + } + + baseflags = NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_DONT_NEGATE_STRIDES | + NPY_ITER_REFS_OK; + + /* + * This copy is based on matching C-order traversals of src and dst. + * By using two iterators, we can find maximal sub-chunks that + * can be processed at once. + */ + dst_iter = NpyIter_New(dst, NPY_ITER_WRITEONLY | baseflags, + order, + NPY_NO_CASTING, + NULL); + if (dst_iter == NULL) { + return -1; + } + src_iter = NpyIter_New(src, NPY_ITER_READONLY | baseflags, + order, + NPY_NO_CASTING, + NULL); + if (src_iter == NULL) { + NpyIter_Deallocate(dst_iter); + return -1; + } + + /* Get all the values needed for the inner loop */ + dst_iternext = NpyIter_GetIterNext(dst_iter, NULL); + dst_dataptr = NpyIter_GetDataPtrArray(dst_iter); + /* Since buffering is disabled, we can cache the stride */ + dst_stride = NpyIter_GetInnerStrideArray(dst_iter)[0]; + dst_countptr = NpyIter_GetInnerLoopSizePtr(dst_iter); + + src_iternext = NpyIter_GetIterNext(src_iter, NULL); + src_dataptr = NpyIter_GetDataPtrArray(src_iter); + /* Since buffering is disabled, we can cache the stride */ + src_stride = NpyIter_GetInnerStrideArray(src_iter)[0]; + src_countptr = NpyIter_GetInnerLoopSizePtr(src_iter); + src_itemsize = PyArray_DESCR(src)->elsize; + + if (dst_iternext == NULL || src_iternext == NULL) { + NpyIter_Deallocate(dst_iter); + NpyIter_Deallocate(src_iter); + return -1; + } + + needs_api = NpyIter_IterationNeedsAPI(dst_iter) || + NpyIter_IterationNeedsAPI(src_iter); + + /* + * Because buffering is disabled in the iterator, the inner loop + * strides will be the same throughout the iteration loop. Thus, + * we can pass them to this function to take advantage of + * contiguous strides, etc. + */ + if (PyArray_GetDTypeTransferFunction( + PyArray_ISALIGNED(src) && PyArray_ISALIGNED(dst), + src_stride, dst_stride, + PyArray_DESCR(src), PyArray_DESCR(dst), + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + NpyIter_Deallocate(dst_iter); + NpyIter_Deallocate(src_iter); + return -1; + } + + if (!needs_api) { + NPY_BEGIN_THREADS; + } + + dst_count = *dst_countptr; + src_count = *src_countptr; + dst_data = dst_dataptr[0]; + src_data = src_dataptr[0]; + for(;;) { + /* Transfer the biggest amount that fits both */ + count = (src_count < dst_count) ? src_count : dst_count; + stransfer(dst_data, dst_stride, + src_data, src_stride, + count, src_itemsize, transferdata); + + /* If we exhausted the dst block, refresh it */ + if (dst_count == count) { + if (!dst_iternext(dst_iter)) { + break; + } + dst_count = *dst_countptr; + dst_data = dst_dataptr[0]; + } + else { + dst_count -= count; + dst_data += count*dst_stride; + } + + /* If we exhausted the src block, refresh it */ + if (src_count == count) { + if (!src_iternext(src_iter)) { + break; + } + src_count = *src_countptr; + src_data = src_dataptr[0]; + } + else { + src_count -= count; + src_data += count*src_stride; + } + } + + NPY_END_THREADS; + + NPY_AUXDATA_FREE(transferdata); + NpyIter_Deallocate(dst_iter); + NpyIter_Deallocate(src_iter); + + return PyErr_Occurred() ? -1 : 0; +} + +/*NUMPY_API + * Copy an Array into another array -- memory must not overlap + * Does not require src and dest to have "broadcastable" shapes + * (only the same number of elements). + * + * TODO: For NumPy 2.0, this could accept an order parameter which + * only allows NPY_CORDER and NPY_FORDER. Could also rename + * this to CopyAsFlat to make the name more intuitive. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyArray_CopyAnyInto(PyArrayObject *dst, PyArrayObject *src) +{ + return PyArray_CopyAsFlat(dst, src, NPY_CORDER); +} + +/*NUMPY_API + * Copy an Array into another array. + * Broadcast to the destination shape if necessary. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_CopyInto(PyArrayObject *dst, PyArrayObject *src) +{ + return PyArray_AssignArray(dst, src, NULL, NPY_UNSAFE_CASTING); +} + +/*NUMPY_API + * Move the memory of one array into another, allowing for overlapping data. + * + * Returns 0 on success, negative on failure. + */ +NPY_NO_EXPORT int +PyArray_MoveInto(PyArrayObject *dst, PyArrayObject *src) +{ + return PyArray_AssignArray(dst, src, NULL, NPY_UNSAFE_CASTING); +} + +/*NUMPY_API + * PyArray_CheckAxis + * + * check that axis is valid + * convert 0-d arrays to 1-d arrays + */ +NPY_NO_EXPORT PyObject * +PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags) +{ + PyObject *temp1, *temp2; + int n = PyArray_NDIM(arr); + + if (*axis == NPY_MAXDIMS || n == 0) { + if (n != 1) { + temp1 = PyArray_Ravel(arr,0); + if (temp1 == NULL) { + *axis = 0; + return NULL; + } + if (*axis == NPY_MAXDIMS) { + *axis = PyArray_NDIM((PyArrayObject *)temp1)-1; + } + } + else { + temp1 = (PyObject *)arr; + Py_INCREF(temp1); + *axis = 0; + } + if (!flags && *axis == 0) { + return temp1; + } + } + else { + temp1 = (PyObject *)arr; + Py_INCREF(temp1); + } + if (flags) { + temp2 = PyArray_CheckFromAny((PyObject *)temp1, NULL, + 0, 0, flags, NULL); + Py_DECREF(temp1); + if (temp2 == NULL) { + return NULL; + } + } + else { + temp2 = (PyObject *)temp1; + } + n = PyArray_NDIM((PyArrayObject *)temp2); + if (check_and_adjust_axis(axis, n) < 0) { + Py_DECREF(temp2); + return NULL; + } + return temp2; +} + +/*NUMPY_API + * Zeros + * + * steals a reference to type. On failure or when dtype->subarray is + * true, dtype will be decrefed. + * accepts NULL type + */ +NPY_NO_EXPORT PyObject * +PyArray_Zeros(int nd, npy_intp *dims, PyArray_Descr *type, int is_f_order) +{ + PyArrayObject *ret; + + if (!type) { + type = PyArray_DescrFromType(NPY_DEFAULT_TYPE); + } + + ret = (PyArrayObject *)PyArray_NewFromDescr_int(&PyArray_Type, + type, + nd, dims, + NULL, NULL, + is_f_order, NULL, 1, 0); + + if (ret == NULL) { + return NULL; + } + + /* handle objects */ + if (PyDataType_REFCHK(PyArray_DESCR(ret))) { + if (_zerofill(ret) < 0) { + Py_DECREF(ret); + return NULL; + } + } + + + return (PyObject *)ret; + +} + +/*NUMPY_API + * Empty + * + * accepts NULL type + * steals referenct to type + */ +NPY_NO_EXPORT PyObject * +PyArray_Empty(int nd, npy_intp *dims, PyArray_Descr *type, int is_f_order) +{ + PyArrayObject *ret; + + if (!type) type = PyArray_DescrFromType(NPY_DEFAULT_TYPE); + + /* + * PyArray_NewFromDescr steals a ref, + * but we need to look at type later. + * */ + Py_INCREF(type); + + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + type, nd, dims, + NULL, NULL, + is_f_order, NULL); + if (ret != NULL && PyDataType_REFCHK(type)) { + PyArray_FillObjectArray(ret, Py_None); + if (PyErr_Occurred()) { + Py_DECREF(ret); + Py_DECREF(type); + return NULL; + } + } + + Py_DECREF(type); + return (PyObject *)ret; +} + +/* + * Like ceil(value), but check for overflow. + * + * Return 0 on success, -1 on failure. In case of failure, set a PyExc_Overflow + * exception + */ +static npy_intp +_arange_safe_ceil_to_intp(double value) +{ + double ivalue; + + ivalue = npy_ceil(value); + /* condition inverted to handle NaN */ + if (npy_isnan(ivalue)) { + PyErr_SetString(PyExc_ValueError, + "arange: cannot compute length"); + return -1; + } + if (!(NPY_MIN_INTP <= ivalue && ivalue <= NPY_MAX_INTP)) { + PyErr_SetString(PyExc_OverflowError, + "arange: overflow while computing length"); + return -1; + } + + return (npy_intp)ivalue; +} + + +/*NUMPY_API + Arange, +*/ +NPY_NO_EXPORT PyObject * +PyArray_Arange(double start, double stop, double step, int type_num) +{ + npy_intp length; + PyArrayObject *range; + PyArray_ArrFuncs *funcs; + PyObject *obj; + int ret; + NPY_BEGIN_THREADS_DEF; + + length = _arange_safe_ceil_to_intp((stop - start)/step); + if (error_converting(length)) { + return NULL; + } + + if (length <= 0) { + length = 0; + return PyArray_New(&PyArray_Type, 1, &length, type_num, + NULL, NULL, 0, 0, NULL); + } + range = (PyArrayObject *)PyArray_New(&PyArray_Type, 1, &length, type_num, + NULL, NULL, 0, 0, NULL); + if (range == NULL) { + return NULL; + } + funcs = PyArray_DESCR(range)->f; + + /* + * place start in the buffer and the next value in the second position + * if length > 2, then call the inner loop, otherwise stop + */ + obj = PyFloat_FromDouble(start); + ret = funcs->setitem(obj, PyArray_DATA(range), range); + Py_DECREF(obj); + if (ret < 0) { + goto fail; + } + if (length == 1) { + return (PyObject *)range; + } + obj = PyFloat_FromDouble(start + step); + ret = funcs->setitem(obj, PyArray_BYTES(range)+PyArray_ITEMSIZE(range), + range); + Py_DECREF(obj); + if (ret < 0) { + goto fail; + } + if (length == 2) { + return (PyObject *)range; + } + if (!funcs->fill) { + PyErr_SetString(PyExc_ValueError, + "no fill-function for data-type."); + Py_DECREF(range); + return NULL; + } + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(range)); + funcs->fill(PyArray_DATA(range), length, range); + NPY_END_THREADS; + if (PyErr_Occurred()) { + goto fail; + } + return (PyObject *)range; + + fail: + Py_DECREF(range); + return NULL; +} + +/* + * the formula is len = (intp) ceil((stop - start) / step); + */ +static npy_intp +_calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, int cmplx) +{ + npy_intp len, tmp; + PyObject *val; + double value; + + *next = PyNumber_Subtract(stop, start); + if (!(*next)) { + if (PyTuple_Check(stop)) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "arange: scalar arguments expected "\ + "instead of a tuple."); + } + return -1; + } + val = PyNumber_TrueDivide(*next, step); + Py_DECREF(*next); + *next = NULL; + if (!val) { + return -1; + } + if (cmplx && PyComplex_Check(val)) { + value = PyComplex_RealAsDouble(val); + if (error_converting(value)) { + Py_DECREF(val); + return -1; + } + len = _arange_safe_ceil_to_intp(value); + if (error_converting(len)) { + Py_DECREF(val); + return -1; + } + value = PyComplex_ImagAsDouble(val); + Py_DECREF(val); + if (error_converting(value)) { + return -1; + } + tmp = _arange_safe_ceil_to_intp(value); + if (error_converting(tmp)) { + return -1; + } + len = PyArray_MIN(len, tmp); + } + else { + value = PyFloat_AsDouble(val); + Py_DECREF(val); + if (error_converting(value)) { + return -1; + } + len = _arange_safe_ceil_to_intp(value); + if (error_converting(len)) { + return -1; + } + } + if (len > 0) { + *next = PyNumber_Add(start, step); + if (!*next) { + return -1; + } + } + return len; +} + +/*NUMPY_API + * + * ArangeObj, + * + * this doesn't change the references + */ +NPY_NO_EXPORT PyObject * +PyArray_ArangeObj(PyObject *start, PyObject *stop, PyObject *step, PyArray_Descr *dtype) +{ + PyArrayObject *range; + PyArray_ArrFuncs *funcs; + PyObject *next, *err; + npy_intp length; + PyArray_Descr *native = NULL; + int swap; + NPY_BEGIN_THREADS_DEF; + + /* Datetime arange is handled specially */ + if ((dtype != NULL && (dtype->type_num == NPY_DATETIME || + dtype->type_num == NPY_TIMEDELTA)) || + (dtype == NULL && (is_any_numpy_datetime_or_timedelta(start) || + is_any_numpy_datetime_or_timedelta(stop) || + is_any_numpy_datetime_or_timedelta(step)))) { + return (PyObject *)datetime_arange(start, stop, step, dtype); + } + + if (!dtype) { + PyArray_Descr *deftype; + PyArray_Descr *newtype; + + /* intentionally made to be at least NPY_LONG */ + deftype = PyArray_DescrFromType(NPY_LONG); + newtype = PyArray_DescrFromObject(start, deftype); + Py_DECREF(deftype); + if (newtype == NULL) { + return NULL; + } + deftype = newtype; + if (stop && stop != Py_None) { + newtype = PyArray_DescrFromObject(stop, deftype); + Py_DECREF(deftype); + if (newtype == NULL) { + return NULL; + } + deftype = newtype; + } + if (step && step != Py_None) { + newtype = PyArray_DescrFromObject(step, deftype); + Py_DECREF(deftype); + if (newtype == NULL) { + return NULL; + } + deftype = newtype; + } + dtype = deftype; + } + else { + Py_INCREF(dtype); + } + if (!step || step == Py_None) { + step = PyInt_FromLong(1); + } + else { + Py_XINCREF(step); + } + if (!stop || stop == Py_None) { + stop = start; + start = PyInt_FromLong(0); + } + else { + Py_INCREF(start); + } + /* calculate the length and next = start + step*/ + length = _calc_length(start, stop, step, &next, + PyTypeNum_ISCOMPLEX(dtype->type_num)); + err = PyErr_Occurred(); + if (err) { + Py_DECREF(dtype); + if (err && PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { + PyErr_SetString(PyExc_ValueError, "Maximum allowed size exceeded"); + } + goto fail; + } + if (length <= 0) { + length = 0; + range = (PyArrayObject *)PyArray_SimpleNewFromDescr(1, &length, dtype); + Py_DECREF(step); + Py_DECREF(start); + return (PyObject *)range; + } + + /* + * If dtype is not in native byte-order then get native-byte + * order version. And then swap on the way out. + */ + if (!PyArray_ISNBO(dtype->byteorder)) { + native = PyArray_DescrNewByteorder(dtype, NPY_NATBYTE); + swap = 1; + } + else { + native = dtype; + swap = 0; + } + + range = (PyArrayObject *)PyArray_SimpleNewFromDescr(1, &length, native); + if (range == NULL) { + goto fail; + } + + /* + * place start in the buffer and the next value in the second position + * if length > 2, then call the inner loop, otherwise stop + */ + funcs = PyArray_DESCR(range)->f; + if (funcs->setitem(start, PyArray_DATA(range), range) < 0) { + goto fail; + } + if (length == 1) { + goto finish; + } + if (funcs->setitem(next, PyArray_BYTES(range)+PyArray_ITEMSIZE(range), + range) < 0) { + goto fail; + } + if (length == 2) { + goto finish; + } + if (!funcs->fill) { + PyErr_SetString(PyExc_ValueError, "no fill-function for data-type."); + Py_DECREF(range); + goto fail; + } + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(range)); + funcs->fill(PyArray_DATA(range), length, range); + NPY_END_THREADS; + if (PyErr_Occurred()) { + goto fail; + } + finish: + /* TODO: This swapping could be handled on the fly by the nditer */ + if (swap) { + PyObject *new; + new = PyArray_Byteswap(range, 1); + Py_DECREF(new); + Py_DECREF(PyArray_DESCR(range)); + /* steals the reference */ + ((PyArrayObject_fields *)range)->descr = dtype; + } + Py_DECREF(start); + Py_DECREF(step); + Py_DECREF(next); + return (PyObject *)range; + + fail: + Py_DECREF(start); + Py_DECREF(step); + Py_XDECREF(next); + return NULL; +} + +static PyArrayObject * +array_fromfile_binary(FILE *fp, PyArray_Descr *dtype, npy_intp num, size_t *nread) +{ + PyArrayObject *r; + npy_off_t start, numbytes; + + if (num < 0) { + int fail = 0; + start = npy_ftell(fp); + if (start < 0) { + fail = 1; + } + if (npy_fseek(fp, 0, SEEK_END) < 0) { + fail = 1; + } + numbytes = npy_ftell(fp); + if (numbytes < 0) { + fail = 1; + } + numbytes -= start; + if (npy_fseek(fp, start, SEEK_SET) < 0) { + fail = 1; + } + if (fail) { + PyErr_SetString(PyExc_IOError, + "could not seek in file"); + Py_DECREF(dtype); + return NULL; + } + num = numbytes / dtype->elsize; + } + /* + * When dtype->subarray is true, PyArray_NewFromDescr will decref dtype + * even on success, so make sure it stays around until exit. + */ + Py_INCREF(dtype); + r = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, 1, &num, + NULL, NULL, 0, NULL); + if (r == NULL) { + Py_DECREF(dtype); + return NULL; + } + NPY_BEGIN_ALLOW_THREADS; + *nread = fread(PyArray_DATA(r), dtype->elsize, num, fp); + NPY_END_ALLOW_THREADS; + Py_DECREF(dtype); + return r; +} + +/* + * Create an array by reading from the given stream, using the passed + * next_element and skip_separator functions. + */ +#define FROM_BUFFER_SIZE 4096 +static PyArrayObject * +array_from_text(PyArray_Descr *dtype, npy_intp num, char *sep, size_t *nread, + void *stream, next_element next, skip_separator skip_sep, + void *stream_data) +{ + PyArrayObject *r; + npy_intp i; + char *dptr, *clean_sep, *tmp; + int err = 0; + npy_intp thisbuf = 0; + npy_intp size; + npy_intp bytes, totalbytes; + + size = (num >= 0) ? num : FROM_BUFFER_SIZE; + + /* + * When dtype->subarray is true, PyArray_NewFromDescr will decref dtype + * even on success, so make sure it stays around until exit. + */ + Py_INCREF(dtype); + r = (PyArrayObject *) + PyArray_NewFromDescr(&PyArray_Type, dtype, 1, &size, + NULL, NULL, 0, NULL); + if (r == NULL) { + Py_DECREF(dtype); + return NULL; + } + clean_sep = swab_separator(sep); + if (clean_sep == NULL) { + err = 1; + goto fail; + } + + NPY_BEGIN_ALLOW_THREADS; + totalbytes = bytes = size * dtype->elsize; + dptr = PyArray_DATA(r); + for (i= 0; num < 0 || i < num; i++) { + if (next(&stream, dptr, dtype, stream_data) < 0) { + /* EOF */ + break; + } + *nread += 1; + thisbuf += 1; + dptr += dtype->elsize; + if (num < 0 && thisbuf == size) { + totalbytes += bytes; + tmp = PyDataMem_RENEW(PyArray_DATA(r), totalbytes); + if (tmp == NULL) { + err = 1; + break; + } + ((PyArrayObject_fields *)r)->data = tmp; + dptr = tmp + (totalbytes - bytes); + thisbuf = 0; + } + if (skip_sep(&stream, clean_sep, stream_data) < 0) { + break; + } + } + if (num < 0) { + tmp = PyDataMem_RENEW(PyArray_DATA(r), PyArray_MAX(*nread,1)*dtype->elsize); + if (tmp == NULL) { + err = 1; + } + else { + PyArray_DIMS(r)[0] = *nread; + ((PyArrayObject_fields *)r)->data = tmp; + } + } + NPY_END_ALLOW_THREADS; + free(clean_sep); + +fail: + Py_DECREF(dtype); + if (err == 1) { + PyErr_NoMemory(); + } + if (PyErr_Occurred()) { + Py_DECREF(r); + return NULL; + } + return r; +} +#undef FROM_BUFFER_SIZE + +/*NUMPY_API + * + * Given a ``FILE *`` pointer ``fp``, and a ``PyArray_Descr``, return an + * array corresponding to the data encoded in that file. + * + * If the dtype is NULL, the default array type is used (double). + * If non-null, the reference is stolen and if dtype->subarray is true dtype + * will be decrefed even on success. + * + * The number of elements to read is given as ``num``; if it is < 0, then + * then as many as possible are read. + * + * If ``sep`` is NULL or empty, then binary data is assumed, else + * text data, with ``sep`` as the separator between elements. Whitespace in + * the separator matches any length of whitespace in the text, and a match + * for whitespace around the separator is added. + * + * For memory-mapped files, use the buffer interface. No more data than + * necessary is read by this routine. + */ +NPY_NO_EXPORT PyObject * +PyArray_FromFile(FILE *fp, PyArray_Descr *dtype, npy_intp num, char *sep) +{ + PyArrayObject *ret; + size_t nread = 0; + + if (PyDataType_REFCHK(dtype)) { + PyErr_SetString(PyExc_ValueError, + "Cannot read into object array"); + Py_DECREF(dtype); + return NULL; + } + if (dtype->elsize == 0) { + /* Nothing to read, just create an empty array of the requested type */ + return PyArray_NewFromDescr_int(&PyArray_Type, + dtype, + 1, &num, + NULL, NULL, + 0, NULL, 0, 1); + } + if ((sep == NULL) || (strlen(sep) == 0)) { + ret = array_fromfile_binary(fp, dtype, num, &nread); + } + else { + if (dtype->f->scanfunc == NULL) { + PyErr_SetString(PyExc_ValueError, + "Unable to read character files of that array type"); + Py_DECREF(dtype); + return NULL; + } + ret = array_from_text(dtype, num, sep, &nread, fp, + (next_element) fromfile_next_element, + (skip_separator) fromfile_skip_separator, NULL); + } + if (ret == NULL) { + Py_DECREF(dtype); + return NULL; + } + if (((npy_intp) nread) < num) { + /* Realloc memory for smaller number of elements */ + const size_t nsize = PyArray_MAX(nread,1)*PyArray_DESCR(ret)->elsize; + char *tmp; + + if((tmp = PyDataMem_RENEW(PyArray_DATA(ret), nsize)) == NULL) { + Py_DECREF(ret); + return PyErr_NoMemory(); + } + ((PyArrayObject_fields *)ret)->data = tmp; + PyArray_DIMS(ret)[0] = nread; + } + return (PyObject *)ret; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_FromBuffer(PyObject *buf, PyArray_Descr *type, + npy_intp count, npy_intp offset) +{ + PyArrayObject *ret; + char *data; + Py_ssize_t ts; + npy_intp s, n; + int itemsize; + int writeable = 1; + + + if (PyDataType_REFCHK(type)) { + PyErr_SetString(PyExc_ValueError, + "cannot create an OBJECT array from memory"\ + " buffer"); + Py_DECREF(type); + return NULL; + } + if (PyDataType_ISUNSIZED(type)) { + PyErr_SetString(PyExc_ValueError, + "itemsize cannot be zero in type"); + Py_DECREF(type); + return NULL; + } + if (Py_TYPE(buf)->tp_as_buffer == NULL +#if defined(NPY_PY3K) + || Py_TYPE(buf)->tp_as_buffer->bf_getbuffer == NULL +#else + || (Py_TYPE(buf)->tp_as_buffer->bf_getwritebuffer == NULL + && Py_TYPE(buf)->tp_as_buffer->bf_getreadbuffer == NULL) +#endif + ) { + PyObject *newbuf; + newbuf = PyObject_GetAttr(buf, npy_ma_str_buffer); + if (newbuf == NULL) { + Py_DECREF(type); + return NULL; + } + buf = newbuf; + } + else { + Py_INCREF(buf); + } + + if (PyObject_AsWriteBuffer(buf, (void *)&data, &ts) == -1) { + writeable = 0; + PyErr_Clear(); + if (PyObject_AsReadBuffer(buf, (void *)&data, &ts) == -1) { + Py_DECREF(buf); + Py_DECREF(type); + return NULL; + } + } + + if ((offset < 0) || (offset > ts)) { + PyErr_Format(PyExc_ValueError, + "offset must be non-negative and no greater than buffer "\ + "length (%" NPY_INTP_FMT ")", (npy_intp)ts); + Py_DECREF(buf); + Py_DECREF(type); + return NULL; + } + + data += offset; + s = (npy_intp)ts - offset; + n = (npy_intp)count; + itemsize = type->elsize; + if (n < 0 ) { + if (s % itemsize != 0) { + PyErr_SetString(PyExc_ValueError, + "buffer size must be a multiple"\ + " of element size"); + Py_DECREF(buf); + Py_DECREF(type); + return NULL; + } + n = s/itemsize; + } + else { + if (s < n*itemsize) { + PyErr_SetString(PyExc_ValueError, + "buffer is smaller than requested"\ + " size"); + Py_DECREF(buf); + Py_DECREF(type); + return NULL; + } + } + + if ((ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + type, + 1, &n, + NULL, data, + NPY_ARRAY_DEFAULT, + NULL)) == NULL) { + Py_DECREF(buf); + return NULL; + } + + if (!writeable) { + PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEABLE); + } + /* Store a reference for decref on deallocation */ + if (PyArray_SetBaseObject(ret, buf) < 0) { + Py_DECREF(ret); + return NULL; + } + PyArray_UpdateFlags(ret, NPY_ARRAY_ALIGNED); + return (PyObject *)ret; +} + +/*NUMPY_API + * + * Given a pointer to a string ``data``, a string length ``slen``, and + * a ``PyArray_Descr``, return an array corresponding to the data + * encoded in that string. + * + * If the dtype is NULL, the default array type is used (double). + * If non-null, the reference is stolen. + * + * If ``slen`` is < 0, then the end of string is used for text data. + * It is an error for ``slen`` to be < 0 for binary data (since embedded NULLs + * would be the norm). + * + * The number of elements to read is given as ``num``; if it is < 0, then + * then as many as possible are read. + * + * If ``sep`` is NULL or empty, then binary data is assumed, else + * text data, with ``sep`` as the separator between elements. Whitespace in + * the separator matches any length of whitespace in the text, and a match + * for whitespace around the separator is added. + */ +NPY_NO_EXPORT PyObject * +PyArray_FromString(char *data, npy_intp slen, PyArray_Descr *dtype, + npy_intp num, char *sep) +{ + int itemsize; + PyArrayObject *ret; + npy_bool binary; + + if (dtype == NULL) { + dtype=PyArray_DescrFromType(NPY_DEFAULT_TYPE); + if (dtype == NULL) { + return NULL; + } + } + if (PyDataType_FLAGCHK(dtype, NPY_ITEM_IS_POINTER) || + PyDataType_REFCHK(dtype)) { + PyErr_SetString(PyExc_ValueError, + "Cannot create an object array from" \ + " a string"); + Py_DECREF(dtype); + return NULL; + } + itemsize = dtype->elsize; + if (itemsize == 0) { + PyErr_SetString(PyExc_ValueError, "zero-valued itemsize"); + Py_DECREF(dtype); + return NULL; + } + + binary = ((sep == NULL) || (strlen(sep) == 0)); + if (binary) { + if (num < 0 ) { + if (slen % itemsize != 0) { + PyErr_SetString(PyExc_ValueError, + "string size must be a "\ + "multiple of element size"); + Py_DECREF(dtype); + return NULL; + } + num = slen/itemsize; + } + else { + if (slen < num*itemsize) { + PyErr_SetString(PyExc_ValueError, + "string is smaller than " \ + "requested size"); + Py_DECREF(dtype); + return NULL; + } + } + ret = (PyArrayObject *) + PyArray_NewFromDescr(&PyArray_Type, dtype, + 1, &num, NULL, NULL, + 0, NULL); + if (ret == NULL) { + return NULL; + } + memcpy(PyArray_DATA(ret), data, num*dtype->elsize); + } + else { + /* read from character-based string */ + size_t nread = 0; + char *end; + + if (dtype->f->scanfunc == NULL) { + PyErr_SetString(PyExc_ValueError, + "don't know how to read " \ + "character strings with that " \ + "array type"); + Py_DECREF(dtype); + return NULL; + } + if (slen < 0) { + end = NULL; + } + else { + end = data + slen; + } + ret = array_from_text(dtype, num, sep, &nread, + data, + (next_element) fromstr_next_element, + (skip_separator) fromstr_skip_separator, + end); + } + return (PyObject *)ret; +} + +/*NUMPY_API + * + * steals a reference to dtype (which cannot be NULL) + */ +NPY_NO_EXPORT PyObject * +PyArray_FromIter(PyObject *obj, PyArray_Descr *dtype, npy_intp count) +{ + PyObject *value; + PyObject *iter = PyObject_GetIter(obj); + PyArrayObject *ret = NULL; + npy_intp i, elsize, elcount; + char *item, *new_data; + + if (iter == NULL) { + goto done; + } + if (PyDataType_ISUNSIZED(dtype)) { + PyErr_SetString(PyExc_ValueError, + "Must specify length when using variable-size data-type."); + goto done; + } + elcount = (count < 0) ? 0 : count; + elsize = dtype->elsize; + + /* + * We would need to alter the memory RENEW code to decrement any + * reference counts before throwing away any memory. + */ + if (PyDataType_REFCHK(dtype)) { + PyErr_SetString(PyExc_ValueError, + "cannot create object arrays from iterator"); + goto done; + } + + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, 1, + &elcount, NULL,NULL, 0, NULL); + dtype = NULL; + if (ret == NULL) { + goto done; + } + for (i = 0; (i < count || count == -1) && + (value = PyIter_Next(iter)); i++) { + if (i >= elcount) { + npy_intp nbytes; + /* + Grow PyArray_DATA(ret): + this is similar for the strategy for PyListObject, but we use + 50% overallocation => 0, 4, 8, 14, 23, 36, 56, 86 ... + */ + elcount = (i >> 1) + (i < 4 ? 4 : 2) + i; + if (!npy_mul_with_overflow_intp(&nbytes, elcount, elsize)) { + new_data = PyDataMem_RENEW(PyArray_DATA(ret), nbytes); + } + else { + new_data = NULL; + } + if (new_data == NULL) { + PyErr_SetString(PyExc_MemoryError, + "cannot allocate array memory"); + Py_DECREF(value); + goto done; + } + ((PyArrayObject_fields *)ret)->data = new_data; + } + PyArray_DIMS(ret)[0] = i + 1; + + if (((item = index2ptr(ret, i)) == NULL) || + PyArray_SETITEM(ret, item, value) == -1) { + Py_DECREF(value); + goto done; + } + Py_DECREF(value); + } + + + if (PyErr_Occurred()) { + goto done; + } + if (i < count) { + PyErr_SetString(PyExc_ValueError, + "iterator too short"); + goto done; + } + + /* + * Realloc the data so that don't keep extra memory tied up + * (assuming realloc is reasonably good about reusing space...) + */ + if (i == 0) { + /* The size cannot be zero for PyDataMem_RENEW. */ + i = 1; + } + new_data = PyDataMem_RENEW(PyArray_DATA(ret), i * elsize); + if (new_data == NULL) { + PyErr_SetString(PyExc_MemoryError, + "cannot allocate array memory"); + goto done; + } + ((PyArrayObject_fields *)ret)->data = new_data; + + done: + Py_XDECREF(iter); + Py_XDECREF(dtype); + if (PyErr_Occurred()) { + Py_XDECREF(ret); + return NULL; + } + return (PyObject *)ret; +} + +/* + * This is the main array creation routine. + * + * Flags argument has multiple related meanings + * depending on data and strides: + * + * If data is given, then flags is flags associated with data. + * If strides is not given, then a contiguous strides array will be created + * and the NPY_ARRAY_C_CONTIGUOUS bit will be set. If the flags argument + * has the NPY_ARRAY_F_CONTIGUOUS bit set, then a FORTRAN-style strides array will be + * created (and of course the NPY_ARRAY_F_CONTIGUOUS flag bit will be set). + * + * If data is not given but created here, then flags will be NPY_ARRAY_DEFAULT + * and a non-zero flags argument can be used to indicate a FORTRAN style + * array is desired. + * + * Dimensions and itemsize must have been checked for validity. + */ + +NPY_NO_EXPORT void +_array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize, + int inflag, int *objflags) +{ + int i; +#if NPY_RELAXED_STRIDES_CHECKING + npy_bool not_cf_contig = 0; + npy_bool nod = 0; /* A dim != 1 was found */ + + /* Check if new array is both F- and C-contiguous */ + for (i = 0; i < nd; i++) { + if (dims[i] != 1) { + if (nod) { + not_cf_contig = 1; + break; + } + nod = 1; + } + } +#endif /* NPY_RELAXED_STRIDES_CHECKING */ + + /* Only make Fortran strides if not contiguous as well */ + if ((inflag & (NPY_ARRAY_F_CONTIGUOUS|NPY_ARRAY_C_CONTIGUOUS)) == + NPY_ARRAY_F_CONTIGUOUS) { + for (i = 0; i < nd; i++) { + strides[i] = itemsize; + if (dims[i]) { + itemsize *= dims[i]; + } +#if NPY_RELAXED_STRIDES_CHECKING + else { + not_cf_contig = 0; + } +#if NPY_RELAXED_STRIDES_DEBUG + /* For testing purpose only */ + if (dims[i] == 1) { + strides[i] = NPY_MAX_INTP; + } +#endif /* NPY_RELAXED_STRIDES_DEBUG */ +#endif /* NPY_RELAXED_STRIDES_CHECKING */ + } +#if NPY_RELAXED_STRIDES_CHECKING + if (not_cf_contig) { +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + if ((nd > 1) && ((strides[0] != strides[nd-1]) || (dims[nd-1] > 1))) { +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ + *objflags = ((*objflags)|NPY_ARRAY_F_CONTIGUOUS) & + ~NPY_ARRAY_C_CONTIGUOUS; + } + else { + *objflags |= (NPY_ARRAY_F_CONTIGUOUS|NPY_ARRAY_C_CONTIGUOUS); + } + } + else { + for (i = nd - 1; i >= 0; i--) { + strides[i] = itemsize; + if (dims[i]) { + itemsize *= dims[i]; + } +#if NPY_RELAXED_STRIDES_CHECKING + else { + not_cf_contig = 0; + } +#if NPY_RELAXED_STRIDES_DEBUG + /* For testing purpose only */ + if (dims[i] == 1) { + strides[i] = NPY_MAX_INTP; + } +#endif /* NPY_RELAXED_STRIDES_DEBUG */ +#endif /* NPY_RELAXED_STRIDES_CHECKING */ + } +#if NPY_RELAXED_STRIDES_CHECKING + if (not_cf_contig) { +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + if ((nd > 1) && ((strides[0] != strides[nd-1]) || (dims[0] > 1))) { +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ + *objflags = ((*objflags)|NPY_ARRAY_C_CONTIGUOUS) & + ~NPY_ARRAY_F_CONTIGUOUS; + } + else { + *objflags |= (NPY_ARRAY_C_CONTIGUOUS|NPY_ARRAY_F_CONTIGUOUS); + } + } + return; +} + +/* + * Calls arr_of_subclass.__array_wrap__(towrap), in order to make 'towrap' + * have the same ndarray subclass as 'arr_of_subclass'. + */ +NPY_NO_EXPORT PyArrayObject * +PyArray_SubclassWrap(PyArrayObject *arr_of_subclass, PyArrayObject *towrap) +{ + PyObject *wrapped = PyObject_CallMethod((PyObject *)arr_of_subclass, + "__array_wrap__", "O", towrap); + if (wrapped == NULL) { + return NULL; + } + if (!PyArray_Check(wrapped)) { + PyErr_SetString(PyExc_RuntimeError, + "ndarray subclass __array_wrap__ method returned an " + "object which was not an instance of an ndarray subclass"); + Py_DECREF(wrapped); + return NULL; + } + + return (PyArrayObject *)wrapped; +} diff --git a/numpy/core/src/multiarray/ctors.h b/numpy/core/src/multiarray/ctors.h new file mode 100644 index 0000000..e889910 --- /dev/null +++ b/numpy/core/src/multiarray/ctors.h @@ -0,0 +1,89 @@ +#ifndef _NPY_ARRAY_CTORS_H_ +#define _NPY_ARRAY_CTORS_H_ + +NPY_NO_EXPORT PyObject * +PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd, + npy_intp *dims, npy_intp *strides, void *data, + int flags, PyObject *obj); + +NPY_NO_EXPORT PyObject * +PyArray_NewFromDescr_int(PyTypeObject *subtype, PyArray_Descr *descr, int nd, + npy_intp *dims, npy_intp *strides, void *data, + int flags, PyObject *obj, int zeroed, + int allow_emptystring); + +NPY_NO_EXPORT PyObject *PyArray_New(PyTypeObject *, int nd, npy_intp *, + int, npy_intp *, void *, int, int, PyObject *); + +NPY_NO_EXPORT PyObject * +PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth, + int max_depth, int flags, PyObject *context); + +NPY_NO_EXPORT PyObject * +PyArray_CheckFromAny(PyObject *op, PyArray_Descr *descr, int min_depth, + int max_depth, int requires, PyObject *context); + +NPY_NO_EXPORT PyObject * +PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags); + +NPY_NO_EXPORT PyObject * +PyArray_FromStructInterface(PyObject *input); + +NPY_NO_EXPORT PyObject * +PyArray_FromInterface(PyObject *input); + +NPY_NO_EXPORT PyObject * +PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, + PyObject *context); + +NPY_NO_EXPORT PyObject * +PyArray_EnsureArray(PyObject *op); + +NPY_NO_EXPORT PyObject * +PyArray_EnsureAnyArray(PyObject *op); + +NPY_NO_EXPORT int +PyArray_MoveInto(PyArrayObject *dest, PyArrayObject *src); + +NPY_NO_EXPORT int +PyArray_CopyAnyInto(PyArrayObject *dest, PyArrayObject *src); + +NPY_NO_EXPORT PyObject * +PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags); + +/* TODO: Put the order parameter in PyArray_CopyAnyInto and remove this */ +NPY_NO_EXPORT int +PyArray_CopyAsFlat(PyArrayObject *dst, PyArrayObject *src, + NPY_ORDER order); + +/* FIXME: remove those from here */ +NPY_NO_EXPORT void +_array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize, + int inflag, int *objflags); + +NPY_NO_EXPORT void +_unaligned_strided_byte_copy(char *dst, npy_intp outstrides, char *src, + npy_intp instrides, npy_intp N, int elsize); + +NPY_NO_EXPORT void +_strided_byte_swap(void *p, npy_intp stride, npy_intp n, int size); + +NPY_NO_EXPORT void +copy_and_swap(void *dst, void *src, int itemsize, npy_intp numitems, + npy_intp srcstrides, int swap); + +NPY_NO_EXPORT void +byte_swap_vector(void *p, npy_intp n, int size); + +NPY_NO_EXPORT int +PyArray_AssignFromSequence(PyArrayObject *self, PyObject *v); + +/* + * Calls arr_of_subclass.__array_wrap__(towrap), in order to make 'towrap' + * have the same ndarray subclass as 'arr_of_subclass'. + */ +NPY_NO_EXPORT PyArrayObject * +PyArray_SubclassWrap(PyArrayObject *arr_of_subclass, PyArrayObject *towrap); + + +#endif diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c new file mode 100644 index 0000000..93babe8 --- /dev/null +++ b/numpy/core/src/multiarray/datetime.c @@ -0,0 +1,3879 @@ +/* + * This file implements core functionality for NumPy datetime. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include +#include + +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "common.h" +#include "numpy/arrayscalars.h" +#include "methods.h" +#include "_datetime.h" +#include "datetime_strings.h" + +/* + * Imports the PyDateTime functions so we can create these objects. + * This is called during module initialization + */ +NPY_NO_EXPORT void +numpy_pydatetime_import(void) +{ + PyDateTime_IMPORT; +} + +/* Exported as DATETIMEUNITS in multiarraymodule.c */ +NPY_NO_EXPORT char *_datetime_strings[NPY_DATETIME_NUMUNITS] = { + "Y", + "M", + "W", + "", + "D", + "h", + "m", + "s", + "ms", + "us", + "ns", + "ps", + "fs", + "as", + "generic" +}; + +/* Days per month, regular year and leap year */ +NPY_NO_EXPORT int _days_per_month_table[2][12] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +/* + * Returns 1 if the given year is a leap year, 0 otherwise. + */ +NPY_NO_EXPORT int +is_leapyear(npy_int64 year) +{ + return (year & 0x3) == 0 && /* year % 4 == 0 */ + ((year % 100) != 0 || + (year % 400) == 0); +} + +/* + * Calculates the days offset from the 1970 epoch. + */ +NPY_NO_EXPORT npy_int64 +get_datetimestruct_days(const npy_datetimestruct *dts) +{ + int i, month; + npy_int64 year, days = 0; + int *month_lengths; + + year = dts->year - 1970; + days = year * 365; + + /* Adjust for leap years */ + if (days >= 0) { + /* + * 1968 is the closest leap year before 1970. + * Exclude the current year, so add 1. + */ + year += 1; + /* Add one day for each 4 years */ + days += year / 4; + /* 1900 is the closest previous year divisible by 100 */ + year += 68; + /* Subtract one day for each 100 years */ + days -= year / 100; + /* 1600 is the closest previous year divisible by 400 */ + year += 300; + /* Add one day for each 400 years */ + days += year / 400; + } + else { + /* + * 1972 is the closest later year after 1970. + * Include the current year, so subtract 2. + */ + year -= 2; + /* Subtract one day for each 4 years */ + days += year / 4; + /* 2000 is the closest later year divisible by 100 */ + year -= 28; + /* Add one day for each 100 years */ + days -= year / 100; + /* 2000 is also the closest later year divisible by 400 */ + /* Subtract one day for each 400 years */ + days += year / 400; + } + + month_lengths = _days_per_month_table[is_leapyear(dts->year)]; + month = dts->month - 1; + + /* Add the months */ + for (i = 0; i < month; ++i) { + days += month_lengths[i]; + } + + /* Add the days */ + days += dts->day - 1; + + return days; +} + +/* + * Calculates the minutes offset from the 1970 epoch. + */ +NPY_NO_EXPORT npy_int64 +get_datetimestruct_minutes(const npy_datetimestruct *dts) +{ + npy_int64 days = get_datetimestruct_days(dts) * 24 * 60; + days += dts->hour * 60; + days += dts->min; + + return days; +} + +/* + * Modifies '*days_' to be the day offset within the year, + * and returns the year. + */ +static npy_int64 +days_to_yearsdays(npy_int64 *days_) +{ + const npy_int64 days_per_400years = (400*365 + 100 - 4 + 1); + /* Adjust so it's relative to the year 2000 (divisible by 400) */ + npy_int64 days = (*days_) - (365*30 + 7); + npy_int64 year; + + /* Break down the 400 year cycle to get the year and day within the year */ + if (days >= 0) { + year = 400 * (days / days_per_400years); + days = days % days_per_400years; + } + else { + year = 400 * ((days - (days_per_400years - 1)) / days_per_400years); + days = days % days_per_400years; + if (days < 0) { + days += days_per_400years; + } + } + + /* Work out the year/day within the 400 year cycle */ + if (days >= 366) { + year += 100 * ((days-1) / (100*365 + 25 - 1)); + days = (days-1) % (100*365 + 25 - 1); + if (days >= 365) { + year += 4 * ((days+1) / (4*365 + 1)); + days = (days+1) % (4*365 + 1); + if (days >= 366) { + year += (days-1) / 365; + days = (days-1) % 365; + } + } + } + + *days_ = days; + return year + 2000; +} + +/* Extracts the month number from a 'datetime64[D]' value */ +NPY_NO_EXPORT int +days_to_month_number(npy_datetime days) +{ + npy_int64 year; + int *month_lengths, i; + + year = days_to_yearsdays(&days); + month_lengths = _days_per_month_table[is_leapyear(year)]; + + for (i = 0; i < 12; ++i) { + if (days < month_lengths[i]) { + return i + 1; + } + else { + days -= month_lengths[i]; + } + } + + /* Should never get here */ + return 1; +} + +/* + * Fills in the year, month, day in 'dts' based on the days + * offset from 1970. + */ +static void +set_datetimestruct_days(npy_int64 days, npy_datetimestruct *dts) +{ + int *month_lengths, i; + + dts->year = days_to_yearsdays(&days); + month_lengths = _days_per_month_table[is_leapyear(dts->year)]; + + for (i = 0; i < 12; ++i) { + if (days < month_lengths[i]) { + dts->month = i + 1; + dts->day = (int)days + 1; + return; + } + else { + days -= month_lengths[i]; + } + } +} + +/* + * Converts a datetime from a datetimestruct to a datetime based + * on some metadata. The date is assumed to be valid. + * + * TODO: If meta->num is really big, there could be overflow + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_datetimestruct_to_datetime(PyArray_DatetimeMetaData *meta, + const npy_datetimestruct *dts, + npy_datetime *out) +{ + npy_datetime ret; + NPY_DATETIMEUNIT base = meta->base; + + /* If the datetimestruct is NaT, return NaT */ + if (dts->year == NPY_DATETIME_NAT) { + *out = NPY_DATETIME_NAT; + return 0; + } + + /* Cannot instantiate a datetime with generic units */ + if (meta->base == NPY_FR_GENERIC) { + PyErr_SetString(PyExc_ValueError, + "Cannot create a NumPy datetime other than NaT " + "with generic units"); + return -1; + } + + if (base == NPY_FR_Y) { + /* Truncate to the year */ + ret = dts->year - 1970; + } + else if (base == NPY_FR_M) { + /* Truncate to the month */ + ret = 12 * (dts->year - 1970) + (dts->month - 1); + } + else { + /* Otherwise calculate the number of days to start */ + npy_int64 days = get_datetimestruct_days(dts); + + switch (base) { + case NPY_FR_W: + /* Truncate to weeks */ + if (days >= 0) { + ret = days / 7; + } + else { + ret = (days - 6) / 7; + } + break; + case NPY_FR_D: + ret = days; + break; + case NPY_FR_h: + ret = days * 24 + + dts->hour; + break; + case NPY_FR_m: + ret = (days * 24 + + dts->hour) * 60 + + dts->min; + break; + case NPY_FR_s: + ret = ((days * 24 + + dts->hour) * 60 + + dts->min) * 60 + + dts->sec; + break; + case NPY_FR_ms: + ret = (((days * 24 + + dts->hour) * 60 + + dts->min) * 60 + + dts->sec) * 1000 + + dts->us / 1000; + break; + case NPY_FR_us: + ret = (((days * 24 + + dts->hour) * 60 + + dts->min) * 60 + + dts->sec) * 1000000 + + dts->us; + break; + case NPY_FR_ns: + ret = ((((days * 24 + + dts->hour) * 60 + + dts->min) * 60 + + dts->sec) * 1000000 + + dts->us) * 1000 + + dts->ps / 1000; + break; + case NPY_FR_ps: + ret = ((((days * 24 + + dts->hour) * 60 + + dts->min) * 60 + + dts->sec) * 1000000 + + dts->us) * 1000000 + + dts->ps; + break; + case NPY_FR_fs: + /* only 2.6 hours */ + ret = (((((days * 24 + + dts->hour) * 60 + + dts->min) * 60 + + dts->sec) * 1000000 + + dts->us) * 1000000 + + dts->ps) * 1000 + + dts->as / 1000; + break; + case NPY_FR_as: + /* only 9.2 secs */ + ret = (((((days * 24 + + dts->hour) * 60 + + dts->min) * 60 + + dts->sec) * 1000000 + + dts->us) * 1000000 + + dts->ps) * 1000000 + + dts->as; + break; + default: + /* Something got corrupted */ + PyErr_SetString(PyExc_ValueError, + "NumPy datetime metadata with corrupt unit value"); + return -1; + } + } + + /* Divide by the multiplier */ + if (meta->num > 1) { + if (ret >= 0) { + ret /= meta->num; + } + else { + ret = (ret - meta->num + 1) / meta->num; + } + } + + *out = ret; + + return 0; +} + +/*NUMPY_API + * Create a datetime value from a filled datetime struct and resolution unit. + * + * TO BE REMOVED - NOT USED INTERNALLY. + */ +NPY_NO_EXPORT npy_datetime +PyArray_DatetimeStructToDatetime(NPY_DATETIMEUNIT fr, npy_datetimestruct *d) +{ + PyErr_SetString(PyExc_RuntimeError, + "The NumPy PyArray_DatetimeStructToDatetime function has " + "been removed"); + return -1; +} + +/*NUMPY_API + * Create a timdelta value from a filled timedelta struct and resolution unit. + * + * TO BE REMOVED - NOT USED INTERNALLY. + */ +NPY_NO_EXPORT npy_datetime +PyArray_TimedeltaStructToTimedelta(NPY_DATETIMEUNIT fr, npy_timedeltastruct *d) +{ + PyErr_SetString(PyExc_RuntimeError, + "The NumPy PyArray_TimedeltaStructToTimedelta function has " + "been removed"); + return -1; +} + +/* + * Converts a datetime based on the given metadata into a datetimestruct + */ +NPY_NO_EXPORT int +convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta, + npy_datetime dt, + npy_datetimestruct *out) +{ + npy_int64 perday; + + /* Initialize the output to all zeros */ + memset(out, 0, sizeof(npy_datetimestruct)); + out->year = 1970; + out->month = 1; + out->day = 1; + + /* NaT is signaled in the year */ + if (dt == NPY_DATETIME_NAT) { + out->year = NPY_DATETIME_NAT; + return 0; + } + + /* Datetimes can't be in generic units */ + if (meta->base == NPY_FR_GENERIC) { + PyErr_SetString(PyExc_ValueError, + "Cannot convert a NumPy datetime value other than NaT " + "with generic units"); + return -1; + } + + /* TODO: Change to a mechanism that avoids the potential overflow */ + dt *= meta->num; + + /* + * Note that care must be taken with the / and % operators + * for negative values. + */ + switch (meta->base) { + case NPY_FR_Y: + out->year = 1970 + dt; + break; + + case NPY_FR_M: + if (dt >= 0) { + out->year = 1970 + dt / 12; + out->month = dt % 12 + 1; + } + else { + out->year = 1969 + (dt + 1) / 12; + out->month = 12 + (dt + 1)% 12; + } + break; + + case NPY_FR_W: + /* A week is 7 days */ + set_datetimestruct_days(dt * 7, out); + break; + + case NPY_FR_D: + set_datetimestruct_days(dt, out); + break; + + case NPY_FR_h: + perday = 24LL; + + if (dt >= 0) { + set_datetimestruct_days(dt / perday, out); + dt = dt % perday; + } + else { + set_datetimestruct_days((dt - (perday-1)) / perday, out); + dt = (perday-1) + (dt + 1) % perday; + } + out->hour = (int)dt; + break; + + case NPY_FR_m: + perday = 24LL * 60; + + if (dt >= 0) { + set_datetimestruct_days(dt / perday, out); + dt = dt % perday; + } + else { + set_datetimestruct_days((dt - (perday-1)) / perday, out); + dt = (perday-1) + (dt + 1) % perday; + } + out->hour = (int)(dt / 60); + out->min = (int)(dt % 60); + break; + + case NPY_FR_s: + perday = 24LL * 60 * 60; + + if (dt >= 0) { + set_datetimestruct_days(dt / perday, out); + dt = dt % perday; + } + else { + set_datetimestruct_days((dt - (perday-1)) / perday, out); + dt = (perday-1) + (dt + 1) % perday; + } + out->hour = (int)(dt / (60*60)); + out->min = (int)((dt / 60) % 60); + out->sec = (int)(dt % 60); + break; + + case NPY_FR_ms: + perday = 24LL * 60 * 60 * 1000; + + if (dt >= 0) { + set_datetimestruct_days(dt / perday, out); + dt = dt % perday; + } + else { + set_datetimestruct_days((dt - (perday-1)) / perday, out); + dt = (perday-1) + (dt + 1) % perday; + } + out->hour = (int)(dt / (60*60*1000LL)); + out->min = (int)((dt / (60*1000LL)) % 60); + out->sec = (int)((dt / 1000LL) % 60); + out->us = (int)((dt % 1000LL) * 1000); + break; + + case NPY_FR_us: + perday = 24LL * 60LL * 60LL * 1000LL * 1000LL; + + if (dt >= 0) { + set_datetimestruct_days(dt / perday, out); + dt = dt % perday; + } + else { + set_datetimestruct_days((dt - (perday-1)) / perday, out); + dt = (perday-1) + (dt + 1) % perday; + } + out->hour = (int)(dt / (60*60*1000000LL)); + out->min = (int)((dt / (60*1000000LL)) % 60); + out->sec = (int)((dt / 1000000LL) % 60); + out->us = (int)(dt % 1000000LL); + break; + + case NPY_FR_ns: + perday = 24LL * 60LL * 60LL * 1000LL * 1000LL * 1000LL; + + if (dt >= 0) { + set_datetimestruct_days(dt / perday, out); + dt = dt % perday; + } + else { + set_datetimestruct_days((dt - (perday-1)) / perday, out); + dt = (perday-1) + (dt + 1) % perday; + } + out->hour = (int)(dt / (60*60*1000000000LL)); + out->min = (int)((dt / (60*1000000000LL)) % 60); + out->sec = (int)((dt / 1000000000LL) % 60); + out->us = (int)((dt / 1000LL) % 1000000LL); + out->ps = (int)((dt % 1000LL) * 1000); + break; + + case NPY_FR_ps: + perday = 24LL * 60 * 60 * 1000 * 1000 * 1000 * 1000; + + if (dt >= 0) { + set_datetimestruct_days(dt / perday, out); + dt = dt % perday; + } + else { + set_datetimestruct_days((dt - (perday-1)) / perday, out); + dt = (perday-1) + (dt + 1) % perday; + } + out->hour = (int)(dt / (60*60*1000000000000LL)); + out->min = (int)((dt / (60*1000000000000LL)) % 60); + out->sec = (int)((dt / 1000000000000LL) % 60); + out->us = (int)((dt / 1000000LL) % 1000000LL); + out->ps = (int)(dt % 1000000LL); + break; + + case NPY_FR_fs: + /* entire range is only +- 2.6 hours */ + if (dt >= 0) { + out->hour = (int)(dt / (60*60*1000000000000000LL)); + out->min = (int)((dt / (60*1000000000000000LL)) % 60); + out->sec = (int)((dt / 1000000000000000LL) % 60); + out->us = (int)((dt / 1000000000LL) % 1000000LL); + out->ps = (int)((dt / 1000LL) % 1000000LL); + out->as = (int)((dt % 1000LL) * 1000); + } + else { + npy_datetime minutes; + + minutes = dt / (60*1000000000000000LL); + dt = dt % (60*1000000000000000LL); + if (dt < 0) { + dt += (60*1000000000000000LL); + --minutes; + } + /* Offset the negative minutes */ + add_minutes_to_datetimestruct(out, minutes); + out->sec = (int)((dt / 1000000000000000LL) % 60); + out->us = (int)((dt / 1000000000LL) % 1000000LL); + out->ps = (int)((dt / 1000LL) % 1000000LL); + out->as = (int)((dt % 1000LL) * 1000); + } + break; + + case NPY_FR_as: + /* entire range is only +- 9.2 seconds */ + if (dt >= 0) { + out->sec = (int)((dt / 1000000000000000000LL) % 60); + out->us = (int)((dt / 1000000000000LL) % 1000000LL); + out->ps = (int)((dt / 1000000LL) % 1000000LL); + out->as = (int)(dt % 1000000LL); + } + else { + npy_datetime seconds; + + seconds = dt / 1000000000000000000LL; + dt = dt % 1000000000000000000LL; + if (dt < 0) { + dt += 1000000000000000000LL; + --seconds; + } + /* Offset the negative seconds */ + add_seconds_to_datetimestruct(out, seconds); + out->us = (int)((dt / 1000000000000LL) % 1000000LL); + out->ps = (int)((dt / 1000000LL) % 1000000LL); + out->as = (int)(dt % 1000000LL); + } + break; + + default: + PyErr_SetString(PyExc_RuntimeError, + "NumPy datetime metadata is corrupted with invalid " + "base unit"); + return -1; + } + + return 0; +} + + +/*NUMPY_API + * Fill the datetime struct from the value and resolution unit. + * + * TO BE REMOVED - NOT USED INTERNALLY. + */ +NPY_NO_EXPORT void +PyArray_DatetimeToDatetimeStruct(npy_datetime val, NPY_DATETIMEUNIT fr, + npy_datetimestruct *result) +{ + PyErr_SetString(PyExc_RuntimeError, + "The NumPy PyArray_DatetimeToDatetimeStruct function has " + "been removed"); + memset(result, -1, sizeof(npy_datetimestruct)); +} + +/* + * FIXME: Overflow is not handled at all + * To convert from Years or Months, + * multiplication by the average is done + */ + +/*NUMPY_API + * Fill the timedelta struct from the timedelta value and resolution unit. + * + * TO BE REMOVED - NOT USED INTERNALLY. + */ +NPY_NO_EXPORT void +PyArray_TimedeltaToTimedeltaStruct(npy_timedelta val, NPY_DATETIMEUNIT fr, + npy_timedeltastruct *result) +{ + PyErr_SetString(PyExc_RuntimeError, + "The NumPy PyArray_TimedeltaToTimedeltaStruct function has " + "been removed"); + memset(result, -1, sizeof(npy_timedeltastruct)); +} + +/* + * Creates a datetime or timedelta dtype using a copy of the provided metadata. + */ +NPY_NO_EXPORT PyArray_Descr * +create_datetime_dtype(int type_num, PyArray_DatetimeMetaData *meta) +{ + PyArray_Descr *dtype = NULL; + PyArray_DatetimeMetaData *dt_data; + + /* Create a default datetime or timedelta */ + if (type_num == NPY_DATETIME || type_num == NPY_TIMEDELTA) { + dtype = PyArray_DescrNewFromType(type_num); + } + else { + PyErr_SetString(PyExc_RuntimeError, + "Asked to create a datetime type with a non-datetime " + "type number"); + return NULL; + } + + if (dtype == NULL) { + return NULL; + } + + dt_data = &(((PyArray_DatetimeDTypeMetaData *)dtype->c_metadata)->meta); + + /* Copy the metadata */ + *dt_data = *meta; + + return dtype; +} + +/* + * Creates a datetime or timedelta dtype using the given unit. + */ +NPY_NO_EXPORT PyArray_Descr * +create_datetime_dtype_with_unit(int type_num, NPY_DATETIMEUNIT unit) +{ + PyArray_DatetimeMetaData meta; + meta.base = unit; + meta.num = 1; + return create_datetime_dtype(type_num, &meta); +} + +/* + * This function returns a pointer to the DateTimeMetaData + * contained within the provided datetime dtype. + */ +NPY_NO_EXPORT PyArray_DatetimeMetaData * +get_datetime_metadata_from_dtype(PyArray_Descr *dtype) +{ + if (!PyDataType_ISDATETIME(dtype)) { + PyErr_SetString(PyExc_TypeError, + "cannot get datetime metadata from non-datetime type"); + return NULL; + } + + return &(((PyArray_DatetimeDTypeMetaData *)dtype->c_metadata)->meta); +} + +/* + * Converts a substring given by 'str' and 'len' into + * a date time unit multiplier + enum value, which are populated + * into out_meta. Other metadata is left along. + * + * 'metastr' is only used in the error message, and may be NULL. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +parse_datetime_extended_unit_from_string(char *str, Py_ssize_t len, + char *metastr, + PyArray_DatetimeMetaData *out_meta) +{ + char *substr = str, *substrend = NULL; + int den = 1; + + /* First comes an optional integer multiplier */ + out_meta->num = (int)strtol(substr, &substrend, 10); + if (substr == substrend) { + out_meta->num = 1; + } + substr = substrend; + + /* Next comes the unit itself, followed by either '/' or the string end */ + substrend = substr; + while (substrend-str < len && *substrend != '/') { + ++substrend; + } + if (substr == substrend) { + goto bad_input; + } + out_meta->base = parse_datetime_unit_from_string(substr, + substrend-substr, metastr); + if (out_meta->base == -1) { + return -1; + } + substr = substrend; + + /* Next comes an optional integer denominator */ + if (substr-str < len && *substr == '/') { + substr++; + den = (int)strtol(substr, &substrend, 10); + /* If the '/' exists, there must be a number followed by ']' */ + if (substr == substrend || *substrend != ']') { + goto bad_input; + } + substr = substrend + 1; + } + else if (substr-str != len) { + goto bad_input; + } + + if (den != 1) { + if (convert_datetime_divisor_to_multiple( + out_meta, den, metastr) < 0) { + return -1; + } + } + + return 0; + +bad_input: + if (metastr != NULL) { + PyErr_Format(PyExc_TypeError, + "Invalid datetime metadata string \"%s\" at position %d", + metastr, (int)(substr-metastr)); + } + else { + PyErr_Format(PyExc_TypeError, + "Invalid datetime metadata string \"%s\"", + str); + } + + return -1; +} + +/* + * Parses the metadata string into the metadata C structure. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +parse_datetime_metadata_from_metastr(char *metastr, Py_ssize_t len, + PyArray_DatetimeMetaData *out_meta) +{ + char *substr = metastr, *substrend = NULL; + + /* Treat the empty string as generic units */ + if (len == 0) { + out_meta->base = NPY_FR_GENERIC; + out_meta->num = 1; + + return 0; + } + + /* The metadata string must start with a '[' */ + if (len < 3 || *substr++ != '[') { + goto bad_input; + } + + substrend = substr; + while (substrend - metastr < len && *substrend != ']') { + ++substrend; + } + if (substrend - metastr == len || substr == substrend) { + substr = substrend; + goto bad_input; + } + + /* Parse the extended unit inside the [] */ + if (parse_datetime_extended_unit_from_string(substr, substrend-substr, + metastr, out_meta) < 0) { + return -1; + } + + substr = substrend+1; + + if (substr - metastr != len) { + goto bad_input; + } + + return 0; + +bad_input: + if (substr != metastr) { + PyErr_Format(PyExc_TypeError, + "Invalid datetime metadata string \"%s\" at position %d", + metastr, (int)(substr-metastr)); + } + else { + PyErr_Format(PyExc_TypeError, + "Invalid datetime metadata string \"%s\"", + metastr); + } + + return -1; +} + +/* + * Converts a datetype dtype string into a dtype descr object. + * The "type" string should be NULL-terminated. + */ +NPY_NO_EXPORT PyArray_Descr * +parse_dtype_from_datetime_typestr(char *typestr, Py_ssize_t len) +{ + PyArray_DatetimeMetaData meta; + char *metastr = NULL; + int is_timedelta = 0; + Py_ssize_t metalen = 0; + + if (len < 2) { + PyErr_Format(PyExc_TypeError, + "Invalid datetime typestr \"%s\"", + typestr); + return NULL; + } + + /* + * First validate that the root is correct, + * and get the metadata string address + */ + if (typestr[0] == 'm' && typestr[1] == '8') { + is_timedelta = 1; + metastr = typestr + 2; + metalen = len - 2; + } + else if (typestr[0] == 'M' && typestr[1] == '8') { + is_timedelta = 0; + metastr = typestr + 2; + metalen = len - 2; + } + else if (len >= 11 && strncmp(typestr, "timedelta64", 11) == 0) { + is_timedelta = 1; + metastr = typestr + 11; + metalen = len - 11; + } + else if (len >= 10 && strncmp(typestr, "datetime64", 10) == 0) { + is_timedelta = 0; + metastr = typestr + 10; + metalen = len - 10; + } + else { + PyErr_Format(PyExc_TypeError, + "Invalid datetime typestr \"%s\"", + typestr); + return NULL; + } + + /* Parse the metadata string into a metadata struct */ + if (parse_datetime_metadata_from_metastr(metastr, metalen, &meta) < 0) { + return NULL; + } + + return create_datetime_dtype(is_timedelta ? NPY_TIMEDELTA : NPY_DATETIME, + &meta); +} + +static NPY_DATETIMEUNIT _multiples_table[16][4] = { + {12, 52, 365}, /* NPY_FR_Y */ + {NPY_FR_M, NPY_FR_W, NPY_FR_D}, + {4, 30, 720}, /* NPY_FR_M */ + {NPY_FR_W, NPY_FR_D, NPY_FR_h}, + {7, 168, 10080}, /* NPY_FR_W */ + {NPY_FR_D, NPY_FR_h, NPY_FR_m}, + {0}, /* Gap for removed NPY_FR_B */ + {0}, + {24, 1440, 86400}, /* NPY_FR_D */ + {NPY_FR_h, NPY_FR_m, NPY_FR_s}, + {60, 3600}, /* NPY_FR_h */ + {NPY_FR_m, NPY_FR_s}, + {60, 60000}, /* NPY_FR_m */ + {NPY_FR_s, NPY_FR_ms}, + {1000, 1000000}, /* >=NPY_FR_s */ + {0, 0} +}; + + + +/* + * Translate divisors into multiples of smaller units. + * 'metastr' is used for the error message if the divisor doesn't work, + * and can be NULL if the metadata didn't come from a string. + * + * This function only affects the 'base' and 'num' values in the metadata. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_datetime_divisor_to_multiple(PyArray_DatetimeMetaData *meta, + int den, char *metastr) +{ + int i, num, ind; + NPY_DATETIMEUNIT *totry; + NPY_DATETIMEUNIT *baseunit; + int q, r; + + if (meta->base == NPY_FR_GENERIC) { + PyErr_SetString(PyExc_ValueError, + "Can't use 'den' divisor with generic units"); + return -1; + } + + ind = ((int)meta->base - (int)NPY_FR_Y)*2; + totry = _multiples_table[ind]; + baseunit = _multiples_table[ind + 1]; + + num = 3; + if (meta->base == NPY_FR_W) { + num = 4; + } + else if (meta->base > NPY_FR_D) { + num = 2; + } + if (meta->base >= NPY_FR_s) { + ind = ((int)NPY_FR_s - (int)NPY_FR_Y)*2; + totry = _multiples_table[ind]; + baseunit = _multiples_table[ind + 1]; + baseunit[0] = meta->base + 1; + baseunit[1] = meta->base + 2; + if (meta->base == NPY_FR_as - 1) { + num = 1; + } + if (meta->base == NPY_FR_as) { + num = 0; + } + } + + for (i = 0; i < num; i++) { + q = totry[i] / den; + r = totry[i] % den; + if (r == 0) { + break; + } + } + if (i == num) { + if (metastr == NULL) { + PyErr_Format(PyExc_ValueError, + "divisor (%d) is not a multiple of a lower-unit " + "in datetime metadata", den); + } + else { + PyErr_Format(PyExc_ValueError, + "divisor (%d) is not a multiple of a lower-unit " + "in datetime metadata \"%s\"", den, metastr); + } + return -1; + } + meta->base = baseunit[i]; + meta->num *= q; + + return 0; +} + +/* + * Lookup table for factors between datetime units, except + * for years and months. + */ +static npy_uint32 +_datetime_factors[] = { + 1, /* Years - not used */ + 1, /* Months - not used */ + 7, /* Weeks -> Days */ + 1, /* Business Days - was removed but a gap still exists in the enum */ + 24, /* Days -> Hours */ + 60, /* Hours -> Minutes */ + 60, /* Minutes -> Seconds */ + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1, /* Attoseconds are the smallest base unit */ + 0 /* Generic units don't have a conversion */ +}; + +/* + * Returns the scale factor between the units. Does not validate + * that bigbase represents larger units than littlebase, or that + * the units are not generic. + * + * Returns 0 if there is an overflow. + */ +static npy_uint64 +get_datetime_units_factor(NPY_DATETIMEUNIT bigbase, NPY_DATETIMEUNIT littlebase) +{ + npy_uint64 factor = 1; + int unit = (int)bigbase; + while (littlebase > unit) { + factor *= _datetime_factors[unit]; + /* + * Detect overflow by disallowing the top 16 bits to be 1. + * That alows a margin of error much bigger than any of + * the datetime factors. + */ + if (factor&0xff00000000000000ULL) { + return 0; + } + ++unit; + } + return factor; +} + +/* Euclidean algorithm on two positive numbers */ +static npy_uint64 +_uint64_euclidean_gcd(npy_uint64 x, npy_uint64 y) +{ + npy_uint64 tmp; + + if (x > y) { + tmp = x; + x = y; + y = tmp; + } + while (x != y && y != 0) { + tmp = x % y; + x = y; + y = tmp; + } + + return x; +} + +/* + * Computes the conversion factor to convert data with 'src_meta' metadata + * into data with 'dst_meta' metadata. + * + * If overflow occurs, both out_num and out_denom are set to 0, but + * no error is set. + */ +NPY_NO_EXPORT void +get_datetime_conversion_factor(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + npy_int64 *out_num, npy_int64 *out_denom) +{ + int src_base, dst_base, swapped; + npy_uint64 num = 1, denom = 1, tmp, gcd; + + /* Generic units change to the destination with no conversion factor */ + if (src_meta->base == NPY_FR_GENERIC) { + *out_num = 1; + *out_denom = 1; + return; + } + /* + * Converting to a generic unit from something other than a generic + * unit is an error. + */ + else if (dst_meta->base == NPY_FR_GENERIC) { + PyErr_SetString(PyExc_ValueError, + "Cannot convert from specific units to generic " + "units in NumPy datetimes or timedeltas"); + *out_num = 0; + *out_denom = 0; + return; + } + + if (src_meta->base <= dst_meta->base) { + src_base = src_meta->base; + dst_base = dst_meta->base; + swapped = 0; + } + else { + src_base = dst_meta->base; + dst_base = src_meta->base; + swapped = 1; + } + + if (src_base != dst_base) { + /* + * Conversions between years/months and other units use + * the factor averaged over the 400 year leap year cycle. + */ + if (src_base == NPY_FR_Y) { + if (dst_base == NPY_FR_M) { + num *= 12; + } + else if (dst_base == NPY_FR_W) { + num *= (97 + 400*365); + denom *= 400*7; + } + else { + /* Year -> Day */ + num *= (97 + 400*365); + denom *= 400; + /* Day -> dst_base */ + num *= get_datetime_units_factor(NPY_FR_D, dst_base); + } + } + else if (src_base == NPY_FR_M) { + if (dst_base == NPY_FR_W) { + num *= (97 + 400*365); + denom *= 400*12*7; + } + else { + /* Month -> Day */ + num *= (97 + 400*365); + denom *= 400*12; + /* Day -> dst_base */ + num *= get_datetime_units_factor(NPY_FR_D, dst_base); + } + } + else { + num *= get_datetime_units_factor(src_base, dst_base); + } + } + + /* If something overflowed, make both num and denom 0 */ + if (denom == 0 || num == 0) { + PyErr_Format(PyExc_OverflowError, + "Integer overflow while computing the conversion " + "factor between NumPy datetime units %s and %s", + _datetime_strings[src_base], + _datetime_strings[dst_base]); + *out_num = 0; + *out_denom = 0; + return; + } + + /* Swap the numerator and denominator if necessary */ + if (swapped) { + tmp = num; + num = denom; + denom = tmp; + } + + num *= src_meta->num; + denom *= dst_meta->num; + + /* Return as a fraction in reduced form */ + gcd = _uint64_euclidean_gcd(num, denom); + *out_num = (npy_int64)(num / gcd); + *out_denom = (npy_int64)(denom / gcd); +} + +/* + * Determines whether the 'divisor' metadata divides evenly into + * the 'dividend' metadata. + */ +NPY_NO_EXPORT npy_bool +datetime_metadata_divides( + PyArray_DatetimeMetaData *dividend, + PyArray_DatetimeMetaData *divisor, + int strict_with_nonlinear_units) +{ + npy_uint64 num1, num2; + + /* + * Any unit can always divide into generic units. In other words, we + * should be able to convert generic units into any more specific unit. + */ + if (dividend->base == NPY_FR_GENERIC) { + return 1; + } + /* + * However, generic units cannot always divide into more specific units. + * We cannot safely convert datetimes with units back into generic units. + */ + else if (divisor->base == NPY_FR_GENERIC) { + return 0; + } + + num1 = (npy_uint64)dividend->num; + num2 = (npy_uint64)divisor->num; + + /* If the bases are different, factor in a conversion */ + if (dividend->base != divisor->base) { + /* + * Years and Months are incompatible with + * all other units (except years and months are compatible + * with each other). + */ + if (dividend->base == NPY_FR_Y) { + if (divisor->base == NPY_FR_M) { + num1 *= 12; + } + else if (strict_with_nonlinear_units) { + return 0; + } + else { + /* Could do something complicated here */ + return 1; + } + } + else if (divisor->base == NPY_FR_Y) { + if (dividend->base == NPY_FR_M) { + num2 *= 12; + } + else if (strict_with_nonlinear_units) { + return 0; + } + else { + /* Could do something complicated here */ + return 1; + } + } + else if (dividend->base == NPY_FR_M || divisor->base == NPY_FR_M) { + if (strict_with_nonlinear_units) { + return 0; + } + else { + /* Could do something complicated here */ + return 1; + } + } + + /* Take the greater base (unit sizes are decreasing in enum) */ + if (dividend->base > divisor->base) { + num2 *= get_datetime_units_factor(divisor->base, dividend->base); + if (num2 == 0) { + return 0; + } + } + else { + num1 *= get_datetime_units_factor(dividend->base, divisor->base); + if (num1 == 0) { + return 0; + } + } + } + + /* Crude, incomplete check for overflow */ + if (num1&0xff00000000000000LL || num2&0xff00000000000000LL ) { + return 0; + } + + return (num1 % num2) == 0; +} + +/* + * This provides the casting rules for the DATETIME data type units. + */ +NPY_NO_EXPORT npy_bool +can_cast_datetime64_units(NPY_DATETIMEUNIT src_unit, + NPY_DATETIMEUNIT dst_unit, + NPY_CASTING casting) +{ + switch (casting) { + /* Allow anything with unsafe casting */ + case NPY_UNSAFE_CASTING: + return 1; + + /* + * Can cast between all units with 'same_kind' casting. + */ + case NPY_SAME_KIND_CASTING: + if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) { + return src_unit == NPY_FR_GENERIC; + } + else { + return 1; + } + + /* + * Casting is only allowed towards more precise units with 'safe' + * casting. + */ + case NPY_SAFE_CASTING: + if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) { + return src_unit == NPY_FR_GENERIC; + } + else { + return (src_unit <= dst_unit); + } + + /* Enforce equality with 'no' or 'equiv' casting */ + default: + return src_unit == dst_unit; + } +} + +/* + * This provides the casting rules for the TIMEDELTA data type units. + * + * Notably, there is a barrier between the nonlinear years and + * months units, and all the other units. + */ +NPY_NO_EXPORT npy_bool +can_cast_timedelta64_units(NPY_DATETIMEUNIT src_unit, + NPY_DATETIMEUNIT dst_unit, + NPY_CASTING casting) +{ + switch (casting) { + /* Allow anything with unsafe casting */ + case NPY_UNSAFE_CASTING: + return 1; + + /* + * Only enforce the 'date units' vs 'time units' barrier with + * 'same_kind' casting. + */ + case NPY_SAME_KIND_CASTING: + if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) { + return src_unit == NPY_FR_GENERIC; + } + else { + return (src_unit <= NPY_FR_M && dst_unit <= NPY_FR_M) || + (src_unit > NPY_FR_M && dst_unit > NPY_FR_M); + } + + /* + * Enforce the 'date units' vs 'time units' barrier and that + * casting is only allowed towards more precise units with + * 'safe' casting. + */ + case NPY_SAFE_CASTING: + if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) { + return src_unit == NPY_FR_GENERIC; + } + else { + return (src_unit <= dst_unit) && + ((src_unit <= NPY_FR_M && dst_unit <= NPY_FR_M) || + (src_unit > NPY_FR_M && dst_unit > NPY_FR_M)); + } + + /* Enforce equality with 'no' or 'equiv' casting */ + default: + return src_unit == dst_unit; + } +} + +/* + * This provides the casting rules for the DATETIME data type metadata. + */ +NPY_NO_EXPORT npy_bool +can_cast_datetime64_metadata(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + NPY_CASTING casting) +{ + switch (casting) { + case NPY_UNSAFE_CASTING: + return 1; + + case NPY_SAME_KIND_CASTING: + return can_cast_datetime64_units(src_meta->base, dst_meta->base, + casting); + + case NPY_SAFE_CASTING: + return can_cast_datetime64_units(src_meta->base, dst_meta->base, + casting) && + datetime_metadata_divides(src_meta, dst_meta, 0); + + default: + return src_meta->base == dst_meta->base && + src_meta->num == dst_meta->num; + } +} + +/* + * This provides the casting rules for the TIMEDELTA data type metadata. + */ +NPY_NO_EXPORT npy_bool +can_cast_timedelta64_metadata(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + NPY_CASTING casting) +{ + switch (casting) { + case NPY_UNSAFE_CASTING: + return 1; + + case NPY_SAME_KIND_CASTING: + return can_cast_timedelta64_units(src_meta->base, dst_meta->base, + casting); + + case NPY_SAFE_CASTING: + return can_cast_timedelta64_units(src_meta->base, dst_meta->base, + casting) && + datetime_metadata_divides(src_meta, dst_meta, 1); + + default: + return src_meta->base == dst_meta->base && + src_meta->num == dst_meta->num; + } +} + +/* + * Tests whether a datetime64 can be cast from the source metadata + * to the destination metadata according to the specified casting rule. + * + * Returns -1 if an exception was raised, 0 otherwise. + */ +NPY_NO_EXPORT int +raise_if_datetime64_metadata_cast_error(char *object_type, + PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + NPY_CASTING casting) +{ + if (can_cast_datetime64_metadata(src_meta, dst_meta, casting)) { + return 0; + } + else { + PyObject *errmsg; + errmsg = PyUString_FromFormat("Cannot cast %s " + "from metadata ", object_type); + errmsg = append_metastr_to_string(src_meta, 0, errmsg); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + errmsg = append_metastr_to_string(dst_meta, 0, errmsg); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" according to the rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } +} + +/* + * Tests whether a timedelta64 can be cast from the source metadata + * to the destination metadata according to the specified casting rule. + * + * Returns -1 if an exception was raised, 0 otherwise. + */ +NPY_NO_EXPORT int +raise_if_timedelta64_metadata_cast_error(char *object_type, + PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + NPY_CASTING casting) +{ + if (can_cast_timedelta64_metadata(src_meta, dst_meta, casting)) { + return 0; + } + else { + PyObject *errmsg; + errmsg = PyUString_FromFormat("Cannot cast %s " + "from metadata ", object_type); + errmsg = append_metastr_to_string(src_meta, 0, errmsg); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + errmsg = append_metastr_to_string(dst_meta, 0, errmsg); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" according to the rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } +} + +/* + * Computes the GCD of the two date-time metadata values. Raises + * an exception if there is no reasonable GCD, such as with + * years and days. + * + * The result is placed in 'out_meta'. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +compute_datetime_metadata_greatest_common_divisor( + PyArray_DatetimeMetaData *meta1, + PyArray_DatetimeMetaData *meta2, + PyArray_DatetimeMetaData *out_meta, + int strict_with_nonlinear_units1, + int strict_with_nonlinear_units2) +{ + NPY_DATETIMEUNIT base; + npy_uint64 num1, num2, num; + + /* If either unit is generic, adopt the metadata from the other one */ + if (meta1->base == NPY_FR_GENERIC) { + *out_meta = *meta2; + return 0; + } + else if (meta2->base == NPY_FR_GENERIC) { + *out_meta = *meta1; + return 0; + } + + num1 = (npy_uint64)meta1->num; + num2 = (npy_uint64)meta2->num; + + /* First validate that the units have a reasonable GCD */ + if (meta1->base == meta2->base) { + base = meta1->base; + } + else { + /* + * Years and Months are incompatible with + * all other units (except years and months are compatible + * with each other). + */ + if (meta1->base == NPY_FR_Y) { + if (meta2->base == NPY_FR_M) { + base = NPY_FR_M; + num1 *= 12; + } + else if (strict_with_nonlinear_units1) { + goto incompatible_units; + } + else { + base = meta2->base; + /* Don't multiply num1 since there is no even factor */ + } + } + else if (meta2->base == NPY_FR_Y) { + if (meta1->base == NPY_FR_M) { + base = NPY_FR_M; + num2 *= 12; + } + else if (strict_with_nonlinear_units2) { + goto incompatible_units; + } + else { + base = meta1->base; + /* Don't multiply num2 since there is no even factor */ + } + } + else if (meta1->base == NPY_FR_M) { + if (strict_with_nonlinear_units1) { + goto incompatible_units; + } + else { + base = meta2->base; + /* Don't multiply num1 since there is no even factor */ + } + } + else if (meta2->base == NPY_FR_M) { + if (strict_with_nonlinear_units2) { + goto incompatible_units; + } + else { + base = meta1->base; + /* Don't multiply num2 since there is no even factor */ + } + } + + /* Take the greater base (unit sizes are decreasing in enum) */ + if (meta1->base > meta2->base) { + base = meta1->base; + num2 *= get_datetime_units_factor(meta2->base, meta1->base); + if (num2 == 0) { + goto units_overflow; + } + } + else { + base = meta2->base; + num1 *= get_datetime_units_factor(meta1->base, meta2->base); + if (num1 == 0) { + goto units_overflow; + } + } + } + + /* Compute the GCD of the resulting multipliers */ + num = _uint64_euclidean_gcd(num1, num2); + + /* Fill the 'out_meta' values */ + out_meta->base = base; + out_meta->num = (int)num; + if (out_meta->num <= 0 || num != (npy_uint64)out_meta->num) { + goto units_overflow; + } + + return 0; + +incompatible_units: { + PyObject *errmsg; + errmsg = PyUString_FromString("Cannot get " + "a common metadata divisor for " + "NumPy datetime metadata "); + errmsg = append_metastr_to_string(meta1, 0, errmsg); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" and ")); + errmsg = append_metastr_to_string(meta2, 0, errmsg); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" because they have " + "incompatible nonlinear base time units")); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } +units_overflow: { + PyObject *errmsg; + errmsg = PyUString_FromString("Integer overflow " + "getting a common metadata divisor for " + "NumPy datetime metadata "); + errmsg = append_metastr_to_string(meta1, 0, errmsg); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" and ")); + errmsg = append_metastr_to_string(meta2, 0, errmsg); + PyErr_SetObject(PyExc_OverflowError, errmsg); + Py_DECREF(errmsg); + return -1; + } +} + +/* + * Both type1 and type2 must be either NPY_DATETIME or NPY_TIMEDELTA. + * Applies the type promotion rules between the two types, returning + * the promoted type. + */ +NPY_NO_EXPORT PyArray_Descr * +datetime_type_promotion(PyArray_Descr *type1, PyArray_Descr *type2) +{ + int type_num1, type_num2; + PyArray_Descr *dtype; + int is_datetime; + + type_num1 = type1->type_num; + type_num2 = type2->type_num; + + is_datetime = (type_num1 == NPY_DATETIME || type_num2 == NPY_DATETIME); + + /* Create a DATETIME or TIMEDELTA dtype */ + dtype = PyArray_DescrNewFromType(is_datetime ? NPY_DATETIME : + NPY_TIMEDELTA); + if (dtype == NULL) { + return NULL; + } + + /* + * Get the metadata GCD, being strict about nonlinear units for + * timedelta and relaxed for datetime. + */ + if (compute_datetime_metadata_greatest_common_divisor( + get_datetime_metadata_from_dtype(type1), + get_datetime_metadata_from_dtype(type2), + get_datetime_metadata_from_dtype(dtype), + type_num1 == NPY_TIMEDELTA, + type_num2 == NPY_TIMEDELTA) < 0) { + Py_DECREF(dtype); + return NULL; + } + + return dtype; +} + +/* + * Converts a substring given by 'str' and 'len' into + * a date time unit enum value. The 'metastr' parameter + * is used for error messages, and may be NULL. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT NPY_DATETIMEUNIT +parse_datetime_unit_from_string(char *str, Py_ssize_t len, char *metastr) +{ + /* Use switch statements so the compiler can make it fast */ + if (len == 1) { + switch (str[0]) { + case 'Y': + return NPY_FR_Y; + case 'M': + return NPY_FR_M; + case 'W': + return NPY_FR_W; + case 'D': + return NPY_FR_D; + case 'h': + return NPY_FR_h; + case 'm': + return NPY_FR_m; + case 's': + return NPY_FR_s; + } + } + /* All the two-letter units are variants of seconds */ + else if (len == 2 && str[1] == 's') { + switch (str[0]) { + case 'm': + return NPY_FR_ms; + case 'u': + return NPY_FR_us; + case 'n': + return NPY_FR_ns; + case 'p': + return NPY_FR_ps; + case 'f': + return NPY_FR_fs; + case 'a': + return NPY_FR_as; + } + } + else if (len == 7 && !strncmp(str, "generic", 7)) { + return NPY_FR_GENERIC; + } + + /* If nothing matched, it's an error */ + if (metastr == NULL) { + PyErr_Format(PyExc_TypeError, + "Invalid datetime unit \"%s\" in metadata", + str); + } + else { + PyErr_Format(PyExc_TypeError, + "Invalid datetime unit in metadata string \"%s\"", + metastr); + } + return -1; +} + + +NPY_NO_EXPORT PyObject * +convert_datetime_metadata_to_tuple(PyArray_DatetimeMetaData *meta) +{ + PyObject *dt_tuple; + + dt_tuple = PyTuple_New(2); + if (dt_tuple == NULL) { + return NULL; + } + + PyTuple_SET_ITEM(dt_tuple, 0, + PyUString_FromString(_datetime_strings[meta->base])); + PyTuple_SET_ITEM(dt_tuple, 1, + PyInt_FromLong(meta->num)); + + return dt_tuple; +} + +/* + * Converts a metadata tuple into a datetime metadata C struct. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_datetime_metadata_tuple_to_datetime_metadata(PyObject *tuple, + PyArray_DatetimeMetaData *out_meta, + npy_bool from_pickle) +{ + char *basestr = NULL; + Py_ssize_t len = 0, tuple_size; + int den = 1; + PyObject *unit_str = NULL; + + if (!PyTuple_Check(tuple)) { + PyObject *errmsg; + errmsg = PyUString_FromString("Require tuple for tuple to NumPy " + "datetime metadata conversion, not "); + PyUString_ConcatAndDel(&errmsg, PyObject_Repr(tuple)); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } + + tuple_size = PyTuple_GET_SIZE(tuple); + if (tuple_size < 2 || tuple_size > 4) { + PyErr_SetString(PyExc_TypeError, + "Require tuple of size 2 to 4 for " + "tuple to NumPy datetime metadata conversion"); + return -1; + } + + unit_str = PyTuple_GET_ITEM(tuple, 0); + Py_INCREF(unit_str); + if (PyUnicode_Check(unit_str)) { + /* Allow unicode format strings: convert to bytes */ + PyObject *tmp = PyUnicode_AsASCIIString(unit_str); + Py_DECREF(unit_str); + if (tmp == NULL) { + return -1; + } + unit_str = tmp; + } + if (PyBytes_AsStringAndSize(unit_str, &basestr, &len) < 0) { + Py_DECREF(unit_str); + return -1; + } + + out_meta->base = parse_datetime_unit_from_string(basestr, len, NULL); + if (out_meta->base == -1) { + Py_DECREF(unit_str); + return -1; + } + + Py_DECREF(unit_str); + + /* Convert the values to longs */ + out_meta->num = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 1)); + if (error_converting(out_meta->num)) { + return -1; + } + + /* + * The event metadata was removed way back in numpy 1.7 (cb4545), but was + * not deprecated at the time. + */ + + /* (unit, num, event) */ + if (tuple_size == 3) { + /* Numpy 1.14, 2017-08-11 */ + if (DEPRECATE( + "When passing a 3-tuple as (unit, num, event), the event " + "is ignored (since 1.7) - use (unit, num) instead") < 0) { + return -1; + } + } + /* (unit, num, den, event) */ + else if (tuple_size == 4) { + PyObject *event = PyTuple_GET_ITEM(tuple, 3); + if (from_pickle) { + /* if (event == 1) */ + PyObject *one = PyLong_FromLong(1); + int equal_one; + if (one == NULL) { + return -1; + } + equal_one = PyObject_RichCompareBool(event, one, Py_EQ); + if (equal_one == -1) { + return -1; + } + + /* if the event data is not 1, it had semantics different to how + * datetime types now behave, which are no longer respected. + */ + if (!equal_one) { + if (PyErr_WarnEx(PyExc_UserWarning, + "Loaded pickle file contains non-default event data " + "for a datetime type, which has been ignored since 1.7", + 1) < 0) { + return -1; + } + } + } + else if (event != Py_None) { + /* Numpy 1.14, 2017-08-11 */ + if (DEPRECATE( + "When passing a 4-tuple as (unit, num, den, event), the " + "event argument is ignored (since 1.7), so should be None" + ) < 0) { + return -1; + } + } + den = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 2)); + if (error_converting(den)) { + return -1; + } + } + + if (out_meta->num <= 0 || den <= 0) { + PyErr_SetString(PyExc_TypeError, + "Invalid tuple values for " + "tuple to NumPy datetime metadata conversion"); + return -1; + } + + if (den != 1) { + if (convert_datetime_divisor_to_multiple(out_meta, den, NULL) < 0) { + return -1; + } + } + + return 0; +} + +/* + * Converts an input object into datetime metadata. The input + * may be either a string or a tuple. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_pyobject_to_datetime_metadata(PyObject *obj, + PyArray_DatetimeMetaData *out_meta) +{ + PyObject *ascii = NULL; + char *str = NULL; + Py_ssize_t len = 0; + + if (PyTuple_Check(obj)) { + return convert_datetime_metadata_tuple_to_datetime_metadata( + obj, out_meta, NPY_FALSE); + } + + /* Get an ASCII string */ + if (PyUnicode_Check(obj)) { + /* Allow unicode format strings: convert to bytes */ + ascii = PyUnicode_AsASCIIString(obj); + if (ascii == NULL) { + return -1; + } + } + else if (PyBytes_Check(obj)) { + ascii = obj; + Py_INCREF(ascii); + } + else { + PyErr_SetString(PyExc_TypeError, + "Invalid object for specifying NumPy datetime metadata"); + return -1; + } + + if (PyBytes_AsStringAndSize(ascii, &str, &len) < 0) { + Py_DECREF(ascii); + return -1; + } + + if (len > 0 && str[0] == '[') { + int r = parse_datetime_metadata_from_metastr(str, len, out_meta); + Py_DECREF(ascii); + return r; + } + else { + if (parse_datetime_extended_unit_from_string(str, len, + NULL, out_meta) < 0) { + Py_DECREF(ascii); + return -1; + } + + Py_DECREF(ascii); + return 0; + } +} + +/* + * 'ret' is a PyUString containing the datetime string, and this + * function appends the metadata string to it. + * + * If 'skip_brackets' is true, skips the '[]'. + * + * This function steals the reference 'ret' + */ +NPY_NO_EXPORT PyObject * +append_metastr_to_string(PyArray_DatetimeMetaData *meta, + int skip_brackets, + PyObject *ret) +{ + PyObject *res; + int num; + char *basestr; + + if (ret == NULL) { + return NULL; + } + + if (meta->base == NPY_FR_GENERIC) { + /* Without brackets, give a string "generic" */ + if (skip_brackets) { + PyUString_ConcatAndDel(&ret, PyUString_FromString("generic")); + return ret; + } + /* But with brackets, append nothing */ + else { + return ret; + } + } + + num = meta->num; + if (meta->base >= 0 && meta->base < NPY_DATETIME_NUMUNITS) { + basestr = _datetime_strings[meta->base]; + } + else { + PyErr_SetString(PyExc_RuntimeError, + "NumPy datetime metadata is corrupted"); + return NULL; + } + + if (num == 1) { + if (skip_brackets) { + res = PyUString_FromFormat("%s", basestr); + } + else { + res = PyUString_FromFormat("[%s]", basestr); + } + } + else { + if (skip_brackets) { + res = PyUString_FromFormat("%d%s", num, basestr); + } + else { + res = PyUString_FromFormat("[%d%s]", num, basestr); + } + } + + PyUString_ConcatAndDel(&ret, res); + return ret; +} + +/* + * Adjusts a datetimestruct based on a seconds offset. Assumes + * the current values are valid. + */ +NPY_NO_EXPORT void +add_seconds_to_datetimestruct(npy_datetimestruct *dts, int seconds) +{ + int minutes; + + dts->sec += seconds; + if (dts->sec < 0) { + minutes = dts->sec / 60; + dts->sec = dts->sec % 60; + if (dts->sec < 0) { + --minutes; + dts->sec += 60; + } + add_minutes_to_datetimestruct(dts, minutes); + } + else if (dts->sec >= 60) { + minutes = dts->sec / 60; + dts->sec = dts->sec % 60; + add_minutes_to_datetimestruct(dts, minutes); + } +} + +/* + * Adjusts a datetimestruct based on a minutes offset. Assumes + * the current values are valid. + */ +NPY_NO_EXPORT void +add_minutes_to_datetimestruct(npy_datetimestruct *dts, int minutes) +{ + int isleap; + + /* MINUTES */ + dts->min += minutes; + while (dts->min < 0) { + dts->min += 60; + dts->hour--; + } + while (dts->min >= 60) { + dts->min -= 60; + dts->hour++; + } + + /* HOURS */ + while (dts->hour < 0) { + dts->hour += 24; + dts->day--; + } + while (dts->hour >= 24) { + dts->hour -= 24; + dts->day++; + } + + /* DAYS */ + if (dts->day < 1) { + dts->month--; + if (dts->month < 1) { + dts->year--; + dts->month = 12; + } + isleap = is_leapyear(dts->year); + dts->day += _days_per_month_table[isleap][dts->month-1]; + } + else if (dts->day > 28) { + isleap = is_leapyear(dts->year); + if (dts->day > _days_per_month_table[isleap][dts->month-1]) { + dts->day -= _days_per_month_table[isleap][dts->month-1]; + dts->month++; + if (dts->month > 12) { + dts->year++; + dts->month = 1; + } + } + } +} + +/* + * Tests for and converts a Python datetime.datetime or datetime.date + * object into a NumPy npy_datetimestruct. + * + * While the C API has PyDate_* and PyDateTime_* functions, the following + * implementation just asks for attributes, and thus supports + * datetime duck typing. The tzinfo time zone conversion would require + * this style of access anyway. + * + * 'out_bestunit' gives a suggested unit based on whether the object + * was a datetime.date or datetime.datetime object. + * + * If 'apply_tzinfo' is 1, this function uses the tzinfo to convert + * to UTC time, otherwise it returns the struct with the local time. + * + * Returns -1 on error, 0 on success, and 1 (with no error set) + * if obj doesn't have the neeeded date or datetime attributes. + */ +NPY_NO_EXPORT int +convert_pydatetime_to_datetimestruct(PyObject *obj, npy_datetimestruct *out, + NPY_DATETIMEUNIT *out_bestunit, + int apply_tzinfo) +{ + PyObject *tmp; + int isleap; + + /* Initialize the output to all zeros */ + memset(out, 0, sizeof(npy_datetimestruct)); + out->month = 1; + out->day = 1; + + /* Need at least year/month/day attributes */ + if (!PyObject_HasAttrString(obj, "year") || + !PyObject_HasAttrString(obj, "month") || + !PyObject_HasAttrString(obj, "day")) { + return 1; + } + + /* Get the year */ + tmp = PyObject_GetAttrString(obj, "year"); + if (tmp == NULL) { + return -1; + } + out->year = PyInt_AsLong(tmp); + if (error_converting(out->year)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Get the month */ + tmp = PyObject_GetAttrString(obj, "month"); + if (tmp == NULL) { + return -1; + } + out->month = PyInt_AsLong(tmp); + if (error_converting(out->month)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Get the day */ + tmp = PyObject_GetAttrString(obj, "day"); + if (tmp == NULL) { + return -1; + } + out->day = PyInt_AsLong(tmp); + if (error_converting(out->day)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Validate that the month and day are valid for the year */ + if (out->month < 1 || out->month > 12) { + goto invalid_date; + } + isleap = is_leapyear(out->year); + if (out->day < 1 || + out->day > _days_per_month_table[isleap][out->month-1]) { + goto invalid_date; + } + + /* Check for time attributes (if not there, return success as a date) */ + if (!PyObject_HasAttrString(obj, "hour") || + !PyObject_HasAttrString(obj, "minute") || + !PyObject_HasAttrString(obj, "second") || + !PyObject_HasAttrString(obj, "microsecond")) { + /* The best unit for date is 'D' */ + if (out_bestunit != NULL) { + *out_bestunit = NPY_FR_D; + } + return 0; + } + + /* Get the hour */ + tmp = PyObject_GetAttrString(obj, "hour"); + if (tmp == NULL) { + return -1; + } + out->hour = PyInt_AsLong(tmp); + if (error_converting(out->hour)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Get the minute */ + tmp = PyObject_GetAttrString(obj, "minute"); + if (tmp == NULL) { + return -1; + } + out->min = PyInt_AsLong(tmp); + if (error_converting(out->min)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Get the second */ + tmp = PyObject_GetAttrString(obj, "second"); + if (tmp == NULL) { + return -1; + } + out->sec = PyInt_AsLong(tmp); + if (error_converting(out->sec)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Get the microsecond */ + tmp = PyObject_GetAttrString(obj, "microsecond"); + if (tmp == NULL) { + return -1; + } + out->us = PyInt_AsLong(tmp); + if (error_converting(out->us)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + if (out->hour < 0 || out->hour >= 24 || + out->min < 0 || out->min >= 60 || + out->sec < 0 || out->sec >= 60 || + out->us < 0 || out->us >= 1000000) { + goto invalid_time; + } + + /* Apply the time zone offset if it exists */ + if (apply_tzinfo && PyObject_HasAttrString(obj, "tzinfo")) { + tmp = PyObject_GetAttrString(obj, "tzinfo"); + if (tmp == NULL) { + return -1; + } + if (tmp == Py_None) { + Py_DECREF(tmp); + } + else { + PyObject *offset; + int seconds_offset, minutes_offset; + + /* 2016-01-14, 1.11 */ + PyErr_Clear(); + if (DEPRECATE( + "parsing timezone aware datetimes is deprecated; " + "this will raise an error in the future") < 0) { + return -1; + } + + /* The utcoffset function should return a timedelta */ + offset = PyObject_CallMethod(tmp, "utcoffset", "O", obj); + if (offset == NULL) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* + * The timedelta should have a function "total_seconds" + * which contains the value we want. + */ + tmp = PyObject_CallMethod(offset, "total_seconds", ""); + if (tmp == NULL) { + return -1; + } + seconds_offset = PyInt_AsLong(tmp); + if (error_converting(seconds_offset)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Convert to a minutes offset and apply it */ + minutes_offset = seconds_offset / 60; + + add_minutes_to_datetimestruct(out, -minutes_offset); + } + } + + /* The resolution of Python's datetime is 'us' */ + if (out_bestunit != NULL) { + *out_bestunit = NPY_FR_us; + } + + return 0; + +invalid_date: + PyErr_Format(PyExc_ValueError, + "Invalid date (%d,%d,%d) when converting to NumPy datetime", + (int)out->year, (int)out->month, (int)out->day); + return -1; + +invalid_time: + PyErr_Format(PyExc_ValueError, + "Invalid time (%d,%d,%d,%d) when converting " + "to NumPy datetime", + (int)out->hour, (int)out->min, (int)out->sec, (int)out->us); + return -1; +} + +/* + * Gets a tzoffset in minutes by calling the fromutc() function on + * the Python datetime.tzinfo object. + */ +NPY_NO_EXPORT int +get_tzoffset_from_pytzinfo(PyObject *timezone_obj, npy_datetimestruct *dts) +{ + PyObject *dt, *loc_dt; + npy_datetimestruct loc_dts; + + /* Create a Python datetime to give to the timezone object */ + dt = PyDateTime_FromDateAndTime((int)dts->year, dts->month, dts->day, + dts->hour, dts->min, 0, 0); + if (dt == NULL) { + return -1; + } + + /* Convert the datetime from UTC to local time */ + loc_dt = PyObject_CallMethod(timezone_obj, "fromutc", "O", dt); + Py_DECREF(dt); + if (loc_dt == NULL) { + return -1; + } + + /* Convert the local datetime into a datetimestruct */ + if (convert_pydatetime_to_datetimestruct(loc_dt, &loc_dts, NULL, 0) < 0) { + Py_DECREF(loc_dt); + return -1; + } + + Py_DECREF(loc_dt); + + /* Calculate the tzoffset as the difference between the datetimes */ + return (int)(get_datetimestruct_minutes(&loc_dts) - + get_datetimestruct_minutes(dts)); +} + +/* + * Converts a PyObject * into a datetime, in any of the forms supported. + * + * If the units metadata isn't known ahead of time, set meta->base + * to -1, and this function will populate meta with either default + * values or values from the input object. + * + * The 'casting' parameter is used to control what kinds of inputs + * are accepted, and what happens. For example, with 'unsafe' casting, + * unrecognized inputs are converted to 'NaT' instead of throwing an error, + * while with 'safe' casting an error will be thrown if any precision + * from the input will be thrown away. + * + * Returns -1 on error, 0 on success. + */ +NPY_NO_EXPORT int +convert_pyobject_to_datetime(PyArray_DatetimeMetaData *meta, PyObject *obj, + NPY_CASTING casting, npy_datetime *out) +{ + if (PyBytes_Check(obj) || PyUnicode_Check(obj)) { + PyObject *bytes = NULL; + char *str = NULL; + Py_ssize_t len = 0; + npy_datetimestruct dts; + NPY_DATETIMEUNIT bestunit = -1; + + /* Convert to an ASCII string for the date parser */ + if (PyUnicode_Check(obj)) { + bytes = PyUnicode_AsASCIIString(obj); + if (bytes == NULL) { + return -1; + } + } + else { + bytes = obj; + Py_INCREF(bytes); + } + if (PyBytes_AsStringAndSize(bytes, &str, &len) < 0) { + Py_DECREF(bytes); + return -1; + } + + /* Parse the ISO date */ + if (parse_iso_8601_datetime(str, len, meta->base, casting, + &dts, &bestunit, NULL) < 0) { + Py_DECREF(bytes); + return -1; + } + + /* Use the detected unit if none was specified */ + if (meta->base == -1) { + meta->base = bestunit; + meta->num = 1; + } + + if (convert_datetimestruct_to_datetime(meta, &dts, out) < 0) { + Py_DECREF(bytes); + return -1; + } + + Py_DECREF(bytes); + return 0; + } + /* Do no conversion on raw integers */ + else if (PyInt_Check(obj) || PyLong_Check(obj)) { + /* Don't allow conversion from an integer without specifying a unit */ + if (meta->base == -1 || meta->base == NPY_FR_GENERIC) { + PyErr_SetString(PyExc_ValueError, "Converting an integer to a " + "NumPy datetime requires a specified unit"); + return -1; + } + *out = PyLong_AsLongLong(obj); + return 0; + } + /* Datetime scalar */ + else if (PyArray_IsScalar(obj, Datetime)) { + PyDatetimeScalarObject *dts = (PyDatetimeScalarObject *)obj; + + /* Copy the scalar directly if units weren't specified */ + if (meta->base == -1) { + *meta = dts->obmeta; + *out = dts->obval; + + return 0; + } + /* Otherwise do a casting transformation */ + else { + /* Allow NaT (not-a-time) values to slip through any rule */ + if (dts->obval != NPY_DATETIME_NAT && + raise_if_datetime64_metadata_cast_error( + "NumPy timedelta64 scalar", + &dts->obmeta, meta, casting) < 0) { + return -1; + } + else { + return cast_datetime_to_datetime(&dts->obmeta, meta, + dts->obval, out); + } + } + } + /* Datetime zero-dimensional array */ + else if (PyArray_Check(obj) && + PyArray_NDIM((PyArrayObject *)obj) == 0 && + PyArray_DESCR((PyArrayObject *)obj)->type_num == NPY_DATETIME) { + PyArrayObject *arr = (PyArrayObject *)obj; + PyArray_DatetimeMetaData *arr_meta; + npy_datetime dt = 0; + + arr_meta = get_datetime_metadata_from_dtype(PyArray_DESCR(arr)); + if (arr_meta == NULL) { + return -1; + } + PyArray_DESCR(arr)->f->copyswap(&dt, + PyArray_DATA(arr), + PyArray_ISBYTESWAPPED(arr), + obj); + + /* Copy the value directly if units weren't specified */ + if (meta->base == -1) { + *meta = *arr_meta; + *out = dt; + + return 0; + } + /* Otherwise do a casting transformation */ + else { + /* Allow NaT (not-a-time) values to slip through any rule */ + if (dt != NPY_DATETIME_NAT && + raise_if_datetime64_metadata_cast_error( + "NumPy timedelta64 scalar", + arr_meta, meta, casting) < 0) { + return -1; + } + else { + return cast_datetime_to_datetime(arr_meta, meta, dt, out); + } + } + } + /* Convert from a Python date or datetime object */ + else { + int code; + npy_datetimestruct dts; + NPY_DATETIMEUNIT bestunit = -1; + + code = convert_pydatetime_to_datetimestruct(obj, &dts, &bestunit, 1); + if (code == -1) { + return -1; + } + else if (code == 0) { + /* Use the detected unit if none was specified */ + if (meta->base == -1) { + meta->base = bestunit; + meta->num = 1; + } + else { + PyArray_DatetimeMetaData obj_meta; + obj_meta.base = bestunit; + obj_meta.num = 1; + + if (raise_if_datetime64_metadata_cast_error( + bestunit == NPY_FR_D ? "datetime.date object" + : "datetime.datetime object", + &obj_meta, meta, casting) < 0) { + return -1; + } + } + + return convert_datetimestruct_to_datetime(meta, &dts, out); + } + } + + /* + * With unsafe casting, convert unrecognized objects into NaT + * and with same_kind casting, convert None into NaT + */ + if (casting == NPY_UNSAFE_CASTING || + (obj == Py_None && casting == NPY_SAME_KIND_CASTING)) { + if (meta->base == -1) { + meta->base = NPY_FR_GENERIC; + meta->num = 1; + } + *out = NPY_DATETIME_NAT; + return 0; + } + else { + PyErr_SetString(PyExc_ValueError, + "Could not convert object to NumPy datetime"); + return -1; + } +} + +/* + * Converts a PyObject * into a timedelta, in any of the forms supported + * + * If the units metadata isn't known ahead of time, set meta->base + * to -1, and this function will populate meta with either default + * values or values from the input object. + * + * The 'casting' parameter is used to control what kinds of inputs + * are accepted, and what happens. For example, with 'unsafe' casting, + * unrecognized inputs are converted to 'NaT' instead of throwing an error, + * while with 'safe' casting an error will be thrown if any precision + * from the input will be thrown away. + * + * Returns -1 on error, 0 on success. + */ +NPY_NO_EXPORT int +convert_pyobject_to_timedelta(PyArray_DatetimeMetaData *meta, PyObject *obj, + NPY_CASTING casting, npy_timedelta *out) +{ + if (PyBytes_Check(obj) || PyUnicode_Check(obj)) { + PyObject *bytes = NULL; + char *str = NULL; + Py_ssize_t len = 0; + int succeeded = 0; + + /* Convert to an ASCII string for the date parser */ + if (PyUnicode_Check(obj)) { + bytes = PyUnicode_AsASCIIString(obj); + if (bytes == NULL) { + return -1; + } + } + else { + bytes = obj; + Py_INCREF(bytes); + } + if (PyBytes_AsStringAndSize(bytes, &str, &len) < 0) { + Py_DECREF(bytes); + return -1; + } + + /* Check for a NaT string */ + if (len <= 0 || (len == 3 && + tolower(str[0]) == 'n' && + tolower(str[1]) == 'a' && + tolower(str[2]) == 't')) { + *out = NPY_DATETIME_NAT; + succeeded = 1; + } + /* Parse as an integer */ + else { + char *strend = NULL; + + *out = strtol(str, &strend, 10); + if (strend - str == len) { + succeeded = 1; + } + } + Py_DECREF(bytes); + + if (succeeded) { + /* Use generic units if none was specified */ + if (meta->base == -1) { + meta->base = NPY_FR_GENERIC; + meta->num = 1; + } + + return 0; + } + } + /* Do no conversion on raw integers */ + else if (PyInt_Check(obj) || PyLong_Check(obj)) { + /* Use the default unit if none was specified */ + if (meta->base == -1) { + meta->base = NPY_DATETIME_DEFAULTUNIT; + meta->num = 1; + } + + *out = PyLong_AsLongLong(obj); + return 0; + } + /* Timedelta scalar */ + else if (PyArray_IsScalar(obj, Timedelta)) { + PyTimedeltaScalarObject *dts = (PyTimedeltaScalarObject *)obj; + + /* Copy the scalar directly if units weren't specified */ + if (meta->base == -1) { + *meta = dts->obmeta; + *out = dts->obval; + + return 0; + } + /* Otherwise do a casting transformation */ + else { + /* Allow NaT (not-a-time) values to slip through any rule */ + if (dts->obval != NPY_DATETIME_NAT && + raise_if_timedelta64_metadata_cast_error( + "NumPy timedelta64 scalar", + &dts->obmeta, meta, casting) < 0) { + return -1; + } + else { + return cast_timedelta_to_timedelta(&dts->obmeta, meta, + dts->obval, out); + } + } + } + /* Timedelta zero-dimensional array */ + else if (PyArray_Check(obj) && + PyArray_NDIM((PyArrayObject *)obj) == 0 && + PyArray_DESCR((PyArrayObject *)obj)->type_num == NPY_TIMEDELTA) { + PyArrayObject *arr = (PyArrayObject *)obj; + PyArray_DatetimeMetaData *arr_meta; + npy_timedelta dt = 0; + + arr_meta = get_datetime_metadata_from_dtype(PyArray_DESCR(arr)); + if (arr_meta == NULL) { + return -1; + } + PyArray_DESCR(arr)->f->copyswap(&dt, + PyArray_DATA(arr), + PyArray_ISBYTESWAPPED(arr), + obj); + + /* Copy the value directly if units weren't specified */ + if (meta->base == -1) { + *meta = *arr_meta; + *out = dt; + + return 0; + } + /* Otherwise do a casting transformation */ + else { + /* Allow NaT (not-a-time) values to slip through any rule */ + if (dt != NPY_DATETIME_NAT && + raise_if_timedelta64_metadata_cast_error( + "NumPy timedelta64 scalar", + arr_meta, meta, casting) < 0) { + return -1; + } + else { + return cast_timedelta_to_timedelta(arr_meta, meta, dt, out); + } + } + } + /* Convert from a Python timedelta object */ + else if (PyObject_HasAttrString(obj, "days") && + PyObject_HasAttrString(obj, "seconds") && + PyObject_HasAttrString(obj, "microseconds")) { + PyObject *tmp; + PyArray_DatetimeMetaData us_meta; + npy_timedelta td; + npy_int64 days; + int seconds = 0, useconds = 0; + + /* Get the days */ + tmp = PyObject_GetAttrString(obj, "days"); + if (tmp == NULL) { + return -1; + } + days = PyLong_AsLongLong(tmp); + if (error_converting(days)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Get the seconds */ + tmp = PyObject_GetAttrString(obj, "seconds"); + if (tmp == NULL) { + return -1; + } + seconds = PyInt_AsLong(tmp); + if (error_converting(seconds)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + /* Get the microseconds */ + tmp = PyObject_GetAttrString(obj, "microseconds"); + if (tmp == NULL) { + return -1; + } + useconds = PyInt_AsLong(tmp); + if (error_converting(useconds)) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + + td = days*(24*60*60*1000000LL) + seconds*1000000LL + useconds; + + /* Use microseconds if none was specified */ + if (meta->base == -1) { + meta->base = NPY_FR_us; + meta->num = 1; + + *out = td; + + return 0; + } + else { + /* + * Detect the largest unit where every value after is zero, + * to allow safe casting to seconds if microseconds is zero, + * for instance. + */ + if (td % 1000LL != 0) { + us_meta.base = NPY_FR_us; + } + else if (td % 1000000LL != 0) { + us_meta.base = NPY_FR_ms; + } + else if (td % (60*1000000LL) != 0) { + us_meta.base = NPY_FR_s; + } + else if (td % (60*60*1000000LL) != 0) { + us_meta.base = NPY_FR_m; + } + else if (td % (24*60*60*1000000LL) != 0) { + us_meta.base = NPY_FR_D; + } + else if (td % (7*24*60*60*1000000LL) != 0) { + us_meta.base = NPY_FR_W; + } + us_meta.num = 1; + + if (raise_if_timedelta64_metadata_cast_error( + "datetime.timedelta object", + &us_meta, meta, casting) < 0) { + return -1; + } + else { + /* Switch back to microseconds for the casting operation */ + us_meta.base = NPY_FR_us; + + return cast_timedelta_to_timedelta(&us_meta, meta, td, out); + } + } + } + + /* + * With unsafe casting, convert unrecognized objects into NaT + * and with same_kind casting, convert None into NaT + */ + if (casting == NPY_UNSAFE_CASTING || + (obj == Py_None && casting == NPY_SAME_KIND_CASTING)) { + if (meta->base == -1) { + meta->base = NPY_FR_GENERIC; + meta->num = 1; + } + *out = NPY_DATETIME_NAT; + return 0; + } + else { + PyErr_SetString(PyExc_ValueError, + "Could not convert object to NumPy timedelta"); + return -1; + } +} + +/* + * Converts a datetime into a PyObject *. + * + * Not-a-time is returned as the string "NaT". + * For days or coarser, returns a datetime.date. + * For microseconds or coarser, returns a datetime.datetime. + * For units finer than microseconds, returns an integer. + */ +NPY_NO_EXPORT PyObject * +convert_datetime_to_pyobject(npy_datetime dt, PyArray_DatetimeMetaData *meta) +{ + PyObject *ret = NULL; + npy_datetimestruct dts; + + /* + * Convert NaT (not-a-time) and any value with generic units + * into None. + */ + if (dt == NPY_DATETIME_NAT || meta->base == NPY_FR_GENERIC) { + Py_RETURN_NONE; + } + + /* If the type's precision is greater than microseconds, return an int */ + if (meta->base > NPY_FR_us) { + return PyLong_FromLongLong(dt); + } + + /* Convert to a datetimestruct */ + if (convert_datetime_to_datetimestruct(meta, dt, &dts) < 0) { + return NULL; + } + + /* + * If the year is outside the range of years supported by Python's + * datetime, or the datetime64 falls on a leap second, + * return a raw int. + */ + if (dts.year < 1 || dts.year > 9999 || dts.sec == 60) { + return PyLong_FromLongLong(dt); + } + + /* If the type's precision is greater than days, return a datetime */ + if (meta->base > NPY_FR_D) { + ret = PyDateTime_FromDateAndTime(dts.year, dts.month, dts.day, + dts.hour, dts.min, dts.sec, dts.us); + } + /* Otherwise return a date */ + else { + ret = PyDate_FromDate(dts.year, dts.month, dts.day); + } + + return ret; +} + +/* + * Converts a timedelta into a PyObject *. + * + * Not-a-time is returned as the string "NaT". + * For microseconds or coarser, returns a datetime.timedelta. + * For units finer than microseconds, returns an integer. + */ +NPY_NO_EXPORT PyObject * +convert_timedelta_to_pyobject(npy_timedelta td, PyArray_DatetimeMetaData *meta) +{ + PyObject *ret = NULL; + npy_timedelta value; + int days = 0, seconds = 0, useconds = 0; + + /* + * Convert NaT (not-a-time) into None. + */ + if (td == NPY_DATETIME_NAT) { + Py_RETURN_NONE; + } + + /* + * If the type's precision is greater than microseconds, is + * Y/M/B (nonlinear units), or is generic units, return an int + */ + if (meta->base > NPY_FR_us || + meta->base == NPY_FR_Y || + meta->base == NPY_FR_M || + meta->base == NPY_FR_GENERIC) { + return PyLong_FromLongLong(td); + } + + value = td; + + /* Apply the unit multiplier (TODO: overflow treatment...) */ + value *= meta->num; + + /* Convert to days/seconds/useconds */ + switch (meta->base) { + case NPY_FR_W: + value *= 7; + break; + case NPY_FR_D: + break; + case NPY_FR_h: + seconds = (int)((value % 24) * (60*60)); + value = value / 24; + break; + case NPY_FR_m: + seconds = (int)(value % (24*60)) * 60; + value = value / (24*60); + break; + case NPY_FR_s: + seconds = (int)(value % (24*60*60)); + value = value / (24*60*60); + break; + case NPY_FR_ms: + useconds = (int)(value % 1000) * 1000; + value = value / 1000; + seconds = (int)(value % (24*60*60)); + value = value / (24*60*60); + break; + case NPY_FR_us: + useconds = (int)(value % (1000*1000)); + value = value / (1000*1000); + seconds = (int)(value % (24*60*60)); + value = value / (24*60*60); + break; + default: + break; + } + /* + * 'value' represents days, and seconds/useconds are filled. + * + * If it would overflow the datetime.timedelta days, return a raw int + */ + if (value < -999999999 || value > 999999999) { + return PyLong_FromLongLong(td); + } + else { + days = (int)value; + ret = PyDelta_FromDSU(days, seconds, useconds); + if (ret == NULL) { + return NULL; + } + } + + return ret; +} + +/* + * Returns true if the datetime metadata matches + */ +NPY_NO_EXPORT npy_bool +has_equivalent_datetime_metadata(PyArray_Descr *type1, PyArray_Descr *type2) +{ + PyArray_DatetimeMetaData *meta1, *meta2; + + if ((type1->type_num != NPY_DATETIME && + type1->type_num != NPY_TIMEDELTA) || + (type2->type_num != NPY_DATETIME && + type2->type_num != NPY_TIMEDELTA)) { + return 0; + } + + meta1 = get_datetime_metadata_from_dtype(type1); + if (meta1 == NULL) { + PyErr_Clear(); + return 0; + } + meta2 = get_datetime_metadata_from_dtype(type2); + if (meta2 == NULL) { + PyErr_Clear(); + return 0; + } + + /* For generic units, the num is ignored */ + if (meta1->base == NPY_FR_GENERIC && meta2->base == NPY_FR_GENERIC) { + return 1; + } + + return meta1->base == meta2->base && + meta1->num == meta2->num; +} + +/* + * Casts a single datetime from having src_meta metadata into + * dst_meta metadata. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +cast_datetime_to_datetime(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + npy_datetime src_dt, + npy_datetime *dst_dt) +{ + npy_datetimestruct dts; + + /* If the metadata is the same, short-circuit the conversion */ + if (src_meta->base == dst_meta->base && + src_meta->num == dst_meta->num) { + *dst_dt = src_dt; + return 0; + } + + /* Otherwise convert through a datetimestruct */ + if (convert_datetime_to_datetimestruct(src_meta, src_dt, &dts) < 0) { + *dst_dt = NPY_DATETIME_NAT; + return -1; + } + if (convert_datetimestruct_to_datetime(dst_meta, &dts, dst_dt) < 0) { + *dst_dt = NPY_DATETIME_NAT; + return -1; + } + + return 0; +} + +/* + * Casts a single timedelta from having src_meta metadata into + * dst_meta metadata. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +cast_timedelta_to_timedelta(PyArray_DatetimeMetaData *src_meta, + PyArray_DatetimeMetaData *dst_meta, + npy_timedelta src_dt, + npy_timedelta *dst_dt) +{ + npy_int64 num = 0, denom = 0; + + /* If the metadata is the same, short-circuit the conversion */ + if (src_meta->base == dst_meta->base && + src_meta->num == dst_meta->num) { + *dst_dt = src_dt; + return 0; + } + + /* Get the conversion factor */ + get_datetime_conversion_factor(src_meta, dst_meta, &num, &denom); + + if (num == 0) { + return -1; + } + + /* Apply the scaling */ + if (src_dt < 0) { + *dst_dt = (src_dt * num - (denom - 1)) / denom; + } + else { + *dst_dt = src_dt * num / denom; + } + + return 0; +} + +/* + * Returns true if the object is something that is best considered + * a Datetime, false otherwise. + */ +static NPY_GCC_NONNULL(1) npy_bool +is_any_numpy_datetime(PyObject *obj) +{ + return (PyArray_IsScalar(obj, Datetime) || + (PyArray_Check(obj) && ( + PyArray_DESCR((PyArrayObject *)obj)->type_num == + NPY_DATETIME)) || + PyDate_Check(obj) || + PyDateTime_Check(obj)); +} + +/* + * Returns true if the object is something that is best considered + * a Timedelta, false otherwise. + */ +static npy_bool +is_any_numpy_timedelta(PyObject *obj) +{ + return (PyArray_IsScalar(obj, Timedelta) || + (PyArray_Check(obj) && ( + PyArray_DESCR((PyArrayObject *)obj)->type_num == NPY_TIMEDELTA)) || + PyDelta_Check(obj)); +} + +/* + * Returns true if the object is something that is best considered + * a Datetime or Timedelta, false otherwise. + */ +NPY_NO_EXPORT npy_bool +is_any_numpy_datetime_or_timedelta(PyObject *obj) +{ + return obj != NULL && + (is_any_numpy_datetime(obj) || + is_any_numpy_timedelta(obj)); +} + +/* + * Converts an array of PyObject * into datetimes and/or timedeltas, + * based on the values in type_nums. + * + * If inout_meta->base is -1, uses GCDs to calculate the metadata, filling + * in 'inout_meta' with the resulting metadata. Otherwise uses the provided + * 'inout_meta' for all the conversions. + * + * When obj[i] is NULL, out_value[i] will be set to NPY_DATETIME_NAT. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +convert_pyobjects_to_datetimes(int count, + PyObject **objs, int *type_nums, + NPY_CASTING casting, + npy_int64 *out_values, + PyArray_DatetimeMetaData *inout_meta) +{ + int i, is_out_strict; + PyArray_DatetimeMetaData *meta; + + /* No values trivially succeeds */ + if (count == 0) { + return 0; + } + + /* Use the inputs to resolve the unit metadata if requested */ + if (inout_meta->base == -1) { + /* Allocate an array of metadata corresponding to the objects */ + meta = PyArray_malloc(count * sizeof(PyArray_DatetimeMetaData)); + if (meta == NULL) { + PyErr_NoMemory(); + return -1; + } + + /* Convert all the objects into timedeltas or datetimes */ + for (i = 0; i < count; ++i) { + meta[i].base = -1; + meta[i].num = 1; + + /* NULL -> NaT */ + if (objs[i] == NULL) { + out_values[i] = NPY_DATETIME_NAT; + meta[i].base = NPY_FR_GENERIC; + } + else if (type_nums[i] == NPY_DATETIME) { + if (convert_pyobject_to_datetime(&meta[i], objs[i], + casting, &out_values[i]) < 0) { + PyArray_free(meta); + return -1; + } + } + else if (type_nums[i] == NPY_TIMEDELTA) { + if (convert_pyobject_to_timedelta(&meta[i], objs[i], + casting, &out_values[i]) < 0) { + PyArray_free(meta); + return -1; + } + } + else { + PyErr_SetString(PyExc_ValueError, + "convert_pyobjects_to_datetimes requires that " + "all the type_nums provided be datetime or timedelta"); + PyArray_free(meta); + return -1; + } + } + + /* Merge all the metadatas, starting with the first one */ + *inout_meta = meta[0]; + is_out_strict = (type_nums[0] == NPY_TIMEDELTA); + + for (i = 1; i < count; ++i) { + if (compute_datetime_metadata_greatest_common_divisor( + &meta[i], inout_meta, inout_meta, + type_nums[i] == NPY_TIMEDELTA, + is_out_strict) < 0) { + PyArray_free(meta); + return -1; + } + is_out_strict = is_out_strict || (type_nums[i] == NPY_TIMEDELTA); + } + + /* Convert all the values into the resolved unit metadata */ + for (i = 0; i < count; ++i) { + if (type_nums[i] == NPY_DATETIME) { + if (cast_datetime_to_datetime(&meta[i], inout_meta, + out_values[i], &out_values[i]) < 0) { + PyArray_free(meta); + return -1; + } + } + else if (type_nums[i] == NPY_TIMEDELTA) { + if (cast_timedelta_to_timedelta(&meta[i], inout_meta, + out_values[i], &out_values[i]) < 0) { + PyArray_free(meta); + return -1; + } + } + } + + PyArray_free(meta); + } + /* Otherwise convert to the provided unit metadata */ + else { + /* Convert all the objects into timedeltas or datetimes */ + for (i = 0; i < count; ++i) { + /* NULL -> NaT */ + if (objs[i] == NULL) { + out_values[i] = NPY_DATETIME_NAT; + } + else if (type_nums[i] == NPY_DATETIME) { + if (convert_pyobject_to_datetime(inout_meta, objs[i], + casting, &out_values[i]) < 0) { + return -1; + } + } + else if (type_nums[i] == NPY_TIMEDELTA) { + if (convert_pyobject_to_timedelta(inout_meta, objs[i], + casting, &out_values[i]) < 0) { + return -1; + } + } + else { + PyErr_SetString(PyExc_ValueError, + "convert_pyobjects_to_datetimes requires that " + "all the type_nums provided be datetime or timedelta"); + return -1; + } + } + } + + return 0; +} + +NPY_NO_EXPORT PyArrayObject * +datetime_arange(PyObject *start, PyObject *stop, PyObject *step, + PyArray_Descr *dtype) +{ + PyArray_DatetimeMetaData meta; + /* + * Both datetime and timedelta are stored as int64, so they can + * share value variables. + */ + npy_int64 values[3]; + PyObject *objs[3]; + int type_nums[3]; + + npy_intp i, length; + PyArrayObject *ret; + npy_int64 *ret_data; + + /* + * First normalize the input parameters so there is no Py_None, + * and start is moved to stop if stop is unspecified. + */ + if (step == Py_None) { + step = NULL; + } + if (stop == NULL || stop == Py_None) { + stop = start; + start = NULL; + /* If start was NULL or None, raise an exception */ + if (stop == NULL || stop == Py_None) { + PyErr_SetString(PyExc_ValueError, + "arange needs at least a stopping value"); + return NULL; + } + } + if (start == Py_None) { + start = NULL; + } + + /* Step must not be a Datetime */ + if (step != NULL && is_any_numpy_datetime(step)) { + PyErr_SetString(PyExc_ValueError, + "cannot use a datetime as a step in arange"); + return NULL; + } + + /* Check if the units of the given dtype are generic, in which + * case we use the code path that detects the units + */ + if (dtype != NULL) { + PyArray_DatetimeMetaData *meta_tmp; + + type_nums[0] = dtype->type_num; + if (type_nums[0] != NPY_DATETIME && type_nums[0] != NPY_TIMEDELTA) { + PyErr_SetString(PyExc_ValueError, + "datetime_arange was given a non-datetime dtype"); + return NULL; + } + + meta_tmp = get_datetime_metadata_from_dtype(dtype); + if (meta_tmp == NULL) { + return NULL; + } + + /* + * If the dtype specified is in generic units, detect the + * units from the input parameters. + */ + if (meta_tmp->base == NPY_FR_GENERIC) { + dtype = NULL; + meta.base = -1; + } + /* Otherwise use the provided metadata */ + else { + meta = *meta_tmp; + } + } + else { + if ((start && is_any_numpy_datetime(start)) || + is_any_numpy_datetime(stop)) { + type_nums[0] = NPY_DATETIME; + } + else { + type_nums[0] = NPY_TIMEDELTA; + } + + meta.base = -1; + } + + if (type_nums[0] == NPY_DATETIME && start == NULL) { + PyErr_SetString(PyExc_ValueError, + "arange requires both a start and a stop for " + "NumPy datetime64 ranges"); + return NULL; + } + + /* Set up to convert the objects to a common datetime unit metadata */ + objs[0] = start; + objs[1] = stop; + objs[2] = step; + if (type_nums[0] == NPY_TIMEDELTA) { + type_nums[1] = NPY_TIMEDELTA; + type_nums[2] = NPY_TIMEDELTA; + } + else { + if (PyInt_Check(objs[1]) || + PyLong_Check(objs[1]) || + PyArray_IsScalar(objs[1], Integer) || + is_any_numpy_timedelta(objs[1])) { + type_nums[1] = NPY_TIMEDELTA; + } + else { + type_nums[1] = NPY_DATETIME; + } + type_nums[2] = NPY_TIMEDELTA; + } + + /* Convert all the arguments */ + if (convert_pyobjects_to_datetimes(3, objs, type_nums, + NPY_SAME_KIND_CASTING, values, &meta) < 0) { + return NULL; + } + + /* If no step was provided, default to 1 */ + if (step == NULL) { + values[2] = 1; + } + + /* + * In the case of arange(datetime, timedelta), convert + * the timedelta into a datetime by adding the start datetime. + */ + if (type_nums[0] == NPY_DATETIME && type_nums[1] == NPY_TIMEDELTA) { + values[1] += values[0]; + } + + /* Now start, stop, and step have their values and matching metadata */ + if (values[0] == NPY_DATETIME_NAT || + values[1] == NPY_DATETIME_NAT || + values[2] == NPY_DATETIME_NAT) { + PyErr_SetString(PyExc_ValueError, + "arange: cannot use NaT (not-a-time) datetime values"); + return NULL; + } + + /* Calculate the array length */ + if (values[2] > 0 && values[1] > values[0]) { + length = (values[1] - values[0] + (values[2] - 1)) / values[2]; + } + else if (values[2] < 0 && values[1] < values[0]) { + length = (values[1] - values[0] + (values[2] + 1)) / values[2]; + } + else if (values[2] != 0) { + length = 0; + } + else { + PyErr_SetString(PyExc_ValueError, + "arange: step cannot be zero"); + return NULL; + } + + /* Create the dtype of the result */ + if (dtype != NULL) { + Py_INCREF(dtype); + } + else { + dtype = create_datetime_dtype(type_nums[0], &meta); + if (dtype == NULL) { + return NULL; + } + } + + /* Create the result array */ + ret = (PyArrayObject *)PyArray_NewFromDescr( + &PyArray_Type, dtype, 1, &length, NULL, + NULL, 0, NULL); + if (ret == NULL) { + return NULL; + } + + if (length > 0) { + /* Extract the data pointer */ + ret_data = (npy_int64 *)PyArray_DATA(ret); + + /* Create the timedeltas or datetimes */ + for (i = 0; i < length; ++i) { + *ret_data = values[0]; + values[0] += values[2]; + ret_data++; + } + } + + return ret; +} + +/* + * Examines all the strings in the given string array, and parses them + * to find the right metadata. + * + * Returns 0 on success, -1 on failure. + */ +static int +find_string_array_datetime64_type(PyArrayObject *arr, + PyArray_DatetimeMetaData *meta) +{ + NpyIter* iter; + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strideptr, *innersizeptr; + PyArray_Descr *string_dtype; + int maxlen; + char *tmp_buffer = NULL; + + npy_datetimestruct dts; + PyArray_DatetimeMetaData tmp_meta; + + /* Handle zero-sized arrays specially */ + if (PyArray_SIZE(arr) == 0) { + return 0; + } + + string_dtype = PyArray_DescrFromType(NPY_STRING); + if (string_dtype == NULL) { + return -1; + } + + /* Use unsafe casting to allow unicode -> ascii string */ + iter = NpyIter_New((PyArrayObject *)arr, + NPY_ITER_READONLY| + NPY_ITER_EXTERNAL_LOOP| + NPY_ITER_BUFFERED, + NPY_KEEPORDER, NPY_UNSAFE_CASTING, + string_dtype); + Py_DECREF(string_dtype); + if (iter == NULL) { + return -1; + } + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + return -1; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strideptr = NpyIter_GetInnerStrideArray(iter); + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + /* Get the resulting string length */ + maxlen = NpyIter_GetDescrArray(iter)[0]->elsize; + + /* Allocate a buffer for strings which fill the buffer completely */ + tmp_buffer = PyArray_malloc(maxlen+1); + if (tmp_buffer == NULL) { + PyErr_NoMemory(); + NpyIter_Deallocate(iter); + return -1; + } + + /* The iteration loop */ + do { + /* Get the inner loop data/stride/count values */ + char* data = *dataptr; + npy_intp stride = *strideptr; + npy_intp count = *innersizeptr; + char *tmp; + + /* The inner loop */ + while (count--) { + /* Replicating strnlen with memchr, because Mac OS X lacks it */ + tmp = memchr(data, '\0', maxlen); + + /* If the string is all full, use the buffer */ + if (tmp == NULL) { + memcpy(tmp_buffer, data, maxlen); + tmp_buffer[maxlen] = '\0'; + + tmp_meta.base = -1; + if (parse_iso_8601_datetime(tmp_buffer, maxlen, -1, + NPY_UNSAFE_CASTING, &dts, + &tmp_meta.base, NULL) < 0) { + goto fail; + } + } + /* Otherwise parse the data in place */ + else { + tmp_meta.base = -1; + if (parse_iso_8601_datetime(data, tmp - data, -1, + NPY_UNSAFE_CASTING, &dts, + &tmp_meta.base, NULL) < 0) { + goto fail; + } + } + + tmp_meta.num = 1; + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + &tmp_meta, meta, 0, 0) < 0) { + goto fail; + } + + + data += stride; + } + } while(iternext(iter)); + + PyArray_free(tmp_buffer); + NpyIter_Deallocate(iter); + + return 0; + +fail: + PyArray_free(tmp_buffer); + NpyIter_Deallocate(iter); + + return -1; +} + + +/* + * Recursively determines the metadata for an NPY_DATETIME dtype. + * + * Returns 0 on success, -1 on failure. + */ +static int +recursive_find_object_datetime64_type(PyObject *obj, + PyArray_DatetimeMetaData *meta) +{ + /* Array -> use its metadata */ + if (PyArray_Check(obj)) { + PyArrayObject *arr = (PyArrayObject *)obj; + PyArray_Descr *arr_dtype = PyArray_DESCR(arr); + + if (arr_dtype->type_num == NPY_STRING || + arr_dtype->type_num == NPY_UNICODE) { + return find_string_array_datetime64_type(arr, meta); + } + /* If the array has metadata, use it */ + else if (arr_dtype->type_num == NPY_DATETIME || + arr_dtype->type_num == NPY_TIMEDELTA) { + PyArray_DatetimeMetaData *tmp_meta; + + /* Get the metadata from the type */ + tmp_meta = get_datetime_metadata_from_dtype(arr_dtype); + if (tmp_meta == NULL) { + return -1; + } + + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + tmp_meta, meta, 0, 0) < 0) { + return -1; + } + + return 0; + } + /* If it's not an object array, stop looking */ + else if (arr_dtype->type_num != NPY_OBJECT) { + return 0; + } + } + /* Datetime scalar -> use its metadata */ + else if (PyArray_IsScalar(obj, Datetime)) { + PyDatetimeScalarObject *dts = (PyDatetimeScalarObject *)obj; + + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + &dts->obmeta, meta, 0, 0) < 0) { + return -1; + } + + return 0; + } + /* String -> parse it to find out */ + else if (PyBytes_Check(obj) || PyUnicode_Check(obj)) { + npy_datetime tmp = 0; + PyArray_DatetimeMetaData tmp_meta; + + tmp_meta.base = -1; + tmp_meta.num = 1; + + if (convert_pyobject_to_datetime(&tmp_meta, obj, + NPY_UNSAFE_CASTING, &tmp) < 0) { + /* If it's a value error, clear the error */ + if (PyErr_Occurred() && + PyErr_GivenExceptionMatches(PyErr_Occurred(), + PyExc_ValueError)) { + PyErr_Clear(); + return 0; + } + /* Otherwise propagate the error */ + else { + return -1; + } + } + + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + &tmp_meta, meta, 0, 0) < 0) { + return -1; + } + + return 0; + } + /* Python date object -> 'D' */ + else if (PyDate_Check(obj)) { + PyArray_DatetimeMetaData tmp_meta; + + tmp_meta.base = NPY_FR_D; + tmp_meta.num = 1; + + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + &tmp_meta, meta, 0, 0) < 0) { + return -1; + } + + return 0; + } + /* Python datetime object -> 'us' */ + else if (PyDateTime_Check(obj)) { + PyArray_DatetimeMetaData tmp_meta; + + tmp_meta.base = NPY_FR_us; + tmp_meta.num = 1; + + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + &tmp_meta, meta, 0, 0) < 0) { + return -1; + } + + return 0; + } + + /* Now check if what we have left is a sequence for recursion */ + if (PySequence_Check(obj)) { + Py_ssize_t i, len = PySequence_Size(obj); + if (len < 0 && PyErr_Occurred()) { + return -1; + } + + for (i = 0; i < len; ++i) { + PyObject *f = PySequence_GetItem(obj, i); + if (f == NULL) { + return -1; + } + if (f == obj) { + Py_DECREF(f); + return 0; + } + if (recursive_find_object_datetime64_type(f, meta) < 0) { + Py_DECREF(f); + return -1; + } + Py_DECREF(f); + } + + return 0; + } + /* Otherwise ignore it */ + else { + return 0; + } +} + +/* + * Recursively determines the metadata for an NPY_TIMEDELTA dtype. + * + * Returns 0 on success, -1 on failure. + */ +static int +recursive_find_object_timedelta64_type(PyObject *obj, + PyArray_DatetimeMetaData *meta) +{ + /* Array -> use its metadata */ + if (PyArray_Check(obj)) { + PyArrayObject *arr = (PyArrayObject *)obj; + PyArray_Descr *arr_dtype = PyArray_DESCR(arr); + + /* If the array has metadata, use it */ + if (arr_dtype->type_num == NPY_DATETIME || + arr_dtype->type_num == NPY_TIMEDELTA) { + PyArray_DatetimeMetaData *tmp_meta; + + /* Get the metadata from the type */ + tmp_meta = get_datetime_metadata_from_dtype(arr_dtype); + if (tmp_meta == NULL) { + return -1; + } + + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + tmp_meta, meta, 0, 0) < 0) { + return -1; + } + + return 0; + } + /* If it's not an object array, stop looking */ + else if (arr_dtype->type_num != NPY_OBJECT) { + return 0; + } + } + /* Datetime scalar -> use its metadata */ + else if (PyArray_IsScalar(obj, Timedelta)) { + PyTimedeltaScalarObject *dts = (PyTimedeltaScalarObject *)obj; + + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + &dts->obmeta, meta, 1, 1) < 0) { + return -1; + } + + return 0; + } + /* String -> parse it to find out */ + else if (PyBytes_Check(obj) || PyUnicode_Check(obj)) { + /* No timedelta parser yet */ + return 0; + } + /* Python timedelta object -> 'us' */ + else if (PyDelta_Check(obj)) { + PyArray_DatetimeMetaData tmp_meta; + + tmp_meta.base = NPY_FR_us; + tmp_meta.num = 1; + + /* Combine it with 'meta' */ + if (compute_datetime_metadata_greatest_common_divisor(meta, + &tmp_meta, meta, 0, 0) < 0) { + return -1; + } + + return 0; + } + + /* Now check if what we have left is a sequence for recursion */ + if (PySequence_Check(obj)) { + Py_ssize_t i, len = PySequence_Size(obj); + if (len < 0 && PyErr_Occurred()) { + return -1; + } + + for (i = 0; i < len; ++i) { + PyObject *f = PySequence_GetItem(obj, i); + if (f == NULL) { + return -1; + } + if (f == obj) { + Py_DECREF(f); + return 0; + } + if (recursive_find_object_timedelta64_type(f, meta) < 0) { + Py_DECREF(f); + return -1; + } + Py_DECREF(f); + } + + return 0; + } + /* Otherwise ignore it */ + else { + return 0; + } +} + +/* + * Examines all the objects in the given Python object by + * recursively descending the sequence structure. Returns a + * datetime or timedelta type with metadata based on the data. + */ +NPY_NO_EXPORT PyArray_Descr * +find_object_datetime_type(PyObject *obj, int type_num) +{ + PyArray_DatetimeMetaData meta; + + meta.base = NPY_FR_GENERIC; + meta.num = 1; + + if (type_num == NPY_DATETIME) { + if (recursive_find_object_datetime64_type(obj, &meta) < 0) { + return NULL; + } + else { + return create_datetime_dtype(type_num, &meta); + } + } + else if (type_num == NPY_TIMEDELTA) { + if (recursive_find_object_timedelta64_type(obj, &meta) < 0) { + return NULL; + } + else { + return create_datetime_dtype(type_num, &meta); + } + } + else { + PyErr_SetString(PyExc_ValueError, + "find_object_datetime_type needs a datetime or " + "timedelta type number"); + return NULL; + } +} diff --git a/numpy/core/src/multiarray/datetime_busday.c b/numpy/core/src/multiarray/datetime_busday.c new file mode 100644 index 0000000..c04a6c1 --- /dev/null +++ b/numpy/core/src/multiarray/datetime_busday.c @@ -0,0 +1,1323 @@ +/* + * This file implements business day functionality for NumPy datetime. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "numpy/arrayscalars.h" +#include "lowlevel_strided_loops.h" +#include "_datetime.h" +#include "datetime_busday.h" +#include "datetime_busdaycal.h" + +/* Gets the day of the week for a datetime64[D] value */ +static int +get_day_of_week(npy_datetime date) +{ + int day_of_week; + + /* Get the day of the week for 'date' (1970-01-05 is Monday) */ + day_of_week = (int)((date - 4) % 7); + if (day_of_week < 0) { + day_of_week += 7; + } + + return day_of_week; +} + +/* + * Returns 1 if the date is a holiday (contained in the sorted + * list of dates), 0 otherwise. + * + * The holidays list should be normalized, which means any NaT (not-a-time) + * values, duplicates, and dates already excluded by the weekmask should + * be removed, and the list should be sorted. + */ +static int +is_holiday(npy_datetime date, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + npy_datetime *trial; + + /* Simple binary search */ + while (holidays_begin < holidays_end) { + trial = holidays_begin + (holidays_end - holidays_begin) / 2; + + if (date < *trial) { + holidays_end = trial; + } + else if (date > *trial) { + holidays_begin = trial + 1; + } + else { + return 1; + } + } + + /* Not found */ + return 0; +} + +/* + * Finds the earliest holiday which is on or after 'date'. If 'date' does not + * appear within the holiday range, returns 'holidays_begin' if 'date' + * is before all holidays, or 'holidays_end' if 'date' is after all + * holidays. + * + * To remove all the holidays before 'date' from a holiday range, do: + * + * holidays_begin = find_holiday_earliest_on_or_after(date, + * holidays_begin, holidays_end); + * + * The holidays list should be normalized, which means any NaT (not-a-time) + * values, duplicates, and dates already excluded by the weekmask should + * be removed, and the list should be sorted. + */ +static npy_datetime * +find_earliest_holiday_on_or_after(npy_datetime date, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + npy_datetime *trial; + + /* Simple binary search */ + while (holidays_begin < holidays_end) { + trial = holidays_begin + (holidays_end - holidays_begin) / 2; + + if (date < *trial) { + holidays_end = trial; + } + else if (date > *trial) { + holidays_begin = trial + 1; + } + else { + return trial; + } + } + + return holidays_begin; +} + +/* + * Finds the earliest holiday which is after 'date'. If 'date' does not + * appear within the holiday range, returns 'holidays_begin' if 'date' + * is before all holidays, or 'holidays_end' if 'date' is after all + * holidays. + * + * To remove all the holidays after 'date' from a holiday range, do: + * + * holidays_end = find_holiday_earliest_after(date, + * holidays_begin, holidays_end); + * + * The holidays list should be normalized, which means any NaT (not-a-time) + * values, duplicates, and dates already excluded by the weekmask should + * be removed, and the list should be sorted. + */ +static npy_datetime * +find_earliest_holiday_after(npy_datetime date, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + npy_datetime *trial; + + /* Simple binary search */ + while (holidays_begin < holidays_end) { + trial = holidays_begin + (holidays_end - holidays_begin) / 2; + + if (date < *trial) { + holidays_end = trial; + } + else if (date > *trial) { + holidays_begin = trial + 1; + } + else { + return trial + 1; + } + } + + return holidays_begin; +} + +/* + * Applies the 'roll' strategy to 'date', placing the result in 'out' + * and setting 'out_day_of_week' to the day of the week that results. + * + * Returns 0 on success, -1 on failure. + */ +static int +apply_business_day_roll(npy_datetime date, npy_datetime *out, + int *out_day_of_week, + NPY_BUSDAY_ROLL roll, + npy_bool *weekmask, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + int day_of_week; + + /* Deal with NaT input */ + if (date == NPY_DATETIME_NAT) { + *out = NPY_DATETIME_NAT; + if (roll == NPY_BUSDAY_RAISE) { + PyErr_SetString(PyExc_ValueError, + "NaT input in busday_offset"); + return -1; + } + else { + return 0; + } + } + + /* Get the day of the week for 'date' */ + day_of_week = get_day_of_week(date); + + /* Apply the 'roll' if it's not a business day */ + if (weekmask[day_of_week] == 0 || + is_holiday(date, holidays_begin, holidays_end)) { + npy_datetime start_date = date; + int start_day_of_week = day_of_week; + + switch (roll) { + case NPY_BUSDAY_FOLLOWING: + case NPY_BUSDAY_MODIFIEDFOLLOWING: { + do { + ++date; + if (++day_of_week == 7) { + day_of_week = 0; + } + } while (weekmask[day_of_week] == 0 || + is_holiday(date, holidays_begin, holidays_end)); + + if (roll == NPY_BUSDAY_MODIFIEDFOLLOWING) { + /* If we crossed a month boundary, do preceding instead */ + if (days_to_month_number(start_date) != + days_to_month_number(date)) { + date = start_date; + day_of_week = start_day_of_week; + + do { + --date; + if (--day_of_week == -1) { + day_of_week = 6; + } + } while (weekmask[day_of_week] == 0 || + is_holiday(date, holidays_begin, holidays_end)); + } + } + break; + } + case NPY_BUSDAY_PRECEDING: + case NPY_BUSDAY_MODIFIEDPRECEDING: { + do { + --date; + if (--day_of_week == -1) { + day_of_week = 6; + } + } while (weekmask[day_of_week] == 0 || + is_holiday(date, holidays_begin, holidays_end)); + + if (roll == NPY_BUSDAY_MODIFIEDPRECEDING) { + /* If we crossed a month boundary, do following instead */ + if (days_to_month_number(start_date) != + days_to_month_number(date)) { + date = start_date; + day_of_week = start_day_of_week; + + do { + ++date; + if (++day_of_week == 7) { + day_of_week = 0; + } + } while (weekmask[day_of_week] == 0 || + is_holiday(date, holidays_begin, holidays_end)); + } + } + break; + } + case NPY_BUSDAY_NAT: { + date = NPY_DATETIME_NAT; + break; + } + case NPY_BUSDAY_RAISE: { + *out = NPY_DATETIME_NAT; + PyErr_SetString(PyExc_ValueError, + "Non-business day date in busday_offset"); + return -1; + } + } + } + + *out = date; + *out_day_of_week = day_of_week; + + return 0; +} + +/* + * Applies a single business day offset. See the function + * business_day_offset for the meaning of all the parameters. + * + * Returns 0 on success, -1 on failure. + */ +static int +apply_business_day_offset(npy_datetime date, npy_int64 offset, + npy_datetime *out, + NPY_BUSDAY_ROLL roll, + npy_bool *weekmask, int busdays_in_weekmask, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + int day_of_week = 0; + npy_datetime *holidays_temp; + + /* Roll the date to a business day */ + if (apply_business_day_roll(date, &date, &day_of_week, + roll, + weekmask, + holidays_begin, holidays_end) < 0) { + return -1; + } + + /* If we get a NaT, just return it */ + if (date == NPY_DATETIME_NAT) { + *out = NPY_DATETIME_NAT; + return 0; + } + + /* Now we're on a valid business day */ + if (offset > 0) { + /* Remove any earlier holidays */ + holidays_begin = find_earliest_holiday_on_or_after(date, + holidays_begin, holidays_end); + + /* Jump by as many weeks as we can */ + date += (offset / busdays_in_weekmask) * 7; + offset = offset % busdays_in_weekmask; + + /* Adjust based on the number of holidays we crossed */ + holidays_temp = find_earliest_holiday_after(date, + holidays_begin, holidays_end); + offset += holidays_temp - holidays_begin; + holidays_begin = holidays_temp; + + /* Step until we use up the rest of the offset */ + while (offset > 0) { + ++date; + if (++day_of_week == 7) { + day_of_week = 0; + } + if (weekmask[day_of_week] && !is_holiday(date, + holidays_begin, holidays_end)) { + offset--; + } + } + } + else if (offset < 0) { + /* Remove any later holidays */ + holidays_end = find_earliest_holiday_after(date, + holidays_begin, holidays_end); + + /* Jump by as many weeks as we can */ + date += (offset / busdays_in_weekmask) * 7; + offset = offset % busdays_in_weekmask; + + /* Adjust based on the number of holidays we crossed */ + holidays_temp = find_earliest_holiday_on_or_after(date, + holidays_begin, holidays_end); + offset -= holidays_end - holidays_temp; + holidays_end = holidays_temp; + + /* Step until we use up the rest of the offset */ + while (offset < 0) { + --date; + if (--day_of_week == -1) { + day_of_week = 6; + } + if (weekmask[day_of_week] && !is_holiday(date, + holidays_begin, holidays_end)) { + offset++; + } + } + } + + *out = date; + return 0; +} + +/* + * Applies a single business day count operation. See the function + * business_day_count for the meaning of all the parameters. + * + * Returns 0 on success, -1 on failure. + */ +static int +apply_business_day_count(npy_datetime date_begin, npy_datetime date_end, + npy_int64 *out, + npy_bool *weekmask, int busdays_in_weekmask, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + npy_int64 count, whole_weeks; + int day_of_week = 0; + int swapped = 0; + + /* If we get a NaT, raise an error */ + if (date_begin == NPY_DATETIME_NAT || date_end == NPY_DATETIME_NAT) { + PyErr_SetString(PyExc_ValueError, + "Cannot compute a business day count with a NaT (not-a-time) " + "date"); + return -1; + } + + /* Trivial empty date range */ + if (date_begin == date_end) { + *out = 0; + return 0; + } + else if (date_begin > date_end) { + npy_datetime tmp = date_begin; + date_begin = date_end; + date_end = tmp; + swapped = 1; + } + + /* Remove any earlier holidays */ + holidays_begin = find_earliest_holiday_on_or_after(date_begin, + holidays_begin, holidays_end); + /* Remove any later holidays */ + holidays_end = find_earliest_holiday_on_or_after(date_end, + holidays_begin, holidays_end); + + /* Start the count as negative the number of holidays in the range */ + count = -(holidays_end - holidays_begin); + + /* Add the whole weeks between date_begin and date_end */ + whole_weeks = (date_end - date_begin) / 7; + count += whole_weeks * busdays_in_weekmask; + date_begin += whole_weeks * 7; + + if (date_begin < date_end) { + /* Get the day of the week for 'date_begin' */ + day_of_week = get_day_of_week(date_begin); + + /* Count the remaining days one by one */ + while (date_begin < date_end) { + if (weekmask[day_of_week]) { + count++; + } + ++date_begin; + if (++day_of_week == 7) { + day_of_week = 0; + } + } + } + + if (swapped) { + count = -count; + } + + *out = count; + return 0; +} + +/* + * Applies the given offsets in business days to the dates provided. + * This is the low-level function which requires already cleaned input + * data. + * + * dates: An array of dates with 'datetime64[D]' data type. + * offsets: An array safely convertible into type int64. + * out: Either NULL, or an array with 'datetime64[D]' data type + * in which to place the resulting dates. + * roll: A rule for how to treat non-business day dates. + * weekmask: A 7-element boolean mask, 1 for possible business days and 0 + * for non-business days. + * busdays_in_weekmask: A count of how many 1's there are in weekmask. + * holidays_begin/holidays_end: A sorted list of dates matching '[D]' + * unit metadata, with any dates falling on a day of the + * week without weekmask[i] == 1 already filtered out. + * + * For each (date, offset) in the broadcasted pair of (dates, offsets), + * does the following: + * + Applies the 'roll' rule to the date to either produce NaT, raise + * an exception, or land on a valid business day. + * + Adds 'offset' business days to the valid business day found. + * + Sets the value in 'out' if provided, or the allocated output array + * otherwise. + */ +NPY_NO_EXPORT PyArrayObject * +business_day_offset(PyArrayObject *dates, PyArrayObject *offsets, + PyArrayObject *out, + NPY_BUSDAY_ROLL roll, + npy_bool *weekmask, int busdays_in_weekmask, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + PyArray_DatetimeMetaData temp_meta; + PyArray_Descr *dtypes[3] = {NULL, NULL, NULL}; + + NpyIter *iter = NULL; + PyArrayObject *op[3] = {NULL, NULL, NULL}; + npy_uint32 op_flags[3], flags; + + PyArrayObject *ret = NULL; + + if (busdays_in_weekmask == 0) { + PyErr_SetString(PyExc_ValueError, + "the business day weekmask must have at least one " + "valid business day"); + return NULL; + } + + /* First create the data types for dates and offsets */ + temp_meta.base = NPY_FR_D; + temp_meta.num = 1; + dtypes[0] = create_datetime_dtype(NPY_DATETIME, &temp_meta); + if (dtypes[0] == NULL) { + goto fail; + } + dtypes[1] = PyArray_DescrFromType(NPY_INT64); + if (dtypes[1] == NULL) { + goto fail; + } + dtypes[2] = dtypes[0]; + Py_INCREF(dtypes[2]); + + /* Set up the iterator parameters */ + flags = NPY_ITER_EXTERNAL_LOOP| + NPY_ITER_BUFFERED| + NPY_ITER_ZEROSIZE_OK; + op[0] = dates; + op_flags[0] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; + op[1] = offsets; + op_flags[1] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; + op[2] = out; + op_flags[2] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE | NPY_ITER_ALIGNED; + + /* Allocate the iterator */ + iter = NpyIter_MultiNew(3, op, flags, NPY_KEEPORDER, NPY_SAFE_CASTING, + op_flags, dtypes); + if (iter == NULL) { + goto fail; + } + + /* Loop over all elements */ + if (NpyIter_GetIterSize(iter) > 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strideptr, *innersizeptr; + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strideptr = NpyIter_GetInnerStrideArray(iter); + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + do { + char *data_dates = dataptr[0]; + char *data_offsets = dataptr[1]; + char *data_out = dataptr[2]; + npy_intp stride_dates = strideptr[0]; + npy_intp stride_offsets = strideptr[1]; + npy_intp stride_out = strideptr[2]; + npy_intp count = *innersizeptr; + + while (count--) { + if (apply_business_day_offset(*(npy_int64 *)data_dates, + *(npy_int64 *)data_offsets, + (npy_int64 *)data_out, + roll, + weekmask, busdays_in_weekmask, + holidays_begin, holidays_end) < 0) { + goto fail; + } + + data_dates += stride_dates; + data_offsets += stride_offsets; + data_out += stride_out; + } + } while (iternext(iter)); + } + + /* Get the return object from the iterator */ + ret = NpyIter_GetOperandArray(iter)[2]; + Py_INCREF(ret); + + goto finish; + +fail: + Py_XDECREF(ret); + ret = NULL; + +finish: + Py_XDECREF(dtypes[0]); + Py_XDECREF(dtypes[1]); + Py_XDECREF(dtypes[2]); + if (iter != NULL) { + if (NpyIter_Deallocate(iter) != NPY_SUCCEED) { + Py_XDECREF(ret); + ret = NULL; + } + } + return ret; +} + +/* + * Counts the number of business days between two dates, not including + * the end date. This is the low-level function which requires already + * cleaned input data. + * + * If dates_begin is before dates_end, the result is positive. If + * dates_begin is after dates_end, it is negative. + * + * dates_begin: An array of dates with 'datetime64[D]' data type. + * dates_end: An array of dates with 'datetime64[D]' data type. + * out: Either NULL, or an array with 'int64' data type + * in which to place the resulting dates. + * weekmask: A 7-element boolean mask, 1 for possible business days and 0 + * for non-business days. + * busdays_in_weekmask: A count of how many 1's there are in weekmask. + * holidays_begin/holidays_end: A sorted list of dates matching '[D]' + * unit metadata, with any dates falling on a day of the + * week without weekmask[i] == 1 already filtered out. + */ +NPY_NO_EXPORT PyArrayObject * +business_day_count(PyArrayObject *dates_begin, PyArrayObject *dates_end, + PyArrayObject *out, + npy_bool *weekmask, int busdays_in_weekmask, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + PyArray_DatetimeMetaData temp_meta; + PyArray_Descr *dtypes[3] = {NULL, NULL, NULL}; + + NpyIter *iter = NULL; + PyArrayObject *op[3] = {NULL, NULL, NULL}; + npy_uint32 op_flags[3], flags; + + PyArrayObject *ret = NULL; + + if (busdays_in_weekmask == 0) { + PyErr_SetString(PyExc_ValueError, + "the business day weekmask must have at least one " + "valid business day"); + return NULL; + } + + /* First create the data types for the dates and the int64 output */ + temp_meta.base = NPY_FR_D; + temp_meta.num = 1; + dtypes[0] = create_datetime_dtype(NPY_DATETIME, &temp_meta); + if (dtypes[0] == NULL) { + goto fail; + } + dtypes[1] = dtypes[0]; + Py_INCREF(dtypes[1]); + dtypes[2] = PyArray_DescrFromType(NPY_INT64); + if (dtypes[2] == NULL) { + goto fail; + } + + /* Set up the iterator parameters */ + flags = NPY_ITER_EXTERNAL_LOOP| + NPY_ITER_BUFFERED| + NPY_ITER_ZEROSIZE_OK; + op[0] = dates_begin; + op_flags[0] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; + op[1] = dates_end; + op_flags[1] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; + op[2] = out; + op_flags[2] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE | NPY_ITER_ALIGNED; + + /* Allocate the iterator */ + iter = NpyIter_MultiNew(3, op, flags, NPY_KEEPORDER, NPY_SAFE_CASTING, + op_flags, dtypes); + if (iter == NULL) { + goto fail; + } + + /* Loop over all elements */ + if (NpyIter_GetIterSize(iter) > 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strideptr, *innersizeptr; + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strideptr = NpyIter_GetInnerStrideArray(iter); + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + do { + char *data_dates_begin = dataptr[0]; + char *data_dates_end = dataptr[1]; + char *data_out = dataptr[2]; + npy_intp stride_dates_begin = strideptr[0]; + npy_intp stride_dates_end = strideptr[1]; + npy_intp stride_out = strideptr[2]; + npy_intp count = *innersizeptr; + + while (count--) { + if (apply_business_day_count(*(npy_int64 *)data_dates_begin, + *(npy_int64 *)data_dates_end, + (npy_int64 *)data_out, + weekmask, busdays_in_weekmask, + holidays_begin, holidays_end) < 0) { + goto fail; + } + + data_dates_begin += stride_dates_begin; + data_dates_end += stride_dates_end; + data_out += stride_out; + } + } while (iternext(iter)); + } + + /* Get the return object from the iterator */ + ret = NpyIter_GetOperandArray(iter)[2]; + Py_INCREF(ret); + + goto finish; + +fail: + Py_XDECREF(ret); + ret = NULL; + +finish: + Py_XDECREF(dtypes[0]); + Py_XDECREF(dtypes[1]); + Py_XDECREF(dtypes[2]); + if (iter != NULL) { + if (NpyIter_Deallocate(iter) != NPY_SUCCEED) { + Py_XDECREF(ret); + ret = NULL; + } + } + return ret; +} + +/* + * Returns a boolean array with True for input dates which are valid + * business days, and False for dates which are not. This is the + * low-level function which requires already cleaned input data. + * + * dates: An array of dates with 'datetime64[D]' data type. + * out: Either NULL, or an array with 'bool' data type + * in which to place the resulting dates. + * weekmask: A 7-element boolean mask, 1 for possible business days and 0 + * for non-business days. + * busdays_in_weekmask: A count of how many 1's there are in weekmask. + * holidays_begin/holidays_end: A sorted list of dates matching '[D]' + * unit metadata, with any dates falling on a day of the + * week without weekmask[i] == 1 already filtered out. + */ +NPY_NO_EXPORT PyArrayObject * +is_business_day(PyArrayObject *dates, PyArrayObject *out, + npy_bool *weekmask, int busdays_in_weekmask, + npy_datetime *holidays_begin, npy_datetime *holidays_end) +{ + PyArray_DatetimeMetaData temp_meta; + PyArray_Descr *dtypes[2] = {NULL, NULL}; + + NpyIter *iter = NULL; + PyArrayObject *op[2] = {NULL, NULL}; + npy_uint32 op_flags[2], flags; + + PyArrayObject *ret = NULL; + + if (busdays_in_weekmask == 0) { + PyErr_SetString(PyExc_ValueError, + "the business day weekmask must have at least one " + "valid business day"); + return NULL; + } + + /* First create the data types for the dates and the bool output */ + temp_meta.base = NPY_FR_D; + temp_meta.num = 1; + dtypes[0] = create_datetime_dtype(NPY_DATETIME, &temp_meta); + if (dtypes[0] == NULL) { + goto fail; + } + dtypes[1] = PyArray_DescrFromType(NPY_BOOL); + if (dtypes[1] == NULL) { + goto fail; + } + + /* Set up the iterator parameters */ + flags = NPY_ITER_EXTERNAL_LOOP| + NPY_ITER_BUFFERED| + NPY_ITER_ZEROSIZE_OK; + op[0] = dates; + op_flags[0] = NPY_ITER_READONLY | NPY_ITER_ALIGNED; + op[1] = out; + op_flags[1] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE | NPY_ITER_ALIGNED; + + /* Allocate the iterator */ + iter = NpyIter_MultiNew(2, op, flags, NPY_KEEPORDER, NPY_SAFE_CASTING, + op_flags, dtypes); + if (iter == NULL) { + goto fail; + } + + /* Loop over all elements */ + if (NpyIter_GetIterSize(iter) > 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strideptr, *innersizeptr; + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strideptr = NpyIter_GetInnerStrideArray(iter); + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + do { + char *data_dates = dataptr[0]; + char *data_out = dataptr[1]; + npy_intp stride_dates = strideptr[0]; + npy_intp stride_out = strideptr[1]; + npy_intp count = *innersizeptr; + + npy_datetime date; + int day_of_week; + + while (count--) { + /* Check if it's a business day */ + date = *(npy_datetime *)data_dates; + day_of_week = get_day_of_week(date); + *(npy_bool *)data_out = weekmask[day_of_week] && + !is_holiday(date, + holidays_begin, holidays_end) && + date != NPY_DATETIME_NAT; + + data_dates += stride_dates; + data_out += stride_out; + } + } while (iternext(iter)); + } + + /* Get the return object from the iterator */ + ret = NpyIter_GetOperandArray(iter)[1]; + Py_INCREF(ret); + + goto finish; + +fail: + Py_XDECREF(ret); + ret = NULL; + +finish: + Py_XDECREF(dtypes[0]); + Py_XDECREF(dtypes[1]); + if (iter != NULL) { + if (NpyIter_Deallocate(iter) != NPY_SUCCEED) { + Py_XDECREF(ret); + ret = NULL; + } + } + return ret; +} + +static int +PyArray_BusDayRollConverter(PyObject *roll_in, NPY_BUSDAY_ROLL *roll) +{ + PyObject *obj = roll_in; + char *str; + Py_ssize_t len; + + /* Make obj into an ASCII string */ + Py_INCREF(obj); + if (PyUnicode_Check(obj)) { + /* accept unicode input */ + PyObject *obj_str; + obj_str = PyUnicode_AsASCIIString(obj); + if (obj_str == NULL) { + Py_DECREF(obj); + return 0; + } + Py_DECREF(obj); + obj = obj_str; + } + + if (PyBytes_AsStringAndSize(obj, &str, &len) < 0) { + Py_DECREF(obj); + return 0; + } + + /* Use switch statements to quickly isolate the right enum value */ + switch (str[0]) { + case 'b': + if (strcmp(str, "backward") == 0) { + *roll = NPY_BUSDAY_BACKWARD; + goto finish; + } + break; + case 'f': + if (len > 2) switch (str[2]) { + case 'r': + if (strcmp(str, "forward") == 0) { + *roll = NPY_BUSDAY_FORWARD; + goto finish; + } + break; + case 'l': + if (strcmp(str, "following") == 0) { + *roll = NPY_BUSDAY_FOLLOWING; + goto finish; + } + break; + } + break; + case 'm': + if (len > 8) switch (str[8]) { + case 'f': + if (strcmp(str, "modifiedfollowing") == 0) { + *roll = NPY_BUSDAY_MODIFIEDFOLLOWING; + goto finish; + } + break; + case 'p': + if (strcmp(str, "modifiedpreceding") == 0) { + *roll = NPY_BUSDAY_MODIFIEDPRECEDING; + goto finish; + } + break; + } + break; + case 'n': + if (strcmp(str, "nat") == 0) { + *roll = NPY_BUSDAY_NAT; + goto finish; + } + break; + case 'p': + if (strcmp(str, "preceding") == 0) { + *roll = NPY_BUSDAY_PRECEDING; + goto finish; + } + break; + case 'r': + if (strcmp(str, "raise") == 0) { + *roll = NPY_BUSDAY_RAISE; + goto finish; + } + break; + } + + PyErr_Format(PyExc_ValueError, + "Invalid business day roll parameter \"%s\"", + str); + Py_DECREF(obj); + return 0; + +finish: + Py_DECREF(obj); + return 1; +} + +/* + * This is the 'busday_offset' function exposed for calling + * from Python. + */ +NPY_NO_EXPORT PyObject * +array_busday_offset(PyObject *NPY_UNUSED(self), + PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"dates", "offsets", "roll", + "weekmask", "holidays", "busdaycal", "out", NULL}; + + PyObject *dates_in = NULL, *offsets_in = NULL, *out_in = NULL; + + PyArrayObject *dates = NULL, *offsets = NULL, *out = NULL, *ret; + NPY_BUSDAY_ROLL roll = NPY_BUSDAY_RAISE; + npy_bool weekmask[7] = {2, 1, 1, 1, 1, 0, 0}; + NpyBusDayCalendar *busdaycal = NULL; + int i, busdays_in_weekmask; + npy_holidayslist holidays = {NULL, NULL}; + int allocated_holidays = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "OO|O&O&O&O!O:busday_offset", kwlist, + &dates_in, + &offsets_in, + &PyArray_BusDayRollConverter, &roll, + &PyArray_WeekMaskConverter, &weekmask[0], + &PyArray_HolidaysConverter, &holidays, + &NpyBusDayCalendar_Type, &busdaycal, + &out_in)) { + goto fail; + } + + /* Make sure only one of the weekmask/holidays and busdaycal is supplied */ + if (busdaycal != NULL) { + if (weekmask[0] != 2 || holidays.begin != NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot supply both the weekmask/holidays and the " + "busdaycal parameters to busday_offset()"); + goto fail; + } + + /* Indicate that the holidays weren't allocated by us */ + allocated_holidays = 0; + + /* Copy the private normalized weekmask/holidays data */ + holidays = busdaycal->holidays; + busdays_in_weekmask = busdaycal->busdays_in_weekmask; + memcpy(weekmask, busdaycal->weekmask, 7); + } + else { + /* + * Fix up the weekmask from the uninitialized + * signal value to a proper default. + */ + if (weekmask[0] == 2) { + weekmask[0] = 1; + } + + /* Count the number of business days in a week */ + busdays_in_weekmask = 0; + for (i = 0; i < 7; ++i) { + busdays_in_weekmask += weekmask[i]; + } + + /* The holidays list must be normalized before using it */ + normalize_holidays_list(&holidays, weekmask); + } + + /* Make 'dates' into an array */ + if (PyArray_Check(dates_in)) { + dates = (PyArrayObject *)dates_in; + Py_INCREF(dates); + } + else { + PyArray_Descr *datetime_dtype; + + /* Use the datetime dtype with generic units so it fills it in */ + datetime_dtype = PyArray_DescrFromType(NPY_DATETIME); + if (datetime_dtype == NULL) { + goto fail; + } + + /* This steals the datetime_dtype reference */ + dates = (PyArrayObject *)PyArray_FromAny(dates_in, datetime_dtype, + 0, 0, 0, dates_in); + if (dates == NULL) { + goto fail; + } + } + + /* Make 'offsets' into an array */ + offsets = (PyArrayObject *)PyArray_FromAny(offsets_in, + PyArray_DescrFromType(NPY_INT64), + 0, 0, 0, offsets_in); + if (offsets == NULL) { + goto fail; + } + + /* Make sure 'out' is an array if it's provided */ + if (out_in != NULL) { + if (!PyArray_Check(out_in)) { + PyErr_SetString(PyExc_ValueError, + "busday_offset: must provide a NumPy array for 'out'"); + goto fail; + } + out = (PyArrayObject *)out_in; + } + + ret = business_day_offset(dates, offsets, out, roll, + weekmask, busdays_in_weekmask, + holidays.begin, holidays.end); + + Py_DECREF(dates); + Py_DECREF(offsets); + if (allocated_holidays && holidays.begin != NULL) { + PyArray_free(holidays.begin); + } + + return out == NULL ? PyArray_Return(ret) : (PyObject *)ret; + +fail: + Py_XDECREF(dates); + Py_XDECREF(offsets); + if (allocated_holidays && holidays.begin != NULL) { + PyArray_free(holidays.begin); + } + + return NULL; +} + +/* + * This is the 'busday_count' function exposed for calling + * from Python. + */ +NPY_NO_EXPORT PyObject * +array_busday_count(PyObject *NPY_UNUSED(self), + PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"begindates", "enddates", + "weekmask", "holidays", "busdaycal", "out", NULL}; + + PyObject *dates_begin_in = NULL, *dates_end_in = NULL, *out_in = NULL; + + PyArrayObject *dates_begin = NULL, *dates_end = NULL, *out = NULL, *ret; + npy_bool weekmask[7] = {2, 1, 1, 1, 1, 0, 0}; + NpyBusDayCalendar *busdaycal = NULL; + int i, busdays_in_weekmask; + npy_holidayslist holidays = {NULL, NULL}; + int allocated_holidays = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "OO|O&O&O!O:busday_count", kwlist, + &dates_begin_in, + &dates_end_in, + &PyArray_WeekMaskConverter, &weekmask[0], + &PyArray_HolidaysConverter, &holidays, + &NpyBusDayCalendar_Type, &busdaycal, + &out_in)) { + goto fail; + } + + /* Make sure only one of the weekmask/holidays and busdaycal is supplied */ + if (busdaycal != NULL) { + if (weekmask[0] != 2 || holidays.begin != NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot supply both the weekmask/holidays and the " + "busdaycal parameters to busday_count()"); + goto fail; + } + + /* Indicate that the holidays weren't allocated by us */ + allocated_holidays = 0; + + /* Copy the private normalized weekmask/holidays data */ + holidays = busdaycal->holidays; + busdays_in_weekmask = busdaycal->busdays_in_weekmask; + memcpy(weekmask, busdaycal->weekmask, 7); + } + else { + /* + * Fix up the weekmask from the uninitialized + * signal value to a proper default. + */ + if (weekmask[0] == 2) { + weekmask[0] = 1; + } + + /* Count the number of business days in a week */ + busdays_in_weekmask = 0; + for (i = 0; i < 7; ++i) { + busdays_in_weekmask += weekmask[i]; + } + + /* The holidays list must be normalized before using it */ + normalize_holidays_list(&holidays, weekmask); + } + + /* Make 'dates_begin' into an array */ + if (PyArray_Check(dates_begin_in)) { + dates_begin = (PyArrayObject *)dates_begin_in; + Py_INCREF(dates_begin); + } + else { + PyArray_Descr *datetime_dtype; + + /* Use the datetime dtype with generic units so it fills it in */ + datetime_dtype = PyArray_DescrFromType(NPY_DATETIME); + if (datetime_dtype == NULL) { + goto fail; + } + + /* This steals the datetime_dtype reference */ + dates_begin = (PyArrayObject *)PyArray_FromAny(dates_begin_in, + datetime_dtype, + 0, 0, 0, dates_begin_in); + if (dates_begin == NULL) { + goto fail; + } + } + + /* Make 'dates_end' into an array */ + if (PyArray_Check(dates_end_in)) { + dates_end = (PyArrayObject *)dates_end_in; + Py_INCREF(dates_end); + } + else { + PyArray_Descr *datetime_dtype; + + /* Use the datetime dtype with generic units so it fills it in */ + datetime_dtype = PyArray_DescrFromType(NPY_DATETIME); + if (datetime_dtype == NULL) { + goto fail; + } + + /* This steals the datetime_dtype reference */ + dates_end = (PyArrayObject *)PyArray_FromAny(dates_end_in, + datetime_dtype, + 0, 0, 0, dates_end_in); + if (dates_end == NULL) { + goto fail; + } + } + + /* Make sure 'out' is an array if it's provided */ + if (out_in != NULL) { + if (!PyArray_Check(out_in)) { + PyErr_SetString(PyExc_ValueError, + "busday_offset: must provide a NumPy array for 'out'"); + goto fail; + } + out = (PyArrayObject *)out_in; + } + + ret = business_day_count(dates_begin, dates_end, out, + weekmask, busdays_in_weekmask, + holidays.begin, holidays.end); + + Py_DECREF(dates_begin); + Py_DECREF(dates_end); + if (allocated_holidays && holidays.begin != NULL) { + PyArray_free(holidays.begin); + } + + return out == NULL ? PyArray_Return(ret) : (PyObject *)ret; + +fail: + Py_XDECREF(dates_begin); + Py_XDECREF(dates_end); + if (allocated_holidays && holidays.begin != NULL) { + PyArray_free(holidays.begin); + } + + return NULL; +} + +/* + * This is the 'is_busday' function exposed for calling + * from Python. + */ +NPY_NO_EXPORT PyObject * +array_is_busday(PyObject *NPY_UNUSED(self), + PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"dates", + "weekmask", "holidays", "busdaycal", "out", NULL}; + + PyObject *dates_in = NULL, *out_in = NULL; + + PyArrayObject *dates = NULL,*out = NULL, *ret; + npy_bool weekmask[7] = {2, 1, 1, 1, 1, 0, 0}; + NpyBusDayCalendar *busdaycal = NULL; + int i, busdays_in_weekmask; + npy_holidayslist holidays = {NULL, NULL}; + int allocated_holidays = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "O|O&O&O!O:is_busday", kwlist, + &dates_in, + &PyArray_WeekMaskConverter, &weekmask[0], + &PyArray_HolidaysConverter, &holidays, + &NpyBusDayCalendar_Type, &busdaycal, + &out_in)) { + goto fail; + } + + /* Make sure only one of the weekmask/holidays and busdaycal is supplied */ + if (busdaycal != NULL) { + if (weekmask[0] != 2 || holidays.begin != NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot supply both the weekmask/holidays and the " + "busdaycal parameters to is_busday()"); + goto fail; + } + + /* Indicate that the holidays weren't allocated by us */ + allocated_holidays = 0; + + /* Copy the private normalized weekmask/holidays data */ + holidays = busdaycal->holidays; + busdays_in_weekmask = busdaycal->busdays_in_weekmask; + memcpy(weekmask, busdaycal->weekmask, 7); + } + else { + /* + * Fix up the weekmask from the uninitialized + * signal value to a proper default. + */ + if (weekmask[0] == 2) { + weekmask[0] = 1; + } + + /* Count the number of business days in a week */ + busdays_in_weekmask = 0; + for (i = 0; i < 7; ++i) { + busdays_in_weekmask += weekmask[i]; + } + + /* The holidays list must be normalized before using it */ + normalize_holidays_list(&holidays, weekmask); + } + + /* Make 'dates' into an array */ + if (PyArray_Check(dates_in)) { + dates = (PyArrayObject *)dates_in; + Py_INCREF(dates); + } + else { + PyArray_Descr *datetime_dtype; + + /* Use the datetime dtype with generic units so it fills it in */ + datetime_dtype = PyArray_DescrFromType(NPY_DATETIME); + if (datetime_dtype == NULL) { + goto fail; + } + + /* This steals the datetime_dtype reference */ + dates = (PyArrayObject *)PyArray_FromAny(dates_in, + datetime_dtype, + 0, 0, 0, dates_in); + if (dates == NULL) { + goto fail; + } + } + + /* Make sure 'out' is an array if it's provided */ + if (out_in != NULL) { + if (!PyArray_Check(out_in)) { + PyErr_SetString(PyExc_ValueError, + "busday_offset: must provide a NumPy array for 'out'"); + goto fail; + } + out = (PyArrayObject *)out_in; + } + + ret = is_business_day(dates, out, + weekmask, busdays_in_weekmask, + holidays.begin, holidays.end); + + Py_DECREF(dates); + if (allocated_holidays && holidays.begin != NULL) { + PyArray_free(holidays.begin); + } + + return out == NULL ? PyArray_Return(ret) : (PyObject *)ret; + +fail: + Py_XDECREF(dates); + if (allocated_holidays && holidays.begin != NULL) { + PyArray_free(holidays.begin); + } + + return NULL; +} diff --git a/numpy/core/src/multiarray/datetime_busday.h b/numpy/core/src/multiarray/datetime_busday.h new file mode 100644 index 0000000..4831511 --- /dev/null +++ b/numpy/core/src/multiarray/datetime_busday.h @@ -0,0 +1,28 @@ +#ifndef _NPY_PRIVATE__DATETIME_BUSDAY_H_ +#define _NPY_PRIVATE__DATETIME_BUSDAY_H_ + +/* + * This is the 'busday_offset' function exposed for calling + * from Python. + */ +NPY_NO_EXPORT PyObject * +array_busday_offset(PyObject *NPY_UNUSED(self), + PyObject *args, PyObject *kwds); + +/* + * This is the 'busday_count' function exposed for calling + * from Python. + */ +NPY_NO_EXPORT PyObject * +array_busday_count(PyObject *NPY_UNUSED(self), + PyObject *args, PyObject *kwds); + +/* + * This is the 'is_busday' function exposed for calling + * from Python. + */ +NPY_NO_EXPORT PyObject * +array_is_busday(PyObject *NPY_UNUSED(self), + PyObject *args, PyObject *kwds); + +#endif diff --git a/numpy/core/src/multiarray/datetime_busdaycal.c b/numpy/core/src/multiarray/datetime_busdaycal.c new file mode 100644 index 0000000..7a26868 --- /dev/null +++ b/numpy/core/src/multiarray/datetime_busdaycal.c @@ -0,0 +1,553 @@ +/* + * This file implements an object encapsulating a business day + * calendar object for accelerating NumPy datetime business day functions. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "common.h" +#include "numpy/arrayscalars.h" +#include "lowlevel_strided_loops.h" +#include "_datetime.h" +#include "datetime_busday.h" +#include "datetime_busdaycal.h" + +NPY_NO_EXPORT int +PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask) +{ + PyObject *obj = weekmask_in; + + /* Make obj into an ASCII string if it is UNICODE */ + Py_INCREF(obj); + if (PyUnicode_Check(obj)) { + /* accept unicode input */ + PyObject *obj_str; + obj_str = PyUnicode_AsASCIIString(obj); + if (obj_str == NULL) { + Py_DECREF(obj); + return 0; + } + Py_DECREF(obj); + obj = obj_str; + } + + if (PyBytes_Check(obj)) { + char *str; + Py_ssize_t len; + int i; + + if (PyBytes_AsStringAndSize(obj, &str, &len) < 0) { + Py_DECREF(obj); + return 0; + } + + /* Length 7 is a string like "1111100" */ + if (len == 7) { + for (i = 0; i < 7; ++i) { + switch(str[i]) { + case '0': + weekmask[i] = 0; + break; + case '1': + weekmask[i] = 1; + break; + default: + goto general_weekmask_string; + } + } + + goto finish; + } + +general_weekmask_string: + /* a string like "SatSun" or "Mon Tue Wed" */ + memset(weekmask, 0, 7); + for (i = 0; i < len; i += 3) { + while (isspace(str[i])) + ++i; + + if (i == len) { + goto finish; + } + else if (i + 2 >= len) { + goto invalid_weekmask_string; + } + + switch (str[i]) { + case 'M': + if (str[i+1] == 'o' && str[i+2] == 'n') { + weekmask[0] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + case 'T': + if (str[i+1] == 'u' && str[i+2] == 'e') { + weekmask[1] = 1; + } + else if (str[i+1] == 'h' && str[i+2] == 'u') { + weekmask[3] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + case 'W': + if (str[i+1] == 'e' && str[i+2] == 'd') { + weekmask[2] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + case 'F': + if (str[i+1] == 'r' && str[i+2] == 'i') { + weekmask[4] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + case 'S': + if (str[i+1] == 'a' && str[i+2] == 't') { + weekmask[5] = 1; + } + else if (str[i+1] == 'u' && str[i+2] == 'n') { + weekmask[6] = 1; + } + else { + goto invalid_weekmask_string; + } + break; + default: + goto invalid_weekmask_string; + } + } + + goto finish; + +invalid_weekmask_string: + PyErr_Format(PyExc_ValueError, + "Invalid business day weekmask string \"%s\"", + str); + Py_DECREF(obj); + return 0; + } + /* Something like [1,1,1,1,1,0,0] */ + else if (PySequence_Check(obj)) { + if (PySequence_Size(obj) != 7 || + (PyArray_Check(obj) && + PyArray_NDIM((PyArrayObject *)obj) != 1)) { + PyErr_SetString(PyExc_ValueError, + "A business day weekmask array must have length 7"); + Py_DECREF(obj); + return 0; + } + else { + int i; + + for (i = 0; i < 7; ++i) { + long val; + PyObject *f = PySequence_GetItem(obj, i); + if (f == NULL) { + Py_DECREF(obj); + return 0; + } + + val = PyInt_AsLong(f); + if (error_converting(val)) { + Py_DECREF(f); + Py_DECREF(obj); + return 0; + } + if (val == 0) { + weekmask[i] = 0; + } + else if (val == 1) { + weekmask[i] = 1; + } + else { + PyErr_SetString(PyExc_ValueError, + "A business day weekmask array must have all " + "1's and 0's"); + Py_DECREF(f); + Py_DECREF(obj); + return 0; + } + Py_DECREF(f); + } + + goto finish; + } + } + + PyErr_SetString(PyExc_ValueError, + "Couldn't convert object into a business day weekmask"); + Py_DECREF(obj); + return 0; + +finish: + Py_DECREF(obj); + return 1; +} + +static int +qsort_datetime_compare(const void *elem1, const void *elem2) +{ + npy_datetime e1 = *(const npy_datetime *)elem1; + npy_datetime e2 = *(const npy_datetime *)elem2; + + return (e1 < e2) ? -1 : (e1 == e2) ? 0 : 1; +} + +/* + * Sorts the array of dates provided in place and removes + * NaT, duplicates and any date which is already excluded on account + * of the weekmask. + * + * Returns the number of dates left after removing weekmask-excluded + * dates. + */ +NPY_NO_EXPORT void +normalize_holidays_list(npy_holidayslist *holidays, npy_bool *weekmask) +{ + npy_datetime *dates = holidays->begin; + npy_intp count = holidays->end - dates; + + npy_datetime lastdate = NPY_DATETIME_NAT; + npy_intp trimcount, i; + int day_of_week; + + /* Sort the dates */ + qsort(dates, count, sizeof(npy_datetime), &qsort_datetime_compare); + + /* Sweep through the array, eliminating unnecessary values */ + trimcount = 0; + for (i = 0; i < count; ++i) { + npy_datetime date = dates[i]; + + /* Skip any NaT or duplicate */ + if (date != NPY_DATETIME_NAT && date != lastdate) { + /* Get the day of the week (1970-01-05 is Monday) */ + day_of_week = (int)((date - 4) % 7); + if (day_of_week < 0) { + day_of_week += 7; + } + + /* + * If the holiday falls on a possible business day, + * then keep it. + */ + if (weekmask[day_of_week] == 1) { + dates[trimcount++] = date; + lastdate = date; + } + } + } + + /* Adjust the end of the holidays array */ + holidays->end = dates + trimcount; +} + +/* + * Converts a Python input into a non-normalized list of holidays. + * + * IMPORTANT: This function can't do the normalization, because it doesn't + * know the weekmask. You must call 'normalize_holiday_list' + * on the result before using it. + */ +NPY_NO_EXPORT int +PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays) +{ + PyArrayObject *dates = NULL; + PyArray_Descr *date_dtype = NULL; + npy_intp count; + + /* Make 'dates' into an array */ + if (PyArray_Check(dates_in)) { + dates = (PyArrayObject *)dates_in; + Py_INCREF(dates); + } + else { + PyArray_Descr *datetime_dtype; + + /* Use the datetime dtype with generic units so it fills it in */ + datetime_dtype = PyArray_DescrFromType(NPY_DATETIME); + if (datetime_dtype == NULL) { + goto fail; + } + + /* This steals the datetime_dtype reference */ + dates = (PyArrayObject *)PyArray_FromAny(dates_in, datetime_dtype, + 0, 0, 0, dates_in); + if (dates == NULL) { + goto fail; + } + } + + date_dtype = create_datetime_dtype_with_unit(NPY_DATETIME, NPY_FR_D); + if (date_dtype == NULL) { + goto fail; + } + + if (!PyArray_CanCastTypeTo(PyArray_DESCR(dates), + date_dtype, NPY_SAFE_CASTING)) { + PyErr_SetString(PyExc_ValueError, "Cannot safely convert " + "provided holidays input into an array of dates"); + goto fail; + } + if (PyArray_NDIM(dates) != 1) { + PyErr_SetString(PyExc_ValueError, "holidays must be a provided " + "as a one-dimensional array"); + goto fail; + } + + /* Allocate the memory for the dates */ + count = PyArray_DIM(dates, 0); + holidays->begin = PyArray_malloc(sizeof(npy_datetime) * count); + if (holidays->begin == NULL) { + PyErr_NoMemory(); + goto fail; + } + holidays->end = holidays->begin + count; + + /* Cast the data into a raw date array */ + if (PyArray_CastRawArrays(count, + PyArray_BYTES(dates), (char *)holidays->begin, + PyArray_STRIDE(dates, 0), sizeof(npy_datetime), + PyArray_DESCR(dates), date_dtype, + 0) != NPY_SUCCEED) { + goto fail; + } + + Py_DECREF(dates); + Py_DECREF(date_dtype); + + return 1; + +fail: + Py_XDECREF(dates); + Py_XDECREF(date_dtype); + return 0; +} + +static PyObject * +busdaycalendar_new(PyTypeObject *subtype, + PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds)) +{ + NpyBusDayCalendar *self; + + self = (NpyBusDayCalendar *)subtype->tp_alloc(subtype, 0); + if (self != NULL) { + /* Start with an empty holidays list */ + self->holidays.begin = NULL; + self->holidays.end = NULL; + + /* Set the weekmask to the default */ + self->busdays_in_weekmask = 5; + self->weekmask[0] = 1; + self->weekmask[1] = 1; + self->weekmask[2] = 1; + self->weekmask[3] = 1; + self->weekmask[4] = 1; + self->weekmask[5] = 0; + self->weekmask[6] = 0; + } + + return (PyObject *)self; +} + +static int +busdaycalendar_init(NpyBusDayCalendar *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"weekmask", "holidays", NULL}; + int i, busdays_in_weekmask; + + /* Clear the holidays if necessary */ + if (self->holidays.begin != NULL) { + PyArray_free(self->holidays.begin); + self->holidays.begin = NULL; + self->holidays.end = NULL; + } + + /* Reset the weekmask to the default */ + self->busdays_in_weekmask = 5; + self->weekmask[0] = 1; + self->weekmask[1] = 1; + self->weekmask[2] = 1; + self->weekmask[3] = 1; + self->weekmask[4] = 1; + self->weekmask[5] = 0; + self->weekmask[6] = 0; + + /* Parse the parameters */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "|O&O&:busdaycal", kwlist, + &PyArray_WeekMaskConverter, &self->weekmask[0], + &PyArray_HolidaysConverter, &self->holidays)) { + return -1; + } + + /* Count the number of business days in a week */ + busdays_in_weekmask = 0; + for (i = 0; i < 7; ++i) { + busdays_in_weekmask += self->weekmask[i]; + } + self->busdays_in_weekmask = busdays_in_weekmask; + + /* Normalize the holidays list */ + normalize_holidays_list(&self->holidays, self->weekmask); + + if (self->busdays_in_weekmask == 0) { + PyErr_SetString(PyExc_ValueError, + "Cannot construct a numpy.busdaycal with a weekmask of " + "all zeros"); + return -1; + } + + return 0; +} + +static void +busdaycalendar_dealloc(NpyBusDayCalendar *self) +{ + /* Clear the holidays */ + if (self->holidays.begin != NULL) { + PyArray_free(self->holidays.begin); + self->holidays.begin = NULL; + self->holidays.end = NULL; + } + + Py_TYPE(self)->tp_free((PyObject*)self); +} + +static PyObject * +busdaycalendar_weekmask_get(NpyBusDayCalendar *self) +{ + PyArrayObject *ret; + npy_intp size = 7; + + /* Allocate a 7-element boolean array */ + ret = (PyArrayObject *)PyArray_SimpleNew(1, &size, NPY_BOOL); + if (ret == NULL) { + return NULL; + } + + /* Copy the weekmask data */ + memcpy(PyArray_DATA(ret), self->weekmask, 7); + + return (PyObject *)ret; +} + +static PyObject * +busdaycalendar_holidays_get(NpyBusDayCalendar *self) +{ + PyArrayObject *ret; + PyArray_Descr *date_dtype; + npy_intp size = self->holidays.end - self->holidays.begin; + + /* Create a date dtype */ + date_dtype = create_datetime_dtype_with_unit(NPY_DATETIME, NPY_FR_D); + if (date_dtype == NULL) { + return NULL; + } + + /* Allocate a date array (this steals the date_dtype reference) */ + ret = (PyArrayObject *)PyArray_SimpleNewFromDescr(1, &size, date_dtype); + if (ret == NULL) { + return NULL; + } + + /* Copy the holidays */ + if (size > 0) { + memcpy(PyArray_DATA(ret), self->holidays.begin, + size * sizeof(npy_datetime)); + } + + return (PyObject *)ret; +} + +static PyGetSetDef busdaycalendar_getsets[] = { + {"weekmask", + (getter)busdaycalendar_weekmask_get, + NULL, NULL, NULL}, + {"holidays", + (getter)busdaycalendar_holidays_get, + NULL, NULL, NULL}, + + {NULL, NULL, NULL, NULL, NULL} +}; + +NPY_NO_EXPORT PyTypeObject NpyBusDayCalendar_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.busdaycalendar", /* tp_name */ + sizeof(NpyBusDayCalendar), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)busdaycalendar_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + busdaycalendar_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)busdaycalendar_init, /* tp_init */ + 0, /* tp_alloc */ + busdaycalendar_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; diff --git a/numpy/core/src/multiarray/datetime_busdaycal.h b/numpy/core/src/multiarray/datetime_busdaycal.h new file mode 100644 index 0000000..02903e3 --- /dev/null +++ b/numpy/core/src/multiarray/datetime_busdaycal.h @@ -0,0 +1,62 @@ +#ifndef _NPY_PRIVATE__DATETIME_BUSDAYDEF_H_ +#define _NPY_PRIVATE__DATETIME_BUSDAYDEF_H_ + +/* + * A list of holidays, which should be sorted, not contain any + * duplicates or NaTs, and not include any days already excluded + * by the associated weekmask. + * + * The data is manually managed with PyArray_malloc/PyArray_free. + */ +typedef struct { + npy_datetime *begin, *end; +} npy_holidayslist; + +/* + * This object encapsulates a weekmask and normalized holidays list, + * so that the business day API can use this data without having + * to normalize it repeatedly. All the data of this object is private + * and cannot be modified from Python. Copies are made when giving + * the weekmask and holidays data to Python code. + */ +typedef struct { + PyObject_HEAD + npy_holidayslist holidays; + int busdays_in_weekmask; + npy_bool weekmask[7]; +} NpyBusDayCalendar; + +extern NPY_NO_EXPORT PyTypeObject NpyBusDayCalendar_Type; + + +/* + * Converts a Python input into a 7-element weekmask, where 0 means + * weekend and 1 means business day. + */ +NPY_NO_EXPORT int +PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask); + +/* + * Sorts the array of dates provided in place and removes + * NaT, duplicates and any date which is already excluded on account + * of the weekmask. + * + * Returns the number of dates left after removing weekmask-excluded + * dates. + */ +NPY_NO_EXPORT void +normalize_holidays_list(npy_holidayslist *holidays, npy_bool *weekmask); + +/* + * Converts a Python input into a non-normalized list of holidays. + * + * IMPORTANT: This function can't do the normalization, because it doesn't + * know the weekmask. You must call 'normalize_holiday_list' + * on the result before using it. + */ +NPY_NO_EXPORT int +PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays); + + + +#endif diff --git a/numpy/core/src/multiarray/datetime_strings.c b/numpy/core/src/multiarray/datetime_strings.c new file mode 100644 index 0000000..b9aeda5 --- /dev/null +++ b/numpy/core/src/multiarray/datetime_strings.c @@ -0,0 +1,1592 @@ +/* + * This file implements string parsing and creation for NumPy datetime. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include + +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "numpy/arrayscalars.h" +#include "methods.h" +#include "_datetime.h" +#include "datetime_strings.h" + +/* + * Platform-specific time_t typedef. Some platforms use 32 bit, some use 64 bit + * and we just use the default with the exception of mingw, where we must use + * 64 bit because MSVCRT version 9 does not have the (32 bit) localtime() + * symbol, so we need to use the 64 bit version [1]. + * + * [1] http://thread.gmane.org/gmane.comp.gnu.mingw.user/27011 + */ +#if defined(NPY_MINGW_USE_CUSTOM_MSVCR) + typedef __time64_t NPY_TIME_T; +#else + typedef time_t NPY_TIME_T; +#endif + +/* + * Wraps `localtime` functionality for multiple platforms. This + * converts a time value to a time structure in the local timezone. + * If size(NPY_TIME_T) == 4, then years must be between 1970 and 2038. If + * size(NPY_TIME_T) == 8, then years must be later than 1970. If the years are + * not in this range, then get_localtime() will fail on some platforms. + * + * Returns 0 on success, -1 on failure. + * + * Notes: + * 1) If NPY_TIME_T is 32 bit (i.e. sizeof(NPY_TIME_T) == 4), then the + * maximum year it can represent is 2038 (see [1] for more details). Trying + * to use a higher date like 2041 in the 32 bit "ts" variable below will + * typically result in "ts" being a negative number (corresponding roughly + * to a year ~ 1905). If NPY_TIME_T is 64 bit, then there is no such + * problem in practice. + * 2) If the "ts" argument to localtime() is negative, it represents + * years < 1970 both for 32 and 64 bits (for 32 bits the earliest year it can + * represent is 1901, while 64 bits can represent much earlier years). + * 3) On Linux, localtime() works for negative "ts". On Windows and in Wine, + * localtime() as well as the localtime_s() and _localtime64_s() functions + * will fail for any negative "ts" and return a nonzero exit number + * (localtime_s, _localtime64_s) or NULL (localtime). This behavior is the + * same for both 32 and 64 bits. + * + * From this it follows that get_localtime() is only guaranteed to work + * correctly on all platforms for years between 1970 and 2038 for 32bit + * NPY_TIME_T and years higher than 1970 for 64bit NPY_TIME_T. For + * multiplatform code, get_localtime() should never be used outside of this + * range. + * + * [1] http://en.wikipedia.org/wiki/Year_2038_problem + */ +static int +get_localtime(NPY_TIME_T *ts, struct tm *tms) +{ + char *func_name = ""; +#if defined(_WIN32) + #if defined(_MSC_VER) && (_MSC_VER >= 1400) + if (localtime_s(tms, ts) != 0) { + func_name = "localtime_s"; + goto fail; + } + #elif defined(NPY_MINGW_USE_CUSTOM_MSVCR) + if (_localtime64_s(tms, ts) != 0) { + func_name = "_localtime64_s"; + goto fail; + } + #else + struct tm *tms_tmp; + tms_tmp = localtime(ts); + if (tms_tmp == NULL) { + func_name = "localtime"; + goto fail; + } + memcpy(tms, tms_tmp, sizeof(struct tm)); + #endif +#else + if (localtime_r(ts, tms) == NULL) { + func_name = "localtime_r"; + goto fail; + } +#endif + + return 0; + +fail: + PyErr_Format(PyExc_OSError, "Failed to use '%s' to convert " + "to a local time", func_name); + return -1; +} + +/* + * Converts a datetimestruct in UTC to a datetimestruct in local time, + * also returning the timezone offset applied. This function works for any year + * > 1970 on all platforms and both 32 and 64 bits. If the year < 1970, then it + * will fail on some platforms. + * + * Returns 0 on success, -1 on failure. + */ +static int +convert_datetimestruct_utc_to_local(npy_datetimestruct *out_dts_local, + const npy_datetimestruct *dts_utc, int *out_timezone_offset) +{ + NPY_TIME_T rawtime = 0, localrawtime; + struct tm tm_; + npy_int64 year_correction = 0; + + /* Make a copy of the input 'dts' to modify */ + *out_dts_local = *dts_utc; + + /* + * For 32 bit NPY_TIME_T, the get_localtime() function does not work for + * years later than 2038, see the comments above get_localtime(). So if the + * year >= 2038, we instead call get_localtime() for the year 2036 or 2037 + * (depending on the leap year) which must work and at the end we add the + * 'year_correction' back. + */ + if (sizeof(NPY_TIME_T) == 4 && out_dts_local->year >= 2038) { + if (is_leapyear(out_dts_local->year)) { + /* 2036 is a leap year */ + year_correction = out_dts_local->year - 2036; + out_dts_local->year -= year_correction; /* = 2036 */ + } + else { + /* 2037 is not a leap year */ + year_correction = out_dts_local->year - 2037; + out_dts_local->year -= year_correction; /* = 2037 */ + } + } + + /* + * Convert everything in 'dts' to a time_t, to minutes precision. + * This is POSIX time, which skips leap-seconds, but because + * we drop the seconds value from the npy_datetimestruct, everything + * is ok for this operation. + */ + rawtime = (NPY_TIME_T)get_datetimestruct_days(out_dts_local) * 24 * 60 * 60; + rawtime += dts_utc->hour * 60 * 60; + rawtime += dts_utc->min * 60; + + /* localtime converts a 'time_t' into a local 'struct tm' */ + if (get_localtime(&rawtime, &tm_) < 0) { + /* This should only fail if year < 1970 on some platforms. */ + return -1; + } + + /* Copy back all the values except seconds */ + out_dts_local->min = tm_.tm_min; + out_dts_local->hour = tm_.tm_hour; + out_dts_local->day = tm_.tm_mday; + out_dts_local->month = tm_.tm_mon + 1; + out_dts_local->year = tm_.tm_year + 1900; + + /* Extract the timezone offset that was applied */ + rawtime /= 60; + localrawtime = (NPY_TIME_T)get_datetimestruct_days(out_dts_local) * 24 * 60; + localrawtime += out_dts_local->hour * 60; + localrawtime += out_dts_local->min; + + *out_timezone_offset = localrawtime - rawtime; + + /* Reapply the year 2038 year correction */ + out_dts_local->year += year_correction; + + return 0; +} + +/* + * Parses (almost) standard ISO 8601 date strings. The differences are: + * + * + The date "20100312" is parsed as the year 20100312, not as + * equivalent to "2010-03-12". The '-' in the dates are not optional. + * + Only seconds may have a decimal point, with up to 18 digits after it + * (maximum attoseconds precision). + * + Either a 'T' as in ISO 8601 or a ' ' may be used to separate + * the date and the time. Both are treated equivalently. + * + Doesn't (yet) handle the "YYYY-DDD" or "YYYY-Www" formats. + * + Doesn't handle leap seconds (seconds value has 60 in these cases). + * + Doesn't handle 24:00:00 as synonym for midnight (00:00:00) tomorrow + * + Accepts special values "NaT" (not a time), "Today", (current + * day according to local time) and "Now" (current time in UTC). + * + * 'str' must be a NULL-terminated string, and 'len' must be its length. + * 'unit' should contain -1 if the unit is unknown, or the unit + * which will be used if it is. + * 'casting' controls how the detected unit from the string is allowed + * to be cast to the 'unit' parameter. + * + * 'out' gets filled with the parsed date-time. + * 'out_bestunit' gives a suggested unit based on the amount of + * resolution provided in the string, or -1 for NaT. + * 'out_special' gets set to 1 if the parsed time was 'today', + * 'now', or ''/'NaT'. For 'today', the unit recommended is + * 'D', for 'now', the unit recommended is 's', and for 'NaT' + * the unit recommended is 'Y'. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +parse_iso_8601_datetime(char *str, Py_ssize_t len, + NPY_DATETIMEUNIT unit, + NPY_CASTING casting, + npy_datetimestruct *out, + NPY_DATETIMEUNIT *out_bestunit, + npy_bool *out_special) +{ + int year_leap = 0; + int i, numdigits; + char *substr; + Py_ssize_t sublen; + NPY_DATETIMEUNIT bestunit; + + /* Initialize the output to all zeros */ + memset(out, 0, sizeof(npy_datetimestruct)); + out->month = 1; + out->day = 1; + + /* + * Convert the empty string and case-variants of "NaT" to not-a-time. + * Tried to use PyOS_stricmp, but that function appears to be broken, + * not even matching the strcmp function signature as it should. + */ + if (len <= 0 || (len == 3 && + tolower(str[0]) == 'n' && + tolower(str[1]) == 'a' && + tolower(str[2]) == 't')) { + out->year = NPY_DATETIME_NAT; + + /* + * Indicate that this was a special value, and + * recommend generic units. + */ + if (out_bestunit != NULL) { + *out_bestunit = NPY_FR_GENERIC; + } + if (out_special != NULL) { + *out_special = 1; + } + + return 0; + } + + if (unit == NPY_FR_GENERIC) { + PyErr_SetString(PyExc_ValueError, + "Cannot create a NumPy datetime other than NaT " + "with generic units"); + return -1; + } + + /* + * The string "today" means take today's date in local time, and + * convert it to a date representation. This date representation, if + * forced into a time unit, will be at midnight UTC. + * This is perhaps a little weird, but done so that the + * 'datetime64[D]' type produces the date you expect, rather than + * switching to an adjacent day depending on the current time and your + * timezone. + */ + if (len == 5 && tolower(str[0]) == 't' && + tolower(str[1]) == 'o' && + tolower(str[2]) == 'd' && + tolower(str[3]) == 'a' && + tolower(str[4]) == 'y') { + NPY_TIME_T rawtime = 0; + struct tm tm_; + + time(&rawtime); + if (get_localtime(&rawtime, &tm_) < 0) { + return -1; + } + out->year = tm_.tm_year + 1900; + out->month = tm_.tm_mon + 1; + out->day = tm_.tm_mday; + + bestunit = NPY_FR_D; + + /* + * Indicate that this was a special value, and + * is a date (unit 'D'). + */ + if (out_bestunit != NULL) { + *out_bestunit = bestunit; + } + if (out_special != NULL) { + *out_special = 1; + } + + /* Check the casting rule */ + if (unit != -1 && !can_cast_datetime64_units(bestunit, unit, + casting)) { + PyErr_Format(PyExc_TypeError, "Cannot parse \"%s\" as unit " + "'%s' using casting rule %s", + str, _datetime_strings[unit], + npy_casting_to_string(casting)); + return -1; + } + + return 0; + } + + /* The string "now" resolves to the current UTC time */ + if (len == 3 && tolower(str[0]) == 'n' && + tolower(str[1]) == 'o' && + tolower(str[2]) == 'w') { + NPY_TIME_T rawtime = 0; + PyArray_DatetimeMetaData meta; + + time(&rawtime); + + /* Set up a dummy metadata for the conversion */ + meta.base = NPY_FR_s; + meta.num = 1; + + bestunit = NPY_FR_s; + + /* + * Indicate that this was a special value, and + * use 's' because the time() function has resolution + * seconds. + */ + if (out_bestunit != NULL) { + *out_bestunit = bestunit; + } + if (out_special != NULL) { + *out_special = 1; + } + + /* Check the casting rule */ + if (unit != -1 && !can_cast_datetime64_units(bestunit, unit, + casting)) { + PyErr_Format(PyExc_TypeError, "Cannot parse \"%s\" as unit " + "'%s' using casting rule %s", + str, _datetime_strings[unit], + npy_casting_to_string(casting)); + return -1; + } + + return convert_datetime_to_datetimestruct(&meta, rawtime, out); + } + + /* Anything else isn't a special value */ + if (out_special != NULL) { + *out_special = 0; + } + + substr = str; + sublen = len; + + /* Skip leading whitespace */ + while (sublen > 0 && isspace(*substr)) { + ++substr; + --sublen; + } + + /* Leading '-' sign for negative year */ + if (*substr == '-') { + ++substr; + --sublen; + } + + if (sublen == 0) { + goto parse_error; + } + + /* PARSE THE YEAR (digits until the '-' character) */ + out->year = 0; + while (sublen > 0 && isdigit(*substr)) { + out->year = 10 * out->year + (*substr - '0'); + ++substr; + --sublen; + } + + /* Negate the year if necessary */ + if (str[0] == '-') { + out->year = -out->year; + } + /* Check whether it's a leap-year */ + year_leap = is_leapyear(out->year); + + /* Next character must be a '-' or the end of the string */ + if (sublen == 0) { + bestunit = NPY_FR_Y; + goto finish; + } + else if (*substr == '-') { + ++substr; + --sublen; + } + else { + goto parse_error; + } + + /* Can't have a trailing '-' */ + if (sublen == 0) { + goto parse_error; + } + + /* PARSE THE MONTH (2 digits) */ + if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) { + out->month = 10 * (substr[0] - '0') + (substr[1] - '0'); + + if (out->month < 1 || out->month > 12) { + PyErr_Format(PyExc_ValueError, + "Month out of range in datetime string \"%s\"", str); + goto error; + } + substr += 2; + sublen -= 2; + } + else { + goto parse_error; + } + + /* Next character must be a '-' or the end of the string */ + if (sublen == 0) { + bestunit = NPY_FR_M; + goto finish; + } + else if (*substr == '-') { + ++substr; + --sublen; + } + else { + goto parse_error; + } + + /* Can't have a trailing '-' */ + if (sublen == 0) { + goto parse_error; + } + + /* PARSE THE DAY (2 digits) */ + if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) { + out->day = 10 * (substr[0] - '0') + (substr[1] - '0'); + + if (out->day < 1 || + out->day > _days_per_month_table[year_leap][out->month-1]) { + PyErr_Format(PyExc_ValueError, + "Day out of range in datetime string \"%s\"", str); + goto error; + } + substr += 2; + sublen -= 2; + } + else { + goto parse_error; + } + + /* Next character must be a 'T', ' ', or end of string */ + if (sublen == 0) { + bestunit = NPY_FR_D; + goto finish; + } + else if (*substr != 'T' && *substr != ' ') { + goto parse_error; + } + else { + ++substr; + --sublen; + } + + /* PARSE THE HOURS (2 digits) */ + if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) { + out->hour = 10 * (substr[0] - '0') + (substr[1] - '0'); + + if (out->hour >= 24) { + PyErr_Format(PyExc_ValueError, + "Hours out of range in datetime string \"%s\"", str); + goto error; + } + substr += 2; + sublen -= 2; + } + else { + goto parse_error; + } + + /* Next character must be a ':' or the end of the string */ + if (sublen > 0 && *substr == ':') { + ++substr; + --sublen; + } + else { + bestunit = NPY_FR_h; + goto parse_timezone; + } + + /* Can't have a trailing ':' */ + if (sublen == 0) { + goto parse_error; + } + + /* PARSE THE MINUTES (2 digits) */ + if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) { + out->min = 10 * (substr[0] - '0') + (substr[1] - '0'); + + if (out->min >= 60) { + PyErr_Format(PyExc_ValueError, + "Minutes out of range in datetime string \"%s\"", str); + goto error; + } + substr += 2; + sublen -= 2; + } + else { + goto parse_error; + } + + /* Next character must be a ':' or the end of the string */ + if (sublen > 0 && *substr == ':') { + ++substr; + --sublen; + } + else { + bestunit = NPY_FR_m; + goto parse_timezone; + } + + /* Can't have a trailing ':' */ + if (sublen == 0) { + goto parse_error; + } + + /* PARSE THE SECONDS (2 digits) */ + if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) { + out->sec = 10 * (substr[0] - '0') + (substr[1] - '0'); + + if (out->sec >= 60) { + PyErr_Format(PyExc_ValueError, + "Seconds out of range in datetime string \"%s\"", str); + goto error; + } + substr += 2; + sublen -= 2; + } + else { + goto parse_error; + } + + /* Next character may be a '.' indicating fractional seconds */ + if (sublen > 0 && *substr == '.') { + ++substr; + --sublen; + } + else { + bestunit = NPY_FR_s; + goto parse_timezone; + } + + /* PARSE THE MICROSECONDS (0 to 6 digits) */ + numdigits = 0; + for (i = 0; i < 6; ++i) { + out->us *= 10; + if (sublen > 0 && isdigit(*substr)) { + out->us += (*substr - '0'); + ++substr; + --sublen; + ++numdigits; + } + } + + if (sublen == 0 || !isdigit(*substr)) { + if (numdigits > 3) { + bestunit = NPY_FR_us; + } + else { + bestunit = NPY_FR_ms; + } + goto parse_timezone; + } + + /* PARSE THE PICOSECONDS (0 to 6 digits) */ + numdigits = 0; + for (i = 0; i < 6; ++i) { + out->ps *= 10; + if (sublen > 0 && isdigit(*substr)) { + out->ps += (*substr - '0'); + ++substr; + --sublen; + ++numdigits; + } + } + + if (sublen == 0 || !isdigit(*substr)) { + if (numdigits > 3) { + bestunit = NPY_FR_ps; + } + else { + bestunit = NPY_FR_ns; + } + goto parse_timezone; + } + + /* PARSE THE ATTOSECONDS (0 to 6 digits) */ + numdigits = 0; + for (i = 0; i < 6; ++i) { + out->as *= 10; + if (sublen > 0 && isdigit(*substr)) { + out->as += (*substr - '0'); + ++substr; + --sublen; + ++numdigits; + } + } + + if (numdigits > 3) { + bestunit = NPY_FR_as; + } + else { + bestunit = NPY_FR_fs; + } + +parse_timezone: + if (sublen == 0) { + goto finish; + } + else { + /* 2016-01-14, 1.11 */ + PyErr_Clear(); + if (DEPRECATE( + "parsing timezone aware datetimes is deprecated; " + "this will raise an error in the future") < 0) { + return -1; + } + } + + /* UTC specifier */ + if (*substr == 'Z') { + if (sublen == 1) { + goto finish; + } + else { + ++substr; + --sublen; + } + } + /* Time zone offset */ + else if (*substr == '-' || *substr == '+') { + int offset_neg = 0, offset_hour = 0, offset_minute = 0; + + if (*substr == '-') { + offset_neg = 1; + } + ++substr; + --sublen; + + /* The hours offset */ + if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) { + offset_hour = 10 * (substr[0] - '0') + (substr[1] - '0'); + substr += 2; + sublen -= 2; + if (offset_hour >= 24) { + PyErr_Format(PyExc_ValueError, + "Timezone hours offset out of range " + "in datetime string \"%s\"", str); + goto error; + } + } + else { + goto parse_error; + } + + /* The minutes offset is optional */ + if (sublen > 0) { + /* Optional ':' */ + if (*substr == ':') { + ++substr; + --sublen; + } + + /* The minutes offset (at the end of the string) */ + if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) { + offset_minute = 10 * (substr[0] - '0') + (substr[1] - '0'); + substr += 2; + sublen -= 2; + if (offset_minute >= 60) { + PyErr_Format(PyExc_ValueError, + "Timezone minutes offset out of range " + "in datetime string \"%s\"", str); + goto error; + } + } + else { + goto parse_error; + } + } + + /* Apply the time zone offset */ + if (offset_neg) { + offset_hour = -offset_hour; + offset_minute = -offset_minute; + } + add_minutes_to_datetimestruct(out, -60 * offset_hour - offset_minute); + } + + /* Skip trailing whitespace */ + while (sublen > 0 && isspace(*substr)) { + ++substr; + --sublen; + } + + if (sublen != 0) { + goto parse_error; + } + +finish: + if (out_bestunit != NULL) { + *out_bestunit = bestunit; + } + + /* Check the casting rule */ + if (unit != -1 && !can_cast_datetime64_units(bestunit, unit, + casting)) { + PyErr_Format(PyExc_TypeError, "Cannot parse \"%s\" as unit " + "'%s' using casting rule %s", + str, _datetime_strings[unit], + npy_casting_to_string(casting)); + return -1; + } + + return 0; + +parse_error: + PyErr_Format(PyExc_ValueError, + "Error parsing datetime string \"%s\" at position %d", + str, (int)(substr-str)); + return -1; + +error: + return -1; +} + +/* + * Provides a string length to use for converting datetime + * objects with the given local and unit settings. + */ +NPY_NO_EXPORT int +get_datetime_iso_8601_strlen(int local, NPY_DATETIMEUNIT base) +{ + int len = 0; + + /* If no unit is provided, return the maximum length */ + if (base == -1) { + return NPY_DATETIME_MAX_ISO8601_STRLEN; + } + + switch (base) { + /* Generic units can only be used to represent NaT */ + case NPY_FR_GENERIC: + return 4; + case NPY_FR_as: + len += 3; /* "###" */ + case NPY_FR_fs: + len += 3; /* "###" */ + case NPY_FR_ps: + len += 3; /* "###" */ + case NPY_FR_ns: + len += 3; /* "###" */ + case NPY_FR_us: + len += 3; /* "###" */ + case NPY_FR_ms: + len += 4; /* ".###" */ + case NPY_FR_s: + len += 3; /* ":##" */ + case NPY_FR_m: + len += 3; /* ":##" */ + case NPY_FR_h: + len += 3; /* "T##" */ + case NPY_FR_D: + case NPY_FR_W: + len += 3; /* "-##" */ + case NPY_FR_M: + len += 3; /* "-##" */ + case NPY_FR_Y: + len += 21; /* 64-bit year */ + break; + } + + if (base >= NPY_FR_h) { + if (local) { + len += 5; /* "+####" or "-####" */ + } + else { + len += 1; /* "Z" */ + } + } + + len += 1; /* NULL terminator */ + + return len; +} + +/* + * Finds the largest unit whose value is nonzero, and for which + * the remainder for the rest of the units is zero. + */ +static NPY_DATETIMEUNIT +lossless_unit_from_datetimestruct(npy_datetimestruct *dts) +{ + if (dts->as % 1000 != 0) { + return NPY_FR_as; + } + else if (dts->as != 0) { + return NPY_FR_fs; + } + else if (dts->ps % 1000 != 0) { + return NPY_FR_ps; + } + else if (dts->ps != 0) { + return NPY_FR_ns; + } + else if (dts->us % 1000 != 0) { + return NPY_FR_us; + } + else if (dts->us != 0) { + return NPY_FR_ms; + } + else if (dts->sec != 0) { + return NPY_FR_s; + } + else if (dts->min != 0) { + return NPY_FR_m; + } + else if (dts->hour != 0) { + return NPY_FR_h; + } + else if (dts->day != 1) { + return NPY_FR_D; + } + else if (dts->month != 1) { + return NPY_FR_M; + } + else { + return NPY_FR_Y; + } +} + +/* + * Converts an npy_datetimestruct to an (almost) ISO 8601 + * NULL-terminated string. If the string fits in the space exactly, + * it leaves out the NULL terminator and returns success. + * + * The differences from ISO 8601 are the 'NaT' string, and + * the number of year digits is >= 4 instead of strictly 4. + * + * If 'local' is non-zero, it produces a string in local time with + * a +-#### timezone offset. If 'local' is zero and 'utc' is non-zero, + * produce a string ending with 'Z' to denote UTC. By default, no time + * zone information is attached. + * + * 'base' restricts the output to that unit. Set 'base' to + * -1 to auto-detect a base after which all the values are zero. + * + * 'tzoffset' is used if 'local' is enabled, and 'tzoffset' is + * set to a value other than -1. This is a manual override for + * the local time zone to use, as an offset in minutes. + * + * 'casting' controls whether data loss is allowed by truncating + * the data to a coarser unit. This interacts with 'local', slightly, + * in order to form a date unit string as a local time, the casting + * must be unsafe. + * + * Returns 0 on success, -1 on failure (for example if the output + * string was too short). + */ +NPY_NO_EXPORT int +make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, npy_intp outlen, + int local, int utc, NPY_DATETIMEUNIT base, int tzoffset, + NPY_CASTING casting) +{ + npy_datetimestruct dts_local; + int timezone_offset = 0; + + char *substr = outstr; + npy_intp sublen = outlen; + npy_intp tmplen; + + /* Handle NaT, and treat a datetime with generic units as NaT */ + if (dts->year == NPY_DATETIME_NAT || base == NPY_FR_GENERIC) { + if (outlen < 3) { + goto string_too_short; + } + outstr[0] = 'N'; + outstr[1] = 'a'; + outstr[2] = 'T'; + if (outlen > 3) { + outstr[3] = '\0'; + } + + return 0; + } + + /* + * Only do local time within a reasonable year range. The years + * earlier than 1970 are not made local, because the Windows API + * raises an error when they are attempted (see the comments above the + * get_localtime() function). For consistency, this + * restriction is applied to all platforms. + * + * Note that this only affects how the datetime becomes a string. + * The result is still completely unambiguous, it only means + * that datetimes outside this range will not include a time zone + * when they are printed. + */ + if ((dts->year < 1970 || dts->year >= 10000) && tzoffset == -1) { + local = 0; + } + + /* Automatically detect a good unit */ + if (base == -1) { + base = lossless_unit_from_datetimestruct(dts); + /* + * If there's a timezone, use at least minutes precision, + * and never split up hours and minutes by default + */ + if ((base < NPY_FR_m && local) || base == NPY_FR_h) { + base = NPY_FR_m; + } + /* Don't split up dates by default */ + else if (base < NPY_FR_D) { + base = NPY_FR_D; + } + } + /* + * Print weeks with the same precision as days. + * + * TODO: Could print weeks with YYYY-Www format if the week + * epoch is a Monday. + */ + else if (base == NPY_FR_W) { + base = NPY_FR_D; + } + + /* Use the C API to convert from UTC to local time */ + if (local && tzoffset == -1) { + if (convert_datetimestruct_utc_to_local(&dts_local, dts, + &timezone_offset) < 0) { + return -1; + } + + /* Set dts to point to our local time instead of the UTC time */ + dts = &dts_local; + } + /* Use the manually provided tzoffset */ + else if (local) { + /* Make a copy of the npy_datetimestruct we can modify */ + dts_local = *dts; + dts = &dts_local; + + /* Set and apply the required timezone offset */ + timezone_offset = tzoffset; + add_minutes_to_datetimestruct(dts, timezone_offset); + } + + /* + * Now the datetimestruct data is in the final form for + * the string representation, so ensure that the data + * is being cast according to the casting rule. + */ + if (casting != NPY_UNSAFE_CASTING) { + /* Producing a date as a local time is always 'unsafe' */ + if (base <= NPY_FR_D && local) { + PyErr_SetString(PyExc_TypeError, "Cannot create a local " + "timezone-based date string from a NumPy " + "datetime without forcing 'unsafe' casting"); + return -1; + } + /* Only 'unsafe' and 'same_kind' allow data loss */ + else { + NPY_DATETIMEUNIT unitprec; + + unitprec = lossless_unit_from_datetimestruct(dts); + if (casting != NPY_SAME_KIND_CASTING && unitprec > base) { + PyErr_Format(PyExc_TypeError, "Cannot create a " + "string with unit precision '%s' " + "from the NumPy datetime, which has data at " + "unit precision '%s', " + "requires 'unsafe' or 'same_kind' casting", + _datetime_strings[base], + _datetime_strings[unitprec]); + return -1; + } + } + } + + /* YEAR */ + /* + * Can't use PyOS_snprintf, because it always produces a '\0' + * character at the end, and NumPy string types are permitted + * to have data all the way to the end of the buffer. + */ +#ifdef _WIN32 + tmplen = _snprintf(substr, sublen, "%04" NPY_INT64_FMT, dts->year); +#else + tmplen = snprintf(substr, sublen, "%04" NPY_INT64_FMT, dts->year); +#endif + /* If it ran out of space or there isn't space for the NULL terminator */ + if (tmplen < 0 || tmplen > sublen) { + goto string_too_short; + } + substr += tmplen; + sublen -= tmplen; + + /* Stop if the unit is years */ + if (base == NPY_FR_Y) { + if (sublen > 0) { + *substr = '\0'; + } + return 0; + } + + /* MONTH */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = '-'; + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->month / 10) + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)((dts->month % 10) + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is months */ + if (base == NPY_FR_M) { + if (sublen > 0) { + *substr = '\0'; + } + return 0; + } + + /* DAY */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = '-'; + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->day / 10) + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)((dts->day % 10) + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is days */ + if (base == NPY_FR_D) { + if (sublen > 0) { + *substr = '\0'; + } + return 0; + } + + /* HOUR */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = 'T'; + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->hour / 10) + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)((dts->hour % 10) + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is hours */ + if (base == NPY_FR_h) { + goto add_time_zone; + } + + /* MINUTE */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = ':'; + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->min / 10) + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)((dts->min % 10) + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is minutes */ + if (base == NPY_FR_m) { + goto add_time_zone; + } + + /* SECOND */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = ':'; + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->sec / 10) + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)((dts->sec % 10) + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is seconds */ + if (base == NPY_FR_s) { + goto add_time_zone; + } + + /* MILLISECOND */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = '.'; + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->us / 100000) % 10 + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)((dts->us / 10000) % 10 + '0'); + if (sublen < 4 ) { + goto string_too_short; + } + substr[3] = (char)((dts->us / 1000) % 10 + '0'); + substr += 4; + sublen -= 4; + + /* Stop if the unit is milliseconds */ + if (base == NPY_FR_ms) { + goto add_time_zone; + } + + /* MICROSECOND */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = (char)((dts->us / 100) % 10 + '0'); + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->us / 10) % 10 + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)(dts->us % 10 + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is microseconds */ + if (base == NPY_FR_us) { + goto add_time_zone; + } + + /* NANOSECOND */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = (char)((dts->ps / 100000) % 10 + '0'); + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->ps / 10000) % 10 + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)((dts->ps / 1000) % 10 + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is nanoseconds */ + if (base == NPY_FR_ns) { + goto add_time_zone; + } + + /* PICOSECOND */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = (char)((dts->ps / 100) % 10 + '0'); + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->ps / 10) % 10 + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)(dts->ps % 10 + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is picoseconds */ + if (base == NPY_FR_ps) { + goto add_time_zone; + } + + /* FEMTOSECOND */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = (char)((dts->as / 100000) % 10 + '0'); + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->as / 10000) % 10 + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)((dts->as / 1000) % 10 + '0'); + substr += 3; + sublen -= 3; + + /* Stop if the unit is femtoseconds */ + if (base == NPY_FR_fs) { + goto add_time_zone; + } + + /* ATTOSECOND */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = (char)((dts->as / 100) % 10 + '0'); + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((dts->as / 10) % 10 + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)(dts->as % 10 + '0'); + substr += 3; + sublen -= 3; + +add_time_zone: + if (local) { + /* Add the +/- sign */ + if (sublen < 1) { + goto string_too_short; + } + if (timezone_offset < 0) { + substr[0] = '-'; + timezone_offset = -timezone_offset; + } + else { + substr[0] = '+'; + } + substr += 1; + sublen -= 1; + + /* Add the timezone offset */ + if (sublen < 1 ) { + goto string_too_short; + } + substr[0] = (char)((timezone_offset / (10*60)) % 10 + '0'); + if (sublen < 2 ) { + goto string_too_short; + } + substr[1] = (char)((timezone_offset / 60) % 10 + '0'); + if (sublen < 3 ) { + goto string_too_short; + } + substr[2] = (char)(((timezone_offset % 60) / 10) % 10 + '0'); + if (sublen < 4 ) { + goto string_too_short; + } + substr[3] = (char)((timezone_offset % 60) % 10 + '0'); + substr += 4; + sublen -= 4; + } + /* UTC "Zulu" time */ + else if (utc) { + if (sublen < 1) { + goto string_too_short; + } + substr[0] = 'Z'; + substr += 1; + sublen -= 1; + } + + /* Add a NULL terminator, and return */ + if (sublen > 0) { + substr[0] = '\0'; + } + + return 0; + +string_too_short: + PyErr_Format(PyExc_RuntimeError, + "The string provided for NumPy ISO datetime formatting " + "was too short, with length %"NPY_INTP_FMT, + outlen); + return -1; +} + + +/* + * This is the Python-exposed datetime_as_string function. + */ +NPY_NO_EXPORT PyObject * +array_datetime_as_string(PyObject *NPY_UNUSED(self), PyObject *args, + PyObject *kwds) +{ + PyObject *arr_in = NULL, *unit_in = NULL, *timezone_obj = NULL; + NPY_DATETIMEUNIT unit; + NPY_CASTING casting = NPY_SAME_KIND_CASTING; + + int local = 0; + int utc = 0; + PyArray_DatetimeMetaData *meta; + int strsize; + + PyArrayObject *ret = NULL; + + NpyIter *iter = NULL; + PyArrayObject *op[2] = {NULL, NULL}; + PyArray_Descr *op_dtypes[2] = {NULL, NULL}; + npy_uint32 flags, op_flags[2]; + + static char *kwlist[] = {"arr", "unit", "timezone", "casting", NULL}; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, + "O|OOO&:datetime_as_string", kwlist, + &arr_in, + &unit_in, + &timezone_obj, + &PyArray_CastingConverter, &casting)) { + return NULL; + } + + /* Claim a reference to timezone for later */ + Py_XINCREF(timezone_obj); + + op[0] = (PyArrayObject *)PyArray_FROM_O(arr_in); + if (op[0] == NULL) { + goto fail; + } + if (PyArray_DESCR(op[0])->type_num != NPY_DATETIME) { + PyErr_SetString(PyExc_TypeError, + "input must have type NumPy datetime"); + goto fail; + } + + /* Get the datetime metadata */ + meta = get_datetime_metadata_from_dtype(PyArray_DESCR(op[0])); + if (meta == NULL) { + goto fail; + } + + /* Use the metadata's unit for printing by default */ + unit = meta->base; + + /* Parse the input unit if provided */ + if (unit_in != NULL && unit_in != Py_None) { + PyObject *strobj; + char *str = NULL; + Py_ssize_t len = 0; + + if (PyUnicode_Check(unit_in)) { + strobj = PyUnicode_AsASCIIString(unit_in); + if (strobj == NULL) { + goto fail; + } + } + else { + strobj = unit_in; + Py_INCREF(strobj); + } + + if (PyBytes_AsStringAndSize(strobj, &str, &len) < 0) { + Py_DECREF(strobj); + goto fail; + } + + /* unit == -1 means to autodetect the unit from the datetime data */ + if (strcmp(str, "auto") == 0) { + unit = -1; + } + else { + unit = parse_datetime_unit_from_string(str, len, NULL); + if (unit == -1) { + Py_DECREF(strobj); + goto fail; + } + } + Py_DECREF(strobj); + + if (unit != -1 && !can_cast_datetime64_units(meta->base, unit, casting)) { + PyErr_Format(PyExc_TypeError, "Cannot create a datetime " + "string as units '%s' from a NumPy datetime " + "with units '%s' according to the rule %s", + _datetime_strings[unit], + _datetime_strings[meta->base], + npy_casting_to_string(casting)); + goto fail; + } + } + + /* Get the input time zone */ + if (timezone_obj != NULL) { + /* Convert to ASCII if it's unicode */ + if (PyUnicode_Check(timezone_obj)) { + /* accept unicode input */ + PyObject *obj_str; + obj_str = PyUnicode_AsASCIIString(timezone_obj); + if (obj_str == NULL) { + goto fail; + } + Py_DECREF(timezone_obj); + timezone_obj = obj_str; + } + + /* Check for the supported string inputs */ + if (PyBytes_Check(timezone_obj)) { + char *str; + Py_ssize_t len; + + if (PyBytes_AsStringAndSize(timezone_obj, &str, &len) < 0) { + goto fail; + } + + if (strcmp(str, "local") == 0) { + local = 1; + utc = 0; + Py_DECREF(timezone_obj); + timezone_obj = NULL; + } + else if (strcmp(str, "UTC") == 0) { + local = 0; + utc = 1; + Py_DECREF(timezone_obj); + timezone_obj = NULL; + } + else if (strcmp(str, "naive") == 0) { + local = 0; + utc = 0; + Py_DECREF(timezone_obj); + timezone_obj = NULL; + } + else { + PyErr_Format(PyExc_ValueError, "Unsupported timezone " + "input string \"%s\"", str); + goto fail; + } + } + /* Otherwise assume it's a Python TZInfo, or acts like one */ + else { + local = 1; + } + } + + /* Get a string size long enough for any datetimes we're given */ + strsize = get_datetime_iso_8601_strlen(local, unit); +#if defined(NPY_PY3K) + /* + * For Python3, allocate the output array as a UNICODE array, so + * that it will behave as strings properly + */ + op_dtypes[1] = PyArray_DescrNewFromType(NPY_UNICODE); + if (op_dtypes[1] == NULL) { + goto fail; + } + op_dtypes[1]->elsize = strsize * 4; + /* This steals the UNICODE dtype reference in op_dtypes[1] */ + op[1] = (PyArrayObject *)PyArray_NewLikeArray(op[0], + NPY_KEEPORDER, op_dtypes[1], 1); + if (op[1] == NULL) { + op_dtypes[1] = NULL; + goto fail; + } +#endif + /* Create the iteration string data type (always ASCII string) */ + op_dtypes[1] = PyArray_DescrNewFromType(NPY_STRING); + if (op_dtypes[1] == NULL) { + goto fail; + } + op_dtypes[1]->elsize = strsize; + + flags = NPY_ITER_ZEROSIZE_OK| + NPY_ITER_BUFFERED; + op_flags[0] = NPY_ITER_READONLY| + NPY_ITER_ALIGNED; + op_flags[1] = NPY_ITER_WRITEONLY| + NPY_ITER_ALLOCATE; + + iter = NpyIter_MultiNew(2, op, flags, NPY_KEEPORDER, NPY_UNSAFE_CASTING, + op_flags, op_dtypes); + if (iter == NULL) { + goto fail; + } + + if (NpyIter_GetIterSize(iter) != 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_datetime dt; + npy_datetimestruct dts; + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + + do { + int tzoffset = -1; + + /* Get the datetime */ + dt = *(npy_datetime *)dataptr[0]; + + /* Convert it to a struct */ + if (convert_datetime_to_datetimestruct(meta, dt, &dts) < 0) { + goto fail; + } + + /* Get the tzoffset from the timezone if provided */ + if (local && timezone_obj != NULL) { + tzoffset = get_tzoffset_from_pytzinfo(timezone_obj, &dts); + if (tzoffset == -1) { + goto fail; + } + } + + /* Zero the destination string completely */ + memset(dataptr[1], 0, strsize); + /* Convert that into a string */ + if (make_iso_8601_datetime(&dts, (char *)dataptr[1], strsize, + local, utc, unit, tzoffset, casting) < 0) { + goto fail; + } + } while(iternext(iter)); + } + + ret = NpyIter_GetOperandArray(iter)[1]; + Py_INCREF(ret); + + Py_XDECREF(timezone_obj); + Py_XDECREF(op[0]); + Py_XDECREF(op[1]); + Py_XDECREF(op_dtypes[0]); + Py_XDECREF(op_dtypes[1]); + if (iter != NULL) { + NpyIter_Deallocate(iter); + } + + return PyArray_Return(ret); + +fail: + Py_XDECREF(timezone_obj); + Py_XDECREF(op[0]); + Py_XDECREF(op[1]); + Py_XDECREF(op_dtypes[0]); + Py_XDECREF(op_dtypes[1]); + if (iter != NULL) { + NpyIter_Deallocate(iter); + } + + return NULL; +} diff --git a/numpy/core/src/multiarray/datetime_strings.h b/numpy/core/src/multiarray/datetime_strings.h new file mode 100644 index 0000000..4e60ce9 --- /dev/null +++ b/numpy/core/src/multiarray/datetime_strings.h @@ -0,0 +1,84 @@ +#ifndef _NPY_PRIVATE__DATETIME_STRINGS_H_ +#define _NPY_PRIVATE__DATETIME_STRINGS_H_ + +/* + * Parses (almost) standard ISO 8601 date strings. The differences are: + * + * + The date "20100312" is parsed as the year 20100312, not as + * equivalent to "2010-03-12". The '-' in the dates are not optional. + * + Only seconds may have a decimal point, with up to 18 digits after it + * (maximum attoseconds precision). + * + Either a 'T' as in ISO 8601 or a ' ' may be used to separate + * the date and the time. Both are treated equivalently. + * + Doesn't (yet) handle the "YYYY-DDD" or "YYYY-Www" formats. + * + Doesn't handle leap seconds (seconds value has 60 in these cases). + * + Doesn't handle 24:00:00 as synonym for midnight (00:00:00) tomorrow + * + Accepts special values "NaT" (not a time), "Today", (current + * day according to local time) and "Now" (current time in UTC). + * + * 'str' must be a NULL-terminated string, and 'len' must be its length. + * 'unit' should contain -1 if the unit is unknown, or the unit + * which will be used if it is. + * 'casting' controls how the detected unit from the string is allowed + * to be cast to the 'unit' parameter. + * + * 'out' gets filled with the parsed date-time. + * 'out_bestunit' gives a suggested unit based on the amount of + * resolution provided in the string, or -1 for NaT. + * 'out_special' gets set to 1 if the parsed time was 'today', + * 'now', or ''/'NaT'. For 'today', the unit recommended is + * 'D', for 'now', the unit recommended is 's', and for 'NaT' + * the unit recommended is 'Y'. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +parse_iso_8601_datetime(char *str, Py_ssize_t len, + NPY_DATETIMEUNIT unit, + NPY_CASTING casting, + npy_datetimestruct *out, + NPY_DATETIMEUNIT *out_bestunit, + npy_bool *out_special); + +/* + * Provides a string length to use for converting datetime + * objects with the given local and unit settings. + */ +NPY_NO_EXPORT int +get_datetime_iso_8601_strlen(int local, NPY_DATETIMEUNIT base); + +/* + * Converts an npy_datetimestruct to an (almost) ISO 8601 + * NULL-terminated string. + * + * If 'local' is non-zero, it produces a string in local time with + * a +-#### timezone offset, otherwise it uses timezone Z (UTC). + * + * 'base' restricts the output to that unit. Set 'base' to + * -1 to auto-detect a base after which all the values are zero. + * + * 'tzoffset' is used if 'local' is enabled, and 'tzoffset' is + * set to a value other than -1. This is a manual override for + * the local time zone to use, as an offset in minutes. + * + * 'casting' controls whether data loss is allowed by truncating + * the data to a coarser unit. This interacts with 'local', slightly, + * in order to form a date unit string as a local time, the casting + * must be unsafe. + * + * Returns 0 on success, -1 on failure (for example if the output + * string was too short). + */ +NPY_NO_EXPORT int +make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, npy_intp outlen, + int local, int utc, NPY_DATETIMEUNIT base, int tzoffset, + NPY_CASTING casting); + +/* + * This is the Python-exposed datetime_as_string function. + */ +NPY_NO_EXPORT PyObject * +array_datetime_as_string(PyObject *NPY_UNUSED(self), PyObject *args, + PyObject *kwds); + +#endif diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c new file mode 100644 index 0000000..b4a0ce3 --- /dev/null +++ b/numpy/core/src/multiarray/descriptor.c @@ -0,0 +1,3905 @@ +/* Array Descr Object */ + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "_datetime.h" +#include "common.h" +#include "templ_common.h" /* for npy_mul_with_overflow_intp */ +#include "descriptor.h" +#include "alloc.h" + +/* + * offset: A starting offset. + * alignment: A power-of-two alignment. + * + * This macro returns the smallest value >= 'offset' + * that is divisible by 'alignment'. Because 'alignment' + * is a power of two and integers are twos-complement, + * it is possible to use some simple bit-fiddling to do this. + */ +#define NPY_NEXT_ALIGNED_OFFSET(offset, alignment) \ + (((offset) + (alignment) - 1) & (-(alignment))) + +#ifndef PyDictProxy_Check +#define PyDictProxy_Check(obj) (Py_TYPE(obj) == &PyDictProxy_Type) +#endif + +static PyObject *typeDict = NULL; /* Must be explicitly loaded */ + +static PyArray_Descr * +_use_inherit(PyArray_Descr *type, PyObject *newobj, int *errflag); + + +/* + * Returns value of PyMapping_GetItemString but as a borrowed reference instead + * of a new reference. + */ +static PyObject * +Borrowed_PyMapping_GetItemString(PyObject *o, char *key) +{ + PyObject *ret = PyMapping_GetItemString(o, key); + Py_XDECREF(ret); + return ret; +} + +/* + * Creates a dtype object from ctypes inputs. + * + * Returns a new reference to a dtype object, or NULL + * if this is not possible. When it returns NULL, it does + * not set a Python exception. + */ +static PyArray_Descr * +_arraydescr_fromctypes(PyObject *obj) +{ + PyObject *dtypedescr; + PyArray_Descr *newdescr; + int ret; + + /* Understand basic ctypes */ + dtypedescr = PyObject_GetAttrString(obj, "_type_"); + PyErr_Clear(); + if (dtypedescr) { + ret = PyArray_DescrConverter(dtypedescr, &newdescr); + Py_DECREF(dtypedescr); + if (ret == NPY_SUCCEED) { + PyObject *length; + /* Check for ctypes arrays */ + length = PyObject_GetAttrString(obj, "_length_"); + PyErr_Clear(); + if (length) { + /* derived type */ + PyObject *newtup; + PyArray_Descr *derived; + newtup = Py_BuildValue("NN", newdescr, length); + ret = PyArray_DescrConverter(newtup, &derived); + Py_DECREF(newtup); + if (ret == NPY_SUCCEED) { + return derived; + } + PyErr_Clear(); + return NULL; + } + return newdescr; + } + PyErr_Clear(); + return NULL; + } + /* Understand ctypes structures -- + bit-fields are not supported + automatically aligns */ + dtypedescr = PyObject_GetAttrString(obj, "_fields_"); + PyErr_Clear(); + if (dtypedescr) { + ret = PyArray_DescrAlignConverter(dtypedescr, &newdescr); + Py_DECREF(dtypedescr); + if (ret == NPY_SUCCEED) { + return newdescr; + } + PyErr_Clear(); + } + + return NULL; +} + +/* + * This function creates a dtype object when: + * - The object has a "dtype" attribute, and it can be converted + * to a dtype object. + * - The object is a ctypes type object, including array + * and structure types. + * + * Returns a new reference to a dtype object, or NULL + * if this is not possible. When it returns NULL, it does + * not set a Python exception. + */ +NPY_NO_EXPORT PyArray_Descr * +_arraydescr_fromobj(PyObject *obj) +{ + PyObject *dtypedescr; + PyArray_Descr *newdescr = NULL; + int ret; + + /* For arbitrary objects that have a "dtype" attribute */ + dtypedescr = PyObject_GetAttrString(obj, "dtype"); + PyErr_Clear(); + if (dtypedescr != NULL) { + ret = PyArray_DescrConverter(dtypedescr, &newdescr); + Py_DECREF(dtypedescr); + if (ret == NPY_SUCCEED) { + return newdescr; + } + PyErr_Clear(); + } + return _arraydescr_fromctypes(obj); +} + +/* + * Sets the global typeDict object, which is a dictionary mapping + * dtype names to numpy scalar types. + */ +NPY_NO_EXPORT PyObject * +array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args) +{ + PyObject *dict; + + if (!PyArg_ParseTuple(args, "O:set_typeDict", &dict)) { + return NULL; + } + /* Decrement old reference (if any)*/ + Py_XDECREF(typeDict); + typeDict = dict; + /* Create an internal reference to it */ + Py_INCREF(dict); + Py_RETURN_NONE; +} + +#define _chk_byteorder(arg) (arg == '>' || arg == '<' || \ + arg == '|' || arg == '=') + +static int +_check_for_commastring(char *type, Py_ssize_t len) +{ + Py_ssize_t i; + int sqbracket; + + /* Check for ints at start of string */ + if ((type[0] >= '0' + && type[0] <= '9') + || ((len > 1) + && _chk_byteorder(type[0]) + && (type[1] >= '0' + && type[1] <= '9'))) { + return 1; + } + /* Check for empty tuple */ + if (((len > 1) + && (type[0] == '(' + && type[1] == ')')) + || ((len > 3) + && _chk_byteorder(type[0]) + && (type[1] == '(' + && type[2] == ')'))) { + return 1; + } + /* + * Check for presence of commas outside square [] brackets. This + * allows commas inside of [], for parameterized dtypes to use. + */ + sqbracket = 0; + for (i = 0; i < len; i++) { + switch (type[i]) { + case ',': + if (sqbracket == 0) { + return 1; + } + break; + case '[': + ++sqbracket; + break; + case ']': + --sqbracket; + break; + } + } + return 0; +} + +#undef _chk_byteorder + +static int +is_datetime_typestr(char *type, Py_ssize_t len) +{ + if (len < 2) { + return 0; + } + if (type[1] == '8' && (type[0] == 'M' || type[0] == 'm')) { + return 1; + } + if (len < 10) { + return 0; + } + if (strncmp(type, "datetime64", 10) == 0) { + return 1; + } + if (len < 11) { + return 0; + } + if (strncmp(type, "timedelta64", 11) == 0) { + return 1; + } + return 0; +} + +static PyArray_Descr * +_convert_from_tuple(PyObject *obj) +{ + PyArray_Descr *type, *res; + PyObject *val; + int errflag; + + if (PyTuple_GET_SIZE(obj) != 2) { + return NULL; + } + if (!PyArray_DescrConverter(PyTuple_GET_ITEM(obj,0), &type)) { + return NULL; + } + val = PyTuple_GET_ITEM(obj,1); + /* try to interpret next item as a type */ + res = _use_inherit(type, val, &errflag); + if (res || errflag) { + Py_DECREF(type); + return res; + } + PyErr_Clear(); + /* + * We get here if res was NULL but errflag wasn't set + * --- i.e. the conversion to a data-descr failed in _use_inherit + */ + if (PyDataType_ISUNSIZED(type)) { + /* interpret next item as a typesize */ + int itemsize = PyArray_PyIntAsInt(PyTuple_GET_ITEM(obj,1)); + + if (error_converting(itemsize)) { + PyErr_SetString(PyExc_ValueError, + "invalid itemsize in generic type tuple"); + Py_DECREF(type); + return NULL; + } + PyArray_DESCR_REPLACE(type); + if (type->type_num == NPY_UNICODE) { + type->elsize = itemsize << 2; + } + else { + type->elsize = itemsize; + } + return type; + } + else if (type->metadata && (PyDict_Check(val) || PyDictProxy_Check(val))) { + /* Assume it's a metadata dictionary */ + if (PyDict_Merge(type->metadata, val, 0) == -1) { + Py_DECREF(type); + return NULL; + } + return type; + } + else { + /* + * interpret next item as shape (if it's a tuple) + * and reset the type to NPY_VOID with + * a new fields attribute. + */ + PyArray_Dims shape = {NULL, -1}; + PyArray_Descr *newdescr = NULL; + npy_intp items; + int i, overflowed; + int nbytes; + + if (!(PyArray_IntpConverter(val, &shape)) || (shape.len > NPY_MAXDIMS)) { + PyErr_SetString(PyExc_ValueError, + "invalid shape in fixed-type tuple."); + goto fail; + } + /* + * If (type, 1) was given, it is equivalent to type... + * or (type, ()) was given it is equivalent to type... + */ + if ((shape.len == 1 + && shape.ptr[0] == 1 + && PyNumber_Check(val)) + || (shape.len == 0 + && PyTuple_Check(val))) { + npy_free_cache_dim_obj(shape); + return type; + } + + /* validate and set shape */ + for (i=0; i < shape.len; i++) { + if (shape.ptr[i] < 0) { + PyErr_SetString(PyExc_ValueError, + "invalid shape in fixed-type tuple: " + "dimension smaller then zero."); + goto fail; + } + if (shape.ptr[i] > NPY_MAX_INT) { + PyErr_SetString(PyExc_ValueError, + "invalid shape in fixed-type tuple: " + "dimension does not fit into a C int."); + goto fail; + } + } + items = PyArray_OverflowMultiplyList(shape.ptr, shape.len); + if (items < 0 || items > NPY_MAX_INT) { + overflowed = 1; + } + else { + overflowed = npy_mul_with_overflow_int( + &nbytes, type->elsize, (int) items); + } + if (overflowed) { + PyErr_SetString(PyExc_ValueError, + "invalid shape in fixed-type tuple: dtype size in " + "bytes must fit into a C int."); + goto fail; + } + newdescr = PyArray_DescrNewFromType(NPY_VOID); + if (newdescr == NULL) { + goto fail; + } + newdescr->elsize = nbytes; + newdescr->subarray = PyArray_malloc(sizeof(PyArray_ArrayDescr)); + if (newdescr->subarray == NULL) { + PyErr_NoMemory(); + goto fail; + } + newdescr->flags = type->flags; + newdescr->alignment = type->alignment; + newdescr->subarray->base = type; + type = NULL; + Py_XDECREF(newdescr->fields); + Py_XDECREF(newdescr->names); + newdescr->fields = NULL; + newdescr->names = NULL; + + /* + * Create a new subarray->shape tuple (it can be an arbitrary + * sequence of integer like objects, neither of which is safe. + */ + newdescr->subarray->shape = PyTuple_New(shape.len); + if (newdescr->subarray->shape == NULL) { + goto fail; + } + for (i=0; i < shape.len; i++) { + PyTuple_SET_ITEM(newdescr->subarray->shape, i, + PyInt_FromLong((long)shape.ptr[i])); + + if (PyTuple_GET_ITEM(newdescr->subarray->shape, i) == NULL) { + goto fail; + } + } + + npy_free_cache_dim_obj(shape); + return newdescr; + + fail: + Py_XDECREF(type); + Py_XDECREF(newdescr); + npy_free_cache_dim_obj(shape); + return NULL; + } +} + +/* + * obj is a list. Each item is a tuple with + * + * (field-name, data-type (either a list or a string), and an optional + * shape parameter). + * + * field-name can be a string or a 2-tuple + * data-type can now be a list, string, or 2-tuple + * (string, metadata dictionary) + */ +static PyArray_Descr * +_convert_from_array_descr(PyObject *obj, int align) +{ + int n, i, totalsize; + int ret; + PyObject *fields, *item, *newobj; + PyObject *name, *tup, *title; + PyObject *nameslist; + PyArray_Descr *new; + PyArray_Descr *conv; + /* Types with fields need the Python C API for field access */ + char dtypeflags = NPY_NEEDS_PYAPI; + int maxalign = 0; + + n = PyList_GET_SIZE(obj); + nameslist = PyTuple_New(n); + if (!nameslist) { + return NULL; + } + totalsize = 0; + fields = PyDict_New(); + for (i = 0; i < n; i++) { + item = PyList_GET_ITEM(obj, i); + if (!PyTuple_Check(item) || (PyTuple_GET_SIZE(item) < 2)) { + goto fail; + } + name = PyTuple_GET_ITEM(item, 0); + if (PyUString_Check(name)) { + title = NULL; + } + else if (PyTuple_Check(name)) { + if (PyTuple_GET_SIZE(name) != 2) { + goto fail; + } + title = PyTuple_GET_ITEM(name, 0); + name = PyTuple_GET_ITEM(name, 1); + if (!PyUString_Check(name)) { + goto fail; + } + } + else { + goto fail; + } + + /* Insert name into nameslist */ + Py_INCREF(name); + + if (PyUString_GET_SIZE(name) == 0) { + Py_DECREF(name); + if (title == NULL) { + name = PyUString_FromFormat("f%d", i); + } +#if defined(NPY_PY3K) + /* On Py3, allow only non-empty Unicode strings as field names */ + else if (PyUString_Check(title) && PyUString_GET_SIZE(title) > 0) { + name = title; + Py_INCREF(name); + } + else { + goto fail; + } +#else + else { + name = title; + Py_INCREF(name); + } +#endif + } + PyTuple_SET_ITEM(nameslist, i, name); + + /* Process rest */ + + if (PyTuple_GET_SIZE(item) == 2) { + if (align) { + ret = PyArray_DescrAlignConverter(PyTuple_GET_ITEM(item, 1), + &conv); + } + else { + ret = PyArray_DescrConverter(PyTuple_GET_ITEM(item, 1), &conv); + } + if (ret == NPY_FAIL) { + PyObject_Print(PyTuple_GET_ITEM(item, 1), stderr, 0); + } + } + else if (PyTuple_GET_SIZE(item) == 3) { + newobj = PyTuple_GetSlice(item, 1, 3); + if (align) { + ret = PyArray_DescrAlignConverter(newobj, &conv); + } + else { + ret = PyArray_DescrConverter(newobj, &conv); + } + Py_DECREF(newobj); + } + else { + goto fail; + } + if (ret == NPY_FAIL) { + goto fail; + } + if ((PyDict_GetItem(fields, name) != NULL) + || (title + && PyBaseString_Check(title) + && (PyDict_GetItem(fields, title) != NULL))) { +#if defined(NPY_PY3K) + name = PyUnicode_AsUTF8String(name); +#endif + PyErr_Format(PyExc_ValueError, + "field '%s' occurs more than once", PyString_AsString(name)); +#if defined(NPY_PY3K) + Py_DECREF(name); +#endif + goto fail; + } + dtypeflags |= (conv->flags & NPY_FROM_FIELDS); + if (align) { + int _align; + + _align = conv->alignment; + if (_align > 1) { + totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, _align); + } + maxalign = PyArray_MAX(maxalign, _align); + } + tup = PyTuple_New((title == NULL ? 2 : 3)); + PyTuple_SET_ITEM(tup, 0, (PyObject *)conv); + PyTuple_SET_ITEM(tup, 1, PyInt_FromLong((long) totalsize)); + + /* + * Title can be "meta-data". Only insert it + * into the fields dictionary if it is a string + * and if it is not the same as the name. + */ + if (title != NULL) { + Py_INCREF(title); + PyTuple_SET_ITEM(tup, 2, title); + PyDict_SetItem(fields, name, tup); + if (PyBaseString_Check(title)) { + if (PyDict_GetItem(fields, title) != NULL) { + PyErr_SetString(PyExc_ValueError, + "title already used as a name or title."); + Py_DECREF(tup); + goto fail; + } + PyDict_SetItem(fields, title, tup); + } + } + else { + PyDict_SetItem(fields, name, tup); + } + + totalsize += conv->elsize; + Py_DECREF(tup); + } + + if (maxalign > 1) { + totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign); + } + + new = PyArray_DescrNewFromType(NPY_VOID); + if (new == NULL) { + Py_XDECREF(fields); + Py_XDECREF(nameslist); + return NULL; + } + new->fields = fields; + new->names = nameslist; + new->elsize = totalsize; + new->flags = dtypeflags; + + /* Structured arrays get a sticky aligned bit */ + if (align) { + new->flags |= NPY_ALIGNED_STRUCT; + new->alignment = maxalign; + } + return new; + + fail: + Py_DECREF(fields); + Py_DECREF(nameslist); + return NULL; + +} + +/* + * a list specifying a data-type can just be + * a list of formats. The names for the fields + * will default to f0, f1, f2, and so forth. + */ +static PyArray_Descr * +_convert_from_list(PyObject *obj, int align) +{ + int n, i; + int totalsize; + PyObject *fields; + PyArray_Descr *conv = NULL; + PyArray_Descr *new; + PyObject *key, *tup; + PyObject *nameslist = NULL; + int ret; + int maxalign = 0; + /* Types with fields need the Python C API for field access */ + char dtypeflags = NPY_NEEDS_PYAPI; + + n = PyList_GET_SIZE(obj); + /* + * Ignore any empty string at end which _internal._commastring + * can produce + */ + key = PyList_GET_ITEM(obj, n-1); + if (PyBytes_Check(key) && PyBytes_GET_SIZE(key) == 0) { + n = n - 1; + } + /* End ignore code.*/ + totalsize = 0; + if (n == 0) { + return NULL; + } + nameslist = PyTuple_New(n); + if (!nameslist) { + return NULL; + } + fields = PyDict_New(); + for (i = 0; i < n; i++) { + tup = PyTuple_New(2); + key = PyUString_FromFormat("f%d", i); + if (align) { + ret = PyArray_DescrAlignConverter(PyList_GET_ITEM(obj, i), &conv); + } + else { + ret = PyArray_DescrConverter(PyList_GET_ITEM(obj, i), &conv); + } + if (ret == NPY_FAIL) { + Py_DECREF(tup); + Py_DECREF(key); + goto fail; + } + dtypeflags |= (conv->flags & NPY_FROM_FIELDS); + PyTuple_SET_ITEM(tup, 0, (PyObject *)conv); + if (align) { + int _align; + + _align = conv->alignment; + if (_align > 1) { + totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, _align); + } + maxalign = PyArray_MAX(maxalign, _align); + } + PyTuple_SET_ITEM(tup, 1, PyInt_FromLong((long) totalsize)); + PyDict_SetItem(fields, key, tup); + Py_DECREF(tup); + PyTuple_SET_ITEM(nameslist, i, key); + totalsize += conv->elsize; + } + new = PyArray_DescrNewFromType(NPY_VOID); + new->fields = fields; + new->names = nameslist; + new->flags = dtypeflags; + if (maxalign > 1) { + totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign); + } + /* Structured arrays get a sticky aligned bit */ + if (align) { + new->flags |= NPY_ALIGNED_STRUCT; + new->alignment = maxalign; + } + new->elsize = totalsize; + return new; + + fail: + Py_DECREF(nameslist); + Py_DECREF(fields); + return NULL; +} + + +/* + * comma-separated string + * this is the format developed by the numarray records module and implemented + * by the format parser in that module this is an alternative implementation + * found in the _internal.py file patterned after that one -- the approach is + * to try to convert to a list (with tuples if any repeat information is + * present) and then call the _convert_from_list) + * + * TODO: Calling Python from C like this in critical-path code is not + * a good idea. This should all be converted to C code. + */ +static PyArray_Descr * +_convert_from_commastring(PyObject *obj, int align) +{ + PyObject *listobj; + PyArray_Descr *res; + PyObject *_numpy_internal; + + if (!PyBytes_Check(obj)) { + return NULL; + } + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + listobj = PyObject_CallMethod(_numpy_internal, "_commastring", "O", obj); + Py_DECREF(_numpy_internal); + if (listobj == NULL) { + return NULL; + } + if (!PyList_Check(listobj) || PyList_GET_SIZE(listobj) < 1) { + PyErr_SetString(PyExc_RuntimeError, + "_commastring is not returning a list with len >= 1"); + Py_DECREF(listobj); + return NULL; + } + if (PyList_GET_SIZE(listobj) == 1) { + int retcode; + retcode = PyArray_DescrConverter(PyList_GET_ITEM(listobj, 0), + &res); + if (retcode == NPY_FAIL) { + res = NULL; + } + } + else { + res = _convert_from_list(listobj, align); + } + Py_DECREF(listobj); + if (!res && !PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "invalid data-type"); + return NULL; + } + return res; +} + +static int +_is_tuple_of_integers(PyObject *obj) +{ + int i; + + if (!PyTuple_Check(obj)) { + return 0; + } + for (i = 0; i < PyTuple_GET_SIZE(obj); i++) { + if (!PyArray_IsIntegerScalar(PyTuple_GET_ITEM(obj, i))) { + return 0; + } + } + return 1; +} + +/* + * helper function for _use_inherit to disallow dtypes of the form + * (old_dtype, new_dtype) where either of the dtypes contains python + * objects - these dtypes are not useful and can be a source of segfaults, + * when an attempt is made to interpret a python object as a different dtype + * or vice versa + * an exception is made for dtypes of the form ('O', [('name', 'O')]), which + * people have been using to add a field to an object array without fields + */ +static int +invalid_union_object_dtype(PyArray_Descr *new, PyArray_Descr *conv) +{ + PyObject *name, *tup; + PyArray_Descr *dtype; + + if (!PyDataType_REFCHK(new) && !PyDataType_REFCHK(conv)) { + return 0; + } + if (PyDataType_HASFIELDS(new) || new->kind != 'O') { + goto fail; + } + if (!PyDataType_HASFIELDS(conv) || PyTuple_GET_SIZE(conv->names) != 1) { + goto fail; + } + name = PyTuple_GET_ITEM(conv->names, 0); + if (name == NULL) { + return -1; + } + tup = PyDict_GetItem(conv->fields, name); + if (tup == NULL) { + return -1; + } + dtype = (PyArray_Descr *)PyTuple_GET_ITEM(tup, 0); + if (dtype == NULL) { + return -1; + } + if (dtype->kind != 'O') { + goto fail; + } + return 0; + +fail: + PyErr_SetString(PyExc_ValueError, + "dtypes of the form (old_dtype, new_dtype) containing the object " + "dtype are not supported"); + return -1; +} + +/* + * A tuple type would be either (generic typeobject, typesize) + * or (fixed-length data-type, shape) + * + * or (inheriting data-type, new-data-type) + * The new data-type must have the same itemsize as the inheriting data-type + * unless the latter is 0 + * + * Thus (int32, {'real':(int16,0),'imag',(int16,2)}) + * + * is one way to specify a descriptor that will give + * a['real'] and a['imag'] to an int32 array. + * + * leave type reference alone + */ +static PyArray_Descr * +_use_inherit(PyArray_Descr *type, PyObject *newobj, int *errflag) +{ + PyArray_Descr *new; + PyArray_Descr *conv; + + *errflag = 0; + if (PyArray_IsScalar(newobj, Integer) + || _is_tuple_of_integers(newobj) + || !PyArray_DescrConverter(newobj, &conv)) { + return NULL; + } + *errflag = 1; + new = PyArray_DescrNew(type); + if (new == NULL) { + goto fail; + } + if (PyDataType_ISUNSIZED(new)) { + new->elsize = conv->elsize; + } + else if (new->elsize != conv->elsize) { + PyErr_SetString(PyExc_ValueError, + "mismatch in size of old and new data-descriptor"); + goto fail; + } + else if (invalid_union_object_dtype(new, conv)) { + goto fail; + } + + if (PyDataType_HASFIELDS(conv)) { + Py_XDECREF(new->fields); + new->fields = conv->fields; + Py_XINCREF(new->fields); + + Py_XDECREF(new->names); + new->names = conv->names; + Py_XINCREF(new->names); + } + if (conv->metadata != NULL) { + Py_XDECREF(new->metadata); + new->metadata = conv->metadata; + Py_XINCREF(new->metadata); + } + new->flags = conv->flags; + Py_DECREF(conv); + *errflag = 0; + return new; + + fail: + Py_DECREF(conv); + return NULL; +} + +/* + * Validates that any field of the structured array 'dtype' which has + * the NPY_ITEM_HASOBJECT flag set does not overlap with another field. + * + * This algorithm is worst case O(n^2). It could be done with a sort + * and sweep algorithm, but the structured dtype representation is + * rather ugly right now, so writing something better can wait until + * that representation is made sane. + * + * Returns 0 on success, -1 if an exception is raised. + */ +static int +validate_object_field_overlap(PyArray_Descr *dtype) +{ + PyObject *names, *fields, *key, *tup, *title; + Py_ssize_t i, j, names_size; + PyArray_Descr *fld_dtype, *fld2_dtype; + int fld_offset, fld2_offset; + + /* Get some properties from the dtype */ + names = dtype->names; + names_size = PyTuple_GET_SIZE(names); + fields = dtype->fields; + + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + if (key == NULL) { + return -1; + } + tup = PyDict_GetItem(fields, key); + if (tup == NULL) { + return -1; + } + if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) { + return -1; + } + + /* If this field has objects, check for overlaps */ + if (PyDataType_REFCHK(fld_dtype)) { + for (j = 0; j < names_size; ++j) { + if (i != j) { + key = PyTuple_GET_ITEM(names, j); + if (key == NULL) { + return -1; + } + tup = PyDict_GetItem(fields, key); + if (tup == NULL) { + return -1; + } + if (!PyArg_ParseTuple(tup, "Oi|O", &fld2_dtype, + &fld2_offset, &title)) { + return -1; + } + /* Raise an exception if it overlaps */ + if (fld_offset < fld2_offset + fld2_dtype->elsize && + fld2_offset < fld_offset + fld_dtype->elsize) { + PyErr_SetString(PyExc_TypeError, + "Cannot create a NumPy dtype with overlapping " + "object fields"); + return -1; + } + } + } + } + } + + /* It passed all the overlap tests */ + return 0; +} + +/* + * a dictionary specifying a data-type + * must have at least two and up to four + * keys These must all be sequences of the same length. + * + * can also have an additional key called "metadata" which can be any dictionary + * + * "names" --- field names + * "formats" --- the data-type descriptors for the field. + * + * Optional: + * + * "offsets" --- integers indicating the offset into the + * record of the start of the field. + * if not given, then "consecutive offsets" + * will be assumed and placed in the dictionary. + * + * "titles" --- Allows the use of an additional key + * for the fields dictionary.(if these are strings + * or unicode objects) or + * this can also be meta-data to + * be passed around with the field description. + * + * Attribute-lookup-based field names merely has to query the fields + * dictionary of the data-descriptor. Any result present can be used + * to return the correct field. + * + * So, the notion of what is a name and what is a title is really quite + * arbitrary. + * + * What does distinguish a title, however, is that if it is not None, + * it will be placed at the end of the tuple inserted into the + * fields dictionary.and can therefore be used to carry meta-data around. + * + * If the dictionary does not have "names" and "formats" entries, + * then it will be checked for conformity and used directly. + */ +static PyArray_Descr * +_use_fields_dict(PyObject *obj, int align) +{ + PyObject *_numpy_internal; + PyArray_Descr *res; + + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + res = (PyArray_Descr *)PyObject_CallMethod(_numpy_internal, + "_usefields", "Oi", obj, align); + Py_DECREF(_numpy_internal); + return res; +} + +/* + * Creates a struct dtype object from a Python dictionary. + */ +static PyArray_Descr * +_convert_from_dict(PyObject *obj, int align) +{ + PyArray_Descr *new; + PyObject *fields = NULL; + PyObject *names, *offsets, *descrs, *titles, *tmp; + PyObject *metadata; + int n, i; + int totalsize, itemsize; + int maxalign = 0; + /* Types with fields need the Python C API for field access */ + char dtypeflags = NPY_NEEDS_PYAPI; + int has_out_of_order_fields = 0; + + fields = PyDict_New(); + if (fields == NULL) { + return (PyArray_Descr *)PyErr_NoMemory(); + } + /* + * Use PyMapping_GetItemString to support dictproxy objects as well. + */ + names = Borrowed_PyMapping_GetItemString(obj, "names"); + descrs = Borrowed_PyMapping_GetItemString(obj, "formats"); + if (!names || !descrs) { + Py_DECREF(fields); + PyErr_Clear(); + return _use_fields_dict(obj, align); + } + n = PyObject_Length(names); + offsets = Borrowed_PyMapping_GetItemString(obj, "offsets"); + if (!offsets) { + PyErr_Clear(); + } + titles = Borrowed_PyMapping_GetItemString(obj, "titles"); + if (!titles) { + PyErr_Clear(); + } + + if ((n > PyObject_Length(descrs)) + || (offsets && (n > PyObject_Length(offsets))) + || (titles && (n > PyObject_Length(titles)))) { + PyErr_SetString(PyExc_ValueError, + "'names', 'formats', 'offsets', and 'titles' dict " + "entries must have the same length"); + goto fail; + } + + /* + * If a property 'aligned' is in the dict, it overrides the align flag + * to be True if it not already true. + */ + tmp = Borrowed_PyMapping_GetItemString(obj, "aligned"); + if (tmp == NULL) { + PyErr_Clear(); + } else { + if (tmp == Py_True) { + align = 1; + } + else if (tmp != Py_False) { + PyErr_SetString(PyExc_ValueError, + "NumPy dtype descriptor includes 'aligned' entry, " + "but its value is neither True nor False"); + return NULL; + } + } + + totalsize = 0; + for (i = 0; i < n; i++) { + PyObject *tup, *descr, *ind, *title, *name, *off; + int len, ret, _align = 1; + PyArray_Descr *newdescr; + + /* Build item to insert (descr, offset, [title])*/ + len = 2; + title = NULL; + ind = PyInt_FromLong(i); + if (titles) { + title=PyObject_GetItem(titles, ind); + if (title && title != Py_None) { + len = 3; + } + else { + Py_XDECREF(title); + } + PyErr_Clear(); + } + tup = PyTuple_New(len); + descr = PyObject_GetItem(descrs, ind); + if (!descr) { + Py_DECREF(tup); + Py_DECREF(ind); + goto fail; + } + if (align) { + ret = PyArray_DescrAlignConverter(descr, &newdescr); + } + else { + ret = PyArray_DescrConverter(descr, &newdescr); + } + Py_DECREF(descr); + if (ret == NPY_FAIL) { + Py_DECREF(tup); + Py_DECREF(ind); + goto fail; + } + PyTuple_SET_ITEM(tup, 0, (PyObject *)newdescr); + if (align) { + _align = newdescr->alignment; + maxalign = PyArray_MAX(maxalign,_align); + } + if (offsets) { + long offset; + off = PyObject_GetItem(offsets, ind); + if (!off) { + Py_DECREF(tup); + Py_DECREF(ind); + goto fail; + } + offset = PyArray_PyIntAsInt(off); + if (error_converting(offset)) { + Py_DECREF(off); + Py_DECREF(tup); + Py_DECREF(ind); + goto fail; + } + Py_DECREF(off); + if (offset < 0) { + PyErr_Format(PyExc_ValueError, "offset %d cannot be negative", + (int)offset); + Py_DECREF(tup); + Py_DECREF(ind); + goto fail; + } + + PyTuple_SET_ITEM(tup, 1, PyInt_FromLong(offset)); + /* Flag whether the fields are specified out of order */ + if (offset < totalsize) { + has_out_of_order_fields = 1; + } + /* If align=True, enforce field alignment */ + if (align && offset % newdescr->alignment != 0) { + PyErr_Format(PyExc_ValueError, + "offset %d for NumPy dtype with fields is " + "not divisible by the field alignment %d " + "with align=True", + (int)offset, (int)newdescr->alignment); + ret = NPY_FAIL; + } + else if (offset + newdescr->elsize > totalsize) { + totalsize = offset + newdescr->elsize; + } + } + else { + if (align && _align > 1) { + totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, _align); + } + PyTuple_SET_ITEM(tup, 1, PyInt_FromLong(totalsize)); + totalsize += newdescr->elsize; + } + if (ret == NPY_FAIL) { + Py_DECREF(ind); + Py_DECREF(tup); + goto fail; + } + if (len == 3) { + PyTuple_SET_ITEM(tup, 2, title); + } + name = PyObject_GetItem(names, ind); + Py_DECREF(ind); + if (!name) { + Py_DECREF(tup); + goto fail; + } + if (!PyBaseString_Check(name)) { + PyErr_SetString(PyExc_ValueError, + "field names must be strings"); + Py_DECREF(tup); + goto fail; + } + + /* Insert into dictionary */ + if (PyDict_GetItem(fields, name) != NULL) { + PyErr_SetString(PyExc_ValueError, + "name already used as a name or title"); + Py_DECREF(tup); + goto fail; + } + PyDict_SetItem(fields, name, tup); + Py_DECREF(name); + if (len == 3) { + if (PyBaseString_Check(title)) { + if (PyDict_GetItem(fields, title) != NULL) { + PyErr_SetString(PyExc_ValueError, + "title already used as a name or title."); + Py_DECREF(tup); + goto fail; + } + PyDict_SetItem(fields, title, tup); + } + } + Py_DECREF(tup); + if (ret == NPY_FAIL) { + goto fail; + } + dtypeflags |= (newdescr->flags & NPY_FROM_FIELDS); + } + + new = PyArray_DescrNewFromType(NPY_VOID); + if (new == NULL) { + goto fail; + } + if (maxalign > 1) { + totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign); + } + if (align) { + new->alignment = maxalign; + } + new->elsize = totalsize; + if (!PyTuple_Check(names)) { + names = PySequence_Tuple(names); + } + else { + Py_INCREF(names); + } + new->names = names; + new->fields = fields; + new->flags = dtypeflags; + + /* + * If the fields weren't in order, and there was an OBJECT type, + * need to verify that no OBJECT types overlap with something else. + */ + if (has_out_of_order_fields && PyDataType_REFCHK(new)) { + if (validate_object_field_overlap(new) < 0) { + Py_DECREF(new); + return NULL; + } + } + + /* Structured arrays get a sticky aligned bit */ + if (align) { + new->flags |= NPY_ALIGNED_STRUCT; + } + + /* Override the itemsize if provided */ + tmp = Borrowed_PyMapping_GetItemString(obj, "itemsize"); + if (tmp == NULL) { + PyErr_Clear(); + } else { + itemsize = (int)PyArray_PyIntAsInt(tmp); + if (error_converting(itemsize)) { + Py_DECREF(new); + return NULL; + } + /* Make sure the itemsize isn't made too small */ + if (itemsize < new->elsize) { + PyErr_Format(PyExc_ValueError, + "NumPy dtype descriptor requires %d bytes, " + "cannot override to smaller itemsize of %d", + (int)new->elsize, (int)itemsize); + Py_DECREF(new); + return NULL; + } + /* If align is set, make sure the alignment divides into the size */ + if (align && itemsize % new->alignment != 0) { + PyErr_Format(PyExc_ValueError, + "NumPy dtype descriptor requires alignment of %d bytes, " + "which is not divisible into the specified itemsize %d", + (int)new->alignment, (int)itemsize); + Py_DECREF(new); + return NULL; + } + /* Set the itemsize */ + new->elsize = itemsize; + } + + /* Add the metadata if provided */ + metadata = Borrowed_PyMapping_GetItemString(obj, "metadata"); + + if (metadata == NULL) { + PyErr_Clear(); + } + else if (new->metadata == NULL) { + new->metadata = metadata; + Py_XINCREF(new->metadata); + } + else if (PyDict_Merge(new->metadata, metadata, 0) == -1) { + Py_DECREF(new); + return NULL; + } + return new; + + fail: + Py_XDECREF(fields); + return NULL; +} + + +/*NUMPY_API*/ +NPY_NO_EXPORT PyArray_Descr * +PyArray_DescrNewFromType(int type_num) +{ + PyArray_Descr *old; + PyArray_Descr *new; + + old = PyArray_DescrFromType(type_num); + new = PyArray_DescrNew(old); + Py_DECREF(old); + return new; +} + +/*NUMPY_API + * Get typenum from an object -- None goes to NULL + */ +NPY_NO_EXPORT int +PyArray_DescrConverter2(PyObject *obj, PyArray_Descr **at) +{ + if (obj == Py_None) { + *at = NULL; + return NPY_SUCCEED; + } + else { + return PyArray_DescrConverter(obj, at); + } +} + +/*NUMPY_API + * Get typenum from an object -- None goes to NPY_DEFAULT_TYPE + * This function takes a Python object representing a type and converts it + * to a the correct PyArray_Descr * structure to describe the type. + * + * Many objects can be used to represent a data-type which in NumPy is + * quite a flexible concept. + * + * This is the central code that converts Python objects to + * Type-descriptor objects that are used throughout numpy. + * + * Returns a new reference in *at, but the returned should not be + * modified as it may be one of the canonical immutable objects or + * a reference to the input obj. + */ +NPY_NO_EXPORT int +PyArray_DescrConverter(PyObject *obj, PyArray_Descr **at) +{ + int check_num = NPY_NOTYPE + 10; + PyObject *item; + int elsize = 0; + char endian = '='; + + *at = NULL; + + /* default */ + if (obj == Py_None) { + *at = PyArray_DescrFromType(NPY_DEFAULT_TYPE); + return NPY_SUCCEED; + } + + if (PyArray_DescrCheck(obj)) { + *at = (PyArray_Descr *)obj; + Py_INCREF(*at); + return NPY_SUCCEED; + } + + if (PyType_Check(obj)) { + if (PyType_IsSubtype((PyTypeObject *)obj, &PyGenericArrType_Type)) { + *at = PyArray_DescrFromTypeObject(obj); + return (*at) ? NPY_SUCCEED : NPY_FAIL; + } + check_num = NPY_OBJECT; +#if !defined(NPY_PY3K) + if (obj == (PyObject *)(&PyInt_Type)) { + check_num = NPY_LONG; + } + else if (obj == (PyObject *)(&PyLong_Type)) { + check_num = NPY_LONGLONG; + } +#else + if (obj == (PyObject *)(&PyLong_Type)) { + check_num = NPY_LONG; + } +#endif + else if (obj == (PyObject *)(&PyFloat_Type)) { + check_num = NPY_DOUBLE; + } + else if (obj == (PyObject *)(&PyComplex_Type)) { + check_num = NPY_CDOUBLE; + } + else if (obj == (PyObject *)(&PyBool_Type)) { + check_num = NPY_BOOL; + } + else if (obj == (PyObject *)(&PyBytes_Type)) { + check_num = NPY_STRING; + } + else if (obj == (PyObject *)(&PyUnicode_Type)) { + check_num = NPY_UNICODE; + } +#if defined(NPY_PY3K) + else if (obj == (PyObject *)(&PyMemoryView_Type)) { +#else + else if (obj == (PyObject *)(&PyBuffer_Type)) { +#endif + check_num = NPY_VOID; + } + else { + *at = _arraydescr_fromobj(obj); + if (*at) { + return NPY_SUCCEED; + } + } + goto finish; + } + + /* or a typecode string */ + + if (PyUnicode_Check(obj)) { + /* Allow unicode format strings: convert to bytes */ + int retval; + PyObject *obj2; + obj2 = PyUnicode_AsASCIIString(obj); + if (obj2 == NULL) { + return NPY_FAIL; + } + retval = PyArray_DescrConverter(obj2, at); + Py_DECREF(obj2); + return retval; + } + + if (PyBytes_Check(obj)) { + char *type = NULL; + Py_ssize_t len = 0; + + /* Check for a string typecode. */ + if (PyBytes_AsStringAndSize(obj, &type, &len) < 0) { + goto error; + } + + /* Empty string is invalid */ + if (len == 0) { + goto fail; + } + + /* check for commas present or first (or second) element a digit */ + if (_check_for_commastring(type, len)) { + *at = _convert_from_commastring(obj, 0); + return (*at) ? NPY_SUCCEED : NPY_FAIL; + } + + /* Process the endian character. '|' is replaced by '='*/ + switch (type[0]) { + case '>': + case '<': + case '=': + endian = type[0]; + ++type; + --len; + break; + + case '|': + endian = '='; + ++type; + --len; + break; + } + + /* Just an endian character is invalid */ + if (len == 0) { + goto fail; + } + + /* Check for datetime format */ + if (is_datetime_typestr(type, len)) { + *at = parse_dtype_from_datetime_typestr(type, len); + if (*at == NULL) { + return NPY_FAIL; + } + /* *at has byte order '=' at this point */ + if (!PyArray_ISNBO(endian)) { + (*at)->byteorder = endian; + } + return NPY_SUCCEED; + } + + /* A typecode like 'd' */ + if (len == 1) { + check_num = type[0]; + } + /* A kind + size like 'f8' */ + else { + char *typeend = NULL; + int kind; + + /* Parse the integer, make sure it's the rest of the string */ + elsize = (int)strtol(type + 1, &typeend, 10); + if (typeend - type == len) { + + kind = type[0]; + switch (kind) { + case NPY_STRINGLTR: + case NPY_STRINGLTR2: + check_num = NPY_STRING; + break; + + /* + * When specifying length of UNICODE + * the number of characters is given to match + * the STRING interface. Each character can be + * more than one byte and itemsize must be + * the number of bytes. + */ + case NPY_UNICODELTR: + check_num = NPY_UNICODE; + elsize <<= 2; + break; + + case NPY_VOIDLTR: + check_num = NPY_VOID; + break; + + default: + if (elsize == 0) { + check_num = NPY_NOTYPE+10; + } + /* Support for generic processing c8, i4, f8, etc...*/ + else { + check_num = PyArray_TypestrConvert(elsize, kind); + if (check_num == NPY_NOTYPE) { + check_num += 10; + } + elsize = 0; + } + } + } + } + } + else if (PyTuple_Check(obj)) { + /* or a tuple */ + *at = _convert_from_tuple(obj); + if (*at == NULL){ + if (PyErr_Occurred()) { + return NPY_FAIL; + } + goto fail; + } + return NPY_SUCCEED; + } + else if (PyList_Check(obj)) { + /* or a list */ + *at = _convert_from_array_descr(obj,0); + if (*at == NULL) { + if (PyErr_Occurred()) { + return NPY_FAIL; + } + goto fail; + } + return NPY_SUCCEED; + } + else if (PyDict_Check(obj) || PyDictProxy_Check(obj)) { + /* or a dictionary */ + *at = _convert_from_dict(obj,0); + if (*at == NULL) { + if (PyErr_Occurred()) { + return NPY_FAIL; + } + goto fail; + } + return NPY_SUCCEED; + } + else if (PyArray_Check(obj)) { + goto fail; + } + else { + *at = _arraydescr_fromobj(obj); + if (*at) { + return NPY_SUCCEED; + } + if (PyErr_Occurred()) { + return NPY_FAIL; + } + goto fail; + } + if (PyErr_Occurred()) { + goto fail; + } + +finish: + if ((check_num == NPY_NOTYPE + 10) || + (*at = PyArray_DescrFromType(check_num)) == NULL) { + PyErr_Clear(); + /* Now check to see if the object is registered in typeDict */ + if (typeDict != NULL) { + item = PyDict_GetItem(typeDict, obj); +#if defined(NPY_PY3K) + if (!item && PyBytes_Check(obj)) { + PyObject *tmp; + tmp = PyUnicode_FromEncodedObject(obj, "ascii", "strict"); + if (tmp != NULL) { + item = PyDict_GetItem(typeDict, tmp); + Py_DECREF(tmp); + } + } +#endif + if (item) { + /* Check for a deprecated Numeric-style typecode */ + if (PyBytes_Check(obj)) { + char *type = NULL; + Py_ssize_t len = 0; + char *dep_tps[] = {"Bool", "Complex", "Float", "Int", + "Object0", "String0", "Timedelta64", + "Unicode0", "UInt", "Void0"}; + int ndep_tps = sizeof(dep_tps) / sizeof(dep_tps[0]); + int i; + + if (PyBytes_AsStringAndSize(obj, &type, &len) < 0) { + goto error; + } + for (i = 0; i < ndep_tps; ++i) { + char *dep_tp = dep_tps[i]; + + if (strncmp(type, dep_tp, strlen(dep_tp)) == 0) { + if (DEPRECATE("Numeric-style type codes are " + "deprecated and will result in " + "an error in the future.") < 0) { + goto fail; + } + } + } + } + return PyArray_DescrConverter(item, at); + } + } + goto fail; + } + + if (PyDataType_ISUNSIZED(*at) && (*at)->elsize != elsize) { + PyArray_DESCR_REPLACE(*at); + (*at)->elsize = elsize; + } + if (endian != '=' && PyArray_ISNBO(endian)) { + endian = '='; + } + if (endian != '=' && (*at)->byteorder != '|' + && (*at)->byteorder != endian) { + PyArray_DESCR_REPLACE(*at); + (*at)->byteorder = endian; + } + return NPY_SUCCEED; + +fail: + if (PyBytes_Check(obj)) { + PyErr_Format(PyExc_TypeError, + "data type \"%s\" not understood", PyBytes_AS_STRING(obj)); + } + else { + PyErr_SetString(PyExc_TypeError, + "data type not understood"); + } + +error: + *at = NULL; + return NPY_FAIL; +} + +/** Array Descr Objects for dynamic types **/ + +/* + * There are some statically-defined PyArray_Descr objects corresponding + * to the basic built-in types. + * These can and should be DECREF'd and INCREF'd as appropriate, anyway. + * If a mistake is made in reference counting, deallocation on these + * builtins will be attempted leading to problems. + * + * This lets us deal with all PyArray_Descr objects using reference + * counting (regardless of whether they are statically or dynamically + * allocated). + */ + +/*NUMPY_API + * base cannot be NULL + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_DescrNew(PyArray_Descr *base) +{ + PyArray_Descr *newdescr = PyObject_New(PyArray_Descr, &PyArrayDescr_Type); + + if (newdescr == NULL) { + return NULL; + } + /* Don't copy PyObject_HEAD part */ + memcpy((char *)newdescr + sizeof(PyObject), + (char *)base + sizeof(PyObject), + sizeof(PyArray_Descr) - sizeof(PyObject)); + + /* + * The c_metadata has a by-value ownership model, need to clone it + * (basically a deep copy, but the auxdata clone function has some + * flexibility still) so the new PyArray_Descr object owns + * a copy of the data. Having both 'base' and 'newdescr' point to + * the same auxdata pointer would cause a double-free of memory. + */ + if (base->c_metadata != NULL) { + newdescr->c_metadata = NPY_AUXDATA_CLONE(base->c_metadata); + if (newdescr->c_metadata == NULL) { + PyErr_NoMemory(); + Py_DECREF(newdescr); + return NULL; + } + } + + if (newdescr->fields == Py_None) { + newdescr->fields = NULL; + } + Py_XINCREF(newdescr->fields); + Py_XINCREF(newdescr->names); + if (newdescr->subarray) { + newdescr->subarray = PyArray_malloc(sizeof(PyArray_ArrayDescr)); + if (newdescr->subarray == NULL) { + Py_DECREF(newdescr); + return (PyArray_Descr *)PyErr_NoMemory(); + } + memcpy(newdescr->subarray, base->subarray, sizeof(PyArray_ArrayDescr)); + Py_INCREF(newdescr->subarray->shape); + Py_INCREF(newdescr->subarray->base); + } + Py_XINCREF(newdescr->typeobj); + Py_XINCREF(newdescr->metadata); + newdescr->hash = -1; + + return newdescr; +} + +/* + * should never be called for builtin-types unless + * there is a reference-count problem + */ +static void +arraydescr_dealloc(PyArray_Descr *self) +{ + if (self->fields == Py_None) { + fprintf(stderr, "*** Reference count error detected: \n" \ + "an attempt was made to deallocate %d (%c) ***\n", + self->type_num, self->type); + Py_INCREF(self); + Py_INCREF(self); + return; + } + Py_XDECREF(self->typeobj); + Py_XDECREF(self->names); + Py_XDECREF(self->fields); + if (self->subarray) { + Py_XDECREF(self->subarray->shape); + Py_DECREF(self->subarray->base); + PyArray_free(self->subarray); + } + Py_XDECREF(self->metadata); + NPY_AUXDATA_FREE(self->c_metadata); + self->c_metadata = NULL; + Py_TYPE(self)->tp_free((PyObject *)self); +} + +/* + * we need to be careful about setting attributes because these + * objects are pointed to by arrays that depend on them for interpreting + * data. Currently no attributes of data-type objects can be set + * directly except names. + */ +static PyMemberDef arraydescr_members[] = { + {"type", + T_OBJECT, offsetof(PyArray_Descr, typeobj), READONLY, NULL}, + {"kind", + T_CHAR, offsetof(PyArray_Descr, kind), READONLY, NULL}, + {"char", + T_CHAR, offsetof(PyArray_Descr, type), READONLY, NULL}, + {"num", + T_INT, offsetof(PyArray_Descr, type_num), READONLY, NULL}, + {"byteorder", + T_CHAR, offsetof(PyArray_Descr, byteorder), READONLY, NULL}, + {"itemsize", + T_INT, offsetof(PyArray_Descr, elsize), READONLY, NULL}, + {"alignment", + T_INT, offsetof(PyArray_Descr, alignment), READONLY, NULL}, + {"flags", + T_BYTE, offsetof(PyArray_Descr, flags), READONLY, NULL}, + {NULL, 0, 0, 0, NULL}, +}; + +static PyObject * +arraydescr_subdescr_get(PyArray_Descr *self) +{ + if (!PyDataType_HASSUBARRAY(self)) { + Py_RETURN_NONE; + } + return Py_BuildValue("OO", + (PyObject *)self->subarray->base, self->subarray->shape); +} + +NPY_NO_EXPORT PyObject * +arraydescr_protocol_typestr_get(PyArray_Descr *self) +{ + char basic_ = self->kind; + char endian = self->byteorder; + int size = self->elsize; + PyObject *ret; + + if (endian == '=') { + endian = '<'; + if (!PyArray_IsNativeByteOrder(endian)) { + endian = '>'; + } + } + if (self->type_num == NPY_UNICODE) { + size >>= 2; + } + if (self->type_num == NPY_OBJECT) { + ret = PyUString_FromFormat("%c%c", endian, basic_); + } + else { + ret = PyUString_FromFormat("%c%c%d", endian, basic_, size); + } + if (PyDataType_ISDATETIME(self)) { + PyArray_DatetimeMetaData *meta; + + meta = get_datetime_metadata_from_dtype(self); + if (meta == NULL) { + Py_DECREF(ret); + return NULL; + } + + ret = append_metastr_to_string(meta, 0, ret); + } + + return ret; +} + +static PyObject * +arraydescr_typename_get(PyArray_Descr *self) +{ + static const char np_prefix[] = "numpy."; + const int np_prefix_len = sizeof(np_prefix) - 1; + PyTypeObject *typeobj = self->typeobj; + PyObject *res; + char *s; + int len; + int prefix_len; + int suffix_len; + + if (PyTypeNum_ISUSERDEF(self->type_num)) { + s = strrchr(typeobj->tp_name, '.'); + if (s == NULL) { + res = PyUString_FromString(typeobj->tp_name); + } + else { + res = PyUString_FromStringAndSize(s + 1, strlen(s) - 1); + } + return res; + } + else { + /* + * NumPy type or subclass + * + * res is derived from typeobj->tp_name with the following rules: + * - if starts with "numpy.", that prefix is removed + * - if ends with "_", that suffix is removed + */ + len = strlen(typeobj->tp_name); + + if (! strncmp(typeobj->tp_name, np_prefix, np_prefix_len)) { + prefix_len = np_prefix_len; + } + else { + prefix_len = 0; + } + + if (typeobj->tp_name[len - 1] == '_') { + suffix_len = 1; + } + else { + suffix_len = 0; + } + + len -= prefix_len; + len -= suffix_len; + res = PyUString_FromStringAndSize(typeobj->tp_name+prefix_len, len); + } + if (PyTypeNum_ISFLEXIBLE(self->type_num) && !PyDataType_ISUNSIZED(self)) { + PyObject *p; + p = PyUString_FromFormat("%d", self->elsize * 8); + PyUString_ConcatAndDel(&res, p); + } + if (PyDataType_ISDATETIME(self)) { + PyArray_DatetimeMetaData *meta; + + meta = get_datetime_metadata_from_dtype(self); + if (meta == NULL) { + Py_DECREF(res); + return NULL; + } + + res = append_metastr_to_string(meta, 0, res); + } + + return res; +} + +static PyObject * +arraydescr_base_get(PyArray_Descr *self) +{ + if (!PyDataType_HASSUBARRAY(self)) { + Py_INCREF(self); + return (PyObject *)self; + } + Py_INCREF(self->subarray->base); + return (PyObject *)(self->subarray->base); +} + +static PyObject * +arraydescr_shape_get(PyArray_Descr *self) +{ + if (!PyDataType_HASSUBARRAY(self)) { + return PyTuple_New(0); + } + /*TODO + * self->subarray->shape should always be a tuple, + * so this check should be unnecessary + */ + if (PyTuple_Check(self->subarray->shape)) { + Py_INCREF(self->subarray->shape); + return (PyObject *)(self->subarray->shape); + } + return Py_BuildValue("(O)", self->subarray->shape); +} + +static PyObject * +arraydescr_ndim_get(PyArray_Descr *self) +{ + if (!PyDataType_HASSUBARRAY(self)) { + return PyInt_FromLong(0); + } + /*TODO + * self->subarray->shape should always be a tuple, + * so this check should be unnecessary + */ + if (PyTuple_Check(self->subarray->shape)) { + Py_ssize_t ndim = PyTuple_Size(self->subarray->shape); + return PyInt_FromLong(ndim); + } + /* consistent with arraydescr_shape_get */ + return PyInt_FromLong(1); +} + + +NPY_NO_EXPORT PyObject * +arraydescr_protocol_descr_get(PyArray_Descr *self) +{ + PyObject *dobj, *res; + PyObject *_numpy_internal; + + if (!PyDataType_HASFIELDS(self)) { + /* get default */ + dobj = PyTuple_New(2); + if (dobj == NULL) { + return NULL; + } + PyTuple_SET_ITEM(dobj, 0, PyUString_FromString("")); + PyTuple_SET_ITEM(dobj, 1, arraydescr_protocol_typestr_get(self)); + res = PyList_New(1); + if (res == NULL) { + Py_DECREF(dobj); + return NULL; + } + PyList_SET_ITEM(res, 0, dobj); + return res; + } + + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + res = PyObject_CallMethod(_numpy_internal, "_array_descr", "O", self); + Py_DECREF(_numpy_internal); + return res; +} + +/* + * returns 1 for a builtin type + * and 2 for a user-defined data-type descriptor + * return 0 if neither (i.e. it's a copy of one) + */ +static PyObject * +arraydescr_isbuiltin_get(PyArray_Descr *self) +{ + long val; + val = 0; + if (self->fields == Py_None) { + val = 1; + } + if (PyTypeNum_ISUSERDEF(self->type_num)) { + val = 2; + } + return PyInt_FromLong(val); +} + +static int +_arraydescr_isnative(PyArray_Descr *self) +{ + if (!PyDataType_HASFIELDS(self)) { + return PyArray_ISNBO(self->byteorder); + } + else { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; + while (PyDict_Next(self->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) { + return -1; + } + if (!_arraydescr_isnative(new)) { + return 0; + } + } + } + return 1; +} + +/* + * return Py_True if this data-type descriptor + * has native byteorder if no fields are defined + * + * or if all sub-fields have native-byteorder if + * fields are defined + */ +static PyObject * +arraydescr_isnative_get(PyArray_Descr *self) +{ + PyObject *ret; + int retval; + retval = _arraydescr_isnative(self); + if (retval == -1) { + return NULL; + } + ret = retval ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} + +static PyObject * +arraydescr_isalignedstruct_get(PyArray_Descr *self) +{ + PyObject *ret; + ret = (self->flags&NPY_ALIGNED_STRUCT) ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} + +static PyObject * +arraydescr_fields_get(PyArray_Descr *self) +{ + if (!PyDataType_HASFIELDS(self)) { + Py_RETURN_NONE; + } + return PyDictProxy_New(self->fields); +} + +static PyObject * +arraydescr_metadata_get(PyArray_Descr *self) +{ + if (self->metadata == NULL) { + Py_RETURN_NONE; + } + return PyDictProxy_New(self->metadata); +} + +static PyObject * +arraydescr_hasobject_get(PyArray_Descr *self) +{ + if (PyDataType_FLAGCHK(self, NPY_ITEM_HASOBJECT)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject * +arraydescr_names_get(PyArray_Descr *self) +{ + if (!PyDataType_HASFIELDS(self)) { + Py_RETURN_NONE; + } + Py_INCREF(self->names); + return self->names; +} + +static int +arraydescr_names_set(PyArray_Descr *self, PyObject *val) +{ + int N = 0; + int i; + PyObject *new_names; + PyObject *new_fields; + + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete dtype names attribute"); + return -1; + } + if (!PyDataType_HASFIELDS(self)) { + PyErr_SetString(PyExc_ValueError, + "there are no fields defined"); + return -1; + } + + /* + * FIXME + * + * This deprecation has been temporarily removed for the NumPy 1.7 + * release. It should be re-added after the 1.7 branch is done, + * and a convenience API to replace the typical use-cases for + * mutable names should be implemented. + * + * if (DEPRECATE("Setting NumPy dtype names is deprecated, the dtype " + * "will become immutable in a future version") < 0) { + * return -1; + * } + */ + + N = PyTuple_GET_SIZE(self->names); + if (!PySequence_Check(val) || PyObject_Size((PyObject *)val) != N) { + PyErr_Format(PyExc_ValueError, + "must replace all names at once with a sequence of length %d", + N); + return -1; + } + /* Make sure all entries are strings */ + for (i = 0; i < N; i++) { + PyObject *item; + int valid = 1; + item = PySequence_GetItem(val, i); + valid = PyUString_Check(item); + Py_DECREF(item); + if (!valid) { + PyErr_Format(PyExc_ValueError, + "item #%d of names is of type %s and not string", + i, Py_TYPE(item)->tp_name); + return -1; + } + } + /* Invalidate cached hash value */ + self->hash = -1; + /* Update dictionary keys in fields */ + new_names = PySequence_Tuple(val); + new_fields = PyDict_New(); + for (i = 0; i < N; i++) { + PyObject *key; + PyObject *item; + PyObject *new_key; + int ret; + key = PyTuple_GET_ITEM(self->names, i); + /* Borrowed references to item and new_key */ + item = PyDict_GetItem(self->fields, key); + new_key = PyTuple_GET_ITEM(new_names, i); + /* Check for duplicates */ + ret = PyDict_Contains(new_fields, new_key); + if (ret != 0) { + if (ret < 0) { + PyErr_Clear(); + } + PyErr_SetString(PyExc_ValueError, "Duplicate field names given."); + Py_DECREF(new_names); + Py_DECREF(new_fields); + return -1; + } + PyDict_SetItem(new_fields, new_key, item); + } + + /* Replace names */ + Py_DECREF(self->names); + self->names = new_names; + + /* Replace fields */ + Py_DECREF(self->fields); + self->fields = new_fields; + + return 0; +} + +static PyGetSetDef arraydescr_getsets[] = { + {"subdtype", + (getter)arraydescr_subdescr_get, + NULL, NULL, NULL}, + {"descr", + (getter)arraydescr_protocol_descr_get, + NULL, NULL, NULL}, + {"str", + (getter)arraydescr_protocol_typestr_get, + NULL, NULL, NULL}, + {"name", + (getter)arraydescr_typename_get, + NULL, NULL, NULL}, + {"base", + (getter)arraydescr_base_get, + NULL, NULL, NULL}, + {"shape", + (getter)arraydescr_shape_get, + NULL, NULL, NULL}, + {"ndim", + (getter)arraydescr_ndim_get, + NULL, NULL, NULL}, + {"isbuiltin", + (getter)arraydescr_isbuiltin_get, + NULL, NULL, NULL}, + {"isnative", + (getter)arraydescr_isnative_get, + NULL, NULL, NULL}, + {"isalignedstruct", + (getter)arraydescr_isalignedstruct_get, + NULL, NULL, NULL}, + {"fields", + (getter)arraydescr_fields_get, + NULL, NULL, NULL}, + {"metadata", + (getter)arraydescr_metadata_get, + NULL, NULL, NULL}, + {"names", + (getter)arraydescr_names_get, + (setter)arraydescr_names_set, + NULL, NULL}, + {"hasobject", + (getter)arraydescr_hasobject_get, + NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL}, +}; + +static PyObject * +arraydescr_new(PyTypeObject *NPY_UNUSED(subtype), + PyObject *args, PyObject *kwds) +{ + PyObject *odescr, *metadata=NULL; + PyArray_Descr *descr, *conv; + npy_bool align = NPY_FALSE; + npy_bool copy = NPY_FALSE; + npy_bool copied = NPY_FALSE; + + static char *kwlist[] = {"dtype", "align", "copy", "metadata", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O&O!:dtype", kwlist, + &odescr, + PyArray_BoolConverter, &align, + PyArray_BoolConverter, ©, + &PyDict_Type, &metadata)) { + return NULL; + } + + if (align) { + if (!PyArray_DescrAlignConverter(odescr, &conv)) { + return NULL; + } + } + else if (!PyArray_DescrConverter(odescr, &conv)) { + return NULL; + } + + /* Get a new copy of it unless it's already a copy */ + if (copy && conv->fields == Py_None) { + descr = PyArray_DescrNew(conv); + Py_DECREF(conv); + conv = descr; + copied = NPY_TRUE; + } + + if ((metadata != NULL)) { + /* + * We need to be sure to make a new copy of the data-type and any + * underlying dictionary + */ + if (!copied) { + copied = NPY_TRUE; + descr = PyArray_DescrNew(conv); + Py_DECREF(conv); + conv = descr; + } + if ((conv->metadata != NULL)) { + /* + * Make a copy of the metadata before merging with the + * input metadata so that this data-type descriptor has + * it's own copy + */ + /* Save a reference */ + odescr = conv->metadata; + conv->metadata = PyDict_Copy(odescr); + /* Decrement the old reference */ + Py_DECREF(odescr); + + /* + * Update conv->metadata with anything new in metadata + * keyword, but do not over-write anything already there + */ + if (PyDict_Merge(conv->metadata, metadata, 0) != 0) { + Py_DECREF(conv); + return NULL; + } + } + else { + /* Make a copy of the input dictionary */ + conv->metadata = PyDict_Copy(metadata); + } + } + + return (PyObject *)conv; +} + +/* + * Return a tuple of + * (cleaned metadata dictionary, tuple with (str, num)) + */ +static PyObject * +_get_pickleabletype_from_datetime_metadata(PyArray_Descr *dtype) +{ + PyObject *ret, *dt_tuple; + PyArray_DatetimeMetaData *meta; + + /* Create the 2-item tuple to return */ + ret = PyTuple_New(2); + if (ret == NULL) { + return NULL; + } + + /* Store the metadata dictionary */ + if (dtype->metadata != NULL) { + Py_INCREF(dtype->metadata); + PyTuple_SET_ITEM(ret, 0, dtype->metadata); + } else { + PyTuple_SET_ITEM(ret, 0, PyDict_New()); + } + + /* Convert the datetime metadata into a tuple */ + meta = get_datetime_metadata_from_dtype(dtype); + if (meta == NULL) { + Py_DECREF(ret); + return NULL; + } + /* Use a 4-tuple that numpy 1.6 knows how to unpickle */ + dt_tuple = PyTuple_New(4); + if (dt_tuple == NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(dt_tuple, 0, + PyBytes_FromString(_datetime_strings[meta->base])); + PyTuple_SET_ITEM(dt_tuple, 1, + PyInt_FromLong(meta->num)); + PyTuple_SET_ITEM(dt_tuple, 2, + PyInt_FromLong(1)); + PyTuple_SET_ITEM(dt_tuple, 3, + PyInt_FromLong(1)); + + PyTuple_SET_ITEM(ret, 1, dt_tuple); + + return ret; +} + +/* + * return a tuple of (callable object, args, state). + * + * TODO: This method needs to change so that unpickling doesn't + * use __setstate__. This is required for the dtype + * to be an immutable object. + */ +static PyObject * +arraydescr_reduce(PyArray_Descr *self, PyObject *NPY_UNUSED(args)) +{ + /* + * version number of this pickle type. Increment if we need to + * change the format. Be sure to handle the old versions in + * arraydescr_setstate. + */ + const int version = 4; + PyObject *ret, *mod, *obj; + PyObject *state; + char endian; + int elsize, alignment; + + ret = PyTuple_New(3); + if (ret == NULL) { + return NULL; + } + mod = PyImport_ImportModule("numpy.core.multiarray"); + if (mod == NULL) { + Py_DECREF(ret); + return NULL; + } + obj = PyObject_GetAttrString(mod, "dtype"); + Py_DECREF(mod); + if (obj == NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(ret, 0, obj); + if (PyTypeNum_ISUSERDEF(self->type_num) + || ((self->type_num == NPY_VOID + && self->typeobj != &PyVoidArrType_Type))) { + obj = (PyObject *)self->typeobj; + Py_INCREF(obj); + } + else { + elsize = self->elsize; + if (self->type_num == NPY_UNICODE) { + elsize >>= 2; + } + obj = PyUString_FromFormat("%c%d",self->kind, elsize); + } + PyTuple_SET_ITEM(ret, 1, Py_BuildValue("(Nii)", obj, 0, 1)); + + /* + * Now return the state which is at least byteorder, + * subarray, and fields + */ + endian = self->byteorder; + if (endian == '=') { + endian = '<'; + if (!PyArray_IsNativeByteOrder(endian)) { + endian = '>'; + } + } + if (PyDataType_ISDATETIME(self)) { + PyObject *newobj; + state = PyTuple_New(9); + PyTuple_SET_ITEM(state, 0, PyInt_FromLong(version)); + /* + * newobj is a tuple of the Python metadata dictionary + * and tuple of date_time info (str, num) + */ + newobj = _get_pickleabletype_from_datetime_metadata(self); + if (newobj == NULL) { + Py_DECREF(state); + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(state, 8, newobj); + } + else if (self->metadata) { + state = PyTuple_New(9); + PyTuple_SET_ITEM(state, 0, PyInt_FromLong(version)); + Py_INCREF(self->metadata); + PyTuple_SET_ITEM(state, 8, self->metadata); + } + else { /* Use version 3 pickle format */ + state = PyTuple_New(8); + PyTuple_SET_ITEM(state, 0, PyInt_FromLong(3)); + } + + PyTuple_SET_ITEM(state, 1, PyUString_FromFormat("%c", endian)); + PyTuple_SET_ITEM(state, 2, arraydescr_subdescr_get(self)); + if (PyDataType_HASFIELDS(self)) { + Py_INCREF(self->names); + Py_INCREF(self->fields); + PyTuple_SET_ITEM(state, 3, self->names); + PyTuple_SET_ITEM(state, 4, self->fields); + } + else { + PyTuple_SET_ITEM(state, 3, Py_None); + PyTuple_SET_ITEM(state, 4, Py_None); + Py_INCREF(Py_None); + Py_INCREF(Py_None); + } + + /* for extended types it also includes elsize and alignment */ + if (PyTypeNum_ISEXTENDED(self->type_num)) { + elsize = self->elsize; + alignment = self->alignment; + } + else { + elsize = -1; + alignment = -1; + } + PyTuple_SET_ITEM(state, 5, PyInt_FromLong(elsize)); + PyTuple_SET_ITEM(state, 6, PyInt_FromLong(alignment)); + PyTuple_SET_ITEM(state, 7, PyInt_FromLong(self->flags)); + + PyTuple_SET_ITEM(ret, 2, state); + return ret; +} + +/* + * returns NPY_OBJECT_DTYPE_FLAGS if this data-type has an object portion used + * when setting the state because hasobject is not stored. + */ +static char +_descr_find_object(PyArray_Descr *self) +{ + if (self->flags + || self->type_num == NPY_OBJECT + || self->kind == 'O') { + return NPY_OBJECT_DTYPE_FLAGS; + } + if (PyDataType_HASFIELDS(self)) { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; + + while (PyDict_Next(self->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) { + PyErr_Clear(); + return 0; + } + if (_descr_find_object(new)) { + new->flags = NPY_OBJECT_DTYPE_FLAGS; + return NPY_OBJECT_DTYPE_FLAGS; + } + } + } + return 0; +} + +/* + * state is at least byteorder, subarray, and fields but could include elsize + * and alignment for EXTENDED arrays + */ +static PyObject * +arraydescr_setstate(PyArray_Descr *self, PyObject *args) +{ + int elsize = -1, alignment = -1; + int version = 4; + char endian; + PyObject *endian_obj; + PyObject *subarray, *fields, *names = NULL, *metadata=NULL; + int incref_names = 1; + int int_dtypeflags = 0; + char dtypeflags; + + if (self->fields == Py_None) { + Py_RETURN_NONE; + } + if (PyTuple_GET_SIZE(args) != 1 + || !(PyTuple_Check(PyTuple_GET_ITEM(args, 0)))) { + PyErr_BadInternalCall(); + return NULL; + } + switch (PyTuple_GET_SIZE(PyTuple_GET_ITEM(args,0))) { + case 9: + if (!PyArg_ParseTuple(args, "(iOOOOiiiO):__setstate__", + &version, &endian_obj, + &subarray, &names, &fields, &elsize, + &alignment, &int_dtypeflags, &metadata)) { + PyErr_Clear(); + return NULL; + } + break; + case 8: + if (!PyArg_ParseTuple(args, "(iOOOOiii):__setstate__", + &version, &endian_obj, + &subarray, &names, &fields, &elsize, + &alignment, &int_dtypeflags)) { + return NULL; + } + break; + case 7: + if (!PyArg_ParseTuple(args, "(iOOOOii):__setstate__", + &version, &endian_obj, + &subarray, &names, &fields, &elsize, + &alignment)) { + return NULL; + } + break; + case 6: + if (!PyArg_ParseTuple(args, "(iOOOii):__setstate__", + &version, + &endian_obj, &subarray, &fields, + &elsize, &alignment)) { + return NULL; + } + break; + case 5: + version = 0; + if (!PyArg_ParseTuple(args, "(OOOii):__setstate__", + &endian_obj, &subarray, &fields, &elsize, + &alignment)) { + return NULL; + } + break; + default: + /* raise an error */ + if (PyTuple_GET_SIZE(PyTuple_GET_ITEM(args,0)) > 5) { + version = PyInt_AsLong(PyTuple_GET_ITEM(args, 0)); + } + else { + version = -1; + } + } + + /* + * If we ever need another pickle format, increment the version + * number. But we should still be able to handle the old versions. + */ + if (version < 0 || version > 4) { + PyErr_Format(PyExc_ValueError, + "can't handle version %d of numpy.dtype pickle", + version); + return NULL; + } + /* Invalidate cached hash value */ + self->hash = -1; + + if (version == 1 || version == 0) { + if (fields != Py_None) { + PyObject *key, *list; + key = PyInt_FromLong(-1); + list = PyDict_GetItem(fields, key); + if (!list) { + return NULL; + } + Py_INCREF(list); + names = list; + PyDict_DelItem(fields, key); + incref_names = 0; + } + else { + names = Py_None; + } + } + + /* Parse endian */ + if (PyUnicode_Check(endian_obj) || PyBytes_Check(endian_obj)) { + PyObject *tmp = NULL; + char *str; + Py_ssize_t len; + + if (PyUnicode_Check(endian_obj)) { + tmp = PyUnicode_AsASCIIString(endian_obj); + if (tmp == NULL) { + return NULL; + } + endian_obj = tmp; + } + + if (PyBytes_AsStringAndSize(endian_obj, &str, &len) < 0) { + Py_XDECREF(tmp); + return NULL; + } + if (len != 1) { + PyErr_SetString(PyExc_ValueError, + "endian is not 1-char string in Numpy dtype unpickling"); + Py_XDECREF(tmp); + return NULL; + } + endian = str[0]; + Py_XDECREF(tmp); + } + else { + PyErr_SetString(PyExc_ValueError, + "endian is not a string in Numpy dtype unpickling"); + return NULL; + } + + if ((fields == Py_None && names != Py_None) || + (names == Py_None && fields != Py_None)) { + PyErr_Format(PyExc_ValueError, + "inconsistent fields and names in Numpy dtype unpickling"); + return NULL; + } + + if (names != Py_None && !PyTuple_Check(names)) { + PyErr_Format(PyExc_ValueError, + "non-tuple names in Numpy dtype unpickling"); + return NULL; + } + + if (fields != Py_None && !PyDict_Check(fields)) { + PyErr_Format(PyExc_ValueError, + "non-dict fields in Numpy dtype unpickling"); + return NULL; + } + + if (endian != '|' && PyArray_IsNativeByteOrder(endian)) { + endian = '='; + } + self->byteorder = endian; + if (self->subarray) { + Py_XDECREF(self->subarray->base); + Py_XDECREF(self->subarray->shape); + PyArray_free(self->subarray); + } + self->subarray = NULL; + + if (subarray != Py_None) { + PyObject *subarray_shape; + + /* + * Ensure that subarray[0] is an ArrayDescr and + * that subarray_shape obtained from subarray[1] is a tuple of integers. + */ + if (!(PyTuple_Check(subarray) && + PyTuple_Size(subarray) == 2 && + PyArray_DescrCheck(PyTuple_GET_ITEM(subarray, 0)))) { + PyErr_Format(PyExc_ValueError, + "incorrect subarray in __setstate__"); + return NULL; + } + subarray_shape = PyTuple_GET_ITEM(subarray, 1); + if (PyNumber_Check(subarray_shape)) { + PyObject *tmp; +#if defined(NPY_PY3K) + tmp = PyNumber_Long(subarray_shape); +#else + tmp = PyNumber_Int(subarray_shape); +#endif + if (tmp == NULL) { + return NULL; + } + subarray_shape = Py_BuildValue("(O)", tmp); + Py_DECREF(tmp); + if (subarray_shape == NULL) { + return NULL; + } + } + else if (_is_tuple_of_integers(subarray_shape)) { + Py_INCREF(subarray_shape); + } + else { + PyErr_Format(PyExc_ValueError, + "incorrect subarray shape in __setstate__"); + return NULL; + } + + self->subarray = PyArray_malloc(sizeof(PyArray_ArrayDescr)); + if (!PyDataType_HASSUBARRAY(self)) { + return PyErr_NoMemory(); + } + self->subarray->base = (PyArray_Descr *)PyTuple_GET_ITEM(subarray, 0); + Py_INCREF(self->subarray->base); + self->subarray->shape = subarray_shape; + } + + if (fields != Py_None) { + /* + * Ensure names are of appropriate string type + */ + Py_ssize_t i; + int names_ok = 1; + PyObject *name; + + for (i = 0; i < PyTuple_GET_SIZE(names); ++i) { + name = PyTuple_GET_ITEM(names, i); + if (!PyUString_Check(name)) { + names_ok = 0; + break; + } + } + + if (names_ok) { + Py_XDECREF(self->fields); + self->fields = fields; + Py_INCREF(fields); + Py_XDECREF(self->names); + self->names = names; + if (incref_names) { + Py_INCREF(names); + } + } + else { +#if defined(NPY_PY3K) + /* + * To support pickle.load(f, encoding='bytes') for loading Py2 + * generated pickles on Py3, we need to be more lenient and convert + * field names from byte strings to unicode. + */ + PyObject *tmp, *new_name, *field; + + tmp = PyDict_New(); + if (tmp == NULL) { + return NULL; + } + Py_XDECREF(self->fields); + self->fields = tmp; + + tmp = PyTuple_New(PyTuple_GET_SIZE(names)); + if (tmp == NULL) { + return NULL; + } + Py_XDECREF(self->names); + self->names = tmp; + + for (i = 0; i < PyTuple_GET_SIZE(names); ++i) { + name = PyTuple_GET_ITEM(names, i); + field = PyDict_GetItem(fields, name); + if (!field) { + return NULL; + } + + if (PyUnicode_Check(name)) { + new_name = name; + Py_INCREF(new_name); + } + else { + new_name = PyUnicode_FromEncodedObject(name, "ASCII", "strict"); + if (new_name == NULL) { + return NULL; + } + } + + PyTuple_SET_ITEM(self->names, i, new_name); + if (PyDict_SetItem(self->fields, new_name, field) != 0) { + return NULL; + } + } +#else + PyErr_Format(PyExc_ValueError, + "non-string names in Numpy dtype unpickling"); + return NULL; +#endif + } + } + + if (PyTypeNum_ISEXTENDED(self->type_num)) { + self->elsize = elsize; + self->alignment = alignment; + } + + /* + * We use an integer converted to char for backward compatibility with + * pickled arrays. Pickled arrays created with previous versions encoded + * flags as an int even though it actually was a char in the PyArray_Descr + * structure + */ + dtypeflags = int_dtypeflags; + if (dtypeflags != int_dtypeflags) { + PyErr_Format(PyExc_ValueError, + "incorrect value for flags variable (overflow)"); + return NULL; + } + else { + self->flags = dtypeflags; + } + + if (version < 3) { + self->flags = _descr_find_object(self); + } + + /* + * We have a borrowed reference to metadata so no need + * to alter reference count when throwing away Py_None. + */ + if (metadata == Py_None) { + metadata = NULL; + } + + if (PyDataType_ISDATETIME(self) && (metadata != NULL)) { + PyObject *old_metadata, *errmsg; + PyArray_DatetimeMetaData temp_dt_data; + + if ((! PyTuple_Check(metadata)) || (PyTuple_Size(metadata) != 2)) { + errmsg = PyUString_FromString("Invalid datetime dtype (metadata, c_metadata): "); + PyUString_ConcatAndDel(&errmsg, PyObject_Repr(metadata)); + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + return NULL; + } + + if (convert_datetime_metadata_tuple_to_datetime_metadata( + PyTuple_GET_ITEM(metadata, 1), + &temp_dt_data, + NPY_TRUE) < 0) { + return NULL; + } + + old_metadata = self->metadata; + self->metadata = PyTuple_GET_ITEM(metadata, 0); + memcpy((char *) &((PyArray_DatetimeDTypeMetaData *)self->c_metadata)->meta, + (char *) &temp_dt_data, + sizeof(PyArray_DatetimeMetaData)); + Py_XINCREF(self->metadata); + Py_XDECREF(old_metadata); + } + else { + PyObject *old_metadata = self->metadata; + self->metadata = metadata; + Py_XINCREF(self->metadata); + Py_XDECREF(old_metadata); + } + + Py_RETURN_NONE; +} + +/*NUMPY_API + * + * Get type-descriptor from an object forcing alignment if possible + * None goes to DEFAULT type. + * + * any object with the .fields attribute and/or .itemsize attribute (if the + *.fields attribute does not give the total size -- i.e. a partial record + * naming). If itemsize is given it must be >= size computed from fields + * + * The .fields attribute must return a convertible dictionary if present. + * Result inherits from NPY_VOID. +*/ +NPY_NO_EXPORT int +PyArray_DescrAlignConverter(PyObject *obj, PyArray_Descr **at) +{ + if (PyDict_Check(obj) || PyDictProxy_Check(obj)) { + *at = _convert_from_dict(obj, 1); + } + else if (PyBytes_Check(obj)) { + *at = _convert_from_commastring(obj, 1); + } + else if (PyUnicode_Check(obj)) { + PyObject *tmp; + tmp = PyUnicode_AsASCIIString(obj); + *at = _convert_from_commastring(tmp, 1); + Py_DECREF(tmp); + } + else if (PyList_Check(obj)) { + *at = _convert_from_array_descr(obj, 1); + } + else { + return PyArray_DescrConverter(obj, at); + } + if (*at == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "data-type-descriptor not understood"); + } + return NPY_FAIL; + } + return NPY_SUCCEED; +} + +/*NUMPY_API + * + * Get type-descriptor from an object forcing alignment if possible + * None goes to NULL. + */ +NPY_NO_EXPORT int +PyArray_DescrAlignConverter2(PyObject *obj, PyArray_Descr **at) +{ + if (PyDict_Check(obj) || PyDictProxy_Check(obj)) { + *at = _convert_from_dict(obj, 1); + } + else if (PyBytes_Check(obj)) { + *at = _convert_from_commastring(obj, 1); + } + else if (PyUnicode_Check(obj)) { + PyObject *tmp; + tmp = PyUnicode_AsASCIIString(obj); + *at = _convert_from_commastring(tmp, 1); + Py_DECREF(tmp); + } + else if (PyList_Check(obj)) { + *at = _convert_from_array_descr(obj, 1); + } + else { + return PyArray_DescrConverter2(obj, at); + } + if (*at == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "data-type-descriptor not understood"); + } + return NPY_FAIL; + } + return NPY_SUCCEED; +} + + + +/*NUMPY_API + * + * returns a copy of the PyArray_Descr structure with the byteorder + * altered: + * no arguments: The byteorder is swapped (in all subfields as well) + * single argument: The byteorder is forced to the given state + * (in all subfields as well) + * + * Valid states: ('big', '>') or ('little' or '<') + * ('native', or '=') + * + * If a descr structure with | is encountered it's own + * byte-order is not changed but any fields are: + * + * + * Deep bytorder change of a data-type descriptor + * *** Leaves reference count of self unchanged --- does not DECREF self *** + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_DescrNewByteorder(PyArray_Descr *self, char newendian) +{ + PyArray_Descr *new; + char endian; + + new = PyArray_DescrNew(self); + endian = new->byteorder; + if (endian != NPY_IGNORE) { + if (newendian == NPY_SWAP) { + /* swap byteorder */ + if (PyArray_ISNBO(endian)) { + endian = NPY_OPPBYTE; + } + else { + endian = NPY_NATBYTE; + } + new->byteorder = endian; + } + else if (newendian != NPY_IGNORE) { + new->byteorder = newendian; + } + } + if (PyDataType_HASFIELDS(new)) { + PyObject *newfields; + PyObject *key, *value; + PyObject *newvalue; + PyObject *old; + PyArray_Descr *newdescr; + Py_ssize_t pos = 0; + int len, i; + + newfields = PyDict_New(); + /* make new dictionary with replaced PyArray_Descr Objects */ + while (PyDict_Next(self->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyUString_Check(key) || !PyTuple_Check(value) || + ((len=PyTuple_GET_SIZE(value)) < 2)) { + continue; + } + old = PyTuple_GET_ITEM(value, 0); + if (!PyArray_DescrCheck(old)) { + continue; + } + newdescr = PyArray_DescrNewByteorder( + (PyArray_Descr *)old, newendian); + if (newdescr == NULL) { + Py_DECREF(newfields); Py_DECREF(new); + return NULL; + } + newvalue = PyTuple_New(len); + PyTuple_SET_ITEM(newvalue, 0, (PyObject *)newdescr); + for (i = 1; i < len; i++) { + old = PyTuple_GET_ITEM(value, i); + Py_INCREF(old); + PyTuple_SET_ITEM(newvalue, i, old); + } + PyDict_SetItem(newfields, key, newvalue); + Py_DECREF(newvalue); + } + Py_DECREF(new->fields); + new->fields = newfields; + } + if (PyDataType_HASSUBARRAY(new)) { + Py_DECREF(new->subarray->base); + new->subarray->base = PyArray_DescrNewByteorder( + self->subarray->base, newendian); + } + return new; +} + + +static PyObject * +arraydescr_newbyteorder(PyArray_Descr *self, PyObject *args) +{ + char endian=NPY_SWAP; + + if (!PyArg_ParseTuple(args, "|O&:newbyteorder", PyArray_ByteorderConverter, + &endian)) { + return NULL; + } + return (PyObject *)PyArray_DescrNewByteorder(self, endian); +} + +static PyMethodDef arraydescr_methods[] = { + /* for pickling */ + {"__reduce__", + (PyCFunction)arraydescr_reduce, + METH_VARARGS, NULL}, + {"__setstate__", + (PyCFunction)arraydescr_setstate, + METH_VARARGS, NULL}, + {"newbyteorder", + (PyCFunction)arraydescr_newbyteorder, + METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} /* sentinel */ +}; + +/* + * Checks whether the structured data type in 'dtype' + * has a simple layout, where all the fields are in order, + * and follow each other with no alignment padding. + * + * When this returns true, the dtype can be reconstructed + * from a list of the field names and dtypes with no additional + * dtype parameters. + * + * Returns 1 if it has a simple layout, 0 otherwise. + */ +NPY_NO_EXPORT int +is_dtype_struct_simple_unaligned_layout(PyArray_Descr *dtype) +{ + PyObject *names, *fields, *key, *tup, *title; + Py_ssize_t i, names_size; + PyArray_Descr *fld_dtype; + int fld_offset; + npy_intp total_offset; + + /* Get some properties from the dtype */ + names = dtype->names; + names_size = PyTuple_GET_SIZE(names); + fields = dtype->fields; + + /* Start at offset zero */ + total_offset = 0; + + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + if (key == NULL) { + return 0; + } + tup = PyDict_GetItem(fields, key); + if (tup == NULL) { + return 0; + } + if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) { + PyErr_Clear(); + return 0; + } + /* If this field doesn't follow the pattern, not a simple layout */ + if (total_offset != fld_offset) { + return 0; + } + /* Get the next offset */ + total_offset += fld_dtype->elsize; + } + + /* + * If the itemsize doesn't match the final offset, it's + * not a simple layout. + */ + if (total_offset != dtype->elsize) { + return 0; + } + + /* It's a simple layout, since all the above tests passed */ + return 1; +} + +/* + * Returns a string representation of a structured array, + * in a list format. + */ +static PyObject * +arraydescr_struct_list_str(PyArray_Descr *dtype) +{ + PyObject *names, *key, *fields, *ret, *tmp, *tup, *title; + Py_ssize_t i, names_size; + PyArray_Descr *fld_dtype; + int fld_offset; + + names = dtype->names; + names_size = PyTuple_GET_SIZE(names); + fields = dtype->fields; + + /* Build up a string to make the list */ + + /* Go through all the names */ + ret = PyUString_FromString("["); + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + tup = PyDict_GetItem(fields, key); + if (tup == NULL) { + return 0; + } + title = NULL; + if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) { + PyErr_Clear(); + return 0; + } + PyUString_ConcatAndDel(&ret, PyUString_FromString("(")); + /* Check for whether to do titles as well */ + if (title != NULL && title != Py_None) { + PyUString_ConcatAndDel(&ret, PyUString_FromString("(")); + PyUString_ConcatAndDel(&ret, PyObject_Repr(title)); + PyUString_ConcatAndDel(&ret, PyUString_FromString(", ")); + PyUString_ConcatAndDel(&ret, PyObject_Repr(key)); + PyUString_ConcatAndDel(&ret, PyUString_FromString("), ")); + } + else { + PyUString_ConcatAndDel(&ret, PyObject_Repr(key)); + PyUString_ConcatAndDel(&ret, PyUString_FromString(", ")); + } + /* Special case subarray handling here */ + if (PyDataType_HASSUBARRAY(fld_dtype)) { + tmp = arraydescr_construction_repr( + fld_dtype->subarray->base, 0, 1); + PyUString_ConcatAndDel(&ret, tmp); + PyUString_ConcatAndDel(&ret, PyUString_FromString(", ")); + PyUString_ConcatAndDel(&ret, + PyObject_Str(fld_dtype->subarray->shape)); + } + else { + tmp = arraydescr_construction_repr(fld_dtype, 0, 1); + PyUString_ConcatAndDel(&ret, tmp); + } + PyUString_ConcatAndDel(&ret, PyUString_FromString(")")); + if (i != names_size - 1) { + PyUString_ConcatAndDel(&ret, PyUString_FromString(", ")); + } + } + PyUString_ConcatAndDel(&ret, PyUString_FromString("]")); + + return ret; +} + +/* + * Returns a string representation of a structured array, + * in a dict format. + */ +static PyObject * +arraydescr_struct_dict_str(PyArray_Descr *dtype, int includealignedflag) +{ + PyObject *names, *key, *fields, *ret, *tmp, *tup, *title; + Py_ssize_t i, names_size; + PyArray_Descr *fld_dtype; + int fld_offset, has_titles; + + names = dtype->names; + names_size = PyTuple_GET_SIZE(names); + fields = dtype->fields; + has_titles = 0; + + /* Build up a string to make the dictionary */ + + /* First, the names */ + ret = PyUString_FromString("{'names':["); + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + PyUString_ConcatAndDel(&ret, PyObject_Repr(key)); + if (i != names_size - 1) { + PyUString_ConcatAndDel(&ret, PyUString_FromString(",")); + } + } + /* Second, the formats */ + PyUString_ConcatAndDel(&ret, PyUString_FromString("], 'formats':[")); + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + tup = PyDict_GetItem(fields, key); + if (tup == NULL) { + return 0; + } + title = NULL; + if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) { + PyErr_Clear(); + return 0; + } + /* Check for whether to do titles as well */ + if (title != NULL && title != Py_None) { + has_titles = 1; + } + tmp = arraydescr_construction_repr(fld_dtype, 0, 1); + PyUString_ConcatAndDel(&ret, tmp); + if (i != names_size - 1) { + PyUString_ConcatAndDel(&ret, PyUString_FromString(",")); + } + } + /* Third, the offsets */ + PyUString_ConcatAndDel(&ret, PyUString_FromString("], 'offsets':[")); + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + tup = PyDict_GetItem(fields, key); + if (tup == NULL) { + return 0; + } + if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) { + PyErr_Clear(); + return 0; + } + PyUString_ConcatAndDel(&ret, PyUString_FromFormat("%d", fld_offset)); + if (i != names_size - 1) { + PyUString_ConcatAndDel(&ret, PyUString_FromString(",")); + } + } + /* Fourth, the titles */ + if (has_titles) { + PyUString_ConcatAndDel(&ret, PyUString_FromString("], 'titles':[")); + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + tup = PyDict_GetItem(fields, key); + if (tup == NULL) { + return 0; + } + title = Py_None; + if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, + &fld_offset, &title)) { + PyErr_Clear(); + return 0; + } + PyUString_ConcatAndDel(&ret, PyObject_Repr(title)); + if (i != names_size - 1) { + PyUString_ConcatAndDel(&ret, PyUString_FromString(",")); + } + } + } + if (includealignedflag && (dtype->flags&NPY_ALIGNED_STRUCT)) { + /* Finally, the itemsize/itemsize and aligned flag */ + PyUString_ConcatAndDel(&ret, + PyUString_FromFormat("], 'itemsize':%d, 'aligned':True}", + (int)dtype->elsize)); + } + else { + /* Finally, the itemsize/itemsize*/ + PyUString_ConcatAndDel(&ret, + PyUString_FromFormat("], 'itemsize':%d}", (int)dtype->elsize)); + } + + return ret; +} + +/* Produces a string representation for a structured dtype */ +static PyObject * +arraydescr_struct_str(PyArray_Descr *dtype, int includealignflag) +{ + PyObject *sub; + + /* + * The list str representation can't include the 'align=' flag, + * so if it is requested and the struct has the aligned flag set, + * we must use the dict str instead. + */ + if (!(includealignflag && (dtype->flags&NPY_ALIGNED_STRUCT)) && + is_dtype_struct_simple_unaligned_layout(dtype)) { + sub = arraydescr_struct_list_str(dtype); + } + else { + sub = arraydescr_struct_dict_str(dtype, includealignflag); + } + + /* If the data type isn't the default, void, show it */ + if (dtype->typeobj != &PyVoidArrType_Type) { + /* + * Note: We cannot get the type name from dtype->typeobj->tp_name + * because its value depends on whether the type is dynamically or + * statically allocated. Instead use __name__ and __module__. + * See https://docs.python.org/2/c-api/typeobj.html. + */ + + PyObject *str_name, *namestr, *str_module, *modulestr, *ret; + + str_name = PyUString_FromString("__name__"); + namestr = PyObject_GetAttr((PyObject*)(dtype->typeobj), str_name); + Py_DECREF(str_name); + + if (namestr == NULL) { + /* this should never happen since types always have __name__ */ + PyErr_Format(PyExc_RuntimeError, + "dtype does not have a __name__ attribute"); + return NULL; + } + + str_module = PyUString_FromString("__module__"); + modulestr = PyObject_GetAttr((PyObject*)(dtype->typeobj), str_module); + Py_DECREF(str_module); + + ret = PyUString_FromString("("); + if (modulestr != NULL) { + /* Note: if modulestr == NULL, the type is unpicklable */ + PyUString_ConcatAndDel(&ret, modulestr); + PyUString_ConcatAndDel(&ret, PyUString_FromString(".")); + } + PyUString_ConcatAndDel(&ret, namestr); + PyUString_ConcatAndDel(&ret, PyUString_FromString(", ")); + PyUString_ConcatAndDel(&ret, sub); + PyUString_ConcatAndDel(&ret, PyUString_FromString(")")); + return ret; + } + else { + return sub; + } +} + +/* Produces a string representation for a subarray dtype */ +static PyObject * +arraydescr_subarray_str(PyArray_Descr *dtype) +{ + PyObject *p, *ret; + + ret = PyUString_FromString("("); + p = arraydescr_construction_repr(dtype->subarray->base, 0, 1); + PyUString_ConcatAndDel(&ret, p); + PyUString_ConcatAndDel(&ret, PyUString_FromString(", ")); + PyUString_ConcatAndDel(&ret, PyObject_Str(dtype->subarray->shape)); + PyUString_ConcatAndDel(&ret, PyUString_FromString(")")); + + return ret; +} + +static PyObject * +arraydescr_str(PyArray_Descr *dtype) +{ + PyObject *sub; + + if (PyDataType_HASFIELDS(dtype)) { + sub = arraydescr_struct_str(dtype, 1); + } + else if (PyDataType_HASSUBARRAY(dtype)) { + sub = arraydescr_subarray_str(dtype); + } + else if (PyDataType_ISFLEXIBLE(dtype) || !PyArray_ISNBO(dtype->byteorder)) { + sub = arraydescr_protocol_typestr_get(dtype); + } + else { + sub = arraydescr_typename_get(dtype); + } + return sub; +} + +/* + * The dtype repr function specifically for structured arrays. + */ +static PyObject * +arraydescr_struct_repr(PyArray_Descr *dtype) +{ + PyObject *sub, *s; + + s = PyUString_FromString("dtype("); + sub = arraydescr_struct_str(dtype, 0); + if (sub == NULL) { + return NULL; + } + + PyUString_ConcatAndDel(&s, sub); + + /* If it's an aligned structure, add the align=True parameter */ + if (dtype->flags&NPY_ALIGNED_STRUCT) { + PyUString_ConcatAndDel(&s, PyUString_FromString(", align=True")); + } + + PyUString_ConcatAndDel(&s, PyUString_FromString(")")); + return s; +} + +/* See descriptor.h for documentation */ +NPY_NO_EXPORT PyObject * +arraydescr_construction_repr(PyArray_Descr *dtype, int includealignflag, + int shortrepr) +{ + PyObject *ret; + PyArray_DatetimeMetaData *meta; + char byteorder[2]; + + if (PyDataType_HASFIELDS(dtype)) { + return arraydescr_struct_str(dtype, includealignflag); + } + else if (PyDataType_HASSUBARRAY(dtype)) { + return arraydescr_subarray_str(dtype); + } + + /* Normalize byteorder to '<' or '>' */ + switch (dtype->byteorder) { + case NPY_NATIVE: + byteorder[0] = NPY_NATBYTE; + break; + case NPY_SWAP: + byteorder[0] = NPY_OPPBYTE; + break; + case NPY_IGNORE: + byteorder[0] = '\0'; + break; + default: + byteorder[0] = dtype->byteorder; + break; + } + byteorder[1] = '\0'; + + /* Handle booleans, numbers, and custom dtypes */ + if (dtype->type_num == NPY_BOOL) { + if (shortrepr) { + return PyUString_FromString("'?'"); + } + else { + return PyUString_FromString("'bool'"); + } + } + else if (PyTypeNum_ISNUMBER(dtype->type_num)) { + /* Short repr with endianness, like 'byteorder != NPY_NATIVE && + dtype->byteorder != NPY_IGNORE)) { + return PyUString_FromFormat("'%s%c%d'", byteorder, + (int)dtype->kind, dtype->elsize); + } + /* Longer repr, like 'float64' */ + else { + char *kindstr; + switch (dtype->kind) { + case 'u': + kindstr = "uint"; + break; + case 'i': + kindstr = "int"; + break; + case 'f': + kindstr = "float"; + break; + case 'c': + kindstr = "complex"; + break; + default: + PyErr_Format(PyExc_RuntimeError, + "internal dtype repr error, unknown kind '%c'", + (int)dtype->kind); + return NULL; + } + return PyUString_FromFormat("'%s%d'", kindstr, 8*dtype->elsize); + } + } + else if (PyTypeNum_ISUSERDEF(dtype->type_num)) { + char *s = strrchr(dtype->typeobj->tp_name, '.'); + if (s == NULL) { + return PyUString_FromString(dtype->typeobj->tp_name); + } + else { + return PyUString_FromStringAndSize(s + 1, strlen(s) - 1); + } + } + + /* All the rest which don't fit in the same pattern */ + switch (dtype->type_num) { + /* + * The object reference may be different sizes on different + * platforms, so it should never include the itemsize here. + */ + case NPY_OBJECT: + return PyUString_FromString("'O'"); + + case NPY_STRING: + if (PyDataType_ISUNSIZED(dtype)) { + return PyUString_FromString("'S'"); + } + else { + return PyUString_FromFormat("'S%d'", (int)dtype->elsize); + } + + case NPY_UNICODE: + if (PyDataType_ISUNSIZED(dtype)) { + return PyUString_FromFormat("'%sU'", byteorder); + } + else { + return PyUString_FromFormat("'%sU%d'", byteorder, + (int)dtype->elsize / 4); + } + + case NPY_VOID: + if (PyDataType_ISUNSIZED(dtype)) { + return PyUString_FromString("'V'"); + } + else { + return PyUString_FromFormat("'V%d'", (int)dtype->elsize); + } + + case NPY_DATETIME: + meta = get_datetime_metadata_from_dtype(dtype); + if (meta == NULL) { + return NULL; + } + ret = PyUString_FromFormat("'%sM8", byteorder); + ret = append_metastr_to_string(meta, 0, ret); + PyUString_ConcatAndDel(&ret, PyUString_FromString("'")); + return ret; + + case NPY_TIMEDELTA: + meta = get_datetime_metadata_from_dtype(dtype); + if (meta == NULL) { + return NULL; + } + ret = PyUString_FromFormat("'%sm8", byteorder); + ret = append_metastr_to_string(meta, 0, ret); + PyUString_ConcatAndDel(&ret, PyUString_FromString("'")); + return ret; + + default: + PyErr_SetString(PyExc_RuntimeError, "Internal error: NumPy dtype " + "unrecognized type number"); + return NULL; + } +} + +/* + * The general dtype repr function. + */ +static PyObject * +arraydescr_repr(PyArray_Descr *dtype) +{ + PyObject *ret; + + if (PyDataType_HASFIELDS(dtype)) { + return arraydescr_struct_repr(dtype); + } + else { + ret = PyUString_FromString("dtype("); + PyUString_ConcatAndDel(&ret, + arraydescr_construction_repr(dtype, 1, 0)); + PyUString_ConcatAndDel(&ret, PyUString_FromString(")")); + return ret; + } +} + +static PyObject * +arraydescr_richcompare(PyArray_Descr *self, PyObject *other, int cmp_op) +{ + PyArray_Descr *new = NULL; + PyObject *result = Py_NotImplemented; + if (!PyArray_DescrCheck(other)) { + if (PyArray_DescrConverter(other, &new) == NPY_FAIL) { + return NULL; + } + } + else { + new = (PyArray_Descr *)other; + Py_INCREF(new); + } + switch (cmp_op) { + case Py_LT: + if (!PyArray_EquivTypes(self, new) && PyArray_CanCastTo(self, new)) { + result = Py_True; + } + else { + result = Py_False; + } + break; + case Py_LE: + if (PyArray_CanCastTo(self, new)) { + result = Py_True; + } + else { + result = Py_False; + } + break; + case Py_EQ: + if (PyArray_EquivTypes(self, new)) { + result = Py_True; + } + else { + result = Py_False; + } + break; + case Py_NE: + if (PyArray_EquivTypes(self, new)) + result = Py_False; + else + result = Py_True; + break; + case Py_GT: + if (!PyArray_EquivTypes(self, new) && PyArray_CanCastTo(new, self)) { + result = Py_True; + } + else { + result = Py_False; + } + break; + case Py_GE: + if (PyArray_CanCastTo(new, self)) { + result = Py_True; + } + else { + result = Py_False; + } + break; + default: + result = Py_NotImplemented; + } + + Py_XDECREF(new); + Py_INCREF(result); + return result; +} + +static int +descr_nonzero(PyObject *self) +{ + /* `bool(np.dtype(...)) == True` for all dtypes. Needed to override default + * nonzero implementation, which checks if `len(object) > 0`. */ + return 1; +} + +static PyNumberMethods descr_as_number = { + (binaryfunc)0, /* nb_add */ + (binaryfunc)0, /* nb_subtract */ + (binaryfunc)0, /* nb_multiply */ + #if defined(NPY_PY3K) + #else + (binaryfunc)0, /* nb_divide */ + #endif + (binaryfunc)0, /* nb_remainder */ + (binaryfunc)0, /* nb_divmod */ + (ternaryfunc)0, /* nb_power */ + (unaryfunc)0, /* nb_negative */ + (unaryfunc)0, /* nb_positive */ + (unaryfunc)0, /* nb_absolute */ + (inquiry)descr_nonzero, /* nb_nonzero */ +}; + +/************************************************************************* + **************** Implement Mapping Protocol *************************** + *************************************************************************/ + +static Py_ssize_t +descr_length(PyObject *self0) +{ + PyArray_Descr *self = (PyArray_Descr *)self0; + + if (PyDataType_HASFIELDS(self)) { + return PyTuple_GET_SIZE(self->names); + } + else { + return 0; + } +} + +static PyObject * +descr_repeat(PyObject *self, Py_ssize_t length) +{ + PyObject *tup; + PyArray_Descr *new; + if (length < 0) { + return PyErr_Format(PyExc_ValueError, + "Array length must be >= 0, not %"NPY_INTP_FMT, (npy_intp)length); + } + tup = Py_BuildValue("O" NPY_SSIZE_T_PYFMT, self, length); + if (tup == NULL) { + return NULL; + } + PyArray_DescrConverter(tup, &new); + Py_DECREF(tup); + return (PyObject *)new; +} + +static int +_check_has_fields(PyArray_Descr *self) +{ + if (!PyDataType_HASFIELDS(self)) { + PyObject *astr = arraydescr_str(self); +#if defined(NPY_PY3K) + PyObject *bstr = PyUnicode_AsUnicodeEscapeString(astr); + Py_DECREF(astr); + astr = bstr; +#endif + PyErr_Format(PyExc_KeyError, + "There are no fields in dtype %s.", PyBytes_AsString(astr)); + Py_DECREF(astr); + return -1; + } + else { + return 0; + } +} + +static PyObject * +_subscript_by_name(PyArray_Descr *self, PyObject *op) +{ + PyObject *obj = PyDict_GetItem(self->fields, op); + PyObject *descr; + PyObject *s; + + if (obj == NULL) { + if (PyUnicode_Check(op)) { + s = PyUnicode_AsUnicodeEscapeString(op); + } + else { + s = op; + } + + PyErr_Format(PyExc_KeyError, + "Field named \'%s\' not found.", PyBytes_AsString(s)); + if (s != op) { + Py_DECREF(s); + } + return NULL; + } + descr = PyTuple_GET_ITEM(obj, 0); + Py_INCREF(descr); + return descr; +} + +static PyObject * +_subscript_by_index(PyArray_Descr *self, Py_ssize_t i) +{ + PyObject *name = PySequence_GetItem(self->names, i); + if (name == NULL) { + PyErr_Format(PyExc_IndexError, + "Field index %zd out of range.", i); + return NULL; + } + return _subscript_by_name(self, name); +} + +static PyObject * +descr_subscript(PyArray_Descr *self, PyObject *op) +{ + if (_check_has_fields(self) < 0) { + return NULL; + } + + if (PyBaseString_Check(op)) { + return _subscript_by_name(self, op); + } + else { + Py_ssize_t i = PyArray_PyIntAsIntp(op); + if (error_converting(i)) { + /* if converting to an int gives a type error, adjust the message */ + PyObject *err = PyErr_Occurred(); + if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) { + PyErr_SetString(PyExc_TypeError, + "Field key must be an integer, string, or unicode."); + } + return NULL; + } + return _subscript_by_index(self, i); + } +} + +static PySequenceMethods descr_as_sequence = { + (lenfunc) descr_length, /* sq_length */ + (binaryfunc) NULL, /* sq_concat */ + (ssizeargfunc) descr_repeat, /* sq_repeat */ + (ssizeargfunc) NULL, /* sq_item */ + (ssizessizeargfunc) NULL, /* sq_slice */ + (ssizeobjargproc) NULL, /* sq_ass_item */ + (ssizessizeobjargproc) NULL, /* sq_ass_slice */ + (objobjproc) NULL, /* sq_contains */ + (binaryfunc) NULL, /* sq_inplace_concat */ + (ssizeargfunc) NULL, /* sq_inplace_repeat */ +}; + +static PyMappingMethods descr_as_mapping = { + descr_length, /* mp_length*/ + (binaryfunc)descr_subscript, /* mp_subscript*/ + (objobjargproc)NULL, /* mp_ass_subscript*/ +}; + +/****************** End of Mapping Protocol ******************************/ + +NPY_NO_EXPORT PyTypeObject PyArrayDescr_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.dtype", /* tp_name */ + sizeof(PyArray_Descr), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)arraydescr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + (void *)0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + (reprfunc)arraydescr_repr, /* tp_repr */ + &descr_as_number, /* tp_as_number */ + &descr_as_sequence, /* tp_as_sequence */ + &descr_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)arraydescr_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)arraydescr_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + arraydescr_methods, /* tp_methods */ + arraydescr_members, /* tp_members */ + arraydescr_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + arraydescr_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; diff --git a/numpy/core/src/multiarray/descriptor.h b/numpy/core/src/multiarray/descriptor.h new file mode 100644 index 0000000..f950411 --- /dev/null +++ b/numpy/core/src/multiarray/descriptor.h @@ -0,0 +1,45 @@ +#ifndef _NPY_ARRAYDESCR_H_ +#define _NPY_ARRAYDESCR_H_ + +NPY_NO_EXPORT PyObject *arraydescr_protocol_typestr_get(PyArray_Descr *); +NPY_NO_EXPORT PyObject *arraydescr_protocol_descr_get(PyArray_Descr *self); + +NPY_NO_EXPORT PyObject * +array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args); + +NPY_NO_EXPORT PyArray_Descr * +_arraydescr_fromobj(PyObject *obj); + + +NPY_NO_EXPORT int +is_dtype_struct_simple_unaligned_layout(PyArray_Descr *dtype); + +/* + * Creates a string repr of the dtype, excluding the 'dtype()' part + * surrounding the object. This object may be a string, a list, or + * a dict depending on the nature of the dtype. This + * is the object passed as the first parameter to the dtype + * constructor, and if no additional constructor parameters are + * given, will reproduce the exact memory layout. + * + * If 'shortrepr' is non-zero, this creates a shorter repr using + * 'kind' and 'itemsize', instead of the longer type name. + * + * If 'includealignflag' is true, this includes the 'align=True' parameter + * inside the struct dtype construction dict when needed. Use this flag + * if you want a proper repr string without the 'dtype()' part around it. + * + * If 'includealignflag' is false, this does not preserve the + * 'align=True' parameter or sticky NPY_ALIGNED_STRUCT flag for + * struct arrays like the regular repr does, because the 'align' + * flag is not part of first dtype constructor parameter. This + * mode is intended for a full 'repr', where the 'align=True' is + * provided as the second parameter. + */ +NPY_NO_EXPORT PyObject * +arraydescr_construction_repr(PyArray_Descr *dtype, int includealignflag, + int shortrepr); + +extern NPY_NO_EXPORT char *_datetime_strings[]; + +#endif diff --git a/numpy/core/src/multiarray/dragon4.c b/numpy/core/src/multiarray/dragon4.c new file mode 100644 index 0000000..e005234 --- /dev/null +++ b/numpy/core/src/multiarray/dragon4.c @@ -0,0 +1,2732 @@ +/* + * Copyright (c) 2014 Ryan Juckett + * http://www.ryanjuckett.com/ + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +/* + * This file contains a modified version of Ryan Juckett's Dragon4 + * implementation, which has been ported from C++ to C and which has + * modifications specific to printing floats in numpy. + */ + +#include "dragon4.h" +#include +#include +#include +#include + +#include + +#if 0 +#define DEBUG_ASSERT(stmnt) assert(stmnt) +#else +#define DEBUG_ASSERT(stmnt) do {} while(0) +#endif + +/* + * Get the log base 2 of a 32-bit unsigned integer. + * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup + */ +static npy_uint32 +LogBase2_32(npy_uint32 val) +{ + static const npy_uint8 logTable[256] = + { + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + }; + + npy_uint32 temp; + + temp = val >> 24; + if (temp) { + return 24 + logTable[temp]; + } + + temp = val >> 16; + if (temp) { + return 16 + logTable[temp]; + } + + temp = val >> 8; + if (temp) { + return 8 + logTable[temp]; + } + + return logTable[val]; +} + +static npy_uint32 +LogBase2_64(npy_uint64 val) +{ + npy_uint64 temp; + + temp = val >> 32; + if (temp) { + return 32 + LogBase2_32((npy_uint32)temp); + } + + return LogBase2_32((npy_uint32)val); +} + + +/* + * Maximum number of 32 bit blocks needed in high precision arithmetic to print + * out 128 bit IEEE floating point values. 1023 chosen to be large enough for + * 128 bit floats, and BigInt is exactly 4kb (nice for page/cache?) + */ +#define c_BigInt_MaxBlocks 1023 + +/* + * This structure stores a high precision unsigned integer. It uses a buffer of + * 32 bit integer blocks along with a length. The lowest bits of the integer + * are stored at the start of the buffer and the length is set to the minimum + * value that contains the integer. Thus, there are never any zero blocks at + * the end of the buffer. + */ +typedef struct BigInt { + npy_uint32 length; + npy_uint32 blocks[c_BigInt_MaxBlocks]; +} BigInt; + +/* Copy integer */ +static void +BigInt_Copy(BigInt *dst, const BigInt *src) +{ + npy_uint32 length = src->length; + npy_uint32 * dstp = dst->blocks; + const npy_uint32 *srcp; + for (srcp = src->blocks; srcp != src->blocks + length; ++dstp, ++srcp) { + *dstp = *srcp; + } + dst->length = length; +} + +/* Basic type accessors */ +static void +BigInt_Set_uint64(BigInt *i, npy_uint64 val) +{ + if (val > 0xFFFFFFFF) { + i->blocks[0] = val & 0xFFFFFFFF; + i->blocks[1] = (val >> 32) & 0xFFFFFFFF; + i->length = 2; + } + else if (val != 0) { + i->blocks[0] = val & 0xFFFFFFFF; + i->length = 1; + } + else { + i->length = 0; + } +} + +static void +BigInt_Set_uint32(BigInt *i, npy_uint32 val) +{ + if (val != 0) { + i->blocks[0] = val; + i->length = (val != 0); + } + else { + i->length = 0; + } +} + +/* + * Returns 0 if (lhs = rhs), negative if (lhs < rhs), positive if (lhs > rhs) + */ +static npy_int32 +BigInt_Compare(const BigInt *lhs, const BigInt *rhs) +{ + int i; + + /* A bigger length implies a bigger number. */ + npy_int32 lengthDiff = lhs->length - rhs->length; + if (lengthDiff != 0) { + return lengthDiff; + } + + /* Compare blocks one by one from high to low. */ + for (i = lhs->length - 1; i >= 0; --i) { + if (lhs->blocks[i] == rhs->blocks[i]) { + continue; + } + else if (lhs->blocks[i] > rhs->blocks[i]) { + return 1; + } + else { + return -1; + } + } + + /* no blocks differed */ + return 0; +} + +/* result = lhs + rhs */ +static void +BigInt_Add(BigInt *result, const BigInt *lhs, const BigInt *rhs) +{ + /* determine which operand has the smaller length */ + const BigInt *large, *small; + npy_uint64 carry = 0; + const npy_uint32 *largeCur, *smallCur, *largeEnd, *smallEnd; + npy_uint32 *resultCur; + + if (lhs->length < rhs->length) { + small = lhs; + large = rhs; + } + else { + small = rhs; + large = lhs; + } + + /* The output will be at least as long as the largest input */ + result->length = large->length; + + /* Add each block and add carry the overflow to the next block */ + largeCur = large->blocks; + largeEnd = largeCur + large->length; + smallCur = small->blocks; + smallEnd = smallCur + small->length; + resultCur = result->blocks; + while (smallCur != smallEnd) { + npy_uint64 sum = carry + (npy_uint64)(*largeCur) + + (npy_uint64)(*smallCur); + carry = sum >> 32; + *resultCur = sum & 0xFFFFFFFF; + ++largeCur; + ++smallCur; + ++resultCur; + } + + /* Add the carry to any blocks that only exist in the large operand */ + while (largeCur != largeEnd) { + npy_uint64 sum = carry + (npy_uint64)(*largeCur); + carry = sum >> 32; + (*resultCur) = sum & 0xFFFFFFFF; + ++largeCur; + ++resultCur; + } + + /* If there's still a carry, append a new block */ + if (carry != 0) { + DEBUG_ASSERT(carry == 1); + DEBUG_ASSERT((npy_uint32)(resultCur - result->blocks) == + large->length && (large->length < c_BigInt_MaxBlocks)); + *resultCur = 1; + result->length = large->length + 1; + } + else { + result->length = large->length; + } +} + +/* + * result = lhs * rhs + */ +static void +BigInt_Multiply(BigInt *result, const BigInt *lhs, const BigInt *rhs) +{ + const BigInt *large; + const BigInt *small; + npy_uint32 maxResultLen; + npy_uint32 *cur, *end, *resultStart; + const npy_uint32 *smallCur; + + DEBUG_ASSERT(result != lhs && result != rhs); + + /* determine which operand has the smaller length */ + if (lhs->length < rhs->length) { + small = lhs; + large = rhs; + } + else { + small = rhs; + large = lhs; + } + + /* set the maximum possible result length */ + maxResultLen = large->length + small->length; + DEBUG_ASSERT(maxResultLen <= c_BigInt_MaxBlocks); + + /* clear the result data */ + for (cur = result->blocks, end = cur + maxResultLen; cur != end; ++cur) { + *cur = 0; + } + + /* perform standard long multiplication for each small block */ + resultStart = result->blocks; + for (smallCur = small->blocks; + smallCur != small->blocks + small->length; + ++smallCur, ++resultStart) { + /* + * if non-zero, multiply against all the large blocks and add into the + * result + */ + const npy_uint32 multiplier = *smallCur; + if (multiplier != 0) { + const npy_uint32 *largeCur = large->blocks; + npy_uint32 *resultCur = resultStart; + npy_uint64 carry = 0; + do { + npy_uint64 product = (*resultCur) + + (*largeCur)*(npy_uint64)multiplier + carry; + carry = product >> 32; + *resultCur = product & 0xFFFFFFFF; + ++largeCur; + ++resultCur; + } while(largeCur != large->blocks + large->length); + + DEBUG_ASSERT(resultCur < result->blocks + maxResultLen); + *resultCur = (npy_uint32)(carry & 0xFFFFFFFF); + } + } + + /* check if the terminating block has no set bits */ + if (maxResultLen > 0 && result->blocks[maxResultLen - 1] == 0) { + result->length = maxResultLen-1; + } + else { + result->length = maxResultLen; + } +} + +/* result = lhs * rhs */ +static void +BigInt_Multiply_int(BigInt *result, const BigInt *lhs, npy_uint32 rhs) +{ + /* perform long multiplication */ + npy_uint32 carry = 0; + npy_uint32 *resultCur = result->blocks; + const npy_uint32 *pLhsCur = lhs->blocks; + const npy_uint32 *pLhsEnd = lhs->blocks + lhs->length; + for ( ; pLhsCur != pLhsEnd; ++pLhsCur, ++resultCur) { + npy_uint64 product = (npy_uint64)(*pLhsCur) * rhs + carry; + *resultCur = (npy_uint32)(product & 0xFFFFFFFF); + carry = product >> 32; + } + + /* if there is a remaining carry, grow the array */ + if (carry != 0) { + /* grow the array */ + DEBUG_ASSERT(lhs->length + 1 <= c_BigInt_MaxBlocks); + *resultCur = (npy_uint32)carry; + result->length = lhs->length + 1; + } + else { + result->length = lhs->length; + } +} + +/* result = in * 2 */ +static void +BigInt_Multiply2(BigInt *result, const BigInt *in) +{ + /* shift all the blocks by one */ + npy_uint32 carry = 0; + + npy_uint32 *resultCur = result->blocks; + const npy_uint32 *pLhsCur = in->blocks; + const npy_uint32 *pLhsEnd = in->blocks + in->length; + for ( ; pLhsCur != pLhsEnd; ++pLhsCur, ++resultCur) { + npy_uint32 cur = *pLhsCur; + *resultCur = (cur << 1) | carry; + carry = cur >> 31; + } + + if (carry != 0) { + /* grow the array */ + DEBUG_ASSERT(in->length + 1 <= c_BigInt_MaxBlocks); + *resultCur = carry; + result->length = in->length + 1; + } + else { + result->length = in->length; + } +} + +/* result = result * 2 */ +static void +BigInt_Multiply2_inplace(BigInt *result) +{ + /* shift all the blocks by one */ + npy_uint32 carry = 0; + + npy_uint32 *cur = result->blocks; + npy_uint32 *end = result->blocks + result->length; + for ( ; cur != end; ++cur) { + npy_uint32 tmpcur = *cur; + *cur = (tmpcur << 1) | carry; + carry = tmpcur >> 31; + } + + if (carry != 0) { + /* grow the array */ + DEBUG_ASSERT(result->length + 1 <= c_BigInt_MaxBlocks); + *cur = carry; + ++result->length; + } +} + +/* result = result * 10 */ +static void +BigInt_Multiply10(BigInt *result) +{ + /* multiply all the blocks */ + npy_uint64 carry = 0; + + npy_uint32 *cur = result->blocks; + npy_uint32 *end = result->blocks + result->length; + for ( ; cur != end; ++cur) { + npy_uint64 product = (npy_uint64)(*cur) * 10ull + carry; + (*cur) = (npy_uint32)(product & 0xFFFFFFFF); + carry = product >> 32; + } + + if (carry != 0) { + /* grow the array */ + DEBUG_ASSERT(result->length + 1 <= c_BigInt_MaxBlocks); + *cur = (npy_uint32)carry; + ++result->length; + } +} + +static npy_uint32 g_PowerOf10_U32[] = +{ + 1, /* 10 ^ 0 */ + 10, /* 10 ^ 1 */ + 100, /* 10 ^ 2 */ + 1000, /* 10 ^ 3 */ + 10000, /* 10 ^ 4 */ + 100000, /* 10 ^ 5 */ + 1000000, /* 10 ^ 6 */ + 10000000, /* 10 ^ 7 */ +}; + +/* + * Note: This has a lot of wasted space in the big integer structures of the + * early table entries. It wouldn't be terribly hard to make the multiply + * function work on integer pointers with an array length instead of + * the BigInt struct which would allow us to store a minimal amount of + * data here. + */ +static BigInt g_PowerOf10_Big[] = +{ + /* 10 ^ 8 */ + { 1, { 100000000 } }, + /* 10 ^ 16 */ + { 2, { 0x6fc10000, 0x002386f2 } }, + /* 10 ^ 32 */ + { 4, { 0x00000000, 0x85acef81, 0x2d6d415b, 0x000004ee, } }, + /* 10 ^ 64 */ + { 7, { 0x00000000, 0x00000000, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, + 0xe93ff9f4, 0x00184f03, } }, + /* 10 ^ 128 */ + { 14, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2e953e01, + 0x03df9909, 0x0f1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, + 0xbccdb0da, 0xa6337f19, 0xe91f2603, 0x0000024e, } }, + /* 10 ^ 256 */ + { 27, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x982e7c01, 0xbed3875b, + 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f, + 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, + 0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, + 0x5fdcefce, 0x000553f7, } }, + /* 10 ^ 512 */ + { 54, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xfc6cf801, 0x77f27267, 0x8f9546dc, 0x5d96976f, + 0xb83a8a97, 0xc31e1ad9, 0x46c40513, 0x94e65747, 0xc88976c1, + 0x4475b579, 0x28f8733b, 0xaa1da1bf, 0x703ed321, 0x1e25cfea, + 0xb21a2f22, 0xbc51fb2e, 0x96e14f5d, 0xbfa3edac, 0x329c57ae, + 0xe7fc7153, 0xc3fc0695, 0x85a91924, 0xf95f635e, 0xb2908ee0, + 0x93abade4, 0x1366732a, 0x9449775c, 0x69be5b0e, 0x7343afac, + 0xb099bc81, 0x45a71d46, 0xa2699748, 0x8cb07303, 0x8a0b1f13, + 0x8cab8a97, 0xc1d238d9, 0x633415d4, 0x0000001c, } }, + /* 10 ^ 1024 */ + { 107, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x2919f001, 0xf55b2b72, 0x6e7c215b, + 0x1ec29f86, 0x991c4e87, 0x15c51a88, 0x140ac535, 0x4c7d1e1a, + 0xcc2cd819, 0x0ed1440e, 0x896634ee, 0x7de16cfb, 0x1e43f61f, + 0x9fce837d, 0x231d2b9c, 0x233e55c7, 0x65dc60d7, 0xf451218b, + 0x1c5cd134, 0xc9635986, 0x922bbb9f, 0xa7e89431, 0x9f9f2a07, + 0x62be695a, 0x8e1042c4, 0x045b7a74, 0x1abe1de3, 0x8ad822a5, + 0xba34c411, 0xd814b505, 0xbf3fdeb3, 0x8fc51a16, 0xb1b896bc, + 0xf56deeec, 0x31fb6bfd, 0xb6f4654b, 0x101a3616, 0x6b7595fb, + 0xdc1a47fe, 0x80d98089, 0x80bda5a5, 0x9a202882, 0x31eb0f66, + 0xfc8f1f90, 0x976a3310, 0xe26a7b7e, 0xdf68368a, 0x3ce3a0b8, + 0x8e4262ce, 0x75a351a2, 0x6cb0b6c9, 0x44597583, 0x31b5653f, + 0xc356e38a, 0x35faaba6, 0x0190fba0, 0x9fc4ed52, 0x88bc491b, + 0x1640114a, 0x005b8041, 0xf4f3235e, 0x1e8d4649, 0x36a8de06, + 0x73c55349, 0xa7e6bd2a, 0xc1a6970c, 0x47187094, 0xd2db49ef, + 0x926c3f5b, 0xae6209d4, 0x2d433949, 0x34f4a3c6, 0xd4305d94, + 0xd9d61a05, 0x00000325, } }, + /* 10 ^ 2048 */ + { 213, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1333e001, + 0xe3096865, 0xb27d4d3f, 0x49e28dcf, 0xec2e4721, 0xee87e354, + 0xb6067584, 0x368b8abb, 0xa5e5a191, 0x2ed56d55, 0xfd827773, + 0xea50d142, 0x51b78db2, 0x98342c9e, 0xc850dabc, 0x866ed6f1, + 0x19342c12, 0x92794987, 0xd2f869c2, 0x66912e4a, 0x71c7fd8f, + 0x57a7842d, 0x235552eb, 0xfb7fedcc, 0xf3861ce0, 0x38209ce1, + 0x9713b449, 0x34c10134, 0x8c6c54de, 0xa7a8289c, 0x2dbb6643, + 0xe3cb64f3, 0x8074ff01, 0xe3892ee9, 0x10c17f94, 0xa8f16f92, + 0xa8281ed6, 0x967abbb3, 0x5a151440, 0x9952fbed, 0x13b41e44, + 0xafe609c3, 0xa2bca416, 0xf111821f, 0xfb1264b4, 0x91bac974, + 0xd6c7d6ab, 0x8e48ff35, 0x4419bd43, 0xc4a65665, 0x685e5510, + 0x33554c36, 0xab498697, 0x0dbd21fe, 0x3cfe491d, 0x982da466, + 0xcbea4ca7, 0x9e110c7b, 0x79c56b8a, 0x5fc5a047, 0x84d80e2e, + 0x1aa9f444, 0x730f203c, 0x6a57b1ab, 0xd752f7a6, 0x87a7dc62, + 0x944545ff, 0x40660460, 0x77c1a42f, 0xc9ac375d, 0xe866d7ef, + 0x744695f0, 0x81428c85, 0xa1fc6b96, 0xd7917c7b, 0x7bf03c19, + 0x5b33eb41, 0x5715f791, 0x8f6cae5f, 0xdb0708fd, 0xb125ac8e, + 0x785ce6b7, 0x56c6815b, 0x6f46eadb, 0x4eeebeee, 0x195355d8, + 0xa244de3c, 0x9d7389c0, 0x53761abd, 0xcf99d019, 0xde9ec24b, + 0x0d76ce39, 0x70beb181, 0x2e55ecee, 0xd5f86079, 0xf56d9d4b, + 0xfb8886fb, 0x13ef5a83, 0x408f43c5, 0x3f3389a4, 0xfad37943, + 0x58ccf45c, 0xf82df846, 0x415c7f3e, 0x2915e818, 0x8b3d5cf4, + 0x6a445f27, 0xf8dbb57a, 0xca8f0070, 0x8ad803ec, 0xb2e87c34, + 0x038f9245, 0xbedd8a6c, 0xc7c9dee0, 0x0eac7d56, 0x2ad3fa14, + 0xe0de0840, 0xf775677c, 0xf1bd0ad5, 0x92be221e, 0x87fa1fb9, + 0xce9d04a4, 0xd2c36fa9, 0x3f6f7024, 0xb028af62, 0x907855ee, + 0xd83e49d6, 0x4efac5dc, 0xe7151aab, 0x77cd8c6b, 0x0a753b7d, + 0x0af908b4, 0x8c983623, 0xe50f3027, 0x94222771, 0x1d08e2d6, + 0xf7e928e6, 0xf2ee5ca6, 0x1b61b93c, 0x11eb962b, 0x9648b21c, + 0xce2bcba1, 0x34f77154, 0x7bbebe30, 0xe526a319, 0x8ce329ac, + 0xde4a74d2, 0xb5dc53d5, 0x0009e8b3, } }, + /* 10 ^ 4096 */ + { 426, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x2a67c001, 0xd4724e8d, + 0x8efe7ae7, 0xf89a1e90, 0xef084117, 0x54e05154, 0x13b1bb51, + 0x506be829, 0xfb29b172, 0xe599574e, 0xf0da6146, 0x806c0ed3, + 0xb86ae5be, 0x45155e93, 0xc0591cc2, 0x7e1e7c34, 0x7c4823da, + 0x1d1f4cce, 0x9b8ba1e8, 0xd6bfdf75, 0xe341be10, 0xc2dfae78, + 0x016b67b2, 0x0f237f1a, 0x3dbeabcd, 0xaf6a2574, 0xcab3e6d7, + 0x142e0e80, 0x61959127, 0x2c234811, 0x87009701, 0xcb4bf982, + 0xf8169c84, 0x88052f8c, 0x68dde6d4, 0xbc131761, 0xff0b0905, + 0x54ab9c41, 0x7613b224, 0x1a1c304e, 0x3bfe167b, 0x441c2d47, + 0x4f6cea9c, 0x78f06181, 0xeb659fb8, 0x30c7ae41, 0x947e0d0e, + 0xa1ebcad7, 0xd97d9556, 0x2130504d, 0x1a8309cb, 0xf2acd507, + 0x3f8ec72a, 0xfd82373a, 0x95a842bc, 0x280f4d32, 0xf3618ac0, + 0x811a4f04, 0x6dc3a5b4, 0xd3967a1b, 0x15b8c898, 0xdcfe388f, + 0x454eb2a0, 0x8738b909, 0x10c4e996, 0x2bd9cc11, 0x3297cd0c, + 0x655fec30, 0xae0725b1, 0xf4090ee8, 0x037d19ee, 0x398c6fed, + 0x3b9af26b, 0xc994a450, 0xb5341743, 0x75a697b2, 0xac50b9c1, + 0x3ccb5b92, 0xffe06205, 0xa8329761, 0xdfea5242, 0xeb83cadb, + 0xe79dadf7, 0x3c20ee69, 0x1e0a6817, 0x7021b97a, 0x743074fa, + 0x176ca776, 0x77fb8af6, 0xeca19beb, 0x92baf1de, 0xaf63b712, + 0xde35c88b, 0xa4eb8f8c, 0xe137d5e9, 0x40b464a0, 0x87d1cde8, + 0x42923bbd, 0xcd8f62ff, 0x2e2690f3, 0x095edc16, 0x59c89f1b, + 0x1fa8fd5d, 0x5138753d, 0x390a2b29, 0x80152f18, 0x2dd8d925, + 0xf984d83e, 0x7a872e74, 0xc19e1faf, 0xed4d542d, 0xecf9b5d0, + 0x9462ea75, 0xc53c0adf, 0x0caea134, 0x37a2d439, 0xc8fa2e8a, + 0x2181327e, 0x6e7bb827, 0x2d240820, 0x50be10e0, 0x5893d4b8, + 0xab312bb9, 0x1f2b2322, 0x440b3f25, 0xbf627ede, 0x72dac789, + 0xb608b895, 0x78787e2a, 0x86deb3f0, 0x6fee7aab, 0xbb9373f4, + 0x27ecf57b, 0xf7d8b57e, 0xfca26a9f, 0x3d04e8d2, 0xc9df13cb, + 0x3172826a, 0xcd9e8d7c, 0xa8fcd8e0, 0xb2c39497, 0x307641d9, + 0x1cc939c1, 0x2608c4cf, 0xb6d1c7bf, 0x3d326a7e, 0xeeaf19e6, + 0x8e13e25f, 0xee63302b, 0x2dfe6d97, 0x25971d58, 0xe41d3cc4, + 0x0a80627c, 0xab8db59a, 0x9eea37c8, 0xe90afb77, 0x90ca19cf, + 0x9ee3352c, 0x3613c850, 0xfe78d682, 0x788f6e50, 0x5b060904, + 0xb71bd1a4, 0x3fecb534, 0xb32c450c, 0x20c33857, 0xa6e9cfda, + 0x0239f4ce, 0x48497187, 0xa19adb95, 0xb492ed8a, 0x95aca6a8, + 0x4dcd6cd9, 0xcf1b2350, 0xfbe8b12a, 0x1a67778c, 0x38eb3acc, + 0xc32da383, 0xfb126ab1, 0xa03f40a8, 0xed5bf546, 0xe9ce4724, + 0x4c4a74fd, 0x73a130d8, 0xd9960e2d, 0xa2ebd6c1, 0x94ab6feb, + 0x6f233b7c, 0x49126080, 0x8e7b9a73, 0x4b8c9091, 0xd298f999, + 0x35e836b5, 0xa96ddeff, 0x96119b31, 0x6b0dd9bc, 0xc6cc3f8d, + 0x282566fb, 0x72b882e7, 0xd6769f3b, 0xa674343d, 0x00fc509b, + 0xdcbf7789, 0xd6266a3f, 0xae9641fd, 0x4e89541b, 0x11953407, + 0x53400d03, 0x8e0dd75a, 0xe5b53345, 0x108f19ad, 0x108b89bc, + 0x41a4c954, 0xe03b2b63, 0x437b3d7f, 0x97aced8e, 0xcbd66670, + 0x2c5508c2, 0x650ebc69, 0x5c4f2ef0, 0x904ff6bf, 0x9985a2df, + 0x9faddd9e, 0x5ed8d239, 0x25585832, 0xe3e51cb9, 0x0ff4f1d4, + 0x56c02d9a, 0x8c4ef804, 0xc1a08a13, 0x13fd01c8, 0xe6d27671, + 0xa7c234f4, 0x9d0176cc, 0xd0d73df2, 0x4d8bfa89, 0x544f10cd, + 0x2b17e0b2, 0xb70a5c7d, 0xfd86fe49, 0xdf373f41, 0x214495bb, + 0x84e857fd, 0x00d313d5, 0x0496fcbe, 0xa4ba4744, 0xe8cac982, + 0xaec29e6e, 0x87ec7038, 0x7000a519, 0xaeee333b, 0xff66e42c, + 0x8afd6b25, 0x03b4f63b, 0xbd7991dc, 0x5ab8d9c7, 0x2ed4684e, + 0x48741a6c, 0xaf06940d, 0x2fdc6349, 0xb03d7ecd, 0xe974996f, + 0xac7867f9, 0x52ec8721, 0xbcdd9d4a, 0x8edd2d00, 0x3557de06, + 0x41c759f8, 0x3956d4b9, 0xa75409f2, 0x123cd8a1, 0xb6100fab, + 0x3e7b21e2, 0x2e8d623b, 0x92959da2, 0xbca35f77, 0x200c03a5, + 0x35fcb457, 0x1bb6c6e4, 0xf74eb928, 0x3d5d0b54, 0x87cc1d21, + 0x4964046f, 0x18ae4240, 0xd868b275, 0x8bd2b496, 0x1c5563f4, + 0xc234d8f5, 0xf868e970, 0xf9151fff, 0xae7be4a2, 0x271133ee, + 0xbb0fd922, 0x25254932, 0xa60a9fc0, 0x104bcd64, 0x30290145, + 0x00000062, } }, +}; + +/* result = 10^exponent */ +static void +BigInt_Pow10(BigInt *result, npy_uint32 exponent) +{ + /* create two temporary values to reduce large integer copy operations */ + BigInt temp1; + BigInt temp2; + BigInt *curTemp = &temp1; + BigInt *pNextTemp = &temp2; + npy_uint32 smallExponent; + npy_uint32 tableIdx = 0; + + /* make sure the exponent is within the bounds of the lookup table data */ + DEBUG_ASSERT(exponent < 8192); + + /* + * initialize the result by looking up a 32-bit power of 10 corresponding to + * the first 3 bits + */ + smallExponent = exponent & 0x7; + BigInt_Set_uint32(curTemp, g_PowerOf10_U32[smallExponent]); + + /* remove the low bits that we used for the 32-bit lookup table */ + exponent >>= 3; + + /* while there are remaining bits in the exponent to be processed */ + while (exponent != 0) { + /* if the current bit is set, multiply by this power of 10 */ + if (exponent & 1) { + BigInt *pSwap; + + /* multiply into the next temporary */ + BigInt_Multiply(pNextTemp, curTemp, &g_PowerOf10_Big[tableIdx]); + + /* swap to the next temporary */ + pSwap = curTemp; + curTemp = pNextTemp; + pNextTemp = pSwap; + } + + /* advance to the next bit */ + ++tableIdx; + exponent >>= 1; + } + + /* output the result */ + BigInt_Copy(result, curTemp); +} + +/* result = in * 10^exponent */ +static void +BigInt_MultiplyPow10(BigInt *result, const BigInt *in, npy_uint32 exponent) +{ + + /* create two temporary values to reduce large integer copy operations */ + BigInt temp1; + BigInt temp2; + BigInt *curTemp = &temp1; + BigInt *pNextTemp = &temp2; + npy_uint32 smallExponent; + npy_uint32 tableIdx = 0; + + /* make sure the exponent is within the bounds of the lookup table data */ + DEBUG_ASSERT(exponent < 8192); + + /* + * initialize the result by looking up a 32-bit power of 10 corresponding to + * the first 3 bits + */ + smallExponent = exponent & 0x7; + if (smallExponent != 0) { + BigInt_Multiply_int(curTemp, in, g_PowerOf10_U32[smallExponent]); + } + else { + BigInt_Copy(curTemp, in); + } + + /* remove the low bits that we used for the 32-bit lookup table */ + exponent >>= 3; + + /* while there are remaining bits in the exponent to be processed */ + while (exponent != 0) { + /* if the current bit is set, multiply by this power of 10 */ + if (exponent & 1) { + BigInt *pSwap; + + /* multiply into the next temporary */ + BigInt_Multiply(pNextTemp, curTemp, &g_PowerOf10_Big[tableIdx]); + + // swap to the next temporary + pSwap = curTemp; + curTemp = pNextTemp; + pNextTemp = pSwap; + } + + /* advance to the next bit */ + ++tableIdx; + exponent >>= 1; + } + + /* output the result */ + BigInt_Copy(result, curTemp); +} + +/* result = 2^exponent */ +static inline void +BigInt_Pow2(BigInt *result, npy_uint32 exponent) +{ + npy_uint32 bitIdx; + npy_uint32 blockIdx = exponent / 32; + npy_uint32 i; + + DEBUG_ASSERT(blockIdx < c_BigInt_MaxBlocks); + + for (i = 0; i <= blockIdx; ++i) { + result->blocks[i] = 0; + } + + result->length = blockIdx + 1; + + bitIdx = (exponent % 32); + result->blocks[blockIdx] |= (1 << bitIdx); +} + +/* + * This function will divide two large numbers under the assumption that the + * result is within the range [0,10) and the input numbers have been shifted + * to satisfy: + * - The highest block of the divisor is greater than or equal to 8 such that + * there is enough precision to make an accurate first guess at the quotient. + * - The highest block of the divisor is less than the maximum value on an + * unsigned 32-bit integer such that we can safely increment without overflow. + * - The dividend does not contain more blocks than the divisor such that we + * can estimate the quotient by dividing the equivalently placed high blocks. + * + * quotient = floor(dividend / divisor) + * remainder = dividend - quotient*divisor + * + * dividend is updated to be the remainder and the quotient is returned. + */ +static npy_uint32 +BigInt_DivideWithRemainder_MaxQuotient9(BigInt *dividend, const BigInt *divisor) +{ + npy_uint32 length, quotient; + const npy_uint32 *finalDivisorBlock; + npy_uint32 *finalDividendBlock; + + /* + * Check that the divisor has been correctly shifted into range and that it + * is not smaller than the dividend in length. + */ + DEBUG_ASSERT(!divisor->length == 0 && + divisor->blocks[divisor->length-1] >= 8 && + divisor->blocks[divisor->length-1] < 0xFFFFFFFF && + dividend->length <= divisor->length); + + /* + * If the dividend is smaller than the divisor, the quotient is zero and the + * divisor is already the remainder. + */ + length = divisor->length; + if (dividend->length < divisor->length) { + return 0; + } + + finalDivisorBlock = divisor->blocks + length - 1; + finalDividendBlock = dividend->blocks + length - 1; + + /* + * Compute an estimated quotient based on the high block value. This will + * either match the actual quotient or undershoot by one. + */ + quotient = *finalDividendBlock / (*finalDivisorBlock + 1); + DEBUG_ASSERT(quotient <= 9); + + /* Divide out the estimated quotient */ + if (quotient != 0) { + /* dividend = dividend - divisor*quotient */ + const npy_uint32 *divisorCur = divisor->blocks; + npy_uint32 *dividendCur = dividend->blocks; + + npy_uint64 borrow = 0; + npy_uint64 carry = 0; + do { + npy_uint64 difference, product; + + product = (npy_uint64)*divisorCur * (npy_uint64)quotient + carry; + carry = product >> 32; + + difference = (npy_uint64)*dividendCur + - (product & 0xFFFFFFFF) - borrow; + borrow = (difference >> 32) & 1; + + *dividendCur = difference & 0xFFFFFFFF; + + ++divisorCur; + ++dividendCur; + } while(divisorCur <= finalDivisorBlock); + + /* remove all leading zero blocks from dividend */ + while (length > 0 && dividend->blocks[length - 1] == 0) { + --length; + } + + dividend->length = length; + } + + /* + * If the dividend is still larger than the divisor, we overshot our + * estimate quotient. To correct, we increment the quotient and subtract one + * more divisor from the dividend. + */ + if (BigInt_Compare(dividend, divisor) >= 0) { + /* dividend = dividend - divisor */ + const npy_uint32 *divisorCur = divisor->blocks; + npy_uint32 *dividendCur = dividend->blocks; + npy_uint64 borrow = 0; + + ++quotient; + + do { + npy_uint64 difference = (npy_uint64)*dividendCur + - (npy_uint64)*divisorCur - borrow; + borrow = (difference >> 32) & 1; + + *dividendCur = difference & 0xFFFFFFFF; + + ++divisorCur; + ++dividendCur; + } while(divisorCur <= finalDivisorBlock); + + /* remove all leading zero blocks from dividend */ + while (length > 0 && dividend->blocks[length - 1] == 0) { + --length; + } + + dividend->length = length; + } + + return quotient; +} + +/* result = result << shift */ +static void +BigInt_ShiftLeft(BigInt *result, npy_uint32 shift) +{ + npy_uint32 shiftBlocks = shift / 32; + npy_uint32 shiftBits = shift % 32; + + /* process blocks high to low so that we can safely process in place */ + const npy_uint32 *pInBlocks = result->blocks; + npy_int32 inLength = result->length; + npy_uint32 *pInCur, *pOutCur; + + DEBUG_ASSERT(inLength + shiftBlocks < c_BigInt_MaxBlocks); + DEBUG_ASSERT(shift != 0); + + /* check if the shift is block aligned */ + if (shiftBits == 0) { + npy_uint32 i; + + /* copy blocks from high to low */ + for (pInCur = result->blocks + result->length, + pOutCur = pInCur + shiftBlocks; + pInCur >= pInBlocks; + --pInCur, --pOutCur) { + *pOutCur = *pInCur; + } + + /* zero the remaining low blocks */ + for (i = 0; i < shiftBlocks; ++i) { + result->blocks[i] = 0; + } + + result->length += shiftBlocks; + } + /* else we need to shift partial blocks */ + else { + npy_uint32 i; + npy_int32 inBlockIdx = inLength - 1; + npy_uint32 outBlockIdx = inLength + shiftBlocks; + + /* output the initial blocks */ + const npy_uint32 lowBitsShift = (32 - shiftBits); + npy_uint32 highBits = 0; + npy_uint32 block = result->blocks[inBlockIdx]; + npy_uint32 lowBits = block >> lowBitsShift; + + /* set the length to hold the shifted blocks */ + DEBUG_ASSERT(outBlockIdx < c_BigInt_MaxBlocks); + result->length = outBlockIdx + 1; + + while (inBlockIdx > 0) { + result->blocks[outBlockIdx] = highBits | lowBits; + highBits = block << shiftBits; + + --inBlockIdx; + --outBlockIdx; + + block = result->blocks[inBlockIdx]; + lowBits = block >> lowBitsShift; + } + + /* output the final blocks */ + DEBUG_ASSERT(outBlockIdx == shiftBlocks + 1); + result->blocks[outBlockIdx] = highBits | lowBits; + result->blocks[outBlockIdx-1] = block << shiftBits; + + /* zero the remaining low blocks */ + for (i = 0; i < shiftBlocks; ++i) { + result->blocks[i] = 0; + } + + /* check if the terminating block has no set bits */ + if (result->blocks[result->length - 1] == 0) { + --result->length; + } + } +} + + +/* + * This is an implementation the Dragon4 algorithm to convert a binary number in + * floating point format to a decimal number in string format. The function + * returns the number of digits written to the output buffer and the output is + * not NUL terminated. + * + * The floating point input value is (mantissa * 2^exponent). + * + * See the following papers for more information on the algorithm: + * "How to Print Floating-Point Numbers Accurately" + * Steele and White + * http://kurtstephens.com/files/p372-steele.pdf + * "Printing Floating-Point Numbers Quickly and Accurately" + * Burger and Dybvig + * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.4656 + * + * This implementation is essentially a port of the "Figure 3" Scheme code from + * Burger and Dybvig, but with the following additional differences: + * 1. Instead of finding the highest k such that high < B**k, we search + * for the one where v < B**k. This has a downside that if a power + * of 10 exists between v and high, we will output a 9 instead of a 1 as + * first digit, violating the "no-carry" guarantee of the paper. This is + * accounted for in a new post-processing loop which implements a carry + * operation. The upside is one less BigInt multiplication. + * 2. The approximate value of k found is offset by a different amount + * (0.69), in order to hit the "fast" branch more often. This is + * extensively described on Ryan Juckett's website. + * 3. The fixed precision mode is much simpler than proposed in the paper. + * It simply outputs digits by repeatedly dividing by 10. The new "carry" + * loop at the end rounds this output nicely. + * There is also some new code to account for details of the BigInt + * implementation, which are not present in the paper since it does not specify + * details of the integer calculations. + * + * There is some more documentation of these changes on Ryan Juckett's website + * at http://www.ryanjuckett.com/programming/printing-floating-point-numbers/ + * + * Ryan Juckett's implementation did not implement "IEEE unbiased rounding", + * except in the last digit. This has been added back, following the Burger & + * Dybvig code, using the isEven variable. + * + * Arguments: + * * mantissa - value significand + * * exponent - value exponent in base 2 + * * mantissaBit - index of the highest set mantissa bit + * * hasUnequalMargins - is the high margin twice as large as the low margin + * * cutoffMode - how to interpret cutoffNumber: fractional or total digits? + * * cutoffNumber - cut off printing after this many digits. -1 for no cutoff + * * pOutBuffer - buffer to output into + * * bufferSize - maximum characters that can be printed to pOutBuffer + * * pOutExponent - the base 10 exponent of the first digit + */ +static npy_uint32 +Dragon4(const npy_uint64 mantissa, const npy_int32 exponent, + const npy_uint32 mantissaBit, const npy_bool hasUnequalMargins, + const DigitMode digitMode, const CutoffMode cutoffMode, + npy_int32 cutoffNumber, char *pOutBuffer, + npy_uint32 bufferSize, npy_int32 *pOutExponent) +{ + char *curDigit = pOutBuffer; + + /* + * We compute values in integer format by rescaling as + * mantissa = scaledValue / scale + * marginLow = scaledMarginLow / scale + * marginHigh = scaledMarginHigh / scale + * Here, marginLow and marginHigh represent 1/2 of the distance to the next + * floating point value above/below the mantissa. + * + * scaledMarginHigh is a pointer so that it can point to scaledMarginLow in + * the case they must be equal to each other, otherwise it will point to + * optionalMarginHigh. + */ + BigInt scale; + BigInt scaledValue; + BigInt scaledMarginLow; + BigInt *scaledMarginHigh; + BigInt optionalMarginHigh; + + const npy_float64 log10_2 = 0.30102999566398119521373889472449; + npy_int32 digitExponent, cutoffExponent, hiBlock; + npy_uint32 outputDigit; /* current digit being output */ + npy_uint32 outputLen; + npy_bool isEven = (mantissa % 2) == 0; + npy_int32 cmp; + + /* values used to determine how to round */ + npy_bool low, high, roundDown; + + DEBUG_ASSERT(bufferSize > 0); + + /* if the mantissa is zero, the value is zero regardless of the exponent */ + if (mantissa == 0) { + *curDigit = '0'; + *pOutExponent = 0; + return 1; + } + + if (hasUnequalMargins) { + /* if we have no fractional component */ + if (exponent > 0) { + /* + * 1) Expand the input value by multiplying out the mantissa and + * exponent. This represents the input value in its whole number + * representation. + * 2) Apply an additional scale of 2 such that later comparisons + * against the margin values are simplified. + * 3) Set the margin value to the lowest mantissa bit's scale. + */ + + /* scaledValue = 2 * 2 * mantissa*2^exponent */ + BigInt_Set_uint64(&scaledValue, mantissa); + BigInt_ShiftLeft(&scaledValue, exponent + 2); + + /* scale = 2 * 2 * 1 */ + BigInt_Set_uint32(&scale, 4); + + /* scaledMarginLow = 2 * 2^(exponent-1) */ + BigInt_Pow2(&scaledMarginLow, exponent); + + /* scaledMarginHigh = 2 * 2 * 2^(exponent-1) */ + BigInt_Pow2(&optionalMarginHigh, exponent + 1); + } + /* else we have a fractional exponent */ + else { + /* + * In order to track the mantissa data as an integer, we store it as + * is with a large scale + */ + + /* scaledValue = 2 * 2 * mantissa */ + BigInt_Set_uint64(&scaledValue, mantissa); + BigInt_ShiftLeft(&scaledValue, 2); + + /* scale = 2 * 2 * 2^(-exponent) */ + BigInt_Pow2(&scale, -exponent + 2); + + /* scaledMarginLow = 2 * 2^(-1) */ + BigInt_Set_uint32(&scaledMarginLow, 1); + + /* scaledMarginHigh = 2 * 2 * 2^(-1) */ + BigInt_Set_uint32(&optionalMarginHigh, 2); + } + + /* the high and low margins are different */ + scaledMarginHigh = &optionalMarginHigh; + } + else { + /* if we have no fractional component */ + if (exponent > 0) { + /* scaledValue = 2 * mantissa*2^exponent */ + BigInt_Set_uint64(&scaledValue, mantissa); + BigInt_ShiftLeft(&scaledValue, exponent + 1); + + /* scale = 2 * 1 */ + BigInt_Set_uint32(&scale, 2); + + /* scaledMarginLow = 2 * 2^(exponent-1) */ + BigInt_Pow2(&scaledMarginLow, exponent); + } + /* else we have a fractional exponent */ + else { + /* + * In order to track the mantissa data as an integer, we store it as + * is with a large scale + */ + + /* scaledValue = 2 * mantissa */ + BigInt_Set_uint64(&scaledValue, mantissa); + BigInt_ShiftLeft(&scaledValue, 1); + + /* scale = 2 * 2^(-exponent) */ + BigInt_Pow2(&scale, -exponent + 1); + + /* scaledMarginLow = 2 * 2^(-1) */ + BigInt_Set_uint32(&scaledMarginLow, 1); + } + + /* the high and low margins are equal */ + scaledMarginHigh = &scaledMarginLow; + } + + /* + * Compute an estimate for digitExponent that will be correct or undershoot + * by one. This optimization is based on the paper "Printing Floating-Point + * Numbers Quickly and Accurately" by Burger and Dybvig + * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.4656 + * We perform an additional subtraction of 0.69 to increase the frequency of + * a failed estimate because that lets us take a faster branch in the code. + * 0.69 is chosen because 0.69 + log10(2) is less than one by a reasonable + * epsilon that will account for any floating point error. + * + * We want to set digitExponent to floor(log10(v)) + 1 + * v = mantissa*2^exponent + * log2(v) = log2(mantissa) + exponent; + * log10(v) = log2(v) * log10(2) + * floor(log2(v)) = mantissaBit + exponent; + * log10(v) - log10(2) < (mantissaBit + exponent) * log10(2) <= log10(v) + * log10(v) < (mantissaBit + exponent) * log10(2) + log10(2) + * <= log10(v) + log10(2) + * floor(log10(v)) < ceil((mantissaBit + exponent) * log10(2)) + * <= floor(log10(v)) + 1 + */ + digitExponent = (npy_int32)( + ceil((npy_float64)((npy_int32)mantissaBit + exponent) * log10_2 - 0.69)); + + /* + * if the digit exponent is smaller than the smallest desired digit for + * fractional cutoff, pull the digit back into legal range at which point we + * will round to the appropriate value. Note that while our value for + * digitExponent is still an estimate, this is safe because it only + * increases the number. This will either correct digitExponent to an + * accurate value or it will clamp it above the accurate value. + */ + if (cutoffNumber >= 0 && cutoffMode == CutoffMode_FractionLength && + digitExponent <= -cutoffNumber) { + digitExponent = -cutoffNumber + 1; + } + + + /* Divide value by 10^digitExponent. */ + if (digitExponent > 0) { + /* A positive exponent creates a division so we multiply the scale. */ + BigInt temp; + BigInt_MultiplyPow10(&temp, &scale, digitExponent); + BigInt_Copy(&scale, &temp); + } + else if (digitExponent < 0) { + /* + * A negative exponent creates a multiplication so we multiply up the + * scaledValue, scaledMarginLow and scaledMarginHigh. + */ + BigInt pow10, temp; + BigInt_Pow10(&pow10, -digitExponent); + + BigInt_Multiply(&temp, &scaledValue, &pow10); + BigInt_Copy(&scaledValue, &temp); + + BigInt_Multiply(&temp, &scaledMarginLow, &pow10); + BigInt_Copy(&scaledMarginLow, &temp); + + if (scaledMarginHigh != &scaledMarginLow) { + BigInt_Multiply2(scaledMarginHigh, &scaledMarginLow); + } + } + + /* If (value >= 1), our estimate for digitExponent was too low */ + if (BigInt_Compare(&scaledValue, &scale) >= 0) { + /* + * The exponent estimate was incorrect. + * Increment the exponent and don't perform the premultiply needed + * for the first loop iteration. + */ + digitExponent = digitExponent + 1; + } + else { + /* + * The exponent estimate was correct. + * Multiply larger by the output base to prepare for the first loop + * iteration. + */ + BigInt_Multiply10(&scaledValue); + BigInt_Multiply10(&scaledMarginLow); + if (scaledMarginHigh != &scaledMarginLow) { + BigInt_Multiply2(scaledMarginHigh, &scaledMarginLow); + } + } + + /* + * Compute the cutoff exponent (the exponent of the final digit to print). + * Default to the maximum size of the output buffer. + */ + cutoffExponent = digitExponent - bufferSize; + if (cutoffNumber >= 0) { + npy_int32 desiredCutoffExponent; + + if (cutoffMode == CutoffMode_TotalLength) { + desiredCutoffExponent = digitExponent - cutoffNumber; + if (desiredCutoffExponent > cutoffExponent) { + cutoffExponent = desiredCutoffExponent; + } + } + /* Otherwise it's CutoffMode_FractionLength. Print cutoffNumber digits + * past the decimal point or until we reach the buffer size + */ + else { + desiredCutoffExponent = -cutoffNumber; + if (desiredCutoffExponent > cutoffExponent) { + cutoffExponent = desiredCutoffExponent; + } + } + } + + /* Output the exponent of the first digit we will print */ + *pOutExponent = digitExponent-1; + + /* + * In preparation for calling BigInt_DivideWithRemainder_MaxQuotient9(), we + * need to scale up our values such that the highest block of the + * denominator is greater than or equal to 8. We also need to guarantee that + * the numerator can never have a length greater than the denominator after + * each loop iteration. This requires the highest block of the denominator + * to be less than or equal to 429496729 which is the highest number that + * can be multiplied by 10 without overflowing to a new block. + */ + DEBUG_ASSERT(scale.length > 0); + hiBlock = scale.blocks[scale.length - 1]; + if (hiBlock < 8 || hiBlock > 429496729) { + npy_uint32 hiBlockLog2, shift; + + /* + * Perform a bit shift on all values to get the highest block of the + * denominator into the range [8,429496729]. We are more likely to make + * accurate quotient estimations in + * BigInt_DivideWithRemainder_MaxQuotient9() with higher denominator + * values so we shift the denominator to place the highest bit at index + * 27 of the highest block. This is safe because (2^28 - 1) = 268435455 + * which is less than 429496729. This means that all values with a + * highest bit at index 27 are within range. + */ + hiBlockLog2 = LogBase2_32(hiBlock); + DEBUG_ASSERT(hiBlockLog2 < 3 || hiBlockLog2 > 27); + shift = (32 + 27 - hiBlockLog2) % 32; + + BigInt_ShiftLeft(&scale, shift); + BigInt_ShiftLeft(&scaledValue, shift); + BigInt_ShiftLeft(&scaledMarginLow, shift); + if (scaledMarginHigh != &scaledMarginLow) { + BigInt_Multiply2(scaledMarginHigh, &scaledMarginLow); + } + } + + if (digitMode == DigitMode_Unique) { + /* + * For the unique cutoff mode, we will try to print until we have + * reached a level of precision that uniquely distinguishes this value + * from its neighbors. If we run out of space in the output buffer, we + * terminate early. + */ + for (;;) { + BigInt scaledValueHigh; + + digitExponent = digitExponent-1; + + /* divide out the scale to extract the digit */ + outputDigit = + BigInt_DivideWithRemainder_MaxQuotient9(&scaledValue, &scale); + DEBUG_ASSERT(outputDigit < 10); + + /* update the high end of the value */ + BigInt_Add(&scaledValueHigh, &scaledValue, scaledMarginHigh); + + /* + * stop looping if we are far enough away from our neighboring + * values or if we have reached the cutoff digit + */ + cmp = BigInt_Compare(&scaledValue, &scaledMarginLow); + low = isEven ? (cmp <= 0) : (cmp < 0); + cmp = BigInt_Compare(&scaledValueHigh, &scale); + high = isEven ? (cmp >= 0) : (cmp > 0); + if (low | high | (digitExponent == cutoffExponent)) + break; + + /* store the output digit */ + *curDigit = (char)('0' + outputDigit); + ++curDigit; + + /* multiply larger by the output base */ + BigInt_Multiply10(&scaledValue); + BigInt_Multiply10(&scaledMarginLow); + if (scaledMarginHigh != &scaledMarginLow) { + BigInt_Multiply2(scaledMarginHigh, &scaledMarginLow); + } + } + } + else { + /* + * For exact digit mode, we will try to print until we + * have exhausted all precision (i.e. all remaining digits are zeros) or + * until we reach the desired cutoff digit. + */ + low = NPY_FALSE; + high = NPY_FALSE; + + for (;;) { + digitExponent = digitExponent-1; + + /* divide out the scale to extract the digit */ + outputDigit = + BigInt_DivideWithRemainder_MaxQuotient9(&scaledValue, &scale); + DEBUG_ASSERT(outputDigit < 10); + + if ((scaledValue.length == 0) | (digitExponent == cutoffExponent)) { + break; + } + + /* store the output digit */ + *curDigit = (char)('0' + outputDigit); + ++curDigit; + + /* multiply larger by the output base */ + BigInt_Multiply10(&scaledValue); + } + } + + /* default to rounding down the final digit if value got too close to 0 */ + roundDown = low; + + /* if it is legal to round up and down */ + if (low == high) { + npy_int32 compare; + + /* + * round to the closest digit by comparing value with 0.5. To do this we + * need to convert the inequality to large integer values. + * compare( value, 0.5 ) + * compare( scale * value, scale * 0.5 ) + * compare( 2 * scale * value, scale ) + */ + BigInt_Multiply2_inplace(&scaledValue); + compare = BigInt_Compare(&scaledValue, &scale); + roundDown = compare < 0; + + /* + * if we are directly in the middle, round towards the even digit (i.e. + * IEEE rounding rules) + */ + if (compare == 0) { + roundDown = (outputDigit & 1) == 0; + } + } + + /* print the rounded digit */ + if (roundDown) { + *curDigit = (char)('0' + outputDigit); + ++curDigit; + } + else { + /* handle rounding up */ + if (outputDigit == 9) { + /* find the first non-nine prior digit */ + for (;;) { + /* if we are at the first digit */ + if (curDigit == pOutBuffer) { + /* output 1 at the next highest exponent */ + *curDigit = '1'; + ++curDigit; + *pOutExponent += 1; + break; + } + + --curDigit; + if (*curDigit != '9') { + /* increment the digit */ + *curDigit += 1; + ++curDigit; + break; + } + } + } + else { + /* values in the range [0,8] can perform a simple round up */ + *curDigit = (char)('0' + outputDigit + 1); + ++curDigit; + } + } + + /* return the number of digits output */ + outputLen = (npy_uint32)(curDigit - pOutBuffer); + DEBUG_ASSERT(outputLen <= bufferSize); + return outputLen; +} + + +/* + * Helper union to decompose a 16-bit IEEE float. + * sign: 1 bit + * exponent: 5 bits + * mantissa: 10 bits + */ +typedef union FloatUnion16 +{ + npy_uint16 integer; +} FloatUnion16; + +npy_bool IsNegative_F16(FloatUnion16 *v) { return (v->integer >> 15) != 0; } +npy_uint32 GetExponent_F16(FloatUnion16 *v) { return (v->integer >> 10) & 0x1F;} +npy_uint32 GetMantissa_F16(FloatUnion16 *v) { return v->integer & 0x3FF; } + + +/* + * Helper union to decompose a 32-bit IEEE float. + * sign: 1 bit + * exponent: 8 bits + * mantissa: 23 bits + */ +typedef union FloatUnion32 +{ + npy_float32 floatingPoint; + npy_uint32 integer; +} FloatUnion32; + +npy_bool IsNegative_F32(FloatUnion32 *v) { return (v->integer >> 31) != 0; } +npy_uint32 GetExponent_F32(FloatUnion32 *v) { return (v->integer >> 23) & 0xFF;} +npy_uint32 GetMantissa_F32(FloatUnion32 *v) { return v->integer & 0x7FFFFF; } + +/* + * Helper union to decompose a 64-bit IEEE float. + * sign: 1 bit + * exponent: 11 bits + * mantissa: 52 bits + */ +typedef union FloatUnion64 +{ + npy_float64 floatingPoint; + npy_uint64 integer; +} FloatUnion64; +npy_bool IsNegative_F64(FloatUnion64 *v) { return (v->integer >> 63) != 0; } +npy_uint32 GetExponent_F64(FloatUnion64 *v) { return (v->integer >> 52) & 0x7FF; } +npy_uint64 GetMantissa_F64(FloatUnion64 *v) { return v->integer & 0xFFFFFFFFFFFFFull; } + +/* + * Helper unions and datatype to decompose a 80-bit IEEE float + * sign: 1 bit, second u64 + * exponent: 15 bits, second u64 + * intbit 1 bit, first u64 + * mantissa: 63 bits, first u64 + */ + +/* + * Since systems have different types of long doubles, and may not necessarily + * have a 128-byte format we can use to pass values around, here we create + * our own 128-bit storage type for convenience. + */ +typedef struct FloatVal128 { + npy_uint64 integer[2]; +} FloatVal128; +npy_bool IsNegative_F128(FloatVal128 *v) { + return ((v->integer[1] >> 15) & 0x1) != 0; +} +npy_uint32 GetExponent_F128(FloatVal128 *v) { return v->integer[1] & 0x7FFF; } +npy_uint64 GetMantissa_F128(FloatVal128 *v) { + return v->integer[0] & 0x7FFFFFFFFFFFFFFFull; +} + +/* + * then for each different definition of long double, we create a union to + * unpack the float data safely. We can then copy these integers to a + * FloatVal128. + */ +#ifdef NPY_FLOAT128 +typedef union FloatUnion128 +{ + npy_float128 floatingPoint; + struct { + npy_uint64 a; + npy_uint16 b; + } integer; +} FloatUnion128; +#endif + +#ifdef NPY_FLOAT96 +typedef union FloatUnion96 +{ + npy_float96 floatingPoint; + struct { + npy_uint64 a; + npy_uint32 b; + } integer; +} FloatUnion96; +#endif + +#ifdef NPY_FLOAT80 +typedef union FloatUnion80 +{ + npy_float80 floatingPoint; + struct { + npy_uint64 a; + npy_uint16 b; + } integer; +} FloatUnion80; +#endif + + +/* + * The main changes above this point, relative to Ryan Juckett's code, are: + * 1. fixed overflow problems when mantissa was 64 bits (in float128 types), + * by replacing multiplication by 2 or 4 by BigInt_ShiftLeft calls. + * 2. Increased c_BigInt_MaxBlocks + * 3. Added more entries to the g_PowerOf10_Big table + * 4. Added unbiased rounding calculation with isEven + * + * Below this point, the FormatPositional and FormatScientific functions have + * been more significantly rewritten. The Dragon4_PrintFloat16 and + * Dragon4_PrintFloat128 functions are new, and were adapted from the 64 and 32 + * bit versions. The python interfacing functions (in the header) are new. + */ + + +/* + * Outputs the positive number with positional notation: ddddd.dddd + * The output is always NUL terminated and the output length (not including the + * NUL) is returned. + * Arguments: + * buffer - buffer to output into + * bufferSize - maximum characters that can be printed to buffer + * mantissa - value significand + * exponent - value exponent in base 2 + * signbit - value of the sign position. Should be '+', '-' or '' + * mantissaBit - index of the highest set mantissa bit + * hasUnequalMargins - is the high margin twice as large as the low margin + * precision - Negative prints as many digits as are needed for a unique + * number. Positive specifies the maximum number of significant + * digits to print past the decimal point. + * trim_mode - how to treat trailing 0s and '.'. See TrimMode comments. + * digits_left - pad characters to left of decimal point. -1 for no padding + * digits_right - pad characters to right of decimal point. -1 for no padding + * padding adds whitespace until there are the specified + * number characters to sides of decimal point. Applies after + * trim_mode characters were removed. If digits_right is + * positive and the decimal point was trimmed, decimal point + * will be replaced by a whitespace character. + */ +static npy_uint32 +FormatPositional(char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa, + npy_int32 exponent, char signbit, npy_uint32 mantissaBit, + npy_bool hasUnequalMargins, DigitMode digit_mode, + CutoffMode cutoff_mode, npy_int32 precision, + TrimMode trim_mode, npy_int32 digits_left, + npy_int32 digits_right) +{ + npy_int32 printExponent; + npy_int32 numDigits, numWholeDigits=0, has_sign=0; + + npy_int32 maxPrintLen = (npy_int32)bufferSize - 1, pos = 0; + + /* track the # of digits past the decimal point that have been printed */ + npy_int32 numFractionDigits = 0, desiredFractionalDigits; + + DEBUG_ASSERT(bufferSize > 0); + + if (digit_mode != DigitMode_Unique) { + DEBUG_ASSERT(precision >= 0); + } + + if (signbit == '+' && pos < maxPrintLen) { + buffer[pos++] = '+'; + has_sign = 1; + } + else if (signbit == '-' && pos < maxPrintLen) { + buffer[pos++] = '-'; + has_sign = 1; + } + + numDigits = Dragon4(mantissa, exponent, mantissaBit, hasUnequalMargins, + digit_mode, cutoff_mode, precision, buffer + has_sign, + maxPrintLen - has_sign, &printExponent); + + DEBUG_ASSERT(numDigits > 0); + DEBUG_ASSERT(numDigits <= bufferSize); + + /* if output has a whole number */ + if (printExponent >= 0) { + /* leave the whole number at the start of the buffer */ + numWholeDigits = printExponent+1; + if (numDigits <= numWholeDigits) { + npy_int32 count = numWholeDigits - numDigits; + pos += numDigits; + + /* don't overflow the buffer */ + if (pos + count > maxPrintLen) { + count = maxPrintLen - pos; + } + + /* add trailing zeros up to the decimal point */ + numDigits += count; + for ( ; count > 0; count--) { + buffer[pos++] = '0'; + } + } + /* insert the decimal point prior to the fraction */ + else if (numDigits > numWholeDigits) { + npy_int32 maxFractionDigits; + + numFractionDigits = numDigits - numWholeDigits; + maxFractionDigits = maxPrintLen - numWholeDigits - 1 - pos; + if (numFractionDigits > maxFractionDigits) { + numFractionDigits = maxFractionDigits; + } + + memmove(buffer + pos + numWholeDigits + 1, + buffer + pos + numWholeDigits, numFractionDigits); + pos += numWholeDigits; + buffer[pos] = '.'; + numDigits = numWholeDigits + 1 + numFractionDigits; + pos += 1 + numFractionDigits; + } + } + else { + /* shift out the fraction to make room for the leading zeros */ + npy_int32 numFractionZeros = 0; + if (pos + 2 < maxPrintLen) { + npy_int32 maxFractionZeros, digitsStartIdx, maxFractionDigits, i; + + maxFractionZeros = maxPrintLen - 2 - pos; + numFractionZeros = -(printExponent + 1); + if (numFractionZeros > maxFractionZeros) { + numFractionZeros = maxFractionZeros; + } + + digitsStartIdx = 2 + numFractionZeros; + + /* + * shift the significant digits right such that there is room for + * leading zeros + */ + numFractionDigits = numDigits; + maxFractionDigits = maxPrintLen - digitsStartIdx - pos; + if (numFractionDigits > maxFractionDigits) { + numFractionDigits = maxFractionDigits; + } + + memmove(buffer + pos + digitsStartIdx, buffer + pos, + numFractionDigits); + + /* insert the leading zeros */ + for (i = 2; i < digitsStartIdx; ++i) { + buffer[pos + i] = '0'; + } + + /* update the counts */ + numFractionDigits += numFractionZeros; + numDigits = numFractionDigits; + } + + /* add the decimal point */ + if (pos + 1 < maxPrintLen) { + buffer[pos+1] = '.'; + } + + /* add the initial zero */ + if (pos < maxPrintLen) { + buffer[pos] = '0'; + numDigits += 1; + } + numWholeDigits = 1; + pos += 2 + numFractionDigits; + } + + /* always add decimal point, except for DprZeros mode */ + if (trim_mode != TrimMode_DptZeros && numFractionDigits == 0 && + pos < maxPrintLen){ + buffer[pos++] = '.'; + } + + desiredFractionalDigits = precision; + if (cutoff_mode == CutoffMode_TotalLength && precision >= 0) { + desiredFractionalDigits = precision - numWholeDigits; + } + + if (trim_mode == TrimMode_LeaveOneZero) { + /* if we didn't print any fractional digits, add a trailing 0 */ + if (numFractionDigits == 0 && pos < maxPrintLen) { + buffer[pos++] = '0'; + numFractionDigits++; + } + } + else if (trim_mode == TrimMode_None && + digit_mode != DigitMode_Unique && + desiredFractionalDigits > numFractionDigits && + pos < maxPrintLen) { + /* add trailing zeros up to precision length */ + /* compute the number of trailing zeros needed */ + npy_int32 count = desiredFractionalDigits - numFractionDigits; + if (pos + count > maxPrintLen) { + count = maxPrintLen - pos; + } + numFractionDigits += count; + + for ( ; count > 0; count--) { + buffer[pos++] = '0'; + } + } + /* else, for trim_mode Zeros or DptZeros, there is nothing more to add */ + + /* + * when rounding, we may still end up with trailing zeros. Remove them + * depending on trim settings. + */ + if (precision >= 0 && trim_mode != TrimMode_None && numFractionDigits > 0){ + while (buffer[pos-1] == '0') { + pos--; + numFractionDigits--; + } + if (trim_mode == TrimMode_LeaveOneZero && buffer[pos-1] == '.') { + buffer[pos++] = '0'; + numFractionDigits++; + } + } + + /* add any whitespace padding to right side */ + if (digits_right >= numFractionDigits) { + npy_int32 count = digits_right - numFractionDigits; + + /* in trim_mode DptZeros, if right padding, add a space for the . */ + if (trim_mode == TrimMode_DptZeros && numFractionDigits == 0 + && pos < maxPrintLen) { + buffer[pos++] = ' '; + } + + if (pos + count > maxPrintLen) { + count = maxPrintLen - pos; + } + + for ( ; count > 0; count--) { + buffer[pos++] = ' '; + } + } + /* add any whitespace padding to left side */ + if (digits_left > numWholeDigits + has_sign) { + npy_int32 shift = digits_left - (numWholeDigits + has_sign); + npy_int32 count = pos; + + if (count + shift > maxPrintLen){ + count = maxPrintLen - shift; + } + + if (count > 0) { + memmove(buffer + shift, buffer, count); + } + pos = shift + count; + for ( ; shift > 0; shift--) { + buffer[shift - 1] = ' '; + } + } + + /* terminate the buffer */ + DEBUG_ASSERT(pos <= maxPrintLen); + buffer[pos] = '\0'; + + return pos; +} + +/* + * Outputs the positive number with scientific notation: d.dddde[sign]ddd + * The output is always NUL terminated and the output length (not including the + * NUL) is returned. + * Arguments: + * buffer - buffer to output into + * bufferSize - maximum characters that can be printed to buffer + * mantissa - value significand + * exponent - value exponent in base 2 + * signbit - value of the sign position. Should be '+', '-' or '' + * mantissaBit - index of the highest set mantissa bit + * hasUnequalMargins - is the high margin twice as large as the low margin + * precision - Negative prints as many digits as are needed for a unique + * number. Positive specifies the maximum number of significant + * digits to print past the decimal point. + * trim_mode - how to treat trailing 0s and '.'. See TrimMode comments. + * digits_left - pad characters to left of decimal point. -1 for no padding + * exp_digits - pads exponent with zeros until it has this many digits + */ +static npy_uint32 +FormatScientific (char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa, + npy_int32 exponent, char signbit, npy_uint32 mantissaBit, + npy_bool hasUnequalMargins, DigitMode digit_mode, + npy_int32 precision, TrimMode trim_mode, + npy_int32 digits_left, npy_int32 exp_digits) +{ + npy_int32 printExponent; + npy_int32 numDigits; + char *pCurOut; + npy_int32 numFractionDigits; + npy_int32 leftchars; + + if (digit_mode != DigitMode_Unique) { + DEBUG_ASSERT(precision >= 0); + } + + + DEBUG_ASSERT(bufferSize > 0); + + pCurOut = buffer; + + /* add any whitespace padding to left side */ + leftchars = 1 + (signbit == '-' || signbit == '+'); + if (digits_left > leftchars) { + int i; + for (i = 0; i < digits_left - leftchars && bufferSize > 1; i++){ + *pCurOut = ' '; + pCurOut++; + --bufferSize; + } + } + + if (signbit == '+' && bufferSize > 1) { + *pCurOut = '+'; + pCurOut++; + --bufferSize; + } + else if (signbit == '-' && bufferSize > 1) { + *pCurOut = '-'; + pCurOut++; + --bufferSize; + } + + numDigits = Dragon4(mantissa, exponent, mantissaBit, hasUnequalMargins, + digit_mode, CutoffMode_TotalLength, precision + 1, + pCurOut, bufferSize, &printExponent); + + DEBUG_ASSERT(numDigits > 0); + DEBUG_ASSERT(numDigits <= bufferSize); + + /* keep the whole number as the first digit */ + if (bufferSize > 1) { + pCurOut += 1; + bufferSize -= 1; + } + + /* insert the decimal point prior to the fractional number */ + numFractionDigits = numDigits-1; + if (numFractionDigits > 0 && bufferSize > 1) { + npy_int32 maxFractionDigits = (npy_int32)bufferSize - 2; + + if (numFractionDigits > maxFractionDigits) { + numFractionDigits = maxFractionDigits; + } + + memmove(pCurOut + 1, pCurOut, numFractionDigits); + pCurOut[0] = '.'; + pCurOut += (1 + numFractionDigits); + bufferSize -= (1 + numFractionDigits); + } + + /* always add decimal point, except for DprZeros mode */ + if (trim_mode != TrimMode_DptZeros && numFractionDigits == 0 && + bufferSize > 1){ + *pCurOut = '.'; + ++pCurOut; + --bufferSize; + } + + if (trim_mode == TrimMode_LeaveOneZero) { + /* if we didn't print any fractional digits, add the 0 */ + if (numFractionDigits == 0 && bufferSize > 1) { + *pCurOut = '0'; + ++pCurOut; + --bufferSize; + ++numFractionDigits; + } + } + else if (trim_mode == TrimMode_None && + digit_mode != DigitMode_Unique) { + /* add trailing zeros up to precision length */ + if (precision > (npy_int32)numFractionDigits) { + char *pEnd; + /* compute the number of trailing zeros needed */ + npy_int32 numZeros = (precision - numFractionDigits); + + if (numZeros > (npy_int32)bufferSize - 1) { + numZeros = (npy_int32)bufferSize - 1; + } + + for (pEnd = pCurOut + numZeros; pCurOut < pEnd; ++pCurOut) { + *pCurOut = '0'; + ++numFractionDigits; + } + } + } + /* else, for trim_mode Zeros or DptZeros, there is nothing more to add */ + + /* + * when rounding, we may still end up with trailing zeros. Remove them + * depending on trim settings. + */ + if (precision >= 0 && trim_mode != TrimMode_None && numFractionDigits > 0){ + --pCurOut; + while (*pCurOut == '0') { + --pCurOut; + ++bufferSize; + --numFractionDigits; + } + if (trim_mode == TrimMode_LeaveOneZero && *pCurOut == '.') { + ++pCurOut; + *pCurOut = '0'; + --bufferSize; + ++numFractionDigits; + } + ++pCurOut; + } + + /* print the exponent into a local buffer and copy into output buffer */ + if (bufferSize > 1) { + char exponentBuffer[7]; + npy_int32 digits[5]; + npy_int32 i, exp_size, count; + + if (exp_digits > 5) { + exp_digits = 5; + } + if (exp_digits < 0) { + exp_digits = 2; + } + + exponentBuffer[0] = 'e'; + if (printExponent >= 0) { + exponentBuffer[1] = '+'; + } + else { + exponentBuffer[1] = '-'; + printExponent = -printExponent; + } + + DEBUG_ASSERT(printExponent < 100000); + + /* get exp digits */ + for (i = 0; i < 5; i++){ + digits[i] = printExponent % 10; + printExponent /= 10; + } + /* count back over leading zeros */ + for (i = 5; i > exp_digits && digits[i-1] == 0; i--) { + } + exp_size = i; + /* write remaining digits to tmp buf */ + for (i = exp_size; i > 0; i--){ + exponentBuffer[2 + (exp_size-i)] = (char)('0' + digits[i-1]); + } + + /* copy the exponent buffer into the output */ + count = exp_size + 2; + if (count > (npy_int32)bufferSize - 1) { + count = (npy_int32)bufferSize - 1; + } + memcpy(pCurOut, exponentBuffer, count); + pCurOut += count; + bufferSize -= count; + } + + + DEBUG_ASSERT(bufferSize > 0); + pCurOut[0] = '\0'; + + return pCurOut - buffer; +} + +/* + * Print a hexadecimal value with a given width. + * The output string is always NUL terminated and the string length (not + * including the NUL) is returned. + */ +/* Unused for now +static npy_uint32 +PrintHex(char * buffer, npy_uint32 bufferSize, npy_uint64 value, + npy_uint32 width) +{ + const char digits[] = "0123456789abcdef"; + char *pCurOut; + + DEBUG_ASSERT(bufferSize > 0); + + npy_uint32 maxPrintLen = bufferSize-1; + if (width > maxPrintLen) { + width = maxPrintLen; + } + + pCurOut = buffer; + while (width > 0) { + --width; + + npy_uint8 digit = (npy_uint8)((value >> 4ull*(npy_uint64)width) & 0xF); + *pCurOut = digits[digit]; + + ++pCurOut; + } + + *pCurOut = '\0'; + return pCurOut - buffer; +} +*/ + +/* + * Print special case values for infinities and NaNs. + * The output string is always NUL terminated and the string length (not + * including the NUL) is returned. + */ +static npy_uint32 +PrintInfNan(char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa, + npy_uint32 mantissaHexWidth, char signbit) +{ + npy_uint32 maxPrintLen = bufferSize-1; + npy_uint32 pos = 0; + + DEBUG_ASSERT(bufferSize > 0); + + /* Check for infinity */ + if (mantissa == 0) { + npy_uint32 printLen; + + /* only print sign for inf values (though nan can have a sign set) */ + if (signbit == '+') { + if (pos < maxPrintLen-1){ + buffer[pos++] = '+'; + } + } + else if (signbit == '-') { + if (pos < maxPrintLen-1){ + buffer[pos++] = '-'; + } + } + + /* copy and make sure the buffer is terminated */ + printLen = (3 < maxPrintLen - pos) ? 3 : maxPrintLen - pos; + memcpy(buffer + pos, "inf", printLen); + buffer[pos + printLen] = '\0'; + return pos + printLen; + } + else { + /* copy and make sure the buffer is terminated */ + npy_uint32 printLen = (3 < maxPrintLen - pos) ? 3 : maxPrintLen - pos; + memcpy(buffer + pos, "nan", printLen); + buffer[pos + printLen] = '\0'; + + /* + * // XXX: Should we change this for numpy? + * // append HEX value + * if (maxPrintLen > 3) { + * printLen += PrintHex(buffer+3, bufferSize-3, mantissa, + * mantissaHexWidth); + * } + */ + + return pos + printLen; + } +} + +/* + * These functions print a floating-point number as a decimal string. + * The output string is always NUL terminated and the string length (not + * including the NUL) is returned. + * + * Arguments are: + * buffer - buffer to output into + * bufferSize - maximum characters that can be printed to buffer + * value - value significand + * scientific - boolean controlling whether scientific notation is used + * precision - If positive, specifies the number of decimals to show after + * decimal point. If negative, sufficient digits to uniquely + * specify the float will be output. + * trim_mode - how to treat trailing zeros and decimal point. See TrimMode. + * digits_right - pad the result with '' on the right past the decimal point + * digits_left - pad the result with '' on the right past the decimal point + * exp_digits - Only affects scientific output. If positive, pads the + * exponent with 0s until there are this many digits. If + * negative, only use sufficient digits. + */ +static npy_uint32 +Dragon4_PrintFloat16(char *buffer, npy_uint32 bufferSize, npy_uint16 value, + npy_bool scientific, DigitMode digit_mode, + CutoffMode cutoff_mode, npy_int32 precision, + npy_bool sign, TrimMode trim_mode, npy_int32 digits_left, + npy_int32 digits_right, npy_int32 exp_digits) +{ + FloatUnion16 floatUnion; + npy_uint32 floatExponent, floatMantissa; + + npy_uint32 mantissa; + npy_int32 exponent; + npy_uint32 mantissaBit; + npy_bool hasUnequalMargins; + char signbit = '\0'; + + if (bufferSize == 0) { + return 0; + } + + if (bufferSize == 1) { + buffer[0] = '\0'; + return 0; + } + + /* deconstruct the floating point value */ + floatUnion.integer = value; + floatExponent = GetExponent_F16(&floatUnion); + floatMantissa = GetMantissa_F16(&floatUnion); + + /* output the sign */ + if (IsNegative_F16(&floatUnion)) { + signbit = '-'; + } + else if (sign) { + signbit = '+'; + } + + /* if this is a special value */ + if (floatExponent == 0x1F) { + return PrintInfNan(buffer, bufferSize, floatMantissa, 3, signbit); + } + /* else this is a number */ + + /* factor the value into its parts */ + if (floatExponent != 0) { + /* + * normalized + * The floating point equation is: + * value = (1 + mantissa/2^10) * 2 ^ (exponent-15) + * We convert the integer equation by factoring a 2^10 out of the + * exponent + * value = (1 + mantissa/2^10) * 2^10 * 2 ^ (exponent-15-10) + * value = (2^10 + mantissa) * 2 ^ (exponent-15-10) + * Because of the implied 1 in front of the mantissa we have 10 bits of + * precision. + * m = (2^10 + mantissa) + * e = (exponent-15-10) + */ + mantissa = (1UL << 10) | floatMantissa; + exponent = floatExponent - 15 - 10; + mantissaBit = 10; + hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0); + } + else { + /* + * denormalized + * The floating point equation is: + * value = (mantissa/2^10) * 2 ^ (1-15) + * We convert the integer equation by factoring a 2^23 out of the + * exponent + * value = (mantissa/2^10) * 2^10 * 2 ^ (1-15-10) + * value = mantissa * 2 ^ (1-15-10) + * We have up to 10 bits of precision. + * m = (mantissa) + * e = (1-15-10) + */ + mantissa = floatMantissa; + exponent = 1 - 15 - 10; + mantissaBit = LogBase2_32(mantissa); + hasUnequalMargins = NPY_FALSE; + } + + /* format the value */ + if (scientific) { + return FormatScientific(buffer, bufferSize, mantissa, exponent, signbit, + mantissaBit, hasUnequalMargins, digit_mode, + precision, trim_mode, digits_left, exp_digits); + } + else { + return FormatPositional(buffer, bufferSize, mantissa, exponent, signbit, + mantissaBit, hasUnequalMargins, digit_mode, + cutoff_mode, precision, trim_mode, + digits_left, digits_right); + } +} + +static npy_uint32 +Dragon4_PrintFloat32(char *buffer, npy_uint32 bufferSize, npy_float32 value, + npy_bool scientific, DigitMode digit_mode, + CutoffMode cutoff_mode, npy_int32 precision, + npy_bool sign, TrimMode trim_mode, npy_int32 digits_left, + npy_int32 digits_right, npy_int32 exp_digits) +{ + FloatUnion32 floatUnion; + npy_uint32 floatExponent, floatMantissa; + + npy_uint32 mantissa; + npy_int32 exponent; + npy_uint32 mantissaBit; + npy_bool hasUnequalMargins; + char signbit = '\0'; + + if (bufferSize == 0) { + return 0; + } + + if (bufferSize == 1) { + buffer[0] = '\0'; + return 0; + } + + /* deconstruct the floating point value */ + floatUnion.floatingPoint = value; + floatExponent = GetExponent_F32(&floatUnion); + floatMantissa = GetMantissa_F32(&floatUnion); + + /* output the sign */ + if (IsNegative_F32(&floatUnion)) { + signbit = '-'; + } + else if (sign) { + signbit = '+'; + } + + /* if this is a special value */ + if (floatExponent == 0xFF) { + return PrintInfNan(buffer, bufferSize, floatMantissa, 6, signbit); + } + /* else this is a number */ + + /* factor the value into its parts */ + if (floatExponent != 0) { + /* + * normalized + * The floating point equation is: + * value = (1 + mantissa/2^23) * 2 ^ (exponent-127) + * We convert the integer equation by factoring a 2^23 out of the + * exponent + * value = (1 + mantissa/2^23) * 2^23 * 2 ^ (exponent-127-23) + * value = (2^23 + mantissa) * 2 ^ (exponent-127-23) + * Because of the implied 1 in front of the mantissa we have 24 bits of + * precision. + * m = (2^23 + mantissa) + * e = (exponent-127-23) + */ + mantissa = (1UL << 23) | floatMantissa; + exponent = floatExponent - 127 - 23; + mantissaBit = 23; + hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0); + } + else { + /* + * denormalized + * The floating point equation is: + * value = (mantissa/2^23) * 2 ^ (1-127) + * We convert the integer equation by factoring a 2^23 out of the + * exponent + * value = (mantissa/2^23) * 2^23 * 2 ^ (1-127-23) + * value = mantissa * 2 ^ (1-127-23) + * We have up to 23 bits of precision. + * m = (mantissa) + * e = (1-127-23) + */ + mantissa = floatMantissa; + exponent = 1 - 127 - 23; + mantissaBit = LogBase2_32(mantissa); + hasUnequalMargins = NPY_FALSE; + } + + /* format the value */ + if (scientific) { + return FormatScientific(buffer, bufferSize, mantissa, exponent, signbit, + mantissaBit, hasUnequalMargins, digit_mode, + precision, trim_mode, digits_left, exp_digits); + } + else { + return FormatPositional(buffer, bufferSize, mantissa, exponent, signbit, + mantissaBit, hasUnequalMargins, digit_mode, + cutoff_mode, precision, trim_mode, + digits_left, digits_right); + } +} + +static npy_uint32 +Dragon4_PrintFloat64(char *buffer, npy_uint32 bufferSize, npy_float64 value, + npy_bool scientific, DigitMode digit_mode, + CutoffMode cutoff_mode, npy_int32 precision, + npy_bool sign, TrimMode trim_mode, npy_int32 digits_left, + npy_int32 digits_right, npy_int32 exp_digits) +{ + FloatUnion64 floatUnion; + npy_uint32 floatExponent; + npy_uint64 floatMantissa; + + npy_uint64 mantissa; + npy_int32 exponent; + npy_uint32 mantissaBit; + npy_bool hasUnequalMargins; + char signbit = '\0'; + + if (bufferSize == 0) { + return 0; + } + + if (bufferSize == 1) { + buffer[0] = '\0'; + return 0; + } + + /* deconstruct the floating point value */ + floatUnion.floatingPoint = value; + floatExponent = GetExponent_F64(&floatUnion); + floatMantissa = GetMantissa_F64(&floatUnion); + + /* output the sign */ + if (IsNegative_F64(&floatUnion)) { + signbit = '-'; + } + else if (sign) { + signbit = '+'; + } + + /* if this is a special value */ + if (floatExponent == 0x7FF) { + return PrintInfNan(buffer, bufferSize, floatMantissa, 13, signbit); + } + /* else this is a number */ + + /* factor the value into its parts */ + if (floatExponent != 0) { + /* + * normal + * The floating point equation is: + * value = (1 + mantissa/2^52) * 2 ^ (exponent-1023) + * We convert the integer equation by factoring a 2^52 out of the + * exponent + * value = (1 + mantissa/2^52) * 2^52 * 2 ^ (exponent-1023-52) + * value = (2^52 + mantissa) * 2 ^ (exponent-1023-52) + * Because of the implied 1 in front of the mantissa we have 53 bits of + * precision. + * m = (2^52 + mantissa) + * e = (exponent-1023+1-53) + */ + mantissa = (1ull << 52) | floatMantissa; + exponent = floatExponent - 1023 - 52; + mantissaBit = 52; + hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0); + } + else { + /* + * subnormal + * The floating point equation is: + * value = (mantissa/2^52) * 2 ^ (1-1023) + * We convert the integer equation by factoring a 2^52 out of the + * exponent + * value = (mantissa/2^52) * 2^52 * 2 ^ (1-1023-52) + * value = mantissa * 2 ^ (1-1023-52) + * We have up to 52 bits of precision. + * m = (mantissa) + * e = (1-1023-52) + */ + mantissa = floatMantissa; + exponent = 1 - 1023 - 52; + mantissaBit = LogBase2_64(mantissa); + hasUnequalMargins = NPY_FALSE; + } + + /* format the value */ + if (scientific) { + return FormatScientific(buffer, bufferSize, mantissa, exponent, signbit, + mantissaBit, hasUnequalMargins, digit_mode, + precision, trim_mode, digits_left, exp_digits); + } + else { + return FormatPositional(buffer, bufferSize, mantissa, exponent, signbit, + mantissaBit, hasUnequalMargins, digit_mode, + cutoff_mode, precision, trim_mode, + digits_left, digits_right); + } +} + +static npy_uint32 +Dragon4_PrintFloat128(char *buffer, npy_uint32 bufferSize, FloatVal128 value, + npy_bool scientific, DigitMode digit_mode, + CutoffMode cutoff_mode, npy_int32 precision, + npy_bool sign, TrimMode trim_mode, npy_int32 digits_left, + npy_int32 digits_right, npy_int32 exp_digits) +{ + npy_uint32 floatExponent; + npy_uint64 floatMantissa; + + npy_uint64 mantissa; + npy_int32 exponent; + npy_uint32 mantissaBit; + npy_bool hasUnequalMargins; + char signbit = '\0'; + + if (bufferSize == 0) { + return 0; + } + + if (bufferSize == 1) { + buffer[0] = '\0'; + return 0; + } + + /* deconstruct the floating point value */ + floatExponent = GetExponent_F128(&value); + floatMantissa = GetMantissa_F128(&value); + + /* output the sign */ + if (IsNegative_F128(&value)) { + signbit = '-'; + } + else if (sign) { + signbit = '+'; + } + + /* if this is a special value */ + if (floatExponent == 0x7FFF) { + return PrintInfNan(buffer, bufferSize, floatMantissa, 16, signbit); + } + /* else this is a number */ + + /* factor the value into its parts */ + if (floatExponent != 0) { + /* + * normal + * The floating point equation is: + * value = (1 + mantissa/2^63) * 2 ^ (exponent-16383) + * We convert the integer equation by factoring a 2^63 out of the + * exponent + * value = (1 + mantissa/2^63) * 2^63 * 2 ^ (exponent-16383-63) + * value = (2^63 + mantissa) * 2 ^ (exponent-16383-63) + * Because of the implied 1 in front of the mantissa we have 64 bits of + * precision. + * m = (2^63 + mantissa) + * e = (exponent-16383+1-64) + */ + mantissa = (1ull << 63) | floatMantissa; + exponent = floatExponent - 16383 - 63; + mantissaBit = 63; + hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0); + } + else { + /* + * subnormal + * The floating point equation is: + * value = (mantissa/2^63) * 2 ^ (1-16383) + * We convert the integer equation by factoring a 2^52 out of the + * exponent + * value = (mantissa/2^63) * 2^52 * 2 ^ (1-16383-63) + * value = mantissa * 2 ^ (1-16383-63) + * We have up to 63 bits of precision. + * m = (mantissa) + * e = (1-16383-63) + */ + mantissa = floatMantissa; + exponent = 1 - 16383 - 63; + mantissaBit = LogBase2_64(mantissa); + hasUnequalMargins = NPY_FALSE; + } + + /* format the value */ + if (scientific) { + return FormatScientific(buffer, bufferSize, mantissa, exponent, signbit, + mantissaBit, hasUnequalMargins, digit_mode, + precision, trim_mode, digits_left, exp_digits); + } + else { + return FormatPositional(buffer, bufferSize, mantissa, exponent, signbit, + mantissaBit, hasUnequalMargins, digit_mode, + cutoff_mode, precision, trim_mode, + digits_left, digits_right); + } +} + +PyObject * +Dragon4_Positional_AnySize(void *val, size_t size, DigitMode digit_mode, + CutoffMode cutoff_mode, int precision, int sign, + TrimMode trim, int pad_left, int pad_right) +{ + /* + * Use a very large buffer in case anyone tries to output a large numberG. + * 16384 should be enough to uniquely print any float128, which goes up + * to about 10^4932 */ + static char repr[16384]; + FloatVal128 val128; +#ifdef NPY_FLOAT80 + FloatUnion80 buf80;; +#endif +#ifdef NPY_FLOAT96 + FloatUnion96 buf96; +#endif +#ifdef NPY_FLOAT128 + FloatUnion128 buf128; +#endif + + switch (size) { + case 2: + Dragon4_PrintFloat16(repr, sizeof(repr), *(npy_float16*)val, + 0, digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right, -1); + break; + case 4: + Dragon4_PrintFloat32(repr, sizeof(repr), *(npy_float32*)val, + 0, digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right, -1); + break; + case 8: + Dragon4_PrintFloat64(repr, sizeof(repr), *(npy_float64*)val, + 0, digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right, -1); + break; +#ifdef NPY_FLOAT80 + case 10: + buf80.floatingPoint = *(npy_float80*)val; + val128.integer[0] = buf80.integer.a; + val128.integer[1] = buf80.integer.b; + Dragon4_PrintFloat128(repr, sizeof(repr), val128, + 0, digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right, -1); + break; +#endif +#ifdef NPY_FLOAT96 + case 12: + buf96.floatingPoint = *(npy_float96*)val; + val128.integer[0] = buf96.integer.a; + val128.integer[1] = buf96.integer.b; + Dragon4_PrintFloat128(repr, sizeof(repr), val128, + 0, digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right, -1); + break; +#endif +#ifdef NPY_FLOAT128 + case 16: + buf128.floatingPoint = *(npy_float128*)val; + val128.integer[0] = buf128.integer.a; + val128.integer[1] = buf128.integer.b; + Dragon4_PrintFloat128(repr, sizeof(repr), val128, + 0, digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right, -1); + break; +#endif + default: + PyErr_Format(PyExc_ValueError, "unexpected itemsize %zu", size); + return NULL; + } + + return PyUString_FromString(repr); +} + +PyObject * +Dragon4_Positional(PyObject *obj, DigitMode digit_mode, CutoffMode cutoff_mode, + int precision, int sign, TrimMode trim, int pad_left, + int pad_right) +{ + double val; + + if (PyArray_IsScalar(obj, Half)) { + npy_half x = ((PyHalfScalarObject *)obj)->obval; + return Dragon4_Positional_AnySize(&x, sizeof(npy_half), + digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right); + } + else if (PyArray_IsScalar(obj, Float)) { + npy_float x = ((PyFloatScalarObject *)obj)->obval; + return Dragon4_Positional_AnySize(&x, sizeof(npy_float), + digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right); + } + else if (PyArray_IsScalar(obj, Double)) { + npy_double x = ((PyDoubleScalarObject *)obj)->obval; + return Dragon4_Positional_AnySize(&x, sizeof(npy_double), + digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right); + } + else if (PyArray_IsScalar(obj, LongDouble)) { + npy_longdouble x = ((PyLongDoubleScalarObject *)obj)->obval; + return Dragon4_Positional_AnySize(&x, sizeof(npy_longdouble), + digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right); + } + + val = PyFloat_AsDouble(obj); + if (PyErr_Occurred()) { + return NULL; + } + return Dragon4_Positional_AnySize(&val, sizeof(double), + digit_mode, cutoff_mode, precision, + sign, trim, pad_left, pad_right); +} + +PyObject * +Dragon4_Scientific_AnySize(void *val, size_t size, DigitMode digit_mode, + int precision, int sign, TrimMode trim, + int pad_left, int exp_digits) +{ + /* use a very large buffer in case anyone tries to output a large precision */ + static char repr[4096]; + FloatVal128 val128; +#ifdef NPY_FLOAT80 + FloatUnion80 buf80;; +#endif +#ifdef NPY_FLOAT96 + FloatUnion96 buf96; +#endif +#ifdef NPY_FLOAT128 + FloatUnion128 buf128; +#endif + + /* dummy, is ignored in scientific mode */ + CutoffMode cutoff_mode = CutoffMode_TotalLength; + + switch (size) { + case 2: + Dragon4_PrintFloat16(repr, sizeof(repr), *(npy_float16*)val, + 1, digit_mode, cutoff_mode, precision, sign, + trim, pad_left, -1, exp_digits); + break; + case 4: + Dragon4_PrintFloat32(repr, sizeof(repr), *(npy_float32*)val, + 1, digit_mode, cutoff_mode, precision, sign, + trim, pad_left, -1, exp_digits); + break; + case 8: + Dragon4_PrintFloat64(repr, sizeof(repr), *(npy_float64*)val, + 1, digit_mode, cutoff_mode, precision, sign, + trim, pad_left, -1, exp_digits); + break; +#ifdef NPY_FLOAT80 + case 10: + buf80.floatingPoint = *(npy_float80*)val; + val128.integer[0] = buf80.integer.a; + val128.integer[1] = buf80.integer.b; + Dragon4_PrintFloat128(repr, sizeof(repr), val128, + 1, digit_mode, cutoff_mode, precision, sign, + trim, pad_left, -1, exp_digits); + break; +#endif +#ifdef NPY_FLOAT96 + case 12: + buf96.floatingPoint = *(npy_float96*)val; + val128.integer[0] = buf96.integer.a; + val128.integer[1] = buf96.integer.b; + Dragon4_PrintFloat128(repr, sizeof(repr), val128, + 1, digit_mode, cutoff_mode, precision, sign, + trim, pad_left, -1, exp_digits); + break; +#endif +#ifdef NPY_FLOAT128 + case 16: + buf128.floatingPoint = *(npy_float128*)val; + val128.integer[0] = buf128.integer.a; + val128.integer[1] = buf128.integer.b; + Dragon4_PrintFloat128(repr, sizeof(repr), val128, + 1, digit_mode, cutoff_mode, precision, sign, + trim, pad_left, -1, exp_digits); + break; +#endif + default: + PyErr_Format(PyExc_ValueError, "unexpected itemsize %zu", size); + return NULL; + } + + return PyUString_FromString(repr); +} + +PyObject * +Dragon4_Scientific(PyObject *obj, DigitMode digit_mode, int precision, + int sign, TrimMode trim, int pad_left, int exp_digits) +{ + double val; + + if (PyArray_IsScalar(obj, Half)) { + npy_half x = ((PyHalfScalarObject *)obj)->obval; + return Dragon4_Scientific_AnySize(&x, sizeof(npy_half), + digit_mode, precision, + sign, trim, pad_left, exp_digits); + } + else if (PyArray_IsScalar(obj, Float)) { + npy_float x = ((PyFloatScalarObject *)obj)->obval; + return Dragon4_Scientific_AnySize(&x, sizeof(npy_float), + digit_mode, precision, + sign, trim, pad_left, exp_digits); + } + else if (PyArray_IsScalar(obj, Double)) { + npy_double x = ((PyDoubleScalarObject *)obj)->obval; + return Dragon4_Scientific_AnySize(&x, sizeof(npy_double), + digit_mode, precision, + sign, trim, pad_left, exp_digits); + } + else if (PyArray_IsScalar(obj, LongDouble)) { + npy_longdouble x = ((PyLongDoubleScalarObject *)obj)->obval; + return Dragon4_Scientific_AnySize(&x, sizeof(npy_longdouble), + digit_mode, precision, + sign, trim, pad_left, exp_digits); + } + + val = PyFloat_AsDouble(obj); + if (PyErr_Occurred()) { + return NULL; + } + return Dragon4_Scientific_AnySize(&val, sizeof(double), + digit_mode, precision, + sign, trim, pad_left, exp_digits); +} diff --git a/numpy/core/src/multiarray/dragon4.h b/numpy/core/src/multiarray/dragon4.h new file mode 100644 index 0000000..5559c51 --- /dev/null +++ b/numpy/core/src/multiarray/dragon4.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014 Ryan Juckett + * http://www.ryanjuckett.com/ + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +/* + * This file contains a modified version of Ryan Juckett's Dragon4 + * implementation, which has been ported from C++ to C and which has + * modifications specific to printing floats in numpy. + */ + +#ifndef _NPY_DRAGON4_H_ +#define _NPY_DRAGON4_H_ + +#include "Python.h" +#include "structmember.h" +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "npy_config.h" +#include "npy_pycompat.h" +#include "numpy/arrayscalars.h" + +typedef enum DigitMode +{ + /* Round digits to print shortest uniquely identifiable number. */ + DigitMode_Unique, + /* Output the digits of the number as if with infinite precision */ + DigitMode_Exact, +} DigitMode; + +typedef enum CutoffMode +{ + /* up to cutoffNumber significant digits */ + CutoffMode_TotalLength, + /* up to cutoffNumber significant digits past the decimal point */ + CutoffMode_FractionLength, +} CutoffMode; + +typedef enum TrimMode +{ + TrimMode_None, /* don't trim zeros, always leave a decimal point */ + TrimMode_LeaveOneZero, /* trim all but the zero before the decimal point */ + TrimMode_Zeros, /* trim all trailing zeros, leave decimal point */ + TrimMode_DptZeros, /* trim trailing zeros & trailing decimal point */ +} TrimMode; + +PyObject * +Dragon4_Positional_AnySize(void *val, size_t size, DigitMode digit_mode, + CutoffMode cutoff_mode, int precision, int sign, + TrimMode trim, int pad_left, int pad_right); + +PyObject * +Dragon4_Scientific_AnySize(void *val, size_t size, DigitMode digit_mode, + int precision, int sign, TrimMode trim, + int pad_left, int pad_right); + +PyObject * +Dragon4_Positional(PyObject *obj, DigitMode digit_mode, CutoffMode cutoff_mode, + int precision, int sign, TrimMode trim, int pad_left, + int pad_right); + +PyObject * +Dragon4_Scientific(PyObject *obj, DigitMode digit_mode, int precision, + int sign, TrimMode trim, int pad_left, int exp_digits); + +#endif + diff --git a/numpy/core/src/multiarray/dtype_transfer.c b/numpy/core/src/multiarray/dtype_transfer.c new file mode 100644 index 0000000..9c27255 --- /dev/null +++ b/numpy/core/src/multiarray/dtype_transfer.c @@ -0,0 +1,4143 @@ +/* + * This file contains low-level loops for data type transfers. + * In particular the function PyArray_GetDTypeTransferFunction is + * implemented here. + * + * Copyright (c) 2010 by Mark Wiebe (mwwiebe@gmail.com) + * The University of British Columbia + * + * See LICENSE.txt for the license. + + */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include +#include + +#include "npy_pycompat.h" + +#include "convert_datatype.h" +#include "ctors.h" +#include "_datetime.h" +#include "datetime_strings.h" +#include "descriptor.h" + +#include "shape.h" +#include "lowlevel_strided_loops.h" +#include "alloc.h" + +#define NPY_LOWLEVEL_BUFFER_BLOCKSIZE 128 + +/********** PRINTF DEBUG TRACING **************/ +#define NPY_DT_DBG_TRACING 0 +/* Tracing incref/decref can be very noisy */ +#define NPY_DT_REF_DBG_TRACING 0 + +#if NPY_DT_REF_DBG_TRACING +#define NPY_DT_DBG_REFTRACE(msg, ref) \ + printf("%-12s %20p %s%d%s\n", msg, ref, \ + ref ? "(refcnt " : "", \ + ref ? (int)ref->ob_refcnt : 0, \ + ref ? ((ref->ob_refcnt <= 0) ? \ + ") <- BIG PROBLEM!!!!" : ")") : ""); \ + fflush(stdout); +#else +#define NPY_DT_DBG_REFTRACE(msg, ref) +#endif +/**********************************************/ + +/* + * Returns a transfer function which DECREFs any references in src_type. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +static int +get_decsrcref_transfer_function(int aligned, + npy_intp src_stride, + PyArray_Descr *src_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api); + +/* + * Returns a transfer function which zeros out the dest values. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +static int +get_setdstzero_transfer_function(int aligned, + npy_intp dst_stride, + PyArray_Descr *dst_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api); + +/* + * Returns a transfer function which sets a boolean type to ones. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +NPY_NO_EXPORT int +get_bool_setdstone_transfer_function(npy_intp dst_stride, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *NPY_UNUSED(out_needs_api)); + +/*************************** COPY REFERENCES *******************************/ + +/* Moves references from src to dst */ +static void +_strided_to_strided_move_references(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + PyObject *src_ref = NULL, *dst_ref = NULL; + while (N > 0) { + NPY_COPY_PYOBJECT_PTR(&src_ref, src); + NPY_COPY_PYOBJECT_PTR(&dst_ref, dst); + + /* Release the reference in dst */ + NPY_DT_DBG_REFTRACE("dec dst ref", dst_ref); + Py_XDECREF(dst_ref); + /* Move the reference */ + NPY_DT_DBG_REFTRACE("move src ref", src_ref); + NPY_COPY_PYOBJECT_PTR(dst, &src_ref); + /* Set the source reference to NULL */ + src_ref = NULL; + NPY_COPY_PYOBJECT_PTR(src, &src_ref); + + src += src_stride; + dst += dst_stride; + --N; + } +} + +/* Copies references from src to dst */ +static void +_strided_to_strided_copy_references(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + PyObject *src_ref = NULL, *dst_ref = NULL; + while (N > 0) { + NPY_COPY_PYOBJECT_PTR(&src_ref, src); + NPY_COPY_PYOBJECT_PTR(&dst_ref, dst); + + /* Copy the reference */ + NPY_DT_DBG_REFTRACE("copy src ref", src_ref); + NPY_COPY_PYOBJECT_PTR(dst, &src_ref); + /* Claim the reference */ + Py_XINCREF(src_ref); + /* Release the reference in dst */ + NPY_DT_DBG_REFTRACE("dec dst ref", dst_ref); + Py_XDECREF(dst_ref); + + src += src_stride; + dst += dst_stride; + --N; + } +} + + +/************************** ZERO-PADDED COPY ******************************/ + +/* Does a zero-padded copy */ +typedef struct { + NpyAuxData base; + npy_intp dst_itemsize; +} _strided_zero_pad_data; + +/* zero-padded data copy function */ +static NpyAuxData *_strided_zero_pad_data_clone(NpyAuxData *data) +{ + _strided_zero_pad_data *newdata = + (_strided_zero_pad_data *)PyArray_malloc( + sizeof(_strided_zero_pad_data)); + if (newdata == NULL) { + return NULL; + } + + memcpy(newdata, data, sizeof(_strided_zero_pad_data)); + + return (NpyAuxData *)newdata; +} + +/* + * Does a strided to strided zero-padded copy for the case where + * dst_itemsize > src_itemsize + */ +static void +_strided_to_strided_zero_pad_copy(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_zero_pad_data *d = (_strided_zero_pad_data *)data; + npy_intp dst_itemsize = d->dst_itemsize; + npy_intp zero_size = dst_itemsize-src_itemsize; + + while (N > 0) { + memcpy(dst, src, src_itemsize); + memset(dst + src_itemsize, 0, zero_size); + src += src_stride; + dst += dst_stride; + --N; + } +} + +/* + * Does a strided to strided zero-padded copy for the case where + * dst_itemsize < src_itemsize + */ +static void +_strided_to_strided_truncate_copy(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_zero_pad_data *d = (_strided_zero_pad_data *)data; + npy_intp dst_itemsize = d->dst_itemsize; + + while (N > 0) { + memcpy(dst, src, dst_itemsize); + src += src_stride; + dst += dst_stride; + --N; + } +} + +/* + * Does a strided to strided zero-padded or truncated copy for the case where + * unicode swapping is needed. + */ +static void +_strided_to_strided_unicode_copyswap(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_zero_pad_data *d = (_strided_zero_pad_data *)data; + npy_intp dst_itemsize = d->dst_itemsize; + npy_intp zero_size = dst_itemsize - src_itemsize; + npy_intp copy_size = zero_size > 0 ? src_itemsize : dst_itemsize; + char *_dst; + npy_intp characters = dst_itemsize / 4; + int i; + + while (N > 0) { + memcpy(dst, src, copy_size); + if (zero_size > 0) { + memset(dst + src_itemsize, 0, zero_size); + } + _dst = dst; + for (i=0; i < characters; i++) { + npy_bswap4_unaligned(_dst); + _dst += 4; + } + src += src_stride; + dst += dst_stride; + --N; + } +} + + +NPY_NO_EXPORT int +PyArray_GetStridedZeroPadCopyFn(int aligned, int unicode_swap, + npy_intp src_stride, npy_intp dst_stride, + npy_intp src_itemsize, npy_intp dst_itemsize, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + if ((src_itemsize == dst_itemsize) && !unicode_swap) { + *out_stransfer = PyArray_GetStridedCopyFn(aligned, src_stride, + dst_stride, src_itemsize); + *out_transferdata = NULL; + return (*out_stransfer == NULL) ? NPY_FAIL : NPY_SUCCEED; + } + else { + _strided_zero_pad_data *d = PyArray_malloc( + sizeof(_strided_zero_pad_data)); + if (d == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + d->dst_itemsize = dst_itemsize; + d->base.free = (NpyAuxData_FreeFunc *)&PyArray_free; + d->base.clone = &_strided_zero_pad_data_clone; + + if (unicode_swap) { + *out_stransfer = &_strided_to_strided_unicode_copyswap; + } + else if (src_itemsize < dst_itemsize) { + *out_stransfer = &_strided_to_strided_zero_pad_copy; + } + else { + *out_stransfer = &_strided_to_strided_truncate_copy; + } + + *out_transferdata = (NpyAuxData *)d; + return NPY_SUCCEED; + } +} + +/***************** WRAP ALIGNED CONTIGUOUS TRANSFER FUNCTION **************/ + +/* Wraps a transfer function + data in alignment code */ +typedef struct { + NpyAuxData base; + PyArray_StridedUnaryOp *wrapped, + *tobuffer, *frombuffer; + NpyAuxData *wrappeddata, *todata, *fromdata; + npy_intp src_itemsize, dst_itemsize; + char *bufferin, *bufferout; +} _align_wrap_data; + +/* transfer data free function */ +static void _align_wrap_data_free(NpyAuxData *data) +{ + _align_wrap_data *d = (_align_wrap_data *)data; + NPY_AUXDATA_FREE(d->wrappeddata); + NPY_AUXDATA_FREE(d->todata); + NPY_AUXDATA_FREE(d->fromdata); + PyArray_free(data); +} + +/* transfer data copy function */ +static NpyAuxData *_align_wrap_data_clone(NpyAuxData *data) +{ + _align_wrap_data *d = (_align_wrap_data *)data; + _align_wrap_data *newdata; + npy_intp basedatasize, datasize; + + /* Round up the structure size to 16-byte boundary */ + basedatasize = (sizeof(_align_wrap_data)+15)&(-0x10); + /* Add space for two low level buffers */ + datasize = basedatasize + + NPY_LOWLEVEL_BUFFER_BLOCKSIZE*d->src_itemsize + + NPY_LOWLEVEL_BUFFER_BLOCKSIZE*d->dst_itemsize; + + /* Allocate the data, and populate it */ + newdata = (_align_wrap_data *)PyArray_malloc(datasize); + if (newdata == NULL) { + return NULL; + } + memcpy(newdata, data, basedatasize); + newdata->bufferin = (char *)newdata + basedatasize; + newdata->bufferout = newdata->bufferin + + NPY_LOWLEVEL_BUFFER_BLOCKSIZE*newdata->src_itemsize; + if (newdata->wrappeddata != NULL) { + newdata->wrappeddata = NPY_AUXDATA_CLONE(d->wrappeddata); + if (newdata->wrappeddata == NULL) { + PyArray_free(newdata); + return NULL; + } + } + if (newdata->todata != NULL) { + newdata->todata = NPY_AUXDATA_CLONE(d->todata); + if (newdata->todata == NULL) { + NPY_AUXDATA_FREE(newdata->wrappeddata); + PyArray_free(newdata); + return NULL; + } + } + if (newdata->fromdata != NULL) { + newdata->fromdata = NPY_AUXDATA_CLONE(d->fromdata); + if (newdata->fromdata == NULL) { + NPY_AUXDATA_FREE(newdata->wrappeddata); + NPY_AUXDATA_FREE(newdata->todata); + PyArray_free(newdata); + return NULL; + } + } + + return (NpyAuxData *)newdata; +} + +static void +_strided_to_strided_contig_align_wrap(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _align_wrap_data *d = (_align_wrap_data *)data; + PyArray_StridedUnaryOp *wrapped = d->wrapped, + *tobuffer = d->tobuffer, + *frombuffer = d->frombuffer; + npy_intp inner_src_itemsize = d->src_itemsize, + dst_itemsize = d->dst_itemsize; + NpyAuxData *wrappeddata = d->wrappeddata, + *todata = d->todata, + *fromdata = d->fromdata; + char *bufferin = d->bufferin, *bufferout = d->bufferout; + + for(;;) { + if (N > NPY_LOWLEVEL_BUFFER_BLOCKSIZE) { + tobuffer(bufferin, inner_src_itemsize, src, src_stride, + NPY_LOWLEVEL_BUFFER_BLOCKSIZE, + src_itemsize, todata); + wrapped(bufferout, dst_itemsize, bufferin, inner_src_itemsize, + NPY_LOWLEVEL_BUFFER_BLOCKSIZE, + inner_src_itemsize, wrappeddata); + frombuffer(dst, dst_stride, bufferout, dst_itemsize, + NPY_LOWLEVEL_BUFFER_BLOCKSIZE, + dst_itemsize, fromdata); + N -= NPY_LOWLEVEL_BUFFER_BLOCKSIZE; + src += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*src_stride; + dst += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*dst_stride; + } + else { + tobuffer(bufferin, inner_src_itemsize, src, src_stride, N, + src_itemsize, todata); + wrapped(bufferout, dst_itemsize, bufferin, inner_src_itemsize, N, + inner_src_itemsize, wrappeddata); + frombuffer(dst, dst_stride, bufferout, dst_itemsize, N, + dst_itemsize, fromdata); + return; + } + } +} + +static void +_strided_to_strided_contig_align_wrap_init_dest(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _align_wrap_data *d = (_align_wrap_data *)data; + PyArray_StridedUnaryOp *wrapped = d->wrapped, + *tobuffer = d->tobuffer, + *frombuffer = d->frombuffer; + npy_intp inner_src_itemsize = d->src_itemsize, + dst_itemsize = d->dst_itemsize; + NpyAuxData *wrappeddata = d->wrappeddata, + *todata = d->todata, + *fromdata = d->fromdata; + char *bufferin = d->bufferin, *bufferout = d->bufferout; + + for(;;) { + if (N > NPY_LOWLEVEL_BUFFER_BLOCKSIZE) { + tobuffer(bufferin, inner_src_itemsize, src, src_stride, + NPY_LOWLEVEL_BUFFER_BLOCKSIZE, + src_itemsize, todata); + memset(bufferout, 0, dst_itemsize*NPY_LOWLEVEL_BUFFER_BLOCKSIZE); + wrapped(bufferout, dst_itemsize, bufferin, inner_src_itemsize, + NPY_LOWLEVEL_BUFFER_BLOCKSIZE, + inner_src_itemsize, wrappeddata); + frombuffer(dst, dst_stride, bufferout, dst_itemsize, + NPY_LOWLEVEL_BUFFER_BLOCKSIZE, + dst_itemsize, fromdata); + N -= NPY_LOWLEVEL_BUFFER_BLOCKSIZE; + src += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*src_stride; + dst += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*dst_stride; + } + else { + tobuffer(bufferin, inner_src_itemsize, src, src_stride, N, + src_itemsize, todata); + memset(bufferout, 0, dst_itemsize*N); + wrapped(bufferout, dst_itemsize, bufferin, inner_src_itemsize, N, + inner_src_itemsize, wrappeddata); + frombuffer(dst, dst_stride, bufferout, dst_itemsize, N, + dst_itemsize, fromdata); + return; + } + } +} + +/* + * Wraps an aligned contig to contig transfer function between either + * copies or byte swaps to temporary buffers. + * + * src_itemsize/dst_itemsize - The sizes of the src and dst datatypes. + * tobuffer - copy/swap function from src to an aligned contiguous buffer. + * todata - data for tobuffer + * frombuffer - copy/swap function from an aligned contiguous buffer to dst. + * fromdata - data for frombuffer + * wrapped - contig to contig transfer function being wrapped + * wrappeddata - data for wrapped + * init_dest - 1 means to memset the dest buffer to 0 before calling wrapped. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +NPY_NO_EXPORT int +wrap_aligned_contig_transfer_function( + npy_intp src_itemsize, npy_intp dst_itemsize, + PyArray_StridedUnaryOp *tobuffer, NpyAuxData *todata, + PyArray_StridedUnaryOp *frombuffer, NpyAuxData *fromdata, + PyArray_StridedUnaryOp *wrapped, NpyAuxData *wrappeddata, + int init_dest, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + _align_wrap_data *data; + npy_intp basedatasize, datasize; + + /* Round up the structure size to 16-byte boundary */ + basedatasize = (sizeof(_align_wrap_data)+15)&(-0x10); + /* Add space for two low level buffers */ + datasize = basedatasize + + NPY_LOWLEVEL_BUFFER_BLOCKSIZE*src_itemsize + + NPY_LOWLEVEL_BUFFER_BLOCKSIZE*dst_itemsize; + + /* Allocate the data, and populate it */ + data = (_align_wrap_data *)PyArray_malloc(datasize); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + data->base.free = &_align_wrap_data_free; + data->base.clone = &_align_wrap_data_clone; + data->tobuffer = tobuffer; + data->todata = todata; + data->frombuffer = frombuffer; + data->fromdata = fromdata; + data->wrapped = wrapped; + data->wrappeddata = wrappeddata; + data->src_itemsize = src_itemsize; + data->dst_itemsize = dst_itemsize; + data->bufferin = (char *)data + basedatasize; + data->bufferout = data->bufferin + + NPY_LOWLEVEL_BUFFER_BLOCKSIZE*src_itemsize; + + /* Set the function and data */ + if (init_dest) { + *out_stransfer = &_strided_to_strided_contig_align_wrap_init_dest; + } + else { + *out_stransfer = &_strided_to_strided_contig_align_wrap; + } + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +/*************************** WRAP DTYPE COPY/SWAP *************************/ +/* Wraps the dtype copy swap function */ +typedef struct { + NpyAuxData base; + PyArray_CopySwapNFunc *copyswapn; + int swap; + PyArrayObject *arr; +} _wrap_copy_swap_data; + +/* wrap copy swap data free function */ +static void _wrap_copy_swap_data_free(NpyAuxData *data) +{ + _wrap_copy_swap_data *d = (_wrap_copy_swap_data *)data; + Py_DECREF(d->arr); + PyArray_free(data); +} + +/* wrap copy swap data copy function */ +static NpyAuxData *_wrap_copy_swap_data_clone(NpyAuxData *data) +{ + _wrap_copy_swap_data *newdata = + (_wrap_copy_swap_data *)PyArray_malloc(sizeof(_wrap_copy_swap_data)); + if (newdata == NULL) { + return NULL; + } + + memcpy(newdata, data, sizeof(_wrap_copy_swap_data)); + Py_INCREF(newdata->arr); + + return (NpyAuxData *)newdata; +} + +static void +_strided_to_strided_wrap_copy_swap(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *data) +{ + _wrap_copy_swap_data *d = (_wrap_copy_swap_data *)data; + + d->copyswapn(dst, dst_stride, src, src_stride, N, d->swap, d->arr); +} + +/* This only gets used for custom data types and for Unicode when swapping */ +static int +wrap_copy_swap_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *dtype, + int should_swap, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + _wrap_copy_swap_data *data; + npy_intp shape = 1; + + /* Allocate the data for the copy swap */ + data = (_wrap_copy_swap_data *)PyArray_malloc(sizeof(_wrap_copy_swap_data)); + if (data == NULL) { + PyErr_NoMemory(); + *out_stransfer = NULL; + *out_transferdata = NULL; + return NPY_FAIL; + } + + data->base.free = &_wrap_copy_swap_data_free; + data->base.clone = &_wrap_copy_swap_data_clone; + data->copyswapn = dtype->f->copyswapn; + data->swap = should_swap; + + /* + * TODO: This is a hack so the copyswap functions have an array. + * The copyswap functions shouldn't need that. + */ + Py_INCREF(dtype); + data->arr = (PyArrayObject *)PyArray_NewFromDescr_int(&PyArray_Type, dtype, + 1, &shape, NULL, NULL, 0, NULL, 0, 1); + if (data->arr == NULL) { + PyArray_free(data); + return NPY_FAIL; + } + + *out_stransfer = &_strided_to_strided_wrap_copy_swap; + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +/*************************** DTYPE CAST FUNCTIONS *************************/ + +/* Does a simple aligned cast */ +typedef struct { + NpyAuxData base; + PyArray_VectorUnaryFunc *castfunc; + PyArrayObject *aip, *aop; +} _strided_cast_data; + +/* strided cast data free function */ +static void _strided_cast_data_free(NpyAuxData *data) +{ + _strided_cast_data *d = (_strided_cast_data *)data; + Py_DECREF(d->aip); + Py_DECREF(d->aop); + PyArray_free(data); +} + +/* strided cast data copy function */ +static NpyAuxData *_strided_cast_data_clone(NpyAuxData *data) +{ + _strided_cast_data *newdata = + (_strided_cast_data *)PyArray_malloc(sizeof(_strided_cast_data)); + if (newdata == NULL) { + return NULL; + } + + memcpy(newdata, data, sizeof(_strided_cast_data)); + Py_INCREF(newdata->aip); + Py_INCREF(newdata->aop); + + return (NpyAuxData *)newdata; +} + +static void +_aligned_strided_to_strided_cast(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_cast_data *d = (_strided_cast_data *)data; + PyArray_VectorUnaryFunc *castfunc = d->castfunc; + PyArrayObject *aip = d->aip, *aop = d->aop; + + while (N > 0) { + castfunc(src, dst, 1, aip, aop); + dst += dst_stride; + src += src_stride; + --N; + } +} + +/* This one requires src be of type NPY_OBJECT */ +static void +_aligned_strided_to_strided_cast_decref_src(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_cast_data *d = (_strided_cast_data *)data; + PyArray_VectorUnaryFunc *castfunc = d->castfunc; + PyArrayObject *aip = d->aip, *aop = d->aop; + PyObject *src_ref; + + while (N > 0) { + castfunc(src, dst, 1, aip, aop); + + /* After casting, decrement the source ref */ + NPY_COPY_PYOBJECT_PTR(&src_ref, src); + NPY_DT_DBG_REFTRACE("dec src ref (cast object -> not object)", src_ref); + Py_XDECREF(src_ref); + + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_aligned_contig_to_contig_cast(char *dst, npy_intp NPY_UNUSED(dst_stride), + char *src, npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(itemsize), + NpyAuxData *data) +{ + _strided_cast_data *d = (_strided_cast_data *)data; + + d->castfunc(src, dst, N, d->aip, d->aop); +} + +static int +get_nbo_cast_numeric_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + int src_type_num, int dst_type_num, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + /* Emit a warning if complex imaginary is being cast away */ + if (PyTypeNum_ISCOMPLEX(src_type_num) && + !PyTypeNum_ISCOMPLEX(dst_type_num) && + !PyTypeNum_ISBOOL(dst_type_num)) { + PyObject *cls = NULL, *obj = NULL; + int ret; + obj = PyImport_ImportModule("numpy.core"); + if (obj) { + cls = PyObject_GetAttrString(obj, "ComplexWarning"); + Py_DECREF(obj); + } + ret = PyErr_WarnEx(cls, + "Casting complex values to real discards " + "the imaginary part", 1); + Py_XDECREF(cls); + if (ret < 0) { + return NPY_FAIL; + } + } + + *out_stransfer = PyArray_GetStridedNumericCastFn(aligned, + src_stride, dst_stride, + src_type_num, dst_type_num); + *out_transferdata = NULL; + if (*out_stransfer == NULL) { + PyErr_SetString(PyExc_ValueError, + "unexpected error in GetStridedNumericCastFn"); + return NPY_FAIL; + } + + return NPY_SUCCEED; +} + +/* + * Does a datetime->datetime, timedelta->timedelta, + * datetime->ascii, or ascii->datetime cast + */ +typedef struct { + NpyAuxData base; + /* The conversion fraction */ + npy_int64 num, denom; + /* For the datetime -> string conversion, the dst string length */ + npy_intp src_itemsize, dst_itemsize; + /* + * A buffer of size 'src_itemsize + 1', for when the input + * string is exactly of length src_itemsize with no NULL + * terminator. + */ + char *tmp_buffer; + /* + * The metadata for when dealing with Months or Years + * which behave non-linearly with respect to the other + * units. + */ + PyArray_DatetimeMetaData src_meta, dst_meta; +} _strided_datetime_cast_data; + +/* strided datetime cast data free function */ +static void _strided_datetime_cast_data_free(NpyAuxData *data) +{ + _strided_datetime_cast_data *d = (_strided_datetime_cast_data *)data; + PyArray_free(d->tmp_buffer); + PyArray_free(data); +} + +/* strided datetime cast data copy function */ +static NpyAuxData *_strided_datetime_cast_data_clone(NpyAuxData *data) +{ + _strided_datetime_cast_data *newdata = + (_strided_datetime_cast_data *)PyArray_malloc( + sizeof(_strided_datetime_cast_data)); + if (newdata == NULL) { + return NULL; + } + + memcpy(newdata, data, sizeof(_strided_datetime_cast_data)); + if (newdata->tmp_buffer != NULL) { + newdata->tmp_buffer = PyArray_malloc(newdata->src_itemsize + 1); + if (newdata->tmp_buffer == NULL) { + PyArray_free(newdata); + return NULL; + } + } + + return (NpyAuxData *)newdata; +} + +static void +_strided_to_strided_datetime_general_cast(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_datetime_cast_data *d = (_strided_datetime_cast_data *)data; + npy_int64 dt; + npy_datetimestruct dts; + + while (N > 0) { + memcpy(&dt, src, sizeof(dt)); + + if (convert_datetime_to_datetimestruct(&d->src_meta, + dt, &dts) < 0) { + dt = NPY_DATETIME_NAT; + } + else { + if (convert_datetimestruct_to_datetime(&d->dst_meta, + &dts, &dt) < 0) { + dt = NPY_DATETIME_NAT; + } + } + + memcpy(dst, &dt, sizeof(dt)); + + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_strided_to_strided_datetime_cast(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_datetime_cast_data *d = (_strided_datetime_cast_data *)data; + npy_int64 num = d->num, denom = d->denom; + npy_int64 dt; + + while (N > 0) { + memcpy(&dt, src, sizeof(dt)); + + if (dt != NPY_DATETIME_NAT) { + /* Apply the scaling */ + if (dt < 0) { + dt = (dt * num - (denom - 1)) / denom; + } + else { + dt = dt * num / denom; + } + } + + memcpy(dst, &dt, sizeof(dt)); + + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_aligned_strided_to_strided_datetime_cast(char *dst, + npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_datetime_cast_data *d = (_strided_datetime_cast_data *)data; + npy_int64 num = d->num, denom = d->denom; + npy_int64 dt; + + while (N > 0) { + dt = *(npy_int64 *)src; + + if (dt != NPY_DATETIME_NAT) { + /* Apply the scaling */ + if (dt < 0) { + dt = (dt * num - (denom - 1)) / denom; + } + else { + dt = dt * num / denom; + } + } + + *(npy_int64 *)dst = dt; + + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_strided_to_strided_datetime_to_string(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *data) +{ + _strided_datetime_cast_data *d = (_strided_datetime_cast_data *)data; + npy_intp dst_itemsize = d->dst_itemsize; + npy_int64 dt; + npy_datetimestruct dts; + + while (N > 0) { + memcpy(&dt, src, sizeof(dt)); + + if (convert_datetime_to_datetimestruct(&d->src_meta, + dt, &dts) < 0) { + /* For an error, produce a 'NaT' string */ + dts.year = NPY_DATETIME_NAT; + } + + /* Initialize the destination to all zeros */ + memset(dst, 0, dst_itemsize); + + /* + * This may also raise an error, but the caller needs + * to use PyErr_Occurred(). + */ + make_iso_8601_datetime(&dts, dst, dst_itemsize, + 0, 0, d->src_meta.base, -1, + NPY_UNSAFE_CASTING); + + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_strided_to_strided_string_to_datetime(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _strided_datetime_cast_data *d = (_strided_datetime_cast_data *)data; + npy_datetimestruct dts; + char *tmp_buffer = d->tmp_buffer; + char *tmp; + + while (N > 0) { + npy_int64 dt = ~NPY_DATETIME_NAT; + + /* Replicating strnlen with memchr, because Mac OS X lacks it */ + tmp = memchr(src, '\0', src_itemsize); + + /* If the string is all full, use the buffer */ + if (tmp == NULL) { + memcpy(tmp_buffer, src, src_itemsize); + tmp_buffer[src_itemsize] = '\0'; + + if (parse_iso_8601_datetime(tmp_buffer, src_itemsize, + d->dst_meta.base, NPY_SAME_KIND_CASTING, + &dts, NULL, NULL) < 0) { + dt = NPY_DATETIME_NAT; + } + } + /* Otherwise parse the data in place */ + else { + if (parse_iso_8601_datetime(src, tmp - src, + d->dst_meta.base, NPY_SAME_KIND_CASTING, + &dts, NULL, NULL) < 0) { + dt = NPY_DATETIME_NAT; + } + } + + /* Convert to the datetime */ + if (dt != NPY_DATETIME_NAT && + convert_datetimestruct_to_datetime(&d->dst_meta, + &dts, &dt) < 0) { + dt = NPY_DATETIME_NAT; + } + + memcpy(dst, &dt, sizeof(dt)); + + dst += dst_stride; + src += src_stride; + --N; + } +} + +/* + * Assumes src_dtype and dst_dtype are both datetimes or both timedeltas + */ +static int +get_nbo_cast_datetime_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + PyArray_DatetimeMetaData *src_meta, *dst_meta; + npy_int64 num = 0, denom = 0; + _strided_datetime_cast_data *data; + + src_meta = get_datetime_metadata_from_dtype(src_dtype); + if (src_meta == NULL) { + return NPY_FAIL; + } + dst_meta = get_datetime_metadata_from_dtype(dst_dtype); + if (dst_meta == NULL) { + return NPY_FAIL; + } + + get_datetime_conversion_factor(src_meta, dst_meta, &num, &denom); + + if (num == 0) { + return NPY_FAIL; + } + + /* Allocate the data for the casting */ + data = (_strided_datetime_cast_data *)PyArray_malloc( + sizeof(_strided_datetime_cast_data)); + if (data == NULL) { + PyErr_NoMemory(); + *out_stransfer = NULL; + *out_transferdata = NULL; + return NPY_FAIL; + } + data->base.free = &_strided_datetime_cast_data_free; + data->base.clone = &_strided_datetime_cast_data_clone; + data->num = num; + data->denom = denom; + data->tmp_buffer = NULL; + + /* + * Special case the datetime (but not timedelta) with the nonlinear + * units (years and months). For timedelta, an average + * years and months value is used. + */ + if (src_dtype->type_num == NPY_DATETIME && + (src_meta->base == NPY_FR_Y || + src_meta->base == NPY_FR_M || + dst_meta->base == NPY_FR_Y || + dst_meta->base == NPY_FR_M)) { + memcpy(&data->src_meta, src_meta, sizeof(data->src_meta)); + memcpy(&data->dst_meta, dst_meta, sizeof(data->dst_meta)); + *out_stransfer = &_strided_to_strided_datetime_general_cast; + } + else if (aligned) { + *out_stransfer = &_aligned_strided_to_strided_datetime_cast; + } + else { + *out_stransfer = &_strided_to_strided_datetime_cast; + } + *out_transferdata = (NpyAuxData *)data; + +#if NPY_DT_DBG_TRACING + printf("Dtype transfer from "); + PyObject_Print((PyObject *)src_dtype, stdout, 0); + printf(" to "); + PyObject_Print((PyObject *)dst_dtype, stdout, 0); + printf("\n"); + printf("has conversion fraction %lld/%lld\n", num, denom); +#endif + + + return NPY_SUCCEED; +} + +static int +get_nbo_datetime_to_string_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + PyArray_DatetimeMetaData *src_meta; + _strided_datetime_cast_data *data; + + src_meta = get_datetime_metadata_from_dtype(src_dtype); + if (src_meta == NULL) { + return NPY_FAIL; + } + + /* Allocate the data for the casting */ + data = (_strided_datetime_cast_data *)PyArray_malloc( + sizeof(_strided_datetime_cast_data)); + if (data == NULL) { + PyErr_NoMemory(); + *out_stransfer = NULL; + *out_transferdata = NULL; + return NPY_FAIL; + } + data->base.free = &_strided_datetime_cast_data_free; + data->base.clone = &_strided_datetime_cast_data_clone; + data->dst_itemsize = dst_dtype->elsize; + data->tmp_buffer = NULL; + + memcpy(&data->src_meta, src_meta, sizeof(data->src_meta)); + + *out_stransfer = &_strided_to_strided_datetime_to_string; + *out_transferdata = (NpyAuxData *)data; + +#if NPY_DT_DBG_TRACING + printf("Dtype transfer from "); + PyObject_Print((PyObject *)src_dtype, stdout, 0); + printf(" to "); + PyObject_Print((PyObject *)dst_dtype, stdout, 0); + printf("\n"); +#endif + + return NPY_SUCCEED; +} + +static int +get_datetime_to_unicode_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + NpyAuxData *castdata = NULL, *todata = NULL, *fromdata = NULL; + PyArray_StridedUnaryOp *caststransfer, *tobuffer, *frombuffer; + PyArray_Descr *str_dtype; + + /* Get an ASCII string data type, adapted to match the UNICODE one */ + str_dtype = PyArray_DescrFromType(NPY_STRING); + PyArray_AdaptFlexibleDType(NULL, dst_dtype, &str_dtype); + if (str_dtype == NULL) { + return NPY_FAIL; + } + + /* Get the copy/swap operation to dst */ + if (PyArray_GetDTypeCopySwapFn(aligned, + src_stride, src_dtype->elsize, + src_dtype, + &tobuffer, &todata) != NPY_SUCCEED) { + Py_DECREF(str_dtype); + return NPY_FAIL; + } + + /* Get the NBO datetime to string aligned contig function */ + if (get_nbo_datetime_to_string_transfer_function(1, + src_dtype->elsize, str_dtype->elsize, + src_dtype, str_dtype, + &caststransfer, &castdata) != NPY_SUCCEED) { + Py_DECREF(str_dtype); + NPY_AUXDATA_FREE(todata); + return NPY_FAIL; + } + + /* Get the cast operation to dst */ + if (PyArray_GetDTypeTransferFunction(aligned, + str_dtype->elsize, dst_stride, + str_dtype, dst_dtype, + 0, + &frombuffer, &fromdata, + out_needs_api) != NPY_SUCCEED) { + Py_DECREF(str_dtype); + NPY_AUXDATA_FREE(todata); + NPY_AUXDATA_FREE(castdata); + return NPY_FAIL; + } + + /* Wrap it all up in a new transfer function + data */ + if (wrap_aligned_contig_transfer_function( + src_dtype->elsize, str_dtype->elsize, + tobuffer, todata, + frombuffer, fromdata, + caststransfer, castdata, + PyDataType_FLAGCHK(str_dtype, NPY_NEEDS_INIT), + out_stransfer, out_transferdata) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(castdata); + NPY_AUXDATA_FREE(todata); + NPY_AUXDATA_FREE(fromdata); + return NPY_FAIL; + } + + Py_DECREF(str_dtype); + + return NPY_SUCCEED; +} + +static int +get_nbo_string_to_datetime_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + PyArray_DatetimeMetaData *dst_meta; + _strided_datetime_cast_data *data; + + dst_meta = get_datetime_metadata_from_dtype(dst_dtype); + if (dst_meta == NULL) { + return NPY_FAIL; + } + + /* Allocate the data for the casting */ + data = (_strided_datetime_cast_data *)PyArray_malloc( + sizeof(_strided_datetime_cast_data)); + if (data == NULL) { + PyErr_NoMemory(); + *out_stransfer = NULL; + *out_transferdata = NULL; + return NPY_FAIL; + } + data->base.free = &_strided_datetime_cast_data_free; + data->base.clone = &_strided_datetime_cast_data_clone; + data->src_itemsize = src_dtype->elsize; + data->tmp_buffer = PyArray_malloc(data->src_itemsize + 1); + if (data->tmp_buffer == NULL) { + PyErr_NoMemory(); + PyArray_free(data); + *out_stransfer = NULL; + *out_transferdata = NULL; + return NPY_FAIL; + } + + memcpy(&data->dst_meta, dst_meta, sizeof(data->dst_meta)); + + *out_stransfer = &_strided_to_strided_string_to_datetime; + *out_transferdata = (NpyAuxData *)data; + +#if NPY_DT_DBG_TRACING + printf("Dtype transfer from "); + PyObject_Print((PyObject *)src_dtype, stdout, 0); + printf(" to "); + PyObject_Print((PyObject *)dst_dtype, stdout, 0); + printf("\n"); +#endif + + return NPY_SUCCEED; +} + +static int +get_unicode_to_datetime_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + NpyAuxData *castdata = NULL, *todata = NULL, *fromdata = NULL; + PyArray_StridedUnaryOp *caststransfer, *tobuffer, *frombuffer; + PyArray_Descr *str_dtype; + + /* Get an ASCII string data type, adapted to match the UNICODE one */ + str_dtype = PyArray_DescrFromType(NPY_STRING); + PyArray_AdaptFlexibleDType(NULL, src_dtype, &str_dtype); + if (str_dtype == NULL) { + return NPY_FAIL; + } + + /* Get the cast operation from src */ + if (PyArray_GetDTypeTransferFunction(aligned, + src_stride, str_dtype->elsize, + src_dtype, str_dtype, + 0, + &tobuffer, &todata, + out_needs_api) != NPY_SUCCEED) { + Py_DECREF(str_dtype); + return NPY_FAIL; + } + + /* Get the string to NBO datetime aligned contig function */ + if (get_nbo_string_to_datetime_transfer_function(1, + str_dtype->elsize, dst_dtype->elsize, + str_dtype, dst_dtype, + &caststransfer, &castdata) != NPY_SUCCEED) { + Py_DECREF(str_dtype); + NPY_AUXDATA_FREE(todata); + return NPY_FAIL; + } + + /* Get the copy/swap operation to dst */ + if (PyArray_GetDTypeCopySwapFn(aligned, + dst_dtype->elsize, dst_stride, + dst_dtype, + &frombuffer, &fromdata) != NPY_SUCCEED) { + Py_DECREF(str_dtype); + NPY_AUXDATA_FREE(todata); + NPY_AUXDATA_FREE(castdata); + return NPY_FAIL; + } + + /* Wrap it all up in a new transfer function + data */ + if (wrap_aligned_contig_transfer_function( + str_dtype->elsize, dst_dtype->elsize, + tobuffer, todata, + frombuffer, fromdata, + caststransfer, castdata, + PyDataType_FLAGCHK(dst_dtype, NPY_NEEDS_INIT), + out_stransfer, out_transferdata) != NPY_SUCCEED) { + Py_DECREF(str_dtype); + NPY_AUXDATA_FREE(castdata); + NPY_AUXDATA_FREE(todata); + NPY_AUXDATA_FREE(fromdata); + return NPY_FAIL; + } + + Py_DECREF(str_dtype); + + return NPY_SUCCEED; +} + +static int +get_nbo_cast_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api, + int *out_needs_wrap) +{ + _strided_cast_data *data; + PyArray_VectorUnaryFunc *castfunc; + PyArray_Descr *tmp_dtype; + npy_intp shape = 1, src_itemsize = src_dtype->elsize, + dst_itemsize = dst_dtype->elsize; + + if (PyTypeNum_ISNUMBER(src_dtype->type_num) && + PyTypeNum_ISNUMBER(dst_dtype->type_num)) { + *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder) || + !PyArray_ISNBO(dst_dtype->byteorder); + return get_nbo_cast_numeric_transfer_function(aligned, + src_stride, dst_stride, + src_dtype->type_num, dst_dtype->type_num, + out_stransfer, out_transferdata); + } + + if (src_dtype->type_num == NPY_DATETIME || + src_dtype->type_num == NPY_TIMEDELTA || + dst_dtype->type_num == NPY_DATETIME || + dst_dtype->type_num == NPY_TIMEDELTA) { + /* A parameterized type, datetime->datetime sometimes needs casting */ + if ((src_dtype->type_num == NPY_DATETIME && + dst_dtype->type_num == NPY_DATETIME) || + (src_dtype->type_num == NPY_TIMEDELTA && + dst_dtype->type_num == NPY_TIMEDELTA)) { + *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder) || + !PyArray_ISNBO(dst_dtype->byteorder); + return get_nbo_cast_datetime_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + out_stransfer, out_transferdata); + } + + /* + * Datetime <-> string conversions can be handled specially. + * The functions may raise an error if the strings have no + * space, or can't be parsed properly. + */ + if (src_dtype->type_num == NPY_DATETIME) { + switch (dst_dtype->type_num) { + case NPY_STRING: + *out_needs_api = 1; + *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder); + return get_nbo_datetime_to_string_transfer_function( + aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + out_stransfer, out_transferdata); + + case NPY_UNICODE: + return get_datetime_to_unicode_transfer_function( + aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + out_stransfer, out_transferdata, + out_needs_api); + } + } + else if (dst_dtype->type_num == NPY_DATETIME) { + switch (src_dtype->type_num) { + case NPY_STRING: + *out_needs_api = 1; + *out_needs_wrap = !PyArray_ISNBO(dst_dtype->byteorder); + return get_nbo_string_to_datetime_transfer_function( + aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + out_stransfer, out_transferdata); + + case NPY_UNICODE: + return get_unicode_to_datetime_transfer_function( + aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + out_stransfer, out_transferdata, + out_needs_api); + } + } + } + + *out_needs_wrap = !aligned || + !PyArray_ISNBO(src_dtype->byteorder) || + !PyArray_ISNBO(dst_dtype->byteorder); + + /* Check the data types whose casting functions use API calls */ + switch (src_dtype->type_num) { + case NPY_OBJECT: + case NPY_STRING: + case NPY_UNICODE: + case NPY_VOID: + if (out_needs_api) { + *out_needs_api = 1; + } + break; + } + switch (dst_dtype->type_num) { + case NPY_OBJECT: + case NPY_STRING: + case NPY_UNICODE: + case NPY_VOID: + if (out_needs_api) { + *out_needs_api = 1; + } + break; + } + + if (PyDataType_FLAGCHK(src_dtype, NPY_NEEDS_PYAPI) || + PyDataType_FLAGCHK(dst_dtype, NPY_NEEDS_PYAPI)) { + if (out_needs_api) { + *out_needs_api = 1; + } + } + + /* Get the cast function */ + castfunc = PyArray_GetCastFunc(src_dtype, dst_dtype->type_num); + if (!castfunc) { + *out_stransfer = NULL; + *out_transferdata = NULL; + return NPY_FAIL; + } + + /* Allocate the data for the casting */ + data = (_strided_cast_data *)PyArray_malloc(sizeof(_strided_cast_data)); + if (data == NULL) { + PyErr_NoMemory(); + *out_stransfer = NULL; + *out_transferdata = NULL; + return NPY_FAIL; + } + data->base.free = &_strided_cast_data_free; + data->base.clone = &_strided_cast_data_clone; + data->castfunc = castfunc; + /* + * TODO: This is a hack so the cast functions have an array. + * The cast functions shouldn't need that. Also, since we + * always handle byte order conversions, this array should + * have native byte order. + */ + if (PyArray_ISNBO(src_dtype->byteorder)) { + tmp_dtype = src_dtype; + Py_INCREF(tmp_dtype); + } + else { + tmp_dtype = PyArray_DescrNewByteorder(src_dtype, NPY_NATIVE); + if (tmp_dtype == NULL) { + PyArray_free(data); + return NPY_FAIL; + } + } + data->aip = (PyArrayObject *)PyArray_NewFromDescr_int(&PyArray_Type, + tmp_dtype, 1, &shape, NULL, NULL, 0, NULL, 0, 1); + if (data->aip == NULL) { + PyArray_free(data); + return NPY_FAIL; + } + /* + * TODO: This is a hack so the cast functions have an array. + * The cast functions shouldn't need that. Also, since we + * always handle byte order conversions, this array should + * have native byte order. + */ + if (PyArray_ISNBO(dst_dtype->byteorder)) { + tmp_dtype = dst_dtype; + Py_INCREF(tmp_dtype); + } + else { + tmp_dtype = PyArray_DescrNewByteorder(dst_dtype, NPY_NATIVE); + if (tmp_dtype == NULL) { + Py_DECREF(data->aip); + PyArray_free(data); + return NPY_FAIL; + } + } + data->aop = (PyArrayObject *)PyArray_NewFromDescr_int(&PyArray_Type, + tmp_dtype, 1, &shape, NULL, NULL, 0, NULL, 0, 1); + if (data->aop == NULL) { + Py_DECREF(data->aip); + PyArray_free(data); + return NPY_FAIL; + } + + /* If it's aligned and all native byte order, we're all done */ + if (move_references && src_dtype->type_num == NPY_OBJECT) { + *out_stransfer = _aligned_strided_to_strided_cast_decref_src; + } + else { + /* + * Use the contig version if the strides are contiguous or + * we're telling the caller to wrap the return, because + * the wrapping uses a contiguous buffer. + */ + if ((src_stride == src_itemsize && dst_stride == dst_itemsize) || + *out_needs_wrap) { + *out_stransfer = _aligned_contig_to_contig_cast; + } + else { + *out_stransfer = _aligned_strided_to_strided_cast; + } + } + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +static int +get_cast_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + PyArray_StridedUnaryOp *caststransfer; + NpyAuxData *castdata, *todata = NULL, *fromdata = NULL; + int needs_wrap = 0; + npy_intp src_itemsize = src_dtype->elsize, + dst_itemsize = dst_dtype->elsize; + + if (get_nbo_cast_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + &caststransfer, + &castdata, + out_needs_api, + &needs_wrap) != NPY_SUCCEED) { + return NPY_FAIL; + } + + /* + * If all native byte order and doesn't need alignment wrapping, + * return the function + */ + if (!needs_wrap) { + *out_stransfer = caststransfer; + *out_transferdata = castdata; + + return NPY_SUCCEED; + } + /* Otherwise, we have to copy and/or swap to aligned temporaries */ + else { + PyArray_StridedUnaryOp *tobuffer, *frombuffer; + + /* Get the copy/swap operation from src */ + PyArray_GetDTypeCopySwapFn(aligned, + src_stride, src_itemsize, + src_dtype, + &tobuffer, &todata); + + + /* Get the copy/swap operation to dst */ + PyArray_GetDTypeCopySwapFn(aligned, + dst_itemsize, dst_stride, + dst_dtype, + &frombuffer, &fromdata); + + if (frombuffer == NULL || tobuffer == NULL) { + NPY_AUXDATA_FREE(castdata); + NPY_AUXDATA_FREE(todata); + NPY_AUXDATA_FREE(fromdata); + return NPY_FAIL; + } + + *out_stransfer = caststransfer; + + /* Wrap it all up in a new transfer function + data */ + if (wrap_aligned_contig_transfer_function( + src_itemsize, dst_itemsize, + tobuffer, todata, + frombuffer, fromdata, + caststransfer, castdata, + PyDataType_FLAGCHK(dst_dtype, NPY_NEEDS_INIT), + out_stransfer, out_transferdata) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(castdata); + NPY_AUXDATA_FREE(todata); + NPY_AUXDATA_FREE(fromdata); + return NPY_FAIL; + } + + return NPY_SUCCEED; + } +} + +/**************************** COPY 1 TO N CONTIGUOUS ************************/ + +/* Copies 1 element to N contiguous elements */ +typedef struct { + NpyAuxData base; + PyArray_StridedUnaryOp *stransfer; + NpyAuxData *data; + npy_intp N, dst_itemsize; + /* If this is non-NULL the source type has references needing a decref */ + PyArray_StridedUnaryOp *stransfer_finish_src; + NpyAuxData *data_finish_src; +} _one_to_n_data; + +/* transfer data free function */ +static void _one_to_n_data_free(NpyAuxData *data) +{ + _one_to_n_data *d = (_one_to_n_data *)data; + NPY_AUXDATA_FREE(d->data); + NPY_AUXDATA_FREE(d->data_finish_src); + PyArray_free(data); +} + +/* transfer data copy function */ +static NpyAuxData *_one_to_n_data_clone(NpyAuxData *data) +{ + _one_to_n_data *d = (_one_to_n_data *)data; + _one_to_n_data *newdata; + + /* Allocate the data, and populate it */ + newdata = (_one_to_n_data *)PyArray_malloc(sizeof(_one_to_n_data)); + if (newdata == NULL) { + return NULL; + } + memcpy(newdata, data, sizeof(_one_to_n_data)); + if (d->data != NULL) { + newdata->data = NPY_AUXDATA_CLONE(d->data); + if (newdata->data == NULL) { + PyArray_free(newdata); + return NULL; + } + } + if (d->data_finish_src != NULL) { + newdata->data_finish_src = NPY_AUXDATA_CLONE(d->data_finish_src); + if (newdata->data_finish_src == NULL) { + NPY_AUXDATA_FREE(newdata->data); + PyArray_free(newdata); + return NULL; + } + } + + return (NpyAuxData *)newdata; +} + +static void +_strided_to_strided_one_to_n(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _one_to_n_data *d = (_one_to_n_data *)data; + PyArray_StridedUnaryOp *subtransfer = d->stransfer; + NpyAuxData *subdata = d->data; + npy_intp subN = d->N, dst_itemsize = d->dst_itemsize; + + while (N > 0) { + subtransfer(dst, dst_itemsize, + src, 0, + subN, src_itemsize, + subdata); + + src += src_stride; + dst += dst_stride; + --N; + } +} + +static void +_strided_to_strided_one_to_n_with_finish(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _one_to_n_data *d = (_one_to_n_data *)data; + PyArray_StridedUnaryOp *subtransfer = d->stransfer, + *stransfer_finish_src = d->stransfer_finish_src; + NpyAuxData *subdata = d->data, *data_finish_src = d->data_finish_src; + npy_intp subN = d->N, dst_itemsize = d->dst_itemsize; + + while (N > 0) { + subtransfer(dst, dst_itemsize, + src, 0, + subN, src_itemsize, + subdata); + + + stransfer_finish_src(NULL, 0, + src, 0, + 1, src_itemsize, + data_finish_src); + + src += src_stride; + dst += dst_stride; + --N; + } +} + +/* + * Wraps a transfer function to produce one that copies one element + * of src to N contiguous elements of dst. If stransfer_finish_src is + * not NULL, it should be a transfer function which just affects + * src, for example to do a final DECREF operation for references. + */ +static int +wrap_transfer_function_one_to_n( + PyArray_StridedUnaryOp *stransfer_inner, + NpyAuxData *data_inner, + PyArray_StridedUnaryOp *stransfer_finish_src, + NpyAuxData *data_finish_src, + npy_intp dst_itemsize, + npy_intp N, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + _one_to_n_data *data; + + + data = PyArray_malloc(sizeof(_one_to_n_data)); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + + data->base.free = &_one_to_n_data_free; + data->base.clone = &_one_to_n_data_clone; + data->stransfer = stransfer_inner; + data->data = data_inner; + data->stransfer_finish_src = stransfer_finish_src; + data->data_finish_src = data_finish_src; + data->N = N; + data->dst_itemsize = dst_itemsize; + + if (stransfer_finish_src == NULL) { + *out_stransfer = &_strided_to_strided_one_to_n; + } + else { + *out_stransfer = &_strided_to_strided_one_to_n_with_finish; + } + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +static int +get_one_to_n_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + npy_intp N, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + PyArray_StridedUnaryOp *stransfer, *stransfer_finish_src = NULL; + NpyAuxData *data, *data_finish_src = NULL; + + /* + * move_references is set to 0, handled in the wrapping transfer fn, + * src_stride is set to zero, because its 1 to N copying, + * and dst_stride is set to contiguous, because subarrays are always + * contiguous. + */ + if (PyArray_GetDTypeTransferFunction(aligned, + 0, dst_dtype->elsize, + src_dtype, dst_dtype, + 0, + &stransfer, &data, + out_needs_api) != NPY_SUCCEED) { + return NPY_FAIL; + } + + /* If the src object will need a DECREF, set src_dtype */ + if (move_references && PyDataType_REFCHK(src_dtype)) { + if (get_decsrcref_transfer_function(aligned, + src_stride, + src_dtype, + &stransfer_finish_src, + &data_finish_src, + out_needs_api) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(data); + return NPY_FAIL; + } + } + + if (wrap_transfer_function_one_to_n(stransfer, data, + stransfer_finish_src, data_finish_src, + dst_dtype->elsize, + N, + out_stransfer, out_transferdata) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(data); + NPY_AUXDATA_FREE(data_finish_src); + return NPY_FAIL; + } + + return NPY_SUCCEED; +} + +/**************************** COPY N TO N CONTIGUOUS ************************/ + +/* Copies N contiguous elements to N contiguous elements */ +typedef struct { + NpyAuxData base; + PyArray_StridedUnaryOp *stransfer; + NpyAuxData *data; + npy_intp N, src_itemsize, dst_itemsize; +} _n_to_n_data; + +/* transfer data free function */ +static void _n_to_n_data_free(NpyAuxData *data) +{ + _n_to_n_data *d = (_n_to_n_data *)data; + NPY_AUXDATA_FREE(d->data); + PyArray_free(data); +} + +/* transfer data copy function */ +static NpyAuxData *_n_to_n_data_clone(NpyAuxData *data) +{ + _n_to_n_data *d = (_n_to_n_data *)data; + _n_to_n_data *newdata; + + /* Allocate the data, and populate it */ + newdata = (_n_to_n_data *)PyArray_malloc(sizeof(_n_to_n_data)); + if (newdata == NULL) { + return NULL; + } + memcpy(newdata, data, sizeof(_n_to_n_data)); + if (newdata->data != NULL) { + newdata->data = NPY_AUXDATA_CLONE(d->data); + if (newdata->data == NULL) { + PyArray_free(newdata); + return NULL; + } + } + + return (NpyAuxData *)newdata; +} + +static void +_strided_to_strided_n_to_n(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *data) +{ + _n_to_n_data *d = (_n_to_n_data *)data; + PyArray_StridedUnaryOp *subtransfer = d->stransfer; + NpyAuxData *subdata = d->data; + npy_intp subN = d->N, src_subitemsize = d->src_itemsize, + dst_subitemsize = d->dst_itemsize; + + while (N > 0) { + subtransfer(dst, dst_subitemsize, + src, src_subitemsize, + subN, src_subitemsize, + subdata); + + src += src_stride; + dst += dst_stride; + --N; + } +} + +static void +_contig_to_contig_n_to_n(char *dst, npy_intp NPY_UNUSED(dst_stride), + char *src, npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *data) +{ + _n_to_n_data *d = (_n_to_n_data *)data; + PyArray_StridedUnaryOp *subtransfer = d->stransfer; + NpyAuxData *subdata = d->data; + npy_intp subN = d->N, src_subitemsize = d->src_itemsize, + dst_subitemsize = d->dst_itemsize; + + subtransfer(dst, dst_subitemsize, + src, src_subitemsize, + subN*N, src_subitemsize, + subdata); +} + +/* + * Wraps a transfer function to produce one that copies N contiguous elements + * of src to N contiguous elements of dst. + */ +static int +wrap_transfer_function_n_to_n( + PyArray_StridedUnaryOp *stransfer_inner, + NpyAuxData *data_inner, + npy_intp src_stride, npy_intp dst_stride, + npy_intp src_itemsize, npy_intp dst_itemsize, + npy_intp N, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata) +{ + _n_to_n_data *data; + + data = PyArray_malloc(sizeof(_n_to_n_data)); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + + data->base.free = &_n_to_n_data_free; + data->base.clone = &_n_to_n_data_clone; + data->stransfer = stransfer_inner; + data->data = data_inner; + data->N = N; + data->src_itemsize = src_itemsize; + data->dst_itemsize = dst_itemsize; + + /* + * If the N subarray elements exactly fit in the strides, + * then can do a faster contiguous transfer. + */ + if (src_stride == N * src_itemsize && + dst_stride == N * dst_itemsize) { + *out_stransfer = &_contig_to_contig_n_to_n; + } + else { + *out_stransfer = &_strided_to_strided_n_to_n; + } + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +static int +get_n_to_n_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + npy_intp N, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + PyArray_StridedUnaryOp *stransfer; + NpyAuxData *data; + + /* + * src_stride and dst_stride are set to contiguous, because + * subarrays are always contiguous. + */ + if (PyArray_GetDTypeTransferFunction(aligned, + src_dtype->elsize, dst_dtype->elsize, + src_dtype, dst_dtype, + move_references, + &stransfer, &data, + out_needs_api) != NPY_SUCCEED) { + return NPY_FAIL; + } + + if (wrap_transfer_function_n_to_n(stransfer, data, + src_stride, dst_stride, + src_dtype->elsize, dst_dtype->elsize, + N, + out_stransfer, + out_transferdata) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(data); + return NPY_FAIL; + } + + return NPY_SUCCEED; +} + +/********************** COPY WITH SUBARRAY BROADCAST ************************/ + +typedef struct { + npy_intp offset, count; +} _subarray_broadcast_offsetrun; + +/* Copies element with subarray broadcasting */ +typedef struct { + NpyAuxData base; + PyArray_StridedUnaryOp *stransfer; + NpyAuxData *data; + npy_intp src_N, dst_N, src_itemsize, dst_itemsize; + PyArray_StridedUnaryOp *stransfer_decsrcref; + NpyAuxData *data_decsrcref; + PyArray_StridedUnaryOp *stransfer_decdstref; + NpyAuxData *data_decdstref; + /* This gets a run-length encoded representation of the transfer */ + npy_intp run_count; + _subarray_broadcast_offsetrun offsetruns; +} _subarray_broadcast_data; + +/* transfer data free function */ +static void _subarray_broadcast_data_free(NpyAuxData *data) +{ + _subarray_broadcast_data *d = (_subarray_broadcast_data *)data; + NPY_AUXDATA_FREE(d->data); + NPY_AUXDATA_FREE(d->data_decsrcref); + NPY_AUXDATA_FREE(d->data_decdstref); + PyArray_free(data); +} + +/* transfer data copy function */ +static NpyAuxData *_subarray_broadcast_data_clone( NpyAuxData *data) +{ + _subarray_broadcast_data *d = (_subarray_broadcast_data *)data; + _subarray_broadcast_data *newdata; + npy_intp run_count = d->run_count, structsize; + + structsize = sizeof(_subarray_broadcast_data) + + run_count*sizeof(_subarray_broadcast_offsetrun); + + /* Allocate the data and populate it */ + newdata = (_subarray_broadcast_data *)PyArray_malloc(structsize); + if (newdata == NULL) { + return NULL; + } + memcpy(newdata, data, structsize); + if (d->data != NULL) { + newdata->data = NPY_AUXDATA_CLONE(d->data); + if (newdata->data == NULL) { + PyArray_free(newdata); + return NULL; + } + } + if (d->data_decsrcref != NULL) { + newdata->data_decsrcref = NPY_AUXDATA_CLONE(d->data_decsrcref); + if (newdata->data_decsrcref == NULL) { + NPY_AUXDATA_FREE(newdata->data); + PyArray_free(newdata); + return NULL; + } + } + if (d->data_decdstref != NULL) { + newdata->data_decdstref = NPY_AUXDATA_CLONE(d->data_decdstref); + if (newdata->data_decdstref == NULL) { + NPY_AUXDATA_FREE(newdata->data); + NPY_AUXDATA_FREE(newdata->data_decsrcref); + PyArray_free(newdata); + return NULL; + } + } + + return (NpyAuxData *)newdata; +} + +static void +_strided_to_strided_subarray_broadcast(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *data) +{ + _subarray_broadcast_data *d = (_subarray_broadcast_data *)data; + PyArray_StridedUnaryOp *subtransfer = d->stransfer; + NpyAuxData *subdata = d->data; + npy_intp run, run_count = d->run_count, + src_subitemsize = d->src_itemsize, + dst_subitemsize = d->dst_itemsize; + npy_intp loop_index, offset, count; + char *dst_ptr; + _subarray_broadcast_offsetrun *offsetruns = &d->offsetruns; + + while (N > 0) { + loop_index = 0; + for (run = 0; run < run_count; ++run) { + offset = offsetruns[run].offset; + count = offsetruns[run].count; + dst_ptr = dst + loop_index*dst_subitemsize; + if (offset != -1) { + subtransfer(dst_ptr, dst_subitemsize, + src + offset, src_subitemsize, + count, src_subitemsize, + subdata); + } + else { + memset(dst_ptr, 0, count*dst_subitemsize); + } + loop_index += count; + } + + src += src_stride; + dst += dst_stride; + --N; + } +} + + +static void +_strided_to_strided_subarray_broadcast_withrefs(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *data) +{ + _subarray_broadcast_data *d = (_subarray_broadcast_data *)data; + PyArray_StridedUnaryOp *subtransfer = d->stransfer; + NpyAuxData *subdata = d->data; + PyArray_StridedUnaryOp *stransfer_decsrcref = d->stransfer_decsrcref; + NpyAuxData *data_decsrcref = d->data_decsrcref; + PyArray_StridedUnaryOp *stransfer_decdstref = d->stransfer_decdstref; + NpyAuxData *data_decdstref = d->data_decdstref; + npy_intp run, run_count = d->run_count, + src_subitemsize = d->src_itemsize, + dst_subitemsize = d->dst_itemsize, + src_subN = d->src_N; + npy_intp loop_index, offset, count; + char *dst_ptr; + _subarray_broadcast_offsetrun *offsetruns = &d->offsetruns; + + while (N > 0) { + loop_index = 0; + for (run = 0; run < run_count; ++run) { + offset = offsetruns[run].offset; + count = offsetruns[run].count; + dst_ptr = dst + loop_index*dst_subitemsize; + if (offset != -1) { + subtransfer(dst_ptr, dst_subitemsize, + src + offset, src_subitemsize, + count, src_subitemsize, + subdata); + } + else { + if (stransfer_decdstref != NULL) { + stransfer_decdstref(NULL, 0, dst_ptr, dst_subitemsize, + count, dst_subitemsize, + data_decdstref); + } + memset(dst_ptr, 0, count*dst_subitemsize); + } + loop_index += count; + } + + if (stransfer_decsrcref != NULL) { + stransfer_decsrcref(NULL, 0, src, src_subitemsize, + src_subN, src_subitemsize, + data_decsrcref); + } + + src += src_stride; + dst += dst_stride; + --N; + } +} + + +static int +get_subarray_broadcast_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + npy_intp src_size, npy_intp dst_size, + PyArray_Dims src_shape, PyArray_Dims dst_shape, + int move_references, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + _subarray_broadcast_data *data; + npy_intp structsize, loop_index, run, run_size, + src_index, dst_index, i, ndim; + _subarray_broadcast_offsetrun *offsetruns; + + structsize = sizeof(_subarray_broadcast_data) + + dst_size*sizeof(_subarray_broadcast_offsetrun); + + /* Allocate the data and populate it */ + data = (_subarray_broadcast_data *)PyArray_malloc(structsize); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + + /* + * move_references is set to 0, handled in the wrapping transfer fn, + * src_stride and dst_stride are set to contiguous, as N will always + * be 1 when it's called. + */ + if (PyArray_GetDTypeTransferFunction(aligned, + src_dtype->elsize, dst_dtype->elsize, + src_dtype, dst_dtype, + 0, + &data->stransfer, &data->data, + out_needs_api) != NPY_SUCCEED) { + PyArray_free(data); + return NPY_FAIL; + } + data->base.free = &_subarray_broadcast_data_free; + data->base.clone = &_subarray_broadcast_data_clone; + data->src_N = src_size; + data->dst_N = dst_size; + data->src_itemsize = src_dtype->elsize; + data->dst_itemsize = dst_dtype->elsize; + + /* If the src object will need a DECREF */ + if (move_references && PyDataType_REFCHK(src_dtype)) { + if (PyArray_GetDTypeTransferFunction(aligned, + src_dtype->elsize, 0, + src_dtype, NULL, + 1, + &data->stransfer_decsrcref, + &data->data_decsrcref, + out_needs_api) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(data->data); + PyArray_free(data); + return NPY_FAIL; + } + } + else { + data->stransfer_decsrcref = NULL; + data->data_decsrcref = NULL; + } + + /* If the dst object needs a DECREF to set it to NULL */ + if (PyDataType_REFCHK(dst_dtype)) { + if (PyArray_GetDTypeTransferFunction(aligned, + dst_dtype->elsize, 0, + dst_dtype, NULL, + 1, + &data->stransfer_decdstref, + &data->data_decdstref, + out_needs_api) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(data->data); + NPY_AUXDATA_FREE(data->data_decsrcref); + PyArray_free(data); + return NPY_FAIL; + } + } + else { + data->stransfer_decdstref = NULL; + data->data_decdstref = NULL; + } + + /* Calculate the broadcasting and set the offsets */ + offsetruns = &data->offsetruns; + ndim = (src_shape.len > dst_shape.len) ? src_shape.len : dst_shape.len; + for (loop_index = 0; loop_index < dst_size; ++loop_index) { + npy_intp src_factor = 1; + + dst_index = loop_index; + src_index = 0; + for (i = ndim-1; i >= 0; --i) { + npy_intp coord = 0, shape; + + /* Get the dst coord of this index for dimension i */ + if (i >= ndim - dst_shape.len) { + shape = dst_shape.ptr[i-(ndim-dst_shape.len)]; + coord = dst_index % shape; + dst_index /= shape; + } + + /* Translate it into a src coord and update src_index */ + if (i >= ndim - src_shape.len) { + shape = src_shape.ptr[i-(ndim-src_shape.len)]; + if (shape == 1) { + coord = 0; + } + else { + if (coord < shape) { + src_index += src_factor*coord; + src_factor *= shape; + } + else { + /* Out of bounds, flag with -1 */ + src_index = -1; + break; + } + } + } + } + /* Set the offset */ + if (src_index == -1) { + offsetruns[loop_index].offset = -1; + } + else { + offsetruns[loop_index].offset = src_index; + } + } + + /* Run-length encode the result */ + run = 0; + run_size = 1; + for (loop_index = 1; loop_index < dst_size; ++loop_index) { + if (offsetruns[run].offset == -1) { + /* Stop the run when there's a valid index again */ + if (offsetruns[loop_index].offset != -1) { + offsetruns[run].count = run_size; + run++; + run_size = 1; + offsetruns[run].offset = offsetruns[loop_index].offset; + } + else { + run_size++; + } + } + else { + /* Stop the run when there's a valid index again */ + if (offsetruns[loop_index].offset != + offsetruns[loop_index-1].offset + 1) { + offsetruns[run].count = run_size; + run++; + run_size = 1; + offsetruns[run].offset = offsetruns[loop_index].offset; + } + else { + run_size++; + } + } + } + offsetruns[run].count = run_size; + run++; + data->run_count = run; + + /* Multiply all the offsets by the src item size */ + while (run--) { + if (offsetruns[run].offset != -1) { + offsetruns[run].offset *= src_dtype->elsize; + } + } + + if (data->stransfer_decsrcref == NULL && + data->stransfer_decdstref == NULL) { + *out_stransfer = &_strided_to_strided_subarray_broadcast; + } + else { + *out_stransfer = &_strided_to_strided_subarray_broadcast_withrefs; + } + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +/* + * Handles subarray transfer. To call this, at least one of the dtype's + * subarrays must be non-NULL + */ +static int +get_subarray_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + PyArray_Dims src_shape = {NULL, -1}, dst_shape = {NULL, -1}; + npy_intp src_size = 1, dst_size = 1; + + /* Get the subarray shapes and sizes */ + if (PyDataType_HASSUBARRAY(src_dtype)) { + if (!(PyArray_IntpConverter(src_dtype->subarray->shape, + &src_shape))) { + PyErr_SetString(PyExc_ValueError, + "invalid subarray shape"); + return NPY_FAIL; + } + src_size = PyArray_MultiplyList(src_shape.ptr, src_shape.len); + src_dtype = src_dtype->subarray->base; + } + if (PyDataType_HASSUBARRAY(dst_dtype)) { + if (!(PyArray_IntpConverter(dst_dtype->subarray->shape, + &dst_shape))) { + npy_free_cache_dim_obj(src_shape); + PyErr_SetString(PyExc_ValueError, + "invalid subarray shape"); + return NPY_FAIL; + } + dst_size = PyArray_MultiplyList(dst_shape.ptr, dst_shape.len); + dst_dtype = dst_dtype->subarray->base; + } + + /* + * Just a straight one-element copy. + */ + if (dst_size == 1 && src_size == 1) { + npy_free_cache_dim_obj(src_shape); + npy_free_cache_dim_obj(dst_shape); + + return PyArray_GetDTypeTransferFunction(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + out_stransfer, out_transferdata, + out_needs_api); + } + /* Copy the src value to all the dst values */ + else if (src_size == 1) { + npy_free_cache_dim_obj(src_shape); + npy_free_cache_dim_obj(dst_shape); + + return get_one_to_n_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + dst_size, + out_stransfer, out_transferdata, + out_needs_api); + } + /* If the shapes match exactly, do an n to n copy */ + else if (src_shape.len == dst_shape.len && + PyArray_CompareLists(src_shape.ptr, dst_shape.ptr, + src_shape.len)) { + npy_free_cache_dim_obj(src_shape); + npy_free_cache_dim_obj(dst_shape); + + return get_n_to_n_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + src_size, + out_stransfer, out_transferdata, + out_needs_api); + } + /* + * Copy the subarray with broadcasting, truncating, and zero-padding + * as necessary. + */ + else { + int ret = get_subarray_broadcast_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + src_size, dst_size, + src_shape, dst_shape, + move_references, + out_stransfer, out_transferdata, + out_needs_api); + + npy_free_cache_dim_obj(src_shape); + npy_free_cache_dim_obj(dst_shape); + return ret; + } +} + +/**************************** COPY FIELDS *******************************/ +typedef struct { + npy_intp src_offset, dst_offset, src_itemsize; + PyArray_StridedUnaryOp *stransfer; + NpyAuxData *data; +} _single_field_transfer; + +typedef struct { + NpyAuxData base; + npy_intp field_count; + + _single_field_transfer fields; +} _field_transfer_data; + +/* transfer data free function */ +static void _field_transfer_data_free(NpyAuxData *data) +{ + _field_transfer_data *d = (_field_transfer_data *)data; + npy_intp i, field_count; + _single_field_transfer *fields; + + field_count = d->field_count; + fields = &d->fields; + + for (i = 0; i < field_count; ++i) { + NPY_AUXDATA_FREE(fields[i].data); + } + PyArray_free(d); +} + +/* transfer data copy function */ +static NpyAuxData *_field_transfer_data_clone(NpyAuxData *data) +{ + _field_transfer_data *d = (_field_transfer_data *)data; + _field_transfer_data *newdata; + npy_intp i, field_count = d->field_count, structsize; + _single_field_transfer *fields, *newfields; + + structsize = sizeof(_field_transfer_data) + + field_count * sizeof(_single_field_transfer); + + /* Allocate the data and populate it */ + newdata = (_field_transfer_data *)PyArray_malloc(structsize); + if (newdata == NULL) { + return NULL; + } + memcpy(newdata, d, structsize); + /* Copy all the fields transfer data */ + fields = &d->fields; + newfields = &newdata->fields; + for (i = 0; i < field_count; ++i) { + if (fields[i].data != NULL) { + newfields[i].data = NPY_AUXDATA_CLONE(fields[i].data); + if (newfields[i].data == NULL) { + for (i = i-1; i >= 0; --i) { + NPY_AUXDATA_FREE(newfields[i].data); + } + PyArray_free(newdata); + return NULL; + } + } + + } + + return (NpyAuxData *)newdata; +} + +static void +_strided_to_strided_field_transfer(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *data) +{ + _field_transfer_data *d = (_field_transfer_data *)data; + npy_intp i, field_count = d->field_count; + _single_field_transfer *field; + + /* Do the transfer a block at a time */ + for (;;) { + field = &d->fields; + if (N > NPY_LOWLEVEL_BUFFER_BLOCKSIZE) { + for (i = 0; i < field_count; ++i, ++field) { + field->stransfer(dst + field->dst_offset, dst_stride, + src + field->src_offset, src_stride, + NPY_LOWLEVEL_BUFFER_BLOCKSIZE, + field->src_itemsize, + field->data); + } + N -= NPY_LOWLEVEL_BUFFER_BLOCKSIZE; + src += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*src_stride; + dst += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*dst_stride; + } + else { + for (i = 0; i < field_count; ++i, ++field) { + field->stransfer(dst + field->dst_offset, dst_stride, + src + field->src_offset, src_stride, + N, + field->src_itemsize, + field->data); + } + return; + } + } +} + +/* + * Handles fields transfer. To call this, at least one of the dtypes + * must have fields. Does not take care of object<->structure conversion + */ +static int +get_fields_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + PyObject *key, *tup, *title; + PyArray_Descr *src_fld_dtype, *dst_fld_dtype; + npy_int i, field_count, structsize; + int src_offset, dst_offset; + _field_transfer_data *data; + _single_field_transfer *fields; + int failed = 0; + + /* + * There are three cases to take care of: 1. src is non-structured, + * 2. dst is non-structured, or 3. both are structured. + */ + + /* 1. src is non-structured. Copy the src value to all the fields of dst */ + if (!PyDataType_HASFIELDS(src_dtype)) { + field_count = PyTuple_GET_SIZE(dst_dtype->names); + + /* Allocate the field-data structure and populate it */ + structsize = sizeof(_field_transfer_data) + + (field_count + 1) * sizeof(_single_field_transfer); + data = (_field_transfer_data *)PyArray_malloc(structsize); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + data->base.free = &_field_transfer_data_free; + data->base.clone = &_field_transfer_data_clone; + fields = &data->fields; + + for (i = 0; i < field_count; ++i) { + key = PyTuple_GET_ITEM(dst_dtype->names, i); + tup = PyDict_GetItem(dst_dtype->fields, key); + if (!PyArg_ParseTuple(tup, "Oi|O", &dst_fld_dtype, + &dst_offset, &title)) { + PyArray_free(data); + return NPY_FAIL; + } + if (PyArray_GetDTypeTransferFunction(0, + src_stride, dst_stride, + src_dtype, dst_fld_dtype, + 0, + &fields[i].stransfer, + &fields[i].data, + out_needs_api) != NPY_SUCCEED) { + for (i = i-1; i >= 0; --i) { + NPY_AUXDATA_FREE(fields[i].data); + } + PyArray_free(data); + return NPY_FAIL; + } + fields[i].src_offset = 0; + fields[i].dst_offset = dst_offset; + fields[i].src_itemsize = src_dtype->elsize; + } + + /* + * If references should be decrefd in src, add + * another transfer function to do that. + */ + if (move_references && PyDataType_REFCHK(src_dtype)) { + if (get_decsrcref_transfer_function(0, + src_stride, + src_dtype, + &fields[field_count].stransfer, + &fields[field_count].data, + out_needs_api) != NPY_SUCCEED) { + for (i = 0; i < field_count; ++i) { + NPY_AUXDATA_FREE(fields[i].data); + } + PyArray_free(data); + return NPY_FAIL; + } + fields[field_count].src_offset = 0; + fields[field_count].dst_offset = 0; + fields[field_count].src_itemsize = src_dtype->elsize; + field_count++; + } + data->field_count = field_count; + + *out_stransfer = &_strided_to_strided_field_transfer; + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; + } + + /* 2. dst is non-structured. Allow transfer from single-field src to dst */ + if (!PyDataType_HASFIELDS(dst_dtype)) { + if (PyTuple_GET_SIZE(src_dtype->names) != 1) { + PyErr_SetString(PyExc_ValueError, + "Can't cast from structure to non-structure, except if the " + "structure only has a single field."); + return NPY_FAIL; + } + + /* Allocate the field-data structure and populate it */ + structsize = sizeof(_field_transfer_data) + + 1 * sizeof(_single_field_transfer); + data = (_field_transfer_data *)PyArray_malloc(structsize); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + data->base.free = &_field_transfer_data_free; + data->base.clone = &_field_transfer_data_clone; + fields = &data->fields; + + key = PyTuple_GET_ITEM(src_dtype->names, 0); + tup = PyDict_GetItem(src_dtype->fields, key); + if (!PyArg_ParseTuple(tup, "Oi|O", + &src_fld_dtype, &src_offset, &title)) { + return NPY_FAIL; + } + + if (PyArray_GetDTypeTransferFunction(0, + src_stride, dst_stride, + src_fld_dtype, dst_dtype, + move_references, + &fields[0].stransfer, + &fields[0].data, + out_needs_api) != NPY_SUCCEED) { + PyArray_free(data); + return NPY_FAIL; + } + fields[0].src_offset = src_offset; + fields[0].dst_offset = 0; + fields[0].src_itemsize = src_fld_dtype->elsize; + + data->field_count = 1; + + *out_stransfer = &_strided_to_strided_field_transfer; + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; + } + + /* 3. Otherwise both src and dst are structured arrays */ + field_count = PyTuple_GET_SIZE(dst_dtype->names); + + /* Match up the fields to copy (field-by-field transfer) */ + if (PyTuple_GET_SIZE(src_dtype->names) != field_count) { + PyErr_SetString(PyExc_ValueError, "structures must have the same size"); + return NPY_FAIL; + } + + /* Allocate the field-data structure and populate it */ + structsize = sizeof(_field_transfer_data) + + field_count * sizeof(_single_field_transfer); + data = (_field_transfer_data *)PyArray_malloc(structsize); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + data->base.free = &_field_transfer_data_free; + data->base.clone = &_field_transfer_data_clone; + fields = &data->fields; + + /* set up the transfer function for each field */ + for (i = 0; i < field_count; ++i) { + key = PyTuple_GET_ITEM(dst_dtype->names, i); + tup = PyDict_GetItem(dst_dtype->fields, key); + if (!PyArg_ParseTuple(tup, "Oi|O", &dst_fld_dtype, + &dst_offset, &title)) { + failed = 1; + break; + } + key = PyTuple_GET_ITEM(src_dtype->names, i); + tup = PyDict_GetItem(src_dtype->fields, key); + if (!PyArg_ParseTuple(tup, "Oi|O", &src_fld_dtype, + &src_offset, &title)) { + failed = 1; + break; + } + + if (PyArray_GetDTypeTransferFunction(0, + src_stride, dst_stride, + src_fld_dtype, dst_fld_dtype, + move_references, + &fields[i].stransfer, + &fields[i].data, + out_needs_api) != NPY_SUCCEED) { + failed = 1; + break; + } + fields[i].src_offset = src_offset; + fields[i].dst_offset = dst_offset; + fields[i].src_itemsize = src_fld_dtype->elsize; + } + + if (failed) { + for (i = i-1; i >= 0; --i) { + NPY_AUXDATA_FREE(fields[i].data); + } + PyArray_free(data); + return NPY_FAIL; + } + + data->field_count = field_count; + + *out_stransfer = &_strided_to_strided_field_transfer; + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +static int +get_decsrcref_fields_transfer_function(int aligned, + npy_intp src_stride, + PyArray_Descr *src_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + PyObject *names, *key, *tup, *title; + PyArray_Descr *src_fld_dtype; + npy_int i, names_size, field_count, structsize; + int src_offset; + _field_transfer_data *data; + _single_field_transfer *fields; + + names = src_dtype->names; + names_size = PyTuple_GET_SIZE(src_dtype->names); + + field_count = names_size; + structsize = sizeof(_field_transfer_data) + + field_count * sizeof(_single_field_transfer); + /* Allocate the data and populate it */ + data = (_field_transfer_data *)PyArray_malloc(structsize); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + data->base.free = &_field_transfer_data_free; + data->base.clone = &_field_transfer_data_clone; + fields = &data->fields; + + field_count = 0; + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + tup = PyDict_GetItem(src_dtype->fields, key); + if (!PyArg_ParseTuple(tup, "Oi|O", &src_fld_dtype, + &src_offset, &title)) { + PyArray_free(data); + return NPY_FAIL; + } + if (PyDataType_REFCHK(src_fld_dtype)) { + if (out_needs_api) { + *out_needs_api = 1; + } + if (get_decsrcref_transfer_function(0, + src_stride, + src_fld_dtype, + &fields[field_count].stransfer, + &fields[field_count].data, + out_needs_api) != NPY_SUCCEED) { + for (i = field_count-1; i >= 0; --i) { + NPY_AUXDATA_FREE(fields[i].data); + } + PyArray_free(data); + return NPY_FAIL; + } + fields[field_count].src_offset = src_offset; + fields[field_count].dst_offset = 0; + fields[field_count].src_itemsize = src_dtype->elsize; + field_count++; + } + } + + data->field_count = field_count; + + *out_stransfer = &_strided_to_strided_field_transfer; + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +static int +get_setdestzero_fields_transfer_function(int aligned, + npy_intp dst_stride, + PyArray_Descr *dst_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + PyObject *names, *key, *tup, *title; + PyArray_Descr *dst_fld_dtype; + npy_int i, names_size, field_count, structsize; + int dst_offset; + _field_transfer_data *data; + _single_field_transfer *fields; + + names = dst_dtype->names; + names_size = PyTuple_GET_SIZE(dst_dtype->names); + + field_count = names_size; + structsize = sizeof(_field_transfer_data) + + field_count * sizeof(_single_field_transfer); + /* Allocate the data and populate it */ + data = (_field_transfer_data *)PyArray_malloc(structsize); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + data->base.free = &_field_transfer_data_free; + data->base.clone = &_field_transfer_data_clone; + fields = &data->fields; + + for (i = 0; i < names_size; ++i) { + key = PyTuple_GET_ITEM(names, i); + tup = PyDict_GetItem(dst_dtype->fields, key); + if (!PyArg_ParseTuple(tup, "Oi|O", &dst_fld_dtype, + &dst_offset, &title)) { + PyArray_free(data); + return NPY_FAIL; + } + if (get_setdstzero_transfer_function(0, + dst_stride, + dst_fld_dtype, + &fields[i].stransfer, + &fields[i].data, + out_needs_api) != NPY_SUCCEED) { + for (i = i-1; i >= 0; --i) { + NPY_AUXDATA_FREE(fields[i].data); + } + PyArray_free(data); + return NPY_FAIL; + } + fields[i].src_offset = 0; + fields[i].dst_offset = dst_offset; + fields[i].src_itemsize = 0; + } + + data->field_count = field_count; + + *out_stransfer = &_strided_to_strided_field_transfer; + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +/************************* MASKED TRANSFER WRAPPER *************************/ + +typedef struct { + NpyAuxData base; + /* The transfer function being wrapped */ + PyArray_StridedUnaryOp *stransfer; + NpyAuxData *transferdata; + + /* The src decref function if necessary */ + PyArray_StridedUnaryOp *decsrcref_stransfer; + NpyAuxData *decsrcref_transferdata; +} _masked_wrapper_transfer_data; + +/* transfer data free function */ +static void _masked_wrapper_transfer_data_free(NpyAuxData *data) +{ + _masked_wrapper_transfer_data *d = (_masked_wrapper_transfer_data *)data; + NPY_AUXDATA_FREE(d->transferdata); + NPY_AUXDATA_FREE(d->decsrcref_transferdata); + PyArray_free(data); +} + +/* transfer data copy function */ +static NpyAuxData *_masked_wrapper_transfer_data_clone(NpyAuxData *data) +{ + _masked_wrapper_transfer_data *d = (_masked_wrapper_transfer_data *)data; + _masked_wrapper_transfer_data *newdata; + + /* Allocate the data and populate it */ + newdata = (_masked_wrapper_transfer_data *)PyArray_malloc( + sizeof(_masked_wrapper_transfer_data)); + if (newdata == NULL) { + return NULL; + } + memcpy(newdata, d, sizeof(_masked_wrapper_transfer_data)); + + /* Clone all the owned auxdata as well */ + if (newdata->transferdata != NULL) { + newdata->transferdata = NPY_AUXDATA_CLONE(newdata->transferdata); + if (newdata->transferdata == NULL) { + PyArray_free(newdata); + return NULL; + } + } + if (newdata->decsrcref_transferdata != NULL) { + newdata->decsrcref_transferdata = + NPY_AUXDATA_CLONE(newdata->decsrcref_transferdata); + if (newdata->decsrcref_transferdata == NULL) { + NPY_AUXDATA_FREE(newdata->transferdata); + PyArray_free(newdata); + return NULL; + } + } + + return (NpyAuxData *)newdata; +} + +static void _strided_masked_wrapper_decsrcref_transfer_function( + char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_bool *mask, npy_intp mask_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *transferdata) +{ + _masked_wrapper_transfer_data *d = + (_masked_wrapper_transfer_data *)transferdata; + npy_intp subloopsize; + PyArray_StridedUnaryOp *unmasked_stransfer, *decsrcref_stransfer; + NpyAuxData *unmasked_transferdata, *decsrcref_transferdata; + + unmasked_stransfer = d->stransfer; + unmasked_transferdata = d->transferdata; + decsrcref_stransfer = d->decsrcref_stransfer; + decsrcref_transferdata = d->decsrcref_transferdata; + + while (N > 0) { + /* Skip masked values, still calling decsrcref for move_references */ + mask = (npy_bool*)npy_memchr((char *)mask, 0, mask_stride, N, + &subloopsize, 1); + decsrcref_stransfer(NULL, 0, src, src_stride, + subloopsize, src_itemsize, decsrcref_transferdata); + dst += subloopsize * dst_stride; + src += subloopsize * src_stride; + N -= subloopsize; + /* Process unmasked values */ + mask = (npy_bool*)npy_memchr((char *)mask, 0, mask_stride, N, + &subloopsize, 0); + unmasked_stransfer(dst, dst_stride, src, src_stride, + subloopsize, src_itemsize, unmasked_transferdata); + dst += subloopsize * dst_stride; + src += subloopsize * src_stride; + N -= subloopsize; + } +} + +static void _strided_masked_wrapper_transfer_function( + char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_bool *mask, npy_intp mask_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *transferdata) +{ + + _masked_wrapper_transfer_data *d = + (_masked_wrapper_transfer_data *)transferdata; + npy_intp subloopsize; + PyArray_StridedUnaryOp *unmasked_stransfer; + NpyAuxData *unmasked_transferdata; + + unmasked_stransfer = d->stransfer; + unmasked_transferdata = d->transferdata; + + while (N > 0) { + /* Skip masked values */ + mask = (npy_bool*)npy_memchr((char *)mask, 0, mask_stride, N, + &subloopsize, 1); + dst += subloopsize * dst_stride; + src += subloopsize * src_stride; + N -= subloopsize; + /* Process unmasked values */ + mask = (npy_bool*)npy_memchr((char *)mask, 0, mask_stride, N, + &subloopsize, 0); + unmasked_stransfer(dst, dst_stride, src, src_stride, + subloopsize, src_itemsize, unmasked_transferdata); + dst += subloopsize * dst_stride; + src += subloopsize * src_stride; + N -= subloopsize; + } +} + + +/************************* DEST BOOL SETONE *******************************/ + +static void +_null_to_strided_set_bool_one(char *dst, + npy_intp dst_stride, + char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *NPY_UNUSED(data)) +{ + /* bool type is one byte, so can just use the char */ + + while (N > 0) { + *dst = 1; + + dst += dst_stride; + --N; + } +} + +static void +_null_to_contig_set_bool_one(char *dst, + npy_intp NPY_UNUSED(dst_stride), + char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *NPY_UNUSED(data)) +{ + /* bool type is one byte, so can just use the char */ + + memset(dst, 1, N); +} + +/* Only for the bool type, sets the destination to 1 */ +NPY_NO_EXPORT int +get_bool_setdstone_transfer_function(npy_intp dst_stride, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *NPY_UNUSED(out_needs_api)) +{ + if (dst_stride == 1) { + *out_stransfer = &_null_to_contig_set_bool_one; + } + else { + *out_stransfer = &_null_to_strided_set_bool_one; + } + *out_transferdata = NULL; + + return NPY_SUCCEED; +} + +/*************************** DEST SETZERO *******************************/ + +/* Sets dest to zero */ +typedef struct { + NpyAuxData base; + npy_intp dst_itemsize; +} _dst_memset_zero_data; + +/* zero-padded data copy function */ +static NpyAuxData *_dst_memset_zero_data_clone(NpyAuxData *data) +{ + _dst_memset_zero_data *newdata = + (_dst_memset_zero_data *)PyArray_malloc( + sizeof(_dst_memset_zero_data)); + if (newdata == NULL) { + return NULL; + } + + memcpy(newdata, data, sizeof(_dst_memset_zero_data)); + + return (NpyAuxData *)newdata; +} + +static void +_null_to_strided_memset_zero(char *dst, + npy_intp dst_stride, + char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *data) +{ + _dst_memset_zero_data *d = (_dst_memset_zero_data *)data; + npy_intp dst_itemsize = d->dst_itemsize; + + while (N > 0) { + memset(dst, 0, dst_itemsize); + dst += dst_stride; + --N; + } +} + +static void +_null_to_contig_memset_zero(char *dst, + npy_intp dst_stride, + char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *data) +{ + _dst_memset_zero_data *d = (_dst_memset_zero_data *)data; + npy_intp dst_itemsize = d->dst_itemsize; + + memset(dst, 0, N*dst_itemsize); +} + +static void +_null_to_strided_reference_setzero(char *dst, + npy_intp dst_stride, + char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *NPY_UNUSED(data)) +{ + PyObject *dst_ref = NULL; + + while (N > 0) { + NPY_COPY_PYOBJECT_PTR(&dst_ref, dst); + + /* Release the reference in dst */ + NPY_DT_DBG_REFTRACE("dec dest ref (to set zero)", dst_ref); + Py_XDECREF(dst_ref); + + /* Set it to zero */ + dst_ref = NULL; + NPY_COPY_PYOBJECT_PTR(dst, &dst_ref); + + dst += dst_stride; + --N; + } +} + +NPY_NO_EXPORT int +get_setdstzero_transfer_function(int aligned, + npy_intp dst_stride, + PyArray_Descr *dst_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + _dst_memset_zero_data *data; + + /* If there are no references, just set the whole thing to zero */ + if (!PyDataType_REFCHK(dst_dtype)) { + data = (_dst_memset_zero_data *) + PyArray_malloc(sizeof(_dst_memset_zero_data)); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } + + data->base.free = (NpyAuxData_FreeFunc *)(&PyArray_free); + data->base.clone = &_dst_memset_zero_data_clone; + data->dst_itemsize = dst_dtype->elsize; + + if (dst_stride == data->dst_itemsize) { + *out_stransfer = &_null_to_contig_memset_zero; + } + else { + *out_stransfer = &_null_to_strided_memset_zero; + } + *out_transferdata = (NpyAuxData *)data; + } + /* If it's exactly one reference, use the decref function */ + else if (dst_dtype->type_num == NPY_OBJECT) { + if (out_needs_api) { + *out_needs_api = 1; + } + + *out_stransfer = &_null_to_strided_reference_setzero; + *out_transferdata = NULL; + } + /* If there are subarrays, need to wrap it */ + else if (PyDataType_HASSUBARRAY(dst_dtype)) { + PyArray_Dims dst_shape = {NULL, -1}; + npy_intp dst_size = 1; + PyArray_StridedUnaryOp *contig_stransfer; + NpyAuxData *contig_data; + + if (out_needs_api) { + *out_needs_api = 1; + } + + if (!(PyArray_IntpConverter(dst_dtype->subarray->shape, + &dst_shape))) { + PyErr_SetString(PyExc_ValueError, + "invalid subarray shape"); + return NPY_FAIL; + } + dst_size = PyArray_MultiplyList(dst_shape.ptr, dst_shape.len); + npy_free_cache_dim_obj(dst_shape); + + /* Get a function for contiguous dst of the subarray type */ + if (get_setdstzero_transfer_function(aligned, + dst_dtype->subarray->base->elsize, + dst_dtype->subarray->base, + &contig_stransfer, &contig_data, + out_needs_api) != NPY_SUCCEED) { + return NPY_FAIL; + } + + if (wrap_transfer_function_n_to_n(contig_stransfer, contig_data, + 0, dst_stride, + 0, dst_dtype->subarray->base->elsize, + dst_size, + out_stransfer, out_transferdata) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(contig_data); + return NPY_FAIL; + } + } + /* If there are fields, need to do each field */ + else if (PyDataType_HASFIELDS(dst_dtype)) { + if (out_needs_api) { + *out_needs_api = 1; + } + + return get_setdestzero_fields_transfer_function(aligned, + dst_stride, dst_dtype, + out_stransfer, + out_transferdata, + out_needs_api); + } + + return NPY_SUCCEED; +} + +static void +_dec_src_ref_nop(char *NPY_UNUSED(dst), + npy_intp NPY_UNUSED(dst_stride), + char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride), + npy_intp NPY_UNUSED(N), + npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *NPY_UNUSED(data)) +{ + /* NOP */ +} + +static void +_strided_to_null_dec_src_ref_reference(char *NPY_UNUSED(dst), + npy_intp NPY_UNUSED(dst_stride), + char *src, npy_intp src_stride, + npy_intp N, + npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *NPY_UNUSED(data)) +{ + PyObject *src_ref = NULL; + while (N > 0) { + NPY_COPY_PYOBJECT_PTR(&src_ref, src); + + /* Release the reference in src */ + NPY_DT_DBG_REFTRACE("dec src ref (null dst)", src_ref); + Py_XDECREF(src_ref); + + src += src_stride; + --N; + } +} + + +NPY_NO_EXPORT int +get_decsrcref_transfer_function(int aligned, + npy_intp src_stride, + PyArray_Descr *src_dtype, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + /* If there are no references, it's a nop */ + if (!PyDataType_REFCHK(src_dtype)) { + *out_stransfer = &_dec_src_ref_nop; + *out_transferdata = NULL; + + return NPY_SUCCEED; + } + /* If it's a single reference, it's one decref */ + else if (src_dtype->type_num == NPY_OBJECT) { + if (out_needs_api) { + *out_needs_api = 1; + } + + *out_stransfer = &_strided_to_null_dec_src_ref_reference; + *out_transferdata = NULL; + + return NPY_SUCCEED; + } + /* If there are subarrays, need to wrap it */ + else if (PyDataType_HASSUBARRAY(src_dtype)) { + PyArray_Dims src_shape = {NULL, -1}; + npy_intp src_size = 1; + PyArray_StridedUnaryOp *stransfer; + NpyAuxData *data; + + if (out_needs_api) { + *out_needs_api = 1; + } + + if (!(PyArray_IntpConverter(src_dtype->subarray->shape, + &src_shape))) { + PyErr_SetString(PyExc_ValueError, + "invalid subarray shape"); + return NPY_FAIL; + } + src_size = PyArray_MultiplyList(src_shape.ptr, src_shape.len); + npy_free_cache_dim_obj(src_shape); + + /* Get a function for contiguous src of the subarray type */ + if (get_decsrcref_transfer_function(aligned, + src_dtype->subarray->base->elsize, + src_dtype->subarray->base, + &stransfer, &data, + out_needs_api) != NPY_SUCCEED) { + return NPY_FAIL; + } + + if (wrap_transfer_function_n_to_n(stransfer, data, + src_stride, 0, + src_dtype->subarray->base->elsize, 0, + src_size, + out_stransfer, out_transferdata) != NPY_SUCCEED) { + NPY_AUXDATA_FREE(data); + return NPY_FAIL; + } + + return NPY_SUCCEED; + } + /* If there are fields, need to do each field */ + else { + if (out_needs_api) { + *out_needs_api = 1; + } + + return get_decsrcref_fields_transfer_function(aligned, + src_stride, src_dtype, + out_stransfer, + out_transferdata, + out_needs_api); + } +} + +/********************* DTYPE COPY SWAP FUNCTION ***********************/ + +NPY_NO_EXPORT int +PyArray_GetDTypeCopySwapFn(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *dtype, + PyArray_StridedUnaryOp **outstransfer, + NpyAuxData **outtransferdata) +{ + npy_intp itemsize = dtype->elsize; + + /* If it's a custom data type, wrap its copy swap function */ + if (dtype->type_num >= NPY_NTYPES) { + *outstransfer = NULL; + wrap_copy_swap_function(aligned, + src_stride, dst_stride, + dtype, + !PyArray_ISNBO(dtype->byteorder), + outstransfer, outtransferdata); + } + /* A straight copy */ + else if (itemsize == 1 || PyArray_ISNBO(dtype->byteorder)) { + *outstransfer = PyArray_GetStridedCopyFn(aligned, + src_stride, dst_stride, + itemsize); + *outtransferdata = NULL; + } + else if (dtype->kind == 'U') { + return wrap_copy_swap_function(aligned, + src_stride, dst_stride, dtype, 1, + outstransfer, outtransferdata); + } + /* If it's not complex, one swap */ + else if (dtype->kind != 'c') { + *outstransfer = PyArray_GetStridedCopySwapFn(aligned, + src_stride, dst_stride, + itemsize); + *outtransferdata = NULL; + } + /* If complex, a paired swap */ + else { + *outstransfer = PyArray_GetStridedCopySwapPairFn(aligned, + src_stride, dst_stride, + itemsize); + *outtransferdata = NULL; + } + + return (*outstransfer == NULL) ? NPY_FAIL : NPY_SUCCEED; +} + +/********************* MAIN DTYPE TRANSFER FUNCTION ***********************/ + +NPY_NO_EXPORT int +PyArray_GetDTypeTransferFunction(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + npy_intp src_itemsize, dst_itemsize; + int src_type_num, dst_type_num; + +#if NPY_DT_DBG_TRACING + printf("Calculating dtype transfer from "); + PyObject_Print((PyObject *)src_dtype, stdout, 0); + printf(" to "); + PyObject_Print((PyObject *)dst_dtype, stdout, 0); + printf("\n"); +#endif + + /* + * If one of the dtypes is NULL, we give back either a src decref + * function or a dst setzero function + */ + if (dst_dtype == NULL) { + if (move_references) { + return get_decsrcref_transfer_function(aligned, + src_dtype->elsize, + src_dtype, + out_stransfer, out_transferdata, + out_needs_api); + } + else { + *out_stransfer = &_dec_src_ref_nop; + *out_transferdata = NULL; + return NPY_SUCCEED; + } + } + else if (src_dtype == NULL) { + return get_setdstzero_transfer_function(aligned, + dst_dtype->elsize, + dst_dtype, + out_stransfer, out_transferdata, + out_needs_api); + } + + src_itemsize = src_dtype->elsize; + dst_itemsize = dst_dtype->elsize; + src_type_num = src_dtype->type_num; + dst_type_num = dst_dtype->type_num; + + /* Common special case - number -> number NBO cast */ + if (PyTypeNum_ISNUMBER(src_type_num) && + PyTypeNum_ISNUMBER(dst_type_num) && + PyArray_ISNBO(src_dtype->byteorder) && + PyArray_ISNBO(dst_dtype->byteorder)) { + + if (PyArray_EquivTypenums(src_type_num, dst_type_num)) { + *out_stransfer = PyArray_GetStridedCopyFn(aligned, + src_stride, dst_stride, + src_itemsize); + *out_transferdata = NULL; + return (*out_stransfer == NULL) ? NPY_FAIL : NPY_SUCCEED; + } + else { + return get_nbo_cast_numeric_transfer_function (aligned, + src_stride, dst_stride, + src_type_num, dst_type_num, + out_stransfer, out_transferdata); + } + } + + /* + * If there are no references and the data types are equivalent, + * return a simple copy + */ + if (PyArray_EquivTypes(src_dtype, dst_dtype) && + !PyDataType_REFCHK(src_dtype) && !PyDataType_REFCHK(dst_dtype) && + ( !PyDataType_HASFIELDS(dst_dtype) || + is_dtype_struct_simple_unaligned_layout(dst_dtype)) ) { + /* + * We can't pass through the aligned flag because it's not + * appropriate. Consider a size-8 string, it will say it's + * aligned because strings only need alignment 1, but the + * copy function wants to know if it's alignment 8. + * + * TODO: Change align from a flag to a "best power of 2 alignment" + * which holds the strongest alignment value for all + * the data which will be used. + */ + *out_stransfer = PyArray_GetStridedCopyFn(0, + src_stride, dst_stride, + src_dtype->elsize); + *out_transferdata = NULL; + return NPY_SUCCEED; + } + + /* First look at the possibilities of just a copy or swap */ + if (src_itemsize == dst_itemsize && src_dtype->kind == dst_dtype->kind && + !PyDataType_HASFIELDS(src_dtype) && + !PyDataType_HASFIELDS(dst_dtype) && + !PyDataType_HASSUBARRAY(src_dtype) && + !PyDataType_HASSUBARRAY(dst_dtype) && + src_type_num != NPY_DATETIME && src_type_num != NPY_TIMEDELTA) { + /* A custom data type requires that we use its copy/swap */ + if (src_type_num >= NPY_NTYPES || dst_type_num >= NPY_NTYPES) { + /* + * If the sizes and kinds are identical, but they're different + * custom types, then get a cast function + */ + if (src_type_num != dst_type_num) { + return get_cast_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + out_stransfer, out_transferdata, + out_needs_api); + } + else { + return wrap_copy_swap_function(aligned, + src_stride, dst_stride, + src_dtype, + PyArray_ISNBO(src_dtype->byteorder) != + PyArray_ISNBO(dst_dtype->byteorder), + out_stransfer, out_transferdata); + } + } + + /* The special types, which have no or subelement byte-order */ + switch (src_type_num) { + case NPY_UNICODE: + /* Wrap the copy swap function when swapping is necessary */ + if (PyArray_ISNBO(src_dtype->byteorder) != + PyArray_ISNBO(dst_dtype->byteorder)) { + return wrap_copy_swap_function(aligned, + src_stride, dst_stride, + src_dtype, 1, + out_stransfer, out_transferdata); + } + case NPY_VOID: + case NPY_STRING: + *out_stransfer = PyArray_GetStridedCopyFn(0, + src_stride, dst_stride, + src_itemsize); + *out_transferdata = NULL; + return NPY_SUCCEED; + case NPY_OBJECT: + if (out_needs_api) { + *out_needs_api = 1; + } + if (move_references) { + *out_stransfer = &_strided_to_strided_move_references; + *out_transferdata = NULL; + } + else { + *out_stransfer = &_strided_to_strided_copy_references; + *out_transferdata = NULL; + } + return NPY_SUCCEED; + } + + /* This is a straight copy */ + if (src_itemsize == 1 || PyArray_ISNBO(src_dtype->byteorder) == + PyArray_ISNBO(dst_dtype->byteorder)) { + *out_stransfer = PyArray_GetStridedCopyFn(aligned, + src_stride, dst_stride, + src_itemsize); + *out_transferdata = NULL; + return (*out_stransfer == NULL) ? NPY_FAIL : NPY_SUCCEED; + } + /* This is a straight copy + byte swap */ + else if (!PyTypeNum_ISCOMPLEX(src_type_num)) { + *out_stransfer = PyArray_GetStridedCopySwapFn(aligned, + src_stride, dst_stride, + src_itemsize); + *out_transferdata = NULL; + return (*out_stransfer == NULL) ? NPY_FAIL : NPY_SUCCEED; + } + /* This is a straight copy + element pair byte swap */ + else { + *out_stransfer = PyArray_GetStridedCopySwapPairFn(aligned, + src_stride, dst_stride, + src_itemsize); + *out_transferdata = NULL; + return (*out_stransfer == NULL) ? NPY_FAIL : NPY_SUCCEED; + } + } + + /* Handle subarrays */ + if (PyDataType_HASSUBARRAY(src_dtype) || + PyDataType_HASSUBARRAY(dst_dtype)) { + return get_subarray_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + out_stransfer, out_transferdata, + out_needs_api); + } + + /* Handle fields */ + if ((PyDataType_HASFIELDS(src_dtype) || PyDataType_HASFIELDS(dst_dtype)) && + src_type_num != NPY_OBJECT && dst_type_num != NPY_OBJECT) { + return get_fields_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + out_stransfer, out_transferdata, + out_needs_api); + } + + /* Check for different-sized strings, unicodes, or voids */ + if (src_type_num == dst_type_num) { + switch (src_type_num) { + case NPY_UNICODE: + if (PyArray_ISNBO(src_dtype->byteorder) != + PyArray_ISNBO(dst_dtype->byteorder)) { + return PyArray_GetStridedZeroPadCopyFn(0, 1, + src_stride, dst_stride, + src_dtype->elsize, dst_dtype->elsize, + out_stransfer, out_transferdata); + } + case NPY_STRING: + case NPY_VOID: + return PyArray_GetStridedZeroPadCopyFn(0, 0, + src_stride, dst_stride, + src_dtype->elsize, dst_dtype->elsize, + out_stransfer, out_transferdata); + } + } + + /* Otherwise a cast is necessary */ + return get_cast_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + out_stransfer, out_transferdata, + out_needs_api); +} + +NPY_NO_EXPORT int +PyArray_GetMaskedDTypeTransferFunction(int aligned, + npy_intp src_stride, + npy_intp dst_stride, + npy_intp mask_stride, + PyArray_Descr *src_dtype, + PyArray_Descr *dst_dtype, + PyArray_Descr *mask_dtype, + int move_references, + PyArray_MaskedStridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api) +{ + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + _masked_wrapper_transfer_data *data; + + /* TODO: Add struct-based mask_dtype support later */ + if (mask_dtype->type_num != NPY_BOOL && + mask_dtype->type_num != NPY_UINT8) { + PyErr_SetString(PyExc_TypeError, + "Only bool and uint8 masks are supported at the moment, " + "structs of bool/uint8 is planned for the future"); + return NPY_FAIL; + } + + /* TODO: Special case some important cases so they're fast */ + + /* Fall back to wrapping a non-masked transfer function */ + if (PyArray_GetDTypeTransferFunction(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + &stransfer, &transferdata, + out_needs_api) != NPY_SUCCEED) { + return NPY_FAIL; + } + + /* Create the wrapper function's auxdata */ + data = (_masked_wrapper_transfer_data *)PyArray_malloc( + sizeof(_masked_wrapper_transfer_data)); + if (data == NULL) { + PyErr_NoMemory(); + NPY_AUXDATA_FREE(transferdata); + return NPY_FAIL; + } + + /* Fill in the auxdata object */ + memset(data, 0, sizeof(_masked_wrapper_transfer_data)); + data->base.free = &_masked_wrapper_transfer_data_free; + data->base.clone = &_masked_wrapper_transfer_data_clone; + + data->stransfer = stransfer; + data->transferdata = transferdata; + + /* If the src object will need a DECREF, get a function to handle that */ + if (move_references && PyDataType_REFCHK(src_dtype)) { + if (get_decsrcref_transfer_function(aligned, + src_stride, + src_dtype, + &data->decsrcref_stransfer, + &data->decsrcref_transferdata, + out_needs_api) != NPY_SUCCEED) { + NPY_AUXDATA_FREE((NpyAuxData *)data); + return NPY_FAIL; + } + + *out_stransfer = &_strided_masked_wrapper_decsrcref_transfer_function; + } + else { + *out_stransfer = &_strided_masked_wrapper_transfer_function; + } + + *out_transferdata = (NpyAuxData *)data; + + return NPY_SUCCEED; +} + +NPY_NO_EXPORT int +PyArray_CastRawArrays(npy_intp count, + char *src, char *dst, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references) +{ + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + int aligned = 1, needs_api = 0; + + /* Make sure the copy is reasonable */ + if (dst_stride == 0 && count > 1) { + PyErr_SetString(PyExc_ValueError, + "NumPy CastRawArrays cannot do a reduction"); + return NPY_FAIL; + } + else if (count == 0) { + return NPY_SUCCEED; + } + + /* Check data alignment */ + aligned = (((npy_intp)src | src_stride) & + (src_dtype->alignment - 1)) == 0 && + (((npy_intp)dst | dst_stride) & + (dst_dtype->alignment - 1)) == 0; + + /* Get the function to do the casting */ + if (PyArray_GetDTypeTransferFunction(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + return NPY_FAIL; + } + + /* Cast */ + stransfer(dst, dst_stride, src, src_stride, count, + src_dtype->elsize, transferdata); + + /* Cleanup */ + NPY_AUXDATA_FREE(transferdata); + + /* If needs_api was set to 1, it may have raised a Python exception */ + return (needs_api && PyErr_Occurred()) ? NPY_FAIL : NPY_SUCCEED; +} + +/* + * Prepares shape and strides for a simple raw array iteration. + * This sorts the strides into FORTRAN order, reverses any negative + * strides, then coalesces axes where possible. The results are + * filled in the output parameters. + * + * This is intended for simple, lightweight iteration over arrays + * where no buffering of any kind is needed, and the array may + * not be stored as a PyArrayObject. + * + * The arrays shape, out_shape, strides, and out_strides must all + * point to different data. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_PrepareOneRawArrayIter(int ndim, npy_intp *shape, + char *data, npy_intp *strides, + int *out_ndim, npy_intp *out_shape, + char **out_data, npy_intp *out_strides) +{ + npy_stride_sort_item strideperm[NPY_MAXDIMS]; + int i, j; + + /* Special case 0 and 1 dimensions */ + if (ndim == 0) { + *out_ndim = 1; + *out_data = data; + out_shape[0] = 1; + out_strides[0] = 0; + return 0; + } + else if (ndim == 1) { + npy_intp stride_entry = strides[0], shape_entry = shape[0]; + *out_ndim = 1; + out_shape[0] = shape[0]; + /* Always make a positive stride */ + if (stride_entry >= 0) { + *out_data = data; + out_strides[0] = stride_entry; + } + else { + *out_data = data + stride_entry * (shape_entry - 1); + out_strides[0] = -stride_entry; + } + return 0; + } + + /* Sort the axes based on the destination strides */ + PyArray_CreateSortedStridePerm(ndim, strides, strideperm); + for (i = 0; i < ndim; ++i) { + int iperm = strideperm[ndim - i - 1].perm; + out_shape[i] = shape[iperm]; + out_strides[i] = strides[iperm]; + } + + /* Reverse any negative strides */ + for (i = 0; i < ndim; ++i) { + npy_intp stride_entry = out_strides[i], shape_entry = out_shape[i]; + + if (stride_entry < 0) { + data += stride_entry * (shape_entry - 1); + out_strides[i] = -stride_entry; + } + /* Detect 0-size arrays here */ + if (shape_entry == 0) { + *out_ndim = 1; + *out_data = data; + out_shape[0] = 0; + out_strides[0] = 0; + return 0; + } + } + + /* Coalesce any dimensions where possible */ + i = 0; + for (j = 1; j < ndim; ++j) { + if (out_shape[i] == 1) { + /* Drop axis i */ + out_shape[i] = out_shape[j]; + out_strides[i] = out_strides[j]; + } + else if (out_shape[j] == 1) { + /* Drop axis j */ + } + else if (out_strides[i] * out_shape[i] == out_strides[j]) { + /* Coalesce axes i and j */ + out_shape[i] *= out_shape[j]; + } + else { + /* Can't coalesce, go to next i */ + ++i; + out_shape[i] = out_shape[j]; + out_strides[i] = out_strides[j]; + } + } + ndim = i+1; + +#if 0 + /* DEBUG */ + { + printf("raw iter ndim %d\n", ndim); + printf("shape: "); + for (i = 0; i < ndim; ++i) { + printf("%d ", (int)out_shape[i]); + } + printf("\n"); + printf("strides: "); + for (i = 0; i < ndim; ++i) { + printf("%d ", (int)out_strides[i]); + } + printf("\n"); + } +#endif + + *out_data = data; + *out_ndim = ndim; + return 0; +} + +/* + * The same as PyArray_PrepareOneRawArrayIter, but for two + * operands instead of one. Any broadcasting of the two operands + * should have already been done before calling this function, + * as the ndim and shape is only specified once for both operands. + * + * Only the strides of the first operand are used to reorder + * the dimensions, no attempt to consider all the strides together + * is made, as is done in the NpyIter object. + * + * You can use this together with NPY_RAW_ITER_START and + * NPY_RAW_ITER_TWO_NEXT to handle the looping boilerplate of everything + * but the innermost loop (which is for idim == 0). + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_PrepareTwoRawArrayIter(int ndim, npy_intp *shape, + char *dataA, npy_intp *stridesA, + char *dataB, npy_intp *stridesB, + int *out_ndim, npy_intp *out_shape, + char **out_dataA, npy_intp *out_stridesA, + char **out_dataB, npy_intp *out_stridesB) +{ + npy_stride_sort_item strideperm[NPY_MAXDIMS]; + int i, j; + + /* Special case 0 and 1 dimensions */ + if (ndim == 0) { + *out_ndim = 1; + *out_dataA = dataA; + *out_dataB = dataB; + out_shape[0] = 1; + out_stridesA[0] = 0; + out_stridesB[0] = 0; + return 0; + } + else if (ndim == 1) { + npy_intp stride_entryA = stridesA[0], stride_entryB = stridesB[0]; + npy_intp shape_entry = shape[0]; + *out_ndim = 1; + out_shape[0] = shape[0]; + /* Always make a positive stride for the first operand */ + if (stride_entryA >= 0) { + *out_dataA = dataA; + *out_dataB = dataB; + out_stridesA[0] = stride_entryA; + out_stridesB[0] = stride_entryB; + } + else { + *out_dataA = dataA + stride_entryA * (shape_entry - 1); + *out_dataB = dataB + stride_entryB * (shape_entry - 1); + out_stridesA[0] = -stride_entryA; + out_stridesB[0] = -stride_entryB; + } + return 0; + } + + /* Sort the axes based on the destination strides */ + PyArray_CreateSortedStridePerm(ndim, stridesA, strideperm); + for (i = 0; i < ndim; ++i) { + int iperm = strideperm[ndim - i - 1].perm; + out_shape[i] = shape[iperm]; + out_stridesA[i] = stridesA[iperm]; + out_stridesB[i] = stridesB[iperm]; + } + + /* Reverse any negative strides of operand A */ + for (i = 0; i < ndim; ++i) { + npy_intp stride_entryA = out_stridesA[i]; + npy_intp stride_entryB = out_stridesB[i]; + npy_intp shape_entry = out_shape[i]; + + if (stride_entryA < 0) { + dataA += stride_entryA * (shape_entry - 1); + dataB += stride_entryB * (shape_entry - 1); + out_stridesA[i] = -stride_entryA; + out_stridesB[i] = -stride_entryB; + } + /* Detect 0-size arrays here */ + if (shape_entry == 0) { + *out_ndim = 1; + *out_dataA = dataA; + *out_dataB = dataB; + out_shape[0] = 0; + out_stridesA[0] = 0; + out_stridesB[0] = 0; + return 0; + } + } + + /* Coalesce any dimensions where possible */ + i = 0; + for (j = 1; j < ndim; ++j) { + if (out_shape[i] == 1) { + /* Drop axis i */ + out_shape[i] = out_shape[j]; + out_stridesA[i] = out_stridesA[j]; + out_stridesB[i] = out_stridesB[j]; + } + else if (out_shape[j] == 1) { + /* Drop axis j */ + } + else if (out_stridesA[i] * out_shape[i] == out_stridesA[j] && + out_stridesB[i] * out_shape[i] == out_stridesB[j]) { + /* Coalesce axes i and j */ + out_shape[i] *= out_shape[j]; + } + else { + /* Can't coalesce, go to next i */ + ++i; + out_shape[i] = out_shape[j]; + out_stridesA[i] = out_stridesA[j]; + out_stridesB[i] = out_stridesB[j]; + } + } + ndim = i+1; + + *out_dataA = dataA; + *out_dataB = dataB; + *out_ndim = ndim; + return 0; +} + +/* + * The same as PyArray_PrepareOneRawArrayIter, but for three + * operands instead of one. Any broadcasting of the three operands + * should have already been done before calling this function, + * as the ndim and shape is only specified once for all operands. + * + * Only the strides of the first operand are used to reorder + * the dimensions, no attempt to consider all the strides together + * is made, as is done in the NpyIter object. + * + * You can use this together with NPY_RAW_ITER_START and + * NPY_RAW_ITER_THREE_NEXT to handle the looping boilerplate of everything + * but the innermost loop (which is for idim == 0). + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp *shape, + char *dataA, npy_intp *stridesA, + char *dataB, npy_intp *stridesB, + char *dataC, npy_intp *stridesC, + int *out_ndim, npy_intp *out_shape, + char **out_dataA, npy_intp *out_stridesA, + char **out_dataB, npy_intp *out_stridesB, + char **out_dataC, npy_intp *out_stridesC) +{ + npy_stride_sort_item strideperm[NPY_MAXDIMS]; + int i, j; + + /* Special case 0 and 1 dimensions */ + if (ndim == 0) { + *out_ndim = 1; + *out_dataA = dataA; + *out_dataB = dataB; + *out_dataC = dataC; + out_shape[0] = 1; + out_stridesA[0] = 0; + out_stridesB[0] = 0; + out_stridesC[0] = 0; + return 0; + } + else if (ndim == 1) { + npy_intp stride_entryA = stridesA[0]; + npy_intp stride_entryB = stridesB[0]; + npy_intp stride_entryC = stridesC[0]; + npy_intp shape_entry = shape[0]; + *out_ndim = 1; + out_shape[0] = shape[0]; + /* Always make a positive stride for the first operand */ + if (stride_entryA >= 0) { + *out_dataA = dataA; + *out_dataB = dataB; + *out_dataC = dataC; + out_stridesA[0] = stride_entryA; + out_stridesB[0] = stride_entryB; + out_stridesC[0] = stride_entryC; + } + else { + *out_dataA = dataA + stride_entryA * (shape_entry - 1); + *out_dataB = dataB + stride_entryB * (shape_entry - 1); + *out_dataC = dataC + stride_entryC * (shape_entry - 1); + out_stridesA[0] = -stride_entryA; + out_stridesB[0] = -stride_entryB; + out_stridesC[0] = -stride_entryC; + } + return 0; + } + + /* Sort the axes based on the destination strides */ + PyArray_CreateSortedStridePerm(ndim, stridesA, strideperm); + for (i = 0; i < ndim; ++i) { + int iperm = strideperm[ndim - i - 1].perm; + out_shape[i] = shape[iperm]; + out_stridesA[i] = stridesA[iperm]; + out_stridesB[i] = stridesB[iperm]; + out_stridesC[i] = stridesC[iperm]; + } + + /* Reverse any negative strides of operand A */ + for (i = 0; i < ndim; ++i) { + npy_intp stride_entryA = out_stridesA[i]; + npy_intp stride_entryB = out_stridesB[i]; + npy_intp stride_entryC = out_stridesC[i]; + npy_intp shape_entry = out_shape[i]; + + if (stride_entryA < 0) { + dataA += stride_entryA * (shape_entry - 1); + dataB += stride_entryB * (shape_entry - 1); + dataC += stride_entryC * (shape_entry - 1); + out_stridesA[i] = -stride_entryA; + out_stridesB[i] = -stride_entryB; + out_stridesC[i] = -stride_entryC; + } + /* Detect 0-size arrays here */ + if (shape_entry == 0) { + *out_ndim = 1; + *out_dataA = dataA; + *out_dataB = dataB; + *out_dataC = dataC; + out_shape[0] = 0; + out_stridesA[0] = 0; + out_stridesB[0] = 0; + out_stridesC[0] = 0; + return 0; + } + } + + /* Coalesce any dimensions where possible */ + i = 0; + for (j = 1; j < ndim; ++j) { + if (out_shape[i] == 1) { + /* Drop axis i */ + out_shape[i] = out_shape[j]; + out_stridesA[i] = out_stridesA[j]; + out_stridesB[i] = out_stridesB[j]; + out_stridesC[i] = out_stridesC[j]; + } + else if (out_shape[j] == 1) { + /* Drop axis j */ + } + else if (out_stridesA[i] * out_shape[i] == out_stridesA[j] && + out_stridesB[i] * out_shape[i] == out_stridesB[j] && + out_stridesC[i] * out_shape[i] == out_stridesC[j]) { + /* Coalesce axes i and j */ + out_shape[i] *= out_shape[j]; + } + else { + /* Can't coalesce, go to next i */ + ++i; + out_shape[i] = out_shape[j]; + out_stridesA[i] = out_stridesA[j]; + out_stridesB[i] = out_stridesB[j]; + out_stridesC[i] = out_stridesC[j]; + } + } + ndim = i+1; + + *out_dataA = dataA; + *out_dataB = dataB; + *out_dataC = dataC; + *out_ndim = ndim; + return 0; +} diff --git a/numpy/core/src/multiarray/einsum.c.src b/numpy/core/src/multiarray/einsum.c.src new file mode 100644 index 0000000..943b8ae --- /dev/null +++ b/numpy/core/src/multiarray/einsum.c.src @@ -0,0 +1,3017 @@ +/* + * This file contains the implementation of the 'einsum' function, + * which provides an einstein-summation operation. + * + * Copyright (c) 2011 by Mark Wiebe (mwwiebe@gmail.com) + * The University of British Columbia + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include +#include +#include +#include + +#include + +#include "convert.h" +#include "common.h" + +#ifdef NPY_HAVE_SSE_INTRINSICS +#define EINSUM_USE_SSE1 1 +#else +#define EINSUM_USE_SSE1 0 +#endif + +/* + * TODO: Only some SSE2 for float64 is implemented. + */ +#ifdef NPY_HAVE_SSE2_INTRINSICS +#define EINSUM_USE_SSE2 1 +#else +#define EINSUM_USE_SSE2 0 +#endif + +#if EINSUM_USE_SSE1 +#include +#endif + +#if EINSUM_USE_SSE2 +#include +#endif + +#define EINSUM_IS_SSE_ALIGNED(x) ((((npy_intp)x)&0xf) == 0) + +/********** PRINTF DEBUG TRACING **************/ +#define NPY_EINSUM_DBG_TRACING 0 + +#if NPY_EINSUM_DBG_TRACING +#define NPY_EINSUM_DBG_PRINT(s) printf("%s", s); +#define NPY_EINSUM_DBG_PRINT1(s, p1) printf(s, p1); +#define NPY_EINSUM_DBG_PRINT2(s, p1, p2) printf(s, p1, p2); +#define NPY_EINSUM_DBG_PRINT3(s, p1, p2, p3) printf(s); +#else +#define NPY_EINSUM_DBG_PRINT(s) +#define NPY_EINSUM_DBG_PRINT1(s, p1) +#define NPY_EINSUM_DBG_PRINT2(s, p1, p2) +#define NPY_EINSUM_DBG_PRINT3(s, p1, p2, p3) +#endif +/**********************************************/ + +/**begin repeat + * #name = byte, short, int, long, longlong, + * ubyte, ushort, uint, ulong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong, + * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + * #temptype = npy_byte, npy_short, npy_int, npy_long, npy_longlong, + * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, + * npy_float, npy_float, npy_double, npy_longdouble, + * npy_float, npy_double, npy_longdouble# + * #to = ,,,,, + * ,,,,, + * npy_float_to_half,,,, + * ,,# + * #from = ,,,,, + * ,,,,, + * npy_half_to_float,,,, + * ,,# + * #complex = 0*5, + * 0*5, + * 0*4, + * 1*3# + * #float32 = 0*5, + * 0*5, + * 0,1,0,0, + * 0*3# + * #float64 = 0*5, + * 0*5, + * 0,0,1,0, + * 0*3# + */ + +/**begin repeat1 + * #nop = 1, 2, 3, 1000# + * #noplabel = one, two, three, any# + */ +static void +@name@_sum_of_products_@noplabel@(int nop, char **dataptr, + npy_intp *strides, npy_intp count) +{ +#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@) + char *data0 = dataptr[0]; + npy_intp stride0 = strides[0]; +#endif +#if (@nop@ == 2 || @nop@ == 3) && !@complex@ + char *data1 = dataptr[1]; + npy_intp stride1 = strides[1]; +#endif +#if (@nop@ == 3) && !@complex@ + char *data2 = dataptr[2]; + npy_intp stride2 = strides[2]; +#endif +#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@) + char *data_out = dataptr[@nop@]; + npy_intp stride_out = strides[@nop@]; +#endif + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_@noplabel@ (%d)\n", (int)count); + + while (count--) { +#if !@complex@ +# if @nop@ == 1 + *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) + + @from@(*(@type@ *)data_out)); + data0 += stride0; + data_out += stride_out; +# elif @nop@ == 2 + *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) * + @from@(*(@type@ *)data1) + + @from@(*(@type@ *)data_out)); + data0 += stride0; + data1 += stride1; + data_out += stride_out; +# elif @nop@ == 3 + *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) * + @from@(*(@type@ *)data1) * + @from@(*(@type@ *)data2) + + @from@(*(@type@ *)data_out)); + data0 += stride0; + data1 += stride1; + data2 += stride2; + data_out += stride_out; +# else + @temptype@ temp = @from@(*(@type@ *)dataptr[0]); + int i; + for (i = 1; i < nop; ++i) { + temp *= @from@(*(@type@ *)dataptr[i]); + } + *(@type@ *)dataptr[nop] = @to@(temp + + @from@(*(@type@ *)dataptr[i])); + for (i = 0; i <= nop; ++i) { + dataptr[i] += strides[i]; + } +# endif +#else /* complex */ +# if @nop@ == 1 + ((@temptype@ *)data_out)[0] = ((@temptype@ *)data0)[0] + + ((@temptype@ *)data_out)[0]; + ((@temptype@ *)data_out)[1] = ((@temptype@ *)data0)[1] + + ((@temptype@ *)data_out)[1]; + data0 += stride0; + data_out += stride_out; +# else +# if @nop@ <= 3 +#define _SUMPROD_NOP @nop@ +# else +#define _SUMPROD_NOP nop +# endif + @temptype@ re, im, tmp; + int i; + re = ((@temptype@ *)dataptr[0])[0]; + im = ((@temptype@ *)dataptr[0])[1]; + for (i = 1; i < _SUMPROD_NOP; ++i) { + tmp = re * ((@temptype@ *)dataptr[i])[0] - + im * ((@temptype@ *)dataptr[i])[1]; + im = re * ((@temptype@ *)dataptr[i])[1] + + im * ((@temptype@ *)dataptr[i])[0]; + re = tmp; + } + ((@temptype@ *)dataptr[_SUMPROD_NOP])[0] = re + + ((@temptype@ *)dataptr[_SUMPROD_NOP])[0]; + ((@temptype@ *)dataptr[_SUMPROD_NOP])[1] = im + + ((@temptype@ *)dataptr[_SUMPROD_NOP])[1]; + + for (i = 0; i <= _SUMPROD_NOP; ++i) { + dataptr[i] += strides[i]; + } +#undef _SUMPROD_NOP +# endif +#endif + } +} + +#if @nop@ == 1 + +static void +@name@_sum_of_products_contig_one(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + @type@ *data0 = (@type@ *)dataptr[0]; + @type@ *data_out = (@type@ *)dataptr[1]; + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_one (%d)\n", + (int)count); + +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat2 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: +#if !@complex@ + data_out[@i@] = @to@(@from@(data0[@i@]) + + @from@(data_out[@i@])); +#else + ((@temptype@ *)data_out + 2*@i@)[0] = + ((@temptype@ *)data0 + 2*@i@)[0] + + ((@temptype@ *)data_out + 2*@i@)[0]; + ((@temptype@ *)data_out + 2*@i@)[1] = + ((@temptype@ *)data0 + 2*@i@)[1] + + ((@temptype@ *)data_out + 2*@i@)[1]; +#endif +/**end repeat2**/ + case 0: + return; + } + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ +#if !@complex@ + data_out[@i@] = @to@(@from@(data0[@i@]) + + @from@(data_out[@i@])); +#else /* complex */ + ((@temptype@ *)data_out + 2*@i@)[0] = + ((@temptype@ *)data0 + 2*@i@)[0] + + ((@temptype@ *)data_out + 2*@i@)[0]; + ((@temptype@ *)data_out + 2*@i@)[1] = + ((@temptype@ *)data0 + 2*@i@)[1] + + ((@temptype@ *)data_out + 2*@i@)[1]; +#endif +/**end repeat2**/ + data0 += 8; + data_out += 8; + } + + /* Finish off the loop */ + goto finish_after_unrolled_loop; +} + +#elif @nop@ == 2 && !@complex@ + +static void +@name@_sum_of_products_contig_two(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + @type@ *data0 = (@type@ *)dataptr[0]; + @type@ *data1 = (@type@ *)dataptr[1]; + @type@ *data_out = (@type@ *)dataptr[2]; + +#if EINSUM_USE_SSE1 && @float32@ + __m128 a, b; +#endif + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_two (%d)\n", + (int)count); + +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat2 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: + data_out[@i@] = @to@(@from@(data0[@i@]) * + @from@(data1[@i@]) + + @from@(data_out[@i@])); +/**end repeat2**/ + case 0: + return; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1) && + EINSUM_IS_SSE_ALIGNED(data_out)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +/**begin repeat2 + * #i = 0, 4# + */ + a = _mm_mul_ps(_mm_load_ps(data0+@i@), _mm_load_ps(data1+@i@)); + b = _mm_add_ps(a, _mm_load_ps(data_out+@i@)); + _mm_store_ps(data_out+@i@, b); +/**end repeat2**/ + data0 += 8; + data1 += 8; + data_out += 8; + } + + /* Finish off the loop */ + goto finish_after_unrolled_loop; + } +#endif + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +#if EINSUM_USE_SSE1 && @float32@ +/**begin repeat2 + * #i = 0, 4# + */ + a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), _mm_loadu_ps(data1+@i@)); + b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@)); + _mm_storeu_ps(data_out+@i@, b); +/**end repeat2**/ +#else +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + data_out[@i@] = @to@(@from@(data0[@i@]) * + @from@(data1[@i@]) + + @from@(data_out[@i@])); +/**end repeat2**/ +#endif + data0 += 8; + data1 += 8; + data_out += 8; + } + + /* Finish off the loop */ + goto finish_after_unrolled_loop; +} + +/* Some extra specializations for the two operand case */ +static void +@name@_sum_of_products_stride0_contig_outcontig_two(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + @temptype@ value0 = @from@(*(@type@ *)dataptr[0]); + @type@ *data1 = (@type@ *)dataptr[1]; + @type@ *data_out = (@type@ *)dataptr[2]; + +#if EINSUM_USE_SSE1 && @float32@ + __m128 a, b, value0_sse; +#elif EINSUM_USE_SSE2 && @float64@ + __m128d a, b, value0_sse; +#endif + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_stride0_contig_outcontig_two (%d)\n", + (int)count); + +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat2 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: + data_out[@i@] = @to@(value0 * + @from@(data1[@i@]) + + @from@(data_out[@i@])); +/**end repeat2**/ + case 0: + return; + } + +#if EINSUM_USE_SSE1 && @float32@ + value0_sse = _mm_set_ps1(value0); + + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data1) && EINSUM_IS_SSE_ALIGNED(data_out)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +/**begin repeat2 + * #i = 0, 4# + */ + a = _mm_mul_ps(value0_sse, _mm_load_ps(data1+@i@)); + b = _mm_add_ps(a, _mm_load_ps(data_out+@i@)); + _mm_store_ps(data_out+@i@, b); +/**end repeat2**/ + data1 += 8; + data_out += 8; + } + + /* Finish off the loop */ + if (count > 0) { + goto finish_after_unrolled_loop; + } + else { + return; + } + } +#elif EINSUM_USE_SSE2 && @float64@ + value0_sse = _mm_set1_pd(value0); + + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data1) && EINSUM_IS_SSE_ALIGNED(data_out)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +/**begin repeat2 + * #i = 0, 2, 4, 6# + */ + a = _mm_mul_pd(value0_sse, _mm_load_pd(data1+@i@)); + b = _mm_add_pd(a, _mm_load_pd(data_out+@i@)); + _mm_store_pd(data_out+@i@, b); +/**end repeat2**/ + data1 += 8; + data_out += 8; + } + + /* Finish off the loop */ + if (count > 0) { + goto finish_after_unrolled_loop; + } + else { + return; + } + } +#endif + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +#if EINSUM_USE_SSE1 && @float32@ +/**begin repeat2 + * #i = 0, 4# + */ + a = _mm_mul_ps(value0_sse, _mm_loadu_ps(data1+@i@)); + b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@)); + _mm_storeu_ps(data_out+@i@, b); +/**end repeat2**/ +#elif EINSUM_USE_SSE2 && @float64@ +/**begin repeat2 + * #i = 0, 2, 4, 6# + */ + a = _mm_mul_pd(value0_sse, _mm_loadu_pd(data1+@i@)); + b = _mm_add_pd(a, _mm_loadu_pd(data_out+@i@)); + _mm_storeu_pd(data_out+@i@, b); +/**end repeat2**/ +#else +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + data_out[@i@] = @to@(value0 * + @from@(data1[@i@]) + + @from@(data_out[@i@])); +/**end repeat2**/ +#endif + data1 += 8; + data_out += 8; + } + + /* Finish off the loop */ + if (count > 0) { + goto finish_after_unrolled_loop; + } +} + +static void +@name@_sum_of_products_contig_stride0_outcontig_two(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + @type@ *data0 = (@type@ *)dataptr[0]; + @temptype@ value1 = @from@(*(@type@ *)dataptr[1]); + @type@ *data_out = (@type@ *)dataptr[2]; + +#if EINSUM_USE_SSE1 && @float32@ + __m128 a, b, value1_sse; +#endif + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_stride0_outcontig_two (%d)\n", + (int)count); + +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat2 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: + data_out[@i@] = @to@(@from@(data0[@i@])* + value1 + + @from@(data_out[@i@])); +/**end repeat2**/ + case 0: + return; + } + +#if EINSUM_USE_SSE1 && @float32@ + value1_sse = _mm_set_ps1(value1); + + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data_out)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +/**begin repeat2 + * #i = 0, 4# + */ + a = _mm_mul_ps(_mm_load_ps(data0+@i@), value1_sse); + b = _mm_add_ps(a, _mm_load_ps(data_out+@i@)); + _mm_store_ps(data_out+@i@, b); +/**end repeat2**/ + data0 += 8; + data_out += 8; + } + + /* Finish off the loop */ + goto finish_after_unrolled_loop; + } +#endif + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +#if EINSUM_USE_SSE1 && @float32@ +/**begin repeat2 + * #i = 0, 4# + */ + a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), value1_sse); + b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@)); + _mm_storeu_ps(data_out+@i@, b); +/**end repeat2**/ +#else +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + data_out[@i@] = @to@(@from@(data0[@i@])* + value1 + + @from@(data_out[@i@])); +/**end repeat2**/ +#endif + data0 += 8; + data_out += 8; + } + + /* Finish off the loop */ + goto finish_after_unrolled_loop; +} + +static void +@name@_sum_of_products_contig_contig_outstride0_two(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + @type@ *data0 = (@type@ *)dataptr[0]; + @type@ *data1 = (@type@ *)dataptr[1]; + @temptype@ accum = 0; + +#if EINSUM_USE_SSE1 && @float32@ + __m128 a, accum_sse = _mm_setzero_ps(); +#elif EINSUM_USE_SSE2 && @float64@ + __m128d a, accum_sse = _mm_setzero_pd(); +#endif + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_contig_outstride0_two (%d)\n", + (int)count); + +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat2 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: + accum += @from@(data0[@i@]) * @from@(data1[@i@]); +/**end repeat2**/ + case 0: + *(@type@ *)dataptr[2] += @to@(accum); + return; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + + _mm_prefetch(data0 + 512, _MM_HINT_T0); + _mm_prefetch(data1 + 512, _MM_HINT_T0); + +/**begin repeat2 + * #i = 0, 4# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + a = _mm_mul_ps(_mm_load_ps(data0+@i@), _mm_load_ps(data1+@i@)); + accum_sse = _mm_add_ps(accum_sse, a); +/**end repeat2**/ + data0 += 8; + data1 += 8; + } + + /* Add the four SSE values and put in accum */ + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1)); + accum_sse = _mm_add_ps(a, accum_sse); + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2)); + accum_sse = _mm_add_ps(a, accum_sse); + _mm_store_ss(&accum, accum_sse); + + /* Finish off the loop */ + goto finish_after_unrolled_loop; + } +#elif EINSUM_USE_SSE2 && @float64@ + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + + _mm_prefetch(data0 + 512, _MM_HINT_T0); + _mm_prefetch(data1 + 512, _MM_HINT_T0); + +/**begin repeat2 + * #i = 0, 2, 4, 6# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + a = _mm_mul_pd(_mm_load_pd(data0+@i@), _mm_load_pd(data1+@i@)); + accum_sse = _mm_add_pd(accum_sse, a); +/**end repeat2**/ + data0 += 8; + data1 += 8; + } + + /* Add the two SSE2 values and put in accum */ + a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1)); + accum_sse = _mm_add_pd(a, accum_sse); + _mm_store_sd(&accum, accum_sse); + + /* Finish off the loop */ + goto finish_after_unrolled_loop; + } +#endif + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +#if EINSUM_USE_SSE1 && @float32@ + _mm_prefetch(data0 + 512, _MM_HINT_T0); + _mm_prefetch(data1 + 512, _MM_HINT_T0); + +/**begin repeat2 + * #i = 0, 4# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), _mm_loadu_ps(data1+@i@)); + accum_sse = _mm_add_ps(accum_sse, a); +/**end repeat2**/ +#elif EINSUM_USE_SSE2 && @float64@ + _mm_prefetch(data0 + 512, _MM_HINT_T0); + _mm_prefetch(data1 + 512, _MM_HINT_T0); + +/**begin repeat2 + * #i = 0, 2, 4, 6# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + a = _mm_mul_pd(_mm_loadu_pd(data0+@i@), _mm_loadu_pd(data1+@i@)); + accum_sse = _mm_add_pd(accum_sse, a); +/**end repeat2**/ +#else +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + accum += @from@(data0[@i@]) * @from@(data1[@i@]); +/**end repeat2**/ +#endif + data0 += 8; + data1 += 8; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Add the four SSE values and put in accum */ + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1)); + accum_sse = _mm_add_ps(a, accum_sse); + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2)); + accum_sse = _mm_add_ps(a, accum_sse); + _mm_store_ss(&accum, accum_sse); +#elif EINSUM_USE_SSE2 && @float64@ + /* Add the two SSE2 values and put in accum */ + a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1)); + accum_sse = _mm_add_pd(a, accum_sse); + _mm_store_sd(&accum, accum_sse); +#endif + + /* Finish off the loop */ + goto finish_after_unrolled_loop; +} + +static void +@name@_sum_of_products_stride0_contig_outstride0_two(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + @temptype@ value0 = @from@(*(@type@ *)dataptr[0]); + @type@ *data1 = (@type@ *)dataptr[1]; + @temptype@ accum = 0; + +#if EINSUM_USE_SSE1 && @float32@ + __m128 a, accum_sse = _mm_setzero_ps(); +#endif + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_stride0_contig_outstride0_two (%d)\n", + (int)count); + +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat2 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: + accum += @from@(data1[@i@]); +/**end repeat2**/ + case 0: + *(@type@ *)dataptr[2] += @to@(value0 * accum); + return; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data1)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +/**begin repeat2 + * #i = 0, 4# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data1+@i@)); +/**end repeat2**/ + data1 += 8; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Add the four SSE values and put in accum */ + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1)); + accum_sse = _mm_add_ps(a, accum_sse); + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2)); + accum_sse = _mm_add_ps(a, accum_sse); + _mm_store_ss(&accum, accum_sse); +#endif + + /* Finish off the loop */ + goto finish_after_unrolled_loop; + } +#endif + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +#if EINSUM_USE_SSE1 && @float32@ +/**begin repeat2 + * #i = 0, 4# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data1+@i@)); +/**end repeat2**/ +#else +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + accum += @from@(data1[@i@]); +/**end repeat2**/ +#endif + data1 += 8; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Add the four SSE values and put in accum */ + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1)); + accum_sse = _mm_add_ps(a, accum_sse); + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2)); + accum_sse = _mm_add_ps(a, accum_sse); + _mm_store_ss(&accum, accum_sse); +#endif + + /* Finish off the loop */ + goto finish_after_unrolled_loop; +} + +static void +@name@_sum_of_products_contig_stride0_outstride0_two(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + @type@ *data0 = (@type@ *)dataptr[0]; + @temptype@ value1 = @from@(*(@type@ *)dataptr[1]); + @temptype@ accum = 0; + +#if EINSUM_USE_SSE1 && @float32@ + __m128 a, accum_sse = _mm_setzero_ps(); +#endif + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_stride0_outstride0_two (%d)\n", + (int)count); + +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat2 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: + accum += @from@(data0[@i@]); +/**end repeat2**/ + case 0: + *(@type@ *)dataptr[2] += @to@(accum * value1); + return; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data0)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +/**begin repeat2 + * #i = 0, 4# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data0+@i@)); +/**end repeat2**/ + data0 += 8; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Add the four SSE values and put in accum */ + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1)); + accum_sse = _mm_add_ps(a, accum_sse); + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2)); + accum_sse = _mm_add_ps(a, accum_sse); + _mm_store_ss(&accum, accum_sse); +#endif + + /* Finish off the loop */ + goto finish_after_unrolled_loop; + } +#endif + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +#if EINSUM_USE_SSE1 && @float32@ +/**begin repeat2 + * #i = 0, 4# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data0+@i@)); +/**end repeat2**/ +#else +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + accum += @from@(data0[@i@]); +/**end repeat2**/ +#endif + data0 += 8; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Add the four SSE values and put in accum */ + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1)); + accum_sse = _mm_add_ps(a, accum_sse); + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2)); + accum_sse = _mm_add_ps(a, accum_sse); + _mm_store_ss(&accum, accum_sse); +#endif + + /* Finish off the loop */ + goto finish_after_unrolled_loop; +} + +#elif @nop@ == 3 && !@complex@ + +static void +@name@_sum_of_products_contig_three(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + @type@ *data0 = (@type@ *)dataptr[0]; + @type@ *data1 = (@type@ *)dataptr[1]; + @type@ *data2 = (@type@ *)dataptr[2]; + @type@ *data_out = (@type@ *)dataptr[3]; + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + data_out[@i@] = @to@(@from@(data0[@i@]) * + @from@(data1[@i@]) * + @from@(data2[@i@]) + + @from@(data_out[@i@])); +/**end repeat2**/ + data0 += 8; + data1 += 8; + data2 += 8; + data_out += 8; + } + + /* Finish off the loop */ + +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + if (count-- == 0) { + return; + } + data_out[@i@] = @to@(@from@(data0[@i@]) * + @from@(data1[@i@]) * + @from@(data2[@i@]) + + @from@(data_out[@i@])); +/**end repeat2**/ +} + +#else /* @nop@ > 3 || @complex */ + +static void +@name@_sum_of_products_contig_@noplabel@(int nop, char **dataptr, + npy_intp *NPY_UNUSED(strides), npy_intp count) +{ + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_@noplabel@ (%d)\n", + (int)count); + + while (count--) { +#if !@complex@ + @temptype@ temp = @from@(*(@type@ *)dataptr[0]); + int i; + for (i = 1; i < nop; ++i) { + temp *= @from@(*(@type@ *)dataptr[i]); + } + *(@type@ *)dataptr[nop] = @to@(temp + + @from@(*(@type@ *)dataptr[i])); + for (i = 0; i <= nop; ++i) { + dataptr[i] += sizeof(@type@); + } +#else /* complex */ +# if @nop@ <= 3 +# define _SUMPROD_NOP @nop@ +# else +# define _SUMPROD_NOP nop +# endif + @temptype@ re, im, tmp; + int i; + re = ((@temptype@ *)dataptr[0])[0]; + im = ((@temptype@ *)dataptr[0])[1]; + for (i = 1; i < _SUMPROD_NOP; ++i) { + tmp = re * ((@temptype@ *)dataptr[i])[0] - + im * ((@temptype@ *)dataptr[i])[1]; + im = re * ((@temptype@ *)dataptr[i])[1] + + im * ((@temptype@ *)dataptr[i])[0]; + re = tmp; + } + ((@temptype@ *)dataptr[_SUMPROD_NOP])[0] = re + + ((@temptype@ *)dataptr[_SUMPROD_NOP])[0]; + ((@temptype@ *)dataptr[_SUMPROD_NOP])[1] = im + + ((@temptype@ *)dataptr[_SUMPROD_NOP])[1]; + + for (i = 0; i <= _SUMPROD_NOP; ++i) { + dataptr[i] += sizeof(@type@); + } +# undef _SUMPROD_NOP +#endif + } +} + +#endif /* functions for various @nop@ */ + +#if @nop@ == 1 + +static void +@name@_sum_of_products_contig_outstride0_one(int nop, char **dataptr, + npy_intp *strides, npy_intp count) +{ +#if @complex@ + @temptype@ accum_re = 0, accum_im = 0; + @temptype@ *data0 = (@temptype@ *)dataptr[0]; +#else + @temptype@ accum = 0; + @type@ *data0 = (@type@ *)dataptr[0]; +#endif + +#if EINSUM_USE_SSE1 && @float32@ + __m128 a, accum_sse = _mm_setzero_ps(); +#elif EINSUM_USE_SSE2 && @float64@ + __m128d a, accum_sse = _mm_setzero_pd(); +#endif + + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_outstride0_one (%d)\n", + (int)count); + +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat2 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: +#if !@complex@ + accum += @from@(data0[@i@]); +#else /* complex */ + accum_re += data0[2*@i@+0]; + accum_im += data0[2*@i@+1]; +#endif +/**end repeat2**/ + case 0: +#if @complex@ + ((@temptype@ *)dataptr[1])[0] += accum_re; + ((@temptype@ *)dataptr[1])[1] += accum_im; +#else + *((@type@ *)dataptr[1]) = @to@(accum + + @from@(*((@type@ *)dataptr[1]))); +#endif + return; + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data0)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + + _mm_prefetch(data0 + 512, _MM_HINT_T0); + +/**begin repeat2 + * #i = 0, 4# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data0+@i@)); +/**end repeat2**/ + data0 += 8; + } + + /* Add the four SSE values and put in accum */ + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1)); + accum_sse = _mm_add_ps(a, accum_sse); + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2)); + accum_sse = _mm_add_ps(a, accum_sse); + _mm_store_ss(&accum, accum_sse); + + /* Finish off the loop */ + goto finish_after_unrolled_loop; + } +#elif EINSUM_USE_SSE2 && @float64@ + /* Use aligned instructions if possible */ + if (EINSUM_IS_SSE_ALIGNED(data0)) { + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + + _mm_prefetch(data0 + 512, _MM_HINT_T0); + +/**begin repeat2 + * #i = 0, 2, 4, 6# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + accum_sse = _mm_add_pd(accum_sse, _mm_load_pd(data0+@i@)); +/**end repeat2**/ + data0 += 8; + } + + /* Add the two SSE2 values and put in accum */ + a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1)); + accum_sse = _mm_add_pd(a, accum_sse); + _mm_store_sd(&accum, accum_sse); + + /* Finish off the loop */ + goto finish_after_unrolled_loop; + } +#endif + + /* Unroll the loop by 8 */ + while (count >= 8) { + count -= 8; + +#if EINSUM_USE_SSE1 && @float32@ + _mm_prefetch(data0 + 512, _MM_HINT_T0); + +/**begin repeat2 + * #i = 0, 4# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data0+@i@)); +/**end repeat2**/ +#elif EINSUM_USE_SSE2 && @float64@ + _mm_prefetch(data0 + 512, _MM_HINT_T0); + +/**begin repeat2 + * #i = 0, 2, 4, 6# + */ + /* + * NOTE: This accumulation changes the order, so will likely + * produce slightly different results. + */ + accum_sse = _mm_add_pd(accum_sse, _mm_loadu_pd(data0+@i@)); +/**end repeat2**/ +#else +/**begin repeat2 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ +# if !@complex@ + accum += @from@(data0[@i@]); +# else /* complex */ + accum_re += data0[2*@i@+0]; + accum_im += data0[2*@i@+1]; +# endif +/**end repeat2**/ +#endif + +#if !@complex@ + data0 += 8; +#else + data0 += 8*2; +#endif + } + +#if EINSUM_USE_SSE1 && @float32@ + /* Add the four SSE values and put in accum */ + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1)); + accum_sse = _mm_add_ps(a, accum_sse); + a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2)); + accum_sse = _mm_add_ps(a, accum_sse); + _mm_store_ss(&accum, accum_sse); +#elif EINSUM_USE_SSE2 && @float64@ + /* Add the two SSE2 values and put in accum */ + a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1)); + accum_sse = _mm_add_pd(a, accum_sse); + _mm_store_sd(&accum, accum_sse); +#endif + + /* Finish off the loop */ + goto finish_after_unrolled_loop; +} + +#endif /* @nop@ == 1 */ + +static void +@name@_sum_of_products_outstride0_@noplabel@(int nop, char **dataptr, + npy_intp *strides, npy_intp count) +{ +#if @complex@ + @temptype@ accum_re = 0, accum_im = 0; +#else + @temptype@ accum = 0; +#endif + +#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@) + char *data0 = dataptr[0]; + npy_intp stride0 = strides[0]; +#endif +#if (@nop@ == 2 || @nop@ == 3) && !@complex@ + char *data1 = dataptr[1]; + npy_intp stride1 = strides[1]; +#endif +#if (@nop@ == 3) && !@complex@ + char *data2 = dataptr[2]; + npy_intp stride2 = strides[2]; +#endif + + NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_outstride0_@noplabel@ (%d)\n", + (int)count); + + while (count--) { +#if !@complex@ +# if @nop@ == 1 + accum += @from@(*(@type@ *)data0); + data0 += stride0; +# elif @nop@ == 2 + accum += @from@(*(@type@ *)data0) * + @from@(*(@type@ *)data1); + data0 += stride0; + data1 += stride1; +# elif @nop@ == 3 + accum += @from@(*(@type@ *)data0) * + @from@(*(@type@ *)data1) * + @from@(*(@type@ *)data2); + data0 += stride0; + data1 += stride1; + data2 += stride2; +# else + @temptype@ temp = @from@(*(@type@ *)dataptr[0]); + int i; + for (i = 1; i < nop; ++i) { + temp *= @from@(*(@type@ *)dataptr[i]); + } + accum += temp; + for (i = 0; i < nop; ++i) { + dataptr[i] += strides[i]; + } +# endif +#else /* complex */ +# if @nop@ == 1 + accum_re += ((@temptype@ *)data0)[0]; + accum_im += ((@temptype@ *)data0)[1]; + data0 += stride0; +# else +# if @nop@ <= 3 +#define _SUMPROD_NOP @nop@ +# else +#define _SUMPROD_NOP nop +# endif + @temptype@ re, im, tmp; + int i; + re = ((@temptype@ *)dataptr[0])[0]; + im = ((@temptype@ *)dataptr[0])[1]; + for (i = 1; i < _SUMPROD_NOP; ++i) { + tmp = re * ((@temptype@ *)dataptr[i])[0] - + im * ((@temptype@ *)dataptr[i])[1]; + im = re * ((@temptype@ *)dataptr[i])[1] + + im * ((@temptype@ *)dataptr[i])[0]; + re = tmp; + } + accum_re += re; + accum_im += im; + for (i = 0; i < _SUMPROD_NOP; ++i) { + dataptr[i] += strides[i]; + } +#undef _SUMPROD_NOP +# endif +#endif + } + +#if @complex@ +# if @nop@ <= 3 + ((@temptype@ *)dataptr[@nop@])[0] += accum_re; + ((@temptype@ *)dataptr[@nop@])[1] += accum_im; +# else + ((@temptype@ *)dataptr[nop])[0] += accum_re; + ((@temptype@ *)dataptr[nop])[1] += accum_im; +# endif +#else +# if @nop@ <= 3 + *((@type@ *)dataptr[@nop@]) = @to@(accum + + @from@(*((@type@ *)dataptr[@nop@]))); +# else + *((@type@ *)dataptr[nop]) = @to@(accum + + @from@(*((@type@ *)dataptr[nop]))); +# endif +#endif + +} + +/**end repeat1**/ + +/**end repeat**/ + + +/* Do OR of ANDs for the boolean type */ + +/**begin repeat + * #nop = 1, 2, 3, 1000# + * #noplabel = one, two, three, any# + */ + +static void +bool_sum_of_products_@noplabel@(int nop, char **dataptr, + npy_intp *strides, npy_intp count) +{ +#if (@nop@ <= 3) + char *data0 = dataptr[0]; + npy_intp stride0 = strides[0]; +#endif +#if (@nop@ == 2 || @nop@ == 3) + char *data1 = dataptr[1]; + npy_intp stride1 = strides[1]; +#endif +#if (@nop@ == 3) + char *data2 = dataptr[2]; + npy_intp stride2 = strides[2]; +#endif +#if (@nop@ <= 3) + char *data_out = dataptr[@nop@]; + npy_intp stride_out = strides[@nop@]; +#endif + + while (count--) { +#if @nop@ == 1 + *(npy_bool *)data_out = *(npy_bool *)data0 || + *(npy_bool *)data_out; + data0 += stride0; + data_out += stride_out; +#elif @nop@ == 2 + *(npy_bool *)data_out = (*(npy_bool *)data0 && + *(npy_bool *)data1) || + *(npy_bool *)data_out; + data0 += stride0; + data1 += stride1; + data_out += stride_out; +#elif @nop@ == 3 + *(npy_bool *)data_out = (*(npy_bool *)data0 && + *(npy_bool *)data1 && + *(npy_bool *)data2) || + *(npy_bool *)data_out; + data0 += stride0; + data1 += stride1; + data2 += stride2; + data_out += stride_out; +#else + npy_bool temp = *(npy_bool *)dataptr[0]; + int i; + for (i = 1; i < nop; ++i) { + temp = temp && *(npy_bool *)dataptr[i]; + } + *(npy_bool *)dataptr[nop] = temp || *(npy_bool *)dataptr[i]; + for (i = 0; i <= nop; ++i) { + dataptr[i] += strides[i]; + } +#endif + } +} + +static void +bool_sum_of_products_contig_@noplabel@(int nop, char **dataptr, + npy_intp *strides, npy_intp count) +{ +#if (@nop@ <= 3) + char *data0 = dataptr[0]; +#endif +#if (@nop@ == 2 || @nop@ == 3) + char *data1 = dataptr[1]; +#endif +#if (@nop@ == 3) + char *data2 = dataptr[2]; +#endif +#if (@nop@ <= 3) + char *data_out = dataptr[@nop@]; +#endif + +#if (@nop@ <= 3) +/* This is placed before the main loop to make small counts faster */ +finish_after_unrolled_loop: + switch (count) { +/**begin repeat1 + * #i = 6, 5, 4, 3, 2, 1, 0# + */ + case @i@+1: +# if @nop@ == 1 + ((npy_bool *)data_out)[@i@] = ((npy_bool *)data0)[@i@] || + ((npy_bool *)data_out)[@i@]; +# elif @nop@ == 2 + ((npy_bool *)data_out)[@i@] = + (((npy_bool *)data0)[@i@] && + ((npy_bool *)data1)[@i@]) || + ((npy_bool *)data_out)[@i@]; +# elif @nop@ == 3 + ((npy_bool *)data_out)[@i@] = + (((npy_bool *)data0)[@i@] && + ((npy_bool *)data1)[@i@] && + ((npy_bool *)data2)[@i@]) || + ((npy_bool *)data_out)[@i@]; +# endif +/**end repeat1**/ + case 0: + return; + } +#endif + +/* Unroll the loop by 8 for fixed-size nop */ +#if (@nop@ <= 3) + while (count >= 8) { + count -= 8; +#else + while (count--) { +#endif + +# if @nop@ == 1 +/**begin repeat1 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + *((npy_bool *)data_out + @i@) = (*((npy_bool *)data0 + @i@)) || + (*((npy_bool *)data_out + @i@)); +/**end repeat1**/ + data0 += 8*sizeof(npy_bool); + data_out += 8*sizeof(npy_bool); +# elif @nop@ == 2 +/**begin repeat1 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + *((npy_bool *)data_out + @i@) = + ((*((npy_bool *)data0 + @i@)) && + (*((npy_bool *)data1 + @i@))) || + (*((npy_bool *)data_out + @i@)); +/**end repeat1**/ + data0 += 8*sizeof(npy_bool); + data1 += 8*sizeof(npy_bool); + data_out += 8*sizeof(npy_bool); +# elif @nop@ == 3 +/**begin repeat1 + * #i = 0, 1, 2, 3, 4, 5, 6, 7# + */ + *((npy_bool *)data_out + @i@) = + ((*((npy_bool *)data0 + @i@)) && + (*((npy_bool *)data1 + @i@)) && + (*((npy_bool *)data2 + @i@))) || + (*((npy_bool *)data_out + @i@)); +/**end repeat1**/ + data0 += 8*sizeof(npy_bool); + data1 += 8*sizeof(npy_bool); + data2 += 8*sizeof(npy_bool); + data_out += 8*sizeof(npy_bool); +# else + npy_bool temp = *(npy_bool *)dataptr[0]; + int i; + for (i = 1; i < nop; ++i) { + temp = temp && *(npy_bool *)dataptr[i]; + } + *(npy_bool *)dataptr[nop] = temp || *(npy_bool *)dataptr[i]; + for (i = 0; i <= nop; ++i) { + dataptr[i] += sizeof(npy_bool); + } +# endif + } + + /* If the loop was unrolled, we need to finish it off */ +#if (@nop@ <= 3) + goto finish_after_unrolled_loop; +#endif +} + +static void +bool_sum_of_products_outstride0_@noplabel@(int nop, char **dataptr, + npy_intp *strides, npy_intp count) +{ + npy_bool accum = 0; + +#if (@nop@ <= 3) + char *data0 = dataptr[0]; + npy_intp stride0 = strides[0]; +#endif +#if (@nop@ == 2 || @nop@ == 3) + char *data1 = dataptr[1]; + npy_intp stride1 = strides[1]; +#endif +#if (@nop@ == 3) + char *data2 = dataptr[2]; + npy_intp stride2 = strides[2]; +#endif + + while (count--) { +#if @nop@ == 1 + accum = *(npy_bool *)data0 || accum; + data0 += stride0; +#elif @nop@ == 2 + accum = (*(npy_bool *)data0 && *(npy_bool *)data1) || accum; + data0 += stride0; + data1 += stride1; +#elif @nop@ == 3 + accum = (*(npy_bool *)data0 && + *(npy_bool *)data1 && + *(npy_bool *)data2) || accum; + data0 += stride0; + data1 += stride1; + data2 += stride2; +#else + npy_bool temp = *(npy_bool *)dataptr[0]; + int i; + for (i = 1; i < nop; ++i) { + temp = temp && *(npy_bool *)dataptr[i]; + } + accum = temp || accum; + for (i = 0; i <= nop; ++i) { + dataptr[i] += strides[i]; + } +#endif + } + +# if @nop@ <= 3 + *((npy_bool *)dataptr[@nop@]) = accum || *((npy_bool *)dataptr[@nop@]); +# else + *((npy_bool *)dataptr[nop]) = accum || *((npy_bool *)dataptr[nop]); +# endif +} + +/**end repeat**/ + +typedef void (*sum_of_products_fn)(int, char **, npy_intp *, npy_intp); + +/* These tables need to match up with the type enum */ +static sum_of_products_fn +_contig_outstride0_unary_specialization_table[NPY_NTYPES] = { +/**begin repeat + * #name = bool, + * byte, ubyte, + * short, ushort, + * int, uint, + * long, ulong, + * longlong, ulonglong, + * float, double, longdouble, + * cfloat, cdouble, clongdouble, + * object, string, unicode, void, + * datetime, timedelta, half# + * #use = 0, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, 1, + * 1, 1, 1, + * 0, 0, 0, 0, + * 0, 0, 1# + */ +#if @use@ + &@name@_sum_of_products_contig_outstride0_one, +#else + NULL, +#endif +/**end repeat**/ +}; /* End of _contig_outstride0_unary_specialization_table */ + +static sum_of_products_fn _binary_specialization_table[NPY_NTYPES][5] = { +/**begin repeat + * #name = bool, + * byte, ubyte, + * short, ushort, + * int, uint, + * long, ulong, + * longlong, ulonglong, + * float, double, longdouble, + * cfloat, cdouble, clongdouble, + * object, string, unicode, void, + * datetime, timedelta, half# + * #use = 0, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, 1, + * 0, 0, 0, + * 0, 0, 0, 0, + * 0, 0, 1# + */ +#if @use@ +{ + &@name@_sum_of_products_stride0_contig_outstride0_two, + &@name@_sum_of_products_stride0_contig_outcontig_two, + &@name@_sum_of_products_contig_stride0_outstride0_two, + &@name@_sum_of_products_contig_stride0_outcontig_two, + &@name@_sum_of_products_contig_contig_outstride0_two, +}, +#else + {NULL, NULL, NULL, NULL, NULL}, +#endif +/**end repeat**/ +}; /* End of _binary_specialization_table */ + +static sum_of_products_fn _outstride0_specialized_table[NPY_NTYPES][4] = { +/**begin repeat + * #name = bool, + * byte, ubyte, + * short, ushort, + * int, uint, + * long, ulong, + * longlong, ulonglong, + * float, double, longdouble, + * cfloat, cdouble, clongdouble, + * object, string, unicode, void, + * datetime, timedelta, half# + * #use = 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, 1, + * 1, 1, 1, + * 0, 0, 0, 0, + * 0, 0, 1# + */ +#if @use@ +{ + &@name@_sum_of_products_outstride0_any, + &@name@_sum_of_products_outstride0_one, + &@name@_sum_of_products_outstride0_two, + &@name@_sum_of_products_outstride0_three +}, +#else + {NULL, NULL, NULL, NULL}, +#endif +/**end repeat**/ +}; /* End of _outstride0_specialized_table */ + +static sum_of_products_fn _allcontig_specialized_table[NPY_NTYPES][4] = { +/**begin repeat + * #name = bool, + * byte, ubyte, + * short, ushort, + * int, uint, + * long, ulong, + * longlong, ulonglong, + * float, double, longdouble, + * cfloat, cdouble, clongdouble, + * object, string, unicode, void, + * datetime, timedelta, half# + * #use = 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, 1, + * 1, 1, 1, + * 0, 0, 0, 0, + * 0, 0, 1# + */ +#if @use@ +{ + &@name@_sum_of_products_contig_any, + &@name@_sum_of_products_contig_one, + &@name@_sum_of_products_contig_two, + &@name@_sum_of_products_contig_three +}, +#else + {NULL, NULL, NULL, NULL}, +#endif +/**end repeat**/ +}; /* End of _allcontig_specialized_table */ + +static sum_of_products_fn _unspecialized_table[NPY_NTYPES][4] = { +/**begin repeat + * #name = bool, + * byte, ubyte, + * short, ushort, + * int, uint, + * long, ulong, + * longlong, ulonglong, + * float, double, longdouble, + * cfloat, cdouble, clongdouble, + * object, string, unicode, void, + * datetime, timedelta, half# + * #use = 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, + * 1, 1, 1, + * 1, 1, 1, + * 0, 0, 0, 0, + * 0, 0, 1# + */ +#if @use@ +{ + &@name@_sum_of_products_any, + &@name@_sum_of_products_one, + &@name@_sum_of_products_two, + &@name@_sum_of_products_three +}, +#else + {NULL, NULL, NULL, NULL}, +#endif +/**end repeat**/ +}; /* End of _unnspecialized_table */ + +static sum_of_products_fn +get_sum_of_products_function(int nop, int type_num, + npy_intp itemsize, npy_intp *fixed_strides) +{ + int iop; + + if (type_num >= NPY_NTYPES) { + return NULL; + } + + /* contiguous reduction */ + if (nop == 1 && fixed_strides[0] == itemsize && fixed_strides[1] == 0) { + sum_of_products_fn ret = + _contig_outstride0_unary_specialization_table[type_num]; + if (ret != NULL) { + return ret; + } + } + + /* nop of 2 has more specializations */ + if (nop == 2) { + /* Encode the zero/contiguous strides */ + int code; + code = (fixed_strides[0] == 0) ? 0 : + (fixed_strides[0] == itemsize) ? 2*2*1 : 8; + code += (fixed_strides[1] == 0) ? 0 : + (fixed_strides[1] == itemsize) ? 2*1 : 8; + code += (fixed_strides[2] == 0) ? 0 : + (fixed_strides[2] == itemsize) ? 1 : 8; + if (code >= 2 && code < 7) { + sum_of_products_fn ret = + _binary_specialization_table[type_num][code-2]; + if (ret != NULL) { + return ret; + } + } + } + + /* Inner loop with an output stride of 0 */ + if (fixed_strides[nop] == 0) { + return _outstride0_specialized_table[type_num][nop <= 3 ? nop : 0]; + } + + /* Check for all contiguous */ + for (iop = 0; iop < nop + 1; ++iop) { + if (fixed_strides[iop] != itemsize) { + break; + } + } + + /* Contiguous loop */ + if (iop == nop + 1) { + return _allcontig_specialized_table[type_num][nop <= 3 ? nop : 0]; + } + + /* None of the above specializations caught it, general loops */ + return _unspecialized_table[type_num][nop <= 3 ? nop : 0]; +} + +/* + * Parses the subscripts for one operand into an output + * of 'ndim' labels + */ +static int +parse_operand_subscripts(char *subscripts, int length, + int ndim, + int iop, char *out_labels, + char *out_label_counts, + int *out_min_label, + int *out_max_label, + int *out_num_labels) +{ + int i, idim, ndim_left, label; + int ellipsis = 0; + + /* Process the labels from the end until the ellipsis */ + idim = ndim-1; + for (i = length-1; i >= 0; --i) { + label = subscripts[i]; + /* A label for an axis */ + if (label > 0 && isalpha(label)) { + if (idim >= 0) { + out_labels[idim--] = label; + /* Calculate the min and max labels */ + if (label < *out_min_label) { + *out_min_label = label; + } + if (label > *out_max_label) { + *out_max_label = label; + } + /* If it's the first time we see this label, count it */ + if (out_label_counts[label] == 0) { + (*out_num_labels)++; + } + out_label_counts[label]++; + } + else { + PyErr_Format(PyExc_ValueError, + "einstein sum subscripts string contains " + "too many subscripts for operand %d", iop); + return 0; + } + } + /* The end of the ellipsis */ + else if (label == '.') { + /* A valid ellipsis */ + if (i >= 2 && subscripts[i-1] == '.' && subscripts[i-2] == '.') { + ellipsis = 1; + length = i-2; + break; + } + else { + PyErr_SetString(PyExc_ValueError, + "einstein sum subscripts string contains a " + "'.' that is not part of an ellipsis ('...')"); + return 0; + + } + } + else if (label != ' ') { + PyErr_Format(PyExc_ValueError, + "invalid subscript '%c' in einstein sum " + "subscripts string, subscripts must " + "be letters", (char)label); + return 0; + } + } + + if (!ellipsis && idim != -1) { + PyErr_Format(PyExc_ValueError, + "operand has more dimensions than subscripts " + "given in einstein sum, but no '...' ellipsis " + "provided to broadcast the extra dimensions."); + return 0; + } + + /* Reduce ndim to just the dimensions left to fill at the beginning */ + ndim_left = idim+1; + idim = 0; + + /* + * If we stopped because of an ellipsis, start again from the beginning. + * The length was truncated to end at the ellipsis in this case. + */ + if (i > 0) { + for (i = 0; i < length; ++i) { + label = subscripts[i]; + /* A label for an axis */ + if (label > 0 && isalnum(label)) { + if (idim < ndim_left) { + out_labels[idim++] = label; + /* Calculate the min and max labels */ + if (label < *out_min_label) { + *out_min_label = label; + } + if (label > *out_max_label) { + *out_max_label = label; + } + /* If it's the first time we see this label, count it */ + if (out_label_counts[label] == 0) { + (*out_num_labels)++; + } + out_label_counts[label]++; + } + else { + PyErr_Format(PyExc_ValueError, + "einstein sum subscripts string contains " + "too many subscripts for operand %d", iop); + return 0; + } + } + else if (label != ' ') { + PyErr_Format(PyExc_ValueError, + "invalid subscript '%c' in einstein sum " + "subscripts string, subscripts must " + "be letters", (char)label); + return 0; + } + } + } + + /* Set the remaining labels to 0 */ + while (idim < ndim_left) { + out_labels[idim++] = 0; + } + + /* + * Find any labels duplicated for this operand, and turn them + * into negative offets to the axis to merge with. + * + * In C, the char type may be signed or unsigned, but with + * twos complement arithmetic the char is ok either way here, and + * later where it matters the char is cast to a signed char. + */ + for (idim = 0; idim < ndim-1; ++idim) { + char *next; + /* If this is a proper label, find any duplicates of it */ + label = out_labels[idim]; + if (label > 0) { + /* Search for the next matching label */ + next = (char *)memchr(out_labels+idim+1, label, + ndim-idim-1); + while (next != NULL) { + /* The offset from next to out_labels[idim] (negative) */ + *next = (char)((out_labels+idim)-next); + /* Search for the next matching label */ + next = (char *)memchr(next+1, label, + out_labels+ndim-1-next); + } + } + } + + return 1; +} + +/* + * Parses the subscripts for the output operand into an output + * that requires 'ndim_broadcast' unlabeled dimensions, returning + * the number of output dimensions. Returns -1 if there is an error. + */ +static int +parse_output_subscripts(char *subscripts, int length, + int ndim_broadcast, + const char *label_counts, + char *out_labels) +{ + int i, nlabels, label, idim, ndim, ndim_left; + int ellipsis = 0; + + /* Count the labels, making sure they're all unique and valid */ + nlabels = 0; + for (i = 0; i < length; ++i) { + label = subscripts[i]; + if (label > 0 && isalpha(label)) { + /* Check if it occurs again */ + if (memchr(subscripts+i+1, label, length-i-1) == NULL) { + /* Check that it was used in the inputs */ + if (label_counts[label] == 0) { + PyErr_Format(PyExc_ValueError, + "einstein sum subscripts string included " + "output subscript '%c' which never appeared " + "in an input", (char)label); + return -1; + } + + nlabels++; + } + else { + PyErr_Format(PyExc_ValueError, + "einstein sum subscripts string includes " + "output subscript '%c' multiple times", + (char)label); + return -1; + } + } + else if (label != '.' && label != ' ') { + PyErr_Format(PyExc_ValueError, + "invalid subscript '%c' in einstein sum " + "subscripts string, subscripts must " + "be letters", (char)label); + return -1; + } + } + + /* The number of output dimensions */ + ndim = ndim_broadcast + nlabels; + + /* Process the labels from the end until the ellipsis */ + idim = ndim-1; + for (i = length-1; i >= 0; --i) { + label = subscripts[i]; + /* A label for an axis */ + if (label != '.' && label != ' ') { + if (idim >= 0) { + out_labels[idim--] = label; + } + else { + PyErr_Format(PyExc_ValueError, + "einstein sum subscripts string contains " + "too many output subscripts"); + return -1; + } + } + /* The end of the ellipsis */ + else if (label == '.') { + /* A valid ellipsis */ + if (i >= 2 && subscripts[i-1] == '.' && subscripts[i-2] == '.') { + ellipsis = 1; + length = i-2; + break; + } + else { + PyErr_SetString(PyExc_ValueError, + "einstein sum subscripts string contains a " + "'.' that is not part of an ellipsis ('...')"); + return -1; + + } + } + } + + if (!ellipsis && idim != -1) { + PyErr_SetString(PyExc_ValueError, + "output has more dimensions than subscripts " + "given in einstein sum, but no '...' ellipsis " + "provided to broadcast the extra dimensions."); + return 0; + } + + /* Reduce ndim to just the dimensions left to fill at the beginning */ + ndim_left = idim+1; + idim = 0; + + /* + * If we stopped because of an ellipsis, start again from the beginning. + * The length was truncated to end at the ellipsis in this case. + */ + if (i > 0) { + for (i = 0; i < length; ++i) { + label = subscripts[i]; + /* A label for an axis */ + if (label != '.' && label != ' ') { + if (idim < ndim_left) { + out_labels[idim++] = label; + } + else { + PyErr_Format(PyExc_ValueError, + "einstein sum subscripts string contains " + "too many subscripts for the output"); + return -1; + } + } + else { + PyErr_SetString(PyExc_ValueError, + "einstein sum subscripts string contains a " + "'.' that is not part of an ellipsis ('...')"); + return -1; + } + } + } + + /* Set the remaining output labels to 0 */ + while (idim < ndim_left) { + out_labels[idim++] = 0; + } + + return ndim; +} + + +/* + * When there's just one operand and no reduction, we + * can return a view into op. This calculates the view + * if possible. + */ +static int +get_single_op_view(PyArrayObject *op, int iop, char *labels, + int ndim_output, char *output_labels, + PyArrayObject **ret) +{ + npy_intp new_strides[NPY_MAXDIMS]; + npy_intp new_dims[NPY_MAXDIMS]; + char *out_label; + int label, i, idim, ndim, ibroadcast = 0; + + ndim = PyArray_NDIM(op); + + /* Initialize the dimensions and strides to zero */ + for (idim = 0; idim < ndim_output; ++idim) { + new_dims[idim] = 0; + new_strides[idim] = 0; + } + + /* Match the labels in the operand with the output labels */ + for (idim = 0; idim < ndim; ++idim) { + /* + * The char type may be either signed or unsigned, we + * need it to be signed here. + */ + label = (signed char)labels[idim]; + /* If this label says to merge axes, get the actual label */ + if (label < 0) { + label = labels[idim+label]; + } + /* If the label is 0, it's an unlabeled broadcast dimension */ + if (label == 0) { + /* The next output label that's a broadcast dimension */ + for (; ibroadcast < ndim_output; ++ibroadcast) { + if (output_labels[ibroadcast] == 0) { + break; + } + } + if (ibroadcast == ndim_output) { + PyErr_SetString(PyExc_ValueError, + "output had too few broadcast dimensions"); + return 0; + } + new_dims[ibroadcast] = PyArray_DIM(op, idim); + new_strides[ibroadcast] = PyArray_STRIDE(op, idim); + ++ibroadcast; + } + else { + /* Find the position for this dimension in the output */ + out_label = (char *)memchr(output_labels, label, + ndim_output); + /* If it's not found, reduction -> can't return a view */ + if (out_label == NULL) { + break; + } + /* Update the dimensions and strides of the output */ + i = out_label - output_labels; + if (new_dims[i] != 0 && + new_dims[i] != PyArray_DIM(op, idim)) { + PyErr_Format(PyExc_ValueError, + "dimensions in operand %d for collapsing " + "index '%c' don't match (%d != %d)", + iop, label, (int)new_dims[i], + (int)PyArray_DIM(op, idim)); + return 0; + } + new_dims[i] = PyArray_DIM(op, idim); + new_strides[i] += PyArray_STRIDE(op, idim); + } + } + /* If we processed all the input axes, return a view */ + if (idim == ndim) { + Py_INCREF(PyArray_DESCR(op)); + *ret = (PyArrayObject *)PyArray_NewFromDescr( + Py_TYPE(op), + PyArray_DESCR(op), + ndim_output, new_dims, new_strides, + PyArray_DATA(op), + PyArray_ISWRITEABLE(op) ? NPY_ARRAY_WRITEABLE : 0, + (PyObject *)op); + + if (*ret == NULL) { + return 0; + } + if (!PyArray_Check(*ret)) { + Py_DECREF(*ret); + *ret = NULL; + PyErr_SetString(PyExc_RuntimeError, + "NewFromDescr failed to return an array"); + return 0; + } + PyArray_UpdateFlags(*ret, + NPY_ARRAY_C_CONTIGUOUS| + NPY_ARRAY_ALIGNED| + NPY_ARRAY_F_CONTIGUOUS); + Py_INCREF(op); + if (PyArray_SetBaseObject(*ret, (PyObject *)op) < 0) { + Py_DECREF(*ret); + *ret = NULL; + return 0; + } + return 1; + } + + /* Return success, but that we couldn't make a view */ + *ret = NULL; + return 1; +} + +static PyArrayObject * +get_combined_dims_view(PyArrayObject *op, int iop, char *labels) +{ + npy_intp new_strides[NPY_MAXDIMS]; + npy_intp new_dims[NPY_MAXDIMS]; + int i, idim, ndim, icombine, combineoffset, label; + int icombinemap[NPY_MAXDIMS]; + + PyArrayObject *ret = NULL; + + ndim = PyArray_NDIM(op); + + /* Initialize the dimensions and strides to zero */ + for (idim = 0; idim < ndim; ++idim) { + new_dims[idim] = 0; + new_strides[idim] = 0; + } + + /* Copy the dimensions and strides, except when collapsing */ + icombine = 0; + for (idim = 0; idim < ndim; ++idim) { + /* + * The char type may be either signed or unsigned, we + * need it to be signed here. + */ + label = (signed char)labels[idim]; + /* If this label says to merge axes, get the actual label */ + if (label < 0) { + combineoffset = label; + label = labels[idim+label]; + } + else { + combineoffset = 0; + if (icombine != idim) { + labels[icombine] = labels[idim]; + } + icombinemap[idim] = icombine; + } + /* If the label is 0, it's an unlabeled broadcast dimension */ + if (label == 0) { + new_dims[icombine] = PyArray_DIM(op, idim); + new_strides[icombine] = PyArray_STRIDE(op, idim); + } + else { + /* Update the combined axis dimensions and strides */ + i = idim + combineoffset; + if (combineoffset < 0 && new_dims[i] != 0 && + new_dims[i] != PyArray_DIM(op, idim)) { + PyErr_Format(PyExc_ValueError, + "dimensions in operand %d for collapsing " + "index '%c' don't match (%d != %d)", + iop, label, (int)new_dims[i], + (int)PyArray_DIM(op, idim)); + return NULL; + } + i = icombinemap[i]; + new_dims[i] = PyArray_DIM(op, idim); + new_strides[i] += PyArray_STRIDE(op, idim); + } + + /* If the label didn't say to combine axes, increment dest i */ + if (combineoffset == 0) { + icombine++; + } + } + + /* The compressed number of dimensions */ + ndim = icombine; + + Py_INCREF(PyArray_DESCR(op)); + ret = (PyArrayObject *)PyArray_NewFromDescr( + Py_TYPE(op), + PyArray_DESCR(op), + ndim, new_dims, new_strides, + PyArray_DATA(op), + PyArray_ISWRITEABLE(op) ? NPY_ARRAY_WRITEABLE : 0, + (PyObject *)op); + + if (ret == NULL) { + return NULL; + } + if (!PyArray_Check(ret)) { + Py_DECREF(ret); + PyErr_SetString(PyExc_RuntimeError, + "NewFromDescr failed to return an array"); + return NULL; + } + PyArray_UpdateFlags(ret, + NPY_ARRAY_C_CONTIGUOUS| + NPY_ARRAY_ALIGNED| + NPY_ARRAY_F_CONTIGUOUS); + Py_INCREF(op); + if (PyArray_SetBaseObject(ret, (PyObject *)op) < 0) { + Py_DECREF(ret); + return NULL; + } + + return ret; +} + +static int +prepare_op_axes(int ndim, int iop, char *labels, int *axes, + int ndim_iter, char *iter_labels) +{ + int i, label, ibroadcast; + + ibroadcast = ndim-1; + for (i = ndim_iter-1; i >= 0; --i) { + label = iter_labels[i]; + /* + * If it's an unlabeled broadcast dimension, choose + * the next broadcast dimension from the operand. + */ + if (label == 0) { + while (ibroadcast >= 0 && labels[ibroadcast] != 0) { + --ibroadcast; + } + /* + * If we used up all the operand broadcast dimensions, + * extend it with a "newaxis" + */ + if (ibroadcast < 0) { + axes[i] = -1; + } + /* Otherwise map to the broadcast axis */ + else { + axes[i] = ibroadcast; + --ibroadcast; + } + } + /* It's a labeled dimension, find the matching one */ + else { + char *match = memchr(labels, label, ndim); + /* If the op doesn't have the label, broadcast it */ + if (match == NULL) { + axes[i] = -1; + } + /* Otherwise use it */ + else { + axes[i] = match - labels; + } + } + } + + return 1; +} + +static int +unbuffered_loop_nop1_ndim2(NpyIter *iter) +{ + npy_intp coord, shape[2], strides[2][2]; + char *ptrs[2][2], *ptr; + sum_of_products_fn sop; + NPY_BEGIN_THREADS_DEF; + +#if NPY_EINSUM_DBG_TRACING + NpyIter_DebugPrint(iter); +#endif + NPY_EINSUM_DBG_PRINT("running hand-coded 1-op 2-dim loop\n"); + + NpyIter_GetShape(iter, shape); + memcpy(strides[0], NpyIter_GetAxisStrideArray(iter, 0), + 2*sizeof(npy_intp)); + memcpy(strides[1], NpyIter_GetAxisStrideArray(iter, 1), + 2*sizeof(npy_intp)); + memcpy(ptrs[0], NpyIter_GetInitialDataPtrArray(iter), + 2*sizeof(char *)); + memcpy(ptrs[1], ptrs[0], 2*sizeof(char*)); + + sop = get_sum_of_products_function(1, + NpyIter_GetDescrArray(iter)[0]->type_num, + NpyIter_GetDescrArray(iter)[0]->elsize, + strides[0]); + + if (sop == NULL) { + PyErr_SetString(PyExc_TypeError, + "invalid data type for einsum"); + return -1; + } + + /* + * Since the iterator wasn't tracking coordinates, the + * loop provided by the iterator is in Fortran-order. + */ + NPY_BEGIN_THREADS_THRESHOLDED(shape[1] * shape[0]); + for (coord = shape[1]; coord > 0; --coord) { + sop(1, ptrs[0], strides[0], shape[0]); + + ptr = ptrs[1][0] + strides[1][0]; + ptrs[0][0] = ptrs[1][0] = ptr; + ptr = ptrs[1][1] + strides[1][1]; + ptrs[0][1] = ptrs[1][1] = ptr; + } + NPY_END_THREADS; + + return 0; +} + +static int +unbuffered_loop_nop1_ndim3(NpyIter *iter) +{ + npy_intp coords[2], shape[3], strides[3][2]; + char *ptrs[3][2], *ptr; + sum_of_products_fn sop; + NPY_BEGIN_THREADS_DEF; + +#if NPY_EINSUM_DBG_TRACING + NpyIter_DebugPrint(iter); +#endif + NPY_EINSUM_DBG_PRINT("running hand-coded 1-op 3-dim loop\n"); + + NpyIter_GetShape(iter, shape); + memcpy(strides[0], NpyIter_GetAxisStrideArray(iter, 0), + 2*sizeof(npy_intp)); + memcpy(strides[1], NpyIter_GetAxisStrideArray(iter, 1), + 2*sizeof(npy_intp)); + memcpy(strides[2], NpyIter_GetAxisStrideArray(iter, 2), + 2*sizeof(npy_intp)); + memcpy(ptrs[0], NpyIter_GetInitialDataPtrArray(iter), + 2*sizeof(char *)); + memcpy(ptrs[1], ptrs[0], 2*sizeof(char*)); + memcpy(ptrs[2], ptrs[0], 2*sizeof(char*)); + + sop = get_sum_of_products_function(1, + NpyIter_GetDescrArray(iter)[0]->type_num, + NpyIter_GetDescrArray(iter)[0]->elsize, + strides[0]); + + if (sop == NULL) { + PyErr_SetString(PyExc_TypeError, + "invalid data type for einsum"); + return -1; + } + + /* + * Since the iterator wasn't tracking coordinates, the + * loop provided by the iterator is in Fortran-order. + */ + NPY_BEGIN_THREADS_THRESHOLDED(shape[2] * shape[1] * shape[0]); + for (coords[1] = shape[2]; coords[1] > 0; --coords[1]) { + for (coords[0] = shape[1]; coords[0] > 0; --coords[0]) { + sop(1, ptrs[0], strides[0], shape[0]); + + ptr = ptrs[1][0] + strides[1][0]; + ptrs[0][0] = ptrs[1][0] = ptr; + ptr = ptrs[1][1] + strides[1][1]; + ptrs[0][1] = ptrs[1][1] = ptr; + } + ptr = ptrs[2][0] + strides[2][0]; + ptrs[0][0] = ptrs[1][0] = ptrs[2][0] = ptr; + ptr = ptrs[2][1] + strides[2][1]; + ptrs[0][1] = ptrs[1][1] = ptrs[2][1] = ptr; + } + NPY_END_THREADS; + + return 0; +} + +static int +unbuffered_loop_nop2_ndim2(NpyIter *iter) +{ + npy_intp coord, shape[2], strides[2][3]; + char *ptrs[2][3], *ptr; + sum_of_products_fn sop; + NPY_BEGIN_THREADS_DEF; + +#if NPY_EINSUM_DBG_TRACING + NpyIter_DebugPrint(iter); +#endif + NPY_EINSUM_DBG_PRINT("running hand-coded 2-op 2-dim loop\n"); + + NpyIter_GetShape(iter, shape); + memcpy(strides[0], NpyIter_GetAxisStrideArray(iter, 0), + 3*sizeof(npy_intp)); + memcpy(strides[1], NpyIter_GetAxisStrideArray(iter, 1), + 3*sizeof(npy_intp)); + memcpy(ptrs[0], NpyIter_GetInitialDataPtrArray(iter), + 3*sizeof(char *)); + memcpy(ptrs[1], ptrs[0], 3*sizeof(char*)); + + sop = get_sum_of_products_function(2, + NpyIter_GetDescrArray(iter)[0]->type_num, + NpyIter_GetDescrArray(iter)[0]->elsize, + strides[0]); + + if (sop == NULL) { + PyErr_SetString(PyExc_TypeError, + "invalid data type for einsum"); + return -1; + } + + /* + * Since the iterator wasn't tracking coordinates, the + * loop provided by the iterator is in Fortran-order. + */ + NPY_BEGIN_THREADS_THRESHOLDED(shape[1] * shape[0]); + for (coord = shape[1]; coord > 0; --coord) { + sop(2, ptrs[0], strides[0], shape[0]); + + ptr = ptrs[1][0] + strides[1][0]; + ptrs[0][0] = ptrs[1][0] = ptr; + ptr = ptrs[1][1] + strides[1][1]; + ptrs[0][1] = ptrs[1][1] = ptr; + ptr = ptrs[1][2] + strides[1][2]; + ptrs[0][2] = ptrs[1][2] = ptr; + } + NPY_END_THREADS; + + return 0; +} + +static int +unbuffered_loop_nop2_ndim3(NpyIter *iter) +{ + npy_intp coords[2], shape[3], strides[3][3]; + char *ptrs[3][3], *ptr; + sum_of_products_fn sop; + NPY_BEGIN_THREADS_DEF; + +#if NPY_EINSUM_DBG_TRACING + NpyIter_DebugPrint(iter); +#endif + NPY_EINSUM_DBG_PRINT("running hand-coded 2-op 3-dim loop\n"); + + NpyIter_GetShape(iter, shape); + memcpy(strides[0], NpyIter_GetAxisStrideArray(iter, 0), + 3*sizeof(npy_intp)); + memcpy(strides[1], NpyIter_GetAxisStrideArray(iter, 1), + 3*sizeof(npy_intp)); + memcpy(strides[2], NpyIter_GetAxisStrideArray(iter, 2), + 3*sizeof(npy_intp)); + memcpy(ptrs[0], NpyIter_GetInitialDataPtrArray(iter), + 3*sizeof(char *)); + memcpy(ptrs[1], ptrs[0], 3*sizeof(char*)); + memcpy(ptrs[2], ptrs[0], 3*sizeof(char*)); + + sop = get_sum_of_products_function(2, + NpyIter_GetDescrArray(iter)[0]->type_num, + NpyIter_GetDescrArray(iter)[0]->elsize, + strides[0]); + + if (sop == NULL) { + PyErr_SetString(PyExc_TypeError, + "invalid data type for einsum"); + return -1; + } + + /* + * Since the iterator wasn't tracking coordinates, the + * loop provided by the iterator is in Fortran-order. + */ + NPY_BEGIN_THREADS_THRESHOLDED(shape[2] * shape[1] * shape[0]); + for (coords[1] = shape[2]; coords[1] > 0; --coords[1]) { + for (coords[0] = shape[1]; coords[0] > 0; --coords[0]) { + sop(2, ptrs[0], strides[0], shape[0]); + + ptr = ptrs[1][0] + strides[1][0]; + ptrs[0][0] = ptrs[1][0] = ptr; + ptr = ptrs[1][1] + strides[1][1]; + ptrs[0][1] = ptrs[1][1] = ptr; + ptr = ptrs[1][2] + strides[1][2]; + ptrs[0][2] = ptrs[1][2] = ptr; + } + ptr = ptrs[2][0] + strides[2][0]; + ptrs[0][0] = ptrs[1][0] = ptrs[2][0] = ptr; + ptr = ptrs[2][1] + strides[2][1]; + ptrs[0][1] = ptrs[1][1] = ptrs[2][1] = ptr; + ptr = ptrs[2][2] + strides[2][2]; + ptrs[0][2] = ptrs[1][2] = ptrs[2][2] = ptr; + } + NPY_END_THREADS; + + return 0; +} + + +/*NUMPY_API + * This function provides summation of array elements according to + * the Einstein summation convention. For example: + * - trace(a) -> einsum("ii", a) + * - transpose(a) -> einsum("ji", a) + * - multiply(a,b) -> einsum(",", a, b) + * - inner(a,b) -> einsum("i,i", a, b) + * - outer(a,b) -> einsum("i,j", a, b) + * - matvec(a,b) -> einsum("ij,j", a, b) + * - matmat(a,b) -> einsum("ij,jk", a, b) + * + * subscripts: The string of subscripts for einstein summation. + * nop: The number of operands + * op_in: The array of operands + * dtype: Either NULL, or the data type to force the calculation as. + * order: The order for the calculation/the output axes. + * casting: What kind of casts should be permitted. + * out: Either NULL, or an array into which the output should be placed. + * + * By default, the labels get placed in alphabetical order + * at the end of the output. So, if c = einsum("i,j", a, b) + * then c[i,j] == a[i]*b[j], but if c = einsum("j,i", a, b) + * then c[i,j] = a[j]*b[i]. + * + * Alternatively, you can control the output order or prevent + * an axis from being summed/force an axis to be summed by providing + * indices for the output. This allows us to turn 'trace' into + * 'diag', for example. + * - diag(a) -> einsum("ii->i", a) + * - sum(a, axis=0) -> einsum("i...->", a) + * + * Subscripts at the beginning and end may be specified by + * putting an ellipsis "..." in the middle. For example, + * the function einsum("i...i", a) takes the diagonal of + * the first and last dimensions of the operand, and + * einsum("ij...,jk...->ik...") takes the matrix product using + * the first two indices of each operand instead of the last two. + * + * When there is only one operand, no axes being summed, and + * no output parameter, this function returns a view + * into the operand instead of making a copy. + */ +NPY_NO_EXPORT PyArrayObject * +PyArray_EinsteinSum(char *subscripts, npy_intp nop, + PyArrayObject **op_in, + PyArray_Descr *dtype, + NPY_ORDER order, NPY_CASTING casting, + PyArrayObject *out) +{ + int iop, label, min_label = 127, max_label = 0, num_labels; + char label_counts[128]; + char op_labels[NPY_MAXARGS][NPY_MAXDIMS]; + char output_labels[NPY_MAXDIMS], *iter_labels; + int idim, ndim_output, ndim_broadcast, ndim_iter; + + PyArrayObject *op[NPY_MAXARGS], *ret = NULL; + PyArray_Descr *op_dtypes_array[NPY_MAXARGS], **op_dtypes; + + int op_axes_arrays[NPY_MAXARGS][NPY_MAXDIMS]; + int *op_axes[NPY_MAXARGS]; + npy_uint32 op_flags[NPY_MAXARGS]; + + NpyIter *iter; + sum_of_products_fn sop; + npy_intp fixed_strides[NPY_MAXARGS]; + + /* nop+1 (+1 is for the output) must fit in NPY_MAXARGS */ + if (nop >= NPY_MAXARGS) { + PyErr_SetString(PyExc_ValueError, + "too many operands provided to einstein sum function"); + return NULL; + } + else if (nop < 1) { + PyErr_SetString(PyExc_ValueError, + "not enough operands provided to einstein sum function"); + return NULL; + } + + /* Parse the subscripts string into label_counts and op_labels */ + memset(label_counts, 0, sizeof(label_counts)); + num_labels = 0; + for (iop = 0; iop < nop; ++iop) { + int length = (int)strcspn(subscripts, ",-"); + + if (iop == nop-1 && subscripts[length] == ',') { + PyErr_SetString(PyExc_ValueError, + "more operands provided to einstein sum function " + "than specified in the subscripts string"); + return NULL; + } + else if(iop < nop-1 && subscripts[length] != ',') { + PyErr_SetString(PyExc_ValueError, + "fewer operands provided to einstein sum function " + "than specified in the subscripts string"); + return NULL; + } + + if (!parse_operand_subscripts(subscripts, length, + PyArray_NDIM(op_in[iop]), + iop, op_labels[iop], label_counts, + &min_label, &max_label, &num_labels)) { + return NULL; + } + + /* Move subscripts to the start of the labels for the next op */ + subscripts += length; + if (iop < nop-1) { + subscripts++; + } + } + + /* + * Find the number of broadcast dimensions, which is the maximum + * number of labels == 0 in an op_labels array. + */ + ndim_broadcast = 0; + for (iop = 0; iop < nop; ++iop) { + npy_intp count_zeros = 0; + int ndim; + char *labels = op_labels[iop]; + + ndim = PyArray_NDIM(op_in[iop]); + for (idim = 0; idim < ndim; ++idim) { + if (labels[idim] == 0) { + ++count_zeros; + } + } + + if (count_zeros > ndim_broadcast) { + ndim_broadcast = count_zeros; + } + } + + /* + * If there is no output signature, create one using each label + * that appeared once, in alphabetical order + */ + if (subscripts[0] == '\0') { + char outsubscripts[NPY_MAXDIMS + 3]; + int length; + /* If no output was specified, always broadcast left (like normal) */ + outsubscripts[0] = '.'; + outsubscripts[1] = '.'; + outsubscripts[2] = '.'; + length = 3; + for (label = min_label; label <= max_label; ++label) { + if (label_counts[label] == 1) { + if (length < NPY_MAXDIMS-1) { + outsubscripts[length++] = label; + } + else { + PyErr_SetString(PyExc_ValueError, + "einstein sum subscript string has too many " + "distinct labels"); + return NULL; + } + } + } + /* Parse the output subscript string */ + ndim_output = parse_output_subscripts(outsubscripts, length, + ndim_broadcast, label_counts, + output_labels); + } + else { + if (subscripts[0] != '-' || subscripts[1] != '>') { + PyErr_SetString(PyExc_ValueError, + "einstein sum subscript string does not " + "contain proper '->' output specified"); + return NULL; + } + subscripts += 2; + + /* Parse the output subscript string */ + ndim_output = parse_output_subscripts(subscripts, strlen(subscripts), + ndim_broadcast, label_counts, + output_labels); + } + if (ndim_output < 0) { + return NULL; + } + + if (out != NULL && PyArray_NDIM(out) != ndim_output) { + PyErr_Format(PyExc_ValueError, + "out parameter does not have the correct number of " + "dimensions, has %d but should have %d", + (int)PyArray_NDIM(out), (int)ndim_output); + return NULL; + } + + /* Set all the op references to NULL */ + for (iop = 0; iop < nop; ++iop) { + op[iop] = NULL; + } + + /* + * Process all the input ops, combining dimensions into their + * diagonal where specified. + */ + for (iop = 0; iop < nop; ++iop) { + char *labels = op_labels[iop]; + int combine, ndim; + + ndim = PyArray_NDIM(op_in[iop]); + + /* + * If there's just one operand and no output parameter, + * first try remapping the axes to the output to return + * a view instead of a copy. + */ + if (iop == 0 && nop == 1 && out == NULL) { + ret = NULL; + + if (!get_single_op_view(op_in[iop], iop, labels, + ndim_output, output_labels, + &ret)) { + return NULL; + } + + if (ret != NULL) { + return ret; + } + } + + /* + * Check whether any dimensions need to be combined + * + * The char type may be either signed or unsigned, we + * need it to be signed here. + */ + combine = 0; + for (idim = 0; idim < ndim; ++idim) { + if ((signed char)labels[idim] < 0) { + combine = 1; + } + } + + /* If any dimensions are combined, create a view which combines them */ + if (combine) { + op[iop] = get_combined_dims_view(op_in[iop], iop, labels); + if (op[iop] == NULL) { + goto fail; + } + } + /* No combining needed */ + else { + Py_INCREF(op_in[iop]); + op[iop] = op_in[iop]; + } + } + + /* Set the output op */ + op[nop] = out; + + /* + * Set up the labels for the iterator (output + combined labels). + * Can just share the output_labels memory, because iter_labels + * is output_labels with some more labels appended. + */ + iter_labels = output_labels; + ndim_iter = ndim_output; + for (label = min_label; label <= max_label; ++label) { + if (label_counts[label] > 0 && + memchr(output_labels, label, ndim_output) == NULL) { + if (ndim_iter >= NPY_MAXDIMS) { + PyErr_SetString(PyExc_ValueError, + "too many subscripts in einsum"); + goto fail; + } + iter_labels[ndim_iter++] = label; + } + } + + /* Set up the op_axes for the iterator */ + for (iop = 0; iop < nop; ++iop) { + op_axes[iop] = op_axes_arrays[iop]; + + if (!prepare_op_axes(PyArray_NDIM(op[iop]), iop, op_labels[iop], + op_axes[iop], ndim_iter, iter_labels)) { + goto fail; + } + } + + /* Set up the op_dtypes if dtype was provided */ + if (dtype == NULL) { + op_dtypes = NULL; + } + else { + op_dtypes = op_dtypes_array; + for (iop = 0; iop <= nop; ++iop) { + op_dtypes[iop] = dtype; + } + } + + /* Set the op_axes for the output */ + op_axes[nop] = op_axes_arrays[nop]; + for (idim = 0; idim < ndim_output; ++idim) { + op_axes[nop][idim] = idim; + } + for (idim = ndim_output; idim < ndim_iter; ++idim) { + op_axes[nop][idim] = -1; + } + + /* Set the iterator per-op flags */ + + for (iop = 0; iop < nop; ++iop) { + op_flags[iop] = NPY_ITER_READONLY| + NPY_ITER_NBO| + NPY_ITER_ALIGNED; + } + op_flags[nop] = NPY_ITER_READWRITE| + NPY_ITER_NBO| + NPY_ITER_ALIGNED| + NPY_ITER_ALLOCATE| + NPY_ITER_NO_BROADCAST; + + /* Allocate the iterator */ + iter = NpyIter_AdvancedNew(nop+1, op, NPY_ITER_EXTERNAL_LOOP| + ((dtype != NULL) ? 0 : NPY_ITER_COMMON_DTYPE)| + NPY_ITER_BUFFERED| + NPY_ITER_DELAY_BUFALLOC| + NPY_ITER_GROWINNER| + NPY_ITER_REDUCE_OK| + NPY_ITER_REFS_OK| + NPY_ITER_ZEROSIZE_OK, + order, casting, + op_flags, op_dtypes, + ndim_iter, op_axes, NULL, 0); + + if (iter == NULL) { + goto fail; + } + + /* Initialize the output to all zeros and reset the iterator */ + ret = NpyIter_GetOperandArray(iter)[nop]; + Py_INCREF(ret); + PyArray_AssignZero(ret, NULL); + + + /***************************/ + /* + * Acceleration for some specific loop structures. Note + * that with axis coalescing, inputs with more dimensions can + * be reduced to fit into these patterns. + */ + if (!NpyIter_RequiresBuffering(iter)) { + int ndim = NpyIter_GetNDim(iter); + switch (nop) { + case 1: + if (ndim == 2) { + if (unbuffered_loop_nop1_ndim2(iter) < 0) { + Py_DECREF(ret); + ret = NULL; + goto fail; + } + goto finish; + } + else if (ndim == 3) { + if (unbuffered_loop_nop1_ndim3(iter) < 0) { + Py_DECREF(ret); + ret = NULL; + goto fail; + } + goto finish; + } + break; + case 2: + if (ndim == 2) { + if (unbuffered_loop_nop2_ndim2(iter) < 0) { + Py_DECREF(ret); + ret = NULL; + goto fail; + } + goto finish; + } + else if (ndim == 3) { + if (unbuffered_loop_nop2_ndim3(iter) < 0) { + Py_DECREF(ret); + ret = NULL; + goto fail; + } + goto finish; + } + break; + } + } + /***************************/ + + if (NpyIter_Reset(iter, NULL) != NPY_SUCCEED) { + Py_DECREF(ret); + goto fail; + } + + /* + * Get an inner loop function, specializing it based on + * the strides that are fixed for the whole loop. + */ + NpyIter_GetInnerFixedStrideArray(iter, fixed_strides); + sop = get_sum_of_products_function(nop, + NpyIter_GetDescrArray(iter)[0]->type_num, + NpyIter_GetDescrArray(iter)[0]->elsize, + fixed_strides); + +#if NPY_EINSUM_DBG_TRACING + NpyIter_DebugPrint(iter); +#endif + + /* Finally, the main loop */ + if (sop == NULL) { + PyErr_SetString(PyExc_TypeError, + "invalid data type for einsum"); + Py_DECREF(ret); + ret = NULL; + } + else if (NpyIter_GetIterSize(iter) != 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *stride; + npy_intp *countptr; + NPY_BEGIN_THREADS_DEF; + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + Py_DECREF(ret); + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + stride = NpyIter_GetInnerStrideArray(iter); + countptr = NpyIter_GetInnerLoopSizePtr(iter); + + NPY_BEGIN_THREADS_NDITER(iter); + NPY_EINSUM_DBG_PRINT("Einsum loop\n"); + do { + sop(nop, dataptr, stride, *countptr); + } while(iternext(iter)); + NPY_END_THREADS; + + /* If the API was needed, it may have thrown an error */ + if (NpyIter_IterationNeedsAPI(iter) && PyErr_Occurred()) { + Py_DECREF(ret); + ret = NULL; + } + } + +finish: + NpyIter_Deallocate(iter); + for (iop = 0; iop < nop; ++iop) { + Py_DECREF(op[iop]); + } + + return ret; + +fail: + for (iop = 0; iop < nop; ++iop) { + Py_XDECREF(op[iop]); + } + + return NULL; +} diff --git a/numpy/core/src/multiarray/flagsobject.c b/numpy/core/src/multiarray/flagsobject.c new file mode 100644 index 0000000..8072cff --- /dev/null +++ b/numpy/core/src/multiarray/flagsobject.c @@ -0,0 +1,788 @@ +/* Array Flags Object */ + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "common.h" + +static void +_UpdateContiguousFlags(PyArrayObject *ap); + +/*NUMPY_API + * + * Get New ArrayFlagsObject + */ +NPY_NO_EXPORT PyObject * +PyArray_NewFlagsObject(PyObject *obj) +{ + PyObject *flagobj; + int flags; + + if (obj == NULL) { + flags = NPY_ARRAY_C_CONTIGUOUS | + NPY_ARRAY_OWNDATA | + NPY_ARRAY_F_CONTIGUOUS | + NPY_ARRAY_ALIGNED; + } + else { + if (!PyArray_Check(obj)) { + PyErr_SetString(PyExc_ValueError, + "Need a NumPy array to create a flags object"); + return NULL; + } + + flags = PyArray_FLAGS((PyArrayObject *)obj); + } + flagobj = PyArrayFlags_Type.tp_alloc(&PyArrayFlags_Type, 0); + if (flagobj == NULL) { + return NULL; + } + Py_XINCREF(obj); + ((PyArrayFlagsObject *)flagobj)->arr = obj; + ((PyArrayFlagsObject *)flagobj)->flags = flags; + return flagobj; +} + +/*NUMPY_API + * Update Several Flags at once. + */ +NPY_NO_EXPORT void +PyArray_UpdateFlags(PyArrayObject *ret, int flagmask) +{ + /* Always update both, as its not trivial to guess one from the other */ + if (flagmask & (NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_C_CONTIGUOUS)) { + _UpdateContiguousFlags(ret); + } + if (flagmask & NPY_ARRAY_ALIGNED) { + if (_IsAligned(ret)) { + PyArray_ENABLEFLAGS(ret, NPY_ARRAY_ALIGNED); + } + else { + PyArray_CLEARFLAGS(ret, NPY_ARRAY_ALIGNED); + } + } + /* + * This is not checked by default WRITEABLE is not + * part of UPDATE_ALL + */ + if (flagmask & NPY_ARRAY_WRITEABLE) { + if (_IsWriteable(ret)) { + PyArray_ENABLEFLAGS(ret, NPY_ARRAY_WRITEABLE); + } + else { + PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEABLE); + } + } + return; +} + +/* + * Check whether the given array is stored contiguously + * in memory. And update the passed in ap flags apropriately. + * + * The traditional rule is that for an array to be flagged as C contiguous, + * the following must hold: + * + * strides[-1] == itemsize + * strides[i] == shape[i+1] * strides[i + 1] + * + * And for an array to be flagged as F contiguous, the obvious reversal: + * + * strides[0] == itemsize + * strides[i] == shape[i - 1] * strides[i - 1] + * + * According to these rules, a 0- or 1-dimensional array is either both + * C- and F-contiguous, or neither; and an array with 2+ dimensions + * can be C- or F- contiguous, or neither, but not both. Though there + * there are exceptions for arrays with zero or one item, in the first + * case the check is relaxed up to and including the first dimension + * with shape[i] == 0. In the second case `strides == itemsize` will + * can be true for all dimensions and both flags are set. + * + * When NPY_RELAXED_STRIDES_CHECKING is set, we use a more accurate + * definition of C- and F-contiguity, in which all 0-sized arrays are + * contiguous (regardless of dimensionality), and if shape[i] == 1 + * then we ignore strides[i] (since it has no affect on memory layout). + * With these new rules, it is possible for e.g. a 10x1 array to be both + * C- and F-contiguous -- but, they break downstream code which assumes + * that for contiguous arrays strides[-1] (resp. strides[0]) always + * contains the itemsize. + */ +static void +_UpdateContiguousFlags(PyArrayObject *ap) +{ + npy_intp sd; + npy_intp dim; + int i; + npy_bool is_c_contig = 1; + + sd = PyArray_ITEMSIZE(ap); + for (i = PyArray_NDIM(ap) - 1; i >= 0; --i) { + dim = PyArray_DIMS(ap)[i]; +#if NPY_RELAXED_STRIDES_CHECKING + /* contiguous by definition */ + if (dim == 0) { + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS); + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); + return; + } + if (dim != 1) { + if (PyArray_STRIDES(ap)[i] != sd) { + is_c_contig = 0; + } + sd *= dim; + } +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + if (PyArray_STRIDES(ap)[i] != sd) { + is_c_contig = 0; + break; + } + /* contiguous, if it got this far */ + if (dim == 0) { + break; + } + sd *= dim; +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ + } + if (is_c_contig) { + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS); + } + else { + PyArray_CLEARFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS); + } + + /* check if fortran contiguous */ + sd = PyArray_ITEMSIZE(ap); + for (i = 0; i < PyArray_NDIM(ap); ++i) { + dim = PyArray_DIMS(ap)[i]; +#if NPY_RELAXED_STRIDES_CHECKING + if (dim != 1) { + if (PyArray_STRIDES(ap)[i] != sd) { + PyArray_CLEARFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); + return; + } + sd *= dim; + } +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + if (PyArray_STRIDES(ap)[i] != sd) { + PyArray_CLEARFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); + return; + } + if (dim == 0) { + break; + } + sd *= dim; +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ + } + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); + return; +} + +static void +arrayflags_dealloc(PyArrayFlagsObject *self) +{ + Py_XDECREF(self->arr); + Py_TYPE(self)->tp_free((PyObject *)self); +} + + +#define _define_get(UPPER, lower) \ + static PyObject * \ + arrayflags_ ## lower ## _get(PyArrayFlagsObject *self) \ + { \ + PyObject *item; \ + item = ((self->flags & (UPPER)) == (UPPER)) ? Py_True : Py_False; \ + Py_INCREF(item); \ + return item; \ + } + +_define_get(NPY_ARRAY_C_CONTIGUOUS, contiguous) +_define_get(NPY_ARRAY_F_CONTIGUOUS, fortran) +_define_get(NPY_ARRAY_WRITEBACKIFCOPY, writebackifcopy) +_define_get(NPY_ARRAY_OWNDATA, owndata) +_define_get(NPY_ARRAY_ALIGNED, aligned) +_define_get(NPY_ARRAY_WRITEABLE, writeable) +_define_get(NPY_ARRAY_ALIGNED| + NPY_ARRAY_WRITEABLE, behaved) +_define_get(NPY_ARRAY_ALIGNED| + NPY_ARRAY_WRITEABLE| + NPY_ARRAY_C_CONTIGUOUS, carray) + +static PyObject * +arrayflags_updateifcopy_get(PyArrayFlagsObject *self) +{ + PyObject *item; + /* 2017-Nov-10 1.14 */ + if(DEPRECATE("UPDATEIFCOPY deprecated, use WRITEBACKIFCOPY instead") < 0) { + return NULL; + } + if ((self->flags & (NPY_ARRAY_UPDATEIFCOPY)) == (NPY_ARRAY_UPDATEIFCOPY)) { + item = Py_True; + } + else { + item = Py_False; + } + Py_INCREF(item); + return item; +} + + +static PyObject * +arrayflags_forc_get(PyArrayFlagsObject *self) +{ + PyObject *item; + + if (((self->flags & NPY_ARRAY_F_CONTIGUOUS) == NPY_ARRAY_F_CONTIGUOUS) || + ((self->flags & NPY_ARRAY_C_CONTIGUOUS) == NPY_ARRAY_C_CONTIGUOUS)) { + item = Py_True; + } + else { + item = Py_False; + } + Py_INCREF(item); + return item; +} + +static PyObject * +arrayflags_fnc_get(PyArrayFlagsObject *self) +{ + PyObject *item; + + if (((self->flags & NPY_ARRAY_F_CONTIGUOUS) == NPY_ARRAY_F_CONTIGUOUS) && + !((self->flags & NPY_ARRAY_C_CONTIGUOUS) == NPY_ARRAY_C_CONTIGUOUS)) { + item = Py_True; + } + else { + item = Py_False; + } + Py_INCREF(item); + return item; +} + +static PyObject * +arrayflags_farray_get(PyArrayFlagsObject *self) +{ + PyObject *item; + + if (((self->flags & (NPY_ARRAY_ALIGNED| + NPY_ARRAY_WRITEABLE| + NPY_ARRAY_F_CONTIGUOUS)) != 0) && + !((self->flags & NPY_ARRAY_C_CONTIGUOUS) != 0)) { + item = Py_True; + } + else { + item = Py_False; + } + Py_INCREF(item); + return item; +} + +static PyObject * +arrayflags_num_get(PyArrayFlagsObject *self) +{ + return PyInt_FromLong(self->flags); +} + +/* relies on setflags order being write, align, uic */ +static int +arrayflags_updateifcopy_set(PyArrayFlagsObject *self, PyObject *obj) +{ + PyObject *res; + + if (obj == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete flags updateifcopy attribute"); + return -1; + } + if (self->arr == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot set flags on array scalars."); + return -1; + } + /* 2017-Nov-10 1.14 */ + if(DEPRECATE("UPDATEIFCOPY deprecated, use WRITEBACKIFCOPY instead") < 0) { + return -1; + } + res = PyObject_CallMethod(self->arr, "setflags", "OOO", Py_None, Py_None, + (PyObject_IsTrue(obj) ? Py_True : Py_False)); + if (res == NULL) { + return -1; + } + Py_DECREF(res); + return 0; +} + +/* relies on setflags order being write, align, uic */ +static int +arrayflags_writebackifcopy_set(PyArrayFlagsObject *self, PyObject *obj) +{ + PyObject *res; + + if (obj == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete flags writebackifcopy attribute"); + return -1; + } + if (self->arr == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot set flags on array scalars."); + return -1; + } + res = PyObject_CallMethod(self->arr, "setflags", "OOO", Py_None, Py_None, + (PyObject_IsTrue(obj) ? Py_True : Py_False)); + if (res == NULL) { + return -1; + } + Py_DECREF(res); + return 0; +} + +static int +arrayflags_aligned_set(PyArrayFlagsObject *self, PyObject *obj) +{ + PyObject *res; + + if (obj == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete flags aligned attribute"); + return -1; + } + if (self->arr == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot set flags on array scalars."); + return -1; + } + res = PyObject_CallMethod(self->arr, "setflags", "OOO", Py_None, + (PyObject_IsTrue(obj) ? Py_True : Py_False), + Py_None); + if (res == NULL) { + return -1; + } + Py_DECREF(res); + return 0; +} + +static int +arrayflags_writeable_set(PyArrayFlagsObject *self, PyObject *obj) +{ + PyObject *res; + + if (obj == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete flags writeable attribute"); + return -1; + } + if (self->arr == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot set flags on array scalars."); + return -1; + } + res = PyObject_CallMethod(self->arr, "setflags", "OOO", + (PyObject_IsTrue(obj) ? Py_True : Py_False), + Py_None, Py_None); + if (res == NULL) { + return -1; + } + Py_DECREF(res); + return 0; +} + + +static PyGetSetDef arrayflags_getsets[] = { + {"contiguous", + (getter)arrayflags_contiguous_get, + NULL, + NULL, NULL}, + {"c_contiguous", + (getter)arrayflags_contiguous_get, + NULL, + NULL, NULL}, + {"f_contiguous", + (getter)arrayflags_fortran_get, + NULL, + NULL, NULL}, + {"fortran", + (getter)arrayflags_fortran_get, + NULL, + NULL, NULL}, + {"updateifcopy", + (getter)arrayflags_updateifcopy_get, + (setter)arrayflags_updateifcopy_set, + NULL, NULL}, + {"writebackifcopy", + (getter)arrayflags_writebackifcopy_get, + (setter)arrayflags_writebackifcopy_set, + NULL, NULL}, + {"owndata", + (getter)arrayflags_owndata_get, + NULL, + NULL, NULL}, + {"aligned", + (getter)arrayflags_aligned_get, + (setter)arrayflags_aligned_set, + NULL, NULL}, + {"writeable", + (getter)arrayflags_writeable_get, + (setter)arrayflags_writeable_set, + NULL, NULL}, + {"fnc", + (getter)arrayflags_fnc_get, + NULL, + NULL, NULL}, + {"forc", + (getter)arrayflags_forc_get, + NULL, + NULL, NULL}, + {"behaved", + (getter)arrayflags_behaved_get, + NULL, + NULL, NULL}, + {"carray", + (getter)arrayflags_carray_get, + NULL, + NULL, NULL}, + {"farray", + (getter)arrayflags_farray_get, + NULL, + NULL, NULL}, + {"num", + (getter)arrayflags_num_get, + NULL, + NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL}, +}; + +static PyObject * +arrayflags_getitem(PyArrayFlagsObject *self, PyObject *ind) +{ + char *key = NULL; + char buf[16]; + int n; + if (PyUnicode_Check(ind)) { + PyObject *tmp_str; + tmp_str = PyUnicode_AsASCIIString(ind); + if (tmp_str == NULL) { + return NULL; + } + key = PyBytes_AS_STRING(tmp_str); + n = PyBytes_GET_SIZE(tmp_str); + if (n > 16) { + Py_DECREF(tmp_str); + goto fail; + } + memcpy(buf, key, n); + Py_DECREF(tmp_str); + key = buf; + } + else if (PyBytes_Check(ind)) { + key = PyBytes_AS_STRING(ind); + n = PyBytes_GET_SIZE(ind); + } + else { + goto fail; + } + switch(n) { + case 1: + switch(key[0]) { + case 'C': + return arrayflags_contiguous_get(self); + case 'F': + return arrayflags_fortran_get(self); + case 'W': + return arrayflags_writeable_get(self); + case 'B': + return arrayflags_behaved_get(self); + case 'O': + return arrayflags_owndata_get(self); + case 'A': + return arrayflags_aligned_get(self); + case 'X': + return arrayflags_writebackifcopy_get(self); + case 'U': + return arrayflags_updateifcopy_get(self); + default: + goto fail; + } + break; + case 2: + if (strncmp(key, "CA", n) == 0) { + return arrayflags_carray_get(self); + } + if (strncmp(key, "FA", n) == 0) { + return arrayflags_farray_get(self); + } + break; + case 3: + if (strncmp(key, "FNC", n) == 0) { + return arrayflags_fnc_get(self); + } + break; + case 4: + if (strncmp(key, "FORC", n) == 0) { + return arrayflags_forc_get(self); + } + break; + case 6: + if (strncmp(key, "CARRAY", n) == 0) { + return arrayflags_carray_get(self); + } + if (strncmp(key, "FARRAY", n) == 0) { + return arrayflags_farray_get(self); + } + break; + case 7: + if (strncmp(key,"FORTRAN",n) == 0) { + return arrayflags_fortran_get(self); + } + if (strncmp(key,"BEHAVED",n) == 0) { + return arrayflags_behaved_get(self); + } + if (strncmp(key,"OWNDATA",n) == 0) { + return arrayflags_owndata_get(self); + } + if (strncmp(key,"ALIGNED",n) == 0) { + return arrayflags_aligned_get(self); + } + break; + case 9: + if (strncmp(key,"WRITEABLE",n) == 0) { + return arrayflags_writeable_get(self); + } + break; + case 10: + if (strncmp(key,"CONTIGUOUS",n) == 0) { + return arrayflags_contiguous_get(self); + } + break; + case 12: + if (strncmp(key, "UPDATEIFCOPY", n) == 0) { + return arrayflags_updateifcopy_get(self); + } + if (strncmp(key, "C_CONTIGUOUS", n) == 0) { + return arrayflags_contiguous_get(self); + } + if (strncmp(key, "F_CONTIGUOUS", n) == 0) { + return arrayflags_fortran_get(self); + } + break; + case 15: + if (strncmp(key, "WRITEBACKIFCOPY", n) == 0) { + return arrayflags_writebackifcopy_get(self); + } + break; + } + + fail: + PyErr_SetString(PyExc_KeyError, "Unknown flag"); + return NULL; +} + +static int +arrayflags_setitem(PyArrayFlagsObject *self, PyObject *ind, PyObject *item) +{ + char *key; + char buf[16]; + int n; + if (PyUnicode_Check(ind)) { + PyObject *tmp_str; + tmp_str = PyUnicode_AsASCIIString(ind); + key = PyBytes_AS_STRING(tmp_str); + n = PyBytes_GET_SIZE(tmp_str); + if (n > 16) n = 16; + memcpy(buf, key, n); + Py_DECREF(tmp_str); + key = buf; + } + else if (PyBytes_Check(ind)) { + key = PyBytes_AS_STRING(ind); + n = PyBytes_GET_SIZE(ind); + } + else { + goto fail; + } + if (((n==9) && (strncmp(key, "WRITEABLE", n) == 0)) || + ((n==1) && (strncmp(key, "W", n) == 0))) { + return arrayflags_writeable_set(self, item); + } + else if (((n==7) && (strncmp(key, "ALIGNED", n) == 0)) || + ((n==1) && (strncmp(key, "A", n) == 0))) { + return arrayflags_aligned_set(self, item); + } + else if (((n==12) && (strncmp(key, "UPDATEIFCOPY", n) == 0)) || + ((n==1) && (strncmp(key, "U", n) == 0))) { + return arrayflags_updateifcopy_set(self, item); + } + else if (((n==14) && (strncmp(key, "WRITEBACKIFCOPY", n) == 0)) || + ((n==1) && (strncmp(key, "X", n) == 0))) { + return arrayflags_writebackifcopy_set(self, item); + } + + fail: + PyErr_SetString(PyExc_KeyError, "Unknown flag"); + return -1; +} + +static char * +_torf_(int flags, int val) +{ + if ((flags & val) == val) { + return "True"; + } + else { + return "False"; + } +} + +static PyObject * +arrayflags_print(PyArrayFlagsObject *self) +{ + int fl = self->flags; + + return PyUString_FromFormat( + " %s : %s\n %s : %s\n" + " %s : %s\n %s : %s\n" + " %s : %s\n %s : %s\n" + " %s : %s", + "C_CONTIGUOUS", _torf_(fl, NPY_ARRAY_C_CONTIGUOUS), + "F_CONTIGUOUS", _torf_(fl, NPY_ARRAY_F_CONTIGUOUS), + "OWNDATA", _torf_(fl, NPY_ARRAY_OWNDATA), + "WRITEABLE", _torf_(fl, NPY_ARRAY_WRITEABLE), + "ALIGNED", _torf_(fl, NPY_ARRAY_ALIGNED), + "WRITEBACKIFCOPY", _torf_(fl, NPY_ARRAY_WRITEBACKIFCOPY), + "UPDATEIFCOPY", _torf_(fl, NPY_ARRAY_UPDATEIFCOPY)); +} + +static int +arrayflags_compare(PyArrayFlagsObject *self, PyArrayFlagsObject *other) +{ + if (self->flags == other->flags) { + return 0; + } + else if (self->flags < other->flags) { + return -1; + } + else { + return 1; + } +} + + +static PyObject* +arrayflags_richcompare(PyObject *self, PyObject *other, int cmp_op) +{ + PyObject *result = Py_NotImplemented; + int cmp; + + if (cmp_op != Py_EQ && cmp_op != Py_NE) { + PyErr_SetString(PyExc_TypeError, + "undefined comparison for flag object"); + return NULL; + } + + if (PyObject_TypeCheck(other, &PyArrayFlags_Type)) { + cmp = arrayflags_compare((PyArrayFlagsObject *)self, + (PyArrayFlagsObject *)other); + + if (cmp_op == Py_EQ) { + result = (cmp == 0) ? Py_True : Py_False; + } + else if (cmp_op == Py_NE) { + result = (cmp != 0) ? Py_True : Py_False; + } + } + + Py_INCREF(result); + return result; +} + +static PyMappingMethods arrayflags_as_mapping = { + (lenfunc)NULL, /*mp_length*/ + (binaryfunc)arrayflags_getitem, /*mp_subscript*/ + (objobjargproc)arrayflags_setitem, /*mp_ass_subscript*/ +}; + + +static PyObject * +arrayflags_new(PyTypeObject *NPY_UNUSED(self), PyObject *args, PyObject *NPY_UNUSED(kwds)) +{ + PyObject *arg=NULL; + if (!PyArg_UnpackTuple(args, "flagsobj", 0, 1, &arg)) { + return NULL; + } + if ((arg != NULL) && PyArray_Check(arg)) { + return PyArray_NewFlagsObject(arg); + } + else { + return PyArray_NewFlagsObject(NULL); + } +} + +NPY_NO_EXPORT PyTypeObject PyArrayFlags_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.flagsobj", + sizeof(PyArrayFlagsObject), + 0, /* tp_itemsize */ + /* methods */ + (destructor)arrayflags_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + (cmpfunc)arrayflags_compare, /* tp_compare */ +#endif + (reprfunc)arrayflags_print, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &arrayflags_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)arrayflags_print, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + arrayflags_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + arrayflags_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + arrayflags_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c new file mode 100644 index 0000000..825363f --- /dev/null +++ b/numpy/core/src/multiarray/getset.c @@ -0,0 +1,1022 @@ +/* Array Descr Object */ + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" + +#include "npy_config.h" +#include "npy_pycompat.h" +#include "npy_import.h" + +#include "common.h" +#include "scalartypes.h" +#include "descriptor.h" +#include "getset.h" +#include "arrayobject.h" +#include "mem_overlap.h" +#include "alloc.h" + +/******************* array attribute get and set routines ******************/ + +static PyObject * +array_ndim_get(PyArrayObject *self) +{ + return PyInt_FromLong(PyArray_NDIM(self)); +} + +static PyObject * +array_flags_get(PyArrayObject *self) +{ + return PyArray_NewFlagsObject((PyObject *)self); +} + +static PyObject * +array_shape_get(PyArrayObject *self) +{ + return PyArray_IntTupleFromIntp(PyArray_NDIM(self), PyArray_DIMS(self)); +} + + +static int +array_shape_set(PyArrayObject *self, PyObject *val) +{ + int nd; + PyArrayObject *ret; + + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete array shape"); + return -1; + } + /* Assumes C-order */ + ret = (PyArrayObject *)PyArray_Reshape(self, val); + if (ret == NULL) { + return -1; + } + if (PyArray_DATA(ret) != PyArray_DATA(self)) { + Py_DECREF(ret); + PyErr_SetString(PyExc_AttributeError, + "incompatible shape for a non-contiguous "\ + "array"); + return -1; + } + + /* Free old dimensions and strides */ + npy_free_cache_dim_array(self); + nd = PyArray_NDIM(ret); + ((PyArrayObject_fields *)self)->nd = nd; + if (nd > 0) { + /* create new dimensions and strides */ + ((PyArrayObject_fields *)self)->dimensions = npy_alloc_cache_dim(3*nd); + if (PyArray_DIMS(self) == NULL) { + Py_DECREF(ret); + PyErr_SetString(PyExc_MemoryError,""); + return -1; + } + ((PyArrayObject_fields *)self)->strides = PyArray_DIMS(self) + nd; + memcpy(PyArray_DIMS(self), PyArray_DIMS(ret), nd*sizeof(npy_intp)); + memcpy(PyArray_STRIDES(self), PyArray_STRIDES(ret), nd*sizeof(npy_intp)); + } + else { + ((PyArrayObject_fields *)self)->dimensions = NULL; + ((PyArrayObject_fields *)self)->strides = NULL; + } + Py_DECREF(ret); + PyArray_UpdateFlags(self, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS); + return 0; +} + + +static PyObject * +array_strides_get(PyArrayObject *self) +{ + return PyArray_IntTupleFromIntp(PyArray_NDIM(self), PyArray_STRIDES(self)); +} + +static int +array_strides_set(PyArrayObject *self, PyObject *obj) +{ + PyArray_Dims newstrides = {NULL, 0}; + PyArrayObject *new; + npy_intp numbytes = 0; + npy_intp offset = 0; + npy_intp lower_offset = 0; + npy_intp upper_offset = 0; + Py_ssize_t buf_len; + char *buf; + + if (obj == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete array strides"); + return -1; + } + if (!PyArray_IntpConverter(obj, &newstrides) || + newstrides.ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "invalid strides"); + return -1; + } + if (newstrides.len != PyArray_NDIM(self)) { + PyErr_Format(PyExc_ValueError, "strides must be " \ + " same length as shape (%d)", PyArray_NDIM(self)); + goto fail; + } + new = self; + while(PyArray_BASE(new) && PyArray_Check(PyArray_BASE(new))) { + new = (PyArrayObject *)(PyArray_BASE(new)); + } + /* + * Get the available memory through the buffer interface on + * PyArray_BASE(new) or if that fails from the current new + */ + if (PyArray_BASE(new) && PyObject_AsReadBuffer(PyArray_BASE(new), + (const void **)&buf, + &buf_len) >= 0) { + offset = PyArray_BYTES(self) - buf; + numbytes = buf_len + offset; + } + else { + PyErr_Clear(); + offset_bounds_from_strides(PyArray_ITEMSIZE(new), PyArray_NDIM(new), + PyArray_DIMS(new), PyArray_STRIDES(new), + &lower_offset, &upper_offset); + + offset = PyArray_BYTES(self) - (PyArray_BYTES(new) + lower_offset); + numbytes = upper_offset - lower_offset; + } + + /* numbytes == 0 is special here, but the 0-size array case always works */ + if (!PyArray_CheckStrides(PyArray_ITEMSIZE(self), PyArray_NDIM(self), + numbytes, offset, + PyArray_DIMS(self), newstrides.ptr)) { + PyErr_SetString(PyExc_ValueError, "strides is not "\ + "compatible with available memory"); + goto fail; + } + memcpy(PyArray_STRIDES(self), newstrides.ptr, sizeof(npy_intp)*newstrides.len); + PyArray_UpdateFlags(self, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS | + NPY_ARRAY_ALIGNED); + npy_free_cache_dim_obj(newstrides); + return 0; + + fail: + npy_free_cache_dim_obj(newstrides); + return -1; +} + + + +static PyObject * +array_priority_get(PyArrayObject *self) +{ + if (PyArray_CheckExact(self)) { + return PyFloat_FromDouble(NPY_PRIORITY); + } + else { + return PyFloat_FromDouble(NPY_PRIORITY); + } +} + +static PyObject * +array_typestr_get(PyArrayObject *self) +{ + return arraydescr_protocol_typestr_get(PyArray_DESCR(self)); +} + +static PyObject * +array_descr_get(PyArrayObject *self) +{ + Py_INCREF(PyArray_DESCR(self)); + return (PyObject *)PyArray_DESCR(self); +} + +static PyObject * +array_protocol_descr_get(PyArrayObject *self) +{ + PyObject *res; + PyObject *dobj; + + res = arraydescr_protocol_descr_get(PyArray_DESCR(self)); + if (res) { + return res; + } + PyErr_Clear(); + + /* get default */ + dobj = PyTuple_New(2); + if (dobj == NULL) { + return NULL; + } + PyTuple_SET_ITEM(dobj, 0, PyString_FromString("")); + PyTuple_SET_ITEM(dobj, 1, array_typestr_get(self)); + res = PyList_New(1); + if (res == NULL) { + Py_DECREF(dobj); + return NULL; + } + PyList_SET_ITEM(res, 0, dobj); + return res; +} + +static PyObject * +array_protocol_strides_get(PyArrayObject *self) +{ + if (PyArray_ISCONTIGUOUS(self)) { + Py_RETURN_NONE; + } + return PyArray_IntTupleFromIntp(PyArray_NDIM(self), PyArray_STRIDES(self)); +} + + + +static PyObject * +array_dataptr_get(PyArrayObject *self) +{ + return Py_BuildValue("NO", + PyLong_FromVoidPtr(PyArray_DATA(self)), + (PyArray_FLAGS(self) & NPY_ARRAY_WRITEABLE ? Py_False : + Py_True)); +} + +static PyObject * +array_ctypes_get(PyArrayObject *self) +{ + PyObject *_numpy_internal; + PyObject *ret; + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + ret = PyObject_CallMethod(_numpy_internal, "_ctypes", "ON", self, + PyLong_FromVoidPtr(PyArray_DATA(self))); + Py_DECREF(_numpy_internal); + return ret; +} + +static PyObject * +array_interface_get(PyArrayObject *self) +{ + PyObject *dict; + PyObject *obj; + + dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + + if (array_might_be_written(self) < 0) { + Py_DECREF(dict); + return NULL; + } + + /* dataptr */ + obj = array_dataptr_get(self); + PyDict_SetItemString(dict, "data", obj); + Py_DECREF(obj); + + obj = array_protocol_strides_get(self); + PyDict_SetItemString(dict, "strides", obj); + Py_DECREF(obj); + + obj = array_protocol_descr_get(self); + PyDict_SetItemString(dict, "descr", obj); + Py_DECREF(obj); + + obj = arraydescr_protocol_typestr_get(PyArray_DESCR(self)); + PyDict_SetItemString(dict, "typestr", obj); + Py_DECREF(obj); + + obj = array_shape_get(self); + PyDict_SetItemString(dict, "shape", obj); + Py_DECREF(obj); + + obj = PyInt_FromLong(3); + PyDict_SetItemString(dict, "version", obj); + Py_DECREF(obj); + + return dict; +} + +static PyObject * +array_data_get(PyArrayObject *self) +{ +#if defined(NPY_PY3K) + return PyMemoryView_FromObject((PyObject *)self); +#else + npy_intp nbytes; + if (!(PyArray_ISONESEGMENT(self))) { + PyErr_SetString(PyExc_AttributeError, "cannot get single-"\ + "segment buffer for discontiguous array"); + return NULL; + } + nbytes = PyArray_NBYTES(self); + if (PyArray_ISWRITEABLE(self)) { + return PyBuffer_FromReadWriteObject((PyObject *)self, 0, (Py_ssize_t) nbytes); + } + else { + return PyBuffer_FromObject((PyObject *)self, 0, (Py_ssize_t) nbytes); + } +#endif +} + +static int +array_data_set(PyArrayObject *self, PyObject *op) +{ + void *buf; + Py_ssize_t buf_len; + int writeable=1; + + /* 2016-19-02, 1.12 */ + int ret = DEPRECATE("Assigning the 'data' attribute is an " + "inherently unsafe operation and will " + "be removed in the future."); + if (ret < 0) { + return -1; + } + + if (op == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete array data"); + return -1; + } + if (PyObject_AsWriteBuffer(op, &buf, &buf_len) < 0) { + writeable = 0; + if (PyObject_AsReadBuffer(op, (const void **)&buf, &buf_len) < 0) { + PyErr_SetString(PyExc_AttributeError, + "object does not have single-segment " \ + "buffer interface"); + return -1; + } + } + if (!PyArray_ISONESEGMENT(self)) { + PyErr_SetString(PyExc_AttributeError, "cannot set single-" \ + "segment buffer for discontiguous array"); + return -1; + } + if (PyArray_NBYTES(self) > buf_len) { + PyErr_SetString(PyExc_AttributeError, "not enough data for array"); + return -1; + } + if (PyArray_FLAGS(self) & NPY_ARRAY_OWNDATA) { + PyArray_XDECREF(self); + PyDataMem_FREE(PyArray_DATA(self)); + } + if (PyArray_BASE(self)) { + if ((PyArray_FLAGS(self) & NPY_ARRAY_WRITEBACKIFCOPY) || + (PyArray_FLAGS(self) & NPY_ARRAY_UPDATEIFCOPY)) { + PyArray_ENABLEFLAGS((PyArrayObject *)PyArray_BASE(self), + NPY_ARRAY_WRITEABLE); + PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY); + PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY); + } + Py_DECREF(PyArray_BASE(self)); + ((PyArrayObject_fields *)self)->base = NULL; + } + Py_INCREF(op); + if (PyArray_SetBaseObject(self, op) < 0) { + return -1; + } + ((PyArrayObject_fields *)self)->data = buf; + ((PyArrayObject_fields *)self)->flags = NPY_ARRAY_CARRAY; + if (!writeable) { + PyArray_CLEARFLAGS(self, ~NPY_ARRAY_WRITEABLE); + } + return 0; +} + + +static PyObject * +array_itemsize_get(PyArrayObject *self) +{ + return PyInt_FromLong((long) PyArray_DESCR(self)->elsize); +} + +static PyObject * +array_size_get(PyArrayObject *self) +{ + npy_intp size=PyArray_SIZE(self); +#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG + return PyInt_FromLong((long) size); +#else + if (size > NPY_MAX_LONG || size < NPY_MIN_LONG) { + return PyLong_FromLongLong(size); + } + else { + return PyInt_FromLong((long) size); + } +#endif +} + +static PyObject * +array_nbytes_get(PyArrayObject *self) +{ + npy_intp nbytes = PyArray_NBYTES(self); +#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG + return PyInt_FromLong((long) nbytes); +#else + if (nbytes > NPY_MAX_LONG || nbytes < NPY_MIN_LONG) { + return PyLong_FromLongLong(nbytes); + } + else { + return PyInt_FromLong((long) nbytes); + } +#endif +} + + +/* + * If the type is changed. + * Also needing change: strides, itemsize + * + * Either itemsize is exactly the same or the array is single-segment + * (contiguous or fortran) with compatible dimensions The shape and strides + * will be adjusted in that case as well. + */ +static int +array_descr_set(PyArrayObject *self, PyObject *arg) +{ + PyArray_Descr *newtype = NULL; + + if (arg == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete array dtype"); + return -1; + } + + if (!(PyArray_DescrConverter(arg, &newtype)) || + newtype == NULL) { + PyErr_SetString(PyExc_TypeError, + "invalid data-type for array"); + return -1; + } + + /* check that we are not reinterpreting memory containing Objects. */ + if (_may_have_objects(PyArray_DESCR(self)) || _may_have_objects(newtype)) { + static PyObject *checkfunc = NULL; + PyObject *safe; + + npy_cache_import("numpy.core._internal", "_view_is_safe", &checkfunc); + if (checkfunc == NULL) { + goto fail; + } + + safe = PyObject_CallFunction(checkfunc, "OO", + PyArray_DESCR(self), newtype); + if (safe == NULL) { + goto fail; + } + Py_DECREF(safe); + } + + /* + * Viewing as an unsized void implies a void dtype matching the size of the + * current dtype. + */ + if (newtype->type_num == NPY_VOID && + PyDataType_ISUNSIZED(newtype) && + newtype->elsize != PyArray_DESCR(self)->elsize) { + PyArray_DESCR_REPLACE(newtype); + if (newtype == NULL) { + return -1; + } + newtype->elsize = PyArray_DESCR(self)->elsize; + } + + /* Changing the size of the dtype results in a shape change */ + if (newtype->elsize != PyArray_DESCR(self)->elsize) { + int axis; + npy_intp newdim; + + /* forbidden cases */ + if (PyArray_NDIM(self) == 0) { + PyErr_SetString(PyExc_ValueError, + "Changing the dtype of a 0d array is only supported " + "if the itemsize is unchanged"); + goto fail; + } + else if (PyDataType_HASSUBARRAY(newtype)) { + PyErr_SetString(PyExc_ValueError, + "Changing the dtype to a subarray type is only supported " + "if the total itemsize is unchanged"); + goto fail; + } + + /* determine which axis to resize */ + if (PyArray_IS_C_CONTIGUOUS(self)) { + axis = PyArray_NDIM(self) - 1; + } + else if (PyArray_IS_F_CONTIGUOUS(self)) { + /* 2015-11-27 1.11.0, gh-6747 */ + if (DEPRECATE( + "Changing the shape of an F-contiguous array by " + "descriptor assignment is deprecated. To maintain the " + "Fortran contiguity of a multidimensional Fortran " + "array, use 'a.T.view(...).T' instead") < 0) { + goto fail; + } + axis = 0; + } + else { + /* Don't mention the deprecated F-contiguous support */ + PyErr_SetString(PyExc_ValueError, + "To change to a dtype of a different size, the array must " + "be C-contiguous"); + goto fail; + } + + if (newtype->elsize < PyArray_DESCR(self)->elsize) { + /* if it is compatible, increase the size of the relevant axis */ + if (newtype->elsize == 0 || + PyArray_DESCR(self)->elsize % newtype->elsize != 0) { + PyErr_SetString(PyExc_ValueError, + "When changing to a smaller dtype, its size must be a " + "divisor of the size of original dtype"); + goto fail; + } + newdim = PyArray_DESCR(self)->elsize / newtype->elsize; + PyArray_DIMS(self)[axis] *= newdim; + PyArray_STRIDES(self)[axis] = newtype->elsize; + } + else if (newtype->elsize > PyArray_DESCR(self)->elsize) { + /* if it is compatible, decrease the size of the relevant axis */ + newdim = PyArray_DIMS(self)[axis] * PyArray_DESCR(self)->elsize; + if ((newdim % newtype->elsize) != 0) { + PyErr_SetString(PyExc_ValueError, + "When changing to a larger dtype, its size must be a " + "divisor of the total size in bytes of the last axis " + "of the array."); + goto fail; + } + PyArray_DIMS(self)[axis] = newdim / newtype->elsize; + PyArray_STRIDES(self)[axis] = newtype->elsize; + } + } + + /* Viewing as a subarray increases the number of dimensions */ + if (PyDataType_HASSUBARRAY(newtype)) { + /* + * create new array object from data and update + * dimensions, strides and descr from it + */ + PyArrayObject *temp; + /* + * We would decref newtype here. + * temp will steal a reference to it + */ + temp = (PyArrayObject *) + PyArray_NewFromDescr(&PyArray_Type, newtype, PyArray_NDIM(self), + PyArray_DIMS(self), PyArray_STRIDES(self), + PyArray_DATA(self), PyArray_FLAGS(self), NULL); + if (temp == NULL) { + return -1; + } + npy_free_cache_dim_array(self); + ((PyArrayObject_fields *)self)->dimensions = PyArray_DIMS(temp); + ((PyArrayObject_fields *)self)->nd = PyArray_NDIM(temp); + ((PyArrayObject_fields *)self)->strides = PyArray_STRIDES(temp); + newtype = PyArray_DESCR(temp); + Py_INCREF(PyArray_DESCR(temp)); + /* Fool deallocator not to delete these*/ + ((PyArrayObject_fields *)temp)->nd = 0; + ((PyArrayObject_fields *)temp)->dimensions = NULL; + Py_DECREF(temp); + } + + Py_DECREF(PyArray_DESCR(self)); + ((PyArrayObject_fields *)self)->descr = newtype; + PyArray_UpdateFlags(self, NPY_ARRAY_UPDATE_ALL); + return 0; + + fail: + Py_DECREF(newtype); + return -1; +} + +static PyObject * +array_struct_get(PyArrayObject *self) +{ + PyArrayInterface *inter; + PyObject *ret; + + if (PyArray_ISWRITEABLE(self)) { + if (array_might_be_written(self) < 0) { + return NULL; + } + } + inter = (PyArrayInterface *)PyArray_malloc(sizeof(PyArrayInterface)); + if (inter==NULL) { + return PyErr_NoMemory(); + } + inter->two = 2; + inter->nd = PyArray_NDIM(self); + inter->typekind = PyArray_DESCR(self)->kind; + inter->itemsize = PyArray_DESCR(self)->elsize; + inter->flags = PyArray_FLAGS(self); + /* reset unused flags */ + inter->flags &= ~(NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_UPDATEIFCOPY |NPY_ARRAY_OWNDATA); + if (PyArray_ISNOTSWAPPED(self)) inter->flags |= NPY_ARRAY_NOTSWAPPED; + /* + * Copy shape and strides over since these can be reset + *when the array is "reshaped". + */ + if (PyArray_NDIM(self) > 0) { + inter->shape = (npy_intp *)PyArray_malloc(2*sizeof(npy_intp)*PyArray_NDIM(self)); + if (inter->shape == NULL) { + PyArray_free(inter); + return PyErr_NoMemory(); + } + inter->strides = inter->shape + PyArray_NDIM(self); + memcpy(inter->shape, PyArray_DIMS(self), sizeof(npy_intp)*PyArray_NDIM(self)); + memcpy(inter->strides, PyArray_STRIDES(self), sizeof(npy_intp)*PyArray_NDIM(self)); + } + else { + inter->shape = NULL; + inter->strides = NULL; + } + inter->data = PyArray_DATA(self); + if (PyDataType_HASFIELDS(PyArray_DESCR(self))) { + inter->descr = arraydescr_protocol_descr_get(PyArray_DESCR(self)); + if (inter->descr == NULL) { + PyErr_Clear(); + } + else { + inter->flags &= NPY_ARR_HAS_DESCR; + } + } + else { + inter->descr = NULL; + } + Py_INCREF(self); + ret = NpyCapsule_FromVoidPtrAndDesc(inter, self, gentype_struct_free); + return ret; +} + +static PyObject * +array_base_get(PyArrayObject *self) +{ + if (PyArray_BASE(self) == NULL) { + Py_RETURN_NONE; + } + else { + Py_INCREF(PyArray_BASE(self)); + return PyArray_BASE(self); + } +} + +/* + * Create a view of a complex array with an equivalent data-type + * except it is real instead of complex. + */ +static PyArrayObject * +_get_part(PyArrayObject *self, int imag) +{ + int float_type_num; + PyArray_Descr *type; + PyArrayObject *ret; + int offset; + + switch (PyArray_DESCR(self)->type_num) { + case NPY_CFLOAT: + float_type_num = NPY_FLOAT; + break; + case NPY_CDOUBLE: + float_type_num = NPY_DOUBLE; + break; + case NPY_CLONGDOUBLE: + float_type_num = NPY_LONGDOUBLE; + break; + default: + PyErr_Format(PyExc_ValueError, + "Cannot convert complex type number %d to float", + PyArray_DESCR(self)->type_num); + return NULL; + + } + type = PyArray_DescrFromType(float_type_num); + + offset = (imag ? type->elsize : 0); + + if (!PyArray_ISNBO(PyArray_DESCR(self)->byteorder)) { + PyArray_Descr *new; + new = PyArray_DescrNew(type); + new->byteorder = PyArray_DESCR(self)->byteorder; + Py_DECREF(type); + type = new; + } + ret = (PyArrayObject *) + PyArray_NewFromDescr(Py_TYPE(self), + type, + PyArray_NDIM(self), + PyArray_DIMS(self), + PyArray_STRIDES(self), + PyArray_BYTES(self) + offset, + PyArray_FLAGS(self), (PyObject *)self); + if (ret == NULL) { + return NULL; + } + Py_INCREF(self); + if (PyArray_SetBaseObject(ret, (PyObject *)self) < 0) { + Py_DECREF(ret); + return NULL; + } + PyArray_CLEARFLAGS(ret, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS); + return ret; +} + +/* For Object arrays, we need to get and set the + real part of each element. + */ + +static PyObject * +array_real_get(PyArrayObject *self) +{ + PyArrayObject *ret; + + if (PyArray_ISCOMPLEX(self)) { + ret = _get_part(self, 0); + return (PyObject *)ret; + } + else { + Py_INCREF(self); + return (PyObject *)self; + } +} + + +static int +array_real_set(PyArrayObject *self, PyObject *val) +{ + PyArrayObject *ret; + PyArrayObject *new; + int retcode; + + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete array real part"); + return -1; + } + if (PyArray_ISCOMPLEX(self)) { + ret = _get_part(self, 0); + if (ret == NULL) { + return -1; + } + } + else { + Py_INCREF(self); + ret = self; + } + new = (PyArrayObject *)PyArray_FROM_O(val); + if (new == NULL) { + Py_DECREF(ret); + return -1; + } + retcode = PyArray_MoveInto(ret, new); + Py_DECREF(ret); + Py_DECREF(new); + return retcode; +} + +/* For Object arrays we need to get + and set the imaginary part of + each element +*/ + +static PyObject * +array_imag_get(PyArrayObject *self) +{ + PyArrayObject *ret; + + if (PyArray_ISCOMPLEX(self)) { + ret = _get_part(self, 1); + } + else { + Py_INCREF(PyArray_DESCR(self)); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self), + PyArray_DESCR(self), + PyArray_NDIM(self), + PyArray_DIMS(self), + NULL, NULL, + PyArray_ISFORTRAN(self), + (PyObject *)self); + if (ret == NULL) { + return NULL; + } + if (_zerofill(ret) < 0) { + return NULL; + } + PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEABLE); + } + return (PyObject *) ret; +} + +static int +array_imag_set(PyArrayObject *self, PyObject *val) +{ + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete array imaginary part"); + return -1; + } + if (PyArray_ISCOMPLEX(self)) { + PyArrayObject *ret; + PyArrayObject *new; + int retcode; + + ret = _get_part(self, 1); + if (ret == NULL) { + return -1; + } + new = (PyArrayObject *)PyArray_FROM_O(val); + if (new == NULL) { + Py_DECREF(ret); + return -1; + } + retcode = PyArray_MoveInto(ret, new); + Py_DECREF(ret); + Py_DECREF(new); + return retcode; + } + else { + PyErr_SetString(PyExc_TypeError, + "array does not have imaginary part to set"); + return -1; + } +} + +static PyObject * +array_flat_get(PyArrayObject *self) +{ + return PyArray_IterNew((PyObject *)self); +} + +static int +array_flat_set(PyArrayObject *self, PyObject *val) +{ + PyArrayObject *arr = NULL; + int retval = -1; + PyArrayIterObject *selfit = NULL, *arrit = NULL; + PyArray_Descr *typecode; + int swap; + PyArray_CopySwapFunc *copyswap; + + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete array flat iterator"); + return -1; + } + if (PyArray_FailUnlessWriteable(self, "array") < 0) return -1; + typecode = PyArray_DESCR(self); + Py_INCREF(typecode); + arr = (PyArrayObject *)PyArray_FromAny(val, typecode, + 0, 0, NPY_ARRAY_FORCECAST | PyArray_FORTRAN_IF(self), NULL); + if (arr == NULL) { + return -1; + } + arrit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arr); + if (arrit == NULL) { + goto exit; + } + selfit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self); + if (selfit == NULL) { + goto exit; + } + if (arrit->size == 0) { + retval = 0; + goto exit; + } + swap = PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(arr); + copyswap = PyArray_DESCR(self)->f->copyswap; + if (PyDataType_REFCHK(PyArray_DESCR(self))) { + while (selfit->index < selfit->size) { + PyArray_Item_XDECREF(selfit->dataptr, PyArray_DESCR(self)); + PyArray_Item_INCREF(arrit->dataptr, PyArray_DESCR(arr)); + memmove(selfit->dataptr, arrit->dataptr, sizeof(PyObject **)); + if (swap) { + copyswap(selfit->dataptr, NULL, swap, self); + } + PyArray_ITER_NEXT(selfit); + PyArray_ITER_NEXT(arrit); + if (arrit->index == arrit->size) { + PyArray_ITER_RESET(arrit); + } + } + retval = 0; + goto exit; + } + + while(selfit->index < selfit->size) { + copyswap(selfit->dataptr, arrit->dataptr, swap, self); + PyArray_ITER_NEXT(selfit); + PyArray_ITER_NEXT(arrit); + if (arrit->index == arrit->size) { + PyArray_ITER_RESET(arrit); + } + } + retval = 0; + + exit: + Py_XDECREF(selfit); + Py_XDECREF(arrit); + Py_XDECREF(arr); + return retval; +} + +static PyObject * +array_transpose_get(PyArrayObject *self) +{ + return PyArray_Transpose(self, NULL); +} + +/* If this is None, no function call is made + --- default sub-class behavior +*/ +static PyObject * +array_finalize_get(PyArrayObject *NPY_UNUSED(self)) +{ + Py_RETURN_NONE; +} + +NPY_NO_EXPORT PyGetSetDef array_getsetlist[] = { + {"ndim", + (getter)array_ndim_get, + NULL, + NULL, NULL}, + {"flags", + (getter)array_flags_get, + NULL, + NULL, NULL}, + {"shape", + (getter)array_shape_get, + (setter)array_shape_set, + NULL, NULL}, + {"strides", + (getter)array_strides_get, + (setter)array_strides_set, + NULL, NULL}, + {"data", + (getter)array_data_get, + (setter)array_data_set, + NULL, NULL}, + {"itemsize", + (getter)array_itemsize_get, + NULL, + NULL, NULL}, + {"size", + (getter)array_size_get, + NULL, + NULL, NULL}, + {"nbytes", + (getter)array_nbytes_get, + NULL, + NULL, NULL}, + {"base", + (getter)array_base_get, + NULL, + NULL, NULL}, + {"dtype", + (getter)array_descr_get, + (setter)array_descr_set, + NULL, NULL}, + {"real", + (getter)array_real_get, + (setter)array_real_set, + NULL, NULL}, + {"imag", + (getter)array_imag_get, + (setter)array_imag_set, + NULL, NULL}, + {"flat", + (getter)array_flat_get, + (setter)array_flat_set, + NULL, NULL}, + {"ctypes", + (getter)array_ctypes_get, + NULL, + NULL, NULL}, + {"T", + (getter)array_transpose_get, + NULL, + NULL, NULL}, + {"__array_interface__", + (getter)array_interface_get, + NULL, + NULL, NULL}, + {"__array_struct__", + (getter)array_struct_get, + NULL, + NULL, NULL}, + {"__array_priority__", + (getter)array_priority_get, + NULL, + NULL, NULL}, + {"__array_finalize__", + (getter)array_finalize_get, + NULL, + NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL}, /* Sentinel */ +}; + +/****************** end of attribute get and set routines *******************/ diff --git a/numpy/core/src/multiarray/getset.h b/numpy/core/src/multiarray/getset.h new file mode 100644 index 0000000..4f1209d --- /dev/null +++ b/numpy/core/src/multiarray/getset.h @@ -0,0 +1,6 @@ +#ifndef _NPY_ARRAY_GETSET_H_ +#define _NPY_ARRAY_GETSET_H_ + +extern NPY_NO_EXPORT PyGetSetDef array_getsetlist[]; + +#endif diff --git a/numpy/core/src/multiarray/hashdescr.c b/numpy/core/src/multiarray/hashdescr.c new file mode 100644 index 0000000..8465093 --- /dev/null +++ b/numpy/core/src/multiarray/hashdescr.c @@ -0,0 +1,318 @@ +#define PY_SSIZE_T_CLEAN +#include +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "hashdescr.h" + +/* + * How does this work ? The hash is computed from a list which contains all the + * information specific to a type. The hard work is to build the list + * (_array_descr_walk). The list is built as follows: + * * If the dtype is builtin (no fields, no subarray), then the list + * contains 6 items which uniquely define one dtype (_array_descr_builtin) + * * If the dtype is a compound array, one walk on each field. For each + * field, we append title, names, offset to the final list used for + * hashing, and then append the list recursively built for each + * corresponding dtype (_array_descr_walk_fields) + * * If the dtype is a subarray, one adds the shape tuple to the list, and + * then append the list recursively built for each corresponding dtype + * (_array_descr_walk_subarray) + * + */ + +static int _is_array_descr_builtin(PyArray_Descr* descr); +static int _array_descr_walk(PyArray_Descr* descr, PyObject *l); +static int _array_descr_walk_fields(PyObject *names, PyObject* fields, PyObject* l); +static int _array_descr_builtin(PyArray_Descr* descr, PyObject *l); + +/* + * normalize endian character: always return 'I', '<' or '>' + */ +static char _normalize_byteorder(char byteorder) +{ + switch(byteorder) { + case '=': + if (PyArray_GetEndianness() == NPY_CPU_BIG) { + return '>'; + } + else { + return '<'; + } + default: + return byteorder; + } +} + +/* + * Return true if descr is a builtin type + */ +static int _is_array_descr_builtin(PyArray_Descr* descr) +{ + if (descr->fields != NULL && descr->fields != Py_None) { + return 0; + } + if (PyDataType_HASSUBARRAY(descr)) { + return 0; + } + return 1; +} + +/* + * Add to l all the items which uniquely define a builtin type + */ +static int _array_descr_builtin(PyArray_Descr* descr, PyObject *l) +{ + Py_ssize_t i; + PyObject *t, *item; + char nbyteorder = _normalize_byteorder(descr->byteorder); + + /* + * For builtin type, hash relies on : kind + byteorder + flags + + * type_num + elsize + alignment + */ + t = Py_BuildValue("(cccii)", descr->kind, nbyteorder, + descr->flags, descr->elsize, descr->alignment); + + for(i = 0; i < PyTuple_Size(t); ++i) { + item = PyTuple_GetItem(t, i); + if (item == NULL) { + PyErr_SetString(PyExc_SystemError, + "(Hash) Error while computing builting hash"); + goto clean_t; + } + PyList_Append(l, item); + } + + Py_DECREF(t); + return 0; + +clean_t: + Py_DECREF(t); + return -1; +} + +/* + * Walk inside the fields and add every item which will be used for hashing + * into the list l + * + * Return 0 on success + */ +static int _array_descr_walk_fields(PyObject *names, PyObject* fields, PyObject* l) +{ + PyObject *key, *value, *foffset, *fdescr, *ftitle; + Py_ssize_t pos = 0; + int st; + + if (!PyTuple_Check(names)) { + PyErr_SetString(PyExc_SystemError, + "(Hash) names is not a tuple ???"); + return -1; + } + if (!PyDict_Check(fields)) { + PyErr_SetString(PyExc_SystemError, + "(Hash) fields is not a dict ???"); + return -1; + } + + for (pos = 0; pos < PyTuple_GET_SIZE(names); pos++) { + /* + * For each field, add the key + descr + offset to l + */ + key = PyTuple_GET_ITEM(names, pos); + value = PyDict_GetItem(fields, key); + /* XXX: are those checks necessary ? */ + if (value == NULL) { + PyErr_SetString(PyExc_SystemError, + "(Hash) names and fields inconsistent ???"); + return -1; + } + if (!PyUString_Check(key)) { + PyErr_SetString(PyExc_SystemError, + "(Hash) key of dtype dict not a string ???"); + return -1; + } + if (!PyTuple_Check(value)) { + PyErr_SetString(PyExc_SystemError, + "(Hash) value of dtype dict not a dtype ???"); + return -1; + } + if (PyTuple_GET_SIZE(value) < 2) { + PyErr_SetString(PyExc_SystemError, + "(Hash) Less than 2 items in dtype dict ???"); + return -1; + } + PyList_Append(l, key); + + fdescr = PyTuple_GET_ITEM(value, 0); + if (!PyArray_DescrCheck(fdescr)) { + PyErr_SetString(PyExc_SystemError, + "(Hash) First item in compound dtype tuple not a descr ???"); + return -1; + } + else { + Py_INCREF(fdescr); + st = _array_descr_walk((PyArray_Descr*)fdescr, l); + Py_DECREF(fdescr); + if (st) { + return -1; + } + } + + foffset = PyTuple_GET_ITEM(value, 1); + if (!PyInt_Check(foffset)) { + PyErr_SetString(PyExc_SystemError, + "(Hash) Second item in compound dtype tuple not an int ???"); + return -1; + } + else { + PyList_Append(l, foffset); + } + + if (PyTuple_GET_SIZE(value) > 2) { + ftitle = PyTuple_GET_ITEM(value, 2); + PyList_Append(l, ftitle); + } + } + + return 0; +} + +/* + * Walk into subarray, and add items for hashing in l + * + * Return 0 on success + */ +static int _array_descr_walk_subarray(PyArray_ArrayDescr* adescr, PyObject *l) +{ + PyObject *item; + Py_ssize_t i; + int st; + + /* + * Add shape and descr itself to the list of object to hash + */ + if (PyTuple_Check(adescr->shape)) { + for(i = 0; i < PyTuple_Size(adescr->shape); ++i) { + item = PyTuple_GetItem(adescr->shape, i); + if (item == NULL) { + PyErr_SetString(PyExc_SystemError, + "(Hash) Error while getting shape item of subarray dtype ???"); + return -1; + } + PyList_Append(l, item); + } + } + else if (PyInt_Check(adescr->shape)) { + PyList_Append(l, adescr->shape); + } + else { + PyErr_SetString(PyExc_SystemError, + "(Hash) Shape of subarray dtype neither a tuple or int ???"); + return -1; + } + + Py_INCREF(adescr->base); + st = _array_descr_walk(adescr->base, l); + Py_DECREF(adescr->base); + + return st; +} + +/* + * 'Root' function to walk into a dtype. May be called recursively + */ +static int _array_descr_walk(PyArray_Descr* descr, PyObject *l) +{ + int st; + + if (_is_array_descr_builtin(descr)) { + return _array_descr_builtin(descr, l); + } + else { + if(descr->fields != NULL && descr->fields != Py_None) { + st = _array_descr_walk_fields(descr->names, descr->fields, l); + if (st) { + return -1; + } + } + if(PyDataType_HASSUBARRAY(descr)) { + st = _array_descr_walk_subarray(descr->subarray, l); + if (st) { + return -1; + } + } + } + + return 0; +} + +/* + * Return 0 if successful + */ +static int _PyArray_DescrHashImp(PyArray_Descr *descr, npy_hash_t *hash) +{ + PyObject *l, *tl; + int st; + + l = PyList_New(0); + if (l == NULL) { + return -1; + } + + st = _array_descr_walk(descr, l); + if (st) { + Py_DECREF(l); + return -1; + } + + /* + * Convert the list to tuple and compute the tuple hash using python + * builtin function + */ + tl = PyList_AsTuple(l); + Py_DECREF(l); + if (tl == NULL) + return -1; + + *hash = PyObject_Hash(tl); + Py_DECREF(tl); + if (*hash == -1) { + /* XXX: does PyObject_Hash set an exception on failure ? */ +#if 0 + PyErr_SetString(PyExc_SystemError, + "(Hash) Error while hashing final tuple"); +#endif + return -1; + } + + return 0; +} + +NPY_NO_EXPORT npy_hash_t +PyArray_DescrHash(PyObject* odescr) +{ + PyArray_Descr *descr; + int st; + + if (!PyArray_DescrCheck(odescr)) { + PyErr_SetString(PyExc_ValueError, + "PyArray_DescrHash argument must be a type descriptor"); + return -1; + } + descr = (PyArray_Descr*)odescr; + + if (descr->hash == -1) { + st = _PyArray_DescrHashImp(descr, &descr->hash); + if (st) { + return -1; + } + } + + return descr->hash; +} diff --git a/numpy/core/src/multiarray/hashdescr.h b/numpy/core/src/multiarray/hashdescr.h new file mode 100644 index 0000000..8d577e7 --- /dev/null +++ b/numpy/core/src/multiarray/hashdescr.h @@ -0,0 +1,7 @@ +#ifndef _NPY_HASHDESCR_H_ +#define _NPY_HASHDESCR_H_ + +NPY_NO_EXPORT npy_hash_t +PyArray_DescrHash(PyObject* odescr); + +#endif diff --git a/numpy/core/src/multiarray/item_selection.c b/numpy/core/src/multiarray/item_selection.c new file mode 100644 index 0000000..486eb43 --- /dev/null +++ b/numpy/core/src/multiarray/item_selection.c @@ -0,0 +1,2447 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "numpy/npy_math.h" +#include "numpy/npy_cpu.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "common.h" +#include "arrayobject.h" +#include "ctors.h" +#include "lowlevel_strided_loops.h" + +#include "item_selection.h" +#include "npy_sort.h" +#include "npy_partition.h" +#include "npy_binsearch.h" +#include "alloc.h" + +/*NUMPY_API + * Take + */ +NPY_NO_EXPORT PyObject * +PyArray_TakeFrom(PyArrayObject *self0, PyObject *indices0, int axis, + PyArrayObject *out, NPY_CLIPMODE clipmode) +{ + PyArray_Descr *dtype; + PyArray_FastTakeFunc *func; + PyArrayObject *obj = NULL, *self, *indices; + npy_intp nd, i, j, n, m, k, max_item, tmp, chunk, itemsize, nelem; + npy_intp shape[NPY_MAXDIMS]; + char *src, *dest, *tmp_src; + int err; + npy_bool needs_refcounting; + + indices = NULL; + self = (PyArrayObject *)PyArray_CheckAxis(self0, &axis, + NPY_ARRAY_CARRAY); + if (self == NULL) { + return NULL; + } + indices = (PyArrayObject *)PyArray_ContiguousFromAny(indices0, + NPY_INTP, + 0, 0); + if (indices == NULL) { + goto fail; + } + + n = m = chunk = 1; + nd = PyArray_NDIM(self) + PyArray_NDIM(indices) - 1; + for (i = 0; i < nd; i++) { + if (i < axis) { + shape[i] = PyArray_DIMS(self)[i]; + n *= shape[i]; + } + else { + if (i < axis+PyArray_NDIM(indices)) { + shape[i] = PyArray_DIMS(indices)[i-axis]; + m *= shape[i]; + } + else { + shape[i] = PyArray_DIMS(self)[i-PyArray_NDIM(indices)+1]; + chunk *= shape[i]; + } + } + } + if (!out) { + dtype = PyArray_DESCR(self); + Py_INCREF(dtype); + obj = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self), + dtype, + nd, shape, + NULL, NULL, 0, + (PyObject *)self); + + if (obj == NULL) { + goto fail; + } + + } + else { + int flags = NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY; + + if ((PyArray_NDIM(out) != nd) || + !PyArray_CompareLists(PyArray_DIMS(out), shape, nd)) { + PyErr_SetString(PyExc_ValueError, + "output array does not match result of ndarray.take"); + goto fail; + } + + if (clipmode == NPY_RAISE) { + /* + * we need to make sure and get a copy + * so the input array is not changed + * before the error is called + */ + flags |= NPY_ARRAY_ENSURECOPY; + } + dtype = PyArray_DESCR(self); + Py_INCREF(dtype); + obj = (PyArrayObject *)PyArray_FromArray(out, dtype, flags); + if (obj == NULL) { + goto fail; + } + } + + max_item = PyArray_DIMS(self)[axis]; + nelem = chunk; + itemsize = PyArray_ITEMSIZE(obj); + chunk = chunk * itemsize; + src = PyArray_DATA(self); + dest = PyArray_DATA(obj); + needs_refcounting = PyDataType_REFCHK(PyArray_DESCR(self)); + + if ((max_item == 0) && (PyArray_SIZE(obj) != 0)) { + /* Index error, since that is the usual error for raise mode */ + PyErr_SetString(PyExc_IndexError, + "cannot do a non-empty take from an empty axes."); + goto fail; + } + + func = PyArray_DESCR(self)->f->fasttake; + if (func == NULL) { + NPY_BEGIN_THREADS_DEF; + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(self)); + switch(clipmode) { + case NPY_RAISE: + for (i = 0; i < n; i++) { + for (j = 0; j < m; j++) { + tmp = ((npy_intp *)(PyArray_DATA(indices)))[j]; + if (check_and_adjust_index(&tmp, max_item, axis, + _save) < 0) { + goto fail; + } + tmp_src = src + tmp * chunk; + if (needs_refcounting) { + for (k=0; k < nelem; k++) { + PyArray_Item_INCREF(tmp_src, PyArray_DESCR(self)); + PyArray_Item_XDECREF(dest, PyArray_DESCR(self)); + memmove(dest, tmp_src, itemsize); + dest += itemsize; + tmp_src += itemsize; + } + } + else { + memmove(dest, tmp_src, chunk); + dest += chunk; + } + } + src += chunk*max_item; + } + break; + case NPY_WRAP: + for (i = 0; i < n; i++) { + for (j = 0; j < m; j++) { + tmp = ((npy_intp *)(PyArray_DATA(indices)))[j]; + if (tmp < 0) { + while (tmp < 0) { + tmp += max_item; + } + } + else if (tmp >= max_item) { + while (tmp >= max_item) { + tmp -= max_item; + } + } + tmp_src = src + tmp * chunk; + if (needs_refcounting) { + for (k=0; k < nelem; k++) { + PyArray_Item_INCREF(tmp_src, PyArray_DESCR(self)); + PyArray_Item_XDECREF(dest, PyArray_DESCR(self)); + memmove(dest, tmp_src, itemsize); + dest += itemsize; + tmp_src += itemsize; + } + } + else { + memmove(dest, tmp_src, chunk); + dest += chunk; + } + } + src += chunk*max_item; + } + break; + case NPY_CLIP: + for (i = 0; i < n; i++) { + for (j = 0; j < m; j++) { + tmp = ((npy_intp *)(PyArray_DATA(indices)))[j]; + if (tmp < 0) { + tmp = 0; + } + else if (tmp >= max_item) { + tmp = max_item - 1; + } + tmp_src = src + tmp * chunk; + if (needs_refcounting) { + for (k=0; k < nelem; k++) { + PyArray_Item_INCREF(tmp_src, PyArray_DESCR(self)); + PyArray_Item_XDECREF(dest, PyArray_DESCR(self)); + memmove(dest, tmp_src, itemsize); + dest += itemsize; + tmp_src += itemsize; + } + } + else { + memmove(dest, tmp_src, chunk); + dest += chunk; + } + } + src += chunk*max_item; + } + break; + } + NPY_END_THREADS; + } + else { + /* no gil release, need it for error reporting */ + err = func(dest, src, (npy_intp *)(PyArray_DATA(indices)), + max_item, n, m, nelem, clipmode); + if (err) { + goto fail; + } + } + + Py_XDECREF(indices); + Py_XDECREF(self); + if (out != NULL && out != obj) { + Py_INCREF(out); + PyArray_ResolveWritebackIfCopy(obj); + Py_DECREF(obj); + obj = out; + } + return (PyObject *)obj; + + fail: + PyArray_DiscardWritebackIfCopy(obj); + Py_XDECREF(obj); + Py_XDECREF(indices); + Py_XDECREF(self); + return NULL; +} + +/*NUMPY_API + * Put values into an array + */ +NPY_NO_EXPORT PyObject * +PyArray_PutTo(PyArrayObject *self, PyObject* values0, PyObject *indices0, + NPY_CLIPMODE clipmode) +{ + PyArrayObject *indices, *values; + npy_intp i, chunk, ni, max_item, nv, tmp; + char *src, *dest; + int copied = 0; + + indices = NULL; + values = NULL; + if (!PyArray_Check(self)) { + PyErr_SetString(PyExc_TypeError, + "put: first argument must be an array"); + return NULL; + } + + if (PyArray_FailUnlessWriteable(self, "put: output array") < 0) { + return NULL; + } + + if (!PyArray_ISCONTIGUOUS(self)) { + PyArrayObject *obj; + int flags = NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY; + + if (clipmode == NPY_RAISE) { + flags |= NPY_ARRAY_ENSURECOPY; + } + Py_INCREF(PyArray_DESCR(self)); + obj = (PyArrayObject *)PyArray_FromArray(self, + PyArray_DESCR(self), flags); + if (obj != self) { + copied = 1; + } + self = obj; + } + max_item = PyArray_SIZE(self); + dest = PyArray_DATA(self); + chunk = PyArray_DESCR(self)->elsize; + indices = (PyArrayObject *)PyArray_ContiguousFromAny(indices0, + NPY_INTP, 0, 0); + if (indices == NULL) { + goto fail; + } + ni = PyArray_SIZE(indices); + Py_INCREF(PyArray_DESCR(self)); + values = (PyArrayObject *)PyArray_FromAny(values0, PyArray_DESCR(self), 0, 0, + NPY_ARRAY_DEFAULT | NPY_ARRAY_FORCECAST, NULL); + if (values == NULL) { + goto fail; + } + nv = PyArray_SIZE(values); + if (nv <= 0) { + goto finish; + } + if (PyDataType_REFCHK(PyArray_DESCR(self))) { + switch(clipmode) { + case NPY_RAISE: + for (i = 0; i < ni; i++) { + src = PyArray_BYTES(values) + chunk*(i % nv); + tmp = ((npy_intp *)(PyArray_DATA(indices)))[i]; + if (check_and_adjust_index(&tmp, max_item, 0, NULL) < 0) { + goto fail; + } + PyArray_Item_INCREF(src, PyArray_DESCR(self)); + PyArray_Item_XDECREF(dest+tmp*chunk, PyArray_DESCR(self)); + memmove(dest + tmp*chunk, src, chunk); + } + break; + case NPY_WRAP: + for (i = 0; i < ni; i++) { + src = PyArray_BYTES(values) + chunk * (i % nv); + tmp = ((npy_intp *)(PyArray_DATA(indices)))[i]; + if (tmp < 0) { + while (tmp < 0) { + tmp += max_item; + } + } + else if (tmp >= max_item) { + while (tmp >= max_item) { + tmp -= max_item; + } + } + PyArray_Item_INCREF(src, PyArray_DESCR(self)); + PyArray_Item_XDECREF(dest+tmp*chunk, PyArray_DESCR(self)); + memmove(dest + tmp * chunk, src, chunk); + } + break; + case NPY_CLIP: + for (i = 0; i < ni; i++) { + src = PyArray_BYTES(values) + chunk * (i % nv); + tmp = ((npy_intp *)(PyArray_DATA(indices)))[i]; + if (tmp < 0) { + tmp = 0; + } + else if (tmp >= max_item) { + tmp = max_item - 1; + } + PyArray_Item_INCREF(src, PyArray_DESCR(self)); + PyArray_Item_XDECREF(dest+tmp*chunk, PyArray_DESCR(self)); + memmove(dest + tmp * chunk, src, chunk); + } + break; + } + } + else { + NPY_BEGIN_THREADS_DEF; + NPY_BEGIN_THREADS_THRESHOLDED(ni); + switch(clipmode) { + case NPY_RAISE: + for (i = 0; i < ni; i++) { + src = PyArray_BYTES(values) + chunk * (i % nv); + tmp = ((npy_intp *)(PyArray_DATA(indices)))[i]; + if (check_and_adjust_index(&tmp, max_item, 0, _save) < 0) { + goto fail; + } + memmove(dest + tmp * chunk, src, chunk); + } + break; + case NPY_WRAP: + for (i = 0; i < ni; i++) { + src = PyArray_BYTES(values) + chunk * (i % nv); + tmp = ((npy_intp *)(PyArray_DATA(indices)))[i]; + if (tmp < 0) { + while (tmp < 0) { + tmp += max_item; + } + } + else if (tmp >= max_item) { + while (tmp >= max_item) { + tmp -= max_item; + } + } + memmove(dest + tmp * chunk, src, chunk); + } + break; + case NPY_CLIP: + for (i = 0; i < ni; i++) { + src = PyArray_BYTES(values) + chunk * (i % nv); + tmp = ((npy_intp *)(PyArray_DATA(indices)))[i]; + if (tmp < 0) { + tmp = 0; + } + else if (tmp >= max_item) { + tmp = max_item - 1; + } + memmove(dest + tmp * chunk, src, chunk); + } + break; + } + NPY_END_THREADS; + } + + finish: + Py_XDECREF(values); + Py_XDECREF(indices); + if (copied) { + PyArray_ResolveWritebackIfCopy(self); + Py_DECREF(self); + } + Py_RETURN_NONE; + + fail: + Py_XDECREF(indices); + Py_XDECREF(values); + if (copied) { + PyArray_DiscardWritebackIfCopy(self); + Py_XDECREF(self); + } + return NULL; +} + +/*NUMPY_API + * Put values into an array according to a mask. + */ +NPY_NO_EXPORT PyObject * +PyArray_PutMask(PyArrayObject *self, PyObject* values0, PyObject* mask0) +{ + PyArray_FastPutmaskFunc *func; + PyArrayObject *mask, *values; + PyArray_Descr *dtype; + npy_intp i, j, chunk, ni, max_item, nv; + char *src, *dest; + npy_bool *mask_data; + int copied = 0; + + mask = NULL; + values = NULL; + if (!PyArray_Check(self)) { + PyErr_SetString(PyExc_TypeError, + "putmask: first argument must " + "be an array"); + return NULL; + } + if (!PyArray_ISCONTIGUOUS(self)) { + PyArrayObject *obj; + + dtype = PyArray_DESCR(self); + Py_INCREF(dtype); + obj = (PyArrayObject *)PyArray_FromArray(self, dtype, + NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY); + if (obj != self) { + copied = 1; + } + self = obj; + } + + max_item = PyArray_SIZE(self); + dest = PyArray_DATA(self); + chunk = PyArray_DESCR(self)->elsize; + mask = (PyArrayObject *)PyArray_FROM_OTF(mask0, NPY_BOOL, + NPY_ARRAY_CARRAY | NPY_ARRAY_FORCECAST); + if (mask == NULL) { + goto fail; + } + ni = PyArray_SIZE(mask); + if (ni != max_item) { + PyErr_SetString(PyExc_ValueError, + "putmask: mask and data must be " + "the same size"); + goto fail; + } + mask_data = PyArray_DATA(mask); + dtype = PyArray_DESCR(self); + Py_INCREF(dtype); + values = (PyArrayObject *)PyArray_FromAny(values0, dtype, + 0, 0, NPY_ARRAY_CARRAY, NULL); + if (values == NULL) { + goto fail; + } + nv = PyArray_SIZE(values); /* zero if null array */ + if (nv <= 0) { + Py_XDECREF(values); + Py_XDECREF(mask); + Py_RETURN_NONE; + } + src = PyArray_DATA(values); + + if (PyDataType_REFCHK(PyArray_DESCR(self))) { + for (i = 0, j = 0; i < ni; i++, j++) { + if (j >= nv) { + j = 0; + } + if (mask_data[i]) { + char *src_ptr = src + j*chunk; + char *dest_ptr = dest + i*chunk; + + PyArray_Item_INCREF(src_ptr, PyArray_DESCR(self)); + PyArray_Item_XDECREF(dest_ptr, PyArray_DESCR(self)); + memmove(dest_ptr, src_ptr, chunk); + } + } + } + else { + NPY_BEGIN_THREADS_DEF; + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(self)); + func = PyArray_DESCR(self)->f->fastputmask; + if (func == NULL) { + for (i = 0, j = 0; i < ni; i++, j++) { + if (j >= nv) { + j = 0; + } + if (mask_data[i]) { + memmove(dest + i*chunk, src + j*chunk, chunk); + } + } + } + else { + func(dest, mask_data, ni, src, nv); + } + NPY_END_THREADS; + } + + Py_XDECREF(values); + Py_XDECREF(mask); + if (copied) { + PyArray_ResolveWritebackIfCopy(self); + Py_DECREF(self); + } + Py_RETURN_NONE; + + fail: + Py_XDECREF(mask); + Py_XDECREF(values); + if (copied) { + PyArray_DiscardWritebackIfCopy(self); + Py_XDECREF(self); + } + return NULL; +} + +/*NUMPY_API + * Repeat the array. + */ +NPY_NO_EXPORT PyObject * +PyArray_Repeat(PyArrayObject *aop, PyObject *op, int axis) +{ + npy_intp *counts; + npy_intp n, n_outer, i, j, k, chunk; + npy_intp total = 0; + npy_bool broadcast = NPY_FALSE; + PyArrayObject *repeats = NULL; + PyObject *ap = NULL; + PyArrayObject *ret = NULL; + char *new_data, *old_data; + + repeats = (PyArrayObject *)PyArray_ContiguousFromAny(op, NPY_INTP, 0, 1); + if (repeats == NULL) { + return NULL; + } + + /* + * Scalar and size 1 'repeat' arrays broadcast to any shape, for all + * other inputs the dimension must match exactly. + */ + if (PyArray_NDIM(repeats) == 0 || PyArray_SIZE(repeats) == 1) { + broadcast = NPY_TRUE; + } + + counts = (npy_intp *)PyArray_DATA(repeats); + + if ((ap = PyArray_CheckAxis(aop, &axis, NPY_ARRAY_CARRAY)) == NULL) { + Py_DECREF(repeats); + return NULL; + } + + aop = (PyArrayObject *)ap; + n = PyArray_DIM(aop, axis); + + if (!broadcast && PyArray_SIZE(repeats) != n) { + PyErr_Format(PyExc_ValueError, + "operands could not be broadcast together " + "with shape (%zd,) (%zd,)", n, PyArray_DIM(repeats, 0)); + goto fail; + } + if (broadcast) { + total = counts[0] * n; + } + else { + for (j = 0; j < n; j++) { + if (counts[j] < 0) { + PyErr_SetString(PyExc_ValueError, "count < 0"); + goto fail; + } + total += counts[j]; + } + } + + /* Construct new array */ + PyArray_DIMS(aop)[axis] = total; + Py_INCREF(PyArray_DESCR(aop)); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(aop), + PyArray_DESCR(aop), + PyArray_NDIM(aop), + PyArray_DIMS(aop), + NULL, NULL, 0, + (PyObject *)aop); + PyArray_DIMS(aop)[axis] = n; + if (ret == NULL) { + goto fail; + } + new_data = PyArray_DATA(ret); + old_data = PyArray_DATA(aop); + + chunk = PyArray_DESCR(aop)->elsize; + for(i = axis + 1; i < PyArray_NDIM(aop); i++) { + chunk *= PyArray_DIMS(aop)[i]; + } + + n_outer = 1; + for (i = 0; i < axis; i++) { + n_outer *= PyArray_DIMS(aop)[i]; + } + for (i = 0; i < n_outer; i++) { + for (j = 0; j < n; j++) { + npy_intp tmp = broadcast ? counts[0] : counts[j]; + for (k = 0; k < tmp; k++) { + memcpy(new_data, old_data, chunk); + new_data += chunk; + } + old_data += chunk; + } + } + + Py_DECREF(repeats); + PyArray_INCREF(ret); + Py_XDECREF(aop); + return (PyObject *)ret; + + fail: + Py_DECREF(repeats); + Py_XDECREF(aop); + Py_XDECREF(ret); + return NULL; +} + +/*NUMPY_API + */ +NPY_NO_EXPORT PyObject * +PyArray_Choose(PyArrayObject *ip, PyObject *op, PyArrayObject *out, + NPY_CLIPMODE clipmode) +{ + PyArrayObject *obj = NULL; + PyArray_Descr *dtype; + int n, elsize; + npy_intp i; + char *ret_data; + PyArrayObject **mps, *ap; + PyArrayMultiIterObject *multi = NULL; + npy_intp mi; + ap = NULL; + + /* + * Convert all inputs to arrays of a common type + * Also makes them C-contiguous + */ + mps = PyArray_ConvertToCommonType(op, &n); + if (mps == NULL) { + return NULL; + } + for (i = 0; i < n; i++) { + if (mps[i] == NULL) { + goto fail; + } + } + ap = (PyArrayObject *)PyArray_FROM_OT((PyObject *)ip, NPY_INTP); + if (ap == NULL) { + goto fail; + } + /* Broadcast all arrays to each other, index array at the end. */ + multi = (PyArrayMultiIterObject *) + PyArray_MultiIterFromObjects((PyObject **)mps, n, 1, ap); + if (multi == NULL) { + goto fail; + } + /* Set-up return array */ + if (out == NULL) { + dtype = PyArray_DESCR(mps[0]); + Py_INCREF(dtype); + obj = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(ap), + dtype, + multi->nd, + multi->dimensions, + NULL, NULL, 0, + (PyObject *)ap); + } + else { + int flags = NPY_ARRAY_CARRAY | + NPY_ARRAY_WRITEBACKIFCOPY | + NPY_ARRAY_FORCECAST; + + if ((PyArray_NDIM(out) != multi->nd) + || !PyArray_CompareLists(PyArray_DIMS(out), + multi->dimensions, + multi->nd)) { + PyErr_SetString(PyExc_TypeError, + "choose: invalid shape for output array."); + goto fail; + } + if (clipmode == NPY_RAISE) { + /* + * we need to make sure and get a copy + * so the input array is not changed + * before the error is called + */ + flags |= NPY_ARRAY_ENSURECOPY; + } + dtype = PyArray_DESCR(mps[0]); + Py_INCREF(dtype); + obj = (PyArrayObject *)PyArray_FromArray(out, dtype, flags); + } + + if (obj == NULL) { + goto fail; + } + elsize = PyArray_DESCR(obj)->elsize; + ret_data = PyArray_DATA(obj); + + while (PyArray_MultiIter_NOTDONE(multi)) { + mi = *((npy_intp *)PyArray_MultiIter_DATA(multi, n)); + if (mi < 0 || mi >= n) { + switch(clipmode) { + case NPY_RAISE: + PyErr_SetString(PyExc_ValueError, + "invalid entry in choice "\ + "array"); + goto fail; + case NPY_WRAP: + if (mi < 0) { + while (mi < 0) { + mi += n; + } + } + else { + while (mi >= n) { + mi -= n; + } + } + break; + case NPY_CLIP: + if (mi < 0) { + mi = 0; + } + else if (mi >= n) { + mi = n - 1; + } + break; + } + } + memmove(ret_data, PyArray_MultiIter_DATA(multi, mi), elsize); + ret_data += elsize; + PyArray_MultiIter_NEXT(multi); + } + + PyArray_INCREF(obj); + Py_DECREF(multi); + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + } + Py_DECREF(ap); + npy_free_cache(mps, n * sizeof(mps[0])); + if (out != NULL && out != obj) { + Py_INCREF(out); + PyArray_ResolveWritebackIfCopy(obj); + Py_DECREF(obj); + obj = out; + } + return (PyObject *)obj; + + fail: + Py_XDECREF(multi); + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + } + Py_XDECREF(ap); + npy_free_cache(mps, n * sizeof(mps[0])); + PyArray_DiscardWritebackIfCopy(obj); + Py_XDECREF(obj); + return NULL; +} + +/* + * These algorithms use special sorting. They are not called unless the + * underlying sort function for the type is available. Note that axis is + * already valid. The sort functions require 1-d contiguous and well-behaved + * data. Therefore, a copy will be made of the data if needed before handing + * it to the sorting routine. An iterator is constructed and adjusted to walk + * over all but the desired sorting axis. + */ +static int +_new_sortlike(PyArrayObject *op, int axis, PyArray_SortFunc *sort, + PyArray_PartitionFunc *part, npy_intp *kth, npy_intp nkth) +{ + npy_intp N = PyArray_DIM(op, axis); + npy_intp elsize = (npy_intp)PyArray_ITEMSIZE(op); + npy_intp astride = PyArray_STRIDE(op, axis); + int swap = PyArray_ISBYTESWAPPED(op); + int needcopy = !PyArray_ISALIGNED(op) || swap || astride != elsize; + int hasrefs = PyDataType_REFCHK(PyArray_DESCR(op)); + + PyArray_CopySwapNFunc *copyswapn = PyArray_DESCR(op)->f->copyswapn; + char *buffer = NULL; + + PyArrayIterObject *it; + npy_intp size; + + int ret = 0; + + NPY_BEGIN_THREADS_DEF; + + /* Check if there is any sorting to do */ + if (N <= 1 || PyArray_SIZE(op) == 0) { + return 0; + } + + it = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)op, &axis); + if (it == NULL) { + return -1; + } + size = it->size; + + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(op)); + + if (needcopy) { + buffer = npy_alloc_cache(N * elsize); + if (buffer == NULL) { + ret = -1; + goto fail; + } + } + + while (size--) { + char *bufptr = it->dataptr; + + if (needcopy) { + if (hasrefs) { + /* + * For dtype's with objects, copyswapn Py_XINCREF's src + * and Py_XDECREF's dst. This would crash if called on + * an uninitialized buffer, or leak a reference to each + * object if initialized. + * + * So, first do the copy with no refcounting... + */ + _unaligned_strided_byte_copy(buffer, elsize, + it->dataptr, astride, N, elsize); + /* ...then swap in-place if needed */ + if (swap) { + copyswapn(buffer, elsize, NULL, 0, N, swap, op); + } + } + else { + copyswapn(buffer, elsize, it->dataptr, astride, N, swap, op); + } + bufptr = buffer; + } + /* + * TODO: If the input array is byte-swapped but contiguous and + * aligned, it could be swapped (and later unswapped) in-place + * rather than after copying to the buffer. Care would have to + * be taken to ensure that, if there is an error in the call to + * sort or part, the unswapping is still done before returning. + */ + + if (part == NULL) { + ret = sort(bufptr, N, op); + if (hasrefs && PyErr_Occurred()) { + ret = -1; + } + if (ret < 0) { + goto fail; + } + } + else { + npy_intp pivots[NPY_MAX_PIVOT_STACK]; + npy_intp npiv = 0; + npy_intp i; + for (i = 0; i < nkth; ++i) { + ret = part(bufptr, N, kth[i], pivots, &npiv, op); + if (hasrefs && PyErr_Occurred()) { + ret = -1; + } + if (ret < 0) { + goto fail; + } + } + } + + if (needcopy) { + if (hasrefs) { + if (swap) { + copyswapn(buffer, elsize, NULL, 0, N, swap, op); + } + _unaligned_strided_byte_copy(it->dataptr, astride, + buffer, elsize, N, elsize); + } + else { + copyswapn(it->dataptr, astride, buffer, elsize, N, swap, op); + } + } + + PyArray_ITER_NEXT(it); + } + +fail: + npy_free_cache(buffer, N * elsize); + NPY_END_THREADS_DESCR(PyArray_DESCR(op)); + if (ret < 0 && !PyErr_Occurred()) { + /* Out of memory during sorting or buffer creation */ + PyErr_NoMemory(); + } + Py_DECREF(it); + + return ret; +} + +static PyObject* +_new_argsortlike(PyArrayObject *op, int axis, PyArray_ArgSortFunc *argsort, + PyArray_ArgPartitionFunc *argpart, + npy_intp *kth, npy_intp nkth) +{ + npy_intp N = PyArray_DIM(op, axis); + npy_intp elsize = (npy_intp)PyArray_ITEMSIZE(op); + npy_intp astride = PyArray_STRIDE(op, axis); + int swap = PyArray_ISBYTESWAPPED(op); + int needcopy = !PyArray_ISALIGNED(op) || swap || astride != elsize; + int hasrefs = PyDataType_REFCHK(PyArray_DESCR(op)); + int needidxbuffer; + + PyArray_CopySwapNFunc *copyswapn = PyArray_DESCR(op)->f->copyswapn; + char *valbuffer = NULL; + npy_intp *idxbuffer = NULL; + + PyArrayObject *rop; + npy_intp rstride; + + PyArrayIterObject *it, *rit; + npy_intp size; + + int ret = 0; + + NPY_BEGIN_THREADS_DEF; + + rop = (PyArrayObject *)PyArray_New(Py_TYPE(op), PyArray_NDIM(op), + PyArray_DIMS(op), NPY_INTP, + NULL, NULL, 0, 0, (PyObject *)op); + if (rop == NULL) { + return NULL; + } + rstride = PyArray_STRIDE(rop, axis); + needidxbuffer = rstride != sizeof(npy_intp); + + /* Check if there is any argsorting to do */ + if (N <= 1 || PyArray_SIZE(op) == 0) { + memset(PyArray_DATA(rop), 0, PyArray_NBYTES(rop)); + return (PyObject *)rop; + } + + it = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)op, &axis); + rit = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)rop, &axis); + if (it == NULL || rit == NULL) { + ret = -1; + goto fail; + } + size = it->size; + + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(op)); + + if (needcopy) { + valbuffer = npy_alloc_cache(N * elsize); + if (valbuffer == NULL) { + ret = -1; + goto fail; + } + } + + if (needidxbuffer) { + idxbuffer = (npy_intp *)npy_alloc_cache(N * sizeof(npy_intp)); + if (idxbuffer == NULL) { + ret = -1; + goto fail; + } + } + + while (size--) { + char *valptr = it->dataptr; + npy_intp *idxptr = (npy_intp *)rit->dataptr; + npy_intp *iptr, i; + + if (needcopy) { + if (hasrefs) { + /* + * For dtype's with objects, copyswapn Py_XINCREF's src + * and Py_XDECREF's dst. This would crash if called on + * an uninitialized valbuffer, or leak a reference to + * each object item if initialized. + * + * So, first do the copy with no refcounting... + */ + _unaligned_strided_byte_copy(valbuffer, elsize, + it->dataptr, astride, N, elsize); + /* ...then swap in-place if needed */ + if (swap) { + copyswapn(valbuffer, elsize, NULL, 0, N, swap, op); + } + } + else { + copyswapn(valbuffer, elsize, + it->dataptr, astride, N, swap, op); + } + valptr = valbuffer; + } + + if (needidxbuffer) { + idxptr = idxbuffer; + } + + iptr = idxptr; + for (i = 0; i < N; ++i) { + *iptr++ = i; + } + + if (argpart == NULL) { + ret = argsort(valptr, idxptr, N, op); +#if defined(NPY_PY3K) + /* Object comparisons may raise an exception in Python 3 */ + if (hasrefs && PyErr_Occurred()) { + ret = -1; + } +#endif + if (ret < 0) { + goto fail; + } + } + else { + npy_intp pivots[NPY_MAX_PIVOT_STACK]; + npy_intp npiv = 0; + + for (i = 0; i < nkth; ++i) { + ret = argpart(valptr, idxptr, N, kth[i], pivots, &npiv, op); +#if defined(NPY_PY3K) + /* Object comparisons may raise an exception in Python 3 */ + if (hasrefs && PyErr_Occurred()) { + ret = -1; + } +#endif + if (ret < 0) { + goto fail; + } + } + } + + if (needidxbuffer) { + char *rptr = rit->dataptr; + iptr = idxbuffer; + + for (i = 0; i < N; ++i) { + *(npy_intp *)rptr = *iptr++; + rptr += rstride; + } + } + + PyArray_ITER_NEXT(it); + PyArray_ITER_NEXT(rit); + } + +fail: + npy_free_cache(valbuffer, N * elsize); + npy_free_cache(idxbuffer, N * sizeof(npy_intp)); + NPY_END_THREADS_DESCR(PyArray_DESCR(op)); + if (ret < 0) { + if (!PyErr_Occurred()) { + /* Out of memory during sorting or buffer creation */ + PyErr_NoMemory(); + } + Py_XDECREF(rop); + rop = NULL; + } + Py_XDECREF(it); + Py_XDECREF(rit); + + return (PyObject *)rop; +} + + +/*NUMPY_API + * Sort an array in-place + */ +NPY_NO_EXPORT int +PyArray_Sort(PyArrayObject *op, int axis, NPY_SORTKIND which) +{ + PyArray_SortFunc *sort; + int n = PyArray_NDIM(op); + + if (check_and_adjust_axis(&axis, n) < 0) { + return -1; + } + + if (PyArray_FailUnlessWriteable(op, "sort array") < 0) { + return -1; + } + + if (which < 0 || which >= NPY_NSORTS) { + PyErr_SetString(PyExc_ValueError, "not a valid sort kind"); + return -1; + } + + sort = PyArray_DESCR(op)->f->sort[which]; + if (sort == NULL) { + if (PyArray_DESCR(op)->f->compare) { + switch (which) { + default: + case NPY_QUICKSORT: + sort = npy_quicksort; + break; + case NPY_HEAPSORT: + sort = npy_heapsort; + break; + case NPY_MERGESORT: + sort = npy_mergesort; + break; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "type does not have compare function"); + return -1; + } + } + + return _new_sortlike(op, axis, sort, NULL, NULL, 0); +} + + +/* + * make kth array positive, ravel and sort it + */ +static PyArrayObject * +partition_prep_kth_array(PyArrayObject * ktharray, + PyArrayObject * op, + int axis) +{ + const npy_intp * shape = PyArray_SHAPE(op); + PyArrayObject * kthrvl; + npy_intp * kth; + npy_intp nkth, i; + + if (!PyArray_CanCastSafely(PyArray_TYPE(ktharray), NPY_INTP)) { + PyErr_Format(PyExc_TypeError, "Partition index must be integer"); + return NULL; + } + + if (PyArray_NDIM(ktharray) > 1) { + PyErr_Format(PyExc_ValueError, "kth array must have dimension <= 1"); + return NULL; + } + kthrvl = (PyArrayObject *)PyArray_Cast(ktharray, NPY_INTP); + + if (kthrvl == NULL) + return NULL; + + kth = PyArray_DATA(kthrvl); + nkth = PyArray_SIZE(kthrvl); + + for (i = 0; i < nkth; i++) { + if (kth[i] < 0) { + kth[i] += shape[axis]; + } + if (PyArray_SIZE(op) != 0 && + (kth[i] < 0 || kth[i] >= shape[axis])) { + PyErr_Format(PyExc_ValueError, "kth(=%zd) out of bounds (%zd)", + kth[i], shape[axis]); + Py_XDECREF(kthrvl); + return NULL; + } + } + + /* + * sort the array of kths so the partitions will + * not trample on each other + */ + if (PyArray_SIZE(kthrvl) > 1) { + PyArray_Sort(kthrvl, -1, NPY_QUICKSORT); + } + + return kthrvl; +} + + +/*NUMPY_API + * Partition an array in-place + */ +NPY_NO_EXPORT int +PyArray_Partition(PyArrayObject *op, PyArrayObject * ktharray, int axis, + NPY_SELECTKIND which) +{ + PyArrayObject *kthrvl; + PyArray_PartitionFunc *part; + PyArray_SortFunc *sort; + int n = PyArray_NDIM(op); + int ret; + + if (check_and_adjust_axis(&axis, n) < 0) { + return -1; + } + + if (PyArray_FailUnlessWriteable(op, "partition array") < 0) { + return -1; + } + + if (which < 0 || which >= NPY_NSELECTS) { + PyErr_SetString(PyExc_ValueError, "not a valid partition kind"); + return -1; + } + part = get_partition_func(PyArray_TYPE(op), which); + if (part == NULL) { + /* Use sorting, slower but equivalent */ + if (PyArray_DESCR(op)->f->compare) { + sort = npy_quicksort; + } + else { + PyErr_SetString(PyExc_TypeError, + "type does not have compare function"); + return -1; + } + } + + /* Process ktharray even if using sorting to do bounds checking */ + kthrvl = partition_prep_kth_array(ktharray, op, axis); + if (kthrvl == NULL) { + return -1; + } + + ret = _new_sortlike(op, axis, sort, part, + PyArray_DATA(kthrvl), PyArray_SIZE(kthrvl)); + + Py_DECREF(kthrvl); + + return ret; +} + + +/*NUMPY_API + * ArgSort an array + */ +NPY_NO_EXPORT PyObject * +PyArray_ArgSort(PyArrayObject *op, int axis, NPY_SORTKIND which) +{ + PyArrayObject *op2; + PyArray_ArgSortFunc *argsort; + PyObject *ret; + + if (which < 0 || which >= NPY_NSORTS) { + PyErr_SetString(PyExc_ValueError, + "not a valid sort kind"); + return NULL; + } + + argsort = PyArray_DESCR(op)->f->argsort[which]; + if (argsort == NULL) { + if (PyArray_DESCR(op)->f->compare) { + switch (which) { + default: + case NPY_QUICKSORT: + argsort = npy_aquicksort; + break; + case NPY_HEAPSORT: + argsort = npy_aheapsort; + break; + case NPY_MERGESORT: + argsort = npy_amergesort; + break; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "type does not have compare function"); + return NULL; + } + } + + op2 = (PyArrayObject *)PyArray_CheckAxis(op, &axis, 0); + if (op2 == NULL) { + return NULL; + } + + ret = _new_argsortlike(op2, axis, argsort, NULL, NULL, 0); + + Py_DECREF(op2); + return ret; +} + + +/*NUMPY_API + * ArgPartition an array + */ +NPY_NO_EXPORT PyObject * +PyArray_ArgPartition(PyArrayObject *op, PyArrayObject *ktharray, int axis, + NPY_SELECTKIND which) +{ + PyArrayObject *op2, *kthrvl; + PyArray_ArgPartitionFunc *argpart; + PyArray_ArgSortFunc *argsort; + PyObject *ret; + + if (which < 0 || which >= NPY_NSELECTS) { + PyErr_SetString(PyExc_ValueError, + "not a valid partition kind"); + return NULL; + } + + argpart = get_argpartition_func(PyArray_TYPE(op), which); + if (argpart == NULL) { + /* Use sorting, slower but equivalent */ + if (PyArray_DESCR(op)->f->compare) { + argsort = npy_aquicksort; + } + else { + PyErr_SetString(PyExc_TypeError, + "type does not have compare function"); + return NULL; + } + } + + op2 = (PyArrayObject *)PyArray_CheckAxis(op, &axis, 0); + if (op2 == NULL) { + return NULL; + } + + /* Process ktharray even if using sorting to do bounds checking */ + kthrvl = partition_prep_kth_array(ktharray, op2, axis); + if (kthrvl == NULL) { + Py_DECREF(op2); + return NULL; + } + + ret = _new_argsortlike(op2, axis, argsort, argpart, + PyArray_DATA(kthrvl), PyArray_SIZE(kthrvl)); + + Py_DECREF(kthrvl); + Py_DECREF(op2); + + return ret; +} + + +/*NUMPY_API + *LexSort an array providing indices that will sort a collection of arrays + *lexicographically. The first key is sorted on first, followed by the second key + *-- requires that arg"merge"sort is available for each sort_key + * + *Returns an index array that shows the indexes for the lexicographic sort along + *the given axis. + */ +NPY_NO_EXPORT PyObject * +PyArray_LexSort(PyObject *sort_keys, int axis) +{ + PyArrayObject **mps; + PyArrayIterObject **its; + PyArrayObject *ret = NULL; + PyArrayIterObject *rit = NULL; + npy_intp n, N, size, i, j; + npy_intp astride, rstride, *iptr; + int nd; + int needcopy = 0; + int elsize; + int maxelsize; + int object = 0; + PyArray_ArgSortFunc *argsort; + NPY_BEGIN_THREADS_DEF; + + if (!PySequence_Check(sort_keys) + || ((n = PySequence_Size(sort_keys)) <= 0)) { + PyErr_SetString(PyExc_TypeError, + "need sequence of keys with len > 0 in lexsort"); + return NULL; + } + mps = (PyArrayObject **) PyArray_malloc(n * sizeof(PyArrayObject *)); + if (mps == NULL) { + return PyErr_NoMemory(); + } + its = (PyArrayIterObject **) PyArray_malloc(n * sizeof(PyArrayIterObject *)); + if (its == NULL) { + PyArray_free(mps); + return PyErr_NoMemory(); + } + for (i = 0; i < n; i++) { + mps[i] = NULL; + its[i] = NULL; + } + for (i = 0; i < n; i++) { + PyObject *obj; + obj = PySequence_GetItem(sort_keys, i); + if (obj == NULL) { + goto fail; + } + mps[i] = (PyArrayObject *)PyArray_FROM_O(obj); + Py_DECREF(obj); + if (mps[i] == NULL) { + goto fail; + } + if (i > 0) { + if ((PyArray_NDIM(mps[i]) != PyArray_NDIM(mps[0])) + || (!PyArray_CompareLists(PyArray_DIMS(mps[i]), + PyArray_DIMS(mps[0]), + PyArray_NDIM(mps[0])))) { + PyErr_SetString(PyExc_ValueError, + "all keys need to be the same shape"); + goto fail; + } + } + if (!PyArray_DESCR(mps[i])->f->argsort[NPY_MERGESORT] + && !PyArray_DESCR(mps[i])->f->compare) { + PyErr_Format(PyExc_TypeError, + "item %zd type does not have compare function", i); + goto fail; + } + if (!object + && PyDataType_FLAGCHK(PyArray_DESCR(mps[i]), NPY_NEEDS_PYAPI)) { + object = 1; + } + } + + /* Now we can check the axis */ + nd = PyArray_NDIM(mps[0]); + if ((nd == 0) || (PyArray_SIZE(mps[0]) == 1)) { + /* single element case */ + ret = (PyArrayObject *)PyArray_New(&PyArray_Type, PyArray_NDIM(mps[0]), + PyArray_DIMS(mps[0]), + NPY_INTP, + NULL, NULL, 0, 0, NULL); + + if (ret == NULL) { + goto fail; + } + *((npy_intp *)(PyArray_DATA(ret))) = 0; + goto finish; + } + if (check_and_adjust_axis(&axis, nd) < 0) { + goto fail; + } + + for (i = 0; i < n; i++) { + its[i] = (PyArrayIterObject *)PyArray_IterAllButAxis( + (PyObject *)mps[i], &axis); + if (its[i] == NULL) { + goto fail; + } + } + + /* Now do the sorting */ + ret = (PyArrayObject *)PyArray_New(&PyArray_Type, PyArray_NDIM(mps[0]), + PyArray_DIMS(mps[0]), NPY_INTP, + NULL, NULL, 0, 0, NULL); + if (ret == NULL) { + goto fail; + } + rit = (PyArrayIterObject *) + PyArray_IterAllButAxis((PyObject *)ret, &axis); + if (rit == NULL) { + goto fail; + } + if (!object) { + NPY_BEGIN_THREADS; + } + size = rit->size; + N = PyArray_DIMS(mps[0])[axis]; + rstride = PyArray_STRIDE(ret, axis); + maxelsize = PyArray_DESCR(mps[0])->elsize; + needcopy = (rstride != sizeof(npy_intp)); + for (j = 0; j < n; j++) { + needcopy = needcopy + || PyArray_ISBYTESWAPPED(mps[j]) + || !(PyArray_FLAGS(mps[j]) & NPY_ARRAY_ALIGNED) + || (PyArray_STRIDES(mps[j])[axis] != (npy_intp)PyArray_DESCR(mps[j])->elsize); + if (PyArray_DESCR(mps[j])->elsize > maxelsize) { + maxelsize = PyArray_DESCR(mps[j])->elsize; + } + } + + if (needcopy) { + char *valbuffer, *indbuffer; + int *swaps; + + valbuffer = npy_alloc_cache(N * maxelsize); + if (valbuffer == NULL) { + goto fail; + } + indbuffer = npy_alloc_cache(N * sizeof(npy_intp)); + if (indbuffer == NULL) { + npy_free_cache(indbuffer, N * sizeof(npy_intp)); + goto fail; + } + swaps = malloc(n*sizeof(int)); + for (j = 0; j < n; j++) { + swaps[j] = PyArray_ISBYTESWAPPED(mps[j]); + } + while (size--) { + iptr = (npy_intp *)indbuffer; + for (i = 0; i < N; i++) { + *iptr++ = i; + } + for (j = 0; j < n; j++) { + int rcode; + elsize = PyArray_DESCR(mps[j])->elsize; + astride = PyArray_STRIDES(mps[j])[axis]; + argsort = PyArray_DESCR(mps[j])->f->argsort[NPY_MERGESORT]; + if(argsort == NULL) { + argsort = npy_amergesort; + } + _unaligned_strided_byte_copy(valbuffer, (npy_intp) elsize, + its[j]->dataptr, astride, N, elsize); + if (swaps[j]) { + _strided_byte_swap(valbuffer, (npy_intp) elsize, N, elsize); + } + rcode = argsort(valbuffer, (npy_intp *)indbuffer, N, mps[j]); +#if defined(NPY_PY3K) + if (rcode < 0 || (PyDataType_REFCHK(PyArray_DESCR(mps[j])) + && PyErr_Occurred())) { +#else + if (rcode < 0) { +#endif + npy_free_cache(valbuffer, N * maxelsize); + npy_free_cache(indbuffer, N * sizeof(npy_intp)); + free(swaps); + goto fail; + } + PyArray_ITER_NEXT(its[j]); + } + _unaligned_strided_byte_copy(rit->dataptr, rstride, indbuffer, + sizeof(npy_intp), N, sizeof(npy_intp)); + PyArray_ITER_NEXT(rit); + } + npy_free_cache(valbuffer, N * maxelsize); + npy_free_cache(indbuffer, N * sizeof(npy_intp)); + free(swaps); + } + else { + while (size--) { + iptr = (npy_intp *)rit->dataptr; + for (i = 0; i < N; i++) { + *iptr++ = i; + } + for (j = 0; j < n; j++) { + int rcode; + argsort = PyArray_DESCR(mps[j])->f->argsort[NPY_MERGESORT]; + if(argsort == NULL) { + argsort = npy_amergesort; + } + rcode = argsort(its[j]->dataptr, + (npy_intp *)rit->dataptr, N, mps[j]); +#if defined(NPY_PY3K) + if (rcode < 0 || (PyDataType_REFCHK(PyArray_DESCR(mps[j])) + && PyErr_Occurred())) { +#else + if (rcode < 0) { +#endif + goto fail; + } + PyArray_ITER_NEXT(its[j]); + } + PyArray_ITER_NEXT(rit); + } + } + + if (!object) { + NPY_END_THREADS; + } + + finish: + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + Py_XDECREF(its[i]); + } + Py_XDECREF(rit); + PyArray_free(mps); + PyArray_free(its); + return (PyObject *)ret; + + fail: + NPY_END_THREADS; + if (!PyErr_Occurred()) { + /* Out of memory during sorting or buffer creation */ + PyErr_NoMemory(); + } + Py_XDECREF(rit); + Py_XDECREF(ret); + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + Py_XDECREF(its[i]); + } + PyArray_free(mps); + PyArray_free(its); + return NULL; +} + + +/*NUMPY_API + * + * Search the sorted array op1 for the location of the items in op2. The + * result is an array of indexes, one for each element in op2, such that if + * the item were to be inserted in op1 just before that index the array + * would still be in sorted order. + * + * Parameters + * ---------- + * op1 : PyArrayObject * + * Array to be searched, must be 1-D. + * op2 : PyObject * + * Array of items whose insertion indexes in op1 are wanted + * side : {NPY_SEARCHLEFT, NPY_SEARCHRIGHT} + * If NPY_SEARCHLEFT, return first valid insertion indexes + * If NPY_SEARCHRIGHT, return last valid insertion indexes + * perm : PyObject * + * Permutation array that sorts op1 (optional) + * + * Returns + * ------- + * ret : PyObject * + * New reference to npy_intp array containing indexes where items in op2 + * could be validly inserted into op1. NULL on error. + * + * Notes + * ----- + * Binary search is used to find the indexes. + */ +NPY_NO_EXPORT PyObject * +PyArray_SearchSorted(PyArrayObject *op1, PyObject *op2, + NPY_SEARCHSIDE side, PyObject *perm) +{ + PyArrayObject *ap1 = NULL; + PyArrayObject *ap2 = NULL; + PyArrayObject *ap3 = NULL; + PyArrayObject *sorter = NULL; + PyArrayObject *ret = NULL; + PyArray_Descr *dtype; + int ap1_flags = NPY_ARRAY_NOTSWAPPED | NPY_ARRAY_ALIGNED; + PyArray_BinSearchFunc *binsearch = NULL; + PyArray_ArgBinSearchFunc *argbinsearch = NULL; + NPY_BEGIN_THREADS_DEF; + + /* Find common type */ + dtype = PyArray_DescrFromObject((PyObject *)op2, PyArray_DESCR(op1)); + if (dtype == NULL) { + return NULL; + } + /* refs to dtype we own = 1 */ + + /* Look for binary search function */ + if (perm) { + argbinsearch = get_argbinsearch_func(dtype, side); + } + else { + binsearch = get_binsearch_func(dtype, side); + } + if (binsearch == NULL && argbinsearch == NULL) { + PyErr_SetString(PyExc_TypeError, "compare not supported for type"); + /* refs to dtype we own = 1 */ + Py_DECREF(dtype); + /* refs to dtype we own = 0 */ + return NULL; + } + + /* need ap2 as contiguous array and of right type */ + /* refs to dtype we own = 1 */ + Py_INCREF(dtype); + /* refs to dtype we own = 2 */ + ap2 = (PyArrayObject *)PyArray_CheckFromAny(op2, dtype, + 0, 0, + NPY_ARRAY_CARRAY_RO | NPY_ARRAY_NOTSWAPPED, + NULL); + /* refs to dtype we own = 1, array creation steals one even on failure */ + if (ap2 == NULL) { + Py_DECREF(dtype); + /* refs to dtype we own = 0 */ + return NULL; + } + + /* + * If the needle (ap2) is larger than the haystack (op1) we copy the + * haystack to a contiguous array for improved cache utilization. + */ + if (PyArray_SIZE(ap2) > PyArray_SIZE(op1)) { + ap1_flags |= NPY_ARRAY_CARRAY_RO; + } + ap1 = (PyArrayObject *)PyArray_CheckFromAny((PyObject *)op1, dtype, + 1, 1, ap1_flags, NULL); + /* refs to dtype we own = 0, array creation steals one even on failure */ + if (ap1 == NULL) { + goto fail; + } + + if (perm) { + /* need ap3 as a 1D aligned, not swapped, array of right type */ + ap3 = (PyArrayObject *)PyArray_CheckFromAny(perm, NULL, + 1, 1, + NPY_ARRAY_ALIGNED | NPY_ARRAY_NOTSWAPPED, + NULL); + if (ap3 == NULL) { + PyErr_SetString(PyExc_TypeError, + "could not parse sorter argument"); + goto fail; + } + if (!PyArray_ISINTEGER(ap3)) { + PyErr_SetString(PyExc_TypeError, + "sorter must only contain integers"); + goto fail; + } + /* convert to known integer size */ + sorter = (PyArrayObject *)PyArray_FromArray(ap3, + PyArray_DescrFromType(NPY_INTP), + NPY_ARRAY_ALIGNED | NPY_ARRAY_NOTSWAPPED); + if (sorter == NULL) { + PyErr_SetString(PyExc_ValueError, + "could not parse sorter argument"); + goto fail; + } + if (PyArray_SIZE(sorter) != PyArray_SIZE(ap1)) { + PyErr_SetString(PyExc_ValueError, + "sorter.size must equal a.size"); + goto fail; + } + } + + /* ret is a contiguous array of intp type to hold returned indexes */ + ret = (PyArrayObject *)PyArray_New(&PyArray_Type, PyArray_NDIM(ap2), + PyArray_DIMS(ap2), NPY_INTP, + NULL, NULL, 0, 0, (PyObject *)ap2); + if (ret == NULL) { + goto fail; + } + + if (ap3 == NULL) { + /* do regular binsearch */ + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ap2)); + binsearch((const char *)PyArray_DATA(ap1), + (const char *)PyArray_DATA(ap2), + (char *)PyArray_DATA(ret), + PyArray_SIZE(ap1), PyArray_SIZE(ap2), + PyArray_STRIDES(ap1)[0], PyArray_DESCR(ap2)->elsize, + NPY_SIZEOF_INTP, ap2); + NPY_END_THREADS_DESCR(PyArray_DESCR(ap2)); + } + else { + /* do binsearch with a sorter array */ + int error = 0; + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ap2)); + error = argbinsearch((const char *)PyArray_DATA(ap1), + (const char *)PyArray_DATA(ap2), + (const char *)PyArray_DATA(sorter), + (char *)PyArray_DATA(ret), + PyArray_SIZE(ap1), PyArray_SIZE(ap2), + PyArray_STRIDES(ap1)[0], + PyArray_DESCR(ap2)->elsize, + PyArray_STRIDES(sorter)[0], NPY_SIZEOF_INTP, ap2); + NPY_END_THREADS_DESCR(PyArray_DESCR(ap2)); + if (error < 0) { + PyErr_SetString(PyExc_ValueError, + "Sorter index out of range."); + goto fail; + } + Py_DECREF(ap3); + Py_DECREF(sorter); + } + Py_DECREF(ap1); + Py_DECREF(ap2); + return (PyObject *)ret; + + fail: + Py_XDECREF(ap1); + Py_XDECREF(ap2); + Py_XDECREF(ap3); + Py_XDECREF(sorter); + Py_XDECREF(ret); + return NULL; +} + +/*NUMPY_API + * Diagonal + * + * In NumPy versions prior to 1.7, this function always returned a copy of + * the diagonal array. In 1.7, the code has been updated to compute a view + * onto 'self', but it still copies this array before returning, as well as + * setting the internal WARN_ON_WRITE flag. In a future version, it will + * simply return a view onto self. + */ +NPY_NO_EXPORT PyObject * +PyArray_Diagonal(PyArrayObject *self, int offset, int axis1, int axis2) +{ + int i, idim, ndim = PyArray_NDIM(self); + npy_intp *strides; + npy_intp stride1, stride2, offset_stride; + npy_intp *shape, dim1, dim2; + + char *data; + npy_intp diag_size; + PyArray_Descr *dtype; + PyObject *ret; + npy_intp ret_shape[NPY_MAXDIMS], ret_strides[NPY_MAXDIMS]; + + if (ndim < 2) { + PyErr_SetString(PyExc_ValueError, + "diag requires an array of at least two dimensions"); + return NULL; + } + + /* Handle negative axes with standard Python indexing rules */ + if (axis1 < 0) { + axis1 += ndim; + } + if (axis2 < 0) { + axis2 += ndim; + } + + /* Error check the two axes */ + if (axis1 == axis2) { + PyErr_SetString(PyExc_ValueError, + "axis1 and axis2 cannot be the same"); + return NULL; + } + else if (axis1 < 0 || axis1 >= ndim || axis2 < 0 || axis2 >= ndim) { + PyErr_Format(PyExc_ValueError, + "axis1(=%d) and axis2(=%d) " + "must be within range (ndim=%d)", + axis1, axis2, ndim); + return NULL; + } + + /* Get the shape and strides of the two axes */ + shape = PyArray_SHAPE(self); + dim1 = shape[axis1]; + dim2 = shape[axis2]; + strides = PyArray_STRIDES(self); + stride1 = strides[axis1]; + stride2 = strides[axis2]; + + /* Compute the data pointers and diag_size for the view */ + data = PyArray_DATA(self); + if (offset >= 0) { + offset_stride = stride2; + dim2 -= offset; + } + else { + offset = -offset; + offset_stride = stride1; + dim1 -= offset; + } + diag_size = dim2 < dim1 ? dim2 : dim1; + if (diag_size < 0) { + diag_size = 0; + } + else { + data += offset * offset_stride; + } + + /* Build the new shape and strides for the main data */ + i = 0; + for (idim = 0; idim < ndim; ++idim) { + if (idim != axis1 && idim != axis2) { + ret_shape[i] = shape[idim]; + ret_strides[i] = strides[idim]; + ++i; + } + } + ret_shape[ndim-2] = diag_size; + ret_strides[ndim-2] = stride1 + stride2; + + /* Create the diagonal view */ + dtype = PyArray_DTYPE(self); + Py_INCREF(dtype); + ret = PyArray_NewFromDescr(Py_TYPE(self), + dtype, + ndim-1, ret_shape, + ret_strides, + data, + PyArray_FLAGS(self), + (PyObject *)self); + if (ret == NULL) { + return NULL; + } + Py_INCREF(self); + if (PyArray_SetBaseObject((PyArrayObject *)ret, (PyObject *)self) < 0) { + Py_DECREF(ret); + return NULL; + } + + /* + * For numpy 1.9 the diagonal view is not writeable. + * This line needs to be removed in 1.10. + */ + PyArray_CLEARFLAGS((PyArrayObject *)ret, NPY_ARRAY_WRITEABLE); + + return ret; +} + +/*NUMPY_API + * Compress + */ +NPY_NO_EXPORT PyObject * +PyArray_Compress(PyArrayObject *self, PyObject *condition, int axis, + PyArrayObject *out) +{ + PyArrayObject *cond; + PyObject *res, *ret; + + if (PyArray_Check(condition)) { + cond = (PyArrayObject *)condition; + Py_INCREF(cond); + } + else { + PyArray_Descr *dtype = PyArray_DescrFromType(NPY_BOOL); + if (dtype == NULL) { + return NULL; + } + cond = (PyArrayObject *)PyArray_FromAny(condition, dtype, + 0, 0, 0, NULL); + if (cond == NULL) { + return NULL; + } + } + + if (PyArray_NDIM(cond) != 1) { + Py_DECREF(cond); + PyErr_SetString(PyExc_ValueError, + "condition must be a 1-d array"); + return NULL; + } + + res = PyArray_Nonzero(cond); + Py_DECREF(cond); + if (res == NULL) { + return res; + } + ret = PyArray_TakeFrom(self, PyTuple_GET_ITEM(res, 0), axis, + out, NPY_RAISE); + Py_DECREF(res); + return ret; +} + +/* + * count number of nonzero bytes in 48 byte block + * w must be aligned to 8 bytes + * + * even though it uses 64 bit types its faster than the bytewise sum on 32 bit + * but a 32 bit type version would make it even faster on these platforms + */ +static NPY_INLINE npy_intp +count_nonzero_bytes_384(const npy_uint64 * w) +{ + const npy_uint64 w1 = w[0]; + const npy_uint64 w2 = w[1]; + const npy_uint64 w3 = w[2]; + const npy_uint64 w4 = w[3]; + const npy_uint64 w5 = w[4]; + const npy_uint64 w6 = w[5]; + npy_intp r; + + /* + * last part of sideways add popcount, first three bisections can be + * skipped as we are dealing with bytes. + * multiplication equivalent to (x + (x>>8) + (x>>16) + (x>>24)) & 0xFF + * multiplication overflow well defined for unsigned types. + * w1 + w2 guaranteed to not overflow as we only have 0 and 1 data. + */ + r = ((w1 + w2 + w3 + w4 + w5 + w6) * 0x0101010101010101ULL) >> 56ULL; + + /* + * bytes not exclusively 0 or 1, sum them individually. + * should only happen if one does weird stuff with views or external + * buffers. + * Doing this after the optimistic computation allows saving registers and + * better pipelining + */ + if (NPY_UNLIKELY( + ((w1 | w2 | w3 | w4 | w5 | w6) & 0xFEFEFEFEFEFEFEFEULL) != 0)) { + /* reload from pointer to avoid a unnecessary stack spill with gcc */ + const char * c = (const char *)w; + npy_uintp i, count = 0; + for (i = 0; i < 48; i++) { + count += (c[i] != 0); + } + return count; + } + + return r; +} + +/* + * Counts the number of True values in a raw boolean array. This + * is a low-overhead function which does no heap allocations. + * + * Returns -1 on error. + */ +NPY_NO_EXPORT npy_intp +count_boolean_trues(int ndim, char *data, npy_intp *ashape, npy_intp *astrides) +{ + int idim; + npy_intp shape[NPY_MAXDIMS], strides[NPY_MAXDIMS]; + npy_intp i, coord[NPY_MAXDIMS]; + npy_intp count = 0; + NPY_BEGIN_THREADS_DEF; + + /* Use raw iteration with no heap memory allocation */ + if (PyArray_PrepareOneRawArrayIter( + ndim, ashape, + data, astrides, + &ndim, shape, + &data, strides) < 0) { + return -1; + } + + /* Handle zero-sized array */ + if (shape[0] == 0) { + return 0; + } + + NPY_BEGIN_THREADS_THRESHOLDED(shape[0]); + + /* Special case for contiguous inner loop */ + if (strides[0] == 1) { + NPY_RAW_ITER_START(idim, ndim, coord, shape) { + /* Process the innermost dimension */ + const char *d = data; + const char *e = data + shape[0]; + if (NPY_CPU_HAVE_UNALIGNED_ACCESS || + npy_is_aligned(d, sizeof(npy_uint64))) { + npy_uintp stride = 6 * sizeof(npy_uint64); + for (; d < e - (shape[0] % stride); d += stride) { + count += count_nonzero_bytes_384((const npy_uint64 *)d); + } + } + for (; d < e; ++d) { + count += (*d != 0); + } + } NPY_RAW_ITER_ONE_NEXT(idim, ndim, coord, shape, data, strides); + } + /* General inner loop */ + else { + NPY_RAW_ITER_START(idim, ndim, coord, shape) { + char *d = data; + /* Process the innermost dimension */ + for (i = 0; i < shape[0]; ++i, d += strides[0]) { + count += (*d != 0); + } + } NPY_RAW_ITER_ONE_NEXT(idim, ndim, coord, shape, data, strides); + } + + NPY_END_THREADS; + + return count; +} + +/*NUMPY_API + * Counts the number of non-zero elements in the array. + * + * Returns -1 on error. + */ +NPY_NO_EXPORT npy_intp +PyArray_CountNonzero(PyArrayObject *self) +{ + PyArray_NonzeroFunc *nonzero; + char *data; + npy_intp stride, count; + npy_intp nonzero_count = 0; + int needs_api = 0; + PyArray_Descr *dtype; + + NpyIter *iter; + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strideptr, *innersizeptr; + NPY_BEGIN_THREADS_DEF; + + /* Special low-overhead version specific to the boolean type */ + dtype = PyArray_DESCR(self); + if (dtype->type_num == NPY_BOOL) { + return count_boolean_trues(PyArray_NDIM(self), PyArray_DATA(self), + PyArray_DIMS(self), PyArray_STRIDES(self)); + } + nonzero = PyArray_DESCR(self)->f->nonzero; + + /* If it's a trivial one-dimensional loop, don't use an iterator */ + if (PyArray_TRIVIALLY_ITERABLE(self)) { + needs_api = PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI); + PyArray_PREPARE_TRIVIAL_ITERATION(self, count, data, stride); + + if (needs_api){ + while (count--) { + if (nonzero(data, self)) { + ++nonzero_count; + } + if (PyErr_Occurred()) { + return -1; + } + data += stride; + } + } + else { + NPY_BEGIN_THREADS_THRESHOLDED(count); + while (count--) { + if (nonzero(data, self)) { + ++nonzero_count; + } + data += stride; + } + NPY_END_THREADS; + } + + return nonzero_count; + } + + /* + * If the array has size zero, return zero (the iterator rejects + * size zero arrays) + */ + if (PyArray_SIZE(self) == 0) { + return 0; + } + + /* + * Otherwise create and use an iterator to count the nonzeros. + */ + iter = NpyIter_New(self, NPY_ITER_READONLY | + NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_REFS_OK, + NPY_KEEPORDER, NPY_NO_CASTING, + NULL); + if (iter == NULL) { + return -1; + } + needs_api = NpyIter_IterationNeedsAPI(iter); + + /* Get the pointers for inner loop iteration */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + return -1; + } + + NPY_BEGIN_THREADS_NDITER(iter); + + dataptr = NpyIter_GetDataPtrArray(iter); + strideptr = NpyIter_GetInnerStrideArray(iter); + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + /* Iterate over all the elements to count the nonzeros */ + do { + data = *dataptr; + stride = *strideptr; + count = *innersizeptr; + + while (count--) { + if (nonzero(data, self)) { + ++nonzero_count; + } + if (needs_api && PyErr_Occurred()) { + nonzero_count = -1; + goto finish; + } + data += stride; + } + + } while(iternext(iter)); + +finish: + NPY_END_THREADS; + + NpyIter_Deallocate(iter); + + return nonzero_count; +} + +/*NUMPY_API + * Nonzero + * + * TODO: In NumPy 2.0, should make the iteration order a parameter. + */ +NPY_NO_EXPORT PyObject * +PyArray_Nonzero(PyArrayObject *self) +{ + int i, ndim = PyArray_NDIM(self); + PyArrayObject *ret = NULL; + PyObject *ret_tuple; + npy_intp ret_dims[2]; + PyArray_NonzeroFunc *nonzero = PyArray_DESCR(self)->f->nonzero; + npy_intp nonzero_count; + + NpyIter *iter; + NpyIter_IterNextFunc *iternext; + NpyIter_GetMultiIndexFunc *get_multi_index; + char **dataptr; + int is_empty = 0; + + /* + * First count the number of non-zeros in 'self'. + */ + nonzero_count = PyArray_CountNonzero(self); + if (nonzero_count < 0) { + return NULL; + } + + /* Allocate the result as a 2D array */ + ret_dims[0] = nonzero_count; + ret_dims[1] = (ndim == 0) ? 1 : ndim; + ret = (PyArrayObject *)PyArray_New(&PyArray_Type, 2, ret_dims, + NPY_INTP, NULL, NULL, 0, 0, + NULL); + if (ret == NULL) { + return NULL; + } + + /* If it's a one-dimensional result, don't use an iterator */ + if (ndim <= 1) { + npy_intp * multi_index = (npy_intp *)PyArray_DATA(ret); + char * data = PyArray_BYTES(self); + npy_intp stride = (ndim == 0) ? 0 : PyArray_STRIDE(self, 0); + npy_intp count = (ndim == 0) ? 1 : PyArray_DIM(self, 0); + NPY_BEGIN_THREADS_DEF; + + /* nothing to do */ + if (nonzero_count == 0) { + goto finish; + } + + NPY_BEGIN_THREADS_THRESHOLDED(count); + + /* avoid function call for bool */ + if (PyArray_ISBOOL(self)) { + /* + * use fast memchr variant for sparse data, see gh-4370 + * the fast bool count is followed by this sparse path is faster + * than combining the two loops, even for larger arrays + */ + if (((double)nonzero_count / count) <= 0.1) { + npy_intp subsize; + npy_intp j = 0; + while (1) { + npy_memchr(data + j * stride, 0, stride, count - j, + &subsize, 1); + j += subsize; + if (j >= count) { + break; + } + *multi_index++ = j++; + } + } + else { + npy_intp j; + for (j = 0; j < count; ++j) { + if (*data != 0) { + *multi_index++ = j; + } + data += stride; + } + } + } + else { + npy_intp j; + for (j = 0; j < count; ++j) { + if (nonzero(data, self)) { + *multi_index++ = j; + } + data += stride; + } + } + + NPY_END_THREADS; + + goto finish; + } + + /* + * Build an iterator tracking a multi-index, in C order. + */ + iter = NpyIter_New(self, NPY_ITER_READONLY | + NPY_ITER_MULTI_INDEX | + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_REFS_OK, + NPY_CORDER, NPY_NO_CASTING, + NULL); + + if (iter == NULL) { + Py_DECREF(ret); + return NULL; + } + + if (NpyIter_GetIterSize(iter) != 0) { + npy_intp * multi_index; + NPY_BEGIN_THREADS_DEF; + /* Get the pointers for inner loop iteration */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + Py_DECREF(ret); + return NULL; + } + get_multi_index = NpyIter_GetGetMultiIndex(iter, NULL); + if (get_multi_index == NULL) { + NpyIter_Deallocate(iter); + Py_DECREF(ret); + return NULL; + } + + NPY_BEGIN_THREADS_NDITER(iter); + + dataptr = NpyIter_GetDataPtrArray(iter); + + multi_index = (npy_intp *)PyArray_DATA(ret); + + /* Get the multi-index for each non-zero element */ + if (PyArray_ISBOOL(self)) { + /* avoid function call for bool */ + do { + if (**dataptr != 0) { + get_multi_index(iter, multi_index); + multi_index += ndim; + } + } while(iternext(iter)); + } + else { + do { + if (nonzero(*dataptr, self)) { + get_multi_index(iter, multi_index); + multi_index += ndim; + } + } while(iternext(iter)); + } + + NPY_END_THREADS; + } + + NpyIter_Deallocate(iter); + +finish: + /* Treat zero-dimensional as shape (1,) */ + if (ndim == 0) { + ndim = 1; + } + + ret_tuple = PyTuple_New(ndim); + if (ret_tuple == NULL) { + Py_DECREF(ret); + return NULL; + } + + for (i = 0; i < PyArray_NDIM(ret); ++i) { + if (PyArray_DIMS(ret)[i] == 0) { + is_empty = 1; + break; + } + } + + /* Create views into ret, one for each dimension */ + for (i = 0; i < ndim; ++i) { + npy_intp stride = ndim * NPY_SIZEOF_INTP; + /* the result is an empty array, the view must point to valid memory */ + npy_intp data_offset = is_empty ? 0 : i * NPY_SIZEOF_INTP; + + PyArrayObject *view = (PyArrayObject *)PyArray_New(Py_TYPE(ret), 1, + &nonzero_count, NPY_INTP, &stride, + PyArray_BYTES(ret) + data_offset, + 0, PyArray_FLAGS(ret), (PyObject *)ret); + if (view == NULL) { + Py_DECREF(ret); + Py_DECREF(ret_tuple); + return NULL; + } + Py_INCREF(ret); + if (PyArray_SetBaseObject(view, (PyObject *)ret) < 0) { + Py_DECREF(ret); + Py_DECREF(ret_tuple); + return NULL; + } + PyTuple_SET_ITEM(ret_tuple, i, (PyObject *)view); + } + Py_DECREF(ret); + + return ret_tuple; +} + +/* + * Gets a single item from the array, based on a single multi-index + * array of values, which must be of length PyArray_NDIM(self). + */ +NPY_NO_EXPORT PyObject * +PyArray_MultiIndexGetItem(PyArrayObject *self, npy_intp *multi_index) +{ + int idim, ndim = PyArray_NDIM(self); + char *data = PyArray_DATA(self); + npy_intp *shape = PyArray_SHAPE(self); + npy_intp *strides = PyArray_STRIDES(self); + + /* Get the data pointer */ + for (idim = 0; idim < ndim; ++idim) { + npy_intp shapevalue = shape[idim]; + npy_intp ind = multi_index[idim]; + + if (check_and_adjust_index(&ind, shapevalue, idim, NULL) < 0) { + return NULL; + } + data += ind * strides[idim]; + } + + return PyArray_GETITEM(self, data); +} + +/* + * Sets a single item in the array, based on a single multi-index + * array of values, which must be of length PyArray_NDIM(self). + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_MultiIndexSetItem(PyArrayObject *self, npy_intp *multi_index, + PyObject *obj) +{ + int idim, ndim = PyArray_NDIM(self); + char *data = PyArray_DATA(self); + npy_intp *shape = PyArray_SHAPE(self); + npy_intp *strides = PyArray_STRIDES(self); + + /* Get the data pointer */ + for (idim = 0; idim < ndim; ++idim) { + npy_intp shapevalue = shape[idim]; + npy_intp ind = multi_index[idim]; + + if (check_and_adjust_index(&ind, shapevalue, idim, NULL) < 0) { + return -1; + } + data += ind * strides[idim]; + } + + return PyArray_SETITEM(self, data, obj); +} diff --git a/numpy/core/src/multiarray/item_selection.h b/numpy/core/src/multiarray/item_selection.h new file mode 100644 index 0000000..90bb510 --- /dev/null +++ b/numpy/core/src/multiarray/item_selection.h @@ -0,0 +1,30 @@ +#ifndef _NPY_PRIVATE__ITEM_SELECTION_H_ +#define _NPY_PRIVATE__ITEM_SELECTION_H_ + +/* + * Counts the number of True values in a raw boolean array. This + * is a low-overhead function which does no heap allocations. + * + * Returns -1 on error. + */ +NPY_NO_EXPORT npy_intp +count_boolean_trues(int ndim, char *data, npy_intp *ashape, npy_intp *astrides); + +/* + * Gets a single item from the array, based on a single multi-index + * array of values, which must be of length PyArray_NDIM(self). + */ +NPY_NO_EXPORT PyObject * +PyArray_MultiIndexGetItem(PyArrayObject *self, npy_intp *multi_index); + +/* + * Sets a single item in the array, based on a single multi-index + * array of values, which must be of length PyArray_NDIM(self). + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_MultiIndexSetItem(PyArrayObject *self, npy_intp *multi_index, + PyObject *obj); + +#endif diff --git a/numpy/core/src/multiarray/iterators.c b/numpy/core/src/multiarray/iterators.c new file mode 100644 index 0000000..9cd5f03 --- /dev/null +++ b/numpy/core/src/multiarray/iterators.c @@ -0,0 +1,2114 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "arrayobject.h" +#include "iterators.h" +#include "ctors.h" +#include "common.h" + +#define NEWAXIS_INDEX -1 +#define ELLIPSIS_INDEX -2 +#define SINGLE_INDEX -3 + +/* + * Tries to convert 'o' into an npy_intp interpreted as an + * index. Returns 1 if it was successful, 0 otherwise. Does + * not set an exception. + */ +static int +coerce_index(PyObject *o, npy_intp *v) +{ + *v = PyArray_PyIntAsIntp(o); + + if ((*v) == -1 && PyErr_Occurred()) { + PyErr_Clear(); + return 0; + } + return 1; +} + +/* + * This function converts one element of the indexing tuple + * into a step size and a number of steps, returning the + * starting index. Non-slices are signalled in 'n_steps', + * as NEWAXIS_INDEX, ELLIPSIS_INDEX, or SINGLE_INDEX. + */ +NPY_NO_EXPORT npy_intp +parse_index_entry(PyObject *op, npy_intp *step_size, + npy_intp *n_steps, npy_intp max, + int axis, int check_index) +{ + npy_intp i; + + if (op == Py_None) { + *n_steps = NEWAXIS_INDEX; + i = 0; + } + else if (op == Py_Ellipsis) { + *n_steps = ELLIPSIS_INDEX; + i = 0; + } + else if (PySlice_Check(op)) { + npy_intp stop; + if (NpySlice_GetIndicesEx(op, max, &i, &stop, step_size, n_steps) < 0) { + goto fail; + } + if (*n_steps <= 0) { + *n_steps = 0; + *step_size = 1; + i = 0; + } + } + else if (coerce_index(op, &i)) { + *n_steps = SINGLE_INDEX; + *step_size = 0; + if (check_index) { + if (check_and_adjust_index(&i, max, axis, NULL) < 0) { + goto fail; + } + } + } + else { + PyErr_SetString(PyExc_IndexError, + "each index entry must be either a " + "slice, an integer, Ellipsis, or " + "newaxis"); + goto fail; + } + return i; + + fail: + return -1; +} + + +/* + * Parses an index that has no fancy indexing. Populates + * out_dimensions, out_strides, and out_offset. + */ +NPY_NO_EXPORT int +parse_index(PyArrayObject *self, PyObject *op, + npy_intp *out_dimensions, + npy_intp *out_strides, + npy_intp *out_offset, + int check_index) +{ + int i, j, n; + int nd_old, nd_new, n_add, n_ellipsis; + npy_intp n_steps, start, offset, step_size; + PyObject *op1 = NULL; + int is_slice; + + if (PySlice_Check(op) || op == Py_Ellipsis || op == Py_None) { + n = 1; + op1 = op; + Py_INCREF(op); + /* this relies on the fact that n==1 for loop below */ + is_slice = 1; + } + else { + if (!PySequence_Check(op)) { + PyErr_SetString(PyExc_IndexError, + "index must be either an int " + "or a sequence"); + return -1; + } + n = PySequence_Length(op); + is_slice = 0; + } + + nd_old = nd_new = 0; + + offset = 0; + for (i = 0; i < n; i++) { + if (!is_slice) { + op1 = PySequence_GetItem(op, i); + if (op1 == NULL) { + return -1; + } + } + start = parse_index_entry(op1, &step_size, &n_steps, + nd_old < PyArray_NDIM(self) ? + PyArray_DIMS(self)[nd_old] : 0, + nd_old, check_index ? + nd_old < PyArray_NDIM(self) : 0); + Py_DECREF(op1); + if (start == -1) { + break; + } + if (n_steps == NEWAXIS_INDEX) { + out_dimensions[nd_new] = 1; + out_strides[nd_new] = 0; + nd_new++; + } + else if (n_steps == ELLIPSIS_INDEX) { + for (j = i + 1, n_ellipsis = 0; j < n; j++) { + op1 = PySequence_GetItem(op, j); + if (op1 == Py_None) { + n_ellipsis++; + } + Py_DECREF(op1); + } + n_add = PyArray_NDIM(self)-(n-i-n_ellipsis-1+nd_old); + if (n_add < 0) { + PyErr_SetString(PyExc_IndexError, "too many indices"); + return -1; + } + for (j = 0; j < n_add; j++) { + out_dimensions[nd_new] = PyArray_DIMS(self)[nd_old]; + out_strides[nd_new] = PyArray_STRIDES(self)[nd_old]; + nd_new++; nd_old++; + } + } + else { + if (nd_old >= PyArray_NDIM(self)) { + PyErr_SetString(PyExc_IndexError, "too many indices"); + return -1; + } + offset += PyArray_STRIDES(self)[nd_old]*start; + nd_old++; + if (n_steps != SINGLE_INDEX) { + out_dimensions[nd_new] = n_steps; + out_strides[nd_new] = step_size * + PyArray_STRIDES(self)[nd_old-1]; + nd_new++; + } + } + } + if (i < n) { + return -1; + } + n_add = PyArray_NDIM(self)-nd_old; + for (j = 0; j < n_add; j++) { + out_dimensions[nd_new] = PyArray_DIMS(self)[nd_old]; + out_strides[nd_new] = PyArray_STRIDES(self)[nd_old]; + nd_new++; + nd_old++; + } + *out_offset = offset; + return nd_new; +} + + +/*********************** Element-wise Array Iterator ***********************/ +/* Aided by Peter J. Verveer's nd_image package and numpy's arraymap ****/ +/* and Python's array iterator ***/ + +/* get the dataptr from its current coordinates for simple iterator */ +static char* +get_ptr_simple(PyArrayIterObject* iter, npy_intp *coordinates) +{ + npy_intp i; + char *ret; + + ret = PyArray_DATA(iter->ao); + + for(i = 0; i < PyArray_NDIM(iter->ao); ++i) { + ret += coordinates[i] * iter->strides[i]; + } + + return ret; +} + +/* + * This is common initialization code between PyArrayIterObject and + * PyArrayNeighborhoodIterObject + * + * Increase ao refcount + */ +static PyObject * +array_iter_base_init(PyArrayIterObject *it, PyArrayObject *ao) +{ + int nd, i; + + nd = PyArray_NDIM(ao); + PyArray_UpdateFlags(ao, NPY_ARRAY_C_CONTIGUOUS); + if (PyArray_ISCONTIGUOUS(ao)) { + it->contiguous = 1; + } + else { + it->contiguous = 0; + } + Py_INCREF(ao); + it->ao = ao; + it->size = PyArray_SIZE(ao); + it->nd_m1 = nd - 1; + if (nd != 0) { + it->factors[nd-1] = 1; + } + for (i = 0; i < nd; i++) { + it->dims_m1[i] = PyArray_DIMS(ao)[i] - 1; + it->strides[i] = PyArray_STRIDES(ao)[i]; + it->backstrides[i] = it->strides[i] * it->dims_m1[i]; + if (i > 0) { + it->factors[nd-i-1] = it->factors[nd-i] * PyArray_DIMS(ao)[nd-i]; + } + it->bounds[i][0] = 0; + it->bounds[i][1] = PyArray_DIMS(ao)[i] - 1; + it->limits[i][0] = 0; + it->limits[i][1] = PyArray_DIMS(ao)[i] - 1; + it->limits_sizes[i] = it->limits[i][1] - it->limits[i][0] + 1; + } + + it->translate = &get_ptr_simple; + PyArray_ITER_RESET(it); + + return (PyObject *)it; +} + +static void +array_iter_base_dealloc(PyArrayIterObject *it) +{ + Py_XDECREF(it->ao); +} + +/*NUMPY_API + * Get Iterator. + */ +NPY_NO_EXPORT PyObject * +PyArray_IterNew(PyObject *obj) +{ + PyArrayIterObject *it; + PyArrayObject *ao; + + if (!PyArray_Check(obj)) { + PyErr_BadInternalCall(); + return NULL; + } + ao = (PyArrayObject *)obj; + + it = (PyArrayIterObject *)PyArray_malloc(sizeof(PyArrayIterObject)); + PyObject_Init((PyObject *)it, &PyArrayIter_Type); + /* it = PyObject_New(PyArrayIterObject, &PyArrayIter_Type);*/ + if (it == NULL) { + return NULL; + } + + array_iter_base_init(it, ao); + return (PyObject *)it; +} + +/*NUMPY_API + * Get Iterator broadcast to a particular shape + */ +NPY_NO_EXPORT PyObject * +PyArray_BroadcastToShape(PyObject *obj, npy_intp *dims, int nd) +{ + PyArrayIterObject *it; + int i, diff, j, compat, k; + PyArrayObject *ao = (PyArrayObject *)obj; + + if (PyArray_NDIM(ao) > nd) { + goto err; + } + compat = 1; + diff = j = nd - PyArray_NDIM(ao); + for (i = 0; i < PyArray_NDIM(ao); i++, j++) { + if (PyArray_DIMS(ao)[i] == 1) { + continue; + } + if (PyArray_DIMS(ao)[i] != dims[j]) { + compat = 0; + break; + } + } + if (!compat) { + goto err; + } + it = (PyArrayIterObject *)PyArray_malloc(sizeof(PyArrayIterObject)); + if (it == NULL) { + return NULL; + } + PyObject_Init((PyObject *)it, &PyArrayIter_Type); + + PyArray_UpdateFlags(ao, NPY_ARRAY_C_CONTIGUOUS); + if (PyArray_ISCONTIGUOUS(ao)) { + it->contiguous = 1; + } + else { + it->contiguous = 0; + } + Py_INCREF(ao); + it->ao = ao; + it->size = PyArray_MultiplyList(dims, nd); + it->nd_m1 = nd - 1; + if (nd != 0) { + it->factors[nd-1] = 1; + } + for (i = 0; i < nd; i++) { + it->dims_m1[i] = dims[i] - 1; + k = i - diff; + if ((k < 0) || PyArray_DIMS(ao)[k] != dims[i]) { + it->contiguous = 0; + it->strides[i] = 0; + } + else { + it->strides[i] = PyArray_STRIDES(ao)[k]; + } + it->backstrides[i] = it->strides[i] * it->dims_m1[i]; + if (i > 0) { + it->factors[nd-i-1] = it->factors[nd-i] * dims[nd-i]; + } + } + PyArray_ITER_RESET(it); + return (PyObject *)it; + + err: + PyErr_SetString(PyExc_ValueError, "array is not broadcastable to "\ + "correct shape"); + return NULL; +} + + + + + +/*NUMPY_API + * Get Iterator that iterates over all but one axis (don't use this with + * PyArray_ITER_GOTO1D). The axis will be over-written if negative + * with the axis having the smallest stride. + */ +NPY_NO_EXPORT PyObject * +PyArray_IterAllButAxis(PyObject *obj, int *inaxis) +{ + PyArrayObject *arr; + PyArrayIterObject *it; + int axis; + + if (!PyArray_Check(obj)) { + PyErr_SetString(PyExc_ValueError, + "Numpy IterAllButAxis requires an ndarray"); + return NULL; + } + arr = (PyArrayObject *)obj; + + it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arr); + if (it == NULL) { + return NULL; + } + if (PyArray_NDIM(arr)==0) { + return (PyObject *)it; + } + if (*inaxis < 0) { + int i, minaxis = 0; + npy_intp minstride = 0; + i = 0; + while (minstride == 0 && i < PyArray_NDIM(arr)) { + minstride = PyArray_STRIDE(arr,i); + i++; + } + for (i = 1; i < PyArray_NDIM(arr); i++) { + if (PyArray_STRIDE(arr,i) > 0 && + PyArray_STRIDE(arr, i) < minstride) { + minaxis = i; + minstride = PyArray_STRIDE(arr,i); + } + } + *inaxis = minaxis; + } + axis = *inaxis; + /* adjust so that will not iterate over axis */ + it->contiguous = 0; + if (it->size != 0) { + it->size /= PyArray_DIM(arr,axis); + } + it->dims_m1[axis] = 0; + it->backstrides[axis] = 0; + + /* + * (won't fix factors so don't use + * PyArray_ITER_GOTO1D with this iterator) + */ + return (PyObject *)it; +} + +/*NUMPY_API + * Adjusts previously broadcasted iterators so that the axis with + * the smallest sum of iterator strides is not iterated over. + * Returns dimension which is smallest in the range [0,multi->nd). + * A -1 is returned if multi->nd == 0. + * + * don't use with PyArray_ITER_GOTO1D because factors are not adjusted + */ +NPY_NO_EXPORT int +PyArray_RemoveSmallest(PyArrayMultiIterObject *multi) +{ + PyArrayIterObject *it; + int i, j; + int axis; + npy_intp smallest; + npy_intp sumstrides[NPY_MAXDIMS]; + + if (multi->nd == 0) { + return -1; + } + for (i = 0; i < multi->nd; i++) { + sumstrides[i] = 0; + for (j = 0; j < multi->numiter; j++) { + sumstrides[i] += multi->iters[j]->strides[i]; + } + } + axis = 0; + smallest = sumstrides[0]; + /* Find longest dimension */ + for (i = 1; i < multi->nd; i++) { + if (sumstrides[i] < smallest) { + axis = i; + smallest = sumstrides[i]; + } + } + for(i = 0; i < multi->numiter; i++) { + it = multi->iters[i]; + it->contiguous = 0; + if (it->size != 0) { + it->size /= (it->dims_m1[axis]+1); + } + it->dims_m1[axis] = 0; + it->backstrides[axis] = 0; + } + multi->size = multi->iters[0]->size; + return axis; +} + +/* Returns an array scalar holding the element desired */ + +static PyObject * +arrayiter_next(PyArrayIterObject *it) +{ + PyObject *ret; + + if (it->index < it->size) { + ret = PyArray_ToScalar(it->dataptr, it->ao); + PyArray_ITER_NEXT(it); + return ret; + } + return NULL; +} + +static void +arrayiter_dealloc(PyArrayIterObject *it) +{ + array_iter_base_dealloc(it); + PyArray_free(it); +} + +static Py_ssize_t +iter_length(PyArrayIterObject *self) +{ + return self->size; +} + + +static PyArrayObject * +iter_subscript_Bool(PyArrayIterObject *self, PyArrayObject *ind) +{ + npy_intp counter, strides; + int itemsize; + npy_intp count = 0; + char *dptr, *optr; + PyArrayObject *ret; + int swap; + PyArray_CopySwapFunc *copyswap; + + + if (PyArray_NDIM(ind) != 1) { + PyErr_SetString(PyExc_ValueError, + "boolean index array should have 1 dimension"); + return NULL; + } + counter = PyArray_DIMS(ind)[0]; + if (counter > self->size) { + PyErr_SetString(PyExc_ValueError, + "too many boolean indices"); + return NULL; + } + + strides = PyArray_STRIDES(ind)[0]; + dptr = PyArray_DATA(ind); + /* Get size of return array */ + while (counter--) { + if (*((npy_bool *)dptr) != 0) { + count++; + } + dptr += strides; + } + itemsize = PyArray_DESCR(self->ao)->elsize; + Py_INCREF(PyArray_DESCR(self->ao)); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self->ao), + PyArray_DESCR(self->ao), 1, &count, + NULL, NULL, + 0, (PyObject *)self->ao); + if (ret == NULL) { + return NULL; + } + /* Set up loop */ + optr = PyArray_DATA(ret); + counter = PyArray_DIMS(ind)[0]; + dptr = PyArray_DATA(ind); + copyswap = PyArray_DESCR(self->ao)->f->copyswap; + /* Loop over Boolean array */ + swap = (PyArray_ISNOTSWAPPED(self->ao) != PyArray_ISNOTSWAPPED(ret)); + while (counter--) { + if (*((npy_bool *)dptr) != 0) { + copyswap(optr, self->dataptr, swap, self->ao); + optr += itemsize; + } + dptr += strides; + PyArray_ITER_NEXT(self); + } + PyArray_ITER_RESET(self); + return ret; +} + +static PyObject * +iter_subscript_int(PyArrayIterObject *self, PyArrayObject *ind) +{ + npy_intp num; + PyArrayObject *ret; + PyArrayIterObject *ind_it; + int itemsize; + int swap; + char *optr; + npy_intp counter; + PyArray_CopySwapFunc *copyswap; + + itemsize = PyArray_DESCR(self->ao)->elsize; + if (PyArray_NDIM(ind) == 0) { + num = *((npy_intp *)PyArray_DATA(ind)); + if (check_and_adjust_index(&num, self->size, -1, NULL) < 0) { + PyArray_ITER_RESET(self); + return NULL; + } + else { + PyObject *tmp; + PyArray_ITER_GOTO1D(self, num); + tmp = PyArray_ToScalar(self->dataptr, self->ao); + PyArray_ITER_RESET(self); + return tmp; + } + } + + Py_INCREF(PyArray_DESCR(self->ao)); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self->ao), + PyArray_DESCR(self->ao), + PyArray_NDIM(ind), + PyArray_DIMS(ind), + NULL, NULL, + 0, (PyObject *)self->ao); + if (ret == NULL) { + return NULL; + } + optr = PyArray_DATA(ret); + ind_it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)ind); + if (ind_it == NULL) { + Py_DECREF(ret); + return NULL; + } + counter = ind_it->size; + copyswap = PyArray_DESCR(ret)->f->copyswap; + swap = (PyArray_ISNOTSWAPPED(ret) != PyArray_ISNOTSWAPPED(self->ao)); + while (counter--) { + num = *((npy_intp *)(ind_it->dataptr)); + if (check_and_adjust_index(&num, self->size, -1, NULL) < 0) { + Py_DECREF(ind_it); + Py_DECREF(ret); + PyArray_ITER_RESET(self); + return NULL; + } + PyArray_ITER_GOTO1D(self, num); + copyswap(optr, self->dataptr, swap, ret); + optr += itemsize; + PyArray_ITER_NEXT(ind_it); + } + Py_DECREF(ind_it); + PyArray_ITER_RESET(self); + return (PyObject *)ret; +} + +/* Always returns arrays */ +NPY_NO_EXPORT PyObject * +iter_subscript(PyArrayIterObject *self, PyObject *ind) +{ + PyArray_Descr *indtype = NULL; + PyArray_Descr *dtype; + npy_intp start, step_size; + npy_intp n_steps; + PyArrayObject *ret; + char *dptr; + int size; + PyObject *obj = NULL; + PyArray_CopySwapFunc *copyswap; + + if (ind == Py_Ellipsis) { + ind = PySlice_New(NULL, NULL, NULL); + obj = iter_subscript(self, ind); + Py_DECREF(ind); + return obj; + } + if (PyTuple_Check(ind)) { + int len; + len = PyTuple_GET_SIZE(ind); + if (len > 1) { + goto fail; + } + if (len == 0) { + Py_INCREF(self->ao); + return (PyObject *)self->ao; + } + ind = PyTuple_GET_ITEM(ind, 0); + } + + /* + * Tuples >1d not accepted --- i.e. no newaxis + * Could implement this with adjusted strides and dimensions in iterator + * Check for Boolean -- this is first because Bool is a subclass of Int + */ + PyArray_ITER_RESET(self); + + if (PyBool_Check(ind)) { + if (PyObject_IsTrue(ind)) { + return PyArray_ToScalar(self->dataptr, self->ao); + } + else { /* empty array */ + npy_intp ii = 0; + dtype = PyArray_DESCR(self->ao); + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self->ao), + dtype, + 1, &ii, + NULL, NULL, 0, + (PyObject *)self->ao); + return (PyObject *)ret; + } + } + + /* Check for Integer or Slice */ + if (PyLong_Check(ind) || PyInt_Check(ind) || PySlice_Check(ind)) { + start = parse_index_entry(ind, &step_size, &n_steps, + self->size, 0, 1); + if (start == -1) { + goto fail; + } + if (n_steps == ELLIPSIS_INDEX || n_steps == NEWAXIS_INDEX) { + PyErr_SetString(PyExc_IndexError, + "cannot use Ellipsis or newaxes here"); + goto fail; + } + PyArray_ITER_GOTO1D(self, start); + if (n_steps == SINGLE_INDEX) { /* Integer */ + PyObject *tmp; + tmp = PyArray_ToScalar(self->dataptr, self->ao); + PyArray_ITER_RESET(self); + return tmp; + } + size = PyArray_DESCR(self->ao)->elsize; + dtype = PyArray_DESCR(self->ao); + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self->ao), + dtype, + 1, &n_steps, + NULL, NULL, + 0, (PyObject *)self->ao); + if (ret == NULL) { + goto fail; + } + dptr = PyArray_DATA(ret); + copyswap = PyArray_DESCR(ret)->f->copyswap; + while (n_steps--) { + copyswap(dptr, self->dataptr, 0, ret); + start += step_size; + PyArray_ITER_GOTO1D(self, start); + dptr += size; + } + PyArray_ITER_RESET(self); + return (PyObject *)ret; + } + + /* convert to INTP array if Integer array scalar or List */ + indtype = PyArray_DescrFromType(NPY_INTP); + if (PyArray_IsScalar(ind, Integer) || PyList_Check(ind)) { + Py_INCREF(indtype); + obj = PyArray_FromAny(ind, indtype, 0, 0, NPY_ARRAY_FORCECAST, NULL); + if (obj == NULL) { + goto fail; + } + } + else { + Py_INCREF(ind); + obj = ind; + } + + if (PyArray_Check(obj)) { + /* Check for Boolean object */ + if (PyArray_TYPE((PyArrayObject *)obj) == NPY_BOOL) { + ret = iter_subscript_Bool(self, (PyArrayObject *)obj); + Py_DECREF(indtype); + } + /* Check for integer array */ + else if (PyArray_ISINTEGER((PyArrayObject *)obj)) { + PyObject *new; + new = PyArray_FromAny(obj, indtype, 0, 0, + NPY_ARRAY_FORCECAST | NPY_ARRAY_ALIGNED, NULL); + if (new == NULL) { + goto fail; + } + Py_DECREF(obj); + obj = new; + new = iter_subscript_int(self, (PyArrayObject *)obj); + Py_DECREF(obj); + return new; + } + else { + goto fail; + } + Py_DECREF(obj); + return (PyObject *)ret; + } + else { + Py_DECREF(indtype); + } + + + fail: + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_IndexError, "unsupported iterator index"); + } + Py_XDECREF(indtype); + Py_XDECREF(obj); + return NULL; + +} + + +static int +iter_ass_sub_Bool(PyArrayIterObject *self, PyArrayObject *ind, + PyArrayIterObject *val, int swap) +{ + npy_intp counter, strides; + char *dptr; + PyArray_CopySwapFunc *copyswap; + + if (PyArray_NDIM(ind) != 1) { + PyErr_SetString(PyExc_ValueError, + "boolean index array should have 1 dimension"); + return -1; + } + + counter = PyArray_DIMS(ind)[0]; + if (counter > self->size) { + PyErr_SetString(PyExc_ValueError, + "boolean index array has too many values"); + return -1; + } + + strides = PyArray_STRIDES(ind)[0]; + dptr = PyArray_DATA(ind); + PyArray_ITER_RESET(self); + /* Loop over Boolean array */ + copyswap = PyArray_DESCR(self->ao)->f->copyswap; + while (counter--) { + if (*((npy_bool *)dptr) != 0) { + copyswap(self->dataptr, val->dataptr, swap, self->ao); + PyArray_ITER_NEXT(val); + if (val->index == val->size) { + PyArray_ITER_RESET(val); + } + } + dptr += strides; + PyArray_ITER_NEXT(self); + } + PyArray_ITER_RESET(self); + return 0; +} + +static int +iter_ass_sub_int(PyArrayIterObject *self, PyArrayObject *ind, + PyArrayIterObject *val, int swap) +{ + npy_intp num; + PyArrayIterObject *ind_it; + npy_intp counter; + PyArray_CopySwapFunc *copyswap; + + copyswap = PyArray_DESCR(self->ao)->f->copyswap; + if (PyArray_NDIM(ind) == 0) { + num = *((npy_intp *)PyArray_DATA(ind)); + if (check_and_adjust_index(&num, self->size, -1, NULL) < 0) { + return -1; + } + PyArray_ITER_GOTO1D(self, num); + copyswap(self->dataptr, val->dataptr, swap, self->ao); + return 0; + } + ind_it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)ind); + if (ind_it == NULL) { + return -1; + } + counter = ind_it->size; + while (counter--) { + num = *((npy_intp *)(ind_it->dataptr)); + if (check_and_adjust_index(&num, self->size, -1, NULL) < 0) { + Py_DECREF(ind_it); + return -1; + } + PyArray_ITER_GOTO1D(self, num); + copyswap(self->dataptr, val->dataptr, swap, self->ao); + PyArray_ITER_NEXT(ind_it); + PyArray_ITER_NEXT(val); + if (val->index == val->size) { + PyArray_ITER_RESET(val); + } + } + Py_DECREF(ind_it); + return 0; +} + +NPY_NO_EXPORT int +iter_ass_subscript(PyArrayIterObject *self, PyObject *ind, PyObject *val) +{ + PyArrayObject *arrval = NULL; + PyArrayIterObject *val_it = NULL; + PyArray_Descr *type; + PyArray_Descr *indtype = NULL; + int swap, retval = -1; + npy_intp start, step_size; + npy_intp n_steps; + PyObject *obj = NULL; + PyArray_CopySwapFunc *copyswap; + + + if (val == NULL) { + PyErr_SetString(PyExc_TypeError, + "Cannot delete iterator elements"); + return -1; + } + + if (PyArray_FailUnlessWriteable(self->ao, "underlying array") < 0) + return -1; + + if (ind == Py_Ellipsis) { + ind = PySlice_New(NULL, NULL, NULL); + retval = iter_ass_subscript(self, ind, val); + Py_DECREF(ind); + return retval; + } + + if (PyTuple_Check(ind)) { + int len; + len = PyTuple_GET_SIZE(ind); + if (len > 1) { + goto finish; + } + ind = PyTuple_GET_ITEM(ind, 0); + } + + type = PyArray_DESCR(self->ao); + + /* + * Check for Boolean -- this is first because + * Bool is a subclass of Int + */ + if (PyBool_Check(ind)) { + retval = 0; + if (PyObject_IsTrue(ind)) { + retval = PyArray_SETITEM(self->ao, self->dataptr, val); + } + goto finish; + } + + if (PySequence_Check(ind) || PySlice_Check(ind)) { + goto skip; + } + start = PyArray_PyIntAsIntp(ind); + if (error_converting(start)) { + PyErr_Clear(); + } + else { + if (check_and_adjust_index(&start, self->size, -1, NULL) < 0) { + goto finish; + } + retval = 0; + PyArray_ITER_GOTO1D(self, start); + retval = type->f->setitem(val, self->dataptr, self->ao); + PyArray_ITER_RESET(self); + if (retval < 0) { + PyErr_SetString(PyExc_ValueError, + "Error setting single item of array."); + } + goto finish; + } + + skip: + Py_INCREF(type); + arrval = (PyArrayObject *)PyArray_FromAny(val, type, 0, 0, + NPY_ARRAY_FORCECAST, NULL); + if (arrval == NULL) { + return -1; + } + val_it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arrval); + if (val_it == NULL) { + goto finish; + } + if (val_it->size == 0) { + retval = 0; + goto finish; + } + + copyswap = PyArray_DESCR(arrval)->f->copyswap; + swap = (PyArray_ISNOTSWAPPED(self->ao)!=PyArray_ISNOTSWAPPED(arrval)); + + /* Check Slice */ + if (PySlice_Check(ind)) { + start = parse_index_entry(ind, &step_size, &n_steps, self->size, 0, 0); + if (start == -1) { + goto finish; + } + if (n_steps == ELLIPSIS_INDEX || n_steps == NEWAXIS_INDEX) { + PyErr_SetString(PyExc_IndexError, + "cannot use Ellipsis or newaxes here"); + goto finish; + } + PyArray_ITER_GOTO1D(self, start); + if (n_steps == SINGLE_INDEX) { + /* Integer */ + copyswap(self->dataptr, PyArray_DATA(arrval), swap, arrval); + PyArray_ITER_RESET(self); + retval = 0; + goto finish; + } + while (n_steps--) { + copyswap(self->dataptr, val_it->dataptr, swap, arrval); + start += step_size; + PyArray_ITER_GOTO1D(self, start); + PyArray_ITER_NEXT(val_it); + if (val_it->index == val_it->size) { + PyArray_ITER_RESET(val_it); + } + } + PyArray_ITER_RESET(self); + retval = 0; + goto finish; + } + + /* convert to INTP array if Integer array scalar or List */ + indtype = PyArray_DescrFromType(NPY_INTP); + if (PyList_Check(ind)) { + Py_INCREF(indtype); + obj = PyArray_FromAny(ind, indtype, 0, 0, NPY_ARRAY_FORCECAST, NULL); + } + else { + Py_INCREF(ind); + obj = ind; + } + + if (obj != NULL && PyArray_Check(obj)) { + /* Check for Boolean object */ + if (PyArray_TYPE((PyArrayObject *)obj)==NPY_BOOL) { + if (iter_ass_sub_Bool(self, (PyArrayObject *)obj, + val_it, swap) < 0) { + goto finish; + } + retval=0; + } + /* Check for integer array */ + else if (PyArray_ISINTEGER((PyArrayObject *)obj)) { + PyObject *new; + Py_INCREF(indtype); + new = PyArray_CheckFromAny(obj, indtype, 0, 0, + NPY_ARRAY_FORCECAST | NPY_ARRAY_BEHAVED_NS, NULL); + Py_DECREF(obj); + obj = new; + if (new == NULL) { + goto finish; + } + if (iter_ass_sub_int(self, (PyArrayObject *)obj, + val_it, swap) < 0) { + goto finish; + } + retval = 0; + } + } + + finish: + if (!PyErr_Occurred() && retval < 0) { + PyErr_SetString(PyExc_IndexError, "unsupported iterator index"); + } + Py_XDECREF(indtype); + Py_XDECREF(obj); + Py_XDECREF(val_it); + Py_XDECREF(arrval); + return retval; + +} + + +static PyMappingMethods iter_as_mapping = { + (lenfunc)iter_length, /*mp_length*/ + (binaryfunc)iter_subscript, /*mp_subscript*/ + (objobjargproc)iter_ass_subscript, /*mp_ass_subscript*/ +}; + + +/* Two options: + * 1) underlying array is contiguous + * -- return 1-d wrapper around it + * 2) underlying array is not contiguous + * -- make new 1-d contiguous array with updateifcopy flag set + * to copy back to the old array + * + * If underlying array is readonly, then we make the output array readonly + * and updateifcopy does not apply. + * + * Changed 2017-07-21, 1.14.0. + * + * In order to start the process of removing UPDATEIFCOPY, see gh-7054, the + * behavior is changed to always return an non-writeable copy when the base + * array is non-contiguous. Doing that will hopefully smoke out those few + * folks who assign to the result with the expectation that the base array + * will be changed. At a later date non-contiguous arrays will always return + * writeable copies. + * + * Note that the type and argument expected for the __array__ method is + * ignored. + */ +static PyArrayObject * +iter_array(PyArrayIterObject *it, PyObject *NPY_UNUSED(op)) +{ + + PyArrayObject *ret; + npy_intp size; + + size = PyArray_SIZE(it->ao); + Py_INCREF(PyArray_DESCR(it->ao)); + + if (PyArray_ISCONTIGUOUS(it->ao)) { + ret = (PyArrayObject *)PyArray_NewFromDescr( + &PyArray_Type, PyArray_DESCR(it->ao), 1, &size, + NULL, PyArray_DATA(it->ao), PyArray_FLAGS(it->ao), + (PyObject *)it->ao); + if (ret == NULL) { + return NULL; + } + Py_INCREF(it->ao); + if (PyArray_SetBaseObject(ret, (PyObject *)it->ao) < 0) { + Py_DECREF(ret); + return NULL; + } + } + else { + ret = (PyArrayObject *)PyArray_NewFromDescr( + &PyArray_Type, PyArray_DESCR(it->ao), 1, &size, + NULL, NULL, 0, + (PyObject *)it->ao); + if (ret == NULL) { + return NULL; + } + if (PyArray_CopyAnyInto(ret, it->ao) < 0) { + Py_DECREF(ret); + return NULL; + } + PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEABLE); + } + return ret; + +} + +static PyObject * +iter_copy(PyArrayIterObject *it, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + return PyArray_Flatten(it->ao, 0); +} + +static PyMethodDef iter_methods[] = { + /* to get array */ + {"__array__", + (PyCFunction)iter_array, + METH_VARARGS, NULL}, + {"copy", + (PyCFunction)iter_copy, + METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} /* sentinel */ +}; + +static PyObject * +iter_richcompare(PyArrayIterObject *self, PyObject *other, int cmp_op) +{ + PyArrayObject *new; + PyObject *ret; + new = (PyArrayObject *)iter_array(self, NULL); + if (new == NULL) { + return NULL; + } + ret = array_richcompare(new, other, cmp_op); + PyArray_ResolveWritebackIfCopy(new); + Py_DECREF(new); + return ret; +} + + +static PyMemberDef iter_members[] = { + {"base", + T_OBJECT, + offsetof(PyArrayIterObject, ao), + READONLY, NULL}, + {"index", + T_INT, + offsetof(PyArrayIterObject, index), + READONLY, NULL}, + {NULL, 0, 0, 0, NULL}, +}; + +static PyObject * +iter_coords_get(PyArrayIterObject *self) +{ + int nd; + nd = PyArray_NDIM(self->ao); + if (self->contiguous) { + /* + * coordinates not kept track of --- + * need to generate from index + */ + npy_intp val; + int i; + val = self->index; + for (i = 0; i < nd; i++) { + if (self->factors[i] != 0) { + self->coordinates[i] = val / self->factors[i]; + val = val % self->factors[i]; + } else { + self->coordinates[i] = 0; + } + } + } + return PyArray_IntTupleFromIntp(nd, self->coordinates); +} + +static PyGetSetDef iter_getsets[] = { + {"coords", + (getter)iter_coords_get, + NULL, + NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL}, +}; + +NPY_NO_EXPORT PyTypeObject PyArrayIter_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.flatiter", /* tp_name */ + sizeof(PyArrayIterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)arrayiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &iter_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)iter_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + (iternextfunc)arrayiter_next, /* tp_iternext */ + iter_methods, /* tp_methods */ + iter_members, /* tp_members */ + iter_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; + +/** END of Array Iterator **/ + +/* Adjust dimensionality and strides for index object iterators + --- i.e. broadcast +*/ +/*NUMPY_API*/ +NPY_NO_EXPORT int +PyArray_Broadcast(PyArrayMultiIterObject *mit) +{ + int i, nd, k, j; + npy_intp tmp; + PyArrayIterObject *it; + + /* Discover the broadcast number of dimensions */ + for (i = 0, nd = 0; i < mit->numiter; i++) { + nd = PyArray_MAX(nd, PyArray_NDIM(mit->iters[i]->ao)); + } + mit->nd = nd; + + /* Discover the broadcast shape in each dimension */ + for (i = 0; i < nd; i++) { + mit->dimensions[i] = 1; + for (j = 0; j < mit->numiter; j++) { + it = mit->iters[j]; + /* This prepends 1 to shapes not already equal to nd */ + k = i + PyArray_NDIM(it->ao) - nd; + if (k >= 0) { + tmp = PyArray_DIMS(it->ao)[k]; + if (tmp == 1) { + continue; + } + if (mit->dimensions[i] == 1) { + mit->dimensions[i] = tmp; + } + else if (mit->dimensions[i] != tmp) { + PyErr_SetString(PyExc_ValueError, + "shape mismatch: objects" \ + " cannot be broadcast" \ + " to a single shape"); + return -1; + } + } + } + } + + /* + * Reset the iterator dimensions and strides of each iterator + * object -- using 0 valued strides for broadcasting + * Need to check for overflow + */ + tmp = PyArray_OverflowMultiplyList(mit->dimensions, mit->nd); + if (tmp < 0) { + PyErr_SetString(PyExc_ValueError, + "broadcast dimensions too large."); + return -1; + } + mit->size = tmp; + for (i = 0; i < mit->numiter; i++) { + it = mit->iters[i]; + it->nd_m1 = mit->nd - 1; + it->size = tmp; + nd = PyArray_NDIM(it->ao); + if (nd != 0) { + it->factors[mit->nd-1] = 1; + } + for (j = 0; j < mit->nd; j++) { + it->dims_m1[j] = mit->dimensions[j] - 1; + k = j + nd - mit->nd; + /* + * If this dimension was added or shape of + * underlying array was 1 + */ + if ((k < 0) || + PyArray_DIMS(it->ao)[k] != mit->dimensions[j]) { + it->contiguous = 0; + it->strides[j] = 0; + } + else { + it->strides[j] = PyArray_STRIDES(it->ao)[k]; + } + it->backstrides[j] = it->strides[j] * it->dims_m1[j]; + if (j > 0) + it->factors[mit->nd-j-1] = + it->factors[mit->nd-j] * mit->dimensions[mit->nd-j]; + } + PyArray_ITER_RESET(it); + } + return 0; +} + +/*NUMPY_API + * Get MultiIterator from array of Python objects and any additional + * + * PyObject **mps -- array of PyObjects + * int n - number of PyObjects in the array + * int nadd - number of additional arrays to include in the iterator. + * + * Returns a multi-iterator object. + */ +NPY_NO_EXPORT PyObject * +PyArray_MultiIterFromObjects(PyObject **mps, int n, int nadd, ...) +{ + va_list va; + PyArrayMultiIterObject *multi; + PyObject *current; + PyObject *arr; + + int i, ntot, err=0; + + ntot = n + nadd; + if (ntot < 1 || ntot > NPY_MAXARGS) { + PyErr_Format(PyExc_ValueError, + "Need at least 1 and at most %d " + "array objects.", NPY_MAXARGS); + return NULL; + } + multi = PyArray_malloc(sizeof(PyArrayMultiIterObject)); + if (multi == NULL) { + return PyErr_NoMemory(); + } + PyObject_Init((PyObject *)multi, &PyArrayMultiIter_Type); + + for (i = 0; i < ntot; i++) { + multi->iters[i] = NULL; + } + multi->numiter = ntot; + multi->index = 0; + + va_start(va, nadd); + for (i = 0; i < ntot; i++) { + if (i < n) { + current = mps[i]; + } + else { + current = va_arg(va, PyObject *); + } + arr = PyArray_FROM_O(current); + if (arr == NULL) { + err = 1; + break; + } + else { + multi->iters[i] = (PyArrayIterObject *)PyArray_IterNew(arr); + if (multi->iters[i] == NULL) { + err = 1; + break; + } + Py_DECREF(arr); + } + } + va_end(va); + + if (!err && PyArray_Broadcast(multi) < 0) { + err = 1; + } + if (err) { + Py_DECREF(multi); + return NULL; + } + PyArray_MultiIter_RESET(multi); + return (PyObject *)multi; +} + +/*NUMPY_API + * Get MultiIterator, + */ +NPY_NO_EXPORT PyObject * +PyArray_MultiIterNew(int n, ...) +{ + va_list va; + PyArrayMultiIterObject *multi; + PyObject *current; + PyObject *arr; + + int i, err = 0; + + if (n < 1 || n > NPY_MAXARGS) { + PyErr_Format(PyExc_ValueError, + "Need at least 1 and at most %d " + "array objects.", NPY_MAXARGS); + return NULL; + } + + /* fprintf(stderr, "multi new...");*/ + + multi = PyArray_malloc(sizeof(PyArrayMultiIterObject)); + if (multi == NULL) { + return PyErr_NoMemory(); + } + PyObject_Init((PyObject *)multi, &PyArrayMultiIter_Type); + + for (i = 0; i < n; i++) { + multi->iters[i] = NULL; + } + multi->numiter = n; + multi->index = 0; + + va_start(va, n); + for (i = 0; i < n; i++) { + current = va_arg(va, PyObject *); + arr = PyArray_FROM_O(current); + if (arr == NULL) { + err = 1; + break; + } + else { + multi->iters[i] = (PyArrayIterObject *)PyArray_IterNew(arr); + if (multi->iters[i] == NULL) { + err = 1; + break; + } + Py_DECREF(arr); + } + } + va_end(va); + + if (!err && PyArray_Broadcast(multi) < 0) { + err = 1; + } + if (err) { + Py_DECREF(multi); + return NULL; + } + PyArray_MultiIter_RESET(multi); + return (PyObject *)multi; +} + +static PyObject * +arraymultiter_new(PyTypeObject *NPY_UNUSED(subtype), PyObject *args, PyObject *kwds) +{ + + Py_ssize_t n = 0; + Py_ssize_t i, j, k; + PyArrayMultiIterObject *multi; + PyObject *arr; + + if (kwds != NULL) { + PyErr_SetString(PyExc_ValueError, + "keyword arguments not accepted."); + return NULL; + } + + for (j = 0; j < PyTuple_Size(args); ++j) { + PyObject *obj = PyTuple_GET_ITEM(args, j); + + if (PyObject_IsInstance(obj, (PyObject *)&PyArrayMultiIter_Type)) { + /* + * If obj is a multi-iterator, all its arrays will be added + * to the new multi-iterator. + */ + n += ((PyArrayMultiIterObject *)obj)->numiter; + } + else { + /* If not, will try to convert it to a single array */ + ++n; + } + } + if (n < 1 || n > NPY_MAXARGS) { + if (PyErr_Occurred()) { + return NULL; + } + PyErr_Format(PyExc_ValueError, + "Need at least 1 and at most %d " + "array objects.", NPY_MAXARGS); + return NULL; + } + + multi = PyArray_malloc(sizeof(PyArrayMultiIterObject)); + if (multi == NULL) { + return PyErr_NoMemory(); + } + PyObject_Init((PyObject *)multi, &PyArrayMultiIter_Type); + + multi->numiter = n; + multi->index = 0; + i = 0; + for (j = 0; j < PyTuple_GET_SIZE(args); ++j) { + PyObject *obj = PyTuple_GET_ITEM(args, j); + PyArrayIterObject *it; + + if (PyObject_IsInstance(obj, (PyObject *)&PyArrayMultiIter_Type)) { + PyArrayMultiIterObject *mit = (PyArrayMultiIterObject *)obj; + + for (k = 0; k < mit->numiter; ++k) { + arr = (PyObject *)mit->iters[k]->ao; + assert (arr != NULL); + it = (PyArrayIterObject *)PyArray_IterNew(arr); + if (it == NULL) { + goto fail; + } + multi->iters[i++] = it; + } + } + else { + arr = PyArray_FROM_O(obj); + if (arr == NULL) { + goto fail; + } + it = (PyArrayIterObject *)PyArray_IterNew(arr); + if (it == NULL) { + goto fail; + } + multi->iters[i++] = it; + Py_DECREF(arr); + } + } + assert (i == n); + if (PyArray_Broadcast(multi) < 0) { + goto fail; + } + PyArray_MultiIter_RESET(multi); + return (PyObject *)multi; + + fail: + Py_DECREF(multi); + return NULL; +} + +static PyObject * +arraymultiter_next(PyArrayMultiIterObject *multi) +{ + PyObject *ret; + int i, n; + + n = multi->numiter; + ret = PyTuple_New(n); + if (ret == NULL) { + return NULL; + } + if (multi->index < multi->size) { + for (i = 0; i < n; i++) { + PyArrayIterObject *it=multi->iters[i]; + PyTuple_SET_ITEM(ret, i, + PyArray_ToScalar(it->dataptr, it->ao)); + PyArray_ITER_NEXT(it); + } + multi->index++; + return ret; + } + Py_DECREF(ret); + return NULL; +} + +static void +arraymultiter_dealloc(PyArrayMultiIterObject *multi) +{ + int i; + + for (i = 0; i < multi->numiter; i++) { + Py_XDECREF(multi->iters[i]); + } + Py_TYPE(multi)->tp_free((PyObject *)multi); +} + +static PyObject * +arraymultiter_size_get(PyArrayMultiIterObject *self) +{ +#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG + return PyInt_FromLong((long) self->size); +#else + if (self->size < NPY_MAX_LONG) { + return PyInt_FromLong((long) self->size); + } + else { + return PyLong_FromLongLong((npy_longlong) self->size); + } +#endif +} + +static PyObject * +arraymultiter_index_get(PyArrayMultiIterObject *self) +{ +#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG + return PyInt_FromLong((long) self->index); +#else + if (self->size < NPY_MAX_LONG) { + return PyInt_FromLong((long) self->index); + } + else { + return PyLong_FromLongLong((npy_longlong) self->index); + } +#endif +} + +static PyObject * +arraymultiter_shape_get(PyArrayMultiIterObject *self) +{ + return PyArray_IntTupleFromIntp(self->nd, self->dimensions); +} + +static PyObject * +arraymultiter_iters_get(PyArrayMultiIterObject *self) +{ + PyObject *res; + int i, n; + + n = self->numiter; + res = PyTuple_New(n); + if (res == NULL) { + return res; + } + for (i = 0; i < n; i++) { + Py_INCREF(self->iters[i]); + PyTuple_SET_ITEM(res, i, (PyObject *)self->iters[i]); + } + return res; +} + +static PyGetSetDef arraymultiter_getsetlist[] = { + {"size", + (getter)arraymultiter_size_get, + NULL, + NULL, NULL}, + {"index", + (getter)arraymultiter_index_get, + NULL, + NULL, NULL}, + {"shape", + (getter)arraymultiter_shape_get, + NULL, + NULL, NULL}, + {"iters", + (getter)arraymultiter_iters_get, + NULL, + NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL}, +}; + +static PyMemberDef arraymultiter_members[] = { + {"numiter", + T_INT, + offsetof(PyArrayMultiIterObject, numiter), + READONLY, NULL}, + {"nd", + T_INT, + offsetof(PyArrayMultiIterObject, nd), + READONLY, NULL}, + {"ndim", + T_INT, + offsetof(PyArrayMultiIterObject, nd), + READONLY, NULL}, + {NULL, 0, 0, 0, NULL}, +}; + +static PyObject * +arraymultiter_reset(PyArrayMultiIterObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + PyArray_MultiIter_RESET(self); + Py_RETURN_NONE; +} + +static PyMethodDef arraymultiter_methods[] = { + {"reset", + (PyCFunction) arraymultiter_reset, + METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL}, /* sentinal */ +}; + +NPY_NO_EXPORT PyTypeObject PyArrayMultiIter_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.broadcast", /* tp_name */ + sizeof(PyArrayMultiIterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)arraymultiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + (iternextfunc)arraymultiter_next, /* tp_iternext */ + arraymultiter_methods, /* tp_methods */ + arraymultiter_members, /* tp_members */ + arraymultiter_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)0, /* tp_init */ + 0, /* tp_alloc */ + arraymultiter_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; + +/*========================= Neighborhood iterator ======================*/ + +static void neighiter_dealloc(PyArrayNeighborhoodIterObject* iter); + +static char* _set_constant(PyArrayNeighborhoodIterObject* iter, + PyArrayObject *fill) +{ + char *ret; + PyArrayIterObject *ar = iter->_internal_iter; + int storeflags, st; + + ret = PyDataMem_NEW(PyArray_DESCR(ar->ao)->elsize); + if (ret == NULL) { + PyErr_SetNone(PyExc_MemoryError); + return NULL; + } + + if (PyArray_ISOBJECT(ar->ao)) { + memcpy(ret, PyArray_DATA(fill), sizeof(PyObject*)); + Py_INCREF(*(PyObject**)ret); + } else { + /* Non-object types */ + + storeflags = PyArray_FLAGS(ar->ao); + PyArray_ENABLEFLAGS(ar->ao, NPY_ARRAY_BEHAVED); + st = PyArray_SETITEM(ar->ao, ret, (PyObject*)fill); + ((PyArrayObject_fields *)ar->ao)->flags = storeflags; + + if (st < 0) { + PyDataMem_FREE(ret); + return NULL; + } + } + + return ret; +} + +#define _INF_SET_PTR(c) \ + bd = coordinates[c] + p->coordinates[c]; \ + if (bd < p->limits[c][0] || bd > p->limits[c][1]) { \ + return niter->constant; \ + } \ + _coordinates[c] = bd; + +/* set the dataptr from its current coordinates */ +static char* +get_ptr_constant(PyArrayIterObject* _iter, npy_intp *coordinates) +{ + int i; + npy_intp bd, _coordinates[NPY_MAXDIMS]; + PyArrayNeighborhoodIterObject *niter = (PyArrayNeighborhoodIterObject*)_iter; + PyArrayIterObject *p = niter->_internal_iter; + + for(i = 0; i < niter->nd; ++i) { + _INF_SET_PTR(i) + } + + return p->translate(p, _coordinates); +} +#undef _INF_SET_PTR + +#define _NPY_IS_EVEN(x) ((x) % 2 == 0) + +/* For an array x of dimension n, and given index i, returns j, 0 <= j < n + * such as x[i] = x[j], with x assumed to be mirrored. For example, for x = + * {1, 2, 3} (n = 3) + * + * index -5 -4 -3 -2 -1 0 1 2 3 4 5 6 + * value 2 3 3 2 1 1 2 3 3 2 1 1 + * + * _npy_pos_index_mirror(4, 3) will return 1, because x[4] = x[1]*/ +NPY_INLINE static npy_intp +__npy_pos_remainder(npy_intp i, npy_intp n) +{ + npy_intp k, l, j; + + /* Mirror i such as it is guaranteed to be positive */ + if (i < 0) { + i = - i - 1; + } + + /* compute k and l such as i = k * n + l, 0 <= l < k */ + k = i / n; + l = i - k * n; + + if (_NPY_IS_EVEN(k)) { + j = l; + } else { + j = n - 1 - l; + } + return j; +} +#undef _NPY_IS_EVEN + +#define _INF_SET_PTR_MIRROR(c) \ + lb = p->limits[c][0]; \ + bd = coordinates[c] + p->coordinates[c] - lb; \ + _coordinates[c] = lb + __npy_pos_remainder(bd, p->limits_sizes[c]); + +/* set the dataptr from its current coordinates */ +static char* +get_ptr_mirror(PyArrayIterObject* _iter, npy_intp *coordinates) +{ + int i; + npy_intp bd, _coordinates[NPY_MAXDIMS], lb; + PyArrayNeighborhoodIterObject *niter = (PyArrayNeighborhoodIterObject*)_iter; + PyArrayIterObject *p = niter->_internal_iter; + + for(i = 0; i < niter->nd; ++i) { + _INF_SET_PTR_MIRROR(i) + } + + return p->translate(p, _coordinates); +} +#undef _INF_SET_PTR_MIRROR + +/* compute l such as i = k * n + l, 0 <= l < |k| */ +NPY_INLINE static npy_intp +__npy_euclidean_division(npy_intp i, npy_intp n) +{ + npy_intp l; + + l = i % n; + if (l < 0) { + l += n; + } + return l; +} + +#define _INF_SET_PTR_CIRCULAR(c) \ + lb = p->limits[c][0]; \ + bd = coordinates[c] + p->coordinates[c] - lb; \ + _coordinates[c] = lb + __npy_euclidean_division(bd, p->limits_sizes[c]); + +static char* +get_ptr_circular(PyArrayIterObject* _iter, npy_intp *coordinates) +{ + int i; + npy_intp bd, _coordinates[NPY_MAXDIMS], lb; + PyArrayNeighborhoodIterObject *niter = (PyArrayNeighborhoodIterObject*)_iter; + PyArrayIterObject *p = niter->_internal_iter; + + for(i = 0; i < niter->nd; ++i) { + _INF_SET_PTR_CIRCULAR(i) + } + return p->translate(p, _coordinates); +} + +#undef _INF_SET_PTR_CIRCULAR + +/* + * fill and x->ao should have equivalent types + */ +/*NUMPY_API + * A Neighborhood Iterator object. +*/ +NPY_NO_EXPORT PyObject* +PyArray_NeighborhoodIterNew(PyArrayIterObject *x, npy_intp *bounds, + int mode, PyArrayObject* fill) +{ + int i; + PyArrayNeighborhoodIterObject *ret; + + ret = PyArray_malloc(sizeof(*ret)); + if (ret == NULL) { + return NULL; + } + PyObject_Init((PyObject *)ret, &PyArrayNeighborhoodIter_Type); + + array_iter_base_init((PyArrayIterObject*)ret, x->ao); + Py_INCREF(x); + ret->_internal_iter = x; + + ret->nd = PyArray_NDIM(x->ao); + + for (i = 0; i < ret->nd; ++i) { + ret->dimensions[i] = PyArray_DIMS(x->ao)[i]; + } + + /* Compute the neighborhood size and copy the shape */ + ret->size = 1; + for (i = 0; i < ret->nd; ++i) { + ret->bounds[i][0] = bounds[2 * i]; + ret->bounds[i][1] = bounds[2 * i + 1]; + ret->size *= (ret->bounds[i][1] - ret->bounds[i][0]) + 1; + + /* limits keep track of valid ranges for the neighborhood: if a bound + * of the neighborhood is outside the array, then limits is the same as + * boundaries. On the contrary, if a bound is strictly inside the + * array, then limits correspond to the array range. For example, for + * an array [1, 2, 3], if bounds are [-1, 3], limits will be [-1, 3], + * but if bounds are [1, 2], then limits will be [0, 2]. + * + * This is used by neighborhood iterators stacked on top of this one */ + ret->limits[i][0] = ret->bounds[i][0] < 0 ? ret->bounds[i][0] : 0; + ret->limits[i][1] = ret->bounds[i][1] >= ret->dimensions[i] - 1 ? + ret->bounds[i][1] : + ret->dimensions[i] - 1; + ret->limits_sizes[i] = (ret->limits[i][1] - ret->limits[i][0]) + 1; + } + + switch (mode) { + case NPY_NEIGHBORHOOD_ITER_ZERO_PADDING: + ret->constant = PyArray_Zero(x->ao); + ret->mode = mode; + ret->translate = &get_ptr_constant; + break; + case NPY_NEIGHBORHOOD_ITER_ONE_PADDING: + ret->constant = PyArray_One(x->ao); + ret->mode = mode; + ret->translate = &get_ptr_constant; + break; + case NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING: + /* New reference in returned value of _set_constant if array + * object */ + assert(PyArray_EquivArrTypes(x->ao, fill) == NPY_TRUE); + ret->constant = _set_constant(ret, fill); + if (ret->constant == NULL) { + goto clean_x; + } + ret->mode = mode; + ret->translate = &get_ptr_constant; + break; + case NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING: + ret->mode = mode; + ret->constant = NULL; + ret->translate = &get_ptr_mirror; + break; + case NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING: + ret->mode = mode; + ret->constant = NULL; + ret->translate = &get_ptr_circular; + break; + default: + PyErr_SetString(PyExc_ValueError, "Unsupported padding mode"); + goto clean_x; + } + + /* + * XXX: we force x iterator to be non contiguous because we need + * coordinates... Modifying the iterator here is not great + */ + x->contiguous = 0; + + PyArrayNeighborhoodIter_Reset(ret); + + return (PyObject*)ret; + +clean_x: + Py_DECREF(ret->_internal_iter); + array_iter_base_dealloc((PyArrayIterObject*)ret); + PyArray_free((PyArrayObject*)ret); + return NULL; +} + +static void neighiter_dealloc(PyArrayNeighborhoodIterObject* iter) +{ + if (iter->mode == NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING) { + if (PyArray_ISOBJECT(iter->_internal_iter->ao)) { + Py_DECREF(*(PyObject**)iter->constant); + } + } + PyDataMem_FREE(iter->constant); + Py_DECREF(iter->_internal_iter); + + array_iter_base_dealloc((PyArrayIterObject*)iter); + PyArray_free((PyArrayObject*)iter); +} + +NPY_NO_EXPORT PyTypeObject PyArrayNeighborhoodIter_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.neigh_internal_iter", /* tp_name*/ + sizeof(PyArrayNeighborhoodIterObject), /* tp_basicsize*/ + 0, /* tp_itemsize*/ + (destructor)neighiter_dealloc, /* tp_dealloc*/ + 0, /* tp_print*/ + 0, /* tp_getattr*/ + 0, /* tp_setattr*/ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr*/ + 0, /* tp_as_number*/ + 0, /* tp_as_sequence*/ + 0, /* tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call*/ + 0, /* tp_str*/ + 0, /* tp_getattro*/ + 0, /* tp_setattro*/ + 0, /* tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /* tp_flags*/ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + (iternextfunc)0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; diff --git a/numpy/core/src/multiarray/iterators.h b/numpy/core/src/multiarray/iterators.h new file mode 100644 index 0000000..04f57c8 --- /dev/null +++ b/numpy/core/src/multiarray/iterators.h @@ -0,0 +1,21 @@ +#ifndef _NPY_ARRAYITERATORS_H_ +#define _NPY_ARRAYITERATORS_H_ + +/* + * Parses an index that has no fancy indexing. Populates + * out_dimensions, out_strides, and out_offset. + */ +NPY_NO_EXPORT int +parse_index(PyArrayObject *self, PyObject *op, + npy_intp *out_dimensions, + npy_intp *out_strides, + npy_intp *out_offset, + int check_index); + +NPY_NO_EXPORT PyObject +*iter_subscript(PyArrayIterObject *, PyObject *); + +NPY_NO_EXPORT int +iter_ass_subscript(PyArrayIterObject *, PyObject *, PyObject *); + +#endif diff --git a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src new file mode 100644 index 0000000..397aaf2 --- /dev/null +++ b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src @@ -0,0 +1,1795 @@ +/* + * This file contains low-level loops for copying and byte-swapping + * strided data. + * + * Copyright (c) 2010 by Mark Wiebe (mwwiebe@gmail.com) + * The University of British Columbia + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include +#include +#include + +#include "lowlevel_strided_loops.h" + +/* used for some alignment checks */ +#define _ALIGN(type) offsetof(struct {char c; type v;}, v) +/* + * Disable harmless compiler warning "4116: unnamed type definition in + * parentheses" which is caused by the _ALIGN macro. + */ +#if defined(_MSC_VER) +#pragma warning(disable:4116) +#endif + + +/* + * x86 platform works with unaligned access but the compiler is allowed to + * assume all data is aligned to its size by the C standard. This means it can + * vectorize instructions peeling only by the size of the type, if the data is + * not aligned to this size one ends up with data not correctly aligned for SSE + * instructions (16 byte). + * So this flag can only be enabled if autovectorization is disabled. + */ +#if NPY_CPU_HAVE_UNALIGNED_ACCESS +# define NPY_USE_UNALIGNED_ACCESS 0 +#else +# define NPY_USE_UNALIGNED_ACCESS 0 +#endif + +#define _NPY_NOP1(x) (x) +#define _NPY_NOP2(x) (x) +#define _NPY_NOP4(x) (x) +#define _NPY_NOP8(x) (x) + +#define _NPY_SWAP2(x) npy_bswap2(x) + +#define _NPY_SWAP4(x) npy_bswap4(x) + +#define _NPY_SWAP_PAIR4(x) (((((npy_uint32)x)&0xffu) << 8) | \ + ((((npy_uint32)x)&0xff00u) >> 8) | \ + ((((npy_uint32)x)&0xff0000u) << 8) | \ + ((((npy_uint32)x)&0xff000000u) >> 8)) + +#define _NPY_SWAP8(x) npy_bswap8(x) + +#define _NPY_SWAP_PAIR8(x) (((((npy_uint64)x)&0xffULL) << 24) | \ + ((((npy_uint64)x)&0xff00ULL) << 8) | \ + ((((npy_uint64)x)&0xff0000ULL) >> 8) | \ + ((((npy_uint64)x)&0xff000000ULL) >> 24) | \ + ((((npy_uint64)x)&0xff00000000ULL) << 24) | \ + ((((npy_uint64)x)&0xff0000000000ULL) << 8) | \ + ((((npy_uint64)x)&0xff000000000000ULL) >> 8) | \ + ((((npy_uint64)x)&0xff00000000000000ULL) >> 24)) + +#define _NPY_SWAP_INPLACE2(x) npy_bswap2_unaligned(x) + +#define _NPY_SWAP_INPLACE4(x) npy_bswap4_unaligned(x) + +#define _NPY_SWAP_INPLACE8(x) npy_bswap8_unaligned(x) + +#define _NPY_SWAP_INPLACE16(x) { \ + char a = (x)[0]; (x)[0] = (x)[15]; (x)[15] = a; \ + a = (x)[1]; (x)[1] = (x)[14]; (x)[14] = a; \ + a = (x)[2]; (x)[2] = (x)[13]; (x)[13] = a; \ + a = (x)[3]; (x)[3] = (x)[12]; (x)[12] = a; \ + a = (x)[4]; (x)[4] = (x)[11]; (x)[11] = a; \ + a = (x)[5]; (x)[5] = (x)[10]; (x)[10] = a; \ + a = (x)[6]; (x)[6] = (x)[9]; (x)[9] = a; \ + a = (x)[7]; (x)[7] = (x)[8]; (x)[8] = a; \ + } + +/************* STRIDED COPYING/SWAPPING SPECIALIZED FUNCTIONS *************/ + +/**begin repeat + * #elsize = 1, 2, 4, 8, 16# + * #elsize_half = 0, 1, 2, 4, 8# + * #type = npy_uint8, npy_uint16, npy_uint32, npy_uint64, npy_uint128# + */ +/**begin repeat1 + * #oper = strided_to_strided, strided_to_contig, + * contig_to_strided, contig_to_contig# + * #src_contig = 0, 0, 1 ,1# + * #dst_contig = 0, 1, 0 ,1# + */ +/**begin repeat2 + * #swap = _NPY_NOP, _NPY_NOP, _NPY_SWAP_INPLACE, _NPY_SWAP, + * _NPY_SWAP_INPLACE, _NPY_SWAP_PAIR# + * #prefix = , _aligned, _swap, _aligned_swap, _swap_pair, _aligned_swap_pair# + * #is_aligned = 0, 1, 0, 1, 0, 1# + * #minelsize = 1, 1, 2, 2, 4, 4# + * #is_swap = 0, 0, 1, 1, 2, 2# + */ + +#if (@elsize@ >= @minelsize@) && \ + (@elsize@ > 1 || @is_aligned@) && \ + (!NPY_USE_UNALIGNED_ACCESS || @is_aligned@) + + +#if @is_swap@ || @src_contig@ == 0 || @dst_contig@ == 0 +/* + * unrolling gains about 20-50% if the copy can be done in one mov instruction + * if not it can decrease performance + * tested to improve performance on intel xeon 5x/7x, core2duo, amd phenom x4 + */ +static void +#if @is_aligned@ && @is_swap@ == 0 && @elsize@ <= NPY_SIZEOF_INTP + NPY_GCC_UNROLL_LOOPS +#endif +@prefix@_@oper@_size@elsize@(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *NPY_UNUSED(data)) +{ +#if @is_aligned@ && @elsize@ != 16 + /* sanity check */ + assert(npy_is_aligned(dst, _ALIGN(@type@))); + assert(npy_is_aligned(src, _ALIGN(@type@))); +#endif + /*printf("fn @prefix@_@oper@_size@elsize@\n");*/ + while (N > 0) { +#if @is_aligned@ + + /* aligned copy and swap */ +# if @elsize@ != 16 + (*((@type@ *)dst)) = @swap@@elsize@(*((@type@ *)src)); +# else +# if @is_swap@ == 0 + (*((npy_uint64 *)dst)) = (*((npy_uint64 *)src)); + (*((npy_uint64 *)dst + 1)) = (*((npy_uint64 *)src + 1)); +# elif @is_swap@ == 1 + (*((npy_uint64 *)dst)) = _NPY_SWAP8(*((npy_uint64 *)src + 1)); + (*((npy_uint64 *)dst + 1)) = _NPY_SWAP8(*((npy_uint64 *)src)); +# elif @is_swap@ == 2 + (*((npy_uint64 *)dst)) = _NPY_SWAP8(*((npy_uint64 *)src)); + (*((npy_uint64 *)dst + 1)) = _NPY_SWAP8(*((npy_uint64 *)src + 1)); +# endif +# endif + +#else + + /* unaligned copy and swap */ + memmove(dst, src, @elsize@); +# if @is_swap@ == 1 + @swap@@elsize@(dst); +# elif @is_swap@ == 2 + @swap@@elsize_half@(dst); + @swap@@elsize_half@(dst + @elsize_half@); +# endif + +#endif + +#if @dst_contig@ + dst += @elsize@; +#else + dst += dst_stride; +#endif + +#if @src_contig@ + src += @elsize@; +#else + src += src_stride; +#endif + + --N; + } +} +#endif + + +/* + * specialized copy and swap for source stride 0, + * interestingly unrolling here is like above is only marginally profitable for + * small types and detrimental for >= 8byte moves on x86 + * but it profits from vectorization enabled with -O3 + */ +#if (@src_contig@ == 0) && @is_aligned@ +static NPY_GCC_OPT_3 void +@prefix@_@oper@_size@elsize@_srcstride0(char *dst, + npy_intp dst_stride, + char *src, npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *NPY_UNUSED(data)) +{ +#if @elsize@ != 16 +# if !(@elsize@ == 1 && @dst_contig@) + @type@ temp; +# endif +#else + npy_uint64 temp0, temp1; +#endif + if (N == 0) { + return; + } +#if @is_aligned@ && @elsize@ != 16 + /* sanity check */ + assert(npy_is_aligned(dst, _ALIGN(@type@))); + assert(npy_is_aligned(src, _ALIGN(@type@))); +#endif +#if @elsize@ == 1 && @dst_contig@ + memset(dst, *src, N); +#else + +# if @elsize@ != 16 + temp = @swap@@elsize@(*((@type@ *)src)); +# else +# if @is_swap@ == 0 + temp0 = (*((npy_uint64 *)src)); + temp1 = (*((npy_uint64 *)src + 1)); +# elif @is_swap@ == 1 + temp0 = _NPY_SWAP8(*((npy_uint64 *)src + 1)); + temp1 = _NPY_SWAP8(*((npy_uint64 *)src)); +# elif @is_swap@ == 2 + temp0 = _NPY_SWAP8(*((npy_uint64 *)src)); + temp1 = _NPY_SWAP8(*((npy_uint64 *)src + 1)); +# endif +# endif + + while (N > 0) { +# if @elsize@ != 16 + *((@type@ *)dst) = temp; +# else + *((npy_uint64 *)dst) = temp0; + *((npy_uint64 *)dst + 1) = temp1; +# endif +# if @dst_contig@ + dst += @elsize@; +# else + dst += dst_stride; +# endif + --N; + } +#endif/* @elsize == 1 && @dst_contig@ -- else */ +} +#endif/* (@src_contig@ == 0) && @is_aligned@ */ + +#endif/* @elsize@ >= @minelsize@ */ + +/**end repeat2**/ +/**end repeat1**/ +/**end repeat**/ + +static void +_strided_to_strided(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *NPY_UNUSED(data)) +{ + while (N > 0) { + memmove(dst, src, src_itemsize); + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_swap_strided_to_strided(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *NPY_UNUSED(data)) +{ + char *a, *b, c; + + while (N > 0) { + memmove(dst, src, src_itemsize); + /* general in-place swap */ + a = dst; + b = dst + src_itemsize - 1; + while (a < b) { + c = *a; + *a = *b; + *b = c; + ++a; --b; + } + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_swap_pair_strided_to_strided(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *NPY_UNUSED(data)) +{ + char *a, *b, c; + npy_intp itemsize_half = src_itemsize / 2; + + while (N > 0) { + memmove(dst, src, src_itemsize); + /* general in-place swap */ + a = dst; + b = dst + itemsize_half - 1; + while (a < b) { + c = *a; + *a = *b; + *b = c; + ++a; --b; + } + /* general in-place swap */ + a = dst + itemsize_half; + b = dst + 2*itemsize_half - 1; + while (a < b) { + c = *a; + *a = *b; + *b = c; + ++a; --b; + } + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_contig_to_contig(char *dst, npy_intp NPY_UNUSED(dst_stride), + char *src, npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp src_itemsize, + NpyAuxData *NPY_UNUSED(data)) +{ + memmove(dst, src, src_itemsize*N); +} + + +NPY_NO_EXPORT PyArray_StridedUnaryOp * +PyArray_GetStridedCopyFn(int aligned, npy_intp src_stride, + npy_intp dst_stride, npy_intp itemsize) +{ +/* + * Skip the "unaligned" versions on CPUs which support unaligned + * memory accesses. + */ +#if !NPY_USE_UNALIGNED_ACCESS + if (aligned) { +#endif/*!NPY_USE_UNALIGNED_ACCESS*/ + + /* contiguous dst */ + if (itemsize != 0 && dst_stride == itemsize) { + /* constant src */ + if (src_stride == 0) { + switch (itemsize) { +/**begin repeat + * #elsize = 1, 2, 4, 8, 16# + */ + case @elsize@: + return + &_aligned_strided_to_contig_size@elsize@_srcstride0; +/**end repeat**/ + } + } + /* contiguous src */ + else if (src_stride == itemsize) { + return &_contig_to_contig; + } + /* general src */ + else { + switch (itemsize) { +/**begin repeat + * #elsize = 1, 2, 4, 8, 16# + */ + case @elsize@: + return &_aligned_strided_to_contig_size@elsize@; +/**end repeat**/ + } + } + + return &_strided_to_strided; + } + /* general dst */ + else { + /* constant src */ + if (src_stride == 0) { + switch (itemsize) { +/**begin repeat + * #elsize = 1, 2, 4, 8, 16# + */ + case @elsize@: + return + &_aligned_strided_to_strided_size@elsize@_srcstride0; +/**end repeat**/ + } + } + /* contiguous src */ + else if (src_stride == itemsize) { + switch (itemsize) { +/**begin repeat + * #elsize = 1, 2, 4, 8, 16# + */ + case @elsize@: + return &_aligned_contig_to_strided_size@elsize@; +/**end repeat**/ + } + + return &_strided_to_strided; + } + else { + switch (itemsize) { +/**begin repeat + * #elsize = 1, 2, 4, 8, 16# + */ + case @elsize@: + return &_aligned_strided_to_strided_size@elsize@; +/**end repeat**/ + } + } + } + +#if !NPY_USE_UNALIGNED_ACCESS + } + else { + /* contiguous dst */ + if (itemsize != 0 && dst_stride == itemsize) { + /* contiguous src */ + if (itemsize != 0 && src_stride == itemsize) { + return &_contig_to_contig; + } + /* general src */ + else { + switch (itemsize) { + case 1: + return &_aligned_strided_to_contig_size1; +/**begin repeat + * #elsize = 2, 4, 8, 16# + */ + case @elsize@: + return &_strided_to_contig_size@elsize@; +/**end repeat**/ + } + } + + return &_strided_to_strided; + } + /* general dst */ + else { + /* contiguous src */ + if (itemsize != 0 && src_stride == itemsize) { + switch (itemsize) { + case 1: + return &_aligned_contig_to_strided_size1; +/**begin repeat + * #elsize = 2, 4, 8, 16# + */ + case @elsize@: + return &_contig_to_strided_size@elsize@; +/**end repeat**/ + } + + return &_strided_to_strided; + } + /* general src */ + else { + switch (itemsize) { + case 1: + return &_aligned_strided_to_strided_size1; +/**begin repeat + * #elsize = 2, 4, 8, 16# + */ + case @elsize@: + return &_strided_to_strided_size@elsize@; +/**end repeat**/ + } + } + } + } +#endif/*!NPY_USE_UNALIGNED_ACCESS*/ + + return &_strided_to_strided; +} + +/* + * PyArray_GetStridedCopySwapFn and PyArray_GetStridedCopySwapPairFn are + * nearly identical, so can do a repeat for them. + */ +/**begin repeat + * #function = PyArray_GetStridedCopySwapFn, PyArray_GetStridedCopySwapPairFn# + * #tag = , _pair# + * #not_pair = 1, 0# + */ + +NPY_NO_EXPORT PyArray_StridedUnaryOp * +@function@(int aligned, npy_intp src_stride, + npy_intp dst_stride, npy_intp itemsize) +{ +/* + * Skip the "unaligned" versions on CPUs which support unaligned + * memory accesses. + */ +#if !NPY_USE_UNALIGNED_ACCESS + if (aligned) { +#endif/*!NPY_USE_UNALIGNED_ACCESS*/ + + /* contiguous dst */ + if (itemsize != 0 && dst_stride == itemsize) { + /* constant src */ + if (src_stride == 0) { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return + &_aligned_swap@tag@_strided_to_contig_size@elsize@_srcstride0; +#endif +/**end repeat1**/ + } + } + /* contiguous src */ + else if (src_stride == itemsize) { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return &_aligned_swap@tag@_contig_to_contig_size@elsize@; +#endif +/**end repeat1**/ + } + } + /* general src */ + else { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return &_aligned_swap@tag@_strided_to_contig_size@elsize@; +#endif +/**end repeat1**/ + } + } + } + /* general dst */ + else { + /* constant src */ + if (src_stride == 0) { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return + &_aligned_swap@tag@_strided_to_strided_size@elsize@_srcstride0; +#endif +/**end repeat1**/ + } + } + /* contiguous src */ + else if (src_stride == itemsize) { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return &_aligned_swap@tag@_contig_to_strided_size@elsize@; +#endif +/**end repeat1**/ + } + + return &_swap@tag@_strided_to_strided; + } + else { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return &_aligned_swap@tag@_strided_to_strided_size@elsize@; +#endif +/**end repeat1**/ + } + } + } + +#if !NPY_USE_UNALIGNED_ACCESS + } + else { + /* contiguous dst */ + if (itemsize != 0 && dst_stride == itemsize) { + /* contiguous src */ + if (itemsize != 0 && src_stride == itemsize) { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return &_swap@tag@_contig_to_contig_size@elsize@; +#endif +/**end repeat1**/ + } + } + /* general src */ + else { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return &_swap@tag@_strided_to_contig_size@elsize@; +#endif +/**end repeat1**/ + } + } + + return &_swap@tag@_strided_to_strided; + } + /* general dst */ + else { + /* contiguous src */ + if (itemsize != 0 && src_stride == itemsize) { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return &_swap@tag@_contig_to_strided_size@elsize@; +#endif +/**end repeat1**/ + } + + return &_swap@tag@_strided_to_strided; + } + /* general src */ + else { + switch (itemsize) { +/**begin repeat1 + * #elsize = 2, 4, 8, 16# + */ +#if @not_pair@ || @elsize@ > 2 + case @elsize@: + return &_swap@tag@_strided_to_strided_size@elsize@; +#endif +/**end repeat1**/ + } + } + } + } +#endif/*!NPY_USE_UNALIGNED_ACCESS*/ + + return &_swap@tag@_strided_to_strided; +} + +/**end repeat**/ + +/************* STRIDED CASTING SPECIALIZED FUNCTIONS *************/ + +/**begin repeat + * + * #NAME1 = BOOL, + * UBYTE, USHORT, UINT, ULONG, ULONGLONG, + * BYTE, SHORT, INT, LONG, LONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #name1 = bool, + * ubyte, ushort, uint, ulong, ulonglong, + * byte, short, int, long, longlong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type1 = npy_bool, + * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, + * npy_byte, npy_short, npy_int, npy_long, npy_longlong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + * #rtype1 = npy_bool, + * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, + * npy_byte, npy_short, npy_int, npy_long, npy_longlong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_float, npy_double, npy_longdouble# + * #is_bool1 = 1, 0*17# + * #is_half1 = 0*11, 1, 0*6# + * #is_float1 = 0*12, 1, 0, 0, 1, 0, 0# + * #is_double1 = 0*13, 1, 0, 0, 1, 0# + * #is_complex1 = 0*15, 1*3# + */ + +/**begin repeat1 + * + * #NAME2 = BOOL, + * UBYTE, USHORT, UINT, ULONG, ULONGLONG, + * BYTE, SHORT, INT, LONG, LONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #name2 = bool, + * ubyte, ushort, uint, ulong, ulonglong, + * byte, short, int, long, longlong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type2 = npy_bool, + * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, + * npy_byte, npy_short, npy_int, npy_long, npy_longlong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + * #rtype2 = npy_bool, + * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, + * npy_byte, npy_short, npy_int, npy_long, npy_longlong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_float, npy_double, npy_longdouble# + * #is_bool2 = 1, 0*17# + * #is_half2 = 0*11, 1, 0*6# + * #is_float2 = 0*12, 1, 0, 0, 1, 0, 0# + * #is_double2 = 0*13, 1, 0, 0, 1, 0# + * #is_complex2 = 0*15, 1*3# + */ + +/**begin repeat2 + * #prefix = _aligned,,_aligned_contig,_contig# + * #aligned = 1,0,1,0# + * #contig = 0,0,1,1# + */ + +#if !(NPY_USE_UNALIGNED_ACCESS && !@aligned@) + +/* For half types, don't use actual double/float types in conversion */ +#if @is_half1@ || @is_half2@ + +# if @is_float1@ +# define _TYPE1 npy_uint32 +# elif @is_double1@ +# define _TYPE1 npy_uint64 +# else +# define _TYPE1 @rtype1@ +# endif + +# if @is_float2@ +# define _TYPE2 npy_uint32 +# elif @is_double2@ +# define _TYPE2 npy_uint64 +# else +# define _TYPE2 @rtype2@ +# endif + +#else + +#define _TYPE1 @rtype1@ +#define _TYPE2 @rtype2@ + +#endif + +/* Determine an appropriate casting conversion function */ +#if @is_half1@ + +# if @is_float2@ +# define _CONVERT_FN(x) npy_halfbits_to_floatbits(x) +# elif @is_double2@ +# define _CONVERT_FN(x) npy_halfbits_to_doublebits(x) +# elif @is_half2@ +# define _CONVERT_FN(x) (x) +# elif @is_bool2@ +# define _CONVERT_FN(x) ((npy_bool)!npy_half_iszero(x)) +# else +# define _CONVERT_FN(x) ((_TYPE2)npy_half_to_float(x)) +# endif + +#elif @is_half2@ + +# if @is_float1@ +# define _CONVERT_FN(x) npy_floatbits_to_halfbits(x) +# elif @is_double1@ +# define _CONVERT_FN(x) npy_doublebits_to_halfbits(x) +# else +# define _CONVERT_FN(x) npy_float_to_half((float)x) +# endif + +#else + +# if @is_bool2@ || @is_bool1@ +# define _CONVERT_FN(x) ((npy_bool)(x != 0)) +# else +# define _CONVERT_FN(x) ((_TYPE2)x) +# endif + +#endif + +static NPY_GCC_OPT_3 void +@prefix@_cast_@name1@_to_@name2@( + char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp NPY_UNUSED(src_itemsize), + NpyAuxData *NPY_UNUSED(data)) +{ +#if @is_complex1@ + _TYPE1 src_value[2]; +#elif !@aligned@ + _TYPE1 src_value; +#endif +#if @is_complex2@ + _TYPE2 dst_value[2]; +#elif !@aligned@ + _TYPE2 dst_value; +#endif + +#if @aligned@ + /* sanity check */ +# if !@is_complex1@ + assert(npy_is_aligned(src, _ALIGN(_TYPE1))); +# endif +# if !@is_complex2@ + assert(npy_is_aligned(dst, _ALIGN(_TYPE2))); +# endif +#endif + + /*printf("@prefix@_cast_@name1@_to_@name2@\n");*/ + + while (N--) { +#if @aligned@ +# if @is_complex1@ + src_value[0] = ((_TYPE1 *)src)[0]; + src_value[1] = ((_TYPE1 *)src)[1]; +# endif +#else + memmove(&src_value, src, sizeof(src_value)); +#endif + +/* Do the cast */ +#if @is_complex1@ +# if @is_complex2@ + dst_value[0] = _CONVERT_FN(src_value[0]); + dst_value[1] = _CONVERT_FN(src_value[1]); +# elif !@aligned@ +# if @is_bool2@ + dst_value = _CONVERT_FN(src_value[0]) || _CONVERT_FN(src_value[1]); +# else + dst_value = _CONVERT_FN(src_value[0]); +# endif +# else +# if @is_bool2@ + *(_TYPE2 *)dst = _CONVERT_FN(src_value[0]) || _CONVERT_FN(src_value[1]); +# else + *(_TYPE2 *)dst = _CONVERT_FN(src_value[0]); +# endif +# endif +#else +# if @is_complex2@ +# if !@aligned@ + dst_value[0] = _CONVERT_FN(src_value); +# else + dst_value[0] = _CONVERT_FN(*(_TYPE1 *)src); +# endif + dst_value[1] = 0; +# elif !@aligned@ + dst_value = _CONVERT_FN(src_value); +# else + *(_TYPE2 *)dst = _CONVERT_FN(*(_TYPE1 *)src); +# endif +#endif + +#if @aligned@ +# if @is_complex2@ + ((_TYPE2 *)dst)[0] = dst_value[0]; + ((_TYPE2 *)dst)[1] = dst_value[1]; +# endif +#else + memmove(dst, &dst_value, sizeof(dst_value)); +#endif + +#if @contig@ + dst += sizeof(@type2@); + src += sizeof(@type1@); +#else + dst += dst_stride; + src += src_stride; +#endif + } +} + +#undef _CONVERT_FN +#undef _TYPE2 +#undef _TYPE1 + +#endif + +/**end repeat2**/ + +/**end repeat1**/ + +/**end repeat**/ + +NPY_NO_EXPORT PyArray_StridedUnaryOp * +PyArray_GetStridedNumericCastFn(int aligned, npy_intp src_stride, + npy_intp dst_stride, + int src_type_num, int dst_type_num) +{ + switch (src_type_num) { +/**begin repeat + * + * #NAME1 = BOOL, + * UBYTE, USHORT, UINT, ULONG, ULONGLONG, + * BYTE, SHORT, INT, LONG, LONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #name1 = bool, + * ubyte, ushort, uint, ulong, ulonglong, + * byte, short, int, long, longlong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type1 = npy_bool, + * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, + * npy_byte, npy_short, npy_int, npy_long, npy_longlong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + */ + + case NPY_@NAME1@: + /*printf("test fn %d - second %d\n", NPY_@NAME1@, dst_type_num);*/ + switch (dst_type_num) { +/**begin repeat1 + * + * #NAME2 = BOOL, + * UBYTE, USHORT, UINT, ULONG, ULONGLONG, + * BYTE, SHORT, INT, LONG, LONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #name2 = bool, + * ubyte, ushort, uint, ulong, ulonglong, + * byte, short, int, long, longlong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type2 = npy_bool, + * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, + * npy_byte, npy_short, npy_int, npy_long, npy_longlong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + */ + + case NPY_@NAME2@: + /*printf("ret fn %d %d\n", NPY_@NAME1@, NPY_@NAME2@);*/ +# if NPY_USE_UNALIGNED_ACCESS + if (src_stride == sizeof(@type1@) && + dst_stride == sizeof(@type2@)) { + return &_aligned_contig_cast_@name1@_to_@name2@; + } + else { + return &_aligned_cast_@name1@_to_@name2@; + } +# else + if (src_stride == sizeof(@type1@) && + dst_stride == sizeof(@type2@)) { + return aligned ? + &_aligned_contig_cast_@name1@_to_@name2@ : + &_contig_cast_@name1@_to_@name2@; + } + else { + return aligned ? &_aligned_cast_@name1@_to_@name2@ : + &_cast_@name1@_to_@name2@; + } +# endif + +/**end repeat1**/ + } + /*printf("switched test fn %d - second %d\n", NPY_@NAME1@, dst_type_num);*/ + +/**end repeat**/ + } + + return NULL; +} + + +/****************** PRIMITIVE FLAT TO/FROM NDIM FUNCTIONS ******************/ + +/* See documentation of arguments in lowlevel_strided_loops.h */ +NPY_NO_EXPORT npy_intp +PyArray_TransferNDimToStrided(npy_intp ndim, + char *dst, npy_intp dst_stride, + char *src, npy_intp *src_strides, npy_intp src_strides_inc, + npy_intp *coords, npy_intp coords_inc, + npy_intp *shape, npy_intp shape_inc, + npy_intp count, npy_intp src_itemsize, + PyArray_StridedUnaryOp *stransfer, + NpyAuxData *data) +{ + npy_intp i, M, N, coord0, shape0, src_stride0, coord1, shape1, src_stride1; + + /* Finish off dimension 0 */ + coord0 = coords[0]; + shape0 = shape[0]; + src_stride0 = src_strides[0]; + N = shape0 - coord0; + if (N >= count) { + stransfer(dst, dst_stride, src, src_stride0, count, src_itemsize, data); + return 0; + } + stransfer(dst, dst_stride, src, src_stride0, N, src_itemsize, data); + count -= N; + + /* If it's 1-dimensional, there's no more to copy */ + if (ndim == 1) { + return count; + } + + /* Adjust the src and dst pointers */ + coord1 = (coords + coords_inc)[0]; + shape1 = (shape + shape_inc)[0]; + src_stride1 = (src_strides + src_strides_inc)[0]; + src = src - coord0*src_stride0 + src_stride1; + dst += N*dst_stride; + + /* Finish off dimension 1 */ + M = (shape1 - coord1 - 1); + N = shape0*M; + for (i = 0; i < M; ++i) { + if (shape0 >= count) { + stransfer(dst, dst_stride, src, src_stride0, + count, src_itemsize, data); + return 0; + } + else { + stransfer(dst, dst_stride, src, src_stride0, + shape0, src_itemsize, data); + } + count -= shape0; + src += src_stride1; + dst += shape0*dst_stride; + } + + /* If it's 2-dimensional, there's no more to copy */ + if (ndim == 2) { + return count; + } + + /* General-case loop for everything else */ + else { + /* Iteration structure for dimensions 2 and up */ + struct { + npy_intp coord, shape, src_stride; + } it[NPY_MAXDIMS]; + + /* Copy the coordinates and shape */ + coords += 2*coords_inc; + shape += 2*shape_inc; + src_strides += 2*src_strides_inc; + for (i = 0; i < ndim-2; ++i) { + it[i].coord = coords[0]; + it[i].shape = shape[0]; + it[i].src_stride = src_strides[0]; + coords += coords_inc; + shape += shape_inc; + src_strides += src_strides_inc; + } + + for (;;) { + /* Adjust the src pointer from the dimension 0 and 1 loop */ + src = src - shape1*src_stride1; + + /* Increment to the next coordinate */ + for (i = 0; i < ndim-2; ++i) { + src += it[i].src_stride; + if (++it[i].coord >= it[i].shape) { + it[i].coord = 0; + src -= it[i].src_stride*it[i].shape; + } + else { + break; + } + } + /* If the last dimension rolled over, we're done */ + if (i == ndim-2) { + return count; + } + + /* A loop for dimensions 0 and 1 */ + for (i = 0; i < shape1; ++i) { + if (shape0 >= count) { + stransfer(dst, dst_stride, src, src_stride0, + count, src_itemsize, data); + return 0; + } + else { + stransfer(dst, dst_stride, src, src_stride0, + shape0, src_itemsize, data); + } + count -= shape0; + src += src_stride1; + dst += shape0*dst_stride; + } + } + } +} + +/* See documentation of arguments in lowlevel_strided_loops.h */ +NPY_NO_EXPORT npy_intp +PyArray_TransferStridedToNDim(npy_intp ndim, + char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, + char *src, npy_intp src_stride, + npy_intp *coords, npy_intp coords_inc, + npy_intp *shape, npy_intp shape_inc, + npy_intp count, npy_intp src_itemsize, + PyArray_StridedUnaryOp *stransfer, + NpyAuxData *data) +{ + npy_intp i, M, N, coord0, shape0, dst_stride0, coord1, shape1, dst_stride1; + + /* Finish off dimension 0 */ + coord0 = coords[0]; + shape0 = shape[0]; + dst_stride0 = dst_strides[0]; + N = shape0 - coord0; + if (N >= count) { + stransfer(dst, dst_stride0, src, src_stride, count, src_itemsize, data); + return 0; + } + stransfer(dst, dst_stride0, src, src_stride, N, src_itemsize, data); + count -= N; + + /* If it's 1-dimensional, there's no more to copy */ + if (ndim == 1) { + return count; + } + + /* Adjust the src and dst pointers */ + coord1 = (coords + coords_inc)[0]; + shape1 = (shape + shape_inc)[0]; + dst_stride1 = (dst_strides + dst_strides_inc)[0]; + dst = dst - coord0*dst_stride0 + dst_stride1; + src += N*src_stride; + + /* Finish off dimension 1 */ + M = (shape1 - coord1 - 1); + N = shape0*M; + for (i = 0; i < M; ++i) { + if (shape0 >= count) { + stransfer(dst, dst_stride0, src, src_stride, + count, src_itemsize, data); + return 0; + } + else { + stransfer(dst, dst_stride0, src, src_stride, + shape0, src_itemsize, data); + } + count -= shape0; + dst += dst_stride1; + src += shape0*src_stride; + } + + /* If it's 2-dimensional, there's no more to copy */ + if (ndim == 2) { + return count; + } + + /* General-case loop for everything else */ + else { + /* Iteration structure for dimensions 2 and up */ + struct { + npy_intp coord, shape, dst_stride; + } it[NPY_MAXDIMS]; + + /* Copy the coordinates and shape */ + coords += 2*coords_inc; + shape += 2*shape_inc; + dst_strides += 2*dst_strides_inc; + for (i = 0; i < ndim-2; ++i) { + it[i].coord = coords[0]; + it[i].shape = shape[0]; + it[i].dst_stride = dst_strides[0]; + coords += coords_inc; + shape += shape_inc; + dst_strides += dst_strides_inc; + } + + for (;;) { + /* Adjust the dst pointer from the dimension 0 and 1 loop */ + dst = dst - shape1*dst_stride1; + + /* Increment to the next coordinate */ + for (i = 0; i < ndim-2; ++i) { + dst += it[i].dst_stride; + if (++it[i].coord >= it[i].shape) { + it[i].coord = 0; + dst -= it[i].dst_stride*it[i].shape; + } + else { + break; + } + } + /* If the last dimension rolled over, we're done */ + if (i == ndim-2) { + return count; + } + + /* A loop for dimensions 0 and 1 */ + for (i = 0; i < shape1; ++i) { + if (shape0 >= count) { + stransfer(dst, dst_stride0, src, src_stride, + count, src_itemsize, data); + return 0; + } + else { + stransfer(dst, dst_stride0, src, src_stride, + shape0, src_itemsize, data); + } + count -= shape0; + dst += dst_stride1; + src += shape0*src_stride; + } + } + } +} + +/* See documentation of arguments in lowlevel_strided_loops.h */ +NPY_NO_EXPORT npy_intp +PyArray_TransferMaskedStridedToNDim(npy_intp ndim, + char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, + char *src, npy_intp src_stride, + npy_uint8 *mask, npy_intp mask_stride, + npy_intp *coords, npy_intp coords_inc, + npy_intp *shape, npy_intp shape_inc, + npy_intp count, npy_intp src_itemsize, + PyArray_MaskedStridedUnaryOp *stransfer, + NpyAuxData *data) +{ + npy_intp i, M, N, coord0, shape0, dst_stride0, coord1, shape1, dst_stride1; + + /* Finish off dimension 0 */ + coord0 = coords[0]; + shape0 = shape[0]; + dst_stride0 = dst_strides[0]; + N = shape0 - coord0; + if (N >= count) { + stransfer(dst, dst_stride0, + src, src_stride, + mask, mask_stride, + count, src_itemsize, data); + return 0; + } + stransfer(dst, dst_stride0, + src, src_stride, + mask, mask_stride, + N, src_itemsize, data); + count -= N; + + /* If it's 1-dimensional, there's no more to copy */ + if (ndim == 1) { + return count; + } + + /* Adjust the src and dst pointers */ + coord1 = (coords + coords_inc)[0]; + shape1 = (shape + shape_inc)[0]; + dst_stride1 = (dst_strides + dst_strides_inc)[0]; + dst = dst - coord0*dst_stride0 + dst_stride1; + src += N*src_stride; + mask += N*mask_stride; + + /* Finish off dimension 1 */ + M = (shape1 - coord1 - 1); + N = shape0*M; + for (i = 0; i < M; ++i) { + if (shape0 >= count) { + stransfer(dst, dst_stride0, + src, src_stride, + mask, mask_stride, + count, src_itemsize, data); + return 0; + } + else { + stransfer(dst, dst_stride0, + src, src_stride, + mask, mask_stride, + shape0, src_itemsize, data); + } + count -= shape0; + dst += dst_stride1; + src += shape0*src_stride; + mask += shape0*mask_stride; + } + + /* If it's 2-dimensional, there's no more to copy */ + if (ndim == 2) { + return count; + } + + /* General-case loop for everything else */ + else { + /* Iteration structure for dimensions 2 and up */ + struct { + npy_intp coord, shape, dst_stride; + } it[NPY_MAXDIMS]; + + /* Copy the coordinates and shape */ + coords += 2*coords_inc; + shape += 2*shape_inc; + dst_strides += 2*dst_strides_inc; + for (i = 0; i < ndim-2; ++i) { + it[i].coord = coords[0]; + it[i].shape = shape[0]; + it[i].dst_stride = dst_strides[0]; + coords += coords_inc; + shape += shape_inc; + dst_strides += dst_strides_inc; + } + + for (;;) { + /* Adjust the dst pointer from the dimension 0 and 1 loop */ + dst = dst - shape1*dst_stride1; + + /* Increment to the next coordinate */ + for (i = 0; i < ndim-2; ++i) { + dst += it[i].dst_stride; + if (++it[i].coord >= it[i].shape) { + it[i].coord = 0; + dst -= it[i].dst_stride*it[i].shape; + } + else { + break; + } + } + /* If the last dimension rolled over, we're done */ + if (i == ndim-2) { + return count; + } + + /* A loop for dimensions 0 and 1 */ + for (i = 0; i < shape1; ++i) { + if (shape0 >= count) { + stransfer(dst, dst_stride0, + src, src_stride, + mask, mask_stride, + count, src_itemsize, data); + return 0; + } + else { + stransfer(dst, dst_stride0, + src, src_stride, + mask, mask_stride, + shape0, src_itemsize, data); + } + count -= shape0; + dst += dst_stride1; + src += shape0*src_stride; + mask += shape0*mask_stride; + } + } + } +} + + +/***************************************************************************/ +/****************** MapIter (Advanced indexing) Get/Set ********************/ +/***************************************************************************/ + +/**begin repeat + * #name = set, get# + * #isget = 0, 1# + */ + +/* + * Advanded indexing iteration of arrays when there is a single indexing + * array which has the same memory order as the value array and both + * can be trivally iterated (single stride, aligned, no casting necessary). + */ +NPY_NO_EXPORT int +mapiter_trivial_@name@(PyArrayObject *self, PyArrayObject *ind, + PyArrayObject *result) +{ + char *base_ptr, *ind_ptr, *result_ptr; + npy_intp self_stride, ind_stride, result_stride; + npy_intp fancy_dim = PyArray_DIM(self, 0); + + npy_intp itersize; + + int is_aligned = PyArray_ISALIGNED(self) && PyArray_ISALIGNED(result); + int needs_api = PyDataType_REFCHK(PyArray_DESCR(self)); + + PyArray_CopySwapFunc *copyswap = PyArray_DESCR(self)->f->copyswap; + NPY_BEGIN_THREADS_DEF; + + base_ptr = PyArray_BYTES(self); + self_stride = PyArray_STRIDE(self, 0); + + PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(ind, result, itersize, + ind_ptr, result_ptr, + ind_stride, result_stride) + + if (!needs_api) { + NPY_BEGIN_THREADS_THRESHOLDED(PyArray_SIZE(ind)); + } +#if !@isget@ + /* Check the indices beforehand */ + while (itersize--) { + npy_intp indval = *((npy_intp*)ind_ptr); + if (check_and_adjust_index(&indval, fancy_dim, 1, _save) < 0 ) { + return -1; + } + ind_ptr += ind_stride; + } + + /* + * Reset the ind_ptr and itersize, due to broadcasting it is always + * the size of ind. + */ + ind_ptr = PyArray_BYTES(ind); + itersize = PyArray_SIZE(ind); +#endif + + /* Optimization for aligned types that do not need the api */ + switch ((is_aligned && !needs_api) ? PyArray_ITEMSIZE(self) : 0) { + +/**begin repeat1 + * #elsize = 1, 2, 4, 8, 0# + * #copytype = npy_uint8, npy_uint16, npy_uint32, npy_uint64, 0# + */ + +#if @elsize@ + case @elsize@: +#else + default: +#endif + while (itersize--) { + char * self_ptr; + npy_intp indval = *((npy_intp*)ind_ptr); + assert(npy_is_aligned(ind_ptr, _ALIGN(npy_intp))); +#if @isget@ + if (check_and_adjust_index(&indval, fancy_dim, 1, _save) < 0 ) { + return -1; + } +#else + if (indval < 0) { + indval += fancy_dim; + } +#endif + self_ptr = base_ptr + indval * self_stride; + +#if @isget@ +#if @elsize@ + assert(npy_is_aligned(result_ptr, _ALIGN(@copytype@))); + assert(npy_is_aligned(self_ptr, _ALIGN(@copytype@))); + *(@copytype@ *)result_ptr = *(@copytype@ *)self_ptr; +#else + copyswap(result_ptr, self_ptr, 0, self); +#endif + +#else /* !@isget@ */ +#if @elsize@ + assert(npy_is_aligned(result_ptr, _ALIGN(@copytype@))); + assert(npy_is_aligned(self_ptr, _ALIGN(@copytype@))); + *(@copytype@ *)self_ptr = *(@copytype@ *)result_ptr; +#else + copyswap(self_ptr, result_ptr, 0, self); +#endif +#endif + + ind_ptr += ind_stride; + result_ptr += result_stride; + } + break; + +/**end repeat1**/ + } + + NPY_END_THREADS; + + return 0; +} + + +/* + * General advanced indexing iteration. + */ +NPY_NO_EXPORT int +mapiter_@name@(PyArrayMapIterObject *mit) +{ + npy_intp *counter, count; + int i, is_aligned; + + /* Cached mit info */ + int numiter = mit->numiter; + int needs_api = mit->needs_api; + /* Constant information */ + npy_intp fancy_dims[NPY_MAXDIMS]; + npy_intp fancy_strides[NPY_MAXDIMS]; +#if @isget@ + int iteraxis; +#endif + + char *baseoffset = mit->baseoffset; + char **outer_ptrs = mit->outer_ptrs; + npy_intp *outer_strides = mit->outer_strides; + PyArrayObject *array= mit->array; + + /* Fill constant information */ +#if @isget@ + iteraxis = mit->iteraxes[0]; +#endif + for (i = 0; i < numiter; i++) { + fancy_dims[i] = mit->fancy_dims[i]; + fancy_strides[i] = mit->fancy_strides[i]; + } + + /* + * Alignment information (swapping is never needed, since we buffer), + * could also check extra_op is buffered, but it should rarely matter. + */ + + is_aligned = PyArray_ISALIGNED(array) && PyArray_ISALIGNED(mit->extra_op); + + if (mit->size == 0) { + return 0; + } + + if (mit->subspace_iter == NULL) { + /* + * Item by item copy situation, the operand is buffered + * so use copyswap. + */ + PyArray_CopySwapFunc *copyswap = PyArray_DESCR(array)->f->copyswap; + + /* We have only one iterator handling everything */ + counter = NpyIter_GetInnerLoopSizePtr(mit->outer); + + /************ Optimized inner loops without subspace *************/ + +/**begin repeat1 + * #one_iter = 1, 0# + * #numiter = 1, numiter# + */ + +#if @one_iter@ + if (numiter == 1) { +#else + else { +#endif + NPY_BEGIN_THREADS_DEF; + if (!needs_api) { + NPY_BEGIN_THREADS; + } + + /* Optimization for aligned types that do not need the api */ + switch ((is_aligned && !needs_api) ? PyArray_ITEMSIZE(array) : 0) { + +/**begin repeat2 + * #elsize = 1, 2, 4, 8, 0# + * #copytype = npy_uint8, npy_uint16, npy_uint32, npy_uint64, 0# + */ + +#if @elsize@ + case @elsize@: +#else + default: +#endif + /* Outer iteration (safe because mit->size != 0) */ + do { +#if !@isget@ + /* + * When the API is needed the casting might fail + * TODO: (only if buffering is enabled). + */ + if (needs_api && PyErr_Occurred()) { + return -1; + } +#endif + count = *counter; + while (count--) { + char * self_ptr = baseoffset; + for (i=0; i < @numiter@; i++) { + npy_intp indval = *((npy_intp*)outer_ptrs[i]); + assert(npy_is_aligned(outer_ptrs[i], + _ALIGN(npy_intp))); + +#if @isget@ && @one_iter@ + if (check_and_adjust_index(&indval, fancy_dims[i], + iteraxis, _save) < 0 ) { + return -1; + } +#else + if (indval < 0) { + indval += fancy_dims[i]; + } +#endif + self_ptr += indval * fancy_strides[i]; + + /* advance indexing arrays */ + outer_ptrs[i] += outer_strides[i]; + } + +#if @isget@ +#if @elsize@ + assert(npy_is_aligned(outer_ptrs[i], _ALIGN(@copytype@))); + assert(npy_is_aligned(self_ptr, _ALIGN(@copytype@))); + *(@copytype@ *)(outer_ptrs[i]) = *(@copytype@ *)self_ptr; +#else + copyswap(outer_ptrs[i], self_ptr, 0, array); +#endif +#else /* !@isget@ */ +#if @elsize@ + assert(npy_is_aligned(outer_ptrs[i], _ALIGN(@copytype@))); + assert(npy_is_aligned(self_ptr, _ALIGN(@copytype@))); + *(@copytype@ *)self_ptr = *(@copytype@ *)(outer_ptrs[i]); +#else + copyswap(self_ptr, outer_ptrs[i], 0, array); +#endif +#endif + /* advance extra operand */ + outer_ptrs[i] += outer_strides[i]; + } + } while (mit->outer_next(mit->outer)); + + break; + +/**end repeat2**/ + } + NPY_END_THREADS; + } +/**end repeat1**/ + } + + /******************* Nested Iteration Situation *******************/ + else { + char *subspace_baseptrs[2]; + char **subspace_ptrs = mit->subspace_ptrs; + npy_intp *subspace_strides = mit->subspace_strides; + int is_subiter_trivial = 0; /* has three states */ + npy_intp reset_offsets[2] = {0, 0}; + + /* Use strided transfer functions for the inner loop */ + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + npy_intp fixed_strides[2]; + +#if @isget@ + npy_intp src_itemsize = PyArray_ITEMSIZE(array); +#else + npy_intp src_itemsize = PyArray_ITEMSIZE(mit->extra_op); +#endif + + /* + * Get a dtype transfer function, since there are no + * buffers, this is safe. + */ + NpyIter_GetInnerFixedStrideArray(mit->subspace_iter, fixed_strides); + + if (PyArray_GetDTypeTransferFunction(is_aligned, +#if @isget@ + fixed_strides[0], fixed_strides[1], + PyArray_DESCR(array), PyArray_DESCR(mit->extra_op), +#else + fixed_strides[1], fixed_strides[0], + PyArray_DESCR(mit->extra_op), PyArray_DESCR(array), +#endif + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + return -1; + } + + counter = NpyIter_GetInnerLoopSizePtr(mit->subspace_iter); + if (*counter == PyArray_SIZE(mit->subspace)) { + /* + * subspace is trivially iterable. + * manipulate pointers to avoid expensive resetting + */ + is_subiter_trivial = 1; + } +/**begin repeat1 + * #one_iter = 1, 0# + * #numiter = 1, numiter# + */ + +#if @one_iter@ + if (numiter == 1) { +#else + else { +#endif + NPY_BEGIN_THREADS_DEF; + if (!needs_api) { + NPY_BEGIN_THREADS; + } + + /* Outer iteration (safe because mit->size != 0) */ + do { + char * self_ptr = baseoffset; + for (i=0; i < @numiter@; i++) { + npy_intp indval = *((npy_intp*)outer_ptrs[i]); + +#if @isget@ && @one_iter@ + if (check_and_adjust_index(&indval, fancy_dims[i], + iteraxis, _save) < 0 ) { + NPY_AUXDATA_FREE(transferdata); + return -1; + } +#else + if (indval < 0) { + indval += fancy_dims[i]; + } +#endif + + self_ptr += indval * fancy_strides[i]; + } + + /* + * Resetting is slow, so try to avoid resetting + * if subspace iteration is trivial. + * Watch out: reset_offsets are kept outside of the loop, + * assuming the subspaces of different external iterations + * share the same structure. + */ + if (is_subiter_trivial <= 1) { + /* slower resetting: first iteration or non-trivial subspace */ + + char * errmsg = NULL; + subspace_baseptrs[0] = self_ptr; + subspace_baseptrs[1] = mit->extra_op_ptrs[0]; + + /* (can't really fail, since no buffering necessary) */ + if (!NpyIter_ResetBasePointers(mit->subspace_iter, + subspace_baseptrs, + &errmsg)) { + NPY_END_THREADS; + PyErr_SetString(PyExc_ValueError, errmsg); + NPY_AUXDATA_FREE(transferdata); + return -1; + } + if (is_subiter_trivial != 0) { + /* reset_offsets are nonzero for negative strides.*/ + reset_offsets[0] = subspace_ptrs[0] - self_ptr; + reset_offsets[1] = subspace_ptrs[1] - mit->extra_op_ptrs[0]; + + /* use the faster adjustment further on */ + is_subiter_trivial ++; + } + } + else { + /* + * faster resetting if the subspace iteration is trival. + * reset_offsets are zero for positive strides, + * for negative strides this shifts the pointer to the last + * item. + */ + subspace_ptrs[0] = self_ptr + reset_offsets[0]; + subspace_ptrs[1] = mit->extra_op_ptrs[0] + reset_offsets[1]; + } + +#if !@isget@ + /* + * When the API is needed the casting might fail + * TODO: Could only check if casting is unsafe, or even just + * not at all... + */ + if (needs_api && PyErr_Occurred()) { + NPY_AUXDATA_FREE(transferdata); + return -1; + } +#endif + + do { + +#if @isget@ + stransfer(subspace_ptrs[1], subspace_strides[1], + subspace_ptrs[0], subspace_strides[0], + *counter, src_itemsize, transferdata); +#else + stransfer(subspace_ptrs[0], subspace_strides[0], + subspace_ptrs[1], subspace_strides[1], + *counter, src_itemsize, transferdata); +#endif + } while (mit->subspace_next(mit->subspace_iter)); + + mit->extra_op_next(mit->extra_op_iter); + } while (mit->outer_next(mit->outer)); + NPY_END_THREADS; + } +/**end repeat1**/ + + NPY_AUXDATA_FREE(transferdata); + } + return 0; +} + +/**end repeat**/ diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c new file mode 100644 index 0000000..3be978f --- /dev/null +++ b/numpy/core/src/multiarray/mapping.c @@ -0,0 +1,3508 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +/*#include */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "arrayobject.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" +#include "npy_import.h" + +#include "common.h" +#include "ctors.h" +#include "iterators.h" +#include "mapping.h" +#include "lowlevel_strided_loops.h" +#include "item_selection.h" +#include "mem_overlap.h" + + +#define HAS_INTEGER 1 +#define HAS_NEWAXIS 2 +#define HAS_SLICE 4 +#define HAS_ELLIPSIS 8 +/* HAS_FANCY can be mixed with HAS_0D_BOOL, be careful when to use & or == */ +#define HAS_FANCY 16 +#define HAS_BOOL 32 +/* NOTE: Only set if it is neither fancy nor purely integer index! */ +#define HAS_SCALAR_ARRAY 64 +/* + * Indicate that this is a fancy index that comes from a 0d boolean. + * This means that the index does not operate along a real axis. The + * corresponding index type is just HAS_FANCY. + */ +#define HAS_0D_BOOL (HAS_FANCY | 128) + + +static int +_nonzero_indices(PyObject *myBool, PyArrayObject **arrays); + +/****************************************************************************** + *** IMPLEMENT MAPPING PROTOCOL *** + *****************************************************************************/ + +NPY_NO_EXPORT Py_ssize_t +array_length(PyArrayObject *self) +{ + if (PyArray_NDIM(self) != 0) { + return PyArray_DIMS(self)[0]; + } else { + PyErr_SetString(PyExc_TypeError, "len() of unsized object"); + return -1; + } +} + + +/* -------------------------------------------------------------- */ + +/*NUMPY_API + * + */ +NPY_NO_EXPORT void +PyArray_MapIterSwapAxes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap) +{ + PyObject *new; + int n1, n2, n3, val, bnd; + int i; + PyArray_Dims permute; + npy_intp d[NPY_MAXDIMS]; + PyArrayObject *arr; + + permute.ptr = d; + permute.len = mit->nd; + + /* + * arr might not have the right number of dimensions + * and need to be reshaped first by pre-pending ones + */ + arr = *ret; + if (PyArray_NDIM(arr) != mit->nd) { + for (i = 1; i <= PyArray_NDIM(arr); i++) { + permute.ptr[mit->nd-i] = PyArray_DIMS(arr)[PyArray_NDIM(arr)-i]; + } + for (i = 0; i < mit->nd-PyArray_NDIM(arr); i++) { + permute.ptr[i] = 1; + } + new = PyArray_Newshape(arr, &permute, NPY_ANYORDER); + Py_DECREF(arr); + *ret = (PyArrayObject *)new; + if (new == NULL) { + return; + } + } + + /* + * Setting and getting need to have different permutations. + * On the get we are permuting the returned object, but on + * setting we are permuting the object-to-be-set. + * The set permutation is the inverse of the get permutation. + */ + + /* + * For getting the array the tuple for transpose is + * (n1,...,n1+n2-1,0,...,n1-1,n1+n2,...,n3-1) + * n1 is the number of dimensions of the broadcast index array + * n2 is the number of dimensions skipped at the start + * n3 is the number of dimensions of the result + */ + + /* + * For setting the array the tuple for transpose is + * (n2,...,n1+n2-1,0,...,n2-1,n1+n2,...n3-1) + */ + n1 = mit->nd_fancy; + n2 = mit->consec; /* axes to insert at */ + n3 = mit->nd; + + /* use n1 as the boundary if getting but n2 if setting */ + bnd = getmap ? n1 : n2; + val = bnd; + i = 0; + while (val < n1 + n2) { + permute.ptr[i++] = val++; + } + val = 0; + while (val < bnd) { + permute.ptr[i++] = val++; + } + val = n1 + n2; + while (val < n3) { + permute.ptr[i++] = val++; + } + new = PyArray_Transpose(*ret, &permute); + Py_DECREF(*ret); + *ret = (PyArrayObject *)new; +} + +static NPY_INLINE void +multi_DECREF(PyObject **objects, npy_intp n) +{ + npy_intp i; + for (i = 0; i < n; i++) { + Py_DECREF(objects[i]); + } +} + +/** + * Unpack a tuple into an array of new references. Returns the number of objects + * unpacked. + * + * Useful if a tuple is being iterated over multiple times, or for a code path + * that doesn't always want the overhead of allocating a tuple. + */ +static NPY_INLINE npy_intp +unpack_tuple(PyTupleObject *index, PyObject **result, npy_intp result_n) +{ + npy_intp n, i; + n = PyTuple_GET_SIZE(index); + if (n > result_n) { + PyErr_SetString(PyExc_IndexError, + "too many indices for array"); + return -1; + } + for (i = 0; i < n; i++) { + result[i] = PyTuple_GET_ITEM(index, i); + Py_INCREF(result[i]); + } + return n; +} + +/* Unpack a single scalar index, taking a new reference to match unpack_tuple */ +static NPY_INLINE npy_intp +unpack_scalar(PyObject *index, PyObject **result, npy_intp result_n) +{ + Py_INCREF(index); + result[0] = index; + return 1; +} + +/** + * Turn an index argument into a c-array of `PyObject *`s, one for each index. + * + * When a scalar is passed, this is written directly to the buffer. When a + * tuple is passed, the tuple elements are unpacked into the buffer. + * + * When some other sequence is passed, this implements the following section + * from the advanced indexing docs to decide whether to unpack or just write + * one element: + * + * > In order to remain backward compatible with a common usage in Numeric, + * > basic slicing is also initiated if the selection object is any non-ndarray + * > sequence (such as a list) containing slice objects, the Ellipsis object, + * > or the newaxis object, but not for integer arrays or other embedded + * > sequences. + * + * It might be worth deprecating this behaviour (gh-4434), in which case the + * entire function should become a simple check of PyTuple_Check. + * + * @param index The index object, which may or may not be a tuple. This is + * a borrowed reference. + * @param result An empty buffer of PyObject* to write each index component + * to. The references written are new. + * @param result_n The length of the result buffer + * + * @returns The number of items in `result`, or -1 if an error occured. + * The entries in `result` at and beyond this index should be + * assumed to contain garbage, even if they were initialized + * to NULL, so are not safe to Py_XDECREF. Use multi_DECREF to + * dispose of them. + */ +NPY_NO_EXPORT npy_intp +unpack_indices(PyObject *index, PyObject **result, npy_intp result_n) +{ + npy_intp n, i; + npy_bool commit_to_unpack; + + /* Fast route for passing a tuple */ + if (PyTuple_CheckExact(index)) { + return unpack_tuple((PyTupleObject *)index, result, result_n); + } + + /* Obvious single-entry cases */ + if (0 /* to aid macros below */ +#if !defined(NPY_PY3K) + || PyInt_CheckExact(index) +#else + || PyLong_CheckExact(index) +#endif + || index == Py_None + || PySlice_Check(index) + || PyArray_Check(index) + || !PySequence_Check(index)) { + + return unpack_scalar(index, result, result_n); + } + + /* + * Passing a tuple subclass - coerce to the base type. This incurs an + * allocation, but doesn't need to be a fast path anyway + */ + if (PyTuple_Check(index)) { + PyTupleObject *tup = (PyTupleObject *) PySequence_Tuple(index); + if (tup == NULL) { + return -1; + } + n = unpack_tuple(tup, result, result_n); + Py_DECREF(tup); + return n; + } + + /* + * At this point, we're left with a non-tuple, non-array, sequence: + * typically, a list. We use some somewhat-arbitrary heuristics from here + * onwards to decided whether to treat that list as a single index, or a + * list of indices. + */ + + /* if len fails, treat like a scalar */ + n = PySequence_Size(index); + if (n < 0) { + PyErr_Clear(); + return unpack_scalar(index, result, result_n); + } + + /* + * Backwards compatibility only takes effect for short sequences - otherwise + * we treat it like any other scalar. + * + * Sequences < NPY_MAXDIMS with any slice objects + * or newaxis, Ellipsis or other arrays or sequences + * embedded, are considered equivalent to an indexing + * tuple. (`a[[[1,2], [3,4]]] == a[[1,2], [3,4]]`) + */ + if (n >= NPY_MAXDIMS) { + return unpack_scalar(index, result, result_n); + } + + /* In case we change result_n elsewhere */ + assert(n <= result_n); + + /* + * Some other type of short sequence - assume we should unpack it like a + * tuple, and then decide whether that was actually necessary. + */ + commit_to_unpack = 0; + for (i = 0; i < n; i++) { + PyObject *tmp_obj = result[i] = PySequence_GetItem(index, i); + + if (commit_to_unpack) { + /* propagate errors */ + if (tmp_obj == NULL) { + multi_DECREF(result, i); + return -1; + } + } + else { + /* + * if getitem fails (unusual) before we've committed, then stop + * unpacking + */ + if (tmp_obj == NULL) { + PyErr_Clear(); + break; + } + + /* decide if we should treat this sequence like a tuple */ + if (PyArray_Check(tmp_obj) + || PySequence_Check(tmp_obj) + || PySlice_Check(tmp_obj) + || tmp_obj == Py_Ellipsis + || tmp_obj == Py_None) { + commit_to_unpack = 1; + } + } + } + + /* unpacking was the right thing to do, and we already did it */ + if (commit_to_unpack) { + return n; + } + /* got to the end, never found an indication that we should have unpacked */ + else { + /* we partially filled result, so empty it first */ + multi_DECREF(result, i); + return unpack_scalar(index, result, result_n); + } +} + +/** + * Prepare an npy_index_object from the python slicing object. + * + * This function handles all index preparations with the exception + * of field access. It fills the array of index_info structs correctly. + * It already handles the boolean array special case for fancy indexing, + * i.e. if the index type is boolean, it is exactly one matching boolean + * array. If the index type is fancy, the boolean array is already + * converted to integer arrays. There is (as before) no checking of the + * boolean dimension. + * + * Checks everything but the bounds. + * + * @param the array being indexed + * @param the index object + * @param index info struct being filled (size of NPY_MAXDIMS * 2 + 1) + * @param number of indices found + * @param dimension of the indexing result + * @param dimension of the fancy/advanced indices part + * @param whether to allow the boolean special case + * + * @returns the index_type or -1 on failure and fills the number of indices. + */ +NPY_NO_EXPORT int +prepare_index(PyArrayObject *self, PyObject *index, + npy_index_info *indices, + int *num, int *ndim, int *out_fancy_ndim, int allow_boolean) +{ + int new_ndim, fancy_ndim, used_ndim, index_ndim; + int curr_idx, get_idx; + + int i; + npy_intp n; + + PyObject *obj = NULL; + PyArrayObject *arr; + + int index_type = 0; + int ellipsis_pos = -1; + + /* + * The choice of only unpacking `2*NPY_MAXDIMS` items is historic. + * The longest "reasonable" index that produces a result of <= 32 dimensions + * is `(0,)*np.MAXDIMS + (None,)*np.MAXDIMS`. Longer indices can exist, but + * are uncommon. + */ + PyObject *raw_indices[NPY_MAXDIMS*2]; + + index_ndim = unpack_indices(index, raw_indices, NPY_MAXDIMS*2); + if (index_ndim == -1) { + return -1; + } + + /* + * Parse all indices into the `indices` array of index_info structs + */ + used_ndim = 0; + new_ndim = 0; + fancy_ndim = 0; + get_idx = 0; + curr_idx = 0; + + while (get_idx < index_ndim) { + if (curr_idx > NPY_MAXDIMS * 2) { + PyErr_SetString(PyExc_IndexError, + "too many indices for array"); + goto failed_building_indices; + } + + obj = raw_indices[get_idx++]; + + /**** Try the cascade of possible indices ****/ + + /* Index is an ellipsis (`...`) */ + if (obj == Py_Ellipsis) { + /* At most one ellipsis in an index */ + if (index_type & HAS_ELLIPSIS) { + PyErr_Format(PyExc_IndexError, + "an index can only have a single ellipsis ('...')"); + goto failed_building_indices; + } + index_type |= HAS_ELLIPSIS; + indices[curr_idx].type = HAS_ELLIPSIS; + indices[curr_idx].object = NULL; + /* number of slices it is worth, won't update if it is 0: */ + indices[curr_idx].value = 0; + + ellipsis_pos = curr_idx; + /* the used and new ndim will be found later */ + used_ndim += 0; + new_ndim += 0; + curr_idx += 1; + continue; + } + + /* Index is np.newaxis/None */ + else if (obj == Py_None) { + index_type |= HAS_NEWAXIS; + + indices[curr_idx].type = HAS_NEWAXIS; + indices[curr_idx].object = NULL; + + used_ndim += 0; + new_ndim += 1; + curr_idx += 1; + continue; + } + + /* Index is a slice object. */ + else if (PySlice_Check(obj)) { + index_type |= HAS_SLICE; + + Py_INCREF(obj); + indices[curr_idx].object = obj; + indices[curr_idx].type = HAS_SLICE; + used_ndim += 1; + new_ndim += 1; + curr_idx += 1; + continue; + } + + /* + * Special case to allow 0-d boolean indexing with scalars. + * Should be removed after boolean as integer deprecation. + * Since this is always an error if it was not a boolean, we can + * allow the 0-d special case before the rest. + */ + else if (PyArray_NDIM(self) != 0) { + /* + * Single integer index, there are two cases here. + * It could be an array, a 0-d array is handled + * a bit weird however, so need to special case it. + * + * Check for integers first, purely for performance + */ +#if !defined(NPY_PY3K) + if (PyInt_CheckExact(obj) || !PyArray_Check(obj)) { +#else + if (PyLong_CheckExact(obj) || !PyArray_Check(obj)) { +#endif + npy_intp ind = PyArray_PyIntAsIntp(obj); + + if (error_converting(ind)) { + PyErr_Clear(); + } + else { + index_type |= HAS_INTEGER; + indices[curr_idx].object = NULL; + indices[curr_idx].value = ind; + indices[curr_idx].type = HAS_INTEGER; + used_ndim += 1; + new_ndim += 0; + curr_idx += 1; + continue; + } + } + } + + /* + * At this point, we must have an index array (or array-like). + * It might still be a (purely) bool special case, a 0-d integer + * array (an array scalar) or something invalid. + */ + + if (!PyArray_Check(obj)) { + PyArrayObject *tmp_arr; + tmp_arr = (PyArrayObject *)PyArray_FROM_O(obj); + if (tmp_arr == NULL) { + /* TODO: Should maybe replace the error here? */ + goto failed_building_indices; + } + + /* + * For example an empty list can be cast to an integer array, + * however it will default to a float one. + */ + if (PyArray_SIZE(tmp_arr) == 0) { + PyArray_Descr *indtype = PyArray_DescrFromType(NPY_INTP); + + arr = (PyArrayObject *)PyArray_FromArray(tmp_arr, indtype, + NPY_ARRAY_FORCECAST); + Py_DECREF(tmp_arr); + if (arr == NULL) { + goto failed_building_indices; + } + } + else { + arr = tmp_arr; + } + } + else { + Py_INCREF(obj); + arr = (PyArrayObject *)obj; + } + + /* Check if the array is valid and fill the information */ + if (PyArray_ISBOOL(arr)) { + /* + * There are two types of boolean indices (which are equivalent, + * for the most part though). A single boolean index of matching + * dimensionality and size is a boolean index. + * If this is not the case, it is instead expanded into (multiple) + * integer array indices. + */ + PyArrayObject *nonzero_result[NPY_MAXDIMS]; + + if ((index_ndim == 1) && allow_boolean) { + /* + * If ndim and size match, this can be optimized as a single + * boolean index. The size check is necessary only to support + * old non-matching sizes by using fancy indexing instead. + * The reason for that is that fancy indexing uses nonzero, + * and only the result of nonzero is checked for legality. + */ + if ((PyArray_NDIM(arr) == PyArray_NDIM(self)) + && PyArray_SIZE(arr) == PyArray_SIZE(self)) { + + index_type = HAS_BOOL; + indices[curr_idx].type = HAS_BOOL; + indices[curr_idx].object = (PyObject *)arr; + + /* keep track anyway, just to be complete */ + used_ndim = PyArray_NDIM(self); + fancy_ndim = PyArray_NDIM(self); + curr_idx += 1; + break; + } + } + + if (PyArray_NDIM(arr) == 0) { + /* + * This can actually be well defined. A new axis is added, + * but at the same time no axis is "used". So if we have True, + * we add a new axis (a bit like with np.newaxis). If it is + * False, we add a new axis, but this axis has 0 entries. + */ + + index_type |= HAS_FANCY; + indices[curr_idx].type = HAS_0D_BOOL; + + /* TODO: This can't fail, right? Is there a faster way? */ + if (PyObject_IsTrue((PyObject *)arr)) { + n = 1; + } + else { + n = 0; + } + indices[curr_idx].value = n; + indices[curr_idx].object = PyArray_Zeros(1, &n, + PyArray_DescrFromType(NPY_INTP), 0); + Py_DECREF(arr); + + if (indices[curr_idx].object == NULL) { + goto failed_building_indices; + } + + used_ndim += 0; + if (fancy_ndim < 1) { + fancy_ndim = 1; + } + curr_idx += 1; + continue; + } + + /* Convert the boolean array into multiple integer ones */ + n = _nonzero_indices((PyObject *)arr, nonzero_result); + Py_DECREF(arr); + + if (n < 0) { + goto failed_building_indices; + } + + /* Check that we will not run out of indices to store new ones */ + if (curr_idx + n >= NPY_MAXDIMS * 2) { + PyErr_SetString(PyExc_IndexError, + "too many indices for array"); + for (i=0; i < n; i++) { + Py_DECREF(nonzero_result[i]); + } + goto failed_building_indices; + } + + /* Add the arrays from the nonzero result to the index */ + index_type |= HAS_FANCY; + for (i=0; i < n; i++) { + indices[curr_idx].type = HAS_FANCY; + indices[curr_idx].value = PyArray_DIM(arr, i); + indices[curr_idx].object = (PyObject *)nonzero_result[i]; + + used_ndim += 1; + curr_idx += 1; + } + + /* All added indices have 1 dimension */ + if (fancy_ndim < 1) { + fancy_ndim = 1; + } + continue; + } + + /* Normal case of an integer array */ + else if (PyArray_ISINTEGER(arr)) { + if (PyArray_NDIM(arr) == 0) { + /* + * A 0-d integer array is an array scalar and can + * be dealt with the HAS_SCALAR_ARRAY flag. + * We could handle 0-d arrays early on, but this makes + * sure that array-likes or odder arrays are always + * handled right. + */ + npy_intp ind = PyArray_PyIntAsIntp((PyObject *)arr); + + Py_DECREF(arr); + if (error_converting(ind)) { + goto failed_building_indices; + } + else { + index_type |= (HAS_INTEGER | HAS_SCALAR_ARRAY); + indices[curr_idx].object = NULL; + indices[curr_idx].value = ind; + indices[curr_idx].type = HAS_INTEGER; + used_ndim += 1; + new_ndim += 0; + curr_idx += 1; + continue; + } + } + + index_type |= HAS_FANCY; + indices[curr_idx].type = HAS_FANCY; + indices[curr_idx].value = -1; + indices[curr_idx].object = (PyObject *)arr; + + used_ndim += 1; + if (fancy_ndim < PyArray_NDIM(arr)) { + fancy_ndim = PyArray_NDIM(arr); + } + curr_idx += 1; + continue; + } + + /* + * The array does not have a valid type. + */ + if ((PyObject *)arr == obj) { + /* The input was an array already */ + PyErr_SetString(PyExc_IndexError, + "arrays used as indices must be of integer (or boolean) type"); + } + else { + /* The input was not an array, so give a general error message */ + PyErr_SetString(PyExc_IndexError, + "only integers, slices (`:`), ellipsis (`...`), " + "numpy.newaxis (`None`) and integer or boolean " + "arrays are valid indices"); + } + Py_DECREF(arr); + goto failed_building_indices; + } + + /* + * Compare dimension of the index to the real ndim. this is + * to find the ellipsis value or append an ellipsis if necessary. + */ + if (used_ndim < PyArray_NDIM(self)) { + if (index_type & HAS_ELLIPSIS) { + indices[ellipsis_pos].value = PyArray_NDIM(self) - used_ndim; + used_ndim = PyArray_NDIM(self); + new_ndim += indices[ellipsis_pos].value; + } + else { + /* + * There is no ellipsis yet, but it is not a full index + * so we append an ellipsis to the end. + */ + index_type |= HAS_ELLIPSIS; + indices[curr_idx].object = NULL; + indices[curr_idx].type = HAS_ELLIPSIS; + indices[curr_idx].value = PyArray_NDIM(self) - used_ndim; + ellipsis_pos = curr_idx; + + used_ndim = PyArray_NDIM(self); + new_ndim += indices[curr_idx].value; + curr_idx += 1; + } + } + else if (used_ndim > PyArray_NDIM(self)) { + PyErr_SetString(PyExc_IndexError, + "too many indices for array"); + goto failed_building_indices; + } + else if (index_ndim == 0) { + /* + * 0-d index into 0-d array, i.e. array[()] + * We consider this an integer index. Which means it will return + * the scalar. + * This makes sense, because then array[...] gives + * an array and array[()] gives the scalar. + */ + used_ndim = 0; + index_type = HAS_INTEGER; + } + + /* HAS_SCALAR_ARRAY requires cleaning up the index_type */ + if (index_type & HAS_SCALAR_ARRAY) { + /* clear as info is unnecessary and makes life harder later */ + if (index_type & HAS_FANCY) { + index_type -= HAS_SCALAR_ARRAY; + } + /* A full integer index sees array scalars as part of itself */ + else if (index_type == (HAS_INTEGER | HAS_SCALAR_ARRAY)) { + index_type -= HAS_SCALAR_ARRAY; + } + } + + /* + * At this point indices are all set correctly, no bounds checking + * has been made and the new array may still have more dimensions + * than is possible and boolean indexing arrays may have an incorrect shape. + * + * Check this now so we do not have to worry about it later. + * It can happen for fancy indexing or with newaxis. + * This means broadcasting errors in the case of too many dimensions + * take less priority. + */ + if (index_type & (HAS_NEWAXIS | HAS_FANCY)) { + if (new_ndim + fancy_ndim > NPY_MAXDIMS) { + PyErr_Format(PyExc_IndexError, + "number of dimensions must be within [0, %d], " + "indexing result would have %d", + NPY_MAXDIMS, (new_ndim + fancy_ndim)); + goto failed_building_indices; + } + + /* + * If we had a fancy index, we may have had a boolean array index. + * So check if this had the correct shape now that we can find out + * which axes it acts on. + */ + used_ndim = 0; + for (i = 0; i < curr_idx; i++) { + if ((indices[i].type == HAS_FANCY) && indices[i].value > 0) { + if (indices[i].value != PyArray_DIM(self, used_ndim)) { + char err_msg[174]; + + PyOS_snprintf(err_msg, sizeof(err_msg), + "boolean index did not match indexed array along " + "dimension %d; dimension is %" NPY_INTP_FMT + " but corresponding boolean dimension is %" NPY_INTP_FMT, + used_ndim, PyArray_DIM(self, used_ndim), + indices[i].value); + PyErr_SetString(PyExc_IndexError, err_msg); + goto failed_building_indices; + } + } + + if (indices[i].type == HAS_ELLIPSIS) { + used_ndim += indices[i].value; + } + else if ((indices[i].type == HAS_NEWAXIS) || + (indices[i].type == HAS_0D_BOOL)) { + used_ndim += 0; + } + else { + used_ndim += 1; + } + } + } + + *num = curr_idx; + *ndim = new_ndim + fancy_ndim; + *out_fancy_ndim = fancy_ndim; + + multi_DECREF(raw_indices, index_ndim); + + return index_type; + + failed_building_indices: + for (i=0; i < curr_idx; i++) { + Py_XDECREF(indices[i].object); + } + multi_DECREF(raw_indices, index_ndim); + return -1; +} + + +/** + * Check if self has memory overlap with one of the index arrays, or with extra_op. + * + * @returns 1 if memory overlap found, 0 if not. + */ +NPY_NO_EXPORT int +index_has_memory_overlap(PyArrayObject *self, + int index_type, npy_index_info *indices, int num, + PyObject *extra_op) +{ + int i; + + if (index_type & (HAS_FANCY | HAS_BOOL)) { + for (i = 0; i < num; ++i) { + if (indices[i].object != NULL && + PyArray_Check(indices[i].object) && + solve_may_share_memory(self, + (PyArrayObject *)indices[i].object, + 1) != 0) { + return 1; + } + } + } + + if (extra_op != NULL && PyArray_Check(extra_op) && + solve_may_share_memory(self, (PyArrayObject *)extra_op, 1) != 0) { + return 1; + } + + return 0; +} + + +/** + * Get pointer for an integer index. + * + * For a purely integer index, set ptr to the memory address. + * Returns 0 on success, -1 on failure. + * The caller must ensure that the index is a full integer + * one. + * + * @param Array being indexed + * @param result pointer + * @param parsed index information + * @param number of indices + * + * @return 0 on success -1 on failure + */ +static int +get_item_pointer(PyArrayObject *self, char **ptr, + npy_index_info *indices, int index_num) { + int i; + *ptr = PyArray_BYTES(self); + for (i=0; i < index_num; i++) { + if ((check_and_adjust_index(&(indices[i].value), + PyArray_DIMS(self)[i], i, NULL)) < 0) { + return -1; + } + *ptr += PyArray_STRIDE(self, i) * indices[i].value; + } + return 0; +} + + +/** + * Get view into an array using all non-array indices. + * + * For any index, get a view of the subspace into the original + * array. If there are no fancy indices, this is the result of + * the indexing operation. + * Ensure_array allows to fetch a safe subspace view for advanced + * indexing. + * + * @param Array being indexed + * @param resulting array (new reference) + * @param parsed index information + * @param number of indices + * @param Whether result should inherit the type from self + * + * @return 0 on success -1 on failure + */ +static int +get_view_from_index(PyArrayObject *self, PyArrayObject **view, + npy_index_info *indices, int index_num, int ensure_array) { + npy_intp new_strides[NPY_MAXDIMS]; + npy_intp new_shape[NPY_MAXDIMS]; + int i, j; + int new_dim = 0; + int orig_dim = 0; + char *data_ptr = PyArray_BYTES(self); + + /* for slice parsing */ + npy_intp start, stop, step, n_steps; + + for (i=0; i < index_num; i++) { + switch (indices[i].type) { + case HAS_INTEGER: + if ((check_and_adjust_index(&indices[i].value, + PyArray_DIMS(self)[orig_dim], orig_dim, + NULL)) < 0) { + return -1; + } + data_ptr += PyArray_STRIDE(self, orig_dim) * indices[i].value; + + new_dim += 0; + orig_dim += 1; + break; + case HAS_ELLIPSIS: + for (j=0; j < indices[i].value; j++) { + new_strides[new_dim] = PyArray_STRIDE(self, orig_dim); + new_shape[new_dim] = PyArray_DIMS(self)[orig_dim]; + new_dim += 1; + orig_dim += 1; + } + break; + case HAS_SLICE: + if (NpySlice_GetIndicesEx(indices[i].object, + PyArray_DIMS(self)[orig_dim], + &start, &stop, &step, &n_steps) < 0) { + return -1; + } + if (n_steps <= 0) { + /* TODO: Always points to start then, could change that */ + n_steps = 0; + step = 1; + start = 0; + } + + data_ptr += PyArray_STRIDE(self, orig_dim) * start; + new_strides[new_dim] = PyArray_STRIDE(self, orig_dim) * step; + new_shape[new_dim] = n_steps; + new_dim += 1; + orig_dim += 1; + break; + case HAS_NEWAXIS: + new_strides[new_dim] = 0; + new_shape[new_dim] = 1; + new_dim += 1; + break; + /* Fancy and 0-d boolean indices are ignored here */ + case HAS_0D_BOOL: + break; + default: + new_dim += 0; + orig_dim += 1; + break; + } + } + + /* Create the new view and set the base array */ + Py_INCREF(PyArray_DESCR(self)); + *view = (PyArrayObject *)PyArray_NewFromDescr( + ensure_array ? &PyArray_Type : Py_TYPE(self), + PyArray_DESCR(self), + new_dim, new_shape, + new_strides, data_ptr, + PyArray_FLAGS(self), + ensure_array ? NULL : (PyObject *)self); + if (*view == NULL) { + return -1; + } + + Py_INCREF(self); + if (PyArray_SetBaseObject(*view, (PyObject *)self) < 0) { + Py_DECREF(*view); + return -1; + } + + return 0; +} + + +/* + * Implements boolean indexing. This produces a one-dimensional + * array which picks out all of the elements of 'self' for which + * the corresponding element of 'op' is True. + * + * This operation is somewhat unfortunate, because to produce + * a one-dimensional output array, it has to choose a particular + * iteration order, in the case of NumPy that is always C order even + * though this function allows different choices. + */ +NPY_NO_EXPORT PyArrayObject * +array_boolean_subscript(PyArrayObject *self, + PyArrayObject *bmask, NPY_ORDER order) +{ + npy_intp size, itemsize; + char *ret_data; + PyArray_Descr *dtype; + PyArrayObject *ret; + int needs_api = 0; + + size = count_boolean_trues(PyArray_NDIM(bmask), PyArray_DATA(bmask), + PyArray_DIMS(bmask), PyArray_STRIDES(bmask)); + + /* Allocate the output of the boolean indexing */ + dtype = PyArray_DESCR(self); + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, 1, &size, + NULL, NULL, 0, NULL); + if (ret == NULL) { + return NULL; + } + + itemsize = dtype->elsize; + ret_data = PyArray_DATA(ret); + + /* Create an iterator for the data */ + if (size > 0) { + NpyIter *iter; + PyArrayObject *op[2] = {self, bmask}; + npy_uint32 flags, op_flags[2]; + npy_intp fixed_strides[3]; + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + + NpyIter_IterNextFunc *iternext; + npy_intp innersize, *innerstrides; + char **dataptrs; + + npy_intp self_stride, bmask_stride, subloopsize; + char *self_data; + char *bmask_data; + NPY_BEGIN_THREADS_DEF; + + /* Set up the iterator */ + flags = NPY_ITER_EXTERNAL_LOOP | NPY_ITER_REFS_OK; + op_flags[0] = NPY_ITER_READONLY | NPY_ITER_NO_BROADCAST; + op_flags[1] = NPY_ITER_READONLY; + + iter = NpyIter_MultiNew(2, op, flags, order, NPY_NO_CASTING, + op_flags, NULL); + if (iter == NULL) { + Py_DECREF(ret); + return NULL; + } + + /* Get a dtype transfer function */ + NpyIter_GetInnerFixedStrideArray(iter, fixed_strides); + if (PyArray_GetDTypeTransferFunction(PyArray_ISALIGNED(self), + fixed_strides[0], itemsize, + dtype, dtype, + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + Py_DECREF(ret); + NpyIter_Deallocate(iter); + return NULL; + } + + /* Get the values needed for the inner loop */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + Py_DECREF(ret); + NpyIter_Deallocate(iter); + NPY_AUXDATA_FREE(transferdata); + return NULL; + } + + NPY_BEGIN_THREADS_NDITER(iter); + + innerstrides = NpyIter_GetInnerStrideArray(iter); + dataptrs = NpyIter_GetDataPtrArray(iter); + + self_stride = innerstrides[0]; + bmask_stride = innerstrides[1]; + do { + innersize = *NpyIter_GetInnerLoopSizePtr(iter); + self_data = dataptrs[0]; + bmask_data = dataptrs[1]; + + while (innersize > 0) { + /* Skip masked values */ + bmask_data = npy_memchr(bmask_data, 0, bmask_stride, + innersize, &subloopsize, 1); + innersize -= subloopsize; + self_data += subloopsize * self_stride; + /* Process unmasked values */ + bmask_data = npy_memchr(bmask_data, 0, bmask_stride, innersize, + &subloopsize, 0); + stransfer(ret_data, itemsize, self_data, self_stride, + subloopsize, itemsize, transferdata); + innersize -= subloopsize; + self_data += subloopsize * self_stride; + ret_data += subloopsize * itemsize; + } + } while (iternext(iter)); + + NPY_END_THREADS; + + NpyIter_Deallocate(iter); + NPY_AUXDATA_FREE(transferdata); + } + + if (!PyArray_CheckExact(self)) { + PyArrayObject *tmp = ret; + + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self), dtype, 1, + &size, PyArray_STRIDES(ret), PyArray_BYTES(ret), + PyArray_FLAGS(self), (PyObject *)self); + + if (ret == NULL) { + Py_DECREF(tmp); + return NULL; + } + + if (PyArray_SetBaseObject(ret, (PyObject *)tmp) < 0) { + Py_DECREF(ret); + return NULL; + } + } + + return ret; +} + +/* + * Implements boolean indexing assignment. This takes the one-dimensional + * array 'v' and assigns its values to all of the elements of 'self' for which + * the corresponding element of 'op' is True. + * + * This operation is somewhat unfortunate, because to match up with + * a one-dimensional output array, it has to choose a particular + * iteration order, in the case of NumPy that is always C order even + * though this function allows different choices. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +array_assign_boolean_subscript(PyArrayObject *self, + PyArrayObject *bmask, PyArrayObject *v, NPY_ORDER order) +{ + npy_intp size, src_itemsize, v_stride; + char *v_data; + int needs_api = 0; + npy_intp bmask_size; + + if (PyArray_DESCR(bmask)->type_num != NPY_BOOL) { + PyErr_SetString(PyExc_TypeError, + "NumPy boolean array indexing assignment " + "requires a boolean index"); + return -1; + } + + if (PyArray_NDIM(v) > 1) { + PyErr_Format(PyExc_TypeError, + "NumPy boolean array indexing assignment " + "requires a 0 or 1-dimensional input, input " + "has %d dimensions", PyArray_NDIM(v)); + return -1; + } + + if (PyArray_NDIM(bmask) != PyArray_NDIM(self)) { + PyErr_SetString(PyExc_ValueError, + "The boolean mask assignment indexing array " + "must have the same number of dimensions as " + "the array being indexed"); + return -1; + } + + size = count_boolean_trues(PyArray_NDIM(bmask), PyArray_DATA(bmask), + PyArray_DIMS(bmask), PyArray_STRIDES(bmask)); + /* Correction factor for broadcasting 'bmask' to 'self' */ + bmask_size = PyArray_SIZE(bmask); + if (bmask_size > 0) { + size *= PyArray_SIZE(self) / bmask_size; + } + + /* Tweak the strides for 0-dim and broadcasting cases */ + if (PyArray_NDIM(v) > 0 && PyArray_DIMS(v)[0] != 1) { + if (size != PyArray_DIMS(v)[0]) { + PyErr_Format(PyExc_ValueError, + "NumPy boolean array indexing assignment " + "cannot assign %d input values to " + "the %d output values where the mask is true", + (int)PyArray_DIMS(v)[0], (int)size); + return -1; + } + v_stride = PyArray_STRIDES(v)[0]; + } + else { + v_stride = 0; + } + + src_itemsize = PyArray_DESCR(v)->elsize; + v_data = PyArray_DATA(v); + + /* Create an iterator for the data */ + if (size > 0) { + NpyIter *iter; + PyArrayObject *op[2] = {self, bmask}; + npy_uint32 flags, op_flags[2]; + npy_intp fixed_strides[3]; + + NpyIter_IterNextFunc *iternext; + npy_intp innersize, *innerstrides; + char **dataptrs; + + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + npy_intp self_stride, bmask_stride, subloopsize; + char *self_data; + char *bmask_data; + NPY_BEGIN_THREADS_DEF; + + /* Set up the iterator */ + flags = NPY_ITER_EXTERNAL_LOOP | NPY_ITER_REFS_OK; + op_flags[0] = NPY_ITER_WRITEONLY | NPY_ITER_NO_BROADCAST; + op_flags[1] = NPY_ITER_READONLY; + + iter = NpyIter_MultiNew(2, op, flags, order, NPY_NO_CASTING, + op_flags, NULL); + if (iter == NULL) { + return -1; + } + + /* Get the values needed for the inner loop */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + return -1; + } + + innerstrides = NpyIter_GetInnerStrideArray(iter); + dataptrs = NpyIter_GetDataPtrArray(iter); + + self_stride = innerstrides[0]; + bmask_stride = innerstrides[1]; + + /* Get a dtype transfer function */ + NpyIter_GetInnerFixedStrideArray(iter, fixed_strides); + if (PyArray_GetDTypeTransferFunction( + PyArray_ISALIGNED(self) && PyArray_ISALIGNED(v), + v_stride, fixed_strides[0], + PyArray_DESCR(v), PyArray_DESCR(self), + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + NpyIter_Deallocate(iter); + return -1; + } + + if (!needs_api) { + NPY_BEGIN_THREADS_NDITER(iter); + } + + do { + innersize = *NpyIter_GetInnerLoopSizePtr(iter); + self_data = dataptrs[0]; + bmask_data = dataptrs[1]; + + while (innersize > 0) { + /* Skip masked values */ + bmask_data = npy_memchr(bmask_data, 0, bmask_stride, + innersize, &subloopsize, 1); + innersize -= subloopsize; + self_data += subloopsize * self_stride; + /* Process unmasked values */ + bmask_data = npy_memchr(bmask_data, 0, bmask_stride, innersize, + &subloopsize, 0); + stransfer(self_data, self_stride, v_data, v_stride, + subloopsize, src_itemsize, transferdata); + innersize -= subloopsize; + self_data += subloopsize * self_stride; + v_data += subloopsize * v_stride; + } + } while (iternext(iter)); + + if (!needs_api) { + NPY_END_THREADS; + } + + NPY_AUXDATA_FREE(transferdata); + NpyIter_Deallocate(iter); + } + + if (needs_api) { + /* + * FIXME?: most assignment operations stop after the first occurrence + * of an error. Boolean does not currently, but should at least + * report the error. (This is only relevant for things like str->int + * casts which call into python) + */ + if (PyErr_Occurred()) { + return -1; + } + } + + return 0; +} + + +/* + * C-level integer indexing always returning an array and never a scalar. + * Works also for subclasses, but it will not be called on one from the + * Python API. + * + * This function does not accept negative indices because it is called by + * PySequence_GetItem (through array_item) and that converts them to + * positive indices. + */ +NPY_NO_EXPORT PyObject * +array_item_asarray(PyArrayObject *self, npy_intp i) +{ + npy_index_info indices[2]; + PyObject *result; + + if (PyArray_NDIM(self) == 0) { + PyErr_SetString(PyExc_IndexError, + "too many indices for array"); + return NULL; + } + if (i < 0) { + /* This is an error, but undo PySequence_GetItem fix for message */ + i -= PyArray_DIM(self, 0); + } + + indices[0].value = i; + indices[0].type = HAS_INTEGER; + indices[1].value = PyArray_NDIM(self) - 1; + indices[1].type = HAS_ELLIPSIS; + if (get_view_from_index(self, (PyArrayObject **)&result, + indices, 2, 0) < 0) { + return NULL; + } + return result; +} + + +/* + * Python C-Api level item subscription (implementation for PySequence_GetItem) + * + * Negative indices are not accepted because PySequence_GetItem converts + * them to positive indices before calling this. + */ +NPY_NO_EXPORT PyObject * +array_item(PyArrayObject *self, Py_ssize_t i) +{ + if (PyArray_NDIM(self) == 1) { + char *item; + npy_index_info index; + + if (i < 0) { + /* This is an error, but undo PySequence_GetItem fix for message */ + i -= PyArray_DIM(self, 0); + } + + index.value = i; + index.type = HAS_INTEGER; + if (get_item_pointer(self, &item, &index, 1) < 0) { + return NULL; + } + return PyArray_Scalar(item, PyArray_DESCR(self), (PyObject *)self); + } + else { + return array_item_asarray(self, i); + } +} + + +/* make sure subscript always returns an array object */ +NPY_NO_EXPORT PyObject * +array_subscript_asarray(PyArrayObject *self, PyObject *op) +{ + return PyArray_EnsureAnyArray(array_subscript(self, op)); +} + +/* + * Helper function for _get_field_view which turns a multifield + * view into a "packed" copy, as done in numpy 1.14 and before. + * In numpy 1.15 this function is removed. + */ +NPY_NO_EXPORT int +_multifield_view_to_copy(PyArrayObject **view) { + static PyObject *copyfunc = NULL; + PyObject *viewcopy; + + /* return a repacked copy of the view */ + npy_cache_import("numpy.lib.recfunctions", "repack_fields", ©func); + if (copyfunc == NULL) { + goto view_fail; + } + + PyArray_CLEARFLAGS(*view, NPY_ARRAY_WARN_ON_WRITE); + viewcopy = PyObject_CallFunction(copyfunc, "O", *view); + if (viewcopy == NULL) { + goto view_fail; + } + Py_DECREF(*view); + *view = (PyArrayObject*)viewcopy; + + /* warn when writing to the copy */ + PyArray_ENABLEFLAGS(*view, NPY_ARRAY_WARN_ON_WRITE); + return 0; + +view_fail: + Py_DECREF(*view); + *view = NULL; + return 0; +} + + +/* + * Attempts to subscript an array using a field name or list of field names. + * + * If an error occurred, return 0 and set view to NULL. If the subscript is not + * a string or list of strings, return -1 and set view to NULL. Otherwise + * return 0 and set view to point to a new view into arr for the given fields. + * + * In numpy 1.14 and before, in the case of a list of field names the returned + * view will actually be a copy by default, with fields packed together. + * The `force_view` argument causes a view to be returned. This argument can be + * removed in 1.15 when we plan to return a view always. + */ +NPY_NO_EXPORT int +_get_field_view(PyArrayObject *arr, PyObject *ind, PyArrayObject **view, + int force_view) +{ + *view = NULL; + + /* first check for a single field name */ + if (PyBaseString_Check(ind)) { + PyObject *tup; + PyArray_Descr *fieldtype; + npy_intp offset; + + /* get the field offset and dtype */ + tup = PyDict_GetItem(PyArray_DESCR(arr)->fields, ind); + if (tup == NULL){ + PyObject *errmsg = PyUString_FromString("no field of name "); + PyUString_Concat(&errmsg, ind); + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + return 0; + } + if (_unpack_field(tup, &fieldtype, &offset) < 0) { + return 0; + } + + /* view the array at the new offset+dtype */ + Py_INCREF(fieldtype); + *view = (PyArrayObject*)PyArray_NewFromDescr_int( + Py_TYPE(arr), + fieldtype, + PyArray_NDIM(arr), + PyArray_SHAPE(arr), + PyArray_STRIDES(arr), + PyArray_BYTES(arr) + offset, + PyArray_FLAGS(arr), + (PyObject *)arr, 0, 1); + if (*view == NULL) { + return 0; + } + Py_INCREF(arr); + if (PyArray_SetBaseObject(*view, (PyObject *)arr) < 0) { + Py_DECREF(*view); + *view = NULL; + } + return 0; + } + /* next check for a list of field names */ + else if (PySequence_Check(ind) && !PyTuple_Check(ind)) { + int seqlen, i; + PyObject *name = NULL, *tup; + PyObject *fields, *names; + PyArray_Descr *view_dtype; + + seqlen = PySequence_Size(ind); + + /* quit if have a 0-d array (seqlen==-1) or a 0-len array */ + if (seqlen == -1) { + PyErr_Clear(); + return -1; + } + if (seqlen == 0) { + return -1; + } + + fields = PyDict_New(); + if (fields == NULL) { + return 0; + } + names = PyTuple_New(seqlen); + if (names == NULL) { + Py_DECREF(fields); + return 0; + } + + for (i = 0; i < seqlen; i++) { + name = PySequence_GetItem(ind, i); + if (name == NULL) { + /* only happens for strange sequence objects */ + PyErr_Clear(); + Py_DECREF(fields); + Py_DECREF(names); + return -1; + } + + if (!PyBaseString_Check(name)) { + Py_DECREF(name); + Py_DECREF(fields); + Py_DECREF(names); + return -1; + } + + tup = PyDict_GetItem(PyArray_DESCR(arr)->fields, name); + if (tup == NULL){ + PyObject *errmsg = PyUString_FromString("no field of name "); + PyUString_ConcatAndDel(&errmsg, name); + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + Py_DECREF(fields); + Py_DECREF(names); + return 0; + } + /* disallow use of titles as index */ + if (PyTuple_Size(tup) == 3) { + PyObject *title = PyTuple_GET_ITEM(tup, 2); + int titlecmp = PyObject_RichCompareBool(title, name, Py_EQ); + if (titlecmp == 1) { + /* if title == name, we got a title, not a field name */ + PyErr_SetString(PyExc_KeyError, + "cannot use field titles in multi-field index"); + } + if (titlecmp != 0 || PyDict_SetItem(fields, title, tup) < 0) { + Py_DECREF(title); + Py_DECREF(name); + Py_DECREF(fields); + Py_DECREF(names); + return 0; + } + Py_DECREF(title); + } + /* disallow duplicate field indices */ + if (PyDict_Contains(fields, name)) { + PyObject *errmsg = PyUString_FromString( + "duplicate field of name "); + PyUString_ConcatAndDel(&errmsg, name); + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + Py_DECREF(fields); + Py_DECREF(names); + return 0; + } + if (PyDict_SetItem(fields, name, tup) < 0) { + Py_DECREF(name); + Py_DECREF(fields); + Py_DECREF(names); + return 0; + } + if (PyTuple_SetItem(names, i, name) < 0) { + Py_DECREF(fields); + Py_DECREF(names); + return 0; + } + } + + view_dtype = PyArray_DescrNewFromType(NPY_VOID); + if (view_dtype == NULL) { + Py_DECREF(fields); + Py_DECREF(names); + return 0; + } + view_dtype->elsize = PyArray_DESCR(arr)->elsize; + view_dtype->names = names; + view_dtype->fields = fields; + view_dtype->flags = PyArray_DESCR(arr)->flags; + + *view = (PyArrayObject*)PyArray_NewFromDescr_int( + Py_TYPE(arr), + view_dtype, + PyArray_NDIM(arr), + PyArray_SHAPE(arr), + PyArray_STRIDES(arr), + PyArray_DATA(arr), + PyArray_FLAGS(arr), + (PyObject *)arr, 0, 1); + if (*view == NULL) { + return 0; + } + Py_INCREF(arr); + if (PyArray_SetBaseObject(*view, (PyObject *)arr) < 0) { + Py_DECREF(*view); + *view = NULL; + return 0; + } + + if (force_view) { + return 0; + } + + return _multifield_view_to_copy(view); + } + return -1; +} + +/* + * General function for indexing a NumPy array with a Python object. + */ +NPY_NO_EXPORT PyObject * +array_subscript(PyArrayObject *self, PyObject *op) +{ + int index_type; + int index_num; + int i, ndim, fancy_ndim; + /* + * Index info array. We can have twice as many indices as dimensions + * (because of None). The + 1 is to not need to check as much. + */ + npy_index_info indices[NPY_MAXDIMS * 2 + 1]; + + PyArrayObject *view = NULL; + PyObject *result = NULL; + + PyArrayMapIterObject * mit = NULL; + + /* return fields if op is a string index */ + if (PyDataType_HASFIELDS(PyArray_DESCR(self))) { + PyArrayObject *view; + int ret = _get_field_view(self, op, &view, 0); + if (ret == 0){ + if (view == NULL) { + return NULL; + } + return (PyObject*)view; + } + } + + /* Prepare the indices */ + index_type = prepare_index(self, op, indices, &index_num, + &ndim, &fancy_ndim, 1); + + if (index_type < 0) { + return NULL; + } + + /* Full integer index */ + else if (index_type == HAS_INTEGER) { + char *item; + if (get_item_pointer(self, &item, indices, index_num) < 0) { + goto finish; + } + result = (PyObject *) PyArray_Scalar(item, PyArray_DESCR(self), + (PyObject *)self); + /* Because the index is full integer, we do not need to decref */ + return result; + } + + /* Single boolean array */ + else if (index_type == HAS_BOOL) { + result = (PyObject *)array_boolean_subscript(self, + (PyArrayObject *)indices[0].object, + NPY_CORDER); + goto finish; + } + + /* If it is only a single ellipsis, just return a view */ + else if (index_type == HAS_ELLIPSIS) { + /* + * TODO: Should this be a view or not? The only reason not would be + * optimization (i.e. of array[...] += 1) I think. + * Before, it was just self for a single ellipsis. + */ + result = PyArray_View(self, NULL, NULL); + /* A single ellipsis, so no need to decref */ + return result; + } + + /* + * View based indexing. + * There are two cases here. First we need to create a simple view, + * second we need to create a (possibly invalid) view for the + * subspace to the fancy index. This procedure is identical. + */ + + else if (index_type & (HAS_SLICE | HAS_NEWAXIS | + HAS_ELLIPSIS | HAS_INTEGER)) { + if (get_view_from_index(self, &view, indices, index_num, + (index_type & HAS_FANCY)) < 0) { + goto finish; + } + + /* + * There is a scalar array, so we need to force a copy to simulate + * fancy indexing. + */ + if (index_type & HAS_SCALAR_ARRAY) { + result = PyArray_NewCopy(view, NPY_KEEPORDER); + goto finish; + } + } + + /* If there is no fancy indexing, we have the result */ + if (!(index_type & HAS_FANCY)) { + result = (PyObject *)view; + Py_INCREF(result); + goto finish; + } + + /* + * Special case for very simple 1-d fancy indexing, which however + * is quite common. This saves not only a lot of setup time in the + * iterator, but also is faster (must be exactly fancy because + * we don't support 0-d booleans here) + */ + if (index_type == HAS_FANCY && index_num == 1) { + /* The array being indexed has one dimension and it is a fancy index */ + PyArrayObject *ind = (PyArrayObject*)indices[0].object; + + /* Check if the index is simple enough */ + if (PyArray_TRIVIALLY_ITERABLE(ind) && + /* Check if the type is equivalent to INTP */ + PyArray_ITEMSIZE(ind) == sizeof(npy_intp) && + PyArray_DESCR(ind)->kind == 'i' && + PyArray_ISALIGNED(ind) && + PyDataType_ISNOTSWAPPED(PyArray_DESCR(ind))) { + + Py_INCREF(PyArray_DESCR(self)); + result = PyArray_NewFromDescr(&PyArray_Type, + PyArray_DESCR(self), + PyArray_NDIM(ind), + PyArray_SHAPE(ind), + NULL, NULL, + /* Same order as indices */ + PyArray_ISFORTRAN(ind) ? + NPY_ARRAY_F_CONTIGUOUS : 0, + NULL); + if (result == NULL) { + goto finish; + } + + if (mapiter_trivial_get(self, ind, (PyArrayObject *)result) < 0) { + Py_DECREF(result); + result = NULL; + goto finish; + } + + goto wrap_out_array; + } + } + + /* fancy indexing has to be used. And view is the subspace. */ + mit = (PyArrayMapIterObject *)PyArray_MapIterNew(indices, index_num, + index_type, + ndim, fancy_ndim, + self, view, 0, + NPY_ITER_READONLY, + NPY_ITER_WRITEONLY, + NULL, PyArray_DESCR(self)); + if (mit == NULL) { + goto finish; + } + + if (mit->numiter > 1) { + /* + * If it is one, the inner loop checks indices, otherwise + * check indices beforehand, because it is much faster if + * broadcasting occurs and most likely no big overhead + */ + if (PyArray_MapIterCheckIndices(mit) < 0) { + goto finish; + } + } + + /* Reset the outer iterator */ + if (NpyIter_Reset(mit->outer, NULL) < 0) { + goto finish; + } + + if (mapiter_get(mit) < 0) { + goto finish; + } + + result = (PyObject *)mit->extra_op; + Py_INCREF(result); + + if (mit->consec) { + PyArray_MapIterSwapAxes(mit, (PyArrayObject **)&result, 1); + } + + wrap_out_array: + if (!PyArray_CheckExact(self)) { + /* + * Need to create a new array as if the old one never existed. + */ + PyArrayObject *tmp_arr = (PyArrayObject *)result; + + Py_INCREF(PyArray_DESCR(tmp_arr)); + result = PyArray_NewFromDescr(Py_TYPE(self), + PyArray_DESCR(tmp_arr), + PyArray_NDIM(tmp_arr), + PyArray_SHAPE(tmp_arr), + PyArray_STRIDES(tmp_arr), + PyArray_BYTES(tmp_arr), + PyArray_FLAGS(self), + (PyObject *)self); + + if (result == NULL) { + Py_DECREF(tmp_arr); + goto finish; + } + + if (PyArray_SetBaseObject((PyArrayObject *)result, + (PyObject *)tmp_arr) < 0) { + Py_DECREF(result); + result = NULL; + goto finish; + } + } + + finish: + Py_XDECREF(mit); + Py_XDECREF(view); + /* Clean up indices */ + for (i=0; i < index_num; i++) { + Py_XDECREF(indices[i].object); + } + return result; +} + + +/* + * Python C-Api level item assignment (implementation for PySequence_SetItem) + * + * Negative indices are not accepted because PySequence_SetItem converts + * them to positive indices before calling this. + */ +NPY_NO_EXPORT int +array_assign_item(PyArrayObject *self, Py_ssize_t i, PyObject *op) +{ + npy_index_info indices[2]; + + if (op == NULL) { + PyErr_SetString(PyExc_ValueError, + "cannot delete array elements"); + return -1; + } + if (PyArray_FailUnlessWriteable(self, "assignment destination") < 0) { + return -1; + } + if (PyArray_NDIM(self) == 0) { + PyErr_SetString(PyExc_IndexError, + "too many indices for array"); + return -1; + } + + if (i < 0) { + /* This is an error, but undo PySequence_SetItem fix for message */ + i -= PyArray_DIM(self, 0); + } + + indices[0].value = i; + indices[0].type = HAS_INTEGER; + if (PyArray_NDIM(self) == 1) { + char *item; + if (get_item_pointer(self, &item, indices, 1) < 0) { + return -1; + } + if (PyArray_SETITEM(self, item, op) < 0) { + return -1; + } + } + else { + PyArrayObject *view; + + indices[1].value = PyArray_NDIM(self) - 1; + indices[1].type = HAS_ELLIPSIS; + if (get_view_from_index(self, &view, indices, 2, 0) < 0) { + return -1; + } + if (PyArray_CopyObject(view, op) < 0) { + Py_DECREF(view); + return -1; + } + Py_DECREF(view); + } + return 0; +} + + +/* + * General assignment with python indexing objects. + */ +static int +array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op) +{ + int index_type; + int index_num; + int i, ndim, fancy_ndim; + PyArray_Descr *descr = PyArray_DESCR(self); + PyArrayObject *view = NULL; + PyArrayObject *tmp_arr = NULL; + npy_index_info indices[NPY_MAXDIMS * 2 + 1]; + + PyArrayMapIterObject *mit = NULL; + + if (op == NULL) { + PyErr_SetString(PyExc_ValueError, + "cannot delete array elements"); + return -1; + } + if (PyArray_FailUnlessWriteable(self, "assignment destination") < 0) { + return -1; + } + + /* field access */ + if (PyDataType_HASFIELDS(PyArray_DESCR(self))){ + PyArrayObject *view; + int ret = _get_field_view(self, ind, &view, 1); + if (ret == 0){ + if (view == NULL) { + return -1; + } + if (PyArray_CopyObject(view, op) < 0) { + Py_DECREF(view); + return -1; + } + Py_DECREF(view); + return 0; + } + } + + /* Prepare the indices */ + index_type = prepare_index(self, ind, indices, &index_num, + &ndim, &fancy_ndim, 1); + + if (index_type < 0) { + return -1; + } + + /* Full integer index */ + if (index_type == HAS_INTEGER) { + char *item; + if (get_item_pointer(self, &item, indices, index_num) < 0) { + return -1; + } + if (PyArray_SETITEM(self, item, op) < 0) { + return -1; + } + /* integers do not store objects in indices */ + return 0; + } + + /* Single boolean array */ + if (index_type == HAS_BOOL) { + if (!PyArray_Check(op)) { + Py_INCREF(PyArray_DESCR(self)); + tmp_arr = (PyArrayObject *)PyArray_FromAny(op, + PyArray_DESCR(self), 0, 0, + NPY_ARRAY_FORCECAST, NULL); + if (tmp_arr == NULL) { + goto fail; + } + } + else { + Py_INCREF(op); + tmp_arr = (PyArrayObject *)op; + } + + if (array_assign_boolean_subscript(self, + (PyArrayObject *)indices[0].object, + tmp_arr, NPY_CORDER) < 0) { + goto fail; + } + goto success; + } + + + /* + * Single ellipsis index, no need to create a new view. + * Note that here, we do *not* go through self.__getitem__ for subclasses + * (defchar array failed then, due to uninitialized values...) + */ + else if (index_type == HAS_ELLIPSIS) { + if ((PyObject *)self == op) { + /* + * CopyObject does not handle this case gracefully and + * there is nothing to do. Removing the special case + * will cause segfaults, though it is unclear what exactly + * happens. + */ + return 0; + } + /* we can just use self, but incref for error handling */ + Py_INCREF((PyObject *)self); + view = self; + } + + /* + * WARNING: There is a huge special case here. If this is not a + * base class array, we have to get the view through its + * very own index machinery. + * Many subclasses should probably call __setitem__ + * with a base class ndarray view to avoid this. + */ + else if (!(index_type & (HAS_FANCY | HAS_SCALAR_ARRAY)) + && !PyArray_CheckExact(self)) { + view = (PyArrayObject *)PyObject_GetItem((PyObject *)self, ind); + if (view == NULL) { + goto fail; + } + if (!PyArray_Check(view)) { + PyErr_SetString(PyExc_RuntimeError, + "Getitem not returning array"); + goto fail; + } + } + + /* + * View based indexing. + * There are two cases here. First we need to create a simple view, + * second we need to create a (possibly invalid) view for the + * subspace to the fancy index. This procedure is identical. + */ + else if (index_type & (HAS_SLICE | HAS_NEWAXIS | + HAS_ELLIPSIS | HAS_INTEGER)) { + if (get_view_from_index(self, &view, indices, index_num, + (index_type & HAS_FANCY)) < 0) { + goto fail; + } + } + else { + view = NULL; + } + + /* If there is no fancy indexing, we have the array to assign to */ + if (!(index_type & HAS_FANCY)) { + if (PyArray_CopyObject(view, op) < 0) { + goto fail; + } + goto success; + } + + if (!PyArray_Check(op)) { + /* + * If the array is of object converting the values to an array + * might not be legal even though normal assignment works. + * So allocate a temporary array of the right size and use the + * normal assignment to handle this case. + */ + if (PyDataType_REFCHK(descr) && PySequence_Check(op)) { + tmp_arr = NULL; + } + else { + /* There is nothing fancy possible, so just make an array */ + Py_INCREF(descr); + tmp_arr = (PyArrayObject *)PyArray_FromAny(op, descr, 0, 0, + NPY_ARRAY_FORCECAST, NULL); + if (tmp_arr == NULL) { + goto fail; + } + } + } + else { + Py_INCREF(op); + tmp_arr = (PyArrayObject *)op; + } + + /* + * Special case for very simple 1-d fancy indexing, which however + * is quite common. This saves not only a lot of setup time in the + * iterator, but also is faster (must be exactly fancy because + * we don't support 0-d booleans here) + */ + if (index_type == HAS_FANCY && + index_num == 1 && tmp_arr) { + /* The array being indexed has one dimension and it is a fancy index */ + PyArrayObject *ind = (PyArrayObject*)indices[0].object; + + /* Check if the type is equivalent */ + if (PyArray_EquivTypes(PyArray_DESCR(self), + PyArray_DESCR(tmp_arr)) && + /* + * Either they are equivalent, or the values must + * be a scalar + */ + (PyArray_EQUIVALENTLY_ITERABLE(ind, tmp_arr, + PyArray_TRIVIALLY_ITERABLE_OP_READ, + PyArray_TRIVIALLY_ITERABLE_OP_READ) || + (PyArray_NDIM(tmp_arr) == 0 && + PyArray_TRIVIALLY_ITERABLE(tmp_arr))) && + /* Check if the type is equivalent to INTP */ + PyArray_ITEMSIZE(ind) == sizeof(npy_intp) && + PyArray_DESCR(ind)->kind == 'i' && + PyArray_ISALIGNED(ind) && + PyDataType_ISNOTSWAPPED(PyArray_DESCR(ind))) { + + /* trivial_set checks the index for us */ + if (mapiter_trivial_set(self, ind, tmp_arr) < 0) { + goto fail; + } + goto success; + } + } + + /* + * NOTE: If tmp_arr was not allocated yet, mit should + * handle the allocation. + * The NPY_ITER_READWRITE is necessary for automatic + * allocation. Readwrite would not allow broadcasting + * correctly, but such an operand always has the full + * size anyway. + */ + mit = (PyArrayMapIterObject *)PyArray_MapIterNew(indices, + index_num, index_type, + ndim, fancy_ndim, self, + view, 0, + NPY_ITER_WRITEONLY, + ((tmp_arr == NULL) ? + NPY_ITER_READWRITE : + NPY_ITER_READONLY), + tmp_arr, descr); + + if (mit == NULL) { + goto fail; + } + + if (tmp_arr == NULL) { + /* Fill extra op, need to swap first */ + tmp_arr = mit->extra_op; + Py_INCREF(tmp_arr); + if (mit->consec) { + PyArray_MapIterSwapAxes(mit, &tmp_arr, 1); + if (tmp_arr == NULL) { + goto fail; + } + } + if (PyArray_CopyObject(tmp_arr, op) < 0) { + goto fail; + } + } + + /* Can now reset the outer iterator (delayed bufalloc) */ + if (NpyIter_Reset(mit->outer, NULL) < 0) { + goto fail; + } + + if (PyArray_MapIterCheckIndices(mit) < 0) { + goto fail; + } + + /* + * Could add a casting check, but apparently most assignments do + * not care about safe casting. + */ + + if (mapiter_set(mit) < 0) { + goto fail; + } + + Py_DECREF(mit); + goto success; + + /* Clean up temporary variables and indices */ + fail: + Py_XDECREF((PyObject *)view); + Py_XDECREF((PyObject *)tmp_arr); + Py_XDECREF((PyObject *)mit); + for (i=0; i < index_num; i++) { + Py_XDECREF(indices[i].object); + } + return -1; + + success: + Py_XDECREF((PyObject *)view); + Py_XDECREF((PyObject *)tmp_arr); + for (i=0; i < index_num; i++) { + Py_XDECREF(indices[i].object); + } + return 0; +} + + +NPY_NO_EXPORT PyMappingMethods array_as_mapping = { + (lenfunc)array_length, /*mp_length*/ + (binaryfunc)array_subscript, /*mp_subscript*/ + (objobjargproc)array_assign_subscript, /*mp_ass_subscript*/ +}; + +/****************** End of Mapping Protocol ******************************/ + +/*********************** Subscript Array Iterator ************************* + * * + * This object handles subscript behavior for array objects. * + * It is an iterator object with a next method * + * It abstracts the n-dimensional mapping behavior to make the looping * + * code more understandable (maybe) * + * and so that indexing can be set up ahead of time * + */ + +/* + * This function takes a Boolean array and constructs index objects and + * iterators as if nonzero(Bool) had been called + * + * Must not be called on a 0-d array. + */ +static int +_nonzero_indices(PyObject *myBool, PyArrayObject **arrays) +{ + PyArray_Descr *typecode; + PyArrayObject *ba = NULL, *new = NULL; + int nd, j; + npy_intp size, i, count; + npy_bool *ptr; + npy_intp coords[NPY_MAXDIMS], dims_m1[NPY_MAXDIMS]; + npy_intp *dptr[NPY_MAXDIMS]; + static npy_intp one = 1; + NPY_BEGIN_THREADS_DEF; + + typecode=PyArray_DescrFromType(NPY_BOOL); + ba = (PyArrayObject *)PyArray_FromAny(myBool, typecode, 0, 0, + NPY_ARRAY_CARRAY, NULL); + if (ba == NULL) { + return -1; + } + nd = PyArray_NDIM(ba); + + for (j = 0; j < nd; j++) { + arrays[j] = NULL; + } + size = PyArray_SIZE(ba); + ptr = (npy_bool *)PyArray_DATA(ba); + + /* + * pre-determine how many nonzero entries there are, + * ignore dimensionality of input as its a CARRAY + */ + count = count_boolean_trues(1, (char*)ptr, &size, &one); + + /* create count-sized index arrays for each dimension */ + for (j = 0; j < nd; j++) { + new = (PyArrayObject *)PyArray_New(&PyArray_Type, 1, &count, + NPY_INTP, NULL, NULL, + 0, 0, NULL); + if (new == NULL) { + goto fail; + } + arrays[j] = new; + + dptr[j] = (npy_intp *)PyArray_DATA(new); + coords[j] = 0; + dims_m1[j] = PyArray_DIMS(ba)[j]-1; + } + if (count == 0) { + goto finish; + } + + /* + * Loop through the Boolean array and copy coordinates + * for non-zero entries + */ + NPY_BEGIN_THREADS_THRESHOLDED(size); + for (i = 0; i < size; i++) { + if (*(ptr++)) { + for (j = 0; j < nd; j++) { + *(dptr[j]++) = coords[j]; + } + } + /* Borrowed from ITER_NEXT macro */ + for (j = nd - 1; j >= 0; j--) { + if (coords[j] < dims_m1[j]) { + coords[j]++; + break; + } + else { + coords[j] = 0; + } + } + } + NPY_END_THREADS; + + finish: + Py_DECREF(ba); + return nd; + + fail: + for (j = 0; j < nd; j++) { + Py_XDECREF(arrays[j]); + } + Py_XDECREF(ba); + return -1; +} + + +/* Reset the map iterator to the beginning */ +NPY_NO_EXPORT void +PyArray_MapIterReset(PyArrayMapIterObject *mit) +{ + npy_intp indval; + char *baseptrs[2]; + int i; + + if (mit->size == 0) { + return; + } + + NpyIter_Reset(mit->outer, NULL); + if (mit->extra_op_iter) { + NpyIter_Reset(mit->extra_op_iter, NULL); + + baseptrs[1] = mit->extra_op_ptrs[0]; + } + + baseptrs[0] = mit->baseoffset; + + for (i = 0; i < mit->numiter; i++) { + indval = *((npy_intp*)mit->outer_ptrs[i]); + if (indval < 0) { + indval += mit->fancy_dims[i]; + } + baseptrs[0] += indval * mit->fancy_strides[i]; + } + mit->dataptr = baseptrs[0]; + + if (mit->subspace_iter) { + NpyIter_ResetBasePointers(mit->subspace_iter, baseptrs, NULL); + mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->subspace_iter); + } + else { + mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->outer); + } + + return; +} + + +/*NUMPY_API + * This function needs to update the state of the map iterator + * and point mit->dataptr to the memory-location of the next object + * + * Note that this function never handles an extra operand but provides + * compatibility for an old (exposed) API. + */ +NPY_NO_EXPORT void +PyArray_MapIterNext(PyArrayMapIterObject *mit) +{ + int i; + char *baseptr; + npy_intp indval; + + if (mit->subspace_iter) { + if (--mit->iter_count > 0) { + mit->subspace_ptrs[0] += mit->subspace_strides[0]; + mit->dataptr = mit->subspace_ptrs[0]; + return; + } + else if (mit->subspace_next(mit->subspace_iter)) { + mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->subspace_iter); + mit->dataptr = mit->subspace_ptrs[0]; + } + else { + if (!mit->outer_next(mit->outer)) { + return; + } + + baseptr = mit->baseoffset; + + for (i = 0; i < mit->numiter; i++) { + indval = *((npy_intp*)mit->outer_ptrs[i]); + if (indval < 0) { + indval += mit->fancy_dims[i]; + } + baseptr += indval * mit->fancy_strides[i]; + } + NpyIter_ResetBasePointers(mit->subspace_iter, &baseptr, NULL); + mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->subspace_iter); + + mit->dataptr = mit->subspace_ptrs[0]; + } + } + else { + if (--mit->iter_count > 0) { + baseptr = mit->baseoffset; + + for (i = 0; i < mit->numiter; i++) { + mit->outer_ptrs[i] += mit->outer_strides[i]; + + indval = *((npy_intp*)mit->outer_ptrs[i]); + if (indval < 0) { + indval += mit->fancy_dims[i]; + } + baseptr += indval * mit->fancy_strides[i]; + } + + mit->dataptr = baseptr; + return; + } + else { + if (!mit->outer_next(mit->outer)) { + return; + } + mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->outer); + baseptr = mit->baseoffset; + + for (i = 0; i < mit->numiter; i++) { + indval = *((npy_intp*)mit->outer_ptrs[i]); + if (indval < 0) { + indval += mit->fancy_dims[i]; + } + baseptr += indval * mit->fancy_strides[i]; + } + + mit->dataptr = baseptr; + } + } +} + + +/** + * Fill information about the iterator. The MapIterObject does not + * need to have any information set for this function to work. + * (PyArray_MapIterSwapAxes requires also nd and nd_fancy info) + * + * Sets the following information: + * * mit->consec: The axis where the fancy indices need transposing to. + * * mit->iteraxes: The axis which the fancy index corresponds to. + * * mit-> fancy_dims: the dimension of `arr` along the indexed dimension + * for each fancy index. + * * mit->fancy_strides: the strides for the dimension being indexed + * by each fancy index. + * * mit->dimensions: Broadcast dimension of the fancy indices and + * the subspace iteration dimension. + * + * @param MapIterObject + * @param The parsed indices object + * @param Number of indices + * @param The array that is being iterated + * + * @return 0 on success -1 on failure + */ +static int +mapiter_fill_info(PyArrayMapIterObject *mit, npy_index_info *indices, + int index_num, PyArrayObject *arr) +{ + int j = 0, i; + int curr_dim = 0; + /* dimension of index result (up to first fancy index) */ + int result_dim = 0; + /* -1 init; 0 found fancy; 1 fancy stopped; 2 found not consecutive fancy */ + int consec_status = -1; + int axis, broadcast_axis; + npy_intp dimension; + PyObject *errmsg, *tmp; + + for (i = 0; i < mit->nd_fancy; i++) { + mit->dimensions[i] = 1; + } + + mit->consec = 0; + for (i = 0; i < index_num; i++) { + /* integer and fancy indexes are transposed together */ + if (indices[i].type & (HAS_FANCY | HAS_INTEGER)) { + /* there was no previous fancy index, so set consec */ + if (consec_status == -1) { + mit->consec = result_dim; + consec_status = 0; + } + /* there was already a non-fancy index after a fancy one */ + else if (consec_status == 1) { + consec_status = 2; + mit->consec = 0; + } + } + else { + /* consec_status == 0 means there was a fancy index before */ + if (consec_status == 0) { + consec_status = 1; + } + } + + /* (iterating) fancy index, store the iterator */ + if (indices[i].type == HAS_FANCY) { + mit->fancy_strides[j] = PyArray_STRIDE(arr, curr_dim); + mit->fancy_dims[j] = PyArray_DIM(arr, curr_dim); + mit->iteraxes[j++] = curr_dim++; + + /* Check broadcasting */ + broadcast_axis = mit->nd_fancy; + /* Fill from back, we know how many dims there are */ + for (axis = PyArray_NDIM((PyArrayObject *)indices[i].object) - 1; + axis >= 0; axis--) { + broadcast_axis--; + dimension = PyArray_DIM((PyArrayObject *)indices[i].object, axis); + + /* If it is 1, we can broadcast */ + if (dimension != 1) { + if (dimension != mit->dimensions[broadcast_axis]) { + if (mit->dimensions[broadcast_axis] != 1) { + goto broadcast_error; + } + mit->dimensions[broadcast_axis] = dimension; + } + } + } + } + else if (indices[i].type == HAS_0D_BOOL) { + mit->fancy_strides[j] = 0; + mit->fancy_dims[j] = 1; + /* Does not exist */ + mit->iteraxes[j++] = -1; + if ((indices[i].value == 0) && + (mit->dimensions[mit->nd_fancy - 1]) > 1) { + goto broadcast_error; + } + mit->dimensions[mit->nd_fancy-1] *= indices[i].value; + } + + /* advance curr_dim for non-fancy indices */ + else if (indices[i].type == HAS_ELLIPSIS) { + curr_dim += (int)indices[i].value; + result_dim += (int)indices[i].value; + } + else if (indices[i].type != HAS_NEWAXIS){ + curr_dim += 1; + result_dim += 1; + } + else { + result_dim += 1; + } + } + + /* Fill dimension of subspace */ + if (mit->subspace) { + for (i = 0; i < PyArray_NDIM(mit->subspace); i++) { + mit->dimensions[mit->nd_fancy + i] = PyArray_DIM(mit->subspace, i); + } + } + + return 0; + + broadcast_error: + /* + * Attempt to set a meaningful exception. Could also find out + * if a boolean index was converted. + */ + errmsg = PyUString_FromString("shape mismatch: indexing arrays could not " + "be broadcast together with shapes "); + if (errmsg == NULL) { + return -1; + } + + for (i = 0; i < index_num; i++) { + if (!(indices[i].type & HAS_FANCY)) { + continue; + } + tmp = convert_shape_to_string( + PyArray_NDIM((PyArrayObject *)indices[i].object), + PyArray_SHAPE((PyArrayObject *)indices[i].object), + " "); + if (tmp == NULL) { + return -1; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return -1; + } + } + + PyErr_SetObject(PyExc_IndexError, errmsg); + Py_DECREF(errmsg); + return -1; +} + + +/* + * Check whether the fancy indices are out of bounds. + * Returns 0 on success and -1 on failure. + * (Gets operands from the outer iterator, but iterates them independently) + */ +NPY_NO_EXPORT int +PyArray_MapIterCheckIndices(PyArrayMapIterObject *mit) +{ + PyArrayObject *op; + NpyIter *op_iter; + NpyIter_IterNextFunc *op_iternext; + npy_intp outer_dim, indval; + int outer_axis; + npy_intp itersize, *iterstride; + char **iterptr; + PyArray_Descr *intp_type; + int i; + NPY_BEGIN_THREADS_DEF; + + if (mit->size == 0) { + /* All indices got broadcast away, do *not* check as it always was */ + return 0; + } + + intp_type = PyArray_DescrFromType(NPY_INTP); + + NPY_BEGIN_THREADS; + + for (i=0; i < mit->numiter; i++) { + op = NpyIter_GetOperandArray(mit->outer)[i]; + + outer_dim = mit->fancy_dims[i]; + outer_axis = mit->iteraxes[i]; + + /* See if it is possible to just trivially iterate the array */ + if (PyArray_TRIVIALLY_ITERABLE(op) && + /* Check if the type is equivalent to INTP */ + PyArray_ITEMSIZE(op) == sizeof(npy_intp) && + PyArray_DESCR(op)->kind == 'i' && + PyArray_ISALIGNED(op) && + PyDataType_ISNOTSWAPPED(PyArray_DESCR(op))) { + char *data; + npy_intp stride; + /* release GIL if it was taken by nditer below */ + if (_save == NULL) { + NPY_BEGIN_THREADS; + } + + PyArray_PREPARE_TRIVIAL_ITERATION(op, itersize, data, stride); + + while (itersize--) { + indval = *((npy_intp*)data); + if (check_and_adjust_index(&indval, + outer_dim, outer_axis, _save) < 0) { + return -1; + } + data += stride; + } + /* GIL retake at end of function or if nditer path required */ + continue; + } + + /* Use NpyIter if the trivial iteration is not possible */ + NPY_END_THREADS; + op_iter = NpyIter_New(op, + NPY_ITER_BUFFERED | NPY_ITER_NBO | NPY_ITER_ALIGNED | + NPY_ITER_EXTERNAL_LOOP | NPY_ITER_GROWINNER | + NPY_ITER_READONLY, + NPY_KEEPORDER, NPY_SAME_KIND_CASTING, intp_type); + + if (op_iter == NULL) { + Py_DECREF(intp_type); + return -1; + } + + op_iternext = NpyIter_GetIterNext(op_iter, NULL); + if (op_iternext == NULL) { + Py_DECREF(intp_type); + NpyIter_Deallocate(op_iter); + return -1; + } + + NPY_BEGIN_THREADS_NDITER(op_iter); + iterptr = NpyIter_GetDataPtrArray(op_iter); + iterstride = NpyIter_GetInnerStrideArray(op_iter); + do { + itersize = *NpyIter_GetInnerLoopSizePtr(op_iter); + while (itersize--) { + indval = *((npy_intp*)*iterptr); + if (check_and_adjust_index(&indval, + outer_dim, outer_axis, _save) < 0) { + Py_DECREF(intp_type); + NpyIter_Deallocate(op_iter); + return -1; + } + *iterptr += *iterstride; + } + } while (op_iternext(op_iter)); + + NPY_END_THREADS; + NpyIter_Deallocate(op_iter); + } + + NPY_END_THREADS; + Py_DECREF(intp_type); + return 0; +} + + +/* + * Create new mapiter. + * + * NOTE: The outer iteration (and subspace if requested buffered) is + * created with DELAY_BUFALLOC. It must be reset before usage! + * + * @param Index information filled by prepare_index. + * @param Number of indices (gotten through prepare_index). + * @param Kind of index (gotten through preprare_index). + * @param NpyIter flags for an extra array. If 0 assume that there is no + * extra operand. NPY_ITER_ALLOCATE can make sense here. + * @param Array being indexed + * @param subspace (result of getting view for the indices) + * @param Subspace iterator flags can be used to enable buffering. + * NOTE: When no subspace is necessary, the extra operand will + * always be buffered! Buffering the subspace when not + * necessary is very slow when the subspace is small. + * @param Subspace operand flags (should just be 0 normally) + * @param Operand iteration flags for the extra operand, this must not be + * 0 if an extra operand should be used, otherwise it must be 0. + * Should be at least READONLY, WRITEONLY or READWRITE. + * @param Extra operand. For getmap, this would be the result, for setmap + * this would be the arrays to get from. + * Can be NULL, and will be allocated in that case. However, + * it matches the mapiter iteration, so you have to call + * MapIterSwapAxes(mit, &extra_op, 1) on it. + * The operand has no effect on the shape. + * @param Dtype for the extra operand, borrows the reference and must not + * be NULL (if extra_op_flags is not 0). + * + * @return A new MapIter (PyObject *) or NULL. + */ +NPY_NO_EXPORT PyObject * +PyArray_MapIterNew(npy_index_info *indices , int index_num, int index_type, + int ndim, int fancy_ndim, + PyArrayObject *arr, PyArrayObject *subspace, + npy_uint32 subspace_iter_flags, npy_uint32 subspace_flags, + npy_uint32 extra_op_flags, PyArrayObject *extra_op, + PyArray_Descr *extra_op_dtype) +{ + PyObject *errmsg, *tmp; + /* For shape reporting on error */ + PyArrayObject *original_extra_op = extra_op; + + PyArrayObject *index_arrays[NPY_MAXDIMS]; + PyArray_Descr *dtypes[NPY_MAXDIMS]; + + npy_uint32 op_flags[NPY_MAXDIMS]; + npy_uint32 outer_flags; + + PyArrayMapIterObject *mit; + + int single_op_axis[NPY_MAXDIMS]; + int *op_axes[NPY_MAXDIMS] = {NULL}; + int i, j, dummy_array = 0; + int nops; + int uses_subspace; + + /* create new MapIter object */ + mit = (PyArrayMapIterObject *)PyArray_malloc(sizeof(PyArrayMapIterObject)); + if (mit == NULL) { + return NULL; + } + /* set all attributes of mapiter to zero */ + memset(mit, 0, sizeof(PyArrayMapIterObject)); + PyObject_Init((PyObject *)mit, &PyArrayMapIter_Type); + + Py_INCREF(arr); + mit->array = arr; + Py_XINCREF(subspace); + mit->subspace = subspace; + + /* + * The subspace, the part of the array which is not indexed by + * arrays, needs to be iterated when the size of the subspace + * is larger than 1. If it is one, it has only an effect on the + * result shape. (Optimizes for example np.newaxis usage) + */ + if ((subspace == NULL) || PyArray_SIZE(subspace) == 1) { + uses_subspace = 0; + } + else { + uses_subspace = 1; + } + + /* Fill basic information about the mapiter */ + mit->nd = ndim; + mit->nd_fancy = fancy_ndim; + if (mapiter_fill_info(mit, indices, index_num, arr) < 0) { + Py_DECREF(mit); + return NULL; + } + + /* + * Set iteration information of the indexing arrays. + */ + for (i=0; i < index_num; i++) { + if (indices[i].type & HAS_FANCY) { + index_arrays[mit->numiter] = (PyArrayObject *)indices[i].object; + dtypes[mit->numiter] = PyArray_DescrFromType(NPY_INTP); + + op_flags[mit->numiter] = (NPY_ITER_NBO | + NPY_ITER_ALIGNED | + NPY_ITER_READONLY); + mit->numiter += 1; + } + } + + if (mit->numiter == 0) { + /* + * For MapIterArray, it is possible that there is no fancy index. + * to support this case, add a a dummy iterator. + * Since it is 0-d its transpose, etc. does not matter. + */ + + /* signal necessity to decref... */ + dummy_array = 1; + + index_arrays[0] = (PyArrayObject *)PyArray_Zeros(0, NULL, + PyArray_DescrFromType(NPY_INTP), 0); + if (index_arrays[0] == NULL) { + Py_DECREF(mit); + return NULL; + } + dtypes[0] = PyArray_DescrFromType(NPY_INTP); + op_flags[0] = NPY_ITER_NBO | NPY_ITER_ALIGNED | NPY_ITER_READONLY; + + mit->fancy_dims[0] = 1; + mit->numiter = 1; + } + + /* + * Now there are two general cases how extra_op is used: + * 1. No subspace iteration is necessary, so the extra_op can + * be included into the index iterator (it will be buffered) + * 2. Subspace iteration is necessary, so the extra op is iterated + * independently, and the iteration order is fixed at C (could + * also use Fortran order if the array is Fortran order). + * In this case the subspace iterator is not buffered. + * + * If subspace iteration is necessary and an extra_op was given, + * it may also be necessary to transpose the extra_op (or signal + * the transposing to the advanced iterator). + */ + + if (extra_op != NULL) { + /* + * If we have an extra_op given, need to prepare it. + * 1. Subclasses might mess with the shape, so need a baseclass + * 2. Need to make sure the shape is compatible + * 3. May need to remove leading 1s and transpose dimensions. + * Normal assignments allows broadcasting away leading 1s, but + * the transposing code does not like this. + */ + if (!PyArray_CheckExact(extra_op)) { + extra_op = (PyArrayObject *)PyArray_View(extra_op, NULL, + &PyArray_Type); + if (extra_op == NULL) { + goto fail; + } + } + else { + Py_INCREF(extra_op); + } + + if (PyArray_NDIM(extra_op) > mit->nd) { + /* + * Usual assignments allows removal of leading one dimensions. + * (or equivalently adding of one dimensions to the array being + * assigned to). To implement this, reshape the array. + */ + PyArrayObject *tmp_arr; + PyArray_Dims permute; + + permute.len = mit->nd; + permute.ptr = &PyArray_DIMS(extra_op)[ + PyArray_NDIM(extra_op) - mit->nd]; + tmp_arr = (PyArrayObject*)PyArray_Newshape(extra_op, &permute, + NPY_CORDER); + if (tmp_arr == NULL) { + goto broadcast_error; + } + Py_DECREF(extra_op); + extra_op = tmp_arr; + } + + /* + * If dimensions need to be prepended (and no swapaxis is needed), + * use op_axes after extra_op is allocated for sure. + */ + if (mit->consec) { + PyArray_MapIterSwapAxes(mit, &extra_op, 0); + if (extra_op == NULL) { + goto fail; + } + } + + if (subspace && !uses_subspace) { + /* + * We are not using the subspace, so its size is 1. + * All dimensions of the extra_op corresponding to the + * subspace must be equal to 1. + */ + if (PyArray_NDIM(subspace) <= PyArray_NDIM(extra_op)) { + j = PyArray_NDIM(subspace); + } + else { + j = PyArray_NDIM(extra_op); + } + for (i = 1; i < j + 1; i++) { + if (PyArray_DIM(extra_op, PyArray_NDIM(extra_op) - i) != 1) { + goto broadcast_error; + } + } + } + } + + /* + * If subspace is not NULL, NpyIter cannot allocate extra_op for us. + * This is a bit of a kludge. A dummy iterator is created to find + * the correct output shape and stride permutation. + * TODO: This can at least partially be replaced, since the shape + * is found for broadcasting errors. + */ + else if (extra_op_flags && (subspace != NULL)) { + npy_uint32 tmp_op_flags[NPY_MAXDIMS]; + + NpyIter *tmp_iter; + npy_intp stride; + npy_intp strides[NPY_MAXDIMS]; + npy_stride_sort_item strideperm[NPY_MAXDIMS]; + + for (i=0; i < mit->numiter; i++) { + tmp_op_flags[i] = NPY_ITER_READONLY; + } + + Py_INCREF(extra_op_dtype); + mit->extra_op_dtype = extra_op_dtype; + + /* Create an iterator, just to broadcast the arrays?! */ + tmp_iter = NpyIter_MultiNew(mit->numiter, index_arrays, + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_REFS_OK | + NPY_ITER_MULTI_INDEX | + NPY_ITER_DONT_NEGATE_STRIDES, + NPY_KEEPORDER, + NPY_UNSAFE_CASTING, + tmp_op_flags, NULL); + if (tmp_iter == NULL) { + goto fail; + } + + if (PyArray_SIZE(subspace) == 1) { + /* + * nditer allows itemsize with npy_intp type, so it works + * here, but it would *not* work directly, since elsize + * is limited to int. + */ + if (!NpyIter_CreateCompatibleStrides(tmp_iter, + extra_op_dtype->elsize * PyArray_SIZE(subspace), + strides)) { + PyErr_SetString(PyExc_ValueError, + "internal error: failed to find output array strides"); + goto fail; + } + } + else { + /* Just use C-order strides (TODO: allow also F-order) */ + stride = extra_op_dtype->elsize * PyArray_SIZE(subspace); + for (i=mit->nd_fancy - 1; i >= 0; i--) { + strides[i] = stride; + stride *= mit->dimensions[i]; + } + } + NpyIter_Deallocate(tmp_iter); + + /* shape is set, and strides is set up to mit->nd, set rest */ + PyArray_CreateSortedStridePerm(PyArray_NDIM(subspace), + PyArray_STRIDES(subspace), strideperm); + stride = extra_op_dtype->elsize; + for (i=PyArray_NDIM(subspace) - 1; i >= 0; i--) { + strides[mit->nd_fancy + strideperm[i].perm] = stride; + stride *= PyArray_DIM(subspace, (int)strideperm[i].perm); + } + + /* + * Allocate new array. Note: Always base class, because + * subclasses might mess with the shape. + */ + Py_INCREF(extra_op_dtype); + extra_op = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + extra_op_dtype, + mit->nd_fancy + PyArray_NDIM(subspace), + mit->dimensions, strides, + NULL, 0, NULL); + if (extra_op == NULL) { + goto fail; + } + } + + /* + * The extra op is now either allocated, can be allocated by + * NpyIter (no subspace) or is not used at all. + * + * Need to set the axis remapping for the extra_op. This needs + * to cause ignoring of subspace dimensions and prepending -1 + * for broadcasting. + */ + if (extra_op) { + for (j=0; j < mit->nd - PyArray_NDIM(extra_op); j++) { + single_op_axis[j] = -1; + } + for (i=0; i < PyArray_NDIM(extra_op); i++) { + /* (fills subspace dimensions too, but they are not unused) */ + single_op_axis[j++] = i; + } + } + + /* + * NOTE: If for some reason someone wishes to use REDUCE_OK, be + * careful and fix the error message replacement at the end. + */ + outer_flags = NPY_ITER_ZEROSIZE_OK | + NPY_ITER_REFS_OK | + NPY_ITER_BUFFERED | + NPY_ITER_DELAY_BUFALLOC | + NPY_ITER_GROWINNER; + + /* + * For a single 1-d operand, guarantee iteration order + * (scipy used this). Note that subspace may be used. + */ + if ((mit->numiter == 1) && (PyArray_NDIM(index_arrays[0]) == 1)) { + outer_flags |= NPY_ITER_DONT_NEGATE_STRIDES; + } + + /* If external array is iterated, and no subspace is needed */ + nops = mit->numiter; + if (extra_op_flags && !uses_subspace) { + /* + * NOTE: This small limitation should practically not matter. + * (replaces npyiter error) + */ + if (mit->numiter > NPY_MAXDIMS - 1) { + PyErr_Format(PyExc_IndexError, + "when no subspace is given, the number of index " + "arrays cannot be above %d, but %d index arrays found", + NPY_MAXDIMS - 1, mit->numiter); + goto fail; + } + + nops += 1; + index_arrays[mit->numiter] = extra_op; + + Py_INCREF(extra_op_dtype); + dtypes[mit->numiter] = extra_op_dtype; + op_flags[mit->numiter] = (extra_op_flags | + NPY_ITER_ALLOCATE | + NPY_ITER_NO_SUBTYPE); + + if (extra_op) { + /* Use the axis remapping */ + op_axes[mit->numiter] = single_op_axis; + mit->outer = NpyIter_AdvancedNew(nops, index_arrays, outer_flags, + NPY_KEEPORDER, NPY_UNSAFE_CASTING, op_flags, dtypes, + mit->nd_fancy, op_axes, mit->dimensions, 0); + } + else { + mit->outer = NpyIter_MultiNew(nops, index_arrays, outer_flags, + NPY_KEEPORDER, NPY_UNSAFE_CASTING, op_flags, dtypes); + } + + } + else { + /* TODO: Maybe add test for the CORDER, and maybe also allow F */ + mit->outer = NpyIter_MultiNew(nops, index_arrays, outer_flags, + NPY_CORDER, NPY_UNSAFE_CASTING, op_flags, dtypes); + } + + /* NpyIter cleanup and information: */ + for (i=0; i < nops; i++) { + Py_DECREF(dtypes[i]); + } + if (dummy_array) { + Py_DECREF(index_arrays[0]); + } + if (mit->outer == NULL) { + goto fail; + } + if (!uses_subspace) { + NpyIter_EnableExternalLoop(mit->outer); + } + + mit->outer_next = NpyIter_GetIterNext(mit->outer, NULL); + if (mit->outer_next == NULL) { + goto fail; + } + mit->outer_ptrs = NpyIter_GetDataPtrArray(mit->outer); + if (!uses_subspace) { + mit->outer_strides = NpyIter_GetInnerStrideArray(mit->outer); + } + if (NpyIter_IterationNeedsAPI(mit->outer)) { + mit->needs_api = 1; + /* We may be doing a cast for the buffer, and that may have failed */ + if (PyErr_Occurred()) { + goto fail; + } + } + + /* Get the allocated extra_op */ + if (extra_op_flags) { + if (extra_op == NULL) { + mit->extra_op = NpyIter_GetOperandArray(mit->outer)[mit->numiter]; + } + else { + mit->extra_op = extra_op; + } + Py_INCREF(mit->extra_op); + } + + /* + * If extra_op is being tracked but subspace is used, we need + * to create a dedicated iterator for the outer iteration of + * the extra operand. + */ + if (extra_op_flags && uses_subspace) { + op_axes[0] = single_op_axis; + mit->extra_op_iter = NpyIter_AdvancedNew(1, &extra_op, + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_REFS_OK | + NPY_ITER_GROWINNER, + NPY_CORDER, + NPY_NO_CASTING, + &extra_op_flags, + NULL, + mit->nd_fancy, op_axes, + mit->dimensions, 0); + + if (mit->extra_op_iter == NULL) { + goto fail; + } + + mit->extra_op_next = NpyIter_GetIterNext(mit->extra_op_iter, NULL); + if (mit->extra_op_next == NULL) { + goto fail; + } + mit->extra_op_ptrs = NpyIter_GetDataPtrArray(mit->extra_op_iter); + } + + /* Get the full dimension information */ + if (subspace != NULL) { + mit->baseoffset = PyArray_BYTES(subspace); + } + else { + mit->baseoffset = PyArray_BYTES(arr); + } + + /* Calculate total size of the MapIter */ + mit->size = PyArray_OverflowMultiplyList(mit->dimensions, mit->nd); + if (mit->size < 0) { + PyErr_SetString(PyExc_ValueError, + "advanced indexing operation result is too large"); + goto fail; + } + + /* Can now return early if no subspace is being used */ + if (!uses_subspace) { + Py_XDECREF(extra_op); + return (PyObject *)mit; + } + + /* Fill in the last bit of mapiter information needed */ + + /* + * Now just need to create the correct subspace iterator. + */ + index_arrays[0] = subspace; + dtypes[0] = NULL; + op_flags[0] = subspace_flags; + op_axes[0] = NULL; + + if (extra_op_flags) { + /* We should iterate the extra_op as well */ + nops = 2; + index_arrays[1] = extra_op; + + op_axes[1] = &single_op_axis[mit->nd_fancy]; + + /* + * Buffering is never used here, but in case someone plugs it in + * somewhere else, set the type correctly then. + */ + if ((subspace_iter_flags & NPY_ITER_BUFFERED)) { + dtypes[1] = extra_op_dtype; + } + else { + dtypes[1] = NULL; + } + op_flags[1] = extra_op_flags; + } + else { + nops = 1; + } + + mit->subspace_iter = NpyIter_AdvancedNew(nops, index_arrays, + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_REFS_OK | + NPY_ITER_GROWINNER | + NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_DELAY_BUFALLOC | + subspace_iter_flags, + (nops == 1 ? NPY_CORDER : NPY_KEEPORDER), + NPY_UNSAFE_CASTING, + op_flags, dtypes, + PyArray_NDIM(subspace), op_axes, + &mit->dimensions[mit->nd_fancy], 0); + + if (mit->subspace_iter == NULL) { + goto fail; + } + + mit->subspace_next = NpyIter_GetIterNext(mit->subspace_iter, NULL); + if (mit->subspace_next == NULL) { + goto fail; + } + mit->subspace_ptrs = NpyIter_GetDataPtrArray(mit->subspace_iter); + mit->subspace_strides = NpyIter_GetInnerStrideArray(mit->subspace_iter); + + if (NpyIter_IterationNeedsAPI(mit->outer)) { + mit->needs_api = 1; + /* + * NOTE: In this case, need to call PyErr_Occurred() after + * basepointer resetting (buffer allocation) + */ + } + + Py_XDECREF(extra_op); + return (PyObject *)mit; + + fail: + /* + * Check whether the operand could not be broadcast and replace the error + * in that case. This should however normally be found early with a + * direct goto to broadcast_error + */ + if (extra_op == NULL) { + goto finish; + } + + j = mit->nd; + for (i = PyArray_NDIM(extra_op) - 1; i >= 0; i--) { + j--; + if ((PyArray_DIM(extra_op, i) != 1) && + /* (j < 0 is currently impossible, extra_op is reshaped) */ + j >= 0 && + PyArray_DIM(extra_op, i) != mit->dimensions[j]) { + /* extra_op cannot be broadcast to the indexing result */ + goto broadcast_error; + } + } + goto finish; + + broadcast_error: + errmsg = PyUString_FromString("shape mismatch: value array " + "of shape "); + if (errmsg == NULL) { + goto finish; + } + + /* Report the shape of the original array if it exists */ + if (original_extra_op == NULL) { + original_extra_op = extra_op; + } + + tmp = convert_shape_to_string(PyArray_NDIM(original_extra_op), + PyArray_DIMS(original_extra_op), " "); + if (tmp == NULL) { + goto finish; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + goto finish; + } + + tmp = PyUString_FromString("could not be broadcast to indexing " + "result of shape "); + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + goto finish; + } + + tmp = convert_shape_to_string(mit->nd, mit->dimensions, ""); + if (tmp == NULL) { + goto finish; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + goto finish; + } + + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + + finish: + Py_XDECREF(extra_op); + Py_DECREF(mit); + return NULL; +} + + +/*NUMPY_API + * + * Same as PyArray_MapIterArray, but: + * + * If copy_if_overlap != 0, check if `a` has memory overlap with any of the + * arrays in `index` and with `extra_op`. If yes, make copies as appropriate + * to avoid problems if `a` is modified during the iteration. + * `iter->array` may contain a copied array (UPDATEIFCOPY/WRITEBACKIFCOPY set). + */ +NPY_NO_EXPORT PyObject * +PyArray_MapIterArrayCopyIfOverlap(PyArrayObject * a, PyObject * index, + int copy_if_overlap, PyArrayObject *extra_op) +{ + PyArrayMapIterObject * mit = NULL; + PyArrayObject *subspace = NULL; + npy_index_info indices[NPY_MAXDIMS * 2 + 1]; + int i, index_num, ndim, fancy_ndim, index_type; + PyArrayObject *a_copy = NULL; + + index_type = prepare_index(a, index, indices, &index_num, + &ndim, &fancy_ndim, 0); + + if (index_type < 0) { + return NULL; + } + + if (copy_if_overlap && index_has_memory_overlap(a, index_type, indices, + index_num, + (PyObject *)extra_op)) { + /* Make a copy of the input array */ + a_copy = (PyArrayObject *)PyArray_NewLikeArray(a, NPY_ANYORDER, + NULL, 0); + if (a_copy == NULL) { + goto fail; + } + + if (PyArray_CopyInto(a_copy, a) != 0) { + goto fail; + } + + Py_INCREF(a); + if (PyArray_SetWritebackIfCopyBase(a_copy, a) < 0) { + goto fail; + } + + a = a_copy; + } + + /* If it is not a pure fancy index, need to get the subspace */ + if (index_type != HAS_FANCY) { + if (get_view_from_index(a, &subspace, indices, index_num, 1) < 0) { + goto fail; + } + } + + mit = (PyArrayMapIterObject *)PyArray_MapIterNew(indices, index_num, + index_type, ndim, + fancy_ndim, + a, subspace, 0, + NPY_ITER_READWRITE, + 0, NULL, NULL); + if (mit == NULL) { + goto fail; + } + + /* Required for backward compatibility */ + mit->ait = (PyArrayIterObject *)PyArray_IterNew((PyObject *)a); + if (mit->ait == NULL) { + goto fail; + } + + if (PyArray_MapIterCheckIndices(mit) < 0) { + goto fail; + } + + Py_XDECREF(a_copy); + Py_XDECREF(subspace); + PyArray_MapIterReset(mit); + + for (i=0; i < index_num; i++) { + Py_XDECREF(indices[i].object); + } + + return (PyObject *)mit; + + fail: + Py_XDECREF(a_copy); + Py_XDECREF(subspace); + Py_XDECREF((PyObject *)mit); + for (i=0; i < index_num; i++) { + Py_XDECREF(indices[i].object); + } + return NULL; +} + + +/*NUMPY_API + * + * Use advanced indexing to iterate an array. + */ +NPY_NO_EXPORT PyObject * +PyArray_MapIterArray(PyArrayObject * a, PyObject * index) +{ + return PyArray_MapIterArrayCopyIfOverlap(a, index, 0, NULL); +} + + +#undef HAS_INTEGER +#undef HAS_NEWAXIS +#undef HAS_SLICE +#undef HAS_ELLIPSIS +#undef HAS_FANCY +#undef HAS_BOOL +#undef HAS_SCALAR_ARRAY +#undef HAS_0D_BOOL + + +static void +arraymapiter_dealloc(PyArrayMapIterObject *mit) +{ + Py_XDECREF(mit->array); + Py_XDECREF(mit->ait); + Py_XDECREF(mit->subspace); + Py_XDECREF(mit->extra_op); + Py_XDECREF(mit->extra_op_dtype); + if (mit->outer != NULL) { + NpyIter_Deallocate(mit->outer); + } + if (mit->subspace_iter != NULL) { + NpyIter_Deallocate(mit->subspace_iter); + } + if (mit->extra_op_iter != NULL) { + NpyIter_Deallocate(mit->extra_op_iter); + } + PyArray_free(mit); +} + +/* + * The mapiter object must be created new each time. It does not work + * to bind to a new array, and continue. + * + * This was the original intention, but currently that does not work. + * Do not expose the MapIter_Type to Python. + * + * The original mapiter(indexobj); mapiter.bind(a); idea is now fully + * removed. This is not very useful anyway, since mapiter is equivalent + * to a[indexobj].flat but the latter gets to use slice syntax. + */ +NPY_NO_EXPORT PyTypeObject PyArrayMapIter_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.mapiter", /* tp_name */ + sizeof(PyArrayMapIterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)arraymapiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; diff --git a/numpy/core/src/multiarray/mapping.h b/numpy/core/src/multiarray/mapping.h new file mode 100644 index 0000000..4e22f79 --- /dev/null +++ b/numpy/core/src/multiarray/mapping.h @@ -0,0 +1,73 @@ +#ifndef _NPY_ARRAYMAPPING_H_ +#define _NPY_ARRAYMAPPING_H_ + +extern NPY_NO_EXPORT PyMappingMethods array_as_mapping; + + +/* + * Struct into which indices are parsed. + * I.e. integer ones should only be parsed once, slices and arrays + * need to be validated later and for the ellipsis we need to find how + * many slices it represents. + */ +typedef struct { + /* + * Object of index: slice, array, or NULL. Owns a reference. + */ + PyObject *object; + /* + * Value of an integer index, number of slices an Ellipsis is worth, + * -1 if input was an integer array and the original size of the + * boolean array if it is a converted boolean array. + */ + npy_intp value; + /* kind of index, see constants in mapping.c */ + int type; +} npy_index_info; + + +NPY_NO_EXPORT Py_ssize_t +array_length(PyArrayObject *self); + +NPY_NO_EXPORT PyObject * +array_item_asarray(PyArrayObject *self, npy_intp i); + +NPY_NO_EXPORT PyObject * +array_item_asscalar(PyArrayObject *self, npy_intp i); + +NPY_NO_EXPORT PyObject * +array_item(PyArrayObject *self, Py_ssize_t i); + +NPY_NO_EXPORT PyObject * +array_subscript_asarray(PyArrayObject *self, PyObject *op); + +NPY_NO_EXPORT PyObject * +array_subscript(PyArrayObject *self, PyObject *op); + +NPY_NO_EXPORT int +array_assign_item(PyArrayObject *self, Py_ssize_t i, PyObject *v); + +/* + * Prototypes for Mapping calls --- not part of the C-API + * because only useful as part of a getitem call. + */ +NPY_NO_EXPORT void +PyArray_MapIterReset(PyArrayMapIterObject *mit); + +NPY_NO_EXPORT void +PyArray_MapIterNext(PyArrayMapIterObject *mit); + +NPY_NO_EXPORT int +PyArray_MapIterCheckIndices(PyArrayMapIterObject *mit); + +NPY_NO_EXPORT void +PyArray_MapIterSwapAxes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap); + +NPY_NO_EXPORT PyObject* +PyArray_MapIterNew(npy_index_info *indices , int index_num, int index_type, + int ndim, int fancy_ndim, + PyArrayObject *arr, PyArrayObject *subspace, + npy_uint32 subspace_iter_flags, npy_uint32 subspace_flags, + npy_uint32 extra_op_flags, PyArrayObject *extra_op, + PyArray_Descr *extra_op_dtype); +#endif diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c new file mode 100644 index 0000000..2c95898 --- /dev/null +++ b/numpy/core/src/multiarray/methods.c @@ -0,0 +1,2733 @@ +#define PY_SSIZE_T_CLEAN +#include +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" +#include "npy_pycompat.h" +#include "npy_import.h" +#include "ufunc_override.h" +#include "common.h" +#include "templ_common.h" /* for npy_mul_with_overflow_intp */ +#include "ctors.h" +#include "calculation.h" +#include "convert_datatype.h" +#include "item_selection.h" +#include "conversion_utils.h" +#include "shape.h" +#include "strfuncs.h" + +#include "methods.h" +#include "alloc.h" + + +/* NpyArg_ParseKeywords + * + * Utility function that provides the keyword parsing functionality of + * PyArg_ParseTupleAndKeywords without having to have an args argument. + * + */ +static int +NpyArg_ParseKeywords(PyObject *keys, const char *format, char **kwlist, ...) +{ + PyObject *args = PyTuple_New(0); + int ret; + va_list va; + + if (args == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Failed to allocate new tuple"); + return 0; + } + va_start(va, kwlist); + ret = PyArg_VaParseTupleAndKeywords(args, keys, format, kwlist, va); + va_end(va); + Py_DECREF(args); + return ret; +} + +static PyObject * +get_forwarding_ndarray_method(const char *name) +{ + PyObject *module_methods, *callable; + + /* Get a reference to the function we're calling */ + module_methods = PyImport_ImportModule("numpy.core._methods"); + if (module_methods == NULL) { + return NULL; + } + callable = PyDict_GetItemString(PyModule_GetDict(module_methods), name); + if (callable == NULL) { + Py_DECREF(module_methods); + PyErr_Format(PyExc_RuntimeError, + "NumPy internal error: could not find function " + "numpy.core._methods.%s", name); + } + else { + Py_INCREF(callable); + } + Py_DECREF(module_methods); + return callable; +} + +/* + * Forwards an ndarray method to a the Python function + * numpy.core._methods.(...) + */ +static PyObject * +forward_ndarray_method(PyArrayObject *self, PyObject *args, PyObject *kwds, + PyObject *forwarding_callable) +{ + PyObject *sargs, *ret; + int i, n; + + /* Combine 'self' and 'args' together into one tuple */ + n = PyTuple_GET_SIZE(args); + sargs = PyTuple_New(n + 1); + if (sargs == NULL) { + return NULL; + } + Py_INCREF(self); + PyTuple_SET_ITEM(sargs, 0, (PyObject *)self); + for (i = 0; i < n; ++i) { + PyObject *item = PyTuple_GET_ITEM(args, i); + Py_INCREF(item); + PyTuple_SET_ITEM(sargs, i+1, item); + } + + /* Call the function and return */ + ret = PyObject_Call(forwarding_callable, sargs, kwds); + Py_DECREF(sargs); + return ret; +} + +/* + * Forwards an ndarray method to the function numpy.core._methods.(...), + * caching the callable in a local static variable. Note that the + * initialization is not thread-safe, but relies on the CPython GIL to + * be correct. + */ +#define NPY_FORWARD_NDARRAY_METHOD(name) \ + static PyObject *callable = NULL; \ + if (callable == NULL) { \ + callable = get_forwarding_ndarray_method(name); \ + if (callable == NULL) { \ + return NULL; \ + } \ + } \ + return forward_ndarray_method(self, args, kwds, callable) + + +static PyObject * +array_take(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int dimension = NPY_MAXDIMS; + PyObject *indices; + PyArrayObject *out = NULL; + NPY_CLIPMODE mode = NPY_RAISE; + static char *kwlist[] = {"indices", "axis", "out", "mode", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O&O&:take", kwlist, + &indices, + PyArray_AxisConverter, &dimension, + PyArray_OutputConverter, &out, + PyArray_ClipmodeConverter, &mode)) + return NULL; + + return PyArray_Return((PyArrayObject *) + PyArray_TakeFrom(self, indices, dimension, out, mode)); +} + +static PyObject * +array_fill(PyArrayObject *self, PyObject *args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O:fill", &obj)) { + return NULL; + } + if (PyArray_FillWithScalar(self, obj) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +array_put(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *indices, *values; + NPY_CLIPMODE mode = NPY_RAISE; + static char *kwlist[] = {"indices", "values", "mode", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O&:put", kwlist, + &indices, + &values, + PyArray_ClipmodeConverter, &mode)) + return NULL; + return PyArray_PutTo(self, values, indices, mode); +} + +static PyObject * +array_reshape(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + static char *keywords[] = {"order", NULL}; + PyArray_Dims newshape; + PyObject *ret; + NPY_ORDER order = NPY_CORDER; + Py_ssize_t n = PyTuple_Size(args); + + if (!NpyArg_ParseKeywords(kwds, "|O&", keywords, + PyArray_OrderConverter, &order)) { + return NULL; + } + + if (n <= 1) { + if (PyTuple_GET_ITEM(args, 0) == Py_None) { + return PyArray_View(self, NULL, NULL); + } + if (!PyArg_ParseTuple(args, "O&:reshape", PyArray_IntpConverter, + &newshape)) { + return NULL; + } + } + else { + if (!PyArray_IntpConverter(args, &newshape)) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "invalid shape"); + } + goto fail; + } + } + ret = PyArray_Newshape(self, &newshape, order); + npy_free_cache_dim_obj(newshape); + return ret; + + fail: + npy_free_cache_dim_obj(newshape); + return NULL; +} + +static PyObject * +array_squeeze(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *axis_in = NULL; + npy_bool axis_flags[NPY_MAXDIMS]; + + static char *kwlist[] = {"axis", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:squeeze", kwlist, + &axis_in)) { + return NULL; + } + + if (axis_in == NULL || axis_in == Py_None) { + return PyArray_Squeeze(self); + } + else { + if (PyArray_ConvertMultiAxis(axis_in, PyArray_NDIM(self), + axis_flags) != NPY_SUCCEED) { + return NULL; + } + + return PyArray_SqueezeSelected(self, axis_flags); + } +} + +static PyObject * +array_view(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *out_dtype = NULL; + PyObject *out_type = NULL; + PyArray_Descr *dtype = NULL; + + static char *kwlist[] = {"dtype", "type", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:view", kwlist, + &out_dtype, + &out_type)) { + return NULL; + } + + /* If user specified a positional argument, guess whether it + represents a type or a dtype for backward compatibility. */ + if (out_dtype) { + /* type specified? */ + if (PyType_Check(out_dtype) && + PyType_IsSubtype((PyTypeObject *)out_dtype, + &PyArray_Type)) { + if (out_type) { + PyErr_SetString(PyExc_ValueError, + "Cannot specify output type twice."); + return NULL; + } + out_type = out_dtype; + out_dtype = NULL; + } + } + + if ((out_type) && (!PyType_Check(out_type) || + !PyType_IsSubtype((PyTypeObject *)out_type, + &PyArray_Type))) { + PyErr_SetString(PyExc_ValueError, + "Type must be a sub-type of ndarray type"); + return NULL; + } + + if ((out_dtype) && + (PyArray_DescrConverter(out_dtype, &dtype) == NPY_FAIL)) { + return NULL; + } + + return PyArray_View(self, dtype, (PyTypeObject*)out_type); +} + +static PyObject * +array_argmax(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis = NPY_MAXDIMS; + PyArrayObject *out = NULL; + static char *kwlist[] = {"axis", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&:argmax", kwlist, + PyArray_AxisConverter, &axis, + PyArray_OutputConverter, &out)) + return NULL; + + return PyArray_Return((PyArrayObject *)PyArray_ArgMax(self, axis, out)); +} + +static PyObject * +array_argmin(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis = NPY_MAXDIMS; + PyArrayObject *out = NULL; + static char *kwlist[] = {"axis", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&:argmin", kwlist, + PyArray_AxisConverter, &axis, + PyArray_OutputConverter, &out)) + return NULL; + + return PyArray_Return((PyArrayObject *)PyArray_ArgMin(self, axis, out)); +} + +static PyObject * +array_max(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_amax"); +} + +static PyObject * +array_min(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_amin"); +} + +static PyObject * +array_ptp(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis = NPY_MAXDIMS; + PyArrayObject *out = NULL; + static char *kwlist[] = {"axis", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&:ptp", kwlist, + PyArray_AxisConverter, &axis, + PyArray_OutputConverter, &out)) + return NULL; + + return PyArray_Ptp(self, axis, out); +} + + +static PyObject * +array_swapaxes(PyArrayObject *self, PyObject *args) +{ + int axis1, axis2; + + if (!PyArg_ParseTuple(args, "ii:swapaxes", &axis1, &axis2)) { + return NULL; + } + return PyArray_SwapAxes(self, axis1, axis2); +} + + +/*NUMPY_API + Get a subset of bytes from each element of the array + steals reference to typed, must not be NULL +*/ +NPY_NO_EXPORT PyObject * +PyArray_GetField(PyArrayObject *self, PyArray_Descr *typed, int offset) +{ + PyObject *ret = NULL; + PyObject *safe; + static PyObject *checkfunc = NULL; + + /* check that we are not reinterpreting memory containing Objects. */ + if (_may_have_objects(PyArray_DESCR(self)) || _may_have_objects(typed)) { + npy_cache_import("numpy.core._internal", "_getfield_is_safe", + &checkfunc); + if (checkfunc == NULL) { + return NULL; + } + + /* only returns True or raises */ + safe = PyObject_CallFunction(checkfunc, "OOi", PyArray_DESCR(self), + typed, offset); + if (safe == NULL) { + return NULL; + } + Py_DECREF(safe); + } + + ret = PyArray_NewFromDescr_int(Py_TYPE(self), + typed, + PyArray_NDIM(self), PyArray_DIMS(self), + PyArray_STRIDES(self), + PyArray_BYTES(self) + offset, + PyArray_FLAGS(self)&(~NPY_ARRAY_F_CONTIGUOUS), + (PyObject *)self, 0, 1); + if (ret == NULL) { + return NULL; + } + Py_INCREF(self); + if (PyArray_SetBaseObject(((PyArrayObject *)ret), (PyObject *)self) < 0) { + Py_DECREF(ret); + return NULL; + } + + PyArray_UpdateFlags((PyArrayObject *)ret, NPY_ARRAY_UPDATE_ALL); + return ret; +} + +static PyObject * +array_getfield(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + + PyArray_Descr *dtype = NULL; + int offset = 0; + static char *kwlist[] = {"dtype", "offset", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i:getfield", kwlist, + PyArray_DescrConverter, &dtype, + &offset)) { + Py_XDECREF(dtype); + return NULL; + } + + return PyArray_GetField(self, dtype, offset); +} + + +/*NUMPY_API + Set a subset of bytes from each element of the array + steals reference to dtype, must not be NULL +*/ +NPY_NO_EXPORT int +PyArray_SetField(PyArrayObject *self, PyArray_Descr *dtype, + int offset, PyObject *val) +{ + PyObject *ret = NULL; + int retval = 0; + + if (PyArray_FailUnlessWriteable(self, "assignment destination") < 0) { + return -1; + } + + /* getfield returns a view we can write to */ + ret = PyArray_GetField(self, dtype, offset); + if (ret == NULL) { + return -1; + } + + retval = PyArray_CopyObject((PyArrayObject *)ret, val); + Py_DECREF(ret); + return retval; +} + +static PyObject * +array_setfield(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + PyArray_Descr *dtype = NULL; + int offset = 0; + PyObject *value; + static char *kwlist[] = {"value", "dtype", "offset", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|i:setfield", kwlist, + &value, + PyArray_DescrConverter, &dtype, + &offset)) { + Py_XDECREF(dtype); + return NULL; + } + + if (PyArray_SetField(self, dtype, offset, value) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +/* This doesn't change the descriptor just the actual data... + */ + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_Byteswap(PyArrayObject *self, npy_bool inplace) +{ + PyArrayObject *ret; + npy_intp size; + PyArray_CopySwapNFunc *copyswapn; + PyArrayIterObject *it; + + copyswapn = PyArray_DESCR(self)->f->copyswapn; + if (inplace) { + if (PyArray_FailUnlessWriteable(self, "array to be byte-swapped") < 0) { + return NULL; + } + size = PyArray_SIZE(self); + if (PyArray_ISONESEGMENT(self)) { + copyswapn(PyArray_DATA(self), PyArray_DESCR(self)->elsize, NULL, -1, size, 1, self); + } + else { /* Use iterator */ + int axis = -1; + npy_intp stride; + it = (PyArrayIterObject *) \ + PyArray_IterAllButAxis((PyObject *)self, &axis); + stride = PyArray_STRIDES(self)[axis]; + size = PyArray_DIMS(self)[axis]; + while (it->index < it->size) { + copyswapn(it->dataptr, stride, NULL, -1, size, 1, self); + PyArray_ITER_NEXT(it); + } + Py_DECREF(it); + } + + Py_INCREF(self); + return (PyObject *)self; + } + else { + PyObject *new; + if ((ret = (PyArrayObject *)PyArray_NewCopy(self,-1)) == NULL) { + return NULL; + } + new = PyArray_Byteswap(ret, NPY_TRUE); + Py_DECREF(new); + return (PyObject *)ret; + } +} + + +static PyObject * +array_byteswap(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + npy_bool inplace = NPY_FALSE; + static char *kwlist[] = {"inplace", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:byteswap", kwlist, + PyArray_BoolConverter, &inplace)) { + return NULL; + } + return PyArray_Byteswap(self, inplace); +} + +static PyObject * +array_tolist(PyArrayObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + return PyArray_ToList(self); +} + + +static PyObject * +array_tobytes(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_ORDER order = NPY_CORDER; + static char *kwlist[] = {"order", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:tobytes", kwlist, + PyArray_OrderConverter, &order)) { + return NULL; + } + return PyArray_ToString(self, order); +} + + +/* This should grow an order= keyword to be consistent + */ + +static PyObject * +array_tofile(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int own; + PyObject *file; + FILE *fd; + char *sep = ""; + char *format = ""; + npy_off_t orig_pos = 0; + static char *kwlist[] = {"file", "sep", "format", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ss:tofile", kwlist, + &file, + &sep, + &format)) { + return NULL; + } + + if (PyBytes_Check(file) || PyUnicode_Check(file)) { + file = npy_PyFile_OpenFile(file, "wb"); + if (file == NULL) { + return NULL; + } + own = 1; + } + else { + Py_INCREF(file); + own = 0; + } + + fd = npy_PyFile_Dup2(file, "wb", &orig_pos); + if (fd == NULL) { + goto fail; + } + if (PyArray_ToFile(self, fd, sep, format) < 0) { + goto fail; + } + if (npy_PyFile_DupClose2(file, fd, orig_pos) < 0) { + goto fail; + } + if (own && npy_PyFile_CloseFile(file) < 0) { + goto fail; + } + Py_DECREF(file); + Py_RETURN_NONE; + +fail: + Py_DECREF(file); + return NULL; +} + +static PyObject * +array_toscalar(PyArrayObject *self, PyObject *args) +{ + npy_intp multi_index[NPY_MAXDIMS]; + int n = PyTuple_GET_SIZE(args); + int idim, ndim = PyArray_NDIM(self); + + /* If there is a tuple as a single argument, treat it as the argument */ + if (n == 1 && PyTuple_Check(PyTuple_GET_ITEM(args, 0))) { + args = PyTuple_GET_ITEM(args, 0); + n = PyTuple_GET_SIZE(args); + } + + if (n == 0) { + if (PyArray_SIZE(self) == 1) { + for (idim = 0; idim < ndim; ++idim) { + multi_index[idim] = 0; + } + } + else { + PyErr_SetString(PyExc_ValueError, + "can only convert an array of size 1 to a Python scalar"); + return NULL; + } + } + /* Special case of C-order flat indexing... :| */ + else if (n == 1 && ndim != 1) { + npy_intp *shape = PyArray_SHAPE(self); + npy_intp value, size = PyArray_SIZE(self); + + value = PyArray_PyIntAsIntp(PyTuple_GET_ITEM(args, 0)); + if (error_converting(value)) { + return NULL; + } + + if (check_and_adjust_index(&value, size, -1, NULL) < 0) { + return NULL; + } + + /* Convert the flat index into a multi-index */ + for (idim = ndim-1; idim >= 0; --idim) { + multi_index[idim] = value % shape[idim]; + value /= shape[idim]; + } + } + /* A multi-index tuple */ + else if (n == ndim) { + npy_intp value; + + for (idim = 0; idim < ndim; ++idim) { + value = PyArray_PyIntAsIntp(PyTuple_GET_ITEM(args, idim)); + if (error_converting(value)) { + return NULL; + } + multi_index[idim] = value; + } + } + else { + PyErr_SetString(PyExc_ValueError, + "incorrect number of indices for array"); + return NULL; + } + + return PyArray_MultiIndexGetItem(self, multi_index); +} + +static PyObject * +array_setscalar(PyArrayObject *self, PyObject *args) +{ + npy_intp multi_index[NPY_MAXDIMS]; + int n = PyTuple_GET_SIZE(args) - 1; + int idim, ndim = PyArray_NDIM(self); + PyObject *obj; + + if (n < 0) { + PyErr_SetString(PyExc_ValueError, + "itemset must have at least one argument"); + return NULL; + } + if (PyArray_FailUnlessWriteable(self, "assignment destination") < 0) { + return NULL; + } + + obj = PyTuple_GET_ITEM(args, n); + + /* If there is a tuple as a single argument, treat it as the argument */ + if (n == 1 && PyTuple_Check(PyTuple_GET_ITEM(args, 0))) { + args = PyTuple_GET_ITEM(args, 0); + n = PyTuple_GET_SIZE(args); + } + + if (n == 0) { + if (PyArray_SIZE(self) == 1) { + for (idim = 0; idim < ndim; ++idim) { + multi_index[idim] = 0; + } + } + else { + PyErr_SetString(PyExc_ValueError, + "can only convert an array of size 1 to a Python scalar"); + } + } + /* Special case of C-order flat indexing... :| */ + else if (n == 1 && ndim != 1) { + npy_intp *shape = PyArray_SHAPE(self); + npy_intp value, size = PyArray_SIZE(self); + + value = PyArray_PyIntAsIntp(PyTuple_GET_ITEM(args, 0)); + if (error_converting(value)) { + return NULL; + } + + if (check_and_adjust_index(&value, size, -1, NULL) < 0) { + return NULL; + } + + /* Convert the flat index into a multi-index */ + for (idim = ndim-1; idim >= 0; --idim) { + multi_index[idim] = value % shape[idim]; + value /= shape[idim]; + } + } + /* A multi-index tuple */ + else if (n == ndim) { + npy_intp value; + + for (idim = 0; idim < ndim; ++idim) { + value = PyArray_PyIntAsIntp(PyTuple_GET_ITEM(args, idim)); + if (error_converting(value)) { + return NULL; + } + multi_index[idim] = value; + } + } + else { + PyErr_SetString(PyExc_ValueError, + "incorrect number of indices for array"); + return NULL; + } + + if (PyArray_MultiIndexSetItem(self, multi_index, obj) < 0) { + return NULL; + } + else { + Py_RETURN_NONE; + } +} + +NPY_NO_EXPORT const char * +npy_casting_to_string(NPY_CASTING casting) +{ + switch (casting) { + case NPY_NO_CASTING: + return "'no'"; + case NPY_EQUIV_CASTING: + return "'equiv'"; + case NPY_SAFE_CASTING: + return "'safe'"; + case NPY_SAME_KIND_CASTING: + return "'same_kind'"; + case NPY_UNSAFE_CASTING: + return "'unsafe'"; + default: + return ""; + } +} + +static PyObject * +array_astype(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"dtype", "order", "casting", + "subok", "copy", NULL}; + PyArray_Descr *dtype = NULL; + /* + * TODO: UNSAFE default for compatibility, I think + * switching to SAME_KIND by default would be good. + */ + NPY_CASTING casting = NPY_UNSAFE_CASTING; + NPY_ORDER order = NPY_KEEPORDER; + int forcecopy = 1, subok = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&ii:astype", kwlist, + PyArray_DescrConverter, &dtype, + PyArray_OrderConverter, &order, + PyArray_CastingConverter, &casting, + &subok, + &forcecopy)) { + Py_XDECREF(dtype); + return NULL; + } + + /* + * If the memory layout matches and, data types are equivalent, + * and it's not a subtype if subok is False, then we + * can skip the copy. + */ + if (!forcecopy && (order == NPY_KEEPORDER || + (order == NPY_ANYORDER && + (PyArray_IS_C_CONTIGUOUS(self) || + PyArray_IS_F_CONTIGUOUS(self))) || + (order == NPY_CORDER && + PyArray_IS_C_CONTIGUOUS(self)) || + (order == NPY_FORTRANORDER && + PyArray_IS_F_CONTIGUOUS(self))) && + (subok || PyArray_CheckExact(self)) && + PyArray_EquivTypes(dtype, PyArray_DESCR(self))) { + Py_DECREF(dtype); + Py_INCREF(self); + return (PyObject *)self; + } + else if (PyArray_CanCastArrayTo(self, dtype, casting)) { + PyArrayObject *ret; + + /* If the requested dtype is flexible, adapt it */ + PyArray_AdaptFlexibleDType((PyObject *)self, PyArray_DESCR(self), + &dtype); + if (dtype == NULL) { + return NULL; + } + + /* This steals the reference to dtype, so no DECREF of dtype */ + ret = (PyArrayObject *)PyArray_NewLikeArray( + self, order, dtype, subok); + if (ret == NULL) { + return NULL; + } + + if (PyArray_CopyInto(ret, self) < 0) { + Py_DECREF(ret); + return NULL; + } + + return (PyObject *)ret; + } + else { + PyObject *errmsg; + errmsg = PyUString_FromString("Cannot cast array from "); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(self))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)dtype)); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" according to the rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + Py_DECREF(dtype); + return NULL; + } +} + +/* default sub-type implementation */ + + +static PyObject * +array_wraparray(PyArrayObject *self, PyObject *args) +{ + PyArrayObject *arr, *ret; + PyObject *obj; + + if (PyTuple_Size(args) < 1) { + PyErr_SetString(PyExc_TypeError, + "only accepts 1 argument"); + return NULL; + } + obj = PyTuple_GET_ITEM(args, 0); + if (obj == NULL) { + return NULL; + } + if (!PyArray_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "can only be called with ndarray object"); + return NULL; + } + arr = (PyArrayObject *)obj; + + if (Py_TYPE(self) != Py_TYPE(arr)){ + PyArray_Descr *dtype = PyArray_DESCR(arr); + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self), + dtype, + PyArray_NDIM(arr), + PyArray_DIMS(arr), + PyArray_STRIDES(arr), PyArray_DATA(arr), + PyArray_FLAGS(arr), (PyObject *)self); + if (ret == NULL) { + return NULL; + } + Py_INCREF(obj); + if (PyArray_SetBaseObject(ret, obj) < 0) { + Py_DECREF(ret); + return NULL; + } + return (PyObject *)ret; + } else { + /*The type was set in __array_prepare__*/ + Py_INCREF(arr); + return (PyObject *)arr; + } +} + + +static PyObject * +array_preparearray(PyArrayObject *self, PyObject *args) +{ + PyObject *obj; + PyArrayObject *arr, *ret; + PyArray_Descr *dtype; + + if (PyTuple_Size(args) < 1) { + PyErr_SetString(PyExc_TypeError, + "only accepts 1 argument"); + return NULL; + } + obj = PyTuple_GET_ITEM(args, 0); + if (!PyArray_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "can only be called with ndarray object"); + return NULL; + } + arr = (PyArrayObject *)obj; + + if (Py_TYPE(self) == Py_TYPE(arr)) { + /* No need to create a new view */ + Py_INCREF(arr); + return (PyObject *)arr; + } + + dtype = PyArray_DESCR(arr); + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self), + dtype, + PyArray_NDIM(arr), + PyArray_DIMS(arr), + PyArray_STRIDES(arr), PyArray_DATA(arr), + PyArray_FLAGS(arr), (PyObject *)self); + if (ret == NULL) { + return NULL; + } + Py_INCREF(arr); + if (PyArray_SetBaseObject(ret, (PyObject *)arr) < 0) { + Py_DECREF(ret); + return NULL; + } + return (PyObject *)ret; +} + + +static PyObject * +array_getarray(PyArrayObject *self, PyObject *args) +{ + PyArray_Descr *newtype = NULL; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "|O&:__array__", + PyArray_DescrConverter, &newtype)) { + Py_XDECREF(newtype); + return NULL; + } + + /* convert to PyArray_Type */ + if (!PyArray_CheckExact(self)) { + PyArrayObject *new; + + Py_INCREF(PyArray_DESCR(self)); + new = (PyArrayObject *)PyArray_NewFromDescr( + &PyArray_Type, + PyArray_DESCR(self), + PyArray_NDIM(self), + PyArray_DIMS(self), + PyArray_STRIDES(self), + PyArray_DATA(self), + PyArray_FLAGS(self), + NULL + ); + if (new == NULL) { + return NULL; + } + Py_INCREF(self); + PyArray_SetBaseObject(new, (PyObject *)self); + self = new; + } + else { + Py_INCREF(self); + } + + if ((newtype == NULL) || PyArray_EquivTypes(PyArray_DESCR(self), newtype)) { + return (PyObject *)self; + } + else { + ret = PyArray_CastToType(self, newtype, 0); + Py_DECREF(self); + return ret; + } +} + + +static PyObject * +array_ufunc(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *ufunc, *method_name, *normal_args, *ufunc_method; + PyObject *result = NULL; + int num_override_args; + + if (PyTuple_Size(args) < 2) { + PyErr_SetString(PyExc_TypeError, + "__array_ufunc__ requires at least 2 arguments"); + return NULL; + } + normal_args = PyTuple_GetSlice(args, 2, PyTuple_GET_SIZE(args)); + if (normal_args == NULL) { + return NULL; + } + /* ndarray cannot handle overrides itself */ + num_override_args = PyUFunc_WithOverride(normal_args, kwds, NULL, NULL); + if (num_override_args == -1) { + return NULL; + } + if (num_override_args) { + result = Py_NotImplemented; + Py_INCREF(Py_NotImplemented); + goto cleanup; + } + + ufunc = PyTuple_GET_ITEM(args, 0); + method_name = PyTuple_GET_ITEM(args, 1); + /* + * TODO(?): call into UFunc code at a later point, since here arguments are + * already normalized and we do not have to look for __array_ufunc__ again. + */ + ufunc_method = PyObject_GetAttr(ufunc, method_name); + if (ufunc_method == NULL) { + goto cleanup; + } + result = PyObject_Call(ufunc_method, normal_args, kwds); + Py_DECREF(ufunc_method); + +cleanup: + Py_DECREF(normal_args); + /* no need to DECREF borrowed references ufunc and method_name */ + return result; +} + + +static PyObject * +array_copy(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_ORDER order = NPY_CORDER; + static char *kwlist[] = {"order", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:copy", kwlist, + PyArray_OrderConverter, &order)) { + return NULL; + } + + return PyArray_NewCopy(self, order); +} + +/* Separate from array_copy to make __copy__ preserve Fortran contiguity. */ +static PyObject * +array_copy_keeporder(PyArrayObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":__copy__")) { + return NULL; + } + return PyArray_NewCopy(self, NPY_KEEPORDER); +} + +#include +static PyObject * +array_resize(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"refcheck", NULL}; + Py_ssize_t size = PyTuple_Size(args); + int refcheck = 1; + PyArray_Dims newshape; + PyObject *ret, *obj; + + + if (!NpyArg_ParseKeywords(kwds, "|i", kwlist, &refcheck)) { + return NULL; + } + + if (size == 0) { + Py_RETURN_NONE; + } + else if (size == 1) { + obj = PyTuple_GET_ITEM(args, 0); + if (obj == Py_None) { + Py_RETURN_NONE; + } + args = obj; + } + if (!PyArray_IntpConverter(args, &newshape)) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "invalid shape"); + } + return NULL; + } + + ret = PyArray_Resize(self, &newshape, refcheck, NPY_CORDER); + npy_free_cache_dim_obj(newshape); + if (ret == NULL) { + return NULL; + } + Py_DECREF(ret); + Py_RETURN_NONE; +} + +static PyObject * +array_repeat(PyArrayObject *self, PyObject *args, PyObject *kwds) { + PyObject *repeats; + int axis = NPY_MAXDIMS; + static char *kwlist[] = {"repeats", "axis", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&:repeat", kwlist, + &repeats, + PyArray_AxisConverter, &axis)) { + return NULL; + } + return PyArray_Return((PyArrayObject *)PyArray_Repeat(self, repeats, axis)); +} + +static PyObject * +array_choose(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + static char *keywords[] = {"out", "mode", NULL}; + PyObject *choices; + PyArrayObject *out = NULL; + NPY_CLIPMODE clipmode = NPY_RAISE; + Py_ssize_t n = PyTuple_Size(args); + + if (n <= 1) { + if (!PyArg_ParseTuple(args, "O:choose", &choices)) { + return NULL; + } + } + else { + choices = args; + } + + if (!NpyArg_ParseKeywords(kwds, "|O&O&", keywords, + PyArray_OutputConverter, &out, + PyArray_ClipmodeConverter, &clipmode)) { + return NULL; + } + + return PyArray_Return((PyArrayObject *)PyArray_Choose(self, choices, out, clipmode)); +} + +static PyObject * +array_sort(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis=-1; + int val; + NPY_SORTKIND sortkind = NPY_QUICKSORT; + PyObject *order = NULL; + PyArray_Descr *saved = NULL; + PyArray_Descr *newd; + static char *kwlist[] = {"axis", "kind", "order", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO&O:sort", kwlist, + &axis, + PyArray_SortkindConverter, &sortkind, + &order)) { + return NULL; + } + if (order == Py_None) { + order = NULL; + } + if (order != NULL) { + PyObject *new_name; + PyObject *_numpy_internal; + saved = PyArray_DESCR(self); + if (!PyDataType_HASFIELDS(saved)) { + PyErr_SetString(PyExc_ValueError, "Cannot specify " \ + "order when the array has no fields."); + return NULL; + } + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + new_name = PyObject_CallMethod(_numpy_internal, "_newnames", + "OO", saved, order); + Py_DECREF(_numpy_internal); + if (new_name == NULL) { + return NULL; + } + newd = PyArray_DescrNew(saved); + Py_DECREF(newd->names); + newd->names = new_name; + ((PyArrayObject_fields *)self)->descr = newd; + } + + val = PyArray_Sort(self, axis, sortkind); + if (order != NULL) { + Py_XDECREF(PyArray_DESCR(self)); + ((PyArrayObject_fields *)self)->descr = saved; + } + if (val < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +array_partition(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis=-1; + int val; + NPY_SELECTKIND sortkind = NPY_INTROSELECT; + PyObject *order = NULL; + PyArray_Descr *saved = NULL; + PyArray_Descr *newd; + static char *kwlist[] = {"kth", "axis", "kind", "order", NULL}; + PyArrayObject * ktharray; + PyObject * kthobj; + + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO&O:partition", kwlist, + &kthobj, + &axis, + PyArray_SelectkindConverter, &sortkind, + &order)) { + return NULL; + } + + if (order == Py_None) { + order = NULL; + } + if (order != NULL) { + PyObject *new_name; + PyObject *_numpy_internal; + saved = PyArray_DESCR(self); + if (!PyDataType_HASFIELDS(saved)) { + PyErr_SetString(PyExc_ValueError, "Cannot specify " \ + "order when the array has no fields."); + return NULL; + } + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + new_name = PyObject_CallMethod(_numpy_internal, "_newnames", + "OO", saved, order); + Py_DECREF(_numpy_internal); + if (new_name == NULL) { + return NULL; + } + newd = PyArray_DescrNew(saved); + Py_DECREF(newd->names); + newd->names = new_name; + ((PyArrayObject_fields *)self)->descr = newd; + } + + ktharray = (PyArrayObject *)PyArray_FromAny(kthobj, NULL, 0, 1, + NPY_ARRAY_DEFAULT, NULL); + if (ktharray == NULL) + return NULL; + + val = PyArray_Partition(self, ktharray, axis, sortkind); + Py_DECREF(ktharray); + + if (order != NULL) { + Py_XDECREF(PyArray_DESCR(self)); + ((PyArrayObject_fields *)self)->descr = saved; + } + if (val < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +array_argsort(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis = -1; + NPY_SORTKIND sortkind = NPY_QUICKSORT; + PyObject *order = NULL, *res; + PyArray_Descr *newd, *saved=NULL; + static char *kwlist[] = {"axis", "kind", "order", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&O:argsort", kwlist, + PyArray_AxisConverter, &axis, + PyArray_SortkindConverter, &sortkind, + &order)) { + return NULL; + } + if (order == Py_None) { + order = NULL; + } + if (order != NULL) { + PyObject *new_name; + PyObject *_numpy_internal; + saved = PyArray_DESCR(self); + if (!PyDataType_HASFIELDS(saved)) { + PyErr_SetString(PyExc_ValueError, "Cannot specify " + "order when the array has no fields."); + return NULL; + } + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + new_name = PyObject_CallMethod(_numpy_internal, "_newnames", + "OO", saved, order); + Py_DECREF(_numpy_internal); + if (new_name == NULL) { + return NULL; + } + newd = PyArray_DescrNew(saved); + newd->names = new_name; + ((PyArrayObject_fields *)self)->descr = newd; + } + + res = PyArray_ArgSort(self, axis, sortkind); + if (order != NULL) { + Py_XDECREF(PyArray_DESCR(self)); + ((PyArrayObject_fields *)self)->descr = saved; + } + return PyArray_Return((PyArrayObject *)res); +} + + +static PyObject * +array_argpartition(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis = -1; + NPY_SELECTKIND sortkind = NPY_INTROSELECT; + PyObject *order = NULL, *res; + PyArray_Descr *newd, *saved=NULL; + static char *kwlist[] = {"kth", "axis", "kind", "order", NULL}; + PyObject * kthobj; + PyArrayObject * ktharray; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O&O:argpartition", kwlist, + &kthobj, + PyArray_AxisConverter, &axis, + PyArray_SelectkindConverter, &sortkind, + &order)) { + return NULL; + } + if (order == Py_None) { + order = NULL; + } + if (order != NULL) { + PyObject *new_name; + PyObject *_numpy_internal; + saved = PyArray_DESCR(self); + if (!PyDataType_HASFIELDS(saved)) { + PyErr_SetString(PyExc_ValueError, "Cannot specify " + "order when the array has no fields."); + return NULL; + } + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + new_name = PyObject_CallMethod(_numpy_internal, "_newnames", + "OO", saved, order); + Py_DECREF(_numpy_internal); + if (new_name == NULL) { + return NULL; + } + newd = PyArray_DescrNew(saved); + newd->names = new_name; + ((PyArrayObject_fields *)self)->descr = newd; + } + + ktharray = (PyArrayObject *)PyArray_FromAny(kthobj, NULL, 0, 1, + NPY_ARRAY_DEFAULT, NULL); + if (ktharray == NULL) + return NULL; + + res = PyArray_ArgPartition(self, ktharray, axis, sortkind); + Py_DECREF(ktharray); + + if (order != NULL) { + Py_XDECREF(PyArray_DESCR(self)); + ((PyArrayObject_fields *)self)->descr = saved; + } + return PyArray_Return((PyArrayObject *)res); +} + +static PyObject * +array_searchsorted(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"keys", "side", "sorter", NULL}; + PyObject *keys; + PyObject *sorter; + NPY_SEARCHSIDE side = NPY_SEARCHLEFT; + + sorter = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O:searchsorted", + kwlist, &keys, + PyArray_SearchsideConverter, &side, &sorter)) { + return NULL; + } + if (sorter == Py_None) { + sorter = NULL; + } + return PyArray_Return((PyArrayObject *)PyArray_SearchSorted(self, keys, side, sorter)); +} + +static void +_deepcopy_call(char *iptr, char *optr, PyArray_Descr *dtype, + PyObject *deepcopy, PyObject *visit) +{ + if (!PyDataType_REFCHK(dtype)) { + return; + } + else if (PyDataType_HASFIELDS(dtype)) { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; + while (PyDict_Next(dtype->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, + &title)) { + return; + } + _deepcopy_call(iptr + offset, optr + offset, new, + deepcopy, visit); + } + } + else { + PyObject *itemp, *otemp; + PyObject *res; + NPY_COPY_PYOBJECT_PTR(&itemp, iptr); + NPY_COPY_PYOBJECT_PTR(&otemp, optr); + Py_XINCREF(itemp); + /* call deepcopy on this argument */ + res = PyObject_CallFunctionObjArgs(deepcopy, itemp, visit, NULL); + Py_XDECREF(itemp); + Py_XDECREF(otemp); + NPY_COPY_PYOBJECT_PTR(optr, &res); + } + +} + + +static PyObject * +array_deepcopy(PyArrayObject *self, PyObject *args) +{ + PyArrayObject *copied_array; + PyObject *visit; + NpyIter *iter; + NpyIter_IterNextFunc *iternext; + char *data; + char **dataptr; + npy_intp *strideptr, *innersizeptr; + npy_intp stride, count; + PyObject *copy, *deepcopy; + + if (!PyArg_ParseTuple(args, "O:__deepcopy__", &visit)) { + return NULL; + } + copied_array = (PyArrayObject*) PyArray_NewCopy(self, NPY_KEEPORDER); + if (copied_array == NULL) { + return NULL; + } + if (PyDataType_REFCHK(PyArray_DESCR(self))) { + copy = PyImport_ImportModule("copy"); + if (copy == NULL) { + Py_DECREF(copied_array); + Py_DECREF(copy); + return NULL; + } + deepcopy = PyObject_GetAttrString(copy, "deepcopy"); + Py_DECREF(copy); + if (deepcopy == NULL) { + Py_DECREF(copied_array); + return NULL; + } + iter = NpyIter_New(copied_array, + NPY_ITER_READWRITE | + NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_REFS_OK | + NPY_ITER_ZEROSIZE_OK, + NPY_KEEPORDER, NPY_NO_CASTING, + NULL); + if (iter == NULL) { + Py_DECREF(deepcopy); + Py_DECREF(copied_array); + return NULL; + } + if (NpyIter_GetIterSize(iter) != 0) { + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + Py_DECREF(deepcopy); + Py_DECREF(copied_array); + return NULL; + } + + dataptr = NpyIter_GetDataPtrArray(iter); + strideptr = NpyIter_GetInnerStrideArray(iter); + innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + + do { + data = *dataptr; + stride = *strideptr; + count = *innersizeptr; + while (count--) { + _deepcopy_call(data, data, PyArray_DESCR(copied_array), + deepcopy, visit); + data += stride; + } + } while (iternext(iter)); + } + NpyIter_Deallocate(iter); + Py_DECREF(deepcopy); + } + return (PyObject*) copied_array; +} + +/* Convert Array to flat list (using getitem) */ +static PyObject * +_getlist_pkl(PyArrayObject *self) +{ + PyObject *theobject; + PyArrayIterObject *iter = NULL; + PyObject *list; + PyArray_GetItemFunc *getitem; + + getitem = PyArray_DESCR(self)->f->getitem; + iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self); + if (iter == NULL) { + return NULL; + } + list = PyList_New(iter->size); + if (list == NULL) { + Py_DECREF(iter); + return NULL; + } + while (iter->index < iter->size) { + theobject = getitem(iter->dataptr, self); + PyList_SET_ITEM(list, (int) iter->index, theobject); + PyArray_ITER_NEXT(iter); + } + Py_DECREF(iter); + return list; +} + +static int +_setlist_pkl(PyArrayObject *self, PyObject *list) +{ + PyObject *theobject; + PyArrayIterObject *iter = NULL; + PyArray_SetItemFunc *setitem; + + setitem = PyArray_DESCR(self)->f->setitem; + iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self); + if (iter == NULL) { + return -1; + } + while(iter->index < iter->size) { + theobject = PyList_GET_ITEM(list, (int) iter->index); + setitem(theobject, iter->dataptr, self); + PyArray_ITER_NEXT(iter); + } + Py_XDECREF(iter); + return 0; +} + + +static PyObject * +array_reduce(PyArrayObject *self, PyObject *NPY_UNUSED(args)) +{ + /* version number of this pickle type. Increment if we need to + change the format. Be sure to handle the old versions in + array_setstate. */ + const int version = 1; + PyObject *ret = NULL, *state = NULL, *obj = NULL, *mod = NULL; + PyObject *mybool, *thestr = NULL; + PyArray_Descr *descr; + + /* Return a tuple of (callable object, arguments, object's state) */ + /* We will put everything in the object's state, so that on UnPickle + it can use the string object as memory without a copy */ + + ret = PyTuple_New(3); + if (ret == NULL) { + return NULL; + } + mod = PyImport_ImportModule("numpy.core.multiarray"); + if (mod == NULL) { + Py_DECREF(ret); + return NULL; + } + obj = PyObject_GetAttrString(mod, "_reconstruct"); + Py_DECREF(mod); + PyTuple_SET_ITEM(ret, 0, obj); + PyTuple_SET_ITEM(ret, 1, + Py_BuildValue("ONc", + (PyObject *)Py_TYPE(self), + Py_BuildValue("(N)", + PyInt_FromLong(0)), + /* dummy data-type */ + 'b')); + + /* Now fill in object's state. This is a tuple with + 5 arguments + + 1) an integer with the pickle version. + 2) a Tuple giving the shape + 3) a PyArray_Descr Object (with correct bytorder set) + 4) a npy_bool stating if Fortran or not + 5) a Python object representing the data (a string, or + a list or any user-defined object). + + Notice because Python does not describe a mechanism to write + raw data to the pickle, this performs a copy to a string first + */ + + state = PyTuple_New(5); + if (state == NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(state, 0, PyInt_FromLong(version)); + PyTuple_SET_ITEM(state, 1, PyObject_GetAttrString((PyObject *)self, + "shape")); + descr = PyArray_DESCR(self); + Py_INCREF(descr); + PyTuple_SET_ITEM(state, 2, (PyObject *)descr); + mybool = (PyArray_ISFORTRAN(self) ? Py_True : Py_False); + Py_INCREF(mybool); + PyTuple_SET_ITEM(state, 3, mybool); + if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_LIST_PICKLE)) { + thestr = _getlist_pkl(self); + } + else { + thestr = PyArray_ToString(self, NPY_ANYORDER); + } + if (thestr == NULL) { + Py_DECREF(ret); + Py_DECREF(state); + return NULL; + } + PyTuple_SET_ITEM(state, 4, thestr); + PyTuple_SET_ITEM(ret, 2, state); + return ret; +} + +static PyObject * +array_setstate(PyArrayObject *self, PyObject *args) +{ + PyObject *shape; + PyArray_Descr *typecode; + int version = 1; + int is_f_order; + PyObject *rawdata = NULL; + char *datastr; + Py_ssize_t len; + npy_intp size, dimensions[NPY_MAXDIMS]; + int nd; + npy_intp nbytes; + int overflowed; + + PyArrayObject_fields *fa = (PyArrayObject_fields *)self; + + /* This will free any memory associated with a and + use the string in setstate as the (writeable) memory. + */ + if (!PyArg_ParseTuple(args, "(iO!O!iO):__setstate__", + &version, + &PyTuple_Type, &shape, + &PyArrayDescr_Type, &typecode, + &is_f_order, + &rawdata)) { + PyErr_Clear(); + version = 0; + if (!PyArg_ParseTuple(args, "(O!O!iO):__setstate__", + &PyTuple_Type, &shape, + &PyArrayDescr_Type, &typecode, + &is_f_order, + &rawdata)) { + return NULL; + } + } + + /* If we ever need another pickle format, increment the version + number. But we should still be able to handle the old versions. + We've only got one right now. */ + if (version != 1 && version != 0) { + PyErr_Format(PyExc_ValueError, + "can't handle version %d of numpy.ndarray pickle", + version); + return NULL; + } + + Py_XDECREF(PyArray_DESCR(self)); + fa->descr = typecode; + Py_INCREF(typecode); + nd = PyArray_IntpFromSequence(shape, dimensions, NPY_MAXDIMS); + if (nd < 0) { + return NULL; + } + size = PyArray_MultiplyList(dimensions, nd); + if (size < 0) { + /* More items than are addressable */ + return PyErr_NoMemory(); + } + overflowed = npy_mul_with_overflow_intp( + &nbytes, size, PyArray_DESCR(self)->elsize); + if (overflowed) { + /* More bytes than are addressable */ + return PyErr_NoMemory(); + } + + if (PyDataType_FLAGCHK(typecode, NPY_LIST_PICKLE)) { + if (!PyList_Check(rawdata)) { + PyErr_SetString(PyExc_TypeError, + "object pickle not returning list"); + return NULL; + } + } + else { + Py_INCREF(rawdata); + +#if defined(NPY_PY3K) + /* Backward compatibility with Python 2 NumPy pickles */ + if (PyUnicode_Check(rawdata)) { + PyObject *tmp; + tmp = PyUnicode_AsLatin1String(rawdata); + Py_DECREF(rawdata); + rawdata = tmp; + if (tmp == NULL) { + /* More informative error message */ + PyErr_SetString(PyExc_ValueError, + ("Failed to encode latin1 string when unpickling a Numpy array. " + "pickle.load(a, encoding='latin1') is assumed.")); + return NULL; + } + } +#endif + + if (!PyBytes_Check(rawdata)) { + PyErr_SetString(PyExc_TypeError, + "pickle not returning string"); + Py_DECREF(rawdata); + return NULL; + } + + if (PyBytes_AsStringAndSize(rawdata, &datastr, &len) < 0) { + Py_DECREF(rawdata); + return NULL; + } + + if (len != nbytes) { + PyErr_SetString(PyExc_ValueError, + "buffer size does not" \ + " match array size"); + Py_DECREF(rawdata); + return NULL; + } + } + + if ((PyArray_FLAGS(self) & NPY_ARRAY_OWNDATA)) { + PyDataMem_FREE(PyArray_DATA(self)); + PyArray_CLEARFLAGS(self, NPY_ARRAY_OWNDATA); + } + Py_XDECREF(PyArray_BASE(self)); + fa->base = NULL; + + PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY); + PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY); + + if (PyArray_DIMS(self) != NULL) { + npy_free_cache_dim_array(self); + fa->dimensions = NULL; + } + + fa->flags = NPY_ARRAY_DEFAULT; + + fa->nd = nd; + + if (nd > 0) { + fa->dimensions = npy_alloc_cache_dim(3*nd); + if (fa->dimensions == NULL) { + return PyErr_NoMemory(); + } + fa->strides = PyArray_DIMS(self) + nd; + memcpy(PyArray_DIMS(self), dimensions, sizeof(npy_intp)*nd); + _array_fill_strides(PyArray_STRIDES(self), dimensions, nd, + PyArray_DESCR(self)->elsize, + (is_f_order ? NPY_ARRAY_F_CONTIGUOUS : + NPY_ARRAY_C_CONTIGUOUS), + &(fa->flags)); + } + + if (!PyDataType_FLAGCHK(typecode, NPY_LIST_PICKLE)) { + int swap = PyArray_ISBYTESWAPPED(self); + fa->data = datastr; +#ifndef NPY_PY3K + /* Check that the string is not interned */ + if (!_IsAligned(self) || swap || PyString_CHECK_INTERNED(rawdata)) { +#else + /* Bytes should always be considered immutable, but we just grab the + * pointer if they are large, to save memory. */ + if (!_IsAligned(self) || swap || (len <= 1000)) { +#endif + npy_intp num = PyArray_NBYTES(self); + fa->data = PyDataMem_NEW(num); + if (PyArray_DATA(self) == NULL) { + fa->nd = 0; + npy_free_cache_dim_array(self); + Py_DECREF(rawdata); + return PyErr_NoMemory(); + } + if (swap) { + /* byte-swap on pickle-read */ + npy_intp numels = PyArray_SIZE(self); + PyArray_DESCR(self)->f->copyswapn(PyArray_DATA(self), + PyArray_DESCR(self)->elsize, + datastr, PyArray_DESCR(self)->elsize, + numels, 1, self); + if (!PyArray_ISEXTENDED(self)) { + fa->descr = PyArray_DescrFromType( + PyArray_DESCR(self)->type_num); + } + else { + fa->descr = PyArray_DescrNew(typecode); + if (PyArray_DESCR(self)->byteorder == NPY_BIG) { + PyArray_DESCR(self)->byteorder = NPY_LITTLE; + } + else if (PyArray_DESCR(self)->byteorder == NPY_LITTLE) { + PyArray_DESCR(self)->byteorder = NPY_BIG; + } + } + Py_DECREF(typecode); + } + else { + memcpy(PyArray_DATA(self), datastr, num); + } + PyArray_ENABLEFLAGS(self, NPY_ARRAY_OWNDATA); + fa->base = NULL; + Py_DECREF(rawdata); + } + else { + if (PyArray_SetBaseObject(self, rawdata) < 0) { + return NULL; + } + } + } + else { + fa->data = PyDataMem_NEW(PyArray_NBYTES(self)); + if (PyArray_DATA(self) == NULL) { + fa->nd = 0; + fa->data = PyDataMem_NEW(PyArray_DESCR(self)->elsize); + npy_free_cache_dim_array(self); + return PyErr_NoMemory(); + } + if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_NEEDS_INIT)) { + memset(PyArray_DATA(self), 0, PyArray_NBYTES(self)); + } + PyArray_ENABLEFLAGS(self, NPY_ARRAY_OWNDATA); + fa->base = NULL; + if (_setlist_pkl(self, rawdata) < 0) { + return NULL; + } + } + + PyArray_UpdateFlags(self, NPY_ARRAY_UPDATE_ALL); + + Py_RETURN_NONE; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT int +PyArray_Dump(PyObject *self, PyObject *file, int protocol) +{ + PyObject *cpick = NULL; + PyObject *ret; + if (protocol < 0) { + protocol = 2; + } + +#if defined(NPY_PY3K) + cpick = PyImport_ImportModule("pickle"); +#else + cpick = PyImport_ImportModule("cPickle"); +#endif + if (cpick == NULL) { + return -1; + } + if (PyBytes_Check(file) || PyUnicode_Check(file)) { + file = npy_PyFile_OpenFile(file, "wb"); + if (file == NULL) { + Py_DECREF(cpick); + return -1; + } + } + else { + Py_INCREF(file); + } + ret = PyObject_CallMethod(cpick, "dump", "OOi", self, file, protocol); + Py_XDECREF(ret); + Py_DECREF(file); + Py_DECREF(cpick); + if (PyErr_Occurred()) { + return -1; + } + return 0; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_Dumps(PyObject *self, int protocol) +{ + PyObject *cpick = NULL; + PyObject *ret; + if (protocol < 0) { + protocol = 2; + } +#if defined(NPY_PY3K) + cpick = PyImport_ImportModule("pickle"); +#else + cpick = PyImport_ImportModule("cPickle"); +#endif + if (cpick == NULL) { + return NULL; + } + ret = PyObject_CallMethod(cpick, "dumps", "Oi", self, protocol); + Py_DECREF(cpick); + return ret; +} + + +static PyObject * +array_dump(PyArrayObject *self, PyObject *args) +{ + PyObject *file = NULL; + int ret; + + if (!PyArg_ParseTuple(args, "O:dump", &file)) { + return NULL; + } + ret = PyArray_Dump((PyObject *)self, file, 2); + if (ret < 0) { + return NULL; + } + Py_RETURN_NONE; +} + + +static PyObject * +array_dumps(PyArrayObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + return PyArray_Dumps((PyObject *)self, 2); +} + + +static PyObject * +array_sizeof(PyArrayObject *self) +{ + /* object + dimension and strides */ + Py_ssize_t nbytes = NPY_SIZEOF_PYARRAYOBJECT + + PyArray_NDIM(self) * sizeof(npy_intp) * 2; + if (PyArray_CHKFLAGS(self, NPY_ARRAY_OWNDATA)) { + nbytes += PyArray_NBYTES(self); + } + return PyLong_FromSsize_t(nbytes); +} + + +static PyObject * +array_transpose(PyArrayObject *self, PyObject *args) +{ + PyObject *shape = Py_None; + Py_ssize_t n = PyTuple_Size(args); + PyArray_Dims permute; + PyObject *ret; + + if (n > 1) { + shape = args; + } + else if (n == 1) { + shape = PyTuple_GET_ITEM(args, 0); + } + + if (shape == Py_None) { + ret = PyArray_Transpose(self, NULL); + } + else { + if (!PyArray_IntpConverter(shape, &permute)) { + return NULL; + } + ret = PyArray_Transpose(self, &permute); + npy_free_cache_dim_obj(permute); + } + + return ret; +} + +#define _CHKTYPENUM(typ) ((typ) ? (typ)->type_num : NPY_NOTYPE) + +static PyObject * +array_mean(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_mean"); +} + +static PyObject * +array_sum(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_sum"); +} + + +static PyObject * +array_cumsum(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis = NPY_MAXDIMS; + PyArray_Descr *dtype = NULL; + PyArrayObject *out = NULL; + int rtype; + static char *kwlist[] = {"axis", "dtype", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&O&:cumsum", kwlist, + PyArray_AxisConverter, &axis, + PyArray_DescrConverter2, &dtype, + PyArray_OutputConverter, &out)) { + Py_XDECREF(dtype); + return NULL; + } + + rtype = _CHKTYPENUM(dtype); + Py_XDECREF(dtype); + return PyArray_CumSum(self, axis, rtype, out); +} + +static PyObject * +array_prod(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_prod"); +} + +static PyObject * +array_cumprod(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis = NPY_MAXDIMS; + PyArray_Descr *dtype = NULL; + PyArrayObject *out = NULL; + int rtype; + static char *kwlist[] = {"axis", "dtype", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&O&:cumprod", kwlist, + PyArray_AxisConverter, &axis, + PyArray_DescrConverter2, &dtype, + PyArray_OutputConverter, &out)) { + Py_XDECREF(dtype); + return NULL; + } + + rtype = _CHKTYPENUM(dtype); + Py_XDECREF(dtype); + return PyArray_CumProd(self, axis, rtype, out); +} + + +static PyObject * +array_dot(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *a = (PyObject *)self, *b, *o = NULL; + PyArrayObject *ret; + char* kwlist[] = {"b", "out", NULL }; + + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:dot", kwlist, &b, &o)) { + return NULL; + } + + if (o != NULL) { + if (o == Py_None) { + o = NULL; + } + else if (!PyArray_Check(o)) { + PyErr_SetString(PyExc_TypeError, + "'out' must be an array"); + return NULL; + } + } + ret = (PyArrayObject *)PyArray_MatrixProduct2(a, b, (PyArrayObject *)o); + return PyArray_Return(ret); +} + + +static PyObject * +array_any(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_any"); +} + + +static PyObject * +array_all(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_all"); +} + +static PyObject * +array_stddev(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_std"); +} + +static PyObject * +array_variance(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_FORWARD_NDARRAY_METHOD("_var"); +} + +static PyObject * +array_compress(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis = NPY_MAXDIMS; + PyObject *condition; + PyArrayObject *out = NULL; + static char *kwlist[] = {"condition", "axis", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O&:compress", kwlist, + &condition, + PyArray_AxisConverter, &axis, + PyArray_OutputConverter, &out)) { + return NULL; + } + return PyArray_Return( + (PyArrayObject *)PyArray_Compress(self, condition, axis, out)); +} + + +static PyObject * +array_nonzero(PyArrayObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + return PyArray_Nonzero(self); +} + + +static PyObject * +array_trace(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis1 = 0, axis2 = 1, offset = 0; + PyArray_Descr *dtype = NULL; + PyArrayObject *out = NULL; + int rtype; + static char *kwlist[] = {"offset", "axis1", "axis2", "dtype", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiO&O&:trace", kwlist, + &offset, + &axis1, + &axis2, + PyArray_DescrConverter2, &dtype, + PyArray_OutputConverter, &out)) { + Py_XDECREF(dtype); + return NULL; + } + + rtype = _CHKTYPENUM(dtype); + Py_XDECREF(dtype); + return PyArray_Return((PyArrayObject *)PyArray_Trace(self, offset, axis1, axis2, rtype, out)); +} + +#undef _CHKTYPENUM + + +static PyObject * +array_clip(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *min = NULL, *max = NULL; + PyArrayObject *out = NULL; + static char *kwlist[] = {"min", "max", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO&:clip", kwlist, + &min, + &max, + PyArray_OutputConverter, &out)) { + return NULL; + } + if (max == NULL && min == NULL) { + PyErr_SetString(PyExc_ValueError, "One of max or min must be given."); + return NULL; + } + return PyArray_Return((PyArrayObject *)PyArray_Clip(self, min, max, out)); +} + + +static PyObject * +array_conjugate(PyArrayObject *self, PyObject *args) +{ + + PyArrayObject *out = NULL; + if (!PyArg_ParseTuple(args, "|O&:conjugate", + PyArray_OutputConverter, + &out)) { + return NULL; + } + return PyArray_Conjugate(self, out); +} + + +static PyObject * +array_diagonal(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int axis1 = 0, axis2 = 1, offset = 0; + static char *kwlist[] = {"offset", "axis1", "axis2", NULL}; + PyArrayObject *ret; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iii:diagonal", kwlist, + &offset, + &axis1, + &axis2)) { + return NULL; + } + + ret = (PyArrayObject *)PyArray_Diagonal(self, offset, axis1, axis2); + return PyArray_Return(ret); +} + + +static PyObject * +array_flatten(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_ORDER order = NPY_CORDER; + static char *kwlist[] = {"order", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:flatten", kwlist, + PyArray_OrderConverter, &order)) { + return NULL; + } + return PyArray_Flatten(self, order); +} + + +static PyObject * +array_ravel(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_ORDER order = NPY_CORDER; + static char *kwlist[] = {"order", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:ravel", kwlist, + PyArray_OrderConverter, &order)) { + return NULL; + } + return PyArray_Ravel(self, order); +} + + +static PyObject * +array_round(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + int decimals = 0; + PyArrayObject *out = NULL; + static char *kwlist[] = {"decimals", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO&:round", kwlist, + &decimals, + PyArray_OutputConverter, &out)) { + return NULL; + } + return PyArray_Return((PyArrayObject *)PyArray_Round(self, decimals, out)); +} + + + +static PyObject * +array_setflags(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"write", "align", "uic", NULL}; + PyObject *write_flag = Py_None; + PyObject *align_flag = Py_None; + PyObject *uic = Py_None; + int flagback = PyArray_FLAGS(self); + + PyArrayObject_fields *fa = (PyArrayObject_fields *)self; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO:setflags", kwlist, + &write_flag, + &align_flag, + &uic)) + return NULL; + + if (align_flag != Py_None) { + if (PyObject_Not(align_flag)) { + PyArray_CLEARFLAGS(self, NPY_ARRAY_ALIGNED); + } + else if (_IsAligned(self)) { + PyArray_ENABLEFLAGS(self, NPY_ARRAY_ALIGNED); + } + else { + PyErr_SetString(PyExc_ValueError, + "cannot set aligned flag of mis-"\ + "aligned array to True"); + return NULL; + } + } + + if (uic != Py_None) { + if (PyObject_IsTrue(uic)) { + fa->flags = flagback; + PyErr_SetString(PyExc_ValueError, + "cannot set WRITEBACKIFCOPY " \ + "flag to True"); + return NULL; + } + else { + PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY); + PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY); + Py_XDECREF(fa->base); + fa->base = NULL; + } + } + + if (write_flag != Py_None) { + if (PyObject_IsTrue(write_flag)) { + if (_IsWriteable(self)) { + PyArray_ENABLEFLAGS(self, NPY_ARRAY_WRITEABLE); + } + else { + fa->flags = flagback; + PyErr_SetString(PyExc_ValueError, + "cannot set WRITEABLE " + "flag to True of this " + "array"); + return NULL; + } + } + else { + PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEABLE); + } + } + + Py_RETURN_NONE; +} + + +static PyObject * +array_newbyteorder(PyArrayObject *self, PyObject *args) +{ + char endian = NPY_SWAP; + PyArray_Descr *new; + + if (!PyArg_ParseTuple(args, "|O&:newbyteorder", PyArray_ByteorderConverter, + &endian)) { + return NULL; + } + new = PyArray_DescrNewByteorder(PyArray_DESCR(self), endian); + if (!new) { + return NULL; + } + return PyArray_View(self, new, NULL); + +} + +static PyObject * +array_complex(PyArrayObject *self, PyObject *NPY_UNUSED(args)) +{ + PyArrayObject *arr; + PyArray_Descr *dtype; + PyObject *c; + if (PyArray_SIZE(self) != 1) { + PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ + "be converted to Python scalars"); + return NULL; + } + + dtype = PyArray_DescrFromType(NPY_CDOUBLE); + if (dtype == NULL) { + return NULL; + } + + if (!PyArray_CanCastArrayTo(self, dtype, NPY_SAME_KIND_CASTING) && + !(PyArray_TYPE(self) == NPY_OBJECT)) { + PyObject *err, *msg_part; + Py_DECREF(dtype); + err = PyString_FromString("unable to convert "); + if (err == NULL) { + return NULL; + } + msg_part = PyObject_Repr((PyObject*)PyArray_DESCR(self)); + if (msg_part == NULL) { + Py_DECREF(err); + return NULL; + } + PyString_ConcatAndDel(&err, msg_part); + if (err == NULL) { + return NULL; + } + msg_part = PyString_FromString(", to complex."); + if (msg_part == NULL) { + Py_DECREF(err); + return NULL; + } + PyString_ConcatAndDel(&err, msg_part); + if (err == NULL) { + return NULL; + } + PyErr_SetObject(PyExc_TypeError, err); + Py_DECREF(err); + return NULL; + } + + if (PyArray_TYPE(self) == NPY_OBJECT) { + /* let python try calling __complex__ on the object. */ + PyObject *args, *res; + Py_DECREF(dtype); + args = Py_BuildValue("(O)", *((PyObject**)PyArray_DATA(self))); + if (args == NULL) { + return NULL; + } + res = PyComplex_Type.tp_new(&PyComplex_Type, args, NULL); + Py_DECREF(args); + return res; + } + + arr = (PyArrayObject *)PyArray_CastToType(self, dtype, 0); + if (arr == NULL) { + return NULL; + } + c = PyComplex_FromCComplex(*((Py_complex*)PyArray_DATA(arr))); + Py_DECREF(arr); + return c; +} + +#ifndef NPY_PY3K + +static PyObject * +array_getslice(PyArrayObject *self, PyObject *args) +{ + PyObject *start, *stop, *slice, *result; + if (!PyArg_ParseTuple(args, "OO:__getslice__", &start, &stop)) { + return NULL; + } + + slice = PySlice_New(start, stop, NULL); + if (slice == NULL) { + return NULL; + } + + /* Deliberately delegate to subclasses */ + result = PyObject_GetItem((PyObject *)self, slice); + Py_DECREF(slice); + return result; +} + +static PyObject * +array_setslice(PyArrayObject *self, PyObject *args) +{ + PyObject *start, *stop, *value, *slice; + if (!PyArg_ParseTuple(args, "OOO:__setslice__", &start, &stop, &value)) { + return NULL; + } + + slice = PySlice_New(start, stop, NULL); + if (slice == NULL) { + return NULL; + } + + /* Deliberately delegate to subclasses */ + if (PyObject_SetItem((PyObject *)self, slice, value) < 0) { + Py_DECREF(slice); + return NULL; + } + Py_DECREF(slice); + Py_RETURN_NONE; +} + +#endif + +NPY_NO_EXPORT PyMethodDef array_methods[] = { + + /* for subtypes */ + {"__array__", + (PyCFunction)array_getarray, + METH_VARARGS, NULL}, + {"__array_prepare__", + (PyCFunction)array_preparearray, + METH_VARARGS, NULL}, + {"__array_wrap__", + (PyCFunction)array_wraparray, + METH_VARARGS, NULL}, + {"__array_ufunc__", + (PyCFunction)array_ufunc, + METH_VARARGS | METH_KEYWORDS, NULL}, + +#ifndef NPY_PY3K + {"__unicode__", + (PyCFunction)array_unicode, + METH_NOARGS, NULL}, +#endif + + /* for the sys module */ + {"__sizeof__", + (PyCFunction) array_sizeof, + METH_NOARGS, NULL}, + + /* for the copy module */ + {"__copy__", + (PyCFunction)array_copy_keeporder, + METH_VARARGS, NULL}, + {"__deepcopy__", + (PyCFunction)array_deepcopy, + METH_VARARGS, NULL}, + + /* for Pickling */ + {"__reduce__", + (PyCFunction) array_reduce, + METH_VARARGS, NULL}, + {"__setstate__", + (PyCFunction) array_setstate, + METH_VARARGS, NULL}, + {"dumps", + (PyCFunction) array_dumps, + METH_VARARGS, NULL}, + {"dump", + (PyCFunction) array_dump, + METH_VARARGS, NULL}, + + {"__complex__", + (PyCFunction) array_complex, + METH_VARARGS, NULL}, + + {"__format__", + (PyCFunction) array_format, + METH_VARARGS, NULL}, + +#ifndef NPY_PY3K + /* + * While we could put these in `tp_sequence`, its' easier to define them + * in terms of PyObject* arguments. + * + * We must provide these for compatibility with code that calls them + * directly. They are already deprecated at a language level in python 2.7, + * but are removed outright in python 3. + */ + {"__getslice__", + (PyCFunction) array_getslice, + METH_VARARGS, NULL}, + {"__setslice__", + (PyCFunction) array_setslice, + METH_VARARGS, NULL}, +#endif + + /* Original and Extended methods added 2005 */ + {"all", + (PyCFunction)array_all, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"any", + (PyCFunction)array_any, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"argmax", + (PyCFunction)array_argmax, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"argmin", + (PyCFunction)array_argmin, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"argpartition", + (PyCFunction)array_argpartition, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"argsort", + (PyCFunction)array_argsort, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"astype", + (PyCFunction)array_astype, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"byteswap", + (PyCFunction)array_byteswap, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"choose", + (PyCFunction)array_choose, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"clip", + (PyCFunction)array_clip, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"compress", + (PyCFunction)array_compress, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"conj", + (PyCFunction)array_conjugate, + METH_VARARGS, NULL}, + {"conjugate", + (PyCFunction)array_conjugate, + METH_VARARGS, NULL}, + {"copy", + (PyCFunction)array_copy, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"cumprod", + (PyCFunction)array_cumprod, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"cumsum", + (PyCFunction)array_cumsum, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"diagonal", + (PyCFunction)array_diagonal, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"dot", + (PyCFunction)array_dot, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"fill", + (PyCFunction)array_fill, + METH_VARARGS, NULL}, + {"flatten", + (PyCFunction)array_flatten, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"getfield", + (PyCFunction)array_getfield, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"item", + (PyCFunction)array_toscalar, + METH_VARARGS, NULL}, + {"itemset", + (PyCFunction) array_setscalar, + METH_VARARGS, NULL}, + {"max", + (PyCFunction)array_max, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"mean", + (PyCFunction)array_mean, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"min", + (PyCFunction)array_min, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"newbyteorder", + (PyCFunction)array_newbyteorder, + METH_VARARGS, NULL}, + {"nonzero", + (PyCFunction)array_nonzero, + METH_VARARGS, NULL}, + {"partition", + (PyCFunction)array_partition, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"prod", + (PyCFunction)array_prod, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"ptp", + (PyCFunction)array_ptp, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"put", + (PyCFunction)array_put, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"ravel", + (PyCFunction)array_ravel, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"repeat", + (PyCFunction)array_repeat, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"reshape", + (PyCFunction)array_reshape, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"resize", + (PyCFunction)array_resize, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"round", + (PyCFunction)array_round, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"searchsorted", + (PyCFunction)array_searchsorted, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"setfield", + (PyCFunction)array_setfield, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"setflags", + (PyCFunction)array_setflags, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"sort", + (PyCFunction)array_sort, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"squeeze", + (PyCFunction)array_squeeze, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"std", + (PyCFunction)array_stddev, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"sum", + (PyCFunction)array_sum, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"swapaxes", + (PyCFunction)array_swapaxes, + METH_VARARGS, NULL}, + {"take", + (PyCFunction)array_take, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"tobytes", + (PyCFunction)array_tobytes, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"tofile", + (PyCFunction)array_tofile, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"tolist", + (PyCFunction)array_tolist, + METH_VARARGS, NULL}, + {"tostring", + (PyCFunction)array_tobytes, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"trace", + (PyCFunction)array_trace, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"transpose", + (PyCFunction)array_transpose, + METH_VARARGS, NULL}, + {"var", + (PyCFunction)array_variance, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"view", + (PyCFunction)array_view, + METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} /* sentinel */ +}; diff --git a/numpy/core/src/multiarray/methods.h b/numpy/core/src/multiarray/methods.h new file mode 100644 index 0000000..7bf87f4 --- /dev/null +++ b/numpy/core/src/multiarray/methods.h @@ -0,0 +1,9 @@ +#ifndef _NPY_ARRAY_METHODS_H_ +#define _NPY_ARRAY_METHODS_H_ + +extern NPY_NO_EXPORT PyMethodDef array_methods[]; + +NPY_NO_EXPORT const char * +npy_casting_to_string(NPY_CASTING casting); + +#endif diff --git a/numpy/core/src/multiarray/multiarray_tests.c.src b/numpy/core/src/multiarray/multiarray_tests.c.src new file mode 100644 index 0000000..577c733 --- /dev/null +++ b/numpy/core/src/multiarray/multiarray_tests.c.src @@ -0,0 +1,1919 @@ +/* -*-c-*- */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#include +#define _NPY_NO_DEPRECATIONS /* for NPY_CHAR */ +#include "numpy/arrayobject.h" +#include "numpy/npy_math.h" +#include "mem_overlap.h" +#include "npy_extint128.h" +#include "common.h" + +/* test PyArray_IsPythonScalar, before including private py3 compat header */ +static PyObject * +IsPythonScalar(PyObject * dummy, PyObject *args) +{ + PyObject *arg = NULL; + if (!PyArg_ParseTuple(args, "O", &arg)) { + return NULL; + } + if (PyArray_IsPythonScalar(arg)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +#include "npy_pycompat.h" + +/* + * TODO: + * - Handle mode + */ + +/**begin repeat + * #name = double, int# + * #type = npy_double, npy_int# + * #typenum = NPY_DOUBLE, NPY_INT# + */ +static int copy_@name@(PyArrayIterObject *itx, PyArrayNeighborhoodIterObject *niterx, + npy_intp *bounds, + PyObject **out) +{ + npy_intp i, j; + @type@ *ptr; + npy_intp odims[NPY_MAXDIMS]; + PyArrayObject *aout; + + /* + * For each point in itx, copy the current neighborhood into an array which + * is appended at the output list + */ + for (i = 0; i < itx->size; ++i) { + PyArrayNeighborhoodIter_Reset(niterx); + + for (j = 0; j < PyArray_NDIM(itx->ao); ++j) { + odims[j] = bounds[2 * j + 1] - bounds[2 * j] + 1; + } + aout = (PyArrayObject*)PyArray_SimpleNew( + PyArray_NDIM(itx->ao), odims, @typenum@); + if (aout == NULL) { + return -1; + } + + ptr = (@type@*)PyArray_DATA(aout); + + for (j = 0; j < niterx->size; ++j) { + *ptr = *((@type@*)niterx->dataptr); + PyArrayNeighborhoodIter_Next(niterx); + ptr += 1; + } + + PyList_Append(*out, (PyObject*)aout); + Py_DECREF(aout); + PyArray_ITER_NEXT(itx); + } + + return 0; +} +/**end repeat**/ + +static int copy_object(PyArrayIterObject *itx, PyArrayNeighborhoodIterObject *niterx, + npy_intp *bounds, + PyObject **out) +{ + npy_intp i, j; + npy_intp odims[NPY_MAXDIMS]; + PyArrayObject *aout; + PyArray_CopySwapFunc *copyswap = PyArray_DESCR(itx->ao)->f->copyswap; + npy_int itemsize = PyArray_ITEMSIZE(itx->ao); + + /* + * For each point in itx, copy the current neighborhood into an array which + * is appended at the output list + */ + for (i = 0; i < itx->size; ++i) { + PyArrayNeighborhoodIter_Reset(niterx); + + for (j = 0; j < PyArray_NDIM(itx->ao); ++j) { + odims[j] = bounds[2 * j + 1] - bounds[2 * j] + 1; + } + aout = (PyArrayObject*)PyArray_SimpleNew(PyArray_NDIM(itx->ao), odims, NPY_OBJECT); + if (aout == NULL) { + return -1; + } + + for (j = 0; j < niterx->size; ++j) { + copyswap(PyArray_BYTES(aout) + j * itemsize, niterx->dataptr, 0, NULL); + PyArrayNeighborhoodIter_Next(niterx); + } + + PyList_Append(*out, (PyObject*)aout); + Py_DECREF(aout); + PyArray_ITER_NEXT(itx); + } + + return 0; +} + +static PyObject* +test_neighborhood_iterator(PyObject* NPY_UNUSED(self), PyObject* args) +{ + PyObject *x, *fill, *out, *b; + PyArrayObject *ax, *afill; + PyArrayIterObject *itx; + int i, typenum, mode, st; + npy_intp bounds[NPY_MAXDIMS*2]; + PyArrayNeighborhoodIterObject *niterx; + + if (!PyArg_ParseTuple(args, "OOOi", &x, &b, &fill, &mode)) { + return NULL; + } + + if (!PySequence_Check(b)) { + return NULL; + } + + typenum = PyArray_ObjectType(x, 0); + typenum = PyArray_ObjectType(fill, typenum); + + ax = (PyArrayObject*)PyArray_FromObject(x, typenum, 1, 10); + if (ax == NULL) { + return NULL; + } + if (PySequence_Size(b) != 2 * PyArray_NDIM(ax)) { + PyErr_SetString(PyExc_ValueError, + "bounds sequence size not compatible with x input"); + goto clean_ax; + } + + out = PyList_New(0); + if (out == NULL) { + goto clean_ax; + } + + itx = (PyArrayIterObject*)PyArray_IterNew(x); + if (itx == NULL) { + goto clean_out; + } + + /* Compute boundaries for the neighborhood iterator */ + for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) { + PyObject* bound; + bound = PySequence_GetItem(b, i); + if (bound == NULL) { + goto clean_itx; + } + if (!PyInt_Check(bound)) { + PyErr_SetString(PyExc_ValueError, + "bound not long"); + Py_DECREF(bound); + goto clean_itx; + } + bounds[i] = PyInt_AsLong(bound); + Py_DECREF(bound); + } + + /* Create the neighborhood iterator */ + afill = NULL; + if (mode == NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING) { + afill = (PyArrayObject *)PyArray_FromObject(fill, typenum, 0, 0); + if (afill == NULL) { + goto clean_itx; + } + } + + niterx = (PyArrayNeighborhoodIterObject*)PyArray_NeighborhoodIterNew( + (PyArrayIterObject*)itx, bounds, mode, afill); + if (niterx == NULL) { + goto clean_afill; + } + + switch (typenum) { + case NPY_OBJECT: + st = copy_object(itx, niterx, bounds, &out); + break; + case NPY_INT: + st = copy_int(itx, niterx, bounds, &out); + break; + case NPY_DOUBLE: + st = copy_double(itx, niterx, bounds, &out); + break; + default: + PyErr_SetString(PyExc_ValueError, + "Type not supported"); + goto clean_niterx; + } + + if (st) { + goto clean_niterx; + } + + Py_DECREF(niterx); + Py_XDECREF(afill); + Py_DECREF(itx); + + Py_DECREF(ax); + + return out; + +clean_niterx: + Py_DECREF(niterx); +clean_afill: + Py_XDECREF(afill); +clean_itx: + Py_DECREF(itx); +clean_out: + Py_DECREF(out); +clean_ax: + Py_DECREF(ax); + return NULL; +} + +static int +copy_double_double(PyArrayNeighborhoodIterObject *itx, + PyArrayNeighborhoodIterObject *niterx, + npy_intp *bounds, + PyObject **out) +{ + npy_intp i, j; + double *ptr; + npy_intp odims[NPY_MAXDIMS]; + PyArrayObject *aout; + + /* + * For each point in itx, copy the current neighborhood into an array which + * is appended at the output list + */ + PyArrayNeighborhoodIter_Reset(itx); + for (i = 0; i < itx->size; ++i) { + for (j = 0; j < PyArray_NDIM(itx->ao); ++j) { + odims[j] = bounds[2 * j + 1] - bounds[2 * j] + 1; + } + aout = (PyArrayObject*)PyArray_SimpleNew( + PyArray_NDIM(itx->ao), odims, NPY_DOUBLE); + if (aout == NULL) { + return -1; + } + + ptr = (double*)PyArray_DATA(aout); + + PyArrayNeighborhoodIter_Reset(niterx); + for (j = 0; j < niterx->size; ++j) { + *ptr = *((double*)niterx->dataptr); + ptr += 1; + PyArrayNeighborhoodIter_Next(niterx); + } + PyList_Append(*out, (PyObject*)aout); + Py_DECREF(aout); + PyArrayNeighborhoodIter_Next(itx); + } + return 0; +} + +static PyObject* +test_neighborhood_iterator_oob(PyObject* NPY_UNUSED(self), PyObject* args) +{ + PyObject *x, *out, *b1, *b2; + PyArrayObject *ax; + PyArrayIterObject *itx; + int i, typenum, mode1, mode2, st; + npy_intp bounds[NPY_MAXDIMS*2]; + PyArrayNeighborhoodIterObject *niterx1, *niterx2; + + if (!PyArg_ParseTuple(args, "OOiOi", &x, &b1, &mode1, &b2, &mode2)) { + return NULL; + } + + if (!PySequence_Check(b1) || !PySequence_Check(b2)) { + return NULL; + } + + typenum = PyArray_ObjectType(x, 0); + + ax = (PyArrayObject*)PyArray_FromObject(x, typenum, 1, 10); + if (ax == NULL) { + return NULL; + } + if (PySequence_Size(b1) != 2 * PyArray_NDIM(ax)) { + PyErr_SetString(PyExc_ValueError, + "bounds sequence 1 size not compatible with x input"); + goto clean_ax; + } + if (PySequence_Size(b2) != 2 * PyArray_NDIM(ax)) { + PyErr_SetString(PyExc_ValueError, + "bounds sequence 2 size not compatible with x input"); + goto clean_ax; + } + + out = PyList_New(0); + if (out == NULL) { + goto clean_ax; + } + + itx = (PyArrayIterObject*)PyArray_IterNew(x); + if (itx == NULL) { + goto clean_out; + } + + /* Compute boundaries for the neighborhood iterator */ + for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) { + PyObject* bound; + bound = PySequence_GetItem(b1, i); + if (bound == NULL) { + goto clean_itx; + } + if (!PyInt_Check(bound)) { + PyErr_SetString(PyExc_ValueError, + "bound not long"); + Py_DECREF(bound); + goto clean_itx; + } + bounds[i] = PyInt_AsLong(bound); + Py_DECREF(bound); + } + + /* Create the neighborhood iterator */ + niterx1 = (PyArrayNeighborhoodIterObject*)PyArray_NeighborhoodIterNew( + (PyArrayIterObject*)itx, bounds, + mode1, NULL); + if (niterx1 == NULL) { + goto clean_out; + } + + for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) { + PyObject* bound; + bound = PySequence_GetItem(b2, i); + if (bound == NULL) { + goto clean_itx; + } + if (!PyInt_Check(bound)) { + PyErr_SetString(PyExc_ValueError, + "bound not long"); + Py_DECREF(bound); + goto clean_itx; + } + bounds[i] = PyInt_AsLong(bound); + Py_DECREF(bound); + } + + niterx2 = (PyArrayNeighborhoodIterObject*)PyArray_NeighborhoodIterNew( + (PyArrayIterObject*)niterx1, bounds, + mode2, NULL); + if (niterx1 == NULL) { + goto clean_niterx1; + } + + switch (typenum) { + case NPY_DOUBLE: + st = copy_double_double(niterx1, niterx2, bounds, &out); + break; + default: + PyErr_SetString(PyExc_ValueError, + "Type not supported"); + goto clean_niterx2; + } + + if (st) { + goto clean_niterx2; + } + + Py_DECREF(niterx2); + Py_DECREF(niterx1); + Py_DECREF(itx); + Py_DECREF(ax); + return out; + +clean_niterx2: + Py_DECREF(niterx2); +clean_niterx1: + Py_DECREF(niterx1); +clean_itx: + Py_DECREF(itx); +clean_out: + Py_DECREF(out); +clean_ax: + Py_DECREF(ax); + return NULL; +} + +/* PyDataMem_SetHook tests */ +static int malloc_free_counts[2]; +static PyDataMem_EventHookFunc *old_hook = NULL; +static void *old_data; + +static void test_hook(void *old, void *new, size_t size, void *user_data) +{ + int* counters = (int *) user_data; + if (old == NULL) { + counters[0]++; /* malloc counter */ + } + if (size == 0) { + counters[1]++; /* free counter */ + } +} + +static PyObject* +test_pydatamem_seteventhook_start(PyObject* NPY_UNUSED(self), PyObject* NPY_UNUSED(args)) +{ + malloc_free_counts[0] = malloc_free_counts[1] = 0; + old_hook = PyDataMem_SetEventHook(test_hook, (void *) malloc_free_counts, &old_data); + Py_RETURN_NONE; +} + +static PyObject* +test_pydatamem_seteventhook_end(PyObject* NPY_UNUSED(self), PyObject* NPY_UNUSED(args)) +{ + PyDataMem_EventHookFunc *my_hook; + void *my_data; + + my_hook = PyDataMem_SetEventHook(old_hook, old_data, &my_data); + if ((my_hook != test_hook) || (my_data != (void *) malloc_free_counts)) { + PyErr_SetString(PyExc_ValueError, + "hook/data was not the expected test hook"); + return NULL; + } + + if (malloc_free_counts[0] == 0) { + PyErr_SetString(PyExc_ValueError, + "malloc count is zero after test"); + return NULL; + } + if (malloc_free_counts[1] == 0) { + PyErr_SetString(PyExc_ValueError, + "free count is zero after test"); + return NULL; + } + + Py_RETURN_NONE; +} + + +typedef void (*inplace_map_binop)(PyArrayMapIterObject *, PyArrayIterObject *); + +static void npy_float64_inplace_add(PyArrayMapIterObject *mit, PyArrayIterObject *it) +{ + int index = mit->size; + while (index--) { + ((npy_float64*)mit->dataptr)[0] = ((npy_float64*)mit->dataptr)[0] + ((npy_float64*)it->dataptr)[0]; + + PyArray_MapIterNext(mit); + PyArray_ITER_NEXT(it); + } +} + +inplace_map_binop addition_funcs[] = { +npy_float64_inplace_add, +NULL}; + +int type_numbers[] = { +NPY_FLOAT64, +-1000}; + + + +static int +map_increment(PyArrayMapIterObject *mit, PyObject *op, inplace_map_binop add_inplace) +{ + PyArrayObject *arr = NULL; + PyArrayIterObject *it; + PyArray_Descr *descr; + + if (mit->ait == NULL) { + return -1; + } + descr = PyArray_DESCR(mit->ait->ao); + Py_INCREF(descr); + arr = (PyArrayObject *)PyArray_FromAny(op, descr, + 0, 0, NPY_ARRAY_FORCECAST, NULL); + if (arr == NULL) { + return -1; + } + + if ((mit->subspace != NULL) && (mit->consec)) { + PyArray_MapIterSwapAxes(mit, (PyArrayObject **)&arr, 0); + if (arr == NULL) { + return -1; + } + } + + if ((it = (PyArrayIterObject *)\ + PyArray_BroadcastToShape((PyObject *)arr, mit->dimensions, + mit->nd)) == NULL) { + Py_DECREF(arr); + + return -1; + } + + (*add_inplace)(mit, it); + + Py_DECREF(arr); + Py_DECREF(it); + return 0; +} + + +static PyObject * +inplace_increment(PyObject *dummy, PyObject *args) +{ + PyObject *arg_a = NULL, *index=NULL, *inc=NULL; + PyArrayObject *a; + inplace_map_binop add_inplace = NULL; + int type_number = -1; + int i =0; + PyArrayMapIterObject * mit; + + if (!PyArg_ParseTuple(args, "OOO", &arg_a, &index, + &inc)) { + return NULL; + } + if (!PyArray_Check(arg_a)) { + PyErr_SetString(PyExc_ValueError, "needs an ndarray as first argument"); + return NULL; + } + a = (PyArrayObject *) arg_a; + + if (PyArray_FailUnlessWriteable(a, "input/output array") < 0) { + return NULL; + } + + if (PyArray_NDIM(a) == 0) { + PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed."); + return NULL; + } + type_number = PyArray_TYPE(a); + + while (type_numbers[i] >= 0 && addition_funcs[i] != NULL){ + if (type_number == type_numbers[i]) { + add_inplace = addition_funcs[i]; + break; + } + i++ ; + } + + if (add_inplace == NULL) { + PyErr_SetString(PyExc_TypeError, "unsupported type for a"); + return NULL; + } + + mit = (PyArrayMapIterObject *) PyArray_MapIterArray(a, index); + if (mit == NULL) { + goto fail; + } + + if (map_increment(mit, inc, add_inplace) != 0) { + goto fail; + } + + Py_DECREF(mit); + + Py_RETURN_NONE; + +fail: + Py_XDECREF(mit); + + return NULL; +} + +/* check no elison for avoided increfs */ +static PyObject * +incref_elide(PyObject *dummy, PyObject *args) +{ + PyObject *arg = NULL, *res, *tup; + if (!PyArg_ParseTuple(args, "O", &arg)) { + return NULL; + } + + /* refcount 1 array but should not be elided */ + arg = PyArray_NewCopy((PyArrayObject*)arg, NPY_KEEPORDER); + res = PyNumber_Add(arg, arg); + + /* return original copy, should be equal to input */ + tup = PyTuple_Pack(2, arg, res); + Py_DECREF(arg); + Py_DECREF(res); + return tup; +} + +/* check no elison for get from list without incref */ +static PyObject * +incref_elide_l(PyObject *dummy, PyObject *args) +{ + PyObject *arg = NULL, *r, *res; + if (!PyArg_ParseTuple(args, "O", &arg)) { + return NULL; + } + /* get item without increasing refcount, item may still be on the python + * stack but above the inaccessible top */ + r = PyList_GetItem(arg, 4); + res = PyNumber_Add(r, r); + + return res; +} + +/* used to test NPY_CHAR usage emits deprecation warning */ +static PyObject* +npy_char_deprecation(PyObject* NPY_UNUSED(self), PyObject* NPY_UNUSED(args)) +{ + PyArray_Descr * descr = PyArray_DescrFromType(NPY_CHAR); + return (PyObject *)descr; +} + +/* used to test UPDATEIFCOPY usage emits deprecation warning */ +static PyObject* +npy_updateifcopy_deprecation(PyObject* NPY_UNUSED(self), PyObject* args) +{ + int flags; + PyObject* array; + if (!PyArray_Check(args)) { + PyErr_SetString(PyExc_TypeError, "test needs ndarray input"); + return NULL; + } + flags = NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY; + array = PyArray_FromArray((PyArrayObject*)args, NULL, flags); + if (array == NULL) + return NULL; + PyArray_ResolveWritebackIfCopy((PyArrayObject*)array); + Py_DECREF(array); + Py_RETURN_NONE; +} + +/* used to create array with WRITEBACKIFCOPY flag */ +static PyObject* +npy_create_writebackifcopy(PyObject* NPY_UNUSED(self), PyObject* args) +{ + int flags; + PyObject* array; + if (!PyArray_Check(args)) { + PyErr_SetString(PyExc_TypeError, "test needs ndarray input"); + return NULL; + } + flags = NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY; + array = PyArray_FromArray((PyArrayObject*)args, NULL, flags); + if (array == NULL) + return NULL; + return array; +} + +/* resolve WRITEBACKIFCOPY */ +static PyObject* +npy_resolve(PyObject* NPY_UNUSED(self), PyObject* args) +{ + if (!PyArray_Check(args)) { + PyErr_SetString(PyExc_TypeError, "test needs ndarray input"); + return NULL; + } + PyArray_ResolveWritebackIfCopy((PyArrayObject*)args); + Py_RETURN_NONE; +} + +/* resolve WRITEBACKIFCOPY */ +static PyObject* +npy_discard(PyObject* NPY_UNUSED(self), PyObject* args) +{ + if (!PyArray_Check(args)) { + PyErr_SetString(PyExc_TypeError, "test needs ndarray input"); + return NULL; + } + PyArray_DiscardWritebackIfCopy((PyArrayObject*)args); + Py_RETURN_NONE; +} + +#if !defined(NPY_PY3K) +static PyObject * +int_subclass(PyObject *dummy, PyObject *args) +{ + + PyObject *result = NULL; + PyObject *scalar_object = NULL; + + if (!PyArg_UnpackTuple(args, "test_int_subclass", 1, 1, &scalar_object)) + return NULL; + + if (PyInt_Check(scalar_object)) + result = Py_True; + else + result = Py_False; + + Py_INCREF(result); + + return result; + +} +#endif + + +/* + * Create python string from a FLAG and or the corresponding PyBuf flag + * for the use in get_buffer_info. + */ +#define GET_PYBUF_FLAG(FLAG) \ + buf_flag = PyUnicode_FromString(#FLAG); \ + flag_matches = PyObject_RichCompareBool(buf_flag, tmp, Py_EQ); \ + Py_DECREF(buf_flag); \ + if (flag_matches == 1) { \ + Py_DECREF(tmp); \ + flags |= PyBUF_##FLAG; \ + continue; \ + } \ + else if (flag_matches == -1) { \ + Py_DECREF(tmp); \ + return NULL; \ + } + + +/* + * Get information for a buffer through PyBuf_GetBuffer with the + * corresponding flags or'ed. Note that the python caller has to + * make sure that or'ing those flags actually makes sense. + * More information should probably be returned for future tests. + */ +static PyObject * +get_buffer_info(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyObject *buffer_obj, *pyflags; + PyObject *tmp, *buf_flag; + Py_buffer buffer; + PyObject *shape, *strides; + Py_ssize_t i, n; + int flag_matches; + int flags = 0; + + if (!PyArg_ParseTuple(args, "OO", &buffer_obj, &pyflags)) { + return NULL; + } + + n = PySequence_Length(pyflags); + if (n < 0) { + return NULL; + } + + for (i=0; i < n; i++) { + tmp = PySequence_GetItem(pyflags, i); + if (tmp == NULL) { + return NULL; + } + + GET_PYBUF_FLAG(SIMPLE); + GET_PYBUF_FLAG(WRITABLE); + GET_PYBUF_FLAG(STRIDES); + GET_PYBUF_FLAG(ND); + GET_PYBUF_FLAG(C_CONTIGUOUS); + GET_PYBUF_FLAG(F_CONTIGUOUS); + GET_PYBUF_FLAG(ANY_CONTIGUOUS); + GET_PYBUF_FLAG(INDIRECT); + GET_PYBUF_FLAG(FORMAT); + GET_PYBUF_FLAG(STRIDED); + GET_PYBUF_FLAG(STRIDED_RO); + GET_PYBUF_FLAG(RECORDS); + GET_PYBUF_FLAG(RECORDS_RO); + GET_PYBUF_FLAG(FULL); + GET_PYBUF_FLAG(FULL_RO); + GET_PYBUF_FLAG(CONTIG); + GET_PYBUF_FLAG(CONTIG_RO); + + Py_DECREF(tmp); + + /* One of the flags must match */ + PyErr_SetString(PyExc_ValueError, "invalid flag used."); + return NULL; + } + + if (PyObject_GetBuffer(buffer_obj, &buffer, flags) < 0) { + return NULL; + } + + if (buffer.shape == NULL) { + Py_INCREF(Py_None); + shape = Py_None; + } + else { + shape = PyTuple_New(buffer.ndim); + for (i=0; i < buffer.ndim; i++) { + PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(buffer.shape[i])); + } + } + + if (buffer.strides == NULL) { + Py_INCREF(Py_None); + strides = Py_None; + } + else { + strides = PyTuple_New(buffer.ndim); + for (i=0; i < buffer.ndim; i++) { + PyTuple_SET_ITEM(strides, i, PyLong_FromSsize_t(buffer.strides[i])); + } + } + + PyBuffer_Release(&buffer); + return Py_BuildValue("(NN)", shape, strides); +} + +#undef GET_PYBUF_FLAG + + +/* + * Test C-api level item getting. + */ +static PyObject * +array_indexing(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int mode; + Py_ssize_t i; + PyObject *arr, *op = NULL; + + if (!PyArg_ParseTuple(args, "iOn|O", &mode, &arr, &i, &op)) { + return NULL; + } + + if (mode == 0) { + return PySequence_GetItem(arr, i); + } + if (mode == 1) { + if (PySequence_SetItem(arr, i, op) < 0) { + return NULL; + } + Py_RETURN_NONE; + } + + PyErr_SetString(PyExc_ValueError, + "invalid mode. 0: item 1: assign"); + return NULL; +} + +/* + * Test C-api PyArray_AsCArray item getter + */ +static PyObject * +test_as_c_array(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyArrayObject *array_obj; + npy_intp dims[3]; /* max 3-dim */ + npy_intp i=0, j=0, k=0; + npy_intp num_dims = 0; + PyArray_Descr *descr = NULL; + double *array1 = NULL; + double **array2 = NULL; + double ***array3 = NULL; + double temp = 9999; + + if (!PyArg_ParseTuple(args, "O!l|ll", + &PyArray_Type, &array_obj, + &i, &j, &k)) { + return NULL; + } + + if (NULL == array_obj) { + return NULL; + } + + num_dims = PyArray_NDIM(array_obj); + descr = PyArray_DESCR(array_obj); + + switch (num_dims) { + case 1: + if (PyArray_AsCArray( + (PyObject **) &array_obj, + (void *) &array1, + dims, + 1, + descr) < 0) { + PyErr_SetString(PyExc_RuntimeError, "error converting 1D array"); + return NULL; + } + temp = array1[i]; + PyArray_Free((PyObject *) array_obj, (void *) array1); + break; + case 2: + if (PyArray_AsCArray( + (PyObject **) &array_obj, + (void **) &array2, + dims, + 2, + descr) < 0) { + PyErr_SetString(PyExc_RuntimeError, "error converting 2D array"); + return NULL; + } + temp = array2[i][j]; + PyArray_Free((PyObject *) array_obj, (void *) array2); + break; + case 3: + if (PyArray_AsCArray( + (PyObject **) &array_obj, + (void ***) &array3, + dims, + 3, + descr) < 0) { + PyErr_SetString(PyExc_RuntimeError, "error converting 3D array"); + return NULL; + } + temp = array3[i][j][k]; + PyArray_Free((PyObject *) array_obj, (void *) array3); + break; + default: + PyErr_SetString(PyExc_ValueError, "array.ndim not in [1, 3]"); + return NULL; + } + return Py_BuildValue("f", temp); +} + +/* + * Test nditer of too large arrays using remove axis, etc. + */ +static PyObject * +test_nditer_too_large(PyObject *NPY_UNUSED(self), PyObject *args) { + NpyIter *iter; + PyObject *array_tuple, *arr; + PyArrayObject *arrays[NPY_MAXARGS]; + npy_uint32 op_flags[NPY_MAXARGS]; + Py_ssize_t nop; + int i, axis, mode; + + npy_intp index[NPY_MAXARGS] = {0}; + char *msg; + + if (!PyArg_ParseTuple(args, "Oii", &array_tuple, &axis, &mode)) { + return NULL; + } + + if (!PyTuple_CheckExact(array_tuple)) { + PyErr_SetString(PyExc_ValueError, "tuple required as first argument"); + return NULL; + } + nop = PyTuple_Size(array_tuple); + if (nop > NPY_MAXARGS) { + PyErr_SetString(PyExc_ValueError, "tuple must be smaller then maxargs"); + return NULL; + } + + for (i=0; i < nop; i++) { + arr = PyTuple_GET_ITEM(array_tuple, i); + if (!PyArray_CheckExact(arr)) { + PyErr_SetString(PyExc_ValueError, "require base class ndarray"); + return NULL; + } + arrays[i] = (PyArrayObject *)arr; + op_flags[i] = NPY_ITER_READONLY; + } + + iter = NpyIter_MultiNew(nop, arrays, NPY_ITER_MULTI_INDEX | NPY_ITER_RANGED, + NPY_KEEPORDER, NPY_NO_CASTING, op_flags, NULL); + + if (iter == NULL) { + return NULL; + } + + /* Remove an axis (negative, do not remove any) */ + if (axis >= 0) { + if (!NpyIter_RemoveAxis(iter, axis)) { + goto fail; + } + } + + switch (mode) { + /* Test IterNext getting */ + case 0: + if (NpyIter_GetIterNext(iter, NULL) == NULL) { + goto fail; + } + break; + case 1: + if (NpyIter_GetIterNext(iter, &msg) == NULL) { + PyErr_SetString(PyExc_ValueError, msg); + goto fail; + } + break; + /* Test Multi Index removal */ + case 2: + if (!NpyIter_RemoveMultiIndex(iter)) { + goto fail; + } + break; + /* Test GotoMultiIndex (just 0 hardcoded) */ + case 3: + if (!NpyIter_GotoMultiIndex(iter, index)) { + goto fail; + } + break; + /* Test setting iterrange (hardcoded range of 0, 1) */ + case 4: + if (!NpyIter_ResetToIterIndexRange(iter, 0, 1, NULL)) { + goto fail; + } + break; + case 5: + if (!NpyIter_ResetToIterIndexRange(iter, 0, 1, &msg)) { + PyErr_SetString(PyExc_ValueError, msg); + goto fail; + } + break; + /* Do nothing */ + default: + break; + } + + NpyIter_Deallocate(iter); + Py_RETURN_NONE; + fail: + NpyIter_Deallocate(iter); + return NULL; +} + + +static PyObject * +array_solve_diophantine(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + PyObject *A = NULL; + PyObject *U = NULL; + Py_ssize_t b_input = 0; + Py_ssize_t max_work = -1; + int simplify = 0; + int require_ub_nontrivial = 0; + static char *kwlist[] = {"A", "U", "b", "max_work", "simplify", + "require_ub_nontrivial", NULL}; + + diophantine_term_t terms[2*NPY_MAXDIMS+2]; + npy_int64 x[2*NPY_MAXDIMS+2]; + npy_int64 b; + unsigned int nterms, j; + mem_overlap_t result = MEM_OVERLAP_YES; + PyObject *retval = NULL; + NPY_BEGIN_THREADS_DEF; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!n|nii", kwlist, + &PyTuple_Type, &A, + &PyTuple_Type, &U, + &b_input, &max_work, &simplify, + &require_ub_nontrivial)) { + return NULL; + } + + if (PyTuple_GET_SIZE(A) > sizeof(terms) / sizeof(diophantine_term_t)) { + PyErr_SetString(PyExc_ValueError, "too many terms in equation"); + goto fail; + } + + nterms = PyTuple_GET_SIZE(A); + + if (PyTuple_GET_SIZE(U) != nterms) { + PyErr_SetString(PyExc_ValueError, "A, U must be tuples of equal length"); + goto fail; + } + + for (j = 0; j < nterms; ++j) { + terms[j].a = (npy_int64)PyInt_AsSsize_t(PyTuple_GET_ITEM(A, j)); + if (error_converting(terms[j].a)) { + goto fail; + } + terms[j].ub = (npy_int64)PyInt_AsSsize_t(PyTuple_GET_ITEM(U, j)); + if (error_converting(terms[j].ub)) { + goto fail; + } + } + + b = b_input; + + NPY_BEGIN_THREADS; + if (simplify && !require_ub_nontrivial) { + if (diophantine_simplify(&nterms, terms, b)) { + result = MEM_OVERLAP_OVERFLOW; + } + } + if (result == MEM_OVERLAP_YES) { + result = solve_diophantine(nterms, terms, b, max_work, require_ub_nontrivial, x); + } + NPY_END_THREADS; + + if (result == MEM_OVERLAP_YES) { + retval = PyTuple_New(nterms); + if (retval == NULL) { + goto fail; + } + + for (j = 0; j < nterms; ++j) { + PyObject *obj; +#if defined(NPY_PY3K) + obj = PyLong_FromSsize_t(x[j]); +#else + obj = PyInt_FromSsize_t(x[j]); +#endif + if (obj == NULL) { + goto fail; + } + PyTuple_SET_ITEM(retval, j, obj); + } + } + else if (result == MEM_OVERLAP_NO) { + retval = Py_None; + Py_INCREF(retval); + } + else if (result == MEM_OVERLAP_ERROR) { + PyErr_SetString(PyExc_ValueError, "Invalid arguments"); + } + else if (result == MEM_OVERLAP_OVERFLOW) { + PyErr_SetString(PyExc_OverflowError, "Integer overflow"); + } + else if (result == MEM_OVERLAP_TOO_HARD) { + PyErr_SetString(PyExc_RuntimeError, "Too much work done"); + } + else { + PyErr_SetString(PyExc_RuntimeError, "Unknown error"); + } + + return retval; + +fail: + Py_XDECREF(retval); + return NULL; +} + + +static PyObject * +array_internal_overlap(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + PyArrayObject * self = NULL; + static char *kwlist[] = {"self", "max_work", NULL}; + + mem_overlap_t result; + Py_ssize_t max_work = NPY_MAY_SHARE_EXACT; + NPY_BEGIN_THREADS_DEF; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|n", kwlist, + PyArray_Converter, &self, + &max_work)) { + return NULL; + } + + if (max_work < -2) { + PyErr_SetString(PyExc_ValueError, "Invalid value for max_work"); + goto fail; + } + + NPY_BEGIN_THREADS; + result = solve_may_have_internal_overlap(self, max_work); + NPY_END_THREADS; + + Py_XDECREF(self); + + if (result == MEM_OVERLAP_NO) { + Py_RETURN_FALSE; + } + else if (result == MEM_OVERLAP_YES) { + Py_RETURN_TRUE; + } + else if (result == MEM_OVERLAP_OVERFLOW) { + PyErr_SetString(PyExc_OverflowError, + "Integer overflow in computing overlap"); + return NULL; + } + else if (result == MEM_OVERLAP_TOO_HARD) { + PyErr_SetString(PyExc_ValueError, + "Exceeded max_work"); + return NULL; + } + else { + /* Doesn't happen usually */ + PyErr_SetString(PyExc_RuntimeError, + "Error in computing overlap"); + return NULL; + } + +fail: + Py_XDECREF(self); + return NULL; +} + + +static PyObject * +pylong_from_int128(npy_extint128_t value) +{ + PyObject *val_64 = NULL, *val = NULL, *tmp = NULL, *tmp2 = NULL; + + val_64 = PyLong_FromLong(64); + if (val_64 == NULL) { + goto fail; + } + + val = PyLong_FromUnsignedLongLong(value.hi); + if (val == NULL) { + goto fail; + } + + tmp = PyNumber_Lshift(val, val_64); + if (tmp == NULL) { + goto fail; + } + + Py_DECREF(val); + val = tmp; + + tmp = PyLong_FromUnsignedLongLong(value.lo); + if (tmp == NULL) { + goto fail; + } + + tmp2 = PyNumber_Or(val, tmp); + if (tmp2 == NULL) { + goto fail; + } + + Py_DECREF(val); + Py_DECREF(tmp); + + val = NULL; + tmp = NULL; + + if (value.sign < 0) { + val = PyNumber_Negative(tmp2); + if (val == NULL) { + goto fail; + } + Py_DECREF(tmp2); + return val; + } + else { + val = tmp2; + } + return val; + +fail: + Py_XDECREF(val_64); + Py_XDECREF(tmp); + Py_XDECREF(tmp2); + Py_XDECREF(val); + return NULL; +} + + +static int +int128_from_pylong(PyObject *obj, npy_extint128_t *result) +{ + PyObject *long_obj = NULL, *val_64 = NULL, *val_0 = NULL, + *mask_64 = NULL, *max_128 = NULL, *hi_bits = NULL, + *lo_bits = NULL, *tmp = NULL; + int cmp; + int negative_zero = 0; + + if (PyBool_Check(obj)) { + /* False means negative zero */ + negative_zero = 1; + } + + long_obj = PyObject_CallFunction((PyObject*)&PyLong_Type, "O", obj); + if (long_obj == NULL) { + goto fail; + } + + val_0 = PyLong_FromLong(0); + if (val_0 == NULL) { + goto fail; + } + + val_64 = PyLong_FromLong(64); + if (val_64 == NULL) { + goto fail; + } + + mask_64 = PyLong_FromUnsignedLongLong(0xffffffffffffffffULL); + if (mask_64 == NULL) { + goto fail; + } + + tmp = PyNumber_Lshift(mask_64, val_64); + if (tmp == NULL) { + goto fail; + } + max_128 = PyNumber_Or(tmp, mask_64); + if (max_128 == NULL) { + goto fail; + } + Py_DECREF(tmp); + tmp = NULL; + + cmp = PyObject_RichCompareBool(long_obj, val_0, Py_LT); + if (cmp == -1) { + goto fail; + } + else if (cmp == 1) { + tmp = PyNumber_Negative(long_obj); + if (tmp == NULL) { + goto fail; + } + Py_DECREF(long_obj); + long_obj = tmp; + tmp = NULL; + result->sign = -1; + } + else { + result->sign = 1; + } + + cmp = PyObject_RichCompareBool(long_obj, max_128, Py_GT); + if (cmp == 1) { + PyErr_SetString(PyExc_OverflowError, ""); + goto fail; + } + else if (cmp == -1) { + goto fail; + } + + hi_bits = PyNumber_Rshift(long_obj, val_64); + if (hi_bits == NULL) { + goto fail; + } + + lo_bits = PyNumber_And(long_obj, mask_64); + if (lo_bits == NULL) { + goto fail; + } + + result->hi = PyLong_AsUnsignedLongLong(hi_bits); + if (result->hi == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) { + goto fail; + } + + result->lo = PyLong_AsUnsignedLongLong(lo_bits); + if (result->lo == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) { + goto fail; + } + + if (negative_zero && result->hi == 0 && result->lo == 0) { + result->sign = -1; + } + + Py_XDECREF(long_obj); + Py_XDECREF(val_64); + Py_XDECREF(val_0); + Py_XDECREF(mask_64); + Py_XDECREF(max_128); + Py_XDECREF(hi_bits); + Py_XDECREF(lo_bits); + Py_XDECREF(tmp); + return 0; + +fail: + Py_XDECREF(long_obj); + Py_XDECREF(val_64); + Py_XDECREF(val_0); + Py_XDECREF(mask_64); + Py_XDECREF(max_128); + Py_XDECREF(hi_bits); + Py_XDECREF(lo_bits); + Py_XDECREF(tmp); + return -1; +} + + +static PyObject * +extint_safe_binop(PyObject *NPY_UNUSED(self), PyObject *args) { + PY_LONG_LONG a, b, c; + int op; + char overflow = 0; + if (!PyArg_ParseTuple(args, "LLi", &a, &b, &op)) { + return NULL; + } + if (op == 1) { + c = safe_add(a, b, &overflow); + } + else if (op == 2) { + c = safe_sub(a, b, &overflow); + } + else if (op == 3) { + c = safe_mul(a, b, &overflow); + } + else { + PyErr_SetString(PyExc_ValueError, "invalid op"); + return NULL; + } + if (overflow) { + PyErr_SetString(PyExc_OverflowError, ""); + return NULL; + } + return PyLong_FromLongLong(c); +} + + +static PyObject * +extint_to_128(PyObject *NPY_UNUSED(self), PyObject *args) { + PY_LONG_LONG a; + if (!PyArg_ParseTuple(args, "L", &a)) { + return NULL; + } + return pylong_from_int128(to_128(a)); +} + + +static PyObject * +extint_to_64(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj; + npy_extint128_t a; + PY_LONG_LONG r; + char overflow = 0; + if (!PyArg_ParseTuple(args, "O", &a_obj)) { + return NULL; + } + if (int128_from_pylong(a_obj, &a)) { + return NULL; + } + r = to_64(a, &overflow); + if (overflow) { + PyErr_SetString(PyExc_OverflowError, ""); + return NULL; + } + return PyLong_FromLongLong(r); +} + + +static PyObject * +extint_mul_64_64(PyObject *NPY_UNUSED(self), PyObject *args) { + PY_LONG_LONG a, b; + npy_extint128_t c; + if (!PyArg_ParseTuple(args, "LL", &a, &b)) { + return NULL; + } + c = mul_64_64(a, b); + return pylong_from_int128(c); +} + + +static PyObject * +extint_add_128(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj, *b_obj; + npy_extint128_t a, b, c; + char overflow = 0; + if (!PyArg_ParseTuple(args, "OO", &a_obj, &b_obj)) { + return NULL; + } + if (int128_from_pylong(a_obj, &a) || int128_from_pylong(b_obj, &b)) { + return NULL; + } + c = add_128(a, b, &overflow); + if (overflow) { + PyErr_SetString(PyExc_OverflowError, ""); + return NULL; + } + return pylong_from_int128(c); +} + + +static PyObject * +extint_sub_128(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj, *b_obj; + npy_extint128_t a, b, c; + char overflow = 0; + if (!PyArg_ParseTuple(args, "OO", &a_obj, &b_obj)) { + return NULL; + } + if (int128_from_pylong(a_obj, &a) || int128_from_pylong(b_obj, &b)) { + return NULL; + } + c = sub_128(a, b, &overflow); + if (overflow) { + PyErr_SetString(PyExc_OverflowError, ""); + return NULL; + } + return pylong_from_int128(c); +} + + +static PyObject * +extint_neg_128(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj; + npy_extint128_t a, b; + if (!PyArg_ParseTuple(args, "O", &a_obj)) { + return NULL; + } + if (int128_from_pylong(a_obj, &a)) { + return NULL; + } + b = neg_128(a); + return pylong_from_int128(b); +} + + +static PyObject * +extint_shl_128(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj; + npy_extint128_t a, b; + if (!PyArg_ParseTuple(args, "O", &a_obj)) { + return NULL; + } + if (int128_from_pylong(a_obj, &a)) { + return NULL; + } + b = shl_128(a); + return pylong_from_int128(b); +} + + +static PyObject * +extint_shr_128(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj; + npy_extint128_t a, b; + if (!PyArg_ParseTuple(args, "O", &a_obj)) { + return NULL; + } + if (int128_from_pylong(a_obj, &a)) { + return NULL; + } + b = shr_128(a); + return pylong_from_int128(b); +} + + +static PyObject * +extint_gt_128(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj, *b_obj; + npy_extint128_t a, b; + if (!PyArg_ParseTuple(args, "OO", &a_obj, &b_obj)) { + return NULL; + } + if (int128_from_pylong(a_obj, &a) || int128_from_pylong(b_obj, &b)) { + return NULL; + } + if (gt_128(a, b)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + + +static PyObject * +extint_divmod_128_64(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj, *ret = NULL, *tmp = NULL; + npy_extint128_t a, c; + PY_LONG_LONG b; + npy_int64 mod; + if (!PyArg_ParseTuple(args, "OL", &a_obj, &b)) { + goto fail; + } + if (b <= 0) { + PyErr_SetString(PyExc_ValueError, ""); + goto fail; + } + if (int128_from_pylong(a_obj, &a)) { + goto fail; + } + + c = divmod_128_64(a, b, &mod); + + ret = PyTuple_New(2); + + tmp = pylong_from_int128(c); + if (tmp == NULL) { + goto fail; + } + PyTuple_SET_ITEM(ret, 0, tmp); + + tmp = PyLong_FromLongLong(mod); + if (tmp == NULL) { + goto fail; + } + PyTuple_SET_ITEM(ret, 1, tmp); + return ret; + +fail: + Py_XDECREF(ret); + Py_XDECREF(tmp); + return NULL; +} + + +static PyObject * +extint_floordiv_128_64(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj; + npy_extint128_t a, c; + PY_LONG_LONG b; + if (!PyArg_ParseTuple(args, "OL", &a_obj, &b)) { + return NULL; + } + if (b <= 0) { + PyErr_SetString(PyExc_ValueError, ""); + return NULL; + } + if (int128_from_pylong(a_obj, &a)) { + return NULL; + } + c = floordiv_128_64(a, b); + return pylong_from_int128(c); +} + + +static PyObject * +extint_ceildiv_128_64(PyObject *NPY_UNUSED(self), PyObject *args) { + PyObject *a_obj; + npy_extint128_t a, c; + PY_LONG_LONG b; + if (!PyArg_ParseTuple(args, "OL", &a_obj, &b)) { + return NULL; + } + if (b <= 0) { + PyErr_SetString(PyExc_ValueError, ""); + return NULL; + } + if (int128_from_pylong(a_obj, &a)) { + return NULL; + } + c = ceildiv_128_64(a, b); + return pylong_from_int128(c); +} + + +static char get_fpu_mode_doc[] = ( + "get_fpu_mode()\n" + "\n" + "Get the current FPU control word, in a platform-dependent format.\n" + "Returns None if not implemented on current platform."); + +static PyObject * +get_fpu_mode(PyObject *NPY_UNUSED(self), PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + +#if defined(_MSC_VER) + { + unsigned int result = 0; + result = _controlfp(0, 0); + return PyLong_FromLongLong(result); + } +#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) + { + unsigned short cw = 0; + __asm__("fstcw %w0" : "=m" (cw)); + return PyLong_FromLongLong(cw); + } +#else + Py_RETURN_NONE; +#endif +} + +/* + * npymath wrappers + */ + +/**begin repeat + * #name = cabs, carg# + */ + +/**begin repeat1 + * #itype = npy_cfloat, npy_cdouble, npy_clongdouble# + * #ITYPE = NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE# + * #otype = npy_float, npy_double, npy_longdouble# + * #OTYPE = NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE# + * #suffix= f, , l# + */ + +static PyObject * +call_npy_@name@@suffix@(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyObject *z_py = NULL, *z_arr = NULL, *w_arr = NULL; + + if (!PyArg_ParseTuple(args, "O", &z_py)) { + return NULL; + } + + z_arr = PyArray_FROMANY(z_py, @ITYPE@, 0, 0, NPY_ARRAY_CARRAY_RO); + if (z_arr == NULL) { + return NULL; + } + + w_arr = PyArray_SimpleNew(0, NULL, @OTYPE@); + if (w_arr == NULL) { + Py_DECREF(z_arr); + return NULL; + } + + *(@otype@*)PyArray_DATA((PyArrayObject *)w_arr) = + npy_@name@@suffix@(*(@itype@*)PyArray_DATA((PyArrayObject *)z_arr)); + + Py_DECREF(z_arr); + return w_arr; +} + +/**end repeat1**/ + +/**end repeat**/ + +/**begin repeat + * #name = log10, cosh, sinh, tan, tanh# + */ + +/**begin repeat1 + * #type = npy_float, npy_double, npy_longdouble# + * #TYPE = NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE# + * #suffix= f, , l# + */ + +static PyObject * +call_npy_@name@@suffix@(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyObject *z_py = NULL, *z_arr = NULL, *w_arr = NULL; + + if (!PyArg_ParseTuple(args, "O", &z_py)) { + return NULL; + } + + z_arr = PyArray_FROMANY(z_py, @TYPE@, 0, 0, NPY_ARRAY_CARRAY_RO); + if (z_arr == NULL) { + return NULL; + } + + w_arr = PyArray_SimpleNew(0, NULL, @TYPE@); + if (w_arr == NULL) { + Py_DECREF(z_arr); + return NULL; + } + + *(@type@*)PyArray_DATA((PyArrayObject *)w_arr) = + npy_@name@@suffix@(*(@type@*)PyArray_DATA((PyArrayObject *)z_arr)); + + Py_DECREF(z_arr); + return w_arr; +} + +/**end repeat1**/ + +/**end repeat**/ + + +static PyMethodDef Multiarray_TestsMethods[] = { + {"IsPythonScalar", + IsPythonScalar, + METH_VARARGS, NULL}, + {"test_neighborhood_iterator", + test_neighborhood_iterator, + METH_VARARGS, NULL}, + {"test_neighborhood_iterator_oob", + test_neighborhood_iterator_oob, + METH_VARARGS, NULL}, + {"test_pydatamem_seteventhook_start", + test_pydatamem_seteventhook_start, + METH_NOARGS, NULL}, + {"test_pydatamem_seteventhook_end", + test_pydatamem_seteventhook_end, + METH_NOARGS, NULL}, + {"test_inplace_increment", + inplace_increment, + METH_VARARGS, NULL}, + {"incref_elide", + incref_elide, + METH_VARARGS, NULL}, + {"incref_elide_l", + incref_elide_l, + METH_VARARGS, NULL}, + {"npy_char_deprecation", + npy_char_deprecation, + METH_NOARGS, NULL}, + {"npy_updateifcopy_deprecation", + npy_updateifcopy_deprecation, + METH_O, NULL}, + {"npy_create_writebackifcopy", + npy_create_writebackifcopy, + METH_O, NULL}, + {"npy_resolve", + npy_resolve, + METH_O, NULL}, + {"npy_discard", + npy_discard, + METH_O, NULL}, +#if !defined(NPY_PY3K) + {"test_int_subclass", + int_subclass, + METH_VARARGS, NULL}, +#endif + {"get_buffer_info", + get_buffer_info, + METH_VARARGS, NULL}, + {"array_indexing", + array_indexing, + METH_VARARGS, NULL}, + {"test_as_c_array", + test_as_c_array, + METH_VARARGS, NULL}, + {"test_nditer_too_large", + test_nditer_too_large, + METH_VARARGS, NULL}, + {"solve_diophantine", + (PyCFunction)array_solve_diophantine, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"internal_overlap", + (PyCFunction)array_internal_overlap, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"extint_safe_binop", + extint_safe_binop, + METH_VARARGS, NULL}, + {"extint_to_128", + extint_to_128, + METH_VARARGS, NULL}, + {"extint_to_64", + extint_to_64, + METH_VARARGS, NULL}, + {"extint_mul_64_64", + extint_mul_64_64, + METH_VARARGS, NULL}, + {"extint_add_128", + extint_add_128, + METH_VARARGS, NULL}, + {"extint_sub_128", + extint_sub_128, + METH_VARARGS, NULL}, + {"extint_neg_128", + extint_neg_128, + METH_VARARGS, NULL}, + {"extint_shl_128", + extint_shl_128, + METH_VARARGS, NULL}, + {"extint_shr_128", + extint_shr_128, + METH_VARARGS, NULL}, + {"extint_gt_128", + extint_gt_128, + METH_VARARGS, NULL}, + {"extint_divmod_128_64", + extint_divmod_128_64, + METH_VARARGS, NULL}, + {"extint_floordiv_128_64", + extint_floordiv_128_64, + METH_VARARGS, NULL}, + {"extint_ceildiv_128_64", + extint_ceildiv_128_64, + METH_VARARGS, NULL}, + {"get_fpu_mode", + get_fpu_mode, + METH_VARARGS, get_fpu_mode_doc}, +/**begin repeat + * #name = cabs, carg# + */ + +/**begin repeat1 + * #suffix = f, , l# + */ + {"npy_@name@@suffix@", + call_npy_@name@@suffix@, + METH_VARARGS, NULL}, +/**end repeat1**/ + +/**end repeat**/ + +/**begin repeat + * #name = log10, cosh, sinh, tan, tanh# + */ + +/**begin repeat1 + * #suffix= f, , l# + */ + {"npy_@name@@suffix@", + call_npy_@name@@suffix@, + METH_VARARGS, NULL}, +/**end repeat1**/ + +/**end repeat**/ + + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "multiarray_tests", + NULL, + -1, + Multiarray_TestsMethods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#if defined(NPY_PY3K) +#define RETVAL m +PyMODINIT_FUNC PyInit_multiarray_tests(void) +#else +#define RETVAL +PyMODINIT_FUNC +initmultiarray_tests(void) +#endif +{ + PyObject *m; + +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("multiarray_tests", Multiarray_TestsMethods); +#endif + if (m == NULL) { + return RETVAL; + } + import_array(); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot load umath_tests module."); + } + return RETVAL; +} diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c new file mode 100644 index 0000000..8e7352e --- /dev/null +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -0,0 +1,4897 @@ +/* + Python Multiarray Module -- A useful collection of functions for creating and + using ndarrays + + Original file + Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu + + Modified for numpy in 2005 + + Travis E. Oliphant + oliphant@ee.byu.edu + Brigham Young University +*/ + +/* $Id: multiarraymodule.c,v 1.36 2005/09/14 00:14:00 teoliphant Exp $ */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "numpy/npy_math.h" + +#include "npy_config.h" +#include "npy_pycompat.h" +#include "npy_import.h" + +NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0; + +/* Internal APIs */ +#include "arraytypes.h" +#include "arrayobject.h" +#include "hashdescr.h" +#include "descriptor.h" +#include "dragon4.h" +#include "calculation.h" +#include "number.h" +#include "scalartypes.h" +#include "convert_datatype.h" +#include "conversion_utils.h" +#include "nditer_pywrap.h" +#include "methods.h" +#include "_datetime.h" +#include "datetime_strings.h" +#include "datetime_busday.h" +#include "datetime_busdaycal.h" +#include "item_selection.h" +#include "shape.h" +#include "ctors.h" +#include "array_assign.h" +#include "common.h" +#include "ufunc_override.h" +#include "multiarraymodule.h" +#include "cblasfuncs.h" +#include "vdot.h" +#include "templ_common.h" /* for npy_mul_with_overflow_intp */ +#include "compiled_base.h" +#include "mem_overlap.h" +#include "alloc.h" + +#include "get_attr_string.h" + +/* + * global variable to determine if legacy printing is enabled, accessible from + * C. For simplicity the mode is encoded as an integer where '0' means no + * legacy mode, and '113' means 1.13 legacy mode. We can upgrade this if we + * have more complex requirements in the future. + */ +int npy_legacy_print_mode = 0; + +static PyObject * +set_legacy_print_mode(PyObject *NPY_UNUSED(self), PyObject *args) +{ + if (!PyArg_ParseTuple(args, "i", &npy_legacy_print_mode)) { + return NULL; + } + Py_RETURN_NONE; +} + + +/* Only here for API compatibility */ +NPY_NO_EXPORT PyTypeObject PyBigArray_Type; + + +/*NUMPY_API + * Get Priority from object + */ +NPY_NO_EXPORT double +PyArray_GetPriority(PyObject *obj, double default_) +{ + PyObject *ret; + double priority = NPY_PRIORITY; + + if (PyArray_CheckExact(obj)) { + return priority; + } + else if (PyArray_CheckAnyScalarExact(obj)) { + return NPY_SCALAR_PRIORITY; + } + + ret = PyArray_LookupSpecial_OnInstance(obj, "__array_priority__"); + if (ret == NULL) { + return default_; + } + + priority = PyFloat_AsDouble(ret); + Py_DECREF(ret); + return priority; +} + +/*NUMPY_API + * Multiply a List of ints + */ +NPY_NO_EXPORT int +PyArray_MultiplyIntList(int *l1, int n) +{ + int s = 1; + + while (n--) { + s *= (*l1++); + } + return s; +} + +/*NUMPY_API + * Multiply a List + */ +NPY_NO_EXPORT npy_intp +PyArray_MultiplyList(npy_intp *l1, int n) +{ + npy_intp s = 1; + + while (n--) { + s *= (*l1++); + } + return s; +} + +/*NUMPY_API + * Multiply a List of Non-negative numbers with over-flow detection. + */ +NPY_NO_EXPORT npy_intp +PyArray_OverflowMultiplyList(npy_intp *l1, int n) +{ + npy_intp prod = 1; + int i; + + for (i = 0; i < n; i++) { + npy_intp dim = l1[i]; + + if (dim == 0) { + return 0; + } + if (npy_mul_with_overflow_intp(&prod, prod, dim)) { + return -1; + } + } + return prod; +} + +/*NUMPY_API + * Produce a pointer into array + */ +NPY_NO_EXPORT void * +PyArray_GetPtr(PyArrayObject *obj, npy_intp* ind) +{ + int n = PyArray_NDIM(obj); + npy_intp *strides = PyArray_STRIDES(obj); + char *dptr = PyArray_DATA(obj); + + while (n--) { + dptr += (*strides++) * (*ind++); + } + return (void *)dptr; +} + +/*NUMPY_API + * Compare Lists + */ +NPY_NO_EXPORT int +PyArray_CompareLists(npy_intp *l1, npy_intp *l2, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if (l1[i] != l2[i]) { + return 0; + } + } + return 1; +} + +/* + * simulates a C-style 1-3 dimensional array which can be accesed using + * ptr[i] or ptr[i][j] or ptr[i][j][k] -- requires pointer allocation + * for 2-d and 3-d. + * + * For 2-d and up, ptr is NOT equivalent to a statically defined + * 2-d or 3-d array. In particular, it cannot be passed into a + * function that requires a true pointer to a fixed-size array. + */ + +/*NUMPY_API + * Simulate a C-array + * steals a reference to typedescr -- can be NULL + */ +NPY_NO_EXPORT int +PyArray_AsCArray(PyObject **op, void *ptr, npy_intp *dims, int nd, + PyArray_Descr* typedescr) +{ + PyArrayObject *ap; + npy_intp n, m, i, j; + char **ptr2; + char ***ptr3; + + if ((nd < 1) || (nd > 3)) { + PyErr_SetString(PyExc_ValueError, + "C arrays of only 1-3 dimensions available"); + Py_XDECREF(typedescr); + return -1; + } + if ((ap = (PyArrayObject*)PyArray_FromAny(*op, typedescr, nd, nd, + NPY_ARRAY_CARRAY, NULL)) == NULL) { + return -1; + } + switch(nd) { + case 1: + *((char **)ptr) = PyArray_DATA(ap); + break; + case 2: + n = PyArray_DIMS(ap)[0]; + ptr2 = (char **)PyArray_malloc(n * sizeof(char *)); + if (!ptr2) { + goto fail; + } + for (i = 0; i < n; i++) { + ptr2[i] = PyArray_BYTES(ap) + i*PyArray_STRIDES(ap)[0]; + } + *((char ***)ptr) = ptr2; + break; + case 3: + n = PyArray_DIMS(ap)[0]; + m = PyArray_DIMS(ap)[1]; + ptr3 = (char ***)PyArray_malloc(n*(m+1) * sizeof(char *)); + if (!ptr3) { + goto fail; + } + for (i = 0; i < n; i++) { + ptr3[i] = (char **) &ptr3[n + m * i]; + for (j = 0; j < m; j++) { + ptr3[i][j] = PyArray_BYTES(ap) + i*PyArray_STRIDES(ap)[0] + j*PyArray_STRIDES(ap)[1]; + } + } + *((char ****)ptr) = ptr3; + } + memcpy(dims, PyArray_DIMS(ap), nd*sizeof(npy_intp)); + *op = (PyObject *)ap; + return 0; + +fail: + PyErr_SetString(PyExc_MemoryError, "no memory"); + return -1; +} + +/* Deprecated --- Use PyArray_AsCArray instead */ + +/*NUMPY_API + * Convert to a 1D C-array + */ +NPY_NO_EXPORT int +PyArray_As1D(PyObject **op, char **ptr, int *d1, int typecode) +{ + npy_intp newd1; + PyArray_Descr *descr; + static const char msg[] = "PyArray_As1D: use PyArray_AsCArray."; + + /* 2008-07-14, 1.5 */ + if (DEPRECATE(msg) < 0) { + return -1; + } + descr = PyArray_DescrFromType(typecode); + if (PyArray_AsCArray(op, (void *)ptr, &newd1, 1, descr) == -1) { + return -1; + } + *d1 = (int) newd1; + return 0; +} + +/*NUMPY_API + * Convert to a 2D C-array + */ +NPY_NO_EXPORT int +PyArray_As2D(PyObject **op, char ***ptr, int *d1, int *d2, int typecode) +{ + npy_intp newdims[2]; + PyArray_Descr *descr; + static const char msg[] = "PyArray_As1D: use PyArray_AsCArray."; + + /* 2008-07-14, 1.5 */ + if (DEPRECATE(msg) < 0) { + return -1; + } + descr = PyArray_DescrFromType(typecode); + if (PyArray_AsCArray(op, (void *)ptr, newdims, 2, descr) == -1) { + return -1; + } + *d1 = (int ) newdims[0]; + *d2 = (int ) newdims[1]; + return 0; +} + +/* End Deprecated */ + +/*NUMPY_API + * Free pointers created if As2D is called + */ +NPY_NO_EXPORT int +PyArray_Free(PyObject *op, void *ptr) +{ + PyArrayObject *ap = (PyArrayObject *)op; + + if ((PyArray_NDIM(ap) < 1) || (PyArray_NDIM(ap) > 3)) { + return -1; + } + if (PyArray_NDIM(ap) >= 2) { + PyArray_free(ptr); + } + Py_DECREF(ap); + return 0; +} + +/* + * Get the ndarray subclass with the highest priority + */ +NPY_NO_EXPORT PyTypeObject * +PyArray_GetSubType(int narrays, PyArrayObject **arrays) { + PyTypeObject *subtype = &PyArray_Type; + double priority = NPY_PRIORITY; + int i; + + /* Get the priority subtype for the array */ + for (i = 0; i < narrays; ++i) { + if (Py_TYPE(arrays[i]) != subtype) { + double pr = PyArray_GetPriority((PyObject *)(arrays[i]), 0.0); + if (pr > priority) { + priority = pr; + subtype = Py_TYPE(arrays[i]); + } + } + } + + return subtype; +} + + +/* + * Concatenates a list of ndarrays. + */ +NPY_NO_EXPORT PyArrayObject * +PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis, + PyArrayObject* ret) +{ + int iarrays, idim, ndim; + npy_intp shape[NPY_MAXDIMS]; + PyArrayObject_fields *sliding_view = NULL; + + if (narrays <= 0) { + PyErr_SetString(PyExc_ValueError, + "need at least one array to concatenate"); + return NULL; + } + + /* All the arrays must have the same 'ndim' */ + ndim = PyArray_NDIM(arrays[0]); + + if (ndim == 0) { + PyErr_SetString(PyExc_ValueError, + "zero-dimensional arrays cannot be concatenated"); + return NULL; + } + + /* Handle standard Python negative indexing */ + if (check_and_adjust_axis(&axis, ndim) < 0) { + return NULL; + } + + /* + * Figure out the final concatenated shape starting from the first + * array's shape. + */ + memcpy(shape, PyArray_SHAPE(arrays[0]), ndim * sizeof(shape[0])); + for (iarrays = 1; iarrays < narrays; ++iarrays) { + npy_intp *arr_shape; + + if (PyArray_NDIM(arrays[iarrays]) != ndim) { + PyErr_SetString(PyExc_ValueError, + "all the input arrays must have same " + "number of dimensions"); + return NULL; + } + arr_shape = PyArray_SHAPE(arrays[iarrays]); + + for (idim = 0; idim < ndim; ++idim) { + /* Build up the size of the concatenation axis */ + if (idim == axis) { + shape[idim] += arr_shape[idim]; + } + /* Validate that the rest of the dimensions match */ + else if (shape[idim] != arr_shape[idim]) { + PyErr_SetString(PyExc_ValueError, + "all the input array dimensions " + "except for the concatenation axis " + "must match exactly"); + return NULL; + } + } + } + + if (ret != NULL) { + if (PyArray_NDIM(ret) != ndim) { + PyErr_SetString(PyExc_ValueError, + "Output array has wrong dimensionality"); + return NULL; + } + if (!PyArray_CompareLists(shape, PyArray_SHAPE(ret), ndim)) { + PyErr_SetString(PyExc_ValueError, + "Output array is the wrong shape"); + return NULL; + } + Py_INCREF(ret); + } + else { + npy_intp s, strides[NPY_MAXDIMS]; + int strideperm[NPY_MAXDIMS]; + + /* Get the priority subtype for the array */ + PyTypeObject *subtype = PyArray_GetSubType(narrays, arrays); + + /* Get the resulting dtype from combining all the arrays */ + PyArray_Descr *dtype = PyArray_ResultType(narrays, arrays, 0, NULL); + if (dtype == NULL) { + return NULL; + } + + /* + * Figure out the permutation to apply to the strides to match + * the memory layout of the input arrays, using ambiguity + * resolution rules matching that of the NpyIter. + */ + PyArray_CreateMultiSortedStridePerm(narrays, arrays, ndim, strideperm); + s = dtype->elsize; + for (idim = ndim-1; idim >= 0; --idim) { + int iperm = strideperm[idim]; + strides[iperm] = s; + s *= shape[iperm]; + } + + /* Allocate the array for the result. This steals the 'dtype' reference. */ + ret = (PyArrayObject *)PyArray_NewFromDescr(subtype, + dtype, + ndim, + shape, + strides, + NULL, + 0, + NULL); + if (ret == NULL) { + return NULL; + } + } + + /* + * Create a view which slides through ret for assigning the + * successive input arrays. + */ + sliding_view = (PyArrayObject_fields *)PyArray_View(ret, + NULL, &PyArray_Type); + if (sliding_view == NULL) { + Py_DECREF(ret); + return NULL; + } + for (iarrays = 0; iarrays < narrays; ++iarrays) { + /* Set the dimension to match the input array's */ + sliding_view->dimensions[axis] = PyArray_SHAPE(arrays[iarrays])[axis]; + + /* Copy the data for this array */ + if (PyArray_AssignArray((PyArrayObject *)sliding_view, arrays[iarrays], + NULL, NPY_SAME_KIND_CASTING) < 0) { + Py_DECREF(sliding_view); + Py_DECREF(ret); + return NULL; + } + + /* Slide to the start of the next window */ + sliding_view->data += sliding_view->dimensions[axis] * + sliding_view->strides[axis]; + } + + Py_DECREF(sliding_view); + return ret; +} + +/* + * Concatenates a list of ndarrays, flattening each in the specified order. + */ +NPY_NO_EXPORT PyArrayObject * +PyArray_ConcatenateFlattenedArrays(int narrays, PyArrayObject **arrays, + NPY_ORDER order, PyArrayObject *ret) +{ + int iarrays; + npy_intp shape = 0; + PyArrayObject_fields *sliding_view = NULL; + + if (narrays <= 0) { + PyErr_SetString(PyExc_ValueError, + "need at least one array to concatenate"); + return NULL; + } + + /* + * Figure out the final concatenated shape starting from the first + * array's shape. + */ + for (iarrays = 0; iarrays < narrays; ++iarrays) { + shape += PyArray_SIZE(arrays[iarrays]); + /* Check for overflow */ + if (shape < 0) { + PyErr_SetString(PyExc_ValueError, + "total number of elements " + "too large to concatenate"); + return NULL; + } + } + + if (ret != NULL) { + if (PyArray_NDIM(ret) != 1) { + PyErr_SetString(PyExc_ValueError, + "Output array must be 1D"); + return NULL; + } + if (shape != PyArray_SIZE(ret)) { + PyErr_SetString(PyExc_ValueError, + "Output array is the wrong size"); + return NULL; + } + Py_INCREF(ret); + } + else { + npy_intp stride; + + /* Get the priority subtype for the array */ + PyTypeObject *subtype = PyArray_GetSubType(narrays, arrays); + + /* Get the resulting dtype from combining all the arrays */ + PyArray_Descr *dtype = PyArray_ResultType(narrays, arrays, 0, NULL); + if (dtype == NULL) { + return NULL; + } + + stride = dtype->elsize; + + /* Allocate the array for the result. This steals the 'dtype' reference. */ + ret = (PyArrayObject *)PyArray_NewFromDescr(subtype, + dtype, + 1, + &shape, + &stride, + NULL, + 0, + NULL); + if (ret == NULL) { + return NULL; + } + } + + /* + * Create a view which slides through ret for assigning the + * successive input arrays. + */ + sliding_view = (PyArrayObject_fields *)PyArray_View(ret, + NULL, &PyArray_Type); + if (sliding_view == NULL) { + Py_DECREF(ret); + return NULL; + } + + for (iarrays = 0; iarrays < narrays; ++iarrays) { + /* Adjust the window dimensions for this array */ + sliding_view->dimensions[0] = PyArray_SIZE(arrays[iarrays]); + + /* Copy the data for this array */ + if (PyArray_CopyAsFlat((PyArrayObject *)sliding_view, arrays[iarrays], + order) < 0) { + Py_DECREF(sliding_view); + Py_DECREF(ret); + return NULL; + } + + /* Slide to the start of the next window */ + sliding_view->data += + sliding_view->strides[0] * PyArray_SIZE(arrays[iarrays]); + } + + Py_DECREF(sliding_view); + return ret; +} + +NPY_NO_EXPORT PyObject * +PyArray_ConcatenateInto(PyObject *op, int axis, PyArrayObject *ret) +{ + int iarrays, narrays; + PyArrayObject **arrays; + + if (!PySequence_Check(op)) { + PyErr_SetString(PyExc_TypeError, + "The first input argument needs to be a sequence"); + return NULL; + } + + /* Convert the input list into arrays */ + narrays = PySequence_Size(op); + if (narrays < 0) { + return NULL; + } + arrays = PyArray_malloc(narrays * sizeof(arrays[0])); + if (arrays == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (iarrays = 0; iarrays < narrays; ++iarrays) { + PyObject *item = PySequence_GetItem(op, iarrays); + if (item == NULL) { + narrays = iarrays; + goto fail; + } + arrays[iarrays] = (PyArrayObject *)PyArray_FROM_O(item); + Py_DECREF(item); + if (arrays[iarrays] == NULL) { + narrays = iarrays; + goto fail; + } + } + + if (axis >= NPY_MAXDIMS) { + ret = PyArray_ConcatenateFlattenedArrays(narrays, arrays, NPY_CORDER, ret); + } + else { + ret = PyArray_ConcatenateArrays(narrays, arrays, axis, ret); + } + + for (iarrays = 0; iarrays < narrays; ++iarrays) { + Py_DECREF(arrays[iarrays]); + } + PyArray_free(arrays); + + return (PyObject *)ret; + +fail: + /* 'narrays' was set to how far we got in the conversion */ + for (iarrays = 0; iarrays < narrays; ++iarrays) { + Py_DECREF(arrays[iarrays]); + } + PyArray_free(arrays); + + return NULL; +} + +/*NUMPY_API + * Concatenate + * + * Concatenate an arbitrary Python sequence into an array. + * op is a python object supporting the sequence interface. + * Its elements will be concatenated together to form a single + * multidimensional array. If axis is NPY_MAXDIMS or bigger, then + * each sequence object will be flattened before concatenation +*/ +NPY_NO_EXPORT PyObject * +PyArray_Concatenate(PyObject *op, int axis) +{ + return PyArray_ConcatenateInto(op, axis, NULL); +} + +static int +_signbit_set(PyArrayObject *arr) +{ + static char bitmask = (char) 0x80; + char *ptr; /* points to the npy_byte to test */ + char byteorder; + int elsize; + + elsize = PyArray_DESCR(arr)->elsize; + byteorder = PyArray_DESCR(arr)->byteorder; + ptr = PyArray_DATA(arr); + if (elsize > 1 && + (byteorder == NPY_LITTLE || + (byteorder == NPY_NATIVE && + PyArray_ISNBO(NPY_LITTLE)))) { + ptr += elsize - 1; + } + return ((*ptr & bitmask) != 0); +} + + +/*NUMPY_API + * ScalarKind + * + * Returns the scalar kind of a type number, with an + * optional tweak based on the scalar value itself. + * If no scalar is provided, it returns INTPOS_SCALAR + * for both signed and unsigned integers, otherwise + * it checks the sign of any signed integer to choose + * INTNEG_SCALAR when appropriate. + */ +NPY_NO_EXPORT NPY_SCALARKIND +PyArray_ScalarKind(int typenum, PyArrayObject **arr) +{ + NPY_SCALARKIND ret = NPY_NOSCALAR; + + if ((unsigned int)typenum < NPY_NTYPES) { + ret = _npy_scalar_kinds_table[typenum]; + /* Signed integer types are INTNEG in the table */ + if (ret == NPY_INTNEG_SCALAR) { + if (!arr || !_signbit_set(*arr)) { + ret = NPY_INTPOS_SCALAR; + } + } + } else if (PyTypeNum_ISUSERDEF(typenum)) { + PyArray_Descr* descr = PyArray_DescrFromType(typenum); + + if (descr->f->scalarkind) { + ret = descr->f->scalarkind((arr ? *arr : NULL)); + } + Py_DECREF(descr); + } + + return ret; +} + +/*NUMPY_API + * + * Determines whether the data type 'thistype', with + * scalar kind 'scalar', can be coerced into 'neededtype'. + */ +NPY_NO_EXPORT int +PyArray_CanCoerceScalar(int thistype, int neededtype, + NPY_SCALARKIND scalar) +{ + PyArray_Descr* from; + int *castlist; + + /* If 'thistype' is not a scalar, it must be safely castable */ + if (scalar == NPY_NOSCALAR) { + return PyArray_CanCastSafely(thistype, neededtype); + } + if ((unsigned int)neededtype < NPY_NTYPES) { + NPY_SCALARKIND neededscalar; + + if (scalar == NPY_OBJECT_SCALAR) { + return PyArray_CanCastSafely(thistype, neededtype); + } + + /* + * The lookup table gives us exactly what we need for + * this comparison, which PyArray_ScalarKind would not. + * + * The rule is that positive scalars can be coerced + * to a signed ints, but negative scalars cannot be coerced + * to unsigned ints. + * _npy_scalar_kinds_table[int]==NEGINT > POSINT, + * so 1 is returned, but + * _npy_scalar_kinds_table[uint]==POSINT < NEGINT, + * so 0 is returned, as required. + * + */ + neededscalar = _npy_scalar_kinds_table[neededtype]; + if (neededscalar >= scalar) { + return 1; + } + if (!PyTypeNum_ISUSERDEF(thistype)) { + return 0; + } + } + + from = PyArray_DescrFromType(thistype); + if (from->f->cancastscalarkindto + && (castlist = from->f->cancastscalarkindto[scalar])) { + while (*castlist != NPY_NOTYPE) { + if (*castlist++ == neededtype) { + Py_DECREF(from); + return 1; + } + } + } + Py_DECREF(from); + + return 0; +} + +/* + * Make a new empty array, of the passed size, of a type that takes the + * priority of ap1 and ap2 into account. + * + * If `out` is non-NULL, memory overlap is checked with ap1 and ap2, and an + * updateifcopy temporary array may be returned. If `result` is non-NULL, the + * output array to be returned (`out` if non-NULL and the newly allocated array + * otherwise) is incref'd and put to *result. + */ +static PyArrayObject * +new_array_for_sum(PyArrayObject *ap1, PyArrayObject *ap2, PyArrayObject* out, + int nd, npy_intp dimensions[], int typenum, PyArrayObject **result) +{ + PyArrayObject *out_buf; + + if (out) { + int d; + + /* verify that out is usable */ + if (PyArray_NDIM(out) != nd || + PyArray_TYPE(out) != typenum || + !PyArray_ISCARRAY(out)) { + PyErr_SetString(PyExc_ValueError, + "output array is not acceptable (must have the right datatype, " + "number of dimensions, and be a C-Array)"); + return 0; + } + for (d = 0; d < nd; ++d) { + if (dimensions[d] != PyArray_DIM(out, d)) { + PyErr_SetString(PyExc_ValueError, + "output array has wrong dimensions"); + return 0; + } + } + + /* check for memory overlap */ + if (!(solve_may_share_memory(out, ap1, 1) == 0 && + solve_may_share_memory(out, ap2, 1) == 0)) { + /* allocate temporary output array */ + out_buf = (PyArrayObject *)PyArray_NewLikeArray(out, NPY_CORDER, + NULL, 0); + if (out_buf == NULL) { + return NULL; + } + + /* set copy-back */ + Py_INCREF(out); + if (PyArray_SetWritebackIfCopyBase(out_buf, out) < 0) { + Py_DECREF(out); + Py_DECREF(out_buf); + return NULL; + } + } + else { + Py_INCREF(out); + out_buf = out; + } + + if (result) { + Py_INCREF(out); + *result = out; + } + + return out_buf; + } + else { + PyTypeObject *subtype; + double prior1, prior2; + /* + * Need to choose an output array that can hold a sum + * -- use priority to determine which subtype. + */ + if (Py_TYPE(ap2) != Py_TYPE(ap1)) { + prior2 = PyArray_GetPriority((PyObject *)ap2, 0.0); + prior1 = PyArray_GetPriority((PyObject *)ap1, 0.0); + subtype = (prior2 > prior1 ? Py_TYPE(ap2) : Py_TYPE(ap1)); + } + else { + prior1 = prior2 = 0.0; + subtype = Py_TYPE(ap1); + } + + out_buf = (PyArrayObject *)PyArray_New(subtype, nd, dimensions, + typenum, NULL, NULL, 0, 0, + (PyObject *) + (prior2 > prior1 ? ap2 : ap1)); + + if (out_buf != NULL && result) { + Py_INCREF(out_buf); + *result = out_buf; + } + + return out_buf; + } +} + +/* Could perhaps be redone to not make contiguous arrays */ + +/*NUMPY_API + * Numeric.innerproduct(a,v) + */ +NPY_NO_EXPORT PyObject * +PyArray_InnerProduct(PyObject *op1, PyObject *op2) +{ + PyArrayObject *ap1 = NULL; + PyArrayObject *ap2 = NULL; + int typenum; + PyArray_Descr *typec = NULL; + PyObject* ap2t = NULL; + npy_intp dims[NPY_MAXDIMS]; + PyArray_Dims newaxes = {dims, 0}; + int i; + PyObject* ret = NULL; + + typenum = PyArray_ObjectType(op1, 0); + typenum = PyArray_ObjectType(op2, typenum); + typec = PyArray_DescrFromType(typenum); + if (typec == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot find a common data type."); + goto fail; + } + + Py_INCREF(typec); + ap1 = (PyArrayObject *)PyArray_FromAny(op1, typec, 0, 0, + NPY_ARRAY_ALIGNED, NULL); + if (ap1 == NULL) { + Py_DECREF(typec); + goto fail; + } + ap2 = (PyArrayObject *)PyArray_FromAny(op2, typec, 0, 0, + NPY_ARRAY_ALIGNED, NULL); + if (ap2 == NULL) { + goto fail; + } + + newaxes.len = PyArray_NDIM(ap2); + if ((PyArray_NDIM(ap1) >= 1) && (newaxes.len >= 2)) { + for (i = 0; i < newaxes.len - 2; i++) { + dims[i] = (npy_intp)i; + } + dims[newaxes.len - 2] = newaxes.len - 1; + dims[newaxes.len - 1] = newaxes.len - 2; + + ap2t = PyArray_Transpose(ap2, &newaxes); + if (ap2t == NULL) { + goto fail; + } + } + else { + ap2t = (PyObject *)ap2; + Py_INCREF(ap2); + } + + ret = PyArray_MatrixProduct2((PyObject *)ap1, ap2t, NULL); + if (ret == NULL) { + goto fail; + } + + + Py_DECREF(ap1); + Py_DECREF(ap2); + Py_DECREF(ap2t); + return ret; + +fail: + Py_XDECREF(ap1); + Py_XDECREF(ap2); + Py_XDECREF(ap2t); + Py_XDECREF(ret); + return NULL; +} + +/*NUMPY_API + * Numeric.matrixproduct(a,v) + * just like inner product but does the swapaxes stuff on the fly + */ +NPY_NO_EXPORT PyObject * +PyArray_MatrixProduct(PyObject *op1, PyObject *op2) +{ + return PyArray_MatrixProduct2(op1, op2, NULL); +} + +/*NUMPY_API + * Numeric.matrixproduct2(a,v,out) + * just like inner product but does the swapaxes stuff on the fly + */ +NPY_NO_EXPORT PyObject * +PyArray_MatrixProduct2(PyObject *op1, PyObject *op2, PyArrayObject* out) +{ + PyArrayObject *ap1, *ap2, *out_buf = NULL, *result = NULL; + PyArrayIterObject *it1, *it2; + npy_intp i, j, l; + int typenum, nd, axis, matchDim; + npy_intp is1, is2, os; + char *op; + npy_intp dimensions[NPY_MAXDIMS]; + PyArray_DotFunc *dot; + PyArray_Descr *typec = NULL; + NPY_BEGIN_THREADS_DEF; + + typenum = PyArray_ObjectType(op1, 0); + typenum = PyArray_ObjectType(op2, typenum); + typec = PyArray_DescrFromType(typenum); + if (typec == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot find a common data type."); + return NULL; + } + + Py_INCREF(typec); + ap1 = (PyArrayObject *)PyArray_FromAny(op1, typec, 0, 0, + NPY_ARRAY_ALIGNED, NULL); + if (ap1 == NULL) { + Py_DECREF(typec); + return NULL; + } + ap2 = (PyArrayObject *)PyArray_FromAny(op2, typec, 0, 0, + NPY_ARRAY_ALIGNED, NULL); + if (ap2 == NULL) { + Py_DECREF(ap1); + return NULL; + } + +#if defined(HAVE_CBLAS) + if (PyArray_NDIM(ap1) <= 2 && PyArray_NDIM(ap2) <= 2 && + (NPY_DOUBLE == typenum || NPY_CDOUBLE == typenum || + NPY_FLOAT == typenum || NPY_CFLOAT == typenum)) { + return cblas_matrixproduct(typenum, ap1, ap2, out); + } +#endif + + if (PyArray_NDIM(ap1) == 0 || PyArray_NDIM(ap2) == 0) { + result = (PyArray_NDIM(ap1) == 0 ? ap1 : ap2); + result = (PyArrayObject *)Py_TYPE(result)->tp_as_number->nb_multiply( + (PyObject *)ap1, (PyObject *)ap2); + Py_DECREF(ap1); + Py_DECREF(ap2); + return (PyObject *)result; + } + l = PyArray_DIMS(ap1)[PyArray_NDIM(ap1) - 1]; + if (PyArray_NDIM(ap2) > 1) { + matchDim = PyArray_NDIM(ap2) - 2; + } + else { + matchDim = 0; + } + if (PyArray_DIMS(ap2)[matchDim] != l) { + dot_alignment_error(ap1, PyArray_NDIM(ap1) - 1, ap2, matchDim); + goto fail; + } + nd = PyArray_NDIM(ap1) + PyArray_NDIM(ap2) - 2; + if (nd > NPY_MAXDIMS) { + PyErr_SetString(PyExc_ValueError, "dot: too many dimensions in result"); + goto fail; + } + j = 0; + for (i = 0; i < PyArray_NDIM(ap1) - 1; i++) { + dimensions[j++] = PyArray_DIMS(ap1)[i]; + } + for (i = 0; i < PyArray_NDIM(ap2) - 2; i++) { + dimensions[j++] = PyArray_DIMS(ap2)[i]; + } + if(PyArray_NDIM(ap2) > 1) { + dimensions[j++] = PyArray_DIMS(ap2)[PyArray_NDIM(ap2)-1]; + } + + is1 = PyArray_STRIDES(ap1)[PyArray_NDIM(ap1)-1]; + is2 = PyArray_STRIDES(ap2)[matchDim]; + /* Choose which subtype to return */ + out_buf = new_array_for_sum(ap1, ap2, out, nd, dimensions, typenum, &result); + if (out_buf == NULL) { + goto fail; + } + /* Ensure that multiarray.dot(,<0xM>) -> zeros((N,M)) */ + if (PyArray_SIZE(ap1) == 0 && PyArray_SIZE(ap2) == 0) { + memset(PyArray_DATA(out_buf), 0, PyArray_NBYTES(out_buf)); + } + + dot = PyArray_DESCR(out_buf)->f->dotfunc; + if (dot == NULL) { + PyErr_SetString(PyExc_ValueError, + "dot not available for this type"); + goto fail; + } + + op = PyArray_DATA(out_buf); + os = PyArray_DESCR(out_buf)->elsize; + axis = PyArray_NDIM(ap1)-1; + it1 = (PyArrayIterObject *) + PyArray_IterAllButAxis((PyObject *)ap1, &axis); + if (it1 == NULL) { + goto fail; + } + it2 = (PyArrayIterObject *) + PyArray_IterAllButAxis((PyObject *)ap2, &matchDim); + if (it2 == NULL) { + Py_DECREF(it1); + goto fail; + } + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ap2)); + while (it1->index < it1->size) { + while (it2->index < it2->size) { + dot(it1->dataptr, is1, it2->dataptr, is2, op, l, out_buf); + op += os; + PyArray_ITER_NEXT(it2); + } + PyArray_ITER_NEXT(it1); + PyArray_ITER_RESET(it2); + } + NPY_END_THREADS_DESCR(PyArray_DESCR(ap2)); + Py_DECREF(it1); + Py_DECREF(it2); + if (PyErr_Occurred()) { + /* only for OBJECT arrays */ + goto fail; + } + Py_DECREF(ap1); + Py_DECREF(ap2); + + /* Trigger possible copy-back into `result` */ + PyArray_ResolveWritebackIfCopy(out_buf); + Py_DECREF(out_buf); + + return (PyObject *)result; + +fail: + Py_XDECREF(ap1); + Py_XDECREF(ap2); + Py_XDECREF(out_buf); + Py_XDECREF(result); + return NULL; +} + + +/*NUMPY_API + * Copy and Transpose + * + * Could deprecate this function, as there isn't a speed benefit over + * calling Transpose and then Copy. + */ +NPY_NO_EXPORT PyObject * +PyArray_CopyAndTranspose(PyObject *op) +{ + PyArrayObject *arr, *tmp, *ret; + int i; + npy_intp new_axes_values[NPY_MAXDIMS]; + PyArray_Dims new_axes; + + /* Make sure we have an array */ + arr = (PyArrayObject *)PyArray_FROM_O(op); + if (arr == NULL) { + return NULL; + } + + if (PyArray_NDIM(arr) > 1) { + /* Set up the transpose operation */ + new_axes.len = PyArray_NDIM(arr); + for (i = 0; i < new_axes.len; ++i) { + new_axes_values[i] = new_axes.len - i - 1; + } + new_axes.ptr = new_axes_values; + + /* Do the transpose (always returns a view) */ + tmp = (PyArrayObject *)PyArray_Transpose(arr, &new_axes); + if (tmp == NULL) { + Py_DECREF(arr); + return NULL; + } + } + else { + tmp = arr; + arr = NULL; + } + + /* TODO: Change this to NPY_KEEPORDER for NumPy 2.0 */ + ret = (PyArrayObject *)PyArray_NewCopy(tmp, NPY_CORDER); + + Py_XDECREF(arr); + Py_DECREF(tmp); + return (PyObject *)ret; +} + +/* + * Implementation which is common between PyArray_Correlate + * and PyArray_Correlate2. + * + * inverted is set to 1 if computed correlate(ap2, ap1), 0 otherwise + */ +static PyArrayObject* +_pyarray_correlate(PyArrayObject *ap1, PyArrayObject *ap2, int typenum, + int mode, int *inverted) +{ + PyArrayObject *ret; + npy_intp length; + npy_intp i, n1, n2, n, n_left, n_right; + npy_intp is1, is2, os; + char *ip1, *ip2, *op; + PyArray_DotFunc *dot; + + NPY_BEGIN_THREADS_DEF; + + n1 = PyArray_DIMS(ap1)[0]; + n2 = PyArray_DIMS(ap2)[0]; + if (n1 < n2) { + ret = ap1; + ap1 = ap2; + ap2 = ret; + ret = NULL; + i = n1; + n1 = n2; + n2 = i; + *inverted = 1; + } else { + *inverted = 0; + } + + length = n1; + n = n2; + switch(mode) { + case 0: + length = length - n + 1; + n_left = n_right = 0; + break; + case 1: + n_left = (npy_intp)(n/2); + n_right = n - n_left - 1; + break; + case 2: + n_right = n - 1; + n_left = n - 1; + length = length + n - 1; + break; + default: + PyErr_SetString(PyExc_ValueError, "mode must be 0, 1, or 2"); + return NULL; + } + + /* + * Need to choose an output array that can hold a sum + * -- use priority to determine which subtype. + */ + ret = new_array_for_sum(ap1, ap2, NULL, 1, &length, typenum, NULL); + if (ret == NULL) { + return NULL; + } + dot = PyArray_DESCR(ret)->f->dotfunc; + if (dot == NULL) { + PyErr_SetString(PyExc_ValueError, + "function not available for this data type"); + goto clean_ret; + } + + NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ret)); + is1 = PyArray_STRIDES(ap1)[0]; + is2 = PyArray_STRIDES(ap2)[0]; + op = PyArray_DATA(ret); + os = PyArray_DESCR(ret)->elsize; + ip1 = PyArray_DATA(ap1); + ip2 = PyArray_BYTES(ap2) + n_left*is2; + n = n - n_left; + for (i = 0; i < n_left; i++) { + dot(ip1, is1, ip2, is2, op, n, ret); + n++; + ip2 -= is2; + op += os; + } + if (small_correlate(ip1, is1, n1 - n2 + 1, PyArray_TYPE(ap1), + ip2, is2, n, PyArray_TYPE(ap2), + op, os)) { + ip1 += is1 * (n1 - n2 + 1); + op += os * (n1 - n2 + 1); + } + else { + for (i = 0; i < (n1 - n2 + 1); i++) { + dot(ip1, is1, ip2, is2, op, n, ret); + ip1 += is1; + op += os; + } + } + for (i = 0; i < n_right; i++) { + n--; + dot(ip1, is1, ip2, is2, op, n, ret); + ip1 += is1; + op += os; + } + + NPY_END_THREADS_DESCR(PyArray_DESCR(ret)); + if (PyErr_Occurred()) { + goto clean_ret; + } + + return ret; + +clean_ret: + Py_DECREF(ret); + return NULL; +} + +/* + * Revert a one dimensional array in-place + * + * Return 0 on success, other value on failure + */ +static int +_pyarray_revert(PyArrayObject *ret) +{ + npy_intp length = PyArray_DIM(ret, 0); + npy_intp os = PyArray_DESCR(ret)->elsize; + char *op = PyArray_DATA(ret); + char *sw1 = op; + char *sw2; + + if (PyArray_ISNUMBER(ret) && !PyArray_ISCOMPLEX(ret)) { + /* Optimization for unstructured dtypes */ + PyArray_CopySwapNFunc *copyswapn = PyArray_DESCR(ret)->f->copyswapn; + sw2 = op + length * os - 1; + /* First reverse the whole array byte by byte... */ + while(sw1 < sw2) { + const char tmp = *sw1; + *sw1++ = *sw2; + *sw2-- = tmp; + } + /* ...then swap in place every item */ + copyswapn(op, os, NULL, 0, length, 1, NULL); + } + else { + char *tmp = PyArray_malloc(PyArray_DESCR(ret)->elsize); + if (tmp == NULL) { + return -1; + } + sw2 = op + (length - 1) * os; + while (sw1 < sw2) { + memcpy(tmp, sw1, os); + memcpy(sw1, sw2, os); + memcpy(sw2, tmp, os); + sw1 += os; + sw2 -= os; + } + PyArray_free(tmp); + } + + return 0; +} + +/*NUMPY_API + * correlate(a1,a2,mode) + * + * This function computes the usual correlation (correlate(a1, a2) != + * correlate(a2, a1), and conjugate the second argument for complex inputs + */ +NPY_NO_EXPORT PyObject * +PyArray_Correlate2(PyObject *op1, PyObject *op2, int mode) +{ + PyArrayObject *ap1, *ap2, *ret = NULL; + int typenum; + PyArray_Descr *typec; + int inverted; + int st; + + typenum = PyArray_ObjectType(op1, 0); + typenum = PyArray_ObjectType(op2, typenum); + + typec = PyArray_DescrFromType(typenum); + Py_INCREF(typec); + ap1 = (PyArrayObject *)PyArray_FromAny(op1, typec, 1, 1, + NPY_ARRAY_DEFAULT, NULL); + if (ap1 == NULL) { + Py_DECREF(typec); + return NULL; + } + ap2 = (PyArrayObject *)PyArray_FromAny(op2, typec, 1, 1, + NPY_ARRAY_DEFAULT, NULL); + if (ap2 == NULL) { + goto clean_ap1; + } + + if (PyArray_ISCOMPLEX(ap2)) { + PyArrayObject *cap2; + cap2 = (PyArrayObject *)PyArray_Conjugate(ap2, NULL); + if (cap2 == NULL) { + goto clean_ap2; + } + Py_DECREF(ap2); + ap2 = cap2; + } + + ret = _pyarray_correlate(ap1, ap2, typenum, mode, &inverted); + if (ret == NULL) { + goto clean_ap2; + } + + /* + * If we inverted input orders, we need to reverse the output array (i.e. + * ret = ret[::-1]) + */ + if (inverted) { + st = _pyarray_revert(ret); + if(st) { + goto clean_ret; + } + } + + Py_DECREF(ap1); + Py_DECREF(ap2); + return (PyObject *)ret; + +clean_ret: + Py_DECREF(ret); +clean_ap2: + Py_DECREF(ap2); +clean_ap1: + Py_DECREF(ap1); + return NULL; +} + +/*NUMPY_API + * Numeric.correlate(a1,a2,mode) + */ +NPY_NO_EXPORT PyObject * +PyArray_Correlate(PyObject *op1, PyObject *op2, int mode) +{ + PyArrayObject *ap1, *ap2, *ret = NULL; + int typenum; + int unused; + PyArray_Descr *typec; + + typenum = PyArray_ObjectType(op1, 0); + typenum = PyArray_ObjectType(op2, typenum); + + typec = PyArray_DescrFromType(typenum); + Py_INCREF(typec); + ap1 = (PyArrayObject *)PyArray_FromAny(op1, typec, 1, 1, + NPY_ARRAY_DEFAULT, NULL); + if (ap1 == NULL) { + Py_DECREF(typec); + return NULL; + } + ap2 = (PyArrayObject *)PyArray_FromAny(op2, typec, 1, 1, + NPY_ARRAY_DEFAULT, NULL); + if (ap2 == NULL) { + goto fail; + } + + ret = _pyarray_correlate(ap1, ap2, typenum, mode, &unused); + if(ret == NULL) { + goto fail; + } + Py_DECREF(ap1); + Py_DECREF(ap2); + return (PyObject *)ret; + +fail: + Py_XDECREF(ap1); + Py_XDECREF(ap2); + Py_XDECREF(ret); + return NULL; +} + + +static PyObject * +array_putmask(PyObject *NPY_UNUSED(module), PyObject *args, PyObject *kwds) +{ + PyObject *mask, *values; + PyObject *array; + + static char *kwlist[] = {"arr", "mask", "values", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!OO:putmask", kwlist, + &PyArray_Type, &array, &mask, &values)) { + return NULL; + } + return PyArray_PutMask((PyArrayObject *)array, values, mask); +} + +/* + * Compare the field dictionaries for two types. + * + * Return 1 if the field types and field names of the two descrs are equal and + * in the same order, 0 if not. + */ +static int +_equivalent_fields(PyArray_Descr *type1, PyArray_Descr *type2) { + + int val; + + if (type1->fields == type2->fields && type1->names == type2->names) { + return 1; + } + if (type1->fields == NULL || type2->fields == NULL) { + return 0; + } + + val = PyObject_RichCompareBool(type1->fields, type2->fields, Py_EQ); + if (val != 1 || PyErr_Occurred()) { + PyErr_Clear(); + return 0; + } + + val = PyObject_RichCompareBool(type1->names, type2->names, Py_EQ); + if (val != 1 || PyErr_Occurred()) { + PyErr_Clear(); + return 0; + } + + return 1; +} + +/* + * Compare the subarray data for two types. + * Return 1 if they are the same, 0 if not. + */ +static int +_equivalent_subarrays(PyArray_ArrayDescr *sub1, PyArray_ArrayDescr *sub2) +{ + int val; + + if (sub1 == sub2) { + return 1; + + } + if (sub1 == NULL || sub2 == NULL) { + return 0; + } + + val = PyObject_RichCompareBool(sub1->shape, sub2->shape, Py_EQ); + if (val != 1 || PyErr_Occurred()) { + PyErr_Clear(); + return 0; + } + + return PyArray_EquivTypes(sub1->base, sub2->base); +} + + +/*NUMPY_API + * + * This function returns true if the two typecodes are + * equivalent (same basic kind and same itemsize). + */ +NPY_NO_EXPORT unsigned char +PyArray_EquivTypes(PyArray_Descr *type1, PyArray_Descr *type2) +{ + int type_num1, type_num2, size1, size2; + + if (type1 == type2) { + return NPY_TRUE; + } + + type_num1 = type1->type_num; + type_num2 = type2->type_num; + size1 = type1->elsize; + size2 = type2->elsize; + + if (size1 != size2) { + return NPY_FALSE; + } + if (PyArray_ISNBO(type1->byteorder) != PyArray_ISNBO(type2->byteorder)) { + return NPY_FALSE; + } + if (type1->subarray || type2->subarray) { + return ((type_num1 == type_num2) + && _equivalent_subarrays(type1->subarray, type2->subarray)); + } + if (type_num1 == NPY_VOID || type_num2 == NPY_VOID) { + return ((type_num1 == type_num2) && _equivalent_fields(type1, type2)); + } + if (type_num1 == NPY_DATETIME + || type_num1 == NPY_TIMEDELTA + || type_num2 == NPY_DATETIME + || type_num2 == NPY_TIMEDELTA) { + return ((type_num1 == type_num2) + && has_equivalent_datetime_metadata(type1, type2)); + } + return type1->kind == type2->kind; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT unsigned char +PyArray_EquivTypenums(int typenum1, int typenum2) +{ + PyArray_Descr *d1, *d2; + npy_bool ret; + + if (typenum1 == typenum2) { + return NPY_SUCCEED; + } + + d1 = PyArray_DescrFromType(typenum1); + d2 = PyArray_DescrFromType(typenum2); + ret = PyArray_EquivTypes(d1, d2); + Py_DECREF(d1); + Py_DECREF(d2); + return ret; +} + +/*** END C-API FUNCTIONS **/ +/* + * NPY_RELAXED_STRIDES_CHECKING: If the strides logic is changed, the + * order specific stride setting is not necessary. + */ +static NPY_STEALS_REF_TO_ARG(1) PyObject * +_prepend_ones(PyArrayObject *arr, int nd, int ndmin, NPY_ORDER order) +{ + npy_intp newdims[NPY_MAXDIMS]; + npy_intp newstrides[NPY_MAXDIMS]; + npy_intp newstride; + int i, k, num; + PyArrayObject *ret; + PyArray_Descr *dtype; + + if (order == NPY_FORTRANORDER || PyArray_ISFORTRAN(arr) || PyArray_NDIM(arr) == 0) { + newstride = PyArray_DESCR(arr)->elsize; + } + else { + newstride = PyArray_STRIDES(arr)[0] * PyArray_DIMS(arr)[0]; + } + + num = ndmin - nd; + for (i = 0; i < num; i++) { + newdims[i] = 1; + newstrides[i] = newstride; + } + for (i = num; i < ndmin; i++) { + k = i - num; + newdims[i] = PyArray_DIMS(arr)[k]; + newstrides[i] = PyArray_STRIDES(arr)[k]; + } + dtype = PyArray_DESCR(arr); + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(arr), + dtype, ndmin, newdims, newstrides, + PyArray_DATA(arr), + PyArray_FLAGS(arr), + (PyObject *)arr); + if (ret == NULL) { + Py_DECREF(arr); + return NULL; + } + /* steals a reference to arr --- so don't increment here */ + if (PyArray_SetBaseObject(ret, (PyObject *)arr) < 0) { + Py_DECREF(ret); + return NULL; + } + + return (PyObject *)ret; +} + + +#define STRIDING_OK(op, order) \ + ((order) == NPY_ANYORDER || \ + (order) == NPY_KEEPORDER || \ + ((order) == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(op)) || \ + ((order) == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(op))) + +static PyObject * +_array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) +{ + PyObject *op; + PyArrayObject *oparr = NULL, *ret = NULL; + npy_bool subok = NPY_FALSE; + npy_bool copy = NPY_TRUE; + int ndmin = 0, nd; + PyArray_Descr *type = NULL; + PyArray_Descr *oldtype = NULL; + NPY_ORDER order = NPY_KEEPORDER; + int flags = 0; + + static char *kwd[]= {"object", "dtype", "copy", "order", "subok", + "ndmin", NULL}; + + if (PyTuple_GET_SIZE(args) > 2) { + PyErr_SetString(PyExc_ValueError, + "only 2 non-keyword arguments accepted"); + return NULL; + } + + /* super-fast path for ndarray argument calls */ + if (PyTuple_GET_SIZE(args) == 0) { + goto full_path; + } + op = PyTuple_GET_ITEM(args, 0); + if (PyArray_CheckExact(op)) { + PyObject * dtype_obj = Py_None; + oparr = (PyArrayObject *)op; + /* get dtype which can be positional */ + if (PyTuple_GET_SIZE(args) == 2) { + dtype_obj = PyTuple_GET_ITEM(args, 1); + } + else if (kws) { + dtype_obj = PyDict_GetItem(kws, npy_ma_str_dtype); + if (dtype_obj == NULL) { + dtype_obj = Py_None; + } + } + if (dtype_obj != Py_None) { + goto full_path; + } + + /* array(ndarray) */ + if (kws == NULL) { + ret = (PyArrayObject *)PyArray_NewCopy(oparr, order); + goto finish; + } + else { + /* fast path for copy=False rest default (np.asarray) */ + PyObject * copy_obj, * order_obj, *ndmin_obj; + copy_obj = PyDict_GetItem(kws, npy_ma_str_copy); + if (copy_obj != Py_False) { + goto full_path; + } + copy = NPY_FALSE; + + /* order does not matter for contiguous 1d arrays */ + if (PyArray_NDIM((PyArrayObject*)op) > 1 || + !PyArray_IS_C_CONTIGUOUS((PyArrayObject*)op)) { + order_obj = PyDict_GetItem(kws, npy_ma_str_order); + if (order_obj != Py_None && order_obj != NULL) { + goto full_path; + } + } + + ndmin_obj = PyDict_GetItem(kws, npy_ma_str_ndmin); + if (ndmin_obj) { + ndmin = PyLong_AsLong(ndmin_obj); + if (error_converting(ndmin)) { + goto clean_type; + } + else if (ndmin > NPY_MAXDIMS) { + goto full_path; + } + } + + /* copy=False with default dtype, order and ndim */ + if (STRIDING_OK(oparr, order)) { + ret = oparr; + Py_INCREF(ret); + goto finish; + } + } + } + +full_path: + if(!PyArg_ParseTupleAndKeywords(args, kws, "O|O&O&O&O&i:array", kwd, + &op, + PyArray_DescrConverter2, &type, + PyArray_BoolConverter, ©, + PyArray_OrderConverter, &order, + PyArray_BoolConverter, &subok, + &ndmin)) { + goto clean_type; + } + + if (ndmin > NPY_MAXDIMS) { + PyErr_Format(PyExc_ValueError, + "ndmin bigger than allowable number of dimensions " + "NPY_MAXDIMS (=%d)", NPY_MAXDIMS); + goto clean_type; + } + /* fast exit if simple call */ + if ((subok && PyArray_Check(op)) || + (!subok && PyArray_CheckExact(op))) { + oparr = (PyArrayObject *)op; + if (type == NULL) { + if (!copy && STRIDING_OK(oparr, order)) { + ret = oparr; + Py_INCREF(ret); + goto finish; + } + else { + ret = (PyArrayObject *)PyArray_NewCopy(oparr, order); + goto finish; + } + } + /* One more chance */ + oldtype = PyArray_DESCR(oparr); + if (PyArray_EquivTypes(oldtype, type)) { + if (!copy && STRIDING_OK(oparr, order)) { + Py_INCREF(op); + ret = oparr; + goto finish; + } + else { + ret = (PyArrayObject *)PyArray_NewCopy(oparr, order); + if (oldtype == type || ret == NULL) { + goto finish; + } + Py_INCREF(oldtype); + Py_DECREF(PyArray_DESCR(ret)); + ((PyArrayObject_fields *)ret)->descr = oldtype; + goto finish; + } + } + } + + if (copy) { + flags = NPY_ARRAY_ENSURECOPY; + } + if (order == NPY_CORDER) { + flags |= NPY_ARRAY_C_CONTIGUOUS; + } + else if ((order == NPY_FORTRANORDER) + /* order == NPY_ANYORDER && */ + || (PyArray_Check(op) && + PyArray_ISFORTRAN((PyArrayObject *)op))) { + flags |= NPY_ARRAY_F_CONTIGUOUS; + } + if (!subok) { + flags |= NPY_ARRAY_ENSUREARRAY; + } + + flags |= NPY_ARRAY_FORCECAST; + Py_XINCREF(type); + ret = (PyArrayObject *)PyArray_CheckFromAny(op, type, + 0, 0, flags, NULL); + + finish: + Py_XDECREF(type); + if (ret == NULL) { + return NULL; + } + + nd = PyArray_NDIM(ret); + if (nd >= ndmin) { + return (PyObject *)ret; + } + /* + * create a new array from the same data with ones in the shape + * steals a reference to ret + */ + return _prepend_ones(ret, nd, ndmin, order); + +clean_type: + Py_XDECREF(type); + return NULL; +} + +static PyObject * +array_copyto(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + + static char *kwlist[] = {"dst","src","casting","where",NULL}; + PyObject *wheremask_in = NULL; + PyArrayObject *dst = NULL, *src = NULL, *wheremask = NULL; + NPY_CASTING casting = NPY_SAME_KIND_CASTING; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O&|O&O:copyto", kwlist, + &PyArray_Type, &dst, + &PyArray_Converter, &src, + &PyArray_CastingConverter, &casting, + &wheremask_in)) { + goto fail; + } + + if (wheremask_in != NULL) { + /* Get the boolean where mask */ + PyArray_Descr *dtype = PyArray_DescrFromType(NPY_BOOL); + if (dtype == NULL) { + goto fail; + } + wheremask = (PyArrayObject *)PyArray_FromAny(wheremask_in, + dtype, 0, 0, 0, NULL); + if (wheremask == NULL) { + goto fail; + } + } + + if (PyArray_AssignArray(dst, src, wheremask, casting) < 0) { + goto fail; + } + + Py_XDECREF(src); + Py_XDECREF(wheremask); + + Py_RETURN_NONE; + +fail: + Py_XDECREF(src); + Py_XDECREF(wheremask); + return NULL; +} + +static PyObject * +array_empty(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + + static char *kwlist[] = {"shape","dtype","order",NULL}; + PyArray_Descr *typecode = NULL; + PyArray_Dims shape = {NULL, 0}; + NPY_ORDER order = NPY_CORDER; + npy_bool is_f_order; + PyArrayObject *ret = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&:empty", kwlist, + PyArray_IntpConverter, &shape, + PyArray_DescrConverter, &typecode, + PyArray_OrderConverter, &order)) { + goto fail; + } + + switch (order) { + case NPY_CORDER: + is_f_order = NPY_FALSE; + break; + case NPY_FORTRANORDER: + is_f_order = NPY_TRUE; + break; + default: + PyErr_SetString(PyExc_ValueError, + "only 'C' or 'F' order is permitted"); + goto fail; + } + + ret = (PyArrayObject *)PyArray_Empty(shape.len, shape.ptr, + typecode, is_f_order); + + npy_free_cache_dim_obj(shape); + return (PyObject *)ret; + +fail: + Py_XDECREF(typecode); + npy_free_cache_dim_obj(shape); + return NULL; +} + +static PyObject * +array_empty_like(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + + static char *kwlist[] = {"prototype","dtype","order","subok",NULL}; + PyArrayObject *prototype = NULL; + PyArray_Descr *dtype = NULL; + NPY_ORDER order = NPY_KEEPORDER; + PyArrayObject *ret = NULL; + int subok = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&i:empty_like", kwlist, + &PyArray_Converter, &prototype, + &PyArray_DescrConverter2, &dtype, + &PyArray_OrderConverter, &order, + &subok)) { + goto fail; + } + /* steals the reference to dtype if it's not NULL */ + ret = (PyArrayObject *)PyArray_NewLikeArray(prototype, + order, dtype, subok); + Py_DECREF(prototype); + + return (PyObject *)ret; + +fail: + Py_XDECREF(prototype); + Py_XDECREF(dtype); + return NULL; +} + +/* + * This function is needed for supporting Pickles of + * numpy scalar objects. + */ +static PyObject * +array_scalar(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + + static char *kwlist[] = {"dtype","obj", NULL}; + PyArray_Descr *typecode; + PyObject *obj = NULL, *tmpobj = NULL; + int alloc = 0; + void *dptr; + PyObject *ret; + + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O:scalar", kwlist, + &PyArrayDescr_Type, &typecode, &obj)) { + return NULL; + } + + if (PyDataType_FLAGCHK(typecode, NPY_ITEM_IS_POINTER)) { + if (obj == NULL) { + obj = Py_None; + } + dptr = &obj; + } + else { + if (obj == NULL) { + if (typecode->elsize == 0) { + typecode->elsize = 1; + } + dptr = PyArray_malloc(typecode->elsize); + if (dptr == NULL) { + return PyErr_NoMemory(); + } + memset(dptr, '\0', typecode->elsize); + alloc = 1; + } + else { +#if defined(NPY_PY3K) + /* Backward compatibility with Python 2 NumPy pickles */ + if (PyUnicode_Check(obj)) { + tmpobj = PyUnicode_AsLatin1String(obj); + obj = tmpobj; + if (tmpobj == NULL) { + /* More informative error message */ + PyErr_SetString(PyExc_ValueError, + "Failed to encode Numpy scalar data string to " + "latin1,\npickle.load(a, encoding='latin1') is " + "assumed if unpickling."); + return NULL; + } + } +#endif + + if (!PyString_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "initializing object must be a string"); + Py_XDECREF(tmpobj); + return NULL; + } + if (PyString_GET_SIZE(obj) < typecode->elsize) { + PyErr_SetString(PyExc_ValueError, + "initialization string is too small"); + Py_XDECREF(tmpobj); + return NULL; + } + dptr = PyString_AS_STRING(obj); + } + } + ret = PyArray_Scalar(dptr, typecode, NULL); + + /* free dptr which contains zeros */ + if (alloc) { + PyArray_free(dptr); + } + Py_XDECREF(tmpobj); + return ret; +} + +static PyObject * +array_zeros(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"shape","dtype","order",NULL}; + PyArray_Descr *typecode = NULL; + PyArray_Dims shape = {NULL, 0}; + NPY_ORDER order = NPY_CORDER; + npy_bool is_f_order = NPY_FALSE; + PyArrayObject *ret = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&:zeros", kwlist, + PyArray_IntpConverter, &shape, + PyArray_DescrConverter, &typecode, + PyArray_OrderConverter, &order)) { + goto fail; + } + + switch (order) { + case NPY_CORDER: + is_f_order = NPY_FALSE; + break; + case NPY_FORTRANORDER: + is_f_order = NPY_TRUE; + break; + default: + PyErr_SetString(PyExc_ValueError, + "only 'C' or 'F' order is permitted"); + goto fail; + } + + ret = (PyArrayObject *)PyArray_Zeros(shape.len, shape.ptr, + typecode, (int) is_f_order); + + npy_free_cache_dim_obj(shape); + return (PyObject *)ret; + +fail: + Py_XDECREF(typecode); + npy_free_cache_dim_obj(shape); + return (PyObject *)ret; +} + +static PyObject * +array_count_nonzero(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds) +{ + PyArrayObject *array; + npy_intp count; + + if (!PyArg_ParseTuple(args, "O&:count_nonzero", PyArray_Converter, &array)) { + return NULL; + } + + count = PyArray_CountNonzero(array); + + Py_DECREF(array); + + if (count == -1) { + return NULL; + } +#if defined(NPY_PY3K) + return PyLong_FromSsize_t(count); +#else + return PyInt_FromSsize_t(count); +#endif +} + +static PyObject * +array_fromstring(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) +{ + char *data; + Py_ssize_t nin = -1; + char *sep = NULL; + Py_ssize_t s; + static char *kwlist[] = {"string", "dtype", "count", "sep", NULL}; + PyArray_Descr *descr = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, + "s#|O&" NPY_SSIZE_T_PYFMT "s:fromstring", kwlist, + &data, &s, PyArray_DescrConverter, &descr, &nin, &sep)) { + Py_XDECREF(descr); + return NULL; + } + + /* binary mode, condition copied from PyArray_FromString */ + if (sep == NULL || strlen(sep) == 0) { + /* Numpy 1.14, 2017-10-19 */ + if (DEPRECATE( + "The binary mode of fromstring is deprecated, as it behaves " + "surprisingly on unicode inputs. Use frombuffer instead") < 0) { + Py_DECREF(descr); + return NULL; + } + } + return PyArray_FromString(data, (npy_intp)s, descr, (npy_intp)nin, sep); +} + + + +static PyObject * +array_fromfile(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) +{ + PyObject *file = NULL, *ret; + char *sep = ""; + Py_ssize_t nin = -1; + static char *kwlist[] = {"file", "dtype", "count", "sep", NULL}; + PyArray_Descr *type = NULL; + int own; + npy_off_t orig_pos = 0; + FILE *fp; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, + "O|O&" NPY_SSIZE_T_PYFMT "s:fromfile", kwlist, + &file, PyArray_DescrConverter, &type, &nin, &sep)) { + Py_XDECREF(type); + return NULL; + } + if (PyString_Check(file) || PyUnicode_Check(file)) { + file = npy_PyFile_OpenFile(file, "rb"); + if (file == NULL) { + return NULL; + } + own = 1; + } + else { + Py_INCREF(file); + own = 0; + } + fp = npy_PyFile_Dup2(file, "rb", &orig_pos); + if (fp == NULL) { + Py_DECREF(file); + return NULL; + } + if (type == NULL) { + type = PyArray_DescrFromType(NPY_DEFAULT_TYPE); + } + ret = PyArray_FromFile(fp, type, (npy_intp) nin, sep); + + if (npy_PyFile_DupClose2(file, fp, orig_pos) < 0) { + goto fail; + } + if (own && npy_PyFile_CloseFile(file) < 0) { + goto fail; + } + Py_DECREF(file); + return ret; + +fail: + Py_DECREF(file); + Py_DECREF(ret); + return NULL; +} + +static PyObject * +array_fromiter(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) +{ + PyObject *iter; + Py_ssize_t nin = -1; + static char *kwlist[] = {"iter", "dtype", "count", NULL}; + PyArray_Descr *descr = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, + "OO&|" NPY_SSIZE_T_PYFMT ":fromiter", kwlist, + &iter, PyArray_DescrConverter, &descr, &nin)) { + Py_XDECREF(descr); + return NULL; + } + return PyArray_FromIter(iter, descr, (npy_intp)nin); +} + +static PyObject * +array_frombuffer(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) +{ + PyObject *obj = NULL; + Py_ssize_t nin = -1, offset = 0; + static char *kwlist[] = {"buffer", "dtype", "count", "offset", NULL}; + PyArray_Descr *type = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, + "O|O&" NPY_SSIZE_T_PYFMT NPY_SSIZE_T_PYFMT ":frombuffer", kwlist, + &obj, PyArray_DescrConverter, &type, &nin, &offset)) { + Py_XDECREF(type); + return NULL; + } + if (type == NULL) { + type = PyArray_DescrFromType(NPY_DEFAULT_TYPE); + } + return PyArray_FromBuffer(obj, type, (npy_intp)nin, (npy_intp)offset); +} + +static PyObject * +array_concatenate(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *a0; + PyObject *out = NULL; + int axis = 0; + static char *kwlist[] = {"seq", "axis", "out", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O:concatenate", kwlist, + &a0, PyArray_AxisConverter, &axis, &out)) { + return NULL; + } + if (out != NULL) { + if (out == Py_None) { + out = NULL; + } + else if (!PyArray_Check(out)) { + PyErr_SetString(PyExc_TypeError, "'out' must be an array"); + return NULL; + } + } + return PyArray_ConcatenateInto(a0, axis, (PyArrayObject *)out); +} + +static PyObject * +array_innerproduct(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyObject *b0, *a0; + + if (!PyArg_ParseTuple(args, "OO:innerproduct", &a0, &b0)) { + return NULL; + } + return PyArray_Return((PyArrayObject *)PyArray_InnerProduct(a0, b0)); +} + +static PyObject * +array_matrixproduct(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject* kwds) +{ + PyObject *v, *a, *o = NULL; + PyArrayObject *ret; + char* kwlist[] = {"a", "b", "out", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:matrixproduct", + kwlist, &a, &v, &o)) { + return NULL; + } + if (o != NULL) { + if (o == Py_None) { + o = NULL; + } + else if (!PyArray_Check(o)) { + PyErr_SetString(PyExc_TypeError, "'out' must be an array"); + return NULL; + } + } + ret = (PyArrayObject *)PyArray_MatrixProduct2(a, v, (PyArrayObject *)o); + return PyArray_Return(ret); +} + + +static PyObject * +array_vdot(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + int typenum; + char *ip1, *ip2, *op; + npy_intp n, stride1, stride2; + PyObject *op1, *op2; + npy_intp newdimptr[1] = {-1}; + PyArray_Dims newdims = {newdimptr, 1}; + PyArrayObject *ap1 = NULL, *ap2 = NULL, *ret = NULL; + PyArray_Descr *type; + PyArray_DotFunc *vdot; + NPY_BEGIN_THREADS_DEF; + + if (!PyArg_ParseTuple(args, "OO:vdot", &op1, &op2)) { + return NULL; + } + + /* + * Conjugating dot product using the BLAS for vectors. + * Flattens both op1 and op2 before dotting. + */ + typenum = PyArray_ObjectType(op1, 0); + typenum = PyArray_ObjectType(op2, typenum); + + type = PyArray_DescrFromType(typenum); + Py_INCREF(type); + ap1 = (PyArrayObject *)PyArray_FromAny(op1, type, 0, 0, 0, NULL); + if (ap1 == NULL) { + Py_DECREF(type); + goto fail; + } + + op1 = PyArray_Newshape(ap1, &newdims, NPY_CORDER); + if (op1 == NULL) { + Py_DECREF(type); + goto fail; + } + Py_DECREF(ap1); + ap1 = (PyArrayObject *)op1; + + ap2 = (PyArrayObject *)PyArray_FromAny(op2, type, 0, 0, 0, NULL); + if (ap2 == NULL) { + goto fail; + } + op2 = PyArray_Newshape(ap2, &newdims, NPY_CORDER); + if (op2 == NULL) { + goto fail; + } + Py_DECREF(ap2); + ap2 = (PyArrayObject *)op2; + + if (PyArray_DIM(ap2, 0) != PyArray_DIM(ap1, 0)) { + PyErr_SetString(PyExc_ValueError, + "vectors have different lengths"); + goto fail; + } + + /* array scalar output */ + ret = new_array_for_sum(ap1, ap2, NULL, 0, (npy_intp *)NULL, typenum, NULL); + if (ret == NULL) { + goto fail; + } + + n = PyArray_DIM(ap1, 0); + stride1 = PyArray_STRIDE(ap1, 0); + stride2 = PyArray_STRIDE(ap2, 0); + ip1 = PyArray_DATA(ap1); + ip2 = PyArray_DATA(ap2); + op = PyArray_DATA(ret); + + switch (typenum) { + case NPY_CFLOAT: + vdot = (PyArray_DotFunc *)CFLOAT_vdot; + break; + case NPY_CDOUBLE: + vdot = (PyArray_DotFunc *)CDOUBLE_vdot; + break; + case NPY_CLONGDOUBLE: + vdot = (PyArray_DotFunc *)CLONGDOUBLE_vdot; + break; + case NPY_OBJECT: + vdot = (PyArray_DotFunc *)OBJECT_vdot; + break; + default: + vdot = type->f->dotfunc; + if (vdot == NULL) { + PyErr_SetString(PyExc_ValueError, + "function not available for this data type"); + goto fail; + } + } + + if (n < 500) { + vdot(ip1, stride1, ip2, stride2, op, n, NULL); + } + else { + NPY_BEGIN_THREADS_DESCR(type); + vdot(ip1, stride1, ip2, stride2, op, n, NULL); + NPY_END_THREADS_DESCR(type); + } + + Py_XDECREF(ap1); + Py_XDECREF(ap2); + return PyArray_Return(ret); +fail: + Py_XDECREF(ap1); + Py_XDECREF(ap2); + Py_XDECREF(ret); + return NULL; +} + + + +/* + * matmul + * + * Implements the protocol used by the '@' operator defined in PEP 364. + * Not in the NUMPY API at this time, maybe later. + * + * + * in1: Left hand side operand + * in2: Right hand side operand + * out: Either NULL, or an array into which the output should be placed. + * + * Returns NULL on error. + */ +static PyObject * +array_matmul(PyObject *NPY_UNUSED(m), PyObject *args, PyObject* kwds) +{ + PyObject *in1, *in2, *out = NULL; + char* kwlist[] = {"a", "b", "out", NULL }; + PyArrayObject *ap1, *ap2, *ret = NULL; + NPY_ORDER order = NPY_KEEPORDER; + NPY_CASTING casting = NPY_SAFE_CASTING; + PyArray_Descr *dtype; + int nd1, nd2, typenum; + char *subscripts; + PyArrayObject *ops[2]; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:matmul", kwlist, + &in1, &in2, &out)) { + return NULL; + } + + if (out != NULL) { + if (out == Py_None) { + out = NULL; + } + else if (!PyArray_Check(out)) { + PyErr_SetString(PyExc_TypeError, "'out' must be an array"); + return NULL; + } + } + + dtype = PyArray_DescrFromObject(in1, NULL); + dtype = PyArray_DescrFromObject(in2, dtype); + if (dtype == NULL) { + PyErr_SetString(PyExc_ValueError, "Cannot find a common data type."); + return NULL; + } + typenum = dtype->type_num; + + if (typenum == NPY_OBJECT) { + /* matmul is not currently implemented for object arrays */ + PyErr_SetString(PyExc_TypeError, + "Object arrays are not currently supported"); + Py_DECREF(dtype); + return NULL; + } + + ap1 = (PyArrayObject *)PyArray_FromAny(in1, dtype, 0, 0, + NPY_ARRAY_ALIGNED, NULL); + if (ap1 == NULL) { + return NULL; + } + + Py_INCREF(dtype); + ap2 = (PyArrayObject *)PyArray_FromAny(in2, dtype, 0, 0, + NPY_ARRAY_ALIGNED, NULL); + if (ap2 == NULL) { + Py_DECREF(ap1); + return NULL; + } + + if (PyArray_NDIM(ap1) == 0 || PyArray_NDIM(ap2) == 0) { + /* Scalars are rejected */ + PyErr_SetString(PyExc_ValueError, + "Scalar operands are not allowed, use '*' instead"); + return NULL; + } + + nd1 = PyArray_NDIM(ap1); + nd2 = PyArray_NDIM(ap2); + +#if defined(HAVE_CBLAS) + if (nd1 <= 2 && nd2 <= 2 && + (NPY_DOUBLE == typenum || NPY_CDOUBLE == typenum || + NPY_FLOAT == typenum || NPY_CFLOAT == typenum)) { + return cblas_matrixproduct(typenum, ap1, ap2, (PyArrayObject *)out); + } +#endif + + /* + * Use einsum for the stacked cases. This is a quick implementation + * to avoid setting up the proper iterators. Einsum broadcasts, so + * we need to check dimensions before the call. + */ + if (nd1 == 1 && nd2 == 1) { + /* vector vector */ + if (PyArray_DIM(ap1, 0) != PyArray_DIM(ap2, 0)) { + dot_alignment_error(ap1, 0, ap2, 0); + goto fail; + } + subscripts = "i, i"; + } + else if (nd1 == 1) { + /* vector matrix */ + if (PyArray_DIM(ap1, 0) != PyArray_DIM(ap2, nd2 - 2)) { + dot_alignment_error(ap1, 0, ap2, nd2 - 2); + goto fail; + } + subscripts = "i, ...ij"; + } + else if (nd2 == 1) { + /* matrix vector */ + if (PyArray_DIM(ap1, nd1 - 1) != PyArray_DIM(ap2, 0)) { + dot_alignment_error(ap1, nd1 - 1, ap2, 0); + goto fail; + } + subscripts = "...i, i"; + } + else { + /* matrix * matrix */ + if (PyArray_DIM(ap1, nd1 - 1) != PyArray_DIM(ap2, nd2 - 2)) { + dot_alignment_error(ap1, nd1 - 1, ap2, nd2 - 2); + goto fail; + } + subscripts = "...ij, ...jk"; + } + ops[0] = ap1; + ops[1] = ap2; + ret = PyArray_EinsteinSum(subscripts, 2, ops, NULL, order, casting, + (PyArrayObject *)out); + Py_DECREF(ap1); + Py_DECREF(ap2); + + /* If no output was supplied, possibly convert to a scalar */ + if (ret != NULL && out == NULL) { + return PyArray_Return((PyArrayObject *)ret); + } + return (PyObject *)ret; + +fail: + Py_XDECREF(ap1); + Py_XDECREF(ap2); + return NULL; +} + + +static int +einsum_sub_op_from_str(PyObject *args, PyObject **str_obj, char **subscripts, + PyArrayObject **op) +{ + int i, nop; + PyObject *subscripts_str; + + nop = PyTuple_GET_SIZE(args) - 1; + if (nop <= 0) { + PyErr_SetString(PyExc_ValueError, + "must specify the einstein sum subscripts string " + "and at least one operand"); + return -1; + } + else if (nop >= NPY_MAXARGS) { + PyErr_SetString(PyExc_ValueError, "too many operands"); + return -1; + } + + /* Get the subscripts string */ + subscripts_str = PyTuple_GET_ITEM(args, 0); + if (PyUnicode_Check(subscripts_str)) { + *str_obj = PyUnicode_AsASCIIString(subscripts_str); + if (*str_obj == NULL) { + return -1; + } + subscripts_str = *str_obj; + } + + *subscripts = PyBytes_AsString(subscripts_str); + if (*subscripts == NULL) { + Py_XDECREF(*str_obj); + *str_obj = NULL; + return -1; + } + + /* Set the operands to NULL */ + for (i = 0; i < nop; ++i) { + op[i] = NULL; + } + + /* Get the operands */ + for (i = 0; i < nop; ++i) { + PyObject *obj = PyTuple_GET_ITEM(args, i+1); + + op[i] = (PyArrayObject *)PyArray_FROM_OF(obj, NPY_ARRAY_ENSUREARRAY); + if (op[i] == NULL) { + goto fail; + } + } + + return nop; + +fail: + for (i = 0; i < nop; ++i) { + Py_XDECREF(op[i]); + op[i] = NULL; + } + + return -1; +} + +/* + * Converts a list of subscripts to a string. + * + * Returns -1 on error, the number of characters placed in subscripts + * otherwise. + */ +static int +einsum_list_to_subscripts(PyObject *obj, char *subscripts, int subsize) +{ + int ellipsis = 0, subindex = 0; + npy_intp i, size; + PyObject *item; + + obj = PySequence_Fast(obj, "the subscripts for each operand must " + "be a list or a tuple"); + if (obj == NULL) { + return -1; + } + size = PySequence_Size(obj); + + + for (i = 0; i < size; ++i) { + item = PySequence_Fast_GET_ITEM(obj, i); + /* Ellipsis */ + if (item == Py_Ellipsis) { + if (ellipsis) { + PyErr_SetString(PyExc_ValueError, + "each subscripts list may have only one ellipsis"); + Py_DECREF(obj); + return -1; + } + if (subindex + 3 >= subsize) { + PyErr_SetString(PyExc_ValueError, + "subscripts list is too long"); + Py_DECREF(obj); + return -1; + } + subscripts[subindex++] = '.'; + subscripts[subindex++] = '.'; + subscripts[subindex++] = '.'; + ellipsis = 1; + } + /* Subscript */ + else if (PyInt_Check(item) || PyLong_Check(item)) { + long s = PyInt_AsLong(item); + if ( s < 0 || s > 2*26) { + PyErr_SetString(PyExc_ValueError, + "subscript is not within the valid range [0, 52]"); + Py_DECREF(obj); + return -1; + } + if (s < 26) { + subscripts[subindex++] = 'A' + s; + } + else { + subscripts[subindex++] = 'a' + s; + } + if (subindex >= subsize) { + PyErr_SetString(PyExc_ValueError, + "subscripts list is too long"); + Py_DECREF(obj); + return -1; + } + } + /* Invalid */ + else { + PyErr_SetString(PyExc_ValueError, + "each subscript must be either an integer " + "or an ellipsis"); + Py_DECREF(obj); + return -1; + } + } + + Py_DECREF(obj); + + return subindex; +} + +/* + * Fills in the subscripts, with maximum size subsize, and op, + * with the values in the tuple 'args'. + * + * Returns -1 on error, number of operands placed in op otherwise. + */ +static int +einsum_sub_op_from_lists(PyObject *args, + char *subscripts, int subsize, PyArrayObject **op) +{ + int subindex = 0; + npy_intp i, nop; + + nop = PyTuple_Size(args)/2; + + if (nop == 0) { + PyErr_SetString(PyExc_ValueError, "must provide at least an " + "operand and a subscripts list to einsum"); + return -1; + } + else if(nop >= NPY_MAXARGS) { + PyErr_SetString(PyExc_ValueError, "too many operands"); + return -1; + } + + /* Set the operands to NULL */ + for (i = 0; i < nop; ++i) { + op[i] = NULL; + } + + /* Get the operands and build the subscript string */ + for (i = 0; i < nop; ++i) { + PyObject *obj = PyTuple_GET_ITEM(args, 2*i); + int n; + + /* Comma between the subscripts for each operand */ + if (i != 0) { + subscripts[subindex++] = ','; + if (subindex >= subsize) { + PyErr_SetString(PyExc_ValueError, + "subscripts list is too long"); + goto fail; + } + } + + op[i] = (PyArrayObject *)PyArray_FROM_OF(obj, NPY_ARRAY_ENSUREARRAY); + if (op[i] == NULL) { + goto fail; + } + + obj = PyTuple_GET_ITEM(args, 2*i+1); + n = einsum_list_to_subscripts(obj, subscripts+subindex, + subsize-subindex); + if (n < 0) { + goto fail; + } + subindex += n; + } + + /* Add the '->' to the string if provided */ + if (PyTuple_Size(args) == 2*nop+1) { + PyObject *obj; + int n; + + if (subindex + 2 >= subsize) { + PyErr_SetString(PyExc_ValueError, + "subscripts list is too long"); + goto fail; + } + subscripts[subindex++] = '-'; + subscripts[subindex++] = '>'; + + obj = PyTuple_GET_ITEM(args, 2*nop); + n = einsum_list_to_subscripts(obj, subscripts+subindex, + subsize-subindex); + if (n < 0) { + goto fail; + } + subindex += n; + } + + /* NULL-terminate the subscripts string */ + subscripts[subindex] = '\0'; + + return nop; + +fail: + for (i = 0; i < nop; ++i) { + Py_XDECREF(op[i]); + op[i] = NULL; + } + + return -1; +} + +static PyObject * +array_einsum(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + char *subscripts = NULL, subscripts_buffer[256]; + PyObject *str_obj = NULL, *str_key_obj = NULL; + PyObject *arg0; + int i, nop; + PyArrayObject *op[NPY_MAXARGS]; + NPY_ORDER order = NPY_KEEPORDER; + NPY_CASTING casting = NPY_SAFE_CASTING; + PyArrayObject *out = NULL; + PyArray_Descr *dtype = NULL; + PyObject *ret = NULL; + + if (PyTuple_GET_SIZE(args) < 1) { + PyErr_SetString(PyExc_ValueError, + "must specify the einstein sum subscripts string " + "and at least one operand, or at least one operand " + "and its corresponding subscripts list"); + return NULL; + } + arg0 = PyTuple_GET_ITEM(args, 0); + + /* einsum('i,j', a, b), einsum('i,j->ij', a, b) */ + if (PyString_Check(arg0) || PyUnicode_Check(arg0)) { + nop = einsum_sub_op_from_str(args, &str_obj, &subscripts, op); + } + /* einsum(a, [0], b, [1]), einsum(a, [0], b, [1], [0,1]) */ + else { + nop = einsum_sub_op_from_lists(args, subscripts_buffer, + sizeof(subscripts_buffer), op); + subscripts = subscripts_buffer; + } + if (nop <= 0) { + goto finish; + } + + /* Get the keyword arguments */ + if (kwds != NULL) { + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(kwds, &pos, &key, &value)) { + char *str = NULL; + +#if defined(NPY_PY3K) + Py_XDECREF(str_key_obj); + str_key_obj = PyUnicode_AsASCIIString(key); + if (str_key_obj != NULL) { + key = str_key_obj; + } +#endif + + str = PyBytes_AsString(key); + + if (str == NULL) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "invalid keyword"); + goto finish; + } + + if (strcmp(str,"out") == 0) { + if (PyArray_Check(value)) { + out = (PyArrayObject *)value; + } + else { + PyErr_SetString(PyExc_TypeError, + "keyword parameter out must be an " + "array for einsum"); + goto finish; + } + } + else if (strcmp(str,"order") == 0) { + if (!PyArray_OrderConverter(value, &order)) { + goto finish; + } + } + else if (strcmp(str,"casting") == 0) { + if (!PyArray_CastingConverter(value, &casting)) { + goto finish; + } + } + else if (strcmp(str,"dtype") == 0) { + if (!PyArray_DescrConverter2(value, &dtype)) { + goto finish; + } + } + else { + PyErr_Format(PyExc_TypeError, + "'%s' is an invalid keyword for einsum", + str); + goto finish; + } + } + } + + ret = (PyObject *)PyArray_EinsteinSum(subscripts, nop, op, dtype, + order, casting, out); + + /* If no output was supplied, possibly convert to a scalar */ + if (ret != NULL && out == NULL) { + ret = PyArray_Return((PyArrayObject *)ret); + } + +finish: + for (i = 0; i < nop; ++i) { + Py_XDECREF(op[i]); + } + Py_XDECREF(dtype); + Py_XDECREF(str_obj); + Py_XDECREF(str_key_obj); + /* out is a borrowed reference */ + + return ret; +} + +static PyObject * +array_fastCopyAndTranspose(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyObject *a0; + + if (!PyArg_ParseTuple(args, "O:_fastCopyAndTranspose", &a0)) { + return NULL; + } + return PyArray_Return((PyArrayObject *)PyArray_CopyAndTranspose(a0)); +} + +static PyObject * +array_correlate(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *shape, *a0; + int mode = 0; + static char *kwlist[] = {"a", "v", "mode", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|i:correlate", kwlist, + &a0, &shape, &mode)) { + return NULL; + } + return PyArray_Correlate(a0, shape, mode); +} + +static PyObject* +array_correlate2(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *shape, *a0; + int mode = 0; + static char *kwlist[] = {"a", "v", "mode", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|i:correlate2", kwlist, + &a0, &shape, &mode)) { + return NULL; + } + return PyArray_Correlate2(a0, shape, mode); +} + +static PyObject * +array_arange(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) { + PyObject *o_start = NULL, *o_stop = NULL, *o_step = NULL, *range=NULL; + static char *kwd[]= {"start", "stop", "step", "dtype", NULL}; + PyArray_Descr *typecode = NULL; + + if(!PyArg_ParseTupleAndKeywords(args, kws, "O|OOO&:arange", kwd, + &o_start, + &o_stop, + &o_step, + PyArray_DescrConverter2, &typecode)) { + Py_XDECREF(typecode); + return NULL; + } + range = PyArray_ArangeObj(o_start, o_stop, o_step, typecode); + Py_XDECREF(typecode); + + return range; +} + +/*NUMPY_API + * + * Included at the very first so not auto-grabbed and thus not labeled. + */ +NPY_NO_EXPORT unsigned int +PyArray_GetNDArrayCVersion(void) +{ + return (unsigned int)NPY_ABI_VERSION; +} + +/*NUMPY_API + * Returns the built-in (at compilation time) C API version + */ +NPY_NO_EXPORT unsigned int +PyArray_GetNDArrayCFeatureVersion(void) +{ + return (unsigned int)NPY_API_VERSION; +} + +static PyObject * +array__get_ndarray_c_version(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {NULL}; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist )) { + return NULL; + } + return PyInt_FromLong( (long) PyArray_GetNDArrayCVersion() ); +} + +/*NUMPY_API +*/ +NPY_NO_EXPORT int +PyArray_GetEndianness(void) +{ + const union { + npy_uint32 i; + char c[4]; + } bint = {0x01020304}; + + if (bint.c[0] == 1) { + return NPY_CPU_BIG; + } + else if (bint.c[0] == 4) { + return NPY_CPU_LITTLE; + } + else { + return NPY_CPU_UNKNOWN_ENDIAN; + } +} + +static PyObject * +array__reconstruct(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + + PyObject *ret; + PyTypeObject *subtype; + PyArray_Dims shape = {NULL, 0}; + PyArray_Descr *dtype = NULL; + + evil_global_disable_warn_O4O8_flag = 1; + + if (!PyArg_ParseTuple(args, "O!O&O&:_reconstruct", + &PyType_Type, &subtype, + PyArray_IntpConverter, &shape, + PyArray_DescrConverter, &dtype)) { + goto fail; + } + if (!PyType_IsSubtype(subtype, &PyArray_Type)) { + PyErr_SetString(PyExc_TypeError, + "_reconstruct: First argument must be a sub-type of ndarray"); + goto fail; + } + ret = PyArray_NewFromDescr(subtype, dtype, + (int)shape.len, shape.ptr, NULL, NULL, 0, NULL); + npy_free_cache_dim_obj(shape); + + evil_global_disable_warn_O4O8_flag = 0; + + return ret; + +fail: + evil_global_disable_warn_O4O8_flag = 0; + + Py_XDECREF(dtype); + npy_free_cache_dim_obj(shape); + return NULL; +} + +static PyObject * +array_set_string_function(PyObject *NPY_UNUSED(self), PyObject *args, + PyObject *kwds) +{ + PyObject *op = NULL; + int repr = 1; + static char *kwlist[] = {"f", "repr", NULL}; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:set_string_function", kwlist, &op, &repr)) { + return NULL; + } + /* reset the array_repr function to built-in */ + if (op == Py_None) { + op = NULL; + } + if (op != NULL && !PyCallable_Check(op)) { + PyErr_SetString(PyExc_TypeError, + "Argument must be callable."); + return NULL; + } + PyArray_SetStringFunction(op, repr); + Py_RETURN_NONE; +} + +static PyObject * +array_set_ops_function(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args), + PyObject *kwds) +{ + PyObject *oldops = NULL; + + if ((oldops = PyArray_GetNumericOps()) == NULL) { + return NULL; + } + /* + * Should probably ensure that objects are at least callable + * Leave this to the caller for now --- error will be raised + * later when use is attempted + */ + if (kwds && PyArray_SetNumericOps(kwds) == -1) { + Py_DECREF(oldops); + PyErr_SetString(PyExc_ValueError, + "one or more objects not callable"); + return NULL; + } + return oldops; +} + +static PyObject * +array_set_datetimeparse_function(PyObject *NPY_UNUSED(self), + PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds)) +{ + PyErr_SetString(PyExc_RuntimeError, "This function has been removed"); + return NULL; +} + +/* + * inner loop with constant size memcpy arguments + * this allows the compiler to replace function calls while still handling the + * alignment requirements of the platform. + */ +#define INNER_WHERE_LOOP(size) \ + do { \ + npy_intp i; \ + for (i = 0; i < n; i++) { \ + if (*csrc) { \ + memcpy(dst, xsrc, size); \ + } \ + else { \ + memcpy(dst, ysrc, size); \ + } \ + dst += size; \ + xsrc += xstride; \ + ysrc += ystride; \ + csrc += cstride; \ + } \ + } while(0) + + +/*NUMPY_API + * Where + */ +NPY_NO_EXPORT PyObject * +PyArray_Where(PyObject *condition, PyObject *x, PyObject *y) +{ + PyArrayObject *arr, *ax, *ay; + PyObject *ret = NULL; + + arr = (PyArrayObject *)PyArray_FROM_O(condition); + if (arr == NULL) { + return NULL; + } + if ((x == NULL) && (y == NULL)) { + ret = PyArray_Nonzero(arr); + Py_DECREF(arr); + return ret; + } + if ((x == NULL) || (y == NULL)) { + Py_DECREF(arr); + PyErr_SetString(PyExc_ValueError, + "either both or neither of x and y should be given"); + return NULL; + } + + ax = (PyArrayObject*)PyArray_FROM_O(x); + ay = (PyArrayObject*)PyArray_FROM_O(y); + if (ax == NULL || ay == NULL) { + goto fail; + } + else { + npy_uint32 flags = NPY_ITER_EXTERNAL_LOOP | NPY_ITER_BUFFERED | + NPY_ITER_REFS_OK | NPY_ITER_ZEROSIZE_OK; + PyArrayObject * op_in[4] = { + NULL, arr, ax, ay + }; + npy_uint32 op_flags[4] = { + NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE | NPY_ITER_NO_SUBTYPE, + NPY_ITER_READONLY, NPY_ITER_READONLY, NPY_ITER_READONLY + }; + PyArray_Descr * common_dt = PyArray_ResultType(2, &op_in[0] + 2, + 0, NULL); + PyArray_Descr * op_dt[4] = {common_dt, PyArray_DescrFromType(NPY_BOOL), + common_dt, common_dt}; + NpyIter * iter; + int needs_api; + NPY_BEGIN_THREADS_DEF; + + if (common_dt == NULL || op_dt[1] == NULL) { + Py_XDECREF(op_dt[1]); + Py_XDECREF(common_dt); + goto fail; + } + iter = NpyIter_MultiNew(4, op_in, flags, + NPY_KEEPORDER, NPY_UNSAFE_CASTING, + op_flags, op_dt); + Py_DECREF(op_dt[1]); + Py_DECREF(common_dt); + if (iter == NULL) { + goto fail; + } + + needs_api = NpyIter_IterationNeedsAPI(iter); + + /* Get the result from the iterator object array */ + ret = (PyObject*)NpyIter_GetOperandArray(iter)[0]; + + NPY_BEGIN_THREADS_NDITER(iter); + + if (NpyIter_GetIterSize(iter) != 0) { + NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(iter, NULL); + npy_intp * innersizeptr = NpyIter_GetInnerLoopSizePtr(iter); + char **dataptrarray = NpyIter_GetDataPtrArray(iter); + + do { + PyArray_Descr * dtx = NpyIter_GetDescrArray(iter)[2]; + PyArray_Descr * dty = NpyIter_GetDescrArray(iter)[3]; + int axswap = PyDataType_ISBYTESWAPPED(dtx); + int ayswap = PyDataType_ISBYTESWAPPED(dty); + PyArray_CopySwapFunc *copyswapx = dtx->f->copyswap; + PyArray_CopySwapFunc *copyswapy = dty->f->copyswap; + int native = (axswap == ayswap) && (axswap == 0) && !needs_api; + npy_intp n = (*innersizeptr); + npy_intp itemsize = NpyIter_GetDescrArray(iter)[0]->elsize; + npy_intp cstride = NpyIter_GetInnerStrideArray(iter)[1]; + npy_intp xstride = NpyIter_GetInnerStrideArray(iter)[2]; + npy_intp ystride = NpyIter_GetInnerStrideArray(iter)[3]; + char * dst = dataptrarray[0]; + char * csrc = dataptrarray[1]; + char * xsrc = dataptrarray[2]; + char * ysrc = dataptrarray[3]; + + /* constant sizes so compiler replaces memcpy */ + if (native && itemsize == 16) { + INNER_WHERE_LOOP(16); + } + else if (native && itemsize == 8) { + INNER_WHERE_LOOP(8); + } + else if (native && itemsize == 4) { + INNER_WHERE_LOOP(4); + } + else if (native && itemsize == 2) { + INNER_WHERE_LOOP(2); + } + else if (native && itemsize == 1) { + INNER_WHERE_LOOP(1); + } + else { + /* copyswap is faster than memcpy even if we are native */ + npy_intp i; + for (i = 0; i < n; i++) { + if (*csrc) { + copyswapx(dst, xsrc, axswap, ret); + } + else { + copyswapy(dst, ysrc, ayswap, ret); + } + dst += itemsize; + xsrc += xstride; + ysrc += ystride; + csrc += cstride; + } + } + } while (iternext(iter)); + } + + NPY_END_THREADS; + + Py_INCREF(ret); + Py_DECREF(arr); + Py_DECREF(ax); + Py_DECREF(ay); + + if (NpyIter_Deallocate(iter) != NPY_SUCCEED) { + Py_DECREF(ret); + return NULL; + } + + return ret; + } + +fail: + Py_DECREF(arr); + Py_XDECREF(ax); + Py_XDECREF(ay); + return NULL; +} + +#undef INNER_WHERE_LOOP + +static PyObject * +array_where(PyObject *NPY_UNUSED(ignored), PyObject *args) +{ + PyObject *obj = NULL, *x = NULL, *y = NULL; + + if (!PyArg_ParseTuple(args, "O|OO:where", &obj, &x, &y)) { + return NULL; + } + return PyArray_Where(obj, x, y); +} + +static PyObject * +array_lexsort(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + int axis = -1; + PyObject *obj; + static char *kwlist[] = {"keys", "axis", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:lexsort", kwlist, &obj, &axis)) { + return NULL; + } + return PyArray_Return((PyArrayObject *)PyArray_LexSort(obj, axis)); +} + +static PyObject * +array_can_cast_safely(PyObject *NPY_UNUSED(self), PyObject *args, + PyObject *kwds) +{ + PyObject *from_obj = NULL; + PyArray_Descr *d1 = NULL; + PyArray_Descr *d2 = NULL; + npy_bool ret; + PyObject *retobj = NULL; + NPY_CASTING casting = NPY_SAFE_CASTING; + static char *kwlist[] = {"from_", "to", "casting", NULL}; + + if(!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|O&:can_cast", kwlist, + &from_obj, + PyArray_DescrConverter2, &d2, + PyArray_CastingConverter, &casting)) { + goto finish; + } + if (d2 == NULL) { + PyErr_SetString(PyExc_TypeError, + "did not understand one of the types; 'None' not accepted"); + goto finish; + } + + /* If the first parameter is an object or scalar, use CanCastArrayTo */ + if (PyArray_Check(from_obj)) { + ret = PyArray_CanCastArrayTo((PyArrayObject *)from_obj, d2, casting); + } + else if (PyArray_IsScalar(from_obj, Generic) || + PyArray_IsPythonNumber(from_obj)) { + PyArrayObject *arr; + arr = (PyArrayObject *)PyArray_FROM_O(from_obj); + if (arr == NULL) { + goto finish; + } + ret = PyArray_CanCastArrayTo(arr, d2, casting); + Py_DECREF(arr); + } + /* Otherwise use CanCastTypeTo */ + else { + if (!PyArray_DescrConverter2(from_obj, &d1) || d1 == NULL) { + PyErr_SetString(PyExc_TypeError, + "did not understand one of the types; 'None' not accepted"); + goto finish; + } + ret = PyArray_CanCastTypeTo(d1, d2, casting); + } + + retobj = ret ? Py_True : Py_False; + Py_INCREF(retobj); + + finish: + Py_XDECREF(d1); + Py_XDECREF(d2); + return retobj; +} + +static PyObject * +array_promote_types(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyArray_Descr *d1 = NULL; + PyArray_Descr *d2 = NULL; + PyObject *ret = NULL; + if(!PyArg_ParseTuple(args, "O&O&:promote_types", + PyArray_DescrConverter2, &d1, PyArray_DescrConverter2, &d2)) { + goto finish; + } + + if (d1 == NULL || d2 == NULL) { + PyErr_SetString(PyExc_TypeError, + "did not understand one of the types"); + goto finish; + } + + ret = (PyObject *)PyArray_PromoteTypes(d1, d2); + + finish: + Py_XDECREF(d1); + Py_XDECREF(d2); + return ret; +} + +static PyObject * +array_min_scalar_type(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyObject *array_in = NULL; + PyArrayObject *array; + PyObject *ret = NULL; + + if(!PyArg_ParseTuple(args, "O:min_scalar_type", &array_in)) { + return NULL; + } + + array = (PyArrayObject *)PyArray_FROM_O(array_in); + if (array == NULL) { + return NULL; + } + + ret = (PyObject *)PyArray_MinScalarType(array); + Py_DECREF(array); + return ret; +} + +static PyObject * +array_result_type(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + npy_intp i, len, narr = 0, ndtypes = 0; + PyArrayObject **arr = NULL; + PyArray_Descr **dtypes = NULL; + PyObject *ret = NULL; + + len = PyTuple_GET_SIZE(args); + if (len == 0) { + PyErr_SetString(PyExc_ValueError, + "at least one array or dtype is required"); + goto finish; + } + + arr = PyArray_malloc(2 * len * sizeof(void *)); + if (arr == NULL) { + return PyErr_NoMemory(); + } + dtypes = (PyArray_Descr**)&arr[len]; + + for (i = 0; i < len; ++i) { + PyObject *obj = PyTuple_GET_ITEM(args, i); + if (PyArray_Check(obj)) { + Py_INCREF(obj); + arr[narr] = (PyArrayObject *)obj; + ++narr; + } + else if (PyArray_IsScalar(obj, Generic) || + PyArray_IsPythonNumber(obj)) { + arr[narr] = (PyArrayObject *)PyArray_FROM_O(obj); + if (arr[narr] == NULL) { + goto finish; + } + ++narr; + } + else { + if (!PyArray_DescrConverter(obj, &dtypes[ndtypes])) { + goto finish; + } + ++ndtypes; + } + } + + ret = (PyObject *)PyArray_ResultType(narr, arr, ndtypes, dtypes); + +finish: + for (i = 0; i < narr; ++i) { + Py_DECREF(arr[i]); + } + for (i = 0; i < ndtypes; ++i) { + Py_DECREF(dtypes[i]); + } + PyArray_free(arr); + return ret; +} + +static PyObject * +array_datetime_data(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyArray_Descr *dtype; + PyArray_DatetimeMetaData *meta; + + if(!PyArg_ParseTuple(args, "O&:datetime_data", + PyArray_DescrConverter, &dtype)) { + return NULL; + } + + meta = get_datetime_metadata_from_dtype(dtype); + if (meta == NULL) { + return NULL; + } + + return convert_datetime_metadata_to_tuple(meta); +} + +#if !defined(NPY_PY3K) +static PyObject * +new_buffer(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + int size; + + if(!PyArg_ParseTuple(args, "i:buffer", &size)) { + return NULL; + } + return PyBuffer_New(size); +} + +static PyObject * +buffer_buffer(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *obj; + Py_ssize_t offset = 0, n; + Py_ssize_t size = Py_END_OF_BUFFER; + void *unused; + static char *kwlist[] = {"object", "offset", "size", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "O|" NPY_SSIZE_T_PYFMT NPY_SSIZE_T_PYFMT ":get_buffer", kwlist, + &obj, &offset, &size)) { + return NULL; + } + if (PyObject_AsWriteBuffer(obj, &unused, &n) < 0) { + PyErr_Clear(); + return PyBuffer_FromObject(obj, offset, size); + } + else { + return PyBuffer_FromReadWriteObject(obj, offset, size); + } +} +#endif + +#ifndef _MSC_VER +#include +#include +jmp_buf _NPY_SIGSEGV_BUF; +static void +_SigSegv_Handler(int signum) +{ + longjmp(_NPY_SIGSEGV_BUF, signum); +} +#endif + +#define _test_code() { \ + test = *((char*)memptr); \ + if (!ro) { \ + *((char *)memptr) = '\0'; \ + *((char *)memptr) = test; \ + } \ + test = *((char*)memptr+size-1); \ + if (!ro) { \ + *((char *)memptr+size-1) = '\0'; \ + *((char *)memptr+size-1) = test; \ + } \ + } + +static PyObject * +as_buffer(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *mem; + Py_ssize_t size; + npy_bool ro = NPY_FALSE, check = NPY_TRUE; + void *memptr; + static char *kwlist[] = {"mem", "size", "readonly", "check", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "O" NPY_SSIZE_T_PYFMT "|O&O&:int_asbuffer", kwlist, + &mem, &size, PyArray_BoolConverter, &ro, + PyArray_BoolConverter, &check)) { + return NULL; + } + memptr = PyLong_AsVoidPtr(mem); + if (memptr == NULL) { + return NULL; + } + if (check) { + /* + * Try to dereference the start and end of the memory region + * Catch segfault and report error if it occurs + */ + char test; + int err = 0; + +#ifdef _MSC_VER + __try { + _test_code(); + } + __except(1) { + err = 1; + } +#else + PyOS_sighandler_t _npy_sig_save; + _npy_sig_save = PyOS_setsig(SIGSEGV, _SigSegv_Handler); + if (setjmp(_NPY_SIGSEGV_BUF) == 0) { + _test_code(); + } + else { + err = 1; + } + PyOS_setsig(SIGSEGV, _npy_sig_save); +#endif + if (err) { + PyErr_SetString(PyExc_ValueError, + "cannot use memory location as a buffer."); + return NULL; + } + } + + +#if defined(NPY_PY3K) + PyErr_SetString(PyExc_RuntimeError, + "XXX -- not implemented!"); + return NULL; +#else + if (ro) { + return PyBuffer_FromMemory(memptr, size); + } + return PyBuffer_FromReadWriteMemory(memptr, size); +#endif +} + +#undef _test_code + + +/* + * Prints floating-point scalars usign the Dragon4 algorithm, scientific mode. + * See docstring of `np.format_float_scientific` for description of arguments. + * The differences is that a value of -1 is valid for pad_left, exp_digits, + * precision, which is equivalent to `None`. + */ +static PyObject * +dragon4_scientific(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *obj; + static char *kwlist[] = {"x", "precision", "unique", "sign", "trim", + "pad_left", "exp_digits", NULL}; + int precision=-1, pad_left=-1, exp_digits=-1; + char *trimstr=NULL; + DigitMode digit_mode; + TrimMode trim = TrimMode_None; + int sign=0, unique=1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiisii:dragon4_scientific", + kwlist, &obj, &precision, &unique, &sign, &trimstr, &pad_left, + &exp_digits)) { + return NULL; + } + + if (trimstr != NULL) { + if (strcmp(trimstr, "k") == 0) { + trim = TrimMode_None; + } + else if (strcmp(trimstr, ".") == 0) { + trim = TrimMode_Zeros; + } + else if (strcmp(trimstr, "0") == 0) { + trim = TrimMode_LeaveOneZero; + } + else if (strcmp(trimstr, "-") == 0) { + trim = TrimMode_DptZeros; + } + else { + PyErr_SetString(PyExc_TypeError, + "if supplied, trim must be 'k', '.', '0' or '-'"); + return NULL; + } + } + + digit_mode = unique ? DigitMode_Unique : DigitMode_Exact; + + if (unique == 0 && precision < 0) { + PyErr_SetString(PyExc_TypeError, + "in non-unique mode `precision` must be supplied"); + return NULL; + } + + return Dragon4_Scientific(obj, digit_mode, precision, sign, trim, + pad_left, exp_digits); +} + +/* + * Prints floating-point scalars usign the Dragon4 algorithm, positional mode. + * See docstring of `np.format_float_positional` for description of arguments. + * The differences is that a value of -1 is valid for pad_left, pad_right, + * precision, which is equivalent to `None`. + */ +static PyObject * +dragon4_positional(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *obj; + static char *kwlist[] = {"x", "precision", "unique", "fractional", + "sign", "trim", "pad_left", "pad_right", NULL}; + int precision=-1, pad_left=-1, pad_right=-1; + char *trimstr=NULL; + CutoffMode cutoff_mode; + DigitMode digit_mode; + TrimMode trim = TrimMode_None; + int sign=0, unique=1, fractional=0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiiisii:dragon4_positional", + kwlist, &obj, &precision, &unique, &fractional, &sign, &trimstr, + &pad_left, &pad_right)) { + return NULL; + } + + if (trimstr != NULL) { + if (strcmp(trimstr, "k") == 0) { + trim = TrimMode_None; + } + else if (strcmp(trimstr, ".") == 0) { + trim = TrimMode_Zeros; + } + else if (strcmp(trimstr, "0") == 0) { + trim = TrimMode_LeaveOneZero; + } + else if (strcmp(trimstr, "-") == 0) { + trim = TrimMode_DptZeros; + } + else { + PyErr_SetString(PyExc_TypeError, + "if supplied, trim must be 'k', '.', '0' or '-'"); + return NULL; + } + } + + digit_mode = unique ? DigitMode_Unique : DigitMode_Exact; + cutoff_mode = fractional ? CutoffMode_FractionLength : + CutoffMode_TotalLength; + + if (unique == 0 && precision < 0) { + PyErr_SetString(PyExc_TypeError, + "in non-unique mode `precision` must be supplied"); + return NULL; + } + + return Dragon4_Positional(obj, digit_mode, cutoff_mode, precision, sign, + trim, pad_left, pad_right); +} + +static PyObject * +format_longfloat(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *obj; + unsigned int precision; + static char *kwlist[] = {"x", "precision", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OI:format_longfloat", kwlist, + &obj, &precision)) { + return NULL; + } + if (!PyArray_IsScalar(obj, LongDouble)) { + PyErr_SetString(PyExc_TypeError, + "not a longfloat"); + return NULL; + } + return Dragon4_Scientific(obj, DigitMode_Unique, precision, 0, + TrimMode_LeaveOneZero, -1, -1); +} + +static PyObject * +compare_chararrays(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyObject *array; + PyObject *other; + PyArrayObject *newarr, *newoth; + int cmp_op; + npy_bool rstrip; + char *cmp_str; + Py_ssize_t strlength; + PyObject *res = NULL; + static char msg[] = "comparison must be '==', '!=', '<', '>', '<=', '>='"; + static char *kwlist[] = {"a1", "a2", "cmp", "rstrip", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOs#O&:compare_chararrays", + kwlist, + &array, &other, &cmp_str, &strlength, + PyArray_BoolConverter, &rstrip)) { + return NULL; + } + if (strlength < 1 || strlength > 2) { + goto err; + } + if (strlength > 1) { + if (cmp_str[1] != '=') { + goto err; + } + if (cmp_str[0] == '=') { + cmp_op = Py_EQ; + } + else if (cmp_str[0] == '!') { + cmp_op = Py_NE; + } + else if (cmp_str[0] == '<') { + cmp_op = Py_LE; + } + else if (cmp_str[0] == '>') { + cmp_op = Py_GE; + } + else { + goto err; + } + } + else { + if (cmp_str[0] == '<') { + cmp_op = Py_LT; + } + else if (cmp_str[0] == '>') { + cmp_op = Py_GT; + } + else { + goto err; + } + } + + newarr = (PyArrayObject *)PyArray_FROM_O(array); + if (newarr == NULL) { + return NULL; + } + newoth = (PyArrayObject *)PyArray_FROM_O(other); + if (newoth == NULL) { + Py_DECREF(newarr); + return NULL; + } + if (PyArray_ISSTRING(newarr) && PyArray_ISSTRING(newoth)) { + res = _strings_richcompare(newarr, newoth, cmp_op, rstrip != 0); + } + else { + PyErr_SetString(PyExc_TypeError, + "comparison of non-string arrays"); + } + Py_DECREF(newarr); + Py_DECREF(newoth); + return res; + + err: + PyErr_SetString(PyExc_ValueError, msg); + return NULL; +} + +static PyObject * +_vec_string_with_args(PyArrayObject* char_array, PyArray_Descr* type, + PyObject* method, PyObject* args) +{ + PyObject* broadcast_args[NPY_MAXARGS]; + PyArrayMultiIterObject* in_iter = NULL; + PyArrayObject* result = NULL; + PyArrayIterObject* out_iter = NULL; + Py_ssize_t i, n, nargs; + + nargs = PySequence_Size(args) + 1; + if (nargs == -1 || nargs > NPY_MAXARGS) { + PyErr_Format(PyExc_ValueError, + "len(args) must be < %d", NPY_MAXARGS - 1); + goto err; + } + + broadcast_args[0] = (PyObject*)char_array; + for (i = 1; i < nargs; i++) { + PyObject* item = PySequence_GetItem(args, i-1); + if (item == NULL) { + goto err; + } + broadcast_args[i] = item; + Py_DECREF(item); + } + in_iter = (PyArrayMultiIterObject*)PyArray_MultiIterFromObjects + (broadcast_args, nargs, 0); + if (in_iter == NULL) { + goto err; + } + n = in_iter->numiter; + + result = (PyArrayObject*)PyArray_SimpleNewFromDescr(in_iter->nd, + in_iter->dimensions, type); + if (result == NULL) { + goto err; + } + + out_iter = (PyArrayIterObject*)PyArray_IterNew((PyObject*)result); + if (out_iter == NULL) { + goto err; + } + + while (PyArray_MultiIter_NOTDONE(in_iter)) { + PyObject* item_result; + PyObject* args_tuple = PyTuple_New(n); + if (args_tuple == NULL) { + goto err; + } + + for (i = 0; i < n; i++) { + PyArrayIterObject* it = in_iter->iters[i]; + PyObject* arg = PyArray_ToScalar(PyArray_ITER_DATA(it), it->ao); + if (arg == NULL) { + Py_DECREF(args_tuple); + goto err; + } + /* Steals ref to arg */ + PyTuple_SetItem(args_tuple, i, arg); + } + + item_result = PyObject_CallObject(method, args_tuple); + Py_DECREF(args_tuple); + if (item_result == NULL) { + goto err; + } + + if (PyArray_SETITEM(result, PyArray_ITER_DATA(out_iter), item_result)) { + Py_DECREF(item_result); + PyErr_SetString( PyExc_TypeError, + "result array type does not match underlying function"); + goto err; + } + Py_DECREF(item_result); + + PyArray_MultiIter_NEXT(in_iter); + PyArray_ITER_NEXT(out_iter); + } + + Py_DECREF(in_iter); + Py_DECREF(out_iter); + + return (PyObject*)result; + + err: + Py_XDECREF(in_iter); + Py_XDECREF(out_iter); + Py_XDECREF(result); + + return 0; +} + +static PyObject * +_vec_string_no_args(PyArrayObject* char_array, + PyArray_Descr* type, PyObject* method) +{ + /* + * This is a faster version of _vec_string_args to use when there + * are no additional arguments to the string method. This doesn't + * require a broadcast iterator (and broadcast iterators don't work + * with 1 argument anyway). + */ + PyArrayIterObject* in_iter = NULL; + PyArrayObject* result = NULL; + PyArrayIterObject* out_iter = NULL; + + in_iter = (PyArrayIterObject*)PyArray_IterNew((PyObject*)char_array); + if (in_iter == NULL) { + goto err; + } + + result = (PyArrayObject*)PyArray_SimpleNewFromDescr( + PyArray_NDIM(char_array), PyArray_DIMS(char_array), type); + if (result == NULL) { + goto err; + } + + out_iter = (PyArrayIterObject*)PyArray_IterNew((PyObject*)result); + if (out_iter == NULL) { + goto err; + } + + while (PyArray_ITER_NOTDONE(in_iter)) { + PyObject* item_result; + PyObject* item = PyArray_ToScalar(in_iter->dataptr, in_iter->ao); + if (item == NULL) { + goto err; + } + + item_result = PyObject_CallFunctionObjArgs(method, item, NULL); + Py_DECREF(item); + if (item_result == NULL) { + goto err; + } + + if (PyArray_SETITEM(result, PyArray_ITER_DATA(out_iter), item_result)) { + Py_DECREF(item_result); + PyErr_SetString( PyExc_TypeError, + "result array type does not match underlying function"); + goto err; + } + Py_DECREF(item_result); + + PyArray_ITER_NEXT(in_iter); + PyArray_ITER_NEXT(out_iter); + } + + Py_DECREF(in_iter); + Py_DECREF(out_iter); + + return (PyObject*)result; + + err: + Py_XDECREF(in_iter); + Py_XDECREF(out_iter); + Py_XDECREF(result); + + return 0; +} + +static PyObject * +_vec_string(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) +{ + PyArrayObject* char_array = NULL; + PyArray_Descr *type = NULL; + PyObject* method_name; + PyObject* args_seq = NULL; + + PyObject* method = NULL; + PyObject* result = NULL; + + if (!PyArg_ParseTuple(args, "O&O&O|O", + PyArray_Converter, &char_array, + PyArray_DescrConverter, &type, + &method_name, &args_seq)) { + goto err; + } + + if (PyArray_TYPE(char_array) == NPY_STRING) { + method = PyObject_GetAttr((PyObject *)&PyString_Type, method_name); + } + else if (PyArray_TYPE(char_array) == NPY_UNICODE) { + method = PyObject_GetAttr((PyObject *)&PyUnicode_Type, method_name); + } + else { + PyErr_SetString(PyExc_TypeError, + "string operation on non-string array"); + goto err; + } + if (method == NULL) { + goto err; + } + + if (args_seq == NULL + || (PySequence_Check(args_seq) && PySequence_Size(args_seq) == 0)) { + result = _vec_string_no_args(char_array, type, method); + } + else if (PySequence_Check(args_seq)) { + result = _vec_string_with_args(char_array, type, method, args_seq); + } + else { + PyErr_SetString(PyExc_TypeError, + "'args' must be a sequence of arguments"); + goto err; + } + if (result == NULL) { + goto err; + } + + Py_DECREF(char_array); + Py_DECREF(method); + + return (PyObject*)result; + + err: + Py_XDECREF(char_array); + Py_XDECREF(method); + + return 0; +} + +#ifndef __NPY_PRIVATE_NO_SIGNAL + +static NPY_TLS int sigint_buf_init = 0; +static NPY_TLS NPY_SIGJMP_BUF _NPY_SIGINT_BUF; + +/*NUMPY_API + */ +NPY_NO_EXPORT void +_PyArray_SigintHandler(int signum) +{ + PyOS_setsig(signum, SIG_IGN); + /* + * jump buffer may be uninitialized as SIGINT allowing functions are usually + * run in other threads than the master thread that receives the signal + */ + if (sigint_buf_init > 0) { + NPY_SIGLONGJMP(_NPY_SIGINT_BUF, signum); + } + /* + * sending SIGINT to the worker threads to cancel them is job of the + * application + */ +} + +/*NUMPY_API + */ +NPY_NO_EXPORT void* +_PyArray_GetSigintBuf(void) +{ + sigint_buf_init = 1; + return (void *)&_NPY_SIGINT_BUF; +} + +#else + +NPY_NO_EXPORT void +_PyArray_SigintHandler(int signum) +{ + return; +} + +NPY_NO_EXPORT void* +_PyArray_GetSigintBuf(void) +{ + return NULL; +} + +#endif + + +static PyObject * +test_interrupt(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int kind = 0; + int a = 0; + + if (!PyArg_ParseTuple(args, "|i:test_interrupt", &kind)) { + return NULL; + } + if (kind) { + Py_BEGIN_ALLOW_THREADS; + while (a >= 0) { + if ((a % 1000 == 0) && PyOS_InterruptOccurred()) { + break; + } + a += 1; + } + Py_END_ALLOW_THREADS; + } + else { + NPY_SIGINT_ON + while(a >= 0) { + a += 1; + } + NPY_SIGINT_OFF + } + return PyInt_FromLong(a); +} + + +static PyObject * +array_shares_memory_impl(PyObject *args, PyObject *kwds, Py_ssize_t default_max_work, + int raise_exceptions) +{ + PyObject * self_obj = NULL; + PyObject * other_obj = NULL; + PyArrayObject * self = NULL; + PyArrayObject * other = NULL; + PyObject *max_work_obj = NULL; + static char *kwlist[] = {"self", "other", "max_work", NULL}; + + mem_overlap_t result; + static PyObject *too_hard_cls = NULL; + Py_ssize_t max_work; + NPY_BEGIN_THREADS_DEF; + + max_work = default_max_work; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:shares_memory_impl", kwlist, + &self_obj, &other_obj, &max_work_obj)) { + return NULL; + } + + if (PyArray_Check(self_obj)) { + self = (PyArrayObject*)self_obj; + Py_INCREF(self); + } + else { + /* Use FromAny to enable checking overlap for objects exposing array + interfaces etc. */ + self = (PyArrayObject*)PyArray_FROM_O(self_obj); + if (self == NULL) { + goto fail; + } + } + + if (PyArray_Check(other_obj)) { + other = (PyArrayObject*)other_obj; + Py_INCREF(other); + } + else { + other = (PyArrayObject*)PyArray_FROM_O(other_obj); + if (other == NULL) { + goto fail; + } + } + + if (max_work_obj == NULL || max_work_obj == Py_None) { + /* noop */ + } + else if (PyLong_Check(max_work_obj)) { + max_work = PyLong_AsSsize_t(max_work_obj); + if (PyErr_Occurred()) { + goto fail; + } + } +#if !defined(NPY_PY3K) + else if (PyInt_Check(max_work_obj)) { + max_work = PyInt_AsSsize_t(max_work_obj); + } +#endif + else { + PyErr_SetString(PyExc_ValueError, "max_work must be an integer"); + goto fail; + } + + if (max_work < -2) { + PyErr_SetString(PyExc_ValueError, "Invalid value for max_work"); + goto fail; + } + + NPY_BEGIN_THREADS; + result = solve_may_share_memory(self, other, max_work); + NPY_END_THREADS; + + Py_XDECREF(self); + Py_XDECREF(other); + + if (result == MEM_OVERLAP_NO) { + Py_RETURN_FALSE; + } + else if (result == MEM_OVERLAP_YES) { + Py_RETURN_TRUE; + } + else if (result == MEM_OVERLAP_OVERFLOW) { + if (raise_exceptions) { + PyErr_SetString(PyExc_OverflowError, + "Integer overflow in computing overlap"); + return NULL; + } + else { + /* Don't know, so say yes */ + Py_RETURN_TRUE; + } + } + else if (result == MEM_OVERLAP_TOO_HARD) { + if (raise_exceptions) { + npy_cache_import("numpy.core._internal", "TooHardError", + &too_hard_cls); + if (too_hard_cls) { + PyErr_SetString(too_hard_cls, "Exceeded max_work"); + } + return NULL; + } + else { + /* Don't know, so say yes */ + Py_RETURN_TRUE; + } + } + else { + /* Doesn't happen usually */ + PyErr_SetString(PyExc_RuntimeError, + "Error in computing overlap"); + return NULL; + } + +fail: + Py_XDECREF(self); + Py_XDECREF(other); + return NULL; +} + + +static PyObject * +array_shares_memory(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + return array_shares_memory_impl(args, kwds, NPY_MAY_SHARE_EXACT, 1); +} + + +static PyObject * +array_may_share_memory(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ + return array_shares_memory_impl(args, kwds, NPY_MAY_SHARE_BOUNDS, 0); +} + +static PyObject * +normalize_axis_index(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"axis", "ndim", "msg_prefix", NULL}; + int axis; + int ndim; + PyObject *msg_prefix = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii|O:normalize_axis_index", + kwlist, &axis, &ndim, &msg_prefix)) { + return NULL; + } + if (check_and_adjust_axis_msg(&axis, ndim, msg_prefix) < 0) { + return NULL; + } + + return PyInt_FromLong(axis); +} + +static struct PyMethodDef array_module_methods[] = { + {"_get_ndarray_c_version", + (PyCFunction)array__get_ndarray_c_version, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"_reconstruct", + (PyCFunction)array__reconstruct, + METH_VARARGS, NULL}, + {"set_string_function", + (PyCFunction)array_set_string_function, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"set_numeric_ops", + (PyCFunction)array_set_ops_function, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"set_datetimeparse_function", + (PyCFunction)array_set_datetimeparse_function, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"set_typeDict", + (PyCFunction)array_set_typeDict, + METH_VARARGS, NULL}, + {"array", + (PyCFunction)_array_fromobject, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"copyto", + (PyCFunction)array_copyto, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"nested_iters", + (PyCFunction)NpyIter_NestedIters, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"arange", + (PyCFunction)array_arange, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"zeros", + (PyCFunction)array_zeros, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"count_nonzero", + (PyCFunction)array_count_nonzero, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"empty", + (PyCFunction)array_empty, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"empty_like", + (PyCFunction)array_empty_like, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"scalar", + (PyCFunction)array_scalar, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"where", + (PyCFunction)array_where, + METH_VARARGS, NULL}, + {"lexsort", + (PyCFunction)array_lexsort, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"putmask", + (PyCFunction)array_putmask, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"fromstring", + (PyCFunction)array_fromstring, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"fromiter", + (PyCFunction)array_fromiter, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"concatenate", + (PyCFunction)array_concatenate, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"inner", + (PyCFunction)array_innerproduct, + METH_VARARGS, NULL}, + {"dot", + (PyCFunction)array_matrixproduct, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"vdot", + (PyCFunction)array_vdot, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"matmul", + (PyCFunction)array_matmul, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"c_einsum", + (PyCFunction)array_einsum, + METH_VARARGS|METH_KEYWORDS, NULL}, + {"_fastCopyAndTranspose", + (PyCFunction)array_fastCopyAndTranspose, + METH_VARARGS, NULL}, + {"correlate", + (PyCFunction)array_correlate, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"correlate2", + (PyCFunction)array_correlate2, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"frombuffer", + (PyCFunction)array_frombuffer, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"fromfile", + (PyCFunction)array_fromfile, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"can_cast", + (PyCFunction)array_can_cast_safely, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"promote_types", + (PyCFunction)array_promote_types, + METH_VARARGS, NULL}, + {"min_scalar_type", + (PyCFunction)array_min_scalar_type, + METH_VARARGS, NULL}, + {"result_type", + (PyCFunction)array_result_type, + METH_VARARGS, NULL}, + {"shares_memory", + (PyCFunction)array_shares_memory, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"may_share_memory", + (PyCFunction)array_may_share_memory, + METH_VARARGS | METH_KEYWORDS, NULL}, + /* Datetime-related functions */ + {"datetime_data", + (PyCFunction)array_datetime_data, + METH_VARARGS, NULL}, + {"datetime_as_string", + (PyCFunction)array_datetime_as_string, + METH_VARARGS | METH_KEYWORDS, NULL}, + /* Datetime business-day API */ + {"busday_offset", + (PyCFunction)array_busday_offset, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"busday_count", + (PyCFunction)array_busday_count, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"is_busday", + (PyCFunction)array_is_busday, + METH_VARARGS | METH_KEYWORDS, NULL}, +#if !defined(NPY_PY3K) + {"newbuffer", + (PyCFunction)new_buffer, + METH_VARARGS, NULL}, + {"getbuffer", + (PyCFunction)buffer_buffer, + METH_VARARGS | METH_KEYWORDS, NULL}, +#endif + {"int_asbuffer", + (PyCFunction)as_buffer, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"format_longfloat", + (PyCFunction)format_longfloat, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"dragon4_positional", + (PyCFunction)dragon4_positional, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"dragon4_scientific", + (PyCFunction)dragon4_scientific, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"compare_chararrays", + (PyCFunction)compare_chararrays, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"_vec_string", + (PyCFunction)_vec_string, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"test_interrupt", + (PyCFunction)test_interrupt, + METH_VARARGS, NULL}, + {"_insert", (PyCFunction)arr_insert, + METH_VARARGS | METH_KEYWORDS, + "Insert vals sequentially into equivalent 1-d positions " + "indicated by mask."}, + {"bincount", (PyCFunction)arr_bincount, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"digitize", (PyCFunction)arr_digitize, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"interp", (PyCFunction)arr_interp, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"interp_complex", (PyCFunction)arr_interp_complex, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"ravel_multi_index", (PyCFunction)arr_ravel_multi_index, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"unravel_index", (PyCFunction)arr_unravel_index, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"add_docstring", (PyCFunction)arr_add_docstring, + METH_VARARGS, NULL}, + {"packbits", (PyCFunction)io_pack, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"unpackbits", (PyCFunction)io_unpack, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"normalize_axis_index", (PyCFunction)normalize_axis_index, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"set_legacy_print_mode", (PyCFunction)set_legacy_print_mode, + METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} /* sentinel */ +}; + +#include "__multiarray_api.c" + +/* Establish scalar-type hierarchy + * + * For dual inheritance we need to make sure that the objects being + * inherited from have the tp->mro object initialized. This is + * not necessarily true for the basic type objects of Python (it is + * checked for single inheritance but not dual in PyType_Ready). + * + * Thus, we call PyType_Ready on the standard Python Types, here. + */ +static int +setup_scalartypes(PyObject *NPY_UNUSED(dict)) +{ + initialize_casting_tables(); + initialize_numeric_types(); + + if (PyType_Ready(&PyBool_Type) < 0) { + return -1; + } +#if !defined(NPY_PY3K) + if (PyType_Ready(&PyInt_Type) < 0) { + return -1; + } +#endif + if (PyType_Ready(&PyFloat_Type) < 0) { + return -1; + } + if (PyType_Ready(&PyComplex_Type) < 0) { + return -1; + } + if (PyType_Ready(&PyString_Type) < 0) { + return -1; + } + if (PyType_Ready(&PyUnicode_Type) < 0) { + return -1; + } + +#define SINGLE_INHERIT(child, parent) \ + Py##child##ArrType_Type.tp_base = &Py##parent##ArrType_Type; \ + if (PyType_Ready(&Py##child##ArrType_Type) < 0) { \ + PyErr_Print(); \ + PyErr_Format(PyExc_SystemError, \ + "could not initialize Py%sArrType_Type", \ + #child); \ + return -1; \ + } + + if (PyType_Ready(&PyGenericArrType_Type) < 0) { + return -1; + } + SINGLE_INHERIT(Number, Generic); + SINGLE_INHERIT(Integer, Number); + SINGLE_INHERIT(Inexact, Number); + SINGLE_INHERIT(SignedInteger, Integer); + SINGLE_INHERIT(UnsignedInteger, Integer); + SINGLE_INHERIT(Floating, Inexact); + SINGLE_INHERIT(ComplexFloating, Inexact); + SINGLE_INHERIT(Flexible, Generic); + SINGLE_INHERIT(Character, Flexible); + +#define DUAL_INHERIT(child, parent1, parent2) \ + Py##child##ArrType_Type.tp_base = &Py##parent2##ArrType_Type; \ + Py##child##ArrType_Type.tp_bases = \ + Py_BuildValue("(OO)", &Py##parent2##ArrType_Type, \ + &Py##parent1##_Type); \ + Py##child##ArrType_Type.tp_hash = Py##parent1##_Type.tp_hash; \ + if (PyType_Ready(&Py##child##ArrType_Type) < 0) { \ + PyErr_Print(); \ + PyErr_Format(PyExc_SystemError, \ + "could not initialize Py%sArrType_Type", \ + #child); \ + return -1; \ + } + +/* + * In Py3K, int is no longer a fixed-width integer type, so don't + * inherit numpy.int_ from it. + */ +#if defined(NPY_PY3K) +#define INHERIT_INT(child, parent2) \ + SINGLE_INHERIT(child, parent2); +#else +#define INHERIT_INT(child, parent2) \ + Py##child##ArrType_Type.tp_flags |= Py_TPFLAGS_INT_SUBCLASS; \ + DUAL_INHERIT(child, Int, parent2); +#endif + +#if defined(NPY_PY3K) +#define DUAL_INHERIT_COMPARE(child, parent1, parent2) +#else +#define DUAL_INHERIT_COMPARE(child, parent1, parent2) \ + Py##child##ArrType_Type.tp_compare = \ + Py##parent1##_Type.tp_compare; +#endif + +#define DUAL_INHERIT2(child, parent1, parent2) \ + Py##child##ArrType_Type.tp_base = &Py##parent1##_Type; \ + Py##child##ArrType_Type.tp_bases = \ + Py_BuildValue("(OO)", &Py##parent1##_Type, \ + &Py##parent2##ArrType_Type); \ + Py##child##ArrType_Type.tp_richcompare = \ + Py##parent1##_Type.tp_richcompare; \ + DUAL_INHERIT_COMPARE(child, parent1, parent2) \ + Py##child##ArrType_Type.tp_hash = Py##parent1##_Type.tp_hash; \ + if (PyType_Ready(&Py##child##ArrType_Type) < 0) { \ + PyErr_Print(); \ + PyErr_Format(PyExc_SystemError, \ + "could not initialize Py%sArrType_Type", \ + #child); \ + return -1; \ + } + + SINGLE_INHERIT(Bool, Generic); + SINGLE_INHERIT(Byte, SignedInteger); + SINGLE_INHERIT(Short, SignedInteger); + +#if NPY_SIZEOF_INT == NPY_SIZEOF_LONG + INHERIT_INT(Int, SignedInteger); +#else + SINGLE_INHERIT(Int, SignedInteger); +#endif + + INHERIT_INT(Long, SignedInteger); + +#if NPY_SIZEOF_LONGLONG == NPY_SIZEOF_LONG + INHERIT_INT(LongLong, SignedInteger); +#else + SINGLE_INHERIT(LongLong, SignedInteger); +#endif + + /* Datetime doesn't fit in any category */ + SINGLE_INHERIT(Datetime, Generic); + /* Timedelta is an integer with an associated unit */ + SINGLE_INHERIT(Timedelta, SignedInteger); + + /* + fprintf(stderr, + "tp_free = %p, PyObject_Del = %p, int_tp_free = %p, base.tp_free = %p\n", + PyIntArrType_Type.tp_free, PyObject_Del, PyInt_Type.tp_free, + PySignedIntegerArrType_Type.tp_free); + */ + SINGLE_INHERIT(UByte, UnsignedInteger); + SINGLE_INHERIT(UShort, UnsignedInteger); + SINGLE_INHERIT(UInt, UnsignedInteger); + SINGLE_INHERIT(ULong, UnsignedInteger); + SINGLE_INHERIT(ULongLong, UnsignedInteger); + + SINGLE_INHERIT(Half, Floating); + SINGLE_INHERIT(Float, Floating); + DUAL_INHERIT(Double, Float, Floating); + SINGLE_INHERIT(LongDouble, Floating); + + SINGLE_INHERIT(CFloat, ComplexFloating); + DUAL_INHERIT(CDouble, Complex, ComplexFloating); + SINGLE_INHERIT(CLongDouble, ComplexFloating); + + DUAL_INHERIT2(String, String, Character); + DUAL_INHERIT2(Unicode, Unicode, Character); + + SINGLE_INHERIT(Void, Flexible); + + SINGLE_INHERIT(Object, Generic); + + return 0; + +#undef SINGLE_INHERIT +#undef DUAL_INHERIT +#undef INHERIT_INT +#undef DUAL_INHERIT2 +#undef DUAL_INHERIT_COMPARE + + /* + * Clean up string and unicode array types so they act more like + * strings -- get their tables from the standard types. + */ +} + +/* place a flag dictionary in d */ + +static void +set_flaginfo(PyObject *d) +{ + PyObject *s; + PyObject *newd; + + newd = PyDict_New(); + +#define _addnew(key, val, one) \ + PyDict_SetItemString(newd, #key, s=PyInt_FromLong(val)); \ + Py_DECREF(s); \ + PyDict_SetItemString(newd, #one, s=PyInt_FromLong(val)); \ + Py_DECREF(s) + +#define _addone(key, val) \ + PyDict_SetItemString(newd, #key, s=PyInt_FromLong(val)); \ + Py_DECREF(s) + + _addnew(OWNDATA, NPY_ARRAY_OWNDATA, O); + _addnew(FORTRAN, NPY_ARRAY_F_CONTIGUOUS, F); + _addnew(CONTIGUOUS, NPY_ARRAY_C_CONTIGUOUS, C); + _addnew(ALIGNED, NPY_ARRAY_ALIGNED, A); + _addnew(UPDATEIFCOPY, NPY_ARRAY_UPDATEIFCOPY, U); + _addnew(WRITEBACKIFCOPY, NPY_ARRAY_WRITEBACKIFCOPY, X); + _addnew(WRITEABLE, NPY_ARRAY_WRITEABLE, W); + _addone(C_CONTIGUOUS, NPY_ARRAY_C_CONTIGUOUS); + _addone(F_CONTIGUOUS, NPY_ARRAY_F_CONTIGUOUS); + +#undef _addone +#undef _addnew + + PyDict_SetItemString(d, "_flagdict", newd); + Py_DECREF(newd); + return; +} + +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_array = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_array_prepare = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_array_wrap = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_array_finalize = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_buffer = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_ufunc = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_order = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_copy = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_dtype = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_ndmin = NULL; + +static int +intern_strings(void) +{ + npy_ma_str_array = PyUString_InternFromString("__array__"); + npy_ma_str_array_prepare = PyUString_InternFromString("__array_prepare__"); + npy_ma_str_array_wrap = PyUString_InternFromString("__array_wrap__"); + npy_ma_str_array_finalize = PyUString_InternFromString("__array_finalize__"); + npy_ma_str_buffer = PyUString_InternFromString("__buffer__"); + npy_ma_str_ufunc = PyUString_InternFromString("__array_ufunc__"); + npy_ma_str_order = PyUString_InternFromString("order"); + npy_ma_str_copy = PyUString_InternFromString("copy"); + npy_ma_str_dtype = PyUString_InternFromString("dtype"); + npy_ma_str_ndmin = PyUString_InternFromString("ndmin"); + + return npy_ma_str_array && npy_ma_str_array_prepare && + npy_ma_str_array_wrap && npy_ma_str_array_finalize && + npy_ma_str_buffer && npy_ma_str_ufunc && + npy_ma_str_order && npy_ma_str_copy && npy_ma_str_dtype && + npy_ma_str_ndmin; +} + + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "multiarray", + NULL, + -1, + array_module_methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +/* Initialization function for the module */ +#if defined(NPY_PY3K) +#define RETVAL m +PyMODINIT_FUNC PyInit_multiarray(void) { +#else +#define RETVAL +PyMODINIT_FUNC initmultiarray(void) { +#endif + PyObject *m, *d, *s; + PyObject *c_api; + + /* Create the module and add the functions */ +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("multiarray", array_module_methods); +#endif + if (!m) { + goto err; + } + +#if defined(MS_WIN64) && defined(__GNUC__) + PyErr_WarnEx(PyExc_Warning, + "Numpy built with MINGW-W64 on Windows 64 bits is experimental, " \ + "and only available for \n" \ + "testing. You are advised not to use it for production. \n\n" \ + "CRASHES ARE TO BE EXPECTED - PLEASE REPORT THEM TO NUMPY DEVELOPERS", + 1); +#endif + + /* Initialize access to the PyDateTime API */ + numpy_pydatetime_import(); + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + if (!d) { + goto err; + } + + /* + * Before calling PyType_Ready, initialize the tp_hash slot in + * PyArray_Type to work around mingw32 not being able initialize + * static structure slots with functions from the Python C_API. + */ + PyArray_Type.tp_hash = PyObject_HashNotImplemented; + if (PyType_Ready(&PyArray_Type) < 0) { + return RETVAL; + } + if (setup_scalartypes(d) < 0) { + goto err; + } + PyArrayIter_Type.tp_iter = PyObject_SelfIter; + NpyIter_Type.tp_iter = PyObject_SelfIter; + PyArrayMultiIter_Type.tp_iter = PyObject_SelfIter; + PyArrayMultiIter_Type.tp_free = PyArray_free; + if (PyType_Ready(&PyArrayIter_Type) < 0) { + return RETVAL; + } + if (PyType_Ready(&PyArrayMapIter_Type) < 0) { + return RETVAL; + } + if (PyType_Ready(&PyArrayMultiIter_Type) < 0) { + return RETVAL; + } + PyArrayNeighborhoodIter_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyArrayNeighborhoodIter_Type) < 0) { + return RETVAL; + } + if (PyType_Ready(&NpyIter_Type) < 0) { + return RETVAL; + } + + PyArrayDescr_Type.tp_hash = PyArray_DescrHash; + if (PyType_Ready(&PyArrayDescr_Type) < 0) { + return RETVAL; + } + if (PyType_Ready(&PyArrayFlags_Type) < 0) { + return RETVAL; + } + NpyBusDayCalendar_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&NpyBusDayCalendar_Type) < 0) { + return RETVAL; + } + + c_api = NpyCapsule_FromVoidPtr((void *)PyArray_API, NULL); + if (c_api == NULL) { + goto err; + } + PyDict_SetItemString(d, "_ARRAY_API", c_api); + Py_DECREF(c_api); + + /* + * PyExc_Exception should catch all the standard errors that are + * now raised instead of the string exception "multiarray.error" + + * This is for backward compatibility with existing code. + */ + PyDict_SetItemString (d, "error", PyExc_Exception); + + s = PyInt_FromLong(NPY_TRACE_DOMAIN); + PyDict_SetItemString(d, "tracemalloc_domain", s); + Py_DECREF(s); + + s = PyUString_FromString("3.1"); + PyDict_SetItemString(d, "__version__", s); + Py_DECREF(s); + + s = NpyCapsule_FromVoidPtr((void *)_datetime_strings, NULL); + if (s == NULL) { + goto err; + } + PyDict_SetItemString(d, "DATETIMEUNITS", s); + Py_DECREF(s); + +#define ADDCONST(NAME) \ + s = PyInt_FromLong(NPY_##NAME); \ + PyDict_SetItemString(d, #NAME, s); \ + Py_DECREF(s) + + + ADDCONST(ALLOW_THREADS); + ADDCONST(BUFSIZE); + ADDCONST(CLIP); + + ADDCONST(ITEM_HASOBJECT); + ADDCONST(LIST_PICKLE); + ADDCONST(ITEM_IS_POINTER); + ADDCONST(NEEDS_INIT); + ADDCONST(NEEDS_PYAPI); + ADDCONST(USE_GETITEM); + ADDCONST(USE_SETITEM); + + ADDCONST(RAISE); + ADDCONST(WRAP); + ADDCONST(MAXDIMS); + + ADDCONST(MAY_SHARE_BOUNDS); + ADDCONST(MAY_SHARE_EXACT); +#undef ADDCONST + + PyDict_SetItemString(d, "ndarray", (PyObject *)&PyArray_Type); + PyDict_SetItemString(d, "flatiter", (PyObject *)&PyArrayIter_Type); + PyDict_SetItemString(d, "nditer", (PyObject *)&NpyIter_Type); + PyDict_SetItemString(d, "broadcast", + (PyObject *)&PyArrayMultiIter_Type); + PyDict_SetItemString(d, "dtype", (PyObject *)&PyArrayDescr_Type); + PyDict_SetItemString(d, "flagsobj", (PyObject *)&PyArrayFlags_Type); + + /* Business day calendar object */ + PyDict_SetItemString(d, "busdaycalendar", + (PyObject *)&NpyBusDayCalendar_Type); + set_flaginfo(d); + + if (!intern_strings()) { + goto err; + } + + if (set_typeinfo(d) != 0) { + goto err; + } + return RETVAL; + + err: + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot load multiarray module."); + } + return RETVAL; +} diff --git a/numpy/core/src/multiarray/multiarraymodule.h b/numpy/core/src/multiarray/multiarraymodule.h new file mode 100644 index 0000000..82ae248 --- /dev/null +++ b/numpy/core/src/multiarray/multiarraymodule.h @@ -0,0 +1,15 @@ +#ifndef _NPY_MULTIARRAY_H_ +#define _NPY_MULTIARRAY_H_ + +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_array; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_array_prepare; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_array_wrap; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_array_finalize; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_buffer; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_ufunc; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_order; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_copy; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_dtype; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_ndmin; + +#endif diff --git a/numpy/core/src/multiarray/nditer_api.c b/numpy/core/src/multiarray/nditer_api.c new file mode 100644 index 0000000..f2bc237 --- /dev/null +++ b/numpy/core/src/multiarray/nditer_api.c @@ -0,0 +1,2803 @@ +/* + * This file implements most of the main API functions of NumPy's nditer. + * This excludes functions specialized using the templating system. + * + * Copyright (c) 2010-2011 by Mark Wiebe (mwwiebe@gmail.com) + * The University of British Columbia + * + * Copyright (c) 2011 Enthought, Inc + * + * See LICENSE.txt for the license. + */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +/* Indicate that this .c file is allowed to include the header */ +#define NPY_ITERATOR_IMPLEMENTATION_CODE +#include "nditer_impl.h" +#include "templ_common.h" + +/* Internal helper functions private to this file */ +static npy_intp +npyiter_checkreducesize(NpyIter *iter, npy_intp count, + npy_intp *reduce_innersize, + npy_intp *reduce_outerdim); + +/*NUMPY_API + * Removes an axis from iteration. This requires that NPY_ITER_MULTI_INDEX + * was set for iterator creation, and does not work if buffering is + * enabled. This function also resets the iterator to its initial state. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +NPY_NO_EXPORT int +NpyIter_RemoveAxis(NpyIter *iter, int axis) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + int xdim = 0; + npy_int8 *perm = NIT_PERM(iter); + NpyIter_AxisData *axisdata_del = NIT_AXISDATA(iter), *axisdata; + npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + npy_intp *baseoffsets = NIT_BASEOFFSETS(iter); + char **resetdataptr = NIT_RESETDATAPTR(iter); + + if (!(itflags&NPY_ITFLAG_HASMULTIINDEX)) { + PyErr_SetString(PyExc_RuntimeError, + "Iterator RemoveAxis may only be called " + "if a multi-index is being tracked"); + return NPY_FAIL; + } + else if (itflags&NPY_ITFLAG_HASINDEX) { + PyErr_SetString(PyExc_RuntimeError, + "Iterator RemoveAxis may not be called on " + "an index is being tracked"); + return NPY_FAIL; + } + else if (itflags&NPY_ITFLAG_BUFFER) { + PyErr_SetString(PyExc_RuntimeError, + "Iterator RemoveAxis may not be called on " + "a buffered iterator"); + return NPY_FAIL; + } + else if (axis < 0 || axis >= ndim) { + PyErr_SetString(PyExc_ValueError, + "axis out of bounds in iterator RemoveAxis"); + return NPY_FAIL; + } + + /* Reverse axis, since the iterator treats them that way */ + axis = ndim - 1 - axis; + + /* First find the axis in question */ + for (idim = 0; idim < ndim; ++idim) { + /* If this is it, and it's iterated forward, done */ + if (perm[idim] == axis) { + xdim = idim; + break; + } + /* If this is it, but it's iterated backward, must reverse the axis */ + else if (-1 - perm[idim] == axis) { + npy_intp *strides = NAD_STRIDES(axisdata_del); + npy_intp shape = NAD_SHAPE(axisdata_del), offset; + + xdim = idim; + + /* + * Adjust baseoffsets and resetbaseptr back to the start of + * this axis. + */ + for (iop = 0; iop < nop; ++iop) { + offset = (shape-1)*strides[iop]; + baseoffsets[iop] += offset; + resetdataptr[iop] += offset; + } + break; + } + + NIT_ADVANCE_AXISDATA(axisdata_del, 1); + } + + if (idim == ndim) { + PyErr_SetString(PyExc_RuntimeError, + "internal error in iterator perm"); + return NPY_FAIL; + } + + /* Adjust the permutation */ + for (idim = 0; idim < ndim-1; ++idim) { + npy_int8 p = (idim < xdim) ? perm[idim] : perm[idim+1]; + if (p >= 0) { + if (p > axis) { + --p; + } + } + else if (p <= 0) { + if (p < -1-axis) { + ++p; + } + } + perm[idim] = p; + } + + /* Shift all the axisdata structures by one */ + axisdata = NIT_INDEX_AXISDATA(axisdata_del, 1); + memmove(axisdata_del, axisdata, (ndim-1-xdim)*sizeof_axisdata); + + /* Adjust the iteration size and reset iterend */ + NIT_ITERSIZE(iter) = 1; + axisdata = NIT_AXISDATA(iter); + for (idim = 0; idim < ndim-1; ++idim) { + if (npy_mul_with_overflow_intp(&NIT_ITERSIZE(iter), + NIT_ITERSIZE(iter), NAD_SHAPE(axisdata))) { + NIT_ITERSIZE(iter) = -1; + break; + } + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + NIT_ITEREND(iter) = NIT_ITERSIZE(iter); + + /* Shrink the iterator */ + NIT_NDIM(iter) = ndim - 1; + /* If it is now 0-d fill the singleton dimension */ + if (ndim == 1) { + npy_intp *strides = NAD_STRIDES(axisdata_del); + NAD_SHAPE(axisdata_del) = 1; + for (iop = 0; iop < nop; ++iop) { + strides[iop] = 0; + } + NIT_ITFLAGS(iter) |= NPY_ITFLAG_ONEITERATION; + } + + return NpyIter_Reset(iter, NULL); +} + +/*NUMPY_API + * Removes multi-index support from an iterator. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +NPY_NO_EXPORT int +NpyIter_RemoveMultiIndex(NpyIter *iter) +{ + npy_uint32 itflags; + + /* Make sure the iterator is reset */ + if (NpyIter_Reset(iter, NULL) != NPY_SUCCEED) { + return NPY_FAIL; + } + + itflags = NIT_ITFLAGS(iter); + if (itflags&NPY_ITFLAG_HASMULTIINDEX) { + if (NIT_ITERSIZE(iter) < 0) { + PyErr_SetString(PyExc_ValueError, "iterator is too large"); + return NPY_FAIL; + } + + NIT_ITFLAGS(iter) = itflags & ~NPY_ITFLAG_HASMULTIINDEX; + npyiter_coalesce_axes(iter); + } + + return NPY_SUCCEED; +} + +/*NUMPY_API + * Removes the inner loop handling (so HasExternalLoop returns true) + */ +NPY_NO_EXPORT int +NpyIter_EnableExternalLoop(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + /* Check conditions under which this can be done */ + if (itflags&(NPY_ITFLAG_HASINDEX|NPY_ITFLAG_HASMULTIINDEX)) { + PyErr_SetString(PyExc_ValueError, + "Iterator flag EXTERNAL_LOOP cannot be used " + "if an index or multi-index is being tracked"); + return NPY_FAIL; + } + if ((itflags&(NPY_ITFLAG_BUFFER|NPY_ITFLAG_RANGE|NPY_ITFLAG_EXLOOP)) + == (NPY_ITFLAG_RANGE|NPY_ITFLAG_EXLOOP)) { + PyErr_SetString(PyExc_ValueError, + "Iterator flag EXTERNAL_LOOP cannot be used " + "with ranged iteration unless buffering is also enabled"); + return NPY_FAIL; + } + /* Set the flag */ + if (!(itflags&NPY_ITFLAG_EXLOOP)) { + itflags |= NPY_ITFLAG_EXLOOP; + NIT_ITFLAGS(iter) = itflags; + + /* + * Check whether we can apply the single iteration + * optimization to the iternext function. + */ + if (!(itflags&NPY_ITFLAG_BUFFER)) { + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + if (NIT_ITERSIZE(iter) == NAD_SHAPE(axisdata)) { + NIT_ITFLAGS(iter) |= NPY_ITFLAG_ONEITERATION; + } + } + } + + /* Reset the iterator */ + return NpyIter_Reset(iter, NULL); +} + +/*NUMPY_API + * Resets the iterator to its initial state + * + * If errmsg is non-NULL, it should point to a variable which will + * receive the error message, and no Python exception will be set. + * This is so that the function can be called from code not holding + * the GIL. + */ +NPY_NO_EXPORT int +NpyIter_Reset(NpyIter *iter, char **errmsg) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *bufferdata; + + /* If buffer allocation was delayed, do it now */ + if (itflags&NPY_ITFLAG_DELAYBUF) { + if (!npyiter_allocate_buffers(iter, errmsg)) { + return NPY_FAIL; + } + NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_DELAYBUF; + } + else { + /* + * If the iterindex is already right, no need to + * do anything + */ + bufferdata = NIT_BUFFERDATA(iter); + if (NIT_ITERINDEX(iter) == NIT_ITERSTART(iter) && + NBF_BUFITEREND(bufferdata) <= NIT_ITEREND(iter) && + NBF_SIZE(bufferdata) > 0) { + return NPY_SUCCEED; + } + + /* Copy any data from the buffers back to the arrays */ + npyiter_copy_from_buffers(iter); + } + } + + npyiter_goto_iterindex(iter, NIT_ITERSTART(iter)); + + if (itflags&NPY_ITFLAG_BUFFER) { + /* Prepare the next buffers and set iterend/size */ + npyiter_copy_to_buffers(iter, NULL); + } + + return NPY_SUCCEED; +} + +/*NUMPY_API + * Resets the iterator to its initial state, with new base data pointers. + * This function requires great caution. + * + * If errmsg is non-NULL, it should point to a variable which will + * receive the error message, and no Python exception will be set. + * This is so that the function can be called from code not holding + * the GIL. + */ +NPY_NO_EXPORT int +NpyIter_ResetBasePointers(NpyIter *iter, char **baseptrs, char **errmsg) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int iop, nop = NIT_NOP(iter); + + char **resetdataptr = NIT_RESETDATAPTR(iter); + npy_intp *baseoffsets = NIT_BASEOFFSETS(iter); + + if (itflags&NPY_ITFLAG_BUFFER) { + /* If buffer allocation was delayed, do it now */ + if (itflags&NPY_ITFLAG_DELAYBUF) { + if (!npyiter_allocate_buffers(iter, errmsg)) { + return NPY_FAIL; + } + NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_DELAYBUF; + } + else { + /* Copy any data from the buffers back to the arrays */ + npyiter_copy_from_buffers(iter); + } + } + + /* The new data pointers for resetting */ + for (iop = 0; iop < nop; ++iop) { + resetdataptr[iop] = baseptrs[iop] + baseoffsets[iop]; + } + + npyiter_goto_iterindex(iter, NIT_ITERSTART(iter)); + + if (itflags&NPY_ITFLAG_BUFFER) { + /* Prepare the next buffers and set iterend/size */ + npyiter_copy_to_buffers(iter, NULL); + } + + return NPY_SUCCEED; +} + +/*NUMPY_API + * Resets the iterator to a new iterator index range + * + * If errmsg is non-NULL, it should point to a variable which will + * receive the error message, and no Python exception will be set. + * This is so that the function can be called from code not holding + * the GIL. + */ +NPY_NO_EXPORT int +NpyIter_ResetToIterIndexRange(NpyIter *iter, + npy_intp istart, npy_intp iend, char **errmsg) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + /*int nop = NIT_NOP(iter);*/ + + if (!(itflags&NPY_ITFLAG_RANGE)) { + if (errmsg == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot call ResetToIterIndexRange on an iterator without " + "requesting ranged iteration support in the constructor"); + } + else { + *errmsg = "Cannot call ResetToIterIndexRange on an iterator " + "without requesting ranged iteration support in the " + "constructor"; + } + return NPY_FAIL; + } + + if (istart < 0 || iend > NIT_ITERSIZE(iter)) { + if (NIT_ITERSIZE(iter) < 0) { + if (errmsg == NULL) { + PyErr_SetString(PyExc_ValueError, "iterator is too large"); + } + else { + *errmsg = "iterator is too large"; + } + return NPY_FAIL; + } + if (errmsg == NULL) { + PyErr_Format(PyExc_ValueError, + "Out-of-bounds range [%d, %d) passed to " + "ResetToIterIndexRange", (int)istart, (int)iend); + } + else { + *errmsg = "Out-of-bounds range passed to ResetToIterIndexRange"; + } + return NPY_FAIL; + } + else if (iend < istart) { + if (errmsg == NULL) { + PyErr_Format(PyExc_ValueError, + "Invalid range [%d, %d) passed to ResetToIterIndexRange", + (int)istart, (int)iend); + } + else { + *errmsg = "Invalid range passed to ResetToIterIndexRange"; + } + return NPY_FAIL; + } + + NIT_ITERSTART(iter) = istart; + NIT_ITEREND(iter) = iend; + + return NpyIter_Reset(iter, errmsg); +} + +/*NUMPY_API + * Sets the iterator to the specified multi-index, which must have the + * correct number of entries for 'ndim'. It is only valid + * when NPY_ITER_MULTI_INDEX was passed to the constructor. This operation + * fails if the multi-index is out of bounds. + * + * Returns NPY_SUCCEED on success, NPY_FAIL on failure. + */ +NPY_NO_EXPORT int +NpyIter_GotoMultiIndex(NpyIter *iter, npy_intp *multi_index) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_intp iterindex, factor; + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + npy_int8 *perm; + + if (!(itflags&NPY_ITFLAG_HASMULTIINDEX)) { + PyErr_SetString(PyExc_ValueError, + "Cannot call GotoMultiIndex on an iterator without " + "requesting a multi-index in the constructor"); + return NPY_FAIL; + } + + if (itflags&NPY_ITFLAG_BUFFER) { + PyErr_SetString(PyExc_ValueError, + "Cannot call GotoMultiIndex on an iterator which " + "is buffered"); + return NPY_FAIL; + } + + if (itflags&NPY_ITFLAG_EXLOOP) { + PyErr_SetString(PyExc_ValueError, + "Cannot call GotoMultiIndex on an iterator which " + "has the flag EXTERNAL_LOOP"); + return NPY_FAIL; + } + + perm = NIT_PERM(iter); + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + /* Compute the iterindex corresponding to the multi-index */ + iterindex = 0; + factor = 1; + for (idim = 0; idim < ndim; ++idim) { + npy_int8 p = perm[idim]; + npy_intp i, shape; + + shape = NAD_SHAPE(axisdata); + if (p < 0) { + /* If the perm entry is negative, reverse the index */ + i = shape - multi_index[ndim+p] - 1; + } + else { + i = multi_index[ndim-p-1]; + } + + /* Bounds-check this index */ + if (i >= 0 && i < shape) { + iterindex += factor * i; + factor *= shape; + } + else { + PyErr_SetString(PyExc_IndexError, + "Iterator GotoMultiIndex called with an out-of-bounds " + "multi-index"); + return NPY_FAIL; + } + + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + + if (iterindex < NIT_ITERSTART(iter) || iterindex >= NIT_ITEREND(iter)) { + if (NIT_ITERSIZE(iter) < 0) { + PyErr_SetString(PyExc_ValueError, "iterator is too large"); + return NPY_FAIL; + } + PyErr_SetString(PyExc_IndexError, + "Iterator GotoMultiIndex called with a multi-index outside the " + "restricted iteration range"); + return NPY_FAIL; + } + + npyiter_goto_iterindex(iter, iterindex); + + return NPY_SUCCEED; +} + +/*NUMPY_API + * If the iterator is tracking an index, sets the iterator + * to the specified index. + * + * Returns NPY_SUCCEED on success, NPY_FAIL on failure. + */ +NPY_NO_EXPORT int +NpyIter_GotoIndex(NpyIter *iter, npy_intp flat_index) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_intp iterindex, factor; + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + + if (!(itflags&NPY_ITFLAG_HASINDEX)) { + PyErr_SetString(PyExc_ValueError, + "Cannot call GotoIndex on an iterator without " + "requesting a C or Fortran index in the constructor"); + return NPY_FAIL; + } + + if (itflags&NPY_ITFLAG_BUFFER) { + PyErr_SetString(PyExc_ValueError, + "Cannot call GotoIndex on an iterator which " + "is buffered"); + return NPY_FAIL; + } + + if (itflags&NPY_ITFLAG_EXLOOP) { + PyErr_SetString(PyExc_ValueError, + "Cannot call GotoIndex on an iterator which " + "has the flag EXTERNAL_LOOP"); + return NPY_FAIL; + } + + if (flat_index < 0 || flat_index >= NIT_ITERSIZE(iter)) { + PyErr_SetString(PyExc_IndexError, + "Iterator GotoIndex called with an out-of-bounds " + "index"); + return NPY_FAIL; + } + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + /* Compute the iterindex corresponding to the flat_index */ + iterindex = 0; + factor = 1; + for (idim = 0; idim < ndim; ++idim) { + npy_intp i, shape, iterstride; + + iterstride = NAD_STRIDES(axisdata)[nop]; + shape = NAD_SHAPE(axisdata); + + /* Extract the index from the flat_index */ + if (iterstride == 0) { + i = 0; + } + else if (iterstride < 0) { + i = shape - (flat_index/(-iterstride))%shape - 1; + } + else { + i = (flat_index/iterstride)%shape; + } + + /* Add its contribution to iterindex */ + iterindex += factor * i; + factor *= shape; + + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + + + if (iterindex < NIT_ITERSTART(iter) || iterindex >= NIT_ITEREND(iter)) { + PyErr_SetString(PyExc_IndexError, + "Iterator GotoIndex called with an index outside the " + "restricted iteration range."); + return NPY_FAIL; + } + + npyiter_goto_iterindex(iter, iterindex); + + return NPY_SUCCEED; +} + +/*NUMPY_API + * Sets the iterator position to the specified iterindex, + * which matches the iteration order of the iterator. + * + * Returns NPY_SUCCEED on success, NPY_FAIL on failure. + */ +NPY_NO_EXPORT int +NpyIter_GotoIterIndex(NpyIter *iter, npy_intp iterindex) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int iop, nop = NIT_NOP(iter); + + if (itflags&NPY_ITFLAG_EXLOOP) { + PyErr_SetString(PyExc_ValueError, + "Cannot call GotoIterIndex on an iterator which " + "has the flag EXTERNAL_LOOP"); + return NPY_FAIL; + } + + if (iterindex < NIT_ITERSTART(iter) || iterindex >= NIT_ITEREND(iter)) { + if (NIT_ITERSIZE(iter) < 0) { + PyErr_SetString(PyExc_ValueError, "iterator is too large"); + return NPY_FAIL; + } + PyErr_SetString(PyExc_IndexError, + "Iterator GotoIterIndex called with an iterindex outside the " + "iteration range."); + return NPY_FAIL; + } + + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + npy_intp bufiterend, size; + + size = NBF_SIZE(bufferdata); + bufiterend = NBF_BUFITEREND(bufferdata); + /* Check if the new iterindex is already within the buffer */ + if (!(itflags&NPY_ITFLAG_REDUCE) && iterindex < bufiterend && + iterindex >= bufiterend - size) { + npy_intp *strides, delta; + char **ptrs; + + strides = NBF_STRIDES(bufferdata); + ptrs = NBF_PTRS(bufferdata); + delta = iterindex - NIT_ITERINDEX(iter); + + for (iop = 0; iop < nop; ++iop) { + ptrs[iop] += delta * strides[iop]; + } + + NIT_ITERINDEX(iter) = iterindex; + } + /* Start the buffer at the provided iterindex */ + else { + /* Write back to the arrays */ + npyiter_copy_from_buffers(iter); + + npyiter_goto_iterindex(iter, iterindex); + + /* Prepare the next buffers and set iterend/size */ + npyiter_copy_to_buffers(iter, NULL); + } + } + else { + npyiter_goto_iterindex(iter, iterindex); + } + + return NPY_SUCCEED; +} + +/*NUMPY_API + * Gets the current iteration index + */ +NPY_NO_EXPORT npy_intp +NpyIter_GetIterIndex(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + /* iterindex is only used if NPY_ITER_RANGED or NPY_ITER_BUFFERED was set */ + if (itflags&(NPY_ITFLAG_RANGE|NPY_ITFLAG_BUFFER)) { + return NIT_ITERINDEX(iter); + } + else { + npy_intp iterindex; + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + + iterindex = 0; + if (ndim == 0) { + return 0; + } + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + axisdata = NIT_INDEX_AXISDATA(NIT_AXISDATA(iter), ndim-1); + + for (idim = ndim-2; idim >= 0; --idim) { + iterindex += NAD_INDEX(axisdata); + NIT_ADVANCE_AXISDATA(axisdata, -1); + iterindex *= NAD_SHAPE(axisdata); + } + iterindex += NAD_INDEX(axisdata); + + return iterindex; + } +} + +/*NUMPY_API + * Whether the buffer allocation is being delayed + */ +NPY_NO_EXPORT npy_bool +NpyIter_HasDelayedBufAlloc(NpyIter *iter) +{ + return (NIT_ITFLAGS(iter)&NPY_ITFLAG_DELAYBUF) != 0; +} + +/*NUMPY_API + * Whether the iterator handles the inner loop + */ +NPY_NO_EXPORT npy_bool +NpyIter_HasExternalLoop(NpyIter *iter) +{ + return (NIT_ITFLAGS(iter)&NPY_ITFLAG_EXLOOP) != 0; +} + +/*NUMPY_API + * Whether the iterator is tracking a multi-index + */ +NPY_NO_EXPORT npy_bool +NpyIter_HasMultiIndex(NpyIter *iter) +{ + return (NIT_ITFLAGS(iter)&NPY_ITFLAG_HASMULTIINDEX) != 0; +} + +/*NUMPY_API + * Whether the iterator is tracking an index + */ +NPY_NO_EXPORT npy_bool +NpyIter_HasIndex(NpyIter *iter) +{ + return (NIT_ITFLAGS(iter)&NPY_ITFLAG_HASINDEX) != 0; +} + +/*NUMPY_API + * Checks to see whether this is the first time the elements + * of the specified reduction operand which the iterator points at are + * being seen for the first time. The function returns + * a reasonable answer for reduction operands and when buffering is + * disabled. The answer may be incorrect for buffered non-reduction + * operands. + * + * This function is intended to be used in EXTERNAL_LOOP mode only, + * and will produce some wrong answers when that mode is not enabled. + * + * If this function returns true, the caller should also + * check the inner loop stride of the operand, because if + * that stride is 0, then only the first element of the innermost + * external loop is being visited for the first time. + * + * WARNING: For performance reasons, 'iop' is not bounds-checked, + * it is not confirmed that 'iop' is actually a reduction + * operand, and it is not confirmed that EXTERNAL_LOOP + * mode is enabled. These checks are the responsibility of + * the caller, and should be done outside of any inner loops. + */ +NPY_NO_EXPORT npy_bool +NpyIter_IsFirstVisit(NpyIter *iter, int iop) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + axisdata = NIT_AXISDATA(iter); + + for (idim = 0; idim < ndim; ++idim) { + npy_intp coord = NAD_INDEX(axisdata); + npy_intp stride = NAD_STRIDES(axisdata)[iop]; + + /* + * If this is a reduction dimension and the coordinate + * is not at the start, it's definitely not the first visit + */ + if (stride == 0 && coord != 0) { + return 0; + } + + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + + /* + * In reduction buffering mode, there's a double loop being + * tracked in the buffer part of the iterator data structure. + * We only need to check the outer level of this two-level loop, + * because of the requirement that EXTERNAL_LOOP be enabled. + */ + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + /* The outer reduce loop */ + if (NBF_REDUCE_POS(bufferdata) != 0 && + NBF_REDUCE_OUTERSTRIDES(bufferdata)[iop] == 0) { + return 0; + } + } + + return 1; +} + +/*NUMPY_API + * Whether the iteration could be done with no buffering. + */ +NPY_NO_EXPORT npy_bool +NpyIter_RequiresBuffering(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int iop, nop = NIT_NOP(iter); + + npyiter_opitflags *op_itflags; + + if (!(itflags&NPY_ITFLAG_BUFFER)) { + return 0; + } + + op_itflags = NIT_OPITFLAGS(iter); + + /* If any operand requires a cast, buffering is mandatory */ + for (iop = 0; iop < nop; ++iop) { + if (op_itflags[iop]&NPY_OP_ITFLAG_CAST) { + return 1; + } + } + + return 0; +} + +/*NUMPY_API + * Whether the iteration loop, and in particular the iternext() + * function, needs API access. If this is true, the GIL must + * be retained while iterating. + */ +NPY_NO_EXPORT npy_bool +NpyIter_IterationNeedsAPI(NpyIter *iter) +{ + return (NIT_ITFLAGS(iter)&NPY_ITFLAG_NEEDSAPI) != 0; +} + +/*NUMPY_API + * Gets the number of dimensions being iterated + */ +NPY_NO_EXPORT int +NpyIter_GetNDim(NpyIter *iter) +{ + return NIT_NDIM(iter); +} + +/*NUMPY_API + * Gets the number of operands being iterated + */ +NPY_NO_EXPORT int +NpyIter_GetNOp(NpyIter *iter) +{ + return NIT_NOP(iter); +} + +/*NUMPY_API + * Gets the number of elements being iterated + */ +NPY_NO_EXPORT npy_intp +NpyIter_GetIterSize(NpyIter *iter) +{ + return NIT_ITERSIZE(iter); +} + +/*NUMPY_API + * Whether the iterator is buffered + */ +NPY_NO_EXPORT npy_bool +NpyIter_IsBuffered(NpyIter *iter) +{ + return (NIT_ITFLAGS(iter)&NPY_ITFLAG_BUFFER) != 0; +} + +/*NUMPY_API + * Whether the inner loop can grow if buffering is unneeded + */ +NPY_NO_EXPORT npy_bool +NpyIter_IsGrowInner(NpyIter *iter) +{ + return (NIT_ITFLAGS(iter)&NPY_ITFLAG_GROWINNER) != 0; +} + +/*NUMPY_API + * Gets the size of the buffer, or 0 if buffering is not enabled + */ +NPY_NO_EXPORT npy_intp +NpyIter_GetBufferSize(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + return NBF_BUFFERSIZE(bufferdata); + } + else { + return 0; + } + +} + +/*NUMPY_API + * Gets the range of iteration indices being iterated + */ +NPY_NO_EXPORT void +NpyIter_GetIterIndexRange(NpyIter *iter, + npy_intp *istart, npy_intp *iend) +{ + *istart = NIT_ITERSTART(iter); + *iend = NIT_ITEREND(iter); +} + +/*NUMPY_API + * Gets the broadcast shape if a multi-index is being tracked by the iterator, + * otherwise gets the shape of the iteration as Fortran-order + * (fastest-changing index first). + * + * The reason Fortran-order is returned when a multi-index + * is not enabled is that this is providing a direct view into how + * the iterator traverses the n-dimensional space. The iterator organizes + * its memory from fastest index to slowest index, and when + * a multi-index is enabled, it uses a permutation to recover the original + * order. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +NPY_NO_EXPORT int +NpyIter_GetShape(NpyIter *iter, npy_intp *outshape) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + int idim, sizeof_axisdata; + NpyIter_AxisData *axisdata; + npy_int8 *perm; + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + if (itflags&NPY_ITFLAG_HASMULTIINDEX) { + perm = NIT_PERM(iter); + for(idim = 0; idim < ndim; ++idim) { + npy_int8 p = perm[idim]; + if (p < 0) { + outshape[ndim+p] = NAD_SHAPE(axisdata); + } + else { + outshape[ndim-p-1] = NAD_SHAPE(axisdata); + } + + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + } + else { + for(idim = 0; idim < ndim; ++idim) { + outshape[idim] = NAD_SHAPE(axisdata); + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + } + + return NPY_SUCCEED; +} + +/*NUMPY_API + * Builds a set of strides which are the same as the strides of an + * output array created using the NPY_ITER_ALLOCATE flag, where NULL + * was passed for op_axes. This is for data packed contiguously, + * but not necessarily in C or Fortran order. This should be used + * together with NpyIter_GetShape and NpyIter_GetNDim. + * + * A use case for this function is to match the shape and layout of + * the iterator and tack on one or more dimensions. For example, + * in order to generate a vector per input value for a numerical gradient, + * you pass in ndim*itemsize for itemsize, then add another dimension to + * the end with size ndim and stride itemsize. To do the Hessian matrix, + * you do the same thing but add two dimensions, or take advantage of + * the symmetry and pack it into 1 dimension with a particular encoding. + * + * This function may only be called if the iterator is tracking a multi-index + * and if NPY_ITER_DONT_NEGATE_STRIDES was used to prevent an axis from + * being iterated in reverse order. + * + * If an array is created with this method, simply adding 'itemsize' + * for each iteration will traverse the new array matching the + * iterator. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +NPY_NO_EXPORT int +NpyIter_CreateCompatibleStrides(NpyIter *iter, + npy_intp itemsize, npy_intp *outstrides) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_intp sizeof_axisdata; + NpyIter_AxisData *axisdata; + npy_int8 *perm; + + if (!(itflags&NPY_ITFLAG_HASMULTIINDEX)) { + PyErr_SetString(PyExc_RuntimeError, + "Iterator CreateCompatibleStrides may only be called " + "if a multi-index is being tracked"); + return NPY_FAIL; + } + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + perm = NIT_PERM(iter); + for(idim = 0; idim < ndim; ++idim) { + npy_int8 p = perm[idim]; + if (p < 0) { + PyErr_SetString(PyExc_RuntimeError, + "Iterator CreateCompatibleStrides may only be called " + "if DONT_NEGATE_STRIDES was used to prevent reverse " + "iteration of an axis"); + return NPY_FAIL; + } + else { + outstrides[ndim-p-1] = itemsize; + } + + itemsize *= NAD_SHAPE(axisdata); + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + + return NPY_SUCCEED; +} + +/*NUMPY_API + * Get the array of data pointers (1 per object being iterated) + * + * This function may be safely called without holding the Python GIL. + */ +NPY_NO_EXPORT char ** +NpyIter_GetDataPtrArray(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + return NBF_PTRS(bufferdata); + } + else { + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + return NAD_PTRS(axisdata); + } +} + +/*NUMPY_API + * Get the array of data pointers (1 per object being iterated), + * directly into the arrays (never pointing to a buffer), for starting + * unbuffered iteration. This always returns the addresses for the + * iterator position as reset to iterator index 0. + * + * These pointers are different from the pointers accepted by + * NpyIter_ResetBasePointers, because the direction along some + * axes may have been reversed, requiring base offsets. + * + * This function may be safely called without holding the Python GIL. + */ +NPY_NO_EXPORT char ** +NpyIter_GetInitialDataPtrArray(NpyIter *iter) +{ + /*npy_uint32 itflags = NIT_ITFLAGS(iter);*/ + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + return NIT_RESETDATAPTR(iter); +} + +/*NUMPY_API + * Get the array of data type pointers (1 per object being iterated) + */ +NPY_NO_EXPORT PyArray_Descr ** +NpyIter_GetDescrArray(NpyIter *iter) +{ + /*npy_uint32 itflags = NIT_ITFLAGS(iter);*/ + /*int ndim = NIT_NDIM(iter);*/ + /*int nop = NIT_NOP(iter);*/ + + return NIT_DTYPES(iter); +} + +/*NUMPY_API + * Get the array of objects being iterated + */ +NPY_NO_EXPORT PyArrayObject ** +NpyIter_GetOperandArray(NpyIter *iter) +{ + /*npy_uint32 itflags = NIT_ITFLAGS(iter);*/ + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + return NIT_OPERANDS(iter); +} + +/*NUMPY_API + * Returns a view to the i-th object with the iterator's internal axes + */ +NPY_NO_EXPORT PyArrayObject * +NpyIter_GetIterView(NpyIter *iter, npy_intp i) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_intp shape[NPY_MAXDIMS], strides[NPY_MAXDIMS]; + PyArrayObject *obj, *view; + PyArray_Descr *dtype; + char *dataptr; + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + int writeable; + + if (i < 0) { + PyErr_SetString(PyExc_IndexError, + "index provided for an iterator view was out of bounds"); + return NULL; + } + + /* Don't provide views if buffering is enabled */ + if (itflags&NPY_ITFLAG_BUFFER) { + PyErr_SetString(PyExc_ValueError, + "cannot provide an iterator view when buffering is enabled"); + return NULL; + } + + obj = NIT_OPERANDS(iter)[i]; + dtype = PyArray_DESCR(obj); + writeable = NIT_OPITFLAGS(iter)[i]&NPY_OP_ITFLAG_WRITE; + dataptr = NIT_RESETDATAPTR(iter)[i]; + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + /* Retrieve the shape and strides from the axisdata */ + for (idim = 0; idim < ndim; ++idim) { + shape[ndim-idim-1] = NAD_SHAPE(axisdata); + strides[ndim-idim-1] = NAD_STRIDES(axisdata)[i]; + + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + + Py_INCREF(dtype); + view = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, ndim, + shape, strides, dataptr, + writeable ? NPY_ARRAY_WRITEABLE : 0, + NULL); + if (view == NULL) { + return NULL; + } + /* Tell the view who owns the data */ + Py_INCREF(obj); + if (PyArray_SetBaseObject(view, (PyObject *)obj) < 0) { + Py_DECREF(view); + return NULL; + } + /* Make sure all the flags are good */ + PyArray_UpdateFlags(view, NPY_ARRAY_UPDATE_ALL); + + return view; +} + +/*NUMPY_API + * Get a pointer to the index, if it is being tracked + */ +NPY_NO_EXPORT npy_intp * +NpyIter_GetIndexPtr(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + + if (itflags&NPY_ITFLAG_HASINDEX) { + /* The index is just after the data pointers */ + return (npy_intp*)NAD_PTRS(axisdata) + nop; + } + else { + return NULL; + } +} + +/*NUMPY_API + * Gets an array of read flags (1 per object being iterated) + */ +NPY_NO_EXPORT void +NpyIter_GetReadFlags(NpyIter *iter, char *outreadflags) +{ + /*npy_uint32 itflags = NIT_ITFLAGS(iter);*/ + /*int ndim = NIT_NDIM(iter);*/ + int iop, nop = NIT_NOP(iter); + + npyiter_opitflags *op_itflags = NIT_OPITFLAGS(iter); + + for (iop = 0; iop < nop; ++iop) { + outreadflags[iop] = (op_itflags[iop]&NPY_OP_ITFLAG_READ) != 0; + } +} + +/*NUMPY_API + * Gets an array of write flags (1 per object being iterated) + */ +NPY_NO_EXPORT void +NpyIter_GetWriteFlags(NpyIter *iter, char *outwriteflags) +{ + /*npy_uint32 itflags = NIT_ITFLAGS(iter);*/ + /*int ndim = NIT_NDIM(iter);*/ + int iop, nop = NIT_NOP(iter); + + npyiter_opitflags *op_itflags = NIT_OPITFLAGS(iter); + + for (iop = 0; iop < nop; ++iop) { + outwriteflags[iop] = (op_itflags[iop]&NPY_OP_ITFLAG_WRITE) != 0; + } +} + + +/*NUMPY_API + * Get the array of strides for the inner loop (when HasExternalLoop is true) + * + * This function may be safely called without holding the Python GIL. + */ +NPY_NO_EXPORT npy_intp * +NpyIter_GetInnerStrideArray(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *data = NIT_BUFFERDATA(iter); + return NBF_STRIDES(data); + } + else { + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + return NAD_STRIDES(axisdata); + } +} + +/*NUMPY_API + * Gets the array of strides for the specified axis. + * If the iterator is tracking a multi-index, gets the strides + * for the axis specified, otherwise gets the strides for + * the iteration axis as Fortran order (fastest-changing axis first). + * + * Returns NULL if an error occurs. + */ +NPY_NO_EXPORT npy_intp * +NpyIter_GetAxisStrideArray(NpyIter *iter, int axis) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_int8 *perm = NIT_PERM(iter); + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + if (axis < 0 || axis >= ndim) { + PyErr_SetString(PyExc_ValueError, + "axis out of bounds in iterator GetStrideAxisArray"); + return NULL; + } + + if (itflags&NPY_ITFLAG_HASMULTIINDEX) { + /* Reverse axis, since the iterator treats them that way */ + axis = ndim-1-axis; + + /* First find the axis in question */ + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + if (perm[idim] == axis || -1 - perm[idim] == axis) { + return NAD_STRIDES(axisdata); + } + } + } + else { + return NAD_STRIDES(NIT_INDEX_AXISDATA(axisdata, axis)); + } + + PyErr_SetString(PyExc_RuntimeError, + "internal error in iterator perm"); + return NULL; +} + +/*NUMPY_API + * Get an array of strides which are fixed. Any strides which may + * change during iteration receive the value NPY_MAX_INTP. Once + * the iterator is ready to iterate, call this to get the strides + * which will always be fixed in the inner loop, then choose optimized + * inner loop functions which take advantage of those fixed strides. + * + * This function may be safely called without holding the Python GIL. + */ +NPY_NO_EXPORT void +NpyIter_GetInnerFixedStrideArray(NpyIter *iter, npy_intp *out_strides) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + NpyIter_AxisData *axisdata0 = NIT_AXISDATA(iter); + npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *data = NIT_BUFFERDATA(iter); + npyiter_opitflags *op_itflags = NIT_OPITFLAGS(iter); + npy_intp stride, *strides = NBF_STRIDES(data), + *ad_strides = NAD_STRIDES(axisdata0); + PyArray_Descr **dtypes = NIT_DTYPES(iter); + + for (iop = 0; iop < nop; ++iop) { + stride = strides[iop]; + /* + * Operands which are always/never buffered have fixed strides, + * and everything has fixed strides when ndim is 0 or 1 + */ + if (ndim <= 1 || (op_itflags[iop]& + (NPY_OP_ITFLAG_CAST|NPY_OP_ITFLAG_BUFNEVER))) { + out_strides[iop] = stride; + } + /* If it's a reduction, 0-stride inner loop may have fixed stride */ + else if (stride == 0 && (itflags&NPY_ITFLAG_REDUCE)) { + /* If it's a reduction operand, definitely fixed stride */ + if (op_itflags[iop]&NPY_OP_ITFLAG_REDUCE) { + out_strides[iop] = stride; + } + /* + * Otherwise it's guaranteed to be a fixed stride if the + * stride is 0 for all the dimensions. + */ + else { + NpyIter_AxisData *axisdata = axisdata0; + int idim; + for (idim = 0; idim < ndim; ++idim) { + if (NAD_STRIDES(axisdata)[iop] != 0) { + break; + } + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + /* If all the strides were 0, the stride won't change */ + if (idim == ndim) { + out_strides[iop] = stride; + } + else { + out_strides[iop] = NPY_MAX_INTP; + } + } + } + /* + * Inner loop contiguous array means its stride won't change when + * switching between buffering and not buffering + */ + else if (ad_strides[iop] == dtypes[iop]->elsize) { + out_strides[iop] = ad_strides[iop]; + } + /* + * Otherwise the strides can change if the operand is sometimes + * buffered, sometimes not. + */ + else { + out_strides[iop] = NPY_MAX_INTP; + } + } + } + else { + /* If there's no buffering, the strides are always fixed */ + memcpy(out_strides, NAD_STRIDES(axisdata0), nop*NPY_SIZEOF_INTP); + } +} + +/*NUMPY_API + * Get a pointer to the size of the inner loop (when HasExternalLoop is true) + * + * This function may be safely called without holding the Python GIL. + */ +NPY_NO_EXPORT npy_intp * +NpyIter_GetInnerLoopSizePtr(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *data = NIT_BUFFERDATA(iter); + return &NBF_SIZE(data); + } + else { + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + return &NAD_SHAPE(axisdata); + } +} + +/*NUMPY_API + * For debugging + */ +NPY_NO_EXPORT void +NpyIter_DebugPrint(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API + + printf("\n------ BEGIN ITERATOR DUMP ------\n"); + printf("| Iterator Address: %p\n", (void *)iter); + printf("| ItFlags: "); + if (itflags&NPY_ITFLAG_IDENTPERM) + printf("IDENTPERM "); + if (itflags&NPY_ITFLAG_NEGPERM) + printf("NEGPERM "); + if (itflags&NPY_ITFLAG_HASINDEX) + printf("HASINDEX "); + if (itflags&NPY_ITFLAG_HASMULTIINDEX) + printf("HASMULTIINDEX "); + if (itflags&NPY_ITFLAG_FORCEDORDER) + printf("FORCEDORDER "); + if (itflags&NPY_ITFLAG_EXLOOP) + printf("EXLOOP "); + if (itflags&NPY_ITFLAG_RANGE) + printf("RANGE "); + if (itflags&NPY_ITFLAG_BUFFER) + printf("BUFFER "); + if (itflags&NPY_ITFLAG_GROWINNER) + printf("GROWINNER "); + if (itflags&NPY_ITFLAG_ONEITERATION) + printf("ONEITERATION "); + if (itflags&NPY_ITFLAG_DELAYBUF) + printf("DELAYBUF "); + if (itflags&NPY_ITFLAG_NEEDSAPI) + printf("NEEDSAPI "); + if (itflags&NPY_ITFLAG_REDUCE) + printf("REDUCE "); + if (itflags&NPY_ITFLAG_REUSE_REDUCE_LOOPS) + printf("REUSE_REDUCE_LOOPS "); + + printf("\n"); + printf("| NDim: %d\n", (int)ndim); + printf("| NOp: %d\n", (int)nop); + if (NIT_MASKOP(iter) >= 0) { + printf("| MaskOp: %d\n", (int)NIT_MASKOP(iter)); + } + printf("| IterSize: %d\n", (int)NIT_ITERSIZE(iter)); + printf("| IterStart: %d\n", (int)NIT_ITERSTART(iter)); + printf("| IterEnd: %d\n", (int)NIT_ITEREND(iter)); + printf("| IterIndex: %d\n", (int)NIT_ITERINDEX(iter)); + printf("| Iterator SizeOf: %d\n", + (int)NIT_SIZEOF_ITERATOR(itflags, ndim, nop)); + printf("| BufferData SizeOf: %d\n", + (int)NIT_BUFFERDATA_SIZEOF(itflags, ndim, nop)); + printf("| AxisData SizeOf: %d\n", + (int)NIT_AXISDATA_SIZEOF(itflags, ndim, nop)); + printf("|\n"); + + printf("| Perm: "); + for (idim = 0; idim < ndim; ++idim) { + printf("%d ", (int)NIT_PERM(iter)[idim]); + } + printf("\n"); + printf("| DTypes: "); + for (iop = 0; iop < nop; ++iop) { + printf("%p ", (void *)NIT_DTYPES(iter)[iop]); + } + printf("\n"); + printf("| DTypes: "); + for (iop = 0; iop < nop; ++iop) { + if (NIT_DTYPES(iter)[iop] != NULL) + PyObject_Print((PyObject*)NIT_DTYPES(iter)[iop], stdout, 0); + else + printf("(nil) "); + printf(" "); + } + printf("\n"); + printf("| InitDataPtrs: "); + for (iop = 0; iop < nop; ++iop) { + printf("%p ", (void *)NIT_RESETDATAPTR(iter)[iop]); + } + printf("\n"); + printf("| BaseOffsets: "); + for (iop = 0; iop < nop; ++iop) { + printf("%i ", (int)NIT_BASEOFFSETS(iter)[iop]); + } + printf("\n"); + if (itflags&NPY_ITFLAG_HASINDEX) { + printf("| InitIndex: %d\n", + (int)(npy_intp)NIT_RESETDATAPTR(iter)[nop]); + } + printf("| Operands: "); + for (iop = 0; iop < nop; ++iop) { + printf("%p ", (void *)NIT_OPERANDS(iter)[iop]); + } + printf("\n"); + printf("| Operand DTypes: "); + for (iop = 0; iop < nop; ++iop) { + PyArray_Descr *dtype; + if (NIT_OPERANDS(iter)[iop] != NULL) { + dtype = PyArray_DESCR(NIT_OPERANDS(iter)[iop]); + if (dtype != NULL) + PyObject_Print((PyObject *)dtype, stdout, 0); + else + printf("(nil) "); + } + else { + printf("(op nil) "); + } + printf(" "); + } + printf("\n"); + printf("| OpItFlags:\n"); + for (iop = 0; iop < nop; ++iop) { + printf("| Flags[%d]: ", (int)iop); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_READ) + printf("READ "); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_WRITE) + printf("WRITE "); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_CAST) + printf("CAST "); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_BUFNEVER) + printf("BUFNEVER "); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_ALIGNED) + printf("ALIGNED "); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_REDUCE) + printf("REDUCE "); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_VIRTUAL) + printf("VIRTUAL "); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_WRITEMASKED) + printf("WRITEMASKED "); + printf("\n"); + } + printf("|\n"); + + if (itflags&NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + printf("| BufferData:\n"); + printf("| BufferSize: %d\n", (int)NBF_BUFFERSIZE(bufferdata)); + printf("| Size: %d\n", (int)NBF_SIZE(bufferdata)); + printf("| BufIterEnd: %d\n", (int)NBF_BUFITEREND(bufferdata)); + if (itflags&NPY_ITFLAG_REDUCE) { + printf("| REDUCE Pos: %d\n", + (int)NBF_REDUCE_POS(bufferdata)); + printf("| REDUCE OuterSize: %d\n", + (int)NBF_REDUCE_OUTERSIZE(bufferdata)); + printf("| REDUCE OuterDim: %d\n", + (int)NBF_REDUCE_OUTERDIM(bufferdata)); + } + printf("| Strides: "); + for (iop = 0; iop < nop; ++iop) + printf("%d ", (int)NBF_STRIDES(bufferdata)[iop]); + printf("\n"); + /* Print the fixed strides when there's no inner loop */ + if (itflags&NPY_ITFLAG_EXLOOP) { + npy_intp fixedstrides[NPY_MAXDIMS]; + printf("| Fixed Strides: "); + NpyIter_GetInnerFixedStrideArray(iter, fixedstrides); + for (iop = 0; iop < nop; ++iop) + printf("%d ", (int)fixedstrides[iop]); + printf("\n"); + } + printf("| Ptrs: "); + for (iop = 0; iop < nop; ++iop) + printf("%p ", (void *)NBF_PTRS(bufferdata)[iop]); + printf("\n"); + if (itflags&NPY_ITFLAG_REDUCE) { + printf("| REDUCE Outer Strides: "); + for (iop = 0; iop < nop; ++iop) + printf("%d ", (int)NBF_REDUCE_OUTERSTRIDES(bufferdata)[iop]); + printf("\n"); + printf("| REDUCE Outer Ptrs: "); + for (iop = 0; iop < nop; ++iop) + printf("%p ", (void *)NBF_REDUCE_OUTERPTRS(bufferdata)[iop]); + printf("\n"); + } + printf("| ReadTransferFn: "); + for (iop = 0; iop < nop; ++iop) + printf("%p ", (void *)NBF_READTRANSFERFN(bufferdata)[iop]); + printf("\n"); + printf("| ReadTransferData: "); + for (iop = 0; iop < nop; ++iop) + printf("%p ", (void *)NBF_READTRANSFERDATA(bufferdata)[iop]); + printf("\n"); + printf("| WriteTransferFn: "); + for (iop = 0; iop < nop; ++iop) + printf("%p ", (void *)NBF_WRITETRANSFERFN(bufferdata)[iop]); + printf("\n"); + printf("| WriteTransferData: "); + for (iop = 0; iop < nop; ++iop) + printf("%p ", (void *)NBF_WRITETRANSFERDATA(bufferdata)[iop]); + printf("\n"); + printf("| Buffers: "); + for (iop = 0; iop < nop; ++iop) + printf("%p ", (void *)NBF_BUFFERS(bufferdata)[iop]); + printf("\n"); + printf("|\n"); + } + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + printf("| AxisData[%d]:\n", (int)idim); + printf("| Shape: %d\n", (int)NAD_SHAPE(axisdata)); + printf("| Index: %d\n", (int)NAD_INDEX(axisdata)); + printf("| Strides: "); + for (iop = 0; iop < nop; ++iop) { + printf("%d ", (int)NAD_STRIDES(axisdata)[iop]); + } + printf("\n"); + if (itflags&NPY_ITFLAG_HASINDEX) { + printf("| Index Stride: %d\n", (int)NAD_STRIDES(axisdata)[nop]); + } + printf("| Ptrs: "); + for (iop = 0; iop < nop; ++iop) { + printf("%p ", (void *)NAD_PTRS(axisdata)[iop]); + } + printf("\n"); + if (itflags&NPY_ITFLAG_HASINDEX) { + printf("| Index Value: %d\n", + (int)((npy_intp*)NAD_PTRS(axisdata))[nop]); + } + } + + printf("------- END ITERATOR DUMP -------\n"); + fflush(stdout); + + NPY_DISABLE_C_API +} + +NPY_NO_EXPORT void +npyiter_coalesce_axes(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_intp istrides, nstrides = NAD_NSTRIDES(); + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + NpyIter_AxisData *ad_compress; + npy_intp new_ndim = 1; + + /* The HASMULTIINDEX or IDENTPERM flags do not apply after coalescing */ + NIT_ITFLAGS(iter) &= ~(NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_HASMULTIINDEX); + + axisdata = NIT_AXISDATA(iter); + ad_compress = axisdata; + + for (idim = 0; idim < ndim-1; ++idim) { + int can_coalesce = 1; + npy_intp shape0 = NAD_SHAPE(ad_compress); + npy_intp shape1 = NAD_SHAPE(NIT_INDEX_AXISDATA(axisdata, 1)); + npy_intp *strides0 = NAD_STRIDES(ad_compress); + npy_intp *strides1 = NAD_STRIDES(NIT_INDEX_AXISDATA(axisdata, 1)); + + /* Check that all the axes can be coalesced */ + for (istrides = 0; istrides < nstrides; ++istrides) { + if (!((shape0 == 1 && strides0[istrides] == 0) || + (shape1 == 1 && strides1[istrides] == 0)) && + (strides0[istrides]*shape0 != strides1[istrides])) { + can_coalesce = 0; + break; + } + } + + if (can_coalesce) { + npy_intp *strides = NAD_STRIDES(ad_compress); + + NIT_ADVANCE_AXISDATA(axisdata, 1); + NAD_SHAPE(ad_compress) *= NAD_SHAPE(axisdata); + for (istrides = 0; istrides < nstrides; ++istrides) { + if (strides[istrides] == 0) { + strides[istrides] = NAD_STRIDES(axisdata)[istrides]; + } + } + } + else { + NIT_ADVANCE_AXISDATA(axisdata, 1); + NIT_ADVANCE_AXISDATA(ad_compress, 1); + if (ad_compress != axisdata) { + memcpy(ad_compress, axisdata, sizeof_axisdata); + } + ++new_ndim; + } + } + + /* + * If the number of axes shrunk, reset the perm and + * compress the data into the new layout. + */ + if (new_ndim < ndim) { + npy_int8 *perm = NIT_PERM(iter); + + /* Reset to an identity perm */ + for (idim = 0; idim < new_ndim; ++idim) { + perm[idim] = (npy_int8)idim; + } + NIT_NDIM(iter) = new_ndim; + } +} + +/* + * If errmsg is non-NULL, it should point to a variable which will + * receive the error message, and no Python exception will be set. + * This is so that the function can be called from code not holding + * the GIL. + */ +NPY_NO_EXPORT int +npyiter_allocate_buffers(NpyIter *iter, char **errmsg) +{ + /*npy_uint32 itflags = NIT_ITFLAGS(iter);*/ + /*int ndim = NIT_NDIM(iter);*/ + int iop = 0, nop = NIT_NOP(iter); + + npy_intp i; + npyiter_opitflags *op_itflags = NIT_OPITFLAGS(iter); + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + PyArray_Descr **op_dtype = NIT_DTYPES(iter); + npy_intp buffersize = NBF_BUFFERSIZE(bufferdata); + char *buffer, **buffers = NBF_BUFFERS(bufferdata); + + for (iop = 0; iop < nop; ++iop) { + npyiter_opitflags flags = op_itflags[iop]; + + /* + * If we have determined that a buffer may be needed, + * allocate one. + */ + if (!(flags&NPY_OP_ITFLAG_BUFNEVER)) { + npy_intp itemsize = op_dtype[iop]->elsize; + buffer = PyArray_malloc(itemsize*buffersize); + if (buffer == NULL) { + if (errmsg == NULL) { + PyErr_NoMemory(); + } + else { + *errmsg = "out of memory"; + } + goto fail; + } + buffers[iop] = buffer; + } + } + + return 1; + +fail: + for (i = 0; i < iop; ++i) { + if (buffers[i] != NULL) { + PyArray_free(buffers[i]); + buffers[i] = NULL; + } + } + return 0; +} + +/* + * This sets the AXISDATA portion of the iterator to the specified + * iterindex, updating the pointers as well. This function does + * no error checking. + */ +NPY_NO_EXPORT void +npyiter_goto_iterindex(NpyIter *iter, npy_intp iterindex) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + char **dataptr; + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + npy_intp istrides, nstrides, i, shape; + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + nstrides = NAD_NSTRIDES(); + + NIT_ITERINDEX(iter) = iterindex; + + ndim = ndim ? ndim : 1; + + if (iterindex == 0) { + dataptr = NIT_RESETDATAPTR(iter); + + for (idim = 0; idim < ndim; ++idim) { + char **ptrs; + NAD_INDEX(axisdata) = 0; + ptrs = NAD_PTRS(axisdata); + for (istrides = 0; istrides < nstrides; ++istrides) { + ptrs[istrides] = dataptr[istrides]; + } + + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + } + else { + /* + * Set the multi-index, from the fastest-changing to the + * slowest-changing. + */ + axisdata = NIT_AXISDATA(iter); + shape = NAD_SHAPE(axisdata); + i = iterindex; + iterindex /= shape; + NAD_INDEX(axisdata) = i - iterindex * shape; + for (idim = 0; idim < ndim-1; ++idim) { + NIT_ADVANCE_AXISDATA(axisdata, 1); + + shape = NAD_SHAPE(axisdata); + i = iterindex; + iterindex /= shape; + NAD_INDEX(axisdata) = i - iterindex * shape; + } + + dataptr = NIT_RESETDATAPTR(iter); + + /* + * Accumulate the successive pointers with their + * offsets in the opposite order, starting from the + * original data pointers. + */ + for (idim = 0; idim < ndim; ++idim) { + npy_intp *strides; + char **ptrs; + + strides = NAD_STRIDES(axisdata); + ptrs = NAD_PTRS(axisdata); + + i = NAD_INDEX(axisdata); + + for (istrides = 0; istrides < nstrides; ++istrides) { + ptrs[istrides] = dataptr[istrides] + i*strides[istrides]; + } + + dataptr = ptrs; + + NIT_ADVANCE_AXISDATA(axisdata, -1); + } + } +} + +/* + * This gets called after the buffers have been exhausted, and + * their data needs to be written back to the arrays. The multi-index + * must be positioned for the beginning of the buffer. + */ +NPY_NO_EXPORT void +npyiter_copy_from_buffers(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + int maskop = NIT_MASKOP(iter); + + npyiter_opitflags *op_itflags = NIT_OPITFLAGS(iter); + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter), + *reduce_outeraxisdata = NULL; + + PyArray_Descr **dtypes = NIT_DTYPES(iter); + npy_intp transfersize = NBF_SIZE(bufferdata); + npy_intp *strides = NBF_STRIDES(bufferdata), + *ad_strides = NAD_STRIDES(axisdata); + npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + char **ad_ptrs = NAD_PTRS(axisdata); + char **buffers = NBF_BUFFERS(bufferdata); + char *buffer; + + npy_intp reduce_outerdim = 0; + npy_intp *reduce_outerstrides = NULL; + + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + + npy_intp axisdata_incr = NIT_AXISDATA_SIZEOF(itflags, ndim, nop) / + NPY_SIZEOF_INTP; + + /* If we're past the end, nothing to copy */ + if (NBF_SIZE(bufferdata) == 0) { + return; + } + + NPY_IT_DBG_PRINT("Iterator: Copying buffers to outputs\n"); + + if (itflags&NPY_ITFLAG_REDUCE) { + reduce_outerdim = NBF_REDUCE_OUTERDIM(bufferdata); + reduce_outerstrides = NBF_REDUCE_OUTERSTRIDES(bufferdata); + reduce_outeraxisdata = NIT_INDEX_AXISDATA(axisdata, reduce_outerdim); + transfersize *= NBF_REDUCE_OUTERSIZE(bufferdata); + } + + for (iop = 0; iop < nop; ++iop) { + stransfer = NBF_WRITETRANSFERFN(bufferdata)[iop]; + transferdata = NBF_WRITETRANSFERDATA(bufferdata)[iop]; + buffer = buffers[iop]; + /* + * Copy the data back to the arrays. If the type has refs, + * this function moves them so the buffer's refs are released. + * + * The flag USINGBUFFER is set when the buffer was used, so + * only copy back when this flag is on. + */ + if ((stransfer != NULL) && + (op_itflags[iop]&(NPY_OP_ITFLAG_WRITE|NPY_OP_ITFLAG_USINGBUFFER)) + == (NPY_OP_ITFLAG_WRITE|NPY_OP_ITFLAG_USINGBUFFER)) { + npy_intp op_transfersize; + + npy_intp src_stride, *dst_strides, *dst_coords, *dst_shape; + int ndim_transfer; + + NPY_IT_DBG_PRINT1("Iterator: Operand %d was buffered\n", + (int)iop); + + /* + * If this operand is being reduced in the inner loop, + * its buffering stride was set to zero, and just + * one element was copied. + */ + if (op_itflags[iop]&NPY_OP_ITFLAG_REDUCE) { + if (strides[iop] == 0) { + if (reduce_outerstrides[iop] == 0) { + op_transfersize = 1; + src_stride = 0; + dst_strides = &src_stride; + dst_coords = &NAD_INDEX(reduce_outeraxisdata); + dst_shape = &NAD_SHAPE(reduce_outeraxisdata); + ndim_transfer = 1; + } + else { + op_transfersize = NBF_REDUCE_OUTERSIZE(bufferdata); + src_stride = reduce_outerstrides[iop]; + dst_strides = + &NAD_STRIDES(reduce_outeraxisdata)[iop]; + dst_coords = &NAD_INDEX(reduce_outeraxisdata); + dst_shape = &NAD_SHAPE(reduce_outeraxisdata); + ndim_transfer = ndim - reduce_outerdim; + } + } + else { + if (reduce_outerstrides[iop] == 0) { + op_transfersize = NBF_SIZE(bufferdata); + src_stride = strides[iop]; + dst_strides = &ad_strides[iop]; + dst_coords = &NAD_INDEX(axisdata); + dst_shape = &NAD_SHAPE(axisdata); + ndim_transfer = reduce_outerdim ? + reduce_outerdim : 1; + } + else { + op_transfersize = transfersize; + src_stride = strides[iop]; + dst_strides = &ad_strides[iop]; + dst_coords = &NAD_INDEX(axisdata); + dst_shape = &NAD_SHAPE(axisdata); + ndim_transfer = ndim; + } + } + } + else { + op_transfersize = transfersize; + src_stride = strides[iop]; + dst_strides = &ad_strides[iop]; + dst_coords = &NAD_INDEX(axisdata); + dst_shape = &NAD_SHAPE(axisdata); + ndim_transfer = ndim; + } + + NPY_IT_DBG_PRINT2("Iterator: Copying buffer to " + "operand %d (%d items)\n", + (int)iop, (int)op_transfersize); + + /* WRITEMASKED operand */ + if (op_itflags[iop] & NPY_OP_ITFLAG_WRITEMASKED) { + npy_bool *maskptr; + + /* + * The mask pointer may be in the buffer or in + * the array, detect which one. + */ + if ((op_itflags[maskop]&NPY_OP_ITFLAG_USINGBUFFER) != 0) { + maskptr = (npy_bool *)buffers[maskop]; + } + else { + maskptr = (npy_bool *)ad_ptrs[maskop]; + } + + PyArray_TransferMaskedStridedToNDim(ndim_transfer, + ad_ptrs[iop], dst_strides, axisdata_incr, + buffer, src_stride, + maskptr, strides[maskop], + dst_coords, axisdata_incr, + dst_shape, axisdata_incr, + op_transfersize, dtypes[iop]->elsize, + (PyArray_MaskedStridedUnaryOp *)stransfer, + transferdata); + } + /* Regular operand */ + else { + PyArray_TransferStridedToNDim(ndim_transfer, + ad_ptrs[iop], dst_strides, axisdata_incr, + buffer, src_stride, + dst_coords, axisdata_incr, + dst_shape, axisdata_incr, + op_transfersize, dtypes[iop]->elsize, + stransfer, + transferdata); + } + } + /* If there's no copy back, we may have to decrement refs. In + * this case, the transfer function has a 'decsrcref' transfer + * function, so we can use it to do the decrement. + * + * The flag USINGBUFFER is set when the buffer was used, so + * only decrement refs when this flag is on. + */ + else if (stransfer != NULL && + (op_itflags[iop]&NPY_OP_ITFLAG_USINGBUFFER) != 0) { + NPY_IT_DBG_PRINT1("Iterator: Freeing refs and zeroing buffer " + "of operand %d\n", (int)iop); + /* Decrement refs */ + stransfer(NULL, 0, buffer, dtypes[iop]->elsize, + transfersize, dtypes[iop]->elsize, + transferdata); + /* + * Zero out the memory for safety. For instance, + * if during iteration some Python code copied an + * array pointing into the buffer, it will get None + * values for its references after this. + */ + memset(buffer, 0, dtypes[iop]->elsize*transfersize); + } + } + + NPY_IT_DBG_PRINT("Iterator: Finished copying buffers to outputs\n"); +} + +/* + * This gets called after the iterator has been positioned to a multi-index + * for the start of a buffer. It decides which operands need a buffer, + * and copies the data into the buffers. + */ +NPY_NO_EXPORT void +npyiter_copy_to_buffers(NpyIter *iter, char **prev_dataptrs) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + npyiter_opitflags *op_itflags = NIT_OPITFLAGS(iter); + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter), + *reduce_outeraxisdata = NULL; + + PyArray_Descr **dtypes = NIT_DTYPES(iter); + PyArrayObject **operands = NIT_OPERANDS(iter); + npy_intp *strides = NBF_STRIDES(bufferdata), + *ad_strides = NAD_STRIDES(axisdata); + npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + char **ptrs = NBF_PTRS(bufferdata), **ad_ptrs = NAD_PTRS(axisdata); + char **buffers = NBF_BUFFERS(bufferdata); + npy_intp iterindex, iterend, transfersize, + singlestridesize, reduce_innersize = 0, reduce_outerdim = 0; + int is_onestride = 0, any_buffered = 0; + + npy_intp *reduce_outerstrides = NULL; + char **reduce_outerptrs = NULL; + + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + + /* + * Have to get this flag before npyiter_checkreducesize sets + * it for the next iteration. + */ + npy_bool reuse_reduce_loops = (prev_dataptrs != NULL) && + ((itflags&NPY_ITFLAG_REUSE_REDUCE_LOOPS) != 0); + + npy_intp axisdata_incr = NIT_AXISDATA_SIZEOF(itflags, ndim, nop) / + NPY_SIZEOF_INTP; + + NPY_IT_DBG_PRINT("Iterator: Copying inputs to buffers\n"); + + /* Calculate the size if using any buffers */ + iterindex = NIT_ITERINDEX(iter); + iterend = NIT_ITEREND(iter); + transfersize = NBF_BUFFERSIZE(bufferdata); + if (transfersize > iterend - iterindex) { + transfersize = iterend - iterindex; + } + + /* If last time around, the reduce loop structure was full, we reuse it */ + if (reuse_reduce_loops) { + npy_intp full_transfersize, prev_reduce_outersize; + + prev_reduce_outersize = NBF_REDUCE_OUTERSIZE(bufferdata); + reduce_outerstrides = NBF_REDUCE_OUTERSTRIDES(bufferdata); + reduce_outerptrs = NBF_REDUCE_OUTERPTRS(bufferdata); + reduce_outerdim = NBF_REDUCE_OUTERDIM(bufferdata); + reduce_outeraxisdata = NIT_INDEX_AXISDATA(axisdata, reduce_outerdim); + reduce_innersize = NBF_SIZE(bufferdata); + NBF_REDUCE_POS(bufferdata) = 0; + /* + * Try to do make the outersize as big as possible. This allows + * it to shrink when processing the last bit of the outer reduce loop, + * then grow again at the beginnning of the next outer reduce loop. + */ + NBF_REDUCE_OUTERSIZE(bufferdata) = (NAD_SHAPE(reduce_outeraxisdata)- + NAD_INDEX(reduce_outeraxisdata)); + full_transfersize = NBF_REDUCE_OUTERSIZE(bufferdata)*reduce_innersize; + /* If the full transfer size doesn't fit in the buffer, truncate it */ + if (full_transfersize > NBF_BUFFERSIZE(bufferdata)) { + NBF_REDUCE_OUTERSIZE(bufferdata) = transfersize/reduce_innersize; + transfersize = NBF_REDUCE_OUTERSIZE(bufferdata)*reduce_innersize; + } + else { + transfersize = full_transfersize; + } + if (prev_reduce_outersize < NBF_REDUCE_OUTERSIZE(bufferdata)) { + /* + * If the previous time around less data was copied it may not + * be safe to reuse the buffers even if the pointers match. + */ + reuse_reduce_loops = 0; + } + NBF_BUFITEREND(bufferdata) = iterindex + reduce_innersize; + + NPY_IT_DBG_PRINT3("Reused reduce transfersize: %d innersize: %d " + "itersize: %d\n", + (int)transfersize, + (int)reduce_innersize, + (int)NpyIter_GetIterSize(iter)); + NPY_IT_DBG_PRINT1("Reduced reduce outersize: %d", + (int)NBF_REDUCE_OUTERSIZE(bufferdata)); + } + /* + * If there are any reduction operands, we may have to make + * the size smaller so we don't copy the same value into + * a buffer twice, as the buffering does not have a mechanism + * to combine values itself. + */ + else if (itflags&NPY_ITFLAG_REDUCE) { + NPY_IT_DBG_PRINT("Iterator: Calculating reduce loops\n"); + transfersize = npyiter_checkreducesize(iter, transfersize, + &reduce_innersize, + &reduce_outerdim); + NPY_IT_DBG_PRINT3("Reduce transfersize: %d innersize: %d " + "itersize: %d\n", + (int)transfersize, + (int)reduce_innersize, + (int)NpyIter_GetIterSize(iter)); + + reduce_outerstrides = NBF_REDUCE_OUTERSTRIDES(bufferdata); + reduce_outerptrs = NBF_REDUCE_OUTERPTRS(bufferdata); + reduce_outeraxisdata = NIT_INDEX_AXISDATA(axisdata, reduce_outerdim); + NBF_SIZE(bufferdata) = reduce_innersize; + NBF_REDUCE_POS(bufferdata) = 0; + NBF_REDUCE_OUTERDIM(bufferdata) = reduce_outerdim; + NBF_BUFITEREND(bufferdata) = iterindex + reduce_innersize; + if (reduce_innersize == 0) { + NBF_REDUCE_OUTERSIZE(bufferdata) = 0; + return; + } + else { + NBF_REDUCE_OUTERSIZE(bufferdata) = transfersize/reduce_innersize; + } + } + else { + NBF_SIZE(bufferdata) = transfersize; + NBF_BUFITEREND(bufferdata) = iterindex + transfersize; + } + + /* Calculate the maximum size if using a single stride and no buffers */ + singlestridesize = NAD_SHAPE(axisdata)-NAD_INDEX(axisdata); + if (singlestridesize > iterend - iterindex) { + singlestridesize = iterend - iterindex; + } + if (singlestridesize >= transfersize) { + is_onestride = 1; + } + + for (iop = 0; iop < nop; ++iop) { + /* + * If the buffer is write-only, these two are NULL, and the buffer + * pointers will be set up but the read copy won't be done + */ + stransfer = NBF_READTRANSFERFN(bufferdata)[iop]; + transferdata = NBF_READTRANSFERDATA(bufferdata)[iop]; + switch (op_itflags[iop]& + (NPY_OP_ITFLAG_BUFNEVER| + NPY_OP_ITFLAG_CAST| + NPY_OP_ITFLAG_REDUCE)) { + /* Never need to buffer this operand */ + case NPY_OP_ITFLAG_BUFNEVER: + ptrs[iop] = ad_ptrs[iop]; + if (itflags&NPY_ITFLAG_REDUCE) { + reduce_outerstrides[iop] = reduce_innersize * + strides[iop]; + reduce_outerptrs[iop] = ptrs[iop]; + } + /* + * Should not adjust the stride - ad_strides[iop] + * could be zero, but strides[iop] was initialized + * to the first non-trivial stride. + */ + stransfer = NULL; + /* The flag NPY_OP_ITFLAG_USINGBUFFER can be ignored here */ + break; + /* Never need to buffer this operand */ + case NPY_OP_ITFLAG_BUFNEVER|NPY_OP_ITFLAG_REDUCE: + ptrs[iop] = ad_ptrs[iop]; + reduce_outerptrs[iop] = ptrs[iop]; + reduce_outerstrides[iop] = 0; + /* + * Should not adjust the stride - ad_strides[iop] + * could be zero, but strides[iop] was initialized + * to the first non-trivial stride. + */ + stransfer = NULL; + /* The flag NPY_OP_ITFLAG_USINGBUFFER can be ignored here */ + break; + /* Just a copy */ + case 0: + /* Do not reuse buffer if it did not exist */ + if (!(op_itflags[iop] & NPY_OP_ITFLAG_USINGBUFFER) && + (prev_dataptrs != NULL)) { + prev_dataptrs[iop] = NULL; + } + /* + * No copyswap or cast was requested, so all we're + * doing is copying the data to fill the buffer and + * produce a single stride. If the underlying data + * already does that, no need to copy it. + */ + if (is_onestride) { + ptrs[iop] = ad_ptrs[iop]; + strides[iop] = ad_strides[iop]; + stransfer = NULL; + /* Signal that the buffer is not being used */ + op_itflags[iop] &= (~NPY_OP_ITFLAG_USINGBUFFER); + } + /* If some other op is reduced, we have a double reduce loop */ + else if ((itflags&NPY_ITFLAG_REDUCE) && + (reduce_outerdim == 1) && + (transfersize/reduce_innersize <= + NAD_SHAPE(reduce_outeraxisdata) - + NAD_INDEX(reduce_outeraxisdata))) { + ptrs[iop] = ad_ptrs[iop]; + reduce_outerptrs[iop] = ptrs[iop]; + strides[iop] = ad_strides[iop]; + reduce_outerstrides[iop] = + NAD_STRIDES(reduce_outeraxisdata)[iop]; + stransfer = NULL; + /* Signal that the buffer is not being used */ + op_itflags[iop] &= (~NPY_OP_ITFLAG_USINGBUFFER); + } + else { + /* In this case, the buffer is being used */ + ptrs[iop] = buffers[iop]; + strides[iop] = dtypes[iop]->elsize; + if (itflags&NPY_ITFLAG_REDUCE) { + reduce_outerstrides[iop] = reduce_innersize * + strides[iop]; + reduce_outerptrs[iop] = ptrs[iop]; + } + /* Signal that the buffer is being used */ + op_itflags[iop] |= NPY_OP_ITFLAG_USINGBUFFER; + } + break; + /* Just a copy, but with a reduction */ + case NPY_OP_ITFLAG_REDUCE: + /* Do not reuse buffer if it did not exist */ + if (!(op_itflags[iop] & NPY_OP_ITFLAG_USINGBUFFER) && + (prev_dataptrs != NULL)) { + prev_dataptrs[iop] = NULL; + } + if (ad_strides[iop] == 0) { + strides[iop] = 0; + /* It's all in one stride in the inner loop dimension */ + if (is_onestride) { + NPY_IT_DBG_PRINT1("reduce op %d all one stride\n", (int)iop); + ptrs[iop] = ad_ptrs[iop]; + reduce_outerstrides[iop] = 0; + stransfer = NULL; + /* Signal that the buffer is not being used */ + op_itflags[iop] &= (~NPY_OP_ITFLAG_USINGBUFFER); + } + /* It's all in one stride in the reduce outer loop */ + else if ((reduce_outerdim > 0) && + (transfersize/reduce_innersize <= + NAD_SHAPE(reduce_outeraxisdata) - + NAD_INDEX(reduce_outeraxisdata))) { + NPY_IT_DBG_PRINT1("reduce op %d all one outer stride\n", + (int)iop); + ptrs[iop] = ad_ptrs[iop]; + /* Outer reduce loop advances by one item */ + reduce_outerstrides[iop] = + NAD_STRIDES(reduce_outeraxisdata)[iop]; + stransfer = NULL; + /* Signal that the buffer is not being used */ + op_itflags[iop] &= (~NPY_OP_ITFLAG_USINGBUFFER); + } + /* In this case, the buffer is being used */ + else { + NPY_IT_DBG_PRINT1("reduce op %d must buffer\n", (int)iop); + ptrs[iop] = buffers[iop]; + /* Both outer and inner reduce loops have stride 0 */ + if (NAD_STRIDES(reduce_outeraxisdata)[iop] == 0) { + reduce_outerstrides[iop] = 0; + } + /* Outer reduce loop advances by one item */ + else { + reduce_outerstrides[iop] = dtypes[iop]->elsize; + } + /* Signal that the buffer is being used */ + op_itflags[iop] |= NPY_OP_ITFLAG_USINGBUFFER; + } + + } + else if (is_onestride) { + NPY_IT_DBG_PRINT1("reduce op %d all one stride in dim 0\n", (int)iop); + ptrs[iop] = ad_ptrs[iop]; + strides[iop] = ad_strides[iop]; + reduce_outerstrides[iop] = 0; + stransfer = NULL; + /* Signal that the buffer is not being used */ + op_itflags[iop] &= (~NPY_OP_ITFLAG_USINGBUFFER); + } + else { + /* It's all in one stride in the reduce outer loop */ + if ((reduce_outerdim == 1) && + (transfersize/reduce_innersize <= + NAD_SHAPE(reduce_outeraxisdata) - + NAD_INDEX(reduce_outeraxisdata))) { + ptrs[iop] = ad_ptrs[iop]; + strides[iop] = ad_strides[iop]; + /* Outer reduce loop advances by one item */ + reduce_outerstrides[iop] = + NAD_STRIDES(reduce_outeraxisdata)[iop]; + stransfer = NULL; + /* Signal that the buffer is not being used */ + op_itflags[iop] &= (~NPY_OP_ITFLAG_USINGBUFFER); + } + /* In this case, the buffer is being used */ + else { + ptrs[iop] = buffers[iop]; + strides[iop] = dtypes[iop]->elsize; + + if (NAD_STRIDES(reduce_outeraxisdata)[iop] == 0) { + /* Reduction in outer reduce loop */ + reduce_outerstrides[iop] = 0; + } + else { + /* Advance to next items in outer reduce loop */ + reduce_outerstrides[iop] = reduce_innersize * + dtypes[iop]->elsize; + } + /* Signal that the buffer is being used */ + op_itflags[iop] |= NPY_OP_ITFLAG_USINGBUFFER; + } + } + reduce_outerptrs[iop] = ptrs[iop]; + break; + default: + /* In this case, the buffer is always being used */ + any_buffered = 1; + + /* Signal that the buffer is being used */ + op_itflags[iop] |= NPY_OP_ITFLAG_USINGBUFFER; + + if (!(op_itflags[iop]&NPY_OP_ITFLAG_REDUCE)) { + ptrs[iop] = buffers[iop]; + strides[iop] = dtypes[iop]->elsize; + if (itflags&NPY_ITFLAG_REDUCE) { + reduce_outerstrides[iop] = reduce_innersize * + strides[iop]; + reduce_outerptrs[iop] = ptrs[iop]; + } + } + /* The buffer is being used with reduction */ + else { + ptrs[iop] = buffers[iop]; + if (ad_strides[iop] == 0) { + NPY_IT_DBG_PRINT1("cast op %d has innermost stride 0\n", (int)iop); + strides[iop] = 0; + /* Both outer and inner reduce loops have stride 0 */ + if (NAD_STRIDES(reduce_outeraxisdata)[iop] == 0) { + NPY_IT_DBG_PRINT1("cast op %d has outermost stride 0\n", (int)iop); + reduce_outerstrides[iop] = 0; + } + /* Outer reduce loop advances by one item */ + else { + NPY_IT_DBG_PRINT1("cast op %d has outermost stride !=0\n", (int)iop); + reduce_outerstrides[iop] = dtypes[iop]->elsize; + } + } + else { + NPY_IT_DBG_PRINT1("cast op %d has innermost stride !=0\n", (int)iop); + strides[iop] = dtypes[iop]->elsize; + + if (NAD_STRIDES(reduce_outeraxisdata)[iop] == 0) { + NPY_IT_DBG_PRINT1("cast op %d has outermost stride 0\n", (int)iop); + /* Reduction in outer reduce loop */ + reduce_outerstrides[iop] = 0; + } + else { + NPY_IT_DBG_PRINT1("cast op %d has outermost stride !=0\n", (int)iop); + /* Advance to next items in outer reduce loop */ + reduce_outerstrides[iop] = reduce_innersize * + dtypes[iop]->elsize; + } + } + reduce_outerptrs[iop] = ptrs[iop]; + } + break; + } + + if (stransfer != NULL) { + npy_intp src_itemsize; + npy_intp op_transfersize; + + npy_intp dst_stride, *src_strides, *src_coords, *src_shape; + int ndim_transfer; + + npy_bool skip_transfer = 0; + + src_itemsize = PyArray_DTYPE(operands[iop])->elsize; + + /* If stransfer wasn't set to NULL, buffering is required */ + any_buffered = 1; + + /* + * If this operand is being reduced in the inner loop, + * set its buffering stride to zero, and just copy + * one element. + */ + if (op_itflags[iop]&NPY_OP_ITFLAG_REDUCE) { + if (ad_strides[iop] == 0) { + strides[iop] = 0; + if (reduce_outerstrides[iop] == 0) { + op_transfersize = 1; + dst_stride = 0; + src_strides = &dst_stride; + src_coords = &NAD_INDEX(reduce_outeraxisdata); + src_shape = &NAD_SHAPE(reduce_outeraxisdata); + ndim_transfer = 1; + + /* + * When we're reducing a single element, and + * it's still the same element, don't overwrite + * it even when reuse reduce loops is unset. + * This preserves the precision of the + * intermediate calculation. + */ + if (prev_dataptrs && + prev_dataptrs[iop] == ad_ptrs[iop]) { + NPY_IT_DBG_PRINT1("Iterator: skipping operand %d" + " copy because it's a 1-element reduce\n", + (int)iop); + + skip_transfer = 1; + } + } + else { + op_transfersize = NBF_REDUCE_OUTERSIZE(bufferdata); + dst_stride = reduce_outerstrides[iop]; + src_strides = &NAD_STRIDES(reduce_outeraxisdata)[iop]; + src_coords = &NAD_INDEX(reduce_outeraxisdata); + src_shape = &NAD_SHAPE(reduce_outeraxisdata); + ndim_transfer = ndim - reduce_outerdim; + } + } + else { + if (reduce_outerstrides[iop] == 0) { + op_transfersize = NBF_SIZE(bufferdata); + dst_stride = strides[iop]; + src_strides = &ad_strides[iop]; + src_coords = &NAD_INDEX(axisdata); + src_shape = &NAD_SHAPE(axisdata); + ndim_transfer = reduce_outerdim ? reduce_outerdim : 1; + } + else { + op_transfersize = transfersize; + dst_stride = strides[iop]; + src_strides = &ad_strides[iop]; + src_coords = &NAD_INDEX(axisdata); + src_shape = &NAD_SHAPE(axisdata); + ndim_transfer = ndim; + } + } + } + else { + op_transfersize = transfersize; + dst_stride = strides[iop]; + src_strides = &ad_strides[iop]; + src_coords = &NAD_INDEX(axisdata); + src_shape = &NAD_SHAPE(axisdata); + ndim_transfer = ndim; + } + + /* + * If the whole buffered loop structure remains the same, + * and the source pointer for this data didn't change, + * we don't have to copy the data again. + */ + if (reuse_reduce_loops && prev_dataptrs[iop] == ad_ptrs[iop]) { + NPY_IT_DBG_PRINT2("Iterator: skipping operands %d " + "copy (%d items) because loops are reused and the data " + "pointer didn't change\n", + (int)iop, (int)op_transfersize); + skip_transfer = 1; + } + + /* If the data type requires zero-inititialization */ + if (PyDataType_FLAGCHK(dtypes[iop], NPY_NEEDS_INIT)) { + NPY_IT_DBG_PRINT("Iterator: Buffer requires init, " + "memsetting to 0\n"); + memset(ptrs[iop], 0, dtypes[iop]->elsize*op_transfersize); + /* Can't skip the transfer in this case */ + skip_transfer = 0; + } + + if (!skip_transfer) { + NPY_IT_DBG_PRINT2("Iterator: Copying operand %d to " + "buffer (%d items)\n", + (int)iop, (int)op_transfersize); + + PyArray_TransferNDimToStrided(ndim_transfer, + ptrs[iop], dst_stride, + ad_ptrs[iop], src_strides, axisdata_incr, + src_coords, axisdata_incr, + src_shape, axisdata_incr, + op_transfersize, src_itemsize, + stransfer, + transferdata); + } + } + else if (ptrs[iop] == buffers[iop]) { + /* If the data type requires zero-inititialization */ + if (PyDataType_FLAGCHK(dtypes[iop], NPY_NEEDS_INIT)) { + NPY_IT_DBG_PRINT1("Iterator: Write-only buffer for " + "operand %d requires init, " + "memsetting to 0\n", (int)iop); + memset(ptrs[iop], 0, dtypes[iop]->elsize*transfersize); + } + } + + } + + /* + * If buffering wasn't needed, we can grow the inner + * loop to as large as possible. + * + * TODO: Could grow REDUCE loop too with some more logic above. + */ + if (!any_buffered && (itflags&NPY_ITFLAG_GROWINNER) && + !(itflags&NPY_ITFLAG_REDUCE)) { + if (singlestridesize > transfersize) { + NPY_IT_DBG_PRINT2("Iterator: Expanding inner loop size " + "from %d to %d since buffering wasn't needed\n", + (int)NBF_SIZE(bufferdata), (int)singlestridesize); + NBF_SIZE(bufferdata) = singlestridesize; + NBF_BUFITEREND(bufferdata) = iterindex + singlestridesize; + } + } + + NPY_IT_DBG_PRINT1("Any buffering needed: %d\n", any_buffered); + + NPY_IT_DBG_PRINT1("Iterator: Finished copying inputs to buffers " + "(buffered size is %d)\n", (int)NBF_SIZE(bufferdata)); +} + +/* + * This checks how much space can be buffered without encountering the + * same value twice, or for operands whose innermost stride is zero, + * without encountering a different value. By reducing the buffered + * amount to this size, reductions can be safely buffered. + * + * Reductions are buffered with two levels of looping, to avoid + * frequent copying to the buffers. The return value is the over-all + * buffer size, and when the flag NPY_ITFLAG_REDUCE is set, reduce_innersize + * receives the size of the inner of the two levels of looping. + * + * The value placed in reduce_outerdim is the index into the AXISDATA + * for where the second level of the double loop begins. + * + * The return value is always a multiple of the value placed in + * reduce_innersize. + */ +static npy_intp +npyiter_checkreducesize(NpyIter *iter, npy_intp count, + npy_intp *reduce_innersize, + npy_intp *reduce_outerdim) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + npy_intp coord, shape, *strides; + npy_intp reducespace = 1, factor; + npy_bool nonzerocoord; + + npyiter_opitflags *op_itflags = NIT_OPITFLAGS(iter); + char stride0op[NPY_MAXARGS]; + + /* Default to no outer axis */ + *reduce_outerdim = 0; + + /* If there's only one dimension, no need to calculate anything */ + if (ndim == 1 || count == 0) { + *reduce_innersize = count; + return count; + } + + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + axisdata = NIT_AXISDATA(iter); + + /* Indicate which REDUCE operands have stride 0 in the inner loop */ + strides = NAD_STRIDES(axisdata); + for (iop = 0; iop < nop; ++iop) { + stride0op[iop] = (op_itflags[iop]&NPY_OP_ITFLAG_REDUCE) && + (strides[iop] == 0); + NPY_IT_DBG_PRINT2("Iterator: Operand %d has stride 0 in " + "the inner loop? %d\n", iop, (int)stride0op[iop]); + } + shape = NAD_SHAPE(axisdata); + coord = NAD_INDEX(axisdata); + reducespace += (shape-coord-1); + factor = shape; + NIT_ADVANCE_AXISDATA(axisdata, 1); + + /* Initialize nonzerocoord based on the first coordinate */ + nonzerocoord = (coord != 0); + + /* Go forward through axisdata, calculating the space available */ + for (idim = 1; idim < ndim && reducespace < count; + ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + NPY_IT_DBG_PRINT2("Iterator: inner loop reducespace %d, count %d\n", + (int)reducespace, (int)count); + + strides = NAD_STRIDES(axisdata); + for (iop = 0; iop < nop; ++iop) { + /* + * If a reduce stride switched from zero to non-zero, or + * vice versa, that's the point where the data will stop + * being the same element or will repeat, and if the + * buffer starts with an all zero multi-index up to this + * point, gives us the reduce_innersize. + */ + if((stride0op[iop] && (strides[iop] != 0)) || + (!stride0op[iop] && + (strides[iop] == 0) && + (op_itflags[iop]&NPY_OP_ITFLAG_REDUCE))) { + NPY_IT_DBG_PRINT1("Iterator: Reduce operation limits " + "buffer to %d\n", (int)reducespace); + /* + * If we already found more elements than count, or + * the starting coordinate wasn't zero, the two-level + * looping is unnecessary/can't be done, so return. + */ + if (count <= reducespace) { + *reduce_innersize = count; + NIT_ITFLAGS(iter) |= NPY_ITFLAG_REUSE_REDUCE_LOOPS; + return count; + } + else if (nonzerocoord) { + if (reducespace < count) { + count = reducespace; + } + *reduce_innersize = count; + /* NOTE: This is similar to the (coord != 0) case below. */ + NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_REUSE_REDUCE_LOOPS; + return count; + } + else { + *reduce_innersize = reducespace; + break; + } + } + } + /* If we broke out of the loop early, we found reduce_innersize */ + if (iop != nop) { + NPY_IT_DBG_PRINT2("Iterator: Found first dim not " + "reduce (%d of %d)\n", iop, nop); + break; + } + + shape = NAD_SHAPE(axisdata); + coord = NAD_INDEX(axisdata); + if (coord != 0) { + nonzerocoord = 1; + } + reducespace += (shape-coord-1) * factor; + factor *= shape; + } + + /* + * If there was any non-zero coordinate, the reduction inner + * loop doesn't fit in the buffersize, or the reduction inner loop + * covered the entire iteration size, can't do the double loop. + */ + if (nonzerocoord || count < reducespace || idim == ndim) { + if (reducespace < count) { + count = reducespace; + } + *reduce_innersize = count; + /* In this case, we can't reuse the reduce loops */ + NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_REUSE_REDUCE_LOOPS; + return count; + } + + coord = NAD_INDEX(axisdata); + if (coord != 0) { + /* + * In this case, it is only safe to reuse the buffer if the amount + * of data copied is not more then the current axes, as is the + * case when reuse_reduce_loops was active already. + * It should be in principle OK when the idim loop returns immidiatly. + */ + NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_REUSE_REDUCE_LOOPS; + } + else { + /* In this case, we can reuse the reduce loops */ + NIT_ITFLAGS(iter) |= NPY_ITFLAG_REUSE_REDUCE_LOOPS; + } + + *reduce_innersize = reducespace; + count /= reducespace; + + NPY_IT_DBG_PRINT2("Iterator: reduce_innersize %d count /ed %d\n", + (int)reducespace, (int)count); + + /* + * Continue through the rest of the dimensions. If there are + * two separated reduction axes, we may have to cut the buffer + * short again. + */ + *reduce_outerdim = idim; + reducespace = 1; + factor = 1; + /* Indicate which REDUCE operands have stride 0 at the current level */ + strides = NAD_STRIDES(axisdata); + for (iop = 0; iop < nop; ++iop) { + stride0op[iop] = (op_itflags[iop]&NPY_OP_ITFLAG_REDUCE) && + (strides[iop] == 0); + NPY_IT_DBG_PRINT2("Iterator: Operand %d has stride 0 in " + "the outer loop? %d\n", iop, (int)stride0op[iop]); + } + shape = NAD_SHAPE(axisdata); + reducespace += (shape-coord-1) * factor; + factor *= shape; + NIT_ADVANCE_AXISDATA(axisdata, 1); + ++idim; + + for (; idim < ndim && reducespace < count; + ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + NPY_IT_DBG_PRINT2("Iterator: outer loop reducespace %d, count %d\n", + (int)reducespace, (int)count); + strides = NAD_STRIDES(axisdata); + for (iop = 0; iop < nop; ++iop) { + /* + * If a reduce stride switched from zero to non-zero, or + * vice versa, that's the point where the data will stop + * being the same element or will repeat, and if the + * buffer starts with an all zero multi-index up to this + * point, gives us the reduce_innersize. + */ + if((stride0op[iop] && (strides[iop] != 0)) || + (!stride0op[iop] && + (strides[iop] == 0) && + (op_itflags[iop]&NPY_OP_ITFLAG_REDUCE))) { + NPY_IT_DBG_PRINT1("Iterator: Reduce operation limits " + "buffer to %d\n", (int)reducespace); + /* + * This terminates the outer level of our double loop. + */ + if (count <= reducespace) { + return count * (*reduce_innersize); + } + else { + return reducespace * (*reduce_innersize); + } + } + } + + shape = NAD_SHAPE(axisdata); + coord = NAD_INDEX(axisdata); + if (coord != 0) { + nonzerocoord = 1; + } + reducespace += (shape-coord-1) * factor; + factor *= shape; + } + + if (reducespace < count) { + count = reducespace; + } + return count * (*reduce_innersize); +} + +#undef NPY_ITERATOR_IMPLEMENTATION_CODE diff --git a/numpy/core/src/multiarray/nditer_constr.c b/numpy/core/src/multiarray/nditer_constr.c new file mode 100644 index 0000000..b74aca0 --- /dev/null +++ b/numpy/core/src/multiarray/nditer_constr.c @@ -0,0 +1,3252 @@ +/* + * This file implements the construction, copying, and destruction + * aspects of NumPy's nditer. + * + * Copyright (c) 2010-2011 by Mark Wiebe (mwwiebe@gmail.com) + * The University of British Columbia + * + * Copyright (c) 2011 Enthought, Inc + * + * See LICENSE.txt for the license. + */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +/* Indicate that this .c file is allowed to include the header */ +#define NPY_ITERATOR_IMPLEMENTATION_CODE +#include "nditer_impl.h" + +#include "arrayobject.h" +#include "templ_common.h" +#include "mem_overlap.h" + + +/* Internal helper functions private to this file */ +static int +npyiter_check_global_flags(npy_uint32 flags, npy_uint32* itflags); +static int +npyiter_check_op_axes(int nop, int oa_ndim, int **op_axes, + npy_intp *itershape); +static int +npyiter_calculate_ndim(int nop, PyArrayObject **op_in, + int oa_ndim); +static int +npyiter_check_per_op_flags(npy_uint32 flags, npyiter_opitflags *op_itflags); +static int +npyiter_prepare_one_operand(PyArrayObject **op, + char **op_dataptr, + PyArray_Descr *op_request_dtype, + PyArray_Descr** op_dtype, + npy_uint32 flags, + npy_uint32 op_flags, npyiter_opitflags *op_itflags); +static int +npyiter_prepare_operands(int nop, + PyArrayObject **op_in, + PyArrayObject **op, + char **op_dataptr, + PyArray_Descr **op_request_dtypes, + PyArray_Descr **op_dtype, + npy_uint32 flags, + npy_uint32 *op_flags, npyiter_opitflags *op_itflags, + npy_int8 *out_maskop); +static int +npyiter_check_casting(int nop, PyArrayObject **op, + PyArray_Descr **op_dtype, + NPY_CASTING casting, + npyiter_opitflags *op_itflags); +static int +npyiter_fill_axisdata(NpyIter *iter, npy_uint32 flags, npyiter_opitflags *op_itflags, + char **op_dataptr, + npy_uint32 *op_flags, int **op_axes, + npy_intp *itershape); +static void +npyiter_replace_axisdata(NpyIter *iter, int iop, + PyArrayObject *op, + int op_ndim, char *op_dataptr, + int *op_axes); +static void +npyiter_compute_index_strides(NpyIter *iter, npy_uint32 flags); +static void +npyiter_apply_forced_iteration_order(NpyIter *iter, NPY_ORDER order); +static void +npyiter_flip_negative_strides(NpyIter *iter); +static void +npyiter_reverse_axis_ordering(NpyIter *iter); +static void +npyiter_find_best_axis_ordering(NpyIter *iter); +static PyArray_Descr * +npyiter_get_common_dtype(int nop, PyArrayObject **op, + npyiter_opitflags *op_itflags, PyArray_Descr **op_dtype, + PyArray_Descr **op_request_dtypes, + int only_inputs); +static PyArrayObject * +npyiter_new_temp_array(NpyIter *iter, PyTypeObject *subtype, + npy_uint32 flags, npyiter_opitflags *op_itflags, + int op_ndim, npy_intp *shape, + PyArray_Descr *op_dtype, int *op_axes); +static int +npyiter_allocate_arrays(NpyIter *iter, + npy_uint32 flags, + PyArray_Descr **op_dtype, PyTypeObject *subtype, + npy_uint32 *op_flags, npyiter_opitflags *op_itflags, + int **op_axes); +static void +npyiter_get_priority_subtype(int nop, PyArrayObject **op, + npyiter_opitflags *op_itflags, + double *subtype_priority, PyTypeObject **subtype); +static int +npyiter_allocate_transfer_functions(NpyIter *iter); + + +/*NUMPY_API + * Allocate a new iterator for multiple array objects, and advanced + * options for controlling the broadcasting, shape, and buffer size. + */ +NPY_NO_EXPORT NpyIter * +NpyIter_AdvancedNew(int nop, PyArrayObject **op_in, npy_uint32 flags, + NPY_ORDER order, NPY_CASTING casting, + npy_uint32 *op_flags, + PyArray_Descr **op_request_dtypes, + int oa_ndim, int **op_axes, npy_intp *itershape, + npy_intp buffersize) +{ + npy_uint32 itflags = NPY_ITFLAG_IDENTPERM; + int idim, ndim; + int iop; + + /* The iterator being constructed */ + NpyIter *iter; + + /* Per-operand values */ + PyArrayObject **op; + PyArray_Descr **op_dtype; + npyiter_opitflags *op_itflags; + char **op_dataptr; + + npy_int8 *perm; + NpyIter_BufferData *bufferdata = NULL; + int any_allocate = 0, any_missing_dtypes = 0, need_subtype = 0; + + /* The subtype for automatically allocated outputs */ + double subtype_priority = NPY_PRIORITY; + PyTypeObject *subtype = &PyArray_Type; + +#if NPY_IT_CONSTRUCTION_TIMING + npy_intp c_temp, + c_start, + c_check_op_axes, + c_check_global_flags, + c_calculate_ndim, + c_malloc, + c_prepare_operands, + c_fill_axisdata, + c_compute_index_strides, + c_apply_forced_iteration_order, + c_find_best_axis_ordering, + c_get_priority_subtype, + c_find_output_common_dtype, + c_check_casting, + c_allocate_arrays, + c_coalesce_axes, + c_prepare_buffers; +#endif + + NPY_IT_TIME_POINT(c_start); + + if (nop > NPY_MAXARGS) { + PyErr_Format(PyExc_ValueError, + "Cannot construct an iterator with more than %d operands " + "(%d were requested)", (int)NPY_MAXARGS, (int)nop); + return NULL; + } + + /* + * Before 1.8, if `oa_ndim == 0`, this meant `op_axes != NULL` was an error. + * With 1.8, `oa_ndim == -1` takes this role, while op_axes in that case + * enforces a 0-d iterator. Using `oa_ndim == 0` with `op_axes == NULL` + * is thus an error in 1.13 after deprecation. + */ + if ((oa_ndim == 0) && (op_axes == NULL)) { + PyErr_Format(PyExc_ValueError, + "Using `oa_ndim == 0` when `op_axes` is NULL. " + "Use `oa_ndim == -1` or the MultiNew " + "iterator for NumPy <1.8 compatibility"); + return NULL; + } + + /* Error check 'oa_ndim' and 'op_axes', which must be used together */ + if (!npyiter_check_op_axes(nop, oa_ndim, op_axes, itershape)) { + return NULL; + } + + NPY_IT_TIME_POINT(c_check_op_axes); + + /* Check the global iterator flags */ + if (!npyiter_check_global_flags(flags, &itflags)) { + return NULL; + } + + NPY_IT_TIME_POINT(c_check_global_flags); + + /* Calculate how many dimensions the iterator should have */ + ndim = npyiter_calculate_ndim(nop, op_in, oa_ndim); + + NPY_IT_TIME_POINT(c_calculate_ndim); + + /* Allocate memory for the iterator */ + iter = (NpyIter*) + PyObject_Malloc(NIT_SIZEOF_ITERATOR(itflags, ndim, nop)); + + NPY_IT_TIME_POINT(c_malloc); + + /* Fill in the basic data */ + NIT_ITFLAGS(iter) = itflags; + NIT_NDIM(iter) = ndim; + NIT_NOP(iter) = nop; + NIT_MASKOP(iter) = -1; + NIT_ITERINDEX(iter) = 0; + memset(NIT_BASEOFFSETS(iter), 0, (nop+1)*NPY_SIZEOF_INTP); + + op = NIT_OPERANDS(iter); + op_dtype = NIT_DTYPES(iter); + op_itflags = NIT_OPITFLAGS(iter); + op_dataptr = NIT_RESETDATAPTR(iter); + + /* Prepare all the operands */ + if (!npyiter_prepare_operands(nop, op_in, op, op_dataptr, + op_request_dtypes, op_dtype, + flags, + op_flags, op_itflags, + &NIT_MASKOP(iter))) { + PyObject_Free(iter); + return NULL; + } + /* Set resetindex to zero as well (it's just after the resetdataptr) */ + op_dataptr[nop] = 0; + + NPY_IT_TIME_POINT(c_prepare_operands); + + /* + * Initialize buffer data (must set the buffers and transferdata + * to NULL before we might deallocate the iterator). + */ + if (itflags & NPY_ITFLAG_BUFFER) { + bufferdata = NIT_BUFFERDATA(iter); + NBF_SIZE(bufferdata) = 0; + memset(NBF_BUFFERS(bufferdata), 0, nop*NPY_SIZEOF_INTP); + memset(NBF_PTRS(bufferdata), 0, nop*NPY_SIZEOF_INTP); + memset(NBF_READTRANSFERDATA(bufferdata), 0, nop*NPY_SIZEOF_INTP); + memset(NBF_WRITETRANSFERDATA(bufferdata), 0, nop*NPY_SIZEOF_INTP); + } + + /* Fill in the AXISDATA arrays and set the ITERSIZE field */ + if (!npyiter_fill_axisdata(iter, flags, op_itflags, op_dataptr, + op_flags, op_axes, itershape)) { + NpyIter_Deallocate(iter); + return NULL; + } + + NPY_IT_TIME_POINT(c_fill_axisdata); + + if (itflags & NPY_ITFLAG_BUFFER) { + /* + * If buffering is enabled and no buffersize was given, use a default + * chosen to be big enough to get some amortization benefits, but + * small enough to be cache-friendly. + */ + if (buffersize <= 0) { + buffersize = NPY_BUFSIZE; + } + /* No point in a buffer bigger than the iteration size */ + if (buffersize > NIT_ITERSIZE(iter)) { + buffersize = NIT_ITERSIZE(iter); + } + NBF_BUFFERSIZE(bufferdata) = buffersize; + + /* + * Initialize for use in FirstVisit, which may be called before + * the buffers are filled and the reduce pos is updated. + */ + NBF_REDUCE_POS(bufferdata) = 0; + } + + /* + * If an index was requested, compute the strides for it. + * Note that we must do this before changing the order of the + * axes + */ + npyiter_compute_index_strides(iter, flags); + + NPY_IT_TIME_POINT(c_compute_index_strides); + + /* Initialize the perm to the identity */ + perm = NIT_PERM(iter); + for(idim = 0; idim < ndim; ++idim) { + perm[idim] = (npy_int8)idim; + } + + /* + * If an iteration order is being forced, apply it. + */ + npyiter_apply_forced_iteration_order(iter, order); + itflags = NIT_ITFLAGS(iter); + + NPY_IT_TIME_POINT(c_apply_forced_iteration_order); + + /* Set some flags for allocated outputs */ + for (iop = 0; iop < nop; ++iop) { + if (op[iop] == NULL) { + /* Flag this so later we can avoid flipping axes */ + any_allocate = 1; + /* If a subtype may be used, indicate so */ + if (!(op_flags[iop] & NPY_ITER_NO_SUBTYPE)) { + need_subtype = 1; + } + /* + * If the data type wasn't provided, will need to + * calculate it. + */ + if (op_dtype[iop] == NULL) { + any_missing_dtypes = 1; + } + } + } + + /* + * If the ordering was not forced, reorder the axes + * and flip negative strides to find the best one. + */ + if (!(itflags & NPY_ITFLAG_FORCEDORDER)) { + if (ndim > 1) { + npyiter_find_best_axis_ordering(iter); + } + /* + * If there's an output being allocated, we must not negate + * any strides. + */ + if (!any_allocate && !(flags & NPY_ITER_DONT_NEGATE_STRIDES)) { + npyiter_flip_negative_strides(iter); + } + itflags = NIT_ITFLAGS(iter); + } + + NPY_IT_TIME_POINT(c_find_best_axis_ordering); + + if (need_subtype) { + npyiter_get_priority_subtype(nop, op, op_itflags, + &subtype_priority, &subtype); + } + + NPY_IT_TIME_POINT(c_get_priority_subtype); + + /* + * If an automatically allocated output didn't have a specified + * dtype, we need to figure it out now, before allocating the outputs. + */ + if (any_missing_dtypes || (flags & NPY_ITER_COMMON_DTYPE)) { + PyArray_Descr *dtype; + int only_inputs = !(flags & NPY_ITER_COMMON_DTYPE); + + op = NIT_OPERANDS(iter); + op_dtype = NIT_DTYPES(iter); + + dtype = npyiter_get_common_dtype(nop, op, + op_itflags, op_dtype, + op_request_dtypes, + only_inputs); + if (dtype == NULL) { + NpyIter_Deallocate(iter); + return NULL; + } + if (flags & NPY_ITER_COMMON_DTYPE) { + NPY_IT_DBG_PRINT("Iterator: Replacing all data types\n"); + /* Replace all the data types */ + for (iop = 0; iop < nop; ++iop) { + if (op_dtype[iop] != dtype) { + Py_XDECREF(op_dtype[iop]); + Py_INCREF(dtype); + op_dtype[iop] = dtype; + } + } + } + else { + NPY_IT_DBG_PRINT("Iterator: Setting unset output data types\n"); + /* Replace the NULL data types */ + for (iop = 0; iop < nop; ++iop) { + if (op_dtype[iop] == NULL) { + Py_INCREF(dtype); + op_dtype[iop] = dtype; + } + } + } + Py_DECREF(dtype); + } + + NPY_IT_TIME_POINT(c_find_output_common_dtype); + + /* + * All of the data types have been settled, so it's time + * to check that data type conversions are following the + * casting rules. + */ + if (!npyiter_check_casting(nop, op, op_dtype, casting, op_itflags)) { + NpyIter_Deallocate(iter); + return NULL; + } + + NPY_IT_TIME_POINT(c_check_casting); + + /* + * At this point, the iteration order has been finalized. so + * any allocation of ops that were NULL, or any temporary + * copying due to casting/byte order/alignment can be + * done now using a memory layout matching the iterator. + */ + if (!npyiter_allocate_arrays(iter, flags, op_dtype, subtype, op_flags, + op_itflags, op_axes)) { + NpyIter_Deallocate(iter); + return NULL; + } + + NPY_IT_TIME_POINT(c_allocate_arrays); + + /* + * Finally, if a multi-index wasn't requested, + * it may be possible to coalesce some axes together. + */ + if (ndim > 1 && !(itflags & NPY_ITFLAG_HASMULTIINDEX)) { + npyiter_coalesce_axes(iter); + /* + * The operation may have changed the layout, so we have to + * get the internal pointers again. + */ + itflags = NIT_ITFLAGS(iter); + ndim = NIT_NDIM(iter); + op = NIT_OPERANDS(iter); + op_dtype = NIT_DTYPES(iter); + op_itflags = NIT_OPITFLAGS(iter); + op_dataptr = NIT_RESETDATAPTR(iter); + } + + NPY_IT_TIME_POINT(c_coalesce_axes); + + /* + * Now that the axes are finished, check whether we can apply + * the single iteration optimization to the iternext function. + */ + if (!(itflags & NPY_ITFLAG_BUFFER)) { + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + if (itflags & NPY_ITFLAG_EXLOOP) { + if (NIT_ITERSIZE(iter) == NAD_SHAPE(axisdata)) { + NIT_ITFLAGS(iter) |= NPY_ITFLAG_ONEITERATION; + } + } + else if (NIT_ITERSIZE(iter) == 1) { + NIT_ITFLAGS(iter) |= NPY_ITFLAG_ONEITERATION; + } + } + + /* + * If REFS_OK was specified, check whether there are any + * reference arrays and flag it if so. + */ + if (flags & NPY_ITER_REFS_OK) { + for (iop = 0; iop < nop; ++iop) { + PyArray_Descr *rdt = op_dtype[iop]; + if ((rdt->flags & (NPY_ITEM_REFCOUNT | + NPY_ITEM_IS_POINTER | + NPY_NEEDS_PYAPI)) != 0) { + /* Iteration needs API access */ + NIT_ITFLAGS(iter) |= NPY_ITFLAG_NEEDSAPI; + } + } + } + + /* If buffering is set without delayed allocation */ + if (itflags & NPY_ITFLAG_BUFFER) { + if (!npyiter_allocate_transfer_functions(iter)) { + NpyIter_Deallocate(iter); + return NULL; + } + if (!(itflags & NPY_ITFLAG_DELAYBUF)) { + /* Allocate the buffers */ + if (!npyiter_allocate_buffers(iter, NULL)) { + NpyIter_Deallocate(iter); + return NULL; + } + + /* Prepare the next buffers and set iterend/size */ + npyiter_copy_to_buffers(iter, NULL); + } + } + + NPY_IT_TIME_POINT(c_prepare_buffers); + +#if NPY_IT_CONSTRUCTION_TIMING + printf("\nIterator construction timing:\n"); + NPY_IT_PRINT_TIME_START(c_start); + NPY_IT_PRINT_TIME_VAR(c_check_op_axes); + NPY_IT_PRINT_TIME_VAR(c_check_global_flags); + NPY_IT_PRINT_TIME_VAR(c_calculate_ndim); + NPY_IT_PRINT_TIME_VAR(c_malloc); + NPY_IT_PRINT_TIME_VAR(c_prepare_operands); + NPY_IT_PRINT_TIME_VAR(c_fill_axisdata); + NPY_IT_PRINT_TIME_VAR(c_compute_index_strides); + NPY_IT_PRINT_TIME_VAR(c_apply_forced_iteration_order); + NPY_IT_PRINT_TIME_VAR(c_find_best_axis_ordering); + NPY_IT_PRINT_TIME_VAR(c_get_priority_subtype); + NPY_IT_PRINT_TIME_VAR(c_find_output_common_dtype); + NPY_IT_PRINT_TIME_VAR(c_check_casting); + NPY_IT_PRINT_TIME_VAR(c_allocate_arrays); + NPY_IT_PRINT_TIME_VAR(c_coalesce_axes); + NPY_IT_PRINT_TIME_VAR(c_prepare_buffers); + printf("\n"); +#endif + + return iter; +} + +/*NUMPY_API + * Allocate a new iterator for more than one array object, using + * standard NumPy broadcasting rules and the default buffer size. + */ +NPY_NO_EXPORT NpyIter * +NpyIter_MultiNew(int nop, PyArrayObject **op_in, npy_uint32 flags, + NPY_ORDER order, NPY_CASTING casting, + npy_uint32 *op_flags, + PyArray_Descr **op_request_dtypes) +{ + return NpyIter_AdvancedNew(nop, op_in, flags, order, casting, + op_flags, op_request_dtypes, + -1, NULL, NULL, 0); +} + +/*NUMPY_API + * Allocate a new iterator for one array object. + */ +NPY_NO_EXPORT NpyIter * +NpyIter_New(PyArrayObject *op, npy_uint32 flags, + NPY_ORDER order, NPY_CASTING casting, + PyArray_Descr* dtype) +{ + /* Split the flags into separate global and op flags */ + npy_uint32 op_flags = flags & NPY_ITER_PER_OP_FLAGS; + flags &= NPY_ITER_GLOBAL_FLAGS; + + return NpyIter_AdvancedNew(1, &op, flags, order, casting, + &op_flags, &dtype, + -1, NULL, NULL, 0); +} + +/*NUMPY_API + * Makes a copy of the iterator + */ +NPY_NO_EXPORT NpyIter * +NpyIter_Copy(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + int out_of_memory = 0; + + npy_intp size; + NpyIter *newiter; + PyArrayObject **objects; + PyArray_Descr **dtypes; + + /* Allocate memory for the new iterator */ + size = NIT_SIZEOF_ITERATOR(itflags, ndim, nop); + newiter = (NpyIter*)PyObject_Malloc(size); + + /* Copy the raw values to the new iterator */ + memcpy(newiter, iter, size); + + /* Take ownership of references to the operands and dtypes */ + objects = NIT_OPERANDS(newiter); + dtypes = NIT_DTYPES(newiter); + for (iop = 0; iop < nop; ++iop) { + Py_INCREF(objects[iop]); + Py_INCREF(dtypes[iop]); + } + + /* Allocate buffers and make copies of the transfer data if necessary */ + if (itflags & NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *bufferdata; + npy_intp buffersize, itemsize; + char **buffers; + NpyAuxData **readtransferdata, **writetransferdata; + + bufferdata = NIT_BUFFERDATA(newiter); + buffers = NBF_BUFFERS(bufferdata); + readtransferdata = NBF_READTRANSFERDATA(bufferdata); + writetransferdata = NBF_WRITETRANSFERDATA(bufferdata); + buffersize = NBF_BUFFERSIZE(bufferdata); + + for (iop = 0; iop < nop; ++iop) { + if (buffers[iop] != NULL) { + if (out_of_memory) { + buffers[iop] = NULL; + } + else { + itemsize = dtypes[iop]->elsize; + buffers[iop] = PyArray_malloc(itemsize*buffersize); + if (buffers[iop] == NULL) { + out_of_memory = 1; + } + } + } + + if (readtransferdata[iop] != NULL) { + if (out_of_memory) { + readtransferdata[iop] = NULL; + } + else { + readtransferdata[iop] = + NPY_AUXDATA_CLONE(readtransferdata[iop]); + if (readtransferdata[iop] == NULL) { + out_of_memory = 1; + } + } + } + + if (writetransferdata[iop] != NULL) { + if (out_of_memory) { + writetransferdata[iop] = NULL; + } + else { + writetransferdata[iop] = + NPY_AUXDATA_CLONE(writetransferdata[iop]); + if (writetransferdata[iop] == NULL) { + out_of_memory = 1; + } + } + } + } + + /* Initialize the buffers to the current iterindex */ + if (!out_of_memory && NBF_SIZE(bufferdata) > 0) { + npyiter_goto_iterindex(newiter, NIT_ITERINDEX(newiter)); + + /* Prepare the next buffers and set iterend/size */ + npyiter_copy_to_buffers(newiter, NULL); + } + } + + if (out_of_memory) { + NpyIter_Deallocate(newiter); + PyErr_NoMemory(); + return NULL; + } + + return newiter; +} + +/*NUMPY_API + * Deallocate an iterator + */ +NPY_NO_EXPORT int +NpyIter_Deallocate(NpyIter *iter) +{ + npy_uint32 itflags; + /*int ndim = NIT_NDIM(iter);*/ + int iop, nop; + PyArray_Descr **dtype; + PyArrayObject **object; + + if (iter == NULL) { + return NPY_SUCCEED; + } + + itflags = NIT_ITFLAGS(iter); + nop = NIT_NOP(iter); + dtype = NIT_DTYPES(iter); + object = NIT_OPERANDS(iter); + + /* Deallocate any buffers and buffering data */ + if (itflags & NPY_ITFLAG_BUFFER) { + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + char **buffers; + NpyAuxData **transferdata; + + /* buffers */ + buffers = NBF_BUFFERS(bufferdata); + for(iop = 0; iop < nop; ++iop, ++buffers) { + PyArray_free(*buffers); + } + /* read bufferdata */ + transferdata = NBF_READTRANSFERDATA(bufferdata); + for(iop = 0; iop < nop; ++iop, ++transferdata) { + if (*transferdata) { + NPY_AUXDATA_FREE(*transferdata); + } + } + /* write bufferdata */ + transferdata = NBF_WRITETRANSFERDATA(bufferdata); + for(iop = 0; iop < nop; ++iop, ++transferdata) { + if (*transferdata) { + NPY_AUXDATA_FREE(*transferdata); + } + } + } + + /* Deallocate all the dtypes and objects that were iterated */ + for(iop = 0; iop < nop; ++iop, ++dtype, ++object) { + Py_XDECREF(*dtype); + Py_XDECREF(*object); + } + + /* Deallocate the iterator memory */ + PyObject_Free(iter); + + return NPY_SUCCEED; +} + +/* Checks 'flags' for (C|F)_ORDER_INDEX, MULTI_INDEX, and EXTERNAL_LOOP, + * setting the appropriate internal flags in 'itflags'. + * + * Returns 1 on success, 0 on error. + */ +static int +npyiter_check_global_flags(npy_uint32 flags, npy_uint32* itflags) +{ + if ((flags & NPY_ITER_PER_OP_FLAGS) != 0) { + PyErr_SetString(PyExc_ValueError, + "A per-operand flag was passed as a global flag " + "to the iterator constructor"); + return 0; + } + + /* Check for an index */ + if (flags & (NPY_ITER_C_INDEX | NPY_ITER_F_INDEX)) { + if ((flags & (NPY_ITER_C_INDEX | NPY_ITER_F_INDEX)) == + (NPY_ITER_C_INDEX | NPY_ITER_F_INDEX)) { + PyErr_SetString(PyExc_ValueError, + "Iterator flags C_INDEX and " + "F_INDEX cannot both be specified"); + return 0; + } + (*itflags) |= NPY_ITFLAG_HASINDEX; + } + /* Check if a multi-index was requested */ + if (flags & NPY_ITER_MULTI_INDEX) { + /* + * This flag primarily disables dimension manipulations that + * would produce an incorrect multi-index. + */ + (*itflags) |= NPY_ITFLAG_HASMULTIINDEX; + } + /* Check if the caller wants to handle inner iteration */ + if (flags & NPY_ITER_EXTERNAL_LOOP) { + if ((*itflags) & (NPY_ITFLAG_HASINDEX | NPY_ITFLAG_HASMULTIINDEX)) { + PyErr_SetString(PyExc_ValueError, + "Iterator flag EXTERNAL_LOOP cannot be used " + "if an index or multi-index is being tracked"); + return 0; + } + (*itflags) |= NPY_ITFLAG_EXLOOP; + } + /* Ranged */ + if (flags & NPY_ITER_RANGED) { + (*itflags) |= NPY_ITFLAG_RANGE; + if ((flags & NPY_ITER_EXTERNAL_LOOP) && + !(flags & NPY_ITER_BUFFERED)) { + PyErr_SetString(PyExc_ValueError, + "Iterator flag RANGED cannot be used with " + "the flag EXTERNAL_LOOP unless " + "BUFFERED is also enabled"); + return 0; + } + } + /* Buffering */ + if (flags & NPY_ITER_BUFFERED) { + (*itflags) |= NPY_ITFLAG_BUFFER; + if (flags & NPY_ITER_GROWINNER) { + (*itflags) |= NPY_ITFLAG_GROWINNER; + } + if (flags & NPY_ITER_DELAY_BUFALLOC) { + (*itflags) |= NPY_ITFLAG_DELAYBUF; + } + } + + return 1; +} + +static int +npyiter_check_op_axes(int nop, int oa_ndim, int **op_axes, + npy_intp *itershape) +{ + char axes_dupcheck[NPY_MAXDIMS]; + int iop, idim; + + if (oa_ndim < 0) { + /* + * If `oa_ndim < 0`, `op_axes` and `itershape` are signalled to + * be unused and should be NULL. (Before NumPy 1.8 this was + * signalled by `oa_ndim == 0`.) + */ + if (op_axes != NULL || itershape != NULL) { + PyErr_Format(PyExc_ValueError, + "If 'op_axes' or 'itershape' is not NULL in the iterator " + "constructor, 'oa_ndim' must be zero or greater"); + return 0; + } + return 1; + } + if (oa_ndim > NPY_MAXDIMS) { + PyErr_Format(PyExc_ValueError, + "Cannot construct an iterator with more than %d dimensions " + "(%d were requested for op_axes)", + (int)NPY_MAXDIMS, oa_ndim); + return 0; + } + if (op_axes == NULL) { + PyErr_Format(PyExc_ValueError, + "If 'oa_ndim' is zero or greater in the iterator " + "constructor, then op_axes cannot be NULL"); + return 0; + } + + /* Check that there are no duplicates in op_axes */ + for (iop = 0; iop < nop; ++iop) { + int *axes = op_axes[iop]; + if (axes != NULL) { + memset(axes_dupcheck, 0, NPY_MAXDIMS); + for (idim = 0; idim < oa_ndim; ++idim) { + npy_intp i = axes[idim]; + if (i >= 0) { + if (i >= NPY_MAXDIMS) { + PyErr_Format(PyExc_ValueError, + "The 'op_axes' provided to the iterator " + "constructor for operand %d " + "contained invalid " + "values %d", (int)iop, (int)i); + return 0; + } + else if (axes_dupcheck[i] == 1) { + PyErr_Format(PyExc_ValueError, + "The 'op_axes' provided to the iterator " + "constructor for operand %d " + "contained duplicate " + "value %d", (int)iop, (int)i); + return 0; + } + else { + axes_dupcheck[i] = 1; + } + } + } + } + } + + return 1; +} + +static int +npyiter_calculate_ndim(int nop, PyArrayObject **op_in, + int oa_ndim) +{ + /* If 'op_axes' is being used, force 'ndim' */ + if (oa_ndim >= 0 ) { + return oa_ndim; + } + /* Otherwise it's the maximum 'ndim' from the operands */ + else { + int ndim = 0, iop; + + for (iop = 0; iop < nop; ++iop) { + if (op_in[iop] != NULL) { + int ondim = PyArray_NDIM(op_in[iop]); + if (ondim > ndim) { + ndim = ondim; + } + } + + } + + return ndim; + } +} + +/* + * Checks the per-operand input flags, and fills in op_itflags. + * + * Returns 1 on success, 0 on failure. + */ +static int +npyiter_check_per_op_flags(npy_uint32 op_flags, npyiter_opitflags *op_itflags) +{ + if ((op_flags & NPY_ITER_GLOBAL_FLAGS) != 0) { + PyErr_SetString(PyExc_ValueError, + "A global iterator flag was passed as a per-operand flag " + "to the iterator constructor"); + return 0; + } + + /* Check the read/write flags */ + if (op_flags & NPY_ITER_READONLY) { + /* The read/write flags are mutually exclusive */ + if (op_flags & (NPY_ITER_READWRITE|NPY_ITER_WRITEONLY)) { + PyErr_SetString(PyExc_ValueError, + "Only one of the iterator flags READWRITE, " + "READONLY, and WRITEONLY may be " + "specified for an operand"); + return 0; + } + + *op_itflags = NPY_OP_ITFLAG_READ; + } + else if (op_flags & NPY_ITER_READWRITE) { + /* The read/write flags are mutually exclusive */ + if (op_flags & NPY_ITER_WRITEONLY) { + PyErr_SetString(PyExc_ValueError, + "Only one of the iterator flags READWRITE, " + "READONLY, and WRITEONLY may be " + "specified for an operand"); + return 0; + } + + *op_itflags = NPY_OP_ITFLAG_READ|NPY_OP_ITFLAG_WRITE; + } + else if(op_flags & NPY_ITER_WRITEONLY) { + *op_itflags = NPY_OP_ITFLAG_WRITE; + } + else { + PyErr_SetString(PyExc_ValueError, + "None of the iterator flags READWRITE, " + "READONLY, or WRITEONLY were " + "specified for an operand"); + return 0; + } + + /* Check the flags for temporary copies */ + if (((*op_itflags) & NPY_OP_ITFLAG_WRITE) && + (op_flags & (NPY_ITER_COPY | + NPY_ITER_UPDATEIFCOPY)) == NPY_ITER_COPY) { + PyErr_SetString(PyExc_ValueError, + "If an iterator operand is writeable, must use " + "the flag UPDATEIFCOPY instead of " + "COPY"); + return 0; + } + + /* Check the flag for a write masked operands */ + if (op_flags & NPY_ITER_WRITEMASKED) { + if (!((*op_itflags) & NPY_OP_ITFLAG_WRITE)) { + PyErr_SetString(PyExc_ValueError, + "The iterator flag WRITEMASKED may only " + "be used with READWRITE or WRITEONLY"); + return 0; + } + if ((op_flags & NPY_ITER_ARRAYMASK) != 0) { + PyErr_SetString(PyExc_ValueError, + "The iterator flag WRITEMASKED may not " + "be used together with ARRAYMASK"); + return 0; + } + *op_itflags |= NPY_OP_ITFLAG_WRITEMASKED; + } + + if ((op_flags & NPY_ITER_VIRTUAL) != 0) { + if ((op_flags & NPY_ITER_READWRITE) == 0) { + PyErr_SetString(PyExc_ValueError, + "The iterator flag VIRTUAL should be " + "be used together with READWRITE"); + return 0; + } + *op_itflags |= NPY_OP_ITFLAG_VIRTUAL; + } + + return 1; +} + +/* + * Prepares a a constructor operand. Assumes a reference to 'op' + * is owned, and that 'op' may be replaced. Fills in 'op_dataptr', + * 'op_dtype', and may modify 'op_itflags'. + * + * Returns 1 on success, 0 on failure. + */ +static int +npyiter_prepare_one_operand(PyArrayObject **op, + char **op_dataptr, + PyArray_Descr *op_request_dtype, + PyArray_Descr **op_dtype, + npy_uint32 flags, + npy_uint32 op_flags, npyiter_opitflags *op_itflags) +{ + /* NULL operands must be automatically allocated outputs */ + if (*op == NULL) { + /* ALLOCATE or VIRTUAL should be enabled */ + if ((op_flags & (NPY_ITER_ALLOCATE|NPY_ITER_VIRTUAL)) == 0) { + PyErr_SetString(PyExc_ValueError, + "Iterator operand was NULL, but neither the " + "ALLOCATE nor the VIRTUAL flag was specified"); + return 0; + } + + if (op_flags & NPY_ITER_ALLOCATE) { + /* Writing should be enabled */ + if (!((*op_itflags) & NPY_OP_ITFLAG_WRITE)) { + PyErr_SetString(PyExc_ValueError, + "Automatic allocation was requested for an iterator " + "operand, but it wasn't flagged for writing"); + return 0; + } + /* + * Reading should be disabled if buffering is enabled without + * also enabling NPY_ITER_DELAY_BUFALLOC. In all other cases, + * the caller may initialize the allocated operand to a value + * before beginning iteration. + */ + if (((flags & (NPY_ITER_BUFFERED | + NPY_ITER_DELAY_BUFALLOC)) == NPY_ITER_BUFFERED) && + ((*op_itflags) & NPY_OP_ITFLAG_READ)) { + PyErr_SetString(PyExc_ValueError, + "Automatic allocation was requested for an iterator " + "operand, and it was flagged as readable, but " + "buffering without delayed allocation was enabled"); + return 0; + } + + /* If a requested dtype was provided, use it, otherwise NULL */ + Py_XINCREF(op_request_dtype); + *op_dtype = op_request_dtype; + } + else { + *op_dtype = NULL; + } + + /* Specify bool if no dtype was requested for the mask */ + if (op_flags & NPY_ITER_ARRAYMASK) { + if (*op_dtype == NULL) { + *op_dtype = PyArray_DescrFromType(NPY_BOOL); + if (*op_dtype == NULL) { + return 0; + } + } + } + + *op_dataptr = NULL; + + return 1; + } + + /* VIRTUAL operands must be NULL */ + if (op_flags & NPY_ITER_VIRTUAL) { + PyErr_SetString(PyExc_ValueError, + "Iterator operand flag VIRTUAL was specified, " + "but the operand was not NULL"); + return 0; + } + + + if (PyArray_Check(*op)) { + + if ((*op_itflags) & NPY_OP_ITFLAG_WRITE + && PyArray_FailUnlessWriteable(*op, "operand array with iterator " + "write flag set") < 0) { + return 0; + } + if (!(flags & NPY_ITER_ZEROSIZE_OK) && PyArray_SIZE(*op) == 0) { + PyErr_SetString(PyExc_ValueError, + "Iteration of zero-sized operands is not enabled"); + return 0; + } + *op_dataptr = PyArray_BYTES(*op); + /* PyArray_DESCR does not give us a reference */ + *op_dtype = PyArray_DESCR(*op); + if (*op_dtype == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator input operand has no dtype descr"); + return 0; + } + Py_INCREF(*op_dtype); + /* + * If references weren't specifically allowed, make sure there + * are no references in the inputs or requested dtypes. + */ + if (!(flags & NPY_ITER_REFS_OK)) { + PyArray_Descr *dt = PyArray_DESCR(*op); + if (((dt->flags & (NPY_ITEM_REFCOUNT | + NPY_ITEM_IS_POINTER)) != 0) || + (dt != *op_dtype && + (((*op_dtype)->flags & (NPY_ITEM_REFCOUNT | + NPY_ITEM_IS_POINTER))) != 0)) { + PyErr_SetString(PyExc_TypeError, + "Iterator operand or requested dtype holds " + "references, but the REFS_OK flag was not enabled"); + return 0; + } + } + /* + * Checking whether casts are valid is done later, once the + * final data types have been selected. For now, just store the + * requested type. + */ + if (op_request_dtype != NULL) { + /* We just have a borrowed reference to op_request_dtype */ + Py_INCREF(op_request_dtype); + /* If the requested dtype is flexible, adapt it */ + PyArray_AdaptFlexibleDType((PyObject *)(*op), PyArray_DESCR(*op), + &op_request_dtype); + if (op_request_dtype == NULL) { + return 0; + } + + /* Store the requested dtype */ + Py_DECREF(*op_dtype); + *op_dtype = op_request_dtype; + } + + /* Check if the operand is in the byte order requested */ + if (op_flags & NPY_ITER_NBO) { + /* Check byte order */ + if (!PyArray_ISNBO((*op_dtype)->byteorder)) { + PyArray_Descr *nbo_dtype; + + /* Replace with a new descr which is in native byte order */ + nbo_dtype = PyArray_DescrNewByteorder(*op_dtype, NPY_NATIVE); + Py_DECREF(*op_dtype); + *op_dtype = nbo_dtype; + + NPY_IT_DBG_PRINT("Iterator: Setting NPY_OP_ITFLAG_CAST " + "because of NPY_ITER_NBO\n"); + /* Indicate that byte order or alignment needs fixing */ + *op_itflags |= NPY_OP_ITFLAG_CAST; + } + } + /* Check if the operand is aligned */ + if (op_flags & NPY_ITER_ALIGNED) { + /* Check alignment */ + if (!PyArray_ISALIGNED(*op)) { + NPY_IT_DBG_PRINT("Iterator: Setting NPY_OP_ITFLAG_CAST " + "because of NPY_ITER_ALIGNED\n"); + *op_itflags |= NPY_OP_ITFLAG_CAST; + } + } + /* + * The check for NPY_ITER_CONTIG can only be done later, + * once the final iteration order is settled. + */ + } + else { + PyErr_SetString(PyExc_ValueError, + "Iterator inputs must be ndarrays"); + return 0; + } + + return 1; +} + +/* + * Process all the operands, copying new references so further processing + * can replace the arrays if copying is necessary. + */ +static int +npyiter_prepare_operands(int nop, PyArrayObject **op_in, + PyArrayObject **op, + char **op_dataptr, + PyArray_Descr **op_request_dtypes, + PyArray_Descr **op_dtype, + npy_uint32 flags, + npy_uint32 *op_flags, npyiter_opitflags *op_itflags, + npy_int8 *out_maskop) +{ + int iop, i; + npy_int8 maskop = -1; + int any_writemasked_ops = 0; + + /* + * Here we just prepare the provided operands. + */ + for (iop = 0; iop < nop; ++iop) { + op[iop] = op_in[iop]; + Py_XINCREF(op[iop]); + op_dtype[iop] = NULL; + + /* Check the readonly/writeonly flags, and fill in op_itflags */ + if (!npyiter_check_per_op_flags(op_flags[iop], &op_itflags[iop])) { + goto fail_iop; + } + + /* Extract the operand which is for masked iteration */ + if ((op_flags[iop] & NPY_ITER_ARRAYMASK) != 0) { + if (maskop != -1) { + PyErr_SetString(PyExc_ValueError, + "Only one iterator operand may receive an " + "ARRAYMASK flag"); + goto fail_iop; + } + + maskop = iop; + *out_maskop = iop; + } + + if (op_flags[iop] & NPY_ITER_WRITEMASKED) { + any_writemasked_ops = 1; + } + + /* + * Prepare the operand. This produces an op_dtype[iop] reference + * on success. + */ + if (!npyiter_prepare_one_operand(&op[iop], + &op_dataptr[iop], + op_request_dtypes ? op_request_dtypes[iop] : NULL, + &op_dtype[iop], + flags, + op_flags[iop], &op_itflags[iop])) { + goto fail_iop; + } + } + + /* If all the operands were NULL, it's an error */ + if (op[0] == NULL) { + int all_null = 1; + for (iop = 1; iop < nop; ++iop) { + if (op[iop] != NULL) { + all_null = 0; + break; + } + } + if (all_null) { + PyErr_SetString(PyExc_ValueError, + "At least one iterator operand must be non-NULL"); + goto fail_nop; + } + } + + if (any_writemasked_ops && maskop < 0) { + PyErr_SetString(PyExc_ValueError, + "An iterator operand was flagged as WRITEMASKED, " + "but no ARRAYMASK operand was given to supply " + "the mask"); + goto fail_nop; + } + else if (!any_writemasked_ops && maskop >= 0) { + PyErr_SetString(PyExc_ValueError, + "An iterator operand was flagged as the ARRAYMASK, " + "but no WRITEMASKED operands were given to use " + "the mask"); + goto fail_nop; + } + + return 1; + + fail_nop: + iop = nop; + fail_iop: + for (i = 0; i < iop; ++i) { + Py_XDECREF(op[i]); + Py_XDECREF(op_dtype[i]); + } + return 0; +} + +static const char * +npyiter_casting_to_string(NPY_CASTING casting) +{ + switch (casting) { + case NPY_NO_CASTING: + return "'no'"; + case NPY_EQUIV_CASTING: + return "'equiv'"; + case NPY_SAFE_CASTING: + return "'safe'"; + case NPY_SAME_KIND_CASTING: + return "'same_kind'"; + case NPY_UNSAFE_CASTING: + return "'unsafe'"; + default: + return ""; + } +} + + +static int +npyiter_check_casting(int nop, PyArrayObject **op, + PyArray_Descr **op_dtype, + NPY_CASTING casting, + npyiter_opitflags *op_itflags) +{ + int iop; + + for(iop = 0; iop < nop; ++iop) { + NPY_IT_DBG_PRINT1("Iterator: Checking casting for operand %d\n", + (int)iop); +#if NPY_IT_DBG_TRACING + printf("op: "); + if (op[iop] != NULL) { + PyObject_Print((PyObject *)PyArray_DESCR(op[iop]), stdout, 0); + } + else { + printf(""); + } + printf(", iter: "); + PyObject_Print((PyObject *)op_dtype[iop], stdout, 0); + printf("\n"); +#endif + /* If the types aren't equivalent, a cast is necessary */ + if (op[iop] != NULL && !PyArray_EquivTypes(PyArray_DESCR(op[iop]), + op_dtype[iop])) { + /* Check read (op -> temp) casting */ + if ((op_itflags[iop] & NPY_OP_ITFLAG_READ) && + !PyArray_CanCastArrayTo(op[iop], + op_dtype[iop], + casting)) { + PyObject *errmsg; + errmsg = PyUString_FromFormat( + "Iterator operand %d dtype could not be cast from ", + (int)iop); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(op[iop]))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)op_dtype[iop])); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" according to the rule %s", + npyiter_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return 0; + } + /* Check write (temp -> op) casting */ + if ((op_itflags[iop] & NPY_OP_ITFLAG_WRITE) && + !PyArray_CanCastTypeTo(op_dtype[iop], + PyArray_DESCR(op[iop]), + casting)) { + PyObject *errmsg; + errmsg = PyUString_FromString( + "Iterator requested dtype could not be cast from "); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)op_dtype[iop])); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(op[iop]))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(", the operand %d dtype, " + "according to the rule %s", + (int)iop, + npyiter_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return 0; + } + + NPY_IT_DBG_PRINT("Iterator: Setting NPY_OP_ITFLAG_CAST " + "because the types aren't equivalent\n"); + /* Indicate that this operand needs casting */ + op_itflags[iop] |= NPY_OP_ITFLAG_CAST; + } + } + + return 1; +} + +/* + * Checks that the mask broadcasts to the WRITEMASK REDUCE + * operand 'iop', but 'iop' never broadcasts to the mask. + * If 'iop' broadcasts to the mask, the result would be more + * than one mask value per reduction element, something which + * is invalid. + * + * This check should only be called after all the operands + * have been filled in. + * + * Returns 1 on success, 0 on error. + */ +static int +check_mask_for_writemasked_reduction(NpyIter *iter, int iop) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + int maskop = NIT_MASKOP(iter); + + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + for(idim = 0; idim < ndim; ++idim) { + npy_intp maskstride, istride; + + istride = NAD_STRIDES(axisdata)[iop]; + maskstride = NAD_STRIDES(axisdata)[maskop]; + + /* + * If 'iop' is being broadcast to 'maskop', we have + * the invalid situation described above. + */ + if (maskstride != 0 && istride == 0) { + PyErr_SetString(PyExc_ValueError, + "Iterator reduction operand is WRITEMASKED, " + "but also broadcasts to multiple mask values. " + "There can be only one mask value per WRITEMASKED " + "element."); + return 0; + } + + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + + return 1; +} + +/* + * Fills in the AXISDATA for the 'nop' operands, broadcasting + * the dimensionas as necessary. Also fills + * in the ITERSIZE data member. + * + * If op_axes is not NULL, it should point to an array of ndim-sized + * arrays, one for each op. + * + * Returns 1 on success, 0 on failure. + */ +static int +npyiter_fill_axisdata(NpyIter *iter, npy_uint32 flags, npyiter_opitflags *op_itflags, + char **op_dataptr, + npy_uint32 *op_flags, int **op_axes, + npy_intp *itershape) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + int maskop = NIT_MASKOP(iter); + + int ondim; + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + PyArrayObject **op = NIT_OPERANDS(iter), *op_cur; + npy_intp broadcast_shape[NPY_MAXDIMS]; + + /* First broadcast the shapes together */ + if (itershape == NULL) { + for (idim = 0; idim < ndim; ++idim) { + broadcast_shape[idim] = 1; + } + } + else { + for (idim = 0; idim < ndim; ++idim) { + broadcast_shape[idim] = itershape[idim]; + /* Negative shape entries are deduced from the operands */ + if (broadcast_shape[idim] < 0) { + broadcast_shape[idim] = 1; + } + } + } + for (iop = 0; iop < nop; ++iop) { + op_cur = op[iop]; + if (op_cur != NULL) { + npy_intp *shape = PyArray_DIMS(op_cur); + ondim = PyArray_NDIM(op_cur); + + if (op_axes == NULL || op_axes[iop] == NULL) { + /* + * Possible if op_axes are being used, but + * op_axes[iop] is NULL + */ + if (ondim > ndim) { + PyErr_SetString(PyExc_ValueError, + "input operand has more dimensions than allowed " + "by the axis remapping"); + return 0; + } + for (idim = 0; idim < ondim; ++idim) { + npy_intp bshape = broadcast_shape[idim+ndim-ondim], + op_shape = shape[idim]; + if (bshape == 1) { + broadcast_shape[idim+ndim-ondim] = op_shape; + } + else if (bshape != op_shape && op_shape != 1) { + goto broadcast_error; + } + } + } + else { + int *axes = op_axes[iop]; + for (idim = 0; idim < ndim; ++idim) { + int i = axes[idim]; + if (i >= 0) { + if (i < ondim) { + npy_intp bshape = broadcast_shape[idim], + op_shape = shape[i]; + if (bshape == 1) { + broadcast_shape[idim] = op_shape; + } + else if (bshape != op_shape && op_shape != 1) { + goto broadcast_error; + } + } + else { + PyErr_Format(PyExc_ValueError, + "Iterator input op_axes[%d][%d] (==%d) " + "is not a valid axis of op[%d], which " + "has %d dimensions ", + (int)iop, (int)(ndim-idim-1), (int)i, + (int)iop, (int)ondim); + return 0; + } + } + } + } + } + } + /* + * If a shape was provided with a 1 entry, make sure that entry didn't + * get expanded by broadcasting. + */ + if (itershape != NULL) { + for (idim = 0; idim < ndim; ++idim) { + if (itershape[idim] == 1 && broadcast_shape[idim] != 1) { + goto broadcast_error; + } + } + } + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + if (ndim == 0) { + /* Need to fill the first axisdata, even if the iterator is 0-d */ + NAD_SHAPE(axisdata) = 1; + NAD_INDEX(axisdata) = 0; + memcpy(NAD_PTRS(axisdata), op_dataptr, NPY_SIZEOF_INTP*nop); + memset(NAD_STRIDES(axisdata), 0, NPY_SIZEOF_INTP*nop); + } + + /* Now process the operands, filling in the axisdata */ + for (idim = 0; idim < ndim; ++idim) { + npy_intp bshape = broadcast_shape[ndim-idim-1]; + npy_intp *strides = NAD_STRIDES(axisdata); + + NAD_SHAPE(axisdata) = bshape; + NAD_INDEX(axisdata) = 0; + memcpy(NAD_PTRS(axisdata), op_dataptr, NPY_SIZEOF_INTP*nop); + + for (iop = 0; iop < nop; ++iop) { + op_cur = op[iop]; + + if (op_axes == NULL || op_axes[iop] == NULL) { + if (op_cur == NULL) { + strides[iop] = 0; + } + else { + ondim = PyArray_NDIM(op_cur); + if (bshape == 1) { + strides[iop] = 0; + if (idim >= ondim && + (op_flags[iop] & NPY_ITER_NO_BROADCAST)) { + goto operand_different_than_broadcast; + } + } + else if (idim >= ondim || + PyArray_DIM(op_cur, ondim-idim-1) == 1) { + strides[iop] = 0; + if (op_flags[iop] & NPY_ITER_NO_BROADCAST) { + goto operand_different_than_broadcast; + } + /* If it's writeable, this means a reduction */ + if (op_itflags[iop] & NPY_OP_ITFLAG_WRITE) { + if (!(flags & NPY_ITER_REDUCE_OK)) { + PyErr_SetString(PyExc_ValueError, + "output operand requires a " + "reduction, but reduction is " + "not enabled"); + return 0; + } + if (!(op_itflags[iop] & NPY_OP_ITFLAG_READ)) { + PyErr_SetString(PyExc_ValueError, + "output operand requires a " + "reduction, but is flagged as " + "write-only, not read-write"); + return 0; + } + /* + * The ARRAYMASK can't be a reduction, because + * it would be possible to write back to the + * array once when the ARRAYMASK says 'True', + * then have the reduction on the ARRAYMASK + * later flip to 'False', indicating that the + * write back should never have been done, + * and violating the strict masking semantics + */ + if (iop == maskop) { + PyErr_SetString(PyExc_ValueError, + "output operand requires a " + "reduction, but is flagged as " + "the ARRAYMASK operand which " + "is not permitted to be the " + "result of a reduction"); + return 0; + } + + NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE; + op_itflags[iop] |= NPY_OP_ITFLAG_REDUCE; + } + } + else { + strides[iop] = PyArray_STRIDE(op_cur, ondim-idim-1); + } + } + } + else { + int *axes = op_axes[iop]; + int i = axes[ndim-idim-1]; + if (i >= 0) { + if (bshape == 1 || op_cur == NULL) { + strides[iop] = 0; + } + else if (PyArray_DIM(op_cur, i) == 1) { + strides[iop] = 0; + if (op_flags[iop] & NPY_ITER_NO_BROADCAST) { + goto operand_different_than_broadcast; + } + /* If it's writeable, this means a reduction */ + if (op_itflags[iop] & NPY_OP_ITFLAG_WRITE) { + if (!(flags & NPY_ITER_REDUCE_OK)) { + PyErr_SetString(PyExc_ValueError, + "output operand requires a reduction, but " + "reduction is not enabled"); + return 0; + } + if (!(op_itflags[iop] & NPY_OP_ITFLAG_READ)) { + PyErr_SetString(PyExc_ValueError, + "output operand requires a reduction, but " + "is flagged as write-only, not " + "read-write"); + return 0; + } + NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE; + op_itflags[iop] |= NPY_OP_ITFLAG_REDUCE; + } + } + else { + strides[iop] = PyArray_STRIDE(op_cur, i); + } + } + else if (bshape == 1) { + strides[iop] = 0; + } + else { + strides[iop] = 0; + /* If it's writeable, this means a reduction */ + if (op_itflags[iop] & NPY_OP_ITFLAG_WRITE) { + if (!(flags & NPY_ITER_REDUCE_OK)) { + PyErr_SetString(PyExc_ValueError, + "output operand requires a reduction, but " + "reduction is not enabled"); + return 0; + } + if (!(op_itflags[iop] & NPY_OP_ITFLAG_READ)) { + PyErr_SetString(PyExc_ValueError, + "output operand requires a reduction, but " + "is flagged as write-only, not " + "read-write"); + return 0; + } + NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE; + op_itflags[iop] |= NPY_OP_ITFLAG_REDUCE; + } + } + } + } + + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + + /* Now fill in the ITERSIZE member */ + NIT_ITERSIZE(iter) = 1; + for (idim = 0; idim < ndim; ++idim) { + if (npy_mul_with_overflow_intp(&NIT_ITERSIZE(iter), + NIT_ITERSIZE(iter), broadcast_shape[idim])) { + if ((itflags & NPY_ITFLAG_HASMULTIINDEX) && + !(itflags & NPY_ITFLAG_HASINDEX) && + !(itflags & NPY_ITFLAG_BUFFER)) { + /* + * If RemoveAxis may be called, the size check is delayed + * until either the multi index is removed, or GetIterNext + * is called. + */ + NIT_ITERSIZE(iter) = -1; + break; + } + else { + PyErr_SetString(PyExc_ValueError, "iterator is too large"); + return 0; + } + } + } + /* The range defaults to everything */ + NIT_ITERSTART(iter) = 0; + NIT_ITEREND(iter) = NIT_ITERSIZE(iter); + + return 1; + +broadcast_error: { + PyObject *errmsg, *tmp; + npy_intp remdims[NPY_MAXDIMS]; + char *tmpstr; + + if (op_axes == NULL) { + errmsg = PyUString_FromString("operands could not be broadcast " + "together with shapes "); + if (errmsg == NULL) { + return 0; + } + for (iop = 0; iop < nop; ++iop) { + if (op[iop] != NULL) { + tmp = convert_shape_to_string(PyArray_NDIM(op[iop]), + PyArray_DIMS(op[iop]), + " "); + if (tmp == NULL) { + Py_DECREF(errmsg); + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + } + } + if (itershape != NULL) { + tmp = PyUString_FromString("and requested shape "); + if (tmp == NULL) { + Py_DECREF(errmsg); + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + + tmp = convert_shape_to_string(ndim, itershape, ""); + if (tmp == NULL) { + Py_DECREF(errmsg); + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + + } + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + } + else { + errmsg = PyUString_FromString("operands could not be broadcast " + "together with remapped shapes " + "[original->remapped]: "); + for (iop = 0; iop < nop; ++iop) { + if (op[iop] != NULL) { + int *axes = op_axes[iop]; + + tmpstr = (axes == NULL) ? " " : "->"; + tmp = convert_shape_to_string(PyArray_NDIM(op[iop]), + PyArray_DIMS(op[iop]), + tmpstr); + if (tmp == NULL) { + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + + if (axes != NULL) { + for (idim = 0; idim < ndim; ++idim) { + npy_intp i = axes[idim]; + + if (i >= 0 && i < PyArray_NDIM(op[iop])) { + remdims[idim] = PyArray_DIM(op[iop], i); + } + else { + remdims[idim] = -1; + } + } + tmp = convert_shape_to_string(ndim, remdims, " "); + if (tmp == NULL) { + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + } + } + } + if (itershape != NULL) { + tmp = PyUString_FromString("and requested shape "); + if (tmp == NULL) { + Py_DECREF(errmsg); + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + + tmp = convert_shape_to_string(ndim, itershape, ""); + if (tmp == NULL) { + Py_DECREF(errmsg); + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + + } + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + } + + return 0; + } + +operand_different_than_broadcast: { + npy_intp remdims[NPY_MAXDIMS]; + PyObject *errmsg, *tmp; + + /* Start of error message */ + if (op_flags[iop] & NPY_ITER_READONLY) { + errmsg = PyUString_FromString("non-broadcastable operand " + "with shape "); + } + else { + errmsg = PyUString_FromString("non-broadcastable output " + "operand with shape "); + } + if (errmsg == NULL) { + return 0; + } + + /* Operand shape */ + tmp = convert_shape_to_string(PyArray_NDIM(op[iop]), + PyArray_DIMS(op[iop]), ""); + if (tmp == NULL) { + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + /* Remapped operand shape */ + if (op_axes != NULL && op_axes[iop] != NULL) { + int *axes = op_axes[iop]; + + for (idim = 0; idim < ndim; ++idim) { + npy_intp i = axes[ndim-idim-1]; + + if (i >= 0 && i < PyArray_NDIM(op[iop])) { + remdims[idim] = PyArray_DIM(op[iop], i); + } + else { + remdims[idim] = -1; + } + } + + tmp = PyUString_FromString(" [remapped to "); + if (tmp == NULL) { + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + + tmp = convert_shape_to_string(ndim, remdims, "]"); + if (tmp == NULL) { + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + } + + tmp = PyUString_FromString(" doesn't match the broadcast shape "); + if (tmp == NULL) { + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + + /* Broadcast shape */ + tmp = convert_shape_to_string(ndim, broadcast_shape, ""); + if (tmp == NULL) { + return 0; + } + PyUString_ConcatAndDel(&errmsg, tmp); + if (errmsg == NULL) { + return 0; + } + + PyErr_SetObject(PyExc_ValueError, errmsg); + Py_DECREF(errmsg); + + return 0; + } +} + +/* + * Replaces the AXISDATA for the iop'th operand, broadcasting + * the dimensions as necessary. Assumes the replacement array is + * exactly the same shape as the original array used when + * npy_fill_axisdata was called. + * + * If op_axes is not NULL, it should point to an ndim-sized + * array. + */ +static void +npyiter_replace_axisdata(NpyIter *iter, int iop, + PyArrayObject *op, + int op_ndim, char *op_dataptr, + int *op_axes) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + NpyIter_AxisData *axisdata0, *axisdata; + npy_intp sizeof_axisdata; + npy_int8 *perm; + npy_intp baseoffset = 0; + + perm = NIT_PERM(iter); + axisdata0 = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + /* + * Replace just the strides which were non-zero, and compute + * the base data address. + */ + axisdata = axisdata0; + + if (op_axes != NULL) { + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + npy_int8 p; + int i; + npy_intp shape; + + /* Apply the perm to get the original axis */ + p = perm[idim]; + if (p < 0) { + i = op_axes[ndim+p]; + } + else { + i = op_axes[ndim-p-1]; + } + + if (0 <= i && i < op_ndim) { + shape = PyArray_DIM(op, i); + if (shape != 1) { + npy_intp stride = PyArray_STRIDE(op, i); + if (p < 0) { + /* If the perm entry is negative, flip the axis */ + NAD_STRIDES(axisdata)[iop] = -stride; + baseoffset += stride*(shape-1); + } + else { + NAD_STRIDES(axisdata)[iop] = stride; + } + } + } + } + } + else { + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + npy_int8 p; + int i; + npy_intp shape; + + /* Apply the perm to get the original axis */ + p = perm[idim]; + if (p < 0) { + i = op_ndim+p; + } + else { + i = op_ndim-p-1; + } + + if (i >= 0) { + shape = PyArray_DIM(op, i); + if (shape != 1) { + npy_intp stride = PyArray_STRIDE(op, i); + if (p < 0) { + /* If the perm entry is negative, flip the axis */ + NAD_STRIDES(axisdata)[iop] = -stride; + baseoffset += stride*(shape-1); + } + else { + NAD_STRIDES(axisdata)[iop] = stride; + } + } + } + } + } + + op_dataptr += baseoffset; + + /* Now the base data pointer is calculated, set it everywhere it's needed */ + NIT_RESETDATAPTR(iter)[iop] = op_dataptr; + NIT_BASEOFFSETS(iter)[iop] = baseoffset; + axisdata = axisdata0; + /* Fill at least one axisdata, for the 0-d case */ + NAD_PTRS(axisdata)[iop] = op_dataptr; + NIT_ADVANCE_AXISDATA(axisdata, 1); + for (idim = 1; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + NAD_PTRS(axisdata)[iop] = op_dataptr; + } +} + +/* + * Computes the iterator's index strides and initializes the index values + * to zero. + * + * This must be called before the axes (i.e. the AXISDATA array) may + * be reordered. + */ +static void +npyiter_compute_index_strides(NpyIter *iter, npy_uint32 flags) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_intp indexstride; + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + + /* + * If there is only one element being iterated, we just have + * to touch the first AXISDATA because nothing will ever be + * incremented. This also initializes the data for the 0-d case. + */ + if (NIT_ITERSIZE(iter) == 1) { + if (itflags & NPY_ITFLAG_HASINDEX) { + axisdata = NIT_AXISDATA(iter); + NAD_PTRS(axisdata)[nop] = 0; + } + return; + } + + if (flags & NPY_ITER_C_INDEX) { + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + axisdata = NIT_AXISDATA(iter); + indexstride = 1; + for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + npy_intp shape = NAD_SHAPE(axisdata); + + if (shape == 1) { + NAD_STRIDES(axisdata)[nop] = 0; + } + else { + NAD_STRIDES(axisdata)[nop] = indexstride; + } + NAD_PTRS(axisdata)[nop] = 0; + indexstride *= shape; + } + } + else if (flags & NPY_ITER_F_INDEX) { + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + axisdata = NIT_INDEX_AXISDATA(NIT_AXISDATA(iter), ndim-1); + indexstride = 1; + for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, -1)) { + npy_intp shape = NAD_SHAPE(axisdata); + + if (shape == 1) { + NAD_STRIDES(axisdata)[nop] = 0; + } + else { + NAD_STRIDES(axisdata)[nop] = indexstride; + } + NAD_PTRS(axisdata)[nop] = 0; + indexstride *= shape; + } + } +} + +/* + * If the order is NPY_KEEPORDER, lets the iterator find the best + * iteration order, otherwise forces it. Indicates in the itflags that + * whether the iteration order was forced. + */ +static void +npyiter_apply_forced_iteration_order(NpyIter *iter, NPY_ORDER order) +{ + /*npy_uint32 itflags = NIT_ITFLAGS(iter);*/ + int ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + switch (order) { + case NPY_CORDER: + NIT_ITFLAGS(iter) |= NPY_ITFLAG_FORCEDORDER; + break; + case NPY_FORTRANORDER: + NIT_ITFLAGS(iter) |= NPY_ITFLAG_FORCEDORDER; + /* Only need to actually do something if there is more than 1 dim */ + if (ndim > 1) { + npyiter_reverse_axis_ordering(iter); + } + break; + case NPY_ANYORDER: + NIT_ITFLAGS(iter) |= NPY_ITFLAG_FORCEDORDER; + /* Only need to actually do something if there is more than 1 dim */ + if (ndim > 1) { + PyArrayObject **op = NIT_OPERANDS(iter); + int forder = 1; + + /* Check that all the array inputs are fortran order */ + for (iop = 0; iop < nop; ++iop, ++op) { + if (*op && !PyArray_CHKFLAGS(*op, NPY_ARRAY_F_CONTIGUOUS)) { + forder = 0; + break; + } + } + + if (forder) { + npyiter_reverse_axis_ordering(iter); + } + } + break; + case NPY_KEEPORDER: + /* Don't set the forced order flag here... */ + break; + } +} + +/* + * This function negates any strides in the iterator + * which are negative. When iterating more than one + * object, it only flips strides when they are all + * negative or zero. + */ +static void +npyiter_flip_negative_strides(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + npy_intp istrides, nstrides = NAD_NSTRIDES(); + NpyIter_AxisData *axisdata, *axisdata0; + npy_intp *baseoffsets; + npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + int any_flipped = 0; + + axisdata0 = axisdata = NIT_AXISDATA(iter); + baseoffsets = NIT_BASEOFFSETS(iter); + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + npy_intp *strides = NAD_STRIDES(axisdata); + int any_negative = 0; + + /* + * Check the signs of all the operand strides. + */ + for (iop = 0; iop < nop; ++iop) { + if (strides[iop] < 0) { + any_negative = 1; + } + else if (strides[iop] != 0) { + break; + } + } + /* + * If at least one stride is negative and none are positive, + * flip all the strides for this dimension. + */ + if (any_negative && iop == nop) { + npy_intp shapem1 = NAD_SHAPE(axisdata) - 1; + + for (istrides = 0; istrides < nstrides; ++istrides) { + npy_intp stride = strides[istrides]; + + /* Adjust the base pointers to start at the end */ + baseoffsets[istrides] += shapem1 * stride; + /* Flip the stride */ + strides[istrides] = -stride; + } + /* + * Make the perm entry negative so get_multi_index + * knows it's flipped + */ + NIT_PERM(iter)[idim] = -1-NIT_PERM(iter)[idim]; + + any_flipped = 1; + } + } + + /* + * If any strides were flipped, the base pointers were adjusted + * in the first AXISDATA, and need to be copied to all the rest + */ + if (any_flipped) { + char **resetdataptr = NIT_RESETDATAPTR(iter); + + for (istrides = 0; istrides < nstrides; ++istrides) { + resetdataptr[istrides] += baseoffsets[istrides]; + } + axisdata = axisdata0; + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + char **ptrs = NAD_PTRS(axisdata); + for (istrides = 0; istrides < nstrides; ++istrides) { + ptrs[istrides] = resetdataptr[istrides]; + } + } + /* + * Indicate that some of the perm entries are negative, + * and that it's not (strictly speaking) the identity perm. + */ + NIT_ITFLAGS(iter) = (NIT_ITFLAGS(iter)|NPY_ITFLAG_NEGPERM) & + ~NPY_ITFLAG_IDENTPERM; + } +} + +static void +npyiter_reverse_axis_ordering(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_intp i, temp, size; + npy_intp *first, *last; + npy_int8 *perm; + + size = NIT_AXISDATA_SIZEOF(itflags, ndim, nop)/NPY_SIZEOF_INTP; + first = (npy_intp*)NIT_AXISDATA(iter); + last = first + (ndim-1)*size; + + /* This loop reverses the order of the AXISDATA array */ + while (first < last) { + for (i = 0; i < size; ++i) { + temp = first[i]; + first[i] = last[i]; + last[i] = temp; + } + first += size; + last -= size; + } + + /* Store the perm we applied */ + perm = NIT_PERM(iter); + for(i = ndim-1; i >= 0; --i, ++perm) { + *perm = (npy_int8)i; + } + + NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_IDENTPERM; +} + +static NPY_INLINE npy_intp +intp_abs(npy_intp x) +{ + return (x < 0) ? -x : x; +} + +static void +npyiter_find_best_axis_ordering(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + npy_intp ax_i0, ax_i1, ax_ipos; + npy_int8 ax_j0, ax_j1; + npy_int8 *perm; + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + int permuted = 0; + + perm = NIT_PERM(iter); + + /* + * Do a custom stable insertion sort. Note that because + * the AXISDATA has been reversed from C order, this + * is sorting from smallest stride to biggest stride. + */ + for (ax_i0 = 1; ax_i0 < ndim; ++ax_i0) { + npy_intp *strides0; + + /* 'ax_ipos' is where perm[ax_i0] will get inserted */ + ax_ipos = ax_i0; + ax_j0 = perm[ax_i0]; + + strides0 = NAD_STRIDES(NIT_INDEX_AXISDATA(axisdata, ax_j0)); + for (ax_i1 = ax_i0-1; ax_i1 >= 0; --ax_i1) { + int ambig = 1, shouldswap = 0; + npy_intp *strides1; + + ax_j1 = perm[ax_i1]; + + strides1 = NAD_STRIDES(NIT_INDEX_AXISDATA(axisdata, ax_j1)); + + for (iop = 0; iop < nop; ++iop) { + if (strides0[iop] != 0 && strides1[iop] != 0) { + if (intp_abs(strides1[iop]) <= + intp_abs(strides0[iop])) { + /* + * Set swap even if it's not ambiguous already, + * because in the case of conflicts between + * different operands, C-order wins. + */ + shouldswap = 0; + } + else { + /* Only set swap if it's still ambiguous */ + if (ambig) { + shouldswap = 1; + } + } + + /* + * A comparison has been done, so it's + * no longer ambiguous + */ + ambig = 0; + } + } + /* + * If the comparison was unambiguous, either shift + * 'ax_ipos' to 'ax_i1' or stop looking for an insertion + * point + */ + if (!ambig) { + if (shouldswap) { + ax_ipos = ax_i1; + } + else { + break; + } + } + } + + /* Insert perm[ax_i0] into the right place */ + if (ax_ipos != ax_i0) { + for (ax_i1 = ax_i0; ax_i1 > ax_ipos; --ax_i1) { + perm[ax_i1] = perm[ax_i1-1]; + } + perm[ax_ipos] = ax_j0; + permuted = 1; + } + } + + /* Apply the computed permutation to the AXISDATA array */ + if (permuted == 1) { + npy_intp i, size = sizeof_axisdata/NPY_SIZEOF_INTP; + NpyIter_AxisData *ad_i; + + /* Use the index as a flag, set each to 1 */ + ad_i = axisdata; + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(ad_i, 1)) { + NAD_INDEX(ad_i) = 1; + } + /* Apply the permutation by following the cycles */ + for (idim = 0; idim < ndim; ++idim) { + ad_i = NIT_INDEX_AXISDATA(axisdata, idim); + + /* If this axis hasn't been touched yet, process it */ + if (NAD_INDEX(ad_i) == 1) { + npy_int8 pidim = perm[idim]; + npy_intp tmp; + NpyIter_AxisData *ad_p, *ad_q; + + if (pidim != idim) { + /* Follow the cycle, copying the data */ + for (i = 0; i < size; ++i) { + pidim = perm[idim]; + ad_q = ad_i; + tmp = *((npy_intp*)ad_q + i); + while (pidim != idim) { + ad_p = NIT_INDEX_AXISDATA(axisdata, pidim); + *((npy_intp*)ad_q + i) = *((npy_intp*)ad_p + i); + + ad_q = ad_p; + pidim = perm[(int)pidim]; + } + *((npy_intp*)ad_q + i) = tmp; + } + /* Follow the cycle again, marking it as done */ + pidim = perm[idim]; + + while (pidim != idim) { + NAD_INDEX(NIT_INDEX_AXISDATA(axisdata, pidim)) = 0; + pidim = perm[(int)pidim]; + } + } + NAD_INDEX(ad_i) = 0; + } + } + /* Clear the identity perm flag */ + NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_IDENTPERM; + } +} + +/* + * Calculates a dtype that all the types can be promoted to, using the + * ufunc rules. If only_inputs is 1, it leaves any operands that + * are not read from out of the calculation. + */ +static PyArray_Descr * +npyiter_get_common_dtype(int nop, PyArrayObject **op, + npyiter_opitflags *op_itflags, PyArray_Descr **op_dtype, + PyArray_Descr **op_request_dtypes, + int only_inputs) +{ + int iop; + npy_intp narrs = 0, ndtypes = 0; + PyArrayObject *arrs[NPY_MAXARGS]; + PyArray_Descr *dtypes[NPY_MAXARGS]; + PyArray_Descr *ret; + + NPY_IT_DBG_PRINT("Iterator: Getting a common data type from operands\n"); + + for (iop = 0; iop < nop; ++iop) { + if (op_dtype[iop] != NULL && + (!only_inputs || (op_itflags[iop] & NPY_OP_ITFLAG_READ))) { + /* If no dtype was requested and the op is a scalar, pass the op */ + if ((op_request_dtypes == NULL || + op_request_dtypes[iop] == NULL) && + PyArray_NDIM(op[iop]) == 0) { + arrs[narrs++] = op[iop]; + } + /* Otherwise just pass in the dtype */ + else { + dtypes[ndtypes++] = op_dtype[iop]; + } + } + } + + if (narrs == 0) { + npy_intp i; + ret = dtypes[0]; + for (i = 1; i < ndtypes; ++i) { + if (ret != dtypes[i]) + break; + } + if (i == ndtypes) { + if (ndtypes == 1 || PyArray_ISNBO(ret->byteorder)) { + Py_INCREF(ret); + } + else { + ret = PyArray_DescrNewByteorder(ret, NPY_NATIVE); + } + } + else { + ret = PyArray_ResultType(narrs, arrs, ndtypes, dtypes); + } + } + else { + ret = PyArray_ResultType(narrs, arrs, ndtypes, dtypes); + } + + return ret; +} + +/* + * Allocates a temporary array which can be used to replace op + * in the iteration. Its dtype will be op_dtype. + * + * The result array has a memory ordering which matches the iterator, + * which may or may not match that of op. The parameter 'shape' may be + * NULL, in which case it is filled in from the iterator's shape. + * + * This function must be called before any axes are coalesced. + */ +static PyArrayObject * +npyiter_new_temp_array(NpyIter *iter, PyTypeObject *subtype, + npy_uint32 flags, npyiter_opitflags *op_itflags, + int op_ndim, npy_intp *shape, + PyArray_Descr *op_dtype, int *op_axes) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_int8 *perm = NIT_PERM(iter); + npy_intp new_shape[NPY_MAXDIMS], strides[NPY_MAXDIMS], + stride = op_dtype->elsize; + NpyIter_AxisData *axisdata; + npy_intp sizeof_axisdata; + npy_intp i; + + PyArrayObject *ret; + + /* + * There is an interaction with array-dtypes here, which + * generally works. Let's say you make an nditer with an + * output dtype of a 2-double array. All-scalar inputs + * will result in a 1-dimensional output with shape (2). + * Everything still works out in the nditer, because the + * new dimension is always added on the end, and it cares + * about what happens at the beginning. + */ + + /* If it's a scalar, don't need to check the axes */ + if (op_ndim == 0) { + Py_INCREF(op_dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(subtype, op_dtype, 0, + NULL, NULL, NULL, 0, NULL); + + return ret; + } + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + + /* Initialize the strides to invalid values */ + for (i = 0; i < NPY_MAXDIMS; ++i) { + strides[i] = NPY_MAX_INTP; + } + + if (op_axes != NULL) { + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + npy_int8 p; + + /* Apply the perm to get the original axis */ + p = perm[idim]; + if (p < 0) { + i = op_axes[ndim+p]; + } + else { + i = op_axes[ndim-p-1]; + } + + if (i >= 0) { + NPY_IT_DBG_PRINT3("Iterator: Setting allocated stride %d " + "for iterator dimension %d to %d\n", (int)i, + (int)idim, (int)stride); + strides[i] = stride; + if (shape == NULL) { + new_shape[i] = NAD_SHAPE(axisdata); + stride *= new_shape[i]; + if (i >= ndim) { + PyErr_SetString(PyExc_ValueError, + "automatically allocated output array " + "specified with an inconsistent axis mapping"); + return NULL; + } + } + else { + stride *= shape[i]; + } + } + else { + if (shape == NULL) { + /* + * If deleting this axis produces a reduction, but + * reduction wasn't enabled, throw an error + */ + if (NAD_SHAPE(axisdata) != 1) { + if (!(flags & NPY_ITER_REDUCE_OK)) { + PyErr_SetString(PyExc_ValueError, + "output requires a reduction, but " + "reduction is not enabled"); + return NULL; + } + if (!((*op_itflags) & NPY_OP_ITFLAG_READ)) { + PyErr_SetString(PyExc_ValueError, + "output requires a reduction, but " + "is flagged as write-only, not read-write"); + return NULL; + } + + NPY_IT_DBG_PRINT("Iterator: Indicating that a " + "reduction is occurring\n"); + /* Indicate that a reduction is occurring */ + NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE; + (*op_itflags) |= NPY_OP_ITFLAG_REDUCE; + } + } + } + } + } + else { + for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + npy_int8 p; + + /* Apply the perm to get the original axis */ + p = perm[idim]; + if (p < 0) { + i = op_ndim + p; + } + else { + i = op_ndim - p - 1; + } + + if (i >= 0) { + NPY_IT_DBG_PRINT3("Iterator: Setting allocated stride %d " + "for iterator dimension %d to %d\n", (int)i, + (int)idim, (int)stride); + strides[i] = stride; + if (shape == NULL) { + new_shape[i] = NAD_SHAPE(axisdata); + stride *= new_shape[i]; + } + else { + stride *= shape[i]; + } + } + } + } + + /* + * If custom axes were specified, some dimensions may not have been used. + * Add the REDUCE itflag if this creates a reduction situation. + */ + if (shape == NULL) { + /* Ensure there are no dimension gaps in op_axes, and find op_ndim */ + op_ndim = ndim; + if (op_axes != NULL) { + for (i = 0; i < ndim; ++i) { + if (strides[i] == NPY_MAX_INTP) { + if (op_ndim == ndim) { + op_ndim = i; + } + } + /* + * If there's a gap in the array's dimensions, it's an error. + * For example, op_axes of [0,2] for the automatically + * allocated output. + */ + else if (op_ndim != ndim) { + PyErr_SetString(PyExc_ValueError, + "automatically allocated output array " + "specified with an inconsistent axis mapping"); + return NULL; + } + } + } + } + else { + for (i = 0; i < op_ndim; ++i) { + if (strides[i] == NPY_MAX_INTP) { + npy_intp factor, new_strides[NPY_MAXDIMS], + itemsize; + + /* Fill in the missing strides in C order */ + factor = 1; + itemsize = op_dtype->elsize; + for (i = op_ndim-1; i >= 0; --i) { + if (strides[i] == NPY_MAX_INTP) { + new_strides[i] = factor * itemsize; + factor *= shape[i]; + } + } + + /* + * Copy the missing strides, and multiply the existing strides + * by the calculated factor. This way, the missing strides + * are tighter together in memory, which is good for nested + * loops. + */ + for (i = 0; i < op_ndim; ++i) { + if (strides[i] == NPY_MAX_INTP) { + strides[i] = new_strides[i]; + } + else { + strides[i] *= factor; + } + } + + break; + } + } + } + + /* If shape was NULL, set it to the shape we calculated */ + if (shape == NULL) { + shape = new_shape; + } + + /* Allocate the temporary array */ + Py_INCREF(op_dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(subtype, op_dtype, op_ndim, + shape, strides, NULL, 0, NULL); + if (ret == NULL) { + return NULL; + } + + /* Make sure all the flags are good */ + PyArray_UpdateFlags(ret, NPY_ARRAY_UPDATE_ALL); + + /* Double-check that the subtype didn't mess with the dimensions */ + if (subtype != &PyArray_Type) { + if (PyArray_NDIM(ret) != op_ndim || + !PyArray_CompareLists(shape, PyArray_DIMS(ret), op_ndim)) { + PyErr_SetString(PyExc_RuntimeError, + "Iterator automatic output has an array subtype " + "which changed the dimensions of the output"); + Py_DECREF(ret); + return NULL; + } + } + + return ret; +} + +static int +npyiter_allocate_arrays(NpyIter *iter, + npy_uint32 flags, + PyArray_Descr **op_dtype, PyTypeObject *subtype, + npy_uint32 *op_flags, npyiter_opitflags *op_itflags, + int **op_axes) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int idim, ndim = NIT_NDIM(iter); + int iop, nop = NIT_NOP(iter); + + int check_writemasked_reductions = 0; + + NpyIter_BufferData *bufferdata = NULL; + PyArrayObject **op = NIT_OPERANDS(iter); + + if (itflags & NPY_ITFLAG_BUFFER) { + bufferdata = NIT_BUFFERDATA(iter); + } + + if (flags & NPY_ITER_COPY_IF_OVERLAP) { + /* + * Perform operand memory overlap checks, if requested. + * + * If any write operand has memory overlap with any read operand, + * eliminate all overlap by making temporary copies, by enabling + * NPY_OP_ITFLAG_FORCECOPY for the write operand to force UPDATEIFCOPY. + * + * Operands with NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE enabled are not + * considered overlapping if the arrays are exactly the same. In this + * case, the iterator loops through them in the same order element by + * element. (As usual, the user-provided inner loop is assumed to be + * able to deal with this level of simple aliasing.) + */ + for (iop = 0; iop < nop; ++iop) { + int may_share_memory = 0; + int iother; + + if (op[iop] == NULL) { + /* Iterator will always allocate */ + continue; + } + + if (!(op_itflags[iop] & NPY_OP_ITFLAG_WRITE)) { + /* + * Copy output operands only, not inputs. + * A more sophisticated heuristic could be + * substituted here later. + */ + continue; + } + + for (iother = 0; iother < nop; ++iother) { + if (iother == iop || op[iother] == NULL) { + continue; + } + + if (!(op_itflags[iother] & NPY_OP_ITFLAG_READ)) { + /* No data dependence for arrays not read from */ + continue; + } + + if (op_itflags[iother] & NPY_OP_ITFLAG_FORCECOPY) { + /* Already copied */ + continue; + } + + /* + * If the arrays are views to exactly the same data, no need + * to make copies, if the caller (eg ufunc) says it accesses + * data only in the iterator order. + * + * However, if there is internal overlap (e.g. a zero stride on + * a non-unit dimension), a copy cannot be avoided. + */ + if ((op_flags[iop] & NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE) && + (op_flags[iother] & NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE) && + PyArray_BYTES(op[iop]) == PyArray_BYTES(op[iother]) && + PyArray_NDIM(op[iop]) == PyArray_NDIM(op[iother]) && + PyArray_CompareLists(PyArray_DIMS(op[iop]), + PyArray_DIMS(op[iother]), + PyArray_NDIM(op[iop])) && + PyArray_CompareLists(PyArray_STRIDES(op[iop]), + PyArray_STRIDES(op[iother]), + PyArray_NDIM(op[iop])) && + PyArray_DESCR(op[iop]) == PyArray_DESCR(op[iother]) && + solve_may_have_internal_overlap(op[iop], 1) == 0) { + + continue; + } + + /* + * Use max work = 1. If the arrays are large, it might + * make sense to go further. + */ + may_share_memory = solve_may_share_memory(op[iop], + op[iother], + 1); + + if (may_share_memory) { + op_itflags[iop] |= NPY_OP_ITFLAG_FORCECOPY; + break; + } + } + } + } + + for (iop = 0; iop < nop; ++iop) { + /* + * Check whether there are any WRITEMASKED REDUCE operands + * which should be validated after all the strides are filled + * in. + */ + if ((op_itflags[iop] & + (NPY_OP_ITFLAG_WRITEMASKED | NPY_OP_ITFLAG_REDUCE)) == + (NPY_OP_ITFLAG_WRITEMASKED | NPY_OP_ITFLAG_REDUCE)) { + check_writemasked_reductions = 1; + } + + /* NULL means an output the iterator should allocate */ + if (op[iop] == NULL) { + PyArrayObject *out; + PyTypeObject *op_subtype; + int ondim = ndim; + + /* Check whether the subtype was disabled */ + op_subtype = (op_flags[iop] & NPY_ITER_NO_SUBTYPE) ? + &PyArray_Type : subtype; + + /* Allocate the output array */ + out = npyiter_new_temp_array(iter, op_subtype, + flags, &op_itflags[iop], + ondim, + NULL, + op_dtype[iop], + op_axes ? op_axes[iop] : NULL); + if (out == NULL) { + return 0; + } + + op[iop] = out; + + /* + * Now we need to replace the pointers and strides with values + * from the new array. + */ + npyiter_replace_axisdata(iter, iop, op[iop], ondim, + PyArray_DATA(op[iop]), op_axes ? op_axes[iop] : NULL); + + /* New arrays are aligned and need no cast */ + op_itflags[iop] |= NPY_OP_ITFLAG_ALIGNED; + op_itflags[iop] &= ~NPY_OP_ITFLAG_CAST; + } + /* + * If casting is required, the operand is read-only, and + * it's an array scalar, make a copy whether or not the + * copy flag is enabled. + */ + else if ((op_itflags[iop] & (NPY_OP_ITFLAG_CAST | + NPY_OP_ITFLAG_READ | + NPY_OP_ITFLAG_WRITE)) == (NPY_OP_ITFLAG_CAST | + NPY_OP_ITFLAG_READ) && + PyArray_NDIM(op[iop]) == 0) { + PyArrayObject *temp; + Py_INCREF(op_dtype[iop]); + temp = (PyArrayObject *)PyArray_NewFromDescr( + &PyArray_Type, op_dtype[iop], + 0, NULL, NULL, NULL, 0, NULL); + if (temp == NULL) { + return 0; + } + if (PyArray_CopyInto(temp, op[iop]) != 0) { + Py_DECREF(temp); + return 0; + } + Py_DECREF(op[iop]); + op[iop] = temp; + + /* + * Now we need to replace the pointers and strides with values + * from the temporary array. + */ + npyiter_replace_axisdata(iter, iop, op[iop], 0, + PyArray_DATA(op[iop]), NULL); + + /* + * New arrays are aligned need no cast, and in the case + * of scalars, always have stride 0 so never need buffering + */ + op_itflags[iop] |= (NPY_OP_ITFLAG_ALIGNED | + NPY_OP_ITFLAG_BUFNEVER); + op_itflags[iop] &= ~NPY_OP_ITFLAG_CAST; + if (itflags & NPY_ITFLAG_BUFFER) { + NBF_STRIDES(bufferdata)[iop] = 0; + } + } + /* + * Make a temporary copy if, + * 1. If casting is required and permitted, or, + * 2. If force-copy is requested + */ + else if (((op_itflags[iop] & NPY_OP_ITFLAG_CAST) && + (op_flags[iop] & + (NPY_ITER_COPY|NPY_ITER_UPDATEIFCOPY))) || + (op_itflags[iop] & NPY_OP_ITFLAG_FORCECOPY)) { + PyArrayObject *temp; + int ondim = PyArray_NDIM(op[iop]); + + /* Allocate the temporary array, if possible */ + temp = npyiter_new_temp_array(iter, &PyArray_Type, + flags, &op_itflags[iop], + ondim, + PyArray_DIMS(op[iop]), + op_dtype[iop], + op_axes ? op_axes[iop] : NULL); + if (temp == NULL) { + return 0; + } + + /* + * If the data will be read, copy it into temp. + * TODO: It might be possible to do a view into + * op[iop]'s mask instead here. + */ + if (op_itflags[iop] & NPY_OP_ITFLAG_READ) { + if (PyArray_CopyInto(temp, op[iop]) != 0) { + Py_DECREF(temp); + return 0; + } + } + /* If the data will be written to, set UPDATEIFCOPY */ + if (op_itflags[iop] & NPY_OP_ITFLAG_WRITE) { + Py_INCREF(op[iop]); + if (PyArray_SetUpdateIfCopyBase(temp, op[iop]) < 0) { + Py_DECREF(temp); + return 0; + } + } + + Py_DECREF(op[iop]); + op[iop] = temp; + + /* + * Now we need to replace the pointers and strides with values + * from the temporary array. + */ + npyiter_replace_axisdata(iter, iop, op[iop], ondim, + PyArray_DATA(op[iop]), op_axes ? op_axes[iop] : NULL); + + /* The temporary copy is aligned and needs no cast */ + op_itflags[iop] |= NPY_OP_ITFLAG_ALIGNED; + op_itflags[iop] &= ~NPY_OP_ITFLAG_CAST; + } + else { + /* + * Buffering must be enabled for casting/conversion if copy + * wasn't specified. + */ + if ((op_itflags[iop] & NPY_OP_ITFLAG_CAST) && + !(itflags & NPY_ITFLAG_BUFFER)) { + PyErr_SetString(PyExc_TypeError, + "Iterator operand required copying or buffering, " + "but neither copying nor buffering was enabled"); + return 0; + } + + /* + * If the operand is aligned, any buffering can use aligned + * optimizations. + */ + if (PyArray_ISALIGNED(op[iop])) { + op_itflags[iop] |= NPY_OP_ITFLAG_ALIGNED; + } + } + + /* Here we can finally check for contiguous iteration */ + if (op_flags[iop] & NPY_ITER_CONTIG) { + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + npy_intp stride = NAD_STRIDES(axisdata)[iop]; + + if (stride != op_dtype[iop]->elsize) { + NPY_IT_DBG_PRINT("Iterator: Setting NPY_OP_ITFLAG_CAST " + "because of NPY_ITER_CONTIG\n"); + op_itflags[iop] |= NPY_OP_ITFLAG_CAST; + if (!(itflags & NPY_ITFLAG_BUFFER)) { + PyErr_SetString(PyExc_TypeError, + "Iterator operand required buffering, " + "to be contiguous as requested, but " + "buffering is not enabled"); + return 0; + } + } + } + + /* + * If no alignment, byte swap, or casting is needed, + * the inner stride of this operand works for the whole + * array, we can set NPY_OP_ITFLAG_BUFNEVER. + */ + if ((itflags & NPY_ITFLAG_BUFFER) && + !(op_itflags[iop] & NPY_OP_ITFLAG_CAST)) { + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + if (ndim <= 1) { + op_itflags[iop] |= NPY_OP_ITFLAG_BUFNEVER; + NBF_STRIDES(bufferdata)[iop] = NAD_STRIDES(axisdata)[iop]; + } + else if (PyArray_NDIM(op[iop]) > 0) { + npy_intp stride, shape, innerstride = 0, innershape; + npy_intp sizeof_axisdata = + NIT_AXISDATA_SIZEOF(itflags, ndim, nop); + /* Find stride of the first non-empty shape */ + for (idim = 0; idim < ndim; ++idim) { + innershape = NAD_SHAPE(axisdata); + if (innershape != 1) { + innerstride = NAD_STRIDES(axisdata)[iop]; + break; + } + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + ++idim; + NIT_ADVANCE_AXISDATA(axisdata, 1); + /* Check that everything could have coalesced together */ + for (; idim < ndim; ++idim) { + stride = NAD_STRIDES(axisdata)[iop]; + shape = NAD_SHAPE(axisdata); + if (shape != 1) { + /* + * If N times the inner stride doesn't equal this + * stride, the multi-dimensionality is needed. + */ + if (innerstride*innershape != stride) { + break; + } + else { + innershape *= shape; + } + } + NIT_ADVANCE_AXISDATA(axisdata, 1); + } + /* + * If we looped all the way to the end, one stride works. + * Set that stride, because it may not belong to the first + * dimension. + */ + if (idim == ndim) { + op_itflags[iop] |= NPY_OP_ITFLAG_BUFNEVER; + NBF_STRIDES(bufferdata)[iop] = innerstride; + } + } + } + } + + if (check_writemasked_reductions) { + for (iop = 0; iop < nop; ++iop) { + /* + * Check whether there are any WRITEMASKED REDUCE operands + * which should be validated now that all the strides are filled + * in. + */ + if ((op_itflags[iop] & + (NPY_OP_ITFLAG_WRITEMASKED | NPY_OP_ITFLAG_REDUCE)) == + (NPY_OP_ITFLAG_WRITEMASKED | NPY_OP_ITFLAG_REDUCE)) { + /* + * If the ARRAYMASK has 'bigger' dimensions + * than this REDUCE WRITEMASKED operand, + * the result would be more than one mask + * value per reduction element, something which + * is invalid. This function provides validation + * for that. + */ + if (!check_mask_for_writemasked_reduction(iter, iop)) { + return 0; + } + } + } + } + + return 1; +} + +/* + * The __array_priority__ attribute of the inputs determines + * the subtype of any output arrays. This function finds the + * subtype of the input array with highest priority. + */ +static void +npyiter_get_priority_subtype(int nop, PyArrayObject **op, + npyiter_opitflags *op_itflags, + double *subtype_priority, + PyTypeObject **subtype) +{ + int iop; + + for (iop = 0; iop < nop; ++iop) { + if (op[iop] != NULL && op_itflags[iop] & NPY_OP_ITFLAG_READ) { + double priority = PyArray_GetPriority((PyObject *)op[iop], 0.0); + if (priority > *subtype_priority) { + *subtype_priority = priority; + *subtype = Py_TYPE(op[iop]); + } + } + } +} + +static int +npyiter_allocate_transfer_functions(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int iop = 0, nop = NIT_NOP(iter); + + npy_intp i; + npyiter_opitflags *op_itflags = NIT_OPITFLAGS(iter); + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + NpyIter_AxisData *axisdata = NIT_AXISDATA(iter); + PyArrayObject **op = NIT_OPERANDS(iter); + PyArray_Descr **op_dtype = NIT_DTYPES(iter); + npy_intp *strides = NAD_STRIDES(axisdata), op_stride; + PyArray_StridedUnaryOp **readtransferfn = NBF_READTRANSFERFN(bufferdata), + **writetransferfn = NBF_WRITETRANSFERFN(bufferdata); + NpyAuxData **readtransferdata = NBF_READTRANSFERDATA(bufferdata), + **writetransferdata = NBF_WRITETRANSFERDATA(bufferdata); + + PyArray_StridedUnaryOp *stransfer = NULL; + NpyAuxData *transferdata = NULL; + int needs_api = 0; + + for (iop = 0; iop < nop; ++iop) { + npyiter_opitflags flags = op_itflags[iop]; + /* + * Reduction operands may be buffered with a different stride, + * so we must pass NPY_MAX_INTP to the transfer function factory. + */ + op_stride = (flags & NPY_OP_ITFLAG_REDUCE) ? NPY_MAX_INTP : + strides[iop]; + + /* + * If we have determined that a buffer may be needed, + * allocate the appropriate transfer functions + */ + if (!(flags & NPY_OP_ITFLAG_BUFNEVER)) { + if (flags & NPY_OP_ITFLAG_READ) { + int move_references = 0; + if (PyArray_GetDTypeTransferFunction( + (flags & NPY_OP_ITFLAG_ALIGNED) != 0, + op_stride, + op_dtype[iop]->elsize, + PyArray_DESCR(op[iop]), + op_dtype[iop], + move_references, + &stransfer, + &transferdata, + &needs_api) != NPY_SUCCEED) { + goto fail; + } + readtransferfn[iop] = stransfer; + readtransferdata[iop] = transferdata; + } + else { + readtransferfn[iop] = NULL; + } + if (flags & NPY_OP_ITFLAG_WRITE) { + int move_references = 1; + + /* If the operand is WRITEMASKED, use a masked transfer fn */ + if (flags & NPY_OP_ITFLAG_WRITEMASKED) { + int maskop = NIT_MASKOP(iter); + PyArray_Descr *mask_dtype = PyArray_DESCR(op[maskop]); + + /* + * If the mask's stride is contiguous, use it, otherwise + * the mask may or may not be buffered, so the stride + * could be inconsistent. + */ + if (PyArray_GetMaskedDTypeTransferFunction( + (flags & NPY_OP_ITFLAG_ALIGNED) != 0, + op_dtype[iop]->elsize, + op_stride, + (strides[maskop] == mask_dtype->elsize) ? + mask_dtype->elsize : + NPY_MAX_INTP, + op_dtype[iop], + PyArray_DESCR(op[iop]), + mask_dtype, + move_references, + (PyArray_MaskedStridedUnaryOp **)&stransfer, + &transferdata, + &needs_api) != NPY_SUCCEED) { + goto fail; + } + } + else { + if (PyArray_GetDTypeTransferFunction( + (flags & NPY_OP_ITFLAG_ALIGNED) != 0, + op_dtype[iop]->elsize, + op_stride, + op_dtype[iop], + PyArray_DESCR(op[iop]), + move_references, + &stransfer, + &transferdata, + &needs_api) != NPY_SUCCEED) { + goto fail; + } + } + writetransferfn[iop] = stransfer; + writetransferdata[iop] = transferdata; + } + /* If no write back but there are references make a decref fn */ + else if (PyDataType_REFCHK(op_dtype[iop])) { + /* + * By passing NULL to dst_type and setting move_references + * to 1, we get back a function that just decrements the + * src references. + */ + if (PyArray_GetDTypeTransferFunction( + (flags & NPY_OP_ITFLAG_ALIGNED) != 0, + op_dtype[iop]->elsize, 0, + op_dtype[iop], NULL, + 1, + &stransfer, + &transferdata, + &needs_api) != NPY_SUCCEED) { + goto fail; + } + writetransferfn[iop] = stransfer; + writetransferdata[iop] = transferdata; + } + else { + writetransferfn[iop] = NULL; + } + } + else { + readtransferfn[iop] = NULL; + writetransferfn[iop] = NULL; + } + } + + /* If any of the dtype transfer functions needed the API, flag it */ + if (needs_api) { + NIT_ITFLAGS(iter) |= NPY_ITFLAG_NEEDSAPI; + } + + return 1; + +fail: + for (i = 0; i < iop; ++i) { + if (readtransferdata[iop] != NULL) { + NPY_AUXDATA_FREE(readtransferdata[iop]); + readtransferdata[iop] = NULL; + } + if (writetransferdata[iop] != NULL) { + NPY_AUXDATA_FREE(writetransferdata[iop]); + writetransferdata[iop] = NULL; + } + } + return 0; +} + +#undef NPY_ITERATOR_IMPLEMENTATION_CODE diff --git a/numpy/core/src/multiarray/nditer_impl.h b/numpy/core/src/multiarray/nditer_impl.h new file mode 100644 index 0000000..7788d32 --- /dev/null +++ b/numpy/core/src/multiarray/nditer_impl.h @@ -0,0 +1,314 @@ +/* + * This is a PRIVATE INTERNAL NumPy header, intended to be used *ONLY* + * by the iterator implementation code. All other internal NumPy code + * should use the exposed iterator API. + */ +#ifndef NPY_ITERATOR_IMPLEMENTATION_CODE +#error "This header is intended for use ONLY by iterator implementation code." +#endif + +#ifndef _NPY_PRIVATE__NDITER_IMPL_H_ +#define _NPY_PRIVATE__NDITER_IMPL_H_ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include +#include +#include "convert_datatype.h" + +#include "lowlevel_strided_loops.h" + +/********** ITERATOR CONSTRUCTION TIMING **************/ +#define NPY_IT_CONSTRUCTION_TIMING 0 + +#if NPY_IT_CONSTRUCTION_TIMING +#define NPY_IT_TIME_POINT(var) { \ + unsigned int hi, lo; \ + __asm__ __volatile__ ( \ + "rdtsc" \ + : "=d" (hi), "=a" (lo)); \ + var = (((unsigned long long)hi) << 32) | lo; \ + } +#define NPY_IT_PRINT_TIME_START(var) { \ + printf("%30s: start\n", #var); \ + c_temp = var; \ + } +#define NPY_IT_PRINT_TIME_VAR(var) { \ + printf("%30s: %6.0f clocks\n", #var, \ + ((double)(var-c_temp))); \ + c_temp = var; \ + } +#else +#define NPY_IT_TIME_POINT(var) +#endif + +/******************************************************/ + +/********** PRINTF DEBUG TRACING **************/ +#define NPY_IT_DBG_TRACING 0 + +#if NPY_IT_DBG_TRACING +#define NPY_IT_DBG_PRINT(s) printf("%s", s) +#define NPY_IT_DBG_PRINT1(s, p1) printf(s, p1) +#define NPY_IT_DBG_PRINT2(s, p1, p2) printf(s, p1, p2) +#define NPY_IT_DBG_PRINT3(s, p1, p2, p3) printf(s, p1, p2, p3) +#else +#define NPY_IT_DBG_PRINT(s) +#define NPY_IT_DBG_PRINT1(s, p1) +#define NPY_IT_DBG_PRINT2(s, p1, p2) +#define NPY_IT_DBG_PRINT3(s, p1, p2, p3) +#endif +/**********************************************/ + +/* Rounds up a number of bytes to be divisible by sizeof intp */ +#if NPY_SIZEOF_INTP == 4 +#define NPY_INTP_ALIGNED(size) ((size + 0x3)&(-0x4)) +#else +#define NPY_INTP_ALIGNED(size) ((size + 0x7)&(-0x8)) +#endif + +/* Internal iterator flags */ + +/* The perm is the identity */ +#define NPY_ITFLAG_IDENTPERM 0x0001 +/* The perm has negative entries (indicating flipped axes) */ +#define NPY_ITFLAG_NEGPERM 0x0002 +/* The iterator is tracking an index */ +#define NPY_ITFLAG_HASINDEX 0x0004 +/* The iterator is tracking a multi-index */ +#define NPY_ITFLAG_HASMULTIINDEX 0x0008 +/* The iteration order was forced on construction */ +#define NPY_ITFLAG_FORCEDORDER 0x0010 +/* The inner loop is handled outside the iterator */ +#define NPY_ITFLAG_EXLOOP 0x0020 +/* The iterator is ranged */ +#define NPY_ITFLAG_RANGE 0x0040 +/* The iterator is buffered */ +#define NPY_ITFLAG_BUFFER 0x0080 +/* The iterator should grow the buffered inner loop when possible */ +#define NPY_ITFLAG_GROWINNER 0x0100 +/* There is just one iteration, can specialize iternext for that */ +#define NPY_ITFLAG_ONEITERATION 0x0200 +/* Delay buffer allocation until first Reset* call */ +#define NPY_ITFLAG_DELAYBUF 0x0400 +/* Iteration needs API access during iternext */ +#define NPY_ITFLAG_NEEDSAPI 0x0800 +/* Iteration includes one or more operands being reduced */ +#define NPY_ITFLAG_REDUCE 0x1000 +/* Reduce iteration doesn't need to recalculate reduce loops next time */ +#define NPY_ITFLAG_REUSE_REDUCE_LOOPS 0x2000 + +/* Internal iterator per-operand iterator flags */ + +/* The operand will be written to */ +#define NPY_OP_ITFLAG_WRITE 0x0001 +/* The operand will be read from */ +#define NPY_OP_ITFLAG_READ 0x0002 +/* The operand needs type conversion/byte swapping/alignment */ +#define NPY_OP_ITFLAG_CAST 0x0004 +/* The operand never needs buffering */ +#define NPY_OP_ITFLAG_BUFNEVER 0x0008 +/* The operand is aligned */ +#define NPY_OP_ITFLAG_ALIGNED 0x0010 +/* The operand is being reduced */ +#define NPY_OP_ITFLAG_REDUCE 0x0020 +/* The operand is for temporary use, does not have a backing array */ +#define NPY_OP_ITFLAG_VIRTUAL 0x0040 +/* The operand requires masking when copying buffer -> array */ +#define NPY_OP_ITFLAG_WRITEMASKED 0x0080 +/* The operand's data pointer is pointing into its buffer */ +#define NPY_OP_ITFLAG_USINGBUFFER 0x0100 +/* The operand must be copied (with UPDATEIFCOPY if also ITFLAG_WRITE) */ +#define NPY_OP_ITFLAG_FORCECOPY 0x0200 + +/* + * The data layout of the iterator is fully specified by + * a triple (itflags, ndim, nop). These three variables + * are expected to exist in all functions calling these macros, + * either as true variables initialized to the correct values + * from the iterator, or as constants in the case of specialized + * functions such as the various iternext functions. + */ + +struct NpyIter_InternalOnly { + /* Initial fixed position data */ + npy_uint32 itflags; + npy_uint8 ndim, nop; + npy_int8 maskop; + npy_intp itersize, iterstart, iterend; + /* iterindex is only used if RANGED or BUFFERED is set */ + npy_intp iterindex; + /* The rest is variable */ + char iter_flexdata; +}; + +typedef struct NpyIter_AD NpyIter_AxisData; +typedef struct NpyIter_BD NpyIter_BufferData; + +typedef npy_int16 npyiter_opitflags; + +/* Byte sizes of the iterator members */ +#define NIT_PERM_SIZEOF(itflags, ndim, nop) \ + NPY_INTP_ALIGNED(NPY_MAXDIMS) +#define NIT_DTYPES_SIZEOF(itflags, ndim, nop) \ + ((NPY_SIZEOF_INTP)*(nop)) +#define NIT_RESETDATAPTR_SIZEOF(itflags, ndim, nop) \ + ((NPY_SIZEOF_INTP)*(nop+1)) +#define NIT_BASEOFFSETS_SIZEOF(itflags, ndim, nop) \ + ((NPY_SIZEOF_INTP)*(nop+1)) +#define NIT_OPERANDS_SIZEOF(itflags, ndim, nop) \ + ((NPY_SIZEOF_INTP)*(nop)) +#define NIT_OPITFLAGS_SIZEOF(itflags, ndim, nop) \ + (NPY_INTP_ALIGNED(sizeof(npyiter_opitflags) * nop)) +#define NIT_BUFFERDATA_SIZEOF(itflags, ndim, nop) \ + ((itflags&NPY_ITFLAG_BUFFER) ? ((NPY_SIZEOF_INTP)*(6 + 9*nop)) : 0) + +/* Byte offsets of the iterator members starting from iter->iter_flexdata */ +#define NIT_PERM_OFFSET() \ + (0) +#define NIT_DTYPES_OFFSET(itflags, ndim, nop) \ + (NIT_PERM_OFFSET() + \ + NIT_PERM_SIZEOF(itflags, ndim, nop)) +#define NIT_RESETDATAPTR_OFFSET(itflags, ndim, nop) \ + (NIT_DTYPES_OFFSET(itflags, ndim, nop) + \ + NIT_DTYPES_SIZEOF(itflags, ndim, nop)) +#define NIT_BASEOFFSETS_OFFSET(itflags, ndim, nop) \ + (NIT_RESETDATAPTR_OFFSET(itflags, ndim, nop) + \ + NIT_RESETDATAPTR_SIZEOF(itflags, ndim, nop)) +#define NIT_OPERANDS_OFFSET(itflags, ndim, nop) \ + (NIT_BASEOFFSETS_OFFSET(itflags, ndim, nop) + \ + NIT_BASEOFFSETS_SIZEOF(itflags, ndim, nop)) +#define NIT_OPITFLAGS_OFFSET(itflags, ndim, nop) \ + (NIT_OPERANDS_OFFSET(itflags, ndim, nop) + \ + NIT_OPERANDS_SIZEOF(itflags, ndim, nop)) +#define NIT_BUFFERDATA_OFFSET(itflags, ndim, nop) \ + (NIT_OPITFLAGS_OFFSET(itflags, ndim, nop) + \ + NIT_OPITFLAGS_SIZEOF(itflags, ndim, nop)) +#define NIT_AXISDATA_OFFSET(itflags, ndim, nop) \ + (NIT_BUFFERDATA_OFFSET(itflags, ndim, nop) + \ + NIT_BUFFERDATA_SIZEOF(itflags, ndim, nop)) + +/* Internal-only ITERATOR DATA MEMBER ACCESS */ +#define NIT_ITFLAGS(iter) \ + ((iter)->itflags) +#define NIT_NDIM(iter) \ + ((iter)->ndim) +#define NIT_NOP(iter) \ + ((iter)->nop) +#define NIT_MASKOP(iter) \ + ((iter)->maskop) +#define NIT_ITERSIZE(iter) \ + (iter->itersize) +#define NIT_ITERSTART(iter) \ + (iter->iterstart) +#define NIT_ITEREND(iter) \ + (iter->iterend) +#define NIT_ITERINDEX(iter) \ + (iter->iterindex) +#define NIT_PERM(iter) ((npy_int8 *)( \ + &(iter)->iter_flexdata + NIT_PERM_OFFSET())) +#define NIT_DTYPES(iter) ((PyArray_Descr **)( \ + &(iter)->iter_flexdata + NIT_DTYPES_OFFSET(itflags, ndim, nop))) +#define NIT_RESETDATAPTR(iter) ((char **)( \ + &(iter)->iter_flexdata + NIT_RESETDATAPTR_OFFSET(itflags, ndim, nop))) +#define NIT_BASEOFFSETS(iter) ((npy_intp *)( \ + &(iter)->iter_flexdata + NIT_BASEOFFSETS_OFFSET(itflags, ndim, nop))) +#define NIT_OPERANDS(iter) ((PyArrayObject **)( \ + &(iter)->iter_flexdata + NIT_OPERANDS_OFFSET(itflags, ndim, nop))) +#define NIT_OPITFLAGS(iter) ((npyiter_opitflags *)( \ + &(iter)->iter_flexdata + NIT_OPITFLAGS_OFFSET(itflags, ndim, nop))) +#define NIT_BUFFERDATA(iter) ((NpyIter_BufferData *)( \ + &(iter)->iter_flexdata + NIT_BUFFERDATA_OFFSET(itflags, ndim, nop))) +#define NIT_AXISDATA(iter) ((NpyIter_AxisData *)( \ + &(iter)->iter_flexdata + NIT_AXISDATA_OFFSET(itflags, ndim, nop))) + +/* Internal-only BUFFERDATA MEMBER ACCESS */ +struct NpyIter_BD { + npy_intp buffersize, size, bufiterend, + reduce_pos, reduce_outersize, reduce_outerdim; + npy_intp bd_flexdata; +}; +#define NBF_BUFFERSIZE(bufferdata) ((bufferdata)->buffersize) +#define NBF_SIZE(bufferdata) ((bufferdata)->size) +#define NBF_BUFITEREND(bufferdata) ((bufferdata)->bufiterend) +#define NBF_REDUCE_POS(bufferdata) ((bufferdata)->reduce_pos) +#define NBF_REDUCE_OUTERSIZE(bufferdata) ((bufferdata)->reduce_outersize) +#define NBF_REDUCE_OUTERDIM(bufferdata) ((bufferdata)->reduce_outerdim) +#define NBF_STRIDES(bufferdata) ( \ + &(bufferdata)->bd_flexdata + 0) +#define NBF_PTRS(bufferdata) ((char **) \ + (&(bufferdata)->bd_flexdata + 1*(nop))) +#define NBF_REDUCE_OUTERSTRIDES(bufferdata) ( \ + (&(bufferdata)->bd_flexdata + 2*(nop))) +#define NBF_REDUCE_OUTERPTRS(bufferdata) ((char **) \ + (&(bufferdata)->bd_flexdata + 3*(nop))) +#define NBF_READTRANSFERFN(bufferdata) ((PyArray_StridedUnaryOp **) \ + (&(bufferdata)->bd_flexdata + 4*(nop))) +#define NBF_READTRANSFERDATA(bufferdata) ((NpyAuxData **) \ + (&(bufferdata)->bd_flexdata + 5*(nop))) +#define NBF_WRITETRANSFERFN(bufferdata) ((PyArray_StridedUnaryOp **) \ + (&(bufferdata)->bd_flexdata + 6*(nop))) +#define NBF_WRITETRANSFERDATA(bufferdata) ((NpyAuxData **) \ + (&(bufferdata)->bd_flexdata + 7*(nop))) +#define NBF_BUFFERS(bufferdata) ((char **) \ + (&(bufferdata)->bd_flexdata + 8*(nop))) + +/* Internal-only AXISDATA MEMBER ACCESS. */ +struct NpyIter_AD { + npy_intp shape, index; + npy_intp ad_flexdata; +}; +#define NAD_SHAPE(axisdata) ((axisdata)->shape) +#define NAD_INDEX(axisdata) ((axisdata)->index) +#define NAD_STRIDES(axisdata) ( \ + &(axisdata)->ad_flexdata + 0) +#define NAD_PTRS(axisdata) ((char **) \ + &(axisdata)->ad_flexdata + 1*(nop+1)) + +#define NAD_NSTRIDES() \ + ((nop) + ((itflags&NPY_ITFLAG_HASINDEX) ? 1 : 0)) + +/* Size of one AXISDATA struct within the iterator */ +#define NIT_AXISDATA_SIZEOF(itflags, ndim, nop) (( \ + /* intp shape */ \ + 1 + \ + /* intp index */ \ + 1 + \ + /* intp stride[nop+1] AND char* ptr[nop+1] */ \ + 2*((nop)+1) \ + )*NPY_SIZEOF_INTP ) + +/* + * Macro to advance an AXISDATA pointer by a specified count. + * Requires that sizeof_axisdata be previously initialized + * to NIT_AXISDATA_SIZEOF(itflags, ndim, nop). + */ +#define NIT_INDEX_AXISDATA(axisdata, index) ((NpyIter_AxisData *) \ + (((char *)(axisdata)) + (index)*sizeof_axisdata)) +#define NIT_ADVANCE_AXISDATA(axisdata, count) \ + axisdata = NIT_INDEX_AXISDATA(axisdata, count) + +/* Size of the whole iterator */ +#define NIT_SIZEOF_ITERATOR(itflags, ndim, nop) ( \ + sizeof(struct NpyIter_InternalOnly) + \ + NIT_AXISDATA_OFFSET(itflags, ndim, nop) + \ + NIT_AXISDATA_SIZEOF(itflags, ndim, nop)*(ndim ? ndim : 1)) + +/* Internal helper functions shared between implementation files */ +NPY_NO_EXPORT void +npyiter_coalesce_axes(NpyIter *iter); +NPY_NO_EXPORT int +npyiter_allocate_buffers(NpyIter *iter, char **errmsg); +NPY_NO_EXPORT void +npyiter_goto_iterindex(NpyIter *iter, npy_intp iterindex); +NPY_NO_EXPORT void +npyiter_copy_from_buffers(NpyIter *iter); +NPY_NO_EXPORT void +npyiter_copy_to_buffers(NpyIter *iter, char **prev_dataptrs); + + +#endif diff --git a/numpy/core/src/multiarray/nditer_pywrap.c b/numpy/core/src/multiarray/nditer_pywrap.c new file mode 100644 index 0000000..0d31817 --- /dev/null +++ b/numpy/core/src/multiarray/nditer_pywrap.c @@ -0,0 +1,2503 @@ +/* + * This file implements the CPython wrapper of the new NumPy iterator. + * + * Copyright (c) 2010 by Mark Wiebe (mwwiebe@gmail.com) + * The University of British Columbia + * + * See LICENSE.txt for the license. + */ +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include +#include "npy_config.h" +#include "npy_pycompat.h" +#include "alloc.h" +#include "common.h" + +typedef struct NewNpyArrayIterObject_tag NewNpyArrayIterObject; + +struct NewNpyArrayIterObject_tag { + PyObject_HEAD + /* The iterator */ + NpyIter *iter; + /* Flag indicating iteration started/stopped */ + char started, finished; + /* Child to update for nested iteration */ + NewNpyArrayIterObject *nested_child; + /* Cached values from the iterator */ + NpyIter_IterNextFunc *iternext; + NpyIter_GetMultiIndexFunc *get_multi_index; + char **dataptrs; + PyArray_Descr **dtypes; + PyArrayObject **operands; + npy_intp *innerstrides, *innerloopsizeptr; + char readflags[NPY_MAXARGS]; + char writeflags[NPY_MAXARGS]; +}; + +static int npyiter_cache_values(NewNpyArrayIterObject *self) +{ + NpyIter *iter = self->iter; + + /* iternext and get_multi_index functions */ + self->iternext = NpyIter_GetIterNext(iter, NULL); + if (self->iternext == NULL) { + return -1; + } + + if (NpyIter_HasMultiIndex(iter) && !NpyIter_HasDelayedBufAlloc(iter)) { + self->get_multi_index = NpyIter_GetGetMultiIndex(iter, NULL); + } + else { + self->get_multi_index = NULL; + } + + /* Internal data pointers */ + self->dataptrs = NpyIter_GetDataPtrArray(iter); + self->dtypes = NpyIter_GetDescrArray(iter); + self->operands = NpyIter_GetOperandArray(iter); + + if (NpyIter_HasExternalLoop(iter)) { + self->innerstrides = NpyIter_GetInnerStrideArray(iter); + self->innerloopsizeptr = NpyIter_GetInnerLoopSizePtr(iter); + } + else { + self->innerstrides = NULL; + self->innerloopsizeptr = NULL; + } + + /* The read/write settings */ + NpyIter_GetReadFlags(iter, self->readflags); + NpyIter_GetWriteFlags(iter, self->writeflags); + return 0; +} + +static PyObject * +npyiter_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) +{ + NewNpyArrayIterObject *self; + + self = (NewNpyArrayIterObject *)subtype->tp_alloc(subtype, 0); + if (self != NULL) { + self->iter = NULL; + self->nested_child = NULL; + } + + return (PyObject *)self; +} + +static int +NpyIter_GlobalFlagsConverter(PyObject *flags_in, npy_uint32 *flags) +{ + npy_uint32 tmpflags = 0; + int iflags, nflags; + + PyObject *f; + char *str = NULL; + Py_ssize_t length = 0; + npy_uint32 flag; + + if (flags_in == NULL || flags_in == Py_None) { + return 1; + } + + if (!PyTuple_Check(flags_in) && !PyList_Check(flags_in)) { + PyErr_SetString(PyExc_ValueError, + "Iterator global flags must be a list or tuple of strings"); + return 0; + } + + nflags = PySequence_Size(flags_in); + + for (iflags = 0; iflags < nflags; ++iflags) { + f = PySequence_GetItem(flags_in, iflags); + if (f == NULL) { + return 0; + } + + if (PyUnicode_Check(f)) { + /* accept unicode input */ + PyObject *f_str; + f_str = PyUnicode_AsASCIIString(f); + if (f_str == NULL) { + Py_DECREF(f); + return 0; + } + Py_DECREF(f); + f = f_str; + } + + if (PyBytes_AsStringAndSize(f, &str, &length) < 0) { + Py_DECREF(f); + return 0; + } + /* Use switch statements to quickly isolate the right flag */ + flag = 0; + switch (str[0]) { + case 'b': + if (strcmp(str, "buffered") == 0) { + flag = NPY_ITER_BUFFERED; + } + break; + case 'c': + if (length >= 6) switch (str[5]) { + case 'e': + if (strcmp(str, "c_index") == 0) { + flag = NPY_ITER_C_INDEX; + } + break; + case 'i': + if (strcmp(str, "copy_if_overlap") == 0) { + flag = NPY_ITER_COPY_IF_OVERLAP; + } + break; + case 'n': + if (strcmp(str, "common_dtype") == 0) { + flag = NPY_ITER_COMMON_DTYPE; + } + break; + } + break; + case 'd': + if (strcmp(str, "delay_bufalloc") == 0) { + flag = NPY_ITER_DELAY_BUFALLOC; + } + break; + case 'e': + if (strcmp(str, "external_loop") == 0) { + flag = NPY_ITER_EXTERNAL_LOOP; + } + break; + case 'f': + if (strcmp(str, "f_index") == 0) { + flag = NPY_ITER_F_INDEX; + } + break; + case 'g': + /* + * Documentation is grow_inner, but initial implementation + * was growinner, so allowing for either. + */ + if (strcmp(str, "grow_inner") == 0 || + strcmp(str, "growinner") == 0) { + flag = NPY_ITER_GROWINNER; + } + break; + case 'm': + if (strcmp(str, "multi_index") == 0) { + flag = NPY_ITER_MULTI_INDEX; + } + break; + case 'r': + if (strcmp(str, "ranged") == 0) { + flag = NPY_ITER_RANGED; + } + else if (strcmp(str, "refs_ok") == 0) { + flag = NPY_ITER_REFS_OK; + } + else if (strcmp(str, "reduce_ok") == 0) { + flag = NPY_ITER_REDUCE_OK; + } + break; + case 'z': + if (strcmp(str, "zerosize_ok") == 0) { + flag = NPY_ITER_ZEROSIZE_OK; + } + break; + } + if (flag == 0) { + PyErr_Format(PyExc_ValueError, + "Unexpected iterator global flag \"%s\"", str); + Py_DECREF(f); + return 0; + } + else { + tmpflags |= flag; + } + Py_DECREF(f); + } + + *flags |= tmpflags; + return 1; +} + +/* TODO: Use PyArray_OrderConverter once 'K' is added there */ +static int +npyiter_order_converter(PyObject *order_in, NPY_ORDER *order) +{ + char *str = NULL; + Py_ssize_t length = 0; + + if (PyUnicode_Check(order_in)) { + /* accept unicode input */ + PyObject *str_obj; + int ret; + str_obj = PyUnicode_AsASCIIString(order_in); + if (str_obj == NULL) { + return 0; + } + ret = npyiter_order_converter(str_obj, order); + Py_DECREF(str_obj); + return ret; + } + + if (PyBytes_AsStringAndSize(order_in, &str, &length) < 0) { + return 0; + } + + if (length == 1) switch (str[0]) { + case 'C': + *order = NPY_CORDER; + return 1; + case 'F': + *order = NPY_FORTRANORDER; + return 1; + case 'A': + *order = NPY_ANYORDER; + return 1; + case 'K': + *order = NPY_KEEPORDER; + return 1; + } + + PyErr_SetString(PyExc_ValueError, + "order must be one of 'C', 'F', 'A', or 'K'"); + return 0; +} + +static int +NpyIter_OpFlagsConverter(PyObject *op_flags_in, + npy_uint32 *op_flags) +{ + int iflags, nflags; + npy_uint32 flag; + + if (!PyTuple_Check(op_flags_in) && !PyList_Check(op_flags_in)) { + PyErr_SetString(PyExc_ValueError, + "op_flags must be a tuple or array of per-op flag-tuples"); + return 0; + } + + nflags = PySequence_Size(op_flags_in); + + *op_flags = 0; + for (iflags = 0; iflags < nflags; ++iflags) { + PyObject *f; + char *str = NULL; + Py_ssize_t length = 0; + + f = PySequence_GetItem(op_flags_in, iflags); + if (f == NULL) { + return 0; + } + + if (PyUnicode_Check(f)) { + /* accept unicode input */ + PyObject *f_str; + f_str = PyUnicode_AsASCIIString(f); + if (f_str == NULL) { + Py_DECREF(f); + return 0; + } + Py_DECREF(f); + f = f_str; + } + + if (PyBytes_AsStringAndSize(f, &str, &length) < 0) { + PyErr_Clear(); + Py_DECREF(f); + PyErr_SetString(PyExc_ValueError, + "op_flags must be a tuple or array of per-op flag-tuples"); + return 0; + } + + /* Use switch statements to quickly isolate the right flag */ + flag = 0; + switch (str[0]) { + case 'a': + if (length > 2) switch(str[2]) { + case 'i': + if (strcmp(str, "aligned") == 0) { + flag = NPY_ITER_ALIGNED; + } + break; + case 'l': + if (strcmp(str, "allocate") == 0) { + flag = NPY_ITER_ALLOCATE; + } + break; + case 'r': + if (strcmp(str, "arraymask") == 0) { + flag = NPY_ITER_ARRAYMASK; + } + break; + } + break; + case 'c': + if (strcmp(str, "copy") == 0) { + flag = NPY_ITER_COPY; + } + if (strcmp(str, "contig") == 0) { + flag = NPY_ITER_CONTIG; + } + break; + case 'n': + switch (str[1]) { + case 'b': + if (strcmp(str, "nbo") == 0) { + flag = NPY_ITER_NBO; + } + break; + case 'o': + if (strcmp(str, "no_subtype") == 0) { + flag = NPY_ITER_NO_SUBTYPE; + } + else if (strcmp(str, "no_broadcast") == 0) { + flag = NPY_ITER_NO_BROADCAST; + } + break; + } + break; + case 'o': + if (strcmp(str, "overlap_assume_elementwise") == 0) { + flag = NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE; + } + break; + case 'r': + if (length > 4) switch (str[4]) { + case 'o': + if (strcmp(str, "readonly") == 0) { + flag = NPY_ITER_READONLY; + } + break; + case 'w': + if (strcmp(str, "readwrite") == 0) { + flag = NPY_ITER_READWRITE; + } + break; + } + break; + case 'u': + switch (str[1]) { + case 'p': + if (strcmp(str, "updateifcopy") == 0) { + flag = NPY_ITER_UPDATEIFCOPY; + } + break; + } + break; + case 'v': + if (strcmp(str, "virtual") == 0) { + flag = NPY_ITER_VIRTUAL; + } + break; + case 'w': + if (length > 5) switch (str[5]) { + case 'o': + if (strcmp(str, "writeonly") == 0) { + flag = NPY_ITER_WRITEONLY; + } + break; + case 'm': + if (strcmp(str, "writemasked") == 0) { + flag = NPY_ITER_WRITEMASKED; + } + break; + } + break; + } + if (flag == 0) { + PyErr_Format(PyExc_ValueError, + "Unexpected per-op iterator flag \"%s\"", str); + Py_DECREF(f); + return 0; + } + else { + *op_flags |= flag; + } + Py_DECREF(f); + } + + return 1; +} + +static int +npyiter_convert_op_flags_array(PyObject *op_flags_in, + npy_uint32 *op_flags_array, npy_intp nop) +{ + npy_intp iop; + + if (!PyTuple_Check(op_flags_in) && !PyList_Check(op_flags_in)) { + PyErr_SetString(PyExc_ValueError, + "op_flags must be a tuple or array of per-op flag-tuples"); + return 0; + } + + if (PySequence_Size(op_flags_in) != nop) { + goto try_single_flags; + } + + for (iop = 0; iop < nop; ++iop) { + PyObject *f = PySequence_GetItem(op_flags_in, iop); + if (f == NULL) { + return 0; + } + /* If the first item is a string, try as one set of flags */ + if (iop == 0 && (PyBytes_Check(f) || PyUnicode_Check(f))) { + Py_DECREF(f); + goto try_single_flags; + } + if (NpyIter_OpFlagsConverter(f, + &op_flags_array[iop]) != 1) { + Py_DECREF(f); + return 0; + } + + Py_DECREF(f); + } + + return 1; + +try_single_flags: + if (NpyIter_OpFlagsConverter(op_flags_in, + &op_flags_array[0]) != 1) { + return 0; + } + + for (iop = 1; iop < nop; ++iop) { + op_flags_array[iop] = op_flags_array[0]; + } + + return 1; +} + +static int +npyiter_convert_dtypes(PyObject *op_dtypes_in, + PyArray_Descr **op_dtypes, + npy_intp nop) +{ + npy_intp iop; + + /* + * If the input isn't a tuple of dtypes, try converting it as-is + * to a dtype, and replicating to all operands. + */ + if ((!PyTuple_Check(op_dtypes_in) && !PyList_Check(op_dtypes_in)) || + PySequence_Size(op_dtypes_in) != nop) { + goto try_single_dtype; + } + + for (iop = 0; iop < nop; ++iop) { + PyObject *dtype = PySequence_GetItem(op_dtypes_in, iop); + if (dtype == NULL) { + npy_intp i; + for (i = 0; i < iop; ++i ) { + Py_XDECREF(op_dtypes[i]); + } + return 0; + } + + /* Try converting the object to a descr */ + if (PyArray_DescrConverter2(dtype, &op_dtypes[iop]) != 1) { + npy_intp i; + for (i = 0; i < iop; ++i ) { + Py_XDECREF(op_dtypes[i]); + } + Py_DECREF(dtype); + PyErr_Clear(); + goto try_single_dtype; + } + + Py_DECREF(dtype); + } + + return 1; + +try_single_dtype: + if (PyArray_DescrConverter2(op_dtypes_in, &op_dtypes[0]) == 1) { + for (iop = 1; iop < nop; ++iop) { + op_dtypes[iop] = op_dtypes[0]; + Py_XINCREF(op_dtypes[iop]); + } + return 1; + } + + return 0; +} + +static int +npyiter_convert_op_axes(PyObject *op_axes_in, npy_intp nop, + int **op_axes, int *oa_ndim) +{ + PyObject *a; + int iop; + + if ((!PyTuple_Check(op_axes_in) && !PyList_Check(op_axes_in)) || + PySequence_Size(op_axes_in) != nop) { + PyErr_SetString(PyExc_ValueError, + "op_axes must be a tuple/list matching the number of ops"); + return 0; + } + + *oa_ndim = -1; + + /* Copy the tuples into op_axes */ + for (iop = 0; iop < nop; ++iop) { + int idim; + a = PySequence_GetItem(op_axes_in, iop); + if (a == NULL) { + return 0; + } + if (a == Py_None) { + op_axes[iop] = NULL; + } else { + if (!PyTuple_Check(a) && !PyList_Check(a)) { + PyErr_SetString(PyExc_ValueError, + "Each entry of op_axes must be None " + "or a tuple/list"); + Py_DECREF(a); + return 0; + } + if (*oa_ndim == -1) { + *oa_ndim = PySequence_Size(a); + if (*oa_ndim > NPY_MAXDIMS) { + PyErr_SetString(PyExc_ValueError, + "Too many dimensions in op_axes"); + return 0; + } + } + if (PySequence_Size(a) != *oa_ndim) { + PyErr_SetString(PyExc_ValueError, + "Each entry of op_axes must have the same size"); + Py_DECREF(a); + return 0; + } + for (idim = 0; idim < *oa_ndim; ++idim) { + PyObject *v = PySequence_GetItem(a, idim); + if (v == NULL) { + Py_DECREF(a); + return 0; + } + /* numpy.newaxis is None */ + if (v == Py_None) { + op_axes[iop][idim] = -1; + } + else { + op_axes[iop][idim] = PyArray_PyIntAsInt(v); + if (op_axes[iop][idim]==-1 && + PyErr_Occurred()) { + Py_DECREF(a); + Py_DECREF(v); + return 0; + } + } + Py_DECREF(v); + } + Py_DECREF(a); + } + } + + if (*oa_ndim == -1) { + PyErr_SetString(PyExc_ValueError, + "If op_axes is provided, at least one list of axes " + "must be contained within it"); + return 0; + } + + return 1; +} + +/* + * Converts the operand array and op_flags array into the form + * NpyIter_AdvancedNew needs. Sets nop, and on success, each + * op[i] owns a reference to an array object. + */ +static int +npyiter_convert_ops(PyObject *op_in, PyObject *op_flags_in, + PyArrayObject **op, npy_uint32 *op_flags, + int *nop_out) +{ + int iop, nop; + + /* nop and op */ + if (PyTuple_Check(op_in) || PyList_Check(op_in)) { + nop = PySequence_Size(op_in); + if (nop == 0) { + PyErr_SetString(PyExc_ValueError, + "Must provide at least one operand"); + return 0; + } + if (nop > NPY_MAXARGS) { + PyErr_SetString(PyExc_ValueError, "Too many operands"); + return 0; + } + + for (iop = 0; iop < nop; ++iop) { + PyObject *item = PySequence_GetItem(op_in, iop); + if (item == NULL) { + npy_intp i; + for (i = 0; i < iop; ++i) { + Py_XDECREF(op[i]); + } + return 0; + } + else if (item == Py_None) { + Py_DECREF(item); + item = NULL; + } + /* This is converted to an array after op flags are retrieved */ + op[iop] = (PyArrayObject *)item; + } + } + else { + nop = 1; + /* Is converted to an array after op flags are retrieved */ + Py_INCREF(op_in); + op[0] = (PyArrayObject *)op_in; + } + + *nop_out = nop; + + /* op_flags */ + if (op_flags_in == NULL || op_flags_in == Py_None) { + for (iop = 0; iop < nop; ++iop) { + /* + * By default, make NULL operands writeonly and flagged for + * allocation, and everything else readonly. To write + * to a provided operand, you must specify the write flag manually. + */ + if (op[iop] == NULL) { + op_flags[iop] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE; + } + else { + op_flags[iop] = NPY_ITER_READONLY; + } + } + } + else if (npyiter_convert_op_flags_array(op_flags_in, + op_flags, nop) != 1) { + for (iop = 0; iop < nop; ++iop) { + Py_XDECREF(op[iop]); + } + *nop_out = 0; + return 0; + } + + /* Now that we have the flags - convert all the ops to arrays */ + for (iop = 0; iop < nop; ++iop) { + if (op[iop] != NULL) { + PyArrayObject *ao; + int fromanyflags = 0; + + if (op_flags[iop]&(NPY_ITER_READWRITE|NPY_ITER_WRITEONLY)) { + fromanyflags |= NPY_ARRAY_WRITEBACKIFCOPY; + } + ao = (PyArrayObject *)PyArray_FROM_OF((PyObject *)op[iop], + fromanyflags); + if (ao == NULL) { + if (PyErr_Occurred() && + PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_SetString(PyExc_TypeError, + "Iterator operand is flagged as writeable, " + "but is an object which cannot be written " + "back to via UPDATEIFCOPY"); + } + for (iop = 0; iop < nop; ++iop) { + Py_DECREF(op[iop]); + } + *nop_out = 0; + return 0; + } + Py_DECREF(op[iop]); + op[iop] = ao; + } + } + + return 1; +} + +static int +npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"op", "flags", "op_flags", "op_dtypes", + "order", "casting", "op_axes", "itershape", + "buffersize", + NULL}; + + PyObject *op_in = NULL, *op_flags_in = NULL, + *op_dtypes_in = NULL, *op_axes_in = NULL; + + int iop, nop = 0; + PyArrayObject *op[NPY_MAXARGS]; + npy_uint32 flags = 0; + NPY_ORDER order = NPY_KEEPORDER; + NPY_CASTING casting = NPY_SAFE_CASTING; + npy_uint32 op_flags[NPY_MAXARGS]; + PyArray_Descr *op_request_dtypes[NPY_MAXARGS]; + int oa_ndim = -1; + int op_axes_arrays[NPY_MAXARGS][NPY_MAXDIMS]; + int *op_axes[NPY_MAXARGS]; + PyArray_Dims itershape = {NULL, 0}; + int buffersize = 0; + + if (self->iter != NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator was already initialized"); + return -1; + } + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&OOO&O&OO&i:nditer", kwlist, + &op_in, + NpyIter_GlobalFlagsConverter, &flags, + &op_flags_in, + &op_dtypes_in, + npyiter_order_converter, &order, + PyArray_CastingConverter, &casting, + &op_axes_in, + PyArray_IntpConverter, &itershape, + &buffersize)) { + npy_free_cache_dim_obj(itershape); + return -1; + } + + /* Set the dtypes and ops to all NULL to start */ + memset(op_request_dtypes, 0, sizeof(op_request_dtypes)); + + /* op and op_flags */ + if (npyiter_convert_ops(op_in, op_flags_in, op, op_flags, &nop) + != 1) { + goto fail; + } + + /* op_request_dtypes */ + if (op_dtypes_in != NULL && op_dtypes_in != Py_None && + npyiter_convert_dtypes(op_dtypes_in, + op_request_dtypes, nop) != 1) { + goto fail; + } + + /* op_axes */ + if (op_axes_in != NULL && op_axes_in != Py_None) { + /* Initialize to point to the op_axes arrays */ + for (iop = 0; iop < nop; ++iop) { + op_axes[iop] = op_axes_arrays[iop]; + } + + if (npyiter_convert_op_axes(op_axes_in, nop, + op_axes, &oa_ndim) != 1) { + goto fail; + } + } + + if (itershape.len > 0) { + if (oa_ndim == -1) { + oa_ndim = itershape.len; + memset(op_axes, 0, sizeof(op_axes[0]) * nop); + } + else if (oa_ndim != itershape.len) { + PyErr_SetString(PyExc_ValueError, + "'op_axes' and 'itershape' must have the same number " + "of entries equal to the iterator ndim"); + goto fail; + } + } + else if (itershape.ptr != NULL) { + npy_free_cache_dim_obj(itershape); + itershape.ptr = NULL; + } + + self->iter = NpyIter_AdvancedNew(nop, op, flags, order, casting, op_flags, + op_request_dtypes, + oa_ndim, oa_ndim >= 0 ? op_axes : NULL, + itershape.ptr, + buffersize); + + if (self->iter == NULL) { + goto fail; + } + + /* Cache some values for the member functions to use */ + if (npyiter_cache_values(self) < 0) { + goto fail; + } + + if (NpyIter_GetIterSize(self->iter) == 0) { + self->started = 1; + self->finished = 1; + } + else { + self->started = 0; + self->finished = 0; + } + + npy_free_cache_dim_obj(itershape); + + /* Release the references we got to the ops and dtypes */ + for (iop = 0; iop < nop; ++iop) { + Py_XDECREF(op[iop]); + Py_XDECREF(op_request_dtypes[iop]); + } + + return 0; + +fail: + npy_free_cache_dim_obj(itershape); + for (iop = 0; iop < nop; ++iop) { + Py_XDECREF(op[iop]); + Py_XDECREF(op_request_dtypes[iop]); + } + return -1; +} + +NPY_NO_EXPORT PyObject * +NpyIter_NestedIters(PyObject *NPY_UNUSED(self), + PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"op", "axes", "flags", "op_flags", + "op_dtypes", "order", + "casting", "buffersize", + NULL}; + + PyObject *op_in = NULL, *axes_in = NULL, + *op_flags_in = NULL, *op_dtypes_in = NULL; + + int iop, nop = 0, inest, nnest = 0; + PyArrayObject *op[NPY_MAXARGS]; + npy_uint32 flags = 0, flags_inner; + NPY_ORDER order = NPY_KEEPORDER; + NPY_CASTING casting = NPY_SAFE_CASTING; + npy_uint32 op_flags[NPY_MAXARGS], op_flags_inner[NPY_MAXARGS]; + PyArray_Descr *op_request_dtypes[NPY_MAXARGS], + *op_request_dtypes_inner[NPY_MAXARGS]; + int op_axes_data[NPY_MAXDIMS]; + int *nested_op_axes[NPY_MAXDIMS]; + int nested_naxes[NPY_MAXDIMS], iaxes, naxes; + int negones[NPY_MAXDIMS]; + char used_axes[NPY_MAXDIMS]; + int buffersize = 0; + + PyObject *ret = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O&OOO&O&i", kwlist, + &op_in, + &axes_in, + NpyIter_GlobalFlagsConverter, &flags, + &op_flags_in, + &op_dtypes_in, + npyiter_order_converter, &order, + PyArray_CastingConverter, &casting, + &buffersize)) { + return NULL; + } + + /* axes */ + if (!PyTuple_Check(axes_in) && !PyList_Check(axes_in)) { + PyErr_SetString(PyExc_ValueError, + "axes must be a tuple of axis arrays"); + return NULL; + } + nnest = PySequence_Size(axes_in); + if (nnest < 2) { + PyErr_SetString(PyExc_ValueError, + "axes must have at least 2 entries for nested iteration"); + return NULL; + } + naxes = 0; + memset(used_axes, 0, NPY_MAXDIMS); + for (inest = 0; inest < nnest; ++inest) { + PyObject *item = PySequence_GetItem(axes_in, inest); + npy_intp i; + if (item == NULL) { + return NULL; + } + if (!PyTuple_Check(item) && !PyList_Check(item)) { + PyErr_SetString(PyExc_ValueError, + "Each item in axes must be a an integer tuple"); + Py_DECREF(item); + return NULL; + } + nested_naxes[inest] = PySequence_Size(item); + if (naxes + nested_naxes[inest] > NPY_MAXDIMS) { + PyErr_SetString(PyExc_ValueError, + "Too many axes given"); + Py_DECREF(item); + return NULL; + } + for (i = 0; i < nested_naxes[inest]; ++i) { + PyObject *v = PySequence_GetItem(item, i); + npy_intp axis; + if (v == NULL) { + Py_DECREF(item); + return NULL; + } + axis = PyInt_AsLong(v); + Py_DECREF(v); + if (axis < 0 || axis >= NPY_MAXDIMS) { + PyErr_SetString(PyExc_ValueError, + "An axis is out of bounds"); + Py_DECREF(item); + return NULL; + } + /* + * This check is very important, without it out of bounds + * data accesses are possible. + */ + if (used_axes[axis] != 0) { + PyErr_SetString(PyExc_ValueError, + "An axis is used more than once"); + Py_DECREF(item); + return NULL; + } + used_axes[axis] = 1; + op_axes_data[naxes+i] = axis; + } + nested_op_axes[inest] = &op_axes_data[naxes]; + naxes += nested_naxes[inest]; + Py_DECREF(item); + } + + /* op and op_flags */ + if (npyiter_convert_ops(op_in, op_flags_in, op, op_flags, &nop) + != 1) { + return NULL; + } + + /* Set the dtypes to all NULL to start as well */ + memset(op_request_dtypes, 0, sizeof(op_request_dtypes[0])*nop); + memset(op_request_dtypes_inner, 0, + sizeof(op_request_dtypes_inner[0])*nop); + + /* op_request_dtypes */ + if (op_dtypes_in != NULL && op_dtypes_in != Py_None && + npyiter_convert_dtypes(op_dtypes_in, + op_request_dtypes, nop) != 1) { + goto fail; + } + + ret = PyTuple_New(nnest); + if (ret == NULL) { + goto fail; + } + + /* For broadcasting allocated arrays */ + for (iaxes = 0; iaxes < naxes; ++iaxes) { + negones[iaxes] = -1; + } + + /* + * Clear any unnecessary ALLOCATE flags, so we can use them + * to indicate exactly the allocated outputs. Also, separate + * the inner loop flags. + */ + for (iop = 0; iop < nop; ++iop) { + if ((op_flags[iop]&NPY_ITER_ALLOCATE) && op[iop] != NULL) { + op_flags[iop] &= ~NPY_ITER_ALLOCATE; + } + + /* + * Clear any flags allowing copies or output allocation for + * the inner loop. + */ + op_flags_inner[iop] = op_flags[iop] & ~(NPY_ITER_COPY| + NPY_ITER_UPDATEIFCOPY| + NPY_ITER_ALLOCATE); + /* + * If buffering is enabled and copying is not, + * clear the nbo_aligned flag and strip the data type + * for the outer loops. + */ + if ((flags&(NPY_ITER_BUFFERED)) && + !(op_flags[iop]&(NPY_ITER_COPY| + NPY_ITER_UPDATEIFCOPY| + NPY_ITER_ALLOCATE))) { + op_flags[iop] &= ~(NPY_ITER_NBO|NPY_ITER_ALIGNED|NPY_ITER_CONTIG); + op_request_dtypes_inner[iop] = op_request_dtypes[iop]; + op_request_dtypes[iop] = NULL; + } + } + + /* Only the inner loop gets the buffering and no inner flags */ + flags_inner = flags&~NPY_ITER_COMMON_DTYPE; + flags &= ~(NPY_ITER_EXTERNAL_LOOP| + NPY_ITER_BUFFERED); + + for (inest = 0; inest < nnest; ++inest) { + NewNpyArrayIterObject *iter; + int *op_axes_nop[NPY_MAXARGS]; + + /* + * All the operands' op_axes are the same, except for + * allocated outputs. + */ + for (iop = 0; iop < nop; ++iop) { + if (op_flags[iop]&NPY_ITER_ALLOCATE) { + if (inest == 0) { + op_axes_nop[iop] = NULL; + } + else { + op_axes_nop[iop] = negones; + } + } + else { + op_axes_nop[iop] = nested_op_axes[inest]; + } + } + + /* + printf("\n"); + for (iop = 0; iop < nop; ++iop) { + npy_intp i; + + for (i = 0; i < nested_naxes[inest]; ++i) { + printf("%d ", (int)op_axes_nop[iop][i]); + } + printf("\n"); + } + */ + + /* Allocate the iterator */ + iter = (NewNpyArrayIterObject *)npyiter_new(&NpyIter_Type, NULL, NULL); + if (iter == NULL) { + Py_DECREF(ret); + goto fail; + } + + if (inest < nnest-1) { + iter->iter = NpyIter_AdvancedNew(nop, op, flags, order, + casting, op_flags, op_request_dtypes, + nested_naxes[inest], op_axes_nop, + NULL, + 0); + } + else { + iter->iter = NpyIter_AdvancedNew(nop, op, flags_inner, order, + casting, op_flags_inner, + op_request_dtypes_inner, + nested_naxes[inest], op_axes_nop, + NULL, + buffersize); + } + + if (iter->iter == NULL) { + Py_DECREF(ret); + goto fail; + } + + /* Cache some values for the member functions to use */ + if (npyiter_cache_values(iter) < 0) { + Py_DECREF(ret); + goto fail; + } + + if (NpyIter_GetIterSize(iter->iter) == 0) { + iter->started = 1; + iter->finished = 1; + } + else { + iter->started = 0; + iter->finished = 0; + } + + /* + * If there are any allocated outputs or any copies were made, + * adjust op so that the other iterators use the same ones. + */ + if (inest == 0) { + PyArrayObject **operands = NpyIter_GetOperandArray(iter->iter); + for (iop = 0; iop < nop; ++iop) { + if (op[iop] != operands[iop]) { + Py_XDECREF(op[iop]); + op[iop] = operands[iop]; + Py_INCREF(op[iop]); + } + + /* + * Clear any flags allowing copies for + * the rest of the iterators + */ + op_flags[iop] &= ~(NPY_ITER_COPY| + NPY_ITER_UPDATEIFCOPY); + } + /* Clear the common dtype flag for the rest of the iterators */ + flags &= ~NPY_ITER_COMMON_DTYPE; + } + + PyTuple_SET_ITEM(ret, inest, (PyObject *)iter); + } + + /* Release our references to the ops and dtypes */ + for (iop = 0; iop < nop; ++iop) { + Py_XDECREF(op[iop]); + Py_XDECREF(op_request_dtypes[iop]); + Py_XDECREF(op_request_dtypes_inner[iop]); + } + + /* Set up the nested child references */ + for (inest = 0; inest < nnest-1; ++inest) { + NewNpyArrayIterObject *iter; + iter = (NewNpyArrayIterObject *)PyTuple_GET_ITEM(ret, inest); + /* + * Indicates which iterator to reset with new base pointers + * each iteration step. + */ + iter->nested_child = + (NewNpyArrayIterObject *)PyTuple_GET_ITEM(ret, inest+1); + Py_INCREF(iter->nested_child); + /* + * Need to do a nested reset so all the iterators point + * at the right data + */ + if (NpyIter_ResetBasePointers(iter->nested_child->iter, + iter->dataptrs, NULL) != NPY_SUCCEED) { + Py_DECREF(ret); + return NULL; + } + } + + return ret; + +fail: + for (iop = 0; iop < nop; ++iop) { + Py_XDECREF(op[iop]); + Py_XDECREF(op_request_dtypes[iop]); + Py_XDECREF(op_request_dtypes_inner[iop]); + } + return NULL; +} + +static void +npyiter_dealloc(NewNpyArrayIterObject *self) +{ + if (self->iter) { + NpyIter_Deallocate(self->iter); + self->iter = NULL; + Py_XDECREF(self->nested_child); + self->nested_child = NULL; + } + Py_TYPE(self)->tp_free((PyObject*)self); +} + +static int +npyiter_resetbasepointers(NewNpyArrayIterObject *self) +{ + while (self->nested_child) { + if (NpyIter_ResetBasePointers(self->nested_child->iter, + self->dataptrs, NULL) != NPY_SUCCEED) { + return NPY_FAIL; + } + self = self->nested_child; + if (NpyIter_GetIterSize(self->iter) == 0) { + self->started = 1; + self->finished = 1; + } + else { + self->started = 0; + self->finished = 0; + } + } + + return NPY_SUCCEED; +} + +static PyObject * +npyiter_reset(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + if (NpyIter_Reset(self->iter, NULL) != NPY_SUCCEED) { + return NULL; + } + if (NpyIter_GetIterSize(self->iter) == 0) { + self->started = 1; + self->finished = 1; + } + else { + self->started = 0; + self->finished = 0; + } + + if (self->get_multi_index == NULL && NpyIter_HasMultiIndex(self->iter)) { + self->get_multi_index = NpyIter_GetGetMultiIndex(self->iter, NULL); + } + + /* If there is nesting, the nested iterators should be reset */ + if (npyiter_resetbasepointers(self) != NPY_SUCCEED) { + return NULL; + } + + Py_RETURN_NONE; +} + +/* + * Makes a copy of the iterator. Note that the nesting is not + * copied. + */ +static PyObject * +npyiter_copy(NewNpyArrayIterObject *self) +{ + NewNpyArrayIterObject *iter; + + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + /* Allocate the iterator */ + iter = (NewNpyArrayIterObject *)npyiter_new(&NpyIter_Type, NULL, NULL); + if (iter == NULL) { + return NULL; + } + + /* Copy the C iterator */ + iter->iter = NpyIter_Copy(self->iter); + if (iter->iter == NULL) { + Py_DECREF(iter); + return NULL; + } + + /* Cache some values for the member functions to use */ + if (npyiter_cache_values(iter) < 0) { + Py_DECREF(iter); + return NULL; + } + + iter->started = self->started; + iter->finished = self->finished; + + return (PyObject *)iter; +} + +static PyObject * +npyiter_iternext(NewNpyArrayIterObject *self) +{ + if (self->iter != NULL && self->iternext != NULL && + !self->finished && self->iternext(self->iter)) { + /* If there is nesting, the nested iterators should be reset */ + if (npyiter_resetbasepointers(self) != NPY_SUCCEED) { + return NULL; + } + + Py_RETURN_TRUE; + } + else { + self->finished = 1; + Py_RETURN_FALSE; + } +} + +static PyObject * +npyiter_remove_axis(NewNpyArrayIterObject *self, PyObject *args) +{ + int axis = 0; + + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + if (!PyArg_ParseTuple(args, "i:remove_axis", &axis)) { + return NULL; + } + + if (NpyIter_RemoveAxis(self->iter, axis) != NPY_SUCCEED) { + return NULL; + } + /* RemoveAxis invalidates cached values */ + if (npyiter_cache_values(self) < 0) { + return NULL; + } + /* RemoveAxis also resets the iterator */ + if (NpyIter_GetIterSize(self->iter) == 0) { + self->started = 1; + self->finished = 1; + } + else { + self->started = 0; + self->finished = 0; + } + + Py_RETURN_NONE; +} + +static PyObject * +npyiter_remove_multi_index(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + NpyIter_RemoveMultiIndex(self->iter); + /* RemoveMultiIndex invalidates cached values */ + npyiter_cache_values(self); + /* RemoveMultiIndex also resets the iterator */ + if (NpyIter_GetIterSize(self->iter) == 0) { + self->started = 1; + self->finished = 1; + } + else { + self->started = 0; + self->finished = 0; + } + + Py_RETURN_NONE; +} + +static PyObject * +npyiter_enable_external_loop(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + NpyIter_EnableExternalLoop(self->iter); + /* EnableExternalLoop invalidates cached values */ + npyiter_cache_values(self); + /* EnableExternalLoop also resets the iterator */ + if (NpyIter_GetIterSize(self->iter) == 0) { + self->started = 1; + self->finished = 1; + } + else { + self->started = 0; + self->finished = 0; + } + + Py_RETURN_NONE; +} + +static PyObject * +npyiter_debug_print(NewNpyArrayIterObject *self) +{ + if (self->iter != NULL) { + NpyIter_DebugPrint(self->iter); + } + else { + printf("Iterator: (nil)\n"); + } + + Py_RETURN_NONE; +} + +NPY_NO_EXPORT PyObject * +npyiter_seq_item(NewNpyArrayIterObject *self, Py_ssize_t i); + +static PyObject *npyiter_value_get(NewNpyArrayIterObject *self) +{ + PyObject *ret; + + npy_intp iop, nop; + + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return NULL; + } + + nop = NpyIter_GetNOp(self->iter); + + /* Return an array or tuple of arrays with the values */ + if (nop == 1) { + ret = npyiter_seq_item(self, 0); + } + else { + ret = PyTuple_New(nop); + if (ret == NULL) { + return NULL; + } + for (iop = 0; iop < nop; ++iop) { + PyObject *a = npyiter_seq_item(self, iop); + if (a == NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(ret, iop, a); + } + } + + return ret; +} + +static PyObject *npyiter_operands_get(NewNpyArrayIterObject *self) +{ + PyObject *ret; + + npy_intp iop, nop; + PyArrayObject **operands; + + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + nop = NpyIter_GetNOp(self->iter); + operands = self->operands; + + ret = PyTuple_New(nop); + if (ret == NULL) { + return NULL; + } + for (iop = 0; iop < nop; ++iop) { + PyObject *operand = (PyObject *)operands[iop]; + + Py_INCREF(operand); + PyTuple_SET_ITEM(ret, iop, operand); + } + + return ret; +} + +static PyObject *npyiter_itviews_get(NewNpyArrayIterObject *self) +{ + PyObject *ret; + + npy_intp iop, nop; + + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + nop = NpyIter_GetNOp(self->iter); + + ret = PyTuple_New(nop); + if (ret == NULL) { + return NULL; + } + for (iop = 0; iop < nop; ++iop) { + PyArrayObject *view = NpyIter_GetIterView(self->iter, iop); + + if (view == NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(ret, iop, (PyObject *)view); + } + + return ret; +} + +static PyObject * +npyiter_next(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL || self->iternext == NULL || self->finished) { + return NULL; + } + + /* + * Use the started flag for the Python iteration protocol to work + * when buffering is enabled. + */ + if (self->started) { + if (!self->iternext(self->iter)) { + self->finished = 1; + return NULL; + } + + /* If there is nesting, the nested iterators should be reset */ + if (npyiter_resetbasepointers(self) != NPY_SUCCEED) { + return NULL; + } + } + self->started = 1; + + return npyiter_value_get(self); +}; + +static PyObject *npyiter_shape_get(NewNpyArrayIterObject *self) +{ + PyObject *ret; + npy_intp idim, ndim, shape[NPY_MAXDIMS]; + + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return NULL; + } + + if (NpyIter_GetShape(self->iter, shape) == NPY_SUCCEED) { + ndim = NpyIter_GetNDim(self->iter); + ret = PyTuple_New(ndim); + if (ret != NULL) { + for (idim = 0; idim < ndim; ++idim) { + PyTuple_SET_ITEM(ret, idim, + PyInt_FromLong(shape[idim])); + } + return ret; + } + } + + return NULL; +} + +static PyObject *npyiter_multi_index_get(NewNpyArrayIterObject *self) +{ + PyObject *ret; + npy_intp idim, ndim, multi_index[NPY_MAXDIMS]; + + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return NULL; + } + + if (self->get_multi_index != NULL) { + ndim = NpyIter_GetNDim(self->iter); + self->get_multi_index(self->iter, multi_index); + ret = PyTuple_New(ndim); + if (ret == NULL) { + return NULL; + } + for (idim = 0; idim < ndim; ++idim) { + PyTuple_SET_ITEM(ret, idim, + PyInt_FromLong(multi_index[idim])); + } + return ret; + } + else { + if (!NpyIter_HasMultiIndex(self->iter)) { + PyErr_SetString(PyExc_ValueError, + "Iterator is not tracking a multi-index"); + return NULL; + } + else if (NpyIter_HasDelayedBufAlloc(self->iter)) { + PyErr_SetString(PyExc_ValueError, + "Iterator construction used delayed buffer allocation, " + "and no reset has been done yet"); + return NULL; + } + else { + PyErr_SetString(PyExc_ValueError, + "Iterator is in an invalid state"); + return NULL; + } + } +} + +static int +npyiter_multi_index_set(NewNpyArrayIterObject *self, PyObject *value) +{ + npy_intp idim, ndim, multi_index[NPY_MAXDIMS]; + + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete nditer multi_index"); + return -1; + } + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return -1; + } + + if (NpyIter_HasMultiIndex(self->iter)) { + ndim = NpyIter_GetNDim(self->iter); + if (!PySequence_Check(value)) { + PyErr_SetString(PyExc_ValueError, + "multi_index must be set with a sequence"); + return -1; + } + if (PySequence_Size(value) != ndim) { + PyErr_SetString(PyExc_ValueError, + "Wrong number of indices"); + return -1; + } + for (idim = 0; idim < ndim; ++idim) { + PyObject *v = PySequence_GetItem(value, idim); + multi_index[idim] = PyInt_AsLong(v); + if (error_converting(multi_index[idim])) { + Py_XDECREF(v); + return -1; + } + } + if (NpyIter_GotoMultiIndex(self->iter, multi_index) != NPY_SUCCEED) { + return -1; + } + self->started = 0; + self->finished = 0; + + /* If there is nesting, the nested iterators should be reset */ + if (npyiter_resetbasepointers(self) != NPY_SUCCEED) { + return -1; + } + + return 0; + } + else { + PyErr_SetString(PyExc_ValueError, + "Iterator is not tracking a multi-index"); + return -1; + } +} + +static PyObject *npyiter_index_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return NULL; + } + + if (NpyIter_HasIndex(self->iter)) { + npy_intp ind = *NpyIter_GetIndexPtr(self->iter); + return PyInt_FromLong(ind); + } + else { + PyErr_SetString(PyExc_ValueError, + "Iterator does not have an index"); + return NULL; + } +} + +static int npyiter_index_set(NewNpyArrayIterObject *self, PyObject *value) +{ + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete nditer index"); + return -1; + } + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return -1; + } + + if (NpyIter_HasIndex(self->iter)) { + npy_intp ind; + ind = PyInt_AsLong(value); + if (error_converting(ind)) { + return -1; + } + if (NpyIter_GotoIndex(self->iter, ind) != NPY_SUCCEED) { + return -1; + } + self->started = 0; + self->finished = 0; + + /* If there is nesting, the nested iterators should be reset */ + if (npyiter_resetbasepointers(self) != NPY_SUCCEED) { + return -1; + } + + return 0; + } + else { + PyErr_SetString(PyExc_ValueError, + "Iterator does not have an index"); + return -1; + } +} + +static PyObject *npyiter_iterindex_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return NULL; + } + + return PyInt_FromLong(NpyIter_GetIterIndex(self->iter)); +} + +static int npyiter_iterindex_set(NewNpyArrayIterObject *self, PyObject *value) +{ + npy_intp iterindex; + + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete nditer iterindex"); + return -1; + } + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return -1; + } + + iterindex = PyInt_AsLong(value); + if (error_converting(iterindex)) { + return -1; + } + if (NpyIter_GotoIterIndex(self->iter, iterindex) != NPY_SUCCEED) { + return -1; + } + self->started = 0; + self->finished = 0; + + /* If there is nesting, the nested iterators should be reset */ + if (npyiter_resetbasepointers(self) != NPY_SUCCEED) { + return -1; + } + + return 0; +} + +static PyObject *npyiter_iterrange_get(NewNpyArrayIterObject *self) +{ + npy_intp istart = 0, iend = 0; + PyObject *ret; + + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + NpyIter_GetIterIndexRange(self->iter, &istart, &iend); + + ret = PyTuple_New(2); + if (ret == NULL) { + return NULL; + } + + PyTuple_SET_ITEM(ret, 0, PyInt_FromLong(istart)); + PyTuple_SET_ITEM(ret, 1, PyInt_FromLong(iend)); + + return ret; +} + +static int npyiter_iterrange_set(NewNpyArrayIterObject *self, PyObject *value) +{ + npy_intp istart = 0, iend = 0; + + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "Cannot delete nditer iterrange"); + return -1; + } + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return -1; + } + + if (!PyArg_ParseTuple(value, "nn", &istart, &iend)) { + return -1; + } + + if (NpyIter_ResetToIterIndexRange(self->iter, istart, iend, NULL) + != NPY_SUCCEED) { + return -1; + } + if (istart < iend) { + self->started = self->finished = 0; + } + else { + self->started = self->finished = 1; + } + + if (self->get_multi_index == NULL && NpyIter_HasMultiIndex(self->iter)) { + self->get_multi_index = NpyIter_GetGetMultiIndex(self->iter, NULL); + } + + /* If there is nesting, the nested iterators should be reset */ + if (npyiter_resetbasepointers(self) != NPY_SUCCEED) { + return -1; + } + + return 0; +} + +static PyObject *npyiter_has_delayed_bufalloc_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + if (NpyIter_HasDelayedBufAlloc(self->iter)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject *npyiter_iterationneedsapi_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + if (NpyIter_IterationNeedsAPI(self->iter)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject *npyiter_has_multi_index_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + if (NpyIter_HasMultiIndex(self->iter)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject *npyiter_has_index_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + if (NpyIter_HasIndex(self->iter)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyObject *npyiter_dtypes_get(NewNpyArrayIterObject *self) +{ + PyObject *ret; + + npy_intp iop, nop; + PyArray_Descr **dtypes; + + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + nop = NpyIter_GetNOp(self->iter); + + ret = PyTuple_New(nop); + if (ret == NULL) { + return NULL; + } + dtypes = self->dtypes; + for (iop = 0; iop < nop; ++iop) { + PyArray_Descr *dtype = dtypes[iop]; + + Py_INCREF(dtype); + PyTuple_SET_ITEM(ret, iop, (PyObject *)dtype); + } + + return ret; +} + +static PyObject *npyiter_ndim_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + return PyInt_FromLong(NpyIter_GetNDim(self->iter)); +} + +static PyObject *npyiter_nop_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + return PyInt_FromLong(NpyIter_GetNOp(self->iter)); +} + +static PyObject *npyiter_itersize_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + PyErr_SetString(PyExc_ValueError, + "Iterator is invalid"); + return NULL; + } + + return PyInt_FromLong(NpyIter_GetIterSize(self->iter)); +} + +static PyObject *npyiter_finished_get(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL || !self->finished) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +NPY_NO_EXPORT Py_ssize_t +npyiter_seq_length(NewNpyArrayIterObject *self) +{ + if (self->iter == NULL) { + return 0; + } + else { + return NpyIter_GetNOp(self->iter); + } +} + +NPY_NO_EXPORT PyObject * +npyiter_seq_item(NewNpyArrayIterObject *self, Py_ssize_t i) +{ + PyArrayObject *ret; + + npy_intp ret_ndim; + npy_intp nop, innerloopsize, innerstride; + char *dataptr; + PyArray_Descr *dtype; + int has_external_loop; + Py_ssize_t i_orig = i; + + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return NULL; + } + + if (NpyIter_HasDelayedBufAlloc(self->iter)) { + PyErr_SetString(PyExc_ValueError, + "Iterator construction used delayed buffer allocation, " + "and no reset has been done yet"); + return NULL; + } + + nop = NpyIter_GetNOp(self->iter); + + /* Negative indexing */ + if (i < 0) { + i += nop; + } + + if (i < 0 || i >= nop) { + PyErr_Format(PyExc_IndexError, + "Iterator operand index %d is out of bounds", (int)i_orig); + return NULL; + } + +#if 0 + /* + * This check is disabled because it prevents things like + * np.add(it[0], it[1], it[2]), where it[2] is a write-only + * parameter. When write-only, the value of it[i] is + * likely random junk, as if it were allocated with an + * np.empty(...) call. + */ + if (!self->readflags[i]) { + PyErr_Format(PyExc_RuntimeError, + "Iterator operand %d is write-only", (int)i); + return NULL; + } +#endif + + dataptr = self->dataptrs[i]; + dtype = self->dtypes[i]; + has_external_loop = NpyIter_HasExternalLoop(self->iter); + + if (has_external_loop) { + innerloopsize = *self->innerloopsizeptr; + innerstride = self->innerstrides[i]; + ret_ndim = 1; + } + else { + innerloopsize = 1; + innerstride = 0; + /* If the iterator is going over every element, return array scalars */ + ret_ndim = 0; + } + + Py_INCREF(dtype); + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, + ret_ndim, &innerloopsize, + &innerstride, dataptr, + self->writeflags[i] ? NPY_ARRAY_WRITEABLE : 0, NULL); + if (ret == NULL) { + return NULL; + } + Py_INCREF(self); + if (PyArray_SetBaseObject(ret, (PyObject *)self) < 0) { + Py_XDECREF(ret); + return NULL; + } + + PyArray_UpdateFlags(ret, NPY_ARRAY_UPDATE_ALL); + + return (PyObject *)ret; +} + +NPY_NO_EXPORT PyObject * +npyiter_seq_slice(NewNpyArrayIterObject *self, + Py_ssize_t ilow, Py_ssize_t ihigh) +{ + PyObject *ret; + npy_intp nop; + Py_ssize_t i; + + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return NULL; + } + + if (NpyIter_HasDelayedBufAlloc(self->iter)) { + PyErr_SetString(PyExc_ValueError, + "Iterator construction used delayed buffer allocation, " + "and no reset has been done yet"); + return NULL; + } + + nop = NpyIter_GetNOp(self->iter); + if (ilow < 0) { + ilow = 0; + } + else if (ilow >= nop) { + ilow = nop-1; + } + if (ihigh < ilow) { + ihigh = ilow; + } + else if (ihigh > nop) { + ihigh = nop; + } + + ret = PyTuple_New(ihigh-ilow); + if (ret == NULL) { + return NULL; + } + for (i = ilow; i < ihigh ; ++i) { + PyObject *item = npyiter_seq_item(self, i); + if (item == NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(ret, i-ilow, item); + } + return ret; +} + +NPY_NO_EXPORT int +npyiter_seq_ass_item(NewNpyArrayIterObject *self, Py_ssize_t i, PyObject *v) +{ + + npy_intp nop, innerloopsize, innerstride; + char *dataptr; + PyArray_Descr *dtype; + PyArrayObject *tmp; + int ret, has_external_loop; + Py_ssize_t i_orig = i; + + + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "Cannot delete iterator elements"); + return -1; + } + + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return -1; + } + + if (NpyIter_HasDelayedBufAlloc(self->iter)) { + PyErr_SetString(PyExc_ValueError, + "Iterator construction used delayed buffer allocation, " + "and no reset has been done yet"); + return -1; + } + + nop = NpyIter_GetNOp(self->iter); + + /* Negative indexing */ + if (i < 0) { + i += nop; + } + + if (i < 0 || i >= nop) { + PyErr_Format(PyExc_IndexError, + "Iterator operand index %d is out of bounds", (int)i_orig); + return -1; + } + if (!self->writeflags[i]) { + PyErr_Format(PyExc_RuntimeError, + "Iterator operand %d is not writeable", (int)i_orig); + return -1; + } + + dataptr = self->dataptrs[i]; + dtype = self->dtypes[i]; + has_external_loop = NpyIter_HasExternalLoop(self->iter); + + if (has_external_loop) { + innerloopsize = *self->innerloopsizeptr; + innerstride = self->innerstrides[i]; + } + else { + innerloopsize = 1; + innerstride = 0; + } + + /* TODO - there should be a better way than this... */ + Py_INCREF(dtype); + tmp = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, + 1, &innerloopsize, + &innerstride, dataptr, + NPY_ARRAY_WRITEABLE, NULL); + if (tmp == NULL) { + return -1; + } + + PyArray_UpdateFlags(tmp, NPY_ARRAY_UPDATE_ALL); + + ret = PyArray_CopyObject(tmp, v); + Py_DECREF(tmp); + return ret; +} + +static int +npyiter_seq_ass_slice(NewNpyArrayIterObject *self, Py_ssize_t ilow, + Py_ssize_t ihigh, PyObject *v) +{ + npy_intp nop; + Py_ssize_t i; + + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "Cannot delete iterator elements"); + return -1; + } + + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return -1; + } + + if (NpyIter_HasDelayedBufAlloc(self->iter)) { + PyErr_SetString(PyExc_ValueError, + "Iterator construction used delayed buffer allocation, " + "and no reset has been done yet"); + return -1; + } + + nop = NpyIter_GetNOp(self->iter); + if (ilow < 0) { + ilow = 0; + } + else if (ilow >= nop) { + ilow = nop-1; + } + if (ihigh < ilow) { + ihigh = ilow; + } + else if (ihigh > nop) { + ihigh = nop; + } + + if (!PySequence_Check(v) || PySequence_Size(v) != ihigh-ilow) { + PyErr_SetString(PyExc_ValueError, + "Wrong size to assign to iterator slice"); + return -1; + } + + for (i = ilow; i < ihigh ; ++i) { + PyObject *item = PySequence_GetItem(v, i-ilow); + if (item == NULL) { + return -1; + } + if (npyiter_seq_ass_item(self, i, item) < 0) { + Py_DECREF(item); + return -1; + } + Py_DECREF(item); + } + + return 0; +} + +static PyObject * +npyiter_subscript(NewNpyArrayIterObject *self, PyObject *op) +{ + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return NULL; + } + + if (NpyIter_HasDelayedBufAlloc(self->iter)) { + PyErr_SetString(PyExc_ValueError, + "Iterator construction used delayed buffer allocation, " + "and no reset has been done yet"); + return NULL; + } + + if (PyInt_Check(op) || PyLong_Check(op) || + (PyIndex_Check(op) && !PySequence_Check(op))) { + npy_intp i = PyArray_PyIntAsIntp(op); + if (error_converting(i)) { + return NULL; + } + return npyiter_seq_item(self, i); + } + else if (PySlice_Check(op)) { + Py_ssize_t istart = 0, iend = 0, istep = 0, islicelength; + if (NpySlice_GetIndicesEx(op, NpyIter_GetNOp(self->iter), + &istart, &iend, &istep, &islicelength) < 0) { + return NULL; + } + if (istep != 1) { + PyErr_SetString(PyExc_ValueError, + "Iterator slicing only supports a step of 1"); + return NULL; + } + return npyiter_seq_slice(self, istart, iend); + } + + PyErr_SetString(PyExc_TypeError, + "invalid index type for iterator indexing"); + return NULL; +} + +static int +npyiter_ass_subscript(NewNpyArrayIterObject *self, PyObject *op, + PyObject *value) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "Cannot delete iterator elements"); + return -1; + } + if (self->iter == NULL || self->finished) { + PyErr_SetString(PyExc_ValueError, + "Iterator is past the end"); + return -1; + } + + if (NpyIter_HasDelayedBufAlloc(self->iter)) { + PyErr_SetString(PyExc_ValueError, + "Iterator construction used delayed buffer allocation, " + "and no reset has been done yet"); + return -1; + } + + if (PyInt_Check(op) || PyLong_Check(op) || + (PyIndex_Check(op) && !PySequence_Check(op))) { + npy_intp i = PyArray_PyIntAsIntp(op); + if (error_converting(i)) { + return -1; + } + return npyiter_seq_ass_item(self, i, value); + } + else if (PySlice_Check(op)) { + Py_ssize_t istart = 0, iend = 0, istep = 0, islicelength = 0; + if (NpySlice_GetIndicesEx(op, NpyIter_GetNOp(self->iter), + &istart, &iend, &istep, &islicelength) < 0) { + return -1; + } + if (istep != 1) { + PyErr_SetString(PyExc_ValueError, + "Iterator slice assignment only supports a step of 1"); + return -1; + } + return npyiter_seq_ass_slice(self, istart, iend, value); + } + + PyErr_SetString(PyExc_TypeError, + "invalid index type for iterator indexing"); + return -1; +} + +static PyMethodDef npyiter_methods[] = { + {"reset", + (PyCFunction)npyiter_reset, + METH_NOARGS, NULL}, + {"copy", + (PyCFunction)npyiter_copy, + METH_NOARGS, NULL}, + {"__copy__", + (PyCFunction)npyiter_copy, + METH_NOARGS, NULL}, + {"iternext", + (PyCFunction)npyiter_iternext, + METH_NOARGS, NULL}, + {"remove_axis", + (PyCFunction)npyiter_remove_axis, + METH_VARARGS, NULL}, + {"remove_multi_index", + (PyCFunction)npyiter_remove_multi_index, + METH_NOARGS, NULL}, + {"enable_external_loop", + (PyCFunction)npyiter_enable_external_loop, + METH_NOARGS, NULL}, + {"debug_print", + (PyCFunction)npyiter_debug_print, + METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL}, +}; + +static PyMemberDef npyiter_members[] = { + {NULL, 0, 0, 0, NULL}, +}; + +static PyGetSetDef npyiter_getsets[] = { + {"value", + (getter)npyiter_value_get, + NULL, NULL, NULL}, + {"shape", + (getter)npyiter_shape_get, + NULL, NULL, NULL}, + {"multi_index", + (getter)npyiter_multi_index_get, + (setter)npyiter_multi_index_set, + NULL, NULL}, + {"index", + (getter)npyiter_index_get, + (setter)npyiter_index_set, + NULL, NULL}, + {"iterindex", + (getter)npyiter_iterindex_get, + (setter)npyiter_iterindex_set, + NULL, NULL}, + {"iterrange", + (getter)npyiter_iterrange_get, + (setter)npyiter_iterrange_set, + NULL, NULL}, + {"operands", + (getter)npyiter_operands_get, + NULL, NULL, NULL}, + {"itviews", + (getter)npyiter_itviews_get, + NULL, NULL, NULL}, + {"has_delayed_bufalloc", + (getter)npyiter_has_delayed_bufalloc_get, + NULL, NULL, NULL}, + {"iterationneedsapi", + (getter)npyiter_iterationneedsapi_get, + NULL, NULL, NULL}, + {"has_multi_index", + (getter)npyiter_has_multi_index_get, + NULL, NULL, NULL}, + {"has_index", + (getter)npyiter_has_index_get, + NULL, NULL, NULL}, + {"dtypes", + (getter)npyiter_dtypes_get, + NULL, NULL, NULL}, + {"ndim", + (getter)npyiter_ndim_get, + NULL, NULL, NULL}, + {"nop", + (getter)npyiter_nop_get, + NULL, NULL, NULL}, + {"itersize", + (getter)npyiter_itersize_get, + NULL, NULL, NULL}, + {"finished", + (getter)npyiter_finished_get, + NULL, NULL, NULL}, + + {NULL, NULL, NULL, NULL, NULL} +}; + +NPY_NO_EXPORT PySequenceMethods npyiter_as_sequence = { + (lenfunc)npyiter_seq_length, /*sq_length*/ + (binaryfunc)NULL, /*sq_concat*/ + (ssizeargfunc)NULL, /*sq_repeat*/ + (ssizeargfunc)npyiter_seq_item, /*sq_item*/ + (ssizessizeargfunc)NULL, /*sq_slice*/ + (ssizeobjargproc)npyiter_seq_ass_item, /*sq_ass_item*/ + (ssizessizeobjargproc)NULL, /*sq_ass_slice*/ + (objobjproc)NULL, /*sq_contains */ + (binaryfunc)NULL, /*sq_inplace_concat */ + (ssizeargfunc)NULL, /*sq_inplace_repeat */ +}; + +NPY_NO_EXPORT PyMappingMethods npyiter_as_mapping = { + (lenfunc)npyiter_seq_length, /*mp_length*/ + (binaryfunc)npyiter_subscript, /*mp_subscript*/ + (objobjargproc)npyiter_ass_subscript, /*mp_ass_subscript*/ +}; + +NPY_NO_EXPORT PyTypeObject NpyIter_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.nditer", /* tp_name */ + sizeof(NewNpyArrayIterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)npyiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + &npyiter_as_sequence, /* tp_as_sequence */ + &npyiter_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + (iternextfunc)npyiter_next, /* tp_iternext */ + npyiter_methods, /* tp_methods */ + npyiter_members, /* tp_members */ + npyiter_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)npyiter_init, /* tp_init */ + 0, /* tp_alloc */ + npyiter_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; diff --git a/numpy/core/src/multiarray/nditer_pywrap.h b/numpy/core/src/multiarray/nditer_pywrap.h new file mode 100644 index 0000000..49eb5d8 --- /dev/null +++ b/numpy/core/src/multiarray/nditer_pywrap.h @@ -0,0 +1,8 @@ +#ifndef __NDITER_PYWRAP_H +#define __NDITER_PYWRAP_H + +NPY_NO_EXPORT PyObject * +NpyIter_NestedIters(PyObject *NPY_UNUSED(self), + PyObject *args, PyObject *kwds); + +#endif diff --git a/numpy/core/src/multiarray/nditer_templ.c.src b/numpy/core/src/multiarray/nditer_templ.c.src new file mode 100644 index 0000000..0f0d599 --- /dev/null +++ b/numpy/core/src/multiarray/nditer_templ.c.src @@ -0,0 +1,615 @@ +/* + * This file implements the API functions for NumPy's nditer that + * are specialized using the templating system. + * + * Copyright (c) 2010-2011 by Mark Wiebe (mwwiebe@gmail.com) + * The University of British Columbia + * + * See LICENSE.txt for the license. + */ + +/* Indicate that this .c file is allowed to include the header */ +#define NPY_ITERATOR_IMPLEMENTATION_CODE +#include "nditer_impl.h" + +/* SPECIALIZED iternext functions that handle the non-buffering part */ + +/**begin repeat + * #const_itflags = 0, + * NPY_ITFLAG_HASINDEX, + * NPY_ITFLAG_EXLOOP, + * NPY_ITFLAG_RANGE, + * NPY_ITFLAG_RANGE|NPY_ITFLAG_HASINDEX# + * #tag_itflags = 0, IND, NOINN, RNG, RNGuIND# + */ +/**begin repeat1 + * #const_ndim = 1, 2, NPY_MAXDIMS# + * #tag_ndim = 1, 2, ANY# + */ +/**begin repeat2 + * #const_nop = 1, 2, NPY_MAXDIMS# + * #tag_nop = 1, 2, ANY# + */ + +/* Specialized iternext (@const_itflags@,@tag_ndim@,@tag_nop@) */ +static int +npyiter_iternext_itflags@tag_itflags@_dims@tag_ndim@_iters@tag_nop@( + NpyIter *iter) +{ +#if !(@const_itflags@&NPY_ITFLAG_EXLOOP) || (@const_ndim@ > 1) + const npy_uint32 itflags = @const_itflags@; +# if @const_ndim@ >= NPY_MAXDIMS + int idim, ndim = NIT_NDIM(iter); +# endif +# if @const_nop@ < NPY_MAXDIMS + const int nop = @const_nop@; +# else + int nop = NIT_NOP(iter); +# endif + + NpyIter_AxisData *axisdata0; + npy_intp istrides, nstrides = NAD_NSTRIDES(); +#endif +#if @const_ndim@ > 1 + NpyIter_AxisData *axisdata1; + npy_intp sizeof_axisdata; +#endif +#if @const_ndim@ > 2 + NpyIter_AxisData *axisdata2; +#endif + +#if (@const_itflags@&NPY_ITFLAG_RANGE) + /* When ranged iteration is enabled, use the iterindex */ + if (++NIT_ITERINDEX(iter) >= NIT_ITEREND(iter)) { + return 0; + } +#endif + +#if @const_ndim@ > 1 + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); +#endif + +# if !(@const_itflags@&NPY_ITFLAG_EXLOOP) || (@const_ndim@ > 1) + axisdata0 = NIT_AXISDATA(iter); +# endif +# if !(@const_itflags@&NPY_ITFLAG_EXLOOP) + /* Increment index 0 */ + NAD_INDEX(axisdata0)++; + /* Increment pointer 0 */ + for (istrides = 0; istrides < nstrides; ++istrides) { + NAD_PTRS(axisdata0)[istrides] += NAD_STRIDES(axisdata0)[istrides]; + } +# endif + +#if @const_ndim@ == 1 + +# if !(@const_itflags@&NPY_ITFLAG_EXLOOP) + /* Finished when the index equals the shape */ + return NAD_INDEX(axisdata0) < NAD_SHAPE(axisdata0); +# else + return 0; +# endif + +#else + +# if !(@const_itflags@&NPY_ITFLAG_EXLOOP) + if (NAD_INDEX(axisdata0) < NAD_SHAPE(axisdata0)) { + return 1; + } +# endif + + axisdata1 = NIT_INDEX_AXISDATA(axisdata0, 1); + /* Increment index 1 */ + NAD_INDEX(axisdata1)++; + /* Increment pointer 1 */ + for (istrides = 0; istrides < nstrides; ++istrides) { + NAD_PTRS(axisdata1)[istrides] += NAD_STRIDES(axisdata1)[istrides]; + } + + if (NAD_INDEX(axisdata1) < NAD_SHAPE(axisdata1)) { + /* Reset the 1st index to 0 */ + NAD_INDEX(axisdata0) = 0; + /* Reset the 1st pointer to the value of the 2nd */ + for (istrides = 0; istrides < nstrides; ++istrides) { + NAD_PTRS(axisdata0)[istrides] = NAD_PTRS(axisdata1)[istrides]; + } + return 1; + } + +# if @const_ndim@ == 2 + return 0; +# else + + axisdata2 = NIT_INDEX_AXISDATA(axisdata1, 1); + /* Increment index 2 */ + NAD_INDEX(axisdata2)++; + /* Increment pointer 2 */ + for (istrides = 0; istrides < nstrides; ++istrides) { + NAD_PTRS(axisdata2)[istrides] += NAD_STRIDES(axisdata2)[istrides]; + } + + if (NAD_INDEX(axisdata2) < NAD_SHAPE(axisdata2)) { + /* Reset the 1st and 2nd indices to 0 */ + NAD_INDEX(axisdata0) = 0; + NAD_INDEX(axisdata1) = 0; + /* Reset the 1st and 2nd pointers to the value of the 3nd */ + for (istrides = 0; istrides < nstrides; ++istrides) { + NAD_PTRS(axisdata0)[istrides] = NAD_PTRS(axisdata2)[istrides]; + NAD_PTRS(axisdata1)[istrides] = NAD_PTRS(axisdata2)[istrides]; + } + return 1; + } + + for (idim = 3; idim < ndim; ++idim) { + NIT_ADVANCE_AXISDATA(axisdata2, 1); + /* Increment the index */ + NAD_INDEX(axisdata2)++; + /* Increment the pointer */ + for (istrides = 0; istrides < nstrides; ++istrides) { + NAD_PTRS(axisdata2)[istrides] += NAD_STRIDES(axisdata2)[istrides]; + } + + + if (NAD_INDEX(axisdata2) < NAD_SHAPE(axisdata2)) { + /* Reset the indices and pointers of all previous axisdatas */ + axisdata1 = axisdata2; + do { + NIT_ADVANCE_AXISDATA(axisdata1, -1); + /* Reset the index to 0 */ + NAD_INDEX(axisdata1) = 0; + /* Reset the pointer to the updated value */ + for (istrides = 0; istrides < nstrides; ++istrides) { + NAD_PTRS(axisdata1)[istrides] = + NAD_PTRS(axisdata2)[istrides]; + } + } while (axisdata1 != axisdata0); + + return 1; + } + } + + return 0; + +# endif /* ndim != 2 */ + +#endif /* ndim != 1 */ +} + +/**end repeat2**/ +/**end repeat1**/ +/**end repeat**/ + + +/**begin repeat + * #const_nop = 1, 2, 3, 4, NPY_MAXDIMS# + * #tag_nop = 1, 2, 3, 4, ANY# + */ + +/* + * Iternext function that handles the reduction buffering part. This + * is done with a double loop to avoid frequent re-buffering. + */ +static int +npyiter_buffered_reduce_iternext_iters@tag_nop@(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ +#if @const_nop@ >= NPY_MAXDIMS + int nop = NIT_NOP(iter); +#else + const int nop = @const_nop@; +#endif + + int iop; + + NpyIter_AxisData *axisdata; + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + char **ptrs; + char *prev_dataptrs[NPY_MAXARGS]; + + ptrs = NBF_PTRS(bufferdata); + + /* + * If the iterator handles the inner loop, need to increment all + * the indices and pointers + */ + if (!(itflags&NPY_ITFLAG_EXLOOP)) { + /* Increment within the buffer */ + if (++NIT_ITERINDEX(iter) < NBF_BUFITEREND(bufferdata)) { + npy_intp *strides; + + strides = NBF_STRIDES(bufferdata); + for (iop = 0; iop < nop; ++iop) { + ptrs[iop] += strides[iop]; + } + return 1; + } + } + else { + NIT_ITERINDEX(iter) += NBF_SIZE(bufferdata); + } + + NPY_IT_DBG_PRINT1("Iterator: Finished iteration %d of outer reduce loop\n", + (int)NBF_REDUCE_POS(bufferdata)); + /* The outer increment for the reduce double loop */ + if (++NBF_REDUCE_POS(bufferdata) < NBF_REDUCE_OUTERSIZE(bufferdata)) { + npy_intp *reduce_outerstrides = NBF_REDUCE_OUTERSTRIDES(bufferdata); + char **reduce_outerptrs = NBF_REDUCE_OUTERPTRS(bufferdata); + for (iop = 0; iop < nop; ++iop) { + char *ptr = reduce_outerptrs[iop] + reduce_outerstrides[iop]; + ptrs[iop] = ptr; + reduce_outerptrs[iop] = ptr; + } + NBF_BUFITEREND(bufferdata) = NIT_ITERINDEX(iter) + NBF_SIZE(bufferdata); + return 1; + } + + /* Save the previously used data pointers */ + axisdata = NIT_AXISDATA(iter); + memcpy(prev_dataptrs, NAD_PTRS(axisdata), NPY_SIZEOF_INTP*nop); + + /* Write back to the arrays */ + npyiter_copy_from_buffers(iter); + + /* Check if we're past the end */ + if (NIT_ITERINDEX(iter) >= NIT_ITEREND(iter)) { + NBF_SIZE(bufferdata) = 0; + return 0; + } + /* Increment to the next buffer */ + else { + npyiter_goto_iterindex(iter, NIT_ITERINDEX(iter)); + } + + /* Prepare the next buffers and set iterend/size */ + npyiter_copy_to_buffers(iter, prev_dataptrs); + + return 1; +} + +/**end repeat**/ + +/* iternext function that handles the buffering part */ +static int +npyiter_buffered_iternext(NpyIter *iter) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + /*int ndim = NIT_NDIM(iter);*/ + int nop = NIT_NOP(iter); + + NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter); + + /* + * If the iterator handles the inner loop, need to increment all + * the indices and pointers + */ + if (!(itflags&NPY_ITFLAG_EXLOOP)) { + /* Increment within the buffer */ + if (++NIT_ITERINDEX(iter) < NBF_BUFITEREND(bufferdata)) { + int iop; + npy_intp *strides; + char **ptrs; + + strides = NBF_STRIDES(bufferdata); + ptrs = NBF_PTRS(bufferdata); + for (iop = 0; iop < nop; ++iop) { + ptrs[iop] += strides[iop]; + } + return 1; + } + } + else { + NIT_ITERINDEX(iter) += NBF_SIZE(bufferdata); + } + + /* Write back to the arrays */ + npyiter_copy_from_buffers(iter); + + /* Check if we're past the end */ + if (NIT_ITERINDEX(iter) >= NIT_ITEREND(iter)) { + NBF_SIZE(bufferdata) = 0; + return 0; + } + /* Increment to the next buffer */ + else { + npyiter_goto_iterindex(iter, NIT_ITERINDEX(iter)); + } + + /* Prepare the next buffers and set iterend/size */ + npyiter_copy_to_buffers(iter, NULL); + + return 1; +} + +/**end repeat2**/ +/**end repeat1**/ +/**end repeat**/ + +/* Specialization of iternext for when the iteration size is 1 */ +static int +npyiter_iternext_sizeone(NpyIter *iter) +{ + return 0; +} + +/*NUMPY_API + * Compute the specialized iteration function for an iterator + * + * If errmsg is non-NULL, it should point to a variable which will + * receive the error message, and no Python exception will be set. + * This is so that the function can be called from code not holding + * the GIL. + */ +NPY_NO_EXPORT NpyIter_IterNextFunc * +NpyIter_GetIterNext(NpyIter *iter, char **errmsg) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + if (NIT_ITERSIZE(iter) < 0) { + if (errmsg == NULL) { + PyErr_SetString(PyExc_ValueError, "iterator is too large"); + } + else { + *errmsg = "iterator is too large"; + } + return NULL; + } + + /* + * When there is just one iteration and buffering is disabled + * the iternext function is very simple. + */ + if (itflags&NPY_ITFLAG_ONEITERATION) { + return &npyiter_iternext_sizeone; + } + + /* + * If buffering is enabled. + */ + if (itflags&NPY_ITFLAG_BUFFER) { + if (itflags&NPY_ITFLAG_REDUCE) { + switch (nop) { + case 1: + return &npyiter_buffered_reduce_iternext_iters1; + case 2: + return &npyiter_buffered_reduce_iternext_iters2; + case 3: + return &npyiter_buffered_reduce_iternext_iters3; + case 4: + return &npyiter_buffered_reduce_iternext_iters4; + default: + return &npyiter_buffered_reduce_iternext_itersANY; + } + } + else { + return &npyiter_buffered_iternext; + } + } + + /* + * Ignore all the flags that don't affect the iterator memory + * layout or the iternext function. Currently only HASINDEX, + * EXLOOP, and RANGE affect them here. + */ + itflags &= (NPY_ITFLAG_HASINDEX|NPY_ITFLAG_EXLOOP|NPY_ITFLAG_RANGE); + + /* Switch statements let the compiler optimize this most effectively */ + switch (itflags) { + /* + * The combinations HASINDEX|EXLOOP and RANGE|EXLOOP are excluded + * by the New functions + */ +/**begin repeat + * #const_itflags = 0, + * NPY_ITFLAG_HASINDEX, + * NPY_ITFLAG_EXLOOP, + * NPY_ITFLAG_RANGE, + * NPY_ITFLAG_RANGE|NPY_ITFLAG_HASINDEX# + * #tag_itflags = 0, IND, NOINN, RNG, RNGuIND# + */ + case @const_itflags@: + switch (ndim) { +/**begin repeat1 + * #const_ndim = 1, 2# + * #tag_ndim = 1, 2# + */ + case @const_ndim@: + switch (nop) { +/**begin repeat2 + * #const_nop = 1, 2# + * #tag_nop = 1, 2# + */ + case @const_nop@: + return &npyiter_iternext_itflags@tag_itflags@_dims@tag_ndim@_iters@tag_nop@; +/**end repeat2**/ + /* Not specialized on nop */ + default: + return &npyiter_iternext_itflags@tag_itflags@_dims@tag_ndim@_itersANY; + } +/**end repeat1**/ + /* Not specialized on ndim */ + default: + switch (nop) { +/**begin repeat1 + * #const_nop = 1, 2# + * #tag_nop = 1, 2# + */ + case @const_nop@: + return &npyiter_iternext_itflags@tag_itflags@_dimsANY_iters@tag_nop@; +/**end repeat1**/ + /* Not specialized on nop */ + default: + return &npyiter_iternext_itflags@tag_itflags@_dimsANY_itersANY; + } + } +/**end repeat**/ + } + /* The switch above should have caught all the possibilities. */ + if (errmsg == NULL) { + PyErr_Format(PyExc_ValueError, + "GetIterNext internal iterator error - unexpected " + "itflags/ndim/nop combination (%04x/%d/%d)", + (int)itflags, (int)ndim, (int)nop); + } + else { + *errmsg = "GetIterNext internal iterator error - unexpected " + "itflags/ndim/nop combination"; + } + return NULL; +} + + +/* SPECIALIZED getindex functions */ + +/**begin repeat + * #const_itflags = 0, + * NPY_ITFLAG_HASINDEX, + * NPY_ITFLAG_IDENTPERM, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_IDENTPERM, + * NPY_ITFLAG_NEGPERM, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_NEGPERM, + * NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_NEGPERM|NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_NEGPERM|NPY_ITFLAG_BUFFER# + * #tag_itflags = 0, IND, IDP, INDuIDP, NEGP, INDuNEGP, + * BUF, INDuBUF, IDPuBUF, INDuIDPuBUF, NEGPuBUF, INDuNEGPuBUF# + */ +static void +npyiter_get_multi_index_itflags@tag_itflags@( + NpyIter *iter, npy_intp *out_multi_index) +{ + const npy_uint32 itflags = @const_itflags@; + int idim, ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + npy_intp sizeof_axisdata; + NpyIter_AxisData *axisdata; +#if !((@const_itflags@)&NPY_ITFLAG_IDENTPERM) + npy_int8 *perm = NIT_PERM(iter); +#endif + + axisdata = NIT_AXISDATA(iter); + sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); +#if ((@const_itflags@)&NPY_ITFLAG_IDENTPERM) + out_multi_index += ndim-1; + for(idim = 0; idim < ndim; ++idim, --out_multi_index, + NIT_ADVANCE_AXISDATA(axisdata, 1)) { + *out_multi_index = NAD_INDEX(axisdata); + } +#elif !((@const_itflags@)&NPY_ITFLAG_NEGPERM) + for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + npy_int8 p = perm[idim]; + out_multi_index[ndim-p-1] = NAD_INDEX(axisdata); + } +#else + for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { + npy_int8 p = perm[idim]; + if (p < 0) { + /* If the perm entry is negative, reverse the index */ + out_multi_index[ndim+p] = NAD_SHAPE(axisdata) - NAD_INDEX(axisdata) - 1; + } + else { + out_multi_index[ndim-p-1] = NAD_INDEX(axisdata); + } + } +#endif /* not ident perm */ +} +/**end repeat**/ + +/*NUMPY_API + * Compute a specialized get_multi_index function for the iterator + * + * If errmsg is non-NULL, it should point to a variable which will + * receive the error message, and no Python exception will be set. + * This is so that the function can be called from code not holding + * the GIL. + */ +NPY_NO_EXPORT NpyIter_GetMultiIndexFunc * +NpyIter_GetGetMultiIndex(NpyIter *iter, char **errmsg) +{ + npy_uint32 itflags = NIT_ITFLAGS(iter); + int ndim = NIT_NDIM(iter); + int nop = NIT_NOP(iter); + + /* These flags must be correct */ + if ((itflags&(NPY_ITFLAG_HASMULTIINDEX|NPY_ITFLAG_DELAYBUF)) != + NPY_ITFLAG_HASMULTIINDEX) { + if (!(itflags&NPY_ITFLAG_HASMULTIINDEX)) { + if (errmsg == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot retrieve a GetMultiIndex function for an " + "iterator that doesn't track a multi-index."); + } + else { + *errmsg = "Cannot retrieve a GetMultiIndex function for an " + "iterator that doesn't track a multi-index."; + } + return NULL; + } + else { + if (errmsg == NULL) { + PyErr_SetString(PyExc_ValueError, + "Cannot retrieve a GetMultiIndex function for an " + "iterator that used DELAY_BUFALLOC before a Reset call"); + } + else { + *errmsg = "Cannot retrieve a GetMultiIndex function for an " + "iterator that used DELAY_BUFALLOC before a " + "Reset call"; + } + return NULL; + } + } + + /* + * Only these flags affect the iterator memory layout or + * the get_multi_index behavior. IDENTPERM and NEGPERM are mutually + * exclusive, so that reduces the number of cases slightly. + */ + itflags &= (NPY_ITFLAG_HASINDEX | + NPY_ITFLAG_IDENTPERM | + NPY_ITFLAG_NEGPERM | + NPY_ITFLAG_BUFFER); + + switch (itflags) { +/**begin repeat + * #const_itflags = 0, + * NPY_ITFLAG_HASINDEX, + * NPY_ITFLAG_IDENTPERM, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_IDENTPERM, + * NPY_ITFLAG_NEGPERM, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_NEGPERM, + * NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_NEGPERM|NPY_ITFLAG_BUFFER, + * NPY_ITFLAG_HASINDEX|NPY_ITFLAG_NEGPERM|NPY_ITFLAG_BUFFER# + * #tag_itflags = 0, IND, IDP, INDuIDP, NEGP, INDuNEGP, + * BUF, INDuBUF, IDPuBUF, INDuIDPuBUF, NEGPuBUF, INDuNEGPuBUF# + */ + case @const_itflags@: + return npyiter_get_multi_index_itflags@tag_itflags@; +/**end repeat**/ + } + /* The switch above should have caught all the possibilities. */ + if (errmsg == NULL) { + PyErr_Format(PyExc_ValueError, + "GetGetMultiIndex internal iterator error - unexpected " + "itflags/ndim/nop combination (%04x/%d/%d)", + (int)itflags, (int)ndim, (int)nop); + } + else { + *errmsg = "GetGetMultiIndex internal iterator error - unexpected " + "itflags/ndim/nop combination"; + } + return NULL; + +} + +#undef NPY_ITERATOR_IMPLEMENTATION_CODE diff --git a/numpy/core/src/multiarray/number.c b/numpy/core/src/multiarray/number.c new file mode 100644 index 0000000..915d743 --- /dev/null +++ b/numpy/core/src/multiarray/number.c @@ -0,0 +1,1016 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +/*#include */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" + +#include "npy_config.h" +#include "npy_pycompat.h" +#include "npy_import.h" +#include "common.h" +#include "number.h" +#include "temp_elide.h" + +#include "binop_override.h" + +/* <2.7.11 and <3.4.4 have the wrong argument type for Py_EnterRecursiveCall */ +#if (PY_VERSION_HEX < 0x02070B00) || \ + ((0x03000000 <= PY_VERSION_HEX) && (PY_VERSION_HEX < 0x03040400)) + #define _Py_EnterRecursiveCall(x) Py_EnterRecursiveCall((char *)(x)) +#else + #define _Py_EnterRecursiveCall(x) Py_EnterRecursiveCall(x) +#endif + + +/************************************************************************* + **************** Implement Number Protocol **************************** + *************************************************************************/ + +NPY_NO_EXPORT NumericOps n_ops; /* NB: static objects initialized to zero */ + +/* + * Forward declarations. Might want to move functions around instead + */ +static PyObject * +array_inplace_add(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_subtract(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_multiply(PyArrayObject *m1, PyObject *m2); +#if !defined(NPY_PY3K) +static PyObject * +array_inplace_divide(PyArrayObject *m1, PyObject *m2); +#endif +static PyObject * +array_inplace_true_divide(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_floor_divide(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_bitwise_and(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_bitwise_or(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_bitwise_xor(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_left_shift(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_right_shift(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_remainder(PyArrayObject *m1, PyObject *m2); +static PyObject * +array_inplace_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo)); + +/* + * Dictionary can contain any of the numeric operations, by name. + * Those not present will not be changed + */ + +/* FIXME - macro contains a return */ +#define SET(op) temp = PyDict_GetItemString(dict, #op); \ + if (temp != NULL) { \ + if (!(PyCallable_Check(temp))) { \ + return -1; \ + } \ + Py_INCREF(temp); \ + Py_XDECREF(n_ops.op); \ + n_ops.op = temp; \ + } + + +/*NUMPY_API + *Set internal structure with number functions that all arrays will use + */ +NPY_NO_EXPORT int +PyArray_SetNumericOps(PyObject *dict) +{ + PyObject *temp = NULL; + SET(add); + SET(subtract); + SET(multiply); + SET(divide); + SET(remainder); + SET(divmod); + SET(power); + SET(square); + SET(reciprocal); + SET(_ones_like); + SET(sqrt); + SET(cbrt); + SET(negative); + SET(positive); + SET(absolute); + SET(invert); + SET(left_shift); + SET(right_shift); + SET(bitwise_and); + SET(bitwise_or); + SET(bitwise_xor); + SET(less); + SET(less_equal); + SET(equal); + SET(not_equal); + SET(greater); + SET(greater_equal); + SET(floor_divide); + SET(true_divide); + SET(logical_or); + SET(logical_and); + SET(floor); + SET(ceil); + SET(maximum); + SET(minimum); + SET(rint); + SET(conjugate); + return 0; +} + +/* FIXME - macro contains goto */ +#define GET(op) if (n_ops.op && \ + (PyDict_SetItemString(dict, #op, n_ops.op)==-1)) \ + goto fail; + +/*NUMPY_API + Get dictionary showing number functions that all arrays will use +*/ +NPY_NO_EXPORT PyObject * +PyArray_GetNumericOps(void) +{ + PyObject *dict; + if ((dict = PyDict_New())==NULL) + return NULL; + GET(add); + GET(subtract); + GET(multiply); + GET(divide); + GET(remainder); + GET(divmod); + GET(power); + GET(square); + GET(reciprocal); + GET(_ones_like); + GET(sqrt); + GET(negative); + GET(positive); + GET(absolute); + GET(invert); + GET(left_shift); + GET(right_shift); + GET(bitwise_and); + GET(bitwise_or); + GET(bitwise_xor); + GET(less); + GET(less_equal); + GET(equal); + GET(not_equal); + GET(greater); + GET(greater_equal); + GET(floor_divide); + GET(true_divide); + GET(logical_or); + GET(logical_and); + GET(floor); + GET(ceil); + GET(maximum); + GET(minimum); + GET(rint); + GET(conjugate); + return dict; + + fail: + Py_DECREF(dict); + return NULL; +} + +static PyObject * +_get_keywords(int rtype, PyArrayObject *out) +{ + PyObject *kwds = NULL; + if (rtype != NPY_NOTYPE || out != NULL) { + kwds = PyDict_New(); + if (rtype != NPY_NOTYPE) { + PyArray_Descr *descr; + descr = PyArray_DescrFromType(rtype); + if (descr) { + PyDict_SetItemString(kwds, "dtype", (PyObject *)descr); + Py_DECREF(descr); + } + } + if (out != NULL) { + PyDict_SetItemString(kwds, "out", (PyObject *)out); + } + } + return kwds; +} + +NPY_NO_EXPORT PyObject * +PyArray_GenericReduceFunction(PyArrayObject *m1, PyObject *op, int axis, + int rtype, PyArrayObject *out) +{ + PyObject *args, *ret = NULL, *meth; + PyObject *kwds; + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + args = Py_BuildValue("(Oi)", m1, axis); + kwds = _get_keywords(rtype, out); + meth = PyObject_GetAttrString(op, "reduce"); + if (meth && PyCallable_Check(meth)) { + ret = PyObject_Call(meth, args, kwds); + } + Py_DECREF(args); + Py_DECREF(meth); + Py_XDECREF(kwds); + return ret; +} + + +NPY_NO_EXPORT PyObject * +PyArray_GenericAccumulateFunction(PyArrayObject *m1, PyObject *op, int axis, + int rtype, PyArrayObject *out) +{ + PyObject *args, *ret = NULL, *meth; + PyObject *kwds; + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + args = Py_BuildValue("(Oi)", m1, axis); + kwds = _get_keywords(rtype, out); + meth = PyObject_GetAttrString(op, "accumulate"); + if (meth && PyCallable_Check(meth)) { + ret = PyObject_Call(meth, args, kwds); + } + Py_DECREF(args); + Py_DECREF(meth); + Py_XDECREF(kwds); + return ret; +} + + +NPY_NO_EXPORT PyObject * +PyArray_GenericBinaryFunction(PyArrayObject *m1, PyObject *m2, PyObject *op) +{ + /* + * I suspect that the next few lines are buggy and cause NotImplemented to + * be returned at weird times... but if we raise an error here, then + * *everything* breaks. (Like, 'arange(10) + 1' and just + * 'repr(arange(10))' both blow up with an error here.) Not sure what's + * going on with that, but I'll leave it alone for now. - njs, 2015-06-21 + */ + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + return PyObject_CallFunctionObjArgs(op, m1, m2, NULL); +} + +NPY_NO_EXPORT PyObject * +PyArray_GenericUnaryFunction(PyArrayObject *m1, PyObject *op) +{ + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyObject_CallFunctionObjArgs(op, m1, NULL); +} + +static PyObject * +PyArray_GenericInplaceBinaryFunction(PyArrayObject *m1, + PyObject *m2, PyObject *op) +{ + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyObject_CallFunctionObjArgs(op, m1, m2, m1, NULL); +} + +static PyObject * +PyArray_GenericInplaceUnaryFunction(PyArrayObject *m1, PyObject *op) +{ + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyObject_CallFunctionObjArgs(op, m1, m1, NULL); +} + +static PyObject * +array_add(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_add, array_add); + if (try_binary_elide(m1, m2, &array_inplace_add, &res, 1)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.add); +} + +static PyObject * +array_subtract(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_subtract, array_subtract); + if (try_binary_elide(m1, m2, &array_inplace_subtract, &res, 0)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.subtract); +} + +static PyObject * +array_multiply(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_multiply, array_multiply); + if (try_binary_elide(m1, m2, &array_inplace_multiply, &res, 1)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.multiply); +} + +#if !defined(NPY_PY3K) +static PyObject * +array_divide(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_divide, array_divide); + if (try_binary_elide(m1, m2, &array_inplace_divide, &res, 0)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.divide); +} +#endif + +static PyObject * +array_remainder(PyArrayObject *m1, PyObject *m2) +{ + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_remainder, array_remainder); + return PyArray_GenericBinaryFunction(m1, m2, n_ops.remainder); +} + +static PyObject * +array_divmod(PyArrayObject *m1, PyObject *m2) +{ + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_divmod, array_divmod); + return PyArray_GenericBinaryFunction(m1, m2, n_ops.divmod); +} + +#if PY_VERSION_HEX >= 0x03050000 +/* Need this to be version dependent on account of the slot check */ +static PyObject * +array_matrix_multiply(PyArrayObject *m1, PyObject *m2) +{ + static PyObject *matmul = NULL; + + npy_cache_import("numpy.core.multiarray", "matmul", &matmul); + if (matmul == NULL) { + return NULL; + } + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_matrix_multiply, array_matrix_multiply); + return PyArray_GenericBinaryFunction(m1, m2, matmul); +} + +static PyObject * +array_inplace_matrix_multiply(PyArrayObject *m1, PyObject *m2) +{ + PyErr_SetString(PyExc_TypeError, + "In-place matrix multiplication is not (yet) supported. " + "Use 'a = a @ b' instead of 'a @= b'."); + return NULL; +} +#endif + +/* + * Determine if object is a scalar and if so, convert the object + * to a double and place it in the out_exponent argument + * and return the "scalar kind" as a result. If the object is + * not a scalar (or if there are other error conditions) + * return NPY_NOSCALAR, and out_exponent is undefined. + */ +static NPY_SCALARKIND +is_scalar_with_conversion(PyObject *o2, double* out_exponent) +{ + PyObject *temp; + const int optimize_fpexps = 1; + + if (PyInt_Check(o2)) { + *out_exponent = (double)PyInt_AsLong(o2); + return NPY_INTPOS_SCALAR; + } + if (optimize_fpexps && PyFloat_Check(o2)) { + *out_exponent = PyFloat_AsDouble(o2); + return NPY_FLOAT_SCALAR; + } + if (PyArray_Check(o2)) { + if ((PyArray_NDIM((PyArrayObject *)o2) == 0) && + ((PyArray_ISINTEGER((PyArrayObject *)o2) || + (optimize_fpexps && PyArray_ISFLOAT((PyArrayObject *)o2))))) { + temp = Py_TYPE(o2)->tp_as_number->nb_float(o2); + if (temp == NULL) { + return NPY_NOSCALAR; + } + *out_exponent = PyFloat_AsDouble(o2); + Py_DECREF(temp); + if (PyArray_ISINTEGER((PyArrayObject *)o2)) { + return NPY_INTPOS_SCALAR; + } + else { /* ISFLOAT */ + return NPY_FLOAT_SCALAR; + } + } + } + else if (PyArray_IsScalar(o2, Integer) || + (optimize_fpexps && PyArray_IsScalar(o2, Floating))) { + temp = Py_TYPE(o2)->tp_as_number->nb_float(o2); + if (temp == NULL) { + return NPY_NOSCALAR; + } + *out_exponent = PyFloat_AsDouble(o2); + Py_DECREF(temp); + + if (PyArray_IsScalar(o2, Integer)) { + return NPY_INTPOS_SCALAR; + } + else { /* IsScalar(o2, Floating) */ + return NPY_FLOAT_SCALAR; + } + } + else if (PyIndex_Check(o2)) { + PyObject* value = PyNumber_Index(o2); + Py_ssize_t val; + if (value==NULL) { + if (PyErr_Occurred()) { + PyErr_Clear(); + } + return NPY_NOSCALAR; + } + val = PyInt_AsSsize_t(value); + if (error_converting(val)) { + PyErr_Clear(); + return NPY_NOSCALAR; + } + *out_exponent = (double) val; + return NPY_INTPOS_SCALAR; + } + return NPY_NOSCALAR; +} + +/* + * optimize float array or complex array to a scalar power + * returns 0 on success, -1 if no optimization is possible + * the result is in value (can be NULL if an error occurred) + */ +static int +fast_scalar_power(PyArrayObject *a1, PyObject *o2, int inplace, + PyObject **value) +{ + double exponent; + NPY_SCALARKIND kind; /* NPY_NOSCALAR is not scalar */ + + if (PyArray_Check(a1) && ((kind=is_scalar_with_conversion(o2, &exponent))>0)) { + PyObject *fastop = NULL; + if (PyArray_ISFLOAT(a1) || PyArray_ISCOMPLEX(a1)) { + if (exponent == 1.0) { + fastop = n_ops.positive; + } + else if (exponent == -1.0) { + fastop = n_ops.reciprocal; + } + else if (exponent == 0.0) { + fastop = n_ops._ones_like; + } + else if (exponent == 0.5) { + fastop = n_ops.sqrt; + } + else if (exponent == 2.0) { + fastop = n_ops.square; + } + else { + return -1; + } + + if (inplace || can_elide_temp_unary(a1)) { + *value = PyArray_GenericInplaceUnaryFunction(a1, fastop); + } + else { + *value = PyArray_GenericUnaryFunction(a1, fastop); + } + return 0; + } + /* Because this is called with all arrays, we need to + * change the output if the kind of the scalar is different + * than that of the input and inplace is not on --- + * (thus, the input should be up-cast) + */ + else if (exponent == 2.0) { + fastop = n_ops.square; + if (inplace) { + *value = PyArray_GenericInplaceUnaryFunction(a1, fastop); + } + else { + /* We only special-case the FLOAT_SCALAR and integer types */ + if (kind == NPY_FLOAT_SCALAR && PyArray_ISINTEGER(a1)) { + PyArray_Descr *dtype = PyArray_DescrFromType(NPY_DOUBLE); + a1 = (PyArrayObject *)PyArray_CastToType(a1, dtype, + PyArray_ISFORTRAN(a1)); + if (a1 != NULL) { + /* cast always creates a new array */ + *value = PyArray_GenericInplaceUnaryFunction(a1, fastop); + Py_DECREF(a1); + } + } + else { + *value = PyArray_GenericUnaryFunction(a1, fastop); + } + } + return 0; + } + } + /* no fast operation found */ + return -1; +} + +static PyObject * +array_power(PyArrayObject *a1, PyObject *o2, PyObject *modulo) +{ + PyObject *value = NULL; + + if (modulo != Py_None) { + /* modular exponentiation is not implemented (gh-8804) */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + BINOP_GIVE_UP_IF_NEEDED(a1, o2, nb_power, array_power); + if (fast_scalar_power(a1, o2, 0, &value) != 0) { + value = PyArray_GenericBinaryFunction(a1, o2, n_ops.power); + } + return value; +} + + +static PyObject * +array_negative(PyArrayObject *m1) +{ + if (can_elide_temp_unary(m1)) { + return PyArray_GenericInplaceUnaryFunction(m1, n_ops.negative); + } + return PyArray_GenericUnaryFunction(m1, n_ops.negative); +} + +static PyObject * +array_absolute(PyArrayObject *m1) +{ + if (can_elide_temp_unary(m1) && !PyArray_ISCOMPLEX(m1)) { + return PyArray_GenericInplaceUnaryFunction(m1, n_ops.absolute); + } + return PyArray_GenericUnaryFunction(m1, n_ops.absolute); +} + +static PyObject * +array_invert(PyArrayObject *m1) +{ + if (can_elide_temp_unary(m1)) { + return PyArray_GenericInplaceUnaryFunction(m1, n_ops.invert); + } + return PyArray_GenericUnaryFunction(m1, n_ops.invert); +} + +static PyObject * +array_left_shift(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_lshift, array_left_shift); + if (try_binary_elide(m1, m2, &array_inplace_left_shift, &res, 0)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.left_shift); +} + +static PyObject * +array_right_shift(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_rshift, array_right_shift); + if (try_binary_elide(m1, m2, &array_inplace_right_shift, &res, 0)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.right_shift); +} + +static PyObject * +array_bitwise_and(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_and, array_bitwise_and); + if (try_binary_elide(m1, m2, &array_inplace_bitwise_and, &res, 1)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_and); +} + +static PyObject * +array_bitwise_or(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_or, array_bitwise_or); + if (try_binary_elide(m1, m2, &array_inplace_bitwise_or, &res, 1)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_or); +} + +static PyObject * +array_bitwise_xor(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_xor, array_bitwise_xor); + if (try_binary_elide(m1, m2, &array_inplace_bitwise_xor, &res, 1)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_xor); +} + +static PyObject * +array_inplace_add(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_add, array_inplace_add); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.add); +} + +static PyObject * +array_inplace_subtract(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_subtract, array_inplace_subtract); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.subtract); +} + +static PyObject * +array_inplace_multiply(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_multiply, array_inplace_multiply); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.multiply); +} + +#if !defined(NPY_PY3K) +static PyObject * +array_inplace_divide(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_divide, array_inplace_divide); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.divide); +} +#endif + +static PyObject * +array_inplace_remainder(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_remainder, array_inplace_remainder); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.remainder); +} + +static PyObject * +array_inplace_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo)) +{ + /* modulo is ignored! */ + PyObject *value = NULL; + + INPLACE_GIVE_UP_IF_NEEDED( + a1, o2, nb_inplace_power, array_inplace_power); + if (fast_scalar_power(a1, o2, 1, &value) != 0) { + value = PyArray_GenericInplaceBinaryFunction(a1, o2, n_ops.power); + } + return value; +} + +static PyObject * +array_inplace_left_shift(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_lshift, array_inplace_left_shift); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.left_shift); +} + +static PyObject * +array_inplace_right_shift(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_rshift, array_inplace_right_shift); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.right_shift); +} + +static PyObject * +array_inplace_bitwise_and(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_and, array_inplace_bitwise_and); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_and); +} + +static PyObject * +array_inplace_bitwise_or(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_or, array_inplace_bitwise_or); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_or); +} + +static PyObject * +array_inplace_bitwise_xor(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_xor, array_inplace_bitwise_xor); + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_xor); +} + +static PyObject * +array_floor_divide(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_floor_divide, array_floor_divide); + if (try_binary_elide(m1, m2, &array_inplace_floor_divide, &res, 0)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.floor_divide); +} + +static PyObject * +array_true_divide(PyArrayObject *m1, PyObject *m2) +{ + PyObject *res; + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_true_divide, array_true_divide); + if (PyArray_CheckExact(m1) && + (PyArray_ISFLOAT(m1) || PyArray_ISCOMPLEX(m1)) && + try_binary_elide(m1, m2, &array_inplace_true_divide, &res, 0)) { + return res; + } + return PyArray_GenericBinaryFunction(m1, m2, n_ops.true_divide); +} + +static PyObject * +array_inplace_floor_divide(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_floor_divide, array_inplace_floor_divide); + return PyArray_GenericInplaceBinaryFunction(m1, m2, + n_ops.floor_divide); +} + +static PyObject * +array_inplace_true_divide(PyArrayObject *m1, PyObject *m2) +{ + INPLACE_GIVE_UP_IF_NEEDED( + m1, m2, nb_inplace_true_divide, array_inplace_true_divide); + return PyArray_GenericInplaceBinaryFunction(m1, m2, + n_ops.true_divide); +} + + +static int +_array_nonzero(PyArrayObject *mp) +{ + npy_intp n; + + n = PyArray_SIZE(mp); + if (n == 1) { + int res; + if (_Py_EnterRecursiveCall(" while converting array to bool")) { + return -1; + } + res = PyArray_DESCR(mp)->f->nonzero(PyArray_DATA(mp), mp); + /* nonzero has no way to indicate an error, but one can occur */ + if (PyErr_Occurred()) { + res = -1; + } + Py_LeaveRecursiveCall(); + return res; + } + else if (n == 0) { + /* 2017-09-25, 1.14 */ + if (DEPRECATE("The truth value of an empty array is ambiguous. " + "Returning False, but in future this will result in an error. " + "Use `array.size > 0` to check that an array is not empty.") < 0) { + return -1; + } + return 0; + } + else { + PyErr_SetString(PyExc_ValueError, + "The truth value of an array " + "with more than one element is ambiguous. " + "Use a.any() or a.all()"); + return -1; + } +} + +/* + * Convert the array to a scalar if allowed, and apply the builtin function + * to it. The where argument is passed onto Py_EnterRecursiveCall when the + * array contains python objects. + */ +NPY_NO_EXPORT PyObject * +array_scalar_forward(PyArrayObject *v, + PyObject *(*builtin_func)(PyObject *), + const char *where) +{ + PyObject *scalar; + if (PyArray_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, "only size-1 arrays can be"\ + " converted to Python scalars"); + return NULL; + } + + scalar = PyArray_GETITEM(v, PyArray_DATA(v)); + if (scalar == NULL) { + return NULL; + } + + /* Need to guard against recursion if our array holds references */ + if (PyDataType_REFCHK(PyArray_DESCR(v))) { + PyObject *res; + if (_Py_EnterRecursiveCall(where) != 0) { + Py_DECREF(scalar); + return NULL; + } + res = builtin_func(scalar); + Py_DECREF(scalar); + Py_LeaveRecursiveCall(); + return res; + } + else { + PyObject *res; + res = builtin_func(scalar); + Py_DECREF(scalar); + return res; + } +} + + +NPY_NO_EXPORT PyObject * +array_float(PyArrayObject *v) +{ + return array_scalar_forward(v, &PyNumber_Float, " in ndarray.__float__"); +} + +#if defined(NPY_PY3K) + +NPY_NO_EXPORT PyObject * +array_int(PyArrayObject *v) +{ + return array_scalar_forward(v, &PyNumber_Long, " in ndarray.__int__"); +} + +#else + +NPY_NO_EXPORT PyObject * +array_int(PyArrayObject *v) +{ + return array_scalar_forward(v, &PyNumber_Int, " in ndarray.__int__"); +} + +NPY_NO_EXPORT PyObject * +array_long(PyArrayObject *v) +{ + return array_scalar_forward(v, &PyNumber_Long, " in ndarray.__long__"); +} + +/* hex and oct aren't exposed to the C api, but we need a function pointer */ +static PyObject * +_PyNumber_Oct(PyObject *o) { + PyObject *res; + PyObject *mod = PyImport_ImportModule("__builtin__"); + if (mod == NULL) { + return NULL; + } + res = PyObject_CallMethod(mod, "oct", "(O)", o); + Py_DECREF(mod); + return res; +} + +static PyObject * +_PyNumber_Hex(PyObject *o) { + PyObject *res; + PyObject *mod = PyImport_ImportModule("__builtin__"); + if (mod == NULL) { + return NULL; + } + res = PyObject_CallMethod(mod, "hex", "(O)", o); + Py_DECREF(mod); + return res; +} + +NPY_NO_EXPORT PyObject * +array_oct(PyArrayObject *v) +{ + return array_scalar_forward(v, &_PyNumber_Oct, " in ndarray.__oct__"); +} + +NPY_NO_EXPORT PyObject * +array_hex(PyArrayObject *v) +{ + return array_scalar_forward(v, &_PyNumber_Hex, " in ndarray.__hex__"); +} + +#endif + +static PyObject * +_array_copy_nice(PyArrayObject *self) +{ + return PyArray_Return((PyArrayObject *) PyArray_Copy(self)); +} + +static PyObject * +array_index(PyArrayObject *v) +{ + if (!PyArray_ISINTEGER(v) || PyArray_NDIM(v) != 0) { + PyErr_SetString(PyExc_TypeError, + "only integer scalar arrays can be converted to a scalar index"); + return NULL; + } + return PyArray_GETITEM(v, PyArray_DATA(v)); +} + + +NPY_NO_EXPORT PyNumberMethods array_as_number = { + (binaryfunc)array_add, /*nb_add*/ + (binaryfunc)array_subtract, /*nb_subtract*/ + (binaryfunc)array_multiply, /*nb_multiply*/ +#if !defined(NPY_PY3K) + (binaryfunc)array_divide, /*nb_divide*/ +#endif + (binaryfunc)array_remainder, /*nb_remainder*/ + (binaryfunc)array_divmod, /*nb_divmod*/ + (ternaryfunc)array_power, /*nb_power*/ + (unaryfunc)array_negative, /*nb_neg*/ + (unaryfunc)_array_copy_nice, /*nb_pos*/ + (unaryfunc)array_absolute, /*(unaryfunc)array_abs,*/ + (inquiry)_array_nonzero, /*nb_nonzero*/ + (unaryfunc)array_invert, /*nb_invert*/ + (binaryfunc)array_left_shift, /*nb_lshift*/ + (binaryfunc)array_right_shift, /*nb_rshift*/ + (binaryfunc)array_bitwise_and, /*nb_and*/ + (binaryfunc)array_bitwise_xor, /*nb_xor*/ + (binaryfunc)array_bitwise_or, /*nb_or*/ +#if !defined(NPY_PY3K) + 0, /*nb_coerce*/ +#endif + (unaryfunc)array_int, /*nb_int*/ +#if defined(NPY_PY3K) + 0, /*nb_reserved*/ +#else + (unaryfunc)array_long, /*nb_long*/ +#endif + (unaryfunc)array_float, /*nb_float*/ +#if !defined(NPY_PY3K) + (unaryfunc)array_oct, /*nb_oct*/ + (unaryfunc)array_hex, /*nb_hex*/ +#endif + + /* + * This code adds augmented assignment functionality + * that was made available in Python 2.0 + */ + (binaryfunc)array_inplace_add, /*nb_inplace_add*/ + (binaryfunc)array_inplace_subtract, /*nb_inplace_subtract*/ + (binaryfunc)array_inplace_multiply, /*nb_inplace_multiply*/ +#if !defined(NPY_PY3K) + (binaryfunc)array_inplace_divide, /*nb_inplace_divide*/ +#endif + (binaryfunc)array_inplace_remainder, /*nb_inplace_remainder*/ + (ternaryfunc)array_inplace_power, /*nb_inplace_power*/ + (binaryfunc)array_inplace_left_shift, /*nb_inplace_lshift*/ + (binaryfunc)array_inplace_right_shift, /*nb_inplace_rshift*/ + (binaryfunc)array_inplace_bitwise_and, /*nb_inplace_and*/ + (binaryfunc)array_inplace_bitwise_xor, /*nb_inplace_xor*/ + (binaryfunc)array_inplace_bitwise_or, /*nb_inplace_or*/ + + (binaryfunc)array_floor_divide, /*nb_floor_divide*/ + (binaryfunc)array_true_divide, /*nb_true_divide*/ + (binaryfunc)array_inplace_floor_divide, /*nb_inplace_floor_divide*/ + (binaryfunc)array_inplace_true_divide, /*nb_inplace_true_divide*/ + (unaryfunc)array_index, /*nb_index */ +#if PY_VERSION_HEX >= 0x03050000 + (binaryfunc)array_matrix_multiply, /*nb_matrix_multiply*/ + (binaryfunc)array_inplace_matrix_multiply, /*nb_inplace_matrix_multiply*/ +#endif +}; diff --git a/numpy/core/src/multiarray/number.h b/numpy/core/src/multiarray/number.h new file mode 100644 index 0000000..99a2a72 --- /dev/null +++ b/numpy/core/src/multiarray/number.h @@ -0,0 +1,70 @@ +#ifndef _NPY_ARRAY_NUMBER_H_ +#define _NPY_ARRAY_NUMBER_H_ + +typedef struct { + PyObject *add; + PyObject *subtract; + PyObject *multiply; + PyObject *divide; + PyObject *remainder; + PyObject *divmod; + PyObject *power; + PyObject *square; + PyObject *reciprocal; + PyObject *_ones_like; + PyObject *sqrt; + PyObject *cbrt; + PyObject *negative; + PyObject *positive; + PyObject *absolute; + PyObject *invert; + PyObject *left_shift; + PyObject *right_shift; + PyObject *bitwise_and; + PyObject *bitwise_xor; + PyObject *bitwise_or; + PyObject *less; + PyObject *less_equal; + PyObject *equal; + PyObject *not_equal; + PyObject *greater; + PyObject *greater_equal; + PyObject *floor_divide; + PyObject *true_divide; + PyObject *logical_or; + PyObject *logical_and; + PyObject *floor; + PyObject *ceil; + PyObject *maximum; + PyObject *minimum; + PyObject *rint; + PyObject *conjugate; +} NumericOps; + +extern NPY_NO_EXPORT NumericOps n_ops; +extern NPY_NO_EXPORT PyNumberMethods array_as_number; + +NPY_NO_EXPORT PyObject * +array_int(PyArrayObject *v); + +NPY_NO_EXPORT int +PyArray_SetNumericOps(PyObject *dict); + +NPY_NO_EXPORT PyObject * +PyArray_GetNumericOps(void); + +NPY_NO_EXPORT PyObject * +PyArray_GenericBinaryFunction(PyArrayObject *m1, PyObject *m2, PyObject *op); + +NPY_NO_EXPORT PyObject * +PyArray_GenericUnaryFunction(PyArrayObject *m1, PyObject *op); + +NPY_NO_EXPORT PyObject * +PyArray_GenericReduceFunction(PyArrayObject *m1, PyObject *op, int axis, + int rtype, PyArrayObject *out); + +NPY_NO_EXPORT PyObject * +PyArray_GenericAccumulateFunction(PyArrayObject *m1, PyObject *op, int axis, + int rtype, PyArrayObject *out); + +#endif diff --git a/numpy/core/src/multiarray/numpyos.c b/numpy/core/src/multiarray/numpyos.c new file mode 100644 index 0000000..e6f4147 --- /dev/null +++ b/numpy/core/src/multiarray/numpyos.c @@ -0,0 +1,771 @@ +#define PY_SSIZE_T_CLEAN +#include + +#include +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/npy_math.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#ifdef HAVE_STRTOLD_L +#include +#ifdef HAVE_XLOCALE_H + /* + * the defines from xlocale.h are included in locale.h on some sytems; + * see gh-8367 + */ + #include +#endif +#endif + + + +/* + * From the C99 standard, section 7.19.6: The exponent always contains at least + * two digits, and only as many more digits as necessary to represent the + * exponent. + */ + +#define MIN_EXPONENT_DIGITS 2 + +/* + * Ensure that any exponent, if present, is at least MIN_EXPONENT_DIGITS + * in length. + */ +static void +ensure_minimum_exponent_length(char* buffer, size_t buf_size) +{ + char *p = strpbrk(buffer, "eE"); + if (p && (*(p + 1) == '-' || *(p + 1) == '+')) { + char *start = p + 2; + int exponent_digit_cnt = 0; + int leading_zero_cnt = 0; + int in_leading_zeros = 1; + int significant_digit_cnt; + + /* Skip over the exponent and the sign. */ + p += 2; + + /* Find the end of the exponent, keeping track of leading zeros. */ + while (*p && isdigit(Py_CHARMASK(*p))) { + if (in_leading_zeros && *p == '0') { + ++leading_zero_cnt; + } + if (*p != '0') { + in_leading_zeros = 0; + } + ++p; + ++exponent_digit_cnt; + } + + significant_digit_cnt = exponent_digit_cnt - leading_zero_cnt; + if (exponent_digit_cnt == MIN_EXPONENT_DIGITS) { + /* + * If there are 2 exactly digits, we're done, + * regardless of what they contain + */ + } + else if (exponent_digit_cnt > MIN_EXPONENT_DIGITS) { + int extra_zeros_cnt; + + /* + * There are more than 2 digits in the exponent. See + * if we can delete some of the leading zeros + */ + if (significant_digit_cnt < MIN_EXPONENT_DIGITS) { + significant_digit_cnt = MIN_EXPONENT_DIGITS; + } + extra_zeros_cnt = exponent_digit_cnt - significant_digit_cnt; + + /* + * Delete extra_zeros_cnt worth of characters from the + * front of the exponent + */ + assert(extra_zeros_cnt >= 0); + + /* + * Add one to significant_digit_cnt to copy the + * trailing 0 byte, thus setting the length + */ + memmove(start, start + extra_zeros_cnt, significant_digit_cnt + 1); + } + else { + /* + * If there are fewer than 2 digits, add zeros + * until there are 2, if there's enough room + */ + int zeros = MIN_EXPONENT_DIGITS - exponent_digit_cnt; + if (start + zeros + exponent_digit_cnt + 1 < buffer + buf_size) { + memmove(start + zeros, start, exponent_digit_cnt + 1); + memset(start, '0', zeros); + } + } + } +} + +/* + * Ensure that buffer has a decimal point in it. The decimal point + * will not be in the current locale, it will always be '.' + */ +static void +ensure_decimal_point(char* buffer, size_t buf_size) +{ + int insert_count = 0; + char* chars_to_insert; + + /* search for the first non-digit character */ + char *p = buffer; + if (*p == '-' || *p == '+') + /* + * Skip leading sign, if present. I think this could only + * ever be '-', but it can't hurt to check for both. + */ + ++p; + while (*p && isdigit(Py_CHARMASK(*p))) { + ++p; + } + if (*p == '.') { + if (isdigit(Py_CHARMASK(*(p+1)))) { + /* + * Nothing to do, we already have a decimal + * point and a digit after it. + */ + } + else { + /* + * We have a decimal point, but no following + * digit. Insert a zero after the decimal. + */ + ++p; + chars_to_insert = "0"; + insert_count = 1; + } + } + else { + chars_to_insert = ".0"; + insert_count = 2; + } + if (insert_count) { + size_t buf_len = strlen(buffer); + if (buf_len + insert_count + 1 >= buf_size) { + /* + * If there is not enough room in the buffer + * for the additional text, just skip it. It's + * not worth generating an error over. + */ + } + else { + memmove(p + insert_count, p, buffer + strlen(buffer) - p + 1); + memcpy(p, chars_to_insert, insert_count); + } + } +} + +/* see FORMATBUFLEN in unicodeobject.c */ +#define FLOAT_FORMATBUFLEN 120 + +/* + * Given a string that may have a decimal point in the current + * locale, change it back to a dot. Since the string cannot get + * longer, no need for a maximum buffer size parameter. + */ +static void +change_decimal_from_locale_to_dot(char* buffer) +{ + struct lconv *locale_data = localeconv(); + const char *decimal_point = locale_data->decimal_point; + + if (decimal_point[0] != '.' || decimal_point[1] != 0) { + size_t decimal_point_len = strlen(decimal_point); + + if (*buffer == '+' || *buffer == '-') { + buffer++; + } + while (isdigit(Py_CHARMASK(*buffer))) { + buffer++; + } + if (strncmp(buffer, decimal_point, decimal_point_len) == 0) { + *buffer = '.'; + buffer++; + if (decimal_point_len > 1) { + /* buffer needs to get smaller */ + size_t rest_len = strlen(buffer + (decimal_point_len - 1)); + memmove(buffer, buffer + (decimal_point_len - 1), rest_len); + buffer[rest_len] = 0; + } + } + } +} + +/* + * Check that the format string is a valid one for NumPyOS_ascii_format* + */ +static int +check_ascii_format(const char *format) +{ + char format_char; + size_t format_len = strlen(format); + + /* The last character in the format string must be the format char */ + format_char = format[format_len - 1]; + + if (format[0] != '%') { + return -1; + } + + /* + * I'm not sure why this test is here. It's ensuring that the format + * string after the first character doesn't have a single quote, a + * lowercase l, or a percent. This is the reverse of the commented-out + * test about 10 lines ago. + */ + if (strpbrk(format + 1, "'l%")) { + return -1; + } + + /* + * Also curious about this function is that it accepts format strings + * like "%xg", which are invalid for floats. In general, the + * interface to this function is not very good, but changing it is + * difficult because it's a public API. + */ + if (!(format_char == 'e' || format_char == 'E' + || format_char == 'f' || format_char == 'F' + || format_char == 'g' || format_char == 'G')) { + return -1; + } + + return 0; +} + +/* + * Fix the generated string: make sure the decimal is ., that exponent has a + * minimal number of digits, and that it has a decimal + one digit after that + * decimal if decimal argument != 0 (Same effect that 'Z' format in + * PyOS_ascii_formatd + */ +static char* +fix_ascii_format(char* buf, size_t buflen, int decimal) +{ + /* + * Get the current locale, and find the decimal point string. + * Convert that string back to a dot. + */ + change_decimal_from_locale_to_dot(buf); + + /* + * If an exponent exists, ensure that the exponent is at least + * MIN_EXPONENT_DIGITS digits, providing the buffer is large enough + * for the extra zeros. Also, if there are more than + * MIN_EXPONENT_DIGITS, remove as many zeros as possible until we get + * back to MIN_EXPONENT_DIGITS + */ + ensure_minimum_exponent_length(buf, buflen); + + if (decimal != 0) { + ensure_decimal_point(buf, buflen); + } + + return buf; +} + +/* + * NumPyOS_ascii_format*: + * - buffer: A buffer to place the resulting string in + * - buf_size: The length of the buffer. + * - format: The printf()-style format to use for the code to use for + * converting. + * - value: The value to convert + * - decimal: if != 0, always has a decimal, and at leasat one digit after + * the decimal. This has the same effect as passing 'Z' in the origianl + * PyOS_ascii_formatd + * + * This is similar to PyOS_ascii_formatd in python > 2.6, except that it does + * not handle 'n', and handles nan / inf. + * + * Converts a #gdouble to a string, using the '.' as decimal point. To format + * the number you pass in a printf()-style format string. Allowed conversion + * specifiers are 'e', 'E', 'f', 'F', 'g', 'G'. + * + * Return value: The pointer to the buffer with the converted string. + */ +#define ASCII_FORMAT(type, suffix, print_type) \ + NPY_NO_EXPORT char* \ + NumPyOS_ascii_format ## suffix(char *buffer, size_t buf_size, \ + const char *format, \ + type val, int decimal) \ + { \ + if (npy_isfinite(val)) { \ + if (check_ascii_format(format)) { \ + return NULL; \ + } \ + PyOS_snprintf(buffer, buf_size, format, (print_type)val); \ + return fix_ascii_format(buffer, buf_size, decimal); \ + } \ + else if (npy_isnan(val)){ \ + if (buf_size < 4) { \ + return NULL; \ + } \ + strcpy(buffer, "nan"); \ + } \ + else { \ + if (npy_signbit(val)) { \ + if (buf_size < 5) { \ + return NULL; \ + } \ + strcpy(buffer, "-inf"); \ + } \ + else { \ + if (buf_size < 4) { \ + return NULL; \ + } \ + strcpy(buffer, "inf"); \ + } \ + } \ + return buffer; \ + } + +ASCII_FORMAT(float, f, float) +ASCII_FORMAT(double, d, double) +#ifndef FORCE_NO_LONG_DOUBLE_FORMATTING +ASCII_FORMAT(long double, l, long double) +#else +ASCII_FORMAT(long double, l, double) +#endif + +/* + * NumPyOS_ascii_isspace: + * + * Same as isspace under C locale + */ +NPY_NO_EXPORT int +NumPyOS_ascii_isspace(int c) +{ + return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' + || c == '\v'; +} + + +/* + * NumPyOS_ascii_isalpha: + * + * Same as isalpha under C locale + */ +static int +NumPyOS_ascii_isalpha(char c) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + + +/* + * NumPyOS_ascii_isdigit: + * + * Same as isdigit under C locale + */ +static int +NumPyOS_ascii_isdigit(char c) +{ + return (c >= '0' && c <= '9'); +} + + +/* + * NumPyOS_ascii_isalnum: + * + * Same as isalnum under C locale + */ +static int +NumPyOS_ascii_isalnum(char c) +{ + return NumPyOS_ascii_isdigit(c) || NumPyOS_ascii_isalpha(c); +} + + +/* + * NumPyOS_ascii_tolower: + * + * Same as tolower under C locale + */ +static int +NumPyOS_ascii_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') { + return c + ('a'-'A'); + } + return c; +} + + +/* + * NumPyOS_ascii_strncasecmp: + * + * Same as strncasecmp under C locale + */ +static int +NumPyOS_ascii_strncasecmp(const char* s1, const char* s2, size_t len) +{ + while (len > 0 && *s1 != '\0' && *s2 != '\0') { + int diff = NumPyOS_ascii_tolower(*s1) - NumPyOS_ascii_tolower(*s2); + if (diff != 0) { + return diff; + } + ++s1; + ++s2; + --len; + } + if (len > 0) { + return *s1 - *s2; + } + return 0; +} + +/* + * NumPyOS_ascii_strtod_plain: + * + * PyOS_ascii_strtod work-alike, with no enhanced features, + * for forward compatibility with Python >= 2.7 + */ +static double +NumPyOS_ascii_strtod_plain(const char *s, char** endptr) +{ + double result; + NPY_ALLOW_C_API_DEF; + NPY_ALLOW_C_API; + result = PyOS_string_to_double(s, endptr, NULL); + if (PyErr_Occurred()) { + if (endptr) { + *endptr = (char*)s; + } + PyErr_Clear(); + } + NPY_DISABLE_C_API; + return result; +} + +/* + * NumPyOS_ascii_strtod: + * + * Work around bugs in PyOS_ascii_strtod + */ +NPY_NO_EXPORT double +NumPyOS_ascii_strtod(const char *s, char** endptr) +{ + const char *p; + double result; + + while (NumPyOS_ascii_isspace(*s)) { + ++s; + } + + /* + * ##1 + * + * Recognize POSIX inf/nan representations on all platforms. + */ + p = s; + result = 1.0; + if (*p == '-') { + result = -1.0; + ++p; + } + else if (*p == '+') { + ++p; + } + if (NumPyOS_ascii_strncasecmp(p, "nan", 3) == 0) { + p += 3; + if (*p == '(') { + ++p; + while (NumPyOS_ascii_isalnum(*p) || *p == '_') { + ++p; + } + if (*p == ')') { + ++p; + } + } + if (endptr != NULL) { + *endptr = (char*)p; + } + return NPY_NAN; + } + else if (NumPyOS_ascii_strncasecmp(p, "inf", 3) == 0) { + p += 3; + if (NumPyOS_ascii_strncasecmp(p, "inity", 5) == 0) { + p += 5; + } + if (endptr != NULL) { + *endptr = (char*)p; + } + return result*NPY_INFINITY; + } + /* End of ##1 */ + + return NumPyOS_ascii_strtod_plain(s, endptr); +} + +NPY_NO_EXPORT long double +NumPyOS_ascii_strtold(const char *s, char** endptr) +{ + const char *p; + long double result; +#ifdef HAVE_STRTOLD_L + locale_t clocale; +#endif + + while (NumPyOS_ascii_isspace(*s)) { + ++s; + } + + /* + * ##1 + * + * Recognize POSIX inf/nan representations on all platforms. + */ + p = s; + result = 1.0; + if (*p == '-') { + result = -1.0; + ++p; + } + else if (*p == '+') { + ++p; + } + if (NumPyOS_ascii_strncasecmp(p, "nan", 3) == 0) { + p += 3; + if (*p == '(') { + ++p; + while (NumPyOS_ascii_isalnum(*p) || *p == '_') { + ++p; + } + if (*p == ')') { + ++p; + } + } + if (endptr != NULL) { + *endptr = (char*)p; + } + return NPY_NAN; + } + else if (NumPyOS_ascii_strncasecmp(p, "inf", 3) == 0) { + p += 3; + if (NumPyOS_ascii_strncasecmp(p, "inity", 5) == 0) { + p += 5; + } + if (endptr != NULL) { + *endptr = (char*)p; + } + return result*NPY_INFINITY; + } + /* End of ##1 */ + +#ifdef HAVE_STRTOLD_L + clocale = newlocale(LC_ALL_MASK, "C", NULL); + if (clocale) { + errno = 0; + result = strtold_l(s, endptr, clocale); + freelocale(clocale); + } + else { + if (endptr != NULL) { + *endptr = (char*)s; + } + result = 0; + } + return result; +#else + return NumPyOS_ascii_strtod(s, endptr); +#endif +} + +/* + * read_numberlike_string: + * * fp: FILE pointer + * * value: Place to store the value read + * + * Read what looks like valid numeric input and store it in a buffer + * for later parsing as a number. + * + * Similarly to fscanf, this function always consumes leading whitespace, + * and any text that could be the leading part in valid input. + * + * Return value: similar to fscanf. + * * 0 if no number read, + * * 1 if a number read, + * * EOF if end-of-file met before reading anything. + */ +static int +read_numberlike_string(FILE *fp, char *buffer, size_t buflen) +{ + + char *endp; + char *p; + int c; + int ok; + + /* + * Fill buffer with the leftmost matching part in regexp + * + * \s*[+-]? ( [0-9]*\.[0-9]+([eE][+-]?[0-9]+) + * | nan ( \([:alphanum:_]*\) )? + * | inf(inity)? + * ) + * + * case-insensitively. + * + * The "do { ... } while (0)" wrapping in macros ensures that they behave + * properly eg. in "if ... else" structures. + */ + +#define END_MATCH() \ + goto buffer_filled + +#define NEXT_CHAR() \ + do { \ + if (c == EOF || endp >= buffer + buflen - 1) \ + END_MATCH(); \ + *endp++ = (char)c; \ + c = getc(fp); \ + } while (0) + +#define MATCH_ALPHA_STRING_NOCASE(string) \ + do { \ + for (p=(string); *p!='\0' && (c==*p || c+('a'-'A')==*p); ++p) \ + NEXT_CHAR(); \ + if (*p != '\0') END_MATCH(); \ + } while (0) + +#define MATCH_ONE_OR_NONE(condition) \ + do { if (condition) NEXT_CHAR(); } while (0) + +#define MATCH_ONE_OR_MORE(condition) \ + do { \ + ok = 0; \ + while (condition) { NEXT_CHAR(); ok = 1; } \ + if (!ok) END_MATCH(); \ + } while (0) + +#define MATCH_ZERO_OR_MORE(condition) \ + while (condition) { NEXT_CHAR(); } + + /* 1. emulate fscanf EOF handling */ + c = getc(fp); + if (c == EOF) { + return EOF; + } + /* 2. consume leading whitespace unconditionally */ + while (NumPyOS_ascii_isspace(c)) { + c = getc(fp); + } + + /* 3. start reading matching input to buffer */ + endp = buffer; + + /* 4.1 sign (optional) */ + MATCH_ONE_OR_NONE(c == '+' || c == '-'); + + /* 4.2 nan, inf, infinity; [case-insensitive] */ + if (c == 'n' || c == 'N') { + NEXT_CHAR(); + MATCH_ALPHA_STRING_NOCASE("an"); + + /* accept nan([:alphanum:_]*), similarly to strtod */ + if (c == '(') { + NEXT_CHAR(); + MATCH_ZERO_OR_MORE(NumPyOS_ascii_isalnum(c) || c == '_'); + if (c == ')') { + NEXT_CHAR(); + } + } + END_MATCH(); + } + else if (c == 'i' || c == 'I') { + NEXT_CHAR(); + MATCH_ALPHA_STRING_NOCASE("nfinity"); + END_MATCH(); + } + + /* 4.3 mantissa */ + MATCH_ZERO_OR_MORE(NumPyOS_ascii_isdigit(c)); + + if (c == '.') { + NEXT_CHAR(); + MATCH_ONE_OR_MORE(NumPyOS_ascii_isdigit(c)); + } + + /* 4.4 exponent */ + if (c == 'e' || c == 'E') { + NEXT_CHAR(); + MATCH_ONE_OR_NONE(c == '+' || c == '-'); + MATCH_ONE_OR_MORE(NumPyOS_ascii_isdigit(c)); + } + + END_MATCH(); + +buffer_filled: + + ungetc(c, fp); + *endp = '\0'; + + /* return 1 if something read, else 0 */ + return (buffer == endp) ? 0 : 1; +} + +#undef END_MATCH +#undef NEXT_CHAR +#undef MATCH_ALPHA_STRING_NOCASE +#undef MATCH_ONE_OR_NONE +#undef MATCH_ONE_OR_MORE +#undef MATCH_ZERO_OR_MORE + +/* + * NumPyOS_ascii_ftolf: + * * fp: FILE pointer + * * value: Place to store the value read + * + * Similar to PyOS_ascii_strtod, except that it reads input from a file. + * + * Similarly to fscanf, this function always consumes leading whitespace, + * and any text that could be the leading part in valid input. + * + * Return value: similar to fscanf. + * * 0 if no number read, + * * 1 if a number read, + * * EOF if end-of-file met before reading anything. + */ +NPY_NO_EXPORT int +NumPyOS_ascii_ftolf(FILE *fp, double *value) +{ + char buffer[FLOAT_FORMATBUFLEN + 1]; + char *p; + int r; + + r = read_numberlike_string(fp, buffer, FLOAT_FORMATBUFLEN+1); + + if (r != EOF && r != 0) { + *value = NumPyOS_ascii_strtod(buffer, &p); + r = (p == buffer) ? 0 : 1; + } + return r; +} + +NPY_NO_EXPORT int +NumPyOS_ascii_ftoLf(FILE *fp, long double *value) +{ + char buffer[FLOAT_FORMATBUFLEN + 1]; + char *p; + int r; + + r = read_numberlike_string(fp, buffer, FLOAT_FORMATBUFLEN+1); + + if (r != EOF && r != 0) { + *value = NumPyOS_ascii_strtold(buffer, &p); + r = (p == buffer) ? 0 : 1; + } + return r; +} diff --git a/numpy/core/src/multiarray/numpyos.h b/numpy/core/src/multiarray/numpyos.h new file mode 100644 index 0000000..7ca795a --- /dev/null +++ b/numpy/core/src/multiarray/numpyos.h @@ -0,0 +1,34 @@ +#ifndef _NPY_NUMPYOS_H_ +#define _NPY_NUMPYOS_H_ + +NPY_NO_EXPORT char* +NumPyOS_ascii_formatd(char *buffer, size_t buf_size, + const char *format, + double val, int decimal); + +NPY_NO_EXPORT char* +NumPyOS_ascii_formatf(char *buffer, size_t buf_size, + const char *format, + float val, int decimal); + +NPY_NO_EXPORT char* +NumPyOS_ascii_formatl(char *buffer, size_t buf_size, + const char *format, + long double val, int decimal); + +NPY_NO_EXPORT double +NumPyOS_ascii_strtod(const char *s, char** endptr); + +NPY_NO_EXPORT long double +NumPyOS_ascii_strtold(const char *s, char** endptr); + +NPY_NO_EXPORT int +NumPyOS_ascii_ftolf(FILE *fp, double *value); + +NPY_NO_EXPORT int +NumPyOS_ascii_ftoLf(FILE *fp, long double *value); + +NPY_NO_EXPORT int +NumPyOS_ascii_isspace(int c); + +#endif diff --git a/numpy/core/src/multiarray/python_xerbla.c b/numpy/core/src/multiarray/python_xerbla.c new file mode 100644 index 0000000..bdf0b90 --- /dev/null +++ b/numpy/core/src/multiarray/python_xerbla.c @@ -0,0 +1,51 @@ +#include "Python.h" + +/* + * From f2c.h, this should be safe unless fortran is set to use 64 + * bit integers. We don't seem to have any good way to detect that. + */ +typedef int integer; + +/* + From the original manpage: + -------------------------- + XERBLA is an error handler for the LAPACK routines. + It is called by an LAPACK routine if an input parameter has an invalid value. + A message is printed and execution stops. + + Instead of printing a message and stopping the execution, a + ValueError is raised with the message. + + Parameters: + ----------- + srname: Subroutine name to use in error message, maximum six characters. + Spaces at the end are skipped. + info: Number of the invalid parameter. +*/ + +int xerbla_(char *srname, integer *info) +{ + static const char format[] = "On entry to %.*s" \ + " parameter number %d had an illegal value"; + char buf[sizeof(format) + 6 + 4]; /* 6 for name, 4 for param. num. */ + + int len = 0; /* length of subroutine name*/ +#ifdef WITH_THREAD + PyGILState_STATE save; +#endif + + while( len<6 && srname[len]!='\0' ) + len++; + while( len && srname[len-1]==' ' ) + len--; +#ifdef WITH_THREAD + save = PyGILState_Ensure(); +#endif + PyOS_snprintf(buf, sizeof(buf), format, len, srname, *info); + PyErr_SetString(PyExc_ValueError, buf); +#ifdef WITH_THREAD + PyGILState_Release(save); +#endif + + return 0; +} diff --git a/numpy/core/src/multiarray/refcount.c b/numpy/core/src/multiarray/refcount.c new file mode 100644 index 0000000..88f6601 --- /dev/null +++ b/numpy/core/src/multiarray/refcount.c @@ -0,0 +1,286 @@ +/* + * This module corresponds to the `Special functions for NPY_OBJECT` + * section in the numpy reference for C-API. + */ + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +static void +_fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype); + +/* Incref all objects found at this record */ +/*NUMPY_API + */ +NPY_NO_EXPORT void +PyArray_Item_INCREF(char *data, PyArray_Descr *descr) +{ + PyObject *temp; + + if (!PyDataType_REFCHK(descr)) { + return; + } + if (descr->type_num == NPY_OBJECT) { + NPY_COPY_PYOBJECT_PTR(&temp, data); + Py_XINCREF(temp); + } + else if (PyDataType_HASFIELDS(descr)) { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; + + while (PyDict_Next(descr->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, + &title)) { + return; + } + PyArray_Item_INCREF(data + offset, new); + } + } + return; +} + +/* XDECREF all objects found at this record */ +/*NUMPY_API + */ +NPY_NO_EXPORT void +PyArray_Item_XDECREF(char *data, PyArray_Descr *descr) +{ + PyObject *temp; + + if (!PyDataType_REFCHK(descr)) { + return; + } + + if (descr->type_num == NPY_OBJECT) { + NPY_COPY_PYOBJECT_PTR(&temp, data); + Py_XDECREF(temp); + } + else if (PyDataType_HASFIELDS(descr)) { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; + + while (PyDict_Next(descr->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, + &title)) { + return; + } + PyArray_Item_XDECREF(data + offset, new); + } + } + return; +} + +/* Used for arrays of python objects to increment the reference count of */ +/* every python object in the array. */ +/*NUMPY_API + For object arrays, increment all internal references. +*/ +NPY_NO_EXPORT int +PyArray_INCREF(PyArrayObject *mp) +{ + npy_intp i, n; + PyObject **data; + PyObject *temp; + PyArrayIterObject *it; + + if (!PyDataType_REFCHK(PyArray_DESCR(mp))) { + return 0; + } + if (PyArray_DESCR(mp)->type_num != NPY_OBJECT) { + it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp); + if (it == NULL) { + return -1; + } + while(it->index < it->size) { + PyArray_Item_INCREF(it->dataptr, PyArray_DESCR(mp)); + PyArray_ITER_NEXT(it); + } + Py_DECREF(it); + return 0; + } + + if (PyArray_ISONESEGMENT(mp)) { + data = (PyObject **)PyArray_DATA(mp); + n = PyArray_SIZE(mp); + if (PyArray_ISALIGNED(mp)) { + for (i = 0; i < n; i++, data++) { + Py_XINCREF(*data); + } + } + else { + for( i = 0; i < n; i++, data++) { + NPY_COPY_PYOBJECT_PTR(&temp, data); + Py_XINCREF(temp); + } + } + } + else { /* handles misaligned data too */ + it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp); + if (it == NULL) { + return -1; + } + while(it->index < it->size) { + NPY_COPY_PYOBJECT_PTR(&temp, it->dataptr); + Py_XINCREF(temp); + PyArray_ITER_NEXT(it); + } + Py_DECREF(it); + } + return 0; +} + +/*NUMPY_API + Decrement all internal references for object arrays. + (or arrays with object fields) +*/ +NPY_NO_EXPORT int +PyArray_XDECREF(PyArrayObject *mp) +{ + npy_intp i, n; + PyObject **data; + PyObject *temp; + PyArrayIterObject *it; + + if (!PyDataType_REFCHK(PyArray_DESCR(mp))) { + return 0; + } + if (PyArray_DESCR(mp)->type_num != NPY_OBJECT) { + it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp); + if (it == NULL) { + return -1; + } + while(it->index < it->size) { + PyArray_Item_XDECREF(it->dataptr, PyArray_DESCR(mp)); + PyArray_ITER_NEXT(it); + } + Py_DECREF(it); + return 0; + } + + if (PyArray_ISONESEGMENT(mp)) { + data = (PyObject **)PyArray_DATA(mp); + n = PyArray_SIZE(mp); + if (PyArray_ISALIGNED(mp)) { + for (i = 0; i < n; i++, data++) Py_XDECREF(*data); + } + else { + for (i = 0; i < n; i++, data++) { + NPY_COPY_PYOBJECT_PTR(&temp, data); + Py_XDECREF(temp); + } + } + } + else { /* handles misaligned data too */ + it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp); + if (it == NULL) { + return -1; + } + while(it->index < it->size) { + NPY_COPY_PYOBJECT_PTR(&temp, it->dataptr); + Py_XDECREF(temp); + PyArray_ITER_NEXT(it); + } + Py_DECREF(it); + } + return 0; +} + +/*NUMPY_API + * Assumes contiguous + */ +NPY_NO_EXPORT void +PyArray_FillObjectArray(PyArrayObject *arr, PyObject *obj) +{ + npy_intp i,n; + n = PyArray_SIZE(arr); + if (PyArray_DESCR(arr)->type_num == NPY_OBJECT) { + PyObject **optr; + optr = (PyObject **)(PyArray_DATA(arr)); + n = PyArray_SIZE(arr); + if (obj == NULL) { + for (i = 0; i < n; i++) { + *optr++ = NULL; + } + } + else { + for (i = 0; i < n; i++) { + Py_INCREF(obj); + *optr++ = obj; + } + } + } + else { + char *optr; + optr = PyArray_DATA(arr); + for (i = 0; i < n; i++) { + _fillobject(optr, obj, PyArray_DESCR(arr)); + optr += PyArray_DESCR(arr)->elsize; + } + } +} + +static void +_fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype) +{ + if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) { + if ((obj == Py_None) || (PyInt_Check(obj) && PyInt_AsLong(obj)==0)) { + return; + } + else { + PyObject *arr; + Py_INCREF(dtype); + arr = PyArray_NewFromDescr(&PyArray_Type, dtype, + 0, NULL, NULL, NULL, + 0, NULL); + if (arr!=NULL) { + dtype->f->setitem(obj, optr, arr); + } + Py_XDECREF(arr); + } + } + else if (PyDataType_HASFIELDS(dtype)) { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; + + while (PyDict_Next(dtype->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) { + return; + } + _fillobject(optr + offset, obj, new); + } + } + else { + npy_intp i; + for (i = 0; i < dtype->elsize / sizeof(obj); i++) { + Py_XINCREF(obj); + NPY_COPY_PYOBJECT_PTR(optr, &obj); + optr += sizeof(obj); + } + return; + } +} diff --git a/numpy/core/src/multiarray/refcount.h b/numpy/core/src/multiarray/refcount.h new file mode 100644 index 0000000..761d53d --- /dev/null +++ b/numpy/core/src/multiarray/refcount.h @@ -0,0 +1,19 @@ +#ifndef _NPY_PRIVATE_REFCOUNT_H_ +#define _NPY_PRIVATE_REFCOUNT_H_ + +NPY_NO_EXPORT void +PyArray_Item_INCREF(char *data, PyArray_Descr *descr); + +NPY_NO_EXPORT void +PyArray_Item_XDECREF(char *data, PyArray_Descr *descr); + +NPY_NO_EXPORT int +PyArray_INCREF(PyArrayObject *mp); + +NPY_NO_EXPORT int +PyArray_XDECREF(PyArrayObject *mp); + +NPY_NO_EXPORT void +PyArray_FillObjectArray(PyArrayObject *arr, PyObject *obj); + +#endif diff --git a/numpy/core/src/multiarray/scalarapi.c b/numpy/core/src/multiarray/scalarapi.c new file mode 100644 index 0000000..1941f84 --- /dev/null +++ b/numpy/core/src/multiarray/scalarapi.c @@ -0,0 +1,870 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "numpy/npy_math.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "ctors.h" +#include "descriptor.h" +#include "scalartypes.h" + +#include "common.h" + +static PyArray_Descr * +_descr_from_subtype(PyObject *type) +{ + PyObject *mro; + mro = ((PyTypeObject *)type)->tp_mro; + if (PyTuple_GET_SIZE(mro) < 2) { + return PyArray_DescrFromType(NPY_OBJECT); + } + return PyArray_DescrFromTypeObject(PyTuple_GET_ITEM(mro, 1)); +} + +NPY_NO_EXPORT void * +scalar_value(PyObject *scalar, PyArray_Descr *descr) +{ + int type_num; + int align; + npy_intp memloc; + if (descr == NULL) { + descr = PyArray_DescrFromScalar(scalar); + type_num = descr->type_num; + Py_DECREF(descr); + } + else { + type_num = descr->type_num; + } + switch (type_num) { +#define CASE(ut,lt) case NPY_##ut: return &(((Py##lt##ScalarObject *)scalar)->obval) + CASE(BOOL, Bool); + CASE(BYTE, Byte); + CASE(UBYTE, UByte); + CASE(SHORT, Short); + CASE(USHORT, UShort); + CASE(INT, Int); + CASE(UINT, UInt); + CASE(LONG, Long); + CASE(ULONG, ULong); + CASE(LONGLONG, LongLong); + CASE(ULONGLONG, ULongLong); + CASE(HALF, Half); + CASE(FLOAT, Float); + CASE(DOUBLE, Double); + CASE(LONGDOUBLE, LongDouble); + CASE(CFLOAT, CFloat); + CASE(CDOUBLE, CDouble); + CASE(CLONGDOUBLE, CLongDouble); + CASE(OBJECT, Object); + CASE(DATETIME, Datetime); + CASE(TIMEDELTA, Timedelta); +#undef CASE + case NPY_STRING: + return (void *)PyString_AS_STRING(scalar); + case NPY_UNICODE: + return (void *)PyUnicode_AS_DATA(scalar); + case NPY_VOID: + return ((PyVoidScalarObject *)scalar)->obval; + } + + /* + * Must be a user-defined type --- check to see which + * scalar it inherits from. + */ + +#define _CHK(cls) (PyObject_IsInstance(scalar, \ + (PyObject *)&Py##cls##ArrType_Type)) +#define _OBJ(lt) &(((Py##lt##ScalarObject *)scalar)->obval) +#define _IFCASE(cls) if _CHK(cls) return _OBJ(cls) + + if _CHK(Number) { + if _CHK(Integer) { + if _CHK(SignedInteger) { + _IFCASE(Byte); + _IFCASE(Short); + _IFCASE(Int); + _IFCASE(Long); + _IFCASE(LongLong); + _IFCASE(Timedelta); + } + else { + /* Unsigned Integer */ + _IFCASE(UByte); + _IFCASE(UShort); + _IFCASE(UInt); + _IFCASE(ULong); + _IFCASE(ULongLong); + } + } + else { + /* Inexact */ + if _CHK(Floating) { + _IFCASE(Half); + _IFCASE(Float); + _IFCASE(Double); + _IFCASE(LongDouble); + } + else { + /*ComplexFloating */ + _IFCASE(CFloat); + _IFCASE(CDouble); + _IFCASE(CLongDouble); + } + } + } + else if (_CHK(Bool)) { + return _OBJ(Bool); + } + else if (_CHK(Datetime)) { + return _OBJ(Datetime); + } + else if (_CHK(Flexible)) { + if (_CHK(String)) { + return (void *)PyString_AS_STRING(scalar); + } + if (_CHK(Unicode)) { + return (void *)PyUnicode_AS_DATA(scalar); + } + if (_CHK(Void)) { + return ((PyVoidScalarObject *)scalar)->obval; + } + } + else { + _IFCASE(Object); + } + + + /* + * Use the alignment flag to figure out where the data begins + * after a PyObject_HEAD + */ + memloc = (npy_intp)scalar; + memloc += sizeof(PyObject); + /* now round-up to the nearest alignment value */ + align = descr->alignment; + if (align > 1) { + memloc = ((memloc + align - 1)/align)*align; + } + return (void *)memloc; +#undef _IFCASE +#undef _OBJ +#undef _CHK +} + +/*NUMPY_API + * return true an object is exactly a numpy scalar + */ +NPY_NO_EXPORT int +PyArray_CheckAnyScalarExact(PyObject * obj) +{ + return is_anyscalar_exact(obj); +} + +/*NUMPY_API + * Convert to c-type + * + * no error checking is performed -- ctypeptr must be same type as scalar + * in case of flexible type, the data is not copied + * into ctypeptr which is expected to be a pointer to pointer + */ +NPY_NO_EXPORT void +PyArray_ScalarAsCtype(PyObject *scalar, void *ctypeptr) +{ + PyArray_Descr *typecode; + void *newptr; + typecode = PyArray_DescrFromScalar(scalar); + newptr = scalar_value(scalar, typecode); + + if (PyTypeNum_ISEXTENDED(typecode->type_num)) { + void **ct = (void **)ctypeptr; + *ct = newptr; + } + else { + memcpy(ctypeptr, newptr, typecode->elsize); + } + Py_DECREF(typecode); + return; +} + +/*NUMPY_API + * Cast Scalar to c-type + * + * The output buffer must be large-enough to receive the value + * Even for flexible types which is different from ScalarAsCtype + * where only a reference for flexible types is returned + * + * This may not work right on narrow builds for NumPy unicode scalars. + */ +NPY_NO_EXPORT int +PyArray_CastScalarToCtype(PyObject *scalar, void *ctypeptr, + PyArray_Descr *outcode) +{ + PyArray_Descr* descr; + PyArray_VectorUnaryFunc* castfunc; + + descr = PyArray_DescrFromScalar(scalar); + castfunc = PyArray_GetCastFunc(descr, outcode->type_num); + if (castfunc == NULL) { + return -1; + } + if (PyTypeNum_ISEXTENDED(descr->type_num) || + PyTypeNum_ISEXTENDED(outcode->type_num)) { + PyArrayObject *ain, *aout; + + ain = (PyArrayObject *)PyArray_FromScalar(scalar, NULL); + if (ain == NULL) { + Py_DECREF(descr); + return -1; + } + aout = (PyArrayObject *) + PyArray_NewFromDescr(&PyArray_Type, + outcode, + 0, NULL, + NULL, ctypeptr, + NPY_ARRAY_CARRAY, NULL); + if (aout == NULL) { + Py_DECREF(ain); + return -1; + } + castfunc(PyArray_DATA(ain), PyArray_DATA(aout), 1, ain, aout); + Py_DECREF(ain); + Py_DECREF(aout); + } + else { + castfunc(scalar_value(scalar, descr), ctypeptr, 1, NULL, NULL); + } + Py_DECREF(descr); + return 0; +} + +/*NUMPY_API + * Cast Scalar to c-type + */ +NPY_NO_EXPORT int +PyArray_CastScalarDirect(PyObject *scalar, PyArray_Descr *indescr, + void *ctypeptr, int outtype) +{ + PyArray_VectorUnaryFunc* castfunc; + void *ptr; + castfunc = PyArray_GetCastFunc(indescr, outtype); + if (castfunc == NULL) { + return -1; + } + ptr = scalar_value(scalar, indescr); + castfunc(ptr, ctypeptr, 1, NULL, NULL); + return 0; +} + +/*NUMPY_API + * Get 0-dim array from scalar + * + * 0-dim array from array-scalar object + * always contains a copy of the data + * unless outcode is NULL, it is of void type and the referrer does + * not own it either. + * + * steals reference to outcode + */ +NPY_NO_EXPORT PyObject * +PyArray_FromScalar(PyObject *scalar, PyArray_Descr *outcode) +{ + PyArray_Descr *typecode; + PyArrayObject *r; + char *memptr; + PyObject *ret; + + /* convert to 0-dim array of scalar typecode */ + typecode = PyArray_DescrFromScalar(scalar); + if (typecode == NULL) { + return NULL; + } + if ((typecode->type_num == NPY_VOID) && + !(((PyVoidScalarObject *)scalar)->flags & NPY_ARRAY_OWNDATA) && + outcode == NULL) { + r = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + typecode, + 0, NULL, NULL, + ((PyVoidScalarObject *)scalar)->obval, + ((PyVoidScalarObject *)scalar)->flags, + NULL); + if (r == NULL) { + return NULL; + } + Py_INCREF(scalar); + if (PyArray_SetBaseObject(r, (PyObject *)scalar) < 0) { + Py_DECREF(r); + return NULL; + } + return (PyObject *)r; + } + + /* Need to INCREF typecode because PyArray_NewFromDescr steals a + * reference below and we still need to access typecode afterwards. */ + Py_INCREF(typecode); + r = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + typecode, + 0, NULL, + NULL, NULL, 0, NULL); + if (r==NULL) { + Py_DECREF(typecode); Py_XDECREF(outcode); + return NULL; + } + if (PyDataType_FLAGCHK(typecode, NPY_USE_SETITEM)) { + if (typecode->f->setitem(scalar, PyArray_DATA(r), r) < 0) { + Py_DECREF(typecode); Py_XDECREF(outcode); Py_DECREF(r); + return NULL; + } + goto finish; + } + + memptr = scalar_value(scalar, typecode); + +#ifndef Py_UNICODE_WIDE + if (typecode->type_num == NPY_UNICODE) { + PyUCS2Buffer_AsUCS4((Py_UNICODE *)memptr, + (npy_ucs4 *)PyArray_DATA(r), + PyUnicode_GET_SIZE(scalar), + PyArray_ITEMSIZE(r) >> 2); + } + else +#endif + { + memcpy(PyArray_DATA(r), memptr, PyArray_ITEMSIZE(r)); + if (PyDataType_FLAGCHK(typecode, NPY_ITEM_HASOBJECT)) { + /* Need to INCREF just the PyObject portion */ + PyArray_Item_INCREF(memptr, typecode); + } + } + +finish: + if (outcode == NULL) { + Py_DECREF(typecode); + return (PyObject *)r; + } + if (PyArray_EquivTypes(outcode, typecode)) { + if (!PyTypeNum_ISEXTENDED(typecode->type_num) + || (outcode->elsize == typecode->elsize)) { + Py_DECREF(typecode); Py_DECREF(outcode); + return (PyObject *)r; + } + } + + /* cast if necessary to desired output typecode */ + ret = PyArray_CastToType((PyArrayObject *)r, outcode, 0); + Py_DECREF(typecode); Py_DECREF(r); + return ret; +} + +/*NUMPY_API + * Get an Array Scalar From a Python Object + * + * Returns NULL if unsuccessful but error is only set if another error occurred. + * Currently only Numeric-like object supported. + */ +NPY_NO_EXPORT PyObject * +PyArray_ScalarFromObject(PyObject *object) +{ + PyObject *ret=NULL; + if (PyArray_IsZeroDim(object)) { + return PyArray_ToScalar(PyArray_DATA((PyArrayObject *)object), + (PyArrayObject *)object); + } + /* + * Booleans in Python are implemented as a subclass of integers, + * so PyBool_Check must be called before PyInt_Check. + */ + if (PyBool_Check(object)) { + if (object == Py_True) { + PyArrayScalar_RETURN_TRUE; + } + else { + PyArrayScalar_RETURN_FALSE; + } + } + else if (PyInt_Check(object)) { + ret = PyArrayScalar_New(Long); + if (ret == NULL) { + return NULL; + } + PyArrayScalar_VAL(ret, Long) = PyInt_AS_LONG(object); + } + else if (PyFloat_Check(object)) { + ret = PyArrayScalar_New(Double); + if (ret == NULL) { + return NULL; + } + PyArrayScalar_VAL(ret, Double) = PyFloat_AS_DOUBLE(object); + } + else if (PyComplex_Check(object)) { + ret = PyArrayScalar_New(CDouble); + if (ret == NULL) { + return NULL; + } + PyArrayScalar_VAL(ret, CDouble).real = PyComplex_RealAsDouble(object); + PyArrayScalar_VAL(ret, CDouble).imag = PyComplex_ImagAsDouble(object); + } + else if (PyLong_Check(object)) { + npy_longlong val; + val = PyLong_AsLongLong(object); + if (error_converting(val)) { + PyErr_Clear(); + return NULL; + } + ret = PyArrayScalar_New(LongLong); + if (ret == NULL) { + return NULL; + } + PyArrayScalar_VAL(ret, LongLong) = val; + } + return ret; +} + +/*New reference */ +/*NUMPY_API + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_DescrFromTypeObject(PyObject *type) +{ + int typenum; + PyArray_Descr *new, *conv = NULL; + + /* if it's a builtin type, then use the typenumber */ + typenum = _typenum_fromtypeobj(type,1); + if (typenum != NPY_NOTYPE) { + new = PyArray_DescrFromType(typenum); + return new; + } + + /* Check the generic types */ + if ((type == (PyObject *) &PyNumberArrType_Type) || + (type == (PyObject *) &PyInexactArrType_Type) || + (type == (PyObject *) &PyFloatingArrType_Type)) { + typenum = NPY_DOUBLE; + } + else if (type == (PyObject *)&PyComplexFloatingArrType_Type) { + typenum = NPY_CDOUBLE; + } + else if ((type == (PyObject *)&PyIntegerArrType_Type) || + (type == (PyObject *)&PySignedIntegerArrType_Type)) { + typenum = NPY_LONG; + } + else if (type == (PyObject *) &PyUnsignedIntegerArrType_Type) { + typenum = NPY_ULONG; + } + else if (type == (PyObject *) &PyCharacterArrType_Type) { + typenum = NPY_STRING; + } + else if ((type == (PyObject *) &PyGenericArrType_Type) || + (type == (PyObject *) &PyFlexibleArrType_Type)) { + typenum = NPY_VOID; + } + + if (typenum != NPY_NOTYPE) { + return PyArray_DescrFromType(typenum); + } + + /* + * Otherwise --- type is a sub-type of an array scalar + * not corresponding to a registered data-type object. + */ + + /* Do special thing for VOID sub-types */ + if (PyType_IsSubtype((PyTypeObject *)type, &PyVoidArrType_Type)) { + new = PyArray_DescrNewFromType(NPY_VOID); + conv = _arraydescr_fromobj(type); + if (conv) { + new->fields = conv->fields; + Py_INCREF(new->fields); + new->names = conv->names; + Py_INCREF(new->names); + new->elsize = conv->elsize; + new->subarray = conv->subarray; + conv->subarray = NULL; + Py_DECREF(conv); + } + Py_XDECREF(new->typeobj); + new->typeobj = (PyTypeObject *)type; + Py_INCREF(type); + return new; + } + return _descr_from_subtype(type); +} + +/*NUMPY_API + * Return the tuple of ordered field names from a dictionary. + */ +NPY_NO_EXPORT PyObject * +PyArray_FieldNames(PyObject *fields) +{ + PyObject *tup; + PyObject *ret; + PyObject *_numpy_internal; + + if (!PyDict_Check(fields)) { + PyErr_SetString(PyExc_TypeError, + "Fields must be a dictionary"); + return NULL; + } + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + tup = PyObject_CallMethod(_numpy_internal, "_makenames_list", "OO", fields, Py_False); + Py_DECREF(_numpy_internal); + if (tup == NULL) { + return NULL; + } + ret = PyTuple_GET_ITEM(tup, 0); + ret = PySequence_Tuple(ret); + Py_DECREF(tup); + return ret; +} + +/*NUMPY_API + * Return descr object from array scalar. + * + * New reference + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_DescrFromScalar(PyObject *sc) +{ + int type_num; + PyArray_Descr *descr; + + if (PyArray_IsScalar(sc, Void)) { + descr = ((PyVoidScalarObject *)sc)->descr; + Py_INCREF(descr); + return descr; + } + + if (PyArray_IsScalar(sc, Datetime) || PyArray_IsScalar(sc, Timedelta)) { + PyArray_DatetimeMetaData *dt_data; + + if (PyArray_IsScalar(sc, Datetime)) { + descr = PyArray_DescrNewFromType(NPY_DATETIME); + } + else { + /* Timedelta */ + descr = PyArray_DescrNewFromType(NPY_TIMEDELTA); + } + if (descr == NULL) { + return NULL; + } + dt_data = &(((PyArray_DatetimeDTypeMetaData *)descr->c_metadata)->meta); + memcpy(dt_data, &((PyDatetimeScalarObject *)sc)->obmeta, + sizeof(PyArray_DatetimeMetaData)); + + return descr; + } + + descr = PyArray_DescrFromTypeObject((PyObject *)Py_TYPE(sc)); + if (PyDataType_ISUNSIZED(descr)) { + PyArray_DESCR_REPLACE(descr); + type_num = descr->type_num; + if (type_num == NPY_STRING) { + descr->elsize = PyString_GET_SIZE(sc); + } + else if (type_num == NPY_UNICODE) { + descr->elsize = PyUnicode_GET_DATA_SIZE(sc); +#ifndef Py_UNICODE_WIDE + descr->elsize <<= 1; +#endif + } + else { + PyArray_Descr *dtype; + dtype = (PyArray_Descr *)PyObject_GetAttrString(sc, "dtype"); + if (dtype != NULL) { + descr->elsize = dtype->elsize; + descr->fields = dtype->fields; + Py_XINCREF(dtype->fields); + descr->names = dtype->names; + Py_XINCREF(dtype->names); + Py_DECREF(dtype); + } + PyErr_Clear(); + } + } + return descr; +} + +/*NUMPY_API + * Get a typeobject from a type-number -- can return NULL. + * + * New reference + */ +NPY_NO_EXPORT PyObject * +PyArray_TypeObjectFromType(int type) +{ + PyArray_Descr *descr; + PyObject *obj; + + descr = PyArray_DescrFromType(type); + if (descr == NULL) { + return NULL; + } + obj = (PyObject *)descr->typeobj; + Py_XINCREF(obj); + Py_DECREF(descr); + return obj; +} + +/* Does nothing with descr (cannot be NULL) */ +/*NUMPY_API + Get scalar-equivalent to a region of memory described by a descriptor. +*/ +NPY_NO_EXPORT PyObject * +PyArray_Scalar(void *data, PyArray_Descr *descr, PyObject *base) +{ + PyTypeObject *type; + PyObject *obj; + void *destptr; + PyArray_CopySwapFunc *copyswap; + int type_num; + int itemsize; + int swap; + + type_num = descr->type_num; + if (type_num == NPY_BOOL) { + PyArrayScalar_RETURN_BOOL_FROM_LONG(*(npy_bool*)data); + } + else if (PyDataType_FLAGCHK(descr, NPY_USE_GETITEM)) { + return descr->f->getitem(data, base); + } + itemsize = descr->elsize; + copyswap = descr->f->copyswap; + type = descr->typeobj; + swap = !PyArray_ISNBO(descr->byteorder); + if (PyTypeNum_ISSTRING(type_num)) { + /* Eliminate NULL bytes */ + char *dptr = data; + + dptr += itemsize - 1; + while(itemsize && *dptr-- == 0) { + itemsize--; + } + if (type_num == NPY_UNICODE && itemsize) { + /* + * make sure itemsize is a multiple of 4 + * so round up to nearest multiple + */ + itemsize = (((itemsize - 1) >> 2) + 1) << 2; + } + } +#if PY_VERSION_HEX >= 0x03030000 + if (type_num == NPY_UNICODE) { + PyObject *u, *args; + int byteorder; + +#if NPY_BYTE_ORDER == NPY_LITTLE_ENDIAN + byteorder = -1; +#elif NPY_BYTE_ORDER == NPY_BIG_ENDIAN + byteorder = +1; +#else + #error Endianness undefined ? +#endif + if (swap) byteorder *= -1; + + u = PyUnicode_DecodeUTF32(data, itemsize, NULL, &byteorder); + if (u == NULL) { + return NULL; + } + args = Py_BuildValue("(O)", u); + if (args == NULL) { + Py_DECREF(u); + return NULL; + } + obj = type->tp_new(type, args, NULL); + Py_DECREF(u); + Py_DECREF(args); + return obj; + } +#endif + if (type->tp_itemsize != 0) { + /* String type */ + obj = type->tp_alloc(type, itemsize); + } + else { + obj = type->tp_alloc(type, 0); + } + if (obj == NULL) { + return NULL; + } + if (PyTypeNum_ISDATETIME(type_num)) { + /* + * We need to copy the resolution information over to the scalar + * Get the void * from the metadata dictionary + */ + PyArray_DatetimeMetaData *dt_data; + + dt_data = &(((PyArray_DatetimeDTypeMetaData *)descr->c_metadata)->meta); + memcpy(&(((PyDatetimeScalarObject *)obj)->obmeta), dt_data, + sizeof(PyArray_DatetimeMetaData)); + } + if (PyTypeNum_ISFLEXIBLE(type_num)) { + if (type_num == NPY_STRING) { + destptr = PyString_AS_STRING(obj); + ((PyStringObject *)obj)->ob_shash = -1; +#if !defined(NPY_PY3K) + ((PyStringObject *)obj)->ob_sstate = SSTATE_NOT_INTERNED; +#endif + memcpy(destptr, data, itemsize); + return obj; + } +#if PY_VERSION_HEX < 0x03030000 + else if (type_num == NPY_UNICODE) { + /* tp_alloc inherited from Python PyBaseObject_Type */ + PyUnicodeObject *uni = (PyUnicodeObject*)obj; + size_t length = itemsize >> 2; + Py_UNICODE *dst; +#ifndef Py_UNICODE_WIDE + char *buffer; + Py_UNICODE *tmp; + int alloc = 0; + + length *= 2; +#endif + /* Set uni->str so that object can be deallocated on failure */ + uni->str = NULL; + uni->defenc = NULL; + uni->hash = -1; + dst = PyObject_MALLOC(sizeof(Py_UNICODE) * (length + 1)); + if (dst == NULL) { + Py_DECREF(obj); + PyErr_NoMemory(); + return NULL; + } +#ifdef Py_UNICODE_WIDE + memcpy(dst, data, itemsize); + if (swap) { + byte_swap_vector(dst, length, 4); + } + uni->str = dst; + uni->str[length] = 0; + uni->length = length; +#else + /* need aligned data buffer */ + if ((swap) || ((((npy_intp)data) % descr->alignment) != 0)) { + buffer = malloc(itemsize); + if (buffer == NULL) { + PyObject_FREE(dst); + Py_DECREF(obj); + PyErr_NoMemory(); + } + alloc = 1; + memcpy(buffer, data, itemsize); + if (swap) { + byte_swap_vector(buffer, itemsize >> 2, 4); + } + } + else { + buffer = data; + } + + /* + * Allocated enough for 2-characters per itemsize. + * Now convert from the data-buffer + */ + length = PyUCS2Buffer_FromUCS4(dst, + (npy_ucs4 *)buffer, itemsize >> 2); + if (alloc) { + free(buffer); + } + /* Resize the unicode result */ + tmp = PyObject_REALLOC(dst, sizeof(Py_UNICODE)*(length + 1)); + if (tmp == NULL) { + PyObject_FREE(dst); + Py_DECREF(obj); + return NULL; + } + uni->str = tmp; + uni->str[length] = 0; + uni->length = length; +#endif + return obj; + } +#endif /* PY_VERSION_HEX < 0x03030000 */ + else { + PyVoidScalarObject *vobj = (PyVoidScalarObject *)obj; + vobj->base = NULL; + vobj->descr = descr; + Py_INCREF(descr); + vobj->obval = NULL; + Py_SIZE(vobj) = itemsize; + vobj->flags = NPY_ARRAY_CARRAY | NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_OWNDATA; + swap = 0; + if (PyDataType_HASFIELDS(descr)) { + if (base) { + Py_INCREF(base); + vobj->base = base; + vobj->flags = PyArray_FLAGS((PyArrayObject *)base); + vobj->flags &= ~NPY_ARRAY_OWNDATA; + vobj->obval = data; + return obj; + } + } + destptr = PyDataMem_NEW(itemsize); + if (destptr == NULL) { + Py_DECREF(obj); + return PyErr_NoMemory(); + } + vobj->obval = destptr; + + /* + * No base available for copyswp and no swap required. + * Copy data directly into dest. + */ + if (base == NULL) { + memcpy(destptr, data, itemsize); + return obj; + } + } + } + else { + destptr = scalar_value(obj, descr); + } + /* copyswap for OBJECT increments the reference count */ + copyswap(destptr, data, swap, base); + return obj; +} + +/* Return Array Scalar if 0-d array object is encountered */ + +/*NUMPY_API + * + * Return either an array or the appropriate Python object if the array + * is 0d and matches a Python type. + * steals reference to mp + */ +NPY_NO_EXPORT PyObject * +PyArray_Return(PyArrayObject *mp) +{ + + if (mp == NULL) { + return NULL; + } + if (PyErr_Occurred()) { + Py_XDECREF(mp); + return NULL; + } + if (!PyArray_Check(mp)) { + return (PyObject *)mp; + } + if (PyArray_NDIM(mp) == 0) { + PyObject *ret; + ret = PyArray_ToScalar(PyArray_DATA(mp), mp); + Py_DECREF(mp); + return ret; + } + else { + return (PyObject *)mp; + } +} diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src new file mode 100644 index 0000000..c2d4bde --- /dev/null +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -0,0 +1,4521 @@ +/* -*- c -*- */ +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#ifndef _MULTIARRAYMODULE +#define _MULTIARRAYMODULE +#endif + +#include "numpy/arrayobject.h" +#include "numpy/npy_math.h" +#include "numpy/halffloat.h" +#include "numpy/arrayscalars.h" + +#include "npy_pycompat.h" + +#include "npy_config.h" +#include "mapping.h" +#include "ctors.h" +#include "usertypes.h" +#include "numpyos.h" +#include "common.h" +#include "scalartypes.h" +#include "_datetime.h" +#include "datetime_strings.h" +#include "alloc.h" +#include "npy_import.h" +#include "dragon4.h" +#include "npy_longdouble.h" + +#include + +#include "binop_override.h" + +NPY_NO_EXPORT PyBoolScalarObject _PyArrayScalar_BoolValues[] = { + {PyObject_HEAD_INIT(&PyBoolArrType_Type) 0}, + {PyObject_HEAD_INIT(&PyBoolArrType_Type) 1}, +}; + +/* TimeInteger is deleted, but still here to fill the API slot */ +NPY_NO_EXPORT PyTypeObject PyTimeIntegerArrType_Type; + +/* + * Inheritance is established later when tp_bases is set (or tp_base for + * single inheritance) + */ + +/**begin repeat + * #name = number, integer, signedinteger, unsignedinteger, inexact, + * floating, complexfloating, flexible, character# + * #NAME = Number, Integer, SignedInteger, UnsignedInteger, Inexact, + * Floating, ComplexFloating, Flexible, Character# + */ +NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.@name@", /* tp_name*/ + sizeof(PyObject), /* tp_basicsize*/ + 0, /* tp_itemsize */ + /* methods */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; +/**end repeat**/ + +static PyObject * +gentype_alloc(PyTypeObject *type, Py_ssize_t nitems) +{ + PyObject *obj; + const size_t size = _PyObject_VAR_SIZE(type, nitems + 1); + + obj = (PyObject *)PyObject_Malloc(size); + /* + * Fixme. Need to check for no memory. + * If we don't need to zero memory, we could use + * PyObject_{New, NewVar} for this whole function. + */ + memset(obj, 0, size); + if (type->tp_itemsize == 0) { + PyObject_Init(obj, type); + } + else { + (void) PyObject_InitVar((PyVarObject *)obj, type, nitems); + } + return obj; +} + +static void +gentype_dealloc(PyObject *v) +{ + Py_TYPE(v)->tp_free(v); +} + +static void +gentype_free(PyObject *v) +{ + /* + * have an explicit tp_free to enforce inheritance from it. + * PyObject_Free is also the tp_free of PyBaseObject so python does not + * COPYSLOT it, instead it takes the next parent PyInt which has a + * different allocator + */ + PyObject_Free(v); +} + + +static PyObject * +gentype_power(PyObject *m1, PyObject *m2, PyObject *modulo) +{ + if (modulo != Py_None) { + /* modular exponentiation is not implemented (gh-8804) */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_power, gentype_power); + return PyArray_Type.tp_as_number->nb_power(m1, m2, Py_None); +} + +static PyObject * +gentype_generic_method(PyObject *self, PyObject *args, PyObject *kwds, + char *str) +{ + PyObject *arr, *meth, *ret; + + arr = PyArray_FromScalar(self, NULL); + if (arr == NULL) { + return NULL; + } + meth = PyObject_GetAttrString(arr, str); + if (meth == NULL) { + Py_DECREF(arr); + return NULL; + } + if (kwds == NULL) { + ret = PyObject_CallObject(meth, args); + } + else { + ret = PyObject_Call(meth, args, kwds); + } + Py_DECREF(meth); + Py_DECREF(arr); + if (ret && PyArray_Check(ret)) { + return PyArray_Return((PyArrayObject *)ret); + } + else { + return ret; + } +} + +static PyObject * +gentype_add(PyObject *m1, PyObject* m2) +{ + /* special case str.__radd__, which should not call array_add */ + if (PyString_Check(m1) || PyUnicode_Check(m1)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_add, gentype_add); + return PyArray_Type.tp_as_number->nb_add(m1, m2); +} + +/**begin repeat + * + * #name = subtract, remainder, divmod, lshift, rshift, + * and, xor, or, floor_divide, true_divide# + */ +static PyObject * +gentype_@name@(PyObject *m1, PyObject *m2) +{ + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_@name@, gentype_@name@); + return PyArray_Type.tp_as_number->nb_@name@(m1, m2); +} + +/**end repeat**/ + +#if !defined(NPY_PY3K) +/**begin repeat + * + * #name = divide# + */ +static PyObject * +gentype_@name@(PyObject *m1, PyObject *m2) +{ + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_@name@, gentype_@name@); + return PyArray_Type.tp_as_number->nb_@name@(m1, m2); +} +/**end repeat**/ +#endif + +static PyObject * +gentype_multiply(PyObject *m1, PyObject *m2) +{ + npy_intp repeat; + + /* + * If the other object supports sequence repeat and not number multiply + * we should call sequence repeat to support e.g. list repeat by numpy + * scalars (they may be converted to ndarray otherwise). + * A python defined class will always only have the nb_multiply slot and + * some classes may have neither defined. For the latter we want need + * to give the normal case a chance to convert the object to ndarray. + * Probably no class has both defined, but if they do, prefer number. + */ + if (!PyArray_IsScalar(m1, Generic) && + ((Py_TYPE(m1)->tp_as_sequence != NULL) && + (Py_TYPE(m1)->tp_as_sequence->sq_repeat != NULL)) && + ((Py_TYPE(m1)->tp_as_number == NULL) || + (Py_TYPE(m1)->tp_as_number->nb_multiply == NULL))) { + /* Try to convert m2 to an int and try sequence repeat */ + repeat = PyArray_PyIntAsIntp(m2); + if (error_converting(repeat)) { + return NULL; + } + /* Note that npy_intp is compatible to Py_Ssize_t */ + return PySequence_Repeat(m1, repeat); + } + if (!PyArray_IsScalar(m2, Generic) && + ((Py_TYPE(m2)->tp_as_sequence != NULL) && + (Py_TYPE(m2)->tp_as_sequence->sq_repeat != NULL)) && + ((Py_TYPE(m2)->tp_as_number == NULL) || + (Py_TYPE(m2)->tp_as_number->nb_multiply == NULL))) { + /* Try to convert m1 to an int and try sequence repeat */ + repeat = PyArray_PyIntAsIntp(m1); + if (error_converting(repeat)) { + return NULL; + } + return PySequence_Repeat(m2, repeat); + } + /* All normal cases are handled by PyArray's multiply */ + BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_multiply, gentype_multiply); + return PyArray_Type.tp_as_number->nb_multiply(m1, m2); +} + +/**begin repeat + * + * #name = positive, negative, absolute, invert, int, float# + */ +static PyObject * +gentype_@name@(PyObject *m1) +{ + PyObject *arr, *ret; + + arr = PyArray_FromScalar(m1, NULL); + if (arr == NULL) { + return NULL; + } + ret = Py_TYPE(arr)->tp_as_number->nb_@name@(arr); + Py_DECREF(arr); + return ret; +} +/**end repeat**/ + +#if !defined(NPY_PY3K) +/**begin repeat + * + * #name = long, oct, hex# + */ +static PyObject * +gentype_@name@(PyObject *m1) +{ + PyObject *arr, *ret; + + arr = PyArray_FromScalar(m1, NULL); + if (arr == NULL) { + return NULL; + } + ret = Py_TYPE(arr)->tp_as_number->nb_@name@(arr); + Py_DECREF(arr); + return ret; +} +/**end repeat**/ +#endif + +static int +gentype_nonzero_number(PyObject *m1) +{ + PyObject *arr; + int ret; + + arr = PyArray_FromScalar(m1, NULL); + if (arr == NULL) { + return -1; + } +#if defined(NPY_PY3K) + ret = Py_TYPE(arr)->tp_as_number->nb_bool(arr); +#else + ret = Py_TYPE(arr)->tp_as_number->nb_nonzero(arr); +#endif + Py_DECREF(arr); + return ret; +} + +static PyObject * +genint_type_str(PyObject *self) +{ + PyObject *item, *item_str; + item = gentype_generic_method(self, NULL, NULL, "item"); + if (item == NULL) { + return NULL; + } + + item_str = PyObject_Str(item); + Py_DECREF(item); + return item_str; +} + +/* + * The __format__ method for PEP 3101. + */ +static PyObject * +gentype_format(PyObject *self, PyObject *args) +{ + PyObject *format_spec; + PyObject *obj, *ret; + +#if defined(NPY_PY3K) + if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) { + return NULL; + } +#else + if (!PyArg_ParseTuple(args, "O:__format__", &format_spec)) { + return NULL; + } + + if (!PyUnicode_Check(format_spec) && !PyString_Check(format_spec)) { + PyErr_SetString(PyExc_TypeError, + "format must be a string"); + return NULL; + } +#endif + + /* + * Convert to an appropriate Python type and call its format. + * TODO: For some types, like long double, this isn't right, + * because it throws away precision. + */ + if (Py_TYPE(self) == &PyBoolArrType_Type) { + obj = PyBool_FromLong(((PyBoolScalarObject *)self)->obval); + } + else if (PyArray_IsScalar(self, Integer)) { +#if defined(NPY_PY3K) + obj = Py_TYPE(self)->tp_as_number->nb_int(self); +#else + obj = Py_TYPE(self)->tp_as_number->nb_long(self); +#endif + } + else if (PyArray_IsScalar(self, Floating)) { + obj = Py_TYPE(self)->tp_as_number->nb_float(self); + } + else if (PyArray_IsScalar(self, ComplexFloating)) { + double val[2]; + PyArray_Descr *dtype = PyArray_DescrFromScalar(self); + + if (dtype == NULL) { + return NULL; + } + if (PyArray_CastScalarDirect(self, dtype, &val[0], NPY_CDOUBLE) < 0) { + Py_DECREF(dtype); + return NULL; + } + obj = PyComplex_FromDoubles(val[0], val[1]); + Py_DECREF(dtype); + } + else { + obj = PyObject_Str(self); + } + + if (obj == NULL) { + return NULL; + } + + ret = PyObject_Format(obj, format_spec); + Py_DECREF(obj); + return ret; +} + +#ifdef FORCE_NO_LONG_DOUBLE_FORMATTING +#undef NPY_LONGDOUBLE_FMT +#define NPY_LONGDOUBLE_FMT NPY_DOUBLE_FMT +#endif + +/**begin repeat + * #name = half, float, double, longdouble# + * #NAME = HALF, FLOAT, DOUBLE, LONGDOUBLE# + * #type = npy_half, npy_float, npy_double, npy_longdouble# + * #suff = h, f, d, l# + */ + +NPY_NO_EXPORT PyObject * +format_@name@(@type@ val, npy_bool scientific, + int precision, int sign, TrimMode trim, + int pad_left, int pad_right, int exp_digits) +{ + if (scientific) { + return Dragon4_Scientific_AnySize(&val, sizeof(@type@), + DigitMode_Unique, precision, + sign, trim, pad_left, exp_digits); + } + else { + return Dragon4_Positional_AnySize(&val, sizeof(@type@), + DigitMode_Unique, CutoffMode_TotalLength, precision, + sign, trim, pad_left, pad_right); + } +} + + +/**end repeat**/ + +/* + * over-ride repr and str of array-scalar strings and unicode to + * remove NULL bytes and then call the corresponding functions + * of string and unicode. + */ + +/**begin repeat + * #name = string*2,unicode*2# + * #form = (repr,str)*2# + * #Name = String*2,Unicode*2# + * #NAME = STRING*2,UNICODE*2# + * #extra = AndSize*2,,# + * #type = npy_char*2, Py_UNICODE*2# + */ +static PyObject * +@name@type_@form@(PyObject *self) +{ + const @type@ *dptr, *ip; + int len; + PyObject *new; + PyObject *ret; + + ip = dptr = Py@Name@_AS_@NAME@(self); + len = Py@Name@_GET_SIZE(self); + dptr += len-1; + while(len > 0 && *dptr-- == 0) { + len--; + } + new = Py@Name@_From@Name@@extra@(ip, len); + if (new == NULL) { + return PyUString_FromString(""); + } + ret = Py@Name@_Type.tp_@form@(new); + Py_DECREF(new); + return ret; +} +/**end repeat**/ + + +/* + * Convert array of bytes to a string representation much like bytes.__repr__, + * but convert all bytes (including ASCII) to the `\x00` notation with + * uppercase hex codes (FF not ff). + * + * Largely copied from _Py_strhex_impl in CPython implementation + */ +static NPY_INLINE PyObject * +_void_to_hex(const char* argbuf, const Py_ssize_t arglen, + const char *schars, const char *bprefix, const char *echars) +{ + PyObject *retval; + int extrachars, slen; + char *retbuf; + Py_ssize_t i, j; + char const *hexdigits = "0123456789ABCDEF"; + + extrachars = strlen(schars) + strlen(echars); + slen = extrachars + arglen*(2 + strlen(bprefix)); + + if (arglen > (PY_SSIZE_T_MAX / 2) - extrachars) { + return PyErr_NoMemory(); + } + + retbuf = (char *)PyMem_Malloc(slen); + if (!retbuf) { + return PyErr_NoMemory(); + } + + memcpy(retbuf, schars, strlen(schars)); + j = strlen(schars); + + for (i = 0; i < arglen; i++) { + unsigned char c; + memcpy(&retbuf[j], bprefix, strlen(bprefix)); + j += strlen(bprefix); + c = (argbuf[i] >> 4) & 0xf; + retbuf[j++] = hexdigits[c]; + c = argbuf[i] & 0xf; + retbuf[j++] = hexdigits[c]; + } + memcpy(&retbuf[j], echars, strlen(echars)); + + retval = PyUString_FromStringAndSize(retbuf, slen); + PyMem_Free(retbuf); + + return retval; +} + +static PyObject * +voidtype_repr(PyObject *self) +{ + PyVoidScalarObject *s = (PyVoidScalarObject*) self; + if (PyDataType_HASFIELDS(s->descr)) { + static PyObject *reprfunc = NULL; + + npy_cache_import("numpy.core.arrayprint", + "_void_scalar_repr", &reprfunc); + if (reprfunc == NULL) { + return NULL; + } + + return PyObject_CallFunction(reprfunc, "O", self); + } + return _void_to_hex(s->obval, s->descr->elsize, "void(b'", "\\x", "')"); +} + +static PyObject * +voidtype_str(PyObject *self) +{ + PyVoidScalarObject *s = (PyVoidScalarObject*) self; + if (PyDataType_HASFIELDS(s->descr)) { + static PyObject *reprfunc = NULL; + + npy_cache_import("numpy.core.arrayprint", + "_void_scalar_repr", &reprfunc); + if (reprfunc == NULL) { + return NULL; + } + + return PyObject_CallFunction(reprfunc, "O", self); + } + return _void_to_hex(s->obval, s->descr->elsize, "b'", "\\x", "'"); +} + +static PyObject * +datetimetype_repr(PyObject *self) +{ + PyDatetimeScalarObject *scal; + npy_datetimestruct dts; + PyObject *ret; + char iso[NPY_DATETIME_MAX_ISO8601_STRLEN]; + NPY_DATETIMEUNIT unit; + + if (!PyArray_IsScalar(self, Datetime)) { + PyErr_SetString(PyExc_RuntimeError, + "Called NumPy datetime repr on a non-datetime type"); + return NULL; + } + + scal = (PyDatetimeScalarObject *)self; + + if (convert_datetime_to_datetimestruct(&scal->obmeta, + scal->obval, &dts) < 0) { + return NULL; + } + + unit = scal->obmeta.base; + if (make_iso_8601_datetime(&dts, iso, sizeof(iso), 0, 0, + unit, -1, NPY_SAFE_CASTING) < 0) { + return NULL; + } + + /* + * For straight units or generic units, the unit will be deduced + * from the string, so it's not necessary to specify it. + */ + if ((scal->obmeta.num == 1 && scal->obmeta.base != NPY_FR_h) || + scal->obmeta.base == NPY_FR_GENERIC) { + ret = PyUString_FromString("numpy.datetime64('"); + PyUString_ConcatAndDel(&ret, + PyUString_FromString(iso)); + PyUString_ConcatAndDel(&ret, + PyUString_FromString("')")); + } + else { + ret = PyUString_FromString("numpy.datetime64('"); + PyUString_ConcatAndDel(&ret, + PyUString_FromString(iso)); + PyUString_ConcatAndDel(&ret, + PyUString_FromString("','")); + ret = append_metastr_to_string(&scal->obmeta, 1, ret); + PyUString_ConcatAndDel(&ret, + PyUString_FromString("')")); + } + + return ret; +} + +static PyObject * +timedeltatype_repr(PyObject *self) +{ + PyTimedeltaScalarObject *scal; + PyObject *ret; + + if (!PyArray_IsScalar(self, Timedelta)) { + PyErr_SetString(PyExc_RuntimeError, + "Called NumPy timedelta repr on a non-datetime type"); + return NULL; + } + + scal = (PyTimedeltaScalarObject *)self; + + /* The value */ + if (scal->obval == NPY_DATETIME_NAT) { + ret = PyUString_FromString("numpy.timedelta64('NaT'"); + } + else { + /* + * Can't use "%lld" if HAVE_LONG_LONG is not defined + */ +#if defined(HAVE_LONG_LONG) + ret = PyUString_FromFormat("numpy.timedelta64(%lld", + (long long)scal->obval); +#else + ret = PyUString_FromFormat("numpy.timedelta64(%ld", + (long)scal->obval); +#endif + } + /* The metadata unit */ + if (scal->obmeta.base == NPY_FR_GENERIC) { + PyUString_ConcatAndDel(&ret, + PyUString_FromString(")")); + } + else { + PyUString_ConcatAndDel(&ret, + PyUString_FromString(",'")); + ret = append_metastr_to_string(&scal->obmeta, 1, ret); + PyUString_ConcatAndDel(&ret, + PyUString_FromString("')")); + } + + return ret; +} + +static PyObject * +datetimetype_str(PyObject *self) +{ + PyDatetimeScalarObject *scal; + npy_datetimestruct dts; + char iso[NPY_DATETIME_MAX_ISO8601_STRLEN]; + NPY_DATETIMEUNIT unit; + + if (!PyArray_IsScalar(self, Datetime)) { + PyErr_SetString(PyExc_RuntimeError, + "Called NumPy datetime str on a non-datetime type"); + return NULL; + } + + scal = (PyDatetimeScalarObject *)self; + + if (convert_datetime_to_datetimestruct(&scal->obmeta, scal->obval, + &dts) < 0) { + return NULL; + } + + unit = scal->obmeta.base; + if (make_iso_8601_datetime(&dts, iso, sizeof(iso), 0, 0, + unit, -1, NPY_SAFE_CASTING) < 0) { + return NULL; + } + + return PyUString_FromString(iso); +} + +static char *_datetime_verbose_strings[NPY_DATETIME_NUMUNITS] = { + "years", + "months", + "weeks", + "", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", + "picoseconds", + "femtoseconds", + "attoseconds", + "generic time units" +}; + +static PyObject * +timedeltatype_str(PyObject *self) +{ + PyTimedeltaScalarObject *scal; + PyObject *ret; + char *basestr = "invalid"; + + if (!PyArray_IsScalar(self, Timedelta)) { + PyErr_SetString(PyExc_RuntimeError, + "Called NumPy timedelta str on a non-datetime type"); + return NULL; + } + + scal = (PyTimedeltaScalarObject *)self; + + if (scal->obmeta.base >= 0 && scal->obmeta.base < NPY_DATETIME_NUMUNITS) { + basestr = _datetime_verbose_strings[scal->obmeta.base]; + } + else { + PyErr_SetString(PyExc_RuntimeError, + "NumPy datetime metadata is corrupted"); + return NULL; + } + + if (scal->obval == NPY_DATETIME_NAT) { + ret = PyUString_FromString("NaT"); + } + else { + /* + * Can't use "%lld" if HAVE_LONG_LONG is not defined + */ +#if defined(HAVE_LONG_LONG) + ret = PyUString_FromFormat("%lld ", + (long long)(scal->obval * scal->obmeta.num)); +#else + ret = PyUString_FromFormat("%ld ", + (long)(scal->obval * scal->obmeta.num)); +#endif + PyUString_ConcatAndDel(&ret, + PyUString_FromString(basestr)); + } + + return ret; +} + +/* + * float type str and repr + * + * These functions will return NULL if PyString creation fails. + */ + + +/* + * *** BEGIN LEGACY PRINTING MODE CODE *** + * + * This code is legacy code needed to reproduce the printing behavior of + * scalars in numpy 1.13. One day we hope to remove it. + */ + +/* determines if legacy mode is enabled, global set in multiarraymodule.c */ +extern int npy_legacy_print_mode; + +#define HALFPREC_REPR 5 +#define HALFPREC_STR 5 +#define FLOATPREC_REPR 8 +#define FLOATPREC_STR 6 +#define DOUBLEPREC_REPR 17 +#define DOUBLEPREC_STR 12 +#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE +#define LONGDOUBLEPREC_REPR DOUBLEPREC_REPR +#define LONGDOUBLEPREC_STR DOUBLEPREC_STR +#else /* More than probably needed on Intel FP */ +#define LONGDOUBLEPREC_REPR 20 +#define LONGDOUBLEPREC_STR 12 +#endif + +/**begin repeat + * #kind = str, repr# + * #KIND = STR, REPR# + */ + +/**begin repeat1 + * #name = cfloat, cdouble, clongdouble# + * #NAME = FLOAT, DOUBLE, LONGDOUBLE# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# + * #suff = f, d, l# + */ + +#define _FMT1 "%%.%i" NPY_@NAME@_FMT +#define _FMT2 "%%+.%i" NPY_@NAME@_FMT + +static PyObject* +legacy_@name@_format@kind@(@type@ val) +{ + /* XXX: Find a correct size here for format string */ + char format[64], buf[100], *res; + + /* + * Ideally, we should handle this nan/inf stuff in NumpyOS_ascii_format* + */ + if (val.real == 0.0 && npy_signbit(val.real) == 0) { + PyOS_snprintf(format, sizeof(format), _FMT1, @NAME@PREC_@KIND@); + res = NumPyOS_ascii_format@suff@(buf, sizeof(buf) - 1, format, val.imag, 0); + if (res == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Error while formatting"); + return NULL; + } + if (!npy_isfinite(val.imag)) { + strncat(buf, "*", 1); + } + strncat(buf, "j", 1); + } + else { + char re[64], im[64]; + if (npy_isfinite(val.real)) { + PyOS_snprintf(format, sizeof(format), _FMT1, @NAME@PREC_@KIND@); + res = NumPyOS_ascii_format@suff@(re, sizeof(re), format, + val.real, 0); + if (res == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Error while formatting"); + return NULL; + } + } + else { + if (npy_isnan(val.real)) { + strcpy(re, "nan"); + } + else if (val.real > 0){ + strcpy(re, "inf"); + } + else { + strcpy(re, "-inf"); + } + } + + + if (npy_isfinite(val.imag)) { + PyOS_snprintf(format, sizeof(format), _FMT2, @NAME@PREC_@KIND@); + res = NumPyOS_ascii_format@suff@(im, sizeof(im), format, + val.imag, 0); + if (res == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Error while formatting"); + return NULL; + } + } + else { + if (npy_isnan(val.imag)) { + strcpy(im, "+nan"); + } + else if (val.imag > 0){ + strcpy(im, "+inf"); + } + else { + strcpy(im, "-inf"); + } + if (!npy_isfinite(val.imag)) { + strncat(im, "*", 1); + } + } + PyOS_snprintf(buf, sizeof(buf), "(%s%sj)", re, im); + } + + return PyUString_FromString(buf); +} + +#undef _FMT1 +#undef _FMT2 + +/**end repeat1**/ + +/**begin repeat1 + * #name = float, double, longdouble# + * #Name = Float, Double, LongDouble# + * #NAME = FLOAT, DOUBLE, LONGDOUBLE# + * #suff = f, d, l# + */ + +#define _FMT1 "%%.%i" NPY_@NAME@_FMT + +static PyObject * +legacy_@name@_format@kind@(npy_@name@ val){ + /* XXX: Find a correct size here for format string */ + char format[64], buf[100], *res; + size_t i, cnt; + + PyOS_snprintf(format, sizeof(format), _FMT1, @NAME@PREC_@KIND@); + res = NumPyOS_ascii_format@suff@(buf, sizeof(buf), format, val, 0); + if (res == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Error while formatting"); + return NULL; + } + + /* If nothing but digits after sign, append ".0" */ + cnt = strlen(buf); + for (i = (buf[0] == '-') ? 1 : 0; i < cnt; ++i) { + if (!isdigit(Py_CHARMASK(buf[i]))) { + break; + } + } + if (i == cnt && sizeof(buf) >= cnt + 3) { + strcpy(&buf[cnt],".0"); + } + + return PyUString_FromString(buf); +} + +#undef _FMT1 + +/**end repeat1**/ + +/**end repeat**/ + + +/* + * *** END LEGACY PRINTING MODE CODE *** + */ + + +/**begin repeat + * #kind = str, repr# + */ + +/**begin repeat1 + * #name = float, double, longdouble# + * #Name = Float, Double, LongDouble# + * #NAME = FLOAT, DOUBLE, LONGDOUBLE# + */ + +/* helper function choose scientific of fractional output, based on a cutoff */ +static PyObject * +@name@type_@kind@_either(npy_@name@ val, TrimMode trim_pos, TrimMode trim_sci, + npy_bool sign) +{ + npy_@name@ absval; + + if (npy_legacy_print_mode == 113) { + return legacy_@name@_format@kind@(val); + } + + absval = val < 0 ? -val : val; + + if (absval == 0 || (absval < 1.e16L && absval >= 1.e-4L) ) { + return format_@name@(val, 0, -1, sign, trim_pos, -1, -1, -1); + } + return format_@name@(val, 1, -1, sign, trim_sci, -1, -1, -1); +} + +static PyObject * +@name@type_@kind@(PyObject *self) +{ + return @name@type_@kind@_either(((Py@Name@ScalarObject *)self)->obval, + TrimMode_LeaveOneZero, TrimMode_DptZeros, 0); +} + +static PyObject * +c@name@type_@kind@(PyObject *self) +{ + PyObject *rstr, *istr, *ret; + npy_c@name@ val = ((PyC@Name@ScalarObject *)self)->obval; + TrimMode trim = TrimMode_DptZeros; + + if (npy_legacy_print_mode == 113) { + return legacy_c@name@_format@kind@(val); + } + + if (val.real == 0.0 && npy_signbit(val.real) == 0) { + istr = @name@type_@kind@_either(val.imag, trim, trim, 0); + if (istr == NULL) { + return NULL; + } + + PyUString_ConcatAndDel(&istr, PyUString_FromString("j")); + return istr; + } + + if (npy_isfinite(val.real)) { + rstr = @name@type_@kind@_either(val.real, trim, trim, 0); + if (rstr == NULL) { + return NULL; + } + } + else if (npy_isnan(val.real)) { + rstr = PyUString_FromString("nan"); + } + else if (val.real > 0){ + rstr = PyUString_FromString("inf"); + } + else { + rstr = PyUString_FromString("-inf"); + } + + if (npy_isfinite(val.imag)) { + istr = @name@type_@kind@_either(val.imag, trim, trim, 1); + if (istr == NULL) { + return NULL; + } + } + else if (npy_isnan(val.imag)) { + istr = PyUString_FromString("+nan"); + } + else if (val.imag > 0){ + istr = PyUString_FromString("+inf"); + } + else { + istr = PyUString_FromString("-inf"); + } + + ret = PyUString_FromString("("); + PyUString_ConcatAndDel(&ret, rstr); + PyUString_ConcatAndDel(&ret, istr); + PyUString_ConcatAndDel(&ret, PyUString_FromString("j)")); + return ret; +} + +#undef PREC + +/**end repeat1**/ + + +static PyObject * +halftype_@kind@(PyObject *self) +{ + npy_half val = ((PyHalfScalarObject *)self)->obval; + float floatval = npy_half_to_float(val); + float absval; + + if (npy_legacy_print_mode == 113) { + return legacy_float_format@kind@(floatval); + } + + absval = floatval < 0 ? -floatval : floatval; + + if (absval == 0 || (absval < 1.e16 && absval >= 1.e-4) ) { + return format_half(val, 0, -1, 0, TrimMode_LeaveOneZero, -1, -1, -1); + } + return format_half(val, 1, -1, 0, TrimMode_DptZeros, -1, -1, -1); +} + + +/**end repeat**/ + +/**begin repeat + * #char = ,c# + * #CHAR = ,C# + * #POST = ,.real# + */ +static PyObject * +@char@longdoubletype_float(PyObject *self) +{ + npy_longdouble val = PyArrayScalar_VAL(self, @CHAR@LongDouble)@POST@; + return PyFloat_FromDouble((double) val); +} + +static PyObject * +@char@longdoubletype_long(PyObject *self) +{ + npy_longdouble val = PyArrayScalar_VAL(self, @CHAR@LongDouble)@POST@; + return npy_longdouble_to_PyLong(val); +} + +#if !defined(NPY_PY3K) + +/**begin repeat1 + * #name = int, hex, oct# + */ +static PyObject * +@char@longdoubletype_@name@(PyObject *self) +{ + PyObject *ret; + PyObject *obj = @char@longdoubletype_long(self); + if (obj == NULL) { + return NULL; + } + ret = Py_TYPE(obj)->tp_as_number->nb_@name@(obj); + Py_DECREF(obj); + return ret; +} +/**end repeat1**/ + +#endif /* !defined(NPY_PY3K) */ + +/**end repeat**/ + +static PyNumberMethods gentype_as_number = { + (binaryfunc)gentype_add, /*nb_add*/ + (binaryfunc)gentype_subtract, /*nb_subtract*/ + (binaryfunc)gentype_multiply, /*nb_multiply*/ +#if defined(NPY_PY3K) +#else + (binaryfunc)gentype_divide, /*nb_divide*/ +#endif + (binaryfunc)gentype_remainder, /*nb_remainder*/ + (binaryfunc)gentype_divmod, /*nb_divmod*/ + (ternaryfunc)gentype_power, /*nb_power*/ + (unaryfunc)gentype_negative, + (unaryfunc)gentype_positive, /*nb_pos*/ + (unaryfunc)gentype_absolute, /*(unaryfunc)gentype_abs,*/ + (inquiry)gentype_nonzero_number, /*nb_nonzero*/ + (unaryfunc)gentype_invert, /*nb_invert*/ + (binaryfunc)gentype_lshift, /*nb_lshift*/ + (binaryfunc)gentype_rshift, /*nb_rshift*/ + (binaryfunc)gentype_and, /*nb_and*/ + (binaryfunc)gentype_xor, /*nb_xor*/ + (binaryfunc)gentype_or, /*nb_or*/ +#if defined(NPY_PY3K) +#else + 0, /*nb_coerce*/ +#endif + (unaryfunc)gentype_int, /*nb_int*/ +#if defined(NPY_PY3K) + 0, /*nb_reserved*/ +#else + (unaryfunc)gentype_long, /*nb_long*/ +#endif + (unaryfunc)gentype_float, /*nb_float*/ +#if defined(NPY_PY3K) +#else + (unaryfunc)gentype_oct, /*nb_oct*/ + (unaryfunc)gentype_hex, /*nb_hex*/ +#endif + 0, /*inplace_add*/ + 0, /*inplace_subtract*/ + 0, /*inplace_multiply*/ +#if defined(NPY_PY3K) +#else + 0, /*inplace_divide*/ +#endif + 0, /*inplace_remainder*/ + 0, /*inplace_power*/ + 0, /*inplace_lshift*/ + 0, /*inplace_rshift*/ + 0, /*inplace_and*/ + 0, /*inplace_xor*/ + 0, /*inplace_or*/ + (binaryfunc)gentype_floor_divide, /*nb_floor_divide*/ + (binaryfunc)gentype_true_divide, /*nb_true_divide*/ + 0, /*nb_inplace_floor_divide*/ + 0, /*nb_inplace_true_divide*/ + (unaryfunc)NULL, /*nb_index*/ +}; + + +static PyObject * +gentype_richcompare(PyObject *self, PyObject *other, int cmp_op) +{ + PyObject *arr, *ret; + + /* + * If the other object is None, False is always right. This avoids + * the array None comparison, at least until deprecation it is fixed. + * After that, this may be removed and numpy false would be returned. + * + * NOTE: np.equal(NaT, None) evaluates to TRUE! This is an + * an inconsistency, which may has to be considered + * when the deprecation is finished. + */ + if (other == Py_None) { + if (cmp_op == Py_EQ) { + Py_RETURN_FALSE; + } + if (cmp_op == Py_NE) { + Py_RETURN_TRUE; + } + } + + arr = PyArray_FromScalar(self, NULL); + if (arr == NULL) { + return NULL; + } + /* + * Call via PyObject_RichCompare to ensure that other.__eq__ + * has a chance to run when necessary + */ + ret = PyObject_RichCompare(arr, other, cmp_op); + Py_DECREF(arr); + return ret; +} + +static PyObject * +gentype_ndim_get(PyObject *NPY_UNUSED(self)) +{ + return PyInt_FromLong(0); +} + +static PyObject * +gentype_flags_get(PyObject *NPY_UNUSED(self)) +{ + return PyArray_NewFlagsObject(NULL); +} + +static PyObject * +voidtype_flags_get(PyVoidScalarObject *self) +{ + PyObject *flagobj; + flagobj = PyArrayFlags_Type.tp_alloc(&PyArrayFlags_Type, 0); + if (flagobj == NULL) { + return NULL; + } + ((PyArrayFlagsObject *)flagobj)->arr = NULL; + ((PyArrayFlagsObject *)flagobj)->flags = self->flags; + return flagobj; +} + +static PyObject * +voidtype_dtypedescr_get(PyVoidScalarObject *self) +{ + Py_INCREF(self->descr); + return (PyObject *)self->descr; +} + + +static PyObject * +inttype_numerator_get(PyObject *self) +{ + Py_INCREF(self); + return self; +} + + +static PyObject * +inttype_denominator_get(PyObject *self) +{ + return PyInt_FromLong(1); +} + + +static PyObject * +gentype_data_get(PyObject *self) +{ +#if defined(NPY_PY3K) + return PyMemoryView_FromObject(self); +#else + return PyBuffer_FromObject(self, 0, Py_END_OF_BUFFER); +#endif +} + + +static PyObject * +gentype_itemsize_get(PyObject *self) +{ + PyArray_Descr *typecode; + PyObject *ret; + int elsize; + + typecode = PyArray_DescrFromScalar(self); + elsize = typecode->elsize; +#ifndef Py_UNICODE_WIDE + if (typecode->type_num == NPY_UNICODE) { + elsize >>= 1; + } +#endif + ret = PyInt_FromLong((long) elsize); + Py_DECREF(typecode); + return ret; +} + +static PyObject * +gentype_size_get(PyObject *NPY_UNUSED(self)) +{ + return PyInt_FromLong(1); +} + +static PyObject * +gentype_sizeof(PyObject *self) +{ + Py_ssize_t nbytes; + PyObject * isz = gentype_itemsize_get(self); + if (isz == NULL) { + return NULL; + } + nbytes = PyLong_AsLong(isz) + Py_TYPE(self)->tp_basicsize + + Py_SIZE(self) * Py_TYPE(self)->tp_itemsize; + Py_DECREF(isz); + return PyLong_FromSsize_t(nbytes); +} + +#if PY_VERSION_HEX >= 0x03000000 +NPY_NO_EXPORT void +gentype_struct_free(PyObject *ptr) +{ + PyArrayInterface *arrif; + PyObject *context; + + arrif = (PyArrayInterface*)PyCapsule_GetPointer(ptr, NULL); + context = (PyObject *)PyCapsule_GetContext(ptr); + Py_DECREF(context); + Py_XDECREF(arrif->descr); + PyArray_free(arrif->shape); + PyArray_free(arrif); +} +#else +NPY_NO_EXPORT void +gentype_struct_free(void *ptr, void *arg) +{ + PyArrayInterface *arrif = (PyArrayInterface *)ptr; + Py_DECREF((PyObject *)arg); + Py_XDECREF(arrif->descr); + PyArray_free(arrif->shape); + PyArray_free(arrif); +} +#endif + +static PyObject * +gentype_struct_get(PyObject *self) +{ + PyArrayObject *arr; + PyArrayInterface *inter; + PyObject *ret; + + arr = (PyArrayObject *)PyArray_FromScalar(self, NULL); + inter = (PyArrayInterface *)PyArray_malloc(sizeof(PyArrayInterface)); + inter->two = 2; + inter->nd = 0; + inter->flags = PyArray_FLAGS(arr); + inter->flags &= ~(NPY_ARRAY_UPDATEIFCOPY | NPY_ARRAY_WRITEBACKIFCOPY | + NPY_ARRAY_OWNDATA); + inter->flags |= NPY_ARRAY_NOTSWAPPED; + inter->typekind = PyArray_DESCR(arr)->kind; + inter->itemsize = PyArray_DESCR(arr)->elsize; + inter->strides = NULL; + inter->shape = NULL; + inter->data = PyArray_DATA(arr); + inter->descr = NULL; + + ret = NpyCapsule_FromVoidPtrAndDesc(inter, arr, gentype_struct_free); + return ret; +} + +static PyObject * +gentype_priority_get(PyObject *NPY_UNUSED(self)) +{ + return PyFloat_FromDouble(NPY_SCALAR_PRIORITY); +} + +static PyObject * +gentype_shape_get(PyObject *NPY_UNUSED(self)) +{ + return PyTuple_New(0); +} + + +static PyObject * +gentype_interface_get(PyObject *self) +{ + PyArrayObject *arr; + PyObject *inter; + + arr = (PyArrayObject *)PyArray_FromScalar(self, NULL); + if (arr == NULL) { + return NULL; + } + inter = PyObject_GetAttrString((PyObject *)arr, "__array_interface__"); + if (inter != NULL) { + PyDict_SetItemString(inter, "__ref", (PyObject *)arr); + } + Py_DECREF(arr); + return inter; +} + + + +static PyObject * +gentype_typedescr_get(PyObject *self) +{ + return (PyObject *)PyArray_DescrFromScalar(self); +} + + +static PyObject * +gentype_base_get(PyObject *NPY_UNUSED(self)) +{ + Py_RETURN_NONE; +} + +static PyObject * +voidtype_base_get(PyVoidScalarObject *self) +{ + if (self->base == NULL) { + Py_RETURN_NONE; + } + else { + Py_INCREF(self->base); + return self->base; + } +} + + +static PyArray_Descr * +_realdescr_fromcomplexscalar(PyObject *self, int *typenum) +{ + if (PyArray_IsScalar(self, CDouble)) { + *typenum = NPY_CDOUBLE; + return PyArray_DescrFromType(NPY_DOUBLE); + } + if (PyArray_IsScalar(self, CFloat)) { + *typenum = NPY_CFLOAT; + return PyArray_DescrFromType(NPY_FLOAT); + } + if (PyArray_IsScalar(self, CLongDouble)) { + *typenum = NPY_CLONGDOUBLE; + return PyArray_DescrFromType(NPY_LONGDOUBLE); + } + return NULL; +} + +static PyObject * +gentype_real_get(PyObject *self) +{ + PyArray_Descr *typecode; + PyObject *ret; + int typenum; + + if (PyArray_IsScalar(self, ComplexFloating)) { + void *ptr; + typecode = _realdescr_fromcomplexscalar(self, &typenum); + ptr = scalar_value(self, NULL); + ret = PyArray_Scalar(ptr, typecode, NULL); + Py_DECREF(typecode); + return ret; + } + else if (PyArray_IsScalar(self, Object)) { + PyObject *obj = ((PyObjectScalarObject *)self)->obval; + ret = PyObject_GetAttrString(obj, "real"); + if (ret != NULL) { + return ret; + } + PyErr_Clear(); + } + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject * +gentype_imag_get(PyObject *self) +{ + PyArray_Descr *typecode=NULL; + PyObject *ret; + int typenum; + + if (PyArray_IsScalar(self, ComplexFloating)) { + char *ptr; + typecode = _realdescr_fromcomplexscalar(self, &typenum); + ptr = (char *)scalar_value(self, NULL); + ret = PyArray_Scalar(ptr + typecode->elsize, typecode, NULL); + } + else if (PyArray_IsScalar(self, Object)) { + PyObject *obj = ((PyObjectScalarObject *)self)->obval; + PyArray_Descr *newtype; + ret = PyObject_GetAttrString(obj, "imag"); + if (ret == NULL) { + PyErr_Clear(); + obj = PyInt_FromLong(0); + newtype = PyArray_DescrFromType(NPY_OBJECT); + ret = PyArray_Scalar((char *)&obj, newtype, NULL); + Py_DECREF(newtype); + Py_DECREF(obj); + } + } + else { + char *temp; + int elsize; + typecode = PyArray_DescrFromScalar(self); + elsize = typecode->elsize; + temp = npy_alloc_cache_zero(elsize); + ret = PyArray_Scalar(temp, typecode, NULL); + npy_free_cache(temp, elsize); + } + + Py_XDECREF(typecode); + return ret; +} + +static PyObject * +gentype_flat_get(PyObject *self) +{ + PyObject *ret, *arr; + + arr = PyArray_FromScalar(self, NULL); + if (arr == NULL) { + return NULL; + } + ret = PyArray_IterNew(arr); + Py_DECREF(arr); + return ret; +} + + +static PyObject * +gentype_transpose_get(PyObject *self) +{ + Py_INCREF(self); + return self; +} + + +static PyGetSetDef gentype_getsets[] = { + {"ndim", + (getter)gentype_ndim_get, + (setter) 0, + "number of array dimensions", + NULL}, + {"flags", + (getter)gentype_flags_get, + (setter)0, + "integer value of flags", + NULL}, + {"shape", + (getter)gentype_shape_get, + (setter)0, + "tuple of array dimensions", + NULL}, + {"strides", + (getter)gentype_shape_get, + (setter) 0, + "tuple of bytes steps in each dimension", + NULL}, + {"data", + (getter)gentype_data_get, + (setter) 0, + "pointer to start of data", + NULL}, + {"itemsize", + (getter)gentype_itemsize_get, + (setter)0, + "length of one element in bytes", + NULL}, + {"size", + (getter)gentype_size_get, + (setter)0, + "number of elements in the gentype", + NULL}, + {"nbytes", + (getter)gentype_itemsize_get, + (setter)0, + "length of item in bytes", + NULL}, + {"base", + (getter)gentype_base_get, + (setter)0, + "base object", + NULL}, + {"dtype", + (getter)gentype_typedescr_get, + NULL, + "get array data-descriptor", + NULL}, + {"real", + (getter)gentype_real_get, + (setter)0, + "real part of scalar", + NULL}, + {"imag", + (getter)gentype_imag_get, + (setter)0, + "imaginary part of scalar", + NULL}, + {"flat", + (getter)gentype_flat_get, + (setter)0, + "a 1-d view of scalar", + NULL}, + {"T", + (getter)gentype_transpose_get, + (setter)0, + "transpose", + NULL}, + {"__array_interface__", + (getter)gentype_interface_get, + NULL, + "Array protocol: Python side", + NULL}, + {"__array_struct__", + (getter)gentype_struct_get, + NULL, + "Array protocol: struct", + NULL}, + {"__array_priority__", + (getter)gentype_priority_get, + NULL, + "Array priority.", + NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + + +/* 0-dim array from scalar object */ + +static char doc_getarray[] = "sc.__array__(|type) return 0-dim array"; + +static PyObject * +gentype_getarray(PyObject *scalar, PyObject *args) +{ + PyArray_Descr *outcode=NULL; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "|O&:__array__", &PyArray_DescrConverter, + &outcode)) { + Py_XDECREF(outcode); + return NULL; + } + ret = PyArray_FromScalar(scalar, outcode); + return ret; +} + +static char doc_sc_wraparray[] = "sc.__array_wrap__(obj) return scalar from array"; + +static PyObject * +gentype_wraparray(PyObject *NPY_UNUSED(scalar), PyObject *args) +{ + PyObject *obj; + PyArrayObject *arr; + + if (PyTuple_Size(args) < 1) { + PyErr_SetString(PyExc_TypeError, + "only accepts 1 argument."); + return NULL; + } + obj = PyTuple_GET_ITEM(args, 0); + if (!PyArray_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "can only be called with ndarray object"); + return NULL; + } + arr = (PyArrayObject *)obj; + + return PyArray_Scalar(PyArray_DATA(arr), + PyArray_DESCR(arr), (PyObject *)arr); +} + +/* + * These gentype_* functions do not take keyword arguments. + * The proper flag is METH_VARARGS. + */ +/**begin repeat + * + * #name = tolist, item, __deepcopy__, __copy__, + * swapaxes, conj, conjugate, nonzero, + * fill, transpose, newbyteorder# + */ +static PyObject * +gentype_@name@(PyObject *self, PyObject *args) +{ + return gentype_generic_method(self, args, NULL, "@name@"); +} +/**end repeat**/ + +static PyObject * +gentype_itemset(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args)) +{ + PyErr_SetString(PyExc_ValueError, "array-scalars are immutable"); + return NULL; +} + +static PyObject * +gentype_squeeze(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + Py_INCREF(self); + return self; +} + +static Py_ssize_t +gentype_getreadbuf(PyObject *, Py_ssize_t, void **); + +static PyObject * +gentype_byteswap(PyObject *self, PyObject *args, PyObject *kwds) +{ + npy_bool inplace = NPY_FALSE; + static char *kwlist[] = {"inplace", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:byteswap", kwlist, + PyArray_BoolConverter, &inplace)) { + return NULL; + } + if (inplace) { + PyErr_SetString(PyExc_ValueError, + "cannot byteswap a scalar in-place"); + return NULL; + } + else { + /* get the data, copyswap it and pass it to a new Array scalar */ + char *data; + PyArray_Descr *descr; + PyObject *new; + char *newmem; + + gentype_getreadbuf(self, 0, (void **)&data); + descr = PyArray_DescrFromScalar(self); + newmem = PyObject_Malloc(descr->elsize); + if (newmem == NULL) { + Py_DECREF(descr); + return PyErr_NoMemory(); + } + else { + descr->f->copyswap(newmem, data, 1, NULL); + } + new = PyArray_Scalar(newmem, descr, NULL); + PyObject_Free(newmem); + Py_DECREF(descr); + return new; + } +} + + +/* + * These gentype_* functions take keyword arguments. + * The proper flag is METH_VARARGS | METH_KEYWORDS. + */ +/**begin repeat + * + * #name = take, getfield, put, repeat, tofile, mean, trace, diagonal, clip, + * std, var, sum, cumsum, prod, cumprod, compress, sort, argsort, + * round, argmax, argmin, max, min, ptp, any, all, astype, resize, + * reshape, choose, tostring, tobytes, copy, searchsorted, view, + * flatten, ravel# + */ +static PyObject * +gentype_@name@(PyObject *self, PyObject *args, PyObject *kwds) +{ + return gentype_generic_method(self, args, kwds, "@name@"); +} +/**end repeat**/ + +static PyObject * +voidtype_getfield(PyVoidScalarObject *self, PyObject *args, PyObject *kwds) +{ + /* Use ndarray's getfield to obtain the field safely */ + return gentype_generic_method((PyObject *)self, args, kwds, "getfield"); +} + +static PyObject * +gentype_setfield(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args), + PyObject *NPY_UNUSED(kwds)) +{ + PyErr_SetString(PyExc_TypeError, + "Can't set fields in a non-void array scalar."); + return NULL; +} + +static PyObject * +voidtype_setfield(PyVoidScalarObject *self, PyObject *args, PyObject *kwds) +{ + /* + * We would like to use ndarray's setfield because it performs safety + * checks on the field datatypes and because it broadcasts properly. + * However, as a special case, void-scalar assignment broadcasts + * differently from ndarrays when assigning to an object field: Assignment + * to an ndarray object field broadcasts, but assignment to a void-scalar + * object-field should not, in order to allow nested ndarrays. + * These lines should then behave identically: + * + * b = np.zeros(1, dtype=[('x', 'O')]) + * b[0]['x'] = arange(3) # uses voidtype_setfield + * b['x'][0] = arange(3) # uses ndarray setitem + * + * Ndarray's setfield would try to broadcast the lhs. Instead we use + * ndarray getfield to get the field safely, then setitem with an empty + * tuple to set the value without broadcast. Note we also want subarrays to + * be set properly, ie + * + * a = np.zeros(1, dtype=[('x', 'i', 5)]) + * a[0]['x'] = 1 + * + * sets all values to 1. "getfield + setitem with empty tuple" takes + * care of both object arrays and subarrays. + */ + PyObject *getfield_args, *value, *arr, *meth, *arr_field, *emptytuple; + + value = PyTuple_GetItem(args, 0); + if (value == NULL) { + return NULL; + } + getfield_args = PyTuple_GetSlice(args, 1, 3); + if (getfield_args == NULL) { + return NULL; + } + + /* 1. Convert to 0-d array and use getfield */ + arr = PyArray_FromScalar((PyObject*)self, NULL); + if (arr == NULL) { + Py_DECREF(getfield_args); + return NULL; + } + meth = PyObject_GetAttrString(arr, "getfield"); + if (meth == NULL) { + Py_DECREF(getfield_args); + Py_DECREF(arr); + return NULL; + } + if (kwds == NULL) { + arr_field = PyObject_CallObject(meth, getfield_args); + } + else { + arr_field = PyObject_Call(meth, getfield_args, kwds); + } + Py_DECREF(getfield_args); + Py_DECREF(meth); + Py_DECREF(arr); + + if(arr_field == NULL){ + return NULL; + } + + /* 2. Assign the value using setitem with empty tuple. */ + emptytuple = PyTuple_New(0); + if (PyObject_SetItem(arr_field, emptytuple, value) < 0) { + Py_DECREF(arr_field); + Py_DECREF(emptytuple); + return NULL; + } + Py_DECREF(emptytuple); + Py_DECREF(arr_field); + + Py_RETURN_NONE; +} + + +static PyObject * +gentype_reduce(PyObject *self, PyObject *NPY_UNUSED(args)) +{ + PyObject *ret = NULL, *obj = NULL, *mod = NULL; + const char *buffer; + Py_ssize_t buflen; + + /* Return a tuple of (callable object, arguments) */ + ret = PyTuple_New(2); + if (ret == NULL) { + return NULL; + } +#if defined(NPY_PY3K) + if (PyArray_IsScalar(self, Unicode)) { + /* Unicode on Python 3 does not expose the buffer interface */ + buffer = PyUnicode_AS_DATA(self); + buflen = PyUnicode_GET_DATA_SIZE(self); + } + else +#endif + if (PyObject_AsReadBuffer(self, (const void **)&buffer, &buflen)<0) { + Py_DECREF(ret); + return NULL; + } + mod = PyImport_ImportModule("numpy.core.multiarray"); + if (mod == NULL) { + return NULL; + } + obj = PyObject_GetAttrString(mod, "scalar"); + Py_DECREF(mod); + if (obj == NULL) { + return NULL; + } + PyTuple_SET_ITEM(ret, 0, obj); + obj = PyObject_GetAttrString((PyObject *)self, "dtype"); + if (PyArray_IsScalar(self, Object)) { + mod = ((PyObjectScalarObject *)self)->obval; + PyTuple_SET_ITEM(ret, 1, Py_BuildValue("NO", obj, mod)); + } + else { +#ifndef Py_UNICODE_WIDE + /* + * We need to expand the buffer so that we always write + * UCS4 to disk for pickle of unicode scalars. + * + * This could be in a unicode_reduce function, but + * that would require re-factoring. + */ + int alloc = 0; + char *tmp; + int newlen; + + if (PyArray_IsScalar(self, Unicode)) { + tmp = PyArray_malloc(buflen*2); + if (tmp == NULL) { + Py_DECREF(ret); + return PyErr_NoMemory(); + } + alloc = 1; + newlen = PyUCS2Buffer_AsUCS4((Py_UNICODE *)buffer, + (npy_ucs4 *)tmp, + buflen / 2, buflen / 2); + buflen = newlen*4; + buffer = tmp; + } +#endif + mod = PyBytes_FromStringAndSize(buffer, buflen); + if (mod == NULL) { + Py_DECREF(ret); +#ifndef Py_UNICODE_WIDE + ret = NULL; + goto fail; +#else + return NULL; +#endif + } + PyTuple_SET_ITEM(ret, 1, + Py_BuildValue("NN", obj, mod)); +#ifndef Py_UNICODE_WIDE +fail: + if (alloc) PyArray_free((char *)buffer); +#endif + } + return ret; +} + +/* ignores everything */ +static PyObject * +gentype_setstate(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args)) +{ + Py_RETURN_NONE; +} + +static PyObject * +gentype_dump(PyObject *self, PyObject *args) +{ + PyObject *file = NULL; + int ret; + + if (!PyArg_ParseTuple(args, "O:dump", &file)) { + return NULL; + } + ret = PyArray_Dump(self, file, 2); + if (ret < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +gentype_dumps(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + return PyArray_Dumps(self, 2); +} + + +/* setting flags cannot be done for scalars */ +static PyObject * +gentype_setflags(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args), + PyObject *NPY_UNUSED(kwds)) +{ + Py_RETURN_NONE; +} + +/* + * casting complex numbers (that don't inherit from Python complex) + * to Python complex + */ + +/**begin repeat + * #name = cfloat, clongdouble# + * #Name = CFloat, CLongDouble# + */ +static PyObject * +@name@_complex(PyObject *self, PyObject *NPY_UNUSED(args), + PyObject *NPY_UNUSED(kwds)) +{ + return PyComplex_FromDoubles(PyArrayScalar_VAL(self, @Name@).real, + PyArrayScalar_VAL(self, @Name@).imag); +} +/**end repeat**/ + +/* + * need to fill in doc-strings for these methods on import -- copy from + * array docstrings + */ +static PyMethodDef gentype_methods[] = { + {"tolist", + (PyCFunction)gentype_tolist, + METH_VARARGS, NULL}, + {"item", + (PyCFunction)gentype_item, + METH_VARARGS, NULL}, + {"itemset", + (PyCFunction)gentype_itemset, + METH_VARARGS, NULL}, + {"tobytes", + (PyCFunction)gentype_tobytes, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"tofile", + (PyCFunction)gentype_tofile, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"tostring", + (PyCFunction)gentype_tostring, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"byteswap", + (PyCFunction)gentype_byteswap, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"astype", + (PyCFunction)gentype_astype, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"getfield", + (PyCFunction)gentype_getfield, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"setfield", + (PyCFunction)gentype_setfield, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"copy", + (PyCFunction)gentype_copy, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"resize", + (PyCFunction)gentype_resize, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"__array__", + (PyCFunction)gentype_getarray, + METH_VARARGS, doc_getarray}, + {"__array_wrap__", + (PyCFunction)gentype_wraparray, + METH_VARARGS, doc_sc_wraparray}, + + /* for the sys module */ + {"__sizeof__", + (PyCFunction)gentype_sizeof, + METH_NOARGS, NULL}, + + /* for the copy module */ + {"__copy__", + (PyCFunction)gentype___copy__, + METH_VARARGS, NULL}, + {"__deepcopy__", + (PyCFunction)gentype___deepcopy__, + METH_VARARGS, NULL}, + + {"__reduce__", + (PyCFunction) gentype_reduce, + METH_VARARGS, NULL}, + /* For consistency does nothing */ + {"__setstate__", + (PyCFunction) gentype_setstate, + METH_VARARGS, NULL}, + + {"dumps", + (PyCFunction) gentype_dumps, + METH_VARARGS, NULL}, + {"dump", + (PyCFunction) gentype_dump, + METH_VARARGS, NULL}, + + /* Methods for array */ + {"fill", + (PyCFunction)gentype_fill, + METH_VARARGS, NULL}, + {"transpose", + (PyCFunction)gentype_transpose, + METH_VARARGS, NULL}, + {"take", + (PyCFunction)gentype_take, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"put", + (PyCFunction)gentype_put, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"repeat", + (PyCFunction)gentype_repeat, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"choose", + (PyCFunction)gentype_choose, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"sort", + (PyCFunction)gentype_sort, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"argsort", + (PyCFunction)gentype_argsort, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"searchsorted", + (PyCFunction)gentype_searchsorted, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"argmax", + (PyCFunction)gentype_argmax, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"argmin", + (PyCFunction)gentype_argmin, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"reshape", + (PyCFunction)gentype_reshape, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"squeeze", + (PyCFunction)gentype_squeeze, + METH_VARARGS, NULL}, + {"view", + (PyCFunction)gentype_view, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"swapaxes", + (PyCFunction)gentype_swapaxes, + METH_VARARGS, NULL}, + {"max", + (PyCFunction)gentype_max, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"min", + (PyCFunction)gentype_min, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"ptp", + (PyCFunction)gentype_ptp, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"mean", + (PyCFunction)gentype_mean, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"trace", + (PyCFunction)gentype_trace, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"diagonal", + (PyCFunction)gentype_diagonal, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"clip", + (PyCFunction)gentype_clip, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"conj", + (PyCFunction)gentype_conj, + METH_VARARGS, NULL}, + {"conjugate", + (PyCFunction)gentype_conjugate, + METH_VARARGS, NULL}, + {"nonzero", + (PyCFunction)gentype_nonzero, + METH_VARARGS, NULL}, + {"std", + (PyCFunction)gentype_std, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"var", + (PyCFunction)gentype_var, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"sum", + (PyCFunction)gentype_sum, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"cumsum", + (PyCFunction)gentype_cumsum, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"prod", + (PyCFunction)gentype_prod, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"cumprod", + (PyCFunction)gentype_cumprod, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"all", + (PyCFunction)gentype_all, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"any", + (PyCFunction)gentype_any, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"compress", + (PyCFunction)gentype_compress, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"flatten", + (PyCFunction)gentype_flatten, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"ravel", + (PyCFunction)gentype_ravel, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"round", + (PyCFunction)gentype_round, + METH_VARARGS | METH_KEYWORDS, NULL}, +#if defined(NPY_PY3K) + /* Hook for the round() builtin */ + {"__round__", + (PyCFunction)gentype_round, + METH_VARARGS | METH_KEYWORDS, NULL}, +#endif + /* For the format function */ + {"__format__", + gentype_format, + METH_VARARGS, + "NumPy array scalar formatter"}, + {"setflags", + (PyCFunction)gentype_setflags, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"newbyteorder", + (PyCFunction)gentype_newbyteorder, + METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} /* sentinel */ +}; + + +static PyGetSetDef voidtype_getsets[] = { + {"flags", + (getter)voidtype_flags_get, + (setter)0, + "integer value of flags", + NULL}, + {"dtype", + (getter)voidtype_dtypedescr_get, + (setter)0, + "dtype object", + NULL}, + {"base", + (getter)voidtype_base_get, + (setter)0, + "base object", + NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +static PyMethodDef voidtype_methods[] = { + {"getfield", + (PyCFunction)voidtype_getfield, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"setfield", + (PyCFunction)voidtype_setfield, + METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef inttype_getsets[] = { + {"numerator", + (getter)inttype_numerator_get, + (setter)0, + "numerator of value (the value itself)", + NULL}, + {"denominator", + (getter)inttype_denominator_get, + (setter)0, + "denominator of value (1)", + NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +/**begin repeat + * #name = cfloat,clongdouble# + */ +static PyMethodDef @name@type_methods[] = { + {"__complex__", + (PyCFunction)@name@_complex, + METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} +}; +/**end repeat**/ + +/************* As_mapping functions for void array scalar ************/ + +static Py_ssize_t +voidtype_length(PyVoidScalarObject *self) +{ + if (!PyDataType_HASFIELDS(self->descr)) { + return 0; + } + else { + /* return the number of fields */ + return (Py_ssize_t) PyTuple_GET_SIZE(self->descr->names); + } +} + +static PyObject * +voidtype_subscript(PyVoidScalarObject *self, PyObject *ind); + +static PyObject * +voidtype_item(PyVoidScalarObject *self, Py_ssize_t n) +{ + npy_intp m; + PyObject *flist=NULL; + + if (!(PyDataType_HASFIELDS(self->descr))) { + PyErr_SetString(PyExc_IndexError, + "can't index void scalar without fields"); + return NULL; + } + flist = self->descr->names; + m = PyTuple_GET_SIZE(flist); + if (n < 0) { + n += m; + } + if (n < 0 || n >= m) { + PyErr_Format(PyExc_IndexError, "invalid index (%d)", (int) n); + return NULL; + } + + return voidtype_subscript(self, PyTuple_GetItem(flist, n)); +} + +/* get field by name or number */ +static PyObject * +voidtype_subscript(PyVoidScalarObject *self, PyObject *ind) +{ + npy_intp n; + PyObject *ret, *res; + + /* structured voids will accept an integer index */ + if (PyDataType_HASFIELDS(self->descr)) { + n = PyArray_PyIntAsIntp(ind); + if (!error_converting(n)) { + return voidtype_item(self, (Py_ssize_t)n); + } + PyErr_Clear(); + } + + res = PyArray_FromScalar((PyObject*)self, NULL); + + /* ellipsis should return 0d array */ + if(ind == Py_Ellipsis){ + return res; + } + + /* + * other cases (field names, empty tuple) will return either + * scalar or non-0d array. Compute this using ndarray subscript. + */ + ret = array_subscript((PyArrayObject *)res, ind); + Py_DECREF(res); + return PyArray_Return((PyArrayObject*)ret); +} + +static int +voidtype_ass_subscript(PyVoidScalarObject *self, PyObject *ind, PyObject *val); + +static int +voidtype_ass_item(PyVoidScalarObject *self, Py_ssize_t n, PyObject *val) +{ + npy_intp m; + PyObject *flist=NULL; + + if (!(PyDataType_HASFIELDS(self->descr))) { + PyErr_SetString(PyExc_IndexError, + "can't index void scalar without fields"); + return -1; + } + + flist = self->descr->names; + m = PyTuple_GET_SIZE(flist); + if (n < 0) { + n += m; + } + if (n < 0 || n >= m) { + PyErr_Format(PyExc_IndexError, "invalid index (%d)", (int) n); + return -1; + } + + return voidtype_ass_subscript(self, PyTuple_GetItem(flist, n), val); +} + +static int +voidtype_ass_subscript(PyVoidScalarObject *self, PyObject *ind, PyObject *val) +{ + npy_intp n; + char *msg = "invalid index"; + PyObject *args; + + if (!PyDataType_HASFIELDS(self->descr)) { + PyErr_SetString(PyExc_IndexError, + "can't index void scalar without fields"); + return -1; + } + + if (!val) { + PyErr_SetString(PyExc_ValueError, + "cannot delete scalar field"); + return -1; + } + + if (PyBaseString_Check(ind)) { + /* + * Much like in voidtype_setfield, we cannot simply use ndarray's + * __setitem__ since assignment to void scalars should not broadcast + * the lhs. Instead we get a view through __getitem__ and then assign + * the value using setitem with an empty tuple (which treats both + * object arrays and subarrays properly). + * + * Also we do not want to use voidtype_setfield here, since we do + * not need to do the (slow) view safety checks, since we already + * know the dtype/offset are safe. + */ + + PyObject *arr, *arr_field, *meth, *emptytuple; + + /* 1. Convert to 0-d array and use getitem */ + arr = PyArray_FromScalar((PyObject*)self, NULL); + if (arr == NULL) { + return -1; + } + meth = PyObject_GetAttrString(arr, "__getitem__"); + if (meth == NULL) { + Py_DECREF(arr); + return -1; + } + args = Py_BuildValue("(O)", ind); + arr_field = PyObject_CallObject(meth, args); + Py_DECREF(meth); + Py_DECREF(arr); + Py_DECREF(args); + + if(arr_field == NULL){ + return -1; + } + + /* 2. Assign the value using setitem with empty tuple. */ + emptytuple = PyTuple_New(0); + if (PyObject_SetItem(arr_field, emptytuple, val) < 0) { + Py_DECREF(arr_field); + Py_DECREF(emptytuple); + return -1; + } + Py_DECREF(emptytuple); + Py_DECREF(arr_field); + return 0; + } + + /* try to convert it to a number */ + n = PyArray_PyIntAsIntp(ind); + if (error_converting(n)) { + goto fail; + } + return voidtype_ass_item(self, (Py_ssize_t)n, val); + +fail: + PyErr_SetString(PyExc_IndexError, msg); + return -1; +} + +static PyMappingMethods voidtype_as_mapping = { + (lenfunc)voidtype_length, /*mp_length*/ + (binaryfunc)voidtype_subscript, /*mp_subscript*/ + (objobjargproc)voidtype_ass_subscript, /*mp_ass_subscript*/ +}; + + +static PySequenceMethods voidtype_as_sequence = { + (lenfunc)voidtype_length, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + (ssizeargfunc)voidtype_item, /*sq_item*/ + 0, /*sq_slice*/ + (ssizeobjargproc)voidtype_ass_item, /*sq_ass_item*/ + 0, /* ssq_ass_slice */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + + +static Py_ssize_t +gentype_getreadbuf(PyObject *self, Py_ssize_t segment, void **ptrptr) +{ + int numbytes; + PyArray_Descr *outcode; + + if (segment != 0) { + PyErr_SetString(PyExc_SystemError, + "Accessing non-existent array segment"); + return -1; + } + + outcode = PyArray_DescrFromScalar(self); + numbytes = outcode->elsize; + *ptrptr = (void *)scalar_value(self, outcode); + +#ifndef Py_UNICODE_WIDE + if (outcode->type_num == NPY_UNICODE) { + numbytes >>= 1; + } +#endif + Py_DECREF(outcode); + return numbytes; +} + +#if !defined(NPY_PY3K) +static Py_ssize_t +gentype_getsegcount(PyObject *self, Py_ssize_t *lenp) +{ + PyArray_Descr *outcode; + + outcode = PyArray_DescrFromScalar(self); + if (lenp) { + *lenp = outcode->elsize; +#ifndef Py_UNICODE_WIDE + if (outcode->type_num == NPY_UNICODE) { + *lenp >>= 1; + } +#endif + } + Py_DECREF(outcode); + return 1; +} + +static Py_ssize_t +gentype_getcharbuf(PyObject *self, Py_ssize_t segment, constchar **ptrptr) +{ + if (PyArray_IsScalar(self, String) || + PyArray_IsScalar(self, Unicode)) { + return gentype_getreadbuf(self, segment, (void **)ptrptr); + } + else { + PyErr_SetString(PyExc_TypeError, + "Non-character array cannot be interpreted "\ + "as character buffer."); + return -1; + } +} +#endif /* !defined(NPY_PY3K) */ + + +static int +gentype_getbuffer(PyObject *self, Py_buffer *view, int flags) +{ + Py_ssize_t len; + void *buf; + + /* FIXME: XXX: the format is not implemented! -- this needs more work */ + + len = gentype_getreadbuf(self, 0, &buf); + return PyBuffer_FillInfo(view, self, buf, len, 1, flags); +} + +/* releasebuffer is not needed */ + + +static PyBufferProcs gentype_as_buffer = { +#if !defined(NPY_PY3K) + gentype_getreadbuf, /* bf_getreadbuffer*/ + NULL, /* bf_getwritebuffer*/ + gentype_getsegcount, /* bf_getsegcount*/ + gentype_getcharbuf, /* bf_getcharbuffer*/ +#endif + gentype_getbuffer, /* bf_getbuffer */ + NULL, /* bf_releasebuffer */ +}; + + +#if defined(NPY_PY3K) +#define BASEFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE +#define LEAFFLAGS Py_TPFLAGS_DEFAULT +#else +#define BASEFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES +#define LEAFFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES +#endif + +NPY_NO_EXPORT PyTypeObject PyGenericArrType_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.generic", /* tp_name*/ + sizeof(PyObject), /* tp_basicsize*/ + 0, /* tp_itemsize */ + /* methods */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; + +static void +void_dealloc(PyVoidScalarObject *v) +{ + if (v->flags & NPY_ARRAY_OWNDATA) { + npy_free_cache(v->obval, Py_SIZE(v)); + } + Py_XDECREF(v->descr); + Py_XDECREF(v->base); + Py_TYPE(v)->tp_free(v); +} + +static void +object_arrtype_dealloc(PyObject *v) +{ + Py_XDECREF(((PyObjectScalarObject *)v)->obval); + Py_TYPE(v)->tp_free(v); +} + +/* + * string and unicode inherit from Python Type first and so GET_ITEM + * is different to get to the Python Type. + * + * ok is a work-around for a bug in complex_new that doesn't allocate + * memory from the sub-types memory allocator. + */ + +#define _WORK(num) \ + if (type->tp_bases && (PyTuple_GET_SIZE(type->tp_bases)==2)) { \ + PyTypeObject *sup; \ + /* We are inheriting from a Python type as well so \ + give it first dibs on conversion */ \ + sup = (PyTypeObject *)PyTuple_GET_ITEM(type->tp_bases, num); \ + /* Prevent recursion */ \ + if (thisfunc != sup->tp_new) { \ + robj = sup->tp_new(type, args, kwds); \ + if (robj != NULL) goto finish; \ + if (PyTuple_GET_SIZE(args)!=1) return NULL; \ + PyErr_Clear(); \ + } \ + /* now do default conversion */ \ + } + +#define _WORK1 _WORK(1) +#define _WORKz _WORK(0) +#define _WORK0 + +/**begin repeat + * #name = byte, short, int, long, longlong, ubyte, ushort, uint, ulong, + * ulonglong, half, float, double, longdouble, cfloat, cdouble, + * clongdouble, string, unicode, object# + * #Name = Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, + * ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, + * CLongDouble, String, Unicode, Object# + * #TYPE = BYTE, SHORT, INT, LONG, LONGLONG, UBYTE, USHORT, UINT, ULONG, + * ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, + * CLONGDOUBLE, STRING, UNICODE, OBJECT# + * #work = 0,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,z,z,0# + * #default = 0*17,1*2,2# + */ + +#define _NPY_UNUSED2_1 +#define _NPY_UNUSED2_z +#define _NPY_UNUSED2_0 NPY_UNUSED +#define _NPY_UNUSED1_0 +#define _NPY_UNUSED1_1 +#define _NPY_UNUSED1_2 NPY_UNUSED + +static PyObject * +@name@_arrtype_new(PyTypeObject *_NPY_UNUSED1_@default@(type), PyObject *args, PyObject *_NPY_UNUSED2_@work@(kwds)) +{ + PyObject *obj = NULL; + PyObject *robj; + PyArrayObject *arr; + PyArray_Descr *typecode = NULL; +#if (@work@ != 0) || (@default@ == 1) + void *thisfunc = (void *)@name@_arrtype_new; +#endif +#if !(@default@ == 2) + int itemsize; + void *dest, *src; +#endif + + /* + * allow base-class (if any) to do conversion + * If successful, this will jump to finish: + */ + _WORK@work@ + + /* TODO: include type name in error message, which is not @name@ */ + if (!PyArg_ParseTuple(args, "|O", &obj)) { + return NULL; + } + typecode = PyArray_DescrFromType(NPY_@TYPE@); + if (typecode == NULL) { + return NULL; + } + /* + * typecode is new reference and stolen by + * PyArray_FromAny but not PyArray_Scalar + */ + if (obj == NULL) { +#if @default@ == 0 + robj = PyArray_Scalar(NULL, typecode, NULL); + if (robj == NULL) { + Py_DECREF(typecode); + return NULL; + } + memset(&((Py@Name@ScalarObject *)robj)->obval, 0, sizeof(npy_@name@)); +#elif @default@ == 1 + robj = PyArray_Scalar(NULL, typecode, NULL); +#elif @default@ == 2 + Py_INCREF(Py_None); + robj = Py_None; +#endif + Py_DECREF(typecode); + goto finish; + } + + /* + * It is expected at this point that robj is a PyArrayScalar + * (even for Object Data Type) + */ + arr = (PyArrayObject *)PyArray_FromAny(obj, typecode, + 0, 0, NPY_ARRAY_FORCECAST, NULL); + if ((arr == NULL) || (PyArray_NDIM(arr) > 0)) { + return (PyObject *)arr; + } + /* 0-d array */ + robj = PyArray_ToScalar(PyArray_DATA(arr), arr); + Py_DECREF(arr); + +finish: + /* + * In OBJECT case, robj is no longer a + * PyArrayScalar at this point but the + * remaining code assumes it is + */ +#if @default@ == 2 + return robj; +#else + /* Normal return */ + if ((robj == NULL) || (Py_TYPE(robj) == type)) { + return robj; + } + + /* + * This return path occurs when the requested type is not created + * but another scalar object is created instead (i.e. when + * the base-class does the conversion in _WORK macro) + */ + + /* Need to allocate new type and copy data-area over */ + if (type->tp_itemsize) { + itemsize = PyBytes_GET_SIZE(robj); + } + else { + itemsize = 0; + } + obj = type->tp_alloc(type, itemsize); + if (obj == NULL) { + Py_DECREF(robj); + return NULL; + } + /* typecode will be NULL */ + typecode = PyArray_DescrFromType(NPY_@TYPE@); + dest = scalar_value(obj, typecode); + src = scalar_value(robj, typecode); + Py_DECREF(typecode); +#if @default@ == 0 + *((npy_@name@ *)dest) = *((npy_@name@ *)src); +#elif @default@ == 1 /* unicode and strings */ + if (itemsize == 0) { /* unicode */ +#if PY_VERSION_HEX >= 0x03030000 + itemsize = PyUnicode_GetLength(robj) * PyUnicode_KIND(robj); +#else + itemsize = ((PyUnicodeObject *)robj)->length * sizeof(Py_UNICODE); +#endif + } + memcpy(dest, src, itemsize); + /* @default@ == 2 won't get here */ +#endif + Py_DECREF(robj); + return obj; +#endif +} +/**end repeat**/ + +#undef _WORK1 +#undef _WORKz +#undef _WORK0 +#undef _WORK + +/**begin repeat + * #name = datetime, timedelta# + * #Name = Datetime, Timedelta# + * #NAME = DATETIME, TIMEDELTA# + * #is_datetime = 1, 0# + */ + +static PyObject * +@name@_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *obj = NULL, *meta_obj = NULL; + Py@Name@ScalarObject *ret; + + /* TODO: include type name in error message, which is not @name@ */ + if (!PyArg_ParseTuple(args, "|OO", &obj, &meta_obj)) { + return NULL; + } + + /* Allocate the return scalar */ + ret = (Py@Name@ScalarObject *)Py@Name@ArrType_Type.tp_alloc( + &Py@Name@ArrType_Type, 0); + if (ret == NULL) { + return NULL; + } + + /* Incorporate the metadata if its provided */ + if (meta_obj != NULL) { + /* Parse the provided metadata input */ + if (convert_pyobject_to_datetime_metadata(meta_obj, &ret->obmeta) + < 0) { + Py_DECREF(ret); + return NULL; + } + } + else { + /* + * A unit of -1 signals that convert_pyobject_to_datetime + * should populate. + */ + ret->obmeta.base = -1; + } + + if (obj == NULL) { + if (ret->obmeta.base == -1) { + ret->obmeta.base = NPY_DATETIME_DEFAULTUNIT; + ret->obmeta.num = 1; + } + + /* Make datetime default to NaT, timedelta default to zero */ +#if @is_datetime@ + ret->obval = NPY_DATETIME_NAT; +#else + ret->obval = 0; +#endif + } + else if (convert_pyobject_to_@name@(&ret->obmeta, obj, + NPY_SAME_KIND_CASTING, &ret->obval) < 0) { + Py_DECREF(ret); + return NULL; + } + + return (PyObject *)ret; +} +/**end repeat**/ + +/* bool->tp_new only returns Py_True or Py_False */ +static PyObject * +bool_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *NPY_UNUSED(kwds)) +{ + PyObject *obj = NULL; + PyArrayObject *arr; + + if (!PyArg_ParseTuple(args, "|O:bool_", &obj)) { + return NULL; + } + if (obj == NULL) { + PyArrayScalar_RETURN_FALSE; + } + if (obj == Py_False) { + PyArrayScalar_RETURN_FALSE; + } + if (obj == Py_True) { + PyArrayScalar_RETURN_TRUE; + } + arr = (PyArrayObject *)PyArray_FROM_OTF(obj, + NPY_BOOL, NPY_ARRAY_FORCECAST); + if (arr && 0 == PyArray_NDIM(arr)) { + npy_bool val = *((npy_bool *)PyArray_DATA(arr)); + Py_DECREF(arr); + PyArrayScalar_RETURN_BOOL_FROM_LONG(val); + } + return PyArray_Return((PyArrayObject *)arr); +} + +static PyObject * +bool_arrtype_and(PyObject *a, PyObject *b) +{ + if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) { + PyArrayScalar_RETURN_BOOL_FROM_LONG + ((a == PyArrayScalar_True) & (b == PyArrayScalar_True)); + } + return PyGenericArrType_Type.tp_as_number->nb_and(a, b); +} + +static PyObject * +bool_arrtype_or(PyObject *a, PyObject *b) +{ + if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) { + PyArrayScalar_RETURN_BOOL_FROM_LONG + ((a == PyArrayScalar_True)|(b == PyArrayScalar_True)); + } + return PyGenericArrType_Type.tp_as_number->nb_or(a, b); +} + +static PyObject * +bool_arrtype_xor(PyObject *a, PyObject *b) +{ + if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) { + PyArrayScalar_RETURN_BOOL_FROM_LONG + ((a == PyArrayScalar_True)^(b == PyArrayScalar_True)); + } + return PyGenericArrType_Type.tp_as_number->nb_xor(a, b); +} + +static int +bool_arrtype_nonzero(PyObject *a) +{ + return a == PyArrayScalar_True; +} + +/**begin repeat + * #name = byte, short, int, long, ubyte, ushort, longlong, uint, + * ulong, ulonglong# + * #Name = Byte, Short, Int, Long, UByte, UShort, LongLong, UInt, + * ULong, ULongLong# + * #type = PyInt_FromLong*6, PyLong_FromLongLong*1, + * PyLong_FromUnsignedLong*2, PyLong_FromUnsignedLongLong# + */ +static PyNumberMethods @name@_arrtype_as_number; +static PyObject * +@name@_index(PyObject *self) +{ + return @type@(PyArrayScalar_VAL(self, @Name@)); +} +/**end repeat**/ + +/**begin repeat + * #name = half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #NAME = Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble# + */ +static PyNumberMethods @name@_arrtype_as_number; +/**end repeat**/ + +static PyObject * +bool_index(PyObject *a) +{ + if (DEPRECATE( + "In future, it will be an error for 'np.bool_' scalars to be " + "interpreted as an index") < 0) { + return NULL; + } + else { + return PyInt_FromLong(PyArrayScalar_VAL(a, Bool)); + } +} + +/* Arithmetic methods -- only so we can override &, |, ^. */ +NPY_NO_EXPORT PyNumberMethods bool_arrtype_as_number = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ +#if defined(NPY_PY3K) +#else + 0, /* nb_divide */ +#endif + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + (inquiry)bool_arrtype_nonzero, /* nb_nonzero / nb_bool */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + (binaryfunc)bool_arrtype_and, /* nb_and */ + (binaryfunc)bool_arrtype_xor, /* nb_xor */ + (binaryfunc)bool_arrtype_or, /* nb_or */ +#if defined(NPY_PY3K) +#else + 0, /* nb_coerce */ +#endif + 0, /* nb_int */ +#if defined(NPY_PY3K) + 0, /* nb_reserved */ +#else + 0, /* nb_long */ +#endif + 0, /* nb_float */ +#if defined(NPY_PY3K) +#else + 0, /* nb_oct */ + 0, /* nb_hex */ +#endif + /* Added in release 2.0 */ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ +#if defined(NPY_PY3K) +#else + 0, /* nb_inplace_divide */ +#endif + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + /* Added in release 2.2 */ + /* The following require the Py_TPFLAGS_HAVE_CLASS flag */ + 0, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + /* Added in release 2.5 */ + 0, /* nb_index */ +}; + +static PyObject * +void_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *NPY_UNUSED(kwds)) +{ + PyObject *obj, *arr; + PyObject *new = NULL; + + if (!PyArg_ParseTuple(args, "O:void", &obj)) { + return NULL; + } + /* + * For a VOID scalar first see if obj is an integer or long + * and create new memory of that size (filled with 0) for the scalar + */ + if (PyLong_Check(obj) || PyInt_Check(obj) || + PyArray_IsScalar(obj, Integer) || + (PyArray_Check(obj) && + PyArray_NDIM((PyArrayObject *)obj)==0 && + PyArray_ISINTEGER((PyArrayObject *)obj))) { +#if defined(NPY_PY3K) + new = Py_TYPE(obj)->tp_as_number->nb_int(obj); +#else + new = Py_TYPE(obj)->tp_as_number->nb_long(obj); +#endif + } + if (new && PyLong_Check(new)) { + PyObject *ret; + char *destptr; + npy_ulonglong memu = PyLong_AsUnsignedLongLong(new); + Py_DECREF(new); + if (PyErr_Occurred() || (memu > NPY_MAX_INT)) { + PyErr_Clear(); + PyErr_Format(PyExc_OverflowError, + "size cannot be greater than %d", + (int) NPY_MAX_INT); + return NULL; + } + destptr = npy_alloc_cache_zero(memu); + if (destptr == NULL) { + return PyErr_NoMemory(); + } + ret = type->tp_alloc(type, 0); + if (ret == NULL) { + npy_free_cache(destptr, memu); + return PyErr_NoMemory(); + } + ((PyVoidScalarObject *)ret)->obval = destptr; + Py_SIZE((PyVoidScalarObject *)ret) = (int) memu; + ((PyVoidScalarObject *)ret)->descr = + PyArray_DescrNewFromType(NPY_VOID); + ((PyVoidScalarObject *)ret)->descr->elsize = (int) memu; + ((PyVoidScalarObject *)ret)->flags = NPY_ARRAY_BEHAVED | + NPY_ARRAY_OWNDATA; + ((PyVoidScalarObject *)ret)->base = NULL; + return ret; + } + + arr = PyArray_FROM_OTF(obj, NPY_VOID, NPY_ARRAY_FORCECAST); + return PyArray_Return((PyArrayObject *)arr); +} + + +/**************** Define Hash functions ********************/ + +/**begin repeat + * #lname = bool, ubyte, ushort# + * #name = Bool,UByte, UShort# + */ +static npy_hash_t +@lname@_arrtype_hash(PyObject *obj) +{ + return (npy_hash_t)(((Py@name@ScalarObject *)obj)->obval); +} +/**end repeat**/ + +/**begin repeat + * #lname = byte, short, uint# + * #name = Byte, Short, UInt# + */ +static npy_hash_t +@lname@_arrtype_hash(PyObject *obj) +{ + npy_hash_t x = (npy_hash_t)(((Py@name@ScalarObject *)obj)->obval); + if (x == -1) { + x = -2; + } + return x; +} +/**end repeat**/ + +static npy_hash_t +ulong_arrtype_hash(PyObject *obj) +{ + PyObject * l = PyLong_FromUnsignedLong(((PyULongScalarObject*)obj)->obval); + npy_hash_t x = PyObject_Hash(l); + Py_DECREF(l); + return x; +} + +#if (NPY_SIZEOF_INT != NPY_SIZEOF_LONG) || defined(NPY_PY3K) +static npy_hash_t +int_arrtype_hash(PyObject *obj) +{ + npy_hash_t x = (npy_hash_t)(((PyIntScalarObject *)obj)->obval); + if (x == -1) { + x = -2; + } + return x; +} +#endif + +#if defined(NPY_PY3K) +static npy_hash_t +long_arrtype_hash(PyObject *obj) +{ + PyObject * l = PyLong_FromLong(((PyLongScalarObject*)obj)->obval); + npy_hash_t x = PyObject_Hash(l); + Py_DECREF(l); + return x; +} +#endif + +/**begin repeat + * #char = ,u# + * #Char = ,U# + * #Word = ,Unsigned# + */ +static NPY_INLINE npy_hash_t +@char@longlong_arrtype_hash(PyObject *obj) +{ + PyObject * l = PyLong_From@Word@LongLong( + ((Py@Char@LongLongScalarObject*)obj)->obval); + npy_hash_t x = PyObject_Hash(l); + Py_DECREF(l); + return x; +} +/**end repeat**/ + + +/**begin repeat + * #lname = datetime, timedelta# + * #name = Datetime, Timedelta# + */ +#if NPY_SIZEOF_HASH_T==NPY_SIZEOF_DATETIME +static npy_hash_t +@lname@_arrtype_hash(PyObject *obj) +{ + npy_hash_t x = (npy_hash_t)(((Py@name@ScalarObject *)obj)->obval); + if (x == -1) { + x = -2; + } + return x; +} +#elif NPY_SIZEOF_LONGLONG==NPY_SIZEOF_DATETIME +static npy_hash_t +@lname@_arrtype_hash(PyObject *obj) +{ + npy_hash_t y; + npy_longlong x = (((Py@name@ScalarObject *)obj)->obval); + + if ((x <= LONG_MAX)) { + y = (npy_hash_t) x; + } + else { + union Mask { + long hashvals[2]; + npy_longlong v; + } both; + + both.v = x; + y = both.hashvals[0] + (1000003)*both.hashvals[1]; + } + if (y == -1) { + y = -2; + } + return y; +} +#endif +/**end repeat**/ + + + +/* Wrong thing to do for longdouble, but....*/ + +/**begin repeat + * #lname = float, longdouble# + * #name = Float, LongDouble# + */ +static npy_hash_t +@lname@_arrtype_hash(PyObject *obj) +{ + return _Py_HashDouble((double) ((Py@name@ScalarObject *)obj)->obval); +} + +/* borrowed from complex_hash */ +static npy_hash_t +c@lname@_arrtype_hash(PyObject *obj) +{ + npy_hash_t hashreal, hashimag, combined; + hashreal = _Py_HashDouble((double) + (((PyC@name@ScalarObject *)obj)->obval).real); + + if (hashreal == -1) { + return -1; + } + hashimag = _Py_HashDouble((double) + (((PyC@name@ScalarObject *)obj)->obval).imag); + if (hashimag == -1) { + return -1; + } + combined = hashreal + 1000003 * hashimag; + if (combined == -1) { + combined = -2; + } + return combined; +} +/**end repeat**/ + +static npy_hash_t +half_arrtype_hash(PyObject *obj) +{ + return _Py_HashDouble(npy_half_to_double(((PyHalfScalarObject *)obj)->obval)); +} + +static npy_hash_t +object_arrtype_hash(PyObject *obj) +{ + return PyObject_Hash(((PyObjectScalarObject *)obj)->obval); +} + +/* we used to just hash the pointer */ +/* now use tuplehash algorithm using voidtype_item to get the object +*/ +static npy_hash_t +void_arrtype_hash(PyObject *obj) +{ + npy_hash_t x, y; + Py_ssize_t len, n; + PyVoidScalarObject *p; + PyObject *element; + npy_hash_t mult = 1000003L; + x = 0x345678L; + p = (PyVoidScalarObject *)obj; + /* Cannot hash mutable void scalars */ + if (p->flags & NPY_ARRAY_WRITEABLE) { + PyErr_SetString(PyExc_TypeError, "unhashable type: 'writeable void-scalar'"); + return -1; + } + len = voidtype_length(p); + for (n=0; n < len; n++) { + element = voidtype_item(p, n); + y = PyObject_Hash(element); + Py_DECREF(element); + if (y == -1) + return -1; + x = (x ^ y) * mult; + mult += (npy_hash_t)(82520L + len + len); + } + x += 97531L; + if (x == -1) + x = -2; + return x; +} + +/*object arrtype getattro and setattro */ +static PyObject * +object_arrtype_getattro(PyObjectScalarObject *obj, PyObject *attr) { + PyObject *res; + + /* first look in object and then hand off to generic type */ + + res = PyObject_GenericGetAttr(obj->obval, attr); + if (res) { + return res; + } + PyErr_Clear(); + return PyObject_GenericGetAttr((PyObject *)obj, attr); +} + +static int +object_arrtype_setattro(PyObjectScalarObject *obj, PyObject *attr, PyObject *val) { + int res; + /* first look in object and then hand off to generic type */ + + res = PyObject_GenericSetAttr(obj->obval, attr, val); + if (res >= 0) { + return res; + } + PyErr_Clear(); + return PyObject_GenericSetAttr((PyObject *)obj, attr, val); +} + +static PyObject * +object_arrtype_concat(PyObjectScalarObject *self, PyObject *other) +{ + return PySequence_Concat(self->obval, other); +} + +static Py_ssize_t +object_arrtype_length(PyObjectScalarObject *self) +{ + return PyObject_Length(self->obval); +} + +static PyObject * +object_arrtype_repeat(PyObjectScalarObject *self, Py_ssize_t count) +{ + return PySequence_Repeat(self->obval, count); +} + +static PyObject * +object_arrtype_subscript(PyObjectScalarObject *self, PyObject *key) +{ + return PyObject_GetItem(self->obval, key); +} + +static int +object_arrtype_ass_subscript(PyObjectScalarObject *self, PyObject *key, + PyObject *value) +{ + return PyObject_SetItem(self->obval, key, value); +} + +static int +object_arrtype_contains(PyObjectScalarObject *self, PyObject *ob) +{ + return PySequence_Contains(self->obval, ob); +} + +static PyObject * +object_arrtype_inplace_concat(PyObjectScalarObject *self, PyObject *o) +{ + return PySequence_InPlaceConcat(self->obval, o); +} + +static PyObject * +object_arrtype_inplace_repeat(PyObjectScalarObject *self, Py_ssize_t count) +{ + return PySequence_InPlaceRepeat(self->obval, count); +} + +static PySequenceMethods object_arrtype_as_sequence = { + (lenfunc)object_arrtype_length, /*sq_length*/ + (binaryfunc)object_arrtype_concat, /*sq_concat*/ + (ssizeargfunc)object_arrtype_repeat, /*sq_repeat*/ + 0, /*sq_item*/ + 0, /*sq_slice*/ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)object_arrtype_contains, /* sq_contains */ + (binaryfunc)object_arrtype_inplace_concat, /* sq_inplace_concat */ + (ssizeargfunc)object_arrtype_inplace_repeat, /* sq_inplace_repeat */ +}; + +static PyMappingMethods object_arrtype_as_mapping = { + (lenfunc)object_arrtype_length, + (binaryfunc)object_arrtype_subscript, + (objobjargproc)object_arrtype_ass_subscript, +}; + +#if !defined(NPY_PY3K) +static Py_ssize_t +object_arrtype_getsegcount(PyObjectScalarObject *self, Py_ssize_t *lenp) +{ + Py_ssize_t newlen; + int cnt; + PyBufferProcs *pb = Py_TYPE(self->obval)->tp_as_buffer; + + if (pb == NULL || + pb->bf_getsegcount == NULL || + (cnt = (*pb->bf_getsegcount)(self->obval, &newlen)) != 1) { + return 0; + } + if (lenp) { + *lenp = newlen; + } + return cnt; +} + +static Py_ssize_t +object_arrtype_getreadbuf(PyObjectScalarObject *self, Py_ssize_t segment, void **ptrptr) +{ + PyBufferProcs *pb = Py_TYPE(self->obval)->tp_as_buffer; + + if (pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL) { + PyErr_SetString(PyExc_TypeError, + "expected a readable buffer object"); + return -1; + } + return (*pb->bf_getreadbuffer)(self->obval, segment, ptrptr); +} + +static Py_ssize_t +object_arrtype_getwritebuf(PyObjectScalarObject *self, Py_ssize_t segment, void **ptrptr) +{ + PyBufferProcs *pb = Py_TYPE(self->obval)->tp_as_buffer; + + if (pb == NULL || + pb->bf_getwritebuffer == NULL || + pb->bf_getsegcount == NULL) { + PyErr_SetString(PyExc_TypeError, + "expected a writeable buffer object"); + return -1; + } + return (*pb->bf_getwritebuffer)(self->obval, segment, ptrptr); +} + +static Py_ssize_t +object_arrtype_getcharbuf(PyObjectScalarObject *self, Py_ssize_t segment, + constchar **ptrptr) +{ + PyBufferProcs *pb = Py_TYPE(self->obval)->tp_as_buffer; + + if (pb == NULL || + pb->bf_getcharbuffer == NULL || + pb->bf_getsegcount == NULL) { + PyErr_SetString(PyExc_TypeError, + "expected a character buffer object"); + return -1; + } + return (*pb->bf_getcharbuffer)(self->obval, segment, ptrptr); +} +#endif + +static int +object_arrtype_getbuffer(PyObjectScalarObject *self, Py_buffer *view, int flags) +{ + PyBufferProcs *pb = Py_TYPE(self->obval)->tp_as_buffer; + if (pb == NULL || pb->bf_getbuffer == NULL) { + PyErr_SetString(PyExc_TypeError, + "expected a readable buffer object"); + return -1; + } + return (*pb->bf_getbuffer)(self->obval, view, flags); +} + +static void +object_arrtype_releasebuffer(PyObjectScalarObject *self, Py_buffer *view) +{ + PyBufferProcs *pb = Py_TYPE(self->obval)->tp_as_buffer; + if (pb == NULL) { + PyErr_SetString(PyExc_TypeError, + "expected a readable buffer object"); + return; + } + if (pb->bf_releasebuffer != NULL) { + (*pb->bf_releasebuffer)(self->obval, view); + } +} + +static PyBufferProcs object_arrtype_as_buffer = { +#if !defined(NPY_PY3K) + (readbufferproc)object_arrtype_getreadbuf, + (writebufferproc)object_arrtype_getwritebuf, + (segcountproc)object_arrtype_getsegcount, + (charbufferproc)object_arrtype_getcharbuf, +#endif + (getbufferproc)object_arrtype_getbuffer, + (releasebufferproc)object_arrtype_releasebuffer, +}; + +static PyObject * +object_arrtype_call(PyObjectScalarObject *obj, PyObject *args, PyObject *kwds) +{ + return PyObject_Call(obj->obval, args, kwds); +} + +NPY_NO_EXPORT PyTypeObject PyObjectArrType_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.object_", /* tp_name*/ + sizeof(PyObjectScalarObject), /* tp_basicsize*/ + 0, /* tp_itemsize */ + (destructor)object_arrtype_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + &object_arrtype_as_sequence, /* tp_as_sequence */ + &object_arrtype_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)object_arrtype_call, /* tp_call */ + 0, /* tp_str */ + (getattrofunc)object_arrtype_getattro, /* tp_getattro */ + (setattrofunc)object_arrtype_setattro, /* tp_setattro */ + &object_arrtype_as_buffer, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; + +static PyObject * +gen_arrtype_subscript(PyObject *self, PyObject *key) +{ + /* + * Only [...], [...,], [, ...], + * is allowed for indexing a scalar + * + * These return a new N-d array with a copy of + * the data where N is the number of None's in . + */ + PyObject *res, *ret; + + res = PyArray_FromScalar(self, NULL); + + ret = array_subscript((PyArrayObject *)res, key); + Py_DECREF(res); + if (ret == NULL) { + PyErr_SetString(PyExc_IndexError, + "invalid index to scalar variable."); + } + return ret; +} + + +#define NAME_bool "bool" +#define NAME_void "void" +#if defined(NPY_PY3K) +#define NAME_string "bytes" +#define NAME_unicode "str" +#else +#define NAME_string "string" +#define NAME_unicode "unicode" +#endif + +/**begin repeat + * #name = bool, string, unicode, void# + * #NAME = Bool, String, Unicode, Void# + * #ex = _,_,_,# + */ +NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy." NAME_@name@ "@ex@", /* tp_name*/ + sizeof(Py@NAME@ScalarObject), /* tp_basicsize*/ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; +/**end repeat**/ + +#undef NAME_bool +#undef NAME_void +#undef NAME_string +#undef NAME_unicode + +/**begin repeat + * #NAME = Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, + * ULongLong, Half, Float, Double, LongDouble, Datetime, Timedelta# + * #name = int*5, uint*5, float*4, datetime, timedelta# + * #CNAME = (CHAR, SHORT, INT, LONG, LONGLONG)*2, HALF, FLOAT, DOUBLE, + * LONGDOUBLE, DATETIME, TIMEDELTA# + */ +#if NPY_BITSOF_@CNAME@ == 8 +#define _THIS_SIZE "8" +#elif NPY_BITSOF_@CNAME@ == 16 +#define _THIS_SIZE "16" +#elif NPY_BITSOF_@CNAME@ == 32 +#define _THIS_SIZE "32" +#elif NPY_BITSOF_@CNAME@ == 64 +#define _THIS_SIZE "64" +#elif NPY_BITSOF_@CNAME@ == 80 +#define _THIS_SIZE "80" +#elif NPY_BITSOF_@CNAME@ == 96 +#define _THIS_SIZE "96" +#elif NPY_BITSOF_@CNAME@ == 128 +#define _THIS_SIZE "128" +#elif NPY_BITSOF_@CNAME@ == 256 +#define _THIS_SIZE "256" +#endif +NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.@name@" _THIS_SIZE, /* tp_name*/ + sizeof(Py@NAME@ScalarObject), /* tp_basicsize*/ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; + +#undef _THIS_SIZE +/**end repeat**/ + + +static PyMappingMethods gentype_as_mapping = { + NULL, + (binaryfunc)gen_arrtype_subscript, + NULL +}; + + +/**begin repeat + * #NAME = CFloat, CDouble, CLongDouble# + * #name = complex*3# + * #CNAME = FLOAT, DOUBLE, LONGDOUBLE# + */ +#if NPY_BITSOF_@CNAME@ == 16 +#define _THIS_SIZE2 "16" +#define _THIS_SIZE1 "32" +#elif NPY_BITSOF_@CNAME@ == 32 +#define _THIS_SIZE2 "32" +#define _THIS_SIZE1 "64" +#elif NPY_BITSOF_@CNAME@ == 64 +#define _THIS_SIZE2 "64" +#define _THIS_SIZE1 "128" +#elif NPY_BITSOF_@CNAME@ == 80 +#define _THIS_SIZE2 "80" +#define _THIS_SIZE1 "160" +#elif NPY_BITSOF_@CNAME@ == 96 +#define _THIS_SIZE2 "96" +#define _THIS_SIZE1 "192" +#elif NPY_BITSOF_@CNAME@ == 128 +#define _THIS_SIZE2 "128" +#define _THIS_SIZE1 "256" +#elif NPY_BITSOF_@CNAME@ == 256 +#define _THIS_SIZE2 "256" +#define _THIS_SIZE1 "512" +#endif + +#define _THIS_DOC "Composed of two " _THIS_SIZE2 " bit floats" + +NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(0, 0) +#else + PyObject_HEAD_INIT(0) + 0, /* ob_size */ +#endif + "numpy.@name@" _THIS_SIZE1, /* tp_name*/ + sizeof(Py@NAME@ScalarObject), /* tp_basicsize*/ + 0, /* tp_itemsize*/ + 0, /* tp_dealloc*/ + 0, /* tp_print*/ + 0, /* tp_getattr*/ + 0, /* tp_setattr*/ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + 0, /* tp_repr*/ + 0, /* tp_as_number*/ + 0, /* tp_as_sequence*/ + 0, /* tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call*/ + 0, /* tp_str*/ + 0, /* tp_getattro*/ + 0, /* tp_setattro*/ + 0, /* tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /* tp_flags*/ + _THIS_DOC, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; +#undef _THIS_SIZE1 +#undef _THIS_SIZE2 +#undef _THIS_DOC + +/**end repeat**/ + +/* + * This table maps the built-in type numbers to their scalar + * type numbers. Note that signed integers are mapped to INTNEG_SCALAR, + * which is different than what PyArray_ScalarKind returns. + */ +NPY_NO_EXPORT signed char +_npy_scalar_kinds_table[NPY_NTYPES]; + +/* + * This table maps a scalar kind (excluding NPY_NOSCALAR) + * to the smallest type number of that kind. + */ +NPY_NO_EXPORT signed char +_npy_smallest_type_of_kind_table[NPY_NSCALARKINDS]; + +/* + * This table gives the type of the same kind, but next in the sequence + * of sizes. + */ +NPY_NO_EXPORT signed char +_npy_next_larger_type_table[NPY_NTYPES]; + +/* + * This table describes safe casting for small type numbers, + * and is used by PyArray_CanCastSafely. + */ +NPY_NO_EXPORT unsigned char +_npy_can_cast_safely_table[NPY_NTYPES][NPY_NTYPES]; + +/* + * This table gives the smallest-size and smallest-kind type to which + * the input types may be safely cast, according to _npy_can_cast_safely. + */ +NPY_NO_EXPORT signed char +_npy_type_promotion_table[NPY_NTYPES][NPY_NTYPES]; + +NPY_NO_EXPORT void +initialize_casting_tables(void) +{ + int i, j; + + _npy_smallest_type_of_kind_table[NPY_BOOL_SCALAR] = NPY_BOOL; + _npy_smallest_type_of_kind_table[NPY_INTPOS_SCALAR] = NPY_UBYTE; + _npy_smallest_type_of_kind_table[NPY_INTNEG_SCALAR] = NPY_BYTE; + _npy_smallest_type_of_kind_table[NPY_FLOAT_SCALAR] = NPY_HALF; + _npy_smallest_type_of_kind_table[NPY_COMPLEX_SCALAR] = NPY_CFLOAT; + _npy_smallest_type_of_kind_table[NPY_OBJECT_SCALAR] = NPY_OBJECT; + + /* Default for built-in types is object scalar */ + memset(_npy_scalar_kinds_table, NPY_OBJECT_SCALAR, + sizeof(_npy_scalar_kinds_table)); + /* Default for next largest type is -1, signalling no bigger */ + memset(_npy_next_larger_type_table, -1, + sizeof(_npy_next_larger_type_table)); + + /* Compile-time loop of scalar kinds */ + + /**begin repeat + * #NAME = BOOL, + * BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #BIGGERTYPE = -1, + * NPY_SHORT, NPY_USHORT, NPY_INT, NPY_UINT, NPY_LONG, NPY_ULONG, + * NPY_LONGLONG, NPY_ULONGLONG, -1, -1, + * NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, -1, + * NPY_CDOUBLE, NPY_CLONGDOUBLE, -1# + * #SCKIND = BOOL, + * (INTNEG, INTPOS)*5, + * FLOAT*4, + * COMPLEX*3# + */ + + _npy_scalar_kinds_table[NPY_@NAME@] = NPY_@SCKIND@_SCALAR; + _npy_next_larger_type_table[NPY_@NAME@] = @BIGGERTYPE@; + + /**end repeat**/ + + memset(_npy_can_cast_safely_table, 0, sizeof(_npy_can_cast_safely_table)); + + for (i = 0; i < NPY_NTYPES; ++i) { + /* Identity */ + _npy_can_cast_safely_table[i][i] = 1; + if (i != NPY_DATETIME) { + /* + * Bool -> except datetime (since + * it conceptually has no zero) + */ + _npy_can_cast_safely_table[NPY_BOOL][i] = 1; + } + /* -> Object */ + _npy_can_cast_safely_table[i][NPY_OBJECT] = 1; + /* -> Void */ + _npy_can_cast_safely_table[i][NPY_VOID] = 1; + } + + _npy_can_cast_safely_table[NPY_STRING][NPY_UNICODE] = 1; + _npy_can_cast_safely_table[NPY_BOOL][NPY_TIMEDELTA] = 1; + +#ifndef NPY_SIZEOF_BYTE +#define NPY_SIZEOF_BYTE 1 +#endif + + /* Compile-time loop of casting rules */ + + /**begin repeat + * #FROM_NAME = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #FROM_BASENAME = BYTE, BYTE, SHORT, SHORT, INT, INT, + * LONG, LONG, LONGLONG, LONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * FLOAT, DOUBLE, LONGDOUBLE# + * #from_isint = 1, 0, 1, 0, 1, 0, 1, 0, + * 1, 0, 0, 0, 0, 0, + * 0, 0, 0# + * #from_isuint = 0, 1, 0, 1, 0, 1, 0, 1, + * 0, 1, 0, 0, 0, 0, + * 0, 0, 0# + * #from_isfloat = 0, 0, 0, 0, 0, 0, 0, 0, + * 0, 0, 1, 1, 1, 1, + * 0, 0, 0# + * #from_iscomplex = 0, 0, 0, 0, 0, 0, 0, 0, + * 0, 0, 0, 0, 0, 0, + * 1, 1, 1# + */ + +#define _FROM_BSIZE NPY_SIZEOF_@FROM_BASENAME@ +#define _FROM_NUM (NPY_@FROM_NAME@) + + _npy_can_cast_safely_table[_FROM_NUM][NPY_STRING] = 1; + _npy_can_cast_safely_table[_FROM_NUM][NPY_UNICODE] = 1; + + /* Allow casts from any integer to the TIMEDELTA type */ +#if @from_isint@ || @from_isuint@ + _npy_can_cast_safely_table[_FROM_NUM][NPY_TIMEDELTA] = 1; +#endif + + /**begin repeat1 + * #TO_NAME = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #TO_BASENAME = BYTE, BYTE, SHORT, SHORT, INT, INT, + * LONG, LONG, LONGLONG, LONGLONG, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * FLOAT, DOUBLE, LONGDOUBLE# + * #to_isint = 1, 0, 1, 0, 1, 0, 1, 0, + * 1, 0, 0, 0, 0, 0, + * 0, 0, 0# + * #to_isuint = 0, 1, 0, 1, 0, 1, 0, 1, + * 0, 1, 0, 0, 0, 0, + * 0, 0, 0# + * #to_isfloat = 0, 0, 0, 0, 0, 0, 0, 0, + * 0, 0, 1, 1, 1, 1, + * 0, 0, 0# + * #to_iscomplex = 0, 0, 0, 0, 0, 0, 0, 0, + * 0, 0, 0, 0, 0, 0, + * 1, 1, 1# + */ +#define _TO_BSIZE NPY_SIZEOF_@TO_BASENAME@ +#define _TO_NUM (NPY_@TO_NAME@) + + /* + * NOTE: _FROM_BSIZE and _TO_BSIZE are the sizes of the "base type" + * which is the same as the size of the type except for + * complex, where it is the size of the real type. + */ + +#if @from_isint@ + +# if @to_isint@ && (_TO_BSIZE >= _FROM_BSIZE) + /* int -> int */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_isfloat@ && (_FROM_BSIZE < 8) && (_TO_BSIZE > _FROM_BSIZE) + /* int -> float */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_isfloat@ && (_FROM_BSIZE >= 8) && (_TO_BSIZE >= _FROM_BSIZE) + /* int -> float */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_iscomplex@ && (_FROM_BSIZE < 8) && (_TO_BSIZE > _FROM_BSIZE) + /* int -> complex */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_iscomplex@ && (_FROM_BSIZE >= 8) && (_TO_BSIZE >= _FROM_BSIZE) + /* int -> complex */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# endif + +#elif @from_isuint@ + +# if @to_isint@ && (_TO_BSIZE > _FROM_BSIZE) + /* uint -> int */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_isuint@ && (_TO_BSIZE >= _FROM_BSIZE) + /* uint -> uint */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_isfloat@ && (_FROM_BSIZE < 8) && (_TO_BSIZE > _FROM_BSIZE) + /* uint -> float */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_isfloat@ && (_FROM_BSIZE >= 8) && (_TO_BSIZE >= _FROM_BSIZE) + /* uint -> float */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_iscomplex@ && (_FROM_BSIZE < 8) && (_TO_BSIZE > _FROM_BSIZE) + /* uint -> complex */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_iscomplex@ && (_FROM_BSIZE >= 8) && (_TO_BSIZE >= _FROM_BSIZE) + /* uint -> complex */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# endif + + +#elif @from_isfloat@ + +# if @to_isfloat@ && (_TO_BSIZE >= _FROM_BSIZE) + /* float -> float */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# elif @to_iscomplex@ && (_TO_BSIZE >= _FROM_BSIZE) + /* float -> complex */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# endif + +#elif @from_iscomplex@ + +# if @to_iscomplex@ && (_TO_BSIZE >= _FROM_BSIZE) + /* complex -> complex */ + _npy_can_cast_safely_table[_FROM_NUM][_TO_NUM] = 1; +# endif + +#endif + +#undef _TO_NUM +#undef _TO_BSIZE + +/**end repeat1**/ + +#undef _FROM_NUM +#undef _FROM_BSIZE + +/**end repeat**/ + + /* + * Now that the _can_cast_safely table is finished, we can + * use it to build the _type_promotion table + */ + for (i = 0; i < NPY_NTYPES; ++i) { + _npy_type_promotion_table[i][i] = i; + /* Don't let number promote to string/unicode/void/datetime/timedelta */ + if (i == NPY_STRING || i == NPY_UNICODE || i == NPY_VOID || + i == NPY_DATETIME || i == NPY_TIMEDELTA) { + /* Promoting these types requires examining their contents */ + _npy_type_promotion_table[i][i] = -1; + for (j = i + 1; j < NPY_NTYPES; ++j) { + _npy_type_promotion_table[i][j] = -1; + _npy_type_promotion_table[j][i] = -1; + } + /* Except they can convert to OBJECT */ + _npy_type_promotion_table[i][NPY_OBJECT] = NPY_OBJECT; + _npy_type_promotion_table[NPY_OBJECT][i] = NPY_OBJECT; + } + else { + for (j = i + 1; j < NPY_NTYPES; ++j) { + /* Don't let number promote to string/unicode/void */ + if (j == NPY_STRING || j == NPY_UNICODE || j == NPY_VOID) { + _npy_type_promotion_table[i][j] = -1; + _npy_type_promotion_table[j][i] = -1; + } + else if (_npy_can_cast_safely_table[i][j]) { + _npy_type_promotion_table[i][j] = j; + _npy_type_promotion_table[j][i] = j; + } + else if (_npy_can_cast_safely_table[j][i]) { + _npy_type_promotion_table[i][j] = i; + _npy_type_promotion_table[j][i] = i; + } + else { + int k, iskind, jskind, skind; + iskind = _npy_scalar_kinds_table[i]; + jskind = _npy_scalar_kinds_table[j]; + /* If there's no kind (void/string/etc) */ + if (iskind == NPY_NOSCALAR || jskind == NPY_NOSCALAR) { + k = -1; + } + else { + /* Start with the type of larger kind */ + if (iskind > jskind) { + skind = iskind; + k = i; + } + else { + skind = jskind; + k = j; + } + for (;;) { + /* Try the next larger type of this kind */ + k = _npy_next_larger_type_table[k]; + + /* If there is no larger, try a larger kind */ + if (k < 0) { + ++skind; + /* Use -1 to signal no promoted type found */ + if (skind < NPY_NSCALARKINDS) { + k = _npy_smallest_type_of_kind_table[skind]; + } + else { + k = -1; + break; + } + } + + if (_npy_can_cast_safely_table[i][k] && + _npy_can_cast_safely_table[j][k]) { + break; + } + } + } + _npy_type_promotion_table[i][j] = k; + _npy_type_promotion_table[j][i] = k; + } + } + } + } +} + +#ifndef NPY_PY3K +/* + * In python2, the `float` and `complex` types still implement the obsolete + * "tp_print" method, which uses CPython's float-printing routines to print the + * float. Numpy's float_/cfloat inherit from Python float/complex, but + * override its tp_repr and tp_str methods. In order to avoid an inconsistency + * with the inherited tp_print, we need to override it too. + * + * In python3 the tp_print method is reserved/unused. + */ +static int +float_print(PyObject *o, FILE *fp, int flags) +{ + int ret; + PyObject *to_print; + if (flags & Py_PRINT_RAW) { + to_print = PyObject_Str(o); + } + else { + to_print = PyObject_Repr(o); + } + + if (to_print == NULL) { + return -1; + } + + ret = PyObject_Print(to_print, fp, flags); + Py_DECREF(to_print); + return ret; +} +#endif + +static PyNumberMethods longdoubletype_as_number; +static PyNumberMethods clongdoubletype_as_number; +static void init_basetypes(void); + + +NPY_NO_EXPORT void +initialize_numeric_types(void) +{ + init_basetypes(); + PyGenericArrType_Type.tp_dealloc = (destructor)gentype_dealloc; + PyGenericArrType_Type.tp_as_number = &gentype_as_number; + PyGenericArrType_Type.tp_as_buffer = &gentype_as_buffer; + PyGenericArrType_Type.tp_as_mapping = &gentype_as_mapping; + PyGenericArrType_Type.tp_flags = BASEFLAGS; + PyGenericArrType_Type.tp_methods = gentype_methods; + PyGenericArrType_Type.tp_getset = gentype_getsets; + PyGenericArrType_Type.tp_new = NULL; + PyGenericArrType_Type.tp_alloc = gentype_alloc; + PyGenericArrType_Type.tp_free = (freefunc)gentype_free; + PyGenericArrType_Type.tp_richcompare = gentype_richcompare; + + PyBoolArrType_Type.tp_as_number = &bool_arrtype_as_number; + /* + * need to add dummy versions with filled-in nb_index + * in-order for PyType_Ready to fill in .__index__() method + * also fill array_type_as_number struct with reasonable defaults + */ + + /**begin repeat + * #name = byte, short, int, long, longlong, ubyte, ushort, + * uint, ulong, ulonglong# + * #NAME = Byte, Short, Int, Long, LongLong, UByte, UShort, + * UInt, ULong, ULongLong# + */ + @name@_arrtype_as_number = gentype_as_number; + Py@NAME@ArrType_Type.tp_as_number = &@name@_arrtype_as_number; + Py@NAME@ArrType_Type.tp_as_number->nb_index = (unaryfunc)@name@_index; + + /**end repeat**/ + + /**begin repeat + * #name = half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #NAME = Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble# + */ + @name@_arrtype_as_number = gentype_as_number; + Py@NAME@ArrType_Type.tp_as_number = &@name@_arrtype_as_number; + + /**end repeat**/ + +#ifndef NPY_PY3K + PyDoubleArrType_Type.tp_print = &float_print; + PyCDoubleArrType_Type.tp_print = &float_print; +#endif + + + PyBoolArrType_Type.tp_as_number->nb_index = (unaryfunc)bool_index; + + PyStringArrType_Type.tp_alloc = NULL; + PyStringArrType_Type.tp_free = NULL; + + PyStringArrType_Type.tp_repr = stringtype_repr; + PyStringArrType_Type.tp_str = stringtype_str; + + PyUnicodeArrType_Type.tp_repr = unicodetype_repr; + PyUnicodeArrType_Type.tp_str = unicodetype_str; + + PyVoidArrType_Type.tp_methods = voidtype_methods; + PyVoidArrType_Type.tp_getset = voidtype_getsets; + PyVoidArrType_Type.tp_as_mapping = &voidtype_as_mapping; + PyVoidArrType_Type.tp_as_sequence = &voidtype_as_sequence; + PyVoidArrType_Type.tp_repr = voidtype_repr; + PyVoidArrType_Type.tp_str = voidtype_str; + + PyIntegerArrType_Type.tp_getset = inttype_getsets; + + /**begin repeat + * #NAME= Number, Integer, SignedInteger, UnsignedInteger, Inexact, + * Floating, ComplexFloating, Flexible, Character# + */ + + Py@NAME@ArrType_Type.tp_flags = BASEFLAGS; + + /**end repeat**/ + + /**begin repeat + * #name = bool, byte, short, int, long, longlong, ubyte, ushort, uint, + * ulong, ulonglong, half, float, double, longdouble, cfloat, + * cdouble, clongdouble, string, unicode, void, object, datetime, + * timedelta# + * #NAME = Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, + * ULong, ULongLong, Half, Float, Double, LongDouble, CFloat, + * CDouble, CLongDouble, String, Unicode, Void, Object, Datetime, + * Timedelta# + */ + + Py@NAME@ArrType_Type.tp_flags = BASEFLAGS; + Py@NAME@ArrType_Type.tp_new = @name@_arrtype_new; + Py@NAME@ArrType_Type.tp_richcompare = gentype_richcompare; + + /**end repeat**/ + + /**begin repeat + * #name = bool, byte, short, ubyte, ushort, uint, ulong, ulonglong, + * half, float, longdouble, cfloat, clongdouble, void, object, + * datetime, timedelta# + * #NAME = Bool, Byte, Short, UByte, UShort, UInt, ULong, ULongLong, + * Half, Float, LongDouble, CFloat, CLongDouble, Void, Object, + * Datetime, Timedelta# + */ + + Py@NAME@ArrType_Type.tp_hash = @name@_arrtype_hash; + + /**end repeat**/ + + /**begin repeat + * #name = cfloat, clongdouble# + * #NAME = CFloat, CLongDouble# + */ + + Py@NAME@ArrType_Type.tp_methods = @name@type_methods; + + /**end repeat**/ + +#if (NPY_SIZEOF_INT != NPY_SIZEOF_LONG) || defined(NPY_PY3K) + /* We won't be inheriting from Python Int type. */ + PyIntArrType_Type.tp_hash = int_arrtype_hash; +#endif + +#if defined(NPY_PY3K) + /* We won't be inheriting from Python Int type. */ + PyLongArrType_Type.tp_hash = long_arrtype_hash; +#endif + +#if (NPY_SIZEOF_LONG != NPY_SIZEOF_LONGLONG) || defined(NPY_PY3K) + /* We won't be inheriting from Python Int type. */ + PyLongLongArrType_Type.tp_hash = longlong_arrtype_hash; +#endif + + /**begin repeat + * #name = repr, str# + */ + + PyHalfArrType_Type.tp_@name@ = halftype_@name@; + + PyFloatArrType_Type.tp_@name@ = floattype_@name@; + PyCFloatArrType_Type.tp_@name@ = cfloattype_@name@; + + PyDoubleArrType_Type.tp_@name@ = doubletype_@name@; + PyCDoubleArrType_Type.tp_@name@ = cdoubletype_@name@; + + PyDatetimeArrType_Type.tp_@name@ = datetimetype_@name@; + PyTimedeltaArrType_Type.tp_@name@ = timedeltatype_@name@; + + /**end repeat**/ + + + /**begin repeat + * #Type = Bool, Byte, UByte, Short, UShort, Int, UInt, Long, + * ULong, LongLong, ULongLong# + */ + + /* both str/repr use genint_type_str to avoid trailing "L" of longs */ + Py@Type@ArrType_Type.tp_str = genint_type_str; + Py@Type@ArrType_Type.tp_repr = genint_type_str; + + /**end repeat**/ + + + + /**begin repeat + * #char = ,c# + * #CHAR = ,C# + */ + + /* + * These need to be coded specially because longdouble/clongdouble getitem + * does not return a normal Python type + */ + @char@longdoubletype_as_number.nb_float = @char@longdoubletype_float; +#if defined(NPY_PY3K) + @char@longdoubletype_as_number.nb_int = @char@longdoubletype_long; +#else + @char@longdoubletype_as_number.nb_int = @char@longdoubletype_int; + @char@longdoubletype_as_number.nb_long = @char@longdoubletype_long; + @char@longdoubletype_as_number.nb_hex = @char@longdoubletype_hex; + @char@longdoubletype_as_number.nb_oct = @char@longdoubletype_oct; +#endif + + Py@CHAR@LongDoubleArrType_Type.tp_as_number = &@char@longdoubletype_as_number; + Py@CHAR@LongDoubleArrType_Type.tp_repr = @char@longdoubletype_repr; + Py@CHAR@LongDoubleArrType_Type.tp_str = @char@longdoubletype_str; + + /**end repeat**/ + + PyStringArrType_Type.tp_itemsize = sizeof(char); + PyVoidArrType_Type.tp_dealloc = (destructor) void_dealloc; + + PyArrayIter_Type.tp_iter = PyObject_SelfIter; + PyArrayMapIter_Type.tp_iter = PyObject_SelfIter; +} + +typedef struct { + PyTypeObject * type; + int typenum; +} scalar_type; + +static scalar_type typeobjects[] = { + {&PyBoolArrType_Type, NPY_BOOL}, + {&PyByteArrType_Type, NPY_BYTE}, + {&PyUByteArrType_Type, NPY_UBYTE}, + {&PyShortArrType_Type, NPY_SHORT}, + {&PyUShortArrType_Type, NPY_USHORT}, + {&PyIntArrType_Type, NPY_INT}, + {&PyUIntArrType_Type, NPY_UINT}, + {&PyLongArrType_Type, NPY_LONG}, + {&PyULongArrType_Type, NPY_ULONG}, + {&PyLongLongArrType_Type, NPY_LONGLONG}, + {&PyULongLongArrType_Type, NPY_ULONGLONG}, + {&PyFloatArrType_Type, NPY_FLOAT}, + {&PyDoubleArrType_Type, NPY_DOUBLE}, + {&PyLongDoubleArrType_Type, NPY_LONGDOUBLE}, + {&PyCFloatArrType_Type, NPY_CFLOAT}, + {&PyCDoubleArrType_Type, NPY_CDOUBLE}, + {&PyCLongDoubleArrType_Type, NPY_CLONGDOUBLE}, + {&PyObjectArrType_Type, NPY_OBJECT}, + {&PyStringArrType_Type, NPY_STRING}, + {&PyUnicodeArrType_Type, NPY_UNICODE}, + {&PyVoidArrType_Type, NPY_VOID}, + {&PyDatetimeArrType_Type, NPY_DATETIME}, + {&PyTimedeltaArrType_Type, NPY_TIMEDELTA}, + {&PyHalfArrType_Type, NPY_HALF} +}; + +static int compare_types(const void * a_, const void * b_) +{ + const PyTypeObject * a = ((const scalar_type *)a_)->type; + const PyTypeObject * b = ((const scalar_type *)b_)->type; + if (a < b) { + return -1; + } + else if (a > b) { + return 1; + } + return 0; +} + +static void init_basetypes(void) +{ + qsort(typeobjects, sizeof(typeobjects) / sizeof(typeobjects[0]), + sizeof(typeobjects[0]), + compare_types); +} + + +NPY_NO_EXPORT int +get_typeobj_idx(PyTypeObject * obj) +{ + npy_intp imin = 0, imax = sizeof(typeobjects) / sizeof(typeobjects[0]) - 1; + while (imax >= imin) + { + npy_intp imid = ((imax - imin) / 2) + imin; + if(typeobjects[imid].type == obj) { + return imid; + } + else if (typeobjects[imid].type < obj) { + imin = imid + 1; + } + else { + imax = imid - 1; + } + } + + return -1; +} + +NPY_NO_EXPORT int +is_anyscalar_exact(PyObject *obj) +{ + return get_typeobj_idx(Py_TYPE(obj)) >= 0; +} + +NPY_NO_EXPORT int +_typenum_fromtypeobj(PyObject *type, int user) +{ + int typenum, i; + + typenum = NPY_NOTYPE; + i = get_typeobj_idx((PyTypeObject*)type); + if (i >= 0) { + typenum = typeobjects[i].typenum; + } + + if (!user) { + return typenum; + } + /* Search any registered types */ + i = 0; + while (i < NPY_NUMUSERTYPES) { + if (type == (PyObject *)(userdescrs[i]->typeobj)) { + typenum = i + NPY_USERDEF; + break; + } + i++; + } + return typenum; +} diff --git a/numpy/core/src/multiarray/scalartypes.h b/numpy/core/src/multiarray/scalartypes.h new file mode 100644 index 0000000..83b1881 --- /dev/null +++ b/numpy/core/src/multiarray/scalartypes.h @@ -0,0 +1,39 @@ +#ifndef _NPY_SCALARTYPES_H_ +#define _NPY_SCALARTYPES_H_ + +/* Internal look-up tables */ +extern NPY_NO_EXPORT unsigned char +_npy_can_cast_safely_table[NPY_NTYPES][NPY_NTYPES]; +extern NPY_NO_EXPORT signed char +_npy_scalar_kinds_table[NPY_NTYPES]; +extern NPY_NO_EXPORT signed char +_npy_type_promotion_table[NPY_NTYPES][NPY_NTYPES]; +extern NPY_NO_EXPORT signed char +_npy_smallest_type_of_kind_table[NPY_NSCALARKINDS]; +extern NPY_NO_EXPORT signed char +_npy_next_larger_type_table[NPY_NTYPES]; + +NPY_NO_EXPORT void +initialize_casting_tables(void); + +NPY_NO_EXPORT void +initialize_numeric_types(void); + +#if PY_VERSION_HEX >= 0x03000000 +NPY_NO_EXPORT void +gentype_struct_free(PyObject *ptr); +#else +NPY_NO_EXPORT void +gentype_struct_free(void *ptr, void *arg); +#endif + +NPY_NO_EXPORT int +is_anyscalar_exact(PyObject *obj); + +NPY_NO_EXPORT int +_typenum_fromtypeobj(PyObject *type, int user); + +NPY_NO_EXPORT void * +scalar_value(PyObject *scalar, PyArray_Descr *descr); + +#endif diff --git a/numpy/core/src/multiarray/sequence.c b/numpy/core/src/multiarray/sequence.c new file mode 100644 index 0000000..4769bda --- /dev/null +++ b/numpy/core/src/multiarray/sequence.c @@ -0,0 +1,63 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "common.h" +#include "mapping.h" + +#include "sequence.h" +#include "calculation.h" + +/************************************************************************* + **************** Implement Sequence Protocol ************************** + *************************************************************************/ + +/* Some of this is repeated in the array_as_mapping protocol. But + we fill it in here so that PySequence_XXXX calls work as expected +*/ + +static int +array_contains(PyArrayObject *self, PyObject *el) +{ + /* equivalent to (self == el).any() */ + + int ret; + PyObject *res, *any; + + res = PyArray_EnsureAnyArray(PyObject_RichCompare((PyObject *)self, + el, Py_EQ)); + if (res == NULL) { + return -1; + } + any = PyArray_Any((PyArrayObject *)res, NPY_MAXDIMS, NULL); + Py_DECREF(res); + ret = PyObject_IsTrue(any); + Py_DECREF(any); + return ret; +} + +NPY_NO_EXPORT PySequenceMethods array_as_sequence = { + (lenfunc)array_length, /*sq_length*/ + (binaryfunc)NULL, /*sq_concat is handled by nb_add*/ + (ssizeargfunc)NULL, + (ssizeargfunc)array_item, + (ssizessizeargfunc)NULL, + (ssizeobjargproc)array_assign_item, /*sq_ass_item*/ + (ssizessizeobjargproc)NULL, /*sq_ass_slice*/ + (objobjproc) array_contains, /*sq_contains */ + (binaryfunc) NULL, /*sg_inplace_concat */ + (ssizeargfunc)NULL, +}; + + +/****************** End of Sequence Protocol ****************************/ + diff --git a/numpy/core/src/multiarray/sequence.h b/numpy/core/src/multiarray/sequence.h new file mode 100644 index 0000000..b28c50d --- /dev/null +++ b/numpy/core/src/multiarray/sequence.h @@ -0,0 +1,6 @@ +#ifndef _NPY_ARRAY_SEQUENCE_H_ +#define _NPY_ARRAY_SEQUENCE_H_ + +extern NPY_NO_EXPORT PySequenceMethods array_as_sequence; + +#endif diff --git a/numpy/core/src/multiarray/shape.c b/numpy/core/src/multiarray/shape.c new file mode 100644 index 0000000..40925d8 --- /dev/null +++ b/numpy/core/src/multiarray/shape.c @@ -0,0 +1,1117 @@ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "numpy/npy_math.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" + +#include "ctors.h" + +#include "shape.h" + +#include "templ_common.h" /* for npy_mul_with_overflow_intp */ +#include "common.h" /* for convert_shape_to_string */ +#include "alloc.h" + +static int +_fix_unknown_dimension(PyArray_Dims *newshape, PyArrayObject *arr); + +static int +_attempt_nocopy_reshape(PyArrayObject *self, int newnd, npy_intp* newdims, + npy_intp *newstrides, int is_f_order); + +static void +_putzero(char *optr, PyObject *zero, PyArray_Descr *dtype); + +/*NUMPY_API + * Resize (reallocate data). Only works if nothing else is referencing this + * array and it is contiguous. If refcheck is 0, then the reference count is + * not checked and assumed to be 1. You still must own this data and have no + * weak-references and no base object. + */ +NPY_NO_EXPORT PyObject * +PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, + NPY_ORDER order) +{ + npy_intp oldnbytes, newnbytes; + npy_intp oldsize, newsize; + int new_nd=newshape->len, k, n, elsize; + int refcnt; + npy_intp* new_dimensions=newshape->ptr; + npy_intp new_strides[NPY_MAXDIMS]; + npy_intp *dimptr; + char *new_data; + + if (!PyArray_ISONESEGMENT(self)) { + PyErr_SetString(PyExc_ValueError, + "resize only works on single-segment arrays"); + return NULL; + } + + /* Compute total size of old and new arrays. The new size might overflow */ + oldsize = PyArray_SIZE(self); + newsize = 1; + for(k = 0; k < new_nd; k++) { + if (new_dimensions[k] == 0) { + newsize = 0; + break; + } + if (new_dimensions[k] < 0) { + PyErr_SetString(PyExc_ValueError, + "negative dimensions not allowed"); + return NULL; + } + if (npy_mul_with_overflow_intp(&newsize, newsize, new_dimensions[k])) { + return PyErr_NoMemory(); + } + } + + /* Convert to number of bytes. The new count might overflow */ + elsize = PyArray_DESCR(self)->elsize; + oldnbytes = oldsize * elsize; + if (npy_mul_with_overflow_intp(&newnbytes, newsize, elsize)) { + return PyErr_NoMemory(); + } + + if (oldnbytes != newnbytes) { + if (!(PyArray_FLAGS(self) & NPY_ARRAY_OWNDATA)) { + PyErr_SetString(PyExc_ValueError, + "cannot resize this array: it does not own its data"); + return NULL; + } + + if (refcheck) { +#ifdef PYPY_VERSION + PyErr_SetString(PyExc_ValueError, + "cannot resize an array with refcheck=True on PyPy.\n" + "Use the resize function or refcheck=False"); + return NULL; +#else + refcnt = PyArray_REFCOUNT(self); +#endif /* PYPY_VERSION */ + } + else { + refcnt = 1; + } + if ((refcnt > 2) + || (PyArray_BASE(self) != NULL) + || (((PyArrayObject_fields *)self)->weakreflist != NULL)) { + PyErr_SetString(PyExc_ValueError, + "cannot resize an array that " + "references or is referenced\n" + "by another array in this way. Use the resize function"); + return NULL; + } + + /* Reallocate space if needed - allocating 0 is forbidden */ + new_data = PyDataMem_RENEW( + PyArray_DATA(self), newnbytes == 0 ? elsize : newnbytes); + if (new_data == NULL) { + PyErr_SetString(PyExc_MemoryError, + "cannot allocate memory for array"); + return NULL; + } + ((PyArrayObject_fields *)self)->data = new_data; + } + + if (newnbytes > oldnbytes && PyArray_ISWRITEABLE(self)) { + /* Fill new memory with zeros */ + if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_ITEM_REFCOUNT)) { + PyObject *zero = PyInt_FromLong(0); + char *optr; + optr = PyArray_BYTES(self) + oldnbytes; + n = newsize - oldsize; + for (k = 0; k < n; k++) { + _putzero((char *)optr, zero, PyArray_DESCR(self)); + optr += elsize; + } + Py_DECREF(zero); + } + else{ + memset(PyArray_BYTES(self) + oldnbytes, 0, newnbytes - oldnbytes); + } + } + + if (new_nd > 0) { + if (PyArray_NDIM(self) != new_nd) { + /* Different number of dimensions. */ + ((PyArrayObject_fields *)self)->nd = new_nd; + /* Need new dimensions and strides arrays */ + dimptr = PyDimMem_RENEW(PyArray_DIMS(self), 3*new_nd); + if (dimptr == NULL) { + PyErr_SetString(PyExc_MemoryError, + "cannot allocate memory for array"); + return NULL; + } + ((PyArrayObject_fields *)self)->dimensions = dimptr; + ((PyArrayObject_fields *)self)->strides = dimptr + new_nd; + } + /* make new_strides variable */ + _array_fill_strides(new_strides, new_dimensions, new_nd, + PyArray_DESCR(self)->elsize, PyArray_FLAGS(self), + &(((PyArrayObject_fields *)self)->flags)); + memmove(PyArray_DIMS(self), new_dimensions, new_nd*sizeof(npy_intp)); + memmove(PyArray_STRIDES(self), new_strides, new_nd*sizeof(npy_intp)); + } + else { + PyDimMem_FREE(((PyArrayObject_fields *)self)->dimensions); + ((PyArrayObject_fields *)self)->nd = 0; + ((PyArrayObject_fields *)self)->dimensions = NULL; + ((PyArrayObject_fields *)self)->strides = NULL; + } + Py_RETURN_NONE; +} + +/* + * Returns a new array + * with the new shape from the data + * in the old array --- order-perspective depends on order argument. + * copy-only-if-necessary + */ + +/*NUMPY_API + * New shape for an array + */ +NPY_NO_EXPORT PyObject * +PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims, + NPY_ORDER order) +{ + npy_intp i; + npy_intp *dimensions = newdims->ptr; + PyArrayObject *ret; + int ndim = newdims->len; + npy_bool same, incref = NPY_TRUE; + npy_intp *strides = NULL; + npy_intp newstrides[NPY_MAXDIMS]; + int flags; + + if (order == NPY_ANYORDER) { + order = PyArray_ISFORTRAN(self); + } + else if (order == NPY_KEEPORDER) { + PyErr_SetString(PyExc_ValueError, + "order 'K' is not permitted for reshaping"); + return NULL; + } + /* Quick check to make sure anything actually needs to be done */ + if (ndim == PyArray_NDIM(self)) { + same = NPY_TRUE; + i = 0; + while (same && i < ndim) { + if (PyArray_DIM(self,i) != dimensions[i]) { + same=NPY_FALSE; + } + i++; + } + if (same) { + return PyArray_View(self, NULL, NULL); + } + } + + /* + * fix any -1 dimensions and check new-dimensions against old size + */ + if (_fix_unknown_dimension(newdims, self) < 0) { + return NULL; + } + /* + * sometimes we have to create a new copy of the array + * in order to get the right orientation and + * because we can't just re-use the buffer with the + * data in the order it is in. + * NPY_RELAXED_STRIDES_CHECKING: size check is unnecessary when set. + */ + if ((PyArray_SIZE(self) > 1) && + ((order == NPY_CORDER && !PyArray_IS_C_CONTIGUOUS(self)) || + (order == NPY_FORTRANORDER && !PyArray_IS_F_CONTIGUOUS(self)))) { + int success = 0; + success = _attempt_nocopy_reshape(self, ndim, dimensions, + newstrides, order); + if (success) { + /* no need to copy the array after all */ + strides = newstrides; + } + else { + PyObject *newcopy; + newcopy = PyArray_NewCopy(self, order); + if (newcopy == NULL) { + return NULL; + } + incref = NPY_FALSE; + self = (PyArrayObject *)newcopy; + } + } + /* We always have to interpret the contiguous buffer correctly */ + + /* Make sure the flags argument is set. */ + flags = PyArray_FLAGS(self); + if (ndim > 1) { + if (order == NPY_FORTRANORDER) { + flags &= ~NPY_ARRAY_C_CONTIGUOUS; + flags |= NPY_ARRAY_F_CONTIGUOUS; + } + else { + flags &= ~NPY_ARRAY_F_CONTIGUOUS; + flags |= NPY_ARRAY_C_CONTIGUOUS; + } + } + + Py_INCREF(PyArray_DESCR(self)); + ret = (PyArrayObject *)PyArray_NewFromDescr_int(Py_TYPE(self), + PyArray_DESCR(self), + ndim, dimensions, + strides, + PyArray_DATA(self), + flags, (PyObject *)self, 0, 1); + + if (ret == NULL) { + goto fail; + } + + if (incref) { + Py_INCREF(self); + } + if (PyArray_SetBaseObject(ret, (PyObject *)self)) { + Py_DECREF(ret); + return NULL; + } + + PyArray_UpdateFlags(ret, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS); + return (PyObject *)ret; + + fail: + if (!incref) { + Py_DECREF(self); + } + return NULL; +} + + + +/* For backward compatibility -- Not recommended */ + +/*NUMPY_API + * Reshape + */ +NPY_NO_EXPORT PyObject * +PyArray_Reshape(PyArrayObject *self, PyObject *shape) +{ + PyObject *ret; + PyArray_Dims newdims; + + if (!PyArray_IntpConverter(shape, &newdims)) { + return NULL; + } + ret = PyArray_Newshape(self, &newdims, NPY_CORDER); + npy_free_cache_dim_obj(newdims); + return ret; +} + + +static void +_putzero(char *optr, PyObject *zero, PyArray_Descr *dtype) +{ + if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) { + memset(optr, 0, dtype->elsize); + } + else if (PyDataType_HASFIELDS(dtype)) { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; + while (PyDict_Next(dtype->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) { + return; + } + _putzero(optr + offset, zero, new); + } + } + else { + npy_intp i; + for (i = 0; i < dtype->elsize / sizeof(zero); i++) { + Py_INCREF(zero); + NPY_COPY_PYOBJECT_PTR(optr, &zero); + optr += sizeof(zero); + } + } + return; +} + + +/* + * attempt to reshape an array without copying data + * + * The requested newdims are not checked, but must be compatible with + * the size of self, which must be non-zero. Other than that this + * function should correctly handle all reshapes, including axes of + * length 1. Zero strides should work but are untested. + * + * If a copy is needed, returns 0 + * If no copy is needed, returns 1 and fills newstrides + * with appropriate strides + * + * The "is_f_order" argument describes how the array should be viewed + * during the reshape, not how it is stored in memory (that + * information is in PyArray_STRIDES(self)). + * + * If some output dimensions have length 1, the strides assigned to + * them are arbitrary. In the current implementation, they are the + * stride of the next-fastest index. + */ +static int +_attempt_nocopy_reshape(PyArrayObject *self, int newnd, npy_intp* newdims, + npy_intp *newstrides, int is_f_order) +{ + int oldnd; + npy_intp olddims[NPY_MAXDIMS]; + npy_intp oldstrides[NPY_MAXDIMS]; + npy_intp last_stride; + int oi, oj, ok, ni, nj, nk; + + oldnd = 0; + /* + * Remove axes with dimension 1 from the old array. They have no effect + * but would need special cases since their strides do not matter. + */ + for (oi = 0; oi < PyArray_NDIM(self); oi++) { + if (PyArray_DIMS(self)[oi]!= 1) { + olddims[oldnd] = PyArray_DIMS(self)[oi]; + oldstrides[oldnd] = PyArray_STRIDES(self)[oi]; + oldnd++; + } + } + + /* oi to oj and ni to nj give the axis ranges currently worked with */ + oi = 0; + oj = 1; + ni = 0; + nj = 1; + while (ni < newnd && oi < oldnd) { + npy_intp np = newdims[ni]; + npy_intp op = olddims[oi]; + + while (np != op) { + if (np < op) { + /* Misses trailing 1s, these are handled later */ + np *= newdims[nj++]; + } else { + op *= olddims[oj++]; + } + } + + /* Check whether the original axes can be combined */ + for (ok = oi; ok < oj - 1; ok++) { + if (is_f_order) { + if (oldstrides[ok+1] != olddims[ok]*oldstrides[ok]) { + /* not contiguous enough */ + return 0; + } + } + else { + /* C order */ + if (oldstrides[ok] != olddims[ok+1]*oldstrides[ok+1]) { + /* not contiguous enough */ + return 0; + } + } + } + + /* Calculate new strides for all axes currently worked with */ + if (is_f_order) { + newstrides[ni] = oldstrides[oi]; + for (nk = ni + 1; nk < nj; nk++) { + newstrides[nk] = newstrides[nk - 1]*newdims[nk - 1]; + } + } + else { + /* C order */ + newstrides[nj - 1] = oldstrides[oj - 1]; + for (nk = nj - 1; nk > ni; nk--) { + newstrides[nk - 1] = newstrides[nk]*newdims[nk]; + } + } + ni = nj++; + oi = oj++; + } + + /* + * Set strides corresponding to trailing 1s of the new shape. + */ + if (ni >= 1) { + last_stride = newstrides[ni - 1]; + } + else { + last_stride = PyArray_ITEMSIZE(self); + } + if (is_f_order) { + last_stride *= newdims[ni - 1]; + } + for (nk = ni; nk < newnd; nk++) { + newstrides[nk] = last_stride; + } + + return 1; +} + +static void +raise_reshape_size_mismatch(PyArray_Dims *newshape, PyArrayObject *arr) +{ + PyObject *msg = PyUString_FromFormat("cannot reshape array of size %zd " + "into shape ", PyArray_SIZE(arr)); + PyObject *tmp = convert_shape_to_string(newshape->len, newshape->ptr, ""); + + PyUString_ConcatAndDel(&msg, tmp); + if (msg != NULL) { + PyErr_SetObject(PyExc_ValueError, msg); + Py_DECREF(msg); + } +} + +static int +_fix_unknown_dimension(PyArray_Dims *newshape, PyArrayObject *arr) +{ + npy_intp *dimensions; + npy_intp s_original = PyArray_SIZE(arr); + npy_intp i_unknown, s_known; + int i, n; + + dimensions = newshape->ptr; + n = newshape->len; + s_known = 1; + i_unknown = -1; + + for (i = 0; i < n; i++) { + if (dimensions[i] < 0) { + if (i_unknown == -1) { + i_unknown = i; + } + else { + PyErr_SetString(PyExc_ValueError, + "can only specify one unknown dimension"); + return -1; + } + } + else if (npy_mul_with_overflow_intp(&s_known, s_known, + dimensions[i])) { + raise_reshape_size_mismatch(newshape, arr); + return -1; + } + } + + if (i_unknown >= 0) { + if (s_known == 0 || s_original % s_known != 0) { + raise_reshape_size_mismatch(newshape, arr); + return -1; + } + dimensions[i_unknown] = s_original / s_known; + } + else { + if (s_original != s_known) { + raise_reshape_size_mismatch(newshape, arr); + return -1; + } + } + return 0; +} + +/*NUMPY_API + * + * return a new view of the array object with all of its unit-length + * dimensions squeezed out if needed, otherwise + * return the same array. + */ +NPY_NO_EXPORT PyObject * +PyArray_Squeeze(PyArrayObject *self) +{ + PyArrayObject *ret; + npy_bool unit_dims[NPY_MAXDIMS]; + int idim, ndim, any_ones; + npy_intp *shape; + + ndim = PyArray_NDIM(self); + shape = PyArray_SHAPE(self); + + any_ones = 0; + for (idim = 0; idim < ndim; ++idim) { + if (shape[idim] == 1) { + unit_dims[idim] = 1; + any_ones = 1; + } + else { + unit_dims[idim] = 0; + } + } + + /* If there were no ones to squeeze out, return the same array */ + if (!any_ones) { + Py_INCREF(self); + return (PyObject *)self; + } + + ret = (PyArrayObject *)PyArray_View(self, NULL, &PyArray_Type); + if (ret == NULL) { + return NULL; + } + + PyArray_RemoveAxesInPlace(ret, unit_dims); + + /* + * If self isn't not a base class ndarray, call its + * __array_wrap__ method + */ + if (Py_TYPE(self) != &PyArray_Type) { + PyArrayObject *tmp = PyArray_SubclassWrap(self, ret); + Py_DECREF(ret); + ret = tmp; + } + + return (PyObject *)ret; +} + +/* + * Just like PyArray_Squeeze, but allows the caller to select + * a subset of the size-one dimensions to squeeze out. + */ +NPY_NO_EXPORT PyObject * +PyArray_SqueezeSelected(PyArrayObject *self, npy_bool *axis_flags) +{ + PyArrayObject *ret; + int idim, ndim, any_ones; + npy_intp *shape; + + ndim = PyArray_NDIM(self); + shape = PyArray_SHAPE(self); + + /* Verify that the axes requested are all of size one */ + any_ones = 0; + for (idim = 0; idim < ndim; ++idim) { + if (axis_flags[idim] != 0) { + if (shape[idim] == 1) { + any_ones = 1; + } + else { + PyErr_SetString(PyExc_ValueError, + "cannot select an axis to squeeze out " + "which has size not equal to one"); + return NULL; + } + } + } + + /* If there were no axes to squeeze out, return the same array */ + if (!any_ones) { + Py_INCREF(self); + return (PyObject *)self; + } + + ret = (PyArrayObject *)PyArray_View(self, NULL, &PyArray_Type); + if (ret == NULL) { + return NULL; + } + + PyArray_RemoveAxesInPlace(ret, axis_flags); + + /* + * If self isn't not a base class ndarray, call its + * __array_wrap__ method + */ + if (Py_TYPE(self) != &PyArray_Type) { + PyArrayObject *tmp = PyArray_SubclassWrap(self, ret); + Py_DECREF(ret); + ret = tmp; + } + + return (PyObject *)ret; +} + +/*NUMPY_API + * SwapAxes + */ +NPY_NO_EXPORT PyObject * +PyArray_SwapAxes(PyArrayObject *ap, int a1, int a2) +{ + PyArray_Dims new_axes; + npy_intp dims[NPY_MAXDIMS]; + int n = PyArray_NDIM(ap); + int i; + + if (a1 < 0) { + a1 += n; + } + if (a2 < 0) { + a2 += n; + } + if ((a1 < 0) || (a1 >= n)) { + PyErr_SetString(PyExc_ValueError, + "bad axis1 argument to swapaxes"); + return NULL; + } + if ((a2 < 0) || (a2 >= n)) { + PyErr_SetString(PyExc_ValueError, + "bad axis2 argument to swapaxes"); + return NULL; + } + + for (i = 0; i < n; ++i) { + dims[i] = i; + } + dims[a1] = a2; + dims[a2] = a1; + + new_axes.ptr = dims; + new_axes.len = n; + + return PyArray_Transpose(ap, &new_axes); +} + + +/*NUMPY_API + * Return Transpose. + */ +NPY_NO_EXPORT PyObject * +PyArray_Transpose(PyArrayObject *ap, PyArray_Dims *permute) +{ + npy_intp *axes; + int i, n; + int permutation[NPY_MAXDIMS], reverse_permutation[NPY_MAXDIMS]; + PyArrayObject *ret = NULL; + int flags; + + if (permute == NULL) { + n = PyArray_NDIM(ap); + for (i = 0; i < n; i++) { + permutation[i] = n-1-i; + } + } + else { + n = permute->len; + axes = permute->ptr; + if (n != PyArray_NDIM(ap)) { + PyErr_SetString(PyExc_ValueError, + "axes don't match array"); + return NULL; + } + for (i = 0; i < n; i++) { + reverse_permutation[i] = -1; + } + for (i = 0; i < n; i++) { + int axis = axes[i]; + if (check_and_adjust_axis(&axis, PyArray_NDIM(ap)) < 0) { + return NULL; + } + if (reverse_permutation[axis] != -1) { + PyErr_SetString(PyExc_ValueError, + "repeated axis in transpose"); + return NULL; + } + reverse_permutation[axis] = i; + permutation[i] = axis; + } + } + + flags = PyArray_FLAGS(ap); + + /* + * this allocates memory for dimensions and strides (but fills them + * incorrectly), sets up descr, and points data at PyArray_DATA(ap). + */ + Py_INCREF(PyArray_DESCR(ap)); + ret = (PyArrayObject *) + PyArray_NewFromDescr(Py_TYPE(ap), + PyArray_DESCR(ap), + n, PyArray_DIMS(ap), + NULL, PyArray_DATA(ap), + flags, + (PyObject *)ap); + if (ret == NULL) { + return NULL; + } + /* point at true owner of memory: */ + Py_INCREF(ap); + if (PyArray_SetBaseObject(ret, (PyObject *)ap) < 0) { + Py_DECREF(ret); + return NULL; + } + + /* fix the dimensions and strides of the return-array */ + for (i = 0; i < n; i++) { + PyArray_DIMS(ret)[i] = PyArray_DIMS(ap)[permutation[i]]; + PyArray_STRIDES(ret)[i] = PyArray_STRIDES(ap)[permutation[i]]; + } + PyArray_UpdateFlags(ret, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS | + NPY_ARRAY_ALIGNED); + return (PyObject *)ret; +} + +/* + * Sorts items so stride is descending, because C-order + * is the default in the face of ambiguity. + */ +static int _npy_stride_sort_item_comparator(const void *a, const void *b) +{ + npy_intp astride = ((const npy_stride_sort_item *)a)->stride, + bstride = ((const npy_stride_sort_item *)b)->stride; + + /* Sort the absolute value of the strides */ + if (astride < 0) { + astride = -astride; + } + if (bstride < 0) { + bstride = -bstride; + } + + if (astride == bstride) { + /* + * Make the qsort stable by next comparing the perm order. + * (Note that two perm entries will never be equal) + */ + npy_intp aperm = ((const npy_stride_sort_item *)a)->perm, + bperm = ((const npy_stride_sort_item *)b)->perm; + return (aperm < bperm) ? -1 : 1; + } + if (astride > bstride) { + return -1; + } + return 1; +} + +/*NUMPY_API + * + * This function populates the first ndim elements + * of strideperm with sorted descending by their absolute values. + * For example, the stride array (4, -2, 12) becomes + * [(2, 12), (0, 4), (1, -2)]. + */ +NPY_NO_EXPORT void +PyArray_CreateSortedStridePerm(int ndim, npy_intp *strides, + npy_stride_sort_item *out_strideperm) +{ + int i; + + /* Set up the strideperm values */ + for (i = 0; i < ndim; ++i) { + out_strideperm[i].perm = i; + out_strideperm[i].stride = strides[i]; + } + + /* Sort them */ + qsort(out_strideperm, ndim, sizeof(npy_stride_sort_item), + &_npy_stride_sort_item_comparator); +} + +static NPY_INLINE npy_intp +s_intp_abs(npy_intp x) +{ + return (x < 0) ? -x : x; +} + + + +/* + * Creates a sorted stride perm matching the KEEPORDER behavior + * of the NpyIter object. Because this operates based on multiple + * input strides, the 'stride' member of the npy_stride_sort_item + * would be useless and we simply argsort a list of indices instead. + * + * The caller should have already validated that 'ndim' matches for + * every array in the arrays list. + */ +NPY_NO_EXPORT void +PyArray_CreateMultiSortedStridePerm(int narrays, PyArrayObject **arrays, + int ndim, int *out_strideperm) +{ + int i0, i1, ipos, ax_j0, ax_j1, iarrays; + + /* Initialize the strideperm values to the identity. */ + for (i0 = 0; i0 < ndim; ++i0) { + out_strideperm[i0] = i0; + } + + /* + * This is the same as the custom stable insertion sort in + * the NpyIter object, but sorting in the reverse order as + * in the iterator. The iterator sorts from smallest stride + * to biggest stride (Fortran order), whereas here we sort + * from biggest stride to smallest stride (C order). + */ + for (i0 = 1; i0 < ndim; ++i0) { + + ipos = i0; + ax_j0 = out_strideperm[i0]; + + for (i1 = i0 - 1; i1 >= 0; --i1) { + int ambig = 1, shouldswap = 0; + + ax_j1 = out_strideperm[i1]; + + for (iarrays = 0; iarrays < narrays; ++iarrays) { + if (PyArray_SHAPE(arrays[iarrays])[ax_j0] != 1 && + PyArray_SHAPE(arrays[iarrays])[ax_j1] != 1) { + if (s_intp_abs(PyArray_STRIDES(arrays[iarrays])[ax_j0]) <= + s_intp_abs(PyArray_STRIDES(arrays[iarrays])[ax_j1])) { + /* + * Set swap even if it's not ambiguous already, + * because in the case of conflicts between + * different operands, C-order wins. + */ + shouldswap = 0; + } + else { + /* Only set swap if it's still ambiguous */ + if (ambig) { + shouldswap = 1; + } + } + + /* + * A comparison has been done, so it's + * no longer ambiguous + */ + ambig = 0; + } + } + /* + * If the comparison was unambiguous, either shift + * 'ipos' to 'i1' or stop looking for an insertion point + */ + if (!ambig) { + if (shouldswap) { + ipos = i1; + } + else { + break; + } + } + } + + /* Insert out_strideperm[i0] into the right place */ + if (ipos != i0) { + for (i1 = i0; i1 > ipos; --i1) { + out_strideperm[i1] = out_strideperm[i1-1]; + } + out_strideperm[ipos] = ax_j0; + } + } +} + +/*NUMPY_API + * Ravel + * Returns a contiguous array + */ +NPY_NO_EXPORT PyObject * +PyArray_Ravel(PyArrayObject *arr, NPY_ORDER order) +{ + PyArray_Dims newdim = {NULL,1}; + npy_intp val[1] = {-1}; + + newdim.ptr = val; + + if (order == NPY_KEEPORDER) { + /* This handles some corner cases, such as 0-d arrays as well */ + if (PyArray_IS_C_CONTIGUOUS(arr)) { + order = NPY_CORDER; + } + else if (PyArray_IS_F_CONTIGUOUS(arr)) { + order = NPY_FORTRANORDER; + } + } + else if (order == NPY_ANYORDER) { + order = PyArray_ISFORTRAN(arr) ? NPY_FORTRANORDER : NPY_CORDER; + } + + if (order == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(arr)) { + return PyArray_Newshape(arr, &newdim, NPY_CORDER); + } + else if (order == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(arr)) { + return PyArray_Newshape(arr, &newdim, NPY_FORTRANORDER); + } + /* For KEEPORDER, check if we can make a flattened view */ + else if (order == NPY_KEEPORDER) { + npy_stride_sort_item strideperm[NPY_MAXDIMS]; + npy_intp stride; + int i, ndim = PyArray_NDIM(arr); + + PyArray_CreateSortedStridePerm(PyArray_NDIM(arr), + PyArray_STRIDES(arr), strideperm); + + /* The output array must be contiguous, so the first stride is fixed */ + stride = PyArray_ITEMSIZE(arr); + + for (i = ndim-1; i >= 0; --i) { + if (PyArray_DIM(arr, strideperm[i].perm) == 1) { + /* A size one dimension does not matter */ + continue; + } + if (strideperm[i].stride != stride) { + break; + } + stride *= PyArray_DIM(arr, strideperm[i].perm); + } + + /* If all the strides matched a contiguous layout, return a view */ + if (i < 0) { + PyArrayObject *ret; + + stride = PyArray_ITEMSIZE(arr); + val[0] = PyArray_SIZE(arr); + + Py_INCREF(PyArray_DESCR(arr)); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(arr), + PyArray_DESCR(arr), + 1, val, + &stride, + PyArray_BYTES(arr), + PyArray_FLAGS(arr), + (PyObject *)arr); + if (ret == NULL) { + return NULL; + } + + PyArray_UpdateFlags(ret, + NPY_ARRAY_C_CONTIGUOUS|NPY_ARRAY_F_CONTIGUOUS); + Py_INCREF(arr); + if (PyArray_SetBaseObject(ret, (PyObject *)arr) < 0) { + Py_DECREF(ret); + return NULL; + } + + return (PyObject *)ret; + } + } + + return PyArray_Flatten(arr, order); +} + +/*NUMPY_API + * Flatten + */ +NPY_NO_EXPORT PyObject * +PyArray_Flatten(PyArrayObject *a, NPY_ORDER order) +{ + PyArrayObject *ret; + npy_intp size; + + if (order == NPY_ANYORDER) { + order = PyArray_ISFORTRAN(a) ? NPY_FORTRANORDER : NPY_CORDER; + } + + size = PyArray_SIZE(a); + Py_INCREF(PyArray_DESCR(a)); + ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(a), + PyArray_DESCR(a), + 1, &size, + NULL, + NULL, + 0, (PyObject *)a); + if (ret == NULL) { + return NULL; + } + + if (PyArray_CopyAsFlat(ret, a, order) < 0) { + Py_DECREF(ret); + return NULL; + } + return (PyObject *)ret; +} + +/* See shape.h for parameters documentation */ +NPY_NO_EXPORT PyObject * +build_shape_string(npy_intp n, npy_intp *vals) +{ + npy_intp i; + PyObject *ret, *tmp; + + /* + * Negative dimension indicates "newaxis", which can + * be discarded for printing if it's a leading dimension. + * Find the first non-"newaxis" dimension. + */ + i = 0; + while (i < n && vals[i] < 0) { + ++i; + } + + if (i == n) { + return PyUString_FromFormat("()"); + } + else { + ret = PyUString_FromFormat("(%" NPY_INTP_FMT, vals[i++]); + if (ret == NULL) { + return NULL; + } + } + + for (; i < n; ++i) { + if (vals[i] < 0) { + tmp = PyUString_FromString(",newaxis"); + } + else { + tmp = PyUString_FromFormat(",%" NPY_INTP_FMT, vals[i]); + } + if (tmp == NULL) { + Py_DECREF(ret); + return NULL; + } + + PyUString_ConcatAndDel(&ret, tmp); + if (ret == NULL) { + return NULL; + } + } + + tmp = PyUString_FromFormat(")"); + PyUString_ConcatAndDel(&ret, tmp); + return ret; +} + +/*NUMPY_API + * + * Removes the axes flagged as True from the array, + * modifying it in place. If an axis flagged for removal + * has a shape entry bigger than one, this effectively selects + * index zero for that axis. + * + * WARNING: If an axis flagged for removal has a shape equal to zero, + * the array will point to invalid memory. The caller must + * validate this! + * If an axis flagged for removal has a shape larger then one, + * the aligned flag (and in the future the contiguous flags), + * may need explicit update. + * (check also NPY_RELAXED_STRIDES_CHECKING) + * + * For example, this can be used to remove the reduction axes + * from a reduction result once its computation is complete. + */ +NPY_NO_EXPORT void +PyArray_RemoveAxesInPlace(PyArrayObject *arr, npy_bool *flags) +{ + PyArrayObject_fields *fa = (PyArrayObject_fields *)arr; + npy_intp *shape = fa->dimensions, *strides = fa->strides; + int idim, ndim = fa->nd, idim_out = 0; + + /* Compress the dimensions and strides */ + for (idim = 0; idim < ndim; ++idim) { + if (!flags[idim]) { + shape[idim_out] = shape[idim]; + strides[idim_out] = strides[idim]; + ++idim_out; + } + } + + /* The final number of dimensions */ + fa->nd = idim_out; + + /* May not be necessary for NPY_RELAXED_STRIDES_CHECKING (see comment) */ + PyArray_UpdateFlags(arr, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS); +} diff --git a/numpy/core/src/multiarray/shape.h b/numpy/core/src/multiarray/shape.h new file mode 100644 index 0000000..0451a46 --- /dev/null +++ b/numpy/core/src/multiarray/shape.h @@ -0,0 +1,31 @@ +#ifndef _NPY_ARRAY_SHAPE_H_ +#define _NPY_ARRAY_SHAPE_H_ + +/* + * Builds a string representation of the shape given in 'vals'. + * A negative value in 'vals' gets interpreted as newaxis. + */ +NPY_NO_EXPORT PyObject * +build_shape_string(npy_intp n, npy_intp *vals); + +/* + * Creates a sorted stride perm matching the KEEPORDER behavior + * of the NpyIter object. Because this operates based on multiple + * input strides, the 'stride' member of the npy_stride_sort_item + * would be useless and we simply argsort a list of indices instead. + * + * The caller should have already validated that 'ndim' matches for + * every array in the arrays list. + */ +NPY_NO_EXPORT void +PyArray_CreateMultiSortedStridePerm(int narrays, PyArrayObject **arrays, + int ndim, int *out_strideperm); + +/* + * Just like PyArray_Squeeze, but allows the caller to select + * a subset of the size-one dimensions to squeeze out. + */ +NPY_NO_EXPORT PyObject * +PyArray_SqueezeSelected(PyArrayObject *self, npy_bool *axis_flags); + +#endif diff --git a/numpy/core/src/multiarray/strfuncs.c b/numpy/core/src/multiarray/strfuncs.c new file mode 100644 index 0000000..646d15c --- /dev/null +++ b/numpy/core/src/multiarray/strfuncs.c @@ -0,0 +1,259 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE + +#include +#include + +#include "npy_pycompat.h" + +#include "strfuncs.h" + +static PyObject *PyArray_StrFunction = NULL; +static PyObject *PyArray_ReprFunction = NULL; + +/*NUMPY_API + * Set the array print function to be a Python function. + */ +NPY_NO_EXPORT void +PyArray_SetStringFunction(PyObject *op, int repr) +{ + if (repr) { + /* Dispose of previous callback */ + Py_XDECREF(PyArray_ReprFunction); + /* Add a reference to new callback */ + Py_XINCREF(op); + /* Remember new callback */ + PyArray_ReprFunction = op; + } + else { + /* Dispose of previous callback */ + Py_XDECREF(PyArray_StrFunction); + /* Add a reference to new callback */ + Py_XINCREF(op); + /* Remember new callback */ + PyArray_StrFunction = op; + } +} + + +/* + * Extend string. On failure, returns NULL and leaves *strp alone. + * XXX we do this in multiple places; time for a string library? + */ +static char * +extend(char **strp, Py_ssize_t n, Py_ssize_t *maxp) +{ + char *str = *strp; + Py_ssize_t new_cap; + + if (n >= *maxp - 16) { + new_cap = *maxp * 2; + + if (new_cap <= *maxp) { /* overflow */ + return NULL; + } + str = PyArray_realloc(*strp, new_cap); + if (str != NULL) { + *strp = str; + *maxp = new_cap; + } + } + return str; +} + + +static int +dump_data(char **string, Py_ssize_t *n, Py_ssize_t *max_n, char *data, int nd, + npy_intp *dimensions, npy_intp *strides, PyArrayObject* self) +{ + PyObject *op = NULL, *sp = NULL; + char *ostring; + npy_intp i, N, ret = 0; + +#define CHECK_MEMORY do { \ + if (extend(string, *n, max_n) == NULL) { \ + ret = -1; \ + goto end; \ + } \ + } while (0) + + if (nd == 0) { + if ((op = PyArray_GETITEM(self, data)) == NULL) { + return -1; + } + sp = PyObject_Repr(op); + if (sp == NULL) { + ret = -1; + goto end; + } + ostring = PyString_AsString(sp); + N = PyString_Size(sp)*sizeof(char); + *n += N; + CHECK_MEMORY; + memmove(*string + (*n - N), ostring, N); + } + else { + CHECK_MEMORY; + (*string)[*n] = '['; + *n += 1; + for (i = 0; i < dimensions[0]; i++) { + if (dump_data(string, n, max_n, + data + (*strides)*i, + nd - 1, dimensions + 1, + strides + 1, self) < 0) { + return -1; + } + CHECK_MEMORY; + if (i < dimensions[0] - 1) { + (*string)[*n] = ','; + (*string)[*n+1] = ' '; + *n += 2; + } + } + CHECK_MEMORY; + (*string)[*n] = ']'; + *n += 1; + } + +#undef CHECK_MEMORY + +end: + Py_XDECREF(op); + Py_XDECREF(sp); + return ret; +} + + +static PyObject * +array_repr_builtin(PyArrayObject *self, int repr) +{ + PyObject *ret; + char *string; + /* max_n initial value is arbitrary, dump_data will extend it */ + Py_ssize_t n = 0, max_n = PyArray_NBYTES(self) * 4 + 7; + + if ((string = PyArray_malloc(max_n)) == NULL) { + return PyErr_NoMemory(); + } + + if (dump_data(&string, &n, &max_n, PyArray_DATA(self), + PyArray_NDIM(self), PyArray_DIMS(self), + PyArray_STRIDES(self), self) < 0) { + PyArray_free(string); + return NULL; + } + + if (repr) { + if (PyArray_ISEXTENDED(self)) { + ret = PyUString_FromFormat("array(%s, '%c%d')", + string, + PyArray_DESCR(self)->type, + PyArray_DESCR(self)->elsize); + } + else { + ret = PyUString_FromFormat("array(%s, '%c')", + string, + PyArray_DESCR(self)->type); + } + } + else { + ret = PyUString_FromStringAndSize(string, n); + } + + PyArray_free(string); + return ret; +} + + +NPY_NO_EXPORT PyObject * +array_repr(PyArrayObject *self) +{ + PyObject *s, *arglist; + + if (PyArray_ReprFunction == NULL) { + s = array_repr_builtin(self, 1); + } + else { + arglist = Py_BuildValue("(O)", self); + s = PyEval_CallObject(PyArray_ReprFunction, arglist); + Py_DECREF(arglist); + } + return s; +} + + +NPY_NO_EXPORT PyObject * +array_str(PyArrayObject *self) +{ + PyObject *s, *arglist; + + if (PyArray_StrFunction == NULL) { + s = array_repr_builtin(self, 0); + } + else { + arglist = Py_BuildValue("(O)", self); + s = PyEval_CallObject(PyArray_StrFunction, arglist); + Py_DECREF(arglist); + } + return s; +} + +NPY_NO_EXPORT PyObject * +array_format(PyArrayObject *self, PyObject *args) +{ + PyObject *format; + if (!PyArg_ParseTuple(args, "O:__format__", &format)) + return NULL; + + /* 0d arrays - forward to the scalar type */ + if (PyArray_NDIM(self) == 0) { + PyObject *item = PyArray_ToScalar(PyArray_DATA(self), self); + PyObject *res; + + if (item == NULL) { + return NULL; + } + res = PyObject_Format(item, format); + Py_DECREF(item); + return res; + } + /* Everything else - use the builtin */ + else { + return PyObject_CallMethod( + (PyObject *)&PyBaseObject_Type, "__format__", "OO", + (PyObject *)self, format + ); + } +} + +#ifndef NPY_PY3K + +NPY_NO_EXPORT PyObject * +array_unicode(PyArrayObject *self) +{ + PyObject *uni; + + if (PyArray_NDIM(self) == 0) { + PyObject *item = PyArray_ToScalar(PyArray_DATA(self), self); + if (item == NULL){ + return NULL; + } + + /* defer to invoking `unicode` on the scalar */ + uni = PyObject_CallFunctionObjArgs( + (PyObject *)&PyUnicode_Type, item, NULL); + Py_DECREF(item); + } + else { + /* Do what unicode(self) would normally do */ + PyObject *str = PyObject_Str((PyObject *)self); + if (str == NULL){ + return NULL; + } + uni = PyUnicode_FromObject(str); + Py_DECREF(str); + } + return uni; +} + +#endif diff --git a/numpy/core/src/multiarray/strfuncs.h b/numpy/core/src/multiarray/strfuncs.h new file mode 100644 index 0000000..7e869d9 --- /dev/null +++ b/numpy/core/src/multiarray/strfuncs.h @@ -0,0 +1,21 @@ +#ifndef _NPY_ARRAY_STRFUNCS_H_ +#define _NPY_ARRAY_STRFUNCS_H_ + +NPY_NO_EXPORT void +PyArray_SetStringFunction(PyObject *op, int repr); + +NPY_NO_EXPORT PyObject * +array_repr(PyArrayObject *self); + +NPY_NO_EXPORT PyObject * +array_str(PyArrayObject *self); + +NPY_NO_EXPORT PyObject * +array_format(PyArrayObject *self, PyObject *args); + +#ifndef NPY_PY3K + NPY_NO_EXPORT PyObject * + array_unicode(PyArrayObject *self); +#endif + +#endif diff --git a/numpy/core/src/multiarray/temp_elide.c b/numpy/core/src/multiarray/temp_elide.c new file mode 100644 index 0000000..e5175f1 --- /dev/null +++ b/numpy/core/src/multiarray/temp_elide.c @@ -0,0 +1,397 @@ +#define PY_SSIZE_T_CLEAN +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "npy_config.h" +#include "numpy/arrayobject.h" + +#define NPY_NUMBER_MAX(a, b) ((a) > (b) ? (a) : (b)) + +/* + * Functions used to try to avoid/elide temporaries in python expressions + * of type a + b + b by translating some operations into in-place operations. + * This example translates to this bytecode: + * + * 0 LOAD_FAST 0 (a) + * 3 LOAD_FAST 1 (b) + * 6 BINARY_ADD + * 7 LOAD_FAST 1 (b) + * 10 BINARY_ADD + * + * The two named variables get their reference count increased by the load + * instructions so they always have a reference count larger than 1. + * The temporary of the first BINARY_ADD on the other hand only has a count of + * 1. Only temporaries can have a count of 1 in python so we can use this to + * transform the second operation into an in-place operation and not affect the + * output of the program. + * CPython does the same thing to resize memory instead of copying when doing + * string concatenation. + * The gain can be very significant (4x-6x) when avoiding the temporary allows + * the operation to remain in the cpu caches and can still be 50% faster for + * array larger than cpu cache size. + * + * A complication is that a DSO (dynamic shared object) module (e.g. cython) + * could call the PyNumber functions directly on arrays with reference count of + * 1. + * This is handled by checking the call stack to verify that we have been + * called directly from the cpython interpreter. + * To achieve this we check that all functions in the callstack until the + * cpython frame evaluation function are located in cpython or numpy. + * This is an expensive operation so temporaries are only avoided for rather + * large arrays. + * + * A possible future improvement would be to change cpython to give us access + * to the top of the stack. Then we could just check that the objects involved + * are on the cpython stack instead of checking the function callstack. + * + * Elision can be applied to all operations that do have in-place variants and + * do not change types (addition, subtraction, multiplication, float division, + * logical and bitwise operations ...) + * For commutative operations (addition, multiplication, ...) if eliding into + * the lefthand side fails it can succeed on the righthand side by swapping the + * arguments. E.g. b * (a * 2) can be elided by changing it to (2 * a) * b. + * + * TODO only supports systems with backtrace(), Windows can probably be + * supported too by using the appropriate Windows APIs. + */ + +#if defined HAVE_BACKTRACE && defined HAVE_DLFCN_H && ! defined PYPY_VERSION +/* 1 prints elided operations, 2 prints stacktraces */ +#define NPY_ELIDE_DEBUG 0 +#define NPY_MAX_STACKSIZE 10 + +#if PY_VERSION_HEX >= 0x03060000 +/* TODO can pep523 be used to somehow? */ +#define PYFRAMEEVAL_FUNC "_PyEval_EvalFrameDefault" +#else +#define PYFRAMEEVAL_FUNC "PyEval_EvalFrameEx" +#endif +/* + * Heuristic size of the array in bytes at which backtrace overhead generation + * becomes less than speed gained by in-place operations. Depends on stack depth + * being checked. Measurements with 10 stacks show it getting worthwhile + * around 100KiB but to be conservative put it higher around where the L2 cache + * spills. + */ +#ifndef Py_DEBUG +#define NPY_MIN_ELIDE_BYTES (256 * 1024) +#else +/* + * in debug mode always elide but skip scalars as these can convert to 0d array + * during in-place operations + */ +#define NPY_MIN_ELIDE_BYTES (32) +#endif +#include +#include + +/* + * linear search pointer in table + * number of pointers is usually quite small but if a performance impact can be + * measured this could be converted to a binary search + */ +static int +find_addr(void * addresses[], npy_intp naddr, void * addr) +{ + npy_intp j; + for (j = 0; j < naddr; j++) { + if (addr == addresses[j]) { + return 1; + } + } + return 0; +} + +static int +check_callers(int * cannot) +{ + /* + * get base addresses of multiarray and python, check if + * backtrace is in these libraries only calling dladdr if a new max address + * is found. + * When after the initial multiarray stack everything is inside python we + * can elide as no C-API user could have messed up the reference counts. + * Only check until the python frame evaluation function is found + * approx 10us overhead for stack size of 10 + * + * TODO some calls go over scalarmath in umath but we cannot get the base + * address of it from multiarraymodule as it is not linked against it + */ + static int init = 0; + /* + * measured DSO object memory start and end, if an address is located + * inside these bounds it is part of that library so we don't need to call + * dladdr on it (assuming linear memory) + */ + static void * pos_python_start; + static void * pos_python_end; + static void * pos_ma_start; + static void * pos_ma_end; + + /* known address storage to save dladdr calls */ + static void * py_addr[64]; + static void * pyeval_addr[64]; + static npy_intp n_py_addr = 0; + static npy_intp n_pyeval = 0; + + void *buffer[NPY_MAX_STACKSIZE]; + int i, nptrs; + int ok = 0; + /* cannot determine callers */ + if (init == -1) { + *cannot = 1; + return 0; + } + + nptrs = backtrace(buffer, NPY_MAX_STACKSIZE); + if (nptrs == 0) { + /* complete failure, disable elision */ + init = -1; + *cannot = 1; + return 0; + } + + /* setup DSO base addresses, ends updated later */ + if (NPY_UNLIKELY(init == 0)) { + Dl_info info; + /* get python base address */ + if (dladdr(&PyNumber_Or, &info)) { + pos_python_start = info.dli_fbase; + pos_python_end = info.dli_fbase; + } + else { + init = -1; + return 0; + } + /* get multiarray base address */ + if (dladdr(&PyArray_SetNumericOps, &info)) { + pos_ma_start = info.dli_fbase; + pos_ma_end = info.dli_fbase; + } + else { + init = -1; + return 0; + } + init = 1; + } + + /* loop over callstack addresses to check if they leave numpy or cpython */ + for (i = 0; i < nptrs; i++) { + Dl_info info; + int in_python = 0; + int in_multiarray = 0; +#if NPY_ELIDE_DEBUG >= 2 + dladdr(buffer[i], &info); + printf("%s(%p) %s(%p)\n", info.dli_fname, info.dli_fbase, + info.dli_sname, info.dli_saddr); +#endif + + /* check stored DSO boundaries first */ + if (buffer[i] >= pos_python_start && buffer[i] <= pos_python_end) { + in_python = 1; + } + else if (buffer[i] >= pos_ma_start && buffer[i] <= pos_ma_end) { + in_multiarray = 1; + } + + /* update DSO boundaries via dladdr if necessary */ + if (!in_python && !in_multiarray) { + if (dladdr(buffer[i], &info) == 0) { + init = -1; + ok = 0; + break; + } + /* update DSO end */ + if (info.dli_fbase == pos_python_start) { + pos_python_end = NPY_NUMBER_MAX(buffer[i], pos_python_end); + in_python = 1; + } + else if (info.dli_fbase == pos_ma_start) { + pos_ma_end = NPY_NUMBER_MAX(buffer[i], pos_ma_end); + in_multiarray = 1; + } + } + + /* no longer in ok libraries and not reached PyEval -> no elide */ + if (!in_python && !in_multiarray) { + ok = 0; + break; + } + + /* in python check if the frame eval function was reached */ + if (in_python) { + /* if reached eval we are done */ + if (find_addr(pyeval_addr, n_pyeval, buffer[i])) { + ok = 1; + break; + } + /* + * check if its some other function, use pointer lookup table to + * save expensive dladdr calls + */ + if (find_addr(py_addr, n_py_addr, buffer[i])) { + continue; + } + + /* new python address, check for PyEvalFrame */ + if (dladdr(buffer[i], &info) == 0) { + init = -1; + ok = 0; + break; + } + if (info.dli_sname && + strcmp(info.dli_sname, PYFRAMEEVAL_FUNC) == 0) { + if (n_pyeval < sizeof(pyeval_addr) / sizeof(pyeval_addr[0])) { + /* store address to not have to dladdr it again */ + pyeval_addr[n_pyeval++] = buffer[i]; + } + ok = 1; + break; + } + else if (n_py_addr < sizeof(py_addr) / sizeof(py_addr[0])) { + /* store other py function to not have to dladdr it again */ + py_addr[n_py_addr++] = buffer[i]; + } + } + } + + /* all stacks after numpy are from python, we can elide */ + if (ok) { + *cannot = 0; + return 1; + } + else { +#if NPY_ELIDE_DEBUG != 0 + puts("cannot elide due to c-api usage"); +#endif + *cannot = 1; + return 0; + } +} + +/* + * check if in "alhs @op@ orhs" that alhs is a temporary (refcnt == 1) so we + * can do in-place operations instead of creating a new temporary + * "cannot" is set to true if it cannot be done even with swapped arguments + */ +static int +can_elide_temp(PyArrayObject * alhs, PyObject * orhs, int * cannot) +{ + /* + * to be a candidate the array needs to have reference count 1, be an exact + * array of a basic type, own its data and size larger than threshold + */ + if (Py_REFCNT(alhs) != 1 || !PyArray_CheckExact(alhs) || + !PyArray_ISNUMBER(alhs) || + !PyArray_CHKFLAGS(alhs, NPY_ARRAY_OWNDATA) || + !PyArray_ISWRITEABLE(alhs) || + PyArray_CHKFLAGS(alhs, NPY_ARRAY_UPDATEIFCOPY) || + PyArray_CHKFLAGS(alhs, NPY_ARRAY_WRITEBACKIFCOPY) || + PyArray_NBYTES(alhs) < NPY_MIN_ELIDE_BYTES) { + return 0; + } + if (PyArray_CheckExact(orhs) || + PyArray_CheckAnyScalar(orhs)) { + PyArrayObject * arhs; + + /* create array from right hand side */ + Py_INCREF(orhs); + arhs = (PyArrayObject *)PyArray_EnsureArray(orhs); + if (arhs == NULL) { + return 0; + } + + /* + * if rhs is not a scalar dimensions must match + * TODO: one could allow broadcasting on equal types + */ + if (!(PyArray_NDIM(arhs) == 0 || + (PyArray_NDIM(arhs) == PyArray_NDIM(alhs) && + PyArray_CompareLists(PyArray_DIMS(alhs), PyArray_DIMS(arhs), + PyArray_NDIM(arhs))))) { + Py_DECREF(arhs); + return 0; + } + + /* must be safe to cast (checks values for scalar in rhs) */ + if (PyArray_CanCastArrayTo(arhs, PyArray_DESCR(alhs), + NPY_SAFE_CASTING)) { + Py_DECREF(arhs); + return check_callers(cannot); + } + Py_DECREF(arhs); + } + + return 0; +} + +/* + * try eliding a binary op, if commutative is true also try swapped arguments + */ +NPY_NO_EXPORT int +try_binary_elide(PyArrayObject * m1, PyObject * m2, + PyObject * (inplace_op)(PyArrayObject * m1, PyObject * m2), + PyObject ** res, int commutative) +{ + /* set when no elision can be done independent of argument order */ + int cannot = 0; + if (can_elide_temp(m1, m2, &cannot)) { + *res = inplace_op(m1, m2); +#if NPY_ELIDE_DEBUG != 0 + puts("elided temporary in binary op"); +#endif + return 1; + } + else if (commutative && !cannot) { + if (can_elide_temp((PyArrayObject *)m2, (PyObject *)m1, &cannot)) { + *res = inplace_op((PyArrayObject *)m2, (PyObject *)m1); +#if NPY_ELIDE_DEBUG != 0 + puts("elided temporary in commutative binary op"); +#endif + return 1; + } + } + *res = NULL; + return 0; +} + +/* try elide unary temporary */ +NPY_NO_EXPORT int +can_elide_temp_unary(PyArrayObject * m1) +{ + int cannot; + if (Py_REFCNT(m1) != 1 || !PyArray_CheckExact(m1) || + !PyArray_ISNUMBER(m1) || + !PyArray_CHKFLAGS(m1, NPY_ARRAY_OWNDATA) || + !PyArray_ISWRITEABLE(m1) || + PyArray_CHKFLAGS(m1, NPY_ARRAY_UPDATEIFCOPY) || + PyArray_NBYTES(m1) < NPY_MIN_ELIDE_BYTES) { + return 0; + } + if (check_callers(&cannot)) { +#if NPY_ELIDE_DEBUG != 0 + puts("elided temporary in unary op"); +#endif + return 1; + } + else { + return 0; + } +} +#else /* unsupported interpreter or missing backtrace */ +NPY_NO_EXPORT int +can_elide_temp_unary(PyArrayObject * m1) +{ + return 0; +} + +NPY_NO_EXPORT int +try_binary_elide(PyArrayObject * m1, PyObject * m2, + PyObject * (inplace_op)(PyArrayObject * m1, PyObject * m2), + PyObject ** res, int commutative) +{ + *res = NULL; + return 0; +} +#endif diff --git a/numpy/core/src/multiarray/temp_elide.h b/numpy/core/src/multiarray/temp_elide.h new file mode 100644 index 0000000..d073adf --- /dev/null +++ b/numpy/core/src/multiarray/temp_elide.h @@ -0,0 +1,15 @@ +#ifndef _NPY_ARRAY_TEMP_AVOID_H_ +#define _NPY_ARRAY_TEMP_AVOID_H_ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include + +NPY_NO_EXPORT int +can_elide_temp_unary(PyArrayObject * m1); + +NPY_NO_EXPORT int +try_binary_elide(PyArrayObject * m1, PyObject * m2, + PyObject * (inplace_op)(PyArrayObject * m1, PyObject * m2), + PyObject ** res, int commutative); + +#endif diff --git a/numpy/core/src/multiarray/ucsnarrow.c b/numpy/core/src/multiarray/ucsnarrow.c new file mode 100644 index 0000000..8e293e9 --- /dev/null +++ b/numpy/core/src/multiarray/ucsnarrow.c @@ -0,0 +1,174 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#define PY_SSIZE_T_CLEAN +#include + +#include +#include + +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/npy_math.h" + +#include "npy_config.h" + +#include "npy_pycompat.h" +#include "ctors.h" + +/* + * Functions only needed on narrow builds of Python for converting back and + * forth between the NumPy Unicode data-type (always 4-bytes) and the + * Python Unicode scalar (2-bytes on a narrow build). + */ + +/* + * The ucs2 buffer must be large enough to hold 2*ucs4length characters + * due to the use of surrogate pairs. + * + * The return value is the number of ucs2 bytes used-up which + * is ucs4length + number of surrogate pairs found. + * + * Values above 0xffff are converted to surrogate pairs. + */ +NPY_NO_EXPORT int +PyUCS2Buffer_FromUCS4(Py_UNICODE *ucs2, npy_ucs4 *ucs4, int ucs4length) +{ + int i; + int numucs2 = 0; + npy_ucs4 chr; + for (i = 0; i < ucs4length; i++) { + chr = *ucs4++; + if (chr > 0xffff) { + numucs2++; + chr -= 0x10000L; + *ucs2++ = 0xD800 + (Py_UNICODE) (chr >> 10); + *ucs2++ = 0xDC00 + (Py_UNICODE) (chr & 0x03FF); + } + else { + *ucs2++ = (Py_UNICODE) chr; + } + numucs2++; + } + return numucs2; +} + + +/* + * This converts a UCS2 buffer of the given length to UCS4 buffer. + * It converts up to ucs4len characters of UCS2 + * + * It returns the number of characters converted which can + * be less than ucs2len if there are surrogate pairs in ucs2. + * + * The return value is the actual size of the used part of the ucs4 buffer. + */ +NPY_NO_EXPORT int +PyUCS2Buffer_AsUCS4(Py_UNICODE *ucs2, npy_ucs4 *ucs4, int ucs2len, int ucs4len) +{ + int i; + npy_ucs4 chr; + Py_UNICODE ch; + int numchars=0; + + for (i = 0; (i < ucs2len) && (numchars < ucs4len); i++) { + ch = *ucs2++; + if (ch >= 0xd800 && ch <= 0xdfff) { + /* surrogate pair */ + chr = ((npy_ucs4)(ch-0xd800)) << 10; + chr += *ucs2++ + 0x2400; /* -0xdc00 + 0x10000 */ + i++; + } + else { + chr = (npy_ucs4) ch; + } + *ucs4++ = chr; + numchars++; + } + return numchars; +} + +/* + * Returns a PyUnicodeObject initialized from a buffer containing + * UCS4 unicode. + * + * Parameters + * ---------- + * src: char * + * Pointer to buffer containing UCS4 unicode. + * size: Py_ssize_t + * Size of buffer in bytes. + * swap: int + * If true, the data will be swapped. + * align: int + * If true, the data will be aligned. + * + * Returns + * ------- + * new_reference: PyUnicodeObject + */ +NPY_NO_EXPORT PyUnicodeObject * +PyUnicode_FromUCS4(char *src, Py_ssize_t size, int swap, int align) +{ + Py_ssize_t ucs4len = size / sizeof(npy_ucs4); + npy_ucs4 *buf = (npy_ucs4 *)src; + int alloc = 0; + PyUnicodeObject *ret; + + /* swap and align if needed */ + if (swap || align) { + buf = (npy_ucs4 *)malloc(size); + if (buf == NULL) { + PyErr_NoMemory(); + goto fail; + } + alloc = 1; + memcpy(buf, src, size); + if (swap) { + byte_swap_vector(buf, ucs4len, sizeof(npy_ucs4)); + } + } + + /* trim trailing zeros */ + while (ucs4len > 0 && buf[ucs4len - 1] == 0) { + ucs4len--; + } + + /* produce PyUnicode object */ +#ifdef Py_UNICODE_WIDE + { + ret = (PyUnicodeObject *)PyUnicode_FromUnicode((Py_UNICODE*)buf, + (Py_ssize_t) ucs4len); + if (ret == NULL) { + goto fail; + } + } +#else + { + Py_ssize_t tmpsiz = 2 * sizeof(Py_UNICODE) * ucs4len; + Py_ssize_t ucs2len; + Py_UNICODE *tmp; + + if ((tmp = (Py_UNICODE *)malloc(tmpsiz)) == NULL) { + PyErr_NoMemory(); + goto fail; + } + ucs2len = PyUCS2Buffer_FromUCS4(tmp, buf, ucs4len); + ret = (PyUnicodeObject *)PyUnicode_FromUnicode(tmp, (Py_ssize_t) ucs2len); + free(tmp); + if (ret == NULL) { + goto fail; + } + } +#endif + + if (alloc) { + free(buf); + } + return ret; + +fail: + if (alloc) { + free(buf); + } + return NULL; +} diff --git a/numpy/core/src/multiarray/ucsnarrow.h b/numpy/core/src/multiarray/ucsnarrow.h new file mode 100644 index 0000000..fe31a5e --- /dev/null +++ b/numpy/core/src/multiarray/ucsnarrow.h @@ -0,0 +1,13 @@ +#ifndef _NPY_UCSNARROW_H_ +#define _NPY_UCSNARROW_H_ + +NPY_NO_EXPORT int +PyUCS2Buffer_FromUCS4(Py_UNICODE *ucs2, npy_ucs4 *ucs4, int ucs4length); + +NPY_NO_EXPORT int +PyUCS2Buffer_AsUCS4(Py_UNICODE *ucs2, npy_ucs4 *ucs4, int ucs2len, int ucs4len); + +NPY_NO_EXPORT PyUnicodeObject * +PyUnicode_FromUCS4(char *src, Py_ssize_t size, int swap, int align); + +#endif diff --git a/numpy/core/src/multiarray/usertypes.c b/numpy/core/src/multiarray/usertypes.c new file mode 100644 index 0000000..8e80900 --- /dev/null +++ b/numpy/core/src/multiarray/usertypes.c @@ -0,0 +1,275 @@ +/* + Provide multidimensional arrays as a basic object type in python. + + Based on Original Numeric implementation + Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu + + with contributions from many Numeric Python developers 1995-2004 + + Heavily modified in 2005 with inspiration from Numarray + + by + + Travis Oliphant, oliphant@ee.byu.edu + Brigham Young University + + +maintainer email: oliphant.travis@ieee.org + + Numarray design (which provided guidance) by + Space Science Telescope Institute + (J. Todd Miller, Perry Greenfield, Rick White) +*/ +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" + +/*#include */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_config.h" + +#include "common.h" + +#include "npy_pycompat.h" + +#include "usertypes.h" + +NPY_NO_EXPORT PyArray_Descr **userdescrs=NULL; + +static int * +_append_new(int *types, int insert) +{ + int n = 0; + int *newtypes; + + while (types[n] != NPY_NOTYPE) { + n++; + } + newtypes = (int *)realloc(types, (n + 2)*sizeof(int)); + newtypes[n] = insert; + newtypes[n + 1] = NPY_NOTYPE; + return newtypes; +} + +static npy_bool +_default_nonzero(void *ip, void *arr) +{ + int elsize = PyArray_ITEMSIZE(arr); + char *ptr = ip; + while (elsize--) { + if (*ptr++ != 0) { + return NPY_TRUE; + } + } + return NPY_FALSE; +} + +static void +_default_copyswapn(void *dst, npy_intp dstride, void *src, + npy_intp sstride, npy_intp n, int swap, void *arr) +{ + npy_intp i; + PyArray_CopySwapFunc *copyswap; + char *dstptr = dst; + char *srcptr = src; + + copyswap = PyArray_DESCR(arr)->f->copyswap; + + for (i = 0; i < n; i++) { + copyswap(dstptr, srcptr, swap, arr); + dstptr += dstride; + srcptr += sstride; + } +} + +/*NUMPY_API + Initialize arrfuncs to NULL +*/ +NPY_NO_EXPORT void +PyArray_InitArrFuncs(PyArray_ArrFuncs *f) +{ + int i; + + for(i = 0; i < NPY_NTYPES_ABI_COMPATIBLE; i++) { + f->cast[i] = NULL; + } + f->getitem = NULL; + f->setitem = NULL; + f->copyswapn = NULL; + f->copyswap = NULL; + f->compare = NULL; + f->argmax = NULL; + f->argmin = NULL; + f->dotfunc = NULL; + f->scanfunc = NULL; + f->fromstr = NULL; + f->nonzero = NULL; + f->fill = NULL; + f->fillwithscalar = NULL; + for(i = 0; i < NPY_NSORTS; i++) { + f->sort[i] = NULL; + f->argsort[i] = NULL; + } + f->castdict = NULL; + f->scalarkind = NULL; + f->cancastscalarkindto = NULL; + f->cancastto = NULL; +} + +/* + returns typenum to associate with this type >=NPY_USERDEF. + needs the userdecrs table and PyArray_NUMUSER variables + defined in arraytypes.inc +*/ +/*NUMPY_API + Register Data type + Does not change the reference count of descr +*/ +NPY_NO_EXPORT int +PyArray_RegisterDataType(PyArray_Descr *descr) +{ + PyArray_Descr *descr2; + int typenum; + int i; + PyArray_ArrFuncs *f; + + /* See if this type is already registered */ + for (i = 0; i < NPY_NUMUSERTYPES; i++) { + descr2 = userdescrs[i]; + if (descr2 == descr) { + return descr->type_num; + } + } + typenum = NPY_USERDEF + NPY_NUMUSERTYPES; + descr->type_num = typenum; + if (PyDataType_ISUNSIZED(descr)) { + PyErr_SetString(PyExc_ValueError, "cannot register a" \ + "flexible data-type"); + return -1; + } + f = descr->f; + if (f->nonzero == NULL) { + f->nonzero = _default_nonzero; + } + if (f->copyswapn == NULL) { + f->copyswapn = _default_copyswapn; + } + if (f->copyswap == NULL || f->getitem == NULL || + f->setitem == NULL) { + PyErr_SetString(PyExc_ValueError, "a required array function" \ + " is missing."); + return -1; + } + if (descr->typeobj == NULL) { + PyErr_SetString(PyExc_ValueError, "missing typeobject"); + return -1; + } + userdescrs = realloc(userdescrs, + (NPY_NUMUSERTYPES+1)*sizeof(void *)); + if (userdescrs == NULL) { + PyErr_SetString(PyExc_MemoryError, "RegisterDataType"); + return -1; + } + userdescrs[NPY_NUMUSERTYPES++] = descr; + return typenum; +} + +/*NUMPY_API + Register Casting Function + Replaces any function currently stored. +*/ +NPY_NO_EXPORT int +PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype, + PyArray_VectorUnaryFunc *castfunc) +{ + PyObject *cobj, *key; + int ret; + + if (totype < NPY_NTYPES_ABI_COMPATIBLE) { + descr->f->cast[totype] = castfunc; + return 0; + } + if (totype >= NPY_NTYPES && !PyTypeNum_ISUSERDEF(totype)) { + PyErr_SetString(PyExc_TypeError, "invalid type number."); + return -1; + } + if (descr->f->castdict == NULL) { + descr->f->castdict = PyDict_New(); + if (descr->f->castdict == NULL) { + return -1; + } + } + key = PyInt_FromLong(totype); + if (PyErr_Occurred()) { + return -1; + } + cobj = NpyCapsule_FromVoidPtr((void *)castfunc, NULL); + if (cobj == NULL) { + Py_DECREF(key); + return -1; + } + ret = PyDict_SetItem(descr->f->castdict, key, cobj); + Py_DECREF(key); + Py_DECREF(cobj); + return ret; +} + +/*NUMPY_API + * Register a type number indicating that a descriptor can be cast + * to it safely + */ +NPY_NO_EXPORT int +PyArray_RegisterCanCast(PyArray_Descr *descr, int totype, + NPY_SCALARKIND scalar) +{ + /* + * If we were to allow this, the casting lookup table for + * built-in types needs to be modified, as cancastto is + * not checked for them. + */ + if (!PyTypeNum_ISUSERDEF(descr->type_num) && + !PyTypeNum_ISUSERDEF(totype)) { + PyErr_SetString(PyExc_ValueError, + "At least one of the types provided to" + "RegisterCanCast must be user-defined."); + return -1; + } + + if (scalar == NPY_NOSCALAR) { + /* + * register with cancastto + * These lists won't be freed once created + * -- they become part of the data-type + */ + if (descr->f->cancastto == NULL) { + descr->f->cancastto = (int *)malloc(1*sizeof(int)); + descr->f->cancastto[0] = NPY_NOTYPE; + } + descr->f->cancastto = _append_new(descr->f->cancastto, + totype); + } + else { + /* register with cancastscalarkindto */ + if (descr->f->cancastscalarkindto == NULL) { + int i; + descr->f->cancastscalarkindto = + (int **)malloc(NPY_NSCALARKINDS* sizeof(int*)); + for (i = 0; i < NPY_NSCALARKINDS; i++) { + descr->f->cancastscalarkindto[i] = NULL; + } + } + if (descr->f->cancastscalarkindto[scalar] == NULL) { + descr->f->cancastscalarkindto[scalar] = + (int *)malloc(1*sizeof(int)); + descr->f->cancastscalarkindto[scalar][0] = + NPY_NOTYPE; + } + descr->f->cancastscalarkindto[scalar] = + _append_new(descr->f->cancastscalarkindto[scalar], totype); + } + return 0; +} diff --git a/numpy/core/src/multiarray/usertypes.h b/numpy/core/src/multiarray/usertypes.h new file mode 100644 index 0000000..b3e386c --- /dev/null +++ b/numpy/core/src/multiarray/usertypes.h @@ -0,0 +1,20 @@ +#ifndef _NPY_PRIVATE_USERTYPES_H_ +#define _NPY_PRIVATE_USERTYPES_H_ + +extern NPY_NO_EXPORT PyArray_Descr **userdescrs; + +NPY_NO_EXPORT void +PyArray_InitArrFuncs(PyArray_ArrFuncs *f); + +NPY_NO_EXPORT int +PyArray_RegisterCanCast(PyArray_Descr *descr, int totype, + NPY_SCALARKIND scalar); + +NPY_NO_EXPORT int +PyArray_RegisterDataType(PyArray_Descr *descr); + +NPY_NO_EXPORT int +PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype, + PyArray_VectorUnaryFunc *castfunc); + +#endif diff --git a/numpy/core/src/multiarray/vdot.c b/numpy/core/src/multiarray/vdot.c new file mode 100644 index 0000000..4be8567 --- /dev/null +++ b/numpy/core/src/multiarray/vdot.c @@ -0,0 +1,180 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include +#include "common.h" +#include "vdot.h" +#include "npy_cblas.h" + + +/* + * All data is assumed aligned. + */ +NPY_NO_EXPORT void +CFLOAT_vdot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, + char *op, npy_intp n, void *NPY_UNUSED(ignore)) +{ +#if defined(HAVE_CBLAS) + int is1b = blas_stride(is1, sizeof(npy_cfloat)); + int is2b = blas_stride(is2, sizeof(npy_cfloat)); + + if (is1b && is2b) { + double sum[2] = {0., 0.}; /* double for stability */ + + while (n > 0) { + int chunk = n < NPY_CBLAS_CHUNK ? n : NPY_CBLAS_CHUNK; + float tmp[2]; + + cblas_cdotc_sub((int)n, ip1, is1b, ip2, is2b, tmp); + sum[0] += (double)tmp[0]; + sum[1] += (double)tmp[1]; + /* use char strides here */ + ip1 += chunk * is1; + ip2 += chunk * is2; + n -= chunk; + } + ((float *)op)[0] = (float)sum[0]; + ((float *)op)[1] = (float)sum[1]; + } + else +#endif + { + float sumr = (float)0.0; + float sumi = (float)0.0; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + const float ip1r = ((float *)ip1)[0]; + const float ip1i = ((float *)ip1)[1]; + const float ip2r = ((float *)ip2)[0]; + const float ip2i = ((float *)ip2)[1]; + + sumr += ip1r * ip2r + ip1i * ip2i; + sumi += ip1r * ip2i - ip1i * ip2r; + } + ((float *)op)[0] = sumr; + ((float *)op)[1] = sumi; + } +} + + +/* + * All data is assumed aligned. + */ +NPY_NO_EXPORT void +CDOUBLE_vdot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, + char *op, npy_intp n, void *NPY_UNUSED(ignore)) +{ +#if defined(HAVE_CBLAS) + int is1b = blas_stride(is1, sizeof(npy_cdouble)); + int is2b = blas_stride(is2, sizeof(npy_cdouble)); + + if (is1b && is2b) { + double sum[2] = {0., 0.}; /* double for stability */ + + while (n > 0) { + int chunk = n < NPY_CBLAS_CHUNK ? n : NPY_CBLAS_CHUNK; + double tmp[2]; + + cblas_zdotc_sub((int)n, ip1, is1b, ip2, is2b, tmp); + sum[0] += (double)tmp[0]; + sum[1] += (double)tmp[1]; + /* use char strides here */ + ip1 += chunk * is1; + ip2 += chunk * is2; + n -= chunk; + } + ((double *)op)[0] = (double)sum[0]; + ((double *)op)[1] = (double)sum[1]; + } + else +#endif + { + double sumr = (double)0.0; + double sumi = (double)0.0; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + const double ip1r = ((double *)ip1)[0]; + const double ip1i = ((double *)ip1)[1]; + const double ip2r = ((double *)ip2)[0]; + const double ip2i = ((double *)ip2)[1]; + + sumr += ip1r * ip2r + ip1i * ip2i; + sumi += ip1r * ip2i - ip1i * ip2r; + } + ((double *)op)[0] = sumr; + ((double *)op)[1] = sumi; + } +} + + +/* + * All data is assumed aligned. + */ +NPY_NO_EXPORT void +CLONGDOUBLE_vdot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, + char *op, npy_intp n, void *NPY_UNUSED(ignore)) +{ + npy_longdouble tmpr = 0.0L; + npy_longdouble tmpi = 0.0L; + npy_intp i; + + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + const npy_longdouble ip1r = ((npy_longdouble *)ip1)[0]; + const npy_longdouble ip1i = ((npy_longdouble *)ip1)[1]; + const npy_longdouble ip2r = ((npy_longdouble *)ip2)[0]; + const npy_longdouble ip2i = ((npy_longdouble *)ip2)[1]; + + tmpr += ip1r * ip2r + ip1i * ip2i; + tmpi += ip1r * ip2i - ip1i * ip2r; + } + ((npy_longdouble *)op)[0] = tmpr; + ((npy_longdouble *)op)[1] = tmpi; +} + +/* + * All data is assumed aligned. + */ +NPY_NO_EXPORT void +OBJECT_vdot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, npy_intp n, + void *NPY_UNUSED(ignore)) +{ + npy_intp i; + PyObject *tmp0, *tmp1, *tmp2, *tmp = NULL; + PyObject **tmp3; + for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) { + if ((*((PyObject **)ip1) == NULL) || (*((PyObject **)ip2) == NULL)) { + tmp1 = Py_False; + Py_INCREF(Py_False); + } + else { + tmp0 = PyObject_CallMethod(*((PyObject **)ip1), "conjugate", NULL); + if (tmp0 == NULL) { + Py_XDECREF(tmp); + return; + } + tmp1 = PyNumber_Multiply(tmp0, *((PyObject **)ip2)); + Py_DECREF(tmp0); + if (tmp1 == NULL) { + Py_XDECREF(tmp); + return; + } + } + if (i == 0) { + tmp = tmp1; + } + else { + tmp2 = PyNumber_Add(tmp, tmp1); + Py_XDECREF(tmp); + Py_XDECREF(tmp1); + if (tmp2 == NULL) { + return; + } + tmp = tmp2; + } + } + tmp3 = (PyObject**) op; + tmp2 = *tmp3; + *((PyObject **)op) = tmp; + Py_XDECREF(tmp2); +} diff --git a/numpy/core/src/multiarray/vdot.h b/numpy/core/src/multiarray/vdot.h new file mode 100644 index 0000000..0f60ca6 --- /dev/null +++ b/numpy/core/src/multiarray/vdot.h @@ -0,0 +1,18 @@ +#ifndef _NPY_VDOT_H_ +#define _NPY_VDOT_H_ + +#include "common.h" + +NPY_NO_EXPORT void +CFLOAT_vdot(char *, npy_intp, char *, npy_intp, char *, npy_intp, void *); + +NPY_NO_EXPORT void +CDOUBLE_vdot(char *, npy_intp, char *, npy_intp, char *, npy_intp, void *); + +NPY_NO_EXPORT void +CLONGDOUBLE_vdot(char *, npy_intp, char *, npy_intp, char *, npy_intp, void *); + +NPY_NO_EXPORT void +OBJECT_vdot(char *, npy_intp, char *, npy_intp, char *, npy_intp, void *); + +#endif diff --git a/numpy/core/src/npymath/_signbit.c b/numpy/core/src/npymath/_signbit.c new file mode 100644 index 0000000..12af553 --- /dev/null +++ b/numpy/core/src/npymath/_signbit.c @@ -0,0 +1,32 @@ +/* Adapted from cephes */ + +int +_npy_signbit_d(double x) +{ + union + { + double d; + short s[4]; + int i[2]; + } u; + + u.d = x; + +#if NPY_SIZEOF_INT == 4 + +#ifdef WORDS_BIGENDIAN /* defined in pyconfig.h */ + return u.i[0] < 0; +#else + return u.i[1] < 0; +#endif + +#else /* NPY_SIZEOF_INT != 4 */ + +#ifdef WORDS_BIGENDIAN + return u.s[0] < 0; +#else + return u.s[3] < 0; +#endif + +#endif /* NPY_SIZEOF_INT */ +} diff --git a/numpy/core/src/npymath/halffloat.c b/numpy/core/src/npymath/halffloat.c new file mode 100644 index 0000000..9517682 --- /dev/null +++ b/numpy/core/src/npymath/halffloat.c @@ -0,0 +1,540 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#include "numpy/halffloat.h" + +/* + * This chooses between 'ties to even' and 'ties away from zero'. + */ +#define NPY_HALF_ROUND_TIES_TO_EVEN 1 +/* + * If these are 1, the conversions try to trigger underflow, + * overflow, and invalid exceptions in the FP system when needed. + */ +#define NPY_HALF_GENERATE_OVERFLOW 1 +#define NPY_HALF_GENERATE_UNDERFLOW 1 +#define NPY_HALF_GENERATE_INVALID 1 + +/* + ******************************************************************** + * HALF-PRECISION ROUTINES * + ******************************************************************** + */ + +float npy_half_to_float(npy_half h) +{ + union { float ret; npy_uint32 retbits; } conv; + conv.retbits = npy_halfbits_to_floatbits(h); + return conv.ret; +} + +double npy_half_to_double(npy_half h) +{ + union { double ret; npy_uint64 retbits; } conv; + conv.retbits = npy_halfbits_to_doublebits(h); + return conv.ret; +} + +npy_half npy_float_to_half(float f) +{ + union { float f; npy_uint32 fbits; } conv; + conv.f = f; + return npy_floatbits_to_halfbits(conv.fbits); +} + +npy_half npy_double_to_half(double d) +{ + union { double d; npy_uint64 dbits; } conv; + conv.d = d; + return npy_doublebits_to_halfbits(conv.dbits); +} + +int npy_half_iszero(npy_half h) +{ + return (h&0x7fff) == 0; +} + +int npy_half_isnan(npy_half h) +{ + return ((h&0x7c00u) == 0x7c00u) && ((h&0x03ffu) != 0x0000u); +} + +int npy_half_isinf(npy_half h) +{ + return ((h&0x7fffu) == 0x7c00u); +} + +int npy_half_isfinite(npy_half h) +{ + return ((h&0x7c00u) != 0x7c00u); +} + +int npy_half_signbit(npy_half h) +{ + return (h&0x8000u) != 0; +} + +npy_half npy_half_spacing(npy_half h) +{ + npy_half ret; + npy_uint16 h_exp = h&0x7c00u; + npy_uint16 h_sig = h&0x03ffu; + if (h_exp == 0x7c00u) { +#if NPY_HALF_GENERATE_INVALID + npy_set_floatstatus_invalid(); +#endif + ret = NPY_HALF_NAN; + } else if (h == 0x7bffu) { +#if NPY_HALF_GENERATE_OVERFLOW + npy_set_floatstatus_overflow(); +#endif + ret = NPY_HALF_PINF; + } else if ((h&0x8000u) && h_sig == 0) { /* Negative boundary case */ + if (h_exp > 0x2c00u) { /* If result is normalized */ + ret = h_exp - 0x2c00u; + } else if(h_exp > 0x0400u) { /* The result is a subnormal, but not the smallest */ + ret = 1 << ((h_exp >> 10) - 2); + } else { + ret = 0x0001u; /* Smallest subnormal half */ + } + } else if (h_exp > 0x2800u) { /* If result is still normalized */ + ret = h_exp - 0x2800u; + } else if (h_exp > 0x0400u) { /* The result is a subnormal, but not the smallest */ + ret = 1 << ((h_exp >> 10) - 1); + } else { + ret = 0x0001u; + } + + return ret; +} + +npy_half npy_half_copysign(npy_half x, npy_half y) +{ + return (x&0x7fffu) | (y&0x8000u); +} + +npy_half npy_half_nextafter(npy_half x, npy_half y) +{ + npy_half ret; + + if (!npy_half_isfinite(x) || npy_half_isnan(y)) { +#if NPY_HALF_GENERATE_INVALID + npy_set_floatstatus_invalid(); +#endif + ret = NPY_HALF_NAN; + } else if (npy_half_eq_nonan(x, y)) { + ret = x; + } else if (npy_half_iszero(x)) { + ret = (y&0x8000u) + 1; /* Smallest subnormal half */ + } else if (!(x&0x8000u)) { /* x > 0 */ + if ((npy_int16)x > (npy_int16)y) { /* x > y */ + ret = x-1; + } else { + ret = x+1; + } + } else { + if (!(y&0x8000u) || (x&0x7fffu) > (y&0x7fffu)) { /* x < y */ + ret = x-1; + } else { + ret = x+1; + } + } +#if NPY_HALF_GENERATE_OVERFLOW + if (npy_half_isinf(ret)) { + npy_set_floatstatus_overflow(); + } +#endif + + return ret; +} + +int npy_half_eq_nonan(npy_half h1, npy_half h2) +{ + return (h1 == h2 || ((h1 | h2) & 0x7fff) == 0); +} + +int npy_half_eq(npy_half h1, npy_half h2) +{ + /* + * The equality cases are as follows: + * - If either value is NaN, never equal. + * - If the values are equal, equal. + * - If the values are both signed zeros, equal. + */ + return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) && + (h1 == h2 || ((h1 | h2) & 0x7fff) == 0); +} + +int npy_half_ne(npy_half h1, npy_half h2) +{ + return !npy_half_eq(h1, h2); +} + +int npy_half_lt_nonan(npy_half h1, npy_half h2) +{ + if (h1&0x8000u) { + if (h2&0x8000u) { + return (h1&0x7fffu) > (h2&0x7fffu); + } else { + /* Signed zeros are equal, have to check for it */ + return (h1 != 0x8000u) || (h2 != 0x0000u); + } + } else { + if (h2&0x8000u) { + return 0; + } else { + return (h1&0x7fffu) < (h2&0x7fffu); + } + } +} + +int npy_half_lt(npy_half h1, npy_half h2) +{ + return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) && npy_half_lt_nonan(h1, h2); +} + +int npy_half_gt(npy_half h1, npy_half h2) +{ + return npy_half_lt(h2, h1); +} + +int npy_half_le_nonan(npy_half h1, npy_half h2) +{ + if (h1&0x8000u) { + if (h2&0x8000u) { + return (h1&0x7fffu) >= (h2&0x7fffu); + } else { + return 1; + } + } else { + if (h2&0x8000u) { + /* Signed zeros are equal, have to check for it */ + return (h1 == 0x0000u) && (h2 == 0x8000u); + } else { + return (h1&0x7fffu) <= (h2&0x7fffu); + } + } +} + +int npy_half_le(npy_half h1, npy_half h2) +{ + return (!npy_half_isnan(h1) && !npy_half_isnan(h2)) && npy_half_le_nonan(h1, h2); +} + +int npy_half_ge(npy_half h1, npy_half h2) +{ + return npy_half_le(h2, h1); +} + +npy_half npy_half_divmod(npy_half h1, npy_half h2, npy_half *modulus) +{ + float fh1 = npy_half_to_float(h1); + float fh2 = npy_half_to_float(h2); + float div, mod; + + div = npy_divmodf(fh1, fh2, &mod); + *modulus = npy_float_to_half(mod); + return npy_float_to_half(div); +} + + + +/* + ******************************************************************** + * BIT-LEVEL CONVERSIONS * + ******************************************************************** + */ + +npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f) +{ + npy_uint32 f_exp, f_sig; + npy_uint16 h_sgn, h_exp, h_sig; + + h_sgn = (npy_uint16) ((f&0x80000000u) >> 16); + f_exp = (f&0x7f800000u); + + /* Exponent overflow/NaN converts to signed inf/NaN */ + if (f_exp >= 0x47800000u) { + if (f_exp == 0x7f800000u) { + /* Inf or NaN */ + f_sig = (f&0x007fffffu); + if (f_sig != 0) { + /* NaN - propagate the flag in the significand... */ + npy_uint16 ret = (npy_uint16) (0x7c00u + (f_sig >> 13)); + /* ...but make sure it stays a NaN */ + if (ret == 0x7c00u) { + ret++; + } + return h_sgn + ret; + } else { + /* signed inf */ + return (npy_uint16) (h_sgn + 0x7c00u); + } + } else { + /* overflow to signed inf */ +#if NPY_HALF_GENERATE_OVERFLOW + npy_set_floatstatus_overflow(); +#endif + return (npy_uint16) (h_sgn + 0x7c00u); + } + } + + /* Exponent underflow converts to a subnormal half or signed zero */ + if (f_exp <= 0x38000000u) { + /* + * Signed zeros, subnormal floats, and floats with small + * exponents all convert to signed zero halfs. + */ + if (f_exp < 0x33000000u) { +#if NPY_HALF_GENERATE_UNDERFLOW + /* If f != 0, it underflowed to 0 */ + if ((f&0x7fffffff) != 0) { + npy_set_floatstatus_underflow(); + } +#endif + return h_sgn; + } + /* Make the subnormal significand */ + f_exp >>= 23; + f_sig = (0x00800000u + (f&0x007fffffu)); +#if NPY_HALF_GENERATE_UNDERFLOW + /* If it's not exactly represented, it underflowed */ + if ((f_sig&(((npy_uint32)1 << (126 - f_exp)) - 1)) != 0) { + npy_set_floatstatus_underflow(); + } +#endif + f_sig >>= (113 - f_exp); + /* Handle rounding by adding 1 to the bit beyond half precision */ +#if NPY_HALF_ROUND_TIES_TO_EVEN + /* + * If the last bit in the half significand is 0 (already even), and + * the remaining bit pattern is 1000...0, then we do not add one + * to the bit after the half significand. In all other cases, we do. + */ + if ((f_sig&0x00003fffu) != 0x00001000u) { + f_sig += 0x00001000u; + } +#else + f_sig += 0x00001000u; +#endif + h_sig = (npy_uint16) (f_sig >> 13); + /* + * If the rounding causes a bit to spill into h_exp, it will + * increment h_exp from zero to one and h_sig will be zero. + * This is the correct result. + */ + return (npy_uint16) (h_sgn + h_sig); + } + + /* Regular case with no overflow or underflow */ + h_exp = (npy_uint16) ((f_exp - 0x38000000u) >> 13); + /* Handle rounding by adding 1 to the bit beyond half precision */ + f_sig = (f&0x007fffffu); +#if NPY_HALF_ROUND_TIES_TO_EVEN + /* + * If the last bit in the half significand is 0 (already even), and + * the remaining bit pattern is 1000...0, then we do not add one + * to the bit after the half significand. In all other cases, we do. + */ + if ((f_sig&0x00003fffu) != 0x00001000u) { + f_sig += 0x00001000u; + } +#else + f_sig += 0x00001000u; +#endif + h_sig = (npy_uint16) (f_sig >> 13); + /* + * If the rounding causes a bit to spill into h_exp, it will + * increment h_exp by one and h_sig will be zero. This is the + * correct result. h_exp may increment to 15, at greatest, in + * which case the result overflows to a signed inf. + */ +#if NPY_HALF_GENERATE_OVERFLOW + h_sig += h_exp; + if (h_sig == 0x7c00u) { + npy_set_floatstatus_overflow(); + } + return h_sgn + h_sig; +#else + return h_sgn + h_exp + h_sig; +#endif +} + +npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d) +{ + npy_uint64 d_exp, d_sig; + npy_uint16 h_sgn, h_exp, h_sig; + + h_sgn = (d&0x8000000000000000ULL) >> 48; + d_exp = (d&0x7ff0000000000000ULL); + + /* Exponent overflow/NaN converts to signed inf/NaN */ + if (d_exp >= 0x40f0000000000000ULL) { + if (d_exp == 0x7ff0000000000000ULL) { + /* Inf or NaN */ + d_sig = (d&0x000fffffffffffffULL); + if (d_sig != 0) { + /* NaN - propagate the flag in the significand... */ + npy_uint16 ret = (npy_uint16) (0x7c00u + (d_sig >> 42)); + /* ...but make sure it stays a NaN */ + if (ret == 0x7c00u) { + ret++; + } + return h_sgn + ret; + } else { + /* signed inf */ + return h_sgn + 0x7c00u; + } + } else { + /* overflow to signed inf */ +#if NPY_HALF_GENERATE_OVERFLOW + npy_set_floatstatus_overflow(); +#endif + return h_sgn + 0x7c00u; + } + } + + /* Exponent underflow converts to subnormal half or signed zero */ + if (d_exp <= 0x3f00000000000000ULL) { + /* + * Signed zeros, subnormal floats, and floats with small + * exponents all convert to signed zero halfs. + */ + if (d_exp < 0x3e60000000000000ULL) { +#if NPY_HALF_GENERATE_UNDERFLOW + /* If d != 0, it underflowed to 0 */ + if ((d&0x7fffffffffffffffULL) != 0) { + npy_set_floatstatus_underflow(); + } +#endif + return h_sgn; + } + /* Make the subnormal significand */ + d_exp >>= 52; + d_sig = (0x0010000000000000ULL + (d&0x000fffffffffffffULL)); +#if NPY_HALF_GENERATE_UNDERFLOW + /* If it's not exactly represented, it underflowed */ + if ((d_sig&(((npy_uint64)1 << (1051 - d_exp)) - 1)) != 0) { + npy_set_floatstatus_underflow(); + } +#endif + d_sig >>= (1009 - d_exp); + /* Handle rounding by adding 1 to the bit beyond half precision */ +#if NPY_HALF_ROUND_TIES_TO_EVEN + /* + * If the last bit in the half significand is 0 (already even), and + * the remaining bit pattern is 1000...0, then we do not add one + * to the bit after the half significand. In all other cases, we do. + */ + if ((d_sig&0x000007ffffffffffULL) != 0x0000020000000000ULL) { + d_sig += 0x0000020000000000ULL; + } +#else + d_sig += 0x0000020000000000ULL; +#endif + h_sig = (npy_uint16) (d_sig >> 42); + /* + * If the rounding causes a bit to spill into h_exp, it will + * increment h_exp from zero to one and h_sig will be zero. + * This is the correct result. + */ + return h_sgn + h_sig; + } + + /* Regular case with no overflow or underflow */ + h_exp = (npy_uint16) ((d_exp - 0x3f00000000000000ULL) >> 42); + /* Handle rounding by adding 1 to the bit beyond half precision */ + d_sig = (d&0x000fffffffffffffULL); +#if NPY_HALF_ROUND_TIES_TO_EVEN + /* + * If the last bit in the half significand is 0 (already even), and + * the remaining bit pattern is 1000...0, then we do not add one + * to the bit after the half significand. In all other cases, we do. + */ + if ((d_sig&0x000007ffffffffffULL) != 0x0000020000000000ULL) { + d_sig += 0x0000020000000000ULL; + } +#else + d_sig += 0x0000020000000000ULL; +#endif + h_sig = (npy_uint16) (d_sig >> 42); + + /* + * If the rounding causes a bit to spill into h_exp, it will + * increment h_exp by one and h_sig will be zero. This is the + * correct result. h_exp may increment to 15, at greatest, in + * which case the result overflows to a signed inf. + */ +#if NPY_HALF_GENERATE_OVERFLOW + h_sig += h_exp; + if (h_sig == 0x7c00u) { + npy_set_floatstatus_overflow(); + } + return h_sgn + h_sig; +#else + return h_sgn + h_exp + h_sig; +#endif +} + +npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h) +{ + npy_uint16 h_exp, h_sig; + npy_uint32 f_sgn, f_exp, f_sig; + + h_exp = (h&0x7c00u); + f_sgn = ((npy_uint32)h&0x8000u) << 16; + switch (h_exp) { + case 0x0000u: /* 0 or subnormal */ + h_sig = (h&0x03ffu); + /* Signed zero */ + if (h_sig == 0) { + return f_sgn; + } + /* Subnormal */ + h_sig <<= 1; + while ((h_sig&0x0400u) == 0) { + h_sig <<= 1; + h_exp++; + } + f_exp = ((npy_uint32)(127 - 15 - h_exp)) << 23; + f_sig = ((npy_uint32)(h_sig&0x03ffu)) << 13; + return f_sgn + f_exp + f_sig; + case 0x7c00u: /* inf or NaN */ + /* All-ones exponent and a copy of the significand */ + return f_sgn + 0x7f800000u + (((npy_uint32)(h&0x03ffu)) << 13); + default: /* normalized */ + /* Just need to adjust the exponent and shift */ + return f_sgn + (((npy_uint32)(h&0x7fffu) + 0x1c000u) << 13); + } +} + +npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h) +{ + npy_uint16 h_exp, h_sig; + npy_uint64 d_sgn, d_exp, d_sig; + + h_exp = (h&0x7c00u); + d_sgn = ((npy_uint64)h&0x8000u) << 48; + switch (h_exp) { + case 0x0000u: /* 0 or subnormal */ + h_sig = (h&0x03ffu); + /* Signed zero */ + if (h_sig == 0) { + return d_sgn; + } + /* Subnormal */ + h_sig <<= 1; + while ((h_sig&0x0400u) == 0) { + h_sig <<= 1; + h_exp++; + } + d_exp = ((npy_uint64)(1023 - 15 - h_exp)) << 52; + d_sig = ((npy_uint64)(h_sig&0x03ffu)) << 42; + return d_sgn + d_exp + d_sig; + case 0x7c00u: /* inf or NaN */ + /* All-ones exponent and a copy of the significand */ + return d_sgn + 0x7ff0000000000000ULL + + (((npy_uint64)(h&0x03ffu)) << 42); + default: /* normalized */ + /* Just need to adjust the exponent and shift */ + return d_sgn + (((npy_uint64)(h&0x7fffu) + 0xfc000u) << 42); + } +} diff --git a/numpy/core/src/npymath/ieee754.c.src b/numpy/core/src/npymath/ieee754.c.src new file mode 100644 index 0000000..0370ea6 --- /dev/null +++ b/numpy/core/src/npymath/ieee754.c.src @@ -0,0 +1,808 @@ +/* -*- c -*- */ +/* + * vim:syntax=c + * + * Low-level routines related to IEEE-754 format + */ +#include "npy_math_common.h" +#include "npy_math_private.h" + +#ifndef HAVE_COPYSIGN +double npy_copysign(double x, double y) +{ + npy_uint32 hx, hy; + GET_HIGH_WORD(hx, x); + GET_HIGH_WORD(hy, y); + SET_HIGH_WORD(x, (hx & 0x7fffffff) | (hy & 0x80000000)); + return x; +} +#endif + +/* + The below code is provided for compilers which do not yet provide C11 compatibility (gcc 4.5 and older) + */ +#ifndef LDBL_TRUE_MIN +#define LDBL_TRUE_MIN __LDBL_DENORM_MIN__ +#endif + +#if !defined(HAVE_DECL_SIGNBIT) +#include "_signbit.c" + +int _npy_signbit_f(float x) +{ + return _npy_signbit_d((double) x); +} + +int _npy_signbit_ld(long double x) +{ + return _npy_signbit_d((double) x); +} +#endif + +/* + * FIXME: There is a lot of redundancy between _next* and npy_nextafter*. + * refactor this at some point + * + * p >= 0, returnx x + nulp + * p < 0, returnx x - nulp + */ +static double _next(double x, int p) +{ + volatile double t; + npy_int32 hx, hy, ix; + npy_uint32 lx; + + EXTRACT_WORDS(hx, lx, x); + ix = hx & 0x7fffffff; /* |x| */ + + if (((ix >= 0x7ff00000) && ((ix - 0x7ff00000) | lx) != 0)) /* x is nan */ + return x; + if ((ix | lx) == 0) { /* x == 0 */ + if (p >= 0) { + INSERT_WORDS(x, 0x0, 1); /* return +minsubnormal */ + } else { + INSERT_WORDS(x, 0x80000000, 1); /* return -minsubnormal */ + } + t = x * x; + if (t == x) + return t; + else + return x; /* raise underflow flag */ + } + if (p < 0) { /* x -= ulp */ + if (lx == 0) + hx -= 1; + lx -= 1; + } else { /* x += ulp */ + lx += 1; + if (lx == 0) + hx += 1; + } + hy = hx & 0x7ff00000; + if (hy >= 0x7ff00000) + return x + x; /* overflow */ + if (hy < 0x00100000) { /* underflow */ + t = x * x; + if (t != x) { /* raise underflow flag */ + INSERT_WORDS(x, hx, lx); + return x; + } + } + INSERT_WORDS(x, hx, lx); + return x; +} + +static float _nextf(float x, int p) +{ + volatile float t; + npy_int32 hx, hy, ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; /* |x| */ + + if ((ix > 0x7f800000)) /* x is nan */ + return x; + if (ix == 0) { /* x == 0 */ + if (p >= 0) { + SET_FLOAT_WORD(x, 0x0 | 1); /* return +minsubnormal */ + } else { + SET_FLOAT_WORD(x, 0x80000000 | 1); /* return -minsubnormal */ + } + t = x * x; + if (t == x) + return t; + else + return x; /* raise underflow flag */ + } + if (p < 0) { /* x -= ulp */ + hx -= 1; + } else { /* x += ulp */ + hx += 1; + } + hy = hx & 0x7f800000; + if (hy >= 0x7f800000) + return x + x; /* overflow */ + if (hy < 0x00800000) { /* underflow */ + t = x * x; + if (t != x) { /* raise underflow flag */ + SET_FLOAT_WORD(x, hx); + return x; + } + } + SET_FLOAT_WORD(x, hx); + return x; +} + +#if defined(HAVE_LDOUBLE_DOUBLE_DOUBLE_BE) || \ + defined(HAVE_LDOUBLE_DOUBLE_DOUBLE_LE) + +/* + * FIXME: this is ugly and untested. The asm part only works with gcc, and we + * should consolidate the GET_LDOUBLE* / SET_LDOUBLE macros + */ +#define math_opt_barrier(x) \ + ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; }) +#define math_force_eval(x) __asm __volatile ("" : : "m" (x)) + +/* only works for big endian */ +typedef union +{ + npy_longdouble value; + struct + { + npy_uint64 msw; + npy_uint64 lsw; + } parts64; + struct + { + npy_uint32 w0, w1, w2, w3; + } parts32; +} ieee854_long_double_shape_type; + +/* Get two 64 bit ints from a long double. */ + +#define GET_LDOUBLE_WORDS64(ix0,ix1,d) \ +do { \ + ieee854_long_double_shape_type qw_u; \ + qw_u.value = (d); \ + (ix0) = qw_u.parts64.msw; \ + (ix1) = qw_u.parts64.lsw; \ +} while (0) + +/* Set a long double from two 64 bit ints. */ + +#define SET_LDOUBLE_WORDS64(d,ix0,ix1) \ +do { \ + ieee854_long_double_shape_type qw_u; \ + qw_u.parts64.msw = (ix0); \ + qw_u.parts64.lsw = (ix1); \ + (d) = qw_u.value; \ +} while (0) + +static npy_longdouble _nextl(npy_longdouble x, int p) +{ + npy_int64 hx,ihx,ilx; + npy_uint64 lx; + + GET_LDOUBLE_WORDS64(hx, lx, x); + ihx = hx & 0x7fffffffffffffffLL; /* |hx| */ + ilx = lx & 0x7fffffffffffffffLL; /* |lx| */ + + if(((ihx & 0x7ff0000000000000LL)==0x7ff0000000000000LL)&& + ((ihx & 0x000fffffffffffffLL)!=0)) { + return x; /* signal the nan */ + } + if(ihx == 0 && ilx == 0) { /* x == 0 */ + npy_longdouble u; + SET_LDOUBLE_WORDS64(x, p, 0ULL);/* return +-minsubnormal */ + u = x * x; + if (u == x) { + return u; + } else { + return x; /* raise underflow flag */ + } + } + + npy_longdouble u; + if(p < 0) { /* p < 0, x -= ulp */ + if((hx==0xffefffffffffffffLL)&&(lx==0xfc8ffffffffffffeLL)) + return x+x; /* overflow, return -inf */ + if (hx >= 0x7ff0000000000000LL) { + SET_LDOUBLE_WORDS64(u,0x7fefffffffffffffLL,0x7c8ffffffffffffeLL); + return u; + } + if(ihx <= 0x0360000000000000LL) { /* x <= LDBL_MIN */ + u = math_opt_barrier (x); + x -= LDBL_TRUE_MIN; + if (ihx < 0x0360000000000000LL + || (hx > 0 && (npy_int64) lx <= 0) + || (hx < 0 && (npy_int64) lx > 1)) { + u = u * u; + math_force_eval (u); /* raise underflow flag */ + } + return x; + } + if (ihx < 0x06a0000000000000LL) { /* ulp will denormal */ + SET_LDOUBLE_WORDS64(u,(hx&0x7ff0000000000000LL),0ULL); + u *= 0x1.0000000000000p-105L; + } else + SET_LDOUBLE_WORDS64(u,(hx&0x7ff0000000000000LL)-0x0690000000000000LL,0ULL); + return x - u; + } else { /* p >= 0, x += ulp */ + if((hx==0x7fefffffffffffffLL)&&(lx==0x7c8ffffffffffffeLL)) + return x+x; /* overflow, return +inf */ + if ((npy_uint64) hx >= 0xfff0000000000000ULL) { + SET_LDOUBLE_WORDS64(u,0xffefffffffffffffLL,0xfc8ffffffffffffeLL); + return u; + } + if(ihx <= 0x0360000000000000LL) { /* x <= LDBL_MIN */ + u = math_opt_barrier (x); + x += LDBL_TRUE_MIN; + if (ihx < 0x0360000000000000LL + || (hx > 0 && (npy_int64) lx < 0 && lx != 0x8000000000000001LL) + || (hx < 0 && (npy_int64) lx >= 0)) { + u = u * u; + math_force_eval (u); /* raise underflow flag */ + } + if (x == 0.0L) /* handle negative LDBL_TRUE_MIN case */ + x = -0.0L; + return x; + } + if (ihx < 0x06a0000000000000LL) { /* ulp will denormal */ + SET_LDOUBLE_WORDS64(u,(hx&0x7ff0000000000000LL),0ULL); + u *= 0x1.0000000000000p-105L; + } else + SET_LDOUBLE_WORDS64(u,(hx&0x7ff0000000000000LL)-0x0690000000000000LL,0ULL); + return x + u; + } +} +#else +static npy_longdouble _nextl(npy_longdouble x, int p) +{ + volatile npy_longdouble t; + union IEEEl2bitsrep ux; + + ux.e = x; + + if ((GET_LDOUBLE_EXP(ux) == 0x7fff && + ((GET_LDOUBLE_MANH(ux) & ~LDBL_NBIT) | GET_LDOUBLE_MANL(ux)) != 0)) { + return ux.e; /* x is nan */ + } + if (ux.e == 0.0) { + SET_LDOUBLE_MANH(ux, 0); /* return +-minsubnormal */ + SET_LDOUBLE_MANL(ux, 1); + if (p >= 0) { + SET_LDOUBLE_SIGN(ux, 0); + } else { + SET_LDOUBLE_SIGN(ux, 1); + } + t = ux.e * ux.e; + if (t == ux.e) { + return t; + } else { + return ux.e; /* raise underflow flag */ + } + } + if (p < 0) { /* x -= ulp */ + if (GET_LDOUBLE_MANL(ux) == 0) { + if ((GET_LDOUBLE_MANH(ux) & ~LDBL_NBIT) == 0) { + SET_LDOUBLE_EXP(ux, GET_LDOUBLE_EXP(ux) - 1); + } + SET_LDOUBLE_MANH(ux, + (GET_LDOUBLE_MANH(ux) - 1) | + (GET_LDOUBLE_MANH(ux) & LDBL_NBIT)); + } + SET_LDOUBLE_MANL(ux, GET_LDOUBLE_MANL(ux) - 1); + } else { /* x += ulp */ + SET_LDOUBLE_MANL(ux, GET_LDOUBLE_MANL(ux) + 1); + if (GET_LDOUBLE_MANL(ux) == 0) { + SET_LDOUBLE_MANH(ux, + (GET_LDOUBLE_MANH(ux) + 1) | + (GET_LDOUBLE_MANH(ux) & LDBL_NBIT)); + if ((GET_LDOUBLE_MANH(ux) & ~LDBL_NBIT) == 0) { + SET_LDOUBLE_EXP(ux, GET_LDOUBLE_EXP(ux) + 1); + } + } + } + if (GET_LDOUBLE_EXP(ux) == 0x7fff) { + return ux.e + ux.e; /* overflow */ + } + if (GET_LDOUBLE_EXP(ux) == 0) { /* underflow */ + if (LDBL_NBIT) { + SET_LDOUBLE_MANH(ux, GET_LDOUBLE_MANH(ux) & ~LDBL_NBIT); + } + t = ux.e * ux.e; + if (t != ux.e) { /* raise underflow flag */ + return ux.e; + } + } + + return ux.e; +} +#endif + +/* + * nextafter code taken from BSD math lib, the code contains the following + * notice: + * + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef HAVE_NEXTAFTER +double npy_nextafter(double x, double y) +{ + volatile double t; + npy_int32 hx, hy, ix, iy; + npy_uint32 lx, ly; + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; /* |x| */ + iy = hy & 0x7fffffff; /* |y| */ + + if (((ix >= 0x7ff00000) && ((ix - 0x7ff00000) | lx) != 0) || /* x is nan */ + ((iy >= 0x7ff00000) && ((iy - 0x7ff00000) | ly) != 0)) /* y is nan */ + return x + y; + if (x == y) + return y; /* x=y, return y */ + if ((ix | lx) == 0) { /* x == 0 */ + INSERT_WORDS(x, hy & 0x80000000, 1); /* return +-minsubnormal */ + t = x * x; + if (t == x) + return t; + else + return x; /* raise underflow flag */ + } + if (hx >= 0) { /* x > 0 */ + if (hx > hy || ((hx == hy) && (lx > ly))) { /* x > y, x -= ulp */ + if (lx == 0) + hx -= 1; + lx -= 1; + } else { /* x < y, x += ulp */ + lx += 1; + if (lx == 0) + hx += 1; + } + } else { /* x < 0 */ + if (hy >= 0 || hx > hy || ((hx == hy) && (lx > ly))) { /* x < y, x -= ulp */ + if (lx == 0) + hx -= 1; + lx -= 1; + } else { /* x > y, x += ulp */ + lx += 1; + if (lx == 0) + hx += 1; + } + } + hy = hx & 0x7ff00000; + if (hy >= 0x7ff00000) + return x + x; /* overflow */ + if (hy < 0x00100000) { /* underflow */ + t = x * x; + if (t != x) { /* raise underflow flag */ + INSERT_WORDS(y, hx, lx); + return y; + } + } + INSERT_WORDS(x, hx, lx); + return x; +} +#endif + +#ifndef HAVE_NEXTAFTERF +float npy_nextafterf(float x, float y) +{ + volatile float t; + npy_int32 hx, hy, ix, iy; + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; /* |x| */ + iy = hy & 0x7fffffff; /* |y| */ + + if ((ix > 0x7f800000) || /* x is nan */ + (iy > 0x7f800000)) /* y is nan */ + return x + y; + if (x == y) + return y; /* x=y, return y */ + if (ix == 0) { /* x == 0 */ + SET_FLOAT_WORD(x, (hy & 0x80000000) | 1); /* return +-minsubnormal */ + t = x * x; + if (t == x) + return t; + else + return x; /* raise underflow flag */ + } + if (hx >= 0) { /* x > 0 */ + if (hx > hy) { /* x > y, x -= ulp */ + hx -= 1; + } else { /* x < y, x += ulp */ + hx += 1; + } + } else { /* x < 0 */ + if (hy >= 0 || hx > hy) { /* x < y, x -= ulp */ + hx -= 1; + } else { /* x > y, x += ulp */ + hx += 1; + } + } + hy = hx & 0x7f800000; + if (hy >= 0x7f800000) + return x + x; /* overflow */ + if (hy < 0x00800000) { /* underflow */ + t = x * x; + if (t != x) { /* raise underflow flag */ + SET_FLOAT_WORD(y, hx); + return y; + } + } + SET_FLOAT_WORD(x, hx); + return x; +} +#endif + +#ifndef HAVE_NEXTAFTERL +npy_longdouble npy_nextafterl(npy_longdouble x, npy_longdouble y) +{ + volatile npy_longdouble t; + union IEEEl2bitsrep ux; + union IEEEl2bitsrep uy; + + ux.e = x; + uy.e = y; + + if ((GET_LDOUBLE_EXP(ux) == 0x7fff && + ((GET_LDOUBLE_MANH(ux) & ~LDBL_NBIT) | GET_LDOUBLE_MANL(ux)) != 0) || + (GET_LDOUBLE_EXP(uy) == 0x7fff && + ((GET_LDOUBLE_MANH(uy) & ~LDBL_NBIT) | GET_LDOUBLE_MANL(uy)) != 0)) { + return ux.e + uy.e; /* x or y is nan */ + } + if (ux.e == uy.e) { + return uy.e; /* x=y, return y */ + } + if (ux.e == 0.0) { + SET_LDOUBLE_MANH(ux, 0); /* return +-minsubnormal */ + SET_LDOUBLE_MANL(ux, 1); + SET_LDOUBLE_SIGN(ux, GET_LDOUBLE_SIGN(uy)); + t = ux.e * ux.e; + if (t == ux.e) { + return t; + } else { + return ux.e; /* raise underflow flag */ + } + } + if ((ux.e > 0.0) ^ (ux.e < uy.e)) { /* x -= ulp */ + if (GET_LDOUBLE_MANL(ux) == 0) { + if ((GET_LDOUBLE_MANH(ux) & ~LDBL_NBIT) == 0) { + SET_LDOUBLE_EXP(ux, GET_LDOUBLE_EXP(ux) - 1); + } + SET_LDOUBLE_MANH(ux, + (GET_LDOUBLE_MANH(ux) - 1) | + (GET_LDOUBLE_MANH(ux) & LDBL_NBIT)); + } + SET_LDOUBLE_MANL(ux, GET_LDOUBLE_MANL(ux) - 1); + } else { /* x += ulp */ + SET_LDOUBLE_MANL(ux, GET_LDOUBLE_MANL(ux) + 1); + if (GET_LDOUBLE_MANL(ux) == 0) { + SET_LDOUBLE_MANH(ux, + (GET_LDOUBLE_MANH(ux) + 1) | + (GET_LDOUBLE_MANH(ux) & LDBL_NBIT)); + if ((GET_LDOUBLE_MANH(ux) & ~LDBL_NBIT) == 0) { + SET_LDOUBLE_EXP(ux, GET_LDOUBLE_EXP(ux) + 1); + } + } + } + if (GET_LDOUBLE_EXP(ux) == 0x7fff) { + return ux.e + ux.e; /* overflow */ + } + if (GET_LDOUBLE_EXP(ux) == 0) { /* underflow */ + if (LDBL_NBIT) { + SET_LDOUBLE_MANH(ux, GET_LDOUBLE_MANH(ux) & ~LDBL_NBIT); + } + t = ux.e * ux.e; + if (t != ux.e) { /* raise underflow flag */ + return ux.e; + } + } + + return ux.e; +} +#endif + +/**begin repeat + * #suff = f,,l# + * #SUFF = F,,L# + * #type = npy_float, npy_double, npy_longdouble# + */ +@type@ npy_spacing@suff@(@type@ x) +{ + /* XXX: npy isnan/isinf may be optimized by bit twiddling */ + if (npy_isinf(x)) { + return NPY_NAN@SUFF@; + } + + return _next@suff@(x, 1) - x; +} +/**end repeat**/ + +/* + * Decorate all the math functions which are available on the current platform + */ + +#ifdef HAVE_NEXTAFTERF +float npy_nextafterf(float x, float y) +{ + return nextafterf(x, y); +} +#endif + +#ifdef HAVE_NEXTAFTER +double npy_nextafter(double x, double y) +{ + return nextafter(x, y); +} +#endif + +#ifdef HAVE_NEXTAFTERL +npy_longdouble npy_nextafterl(npy_longdouble x, npy_longdouble y) +{ + return nextafterl(x, y); +} +#endif + +/* + * Functions to set the floating point status word. + * keep in sync with NO_FLOATING_POINT_SUPPORT in ufuncobject.h + */ + +#if (defined(__unix__) || defined(unix)) && !defined(USG) +#include +#endif + +/* Solaris --------------------------------------------------------*/ +/* --------ignoring SunOS ieee_flags approach, someone else can +** deal with that! */ +#if defined(sun) || defined(__BSD__) || defined(__OpenBSD__) || \ + (defined(__FreeBSD__) && (__FreeBSD_version < 502114)) || \ + defined(__NetBSD__) +#include + +int npy_get_floatstatus(void) +{ + int fpstatus = fpgetsticky(); + return ((FP_X_DZ & fpstatus) ? NPY_FPE_DIVIDEBYZERO : 0) | + ((FP_X_OFL & fpstatus) ? NPY_FPE_OVERFLOW : 0) | + ((FP_X_UFL & fpstatus) ? NPY_FPE_UNDERFLOW : 0) | + ((FP_X_INV & fpstatus) ? NPY_FPE_INVALID : 0); +} + +int npy_clear_floatstatus(void) +{ + int fpstatus = npy_get_floatstatus(); + fpsetsticky(0); + + return fpstatus; +} + +void npy_set_floatstatus_divbyzero(void) +{ + fpsetsticky(FP_X_DZ); +} + +void npy_set_floatstatus_overflow(void) +{ + fpsetsticky(FP_X_OFL); +} + +void npy_set_floatstatus_underflow(void) +{ + fpsetsticky(FP_X_UFL); +} + +void npy_set_floatstatus_invalid(void) +{ + fpsetsticky(FP_X_INV); +} + + +#elif defined(__GLIBC__) || defined(__APPLE__) || \ + defined(__CYGWIN__) || defined(__MINGW32__) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 502114)) +# include + +int npy_get_floatstatus(void) +{ + int fpstatus = fetestexcept(FE_DIVBYZERO | FE_OVERFLOW | + FE_UNDERFLOW | FE_INVALID); + + return ((FE_DIVBYZERO & fpstatus) ? NPY_FPE_DIVIDEBYZERO : 0) | + ((FE_OVERFLOW & fpstatus) ? NPY_FPE_OVERFLOW : 0) | + ((FE_UNDERFLOW & fpstatus) ? NPY_FPE_UNDERFLOW : 0) | + ((FE_INVALID & fpstatus) ? NPY_FPE_INVALID : 0); +} + +int npy_clear_floatstatus(void) +{ + /* testing float status is 50-100 times faster than clearing on x86 */ + int fpstatus = npy_get_floatstatus(); + if (fpstatus != 0) { + feclearexcept(FE_DIVBYZERO | FE_OVERFLOW | + FE_UNDERFLOW | FE_INVALID); + } + + return fpstatus; +} + + +void npy_set_floatstatus_divbyzero(void) +{ + feraiseexcept(FE_DIVBYZERO); +} + +void npy_set_floatstatus_overflow(void) +{ + feraiseexcept(FE_OVERFLOW); +} + +void npy_set_floatstatus_underflow(void) +{ + feraiseexcept(FE_UNDERFLOW); +} + +void npy_set_floatstatus_invalid(void) +{ + feraiseexcept(FE_INVALID); +} + +#elif defined(_AIX) +#include +#include + +int npy_get_floatstatus(void) +{ + int fpstatus = fp_read_flag(); + return ((FP_DIV_BY_ZERO & fpstatus) ? NPY_FPE_DIVIDEBYZERO : 0) | + ((FP_OVERFLOW & fpstatus) ? NPY_FPE_OVERFLOW : 0) | + ((FP_UNDERFLOW & fpstatus) ? NPY_FPE_UNDERFLOW : 0) | + ((FP_INVALID & fpstatus) ? NPY_FPE_INVALID : 0); +} + +int npy_clear_floatstatus(void) +{ + int fpstatus = npy_get_floatstatus(); + fp_swap_flag(0); + + return fpstatus; +} + +void npy_set_floatstatus_divbyzero(void) +{ + fp_raise_xcp(FP_DIV_BY_ZERO); +} + +void npy_set_floatstatus_overflow(void) +{ + fp_raise_xcp(FP_OVERFLOW); +} + +void npy_set_floatstatus_underflow(void) +{ + fp_raise_xcp(FP_UNDERFLOW); +} + +void npy_set_floatstatus_invalid(void) +{ + fp_raise_xcp(FP_INVALID); +} + +#else + +/* MS Windows -----------------------------------------------------*/ +#if defined(_MSC_VER) + +#include + + +int npy_get_floatstatus(void) +{ +#if defined(_WIN64) + int fpstatus = _statusfp(); +#else + /* windows enables sse on 32 bit, so check both flags */ + int fpstatus, fpstatus2; + _statusfp2(&fpstatus, &fpstatus2); + fpstatus |= fpstatus2; +#endif + return ((SW_ZERODIVIDE & fpstatus) ? NPY_FPE_DIVIDEBYZERO : 0) | + ((SW_OVERFLOW & fpstatus) ? NPY_FPE_OVERFLOW : 0) | + ((SW_UNDERFLOW & fpstatus) ? NPY_FPE_UNDERFLOW : 0) | + ((SW_INVALID & fpstatus) ? NPY_FPE_INVALID : 0); +} + +int npy_clear_floatstatus(void) +{ + int fpstatus = npy_get_floatstatus(); + _clearfp(); + + return fpstatus; +} + +/* OSF/Alpha (Tru64) ---------------------------------------------*/ +#elif defined(__osf__) && defined(__alpha) + +#include + +int npy_get_floatstatus(void) +{ + unsigned long fpstatus = ieee_get_fp_control(); + return ((IEEE_STATUS_DZE & fpstatus) ? NPY_FPE_DIVIDEBYZERO : 0) | + ((IEEE_STATUS_OVF & fpstatus) ? NPY_FPE_OVERFLOW : 0) | + ((IEEE_STATUS_UNF & fpstatus) ? NPY_FPE_UNDERFLOW : 0) | + ((IEEE_STATUS_INV & fpstatus) ? NPY_FPE_INVALID : 0); +} + +int npy_clear_floatstatus(void) +{ + long fpstatus = npy_get_floatstatus(); + /* clear status bits as well as disable exception mode if on */ + ieee_set_fp_control(0); + + return fpstatus; +} + +#else + +int npy_get_floatstatus(void) +{ + return 0; +} + +int npy_clear_floatstatus(void) +{ + return 0; +} + +#endif + +/* + * By using a volatile floating point value, + * the compiler is forced to actually do the requested + * operations because of potential concurrency. + * + * We shouldn't write multiple values to a single + * global here, because that would cause + * a race condition. + */ +static volatile double _npy_floatstatus_x, + _npy_floatstatus_zero = 0.0, _npy_floatstatus_big = 1e300, + _npy_floatstatus_small = 1e-300, _npy_floatstatus_inf; + +void npy_set_floatstatus_divbyzero(void) +{ + _npy_floatstatus_x = 1.0 / _npy_floatstatus_zero; +} + +void npy_set_floatstatus_overflow(void) +{ + _npy_floatstatus_x = _npy_floatstatus_big * 1e300; +} + +void npy_set_floatstatus_underflow(void) +{ + _npy_floatstatus_x = _npy_floatstatus_small * 1e-300; +} + +void npy_set_floatstatus_invalid(void) +{ + _npy_floatstatus_inf = NPY_INFINITY; + _npy_floatstatus_x = _npy_floatstatus_inf - NPY_INFINITY; +} + +#endif diff --git a/numpy/core/src/npymath/npy_math.c b/numpy/core/src/npymath/npy_math.c new file mode 100644 index 0000000..404cf67 --- /dev/null +++ b/numpy/core/src/npymath/npy_math.c @@ -0,0 +1,9 @@ +/* + * vim:syntax=c + * This file is compiled into the npy_math library with externally visible + * symbols, and the static and inline specifiers utilized in the npy_math + * function definitions are switched off. + */ + +#define NPY_INLINE_MATH 0 +#include "npy_math_internal.h" diff --git a/numpy/core/src/npymath/npy_math_common.h b/numpy/core/src/npymath/npy_math_common.h new file mode 100644 index 0000000..1f555a9 --- /dev/null +++ b/numpy/core/src/npymath/npy_math_common.h @@ -0,0 +1,9 @@ +/* + * Common headers needed by every npy math compilation unit + */ +#include +#include +#include + +#include "npy_config.h" +#include "numpy/npy_math.h" diff --git a/numpy/core/src/npymath/npy_math_complex.c.src b/numpy/core/src/npymath/npy_math_complex.c.src new file mode 100644 index 0000000..fb31e8e --- /dev/null +++ b/numpy/core/src/npymath/npy_math_complex.c.src @@ -0,0 +1,1801 @@ +/* + * vim: syntax=c + * + * Implement some C99-compatible complex math functions + * + * Most of the code is taken from the msun library in FreeBSD (HEAD @ 4th + * October 2013), under the following license: + * + * Copyright (c) 2007, 2011 David Schultz + * Copyright (c) 2012 Stephen Montgomery-Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "npy_math_common.h" +#include "npy_math_private.h" +#include + + +#define raise_inexact() do { volatile npy_float junk = 1 + tiny; } while(0) + + +static __COMP_NPY_UNUSED npy_float tiny = 3.9443045e-31f; + + +/**begin repeat + * #type = npy_float, npy_double, npy_longdouble# + * #ctype = npy_cfloat,npy_cdouble,npy_clongdouble# + * #c = f, , l# + * #C = F, , L# + * #TMAX = FLT_MAX, DBL_MAX, LDBL_MAX# + * #TMIN = FLT_MIN, DBL_MIN, LDBL_MIN# + * #TMANT_DIG = FLT_MANT_DIG, DBL_MANT_DIG, LDBL_MANT_DIG# + * #TEPS = FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON# + * #precision = 1, 2, 3# + */ + +/*========================================================== + * Constants + *=========================================================*/ +static const @ctype@ c_1@c@ = {1.0@C@, 0.0}; +static const @ctype@ c_half@c@ = {0.5@C@, 0.0}; +static const @ctype@ c_i@c@ = {0.0, 1.0@C@}; +static const @ctype@ c_ihalf@c@ = {0.0, 0.5@C@}; + +/*========================================================== + * Helper functions + * + * These are necessary because we do not count on using a + * C99 compiler. + *=========================================================*/ +static NPY_INLINE +@ctype@ +cadd@c@(@ctype@ a, @ctype@ b) +{ + return npy_cpack@c@(npy_creal@c@(a) + npy_creal@c@(b), + npy_cimag@c@(a) + npy_cimag@c@(b)); +} + +static NPY_INLINE +@ctype@ +csub@c@(@ctype@ a, @ctype@ b) +{ + return npy_cpack@c@(npy_creal@c@(a) - npy_creal@c@(b), + npy_cimag@c@(a) - npy_cimag@c@(b)); +} + +static NPY_INLINE +@ctype@ +cmul@c@(@ctype@ a, @ctype@ b) +{ + @type@ ar, ai, br, bi; + ar = npy_creal@c@(a); + ai = npy_cimag@c@(a); + br = npy_creal@c@(b); + bi = npy_cimag@c@(b); + return npy_cpack@c@(ar*br - ai*bi, ar*bi + ai*br); +} + +static NPY_INLINE +@ctype@ +cdiv@c@(@ctype@ a, @ctype@ b) +{ + @type@ ar, ai, br, bi, abs_br, abs_bi; + ar = npy_creal@c@(a); + ai = npy_cimag@c@(a); + br = npy_creal@c@(b); + bi = npy_cimag@c@(b); + abs_br = npy_fabs@c@(br); + abs_bi = npy_fabs@c@(bi); + + if (abs_br >= abs_bi) { + if (abs_br == 0 && abs_bi == 0) { + /* divide by zeros should yield a complex inf or nan */ + return npy_cpack@c@(ar/abs_br, ai/abs_bi); + } + else { + @type@ rat = bi/br; + @type@ scl = 1.0@C@/(br+bi*rat); + return npy_cpack@c@((ar + ai*rat)*scl, (ai - ar*rat)*scl); + } + } + else { + @type@ rat = br/bi; + @type@ scl = 1.0@C@/(bi + br*rat); + return npy_cpack@c@((ar*rat + ai)*scl, (ai*rat - ar)*scl); + } +} + +static NPY_INLINE +@ctype@ +cneg@c@(@ctype@ a) +{ + return npy_cpack@c@(-npy_creal@c@(a), -npy_cimag@c@(a)); +} + +static NPY_INLINE +@ctype@ +cmuli@c@(@ctype@ a) +{ + return npy_cpack@c@(-npy_cimag@c@(a), npy_creal@c@(a)); +} + +/*========================================================== + * Custom implementation of missing complex C99 functions + *=========================================================*/ + +#ifndef HAVE_CABS@C@ +@type@ +npy_cabs@c@(@ctype@ z) +{ + return npy_hypot@c@(npy_creal@c@(z), npy_cimag@c@(z)); +} +#endif + +#ifndef HAVE_CARG@C@ +@type@ +npy_carg@c@(@ctype@ z) +{ + return npy_atan2@c@(npy_cimag@c@(z), npy_creal@c@(z)); +} +#endif + +/* + * cexp and (ccos, csin)h functions need to calculate exp scaled by another + * number. This can be difficult if exp(x) overflows. By doing this way, we + * don't risk overflowing exp. This likely raises floating-point exceptions, + * if we decide that we care. + * + * This is only useful over a limited range, (see below) an expects that the + * input values are in this range. + * + * This is based on the technique used in FreeBSD's __frexp_exp and + * __ldexp_(c)exp functions by David Schultz. + * + * SCALED_CEXP_LOWER = log(FLT_MAX) + * SCALED_CEXP_UPPER = log(2) + log(FLT_MAX) - log(FLT_TRUE_MIN), + * where FLT_TRUE_MIN is the smallest possible subnormal number. + */ + +#define SCALED_CEXP_LOWERF 88.722839f +#define SCALED_CEXP_UPPERF 192.69492f +#define SCALED_CEXP_LOWER 710.47586007394386 +#define SCALED_CEXP_UPPER 1454.9159319953251 +#define SCALED_CEXP_LOWERL 11357.216553474703895L +#define SCALED_CEXP_UPPERL 22756.021937783004509L + +#if !defined(HAVE_CSINH@C@) || \ + !defined(HAVE_CCOSH@C@) || \ + !defined(HAVE_CEXP@C@) + +static +@ctype@ +_npy_scaled_cexp@c@(@type@ x, @type@ y, npy_int expt) +{ +#if @precision@ == 1 + const npy_int k = 235; +#endif +#if @precision@ == 2 + const npy_int k = 1799; +#endif +#if @precision@ == 3 + const npy_int k = 19547; +#endif + const @type@ kln2 = k * NPY_LOGE2@c@; + @type@ mant, mantcos, mantsin; + npy_int ex, excos, exsin; + + mant = npy_frexp@c@(npy_exp@c@(x - kln2), &ex); + mantcos = npy_frexp@c@(npy_cos@c@(y), &excos); + mantsin = npy_frexp@c@(npy_sin@c@(y), &exsin); + + expt += ex + k; + return npy_cpack@c@( npy_ldexp@c@(mant * mantcos, expt + excos), + npy_ldexp@c@(mant * mantsin, expt + exsin)); +} + +#endif + +#ifndef HAVE_CEXP@C@ + +@ctype@ +npy_cexp@c@(@ctype@ z) +{ + @type@ x, c, s; + @type@ r, i; + @ctype@ ret; + + r = npy_creal@c@(z); + i = npy_cimag@c@(z); + + if (npy_isfinite(r)) { + if (r >= SCALED_CEXP_LOWER@C@ && r <= SCALED_CEXP_UPPER@C@) { + ret = _npy_scaled_cexp@c@(r, i, 0); + } + else { + x = npy_exp@c@(r); + + c = npy_cos@c@(i); + s = npy_sin@c@(i); + + if (npy_isfinite(i)) { + ret = npy_cpack@c@(x * c, x * s); + } + else { + ret = npy_cpack@c@(NPY_NAN@C@, npy_copysign@c@(NPY_NAN@C@, i)); + } + } + + } + else if (npy_isnan(r)) { + /* r is nan */ + if (i == 0) { + ret = z; + } + else { + ret = npy_cpack@c@(r, npy_copysign@c@(NPY_NAN@C@, i)); + } + } + else { + /* r is +- inf */ + if (r > 0) { + if (i == 0) { + ret = npy_cpack@c@(r, i); + } + else if (npy_isfinite(i)) { + c = npy_cos@c@(i); + s = npy_sin@c@(i); + + ret = npy_cpack@c@(r * c, r * s); + } + else { + /* x = +inf, y = +-inf | nan */ + npy_set_floatstatus_invalid(); + ret = npy_cpack@c@(r, NPY_NAN@C@); + } + } + else { + if (npy_isfinite(i)) { + x = npy_exp@c@(r); + c = npy_cos@c@(i); + s = npy_sin@c@(i); + + ret = npy_cpack@c@(x * c, x * s); + } + else { + /* x = -inf, y = nan | +i inf */ + ret = npy_cpack@c@(0, 0); + } + } + } + + return ret; +} +#endif + +#ifndef HAVE_CLOG@C@ +/* algorithm from cpython, rev. d86f5686cef9 + * + * The usual formula for the real part is log(hypot(z.real, z.imag)). + * There are four situations where this formula is potentially + * problematic: + * + * (1) the absolute value of z is subnormal. Then hypot is subnormal, + * so has fewer than the usual number of bits of accuracy, hence may + * have large relative error. This then gives a large absolute error + * in the log. This can be solved by rescaling z by a suitable power + * of 2. + * + * (2) the absolute value of z is greater than DBL_MAX (e.g. when both + * z.real and z.imag are within a factor of 1/sqrt(2) of DBL_MAX) + * Again, rescaling solves this. + * + * (3) the absolute value of z is close to 1. In this case it's + * difficult to achieve good accuracy, at least in part because a + * change of 1ulp in the real or imaginary part of z can result in a + * change of billions of ulps in the correctly rounded answer. + * + * (4) z = 0. The simplest thing to do here is to call the + * floating-point log with an argument of 0, and let its behaviour + * (returning -infinity, signaling a floating-point exception, setting + * errno, or whatever) determine that of c_log. So the usual formula + * is fine here. +*/ +@ctype@ +npy_clog@c@(@ctype@ z) +{ + @type@ ax = npy_fabs@c@(npy_creal@c@(z)); + @type@ ay = npy_fabs@c@(npy_cimag@c@(z)); + @type@ rr, ri; + + if (ax > @TMAX@/4 || ay > @TMAX@/4) { + rr = npy_log@c@(npy_hypot@c@(ax/2, ay/2)) + NPY_LOGE2@c@; + } + else if (ax < @TMIN@ && ay < @TMIN@) { + if (ax > 0 || ay > 0) { + /* catch cases where hypot(ax, ay) is subnormal */ + rr = npy_log@c@(npy_hypot@c@(npy_ldexp@c@(ax, @TMANT_DIG@), + npy_ldexp@c@(ay, @TMANT_DIG@))) - @TMANT_DIG@*NPY_LOGE2@c@; + } + else { + /* log(+/-0 +/- 0i) */ + /* raise divide-by-zero floating point exception */ + rr = -1.0@c@ / npy_creal@c@(z); + rr = npy_copysign@c@(rr, -1); + ri = npy_carg@c@(z); + return npy_cpack@c@(rr, ri); + } + } + else { + @type@ h = npy_hypot@c@(ax, ay); + if (0.71 <= h && h <= 1.73) { + @type@ am = ax > ay ? ax : ay; /* max(ax, ay) */ + @type@ an = ax > ay ? ay : ax; /* min(ax, ay) */ + rr = npy_log1p@c@((am-1)*(am+1)+an*an)/2; + } + else { + rr = npy_log@c@(h); + } + } + ri = npy_carg@c@(z); + + return npy_cpack@c@(rr, ri); +} +#endif + +#ifndef HAVE_CSQRT@C@ + +/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */ +#define THRESH (@TMAX@ / (1 + NPY_SQRT2@c@)) + +@ctype@ +npy_csqrt@c@(@ctype@ z) +{ + @ctype@ result; + @type@ a, b; + @type@ t; + int scale; + + a = npy_creal@c@(z); + b = npy_cimag@c@(z); + + /* Handle special cases. */ + if (a == 0 && b == 0) { + return (npy_cpack@c@(0, b)); + } + if (npy_isinf(b)) { + return (npy_cpack@c@(NPY_INFINITY@C@, b)); + } + if (npy_isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return (npy_cpack@c@(a, t)); /* return NaN + NaN i */ + } + if (npy_isinf(a)) { + /* + * csqrt(inf + NaN i) = inf + NaN i + * csqrt(inf + y i) = inf + 0 i + * csqrt(-inf + NaN i) = NaN +- inf i + * csqrt(-inf + y i) = 0 + inf i + */ + if (npy_signbit(a)) { + return (npy_cpack@c@(npy_fabs@c@(b - b), npy_copysign@c@(a, b))); + } + else { + return (npy_cpack@c@(a, npy_copysign@c@(b - b, b))); + } + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* Scale to avoid overflow. */ + if (npy_fabs@c@(a) >= THRESH || npy_fabs@c@(b) >= THRESH) { + a *= 0.25; + b *= 0.25; + scale = 1; + } + else { + scale = 0; + } + + /* Algorithm 312, CACM vol 10, Oct 1967. */ + if (a >= 0) { + t = npy_sqrt@c@((a + npy_hypot@c@(a, b)) * 0.5@c@); + result = npy_cpack@c@(t, b / (2 * t)); + } + else { + t = npy_sqrt@c@((-a + npy_hypot@c@(a, b)) * 0.5@c@); + result = npy_cpack@c@(npy_fabs@c@(b) / (2 * t), npy_copysign@c@(t, b)); + } + + /* Rescale. */ + if (scale) { + return (npy_cpack@c@(npy_creal@c@(result) * 2, npy_cimag@c@(result))); + } + else { + return (result); + } +} +#undef THRESH +#endif + +/* + * Always use this function because of the multiplication for small + * integer powers, but in the body use cpow if it is available. + */ + +/* private function for use in npy_pow{f, ,l} */ +#ifdef HAVE_CPOW@C@ +static @ctype@ +sys_cpow@c@(@ctype@ x, @ctype@ y) +{ + __@ctype@_to_c99_cast xcast; + __@ctype@_to_c99_cast ycast; + __@ctype@_to_c99_cast ret; + xcast.npy_z = x; + ycast.npy_z = y; + ret.c99_z = cpow@c@(xcast.c99_z, ycast.c99_z); + return ret.npy_z; +} +#endif + + +@ctype@ +npy_cpow@c@ (@ctype@ a, @ctype@ b) +{ + npy_intp n; + @type@ ar = npy_creal@c@(a); + @type@ br = npy_creal@c@(b); + @type@ ai = npy_cimag@c@(a); + @type@ bi = npy_cimag@c@(b); + @ctype@ r; + + if (br == 0. && bi == 0.) { + return npy_cpack@c@(1., 0.); + } + if (ar == 0. && ai == 0.) { + if (br > 0 && bi == 0) { + return npy_cpack@c@(0., 0.); + } + else { + volatile @type@ tmp = NPY_INFINITY@C@; + /* + * NB: there are four complex zeros; c0 = (+-0, +-0), so that + * unlike for reals, c0**p, with `p` negative is in general + * ill-defined. + * + * c0**z with z complex is also ill-defined. + */ + r = npy_cpack@c@(NPY_NAN@C@, NPY_NAN@C@); + + /* Raise invalid */ + tmp -= NPY_INFINITY@C@; + ar = tmp; + return r; + } + } + if (bi == 0 && (n=(npy_intp)br) == br) { + if (n == 1) { + /* unroll: handle inf better */ + return npy_cpack@c@(ar, ai); + } + else if (n == 2) { + /* unroll: handle inf better */ + return cmul@c@(a, a); + } + else if (n == 3) { + /* unroll: handle inf better */ + return cmul@c@(a, cmul@c@(a, a)); + } + else if (n > -100 && n < 100) { + @ctype@ p, aa; + npy_intp mask = 1; + if (n < 0) { + n = -n; + } + aa = c_1@c@; + p = npy_cpack@c@(ar, ai); + while (1) { + if (n & mask) { + aa = cmul@c@(aa,p); + } + mask <<= 1; + if (n < mask || mask <= 0) { + break; + } + p = cmul@c@(p,p); + } + r = npy_cpack@c@(npy_creal@c@(aa), npy_cimag@c@(aa)); + if (br < 0) { + r = cdiv@c@(c_1@c@, r); + } + return r; + } + } + +#ifdef HAVE_CPOW@C@ + return sys_cpow@c@(a, b); + +#else + { + @ctype@ loga = npy_clog@c@(a); + + ar = npy_creal@c@(loga); + ai = npy_cimag@c@(loga); + return npy_cexp@c@(npy_cpack@c@(ar*br - ai*bi, ar*bi + ai*br)); + } + +#endif +} + + +#ifndef HAVE_CCOS@C@ +@ctype@ +npy_ccos@c@(@ctype@ z) +{ + /* ccos(z) = ccosh(I * z) */ + return npy_ccosh@c@(npy_cpack@c@(-npy_cimag@c@(z), npy_creal@c@(z))); +} +#endif + +#ifndef HAVE_CSIN@C@ +@ctype@ +npy_csin@c@(@ctype@ z) +{ + /* csin(z) = -I * csinh(I * z) */ + z = npy_csinh@c@(npy_cpack@c@(-npy_cimag@c@(z), npy_creal@c@(z))); + return npy_cpack@c@(npy_cimag@c@(z), -npy_creal@c@(z)); +} +#endif + +#ifndef HAVE_CTAN@C@ +@ctype@ +npy_ctan@c@(@ctype@ z) +{ + /* ctan(z) = -I * ctanh(I * z) */ + z = npy_ctanh@c@(npy_cpack@c@(-npy_cimag@c@(z), npy_creal@c@(z))); + return (npy_cpack@c@(npy_cimag@c@(z), -npy_creal@c@(z))); +} +#endif + +#ifndef HAVE_CCOSH@C@ +/* + * Taken from the msun library in FreeBSD, rev 226599. + * + * Hyperbolic cosine of a complex argument z = x + i y. + * + * cosh(z) = cosh(x+iy) + * = cosh(x) cos(y) + i sinh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + * + * CCOSH_BIG is chosen such that + * spacing(0.5 * exp(CCOSH_BIG)) > 0.5*exp(-CCOSH_BIG) + * although the exact value assigned to CCOSH_BIG is not so important + */ +@ctype@ +npy_ccosh@c@(@ctype@ z) +{ +#if @precision@ == 1 + const npy_float CCOSH_BIG = 9.0f; + const npy_float CCOSH_HUGE = 1.70141183e+38f; +#endif +#if @precision@ == 2 + const npy_double CCOSH_BIG = 22.0; + const npy_double CCOSH_HUGE = 8.9884656743115795e+307; +#endif +#if @precision@ >= 3 +#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE + const npy_longdouble CCOSH_BIG = 22.0L; + const npy_longdouble CCOSH_HUGE = 8.9884656743115795e+307L; +#else + const npy_longdouble CCOSH_BIG = 24.0L; + const npy_longdouble CCOSH_HUGE = 5.94865747678615882543e+4931L; +#endif +#endif + + @type@ x, y, h, absx; + npy_int xfinite, yfinite; + + x = npy_creal@c@(z); + y = npy_cimag@c@(z); + + xfinite = npy_isfinite(x); + yfinite = npy_isfinite(y); + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (xfinite && yfinite) { + if (y == 0) { + return npy_cpack@c@(npy_cosh@c@(x), x * y); + } + absx = npy_fabs@c@(x); + if (absx < CCOSH_BIG) { + /* small x: normal case */ + return npy_cpack@c@(npy_cosh@c@(x) * npy_cos@c@(y), + npy_sinh@c@(x) * npy_sin@c@(y)); + } + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (absx < SCALED_CEXP_LOWER@C@) { + /* x < 710: exp(|x|) won't overflow */ + h = npy_exp@c@(absx) * 0.5@c@; + return npy_cpack@c@(h * npy_cos@c@(y), + npy_copysign@c@(h, x) * npy_sin@c@(y)); + } + else if (absx < SCALED_CEXP_UPPER@C@) { + /* x < 1455: scale to avoid overflow */ + z = _npy_scaled_cexp@c@(absx, y, -1); + return npy_cpack@c@(npy_creal@c@(z), + npy_cimag@c@(z) * npy_copysign@c@(1, x)); + } + else { + /* x >= 1455: the result always overflows */ + h = CCOSH_HUGE * x; + return npy_cpack@c@(h * h * npy_cos@c@(y), h * npy_sin@c@(y)); + } + } + + /* + * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if (x == 0 && !yfinite) { + return npy_cpack@c@(y - y, npy_copysign@c@(0, x * (y - y))); + } + + /* + * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0. + * + * cosh(NaN +- I 0) = d(NaN) + I sign(d(NaN, +-0))0. + * The sign of 0 in the result is unspecified. + */ + if (y == 0 && !xfinite) { + return npy_cpack@c@(x * x, npy_copysign@c@(0, x) * y); + } + + /* + * cosh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * cosh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (xfinite && !yfinite) { + return npy_cpack@c@(y - y, x * (y - y)); + } + + /* + * cosh(+-Inf + I NaN) = +Inf + I d(NaN). + * + * cosh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * cosh(+-Inf + I y) = +Inf cos(y) +- I Inf sin(y) + */ + if (npy_isinf(x)) { + if (!yfinite) { + return npy_cpack@c@(x * x, x * (y - y)); + } + return npy_cpack@c@((x * x) * npy_cos@c@(y), x * npy_sin@c@(y)); + } + + /* + * cosh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * cosh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * cosh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return npy_cpack@c@((x * x) * (y - y), (x + x) * (y - y)); +} +#undef CCOSH_BIG +#undef CCOSH_HUGE +#endif + +#ifndef HAVE_CSINH@C@ +/* + * Taken from the msun library in FreeBSD, rev 226599. + * + * Hyperbolic sine of a complex argument z = x + i y. + * + * sinh(z) = sinh(x+iy) + * = sinh(x) cos(y) + i cosh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ +@ctype@ +npy_csinh@c@(@ctype@ z) +{ +#if @precision@ == 1 + const npy_float CSINH_BIG = 9.0f; + const npy_float CSINH_HUGE = 1.70141183e+38f; +#endif +#if @precision@ == 2 + const npy_double CSINH_BIG = 22.0; + const npy_double CSINH_HUGE = 8.9884656743115795e+307; +#endif +#if @precision@ >= 3 +#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE + const npy_longdouble CSINH_BIG = 22.0L; + const npy_longdouble CSINH_HUGE = 8.9884656743115795e+307L; +#else + const npy_longdouble CSINH_BIG = 24.0L; + const npy_longdouble CSINH_HUGE = 5.94865747678615882543e+4931L; +#endif +#endif + + @type@ x, y, h, absx; + npy_int xfinite, yfinite; + + x = npy_creal@c@(z); + y = npy_cimag@c@(z); + + xfinite = npy_isfinite(x); + yfinite = npy_isfinite(y); + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (xfinite && yfinite) { + if (y == 0) { + return npy_cpack@c@(npy_sinh@c@(x), y); + } + absx = npy_fabs@c@(x); + if (absx < CSINH_BIG) { + /* small x: normal case */ + return npy_cpack@c@(npy_sinh@c@(x) * npy_cos@c@(y), + npy_cosh@c@(x) * npy_sin@c@(y)); + } + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (absx < SCALED_CEXP_LOWER@C@) { + /* x < 710: exp(|x|) won't overflow */ + h = npy_exp@c@(npy_fabs@c@(x)) * 0.5@c@; + return npy_cpack@c@(npy_copysign@c@(h, x) * npy_cos@c@(y), + h * npy_sin@c@(y)); + } + else if (x < SCALED_CEXP_UPPER@C@) { + /* x < 1455: scale to avoid overflow */ + z = _npy_scaled_cexp@c@(absx, y, -1); + return npy_cpack@c@(npy_creal@c@(z) * npy_copysign@c@(1, x), + npy_cimag@c@(z)); + } + else { + /* x >= 1455: the result always overflows */ + h = CSINH_HUGE * x; + return npy_cpack@c@(h * npy_cos@c@(y), h * h * npy_sin@c@(y)); + } + } + + /* + * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN). + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if (x == 0 && !yfinite) { + return npy_cpack@c@(npy_copysign@c@(0, x * (y - y)), y - y); + } + + /* + * sinh(+-Inf +- I 0) = +-Inf + I +-0. + * + * sinh(NaN +- I 0) = d(NaN) + I +-0. + */ + if (y == 0 && !xfinite) { + if (npy_isnan(x)) { + return z; + } + return npy_cpack@c@(x, npy_copysign@c@(0, y)); + } + + /* + * sinh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * sinh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (xfinite && !yfinite) { + return npy_cpack@c@(y - y, x * (y - y)); + } + + /* + * sinh(+-Inf + I NaN) = +-Inf + I d(NaN). + * The sign of Inf in the result is unspecified. Choice = normally + * the same as d(NaN). + * + * sinh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y) + */ + if (!xfinite && !npy_isnan(x)) { + if (!yfinite) { + return npy_cpack@c@(x * x, x * (y - y)); + } + return npy_cpack@c@(x * npy_cos@c@(y), + NPY_INFINITY@C@ * npy_sin@c@(y)); + } + + /* + * sinh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * sinh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * sinh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return npy_cpack@c@((x * x) * (y - y), (x + x) * (y - y)); +} +#undef CSINH_BIG +#undef CSINH_HUGE +#endif + +#ifndef HAVE_CTANH@C@ +/* + * Taken from the msun library in FreeBSD, rev 226600. + * + * Hyperbolic tangent of a complex argument z = x + i y. + * + * The algorithm is from: + * + * W. Kahan. Branch Cuts for Complex Elementary Functions or Much + * Ado About Nothing's Sign Bit. In The State of the Art in + * Numerical Analysis, pp. 165 ff. Iserles and Powell, eds., 1987. + * + * Method: + * + * Let t = tan(x) + * beta = 1/cos^2(y) + * s = sinh(x) + * rho = cosh(x) + * + * We have: + * + * tanh(z) = sinh(z) / cosh(z) + * + * sinh(x) cos(y) + i cosh(x) sin(y) + * = --------------------------------- + * cosh(x) cos(y) + i sinh(x) sin(y) + * + * cosh(x) sinh(x) / cos^2(y) + i tan(y) + * = ------------------------------------- + * 1 + sinh^2(x) / cos^2(y) + * + * beta rho s + i t + * = ---------------- + * 1 + beta s^2 + * + * Modifications: + * + * I omitted the original algorithm's handling of overflow in tan(x) after + * verifying with nearpi.c that this can't happen in IEEE single or double + * precision. I also handle large x differently. + */ + +#define TANH_HUGE 22.0 +#define TANHF_HUGE 11.0F +#define TANHL_HUGE 42.0L + +@ctype@ +npy_ctanh@c@(@ctype@ z) +{ + @type@ x, y; + @type@ t, beta, s, rho, denom; + + x = npy_creal@c@(z); + y = npy_cimag@c@(z); + + /* + * ctanh(NaN + i 0) = NaN + i 0 + * + * ctanh(NaN + i y) = NaN + i NaN for y != 0 + * + * The imaginary part has the sign of x*sin(2*y), but there's no + * special effort to get this right. + * + * ctanh(+-Inf +- i Inf) = +-1 +- 0 + * + * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite + * + * The imaginary part of the sign is unspecified. This special + * case is only needed to avoid a spurious invalid exception when + * y is infinite. + */ + if (!npy_isfinite(x)) { + if (npy_isnan(x)) { + return npy_cpack@c@(x, (y == 0 ? y : x * y)); + } + return npy_cpack@c@(npy_copysign@c@(1,x), + npy_copysign@c@(0, + npy_isinf(y) ? + y : npy_sin@c@(y) * npy_cos@c@(y))); + } + + /* + * ctanh(x + i NAN) = NaN + i NaN + * ctanh(x +- i Inf) = NaN + i NaN + */ + if (!npy_isfinite(y)) { + return (npy_cpack@c@(y - y, y - y)); + } + + /* + * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the + * approximation sinh^2(huge) ~= exp(2*huge) / 4. + * We use a modified formula to avoid spurious overflow. + */ + if (npy_fabs@c@(x) >= TANH@C@_HUGE) { + @type@ exp_mx = npy_exp@c@(-npy_fabs@c@(x)); + return npy_cpack@c@(npy_copysign@c@(1, x), + 4 * npy_sin@c@(y) * npy_cos@c@(y) * + exp_mx * exp_mx); + } + + /* Kahan's algorithm */ + t = npy_tan@c@(y); + beta = 1 + t * t; /* = 1 / cos^2(y) */ + s = npy_sinh@c@(x); + rho = npy_sqrt@c@(1 + s * s); /* = cosh(x) */ + denom = 1 + beta * s * s; + return (npy_cpack@c@((beta * rho * s) / denom, t / denom)); +} +#undef TANH_HUGE +#undef TANHF_HUGE +#undef TANHL_HUGE +#endif + +#if !defined (HAVE_CACOS@C@) || !defined (HAVE_CASINH@C@) +/* + * Complex inverse trig functions taken from the msum library in FreeBSD + * revision 251404 + * + * The algorithm is very close to that in "Implementing the complex arcsine + * and arccosine functions using exception handling" by T. E. Hull, Thomas F. + * Fairgrieve, and Ping Tak Peter Tang, published in ACM Transactions on + * Mathematical Software, Volume 23 Issue 3, 1997, Pages 299-335, + * http://dl.acm.org/citation.cfm?id=275324. + * + * Throughout we use the convention z = x + I*y. + * + * casinh(z) = sign(x)*log(A+sqrt(A*A-1)) + I*asin(B) + * where + * A = (|z+I| + |z-I|) / 2 + * B = (|z+I| - |z-I|) / 2 = y/A + * + * These formulas become numerically unstable: + * (a) for Re(casinh(z)) when z is close to the line segment [-I, I] (that + * is, Re(casinh(z)) is close to 0); + * (b) for Im(casinh(z)) when z is close to either of the intervals + * [I, I*infinity) or (-I*infinity, -I] (that is, |Im(casinh(z))| is + * close to PI/2). + * + * These numerical problems are overcome by defining + * f(a, b) = (hypot(a, b) - b) / 2 = a*a / (hypot(a, b) + b) / 2 + * Then if A < A_crossover, we use + * log(A + sqrt(A*A-1)) = log1p((A-1) + sqrt((A-1)*(A+1))) + * A-1 = f(x, 1+y) + f(x, 1-y) + * and if B > B_crossover, we use + * asin(B) = atan2(y, sqrt(A*A - y*y)) = atan2(y, sqrt((A+y)*(A-y))) + * A-y = f(x, y+1) + f(x, y-1) + * where without loss of generality we have assumed that x and y are + * non-negative. + * + * Much of the difficulty comes because the intermediate computations may + * produce overflows or underflows. This is dealt with in the paper by Hull + * et al by using exception handling. We do this by detecting when + * computations risk underflow or overflow. The hardest part is handling the + * underflows when computing f(a, b). + * + * Note that the function f(a, b) does not appear explicitly in the paper by + * Hull et al, but the idea may be found on pages 308 and 309. Introducing the + * function f(a, b) allows us to concentrate many of the clever tricks in this + * paper into one function. + */ + +/* + * Function f(a, b, hypot_a_b) = (hypot(a, b) - b) / 2. + * Pass hypot(a, b) as the third argument. + */ +static NPY_INLINE @type@ +_f@c@(@type@ a, @type@ b, @type@ hypot_a_b) +{ + if (b < 0) { + return ((hypot_a_b - b) / 2); + } + if (b == 0) { + return (a / 2); + } + return (a * a / (hypot_a_b + b) / 2); +} + +/* + * All the hard work is contained in this function. + * x and y are assumed positive or zero, and less than RECIP_EPSILON. + * Upon return: + * rx = Re(casinh(z)) = -Im(cacos(y + I*x)). + * B_is_usable is set to 1 if the value of B is usable. + * If B_is_usable is set to 0, sqrt_A2my2 = sqrt(A*A - y*y), and new_y = y. + * If returning sqrt_A2my2 has potential to result in an underflow, it is + * rescaled, and new_y is similarly rescaled. + */ +static NPY_INLINE void +_do_hard_work@c@(@type@ x, @type@ y, @type@ *rx, + npy_int *B_is_usable, @type@ *B, @type@ *sqrt_A2my2, @type@ *new_y) +{ +#if @precision@ == 1 + const npy_float A_crossover = 10.0f; + const npy_float B_crossover = 0.6417f; + const npy_float FOUR_SQRT_MIN = 4.3368086899420177e-19f; +#endif +#if @precision@ == 2 + const npy_double A_crossover = 10.0; + const npy_double B_crossover = 0.6417; + const npy_double FOUR_SQRT_MIN = 5.9666725849601654e-154; +#endif +#if @precision@ == 3 + const npy_longdouble A_crossover = 10.0l; + const npy_longdouble B_crossover = 0.6417l; +#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE + const npy_longdouble FOUR_SQRT_MIN = 5.9666725849601654e-154; +#else + const npy_longdouble FOUR_SQRT_MIN = 7.3344154702193886625e-2466l; +#endif +#endif + @type@ R, S, A; /* A, B, R, and S are as in Hull et al. */ + @type@ Am1, Amy; /* A-1, A-y. */ + + R = npy_hypot@c@(x, y + 1); /* |z+I| */ + S = npy_hypot@c@(x, y - 1); /* |z-I| */ + + /* A = (|z+I| + |z-I|) / 2 */ + A = (R + S) / 2; + /* + * Mathematically A >= 1. There is a small chance that this will not + * be so because of rounding errors. So we will make certain it is + * so. + */ + if (A < 1) { + A = 1; + } + + if (A < A_crossover) { + /* + * Am1 = fp + fm, where fp = f(x, 1+y), and fm = f(x, 1-y). + * rx = log1p(Am1 + sqrt(Am1*(A+1))) + */ + if (y == 1 && x < @TEPS@ * @TEPS@ / 128) { + /* + * fp is of order x^2, and fm = x/2. + * A = 1 (inexactly). + */ + *rx = npy_sqrt@c@(x); + } + else if (x >= @TEPS@ * npy_fabs@c@(y - 1)) { + /* + * Underflow will not occur because + * x >= DBL_EPSILON^2/128 >= FOUR_SQRT_MIN + */ + Am1 = _f@c@(x, 1 + y, R) + _f@c@(x, 1 - y, S); + *rx = npy_log1p@c@(Am1 + npy_sqrt@c@(Am1 * (A + 1))); + } + else if (y < 1) { + /* + * fp = x*x/(1+y)/4, fm = x*x/(1-y)/4, and + * A = 1 (inexactly). + */ + *rx = x / npy_sqrt@c@((1 - y) * (1 + y)); + } + else { /* if (y > 1) */ + /* + * A-1 = y-1 (inexactly). + */ + *rx = npy_log1p@c@((y - 1) + npy_sqrt@c@((y - 1) * (y + 1))); + } + } + else { + *rx = npy_log@c@(A + npy_sqrt@c@(A * A - 1)); + } + + *new_y = y; + + if (y < FOUR_SQRT_MIN) { + /* + * Avoid a possible underflow caused by y/A. For casinh this + * would be legitimate, but will be picked up by invoking atan2 + * later on. For cacos this would not be legitimate. + */ + *B_is_usable = 0; + *sqrt_A2my2 = A * (2 / @TEPS@); + *new_y = y * (2 / @TEPS@); + return; + } + + /* B = (|z+I| - |z-I|) / 2 = y/A */ + *B = y / A; + *B_is_usable = 1; + + if (*B > B_crossover) { + *B_is_usable = 0; + /* + * Amy = fp + fm, where fp = f(x, y+1), and fm = f(x, y-1). + * sqrt_A2my2 = sqrt(Amy*(A+y)) + */ + if (y == 1 && x < @TEPS@ / 128) { + /* + * fp is of order x^2, and fm = x/2. + * A = 1 (inexactly). + */ + *sqrt_A2my2 = npy_sqrt@c@(x) * npy_sqrt@c@((A + y) / 2); + } + else if (x >= @TEPS@ * npy_fabs@c@(y - 1)) { + /* + * Underflow will not occur because + * x >= DBL_EPSILON/128 >= FOUR_SQRT_MIN + * and + * x >= DBL_EPSILON^2 >= FOUR_SQRT_MIN + */ + Amy = _f@c@(x, y + 1, R) + _f@c@(x, y - 1, S); + *sqrt_A2my2 = npy_sqrt@c@(Amy * (A + y)); + } + else if (y > 1) { + /* + * fp = x*x/(y+1)/4, fm = x*x/(y-1)/4, and + * A = y (inexactly). + * + * y < RECIP_EPSILON. So the following + * scaling should avoid any underflow problems. + */ + *sqrt_A2my2 = x * (4 / @TEPS@ / @TEPS@) * y / + npy_sqrt@c@((y + 1) * (y - 1)); + *new_y = y * (4 / @TEPS@ / @TEPS@); + } + else { /* if (y < 1) */ + /* + * fm = 1-y >= DBL_EPSILON, fp is of order x^2, and + * A = 1 (inexactly). + */ + *sqrt_A2my2 = npy_sqrt@c@((1 - y) * (1 + y)); + } + } +} + +/* + * Optimized version of clog() for |z| finite and larger than ~RECIP_EPSILON. + */ +static NPY_INLINE void +_clog_for_large_values@c@(@type@ x, @type@ y, + @type@ *rr, @type@ *ri) +{ +#if @precision@ == 1 + const npy_float QUARTER_SQRT_MAX = 4.611685743549481e+18f; + const npy_float SQRT_MIN = 1.0842021724855044e-19f; + #endif +#if @precision@ == 2 + const npy_double QUARTER_SQRT_MAX = 3.3519519824856489e+153; + const npy_double SQRT_MIN = 1.4916681462400413e-154; + #endif +#if @precision@ == 3 +#if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE + const npy_longdouble QUARTER_SQRT_MAX = 3.3519519824856489e+153; + const npy_longdouble SQRT_MIN = 1.4916681462400413e-154; +#else + const npy_longdouble QUARTER_SQRT_MAX = 2.7268703390485398235e+2465l; + const npy_longdouble SQRT_MIN = 1.8336038675548471656e-2466l; +#endif +#endif + @type@ ax, ay, t; + + ax = npy_fabs@c@(x); + ay = npy_fabs@c@(y); + if (ax < ay) { + t = ax; + ax = ay; + ay = t; + } + + /* + * Avoid overflow in hypot() when x and y are both very large. + * Divide x and y by E, and then add 1 to the logarithm. This depends + * on E being larger than sqrt(2). + * Dividing by E causes an insignificant loss of accuracy; however + * this method is still poor since it is uneccessarily slow. + */ + if (ax > @TMAX@ / 2) { + *rr = npy_log@c@(npy_hypot@c@(x / NPY_E@c@, y / NPY_E@c@)) + 1; + } + /* + * Avoid overflow when x or y is large. Avoid underflow when x or + * y is small. + */ + else if (ax > QUARTER_SQRT_MAX || ay < SQRT_MIN) { + *rr = npy_log@c@(npy_hypot@c@(x, y)); + } + else { + *rr = npy_log@c@(ax * ax + ay * ay) / 2; + } + *ri = npy_atan2@c@(y, x); +} +#endif + +#ifndef HAVE_CACOS@C@ +@ctype@ +npy_cacos@c@(@ctype@ z) +{ +#if @precision@ == 1 + /* this is sqrt(6*EPS) */ + const npy_float SQRT_6_EPSILON = 8.4572793338e-4f; + /* chosen such that pio2_hi + pio2_lo == pio2_hi but causes FE_INEXACT. */ + const volatile npy_float pio2_lo = 7.5497899549e-9f; +#endif +#if @precision@ == 2 + const npy_double SQRT_6_EPSILON = 3.65002414998885671e-08; + const volatile npy_double pio2_lo = 6.1232339957367659e-17; +#endif +#if @precision@ == 3 + const npy_longdouble SQRT_6_EPSILON = 8.0654900873493277169e-10l; + const volatile npy_longdouble pio2_lo = 2.710505431213761085e-20l; +#endif + const @type@ RECIP_EPSILON = 1.0@c@ / @TEPS@; + const @type@ pio2_hi = NPY_PI_2@c@; + @type@ x, y, ax, ay, wx, wy, rx, ry, B, sqrt_A2mx2, new_x; + npy_int sx, sy; + npy_int B_is_usable; + + x = npy_creal@c@(z); + y = npy_cimag@c@(z); + sx = npy_signbit(x); + sy = npy_signbit(y); + ax = npy_fabs@c@(x); + ay = npy_fabs@c@(y); + + if (npy_isnan(x) || npy_isnan(y)) { + /* cacos(+-Inf + I*NaN) = NaN + I*opt(-)Inf */ + if (npy_isinf(x)) { + return npy_cpack@c@(y + y, -NPY_INFINITY@C@); + } + /* cacos(NaN + I*+-Inf) = NaN + I*-+Inf */ + if (npy_isinf(y)) { + return npy_cpack@c@(x + x, -y); + } + /* cacos(0 + I*NaN) = PI/2 + I*NaN with inexact */ + if (x == 0) { + return npy_cpack@c@(pio2_hi + pio2_lo, y + y); + } + /* + * All other cases involving NaN return NaN + I*NaN. + * C99 leaves it optional whether to raise invalid if one of + * the arguments is not NaN, so we opt not to raise it. + */ + return npy_cpack@c@(NPY_NAN@C@, NPY_NAN@C@); + } + + if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) { + /* clog...() will raise inexact unless x or y is infinite. */ + _clog_for_large_values@c@(x, y, &wx, &wy); + rx = npy_fabs@c@(wy); + ry = wx + NPY_LOGE2@c@; + if (sy == 0) { + ry = -ry; + } + return npy_cpack@c@(rx, ry); + } + + /* Avoid spuriously raising inexact for z = 1. */ + if (x == 1 && y == 0) { + return npy_cpack@c@(0, -y); + } + + /* All remaining cases are inexact. */ + raise_inexact(); + + if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4) { + return npy_cpack@c@(pio2_hi - (x - pio2_lo), -y); + } + + _do_hard_work@c@(ay, ax, &ry, &B_is_usable, &B, &sqrt_A2mx2, &new_x); + if (B_is_usable) { + if (sx == 0) { + rx = npy_acos@c@(B); + } + else { + rx = npy_acos@c@(-B); + } + } + else { + if (sx == 0) { + rx = npy_atan2@c@(sqrt_A2mx2, new_x); + } + else { + rx = npy_atan2@c@(sqrt_A2mx2, -new_x); + } + } + if (sy == 0) { + ry = -ry; + } + return npy_cpack@c@(rx, ry); +} +#endif + +#ifndef HAVE_CASIN@C@ +@ctype@ +npy_casin@c@(@ctype@ z) +{ + /* casin(z) = I * conj( casinh(I * conj(z)) ) */ + z = npy_casinh@c@(npy_cpack@c@(npy_cimag@c@(z), npy_creal@c@(z))); + return npy_cpack@c@(npy_cimag@c@(z), npy_creal@c@(z)); +} +#endif + +#ifndef HAVE_CATAN@C@ +@ctype@ +npy_catan@c@(@ctype@ z) +{ + /* catan(z) = I * conj( catanh(I * conj(z)) ) */ + z = npy_catanh@c@(npy_cpack@c@(npy_cimag@c@(z), npy_creal@c@(z))); + return npy_cpack@c@(npy_cimag@c@(z), npy_creal@c@(z)); +} +#endif + +#ifndef HAVE_CACOSH@C@ +@ctype@ +npy_cacosh@c@(@ctype@ z) +{ + /* + * cacosh(z) = I*cacos(z) or -I*cacos(z) + * where the sign is chosen so Re(cacosh(z)) >= 0. + */ + @ctype@ w; + @type@ rx, ry; + + w = npy_cacos@c@(z); + rx = npy_creal@c@(w); + ry = npy_cimag@c@(w); + /* cacosh(NaN + I*NaN) = NaN + I*NaN */ + if (npy_isnan(rx) && npy_isnan(ry)) { + return npy_cpack@c@(ry, rx); + } + /* cacosh(NaN + I*+-Inf) = +Inf + I*NaN */ + /* cacosh(+-Inf + I*NaN) = +Inf + I*NaN */ + if (npy_isnan(rx)) { + return npy_cpack@c@(npy_fabs@c@(ry), rx); + } + /* cacosh(0 + I*NaN) = NaN + I*NaN */ + if (npy_isnan(ry)) { + return npy_cpack@c@(ry, ry); + } + return npy_cpack@c@(npy_fabs@c@(ry), npy_copysign@c@(rx, npy_cimag@c@(z))); +} +#endif + +#ifndef HAVE_CASINH@C@ +/* + * casinh(z) = z + O(z^3) as z -> 0 + * + * casinh(z) = sign(x)*clog(sign(x)*z) + O(1/z^2) as z -> infinity + * The above formula works for the imaginary part as well, because + * Im(casinh(z)) = sign(x)*atan2(sign(x)*y, fabs(x)) + O(y/z^3) + * as z -> infinity, uniformly in y + */ +@ctype@ +npy_casinh@c@(@ctype@ z) +{ +#if @precision@ == 1 + /* this is sqrt(6*EPS) */ + const npy_float SQRT_6_EPSILON = 8.4572793338e-4f; + /* chosen such that pio2_hi + pio2_lo == pio2_hi but causes FE_INEXACT. */ + const volatile npy_float pio2_lo = 7.5497899549e-9f; +#endif +#if @precision@ == 2 + const npy_double SQRT_6_EPSILON = 3.65002414998885671e-08; + const volatile npy_double pio2_lo = 6.1232339957367659e-17; +#endif +#if @precision@ == 3 + const npy_longdouble SQRT_6_EPSILON = 8.0654900873493277169e-10l; + const volatile npy_longdouble pio2_lo = 2.710505431213761085e-20l; +#endif + const @type@ RECIP_EPSILON = 1.0@c@ / @TEPS@; + const @type@ pio2_hi = NPY_PI_2@c@; + @type@ x, y, ax, ay, wx, wy, rx, ry, B, sqrt_A2my2, new_y; + npy_int B_is_usable; + + x = npy_creal@c@(z); + y = npy_cimag@c@(z); + ax = npy_fabs@c@(x); + ay = npy_fabs@c@(y); + + if (npy_isnan(x) || npy_isnan(y)) { + /* casinh(+-Inf + I*NaN) = +-Inf + I*NaN */ + if (npy_isinf(x)) { + return npy_cpack@c@(x, y + y); + } + /* casinh(NaN + I*+-Inf) = opt(+-)Inf + I*NaN */ + if (npy_isinf(y)) { + return npy_cpack@c@(y, x + x); + } + /* casinh(NaN + I*0) = NaN + I*0 */ + if (y == 0) { + return npy_cpack@c@(x + x, y); + } + /* + * All other cases involving NaN return NaN + I*NaN. + * C99 leaves it optional whether to raise invalid if one of + * the arguments is not NaN, so we opt not to raise it. + */ + return npy_cpack@c@(NPY_NAN@C@, NPY_NAN@C@); + } + + if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) { + /* clog...() will raise inexact unless x or y is infinite. */ + if (npy_signbit(x) == 0) { + _clog_for_large_values@c@(x, y, &wx, &wy); + wx += NPY_LOGE2@c@; + } + else { + _clog_for_large_values@c@(-x, -y, &wx, &wy); + wx += NPY_LOGE2@c@; + } + return npy_cpack@c@(npy_copysign@c@(wx, x), npy_copysign@c@(wy, y)); + } + + /* Avoid spuriously raising inexact for z = 0. */ + if (x == 0 && y == 0) { + return (z); + } + + /* All remaining cases are inexact. */ + raise_inexact(); + + if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4) { + return (z); + } + + _do_hard_work@c@(ax, ay, &rx, &B_is_usable, &B, &sqrt_A2my2, &new_y); + if (B_is_usable) { + ry = npy_asin@c@(B); + } + else { + ry = npy_atan2@c@(new_y, sqrt_A2my2); + } + return npy_cpack@c@(npy_copysign@c@(rx, x), npy_copysign@c@(ry, y)); +} +#endif + +#ifndef HAVE_CATANH@C@ +/* + * sum_squares(x,y) = x*x + y*y (or just x*x if y*y would underflow). + * Assumes x*x and y*y will not overflow. + * Assumes x and y are finite. + * Assumes y is non-negative. + * Assumes fabs(x) >= DBL_EPSILON. + */ +static NPY_INLINE @type@ +_sum_squares@c@(@type@ x, @type@ y) +{ +#if @precision@ == 1 +const npy_float SQRT_MIN = 1.0842022e-19f; +#endif +#if @precision@ == 2 +const npy_double SQRT_MIN = 1.4916681462400413e-154; /* sqrt(DBL_MIN) */ +#endif +#if @precision@ == 3 +/* this is correct for 80 bit long doubles */ +const npy_longdouble SQRT_MIN = 1.8336038675548471656e-2466l; +#endif + /* Avoid underflow when y is small. */ + if (y < SQRT_MIN) { + return (x * x); + } + + return (x * x + y * y); +} + +/* + * real_part_reciprocal(x, y) = Re(1/(x+I*y)) = x/(x*x + y*y). + * Assumes x and y are not NaN, and one of x and y is larger than + * RECIP_EPSILON. We avoid unwarranted underflow. It is important to not use + * the code creal(1/z), because the imaginary part may produce an unwanted + * underflow. + * This is only called in a context where inexact is always raised before + * the call, so no effort is made to avoid or force inexact. + */ +#if @precision@ == 1 +#define BIAS (FLT_MAX_EXP - 1) +#define CUTOFF (FLT_MANT_DIG / 2 + 1) +static NPY_INLINE npy_float +_real_part_reciprocalf(npy_float x, npy_float y) +{ + npy_float scale; + npy_uint32 hx, hy; + npy_int32 ix, iy; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7f800000; + GET_FLOAT_WORD(hy, y); + iy = hy & 0x7f800000; + if (ix - iy >= CUTOFF << 23 || npy_isinf(x)) { + return (1 / x); + } + if (iy - ix >= CUTOFF << 23) { + return (x / y / y); + } + if (ix <= (BIAS + FLT_MAX_EXP / 2 - CUTOFF) << 23) { + return (x / (x * x + y * y)); + } + SET_FLOAT_WORD(scale, 0x7f800000 - ix); + x *= scale; + y *= scale; + return (x / (x * x + y * y) * scale); +} +#undef BIAS +#undef CUTOFF +#endif + +#if @precision@ == 2 +#define BIAS (DBL_MAX_EXP - 1) +/* more guard digits are useful iff there is extra precision. */ +#define CUTOFF (DBL_MANT_DIG / 2 + 1) /* just half or 1 guard digit */ +static NPY_INLINE npy_double +_real_part_reciprocal(npy_double x, npy_double y) +{ + npy_double scale; + npy_uint32 hx, hy; + npy_int32 ix, iy; + + /* + * This code is inspired by the C99 document n1124.pdf, Section G.5.1, + * example 2. + */ + GET_HIGH_WORD(hx, x); + ix = hx & 0x7ff00000; + GET_HIGH_WORD(hy, y); + iy = hy & 0x7ff00000; + if (ix - iy >= CUTOFF << 20 || npy_isinf(x)) { + /* +-Inf -> +-0 is special */ + return (1 / x); + } + if (iy - ix >= CUTOFF << 20) { + /* should avoid double div, but hard */ + return (x / y / y); + } + if (ix <= (BIAS + DBL_MAX_EXP / 2 - CUTOFF) << 20) { + return (x / (x * x + y * y)); + } + scale = 1; + SET_HIGH_WORD(scale, 0x7ff00000 - ix); /* 2**(1-ilogb(x)) */ + x *= scale; + y *= scale; + return (x / (x * x + y * y) * scale); +} +#undef BIAS +#undef CUTOFF +#endif + +#if @precision@ == 3 +#if !defined(HAVE_LDOUBLE_DOUBLE_DOUBLE_BE) && \ + !defined(HAVE_LDOUBLE_DOUBLE_DOUBLE_LE) + +#define BIAS (LDBL_MAX_EXP - 1) +#define CUTOFF (LDBL_MANT_DIG / 2 + 1) +static NPY_INLINE npy_longdouble +_real_part_reciprocall(npy_longdouble x, + npy_longdouble y) +{ + npy_longdouble scale; + union IEEEl2bitsrep ux, uy, us; + npy_int32 ix, iy; + + ux.e = x; + ix = GET_LDOUBLE_EXP(ux); + uy.e = y; + iy = GET_LDOUBLE_EXP(uy); + if (ix - iy >= CUTOFF || npy_isinf(x)) { + return (1/x); + } + if (iy - ix >= CUTOFF) { + return (x/y/y); + } + if (ix <= BIAS + LDBL_MAX_EXP / 2 - CUTOFF) { + return (x/(x*x + y*y)); + } + us.e = 1; + SET_LDOUBLE_EXP(us, 0x7fff - ix); + scale = us.e; + x *= scale; + y *= scale; + return (x/(x*x + y*y) * scale); +} +#undef BIAS +#undef CUTOFF + +#else + +static NPY_INLINE npy_longdouble +_real_part_reciprocall(npy_longdouble x, + npy_longdouble y) +{ + return x/(x*x + y*y); +} + +#endif +#endif + +@ctype@ +npy_catanh@c@(@ctype@ z) +{ +#if @precision@ == 1 + /* this is sqrt(3*EPS) */ + const npy_float SQRT_3_EPSILON = 5.9801995673e-4f; + /* chosen such that pio2_hi + pio2_lo == pio2_hi but causes FE_INEXACT. */ + const volatile npy_float pio2_lo = 7.5497899549e-9f; +#endif +#if @precision@ == 2 + const npy_double SQRT_3_EPSILON = 2.5809568279517849e-8; + const volatile npy_double pio2_lo = 6.1232339957367659e-17; +#endif +#if @precision@ == 3 + const npy_longdouble SQRT_3_EPSILON = 5.70316273435758915310e-10l; + const volatile npy_longdouble pio2_lo = 2.710505431213761085e-20l; +#endif + const @type@ RECIP_EPSILON = 1.0@c@ / @TEPS@; + const @type@ pio2_hi = NPY_PI_2@c@; + @type@ x, y, ax, ay, rx, ry; + + x = npy_creal@c@(z); + y = npy_cimag@c@(z); + ax = npy_fabs@c@(x); + ay = npy_fabs@c@(y); + + /* This helps handle many cases. */ + if (y == 0 && ax <= 1) { + return npy_cpack@c@(npy_atanh@c@(x), y); + } + + /* To ensure the same accuracy as atan(), and to filter out z = 0. */ + if (x == 0) { + return npy_cpack@c@(x, npy_atan@c@(y)); + } + + if (npy_isnan(x) || npy_isnan(y)) { + /* catanh(+-Inf + I*NaN) = +-0 + I*NaN */ + if (npy_isinf(x)) { + return npy_cpack@c@(npy_copysign@c@(0, x), y + y); + } + /* catanh(NaN + I*+-Inf) = sign(NaN)0 + I*+-PI/2 */ + if (npy_isinf(y)) { + return npy_cpack@c@(npy_copysign@c@(0, x), + npy_copysign@c@(pio2_hi + pio2_lo, y)); + } + /* + * All other cases involving NaN return NaN + I*NaN. + * C99 leaves it optional whether to raise invalid if one of + * the arguments is not NaN, so we opt not to raise it. + */ + return npy_cpack@c@(NPY_NAN@C@, NPY_NAN@C@); + } + + if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) { + return npy_cpack@c@(_real_part_reciprocal@c@(x, y), + npy_copysign@c@(pio2_hi + pio2_lo, y)); + } + + if (ax < SQRT_3_EPSILON / 2 && ay < SQRT_3_EPSILON / 2) { + /* + * z = 0 was filtered out above. All other cases must raise + * inexact, but this is the only only that needs to do it + * explicitly. + */ + raise_inexact(); + return (z); + } + + if (ax == 1 && ay < @TEPS@) { + rx = (NPY_LOGE2@c@ - npy_log@c@(ay)) / 2; + } + else { + rx = npy_log1p@c@(4 * ax / _sum_squares@c@(ax - 1, ay)) / 4; + } + + if (ax == 1) { + ry = npy_atan2@c@(2, -ay) / 2; + } + else if (ay < @TEPS@) { + ry = npy_atan2@c@(2 * ay, (1 - ax) * (1 + ax)) / 2; + } + else { + ry = npy_atan2@c@(2 * ay, (1 - ax) * (1 + ax) - ay * ay) / 2; + } + + return npy_cpack@c@(npy_copysign@c@(rx, x), npy_copysign@c@(ry, y)); +} +#endif +/**end repeat**/ + +/*========================================================== + * Decorate all the functions which are available natively + *=========================================================*/ + +/**begin repeat + * #type = npy_float, npy_double, npy_longdouble# + * #ctype = npy_cfloat, npy_cdouble, npy_clongdouble# + * #c = f, , l# + * #C = F, , L# + */ + +/**begin repeat1 + * #kind = cabs,carg# + * #KIND = CABS,CARG# + */ +#ifdef HAVE_@KIND@@C@ +@type@ +npy_@kind@@c@(@ctype@ z) +{ + __@ctype@_to_c99_cast z1; + z1.npy_z = z; + return @kind@@c@(z1.c99_z); +} +#endif +/**end repeat1**/ + +/**begin repeat1 + * #kind = cexp,clog,csqrt,ccos,csin,ctan,ccosh,csinh,ctanh, + * cacos,casin,catan,cacosh,casinh,catanh# + * #KIND = CEXP,CLOG,CSQRT,CCOS,CSIN,CTAN,CCOSH,CSINH,CTANH, + * CACOS,CASIN,CATAN,CACOSH,CASINH,CATANH# + */ +#ifdef HAVE_@KIND@@C@ +@ctype@ +npy_@kind@@c@(@ctype@ z) +{ + __@ctype@_to_c99_cast z1; + __@ctype@_to_c99_cast ret; + z1.npy_z = z; + ret.c99_z = @kind@@c@(z1.c99_z); + return ret.npy_z; +} +#endif +/**end repeat1**/ + + +/**end repeat**/ diff --git a/numpy/core/src/npymath/npy_math_internal.h.src b/numpy/core/src/npymath/npy_math_internal.h.src new file mode 100644 index 0000000..093e51b --- /dev/null +++ b/numpy/core/src/npymath/npy_math_internal.h.src @@ -0,0 +1,680 @@ +/* + * vim:syntax=c + * A small module to implement missing C99 math capabilities required by numpy + * + * Please keep this independent of python ! Only basic types (npy_longdouble) + * can be used, otherwise, pure C, without any use of Python facilities + * + * How to add a function to this section + * ------------------------------------- + * + * Say you want to add `foo`, these are the steps and the reasons for them. + * + * 1) Add foo to the appropriate list in the configuration system. The + * lists can be found in numpy/core/setup.py lines 63-105. Read the + * comments that come with them, they are very helpful. + * + * 2) The configuration system will define a macro HAVE_FOO if your function + * can be linked from the math library. The result can depend on the + * optimization flags as well as the compiler, so can't be known ahead of + * time. If the function can't be linked, then either it is absent, defined + * as a macro, or is an intrinsic (hardware) function. + * + * i) Undefine any possible macros: + * + * #ifdef foo + * #undef foo + * #endif + * + * ii) Avoid as much as possible to declare any function here. Declaring + * functions is not portable: some platforms define some function inline + * with a non standard identifier, for example, or may put another + * identifier which changes the calling convention of the function. If you + * really have to, ALWAYS declare it for the one platform you are dealing + * with: + * + * Not ok: + * double exp(double a); + * + * Ok: + * #ifdef SYMBOL_DEFINED_WEIRD_PLATFORM + * double exp(double); + * #endif + * + * Some of the code is taken from msun library in FreeBSD, with the following + * notice: + * + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +#include "npy_math_private.h" + +/* + ***************************************************************************** + ** BASIC MATH FUNCTIONS ** + ***************************************************************************** + */ + +/* Original code by Konrad Hinsen. */ +#ifndef HAVE_EXPM1 +NPY_INPLACE double npy_expm1(double x) +{ + if (npy_isinf(x) && x > 0) { + return x; + } + else { + const double u = npy_exp(x); + + if (u == 1.0) { + return x; + } else if (u - 1.0 == -1.0) { + return -1; + } else { + return (u - 1.0) * x/npy_log(u); + } + } +} +#endif + +#ifndef HAVE_LOG1P +NPY_INPLACE double npy_log1p(double x) +{ + if (npy_isinf(x) && x > 0) { + return x; + } + else { + const double u = 1. + x; + const double d = u - 1.; + + if (d == 0) { + return x; + } else { + return npy_log(u) * x / d; + } + } +} +#endif + +/* Taken from FreeBSD mlib, adapted for numpy + * + * XXX: we could be a bit faster by reusing high/low words for inf/nan + * classification instead of calling npy_isinf/npy_isnan: we should have some + * macros for this, though, instead of doing it manually + */ +#ifndef HAVE_ATAN2 +/* XXX: we should have this in npy_math.h */ +#define NPY_DBL_EPSILON 1.2246467991473531772E-16 +NPY_INPLACE double npy_atan2(double y, double x) +{ + npy_int32 k, m, iy, ix, hx, hy; + npy_uint32 lx,ly; + double z; + + EXTRACT_WORDS(hx, lx, x); + ix = hx & 0x7fffffff; + EXTRACT_WORDS(hy, ly, y); + iy = hy & 0x7fffffff; + + /* if x or y is nan, return nan */ + if (npy_isnan(x * y)) { + return x + y; + } + + if (x == 1.0) { + return npy_atan(y); + } + + m = 2 * (npy_signbit((x)) != 0) + (npy_signbit((y)) != 0); + if (y == 0.0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return NPY_PI;/* atan(+0,-anything) = pi */ + case 3: return -NPY_PI;/* atan(-0,-anything) =-pi */ + } + } + + if (x == 0.0) { + return y > 0 ? NPY_PI_2 : -NPY_PI_2; + } + + if (npy_isinf(x)) { + if (npy_isinf(y)) { + switch(m) { + case 0: return NPY_PI_4;/* atan(+INF,+INF) */ + case 1: return -NPY_PI_4;/* atan(-INF,+INF) */ + case 2: return 3.0*NPY_PI_4;/*atan(+INF,-INF)*/ + case 3: return -3.0*NPY_PI_4;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return NPY_PZERO; /* atan(+...,+INF) */ + case 1: return NPY_NZERO; /* atan(-...,+INF) */ + case 2: return NPY_PI; /* atan(+...,-INF) */ + case 3: return -NPY_PI; /* atan(-...,-INF) */ + } + } + } + + if (npy_isinf(y)) { + return y > 0 ? NPY_PI_2 : -NPY_PI_2; + } + + /* compute y/x */ + k = (iy - ix) >> 20; + if (k > 60) { /* |y/x| > 2**60 */ + z = NPY_PI_2 + 0.5 * NPY_DBL_EPSILON; + m &= 1; + } else if (hx < 0 && k < -60) { + z = 0.0; /* 0 > |y|/x > -2**-60 */ + } else { + z = npy_atan(npy_fabs(y/x)); /* safe to do y/x */ + } + + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return NPY_PI - (z - NPY_DBL_EPSILON);/* atan(+,-) */ + default: /* case 3 */ + return (z - NPY_DBL_EPSILON) - NPY_PI;/* atan(-,-) */ + } +} + +#endif + +#ifndef HAVE_HYPOT +NPY_INPLACE double npy_hypot(double x, double y) +{ + double yx; + + if (npy_isinf(x) || npy_isinf(y)) { + return NPY_INFINITY; + } + + if (npy_isnan(x) || npy_isnan(y)) { + return NPY_NAN; + } + + x = npy_fabs(x); + y = npy_fabs(y); + if (x < y) { + double temp = x; + x = y; + y = temp; + } + if (x == 0.) { + return 0.; + } + else { + yx = y/x; + return x*npy_sqrt(1.+yx*yx); + } +} +#endif + +#ifndef HAVE_ACOSH +NPY_INPLACE double npy_acosh(double x) +{ + if (x < 1.0) { + return NPY_NAN; + } + + if (npy_isfinite(x)) { + if (x > 1e8) { + return npy_log(x) + NPY_LOGE2; + } + else { + double u = x - 1.0; + return npy_log1p(u + npy_sqrt(2*u + u*u)); + } + } + return x; +} +#endif + +#ifndef HAVE_ASINH +NPY_INPLACE double npy_asinh(double xx) +{ + double x, d; + int sign; + if (xx < 0.0) { + sign = -1; + x = -xx; + } + else { + sign = 1; + x = xx; + } + if (x > 1e8) { + d = x; + } else { + d = npy_sqrt(x*x + 1); + } + return sign*npy_log1p(x*(1.0 + x/(d+1))); +} +#endif + +#ifndef HAVE_ATANH +NPY_INPLACE double npy_atanh(double x) +{ + if (x > 0) { + return -0.5*npy_log1p(-2.0*x/(1.0 + x)); + } + else { + return 0.5*npy_log1p(2.0*x/(1.0 - x)); + } +} +#endif + +#ifndef HAVE_RINT +#if defined(_MSC_VER) && (_MSC_VER == 1500) && !defined(_WIN64) +#pragma optimize("", off) +#endif +NPY_INPLACE double npy_rint(double x) +{ + double y, r; + + y = npy_floor(x); + r = x - y; + + if (r > 0.5) { + y += 1.0; + } + + /* Round to nearest even */ + if (r == 0.5) { + r = y - 2.0*npy_floor(0.5*y); + if (r == 1.0) { + y += 1.0; + } + } + return y; +} +#if defined(_MSC_VER) && (_MSC_VER == 1500) && !defined(_WIN64) +#pragma optimize("", on) +#endif +#endif + +#ifndef HAVE_TRUNC +NPY_INPLACE double npy_trunc(double x) +{ + return x < 0 ? npy_ceil(x) : npy_floor(x); +} +#endif + +#ifndef HAVE_EXP2 +NPY_INPLACE double npy_exp2(double x) +{ + return npy_exp(NPY_LOGE2*x); +} +#endif + +#ifndef HAVE_LOG2 +NPY_INPLACE double npy_log2(double x) +{ +#ifdef HAVE_FREXP + if (!npy_isfinite(x) || x <= 0.) { + /* special value result */ + return npy_log(x); + } + else { + /* + * fallback implementation copied from python3.4 math.log2 + * provides int(log(2**i)) == i for i 1-64 in default rounding mode. + * + * We want log2(m * 2**e) == log(m) / log(2) + e. Care is needed when + * x is just greater than 1.0: in that case e is 1, log(m) is negative, + * and we get significant cancellation error from the addition of + * log(m) / log(2) to e. The slight rewrite of the expression below + * avoids this problem. + */ + int e; + double m = frexp(x, &e); + if (x >= 1.0) { + return log(2.0 * m) / log(2.0) + (e - 1); + } + else { + return log(m) / log(2.0) + e; + } + } +#else + /* does not provide int(log(2**i)) == i */ + return NPY_LOG2E * npy_log(x); +#endif +} +#endif + +/* + * if C99 extensions not available then define dummy functions that use the + * double versions for + * + * sin, cos, tan + * sinh, cosh, tanh, + * fabs, floor, ceil, rint, trunc + * sqrt, log10, log, exp, expm1 + * asin, acos, atan, + * asinh, acosh, atanh + * + * hypot, atan2, pow, fmod, modf + * ldexp, frexp + * + * We assume the above are always available in their double versions. + * + * NOTE: some facilities may be available as macro only instead of functions. + * For simplicity, we define our own functions and undef the macros. We could + * instead test for the macro, but I am lazy to do that for now. + */ + +/**begin repeat + * #type = npy_longdouble, npy_float# + * #TYPE = NPY_LONGDOUBLE, FLOAT# + * #c = l,f# + * #C = L,F# + */ + +/**begin repeat1 + * #kind = sin,cos,tan,sinh,cosh,tanh,fabs,floor,ceil,rint,trunc,sqrt,log10, + * log,exp,expm1,asin,acos,atan,asinh,acosh,atanh,log1p,exp2,log2# + * #KIND = SIN,COS,TAN,SINH,COSH,TANH,FABS,FLOOR,CEIL,RINT,TRUNC,SQRT,LOG10, + * LOG,EXP,EXPM1,ASIN,ACOS,ATAN,ASINH,ACOSH,ATANH,LOG1P,EXP2,LOG2# + */ + +#ifdef @kind@@c@ +#undef @kind@@c@ +#endif +#ifndef HAVE_@KIND@@C@ +NPY_INPLACE @type@ npy_@kind@@c@(@type@ x) +{ + return (@type@) npy_@kind@((double)x); +} +#endif + +/**end repeat1**/ + +/**begin repeat1 + * #kind = atan2,hypot,pow,fmod,copysign# + * #KIND = ATAN2,HYPOT,POW,FMOD,COPYSIGN# + */ +#ifdef @kind@@c@ +#undef @kind@@c@ +#endif +#ifndef HAVE_@KIND@@C@ +NPY_INPLACE @type@ npy_@kind@@c@(@type@ x, @type@ y) +{ + return (@type@) npy_@kind@((double)x, (double) y); +} +#endif +/**end repeat1**/ + +#ifdef modf@c@ +#undef modf@c@ +#endif +#ifndef HAVE_MODF@C@ +NPY_INPLACE @type@ npy_modf@c@(@type@ x, @type@ *iptr) +{ + double niptr; + double y = npy_modf((double)x, &niptr); + *iptr = (@type@) niptr; + return (@type@) y; +} +#endif + +#ifdef ldexp@c@ +#undef ldexp@c@ +#endif +#ifndef HAVE_LDEXP@C@ +NPY_INPLACE @type@ npy_ldexp@c@(@type@ x, int exp) +{ + return (@type@) npy_ldexp((double)x, exp); +} +#endif + +#ifdef frexp@c@ +#undef frexp@c@ +#endif +#ifndef HAVE_FREXP@C@ +NPY_INPLACE @type@ npy_frexp@c@(@type@ x, int* exp) +{ + return (@type@) npy_frexp(x, exp); +} +#endif + +/**end repeat**/ + + +/* + * Decorate all the math functions which are available on the current platform + */ + +/**begin repeat + * #type = npy_longdouble, npy_double, npy_float# + * #c = l,,f# + * #C = L,,F# + */ +/**begin repeat1 + * #kind = sin,cos,tan,sinh,cosh,tanh,fabs,floor,ceil,rint,trunc,sqrt,log10, + * log,exp,expm1,asin,acos,atan,asinh,acosh,atanh,log1p,exp2,log2# + * #KIND = SIN,COS,TAN,SINH,COSH,TANH,FABS,FLOOR,CEIL,RINT,TRUNC,SQRT,LOG10, + * LOG,EXP,EXPM1,ASIN,ACOS,ATAN,ASINH,ACOSH,ATANH,LOG1P,EXP2,LOG2# + */ +#ifdef HAVE_@KIND@@C@ +NPY_INPLACE @type@ npy_@kind@@c@(@type@ x) +{ + return @kind@@c@(x); +} +#endif + +/**end repeat1**/ + +/**begin repeat1 + * #kind = atan2,hypot,pow,fmod,copysign# + * #KIND = ATAN2,HYPOT,POW,FMOD,COPYSIGN# + */ +#ifdef HAVE_@KIND@@C@ +NPY_INPLACE @type@ npy_@kind@@c@(@type@ x, @type@ y) +{ + return @kind@@c@(x, y); +} +#endif +/**end repeat1**/ + +#ifdef HAVE_MODF@C@ +NPY_INPLACE @type@ npy_modf@c@(@type@ x, @type@ *iptr) +{ + return modf@c@(x, iptr); +} +#endif + +#ifdef HAVE_LDEXP@C@ +NPY_INPLACE @type@ npy_ldexp@c@(@type@ x, int exp) +{ + return ldexp@c@(x, exp); +} +#endif + +#ifdef HAVE_FREXP@C@ +NPY_INPLACE @type@ npy_frexp@c@(@type@ x, int* exp) +{ + return frexp@c@(x, exp); +} +#endif + +/* C99 but not mandatory */ + +#ifndef HAVE_CBRT@C@ +NPY_INPLACE @type@ npy_cbrt@c@(@type@ x) +{ + /* don't set invalid flag */ + if (npy_isnan(x)) { + return NPY_NAN; + } + else if (x < 0) { + return -npy_pow@c@(-x, 1. / 3.); + } + else { + return npy_pow@c@(x, 1. / 3.); + } +} +#else +NPY_INPLACE @type@ npy_cbrt@c@(@type@ x) +{ + return cbrt@c@(x); +} +#endif + +/**end repeat**/ + + +/* + * Non standard functions + */ + +/**begin repeat + * #type = npy_float, npy_double, npy_longdouble# + * #c = f, ,l# + * #C = F, ,L# + */ + +@type@ npy_heaviside@c@(@type@ x, @type@ h0) +{ + if (npy_isnan(x)) { + return (@type@) NPY_NAN; + } + else if (x == 0) { + return h0; + } + else if (x < 0) { + return (@type@) 0.0; + } + else { + return (@type@) 1.0; + } +} + +#define LOGE2 NPY_LOGE2@c@ +#define LOG2E NPY_LOG2E@c@ +#define RAD2DEG (180.0@c@/NPY_PI@c@) +#define DEG2RAD (NPY_PI@c@/180.0@c@) + +NPY_INPLACE @type@ npy_rad2deg@c@(@type@ x) +{ + return x*RAD2DEG; +} + +NPY_INPLACE @type@ npy_deg2rad@c@(@type@ x) +{ + return x*DEG2RAD; +} + +NPY_INPLACE @type@ npy_log2_1p@c@(@type@ x) +{ + return LOG2E*npy_log1p@c@(x); +} + +NPY_INPLACE @type@ npy_exp2_m1@c@(@type@ x) +{ + return npy_expm1@c@(LOGE2*x); +} + +NPY_INPLACE @type@ npy_logaddexp@c@(@type@ x, @type@ y) +{ + if (x == y) { + /* Handles infinities of the same sign without warnings */ + return x + LOGE2; + } + else { + const @type@ tmp = x - y; + if (tmp > 0) { + return x + npy_log1p@c@(npy_exp@c@(-tmp)); + } + else if (tmp <= 0) { + return y + npy_log1p@c@(npy_exp@c@(tmp)); + } + else { + /* NaNs */ + return tmp; + } + } +} + +NPY_INPLACE @type@ npy_logaddexp2@c@(@type@ x, @type@ y) +{ + if (x == y) { + /* Handles infinities of the same sign without warnings */ + return x + 1; + } + else { + const @type@ tmp = x - y; + if (tmp > 0) { + return x + npy_log2_1p@c@(npy_exp2@c@(-tmp)); + } + else if (tmp <= 0) { + return y + npy_log2_1p@c@(npy_exp2@c@(tmp)); + } + else { + /* NaNs */ + return tmp; + } + } +} + +/* + * Python version of divmod. + * + * The implementation is mostly copied from cpython 3.5. + */ +NPY_INPLACE @type@ +npy_divmod@c@(@type@ a, @type@ b, @type@ *modulus) +{ + @type@ div, mod, floordiv; + + mod = npy_fmod@c@(a, b); + + if (!b) { + /* If b == 0, return result of fmod. For IEEE is nan */ + *modulus = mod; + return mod; + } + + /* a - mod should be very nearly an integer multiple of b */ + div = (a - mod) / b; + + /* adjust fmod result to conform to Python convention of remainder */ + if (mod) { + if ((b < 0) != (mod < 0)) { + mod += b; + div -= 1.0@c@; + } + } + else { + /* if mod is zero ensure correct sign */ + mod = (b > 0) ? 0.0@c@ : -0.0@c@; + } + + /* snap quotient to nearest integral value */ + if (div) { + floordiv = npy_floor@c@(div); + if (div - floordiv > 0.5@c@) + floordiv += 1.0@c@; + } + else { + /* if div is zero ensure correct sign */ + floordiv = (a / b > 0) ? 0.0@c@ : -0.0@c@; + } + + *modulus = mod; + return floordiv; +} + +#undef LOGE2 +#undef LOG2E +#undef RAD2DEG +#undef DEG2RAD + +/**end repeat**/ diff --git a/numpy/core/src/npymath/npy_math_private.h b/numpy/core/src/npymath/npy_math_private.h new file mode 100644 index 0000000..d75b9e9 --- /dev/null +++ b/numpy/core/src/npymath/npy_math_private.h @@ -0,0 +1,544 @@ +/* + * + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD$ + */ + +#ifndef _NPY_MATH_PRIVATE_H_ +#define _NPY_MATH_PRIVATE_H_ + +#include +#include + +#include "npy_config.h" +#include "npy_fpmath.h" + +#include "numpy/npy_math.h" +#include "numpy/npy_cpu.h" +#include "numpy/npy_endian.h" +#include "numpy/npy_common.h" + +/* + * The original fdlibm code used statements like: + * n0 = ((*(int*)&one)>>29)^1; * index of high word * + * ix0 = *(n0+(int*)&x); * high word of x * + * ix1 = *((1-n0)+(int*)&x); * low word of x * + * to dig two 32 bit words out of the 64 bit IEEE floating point + * value. That is non-ANSI, and, moreover, the gcc instruction + * scheduler gets it wrong. We instead use the following macros. + * Unlike the original code, we determine the endianness at compile + * time, not at run time; I don't see much benefit to selecting + * endianness at run time. + */ + +/* + * A union which permits us to convert between a double and two 32 bit + * ints. + */ + +/* XXX: not really, but we already make this assumption elsewhere. Will have to + * fix this at some point */ +#define IEEE_WORD_ORDER NPY_BYTE_ORDER + +#if IEEE_WORD_ORDER == NPY_BIG_ENDIAN + +typedef union +{ + double value; + struct + { + npy_uint32 msw; + npy_uint32 lsw; + } parts; +} ieee_double_shape_type; + +#endif + +#if IEEE_WORD_ORDER == NPY_LITTLE_ENDIAN + +typedef union +{ + double value; + struct + { + npy_uint32 lsw; + npy_uint32 msw; + } parts; +} ieee_double_shape_type; + +#endif + +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(ix0,ix1,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ + +#define GET_HIGH_WORD(i,d) \ +do { \ + ieee_double_shape_type gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ + +#define GET_LOW_WORD(i,d) \ +do { \ + ieee_double_shape_type gl_u; \ + gl_u.value = (d); \ + (i) = gl_u.parts.lsw; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ + +#define SET_HIGH_WORD(d,v) \ +do { \ + ieee_double_shape_type sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ + +#define SET_LOW_WORD(d,v) \ +do { \ + ieee_double_shape_type sl_u; \ + sl_u.value = (d); \ + sl_u.parts.lsw = (v); \ + (d) = sl_u.value; \ +} while (0) + +/* Set a double from two 32 bit ints. */ + +#define INSERT_WORDS(d,ix0,ix1) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ +} while (0) + +/* + * A union which permits us to convert between a float and a 32 bit + * int. + */ + +typedef union +{ + float value; + /* FIXME: Assumes 32 bit int. */ + npy_uint32 word; +} ieee_float_shape_type; + +/* Get a 32 bit int from a float. */ + +#define GET_FLOAT_WORD(i,d) \ +do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ +} while (0) + +/* Set a float from a 32 bit int. */ + +#define SET_FLOAT_WORD(d,i) \ +do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ +} while (0) + +#ifdef NPY_USE_C99_COMPLEX +#include +#endif + +/* + * Long double support + */ +#if defined(HAVE_LDOUBLE_INTEL_EXTENDED_12_BYTES_LE) + /* + * Intel extended 80 bits precision. Bit representation is + * | junk | s |eeeeeeeeeeeeeee|mmmmmmmm................mmmmmmm| + * | 16 bits| 1 bit | 15 bits | 64 bits | + * | a[2] | a[1] | a[0] | + * + * 16 stronger bits of a[2] are junk + */ + typedef npy_uint32 IEEEl2bitsrep_part; + + + union IEEEl2bitsrep { + npy_longdouble e; + IEEEl2bitsrep_part a[3]; + }; + + #define LDBL_MANL_INDEX 0 + #define LDBL_MANL_MASK 0xFFFFFFFF + #define LDBL_MANL_SHIFT 0 + + #define LDBL_MANH_INDEX 1 + #define LDBL_MANH_MASK 0xFFFFFFFF + #define LDBL_MANH_SHIFT 0 + + #define LDBL_EXP_INDEX 2 + #define LDBL_EXP_MASK 0x7FFF + #define LDBL_EXP_SHIFT 0 + + #define LDBL_SIGN_INDEX 2 + #define LDBL_SIGN_MASK 0x8000 + #define LDBL_SIGN_SHIFT 15 + + #define LDBL_NBIT 0x80000000 + + typedef npy_uint32 ldouble_man_t; + typedef npy_uint32 ldouble_exp_t; + typedef npy_uint32 ldouble_sign_t; +#elif defined(HAVE_LDOUBLE_INTEL_EXTENDED_16_BYTES_LE) + /* + * Intel extended 80 bits precision, 16 bytes alignment.. Bit representation is + * | junk | s |eeeeeeeeeeeeeee|mmmmmmmm................mmmmmmm| + * | 16 bits| 1 bit | 15 bits | 64 bits | + * | a[2] | a[1] | a[0] | + * + * a[3] and 16 stronger bits of a[2] are junk + */ + typedef npy_uint32 IEEEl2bitsrep_part; + + union IEEEl2bitsrep { + npy_longdouble e; + IEEEl2bitsrep_part a[4]; + }; + + #define LDBL_MANL_INDEX 0 + #define LDBL_MANL_MASK 0xFFFFFFFF + #define LDBL_MANL_SHIFT 0 + + #define LDBL_MANH_INDEX 1 + #define LDBL_MANH_MASK 0xFFFFFFFF + #define LDBL_MANH_SHIFT 0 + + #define LDBL_EXP_INDEX 2 + #define LDBL_EXP_MASK 0x7FFF + #define LDBL_EXP_SHIFT 0 + + #define LDBL_SIGN_INDEX 2 + #define LDBL_SIGN_MASK 0x8000 + #define LDBL_SIGN_SHIFT 15 + + #define LDBL_NBIT 0x800000000 + + typedef npy_uint32 ldouble_man_t; + typedef npy_uint32 ldouble_exp_t; + typedef npy_uint32 ldouble_sign_t; +#elif defined(HAVE_LDOUBLE_MOTOROLA_EXTENDED_12_BYTES_BE) + /* + * Motorola extended 80 bits precision. Bit representation is + * | s |eeeeeeeeeeeeeee| junk |mmmmmmmm................mmmmmmm| + * | 1 bit | 15 bits | 16 bits| 64 bits | + * | a[0] | a[1] | a[2] | + * + * 16 low bits of a[0] are junk + */ + typedef npy_uint32 IEEEl2bitsrep_part; + + + union IEEEl2bitsrep { + npy_longdouble e; + IEEEl2bitsrep_part a[3]; + }; + + #define LDBL_MANL_INDEX 2 + #define LDBL_MANL_MASK 0xFFFFFFFF + #define LDBL_MANL_SHIFT 0 + + #define LDBL_MANH_INDEX 1 + #define LDBL_MANH_MASK 0xFFFFFFFF + #define LDBL_MANH_SHIFT 0 + + #define LDBL_EXP_INDEX 0 + #define LDBL_EXP_MASK 0x7FFF0000 + #define LDBL_EXP_SHIFT 16 + + #define LDBL_SIGN_INDEX 0 + #define LDBL_SIGN_MASK 0x80000000 + #define LDBL_SIGN_SHIFT 31 + + #define LDBL_NBIT 0x80000000 + + typedef npy_uint32 ldouble_man_t; + typedef npy_uint32 ldouble_exp_t; + typedef npy_uint32 ldouble_sign_t; +#elif defined(HAVE_LDOUBLE_IEEE_DOUBLE_16_BYTES_BE) || \ + defined(HAVE_LDOUBLE_IEEE_DOUBLE_BE) + /* 64 bits IEEE double precision aligned on 16 bytes: used by ppc arch on + * Mac OS X */ + + /* + * IEEE double precision. Bit representation is + * | s |eeeeeeeeeee|mmmmmmmm................mmmmmmm| + * |1 bit| 11 bits | 52 bits | + * | a[0] | a[1] | + */ + typedef npy_uint32 IEEEl2bitsrep_part; + + union IEEEl2bitsrep { + npy_longdouble e; + IEEEl2bitsrep_part a[2]; + }; + + #define LDBL_MANL_INDEX 1 + #define LDBL_MANL_MASK 0xFFFFFFFF + #define LDBL_MANL_SHIFT 0 + + #define LDBL_MANH_INDEX 0 + #define LDBL_MANH_MASK 0x000FFFFF + #define LDBL_MANH_SHIFT 0 + + #define LDBL_EXP_INDEX 0 + #define LDBL_EXP_MASK 0x7FF00000 + #define LDBL_EXP_SHIFT 20 + + #define LDBL_SIGN_INDEX 0 + #define LDBL_SIGN_MASK 0x80000000 + #define LDBL_SIGN_SHIFT 31 + + #define LDBL_NBIT 0 + + typedef npy_uint32 ldouble_man_t; + typedef npy_uint32 ldouble_exp_t; + typedef npy_uint32 ldouble_sign_t; +#elif defined(HAVE_LDOUBLE_IEEE_DOUBLE_LE) + /* 64 bits IEEE double precision, Little Endian. */ + + /* + * IEEE double precision. Bit representation is + * | s |eeeeeeeeeee|mmmmmmmm................mmmmmmm| + * |1 bit| 11 bits | 52 bits | + * | a[1] | a[0] | + */ + typedef npy_uint32 IEEEl2bitsrep_part; + + union IEEEl2bitsrep { + npy_longdouble e; + IEEEl2bitsrep_part a[2]; + }; + + #define LDBL_MANL_INDEX 0 + #define LDBL_MANL_MASK 0xFFFFFFFF + #define LDBL_MANL_SHIFT 0 + + #define LDBL_MANH_INDEX 1 + #define LDBL_MANH_MASK 0x000FFFFF + #define LDBL_MANH_SHIFT 0 + + #define LDBL_EXP_INDEX 1 + #define LDBL_EXP_MASK 0x7FF00000 + #define LDBL_EXP_SHIFT 20 + + #define LDBL_SIGN_INDEX 1 + #define LDBL_SIGN_MASK 0x80000000 + #define LDBL_SIGN_SHIFT 31 + + #define LDBL_NBIT 0x00000080 + + typedef npy_uint32 ldouble_man_t; + typedef npy_uint32 ldouble_exp_t; + typedef npy_uint32 ldouble_sign_t; +#elif defined(HAVE_LDOUBLE_IEEE_QUAD_BE) + /* + * IEEE quad precision, Big Endian. Bit representation is + * | s |eeeeeeeeeee|mmmmmmmm................mmmmmmm| + * |1 bit| 15 bits | 112 bits | + * | a[0] | a[1] | + */ + typedef npy_uint64 IEEEl2bitsrep_part; + + union IEEEl2bitsrep { + npy_longdouble e; + IEEEl2bitsrep_part a[2]; + }; + + #define LDBL_MANL_INDEX 1 + #define LDBL_MANL_MASK 0xFFFFFFFFFFFFFFFF + #define LDBL_MANL_SHIFT 0 + + #define LDBL_MANH_INDEX 0 + #define LDBL_MANH_MASK 0x0000FFFFFFFFFFFF + #define LDBL_MANH_SHIFT 0 + + #define LDBL_EXP_INDEX 0 + #define LDBL_EXP_MASK 0x7FFF000000000000 + #define LDBL_EXP_SHIFT 48 + + #define LDBL_SIGN_INDEX 0 + #define LDBL_SIGN_MASK 0x8000000000000000 + #define LDBL_SIGN_SHIFT 63 + + #define LDBL_NBIT 0 + + typedef npy_uint64 ldouble_man_t; + typedef npy_uint64 ldouble_exp_t; + typedef npy_uint32 ldouble_sign_t; +#elif defined(HAVE_LDOUBLE_IEEE_QUAD_LE) + /* + * IEEE quad precision, Little Endian. Bit representation is + * | s |eeeeeeeeeee|mmmmmmmm................mmmmmmm| + * |1 bit| 15 bits | 112 bits | + * | a[1] | a[0] | + */ + typedef npy_uint64 IEEEl2bitsrep_part; + + union IEEEl2bitsrep { + npy_longdouble e; + IEEEl2bitsrep_part a[2]; + }; + + #define LDBL_MANL_INDEX 0 + #define LDBL_MANL_MASK 0xFFFFFFFFFFFFFFFF + #define LDBL_MANL_SHIFT 0 + + #define LDBL_MANH_INDEX 1 + #define LDBL_MANH_MASK 0x0000FFFFFFFFFFFF + #define LDBL_MANH_SHIFT 0 + + #define LDBL_EXP_INDEX 1 + #define LDBL_EXP_MASK 0x7FFF000000000000 + #define LDBL_EXP_SHIFT 48 + + #define LDBL_SIGN_INDEX 1 + #define LDBL_SIGN_MASK 0x8000000000000000 + #define LDBL_SIGN_SHIFT 63 + + #define LDBL_NBIT 0 + + typedef npy_uint64 ldouble_man_t; + typedef npy_uint64 ldouble_exp_t; + typedef npy_uint32 ldouble_sign_t; +#endif + +#if !defined(HAVE_LDOUBLE_DOUBLE_DOUBLE_BE) && \ + !defined(HAVE_LDOUBLE_DOUBLE_DOUBLE_LE) +/* Get the sign bit of x. x should be of type IEEEl2bitsrep */ +#define GET_LDOUBLE_SIGN(x) \ + (((x).a[LDBL_SIGN_INDEX] & LDBL_SIGN_MASK) >> LDBL_SIGN_SHIFT) + +/* Set the sign bit of x to v. x should be of type IEEEl2bitsrep */ +#define SET_LDOUBLE_SIGN(x, v) \ + ((x).a[LDBL_SIGN_INDEX] = \ + ((x).a[LDBL_SIGN_INDEX] & ~LDBL_SIGN_MASK) | \ + (((IEEEl2bitsrep_part)(v) << LDBL_SIGN_SHIFT) & LDBL_SIGN_MASK)) + +/* Get the exp bits of x. x should be of type IEEEl2bitsrep */ +#define GET_LDOUBLE_EXP(x) \ + (((x).a[LDBL_EXP_INDEX] & LDBL_EXP_MASK) >> LDBL_EXP_SHIFT) + +/* Set the exp bit of x to v. x should be of type IEEEl2bitsrep */ +#define SET_LDOUBLE_EXP(x, v) \ + ((x).a[LDBL_EXP_INDEX] = \ + ((x).a[LDBL_EXP_INDEX] & ~LDBL_EXP_MASK) | \ + (((IEEEl2bitsrep_part)(v) << LDBL_EXP_SHIFT) & LDBL_EXP_MASK)) + +/* Get the manl bits of x. x should be of type IEEEl2bitsrep */ +#define GET_LDOUBLE_MANL(x) \ + (((x).a[LDBL_MANL_INDEX] & LDBL_MANL_MASK) >> LDBL_MANL_SHIFT) + +/* Set the manl bit of x to v. x should be of type IEEEl2bitsrep */ +#define SET_LDOUBLE_MANL(x, v) \ + ((x).a[LDBL_MANL_INDEX] = \ + ((x).a[LDBL_MANL_INDEX] & ~LDBL_MANL_MASK) | \ + (((IEEEl2bitsrep_part)(v) << LDBL_MANL_SHIFT) & LDBL_MANL_MASK)) + +/* Get the manh bits of x. x should be of type IEEEl2bitsrep */ +#define GET_LDOUBLE_MANH(x) \ + (((x).a[LDBL_MANH_INDEX] & LDBL_MANH_MASK) >> LDBL_MANH_SHIFT) + +/* Set the manh bit of x to v. x should be of type IEEEl2bitsrep */ +#define SET_LDOUBLE_MANH(x, v) \ + ((x).a[LDBL_MANH_INDEX] = \ + ((x).a[LDBL_MANH_INDEX] & ~LDBL_MANH_MASK) | \ + (((IEEEl2bitsrep_part)(v) << LDBL_MANH_SHIFT) & LDBL_MANH_MASK)) + +#endif /* #ifndef HAVE_LDOUBLE_DOUBLE_DOUBLE_BE */ + +/* + * Those unions are used to convert a pointer of npy_cdouble to native C99 + * complex or our own complex type independently on whether C99 complex + * support is available + */ +#ifdef NPY_USE_C99_COMPLEX + +/* + * Microsoft C defines _MSC_VER + * Intel compiler does not use MSVC complex types, but defines _MSC_VER by + * default. + */ +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +typedef union { + npy_cdouble npy_z; + _Dcomplex c99_z; +} __npy_cdouble_to_c99_cast; + +typedef union { + npy_cfloat npy_z; + _Fcomplex c99_z; +} __npy_cfloat_to_c99_cast; + +typedef union { + npy_clongdouble npy_z; + _Lcomplex c99_z; +} __npy_clongdouble_to_c99_cast; +#else /* !_MSC_VER */ +typedef union { + npy_cdouble npy_z; + complex double c99_z; +} __npy_cdouble_to_c99_cast; + +typedef union { + npy_cfloat npy_z; + complex float c99_z; +} __npy_cfloat_to_c99_cast; + +typedef union { + npy_clongdouble npy_z; + complex long double c99_z; +} __npy_clongdouble_to_c99_cast; +#endif /* !_MSC_VER */ + +#else /* !NPY_USE_C99_COMPLEX */ +typedef union { + npy_cdouble npy_z; + npy_cdouble c99_z; +} __npy_cdouble_to_c99_cast; + +typedef union { + npy_cfloat npy_z; + npy_cfloat c99_z; +} __npy_cfloat_to_c99_cast; + +typedef union { + npy_clongdouble npy_z; + npy_clongdouble c99_z; +} __npy_clongdouble_to_c99_cast; +#endif /* !NPY_USE_C99_COMPLEX */ + + +#endif /* !_NPY_MATH_PRIVATE_H_ */ diff --git a/numpy/core/src/npysort/binsearch.c.src b/numpy/core/src/npysort/binsearch.c.src new file mode 100644 index 0000000..a1a0703 --- /dev/null +++ b/numpy/core/src/npysort/binsearch.c.src @@ -0,0 +1,240 @@ +/* -*- c -*- */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "npy_sort.h" +#include "npysort_common.h" +#include "npy_binsearch.h" + +#define NOT_USED NPY_UNUSED(unused) + +/* + ***************************************************************************** + ** NUMERIC SEARCHES ** + ***************************************************************************** + */ + +/**begin repeat + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA# + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, half, float, double, longdouble, + * cfloat, cdouble, clongdouble, datetime, timedelta# + * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat, + * npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta# + */ + +#define @TYPE@_LTE(a, b) (!@TYPE@_LT((b), (a))) + +/**begin repeat1 + * + * #side = left, right# + * #CMP = LT, LTE# + */ + +NPY_VISIBILITY_HIDDEN void +binsearch_@side@_@suff@(const char *arr, const char *key, char *ret, + npy_intp arr_len, npy_intp key_len, + npy_intp arr_str, npy_intp key_str, npy_intp ret_str, + PyArrayObject *NOT_USED) +{ + npy_intp min_idx = 0; + npy_intp max_idx = arr_len; + @type@ last_key_val = *(const @type@ *)key; + + for (; key_len > 0; key_len--, key += key_str, ret += ret_str) { + const @type@ key_val = *(const @type@ *)key; + /* + * Updating only one of the indices based on the previous key + * gives the search a big boost when keys are sorted, but slightly + * slows down things for purely random ones. + */ + if (@TYPE@_LT(last_key_val, key_val)) { + max_idx = arr_len; + } + else { + min_idx = 0; + max_idx = (max_idx < arr_len) ? (max_idx + 1) : arr_len; + } + + last_key_val = key_val; + + while (min_idx < max_idx) { + const npy_intp mid_idx = min_idx + ((max_idx - min_idx) >> 1); + const @type@ mid_val = *(const @type@ *)(arr + mid_idx*arr_str); + if (@TYPE@_@CMP@(mid_val, key_val)) { + min_idx = mid_idx + 1; + } + else { + max_idx = mid_idx; + } + } + *(npy_intp *)ret = min_idx; + } +} + +NPY_VISIBILITY_HIDDEN int +argbinsearch_@side@_@suff@(const char *arr, const char *key, + const char *sort, char *ret, + npy_intp arr_len, npy_intp key_len, + npy_intp arr_str, npy_intp key_str, + npy_intp sort_str, npy_intp ret_str, + PyArrayObject *NOT_USED) +{ + npy_intp min_idx = 0; + npy_intp max_idx = arr_len; + @type@ last_key_val = *(const @type@ *)key; + + for (; key_len > 0; key_len--, key += key_str, ret += ret_str) { + const @type@ key_val = *(const @type@ *)key; + /* + * Updating only one of the indices based on the previous key + * gives the search a big boost when keys are sorted, but slightly + * slows down things for purely random ones. + */ + if (@TYPE@_LT(last_key_val, key_val)) { + max_idx = arr_len; + } + else { + min_idx = 0; + max_idx = (max_idx < arr_len) ? (max_idx + 1) : arr_len; + } + + last_key_val = key_val; + + while (min_idx < max_idx) { + const npy_intp mid_idx = min_idx + ((max_idx - min_idx) >> 1); + const npy_intp sort_idx = *(npy_intp *)(sort + mid_idx*sort_str); + @type@ mid_val; + + if (sort_idx < 0 || sort_idx >= arr_len) { + return -1; + } + + mid_val = *(const @type@ *)(arr + sort_idx*arr_str); + + if (@TYPE@_@CMP@(mid_val, key_val)) { + min_idx = mid_idx + 1; + } + else { + max_idx = mid_idx; + } + } + *(npy_intp *)ret = min_idx; + } + return 0; +} + +/**end repeat1**/ +/**end repeat**/ + +/* + ***************************************************************************** + ** GENERIC SEARCH ** + ***************************************************************************** + */ + + /**begin repeat + * + * #side = left, right# + * #CMP = <, <=# + */ + +NPY_VISIBILITY_HIDDEN void +npy_binsearch_@side@(const char *arr, const char *key, char *ret, + npy_intp arr_len, npy_intp key_len, + npy_intp arr_str, npy_intp key_str, npy_intp ret_str, + PyArrayObject *cmp) +{ + PyArray_CompareFunc *compare = PyArray_DESCR(cmp)->f->compare; + npy_intp min_idx = 0; + npy_intp max_idx = arr_len; + const char *last_key = key; + + for (; key_len > 0; key_len--, key += key_str, ret += ret_str) { + /* + * Updating only one of the indices based on the previous key + * gives the search a big boost when keys are sorted, but slightly + * slows down things for purely random ones. + */ + if (compare(last_key, key, cmp) @CMP@ 0) { + max_idx = arr_len; + } + else { + min_idx = 0; + max_idx = (max_idx < arr_len) ? (max_idx + 1) : arr_len; + } + + last_key = key; + + while (min_idx < max_idx) { + const npy_intp mid_idx = min_idx + ((max_idx - min_idx) >> 1); + const char *arr_ptr = arr + mid_idx*arr_str; + + if (compare(arr_ptr, key, cmp) @CMP@ 0) { + min_idx = mid_idx + 1; + } + else { + max_idx = mid_idx; + } + } + *(npy_intp *)ret = min_idx; + } +} + +NPY_VISIBILITY_HIDDEN int +npy_argbinsearch_@side@(const char *arr, const char *key, + const char *sort, char *ret, + npy_intp arr_len, npy_intp key_len, + npy_intp arr_str, npy_intp key_str, + npy_intp sort_str, npy_intp ret_str, + PyArrayObject *cmp) +{ + PyArray_CompareFunc *compare = PyArray_DESCR(cmp)->f->compare; + npy_intp min_idx = 0; + npy_intp max_idx = arr_len; + const char *last_key = key; + + for (; key_len > 0; key_len--, key += key_str, ret += ret_str) { + /* + * Updating only one of the indices based on the previous key + * gives the search a big boost when keys are sorted, but slightly + * slows down things for purely random ones. + */ + if (compare(last_key, key, cmp) @CMP@ 0) { + max_idx = arr_len; + } + else { + min_idx = 0; + max_idx = (max_idx < arr_len) ? (max_idx + 1) : arr_len; + } + + last_key = key; + + while (min_idx < max_idx) { + const npy_intp mid_idx = min_idx + ((max_idx - min_idx) >> 1); + const npy_intp sort_idx = *(npy_intp *)(sort + mid_idx*sort_str); + const char *arr_ptr; + + if (sort_idx < 0 || sort_idx >= arr_len) { + return -1; + } + + arr_ptr = arr + sort_idx*arr_str; + + if (compare(arr_ptr, key, cmp) @CMP@ 0) { + min_idx = mid_idx + 1; + } + else { + max_idx = mid_idx; + } + } + *(npy_intp *)ret = min_idx; + } + return 0; +} + +/**end repeat**/ diff --git a/numpy/core/src/npysort/heapsort.c.src b/numpy/core/src/npysort/heapsort.c.src new file mode 100644 index 0000000..c2e3b63 --- /dev/null +++ b/numpy/core/src/npysort/heapsort.c.src @@ -0,0 +1,402 @@ +/* -*- c -*- */ + +/* + * The purpose of this module is to add faster sort functions + * that are type-specific. This is done by altering the + * function table for the builtin descriptors. + * + * These sorting functions are copied almost directly from numarray + * with a few modifications (complex comparisons compare the imaginary + * part if the real parts are equal, for example), and the names + * are changed. + * + * The original sorting code is due to Charles R. Harris who wrote + * it for numarray. + */ + +/* + * Quick sort is usually the fastest, but the worst case scenario can + * be slower than the merge and heap sorts. The merge sort requires + * extra memory and so for large arrays may not be useful. + * + * The merge sort is *stable*, meaning that equal components + * are unmoved from their entry versions, so it can be used to + * implement lexigraphic sorting on multiple keys. + * + * The heap sort is included for completeness. + */ + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "npy_sort.h" +#include "npysort_common.h" +#include + +#define NOT_USED NPY_UNUSED(unused) +#define PYA_QS_STACK 100 +#define SMALL_QUICKSORT 15 +#define SMALL_MERGESORT 20 +#define SMALL_STRING 16 + + +/* + ***************************************************************************** + ** NUMERIC SORTS ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA# + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, half, float, double, longdouble, + * cfloat, cdouble, clongdouble, datetime, timedelta# + * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat, + * npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta# + */ + +int +heapsort_@suff@(void *start, npy_intp n, void *NOT_USED) +{ + @type@ tmp, *a; + npy_intp i,j,l; + + /* The array needs to be offset by one for heapsort indexing */ + a = (@type@ *)start - 1; + + for (l = n>>1; l > 0; --l) { + tmp = a[l]; + for (i = l, j = l<<1; j <= n;) { + if (j < n && @TYPE@_LT(a[j], a[j+1])) { + j += 1; + } + if (@TYPE@_LT(tmp, a[j])) { + a[i] = a[j]; + i = j; + j += j; + } + else { + break; + } + } + a[i] = tmp; + } + + for (; n > 1;) { + tmp = a[n]; + a[n] = a[1]; + n -= 1; + for (i = 1, j = 2; j <= n;) { + if (j < n && @TYPE@_LT(a[j], a[j+1])) { + j++; + } + if (@TYPE@_LT(tmp, a[j])) { + a[i] = a[j]; + i = j; + j += j; + } + else { + break; + } + } + a[i] = tmp; + } + + return 0; +} + + +int +aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *NOT_USED) +{ + @type@ *v = vv; + npy_intp *a, i,j,l, tmp; + /* The arrays need to be offset by one for heapsort indexing */ + a = tosort - 1; + + for (l = n>>1; l > 0; --l) { + tmp = a[l]; + for (i = l, j = l<<1; j <= n;) { + if (j < n && @TYPE@_LT(v[a[j]], v[a[j+1]])) { + j += 1; + } + if (@TYPE@_LT(v[tmp], v[a[j]])) { + a[i] = a[j]; + i = j; + j += j; + } + else { + break; + } + } + a[i] = tmp; + } + + for (; n > 1;) { + tmp = a[n]; + a[n] = a[1]; + n -= 1; + for (i = 1, j = 2; j <= n;) { + if (j < n && @TYPE@_LT(v[a[j]], v[a[j+1]])) { + j++; + } + if (@TYPE@_LT(v[tmp], v[a[j]])) { + a[i] = a[j]; + i = j; + j += j; + } + else { + break; + } + } + a[i] = tmp; + } + + return 0; +} + +/**end repeat**/ + + +/* + ***************************************************************************** + ** STRING SORTS ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #TYPE = STRING, UNICODE# + * #suff = string, unicode# + * #type = npy_char, npy_ucs4# + */ + +int +heapsort_@suff@(void *start, npy_intp n, void *varr) +{ + PyArrayObject *arr = varr; + size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@); + @type@ *tmp = malloc(PyArray_ITEMSIZE(arr)); + @type@ *a = (@type@ *)start - len; + npy_intp i, j, l; + + if (tmp == NULL) { + return -NPY_ENOMEM; + } + + for (l = n>>1; l > 0; --l) { + @TYPE@_COPY(tmp, a + l*len, len); + for (i = l, j = l<<1; j <= n;) { + if (j < n && @TYPE@_LT(a + j*len, a + (j+1)*len, len)) + j += 1; + if (@TYPE@_LT(tmp, a + j*len, len)) { + @TYPE@_COPY(a + i*len, a + j*len, len); + i = j; + j += j; + } + else { + break; + } + } + @TYPE@_COPY(a + i*len, tmp, len); + } + + for (; n > 1;) { + @TYPE@_COPY(tmp, a + n*len, len); + @TYPE@_COPY(a + n*len, a + len, len); + n -= 1; + for (i = 1, j = 2; j <= n;) { + if (j < n && @TYPE@_LT(a + j*len, a + (j+1)*len, len)) + j++; + if (@TYPE@_LT(tmp, a + j*len, len)) { + @TYPE@_COPY(a + i*len, a + j*len, len); + i = j; + j += j; + } + else { + break; + } + } + @TYPE@_COPY(a + i*len, tmp, len); + } + + free(tmp); + return 0; +} + + +int +aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *varr) +{ + @type@ *v = vv; + PyArrayObject *arr = varr; + size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@); + npy_intp *a, i,j,l, tmp; + + /* The array needs to be offset by one for heapsort indexing */ + a = tosort - 1; + + for (l = n>>1; l > 0; --l) { + tmp = a[l]; + for (i = l, j = l<<1; j <= n;) { + if (j < n && @TYPE@_LT(v + a[j]*len, v + a[j+1]*len, len)) + j += 1; + if (@TYPE@_LT(v + tmp*len, v + a[j]*len, len)) { + a[i] = a[j]; + i = j; + j += j; + } + else { + break; + } + } + a[i] = tmp; + } + + for (; n > 1;) { + tmp = a[n]; + a[n] = a[1]; + n -= 1; + for (i = 1, j = 2; j <= n;) { + if (j < n && @TYPE@_LT(v + a[j]*len, v + a[j+1]*len, len)) + j++; + if (@TYPE@_LT(v + tmp*len, v + a[j]*len, len)) { + a[i] = a[j]; + i = j; + j += j; + } + else { + break; + } + } + a[i] = tmp; + } + + return 0; +} + +/**end repeat**/ + + +/* + ***************************************************************************** + ** GENERIC SORT ** + ***************************************************************************** + */ + + +int +npy_heapsort(void *start, npy_intp num, void *varr) +{ + PyArrayObject *arr = varr; + npy_intp elsize = PyArray_ITEMSIZE(arr); + PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; + char *tmp = malloc(elsize); + char *a = (char *)start - elsize; + npy_intp i, j, l; + + if (tmp == NULL) { + return -NPY_ENOMEM; + } + + for (l = num >> 1; l > 0; --l) { + GENERIC_COPY(tmp, a + l*elsize, elsize); + for (i = l, j = l << 1; j <= num;) { + if (j < num && cmp(a + j*elsize, a + (j+1)*elsize, arr) < 0) { + ++j; + } + if (cmp(tmp, a + j*elsize, arr) < 0) { + GENERIC_COPY(a + i*elsize, a + j*elsize, elsize); + i = j; + j += j; + } + else { + break; + } + } + GENERIC_COPY(a + i*elsize, tmp, elsize); + } + + for (; num > 1;) { + GENERIC_COPY(tmp, a + num*elsize, elsize); + GENERIC_COPY(a + num*elsize, a + elsize, elsize); + num -= 1; + for (i = 1, j = 2; j <= num;) { + if (j < num && cmp(a + j*elsize, a + (j+1)*elsize, arr) < 0) { + ++j; + } + if (cmp(tmp, a + j*elsize, arr) < 0) { + GENERIC_COPY(a + i*elsize, a + j*elsize, elsize); + i = j; + j += j; + } + else { + break; + } + } + GENERIC_COPY(a + i*elsize, tmp, elsize); + } + + free(tmp); + return 0; +} + + +int +npy_aheapsort(void *vv, npy_intp *tosort, npy_intp n, void *varr) +{ + char *v = vv; + PyArrayObject *arr = varr; + npy_intp elsize = PyArray_ITEMSIZE(arr); + PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; + npy_intp *a, i, j, l, tmp; + + /* The array needs to be offset by one for heapsort indexing */ + a = tosort - 1; + + for (l = n >> 1; l > 0; --l) { + tmp = a[l]; + for (i = l, j = l<<1; j <= n;) { + if (j < n && cmp(v + a[j]*elsize, v + a[j+1]*elsize, arr) < 0) { + ++j; + } + if (cmp(v + tmp*elsize, v + a[j]*elsize, arr) < 0) { + a[i] = a[j]; + i = j; + j += j; + } + else { + break; + } + } + a[i] = tmp; + } + + for (; n > 1;) { + tmp = a[n]; + a[n] = a[1]; + n -= 1; + for (i = 1, j = 2; j <= n;) { + if (j < n && cmp(v + a[j]*elsize, v + a[j+1]*elsize, arr) < 0) { + ++j; + } + if (cmp(v + tmp*elsize, v + a[j]*elsize, arr) < 0) { + a[i] = a[j]; + i = j; + j += j; + } + else { + break; + } + } + a[i] = tmp; + } + + return 0; +} diff --git a/numpy/core/src/npysort/mergesort.c.src b/numpy/core/src/npysort/mergesort.c.src new file mode 100644 index 0000000..6f65961 --- /dev/null +++ b/numpy/core/src/npysort/mergesort.c.src @@ -0,0 +1,511 @@ +/* -*- c -*- */ + +/* + * The purpose of this module is to add faster sort functions + * that are type-specific. This is done by altering the + * function table for the builtin descriptors. + * + * These sorting functions are copied almost directly from numarray + * with a few modifications (complex comparisons compare the imaginary + * part if the real parts are equal, for example), and the names + * are changed. + * + * The original sorting code is due to Charles R. Harris who wrote + * it for numarray. + */ + +/* + * Quick sort is usually the fastest, but the worst case scenario can + * be slower than the merge and heap sorts. The merge sort requires + * extra memory and so for large arrays may not be useful. + * + * The merge sort is *stable*, meaning that equal components + * are unmoved from their entry versions, so it can be used to + * implement lexigraphic sorting on multiple keys. + * + * The heap sort is included for completeness. + */ + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "npy_sort.h" +#include "npysort_common.h" +#include + +#define NOT_USED NPY_UNUSED(unused) +#define PYA_QS_STACK 100 +#define SMALL_QUICKSORT 15 +#define SMALL_MERGESORT 20 +#define SMALL_STRING 16 + + +/* + ***************************************************************************** + ** NUMERIC SORTS ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA# + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, half, float, double, longdouble, + * cfloat, cdouble, clongdouble, datetime, timedelta# + * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat, + * npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta# + */ + +static void +mergesort0_@suff@(@type@ *pl, @type@ *pr, @type@ *pw) +{ + @type@ vp, *pi, *pj, *pk, *pm; + + if (pr - pl > SMALL_MERGESORT) { + /* merge sort */ + pm = pl + ((pr - pl) >> 1); + mergesort0_@suff@(pl, pm, pw); + mergesort0_@suff@(pm, pr, pw); + for (pi = pw, pj = pl; pj < pm;) { + *pi++ = *pj++; + } + pi = pw + (pm - pl); + pj = pw; + pk = pl; + while (pj < pi && pm < pr) { + if (@TYPE@_LT(*pm, *pj)) { + *pk++ = *pm++; + } + else { + *pk++ = *pj++; + } + } + while(pj < pi) { + *pk++ = *pj++; + } + } + else { + /* insertion sort */ + for (pi = pl + 1; pi < pr; ++pi) { + vp = *pi; + pj = pi; + pk = pi - 1; + while (pj > pl && @TYPE@_LT(vp, *pk)) { + *pj-- = *pk--; + } + *pj = vp; + } + } +} + + +int +mergesort_@suff@(void *start, npy_intp num, void *NOT_USED) +{ + @type@ *pl, *pr, *pw; + + pl = start; + pr = pl + num; + pw = malloc((num/2) * sizeof(@type@)); + if (pw == NULL) { + return -NPY_ENOMEM; + } + mergesort0_@suff@(pl, pr, pw); + + free(pw); + return 0; +} + + +static void +amergesort0_@suff@(npy_intp *pl, npy_intp *pr, @type@ *v, npy_intp *pw) +{ + @type@ vp; + npy_intp vi, *pi, *pj, *pk, *pm; + + if (pr - pl > SMALL_MERGESORT) { + /* merge sort */ + pm = pl + ((pr - pl) >> 1); + amergesort0_@suff@(pl, pm, v, pw); + amergesort0_@suff@(pm, pr, v, pw); + for (pi = pw, pj = pl; pj < pm;) { + *pi++ = *pj++; + } + pi = pw + (pm - pl); + pj = pw; + pk = pl; + while (pj < pi && pm < pr) { + if (@TYPE@_LT(v[*pm], v[*pj])) { + *pk++ = *pm++; + } + else { + *pk++ = *pj++; + } + } + while(pj < pi) { + *pk++ = *pj++; + } + } + else { + /* insertion sort */ + for (pi = pl + 1; pi < pr; ++pi) { + vi = *pi; + vp = v[vi]; + pj = pi; + pk = pi - 1; + while (pj > pl && @TYPE@_LT(vp, v[*pk])) { + *pj-- = *pk--; + } + *pj = vi; + } + } +} + + +int +amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *NOT_USED) +{ + npy_intp *pl, *pr, *pw; + + pl = tosort; + pr = pl + num; + pw = malloc((num/2) * sizeof(npy_intp)); + if (pw == NULL) { + return -NPY_ENOMEM; + } + amergesort0_@suff@(pl, pr, v, pw); + free(pw); + + return 0; +} + +/**end repeat**/ + + +/* + ***************************************************************************** + ** STRING SORTS ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #TYPE = STRING, UNICODE# + * #suff = string, unicode# + * #type = npy_char, npy_ucs4# + */ + +static void +mergesort0_@suff@(@type@ *pl, @type@ *pr, @type@ *pw, @type@ *vp, size_t len) +{ + @type@ *pi, *pj, *pk, *pm; + + if ((size_t)(pr - pl) > SMALL_MERGESORT*len) { + /* merge sort */ + pm = pl + (((pr - pl)/len) >> 1)*len; + mergesort0_@suff@(pl, pm, pw, vp, len); + mergesort0_@suff@(pm, pr, pw, vp, len); + @TYPE@_COPY(pw, pl, pm - pl); + pi = pw + (pm - pl); + pj = pw; + pk = pl; + while (pj < pi && pm < pr) { + if (@TYPE@_LT(pm, pj, len)) { + @TYPE@_COPY(pk, pm, len); + pm += len; + pk += len; + } + else { + @TYPE@_COPY(pk, pj, len); + pj += len; + pk += len; + } + } + @TYPE@_COPY(pk, pj, pi - pj); + } + else { + /* insertion sort */ + for (pi = pl + len; pi < pr; pi += len) { + @TYPE@_COPY(vp, pi, len); + pj = pi; + pk = pi - len; + while (pj > pl && @TYPE@_LT(vp, pk, len)) { + @TYPE@_COPY(pj, pk, len); + pj -= len; + pk -= len; + } + @TYPE@_COPY(pj, vp, len); + } + } +} + + +int +mergesort_@suff@(void *start, npy_intp num, void *varr) +{ + PyArrayObject *arr = varr; + size_t elsize = PyArray_ITEMSIZE(arr); + size_t len = elsize / sizeof(@type@); + @type@ *pl, *pr, *pw, *vp; + int err = 0; + + /* Items that have zero size don't make sense to sort */ + if (elsize == 0) { + return 0; + } + + pl = start; + pr = pl + num*len; + pw = malloc((num/2) * elsize); + if (pw == NULL) { + err = -NPY_ENOMEM; + goto fail_0; + } + vp = malloc(elsize); + if (vp == NULL) { + err = -NPY_ENOMEM; + goto fail_1; + } + mergesort0_@suff@(pl, pr, pw, vp, len); + + free(vp); +fail_1: + free(pw); +fail_0: + return err; +} + + +static void +amergesort0_@suff@(npy_intp *pl, npy_intp *pr, @type@ *v, npy_intp *pw, size_t len) +{ + @type@ *vp; + npy_intp vi, *pi, *pj, *pk, *pm; + + if (pr - pl > SMALL_MERGESORT) { + /* merge sort */ + pm = pl + ((pr - pl) >> 1); + amergesort0_@suff@(pl, pm, v, pw, len); + amergesort0_@suff@(pm, pr, v, pw, len); + for (pi = pw, pj = pl; pj < pm;) { + *pi++ = *pj++; + } + pi = pw + (pm - pl); + pj = pw; + pk = pl; + while (pj < pi && pm < pr) { + if (@TYPE@_LT(v + (*pm)*len, v + (*pj)*len, len)) { + *pk++ = *pm++; + } + else { + *pk++ = *pj++; + } + } + while (pj < pi) { + *pk++ = *pj++; + } + } + else { + /* insertion sort */ + for (pi = pl + 1; pi < pr; ++pi) { + vi = *pi; + vp = v + vi*len; + pj = pi; + pk = pi - 1; + while (pj > pl && @TYPE@_LT(vp, v + (*pk)*len, len)) { + *pj-- = *pk--; + } + *pj = vi; + } + } +} + + +int +amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *varr) +{ + PyArrayObject *arr = varr; + size_t elsize = PyArray_ITEMSIZE(arr); + size_t len = elsize / sizeof(@type@); + npy_intp *pl, *pr, *pw; + + /* Items that have zero size don't make sense to sort */ + if (elsize == 0) { + return 0; + } + + pl = tosort; + pr = pl + num; + pw = malloc((num/2) * sizeof(npy_intp)); + if (pw == NULL) { + return -NPY_ENOMEM; + } + amergesort0_@suff@(pl, pr, v, pw, len); + free(pw); + + return 0; +} + +/**end repeat**/ + + +/* + ***************************************************************************** + ** GENERIC SORT ** + ***************************************************************************** + */ + + +static void +npy_mergesort0(char *pl, char *pr, char *pw, char *vp, npy_intp elsize, + PyArray_CompareFunc *cmp, PyArrayObject *arr) +{ + char *pi, *pj, *pk, *pm; + + if (pr - pl > SMALL_MERGESORT*elsize) { + /* merge sort */ + pm = pl + (((pr - pl)/elsize) >> 1)*elsize; + npy_mergesort0(pl, pm, pw, vp, elsize, cmp, arr); + npy_mergesort0(pm, pr, pw, vp, elsize, cmp, arr); + GENERIC_COPY(pw, pl, pm - pl); + pi = pw + (pm - pl); + pj = pw; + pk = pl; + while (pj < pi && pm < pr) { + if (cmp(pm, pj, arr) < 0) { + GENERIC_COPY(pk, pm, elsize); + pm += elsize; + pk += elsize; + } + else { + GENERIC_COPY(pk, pj, elsize); + pj += elsize; + pk += elsize; + } + } + GENERIC_COPY(pk, pj, pi - pj); + } + else { + /* insertion sort */ + for (pi = pl + elsize; pi < pr; pi += elsize) { + GENERIC_COPY(vp, pi, elsize); + pj = pi; + pk = pi - elsize; + while (pj > pl && cmp(vp, pk, arr) < 0) { + GENERIC_COPY(pj, pk, elsize); + pj -= elsize; + pk -= elsize; + } + GENERIC_COPY(pj, vp, elsize); + } + } +} + + +int +npy_mergesort(void *start, npy_intp num, void *varr) +{ + PyArrayObject *arr = varr; + npy_intp elsize = PyArray_ITEMSIZE(arr); + PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; + char *pl = start; + char *pr = pl + num*elsize; + char *pw; + char *vp; + int err = -NPY_ENOMEM; + + /* Items that have zero size don't make sense to sort */ + if (elsize == 0) { + return 0; + } + + pw = malloc((num >> 1) *elsize); + vp = malloc(elsize); + + if (pw != NULL && vp != NULL) { + npy_mergesort0(pl, pr, pw, vp, elsize, cmp, arr); + err = 0; + } + + free(vp); + free(pw); + + return err; +} + + +static void +npy_amergesort0(npy_intp *pl, npy_intp *pr, char *v, npy_intp *pw, + npy_intp elsize, PyArray_CompareFunc *cmp, PyArrayObject *arr) +{ + char *vp; + npy_intp vi, *pi, *pj, *pk, *pm; + + if (pr - pl > SMALL_MERGESORT) { + /* merge sort */ + pm = pl + ((pr - pl) >> 1); + npy_amergesort0(pl, pm, v, pw, elsize, cmp, arr); + npy_amergesort0(pm, pr, v, pw, elsize, cmp, arr); + for (pi = pw, pj = pl; pj < pm;) { + *pi++ = *pj++; + } + pi = pw + (pm - pl); + pj = pw; + pk = pl; + while (pj < pi && pm < pr) { + if (cmp(v + (*pm)*elsize, v + (*pj)*elsize, arr) < 0) { + *pk++ = *pm++; + } + else { + *pk++ = *pj++; + } + } + while (pj < pi) { + *pk++ = *pj++; + } + } + else { + /* insertion sort */ + for (pi = pl + 1; pi < pr; ++pi) { + vi = *pi; + vp = v + vi*elsize; + pj = pi; + pk = pi - 1; + while (pj > pl && cmp(vp, v + (*pk)*elsize, arr) < 0) { + *pj-- = *pk--; + } + *pj = vi; + } + } +} + + +int +npy_amergesort(void *v, npy_intp *tosort, npy_intp num, void *varr) +{ + PyArrayObject *arr = varr; + npy_intp elsize = PyArray_ITEMSIZE(arr); + PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; + npy_intp *pl, *pr, *pw; + + /* Items that have zero size don't make sense to sort */ + if (elsize == 0) { + return 0; + } + + pl = tosort; + pr = pl + num; + pw = malloc((num >> 1) * sizeof(npy_intp)); + if (pw == NULL) { + return -NPY_ENOMEM; + } + npy_amergesort0(pl, pr, v, pw, elsize, cmp, arr); + free(pw); + + return 0; +} diff --git a/numpy/core/src/npysort/npysort_common.h b/numpy/core/src/npysort/npysort_common.h new file mode 100644 index 0000000..a22045b --- /dev/null +++ b/numpy/core/src/npysort/npysort_common.h @@ -0,0 +1,360 @@ +#ifndef __NPY_SORT_COMMON_H__ +#define __NPY_SORT_COMMON_H__ + +#include +#include + +/* + ***************************************************************************** + ** SWAP MACROS ** + ***************************************************************************** + */ + +#define BOOL_SWAP(a,b) {npy_bool tmp = (b); (b)=(a); (a) = tmp;} +#define BYTE_SWAP(a,b) {npy_byte tmp = (b); (b)=(a); (a) = tmp;} +#define UBYTE_SWAP(a,b) {npy_ubyte tmp = (b); (b)=(a); (a) = tmp;} +#define SHORT_SWAP(a,b) {npy_short tmp = (b); (b)=(a); (a) = tmp;} +#define USHORT_SWAP(a,b) {npy_ushort tmp = (b); (b)=(a); (a) = tmp;} +#define INT_SWAP(a,b) {npy_int tmp = (b); (b)=(a); (a) = tmp;} +#define UINT_SWAP(a,b) {npy_uint tmp = (b); (b)=(a); (a) = tmp;} +#define LONG_SWAP(a,b) {npy_long tmp = (b); (b)=(a); (a) = tmp;} +#define ULONG_SWAP(a,b) {npy_ulong tmp = (b); (b)=(a); (a) = tmp;} +#define LONGLONG_SWAP(a,b) {npy_longlong tmp = (b); (b)=(a); (a) = tmp;} +#define ULONGLONG_SWAP(a,b) {npy_ulonglong tmp = (b); (b)=(a); (a) = tmp;} +#define HALF_SWAP(a,b) {npy_half tmp = (b); (b)=(a); (a) = tmp;} +#define FLOAT_SWAP(a,b) {npy_float tmp = (b); (b)=(a); (a) = tmp;} +#define DOUBLE_SWAP(a,b) {npy_double tmp = (b); (b)=(a); (a) = tmp;} +#define LONGDOUBLE_SWAP(a,b) {npy_longdouble tmp = (b); (b)=(a); (a) = tmp;} +#define CFLOAT_SWAP(a,b) {npy_cfloat tmp = (b); (b)=(a); (a) = tmp;} +#define CDOUBLE_SWAP(a,b) {npy_cdouble tmp = (b); (b)=(a); (a) = tmp;} +#define CLONGDOUBLE_SWAP(a,b) {npy_clongdouble tmp = (b); (b)=(a); (a) = tmp;} +#define DATETIME_SWAP(a,b) {npy_datetime tmp = (b); (b)=(a); (a) = tmp;} +#define TIMEDELTA_SWAP(a,b) {npy_timedelta tmp = (b); (b)=(a); (a) = tmp;} + +/* Need this for the argsort functions */ +#define INTP_SWAP(a,b) {npy_intp tmp = (b); (b)=(a); (a) = tmp;} + +/* + ***************************************************************************** + ** COMPARISON FUNCTIONS ** + ***************************************************************************** + */ + +NPY_INLINE static int +BOOL_LT(npy_bool a, npy_bool b) +{ + return a < b; +} + + +NPY_INLINE static int +BYTE_LT(npy_byte a, npy_byte b) +{ + return a < b; +} + + +NPY_INLINE static int +UBYTE_LT(npy_ubyte a, npy_ubyte b) +{ + return a < b; +} + + +NPY_INLINE static int +SHORT_LT(npy_short a, npy_short b) +{ + return a < b; +} + + +NPY_INLINE static int +USHORT_LT(npy_ushort a, npy_ushort b) +{ + return a < b; +} + + +NPY_INLINE static int +INT_LT(npy_int a, npy_int b) +{ + return a < b; +} + + +NPY_INLINE static int +UINT_LT(npy_uint a, npy_uint b) +{ + return a < b; +} + + +NPY_INLINE static int +LONG_LT(npy_long a, npy_long b) +{ + return a < b; +} + + +NPY_INLINE static int +ULONG_LT(npy_ulong a, npy_ulong b) +{ + return a < b; +} + + +NPY_INLINE static int +LONGLONG_LT(npy_longlong a, npy_longlong b) +{ + return a < b; +} + + +NPY_INLINE static int +ULONGLONG_LT(npy_ulonglong a, npy_ulonglong b) +{ + return a < b; +} + + +NPY_INLINE static int +FLOAT_LT(npy_float a, npy_float b) +{ + return a < b || (b != b && a == a); +} + + +NPY_INLINE static int +DOUBLE_LT(npy_double a, npy_double b) +{ + return a < b || (b != b && a == a); +} + + +NPY_INLINE static int +LONGDOUBLE_LT(npy_longdouble a, npy_longdouble b) +{ + return a < b || (b != b && a == a); +} + + +NPY_INLINE static int +npy_half_isnan(npy_half h) +{ + return ((h&0x7c00u) == 0x7c00u) && ((h&0x03ffu) != 0x0000u); +} + + +NPY_INLINE static int +npy_half_lt_nonan(npy_half h1, npy_half h2) +{ + if (h1&0x8000u) { + if (h2&0x8000u) { + return (h1&0x7fffu) > (h2&0x7fffu); + } + else { + /* Signed zeros are equal, have to check for it */ + return (h1 != 0x8000u) || (h2 != 0x0000u); + } + } + else { + if (h2&0x8000u) { + return 0; + } + else { + return (h1&0x7fffu) < (h2&0x7fffu); + } + } +} + + +NPY_INLINE static int +HALF_LT(npy_half a, npy_half b) +{ + int ret; + + if (npy_half_isnan(b)) { + ret = !npy_half_isnan(a); + } + else { + ret = !npy_half_isnan(a) && npy_half_lt_nonan(a, b); + } + + return ret; +} + +/* + * For inline functions SUN recommends not using a return in the then part + * of an if statement. It's a SUN compiler thing, so assign the return value + * to a variable instead. + */ +NPY_INLINE static int +CFLOAT_LT(npy_cfloat a, npy_cfloat b) +{ + int ret; + + if (a.real < b.real) { + ret = a.imag == a.imag || b.imag != b.imag; + } + else if (a.real > b.real) { + ret = b.imag != b.imag && a.imag == a.imag; + } + else if (a.real == b.real || (a.real != a.real && b.real != b.real)) { + ret = a.imag < b.imag || (b.imag != b.imag && a.imag == a.imag); + } + else { + ret = b.real != b.real; + } + + return ret; +} + + +NPY_INLINE static int +CDOUBLE_LT(npy_cdouble a, npy_cdouble b) +{ + int ret; + + if (a.real < b.real) { + ret = a.imag == a.imag || b.imag != b.imag; + } + else if (a.real > b.real) { + ret = b.imag != b.imag && a.imag == a.imag; + } + else if (a.real == b.real || (a.real != a.real && b.real != b.real)) { + ret = a.imag < b.imag || (b.imag != b.imag && a.imag == a.imag); + } + else { + ret = b.real != b.real; + } + + return ret; +} + + +NPY_INLINE static int +CLONGDOUBLE_LT(npy_clongdouble a, npy_clongdouble b) +{ + int ret; + + if (a.real < b.real) { + ret = a.imag == a.imag || b.imag != b.imag; + } + else if (a.real > b.real) { + ret = b.imag != b.imag && a.imag == a.imag; + } + else if (a.real == b.real || (a.real != a.real && b.real != b.real)) { + ret = a.imag < b.imag || (b.imag != b.imag && a.imag == a.imag); + } + else { + ret = b.real != b.real; + } + + return ret; +} + + +NPY_INLINE static void +STRING_COPY(char *s1, char *s2, size_t len) +{ + memcpy(s1, s2, len); +} + + +NPY_INLINE static void +STRING_SWAP(char *s1, char *s2, size_t len) +{ + while(len--) { + const char t = *s1; + *s1++ = *s2; + *s2++ = t; + } +} + + +NPY_INLINE static int +STRING_LT(char *s1, char *s2, size_t len) +{ + const unsigned char *c1 = (unsigned char *)s1; + const unsigned char *c2 = (unsigned char *)s2; + size_t i; + int ret = 0; + + for (i = 0; i < len; ++i) { + if (c1[i] != c2[i]) { + ret = c1[i] < c2[i]; + break; + } + } + return ret; +} + + +NPY_INLINE static void +UNICODE_COPY(npy_ucs4 *s1, npy_ucs4 *s2, size_t len) +{ + while(len--) { + *s1++ = *s2++; + } +} + + +NPY_INLINE static void +UNICODE_SWAP(npy_ucs4 *s1, npy_ucs4 *s2, size_t len) +{ + while(len--) { + const npy_ucs4 t = *s1; + *s1++ = *s2; + *s2++ = t; + } +} + + +NPY_INLINE static int +UNICODE_LT(npy_ucs4 *s1, npy_ucs4 *s2, size_t len) +{ + size_t i; + int ret = 0; + + for (i = 0; i < len; ++i) { + if (s1[i] != s2[i]) { + ret = s1[i] < s2[i]; + break; + } + } + return ret; +} + + +NPY_INLINE static int +DATETIME_LT(npy_datetime a, npy_datetime b) +{ + return a < b; +} + + +NPY_INLINE static int +TIMEDELTA_LT(npy_timedelta a, npy_timedelta b) +{ + return a < b; +} + + +NPY_INLINE static void +GENERIC_COPY(char *a, char *b, size_t len) +{ + memcpy(a, b, len); +} + + +NPY_INLINE static void +GENERIC_SWAP(char *a, char *b, size_t len) +{ + while(len--) { + const char t = *a; + *a++ = *b; + *b++ = t; + } +} + +#endif diff --git a/numpy/core/src/npysort/quicksort.c.src b/numpy/core/src/npysort/quicksort.c.src new file mode 100644 index 0000000..ff0e8a1 --- /dev/null +++ b/numpy/core/src/npysort/quicksort.c.src @@ -0,0 +1,634 @@ +/* -*- c -*- */ + +/* + * The purpose of this module is to add faster sort functions + * that are type-specific. This is done by altering the + * function table for the builtin descriptors. + * + * These sorting functions are copied almost directly from numarray + * with a few modifications (complex comparisons compare the imaginary + * part if the real parts are equal, for example), and the names + * are changed. + * + * The original sorting code is due to Charles R. Harris who wrote + * it for numarray. + */ + +/* + * Quick sort is usually the fastest, but the worst case scenario is O(N^2) so + * the code switches to the O(NlogN) worst case heapsort if not enough progress + * is made on the large side of the two quicksort partitions. This improves the + * worst case while still retaining the speed of quicksort for the common case. + * This is variant known as introsort. + * + * + * def introsort(lower, higher, recursion_limit=log2(higher - lower + 1) * 2): + * # sort remainder with heapsort if we are not making enough progress + * # we arbitrarily choose 2 * log(n) as the cutoff point + * if recursion_limit < 0: + * heapsort(lower, higher) + * return + * + * if lower < higher: + * pivot_pos = partition(lower, higher) + * # recurse into smaller first and leave larger on stack + * # this limits the required stack space + * if (pivot_pos - lower > higher - pivot_pos): + * quicksort(pivot_pos + 1, higher, recursion_limit - 1) + * quicksort(lower, pivot_pos, recursion_limit - 1) + * else: + * quicksort(lower, pivot_pos, recursion_limit - 1) + * quicksort(pivot_pos + 1, higher, recursion_limit - 1) + * + * + * the below code implements this converted to an iteration and as an + * additional minor optimization skips the recursion depth checking on the + * smaller partition as it is always less than half of the remaining data and + * will thus terminate fast enough + */ + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "npy_sort.h" +#include "npysort_common.h" +#include + +#define NOT_USED NPY_UNUSED(unused) +/* + * pushing largest partition has upper bound of log2(n) space + * we store two pointers each time + */ +#define PYA_QS_STACK (NPY_BITSOF_INTP * 2) +#define SMALL_QUICKSORT 15 +#define SMALL_MERGESORT 20 +#define SMALL_STRING 16 + + +/* + ***************************************************************************** + ** NUMERIC SORTS ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA# + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, half, float, double, longdouble, + * cfloat, cdouble, clongdouble, datetime, timedelta# + * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat, + * npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta# + */ + +int +quicksort_@suff@(void *start, npy_intp num, void *NOT_USED) +{ + @type@ vp; + @type@ *pl = start; + @type@ *pr = pl + num - 1; + @type@ *stack[PYA_QS_STACK]; + @type@ **sptr = stack; + @type@ *pm, *pi, *pj, *pk; + int depth[PYA_QS_STACK]; + int * psdepth = depth; + int cdepth = npy_get_msb(num) * 2; + + for (;;) { + if (NPY_UNLIKELY(cdepth < 0)) { + heapsort_@suff@(pl, pr - pl + 1, NULL); + goto stack_pop; + } + while ((pr - pl) > SMALL_QUICKSORT) { + /* quicksort partition */ + pm = pl + ((pr - pl) >> 1); + if (@TYPE@_LT(*pm, *pl)) @TYPE@_SWAP(*pm, *pl); + if (@TYPE@_LT(*pr, *pm)) @TYPE@_SWAP(*pr, *pm); + if (@TYPE@_LT(*pm, *pl)) @TYPE@_SWAP(*pm, *pl); + vp = *pm; + pi = pl; + pj = pr - 1; + @TYPE@_SWAP(*pm, *pj); + for (;;) { + do ++pi; while (@TYPE@_LT(*pi, vp)); + do --pj; while (@TYPE@_LT(vp, *pj)); + if (pi >= pj) { + break; + } + @TYPE@_SWAP(*pi,*pj); + } + pk = pr - 1; + @TYPE@_SWAP(*pi, *pk); + /* push largest partition on stack */ + if (pi - pl < pr - pi) { + *sptr++ = pi + 1; + *sptr++ = pr; + pr = pi - 1; + } + else { + *sptr++ = pl; + *sptr++ = pi - 1; + pl = pi + 1; + } + *psdepth++ = --cdepth; + } + + /* insertion sort */ + for (pi = pl + 1; pi <= pr; ++pi) { + vp = *pi; + pj = pi; + pk = pi - 1; + while (pj > pl && @TYPE@_LT(vp, *pk)) { + *pj-- = *pk--; + } + *pj = vp; + } +stack_pop: + if (sptr == stack) { + break; + } + pr = *(--sptr); + pl = *(--sptr); + cdepth = *(--psdepth); + } + + return 0; +} + + +int +aquicksort_@suff@(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED) +{ + @type@ *v = vv; + @type@ vp; + npy_intp *pl = tosort; + npy_intp *pr = tosort + num - 1; + npy_intp *stack[PYA_QS_STACK]; + npy_intp **sptr = stack; + npy_intp *pm, *pi, *pj, *pk, vi; + int depth[PYA_QS_STACK]; + int * psdepth = depth; + int cdepth = npy_get_msb(num) * 2; + + for (;;) { + if (NPY_UNLIKELY(cdepth < 0)) { + aheapsort_@suff@(vv, pl, pr - pl + 1, NULL); + goto stack_pop; + } + while ((pr - pl) > SMALL_QUICKSORT) { + /* quicksort partition */ + pm = pl + ((pr - pl) >> 1); + if (@TYPE@_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl); + if (@TYPE@_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm); + if (@TYPE@_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl); + vp = v[*pm]; + pi = pl; + pj = pr - 1; + INTP_SWAP(*pm, *pj); + for (;;) { + do ++pi; while (@TYPE@_LT(v[*pi], vp)); + do --pj; while (@TYPE@_LT(vp, v[*pj])); + if (pi >= pj) { + break; + } + INTP_SWAP(*pi, *pj); + } + pk = pr - 1; + INTP_SWAP(*pi,*pk); + /* push largest partition on stack */ + if (pi - pl < pr - pi) { + *sptr++ = pi + 1; + *sptr++ = pr; + pr = pi - 1; + } + else { + *sptr++ = pl; + *sptr++ = pi - 1; + pl = pi + 1; + } + *psdepth++ = --cdepth; + } + + /* insertion sort */ + for (pi = pl + 1; pi <= pr; ++pi) { + vi = *pi; + vp = v[vi]; + pj = pi; + pk = pi - 1; + while (pj > pl && @TYPE@_LT(vp, v[*pk])) { + *pj-- = *pk--; + } + *pj = vi; + } +stack_pop: + if (sptr == stack) { + break; + } + pr = *(--sptr); + pl = *(--sptr); + cdepth = *(--psdepth); + } + + return 0; +} + +/**end repeat**/ + + +/* + ***************************************************************************** + ** STRING SORTS ** + ***************************************************************************** + */ + + +/**begin repeat + * + * #TYPE = STRING, UNICODE# + * #suff = string, unicode# + * #type = npy_char, npy_ucs4# + */ + +int +quicksort_@suff@(void *start, npy_intp num, void *varr) +{ + PyArrayObject *arr = varr; + const size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@); + @type@ *vp; + @type@ *pl = start; + @type@ *pr = pl + (num - 1)*len; + @type@ *stack[PYA_QS_STACK], **sptr = stack, *pm, *pi, *pj, *pk; + int depth[PYA_QS_STACK]; + int * psdepth = depth; + int cdepth = npy_get_msb(num) * 2; + + /* Items that have zero size don't make sense to sort */ + if (len == 0) { + return 0; + } + + vp = malloc(PyArray_ITEMSIZE(arr)); + if (vp == NULL) { + return -NPY_ENOMEM; + } + + for (;;) { + if (NPY_UNLIKELY(cdepth < 0)) { + heapsort_@suff@(pl, (pr - pl) / len + 1, varr); + goto stack_pop; + } + while ((size_t)(pr - pl) > SMALL_QUICKSORT*len) { + /* quicksort partition */ + pm = pl + (((pr - pl)/len) >> 1)*len; + if (@TYPE@_LT(pm, pl, len)) @TYPE@_SWAP(pm, pl, len); + if (@TYPE@_LT(pr, pm, len)) @TYPE@_SWAP(pr, pm, len); + if (@TYPE@_LT(pm, pl, len)) @TYPE@_SWAP(pm, pl, len); + @TYPE@_COPY(vp, pm, len); + pi = pl; + pj = pr - len; + @TYPE@_SWAP(pm, pj, len); + for (;;) { + do pi += len; while (@TYPE@_LT(pi, vp, len)); + do pj -= len; while (@TYPE@_LT(vp, pj, len)); + if (pi >= pj) { + break; + } + @TYPE@_SWAP(pi, pj, len); + } + pk = pr - len; + @TYPE@_SWAP(pi, pk, len); + /* push largest partition on stack */ + if (pi - pl < pr - pi) { + *sptr++ = pi + len; + *sptr++ = pr; + pr = pi - len; + } + else { + *sptr++ = pl; + *sptr++ = pi - len; + pl = pi + len; + } + *psdepth++ = --cdepth; + } + + /* insertion sort */ + for (pi = pl + len; pi <= pr; pi += len) { + @TYPE@_COPY(vp, pi, len); + pj = pi; + pk = pi - len; + while (pj > pl && @TYPE@_LT(vp, pk, len)) { + @TYPE@_COPY(pj, pk, len); + pj -= len; + pk -= len; + } + @TYPE@_COPY(pj, vp, len); + } +stack_pop: + if (sptr == stack) { + break; + } + pr = *(--sptr); + pl = *(--sptr); + cdepth = *(--psdepth); + } + + free(vp); + return 0; +} + + +int +aquicksort_@suff@(void *vv, npy_intp* tosort, npy_intp num, void *varr) +{ + @type@ *v = vv; + PyArrayObject *arr = varr; + size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@); + @type@ *vp; + npy_intp *pl = tosort; + npy_intp *pr = tosort + num - 1; + npy_intp *stack[PYA_QS_STACK]; + npy_intp **sptr=stack; + npy_intp *pm, *pi, *pj, *pk, vi; + int depth[PYA_QS_STACK]; + int * psdepth = depth; + int cdepth = npy_get_msb(num) * 2; + + /* Items that have zero size don't make sense to sort */ + if (len == 0) { + return 0; + } + + for (;;) { + if (NPY_UNLIKELY(cdepth < 0)) { + aheapsort_@suff@(vv, pl, pr - pl + 1, varr); + goto stack_pop; + } + while ((pr - pl) > SMALL_QUICKSORT) { + /* quicksort partition */ + pm = pl + ((pr - pl) >> 1); + if (@TYPE@_LT(v + (*pm)*len, v + (*pl)*len, len)) INTP_SWAP(*pm, *pl); + if (@TYPE@_LT(v + (*pr)*len, v + (*pm)*len, len)) INTP_SWAP(*pr, *pm); + if (@TYPE@_LT(v + (*pm)*len, v + (*pl)*len, len)) INTP_SWAP(*pm, *pl); + vp = v + (*pm)*len; + pi = pl; + pj = pr - 1; + INTP_SWAP(*pm,*pj); + for (;;) { + do ++pi; while (@TYPE@_LT(v + (*pi)*len, vp, len)); + do --pj; while (@TYPE@_LT(vp, v + (*pj)*len, len)); + if (pi >= pj) { + break; + } + INTP_SWAP(*pi,*pj); + } + pk = pr - 1; + INTP_SWAP(*pi,*pk); + /* push largest partition on stack */ + if (pi - pl < pr - pi) { + *sptr++ = pi + 1; + *sptr++ = pr; + pr = pi - 1; + } + else { + *sptr++ = pl; + *sptr++ = pi - 1; + pl = pi + 1; + } + *psdepth++ = --cdepth; + } + + /* insertion sort */ + for (pi = pl + 1; pi <= pr; ++pi) { + vi = *pi; + vp = v + vi*len; + pj = pi; + pk = pi - 1; + while (pj > pl && @TYPE@_LT(vp, v + (*pk)*len, len)) { + *pj-- = *pk--; + } + *pj = vi; + } +stack_pop: + if (sptr == stack) { + break; + } + pr = *(--sptr); + pl = *(--sptr); + cdepth = *(--psdepth); + } + + return 0; +} + +/**end repeat**/ + + +/* + ***************************************************************************** + ** GENERIC SORT ** + ***************************************************************************** + */ + + +int +npy_quicksort(void *start, npy_intp num, void *varr) +{ + PyArrayObject *arr = varr; + npy_intp elsize = PyArray_ITEMSIZE(arr); + PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; + char *vp; + char *pl = start; + char *pr = pl + (num - 1)*elsize; + char *stack[PYA_QS_STACK]; + char **sptr = stack; + char *pm, *pi, *pj, *pk; + int depth[PYA_QS_STACK]; + int * psdepth = depth; + int cdepth = npy_get_msb(num) * 2; + + /* Items that have zero size don't make sense to sort */ + if (elsize == 0) { + return 0; + } + + vp = malloc(elsize); + if (vp == NULL) { + return -NPY_ENOMEM; + } + + for (;;) { + if (NPY_UNLIKELY(cdepth < 0)) { + npy_heapsort(pl, (pr - pl) / elsize + 1, varr); + goto stack_pop; + } + while(pr - pl > SMALL_QUICKSORT*elsize) { + /* quicksort partition */ + pm = pl + (((pr - pl) / elsize) >> 1) * elsize; + if (cmp(pm, pl, arr) < 0) { + GENERIC_SWAP(pm, pl, elsize); + } + if (cmp(pr, pm, arr) < 0) { + GENERIC_SWAP(pr, pm, elsize); + } + if (cmp(pm, pl, arr) < 0) { + GENERIC_SWAP(pm, pl, elsize); + } + GENERIC_COPY(vp, pm, elsize); + pi = pl; + pj = pr - elsize; + GENERIC_SWAP(pm, pj, elsize); + /* + * Generic comparisons may be buggy, so don't rely on the sentinals + * to keep the pointers from going out of bounds. + */ + for (;;) { + do { + pi += elsize; + } while (cmp(pi, vp, arr) < 0 && pi < pj); + do { + pj -= elsize; + } while (cmp(vp, pj, arr) < 0 && pi < pj); + if (pi >= pj) { + break; + } + GENERIC_SWAP(pi, pj, elsize); + } + pk = pr - elsize; + GENERIC_SWAP(pi, pk, elsize); + /* push largest partition on stack */ + if (pi - pl < pr - pi) { + *sptr++ = pi + elsize; + *sptr++ = pr; + pr = pi - elsize; + } + else { + *sptr++ = pl; + *sptr++ = pi - elsize; + pl = pi + elsize; + } + *psdepth++ = --cdepth; + } + + /* insertion sort */ + for (pi = pl + elsize; pi <= pr; pi += elsize) { + GENERIC_COPY(vp, pi, elsize); + pj = pi; + pk = pi - elsize; + while (pj > pl && cmp(vp, pk, arr) < 0) { + GENERIC_COPY(pj, pk, elsize); + pj -= elsize; + pk -= elsize; + } + GENERIC_COPY(pj, vp, elsize); + } +stack_pop: + if (sptr == stack) { + break; + } + pr = *(--sptr); + pl = *(--sptr); + cdepth = *(--psdepth); + } + + free(vp); + return 0; +} + + +int +npy_aquicksort(void *vv, npy_intp* tosort, npy_intp num, void *varr) +{ + char *v = vv; + PyArrayObject *arr = varr; + npy_intp elsize = PyArray_ITEMSIZE(arr); + PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; + char *vp; + npy_intp *pl = tosort; + npy_intp *pr = tosort + num - 1; + npy_intp *stack[PYA_QS_STACK]; + npy_intp **sptr = stack; + npy_intp *pm, *pi, *pj, *pk, vi; + int depth[PYA_QS_STACK]; + int * psdepth = depth; + int cdepth = npy_get_msb(num) * 2; + + /* Items that have zero size don't make sense to sort */ + if (elsize == 0) { + return 0; + } + + for (;;) { + if (NPY_UNLIKELY(cdepth < 0)) { + npy_aheapsort(vv, pl, pr - pl + 1, varr); + goto stack_pop; + } + while ((pr - pl) > SMALL_QUICKSORT) { + /* quicksort partition */ + pm = pl + ((pr - pl) >> 1); + if (cmp(v + (*pm)*elsize, v + (*pl)*elsize, arr) < 0) { + INTP_SWAP(*pm, *pl); + } + if (cmp(v + (*pr)*elsize, v + (*pm)*elsize, arr) < 0) { + INTP_SWAP(*pr, *pm); + } + if (cmp(v + (*pm)*elsize, v + (*pl)*elsize, arr) < 0) { + INTP_SWAP(*pm, *pl); + } + vp = v + (*pm)*elsize; + pi = pl; + pj = pr - 1; + INTP_SWAP(*pm,*pj); + for (;;) { + do { + ++pi; + } while (cmp(v + (*pi)*elsize, vp, arr) < 0 && pi < pj); + do { + --pj; + } while (cmp(vp, v + (*pj)*elsize, arr) < 0 && pi < pj); + if (pi >= pj) { + break; + } + INTP_SWAP(*pi,*pj); + } + pk = pr - 1; + INTP_SWAP(*pi,*pk); + /* push largest partition on stack */ + if (pi - pl < pr - pi) { + *sptr++ = pi + 1; + *sptr++ = pr; + pr = pi - 1; + } + else { + *sptr++ = pl; + *sptr++ = pi - 1; + pl = pi + 1; + } + *psdepth++ = --cdepth; + } + + /* insertion sort */ + for (pi = pl + 1; pi <= pr; ++pi) { + vi = *pi; + vp = v + vi*elsize; + pj = pi; + pk = pi - 1; + while (pj > pl && cmp(vp, v + (*pk)*elsize, arr) < 0) { + *pj-- = *pk--; + } + *pj = vi; + } +stack_pop: + if (sptr == stack) { + break; + } + pr = *(--sptr); + pl = *(--sptr); + cdepth = *(--psdepth); + } + + return 0; +} diff --git a/numpy/core/src/npysort/selection.c.src b/numpy/core/src/npysort/selection.c.src new file mode 100644 index 0000000..1e09345 --- /dev/null +++ b/numpy/core/src/npysort/selection.c.src @@ -0,0 +1,418 @@ +/* -*- c -*- */ + +/* + * + * The code is loosely based on the quickselect from + * Nicolas Devillard - 1998 public domain + * http://ndevilla.free.fr/median/median/ + * + * Quick select with median of 3 pivot is usually the fastest, + * but the worst case scenario can be quadratic complexity, + * e.g. np.roll(np.arange(x), x / 2) + * To avoid this if it recurses too much it falls back to the + * worst case linear median of median of group 5 pivot strategy. + */ + + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "npy_sort.h" +#include "npysort_common.h" +#include "numpy/npy_math.h" +#include "npy_partition.h" +#include + +#define NOT_USED NPY_UNUSED(unused) + + +/* + ***************************************************************************** + ** NUMERIC SORTS ** + ***************************************************************************** + */ + + +static NPY_INLINE void store_pivot(npy_intp pivot, npy_intp kth, + npy_intp * pivots, npy_intp * npiv) +{ + if (pivots == NULL) { + return; + } + + /* + * If pivot is the requested kth store it, overwritting other pivots if + * required. This must be done so iterative partition can work without + * manually shifting lower data offset by kth each time + */ + if (pivot == kth && *npiv == NPY_MAX_PIVOT_STACK) { + pivots[*npiv - 1] = pivot; + } + /* + * we only need pivots larger than current kth, larger pivots are not + * useful as partitions on smaller kth would reorder the stored pivots + */ + else if (pivot >= kth && *npiv < NPY_MAX_PIVOT_STACK) { + pivots[*npiv] = pivot; + (*npiv) += 1; + } +} + +/**begin repeat + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat, + * npy_cdouble, npy_clongdouble# + * #inexact = 0*11, 1*7# + */ + +static npy_intp +amedian_of_median5_@suff@(@type@ *v, npy_intp* tosort, const npy_intp num, + npy_intp * pivots, + npy_intp * npiv); + +static npy_intp +median_of_median5_@suff@(@type@ *v, const npy_intp num, + npy_intp * pivots, + npy_intp * npiv); + +/**begin repeat1 + * #name = , a# + * #idx = , tosort# + * #arg = 0, 1# + */ +#if @arg@ +/* helper macros to avoid duplication of direct/indirect selection */ +#define IDX(x) tosort[x] +#define SORTEE(x) tosort[x] +#define SWAP INTP_SWAP +#define MEDIAN3_SWAP(v, tosort, low, mid, high) \ + amedian3_swap_@suff@(v, tosort, low, mid, high) +#define MEDIAN5(v, tosort, subleft) \ + amedian5_@suff@(v, tosort + subleft) +#define UNGUARDED_PARTITION(v, tosort, pivot, ll, hh) \ + aunguarded_partition_@suff@(v, tosort, pivot, ll, hh) +#define INTROSELECT(v, tosort, num, kth, pivots, npiv) \ + aintroselect_@suff@(v, tosort, nmed, nmed / 2, pivots, npiv, NULL) +#define DUMBSELECT(v, tosort, left, num, kth) \ + adumb_select_@suff@(v, tosort + left, num, kth) +#else +#define IDX(x) (x) +#define SORTEE(x) v[x] +#define SWAP @TYPE@_SWAP +#define MEDIAN3_SWAP(v, tosort, low, mid, high) \ + median3_swap_@suff@(v, low, mid, high) +#define MEDIAN5(v, tosort, subleft) \ + median5_@suff@(v + subleft) +#define UNGUARDED_PARTITION(v, tosort, pivot, ll, hh) \ + unguarded_partition_@suff@(v, pivot, ll, hh) +#define INTROSELECT(v, tosort, num, kth, pivots, npiv) \ + introselect_@suff@(v, nmed, nmed / 2, pivots, npiv, NULL) +#define DUMBSELECT(v, tosort, left, num, kth) \ + dumb_select_@suff@(v + left, num, kth) +#endif + + +/* + * median of 3 pivot strategy + * gets min and median and moves median to low and min to low + 1 + * for efficient partitioning, see unguarded_partition + */ +static NPY_INLINE void +@name@median3_swap_@suff@(@type@ * v, +#if @arg@ + npy_intp * tosort, +#endif + npy_intp low, npy_intp mid, npy_intp high) +{ + if (@TYPE@_LT(v[IDX(high)], v[IDX(mid)])) + SWAP(SORTEE(high), SORTEE(mid)); + if (@TYPE@_LT(v[IDX(high)], v[IDX(low)])) + SWAP(SORTEE(high), SORTEE(low)); + /* move pivot to low */ + if (@TYPE@_LT(v[IDX(low)], v[IDX(mid)])) + SWAP(SORTEE(low), SORTEE(mid)); + /* move 3-lowest element to low + 1 */ + SWAP(SORTEE(mid), SORTEE(low + 1)); +} + + +/* select index of median of five elements */ +static npy_intp @name@median5_@suff@( +#if @arg@ + const @type@ * v, npy_intp * tosort +#else + @type@ * v +#endif + ) +{ + /* could be optimized as we only need the index (no swaps) */ + if (@TYPE@_LT(v[IDX(1)], v[IDX(0)])) { + SWAP(SORTEE(1), SORTEE(0)); + } + if (@TYPE@_LT(v[IDX(4)], v[IDX(3)])) { + SWAP(SORTEE(4), SORTEE(3)); + } + if (@TYPE@_LT(v[IDX(3)], v[IDX(0)])) { + SWAP(SORTEE(3), SORTEE(0)); + } + if (@TYPE@_LT(v[IDX(4)], v[IDX(1)])) { + SWAP(SORTEE(4), SORTEE(1)); + } + if (@TYPE@_LT(v[IDX(2)], v[IDX(1)])) { + SWAP(SORTEE(2), SORTEE(1)); + } + if (@TYPE@_LT(v[IDX(3)], v[IDX(2)])) { + if (@TYPE@_LT(v[IDX(3)], v[IDX(1)])) { + return 1; + } + else { + return 3; + } + } + else { + /* v[1] and v[2] swapped into order above */ + return 2; + } +} + + +/* + * partition and return the index were the pivot belongs + * the data must have following property to avoid bound checks: + * ll ... hh + * lower-than-pivot [x x x x] larger-than-pivot + */ +static NPY_INLINE void +@name@unguarded_partition_@suff@(@type@ * v, +#if @arg@ + npy_intp * tosort, +#endif + const @type@ pivot, + npy_intp * ll, npy_intp * hh) +{ + for (;;) { + do (*ll)++; while (@TYPE@_LT(v[IDX(*ll)], pivot)); + do (*hh)--; while (@TYPE@_LT(pivot, v[IDX(*hh)])); + + if (*hh < *ll) + break; + + SWAP(SORTEE(*ll), SORTEE(*hh)); + } +} + + +/* + * select median of median of blocks of 5 + * if used as partition pivot it splits the range into at least 30%/70% + * allowing linear time worstcase quickselect + */ +static npy_intp +@name@median_of_median5_@suff@(@type@ *v, +#if @arg@ + npy_intp* tosort, +#endif + const npy_intp num, + npy_intp * pivots, + npy_intp * npiv) +{ + npy_intp i, subleft; + npy_intp right = num - 1; + npy_intp nmed = (right + 1) / 5; + for (i = 0, subleft = 0; i < nmed; i++, subleft += 5) { + npy_intp m = MEDIAN5(v, tosort, subleft); + SWAP(SORTEE(subleft + m), SORTEE(i)); + } + + if (nmed > 2) + INTROSELECT(v, tosort, nmed, nmed / 2, pivots, npiv); + return nmed / 2; +} + + +/* + * N^2 selection, fast only for very small kth + * useful for close multiple partitions + * (e.g. even element median, interpolating percentile) + */ +static int +@name@dumb_select_@suff@(@type@ *v, +#if @arg@ + npy_intp * tosort, +#endif + npy_intp num, npy_intp kth) +{ + npy_intp i; + for (i = 0; i <= kth; i++) { + npy_intp minidx = i; + @type@ minval = v[IDX(i)]; + npy_intp k; + for (k = i + 1; k < num; k++) { + if (@TYPE@_LT(v[IDX(k)], minval)) { + minidx = k; + minval = v[IDX(k)]; + } + } + SWAP(SORTEE(i), SORTEE(minidx)); + } + + return 0; +} + + +/* + * iterative median of 3 quickselect with cutoff to median-of-medians-of5 + * receives stack of already computed pivots in v to minimize the + * partition size were kth is searched in + * + * area that needs partitioning in [...] + * kth 0: [8 7 6 5 4 3 2 1 0] -> med3 partitions elements [4, 2, 0] + * 0 1 2 3 4 8 7 5 6 -> pop requested kth -> stack [4, 2] + * kth 3: 0 1 2 [3] 4 8 7 5 6 -> stack [4] + * kth 5: 0 1 2 3 4 [8 7 5 6] -> stack [6] + * kth 8: 0 1 2 3 4 5 6 [8 7] -> stack [] + * + */ +int +@name@introselect_@suff@(@type@ *v, +#if @arg@ + npy_intp* tosort, +#endif + npy_intp num, npy_intp kth, + npy_intp * pivots, + npy_intp * npiv, + void *NOT_USED) +{ + npy_intp low = 0; + npy_intp high = num - 1; + int depth_limit; + + if (npiv == NULL) + pivots = NULL; + + while (pivots != NULL && *npiv > 0) { + if (pivots[*npiv - 1] > kth) { + /* pivot larger than kth set it as upper bound */ + high = pivots[*npiv - 1] - 1; + break; + } + else if (pivots[*npiv - 1] == kth) { + /* kth was already found in a previous iteration -> done */ + return 0; + } + + low = pivots[*npiv - 1] + 1; + + /* pop from stack */ + *npiv -= 1; + } + + /* + * use a faster O(n*kth) algorithm for very small kth + * e.g. for interpolating percentile + */ + if (kth - low < 3) { + DUMBSELECT(v, tosort, low, high - low + 1, kth - low); + store_pivot(kth, kth, pivots, npiv); + return 0; + } + else if (@inexact@ && kth == num - 1) { + /* useful to check if NaN present via partition(d, (x, -1)) */ + npy_intp k; + npy_intp maxidx = low; + @type@ maxval = v[IDX(low)]; + for (k = low + 1; k < num; k++) { + if (!@TYPE@_LT(v[IDX(k)], maxval)) { + maxidx = k; + maxval = v[IDX(k)]; + } + } + SWAP(SORTEE(kth), SORTEE(maxidx)); + return 0; + } + + depth_limit = npy_get_msb(num) * 2; + + /* guarantee three elements */ + for (;low + 1 < high;) { + npy_intp ll = low + 1; + npy_intp hh = high; + + /* + * if we aren't making sufficient progress with median of 3 + * fall back to median-of-median5 pivot for linear worst case + * med3 for small sizes is required to do unguarded partition + */ + if (depth_limit > 0 || hh - ll < 5) { + const npy_intp mid = low + (high - low) / 2; + /* median of 3 pivot strategy, + * swapping for efficient partition */ + MEDIAN3_SWAP(v, tosort, low, mid, high); + } + else { + npy_intp mid; + /* FIXME: always use pivots to optimize this iterative partition */ +#if @arg@ + mid = ll + amedian_of_median5_@suff@(v, tosort + ll, hh - ll, NULL, NULL); +#else + mid = ll + median_of_median5_@suff@(v + ll, hh - ll, NULL, NULL); +#endif + SWAP(SORTEE(mid), SORTEE(low)); + /* adapt for the larger partition than med3 pivot */ + ll--; + hh++; + } + + depth_limit--; + + /* + * find place to put pivot (in low): + * previous swapping removes need for bound checks + * pivot 3-lowest [x x x] 3-highest + */ + UNGUARDED_PARTITION(v, tosort, v[IDX(low)], &ll, &hh); + + /* move pivot into position */ + SWAP(SORTEE(low), SORTEE(hh)); + + /* kth pivot stored later */ + if (hh != kth) { + store_pivot(hh, kth, pivots, npiv); + } + + if (hh >= kth) + high = hh - 1; + if (hh <= kth) + low = ll; + } + + /* two elements */ + if (high == low + 1) { + if (@TYPE@_LT(v[IDX(high)], v[IDX(low)])) { + SWAP(SORTEE(high), SORTEE(low)) + } + } + store_pivot(kth, kth, pivots, npiv); + + return 0; +} + + +#undef IDX +#undef SWAP +#undef SORTEE +#undef MEDIAN3_SWAP +#undef MEDIAN5 +#undef UNGUARDED_PARTITION +#undef INTROSELECT +#undef DUMBSELECT +/**end repeat1**/ + +/**end repeat**/ diff --git a/numpy/core/src/private/binop_override.h b/numpy/core/src/private/binop_override.h new file mode 100644 index 0000000..47df63e --- /dev/null +++ b/numpy/core/src/private/binop_override.h @@ -0,0 +1,212 @@ +#ifndef __BINOP_OVERRIDE_H +#define __BINOP_OVERRIDE_H + +#include +#include +#include "numpy/arrayobject.h" + +#include "get_attr_string.h" + +/* + * Logic for deciding when binops should return NotImplemented versus when + * they should go ahead and call a ufunc (or similar). + * + * The interaction between binop methods (ndarray.__add__ and friends) and + * ufuncs (which dispatch to __array_ufunc__) is both complicated in its own + * right, and also has complicated historical constraints. + * + * In the very old days, the rules were: + * - If the other argument has a higher __array_priority__, then return + * NotImplemented + * - Otherwise, call the corresponding ufunc. + * - And the ufunc might return NotImplemented based on some complex + * criteria that I won't reproduce here. + * + * Ufuncs no longer return NotImplemented (except in a few marginal situations + * which are being phased out -- see https://github.com/numpy/numpy/pull/5864) + * + * So as of 1.9, the effective rules were: + * - If the other argument has a higher __array_priority__, and is *not* a + * subclass of ndarray, then return NotImplemented. (If it is a subclass, + * the regular Python rules have already given it a chance to run; so if we + * are running, then it means the other argument has already returned + * NotImplemented and is basically asking us to take care of things.) + * - Otherwise call the corresponding ufunc. + * + * We would like to get rid of __array_priority__, and __array_ufunc__ + * provides a large part of a replacement for it. Once __array_ufunc__ is + * widely available, the simplest dispatch rules that might possibly work + * would be: + * - Always call the corresponding ufunc. + * + * But: + * - Doing this immediately would break backwards compatibility -- there's a + * lot of code using __array_priority__ out there. + * - It's not at all clear whether __array_ufunc__ actually is sufficient for + * all use cases. (See https://github.com/numpy/numpy/issues/5844 for lots + * of discussion of this, and in particular + * https://github.com/numpy/numpy/issues/5844#issuecomment-112014014 + * for a summary of some conclusions.) Also, python 3.6 defines a standard + * where setting a special-method name to None is a signal that that method + * cannot be used. + * + * So for 1.13, we are going to try the following rules. + * + * For binops like a.__add__(b): + * - If b does not define __array_ufunc__, apply the legacy rule: + * - If not isinstance(b, a.__class__), and b.__array_priority__ is higher + * than a.__array_priority__, return NotImplemented + * - If b does define __array_ufunc__ but it is None, return NotImplemented + * - Otherwise, call the corresponding ufunc. + * + * For in-place operations like a.__iadd__(b) + * - If b does not define __array_ufunc__, apply the legacy rule: + * - If not isinstance(b, a.__class__), and b.__array_priority__ is higher + * than a.__array_priority__, return NotImplemented + * - Otherwise, call the corresponding ufunc. + * + * For reversed operations like b.__radd__(a) we call the corresponding ufunc. + * + * Rationale for __radd__: This is because by the time the reversed operation + * is called, there are only two possibilities: The first possibility is that + * the current class is a strict subclass of the other class. In practice, the + * only way this will happen is if b is a strict subclass of a, and a is + * ndarray or a subclass of ndarray, and neither a nor b has actually + * overridden this method. In this case, Python will never call a.__add__ + * (because it's identical to b.__radd__), so we have no-one to defer to; + * there's no reason to return NotImplemented. The second possibility is that + * b.__add__ has already been called and returned NotImplemented. Again, in + * this case there is no point in returning NotImplemented. + * + * Rationale for __iadd__: In-place operations do not take all the trouble + * above, because if __iadd__ returns NotImplemented then Python will silently + * convert the operation into an out-of-place operation, i.e. 'a += b' will + * silently become 'a = a + b'. We don't want to allow this for arrays, + * because it will create unexpected memory allocations, break views, etc. + * However, backwards compatibility requires that we follow the rules of + * __array_priority__ for arrays that define it. For classes that use the new + * __array_ufunc__ mechanism we simply defer to the ufunc. That has the effect + * that when the other array has__array_ufunc = None a TypeError will be raised. + * + * In the future we might change these rules further. For example, we plan to + * eventually deprecate __array_priority__ in cases where __array_ufunc__ is + * not present. + */ + +static int +binop_should_defer(PyObject *self, PyObject *other, int inplace) +{ + /* + * This function assumes that self.__binop__(other) is underway and + * implements the rules described above. Python's C API is funny, and + * makes it tricky to tell whether a given slot is called for __binop__ + * ("forward") or __rbinop__ ("reversed"). You are responsible for + * determining this before calling this function; it only provides the + * logic for forward binop implementations. + */ + + /* + * NB: there's another copy of this code in + * numpy.ma.core.MaskedArray._delegate_binop + * which should possibly be updated when this is. + */ + + PyObject *attr; + double self_prio, other_prio; + int defer; + /* + * attribute check is expensive for scalar operations, avoid if possible + */ + if (other == NULL || + self == NULL || + Py_TYPE(self) == Py_TYPE(other) || + PyArray_CheckExact(other) || + PyArray_CheckAnyScalarExact(other)) { + return 0; + } + /* + * Classes with __array_ufunc__ are living in the future, and only need to + * check whether __array_ufunc__ equals None. + */ + attr = PyArray_LookupSpecial(other, "__array_ufunc__"); + if (attr) { + defer = !inplace && (attr == Py_None); + Py_DECREF(attr); + return defer; + } + /* + * Otherwise, we need to check for the legacy __array_priority__. But if + * other.__class__ is a subtype of self.__class__, then it's already had + * a chance to run, so no need to defer to it. + */ + if(PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self))) { + return 0; + } + self_prio = PyArray_GetPriority((PyObject *)self, NPY_SCALAR_PRIORITY); + other_prio = PyArray_GetPriority((PyObject *)other, NPY_SCALAR_PRIORITY); + return self_prio < other_prio; +} + +/* + * A CPython slot like ->tp_as_number->nb_add gets called for *both* forward + * and reversed operations. E.g. + * a + b + * may call + * a->tp_as_number->nb_add(a, b) + * and + * b + a + * may call + * a->tp_as_number->nb_add(b, a) + * and the only way to tell which is which is for a slot implementation 'f' to + * check + * arg1->tp_as_number->nb_add == f + * arg2->tp_as_number->nb_add == f + * If both are true, then CPython will as a special case only call the + * operation once (i.e., it performs both the forward and reversed binops + * simultaneously). This function is mostly intended for figuring out + * whether we are a forward binop that might want to return NotImplemented, + * and in the both-at-once case we never want to return NotImplemented, so in + * that case BINOP_IS_FORWARD returns false. + * + * This is modeled on the checks in CPython's typeobject.c SLOT1BINFULL + * macro. + */ +#define BINOP_IS_FORWARD(m1, m2, SLOT_NAME, test_func) \ + (Py_TYPE(m2)->tp_as_number != NULL && \ + (void*)(Py_TYPE(m2)->tp_as_number->SLOT_NAME) != (void*)(test_func)) + +#define BINOP_GIVE_UP_IF_NEEDED(m1, m2, slot_expr, test_func) \ + do { \ + if (BINOP_IS_FORWARD(m1, m2, slot_expr, test_func) && \ + binop_should_defer((PyObject*)m1, (PyObject*)m2, 0)) { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + } while (0) + +#define INPLACE_GIVE_UP_IF_NEEDED(m1, m2, slot_expr, test_func) \ + do { \ + if (BINOP_IS_FORWARD(m1, m2, slot_expr, test_func) && \ + binop_should_defer((PyObject*)m1, (PyObject*)m2, 1)) { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + } while (0) + +/* + * For rich comparison operations, it's impossible to distinguish + * between a forward comparison and a reversed/reflected + * comparison. So we assume they are all forward. This only works because the + * logic in binop_override_forward_binop_should_defer is essentially + * asymmetric -- you can never have two duck-array types that each decide to + * defer to the other. + */ +#define RICHCMP_GIVE_UP_IF_NEEDED(m1, m2) \ + do { \ + if (binop_should_defer((PyObject*)m1, (PyObject*)m2, 0)) { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + } while (0) + +#endif diff --git a/numpy/core/src/private/get_attr_string.h b/numpy/core/src/private/get_attr_string.h new file mode 100644 index 0000000..bec87c5 --- /dev/null +++ b/numpy/core/src/private/get_attr_string.h @@ -0,0 +1,131 @@ +#ifndef __GET_ATTR_STRING_H +#define __GET_ATTR_STRING_H + +static NPY_INLINE npy_bool +_is_basic_python_type(PyTypeObject *tp) +{ + return ( + /* Basic number types */ + tp == &PyBool_Type || +#if !defined(NPY_PY3K) + tp == &PyInt_Type || +#endif + tp == &PyLong_Type || + tp == &PyFloat_Type || + tp == &PyComplex_Type || + + /* Basic sequence types */ + tp == &PyList_Type || + tp == &PyTuple_Type || + tp == &PyDict_Type || + tp == &PySet_Type || + tp == &PyFrozenSet_Type || + tp == &PyUnicode_Type || + tp == &PyBytes_Type || +#if !defined(NPY_PY3K) + tp == &PyString_Type || +#endif + + /* other builtins */ + tp == &PySlice_Type || + tp == Py_TYPE(Py_None) || + tp == Py_TYPE(Py_Ellipsis) || + tp == Py_TYPE(Py_NotImplemented) || + + /* TODO: ndarray, but we can't see PyArray_Type here */ + + /* sentinel to swallow trailing || */ + NPY_FALSE + ); +} + +/* + * Stripped down version of PyObject_GetAttrString, + * avoids lookups for None, tuple, and List objects, + * and doesn't create a PyErr since this code ignores it. + * + * This can be much faster then PyObject_GetAttrString where + * exceptions are not used by caller. + * + * 'obj' is the object to search for attribute. + * + * 'name' is the attribute to search for. + * + * Returns attribute value on success, NULL on failure. + */ +static NPY_INLINE PyObject * +maybe_get_attr(PyObject *obj, char *name) +{ + PyTypeObject *tp = Py_TYPE(obj); + PyObject *res = (PyObject *)NULL; + + /* Attribute referenced by (char *)name */ + if (tp->tp_getattr != NULL) { + res = (*tp->tp_getattr)(obj, name); + if (res == NULL) { + PyErr_Clear(); + } + } + /* Attribute referenced by (PyObject *)name */ + else if (tp->tp_getattro != NULL) { +#if defined(NPY_PY3K) + PyObject *w = PyUnicode_InternFromString(name); +#else + PyObject *w = PyString_InternFromString(name); +#endif + if (w == NULL) { + return (PyObject *)NULL; + } + res = (*tp->tp_getattro)(obj, w); + Py_DECREF(w); + if (res == NULL) { + PyErr_Clear(); + } + } + return res; +} + +/* + * Lookup a special method, following the python approach of looking up + * on the type object, rather than on the instance itself. + * + * Assumes that the special method is a numpy-specific one, so does not look + * at builtin types, nor does it look at a base ndarray. + * + * In future, could be made more like _Py_LookupSpecial + */ +static NPY_INLINE PyObject * +PyArray_LookupSpecial(PyObject *obj, char *name) +{ + PyTypeObject *tp = Py_TYPE(obj); + + /* We do not need to check for special attributes on trivial types */ + if (_is_basic_python_type(tp)) { + return NULL; + } + + return maybe_get_attr((PyObject *)tp, name); +} + +/* + * PyArray_LookupSpecial_OnInstance: + * + * Implements incorrect special method lookup rules, that break the python + * convention, and looks on the instance, not the type. + * + * Kept for backwards compatibility. In future, we should deprecate this. + */ +static NPY_INLINE PyObject * +PyArray_LookupSpecial_OnInstance(PyObject *obj, char *name) +{ + PyTypeObject *tp = Py_TYPE(obj); + + /* We do not need to check for special attributes on trivial types */ + if (_is_basic_python_type(tp)) { + return NULL; + } + + return maybe_get_attr(obj, name); +} + +#endif diff --git a/numpy/core/src/private/lowlevel_strided_loops.h b/numpy/core/src/private/lowlevel_strided_loops.h new file mode 100644 index 0000000..e785c67 --- /dev/null +++ b/numpy/core/src/private/lowlevel_strided_loops.h @@ -0,0 +1,833 @@ +#ifndef __LOWLEVEL_STRIDED_LOOPS_H +#define __LOWLEVEL_STRIDED_LOOPS_H +#include "common.h" +#include +#include "mem_overlap.h" + +/* + * NOTE: This API should remain private for the time being, to allow + * for further refinement. I think the 'aligned' mechanism + * needs changing, for example. + */ + +/* + * This function pointer is for unary operations that input an + * arbitrarily strided one-dimensional array segment and output + * an arbitrarily strided array segment of the same size. + * It may be a fully general function, or a specialized function + * when the strides or item size have particular known values. + * + * Examples of unary operations are a straight copy, a byte-swap, + * and a casting operation, + * + * The 'transferdata' parameter is slightly special, following a + * generic auxiliary data pattern defined in ndarraytypes.h + * Use NPY_AUXDATA_CLONE and NPY_AUXDATA_FREE to deal with this data. + * + */ +typedef void (PyArray_StridedUnaryOp)(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *transferdata); + +/* + * This is for pointers to functions which behave exactly as + * for PyArray_StridedUnaryOp, but with an additional mask controlling + * which values are transformed. + * + * In particular, the 'i'-th element is operated on if and only if + * mask[i*mask_stride] is true. + */ +typedef void (PyArray_MaskedStridedUnaryOp)(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_bool *mask, npy_intp mask_stride, + npy_intp N, npy_intp src_itemsize, + NpyAuxData *transferdata); + +/* + * This function pointer is for binary operations that input two + * arbitrarily strided one-dimensional array segments and output + * an arbitrarily strided array segment of the same size. + * It may be a fully general function, or a specialized function + * when the strides or item size have particular known values. + * + * Examples of binary operations are the basic arithmetic operations, + * logical operators AND, OR, and many others. + * + * The 'transferdata' parameter is slightly special, following a + * generic auxiliary data pattern defined in ndarraytypes.h + * Use NPY_AUXDATA_CLONE and NPY_AUXDATA_FREE to deal with this data. + * + */ +typedef void (PyArray_StridedBinaryOp)(char *dst, npy_intp dst_stride, + char *src0, npy_intp src0_stride, + char *src1, npy_intp src1_stride, + npy_intp N, NpyAuxData *transferdata); + +/* + * Gives back a function pointer to a specialized function for copying + * strided memory. Returns NULL if there is a problem with the inputs. + * + * aligned: + * Should be 1 if the src and dst pointers are always aligned, + * 0 otherwise. + * src_stride: + * Should be the src stride if it will always be the same, + * NPY_MAX_INTP otherwise. + * dst_stride: + * Should be the dst stride if it will always be the same, + * NPY_MAX_INTP otherwise. + * itemsize: + * Should be the item size if it will always be the same, 0 otherwise. + * + */ +NPY_NO_EXPORT PyArray_StridedUnaryOp * +PyArray_GetStridedCopyFn(int aligned, + npy_intp src_stride, npy_intp dst_stride, + npy_intp itemsize); + +/* + * Gives back a function pointer to a specialized function for copying + * and swapping strided memory. This assumes each element is a single + * value to be swapped. + * + * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters + * see above. + * + * Parameters are as for PyArray_GetStridedCopyFn. + */ +NPY_NO_EXPORT PyArray_StridedUnaryOp * +PyArray_GetStridedCopySwapFn(int aligned, + npy_intp src_stride, npy_intp dst_stride, + npy_intp itemsize); + +/* + * Gives back a function pointer to a specialized function for copying + * and swapping strided memory. This assumes each element is a pair + * of values, each of which needs to be swapped. + * + * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters + * see above. + * + * Parameters are as for PyArray_GetStridedCopyFn. + */ +NPY_NO_EXPORT PyArray_StridedUnaryOp * +PyArray_GetStridedCopySwapPairFn(int aligned, + npy_intp src_stride, npy_intp dst_stride, + npy_intp itemsize); + +/* + * Gives back a transfer function and transfer data pair which copies + * the data from source to dest, truncating it if the data doesn't + * fit, and padding with zero bytes if there's too much space. + * + * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters + * see above. + * + * Returns NPY_SUCCEED or NPY_FAIL + */ +NPY_NO_EXPORT int +PyArray_GetStridedZeroPadCopyFn(int aligned, int unicode_swap, + npy_intp src_stride, npy_intp dst_stride, + npy_intp src_itemsize, npy_intp dst_itemsize, + PyArray_StridedUnaryOp **outstransfer, + NpyAuxData **outtransferdata); + +/* + * For casts between built-in numeric types, + * this produces a function pointer for casting from src_type_num + * to dst_type_num. If a conversion is unsupported, returns NULL + * without setting a Python exception. + */ +NPY_NO_EXPORT PyArray_StridedUnaryOp * +PyArray_GetStridedNumericCastFn(int aligned, + npy_intp src_stride, npy_intp dst_stride, + int src_type_num, int dst_type_num); + +/* + * Gets an operation which copies elements of the given dtype, + * swapping if the dtype isn't in NBO. + * + * Returns NPY_SUCCEED or NPY_FAIL + */ +NPY_NO_EXPORT int +PyArray_GetDTypeCopySwapFn(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *dtype, + PyArray_StridedUnaryOp **outstransfer, + NpyAuxData **outtransferdata); + +/* + * If it's possible, gives back a transfer function which casts and/or + * byte swaps data with the dtype 'src_dtype' into data with the dtype + * 'dst_dtype'. If the outtransferdata is populated with a non-NULL value, + * it must be deallocated with the NPY_AUXDATA_FREE + * function when the transfer function is no longer required. + * + * aligned: + * Should be 1 if the src and dst pointers are always aligned, + * 0 otherwise. + * src_stride: + * Should be the src stride if it will always be the same, + * NPY_MAX_INTP otherwise. + * dst_stride: + * Should be the dst stride if it will always be the same, + * NPY_MAX_INTP otherwise. + * src_dtype: + * The data type of source data. If this is NULL, a transfer + * function which sets the destination to zeros is produced. + * dst_dtype: + * The data type of destination data. If this is NULL and + * move_references is 1, a transfer function which decrements + * source data references is produced. + * move_references: + * If 0, the destination data gets new reference ownership. + * If 1, the references from the source data are moved to + * the destination data. + * out_stransfer: + * The resulting transfer function is placed here. + * out_transferdata: + * The auxiliary data for the transfer function is placed here. + * When finished with the transfer function, the caller must call + * NPY_AUXDATA_FREE on this data. + * out_needs_api: + * If this is non-NULL, and the transfer function produced needs + * to call into the (Python) API, this gets set to 1. This + * remains untouched if no API access is required. + * + * WARNING: If you set move_references to 1, it is best that src_stride is + * never zero when calling the transfer function. Otherwise, the + * first destination reference will get the value and all the rest + * will get NULL. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +NPY_NO_EXPORT int +PyArray_GetDTypeTransferFunction(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + PyArray_StridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api); + +/* + * This is identical to PyArray_GetDTypeTransferFunction, but returns a + * transfer function which also takes a mask as a parameter. The mask is used + * to determine which values to copy, and data is transferred exactly when + * mask[i*mask_stride] is true. + * + * If move_references is true, values which are not copied to the + * destination will still have their source reference decremented. + * + * If mask_dtype is NPY_BOOL or NPY_UINT8, each full element is either + * transferred or not according to the mask as described above. If + * dst_dtype and mask_dtype are both struct dtypes, their names must + * match exactly, and the dtype of each leaf field in mask_dtype must + * be either NPY_BOOL or NPY_UINT8. + */ +NPY_NO_EXPORT int +PyArray_GetMaskedDTypeTransferFunction(int aligned, + npy_intp src_stride, + npy_intp dst_stride, + npy_intp mask_stride, + PyArray_Descr *src_dtype, + PyArray_Descr *dst_dtype, + PyArray_Descr *mask_dtype, + int move_references, + PyArray_MaskedStridedUnaryOp **out_stransfer, + NpyAuxData **out_transferdata, + int *out_needs_api); + +/* + * Casts the specified number of elements from 'src' with data type + * 'src_dtype' to 'dst' with 'dst_dtype'. See + * PyArray_GetDTypeTransferFunction for more details. + * + * Returns NPY_SUCCEED or NPY_FAIL. + */ +NPY_NO_EXPORT int +PyArray_CastRawArrays(npy_intp count, + char *src, char *dst, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references); + +/* + * These two functions copy or convert the data of an n-dimensional array + * to/from a 1-dimensional strided buffer. These functions will only call + * 'stransfer' with the provided dst_stride/src_stride and + * dst_strides[0]/src_strides[0], so the caller can use those values to + * specialize the function. + * Note that even if ndim == 0, everything needs to be set as if ndim == 1. + * + * The return value is the number of elements it couldn't copy. A return value + * of 0 means all elements were copied, a larger value means the end of + * the n-dimensional array was reached before 'count' elements were copied. + * + * ndim: + * The number of dimensions of the n-dimensional array. + * dst/src/mask: + * The destination, source or mask starting pointer. + * dst_stride/src_stride/mask_stride: + * The stride of the 1-dimensional strided buffer + * dst_strides/src_strides: + * The strides of the n-dimensional array. + * dst_strides_inc/src_strides_inc: + * How much to add to the ..._strides pointer to get to the next stride. + * coords: + * The starting coordinates in the n-dimensional array. + * coords_inc: + * How much to add to the coords pointer to get to the next coordinate. + * shape: + * The shape of the n-dimensional array. + * shape_inc: + * How much to add to the shape pointer to get to the next shape entry. + * count: + * How many elements to transfer + * src_itemsize: + * How big each element is. If transferring between elements of different + * sizes, for example a casting operation, the 'stransfer' function + * should be specialized for that, in which case 'stransfer' will use + * this parameter as the source item size. + * stransfer: + * The strided transfer function. + * transferdata: + * An auxiliary data pointer passed to the strided transfer function. + * This follows the conventions of NpyAuxData objects. + */ +NPY_NO_EXPORT npy_intp +PyArray_TransferNDimToStrided(npy_intp ndim, + char *dst, npy_intp dst_stride, + char *src, npy_intp *src_strides, npy_intp src_strides_inc, + npy_intp *coords, npy_intp coords_inc, + npy_intp *shape, npy_intp shape_inc, + npy_intp count, npy_intp src_itemsize, + PyArray_StridedUnaryOp *stransfer, + NpyAuxData *transferdata); + +NPY_NO_EXPORT npy_intp +PyArray_TransferStridedToNDim(npy_intp ndim, + char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, + char *src, npy_intp src_stride, + npy_intp *coords, npy_intp coords_inc, + npy_intp *shape, npy_intp shape_inc, + npy_intp count, npy_intp src_itemsize, + PyArray_StridedUnaryOp *stransfer, + NpyAuxData *transferdata); + +NPY_NO_EXPORT npy_intp +PyArray_TransferMaskedStridedToNDim(npy_intp ndim, + char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, + char *src, npy_intp src_stride, + npy_bool *mask, npy_intp mask_stride, + npy_intp *coords, npy_intp coords_inc, + npy_intp *shape, npy_intp shape_inc, + npy_intp count, npy_intp src_itemsize, + PyArray_MaskedStridedUnaryOp *stransfer, + NpyAuxData *data); + +NPY_NO_EXPORT int +mapiter_trivial_get(PyArrayObject *self, PyArrayObject *ind, + PyArrayObject *result); + +NPY_NO_EXPORT int +mapiter_trivial_set(PyArrayObject *self, PyArrayObject *ind, + PyArrayObject *result); + +NPY_NO_EXPORT int +mapiter_get(PyArrayMapIterObject *mit); + +NPY_NO_EXPORT int +mapiter_set(PyArrayMapIterObject *mit); + +/* + * Prepares shape and strides for a simple raw array iteration. + * This sorts the strides into FORTRAN order, reverses any negative + * strides, then coalesces axes where possible. The results are + * filled in the output parameters. + * + * This is intended for simple, lightweight iteration over arrays + * where no buffering of any kind is needed, and the array may + * not be stored as a PyArrayObject. + * + * You can use this together with NPY_RAW_ITER_START and + * NPY_RAW_ITER_ONE_NEXT to handle the looping boilerplate of everything + * but the innermost loop (which is for idim == 0). + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_PrepareOneRawArrayIter(int ndim, npy_intp *shape, + char *data, npy_intp *strides, + int *out_ndim, npy_intp *out_shape, + char **out_data, npy_intp *out_strides); + +/* + * The same as PyArray_PrepareOneRawArrayIter, but for two + * operands instead of one. Any broadcasting of the two operands + * should have already been done before calling this function, + * as the ndim and shape is only specified once for both operands. + * + * Only the strides of the first operand are used to reorder + * the dimensions, no attempt to consider all the strides together + * is made, as is done in the NpyIter object. + * + * You can use this together with NPY_RAW_ITER_START and + * NPY_RAW_ITER_TWO_NEXT to handle the looping boilerplate of everything + * but the innermost loop (which is for idim == 0). + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_PrepareTwoRawArrayIter(int ndim, npy_intp *shape, + char *dataA, npy_intp *stridesA, + char *dataB, npy_intp *stridesB, + int *out_ndim, npy_intp *out_shape, + char **out_dataA, npy_intp *out_stridesA, + char **out_dataB, npy_intp *out_stridesB); + +/* + * The same as PyArray_PrepareOneRawArrayIter, but for three + * operands instead of one. Any broadcasting of the three operands + * should have already been done before calling this function, + * as the ndim and shape is only specified once for all operands. + * + * Only the strides of the first operand are used to reorder + * the dimensions, no attempt to consider all the strides together + * is made, as is done in the NpyIter object. + * + * You can use this together with NPY_RAW_ITER_START and + * NPY_RAW_ITER_THREE_NEXT to handle the looping boilerplate of everything + * but the innermost loop (which is for idim == 0). + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp *shape, + char *dataA, npy_intp *stridesA, + char *dataB, npy_intp *stridesB, + char *dataC, npy_intp *stridesC, + int *out_ndim, npy_intp *out_shape, + char **out_dataA, npy_intp *out_stridesA, + char **out_dataB, npy_intp *out_stridesB, + char **out_dataC, npy_intp *out_stridesC); + +/* + * Return number of elements that must be peeled from + * the start of 'addr' with 'nvals' elements of size 'esize' + * in order to reach 'alignment'. + * alignment must be a power of two. + * see npy_blocked_end for an example + */ +static NPY_INLINE npy_uintp +npy_aligned_block_offset(const void * addr, const npy_uintp esize, + const npy_uintp alignment, const npy_uintp nvals) +{ + const npy_uintp offset = (npy_uintp)addr & (alignment - 1); + npy_uintp peel = offset ? (alignment - offset) / esize : 0; + peel = nvals < peel ? nvals : peel; + return peel; +} + +/* + * Return upper loop bound for an array of 'nvals' elements + * of size 'esize' peeled by 'offset' elements and blocking to + * a vector size of 'vsz' in bytes + * + * example usage: + * npy_intp i; + * double v[101]; + * npy_intp esize = sizeof(v[0]); + * npy_intp peel = npy_aligned_block_offset(v, esize, 16, n); + * // peel to alignment 16 + * for (i = 0; i < peel; i++) + * + * // simd vectorized operation + * for (; i < npy_blocked_end(peel, esize, 16, n); i += 16 / esize) + * + * // handle scalar rest + * for(; i < n; i++) + * + */ +static NPY_INLINE npy_uintp +npy_blocked_end(const npy_uintp offset, const npy_uintp esize, + const npy_uintp vsz, const npy_uintp nvals) +{ + return nvals - offset - (nvals - offset) % (vsz / esize); +} + + +/* byte swapping functions */ +static NPY_INLINE npy_uint16 +npy_bswap2(npy_uint16 x) +{ + return ((x & 0xffu) << 8) | (x >> 8); +} + +/* + * treat as int16 and byteswap unaligned memory, + * some cpus don't support unaligned access + */ +static NPY_INLINE void +npy_bswap2_unaligned(char * x) +{ + char a = x[0]; + x[0] = x[1]; + x[1] = a; +} + +static NPY_INLINE npy_uint32 +npy_bswap4(npy_uint32 x) +{ +#ifdef HAVE___BUILTIN_BSWAP32 + return __builtin_bswap32(x); +#else + return ((x & 0xffu) << 24) | ((x & 0xff00u) << 8) | + ((x & 0xff0000u) >> 8) | (x >> 24); +#endif +} + +static NPY_INLINE void +npy_bswap4_unaligned(char * x) +{ + char a = x[0]; + x[0] = x[3]; + x[3] = a; + a = x[1]; + x[1] = x[2]; + x[2] = a; +} + +static NPY_INLINE npy_uint64 +npy_bswap8(npy_uint64 x) +{ +#ifdef HAVE___BUILTIN_BSWAP64 + return __builtin_bswap64(x); +#else + return ((x & 0xffULL) << 56) | + ((x & 0xff00ULL) << 40) | + ((x & 0xff0000ULL) << 24) | + ((x & 0xff000000ULL) << 8) | + ((x & 0xff00000000ULL) >> 8) | + ((x & 0xff0000000000ULL) >> 24) | + ((x & 0xff000000000000ULL) >> 40) | + ( x >> 56); +#endif +} + +static NPY_INLINE void +npy_bswap8_unaligned(char * x) +{ + char a = x[0]; x[0] = x[7]; x[7] = a; + a = x[1]; x[1] = x[6]; x[6] = a; + a = x[2]; x[2] = x[5]; x[5] = a; + a = x[3]; x[3] = x[4]; x[4] = a; +} + + +/* Start raw iteration */ +#define NPY_RAW_ITER_START(idim, ndim, coord, shape) \ + memset((coord), 0, (ndim) * sizeof(coord[0])); \ + do { + +/* Increment to the next n-dimensional coordinate for one raw array */ +#define NPY_RAW_ITER_ONE_NEXT(idim, ndim, coord, shape, data, strides) \ + for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ + if (++(coord)[idim] == (shape)[idim]) { \ + (coord)[idim] = 0; \ + (data) -= ((shape)[idim] - 1) * (strides)[idim]; \ + } \ + else { \ + (data) += (strides)[idim]; \ + break; \ + } \ + } \ + } while ((idim) < (ndim)) + +/* Increment to the next n-dimensional coordinate for two raw arrays */ +#define NPY_RAW_ITER_TWO_NEXT(idim, ndim, coord, shape, \ + dataA, stridesA, dataB, stridesB) \ + for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ + if (++(coord)[idim] == (shape)[idim]) { \ + (coord)[idim] = 0; \ + (dataA) -= ((shape)[idim] - 1) * (stridesA)[idim]; \ + (dataB) -= ((shape)[idim] - 1) * (stridesB)[idim]; \ + } \ + else { \ + (dataA) += (stridesA)[idim]; \ + (dataB) += (stridesB)[idim]; \ + break; \ + } \ + } \ + } while ((idim) < (ndim)) + +/* Increment to the next n-dimensional coordinate for three raw arrays */ +#define NPY_RAW_ITER_THREE_NEXT(idim, ndim, coord, shape, \ + dataA, stridesA, \ + dataB, stridesB, \ + dataC, stridesC) \ + for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ + if (++(coord)[idim] == (shape)[idim]) { \ + (coord)[idim] = 0; \ + (dataA) -= ((shape)[idim] - 1) * (stridesA)[idim]; \ + (dataB) -= ((shape)[idim] - 1) * (stridesB)[idim]; \ + (dataC) -= ((shape)[idim] - 1) * (stridesC)[idim]; \ + } \ + else { \ + (dataA) += (stridesA)[idim]; \ + (dataB) += (stridesB)[idim]; \ + (dataC) += (stridesC)[idim]; \ + break; \ + } \ + } \ + } while ((idim) < (ndim)) + +/* Increment to the next n-dimensional coordinate for four raw arrays */ +#define NPY_RAW_ITER_FOUR_NEXT(idim, ndim, coord, shape, \ + dataA, stridesA, \ + dataB, stridesB, \ + dataC, stridesC, \ + dataD, stridesD) \ + for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ + if (++(coord)[idim] == (shape)[idim]) { \ + (coord)[idim] = 0; \ + (dataA) -= ((shape)[idim] - 1) * (stridesA)[idim]; \ + (dataB) -= ((shape)[idim] - 1) * (stridesB)[idim]; \ + (dataC) -= ((shape)[idim] - 1) * (stridesC)[idim]; \ + (dataD) -= ((shape)[idim] - 1) * (stridesD)[idim]; \ + } \ + else { \ + (dataA) += (stridesA)[idim]; \ + (dataB) += (stridesB)[idim]; \ + (dataC) += (stridesC)[idim]; \ + (dataD) += (stridesD)[idim]; \ + break; \ + } \ + } \ + } while ((idim) < (ndim)) + + +/* + * TRIVIAL ITERATION + * + * In some cases when the iteration order isn't important, iteration over + * arrays is trivial. This is the case when: + * * The array has 0 or 1 dimensions. + * * The array is C or Fortran contiguous. + * Use of an iterator can be skipped when this occurs. These macros assist + * in detecting and taking advantage of the situation. Note that it may + * be worthwhile to further check if the stride is a contiguous stride + * and take advantage of that. + * + * Here is example code for a single array: + * + * if (PyArray_TRIVIALLY_ITERABLE(self) { + * char *data; + * npy_intp count, stride; + * + * PyArray_PREPARE_TRIVIAL_ITERATION(self, count, data, stride); + * + * while (count--) { + * // Use the data pointer + * + * data += stride; + * } + * } + * else { + * // Create iterator, etc... + * } + * + * Here is example code for a pair of arrays: + * + * if (PyArray_TRIVIALLY_ITERABLE_PAIR(a1, a2) { + * char *data1, *data2; + * npy_intp count, stride1, stride2; + * + * PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(a1, a2, count, + * data1, data2, stride1, stride2); + * + * while (count--) { + * // Use the data1 and data2 pointers + * + * data1 += stride1; + * data2 += stride2; + * } + * } + * else { + * // Create iterator, etc... + * } + */ + +/* + * Note: Equivalently iterable macro requires one of arr1 or arr2 be + * trivially iterable to be valid. + */ + +/** + * Determine whether two arrays are safe for trivial iteration in cases where + * some of the arrays may be modified. + * + * In-place iteration is safe if one of the following is true: + * + * - Both arrays are read-only + * - The arrays do not have overlapping memory (based on a check that may be too + * strict) + * - The strides match, and the non-read-only array base addresses are equal or + * before the read-only one, ensuring correct data dependency. + */ + +#define PyArray_TRIVIALLY_ITERABLE_OP_NOREAD 0 +#define PyArray_TRIVIALLY_ITERABLE_OP_READ 1 + +#define PyArray_EQUIVALENTLY_ITERABLE_BASE(arr1, arr2) ( \ + PyArray_NDIM(arr1) == PyArray_NDIM(arr2) && \ + PyArray_CompareLists(PyArray_DIMS(arr1), \ + PyArray_DIMS(arr2), \ + PyArray_NDIM(arr1)) && \ + (PyArray_FLAGS(arr1)&(NPY_ARRAY_C_CONTIGUOUS| \ + NPY_ARRAY_F_CONTIGUOUS)) & \ + (PyArray_FLAGS(arr2)&(NPY_ARRAY_C_CONTIGUOUS| \ + NPY_ARRAY_F_CONTIGUOUS)) \ + ) + +#define PyArray_TRIVIAL_PAIR_ITERATION_STRIDE(size, arr) ( \ + size == 1 ? 0 : ((PyArray_NDIM(arr) == 1) ? \ + PyArray_STRIDE(arr, 0) : \ + PyArray_ITEMSIZE(arr))) + +static NPY_INLINE int +PyArray_EQUIVALENTLY_ITERABLE_OVERLAP_OK(PyArrayObject *arr1, PyArrayObject *arr2, + int arr1_read, int arr2_read) +{ + npy_intp size1, size2, stride1, stride2; + int arr1_ahead = 0, arr2_ahead = 0; + + if (arr1_read && arr2_read) { + return 1; + } + + if (solve_may_share_memory(arr1, arr2, 1) == 0) { + return 1; + } + + /* + * Arrays overlapping in memory may be equivalently iterable if input + * arrays stride ahead faster than output arrays. + */ + + size1 = PyArray_SIZE(arr1); + size2 = PyArray_SIZE(arr2); + + stride1 = PyArray_TRIVIAL_PAIR_ITERATION_STRIDE(size1, arr1); + stride2 = PyArray_TRIVIAL_PAIR_ITERATION_STRIDE(size2, arr2); + + /* + * Arrays with zero stride are never "ahead" since the element is reused + * (at this point we know the array extents overlap). + */ + + if (stride1 > 0) { + arr1_ahead = (stride1 >= stride2 && + PyArray_BYTES(arr1) >= PyArray_BYTES(arr2)); + } + else if (stride1 < 0) { + arr1_ahead = (stride1 <= stride2 && + PyArray_BYTES(arr1) <= PyArray_BYTES(arr2)); + } + + if (stride2 > 0) { + arr2_ahead = (stride2 >= stride1 && + PyArray_BYTES(arr2) >= PyArray_BYTES(arr1)); + } + else if (stride2 < 0) { + arr2_ahead = (stride2 <= stride1 && + PyArray_BYTES(arr2) <= PyArray_BYTES(arr1)); + } + + return (!arr1_read || arr1_ahead) && (!arr2_read || arr2_ahead); +} + +#define PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2, arr1_read, arr2_read) ( \ + PyArray_EQUIVALENTLY_ITERABLE_BASE(arr1, arr2) && \ + PyArray_EQUIVALENTLY_ITERABLE_OVERLAP_OK( \ + arr1, arr2, arr1_read, arr2_read)) +#define PyArray_TRIVIALLY_ITERABLE(arr) ( \ + PyArray_NDIM(arr) <= 1 || \ + PyArray_CHKFLAGS(arr, NPY_ARRAY_C_CONTIGUOUS) || \ + PyArray_CHKFLAGS(arr, NPY_ARRAY_F_CONTIGUOUS) \ + ) +#define PyArray_PREPARE_TRIVIAL_ITERATION(arr, count, data, stride) \ + count = PyArray_SIZE(arr); \ + data = PyArray_BYTES(arr); \ + stride = ((PyArray_NDIM(arr) == 0) ? 0 : \ + ((PyArray_NDIM(arr) == 1) ? \ + PyArray_STRIDE(arr, 0) : \ + PyArray_ITEMSIZE(arr))); + + +#define PyArray_TRIVIALLY_ITERABLE_PAIR(arr1, arr2, arr1_read, arr2_read) ( \ + PyArray_TRIVIALLY_ITERABLE(arr1) && \ + (PyArray_NDIM(arr2) == 0 || \ + PyArray_EQUIVALENTLY_ITERABLE_BASE(arr1, arr2) || \ + (PyArray_NDIM(arr1) == 0 && \ + PyArray_TRIVIALLY_ITERABLE(arr2) \ + ) \ + ) && \ + PyArray_EQUIVALENTLY_ITERABLE_OVERLAP_OK(arr1, arr2, arr1_read, arr2_read) \ + ) +#define PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(arr1, arr2, \ + count, \ + data1, data2, \ + stride1, stride2) { \ + npy_intp size1 = PyArray_SIZE(arr1); \ + npy_intp size2 = PyArray_SIZE(arr2); \ + count = ((size1 > size2) || size1 == 0) ? size1 : size2; \ + data1 = PyArray_BYTES(arr1); \ + data2 = PyArray_BYTES(arr2); \ + stride1 = PyArray_TRIVIAL_PAIR_ITERATION_STRIDE(size1, arr1); \ + stride2 = PyArray_TRIVIAL_PAIR_ITERATION_STRIDE(size2, arr2); \ + } + +#define PyArray_TRIVIALLY_ITERABLE_TRIPLE(arr1, arr2, arr3, arr1_read, arr2_read, arr3_read) ( \ + PyArray_TRIVIALLY_ITERABLE(arr1) && \ + ((PyArray_NDIM(arr2) == 0 && \ + (PyArray_NDIM(arr3) == 0 || \ + PyArray_EQUIVALENTLY_ITERABLE_BASE(arr1, arr3) \ + ) \ + ) || \ + (PyArray_EQUIVALENTLY_ITERABLE_BASE(arr1, arr2) && \ + (PyArray_NDIM(arr3) == 0 || \ + PyArray_EQUIVALENTLY_ITERABLE_BASE(arr1, arr3) \ + ) \ + ) || \ + (PyArray_NDIM(arr1) == 0 && \ + PyArray_TRIVIALLY_ITERABLE(arr2) && \ + (PyArray_NDIM(arr3) == 0 || \ + PyArray_EQUIVALENTLY_ITERABLE_BASE(arr2, arr3) \ + ) \ + ) \ + ) && \ + PyArray_EQUIVALENTLY_ITERABLE_OVERLAP_OK(arr1, arr2, arr1_read, arr2_read) && \ + PyArray_EQUIVALENTLY_ITERABLE_OVERLAP_OK(arr1, arr3, arr1_read, arr3_read) && \ + PyArray_EQUIVALENTLY_ITERABLE_OVERLAP_OK(arr2, arr3, arr2_read, arr3_read) \ + ) + +#define PyArray_PREPARE_TRIVIAL_TRIPLE_ITERATION(arr1, arr2, arr3, \ + count, \ + data1, data2, data3, \ + stride1, stride2, stride3) { \ + npy_intp size1 = PyArray_SIZE(arr1); \ + npy_intp size2 = PyArray_SIZE(arr2); \ + npy_intp size3 = PyArray_SIZE(arr3); \ + count = ((size1 > size2) || size1 == 0) ? size1 : size2; \ + count = ((size3 > count) || size3 == 0) ? size3 : count; \ + data1 = PyArray_BYTES(arr1); \ + data2 = PyArray_BYTES(arr2); \ + data3 = PyArray_BYTES(arr3); \ + stride1 = PyArray_TRIVIAL_PAIR_ITERATION_STRIDE(size1, arr1); \ + stride2 = PyArray_TRIVIAL_PAIR_ITERATION_STRIDE(size2, arr2); \ + stride3 = PyArray_TRIVIAL_PAIR_ITERATION_STRIDE(size3, arr3); \ + } + +#endif diff --git a/numpy/core/src/private/mem_overlap.c b/numpy/core/src/private/mem_overlap.c new file mode 100644 index 0000000..2145791 --- /dev/null +++ b/numpy/core/src/private/mem_overlap.c @@ -0,0 +1,919 @@ +/* + Solving memory overlap integer programs and bounded Diophantine equations with + positive coefficients. + + Asking whether two strided arrays `a` and `b` overlap is equivalent to + asking whether there is a solution to the following problem:: + + sum(stride_a[i] * x_a[i] for i in range(ndim_a)) + - + sum(stride_b[i] * x_b[i] for i in range(ndim_b)) + == + base_b - base_a + + 0 <= x_a[i] < shape_a[i] + 0 <= x_b[i] < shape_b[i] + + for some integer x_a, x_b. Itemsize needs to be considered as an additional + dimension with stride 1 and size itemsize. + + Negative strides can be changed to positive (and vice versa) by changing + variables x[i] -> shape[i] - 1 - x[i], and zero strides can be dropped, so + that the problem can be recast into a bounded Diophantine equation with + positive coefficients:: + + sum(a[i] * x[i] for i in range(n)) == b + + a[i] > 0 + + 0 <= x[i] <= ub[i] + + This problem is NP-hard --- runtime of algorithms grows exponentially with + increasing ndim. + + + *Algorithm description* + + A straightforward algorithm that excludes infeasible solutions using GCD-based + pruning is outlined in Ref. [1]. It is implemented below. A number of other + algorithms exist in the literature; however, this one seems to have + performance satisfactory for the present purpose. + + The idea is that an equation:: + + a_1 x_1 + a_2 x_2 + ... + a_n x_n = b + 0 <= x_i <= ub_i, i = 1...n + + implies:: + + a_2' x_2' + a_3 x_3 + ... + a_n x_n = b + + 0 <= x_i <= ub_i, i = 2...n + + 0 <= x_1' <= c_1 ub_1 + c_2 ub_2 + + with a_2' = gcd(a_1, a_2) and x_2' = c_1 x_1 + c_2 x_2 with c_1 = (a_1/a_1'), + and c_2 = (a_2/a_1'). This procedure can be repeated to obtain:: + + a_{n-1}' x_{n-1}' + a_n x_n = b + + 0 <= x_{n-1}' <= ub_{n-1}' + + 0 <= x_n <= ub_n + + Now, one can enumerate all candidate solutions for x_n. For each, one can use + the previous-level equation to enumerate potential solutions for x_{n-1}, with + transformed right-hand side b -> b - a_n x_n. And so forth, until after n-1 + nested for loops we either arrive at a candidate solution for x_1 (in which + case we have found one solution to the problem), or find that the equations do + not allow any solutions either for x_1 or one of the intermediate x_i (in + which case we have proved there is no solution for the upper-level candidates + chosen). If no solution is found for any candidate x_n, we have proved the + problem is infeasible --- which for the memory overlap problem means there is + no overlap. + + + *Performance* + + Some common ndarray cases are easy for the algorithm: + + - Two arrays whose memory ranges do not overlap. + + These will be excluded by the bounds on x_n, with max_work=1. We also add + this check as a fast path, to avoid computing GCDs needlessly, as this can + take some time. + + - Arrays produced by continuous slicing of a continuous parent array (no + internal overlap), e.g., a=x[:,0,:], b=x[:,1,:]. The strides taken together, + mapped positive, and duplicates then satisfy gcd(stride[0], .., stride[j]) = + stride[j] for some ordering. + + In this case, for each x[i] at most one candidate exists, given that the + algorithm runs with strides sorted from largest to smallest. The problem can + be written as:: + + sum a_j x_j ?= b = sum a_j z_j + + a_j = n_{j+1} * n_{j+2} * ... * n_d, a_d = 1 + 0 <= x_j <= u_j <= 2*n_j - 2 + 0 <= z_j <= n_j - 1 + + b is the offset of the last element of the second array from the start of + the first. z_j are uniquely determined because of the gcd property. For + each x_j, the bounds at first sight allow x_j=z_j and x_j=z_j+n_j. However, + u_j <= n_j - 1 + z_j, so that at most one candidate is left. + + - Two arrays with stride-incommensurate starting points. For example, + a=x[:,::2], b=x[:,1::2]. + + The base address difference is incommensurate with all strides, so that + there are no solution candidates to consider. For itemsize != 1, similar + result is obtained for x_{n-1}. + + The above cases cover arrays produced by typical slicing of well-behaved + parent arrays. More generally, more difficult cases can result:: + + x = np.arange(4*20).reshape(4, 20).astype(np.int8) + a = x[:,::7] + b = x[:,3::3] + + <=> + + 20*x1 + 7*x2 + 3*x3 = 78 (= 3 + 3*20 + 5*3) + 0 <= x1 <= 6, 0 <= x2 <= 2, 0 <= x3 <= 5 + + Non-overlapping in this case relies on x.shape[1] <= lcm(7, 3) = 21. However, + elimination of x1 does not restrict candidate values for x3, so the algorithm + ends up considering all values x3=0...5 separately. + + The upper bound for work done is prod(shape_a)*prod(shape_b), which scales + faster than than work done by binary ufuncs, after broadcasting, + prod(shape_a). The bound may be loose, but it is possible to construct hard + instances where ufunc is faster (adapted from [2,3]):: + + from numpy.lib.stride_tricks import as_strided + # Construct non-overlapping x1 and x2 + x = np.zeros([192163377], dtype=np.int8) + x1 = as_strided(x, strides=(36674, 61119, 85569), shape=(1049, 1049, 1049)) + x2 = as_strided(x[64023025:], strides=(12223, 12224, 1), shape=(1049, 1049, 1)) + + To avoid such worst cases, the amount of work done needs to be capped. If the + overlap problem is related to ufuncs, one suitable cap choice is to scale + max_work with the number of elements of the array. (Ref. [3] describes a more + efficient algorithm for solving problems similar to the above --- however, + also it must scale exponentially.) + + + *Integer overflows* + + The algorithm is written in fixed-width integers, and can terminate with + failure if integer overflow is detected (the implementation catches all + cases). Potential failure modes: + + - Array extent sum(stride*(shape-1)) is too large (for int64). + + - Minimal solutions to a_i x_i + a_j x_j == b are too large, + in some of the intermediate equations. + + We do this part of the computation in 128-bit integers. + + In general, overflows are expected only if array size is close to + NPY_INT64_MAX, requiring ~exabyte size arrays, which is usually not possible. + + References + ---------- + .. [1] P. Ramachandran, ''Use of Extended Euclidean Algorithm in Solving + a System of Linear Diophantine Equations with Bounded Variables''. + Algorithmic Number Theory, Lecture Notes in Computer Science **4076**, + 182-192 (2006). doi:10.1007/11792086_14 + + .. [2] Cornuejols, Urbaniak, Weismantel, and Wolsey, + ''Decomposition of integer programs and of generating sets.'', + Lecture Notes in Computer Science 1284, 92-103 (1997). + + .. [3] K. Aardal, A.K. Lenstra, + ''Hard equality constrained integer knapsacks'', + Lecture Notes in Computer Science 2337, 350-366 (2002). +*/ + +/* + Copyright (c) 2015 Pauli Virtanen + All rights reserved. + Licensed under 3-clause BSD license, see LICENSE.txt. +*/ +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#include "numpy/ndarraytypes.h" +#include "mem_overlap.h" +#include "npy_extint128.h" + +#include +#include +#include + + +#define MAX(a, b) (((a) >= (b)) ? (a) : (b)) +#define MIN(a, b) (((a) <= (b)) ? (a) : (b)) + + +/** + * Euclid's algorithm for GCD. + * + * Solves for gamma*a1 + epsilon*a2 == gcd(a1, a2) + * providing |gamma| < |a2|/gcd, |epsilon| < |a1|/gcd. + */ +static void +euclid(npy_int64 a1, npy_int64 a2, npy_int64 *a_gcd, npy_int64 *gamma, npy_int64 *epsilon) +{ + npy_int64 gamma1, gamma2, epsilon1, epsilon2, r; + + assert(a1 > 0); + assert(a2 > 0); + + gamma1 = 1; + gamma2 = 0; + epsilon1 = 0; + epsilon2 = 1; + + /* The numbers remain bounded by |a1|, |a2| during + the iteration, so no integer overflows */ + while (1) { + if (a2 > 0) { + r = a1/a2; + a1 -= r*a2; + gamma1 -= r*gamma2; + epsilon1 -= r*epsilon2; + } + else { + *a_gcd = a1; + *gamma = gamma1; + *epsilon = epsilon1; + break; + } + + if (a1 > 0) { + r = a2/a1; + a2 -= r*a1; + gamma2 -= r*gamma1; + epsilon2 -= r*epsilon1; + } + else { + *a_gcd = a2; + *gamma = gamma2; + *epsilon = epsilon2; + break; + } + } +} + + +/** + * Precompute GCD and bounds transformations + */ +static int +diophantine_precompute(unsigned int n, + diophantine_term_t *E, + diophantine_term_t *Ep, + npy_int64 *Gamma, npy_int64 *Epsilon) +{ + npy_int64 a_gcd, gamma, epsilon, c1, c2; + unsigned int j; + char overflow = 0; + + assert(n >= 2); + + euclid(E[0].a, E[1].a, &a_gcd, &gamma, &epsilon); + Ep[0].a = a_gcd; + Gamma[0] = gamma; + Epsilon[0] = epsilon; + + if (n > 2) { + c1 = E[0].a / a_gcd; + c2 = E[1].a / a_gcd; + + /* Ep[0].ub = E[0].ub * c1 + E[1].ub * c2; */ + Ep[0].ub = safe_add(safe_mul(E[0].ub, c1, &overflow), + safe_mul(E[1].ub, c2, &overflow), &overflow); + if (overflow) { + return 1; + } + } + + for (j = 2; j < n; ++j) { + euclid(Ep[j-2].a, E[j].a, &a_gcd, &gamma, &epsilon); + Ep[j-1].a = a_gcd; + Gamma[j-1] = gamma; + Epsilon[j-1] = epsilon; + + if (j < n - 1) { + c1 = Ep[j-2].a / a_gcd; + c2 = E[j].a / a_gcd; + + /* Ep[j-1].ub = c1 * Ep[j-2].ub + c2 * E[j].ub; */ + Ep[j-1].ub = safe_add(safe_mul(c1, Ep[j-2].ub, &overflow), + safe_mul(c2, E[j].ub, &overflow), &overflow); + + if (overflow) { + return 1; + } + } + } + + return 0; +} + + +/** + * Depth-first bounded Euclid search + */ +static mem_overlap_t +diophantine_dfs(unsigned int n, + unsigned int v, + diophantine_term_t *E, + diophantine_term_t *Ep, + npy_int64 *Gamma, npy_int64 *Epsilon, + npy_int64 b, + Py_ssize_t max_work, + int require_ub_nontrivial, + npy_int64 *x, + Py_ssize_t *count) +{ + npy_int64 a_gcd, gamma, epsilon, a1, u1, a2, u2, c, r, c1, c2, t, t_l, t_u, b2, x1, x2; + npy_extint128_t x10, x20, t_l1, t_l2, t_u1, t_u2; + mem_overlap_t res; + char overflow = 0; + + if (max_work >= 0 && *count >= max_work) { + return MEM_OVERLAP_TOO_HARD; + } + + /* Fetch precomputed values for the reduced problem */ + if (v == 1) { + a1 = E[0].a; + u1 = E[0].ub; + } + else { + a1 = Ep[v-2].a; + u1 = Ep[v-2].ub; + } + + a2 = E[v].a; + u2 = E[v].ub; + + a_gcd = Ep[v-1].a; + gamma = Gamma[v-1]; + epsilon = Epsilon[v-1]; + + /* Generate set of allowed solutions */ + c = b / a_gcd; + r = b % a_gcd; + if (r != 0) { + ++*count; + return MEM_OVERLAP_NO; + } + + c1 = a2 / a_gcd; + c2 = a1 / a_gcd; + + /* + The set to enumerate is: + x1 = gamma*c + c1*t + x2 = epsilon*c - c2*t + t integer + 0 <= x1 <= u1 + 0 <= x2 <= u2 + and we have c, c1, c2 >= 0 + */ + + x10 = mul_64_64(gamma, c); + x20 = mul_64_64(epsilon, c); + + t_l1 = ceildiv_128_64(neg_128(x10), c1); + t_l2 = ceildiv_128_64(sub_128(x20, to_128(u2), &overflow), c2); + + t_u1 = floordiv_128_64(sub_128(to_128(u1), x10, &overflow), c1); + t_u2 = floordiv_128_64(x20, c2); + + if (overflow) { + return MEM_OVERLAP_OVERFLOW; + } + + if (gt_128(t_l2, t_l1)) { + t_l1 = t_l2; + } + + if (gt_128(t_u1, t_u2)) { + t_u1 = t_u2; + } + + if (gt_128(t_l1, t_u1)) { + ++*count; + return MEM_OVERLAP_NO; + } + + t_l = to_64(t_l1, &overflow); + t_u = to_64(t_u1, &overflow); + + x10 = add_128(x10, mul_64_64(c1, t_l), &overflow); + x20 = sub_128(x20, mul_64_64(c2, t_l), &overflow); + + t_u = safe_sub(t_u, t_l, &overflow); + t_l = 0; + x1 = to_64(x10, &overflow); + x2 = to_64(x20, &overflow); + + if (overflow) { + return MEM_OVERLAP_OVERFLOW; + } + + /* The bounds t_l, t_u ensure the x computed below do not overflow */ + + if (v == 1) { + /* Base case */ + if (t_u >= t_l) { + x[0] = x1 + c1*t_l; + x[1] = x2 - c2*t_l; + if (require_ub_nontrivial) { + int j, is_ub_trivial; + + is_ub_trivial = 1; + for (j = 0; j < n; ++j) { + if (x[j] != E[j].ub/2) { + is_ub_trivial = 0; + break; + } + } + + if (is_ub_trivial) { + /* Ignore 'trivial' solution */ + ++*count; + return MEM_OVERLAP_NO; + } + } + return MEM_OVERLAP_YES; + } + ++*count; + return MEM_OVERLAP_NO; + } + else { + /* Recurse to all candidates */ + for (t = t_l; t <= t_u; ++t) { + x[v] = x2 - c2*t; + + /* b2 = b - a2*x[v]; */ + b2 = safe_sub(b, safe_mul(a2, x[v], &overflow), &overflow); + if (overflow) { + return MEM_OVERLAP_OVERFLOW; + } + + res = diophantine_dfs(n, v-1, E, Ep, Gamma, Epsilon, + b2, max_work, require_ub_nontrivial, + x, count); + if (res != MEM_OVERLAP_NO) { + return res; + } + } + ++*count; + return MEM_OVERLAP_NO; + } +} + + +/** + * Solve bounded Diophantine equation + * + * The problem considered is:: + * + * A[0] x[0] + A[1] x[1] + ... + A[n-1] x[n-1] == b + * 0 <= x[i] <= U[i] + * A[i] > 0 + * + * Solve via depth-first Euclid's algorithm, as explained in [1]. + * + * If require_ub_nontrivial!=0, look for solutions to the problem + * where b = A[0]*(U[0]/2) + ... + A[n]*(U[n-1]/2) but ignoring + * the trivial solution x[i] = U[i]/2. All U[i] must be divisible by 2. + * The value given for `b` is ignored in this case. + */ +NPY_VISIBILITY_HIDDEN mem_overlap_t +solve_diophantine(unsigned int n, diophantine_term_t *E, npy_int64 b, + Py_ssize_t max_work, int require_ub_nontrivial, npy_int64 *x) +{ + mem_overlap_t res; + unsigned int j; + + for (j = 0; j < n; ++j) { + if (E[j].a <= 0) { + return MEM_OVERLAP_ERROR; + } + else if (E[j].ub < 0) { + return MEM_OVERLAP_NO; + } + } + + if (require_ub_nontrivial) { + npy_int64 ub_sum = 0; + char overflow = 0; + for (j = 0; j < n; ++j) { + if (E[j].ub % 2 != 0) { + return MEM_OVERLAP_ERROR; + } + ub_sum = safe_add(ub_sum, + safe_mul(E[j].a, E[j].ub/2, &overflow), + &overflow); + } + if (overflow) { + return MEM_OVERLAP_ERROR; + } + b = ub_sum; + } + + if (b < 0) { + return MEM_OVERLAP_NO; + } + + if (n == 0) { + if (require_ub_nontrivial) { + /* Only trivial solution for 0-variable problem */ + return MEM_OVERLAP_NO; + } + if (b == 0) { + return MEM_OVERLAP_YES; + } + return MEM_OVERLAP_NO; + } + else if (n == 1) { + if (require_ub_nontrivial) { + /* Only trivial solution for 1-variable problem */ + return MEM_OVERLAP_NO; + } + if (b % E[0].a == 0) { + x[0] = b / E[0].a; + if (x[0] >= 0 && x[0] <= E[0].ub) { + return MEM_OVERLAP_YES; + } + } + return MEM_OVERLAP_NO; + } + else { + Py_ssize_t count = 0; + diophantine_term_t *Ep = NULL; + npy_int64 *Epsilon = NULL, *Gamma = NULL; + + Ep = malloc(n * sizeof(diophantine_term_t)); + Epsilon = malloc(n * sizeof(npy_int64)); + Gamma = malloc(n * sizeof(npy_int64)); + if (Ep == NULL || Epsilon == NULL || Gamma == NULL) { + res = MEM_OVERLAP_ERROR; + } + else if (diophantine_precompute(n, E, Ep, Gamma, Epsilon)) { + res = MEM_OVERLAP_OVERFLOW; + } + else { + res = diophantine_dfs(n, n-1, E, Ep, Gamma, Epsilon, b, max_work, + require_ub_nontrivial, x, &count); + } + free(Ep); + free(Gamma); + free(Epsilon); + return res; + } +} + + +static int +diophantine_sort_A(const void *xp, const void *yp) +{ + npy_int64 xa = ((diophantine_term_t*)xp)->a; + npy_int64 ya = ((diophantine_term_t*)yp)->a; + + if (xa < ya) { + return 1; + } + else if (ya < xa) { + return -1; + } + else { + return 0; + } +} + + +/** + * Simplify Diophantine decision problem. + * + * Combine identical coefficients, remove unnecessary variables, and trim + * bounds. + * + * The feasible/infeasible decision result is retained. + * + * Returns: 0 (success), -1 (integer overflow). + */ +NPY_VISIBILITY_HIDDEN int +diophantine_simplify(unsigned int *n, diophantine_term_t *E, npy_int64 b) +{ + unsigned int i, j, m; + char overflow = 0; + + /* Skip obviously infeasible cases */ + for (j = 0; j < *n; ++j) { + if (E[j].ub < 0) { + return 0; + } + } + + if (b < 0) { + return 0; + } + + /* Sort vs. coefficients */ + qsort(E, *n, sizeof(diophantine_term_t), diophantine_sort_A); + + /* Combine identical coefficients */ + m = *n; + i = 0; + for (j = 1; j < m; ++j) { + if (E[i].a == E[j].a) { + E[i].ub = safe_add(E[i].ub, E[j].ub, &overflow); + --*n; + } + else { + ++i; + if (i != j) { + E[i] = E[j]; + } + } + } + + /* Trim bounds and remove unnecessary variables */ + m = *n; + i = 0; + for (j = 0; j < m; ++j) { + E[j].ub = MIN(E[j].ub, b / E[j].a); + if (E[j].ub == 0) { + /* If the problem is feasible at all, x[i]=0 */ + --*n; + } + else { + if (i != j) { + E[i] = E[j]; + } + ++i; + } + } + + if (overflow) { + return -1; + } + else { + return 0; + } +} + + +/* Gets a half-open range [start, end) of offsets from the data pointer */ +NPY_VISIBILITY_HIDDEN void +offset_bounds_from_strides(const int itemsize, const int nd, + const npy_intp *dims, const npy_intp *strides, + npy_intp *lower_offset, npy_intp *upper_offset) +{ + npy_intp max_axis_offset; + npy_intp lower = 0; + npy_intp upper = 0; + int i; + + for (i = 0; i < nd; i++) { + if (dims[i] == 0) { + /* If the array size is zero, return an empty range */ + *lower_offset = 0; + *upper_offset = 0; + return; + } + /* Expand either upwards or downwards depending on stride */ + max_axis_offset = strides[i] * (dims[i] - 1); + if (max_axis_offset > 0) { + upper += max_axis_offset; + } + else { + lower += max_axis_offset; + } + } + /* Return a half-open range */ + upper += itemsize; + *lower_offset = lower; + *upper_offset = upper; +} + + +/* Gets a half-open range [start, end) which contains the array data */ +static void +get_array_memory_extents(PyArrayObject *arr, + npy_uintp *out_start, npy_uintp *out_end, + npy_uintp *num_bytes) +{ + npy_intp low, upper; + int j; + offset_bounds_from_strides(PyArray_ITEMSIZE(arr), PyArray_NDIM(arr), + PyArray_DIMS(arr), PyArray_STRIDES(arr), + &low, &upper); + *out_start = (npy_uintp)PyArray_DATA(arr) + (npy_uintp)low; + *out_end = (npy_uintp)PyArray_DATA(arr) + (npy_uintp)upper; + + *num_bytes = PyArray_ITEMSIZE(arr); + for (j = 0; j < PyArray_NDIM(arr); ++j) { + *num_bytes *= PyArray_DIM(arr, j); + } +} + + +static int +strides_to_terms(PyArrayObject *arr, diophantine_term_t *terms, + unsigned int *nterms, int skip_empty) +{ + unsigned int i; + + for (i = 0; i < PyArray_NDIM(arr); ++i) { + if (skip_empty) { + if (PyArray_DIM(arr, i) <= 1 || PyArray_STRIDE(arr, i) == 0) { + continue; + } + } + + terms[*nterms].a = PyArray_STRIDE(arr, i); + + if (terms[*nterms].a < 0) { + terms[*nterms].a = -terms[*nterms].a; + } + + if (terms[*nterms].a < 0) { + /* integer overflow */ + return 1; + } + + terms[*nterms].ub = PyArray_DIM(arr, i) - 1; + ++*nterms; + } + + return 0; +} + + +/** + * Determine whether two arrays share some memory. + * + * Returns: 0 (no shared memory), 1 (shared memory), or < 0 (failed to solve). + * + * Note that failures to solve can occur due to integer overflows, or effort + * required solving the problem exceeding max_work. The general problem is + * NP-hard and worst case runtime is exponential in the number of dimensions. + * max_work controls the amount of work done, either exact (max_work == -1), only + * a simple memory extent check (max_work == 0), or set an upper bound + * max_work > 0 for the number of solution candidates considered. + */ +NPY_VISIBILITY_HIDDEN mem_overlap_t +solve_may_share_memory(PyArrayObject *a, PyArrayObject *b, + Py_ssize_t max_work) +{ + npy_int64 rhs; + diophantine_term_t terms[2*NPY_MAXDIMS+2]; + npy_uintp start1 = 0, start2 = 0, end1 = 0, end2 = 0, size1 = 0, size2 = 0; + npy_int64 x[2*NPY_MAXDIMS+2]; + unsigned int nterms; + + get_array_memory_extents(a, &start1, &end1, &size1); + get_array_memory_extents(b, &start2, &end2, &size2); + + if (!(start1 < end2 && start2 < end1 && start1 < end1 && start2 < end2)) { + /* Memory extents don't overlap */ + return MEM_OVERLAP_NO; + } + + if (max_work == 0) { + /* Too much work required, give up */ + return MEM_OVERLAP_TOO_HARD; + } + + /* Convert problem to Diophantine equation form with positive coefficients. + The bounds computed by offset_bounds_from_strides correspond to + all-positive strides. + + start1 + sum(abs(stride1)*x1) + == start2 + sum(abs(stride2)*x2) + == end1 - 1 - sum(abs(stride1)*x1') + == end2 - 1 - sum(abs(stride2)*x2') + + <=> + + sum(abs(stride1)*x1) + sum(abs(stride2)*x2') + == end2 - 1 - start1 + + OR + + sum(abs(stride1)*x1') + sum(abs(stride2)*x2) + == end1 - 1 - start2 + + We pick the problem with the smaller RHS (they are non-negative due to + the extent check above.) + */ + + rhs = MIN(end2 - 1 - start1, end1 - 1 - start2); + + if (rhs != (npy_uintp)rhs) { + /* Integer overflow */ + return MEM_OVERLAP_OVERFLOW; + } + + nterms = 0; + if (strides_to_terms(a, terms, &nterms, 1)) { + return MEM_OVERLAP_OVERFLOW; + } + if (strides_to_terms(b, terms, &nterms, 1)) { + return MEM_OVERLAP_OVERFLOW; + } + if (PyArray_ITEMSIZE(a) > 1) { + terms[nterms].a = 1; + terms[nterms].ub = PyArray_ITEMSIZE(a) - 1; + ++nterms; + } + if (PyArray_ITEMSIZE(b) > 1) { + terms[nterms].a = 1; + terms[nterms].ub = PyArray_ITEMSIZE(b) - 1; + ++nterms; + } + + /* Simplify, if possible */ + if (diophantine_simplify(&nterms, terms, rhs)) { + /* Integer overflow */ + return MEM_OVERLAP_OVERFLOW; + } + + /* Solve */ + return solve_diophantine(nterms, terms, rhs, max_work, 0, x); +} + + +/** + * Determine whether an array has internal overlap. + * + * Returns: 0 (no overlap), 1 (overlap), or < 0 (failed to solve). + * + * max_work and reasons for solver failures are as in solve_may_share_memory. + */ +NPY_VISIBILITY_HIDDEN mem_overlap_t +solve_may_have_internal_overlap(PyArrayObject *a, Py_ssize_t max_work) +{ + diophantine_term_t terms[NPY_MAXDIMS+1]; + npy_int64 x[NPY_MAXDIMS+1]; + unsigned int nterms; + int i, j; + + if (PyArray_ISCONTIGUOUS(a)) { + /* Quick case */ + return MEM_OVERLAP_NO; + } + + /* The internal memory overlap problem is looking for two different + solutions to + + sum(a*x) = b, 0 <= x[i] <= ub[i] + + for any b. Equivalently, + + sum(a*x0) - sum(a*x1) = 0 + + Mapping the coefficients on the left by x0'[i] = x0[i] if a[i] > 0 + else ub[i]-x0[i] and opposite for x1, we have + + sum(abs(a)*(x0' + x1')) = sum(abs(a)*ub) + + Now, x0!=x1 if for some i we have x0'[i] + x1'[i] != ub[i]. + We can now change variables to z[i] = x0'[i] + x1'[i] so the problem + becomes + + sum(abs(a)*z) = sum(abs(a)*ub), 0 <= z[i] <= 2*ub[i], z != ub + + This can be solved with solve_diophantine. + */ + + nterms = 0; + if (strides_to_terms(a, terms, &nterms, 0)) { + return MEM_OVERLAP_OVERFLOW; + } + if (PyArray_ITEMSIZE(a) > 1) { + terms[nterms].a = 1; + terms[nterms].ub = PyArray_ITEMSIZE(a) - 1; + ++nterms; + } + + /* Get rid of zero coefficients and empty terms */ + i = 0; + for (j = 0; j < nterms; ++j) { + if (terms[j].ub == 0) { + continue; + } + else if (terms[j].ub < 0) { + return MEM_OVERLAP_NO; + } + else if (terms[j].a == 0) { + return MEM_OVERLAP_YES; + } + if (i != j) { + terms[i] = terms[j]; + } + ++i; + } + nterms = i; + + /* Double bounds to get the internal overlap problem */ + for (j = 0; j < nterms; ++j) { + terms[j].ub *= 2; + } + + /* Sort vs. coefficients; cannot call diophantine_simplify because it may + change the decision problem inequality part */ + qsort(terms, nterms, sizeof(diophantine_term_t), diophantine_sort_A); + + /* Solve */ + return solve_diophantine(nterms, terms, -1, max_work, 1, x); +} diff --git a/numpy/core/src/private/mem_overlap.h b/numpy/core/src/private/mem_overlap.h new file mode 100644 index 0000000..8044f16 --- /dev/null +++ b/numpy/core/src/private/mem_overlap.h @@ -0,0 +1,50 @@ +#ifndef MEM_OVERLAP_H_ +#define MEM_OVERLAP_H_ + +#include "npy_config.h" +#include "numpy/ndarraytypes.h" + + +/* Bounds check only */ +#define NPY_MAY_SHARE_BOUNDS 0 + +/* Exact solution */ +#define NPY_MAY_SHARE_EXACT -1 + + +typedef enum { + MEM_OVERLAP_NO = 0, /* no solution exists */ + MEM_OVERLAP_YES = 1, /* solution found */ + MEM_OVERLAP_TOO_HARD = -1, /* max_work exceeded */ + MEM_OVERLAP_OVERFLOW = -2, /* algorithm failed due to integer overflow */ + MEM_OVERLAP_ERROR = -3 /* invalid input */ +} mem_overlap_t; + + +typedef struct { + npy_int64 a; + npy_int64 ub; +} diophantine_term_t; + +NPY_VISIBILITY_HIDDEN mem_overlap_t +solve_diophantine(unsigned int n, diophantine_term_t *E, + npy_int64 b, Py_ssize_t max_work, int require_nontrivial, + npy_int64 *x); + +NPY_VISIBILITY_HIDDEN int +diophantine_simplify(unsigned int *n, diophantine_term_t *E, npy_int64 b); + +NPY_VISIBILITY_HIDDEN mem_overlap_t +solve_may_share_memory(PyArrayObject *a, PyArrayObject *b, + Py_ssize_t max_work); + +NPY_VISIBILITY_HIDDEN mem_overlap_t +solve_may_have_internal_overlap(PyArrayObject *a, Py_ssize_t max_work); + +NPY_VISIBILITY_HIDDEN void +offset_bounds_from_strides(const int itemsize, const int nd, + const npy_intp *dims, const npy_intp *strides, + npy_intp *lower_offset, npy_intp *upper_offset); + +#endif + diff --git a/numpy/core/src/private/npy_binsearch.h.src b/numpy/core/src/private/npy_binsearch.h.src new file mode 100644 index 0000000..3b2c594 --- /dev/null +++ b/numpy/core/src/private/npy_binsearch.h.src @@ -0,0 +1,140 @@ +#ifndef __NPY_BINSEARCH_H__ +#define __NPY_BINSEARCH_H__ + +#include "npy_sort.h" +#include +#include + +typedef void (PyArray_BinSearchFunc)(const char*, const char*, char*, + npy_intp, npy_intp, + npy_intp, npy_intp, npy_intp, + PyArrayObject*); + +typedef int (PyArray_ArgBinSearchFunc)(const char*, const char*, + const char*, char*, + npy_intp, npy_intp, npy_intp, + npy_intp, npy_intp, npy_intp, + PyArrayObject*); + +struct binsearch_map { + enum NPY_TYPES typenum; + PyArray_BinSearchFunc *binsearch[NPY_NSEARCHSIDES]; +}; + +struct argbinsearch_map { + enum NPY_TYPES typenum; + PyArray_ArgBinSearchFunc *argbinsearch[NPY_NSEARCHSIDES]; +}; + +/**begin repeat + * + * #side = left, right# + */ + +/**begin repeat1 + * + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, half, float, double, longdouble, + * cfloat, cdouble, clongdouble, datetime, timedelta# + */ + +NPY_VISIBILITY_HIDDEN void +binsearch_@side@_@suff@(const char *arr, const char *key, char *ret, + npy_intp arr_len, npy_intp key_len, + npy_intp arr_str, npy_intp key_str, npy_intp ret_str, + PyArrayObject *unused); +NPY_VISIBILITY_HIDDEN int +argbinsearch_@side@_@suff@(const char *arr, const char *key, + const char *sort, char *ret, + npy_intp arr_len, npy_intp key_len, + npy_intp arr_str, npy_intp key_str, + npy_intp sort_str, npy_intp ret_str, + PyArrayObject *unused); +/**end repeat1**/ + +NPY_VISIBILITY_HIDDEN void +npy_binsearch_@side@(const char *arr, const char *key, char *ret, + npy_intp arr_len, npy_intp key_len, + npy_intp arr_str, npy_intp key_str, + npy_intp ret_str, PyArrayObject *cmp); +NPY_VISIBILITY_HIDDEN int +npy_argbinsearch_@side@(const char *arr, const char *key, + const char *sort, char *ret, + npy_intp arr_len, npy_intp key_len, + npy_intp arr_str, npy_intp key_str, + npy_intp sort_str, npy_intp ret_str, + PyArrayObject *cmp); +/**end repeat**/ + +/**begin repeat + * + * #arg = , arg# + * #Arg = , Arg# + */ + +static struct @arg@binsearch_map _@arg@binsearch_map[] = { + /* If adding new types, make sure to keep them ordered by type num */ + /**begin repeat1 + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA, HALF# + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, float, double, longdouble, + * cfloat, cdouble, clongdouble, datetime, timedelta, half# + */ + {NPY_@TYPE@, + { + &@arg@binsearch_left_@suff@, + &@arg@binsearch_right_@suff@, + }, + }, + /**end repeat1**/ +}; + +static PyArray_@Arg@BinSearchFunc *gen@arg@binsearch_map[] = { + &npy_@arg@binsearch_left, + &npy_@arg@binsearch_right, +}; + +static NPY_INLINE PyArray_@Arg@BinSearchFunc* +get_@arg@binsearch_func(PyArray_Descr *dtype, NPY_SEARCHSIDE side) +{ + static npy_intp num_funcs = sizeof(_@arg@binsearch_map) / + sizeof(_@arg@binsearch_map[0]); + npy_intp min_idx = 0; + npy_intp max_idx = num_funcs; + int type = dtype->type_num; + + if (side >= NPY_NSEARCHSIDES) { + return NULL; + } + + /* + * It seems only fair that a binary search function be searched for + * using a binary search... + */ + while (min_idx < max_idx) { + npy_intp mid_idx = min_idx + ((max_idx - min_idx) >> 1); + + if (_@arg@binsearch_map[mid_idx].typenum < type) { + min_idx = mid_idx + 1; + } + else { + max_idx = mid_idx; + } + } + + if (min_idx < num_funcs && _@arg@binsearch_map[min_idx].typenum == type) { + return _@arg@binsearch_map[min_idx].@arg@binsearch[side]; + } + + if (dtype->f->compare) { + return gen@arg@binsearch_map[side]; + } + + return NULL; +} +/**end repeat**/ + +#endif diff --git a/numpy/core/src/private/npy_cblas.h b/numpy/core/src/private/npy_cblas.h new file mode 100644 index 0000000..a083f3b --- /dev/null +++ b/numpy/core/src/private/npy_cblas.h @@ -0,0 +1,584 @@ +/* + * This header provides numpy a consistent interface to CBLAS code. It is needed + * because not all providers of cblas provide cblas.h. For instance, MKL provides + * mkl_cblas.h and also typedefs the CBLAS_XXX enums. + */ +#ifndef _NPY_CBLAS_H_ +#define _NPY_CBLAS_H_ + +#include + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * Enumerated and derived types + */ +#define CBLAS_INDEX size_t /* this may vary between platforms */ + +enum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102}; +enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113}; +enum CBLAS_UPLO {CblasUpper=121, CblasLower=122}; +enum CBLAS_DIAG {CblasNonUnit=131, CblasUnit=132}; +enum CBLAS_SIDE {CblasLeft=141, CblasRight=142}; + +/* + * =========================================================================== + * Prototypes for level 1 BLAS functions (complex are recast as routines) + * =========================================================================== + */ +float cblas_sdsdot(const int N, const float alpha, const float *X, + const int incX, const float *Y, const int incY); +double cblas_dsdot(const int N, const float *X, const int incX, const float *Y, + const int incY); +float cblas_sdot(const int N, const float *X, const int incX, + const float *Y, const int incY); +double cblas_ddot(const int N, const double *X, const int incX, + const double *Y, const int incY); + +/* + * Functions having prefixes Z and C only + */ +void cblas_cdotu_sub(const int N, const void *X, const int incX, + const void *Y, const int incY, void *dotu); +void cblas_cdotc_sub(const int N, const void *X, const int incX, + const void *Y, const int incY, void *dotc); + +void cblas_zdotu_sub(const int N, const void *X, const int incX, + const void *Y, const int incY, void *dotu); +void cblas_zdotc_sub(const int N, const void *X, const int incX, + const void *Y, const int incY, void *dotc); + + +/* + * Functions having prefixes S D SC DZ + */ +float cblas_snrm2(const int N, const float *X, const int incX); +float cblas_sasum(const int N, const float *X, const int incX); + +double cblas_dnrm2(const int N, const double *X, const int incX); +double cblas_dasum(const int N, const double *X, const int incX); + +float cblas_scnrm2(const int N, const void *X, const int incX); +float cblas_scasum(const int N, const void *X, const int incX); + +double cblas_dznrm2(const int N, const void *X, const int incX); +double cblas_dzasum(const int N, const void *X, const int incX); + + +/* + * Functions having standard 4 prefixes (S D C Z) + */ +CBLAS_INDEX cblas_isamax(const int N, const float *X, const int incX); +CBLAS_INDEX cblas_idamax(const int N, const double *X, const int incX); +CBLAS_INDEX cblas_icamax(const int N, const void *X, const int incX); +CBLAS_INDEX cblas_izamax(const int N, const void *X, const int incX); + +/* + * =========================================================================== + * Prototypes for level 1 BLAS routines + * =========================================================================== + */ + +/* + * Routines with standard 4 prefixes (s, d, c, z) + */ +void cblas_sswap(const int N, float *X, const int incX, + float *Y, const int incY); +void cblas_scopy(const int N, const float *X, const int incX, + float *Y, const int incY); +void cblas_saxpy(const int N, const float alpha, const float *X, + const int incX, float *Y, const int incY); + +void cblas_dswap(const int N, double *X, const int incX, + double *Y, const int incY); +void cblas_dcopy(const int N, const double *X, const int incX, + double *Y, const int incY); +void cblas_daxpy(const int N, const double alpha, const double *X, + const int incX, double *Y, const int incY); + +void cblas_cswap(const int N, void *X, const int incX, + void *Y, const int incY); +void cblas_ccopy(const int N, const void *X, const int incX, + void *Y, const int incY); +void cblas_caxpy(const int N, const void *alpha, const void *X, + const int incX, void *Y, const int incY); + +void cblas_zswap(const int N, void *X, const int incX, + void *Y, const int incY); +void cblas_zcopy(const int N, const void *X, const int incX, + void *Y, const int incY); +void cblas_zaxpy(const int N, const void *alpha, const void *X, + const int incX, void *Y, const int incY); + + +/* + * Routines with S and D prefix only + */ +void cblas_srotg(float *a, float *b, float *c, float *s); +void cblas_srotmg(float *d1, float *d2, float *b1, const float b2, float *P); +void cblas_srot(const int N, float *X, const int incX, + float *Y, const int incY, const float c, const float s); +void cblas_srotm(const int N, float *X, const int incX, + float *Y, const int incY, const float *P); + +void cblas_drotg(double *a, double *b, double *c, double *s); +void cblas_drotmg(double *d1, double *d2, double *b1, const double b2, double *P); +void cblas_drot(const int N, double *X, const int incX, + double *Y, const int incY, const double c, const double s); +void cblas_drotm(const int N, double *X, const int incX, + double *Y, const int incY, const double *P); + + +/* + * Routines with S D C Z CS and ZD prefixes + */ +void cblas_sscal(const int N, const float alpha, float *X, const int incX); +void cblas_dscal(const int N, const double alpha, double *X, const int incX); +void cblas_cscal(const int N, const void *alpha, void *X, const int incX); +void cblas_zscal(const int N, const void *alpha, void *X, const int incX); +void cblas_csscal(const int N, const float alpha, void *X, const int incX); +void cblas_zdscal(const int N, const double alpha, void *X, const int incX); + +/* + * =========================================================================== + * Prototypes for level 2 BLAS + * =========================================================================== + */ + +/* + * Routines with standard 4 prefixes (S, D, C, Z) + */ +void cblas_sgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const float alpha, const float *A, const int lda, + const float *X, const int incX, const float beta, + float *Y, const int incY); +void cblas_sgbmv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const int KL, const int KU, const float alpha, + const float *A, const int lda, const float *X, + const int incX, const float beta, float *Y, const int incY); +void cblas_strmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const float *A, const int lda, + float *X, const int incX); +void cblas_stbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const int K, const float *A, const int lda, + float *X, const int incX); +void cblas_stpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const float *Ap, float *X, const int incX); +void cblas_strsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const float *A, const int lda, float *X, + const int incX); +void cblas_stbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const int K, const float *A, const int lda, + float *X, const int incX); +void cblas_stpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const float *Ap, float *X, const int incX); + +void cblas_dgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const double alpha, const double *A, const int lda, + const double *X, const int incX, const double beta, + double *Y, const int incY); +void cblas_dgbmv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const int KL, const int KU, const double alpha, + const double *A, const int lda, const double *X, + const int incX, const double beta, double *Y, const int incY); +void cblas_dtrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const double *A, const int lda, + double *X, const int incX); +void cblas_dtbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const int K, const double *A, const int lda, + double *X, const int incX); +void cblas_dtpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const double *Ap, double *X, const int incX); +void cblas_dtrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const double *A, const int lda, double *X, + const int incX); +void cblas_dtbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const int K, const double *A, const int lda, + double *X, const int incX); +void cblas_dtpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const double *Ap, double *X, const int incX); + +void cblas_cgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const void *alpha, const void *A, const int lda, + const void *X, const int incX, const void *beta, + void *Y, const int incY); +void cblas_cgbmv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const int KL, const int KU, const void *alpha, + const void *A, const int lda, const void *X, + const int incX, const void *beta, void *Y, const int incY); +void cblas_ctrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const void *A, const int lda, + void *X, const int incX); +void cblas_ctbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const int K, const void *A, const int lda, + void *X, const int incX); +void cblas_ctpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const void *Ap, void *X, const int incX); +void cblas_ctrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const void *A, const int lda, void *X, + const int incX); +void cblas_ctbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const int K, const void *A, const int lda, + void *X, const int incX); +void cblas_ctpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const void *Ap, void *X, const int incX); + +void cblas_zgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const void *alpha, const void *A, const int lda, + const void *X, const int incX, const void *beta, + void *Y, const int incY); +void cblas_zgbmv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + const int KL, const int KU, const void *alpha, + const void *A, const int lda, const void *X, + const int incX, const void *beta, void *Y, const int incY); +void cblas_ztrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const void *A, const int lda, + void *X, const int incX); +void cblas_ztbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const int K, const void *A, const int lda, + void *X, const int incX); +void cblas_ztpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const void *Ap, void *X, const int incX); +void cblas_ztrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const void *A, const int lda, void *X, + const int incX); +void cblas_ztbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const int K, const void *A, const int lda, + void *X, const int incX); +void cblas_ztpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const int N, const void *Ap, void *X, const int incX); + + +/* + * Routines with S and D prefixes only + */ +void cblas_ssymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const float alpha, const float *A, + const int lda, const float *X, const int incX, + const float beta, float *Y, const int incY); +void cblas_ssbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const int K, const float alpha, const float *A, + const int lda, const float *X, const int incX, + const float beta, float *Y, const int incY); +void cblas_sspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const float alpha, const float *Ap, + const float *X, const int incX, + const float beta, float *Y, const int incY); +void cblas_sger(const enum CBLAS_ORDER order, const int M, const int N, + const float alpha, const float *X, const int incX, + const float *Y, const int incY, float *A, const int lda); +void cblas_ssyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const float alpha, const float *X, + const int incX, float *A, const int lda); +void cblas_sspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const float alpha, const float *X, + const int incX, float *Ap); +void cblas_ssyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const float alpha, const float *X, + const int incX, const float *Y, const int incY, float *A, + const int lda); +void cblas_sspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const float alpha, const float *X, + const int incX, const float *Y, const int incY, float *A); + +void cblas_dsymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const double alpha, const double *A, + const int lda, const double *X, const int incX, + const double beta, double *Y, const int incY); +void cblas_dsbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const int K, const double alpha, const double *A, + const int lda, const double *X, const int incX, + const double beta, double *Y, const int incY); +void cblas_dspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const double alpha, const double *Ap, + const double *X, const int incX, + const double beta, double *Y, const int incY); +void cblas_dger(const enum CBLAS_ORDER order, const int M, const int N, + const double alpha, const double *X, const int incX, + const double *Y, const int incY, double *A, const int lda); +void cblas_dsyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const double alpha, const double *X, + const int incX, double *A, const int lda); +void cblas_dspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const double alpha, const double *X, + const int incX, double *Ap); +void cblas_dsyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const double alpha, const double *X, + const int incX, const double *Y, const int incY, double *A, + const int lda); +void cblas_dspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const double alpha, const double *X, + const int incX, const double *Y, const int incY, double *A); + + +/* + * Routines with C and Z prefixes only + */ +void cblas_chemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const void *alpha, const void *A, + const int lda, const void *X, const int incX, + const void *beta, void *Y, const int incY); +void cblas_chbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const int K, const void *alpha, const void *A, + const int lda, const void *X, const int incX, + const void *beta, void *Y, const int incY); +void cblas_chpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const void *alpha, const void *Ap, + const void *X, const int incX, + const void *beta, void *Y, const int incY); +void cblas_cgeru(const enum CBLAS_ORDER order, const int M, const int N, + const void *alpha, const void *X, const int incX, + const void *Y, const int incY, void *A, const int lda); +void cblas_cgerc(const enum CBLAS_ORDER order, const int M, const int N, + const void *alpha, const void *X, const int incX, + const void *Y, const int incY, void *A, const int lda); +void cblas_cher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const float alpha, const void *X, const int incX, + void *A, const int lda); +void cblas_chpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const float alpha, const void *X, + const int incX, void *A); +void cblas_cher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N, + const void *alpha, const void *X, const int incX, + const void *Y, const int incY, void *A, const int lda); +void cblas_chpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N, + const void *alpha, const void *X, const int incX, + const void *Y, const int incY, void *Ap); + +void cblas_zhemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const void *alpha, const void *A, + const int lda, const void *X, const int incX, + const void *beta, void *Y, const int incY); +void cblas_zhbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const int K, const void *alpha, const void *A, + const int lda, const void *X, const int incX, + const void *beta, void *Y, const int incY); +void cblas_zhpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const void *alpha, const void *Ap, + const void *X, const int incX, + const void *beta, void *Y, const int incY); +void cblas_zgeru(const enum CBLAS_ORDER order, const int M, const int N, + const void *alpha, const void *X, const int incX, + const void *Y, const int incY, void *A, const int lda); +void cblas_zgerc(const enum CBLAS_ORDER order, const int M, const int N, + const void *alpha, const void *X, const int incX, + const void *Y, const int incY, void *A, const int lda); +void cblas_zher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const double alpha, const void *X, const int incX, + void *A, const int lda); +void cblas_zhpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const int N, const double alpha, const void *X, + const int incX, void *A); +void cblas_zher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N, + const void *alpha, const void *X, const int incX, + const void *Y, const int incY, void *A, const int lda); +void cblas_zhpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N, + const void *alpha, const void *X, const int incX, + const void *Y, const int incY, void *Ap); + +/* + * =========================================================================== + * Prototypes for level 3 BLAS + * =========================================================================== + */ + +/* + * Routines with standard 4 prefixes (S, D, C, Z) + */ +void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_TRANSPOSE TransB, const int M, const int N, + const int K, const float alpha, const float *A, + const int lda, const float *B, const int ldb, + const float beta, float *C, const int ldc); +void cblas_ssymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const int M, const int N, + const float alpha, const float *A, const int lda, + const float *B, const int ldb, const float beta, + float *C, const int ldc); +void cblas_ssyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const float alpha, const float *A, const int lda, + const float beta, float *C, const int ldc); +void cblas_ssyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const float alpha, const float *A, const int lda, + const float *B, const int ldb, const float beta, + float *C, const int ldc); +void cblas_strmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const int M, const int N, + const float alpha, const float *A, const int lda, + float *B, const int ldb); +void cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const int M, const int N, + const float alpha, const float *A, const int lda, + float *B, const int ldb); + +void cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_TRANSPOSE TransB, const int M, const int N, + const int K, const double alpha, const double *A, + const int lda, const double *B, const int ldb, + const double beta, double *C, const int ldc); +void cblas_dsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const int M, const int N, + const double alpha, const double *A, const int lda, + const double *B, const int ldb, const double beta, + double *C, const int ldc); +void cblas_dsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const double alpha, const double *A, const int lda, + const double beta, double *C, const int ldc); +void cblas_dsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const double alpha, const double *A, const int lda, + const double *B, const int ldb, const double beta, + double *C, const int ldc); +void cblas_dtrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const int M, const int N, + const double alpha, const double *A, const int lda, + double *B, const int ldb); +void cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const int M, const int N, + const double alpha, const double *A, const int lda, + double *B, const int ldb); + +void cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_TRANSPOSE TransB, const int M, const int N, + const int K, const void *alpha, const void *A, + const int lda, const void *B, const int ldb, + const void *beta, void *C, const int ldc); +void cblas_csymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const int M, const int N, + const void *alpha, const void *A, const int lda, + const void *B, const int ldb, const void *beta, + void *C, const int ldc); +void cblas_csyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const void *alpha, const void *A, const int lda, + const void *beta, void *C, const int ldc); +void cblas_csyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const void *alpha, const void *A, const int lda, + const void *B, const int ldb, const void *beta, + void *C, const int ldc); +void cblas_ctrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const int M, const int N, + const void *alpha, const void *A, const int lda, + void *B, const int ldb); +void cblas_ctrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const int M, const int N, + const void *alpha, const void *A, const int lda, + void *B, const int ldb); + +void cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_TRANSPOSE TransB, const int M, const int N, + const int K, const void *alpha, const void *A, + const int lda, const void *B, const int ldb, + const void *beta, void *C, const int ldc); +void cblas_zsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const int M, const int N, + const void *alpha, const void *A, const int lda, + const void *B, const int ldb, const void *beta, + void *C, const int ldc); +void cblas_zsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const void *alpha, const void *A, const int lda, + const void *beta, void *C, const int ldc); +void cblas_zsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const void *alpha, const void *A, const int lda, + const void *B, const int ldb, const void *beta, + void *C, const int ldc); +void cblas_ztrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const int M, const int N, + const void *alpha, const void *A, const int lda, + void *B, const int ldb); +void cblas_ztrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const int M, const int N, + const void *alpha, const void *A, const int lda, + void *B, const int ldb); + + +/* + * Routines with prefixes C and Z only + */ +void cblas_chemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const int M, const int N, + const void *alpha, const void *A, const int lda, + const void *B, const int ldb, const void *beta, + void *C, const int ldc); +void cblas_cherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const float alpha, const void *A, const int lda, + const float beta, void *C, const int ldc); +void cblas_cher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const void *alpha, const void *A, const int lda, + const void *B, const int ldb, const float beta, + void *C, const int ldc); + +void cblas_zhemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const int M, const int N, + const void *alpha, const void *A, const int lda, + const void *B, const int ldb, const void *beta, + void *C, const int ldc); +void cblas_zherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const double alpha, const void *A, const int lda, + const double beta, void *C, const int ldc); +void cblas_zher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const int N, const int K, + const void *alpha, const void *A, const int lda, + const void *B, const int ldb, const double beta, + void *C, const int ldc); + +void cblas_xerbla(int p, const char *rout, const char *form, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/numpy/core/src/private/npy_config.h b/numpy/core/src/private/npy_config.h new file mode 100644 index 0000000..107b3cb --- /dev/null +++ b/numpy/core/src/private/npy_config.h @@ -0,0 +1,122 @@ +#ifndef _NPY_NPY_CONFIG_H_ +#define _NPY_NPY_CONFIG_H_ + +#include "config.h" +#include "numpy/numpyconfig.h" +#include "numpy/npy_cpu.h" +#include "numpy/npy_os.h" + +/* + * largest alignment the copy loops might require + * required as string, void and complex types might get copied using larger + * instructions than required to operate on them. E.g. complex float is copied + * in 8 byte moves but arithmetic on them only loads in 4 byte moves. + * the sparc platform may need that alignment for long doubles. + * amd64 is not harmed much by the bloat as the system provides 16 byte + * alignment by default. + */ +#if (defined NPY_CPU_X86 || defined _WIN32) +#define NPY_MAX_COPY_ALIGNMENT 8 +#else +#define NPY_MAX_COPY_ALIGNMENT 16 +#endif + +/* blacklist */ + +/* Disable broken Sun Workshop Pro math functions */ +#ifdef __SUNPRO_C + +#undef HAVE_ATAN2 +#undef HAVE_ATAN2F +#undef HAVE_ATAN2L + +#endif + +/* Disable broken MS math functions */ +#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__MINGW32_VERSION) + +#undef HAVE_ATAN2 +#undef HAVE_ATAN2F +#undef HAVE_ATAN2L + +#undef HAVE_HYPOT +#undef HAVE_HYPOTF +#undef HAVE_HYPOTL + +#endif + +#if defined(_MSC_VER) && (_MSC_VER == 1900) + +#undef HAVE_CASIN +#undef HAVE_CASINF +#undef HAVE_CASINL +#undef HAVE_CASINH +#undef HAVE_CASINHF +#undef HAVE_CASINHL +#undef HAVE_CATAN +#undef HAVE_CATANF +#undef HAVE_CATANL +#undef HAVE_CATANH +#undef HAVE_CATANHF +#undef HAVE_CATANHL + +#endif + +/* MSVC _hypot messes with fp precision mode on 32-bit, see gh-9567 */ +#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(_WIN64) + +#undef HAVE_CABS +#undef HAVE_CABSF +#undef HAVE_CABSL + +#undef HAVE_HYPOT +#undef HAVE_HYPOTF +#undef HAVE_HYPOTL + +#endif + + +/* Intel C for Windows uses POW for 64 bits longdouble*/ +#if defined(_MSC_VER) && defined(__INTEL_COMPILER) +#if defined(HAVE_POWL) && (NPY_SIZEOF_LONGDOUBLE == 8) +#undef HAVE_POWL +#endif +#endif /* defined(_MSC_VER) && defined(__INTEL_COMPILER) */ + +/* powl gives zero division warning on OS X, see gh-8307 */ +#if defined(HAVE_POWL) && defined(NPY_OS_DARWIN) +#undef HAVE_POWL +#endif + +/* Disable broken gnu trig functions */ +#if defined(HAVE_FEATURES_H) +#include + +#if defined(__GLIBC__) +#if !__GLIBC_PREREQ(2, 18) + +#undef HAVE_CASIN +#undef HAVE_CASINF +#undef HAVE_CASINL +#undef HAVE_CASINH +#undef HAVE_CASINHF +#undef HAVE_CASINHL +#undef HAVE_CATAN +#undef HAVE_CATANF +#undef HAVE_CATANL +#undef HAVE_CATANH +#undef HAVE_CATANHF +#undef HAVE_CATANHL +#undef HAVE_CACOS +#undef HAVE_CACOSF +#undef HAVE_CACOSL +#undef HAVE_CACOSH +#undef HAVE_CACOSHF +#undef HAVE_CACOSHL + +#endif /* __GLIBC_PREREQ(2, 18) */ +#endif /* defined(__GLIBC_PREREQ) */ + +#endif /* defined(HAVE_FEATURES_H) */ + +#endif diff --git a/numpy/core/src/private/npy_extint128.h b/numpy/core/src/private/npy_extint128.h new file mode 100644 index 0000000..a887ff3 --- /dev/null +++ b/numpy/core/src/private/npy_extint128.h @@ -0,0 +1,317 @@ +#ifndef NPY_EXTINT128_H_ +#define NPY_EXTINT128_H_ + + +typedef struct { + signed char sign; + npy_uint64 lo, hi; +} npy_extint128_t; + + +/* Integer addition with overflow checking */ +static NPY_INLINE npy_int64 +safe_add(npy_int64 a, npy_int64 b, char *overflow_flag) +{ + if (a > 0 && b > NPY_MAX_INT64 - a) { + *overflow_flag = 1; + } + else if (a < 0 && b < NPY_MIN_INT64 - a) { + *overflow_flag = 1; + } + return a + b; +} + + +/* Integer subtraction with overflow checking */ +static NPY_INLINE npy_int64 +safe_sub(npy_int64 a, npy_int64 b, char *overflow_flag) +{ + if (a >= 0 && b < a - NPY_MAX_INT64) { + *overflow_flag = 1; + } + else if (a < 0 && b > a - NPY_MIN_INT64) { + *overflow_flag = 1; + } + return a - b; +} + + +/* Integer multiplication with overflow checking */ +static NPY_INLINE npy_int64 +safe_mul(npy_int64 a, npy_int64 b, char *overflow_flag) +{ + if (a > 0) { + if (b > NPY_MAX_INT64 / a || b < NPY_MIN_INT64 / a) { + *overflow_flag = 1; + } + } + else if (a < 0) { + if (b > 0 && a < NPY_MIN_INT64 / b) { + *overflow_flag = 1; + } + else if (b < 0 && a < NPY_MAX_INT64 / b) { + *overflow_flag = 1; + } + } + return a * b; +} + + +/* Long integer init */ +static NPY_INLINE npy_extint128_t +to_128(npy_int64 x) +{ + npy_extint128_t result; + result.sign = (x >= 0 ? 1 : -1); + if (x >= 0) { + result.lo = x; + } + else { + result.lo = (npy_uint64)(-(x + 1)) + 1; + } + result.hi = 0; + return result; +} + + +static NPY_INLINE npy_int64 +to_64(npy_extint128_t x, char *overflow) +{ + if (x.hi != 0 || + (x.sign > 0 && x.lo > NPY_MAX_INT64) || + (x.sign < 0 && x.lo != 0 && x.lo - 1 > -(NPY_MIN_INT64 + 1))) { + *overflow = 1; + } + return x.lo * x.sign; +} + + +/* Long integer multiply */ +static NPY_INLINE npy_extint128_t +mul_64_64(npy_int64 a, npy_int64 b) +{ + npy_extint128_t x, y, z; + npy_uint64 x1, x2, y1, y2, r1, r2, prev; + + x = to_128(a); + y = to_128(b); + + x1 = x.lo & 0xffffffff; + x2 = x.lo >> 32; + + y1 = y.lo & 0xffffffff; + y2 = y.lo >> 32; + + r1 = x1*y2; + r2 = x2*y1; + + z.sign = x.sign * y.sign; + z.hi = x2*y2 + (r1 >> 32) + (r2 >> 32); + z.lo = x1*y1; + + /* Add with carry */ + prev = z.lo; + z.lo += (r1 << 32); + if (z.lo < prev) { + ++z.hi; + } + + prev = z.lo; + z.lo += (r2 << 32); + if (z.lo < prev) { + ++z.hi; + } + + return z; +} + + +/* Long integer add */ +static NPY_INLINE npy_extint128_t +add_128(npy_extint128_t x, npy_extint128_t y, char *overflow) +{ + npy_extint128_t z; + + if (x.sign == y.sign) { + z.sign = x.sign; + z.hi = x.hi + y.hi; + if (z.hi < x.hi) { + *overflow = 1; + } + z.lo = x.lo + y.lo; + if (z.lo < x.lo) { + if (z.hi == NPY_MAX_UINT64) { + *overflow = 1; + } + ++z.hi; + } + } + else if (x.hi > y.hi || (x.hi == y.hi && x.lo >= y.lo)) { + z.sign = x.sign; + z.hi = x.hi - y.hi; + z.lo = x.lo; + z.lo -= y.lo; + if (z.lo > x.lo) { + --z.hi; + } + } + else { + z.sign = y.sign; + z.hi = y.hi - x.hi; + z.lo = y.lo; + z.lo -= x.lo; + if (z.lo > y.lo) { + --z.hi; + } + } + + return z; +} + + +/* Long integer negation */ +static NPY_INLINE npy_extint128_t +neg_128(npy_extint128_t x) +{ + npy_extint128_t z = x; + z.sign *= -1; + return z; +} + + +static NPY_INLINE npy_extint128_t +sub_128(npy_extint128_t x, npy_extint128_t y, char *overflow) +{ + return add_128(x, neg_128(y), overflow); +} + + +static NPY_INLINE npy_extint128_t +shl_128(npy_extint128_t v) +{ + npy_extint128_t z; + z = v; + z.hi <<= 1; + z.hi |= (z.lo & (((npy_uint64)1) << 63)) >> 63; + z.lo <<= 1; + return z; +} + + +static NPY_INLINE npy_extint128_t +shr_128(npy_extint128_t v) +{ + npy_extint128_t z; + z = v; + z.lo >>= 1; + z.lo |= (z.hi & 0x1) << 63; + z.hi >>= 1; + return z; +} + +static NPY_INLINE int +gt_128(npy_extint128_t a, npy_extint128_t b) +{ + if (a.sign > 0 && b.sign > 0) { + return (a.hi > b.hi) || (a.hi == b.hi && a.lo > b.lo); + } + else if (a.sign < 0 && b.sign < 0) { + return (a.hi < b.hi) || (a.hi == b.hi && a.lo < b.lo); + } + else if (a.sign > 0 && b.sign < 0) { + return a.hi != 0 || a.lo != 0 || b.hi != 0 || b.lo != 0; + } + else { + return 0; + } +} + + +/* Long integer divide */ +static NPY_INLINE npy_extint128_t +divmod_128_64(npy_extint128_t x, npy_int64 b, npy_int64 *mod) +{ + npy_extint128_t remainder, pointer, result, divisor; + char overflow = 0; + + assert(b > 0); + + if (b <= 1 || x.hi == 0) { + result.sign = x.sign; + result.lo = x.lo / b; + result.hi = x.hi / b; + *mod = x.sign * (x.lo % b); + return result; + } + + /* Long division, not the most efficient choice */ + remainder = x; + remainder.sign = 1; + + divisor.sign = 1; + divisor.hi = 0; + divisor.lo = b; + + result.sign = 1; + result.lo = 0; + result.hi = 0; + + pointer.sign = 1; + pointer.lo = 1; + pointer.hi = 0; + + while ((divisor.hi & (((npy_uint64)1) << 63)) == 0 && + gt_128(remainder, divisor)) { + divisor = shl_128(divisor); + pointer = shl_128(pointer); + } + + while (pointer.lo || pointer.hi) { + if (!gt_128(divisor, remainder)) { + remainder = sub_128(remainder, divisor, &overflow); + result = add_128(result, pointer, &overflow); + } + divisor = shr_128(divisor); + pointer = shr_128(pointer); + } + + /* Fix signs and return; cannot overflow */ + result.sign = x.sign; + *mod = x.sign * remainder.lo; + + return result; +} + + +/* Divide and round down (positive divisor; no overflows) */ +static NPY_INLINE npy_extint128_t +floordiv_128_64(npy_extint128_t a, npy_int64 b) +{ + npy_extint128_t result; + npy_int64 remainder; + char overflow = 0; + assert(b > 0); + result = divmod_128_64(a, b, &remainder); + if (a.sign < 0 && remainder != 0) { + result = sub_128(result, to_128(1), &overflow); + } + return result; +} + + +/* Divide and round up (positive divisor; no overflows) */ +static NPY_INLINE npy_extint128_t +ceildiv_128_64(npy_extint128_t a, npy_int64 b) +{ + npy_extint128_t result; + npy_int64 remainder; + char overflow = 0; + assert(b > 0); + result = divmod_128_64(a, b, &remainder); + if (a.sign > 0 && remainder != 0) { + result = add_128(result, to_128(1), &overflow); + } + return result; +} + +#endif diff --git a/numpy/core/src/private/npy_fpmath.h b/numpy/core/src/private/npy_fpmath.h new file mode 100644 index 0000000..86b9cf3 --- /dev/null +++ b/numpy/core/src/private/npy_fpmath.h @@ -0,0 +1,51 @@ +#ifndef _NPY_NPY_FPMATH_H_ +#define _NPY_NPY_FPMATH_H_ + +#include "npy_config.h" + +#include "numpy/npy_os.h" +#include "numpy/npy_cpu.h" +#include "numpy/npy_common.h" + +#ifdef NPY_OS_DARWIN + /* This hardcoded logic is fragile, but universal builds makes it + * difficult to detect arch-specific features */ + + /* MAC OS X < 10.4 and gcc < 4 does not support proper long double, and + * is the same as double on those platforms */ + #if NPY_BITSOF_LONGDOUBLE == NPY_BITSOF_DOUBLE + /* This assumes that FPU and ALU have the same endianness */ + #if NPY_BYTE_ORDER == NPY_LITTLE_ENDIAN + #define HAVE_LDOUBLE_IEEE_DOUBLE_LE + #elif NPY_BYTE_ORDER == NPY_BIG_ENDIAN + #define HAVE_LDOUBLE_IEEE_DOUBLE_BE + #else + #error Endianness undefined ? + #endif + #else + #if defined(NPY_CPU_X86) + #define HAVE_LDOUBLE_INTEL_EXTENDED_12_BYTES_LE + #elif defined(NPY_CPU_AMD64) + #define HAVE_LDOUBLE_INTEL_EXTENDED_16_BYTES_LE + #elif defined(NPY_CPU_PPC) || defined(NPY_CPU_PPC64) + #define HAVE_LDOUBLE_IEEE_DOUBLE_16_BYTES_BE + #elif defined(NPY_CPU_PPC64LE) + #define HAVE_LDOUBLE_IEEE_DOUBLE_16_BYTES_LE + #endif + #endif +#endif + +#if !(defined(HAVE_LDOUBLE_IEEE_QUAD_BE) || \ + defined(HAVE_LDOUBLE_IEEE_QUAD_LE) || \ + defined(HAVE_LDOUBLE_IEEE_DOUBLE_LE) || \ + defined(HAVE_LDOUBLE_IEEE_DOUBLE_BE) || \ + defined(HAVE_LDOUBLE_IEEE_DOUBLE_16_BYTES_BE) || \ + defined(HAVE_LDOUBLE_INTEL_EXTENDED_16_BYTES_LE) || \ + defined(HAVE_LDOUBLE_INTEL_EXTENDED_12_BYTES_LE) || \ + defined(HAVE_LDOUBLE_MOTOROLA_EXTENDED_12_BYTES_BE) || \ + defined(HAVE_LDOUBLE_DOUBLE_DOUBLE_BE) || \ + defined(HAVE_LDOUBLE_DOUBLE_DOUBLE_LE)) + #error No long double representation defined +#endif + +#endif diff --git a/numpy/core/src/private/npy_import.h b/numpy/core/src/private/npy_import.h new file mode 100644 index 0000000..e145a84 --- /dev/null +++ b/numpy/core/src/private/npy_import.h @@ -0,0 +1,46 @@ +#ifndef NPY_IMPORT_H +#define NPY_IMPORT_H + +#include + +/*! \brief Fetch and cache Python function. + * + * Import a Python function and cache it for use. The function checks if + * cache is NULL, and if not NULL imports the Python function specified by + * \a module and \a function, increments its reference count, and stores + * the result in \a cache. Usually \a cache will be a static variable and + * should be initialized to NULL. On error \a cache will contain NULL on + * exit, + * + * @param module Absolute module name. + * @param attr module attribute to cache. + * @param cache Storage location for imported function. + */ +NPY_INLINE static void +npy_cache_import(const char *module, const char *attr, PyObject **cache) +{ + if (*cache == NULL) { + PyObject *mod = PyImport_ImportModule(module); + + if (mod != NULL) { + *cache = PyObject_GetAttrString(mod, attr); + Py_DECREF(mod); + } + } +} + +NPY_INLINE static PyObject * +npy_import(const char *module, const char *attr) +{ + PyObject *mod = PyImport_ImportModule(module); + PyObject *ret = NULL; + + if (mod != NULL) { + ret = PyObject_GetAttrString(mod, attr); + } + Py_XDECREF(mod); + + return ret; +} + +#endif diff --git a/numpy/core/src/private/npy_longdouble.c b/numpy/core/src/private/npy_longdouble.c new file mode 100644 index 0000000..508fbce --- /dev/null +++ b/numpy/core/src/private/npy_longdouble.c @@ -0,0 +1,102 @@ +#include + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#include "numpy/ndarraytypes.h" +#include "numpy/npy_math.h" + +/* This is a backport of Py_SETREF */ +#define NPY_SETREF(op, op2) \ + do { \ + PyObject *_py_tmp = (PyObject *)(op); \ + (op) = (op2); \ + Py_DECREF(_py_tmp); \ + } while (0) + + +/* + * Heavily derived from PyLong_FromDouble + * Notably, we can't set the digits directly, so have to shift and or instead. + */ +NPY_VISIBILITY_HIDDEN PyObject * +npy_longdouble_to_PyLong(npy_longdouble ldval) +{ + PyObject *v; + PyObject *l_chunk_size; + /* + * number of bits to extract at a time. CPython uses 30, but that's because + * it's tied to the internal long representation + */ + const int chunk_size = NPY_BITSOF_LONGLONG; + npy_longdouble frac; + int i, ndig, expo, neg; + neg = 0; + + if (npy_isinf(ldval)) { + PyErr_SetString(PyExc_OverflowError, + "cannot convert longdouble infinity to integer"); + return NULL; + } + if (npy_isnan(ldval)) { + PyErr_SetString(PyExc_ValueError, + "cannot convert longdouble NaN to integer"); + return NULL; + } + if (ldval < 0.0) { + neg = 1; + ldval = -ldval; + } + frac = npy_frexpl(ldval, &expo); /* ldval = frac*2**expo; 0.0 <= frac < 1.0 */ + v = PyLong_FromLong(0L); + if (v == NULL) + return NULL; + if (expo <= 0) + return v; + + ndig = (expo-1) / chunk_size + 1; + + l_chunk_size = PyLong_FromLong(chunk_size); + if (l_chunk_size == NULL) { + Py_DECREF(v); + return NULL; + } + + /* Get the MSBs of the integral part of the float */ + frac = npy_ldexpl(frac, (expo-1) % chunk_size + 1); + for (i = ndig; --i >= 0; ) { + npy_ulonglong chunk = (npy_ulonglong)frac; + PyObject *l_chunk; + /* v = v << chunk_size */ + NPY_SETREF(v, PyNumber_Lshift(v, l_chunk_size)); + if (v == NULL) { + goto done; + } + l_chunk = PyLong_FromUnsignedLongLong(chunk); + if (l_chunk == NULL) { + Py_DECREF(v); + v = NULL; + goto done; + } + /* v = v | chunk */ + NPY_SETREF(v, PyNumber_Or(v, l_chunk)); + Py_DECREF(l_chunk); + if (v == NULL) { + goto done; + } + + /* Remove the msbs, and repeat */ + frac = frac - (npy_longdouble) chunk; + frac = npy_ldexpl(frac, chunk_size); + } + + /* v = -v */ + if (neg) { + NPY_SETREF(v, PyNumber_Negative(v)); + if (v == NULL) { + goto done; + } + } + +done: + Py_DECREF(l_chunk_size); + return v; +} diff --git a/numpy/core/src/private/npy_longdouble.h b/numpy/core/src/private/npy_longdouble.h new file mode 100644 index 0000000..036b530 --- /dev/null +++ b/numpy/core/src/private/npy_longdouble.h @@ -0,0 +1,17 @@ +#ifndef __NPY_LONGDOUBLE_H +#define __NPY_LONGDOUBLE_H + +#include "npy_config.h" +#include "numpy/ndarraytypes.h" + +/* Convert a npy_longdouble to a python `long` integer. + * + * Results are rounded towards zero. + * + * This performs the same task as PyLong_FromDouble, but for long doubles + * which have a greater range. + */ +NPY_VISIBILITY_HIDDEN PyObject * +npy_longdouble_to_PyLong(npy_longdouble ldval); + +#endif diff --git a/numpy/core/src/private/npy_partition.h.src b/numpy/core/src/private/npy_partition.h.src new file mode 100644 index 0000000..07aecd4 --- /dev/null +++ b/numpy/core/src/private/npy_partition.h.src @@ -0,0 +1,122 @@ +/* + ***************************************************************************** + ** IMPORTANT NOTE for npy_partition.h.src -> npy_partition.h ** + ***************************************************************************** + * The template file loops.h.src is not automatically converted into + * loops.h by the build system. If you edit this file, you must manually + * do the conversion using numpy/distutils/conv_template.py from the + * command line as follows: + * + * $ cd + * $ python numpy/distutils/conv_template.py numpy/core/src/private/npy_partition.h.src + * $ + */ + + +#ifndef __NPY_PARTITION_H__ +#define __NPY_PARTITION_H__ + + +#include "npy_sort.h" + +/* Python include is for future object sorts */ +#include +#include +#include + +#define NPY_MAX_PIVOT_STACK 50 + + +/**begin repeat + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat, + * npy_cdouble, npy_clongdouble# + */ + +NPY_VISIBILITY_HIDDEN int introselect_@suff@(@type@ *v, npy_intp num, + npy_intp kth, + npy_intp * pivots, + npy_intp * npiv, + void *NOT_USED); +NPY_VISIBILITY_HIDDEN int aintroselect_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, + npy_intp kth, + npy_intp * pivots, + npy_intp * npiv, + void *NOT_USED); + + +/**end repeat**/ + +typedef struct { + enum NPY_TYPES typenum; + PyArray_PartitionFunc * part[NPY_NSELECTS]; + PyArray_ArgPartitionFunc * argpart[NPY_NSELECTS]; +} part_map; + +static part_map _part_map[] = { +/**begin repeat + * + * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, + * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE# + * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat, + * npy_cdouble, npy_clongdouble# + */ + { + NPY_@TYPE@, + { + (PyArray_PartitionFunc *)&introselect_@suff@, + }, + { + (PyArray_ArgPartitionFunc *)&aintroselect_@suff@, + } + }, +/**end repeat**/ +}; + + +static NPY_INLINE PyArray_PartitionFunc * +get_partition_func(int type, NPY_SELECTKIND which) +{ + npy_intp i; + if (which >= NPY_NSELECTS) { + return NULL; + } + for (i = 0; i < sizeof(_part_map)/sizeof(_part_map[0]); i++) { + if (type == _part_map[i].typenum) { + return _part_map[i].part[which]; + } + } + return NULL; +} + + +static NPY_INLINE PyArray_ArgPartitionFunc * +get_argpartition_func(int type, NPY_SELECTKIND which) +{ + npy_intp i; + if (which >= NPY_NSELECTS) { + return NULL; + } + for (i = 0; i < sizeof(_part_map)/sizeof(_part_map[0]); i++) { + if (type == _part_map[i].typenum) { + return _part_map[i].argpart[which]; + } + } + return NULL; +} + +#endif diff --git a/numpy/core/src/private/npy_pycompat.h b/numpy/core/src/private/npy_pycompat.h new file mode 100644 index 0000000..aa0b5c1 --- /dev/null +++ b/numpy/core/src/private/npy_pycompat.h @@ -0,0 +1,6 @@ +#ifndef _NPY_PYCOMPAT_H_ +#define _NPY_PYCOMPAT_H_ + +#include "numpy/npy_3kcompat.h" + +#endif /* _NPY_COMPAT_H_ */ diff --git a/numpy/core/src/private/npy_sort.h b/numpy/core/src/private/npy_sort.h new file mode 100644 index 0000000..8c6f056 --- /dev/null +++ b/numpy/core/src/private/npy_sort.h @@ -0,0 +1,204 @@ +#ifndef __NPY_SORT_H__ +#define __NPY_SORT_H__ + +/* Python include is for future object sorts */ +#include +#include +#include + +#define NPY_ENOMEM 1 +#define NPY_ECOMP 2 + +static NPY_INLINE int npy_get_msb(npy_uintp unum) +{ + int depth_limit = 0; + while (unum >>= 1) { + depth_limit++; + } + return depth_limit; +} + +int quicksort_bool(void *vec, npy_intp cnt, void *null); +int heapsort_bool(void *vec, npy_intp cnt, void *null); +int mergesort_bool(void *vec, npy_intp cnt, void *null); +int aquicksort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_byte(void *vec, npy_intp cnt, void *null); +int heapsort_byte(void *vec, npy_intp cnt, void *null); +int mergesort_byte(void *vec, npy_intp cnt, void *null); +int aquicksort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_ubyte(void *vec, npy_intp cnt, void *null); +int heapsort_ubyte(void *vec, npy_intp cnt, void *null); +int mergesort_ubyte(void *vec, npy_intp cnt, void *null); +int aquicksort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_short(void *vec, npy_intp cnt, void *null); +int heapsort_short(void *vec, npy_intp cnt, void *null); +int mergesort_short(void *vec, npy_intp cnt, void *null); +int aquicksort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_ushort(void *vec, npy_intp cnt, void *null); +int heapsort_ushort(void *vec, npy_intp cnt, void *null); +int mergesort_ushort(void *vec, npy_intp cnt, void *null); +int aquicksort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_int(void *vec, npy_intp cnt, void *null); +int heapsort_int(void *vec, npy_intp cnt, void *null); +int mergesort_int(void *vec, npy_intp cnt, void *null); +int aquicksort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_uint(void *vec, npy_intp cnt, void *null); +int heapsort_uint(void *vec, npy_intp cnt, void *null); +int mergesort_uint(void *vec, npy_intp cnt, void *null); +int aquicksort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_long(void *vec, npy_intp cnt, void *null); +int heapsort_long(void *vec, npy_intp cnt, void *null); +int mergesort_long(void *vec, npy_intp cnt, void *null); +int aquicksort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_ulong(void *vec, npy_intp cnt, void *null); +int heapsort_ulong(void *vec, npy_intp cnt, void *null); +int mergesort_ulong(void *vec, npy_intp cnt, void *null); +int aquicksort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_longlong(void *vec, npy_intp cnt, void *null); +int heapsort_longlong(void *vec, npy_intp cnt, void *null); +int mergesort_longlong(void *vec, npy_intp cnt, void *null); +int aquicksort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_ulonglong(void *vec, npy_intp cnt, void *null); +int heapsort_ulonglong(void *vec, npy_intp cnt, void *null); +int mergesort_ulonglong(void *vec, npy_intp cnt, void *null); +int aquicksort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_half(void *vec, npy_intp cnt, void *null); +int heapsort_half(void *vec, npy_intp cnt, void *null); +int mergesort_half(void *vec, npy_intp cnt, void *null); +int aquicksort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_float(void *vec, npy_intp cnt, void *null); +int heapsort_float(void *vec, npy_intp cnt, void *null); +int mergesort_float(void *vec, npy_intp cnt, void *null); +int aquicksort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_double(void *vec, npy_intp cnt, void *null); +int heapsort_double(void *vec, npy_intp cnt, void *null); +int mergesort_double(void *vec, npy_intp cnt, void *null); +int aquicksort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_longdouble(void *vec, npy_intp cnt, void *null); +int heapsort_longdouble(void *vec, npy_intp cnt, void *null); +int mergesort_longdouble(void *vec, npy_intp cnt, void *null); +int aquicksort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_cfloat(void *vec, npy_intp cnt, void *null); +int heapsort_cfloat(void *vec, npy_intp cnt, void *null); +int mergesort_cfloat(void *vec, npy_intp cnt, void *null); +int aquicksort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_cdouble(void *vec, npy_intp cnt, void *null); +int heapsort_cdouble(void *vec, npy_intp cnt, void *null); +int mergesort_cdouble(void *vec, npy_intp cnt, void *null); +int aquicksort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_clongdouble(void *vec, npy_intp cnt, void *null); +int heapsort_clongdouble(void *vec, npy_intp cnt, void *null); +int mergesort_clongdouble(void *vec, npy_intp cnt, void *null); +int aquicksort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_string(void *vec, npy_intp cnt, void *arr); +int heapsort_string(void *vec, npy_intp cnt, void *arr); +int mergesort_string(void *vec, npy_intp cnt, void *arr); +int aquicksort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int aheapsort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int amergesort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr); + + +int quicksort_unicode(void *vec, npy_intp cnt, void *arr); +int heapsort_unicode(void *vec, npy_intp cnt, void *arr); +int mergesort_unicode(void *vec, npy_intp cnt, void *arr); +int aquicksort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int aheapsort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int amergesort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr); + + +int quicksort_datetime(void *vec, npy_intp cnt, void *null); +int heapsort_datetime(void *vec, npy_intp cnt, void *null); +int mergesort_datetime(void *vec, npy_intp cnt, void *null); +int aquicksort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_timedelta(void *vec, npy_intp cnt, void *null); +int heapsort_timedelta(void *vec, npy_intp cnt, void *null); +int mergesort_timedelta(void *vec, npy_intp cnt, void *null); +int aquicksort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int npy_quicksort(void *vec, npy_intp cnt, void *arr); +int npy_heapsort(void *vec, npy_intp cnt, void *arr); +int npy_mergesort(void *vec, npy_intp cnt, void *arr); +int npy_aquicksort(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int npy_aheapsort(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int npy_amergesort(void *vec, npy_intp *ind, npy_intp cnt, void *arr); + +#endif diff --git a/numpy/core/src/private/templ_common.h.src b/numpy/core/src/private/templ_common.h.src new file mode 100644 index 0000000..a65a007 --- /dev/null +++ b/numpy/core/src/private/templ_common.h.src @@ -0,0 +1,46 @@ +#ifndef __NPY_TYPED_COMMON_INC +#define __NPY_TYPED_COMMON_INC + +/* utility functions that profit from templates */ + +#include "numpy/npy_common.h" + +/**begin repeat + * #name = int, uint, long, ulong, + * longlong, ulonglong, intp# + * #type = npy_int, npy_uint, npy_long, npy_ulong, + * npy_longlong, npy_ulonglong, npy_intp# + * #MAX = NPY_MAX_INT, NPY_MAX_UINT, NPY_MAX_LONG, NPY_MAX_ULONG, + * NPY_MAX_LONGLONG, NPY_MAX_ULONGLONG, NPY_MAX_INTP# + */ + +/* + * writes result of a * b into r + * returns 1 if a * b overflowed else returns 0 + * + * These functions are not designed to work if either a or b is negative, but + * that is not checked. Could use absolute values and adjust the sign if that + * functionality was desired. + */ +static NPY_INLINE int +npy_mul_with_overflow_@name@(@type@ * r, @type@ a, @type@ b) +{ +#ifdef HAVE___BUILTIN_MUL_OVERFLOW + return __builtin_mul_overflow(a, b, r); +#else + const @type@ half_sz = ((@type@)1 << ((sizeof(a) * 8 - 1 ) / 2)); + + *r = a * b; + /* + * avoid expensive division on common no overflow case + */ + if (NPY_UNLIKELY((a | b) >= half_sz) && + a != 0 && b > @MAX@ / a) { + return 1; + } + return 0; +#endif +} +/**end repeat**/ + +#endif diff --git a/numpy/core/src/private/ufunc_override.c b/numpy/core/src/private/ufunc_override.c new file mode 100644 index 0000000..e405155 --- /dev/null +++ b/numpy/core/src/private/ufunc_override.c @@ -0,0 +1,155 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define NO_IMPORT_ARRAY + +#include "npy_pycompat.h" +#include "get_attr_string.h" +#include "npy_import.h" + +#include "ufunc_override.h" + +/* + * Check whether an object has __array_ufunc__ defined on its class and it + * is not the default, i.e., the object is not an ndarray, and its + * __array_ufunc__ is not the same as that of ndarray. + * + * Returns a new reference, the value of type(obj).__array_ufunc__ + * + * If the __array_ufunc__ matches that of ndarray, or does not exist, return + * NULL. + * + * Note that since this module is used with both multiarray and umath, we do + * not have access to PyArray_Type and therewith neither to PyArray_CheckExact + * nor to the default __array_ufunc__ method, so instead we import locally. + * TODO: Can this really not be done more smartly? + */ +static PyObject * +get_non_default_array_ufunc(PyObject *obj) +{ + static PyObject *ndarray = NULL; + static PyObject *ndarray_array_ufunc = NULL; + PyObject *cls_array_ufunc; + + /* on first entry, import and cache ndarray and its __array_ufunc__ */ + if (ndarray == NULL) { + npy_cache_import("numpy.core.multiarray", "ndarray", &ndarray); + ndarray_array_ufunc = PyObject_GetAttrString(ndarray, + "__array_ufunc__"); + } + + /* Fast return for ndarray */ + if ((PyObject *)Py_TYPE(obj) == ndarray) { + return NULL; + } + /* does the class define __array_ufunc__? */ + cls_array_ufunc = PyArray_LookupSpecial(obj, "__array_ufunc__"); + if (cls_array_ufunc == NULL) { + return NULL; + } + /* is it different from ndarray.__array_ufunc__? */ + if (cls_array_ufunc != ndarray_array_ufunc) { + return cls_array_ufunc; + } + Py_DECREF(cls_array_ufunc); + return NULL; +} + +/* + * Check whether a set of input and output args have a non-default + * `__array_ufunc__` method. Return the number of overrides, setting + * corresponding objects in PyObject array with_override and the corresponding + * __array_ufunc__ methods in methods (both only if not NULL, and both using + * new references). + * + * returns -1 on failure. + */ +NPY_NO_EXPORT int +PyUFunc_WithOverride(PyObject *args, PyObject *kwds, + PyObject **with_override, PyObject **methods) +{ + int i; + + int nargs; + int nout_kwd = 0; + int out_kwd_is_tuple = 0; + int num_override_args = 0; + + PyObject *obj; + PyObject *out_kwd_obj = NULL; + /* + * Check inputs + */ + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "Internal Numpy error: call to PyUFunc_HasOverride " + "with non-tuple"); + goto fail; + } + nargs = PyTuple_GET_SIZE(args); + if (nargs > NPY_MAXARGS) { + PyErr_SetString(PyExc_TypeError, + "Internal Numpy error: too many arguments in call " + "to PyUFunc_HasOverride"); + goto fail; + } + /* be sure to include possible 'out' keyword argument. */ + if (kwds && PyDict_CheckExact(kwds)) { + out_kwd_obj = PyDict_GetItemString(kwds, "out"); + if (out_kwd_obj != NULL) { + out_kwd_is_tuple = PyTuple_CheckExact(out_kwd_obj); + if (out_kwd_is_tuple) { + nout_kwd = PyTuple_GET_SIZE(out_kwd_obj); + } + else { + nout_kwd = 1; + } + } + } + + for (i = 0; i < nargs + nout_kwd; ++i) { + PyObject *method; + if (i < nargs) { + obj = PyTuple_GET_ITEM(args, i); + } + else { + if (out_kwd_is_tuple) { + obj = PyTuple_GET_ITEM(out_kwd_obj, i - nargs); + } + else { + obj = out_kwd_obj; + } + } + /* + * Now see if the object provides an __array_ufunc__. However, we should + * ignore the base ndarray.__ufunc__, so we skip any ndarray as well as + * any ndarray subclass instances that did not override __array_ufunc__. + */ + method = get_non_default_array_ufunc(obj); + if (method != NULL) { + if (method == Py_None) { + PyErr_Format(PyExc_TypeError, + "operand '%.200s' does not support ufuncs " + "(__array_ufunc__=None)", + obj->ob_type->tp_name); + Py_DECREF(method); + goto fail; + } + if (with_override != NULL) { + Py_INCREF(obj); + with_override[num_override_args] = obj; + } + if (methods != NULL) { + methods[num_override_args] = method; + } + ++num_override_args; + } + } + return num_override_args; + +fail: + if (methods != NULL) { + for (i = 0; i < num_override_args; i++) { + Py_XDECREF(methods[i]); + } + } + return -1; +} diff --git a/numpy/core/src/private/ufunc_override.h b/numpy/core/src/private/ufunc_override.h new file mode 100644 index 0000000..2ed1c62 --- /dev/null +++ b/numpy/core/src/private/ufunc_override.h @@ -0,0 +1,15 @@ +#ifndef __UFUNC_OVERRIDE_H +#define __UFUNC_OVERRIDE_H + +#include "npy_config.h" + +/* + * Check whether a set of input and output args have a non-default + * `__array_ufunc__` method. Returns the number of overrides, setting + * corresponding objects in PyObject array with_override (if not NULL). + * returns -1 on failure. + */ +NPY_NO_EXPORT int +PyUFunc_WithOverride(PyObject *args, PyObject *kwds, + PyObject **with_override, PyObject **methods); +#endif diff --git a/numpy/core/src/umath/extobj.c b/numpy/core/src/umath/extobj.c new file mode 100644 index 0000000..e440363 --- /dev/null +++ b/numpy/core/src/umath/extobj.c @@ -0,0 +1,323 @@ +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include + +#include "npy_config.h" + +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API +#define NO_IMPORT_ARRAY + +#include "npy_pycompat.h" + +#include "extobj.h" +#include "numpy/ufuncobject.h" + +#include "ufunc_object.h" /* for npy_um_str_pyvals_name */ +#include "common.h" + +#if USE_USE_DEFAULTS==1 +static int PyUFunc_NUM_NODEFAULTS = 0; + +/* + * This is a strategy to buy a little speed up and avoid the dictionary + * look-up in the default case. It should work in the presence of + * threads. If it is deemed too complicated or it doesn't actually work + * it could be taken out. + */ +NPY_NO_EXPORT int +ufunc_update_use_defaults(void) +{ + PyObject *errobj = NULL; + int errmask, bufsize; + int res; + + PyUFunc_NUM_NODEFAULTS += 1; + res = PyUFunc_GetPyValues("test", &bufsize, &errmask, &errobj); + PyUFunc_NUM_NODEFAULTS -= 1; + if (res < 0) { + Py_XDECREF(errobj); + return -1; + } + if ((errmask != UFUNC_ERR_DEFAULT) || (bufsize != NPY_BUFSIZE) + || (PyTuple_GET_ITEM(errobj, 1) != Py_None)) { + PyUFunc_NUM_NODEFAULTS += 1; + } + else if (PyUFunc_NUM_NODEFAULTS > 0) { + PyUFunc_NUM_NODEFAULTS -= 1; + } + Py_XDECREF(errobj); + return 0; +} +#endif + +/* + * fpstatus is the ufunc_formatted hardware status + * errmask is the handling mask specified by the user. + * errobj is a Python object with (string, callable object or None) + * or NULL + */ + +/* + * 2. for each of the flags + * determine whether to ignore, warn, raise error, or call Python function. + * If ignore, do nothing + * If warn, print a warning and continue + * If raise return an error + * If call, call a user-defined function with string + */ + +NPY_NO_EXPORT int +_error_handler(int method, PyObject *errobj, char *errtype, int retstatus, int *first) +{ + PyObject *pyfunc, *ret, *args; + char *name = PyBytes_AS_STRING(PyTuple_GET_ITEM(errobj,0)); + char msg[100]; + + NPY_ALLOW_C_API_DEF + + /* don't need C API for a simple ignore */ + if (method == UFUNC_ERR_IGNORE) { + return 0; + } + + /* don't need C API for a simple print */ + if (method == UFUNC_ERR_PRINT) { + if (*first) { + fprintf(stderr, "Warning: %s encountered in %s\n", errtype, name); + *first = 0; + } + return 0; + } + + NPY_ALLOW_C_API; + switch(method) { + case UFUNC_ERR_WARN: + PyOS_snprintf(msg, sizeof(msg), "%s encountered in %s", errtype, name); + if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) { + goto fail; + } + break; + case UFUNC_ERR_RAISE: + PyErr_Format(PyExc_FloatingPointError, "%s encountered in %s", + errtype, name); + goto fail; + case UFUNC_ERR_CALL: + pyfunc = PyTuple_GET_ITEM(errobj, 1); + if (pyfunc == Py_None) { + PyErr_Format(PyExc_NameError, + "python callback specified for %s (in " \ + " %s) but no function found.", + errtype, name); + goto fail; + } + args = Py_BuildValue("NN", PyUString_FromString(errtype), + PyInt_FromLong((long) retstatus)); + if (args == NULL) { + goto fail; + } + ret = PyObject_CallObject(pyfunc, args); + Py_DECREF(args); + if (ret == NULL) { + goto fail; + } + Py_DECREF(ret); + break; + case UFUNC_ERR_LOG: + if (first) { + *first = 0; + pyfunc = PyTuple_GET_ITEM(errobj, 1); + if (pyfunc == Py_None) { + PyErr_Format(PyExc_NameError, + "log specified for %s (in %s) but no " \ + "object with write method found.", + errtype, name); + goto fail; + } + PyOS_snprintf(msg, sizeof(msg), + "Warning: %s encountered in %s\n", errtype, name); + ret = PyObject_CallMethod(pyfunc, "write", "s", msg); + if (ret == NULL) { + goto fail; + } + Py_DECREF(ret); + } + break; + } + NPY_DISABLE_C_API; + return 0; + +fail: + NPY_DISABLE_C_API; + return -1; +} + + + +NPY_NO_EXPORT PyObject * +get_global_ext_obj(void) +{ + PyObject *thedict; + PyObject *ref = NULL; + +#if USE_USE_DEFAULTS==1 + if (PyUFunc_NUM_NODEFAULTS != 0) { +#endif + thedict = PyThreadState_GetDict(); + if (thedict == NULL) { + thedict = PyEval_GetBuiltins(); + } + ref = PyDict_GetItem(thedict, npy_um_str_pyvals_name); +#if USE_USE_DEFAULTS==1 + } +#endif + + return ref; +} + + +/* + * Extracts some values from the global pyvals tuple. + * all destinations may be NULL, in which case they are not retrieved + * ref - should hold the global tuple + * name - is the name of the ufunc (ufuncobj->name) + * + * bufsize - receives the buffer size to use + * errmask - receives the bitmask for error handling + * errobj - receives the python object to call with the error, + * if an error handling method is 'call' + */ +NPY_NO_EXPORT int +_extract_pyvals(PyObject *ref, const char *name, int *bufsize, + int *errmask, PyObject **errobj) +{ + PyObject *retval; + + /* default errobj case, skips dictionary lookup */ + if (ref == NULL) { + if (errmask) { + *errmask = UFUNC_ERR_DEFAULT; + } + if (errobj) { + *errobj = Py_BuildValue("NO", PyBytes_FromString(name), Py_None); + } + if (bufsize) { + *bufsize = NPY_BUFSIZE; + } + return 0; + } + + if (!PyList_Check(ref) || (PyList_GET_SIZE(ref)!=3)) { + PyErr_Format(PyExc_TypeError, + "%s must be a length 3 list.", UFUNC_PYVALS_NAME); + return -1; + } + + if (bufsize != NULL) { + *bufsize = PyInt_AsLong(PyList_GET_ITEM(ref, 0)); + if (error_converting(*bufsize)) { + return -1; + } + if ((*bufsize < NPY_MIN_BUFSIZE) || + (*bufsize > NPY_MAX_BUFSIZE) || + (*bufsize % 16 != 0)) { + PyErr_Format(PyExc_ValueError, + "buffer size (%d) is not in range " + "(%"NPY_INTP_FMT" - %"NPY_INTP_FMT") or not a multiple of 16", + *bufsize, (npy_intp) NPY_MIN_BUFSIZE, + (npy_intp) NPY_MAX_BUFSIZE); + return -1; + } + } + + if (errmask != NULL) { + *errmask = PyInt_AsLong(PyList_GET_ITEM(ref, 1)); + if (*errmask < 0) { + if (PyErr_Occurred()) { + return -1; + } + PyErr_Format(PyExc_ValueError, + "invalid error mask (%d)", + *errmask); + return -1; + } + } + + if (errobj != NULL) { + *errobj = NULL; + retval = PyList_GET_ITEM(ref, 2); + if (retval != Py_None && !PyCallable_Check(retval)) { + PyObject *temp; + temp = PyObject_GetAttrString(retval, "write"); + if (temp == NULL || !PyCallable_Check(temp)) { + PyErr_SetString(PyExc_TypeError, + "python object must be callable or have " \ + "a callable write method"); + Py_XDECREF(temp); + return -1; + } + Py_DECREF(temp); + } + + *errobj = Py_BuildValue("NO", PyBytes_FromString(name), retval); + if (*errobj == NULL) { + return -1; + } + } + return 0; +} + +/* + * check the floating point status + * - errmask: mask of status to check + * - extobj: ufunc pyvals object + * may be null, in which case the thread global one is fetched + * - ufunc_name: name of ufunc + */ +NPY_NO_EXPORT int +_check_ufunc_fperr(int errmask, PyObject *extobj, const char *ufunc_name) { + int fperr; + PyObject *errobj = NULL; + int ret; + int first = 1; + + if (!errmask) { + return 0; + } + fperr = PyUFunc_getfperr(); + if (!fperr) { + return 0; + } + + /* Get error object globals */ + if (extobj == NULL) { + extobj = get_global_ext_obj(); + } + if (_extract_pyvals(extobj, ufunc_name, + NULL, NULL, &errobj) < 0) { + Py_XDECREF(errobj); + return -1; + } + + ret = PyUFunc_handlefperr(errmask, errobj, fperr, &first); + Py_XDECREF(errobj); + + return ret; +} + + +NPY_NO_EXPORT int +_get_bufsize_errmask(PyObject * extobj, const char *ufunc_name, + int *buffersize, int *errormask) +{ + /* Get the buffersize and errormask */ + if (extobj == NULL) { + extobj = get_global_ext_obj(); + } + if (_extract_pyvals(extobj, ufunc_name, + buffersize, errormask, NULL) < 0) { + return -1; + } + + return 0; +} diff --git a/numpy/core/src/umath/extobj.h b/numpy/core/src/umath/extobj.h new file mode 100644 index 0000000..1a569df --- /dev/null +++ b/numpy/core/src/umath/extobj.h @@ -0,0 +1,32 @@ +#ifndef _NPY_PRIVATE__EXTOBJ_H_ +#define _NPY_PRIVATE__EXTOBJ_H_ + +#include /* for NPY_NO_EXPORT */ + +NPY_NO_EXPORT int +_error_handler(int method, PyObject *errobj, char *errtype, int retstatus, int *first); + +NPY_NO_EXPORT PyObject * +get_global_ext_obj(void); + +NPY_NO_EXPORT int +_extract_pyvals(PyObject *ref, const char *name, int *bufsize, + int *errmask, PyObject **errobj); + +NPY_NO_EXPORT int +_check_ufunc_fperr(int errmask, PyObject *extobj, const char *ufunc_name); + +NPY_NO_EXPORT int +_get_bufsize_errmask(PyObject * extobj, const char *ufunc_name, + int *buffersize, int *errormask); + +/********************/ +#define USE_USE_DEFAULTS 1 +/********************/ + +#if USE_USE_DEFAULTS==1 +NPY_NO_EXPORT int +ufunc_update_use_defaults(void); +#endif + +#endif diff --git a/numpy/core/src/umath/funcs.inc.src b/numpy/core/src/umath/funcs.inc.src new file mode 100644 index 0000000..5613c30 --- /dev/null +++ b/numpy/core/src/umath/funcs.inc.src @@ -0,0 +1,364 @@ +/* -*- c -*- */ + +/* + * This file is for the definitions of the non-c99 functions used in ufuncs. + * All the complex ufuncs are defined here along with a smattering of real and + * object functions. + */ + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#include "npy_pycompat.h" + + +/* + ***************************************************************************** + ** PYTHON OBJECT FUNCTIONS ** + ***************************************************************************** + */ + +static PyObject * +Py_square(PyObject *o) +{ + return PyNumber_Multiply(o, o); +} + +static PyObject * +Py_get_one(PyObject *NPY_UNUSED(o)) +{ + return PyInt_FromLong(1); +} + +static PyObject * +Py_reciprocal(PyObject *o) +{ + PyObject *one = PyInt_FromLong(1); + PyObject *result; + + if (!one) { + return NULL; + } +#if defined(NPY_PY3K) + result = PyNumber_TrueDivide(one, o); +#else + result = PyNumber_Divide(one, o); +#endif + Py_DECREF(one); + return result; +} + +/* + * Define numpy version of PyNumber_Power as binary function. + */ +static PyObject * +npy_ObjectPower(PyObject *x, PyObject *y) +{ + return PyNumber_Power(x, y, Py_None); +} + +/**begin repeat + * #Kind = Max, Min# + * #OP = Py_GE, Py_LE# + */ +static PyObject * +npy_Object@Kind@(PyObject *i1, PyObject *i2) +{ + PyObject *result; + int cmp; + + cmp = PyObject_RichCompareBool(i1, i2, @OP@); + if (cmp < 0) { + return NULL; + } + if (cmp == 1) { + result = i1; + } + else { + result = i2; + } + Py_INCREF(result); + return result; +} +/**end repeat**/ + +/* Emulates Python's 'a or b' behavior */ +static PyObject * +npy_ObjectLogicalOr(PyObject *i1, PyObject *i2) +{ + if (i1 == NULL) { + Py_XINCREF(i2); + return i2; + } + else if (i2 == NULL) { + Py_INCREF(i1); + return i1; + } + else { + int retcode = PyObject_IsTrue(i1); + if (retcode == -1) { + return NULL; + } + else if (retcode) { + Py_INCREF(i1); + return i1; + } + else { + Py_INCREF(i2); + return i2; + } + } +} + +/* Emulates Python's 'a and b' behavior */ +static PyObject * +npy_ObjectLogicalAnd(PyObject *i1, PyObject *i2) +{ + if (i1 == NULL) { + return NULL; + } + else if (i2 == NULL) { + return NULL; + } + else { + int retcode = PyObject_IsTrue(i1); + if (retcode == -1) { + return NULL; + } + else if (!retcode) { + Py_INCREF(i1); + return i1; + } + else { + Py_INCREF(i2); + return i2; + } + } +} + + +/* Emulates Python's 'not b' behavior */ +static PyObject * +npy_ObjectLogicalNot(PyObject *i1) +{ + if (i1 == NULL) { + return NULL; + } + else { + int retcode = PyObject_Not(i1); + if (retcode == -1) { + return NULL; + } + else if (retcode) { + Py_INCREF(Py_True); + return Py_True; + } + else { + Py_INCREF(Py_False); + return Py_False; + } + } +} + +/* + ***************************************************************************** + ** COMPLEX FUNCTIONS ** + ***************************************************************************** + */ + + +/* + * Don't pass structures between functions (only pointers) because how + * structures are passed is compiler dependent and could cause segfaults if + * umath_ufunc_object.inc is compiled with a different compiler than an + * extension that makes use of the UFUNC API + */ + +/**begin repeat + * + * #ctype = npy_cfloat, npy_cdouble, npy_clongdouble# + * #ftype = npy_float, npy_double, npy_longdouble# + * #c = f, ,l# + */ + +static void +nc_neg@c@(@ctype@ *a, @ctype@ *r) +{ + r->real = -a->real; + r->imag = -a->imag; + return; +} + +static void +nc_pos@c@(@ctype@ *a, @ctype@ *r) +{ + r->real = +a->real; + r->imag = +a->imag; + return; +} + +static void +nc_sqrt@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_csqrt@c@(*x); + return; +} + +static void +nc_rint@c@(@ctype@ *x, @ctype@ *r) +{ + r->real = npy_rint@c@(x->real); + r->imag = npy_rint@c@(x->imag); +} + +static void +nc_log@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_clog@c@(*x); + return; +} + +static void +nc_log1p@c@(@ctype@ *x, @ctype@ *r) +{ + @ftype@ l = npy_hypot@c@(x->real + 1,x->imag); + r->imag = npy_atan2@c@(x->imag, x->real + 1); + r->real = npy_log@c@(l); + return; +} + +static void +nc_exp@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_cexp@c@(*x); + return; +} + +static void +nc_exp2@c@(@ctype@ *x, @ctype@ *r) +{ + @ctype@ a; + a.real = x->real*NPY_LOGE2@c@; + a.imag = x->imag*NPY_LOGE2@c@; + nc_exp@c@(&a, r); + return; +} + +static void +nc_expm1@c@(@ctype@ *x, @ctype@ *r) +{ + @ftype@ a = npy_exp@c@(x->real); + r->real = a*npy_cos@c@(x->imag) - 1.0@c@; + r->imag = a*npy_sin@c@(x->imag); + return; +} + +static void +nc_pow@c@(@ctype@ *a, @ctype@ *b, @ctype@ *r) +{ + *r = npy_cpow@c@(*a, *b); + return; +} + +static void +nc_acos@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_cacos@c@(*x); + return; +} + +static void +nc_acosh@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_cacosh@c@(*x); + return; +} + +static void +nc_asin@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_casin@c@(*x); + return; +} + + +static void +nc_asinh@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_casinh@c@(*x); + return; +} + +static void +nc_atan@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_catan@c@(*x); + return; +} + +static void +nc_atanh@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_catanh@c@(*x); + return; +} + +static void +nc_cos@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_ccos@c@(*x); + return; +} + +static void +nc_cosh@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_ccosh@c@(*x); + return; +} + +static void +nc_log10@c@(@ctype@ *x, @ctype@ *r) +{ + nc_log@c@(x, r); + r->real *= NPY_LOG10E@c@; + r->imag *= NPY_LOG10E@c@; + return; +} + +static void +nc_log2@c@(@ctype@ *x, @ctype@ *r) +{ + nc_log@c@(x, r); + r->real *= NPY_LOG2E@c@; + r->imag *= NPY_LOG2E@c@; + return; +} + +static void +nc_sin@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_csin@c@(*x); + return; +} + +static void +nc_sinh@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_csinh@c@(*x); + return; +} + +static void +nc_tan@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_ctan@c@(*x); + return; +} + +static void +nc_tanh@c@(@ctype@ *x, @ctype@ *r) +{ + *r = npy_ctanh@c@(*x); + return; +} + +/**end repeat**/ diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src new file mode 100644 index 0000000..7897175 --- /dev/null +++ b/numpy/core/src/umath/loops.c.src @@ -0,0 +1,2872 @@ +/* -*- c -*- */ + +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" + +#include "npy_config.h" +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API +#define NO_IMPORT_ARRAY + +#include "numpy/npy_common.h" +#include "numpy/arrayobject.h" +#include "numpy/ufuncobject.h" +#include "numpy/npy_math.h" +#include "numpy/halffloat.h" +#include "lowlevel_strided_loops.h" + +#include "npy_pycompat.h" + +#include "ufunc_object.h" + +#include /* for memchr */ + +/* + * cutoff blocksize for pairwise summation + * decreasing it decreases errors slightly as more pairs are summed but + * also lowers performance, as the inner loop is unrolled eight times it is + * effectively 16 + */ +#define PW_BLOCKSIZE 128 + +/* + * include vectorized functions and dispatchers + * this file is safe to include also for generic builds + * platform specific instructions are either masked via the proprocessor or + * runtime detected + */ +#include "simd.inc" + + +/* + ***************************************************************************** + ** UFUNC LOOPS ** + ***************************************************************************** + */ + +/* unary loop input and output contiguous */ +#define IS_UNARY_CONT(tin, tout) (steps[0] == sizeof(tin) && \ + steps[1] == sizeof(tout)) + +#define IS_BINARY_REDUCE ((args[0] == args[2])\ + && (steps[0] == steps[2])\ + && (steps[0] == 0)) + +/* binary loop input and output contiguous */ +#define IS_BINARY_CONT(tin, tout) (steps[0] == sizeof(tin) && \ + steps[1] == sizeof(tin) && \ + steps[2] == sizeof(tout)) +/* binary loop input and output contiguous with first scalar */ +#define IS_BINARY_CONT_S1(tin, tout) (steps[0] == 0 && \ + steps[1] == sizeof(tin) && \ + steps[2] == sizeof(tout)) +/* binary loop input and output contiguous with second scalar */ +#define IS_BINARY_CONT_S2(tin, tout) (steps[0] == sizeof(tin) && \ + steps[1] == 0 && \ + steps[2] == sizeof(tout)) + +#define OUTPUT_LOOP\ + char *op1 = args[1];\ + npy_intp os1 = steps[1];\ + npy_intp n = dimensions[0];\ + npy_intp i;\ + for(i = 0; i < n; i++, op1 += os1) + +#define UNARY_LOOP\ + char *ip1 = args[0], *op1 = args[1];\ + npy_intp is1 = steps[0], os1 = steps[1];\ + npy_intp n = dimensions[0];\ + npy_intp i;\ + for(i = 0; i < n; i++, ip1 += is1, op1 += os1) + +/* + * loop with contiguous specialization + * op should be the code working on `tin in` and + * storing the result in `tout * out` + * combine with NPY_GCC_OPT_3 to allow autovectorization + * should only be used where its worthwhile to avoid code bloat + */ +#define BASE_UNARY_LOOP(tin, tout, op) \ + UNARY_LOOP { \ + const tin in = *(tin *)ip1; \ + tout * out = (tout *)op1; \ + op; \ + } +#define UNARY_LOOP_FAST(tin, tout, op) \ + do { \ + /* condition allows compiler to optimize the generic macro */ \ + if (IS_UNARY_CONT(tin, tout)) { \ + if (args[0] == args[1]) { \ + BASE_UNARY_LOOP(tin, tout, op) \ + } \ + else { \ + BASE_UNARY_LOOP(tin, tout, op) \ + } \ + } \ + else { \ + BASE_UNARY_LOOP(tin, tout, op) \ + } \ + } \ + while (0) + +#define UNARY_LOOP_TWO_OUT\ + char *ip1 = args[0], *op1 = args[1], *op2 = args[2];\ + npy_intp is1 = steps[0], os1 = steps[1], os2 = steps[2];\ + npy_intp n = dimensions[0];\ + npy_intp i;\ + for(i = 0; i < n; i++, ip1 += is1, op1 += os1, op2 += os2) + +#define BINARY_LOOP\ + char *ip1 = args[0], *ip2 = args[1], *op1 = args[2];\ + npy_intp is1 = steps[0], is2 = steps[1], os1 = steps[2];\ + npy_intp n = dimensions[0];\ + npy_intp i;\ + for(i = 0; i < n; i++, ip1 += is1, ip2 += is2, op1 += os1) + +/* + * loop with contiguous specialization + * op should be the code working on `tin in1`, `tin in2` and + * storing the result in `tout * out` + * combine with NPY_GCC_OPT_3 to allow autovectorization + * should only be used where its worthwhile to avoid code bloat + */ +#define BASE_BINARY_LOOP(tin, tout, op) \ + BINARY_LOOP { \ + const tin in1 = *(tin *)ip1; \ + const tin in2 = *(tin *)ip2; \ + tout * out = (tout *)op1; \ + op; \ + } +/* + * unfortunately gcc 6/7 regressed and we need to give it additional hints to + * vectorize inplace operations (PR80198) + * must only be used after op1 == ip1 or ip2 has been checked + * TODO: using ivdep might allow other compilers to vectorize too + */ +#if __GNUC__ >= 6 +#define IVDEP_LOOP _Pragma("GCC ivdep") +#else +#define IVDEP_LOOP +#endif +#define BASE_BINARY_LOOP_INP(tin, tout, op) \ + char *ip1 = args[0], *ip2 = args[1], *op1 = args[2];\ + npy_intp is1 = steps[0], is2 = steps[1], os1 = steps[2];\ + npy_intp n = dimensions[0];\ + npy_intp i;\ + IVDEP_LOOP \ + for(i = 0; i < n; i++, ip1 += is1, ip2 += is2, op1 += os1) { \ + const tin in1 = *(tin *)ip1; \ + const tin in2 = *(tin *)ip2; \ + tout * out = (tout *)op1; \ + op; \ + } +#define BASE_BINARY_LOOP_S(tin, tout, cin, cinp, vin, vinp, op) \ + const tin cin = *(tin *)cinp; \ + BINARY_LOOP { \ + const tin vin = *(tin *)vinp; \ + tout * out = (tout *)op1; \ + op; \ + } +/* PR80198 again, scalar works without the pragma */ +#define BASE_BINARY_LOOP_S_INP(tin, tout, cin, cinp, vin, vinp, op) \ + const tin cin = *(tin *)cinp; \ + BINARY_LOOP { \ + const tin vin = *(tin *)vinp; \ + tout * out = (tout *)vinp; \ + op; \ + } +#define BINARY_LOOP_FAST(tin, tout, op) \ + do { \ + /* condition allows compiler to optimize the generic macro */ \ + if (IS_BINARY_CONT(tin, tout)) { \ + if (args[2] == args[0]) { \ + BASE_BINARY_LOOP_INP(tin, tout, op) \ + } \ + else if (args[2] == args[1]) { \ + BASE_BINARY_LOOP_INP(tin, tout, op) \ + } \ + else { \ + BASE_BINARY_LOOP(tin, tout, op) \ + } \ + } \ + else if (IS_BINARY_CONT_S1(tin, tout)) { \ + if (args[1] == args[2]) { \ + BASE_BINARY_LOOP_S_INP(tin, tout, in1, args[0], in2, ip2, op) \ + } \ + else { \ + BASE_BINARY_LOOP_S(tin, tout, in1, args[0], in2, ip2, op) \ + } \ + } \ + else if (IS_BINARY_CONT_S2(tin, tout)) { \ + if (args[0] == args[2]) { \ + BASE_BINARY_LOOP_S_INP(tin, tout, in2, args[1], in1, ip1, op) \ + } \ + else { \ + BASE_BINARY_LOOP_S(tin, tout, in2, args[1], in1, ip1, op) \ + }\ + } \ + else { \ + BASE_BINARY_LOOP(tin, tout, op) \ + } \ + } \ + while (0) + +#define BINARY_REDUCE_LOOP_INNER\ + char *ip2 = args[1]; \ + npy_intp is2 = steps[1]; \ + npy_intp n = dimensions[0]; \ + npy_intp i; \ + for(i = 0; i < n; i++, ip2 += is2) + +#define BINARY_REDUCE_LOOP(TYPE)\ + char *iop1 = args[0]; \ + TYPE io1 = *(TYPE *)iop1; \ + BINARY_REDUCE_LOOP_INNER + +#define BINARY_LOOP_TWO_OUT\ + char *ip1 = args[0], *ip2 = args[1], *op1 = args[2], *op2 = args[3];\ + npy_intp is1 = steps[0], is2 = steps[1], os1 = steps[2], os2 = steps[3];\ + npy_intp n = dimensions[0];\ + npy_intp i;\ + for(i = 0; i < n; i++, ip1 += is1, ip2 += is2, op1 += os1, op2 += os2) + +/****************************************************************************** + ** GENERIC FLOAT LOOPS ** + *****************************************************************************/ + + +typedef float halfUnaryFunc(npy_half x); +typedef float floatUnaryFunc(float x); +typedef double doubleUnaryFunc(double x); +typedef npy_longdouble longdoubleUnaryFunc(npy_longdouble x); +typedef npy_half halfBinaryFunc(npy_half x, npy_half y); +typedef float floatBinaryFunc(float x, float y); +typedef double doubleBinaryFunc(double x, double y); +typedef npy_longdouble longdoubleBinaryFunc(npy_longdouble x, npy_longdouble y); + + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_e_e(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + halfUnaryFunc *f = (halfUnaryFunc *)func; + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *(npy_half *)op1 = f(in1); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_e_e_As_f_f(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + floatUnaryFunc *f = (floatUnaryFunc *)func; + UNARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *(npy_half *)op1 = npy_float_to_half(f(in1)); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_e_e_As_d_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + doubleUnaryFunc *f = (doubleUnaryFunc *)func; + UNARY_LOOP { + const double in1 = npy_half_to_double(*(npy_half *)ip1); + *(npy_half *)op1 = npy_double_to_half(f(in1)); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_f_f(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + floatUnaryFunc *f = (floatUnaryFunc *)func; + UNARY_LOOP { + const float in1 = *(float *)ip1; + *(float *)op1 = f(in1); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_f_f_As_d_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + doubleUnaryFunc *f = (doubleUnaryFunc *)func; + UNARY_LOOP { + const float in1 = *(float *)ip1; + *(float *)op1 = (float)f((double)in1); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_ee_e(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + halfBinaryFunc *f = (halfBinaryFunc *)func; + BINARY_LOOP { + npy_half in1 = *(npy_half *)ip1; + npy_half in2 = *(npy_half *)ip2; + *(npy_half *)op1 = f(in1, in2); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_ee_e_As_ff_f(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + floatBinaryFunc *f = (floatBinaryFunc *)func; + BINARY_LOOP { + float in1 = npy_half_to_float(*(npy_half *)ip1); + float in2 = npy_half_to_float(*(npy_half *)ip2); + *(npy_half *)op1 = npy_float_to_half(f(in1, in2)); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_ee_e_As_dd_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + doubleBinaryFunc *f = (doubleBinaryFunc *)func; + BINARY_LOOP { + double in1 = npy_half_to_double(*(npy_half *)ip1); + double in2 = npy_half_to_double(*(npy_half *)ip2); + *(npy_half *)op1 = npy_double_to_half(f(in1, in2)); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_ff_f(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + floatBinaryFunc *f = (floatBinaryFunc *)func; + BINARY_LOOP { + float in1 = *(float *)ip1; + float in2 = *(float *)ip2; + *(float *)op1 = f(in1, in2); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_ff_f_As_dd_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + doubleBinaryFunc *f = (doubleBinaryFunc *)func; + BINARY_LOOP { + float in1 = *(float *)ip1; + float in2 = *(float *)ip2; + *(float *)op1 = (double)f((double)in1, (double)in2); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_d_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + doubleUnaryFunc *f = (doubleUnaryFunc *)func; + UNARY_LOOP { + double in1 = *(double *)ip1; + *(double *)op1 = f(in1); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_dd_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + doubleBinaryFunc *f = (doubleBinaryFunc *)func; + BINARY_LOOP { + double in1 = *(double *)ip1; + double in2 = *(double *)ip2; + *(double *)op1 = f(in1, in2); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_g_g(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + longdoubleUnaryFunc *f = (longdoubleUnaryFunc *)func; + UNARY_LOOP { + npy_longdouble in1 = *(npy_longdouble *)ip1; + *(npy_longdouble *)op1 = f(in1); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_gg_g(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + longdoubleBinaryFunc *f = (longdoubleBinaryFunc *)func; + BINARY_LOOP { + npy_longdouble in1 = *(npy_longdouble *)ip1; + npy_longdouble in2 = *(npy_longdouble *)ip2; + *(npy_longdouble *)op1 = f(in1, in2); + } +} + + + +/****************************************************************************** + ** GENERIC COMPLEX LOOPS ** + *****************************************************************************/ + + +typedef void cdoubleUnaryFunc(npy_cdouble *x, npy_cdouble *r); +typedef void cfloatUnaryFunc(npy_cfloat *x, npy_cfloat *r); +typedef void clongdoubleUnaryFunc(npy_clongdouble *x, npy_clongdouble *r); +typedef void cdoubleBinaryFunc(npy_cdouble *x, npy_cdouble *y, npy_cdouble *r); +typedef void cfloatBinaryFunc(npy_cfloat *x, npy_cfloat *y, npy_cfloat *r); +typedef void clongdoubleBinaryFunc(npy_clongdouble *x, npy_clongdouble *y, + npy_clongdouble *r); + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_F_F(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + cfloatUnaryFunc *f = (cfloatUnaryFunc *)func; + UNARY_LOOP { + npy_cfloat in1 = *(npy_cfloat *)ip1; + npy_cfloat *out = (npy_cfloat *)op1; + f(&in1, out); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_F_F_As_D_D(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + cdoubleUnaryFunc *f = (cdoubleUnaryFunc *)func; + UNARY_LOOP { + npy_cdouble tmp, out; + tmp.real = (double)((float *)ip1)[0]; + tmp.imag = (double)((float *)ip1)[1]; + f(&tmp, &out); + ((float *)op1)[0] = (float)out.real; + ((float *)op1)[1] = (float)out.imag; + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_FF_F(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + cfloatBinaryFunc *f = (cfloatBinaryFunc *)func; + BINARY_LOOP { + npy_cfloat in1 = *(npy_cfloat *)ip1; + npy_cfloat in2 = *(npy_cfloat *)ip2; + npy_cfloat *out = (npy_cfloat *)op1; + f(&in1, &in2, out); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_FF_F_As_DD_D(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + cdoubleBinaryFunc *f = (cdoubleBinaryFunc *)func; + BINARY_LOOP { + npy_cdouble tmp1, tmp2, out; + tmp1.real = (double)((float *)ip1)[0]; + tmp1.imag = (double)((float *)ip1)[1]; + tmp2.real = (double)((float *)ip2)[0]; + tmp2.imag = (double)((float *)ip2)[1]; + f(&tmp1, &tmp2, &out); + ((float *)op1)[0] = (float)out.real; + ((float *)op1)[1] = (float)out.imag; + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_D_D(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + cdoubleUnaryFunc *f = (cdoubleUnaryFunc *)func; + UNARY_LOOP { + npy_cdouble in1 = *(npy_cdouble *)ip1; + npy_cdouble *out = (npy_cdouble *)op1; + f(&in1, out); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_DD_D(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + cdoubleBinaryFunc *f = (cdoubleBinaryFunc *)func; + BINARY_LOOP { + npy_cdouble in1 = *(npy_cdouble *)ip1; + npy_cdouble in2 = *(npy_cdouble *)ip2; + npy_cdouble *out = (npy_cdouble *)op1; + f(&in1, &in2, out); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_G_G(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + clongdoubleUnaryFunc *f = (clongdoubleUnaryFunc *)func; + UNARY_LOOP { + npy_clongdouble in1 = *(npy_clongdouble *)ip1; + npy_clongdouble *out = (npy_clongdouble *)op1; + f(&in1, out); + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_GG_G(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + clongdoubleBinaryFunc *f = (clongdoubleBinaryFunc *)func; + BINARY_LOOP { + npy_clongdouble in1 = *(npy_clongdouble *)ip1; + npy_clongdouble in2 = *(npy_clongdouble *)ip2; + npy_clongdouble *out = (npy_clongdouble *)op1; + f(&in1, &in2, out); + } +} + + +/****************************************************************************** + ** GENERIC OBJECT lOOPS ** + *****************************************************************************/ + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_O_O(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + unaryfunc f = (unaryfunc)func; + UNARY_LOOP { + PyObject *in1 = *(PyObject **)ip1; + PyObject **out = (PyObject **)op1; + PyObject *ret = f(in1 ? in1 : Py_None); + if (ret == NULL) { + return; + } + Py_XDECREF(*out); + *out = ret; + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_O_O_method(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + char *meth = (char *)func; + UNARY_LOOP { + PyObject *in1 = *(PyObject **)ip1; + PyObject **out = (PyObject **)op1; + PyObject *ret = PyObject_CallMethod(in1 ? in1 : Py_None, meth, NULL); + if (ret == NULL) { + return; + } + Py_XDECREF(*out); + *out = ret; + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_OO_O(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + binaryfunc f = (binaryfunc)func; + BINARY_LOOP { + PyObject *in1 = *(PyObject **)ip1; + PyObject *in2 = *(PyObject **)ip2; + PyObject **out = (PyObject **)op1; + PyObject *ret = f(in1 ? in1 : Py_None, in2 ? in2 : Py_None); + if (ret == NULL) { + return; + } + Py_XDECREF(*out); + *out = ret; + } +} + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_OO_O_method(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + char *meth = (char *)func; + BINARY_LOOP { + PyObject *in1 = *(PyObject **)ip1; + PyObject *in2 = *(PyObject **)ip2; + PyObject **out = (PyObject **)op1; + PyObject *ret = PyObject_CallMethod(in1 ? in1 : Py_None, + meth, "(O)", in2); + if (ret == NULL) { + return; + } + Py_XDECREF(*out); + *out = ret; + } +} + +/* + * A general-purpose ufunc that deals with general-purpose Python callable. + * func is a structure with nin, nout, and a Python callable function + */ + +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_On_Om(char **args, npy_intp *dimensions, npy_intp *steps, void *func) +{ + npy_intp n = dimensions[0]; + PyUFunc_PyFuncData *data = (PyUFunc_PyFuncData *)func; + int nin = data->nin; + int nout = data->nout; + PyObject *tocall = data->callable; + char *ptrs[NPY_MAXARGS]; + PyObject *arglist, *result; + PyObject *in, **op; + npy_intp i, j, ntot; + + ntot = nin+nout; + + for(j = 0; j < ntot; j++) { + ptrs[j] = args[j]; + } + for(i = 0; i < n; i++) { + arglist = PyTuple_New(nin); + if (arglist == NULL) { + return; + } + for(j = 0; j < nin; j++) { + in = *((PyObject **)ptrs[j]); + if (in == NULL) { + in = Py_None; + } + PyTuple_SET_ITEM(arglist, j, in); + Py_INCREF(in); + } + result = PyEval_CallObject(tocall, arglist); + Py_DECREF(arglist); + if (result == NULL) { + return; + } + if (nout == 0 && result == Py_None) { + /* No output expected, no output received, continue */ + Py_DECREF(result); + } + else if (nout == 1) { + /* Single output expected, assign and continue */ + op = (PyObject **)ptrs[nin]; + Py_XDECREF(*op); + *op = result; + } + else if (PyTuple_Check(result) && nout == PyTuple_Size(result)) { + /* + * Multiple returns match expected number of outputs, assign + * and continue. Will also gobble empty tuples if nout == 0. + */ + for(j = 0; j < nout; j++) { + op = (PyObject **)ptrs[j+nin]; + Py_XDECREF(*op); + *op = PyTuple_GET_ITEM(result, j); + Py_INCREF(*op); + } + Py_DECREF(result); + } + else { + /* Mismatch between returns and expected outputs, exit */ + Py_DECREF(result); + return; + } + for(j = 0; j < ntot; j++) { + ptrs[j] += steps[j]; + } + } +} + +/* + ***************************************************************************** + ** BOOLEAN LOOPS ** + ***************************************************************************** + */ + +/**begin repeat + * #kind = equal, not_equal, greater, greater_equal, less, less_equal# + * #OP = ==, !=, >, >=, <, <=# + **/ + +NPY_NO_EXPORT void +BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + npy_bool in1 = *((npy_bool *)ip1) != 0; + npy_bool in2 = *((npy_bool *)ip2) != 0; + *((npy_bool *)op1)= in1 @OP@ in2; + } +} +/**end repeat**/ + + +/**begin repeat + * #kind = logical_and, logical_or# + * #OP = &&, ||# + * #SC = ==, !=# + * #and = 1, 0# + **/ + +NPY_NO_EXPORT void +BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if(IS_BINARY_REDUCE) { +#ifdef NPY_HAVE_SSE2_INTRINSICS + /* + * stick with our variant for more reliable performance, only known + * platform which outperforms it by ~20% is an i7 with glibc 2.17 + */ + if (run_reduce_simd_@kind@_BOOL(args, dimensions, steps)) { + return; + } +#else + /* for now only use libc on 32-bit/non-x86 */ + if (steps[1] == 1) { + npy_bool * op = (npy_bool *)args[0]; +#if @and@ + /* np.all(), search for a zero (false) */ + if (*op) { + *op = memchr(args[1], 0, dimensions[0]) == NULL; + } +#else + /* + * np.any(), search for a non-zero (true) via comparing against + * zero blocks, memcmp is faster than memchr on SSE4 machines + * with glibc >= 2.12 and memchr can only check for equal 1 + */ + static const npy_bool zero[4096]; /* zero by C standard */ + npy_uintp i, n = dimensions[0]; + + for (i = 0; !*op && i < n - (n % sizeof(zero)); i += sizeof(zero)) { + *op = memcmp(&args[1][i], zero, sizeof(zero)) != 0; + } + if (!*op && n - i > 0) { + *op = memcmp(&args[1][i], zero, n - i) != 0; + } +#endif + return; + } +#endif + else { + BINARY_REDUCE_LOOP(npy_bool) { + const npy_bool in2 = *(npy_bool *)ip2; + io1 = io1 @OP@ in2; + if (io1 @SC@ 0) { + break; + } + } + *((npy_bool *)iop1) = io1; + } + } + else { + if (run_binary_simd_@kind@_BOOL(args, dimensions, steps)) { + return; + } + else { + BINARY_LOOP { + const npy_bool in1 = *(npy_bool *)ip1; + const npy_bool in2 = *(npy_bool *)ip2; + *((npy_bool *)op1) = in1 @OP@ in2; + } + } + } +} +/**end repeat**/ + +/**begin repeat + * #kind = absolute, logical_not# + * #OP = !=, ==# + **/ +NPY_NO_EXPORT void +BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (run_unary_simd_@kind@_BOOL(args, dimensions, steps)) { + return; + } + else { + UNARY_LOOP { + npy_bool in1 = *(npy_bool *)ip1; + *((npy_bool *)op1) = in1 @OP@ 0; + } + } +} +/**end repeat**/ + +NPY_NO_EXPORT void +BOOL__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + OUTPUT_LOOP { + *((npy_bool *)op1) = 1; + } +} + + +/* + ***************************************************************************** + ** INTEGER LOOPS + ***************************************************************************** + */ + +/**begin repeat + * #TYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong# + * #ftype = npy_float, npy_float, npy_float, npy_float, npy_double, npy_double, + * npy_double, npy_double, npy_double, npy_double# + * #SIGNED = 1, 0, 1, 0, 1, 0, 1, 0, 1, 0# + */ + +#define @TYPE@_floor_divide @TYPE@_divide +#define @TYPE@_fmax @TYPE@_maximum +#define @TYPE@_fmin @TYPE@_minimum + +NPY_NO_EXPORT void +@TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + OUTPUT_LOOP { + *((@type@ *)op1) = 1; + } +} + +NPY_NO_EXPORT void +@TYPE@_positive(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = +in); +} + +/**begin repeat1 + * #isa = , _avx2# + * #ISA = , AVX2# + * #CHK = 1, HAVE_ATTRIBUTE_TARGET_AVX2# + * #ATTR = , NPY_GCC_TARGET_AVX2# + */ + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_square@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = in * in); +} +#endif + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_reciprocal@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = 1.0 / in); +} +#endif + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_conjugate@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = in); +} +#endif + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_negative@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = -in); +} +#endif + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_logical_not@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(@type@, npy_bool, *out = !in); +} +#endif + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_invert@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = ~in); +} +#endif + +/**begin repeat2 + * Arithmetic + * #kind = add, subtract, multiply, bitwise_and, bitwise_or, bitwise_xor, + * left_shift, right_shift# + * #OP = +, -,*, &, |, ^, <<, >># + */ + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_@kind@@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if(IS_BINARY_REDUCE) { + BINARY_REDUCE_LOOP(@type@) { + io1 @OP@= *(@type@ *)ip2; + } + *((@type@ *)iop1) = io1; + } + else { + BINARY_LOOP_FAST(@type@, @type@, *out = in1 @OP@ in2); + } +} +#endif + +/**end repeat2**/ + +/**begin repeat2 + * #kind = equal, not_equal, greater, greater_equal, less, less_equal, + * logical_and, logical_or# + * #OP = ==, !=, >, >=, <, <=, &&, ||# + */ + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_@kind@@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* + * gcc vectorization of this is not good (PR60575) but manual integer + * vectorization is too tedious to be worthwhile + */ + BINARY_LOOP_FAST(@type@, npy_bool, *out = in1 @OP@ in2); +} +#endif + +/**end repeat2**/ + +#if @CHK@ +NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void +@TYPE@_logical_xor@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const int t1 = !!*(@type@ *)ip1; + const int t2 = !!*(@type@ *)ip2; + *((npy_bool *)op1) = (t1 != t2); + } +} +#endif + +/**end repeat1**/ + +/**begin repeat1 + * #kind = maximum, minimum# + * #OP = >, <# + **/ + +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (IS_BINARY_REDUCE) { + BINARY_REDUCE_LOOP(@type@) { + const @type@ in2 = *(@type@ *)ip2; + io1 = (io1 @OP@ in2) ? io1 : in2; + } + *((@type@ *)iop1) = io1; + } + else { + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((@type@ *)op1) = (in1 @OP@ in2) ? in1 : in2; + } + } +} + +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_power(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + @type@ in1 = *(@type@ *)ip1; + @type@ in2 = *(@type@ *)ip2; + @type@ out; + +#if @SIGNED@ + if (in2 < 0) { + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API; + PyErr_SetString(PyExc_ValueError, + "Integers to negative integer powers are not allowed."); + NPY_DISABLE_C_API; + return; + } +#endif + if (in2 == 0) { + *((@type@ *)op1) = 1; + continue; + } + if (in1 == 1) { + *((@type@ *)op1) = 1; + continue; + } + + out = in2 & 1 ? in1 : 1; + in2 >>= 1; + while (in2 > 0) { + in1 *= in1; + if (in2 & 1) { + out *= in1; + } + in2 >>= 1; + } + *((@type@ *) op1) = out; + } +} + +NPY_NO_EXPORT void +@TYPE@_fmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + if (in2 == 0) { + npy_set_floatstatus_divbyzero(); + *((@type@ *)op1) = 0; + } + else { + *((@type@ *)op1)= in1 % in2; + } + + } +} + +/**end repeat**/ + +/**begin repeat + * #TYPE = BYTE, SHORT, INT, LONG, LONGLONG# + * #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong# + */ + +NPY_NO_EXPORT NPY_GCC_OPT_3 void +@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = (in >= 0) ? in : -in); +} + +NPY_NO_EXPORT NPY_GCC_OPT_3 void +@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = in > 0 ? 1 : (in < 0 ? -1 : 0)); +} + +NPY_NO_EXPORT void +@TYPE@_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + /* + * FIXME: On x86 at least, dividing the smallest representable integer + * by -1 causes a SIFGPE (division overflow). We treat this case here + * (to avoid a SIGFPE crash at python level), but a good solution would + * be to treat integer division problems separately from FPU exceptions + * (i.e. a different approach than npy_set_floatstatus_divbyzero()). + */ + if (in2 == 0 || (in1 == NPY_MIN_@TYPE@ && in2 == -1)) { + npy_set_floatstatus_divbyzero(); + *((@type@ *)op1) = 0; + } + else if (((in1 > 0) != (in2 > 0)) && (in1 % in2 != 0)) { + *((@type@ *)op1) = in1/in2 - 1; + } + else { + *((@type@ *)op1) = in1/in2; + } + } +} + +NPY_NO_EXPORT void +@TYPE@_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + if (in2 == 0) { + npy_set_floatstatus_divbyzero(); + *((@type@ *)op1) = 0; + } + else { + /* handle mixed case the way Python does */ + const @type@ rem = in1 % in2; + if ((in1 > 0) == (in2 > 0) || rem == 0) { + *((@type@ *)op1) = rem; + } + else { + *((@type@ *)op1) = rem + in2; + } + } + } +} + +NPY_NO_EXPORT void +@TYPE@_divmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP_TWO_OUT { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + /* see FIXME note for divide above */ + if (in2 == 0 || (in1 == NPY_MIN_@TYPE@ && in2 == -1)) { + npy_set_floatstatus_divbyzero(); + *((@type@ *)op1) = 0; + *((@type@ *)op2) = 0; + } + else { + /* handle mixed case the way Python does */ + const @type@ quo = in1 / in2; + const @type@ rem = in1 % in2; + if ((in1 > 0) == (in2 > 0) || rem == 0) { + *((@type@ *)op1) = quo; + *((@type@ *)op2) = rem; + } + else { + *((@type@ *)op1) = quo - 1; + *((@type@ *)op2) = rem + in2; + } + } + } +} + +/**end repeat**/ + +/**begin repeat + * #TYPE = UBYTE, USHORT, UINT, ULONG, ULONGLONG# + * #type = npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong# + */ + +NPY_NO_EXPORT void +@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = in1; + } +} + +NPY_NO_EXPORT NPY_GCC_OPT_3 void +@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(@type@, @type@, *out = in > 0 ? 1 : 0); +} + +NPY_NO_EXPORT void +@TYPE@_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + if (in2 == 0) { + npy_set_floatstatus_divbyzero(); + *((@type@ *)op1) = 0; + } + else { + *((@type@ *)op1)= in1/in2; + } + } +} + +NPY_NO_EXPORT void +@TYPE@_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + if (in2 == 0) { + npy_set_floatstatus_divbyzero(); + *((@type@ *)op1) = 0; + } + else { + *((@type@ *)op1) = in1 % in2; + } + } +} + +NPY_NO_EXPORT void +@TYPE@_divmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP_TWO_OUT { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + if (in2 == 0) { + npy_set_floatstatus_divbyzero(); + *((@type@ *)op1) = 0; + *((@type@ *)op2) = 0; + } + else { + *((@type@ *)op1)= in1/in2; + *((@type@ *)op2) = in1 % in2; + } + } +} + +/**end repeat**/ + +/* + ***************************************************************************** + ** DATETIME LOOPS ** + ***************************************************************************** + */ + +NPY_NO_EXPORT void +TIMEDELTA_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + if (in1 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_timedelta *)op1) = -in1; + } + } +} + +NPY_NO_EXPORT void +TIMEDELTA_positive(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + *((npy_timedelta *)op1) = +in1; + } +} + +NPY_NO_EXPORT void +TIMEDELTA_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + if (in1 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_timedelta *)op1) = (in1 >= 0) ? in1 : -in1; + } + } +} + +NPY_NO_EXPORT void +TIMEDELTA_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + *((npy_timedelta *)op1) = in1 > 0 ? 1 : (in1 < 0 ? -1 : 0); + } +} + +/**begin repeat + * #type = npy_datetime, npy_timedelta# + * #TYPE = DATETIME, TIMEDELTA# + */ + +NPY_NO_EXPORT void +@TYPE@_isnat(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((npy_bool *)op1) = (in1 == NPY_DATETIME_NAT); + } +} + +NPY_NO_EXPORT void +@TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + OUTPUT_LOOP { + *((@type@ *)op1) = 1; + } +} + +/**begin repeat1 + * #kind = equal, greater, greater_equal, less, less_equal# + * #OP = ==, >, >=, <, <=# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + npy_bool give_future_warning = 0; + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + const npy_bool res = in1 @OP@ in2; + *((npy_bool *)op1) = res; + + if ((in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) && res) { + give_future_warning = 1; + } + } + if (give_future_warning) { + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API; + /* 2016-01-18, 1.11 */ + if (DEPRECATE_FUTUREWARNING( + "In the future, 'NAT @OP@ x' and 'x @OP@ NAT' " + "will always be False.") < 0) { + /* nothing to do, we return anyway */ + } + NPY_DISABLE_C_API; + } +} +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_not_equal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + npy_bool give_future_warning = 0; + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((npy_bool *)op1) = in1 != in2; + + if (in1 == NPY_DATETIME_NAT && in2 == NPY_DATETIME_NAT) { + give_future_warning = 1; + } + } + if (give_future_warning) { + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API; + /* 2016-01-18, 1.11 */ + if (DEPRECATE_FUTUREWARNING( + "In the future, NAT != NAT will be True " + "rather than False.") < 0) { + /* nothing to do, we return anyway */ + } + NPY_DISABLE_C_API; + } +} + + +/**begin repeat1 + * #kind = maximum, minimum# + * #OP = >, <# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + if (in1 == NPY_DATETIME_NAT) { + *((@type@ *)op1) = in2; + } + else if (in2 == NPY_DATETIME_NAT) { + *((@type@ *)op1) = in1; + } + else { + *((@type@ *)op1) = (in1 @OP@ in2) ? in1 : in2; + } + } +} +/**end repeat1**/ + +/**end repeat**/ + +NPY_NO_EXPORT void +DATETIME_Mm_M_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + BINARY_LOOP { + const npy_datetime in1 = *(npy_datetime *)ip1; + const npy_timedelta in2 = *(npy_timedelta *)ip2; + if (in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) { + *((npy_datetime *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_datetime *)op1) = in1 + in2; + } + } +} + +NPY_NO_EXPORT void +DATETIME_mM_M_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + const npy_datetime in2 = *(npy_datetime *)ip2; + if (in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) { + *((npy_datetime *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_datetime *)op1) = in1 + in2; + } + } +} + +NPY_NO_EXPORT void +TIMEDELTA_mm_m_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + const npy_timedelta in2 = *(npy_timedelta *)ip2; + if (in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_timedelta *)op1) = in1 + in2; + } + } +} + +NPY_NO_EXPORT void +DATETIME_Mm_M_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_datetime in1 = *(npy_datetime *)ip1; + const npy_timedelta in2 = *(npy_timedelta *)ip2; + if (in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) { + *((npy_datetime *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_datetime *)op1) = in1 - in2; + } + } +} + +NPY_NO_EXPORT void +DATETIME_MM_m_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_datetime in1 = *(npy_datetime *)ip1; + const npy_datetime in2 = *(npy_datetime *)ip2; + if (in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_timedelta *)op1) = in1 - in2; + } + } +} + +NPY_NO_EXPORT void +TIMEDELTA_mm_m_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + const npy_timedelta in2 = *(npy_timedelta *)ip2; + if (in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_timedelta *)op1) = in1 - in2; + } + } +} + +/* Note: Assuming 'q' == NPY_LONGLONG */ +NPY_NO_EXPORT void +TIMEDELTA_mq_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + const npy_int64 in2 = *(npy_int64 *)ip2; + if (in1 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_timedelta *)op1) = in1 * in2; + } + } +} + +/* Note: Assuming 'q' == NPY_LONGLONG */ +NPY_NO_EXPORT void +TIMEDELTA_qm_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_int64 in1 = *(npy_int64 *)ip1; + const npy_timedelta in2 = *(npy_timedelta *)ip2; + if (in2 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_timedelta *)op1) = in1 * in2; + } + } +} + +NPY_NO_EXPORT void +TIMEDELTA_md_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + const double in2 = *(double *)ip2; + if (in1 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + double result = in1 * in2; + if (npy_isfinite(result)) { + *((npy_timedelta *)op1) = (npy_timedelta)result; + } + else { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + } + } +} + +NPY_NO_EXPORT void +TIMEDELTA_dm_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const double in1 = *(double *)ip1; + const npy_timedelta in2 = *(npy_timedelta *)ip2; + if (in2 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + double result = in1 * in2; + if (npy_isfinite(result)) { + *((npy_timedelta *)op1) = (npy_timedelta)result; + } + else { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + } + } +} + +/* Note: Assuming 'q' == NPY_LONGLONG */ +NPY_NO_EXPORT void +TIMEDELTA_mq_m_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + const npy_int64 in2 = *(npy_int64 *)ip2; + if (in1 == NPY_DATETIME_NAT || in2 == 0) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + *((npy_timedelta *)op1) = in1 / in2; + } + } +} + +NPY_NO_EXPORT void +TIMEDELTA_md_m_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + const double in2 = *(double *)ip2; + if (in1 == NPY_DATETIME_NAT) { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + else { + double result = in1 / in2; + if (npy_isfinite(result)) { + *((npy_timedelta *)op1) = (npy_timedelta)result; + } + else { + *((npy_timedelta *)op1) = NPY_DATETIME_NAT; + } + } + } +} + +NPY_NO_EXPORT void +TIMEDELTA_mm_d_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_timedelta in1 = *(npy_timedelta *)ip1; + const npy_timedelta in2 = *(npy_timedelta *)ip2; + if (in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) { + *((double *)op1) = NPY_NAN; + } + else { + *((double *)op1) = (double)in1 / (double)in2; + } + } +} + +/* + ***************************************************************************** + ** FLOAT LOOPS ** + ***************************************************************************** + */ + +/**begin repeat + * Float types + * #type = npy_float, npy_double# + * #TYPE = FLOAT, DOUBLE# + * #scalarf = npy_sqrtf, npy_sqrt# + */ + +NPY_NO_EXPORT void +@TYPE@_sqrt(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (!run_unary_simd_sqrt_@TYPE@(args, dimensions, steps)) { + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *(@type@ *)op1 = @scalarf@(in1); + } + } +} + +/**end repeat**/ + + +/**begin repeat + * Float types + * #type = npy_float, npy_double, npy_longdouble, npy_float# + * #dtype = npy_float, npy_double, npy_longdouble, npy_half# + * #TYPE = FLOAT, DOUBLE, LONGDOUBLE, HALF# + * #c = f, , l, # + * #C = F, , L, # + * #trf = , , , npy_half_to_float# + */ + +/* + * Pairwise summation, rounding error O(lg n) instead of O(n). + * The recursion depth is O(lg n) as well. + * when updating also update similar complex floats summation + */ +static @type@ +pairwise_sum_@TYPE@(char *a, npy_uintp n, npy_intp stride) +{ + if (n < 8) { + npy_intp i; + @type@ res = 0.; + for (i = 0; i < n; i++) { + res += @trf@(*((@dtype@*)(a + i * stride))); + } + return res; + } + else if (n <= PW_BLOCKSIZE) { + npy_intp i; + @type@ r[8], res; + + /* + * sum a block with 8 accumulators + * 8 times unroll reduces blocksize to 16 and allows vectorization with + * avx without changing summation ordering + */ + r[0] = @trf@(*((@dtype@ *)(a + 0 * stride))); + r[1] = @trf@(*((@dtype@ *)(a + 1 * stride))); + r[2] = @trf@(*((@dtype@ *)(a + 2 * stride))); + r[3] = @trf@(*((@dtype@ *)(a + 3 * stride))); + r[4] = @trf@(*((@dtype@ *)(a + 4 * stride))); + r[5] = @trf@(*((@dtype@ *)(a + 5 * stride))); + r[6] = @trf@(*((@dtype@ *)(a + 6 * stride))); + r[7] = @trf@(*((@dtype@ *)(a + 7 * stride))); + + for (i = 8; i < n - (n % 8); i += 8) { + /* small blocksizes seems to mess with hardware prefetch */ + NPY_PREFETCH(a + (i + 512 / sizeof(@dtype@)) * stride, 0, 3); + r[0] += @trf@(*((@dtype@ *)(a + (i + 0) * stride))); + r[1] += @trf@(*((@dtype@ *)(a + (i + 1) * stride))); + r[2] += @trf@(*((@dtype@ *)(a + (i + 2) * stride))); + r[3] += @trf@(*((@dtype@ *)(a + (i + 3) * stride))); + r[4] += @trf@(*((@dtype@ *)(a + (i + 4) * stride))); + r[5] += @trf@(*((@dtype@ *)(a + (i + 5) * stride))); + r[6] += @trf@(*((@dtype@ *)(a + (i + 6) * stride))); + r[7] += @trf@(*((@dtype@ *)(a + (i + 7) * stride))); + } + + /* accumulate now to avoid stack spills for single peel loop */ + res = ((r[0] + r[1]) + (r[2] + r[3])) + + ((r[4] + r[5]) + (r[6] + r[7])); + + /* do non multiple of 8 rest */ + for (; i < n; i++) { + res += @trf@(*((@dtype@ *)(a + i * stride))); + } + return res; + } + else { + /* divide by two but avoid non-multiples of unroll factor */ + npy_uintp n2 = n / 2; + n2 -= n2 % 8; + return pairwise_sum_@TYPE@(a, n2, stride) + + pairwise_sum_@TYPE@(a + n2 * stride, n - n2, stride); + } +} + +/**end repeat**/ + +/**begin repeat + * Float types + * #type = npy_float, npy_double, npy_longdouble# + * #TYPE = FLOAT, DOUBLE, LONGDOUBLE# + * #c = f, , l# + * #C = F, , L# + */ + +/**begin repeat1 + * Arithmetic + * # kind = add, subtract, multiply, divide# + * # OP = +, -, *, /# + * # PW = 1, 0, 0, 0# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (IS_BINARY_REDUCE) { +#if @PW@ + @type@ * iop1 = (@type@ *)args[0]; + npy_intp n = dimensions[0]; + + *iop1 @OP@= pairwise_sum_@TYPE@(args[1], n, steps[1]); +#else + BINARY_REDUCE_LOOP(@type@) { + io1 @OP@= *(@type@ *)ip2; + } + *((@type@ *)iop1) = io1; +#endif + } + else if (!run_binary_simd_@kind@_@TYPE@(args, dimensions, steps)) { + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((@type@ *)op1) = in1 @OP@ in2; + } + } +} +/**end repeat1**/ + +/**begin repeat1 + * #kind = equal, not_equal, less, less_equal, greater, greater_equal, + * logical_and, logical_or# + * #OP = ==, !=, <, <=, >, >=, &&, ||# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (!run_binary_simd_@kind@_@TYPE@(args, dimensions, steps)) { + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((npy_bool *)op1) = in1 @OP@ in2; + } + } +} +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const int t1 = !!*(@type@ *)ip1; + const int t2 = !!*(@type@ *)ip2; + *((npy_bool *)op1) = (t1 != t2); + } +} + +NPY_NO_EXPORT void +@TYPE@_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((npy_bool *)op1) = !in1; + } +} + +/**begin repeat1 + * #kind = isnan, isinf, isfinite, signbit# + * #func = npy_isnan, npy_isinf, npy_isfinite, npy_signbit# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (!run_@kind@_simd_@TYPE@(args, dimensions, steps)) { + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((npy_bool *)op1) = @func@(in1) != 0; + } + } + npy_clear_floatstatus(); +} +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_spacing(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = npy_spacing@c@(in1); + } +} + +NPY_NO_EXPORT void +@TYPE@_copysign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((@type@ *)op1)= npy_copysign@c@(in1, in2); + } +} + +NPY_NO_EXPORT void +@TYPE@_nextafter(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((@type@ *)op1)= npy_nextafter@c@(in1, in2); + } +} + +/**begin repeat1 + * #kind = maximum, minimum# + * #OP = >=, <=# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* */ + if (IS_BINARY_REDUCE) { + if (!run_unary_reduce_simd_@kind@_@TYPE@(args, dimensions, steps)) { + BINARY_REDUCE_LOOP(@type@) { + const @type@ in2 = *(@type@ *)ip2; + io1 = (io1 @OP@ in2 || npy_isnan(io1)) ? io1 : in2; + } + *((@type@ *)iop1) = io1; + } + } + else { + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((@type@ *)op1) = (in1 @OP@ in2 || npy_isnan(in1)) ? in1 : in2; + } + } +} +/**end repeat1**/ + +/**begin repeat1 + * #kind = fmax, fmin# + * #OP = >=, <=# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* */ + if (IS_BINARY_REDUCE) { + BINARY_REDUCE_LOOP(@type@) { + const @type@ in2 = *(@type@ *)ip2; + io1 = (io1 @OP@ in2 || npy_isnan(in2)) ? io1 : in2; + } + *((@type@ *)iop1) = io1; + } + else { + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((@type@ *)op1) = (in1 @OP@ in2 || npy_isnan(in2)) ? in1 : in2; + } + } + npy_clear_floatstatus(); +} +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + @type@ mod; + *((@type@ *)op1) = npy_divmod@c@(in1, in2, &mod); + } +} + +NPY_NO_EXPORT void +@TYPE@_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + npy_divmod@c@(in1, in2, (@type@ *)op1); + } +} + +NPY_NO_EXPORT void +@TYPE@_divmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP_TWO_OUT { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + *((@type@ *)op1) = npy_divmod@c@(in1, in2, (@type@ *)op2); + } +} + +NPY_NO_EXPORT void +@TYPE@_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + char * margs[] = {args[0], args[0], args[1]}; + npy_intp msteps[] = {steps[0], steps[0], steps[1]}; + if (!run_binary_simd_multiply_@TYPE@(margs, dimensions, msteps)) { + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = in1*in1; + } + } +} + +NPY_NO_EXPORT void +@TYPE@_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + @type@ one = 1.@c@; + char * margs[] = {(char*)&one, args[0], args[1]}; + npy_intp msteps[] = {0, steps[0], steps[1]}; + if (!run_binary_simd_divide_@TYPE@(margs, dimensions, msteps)) { + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = 1/in1; + } + } +} + +NPY_NO_EXPORT void +@TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + OUTPUT_LOOP { + *((@type@ *)op1) = 1; + } +} + +NPY_NO_EXPORT void +@TYPE@_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = in1; + } +} + +NPY_NO_EXPORT void +@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (!run_unary_simd_absolute_@TYPE@(args, dimensions, steps)) { + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ tmp = in1 > 0 ? in1 : -in1; + /* add 0 to clear -0.0 */ + *((@type@ *)op1) = tmp + 0; + } + } + npy_clear_floatstatus(); +} + +NPY_NO_EXPORT void +@TYPE@_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (!run_unary_simd_negative_@TYPE@(args, dimensions, steps)) { + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = -in1; + } + } +} + +NPY_NO_EXPORT void +@TYPE@_positive(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = +in1; + } +} + +NPY_NO_EXPORT void +@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* Sign of nan is nan */ + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = in1 > 0 ? 1 : (in1 < 0 ? -1 : (in1 == 0 ? 0 : in1)); + } +} + +NPY_NO_EXPORT void +@TYPE@_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_TWO_OUT { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = npy_modf@c@(in1, (@type@ *)op2); + } +} + +NPY_NO_EXPORT void +@TYPE@_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_TWO_OUT { + const @type@ in1 = *(@type@ *)ip1; + *((@type@ *)op1) = npy_frexp@c@(in1, (int *)op2); + } +} + +NPY_NO_EXPORT void +@TYPE@_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const int in2 = *(int *)ip2; + *((@type@ *)op1) = npy_ldexp@c@(in1, in2); + } +} + +NPY_NO_EXPORT void +@TYPE@_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* + * Additional loop to handle npy_long integer inputs (cf. #866, #1633). + * npy_long != npy_int on many 64-bit platforms, so we need this second loop + * to handle the default integer type. + */ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const long in2 = *(long *)ip2; + if (((int)in2) == in2) { + /* Range OK */ + *((@type@ *)op1) = npy_ldexp@c@(in1, ((int)in2)); + } + else { + /* + * Outside npy_int range -- also ldexp will overflow in this case, + * given that exponent has less bits than npy_int. + */ + if (in2 > 0) { + *((@type@ *)op1) = npy_ldexp@c@(in1, NPY_MAX_INT); + } + else { + *((@type@ *)op1) = npy_ldexp@c@(in1, NPY_MIN_INT); + } + } + } +} + +#define @TYPE@_true_divide @TYPE@_divide + +/**end repeat**/ + +/* + ***************************************************************************** + ** HALF-FLOAT LOOPS ** + ***************************************************************************** + */ + + +/**begin repeat + * Arithmetic + * # kind = add, subtract, multiply, divide# + * # OP = +, -, *, /# + * # PW = 1, 0, 0, 0# + */ +NPY_NO_EXPORT void +HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (IS_BINARY_REDUCE) { + char *iop1 = args[0]; + float io1 = npy_half_to_float(*(npy_half *)iop1); +#if @PW@ + npy_intp n = dimensions[0]; + + io1 @OP@= pairwise_sum_HALF(args[1], n, steps[1]); +#else + BINARY_REDUCE_LOOP_INNER { + io1 @OP@= npy_half_to_float(*(npy_half *)ip2); + } +#endif + *((npy_half *)iop1) = npy_float_to_half(io1); + } + else { + BINARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + const float in2 = npy_half_to_float(*(npy_half *)ip2); + *((npy_half *)op1) = npy_float_to_half(in1 @OP@ in2); + } + } +} +/**end repeat**/ + +#define _HALF_LOGICAL_AND(a,b) (!npy_half_iszero(a) && !npy_half_iszero(b)) +#define _HALF_LOGICAL_OR(a,b) (!npy_half_iszero(a) || !npy_half_iszero(b)) +/**begin repeat + * #kind = equal, not_equal, less, less_equal, greater, + * greater_equal, logical_and, logical_or# + * #OP = npy_half_eq, npy_half_ne, npy_half_lt, npy_half_le, npy_half_gt, + * npy_half_ge, _HALF_LOGICAL_AND, _HALF_LOGICAL_OR# + */ +NPY_NO_EXPORT void +HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_bool *)op1) = @OP@(in1, in2); + } +} +/**end repeat**/ +#undef _HALF_LOGICAL_AND +#undef _HALF_LOGICAL_OR + +NPY_NO_EXPORT void +HALF_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const int in1 = !npy_half_iszero(*(npy_half *)ip1); + const int in2 = !npy_half_iszero(*(npy_half *)ip2); + *((npy_bool *)op1) = (in1 != in2); + } +} + +NPY_NO_EXPORT void +HALF_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_bool *)op1) = npy_half_iszero(in1); + } +} + +/**begin repeat + * #kind = isnan, isinf, isfinite, signbit# + * #func = npy_half_isnan, npy_half_isinf, npy_half_isfinite, npy_half_signbit# + **/ +NPY_NO_EXPORT void +HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_bool *)op1) = @func@(in1) != 0; + } + npy_clear_floatstatus(); +} +/**end repeat**/ + +NPY_NO_EXPORT void +HALF_spacing(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = npy_half_spacing(in1); + } +} + +NPY_NO_EXPORT void +HALF_copysign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1)= npy_half_copysign(in1, in2); + } +} + +NPY_NO_EXPORT void +HALF_nextafter(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1)= npy_half_nextafter(in1, in2); + } +} + +/**begin repeat + * #kind = maximum, minimum# + * #OP = npy_half_ge, npy_half_le# + **/ +NPY_NO_EXPORT void +HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* */ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in1)) ? in1 : in2; + } +} +/**end repeat**/ + +/**begin repeat + * #kind = fmax, fmin# + * #OP = npy_half_ge, npy_half_le# + **/ +NPY_NO_EXPORT void +HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* */ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in2)) ? in1 : in2; + } + npy_clear_floatstatus(); +} +/**end repeat**/ + +NPY_NO_EXPORT void +HALF_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + npy_half mod; + *((npy_half *)op1) = npy_half_divmod(in1, in2, &mod); + } +} + +NPY_NO_EXPORT void +HALF_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + npy_half_divmod(in1, in2, (npy_half *)op1); + } +} + +NPY_NO_EXPORT void +HALF_divmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP_TWO_OUT { + const npy_half in1 = *(npy_half *)ip1; + const npy_half in2 = *(npy_half *)ip2; + *((npy_half *)op1) = npy_half_divmod(in1, in2, (npy_half *)op2); + } +} + +NPY_NO_EXPORT void +HALF_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + UNARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *((npy_half *)op1) = npy_float_to_half(in1*in1); + } +} + +NPY_NO_EXPORT void +HALF_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + UNARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *((npy_half *)op1) = npy_float_to_half(1/in1); + } +} + +NPY_NO_EXPORT void +HALF__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + OUTPUT_LOOP { + *((npy_half *)op1) = NPY_HALF_ONE; + } +} + +NPY_NO_EXPORT void +HALF_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = in1; + } +} + +NPY_NO_EXPORT void +HALF_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = in1&0x7fffu; + } +} + +NPY_NO_EXPORT void +HALF_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = in1^0x8000u; + } +} + +NPY_NO_EXPORT void +HALF_positive(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = +in1; + } +} + +NPY_NO_EXPORT void +HALF_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* Sign of nan is nan */ + UNARY_LOOP { + const npy_half in1 = *(npy_half *)ip1; + *((npy_half *)op1) = npy_half_isnan(in1) ? in1 : + (((in1&0x7fffu) == 0) ? 0 : + (((in1&0x8000u) == 0) ? NPY_HALF_ONE : NPY_HALF_NEGONE)); + } +} + +NPY_NO_EXPORT void +HALF_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + float temp; + + UNARY_LOOP_TWO_OUT { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *((npy_half *)op1) = npy_float_to_half(npy_modff(in1, &temp)); + *((npy_half *)op2) = npy_float_to_half(temp); + } +} + +NPY_NO_EXPORT void +HALF_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_TWO_OUT { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + *((npy_half *)op1) = npy_float_to_half(npy_frexpf(in1, (int *)op2)); + } +} + +NPY_NO_EXPORT void +HALF_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + const int in2 = *(int *)ip2; + *((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, in2)); + } +} + +NPY_NO_EXPORT void +HALF_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* + * Additional loop to handle npy_long integer inputs (cf. #866, #1633). + * npy_long != npy_int on many 64-bit platforms, so we need this second loop + * to handle the default integer type. + */ + BINARY_LOOP { + const float in1 = npy_half_to_float(*(npy_half *)ip1); + const long in2 = *(long *)ip2; + if (((int)in2) == in2) { + /* Range OK */ + *((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, ((int)in2))); + } + else { + /* + * Outside npy_int range -- also ldexp will overflow in this case, + * given that exponent has less bits than npy_int. + */ + if (in2 > 0) { + *((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, NPY_MAX_INT)); + } + else { + *((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, NPY_MIN_INT)); + } + } + } +} + +#define HALF_true_divide HALF_divide + + +/* + ***************************************************************************** + ** COMPLEX LOOPS ** + ***************************************************************************** + */ + +#define CGE(xr,xi,yr,yi) ((xr > yr && !npy_isnan(xi) && !npy_isnan(yi)) \ + || (xr == yr && xi >= yi)) +#define CLE(xr,xi,yr,yi) ((xr < yr && !npy_isnan(xi) && !npy_isnan(yi)) \ + || (xr == yr && xi <= yi)) +#define CGT(xr,xi,yr,yi) ((xr > yr && !npy_isnan(xi) && !npy_isnan(yi)) \ + || (xr == yr && xi > yi)) +#define CLT(xr,xi,yr,yi) ((xr < yr && !npy_isnan(xi) && !npy_isnan(yi)) \ + || (xr == yr && xi < yi)) +#define CEQ(xr,xi,yr,yi) (xr == yr && xi == yi) +#define CNE(xr,xi,yr,yi) (xr != yr || xi != yi) + +/**begin repeat + * complex types + * #TYPE = CFLOAT, CDOUBLE, CLONGDOUBLE# + * #ftype = npy_float, npy_double, npy_longdouble# + * #c = f, , l# + * #C = F, , L# + */ + +/* similar to pairwise sum of real floats */ +static void +pairwise_sum_@TYPE@(@ftype@ *rr, @ftype@ * ri, char * a, npy_uintp n, + npy_intp stride) +{ + assert(n % 2 == 0); + if (n < 8) { + npy_intp i; + *rr = 0.; + *ri = 0.; + for (i = 0; i < n; i += 2) { + *rr += *((@ftype@ *)(a + i * stride + 0)); + *ri += *((@ftype@ *)(a + i * stride + sizeof(@ftype@))); + } + return; + } + else if (n <= PW_BLOCKSIZE) { + npy_intp i; + @ftype@ r[8]; + + /* + * sum a block with 8 accumulators + * 8 times unroll reduces blocksize to 16 and allows vectorization with + * avx without changing summation ordering + */ + r[0] = *((@ftype@ *)(a + 0 * stride)); + r[1] = *((@ftype@ *)(a + 0 * stride + sizeof(@ftype@))); + r[2] = *((@ftype@ *)(a + 2 * stride)); + r[3] = *((@ftype@ *)(a + 2 * stride + sizeof(@ftype@))); + r[4] = *((@ftype@ *)(a + 4 * stride)); + r[5] = *((@ftype@ *)(a + 4 * stride + sizeof(@ftype@))); + r[6] = *((@ftype@ *)(a + 6 * stride)); + r[7] = *((@ftype@ *)(a + 6 * stride + sizeof(@ftype@))); + + for (i = 8; i < n - (n % 8); i += 8) { + /* small blocksizes seems to mess with hardware prefetch */ + NPY_PREFETCH(a + (i + 512 / sizeof(@ftype@)) * stride, 0, 3); + r[0] += *((@ftype@ *)(a + (i + 0) * stride)); + r[1] += *((@ftype@ *)(a + (i + 0) * stride + sizeof(@ftype@))); + r[2] += *((@ftype@ *)(a + (i + 2) * stride)); + r[3] += *((@ftype@ *)(a + (i + 2) * stride + sizeof(@ftype@))); + r[4] += *((@ftype@ *)(a + (i + 4) * stride)); + r[5] += *((@ftype@ *)(a + (i + 4) * stride + sizeof(@ftype@))); + r[6] += *((@ftype@ *)(a + (i + 6) * stride)); + r[7] += *((@ftype@ *)(a + (i + 6) * stride + sizeof(@ftype@))); + } + + /* accumulate now to avoid stack spills for single peel loop */ + *rr = ((r[0] + r[2]) + (r[4] + r[6])); + *ri = ((r[1] + r[3]) + (r[5] + r[7])); + + /* do non multiple of 8 rest */ + for (; i < n; i+=2) { + *rr += *((@ftype@ *)(a + i * stride + 0)); + *ri += *((@ftype@ *)(a + i * stride + sizeof(@ftype@))); + } + return; + } + else { + /* divide by two but avoid non-multiples of unroll factor */ + @ftype@ rr1, ri1, rr2, ri2; + npy_uintp n2 = n / 2; + n2 -= n2 % 8; + pairwise_sum_@TYPE@(&rr1, &ri1, a, n2, stride); + pairwise_sum_@TYPE@(&rr2, &ri2, a + n2 * stride, n - n2, stride); + *rr = rr1 + rr2; + *ri = ri1 + ri2; + return; + } +} + +/**begin repeat1 + * arithmetic + * #kind = add, subtract# + * #OP = +, -# + * #PW = 1, 0# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + if (IS_BINARY_REDUCE && @PW@) { + npy_intp n = dimensions[0]; + @ftype@ * or = ((@ftype@ *)args[0]); + @ftype@ * oi = ((@ftype@ *)args[0]) + 1; + @ftype@ rr, ri; + + pairwise_sum_@TYPE@(&rr, &ri, args[1], n * 2, steps[1] / 2); + *or @OP@= rr; + *oi @OP@= ri; + return; + } + else { + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + ((@ftype@ *)op1)[0] = in1r @OP@ in2r; + ((@ftype@ *)op1)[1] = in1i @OP@ in2i; + } + } +} +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + ((@ftype@ *)op1)[0] = in1r*in2r - in1i*in2i; + ((@ftype@ *)op1)[1] = in1r*in2i + in1i*in2r; + } +} + +NPY_NO_EXPORT void +@TYPE@_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + const @ftype@ in2r_abs = npy_fabs@c@(in2r); + const @ftype@ in2i_abs = npy_fabs@c@(in2i); + if (in2r_abs >= in2i_abs) { + if (in2r_abs == 0 && in2i_abs == 0) { + /* divide by zero should yield a complex inf or nan */ + ((@ftype@ *)op1)[0] = in1r/in2r_abs; + ((@ftype@ *)op1)[1] = in1i/in2i_abs; + } + else { + const @ftype@ rat = in2i/in2r; + const @ftype@ scl = 1.0@c@/(in2r + in2i*rat); + ((@ftype@ *)op1)[0] = (in1r + in1i*rat)*scl; + ((@ftype@ *)op1)[1] = (in1i - in1r*rat)*scl; + } + } + else { + const @ftype@ rat = in2r/in2i; + const @ftype@ scl = 1.0@c@/(in2i + in2r*rat); + ((@ftype@ *)op1)[0] = (in1r*rat + in1i)*scl; + ((@ftype@ *)op1)[1] = (in1i*rat - in1r)*scl; + } + } +} + +NPY_NO_EXPORT void +@TYPE@_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + if (npy_fabs@c@(in2r) >= npy_fabs@c@(in2i)) { + const @ftype@ rat = in2i/in2r; + ((@ftype@ *)op1)[0] = npy_floor@c@((in1r + in1i*rat)/(in2r + in2i*rat)); + ((@ftype@ *)op1)[1] = 0; + } + else { + const @ftype@ rat = in2r/in2i; + ((@ftype@ *)op1)[0] = npy_floor@c@((in1r*rat + in1i)/(in2i + in2r*rat)); + ((@ftype@ *)op1)[1] = 0; + } + } +} + +/**begin repeat1 + * #kind= greater, greater_equal, less, less_equal, equal, not_equal# + * #OP = CGT, CGE, CLT, CLE, CEQ, CNE# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + *((npy_bool *)op1) = @OP@(in1r,in1i,in2r,in2i); + } +} +/**end repeat1**/ + +/**begin repeat1 + #kind = logical_and, logical_or# + #OP1 = ||, ||# + #OP2 = &&, ||# +*/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + *((npy_bool *)op1) = (in1r @OP1@ in1i) @OP2@ (in2r @OP1@ in2i); + } +} +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + const npy_bool tmp1 = (in1r || in1i); + const npy_bool tmp2 = (in2r || in2i); + *((npy_bool *)op1) = tmp1 != tmp2; + } +} + +NPY_NO_EXPORT void +@TYPE@_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + *((npy_bool *)op1) = !(in1r || in1i); + } +} + +/**begin repeat1 + * #kind = isnan, isinf, isfinite# + * #func = npy_isnan, npy_isinf, npy_isfinite# + * #OP = ||, ||, &&# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + *((npy_bool *)op1) = @func@(in1r) @OP@ @func@(in1i); + } + npy_clear_floatstatus(); +} +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + UNARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + ((@ftype@ *)op1)[0] = in1r*in1r - in1i*in1i; + ((@ftype@ *)op1)[1] = in1r*in1i + in1i*in1r; + } +} + +NPY_NO_EXPORT void +@TYPE@_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + UNARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + if (npy_fabs@c@(in1i) <= npy_fabs@c@(in1r)) { + const @ftype@ r = in1i/in1r; + const @ftype@ d = in1r + in1i*r; + ((@ftype@ *)op1)[0] = 1/d; + ((@ftype@ *)op1)[1] = -r/d; + } else { + const @ftype@ r = in1r/in1i; + const @ftype@ d = in1r*r + in1i; + ((@ftype@ *)op1)[0] = r/d; + ((@ftype@ *)op1)[1] = -1/d; + } + } +} + +NPY_NO_EXPORT void +@TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) +{ + OUTPUT_LOOP { + ((@ftype@ *)op1)[0] = 1; + ((@ftype@ *)op1)[1] = 0; + } +} + +NPY_NO_EXPORT void +@TYPE@_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { + UNARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + ((@ftype@ *)op1)[0] = in1r; + ((@ftype@ *)op1)[1] = -in1i; + } +} + +NPY_NO_EXPORT void +@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + *((@ftype@ *)op1) = npy_hypot@c@(in1r, in1i); + } +} + +NPY_NO_EXPORT void +@TYPE@__arg(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + *((@ftype@ *)op1) = npy_atan2@c@(in1i, in1r); + } +} + +NPY_NO_EXPORT void +@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* fixme: sign of nan is currently 0 */ + UNARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + ((@ftype@ *)op1)[0] = CGT(in1r, in1i, 0.0, 0.0) ? 1 : + (CLT(in1r, in1i, 0.0, 0.0) ? -1 : + (CEQ(in1r, in1i, 0.0, 0.0) ? 0 : NPY_NAN@C@)); + ((@ftype@ *)op1)[1] = 0; + } +} + +/**begin repeat1 + * #kind = maximum, minimum# + * #OP = CGE, CLE# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + if (@OP@(in1r, in1i, in2r, in2i) || npy_isnan(in1r) || npy_isnan(in1i)) { + ((@ftype@ *)op1)[0] = in1r; + ((@ftype@ *)op1)[1] = in1i; + } + else { + ((@ftype@ *)op1)[0] = in2r; + ((@ftype@ *)op1)[1] = in2i; + } + } + npy_clear_floatstatus(); +} +/**end repeat1**/ + +/**begin repeat1 + * #kind = fmax, fmin# + * #OP = CGE, CLE# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @ftype@ in1r = ((@ftype@ *)ip1)[0]; + const @ftype@ in1i = ((@ftype@ *)ip1)[1]; + const @ftype@ in2r = ((@ftype@ *)ip2)[0]; + const @ftype@ in2i = ((@ftype@ *)ip2)[1]; + if (@OP@(in1r, in1i, in2r, in2i) || npy_isnan(in2r) || npy_isnan(in2i)) { + ((@ftype@ *)op1)[0] = in1r; + ((@ftype@ *)op1)[1] = in1i; + } + else { + ((@ftype@ *)op1)[0] = in2r; + ((@ftype@ *)op1)[1] = in2i; + } + } +} +/**end repeat1**/ + +#define @TYPE@_true_divide @TYPE@_divide + +/**end repeat**/ + +#undef CGE +#undef CLE +#undef CGT +#undef CLT +#undef CEQ +#undef CNE + +/* + ***************************************************************************** + ** OBJECT LOOPS ** + ***************************************************************************** + */ + +/**begin repeat + * #kind = equal, not_equal, greater, greater_equal, less, less_equal# + * #OP = EQ, NE, GT, GE, LT, LE# + * #identity = NPY_TRUE, NPY_FALSE, -1*4# + */ +NPY_NO_EXPORT void +OBJECT_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { + BINARY_LOOP { + int ret; + PyObject *ret_obj; + PyObject *in1 = *(PyObject **)ip1; + PyObject *in2 = *(PyObject **)ip2; + + in1 = in1 ? in1 : Py_None; + in2 = in2 ? in2 : Py_None; + + /* + * Do not use RichCompareBool because it includes an identity check for + * == and !=. This is wrong for elementwise behaviour, since it means + * that NaN can be equal to NaN and an array is equal to itself. + */ + ret_obj = PyObject_RichCompare(in1, in2, Py_@OP@); + if (ret_obj == NULL) { + return; + } + ret = PyObject_IsTrue(ret_obj); + Py_DECREF(ret_obj); + if (ret == -1) { + return; + } + *((npy_bool *)op1) = (npy_bool)ret; + } +} +/**end repeat**/ + +NPY_NO_EXPORT void +OBJECT_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + PyObject *zero = PyLong_FromLong(0); + + UNARY_LOOP { + PyObject *in1 = *(PyObject **)ip1; + PyObject **out = (PyObject **)op1; + PyObject *ret = NULL; + int v; + + if (in1 == NULL) { + in1 = Py_None; + } + + if ((v = PyObject_RichCompareBool(in1, zero, Py_LT)) == 1) { + ret = PyLong_FromLong(-1); + } + else if (v == 0 && + (v = PyObject_RichCompareBool(in1, zero, Py_GT)) == 1) { + ret = PyLong_FromLong(1); + } + else if (v == 0 && + (v = PyObject_RichCompareBool(in1, zero, Py_EQ)) == 1) { + ret = PyLong_FromLong(0); + } + else if (v == 0) { + /* in1 is NaN */ + PyErr_SetString(PyExc_TypeError, + "unorderable types for comparison"); + } + + if (ret == NULL) { + break; + } + Py_XDECREF(*out); + *out = ret; + } + Py_XDECREF(zero); +} + +/* + ***************************************************************************** + ** END LOOPS ** + ***************************************************************************** + */ diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src new file mode 100644 index 0000000..a978b03 --- /dev/null +++ b/numpy/core/src/umath/loops.h.src @@ -0,0 +1,506 @@ +/* -*- c -*- */ +/* + * vim:syntax=c + */ + +#ifndef _NPY_UMATH_LOOPS_H_ +#define _NPY_UMATH_LOOPS_H_ + +#define BOOL_invert BOOL_logical_not +#define BOOL_negative BOOL_logical_not +#define BOOL_add BOOL_logical_or +#define BOOL_bitwise_and BOOL_logical_and +#define BOOL_bitwise_or BOOL_logical_or +#define BOOL_logical_xor BOOL_not_equal +#define BOOL_bitwise_xor BOOL_logical_xor +#define BOOL_multiply BOOL_logical_and +#define BOOL_subtract BOOL_logical_xor +#define BOOL_maximum BOOL_logical_or +#define BOOL_minimum BOOL_logical_and +#define BOOL_fmax BOOL_maximum +#define BOOL_fmin BOOL_minimum + + +/* + ***************************************************************************** + ** BOOLEAN LOOPS ** + ***************************************************************************** + */ + +/**begin repeat + * #kind = equal, not_equal, greater, greater_equal, less, less_equal, + * logical_and, logical_or, absolute, logical_not# + **/ +NPY_NO_EXPORT void +BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat**/ + +NPY_NO_EXPORT void +BOOL__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +/* + ***************************************************************************** + ** INTEGER LOOPS + ***************************************************************************** + */ + +/**begin repeat + * #TYPE = BYTE, SHORT, INT, LONG, LONGLONG# + */ + +/**begin repeat1 + * both signed and unsigned integer types + * #s = , u# + * #S = , U# + */ + +#define @S@@TYPE@_floor_divide @S@@TYPE@_divide +#define @S@@TYPE@_fmax @S@@TYPE@_maximum +#define @S@@TYPE@_fmin @S@@TYPE@_minimum + +NPY_NO_EXPORT void +@S@@TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +@S@@TYPE@_positive(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**begin repeat2 + * #isa = , _avx2# + */ + +NPY_NO_EXPORT void +@S@@TYPE@_square@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +@S@@TYPE@_reciprocal@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +@S@@TYPE@_conjugate@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_negative@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_logical_not@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_invert@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**begin repeat3 + * Arithmetic + * #kind = add, subtract, multiply, bitwise_and, bitwise_or, bitwise_xor, + * left_shift, right_shift# + * #OP = +, -,*, &, |, ^, <<, >># + */ +NPY_NO_EXPORT void +@S@@TYPE@_@kind@@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**end repeat3**/ + +/**begin repeat3 + * #kind = equal, not_equal, greater, greater_equal, less, less_equal, + * logical_and, logical_or# + * #OP = ==, !=, >, >=, <, <=, &&, ||# + */ +NPY_NO_EXPORT void +@S@@TYPE@_@kind@@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**end repeat3**/ + +NPY_NO_EXPORT void +@S@@TYPE@_logical_xor@isa@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat2**/ + +/**begin repeat2 + * #kind = maximum, minimum# + * #OP = >, <# + **/ +NPY_NO_EXPORT void +@S@@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat2**/ + +NPY_NO_EXPORT void +@S@@TYPE@_power(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_fmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@S@@TYPE@_divmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**end repeat1**/ + +/**end repeat**/ + +/* + ***************************************************************************** + ** FLOAT LOOPS ** + ***************************************************************************** + */ + +/**begin repeat + * #TYPE = FLOAT, DOUBLE# + */ +NPY_NO_EXPORT void +@TYPE@_sqrt(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat**/ + +/**begin repeat + * Float types + * #TYPE = HALF, FLOAT, DOUBLE, LONGDOUBLE# + * #c = f, f, , l# + * #C = F, F, , L# + */ + + +/**begin repeat1 + * Arithmetic + * # kind = add, subtract, multiply, divide# + * # OP = +, -, *, /# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +/**begin repeat1 + * #kind = equal, not_equal, less, less_equal, greater, greater_equal, + * logical_and, logical_or# + * #OP = ==, !=, <, <=, >, >=, &&, ||# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**begin repeat1 + * #kind = isnan, isinf, isfinite, signbit, copysign, nextafter, spacing# + * #func = npy_isnan, npy_isinf, npy_isfinite, npy_signbit, npy_copysign, nextafter, spacing# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +/**begin repeat1 + * #kind = maximum, minimum# + * #OP = >=, <=# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +/**begin repeat1 + * #kind = fmax, fmin# + * #OP = >=, <=# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +NPY_NO_EXPORT void +@TYPE@_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_divmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +@TYPE@_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + + +NPY_NO_EXPORT void +@TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +@TYPE@_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_positive(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + + +NPY_NO_EXPORT void +@TYPE@_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void +@TYPE@_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +#define @TYPE@_true_divide @TYPE@_divide + +/**end repeat**/ + + +/* + ***************************************************************************** + ** COMPLEX LOOPS ** + ***************************************************************************** + */ + +#define CGE(xr,xi,yr,yi) (xr > yr || (xr == yr && xi >= yi)); +#define CLE(xr,xi,yr,yi) (xr < yr || (xr == yr && xi <= yi)); +#define CGT(xr,xi,yr,yi) (xr > yr || (xr == yr && xi > yi)); +#define CLT(xr,xi,yr,yi) (xr < yr || (xr == yr && xi < yi)); +#define CEQ(xr,xi,yr,yi) (xr == yr && xi == yi); +#define CNE(xr,xi,yr,yi) (xr != yr || xi != yi); + +/**begin repeat + * complex types + * #TYPE = FLOAT, DOUBLE, LONGDOUBLE# + * #c = f, , l# + * #C = F, , L# + */ + +/**begin repeat1 + * arithmetic + * #kind = add, subtract# + * #OP = +, -# + */ +NPY_NO_EXPORT void +C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**end repeat1**/ + +NPY_NO_EXPORT void +C@TYPE@_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +C@TYPE@_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +C@TYPE@_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**begin repeat1 + * #kind= greater, greater_equal, less, less_equal, equal, not_equal# + * #OP = CGT, CGE, CLT, CLE, CEQ, CNE# + */ +NPY_NO_EXPORT void +C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +/**begin repeat1 + #kind = logical_and, logical_or# + #OP1 = ||, ||# + #OP2 = &&, ||# +*/ +NPY_NO_EXPORT void +C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +NPY_NO_EXPORT void +C@TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +C@TYPE@_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**begin repeat1 + * #kind = isnan, isinf, isfinite# + * #func = npy_isnan, npy_isinf, npy_isfinite# + * #OP = ||, ||, &&# + **/ +NPY_NO_EXPORT void +C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +NPY_NO_EXPORT void +C@TYPE@_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +C@TYPE@_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +C@TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +C@TYPE@_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +C@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +C@TYPE@__arg(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +C@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**begin repeat1 + * #kind = maximum, minimum# + * #OP = CGE, CLE# + */ +NPY_NO_EXPORT void +C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +/**begin repeat1 + * #kind = fmax, fmin# + * #OP = CGE, CLE# + */ +NPY_NO_EXPORT void +C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +#define C@TYPE@_true_divide C@TYPE@_divide + +/**end repeat**/ + +#undef CGE +#undef CLE +#undef CGT +#undef CLT +#undef CEQ +#undef CNE + +/* + ***************************************************************************** + ** DATETIME LOOPS ** + ***************************************************************************** + */ + +NPY_NO_EXPORT void +TIMEDELTA_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_positive(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/**begin repeat + * #TYPE = DATETIME, TIMEDELTA# + */ + +NPY_NO_EXPORT void +@TYPE@_isnat(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +/**begin repeat1 + * #kind = equal, not_equal, greater, greater_equal, less, less_equal# + * #OP = ==, !=, >, >=, <, <=# + */ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +/**begin repeat1 + * #kind = maximum, minimum# + * #OP = >, <# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat1**/ + +/**end repeat**/ + +NPY_NO_EXPORT void +DATETIME_Mm_M_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); + +NPY_NO_EXPORT void +DATETIME_mM_M_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_mm_m_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +DATETIME_Mm_M_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +DATETIME_MM_m_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_mm_m_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_mq_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_qm_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_md_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_dm_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_mq_m_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_md_m_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +TIMEDELTA_mm_d_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/* Special case equivalents to above functions */ + +#define TIMEDELTA_mq_m_true_divide TIMEDELTA_mq_m_divide +#define TIMEDELTA_md_m_true_divide TIMEDELTA_md_m_divide +#define TIMEDELTA_mm_d_true_divide TIMEDELTA_mm_d_divide +#define TIMEDELTA_mq_m_floor_divide TIMEDELTA_mq_m_divide +#define TIMEDELTA_md_m_floor_divide TIMEDELTA_md_m_divide +/* #define TIMEDELTA_mm_d_floor_divide TIMEDELTA_mm_d_divide */ +#define TIMEDELTA_fmin TIMEDELTA_minimum +#define TIMEDELTA_fmax TIMEDELTA_maximum +#define DATETIME_fmin DATETIME_minimum +#define DATETIME_fmax DATETIME_maximum + +/* + ***************************************************************************** + ** OBJECT LOOPS ** + ***************************************************************************** + */ + +/**begin repeat + * #kind = equal, not_equal, greater, greater_equal, less, less_equal# + * #OP = EQ, NE, GT, GE, LT, LE# + */ +NPY_NO_EXPORT void +OBJECT_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +/**end repeat**/ + +NPY_NO_EXPORT void +OBJECT_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +/* + ***************************************************************************** + ** END LOOPS ** + ***************************************************************************** + */ + +#endif diff --git a/numpy/core/src/umath/operand_flag_tests.c.src b/numpy/core/src/umath/operand_flag_tests.c.src new file mode 100644 index 0000000..046c375 --- /dev/null +++ b/numpy/core/src/umath/operand_flag_tests.c.src @@ -0,0 +1,105 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include +#include +#include +#include "numpy/npy_3kcompat.h" +#include +#include + + +static PyMethodDef TestMethods[] = { + {NULL, NULL, 0, NULL} +}; + + +static void +inplace_add(char **args, npy_intp *dimensions, npy_intp *steps, void *data) +{ + npy_intp i; + npy_intp n = dimensions[0]; + char *in1 = args[0]; + char *in2 = args[1]; + npy_intp in1_step = steps[0]; + npy_intp in2_step = steps[1]; + + for (i = 0; i < n; i++) { + (*(long *)in1) = *(long*)in1 + *(long*)in2; + in1 += in1_step; + in2 += in2_step; + } +} + + +/*This a pointer to the above function*/ +PyUFuncGenericFunction funcs[1] = {&inplace_add}; + +/* These are the input and return dtypes of logit.*/ +static char types[2] = {NPY_LONG, NPY_LONG}; + +static void *data[1] = {NULL}; + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "operand_flag_tests", + NULL, + -1, + TestMethods, + NULL, + NULL, + NULL, + NULL +}; + +#define RETVAL m +PyMODINIT_FUNC PyInit_operand_flag_tests(void) +{ +#else +#define RETVAL +PyMODINIT_FUNC initoperand_flag_tests(void) +{ +#endif + PyObject *m = NULL; + PyObject *ufunc; + +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("operand_flag_tests", TestMethods); +#endif + if (m == NULL) { + goto fail; + } + + import_array(); + import_umath(); + + ufunc = PyUFunc_FromFuncAndData(funcs, data, types, 1, 2, 0, + PyUFunc_None, "inplace_add", + "inplace_add_docstring", 0); + + /* + * Set flags to turn off buffering for first input operand, + * so that result can be written back to input operand. + */ + ((PyUFuncObject*)ufunc)->op_flags[0] = NPY_ITER_READWRITE; + ((PyUFuncObject*)ufunc)->iter_flags = NPY_ITER_REDUCE_OK; + PyModule_AddObject(m, "inplace_add", (PyObject*)ufunc); + + return RETVAL; + +fail: + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot load operand_flag_tests module."); + } +#if defined(NPY_PY3K) + if (m) { + Py_DECREF(m); + m = NULL; + } +#endif + return RETVAL; + +} diff --git a/numpy/core/src/umath/override.c b/numpy/core/src/umath/override.c new file mode 100644 index 0000000..7e787b8 --- /dev/null +++ b/numpy/core/src/umath/override.c @@ -0,0 +1,608 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define NO_IMPORT_ARRAY + +#include "npy_pycompat.h" +#include "numpy/ufuncobject.h" +#include "npy_import.h" + +#include "ufunc_override.h" +#include "override.h" + +/* + * The following functions normalize ufunc arguments. The work done is similar + * to what is done inside ufunc_object by get_ufunc_arguments for __call__ and + * generalized ufuncs, and by PyUFunc_GenericReduction for the other methods. + * It would be good to unify (see gh-8892). + */ + +/* + * ufunc() and ufunc.outer() accept 'sig' or 'signature'; + * normalize to 'signature' + */ +static int +normalize_signature_keyword(PyObject *normal_kwds) +{ + PyObject* obj = PyDict_GetItemString(normal_kwds, "sig"); + if (obj != NULL) { + if (PyDict_GetItemString(normal_kwds, "signature")) { + PyErr_SetString(PyExc_TypeError, + "cannot specify both 'sig' and 'signature'"); + return -1; + } + Py_INCREF(obj); + PyDict_SetItemString(normal_kwds, "signature", obj); + PyDict_DelItemString(normal_kwds, "sig"); + } + return 0; +} + +static int +normalize___call___args(PyUFuncObject *ufunc, PyObject *args, + PyObject **normal_args, PyObject **normal_kwds) +{ + /* + * ufunc.__call__(*args, **kwds) + */ + npy_intp i; + int not_all_none; + npy_intp nin = ufunc->nin; + npy_intp nout = ufunc->nout; + npy_intp nargs = PyTuple_GET_SIZE(args); + PyObject *obj; + + if (nargs < nin) { + PyErr_Format(PyExc_TypeError, + "ufunc() missing %"NPY_INTP_FMT" of %"NPY_INTP_FMT + "required positional argument(s)", nin - nargs, nin); + return -1; + } + if (nargs > nin+nout) { + PyErr_Format(PyExc_TypeError, + "ufunc() takes from %"NPY_INTP_FMT" to %"NPY_INTP_FMT + "arguments but %"NPY_INTP_FMT" were given", + nin, nin+nout, nargs); + return -1; + } + + *normal_args = PyTuple_GetSlice(args, 0, nin); + if (*normal_args == NULL) { + return -1; + } + + /* If we have more args than nin, they must be the output variables.*/ + if (nargs > nin) { + if(PyDict_GetItemString(*normal_kwds, "out")) { + PyErr_Format(PyExc_TypeError, + "argument given by name ('out') and position " + "(%"NPY_INTP_FMT")", nin); + return -1; + } + for (i = nin; i < nargs; i++) { + not_all_none = (PyTuple_GET_ITEM(args, i) != Py_None); + if (not_all_none) { + break; + } + } + if (not_all_none) { + if (nargs - nin == nout) { + obj = PyTuple_GetSlice(args, nin, nargs); + } + else { + PyObject *item; + + obj = PyTuple_New(nout); + if (obj == NULL) { + return -1; + } + for (i = 0; i < nout; i++) { + if (i + nin < nargs) { + item = PyTuple_GET_ITEM(args, nin+i); + } + else { + item = Py_None; + } + Py_INCREF(item); + PyTuple_SET_ITEM(obj, i, item); + } + } + PyDict_SetItemString(*normal_kwds, "out", obj); + Py_DECREF(obj); + } + } + /* finally, ufuncs accept 'sig' or 'signature' normalize to 'signature' */ + return normalize_signature_keyword(*normal_kwds); +} + +static int +normalize_reduce_args(PyUFuncObject *ufunc, PyObject *args, + PyObject **normal_args, PyObject **normal_kwds) +{ + /* + * ufunc.reduce(a[, axis, dtype, out, keepdims]) + */ + npy_intp nargs = PyTuple_GET_SIZE(args); + npy_intp i; + PyObject *obj; + static char *kwlist[] = {"array", "axis", "dtype", "out", "keepdims"}; + + if (nargs < 1 || nargs > 5) { + PyErr_Format(PyExc_TypeError, + "ufunc.reduce() takes from 1 to 5 positional " + "arguments but %"NPY_INTP_FMT" were given", nargs); + return -1; + } + *normal_args = PyTuple_GetSlice(args, 0, 1); + if (*normal_args == NULL) { + return -1; + } + + for (i = 1; i < nargs; i++) { + if (PyDict_GetItemString(*normal_kwds, kwlist[i])) { + PyErr_Format(PyExc_TypeError, + "argument given by name ('%s') and position " + "(%"NPY_INTP_FMT")", kwlist[i], i); + return -1; + } + obj = PyTuple_GET_ITEM(args, i); + if (i == 3) { + /* remove out=None */ + if (obj == Py_None) { + continue; + } + obj = PyTuple_GetSlice(args, 3, 4); + } + PyDict_SetItemString(*normal_kwds, kwlist[i], obj); + if (i == 3) { + Py_DECREF(obj); + } + } + return 0; +} + +static int +normalize_accumulate_args(PyUFuncObject *ufunc, PyObject *args, + PyObject **normal_args, PyObject **normal_kwds) +{ + /* + * ufunc.accumulate(a[, axis, dtype, out]) + */ + npy_intp nargs = PyTuple_GET_SIZE(args); + npy_intp i; + PyObject *obj; + static char *kwlist[] = {"array", "axis", "dtype", "out", "keepdims"}; + + if (nargs < 1 || nargs > 4) { + PyErr_Format(PyExc_TypeError, + "ufunc.accumulate() takes from 1 to 4 positional " + "arguments but %"NPY_INTP_FMT" were given", nargs); + return -1; + } + *normal_args = PyTuple_GetSlice(args, 0, 1); + if (*normal_args == NULL) { + return -1; + } + + for (i = 1; i < nargs; i++) { + if (PyDict_GetItemString(*normal_kwds, kwlist[i])) { + PyErr_Format(PyExc_TypeError, + "argument given by name ('%s') and position " + "(%"NPY_INTP_FMT")", kwlist[i], i); + return -1; + } + obj = PyTuple_GET_ITEM(args, i); + if (i == 3) { + /* remove out=None */ + if (obj == Py_None) { + continue; + } + obj = PyTuple_GetSlice(args, 3, 4); + } + PyDict_SetItemString(*normal_kwds, kwlist[i], obj); + if (i == 3) { + Py_DECREF(obj); + } + } + return 0; +} + +static int +normalize_reduceat_args(PyUFuncObject *ufunc, PyObject *args, + PyObject **normal_args, PyObject **normal_kwds) +{ + /* + * ufunc.reduceat(a, indicies[, axis, dtype, out]) + * the number of arguments has been checked in PyUFunc_GenericReduction. + */ + npy_intp i; + npy_intp nargs = PyTuple_GET_SIZE(args); + PyObject *obj; + static char *kwlist[] = {"array", "indices", "axis", "dtype", "out"}; + + if (nargs < 2 || nargs > 5) { + PyErr_Format(PyExc_TypeError, + "ufunc.reduceat() takes from 2 to 4 positional " + "arguments but %"NPY_INTP_FMT" were given", nargs); + return -1; + } + /* a and indicies */ + *normal_args = PyTuple_GetSlice(args, 0, 2); + if (*normal_args == NULL) { + return -1; + } + + for (i = 2; i < nargs; i++) { + if (PyDict_GetItemString(*normal_kwds, kwlist[i])) { + PyErr_Format(PyExc_TypeError, + "argument given by name ('%s') and position " + "(%"NPY_INTP_FMT")", kwlist[i], i); + return -1; + } + obj = PyTuple_GET_ITEM(args, i); + if (i == 4) { + /* remove out=None */ + if (obj == Py_None) { + continue; + } + obj = PyTuple_GetSlice(args, 4, 5); + } + PyDict_SetItemString(*normal_kwds, kwlist[i], obj); + if (i == 4) { + Py_DECREF(obj); + } + } + return 0; +} + +static int +normalize_outer_args(PyUFuncObject *ufunc, PyObject *args, + PyObject **normal_args, PyObject **normal_kwds) +{ + /* + * ufunc.outer(*args, **kwds) + * all positional arguments should be inputs. + * for the keywords, we only need to check 'sig' vs 'signature'. + */ + npy_intp nin = ufunc->nin; + npy_intp nargs = PyTuple_GET_SIZE(args); + + if (nargs < nin) { + PyErr_Format(PyExc_TypeError, + "ufunc.outer() missing %"NPY_INTP_FMT" of %"NPY_INTP_FMT + "required positional " "argument(s)", nin - nargs, nin); + return -1; + } + if (nargs > nin) { + PyErr_Format(PyExc_TypeError, + "ufunc.outer() takes %"NPY_INTP_FMT" arguments but" + "%"NPY_INTP_FMT" were given", nin, nargs); + return -1; + } + + *normal_args = PyTuple_GetSlice(args, 0, nin); + if (*normal_args == NULL) { + return -1; + } + + /* ufuncs accept 'sig' or 'signature' normalize to 'signature' */ + return normalize_signature_keyword(*normal_kwds); +} + +static int +normalize_at_args(PyUFuncObject *ufunc, PyObject *args, + PyObject **normal_args, PyObject **normal_kwds) +{ + /* ufunc.at(a, indices[, b]) */ + npy_intp nargs = PyTuple_GET_SIZE(args); + + if (nargs < 2 || nargs > 3) { + PyErr_Format(PyExc_TypeError, + "ufunc.at() takes from 2 to 3 positional " + "arguments but %"NPY_INTP_FMT" were given", nargs); + return -1; + } + *normal_args = PyTuple_GetSlice(args, 0, nargs); + return (*normal_args == NULL); +} + +/* + * Check a set of args for the `__array_ufunc__` method. If more than one of + * the input arguments implements `__array_ufunc__`, they are tried in the + * order: subclasses before superclasses, otherwise left to right. The first + * (non-None) routine returning something other than `NotImplemented` + * determines the result. If all of the `__array_ufunc__` operations return + * `NotImplemented` (or are None), a `TypeError` is raised. + * + * Returns 0 on success and 1 on exception. On success, *result contains the + * result of the operation, if any. If *result is NULL, there is no override. + */ +NPY_NO_EXPORT int +PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, + PyObject *args, PyObject *kwds, + PyObject **result) +{ + int i; + int j; + int status; + + int num_override_args; + PyObject *with_override[NPY_MAXARGS]; + PyObject *array_ufunc_methods[NPY_MAXARGS]; + + PyObject *obj; + PyObject *other_obj; + PyObject *out; + + PyObject *method_name = NULL; + PyObject *normal_args = NULL; /* normal_* holds normalized arguments. */ + PyObject *normal_kwds = NULL; + + PyObject *override_args = NULL; + Py_ssize_t len; + + /* + * Check inputs for overrides + */ + num_override_args = PyUFunc_WithOverride( + args, kwds, with_override, array_ufunc_methods); + if (num_override_args == -1) { + goto fail; + } + /* No overrides, bail out.*/ + if (num_override_args == 0) { + *result = NULL; + return 0; + } + + /* + * Normalize ufunc arguments. + */ + + /* Build new kwds */ + if (kwds && PyDict_CheckExact(kwds)) { + + /* ensure out is always a tuple */ + normal_kwds = PyDict_Copy(kwds); + out = PyDict_GetItemString(normal_kwds, "out"); + if (out != NULL) { + int nout = ufunc->nout; + + if (PyTuple_CheckExact(out)) { + int all_none = 1; + + if (PyTuple_GET_SIZE(out) != nout) { + PyErr_Format(PyExc_ValueError, + "The 'out' tuple must have exactly " + "%d entries: one per ufunc output", nout); + goto fail; + } + for (i = 0; i < PyTuple_GET_SIZE(out); i++) { + all_none = (PyTuple_GET_ITEM(out, i) == Py_None); + if (!all_none) { + break; + } + } + if (all_none) { + PyDict_DelItemString(normal_kwds, "out"); + } + } + else { + /* not a tuple */ + if (nout > 1 && DEPRECATE("passing a single argument to the " + "'out' keyword argument of a " + "ufunc with\n" + "more than one output will " + "result in an error in the " + "future") < 0) { + /* + * If the deprecation is removed, also remove the loop + * below setting tuple items to None (but keep this future + * error message.) + */ + PyErr_SetString(PyExc_TypeError, + "'out' must be a tuple of arguments"); + goto fail; + } + if (out != Py_None) { + /* not already a tuple and not None */ + PyObject *out_tuple = PyTuple_New(nout); + + if (out_tuple == NULL) { + goto fail; + } + for (i = 1; i < nout; i++) { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(out_tuple, i, Py_None); + } + /* out was borrowed ref; make it permanent */ + Py_INCREF(out); + /* steals reference */ + PyTuple_SET_ITEM(out_tuple, 0, out); + PyDict_SetItemString(normal_kwds, "out", out_tuple); + Py_DECREF(out_tuple); + } + else { + /* out=None; remove it */ + PyDict_DelItemString(normal_kwds, "out"); + } + } + } + } + else { + normal_kwds = PyDict_New(); + } + if (normal_kwds == NULL) { + goto fail; + } + + /* decide what to do based on the method. */ + + /* ufunc.__call__ */ + if (strcmp(method, "__call__") == 0) { + status = normalize___call___args(ufunc, args, &normal_args, + &normal_kwds); + } + /* ufunc.reduce */ + else if (strcmp(method, "reduce") == 0) { + status = normalize_reduce_args(ufunc, args, &normal_args, + &normal_kwds); + } + /* ufunc.accumulate */ + else if (strcmp(method, "accumulate") == 0) { + status = normalize_accumulate_args(ufunc, args, &normal_args, + &normal_kwds); + } + /* ufunc.reduceat */ + else if (strcmp(method, "reduceat") == 0) { + status = normalize_reduceat_args(ufunc, args, &normal_args, + &normal_kwds); + } + /* ufunc.outer */ + else if (strcmp(method, "outer") == 0) { + status = normalize_outer_args(ufunc, args, &normal_args, &normal_kwds); + } + /* ufunc.at */ + else if (strcmp(method, "at") == 0) { + status = normalize_at_args(ufunc, args, &normal_args, &normal_kwds); + } + /* unknown method */ + else { + PyErr_Format(PyExc_TypeError, + "Internal Numpy error: unknown ufunc method '%s' in call " + "to PyUFunc_CheckOverride", method); + status = -1; + } + if (status != 0) { + goto fail; + } + + method_name = PyUString_FromString(method); + if (method_name == NULL) { + goto fail; + } + + len = PyTuple_GET_SIZE(normal_args); + + /* Call __array_ufunc__ functions in correct order */ + while (1) { + PyObject *override_obj; + PyObject *override_array_ufunc; + + override_obj = NULL; + *result = NULL; + + /* Choose an overriding argument */ + for (i = 0; i < num_override_args; i++) { + obj = with_override[i]; + if (obj == NULL) { + continue; + } + + /* Get the first instance of an overriding arg.*/ + override_obj = obj; + + /* Check for sub-types to the right of obj. */ + for (j = i + 1; j < num_override_args; j++) { + other_obj = with_override[j]; + if (other_obj != NULL && + PyObject_Type(other_obj) != PyObject_Type(obj) && + PyObject_IsInstance(other_obj, + PyObject_Type(override_obj))) { + override_obj = NULL; + break; + } + } + + /* override_obj had no subtypes to the right. */ + if (override_obj) { + override_array_ufunc = array_ufunc_methods[i]; + /* We won't call this one again (references decref'd below) */ + with_override[i] = NULL; + array_ufunc_methods[i] = NULL; + break; + } + } + /* + * Set override arguments for each call since the tuple must + * not be mutated after use in PyPy + * We increase all references since SET_ITEM steals + * them and they will be DECREF'd when the tuple is deleted. + */ + override_args = PyTuple_New(len + 3); + if (override_args == NULL) { + goto fail; + } + Py_INCREF(ufunc); + PyTuple_SET_ITEM(override_args, 1, (PyObject *)ufunc); + Py_INCREF(method_name); + PyTuple_SET_ITEM(override_args, 2, method_name); + for (i = 0; i < len; i++) { + PyObject *item = PyTuple_GET_ITEM(normal_args, i); + + Py_INCREF(item); + PyTuple_SET_ITEM(override_args, i + 3, item); + } + + /* Check if there is a method left to call */ + if (!override_obj) { + /* No acceptable override found. */ + static PyObject *errmsg_formatter = NULL; + PyObject *errmsg; + + npy_cache_import("numpy.core._internal", + "array_ufunc_errmsg_formatter", + &errmsg_formatter); + + if (errmsg_formatter != NULL) { + /* All tuple items must be set before use */ + Py_INCREF(Py_None); + PyTuple_SET_ITEM(override_args, 0, Py_None); + errmsg = PyObject_Call(errmsg_formatter, override_args, + normal_kwds); + if (errmsg != NULL) { + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + } + } + Py_DECREF(override_args); + goto fail; + } + + /* + * Set the self argument of our unbound method. + * This also steals the reference, so no need to DECREF after. + */ + PyTuple_SET_ITEM(override_args, 0, override_obj); + /* Call the method */ + *result = PyObject_Call( + override_array_ufunc, override_args, normal_kwds); + Py_DECREF(override_array_ufunc); + Py_DECREF(override_args); + if (*result == NULL) { + /* Exception occurred */ + goto fail; + } + else if (*result == Py_NotImplemented) { + /* Try the next one */ + Py_DECREF(*result); + continue; + } + else { + /* Good result. */ + break; + } + } + status = 0; + /* Override found, return it. */ + goto cleanup; +fail: + status = -1; +cleanup: + for (i = 0; i < num_override_args; i++) { + Py_XDECREF(with_override[i]); + Py_XDECREF(array_ufunc_methods[i]); + } + Py_XDECREF(normal_args); + Py_XDECREF(method_name); + Py_XDECREF(normal_kwds); + return status; +} diff --git a/numpy/core/src/umath/override.h b/numpy/core/src/umath/override.h new file mode 100644 index 0000000..68f3c6e --- /dev/null +++ b/numpy/core/src/umath/override.h @@ -0,0 +1,11 @@ +#ifndef _NPY_UMATH_OVERRIDE_H +#define _NPY_UMATH_OVERRIDE_H + +#include "npy_config.h" +#include "numpy/ufuncobject.h" + +NPY_NO_EXPORT int +PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, + PyObject *args, PyObject *kwds, + PyObject **result); +#endif diff --git a/numpy/core/src/umath/reduction.c b/numpy/core/src/umath/reduction.c new file mode 100644 index 0000000..04f5cc1 --- /dev/null +++ b/numpy/core/src/umath/reduction.c @@ -0,0 +1,631 @@ +/* + * This file implements generic methods for computing reductions on arrays. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#define PY_SSIZE_T_CLEAN +#include + +#include "npy_config.h" +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API +#define NO_IMPORT_ARRAY + +#include + +#include "npy_config.h" +#include "npy_pycompat.h" + +#include "numpy/ufuncobject.h" +#include "lowlevel_strided_loops.h" +#include "reduction.h" +#include "extobj.h" /* for _check_ufunc_fperr */ + +/* + * Allocates a result array for a reduction operation, with + * dimensions matching 'arr' except set to 1 with 0 stride + * wherever axis_flags is True. Dropping the reduction axes + * from the result must be done later by the caller once the + * computation is complete. + * + * This function always allocates a base class ndarray. + * + * If 'dtype' isn't NULL, this function steals its reference. + */ +static PyArrayObject * +allocate_reduce_result(PyArrayObject *arr, npy_bool *axis_flags, + PyArray_Descr *dtype, int subok) +{ + npy_intp strides[NPY_MAXDIMS], stride; + npy_intp shape[NPY_MAXDIMS], *arr_shape = PyArray_DIMS(arr); + npy_stride_sort_item strideperm[NPY_MAXDIMS]; + int idim, ndim = PyArray_NDIM(arr); + + if (dtype == NULL) { + dtype = PyArray_DTYPE(arr); + Py_INCREF(dtype); + } + + PyArray_CreateSortedStridePerm(PyArray_NDIM(arr), + PyArray_STRIDES(arr), strideperm); + + /* Build the new strides and shape */ + stride = dtype->elsize; + memcpy(shape, arr_shape, ndim * sizeof(shape[0])); + for (idim = ndim-1; idim >= 0; --idim) { + npy_intp i_perm = strideperm[idim].perm; + if (axis_flags[i_perm]) { + strides[i_perm] = 0; + shape[i_perm] = 1; + } + else { + strides[i_perm] = stride; + stride *= shape[i_perm]; + } + } + + /* Finally, allocate the array */ + return (PyArrayObject *)PyArray_NewFromDescr( + subok ? Py_TYPE(arr) : &PyArray_Type, + dtype, ndim, shape, strides, + NULL, 0, subok ? (PyObject *)arr : NULL); +} + +/* + * Conforms an output parameter 'out' to have 'ndim' dimensions + * with dimensions of size one added in the appropriate places + * indicated by 'axis_flags'. + * + * The return value is a view into 'out'. + */ +static PyArrayObject * +conform_reduce_result(int ndim, npy_bool *axis_flags, + PyArrayObject *out, int keepdims, const char *funcname, + int need_copy) +{ + npy_intp strides[NPY_MAXDIMS], shape[NPY_MAXDIMS]; + npy_intp *strides_out = PyArray_STRIDES(out); + npy_intp *shape_out = PyArray_DIMS(out); + int idim, idim_out, ndim_out = PyArray_NDIM(out); + PyArray_Descr *dtype; + PyArrayObject_fields *ret; + + /* + * If the 'keepdims' parameter is true, do a simpler validation and + * return a new reference to 'out'. + */ + if (keepdims) { + if (PyArray_NDIM(out) != ndim) { + PyErr_Format(PyExc_ValueError, + "output parameter for reduction operation %s " + "has the wrong number of dimensions (must match " + "the operand's when keepdims=True)", funcname); + return NULL; + } + + for (idim = 0; idim < ndim; ++idim) { + if (axis_flags[idim]) { + if (shape_out[idim] != 1) { + PyErr_Format(PyExc_ValueError, + "output parameter for reduction operation %s " + "has a reduction dimension not equal to one " + "(required when keepdims=True)", funcname); + return NULL; + } + } + } + + Py_INCREF(out); + return out; + } + + /* Construct the strides and shape */ + idim_out = 0; + for (idim = 0; idim < ndim; ++idim) { + if (axis_flags[idim]) { + strides[idim] = 0; + shape[idim] = 1; + } + else { + if (idim_out >= ndim_out) { + PyErr_Format(PyExc_ValueError, + "output parameter for reduction operation %s " + "does not have enough dimensions", funcname); + return NULL; + } + strides[idim] = strides_out[idim_out]; + shape[idim] = shape_out[idim_out]; + ++idim_out; + } + } + + if (idim_out != ndim_out) { + PyErr_Format(PyExc_ValueError, + "output parameter for reduction operation %s " + "has too many dimensions", funcname); + return NULL; + } + + /* Allocate the view */ + dtype = PyArray_DESCR(out); + Py_INCREF(dtype); + + ret = (PyArrayObject_fields *)PyArray_NewFromDescr(&PyArray_Type, + dtype, + ndim, shape, + strides, + PyArray_DATA(out), + PyArray_FLAGS(out), + NULL); + if (ret == NULL) { + return NULL; + } + + Py_INCREF(out); + if (PyArray_SetBaseObject((PyArrayObject *)ret, (PyObject *)out) < 0) { + Py_DECREF(ret); + return NULL; + } + + if (need_copy) { + PyArrayObject *ret_copy; + + ret_copy = (PyArrayObject *)PyArray_NewLikeArray( + (PyArrayObject *)ret, NPY_ANYORDER, NULL, 0); + if (ret_copy == NULL) { + Py_DECREF(ret); + return NULL; + } + + if (PyArray_CopyInto(ret_copy, (PyArrayObject *)ret) != 0) { + Py_DECREF(ret); + Py_DECREF(ret_copy); + return NULL; + } + + Py_INCREF(ret); + if (PyArray_SetWritebackIfCopyBase(ret_copy, (PyArrayObject *)ret) < 0) { + Py_DECREF(ret); + Py_DECREF(ret_copy); + return NULL; + } + + return ret_copy; + } + else { + return (PyArrayObject *)ret; + } +} + +/* + * Creates a result for reducing 'operand' along the axes specified + * in 'axis_flags'. If 'dtype' isn't NULL, this function steals a + * reference to 'dtype'. + * + * If 'out' isn't NULL, this function creates a view conforming + * to the number of dimensions of 'operand', adding a singleton dimension + * for each reduction axis specified. In this case, 'dtype' is ignored + * (but its reference is still stolen), and the caller must handle any + * type conversion/validity check for 'out' + * + * If 'subok' is true, creates a result with the subtype of 'operand', + * otherwise creates on with the base ndarray class. + * + * If 'out' is NULL, it allocates a new array whose shape matches that of + * 'operand', except for at the reduction axes. If 'dtype' is NULL, the dtype + * of 'operand' is used for the result. + */ +NPY_NO_EXPORT PyArrayObject * +PyArray_CreateReduceResult(PyArrayObject *operand, PyArrayObject *out, + PyArray_Descr *dtype, npy_bool *axis_flags, + int keepdims, int subok, + const char *funcname) +{ + PyArrayObject *result; + + if (out == NULL) { + /* This function steals the reference to 'dtype' */ + result = allocate_reduce_result(operand, axis_flags, dtype, subok); + } + else { + int need_copy = 0; + + if (solve_may_share_memory(operand, out, 1) != 0) { + need_copy = 1; + } + + /* Steal the dtype reference */ + Py_XDECREF(dtype); + result = conform_reduce_result(PyArray_NDIM(operand), axis_flags, + out, keepdims, funcname, need_copy); + } + + return result; +} + +/* + * Checks that there are only zero or one dimensions selected in 'axis_flags', + * and raises an error about a non-reorderable reduction if not. + */ +static int +check_nonreorderable_axes(int ndim, npy_bool *axis_flags, const char *funcname) +{ + int idim, single_axis = 0; + for (idim = 0; idim < ndim; ++idim) { + if (axis_flags[idim]) { + if (single_axis) { + PyErr_Format(PyExc_ValueError, + "reduction operation '%s' is not reorderable, " + "so only one axis may be specified", + funcname); + return -1; + } + else { + single_axis = 1; + } + } + } + + return 0; +} + +/* + * This function initializes a result array for a reduction operation + * which has no identity. This means it needs to copy the first element + * it sees along the reduction axes to result, then return a view of + * the operand which excludes that element. + * + * If a reduction has an identity, such as 0 or 1, the result should be + * initialized by calling PyArray_AssignZero(result, NULL, NULL) or + * PyArray_AssignOne(result, NULL, NULL), because this function raises an + * exception when there are no elements to reduce (which appropriate iff the + * reduction operation has no identity). + * + * This means it copies the subarray indexed at zero along each reduction axis + * into 'result', then returns a view into 'operand' excluding those copied + * elements. + * + * result : The array into which the result is computed. This must have + * the same number of dimensions as 'operand', but for each + * axis i where 'axis_flags[i]' is True, it has a single element. + * operand : The array being reduced. + * axis_flags : An array of boolean flags, one for each axis of 'operand'. + * When a flag is True, it indicates to reduce along that axis. + * reorderable : If True, the reduction being done is reorderable, which + * means specifying multiple axes of reduction at once is ok, + * and the reduction code may calculate the reduction in an + * arbitrary order. The calculation may be reordered because + * of cache behavior or multithreading requirements. + * out_skip_first_count : This gets populated with the number of first-visit + * elements that should be skipped during the + * iteration loop. + * funcname : The name of the reduction operation, for the purpose of + * better quality error messages. For example, "numpy.max" + * would be a good name for NumPy's max function. + * + * Returns a view which contains the remaining elements on which to do + * the reduction. + */ +NPY_NO_EXPORT PyArrayObject * +PyArray_InitializeReduceResult( + PyArrayObject *result, PyArrayObject *operand, + npy_bool *axis_flags, int reorderable, + npy_intp *out_skip_first_count, const char *funcname) +{ + npy_intp *strides, *shape, shape_orig[NPY_MAXDIMS]; + PyArrayObject *op_view = NULL; + int idim, ndim, nreduce_axes; + + ndim = PyArray_NDIM(operand); + + /* Default to no skipping first-visit elements in the iteration */ + *out_skip_first_count = 0; + + /* + * If this reduction is non-reorderable, make sure there are + * only 0 or 1 axes in axis_flags. + */ + if (!reorderable && check_nonreorderable_axes(ndim, + axis_flags, funcname) < 0) { + return NULL; + } + + /* Take a view into 'operand' which we can modify. */ + op_view = (PyArrayObject *)PyArray_View(operand, NULL, &PyArray_Type); + if (op_view == NULL) { + return NULL; + } + + /* + * Now copy the subarray of the first element along each reduction axis, + * then return a view to the rest. + * + * Adjust the shape to only look at the first element along + * any of the reduction axes. We count the number of reduction axes + * at the same time. + */ + shape = PyArray_SHAPE(op_view); + nreduce_axes = 0; + memcpy(shape_orig, shape, ndim * sizeof(npy_intp)); + for (idim = 0; idim < ndim; ++idim) { + if (axis_flags[idim]) { + if (shape[idim] == 0) { + PyErr_Format(PyExc_ValueError, + "zero-size array to reduction operation %s " + "which has no identity", + funcname); + Py_DECREF(op_view); + return NULL; + } + shape[idim] = 1; + ++nreduce_axes; + } + } + + /* + * Copy the elements into the result to start. + */ + if (PyArray_CopyInto(result, op_view) < 0) { + Py_DECREF(op_view); + return NULL; + } + + /* + * If there is one reduction axis, adjust the view's + * shape to only look at the remaining elements + */ + if (nreduce_axes == 1) { + strides = PyArray_STRIDES(op_view); + for (idim = 0; idim < ndim; ++idim) { + if (axis_flags[idim]) { + shape[idim] = shape_orig[idim] - 1; + ((PyArrayObject_fields *)op_view)->data += strides[idim]; + } + } + } + /* If there are zero reduction axes, make the view empty */ + else if (nreduce_axes == 0) { + for (idim = 0; idim < ndim; ++idim) { + shape[idim] = 0; + } + } + /* + * Otherwise iterate over the whole operand, but tell the inner loop + * to skip the elements we already copied by setting the skip_first_count. + */ + else { + *out_skip_first_count = PyArray_SIZE(result); + + Py_DECREF(op_view); + Py_INCREF(operand); + op_view = operand; + } + + return op_view; +} + +/* + * This function executes all the standard NumPy reduction function + * boilerplate code, just calling assign_identity and the appropriate + * inner loop function where necessary. + * + * operand : The array to be reduced. + * out : NULL, or the array into which to place the result. + * wheremask : NOT YET SUPPORTED, but this parameter is placed here + * so that support can be added in the future without breaking + * API compatibility. Pass in NULL. + * operand_dtype : The dtype the inner loop expects for the operand. + * result_dtype : The dtype the inner loop expects for the result. + * casting : The casting rule to apply to the operands. + * axis_flags : Flags indicating the reduction axes of 'operand'. + * reorderable : If True, the reduction being done is reorderable, which + * means specifying multiple axes of reduction at once is ok, + * and the reduction code may calculate the reduction in an + * arbitrary order. The calculation may be reordered because + * of cache behavior or multithreading requirements. + * keepdims : If true, leaves the reduction dimensions in the result + * with size one. + * subok : If true, the result uses the subclass of operand, otherwise + * it is always a base class ndarray. + * assign_identity : If NULL, PyArray_InitializeReduceResult is used, otherwise + * this function is called to initialize the result to + * the reduction's unit. + * loop : The loop which does the reduction. + * data : Data which is passed to assign_identity and the inner loop. + * buffersize : Buffer size for the iterator. For the default, pass in 0. + * funcname : The name of the reduction function, for error messages. + * errormask : forwarded from _get_bufsize_errmask + * + * TODO FIXME: if you squint, this is essentially an second independent + * implementation of generalized ufuncs with signature (i)->(), plus a few + * extra bells and whistles. (Indeed, as far as I can tell, it was originally + * split out to support a fancy version of count_nonzero... which is not + * actually a reduction function at all, it's just a (i)->() function!) So + * probably these two implementation should be merged into one. (In fact it + * would be quite nice to support axis= and keepdims etc. for arbitrary + * generalized ufuncs!) + */ +NPY_NO_EXPORT PyArrayObject * +PyUFunc_ReduceWrapper(PyArrayObject *operand, PyArrayObject *out, + PyArrayObject *wheremask, + PyArray_Descr *operand_dtype, + PyArray_Descr *result_dtype, + NPY_CASTING casting, + npy_bool *axis_flags, int reorderable, + int keepdims, + int subok, + PyArray_AssignReduceIdentityFunc *assign_identity, + PyArray_ReduceLoopFunc *loop, + void *data, npy_intp buffersize, const char *funcname, + int errormask) +{ + PyArrayObject *result = NULL, *op_view = NULL; + npy_intp skip_first_count = 0; + + /* Iterator parameters */ + NpyIter *iter = NULL; + PyArrayObject *op[2]; + PyArray_Descr *op_dtypes[2]; + npy_uint32 flags, op_flags[2]; + + /* Validate that the parameters for future expansion are NULL */ + if (wheremask != NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Reduce operations in NumPy do not yet support " + "a where mask"); + return NULL; + } + + /* + * This either conforms 'out' to the ndim of 'operand', or allocates + * a new array appropriate for this reduction. + * + * A new array with WRITEBACKIFCOPY is allocated if operand and out have memory + * overlap. + */ + Py_INCREF(result_dtype); + result = PyArray_CreateReduceResult(operand, out, + result_dtype, axis_flags, + keepdims, subok, funcname); + if (result == NULL) { + goto fail; + } + + /* + * Initialize the result to the reduction unit if possible, + * otherwise copy the initial values and get a view to the rest. + */ + if (assign_identity != NULL) { + /* + * If this reduction is non-reorderable, make sure there are + * only 0 or 1 axes in axis_flags. + */ + if (!reorderable && check_nonreorderable_axes(PyArray_NDIM(operand), + axis_flags, funcname) < 0) { + goto fail; + } + + if (assign_identity(result, data) < 0) { + goto fail; + } + op_view = operand; + Py_INCREF(op_view); + } + else { + op_view = PyArray_InitializeReduceResult(result, operand, + axis_flags, reorderable, + &skip_first_count, funcname); + if (op_view == NULL) { + goto fail; + } + /* empty op_view signals no reduction; but 0-d arrays cannot be empty */ + if ((PyArray_SIZE(op_view) == 0) || (PyArray_NDIM(operand) == 0)) { + Py_DECREF(op_view); + op_view = NULL; + goto finish; + } + } + + /* Set up the iterator */ + op[0] = result; + op[1] = op_view; + op_dtypes[0] = result_dtype; + op_dtypes[1] = operand_dtype; + + flags = NPY_ITER_BUFFERED | + NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_GROWINNER | + NPY_ITER_DONT_NEGATE_STRIDES | + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_REDUCE_OK | + NPY_ITER_REFS_OK; + op_flags[0] = NPY_ITER_READWRITE | + NPY_ITER_ALIGNED | + NPY_ITER_NO_SUBTYPE; + op_flags[1] = NPY_ITER_READONLY | + NPY_ITER_ALIGNED; + + iter = NpyIter_AdvancedNew(2, op, flags, + NPY_KEEPORDER, casting, + op_flags, + op_dtypes, + -1, NULL, NULL, buffersize); + if (iter == NULL) { + goto fail; + } + + /* Start with the floating-point exception flags cleared */ + PyUFunc_clearfperr(); + + if (NpyIter_GetIterSize(iter) != 0) { + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strideptr; + npy_intp *countptr; + int needs_api; + + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strideptr = NpyIter_GetInnerStrideArray(iter); + countptr = NpyIter_GetInnerLoopSizePtr(iter); + + needs_api = NpyIter_IterationNeedsAPI(iter); + + /* Straightforward reduction */ + if (loop == NULL) { + PyErr_Format(PyExc_RuntimeError, + "reduction operation %s did not supply an " + "inner loop function", funcname); + goto fail; + } + + if (loop(iter, dataptr, strideptr, countptr, + iternext, needs_api, skip_first_count, data) < 0) { + + goto fail; + } + } + + /* Check whether any errors occurred during the loop */ + if (PyErr_Occurred() || + _check_ufunc_fperr(errormask, NULL, "reduce") < 0) { + goto fail; + } + + NpyIter_Deallocate(iter); + Py_DECREF(op_view); + +finish: + /* Strip out the extra 'one' dimensions in the result */ + if (out == NULL) { + if (!keepdims) { + PyArray_RemoveAxesInPlace(result, axis_flags); + } + } + else { + PyArray_ResolveWritebackIfCopy(result); /* prevent spurious warnings */ + Py_DECREF(result); + result = out; + Py_INCREF(result); + } + + return result; + +fail: + PyArray_ResolveWritebackIfCopy(result); /* prevent spurious warnings */ + Py_XDECREF(result); + Py_XDECREF(op_view); + if (iter != NULL) { + NpyIter_Deallocate(iter); + } + + return NULL; +} diff --git a/numpy/core/src/umath/reduction.h b/numpy/core/src/umath/reduction.h new file mode 100644 index 0000000..7a55c5d --- /dev/null +++ b/numpy/core/src/umath/reduction.h @@ -0,0 +1,156 @@ +#ifndef _NPY_PRIVATE__REDUCTION_H_ +#define _NPY_PRIVATE__REDUCTION_H_ + +/************************************************************ + * Typedefs used by PyArray_ReduceWrapper, new in 1.7. + ************************************************************/ + +/* + * This is a function for assigning a reduction identity to the result, + * before doing the reduction computation. The + * value in 'data' is passed through from PyArray_ReduceWrapper. + * + * This function could, for example, simply be a call like + * return PyArray_AssignZero(result, NULL, NULL); + * + * It should return -1 on failure, or 0 on success. + */ +typedef int (PyArray_AssignReduceIdentityFunc)(PyArrayObject *result, + void *data); + +/* + * This is a function for the reduce loop. + * + * The needs_api parameter indicates whether it's ok to release the GIL during + * the loop, such as when the iternext() function never calls + * a function which could raise a Python exception. + * + * Ths skip_first_count parameter indicates how many elements need to be + * skipped based on NpyIter_IsFirstVisit checks. This can only be positive + * when the 'assign_identity' parameter was NULL when calling + * PyArray_ReduceWrapper. + * + * The loop gets two data pointers and two strides, and should + * look roughly like this: + * { + * NPY_BEGIN_THREADS_DEF; + * if (!needs_api) { + * NPY_BEGIN_THREADS; + * } + * // This first-visit loop can be skipped if 'assign_identity' was non-NULL + * if (skip_first_count > 0) { + * do { + * char *data0 = dataptr[0], *data1 = dataptr[1]; + * npy_intp stride0 = strideptr[0], stride1 = strideptr[1]; + * npy_intp count = *countptr; + * + * // Skip any first-visit elements + * if (NpyIter_IsFirstVisit(iter, 0)) { + * if (stride0 == 0) { + * --count; + * --skip_first_count; + * data1 += stride1; + * } + * else { + * skip_first_count -= count; + * count = 0; + * } + * } + * + * while (count--) { + * *(result_t *)data0 = my_reduce_op(*(result_t *)data0, + * *(operand_t *)data1); + * data0 += stride0; + * data1 += stride1; + * } + * + * // Jump to the faster loop when skipping is done + * if (skip_first_count == 0) { + * if (iternext(iter)) { + * break; + * } + * else { + * goto finish_loop; + * } + * } + * } while (iternext(iter)); + * } + * do { + * char *data0 = dataptr[0], *data1 = dataptr[1]; + * npy_intp stride0 = strideptr[0], stride1 = strideptr[1]; + * npy_intp count = *countptr; + * + * while (count--) { + * *(result_t *)data0 = my_reduce_op(*(result_t *)data0, + * *(operand_t *)data1); + * data0 += stride0; + * data1 += stride1; + * } + * } while (iternext(iter)); + * finish_loop: + * if (!needs_api) { + * NPY_END_THREADS; + * } + * return (needs_api && PyErr_Occurred()) ? -1 : 0; + * } + * + * If needs_api is True, this function should call PyErr_Occurred() + * to check if an error occurred during processing, and return -1 for + * error, 0 for success. + */ +typedef int (PyArray_ReduceLoopFunc)(NpyIter *iter, + char **dataptr, + npy_intp *strideptr, + npy_intp *countptr, + NpyIter_IterNextFunc *iternext, + int needs_api, + npy_intp skip_first_count, + void *data); + +/* + * This function executes all the standard NumPy reduction function + * boilerplate code, just calling assign_identity and the appropriate + * inner loop function where necessary. + * + * operand : The array to be reduced. + * out : NULL, or the array into which to place the result. + * wheremask : NOT YET SUPPORTED, but this parameter is placed here + * so that support can be added in the future without breaking + * API compatibility. Pass in NULL. + * operand_dtype : The dtype the inner loop expects for the operand. + * result_dtype : The dtype the inner loop expects for the result. + * casting : The casting rule to apply to the operands. + * axis_flags : Flags indicating the reduction axes of 'operand'. + * reorderable : If True, the reduction being done is reorderable, which + * means specifying multiple axes of reduction at once is ok, + * and the reduction code may calculate the reduction in an + * arbitrary order. The calculation may be reordered because + * of cache behavior or multithreading requirements. + * keepdims : If true, leaves the reduction dimensions in the result + * with size one. + * subok : If true, the result uses the subclass of operand, otherwise + * it is always a base class ndarray. + * assign_identity : If NULL, PyArray_InitializeReduceResult is used, otherwise + * this function is called to initialize the result to + * the reduction's unit. + * loop : The loop which does the reduction. + * data : Data which is passed to assign_identity and the inner loop. + * buffersize : Buffer size for the iterator. For the default, pass in 0. + * funcname : The name of the reduction function, for error messages. + * errormask : forwarded from _get_bufsize_errmask + */ +NPY_NO_EXPORT PyArrayObject * +PyUFunc_ReduceWrapper(PyArrayObject *operand, PyArrayObject *out, + PyArrayObject *wheremask, + PyArray_Descr *operand_dtype, + PyArray_Descr *result_dtype, + NPY_CASTING casting, + npy_bool *axis_flags, int reorderable, + int keepdims, + int subok, + PyArray_AssignReduceIdentityFunc *assign_identity, + PyArray_ReduceLoopFunc *loop, + void *data, npy_intp buffersize, const char *funcname, + int errormask); + +#endif diff --git a/numpy/core/src/umath/scalarmath.c.src b/numpy/core/src/umath/scalarmath.c.src new file mode 100644 index 0000000..7b424cc --- /dev/null +++ b/numpy/core/src/umath/scalarmath.c.src @@ -0,0 +1,1756 @@ +/* -*- c -*- */ + +/* The purpose of this module is to add faster math for array scalars + that does not go through the ufunc machinery + + but still supports error-modes. +*/ + +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" +#include "npy_config.h" +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API +#define NO_IMPORT_ARRAY + +#include "numpy/arrayobject.h" +#include "numpy/ufuncobject.h" +#include "numpy/arrayscalars.h" + +#include "npy_pycompat.h" + +#include "numpy/halffloat.h" +#include "templ_common.h" + +#include "binop_override.h" +#include "npy_longdouble.h" + +/* Basic operations: + * + * BINARY: + * + * add, subtract, multiply, divide, remainder, divmod, power, + * floor_divide, true_divide + * + * lshift, rshift, and, or, xor (integers only) + * + * UNARY: + * + * negative, positive, absolute, nonzero, invert, int, long, float, oct, hex + * + */ + +/**begin repeat + * #name = byte, short, int, long, longlong# + * #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong# + */ +static void +@name@_ctype_add(@type@ a, @type@ b, @type@ *out) { + *out = a + b; + if ((*out^a) >= 0 || (*out^b) >= 0) { + return; + } + npy_set_floatstatus_overflow(); + return; +} +static void +@name@_ctype_subtract(@type@ a, @type@ b, @type@ *out) { + *out = a - b; + if ((*out^a) >= 0 || (*out^~b) >= 0) { + return; + } + npy_set_floatstatus_overflow(); + return; +} +/**end repeat**/ + +/**begin repeat + * #name = ubyte, ushort, uint, ulong, ulonglong# + * #type = npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong# + */ +static void +@name@_ctype_add(@type@ a, @type@ b, @type@ *out) { + *out = a + b; + if (*out >= a && *out >= b) { + return; + } + npy_set_floatstatus_overflow(); + return; +} +static void +@name@_ctype_subtract(@type@ a, @type@ b, @type@ *out) { + *out = a - b; + if (a >= b) { + return; + } + npy_set_floatstatus_overflow(); + return; +} +/**end repeat**/ + +#ifndef NPY_SIZEOF_BYTE +#define NPY_SIZEOF_BYTE 1 +#endif + +/**begin repeat + * + * #name = byte, ubyte, short, ushort, + * int, uint, long, ulong# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, + * npy_int, npy_uint, npy_long, npy_ulong# + * #big = npy_int, npy_uint, npy_int, npy_uint, + * npy_longlong, npy_ulonglong, npy_longlong, npy_ulonglong# + * #NAME = BYTE, UBYTE, SHORT, USHORT, + * INT, UINT, LONG, ULONG# + * #SIZENAME = BYTE*2, SHORT*2, INT*2, LONG*2# + * #SIZE = INT*4,LONGLONG*4# + * #neg = (1,0)*4# + */ +#if NPY_SIZEOF_@SIZE@ > NPY_SIZEOF_@SIZENAME@ +static void +@name@_ctype_multiply(@type@ a, @type@ b, @type@ *out) { + @big@ temp; + temp = ((@big@) a) * ((@big@) b); + *out = (@type@) temp; +#if @neg@ + if (temp > NPY_MAX_@NAME@ || temp < NPY_MIN_@NAME@) +#else + if (temp > NPY_MAX_@NAME@) +#endif + npy_set_floatstatus_overflow(); + return; +} +#endif +/**end repeat**/ + +/**begin repeat + * + * #name = int, uint, long, ulong, + * longlong, ulonglong# + * #type = npy_int, npy_uint, npy_long, npy_ulong, + * npy_longlong, npy_ulonglong# + * #SIZE = INT*2, LONG*2, LONGLONG*2# + */ +#if NPY_SIZEOF_LONGLONG == NPY_SIZEOF_@SIZE@ +static void +@name@_ctype_multiply(@type@ a, @type@ b, @type@ *out) { + if (npy_mul_with_overflow_@name@(out, a, b)) { + npy_set_floatstatus_overflow(); + } + return; +} +#endif +/**end repeat**/ + +/**begin repeat + * + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong# + * #neg = (1,0)*5# + */ +static void +@name@_ctype_divide(@type@ a, @type@ b, @type@ *out) { + if (b == 0) { + npy_set_floatstatus_divbyzero(); + *out = 0; + } +#if @neg@ + else if (b == -1 && a < 0 && a == -a) { + npy_set_floatstatus_overflow(); + *out = a / b; + } +#endif + else { +#if @neg@ + @type@ tmp; + tmp = a / b; + if (((a > 0) != (b > 0)) && (a % b != 0)) { + tmp--; + } + *out = tmp; +#else + *out = a / b; +#endif + } +} + +#define @name@_ctype_floor_divide @name@_ctype_divide + +static void +@name@_ctype_remainder(@type@ a, @type@ b, @type@ *out) { + if (a == 0 || b == 0) { + if (b == 0) npy_set_floatstatus_divbyzero(); + *out = 0; + return; + } +#if @neg@ + else if ((a > 0) == (b > 0)) { + *out = a % b; + } + else { + /* handled like Python does */ + *out = a % b; + if (*out) *out += b; + } +#else + *out = a % b; +#endif +} +/**end repeat**/ + +/**begin repeat + * + * #name = byte, ubyte, short, ushort, int, uint, long, + * ulong, longlong, ulonglong# + * #otyp = npy_float*4, npy_double*6# + */ +#define @name@_ctype_true_divide(a, b, out) \ + *(out) = ((@otyp@) (a)) / ((@otyp@) (b)); +/**end repeat**/ + +/* b will always be positive in this call */ +/**begin repeat + * + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong# + * #upc = BYTE, UBYTE, SHORT, USHORT, INT, UINT, + * LONG, ULONG, LONGLONG, ULONGLONG# + */ +static void +@name@_ctype_power(@type@ a, @type@ b, @type@ *out) { + @type@ tmp; + + if (b == 0) { + *out = 1; + return; + } + if (a == 1) { + *out = 1; + return; + } + + tmp = b & 1 ? a : 1; + b >>= 1; + while (b > 0) { + a *= a; + if (b & 1) { + tmp *= a; + } + b >>= 1; + } + *out = tmp; +} +/**end repeat**/ + + + +/* QUESTION: Should we check for overflow / underflow in (l,r)shift? */ + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong# + */ + +/**begin repeat1 + * #oper = and, xor, or, lshift, rshift# + * #op = &, ^, |, <<, >># + */ + +#define @name@_ctype_@oper@(arg1, arg2, out) *(out) = (arg1) @op@ (arg2) + +/**end repeat1**/ + +/**end repeat**/ + +/**begin repeat + * #name = float, double, longdouble# + * #type = npy_float, npy_double, npy_longdouble# + * #c = f, , l# + */ +static @type@ (*_basic_@name@_sqrt)(@type@); +static @type@ (*_basic_@name@_fmod)(@type@, @type@); + +#define @name@_ctype_add(a, b, outp) *(outp) = (a) + (b) +#define @name@_ctype_subtract(a, b, outp) *(outp) = (a) - (b) +#define @name@_ctype_multiply(a, b, outp) *(outp) = (a) * (b) +#define @name@_ctype_divide(a, b, outp) *(outp) = (a) / (b) +#define @name@_ctype_true_divide @name@_ctype_divide + + +static void +@name@_ctype_floor_divide(@type@ a, @type@ b, @type@ *out) { + @type@ mod; + + *out = npy_divmod@c@(a, b, &mod); +} + + +static void +@name@_ctype_remainder(@type@ a, @type@ b, @type@ *out) { + npy_divmod@c@(a, b, out); +} + + +static void +@name@_ctype_divmod(@type@ a, @type@ b, @type@ *out1, @type@ *out2) { + *out1 = npy_divmod@c@(a, b, out2); +} + + +/**end repeat**/ + +static npy_half (*_basic_half_sqrt)(npy_half); +static npy_half (*_basic_half_fmod)(npy_half, npy_half); + +#define half_ctype_add(a, b, outp) *(outp) = \ + npy_float_to_half(npy_half_to_float(a) + npy_half_to_float(b)) +#define half_ctype_subtract(a, b, outp) *(outp) = \ + npy_float_to_half(npy_half_to_float(a) - npy_half_to_float(b)) +#define half_ctype_multiply(a, b, outp) *(outp) = \ + npy_float_to_half(npy_half_to_float(a) * npy_half_to_float(b)) +#define half_ctype_divide(a, b, outp) *(outp) = \ + npy_float_to_half(npy_half_to_float(a) / npy_half_to_float(b)) +#define half_ctype_true_divide half_ctype_divide + + +static void +half_ctype_floor_divide(npy_half a, npy_half b, npy_half *out) { + npy_half mod; + + *out = npy_half_divmod(a, b, &mod); +} + + +static void +half_ctype_remainder(npy_half a, npy_half b, npy_half *out) { + npy_half_divmod(a, b, out); +} + + +static void +half_ctype_divmod(npy_half a, npy_half b, npy_half *out1, npy_half *out2) { + *out1 = npy_half_divmod(a, b, out2); +} + +/**begin repeat + * #name = cfloat, cdouble, clongdouble# + * #rname = float, double, longdouble# + * #rtype = npy_float, npy_double, npy_longdouble# + * #c = f,,l# + */ +#define @name@_ctype_add(a, b, outp) do{ \ + (outp)->real = (a).real + (b).real; \ + (outp)->imag = (a).imag + (b).imag; \ + } while(0) +#define @name@_ctype_subtract(a, b, outp) do{ \ + (outp)->real = (a).real - (b).real; \ + (outp)->imag = (a).imag - (b).imag; \ + } while(0) +#define @name@_ctype_multiply(a, b, outp) do{ \ + (outp)->real = (a).real * (b).real - (a).imag * (b).imag; \ + (outp)->imag = (a).real * (b).imag + (a).imag * (b).real; \ + } while(0) +/* Algorithm identical to that in loops.c.src, for consistency */ +#define @name@_ctype_divide(a, b, outp) do{ \ + @rtype@ in1r = (a).real; \ + @rtype@ in1i = (a).imag; \ + @rtype@ in2r = (b).real; \ + @rtype@ in2i = (b).imag; \ + @rtype@ in2r_abs = npy_fabs@c@(in2r); \ + @rtype@ in2i_abs = npy_fabs@c@(in2i); \ + if (in2r_abs >= in2i_abs) { \ + if (in2r_abs == 0 && in2i_abs == 0) { \ + /* divide by zero should yield a complex inf or nan */ \ + (outp)->real = in1r/in2r_abs; \ + (outp)->imag = in1i/in2i_abs; \ + } \ + else { \ + @rtype@ rat = in2i/in2r; \ + @rtype@ scl = 1.0@c@/(in2r + in2i*rat); \ + (outp)->real = (in1r + in1i*rat)*scl; \ + (outp)->imag = (in1i - in1r*rat)*scl; \ + } \ + } \ + else { \ + @rtype@ rat = in2r/in2i; \ + @rtype@ scl = 1.0@c@/(in2i + in2r*rat); \ + (outp)->real = (in1r*rat + in1i)*scl; \ + (outp)->imag = (in1i*rat - in1r)*scl; \ + } \ + } while(0) + +#define @name@_ctype_true_divide @name@_ctype_divide + +#define @name@_ctype_floor_divide(a, b, outp) do { \ + @rname@_ctype_floor_divide( \ + ((a).real*(b).real + (a).imag*(b).imag), \ + ((b).real*(b).real + (b).imag*(b).imag), \ + &((outp)->real)); \ + (outp)->imag = 0; \ + } while(0) +/**end repeat**/ + + + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, long, ulong, + * longlong, ulonglong, cfloat, cdouble, clongdouble# + */ +#define @name@_ctype_divmod(a, b, out, out2) { \ + @name@_ctype_floor_divide(a, b, out); \ + @name@_ctype_remainder(a, b, out2); \ + } +/**end repeat**/ + + +/**begin repeat + * #name = float, double, longdouble# + * #type = npy_float, npy_double, npy_longdouble# + */ +static npy_@name@ (*_basic_@name@_pow)(@type@ a, @type@ b); + +static void +@name@_ctype_power(@type@ a, @type@ b, @type@ *out) +{ + *out = _basic_@name@_pow(a, b); +} +/**end repeat**/ +static void +half_ctype_power(npy_half a, npy_half b, npy_half *out) +{ + const npy_float af = npy_half_to_float(a); + const npy_float bf = npy_half_to_float(b); + const npy_float outf = _basic_float_pow(af,bf); + *out = npy_float_to_half(outf); +} + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * float, double, longdouble# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_float, npy_double, npy_longdouble# + * #uns = (0,1)*5,0*3# + */ +static void +@name@_ctype_negative(@type@ a, @type@ *out) +{ +#if @uns@ + npy_set_floatstatus_overflow(); +#endif + *out = -a; +} +/**end repeat**/ + +static void +half_ctype_negative(npy_half a, npy_half *out) +{ + *out = a^0x8000u; +} + + +/**begin repeat + * #name = cfloat, cdouble, clongdouble# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# + */ +static void +@name@_ctype_negative(@type@ a, @type@ *out) +{ + out->real = -a.real; + out->imag = -a.imag; +} +/**end repeat**/ + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble# + */ +static void +@name@_ctype_positive(@type@ a, @type@ *out) +{ + *out = a; +} +/**end repeat**/ + +/* + * Get the nc_powf, nc_pow, and nc_powl functions from + * the data area of the power ufunc in umathmodule. + */ + +/**begin repeat + * #name = cfloat, cdouble, clongdouble# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# + */ +static void +@name@_ctype_positive(@type@ a, @type@ *out) +{ + out->real = a.real; + out->imag = a.imag; +} + +static void (*_basic_@name@_pow)(@type@ *, @type@ *, @type@ *); + +static void +@name@_ctype_power(@type@ a, @type@ b, @type@ *out) +{ + _basic_@name@_pow(&a, &b, out); +} +/**end repeat**/ + + +/**begin repeat + * #name = ubyte, ushort, uint, ulong, ulonglong# + */ + +#define @name@_ctype_absolute @name@_ctype_positive + +/**end repeat**/ + + +/**begin repeat + * #name = byte, short, int, long, longlong# + * #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong# + */ +static void +@name@_ctype_absolute(@type@ a, @type@ *out) +{ + *out = (a < 0 ? -a : a); +} +/**end repeat**/ + +/**begin repeat + * #name = float, double, longdouble# + * #type = npy_float, npy_double, npy_longdouble# + * #c = f,,l# + */ +static void +@name@_ctype_absolute(@type@ a, @type@ *out) +{ + *out = npy_fabs@c@(a); +} +/**end repeat**/ + +static void +half_ctype_absolute(npy_half a, npy_half *out) +{ + *out = a&0x7fffu; +} + +/**begin repeat + * #name = cfloat, cdouble, clongdouble# + * #type = npy_cfloat, npy_cdouble, npy_clongdouble# + * #rtype = npy_float, npy_double, npy_longdouble# + * #c = f,,l# + */ +static void +@name@_ctype_absolute(@type@ a, @rtype@ *out) +{ + *out = npy_cabs@c@(a); +} +/**end repeat**/ + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, long, + * ulong, longlong, ulonglong# + */ + +#define @name@_ctype_invert(a, out) *(out) = ~a; + +/**end repeat**/ + +/*** END OF BASIC CODE **/ + + +/* The general strategy for commutative binary operators is to + * + * 1) Convert the types to the common type if both are scalars (0 return) + * 2) If both are not scalars use ufunc machinery (-2 return) + * 3) If both are scalars but cannot be cast to the right type + * return NotImplmented (-1 return) + * + * 4) Perform the function on the C-type. + * 5) If an error condition occurred, check to see + * what the current error-handling is and handle the error. + * + * 6) Construct and return the output scalar. + */ + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, longdouble, + * cfloat, cdouble, clongdouble# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + * #Name = Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong, + * Half, Float, LongDouble, + * CFloat, CDouble, CLongDouble# + * #TYPE = NPY_BYTE, NPY_UBYTE, NPY_SHORT, NPY_USHORT, NPY_INT, NPY_UINT, + * NPY_LONG, NPY_ULONG, NPY_LONGLONG, NPY_ULONGLONG, + * NPY_HALF, NPY_FLOAT, NPY_LONGDOUBLE, + * NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE# + */ + +static int +_@name@_convert_to_ctype(PyObject *a, @type@ *arg1) +{ + PyObject *temp; + + if (PyArray_IsScalar(a, @Name@)) { + *arg1 = PyArrayScalar_VAL(a, @Name@); + return 0; + } + else if (PyArray_IsScalar(a, Generic)) { + PyArray_Descr *descr1; + + if (!PyArray_IsScalar(a, Number)) { + return -1; + } + descr1 = PyArray_DescrFromTypeObject((PyObject *)Py_TYPE(a)); + if (PyArray_CanCastSafely(descr1->type_num, @TYPE@)) { + PyArray_CastScalarDirect(a, descr1, arg1, @TYPE@); + Py_DECREF(descr1); + return 0; + } + else { + Py_DECREF(descr1); + return -1; + } + } + else if (PyArray_GetPriority(a, NPY_PRIORITY) > NPY_PRIORITY) { + return -2; + } + else if ((temp = PyArray_ScalarFromObject(a)) != NULL) { + int retval = _@name@_convert_to_ctype(temp, arg1); + + Py_DECREF(temp); + return retval; + } + return -2; +} + +/**end repeat**/ + + +/* Same as above but added exact checks against known python types for speed */ + +/**begin repeat + * #name = double# + * #type = npy_double# + * #Name = Double# + * #TYPE = NPY_DOUBLE# + * #PYCHECKEXACT = PyFloat_CheckExact# + * #PYEXTRACTCTYPE = PyFloat_AS_DOUBLE# + */ + +static int +_@name@_convert_to_ctype(PyObject *a, @type@ *arg1) +{ + PyObject *temp; + + if (@PYCHECKEXACT@(a)){ + *arg1 = @PYEXTRACTCTYPE@(a); + return 0; + } + + if (PyArray_IsScalar(a, @Name@)) { + *arg1 = PyArrayScalar_VAL(a, @Name@); + return 0; + } + else if (PyArray_IsScalar(a, Generic)) { + PyArray_Descr *descr1; + + if (!PyArray_IsScalar(a, Number)) { + return -1; + } + descr1 = PyArray_DescrFromTypeObject((PyObject *)Py_TYPE(a)); + if (PyArray_CanCastSafely(descr1->type_num, @TYPE@)) { + PyArray_CastScalarDirect(a, descr1, arg1, @TYPE@); + Py_DECREF(descr1); + return 0; + } + else { + Py_DECREF(descr1); + return -1; + } + } + else if (PyArray_GetPriority(a, NPY_PRIORITY) > NPY_PRIORITY) { + return -2; + } + else if ((temp = PyArray_ScalarFromObject(a)) != NULL) { + int retval = _@name@_convert_to_ctype(temp, arg1); + + Py_DECREF(temp); + return retval; + } + return -2; +} + +/**end repeat**/ + + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, cfloat, cdouble# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_cfloat, npy_cdouble# + */ +static int +_@name@_convert2_to_ctypes(PyObject *a, @type@ *arg1, + PyObject *b, @type@ *arg2) +{ + int ret; + ret = _@name@_convert_to_ctype(a, arg1); + if (ret < 0) { + return ret; + } + ret = _@name@_convert_to_ctype(b, arg2); + if (ret < 0) { + return ret; + } + return 0; +} +/**end repeat**/ + +/**begin repeat + * #name = longdouble, clongdouble# + * #type = npy_longdouble, npy_clongdouble# + */ + +static int +_@name@_convert2_to_ctypes(PyObject *a, @type@ *arg1, + PyObject *b, @type@ *arg2) +{ + int ret; + ret = _@name@_convert_to_ctype(a, arg1); + if (ret < 0) { + return ret; + } + ret = _@name@_convert_to_ctype(b, arg2); + if (ret == -2) { + ret = -3; + } + if (ret < 0) { + return ret; + } + return 0; +} + +/**end repeat**/ + + +#if defined(NPY_PY3K) +#define CODEGEN_SKIP_divide_FLAG +#endif + +/**begin repeat + * + * #name = (byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong)*13, + * (half, float, double, longdouble, + * cfloat, cdouble, clongdouble)*6, + * (half, float, double, longdouble)*2# + * #Name = (Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong,LongLong,ULongLong)*13, + * (Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble)*6, + * (Half, Float, Double, LongDouble)*2# + * #type = (npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong)*13, + * (npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble)*6, + * (npy_half, npy_float, npy_double, npy_longdouble)*2# + * + * #oper = add*10, subtract*10, multiply*10, divide*10, remainder*10, + * divmod*10, floor_divide*10, lshift*10, rshift*10, and*10, + * or*10, xor*10, true_divide*10, + * add*7, subtract*7, multiply*7, divide*7, floor_divide*7, true_divide*7, + * divmod*4, remainder*4# + * + * #fperr = 1*70,0*50,1*10, + * 1*42, + * 1*8# + * #twoout = 0*50,1*10,0*70, + * 0*42, + * 1*4,0*4# + * #otype = (npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong)*12, + * npy_float*4, npy_double*6, + * (npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble)*6, + * (npy_half, npy_float, npy_double, npy_longdouble)*2# + * #OName = (Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong)*12, + * Float*4, Double*6, + * (Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble)*6, + * (Half, Float, Double, LongDouble)*2# + */ + +#if !defined(CODEGEN_SKIP_@oper@_FLAG) + +static PyObject * +@name@_@oper@(PyObject *a, PyObject *b) +{ + PyObject *ret; + @type@ arg1, arg2; + /* + * NOTE: In gcc >= 4.1, the compiler will reorder floating point + * operations and floating point error state checks. In + * particular, the arithmetic operations were being reordered + * so that the errors weren't caught. Declaring this output + * variable volatile was the minimal fix for the issue. + * (Ticket #1671) + */ + volatile @otype@ out; +#if @twoout@ + @otype@ out2; + PyObject *obj; +#endif + +#if @fperr@ + int retstatus; + int first; +#endif + + BINOP_GIVE_UP_IF_NEEDED(a, b, nb_@oper@, @name@_@oper@); + + switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) { + case 0: + break; + case -1: + /* one of them can't be cast safely must be mixed-types*/ + return PyArray_Type.tp_as_number->nb_@oper@(a,b); + case -2: + /* use default handling */ + if (PyErr_Occurred()) { + return NULL; + } + return PyGenericArrType_Type.tp_as_number->nb_@oper@(a,b); + case -3: + /* + * special case for longdouble and clongdouble + * because they have a recursive getitem in their dtype + */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + +#if @fperr@ + PyUFunc_clearfperr(); +#endif + + /* + * here we do the actual calculation with arg1 and arg2 + * as a function call. + */ +#if @twoout@ + @name@_ctype_@oper@(arg1, arg2, (@otype@ *)&out, &out2); +#else + @name@_ctype_@oper@(arg1, arg2, (@otype@ *)&out); +#endif + +#if @fperr@ + /* Check status flag. If it is set, then look up what to do */ + retstatus = PyUFunc_getfperr(); + if (retstatus) { + int bufsize, errmask; + PyObject *errobj; + + if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask, + &errobj) < 0) { + return NULL; + } + first = 1; + if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) { + Py_XDECREF(errobj); + return NULL; + } + Py_XDECREF(errobj); + } +#endif + + +#if @twoout@ + ret = PyTuple_New(2); + if (ret == NULL) { + return NULL; + } + obj = PyArrayScalar_New(@OName@); + if (obj == NULL) { + Py_DECREF(ret); + return NULL; + } + PyArrayScalar_ASSIGN(obj, @OName@, out); + PyTuple_SET_ITEM(ret, 0, obj); + obj = PyArrayScalar_New(@OName@); + if (obj == NULL) { + Py_DECREF(ret); + return NULL; + } + PyArrayScalar_ASSIGN(obj, @OName@, out2); + PyTuple_SET_ITEM(ret, 1, obj); +#else + ret = PyArrayScalar_New(@OName@); + if (ret == NULL) { + return NULL; + } + PyArrayScalar_ASSIGN(ret, @OName@, out); +#endif + return ret; +} +#endif + +/**end repeat**/ + +#undef CODEGEN_SKIP_divide_FLAG + +#define _IS_ZERO(x) (x == 0) + +/**begin repeat + * + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + * + * #Name = Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong, + * Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble# + * + * #oname = float*4, double*6, half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * + * #otype = npy_float*4, npy_double*6, npy_half, npy_float, + * npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + * + * #OName = Float*4, Double*6, Half, Float, + * Double, LongDouble, + * CFloat, CDouble, CLongDouble# + * + * #isint = (1,0)*5,0*7# + * #cmplx = 0*14,1*3# + * #iszero = _IS_ZERO*10, npy_half_iszero, _IS_ZERO*6# + * #zero = 0*10, NPY_HALF_ZERO, 0*6# + * #one = 1*10, NPY_HALF_ONE, 1*6# + */ + +#if @cmplx@ +static PyObject * +@name@_power(PyObject *a, PyObject *b, PyObject *modulo) +{ + PyObject *ret; + @type@ arg1, arg2; + int retstatus; + int first; + @type@ out = {@zero@, @zero@}; + + BINOP_GIVE_UP_IF_NEEDED(a, b, nb_power, @name@_power); + + switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) { + case 0: + break; + case -1: + /* can't cast both safely mixed-types? */ + return PyArray_Type.tp_as_number->nb_power(a,b,modulo); + case -2: + /* use default handling */ + if (PyErr_Occurred()) { + return NULL; + } + return PyGenericArrType_Type.tp_as_number->nb_power(a,b,modulo); + case -3: + default: + /* + * special case for longdouble and clongdouble + * because they have a recursive getitem in their dtype + */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (modulo != Py_None) { + /* modular exponentiation is not implemented (gh-8804) */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyUFunc_clearfperr(); + + /* + * here we do the actual calculation with arg1 and arg2 + * as a function call. + */ + if (@iszero@(arg2.real) && @iszero@(arg2.imag)) { + out.real = @one@; + out.imag = @zero@; + } + else { + @name@_ctype_power(arg1, arg2, &out); + } + + /* Check status flag. If it is set, then look up what to do */ + retstatus = PyUFunc_getfperr(); + if (retstatus) { + int bufsize, errmask; + PyObject *errobj; + + if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask, + &errobj) < 0) { + return NULL; + } + first = 1; + if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) { + Py_XDECREF(errobj); + return NULL; + } + Py_XDECREF(errobj); + } + + ret = PyArrayScalar_New(@Name@); + if (ret == NULL) { + return NULL; + } + PyArrayScalar_ASSIGN(ret, @Name@, out); + + return ret; +} + +#elif @isint@ + +static PyObject * +@name@_power(PyObject *a, PyObject *b, PyObject *modulo) +{ + PyObject *ret; + @type@ arg1, arg2, out; + + BINOP_GIVE_UP_IF_NEEDED(a, b, nb_power, @name@_power); + + switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) { + case 0: + break; + case -1: + /* can't cast both safely mixed-types? */ + return PyArray_Type.tp_as_number->nb_power(a,b,modulo); + case -2: + /* use default handling */ + if (PyErr_Occurred()) { + return NULL; + } + return PyGenericArrType_Type.tp_as_number->nb_power(a,b,modulo); + case -3: + default: + /* + * special case for longdouble and clongdouble + * because they have a recursive getitem in their dtype + */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (modulo != Py_None) { + /* modular exponentiation is not implemented (gh-8804) */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyUFunc_clearfperr(); + + /* + * here we do the actual calculation with arg1 and arg2 + * as a function call. + */ + if (arg2 < 0) { + PyErr_SetString(PyExc_ValueError, + "Integers to negative integer powers are not allowed."); + return NULL; + } + @name@_ctype_power(arg1, arg2, &out); + + ret = PyArrayScalar_New(@Name@); + if (ret == NULL) { + return NULL; + } + PyArrayScalar_ASSIGN(ret, @Name@, out); + + return ret; +} + +#else + +static PyObject * +@name@_power(PyObject *a, PyObject *b, PyObject *modulo) +{ + PyObject *ret; + @type@ arg1, arg2; + int retstatus; + int first; + + @type@ out = @zero@; + + BINOP_GIVE_UP_IF_NEEDED(a, b, nb_power, @name@_power); + + switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) { + case 0: + break; + case -1: + /* can't cast both safely mixed-types? */ + return PyArray_Type.tp_as_number->nb_power(a,b,modulo); + case -2: + /* use default handling */ + if (PyErr_Occurred()) { + return NULL; + } + return PyGenericArrType_Type.tp_as_number->nb_power(a,b,modulo); + case -3: + default: + /* + * special case for longdouble and clongdouble + * because they have a recursive getitem in their dtype + */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (modulo != Py_None) { + /* modular exponentiation is not implemented (gh-8804) */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + PyUFunc_clearfperr(); + + /* + * here we do the actual calculation with arg1 and arg2 + * as a function call. + */ + if (@iszero@(arg2)) { + out = @one@; + } + else { + @name@_ctype_power(arg1, arg2, &out); + } + + /* Check status flag. If it is set, then look up what to do */ + retstatus = PyUFunc_getfperr(); + if (retstatus) { + int bufsize, errmask; + PyObject *errobj; + + if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask, + &errobj) < 0) { + return NULL; + } + first = 1; + if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) { + Py_XDECREF(errobj); + return NULL; + } + Py_XDECREF(errobj); + } + + ret = PyArrayScalar_New(@Name@); + if (ret == NULL) { + return NULL; + } + PyArrayScalar_ASSIGN(ret, @Name@, out); + + return ret; +} + +#endif + +/**end repeat**/ +#undef _IS_ZERO + + +/**begin repeat + * + * #name = cfloat, cdouble, clongdouble# + * + */ + +/**begin repeat1 + * + * #oper = divmod, remainder# + * + */ + +#define @name@_@oper@ NULL + +/**end repeat1**/ + +/**end repeat**/ + +/**begin repeat + * + * #name = half, float, double, longdouble, cfloat, cdouble, clongdouble# + * + */ + +/**begin repeat1 + * + * #oper = lshift, rshift, and, or, xor# + * + */ + +#define @name@_@oper@ NULL + +/**end repeat1**/ + +/**end repeat**/ + +/**begin repeat + * #name = (byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble)*3, + * + * byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong# + * + * #type = (npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble)*3, + * + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong# + * + * #otype = (npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble)*2, + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_float, npy_double, npy_longdouble, + * + * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, + * npy_long, npy_ulong, npy_longlong, npy_ulonglong# + * + * #OName = (Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong, + * Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble)*2, + * Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong, + * Half, Float, Double, LongDouble, + * Float, Double, LongDouble, + * + * Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong# + * + * #oper = negative*17, positive*17, absolute*17, invert*10# + */ +static PyObject * +@name@_@oper@(PyObject *a) +{ + @type@ arg1; + @otype@ out; + PyObject *ret; + + switch(_@name@_convert_to_ctype(a, &arg1)) { + case 0: + break; + case -1: + /* can't cast both safely use different add function */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + case -2: + /* use default handling */ + if (PyErr_Occurred()) { + return NULL; + } + return PyGenericArrType_Type.tp_as_number->nb_@oper@(a); + } + + /* + * here we do the actual calculation with arg1 and arg2 + * make it a function call. + */ + + @name@_ctype_@oper@(arg1, &out); + + ret = PyArrayScalar_New(@OName@); + PyArrayScalar_ASSIGN(ret, @OName@, out); + + return ret; +} +/**end repeat**/ + +/**begin repeat + * + * #name = half, float, double, longdouble, cfloat, cdouble, clongdouble# + */ + +#define @name@_invert NULL + +/**end repeat**/ + +#if defined(NPY_PY3K) +#define NONZERO_NAME(prefix) prefix##bool +#else +#define NONZERO_NAME(prefix) prefix##nonzero +#endif + +#define _IS_NONZERO(x) (x != 0) +/**begin repeat + * + * #name = byte, ubyte, short, ushort, int, + * uint, long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, + * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong, + * npy_half, npy_float, npy_double, npy_longdouble, + * npy_cfloat, npy_cdouble, npy_clongdouble# + * #simp = 1*14, 0*3# + * #nonzero = _IS_NONZERO*10, !npy_half_iszero, _IS_NONZERO*6# + */ +static int +NONZERO_NAME(@name@_)(PyObject *a) +{ + int ret; + @type@ arg1; + + if (_@name@_convert_to_ctype(a, &arg1) < 0) { + if (PyErr_Occurred()) { + return -1; + } + return PyGenericArrType_Type.tp_as_number->NONZERO_NAME(nb_)(a); + } + + /* + * here we do the actual calculation with arg1 and arg2 + * make it a function call. + */ + +#if @simp@ + ret = @nonzero@(arg1); +#else + ret = (@nonzero@(arg1.real) || @nonzero@(arg1.imag)); +#endif + + return ret; +} +/**end repeat**/ +#undef _IS_NONZERO + + +static int +emit_complexwarning(void) +{ + static PyObject *cls = NULL; + if (cls == NULL) { + PyObject *mod; + mod = PyImport_ImportModule("numpy.core"); + assert(mod != NULL); + cls = PyObject_GetAttrString(mod, "ComplexWarning"); + assert(cls != NULL); + Py_DECREF(mod); + } + return PyErr_WarnEx(cls, + "Casting complex values to real discards the imaginary part", 1); +} + +/**begin repeat + * + * #name = byte, ubyte, short, ushort, int, + * uint, long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * + * #Name = Byte, UByte, Short, UShort, Int, + * UInt, Long, ULong, LongLong, ULongLong, + * Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble# + * + * #cmplx = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1# + * #sign = (signed, unsigned)*5, , , , , , , # + * #ctype = long*8, PY_LONG_LONG*2, + * double*3, npy_longdouble, double*2, npy_longdouble# + * #to_ctype = , , , , , , , , , , npy_half_to_double, , , , , , # + * #func = (PyLong_FromLong, PyLong_FromUnsignedLong)*4, + * PyLong_FromLongLong, PyLong_FromUnsignedLongLong, + * PyLong_FromDouble*3, npy_longdouble_to_PyLong, + * PyLong_FromDouble*2, npy_longdouble_to_PyLong# + */ +static PyObject * +@name@_int(PyObject *obj) +{ + PyObject *long_result; + +#if @cmplx@ + @sign@ @ctype@ x = @to_ctype@(PyArrayScalar_VAL(obj, @Name@).real); +#else + @sign@ @ctype@ x = @to_ctype@(PyArrayScalar_VAL(obj, @Name@)); +#endif + +#if @cmplx@ + if (emit_complexwarning() < 0) { + return NULL; + } +#endif + + long_result = @func@(x); + if (long_result == NULL){ + return NULL; + } + +#ifndef NPY_PY3K + /* Invoke long.__int__ to try to downcast */ + { + PyObject *before_downcast = long_result; + long_result = Py_TYPE(long_result)->tp_as_number->nb_int(long_result); + Py_DECREF(before_downcast); + } +#endif + + return long_result; +} +/**end repeat**/ + +/**begin repeat + * + * #name = (byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble)*2# + * #Name = (Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong, + * Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble)*2# + * #cmplx = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1)*2# + * #to_ctype = (, , , , , , , , , , npy_half_to_double, , , , , , )*2# + * #which = long*17, float*17# + * #func = (PyLong_FromLongLong, PyLong_FromUnsignedLongLong)*5, + * PyLong_FromDouble*3, npy_longdouble_to_PyLong, + * PyLong_FromDouble*2, npy_longdouble_to_PyLong, + * PyFloat_FromDouble*17# + */ +static NPY_INLINE PyObject * +@name@_@which@(PyObject *obj) +{ +#if @cmplx@ + if (emit_complexwarning() < 0) { + return NULL; + } + return @func@(@to_ctype@(PyArrayScalar_VAL(obj, @Name@).real)); +#else + return @func@(@to_ctype@(PyArrayScalar_VAL(obj, @Name@))); +#endif +} +/**end repeat**/ + +#if !defined(NPY_PY3K) + +/**begin repeat + * + * #name = (byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble)*2# + * #oper = oct*17, hex*17# + * #kind = (int*5, long*5, int*2, long*2, int, long*2)*2# + * #cap = (Int*5, Long*5, Int*2, Long*2, Int, Long*2)*2# + */ +static PyObject * +@name@_@oper@(PyObject *obj) +{ + PyObject *pyint; + pyint = @name@_@kind@(obj); + if (pyint == NULL) { + return NULL; + } + return Py@cap@_Type.tp_as_number->nb_@oper@(pyint); +} +/**end repeat**/ + +#endif + +/**begin repeat + * #oper = le, ge, lt, gt, eq, ne# + * #op = <=, >=, <, >, ==, !=# + * #halfop = npy_half_le, npy_half_ge, npy_half_lt, + * npy_half_gt, npy_half_eq, npy_half_ne# + */ +#define def_cmp_@oper@(arg1, arg2) (arg1 @op@ arg2) +#define cmplx_cmp_@oper@(arg1, arg2) ((arg1.real == arg2.real) ? \ + arg1.imag @op@ arg2.imag : \ + arg1.real @op@ arg2.real) +#define def_half_cmp_@oper@(arg1, arg2) @halfop@(arg1, arg2) +/**end repeat**/ + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #simp = def*10, def_half, def*3, cmplx*3# + */ +static PyObject* +@name@_richcompare(PyObject *self, PyObject *other, int cmp_op) +{ + npy_@name@ arg1, arg2; + int out=0; + + RICHCMP_GIVE_UP_IF_NEEDED(self, other); + + switch(_@name@_convert2_to_ctypes(self, &arg1, other, &arg2)) { + case 0: + break; + case -1: + /* can't cast both safely use different add function */ + case -2: + /* use ufunc */ + if (PyErr_Occurred()) { + return NULL; + } + return PyGenericArrType_Type.tp_richcompare(self, other, cmp_op); + case -3: + /* + * special case for longdouble and clongdouble + * because they have a recursive getitem in their dtype + */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + /* here we do the actual calculation with arg1 and arg2 */ + switch (cmp_op) { + case Py_EQ: + out = @simp@_cmp_eq(arg1, arg2); + break; + case Py_NE: + out = @simp@_cmp_ne(arg1, arg2); + break; + case Py_LE: + out = @simp@_cmp_le(arg1, arg2); + break; + case Py_GE: + out = @simp@_cmp_ge(arg1, arg2); + break; + case Py_LT: + out = @simp@_cmp_lt(arg1, arg2); + break; + case Py_GT: + out = @simp@_cmp_gt(arg1, arg2); + break; + } + + if (out) { + PyArrayScalar_RETURN_TRUE; + } + else { + PyArrayScalar_RETURN_FALSE; + } +} +/**end repeat**/ + + +/**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# +**/ +static PyNumberMethods @name@_as_number = { + (binaryfunc)@name@_add, /*nb_add*/ + (binaryfunc)@name@_subtract, /*nb_subtract*/ + (binaryfunc)@name@_multiply, /*nb_multiply*/ +#if defined(NPY_PY3K) +#else + (binaryfunc)@name@_divide, /*nb_divide*/ +#endif + (binaryfunc)@name@_remainder, /*nb_remainder*/ + (binaryfunc)@name@_divmod, /*nb_divmod*/ + (ternaryfunc)@name@_power, /*nb_power*/ + (unaryfunc)@name@_negative, + (unaryfunc)@name@_positive, /*nb_pos*/ + (unaryfunc)@name@_absolute, /*nb_abs*/ +#if defined(NPY_PY3K) + (inquiry)@name@_bool, /*nb_bool*/ +#else + (inquiry)@name@_nonzero, /*nb_nonzero*/ +#endif + (unaryfunc)@name@_invert, /*nb_invert*/ + (binaryfunc)@name@_lshift, /*nb_lshift*/ + (binaryfunc)@name@_rshift, /*nb_rshift*/ + (binaryfunc)@name@_and, /*nb_and*/ + (binaryfunc)@name@_xor, /*nb_xor*/ + (binaryfunc)@name@_or, /*nb_or*/ +#if defined(NPY_PY3K) +#else + 0, /*nb_coerce*/ +#endif + (unaryfunc)@name@_int, /*nb_int*/ +#if defined(NPY_PY3K) + (unaryfunc)0, /*nb_reserved*/ +#else + (unaryfunc)@name@_long, /*nb_long*/ +#endif + (unaryfunc)@name@_float, /*nb_float*/ +#if defined(NPY_PY3K) +#else + (unaryfunc)@name@_oct, /*nb_oct*/ + (unaryfunc)@name@_hex, /*nb_hex*/ +#endif + 0, /*inplace_add*/ + 0, /*inplace_subtract*/ + 0, /*inplace_multiply*/ +#if defined(NPY_PY3K) +#else + 0, /*inplace_divide*/ +#endif + 0, /*inplace_remainder*/ + 0, /*inplace_power*/ + 0, /*inplace_lshift*/ + 0, /*inplace_rshift*/ + 0, /*inplace_and*/ + 0, /*inplace_xor*/ + 0, /*inplace_or*/ + (binaryfunc)@name@_floor_divide, /*nb_floor_divide*/ + (binaryfunc)@name@_true_divide, /*nb_true_divide*/ + 0, /*nb_inplace_floor_divide*/ + 0, /*nb_inplace_true_divide*/ + (unaryfunc)NULL, /*nb_index*/ +}; +/**end repeat**/ + +NPY_NO_EXPORT void +add_scalarmath(void) +{ + /**begin repeat + * #name = byte, ubyte, short, ushort, int, uint, + * long, ulong, longlong, ulonglong, + * half, float, double, longdouble, + * cfloat, cdouble, clongdouble# + * #NAME = Byte, UByte, Short, UShort, Int, UInt, + * Long, ULong, LongLong, ULongLong, + * Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble# + **/ + @name@_as_number.nb_index = Py@NAME@ArrType_Type.tp_as_number->nb_index; + Py@NAME@ArrType_Type.tp_as_number = &(@name@_as_number); + Py@NAME@ArrType_Type.tp_richcompare = @name@_richcompare; + /**end repeat**/ +} + +static int +get_functions(PyObject * mm) +{ + PyObject *obj; + void **funcdata; + char *signatures; + int i, j; + int ret = -1; + + /* Get the nc_pow functions */ + /* Get the pow functions */ + obj = PyObject_GetAttrString(mm, "power"); + if (obj == NULL) { + goto fail; + } + funcdata = ((PyUFuncObject *)obj)->data; + signatures = ((PyUFuncObject *)obj)->types; + + i = 0; + j = 0; + while (signatures[i] != NPY_FLOAT) { + i += 3; + j++; + } + _basic_float_pow = funcdata[j]; + _basic_double_pow = funcdata[j + 1]; + _basic_longdouble_pow = funcdata[j + 2]; + _basic_cfloat_pow = funcdata[j + 3]; + _basic_cdouble_pow = funcdata[j + 4]; + _basic_clongdouble_pow = funcdata[j + 5]; + Py_DECREF(obj); + + /* Get the sqrt functions */ + obj = PyObject_GetAttrString(mm, "sqrt"); + if (obj == NULL) { + goto fail; + } + funcdata = ((PyUFuncObject *)obj)->data; + signatures = ((PyUFuncObject *)obj)->types; + /* + * sqrt ufunc is specialized for double and float loops in + * generate_umath.py, the first to go into FLOAT/DOUBLE_sqrt + * they have the same signature as the scalar variants so we need to skip + * over them + * also skip float16 copy placed before + */ + i = 6; + j = 3; + while (signatures[i] != NPY_FLOAT) { + i += 2; j++; + } + _basic_half_sqrt = funcdata[j - 1]; + _basic_float_sqrt = funcdata[j]; + _basic_double_sqrt = funcdata[j + 1]; + _basic_longdouble_sqrt = funcdata[j + 2]; + Py_DECREF(obj); + + /* Get the fmod functions */ + obj = PyObject_GetAttrString(mm, "fmod"); + if (obj == NULL) { + goto fail; + } + funcdata = ((PyUFuncObject *)obj)->data; + signatures = ((PyUFuncObject *)obj)->types; + i = 0; + j = 0; + while (signatures[i] != NPY_FLOAT) { + i += 3; + j++; + } + _basic_half_fmod = funcdata[j - 1]; + _basic_float_fmod = funcdata[j]; + _basic_double_fmod = funcdata[j + 1]; + _basic_longdouble_fmod = funcdata[j + 2]; + Py_DECREF(obj); + return ret = 0; + + fail: + Py_DECREF(mm); + return ret; +} + + +NPY_NO_EXPORT int initscalarmath(PyObject * m) +{ + if (get_functions(m) < 0) { + return -1; + } + + add_scalarmath(); + + return 0; +} diff --git a/numpy/core/src/umath/simd.inc.src b/numpy/core/src/umath/simd.inc.src new file mode 100644 index 0000000..8a799fe --- /dev/null +++ b/numpy/core/src/umath/simd.inc.src @@ -0,0 +1,1007 @@ +/* -*- c -*- */ + +/* + * This file is for the definitions of simd vectorized operations. + * + * Currently contains sse2 functions that are built on amd64, x32 or + * non-generic builds (CFLAGS=-march=...) + * In future it may contain other instruction sets like AVX or NEON detected + * at runtime in which case it needs to be included indirectly via a file + * compiled with special options (or use gcc target attributes) so the binary + * stays portable. + */ + + +#ifndef __NPY_SIMD_INC +#define __NPY_SIMD_INC + +#include "lowlevel_strided_loops.h" +#include "numpy/npy_common.h" +/* for NO_FLOATING_POINT_SUPPORT */ +#include "numpy/ufuncobject.h" +#include "numpy/npy_math.h" +#ifdef NPY_HAVE_SSE2_INTRINSICS +#include +#endif +#include +#include +#include +#include /* for memcpy */ + +/* Figure out the right abs function for pointer addresses */ +static NPY_INLINE npy_intp +abs_intp(npy_intp x) +{ +#if (NPY_SIZEOF_INTP <= NPY_SIZEOF_INT) + return abs(x); +#elif (NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG) + return labs(x); +#elif defined(_MSC_VER) && (_MSC_VER < 1600) + /* llabs is not available with Visual Studio 2008 */ + return x > 0 ? x : -x; +#else + return llabs(x); +#endif +} + +/* + * stride is equal to element size and input and destination are equal or + * don't overlap within one register + */ +#define IS_BLOCKABLE_UNARY(esize, vsize) \ + (steps[0] == (esize) && steps[0] == steps[1] && \ + (npy_is_aligned(args[0], esize) && npy_is_aligned(args[1], esize)) && \ + ((abs_intp(args[1] - args[0]) >= (vsize)) || \ + ((abs_intp(args[1] - args[0]) == 0)))) + +#define IS_BLOCKABLE_REDUCE(esize, vsize) \ + (steps[1] == (esize) && abs_intp(args[1] - args[0]) >= (vsize) && \ + npy_is_aligned(args[1], (esize)) && \ + npy_is_aligned(args[0], (esize))) + +#define IS_BLOCKABLE_BINARY(esize, vsize) \ + (steps[0] == steps[1] && steps[1] == steps[2] && steps[2] == (esize) && \ + npy_is_aligned(args[2], (esize)) && npy_is_aligned(args[1], (esize)) && \ + npy_is_aligned(args[0], (esize)) && \ + (abs_intp(args[2] - args[0]) >= (vsize) || \ + abs_intp(args[2] - args[0]) == 0) && \ + (abs_intp(args[2] - args[1]) >= (vsize) || \ + abs_intp(args[2] - args[1]) >= 0)) + +#define IS_BLOCKABLE_BINARY_SCALAR1(esize, vsize) \ + (steps[0] == 0 && steps[1] == steps[2] && steps[2] == (esize) && \ + npy_is_aligned(args[2], (esize)) && npy_is_aligned(args[1], (esize)) && \ + ((abs_intp(args[2] - args[1]) >= (vsize)) || \ + (abs_intp(args[2] - args[1]) == 0)) && \ + abs_intp(args[2] - args[0]) >= (esize)) + +#define IS_BLOCKABLE_BINARY_SCALAR2(esize, vsize) \ + (steps[1] == 0 && steps[0] == steps[2] && steps[2] == (esize) && \ + npy_is_aligned(args[2], (esize)) && npy_is_aligned(args[0], (esize)) && \ + ((abs_intp(args[2] - args[0]) >= (vsize)) || \ + (abs_intp(args[2] - args[0]) == 0)) && \ + abs_intp(args[2] - args[1]) >= (esize)) + +#undef abs_intp + +#define IS_BLOCKABLE_BINARY_BOOL(esize, vsize) \ + (steps[0] == (esize) && steps[0] == steps[1] && steps[2] == (1) && \ + npy_is_aligned(args[1], (esize)) && \ + npy_is_aligned(args[0], (esize))) + +#define IS_BLOCKABLE_BINARY_SCALAR1_BOOL(esize, vsize) \ + (steps[0] == 0 && steps[1] == (esize) && steps[2] == (1) && \ + npy_is_aligned(args[1], (esize))) + +#define IS_BLOCKABLE_BINARY_SCALAR2_BOOL(esize, vsize) \ + (steps[0] == (esize) && steps[1] == 0 && steps[2] == (1) && \ + npy_is_aligned(args[0], (esize))) + +/* align var to alignment */ +#define LOOP_BLOCK_ALIGN_VAR(var, type, alignment)\ + npy_intp i, peel = npy_aligned_block_offset(var, sizeof(type),\ + alignment, n);\ + for(i = 0; i < peel; i++) + +#define LOOP_BLOCKED(type, vsize)\ + for(; i < npy_blocked_end(peel, sizeof(type), vsize, n);\ + i += (vsize / sizeof(type))) + +#define LOOP_BLOCKED_END\ + for (; i < n; i++) + + +/* + * Dispatcher functions + * decide whether the operation can be vectorized and run it + * if it was run returns true and false if nothing was done + */ + +/* + ***************************************************************************** + ** FLOAT DISPATCHERS + ***************************************************************************** + */ + +/**begin repeat + * Float types + * #type = npy_float, npy_double, npy_longdouble# + * #TYPE = FLOAT, DOUBLE, LONGDOUBLE# + * #vector = 1, 1, 0# + */ + +/**begin repeat1 + * #func = sqrt, absolute, negative, minimum, maximum# + * #check = IS_BLOCKABLE_UNARY*3, IS_BLOCKABLE_REDUCE*2 # + * #name = unary*3, unary_reduce*2# + * #minmax = 0*3, 1*2# + */ + +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS + +/* prototypes */ +static void +sse2_@func@_@TYPE@(@type@ *, @type@ *, const npy_intp n); + +#endif + +static NPY_INLINE int +run_@name@_simd_@func@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps) +{ +#if @minmax@ && (defined NO_FLOATING_POINT_SUPPORT) + return 0; +#else +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS + if (@check@(sizeof(@type@), 16)) { + sse2_@func@_@TYPE@((@type@*)args[1], (@type@*)args[0], dimensions[0]); + return 1; + } +#endif + return 0; +#endif +} + +/**end repeat1**/ + +/**begin repeat1 + * Arithmetic + * # kind = add, subtract, multiply, divide# + */ + +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS + +/* prototypes */ +static void +sse2_binary_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, + npy_intp n); +static void +sse2_binary_scalar1_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, + npy_intp n); +static void +sse2_binary_scalar2_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, + npy_intp n); + +#endif + +static NPY_INLINE int +run_binary_simd_@kind@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps) +{ +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS + @type@ * ip1 = (@type@ *)args[0]; + @type@ * ip2 = (@type@ *)args[1]; + @type@ * op = (@type@ *)args[2]; + npy_intp n = dimensions[0]; + /* argument one scalar */ + if (IS_BLOCKABLE_BINARY_SCALAR1(sizeof(@type@), 16)) { + sse2_binary_scalar1_@kind@_@TYPE@(op, ip1, ip2, n); + return 1; + } + /* argument two scalar */ + else if (IS_BLOCKABLE_BINARY_SCALAR2(sizeof(@type@), 16)) { + sse2_binary_scalar2_@kind@_@TYPE@(op, ip1, ip2, n); + return 1; + } + else if (IS_BLOCKABLE_BINARY(sizeof(@type@), 16)) { + sse2_binary_@kind@_@TYPE@(op, ip1, ip2, n); + return 1; + } +#endif + return 0; +} + +/**end repeat1**/ + +/**begin repeat1 + * #kind = equal, not_equal, less, less_equal, greater, greater_equal, + * logical_and, logical_or# + * #simd = 1, 1, 1, 1, 1, 1, 0, 0# + */ + +#if @vector@ && @simd@ && defined NPY_HAVE_SSE2_INTRINSICS + +/* prototypes */ +static void +sse2_binary_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, @type@ * ip2, + npy_intp n); +static void +sse2_binary_scalar1_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, @type@ * ip2, + npy_intp n); +static void +sse2_binary_scalar2_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, @type@ * ip2, + npy_intp n); + +#endif + +static NPY_INLINE int +run_binary_simd_@kind@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps) +{ +#if @vector@ && @simd@ && defined NPY_HAVE_SSE2_INTRINSICS + @type@ * ip1 = (@type@ *)args[0]; + @type@ * ip2 = (@type@ *)args[1]; + npy_bool * op = (npy_bool *)args[2]; + npy_intp n = dimensions[0]; + /* argument one scalar */ + if (IS_BLOCKABLE_BINARY_SCALAR1_BOOL(sizeof(@type@), 16)) { + sse2_binary_scalar1_@kind@_@TYPE@(op, ip1, ip2, n); + return 1; + } + /* argument two scalar */ + else if (IS_BLOCKABLE_BINARY_SCALAR2_BOOL(sizeof(@type@), 16)) { + sse2_binary_scalar2_@kind@_@TYPE@(op, ip1, ip2, n); + return 1; + } + else if (IS_BLOCKABLE_BINARY_BOOL(sizeof(@type@), 16)) { + sse2_binary_@kind@_@TYPE@(op, ip1, ip2, n); + return 1; + } +#endif + return 0; +} + +/**end repeat1**/ + +/**begin repeat1 + * #kind = isnan, isfinite, isinf, signbit# + */ + +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS + +static void +sse2_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, npy_intp n); + +#endif + +static NPY_INLINE int +run_@kind@_simd_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps) +{ +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS + if (steps[0] == sizeof(@type@) && steps[1] == 1 && + npy_is_aligned(args[0], sizeof(@type@))) { + sse2_@kind@_@TYPE@((npy_bool*)args[1], (@type@*)args[0], dimensions[0]); + return 1; + } +#endif + return 0; +} + +/**end repeat1**/ + +/**end repeat**/ + +/* + ***************************************************************************** + ** BOOL DISPATCHERS + ***************************************************************************** + */ + +/**begin repeat + * # kind = logical_or, logical_and# + */ + +#if defined NPY_HAVE_SSE2_INTRINSICS +static void +sse2_binary_@kind@_BOOL(npy_bool * op, npy_bool * ip1, npy_bool * ip2, + npy_intp n); + +static void +sse2_reduce_@kind@_BOOL(npy_bool * op, npy_bool * ip, npy_intp n); +#endif + +static NPY_INLINE int +run_binary_simd_@kind@_BOOL(char **args, npy_intp *dimensions, npy_intp *steps) +{ +#if defined NPY_HAVE_SSE2_INTRINSICS + if (sizeof(npy_bool) == 1 && IS_BLOCKABLE_BINARY(sizeof(npy_bool), 16)) { + sse2_binary_@kind@_BOOL((npy_bool*)args[2], (npy_bool*)args[0], + (npy_bool*)args[1], dimensions[0]); + return 1; + } +#endif + return 0; +} + + +static NPY_INLINE int +run_reduce_simd_@kind@_BOOL(char **args, npy_intp *dimensions, npy_intp *steps) +{ +#if defined NPY_HAVE_SSE2_INTRINSICS + if (sizeof(npy_bool) == 1 && IS_BLOCKABLE_REDUCE(sizeof(npy_bool), 16)) { + sse2_reduce_@kind@_BOOL((npy_bool*)args[0], (npy_bool*)args[1], + dimensions[0]); + return 1; + } +#endif + return 0; +} + +/**end repeat**/ + +/**begin repeat + * # kind = absolute, logical_not# + */ + +#if defined NPY_HAVE_SSE2_INTRINSICS +static void +sse2_@kind@_BOOL(npy_bool *, npy_bool *, const npy_intp n); +#endif + +static NPY_INLINE int +run_unary_simd_@kind@_BOOL(char **args, npy_intp *dimensions, npy_intp *steps) +{ +#if defined NPY_HAVE_SSE2_INTRINSICS + if (sizeof(npy_bool) == 1 && IS_BLOCKABLE_UNARY(sizeof(npy_bool), 16)) { + sse2_@kind@_BOOL((npy_bool*)args[1], (npy_bool*)args[0], dimensions[0]); + return 1; + } +#endif + return 0; +} + +/**end repeat**/ + +#ifdef NPY_HAVE_SSE2_INTRINSICS + +/* + * Vectorized operations + */ +/* + ***************************************************************************** + ** FLOAT LOOPS + ***************************************************************************** + */ + +/**begin repeat +* horizontal reductions on a vector +* # VOP = min, max# +*/ + +static NPY_INLINE npy_float sse2_horizontal_@VOP@___m128(__m128 v) +{ + npy_float r; + __m128 tmp = _mm_movehl_ps(v, v); /* c d ... */ + __m128 m = _mm_@VOP@_ps(v, tmp); /* m(ac) m(bd) ... */ + tmp = _mm_shuffle_ps(m, m, _MM_SHUFFLE(1, 1, 1, 1));/* m(bd) m(bd) ... */ + _mm_store_ss(&r, _mm_@VOP@_ps(tmp, m)); /* m(acbd) ... */ + return r; +} + +static NPY_INLINE npy_double sse2_horizontal_@VOP@___m128d(__m128d v) +{ + npy_double r; + __m128d tmp = _mm_unpackhi_pd(v, v); /* b b */ + _mm_store_sd(&r, _mm_@VOP@_pd(tmp, v)); /* m(ab) m(bb) */ + return r; +} + +/**end repeat**/ + +/**begin repeat + * #type = npy_float, npy_double# + * #TYPE = FLOAT, DOUBLE# + * #scalarf = npy_sqrtf, npy_sqrt# + * #c = f, # + * #vtype = __m128, __m128d# + * #vpre = _mm, _mm# + * #vsuf = ps, pd# + * #vsufs = ss, sd# + * #nan = NPY_NANF, NPY_NAN# + * #double = 0, 1# + * #cast = _mm_castps_si128, _mm_castpd_si128# + */ + + +/**begin repeat1 +* Arithmetic +* # kind = add, subtract, multiply, divide# +* # OP = +, -, *, /# +* # VOP = add, sub, mul, div# +*/ + +static void +sse2_binary_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, npy_intp n) +{ + LOOP_BLOCK_ALIGN_VAR(op, @type@, 16) + op[i] = ip1[i] @OP@ ip2[i]; + /* lots of specializations, to squeeze out max performance */ + if (npy_is_aligned(&ip1[i], 16) && npy_is_aligned(&ip2[i], 16)) { + if (ip1 == ip2) { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_load_@vsuf@(&ip1[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, a); + @vpre@_store_@vsuf@(&op[i], c); + } + } + else { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_load_@vsuf@(&ip1[i]); + @vtype@ b = @vpre@_load_@vsuf@(&ip2[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, b); + @vpre@_store_@vsuf@(&op[i], c); + } + } + } + else if (npy_is_aligned(&ip1[i], 16)) { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_load_@vsuf@(&ip1[i]); + @vtype@ b = @vpre@_loadu_@vsuf@(&ip2[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, b); + @vpre@_store_@vsuf@(&op[i], c); + } + } + else if (npy_is_aligned(&ip2[i], 16)) { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_loadu_@vsuf@(&ip1[i]); + @vtype@ b = @vpre@_load_@vsuf@(&ip2[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, b); + @vpre@_store_@vsuf@(&op[i], c); + } + } + else { + if (ip1 == ip2) { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_loadu_@vsuf@(&ip1[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, a); + @vpre@_store_@vsuf@(&op[i], c); + } + } + else { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_loadu_@vsuf@(&ip1[i]); + @vtype@ b = @vpre@_loadu_@vsuf@(&ip2[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, b); + @vpre@_store_@vsuf@(&op[i], c); + } + } + } + LOOP_BLOCKED_END { + op[i] = ip1[i] @OP@ ip2[i]; + } +} + + +static void +sse2_binary_scalar1_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, npy_intp n) +{ + const @vtype@ a = @vpre@_set1_@vsuf@(ip1[0]); + LOOP_BLOCK_ALIGN_VAR(op, @type@, 16) + op[i] = ip1[0] @OP@ ip2[i]; + if (npy_is_aligned(&ip2[i], 16)) { + LOOP_BLOCKED(@type@, 16) { + @vtype@ b = @vpre@_load_@vsuf@(&ip2[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, b); + @vpre@_store_@vsuf@(&op[i], c); + } + } + else { + LOOP_BLOCKED(@type@, 16) { + @vtype@ b = @vpre@_loadu_@vsuf@(&ip2[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, b); + @vpre@_store_@vsuf@(&op[i], c); + } + } + LOOP_BLOCKED_END { + op[i] = ip1[0] @OP@ ip2[i]; + } +} + + +static void +sse2_binary_scalar2_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, npy_intp n) +{ + const @vtype@ b = @vpre@_set1_@vsuf@(ip2[0]); + LOOP_BLOCK_ALIGN_VAR(op, @type@, 16) + op[i] = ip1[i] @OP@ ip2[0]; + if (npy_is_aligned(&ip1[i], 16)) { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_load_@vsuf@(&ip1[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, b); + @vpre@_store_@vsuf@(&op[i], c); + } + } + else { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_loadu_@vsuf@(&ip1[i]); + @vtype@ c = @vpre@_@VOP@_@vsuf@(a, b); + @vpre@_store_@vsuf@(&op[i], c); + } + } + LOOP_BLOCKED_END { + op[i] = ip1[i] @OP@ ip2[0]; + } +} + +/**end repeat1**/ + +/* + * compress 4 vectors to 4/8 bytes in op with filled with 0 or 1 + * the last vector is passed as a pointer as MSVC 2010 is unable to ignore the + * calling convention leading to C2719 on 32 bit, see #4795 + */ +static NPY_INLINE void +sse2_compress4_to_byte_@TYPE@(@vtype@ r1, @vtype@ r2, @vtype@ r3, @vtype@ * r4, + npy_bool * op) +{ + const __m128i mask = @vpre@_set1_epi8(0x1); + __m128i ir1 = @vpre@_packs_epi32(@cast@(r1), @cast@(r2)); + __m128i ir2 = @vpre@_packs_epi32(@cast@(r3), @cast@(*r4)); + __m128i rr = @vpre@_packs_epi16(ir1, ir2); +#if @double@ + rr = @vpre@_packs_epi16(rr, rr); + rr = @vpre@_and_si128(rr, mask); + @vpre@_storel_epi64((__m128i*)op, rr); +#else + rr = @vpre@_and_si128(rr, mask); + @vpre@_storeu_si128((__m128i*)op, rr); +#endif +} + +static void +sse2_signbit_@TYPE@(npy_bool * op, @type@ * ip1, npy_intp n) +{ + LOOP_BLOCK_ALIGN_VAR(ip1, @type@, 16) { + op[i] = npy_signbit(ip1[i]) != 0; + } + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_load_@vsuf@(&ip1[i]); + int r = @vpre@_movemask_@vsuf@(a); + if (sizeof(@type@) == 8) { + op[i] = r & 1; + op[i + 1] = (r >> 1); + } + else { + op[i] = r & 1; + op[i + 1] = (r >> 1) & 1; + op[i + 2] = (r >> 2) & 1; + op[i + 3] = (r >> 3); + } + } + LOOP_BLOCKED_END { + op[i] = npy_signbit(ip1[i]) != 0; + } +} + +/**begin repeat1 + * #kind = isnan, isfinite, isinf# + * #var = 0, 1, 2# + */ + +static void +sse2_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, npy_intp n) +{ +#if @var@ != 0 /* isinf/isfinite */ + /* signbit mask 0x7FFFFFFF after andnot */ + const @vtype@ mask = @vpre@_set1_@vsuf@(-0.@c@); + const @vtype@ ones = @vpre@_cmpeq_@vsuf@(@vpre@_setzero_@vsuf@(), + @vpre@_setzero_@vsuf@()); +#if @double@ + const @vtype@ fltmax = @vpre@_set1_@vsuf@(DBL_MAX); +#else + const @vtype@ fltmax = @vpre@_set1_@vsuf@(FLT_MAX); +#endif +#endif + LOOP_BLOCK_ALIGN_VAR(ip1, @type@, 16) { + op[i] = npy_@kind@(ip1[i]) != 0; + } + LOOP_BLOCKED(@type@, 64) { + @vtype@ a = @vpre@_load_@vsuf@(&ip1[i + 0 * 16 / sizeof(@type@)]); + @vtype@ b = @vpre@_load_@vsuf@(&ip1[i + 1 * 16 / sizeof(@type@)]); + @vtype@ c = @vpre@_load_@vsuf@(&ip1[i + 2 * 16 / sizeof(@type@)]); + @vtype@ d = @vpre@_load_@vsuf@(&ip1[i + 3 * 16 / sizeof(@type@)]); + @vtype@ r1, r2, r3, r4; +#if @var@ != 0 /* isinf/isfinite */ + /* fabs via masking of sign bit */ + r1 = @vpre@_andnot_@vsuf@(mask, a); + r2 = @vpre@_andnot_@vsuf@(mask, b); + r3 = @vpre@_andnot_@vsuf@(mask, c); + r4 = @vpre@_andnot_@vsuf@(mask, d); +#if @var@ == 1 /* isfinite */ + /* negative compare against max float, nan is always true */ + r1 = @vpre@_cmpnle_@vsuf@(r1, fltmax); + r2 = @vpre@_cmpnle_@vsuf@(r2, fltmax); + r3 = @vpre@_cmpnle_@vsuf@(r3, fltmax); + r4 = @vpre@_cmpnle_@vsuf@(r4, fltmax); +#else /* isinf */ + r1 = @vpre@_cmpnlt_@vsuf@(fltmax, r1); + r2 = @vpre@_cmpnlt_@vsuf@(fltmax, r2); + r3 = @vpre@_cmpnlt_@vsuf@(fltmax, r3); + r4 = @vpre@_cmpnlt_@vsuf@(fltmax, r4); +#endif + /* flip results to what we want (andnot as there is no sse not) */ + r1 = @vpre@_andnot_@vsuf@(r1, ones); + r2 = @vpre@_andnot_@vsuf@(r2, ones); + r3 = @vpre@_andnot_@vsuf@(r3, ones); + r4 = @vpre@_andnot_@vsuf@(r4, ones); +#endif +#if @var@ == 0 /* isnan */ + r1 = @vpre@_cmpneq_@vsuf@(a, a); + r2 = @vpre@_cmpneq_@vsuf@(b, b); + r3 = @vpre@_cmpneq_@vsuf@(c, c); + r4 = @vpre@_cmpneq_@vsuf@(d, d); +#endif + sse2_compress4_to_byte_@TYPE@(r1, r2, r3, &r4, &op[i]); + } + LOOP_BLOCKED_END { + op[i] = npy_@kind@(ip1[i]) != 0; + } +} + +/**end repeat1**/ + +/**begin repeat1 + * #kind = equal, not_equal, less, less_equal, greater, greater_equal# + * #OP = ==, !=, <, <=, >, >=# + * #VOP = cmpeq, cmpneq, cmplt, cmple, cmpgt, cmpge# +*/ + +/* sets invalid fpu flag on QNaN for consistency with packed compare */ +static NPY_INLINE int +sse2_ordered_cmp_@kind@_@TYPE@(const @type@ a, const @type@ b) +{ + @vtype@ one = @vpre@_set1_@vsuf@(1); + @type@ tmp; + @vtype@ v = @vpre@_@VOP@_@vsufs@(@vpre@_load_@vsufs@(&a), + @vpre@_load_@vsufs@(&b)); + v = @vpre@_and_@vsuf@(v, one); + @vpre@_store_@vsufs@(&tmp, v); + return tmp; +} + +static void +sse2_binary_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, @type@ * ip2, npy_intp n) +{ + LOOP_BLOCK_ALIGN_VAR(ip1, @type@, 16) { + op[i] = sse2_ordered_cmp_@kind@_@TYPE@(ip1[i], ip2[i]); + } + LOOP_BLOCKED(@type@, 64) { + @vtype@ a1 = @vpre@_load_@vsuf@(&ip1[i + 0 * 16 / sizeof(@type@)]); + @vtype@ b1 = @vpre@_load_@vsuf@(&ip1[i + 1 * 16 / sizeof(@type@)]); + @vtype@ c1 = @vpre@_load_@vsuf@(&ip1[i + 2 * 16 / sizeof(@type@)]); + @vtype@ d1 = @vpre@_load_@vsuf@(&ip1[i + 3 * 16 / sizeof(@type@)]); + @vtype@ a2 = @vpre@_loadu_@vsuf@(&ip2[i + 0 * 16 / sizeof(@type@)]); + @vtype@ b2 = @vpre@_loadu_@vsuf@(&ip2[i + 1 * 16 / sizeof(@type@)]); + @vtype@ c2 = @vpre@_loadu_@vsuf@(&ip2[i + 2 * 16 / sizeof(@type@)]); + @vtype@ d2 = @vpre@_loadu_@vsuf@(&ip2[i + 3 * 16 / sizeof(@type@)]); + @vtype@ r1 = @vpre@_@VOP@_@vsuf@(a1, a2); + @vtype@ r2 = @vpre@_@VOP@_@vsuf@(b1, b2); + @vtype@ r3 = @vpre@_@VOP@_@vsuf@(c1, c2); + @vtype@ r4 = @vpre@_@VOP@_@vsuf@(d1, d2); + sse2_compress4_to_byte_@TYPE@(r1, r2, r3, &r4, &op[i]); + } + LOOP_BLOCKED_END { + op[i] = sse2_ordered_cmp_@kind@_@TYPE@(ip1[i], ip2[i]); + } +} + + +static void +sse2_binary_scalar1_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, @type@ * ip2, npy_intp n) +{ + @vtype@ s = @vpre@_set1_@vsuf@(ip1[0]); + LOOP_BLOCK_ALIGN_VAR(ip2, @type@, 16) { + op[i] = sse2_ordered_cmp_@kind@_@TYPE@(ip1[0], ip2[i]); + } + LOOP_BLOCKED(@type@, 64) { + @vtype@ a = @vpre@_load_@vsuf@(&ip2[i + 0 * 16 / sizeof(@type@)]); + @vtype@ b = @vpre@_load_@vsuf@(&ip2[i + 1 * 16 / sizeof(@type@)]); + @vtype@ c = @vpre@_load_@vsuf@(&ip2[i + 2 * 16 / sizeof(@type@)]); + @vtype@ d = @vpre@_load_@vsuf@(&ip2[i + 3 * 16 / sizeof(@type@)]); + @vtype@ r1 = @vpre@_@VOP@_@vsuf@(s, a); + @vtype@ r2 = @vpre@_@VOP@_@vsuf@(s, b); + @vtype@ r3 = @vpre@_@VOP@_@vsuf@(s, c); + @vtype@ r4 = @vpre@_@VOP@_@vsuf@(s, d); + sse2_compress4_to_byte_@TYPE@(r1, r2, r3, &r4, &op[i]); + } + LOOP_BLOCKED_END { + op[i] = sse2_ordered_cmp_@kind@_@TYPE@(ip1[0], ip2[i]); + } +} + + +static void +sse2_binary_scalar2_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, @type@ * ip2, npy_intp n) +{ + @vtype@ s = @vpre@_set1_@vsuf@(ip2[0]); + LOOP_BLOCK_ALIGN_VAR(ip1, @type@, 16) { + op[i] = sse2_ordered_cmp_@kind@_@TYPE@(ip1[i], ip2[0]); + } + LOOP_BLOCKED(@type@, 64) { + @vtype@ a = @vpre@_load_@vsuf@(&ip1[i + 0 * 16 / sizeof(@type@)]); + @vtype@ b = @vpre@_load_@vsuf@(&ip1[i + 1 * 16 / sizeof(@type@)]); + @vtype@ c = @vpre@_load_@vsuf@(&ip1[i + 2 * 16 / sizeof(@type@)]); + @vtype@ d = @vpre@_load_@vsuf@(&ip1[i + 3 * 16 / sizeof(@type@)]); + @vtype@ r1 = @vpre@_@VOP@_@vsuf@(a, s); + @vtype@ r2 = @vpre@_@VOP@_@vsuf@(b, s); + @vtype@ r3 = @vpre@_@VOP@_@vsuf@(c, s); + @vtype@ r4 = @vpre@_@VOP@_@vsuf@(d, s); + sse2_compress4_to_byte_@TYPE@(r1, r2, r3, &r4, &op[i]); + } + LOOP_BLOCKED_END { + op[i] = sse2_ordered_cmp_@kind@_@TYPE@(ip1[i], ip2[0]); + } +} +/**end repeat1**/ + +static void +sse2_sqrt_@TYPE@(@type@ * op, @type@ * ip, const npy_intp n) +{ + /* align output to 16 bytes */ + LOOP_BLOCK_ALIGN_VAR(op, @type@, 16) { + op[i] = @scalarf@(ip[i]); + } + assert(n < (16 / sizeof(@type@)) || npy_is_aligned(&op[i], 16)); + if (npy_is_aligned(&ip[i], 16)) { + LOOP_BLOCKED(@type@, 16) { + @vtype@ d = @vpre@_load_@vsuf@(&ip[i]); + @vpre@_store_@vsuf@(&op[i], @vpre@_sqrt_@vsuf@(d)); + } + } + else { + LOOP_BLOCKED(@type@, 16) { + @vtype@ d = @vpre@_loadu_@vsuf@(&ip[i]); + @vpre@_store_@vsuf@(&op[i], @vpre@_sqrt_@vsuf@(d)); + } + } + LOOP_BLOCKED_END { + op[i] = @scalarf@(ip[i]); + } +} + + +static NPY_INLINE +@type@ scalar_abs_@type@(@type@ v) +{ + /* add 0 to clear -0.0 */ + return (v > 0 ? v: -v) + 0; +} + +static NPY_INLINE +@type@ scalar_neg_@type@(@type@ v) +{ + return -v; +} + +/**begin repeat1 + * #kind = absolute, negative# + * #VOP = andnot, xor# + * #scalar = scalar_abs, scalar_neg# + **/ +static void +sse2_@kind@_@TYPE@(@type@ * op, @type@ * ip, const npy_intp n) +{ + /* + * get 0x7FFFFFFF mask (everything but signbit set) + * float & ~mask will remove the sign, float ^ mask flips the sign + * this is equivalent to how the compiler implements fabs on amd64 + */ + const @vtype@ mask = @vpre@_set1_@vsuf@(-0.@c@); + + /* align output to 16 bytes */ + LOOP_BLOCK_ALIGN_VAR(op, @type@, 16) { + op[i] = @scalar@_@type@(ip[i]); + } + assert(n < (16 / sizeof(@type@)) || npy_is_aligned(&op[i], 16)); + if (npy_is_aligned(&ip[i], 16)) { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_load_@vsuf@(&ip[i]); + @vpre@_store_@vsuf@(&op[i], @vpre@_@VOP@_@vsuf@(mask, a)); + } + } + else { + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vpre@_loadu_@vsuf@(&ip[i]); + @vpre@_store_@vsuf@(&op[i], @vpre@_@VOP@_@vsuf@(mask, a)); + } + } + LOOP_BLOCKED_END { + op[i] = @scalar@_@type@(ip[i]); + } +} +/**end repeat1**/ + + +/**begin repeat1 + * #kind = maximum, minimum# + * #VOP = max, min# + * #OP = >=, <=# + **/ +/* arguments swapped as unary reduce has the swapped compared to unary */ +static void +sse2_@kind@_@TYPE@(@type@ * ip, @type@ * op, const npy_intp n) +{ + const size_t stride = 16 / sizeof(@type@); + LOOP_BLOCK_ALIGN_VAR(ip, @type@, 16) { + *op = (*op @OP@ ip[i] || npy_isnan(*op)) ? *op : ip[i]; + } + assert(n < (stride) || npy_is_aligned(&ip[i], 16)); + if (i + 3 * stride <= n) { + /* load the first elements */ + @vtype@ c1 = @vpre@_load_@vsuf@((@type@*)&ip[i]); + @vtype@ c2 = @vpre@_load_@vsuf@((@type@*)&ip[i + stride]); + i += 2 * stride; + + /* minps/minpd will set invalid flag if nan is encountered */ + npy_clear_floatstatus(); + LOOP_BLOCKED(@type@, 32) { + @vtype@ v1 = @vpre@_load_@vsuf@((@type@*)&ip[i]); + @vtype@ v2 = @vpre@_load_@vsuf@((@type@*)&ip[i + stride]); + c1 = @vpre@_@VOP@_@vsuf@(c1, v1); + c2 = @vpre@_@VOP@_@vsuf@(c2, v2); + } + c1 = @vpre@_@VOP@_@vsuf@(c1, c2); + + if (npy_get_floatstatus() & NPY_FPE_INVALID) { + *op = @nan@; + } + else { + @type@ tmp = sse2_horizontal_@VOP@_@vtype@(c1); + *op = (*op @OP@ tmp || npy_isnan(*op)) ? *op : tmp; + } + } + LOOP_BLOCKED_END { + *op = (*op @OP@ ip[i] || npy_isnan(*op)) ? *op : ip[i]; + } +} +/**end repeat1**/ + +/**end repeat**/ + +/* + ***************************************************************************** + ** BOOL LOOPS + ***************************************************************************** + */ + +/**begin repeat + * # kind = logical_or, logical_and# + * # and = 0, 1# + * # op = ||, &&# + * # sc = !=, ==# + * # vpre = _mm*2# + * # vsuf = si128*2# + * # vtype = __m128i*2# + * # type = npy_bool*2# + * # vload = _mm_load_si128*2# + * # vloadu = _mm_loadu_si128*2# + * # vstore = _mm_store_si128*2# + */ + +/* + * convert any bit set to boolean true so vectorized and normal operations are + * consistent, should not be required if bool is used correctly everywhere but + * you never know + */ +#if !@and@ +static NPY_INLINE @vtype@ byte_to_true(@vtype@ v) +{ + const @vtype@ zero = @vpre@_setzero_@vsuf@(); + const @vtype@ truemask = @vpre@_set1_epi8(1 == 1); + /* get 0xFF for zeros */ + @vtype@ tmp = @vpre@_cmpeq_epi8(v, zero); + /* filled with 0xFF/0x00, negate and mask to boolean true */ + return @vpre@_andnot_@vsuf@(tmp, truemask); +} +#endif + +static void +sse2_binary_@kind@_BOOL(npy_bool * op, npy_bool * ip1, npy_bool * ip2, npy_intp n) +{ + LOOP_BLOCK_ALIGN_VAR(op, @type@, 16) + op[i] = ip1[i] @op@ ip2[i]; + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vloadu@((@vtype@*)&ip1[i]); + @vtype@ b = @vloadu@((@vtype@*)&ip2[i]); +#if @and@ + const @vtype@ zero = @vpre@_setzero_@vsuf@(); + /* get 0xFF for non zeros*/ + @vtype@ tmp = @vpre@_cmpeq_epi8(a, zero); + /* andnot -> 0x00 for zeros xFF for non zeros, & with ip2 */ + tmp = @vpre@_andnot_@vsuf@(tmp, b); +#else + @vtype@ tmp = @vpre@_or_@vsuf@(a, b); +#endif + + @vstore@((@vtype@*)&op[i], byte_to_true(tmp)); + } + LOOP_BLOCKED_END { + op[i] = (ip1[i] @op@ ip2[i]); + } +} + + +static void +sse2_reduce_@kind@_BOOL(npy_bool * op, npy_bool * ip, const npy_intp n) +{ + const @vtype@ zero = @vpre@_setzero_@vsuf@(); + LOOP_BLOCK_ALIGN_VAR(ip, npy_bool, 16) { + *op = *op @op@ ip[i]; + if (*op @sc@ 0) { + return; + } + } + /* unrolled once to replace a slow movmsk with a fast pmaxb */ + LOOP_BLOCKED(npy_bool, 32) { + @vtype@ v = @vload@((@vtype@*)&ip[i]); + @vtype@ v2 = @vload@((@vtype@*)&ip[i + 16]); + v = @vpre@_cmpeq_epi8(v, zero); + v2 = @vpre@_cmpeq_epi8(v2, zero); +#if @and@ + if ((@vpre@_movemask_epi8(@vpre@_max_epu8(v, v2)) != 0)) { + *op = 0; +#else + if ((@vpre@_movemask_epi8(@vpre@_min_epu8(v, v2)) != 0xFFFF)) { + *op = 1; +#endif + return; + } + } + LOOP_BLOCKED_END { + *op = *op @op@ ip[i]; + if (*op @sc@ 0) { + return; + } + } +} + +/**end repeat**/ + +/**begin repeat + * # kind = absolute, logical_not# + * # op = !=, ==# + * # not = 0, 1# + * # vpre = _mm*2# + * # vsuf = si128*2# + * # vtype = __m128i*2# + * # type = npy_bool*2# + * # vloadu = _mm_loadu_si128*2# + * # vstore = _mm_store_si128*2# + */ + +static void +sse2_@kind@_BOOL(@type@ * op, @type@ * ip, const npy_intp n) +{ + LOOP_BLOCK_ALIGN_VAR(op, @type@, 16) + op[i] = (ip[i] @op@ 0); + LOOP_BLOCKED(@type@, 16) { + @vtype@ a = @vloadu@((@vtype@*)&ip[i]); +#if @not@ + const @vtype@ zero = @vpre@_setzero_@vsuf@(); + const @vtype@ truemask = @vpre@_set1_epi8(1 == 1); + /* equivalent to byte_to_true but can skip the negation */ + a = @vpre@_cmpeq_epi8(a, zero); + a = @vpre@_and_@vsuf@(a, truemask); +#else + /* abs is kind of pointless but maybe its used for byte_to_true */ + a = byte_to_true(a); +#endif + @vstore@((@vtype@*)&op[i], a); + } + LOOP_BLOCKED_END { + op[i] = (ip[i] @op@ 0); + } +} + +/**end repeat**/ + +#endif /* NPY_HAVE_SSE2_INTRINSICS */ + +#endif diff --git a/numpy/core/src/umath/struct_ufunc_test.c.src b/numpy/core/src/umath/struct_ufunc_test.c.src new file mode 100644 index 0000000..9a6318f --- /dev/null +++ b/numpy/core/src/umath/struct_ufunc_test.c.src @@ -0,0 +1,124 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" +#include "math.h" +#include "numpy/ndarraytypes.h" +#include "numpy/ufuncobject.h" +#include "numpy/npy_3kcompat.h" + + +/* + * struct_ufunc_test.c + * This is the C code for creating your own + * NumPy ufunc for a structured array dtype. + * + * Details explaining the Python-C API can be found under + * 'Extending and Embedding' and 'Python/C API' at + * docs.python.org . + */ + +static PyMethodDef StructUfuncTestMethods[] = { + {NULL, NULL, 0, NULL} +}; + +/* The loop definition must precede the PyMODINIT_FUNC. */ + +static void add_uint64_triplet(char **args, npy_intp *dimensions, + npy_intp* steps, void* data) +{ + npy_intp i; + npy_intp is1=steps[0]; + npy_intp is2=steps[1]; + npy_intp os=steps[2]; + npy_intp n=dimensions[0]; + npy_uint64 *x, *y, *z; + + char *i1=args[0]; + char *i2=args[1]; + char *op=args[2]; + + for (i = 0; i < n; i++) { + + x = (npy_uint64*)i1; + y = (npy_uint64*)i2; + z = (npy_uint64*)op; + + z[0] = x[0] + y[0]; + z[1] = x[1] + y[1]; + z[2] = x[2] + y[2]; + + i1 += is1; + i2 += is2; + op += os; + } +} + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "struct_ufunc_test", + NULL, + -1, + StructUfuncTestMethods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#if defined(NPY_PY3K) +PyMODINIT_FUNC PyInit_struct_ufunc_test(void) +#else +PyMODINIT_FUNC initstruct_ufunc_test(void) +#endif +{ + PyObject *m, *add_triplet, *d; + PyObject *dtype_dict; + PyArray_Descr *dtype; + PyArray_Descr *dtypes[3]; + +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("struct_ufunc_test", StructUfuncTestMethods); +#endif + + if (m == NULL) { +#if defined(NPY_PY3K) + return NULL; +#else + return; +#endif + } + + import_array(); + import_umath(); + + add_triplet = PyUFunc_FromFuncAndData(NULL, NULL, NULL, 0, 2, 1, + PyUFunc_None, "add_triplet", + "add_triplet_docstring", 0); + + dtype_dict = Py_BuildValue("[(s, s), (s, s), (s, s)]", + "f0", "u8", "f1", "u8", "f2", "u8"); + PyArray_DescrConverter(dtype_dict, &dtype); + Py_DECREF(dtype_dict); + + dtypes[0] = dtype; + dtypes[1] = dtype; + dtypes[2] = dtype; + + PyUFunc_RegisterLoopForDescr((PyUFuncObject *)add_triplet, + dtype, + &add_uint64_triplet, + dtypes, + NULL); + + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "add_triplet", add_triplet); + Py_DECREF(add_triplet); +#if defined(NPY_PY3K) + return m; +#endif +} diff --git a/numpy/core/src/umath/test_rational.c.src b/numpy/core/src/umath/test_rational.c.src new file mode 100644 index 0000000..26c3d37 --- /dev/null +++ b/numpy/core/src/umath/test_rational.c.src @@ -0,0 +1,1407 @@ +/* Fixed size rational numbers exposed to Python */ + +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include +#include +#include +#include +#include +#include + +#include "common.h" /* for error_converting */ + + +/* Relevant arithmetic exceptions */ + +/* Uncomment the following line to work around a bug in numpy */ +/* #define ACQUIRE_GIL */ + +static void +set_overflow(void) { +#ifdef ACQUIRE_GIL + /* Need to grab the GIL to dodge a bug in numpy */ + PyGILState_STATE state = PyGILState_Ensure(); +#endif + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_OverflowError, + "overflow in rational arithmetic"); + } +#ifdef ACQUIRE_GIL + PyGILState_Release(state); +#endif +} + +static void +set_zero_divide(void) { +#ifdef ACQUIRE_GIL + /* Need to grab the GIL to dodge a bug in numpy */ + PyGILState_STATE state = PyGILState_Ensure(); +#endif + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ZeroDivisionError, + "zero divide in rational arithmetic"); + } +#ifdef ACQUIRE_GIL + PyGILState_Release(state); +#endif +} + +/* Integer arithmetic utilities */ + +static NPY_INLINE npy_int32 +safe_neg(npy_int32 x) { + if (x==(npy_int32)1<<31) { + set_overflow(); + } + return -x; +} + +static NPY_INLINE npy_int32 +safe_abs32(npy_int32 x) { + npy_int32 nx; + if (x>=0) { + return x; + } + nx = -x; + if (nx<0) { + set_overflow(); + } + return nx; +} + +static NPY_INLINE npy_int64 +safe_abs64(npy_int64 x) { + npy_int64 nx; + if (x>=0) { + return x; + } + nx = -x; + if (nx<0) { + set_overflow(); + } + return nx; +} + +static NPY_INLINE npy_int64 +gcd(npy_int64 x, npy_int64 y) { + x = safe_abs64(x); + y = safe_abs64(y); + if (x < y) { + npy_int64 t = x; + x = y; + y = t; + } + while (y) { + npy_int64 t; + x = x%y; + t = x; + x = y; + y = t; + } + return x; +} + +static NPY_INLINE npy_int64 +lcm(npy_int64 x, npy_int64 y) { + npy_int64 lcm; + if (!x || !y) { + return 0; + } + x /= gcd(x,y); + lcm = x*y; + if (lcm/y!=x) { + set_overflow(); + } + return safe_abs64(lcm); +} + +/* Fixed precision rational numbers */ + +typedef struct { + /* numerator */ + npy_int32 n; + /* + * denominator minus one: numpy.zeros() uses memset(0) for non-object + * types, so need to ensure that rational(0) has all zero bytes + */ + npy_int32 dmm; +} rational; + +static NPY_INLINE rational +make_rational_int(npy_int64 n) { + rational r = {(npy_int32)n,0}; + if (r.n != n) { + set_overflow(); + } + return r; +} + +static rational +make_rational_slow(npy_int64 n_, npy_int64 d_) { + rational r = {0}; + if (!d_) { + set_zero_divide(); + } + else { + npy_int64 g = gcd(n_,d_); + npy_int32 d; + n_ /= g; + d_ /= g; + r.n = (npy_int32)n_; + d = (npy_int32)d_; + if (r.n!=n_ || d!=d_) { + set_overflow(); + } + else { + if (d <= 0) { + d = -d; + r.n = safe_neg(r.n); + } + r.dmm = d-1; + } + } + return r; +} + +static NPY_INLINE npy_int32 +d(rational r) { + return r.dmm+1; +} + +/* Assumes d_ > 0 */ +static rational +make_rational_fast(npy_int64 n_, npy_int64 d_) { + npy_int64 g = gcd(n_,d_); + rational r; + n_ /= g; + d_ /= g; + r.n = (npy_int32)n_; + r.dmm = (npy_int32)(d_-1); + if (r.n!=n_ || r.dmm+1!=d_) { + set_overflow(); + } + return r; +} + +static NPY_INLINE rational +rational_negative(rational r) { + rational x; + x.n = safe_neg(r.n); + x.dmm = r.dmm; + return x; +} + +static NPY_INLINE rational +rational_add(rational x, rational y) { + /* + * Note that the numerator computation can never overflow int128_t, + * since each term is strictly under 2**128/4 (since d > 0). + */ + return make_rational_fast((npy_int64)x.n*d(y)+(npy_int64)d(x)*y.n, + (npy_int64)d(x)*d(y)); +} + +static NPY_INLINE rational +rational_subtract(rational x, rational y) { + /* We're safe from overflow as with + */ + return make_rational_fast((npy_int64)x.n*d(y)-(npy_int64)d(x)*y.n, + (npy_int64)d(x)*d(y)); +} + +static NPY_INLINE rational +rational_multiply(rational x, rational y) { + /* We're safe from overflow as with + */ + return make_rational_fast((npy_int64)x.n*y.n,(npy_int64)d(x)*d(y)); +} + +static NPY_INLINE rational +rational_divide(rational x, rational y) { + return make_rational_slow((npy_int64)x.n*d(y),(npy_int64)d(x)*y.n); +} + +static NPY_INLINE npy_int64 +rational_floor(rational x) { + /* Always round down */ + if (x.n>=0) { + return x.n/d(x); + } + /* + * This can be done without casting up to 64 bits, but it requires + * working out all the sign cases + */ + return -((-(npy_int64)x.n+d(x)-1)/d(x)); +} + +static NPY_INLINE npy_int64 +rational_ceil(rational x) { + return -rational_floor(rational_negative(x)); +} + +static NPY_INLINE rational +rational_remainder(rational x, rational y) { + return rational_subtract(x, rational_multiply(y,make_rational_int( + rational_floor(rational_divide(x,y))))); +} + +static NPY_INLINE rational +rational_abs(rational x) { + rational y; + y.n = safe_abs32(x.n); + y.dmm = x.dmm; + return y; +} + +static NPY_INLINE npy_int64 +rational_rint(rational x) { + /* + * Round towards nearest integer, moving exact half integers towards + * zero + */ + npy_int32 d_ = d(x); + return (2*(npy_int64)x.n+(x.n<0?-d_:d_))/(2*(npy_int64)d_); +} + +static NPY_INLINE int +rational_sign(rational x) { + return x.n<0?-1:x.n==0?0:1; +} + +static NPY_INLINE rational +rational_inverse(rational x) { + rational y = {0}; + if (!x.n) { + set_zero_divide(); + } + else { + npy_int32 d_; + y.n = d(x); + d_ = x.n; + if (d_ <= 0) { + d_ = safe_neg(d_); + y.n = -y.n; + } + y.dmm = d_-1; + } + return y; +} + +static NPY_INLINE int +rational_eq(rational x, rational y) { + /* + * Since we enforce d > 0, and store fractions in reduced form, + * equality is easy. + */ + return x.n==y.n && x.dmm==y.dmm; +} + +static NPY_INLINE int +rational_ne(rational x, rational y) { + return !rational_eq(x,y); +} + +static NPY_INLINE int +rational_lt(rational x, rational y) { + return (npy_int64)x.n*d(y) < (npy_int64)y.n*d(x); +} + +static NPY_INLINE int +rational_gt(rational x, rational y) { + return rational_lt(y,x); +} + +static NPY_INLINE int +rational_le(rational x, rational y) { + return !rational_lt(y,x); +} + +static NPY_INLINE int +rational_ge(rational x, rational y) { + return !rational_lt(x,y); +} + +static NPY_INLINE npy_int32 +rational_int(rational x) { + return x.n/d(x); +} + +static NPY_INLINE double +rational_double(rational x) { + return (double)x.n/d(x); +} + +static NPY_INLINE int +rational_nonzero(rational x) { + return x.n!=0; +} + +static int +scan_rational(const char** s, rational* x) { + long n,d; + int offset; + const char* ss; + if (sscanf(*s,"%ld%n",&n,&offset)<=0) { + return 0; + } + ss = *s+offset; + if (*ss!='/') { + *s = ss; + *x = make_rational_int(n); + return 1; + } + ss++; + if (sscanf(ss,"%ld%n",&d,&offset)<=0 || d<=0) { + return 0; + } + *s = ss+offset; + *x = make_rational_slow(n,d); + return 1; +} + +/* Expose rational to Python as a numpy scalar */ + +typedef struct { + PyObject_HEAD + rational r; +} PyRational; + +static PyTypeObject PyRational_Type; + +static NPY_INLINE int +PyRational_Check(PyObject* object) { + return PyObject_IsInstance(object,(PyObject*)&PyRational_Type); +} + +static PyObject* +PyRational_FromRational(rational x) { + PyRational* p = (PyRational*)PyRational_Type.tp_alloc(&PyRational_Type,0); + if (p) { + p->r = x; + } + return (PyObject*)p; +} + +static PyObject* +pyrational_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { + Py_ssize_t size; + PyObject* x[2]; + long n[2]={0,1}; + int i; + rational r; + if (kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, + "constructor takes no keyword arguments"); + return 0; + } + size = PyTuple_GET_SIZE(args); + if (size>2) { + PyErr_SetString(PyExc_TypeError, + "expected rational or numerator and optional denominator"); + return 0; + } + x[0] = PyTuple_GET_ITEM(args,0); + x[1] = PyTuple_GET_ITEM(args,1); + if (size==1) { + if (PyRational_Check(x[0])) { + Py_INCREF(x[0]); + return x[0]; + } + else if (PyString_Check(x[0])) { + const char* s = PyString_AS_STRING(x[0]); + rational x; + if (scan_rational(&s,&x)) { + const char* p; + for (p = s; *p; p++) { + if (!isspace(*p)) { + goto bad; + } + } + return PyRational_FromRational(x); + } + bad: + PyErr_Format(PyExc_ValueError, + "invalid rational literal '%s'",s); + return 0; + } + } + for (i=0;iob_type->tp_name); + } + return 0; + } + /* Check that we had an exact integer */ + y = PyInt_FromLong(n[i]); + if (!y) { + return 0; + } + eq = PyObject_RichCompareBool(x[i],y,Py_EQ); + Py_DECREF(y); + if (eq<0) { + return 0; + } + if (!eq) { + PyErr_Format(PyExc_TypeError, + "expected integer %s, got %s", + (i ? "denominator" : "numerator"), + x[i]->ob_type->tp_name); + return 0; + } + } + r = make_rational_slow(n[0],n[1]); + if (PyErr_Occurred()) { + return 0; + } + return PyRational_FromRational(r); +} + +/* + * Returns Py_NotImplemented on most conversion failures, or raises an + * overflow error for too long ints + */ +#define AS_RATIONAL(dst,object) \ + { \ + dst.n = 0; \ + if (PyRational_Check(object)) { \ + dst = ((PyRational*)object)->r; \ + } \ + else { \ + PyObject* y_; \ + int eq_; \ + long n_ = PyInt_AsLong(object); \ + if (error_converting(n_)) { \ + if (PyErr_ExceptionMatches(PyExc_TypeError)) { \ + PyErr_Clear(); \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + return 0; \ + } \ + y_ = PyInt_FromLong(n_); \ + if (!y_) { \ + return 0; \ + } \ + eq_ = PyObject_RichCompareBool(object,y_,Py_EQ); \ + Py_DECREF(y_); \ + if (eq_<0) { \ + return 0; \ + } \ + if (!eq_) { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + dst = make_rational_int(n_); \ + } \ + } + +static PyObject* +pyrational_richcompare(PyObject* a, PyObject* b, int op) { + rational x, y; + int result = 0; + AS_RATIONAL(x,a); + AS_RATIONAL(y,b); + #define OP(py,op) case py: result = rational_##op(x,y); break; + switch (op) { + OP(Py_LT,lt) + OP(Py_LE,le) + OP(Py_EQ,eq) + OP(Py_NE,ne) + OP(Py_GT,gt) + OP(Py_GE,ge) + }; + #undef OP + return PyBool_FromLong(result); +} + +static PyObject* +pyrational_repr(PyObject* self) { + rational x = ((PyRational*)self)->r; + if (d(x)!=1) { + return PyUString_FromFormat( + "rational(%ld,%ld)",(long)x.n,(long)d(x)); + } + else { + return PyUString_FromFormat( + "rational(%ld)",(long)x.n); + } +} + +static PyObject* +pyrational_str(PyObject* self) { + rational x = ((PyRational*)self)->r; + if (d(x)!=1) { + return PyString_FromFormat( + "%ld/%ld",(long)x.n,(long)d(x)); + } + else { + return PyString_FromFormat( + "%ld",(long)x.n); + } +} + +static npy_hash_t +pyrational_hash(PyObject* self) { + rational x = ((PyRational*)self)->r; + /* Use a fairly weak hash as Python expects */ + long h = 131071*x.n+524287*x.dmm; + /* Never return the special error value -1 */ + return h==-1?2:h; +} + +#define RATIONAL_BINOP_2(name,exp) \ + static PyObject* \ + pyrational_##name(PyObject* a, PyObject* b) { \ + rational x, y, z; \ + AS_RATIONAL(x,a); \ + AS_RATIONAL(y,b); \ + z = exp; \ + if (PyErr_Occurred()) { \ + return 0; \ + } \ + return PyRational_FromRational(z); \ + } +#define RATIONAL_BINOP(name) RATIONAL_BINOP_2(name,rational_##name(x,y)) +RATIONAL_BINOP(add) +RATIONAL_BINOP(subtract) +RATIONAL_BINOP(multiply) +RATIONAL_BINOP(divide) +RATIONAL_BINOP(remainder) +RATIONAL_BINOP_2(floor_divide, + make_rational_int(rational_floor(rational_divide(x,y)))) + +#define RATIONAL_UNOP(name,type,exp,convert) \ + static PyObject* \ + pyrational_##name(PyObject* self) { \ + rational x = ((PyRational*)self)->r; \ + type y = exp; \ + if (PyErr_Occurred()) { \ + return 0; \ + } \ + return convert(y); \ + } +RATIONAL_UNOP(negative,rational,rational_negative(x),PyRational_FromRational) +RATIONAL_UNOP(absolute,rational,rational_abs(x),PyRational_FromRational) +RATIONAL_UNOP(int,long,rational_int(x),PyInt_FromLong) +RATIONAL_UNOP(float,double,rational_double(x),PyFloat_FromDouble) + +static PyObject* +pyrational_positive(PyObject* self) { + Py_INCREF(self); + return self; +} + +static int +pyrational_nonzero(PyObject* self) { + rational x = ((PyRational*)self)->r; + return rational_nonzero(x); +} + +static PyNumberMethods pyrational_as_number = { + pyrational_add, /* nb_add */ + pyrational_subtract, /* nb_subtract */ + pyrational_multiply, /* nb_multiply */ +#if PY_MAJOR_VERSION < 3 + pyrational_divide, /* nb_divide */ +#endif + pyrational_remainder, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + pyrational_negative, /* nb_negative */ + pyrational_positive, /* nb_positive */ + pyrational_absolute, /* nb_absolute */ + pyrational_nonzero, /* nb_nonzero */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + 0, /* nb_and */ + 0, /* nb_xor */ + 0, /* nb_or */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_coerce */ +#endif + pyrational_int, /* nb_int */ +#if PY_MAJOR_VERSION < 3 + pyrational_int, /* nb_long */ +#else + 0, /* reserved */ +#endif + pyrational_float, /* nb_float */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_oct */ + 0, /* nb_hex */ +#endif + + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_inplace_divide */ +#endif + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + + pyrational_floor_divide, /* nb_floor_divide */ + pyrational_divide, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + 0, /* nb_index */ +}; + +static PyObject* +pyrational_n(PyObject* self, void* closure) { + return PyInt_FromLong(((PyRational*)self)->r.n); +} + +static PyObject* +pyrational_d(PyObject* self, void* closure) { + return PyInt_FromLong(d(((PyRational*)self)->r)); +} + +static PyGetSetDef pyrational_getset[] = { + {(char*)"n",pyrational_n,0,(char*)"numerator",0}, + {(char*)"d",pyrational_d,0,(char*)"denominator",0}, + {0} /* sentinel */ +}; + +static PyTypeObject PyRational_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "rational", /* tp_name */ + sizeof(PyRational), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + pyrational_repr, /* tp_repr */ + &pyrational_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + pyrational_hash, /* tp_hash */ + 0, /* tp_call */ + pyrational_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Fixed precision rational numbers", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + pyrational_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + pyrational_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + pyrational_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; + +/* NumPy support */ + +static PyObject* +npyrational_getitem(void* data, void* arr) { + rational r; + memcpy(&r,data,sizeof(rational)); + return PyRational_FromRational(r); +} + +static int +npyrational_setitem(PyObject* item, void* data, void* arr) { + rational r; + if (PyRational_Check(item)) { + r = ((PyRational*)item)->r; + } + else { + long n = PyInt_AsLong(item); + PyObject* y; + int eq; + if (error_converting(n)) { + return -1; + } + y = PyInt_FromLong(n); + if (!y) { + return -1; + } + eq = PyObject_RichCompareBool(item,y,Py_EQ); + Py_DECREF(y); + if (eq<0) { + return -1; + } + if (!eq) { + PyErr_Format(PyExc_TypeError, + "expected rational, got %s", item->ob_type->tp_name); + return -1; + } + r = make_rational_int(n); + } + memcpy(data,&r,sizeof(rational)); + return 0; +} + +static NPY_INLINE void +byteswap(npy_int32* x) { + char* p = (char*)x; + size_t i; + for (i = 0; i < sizeof(*x)/2; i++) { + size_t j = sizeof(*x)-1-i; + char t = p[i]; + p[i] = p[j]; + p[j] = t; + } +} + +static void +npyrational_copyswapn(void* dst_, npy_intp dstride, void* src_, + npy_intp sstride, npy_intp n, int swap, void* arr) { + char *dst = (char*)dst_, *src = (char*)src_; + npy_intp i; + if (!src) { + return; + } + if (swap) { + for (i = 0; i < n; i++) { + rational* r = (rational*)(dst+dstride*i); + memcpy(r,src+sstride*i,sizeof(rational)); + byteswap(&r->n); + byteswap(&r->dmm); + } + } + else if (dstride == sizeof(rational) && sstride == sizeof(rational)) { + memcpy(dst, src, n*sizeof(rational)); + } + else { + for (i = 0; i < n; i++) { + memcpy(dst + dstride*i, src + sstride*i, sizeof(rational)); + } + } +} + +static void +npyrational_copyswap(void* dst, void* src, int swap, void* arr) { + rational* r; + if (!src) { + return; + } + r = (rational*)dst; + memcpy(r,src,sizeof(rational)); + if (swap) { + byteswap(&r->n); + byteswap(&r->dmm); + } +} + +static int +npyrational_compare(const void* d0, const void* d1, void* arr) { + rational x = *(rational*)d0, + y = *(rational*)d1; + return rational_lt(x,y)?-1:rational_eq(x,y)?0:1; +} + +#define FIND_EXTREME(name,op) \ + static int \ + npyrational_##name(void* data_, npy_intp n, \ + npy_intp* max_ind, void* arr) { \ + const rational* data; \ + npy_intp best_i; \ + rational best_r; \ + npy_intp i; \ + if (!n) { \ + return 0; \ + } \ + data = (rational*)data_; \ + best_i = 0; \ + best_r = data[0]; \ + for (i = 1; i < n; i++) { \ + if (rational_##op(data[i],best_r)) { \ + best_i = i; \ + best_r = data[i]; \ + } \ + } \ + *max_ind = best_i; \ + return 0; \ + } +FIND_EXTREME(argmin,lt) +FIND_EXTREME(argmax,gt) + +static void +npyrational_dot(void* ip0_, npy_intp is0, void* ip1_, npy_intp is1, + void* op, npy_intp n, void* arr) { + rational r = {0}; + const char *ip0 = (char*)ip0_, *ip1 = (char*)ip1_; + npy_intp i; + for (i = 0; i < n; i++) { + r = rational_add(r,rational_multiply(*(rational*)ip0,*(rational*)ip1)); + ip0 += is0; + ip1 += is1; + } + *(rational*)op = r; +} + +static npy_bool +npyrational_nonzero(void* data, void* arr) { + rational r; + memcpy(&r,data,sizeof(r)); + return rational_nonzero(r)?NPY_TRUE:NPY_FALSE; +} + +static int +npyrational_fill(void* data_, npy_intp length, void* arr) { + rational* data = (rational*)data_; + rational delta = rational_subtract(data[1],data[0]); + rational r = data[1]; + npy_intp i; + for (i = 2; i < length; i++) { + r = rational_add(r,delta); + data[i] = r; + } + return 0; +} + +static int +npyrational_fillwithscalar(void* buffer_, npy_intp length, + void* value, void* arr) { + rational r = *(rational*)value; + rational* buffer = (rational*)buffer_; + npy_intp i; + for (i = 0; i < length; i++) { + buffer[i] = r; + } + return 0; +} + +static PyArray_ArrFuncs npyrational_arrfuncs; + +typedef struct { char c; rational r; } align_test; + +PyArray_Descr npyrational_descr = { + PyObject_HEAD_INIT(0) + &PyRational_Type, /* typeobj */ + 'V', /* kind */ + 'r', /* type */ + '=', /* byteorder */ + /* + * For now, we need NPY_NEEDS_PYAPI in order to make numpy detect our + * exceptions. This isn't technically necessary, + * since we're careful about thread safety, and hopefully future + * versions of numpy will recognize that. + */ + NPY_NEEDS_PYAPI | NPY_USE_GETITEM | NPY_USE_SETITEM, /* hasobject */ + 0, /* type_num */ + sizeof(rational), /* elsize */ + offsetof(align_test,r), /* alignment */ + 0, /* subarray */ + 0, /* fields */ + 0, /* names */ + &npyrational_arrfuncs, /* f */ +}; + +#define DEFINE_CAST(From,To,statement) \ + static void \ + npycast_##From##_##To(void* from_, void* to_, npy_intp n, \ + void* fromarr, void* toarr) { \ + const From* from = (From*)from_; \ + To* to = (To*)to_; \ + npy_intp i; \ + for (i = 0; i < n; i++) { \ + From x = from[i]; \ + statement \ + to[i] = y; \ + } \ + } +#define DEFINE_INT_CAST(bits) \ + DEFINE_CAST(npy_int##bits,rational,rational y = make_rational_int(x);) \ + DEFINE_CAST(rational,npy_int##bits,npy_int32 z = rational_int(x); \ + npy_int##bits y = z; if (y != z) set_overflow();) +DEFINE_INT_CAST(8) +DEFINE_INT_CAST(16) +DEFINE_INT_CAST(32) +DEFINE_INT_CAST(64) +DEFINE_CAST(rational,float,double y = rational_double(x);) +DEFINE_CAST(rational,double,double y = rational_double(x);) +DEFINE_CAST(npy_bool,rational,rational y = make_rational_int(x);) +DEFINE_CAST(rational,npy_bool,npy_bool y = rational_nonzero(x);) + +#define BINARY_UFUNC(name,intype0,intype1,outtype,exp) \ + void name(char** args, npy_intp* dimensions, \ + npy_intp* steps, void* data) { \ + npy_intp is0 = steps[0], is1 = steps[1], \ + os = steps[2], n = *dimensions; \ + char *i0 = args[0], *i1 = args[1], *o = args[2]; \ + int k; \ + for (k = 0; k < n; k++) { \ + intype0 x = *(intype0*)i0; \ + intype1 y = *(intype1*)i1; \ + *(outtype*)o = exp; \ + i0 += is0; i1 += is1; o += os; \ + } \ + } +#define RATIONAL_BINARY_UFUNC(name,type,exp) \ + BINARY_UFUNC(rational_ufunc_##name,rational,rational,type,exp) +RATIONAL_BINARY_UFUNC(add,rational,rational_add(x,y)) +RATIONAL_BINARY_UFUNC(subtract,rational,rational_subtract(x,y)) +RATIONAL_BINARY_UFUNC(multiply,rational,rational_multiply(x,y)) +RATIONAL_BINARY_UFUNC(divide,rational,rational_divide(x,y)) +RATIONAL_BINARY_UFUNC(remainder,rational,rational_remainder(x,y)) +RATIONAL_BINARY_UFUNC(floor_divide,rational, + make_rational_int(rational_floor(rational_divide(x,y)))) +PyUFuncGenericFunction rational_ufunc_true_divide = rational_ufunc_divide; +RATIONAL_BINARY_UFUNC(minimum,rational,rational_lt(x,y)?x:y) +RATIONAL_BINARY_UFUNC(maximum,rational,rational_lt(x,y)?y:x) +RATIONAL_BINARY_UFUNC(equal,npy_bool,rational_eq(x,y)) +RATIONAL_BINARY_UFUNC(not_equal,npy_bool,rational_ne(x,y)) +RATIONAL_BINARY_UFUNC(less,npy_bool,rational_lt(x,y)) +RATIONAL_BINARY_UFUNC(greater,npy_bool,rational_gt(x,y)) +RATIONAL_BINARY_UFUNC(less_equal,npy_bool,rational_le(x,y)) +RATIONAL_BINARY_UFUNC(greater_equal,npy_bool,rational_ge(x,y)) + +BINARY_UFUNC(gcd_ufunc,npy_int64,npy_int64,npy_int64,gcd(x,y)) +BINARY_UFUNC(lcm_ufunc,npy_int64,npy_int64,npy_int64,lcm(x,y)) + +#define UNARY_UFUNC(name,type,exp) \ + void rational_ufunc_##name(char** args, npy_intp* dimensions, \ + npy_intp* steps, void* data) { \ + npy_intp is = steps[0], os = steps[1], n = *dimensions; \ + char *i = args[0], *o = args[1]; \ + int k; \ + for (k = 0; k < n; k++) { \ + rational x = *(rational*)i; \ + *(type*)o = exp; \ + i += is; o += os; \ + } \ + } +UNARY_UFUNC(negative,rational,rational_negative(x)) +UNARY_UFUNC(absolute,rational,rational_abs(x)) +UNARY_UFUNC(floor,rational,make_rational_int(rational_floor(x))) +UNARY_UFUNC(ceil,rational,make_rational_int(rational_ceil(x))) +UNARY_UFUNC(trunc,rational,make_rational_int(x.n/d(x))) +UNARY_UFUNC(square,rational,rational_multiply(x,x)) +UNARY_UFUNC(rint,rational,make_rational_int(rational_rint(x))) +UNARY_UFUNC(sign,rational,make_rational_int(rational_sign(x))) +UNARY_UFUNC(reciprocal,rational,rational_inverse(x)) +UNARY_UFUNC(numerator,npy_int64,x.n) +UNARY_UFUNC(denominator,npy_int64,d(x)) + +static NPY_INLINE void +rational_matrix_multiply(char **args, npy_intp *dimensions, npy_intp *steps) +{ + /* pointers to data for input and output arrays */ + char *ip1 = args[0]; + char *ip2 = args[1]; + char *op = args[2]; + + /* lengths of core dimensions */ + npy_intp dm = dimensions[0]; + npy_intp dn = dimensions[1]; + npy_intp dp = dimensions[2]; + + /* striding over core dimensions */ + npy_intp is1_m = steps[0]; + npy_intp is1_n = steps[1]; + npy_intp is2_n = steps[2]; + npy_intp is2_p = steps[3]; + npy_intp os_m = steps[4]; + npy_intp os_p = steps[5]; + + /* core dimensions counters */ + npy_intp m, p; + + /* calculate dot product for each row/column vector pair */ + for (m = 0; m < dm; m++) { + for (p = 0; p < dp; p++) { + npyrational_dot(ip1, is1_n, ip2, is2_n, op, dn, NULL); + + /* advance to next column of 2nd input array and output array */ + ip2 += is2_p; + op += os_p; + } + + /* reset to first column of 2nd input array and output array */ + ip2 -= is2_p * p; + op -= os_p * p; + + /* advance to next row of 1st input array and output array */ + ip1 += is1_m; + op += os_m; + } +} + + +static void +rational_gufunc_matrix_multiply(char **args, npy_intp *dimensions, + npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* outer dimensions counter */ + npy_intp N_; + + /* length of flattened outer dimensions */ + npy_intp dN = dimensions[0]; + + /* striding over flattened outer dimensions for input and output arrays */ + npy_intp s0 = steps[0]; + npy_intp s1 = steps[1]; + npy_intp s2 = steps[2]; + + /* + * loop through outer dimensions, performing matrix multiply on + * core dimensions for each loop + */ + for (N_ = 0; N_ < dN; N_++, args[0] += s0, args[1] += s1, args[2] += s2) { + rational_matrix_multiply(args, dimensions+1, steps+3); + } +} + + +static void +rational_ufunc_test_add(char** args, npy_intp* dimensions, + npy_intp* steps, void* data) { + npy_intp is0 = steps[0], is1 = steps[1], os = steps[2], n = *dimensions; + char *i0 = args[0], *i1 = args[1], *o = args[2]; + int k; + for (k = 0; k < n; k++) { + npy_int64 x = *(npy_int64*)i0; + npy_int64 y = *(npy_int64*)i1; + *(rational*)o = rational_add(make_rational_fast(x, 1), + make_rational_fast(y, 1)); + i0 += is0; i1 += is1; o += os; + } +} + + +static void +rational_ufunc_test_add_rationals(char** args, npy_intp* dimensions, + npy_intp* steps, void* data) { + npy_intp is0 = steps[0], is1 = steps[1], os = steps[2], n = *dimensions; + char *i0 = args[0], *i1 = args[1], *o = args[2]; + int k; + for (k = 0; k < n; k++) { + rational x = *(rational*)i0; + rational y = *(rational*)i1; + *(rational*)o = rational_add(x, y); + i0 += is0; i1 += is1; o += os; + } +} + + +PyMethodDef module_methods[] = { + {0} /* sentinel */ +}; + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "test_rational", + NULL, + -1, + module_methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#if defined(NPY_PY3K) +#define RETVAL m +PyMODINIT_FUNC PyInit_test_rational(void) { +#else +#define RETVAL +PyMODINIT_FUNC inittest_rational(void) { +#endif + + PyObject *m = NULL; + PyObject* numpy_str; + PyObject* numpy; + int npy_rational; + + import_array(); + if (PyErr_Occurred()) { + goto fail; + } + import_umath(); + if (PyErr_Occurred()) { + goto fail; + } + numpy_str = PyUString_FromString("numpy"); + if (!numpy_str) { + goto fail; + } + numpy = PyImport_Import(numpy_str); + Py_DECREF(numpy_str); + if (!numpy) { + goto fail; + } + + /* Can't set this until we import numpy */ + PyRational_Type.tp_base = &PyGenericArrType_Type; + + /* Initialize rational type object */ + if (PyType_Ready(&PyRational_Type) < 0) { + goto fail; + } + + /* Initialize rational descriptor */ + PyArray_InitArrFuncs(&npyrational_arrfuncs); + npyrational_arrfuncs.getitem = npyrational_getitem; + npyrational_arrfuncs.setitem = npyrational_setitem; + npyrational_arrfuncs.copyswapn = npyrational_copyswapn; + npyrational_arrfuncs.copyswap = npyrational_copyswap; + npyrational_arrfuncs.compare = npyrational_compare; + npyrational_arrfuncs.argmin = npyrational_argmin; + npyrational_arrfuncs.argmax = npyrational_argmax; + npyrational_arrfuncs.dotfunc = npyrational_dot; + npyrational_arrfuncs.nonzero = npyrational_nonzero; + npyrational_arrfuncs.fill = npyrational_fill; + npyrational_arrfuncs.fillwithscalar = npyrational_fillwithscalar; + /* Left undefined: scanfunc, fromstr, sort, argsort */ + Py_TYPE(&npyrational_descr) = &PyArrayDescr_Type; + npy_rational = PyArray_RegisterDataType(&npyrational_descr); + if (npy_rational<0) { + goto fail; + } + + /* Support dtype(rational) syntax */ + if (PyDict_SetItemString(PyRational_Type.tp_dict, "dtype", + (PyObject*)&npyrational_descr) < 0) { + goto fail; + } + + /* Register casts to and from rational */ + #define REGISTER_CAST(From,To,from_descr,to_typenum,safe) { \ + PyArray_Descr* from_descr_##From##_##To = (from_descr); \ + if (PyArray_RegisterCastFunc(from_descr_##From##_##To, \ + (to_typenum), \ + npycast_##From##_##To) < 0) { \ + goto fail; \ + } \ + if (safe && PyArray_RegisterCanCast(from_descr_##From##_##To, \ + (to_typenum), \ + NPY_NOSCALAR) < 0) { \ + goto fail; \ + } \ + } + #define REGISTER_INT_CASTS(bits) \ + REGISTER_CAST(npy_int##bits, rational, \ + PyArray_DescrFromType(NPY_INT##bits), npy_rational, 1) \ + REGISTER_CAST(rational, npy_int##bits, &npyrational_descr, \ + NPY_INT##bits, 0) + REGISTER_INT_CASTS(8) + REGISTER_INT_CASTS(16) + REGISTER_INT_CASTS(32) + REGISTER_INT_CASTS(64) + REGISTER_CAST(rational,float,&npyrational_descr,NPY_FLOAT,0) + REGISTER_CAST(rational,double,&npyrational_descr,NPY_DOUBLE,1) + REGISTER_CAST(npy_bool,rational, PyArray_DescrFromType(NPY_BOOL), + npy_rational,1) + REGISTER_CAST(rational,npy_bool,&npyrational_descr,NPY_BOOL,0) + + /* Register ufuncs */ + #define REGISTER_UFUNC(name,...) { \ + PyUFuncObject* ufunc = \ + (PyUFuncObject*)PyObject_GetAttrString(numpy, #name); \ + int _types[] = __VA_ARGS__; \ + if (!ufunc) { \ + goto fail; \ + } \ + if (sizeof(_types)/sizeof(int)!=ufunc->nargs) { \ + PyErr_Format(PyExc_AssertionError, \ + "ufunc %s takes %d arguments, our loop takes %lu", \ + #name, ufunc->nargs, (unsigned long) \ + (sizeof(_types)/sizeof(int))); \ + Py_DECREF(ufunc); \ + goto fail; \ + } \ + if (PyUFunc_RegisterLoopForType((PyUFuncObject*)ufunc, npy_rational, \ + rational_ufunc_##name, _types, 0) < 0) { \ + Py_DECREF(ufunc); \ + goto fail; \ + } \ + Py_DECREF(ufunc); \ + } + #define REGISTER_UFUNC_BINARY_RATIONAL(name) \ + REGISTER_UFUNC(name, {npy_rational, npy_rational, npy_rational}) + #define REGISTER_UFUNC_BINARY_COMPARE(name) \ + REGISTER_UFUNC(name, {npy_rational, npy_rational, NPY_BOOL}) + #define REGISTER_UFUNC_UNARY(name) \ + REGISTER_UFUNC(name, {npy_rational, npy_rational}) + /* Binary */ + REGISTER_UFUNC_BINARY_RATIONAL(add) + REGISTER_UFUNC_BINARY_RATIONAL(subtract) + REGISTER_UFUNC_BINARY_RATIONAL(multiply) + REGISTER_UFUNC_BINARY_RATIONAL(divide) + REGISTER_UFUNC_BINARY_RATIONAL(remainder) + REGISTER_UFUNC_BINARY_RATIONAL(true_divide) + REGISTER_UFUNC_BINARY_RATIONAL(floor_divide) + REGISTER_UFUNC_BINARY_RATIONAL(minimum) + REGISTER_UFUNC_BINARY_RATIONAL(maximum) + /* Comparisons */ + REGISTER_UFUNC_BINARY_COMPARE(equal) + REGISTER_UFUNC_BINARY_COMPARE(not_equal) + REGISTER_UFUNC_BINARY_COMPARE(less) + REGISTER_UFUNC_BINARY_COMPARE(greater) + REGISTER_UFUNC_BINARY_COMPARE(less_equal) + REGISTER_UFUNC_BINARY_COMPARE(greater_equal) + /* Unary */ + REGISTER_UFUNC_UNARY(negative) + REGISTER_UFUNC_UNARY(absolute) + REGISTER_UFUNC_UNARY(floor) + REGISTER_UFUNC_UNARY(ceil) + REGISTER_UFUNC_UNARY(trunc) + REGISTER_UFUNC_UNARY(rint) + REGISTER_UFUNC_UNARY(square) + REGISTER_UFUNC_UNARY(reciprocal) + REGISTER_UFUNC_UNARY(sign) + + /* Create module */ +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("test_rational", module_methods); +#endif + + if (!m) { + goto fail; + } + + /* Add rational type */ + Py_INCREF(&PyRational_Type); + PyModule_AddObject(m,"rational",(PyObject*)&PyRational_Type); + + /* Create matrix multiply generalized ufunc */ + { + int types2[3] = {npy_rational,npy_rational,npy_rational}; + PyObject* gufunc = PyUFunc_FromFuncAndDataAndSignature(0,0,0,0,2,1, + PyUFunc_None,(char*)"matrix_multiply", + (char*)"return result of multiplying two matrices of rationals", + 0,"(m,n),(n,p)->(m,p)"); + if (!gufunc) { + goto fail; + } + if (PyUFunc_RegisterLoopForType((PyUFuncObject*)gufunc, npy_rational, + rational_gufunc_matrix_multiply, types2, 0) < 0) { + goto fail; + } + PyModule_AddObject(m,"matrix_multiply",(PyObject*)gufunc); + } + + /* Create test ufunc with built in input types and rational output type */ + { + int types3[3] = {NPY_INT64,NPY_INT64,npy_rational}; + + PyObject* ufunc = PyUFunc_FromFuncAndData(0,0,0,0,2,1, + PyUFunc_None,(char*)"test_add", + (char*)"add two matrices of int64 and return rational matrix",0); + if (!ufunc) { + goto fail; + } + if (PyUFunc_RegisterLoopForType((PyUFuncObject*)ufunc, npy_rational, + rational_ufunc_test_add, types3, 0) < 0) { + goto fail; + } + PyModule_AddObject(m,"test_add",(PyObject*)ufunc); + } + + /* Create test ufunc with rational types using RegisterLoopForDescr */ + { + PyObject* ufunc = PyUFunc_FromFuncAndData(0,0,0,0,2,1, + PyUFunc_None,(char*)"test_add_rationals", + (char*)"add two matrices of rationals and return rational matrix",0); + PyArray_Descr* types[3] = {&npyrational_descr, + &npyrational_descr, + &npyrational_descr}; + + if (!ufunc) { + goto fail; + } + if (PyUFunc_RegisterLoopForDescr((PyUFuncObject*)ufunc, &npyrational_descr, + rational_ufunc_test_add_rationals, types, 0) < 0) { + goto fail; + } + PyModule_AddObject(m,"test_add_rationals",(PyObject*)ufunc); + } + + /* Create numerator and denominator ufuncs */ + #define NEW_UNARY_UFUNC(name,type,doc) { \ + int types[2] = {npy_rational,type}; \ + PyObject* ufunc = PyUFunc_FromFuncAndData(0,0,0,0,1,1, \ + PyUFunc_None,(char*)#name,(char*)doc,0); \ + if (!ufunc) { \ + goto fail; \ + } \ + if (PyUFunc_RegisterLoopForType((PyUFuncObject*)ufunc, \ + npy_rational,rational_ufunc_##name,types,0)<0) { \ + goto fail; \ + } \ + PyModule_AddObject(m,#name,(PyObject*)ufunc); \ + } + NEW_UNARY_UFUNC(numerator,NPY_INT64,"rational number numerator"); + NEW_UNARY_UFUNC(denominator,NPY_INT64,"rational number denominator"); + + /* Create gcd and lcm ufuncs */ + #define GCD_LCM_UFUNC(name,type,doc) { \ + static const PyUFuncGenericFunction func[1] = {name##_ufunc}; \ + static const char types[3] = {type,type,type}; \ + static void* data[1] = {0}; \ + PyObject* ufunc = PyUFunc_FromFuncAndData( \ + (PyUFuncGenericFunction*)func, data,(char*)types, \ + 1,2,1,PyUFunc_One,(char*)#name,(char*)doc,0); \ + if (!ufunc) { \ + goto fail; \ + } \ + PyModule_AddObject(m,#name,(PyObject*)ufunc); \ + } + GCD_LCM_UFUNC(gcd,NPY_INT64,"greatest common denominator of two integers"); + GCD_LCM_UFUNC(lcm,NPY_INT64,"least common multiple of two integers"); + + return RETVAL; + +fail: + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot load test_rational module."); + } +#if defined(NPY_PY3K) + if (m) { + Py_DECREF(m); + m = NULL; + } +#endif + return RETVAL; +} diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c new file mode 100644 index 0000000..2570670 --- /dev/null +++ b/numpy/core/src/umath/ufunc_object.c @@ -0,0 +1,5524 @@ +/* + * Python Universal Functions Object -- Math for all types, plus fast + * arrays math + * + * Full description + * + * This supports mathematical (and Boolean) functions on arrays and other python + * objects. Math on large arrays of basic C types is rather efficient. + * + * Travis E. Oliphant 2005, 2006 oliphant@ee.byu.edu (oliphant.travis@ieee.org) + * Brigham Young University + * + * based on the + * + * Original Implementation: + * Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu + * + * with inspiration and code from + * Numarray + * Space Science Telescope Institute + * J. Todd Miller + * Perry Greenfield + * Rick White + * + */ +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" + +#include "npy_config.h" + +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API +#define NO_IMPORT_ARRAY + +#include "npy_pycompat.h" + +#include "numpy/arrayobject.h" +#include "numpy/ufuncobject.h" +#include "numpy/arrayscalars.h" +#include "lowlevel_strided_loops.h" +#include "ufunc_type_resolution.h" +#include "reduction.h" +#include "mem_overlap.h" + +#include "ufunc_object.h" +#include "override.h" +#include "npy_import.h" +#include "extobj.h" +#include "common.h" + +/********** PRINTF DEBUG TRACING **************/ +#define NPY_UF_DBG_TRACING 0 + +#if NPY_UF_DBG_TRACING +#define NPY_UF_DBG_PRINT(s) {printf("%s", s);fflush(stdout);} +#define NPY_UF_DBG_PRINT1(s, p1) {printf((s), (p1));fflush(stdout);} +#define NPY_UF_DBG_PRINT2(s, p1, p2) {printf(s, p1, p2);fflush(stdout);} +#define NPY_UF_DBG_PRINT3(s, p1, p2, p3) {printf(s, p1, p2, p3);fflush(stdout);} +#else +#define NPY_UF_DBG_PRINT(s) +#define NPY_UF_DBG_PRINT1(s, p1) +#define NPY_UF_DBG_PRINT2(s, p1, p2) +#define NPY_UF_DBG_PRINT3(s, p1, p2, p3) +#endif +/**********************************************/ + +/* ---------------------------------------------------------------- */ + +static int +_does_loop_use_arrays(void *data); + +static int +assign_reduce_identity_zero(PyArrayObject *result, void *data); + +static int +assign_reduce_identity_minusone(PyArrayObject *result, void *data); + +static int +assign_reduce_identity_one(PyArrayObject *result, void *data); + + +/*UFUNC_API*/ +NPY_NO_EXPORT int +PyUFunc_getfperr(void) +{ + /* + * non-clearing get was only added in 1.9 so this function always cleared + * keep it so just in case third party code relied on the clearing + */ + return npy_clear_floatstatus(); +} + +#define HANDLEIT(NAME, str) {if (retstatus & NPY_FPE_##NAME) { \ + handle = errmask & UFUNC_MASK_##NAME; \ + if (handle && \ + _error_handler(handle >> UFUNC_SHIFT_##NAME, \ + errobj, str, retstatus, first) < 0) \ + return -1; \ + }} + +/*UFUNC_API*/ +NPY_NO_EXPORT int +PyUFunc_handlefperr(int errmask, PyObject *errobj, int retstatus, int *first) +{ + int handle; + if (errmask && retstatus) { + HANDLEIT(DIVIDEBYZERO, "divide by zero"); + HANDLEIT(OVERFLOW, "overflow"); + HANDLEIT(UNDERFLOW, "underflow"); + HANDLEIT(INVALID, "invalid value"); + } + return 0; +} + +#undef HANDLEIT + + +/*UFUNC_API*/ +NPY_NO_EXPORT int +PyUFunc_checkfperr(int errmask, PyObject *errobj, int *first) +{ + /* clearing is done for backward compatibility */ + int retstatus = npy_clear_floatstatus(); + + return PyUFunc_handlefperr(errmask, errobj, retstatus, first); +} + + +/* Checking the status flag clears it */ +/*UFUNC_API*/ +NPY_NO_EXPORT void +PyUFunc_clearfperr() +{ + npy_clear_floatstatus(); +} + +/* + * This function analyzes the input arguments + * and determines an appropriate __array_prepare__ function to call + * for the outputs. + * Assumes subok is already true if check_subok is false. + * + * If an output argument is provided, then it is prepped + * with its own __array_prepare__ not with the one determined by + * the input arguments. + * + * if the provided output argument is already an ndarray, + * the prepping function is None (which means no prepping will + * be done --- not even PyArray_Return). + * + * A NULL is placed in output_prep for outputs that + * should just have PyArray_Return called. + */ +static void +_find_array_prepare(PyObject *args, PyObject *kwds, + PyObject **output_prep, int nin, int nout, + int check_subok) +{ + Py_ssize_t nargs; + int i; + int np = 0; + PyObject *with_prep[NPY_MAXARGS], *preps[NPY_MAXARGS]; + PyObject *obj, *prep = NULL; + + /* + * If a 'subok' parameter is passed and isn't True, don't wrap + * if check_subok is false it assumed subok in kwds keyword is True + */ + if (check_subok && kwds != NULL && + (obj = PyDict_GetItem(kwds, npy_um_str_subok)) != NULL) { + if (obj != Py_True) { + for (i = 0; i < nout; i++) { + output_prep[i] = NULL; + } + return; + } + } + + nargs = PyTuple_GET_SIZE(args); + for (i = 0; i < nin; i++) { + obj = PyTuple_GET_ITEM(args, i); + if (PyArray_CheckExact(obj) || PyArray_IsAnyScalar(obj)) { + continue; + } + prep = PyObject_GetAttr(obj, npy_um_str_array_prepare); + if (prep) { + if (PyCallable_Check(prep)) { + with_prep[np] = obj; + preps[np] = prep; + ++np; + } + else { + Py_DECREF(prep); + prep = NULL; + } + } + else { + PyErr_Clear(); + } + } + if (np > 0) { + /* If we have some preps defined, find the one of highest priority */ + prep = preps[0]; + if (np > 1) { + double maxpriority = PyArray_GetPriority(with_prep[0], + NPY_PRIORITY); + for (i = 1; i < np; ++i) { + double priority = PyArray_GetPriority(with_prep[i], + NPY_PRIORITY); + if (priority > maxpriority) { + maxpriority = priority; + Py_DECREF(prep); + prep = preps[i]; + } + else { + Py_DECREF(preps[i]); + } + } + } + } + + /* + * Here prep is the prepping function determined from the + * input arrays (could be NULL). + * + * For all the output arrays decide what to do. + * + * 1) Use the prep function determined from the input arrays + * This is the default if the output array is not + * passed in. + * + * 2) Use the __array_prepare__ method of the output object. + * This is special cased for + * exact ndarray so that no PyArray_Return is + * done in that case. + */ + for (i = 0; i < nout; i++) { + int j = nin + i; + int incref = 1; + output_prep[i] = prep; + obj = NULL; + if (j < nargs) { + obj = PyTuple_GET_ITEM(args, j); + /* Output argument one may also be in a keyword argument */ + if (i == 0 && obj == Py_None && kwds != NULL) { + obj = PyDict_GetItem(kwds, npy_um_str_out); + } + } + /* Output argument one may also be in a keyword argument */ + else if (i == 0 && kwds != NULL) { + obj = PyDict_GetItem(kwds, npy_um_str_out); + } + + if (obj != Py_None && obj != NULL) { + if (PyArray_CheckExact(obj)) { + /* None signals to not call any wrapping */ + output_prep[i] = Py_None; + } + else { + PyObject *oprep = PyObject_GetAttr(obj, + npy_um_str_array_prepare); + incref = 0; + if (!(oprep) || !(PyCallable_Check(oprep))) { + Py_XDECREF(oprep); + oprep = prep; + incref = 1; + PyErr_Clear(); + } + output_prep[i] = oprep; + } + } + + if (incref) { + Py_XINCREF(output_prep[i]); + } + } + Py_XDECREF(prep); + return; +} + + +/*UFUNC_API + * + * On return, if errobj is populated with a non-NULL value, the caller + * owns a new reference to errobj. + */ +NPY_NO_EXPORT int +PyUFunc_GetPyValues(char *name, int *bufsize, int *errmask, PyObject **errobj) +{ + PyObject *ref = get_global_ext_obj(); + + return _extract_pyvals(ref, name, bufsize, errmask, errobj); +} + +/* Return the position of next non-white-space char in the string */ +static int +_next_non_white_space(const char* str, int offset) +{ + int ret = offset; + while (str[ret] == ' ' || str[ret] == '\t') { + ret++; + } + return ret; +} + +static int +_is_alpha_underscore(char ch) +{ + return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_'; +} + +static int +_is_alnum_underscore(char ch) +{ + return _is_alpha_underscore(ch) || (ch >= '0' && ch <= '9'); +} + +/* + * Return the ending position of a variable name + */ +static int +_get_end_of_name(const char* str, int offset) +{ + int ret = offset; + while (_is_alnum_underscore(str[ret])) { + ret++; + } + return ret; +} + +/* + * Returns 1 if the dimension names pointed by s1 and s2 are the same, + * otherwise returns 0. + */ +static int +_is_same_name(const char* s1, const char* s2) +{ + while (_is_alnum_underscore(*s1) && _is_alnum_underscore(*s2)) { + if (*s1 != *s2) { + return 0; + } + s1++; + s2++; + } + return !_is_alnum_underscore(*s1) && !_is_alnum_underscore(*s2); +} + +/* + * Sets core_num_dim_ix, core_num_dims, core_dim_ixs, core_offsets, + * and core_signature in PyUFuncObject "ufunc". Returns 0 unless an + * error occurred. + */ +static int +_parse_signature(PyUFuncObject *ufunc, const char *signature) +{ + size_t len; + char const **var_names; + int nd = 0; /* number of dimension of the current argument */ + int cur_arg = 0; /* index into core_num_dims&core_offsets */ + int cur_core_dim = 0; /* index into core_dim_ixs */ + int i = 0; + char *parse_error = NULL; + + if (signature == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "_parse_signature with NULL signature"); + return -1; + } + + len = strlen(signature); + ufunc->core_signature = PyArray_malloc(sizeof(char) * (len+1)); + if (ufunc->core_signature) { + strcpy(ufunc->core_signature, signature); + } + /* Allocate sufficient memory to store pointers to all dimension names */ + var_names = PyArray_malloc(sizeof(char const*) * len); + if (var_names == NULL) { + PyErr_NoMemory(); + return -1; + } + + ufunc->core_enabled = 1; + ufunc->core_num_dim_ix = 0; + ufunc->core_num_dims = PyArray_malloc(sizeof(int) * ufunc->nargs); + ufunc->core_dim_ixs = PyArray_malloc(sizeof(int) * len); /* shrink this later */ + ufunc->core_offsets = PyArray_malloc(sizeof(int) * ufunc->nargs); + if (ufunc->core_num_dims == NULL || ufunc->core_dim_ixs == NULL + || ufunc->core_offsets == NULL) { + PyErr_NoMemory(); + goto fail; + } + + i = _next_non_white_space(signature, 0); + while (signature[i] != '\0') { + /* loop over input/output arguments */ + if (cur_arg == ufunc->nin) { + /* expect "->" */ + if (signature[i] != '-' || signature[i+1] != '>') { + parse_error = "expect '->'"; + goto fail; + } + i = _next_non_white_space(signature, i + 2); + } + + /* + * parse core dimensions of one argument, + * e.g. "()", "(i)", or "(i,j)" + */ + if (signature[i] != '(') { + parse_error = "expect '('"; + goto fail; + } + i = _next_non_white_space(signature, i + 1); + while (signature[i] != ')') { + /* loop over core dimensions */ + int j = 0; + if (!_is_alpha_underscore(signature[i])) { + parse_error = "expect dimension name"; + goto fail; + } + while (j < ufunc->core_num_dim_ix) { + if (_is_same_name(signature+i, var_names[j])) { + break; + } + j++; + } + if (j >= ufunc->core_num_dim_ix) { + var_names[j] = signature+i; + ufunc->core_num_dim_ix++; + } + ufunc->core_dim_ixs[cur_core_dim] = j; + cur_core_dim++; + nd++; + i = _get_end_of_name(signature, i); + i = _next_non_white_space(signature, i); + if (signature[i] != ',' && signature[i] != ')') { + parse_error = "expect ',' or ')'"; + goto fail; + } + if (signature[i] == ',') + { + i = _next_non_white_space(signature, i + 1); + if (signature[i] == ')') { + parse_error = "',' must not be followed by ')'"; + goto fail; + } + } + } + ufunc->core_num_dims[cur_arg] = nd; + ufunc->core_offsets[cur_arg] = cur_core_dim-nd; + cur_arg++; + nd = 0; + + i = _next_non_white_space(signature, i + 1); + if (cur_arg != ufunc->nin && cur_arg != ufunc->nargs) { + /* + * The list of input arguments (or output arguments) was + * only read partially + */ + if (signature[i] != ',') { + parse_error = "expect ','"; + goto fail; + } + i = _next_non_white_space(signature, i + 1); + } + } + if (cur_arg != ufunc->nargs) { + parse_error = "incomplete signature: not all arguments found"; + goto fail; + } + ufunc->core_dim_ixs = PyArray_realloc(ufunc->core_dim_ixs, + sizeof(int)*cur_core_dim); + /* check for trivial core-signature, e.g. "(),()->()" */ + if (cur_core_dim == 0) { + ufunc->core_enabled = 0; + } + PyArray_free((void*)var_names); + return 0; + +fail: + PyArray_free((void*)var_names); + if (parse_error) { + PyErr_Format(PyExc_ValueError, + "%s at position %d in \"%s\"", + parse_error, i, signature); + } + return -1; +} + +/* + * Checks if 'obj' is a valid output array for a ufunc, i.e. it is + * either None or a writeable array, increments its reference count + * and stores a pointer to it in 'store'. Returns 0 on success, sets + * an exception and returns -1 on failure. + */ +static int +_set_out_array(PyObject *obj, PyArrayObject **store) +{ + if (obj == Py_None) { + /* Translate None to NULL */ + return 0; + } + if PyArray_Check(obj) { + /* If it's an array, store it */ + if (PyArray_FailUnlessWriteable((PyArrayObject *)obj, + "output array") < 0) { + return -1; + } + Py_INCREF(obj); + *store = (PyArrayObject *)obj; + + return 0; + } + PyErr_SetString(PyExc_TypeError, "return arrays must be of ArrayType"); + + return -1; +} + +/********* GENERIC UFUNC USING ITERATOR *********/ + +/* + * Produce a name for the ufunc, if one is not already set + * This is used in the PyUFunc_handlefperr machinery, and in error messages + */ +NPY_NO_EXPORT const char* +ufunc_get_name_cstr(PyUFuncObject *ufunc) { + return ufunc->name ? ufunc->name : ""; +} + +/* + * Parses the positional and keyword arguments for a generic ufunc call. + * + * Note that if an error is returned, the caller must free the + * non-zero references in out_op. This + * function does not do its own clean-up. + */ +static int +get_ufunc_arguments(PyUFuncObject *ufunc, + PyObject *args, PyObject *kwds, + PyArrayObject **out_op, + NPY_ORDER *out_order, + NPY_CASTING *out_casting, + PyObject **out_extobj, + PyObject **out_typetup, + int *out_subok, + PyArrayObject **out_wheremask) +{ + int i, nargs; + int nin = ufunc->nin; + int nout = ufunc->nout; + PyObject *obj, *context; + PyObject *str_key_obj = NULL; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + int type_num; + + int any_flexible = 0, any_object = 0, any_flexible_userloops = 0; + int has_sig = 0; + + *out_extobj = NULL; + *out_typetup = NULL; + if (out_wheremask != NULL) { + *out_wheremask = NULL; + } + + /* Check number of arguments */ + nargs = PyTuple_Size(args); + if ((nargs < nin) || (nargs > ufunc->nargs)) { + PyErr_SetString(PyExc_ValueError, "invalid number of arguments"); + return -1; + } + + /* Get input arguments */ + for (i = 0; i < nin; ++i) { + obj = PyTuple_GET_ITEM(args, i); + + if (PyArray_Check(obj)) { + PyArrayObject *obj_a = (PyArrayObject *)obj; + out_op[i] = (PyArrayObject *)PyArray_FromArray(obj_a, NULL, 0); + } + else { + if (!PyArray_IsScalar(obj, Generic)) { + /* + * TODO: There should be a comment here explaining what + * context does. + */ + context = Py_BuildValue("OOi", ufunc, args, i); + if (context == NULL) { + return -1; + } + } + else { + context = NULL; + } + out_op[i] = (PyArrayObject *)PyArray_FromAny(obj, + NULL, 0, 0, 0, context); + Py_XDECREF(context); + } + + if (out_op[i] == NULL) { + return -1; + } + + type_num = PyArray_DESCR(out_op[i])->type_num; + if (!any_flexible && + PyTypeNum_ISFLEXIBLE(type_num)) { + any_flexible = 1; + } + if (!any_object && + PyTypeNum_ISOBJECT(type_num)) { + any_object = 1; + } + + /* + * If any operand is a flexible dtype, check to see if any + * struct dtype ufuncs are registered. A ufunc has been registered + * for a struct dtype if ufunc's arg_dtypes array is not NULL. + */ + if (PyTypeNum_ISFLEXIBLE(type_num) && + !any_flexible_userloops && + ufunc->userloops != NULL) { + PyUFunc_Loop1d *funcdata; + PyObject *key, *obj; + key = PyInt_FromLong(type_num); + if (key == NULL) { + continue; + } + obj = PyDict_GetItem(ufunc->userloops, key); + Py_DECREF(key); + if (obj == NULL) { + continue; + } + funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj); + while (funcdata != NULL) { + if (funcdata->arg_dtypes != NULL) { + any_flexible_userloops = 1; + break; + } + funcdata = funcdata->next; + } + } + } + + if (any_flexible && !any_flexible_userloops && !any_object) { + /* Traditionally, we return -2 here (meaning "NotImplemented") anytime + * we hit the above condition. + * + * This condition basically means "we are doomed", b/c the "flexible" + * dtypes -- strings and void -- cannot have their own ufunc loops + * registered (except via the special "flexible userloops" mechanism), + * and they can't be cast to anything except object (and we only cast + * to object if any_object is true). So really we should do nothing + * here and continue and let the proper error be raised. But, we can't + * quite yet, b/c of backcompat. + * + * Most of the time, this NotImplemented either got returned directly + * to the user (who can't do anything useful with it), or got passed + * back out of a special function like __mul__. And fortunately, for + * almost all special functions, the end result of this was a + * TypeError. Which is also what we get if we just continue without + * this special case, so this special case is unnecessary. + * + * The only thing that actually depended on the NotImplemented is + * array_richcompare, which did two things with it. First, it needed + * to see this NotImplemented in order to implement the special-case + * comparisons for + * + * string < <= == != >= > string + * void == != void + * + * Now it checks for those cases first, before trying to call the + * ufunc, so that's no problem. What it doesn't handle, though, is + * cases like + * + * float < string + * + * or + * + * float == void + * + * For those, it just let the NotImplemented bubble out, and accepted + * Python's default handling. And unfortunately, for comparisons, + * Python's default is *not* to raise an error. Instead, it returns + * something that depends on the operator: + * + * == return False + * != return True + * < <= >= > Python 2: use "fallback" (= weird and broken) ordering + * Python 3: raise TypeError (hallelujah) + * + * In most cases this is straightforwardly broken, because comparison + * of two arrays should always return an array, and here we end up + * returning a scalar. However, there is an exception: if we are + * comparing two scalars for equality, then it actually is correct to + * return a scalar bool instead of raising an error. If we just + * removed this special check entirely, then "np.float64(1) == 'foo'" + * would raise an error instead of returning False, which is genuinely + * wrong. + * + * The proper end goal here is: + * 1) == and != should be implemented in a proper vectorized way for + * all types. The short-term hack for this is just to add a + * special case to PyUFunc_DefaultLegacyInnerLoopSelector where + * if it can't find a comparison loop for the given types, and + * the ufunc is np.equal or np.not_equal, then it returns a loop + * that just fills the output array with False (resp. True). Then + * array_richcompare could trust that whenever its special cases + * don't apply, simply calling the ufunc will do the right thing, + * even without this special check. + * 2) < <= >= > should raise an error if no comparison function can + * be found. array_richcompare already handles all string <> + * string cases, and void dtypes don't have ordering, so again + * this would mean that array_richcompare could simply call the + * ufunc and it would do the right thing (i.e., raise an error), + * again without needing this special check. + * + * So this means that for the transition period, our goal is: + * == and != on scalars should simply return NotImplemented like + * they always did, since everything ends up working out correctly + * in this case only + * == and != on arrays should issue a FutureWarning and then return + * NotImplemented + * < <= >= > on all flexible dtypes on py2 should raise a + * DeprecationWarning, and then return NotImplemented. On py3 we + * skip the warning, though, b/c it would just be immediately be + * followed by an exception anyway. + * + * And for all other operations, we let things continue as normal. + */ + /* strcmp() is a hack but I think we can get away with it for this + * temporary measure. + */ + if (!strcmp(ufunc_name, "equal") || + !strcmp(ufunc_name, "not_equal")) { + /* Warn on non-scalar, return NotImplemented regardless */ + assert(nin == 2); + if (PyArray_NDIM(out_op[0]) != 0 || + PyArray_NDIM(out_op[1]) != 0) { + if (DEPRECATE_FUTUREWARNING( + "elementwise comparison failed; returning scalar " + "instead, but in the future will perform elementwise " + "comparison") < 0) { + return -1; + } + } + return -2; + } + else if (!strcmp(ufunc_name, "less") || + !strcmp(ufunc_name, "less_equal") || + !strcmp(ufunc_name, "greater") || + !strcmp(ufunc_name, "greater_equal")) { +#if !defined(NPY_PY3K) + if (DEPRECATE("unorderable dtypes; returning scalar but in " + "the future this will be an error") < 0) { + return -1; + } +#endif + return -2; + } + } + + /* Get positional output arguments */ + for (i = nin; i < nargs; ++i) { + obj = PyTuple_GET_ITEM(args, i); + if (_set_out_array(obj, out_op + i) < 0) { + return -1; + } + } + + /* + * Get keyword output and other arguments. + * Raise an error if anything else is present in the + * keyword dictionary. + */ + if (kwds != NULL) { + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(kwds, &pos, &key, &value)) { + Py_ssize_t length = 0; + char *str = NULL; + int bad_arg = 1; + +#if defined(NPY_PY3K) + Py_XDECREF(str_key_obj); + str_key_obj = PyUnicode_AsASCIIString(key); + if (str_key_obj != NULL) { + key = str_key_obj; + } +#endif + + if (PyBytes_AsStringAndSize(key, &str, &length) < 0) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "invalid keyword argument"); + goto fail; + } + + switch (str[0]) { + case 'c': + /* Provides a policy for allowed casting */ + if (strcmp(str, "casting") == 0) { + if (!PyArray_CastingConverter(value, out_casting)) { + goto fail; + } + bad_arg = 0; + } + break; + case 'd': + /* Another way to specify 'sig' */ + if (strcmp(str, "dtype") == 0) { + /* Allow this parameter to be None */ + PyArray_Descr *dtype; + if (!PyArray_DescrConverter2(value, &dtype)) { + goto fail; + } + if (dtype != NULL) { + if (*out_typetup != NULL) { + PyErr_SetString(PyExc_RuntimeError, + "cannot specify both 'sig' and 'dtype'"); + goto fail; + } + *out_typetup = Py_BuildValue("(N)", dtype); + } + bad_arg = 0; + } + break; + case 'e': + /* + * Overrides the global parameters buffer size, + * error mask, and error object + */ + if (strcmp(str, "extobj") == 0) { + *out_extobj = value; + bad_arg = 0; + } + break; + case 'o': + /* + * Output arrays may be specified as a keyword argument, + * either as a single array or None for single output + * ufuncs, or as a tuple of arrays and Nones. + */ + if (strcmp(str, "out") == 0) { + if (nargs > nin) { + PyErr_SetString(PyExc_ValueError, + "cannot specify 'out' as both a " + "positional and keyword argument"); + goto fail; + } + if (PyTuple_CheckExact(value)) { + if (PyTuple_GET_SIZE(value) != nout) { + PyErr_SetString(PyExc_ValueError, + "The 'out' tuple must have exactly " + "one entry per ufunc output"); + goto fail; + } + /* 'out' must be a tuple of arrays and Nones */ + for(i = 0; i < nout; ++i) { + PyObject *val = PyTuple_GET_ITEM(value, i); + if (_set_out_array(val, out_op+nin+i) < 0) { + goto fail; + } + } + } + else if (nout == 1) { + /* Can be an array if it only has one output */ + if (_set_out_array(value, out_op + nin) < 0) { + goto fail; + } + } + else { + /* + * If the deprecated behavior is ever removed, + * keep only the else branch of this if-else + */ + if (PyArray_Check(value) || value == Py_None) { + if (DEPRECATE("passing a single array to the " + "'out' keyword argument of a " + "ufunc with\n" + "more than one output will " + "result in an error in the " + "future") < 0) { + /* The future error message */ + PyErr_SetString(PyExc_TypeError, + "'out' must be a tuple of arrays"); + goto fail; + } + if (_set_out_array(value, out_op+nin) < 0) { + goto fail; + } + } + else { + PyErr_SetString(PyExc_TypeError, + nout > 1 ? "'out' must be a tuple " + "of arrays" : + "'out' must be an array or a " + "tuple of a single array"); + goto fail; + } + } + bad_arg = 0; + } + /* Allows the default output layout to be overridden */ + else if (strcmp(str, "order") == 0) { + if (!PyArray_OrderConverter(value, out_order)) { + goto fail; + } + bad_arg = 0; + } + break; + case 's': + /* Allows a specific function inner loop to be selected */ + if (strcmp(str, "sig") == 0 || + strcmp(str, "signature") == 0) { + if (has_sig == 1) { + PyErr_SetString(PyExc_ValueError, + "cannot specify both 'sig' and 'signature'"); + goto fail; + } + if (*out_typetup != NULL) { + PyErr_SetString(PyExc_RuntimeError, + "cannot specify both 'sig' and 'dtype'"); + goto fail; + } + *out_typetup = value; + Py_INCREF(value); + bad_arg = 0; + has_sig = 1; + } + else if (strcmp(str, "subok") == 0) { + if (!PyBool_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "'subok' must be a boolean"); + goto fail; + } + *out_subok = (value == Py_True); + bad_arg = 0; + } + break; + case 'w': + /* + * Provides a boolean array 'where=' mask if + * out_wheremask is supplied. + */ + if (out_wheremask != NULL && strcmp(str, "where") == 0) { + PyArray_Descr *dtype; + dtype = PyArray_DescrFromType(NPY_BOOL); + if (dtype == NULL) { + goto fail; + } + if (value == Py_True) { + /* + * Optimization: where=True is the same as no + * where argument. This lets us document it as a + * default argument + */ + bad_arg = 0; + break; + } + *out_wheremask = (PyArrayObject *)PyArray_FromAny( + value, dtype, + 0, 0, 0, NULL); + if (*out_wheremask == NULL) { + goto fail; + } + bad_arg = 0; + } + break; + } + + if (bad_arg) { + char *format = "'%s' is an invalid keyword to ufunc '%s'"; + PyErr_Format(PyExc_TypeError, format, str, ufunc_name); + goto fail; + } + } + } + Py_XDECREF(str_key_obj); + + return 0; + +fail: + Py_XDECREF(str_key_obj); + Py_XDECREF(*out_extobj); + *out_extobj = NULL; + Py_XDECREF(*out_typetup); + *out_typetup = NULL; + if (out_wheremask != NULL) { + Py_XDECREF(*out_wheremask); + *out_wheremask = NULL; + } + return -1; +} + +/* + * This checks whether a trivial loop is ok, + * making copies of scalar and one dimensional operands if that will + * help. + * + * Returns 1 if a trivial loop is ok, 0 if it is not, and + * -1 if there is an error. + */ +static int +check_for_trivial_loop(PyUFuncObject *ufunc, + PyArrayObject **op, + PyArray_Descr **dtype, + npy_intp buffersize) +{ + npy_intp i, nin = ufunc->nin, nop = nin + ufunc->nout; + + for (i = 0; i < nop; ++i) { + /* + * If the dtype doesn't match, or the array isn't aligned, + * indicate that the trivial loop can't be done. + */ + if (op[i] != NULL && + (!PyArray_ISALIGNED(op[i]) || + !PyArray_EquivTypes(dtype[i], PyArray_DESCR(op[i])) + )) { + /* + * If op[j] is a scalar or small one dimensional + * array input, make a copy to keep the opportunity + * for a trivial loop. + */ + if (i < nin && (PyArray_NDIM(op[i]) == 0 || + (PyArray_NDIM(op[i]) == 1 && + PyArray_DIM(op[i],0) <= buffersize))) { + PyArrayObject *tmp; + Py_INCREF(dtype[i]); + tmp = (PyArrayObject *) + PyArray_CastToType(op[i], dtype[i], 0); + if (tmp == NULL) { + return -1; + } + Py_DECREF(op[i]); + op[i] = tmp; + } + else { + return 0; + } + } + } + + return 1; +} + +static void +trivial_two_operand_loop(PyArrayObject **op, + PyUFuncGenericFunction innerloop, + void *innerloopdata) +{ + char *data[2]; + npy_intp count[2], stride[2]; + int needs_api; + NPY_BEGIN_THREADS_DEF; + + needs_api = PyDataType_REFCHK(PyArray_DESCR(op[0])) || + PyDataType_REFCHK(PyArray_DESCR(op[1])); + + PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(op[0], op[1], + count[0], + data[0], data[1], + stride[0], stride[1]); + count[1] = count[0]; + NPY_UF_DBG_PRINT1("two operand loop count %d\n", (int)count[0]); + + if (!needs_api) { + NPY_BEGIN_THREADS_THRESHOLDED(count[0]); + } + + innerloop(data, count, stride, innerloopdata); + + NPY_END_THREADS; +} + +static void +trivial_three_operand_loop(PyArrayObject **op, + PyUFuncGenericFunction innerloop, + void *innerloopdata) +{ + char *data[3]; + npy_intp count[3], stride[3]; + int needs_api; + NPY_BEGIN_THREADS_DEF; + + needs_api = PyDataType_REFCHK(PyArray_DESCR(op[0])) || + PyDataType_REFCHK(PyArray_DESCR(op[1])) || + PyDataType_REFCHK(PyArray_DESCR(op[2])); + + PyArray_PREPARE_TRIVIAL_TRIPLE_ITERATION(op[0], op[1], op[2], + count[0], + data[0], data[1], data[2], + stride[0], stride[1], stride[2]); + count[1] = count[0]; + count[2] = count[0]; + NPY_UF_DBG_PRINT1("three operand loop count %d\n", (int)count[0]); + + if (!needs_api) { + NPY_BEGIN_THREADS_THRESHOLDED(count[0]); + } + + innerloop(data, count, stride, innerloopdata); + + NPY_END_THREADS; +} + +/* + * Calls the given __array_prepare__ function on the operand *op, + * substituting it in place if a new array is returned and matches + * the old one. + * + * This requires that the dimensions, strides and data type remain + * exactly the same, which may be more strict than before. + */ +static int +prepare_ufunc_output(PyUFuncObject *ufunc, + PyArrayObject **op, + PyObject *arr_prep, + PyObject *arr_prep_args, + int i) +{ + if (arr_prep != NULL && arr_prep != Py_None) { + PyObject *res; + PyArrayObject *arr; + + res = PyObject_CallFunction(arr_prep, "O(OOi)", + *op, ufunc, arr_prep_args, i); + if ((res == NULL) || (res == Py_None) || !PyArray_Check(res)) { + if (!PyErr_Occurred()){ + PyErr_SetString(PyExc_TypeError, + "__array_prepare__ must return an " + "ndarray or subclass thereof"); + } + Py_XDECREF(res); + return -1; + } + arr = (PyArrayObject *)res; + + /* If the same object was returned, nothing to do */ + if (arr == *op) { + Py_DECREF(arr); + } + /* If the result doesn't match, throw an error */ + else if (PyArray_NDIM(arr) != PyArray_NDIM(*op) || + !PyArray_CompareLists(PyArray_DIMS(arr), + PyArray_DIMS(*op), + PyArray_NDIM(arr)) || + !PyArray_CompareLists(PyArray_STRIDES(arr), + PyArray_STRIDES(*op), + PyArray_NDIM(arr)) || + !PyArray_EquivTypes(PyArray_DESCR(arr), + PyArray_DESCR(*op))) { + PyErr_SetString(PyExc_TypeError, + "__array_prepare__ must return an " + "ndarray or subclass thereof which is " + "otherwise identical to its input"); + Py_DECREF(arr); + return -1; + } + /* Replace the op value */ + else { + Py_DECREF(*op); + *op = arr; + } + } + + return 0; +} + +static int +iterator_loop(PyUFuncObject *ufunc, + PyArrayObject **op, + PyArray_Descr **dtype, + NPY_ORDER order, + npy_intp buffersize, + PyObject **arr_prep, + PyObject *arr_prep_args, + PyUFuncGenericFunction innerloop, + void *innerloopdata) +{ + npy_intp i, iop, nin = ufunc->nin, nout = ufunc->nout; + npy_intp nop = nin + nout; + npy_uint32 op_flags[NPY_MAXARGS]; + NpyIter *iter; + char *baseptrs[NPY_MAXARGS]; + + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *stride; + npy_intp *count_ptr; + + PyArrayObject **op_it; + npy_uint32 iter_flags; + + NPY_BEGIN_THREADS_DEF; + + /* Set up the flags */ + for (i = 0; i < nin; ++i) { + op_flags[i] = NPY_ITER_READONLY | + NPY_ITER_ALIGNED | + NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE; + /* + * If READWRITE flag has been set for this operand, + * then clear default READONLY flag + */ + op_flags[i] |= ufunc->op_flags[i]; + if (op_flags[i] & (NPY_ITER_READWRITE | NPY_ITER_WRITEONLY)) { + op_flags[i] &= ~NPY_ITER_READONLY; + } + } + for (i = nin; i < nop; ++i) { + op_flags[i] = NPY_ITER_WRITEONLY | + NPY_ITER_ALIGNED | + NPY_ITER_ALLOCATE | + NPY_ITER_NO_BROADCAST | + NPY_ITER_NO_SUBTYPE | + NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE; + } + + iter_flags = ufunc->iter_flags | + NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_REFS_OK | + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_BUFFERED | + NPY_ITER_GROWINNER | + NPY_ITER_DELAY_BUFALLOC | + NPY_ITER_COPY_IF_OVERLAP; + + /* Call the __array_prepare__ functions for already existing output arrays. + * Do this before creating the iterator, as the iterator may UPDATEIFCOPY + * some of them. + */ + for (i = 0; i < nout; ++i) { + if (op[nin+i] == NULL) { + continue; + } + if (prepare_ufunc_output(ufunc, &op[nin+i], + arr_prep[i], arr_prep_args, i) < 0) { + return -1; + } + } + + /* + * Allocate the iterator. Because the types of the inputs + * were already checked, we use the casting rule 'unsafe' which + * is faster to calculate. + */ + iter = NpyIter_AdvancedNew(nop, op, + iter_flags, + order, NPY_UNSAFE_CASTING, + op_flags, dtype, + -1, NULL, NULL, buffersize); + if (iter == NULL) { + return -1; + } + + /* Copy any allocated outputs */ + op_it = NpyIter_GetOperandArray(iter); + for (i = 0; i < nout; ++i) { + if (op[nin+i] == NULL) { + op[nin+i] = op_it[nin+i]; + Py_INCREF(op[nin+i]); + + /* Call the __array_prepare__ functions for the new array */ + if (prepare_ufunc_output(ufunc, &op[nin+i], + arr_prep[i], arr_prep_args, i) < 0) { + for(iop = 0; iop < nin+i; ++iop) { + if (op_it[iop] != op[iop]) { + /* ignore errrors */ + PyArray_ResolveWritebackIfCopy(op_it[iop]); + } + } + NpyIter_Deallocate(iter); + return -1; + } + + /* + * In case __array_prepare__ returned a different array, put the + * results directly there, ignoring the array allocated by the + * iterator. + * + * Here, we assume the user-provided __array_prepare__ behaves + * sensibly and doesn't return an array overlapping in memory + * with other operands --- the op[nin+i] array passed to it is newly + * allocated and doesn't have any overlap. + */ + baseptrs[nin+i] = PyArray_BYTES(op[nin+i]); + } + else { + baseptrs[nin+i] = PyArray_BYTES(op_it[nin+i]); + } + } + + /* Only do the loop if the iteration size is non-zero */ + if (NpyIter_GetIterSize(iter) != 0) { + /* Reset the iterator with the base pointers from possible __array_prepare__ */ + for (i = 0; i < nin; ++i) { + baseptrs[i] = PyArray_BYTES(op_it[i]); + } + if (NpyIter_ResetBasePointers(iter, baseptrs, NULL) != NPY_SUCCEED) { + NpyIter_Deallocate(iter); + return -1; + } + + /* Get the variables needed for the loop */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + return -1; + } + dataptr = NpyIter_GetDataPtrArray(iter); + stride = NpyIter_GetInnerStrideArray(iter); + count_ptr = NpyIter_GetInnerLoopSizePtr(iter); + + NPY_BEGIN_THREADS_NDITER(iter); + + /* Execute the loop */ + do { + NPY_UF_DBG_PRINT1("iterator loop count %d\n", (int)*count_ptr); + innerloop(dataptr, count_ptr, stride, innerloopdata); + } while (iternext(iter)); + + NPY_END_THREADS; + } + for(iop = 0; iop < nop; ++iop) { + if (op_it[iop] != op[iop]) { + PyArray_ResolveWritebackIfCopy(op_it[iop]); + } + } + NpyIter_Deallocate(iter); + return 0; +} + +/* + * trivial_loop_ok - 1 if no alignment, data conversion, etc required + * nin - number of inputs + * nout - number of outputs + * op - the operands (nin + nout of them) + * order - the loop execution order/output memory order + * buffersize - how big of a buffer to use + * arr_prep - the __array_prepare__ functions for the outputs + * innerloop - the inner loop function + * innerloopdata - data to pass to the inner loop + */ +static int +execute_legacy_ufunc_loop(PyUFuncObject *ufunc, + int trivial_loop_ok, + PyArrayObject **op, + PyArray_Descr **dtypes, + NPY_ORDER order, + npy_intp buffersize, + PyObject **arr_prep, + PyObject *arr_prep_args) +{ + npy_intp nin = ufunc->nin, nout = ufunc->nout; + PyUFuncGenericFunction innerloop; + void *innerloopdata; + int needs_api = 0; + + if (ufunc->legacy_inner_loop_selector(ufunc, dtypes, + &innerloop, &innerloopdata, &needs_api) < 0) { + return -1; + } + /* If the loop wants the arrays, provide them. */ + if (_does_loop_use_arrays(innerloopdata)) { + innerloopdata = (void*)op; + } + + /* First check for the trivial cases that don't need an iterator */ + if (trivial_loop_ok) { + if (nin == 1 && nout == 1) { + if (op[1] == NULL && + (order == NPY_ANYORDER || order == NPY_KEEPORDER) && + PyArray_TRIVIALLY_ITERABLE(op[0])) { + Py_INCREF(dtypes[1]); + op[1] = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + dtypes[1], + PyArray_NDIM(op[0]), + PyArray_DIMS(op[0]), + NULL, NULL, + PyArray_ISFORTRAN(op[0]) ? + NPY_ARRAY_F_CONTIGUOUS : 0, + NULL); + if (op[1] == NULL) { + return -1; + } + + /* Call the __prepare_array__ if necessary */ + if (prepare_ufunc_output(ufunc, &op[1], + arr_prep[0], arr_prep_args, 0) < 0) { + return -1; + } + + NPY_UF_DBG_PRINT("trivial 1 input with allocated output\n"); + trivial_two_operand_loop(op, innerloop, innerloopdata); + + return 0; + } + else if (op[1] != NULL && + PyArray_NDIM(op[1]) >= PyArray_NDIM(op[0]) && + PyArray_TRIVIALLY_ITERABLE_PAIR(op[0], op[1], + PyArray_TRIVIALLY_ITERABLE_OP_READ, + PyArray_TRIVIALLY_ITERABLE_OP_NOREAD)) { + + /* Call the __prepare_array__ if necessary */ + if (prepare_ufunc_output(ufunc, &op[1], + arr_prep[0], arr_prep_args, 0) < 0) { + return -1; + } + + NPY_UF_DBG_PRINT("trivial 1 input\n"); + trivial_two_operand_loop(op, innerloop, innerloopdata); + + return 0; + } + } + else if (nin == 2 && nout == 1) { + if (op[2] == NULL && + (order == NPY_ANYORDER || order == NPY_KEEPORDER) && + PyArray_TRIVIALLY_ITERABLE_PAIR(op[0], op[1], + PyArray_TRIVIALLY_ITERABLE_OP_READ, + PyArray_TRIVIALLY_ITERABLE_OP_READ)) { + PyArrayObject *tmp; + /* + * Have to choose the input with more dimensions to clone, as + * one of them could be a scalar. + */ + if (PyArray_NDIM(op[0]) >= PyArray_NDIM(op[1])) { + tmp = op[0]; + } + else { + tmp = op[1]; + } + Py_INCREF(dtypes[2]); + op[2] = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, + dtypes[2], + PyArray_NDIM(tmp), + PyArray_DIMS(tmp), + NULL, NULL, + PyArray_ISFORTRAN(tmp) ? + NPY_ARRAY_F_CONTIGUOUS : 0, + NULL); + if (op[2] == NULL) { + return -1; + } + + /* Call the __prepare_array__ if necessary */ + if (prepare_ufunc_output(ufunc, &op[2], + arr_prep[0], arr_prep_args, 0) < 0) { + return -1; + } + + NPY_UF_DBG_PRINT("trivial 2 input with allocated output\n"); + trivial_three_operand_loop(op, innerloop, innerloopdata); + + return 0; + } + else if (op[2] != NULL && + PyArray_NDIM(op[2]) >= PyArray_NDIM(op[0]) && + PyArray_NDIM(op[2]) >= PyArray_NDIM(op[1]) && + PyArray_TRIVIALLY_ITERABLE_TRIPLE(op[0], op[1], op[2], + PyArray_TRIVIALLY_ITERABLE_OP_READ, + PyArray_TRIVIALLY_ITERABLE_OP_READ, + PyArray_TRIVIALLY_ITERABLE_OP_NOREAD)) { + + /* Call the __prepare_array__ if necessary */ + if (prepare_ufunc_output(ufunc, &op[2], + arr_prep[0], arr_prep_args, 0) < 0) { + return -1; + } + + NPY_UF_DBG_PRINT("trivial 2 input\n"); + trivial_three_operand_loop(op, innerloop, innerloopdata); + + return 0; + } + } + } + + /* + * If no trivial loop matched, an iterator is required to + * resolve broadcasting, etc + */ + + NPY_UF_DBG_PRINT("iterator loop\n"); + if (iterator_loop(ufunc, op, dtypes, order, + buffersize, arr_prep, arr_prep_args, + innerloop, innerloopdata) < 0) { + return -1; + } + + return 0; +} + +/* + * nin - number of inputs + * nout - number of outputs + * wheremask - if not NULL, the 'where=' parameter to the ufunc. + * op - the operands (nin + nout of them) + * order - the loop execution order/output memory order + * buffersize - how big of a buffer to use + * arr_prep - the __array_prepare__ functions for the outputs + * innerloop - the inner loop function + * innerloopdata - data to pass to the inner loop + */ +static int +execute_fancy_ufunc_loop(PyUFuncObject *ufunc, + PyArrayObject *wheremask, + PyArrayObject **op, + PyArray_Descr **dtypes, + NPY_ORDER order, + npy_intp buffersize, + PyObject **arr_prep, + PyObject *arr_prep_args) +{ + int retval, i, nin = ufunc->nin, nout = ufunc->nout; + int nop = nin + nout; + npy_uint32 op_flags[NPY_MAXARGS]; + NpyIter *iter; + int needs_api; + npy_intp default_op_in_flags = 0, default_op_out_flags = 0; + + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *strides; + npy_intp *countptr; + + PyArrayObject **op_it; + npy_uint32 iter_flags; + + if (wheremask != NULL) { + if (nop + 1 > NPY_MAXARGS) { + PyErr_SetString(PyExc_ValueError, + "Too many operands when including where= parameter"); + return -1; + } + op[nop] = wheremask; + dtypes[nop] = NULL; + default_op_out_flags |= NPY_ITER_WRITEMASKED; + } + + /* Set up the flags */ + for (i = 0; i < nin; ++i) { + op_flags[i] = default_op_in_flags | + NPY_ITER_READONLY | + NPY_ITER_ALIGNED | + NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE; + /* + * If READWRITE flag has been set for this operand, + * then clear default READONLY flag + */ + op_flags[i] |= ufunc->op_flags[i]; + if (op_flags[i] & (NPY_ITER_READWRITE | NPY_ITER_WRITEONLY)) { + op_flags[i] &= ~NPY_ITER_READONLY; + } + } + for (i = nin; i < nop; ++i) { + /* + * We don't write to all elements, and the iterator may make + * UPDATEIFCOPY temporary copies. The output arrays (unless they are + * allocated by the iterator itself) must be considered READWRITE by the + * iterator, so that the elements we don't write to are copied to the + * possible temporary array. + */ + op_flags[i] = default_op_out_flags | + (op[i] != NULL ? NPY_ITER_READWRITE : NPY_ITER_WRITEONLY) | + NPY_ITER_ALIGNED | + NPY_ITER_ALLOCATE | + NPY_ITER_NO_BROADCAST | + NPY_ITER_NO_SUBTYPE | + NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE; + } + if (wheremask != NULL) { + op_flags[nop] = NPY_ITER_READONLY | NPY_ITER_ARRAYMASK; + } + + NPY_UF_DBG_PRINT("Making iterator\n"); + + iter_flags = ufunc->iter_flags | + NPY_ITER_EXTERNAL_LOOP | + NPY_ITER_REFS_OK | + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_BUFFERED | + NPY_ITER_GROWINNER | + NPY_ITER_COPY_IF_OVERLAP; + + /* + * Allocate the iterator. Because the types of the inputs + * were already checked, we use the casting rule 'unsafe' which + * is faster to calculate. + */ + iter = NpyIter_AdvancedNew(nop + ((wheremask != NULL) ? 1 : 0), op, + iter_flags, + order, NPY_UNSAFE_CASTING, + op_flags, dtypes, + -1, NULL, NULL, buffersize); + if (iter == NULL) { + return -1; + } + + NPY_UF_DBG_PRINT("Made iterator\n"); + + needs_api = NpyIter_IterationNeedsAPI(iter); + + /* Call the __array_prepare__ functions where necessary */ + op_it = NpyIter_GetOperandArray(iter); + for (i = nin; i < nop; ++i) { + PyArrayObject *op_tmp, *orig_op_tmp; + + /* + * The array can be allocated by the iterator -- it is placed in op[i] + * and returned to the caller, and this needs an extra incref. + */ + if (op[i] == NULL) { + op_tmp = op_it[i]; + Py_INCREF(op_tmp); + } + else { + op_tmp = op[i]; + } + + /* prepare_ufunc_output may decref & replace the pointer */ + orig_op_tmp = op_tmp; + Py_INCREF(op_tmp); + + if (prepare_ufunc_output(ufunc, &op_tmp, + arr_prep[i], arr_prep_args, i) < 0) { + NpyIter_Deallocate(iter); + return -1; + } + + /* Validate that the prepare_ufunc_output didn't mess with pointers */ + if (PyArray_BYTES(op_tmp) != PyArray_BYTES(orig_op_tmp)) { + PyErr_SetString(PyExc_ValueError, + "The __array_prepare__ functions modified the data " + "pointer addresses in an invalid fashion"); + Py_DECREF(op_tmp); + NpyIter_Deallocate(iter); + return -1; + } + + /* + * Put the updated operand back and undo the DECREF above. If + * COPY_IF_OVERLAP made a temporary copy, the output will be copied + * by UPDATEIFCOPY even if op[i] was changed by prepare_ufunc_output. + */ + op[i] = op_tmp; + Py_DECREF(op_tmp); + } + + /* Only do the loop if the iteration size is non-zero */ + if (NpyIter_GetIterSize(iter) != 0) { + PyUFunc_MaskedStridedInnerLoopFunc *innerloop; + NpyAuxData *innerloopdata; + npy_intp fixed_strides[2*NPY_MAXARGS]; + PyArray_Descr **iter_dtypes; + NPY_BEGIN_THREADS_DEF; + + /* + * Get the inner loop, with the possibility of specialization + * based on the fixed strides. + */ + NpyIter_GetInnerFixedStrideArray(iter, fixed_strides); + iter_dtypes = NpyIter_GetDescrArray(iter); + if (ufunc->masked_inner_loop_selector(ufunc, dtypes, + wheremask != NULL ? iter_dtypes[nop] + : iter_dtypes[nop + nin], + fixed_strides, + wheremask != NULL ? fixed_strides[nop] + : fixed_strides[nop + nin], + &innerloop, &innerloopdata, &needs_api) < 0) { + NpyIter_Deallocate(iter); + return -1; + } + + /* Get the variables needed for the loop */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter); + return -1; + } + dataptr = NpyIter_GetDataPtrArray(iter); + strides = NpyIter_GetInnerStrideArray(iter); + countptr = NpyIter_GetInnerLoopSizePtr(iter); + + NPY_BEGIN_THREADS_NDITER(iter); + + NPY_UF_DBG_PRINT("Actual inner loop:\n"); + /* Execute the loop */ + do { + NPY_UF_DBG_PRINT1("iterator loop count %d\n", (int)*countptr); + innerloop(dataptr, strides, + dataptr[nop], strides[nop], + *countptr, innerloopdata); + } while (iternext(iter)); + + NPY_END_THREADS; + + NPY_AUXDATA_FREE(innerloopdata); + } + + retval = 0; + nop = NpyIter_GetNOp(iter); + for(i=0; i< nop; ++i) { + if (PyArray_ResolveWritebackIfCopy(NpyIter_GetOperandArray(iter)[i]) < 0) { + retval = -1; + } + } + + NpyIter_Deallocate(iter); + return retval; +} + +static PyObject * +make_arr_prep_args(npy_intp nin, PyObject *args, PyObject *kwds) +{ + PyObject *out = kwds ? PyDict_GetItem(kwds, npy_um_str_out) : NULL; + PyObject *arr_prep_args; + + if (out == NULL) { + Py_INCREF(args); + return args; + } + else { + npy_intp i, nargs = PyTuple_GET_SIZE(args), n; + n = nargs; + if (n < nin + 1) { + n = nin + 1; + } + arr_prep_args = PyTuple_New(n); + if (arr_prep_args == NULL) { + return NULL; + } + /* Copy the tuple, but set the nin-th item to the keyword arg */ + for (i = 0; i < nin; ++i) { + PyObject *item = PyTuple_GET_ITEM(args, i); + Py_INCREF(item); + PyTuple_SET_ITEM(arr_prep_args, i, item); + } + Py_INCREF(out); + PyTuple_SET_ITEM(arr_prep_args, nin, out); + for (i = nin+1; i < n; ++i) { + PyObject *item = PyTuple_GET_ITEM(args, i); + Py_INCREF(item); + PyTuple_SET_ITEM(arr_prep_args, i, item); + } + + return arr_prep_args; + } +} + +/* + * Validate the core dimensions of all the operands, and collect all of + * the labelled core dimensions into 'core_dim_sizes'. + * + * Returns 0 on success, and -1 on failure + * + * The behavior has been changed in NumPy 1.10.0, and the following + * requirements must be fulfilled or an error will be raised: + * * Arguments, both input and output, must have at least as many + * dimensions as the corresponding number of core dimensions. In + * previous versions, 1's were prepended to the shape as needed. + * * Core dimensions with same labels must have exactly matching sizes. + * In previous versions, core dimensions of size 1 would broadcast + * against other core dimensions with the same label. + * * All core dimensions must have their size specified by a passed in + * input or output argument. In previous versions, core dimensions in + * an output argument that were not specified in an input argument, + * and whose size could not be inferred from a passed in output + * argument, would have their size set to 1. + */ +static int +_get_coredim_sizes(PyUFuncObject *ufunc, PyArrayObject **op, + npy_intp* core_dim_sizes) { + int i; + int nin = ufunc->nin; + int nout = ufunc->nout; + int nop = nin + nout; + + for (i = 0; i < ufunc->core_num_dim_ix; ++i) { + core_dim_sizes[i] = -1; + } + for (i = 0; i < nop; ++i) { + if (op[i] != NULL) { + int idim; + int dim_offset = ufunc->core_offsets[i]; + int num_dims = ufunc->core_num_dims[i]; + int core_start_dim = PyArray_NDIM(op[i]) - num_dims; + + /* Check if operands have enough dimensions */ + if (core_start_dim < 0) { + PyErr_Format(PyExc_ValueError, + "%s: %s operand %d does not have enough " + "dimensions (has %d, gufunc core with " + "signature %s requires %d)", + ufunc_get_name_cstr(ufunc), i < nin ? "Input" : "Output", + i < nin ? i : i - nin, PyArray_NDIM(op[i]), + ufunc->core_signature, num_dims); + return -1; + } + + /* + * Make sure every core dimension exactly matches all other core + * dimensions with the same label. + */ + for (idim = 0; idim < num_dims; ++idim) { + int core_dim_index = ufunc->core_dim_ixs[dim_offset+idim]; + npy_intp op_dim_size = + PyArray_DIM(op[i], core_start_dim+idim); + + if (core_dim_sizes[core_dim_index] == -1) { + core_dim_sizes[core_dim_index] = op_dim_size; + } + else if (op_dim_size != core_dim_sizes[core_dim_index]) { + PyErr_Format(PyExc_ValueError, + "%s: %s operand %d has a mismatch in its " + "core dimension %d, with gufunc " + "signature %s (size %zd is different " + "from %zd)", + ufunc_get_name_cstr(ufunc), i < nin ? "Input" : "Output", + i < nin ? i : i - nin, idim, + ufunc->core_signature, op_dim_size, + core_dim_sizes[core_dim_index]); + return -1; + } + } + } + } + + /* + * Make sure no core dimension is unspecified. + */ + for (i = 0; i < ufunc->core_num_dim_ix; ++i) { + if (core_dim_sizes[i] == -1) { + break; + } + } + if (i != ufunc->core_num_dim_ix) { + /* + * There is at least one core dimension missing, find in which + * operand it comes up first (it has to be an output operand). + */ + const int missing_core_dim = i; + int out_op; + for (out_op = nin; out_op < nop; ++out_op) { + int first_idx = ufunc->core_offsets[out_op]; + int last_idx = first_idx + ufunc->core_num_dims[out_op]; + for (i = first_idx; i < last_idx; ++i) { + if (ufunc->core_dim_ixs[i] == missing_core_dim) { + break; + } + } + if (i < last_idx) { + /* Change index offsets for error message */ + out_op -= nin; + i -= first_idx; + break; + } + } + PyErr_Format(PyExc_ValueError, + "%s: Output operand %d has core dimension %d " + "unspecified, with gufunc signature %s", + ufunc_get_name_cstr(ufunc), out_op, i, ufunc->core_signature); + return -1; + } + return 0; +} + +static int +PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, + PyObject *args, PyObject *kwds, + PyArrayObject **op) +{ + int nin, nout; + int i, j, idim, nop; + const char *ufunc_name; + int retval = 0, subok = 1; + int needs_api = 0; + + PyArray_Descr *dtypes[NPY_MAXARGS]; + + /* Use remapped axes for generalized ufunc */ + int broadcast_ndim, iter_ndim; + int op_axes_arrays[NPY_MAXARGS][NPY_MAXDIMS]; + int *op_axes[NPY_MAXARGS]; + + npy_uint32 op_flags[NPY_MAXARGS]; + npy_intp iter_shape[NPY_MAXARGS]; + NpyIter *iter = NULL; + npy_uint32 iter_flags; + npy_intp total_problem_size; + + /* These parameters come from extobj= or from a TLS global */ + int buffersize = 0, errormask = 0; + + /* The selected inner loop */ + PyUFuncGenericFunction innerloop = NULL; + void *innerloopdata = NULL; + /* The dimensions which get passed to the inner loop */ + npy_intp inner_dimensions[NPY_MAXDIMS+1]; + /* The strides which get passed to the inner loop */ + npy_intp *inner_strides = NULL; + + /* The sizes of the core dimensions (# entries is ufunc->core_num_dim_ix) */ + npy_intp *core_dim_sizes = inner_dimensions + 1; + int core_dim_ixs_size; + + /* The __array_prepare__ function to call for each output */ + PyObject *arr_prep[NPY_MAXARGS]; + /* + * This is either args, or args with the out= parameter from + * kwds added appropriately. + */ + PyObject *arr_prep_args = NULL; + + NPY_ORDER order = NPY_KEEPORDER; + /* Use the default assignment casting rule */ + NPY_CASTING casting = NPY_DEFAULT_ASSIGN_CASTING; + /* When provided, extobj and typetup contain borrowed references */ + PyObject *extobj = NULL, *type_tup = NULL; + + if (ufunc == NULL) { + PyErr_SetString(PyExc_ValueError, "function not supported"); + return -1; + } + + nin = ufunc->nin; + nout = ufunc->nout; + nop = nin + nout; + + ufunc_name = ufunc_get_name_cstr(ufunc); + + NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s\n", ufunc_name); + + /* Initialize all the operands and dtypes to NULL */ + for (i = 0; i < nop; ++i) { + op[i] = NULL; + dtypes[i] = NULL; + arr_prep[i] = NULL; + } + + NPY_UF_DBG_PRINT("Getting arguments\n"); + + /* Get all the arguments */ + retval = get_ufunc_arguments(ufunc, args, kwds, + op, &order, &casting, &extobj, + &type_tup, &subok, NULL); + if (retval < 0) { + goto fail; + } + + /* + * Figure out the number of iteration dimensions, which + * is the broadcast result of all the input non-core + * dimensions. + */ + broadcast_ndim = 0; + for (i = 0; i < nin; ++i) { + int n = PyArray_NDIM(op[i]) - ufunc->core_num_dims[i]; + if (n > broadcast_ndim) { + broadcast_ndim = n; + } + } + + /* + * Figure out the number of iterator creation dimensions, + * which is the broadcast dimensions + all the core dimensions of + * the outputs, so that the iterator can allocate those output + * dimensions following the rules of order='F', for example. + */ + iter_ndim = broadcast_ndim; + for (i = nin; i < nop; ++i) { + iter_ndim += ufunc->core_num_dims[i]; + } + if (iter_ndim > NPY_MAXDIMS) { + PyErr_Format(PyExc_ValueError, + "too many dimensions for generalized ufunc %s", + ufunc_name); + retval = -1; + goto fail; + } + + /* Collect the lengths of the labelled core dimensions */ + retval = _get_coredim_sizes(ufunc, op, core_dim_sizes); + if(retval < 0) { + goto fail; + } + + /* Fill in the initial part of 'iter_shape' */ + for (idim = 0; idim < broadcast_ndim; ++idim) { + iter_shape[idim] = -1; + } + + /* Fill in op_axes for all the operands */ + j = broadcast_ndim; + for (i = 0; i < nop; ++i) { + int n; + if (op[i]) { + /* + * Note that n may be negative if broadcasting + * extends into the core dimensions. + */ + n = PyArray_NDIM(op[i]) - ufunc->core_num_dims[i]; + } + else { + n = broadcast_ndim; + } + /* Broadcast all the unspecified dimensions normally */ + for (idim = 0; idim < broadcast_ndim; ++idim) { + if (idim >= broadcast_ndim - n) { + op_axes_arrays[i][idim] = idim - (broadcast_ndim - n); + } + else { + op_axes_arrays[i][idim] = -1; + } + } + + /* Any output core dimensions shape should be ignored */ + for (idim = broadcast_ndim; idim < iter_ndim; ++idim) { + op_axes_arrays[i][idim] = -1; + } + + /* Except for when it belongs to this output */ + if (i >= nin) { + int dim_offset = ufunc->core_offsets[i]; + int num_dims = ufunc->core_num_dims[i]; + /* Fill in 'iter_shape' and 'op_axes' for this output */ + for (idim = 0; idim < num_dims; ++idim) { + iter_shape[j] = core_dim_sizes[ + ufunc->core_dim_ixs[dim_offset + idim]]; + op_axes_arrays[i][j] = n + idim; + ++j; + } + } + + op_axes[i] = op_axes_arrays[i]; + } + + /* Get the buffersize and errormask */ + if (_get_bufsize_errmask(extobj, ufunc_name, &buffersize, &errormask) < 0) { + retval = -1; + goto fail; + } + + NPY_UF_DBG_PRINT("Finding inner loop\n"); + + + retval = ufunc->type_resolver(ufunc, casting, + op, type_tup, dtypes); + if (retval < 0) { + goto fail; + } + /* For the generalized ufunc, we get the loop right away too */ + retval = ufunc->legacy_inner_loop_selector(ufunc, dtypes, + &innerloop, &innerloopdata, &needs_api); + if (retval < 0) { + goto fail; + } + +#if NPY_UF_DBG_TRACING + printf("input types:\n"); + for (i = 0; i < nin; ++i) { + PyObject_Print((PyObject *)dtypes[i], stdout, 0); + printf(" "); + } + printf("\noutput types:\n"); + for (i = nin; i < nop; ++i) { + PyObject_Print((PyObject *)dtypes[i], stdout, 0); + printf(" "); + } + printf("\n"); +#endif + + if (subok) { + /* + * Get the appropriate __array_prepare__ function to call + * for each output + */ + _find_array_prepare(args, kwds, arr_prep, nin, nout, 0); + + /* Set up arr_prep_args if a prep function was needed */ + for (i = 0; i < nout; ++i) { + if (arr_prep[i] != NULL && arr_prep[i] != Py_None) { + arr_prep_args = make_arr_prep_args(nin, args, kwds); + break; + } + } + } + + /* If the loop wants the arrays, provide them */ + if (_does_loop_use_arrays(innerloopdata)) { + innerloopdata = (void*)op; + } + + /* + * Set up the iterator per-op flags. For generalized ufuncs, we + * can't do buffering, so must COPY or UPDATEIFCOPY. + */ + for (i = 0; i < nin; ++i) { + op_flags[i] = NPY_ITER_READONLY | + NPY_ITER_COPY | + NPY_ITER_ALIGNED | + NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE; + /* + * If READWRITE flag has been set for this operand, + * then clear default READONLY flag + */ + op_flags[i] |= ufunc->op_flags[i]; + if (op_flags[i] & (NPY_ITER_READWRITE | NPY_ITER_WRITEONLY)) { + op_flags[i] &= ~NPY_ITER_READONLY; + } + } + for (i = nin; i < nop; ++i) { + op_flags[i] = NPY_ITER_READWRITE| + NPY_ITER_UPDATEIFCOPY| + NPY_ITER_ALIGNED| + NPY_ITER_ALLOCATE| + NPY_ITER_NO_BROADCAST| + NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE; + } + + iter_flags = ufunc->iter_flags | + NPY_ITER_MULTI_INDEX | + NPY_ITER_REFS_OK | + NPY_ITER_REDUCE_OK | + NPY_ITER_ZEROSIZE_OK | + NPY_ITER_COPY_IF_OVERLAP; + + /* Create the iterator */ + iter = NpyIter_AdvancedNew(nop, op, iter_flags, + order, NPY_UNSAFE_CASTING, op_flags, + dtypes, iter_ndim, + op_axes, iter_shape, 0); + if (iter == NULL) { + retval = -1; + goto fail; + } + + /* Fill in any allocated outputs */ + for (i = nin; i < nop; ++i) { + if (op[i] == NULL) { + op[i] = NpyIter_GetOperandArray(iter)[i]; + Py_INCREF(op[i]); + } + } + + /* + * Set up the inner strides array. Because we're not doing + * buffering, the strides are fixed throughout the looping. + */ + core_dim_ixs_size = 0; + for (i = 0; i < nop; ++i) { + core_dim_ixs_size += ufunc->core_num_dims[i]; + } + inner_strides = (npy_intp *)PyArray_malloc( + NPY_SIZEOF_INTP * (nop+core_dim_ixs_size)); + if (inner_strides == NULL) { + PyErr_NoMemory(); + retval = -1; + goto fail; + } + /* Copy the strides after the first nop */ + idim = nop; + for (i = 0; i < nop; ++i) { + int num_dims = ufunc->core_num_dims[i]; + int core_start_dim = PyArray_NDIM(op[i]) - num_dims; + /* + * Need to use the arrays in the iterator, not op, because + * a copy with a different-sized type may have been made. + */ + PyArrayObject *arr = NpyIter_GetOperandArray(iter)[i]; + npy_intp *shape = PyArray_SHAPE(arr); + npy_intp *strides = PyArray_STRIDES(arr); + for (j = 0; j < num_dims; ++j) { + if (core_start_dim + j >= 0) { + /* + * Force the stride to zero when the shape is 1, sot + * that the broadcasting works right. + */ + if (shape[core_start_dim + j] != 1) { + inner_strides[idim++] = strides[core_start_dim + j]; + } else { + inner_strides[idim++] = 0; + } + } else { + inner_strides[idim++] = 0; + } + } + } + + total_problem_size = NpyIter_GetIterSize(iter); + if (total_problem_size < 0) { + /* + * Only used for threading, if negative (this means that it is + * larger then ssize_t before axes removal) assume that the actual + * problem is large enough to be threaded usefully. + */ + total_problem_size = 1000; + } + + /* Remove all the core output dimensions from the iterator */ + for (i = broadcast_ndim; i < iter_ndim; ++i) { + if (NpyIter_RemoveAxis(iter, broadcast_ndim) != NPY_SUCCEED) { + retval = -1; + goto fail; + } + } + if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED) { + retval = -1; + goto fail; + } + if (NpyIter_EnableExternalLoop(iter) != NPY_SUCCEED) { + retval = -1; + goto fail; + } + + /* + * The first nop strides are for the inner loop (but only can + * copy them after removing the core axes + */ + memcpy(inner_strides, NpyIter_GetInnerStrideArray(iter), + NPY_SIZEOF_INTP * nop); + +#if 0 + printf("strides: "); + for (i = 0; i < nop+core_dim_ixs_size; ++i) { + printf("%d ", (int)inner_strides[i]); + } + printf("\n"); +#endif + + /* Start with the floating-point exception flags cleared */ + PyUFunc_clearfperr(); + + NPY_UF_DBG_PRINT("Executing inner loop\n"); + + if (NpyIter_GetIterSize(iter) != 0) { + /* Do the ufunc loop */ + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp *count_ptr; + NPY_BEGIN_THREADS_DEF; + + /* Get the variables needed for the loop */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + retval = -1; + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + count_ptr = NpyIter_GetInnerLoopSizePtr(iter); + + if (!needs_api && !NpyIter_IterationNeedsAPI(iter)) { + NPY_BEGIN_THREADS_THRESHOLDED(total_problem_size); + } + do { + inner_dimensions[0] = *count_ptr; + innerloop(dataptr, inner_dimensions, inner_strides, innerloopdata); + } while (iternext(iter)); + + if (!needs_api && !NpyIter_IterationNeedsAPI(iter)) { + NPY_END_THREADS; + } + } else { + /** + * For each output operand, check if it has non-zero size, + * and assign the identity if it does. For example, a dot + * product of two zero-length arrays will be a scalar, + * which has size one. + */ + for (i = nin; i < nop; ++i) { + if (PyArray_SIZE(op[i]) != 0) { + switch (ufunc->identity) { + case PyUFunc_Zero: + assign_reduce_identity_zero(op[i], NULL); + break; + case PyUFunc_One: + assign_reduce_identity_one(op[i], NULL); + break; + case PyUFunc_MinusOne: + assign_reduce_identity_minusone(op[i], NULL); + break; + case PyUFunc_None: + case PyUFunc_ReorderableNone: + PyErr_Format(PyExc_ValueError, + "ufunc %s ", + ufunc_name); + retval = -1; + goto fail; + default: + PyErr_Format(PyExc_ValueError, + "ufunc %s has an invalid identity for reduction", + ufunc_name); + retval = -1; + goto fail; + } + } + } + } + + /* Check whether any errors occurred during the loop */ + if (PyErr_Occurred() || + _check_ufunc_fperr(errormask, extobj, ufunc_name) < 0) { + retval = -1; + goto fail; + } + + /* Write back any temporary data from PyArray_SetWritebackIfCopyBase */ + for(i=nin; i< nop; ++i) + if (PyArray_ResolveWritebackIfCopy(NpyIter_GetOperandArray(iter)[i]) < 0) + goto fail; + + PyArray_free(inner_strides); + NpyIter_Deallocate(iter); + /* The caller takes ownership of all the references in op */ + for (i = 0; i < nop; ++i) { + Py_XDECREF(dtypes[i]); + Py_XDECREF(arr_prep[i]); + } + Py_XDECREF(type_tup); + Py_XDECREF(arr_prep_args); + + NPY_UF_DBG_PRINT("Returning Success\n"); + + return 0; + +fail: + NPY_UF_DBG_PRINT1("Returning failure code %d\n", retval); + PyArray_free(inner_strides); + NpyIter_Deallocate(iter); + for (i = 0; i < nop; ++i) { + Py_XDECREF(op[i]); + op[i] = NULL; + Py_XDECREF(dtypes[i]); + Py_XDECREF(arr_prep[i]); + } + Py_XDECREF(type_tup); + Py_XDECREF(arr_prep_args); + + return retval; +} + +/*UFUNC_API + * + * This generic function is called with the ufunc object, the arguments to it, + * and an array of (pointers to) PyArrayObjects which are NULL. + * + * 'op' is an array of at least NPY_MAXARGS PyArrayObject *. + */ +NPY_NO_EXPORT int +PyUFunc_GenericFunction(PyUFuncObject *ufunc, + PyObject *args, PyObject *kwds, + PyArrayObject **op) +{ + int nin, nout; + int i, nop; + const char *ufunc_name; + int retval = -1, subok = 1; + int need_fancy = 0; + + PyArray_Descr *dtypes[NPY_MAXARGS]; + + /* These parameters come from extobj= or from a TLS global */ + int buffersize = 0, errormask = 0; + + /* The mask provided in the 'where=' parameter */ + PyArrayObject *wheremask = NULL; + + /* The __array_prepare__ function to call for each output */ + PyObject *arr_prep[NPY_MAXARGS]; + /* + * This is either args, or args with the out= parameter from + * kwds added appropriately. + */ + PyObject *arr_prep_args = NULL; + + int trivial_loop_ok = 0; + + NPY_ORDER order = NPY_KEEPORDER; + /* Use the default assignment casting rule */ + NPY_CASTING casting = NPY_DEFAULT_ASSIGN_CASTING; + /* When provided, extobj and typetup contain borrowed references */ + PyObject *extobj = NULL, *type_tup = NULL; + + if (ufunc == NULL) { + PyErr_SetString(PyExc_ValueError, "function not supported"); + return -1; + } + + if (ufunc->core_enabled) { + return PyUFunc_GeneralizedFunction(ufunc, args, kwds, op); + } + + nin = ufunc->nin; + nout = ufunc->nout; + nop = nin + nout; + + ufunc_name = ufunc_get_name_cstr(ufunc); + + NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s\n", ufunc_name); + + /* Initialize all the operands and dtypes to NULL */ + for (i = 0; i < nop; ++i) { + op[i] = NULL; + dtypes[i] = NULL; + arr_prep[i] = NULL; + } + + NPY_UF_DBG_PRINT("Getting arguments\n"); + + /* Get all the arguments */ + retval = get_ufunc_arguments(ufunc, args, kwds, + op, &order, &casting, &extobj, + &type_tup, &subok, &wheremask); + if (retval < 0) { + goto fail; + } + + /* + * Use the masked loop if a wheremask was specified. + */ + if (wheremask != NULL) { + need_fancy = 1; + } + + /* Get the buffersize and errormask */ + if (_get_bufsize_errmask(extobj, ufunc_name, &buffersize, &errormask) < 0) { + retval = -1; + goto fail; + } + + NPY_UF_DBG_PRINT("Finding inner loop\n"); + + retval = ufunc->type_resolver(ufunc, casting, + op, type_tup, dtypes); + if (retval < 0) { + goto fail; + } + + /* Only do the trivial loop check for the unmasked version. */ + if (!need_fancy) { + /* + * This checks whether a trivial loop is ok, making copies of + * scalar and one dimensional operands if that will help. + */ + trivial_loop_ok = check_for_trivial_loop(ufunc, op, dtypes, buffersize); + if (trivial_loop_ok < 0) { + goto fail; + } + } + +#if NPY_UF_DBG_TRACING + printf("input types:\n"); + for (i = 0; i < nin; ++i) { + PyObject_Print((PyObject *)dtypes[i], stdout, 0); + printf(" "); + } + printf("\noutput types:\n"); + for (i = nin; i < nop; ++i) { + PyObject_Print((PyObject *)dtypes[i], stdout, 0); + printf(" "); + } + printf("\n"); +#endif + + if (subok) { + /* + * Get the appropriate __array_prepare__ function to call + * for each output + */ + _find_array_prepare(args, kwds, arr_prep, nin, nout, 0); + + /* Set up arr_prep_args if a prep function was needed */ + for (i = 0; i < nout; ++i) { + if (arr_prep[i] != NULL && arr_prep[i] != Py_None) { + arr_prep_args = make_arr_prep_args(nin, args, kwds); + break; + } + } + } + + /* Start with the floating-point exception flags cleared */ + PyUFunc_clearfperr(); + + /* Do the ufunc loop */ + if (need_fancy) { + NPY_UF_DBG_PRINT("Executing fancy inner loop\n"); + + retval = execute_fancy_ufunc_loop(ufunc, wheremask, + op, dtypes, order, + buffersize, arr_prep, arr_prep_args); + } + else { + NPY_UF_DBG_PRINT("Executing legacy inner loop\n"); + + retval = execute_legacy_ufunc_loop(ufunc, trivial_loop_ok, + op, dtypes, order, + buffersize, arr_prep, arr_prep_args); + } + if (retval < 0) { + goto fail; + } + + /* Check whether any errors occurred during the loop */ + if (PyErr_Occurred() || + _check_ufunc_fperr(errormask, extobj, ufunc_name) < 0) { + retval = -1; + goto fail; + } + + + /* The caller takes ownership of all the references in op */ + for (i = 0; i < nop; ++i) { + Py_XDECREF(dtypes[i]); + Py_XDECREF(arr_prep[i]); + } + Py_XDECREF(type_tup); + Py_XDECREF(arr_prep_args); + Py_XDECREF(wheremask); + + NPY_UF_DBG_PRINT("Returning Success\n"); + + return 0; + +fail: + NPY_UF_DBG_PRINT1("Returning failure code %d\n", retval); + for (i = 0; i < nop; ++i) { + Py_XDECREF(op[i]); + op[i] = NULL; + Py_XDECREF(dtypes[i]); + Py_XDECREF(arr_prep[i]); + } + Py_XDECREF(type_tup); + Py_XDECREF(arr_prep_args); + Py_XDECREF(wheremask); + + return retval; +} + +/* + * Given the output type, finds the specified binary op. The + * ufunc must have nin==2 and nout==1. The function may modify + * otype if the given type isn't found. + * + * Returns 0 on success, -1 on failure. + */ +static int +get_binary_op_function(PyUFuncObject *ufunc, int *otype, + PyUFuncGenericFunction *out_innerloop, + void **out_innerloopdata) +{ + int i; + PyUFunc_Loop1d *funcdata; + + NPY_UF_DBG_PRINT1("Getting binary op function for type number %d\n", + *otype); + + /* If the type is custom and there are userloops, search for it here */ + if (ufunc->userloops != NULL && PyTypeNum_ISUSERDEF(*otype)) { + PyObject *key, *obj; + key = PyInt_FromLong(*otype); + if (key == NULL) { + return -1; + } + obj = PyDict_GetItem(ufunc->userloops, key); + Py_DECREF(key); + if (obj != NULL) { + funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj); + while (funcdata != NULL) { + int *types = funcdata->arg_types; + + if (types[0] == *otype && types[1] == *otype && + types[2] == *otype) { + *out_innerloop = funcdata->func; + *out_innerloopdata = funcdata->data; + return 0; + } + + funcdata = funcdata->next; + } + } + } + + /* Search for a function with compatible inputs */ + for (i = 0; i < ufunc->ntypes; ++i) { + char *types = ufunc->types + i*ufunc->nargs; + + NPY_UF_DBG_PRINT3("Trying loop with signature %d %d -> %d\n", + types[0], types[1], types[2]); + + if (PyArray_CanCastSafely(*otype, types[0]) && + types[0] == types[1] && + (*otype == NPY_OBJECT || types[0] != NPY_OBJECT)) { + /* If the signature is "xx->x", we found the loop */ + if (types[2] == types[0]) { + *out_innerloop = ufunc->functions[i]; + *out_innerloopdata = ufunc->data[i]; + *otype = types[0]; + return 0; + } + /* + * Otherwise, we found the natural type of the reduction, + * replace otype and search again + */ + else { + *otype = types[2]; + break; + } + } + } + + /* Search for the exact function */ + for (i = 0; i < ufunc->ntypes; ++i) { + char *types = ufunc->types + i*ufunc->nargs; + + if (PyArray_CanCastSafely(*otype, types[0]) && + types[0] == types[1] && + types[1] == types[2] && + (*otype == NPY_OBJECT || types[0] != NPY_OBJECT)) { + /* Since the signature is "xx->x", we found the loop */ + *out_innerloop = ufunc->functions[i]; + *out_innerloopdata = ufunc->data[i]; + *otype = types[0]; + return 0; + } + } + + return -1; +} + +static int +reduce_type_resolver(PyUFuncObject *ufunc, PyArrayObject *arr, + PyArray_Descr *odtype, PyArray_Descr **out_dtype) +{ + int i, retcode; + PyArrayObject *op[3] = {arr, arr, NULL}; + PyArray_Descr *dtypes[3] = {NULL, NULL, NULL}; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + PyObject *type_tup = NULL; + + *out_dtype = NULL; + + /* + * If odtype is specified, make a type tuple for the type + * resolution. + */ + if (odtype != NULL) { + type_tup = PyTuple_Pack(3, odtype, odtype, Py_None); + if (type_tup == NULL) { + return -1; + } + } + + /* Use the type resolution function to find our loop */ + retcode = ufunc->type_resolver( + ufunc, NPY_UNSAFE_CASTING, + op, type_tup, dtypes); + Py_DECREF(type_tup); + if (retcode == -1) { + return -1; + } + else if (retcode == -2) { + PyErr_Format(PyExc_RuntimeError, + "type resolution returned NotImplemented to " + "reduce ufunc %s", ufunc_name); + return -1; + } + + /* + * The first two type should be equivalent. Because of how + * reduce has historically behaved in NumPy, the return type + * could be different, and it is the return type on which the + * reduction occurs. + */ + if (!PyArray_EquivTypes(dtypes[0], dtypes[1])) { + for (i = 0; i < 3; ++i) { + Py_DECREF(dtypes[i]); + } + PyErr_Format(PyExc_RuntimeError, + "could not find a type resolution appropriate for " + "reduce ufunc %s", ufunc_name); + return -1; + } + + Py_DECREF(dtypes[0]); + Py_DECREF(dtypes[1]); + *out_dtype = dtypes[2]; + + return 0; +} + +static int +assign_reduce_identity_zero(PyArrayObject *result, void *NPY_UNUSED(data)) +{ + return PyArray_FillWithScalar(result, PyArrayScalar_False); +} + +static int +assign_reduce_identity_one(PyArrayObject *result, void *NPY_UNUSED(data)) +{ + return PyArray_FillWithScalar(result, PyArrayScalar_True); +} + +static int +assign_reduce_identity_minusone(PyArrayObject *result, void *NPY_UNUSED(data)) +{ + static PyObject *MinusOne = NULL; + + if (MinusOne == NULL) { + if ((MinusOne = PyInt_FromLong(-1)) == NULL) { + return -1; + } + } + return PyArray_FillWithScalar(result, MinusOne); +} + +static int +reduce_loop(NpyIter *iter, char **dataptrs, npy_intp *strides, + npy_intp *countptr, NpyIter_IterNextFunc *iternext, + int needs_api, npy_intp skip_first_count, void *data) +{ + PyArray_Descr *dtypes[3], **iter_dtypes; + PyUFuncObject *ufunc = (PyUFuncObject *)data; + char *dataptrs_copy[3]; + npy_intp strides_copy[3]; + + /* The normal selected inner loop */ + PyUFuncGenericFunction innerloop = NULL; + void *innerloopdata = NULL; + + NPY_BEGIN_THREADS_DEF; + + /* Get the inner loop */ + iter_dtypes = NpyIter_GetDescrArray(iter); + dtypes[0] = iter_dtypes[0]; + dtypes[1] = iter_dtypes[1]; + dtypes[2] = iter_dtypes[0]; + if (ufunc->legacy_inner_loop_selector(ufunc, dtypes, + &innerloop, &innerloopdata, &needs_api) < 0) { + return -1; + } + + NPY_BEGIN_THREADS_NDITER(iter); + + if (skip_first_count > 0) { + do { + npy_intp count = *countptr; + + /* Skip any first-visit elements */ + if (NpyIter_IsFirstVisit(iter, 0)) { + if (strides[0] == 0) { + --count; + --skip_first_count; + dataptrs[1] += strides[1]; + } + else { + skip_first_count -= count; + count = 0; + } + } + + /* Turn the two items into three for the inner loop */ + dataptrs_copy[0] = dataptrs[0]; + dataptrs_copy[1] = dataptrs[1]; + dataptrs_copy[2] = dataptrs[0]; + strides_copy[0] = strides[0]; + strides_copy[1] = strides[1]; + strides_copy[2] = strides[0]; + innerloop(dataptrs_copy, &count, + strides_copy, innerloopdata); + + /* Jump to the faster loop when skipping is done */ + if (skip_first_count == 0) { + if (iternext(iter)) { + break; + } + else { + goto finish_loop; + } + } + } while (iternext(iter)); + } + do { + /* Turn the two items into three for the inner loop */ + dataptrs_copy[0] = dataptrs[0]; + dataptrs_copy[1] = dataptrs[1]; + dataptrs_copy[2] = dataptrs[0]; + strides_copy[0] = strides[0]; + strides_copy[1] = strides[1]; + strides_copy[2] = strides[0]; + innerloop(dataptrs_copy, countptr, + strides_copy, innerloopdata); + } while (iternext(iter)); + +finish_loop: + NPY_END_THREADS; + + return (needs_api && PyErr_Occurred()) ? -1 : 0; +} + +/* + * The implementation of the reduction operators with the new iterator + * turned into a bit of a long function here, but I think the design + * of this part needs to be changed to be more like einsum, so it may + * not be worth refactoring it too much. Consider this timing: + * + * >>> a = arange(10000) + * + * >>> timeit sum(a) + * 10000 loops, best of 3: 17 us per loop + * + * >>> timeit einsum("i->",a) + * 100000 loops, best of 3: 13.5 us per loop + * + * The axes must already be bounds-checked by the calling function, + * this function does not validate them. + */ +static PyArrayObject * +PyUFunc_Reduce(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out, + int naxes, int *axes, PyArray_Descr *odtype, int keepdims) +{ + int iaxes, reorderable, ndim; + npy_bool axis_flags[NPY_MAXDIMS]; + PyArray_Descr *dtype; + PyArrayObject *result; + PyArray_AssignReduceIdentityFunc *assign_identity = NULL; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + /* These parameters come from a TLS global */ + int buffersize = 0, errormask = 0; + + NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s.reduce\n", ufunc_name); + + ndim = PyArray_NDIM(arr); + + /* Create an array of flags for reduction */ + memset(axis_flags, 0, ndim); + for (iaxes = 0; iaxes < naxes; ++iaxes) { + int axis = axes[iaxes]; + if (axis_flags[axis]) { + PyErr_SetString(PyExc_ValueError, + "duplicate value in 'axis'"); + return NULL; + } + axis_flags[axis] = 1; + } + + switch (ufunc->identity) { + case PyUFunc_Zero: + assign_identity = &assign_reduce_identity_zero; + reorderable = 1; + /* + * The identity for a dynamic dtype like + * object arrays can't be used in general + */ + if (PyArray_ISOBJECT(arr) && PyArray_SIZE(arr) != 0) { + assign_identity = NULL; + } + break; + case PyUFunc_One: + assign_identity = &assign_reduce_identity_one; + reorderable = 1; + /* + * The identity for a dynamic dtype like + * object arrays can't be used in general + */ + if (PyArray_ISOBJECT(arr) && PyArray_SIZE(arr) != 0) { + assign_identity = NULL; + } + break; + case PyUFunc_MinusOne: + assign_identity = &assign_reduce_identity_minusone; + reorderable = 1; + /* + * The identity for a dynamic dtype like + * object arrays can't be used in general + */ + if (PyArray_ISOBJECT(arr) && PyArray_SIZE(arr) != 0) { + assign_identity = NULL; + } + break; + + case PyUFunc_None: + reorderable = 0; + break; + case PyUFunc_ReorderableNone: + reorderable = 1; + break; + default: + PyErr_Format(PyExc_ValueError, + "ufunc %s has an invalid identity for reduction", + ufunc_name); + return NULL; + } + + if (_get_bufsize_errmask(NULL, "reduce", &buffersize, &errormask) < 0) { + return NULL; + } + + /* Get the reduction dtype */ + if (reduce_type_resolver(ufunc, arr, odtype, &dtype) < 0) { + return NULL; + } + + result = PyUFunc_ReduceWrapper(arr, out, NULL, dtype, dtype, + NPY_UNSAFE_CASTING, + axis_flags, reorderable, + keepdims, 0, + assign_identity, + reduce_loop, + ufunc, buffersize, ufunc_name, errormask); + + Py_DECREF(dtype); + return result; +} + + +static PyObject * +PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out, + int axis, int otype) +{ + PyArrayObject *op[2]; + PyArray_Descr *op_dtypes[2] = {NULL, NULL}; + int op_axes_arrays[2][NPY_MAXDIMS]; + int *op_axes[2] = {op_axes_arrays[0], op_axes_arrays[1]}; + npy_uint32 op_flags[2]; + int idim, ndim, otype_final; + int needs_api, need_outer_iterator; + + NpyIter *iter = NULL, *iter_inner = NULL; + + /* The selected inner loop */ + PyUFuncGenericFunction innerloop = NULL; + void *innerloopdata = NULL; + + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + /* These parameters come from extobj= or from a TLS global */ + int buffersize = 0, errormask = 0; + + NPY_BEGIN_THREADS_DEF; + + NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s.accumulate\n", ufunc_name); + +#if 0 + printf("Doing %s.accumulate on array with dtype : ", ufunc_name); + PyObject_Print((PyObject *)PyArray_DESCR(arr), stdout, 0); + printf("\n"); +#endif + + if (_get_bufsize_errmask(NULL, "accumulate", &buffersize, &errormask) < 0) { + return NULL; + } + + /* Take a reference to out for later returning */ + Py_XINCREF(out); + + otype_final = otype; + if (get_binary_op_function(ufunc, &otype_final, + &innerloop, &innerloopdata) < 0) { + PyArray_Descr *dtype = PyArray_DescrFromType(otype); + PyErr_Format(PyExc_ValueError, + "could not find a matching type for %s.accumulate, " + "requested type has type code '%c'", + ufunc_name, dtype ? dtype->type : '-'); + Py_XDECREF(dtype); + goto fail; + } + + ndim = PyArray_NDIM(arr); + + /* + * Set up the output data type, using the input's exact + * data type if the type number didn't change to preserve + * metadata + */ + if (PyArray_DESCR(arr)->type_num == otype_final) { + if (PyArray_ISNBO(PyArray_DESCR(arr)->byteorder)) { + op_dtypes[0] = PyArray_DESCR(arr); + Py_INCREF(op_dtypes[0]); + } + else { + op_dtypes[0] = PyArray_DescrNewByteorder(PyArray_DESCR(arr), + NPY_NATIVE); + } + } + else { + op_dtypes[0] = PyArray_DescrFromType(otype_final); + } + if (op_dtypes[0] == NULL) { + goto fail; + } + +#if NPY_UF_DBG_TRACING + printf("Found %s.accumulate inner loop with dtype : ", ufunc_name); + PyObject_Print((PyObject *)op_dtypes[0], stdout, 0); + printf("\n"); +#endif + + /* Set up the op_axes for the outer loop */ + for (idim = 0; idim < ndim; ++idim) { + op_axes_arrays[0][idim] = idim; + op_axes_arrays[1][idim] = idim; + } + + /* The per-operand flags for the outer loop */ + op_flags[0] = NPY_ITER_READWRITE | + NPY_ITER_NO_BROADCAST | + NPY_ITER_ALLOCATE | + NPY_ITER_NO_SUBTYPE; + op_flags[1] = NPY_ITER_READONLY; + + op[0] = out; + op[1] = arr; + + need_outer_iterator = (ndim > 1); + /* We can't buffer, so must do UPDATEIFCOPY */ + if (!PyArray_ISALIGNED(arr) || (out && !PyArray_ISALIGNED(out)) || + !PyArray_EquivTypes(op_dtypes[0], PyArray_DESCR(arr)) || + (out && + !PyArray_EquivTypes(op_dtypes[0], PyArray_DESCR(out)))) { + need_outer_iterator = 1; + } + /* If input and output overlap in memory, use iterator to figure it out */ + else if (out != NULL && solve_may_share_memory(out, arr, NPY_MAY_SHARE_BOUNDS) != 0) { + need_outer_iterator = 1; + } + + if (need_outer_iterator) { + int ndim_iter = 0; + npy_uint32 flags = NPY_ITER_ZEROSIZE_OK| + NPY_ITER_REFS_OK| + NPY_ITER_COPY_IF_OVERLAP; + PyArray_Descr **op_dtypes_param = NULL; + + /* + * The way accumulate is set up, we can't do buffering, + * so make a copy instead when necessary. + */ + ndim_iter = ndim; + flags |= NPY_ITER_MULTI_INDEX; + /* Add some more flags */ + op_flags[0] |= NPY_ITER_UPDATEIFCOPY|NPY_ITER_ALIGNED; + op_flags[1] |= NPY_ITER_COPY|NPY_ITER_ALIGNED; + op_dtypes_param = op_dtypes; + op_dtypes[1] = op_dtypes[0]; + NPY_UF_DBG_PRINT("Allocating outer iterator\n"); + iter = NpyIter_AdvancedNew(2, op, flags, + NPY_KEEPORDER, NPY_UNSAFE_CASTING, + op_flags, + op_dtypes_param, + ndim_iter, op_axes, NULL, 0); + if (iter == NULL) { + goto fail; + } + + /* In case COPY or UPDATEIFCOPY occurred */ + op[0] = NpyIter_GetOperandArray(iter)[0]; + op[1] = NpyIter_GetOperandArray(iter)[1]; + + if (NpyIter_RemoveAxis(iter, axis) != NPY_SUCCEED) { + goto fail; + } + if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED) { + goto fail; + } + } + + /* Get the output */ + if (out == NULL) { + if (iter) { + op[0] = out = NpyIter_GetOperandArray(iter)[0]; + Py_INCREF(out); + } + else { + PyArray_Descr *dtype = op_dtypes[0]; + Py_INCREF(dtype); + op[0] = out = (PyArrayObject *)PyArray_NewFromDescr( + &PyArray_Type, dtype, + ndim, PyArray_DIMS(op[1]), NULL, NULL, + 0, NULL); + if (out == NULL) { + goto fail; + } + + } + } + + /* + * If the reduction axis has size zero, either return the reduction + * unit for UFUNC_REDUCE, or return the zero-sized output array + * for UFUNC_ACCUMULATE. + */ + if (PyArray_DIM(op[1], axis) == 0) { + goto finish; + } + else if (PyArray_SIZE(op[0]) == 0) { + goto finish; + } + + if (iter && NpyIter_GetIterSize(iter) != 0) { + char *dataptr_copy[3]; + npy_intp stride_copy[3]; + npy_intp count_m1, stride0, stride1; + + NpyIter_IterNextFunc *iternext; + char **dataptr; + + int itemsize = op_dtypes[0]->elsize; + + /* Get the variables needed for the loop */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + + + /* Execute the loop with just the outer iterator */ + count_m1 = PyArray_DIM(op[1], axis)-1; + stride0 = 0, stride1 = PyArray_STRIDE(op[1], axis); + + NPY_UF_DBG_PRINT("UFunc: Reduce loop with just outer iterator\n"); + + stride0 = PyArray_STRIDE(op[0], axis); + + stride_copy[0] = stride0; + stride_copy[1] = stride1; + stride_copy[2] = stride0; + + needs_api = NpyIter_IterationNeedsAPI(iter); + + NPY_BEGIN_THREADS_NDITER(iter); + + do { + dataptr_copy[0] = dataptr[0]; + dataptr_copy[1] = dataptr[1]; + dataptr_copy[2] = dataptr[0]; + + /* + * Copy the first element to start the reduction. + * + * Output (dataptr[0]) and input (dataptr[1]) may point to + * the same memory, e.g. np.add.accumulate(a, out=a). + */ + if (otype == NPY_OBJECT) { + /* + * Incref before decref to avoid the possibility of the + * reference count being zero temporarily. + */ + Py_XINCREF(*(PyObject **)dataptr_copy[1]); + Py_XDECREF(*(PyObject **)dataptr_copy[0]); + *(PyObject **)dataptr_copy[0] = + *(PyObject **)dataptr_copy[1]; + } + else { + memmove(dataptr_copy[0], dataptr_copy[1], itemsize); + } + + if (count_m1 > 0) { + /* Turn the two items into three for the inner loop */ + dataptr_copy[1] += stride1; + dataptr_copy[2] += stride0; + NPY_UF_DBG_PRINT1("iterator loop count %d\n", + (int)count_m1); + innerloop(dataptr_copy, &count_m1, + stride_copy, innerloopdata); + } + } while (iternext(iter)); + + NPY_END_THREADS; + } + else if (iter == NULL) { + char *dataptr_copy[3]; + npy_intp stride_copy[3]; + + int itemsize = op_dtypes[0]->elsize; + + /* Execute the loop with no iterators */ + npy_intp count = PyArray_DIM(op[1], axis); + npy_intp stride0 = 0, stride1 = PyArray_STRIDE(op[1], axis); + + NPY_UF_DBG_PRINT("UFunc: Reduce loop with no iterators\n"); + + if (PyArray_NDIM(op[0]) != PyArray_NDIM(op[1]) || + !PyArray_CompareLists(PyArray_DIMS(op[0]), + PyArray_DIMS(op[1]), + PyArray_NDIM(op[0]))) { + PyErr_SetString(PyExc_ValueError, + "provided out is the wrong size " + "for the reduction"); + goto fail; + } + stride0 = PyArray_STRIDE(op[0], axis); + + stride_copy[0] = stride0; + stride_copy[1] = stride1; + stride_copy[2] = stride0; + + /* Turn the two items into three for the inner loop */ + dataptr_copy[0] = PyArray_BYTES(op[0]); + dataptr_copy[1] = PyArray_BYTES(op[1]); + dataptr_copy[2] = PyArray_BYTES(op[0]); + + /* + * Copy the first element to start the reduction. + * + * Output (dataptr[0]) and input (dataptr[1]) may point to the + * same memory, e.g. np.add.accumulate(a, out=a). + */ + if (otype == NPY_OBJECT) { + /* + * Incref before decref to avoid the possibility of the + * reference count being zero temporarily. + */ + Py_XINCREF(*(PyObject **)dataptr_copy[1]); + Py_XDECREF(*(PyObject **)dataptr_copy[0]); + *(PyObject **)dataptr_copy[0] = + *(PyObject **)dataptr_copy[1]; + } + else { + memmove(dataptr_copy[0], dataptr_copy[1], itemsize); + } + + if (count > 1) { + --count; + dataptr_copy[1] += stride1; + dataptr_copy[2] += stride0; + + NPY_UF_DBG_PRINT1("iterator loop count %d\n", (int)count); + + needs_api = PyDataType_REFCHK(op_dtypes[0]); + + if (!needs_api) { + NPY_BEGIN_THREADS_THRESHOLDED(count); + } + + innerloop(dataptr_copy, &count, + stride_copy, innerloopdata); + + NPY_END_THREADS; + } + } + +finish: + /* Write back any temporary data from PyArray_SetWritebackIfCopyBase */ + if (PyArray_ResolveWritebackIfCopy(op[0]) < 0) + goto fail; + Py_XDECREF(op_dtypes[0]); + NpyIter_Deallocate(iter); + NpyIter_Deallocate(iter_inner); + + return (PyObject *)out; + +fail: + Py_XDECREF(out); + Py_XDECREF(op_dtypes[0]); + + NpyIter_Deallocate(iter); + NpyIter_Deallocate(iter_inner); + + return NULL; +} + +/* + * Reduceat performs a reduce over an axis using the indices as a guide + * + * op.reduceat(array,indices) computes + * op.reduce(array[indices[i]:indices[i+1]] + * for i=0..end with an implicit indices[i+1]=len(array) + * assumed when i=end-1 + * + * if indices[i+1] <= indices[i]+1 + * then the result is array[indices[i]] for that value + * + * op.accumulate(array) is the same as + * op.reduceat(array,indices)[::2] + * where indices is range(len(array)-1) with a zero placed in every other sample + * indices = zeros(len(array)*2-1) + * indices[1::2] = range(1,len(array)) + * + * output shape is based on the size of indices + */ +static PyObject * +PyUFunc_Reduceat(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *ind, + PyArrayObject *out, int axis, int otype) +{ + PyArrayObject *op[3]; + PyArray_Descr *op_dtypes[3] = {NULL, NULL, NULL}; + int op_axes_arrays[3][NPY_MAXDIMS]; + int *op_axes[3] = {op_axes_arrays[0], op_axes_arrays[1], + op_axes_arrays[2]}; + npy_uint32 op_flags[3]; + int i, idim, ndim, otype_final; + int need_outer_iterator; + + NpyIter *iter = NULL; + + /* The reduceat indices - ind must be validated outside this call */ + npy_intp *reduceat_ind; + npy_intp ind_size, red_axis_size; + /* The selected inner loop */ + PyUFuncGenericFunction innerloop = NULL; + void *innerloopdata = NULL; + + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + char *opname = "reduceat"; + + /* These parameters come from extobj= or from a TLS global */ + int buffersize = 0, errormask = 0; + + NPY_BEGIN_THREADS_DEF; + + reduceat_ind = (npy_intp *)PyArray_DATA(ind); + ind_size = PyArray_DIM(ind, 0); + red_axis_size = PyArray_DIM(arr, axis); + + /* Check for out-of-bounds values in indices array */ + for (i = 0; i < ind_size; ++i) { + if (reduceat_ind[i] < 0 || reduceat_ind[i] >= red_axis_size) { + PyErr_Format(PyExc_IndexError, + "index %d out-of-bounds in %s.%s [0, %d)", + (int)reduceat_ind[i], ufunc_name, opname, (int)red_axis_size); + return NULL; + } + } + + NPY_UF_DBG_PRINT2("\nEvaluating ufunc %s.%s\n", ufunc_name, opname); + +#if 0 + printf("Doing %s.%s on array with dtype : ", ufunc_name, opname); + PyObject_Print((PyObject *)PyArray_DESCR(arr), stdout, 0); + printf("\n"); + printf("Index size is %d\n", (int)ind_size); +#endif + + if (_get_bufsize_errmask(NULL, opname, &buffersize, &errormask) < 0) { + return NULL; + } + + /* Take a reference to out for later returning */ + Py_XINCREF(out); + + otype_final = otype; + if (get_binary_op_function(ufunc, &otype_final, + &innerloop, &innerloopdata) < 0) { + PyArray_Descr *dtype = PyArray_DescrFromType(otype); + PyErr_Format(PyExc_ValueError, + "could not find a matching type for %s.%s, " + "requested type has type code '%c'", + ufunc_name, opname, dtype ? dtype->type : '-'); + Py_XDECREF(dtype); + goto fail; + } + + ndim = PyArray_NDIM(arr); + + /* + * Set up the output data type, using the input's exact + * data type if the type number didn't change to preserve + * metadata + */ + if (PyArray_DESCR(arr)->type_num == otype_final) { + if (PyArray_ISNBO(PyArray_DESCR(arr)->byteorder)) { + op_dtypes[0] = PyArray_DESCR(arr); + Py_INCREF(op_dtypes[0]); + } + else { + op_dtypes[0] = PyArray_DescrNewByteorder(PyArray_DESCR(arr), + NPY_NATIVE); + } + } + else { + op_dtypes[0] = PyArray_DescrFromType(otype_final); + } + if (op_dtypes[0] == NULL) { + goto fail; + } + +#if NPY_UF_DBG_TRACING + printf("Found %s.%s inner loop with dtype : ", ufunc_name, opname); + PyObject_Print((PyObject *)op_dtypes[0], stdout, 0); + printf("\n"); +#endif + + /* Set up the op_axes for the outer loop */ + for (i = 0, idim = 0; idim < ndim; ++idim) { + /* Use the i-th iteration dimension to match up ind */ + if (idim == axis) { + op_axes_arrays[0][idim] = axis; + op_axes_arrays[1][idim] = -1; + op_axes_arrays[2][idim] = 0; + } + else { + op_axes_arrays[0][idim] = idim; + op_axes_arrays[1][idim] = idim; + op_axes_arrays[2][idim] = -1; + } + } + + op[0] = out; + op[1] = arr; + op[2] = ind; + + if (out != NULL || ndim > 1 || !PyArray_ISALIGNED(arr) || + !PyArray_EquivTypes(op_dtypes[0], PyArray_DESCR(arr))) { + need_outer_iterator = 1; + } + + if (need_outer_iterator) { + npy_uint32 flags = NPY_ITER_ZEROSIZE_OK| + NPY_ITER_REFS_OK| + NPY_ITER_MULTI_INDEX| + NPY_ITER_COPY_IF_OVERLAP; + + /* + * The way reduceat is set up, we can't do buffering, + * so make a copy instead when necessary using + * the UPDATEIFCOPY flag + */ + + /* The per-operand flags for the outer loop */ + op_flags[0] = NPY_ITER_READWRITE| + NPY_ITER_NO_BROADCAST| + NPY_ITER_ALLOCATE| + NPY_ITER_NO_SUBTYPE| + NPY_ITER_UPDATEIFCOPY| + NPY_ITER_ALIGNED; + op_flags[1] = NPY_ITER_READONLY| + NPY_ITER_COPY| + NPY_ITER_ALIGNED; + op_flags[2] = NPY_ITER_READONLY; + + op_dtypes[1] = op_dtypes[0]; + + NPY_UF_DBG_PRINT("Allocating outer iterator\n"); + iter = NpyIter_AdvancedNew(3, op, flags, + NPY_KEEPORDER, NPY_UNSAFE_CASTING, + op_flags, + op_dtypes, + ndim, op_axes, NULL, 0); + if (iter == NULL) { + goto fail; + } + + /* Remove the inner loop axis from the outer iterator */ + if (NpyIter_RemoveAxis(iter, axis) != NPY_SUCCEED) { + goto fail; + } + if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED) { + goto fail; + } + + /* In case COPY or UPDATEIFCOPY occurred */ + op[0] = NpyIter_GetOperandArray(iter)[0]; + op[1] = NpyIter_GetOperandArray(iter)[1]; + op[2] = NpyIter_GetOperandArray(iter)[2]; + + if (out == NULL) { + out = op[0]; + Py_INCREF(out); + } + } + /* Allocate the output for when there's no outer iterator */ + else if (out == NULL) { + Py_INCREF(op_dtypes[0]); + op[0] = out = (PyArrayObject *)PyArray_NewFromDescr( + &PyArray_Type, op_dtypes[0], + 1, &ind_size, NULL, NULL, + 0, NULL); + if (out == NULL) { + goto fail; + } + } + + /* + * If the output has zero elements, return now. + */ + if (PyArray_SIZE(op[0]) == 0) { + goto finish; + } + + if (iter && NpyIter_GetIterSize(iter) != 0) { + char *dataptr_copy[3]; + npy_intp stride_copy[3]; + + NpyIter_IterNextFunc *iternext; + char **dataptr; + npy_intp count_m1; + npy_intp stride0, stride1; + npy_intp stride0_ind = PyArray_STRIDE(op[0], axis); + + int itemsize = op_dtypes[0]->elsize; + + /* Get the variables needed for the loop */ + iternext = NpyIter_GetIterNext(iter, NULL); + if (iternext == NULL) { + goto fail; + } + dataptr = NpyIter_GetDataPtrArray(iter); + + /* Execute the loop with just the outer iterator */ + count_m1 = PyArray_DIM(op[1], axis)-1; + stride0 = 0; + stride1 = PyArray_STRIDE(op[1], axis); + + NPY_UF_DBG_PRINT("UFunc: Reduce loop with just outer iterator\n"); + + stride_copy[0] = stride0; + stride_copy[1] = stride1; + stride_copy[2] = stride0; + + NPY_BEGIN_THREADS_NDITER(iter); + + do { + + for (i = 0; i < ind_size; ++i) { + npy_intp start = reduceat_ind[i], + end = (i == ind_size-1) ? count_m1+1 : + reduceat_ind[i+1]; + npy_intp count = end - start; + + dataptr_copy[0] = dataptr[0] + stride0_ind*i; + dataptr_copy[1] = dataptr[1] + stride1*start; + dataptr_copy[2] = dataptr[0] + stride0_ind*i; + + /* + * Copy the first element to start the reduction. + * + * Output (dataptr[0]) and input (dataptr[1]) may point + * to the same memory, e.g. + * np.add.reduceat(a, np.arange(len(a)), out=a). + */ + if (otype == NPY_OBJECT) { + /* + * Incref before decref to avoid the possibility of + * the reference count being zero temporarily. + */ + Py_XINCREF(*(PyObject **)dataptr_copy[1]); + Py_XDECREF(*(PyObject **)dataptr_copy[0]); + *(PyObject **)dataptr_copy[0] = + *(PyObject **)dataptr_copy[1]; + } + else { + memmove(dataptr_copy[0], dataptr_copy[1], itemsize); + } + + if (count > 1) { + /* Inner loop like REDUCE */ + --count; + dataptr_copy[1] += stride1; + NPY_UF_DBG_PRINT1("iterator loop count %d\n", + (int)count); + innerloop(dataptr_copy, &count, + stride_copy, innerloopdata); + } + } + } while (iternext(iter)); + + NPY_END_THREADS; + } + else if (iter == NULL) { + char *dataptr_copy[3]; + npy_intp stride_copy[3]; + + int itemsize = op_dtypes[0]->elsize; + + npy_intp stride0_ind = PyArray_STRIDE(op[0], axis); + + /* Execute the loop with no iterators */ + npy_intp stride0 = 0, stride1 = PyArray_STRIDE(op[1], axis); + + int needs_api = PyDataType_REFCHK(op_dtypes[0]); + + NPY_UF_DBG_PRINT("UFunc: Reduce loop with no iterators\n"); + + stride_copy[0] = stride0; + stride_copy[1] = stride1; + stride_copy[2] = stride0; + + if (!needs_api) { + NPY_BEGIN_THREADS; + } + + for (i = 0; i < ind_size; ++i) { + npy_intp start = reduceat_ind[i], + end = (i == ind_size-1) ? PyArray_DIM(arr,axis) : + reduceat_ind[i+1]; + npy_intp count = end - start; + + dataptr_copy[0] = PyArray_BYTES(op[0]) + stride0_ind*i; + dataptr_copy[1] = PyArray_BYTES(op[1]) + stride1*start; + dataptr_copy[2] = PyArray_BYTES(op[0]) + stride0_ind*i; + + /* + * Copy the first element to start the reduction. + * + * Output (dataptr[0]) and input (dataptr[1]) may point to + * the same memory, e.g. + * np.add.reduceat(a, np.arange(len(a)), out=a). + */ + if (otype == NPY_OBJECT) { + /* + * Incref before decref to avoid the possibility of the + * reference count being zero temporarily. + */ + Py_XINCREF(*(PyObject **)dataptr_copy[1]); + Py_XDECREF(*(PyObject **)dataptr_copy[0]); + *(PyObject **)dataptr_copy[0] = + *(PyObject **)dataptr_copy[1]; + } + else { + memmove(dataptr_copy[0], dataptr_copy[1], itemsize); + } + + if (count > 1) { + /* Inner loop like REDUCE */ + --count; + dataptr_copy[1] += stride1; + NPY_UF_DBG_PRINT1("iterator loop count %d\n", + (int)count); + innerloop(dataptr_copy, &count, + stride_copy, innerloopdata); + } + } + + NPY_END_THREADS; + } + +finish: + if (op[0] && PyArray_ResolveWritebackIfCopy(op[0]) < 0) { + goto fail; + } + Py_XDECREF(op_dtypes[0]); + NpyIter_Deallocate(iter); + + return (PyObject *)out; + +fail: + Py_XDECREF(out); + Py_XDECREF(op_dtypes[0]); + + NpyIter_Deallocate(iter); + + return NULL; +} + + +/* + * This code handles reduce, reduceat, and accumulate + * (accumulate and reduce are special cases of the more general reduceat + * but they are handled separately for speed) + */ +static PyObject * +PyUFunc_GenericReduction(PyUFuncObject *ufunc, PyObject *args, + PyObject *kwds, int operation) +{ + int i, naxes=0, ndim; + int axes[NPY_MAXDIMS]; + PyObject *axes_in = NULL; + PyArrayObject *mp = NULL, *ret = NULL; + PyObject *op, *res = NULL; + PyObject *obj_ind, *context; + PyArrayObject *indices = NULL; + PyArray_Descr *otype = NULL; + PyArrayObject *out = NULL; + int keepdims = 0; + static char *reduce_kwlist[] = { + "array", "axis", "dtype", "out", "keepdims", NULL}; + static char *accumulate_kwlist[] = { + "array", "axis", "dtype", "out", NULL}; + static char *reduceat_kwlist[] = { + "array", "indices", "axis", "dtype", "out", NULL}; + + static char *_reduce_type[] = {"reduce", "accumulate", "reduceat", NULL}; + + if (ufunc == NULL) { + PyErr_SetString(PyExc_ValueError, "function not supported"); + return NULL; + } + if (ufunc->core_enabled) { + PyErr_Format(PyExc_RuntimeError, + "Reduction not defined on ufunc with signature"); + return NULL; + } + if (ufunc->nin != 2) { + PyErr_Format(PyExc_ValueError, + "%s only supported for binary functions", + _reduce_type[operation]); + return NULL; + } + if (ufunc->nout != 1) { + PyErr_Format(PyExc_ValueError, + "%s only supported for functions " + "returning a single value", + _reduce_type[operation]); + return NULL; + } + /* if there is a tuple of 1 for `out` in kwds, unpack it */ + if (kwds != NULL) { + PyObject *out_obj = PyDict_GetItem(kwds, npy_um_str_out); + if (out_obj != NULL && PyTuple_CheckExact(out_obj)) { + if (PyTuple_GET_SIZE(out_obj) != 1) { + PyErr_SetString(PyExc_ValueError, + "The 'out' tuple must have exactly one entry"); + return NULL; + } + out_obj = PyTuple_GET_ITEM(out_obj, 0); + PyDict_SetItem(kwds, npy_um_str_out, out_obj); + } + } + + if (operation == UFUNC_REDUCEAT) { + PyArray_Descr *indtype; + indtype = PyArray_DescrFromType(NPY_INTP); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO&O&:reduceat", reduceat_kwlist, + &op, + &obj_ind, + &axes_in, + PyArray_DescrConverter2, &otype, + PyArray_OutputConverter, &out)) { + goto fail; + } + indices = (PyArrayObject *)PyArray_FromAny(obj_ind, indtype, + 1, 1, NPY_ARRAY_CARRAY, NULL); + if (indices == NULL) { + goto fail; + } + } + else if (operation == UFUNC_ACCUMULATE) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO&O&:accumulate", + accumulate_kwlist, + &op, + &axes_in, + PyArray_DescrConverter2, &otype, + PyArray_OutputConverter, &out)) { + goto fail; + } + } + else { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO&O&i:reduce", + reduce_kwlist, + &op, + &axes_in, + PyArray_DescrConverter2, &otype, + PyArray_OutputConverter, &out, + &keepdims)) { + goto fail; + } + } + /* Ensure input is an array */ + if (!PyArray_Check(op) && !PyArray_IsScalar(op, Generic)) { + context = Py_BuildValue("O(O)i", ufunc, op, 0); + } + else { + context = NULL; + } + mp = (PyArrayObject *)PyArray_FromAny(op, NULL, 0, 0, 0, context); + Py_XDECREF(context); + if (mp == NULL) { + goto fail; + } + + ndim = PyArray_NDIM(mp); + + /* Check to see that type (and otype) is not FLEXIBLE */ + if (PyArray_ISFLEXIBLE(mp) || + (otype && PyTypeNum_ISFLEXIBLE(otype->type_num))) { + PyErr_Format(PyExc_TypeError, + "cannot perform %s with flexible type", + _reduce_type[operation]); + goto fail; + } + + /* Convert the 'axis' parameter into a list of axes */ + if (axes_in == NULL) { + naxes = 1; + axes[0] = 0; + } + /* Convert 'None' into all the axes */ + else if (axes_in == Py_None) { + naxes = ndim; + for (i = 0; i < naxes; ++i) { + axes[i] = i; + } + } + else if (PyTuple_Check(axes_in)) { + naxes = PyTuple_Size(axes_in); + if (naxes < 0 || naxes > NPY_MAXDIMS) { + PyErr_SetString(PyExc_ValueError, + "too many values for 'axis'"); + goto fail; + } + for (i = 0; i < naxes; ++i) { + PyObject *tmp = PyTuple_GET_ITEM(axes_in, i); + int axis = PyArray_PyIntAsInt(tmp); + if (error_converting(axis)) { + goto fail; + } + if (check_and_adjust_axis(&axis, ndim) < 0) { + goto fail; + } + axes[i] = (int)axis; + } + } + /* Try to interpret axis as an integer */ + else { + int axis = PyArray_PyIntAsInt(axes_in); + /* TODO: PyNumber_Index would be good to use here */ + if (error_converting(axis)) { + goto fail; + } + /* Special case letting axis={0 or -1} slip through for scalars */ + if (ndim == 0 && (axis == 0 || axis == -1)) { + axis = 0; + } + else if (check_and_adjust_axis(&axis, ndim) < 0) { + goto fail; + } + axes[0] = (int)axis; + naxes = 1; + } + + /* Check to see if input is zero-dimensional. */ + if (ndim == 0) { + /* + * A reduction with no axes is still valid but trivial. + * As a special case for backwards compatibility in 'sum', + * 'prod', et al, also allow a reduction where axis=0, even + * though this is technically incorrect. + */ + naxes = 0; + + if (!(operation == UFUNC_REDUCE && + (naxes == 0 || (naxes == 1 && axes[0] == 0)))) { + PyErr_Format(PyExc_TypeError, "cannot %s on a scalar", + _reduce_type[operation]); + goto fail; + } + } + + /* + * If out is specified it determines otype + * unless otype already specified. + */ + if (otype == NULL && out != NULL) { + otype = PyArray_DESCR(out); + Py_INCREF(otype); + } + if (otype == NULL) { + /* + * For integer types --- make sure at least a long + * is used for add and multiply reduction to avoid overflow + */ + int typenum = PyArray_TYPE(mp); + if ((PyTypeNum_ISBOOL(typenum) || PyTypeNum_ISINTEGER(typenum)) + && ((strcmp(ufunc->name,"add") == 0) + || (strcmp(ufunc->name,"multiply") == 0))) { + if (PyTypeNum_ISBOOL(typenum)) { + typenum = NPY_LONG; + } + else if ((size_t)PyArray_DESCR(mp)->elsize < sizeof(long)) { + if (PyTypeNum_ISUNSIGNED(typenum)) { + typenum = NPY_ULONG; + } + else { + typenum = NPY_LONG; + } + } + } + otype = PyArray_DescrFromType(typenum); + } + + + switch(operation) { + case UFUNC_REDUCE: + ret = PyUFunc_Reduce(ufunc, mp, out, naxes, axes, + otype, keepdims); + break; + case UFUNC_ACCUMULATE: + if (naxes != 1) { + PyErr_SetString(PyExc_ValueError, + "accumulate does not allow multiple axes"); + goto fail; + } + ret = (PyArrayObject *)PyUFunc_Accumulate(ufunc, mp, out, axes[0], + otype->type_num); + break; + case UFUNC_REDUCEAT: + if (naxes != 1) { + PyErr_SetString(PyExc_ValueError, + "reduceat does not allow multiple axes"); + goto fail; + } + ret = (PyArrayObject *)PyUFunc_Reduceat(ufunc, mp, indices, out, + axes[0], otype->type_num); + Py_DECREF(indices); + break; + } + Py_DECREF(mp); + Py_DECREF(otype); + + if (ret == NULL) { + return NULL; + } + + /* If an output parameter was provided, don't wrap it */ + if (out != NULL) { + return (PyObject *)ret; + } + + if (Py_TYPE(op) != Py_TYPE(ret)) { + res = PyObject_CallMethod(op, "__array_wrap__", "O", ret); + if (res == NULL) { + PyErr_Clear(); + } + else if (res == Py_None) { + Py_DECREF(res); + } + else { + Py_DECREF(ret); + return res; + } + } + return PyArray_Return(ret); + +fail: + Py_XDECREF(otype); + Py_XDECREF(mp); + return NULL; +} + +/* + * Returns an incref'ed pointer to the proper wrapping object for a + * ufunc output argument, given the output argument 'out', and the + * input's wrapping function, 'wrap'. + */ +static PyObject* +_get_out_wrap(PyObject *out, PyObject *wrap) { + PyObject *owrap; + + if (out == Py_None) { + /* Iterator allocated outputs get the input's wrapping */ + Py_XINCREF(wrap); + return wrap; + } + if (PyArray_CheckExact(out)) { + /* None signals to not call any wrapping */ + Py_RETURN_NONE; + } + /* + * For array subclasses use their __array_wrap__ method, or the + * input's wrapping if not available + */ + owrap = PyObject_GetAttr(out, npy_um_str_array_wrap); + if (owrap == NULL || !PyCallable_Check(owrap)) { + Py_XDECREF(owrap); + owrap = wrap; + Py_XINCREF(wrap); + PyErr_Clear(); + } + return owrap; +} + +/* + * This function analyzes the input arguments + * and determines an appropriate __array_wrap__ function to call + * for the outputs. + * + * If an output argument is provided, then it is wrapped + * with its own __array_wrap__ not with the one determined by + * the input arguments. + * + * if the provided output argument is already an array, + * the wrapping function is None (which means no wrapping will + * be done --- not even PyArray_Return). + * + * A NULL is placed in output_wrap for outputs that + * should just have PyArray_Return called. + */ +static void +_find_array_wrap(PyObject *args, PyObject *kwds, + PyObject **output_wrap, int nin, int nout) +{ + Py_ssize_t nargs; + int i, idx_offset, start_idx; + int np = 0; + PyObject *with_wrap[NPY_MAXARGS], *wraps[NPY_MAXARGS]; + PyObject *obj, *wrap = NULL; + + /* + * If a 'subok' parameter is passed and isn't True, don't wrap but put None + * into slots with out arguments which means return the out argument + */ + if (kwds != NULL && (obj = PyDict_GetItem(kwds, + npy_um_str_subok)) != NULL) { + if (obj != Py_True) { + /* skip search for wrap members */ + goto handle_out; + } + } + + + for (i = 0; i < nin; i++) { + obj = PyTuple_GET_ITEM(args, i); + if (PyArray_CheckExact(obj) || PyArray_IsAnyScalar(obj)) { + continue; + } + wrap = PyObject_GetAttr(obj, npy_um_str_array_wrap); + if (wrap) { + if (PyCallable_Check(wrap)) { + with_wrap[np] = obj; + wraps[np] = wrap; + ++np; + } + else { + Py_DECREF(wrap); + wrap = NULL; + } + } + else { + PyErr_Clear(); + } + } + if (np > 0) { + /* If we have some wraps defined, find the one of highest priority */ + wrap = wraps[0]; + if (np > 1) { + double maxpriority = PyArray_GetPriority(with_wrap[0], + NPY_PRIORITY); + for (i = 1; i < np; ++i) { + double priority = PyArray_GetPriority(with_wrap[i], + NPY_PRIORITY); + if (priority > maxpriority) { + maxpriority = priority; + Py_DECREF(wrap); + wrap = wraps[i]; + } + else { + Py_DECREF(wraps[i]); + } + } + } + } + + /* + * Here wrap is the wrapping function determined from the + * input arrays (could be NULL). + * + * For all the output arrays decide what to do. + * + * 1) Use the wrap function determined from the input arrays + * This is the default if the output array is not + * passed in. + * + * 2) Use the __array_wrap__ method of the output object + * passed in. -- this is special cased for + * exact ndarray so that no PyArray_Return is + * done in that case. + */ +handle_out: + nargs = PyTuple_GET_SIZE(args); + /* Default is using positional arguments */ + obj = args; + idx_offset = nin; + start_idx = 0; + if (nin == nargs && kwds != NULL) { + /* There may be a keyword argument we can use instead */ + obj = PyDict_GetItem(kwds, npy_um_str_out); + if (obj == NULL) { + /* No, go back to positional (even though there aren't any) */ + obj = args; + } + else { + idx_offset = 0; + if (PyTuple_Check(obj)) { + /* If a tuple, must have all nout items */ + nargs = nout; + } + else { + /* If the kwarg is not a tuple then it is an array (or None) */ + output_wrap[0] = _get_out_wrap(obj, wrap); + start_idx = 1; + nargs = 1; + } + } + } + + for (i = start_idx; i < nout; ++i) { + int j = idx_offset + i; + + if (j < nargs) { + output_wrap[i] = _get_out_wrap(PyTuple_GET_ITEM(obj, j), + wrap); + } + else { + output_wrap[i] = wrap; + Py_XINCREF(wrap); + } + } + + Py_XDECREF(wrap); + return; +} + + +static PyObject * +ufunc_generic_call(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) +{ + int i; + PyTupleObject *ret; + PyArrayObject *mps[NPY_MAXARGS]; + PyObject *retobj[NPY_MAXARGS]; + PyObject *wraparr[NPY_MAXARGS]; + PyObject *res; + PyObject *override = NULL; + int errval; + + /* + * Initialize all array objects to NULL to make cleanup easier + * if something goes wrong. + */ + for (i = 0; i < ufunc->nargs; i++) { + mps[i] = NULL; + } + + errval = PyUFunc_CheckOverride(ufunc, "__call__", args, kwds, &override); + if (errval) { + return NULL; + } + else if (override) { + for (i = 0; i < ufunc->nargs; i++) { + PyArray_DiscardWritebackIfCopy(mps[i]); + Py_XDECREF(mps[i]); + } + return override; + } + + errval = PyUFunc_GenericFunction(ufunc, args, kwds, mps); + if (errval < 0) { + for (i = 0; i < ufunc->nargs; i++) { + PyArray_DiscardWritebackIfCopy(mps[i]); + Py_XDECREF(mps[i]); + } + if (errval == -1) { + return NULL; + } + else if (ufunc->nin == 2 && ufunc->nout == 1) { + /* + * For array_richcompare's benefit -- see the long comment in + * get_ufunc_arguments. + */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + else { + PyErr_SetString(PyExc_TypeError, + "XX can't happen, please report a bug XX"); + return NULL; + } + } + + /* Free the input references */ + for (i = 0; i < ufunc->nin; i++) { + Py_XDECREF(mps[i]); + } + + /* + * Use __array_wrap__ on all outputs + * if present on one of the input arguments. + * If present for multiple inputs: + * use __array_wrap__ of input object with largest + * __array_priority__ (default = 0.0) + * + * Exception: we should not wrap outputs for items already + * passed in as output-arguments. These items should either + * be left unwrapped or wrapped by calling their own __array_wrap__ + * routine. + * + * For each output argument, wrap will be either + * NULL --- call PyArray_Return() -- default if no output arguments given + * None --- array-object passed in don't call PyArray_Return + * method --- the __array_wrap__ method to call. + */ + _find_array_wrap(args, kwds, wraparr, ufunc->nin, ufunc->nout); + + /* wrap outputs */ + for (i = 0; i < ufunc->nout; i++) { + int j = ufunc->nin+i; + PyObject *wrap = wraparr[i]; + + if (wrap != NULL) { + if (wrap == Py_None) { + Py_DECREF(wrap); + retobj[i] = (PyObject *)mps[j]; + continue; + } + res = PyObject_CallFunction(wrap, "O(OOi)", mps[j], ufunc, args, i); + /* Handle __array_wrap__ that does not accept a context argument */ + if (res == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + res = PyObject_CallFunctionObjArgs(wrap, mps[j], NULL); + } + Py_DECREF(wrap); + if (res == NULL) { + goto fail; + } + else { + Py_DECREF(mps[j]); + retobj[i] = res; + continue; + } + } + else { + /* default behavior */ + retobj[i] = PyArray_Return(mps[j]); + } + + } + + if (ufunc->nout == 1) { + return retobj[0]; + } + else { + ret = (PyTupleObject *)PyTuple_New(ufunc->nout); + for (i = 0; i < ufunc->nout; i++) { + PyTuple_SET_ITEM(ret, i, retobj[i]); + } + return (PyObject *)ret; + } + +fail: + for (i = ufunc->nin; i < ufunc->nargs; i++) { + Py_XDECREF(mps[i]); + } + return NULL; +} + +NPY_NO_EXPORT PyObject * +ufunc_geterr(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyObject *thedict; + PyObject *res; + + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + thedict = PyThreadState_GetDict(); + if (thedict == NULL) { + thedict = PyEval_GetBuiltins(); + } + res = PyDict_GetItem(thedict, npy_um_str_pyvals_name); + if (res != NULL) { + Py_INCREF(res); + return res; + } + /* Construct list of defaults */ + res = PyList_New(3); + if (res == NULL) { + return NULL; + } + PyList_SET_ITEM(res, 0, PyInt_FromLong(NPY_BUFSIZE)); + PyList_SET_ITEM(res, 1, PyInt_FromLong(UFUNC_ERR_DEFAULT)); + PyList_SET_ITEM(res, 2, Py_None); Py_INCREF(Py_None); + return res; +} + +NPY_NO_EXPORT PyObject * +ufunc_seterr(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyObject *thedict; + int res; + PyObject *val; + static char *msg = "Error object must be a list of length 3"; + + if (!PyArg_ParseTuple(args, "O:seterrobj", &val)) { + return NULL; + } + if (!PyList_CheckExact(val) || PyList_GET_SIZE(val) != 3) { + PyErr_SetString(PyExc_ValueError, msg); + return NULL; + } + thedict = PyThreadState_GetDict(); + if (thedict == NULL) { + thedict = PyEval_GetBuiltins(); + } + res = PyDict_SetItem(thedict, npy_um_str_pyvals_name, val); + if (res < 0) { + return NULL; + } +#if USE_USE_DEFAULTS==1 + if (ufunc_update_use_defaults() < 0) { + return NULL; + } +#endif + Py_RETURN_NONE; +} + + + +/*UFUNC_API*/ +NPY_NO_EXPORT int +PyUFunc_ReplaceLoopBySignature(PyUFuncObject *func, + PyUFuncGenericFunction newfunc, + int *signature, + PyUFuncGenericFunction *oldfunc) +{ + int i, j; + int res = -1; + /* Find the location of the matching signature */ + for (i = 0; i < func->ntypes; i++) { + for (j = 0; j < func->nargs; j++) { + if (signature[j] != func->types[i*func->nargs+j]) { + break; + } + } + if (j < func->nargs) { + continue; + } + if (oldfunc != NULL) { + *oldfunc = func->functions[i]; + } + func->functions[i] = newfunc; + res = 0; + break; + } + return res; +} + +/*UFUNC_API*/ +NPY_NO_EXPORT PyObject * +PyUFunc_FromFuncAndData(PyUFuncGenericFunction *func, void **data, + char *types, int ntypes, + int nin, int nout, int identity, + const char *name, const char *doc, int unused) +{ + return PyUFunc_FromFuncAndDataAndSignature(func, data, types, ntypes, + nin, nout, identity, name, doc, 0, NULL); +} + +/*UFUNC_API*/ +NPY_NO_EXPORT PyObject * +PyUFunc_FromFuncAndDataAndSignature(PyUFuncGenericFunction *func, void **data, + char *types, int ntypes, + int nin, int nout, int identity, + const char *name, const char *doc, + int unused, const char *signature) +{ + PyUFuncObject *ufunc; + + if (nin + nout > NPY_MAXARGS) { + PyErr_Format(PyExc_ValueError, + "Cannot construct a ufunc with more than %d operands " + "(requested number were: inputs = %d and outputs = %d)", + NPY_MAXARGS, nin, nout); + return NULL; + } + + ufunc = PyArray_malloc(sizeof(PyUFuncObject)); + if (ufunc == NULL) { + return NULL; + } + PyObject_Init((PyObject *)ufunc, &PyUFunc_Type); + + ufunc->reserved1 = 0; + ufunc->reserved2 = NULL; + + ufunc->nin = nin; + ufunc->nout = nout; + ufunc->nargs = nin+nout; + ufunc->identity = identity; + + ufunc->functions = func; + ufunc->data = data; + ufunc->types = types; + ufunc->ntypes = ntypes; + ufunc->ptr = NULL; + ufunc->obj = NULL; + ufunc->userloops=NULL; + + /* Type resolution and inner loop selection functions */ + ufunc->type_resolver = &PyUFunc_DefaultTypeResolver; + ufunc->legacy_inner_loop_selector = &PyUFunc_DefaultLegacyInnerLoopSelector; + ufunc->masked_inner_loop_selector = &PyUFunc_DefaultMaskedInnerLoopSelector; + + if (name == NULL) { + ufunc->name = "?"; + } + else { + ufunc->name = name; + } + ufunc->doc = doc; + + ufunc->op_flags = PyArray_malloc(sizeof(npy_uint32)*ufunc->nargs); + if (ufunc->op_flags == NULL) { + return PyErr_NoMemory(); + } + memset(ufunc->op_flags, 0, sizeof(npy_uint32)*ufunc->nargs); + + ufunc->iter_flags = 0; + + /* generalized ufunc */ + ufunc->core_enabled = 0; + ufunc->core_num_dim_ix = 0; + ufunc->core_num_dims = NULL; + ufunc->core_dim_ixs = NULL; + ufunc->core_offsets = NULL; + ufunc->core_signature = NULL; + if (signature != NULL) { + if (_parse_signature(ufunc, signature) != 0) { + Py_DECREF(ufunc); + return NULL; + } + } + return (PyObject *)ufunc; +} + +/* Specify that the loop specified by the given index should use the array of + * input and arrays as the data pointer to the loop. + */ +/*UFUNC_API*/ +NPY_NO_EXPORT int +PyUFunc_SetUsesArraysAsData(void **data, size_t i) +{ + data[i] = (void*)PyUFunc_SetUsesArraysAsData; + return 0; +} + +/* + * Return 1 if the given data pointer for the loop specifies that it needs the + * arrays as the data pointer. + * + * NOTE: This is easier to specify with the type_resolver + * in the ufunc object. + * + * TODO: Remove this, since this is already basically broken + * with the addition of the masked inner loops and + * not worth fixing since the new loop selection functions + * have access to the full dtypes and can dynamically allocate + * arbitrary auxiliary data. + */ +static int +_does_loop_use_arrays(void *data) +{ + return (data == PyUFunc_SetUsesArraysAsData); +} + + +/* + * This is the first-part of the CObject structure. + * + * I don't think this will change, but if it should, then + * this needs to be fixed. The exposed C-API was insufficient + * because I needed to replace the pointer and it wouldn't + * let me with a destructor set (even though it works fine + * with the destructor). + */ +typedef struct { + PyObject_HEAD + void *c_obj; +} _simple_cobj; + +#define _SETCPTR(cobj, val) ((_simple_cobj *)(cobj))->c_obj = (val) + +/* return 1 if arg1 > arg2, 0 if arg1 == arg2, and -1 if arg1 < arg2 */ +static int +cmp_arg_types(int *arg1, int *arg2, int n) +{ + for (; n > 0; n--, arg1++, arg2++) { + if (PyArray_EquivTypenums(*arg1, *arg2)) { + continue; + } + if (PyArray_CanCastSafely(*arg1, *arg2)) { + return -1; + } + return 1; + } + return 0; +} + +/* + * This frees the linked-list structure when the CObject + * is destroyed (removed from the internal dictionary) +*/ +static NPY_INLINE void +_free_loop1d_list(PyUFunc_Loop1d *data) +{ + int i; + + while (data != NULL) { + PyUFunc_Loop1d *next = data->next; + PyArray_free(data->arg_types); + + if (data->arg_dtypes != NULL) { + for (i = 0; i < data->nargs; i++) { + Py_DECREF(data->arg_dtypes[i]); + } + PyArray_free(data->arg_dtypes); + } + + PyArray_free(data); + data = next; + } +} + +#if PY_VERSION_HEX >= 0x03000000 +static void +_loop1d_list_free(PyObject *ptr) +{ + PyUFunc_Loop1d *data = (PyUFunc_Loop1d *)PyCapsule_GetPointer(ptr, NULL); + _free_loop1d_list(data); +} +#else +static void +_loop1d_list_free(void *ptr) +{ + PyUFunc_Loop1d *data = (PyUFunc_Loop1d *)ptr; + _free_loop1d_list(data); +} +#endif + + +/* + * This function allows the user to register a 1-d loop with an already + * created ufunc. This function is similar to RegisterLoopForType except + * that it allows a 1-d loop to be registered with PyArray_Descr objects + * instead of dtype type num values. This allows a 1-d loop to be registered + * for a structured array dtype or a custom dtype. The ufunc is called + * whenever any of it's input arguments match the user_dtype argument. + * ufunc - ufunc object created from call to PyUFunc_FromFuncAndData + * user_dtype - dtype that ufunc will be registered with + * function - 1-d loop function pointer + * arg_dtypes - array of dtype objects describing the ufunc operands + * data - arbitrary data pointer passed in to loop function + */ +/*UFUNC_API*/ +NPY_NO_EXPORT int +PyUFunc_RegisterLoopForDescr(PyUFuncObject *ufunc, + PyArray_Descr *user_dtype, + PyUFuncGenericFunction function, + PyArray_Descr **arg_dtypes, + void *data) +{ + int i; + int result = 0; + int *arg_typenums; + PyObject *key, *cobj; + + if (user_dtype == NULL) { + PyErr_SetString(PyExc_TypeError, + "unknown user defined struct dtype"); + return -1; + } + + key = PyInt_FromLong((long) user_dtype->type_num); + if (key == NULL) { + return -1; + } + + arg_typenums = PyArray_malloc(ufunc->nargs * sizeof(int)); + if (arg_typenums == NULL) { + PyErr_NoMemory(); + return -1; + } + if (arg_dtypes != NULL) { + for (i = 0; i < ufunc->nargs; i++) { + arg_typenums[i] = arg_dtypes[i]->type_num; + } + } + else { + for (i = 0; i < ufunc->nargs; i++) { + arg_typenums[i] = user_dtype->type_num; + } + } + + result = PyUFunc_RegisterLoopForType(ufunc, user_dtype->type_num, + function, arg_typenums, data); + + if (result == 0) { + cobj = PyDict_GetItem(ufunc->userloops, key); + if (cobj == NULL) { + PyErr_SetString(PyExc_KeyError, + "userloop for user dtype not found"); + result = -1; + } + else { + PyUFunc_Loop1d *current; + int cmp = 1; + current = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(cobj); + while (current != NULL) { + cmp = cmp_arg_types(current->arg_types, + arg_typenums, ufunc->nargs); + if (cmp >= 0 && current->arg_dtypes == NULL) { + break; + } + current = current->next; + } + if (cmp == 0 && current->arg_dtypes == NULL) { + current->arg_dtypes = PyArray_malloc(ufunc->nargs * + sizeof(PyArray_Descr*)); + if (arg_dtypes != NULL) { + for (i = 0; i < ufunc->nargs; i++) { + current->arg_dtypes[i] = arg_dtypes[i]; + Py_INCREF(current->arg_dtypes[i]); + } + } + else { + for (i = 0; i < ufunc->nargs; i++) { + current->arg_dtypes[i] = user_dtype; + Py_INCREF(current->arg_dtypes[i]); + } + } + current->nargs = ufunc->nargs; + } + else { + result = -1; + } + } + } + + PyArray_free(arg_typenums); + + Py_DECREF(key); + + return result; +} + +/*UFUNC_API*/ +NPY_NO_EXPORT int +PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc, + int usertype, + PyUFuncGenericFunction function, + int *arg_types, + void *data) +{ + PyArray_Descr *descr; + PyUFunc_Loop1d *funcdata; + PyObject *key, *cobj; + int i; + int *newtypes=NULL; + + descr=PyArray_DescrFromType(usertype); + if ((usertype < NPY_USERDEF && usertype != NPY_VOID) || (descr==NULL)) { + PyErr_SetString(PyExc_TypeError, "unknown user-defined type"); + return -1; + } + Py_DECREF(descr); + + if (ufunc->userloops == NULL) { + ufunc->userloops = PyDict_New(); + } + key = PyInt_FromLong((long) usertype); + if (key == NULL) { + return -1; + } + funcdata = PyArray_malloc(sizeof(PyUFunc_Loop1d)); + if (funcdata == NULL) { + goto fail; + } + newtypes = PyArray_malloc(sizeof(int)*ufunc->nargs); + if (newtypes == NULL) { + goto fail; + } + if (arg_types != NULL) { + for (i = 0; i < ufunc->nargs; i++) { + newtypes[i] = arg_types[i]; + } + } + else { + for (i = 0; i < ufunc->nargs; i++) { + newtypes[i] = usertype; + } + } + + funcdata->func = function; + funcdata->arg_types = newtypes; + funcdata->data = data; + funcdata->next = NULL; + funcdata->arg_dtypes = NULL; + funcdata->nargs = 0; + + /* Get entry for this user-defined type*/ + cobj = PyDict_GetItem(ufunc->userloops, key); + /* If it's not there, then make one and return. */ + if (cobj == NULL) { + cobj = NpyCapsule_FromVoidPtr((void *)funcdata, _loop1d_list_free); + if (cobj == NULL) { + goto fail; + } + PyDict_SetItem(ufunc->userloops, key, cobj); + Py_DECREF(cobj); + Py_DECREF(key); + return 0; + } + else { + PyUFunc_Loop1d *current, *prev = NULL; + int cmp = 1; + /* + * There is already at least 1 loop. Place this one in + * lexicographic order. If the next one signature + * is exactly like this one, then just replace. + * Otherwise insert. + */ + current = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(cobj); + while (current != NULL) { + cmp = cmp_arg_types(current->arg_types, newtypes, ufunc->nargs); + if (cmp >= 0) { + break; + } + prev = current; + current = current->next; + } + if (cmp == 0) { + /* just replace it with new function */ + current->func = function; + current->data = data; + PyArray_free(newtypes); + PyArray_free(funcdata); + } + else { + /* + * insert it before the current one by hacking the internals + * of cobject to replace the function pointer --- can't use + * CObject API because destructor is set. + */ + funcdata->next = current; + if (prev == NULL) { + /* place this at front */ + _SETCPTR(cobj, funcdata); + } + else { + prev->next = funcdata; + } + } + } + Py_DECREF(key); + return 0; + + fail: + Py_DECREF(key); + PyArray_free(funcdata); + PyArray_free(newtypes); + if (!PyErr_Occurred()) PyErr_NoMemory(); + return -1; +} + +#undef _SETCPTR + + +static void +ufunc_dealloc(PyUFuncObject *ufunc) +{ + PyArray_free(ufunc->core_num_dims); + PyArray_free(ufunc->core_dim_ixs); + PyArray_free(ufunc->core_offsets); + PyArray_free(ufunc->core_signature); + PyArray_free(ufunc->ptr); + PyArray_free(ufunc->op_flags); + Py_XDECREF(ufunc->userloops); + Py_XDECREF(ufunc->obj); + PyArray_free(ufunc); +} + +static PyObject * +ufunc_repr(PyUFuncObject *ufunc) +{ + return PyUString_FromFormat("", ufunc->name); +} + + +/****************************************************************************** + *** UFUNC METHODS *** + *****************************************************************************/ + + +/* + * op.outer(a,b) is equivalent to op(a[:,NewAxis,NewAxis,etc.],b) + * where a has b.ndim NewAxis terms appended. + * + * The result has dimensions a.ndim + b.ndim + */ +static PyObject * +ufunc_outer(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) +{ + int i; + int errval; + PyObject *override = NULL; + PyObject *ret; + PyArrayObject *ap1 = NULL, *ap2 = NULL, *ap_new = NULL; + PyObject *new_args, *tmp; + PyObject *shape1, *shape2, *newshape; + + errval = PyUFunc_CheckOverride(ufunc, "outer", args, kwds, &override); + if (errval) { + return NULL; + } + else if (override) { + return override; + } + + if (ufunc->core_enabled) { + PyErr_Format(PyExc_TypeError, + "method outer is not allowed in ufunc with non-trivial"\ + " signature"); + return NULL; + } + + if (ufunc->nin != 2) { + PyErr_SetString(PyExc_ValueError, + "outer product only supported "\ + "for binary functions"); + return NULL; + } + + if (PySequence_Length(args) != 2) { + PyErr_SetString(PyExc_TypeError, "exactly two arguments expected"); + return NULL; + } + + tmp = PySequence_GetItem(args, 0); + if (tmp == NULL) { + return NULL; + } + ap1 = (PyArrayObject *) PyArray_FromObject(tmp, NPY_NOTYPE, 0, 0); + Py_DECREF(tmp); + if (ap1 == NULL) { + return NULL; + } + tmp = PySequence_GetItem(args, 1); + if (tmp == NULL) { + return NULL; + } + ap2 = (PyArrayObject *)PyArray_FromObject(tmp, NPY_NOTYPE, 0, 0); + Py_DECREF(tmp); + if (ap2 == NULL) { + Py_DECREF(ap1); + return NULL; + } + /* Construct new shape tuple */ + shape1 = PyTuple_New(PyArray_NDIM(ap1)); + if (shape1 == NULL) { + goto fail; + } + for (i = 0; i < PyArray_NDIM(ap1); i++) { + PyTuple_SET_ITEM(shape1, i, + PyLong_FromLongLong((npy_longlong)PyArray_DIMS(ap1)[i])); + } + shape2 = PyTuple_New(PyArray_NDIM(ap2)); + for (i = 0; i < PyArray_NDIM(ap2); i++) { + PyTuple_SET_ITEM(shape2, i, PyInt_FromLong((long) 1)); + } + if (shape2 == NULL) { + Py_DECREF(shape1); + goto fail; + } + newshape = PyNumber_Add(shape1, shape2); + Py_DECREF(shape1); + Py_DECREF(shape2); + if (newshape == NULL) { + goto fail; + } + ap_new = (PyArrayObject *)PyArray_Reshape(ap1, newshape); + Py_DECREF(newshape); + if (ap_new == NULL) { + goto fail; + } + new_args = Py_BuildValue("(OO)", ap_new, ap2); + Py_DECREF(ap1); + Py_DECREF(ap2); + Py_DECREF(ap_new); + ret = ufunc_generic_call(ufunc, new_args, kwds); + Py_DECREF(new_args); + return ret; + + fail: + Py_XDECREF(ap1); + Py_XDECREF(ap2); + Py_XDECREF(ap_new); + return NULL; +} + + +static PyObject * +ufunc_reduce(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) +{ + int errval; + PyObject *override = NULL; + + errval = PyUFunc_CheckOverride(ufunc, "reduce", args, kwds, &override); + if (errval) { + return NULL; + } + else if (override) { + return override; + } + return PyUFunc_GenericReduction(ufunc, args, kwds, UFUNC_REDUCE); +} + +static PyObject * +ufunc_accumulate(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) +{ + int errval; + PyObject *override = NULL; + + errval = PyUFunc_CheckOverride(ufunc, "accumulate", args, kwds, &override); + if (errval) { + return NULL; + } + else if (override) { + return override; + } + return PyUFunc_GenericReduction(ufunc, args, kwds, UFUNC_ACCUMULATE); +} + +static PyObject * +ufunc_reduceat(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) +{ + int errval; + PyObject *override = NULL; + + errval = PyUFunc_CheckOverride(ufunc, "reduceat", args, kwds, &override); + if (errval) { + return NULL; + } + else if (override) { + return override; + } + return PyUFunc_GenericReduction(ufunc, args, kwds, UFUNC_REDUCEAT); +} + +/* Helper for ufunc_at, below */ +static NPY_INLINE PyArrayObject * +new_array_op(PyArrayObject *op_array, char *data) +{ + npy_intp dims[1] = {1}; + PyObject *r = PyArray_NewFromDescr(&PyArray_Type, PyArray_DESCR(op_array), + 1, dims, NULL, data, + NPY_ARRAY_WRITEABLE, NULL); + return (PyArrayObject *)r; +} + +/* + * Call ufunc only on selected array items and store result in first operand. + * For add ufunc, method call is equivalent to op1[idx] += op2 with no + * buffering of the first operand. + * Arguments: + * op1 - First operand to ufunc + * idx - Indices that are applied to first operand. Equivalent to op1[idx]. + * op2 - Second operand to ufunc (if needed). Must be able to broadcast + * over first operand. + */ +static PyObject * +ufunc_at(PyUFuncObject *ufunc, PyObject *args) +{ + PyObject *op1 = NULL; + PyObject *idx = NULL; + PyObject *op2 = NULL; + PyArrayObject *op1_array = NULL; + PyArrayObject *op2_array = NULL; + PyArrayMapIterObject *iter = NULL; + PyArrayIterObject *iter2 = NULL; + PyArray_Descr *dtypes[3] = {NULL, NULL, NULL}; + PyArrayObject *operands[3] = {NULL, NULL, NULL}; + PyArrayObject *array_operands[3] = {NULL, NULL, NULL}; + + int needs_api = 0; + + PyUFuncGenericFunction innerloop; + void *innerloopdata; + int i; + int nop; + + /* override vars */ + int errval; + PyObject *override = NULL; + + NpyIter *iter_buffer; + NpyIter_IterNextFunc *iternext; + npy_uint32 op_flags[NPY_MAXARGS]; + int buffersize; + int errormask = 0; + char * err_msg = NULL; + NPY_BEGIN_THREADS_DEF; + + errval = PyUFunc_CheckOverride(ufunc, "at", args, NULL, &override); + if (errval) { + return NULL; + } + else if (override) { + return override; + } + + if (ufunc->nin > 2) { + PyErr_SetString(PyExc_ValueError, + "Only unary and binary ufuncs supported at this time"); + return NULL; + } + + if (ufunc->nout != 1) { + PyErr_SetString(PyExc_ValueError, + "Only single output ufuncs supported at this time"); + return NULL; + } + + if (!PyArg_ParseTuple(args, "OO|O:at", &op1, &idx, &op2)) { + return NULL; + } + + if (ufunc->nin == 2 && op2 == NULL) { + PyErr_SetString(PyExc_ValueError, + "second operand needed for ufunc"); + return NULL; + } + + if (!PyArray_Check(op1)) { + PyErr_SetString(PyExc_TypeError, + "first operand must be array"); + return NULL; + } + + op1_array = (PyArrayObject *)op1; + + /* Create second operand from number array if needed. */ + if (op2 != NULL) { + op2_array = (PyArrayObject *)PyArray_FromAny(op2, NULL, + 0, 0, 0, NULL); + if (op2_array == NULL) { + goto fail; + } + } + + /* Create map iterator */ + iter = (PyArrayMapIterObject *)PyArray_MapIterArrayCopyIfOverlap( + op1_array, idx, 1, op2_array); + if (iter == NULL) { + goto fail; + } + op1_array = iter->array; /* May be updateifcopied on overlap */ + + if (op2 != NULL) { + /* + * May need to swap axes so that second operand is + * iterated over correctly + */ + if ((iter->subspace != NULL) && (iter->consec)) { + PyArray_MapIterSwapAxes(iter, &op2_array, 0); + if (op2_array == NULL) { + goto fail; + } + } + + /* + * Create array iter object for second operand that + * "matches" the map iter object for the first operand. + * Then we can just iterate over the first and second + * operands at the same time and not have to worry about + * picking the correct elements from each operand to apply + * the ufunc to. + */ + if ((iter2 = (PyArrayIterObject *)\ + PyArray_BroadcastToShape((PyObject *)op2_array, + iter->dimensions, iter->nd))==NULL) { + goto fail; + } + } + + /* + * Create dtypes array for either one or two input operands. + * The output operand is set to the first input operand + */ + dtypes[0] = PyArray_DESCR(op1_array); + operands[0] = op1_array; + if (op2_array != NULL) { + dtypes[1] = PyArray_DESCR(op2_array); + dtypes[2] = dtypes[0]; + operands[1] = op2_array; + operands[2] = op1_array; + nop = 3; + } + else { + dtypes[1] = dtypes[0]; + dtypes[2] = NULL; + operands[1] = op1_array; + operands[2] = NULL; + nop = 2; + } + + if (ufunc->type_resolver(ufunc, NPY_UNSAFE_CASTING, + operands, NULL, dtypes) < 0) { + goto fail; + } + if (ufunc->legacy_inner_loop_selector(ufunc, dtypes, + &innerloop, &innerloopdata, &needs_api) < 0) { + goto fail; + } + + Py_INCREF(PyArray_DESCR(op1_array)); + array_operands[0] = new_array_op(op1_array, iter->dataptr); + if (iter2 != NULL) { + Py_INCREF(PyArray_DESCR(op2_array)); + array_operands[1] = new_array_op(op2_array, PyArray_ITER_DATA(iter2)); + Py_INCREF(PyArray_DESCR(op1_array)); + array_operands[2] = new_array_op(op1_array, iter->dataptr); + } + else { + Py_INCREF(PyArray_DESCR(op1_array)); + array_operands[1] = new_array_op(op1_array, iter->dataptr); + array_operands[2] = NULL; + } + + /* Set up the flags */ + op_flags[0] = NPY_ITER_READONLY| + NPY_ITER_ALIGNED; + + if (iter2 != NULL) { + op_flags[1] = NPY_ITER_READONLY| + NPY_ITER_ALIGNED; + op_flags[2] = NPY_ITER_WRITEONLY| + NPY_ITER_ALIGNED| + NPY_ITER_ALLOCATE| + NPY_ITER_NO_BROADCAST| + NPY_ITER_NO_SUBTYPE; + } + else { + op_flags[1] = NPY_ITER_WRITEONLY| + NPY_ITER_ALIGNED| + NPY_ITER_ALLOCATE| + NPY_ITER_NO_BROADCAST| + NPY_ITER_NO_SUBTYPE; + } + + if (_get_bufsize_errmask(NULL, ufunc->name, &buffersize, &errormask) < 0) { + goto fail; + } + + /* + * Create NpyIter object to "iterate" over single element of each input + * operand. This is an easy way to reuse the NpyIter logic for dealing + * with certain cases like casting operands to correct dtype. On each + * iteration over the MapIterArray object created above, we'll take the + * current data pointers from that and reset this NpyIter object using + * those data pointers, and then trigger a buffer copy. The buffer data + * pointers from the NpyIter object will then be passed to the inner loop + * function. + */ + iter_buffer = NpyIter_AdvancedNew(nop, array_operands, + NPY_ITER_EXTERNAL_LOOP| + NPY_ITER_REFS_OK| + NPY_ITER_ZEROSIZE_OK| + NPY_ITER_BUFFERED| + NPY_ITER_GROWINNER| + NPY_ITER_DELAY_BUFALLOC, + NPY_KEEPORDER, NPY_UNSAFE_CASTING, + op_flags, dtypes, + -1, NULL, NULL, buffersize); + + if (iter_buffer == NULL) { + goto fail; + } + + needs_api = needs_api | NpyIter_IterationNeedsAPI(iter_buffer); + + iternext = NpyIter_GetIterNext(iter_buffer, NULL); + if (iternext == NULL) { + NpyIter_Deallocate(iter_buffer); + goto fail; + } + + if (!needs_api) { + NPY_BEGIN_THREADS; + } + + /* + * Iterate over first and second operands and call ufunc + * for each pair of inputs + */ + i = iter->size; + while (i > 0) + { + char *dataptr[3]; + char **buffer_dataptr; + /* one element at a time, no stride required but read by innerloop */ + npy_intp count[3] = {1, 0xDEADBEEF, 0xDEADBEEF}; + npy_intp stride[3] = {0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF}; + + /* + * Set up data pointers for either one or two input operands. + * The output data pointer points to the first operand data. + */ + dataptr[0] = iter->dataptr; + if (iter2 != NULL) { + dataptr[1] = PyArray_ITER_DATA(iter2); + dataptr[2] = iter->dataptr; + } + else { + dataptr[1] = iter->dataptr; + dataptr[2] = NULL; + } + + /* Reset NpyIter data pointers which will trigger a buffer copy */ + NpyIter_ResetBasePointers(iter_buffer, dataptr, &err_msg); + if (err_msg) { + break; + } + + buffer_dataptr = NpyIter_GetDataPtrArray(iter_buffer); + + innerloop(buffer_dataptr, count, stride, innerloopdata); + + if (needs_api && PyErr_Occurred()) { + break; + } + + /* + * Call to iternext triggers copy from buffer back to output array + * after innerloop puts result in buffer. + */ + iternext(iter_buffer); + + PyArray_MapIterNext(iter); + if (iter2 != NULL) { + PyArray_ITER_NEXT(iter2); + } + + i--; + } + + NPY_END_THREADS; + + if (err_msg) { + PyErr_SetString(PyExc_ValueError, err_msg); + } + + NpyIter_Deallocate(iter_buffer); + + if (op1_array != (PyArrayObject*)op1) { + PyArray_ResolveWritebackIfCopy(op1_array); + } + Py_XDECREF(op2_array); + Py_XDECREF(iter); + Py_XDECREF(iter2); + Py_XDECREF(array_operands[0]); + Py_XDECREF(array_operands[1]); + Py_XDECREF(array_operands[2]); + + if (needs_api && PyErr_Occurred()) { + return NULL; + } + else { + Py_RETURN_NONE; + } + +fail: + + if (op1_array != (PyArrayObject*)op1) { + PyArray_ResolveWritebackIfCopy(op1_array); + } + Py_XDECREF(op2_array); + Py_XDECREF(iter); + Py_XDECREF(iter2); + Py_XDECREF(array_operands[0]); + Py_XDECREF(array_operands[1]); + Py_XDECREF(array_operands[2]); + + return NULL; +} + + +static struct PyMethodDef ufunc_methods[] = { + {"reduce", + (PyCFunction)ufunc_reduce, + METH_VARARGS | METH_KEYWORDS, NULL }, + {"accumulate", + (PyCFunction)ufunc_accumulate, + METH_VARARGS | METH_KEYWORDS, NULL }, + {"reduceat", + (PyCFunction)ufunc_reduceat, + METH_VARARGS | METH_KEYWORDS, NULL }, + {"outer", + (PyCFunction)ufunc_outer, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"at", + (PyCFunction)ufunc_at, + METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} /* sentinel */ +}; + + +/****************************************************************************** + *** UFUNC GETSET *** + *****************************************************************************/ + + +static char +_typecharfromnum(int num) { + PyArray_Descr *descr; + char ret; + + descr = PyArray_DescrFromType(num); + ret = descr->type; + Py_DECREF(descr); + return ret; +} + +static PyObject * +ufunc_get_doc(PyUFuncObject *ufunc) +{ + static PyObject *_sig_formatter; + PyObject *doc; + + npy_cache_import( + "numpy.core._internal", + "_ufunc_doc_signature_formatter", + &_sig_formatter); + + if (_sig_formatter == NULL) { + return NULL; + } + + /* + * Put docstring first or FindMethod finds it... could so some + * introspection on name and nin + nout to automate the first part + * of it the doc string shouldn't need the calling convention + */ + doc = PyObject_CallFunctionObjArgs( + _sig_formatter, (PyObject *)ufunc, NULL); + if (doc == NULL) { + return NULL; + } + if (ufunc->doc != NULL) { + PyUString_ConcatAndDel(&doc, + PyUString_FromFormat("\n\n%s", ufunc->doc)); + } + return doc; +} + +static PyObject * +ufunc_get_nin(PyUFuncObject *ufunc) +{ + return PyInt_FromLong(ufunc->nin); +} + +static PyObject * +ufunc_get_nout(PyUFuncObject *ufunc) +{ + return PyInt_FromLong(ufunc->nout); +} + +static PyObject * +ufunc_get_nargs(PyUFuncObject *ufunc) +{ + return PyInt_FromLong(ufunc->nargs); +} + +static PyObject * +ufunc_get_ntypes(PyUFuncObject *ufunc) +{ + return PyInt_FromLong(ufunc->ntypes); +} + +static PyObject * +ufunc_get_types(PyUFuncObject *ufunc) +{ + /* return a list with types grouped input->output */ + PyObject *list; + PyObject *str; + int k, j, n, nt = ufunc->ntypes; + int ni = ufunc->nin; + int no = ufunc->nout; + char *t; + list = PyList_New(nt); + if (list == NULL) { + return NULL; + } + t = PyArray_malloc(no+ni+2); + n = 0; + for (k = 0; k < nt; k++) { + for (j = 0; jtypes[n]); + n++; + } + t[ni] = '-'; + t[ni+1] = '>'; + for (j = 0; j < no; j++) { + t[ni + 2 + j] = _typecharfromnum(ufunc->types[n]); + n++; + } + str = PyUString_FromStringAndSize(t, no + ni + 2); + PyList_SET_ITEM(list, k, str); + } + PyArray_free(t); + return list; +} + +static PyObject * +ufunc_get_name(PyUFuncObject *ufunc) +{ + return PyUString_FromString(ufunc->name); +} + +static PyObject * +ufunc_get_identity(PyUFuncObject *ufunc) +{ + switch(ufunc->identity) { + case PyUFunc_One: + return PyInt_FromLong(1); + case PyUFunc_Zero: + return PyInt_FromLong(0); + case PyUFunc_MinusOne: + return PyInt_FromLong(-1); + } + Py_RETURN_NONE; +} + +static PyObject * +ufunc_get_signature(PyUFuncObject *ufunc) +{ + if (!ufunc->core_enabled) { + Py_RETURN_NONE; + } + return PyUString_FromString(ufunc->core_signature); +} + +#undef _typecharfromnum + +/* + * Docstring is now set from python + * static char *Ufunctype__doc__ = NULL; + */ +static PyGetSetDef ufunc_getset[] = { + {"__doc__", + (getter)ufunc_get_doc, + NULL, NULL, NULL}, + {"nin", + (getter)ufunc_get_nin, + NULL, NULL, NULL}, + {"nout", + (getter)ufunc_get_nout, + NULL, NULL, NULL}, + {"nargs", + (getter)ufunc_get_nargs, + NULL, NULL, NULL}, + {"ntypes", + (getter)ufunc_get_ntypes, + NULL, NULL, NULL}, + {"types", + (getter)ufunc_get_types, + NULL, NULL, NULL}, + {"__name__", + (getter)ufunc_get_name, + NULL, NULL, NULL}, + {"identity", + (getter)ufunc_get_identity, + NULL, NULL, NULL}, + {"signature", + (getter)ufunc_get_signature, + NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL}, /* Sentinel */ +}; + + +/****************************************************************************** + *** UFUNC TYPE OBJECT *** + *****************************************************************************/ + +NPY_NO_EXPORT PyTypeObject PyUFunc_Type = { +#if defined(NPY_PY3K) + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "numpy.ufunc", /* tp_name */ + sizeof(PyUFuncObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)ufunc_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +#if defined(NPY_PY3K) + 0, /* tp_reserved */ +#else + 0, /* tp_compare */ +#endif + (reprfunc)ufunc_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)ufunc_generic_call, /* tp_call */ + (reprfunc)ufunc_repr, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ufunc_methods, /* tp_methods */ + 0, /* tp_members */ + ufunc_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +}; + +/* End of code for ufunc objects */ diff --git a/numpy/core/src/umath/ufunc_object.h b/numpy/core/src/umath/ufunc_object.h new file mode 100644 index 0000000..d6fd383 --- /dev/null +++ b/numpy/core/src/umath/ufunc_object.h @@ -0,0 +1,22 @@ +#ifndef _NPY_UMATH_UFUNC_OBJECT_H_ +#define _NPY_UMATH_UFUNC_OBJECT_H_ + +NPY_NO_EXPORT PyObject * +ufunc_geterr(PyObject *NPY_UNUSED(dummy), PyObject *args); + +NPY_NO_EXPORT PyObject * +ufunc_seterr(PyObject *NPY_UNUSED(dummy), PyObject *args); + +NPY_NO_EXPORT const char* +ufunc_get_name_cstr(PyUFuncObject *ufunc); + +/* interned strings (on umath import) */ +NPY_VISIBILITY_HIDDEN extern PyObject * npy_um_str_out; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_um_str_subok; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_um_str_array_prepare; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_um_str_array_wrap; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_um_str_array_finalize; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_um_str_ufunc; +NPY_VISIBILITY_HIDDEN extern PyObject * npy_um_str_pyvals_name; + +#endif diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c new file mode 100644 index 0000000..1766ba5 --- /dev/null +++ b/numpy/core/src/umath/ufunc_type_resolution.c @@ -0,0 +1,2241 @@ +/* + * This file implements type resolution for NumPy element-wise ufuncs. + * This mechanism is still backwards-compatible with the pre-existing + * legacy mechanism, so performs much slower than is necessary. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" + +#include "npy_config.h" +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API +#define NO_IMPORT_ARRAY + +#include "npy_pycompat.h" + +#include "numpy/ufuncobject.h" +#include "ufunc_type_resolution.h" +#include "ufunc_object.h" +#include "common.h" + +static const char * +npy_casting_to_string(NPY_CASTING casting) +{ + switch (casting) { + case NPY_NO_CASTING: + return "'no'"; + case NPY_EQUIV_CASTING: + return "'equiv'"; + case NPY_SAFE_CASTING: + return "'safe'"; + case NPY_SAME_KIND_CASTING: + return "'same_kind'"; + case NPY_UNSAFE_CASTING: + return "'unsafe'"; + default: + return ""; + } +} +/*UFUNC_API + * + * Validates that the input operands can be cast to + * the input types, and the output types can be cast to + * the output operands where provided. + * + * Returns 0 on success, -1 (with exception raised) on validation failure. + */ +NPY_NO_EXPORT int +PyUFunc_ValidateCasting(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyArray_Descr **dtypes) +{ + int i, nin = ufunc->nin, nop = nin + ufunc->nout; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + for (i = 0; i < nop; ++i) { + if (i < nin) { + if (!PyArray_CanCastArrayTo(operands[i], dtypes[i], casting)) { + PyObject *errmsg; + errmsg = PyUString_FromFormat("Cannot cast ufunc %s " + "input from ", ufunc_name); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[i]))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)dtypes[i])); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" with casting rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } + } else if (operands[i] != NULL) { + if (!PyArray_CanCastTypeTo(dtypes[i], + PyArray_DESCR(operands[i]), casting)) { + PyObject *errmsg; + errmsg = PyUString_FromFormat("Cannot cast ufunc %s " + "output from ", ufunc_name); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)dtypes[i])); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[i]))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" with casting rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } + } + } + + return 0; +} + +/* + * Returns a new reference to type if it is already NBO, otherwise + * returns a copy converted to NBO. + */ +static PyArray_Descr * +ensure_dtype_nbo(PyArray_Descr *type) +{ + if (PyArray_ISNBO(type->byteorder)) { + Py_INCREF(type); + return type; + } + else { + return PyArray_DescrNewByteorder(type, NPY_NATIVE); + } +} + +/*UFUNC_API + * + * This function applies the default type resolution rules + * for the provided ufunc. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyUFunc_DefaultTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int i, nop = ufunc->nin + ufunc->nout; + int retval = 0, any_object = 0; + NPY_CASTING input_casting; + + for (i = 0; i < nop; ++i) { + if (operands[i] != NULL && + PyTypeNum_ISOBJECT(PyArray_DESCR(operands[i])->type_num)) { + any_object = 1; + break; + } + } + + /* + * Decide the casting rules for inputs and outputs. We want + * NPY_SAFE_CASTING or stricter, so that the loop selection code + * doesn't choose an integer loop for float inputs, or a float32 + * loop for float64 inputs. + */ + input_casting = (casting > NPY_SAFE_CASTING) ? NPY_SAFE_CASTING : casting; + + if (type_tup == NULL) { + /* Find the best ufunc inner loop, and fill in the dtypes */ + retval = linear_search_type_resolver(ufunc, operands, + input_casting, casting, any_object, + out_dtypes); + } else { + /* Find the specified ufunc inner loop, and fill in the dtypes */ + retval = type_tuple_type_resolver(ufunc, type_tup, + operands, casting, any_object, out_dtypes); + } + + return retval; +} + +/* + * This function applies special type resolution rules for the case + * where all the functions have the pattern XX->bool, using + * PyArray_ResultType instead of a linear search to get the best + * loop. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyUFunc_SimpleBinaryComparisonTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int i, type_num1, type_num2; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + if (ufunc->nin != 2 || ufunc->nout != 1) { + PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured " + "to use binary comparison type resolution but has " + "the wrong number of inputs or outputs", + ufunc_name); + return -1; + } + + /* + * Use the default type resolution if there's a custom data type + * or object arrays. + */ + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + if (type_num1 >= NPY_NTYPES || type_num2 >= NPY_NTYPES || + type_num1 == NPY_OBJECT || type_num2 == NPY_OBJECT) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); + } + + if (type_tup == NULL) { + /* Input types are the result type */ + out_dtypes[0] = PyArray_ResultType(2, operands, 0, NULL); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + } + else { + PyObject *item; + PyArray_Descr *dtype = NULL; + + /* + * If the type tuple isn't a single-element tuple, let the + * default type resolution handle this one. + */ + if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, + operands, type_tup, out_dtypes); + } + + item = PyTuple_GET_ITEM(type_tup, 0); + + if (item == Py_None) { + PyErr_SetString(PyExc_ValueError, + "require data type in the type tuple"); + return -1; + } + else if (!PyArray_DescrConverter(item, &dtype)) { + return -1; + } + + out_dtypes[0] = ensure_dtype_nbo(dtype); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + } + + /* Output type is always boolean */ + out_dtypes[2] = PyArray_DescrFromType(NPY_BOOL); + if (out_dtypes[2] == NULL) { + for (i = 0; i < 2; ++i) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; + } + + /* Check against the casting rules */ + if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) { + for (i = 0; i < 3; ++i) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; + } + + return 0; +} + +/* + * This function applies special type resolution rules for the case + * where all the functions have the pattern X->X, copying + * the input descr directly so that metadata is maintained. + * + * Note that a simpler linear search through the functions loop + * is still done, but switching to a simple array lookup for + * built-in types would be better at some point. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyUFunc_SimpleUnaryOperationTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int i, type_num1; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + if (ufunc->nin != 1 || ufunc->nout != 1) { + PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured " + "to use unary operation type resolution but has " + "the wrong number of inputs or outputs", + ufunc_name); + return -1; + } + + /* + * Use the default type resolution if there's a custom data type + * or object arrays. + */ + type_num1 = PyArray_DESCR(operands[0])->type_num; + if (type_num1 >= NPY_NTYPES || type_num1 == NPY_OBJECT) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); + } + + if (type_tup == NULL) { + /* Input types are the result type */ + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + } + else { + PyObject *item; + PyArray_Descr *dtype = NULL; + + /* + * If the type tuple isn't a single-element tuple, let the + * default type resolution handle this one. + */ + if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, + operands, type_tup, out_dtypes); + } + + item = PyTuple_GET_ITEM(type_tup, 0); + + if (item == Py_None) { + PyErr_SetString(PyExc_ValueError, + "require data type in the type tuple"); + return -1; + } + else if (!PyArray_DescrConverter(item, &dtype)) { + return -1; + } + + out_dtypes[0] = ensure_dtype_nbo(dtype); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + } + + /* Check against the casting rules */ + if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) { + for (i = 0; i < 2; ++i) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; + } + + return 0; +} + + +NPY_NO_EXPORT int +PyUFunc_NegativeTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int ret; + ret = PyUFunc_SimpleUnaryOperationTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); + if (ret < 0) { + return ret; + } + + /* The type resolver would have upcast already */ + if (out_dtypes[0]->type_num == NPY_BOOL) { + PyErr_Format(PyExc_TypeError, + "The numpy boolean negative, the `-` operator, is not supported, " + "use the `~` operator or the logical_not function instead."); + return -1; + } + + return ret; +} + + +/* + * The ones_like function shouldn't really be a ufunc, but while it + * still is, this provides type resolution that always forces UNSAFE + * casting. + */ +NPY_NO_EXPORT int +PyUFunc_OnesLikeTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING NPY_UNUSED(casting), + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + return PyUFunc_SimpleUnaryOperationTypeResolver(ufunc, + NPY_UNSAFE_CASTING, + operands, type_tup, out_dtypes); +} + + +/* + * This function applies special type resolution rules for the case + * where all the functions have the pattern XX->X, using + * PyArray_ResultType instead of a linear search to get the best + * loop. + * + * Note that a simpler linear search through the functions loop + * is still done, but switching to a simple array lookup for + * built-in types would be better at some point. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyUFunc_SimpleBinaryOperationTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int i, type_num1, type_num2; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + if (ufunc->nin != 2 || ufunc->nout != 1) { + PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured " + "to use binary operation type resolution but has " + "the wrong number of inputs or outputs", + ufunc_name); + return -1; + } + + /* + * Use the default type resolution if there's a custom data type + * or object arrays. + */ + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + if (type_num1 >= NPY_NTYPES || type_num2 >= NPY_NTYPES || + type_num1 == NPY_OBJECT || type_num2 == NPY_OBJECT) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); + } + + if (type_tup == NULL) { + /* Input types are the result type */ + out_dtypes[0] = PyArray_ResultType(2, operands, 0, NULL); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + } + else { + PyObject *item; + PyArray_Descr *dtype = NULL; + + /* + * If the type tuple isn't a single-element tuple, let the + * default type resolution handle this one. + */ + if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, + operands, type_tup, out_dtypes); + } + + item = PyTuple_GET_ITEM(type_tup, 0); + + if (item == Py_None) { + PyErr_SetString(PyExc_ValueError, + "require data type in the type tuple"); + return -1; + } + else if (!PyArray_DescrConverter(item, &dtype)) { + return -1; + } + + out_dtypes[0] = ensure_dtype_nbo(dtype); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + } + + /* Check against the casting rules */ + if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) { + for (i = 0; i < 3; ++i) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; + } + + return 0; +} + +/* + * This function applies special type resolution rules for the absolute + * ufunc. This ufunc converts complex -> float, so isn't covered + * by the simple unary type resolution. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyUFunc_AbsoluteTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + /* Use the default for complex types, to find the loop producing float */ + if (PyTypeNum_ISCOMPLEX(PyArray_DESCR(operands[0])->type_num)) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); + } + else { + return PyUFunc_SimpleUnaryOperationTypeResolver(ufunc, casting, + operands, type_tup, out_dtypes); + } +} + +/* + * This function applies special type resolution rules for the isnat + * ufunc. This ufunc converts datetime/timedelta -> bool, and is not covered + * by the simple unary type resolution. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyUFunc_IsNaTTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + if (!PyTypeNum_ISDATETIME(PyArray_DESCR(operands[0])->type_num)) { + PyErr_SetString(PyExc_TypeError, + "ufunc 'isnat' is only defined for datetime and timedelta."); + return -1; + } + + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + out_dtypes[1] = PyArray_DescrFromType(NPY_BOOL); + + return 0; +} + +/* + * Creates a new NPY_TIMEDELTA dtype, copying the datetime metadata + * from the given dtype. + * + * NOTE: This function is copied from datetime.c in multiarray, + * because umath and multiarray are not linked together. + */ +static PyArray_Descr * +timedelta_dtype_with_copied_meta(PyArray_Descr *dtype) +{ + PyArray_Descr *ret; + PyArray_DatetimeMetaData *dst, *src; + PyArray_DatetimeDTypeMetaData *dst_dtmd, *src_dtmd; + + ret = PyArray_DescrNewFromType(NPY_TIMEDELTA); + if (ret == NULL) { + return NULL; + } + + src_dtmd = ((PyArray_DatetimeDTypeMetaData *)dtype->c_metadata); + dst_dtmd = ((PyArray_DatetimeDTypeMetaData *)ret->c_metadata); + src = &(src_dtmd->meta); + dst = &(dst_dtmd->meta); + + *dst = *src; + + return ret; +} + +/* + * This function applies the type resolution rules for addition. + * In particular, there are a number of special cases with datetime: + * m8[] + m8[] => m8[gcd(,)] + m8[gcd(,)] + * m8[] + int => m8[] + m8[] + * int + m8[] => m8[] + m8[] + * M8[] + int => M8[] + m8[] + * int + M8[] => m8[] + M8[] + * M8[] + m8[] => M8[gcd(,)] + m8[gcd(,)] + * m8[] + M8[] => m8[gcd(,)] + M8[gcd(,)] + * TODO: Non-linear time unit cases require highly special-cased loops + * M8[] + m8[Y|M|B] + * m8[Y|M|B] + M8[] + */ +NPY_NO_EXPORT int +PyUFunc_AdditionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int type_num1, type_num2; + int i; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + + /* Use the default when datetime and timedelta are not involved */ + if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) { + return PyUFunc_SimpleBinaryOperationTypeResolver(ufunc, casting, + operands, type_tup, out_dtypes); + } + + if (type_num1 == NPY_TIMEDELTA) { + /* m8[] + m8[] => m8[gcd(,)] + m8[gcd(,)] */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]), + PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + } + /* m8[] + M8[] => m8[gcd(,)] + M8[gcd(,)] */ + else if (type_num2 == NPY_DATETIME) { + out_dtypes[1] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]), + PyArray_DESCR(operands[1])); + if (out_dtypes[1] == NULL) { + return -1; + } + /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */ + out_dtypes[0] = timedelta_dtype_with_copied_meta(out_dtypes[1]); + if (out_dtypes[0] == NULL) { + Py_DECREF(out_dtypes[1]); + out_dtypes[1] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[1]; + Py_INCREF(out_dtypes[2]); + } + /* m8[] + int => m8[] + m8[] */ + else if (PyTypeNum_ISINTEGER(type_num2) || + PyTypeNum_ISBOOL(type_num2)) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num2 = NPY_TIMEDELTA; + } + else { + goto type_reso_error; + } + } + else if (type_num1 == NPY_DATETIME) { + /* M8[] + m8[] => M8[gcd(,)] + m8[gcd(,)] */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]), + PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */ + out_dtypes[1] = timedelta_dtype_with_copied_meta(out_dtypes[0]); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + } + /* M8[] + int => M8[] + m8[] */ + else if (PyTypeNum_ISINTEGER(type_num2) || + PyTypeNum_ISBOOL(type_num2)) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + /* Make a new NPY_TIMEDELTA, and copy type1's metadata */ + out_dtypes[1] = timedelta_dtype_with_copied_meta( + PyArray_DESCR(operands[0])); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num2 = NPY_TIMEDELTA; + } + else { + goto type_reso_error; + } + } + else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) { + /* int + m8[] => m8[] + m8[] */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num1 = NPY_TIMEDELTA; + } + else if (type_num2 == NPY_DATETIME) { + /* Make a new NPY_TIMEDELTA, and copy type2's metadata */ + out_dtypes[0] = timedelta_dtype_with_copied_meta( + PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1])); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[1]; + Py_INCREF(out_dtypes[2]); + + type_num1 = NPY_TIMEDELTA; + } + else { + goto type_reso_error; + } + } + else { + goto type_reso_error; + } + + /* Check against the casting rules */ + if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) { + for (i = 0; i < 3; ++i) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; + } + + return 0; + +type_reso_error: { + PyObject *errmsg; + errmsg = PyUString_FromFormat("ufunc %s cannot use operands " + "with types ", ufunc_name); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[0]))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" and ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[1]))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } +} + +/* + * This function applies the type resolution rules for subtraction. + * In particular, there are a number of special cases with datetime: + * m8[] - m8[] => m8[gcd(,)] - m8[gcd(,)] + * m8[] - int => m8[] - m8[] + * int - m8[] => m8[] - m8[] + * M8[] - int => M8[] - m8[] + * M8[] - m8[] => M8[gcd(,)] - m8[gcd(,)] + * TODO: Non-linear time unit cases require highly special-cased loops + * M8[] - m8[Y|M|B] + */ +NPY_NO_EXPORT int +PyUFunc_SubtractionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int type_num1, type_num2; + int i; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + + /* Use the default when datetime and timedelta are not involved */ + if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) { + int ret; + ret = PyUFunc_SimpleBinaryOperationTypeResolver(ufunc, casting, + operands, type_tup, out_dtypes); + if (ret < 0) { + return ret; + } + + /* The type resolver would have upcast already */ + if (out_dtypes[0]->type_num == NPY_BOOL) { + PyErr_Format(PyExc_TypeError, + "numpy boolean subtract, the `-` operator, is deprecated, " + "use the bitwise_xor, the `^` operator, or the logical_xor " + "function instead."); + return -1; + } + return ret; + } + + if (type_num1 == NPY_TIMEDELTA) { + /* m8[] - m8[] => m8[gcd(,)] - m8[gcd(,)] */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]), + PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + } + /* m8[] - int => m8[] - m8[] */ + else if (PyTypeNum_ISINTEGER(type_num2) || + PyTypeNum_ISBOOL(type_num2)) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num2 = NPY_TIMEDELTA; + } + else { + goto type_reso_error; + } + } + else if (type_num1 == NPY_DATETIME) { + /* M8[] - m8[] => M8[gcd(,)] - m8[gcd(,)] */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]), + PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */ + out_dtypes[1] = timedelta_dtype_with_copied_meta(out_dtypes[0]); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + } + /* M8[] - int => M8[] - m8[] */ + else if (PyTypeNum_ISINTEGER(type_num2) || + PyTypeNum_ISBOOL(type_num2)) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + /* Make a new NPY_TIMEDELTA, and copy type1's metadata */ + out_dtypes[1] = timedelta_dtype_with_copied_meta( + PyArray_DESCR(operands[0])); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num2 = NPY_TIMEDELTA; + } + /* M8[] - M8[] => M8[gcd(,)] - M8[gcd(,)] */ + else if (type_num2 == NPY_DATETIME) { + out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]), + PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + /* Make a new NPY_TIMEDELTA, and copy type1's metadata */ + out_dtypes[2] = timedelta_dtype_with_copied_meta(out_dtypes[0]); + if (out_dtypes[2] == NULL) { + Py_DECREF(out_dtypes[0]); + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + } + else { + goto type_reso_error; + } + } + else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) { + /* int - m8[] => m8[] - m8[] */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num1 = NPY_TIMEDELTA; + } + else { + goto type_reso_error; + } + } + else { + goto type_reso_error; + } + + /* Check against the casting rules */ + if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) { + for (i = 0; i < 3; ++i) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; + } + + return 0; + +type_reso_error: { + PyObject *errmsg; + errmsg = PyUString_FromFormat("ufunc %s cannot use operands " + "with types ", ufunc_name); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[0]))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" and ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[1]))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } +} + +/* + * This function applies the type resolution rules for multiplication. + * In particular, there are a number of special cases with datetime: + * int## * m8[] => int64 * m8[] + * m8[] * int## => m8[] * int64 + * float## * m8[] => float64 * m8[] + * m8[] * float## => m8[] * float64 + */ +NPY_NO_EXPORT int +PyUFunc_MultiplicationTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int type_num1, type_num2; + int i; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + + /* Use the default when datetime and timedelta are not involved */ + if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) { + return PyUFunc_SimpleBinaryOperationTypeResolver(ufunc, casting, + operands, type_tup, out_dtypes); + } + + if (type_num1 == NPY_TIMEDELTA) { + /* m8[] * int## => m8[] * int64 */ + if (PyTypeNum_ISINTEGER(type_num2) || PyTypeNum_ISBOOL(type_num2)) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = PyArray_DescrNewFromType(NPY_LONGLONG); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num2 = NPY_LONGLONG; + } + /* m8[] * float## => m8[] * float64 */ + else if (PyTypeNum_ISFLOAT(type_num2)) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = PyArray_DescrNewFromType(NPY_DOUBLE); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num2 = NPY_DOUBLE; + } + else { + goto type_reso_error; + } + } + else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) { + /* int## * m8[] => int64 * m8[] */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = PyArray_DescrNewFromType(NPY_LONGLONG); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1])); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[1]; + Py_INCREF(out_dtypes[2]); + + type_num1 = NPY_LONGLONG; + } + else { + goto type_reso_error; + } + } + else if (PyTypeNum_ISFLOAT(type_num1)) { + /* float## * m8[] => float64 * m8[] */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = PyArray_DescrNewFromType(NPY_DOUBLE); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1])); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[1]; + Py_INCREF(out_dtypes[2]); + + type_num1 = NPY_DOUBLE; + } + else { + goto type_reso_error; + } + } + else { + goto type_reso_error; + } + + /* Check against the casting rules */ + if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) { + for (i = 0; i < 3; ++i) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; + } + + return 0; + +type_reso_error: { + PyObject *errmsg; + errmsg = PyUString_FromFormat("ufunc %s cannot use operands " + "with types ", ufunc_name); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[0]))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" and ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[1]))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } +} + + +/* + * This function applies the type resolution rules for division. + * In particular, there are a number of special cases with datetime: + * m8[] / m8[] to m8[gcd(,)] / m8[gcd(,)] -> float64 + * m8[] / int## to m8[] / int64 -> m8[] + * m8[] / float## to m8[] / float64 -> m8[] + */ +NPY_NO_EXPORT int +PyUFunc_DivisionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int type_num1, type_num2; + int i; + const char *ufunc_name = ufunc_get_name_cstr(ufunc); + + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + + /* Use the default when datetime and timedelta are not involved */ + if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); + } + + if (type_num1 == NPY_TIMEDELTA) { + /* + * m8[] / m8[] to + * m8[gcd(,)] / m8[gcd(,)] -> float64 + */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]), + PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = PyArray_DescrFromType(NPY_DOUBLE); + if (out_dtypes[2] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + Py_DECREF(out_dtypes[1]); + out_dtypes[1] = NULL; + return -1; + } + } + /* m8[] / int## => m8[] / int64 */ + else if (PyTypeNum_ISINTEGER(type_num2)) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = PyArray_DescrFromType(NPY_LONGLONG); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num2 = NPY_LONGLONG; + } + /* m8[] / float## => m8[] / float64 */ + else if (PyTypeNum_ISFLOAT(type_num2)) { + out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = PyArray_DescrNewFromType(NPY_DOUBLE); + if (out_dtypes[1] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + return -1; + } + out_dtypes[2] = out_dtypes[0]; + Py_INCREF(out_dtypes[2]); + + type_num2 = NPY_DOUBLE; + } + else { + goto type_reso_error; + } + } + else { + goto type_reso_error; + } + + /* Check against the casting rules */ + if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) { + for (i = 0; i < 3; ++i) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; + } + + return 0; + +type_reso_error: { + PyObject *errmsg; + errmsg = PyUString_FromFormat("ufunc %s cannot use operands " + "with types ", ufunc_name); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[0]))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" and ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(operands[1]))); + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + return -1; + } +} + + +/* + * True division should return float64 results when both inputs are integer + * types. The PyUFunc_DefaultTypeResolver promotes 8 bit integers to float16 + * and 16 bit integers to float32, so that is overridden here by specifying a + * 'dd->d' signature. Returns -1 on failure. +*/ +NPY_NO_EXPORT int +PyUFunc_TrueDivisionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int type_num1, type_num2; + static PyObject *default_type_tup = NULL; + + /* Set default type for integer inputs to NPY_DOUBLE */ + if (default_type_tup == NULL) { + PyArray_Descr *tmp = PyArray_DescrFromType(NPY_DOUBLE); + + if (tmp == NULL) { + return -1; + } + default_type_tup = PyTuple_Pack(3, tmp, tmp, tmp); + if (default_type_tup == NULL) { + Py_DECREF(tmp); + return -1; + } + Py_DECREF(tmp); + } + + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + + if (type_tup == NULL && + (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) && + (PyTypeNum_ISINTEGER(type_num2) || PyTypeNum_ISBOOL(type_num2))) { + return PyUFunc_DefaultTypeResolver(ufunc, casting, operands, + default_type_tup, out_dtypes); + } + return PyUFunc_DivisionTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); +} +/* + * Function to check and report floor division warning when python2.x is + * invoked with -3 switch + * See PEP238 and #7949 for numpy + * This function will not be hit for py3 or when __future__ imports division. + * See generate_umath.py for reason +*/ +NPY_NO_EXPORT int +PyUFunc_MixedDivisionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + /* Depreciation checks needed only on python 2 */ +#if !defined(NPY_PY3K) + int type_num1, type_num2; + + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + + /* If both types are integer, warn the user, same as python does */ + if (Py_DivisionWarningFlag && + (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) && + (PyTypeNum_ISINTEGER(type_num2) || PyTypeNum_ISBOOL(type_num2))) { + PyErr_Warn(PyExc_DeprecationWarning, "numpy: classic int division"); + } +#endif + return PyUFunc_DivisionTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); +} + + +static int +find_userloop(PyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyUFuncGenericFunction *out_innerloop, + void **out_innerloopdata) +{ + npy_intp i, nin = ufunc->nin, j, nargs = nin + ufunc->nout; + PyUFunc_Loop1d *funcdata; + + /* Use this to try to avoid repeating the same userdef loop search */ + int last_userdef = -1; + + for (i = 0; i < nargs; ++i) { + int type_num; + + /* no more ufunc arguments to check */ + if (dtypes[i] == NULL) { + break; + } + + type_num = dtypes[i]->type_num; + if (type_num != last_userdef && + (PyTypeNum_ISUSERDEF(type_num) || type_num == NPY_VOID)) { + PyObject *key, *obj; + + last_userdef = type_num; + + key = PyInt_FromLong(type_num); + if (key == NULL) { + return -1; + } + obj = PyDict_GetItem(ufunc->userloops, key); + Py_DECREF(key); + if (obj == NULL) { + continue; + } + for (funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj); + funcdata != NULL; + funcdata = funcdata->next) { + int *types = funcdata->arg_types; + + for (j = 0; j < nargs; ++j) { + if (types[j] != dtypes[j]->type_num) { + break; + } + } + /* It matched */ + if (j == nargs) { + *out_innerloop = funcdata->func; + *out_innerloopdata = funcdata->data; + return 1; + } + } + } + } + + /* Didn't find a match */ + return 0; +} + +NPY_NO_EXPORT int +PyUFunc_DefaultLegacyInnerLoopSelector(PyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyUFuncGenericFunction *out_innerloop, + void **out_innerloopdata, + int *out_needs_api) +{ + int nargs = ufunc->nargs; + char *types; + const char *ufunc_name; + PyObject *errmsg; + int i, j; + + ufunc_name = ufunc_get_name_cstr(ufunc); + + /* + * If there are user-loops search them first. + * TODO: There needs to be a loop selection acceleration structure, + * like a hash table. + */ + if (ufunc->userloops) { + switch (find_userloop(ufunc, dtypes, + out_innerloop, out_innerloopdata)) { + /* Error */ + case -1: + return -1; + /* Found a loop */ + case 1: + return 0; + } + } + + types = ufunc->types; + for (i = 0; i < ufunc->ntypes; ++i) { + /* Copy the types into an int array for matching */ + for (j = 0; j < nargs; ++j) { + if (types[j] != dtypes[j]->type_num) { + break; + } + } + if (j == nargs) { + *out_innerloop = ufunc->functions[i]; + *out_innerloopdata = ufunc->data[i]; + return 0; + } + + types += nargs; + } + + errmsg = PyUString_FromFormat("ufunc '%s' did not contain a loop " + "with signature matching types ", ufunc_name); + for (i = 0; i < nargs; ++i) { + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)dtypes[i])); + if (i < nargs - 1) { + PyUString_ConcatAndDel(&errmsg, PyUString_FromString(" ")); + } + } + PyErr_SetObject(PyExc_TypeError, errmsg); + Py_DECREF(errmsg); + + return -1; +} + +typedef struct { + NpyAuxData base; + PyUFuncGenericFunction unmasked_innerloop; + void *unmasked_innerloopdata; + int nargs; +} _ufunc_masker_data; + +static NpyAuxData * +ufunc_masker_data_clone(NpyAuxData *data) +{ + _ufunc_masker_data *n; + + /* Allocate a new one */ + n = (_ufunc_masker_data *)PyArray_malloc(sizeof(_ufunc_masker_data)); + if (n == NULL) { + return NULL; + } + + /* Copy the data (unmasked data doesn't have object semantics) */ + memcpy(n, data, sizeof(_ufunc_masker_data)); + + return (NpyAuxData *)n; +} + +/* + * This function wraps a regular unmasked ufunc inner loop as a + * masked ufunc inner loop, only calling the function for + * elements where the mask is True. + */ +static void +unmasked_ufunc_loop_as_masked( + char **dataptrs, npy_intp *strides, + char *mask, npy_intp mask_stride, + npy_intp loopsize, + NpyAuxData *innerloopdata) +{ + _ufunc_masker_data *data; + int iargs, nargs; + PyUFuncGenericFunction unmasked_innerloop; + void *unmasked_innerloopdata; + npy_intp subloopsize; + + /* Put the aux data into local variables */ + data = (_ufunc_masker_data *)innerloopdata; + unmasked_innerloop = data->unmasked_innerloop; + unmasked_innerloopdata = data->unmasked_innerloopdata; + nargs = data->nargs; + + /* Process the data as runs of unmasked values */ + do { + /* Skip masked values */ + mask = npy_memchr(mask, 0, mask_stride, loopsize, &subloopsize, 1); + for (iargs = 0; iargs < nargs; ++iargs) { + dataptrs[iargs] += subloopsize * strides[iargs]; + } + loopsize -= subloopsize; + /* + * Process unmasked values (assumes unmasked loop doesn't + * mess with the 'args' pointer values) + */ + mask = npy_memchr(mask, 0, mask_stride, loopsize, &subloopsize, 0); + unmasked_innerloop(dataptrs, &subloopsize, strides, + unmasked_innerloopdata); + for (iargs = 0; iargs < nargs; ++iargs) { + dataptrs[iargs] += subloopsize * strides[iargs]; + } + loopsize -= subloopsize; + } while (loopsize > 0); +} + + +/* + * This function wraps a legacy inner loop so it becomes masked. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyUFunc_DefaultMaskedInnerLoopSelector(PyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyArray_Descr *mask_dtype, + npy_intp *NPY_UNUSED(fixed_strides), + npy_intp NPY_UNUSED(fixed_mask_stride), + PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop, + NpyAuxData **out_innerloopdata, + int *out_needs_api) +{ + int retcode; + _ufunc_masker_data *data; + + if (ufunc->legacy_inner_loop_selector == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "the ufunc default masked inner loop selector doesn't " + "yet support wrapping the new inner loop selector, it " + "still only wraps the legacy inner loop selector"); + return -1; + } + + if (mask_dtype->type_num != NPY_BOOL) { + PyErr_SetString(PyExc_ValueError, + "only boolean masks are supported in ufunc inner loops " + "presently"); + return -1; + } + + /* Create a new NpyAuxData object for the masker data */ + data = (_ufunc_masker_data *)PyArray_malloc(sizeof(_ufunc_masker_data)); + if (data == NULL) { + PyErr_NoMemory(); + return -1; + } + memset(data, 0, sizeof(_ufunc_masker_data)); + data->base.free = (NpyAuxData_FreeFunc *)&PyArray_free; + data->base.clone = &ufunc_masker_data_clone; + data->nargs = ufunc->nin + ufunc->nout; + + /* Get the unmasked ufunc inner loop */ + retcode = ufunc->legacy_inner_loop_selector(ufunc, dtypes, + &data->unmasked_innerloop, &data->unmasked_innerloopdata, + out_needs_api); + if (retcode < 0) { + PyArray_free(data); + return retcode; + } + + /* Return the loop function + aux data */ + *out_innerloop = &unmasked_ufunc_loop_as_masked; + *out_innerloopdata = (NpyAuxData *)data; + return 0; +} + +static int +ufunc_loop_matches(PyUFuncObject *self, + PyArrayObject **op, + NPY_CASTING input_casting, + NPY_CASTING output_casting, + int any_object, + int use_min_scalar, + int *types, PyArray_Descr **dtypes, + int *out_no_castable_output, + char *out_err_src_typecode, + char *out_err_dst_typecode) +{ + npy_intp i, nin = self->nin, nop = nin + self->nout; + + /* + * First check if all the inputs can be safely cast + * to the types for this function + */ + for (i = 0; i < nin; ++i) { + PyArray_Descr *tmp; + + /* + * If no inputs are objects and there are more than one + * loop, don't allow conversion to object. The rationale + * behind this is mostly performance. Except for custom + * ufuncs built with just one object-parametered inner loop, + * only the types that are supported are implemented. Trying + * the object version of logical_or on float arguments doesn't + * seem right. + */ + if (types[i] == NPY_OBJECT && !any_object && self->ntypes > 1) { + return 0; + } + + /* + * If type num is NPY_VOID and struct dtypes have been passed in, + * use struct dtype object. Otherwise create new dtype object + * from type num. + */ + if (types[i] == NPY_VOID && dtypes != NULL) { + tmp = dtypes[i]; + Py_INCREF(tmp); + } + else { + tmp = PyArray_DescrFromType(types[i]); + } + if (tmp == NULL) { + return -1; + } + +#if NPY_UF_DBG_TRACING + printf("Checking type for op %d, type %d: ", (int)i, (int)types[i]); + PyObject_Print((PyObject *)tmp, stdout, 0); + printf(", operand type: "); + PyObject_Print((PyObject *)PyArray_DESCR(op[i]), stdout, 0); + printf("\n"); +#endif + /* + * If all the inputs are scalars, use the regular + * promotion rules, not the special value-checking ones. + */ + if (!use_min_scalar) { + if (!PyArray_CanCastTypeTo(PyArray_DESCR(op[i]), tmp, + input_casting)) { + Py_DECREF(tmp); + return 0; + } + } + else { + if (!PyArray_CanCastArrayTo(op[i], tmp, input_casting)) { + Py_DECREF(tmp); + return 0; + } + } + Py_DECREF(tmp); + } + + /* + * If all the inputs were ok, then check casting back to the + * outputs. + */ + for (i = nin; i < nop; ++i) { + if (op[i] != NULL) { + PyArray_Descr *tmp = PyArray_DescrFromType(types[i]); + if (tmp == NULL) { + return -1; + } + if (!PyArray_CanCastTypeTo(tmp, PyArray_DESCR(op[i]), + output_casting)) { + if (!(*out_no_castable_output)) { + *out_no_castable_output = 1; + *out_err_src_typecode = tmp->type; + *out_err_dst_typecode = PyArray_DESCR(op[i])->type; + } + Py_DECREF(tmp); + return 0; + } + Py_DECREF(tmp); + } + } + + return 1; +} + +static int +set_ufunc_loop_data_types(PyUFuncObject *self, PyArrayObject **op, + PyArray_Descr **out_dtypes, + int *type_nums, PyArray_Descr **dtypes) +{ + int i, nin = self->nin, nop = nin + self->nout; + + /* + * Fill the dtypes array. + * For outputs, + * also search the inputs for a matching type_num to copy + * instead of creating a new one, similarly to preserve metadata. + **/ + for (i = 0; i < nop; ++i) { + if (dtypes != NULL) { + out_dtypes[i] = dtypes[i]; + Py_XINCREF(out_dtypes[i]); + /* + * Copy the dtype from 'op' if the type_num matches, + * to preserve metadata. + */ + } + else if (op[i] != NULL && + PyArray_DESCR(op[i])->type_num == type_nums[i]) { + out_dtypes[i] = ensure_dtype_nbo(PyArray_DESCR(op[i])); + } + /* + * For outputs, copy the dtype from op[0] if the type_num + * matches, similarly to preserve metdata. + */ + else if (i >= nin && op[0] != NULL && + PyArray_DESCR(op[0])->type_num == type_nums[i]) { + out_dtypes[i] = ensure_dtype_nbo(PyArray_DESCR(op[0])); + } + /* Otherwise create a plain descr from the type number */ + else { + out_dtypes[i] = PyArray_DescrFromType(type_nums[i]); + } + + if (out_dtypes[i] == NULL) { + goto fail; + } + } + + return 0; + +fail: + while (--i >= 0) { + Py_DECREF(out_dtypes[i]); + out_dtypes[i] = NULL; + } + return -1; +} + +/* + * Does a search through the arguments and the loops + */ +static int +linear_search_userloop_type_resolver(PyUFuncObject *self, + PyArrayObject **op, + NPY_CASTING input_casting, + NPY_CASTING output_casting, + int any_object, + int use_min_scalar, + PyArray_Descr **out_dtype, + int *out_no_castable_output, + char *out_err_src_typecode, + char *out_err_dst_typecode) +{ + npy_intp i, nop = self->nin + self->nout; + PyUFunc_Loop1d *funcdata; + + /* Use this to try to avoid repeating the same userdef loop search */ + int last_userdef = -1; + + for (i = 0; i < nop; ++i) { + int type_num; + + /* no more ufunc arguments to check */ + if (op[i] == NULL) { + break; + } + + type_num = PyArray_DESCR(op[i])->type_num; + if (type_num != last_userdef && + (PyTypeNum_ISUSERDEF(type_num) || type_num == NPY_VOID)) { + PyObject *key, *obj; + + last_userdef = type_num; + + key = PyInt_FromLong(type_num); + if (key == NULL) { + return -1; + } + obj = PyDict_GetItem(self->userloops, key); + Py_DECREF(key); + if (obj == NULL) { + continue; + } + for (funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj); + funcdata != NULL; + funcdata = funcdata->next) { + int *types = funcdata->arg_types; + switch (ufunc_loop_matches(self, op, + input_casting, output_casting, + any_object, use_min_scalar, + types, funcdata->arg_dtypes, + out_no_castable_output, out_err_src_typecode, + out_err_dst_typecode)) { + /* Error */ + case -1: + return -1; + /* Found a match */ + case 1: + set_ufunc_loop_data_types(self, op, out_dtype, types, funcdata->arg_dtypes); + return 1; + } + } + } + } + + /* Didn't find a match */ + return 0; +} + +/* + * Does a search through the arguments and the loops + */ +static int +type_tuple_userloop_type_resolver(PyUFuncObject *self, + int n_specified, + int *specified_types, + PyArrayObject **op, + NPY_CASTING casting, + int any_object, + int use_min_scalar, + PyArray_Descr **out_dtype) +{ + int i, j, nin = self->nin, nop = nin + self->nout; + PyUFunc_Loop1d *funcdata; + + /* Use this to try to avoid repeating the same userdef loop search */ + int last_userdef = -1; + + int no_castable_output = 0; + char err_src_typecode = '-', err_dst_typecode = '-'; + + for (i = 0; i < nin; ++i) { + int type_num = PyArray_DESCR(op[i])->type_num; + if (type_num != last_userdef && PyTypeNum_ISUSERDEF(type_num)) { + PyObject *key, *obj; + + last_userdef = type_num; + + key = PyInt_FromLong(type_num); + if (key == NULL) { + return -1; + } + obj = PyDict_GetItem(self->userloops, key); + Py_DECREF(key); + if (obj == NULL) { + continue; + } + + for (funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj); + funcdata != NULL; + funcdata = funcdata->next) { + int *types = funcdata->arg_types; + int matched = 1; + + if (n_specified == nop) { + for (j = 0; j < nop; ++j) { + if (types[j] != specified_types[j] && + specified_types[j] != NPY_NOTYPE) { + matched = 0; + break; + } + } + } else { + if (types[nin] != specified_types[0]) { + matched = 0; + } + } + if (!matched) { + continue; + } + + switch (ufunc_loop_matches(self, op, + casting, casting, + any_object, use_min_scalar, + types, NULL, + &no_castable_output, &err_src_typecode, + &err_dst_typecode)) { + /* It works */ + case 1: + set_ufunc_loop_data_types(self, op, + out_dtype, types, NULL); + return 1; + /* Didn't match */ + case 0: + PyErr_Format(PyExc_TypeError, + "found a user loop for ufunc '%s' " + "matching the type-tuple, " + "but the inputs and/or outputs could not be " + "cast according to the casting rule", + ufunc_get_name_cstr(self)); + return -1; + /* Error */ + case -1: + return -1; + } + } + } + } + + /* Didn't find a match */ + return 0; +} + +/* + * Provides an ordering for the dtype 'kind' character codes, to help + * determine when to use the min_scalar_type function. This groups + * 'kind' into boolean, integer, floating point, and everything else. + */ + +static int +dtype_kind_to_simplified_ordering(char kind) +{ + switch (kind) { + /* Boolean kind */ + case 'b': + return 0; + /* Unsigned int kind */ + case 'u': + /* Signed int kind */ + case 'i': + return 1; + /* Float kind */ + case 'f': + /* Complex kind */ + case 'c': + return 2; + /* Anything else */ + default: + return 3; + } +} + +static int +should_use_min_scalar(PyArrayObject **op, int nop) +{ + int i, use_min_scalar, kind; + int all_scalars = 1, max_scalar_kind = -1, max_array_kind = -1; + + /* + * Determine if there are any scalars, and if so, whether + * the maximum "kind" of the scalars surpasses the maximum + * "kind" of the arrays + */ + use_min_scalar = 0; + if (nop > 1) { + for(i = 0; i < nop; ++i) { + kind = dtype_kind_to_simplified_ordering( + PyArray_DESCR(op[i])->kind); + if (PyArray_NDIM(op[i]) == 0) { + if (kind > max_scalar_kind) { + max_scalar_kind = kind; + } + } + else { + all_scalars = 0; + if (kind > max_array_kind) { + max_array_kind = kind; + } + + } + } + + /* Indicate whether to use the min_scalar_type function */ + if (!all_scalars && max_array_kind >= max_scalar_kind) { + use_min_scalar = 1; + } + } + + return use_min_scalar; +} + +/* + * Does a linear search for the best inner loop of the ufunc. + * + * Note that if an error is returned, the caller must free the non-zero + * references in out_dtype. This function does not do its own clean-up. + */ +NPY_NO_EXPORT int +linear_search_type_resolver(PyUFuncObject *self, + PyArrayObject **op, + NPY_CASTING input_casting, + NPY_CASTING output_casting, + int any_object, + PyArray_Descr **out_dtype) +{ + npy_intp i, j, nin = self->nin, nop = nin + self->nout; + int types[NPY_MAXARGS]; + const char *ufunc_name; + int no_castable_output, use_min_scalar; + + /* For making a better error message on coercion error */ + char err_dst_typecode = '-', err_src_typecode = '-'; + + ufunc_name = ufunc_get_name_cstr(self); + + use_min_scalar = should_use_min_scalar(op, nin); + + /* If the ufunc has userloops, search for them. */ + if (self->userloops) { + switch (linear_search_userloop_type_resolver(self, op, + input_casting, output_casting, + any_object, use_min_scalar, out_dtype, + &no_castable_output, &err_src_typecode, + &err_dst_typecode)) { + /* Error */ + case -1: + return -1; + /* A loop was found */ + case 1: + return 0; + } + } + + /* + * Determine the UFunc loop. This could in general be *much* faster, + * and a better way to implement it might be for the ufunc to + * provide a function which gives back the result type and inner + * loop function. + * + * A default fast mechanism could be provided for functions which + * follow the most typical pattern, when all functions have signatures + * "xx...x -> x" for some built-in data type x, as follows. + * - Use PyArray_ResultType to get the output type + * - Look up the inner loop in a table based on the output type_num + * + * The method for finding the loop in the previous code did not + * appear consistent (as noted by some asymmetry in the generated + * coercion tables for np.add). + */ + no_castable_output = 0; + for (i = 0; i < self->ntypes; ++i) { + char *orig_types = self->types + i*self->nargs; + + /* Copy the types into an int array for matching */ + for (j = 0; j < nop; ++j) { + types[j] = orig_types[j]; + } + + switch (ufunc_loop_matches(self, op, + input_casting, output_casting, + any_object, use_min_scalar, + types, NULL, + &no_castable_output, &err_src_typecode, + &err_dst_typecode)) { + /* Error */ + case -1: + return -1; + /* Found a match */ + case 1: + set_ufunc_loop_data_types(self, op, out_dtype, types, NULL); + return 0; + } + } + + /* If no function was found, throw an error */ + if (no_castable_output) { + PyErr_Format(PyExc_TypeError, + "ufunc '%s' output (typecode '%c') could not be coerced to " + "provided output parameter (typecode '%c') according " + "to the casting rule '%s'", + ufunc_name, err_src_typecode, err_dst_typecode, + npy_casting_to_string(output_casting)); + } + else { + /* + * TODO: We should try again if the casting rule is same_kind + * or unsafe, and look for a function more liberally. + */ + PyErr_Format(PyExc_TypeError, + "ufunc '%s' not supported for the input types, and the " + "inputs could not be safely coerced to any supported " + "types according to the casting rule '%s'", + ufunc_name, + npy_casting_to_string(input_casting)); + } + + return -1; +} + +/* + * Does a linear search for the inner loop of the ufunc specified by type_tup. + * + * Note that if an error is returned, the caller must free the non-zero + * references in out_dtype. This function does not do its own clean-up. + */ +NPY_NO_EXPORT int +type_tuple_type_resolver(PyUFuncObject *self, + PyObject *type_tup, + PyArrayObject **op, + NPY_CASTING casting, + int any_object, + PyArray_Descr **out_dtype) +{ + npy_intp i, j, n, nin = self->nin, nop = nin + self->nout; + int n_specified = 0; + int specified_types[NPY_MAXARGS], types[NPY_MAXARGS]; + const char *ufunc_name; + int no_castable_output, use_min_scalar; + + /* For making a better error message on coercion error */ + char err_dst_typecode = '-', err_src_typecode = '-'; + + ufunc_name = ufunc_get_name_cstr(self); + + use_min_scalar = should_use_min_scalar(op, nin); + + /* Fill in specified_types from the tuple or string */ + if (PyTuple_Check(type_tup)) { + int nonecount = 0; + n = PyTuple_GET_SIZE(type_tup); + if (n != 1 && n != nop) { + PyErr_Format(PyExc_ValueError, + "a type-tuple must be specified " + "of length 1 or %d for ufunc '%s'", (int)nop, + ufunc_get_name_cstr(self)); + return -1; + } + + for (i = 0; i < n; ++i) { + PyObject *item = PyTuple_GET_ITEM(type_tup, i); + if (item == Py_None) { + specified_types[i] = NPY_NOTYPE; + ++nonecount; + } + else { + PyArray_Descr *dtype = NULL; + if (!PyArray_DescrConverter(item, &dtype)) { + return -1; + } + specified_types[i] = dtype->type_num; + Py_DECREF(dtype); + } + } + + if (nonecount == n) { + PyErr_SetString(PyExc_ValueError, + "the type-tuple provided to the ufunc " + "must specify at least one none-None dtype"); + return -1; + } + + n_specified = n; + } + else if (PyBytes_Check(type_tup) || PyUnicode_Check(type_tup)) { + Py_ssize_t length; + char *str; + PyObject *str_obj = NULL; + + if (PyUnicode_Check(type_tup)) { + str_obj = PyUnicode_AsASCIIString(type_tup); + if (str_obj == NULL) { + return -1; + } + type_tup = str_obj; + } + + if (PyBytes_AsStringAndSize(type_tup, &str, &length) < 0) { + Py_XDECREF(str_obj); + return -1; + } + if (length != 1 && (length != nop + 2 || + str[nin] != '-' || str[nin+1] != '>')) { + PyErr_Format(PyExc_ValueError, + "a type-string for %s, " \ + "requires 1 typecode, or " + "%d typecode(s) before " \ + "and %d after the -> sign", + ufunc_get_name_cstr(self), + self->nin, self->nout); + Py_XDECREF(str_obj); + return -1; + } + if (length == 1) { + PyArray_Descr *dtype; + n_specified = 1; + dtype = PyArray_DescrFromType(str[0]); + if (dtype == NULL) { + Py_XDECREF(str_obj); + return -1; + } + specified_types[0] = dtype->type_num; + Py_DECREF(dtype); + } + else { + PyArray_Descr *dtype; + n_specified = (int)nop; + + for (i = 0; i < nop; ++i) { + npy_intp istr = i < nin ? i : i+2; + + dtype = PyArray_DescrFromType(str[istr]); + if (dtype == NULL) { + Py_XDECREF(str_obj); + return -1; + } + specified_types[i] = dtype->type_num; + Py_DECREF(dtype); + } + } + Py_XDECREF(str_obj); + } + + /* If the ufunc has userloops, search for them. */ + if (self->userloops) { + switch (type_tuple_userloop_type_resolver(self, + n_specified, specified_types, + op, casting, + any_object, use_min_scalar, + out_dtype)) { + /* Error */ + case -1: + return -1; + /* Found matching loop */ + case 1: + return 0; + } + } + + for (i = 0; i < self->ntypes; ++i) { + char *orig_types = self->types + i*self->nargs; + + /* Copy the types into an int array for matching */ + for (j = 0; j < nop; ++j) { + types[j] = orig_types[j]; + } + + if (n_specified == nop) { + for (j = 0; j < nop; ++j) { + if (types[j] != specified_types[j] && + specified_types[j] != NPY_NOTYPE) { + break; + } + } + if (j < nop) { + /* no match */ + continue; + } + } + else if (types[nin] != specified_types[0]) { + /* no match */ + continue; + } + + switch (ufunc_loop_matches(self, op, + casting, casting, + any_object, use_min_scalar, + types, NULL, + &no_castable_output, &err_src_typecode, + &err_dst_typecode)) { + case -1: + /* Error */ + return -1; + case 0: + /* Cannot cast inputs */ + continue; + case 1: + /* Success */ + set_ufunc_loop_data_types(self, op, out_dtype, types, NULL); + return 0; + } + } + + /* If no function was found, throw an error */ + PyErr_Format(PyExc_TypeError, + "No loop matching the specified signature and casting\n" + "was found for ufunc %s", ufunc_name); + + return -1; +} diff --git a/numpy/core/src/umath/ufunc_type_resolution.h b/numpy/core/src/umath/ufunc_type_resolution.h new file mode 100644 index 0000000..fa9f1db --- /dev/null +++ b/numpy/core/src/umath/ufunc_type_resolution.h @@ -0,0 +1,142 @@ +#ifndef _NPY_PRIVATE__UFUNC_TYPE_RESOLUTION_H_ +#define _NPY_PRIVATE__UFUNC_TYPE_RESOLUTION_H_ + +NPY_NO_EXPORT int +PyUFunc_SimpleBinaryComparisonTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_SimpleUnaryOperationTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_NegativeTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_OnesLikeTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_SimpleBinaryOperationTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_AbsoluteTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_IsNaTTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_AdditionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_SubtractionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_MultiplicationTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_MixedDivisionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_TrueDivisionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_DivisionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +/* + * Does a linear search for the best inner loop of the ufunc. + * + * Note that if an error is returned, the caller must free the non-zero + * references in out_dtype. This function does not do its own clean-up. + */ +NPY_NO_EXPORT int +linear_search_type_resolver(PyUFuncObject *self, + PyArrayObject **op, + NPY_CASTING input_casting, + NPY_CASTING output_casting, + int any_object, + PyArray_Descr **out_dtype); + +/* + * Does a linear search for the inner loop of the ufunc specified by type_tup. + * + * Note that if an error is returned, the caller must free the non-zero + * references in out_dtype. This function does not do its own clean-up. + */ +NPY_NO_EXPORT int +type_tuple_type_resolver(PyUFuncObject *self, + PyObject *type_tup, + PyArrayObject **op, + NPY_CASTING casting, + int any_object, + PyArray_Descr **out_dtype); + +NPY_NO_EXPORT int +PyUFunc_DefaultLegacyInnerLoopSelector(PyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyUFuncGenericFunction *out_innerloop, + void **out_innerloopdata, + int *out_needs_api); + +NPY_NO_EXPORT int +PyUFunc_DefaultMaskedInnerLoopSelector(PyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyArray_Descr *mask_dtypes, + npy_intp *NPY_UNUSED(fixed_strides), + npy_intp NPY_UNUSED(fixed_mask_stride), + PyUFunc_MaskedStridedInnerLoopFunc + **out_innerloop, + NpyAuxData **out_innerloopdata, + int *out_needs_api); + + +#endif diff --git a/numpy/core/src/umath/umath_tests.c.src b/numpy/core/src/umath/umath_tests.c.src new file mode 100644 index 0000000..8d9009a --- /dev/null +++ b/numpy/core/src/umath/umath_tests.c.src @@ -0,0 +1,413 @@ +/* -*- c -*- */ + +/* + ***************************************************************************** + ** INCLUDES ** + ***************************************************************************** + */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" +#include "numpy/arrayobject.h" +#include "numpy/ufuncobject.h" +#include "numpy/npy_math.h" + +#include "npy_pycompat.h" + +#include "npy_config.h" + +/* + ***************************************************************************** + ** BASICS ** + ***************************************************************************** + */ + +#define INIT_OUTER_LOOP_1 \ + npy_intp dN = *dimensions++;\ + npy_intp N_; \ + npy_intp s0 = *steps++; + +#define INIT_OUTER_LOOP_2 \ + INIT_OUTER_LOOP_1 \ + npy_intp s1 = *steps++; + +#define INIT_OUTER_LOOP_3 \ + INIT_OUTER_LOOP_2 \ + npy_intp s2 = *steps++; + +#define INIT_OUTER_LOOP_4 \ + INIT_OUTER_LOOP_3 \ + npy_intp s3 = *steps++; + +#define BEGIN_OUTER_LOOP_2 \ + for (N_ = 0; N_ < dN; N_++, args[0] += s0, args[1] += s1) { + +#define BEGIN_OUTER_LOOP_3 \ + for (N_ = 0; N_ < dN; N_++, args[0] += s0, args[1] += s1, args[2] += s2) { + +#define BEGIN_OUTER_LOOP_4 \ + for (N_ = 0; N_ < dN; N_++, args[0] += s0, args[1] += s1, args[2] += s2, args[3] += s3) { + +#define END_OUTER_LOOP } + + +/* + ***************************************************************************** + ** UFUNC LOOPS ** + ***************************************************************************** + */ + +char *inner1d_signature = "(i),(i)->()"; + +/**begin repeat + + #TYPE=LONG,DOUBLE# + #typ=npy_long,npy_double# +*/ + +/* + * This implements the function + * out[n] = sum_i { in1[n, i] * in2[n, i] }. + */ + +static void +@TYPE@_inner1d(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + INIT_OUTER_LOOP_3 + npy_intp di = dimensions[0]; + npy_intp i; + npy_intp is1=steps[0], is2=steps[1]; + BEGIN_OUTER_LOOP_3 + char *ip1=args[0], *ip2=args[1], *op=args[2]; + @typ@ sum = 0; + for (i = 0; i < di; i++) { + sum += (*(@typ@ *)ip1) * (*(@typ@ *)ip2); + ip1 += is1; + ip2 += is2; + } + *(@typ@ *)op = sum; + END_OUTER_LOOP +} + +/**end repeat**/ + +char *innerwt_signature = "(i),(i),(i)->()"; + +/**begin repeat + + #TYPE=LONG,DOUBLE# + #typ=npy_long,npy_double# +*/ + + +/* + * This implements the function + * out[n] = sum_i { in1[n, i] * in2[n, i] * in3[n, i] }. + */ + +static void +@TYPE@_innerwt(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + INIT_OUTER_LOOP_4 + npy_intp di = dimensions[0]; + npy_intp i; + npy_intp is1=steps[0], is2=steps[1], is3=steps[2]; + BEGIN_OUTER_LOOP_4 + char *ip1=args[0], *ip2=args[1], *ip3=args[2], *op=args[3]; + @typ@ sum = 0; + for (i = 0; i < di; i++) { + sum += (*(@typ@ *)ip1) * (*(@typ@ *)ip2) * (*(@typ@ *)ip3); + ip1 += is1; + ip2 += is2; + ip3 += is3; + } + *(@typ@ *)op = sum; + END_OUTER_LOOP +} + +/**end repeat**/ + +char *matrix_multiply_signature = "(m,n),(n,p)->(m,p)"; + +/**begin repeat + + #TYPE=FLOAT,DOUBLE,LONG# + #typ=npy_float,npy_double,npy_long# +*/ + +/* + * This implements the function + * out[k, m, p] = sum_n { in1[k, m, n] * in2[k, n, p] }. + */ + +static void +@TYPE@_matrix_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + /* no BLAS is available */ + INIT_OUTER_LOOP_3 + npy_intp dm = dimensions[0]; + npy_intp dn = dimensions[1]; + npy_intp dp = dimensions[2]; + npy_intp m,n,p; + npy_intp is1_m=steps[0], is1_n=steps[1], is2_n=steps[2], is2_p=steps[3], + os_m=steps[4], os_p=steps[5]; + npy_intp ib1_n = is1_n*dn; + npy_intp ib2_n = is2_n*dn; + npy_intp ib2_p = is2_p*dp; + npy_intp ob_p = os_p *dp; + if (dn == 0) { + /* No operand, need to zero the output */ + BEGIN_OUTER_LOOP_3 + char *op=args[2]; + for (m = 0; m < dm; m++) { + for (p = 0; p < dp; p++) { + *(@typ@ *)op = 0; + op += os_p; + } + op += os_m - ob_p; + } + END_OUTER_LOOP + return; + } + BEGIN_OUTER_LOOP_3 + char *ip1=args[0], *ip2=args[1], *op=args[2]; + for (m = 0; m < dm; m++) { + for (n = 0; n < dn; n++) { + @typ@ val1 = (*(@typ@ *)ip1); + for (p = 0; p < dp; p++) { + if (n == 0) *(@typ@ *)op = 0; + *(@typ@ *)op += val1 * (*(@typ@ *)ip2); + ip2 += is2_p; + op += os_p; + } + ip2 -= ib2_p; + op -= ob_p; + ip1 += is1_n; + ip2 += is2_n; + } + ip1 -= ib1_n; + ip2 -= ib2_n; + ip1 += is1_m; + op += os_m; + } + END_OUTER_LOOP +} + +/**end repeat**/ + +char *euclidean_pdist_signature = "(n,d)->(p)"; + +/**begin repeat + + #TYPE=FLOAT,DOUBLE# + #typ=npy_float,npy_double# + #sqrt_func=sqrtf,sqrt# +*/ + +/* + * This implements the function + * out[j*(2*n-3-j)+k-1] = sum_d { (in1[j, d] - in1[k, d])^2 } + * with 0 < k < j < n, i.e. computes all unique pairwise euclidean distances. + */ + +static void +@TYPE@_euclidean_pdist(char **args, npy_intp *dimensions, npy_intp *steps, + void *NPY_UNUSED(func)) +{ + INIT_OUTER_LOOP_2 + npy_intp len_n = *dimensions++; + npy_intp len_d = *dimensions++; + npy_intp stride_n = *steps++; + npy_intp stride_d = *steps++; + npy_intp stride_p = *steps; + + assert(len_n * (len_n - 1) / 2 == *dimensions); + + BEGIN_OUTER_LOOP_2 + const char *data_this = (const char *)args[0]; + char *data_out = args[1]; + npy_intp n; + for (n = 0; n < len_n; ++n) { + const char *data_that = data_this + stride_n; + npy_intp nn; + for (nn = n + 1; nn < len_n; ++nn) { + const char *ptr_this = data_this; + const char *ptr_that = data_that; + @typ@ out = 0; + npy_intp d; + for (d = 0; d < len_d; ++d) { + const @typ@ delta = *(const @typ@ *)ptr_this - + *(const @typ@ *)ptr_that; + out += delta * delta; + ptr_this += stride_d; + ptr_that += stride_d; + } + *(@typ@ *)data_out = npy_@sqrt_func@(out); + data_that += stride_n; + data_out += stride_p; + } + data_this += stride_n; + } + END_OUTER_LOOP +} + +/**end repeat**/ + + +static PyUFuncGenericFunction inner1d_functions[] = { LONG_inner1d, DOUBLE_inner1d }; +static void * inner1d_data[] = { (void *)NULL, (void *)NULL }; +static char inner1d_signatures[] = { NPY_LONG, NPY_LONG, NPY_LONG, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE }; +static PyUFuncGenericFunction innerwt_functions[] = { LONG_innerwt, DOUBLE_innerwt }; +static void * innerwt_data[] = { (void *)NULL, (void *)NULL }; +static char innerwt_signatures[] = { NPY_LONG, NPY_LONG, NPY_LONG, NPY_LONG, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE }; +static PyUFuncGenericFunction matrix_multiply_functions[] = { LONG_matrix_multiply, FLOAT_matrix_multiply, DOUBLE_matrix_multiply }; +static void *matrix_multiply_data[] = { (void *)NULL, (void *)NULL, (void *)NULL }; +static char matrix_multiply_signatures[] = { NPY_LONG, NPY_LONG, NPY_LONG, NPY_FLOAT, NPY_FLOAT, NPY_FLOAT, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE }; + +static PyUFuncGenericFunction euclidean_pdist_functions[] = + { FLOAT_euclidean_pdist, DOUBLE_euclidean_pdist }; +static void *eucldiean_pdist_data[] = { (void *)NULL, (void *)NULL }; +static char euclidean_pdist_signatures[] = { NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE }; + + +static void +addUfuncs(PyObject *dictionary) { + PyObject *f; + + f = PyUFunc_FromFuncAndDataAndSignature(inner1d_functions, inner1d_data, + inner1d_signatures, 2, 2, 1, PyUFunc_None, "inner1d", + "inner on the last dimension and broadcast on the rest \n" + " \"(i),(i)->()\" \n", + 0, inner1d_signature); + PyDict_SetItemString(dictionary, "inner1d", f); + Py_DECREF(f); + f = PyUFunc_FromFuncAndDataAndSignature(innerwt_functions, innerwt_data, + innerwt_signatures, 2, 3, 1, PyUFunc_None, "innerwt", + "inner1d with a weight argument \n" + " \"(i),(i),(i)->()\" \n", + 0, innerwt_signature); + PyDict_SetItemString(dictionary, "innerwt", f); + Py_DECREF(f); + f = PyUFunc_FromFuncAndDataAndSignature(matrix_multiply_functions, + matrix_multiply_data, matrix_multiply_signatures, + 3, 2, 1, PyUFunc_None, "matrix_multiply", + "matrix multiplication on last two dimensions \n" + " \"(m,n),(n,p)->(m,p)\" \n", + 0, matrix_multiply_signature); + PyDict_SetItemString(dictionary, "matrix_multiply", f); + Py_DECREF(f); + f = PyUFunc_FromFuncAndDataAndSignature(euclidean_pdist_functions, + eucldiean_pdist_data, euclidean_pdist_signatures, + 2, 1, 1, PyUFunc_None, "euclidean_pdist", + "pairwise euclidean distance on last two dimensions \n" + " \"(n,d)->(p)\" \n", + 0, euclidean_pdist_signature); + PyDict_SetItemString(dictionary, "euclidean_pdist", f); + Py_DECREF(f); + f = PyUFunc_FromFuncAndDataAndSignature(inner1d_functions, inner1d_data, + inner1d_signatures, 2, 2, 1, PyUFunc_None, "inner1d_no_doc", + NULL, + 0, inner1d_signature); + PyDict_SetItemString(dictionary, "inner1d_no_doc", f); + Py_DECREF(f); +} + + +static PyObject * +UMath_Tests_test_signature(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + int nin, nout; + PyObject *signature, *sig_str; + PyObject *f; + int core_enabled; + + if (!PyArg_ParseTuple(args, "iiO", &nin, &nout, &signature)) return NULL; + + + if (PyString_Check(signature)) { + sig_str = signature; + } else if (PyUnicode_Check(signature)) { + sig_str = PyUnicode_AsUTF8String(signature); + } else { + PyErr_SetString(PyExc_ValueError, "signature should be a string"); + return NULL; + } + + f = PyUFunc_FromFuncAndDataAndSignature(NULL, NULL, NULL, + 0, nin, nout, PyUFunc_None, "no name", + "doc:none", + 1, PyString_AS_STRING(sig_str)); + if (sig_str != signature) { + Py_DECREF(sig_str); + } + if (f == NULL) return NULL; + core_enabled = ((PyUFuncObject*)f)->core_enabled; + Py_DECREF(f); + return Py_BuildValue("i", core_enabled); +} + +static PyMethodDef UMath_TestsMethods[] = { + {"test_signature", UMath_Tests_test_signature, METH_VARARGS, + "Test signature parsing of ufunc. \n" + "Arguments: nin nout signature \n" + "If fails, it returns NULL. Otherwise it will returns 0 for scalar ufunc " + "and 1 for generalized ufunc. \n", + }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "umath_tests", + NULL, + -1, + UMath_TestsMethods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#if defined(NPY_PY3K) +#define RETVAL m +PyMODINIT_FUNC PyInit_umath_tests(void) +#else +#define RETVAL +PyMODINIT_FUNC +initumath_tests(void) +#endif +{ + PyObject *m; + PyObject *d; + PyObject *version; + +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("umath_tests", UMath_TestsMethods); +#endif + if (m == NULL) + return RETVAL; + + import_array(); + import_ufunc(); + + d = PyModule_GetDict(m); + + version = PyString_FromString("0.1"); + PyDict_SetItemString(d, "__version__", version); + Py_DECREF(version); + + /* Load the ufunc operators into the module's namespace */ + addUfuncs(d); + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot load umath_tests module."); + } + + return RETVAL; +} diff --git a/numpy/core/src/umath/umathmodule.c b/numpy/core/src/umath/umathmodule.c new file mode 100644 index 0000000..1a6cee0 --- /dev/null +++ b/numpy/core/src/umath/umathmodule.c @@ -0,0 +1,440 @@ +/* -*- c -*- */ + +/* + * vim:syntax=c + */ + +/* + ***************************************************************************** + ** INCLUDES ** + ***************************************************************************** + */ + +/* + * _UMATHMODULE IS needed in __ufunc_api.h, included from numpy/ufuncobject.h. + * This is a mess and it would be nice to fix it. It has nothing to do with + * __ufunc_api.c + */ +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" + +#include "npy_config.h" +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API + +#include "numpy/arrayobject.h" +#include "numpy/ufuncobject.h" +#include "numpy/npy_3kcompat.h" +#include "abstract.h" + +#include "numpy/npy_math.h" + +/* + ***************************************************************************** + ** INCLUDE GENERATED CODE ** + ***************************************************************************** + */ +#include "funcs.inc" +#include "loops.h" +#include "ufunc_object.h" +#include "ufunc_type_resolution.h" +#include "__umath_generated.c" +#include "__ufunc_api.c" + +NPY_NO_EXPORT int initscalarmath(PyObject *); + +static PyUFuncGenericFunction pyfunc_functions[] = {PyUFunc_On_Om}; + +static int +object_ufunc_type_resolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + int i, nop = ufunc->nin + ufunc->nout; + + out_dtypes[0] = PyArray_DescrFromType(NPY_OBJECT); + if (out_dtypes[0] == NULL) { + return -1; + } + + for (i = 1; i < nop; ++i) { + Py_INCREF(out_dtypes[0]); + out_dtypes[i] = out_dtypes[0]; + } + + return 0; +} + +static int +object_ufunc_loop_selector(PyUFuncObject *ufunc, + PyArray_Descr **NPY_UNUSED(dtypes), + PyUFuncGenericFunction *out_innerloop, + void **out_innerloopdata, + int *out_needs_api) +{ + *out_innerloop = ufunc->functions[0]; + *out_innerloopdata = ufunc->data[0]; + *out_needs_api = 1; + + return 0; +} + +static PyObject * +ufunc_frompyfunc(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *NPY_UNUSED(kwds)) { + /* Keywords are ignored for now */ + + PyObject *function, *pyname = NULL; + int nin, nout, i; + PyUFunc_PyFuncData *fdata; + PyUFuncObject *self; + char *fname, *str; + Py_ssize_t fname_len = -1; + int offset[2]; + + if (!PyArg_ParseTuple(args, "Oii:frompyfunc", &function, &nin, &nout)) { + return NULL; + } + if (!PyCallable_Check(function)) { + PyErr_SetString(PyExc_TypeError, "function must be callable"); + return NULL; + } + if (nin + nout > NPY_MAXARGS) { + PyErr_Format(PyExc_ValueError, + "Cannot construct a ufunc with more than %d operands " + "(requested number were: inputs = %d and outputs = %d)", + NPY_MAXARGS, nin, nout); + return NULL; + } + self = PyArray_malloc(sizeof(PyUFuncObject)); + if (self == NULL) { + return NULL; + } + PyObject_Init((PyObject *)self, &PyUFunc_Type); + + self->userloops = NULL; + self->nin = nin; + self->nout = nout; + self->nargs = nin + nout; + self->identity = PyUFunc_None; + self->functions = pyfunc_functions; + self->ntypes = 1; + + /* generalized ufunc */ + self->core_enabled = 0; + self->core_num_dim_ix = 0; + self->core_num_dims = NULL; + self->core_dim_ixs = NULL; + self->core_offsets = NULL; + self->core_signature = NULL; + self->op_flags = PyArray_malloc(sizeof(npy_uint32)*self->nargs); + if (self->op_flags == NULL) { + return PyErr_NoMemory(); + } + memset(self->op_flags, 0, sizeof(npy_uint32)*self->nargs); + self->iter_flags = 0; + + self->type_resolver = &object_ufunc_type_resolver; + self->legacy_inner_loop_selector = &object_ufunc_loop_selector; + + pyname = PyObject_GetAttrString(function, "__name__"); + if (pyname) { + (void) PyString_AsStringAndSize(pyname, &fname, &fname_len); + } + if (PyErr_Occurred()) { + fname = "?"; + fname_len = 1; + PyErr_Clear(); + } + + /* + * self->ptr holds a pointer for enough memory for + * self->data[0] (fdata) + * self->data + * self->name + * self->types + * + * To be safest, all of these need their memory aligned on void * pointers + * Therefore, we may need to allocate extra space. + */ + offset[0] = sizeof(PyUFunc_PyFuncData); + i = (sizeof(PyUFunc_PyFuncData) % sizeof(void *)); + if (i) { + offset[0] += (sizeof(void *) - i); + } + offset[1] = self->nargs; + i = (self->nargs % sizeof(void *)); + if (i) { + offset[1] += (sizeof(void *)-i); + } + self->ptr = PyArray_malloc(offset[0] + offset[1] + sizeof(void *) + + (fname_len + 14)); + if (self->ptr == NULL) { + Py_XDECREF(pyname); + return PyErr_NoMemory(); + } + Py_INCREF(function); + self->obj = function; + fdata = (PyUFunc_PyFuncData *)(self->ptr); + fdata->nin = nin; + fdata->nout = nout; + fdata->callable = function; + + self->data = (void **)(((char *)self->ptr) + offset[0]); + self->data[0] = (void *)fdata; + self->types = (char *)self->data + sizeof(void *); + for (i = 0; i < self->nargs; i++) { + self->types[i] = NPY_OBJECT; + } + str = self->types + offset[1]; + memcpy(str, fname, fname_len); + memcpy(str+fname_len, " (vectorized)", 14); + self->name = str; + + Py_XDECREF(pyname); + + /* Do a better job someday */ + self->doc = "dynamic ufunc based on a python function"; + + return (PyObject *)self; +} + +/* docstring in numpy.add_newdocs.py */ +static PyObject * +add_newdoc_ufunc(PyObject *NPY_UNUSED(dummy), PyObject *args) +{ + PyUFuncObject *ufunc; + PyObject *str; + char *docstr, *newdocstr; + +#if defined(NPY_PY3K) + if (!PyArg_ParseTuple(args, "O!O!:_add_newdoc_ufunc", &PyUFunc_Type, &ufunc, + &PyUnicode_Type, &str)) { + return NULL; + } + docstr = PyBytes_AS_STRING(PyUnicode_AsUTF8String(str)); +#else + if (!PyArg_ParseTuple(args, "O!O!:_add_newdoc_ufunc", &PyUFunc_Type, &ufunc, + &PyString_Type, &str)) { + return NULL; + } + docstr = PyString_AS_STRING(str); +#endif + + if (NULL != ufunc->doc) { + PyErr_SetString(PyExc_ValueError, + "Cannot change docstring of ufunc with non-NULL docstring"); + return NULL; + } + + /* + * This introduces a memory leak, as the memory allocated for the doc + * will not be freed even if the ufunc itself is deleted. In practice + * this should not be a problem since the user would have to + * repeatedly create, document, and throw away ufuncs. + */ + newdocstr = malloc(strlen(docstr) + 1); + strcpy(newdocstr, docstr); + ufunc->doc = newdocstr; + + Py_RETURN_NONE; +} + + +/* + ***************************************************************************** + ** SETUP UFUNCS ** + ***************************************************************************** + */ + +NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_out = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_subok = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_array_prepare = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_array_wrap = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_array_finalize = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_ufunc = NULL; +NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_pyvals_name = NULL; + +/* intern some strings used in ufuncs */ +static int +intern_strings(void) +{ + npy_um_str_out = PyUString_InternFromString("out"); + npy_um_str_subok = PyUString_InternFromString("subok"); + npy_um_str_array_prepare = PyUString_InternFromString("__array_prepare__"); + npy_um_str_array_wrap = PyUString_InternFromString("__array_wrap__"); + npy_um_str_array_finalize = PyUString_InternFromString("__array_finalize__"); + npy_um_str_ufunc = PyUString_InternFromString("__array_ufunc__"); + npy_um_str_pyvals_name = PyUString_InternFromString(UFUNC_PYVALS_NAME); + + return npy_um_str_out && npy_um_str_subok && npy_um_str_array_prepare && + npy_um_str_array_wrap && npy_um_str_array_finalize && npy_um_str_ufunc; +} + +/* Setup the umath module */ +/* Remove for time being, it is declared in __ufunc_api.h */ +/*static PyTypeObject PyUFunc_Type;*/ + +static struct PyMethodDef methods[] = { + {"frompyfunc", + (PyCFunction) ufunc_frompyfunc, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"seterrobj", + (PyCFunction) ufunc_seterr, + METH_VARARGS, NULL}, + {"geterrobj", + (PyCFunction) ufunc_geterr, + METH_VARARGS, NULL}, + {"_add_newdoc_ufunc", (PyCFunction)add_newdoc_ufunc, + METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} /* sentinel */ +}; + + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "umath", + NULL, + -1, + methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#include + +#if defined(NPY_PY3K) +#define RETVAL m +PyMODINIT_FUNC PyInit_umath(void) +#else +#define RETVAL +PyMODINIT_FUNC initumath(void) +#endif +{ + PyObject *m, *d, *s, *s2, *c_api; + int UFUNC_FLOATING_POINT_SUPPORT = 1; + +#ifdef NO_UFUNC_FLOATING_POINT_SUPPORT + UFUNC_FLOATING_POINT_SUPPORT = 0; +#endif + /* Create the module and add the functions */ +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("umath", methods); +#endif + if (!m) { + return RETVAL; + } + + /* Import the array */ + if (_import_array() < 0) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, + "umath failed: Could not import array core."); + } + return RETVAL; + } + + /* Initialize the types */ + if (PyType_Ready(&PyUFunc_Type) < 0) + return RETVAL; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + + c_api = NpyCapsule_FromVoidPtr((void *)PyUFunc_API, NULL); + if (PyErr_Occurred()) { + goto err; + } + PyDict_SetItemString(d, "_UFUNC_API", c_api); + Py_DECREF(c_api); + if (PyErr_Occurred()) { + goto err; + } + + s = PyString_FromString("0.4.0"); + PyDict_SetItemString(d, "__version__", s); + Py_DECREF(s); + + /* Load the ufunc operators into the array module's namespace */ + InitOperators(d); + + PyDict_SetItemString(d, "pi", s = PyFloat_FromDouble(NPY_PI)); + Py_DECREF(s); + PyDict_SetItemString(d, "e", s = PyFloat_FromDouble(NPY_E)); + Py_DECREF(s); + PyDict_SetItemString(d, "euler_gamma", s = PyFloat_FromDouble(NPY_EULER)); + Py_DECREF(s); + +#define ADDCONST(str) PyModule_AddIntConstant(m, #str, UFUNC_##str) +#define ADDSCONST(str) PyModule_AddStringConstant(m, "UFUNC_" #str, UFUNC_##str) + + ADDCONST(ERR_IGNORE); + ADDCONST(ERR_WARN); + ADDCONST(ERR_CALL); + ADDCONST(ERR_RAISE); + ADDCONST(ERR_PRINT); + ADDCONST(ERR_LOG); + ADDCONST(ERR_DEFAULT); + + ADDCONST(SHIFT_DIVIDEBYZERO); + ADDCONST(SHIFT_OVERFLOW); + ADDCONST(SHIFT_UNDERFLOW); + ADDCONST(SHIFT_INVALID); + + ADDCONST(FPE_DIVIDEBYZERO); + ADDCONST(FPE_OVERFLOW); + ADDCONST(FPE_UNDERFLOW); + ADDCONST(FPE_INVALID); + + ADDCONST(FLOATING_POINT_SUPPORT); + + ADDSCONST(PYVALS_NAME); + +#undef ADDCONST +#undef ADDSCONST + PyModule_AddIntConstant(m, "UFUNC_BUFSIZE_DEFAULT", (long)NPY_BUFSIZE); + + PyModule_AddObject(m, "PINF", PyFloat_FromDouble(NPY_INFINITY)); + PyModule_AddObject(m, "NINF", PyFloat_FromDouble(-NPY_INFINITY)); + PyModule_AddObject(m, "PZERO", PyFloat_FromDouble(NPY_PZERO)); + PyModule_AddObject(m, "NZERO", PyFloat_FromDouble(NPY_NZERO)); + PyModule_AddObject(m, "NAN", PyFloat_FromDouble(NPY_NAN)); + +#if defined(NPY_PY3K) + s = PyDict_GetItemString(d, "true_divide"); + PyDict_SetItemString(d, "divide", s); +#endif + + s = PyDict_GetItemString(d, "conjugate"); + s2 = PyDict_GetItemString(d, "remainder"); + /* Setup the array object's numerical structures with appropriate + ufuncs in d*/ + PyArray_SetNumericOps(d); + + PyDict_SetItemString(d, "conj", s); + PyDict_SetItemString(d, "mod", s2); + + initscalarmath(m); + + if (!intern_strings()) { + goto err; + } + + return RETVAL; + + err: + /* Check for errors */ + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot load umath module."); + } + return RETVAL; +} diff --git a/numpy/core/tests/__init__.py b/numpy/core/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/core/tests/__init__.py diff --git a/numpy/core/tests/data/astype_copy.pkl b/numpy/core/tests/data/astype_copy.pkl new file mode 100644 index 0000000..7397c97 Binary files /dev/null and b/numpy/core/tests/data/astype_copy.pkl differ diff --git a/numpy/core/tests/data/recarray_from_file.fits b/numpy/core/tests/data/recarray_from_file.fits new file mode 100644 index 0000000..ca48ee8 Binary files /dev/null and b/numpy/core/tests/data/recarray_from_file.fits differ diff --git a/numpy/core/tests/test_abc.py b/numpy/core/tests/test_abc.py new file mode 100644 index 0000000..77cf406 --- /dev/null +++ b/numpy/core/tests/test_abc.py @@ -0,0 +1,60 @@ +from __future__ import division, absolute_import, print_function + +from numpy.testing import assert_, run_module_suite + +import numbers + +import numpy as np +from numpy.core.numerictypes import sctypes + +class TestABC(object): + def test_abstract(self): + assert_(issubclass(np.number, numbers.Number)) + + assert_(issubclass(np.inexact, numbers.Complex)) + assert_(issubclass(np.complexfloating, numbers.Complex)) + assert_(issubclass(np.floating, numbers.Real)) + + assert_(issubclass(np.integer, numbers.Integral)) + assert_(issubclass(np.signedinteger, numbers.Integral)) + assert_(issubclass(np.unsignedinteger, numbers.Integral)) + + def test_floats(self): + for t in sctypes['float']: + assert_(isinstance(t(), numbers.Real), + "{0} is not instance of Real".format(t.__name__)) + assert_(issubclass(t, numbers.Real), + "{0} is not subclass of Real".format(t.__name__)) + assert_(not isinstance(t(), numbers.Rational), + "{0} is instance of Rational".format(t.__name__)) + assert_(not issubclass(t, numbers.Rational), + "{0} is subclass of Rational".format(t.__name__)) + + def test_complex(self): + for t in sctypes['complex']: + assert_(isinstance(t(), numbers.Complex), + "{0} is not instance of Complex".format(t.__name__)) + assert_(issubclass(t, numbers.Complex), + "{0} is not subclass of Complex".format(t.__name__)) + assert_(not isinstance(t(), numbers.Real), + "{0} is instance of Real".format(t.__name__)) + assert_(not issubclass(t, numbers.Real), + "{0} is subclass of Real".format(t.__name__)) + + def test_int(self): + for t in sctypes['int']: + assert_(isinstance(t(), numbers.Integral), + "{0} is not instance of Integral".format(t.__name__)) + assert_(issubclass(t, numbers.Integral), + "{0} is not subclass of Integral".format(t.__name__)) + + def test_uint(self): + for t in sctypes['uint']: + assert_(isinstance(t(), numbers.Integral), + "{0} is not instance of Integral".format(t.__name__)) + assert_(issubclass(t, numbers.Integral), + "{0} is not subclass of Integral".format(t.__name__)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_api.py b/numpy/core/tests/test_api.py new file mode 100644 index 0000000..10c2d54 --- /dev/null +++ b/numpy/core/tests/test_api.py @@ -0,0 +1,517 @@ +from __future__ import division, absolute_import, print_function + +import sys + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal, + assert_raises, HAS_REFCOUNT +) + +# Switch between new behaviour when NPY_RELAXED_STRIDES_CHECKING is set. +NPY_RELAXED_STRIDES_CHECKING = np.ones((10, 1), order='C').flags.f_contiguous + + +def test_array_array(): + tobj = type(object) + ones11 = np.ones((1, 1), np.float64) + tndarray = type(ones11) + # Test is_ndarray + assert_equal(np.array(ones11, dtype=np.float64), ones11) + if HAS_REFCOUNT: + old_refcount = sys.getrefcount(tndarray) + np.array(ones11) + assert_equal(old_refcount, sys.getrefcount(tndarray)) + + # test None + assert_equal(np.array(None, dtype=np.float64), + np.array(np.nan, dtype=np.float64)) + if HAS_REFCOUNT: + old_refcount = sys.getrefcount(tobj) + np.array(None, dtype=np.float64) + assert_equal(old_refcount, sys.getrefcount(tobj)) + + # test scalar + assert_equal(np.array(1.0, dtype=np.float64), + np.ones((), dtype=np.float64)) + if HAS_REFCOUNT: + old_refcount = sys.getrefcount(np.float64) + np.array(np.array(1.0, dtype=np.float64), dtype=np.float64) + assert_equal(old_refcount, sys.getrefcount(np.float64)) + + # test string + S2 = np.dtype((str, 2)) + S3 = np.dtype((str, 3)) + S5 = np.dtype((str, 5)) + assert_equal(np.array("1.0", dtype=np.float64), + np.ones((), dtype=np.float64)) + assert_equal(np.array("1.0").dtype, S3) + assert_equal(np.array("1.0", dtype=str).dtype, S3) + assert_equal(np.array("1.0", dtype=S2), np.array("1.")) + assert_equal(np.array("1", dtype=S5), np.ones((), dtype=S5)) + + # test unicode + _unicode = globals().get("unicode") + if _unicode: + U2 = np.dtype((_unicode, 2)) + U3 = np.dtype((_unicode, 3)) + U5 = np.dtype((_unicode, 5)) + assert_equal(np.array(_unicode("1.0"), dtype=np.float64), + np.ones((), dtype=np.float64)) + assert_equal(np.array(_unicode("1.0")).dtype, U3) + assert_equal(np.array(_unicode("1.0"), dtype=_unicode).dtype, U3) + assert_equal(np.array(_unicode("1.0"), dtype=U2), + np.array(_unicode("1."))) + assert_equal(np.array(_unicode("1"), dtype=U5), + np.ones((), dtype=U5)) + + builtins = getattr(__builtins__, '__dict__', __builtins__) + assert_(hasattr(builtins, 'get')) + + # test buffer + _buffer = builtins.get("buffer") + if _buffer and sys.version_info[:3] >= (2, 7, 5): + # This test fails for earlier versions of Python. + # Evidently a bug got fixed in 2.7.5. + dat = np.array(_buffer('1.0'), dtype=np.float64) + assert_equal(dat, [49.0, 46.0, 48.0]) + assert_(dat.dtype.type is np.float64) + + dat = np.array(_buffer(b'1.0')) + assert_equal(dat, [49, 46, 48]) + assert_(dat.dtype.type is np.uint8) + + # test memoryview, new version of buffer + _memoryview = builtins.get("memoryview") + if _memoryview: + dat = np.array(_memoryview(b'1.0'), dtype=np.float64) + assert_equal(dat, [49.0, 46.0, 48.0]) + assert_(dat.dtype.type is np.float64) + + dat = np.array(_memoryview(b'1.0')) + assert_equal(dat, [49, 46, 48]) + assert_(dat.dtype.type is np.uint8) + + # test array interface + a = np.array(100.0, dtype=np.float64) + o = type("o", (object,), + dict(__array_interface__=a.__array_interface__)) + assert_equal(np.array(o, dtype=np.float64), a) + + # test array_struct interface + a = np.array([(1, 4.0, 'Hello'), (2, 6.0, 'World')], + dtype=[('f0', int), ('f1', float), ('f2', str)]) + o = type("o", (object,), + dict(__array_struct__=a.__array_struct__)) + ## wasn't what I expected... is np.array(o) supposed to equal a ? + ## instead we get a array([...], dtype=">V18") + assert_equal(bytes(np.array(o).data), bytes(a.data)) + + # test array + o = type("o", (object,), + dict(__array__=lambda *x: np.array(100.0, dtype=np.float64)))() + assert_equal(np.array(o, dtype=np.float64), np.array(100.0, np.float64)) + + # test recursion + nested = 1.5 + for i in range(np.MAXDIMS): + nested = [nested] + + # no error + np.array(nested) + + # Exceeds recursion limit + assert_raises(ValueError, np.array, [nested], dtype=np.float64) + + # Try with lists... + assert_equal(np.array([None] * 10, dtype=np.float64), + np.full((10,), np.nan, dtype=np.float64)) + assert_equal(np.array([[None]] * 10, dtype=np.float64), + np.full((10, 1), np.nan, dtype=np.float64)) + assert_equal(np.array([[None] * 10], dtype=np.float64), + np.full((1, 10), np.nan, dtype=np.float64)) + assert_equal(np.array([[None] * 10] * 10, dtype=np.float64), + np.full((10, 10), np.nan, dtype=np.float64)) + + assert_equal(np.array([1.0] * 10, dtype=np.float64), + np.ones((10,), dtype=np.float64)) + assert_equal(np.array([[1.0]] * 10, dtype=np.float64), + np.ones((10, 1), dtype=np.float64)) + assert_equal(np.array([[1.0] * 10], dtype=np.float64), + np.ones((1, 10), dtype=np.float64)) + assert_equal(np.array([[1.0] * 10] * 10, dtype=np.float64), + np.ones((10, 10), dtype=np.float64)) + + # Try with tuples + assert_equal(np.array((None,) * 10, dtype=np.float64), + np.full((10,), np.nan, dtype=np.float64)) + assert_equal(np.array([(None,)] * 10, dtype=np.float64), + np.full((10, 1), np.nan, dtype=np.float64)) + assert_equal(np.array([(None,) * 10], dtype=np.float64), + np.full((1, 10), np.nan, dtype=np.float64)) + assert_equal(np.array([(None,) * 10] * 10, dtype=np.float64), + np.full((10, 10), np.nan, dtype=np.float64)) + + assert_equal(np.array((1.0,) * 10, dtype=np.float64), + np.ones((10,), dtype=np.float64)) + assert_equal(np.array([(1.0,)] * 10, dtype=np.float64), + np.ones((10, 1), dtype=np.float64)) + assert_equal(np.array([(1.0,) * 10], dtype=np.float64), + np.ones((1, 10), dtype=np.float64)) + assert_equal(np.array([(1.0,) * 10] * 10, dtype=np.float64), + np.ones((10, 10), dtype=np.float64)) + + +def test_fastCopyAndTranspose(): + # 0D array + a = np.array(2) + b = np.fastCopyAndTranspose(a) + assert_equal(b, a.T) + assert_(b.flags.owndata) + + # 1D array + a = np.array([3, 2, 7, 0]) + b = np.fastCopyAndTranspose(a) + assert_equal(b, a.T) + assert_(b.flags.owndata) + + # 2D array + a = np.arange(6).reshape(2, 3) + b = np.fastCopyAndTranspose(a) + assert_equal(b, a.T) + assert_(b.flags.owndata) + +def test_array_astype(): + a = np.arange(6, dtype='f4').reshape(2, 3) + # Default behavior: allows unsafe casts, keeps memory layout, + # always copies. + b = a.astype('i4') + assert_equal(a, b) + assert_equal(b.dtype, np.dtype('i4')) + assert_equal(a.strides, b.strides) + b = a.T.astype('i4') + assert_equal(a.T, b) + assert_equal(b.dtype, np.dtype('i4')) + assert_equal(a.T.strides, b.strides) + b = a.astype('f4') + assert_equal(a, b) + assert_(not (a is b)) + + # copy=False parameter can sometimes skip a copy + b = a.astype('f4', copy=False) + assert_(a is b) + + # order parameter allows overriding of the memory layout, + # forcing a copy if the layout is wrong + b = a.astype('f4', order='F', copy=False) + assert_equal(a, b) + assert_(not (a is b)) + assert_(b.flags.f_contiguous) + + b = a.astype('f4', order='C', copy=False) + assert_equal(a, b) + assert_(a is b) + assert_(b.flags.c_contiguous) + + # casting parameter allows catching bad casts + b = a.astype('c8', casting='safe') + assert_equal(a, b) + assert_equal(b.dtype, np.dtype('c8')) + + assert_raises(TypeError, a.astype, 'i4', casting='safe') + + # subok=False passes through a non-subclassed array + b = a.astype('f4', subok=0, copy=False) + assert_(a is b) + + a = np.matrix([[0, 1, 2], [3, 4, 5]], dtype='f4') + + # subok=True passes through a matrix + b = a.astype('f4', subok=True, copy=False) + assert_(a is b) + + # subok=True is default, and creates a subtype on a cast + b = a.astype('i4', copy=False) + assert_equal(a, b) + assert_equal(type(b), np.matrix) + + # subok=False never returns a matrix + b = a.astype('f4', subok=False, copy=False) + assert_equal(a, b) + assert_(not (a is b)) + assert_(type(b) is not np.matrix) + + # Make sure converting from string object to fixed length string + # does not truncate. + a = np.array([b'a'*100], dtype='O') + b = a.astype('S') + assert_equal(a, b) + assert_equal(b.dtype, np.dtype('S100')) + a = np.array([u'a'*100], dtype='O') + b = a.astype('U') + assert_equal(a, b) + assert_equal(b.dtype, np.dtype('U100')) + + # Same test as above but for strings shorter than 64 characters + a = np.array([b'a'*10], dtype='O') + b = a.astype('S') + assert_equal(a, b) + assert_equal(b.dtype, np.dtype('S10')) + a = np.array([u'a'*10], dtype='O') + b = a.astype('U') + assert_equal(a, b) + assert_equal(b.dtype, np.dtype('U10')) + + a = np.array(123456789012345678901234567890, dtype='O').astype('S') + assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30')) + a = np.array(123456789012345678901234567890, dtype='O').astype('U') + assert_array_equal(a, np.array(u'1234567890' * 3, dtype='U30')) + + a = np.array([123456789012345678901234567890], dtype='O').astype('S') + assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30')) + a = np.array([123456789012345678901234567890], dtype='O').astype('U') + assert_array_equal(a, np.array(u'1234567890' * 3, dtype='U30')) + + a = np.array(123456789012345678901234567890, dtype='S') + assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30')) + a = np.array(123456789012345678901234567890, dtype='U') + assert_array_equal(a, np.array(u'1234567890' * 3, dtype='U30')) + + a = np.array(u'a\u0140', dtype='U') + b = np.ndarray(buffer=a, dtype='uint32', shape=2) + assert_(b.size == 2) + + a = np.array([1000], dtype='i4') + assert_raises(TypeError, a.astype, 'S1', casting='safe') + + a = np.array(1000, dtype='i4') + assert_raises(TypeError, a.astype, 'U1', casting='safe') + +def test_copyto_fromscalar(): + a = np.arange(6, dtype='f4').reshape(2, 3) + + # Simple copy + np.copyto(a, 1.5) + assert_equal(a, 1.5) + np.copyto(a.T, 2.5) + assert_equal(a, 2.5) + + # Where-masked copy + mask = np.array([[0, 1, 0], [0, 0, 1]], dtype='?') + np.copyto(a, 3.5, where=mask) + assert_equal(a, [[2.5, 3.5, 2.5], [2.5, 2.5, 3.5]]) + mask = np.array([[0, 1], [1, 1], [1, 0]], dtype='?') + np.copyto(a.T, 4.5, where=mask) + assert_equal(a, [[2.5, 4.5, 4.5], [4.5, 4.5, 3.5]]) + +def test_copyto(): + a = np.arange(6, dtype='i4').reshape(2, 3) + + # Simple copy + np.copyto(a, [[3, 1, 5], [6, 2, 1]]) + assert_equal(a, [[3, 1, 5], [6, 2, 1]]) + + # Overlapping copy should work + np.copyto(a[:, :2], a[::-1, 1::-1]) + assert_equal(a, [[2, 6, 5], [1, 3, 1]]) + + # Defaults to 'same_kind' casting + assert_raises(TypeError, np.copyto, a, 1.5) + + # Force a copy with 'unsafe' casting, truncating 1.5 to 1 + np.copyto(a, 1.5, casting='unsafe') + assert_equal(a, 1) + + # Copying with a mask + np.copyto(a, 3, where=[True, False, True]) + assert_equal(a, [[3, 1, 3], [3, 1, 3]]) + + # Casting rule still applies with a mask + assert_raises(TypeError, np.copyto, a, 3.5, where=[True, False, True]) + + # Lists of integer 0's and 1's is ok too + np.copyto(a, 4.0, casting='unsafe', where=[[0, 1, 1], [1, 0, 0]]) + assert_equal(a, [[3, 4, 4], [4, 1, 3]]) + + # Overlapping copy with mask should work + np.copyto(a[:, :2], a[::-1, 1::-1], where=[[0, 1], [1, 1]]) + assert_equal(a, [[3, 4, 4], [4, 3, 3]]) + + # 'dst' must be an array + assert_raises(TypeError, np.copyto, [1, 2, 3], [2, 3, 4]) + +def test_copyto_permut(): + # test explicit overflow case + pad = 500 + l = [True] * pad + [True, True, True, True] + r = np.zeros(len(l)-pad) + d = np.ones(len(l)-pad) + mask = np.array(l)[pad:] + np.copyto(r, d, where=mask[::-1]) + + # test all permutation of possible masks, 9 should be sufficient for + # current 4 byte unrolled code + power = 9 + d = np.ones(power) + for i in range(2**power): + r = np.zeros(power) + l = [(i & x) != 0 for x in range(power)] + mask = np.array(l) + np.copyto(r, d, where=mask) + assert_array_equal(r == 1, l) + assert_equal(r.sum(), sum(l)) + + r = np.zeros(power) + np.copyto(r, d, where=mask[::-1]) + assert_array_equal(r == 1, l[::-1]) + assert_equal(r.sum(), sum(l)) + + r = np.zeros(power) + np.copyto(r[::2], d[::2], where=mask[::2]) + assert_array_equal(r[::2] == 1, l[::2]) + assert_equal(r[::2].sum(), sum(l[::2])) + + r = np.zeros(power) + np.copyto(r[::2], d[::2], where=mask[::-2]) + assert_array_equal(r[::2] == 1, l[::-2]) + assert_equal(r[::2].sum(), sum(l[::-2])) + + for c in [0xFF, 0x7F, 0x02, 0x10]: + r = np.zeros(power) + mask = np.array(l) + imask = np.array(l).view(np.uint8) + imask[mask != 0] = c + np.copyto(r, d, where=mask) + assert_array_equal(r == 1, l) + assert_equal(r.sum(), sum(l)) + + r = np.zeros(power) + np.copyto(r, d, where=True) + assert_equal(r.sum(), r.size) + r = np.ones(power) + d = np.zeros(power) + np.copyto(r, d, where=False) + assert_equal(r.sum(), r.size) + +def test_copy_order(): + a = np.arange(24).reshape(2, 1, 3, 4) + b = a.copy(order='F') + c = np.arange(24).reshape(2, 1, 4, 3).swapaxes(2, 3) + + def check_copy_result(x, y, ccontig, fcontig, strides=False): + assert_(not (x is y)) + assert_equal(x, y) + assert_equal(res.flags.c_contiguous, ccontig) + assert_equal(res.flags.f_contiguous, fcontig) + # This check is impossible only because + # NPY_RELAXED_STRIDES_CHECKING changes the strides actively + if not NPY_RELAXED_STRIDES_CHECKING: + if strides: + assert_equal(x.strides, y.strides) + else: + assert_(x.strides != y.strides) + + # Validate the initial state of a, b, and c + assert_(a.flags.c_contiguous) + assert_(not a.flags.f_contiguous) + assert_(not b.flags.c_contiguous) + assert_(b.flags.f_contiguous) + assert_(not c.flags.c_contiguous) + assert_(not c.flags.f_contiguous) + + # Copy with order='C' + res = a.copy(order='C') + check_copy_result(res, a, ccontig=True, fcontig=False, strides=True) + res = b.copy(order='C') + check_copy_result(res, b, ccontig=True, fcontig=False, strides=False) + res = c.copy(order='C') + check_copy_result(res, c, ccontig=True, fcontig=False, strides=False) + res = np.copy(a, order='C') + check_copy_result(res, a, ccontig=True, fcontig=False, strides=True) + res = np.copy(b, order='C') + check_copy_result(res, b, ccontig=True, fcontig=False, strides=False) + res = np.copy(c, order='C') + check_copy_result(res, c, ccontig=True, fcontig=False, strides=False) + + # Copy with order='F' + res = a.copy(order='F') + check_copy_result(res, a, ccontig=False, fcontig=True, strides=False) + res = b.copy(order='F') + check_copy_result(res, b, ccontig=False, fcontig=True, strides=True) + res = c.copy(order='F') + check_copy_result(res, c, ccontig=False, fcontig=True, strides=False) + res = np.copy(a, order='F') + check_copy_result(res, a, ccontig=False, fcontig=True, strides=False) + res = np.copy(b, order='F') + check_copy_result(res, b, ccontig=False, fcontig=True, strides=True) + res = np.copy(c, order='F') + check_copy_result(res, c, ccontig=False, fcontig=True, strides=False) + + # Copy with order='K' + res = a.copy(order='K') + check_copy_result(res, a, ccontig=True, fcontig=False, strides=True) + res = b.copy(order='K') + check_copy_result(res, b, ccontig=False, fcontig=True, strides=True) + res = c.copy(order='K') + check_copy_result(res, c, ccontig=False, fcontig=False, strides=True) + res = np.copy(a, order='K') + check_copy_result(res, a, ccontig=True, fcontig=False, strides=True) + res = np.copy(b, order='K') + check_copy_result(res, b, ccontig=False, fcontig=True, strides=True) + res = np.copy(c, order='K') + check_copy_result(res, c, ccontig=False, fcontig=False, strides=True) + +def test_contiguous_flags(): + a = np.ones((4, 4, 1))[::2,:,:] + if NPY_RELAXED_STRIDES_CHECKING: + a.strides = a.strides[:2] + (-123,) + b = np.ones((2, 2, 1, 2, 2)).swapaxes(3, 4) + + def check_contig(a, ccontig, fcontig): + assert_(a.flags.c_contiguous == ccontig) + assert_(a.flags.f_contiguous == fcontig) + + # Check if new arrays are correct: + check_contig(a, False, False) + check_contig(b, False, False) + if NPY_RELAXED_STRIDES_CHECKING: + check_contig(np.empty((2, 2, 0, 2, 2)), True, True) + check_contig(np.array([[[1], [2]]], order='F'), True, True) + else: + check_contig(np.empty((2, 2, 0, 2, 2)), True, False) + check_contig(np.array([[[1], [2]]], order='F'), False, True) + check_contig(np.empty((2, 2)), True, False) + check_contig(np.empty((2, 2), order='F'), False, True) + + # Check that np.array creates correct contiguous flags: + check_contig(np.array(a, copy=False), False, False) + check_contig(np.array(a, copy=False, order='C'), True, False) + check_contig(np.array(a, ndmin=4, copy=False, order='F'), False, True) + + if NPY_RELAXED_STRIDES_CHECKING: + # Check slicing update of flags and : + check_contig(a[0], True, True) + check_contig(a[None, ::4, ..., None], True, True) + check_contig(b[0, 0, ...], False, True) + check_contig(b[:,:, 0:0,:,:], True, True) + else: + # Check slicing update of flags: + check_contig(a[0], True, False) + # Would be nice if this was C-Contiguous: + check_contig(a[None, 0, ..., None], False, False) + check_contig(b[0, 0, 0, ...], False, True) + + # Test ravel and squeeze. + check_contig(a.ravel(), True, True) + check_contig(np.ones((1, 3, 1)).squeeze(), True, True) + +def test_broadcast_arrays(): + # Test user defined dtypes + a = np.array([(1, 2, 3)], dtype='u4,u4,u4') + b = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype='u4,u4,u4') + result = np.broadcast_arrays(a, b) + assert_equal(result[0], np.array([(1, 2, 3), (1, 2, 3), (1, 2, 3)], dtype='u4,u4,u4')) + assert_equal(result[1], np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype='u4,u4,u4')) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_arrayprint.py b/numpy/core/tests/test_arrayprint.py new file mode 100644 index 0000000..40a99e1 --- /dev/null +++ b/numpy/core/tests/test_arrayprint.py @@ -0,0 +1,844 @@ +# -*- coding: utf-8 -*- +from __future__ import division, absolute_import, print_function + +import sys, gc + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, assert_warns, dec +) +import textwrap + +class TestArrayRepr(object): + def test_nan_inf(self): + x = np.array([np.nan, np.inf]) + assert_equal(repr(x), 'array([nan, inf])') + + def test_subclass(self): + class sub(np.ndarray): pass + + # one dimensional + x1d = np.array([1, 2]).view(sub) + assert_equal(repr(x1d), 'sub([1, 2])') + + # two dimensional + x2d = np.array([[1, 2], [3, 4]]).view(sub) + assert_equal(repr(x2d), + 'sub([[1, 2],\n' + ' [3, 4]])') + + # two dimensional with flexible dtype + xstruct = np.ones((2,2), dtype=[('a', ' 1) + y = sub(None) + x[()] = y + y[()] = x + assert_equal(repr(x), + 'sub(sub(sub(..., dtype=object), dtype=object), dtype=object)') + assert_equal(str(x), '...') + + # nested 0d-subclass-object + x = sub(None) + x[()] = sub(None) + assert_equal(repr(x), 'sub(sub(None, dtype=object), dtype=object)') + assert_equal(str(x), 'None') + + # gh-10663 + class DuckCounter(np.ndarray): + def __getitem__(self, item): + result = super(DuckCounter, self).__getitem__(item) + if not isinstance(result, DuckCounter): + result = result[...].view(DuckCounter) + return result + + def to_string(self): + return {0: 'zero', 1: 'one', 2: 'two'}.get(self.item(), 'many') + + def __str__(self): + if self.shape == (): + return self.to_string() + else: + fmt = {'all': lambda x: x.to_string()} + return np.array2string(self, formatter=fmt) + + dc = np.arange(5).view(DuckCounter) + assert_equal(str(dc), "[zero one two many many]") + assert_equal(str(dc[0]), "zero") + + def test_self_containing(self): + arr0d = np.array(None) + arr0d[()] = arr0d + assert_equal(repr(arr0d), + 'array(array(..., dtype=object), dtype=object)') + + arr1d = np.array([None, None]) + arr1d[1] = arr1d + assert_equal(repr(arr1d), + 'array([None, array(..., dtype=object)], dtype=object)') + + first = np.array(None) + second = np.array(None) + first[()] = second + second[()] = first + assert_equal(repr(first), + 'array(array(array(..., dtype=object), dtype=object), dtype=object)') + + def test_containing_list(self): + # printing square brackets directly would be ambiguuous + arr1d = np.array([None, None]) + arr1d[0] = [1, 2] + arr1d[1] = [3] + assert_equal(repr(arr1d), + 'array([list([1, 2]), list([3])], dtype=object)') + + def test_void_scalar_recursion(self): + # gh-9345 + repr(np.void(b'test')) # RecursionError ? + + def test_fieldless_structured(self): + # gh-10366 + no_fields = np.dtype([]) + arr_no_fields = np.empty(4, dtype=no_fields) + assert_equal(repr(arr_no_fields), 'array([(), (), (), ()], dtype=[])') + + +class TestComplexArray(object): + def test_str(self): + rvals = [0, 1, -1, np.inf, -np.inf, np.nan] + cvals = [complex(rp, ip) for rp in rvals for ip in rvals] + dtypes = [np.complex64, np.cdouble, np.clongdouble] + actual = [str(np.array([c], dt)) for c in cvals for dt in dtypes] + wanted = [ + '[0.+0.j]', '[0.+0.j]', '[0.+0.j]', + '[0.+1.j]', '[0.+1.j]', '[0.+1.j]', + '[0.-1.j]', '[0.-1.j]', '[0.-1.j]', + '[0.+infj]', '[0.+infj]', '[0.+infj]', + '[0.-infj]', '[0.-infj]', '[0.-infj]', + '[0.+nanj]', '[0.+nanj]', '[0.+nanj]', + '[1.+0.j]', '[1.+0.j]', '[1.+0.j]', + '[1.+1.j]', '[1.+1.j]', '[1.+1.j]', + '[1.-1.j]', '[1.-1.j]', '[1.-1.j]', + '[1.+infj]', '[1.+infj]', '[1.+infj]', + '[1.-infj]', '[1.-infj]', '[1.-infj]', + '[1.+nanj]', '[1.+nanj]', '[1.+nanj]', + '[-1.+0.j]', '[-1.+0.j]', '[-1.+0.j]', + '[-1.+1.j]', '[-1.+1.j]', '[-1.+1.j]', + '[-1.-1.j]', '[-1.-1.j]', '[-1.-1.j]', + '[-1.+infj]', '[-1.+infj]', '[-1.+infj]', + '[-1.-infj]', '[-1.-infj]', '[-1.-infj]', + '[-1.+nanj]', '[-1.+nanj]', '[-1.+nanj]', + '[inf+0.j]', '[inf+0.j]', '[inf+0.j]', + '[inf+1.j]', '[inf+1.j]', '[inf+1.j]', + '[inf-1.j]', '[inf-1.j]', '[inf-1.j]', + '[inf+infj]', '[inf+infj]', '[inf+infj]', + '[inf-infj]', '[inf-infj]', '[inf-infj]', + '[inf+nanj]', '[inf+nanj]', '[inf+nanj]', + '[-inf+0.j]', '[-inf+0.j]', '[-inf+0.j]', + '[-inf+1.j]', '[-inf+1.j]', '[-inf+1.j]', + '[-inf-1.j]', '[-inf-1.j]', '[-inf-1.j]', + '[-inf+infj]', '[-inf+infj]', '[-inf+infj]', + '[-inf-infj]', '[-inf-infj]', '[-inf-infj]', + '[-inf+nanj]', '[-inf+nanj]', '[-inf+nanj]', + '[nan+0.j]', '[nan+0.j]', '[nan+0.j]', + '[nan+1.j]', '[nan+1.j]', '[nan+1.j]', + '[nan-1.j]', '[nan-1.j]', '[nan-1.j]', + '[nan+infj]', '[nan+infj]', '[nan+infj]', + '[nan-infj]', '[nan-infj]', '[nan-infj]', + '[nan+nanj]', '[nan+nanj]', '[nan+nanj]'] + + for res, val in zip(actual, wanted): + assert_equal(res, val) + +class TestArray2String(object): + def test_basic(self): + """Basic test of array2string.""" + a = np.arange(3) + assert_(np.array2string(a) == '[0 1 2]') + assert_(np.array2string(a, max_line_width=4, legacy='1.13') == '[0 1\n 2]') + assert_(np.array2string(a, max_line_width=4) == '[0\n 1\n 2]') + + def test_format_function(self): + """Test custom format function for each element in array.""" + def _format_function(x): + if np.abs(x) < 1: + return '.' + elif np.abs(x) < 2: + return 'o' + else: + return 'O' + + x = np.arange(3) + if sys.version_info[0] >= 3: + x_hex = "[0x0 0x1 0x2]" + x_oct = "[0o0 0o1 0o2]" + else: + x_hex = "[0x0L 0x1L 0x2L]" + x_oct = "[0L 01L 02L]" + assert_(np.array2string(x, formatter={'all':_format_function}) == + "[. o O]") + assert_(np.array2string(x, formatter={'int_kind':_format_function}) == + "[. o O]") + assert_(np.array2string(x, formatter={'all':lambda x: "%.4f" % x}) == + "[0.0000 1.0000 2.0000]") + assert_equal(np.array2string(x, formatter={'int':lambda x: hex(x)}), + x_hex) + assert_equal(np.array2string(x, formatter={'int':lambda x: oct(x)}), + x_oct) + + x = np.arange(3.) + assert_(np.array2string(x, formatter={'float_kind':lambda x: "%.2f" % x}) == + "[0.00 1.00 2.00]") + assert_(np.array2string(x, formatter={'float':lambda x: "%.2f" % x}) == + "[0.00 1.00 2.00]") + + s = np.array(['abc', 'def']) + assert_(np.array2string(s, formatter={'numpystr':lambda s: s*2}) == + '[abcabc defdef]') + + # check for backcompat that using FloatFormat works and emits warning + with assert_warns(DeprecationWarning): + fmt = np.core.arrayprint.FloatFormat(x, 9, 'maxprec', False) + assert_equal(np.array2string(x, formatter={'float_kind': fmt}), + '[0. 1. 2.]') + + def test_structure_format(self): + dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))]) + x = np.array([('Sarah', (8.0, 7.0)), ('John', (6.0, 7.0))], dtype=dt) + assert_equal(np.array2string(x), + "[('Sarah', [8., 7.]) ('John', [6., 7.])]") + + np.set_printoptions(legacy='1.13') + try: + # for issue #5692 + A = np.zeros(shape=10, dtype=[("A", "M8[s]")]) + A[5:].fill(np.datetime64('NaT')) + assert_equal( + np.array2string(A), + textwrap.dedent("""\ + [('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',) + ('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',) ('NaT',) ('NaT',) + ('NaT',) ('NaT',) ('NaT',)]""") + ) + finally: + np.set_printoptions(legacy=False) + + # same again, but with non-legacy behavior + assert_equal( + np.array2string(A), + textwrap.dedent("""\ + [('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',) + ('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',) + ('1970-01-01T00:00:00',) ( 'NaT',) + ( 'NaT',) ( 'NaT',) + ( 'NaT',) ( 'NaT',)]""") + ) + + # and again, with timedeltas + A = np.full(10, 123456, dtype=[("A", "m8[s]")]) + A[5:].fill(np.datetime64('NaT')) + assert_equal( + np.array2string(A), + textwrap.dedent("""\ + [(123456,) (123456,) (123456,) (123456,) (123456,) ( 'NaT',) ( 'NaT',) + ( 'NaT',) ( 'NaT',) ( 'NaT',)]""") + ) + + # See #8160 + struct_int = np.array([([1, -1],), ([123, 1],)], dtype=[('B', 'i4', 2)]) + assert_equal(np.array2string(struct_int), + "[([ 1, -1],) ([123, 1],)]") + struct_2dint = np.array([([[0, 1], [2, 3]],), ([[12, 0], [0, 0]],)], + dtype=[('B', 'i4', (2, 2))]) + assert_equal(np.array2string(struct_2dint), + "[([[ 0, 1], [ 2, 3]],) ([[12, 0], [ 0, 0]],)]") + + # See #8172 + array_scalar = np.array( + (1., 2.1234567890123456789, 3.), dtype=('f8,f8,f8')) + assert_equal(np.array2string(array_scalar), "(1., 2.12345679, 3.)") + + def test_unstructured_void_repr(self): + a = np.array([27, 91, 50, 75, 7, 65, 10, 8, + 27, 91, 51, 49,109, 82,101,100], dtype='u1').view('V8') + assert_equal(repr(a[0]), r"void(b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08')") + assert_equal(str(a[0]), r"b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08'") + assert_equal(repr(a), + r"array([b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08'," "\n" + r" b'\x1B\x5B\x33\x31\x6D\x52\x65\x64'], dtype='|V8')") + + assert_equal(eval(repr(a), vars(np)), a) + assert_equal(eval(repr(a[0]), vars(np)), a[0]) + + def test_edgeitems_kwarg(self): + # previously the global print options would be taken over the kwarg + arr = np.zeros(3, int) + assert_equal( + np.array2string(arr, edgeitems=1, threshold=0), + "[0 ... 0]" + ) + + def test_summarize_1d(self): + A = np.arange(1001) + strA = '[ 0 1 2 ... 998 999 1000]' + assert_equal(str(A), strA) + + reprA = 'array([ 0, 1, 2, ..., 998, 999, 1000])' + assert_equal(repr(A), reprA) + + def test_summarize_2d(self): + A = np.arange(1002).reshape(2, 501) + strA = '[[ 0 1 2 ... 498 499 500]\n' \ + ' [ 501 502 503 ... 999 1000 1001]]' + assert_equal(str(A), strA) + + reprA = 'array([[ 0, 1, 2, ..., 498, 499, 500],\n' \ + ' [ 501, 502, 503, ..., 999, 1000, 1001]])' + assert_equal(repr(A), reprA) + + def test_linewidth(self): + a = np.full(6, 1) + + def make_str(a, width, **kw): + return np.array2string(a, separator="", max_line_width=width, **kw) + + assert_equal(make_str(a, 8, legacy='1.13'), '[111111]') + assert_equal(make_str(a, 7, legacy='1.13'), '[111111]') + assert_equal(make_str(a, 5, legacy='1.13'), '[1111\n' + ' 11]') + + assert_equal(make_str(a, 8), '[111111]') + assert_equal(make_str(a, 7), '[11111\n' + ' 1]') + assert_equal(make_str(a, 5), '[111\n' + ' 111]') + + b = a[None,None,:] + + assert_equal(make_str(b, 12, legacy='1.13'), '[[[111111]]]') + assert_equal(make_str(b, 9, legacy='1.13'), '[[[111111]]]') + assert_equal(make_str(b, 8, legacy='1.13'), '[[[11111\n' + ' 1]]]') + + assert_equal(make_str(b, 12), '[[[111111]]]') + assert_equal(make_str(b, 9), '[[[111\n' + ' 111]]]') + assert_equal(make_str(b, 8), '[[[11\n' + ' 11\n' + ' 11]]]') + + def test_wide_element(self): + a = np.array(['xxxxx']) + assert_equal( + np.array2string(a, max_line_width=5), + "['xxxxx']" + ) + assert_equal( + np.array2string(a, max_line_width=5, legacy='1.13'), + "[ 'xxxxx']" + ) + + def test_refcount(self): + # make sure we do not hold references to the array due to a recursive + # closure (gh-10620) + gc.disable() + a = np.arange(2) + r1 = sys.getrefcount(a) + np.array2string(a) + np.array2string(a) + r2 = sys.getrefcount(a) + gc.collect() + gc.enable() + assert_(r1 == r2) + +class TestPrintOptions(object): + """Test getting and setting global print options.""" + + def setup(self): + self.oldopts = np.get_printoptions() + + def teardown(self): + np.set_printoptions(**self.oldopts) + + def test_basic(self): + x = np.array([1.5, 0, 1.234567890]) + assert_equal(repr(x), "array([1.5 , 0. , 1.23456789])") + np.set_printoptions(precision=4) + assert_equal(repr(x), "array([1.5 , 0. , 1.2346])") + + def test_precision_zero(self): + np.set_printoptions(precision=0) + for values, string in ( + ([0.], "0."), ([.3], "0."), ([-.3], "-0."), ([.7], "1."), + ([1.5], "2."), ([-1.5], "-2."), ([-15.34], "-15."), + ([100.], "100."), ([.2, -1, 122.51], " 0., -1., 123."), + ([0], "0"), ([-12], "-12"), ([complex(.3, -.7)], "0.-1.j")): + x = np.array(values) + assert_equal(repr(x), "array([%s])" % string) + + def test_formatter(self): + x = np.arange(3) + np.set_printoptions(formatter={'all':lambda x: str(x-1)}) + assert_equal(repr(x), "array([-1, 0, 1])") + + def test_formatter_reset(self): + x = np.arange(3) + np.set_printoptions(formatter={'all':lambda x: str(x-1)}) + assert_equal(repr(x), "array([-1, 0, 1])") + np.set_printoptions(formatter={'int':None}) + assert_equal(repr(x), "array([0, 1, 2])") + + np.set_printoptions(formatter={'all':lambda x: str(x-1)}) + assert_equal(repr(x), "array([-1, 0, 1])") + np.set_printoptions(formatter={'all':None}) + assert_equal(repr(x), "array([0, 1, 2])") + + np.set_printoptions(formatter={'int':lambda x: str(x-1)}) + assert_equal(repr(x), "array([-1, 0, 1])") + np.set_printoptions(formatter={'int_kind':None}) + assert_equal(repr(x), "array([0, 1, 2])") + + x = np.arange(3.) + np.set_printoptions(formatter={'float':lambda x: str(x-1)}) + assert_equal(repr(x), "array([-1.0, 0.0, 1.0])") + np.set_printoptions(formatter={'float_kind':None}) + assert_equal(repr(x), "array([0., 1., 2.])") + + def test_0d_arrays(self): + unicode = type(u'') + + assert_equal(unicode(np.array(u'café', '= 3: + assert_equal(repr(np.array('café', '= 3 else '|S4' + assert_equal(repr(np.ones(3, dtype=styp)), + "array(['1', '1', '1'], dtype='{}')".format(styp)) + assert_equal(repr(np.ones(12, dtype=styp)), textwrap.dedent("""\ + array(['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'], + dtype='{}')""".format(styp))) + + def test_linewidth_repr(self): + a = np.full(7, fill_value=2) + np.set_printoptions(linewidth=17) + assert_equal( + repr(a), + textwrap.dedent("""\ + array([2, 2, 2, + 2, 2, 2, + 2])""") + ) + np.set_printoptions(linewidth=17, legacy='1.13') + assert_equal( + repr(a), + textwrap.dedent("""\ + array([2, 2, 2, + 2, 2, 2, 2])""") + ) + + a = np.full(8, fill_value=2) + + np.set_printoptions(linewidth=18, legacy=False) + assert_equal( + repr(a), + textwrap.dedent("""\ + array([2, 2, 2, + 2, 2, 2, + 2, 2])""") + ) + + np.set_printoptions(linewidth=18, legacy='1.13') + assert_equal( + repr(a), + textwrap.dedent("""\ + array([2, 2, 2, 2, + 2, 2, 2, 2])""") + ) + + def test_linewidth_str(self): + a = np.full(18, fill_value=2) + np.set_printoptions(linewidth=18) + assert_equal( + str(a), + textwrap.dedent("""\ + [2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 + 2 2]""") + ) + np.set_printoptions(linewidth=18, legacy='1.13') + assert_equal( + str(a), + textwrap.dedent("""\ + [2 2 2 2 2 2 2 2 2 + 2 2 2 2 2 2 2 2 2]""") + ) + + def test_edgeitems(self): + np.set_printoptions(edgeitems=1, threshold=1) + a = np.arange(27).reshape((3, 3, 3)) + assert_equal( + repr(a), + textwrap.dedent("""\ + array([[[ 0, ..., 2], + ..., + [ 6, ..., 8]], + + ..., + + [[18, ..., 20], + ..., + [24, ..., 26]]])""") + ) + + b = np.zeros((3, 3, 1, 1)) + assert_equal( + repr(b), + textwrap.dedent("""\ + array([[[[0.]], + + ..., + + [[0.]]], + + + ..., + + + [[[0.]], + + ..., + + [[0.]]]])""") + ) + + # 1.13 had extra trailing spaces, and was missing newlines + np.set_printoptions(legacy='1.13') + + assert_equal( + repr(a), + textwrap.dedent("""\ + array([[[ 0, ..., 2], + ..., + [ 6, ..., 8]], + + ..., + [[18, ..., 20], + ..., + [24, ..., 26]]])""") + ) + + assert_equal( + repr(b), + textwrap.dedent("""\ + array([[[[ 0.]], + + ..., + [[ 0.]]], + + + ..., + [[[ 0.]], + + ..., + [[ 0.]]]])""") + ) + + +def test_unicode_object_array(): + import sys + if sys.version_info[0] >= 3: + expected = "array(['é'], dtype=object)" + else: + expected = "array([u'\\xe9'], dtype=object)" + x = np.array([u'\xe9'], dtype=object) + assert_equal(repr(x), expected) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py new file mode 100644 index 0000000..638994a --- /dev/null +++ b/numpy/core/tests/test_datetime.py @@ -0,0 +1,1976 @@ +from __future__ import division, absolute_import, print_function + +import pickle + +import numpy +import numpy as np +import datetime +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, + assert_warns, dec, suppress_warnings +) + +# Use pytz to test out various time zones if available +try: + from pytz import timezone as tz + _has_pytz = True +except ImportError: + _has_pytz = False + + +class TestDateTime(object): + def test_datetime_dtype_creation(self): + for unit in ['Y', 'M', 'W', 'D', + 'h', 'm', 's', 'ms', 'us', + 'ns', 'ps', 'fs', 'as']: + dt1 = np.dtype('M8[750%s]' % unit) + assert_(dt1 == np.dtype('datetime64[750%s]' % unit)) + dt2 = np.dtype('m8[%s]' % unit) + assert_(dt2 == np.dtype('timedelta64[%s]' % unit)) + + # Generic units shouldn't add [] to the end + assert_equal(str(np.dtype("M8")), "datetime64") + + # Should be possible to specify the endianness + assert_equal(np.dtype("=M8"), np.dtype("M8")) + assert_equal(np.dtype("=M8[s]"), np.dtype("M8[s]")) + assert_(np.dtype(">M8") == np.dtype("M8") or + np.dtype("M8[D]") == np.dtype("M8[D]") or + np.dtype("M8") != np.dtype("m8") == np.dtype("m8") or + np.dtype("m8[D]") == np.dtype("m8[D]") or + np.dtype("m8") != np.dtype(" Scalars + assert_equal(np.datetime64(b, '[s]'), np.datetime64('NaT', '[s]')) + assert_equal(np.datetime64(b, '[ms]'), np.datetime64('NaT', '[ms]')) + assert_equal(np.datetime64(b, '[M]'), np.datetime64('NaT', '[M]')) + assert_equal(np.datetime64(b, '[Y]'), np.datetime64('NaT', '[Y]')) + assert_equal(np.datetime64(b, '[W]'), np.datetime64('NaT', '[W]')) + + # Arrays -> Scalars + assert_equal(np.datetime64(a, '[s]'), np.datetime64('NaT', '[s]')) + assert_equal(np.datetime64(a, '[ms]'), np.datetime64('NaT', '[ms]')) + assert_equal(np.datetime64(a, '[M]'), np.datetime64('NaT', '[M]')) + assert_equal(np.datetime64(a, '[Y]'), np.datetime64('NaT', '[Y]')) + assert_equal(np.datetime64(a, '[W]'), np.datetime64('NaT', '[W]')) + + def test_days_creation(self): + assert_equal(np.array('1599', dtype='M8[D]').astype('i8'), + (1600-1970)*365 - (1972-1600)/4 + 3 - 365) + assert_equal(np.array('1600', dtype='M8[D]').astype('i8'), + (1600-1970)*365 - (1972-1600)/4 + 3) + assert_equal(np.array('1601', dtype='M8[D]').astype('i8'), + (1600-1970)*365 - (1972-1600)/4 + 3 + 366) + assert_equal(np.array('1900', dtype='M8[D]').astype('i8'), + (1900-1970)*365 - (1970-1900)//4) + assert_equal(np.array('1901', dtype='M8[D]').astype('i8'), + (1900-1970)*365 - (1970-1900)//4 + 365) + assert_equal(np.array('1967', dtype='M8[D]').astype('i8'), -3*365 - 1) + assert_equal(np.array('1968', dtype='M8[D]').astype('i8'), -2*365 - 1) + assert_equal(np.array('1969', dtype='M8[D]').astype('i8'), -1*365) + assert_equal(np.array('1970', dtype='M8[D]').astype('i8'), 0*365) + assert_equal(np.array('1971', dtype='M8[D]').astype('i8'), 1*365) + assert_equal(np.array('1972', dtype='M8[D]').astype('i8'), 2*365) + assert_equal(np.array('1973', dtype='M8[D]').astype('i8'), 3*365 + 1) + assert_equal(np.array('1974', dtype='M8[D]').astype('i8'), 4*365 + 1) + assert_equal(np.array('2000', dtype='M8[D]').astype('i8'), + (2000 - 1970)*365 + (2000 - 1972)//4) + assert_equal(np.array('2001', dtype='M8[D]').astype('i8'), + (2000 - 1970)*365 + (2000 - 1972)//4 + 366) + assert_equal(np.array('2400', dtype='M8[D]').astype('i8'), + (2400 - 1970)*365 + (2400 - 1972)//4 - 3) + assert_equal(np.array('2401', dtype='M8[D]').astype('i8'), + (2400 - 1970)*365 + (2400 - 1972)//4 - 3 + 366) + + assert_equal(np.array('1600-02-29', dtype='M8[D]').astype('i8'), + (1600-1970)*365 - (1972-1600)//4 + 3 + 31 + 28) + assert_equal(np.array('1600-03-01', dtype='M8[D]').astype('i8'), + (1600-1970)*365 - (1972-1600)//4 + 3 + 31 + 29) + assert_equal(np.array('2000-02-29', dtype='M8[D]').astype('i8'), + (2000 - 1970)*365 + (2000 - 1972)//4 + 31 + 28) + assert_equal(np.array('2000-03-01', dtype='M8[D]').astype('i8'), + (2000 - 1970)*365 + (2000 - 1972)//4 + 31 + 29) + assert_equal(np.array('2001-03-22', dtype='M8[D]').astype('i8'), + (2000 - 1970)*365 + (2000 - 1972)//4 + 366 + 31 + 28 + 21) + + def test_days_to_pydate(self): + assert_equal(np.array('1599', dtype='M8[D]').astype('O'), + datetime.date(1599, 1, 1)) + assert_equal(np.array('1600', dtype='M8[D]').astype('O'), + datetime.date(1600, 1, 1)) + assert_equal(np.array('1601', dtype='M8[D]').astype('O'), + datetime.date(1601, 1, 1)) + assert_equal(np.array('1900', dtype='M8[D]').astype('O'), + datetime.date(1900, 1, 1)) + assert_equal(np.array('1901', dtype='M8[D]').astype('O'), + datetime.date(1901, 1, 1)) + assert_equal(np.array('2000', dtype='M8[D]').astype('O'), + datetime.date(2000, 1, 1)) + assert_equal(np.array('2001', dtype='M8[D]').astype('O'), + datetime.date(2001, 1, 1)) + assert_equal(np.array('1600-02-29', dtype='M8[D]').astype('O'), + datetime.date(1600, 2, 29)) + assert_equal(np.array('1600-03-01', dtype='M8[D]').astype('O'), + datetime.date(1600, 3, 1)) + assert_equal(np.array('2001-03-22', dtype='M8[D]').astype('O'), + datetime.date(2001, 3, 22)) + + def test_dtype_comparison(self): + assert_(not (np.dtype('M8[us]') == np.dtype('M8[ms]'))) + assert_(np.dtype('M8[us]') != np.dtype('M8[ms]')) + assert_(np.dtype('M8[2D]') != np.dtype('M8[D]')) + assert_(np.dtype('M8[D]') != np.dtype('M8[2D]')) + + def test_pydatetime_creation(self): + a = np.array(['1960-03-12', datetime.date(1960, 3, 12)], dtype='M8[D]') + assert_equal(a[0], a[1]) + a = np.array(['1999-12-31', datetime.date(1999, 12, 31)], dtype='M8[D]') + assert_equal(a[0], a[1]) + a = np.array(['2000-01-01', datetime.date(2000, 1, 1)], dtype='M8[D]') + assert_equal(a[0], a[1]) + # Will fail if the date changes during the exact right moment + a = np.array(['today', datetime.date.today()], dtype='M8[D]') + assert_equal(a[0], a[1]) + # datetime.datetime.now() returns local time, not UTC + #a = np.array(['now', datetime.datetime.now()], dtype='M8[s]') + #assert_equal(a[0], a[1]) + + # we can give a datetime.date time units + assert_equal(np.array(datetime.date(1960, 3, 12), dtype='M8[s]'), + np.array(np.datetime64('1960-03-12T00:00:00'))) + + def test_datetime_string_conversion(self): + a = ['2011-03-16', '1920-01-01', '2013-05-19'] + str_a = np.array(a, dtype='S') + uni_a = np.array(a, dtype='U') + dt_a = np.array(a, dtype='M') + + # String to datetime + assert_equal(dt_a, str_a.astype('M')) + assert_equal(dt_a.dtype, str_a.astype('M').dtype) + dt_b = np.empty_like(dt_a) + dt_b[...] = str_a + assert_equal(dt_a, dt_b) + + # Datetime to string + assert_equal(str_a, dt_a.astype('S0')) + str_b = np.empty_like(str_a) + str_b[...] = dt_a + assert_equal(str_a, str_b) + + # Unicode to datetime + assert_equal(dt_a, uni_a.astype('M')) + assert_equal(dt_a.dtype, uni_a.astype('M').dtype) + dt_b = np.empty_like(dt_a) + dt_b[...] = uni_a + assert_equal(dt_a, dt_b) + + # Datetime to unicode + assert_equal(uni_a, dt_a.astype('U')) + uni_b = np.empty_like(uni_a) + uni_b[...] = dt_a + assert_equal(uni_a, uni_b) + + # Datetime to long string - gh-9712 + assert_equal(str_a, dt_a.astype((np.string_, 128))) + str_b = np.empty(str_a.shape, dtype=(np.string_, 128)) + str_b[...] = dt_a + assert_equal(str_a, str_b) + + def test_datetime_array_str(self): + a = np.array(['2011-03-16', '1920-01-01', '2013-05-19'], dtype='M') + assert_equal(str(a), "['2011-03-16' '1920-01-01' '2013-05-19']") + + a = np.array(['2011-03-16T13:55', '1920-01-01T03:12'], dtype='M') + assert_equal(np.array2string(a, separator=', ', + formatter={'datetime': lambda x: + "'%s'" % np.datetime_as_string(x, timezone='UTC')}), + "['2011-03-16T13:55Z', '1920-01-01T03:12Z']") + + # Check that one NaT doesn't corrupt subsequent entries + a = np.array(['2010', 'NaT', '2030']).astype('M') + assert_equal(str(a), "['2010' 'NaT' '2030']") + + def test_timedelta_array_str(self): + a = np.array([-1, 0, 100], dtype='m') + assert_equal(str(a), "[ -1 0 100]") + a = np.array(['NaT', 'NaT'], dtype='m') + assert_equal(str(a), "['NaT' 'NaT']") + # Check right-alignment with NaTs + a = np.array([-1, 'NaT', 0], dtype='m') + assert_equal(str(a), "[ -1 'NaT' 0]") + a = np.array([-1, 'NaT', 1234567], dtype='m') + assert_equal(str(a), "[ -1 'NaT' 1234567]") + + # Test with other byteorder: + a = np.array([-1, 'NaT', 1234567], dtype='>m') + assert_equal(str(a), "[ -1 'NaT' 1234567]") + a = np.array([-1, 'NaT', 1234567], dtype=''\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'us'\np6\n" + \ + b"I1\nI1\nI1\ntp7\ntp8\ntp9\nb." + assert_equal(pickle.loads(pkl), np.dtype('>M8[us]')) + + def test_setstate(self): + "Verify that datetime dtype __setstate__ can handle bad arguments" + dt = np.dtype('>M8[us]') + assert_raises(ValueError, dt.__setstate__, (4, '>', None, None, None, -1, -1, 0, 1)) + assert_(dt.__reduce__()[2] == np.dtype('>M8[us]').__reduce__()[2]) + assert_raises(TypeError, dt.__setstate__, (4, '>', None, None, None, -1, -1, 0, ({}, 'xxx'))) + assert_(dt.__reduce__()[2] == np.dtype('>M8[us]').__reduce__()[2]) + + def test_dtype_promotion(self): + # datetime datetime computes the metadata gcd + # timedelta timedelta computes the metadata gcd + for mM in ['m', 'M']: + assert_equal( + np.promote_types(np.dtype(mM+'8[2Y]'), np.dtype(mM+'8[2Y]')), + np.dtype(mM+'8[2Y]')) + assert_equal( + np.promote_types(np.dtype(mM+'8[12Y]'), np.dtype(mM+'8[15Y]')), + np.dtype(mM+'8[3Y]')) + assert_equal( + np.promote_types(np.dtype(mM+'8[62M]'), np.dtype(mM+'8[24M]')), + np.dtype(mM+'8[2M]')) + assert_equal( + np.promote_types(np.dtype(mM+'8[1W]'), np.dtype(mM+'8[2D]')), + np.dtype(mM+'8[1D]')) + assert_equal( + np.promote_types(np.dtype(mM+'8[W]'), np.dtype(mM+'8[13s]')), + np.dtype(mM+'8[s]')) + assert_equal( + np.promote_types(np.dtype(mM+'8[13W]'), np.dtype(mM+'8[49s]')), + np.dtype(mM+'8[7s]')) + # timedelta timedelta raises when there is no reasonable gcd + assert_raises(TypeError, np.promote_types, + np.dtype('m8[Y]'), np.dtype('m8[D]')) + assert_raises(TypeError, np.promote_types, + np.dtype('m8[M]'), np.dtype('m8[W]')) + # timedelta timedelta may overflow with big unit ranges + assert_raises(OverflowError, np.promote_types, + np.dtype('m8[W]'), np.dtype('m8[fs]')) + assert_raises(OverflowError, np.promote_types, + np.dtype('m8[s]'), np.dtype('m8[as]')) + + def test_cast_overflow(self): + # gh-4486 + def cast(): + numpy.datetime64("1971-01-01 00:00:00.000000000000000").astype("= self.B)) + assert_(np.all(self.A <= self.B)) + assert_(not np.any(self.A > self.B)) + assert_(not np.any(self.A < self.B)) + assert_(not np.any(self.A != self.B)) + +class TestChar(object): + def setup(self): + self.A = np.array('abc1', dtype='c').view(np.chararray) + + def test_it(self): + assert_equal(self.A.shape, (4,)) + assert_equal(self.A.upper()[:2].tobytes(), b'AB') + +class TestComparisons(object): + def setup(self): + self.A = np.array([['abc', '123'], + ['789', 'xyz']]).view(np.chararray) + self.B = np.array([['efg', '123 '], + ['051', 'tuv']]).view(np.chararray) + + def test_not_equal(self): + assert_array_equal((self.A != self.B), [[True, False], [True, True]]) + + def test_equal(self): + assert_array_equal((self.A == self.B), [[False, True], [False, False]]) + + def test_greater_equal(self): + assert_array_equal((self.A >= self.B), [[False, True], [True, True]]) + + def test_less_equal(self): + assert_array_equal((self.A <= self.B), [[True, True], [False, False]]) + + def test_greater(self): + assert_array_equal((self.A > self.B), [[False, False], [True, True]]) + + def test_less(self): + assert_array_equal((self.A < self.B), [[True, False], [False, False]]) + +class TestComparisonsMixed1(TestComparisons): + """Ticket #1276""" + + def setup(self): + TestComparisons.setup(self) + self.B = np.array([['efg', '123 '], + ['051', 'tuv']], np.unicode_).view(np.chararray) + +class TestComparisonsMixed2(TestComparisons): + """Ticket #1276""" + + def setup(self): + TestComparisons.setup(self) + self.A = np.array([['abc', '123'], + ['789', 'xyz']], np.unicode_).view(np.chararray) + +class TestInformation(object): + def setup(self): + self.A = np.array([[' abc ', ''], + ['12345', 'MixedCase'], + ['123 \t 345 \0 ', 'UPPER']]).view(np.chararray) + self.B = np.array([[u' \u03a3 ', u''], + [u'12345', u'MixedCase'], + [u'123 \t 345 \0 ', u'UPPER']]).view(np.chararray) + + def test_len(self): + assert_(issubclass(np.char.str_len(self.A).dtype.type, np.integer)) + assert_array_equal(np.char.str_len(self.A), [[5, 0], [5, 9], [12, 5]]) + assert_array_equal(np.char.str_len(self.B), [[3, 0], [5, 9], [12, 5]]) + + def test_count(self): + assert_(issubclass(self.A.count('').dtype.type, np.integer)) + assert_array_equal(self.A.count('a'), [[1, 0], [0, 1], [0, 0]]) + assert_array_equal(self.A.count('123'), [[0, 0], [1, 0], [1, 0]]) + # Python doesn't seem to like counting NULL characters + # assert_array_equal(self.A.count('\0'), [[0, 0], [0, 0], [1, 0]]) + assert_array_equal(self.A.count('a', 0, 2), [[1, 0], [0, 0], [0, 0]]) + assert_array_equal(self.B.count('a'), [[0, 0], [0, 1], [0, 0]]) + assert_array_equal(self.B.count('123'), [[0, 0], [1, 0], [1, 0]]) + # assert_array_equal(self.B.count('\0'), [[0, 0], [0, 0], [1, 0]]) + + def test_endswith(self): + assert_(issubclass(self.A.endswith('').dtype.type, np.bool_)) + assert_array_equal(self.A.endswith(' '), [[1, 0], [0, 0], [1, 0]]) + assert_array_equal(self.A.endswith('3', 0, 3), [[0, 0], [1, 0], [1, 0]]) + + def fail(): + self.A.endswith('3', 'fdjk') + + assert_raises(TypeError, fail) + + def test_find(self): + assert_(issubclass(self.A.find('a').dtype.type, np.integer)) + assert_array_equal(self.A.find('a'), [[1, -1], [-1, 6], [-1, -1]]) + assert_array_equal(self.A.find('3'), [[-1, -1], [2, -1], [2, -1]]) + assert_array_equal(self.A.find('a', 0, 2), [[1, -1], [-1, -1], [-1, -1]]) + assert_array_equal(self.A.find(['1', 'P']), [[-1, -1], [0, -1], [0, 1]]) + + def test_index(self): + + def fail(): + self.A.index('a') + + assert_raises(ValueError, fail) + assert_(np.char.index('abcba', 'b') == 1) + assert_(issubclass(np.char.index('abcba', 'b').dtype.type, np.integer)) + + def test_isalnum(self): + assert_(issubclass(self.A.isalnum().dtype.type, np.bool_)) + assert_array_equal(self.A.isalnum(), [[False, False], [True, True], [False, True]]) + + def test_isalpha(self): + assert_(issubclass(self.A.isalpha().dtype.type, np.bool_)) + assert_array_equal(self.A.isalpha(), [[False, False], [False, True], [False, True]]) + + def test_isdigit(self): + assert_(issubclass(self.A.isdigit().dtype.type, np.bool_)) + assert_array_equal(self.A.isdigit(), [[False, False], [True, False], [False, False]]) + + def test_islower(self): + assert_(issubclass(self.A.islower().dtype.type, np.bool_)) + assert_array_equal(self.A.islower(), [[True, False], [False, False], [False, False]]) + + def test_isspace(self): + assert_(issubclass(self.A.isspace().dtype.type, np.bool_)) + assert_array_equal(self.A.isspace(), [[False, False], [False, False], [False, False]]) + + def test_istitle(self): + assert_(issubclass(self.A.istitle().dtype.type, np.bool_)) + assert_array_equal(self.A.istitle(), [[False, False], [False, False], [False, False]]) + + def test_isupper(self): + assert_(issubclass(self.A.isupper().dtype.type, np.bool_)) + assert_array_equal(self.A.isupper(), [[False, False], [False, False], [False, True]]) + + def test_rfind(self): + assert_(issubclass(self.A.rfind('a').dtype.type, np.integer)) + assert_array_equal(self.A.rfind('a'), [[1, -1], [-1, 6], [-1, -1]]) + assert_array_equal(self.A.rfind('3'), [[-1, -1], [2, -1], [6, -1]]) + assert_array_equal(self.A.rfind('a', 0, 2), [[1, -1], [-1, -1], [-1, -1]]) + assert_array_equal(self.A.rfind(['1', 'P']), [[-1, -1], [0, -1], [0, 2]]) + + def test_rindex(self): + + def fail(): + self.A.rindex('a') + + assert_raises(ValueError, fail) + assert_(np.char.rindex('abcba', 'b') == 3) + assert_(issubclass(np.char.rindex('abcba', 'b').dtype.type, np.integer)) + + def test_startswith(self): + assert_(issubclass(self.A.startswith('').dtype.type, np.bool_)) + assert_array_equal(self.A.startswith(' '), [[1, 0], [0, 0], [0, 0]]) + assert_array_equal(self.A.startswith('1', 0, 3), [[0, 0], [1, 0], [1, 0]]) + + def fail(): + self.A.startswith('3', 'fdjk') + + assert_raises(TypeError, fail) + + +class TestMethods(object): + def setup(self): + self.A = np.array([[' abc ', ''], + ['12345', 'MixedCase'], + ['123 \t 345 \0 ', 'UPPER']], + dtype='S').view(np.chararray) + self.B = np.array([[u' \u03a3 ', u''], + [u'12345', u'MixedCase'], + [u'123 \t 345 \0 ', u'UPPER']]).view(np.chararray) + + def test_capitalize(self): + tgt = [[b' abc ', b''], + [b'12345', b'Mixedcase'], + [b'123 \t 345 \0 ', b'Upper']] + assert_(issubclass(self.A.capitalize().dtype.type, np.string_)) + assert_array_equal(self.A.capitalize(), tgt) + + tgt = [[u' \u03c3 ', ''], + ['12345', 'Mixedcase'], + ['123 \t 345 \0 ', 'Upper']] + assert_(issubclass(self.B.capitalize().dtype.type, np.unicode_)) + assert_array_equal(self.B.capitalize(), tgt) + + def test_center(self): + assert_(issubclass(self.A.center(10).dtype.type, np.string_)) + C = self.A.center([10, 20]) + assert_array_equal(np.char.str_len(C), [[10, 20], [10, 20], [12, 20]]) + + C = self.A.center(20, b'#') + assert_(np.all(C.startswith(b'#'))) + assert_(np.all(C.endswith(b'#'))) + + C = np.char.center(b'FOO', [[10, 20], [15, 8]]) + tgt = [[b' FOO ', b' FOO '], + [b' FOO ', b' FOO ']] + assert_(issubclass(C.dtype.type, np.string_)) + assert_array_equal(C, tgt) + + def test_decode(self): + if sys.version_info[0] >= 3: + A = np.char.array([b'\\u03a3']) + assert_(A.decode('unicode-escape')[0] == '\u03a3') + else: + with suppress_warnings() as sup: + if sys.py3kwarning: + sup.filter(DeprecationWarning, "'hex_codec'") + A = np.char.array(['736563726574206d657373616765']) + assert_(A.decode('hex_codec')[0] == 'secret message') + + def test_encode(self): + B = self.B.encode('unicode_escape') + assert_(B[0][0] == str(' \\u03a3 ').encode('latin1')) + + def test_expandtabs(self): + T = self.A.expandtabs() + assert_(T[2, 0] == b'123 345 \0') + + def test_join(self): + if sys.version_info[0] >= 3: + # NOTE: list(b'123') == [49, 50, 51] + # so that b','.join(b'123') results to an error on Py3 + A0 = self.A.decode('ascii') + else: + A0 = self.A + + A = np.char.join([',', '#'], A0) + if sys.version_info[0] >= 3: + assert_(issubclass(A.dtype.type, np.unicode_)) + else: + assert_(issubclass(A.dtype.type, np.string_)) + tgt = np.array([[' ,a,b,c, ', ''], + ['1,2,3,4,5', 'M#i#x#e#d#C#a#s#e'], + ['1,2,3, ,\t, ,3,4,5, ,\x00, ', 'U#P#P#E#R']]) + assert_array_equal(np.char.join([',', '#'], A0), tgt) + + def test_ljust(self): + assert_(issubclass(self.A.ljust(10).dtype.type, np.string_)) + + C = self.A.ljust([10, 20]) + assert_array_equal(np.char.str_len(C), [[10, 20], [10, 20], [12, 20]]) + + C = self.A.ljust(20, b'#') + assert_array_equal(C.startswith(b'#'), [ + [False, True], [False, False], [False, False]]) + assert_(np.all(C.endswith(b'#'))) + + C = np.char.ljust(b'FOO', [[10, 20], [15, 8]]) + tgt = [[b'FOO ', b'FOO '], + [b'FOO ', b'FOO ']] + assert_(issubclass(C.dtype.type, np.string_)) + assert_array_equal(C, tgt) + + def test_lower(self): + tgt = [[b' abc ', b''], + [b'12345', b'mixedcase'], + [b'123 \t 345 \0 ', b'upper']] + assert_(issubclass(self.A.lower().dtype.type, np.string_)) + assert_array_equal(self.A.lower(), tgt) + + tgt = [[u' \u03c3 ', u''], + [u'12345', u'mixedcase'], + [u'123 \t 345 \0 ', u'upper']] + assert_(issubclass(self.B.lower().dtype.type, np.unicode_)) + assert_array_equal(self.B.lower(), tgt) + + def test_lstrip(self): + tgt = [[b'abc ', b''], + [b'12345', b'MixedCase'], + [b'123 \t 345 \0 ', b'UPPER']] + assert_(issubclass(self.A.lstrip().dtype.type, np.string_)) + assert_array_equal(self.A.lstrip(), tgt) + + tgt = [[b' abc', b''], + [b'2345', b'ixedCase'], + [b'23 \t 345 \x00', b'UPPER']] + assert_array_equal(self.A.lstrip([b'1', b'M']), tgt) + + tgt = [[u'\u03a3 ', ''], + ['12345', 'MixedCase'], + ['123 \t 345 \0 ', 'UPPER']] + assert_(issubclass(self.B.lstrip().dtype.type, np.unicode_)) + assert_array_equal(self.B.lstrip(), tgt) + + def test_partition(self): + P = self.A.partition([b'3', b'M']) + tgt = [[(b' abc ', b'', b''), (b'', b'', b'')], + [(b'12', b'3', b'45'), (b'', b'M', b'ixedCase')], + [(b'12', b'3', b' \t 345 \0 '), (b'UPPER', b'', b'')]] + assert_(issubclass(P.dtype.type, np.string_)) + assert_array_equal(P, tgt) + + def test_replace(self): + R = self.A.replace([b'3', b'a'], + [b'##########', b'@']) + tgt = [[b' abc ', b''], + [b'12##########45', b'MixedC@se'], + [b'12########## \t ##########45 \x00', b'UPPER']] + assert_(issubclass(R.dtype.type, np.string_)) + assert_array_equal(R, tgt) + + if sys.version_info[0] < 3: + # NOTE: b'abc'.replace(b'a', 'b') is not allowed on Py3 + R = self.A.replace(b'a', u'\u03a3') + tgt = [[u' \u03a3bc ', ''], + ['12345', u'MixedC\u03a3se'], + ['123 \t 345 \x00', 'UPPER']] + assert_(issubclass(R.dtype.type, np.unicode_)) + assert_array_equal(R, tgt) + + def test_rjust(self): + assert_(issubclass(self.A.rjust(10).dtype.type, np.string_)) + + C = self.A.rjust([10, 20]) + assert_array_equal(np.char.str_len(C), [[10, 20], [10, 20], [12, 20]]) + + C = self.A.rjust(20, b'#') + assert_(np.all(C.startswith(b'#'))) + assert_array_equal(C.endswith(b'#'), + [[False, True], [False, False], [False, False]]) + + C = np.char.rjust(b'FOO', [[10, 20], [15, 8]]) + tgt = [[b' FOO', b' FOO'], + [b' FOO', b' FOO']] + assert_(issubclass(C.dtype.type, np.string_)) + assert_array_equal(C, tgt) + + def test_rpartition(self): + P = self.A.rpartition([b'3', b'M']) + tgt = [[(b'', b'', b' abc '), (b'', b'', b'')], + [(b'12', b'3', b'45'), (b'', b'M', b'ixedCase')], + [(b'123 \t ', b'3', b'45 \0 '), (b'', b'', b'UPPER')]] + assert_(issubclass(P.dtype.type, np.string_)) + assert_array_equal(P, tgt) + + def test_rsplit(self): + A = self.A.rsplit(b'3') + tgt = [[[b' abc '], [b'']], + [[b'12', b'45'], [b'MixedCase']], + [[b'12', b' \t ', b'45 \x00 '], [b'UPPER']]] + assert_(issubclass(A.dtype.type, np.object_)) + assert_equal(A.tolist(), tgt) + + def test_rstrip(self): + assert_(issubclass(self.A.rstrip().dtype.type, np.string_)) + + tgt = [[b' abc', b''], + [b'12345', b'MixedCase'], + [b'123 \t 345', b'UPPER']] + assert_array_equal(self.A.rstrip(), tgt) + + tgt = [[b' abc ', b''], + [b'1234', b'MixedCase'], + [b'123 \t 345 \x00', b'UPP'] + ] + assert_array_equal(self.A.rstrip([b'5', b'ER']), tgt) + + tgt = [[u' \u03a3', ''], + ['12345', 'MixedCase'], + ['123 \t 345', 'UPPER']] + assert_(issubclass(self.B.rstrip().dtype.type, np.unicode_)) + assert_array_equal(self.B.rstrip(), tgt) + + def test_strip(self): + tgt = [[b'abc', b''], + [b'12345', b'MixedCase'], + [b'123 \t 345', b'UPPER']] + assert_(issubclass(self.A.strip().dtype.type, np.string_)) + assert_array_equal(self.A.strip(), tgt) + + tgt = [[b' abc ', b''], + [b'234', b'ixedCas'], + [b'23 \t 345 \x00', b'UPP']] + assert_array_equal(self.A.strip([b'15', b'EReM']), tgt) + + tgt = [[u'\u03a3', ''], + ['12345', 'MixedCase'], + ['123 \t 345', 'UPPER']] + assert_(issubclass(self.B.strip().dtype.type, np.unicode_)) + assert_array_equal(self.B.strip(), tgt) + + def test_split(self): + A = self.A.split(b'3') + tgt = [ + [[b' abc '], [b'']], + [[b'12', b'45'], [b'MixedCase']], + [[b'12', b' \t ', b'45 \x00 '], [b'UPPER']]] + assert_(issubclass(A.dtype.type, np.object_)) + assert_equal(A.tolist(), tgt) + + def test_splitlines(self): + A = np.char.array(['abc\nfds\nwer']).splitlines() + assert_(issubclass(A.dtype.type, np.object_)) + assert_(A.shape == (1,)) + assert_(len(A[0]) == 3) + + def test_swapcase(self): + tgt = [[b' ABC ', b''], + [b'12345', b'mIXEDcASE'], + [b'123 \t 345 \0 ', b'upper']] + assert_(issubclass(self.A.swapcase().dtype.type, np.string_)) + assert_array_equal(self.A.swapcase(), tgt) + + tgt = [[u' \u03c3 ', u''], + [u'12345', u'mIXEDcASE'], + [u'123 \t 345 \0 ', u'upper']] + assert_(issubclass(self.B.swapcase().dtype.type, np.unicode_)) + assert_array_equal(self.B.swapcase(), tgt) + + def test_title(self): + tgt = [[b' Abc ', b''], + [b'12345', b'Mixedcase'], + [b'123 \t 345 \0 ', b'Upper']] + assert_(issubclass(self.A.title().dtype.type, np.string_)) + assert_array_equal(self.A.title(), tgt) + + tgt = [[u' \u03a3 ', u''], + [u'12345', u'Mixedcase'], + [u'123 \t 345 \0 ', u'Upper']] + assert_(issubclass(self.B.title().dtype.type, np.unicode_)) + assert_array_equal(self.B.title(), tgt) + + def test_upper(self): + tgt = [[b' ABC ', b''], + [b'12345', b'MIXEDCASE'], + [b'123 \t 345 \0 ', b'UPPER']] + assert_(issubclass(self.A.upper().dtype.type, np.string_)) + assert_array_equal(self.A.upper(), tgt) + + tgt = [[u' \u03a3 ', u''], + [u'12345', u'MIXEDCASE'], + [u'123 \t 345 \0 ', u'UPPER']] + assert_(issubclass(self.B.upper().dtype.type, np.unicode_)) + assert_array_equal(self.B.upper(), tgt) + + def test_isnumeric(self): + + def fail(): + self.A.isnumeric() + + assert_raises(TypeError, fail) + assert_(issubclass(self.B.isnumeric().dtype.type, np.bool_)) + assert_array_equal(self.B.isnumeric(), [ + [False, False], [True, False], [False, False]]) + + def test_isdecimal(self): + + def fail(): + self.A.isdecimal() + + assert_raises(TypeError, fail) + assert_(issubclass(self.B.isdecimal().dtype.type, np.bool_)) + assert_array_equal(self.B.isdecimal(), [ + [False, False], [True, False], [False, False]]) + + +class TestOperations(object): + def setup(self): + self.A = np.array([['abc', '123'], + ['789', 'xyz']]).view(np.chararray) + self.B = np.array([['efg', '456'], + ['051', 'tuv']]).view(np.chararray) + + def test_add(self): + AB = np.array([['abcefg', '123456'], + ['789051', 'xyztuv']]).view(np.chararray) + assert_array_equal(AB, (self.A + self.B)) + assert_(len((self.A + self.B)[0][0]) == 6) + + def test_radd(self): + QA = np.array([['qabc', 'q123'], + ['q789', 'qxyz']]).view(np.chararray) + assert_array_equal(QA, ('q' + self.A)) + + def test_mul(self): + A = self.A + for r in (2, 3, 5, 7, 197): + Ar = np.array([[A[0, 0]*r, A[0, 1]*r], + [A[1, 0]*r, A[1, 1]*r]]).view(np.chararray) + + assert_array_equal(Ar, (self.A * r)) + + for ob in [object(), 'qrs']: + try: + A * ob + except ValueError: + pass + else: + self.fail("chararray can only be multiplied by integers") + + def test_rmul(self): + A = self.A + for r in (2, 3, 5, 7, 197): + Ar = np.array([[A[0, 0]*r, A[0, 1]*r], + [A[1, 0]*r, A[1, 1]*r]]).view(np.chararray) + assert_array_equal(Ar, (r * self.A)) + + for ob in [object(), 'qrs']: + try: + ob * A + except ValueError: + pass + else: + self.fail("chararray can only be multiplied by integers") + + def test_mod(self): + """Ticket #856""" + F = np.array([['%d', '%f'], ['%s', '%r']]).view(np.chararray) + C = np.array([[3, 7], [19, 1]]) + FC = np.array([['3', '7.000000'], + ['19', '1']]).view(np.chararray) + assert_array_equal(FC, F % C) + + A = np.array([['%.3f', '%d'], ['%s', '%r']]).view(np.chararray) + A1 = np.array([['1.000', '1'], ['1', '1']]).view(np.chararray) + assert_array_equal(A1, (A % 1)) + + A2 = np.array([['1.000', '2'], ['3', '4']]).view(np.chararray) + assert_array_equal(A2, (A % [[1, 2], [3, 4]])) + + def test_rmod(self): + assert_(("%s" % self.A) == str(self.A)) + assert_(("%r" % self.A) == repr(self.A)) + + for ob in [42, object()]: + try: + ob % self.A + except TypeError: + pass + else: + self.fail("chararray __rmod__ should fail with " + "non-string objects") + + def test_slice(self): + """Regression test for https://github.com/numpy/numpy/issues/5982""" + + arr = np.array([['abc ', 'def '], ['geh ', 'ijk ']], + dtype='S4').view(np.chararray) + sl1 = arr[:] + assert_array_equal(sl1, arr) + assert_(sl1.base is arr) + assert_(sl1.base.base is arr.base) + + sl2 = arr[:, :] + assert_array_equal(sl2, arr) + assert_(sl2.base is arr) + assert_(sl2.base.base is arr.base) + + assert_(arr[0, 0] == b'abc') + + +def test_empty_indexing(): + """Regression test for ticket 1948.""" + # Check that indexing a chararray with an empty list/array returns an + # empty chararray instead of a chararray with a single empty string in it. + s = np.chararray((4,)) + assert_(s[[]].size == 0) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py new file mode 100644 index 0000000..fe0c7cc --- /dev/null +++ b/numpy/core/tests/test_deprecations.py @@ -0,0 +1,485 @@ +""" +Tests related to deprecation warnings. Also a convenient place +to document how deprecations should eventually be turned into errors. + +""" +from __future__ import division, absolute_import, print_function + +import datetime +import sys +import operator +import warnings + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_raises, assert_warns, assert_no_warnings, + assert_array_equal, assert_, dec) + +try: + import pytz + _has_pytz = True +except ImportError: + _has_pytz = False + + +class _DeprecationTestCase(object): + # Just as warning: warnings uses re.match, so the start of this message + # must match. + message = '' + warning_cls = DeprecationWarning + + def setup(self): + self.warn_ctx = warnings.catch_warnings(record=True) + self.log = self.warn_ctx.__enter__() + + # Do *not* ignore other DeprecationWarnings. Ignoring warnings + # can give very confusing results because of + # http://bugs.python.org/issue4180 and it is probably simplest to + # try to keep the tests cleanly giving only the right warning type. + # (While checking them set to "error" those are ignored anyway) + # We still have them show up, because otherwise they would be raised + warnings.filterwarnings("always", category=self.warning_cls) + warnings.filterwarnings("always", message=self.message, + category=self.warning_cls) + + def teardown(self): + self.warn_ctx.__exit__() + + def assert_deprecated(self, function, num=1, ignore_others=False, + function_fails=False, + exceptions=np._NoValue, + args=(), kwargs={}): + """Test if DeprecationWarnings are given and raised. + + This first checks if the function when called gives `num` + DeprecationWarnings, after that it tries to raise these + DeprecationWarnings and compares them with `exceptions`. + The exceptions can be different for cases where this code path + is simply not anticipated and the exception is replaced. + + Parameters + ---------- + function : callable + The function to test + num : int + Number of DeprecationWarnings to expect. This should normally be 1. + ignore_others : bool + Whether warnings of the wrong type should be ignored (note that + the message is not checked) + function_fails : bool + If the function would normally fail, setting this will check for + warnings inside a try/except block. + exceptions : Exception or tuple of Exceptions + Exception to expect when turning the warnings into an error. + The default checks for DeprecationWarnings. If exceptions is + empty the function is expected to run successfully. + args : tuple + Arguments for `function` + kwargs : dict + Keyword arguments for `function` + """ + # reset the log + self.log[:] = [] + + if exceptions is np._NoValue: + exceptions = (self.warning_cls,) + + try: + function(*args, **kwargs) + except (Exception if function_fails else tuple()): + pass + + # just in case, clear the registry + num_found = 0 + for warning in self.log: + if warning.category is self.warning_cls: + num_found += 1 + elif not ignore_others: + raise AssertionError( + "expected %s but got: %s" % + (self.warning_cls.__name__, warning.category)) + if num is not None and num_found != num: + msg = "%i warnings found but %i expected." % (len(self.log), num) + lst = [str(w.category) for w in self.log] + raise AssertionError("\n".join([msg] + lst)) + + with warnings.catch_warnings(): + warnings.filterwarnings("error", message=self.message, + category=self.warning_cls) + try: + function(*args, **kwargs) + if exceptions != tuple(): + raise AssertionError( + "No error raised during function call") + except exceptions: + if exceptions == tuple(): + raise AssertionError( + "Error raised during function call") + + def assert_not_deprecated(self, function, args=(), kwargs={}): + """Test that warnings are not raised. + + This is just a shorthand for: + + self.assert_deprecated(function, num=0, ignore_others=True, + exceptions=tuple(), args=args, kwargs=kwargs) + """ + self.assert_deprecated(function, num=0, ignore_others=True, + exceptions=tuple(), args=args, kwargs=kwargs) + + +class _VisibleDeprecationTestCase(_DeprecationTestCase): + warning_cls = np.VisibleDeprecationWarning + + +class TestRankDeprecation(_DeprecationTestCase): + """Test that np.rank is deprecated. The function should simply be + removed. The VisibleDeprecationWarning may become unnecessary. + """ + + def test(self): + a = np.arange(10) + assert_warns(np.VisibleDeprecationWarning, np.rank, a) + + +class TestComparisonDeprecations(_DeprecationTestCase): + """This tests the deprecation, for non-element-wise comparison logic. + This used to mean that when an error occurred during element-wise comparison + (i.e. broadcasting) NotImplemented was returned, but also in the comparison + itself, False was given instead of the error. + + Also test FutureWarning for the None comparison. + """ + + message = "elementwise.* comparison failed; .*" + + def test_normal_types(self): + for op in (operator.eq, operator.ne): + # Broadcasting errors: + self.assert_deprecated(op, args=(np.zeros(3), [])) + a = np.zeros(3, dtype='i,i') + # (warning is issued a couple of times here) + self.assert_deprecated(op, args=(a, a[:-1]), num=None) + + # Element comparison error (numpy array can't be compared). + a = np.array([1, np.array([1,2,3])], dtype=object) + b = np.array([1, np.array([1,2,3])], dtype=object) + self.assert_deprecated(op, args=(a, b), num=None) + + def test_string(self): + # For two string arrays, strings always raised the broadcasting error: + a = np.array(['a', 'b']) + b = np.array(['a', 'b', 'c']) + assert_raises(ValueError, lambda x, y: x == y, a, b) + + # The empty list is not cast to string, as this is only to document + # that fact (it likely should be changed). This means that the + # following works (and returns False) due to dtype mismatch: + a == [] + + def test_void_dtype_equality_failures(self): + class NotArray(object): + def __array__(self): + raise TypeError + + # Needed so Python 3 does not raise DeprecationWarning twice. + def __ne__(self, other): + return NotImplemented + + self.assert_deprecated(lambda: np.arange(2) == NotArray()) + self.assert_deprecated(lambda: np.arange(2) != NotArray()) + + struct1 = np.zeros(2, dtype="i4,i4") + struct2 = np.zeros(2, dtype="i4,i4,i4") + + assert_warns(FutureWarning, lambda: struct1 == 1) + assert_warns(FutureWarning, lambda: struct1 == struct2) + assert_warns(FutureWarning, lambda: struct1 != 1) + assert_warns(FutureWarning, lambda: struct1 != struct2) + + def test_array_richcompare_legacy_weirdness(self): + # It doesn't really work to use assert_deprecated here, b/c part of + # the point of assert_deprecated is to check that when warnings are + # set to "error" mode then the error is propagated -- which is good! + # But here we are testing a bunch of code that is deprecated *because* + # it has the habit of swallowing up errors and converting them into + # different warnings. So assert_warns will have to be sufficient. + assert_warns(FutureWarning, lambda: np.arange(2) == "a") + assert_warns(FutureWarning, lambda: np.arange(2) != "a") + # No warning for scalar comparisons + with warnings.catch_warnings(): + warnings.filterwarnings("error") + assert_(not (np.array(0) == "a")) + assert_(np.array(0) != "a") + assert_(not (np.int16(0) == "a")) + assert_(np.int16(0) != "a") + + for arg1 in [np.asarray(0), np.int16(0)]: + struct = np.zeros(2, dtype="i4,i4") + for arg2 in [struct, "a"]: + for f in [operator.lt, operator.le, operator.gt, operator.ge]: + if sys.version_info[0] >= 3: + # py3 + with warnings.catch_warnings() as l: + warnings.filterwarnings("always") + assert_raises(TypeError, f, arg1, arg2) + assert_(not l) + else: + # py2 + assert_warns(DeprecationWarning, f, arg1, arg2) + + +class TestDatetime64Timezone(_DeprecationTestCase): + """Parsing of datetime64 with timezones deprecated in 1.11.0, because + datetime64 is now timezone naive rather than UTC only. + + It will be quite a while before we can remove this, because, at the very + least, a lot of existing code uses the 'Z' modifier to avoid conversion + from local time to UTC, even if otherwise it handles time in a timezone + naive fashion. + """ + def test_string(self): + self.assert_deprecated(np.datetime64, args=('2000-01-01T00+01',)) + self.assert_deprecated(np.datetime64, args=('2000-01-01T00Z',)) + + @dec.skipif(not _has_pytz, "The pytz module is not available.") + def test_datetime(self): + tz = pytz.timezone('US/Eastern') + dt = datetime.datetime(2000, 1, 1, 0, 0, tzinfo=tz) + self.assert_deprecated(np.datetime64, args=(dt,)) + + +class TestNonCContiguousViewDeprecation(_DeprecationTestCase): + """View of non-C-contiguous arrays deprecated in 1.11.0. + + The deprecation will not be raised for arrays that are both C and F + contiguous, as C contiguous is dominant. There are more such arrays + with relaxed stride checking than without so the deprecation is not + as visible with relaxed stride checking in force. + """ + + def test_fortran_contiguous(self): + self.assert_deprecated(np.ones((2,2)).T.view, args=(complex,)) + self.assert_deprecated(np.ones((2,2)).T.view, args=(np.int8,)) + + +class TestInvalidOrderParameterInputForFlattenArrayDeprecation(_DeprecationTestCase): + """Invalid arguments to the ORDER parameter in array.flatten() should not be + allowed and should raise an error. However, in the interests of not breaking + code that may inadvertently pass invalid arguments to this parameter, a + DeprecationWarning will be issued instead for the time being to give developers + time to refactor relevant code. + """ + + def test_flatten_array_non_string_arg(self): + x = np.zeros((3, 5)) + self.message = ("Non-string object detected for " + "the array ordering. Please pass " + "in 'C', 'F', 'A', or 'K' instead") + self.assert_deprecated(x.flatten, args=(np.pi,)) + + def test_flatten_array_invalid_string_arg(self): + # Tests that a DeprecationWarning is raised + # when a string of length greater than one + # starting with "C", "F", "A", or "K" (case- + # and unicode-insensitive) is passed in for + # the ORDER parameter. Otherwise, a TypeError + # will be raised! + + x = np.zeros((3, 5)) + self.message = ("Non length-one string passed " + "in for the array ordering. Please " + "pass in 'C', 'F', 'A', or 'K' instead") + self.assert_deprecated(x.flatten, args=("FACK",)) + + +class TestArrayDataAttributeAssignmentDeprecation(_DeprecationTestCase): + """Assigning the 'data' attribute of an ndarray is unsafe as pointed + out in gh-7093. Eventually, such assignment should NOT be allowed, but + in the interests of maintaining backwards compatibility, only a Deprecation- + Warning will be raised instead for the time being to give developers time to + refactor relevant code. + """ + + def test_data_attr_assignment(self): + a = np.arange(10) + b = np.linspace(0, 1, 10) + + self.message = ("Assigning the 'data' attribute is an " + "inherently unsafe operation and will " + "be removed in the future.") + self.assert_deprecated(a.__setattr__, args=('data', b.data)) + + +class TestLinspaceInvalidNumParameter(_DeprecationTestCase): + """Argument to the num parameter in linspace that cannot be + safely interpreted as an integer is deprecated in 1.12.0. + + Argument to the num parameter in linspace that cannot be + safely interpreted as an integer should not be allowed. + In the interest of not breaking code that passes + an argument that could still be interpreted as an integer, a + DeprecationWarning will be issued for the time being to give + developers time to refactor relevant code. + """ + def test_float_arg(self): + # 2016-02-25, PR#7328 + self.assert_deprecated(np.linspace, args=(0, 10, 2.5)) + + +class TestBinaryReprInsufficientWidthParameterForRepresentation(_DeprecationTestCase): + """ + If a 'width' parameter is passed into ``binary_repr`` that is insufficient to + represent the number in base 2 (positive) or 2's complement (negative) form, + the function used to silently ignore the parameter and return a representation + using the minimal number of bits needed for the form in question. Such behavior + is now considered unsafe from a user perspective and will raise an error in the future. + """ + + def test_insufficient_width_positive(self): + args = (10,) + kwargs = {'width': 2} + + self.message = ("Insufficient bit width provided. This behavior " + "will raise an error in the future.") + self.assert_deprecated(np.binary_repr, args=args, kwargs=kwargs) + + def test_insufficient_width_negative(self): + args = (-5,) + kwargs = {'width': 2} + + self.message = ("Insufficient bit width provided. This behavior " + "will raise an error in the future.") + self.assert_deprecated(np.binary_repr, args=args, kwargs=kwargs) + + +class TestNumericStyleTypecodes(_DeprecationTestCase): + """ + Deprecate the old numeric-style dtypes, which are especially + confusing for complex types, e.g. Complex32 -> complex64. When the + deprecation cycle is complete, the check for the strings should be + removed from PyArray_DescrConverter in descriptor.c, and the + deprecated keys should not be added as capitalized aliases in + _add_aliases in numerictypes.py. + """ + def test_all_dtypes(self): + deprecated_types = [ + 'Bool', 'Complex32', 'Complex64', 'Float16', 'Float32', 'Float64', + 'Int8', 'Int16', 'Int32', 'Int64', 'Object0', 'Timedelta64', + 'UInt8', 'UInt16', 'UInt32', 'UInt64', 'Void0' + ] + if sys.version_info[0] < 3: + deprecated_types.extend(['Unicode0', 'String0']) + + for dt in deprecated_types: + self.assert_deprecated(np.dtype, exceptions=(TypeError,), + args=(dt,)) + + +class TestTestDeprecated(object): + def test_assert_deprecated(self): + test_case_instance = _DeprecationTestCase() + test_case_instance.setup() + assert_raises(AssertionError, + test_case_instance.assert_deprecated, + lambda: None) + + def foo(): + warnings.warn("foo", category=DeprecationWarning, stacklevel=2) + + test_case_instance.assert_deprecated(foo) + test_case_instance.teardown() + + +class TestClassicIntDivision(_DeprecationTestCase): + """ + See #7949. Deprecate the numeric-style dtypes with -3 flag in python 2 + if used for division + List of data types: http://docs.scipy.org/doc/numpy/user/basics.types.html + """ + def test_int_dtypes(self): + #scramble types and do some mix and match testing + deprecated_types = [ + 'bool_', 'int_', 'intc', 'uint8', 'int8', 'uint64', 'int32', 'uint16', + 'intp', 'int64', 'uint32', 'int16' + ] + if sys.version_info[0] < 3 and sys.py3kwarning: + import operator as op + dt2 = 'bool_' + for dt1 in deprecated_types: + a = np.array([1,2,3], dtype=dt1) + b = np.array([1,2,3], dtype=dt2) + self.assert_deprecated(op.div, args=(a,b)) + dt2 = dt1 + + +class TestNonNumericConjugate(_DeprecationTestCase): + """ + Deprecate no-op behavior of ndarray.conjugate on non-numeric dtypes, + which conflicts with the error behavior of np.conjugate. + """ + def test_conjugate(self): + for a in np.array(5), np.array(5j): + self.assert_not_deprecated(a.conjugate) + for a in (np.array('s'), np.array('2016', 'M'), + np.array((1, 2), [('a', int), ('b', int)])): + self.assert_deprecated(a.conjugate) + + +class TestNPY_CHAR(_DeprecationTestCase): + # 2017-05-03, 1.13.0 + def test_npy_char_deprecation(self): + from numpy.core.multiarray_tests import npy_char_deprecation + self.assert_deprecated(npy_char_deprecation) + assert_(npy_char_deprecation() == 'S1') + + +class Test_UPDATEIFCOPY(_DeprecationTestCase): + """ + v1.14 deprecates creating an array with the UPDATEIFCOPY flag, use + WRITEBACKIFCOPY instead + """ + def test_npy_updateifcopy_deprecation(self): + from numpy.core.multiarray_tests import npy_updateifcopy_deprecation + arr = np.arange(9).reshape(3, 3) + v = arr.T + self.assert_deprecated(npy_updateifcopy_deprecation, args=(v,)) + + +class TestDatetimeEvent(_DeprecationTestCase): + # 2017-08-11, 1.14.0 + def test_3_tuple(self): + for cls in (np.datetime64, np.timedelta64): + # two valid uses - (unit, num) and (unit, num, den, None) + self.assert_not_deprecated(cls, args=(1, ('ms', 2))) + self.assert_not_deprecated(cls, args=(1, ('ms', 2, 1, None))) + + # trying to use the event argument, removed in 1.7.0, is deprecated + # it used to be a uint8 + self.assert_deprecated(cls, args=(1, ('ms', 2, 'event'))) + self.assert_deprecated(cls, args=(1, ('ms', 2, 63))) + self.assert_deprecated(cls, args=(1, ('ms', 2, 1, 'event'))) + self.assert_deprecated(cls, args=(1, ('ms', 2, 1, 63))) + + +class TestTruthTestingEmptyArrays(_DeprecationTestCase): + # 2017-09-25, 1.14.0 + message = '.*truth value of an empty array is ambiguous.*' + + def test_1d(self): + self.assert_deprecated(bool, args=(np.array([]),)) + + def test_2d(self): + self.assert_deprecated(bool, args=(np.zeros((1, 0)),)) + self.assert_deprecated(bool, args=(np.zeros((0, 1)),)) + self.assert_deprecated(bool, args=(np.zeros((0, 0)),)) + + +class TestBincount(_DeprecationTestCase): + # 2017-06-01, 1.14.0 + def test_bincount_minlength(self): + self.assert_deprecated(lambda: np.bincount([1, 2, 3], minlength=None)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_dtype.py b/numpy/core/tests/test_dtype.py new file mode 100644 index 0000000..2f997b4 --- /dev/null +++ b/numpy/core/tests/test_dtype.py @@ -0,0 +1,728 @@ +from __future__ import division, absolute_import, print_function + +import pickle +import sys +import operator + +import numpy as np +from numpy.core.test_rational import rational +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, + dec +) + +def assert_dtype_equal(a, b): + assert_equal(a, b) + assert_equal(hash(a), hash(b), + "two equivalent types do not hash to the same value !") + +def assert_dtype_not_equal(a, b): + assert_(a != b) + assert_(hash(a) != hash(b), + "two different types hash to the same value !") + +class TestBuiltin(object): + def test_run(self): + """Only test hash runs at all.""" + for t in [int, float, complex, np.int32, str, object, + np.unicode]: + dt = np.dtype(t) + hash(dt) + + def test_dtype(self): + # Make sure equivalent byte order char hash the same (e.g. < and = on + # little endian) + for t in [int, float]: + dt = np.dtype(t) + dt2 = dt.newbyteorder("<") + dt3 = dt.newbyteorder(">") + if dt == dt2: + assert_(dt.byteorder != dt2.byteorder, "bogus test") + assert_dtype_equal(dt, dt2) + else: + assert_(dt.byteorder != dt3.byteorder, "bogus test") + assert_dtype_equal(dt, dt3) + + def test_equivalent_dtype_hashing(self): + # Make sure equivalent dtypes with different type num hash equal + uintp = np.dtype(np.uintp) + if uintp.itemsize == 4: + left = uintp + right = np.dtype(np.uint32) + else: + left = uintp + right = np.dtype(np.ulonglong) + assert_(left == right) + assert_(hash(left) == hash(right)) + + def test_invalid_types(self): + # Make sure invalid type strings raise an error + + assert_raises(TypeError, np.dtype, 'O3') + assert_raises(TypeError, np.dtype, 'O5') + assert_raises(TypeError, np.dtype, 'O7') + assert_raises(TypeError, np.dtype, 'b3') + assert_raises(TypeError, np.dtype, 'h4') + assert_raises(TypeError, np.dtype, 'I5') + assert_raises(TypeError, np.dtype, 'e3') + assert_raises(TypeError, np.dtype, 'f5') + + if np.dtype('g').itemsize == 8 or np.dtype('g').itemsize == 16: + assert_raises(TypeError, np.dtype, 'g12') + elif np.dtype('g').itemsize == 12: + assert_raises(TypeError, np.dtype, 'g16') + + if np.dtype('l').itemsize == 8: + assert_raises(TypeError, np.dtype, 'l4') + assert_raises(TypeError, np.dtype, 'L4') + else: + assert_raises(TypeError, np.dtype, 'l8') + assert_raises(TypeError, np.dtype, 'L8') + + if np.dtype('q').itemsize == 8: + assert_raises(TypeError, np.dtype, 'q4') + assert_raises(TypeError, np.dtype, 'Q4') + else: + assert_raises(TypeError, np.dtype, 'q8') + assert_raises(TypeError, np.dtype, 'Q8') + + def test_bad_param(self): + # Can't give a size that's too small + assert_raises(ValueError, np.dtype, + {'names':['f0', 'f1'], + 'formats':['i4', 'i1'], + 'offsets':[0, 4], + 'itemsize':4}) + # If alignment is enabled, the alignment (4) must divide the itemsize + assert_raises(ValueError, np.dtype, + {'names':['f0', 'f1'], + 'formats':['i4', 'i1'], + 'offsets':[0, 4], + 'itemsize':9}, align=True) + # If alignment is enabled, the individual fields must be aligned + assert_raises(ValueError, np.dtype, + {'names':['f0', 'f1'], + 'formats':['i1', 'f4'], + 'offsets':[0, 2]}, align=True) + + def test_field_order_equality(self): + x = np.dtype({'names': ['A', 'B'], + 'formats': ['i4', 'f4'], + 'offsets': [0, 4]}) + y = np.dtype({'names': ['B', 'A'], + 'formats': ['f4', 'i4'], + 'offsets': [4, 0]}) + assert_equal(x == y, False) + +class TestRecord(object): + def test_equivalent_record(self): + """Test whether equivalent record dtypes hash the same.""" + a = np.dtype([('yo', int)]) + b = np.dtype([('yo', int)]) + assert_dtype_equal(a, b) + + def test_different_names(self): + # In theory, they may hash the same (collision) ? + a = np.dtype([('yo', int)]) + b = np.dtype([('ye', int)]) + assert_dtype_not_equal(a, b) + + def test_different_titles(self): + # In theory, they may hash the same (collision) ? + a = np.dtype({'names': ['r', 'b'], + 'formats': ['u1', 'u1'], + 'titles': ['Red pixel', 'Blue pixel']}) + b = np.dtype({'names': ['r', 'b'], + 'formats': ['u1', 'u1'], + 'titles': ['RRed pixel', 'Blue pixel']}) + assert_dtype_not_equal(a, b) + + def test_mutate(self): + # Mutating a dtype should reset the cached hash value + a = np.dtype([('yo', int)]) + b = np.dtype([('yo', int)]) + c = np.dtype([('ye', int)]) + assert_dtype_equal(a, b) + assert_dtype_not_equal(a, c) + a.names = ['ye'] + assert_dtype_equal(a, c) + assert_dtype_not_equal(a, b) + state = b.__reduce__()[2] + a.__setstate__(state) + assert_dtype_equal(a, b) + assert_dtype_not_equal(a, c) + + def test_not_lists(self): + """Test if an appropriate exception is raised when passing bad values to + the dtype constructor. + """ + assert_raises(TypeError, np.dtype, + dict(names=set(['A', 'B']), formats=['f8', 'i4'])) + assert_raises(TypeError, np.dtype, + dict(names=['A', 'B'], formats=set(['f8', 'i4']))) + + def test_aligned_size(self): + # Check that structured dtypes get padded to an aligned size + dt = np.dtype('i4, i1', align=True) + assert_equal(dt.itemsize, 8) + dt = np.dtype([('f0', 'i4'), ('f1', 'i1')], align=True) + assert_equal(dt.itemsize, 8) + dt = np.dtype({'names':['f0', 'f1'], + 'formats':['i4', 'u1'], + 'offsets':[0, 4]}, align=True) + assert_equal(dt.itemsize, 8) + dt = np.dtype({'f0': ('i4', 0), 'f1':('u1', 4)}, align=True) + assert_equal(dt.itemsize, 8) + # Nesting should preserve that alignment + dt1 = np.dtype([('f0', 'i4'), + ('f1', [('f1', 'i1'), ('f2', 'i4'), ('f3', 'i1')]), + ('f2', 'i1')], align=True) + assert_equal(dt1.itemsize, 20) + dt2 = np.dtype({'names':['f0', 'f1', 'f2'], + 'formats':['i4', + [('f1', 'i1'), ('f2', 'i4'), ('f3', 'i1')], + 'i1'], + 'offsets':[0, 4, 16]}, align=True) + assert_equal(dt2.itemsize, 20) + dt3 = np.dtype({'f0': ('i4', 0), + 'f1': ([('f1', 'i1'), ('f2', 'i4'), ('f3', 'i1')], 4), + 'f2': ('i1', 16)}, align=True) + assert_equal(dt3.itemsize, 20) + assert_equal(dt1, dt2) + assert_equal(dt2, dt3) + # Nesting should preserve packing + dt1 = np.dtype([('f0', 'i4'), + ('f1', [('f1', 'i1'), ('f2', 'i4'), ('f3', 'i1')]), + ('f2', 'i1')], align=False) + assert_equal(dt1.itemsize, 11) + dt2 = np.dtype({'names':['f0', 'f1', 'f2'], + 'formats':['i4', + [('f1', 'i1'), ('f2', 'i4'), ('f3', 'i1')], + 'i1'], + 'offsets':[0, 4, 10]}, align=False) + assert_equal(dt2.itemsize, 11) + dt3 = np.dtype({'f0': ('i4', 0), + 'f1': ([('f1', 'i1'), ('f2', 'i4'), ('f3', 'i1')], 4), + 'f2': ('i1', 10)}, align=False) + assert_equal(dt3.itemsize, 11) + assert_equal(dt1, dt2) + assert_equal(dt2, dt3) + + def test_union_struct(self): + # Should be able to create union dtypes + dt = np.dtype({'names':['f0', 'f1', 'f2'], 'formats':['f4', (64, 64)), (1,)), + ('rtile', '>f4', (64, 36))], (3,)), + ('bottom', [('bleft', ('>f4', (8, 64)), (1,)), + ('bright', '>f4', (8, 36))])]) + assert_equal(str(dt), + "[('top', [('tiles', ('>f4', (64, 64)), (1,)), " + "('rtile', '>f4', (64, 36))], (3,)), " + "('bottom', [('bleft', ('>f4', (8, 64)), (1,)), " + "('bright', '>f4', (8, 36))])]") + + # If the sticky aligned flag is set to True, it makes the + # str() function use a dict representation with an 'aligned' flag + dt = np.dtype([('top', [('tiles', ('>f4', (64, 64)), (1,)), + ('rtile', '>f4', (64, 36))], + (3,)), + ('bottom', [('bleft', ('>f4', (8, 64)), (1,)), + ('bright', '>f4', (8, 36))])], + align=True) + assert_equal(str(dt), + "{'names':['top','bottom'], " + "'formats':[([('tiles', ('>f4', (64, 64)), (1,)), " + "('rtile', '>f4', (64, 36))], (3,))," + "[('bleft', ('>f4', (8, 64)), (1,)), " + "('bright', '>f4', (8, 36))]], " + "'offsets':[0,76800], " + "'itemsize':80000, " + "'aligned':True}") + assert_equal(np.dtype(eval(str(dt))), dt) + + dt = np.dtype({'names': ['r', 'g', 'b'], 'formats': ['u1', 'u1', 'u1'], + 'offsets': [0, 1, 2], + 'titles': ['Red pixel', 'Green pixel', 'Blue pixel']}) + assert_equal(str(dt), + "[(('Red pixel', 'r'), 'u1'), " + "(('Green pixel', 'g'), 'u1'), " + "(('Blue pixel', 'b'), 'u1')]") + + dt = np.dtype({'names': ['rgba', 'r', 'g', 'b'], + 'formats': ['f4', (64, 64)), (1,)), + ('rtile', '>f4', (64, 36))], (3,)), + ('bottom', [('bleft', ('>f4', (8, 64)), (1,)), + ('bright', '>f4', (8, 36))])]) + assert_equal(repr(dt), + "dtype([('top', [('tiles', ('>f4', (64, 64)), (1,)), " + "('rtile', '>f4', (64, 36))], (3,)), " + "('bottom', [('bleft', ('>f4', (8, 64)), (1,)), " + "('bright', '>f4', (8, 36))])])") + + dt = np.dtype({'names': ['r', 'g', 'b'], 'formats': ['u1', 'u1', 'u1'], + 'offsets': [0, 1, 2], + 'titles': ['Red pixel', 'Green pixel', 'Blue pixel']}, + align=True) + assert_equal(repr(dt), + "dtype([(('Red pixel', 'r'), 'u1'), " + "(('Green pixel', 'g'), 'u1'), " + "(('Blue pixel', 'b'), 'u1')], align=True)") + + dt = np.dtype({'names': ['rgba', 'r', 'g', 'b'], + 'formats': ['= 3) + def test_dtype_str_with_long_in_shape(self): + # Pull request #376, should not error + np.dtype('(1L,)i4') + + def test_base_dtype_with_object_type(self): + # Issue gh-2798, should not error. + np.array(['a'], dtype="O").astype(("O", [("name", "O")])) + + def test_empty_string_to_object(self): + # Pull request #4722 + np.array(["", ""]).astype(object) + +class TestDtypeAttributeDeletion(object): + + def test_dtype_non_writable_attributes_deletion(self): + dt = np.dtype(np.double) + attr = ["subdtype", "descr", "str", "name", "base", "shape", + "isbuiltin", "isnative", "isalignedstruct", "fields", + "metadata", "hasobject"] + + for s in attr: + assert_raises(AttributeError, delattr, dt, s) + + def test_dtype_writable_attributes_deletion(self): + dt = np.dtype(np.double) + attr = ["names"] + for s in attr: + assert_raises(AttributeError, delattr, dt, s) + + +class TestDtypeAttributes(object): + def test_descr_has_trailing_void(self): + # see gh-6359 + dtype = np.dtype({ + 'names': ['A', 'B'], + 'formats': ['f4', 'f4'], + 'offsets': [0, 8], + 'itemsize': 16}) + new_dtype = np.dtype(dtype.descr) + assert_equal(new_dtype.itemsize, 16) + + def test_name_builtin(self): + for t in np.typeDict.values(): + name = t.__name__ + if name.endswith('_'): + name = name[:-1] + assert_equal(np.dtype(t).name, name) + + def test_name_dtype_subclass(self): + # Ticket #4357 + class user_def_subcls(np.void): + pass + assert_equal(np.dtype(user_def_subcls).name, 'user_def_subcls') + + +class TestPickling(object): + + def check_pickling(self, dtype): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + pickled = pickle.loads(pickle.dumps(dtype, proto)) + assert_equal(pickled, dtype) + assert_equal(pickled.descr, dtype.descr) + if dtype.metadata is not None: + assert_equal(pickled.metadata, dtype.metadata) + # Check the reconstructed dtype is functional + x = np.zeros(3, dtype=dtype) + y = np.zeros(3, dtype=pickled) + assert_equal(x, y) + assert_equal(x[0], y[0]) + + def test_builtin(self): + for t in [int, float, complex, np.int32, str, object, + np.unicode, bool]: + self.check_pickling(np.dtype(t)) + + def test_structured(self): + dt = np.dtype(([('a', '>f4', (2, 1)), ('b', '..j", [0, 0], optimize=do_opt) + assert_raises(ValueError, np.einsum, "j->.j...", [0, 0], optimize=do_opt) + + # invalid subscript character + assert_raises(ValueError, np.einsum, "i%...", [0, 0], optimize=do_opt) + assert_raises(ValueError, np.einsum, "...j$", [0, 0], optimize=do_opt) + assert_raises(ValueError, np.einsum, "i->&", [0, 0], optimize=do_opt) + + # output subscripts must appear in input + assert_raises(ValueError, np.einsum, "i->ij", [0, 0], optimize=do_opt) + + # output subscripts may only be specified once + assert_raises(ValueError, np.einsum, "ij->jij", [[0, 0], [0, 0]], + optimize=do_opt) + + # dimensions much match when being collapsed + assert_raises(ValueError, np.einsum, "ii", + np.arange(6).reshape(2, 3), optimize=do_opt) + assert_raises(ValueError, np.einsum, "ii->i", + np.arange(6).reshape(2, 3), optimize=do_opt) + + # broadcasting to new dimensions must be enabled explicitly + assert_raises(ValueError, np.einsum, "i", np.arange(6).reshape(2, 3), + optimize=do_opt) + assert_raises(ValueError, np.einsum, "i->i", [[0, 1], [0, 1]], + out=np.arange(4).reshape(2, 2), optimize=do_opt) + + def test_einsum_views(self): + # pass-through + for do_opt in [True, False]: + a = np.arange(6) + a.shape = (2, 3) + + b = np.einsum("...", a, optimize=do_opt) + assert_(b.base is a) + + b = np.einsum(a, [Ellipsis], optimize=do_opt) + assert_(b.base is a) + + b = np.einsum("ij", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, a) + + b = np.einsum(a, [0, 1], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, a) + + # output is writeable whenever input is writeable + b = np.einsum("...", a, optimize=do_opt) + assert_(b.flags['WRITEABLE']) + a.flags['WRITEABLE'] = False + b = np.einsum("...", a, optimize=do_opt) + assert_(not b.flags['WRITEABLE']) + + # transpose + a = np.arange(6) + a.shape = (2, 3) + + b = np.einsum("ji", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, a.T) + + b = np.einsum(a, [1, 0], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, a.T) + + # diagonal + a = np.arange(9) + a.shape = (3, 3) + + b = np.einsum("ii->i", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a[i, i] for i in range(3)]) + + b = np.einsum(a, [0, 0], [0], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a[i, i] for i in range(3)]) + + # diagonal with various ways of broadcasting an additional dimension + a = np.arange(27) + a.shape = (3, 3, 3) + + b = np.einsum("...ii->...i", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [[x[i, i] for i in range(3)] for x in a]) + + b = np.einsum(a, [Ellipsis, 0, 0], [Ellipsis, 0], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [[x[i, i] for i in range(3)] for x in a]) + + b = np.einsum("ii...->...i", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [[x[i, i] for i in range(3)] + for x in a.transpose(2, 0, 1)]) + + b = np.einsum(a, [0, 0, Ellipsis], [Ellipsis, 0], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [[x[i, i] for i in range(3)] + for x in a.transpose(2, 0, 1)]) + + b = np.einsum("...ii->i...", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a[:, i, i] for i in range(3)]) + + b = np.einsum(a, [Ellipsis, 0, 0], [0, Ellipsis], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a[:, i, i] for i in range(3)]) + + b = np.einsum("jii->ij", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a[:, i, i] for i in range(3)]) + + b = np.einsum(a, [1, 0, 0], [0, 1], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a[:, i, i] for i in range(3)]) + + b = np.einsum("ii...->i...", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a.transpose(2, 0, 1)[:, i, i] for i in range(3)]) + + b = np.einsum(a, [0, 0, Ellipsis], [0, Ellipsis], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a.transpose(2, 0, 1)[:, i, i] for i in range(3)]) + + b = np.einsum("i...i->i...", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a.transpose(1, 0, 2)[:, i, i] for i in range(3)]) + + b = np.einsum(a, [0, Ellipsis, 0], [0, Ellipsis], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a.transpose(1, 0, 2)[:, i, i] for i in range(3)]) + + b = np.einsum("i...i->...i", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [[x[i, i] for i in range(3)] + for x in a.transpose(1, 0, 2)]) + + b = np.einsum(a, [0, Ellipsis, 0], [Ellipsis, 0], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [[x[i, i] for i in range(3)] + for x in a.transpose(1, 0, 2)]) + + # triple diagonal + a = np.arange(27) + a.shape = (3, 3, 3) + + b = np.einsum("iii->i", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a[i, i, i] for i in range(3)]) + + b = np.einsum(a, [0, 0, 0], [0], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, [a[i, i, i] for i in range(3)]) + + # swap axes + a = np.arange(24) + a.shape = (2, 3, 4) + + b = np.einsum("ijk->jik", a, optimize=do_opt) + assert_(b.base is a) + assert_equal(b, a.swapaxes(0, 1)) + + b = np.einsum(a, [0, 1, 2], [1, 0, 2], optimize=do_opt) + assert_(b.base is a) + assert_equal(b, a.swapaxes(0, 1)) + + def check_einsum_sums(self, dtype, do_opt=False): + # Check various sums. Does many sizes to exercise unrolled loops. + + # sum(a, axis=-1) + for n in range(1, 17): + a = np.arange(n, dtype=dtype) + assert_equal(np.einsum("i->", a, optimize=do_opt), + np.sum(a, axis=-1).astype(dtype)) + assert_equal(np.einsum(a, [0], [], optimize=do_opt), + np.sum(a, axis=-1).astype(dtype)) + + for n in range(1, 17): + a = np.arange(2*3*n, dtype=dtype).reshape(2, 3, n) + assert_equal(np.einsum("...i->...", a, optimize=do_opt), + np.sum(a, axis=-1).astype(dtype)) + assert_equal(np.einsum(a, [Ellipsis, 0], [Ellipsis], optimize=do_opt), + np.sum(a, axis=-1).astype(dtype)) + + # sum(a, axis=0) + for n in range(1, 17): + a = np.arange(2*n, dtype=dtype).reshape(2, n) + assert_equal(np.einsum("i...->...", a, optimize=do_opt), + np.sum(a, axis=0).astype(dtype)) + assert_equal(np.einsum(a, [0, Ellipsis], [Ellipsis], optimize=do_opt), + np.sum(a, axis=0).astype(dtype)) + + for n in range(1, 17): + a = np.arange(2*3*n, dtype=dtype).reshape(2, 3, n) + assert_equal(np.einsum("i...->...", a, optimize=do_opt), + np.sum(a, axis=0).astype(dtype)) + assert_equal(np.einsum(a, [0, Ellipsis], [Ellipsis], optimize=do_opt), + np.sum(a, axis=0).astype(dtype)) + + # trace(a) + for n in range(1, 17): + a = np.arange(n*n, dtype=dtype).reshape(n, n) + assert_equal(np.einsum("ii", a, optimize=do_opt), + np.trace(a).astype(dtype)) + assert_equal(np.einsum(a, [0, 0], optimize=do_opt), + np.trace(a).astype(dtype)) + + # multiply(a, b) + assert_equal(np.einsum("..., ...", 3, 4), 12) # scalar case + for n in range(1, 17): + a = np.arange(3 * n, dtype=dtype).reshape(3, n) + b = np.arange(2 * 3 * n, dtype=dtype).reshape(2, 3, n) + assert_equal(np.einsum("..., ...", a, b, optimize=do_opt), + np.multiply(a, b)) + assert_equal(np.einsum(a, [Ellipsis], b, [Ellipsis], optimize=do_opt), + np.multiply(a, b)) + + # inner(a,b) + for n in range(1, 17): + a = np.arange(2 * 3 * n, dtype=dtype).reshape(2, 3, n) + b = np.arange(n, dtype=dtype) + assert_equal(np.einsum("...i, ...i", a, b, optimize=do_opt), np.inner(a, b)) + assert_equal(np.einsum(a, [Ellipsis, 0], b, [Ellipsis, 0], optimize=do_opt), + np.inner(a, b)) + + for n in range(1, 11): + a = np.arange(n * 3 * 2, dtype=dtype).reshape(n, 3, 2) + b = np.arange(n, dtype=dtype) + assert_equal(np.einsum("i..., i...", a, b, optimize=do_opt), + np.inner(a.T, b.T).T) + assert_equal(np.einsum(a, [0, Ellipsis], b, [0, Ellipsis], optimize=do_opt), + np.inner(a.T, b.T).T) + + # outer(a,b) + for n in range(1, 17): + a = np.arange(3, dtype=dtype)+1 + b = np.arange(n, dtype=dtype)+1 + assert_equal(np.einsum("i,j", a, b, optimize=do_opt), + np.outer(a, b)) + assert_equal(np.einsum(a, [0], b, [1], optimize=do_opt), + np.outer(a, b)) + + # Suppress the complex warnings for the 'as f8' tests + with suppress_warnings() as sup: + sup.filter(np.ComplexWarning) + + # matvec(a,b) / a.dot(b) where a is matrix, b is vector + for n in range(1, 17): + a = np.arange(4*n, dtype=dtype).reshape(4, n) + b = np.arange(n, dtype=dtype) + assert_equal(np.einsum("ij, j", a, b, optimize=do_opt), + np.dot(a, b)) + assert_equal(np.einsum(a, [0, 1], b, [1], optimize=do_opt), + np.dot(a, b)) + + c = np.arange(4, dtype=dtype) + np.einsum("ij,j", a, b, out=c, + dtype='f8', casting='unsafe', optimize=do_opt) + assert_equal(c, + np.dot(a.astype('f8'), + b.astype('f8')).astype(dtype)) + c[...] = 0 + np.einsum(a, [0, 1], b, [1], out=c, + dtype='f8', casting='unsafe', optimize=do_opt) + assert_equal(c, + np.dot(a.astype('f8'), + b.astype('f8')).astype(dtype)) + + for n in range(1, 17): + a = np.arange(4*n, dtype=dtype).reshape(4, n) + b = np.arange(n, dtype=dtype) + assert_equal(np.einsum("ji,j", a.T, b.T, optimize=do_opt), + np.dot(b.T, a.T)) + assert_equal(np.einsum(a.T, [1, 0], b.T, [1], optimize=do_opt), + np.dot(b.T, a.T)) + + c = np.arange(4, dtype=dtype) + np.einsum("ji,j", a.T, b.T, out=c, + dtype='f8', casting='unsafe', optimize=do_opt) + assert_equal(c, + np.dot(b.T.astype('f8'), + a.T.astype('f8')).astype(dtype)) + c[...] = 0 + np.einsum(a.T, [1, 0], b.T, [1], out=c, + dtype='f8', casting='unsafe', optimize=do_opt) + assert_equal(c, + np.dot(b.T.astype('f8'), + a.T.astype('f8')).astype(dtype)) + + # matmat(a,b) / a.dot(b) where a is matrix, b is matrix + for n in range(1, 17): + if n < 8 or dtype != 'f2': + a = np.arange(4*n, dtype=dtype).reshape(4, n) + b = np.arange(n*6, dtype=dtype).reshape(n, 6) + assert_equal(np.einsum("ij,jk", a, b, optimize=do_opt), + np.dot(a, b)) + assert_equal(np.einsum(a, [0, 1], b, [1, 2], optimize=do_opt), + np.dot(a, b)) + + for n in range(1, 17): + a = np.arange(4*n, dtype=dtype).reshape(4, n) + b = np.arange(n*6, dtype=dtype).reshape(n, 6) + c = np.arange(24, dtype=dtype).reshape(4, 6) + np.einsum("ij,jk", a, b, out=c, dtype='f8', casting='unsafe', + optimize=do_opt) + assert_equal(c, + np.dot(a.astype('f8'), + b.astype('f8')).astype(dtype)) + c[...] = 0 + np.einsum(a, [0, 1], b, [1, 2], out=c, + dtype='f8', casting='unsafe', optimize=do_opt) + assert_equal(c, + np.dot(a.astype('f8'), + b.astype('f8')).astype(dtype)) + + # matrix triple product (note this is not currently an efficient + # way to multiply 3 matrices) + a = np.arange(12, dtype=dtype).reshape(3, 4) + b = np.arange(20, dtype=dtype).reshape(4, 5) + c = np.arange(30, dtype=dtype).reshape(5, 6) + if dtype != 'f2': + assert_equal(np.einsum("ij,jk,kl", a, b, c, optimize=do_opt), + a.dot(b).dot(c)) + assert_equal(np.einsum(a, [0, 1], b, [1, 2], c, [2, 3], + optimize=do_opt), a.dot(b).dot(c)) + + d = np.arange(18, dtype=dtype).reshape(3, 6) + np.einsum("ij,jk,kl", a, b, c, out=d, + dtype='f8', casting='unsafe', optimize=do_opt) + tgt = a.astype('f8').dot(b.astype('f8')) + tgt = tgt.dot(c.astype('f8')).astype(dtype) + assert_equal(d, tgt) + + d[...] = 0 + np.einsum(a, [0, 1], b, [1, 2], c, [2, 3], out=d, + dtype='f8', casting='unsafe', optimize=do_opt) + tgt = a.astype('f8').dot(b.astype('f8')) + tgt = tgt.dot(c.astype('f8')).astype(dtype) + assert_equal(d, tgt) + + # tensordot(a, b) + if np.dtype(dtype) != np.dtype('f2'): + a = np.arange(60, dtype=dtype).reshape(3, 4, 5) + b = np.arange(24, dtype=dtype).reshape(4, 3, 2) + assert_equal(np.einsum("ijk, jil -> kl", a, b), + np.tensordot(a, b, axes=([1, 0], [0, 1]))) + assert_equal(np.einsum(a, [0, 1, 2], b, [1, 0, 3], [2, 3]), + np.tensordot(a, b, axes=([1, 0], [0, 1]))) + + c = np.arange(10, dtype=dtype).reshape(5, 2) + np.einsum("ijk,jil->kl", a, b, out=c, + dtype='f8', casting='unsafe', optimize=do_opt) + assert_equal(c, np.tensordot(a.astype('f8'), b.astype('f8'), + axes=([1, 0], [0, 1])).astype(dtype)) + c[...] = 0 + np.einsum(a, [0, 1, 2], b, [1, 0, 3], [2, 3], out=c, + dtype='f8', casting='unsafe', optimize=do_opt) + assert_equal(c, np.tensordot(a.astype('f8'), b.astype('f8'), + axes=([1, 0], [0, 1])).astype(dtype)) + + # logical_and(logical_and(a!=0, b!=0), c!=0) + a = np.array([1, 3, -2, 0, 12, 13, 0, 1], dtype=dtype) + b = np.array([0, 3.5, 0., -2, 0, 1, 3, 12], dtype=dtype) + c = np.array([True, True, False, True, True, False, True, True]) + assert_equal(np.einsum("i,i,i->i", a, b, c, + dtype='?', casting='unsafe', optimize=do_opt), + np.logical_and(np.logical_and(a != 0, b != 0), c != 0)) + assert_equal(np.einsum(a, [0], b, [0], c, [0], [0], + dtype='?', casting='unsafe'), + np.logical_and(np.logical_and(a != 0, b != 0), c != 0)) + + a = np.arange(9, dtype=dtype) + assert_equal(np.einsum(",i->", 3, a), 3*np.sum(a)) + assert_equal(np.einsum(3, [], a, [0], []), 3*np.sum(a)) + assert_equal(np.einsum("i,->", a, 3), 3*np.sum(a)) + assert_equal(np.einsum(a, [0], 3, [], []), 3*np.sum(a)) + + # Various stride0, contiguous, and SSE aligned variants + for n in range(1, 25): + a = np.arange(n, dtype=dtype) + if np.dtype(dtype).itemsize > 1: + assert_equal(np.einsum("...,...", a, a, optimize=do_opt), + np.multiply(a, a)) + assert_equal(np.einsum("i,i", a, a, optimize=do_opt), np.dot(a, a)) + assert_equal(np.einsum("i,->i", a, 2, optimize=do_opt), 2*a) + assert_equal(np.einsum(",i->i", 2, a, optimize=do_opt), 2*a) + assert_equal(np.einsum("i,->", a, 2, optimize=do_opt), 2*np.sum(a)) + assert_equal(np.einsum(",i->", 2, a, optimize=do_opt), 2*np.sum(a)) + + assert_equal(np.einsum("...,...", a[1:], a[:-1], optimize=do_opt), + np.multiply(a[1:], a[:-1])) + assert_equal(np.einsum("i,i", a[1:], a[:-1], optimize=do_opt), + np.dot(a[1:], a[:-1])) + assert_equal(np.einsum("i,->i", a[1:], 2, optimize=do_opt), 2*a[1:]) + assert_equal(np.einsum(",i->i", 2, a[1:], optimize=do_opt), 2*a[1:]) + assert_equal(np.einsum("i,->", a[1:], 2, optimize=do_opt), + 2*np.sum(a[1:])) + assert_equal(np.einsum(",i->", 2, a[1:], optimize=do_opt), + 2*np.sum(a[1:])) + + # An object array, summed as the data type + a = np.arange(9, dtype=object) + + b = np.einsum("i->", a, dtype=dtype, casting='unsafe') + assert_equal(b, np.sum(a)) + assert_equal(b.dtype, np.dtype(dtype)) + + b = np.einsum(a, [0], [], dtype=dtype, casting='unsafe') + assert_equal(b, np.sum(a)) + assert_equal(b.dtype, np.dtype(dtype)) + + # A case which was failing (ticket #1885) + p = np.arange(2) + 1 + q = np.arange(4).reshape(2, 2) + 3 + r = np.arange(4).reshape(2, 2) + 7 + assert_equal(np.einsum('z,mz,zm->', p, q, r), 253) + + # singleton dimensions broadcast (gh-10343) + p = np.ones((10,2)) + q = np.ones((1,2)) + assert_array_equal(np.einsum('ij,ij->j', p, q, optimize=True), + np.einsum('ij,ij->j', p, q, optimize=False)) + assert_array_equal(np.einsum('ij,ij->j', p, q, optimize=True), + [10.] * 2) + + p = np.ones((1, 5)) + q = np.ones((5, 5)) + for optimize in (True, False): + assert_array_equal(np.einsum("...ij,...jk->...ik", p, p, + optimize=optimize), + np.einsum("...ij,...jk->...ik", p, q, + optimize=optimize)) + assert_array_equal(np.einsum("...ij,...jk->...ik", p, q, + optimize=optimize), + np.full((1, 5), 5)) + + def test_einsum_sums_int8(self): + self.check_einsum_sums('i1') + + def test_einsum_sums_uint8(self): + self.check_einsum_sums('u1') + + def test_einsum_sums_int16(self): + self.check_einsum_sums('i2') + + def test_einsum_sums_uint16(self): + self.check_einsum_sums('u2') + + def test_einsum_sums_int32(self): + self.check_einsum_sums('i4') + self.check_einsum_sums('i4', True) + + def test_einsum_sums_uint32(self): + self.check_einsum_sums('u4') + self.check_einsum_sums('u4', True) + + def test_einsum_sums_int64(self): + self.check_einsum_sums('i8') + + def test_einsum_sums_uint64(self): + self.check_einsum_sums('u8') + + def test_einsum_sums_float16(self): + self.check_einsum_sums('f2') + + def test_einsum_sums_float32(self): + self.check_einsum_sums('f4') + + def test_einsum_sums_float64(self): + self.check_einsum_sums('f8') + self.check_einsum_sums('f8', True) + + def test_einsum_sums_longdouble(self): + self.check_einsum_sums(np.longdouble) + + def test_einsum_sums_cfloat64(self): + self.check_einsum_sums('c8') + self.check_einsum_sums('c8', True) + + def test_einsum_sums_cfloat128(self): + self.check_einsum_sums('c16') + + def test_einsum_sums_clongdouble(self): + self.check_einsum_sums(np.clongdouble) + + def test_einsum_misc(self): + # This call used to crash because of a bug in + # PyArray_AssignZero + a = np.ones((1, 2)) + b = np.ones((2, 2, 1)) + assert_equal(np.einsum('ij...,j...->i...', a, b), [[[2], [2]]]) + assert_equal(np.einsum('ij...,j...->i...', a, b, optimize=True), [[[2], [2]]]) + + # Regression test for issue #10369 (test unicode inputs with Python 2) + assert_equal(np.einsum(u'ij...,j...->i...', a, b), [[[2], [2]]]) + assert_equal(np.einsum('...i,...i', [1, 2, 3], [2, 3, 4]), 20) + assert_equal(np.einsum(u'...i,...i', [1, 2, 3], [2, 3, 4]), 20) + assert_equal(np.einsum('...i,...i', [1, 2, 3], [2, 3, 4], + optimize=u'greedy'), 20) + + # The iterator had an issue with buffering this reduction + a = np.ones((5, 12, 4, 2, 3), np.int64) + b = np.ones((5, 12, 11), np.int64) + assert_equal(np.einsum('ijklm,ijn,ijn->', a, b, b), + np.einsum('ijklm,ijn->', a, b)) + assert_equal(np.einsum('ijklm,ijn,ijn->', a, b, b, optimize=True), + np.einsum('ijklm,ijn->', a, b, optimize=True)) + + # Issue #2027, was a problem in the contiguous 3-argument + # inner loop implementation + a = np.arange(1, 3) + b = np.arange(1, 5).reshape(2, 2) + c = np.arange(1, 9).reshape(4, 2) + assert_equal(np.einsum('x,yx,zx->xzy', a, b, c), + [[[1, 3], [3, 9], [5, 15], [7, 21]], + [[8, 16], [16, 32], [24, 48], [32, 64]]]) + assert_equal(np.einsum('x,yx,zx->xzy', a, b, c, optimize=True), + [[[1, 3], [3, 9], [5, 15], [7, 21]], + [[8, 16], [16, 32], [24, 48], [32, 64]]]) + + def test_einsum_broadcast(self): + # Issue #2455 change in handling ellipsis + # remove the 'middle broadcast' error + # only use the 'RIGHT' iteration in prepare_op_axes + # adds auto broadcast on left where it belongs + # broadcast on right has to be explicit + # We need to test the optimized parsing as well + + A = np.arange(2 * 3 * 4).reshape(2, 3, 4) + B = np.arange(3) + ref = np.einsum('ijk,j->ijk', A, B, optimize=False) + for opt in [True, False]: + assert_equal(np.einsum('ij...,j...->ij...', A, B, optimize=opt), ref) + assert_equal(np.einsum('ij...,...j->ij...', A, B, optimize=opt), ref) + assert_equal(np.einsum('ij...,j->ij...', A, B, optimize=opt), ref) # used to raise error + + A = np.arange(12).reshape((4, 3)) + B = np.arange(6).reshape((3, 2)) + ref = np.einsum('ik,kj->ij', A, B, optimize=False) + for opt in [True, False]: + assert_equal(np.einsum('ik...,k...->i...', A, B, optimize=opt), ref) + assert_equal(np.einsum('ik...,...kj->i...j', A, B, optimize=opt), ref) + assert_equal(np.einsum('...k,kj', A, B, optimize=opt), ref) # used to raise error + assert_equal(np.einsum('ik,k...->i...', A, B, optimize=opt), ref) # used to raise error + + dims = [2, 3, 4, 5] + a = np.arange(np.prod(dims)).reshape(dims) + v = np.arange(dims[2]) + ref = np.einsum('ijkl,k->ijl', a, v, optimize=False) + for opt in [True, False]: + assert_equal(np.einsum('ijkl,k', a, v, optimize=opt), ref) + assert_equal(np.einsum('...kl,k', a, v, optimize=opt), ref) # used to raise error + assert_equal(np.einsum('...kl,k...', a, v, optimize=opt), ref) + + J, K, M = 160, 160, 120 + A = np.arange(J * K * M).reshape(1, 1, 1, J, K, M) + B = np.arange(J * K * M * 3).reshape(J, K, M, 3) + ref = np.einsum('...lmn,...lmno->...o', A, B, optimize=False) + for opt in [True, False]: + assert_equal(np.einsum('...lmn,lmno->...o', A, B, + optimize=opt), ref) # used to raise error + + def test_einsum_fixedstridebug(self): + # Issue #4485 obscure einsum bug + # This case revealed a bug in nditer where it reported a stride + # as 'fixed' (0) when it was in fact not fixed during processing + # (0 or 4). The reason for the bug was that the check for a fixed + # stride was using the information from the 2D inner loop reuse + # to restrict the iteration dimensions it had to validate to be + # the same, but that 2D inner loop reuse logic is only triggered + # during the buffer copying step, and hence it was invalid to + # rely on those values. The fix is to check all the dimensions + # of the stride in question, which in the test case reveals that + # the stride is not fixed. + # + # NOTE: This test is triggered by the fact that the default buffersize, + # used by einsum, is 8192, and 3*2731 = 8193, is larger than that + # and results in a mismatch between the buffering and the + # striding for operand A. + A = np.arange(2 * 3).reshape(2, 3).astype(np.float32) + B = np.arange(2 * 3 * 2731).reshape(2, 3, 2731).astype(np.int16) + es = np.einsum('cl, cpx->lpx', A, B) + tp = np.tensordot(A, B, axes=(0, 0)) + assert_equal(es, tp) + # The following is the original test case from the bug report, + # made repeatable by changing random arrays to aranges. + A = np.arange(3 * 3).reshape(3, 3).astype(np.float64) + B = np.arange(3 * 3 * 64 * 64).reshape(3, 3, 64, 64).astype(np.float32) + es = np.einsum('cl, cpxy->lpxy', A, B) + tp = np.tensordot(A, B, axes=(0, 0)) + assert_equal(es, tp) + + def test_einsum_fixed_collapsingbug(self): + # Issue #5147. + # The bug only occurred when output argument of einssum was used. + x = np.random.normal(0, 1, (5, 5, 5, 5)) + y1 = np.zeros((5, 5)) + np.einsum('aabb->ab', x, out=y1) + idx = np.arange(5) + y2 = x[idx[:, None], idx[:, None], idx, idx] + assert_equal(y1, y2) + + def test_einsum_all_contig_non_contig_output(self): + # Issue gh-5907, tests that the all contiguous special case + # actually checks the contiguity of the output + x = np.ones((5, 5)) + out = np.ones(10)[::2] + correct_base = np.ones(10) + correct_base[::2] = 5 + # Always worked (inner iteration is done with 0-stride): + np.einsum('mi,mi,mi->m', x, x, x, out=out) + assert_array_equal(out.base, correct_base) + # Example 1: + out = np.ones(10)[::2] + np.einsum('im,im,im->m', x, x, x, out=out) + assert_array_equal(out.base, correct_base) + # Example 2, buffering causes x to be contiguous but + # special cases do not catch the operation before: + out = np.ones((2, 2, 2))[..., 0] + correct_base = np.ones((2, 2, 2)) + correct_base[..., 0] = 2 + x = np.ones((2, 2), np.float32) + np.einsum('ij,jk->ik', x, x, out=out) + assert_array_equal(out.base, correct_base) + + def test_small_boolean_arrays(self): + # See gh-5946. + # Use array of True embedded in False. + a = np.zeros((16, 1, 1), dtype=np.bool_)[:2] + a[...] = True + out = np.zeros((16, 1, 1), dtype=np.bool_)[:2] + tgt = np.ones((2, 1, 1), dtype=np.bool_) + res = np.einsum('...ij,...jk->...ik', a, a, out=out) + assert_equal(res, tgt) + + def optimize_compare(self, string): + # Tests all paths of the optimization function against + # conventional einsum + operands = [string] + terms = string.split('->')[0].split(',') + for term in terms: + dims = [global_size_dict[x] for x in term] + operands.append(np.random.rand(*dims)) + + noopt = np.einsum(*operands, optimize=False) + opt = np.einsum(*operands, optimize='greedy') + assert_almost_equal(opt, noopt) + opt = np.einsum(*operands, optimize='optimal') + assert_almost_equal(opt, noopt) + + def test_hadamard_like_products(self): + # Hadamard outer products + self.optimize_compare('a,ab,abc->abc') + self.optimize_compare('a,b,ab->ab') + + def test_index_transformations(self): + # Simple index transformation cases + self.optimize_compare('ea,fb,gc,hd,abcd->efgh') + self.optimize_compare('ea,fb,abcd,gc,hd->efgh') + self.optimize_compare('abcd,ea,fb,gc,hd->efgh') + + def test_complex(self): + # Long test cases + self.optimize_compare('acdf,jbje,gihb,hfac,gfac,gifabc,hfac') + self.optimize_compare('acdf,jbje,gihb,hfac,gfac,gifabc,hfac') + self.optimize_compare('cd,bdhe,aidb,hgca,gc,hgibcd,hgac') + self.optimize_compare('abhe,hidj,jgba,hiab,gab') + self.optimize_compare('bde,cdh,agdb,hica,ibd,hgicd,hiac') + self.optimize_compare('chd,bde,agbc,hiad,hgc,hgi,hiad') + self.optimize_compare('chd,bde,agbc,hiad,bdi,cgh,agdb') + self.optimize_compare('bdhe,acad,hiab,agac,hibd') + + def test_collapse(self): + # Inner products + self.optimize_compare('ab,ab,c->') + self.optimize_compare('ab,ab,c->c') + self.optimize_compare('ab,ab,cd,cd->') + self.optimize_compare('ab,ab,cd,cd->ac') + self.optimize_compare('ab,ab,cd,cd->cd') + self.optimize_compare('ab,ab,cd,cd,ef,ef->') + + def test_expand(self): + # Outer products + self.optimize_compare('ab,cd,ef->abcdef') + self.optimize_compare('ab,cd,ef->acdf') + self.optimize_compare('ab,cd,de->abcde') + self.optimize_compare('ab,cd,de->be') + self.optimize_compare('ab,bcd,cd->abcd') + self.optimize_compare('ab,bcd,cd->abd') + + def test_edge_cases(self): + # Difficult edge cases for optimization + self.optimize_compare('eb,cb,fb->cef') + self.optimize_compare('dd,fb,be,cdb->cef') + self.optimize_compare('bca,cdb,dbf,afc->') + self.optimize_compare('dcc,fce,ea,dbf->ab') + self.optimize_compare('fdf,cdd,ccd,afe->ae') + self.optimize_compare('abcd,ad') + self.optimize_compare('ed,fcd,ff,bcf->be') + self.optimize_compare('baa,dcf,af,cde->be') + self.optimize_compare('bd,db,eac->ace') + self.optimize_compare('fff,fae,bef,def->abd') + self.optimize_compare('efc,dbc,acf,fd->abe') + self.optimize_compare('ba,ac,da->bcd') + + def test_inner_product(self): + # Inner products + self.optimize_compare('ab,ab') + self.optimize_compare('ab,ba') + self.optimize_compare('abc,abc') + self.optimize_compare('abc,bac') + self.optimize_compare('abc,cba') + + def test_random_cases(self): + # Randomly built test cases + self.optimize_compare('aab,fa,df,ecc->bde') + self.optimize_compare('ecb,fef,bad,ed->ac') + self.optimize_compare('bcf,bbb,fbf,fc->') + self.optimize_compare('bb,ff,be->e') + self.optimize_compare('bcb,bb,fc,fff->') + self.optimize_compare('fbb,dfd,fc,fc->') + self.optimize_compare('afd,ba,cc,dc->bf') + self.optimize_compare('adb,bc,fa,cfc->d') + self.optimize_compare('bbd,bda,fc,db->acf') + self.optimize_compare('dba,ead,cad->bce') + self.optimize_compare('aef,fbc,dca->bde') + + +class TestEinSumPath(object): + def build_operands(self, string, size_dict=global_size_dict): + + # Builds views based off initial operands + operands = [string] + terms = string.split('->')[0].split(',') + for term in terms: + dims = [size_dict[x] for x in term] + operands.append(np.random.rand(*dims)) + + return operands + + def assert_path_equal(self, comp, benchmark): + # Checks if list of tuples are equivalent + ret = (len(comp) == len(benchmark)) + assert_(ret) + for pos in range(len(comp) - 1): + ret &= isinstance(comp[pos + 1], tuple) + ret &= (comp[pos + 1] == benchmark[pos + 1]) + assert_(ret) + + def test_memory_contraints(self): + # Ensure memory constraints are satisfied + + outer_test = self.build_operands('a,b,c->abc') + + path, path_str = np.einsum_path(*outer_test, optimize=('greedy', 0)) + self.assert_path_equal(path, ['einsum_path', (0, 1, 2)]) + + path, path_str = np.einsum_path(*outer_test, optimize=('optimal', 0)) + self.assert_path_equal(path, ['einsum_path', (0, 1, 2)]) + + long_test = self.build_operands('acdf,jbje,gihb,hfac') + path, path_str = np.einsum_path(*long_test, optimize=('greedy', 0)) + self.assert_path_equal(path, ['einsum_path', (0, 1, 2, 3)]) + + path, path_str = np.einsum_path(*long_test, optimize=('optimal', 0)) + self.assert_path_equal(path, ['einsum_path', (0, 1, 2, 3)]) + + def test_long_paths(self): + # Long complex cases + + # Long test 1 + long_test1 = self.build_operands('acdf,jbje,gihb,hfac,gfac,gifabc,hfac') + path, path_str = np.einsum_path(*long_test1, optimize='greedy') + self.assert_path_equal(path, ['einsum_path', + (1, 4), (2, 4), (1, 4), (1, 3), (1, 2), (0, 1)]) + + path, path_str = np.einsum_path(*long_test1, optimize='optimal') + self.assert_path_equal(path, ['einsum_path', + (3, 6), (3, 4), (2, 4), (2, 3), (0, 2), (0, 1)]) + + # Long test 2 + long_test2 = self.build_operands('chd,bde,agbc,hiad,bdi,cgh,agdb') + path, path_str = np.einsum_path(*long_test2, optimize='greedy') + self.assert_path_equal(path, ['einsum_path', + (3, 4), (0, 3), (3, 4), (1, 3), (1, 2), (0, 1)]) + + path, path_str = np.einsum_path(*long_test2, optimize='optimal') + self.assert_path_equal(path, ['einsum_path', + (0, 5), (1, 4), (3, 4), (1, 3), (1, 2), (0, 1)]) + + def test_edge_paths(self): + # Difficult edge cases + + # Edge test1 + edge_test1 = self.build_operands('eb,cb,fb->cef') + path, path_str = np.einsum_path(*edge_test1, optimize='greedy') + self.assert_path_equal(path, ['einsum_path', (0, 2), (0, 1)]) + + path, path_str = np.einsum_path(*edge_test1, optimize='optimal') + self.assert_path_equal(path, ['einsum_path', (0, 2), (0, 1)]) + + # Edge test2 + edge_test2 = self.build_operands('dd,fb,be,cdb->cef') + path, path_str = np.einsum_path(*edge_test2, optimize='greedy') + self.assert_path_equal(path, ['einsum_path', (0, 3), (0, 1), (0, 1)]) + + path, path_str = np.einsum_path(*edge_test2, optimize='optimal') + self.assert_path_equal(path, ['einsum_path', (0, 3), (0, 1), (0, 1)]) + + # Edge test3 + edge_test3 = self.build_operands('bca,cdb,dbf,afc->') + path, path_str = np.einsum_path(*edge_test3, optimize='greedy') + self.assert_path_equal(path, ['einsum_path', (1, 2), (0, 2), (0, 1)]) + + path, path_str = np.einsum_path(*edge_test3, optimize='optimal') + self.assert_path_equal(path, ['einsum_path', (1, 2), (0, 2), (0, 1)]) + + # Edge test4 + edge_test4 = self.build_operands('dcc,fce,ea,dbf->ab') + path, path_str = np.einsum_path(*edge_test4, optimize='greedy') + self.assert_path_equal(path, ['einsum_path', (0, 3), (0, 2), (0, 1)]) + + path, path_str = np.einsum_path(*edge_test4, optimize='optimal') + self.assert_path_equal(path, ['einsum_path', (1, 2), (0, 2), (0, 1)]) + + # Edge test5 + edge_test4 = self.build_operands('a,ac,ab,ad,cd,bd,bc->', + size_dict={"a": 20, "b": 20, "c": 20, "d": 20}) + path, path_str = np.einsum_path(*edge_test4, optimize='greedy') + self.assert_path_equal(path, ['einsum_path', (0, 1), (0, 1, 2, 3, 4, 5)]) + + path, path_str = np.einsum_path(*edge_test4, optimize='optimal') + self.assert_path_equal(path, ['einsum_path', (0, 1), (0, 1, 2, 3, 4, 5)]) + + + def test_path_type_input(self): + # Test explicit path handeling + path_test = self.build_operands('dcc,fce,ea,dbf->ab') + + path, path_str = np.einsum_path(*path_test, optimize=False) + self.assert_path_equal(path, ['einsum_path', (0, 1, 2, 3)]) + + path, path_str = np.einsum_path(*path_test, optimize=True) + self.assert_path_equal(path, ['einsum_path', (0, 3), (0, 2), (0, 1)]) + + exp_path = ['einsum_path', (0, 2), (0, 2), (0, 1)] + path, path_str = np.einsum_path(*path_test, optimize=exp_path) + self.assert_path_equal(path, exp_path) + + # Double check einsum works on the input path + noopt = np.einsum(*path_test, optimize=False) + opt = np.einsum(*path_test, optimize=exp_path) + assert_almost_equal(noopt, opt) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_errstate.py b/numpy/core/tests/test_errstate.py new file mode 100644 index 0000000..ae06af7 --- /dev/null +++ b/numpy/core/tests/test_errstate.py @@ -0,0 +1,52 @@ +from __future__ import division, absolute_import, print_function + +import platform + +import numpy as np +from numpy.testing import assert_, run_module_suite, dec + + +class TestErrstate(object): + @dec.skipif(platform.machine() == "armv5tel", "See gh-413.") + def test_invalid(self): + with np.errstate(all='raise', under='ignore'): + a = -np.arange(3) + # This should work + with np.errstate(invalid='ignore'): + np.sqrt(a) + # While this should fail! + try: + np.sqrt(a) + except FloatingPointError: + pass + else: + self.fail("Did not raise an invalid error") + + def test_divide(self): + with np.errstate(all='raise', under='ignore'): + a = -np.arange(3) + # This should work + with np.errstate(divide='ignore'): + a // 0 + # While this should fail! + try: + a // 0 + except FloatingPointError: + pass + else: + self.fail("Did not raise divide by zero error") + + def test_errcall(self): + def foo(*args): + print(args) + + olderrcall = np.geterrcall() + with np.errstate(call=foo): + assert_(np.geterrcall() is foo, 'call is not foo') + with np.errstate(call=None): + assert_(np.geterrcall() is None, 'call is not None') + assert_(np.geterrcall() is olderrcall, 'call is not olderrcall') + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_extint128.py b/numpy/core/tests/test_extint128.py new file mode 100644 index 0000000..d87585d --- /dev/null +++ b/numpy/core/tests/test_extint128.py @@ -0,0 +1,226 @@ +from __future__ import division, absolute_import, print_function + +import sys +import itertools +import contextlib +import operator + +import numpy as np +import numpy.core.multiarray_tests as mt +from numpy.compat import long + +from numpy.testing import assert_raises, assert_equal, dec + + +INT64_MAX = np.iinfo(np.int64).max +INT64_MIN = np.iinfo(np.int64).min +INT64_MID = 2**32 + +# int128 is not two's complement, the sign bit is separate +INT128_MAX = 2**128 - 1 +INT128_MIN = -INT128_MAX +INT128_MID = 2**64 + +INT64_VALUES = ( + [INT64_MIN + j for j in range(20)] + + [INT64_MAX - j for j in range(20)] + + [INT64_MID + j for j in range(-20, 20)] + + [2*INT64_MID + j for j in range(-20, 20)] + + [INT64_MID//2 + j for j in range(-20, 20)] + + list(range(-70, 70)) +) + +INT128_VALUES = ( + [INT128_MIN + j for j in range(20)] + + [INT128_MAX - j for j in range(20)] + + [INT128_MID + j for j in range(-20, 20)] + + [2*INT128_MID + j for j in range(-20, 20)] + + [INT128_MID//2 + j for j in range(-20, 20)] + + list(range(-70, 70)) + + [False] # negative zero +) + +INT64_POS_VALUES = [x for x in INT64_VALUES if x > 0] + + +@contextlib.contextmanager +def exc_iter(*args): + """ + Iterate over Cartesian product of *args, and if an exception is raised, + add information of the current iterate. + """ + + value = [None] + + def iterate(): + for v in itertools.product(*args): + value[0] = v + yield v + + try: + yield iterate() + except Exception: + import traceback + msg = "At: %r\n%s" % (repr(value[0]), + traceback.format_exc()) + raise AssertionError(msg) + + +def test_safe_binop(): + # Test checked arithmetic routines + + ops = [ + (operator.add, 1), + (operator.sub, 2), + (operator.mul, 3) + ] + + with exc_iter(ops, INT64_VALUES, INT64_VALUES) as it: + for xop, a, b in it: + pyop, op = xop + c = pyop(a, b) + + if not (INT64_MIN <= c <= INT64_MAX): + assert_raises(OverflowError, mt.extint_safe_binop, a, b, op) + else: + d = mt.extint_safe_binop(a, b, op) + if c != d: + # assert_equal is slow + assert_equal(d, c) + + +def test_to_128(): + with exc_iter(INT64_VALUES) as it: + for a, in it: + b = mt.extint_to_128(a) + if a != b: + assert_equal(b, a) + + +def test_to_64(): + with exc_iter(INT128_VALUES) as it: + for a, in it: + if not (INT64_MIN <= a <= INT64_MAX): + assert_raises(OverflowError, mt.extint_to_64, a) + else: + b = mt.extint_to_64(a) + if a != b: + assert_equal(b, a) + + +def test_mul_64_64(): + with exc_iter(INT64_VALUES, INT64_VALUES) as it: + for a, b in it: + c = a * b + d = mt.extint_mul_64_64(a, b) + if c != d: + assert_equal(d, c) + + +def test_add_128(): + with exc_iter(INT128_VALUES, INT128_VALUES) as it: + for a, b in it: + c = a + b + if not (INT128_MIN <= c <= INT128_MAX): + assert_raises(OverflowError, mt.extint_add_128, a, b) + else: + d = mt.extint_add_128(a, b) + if c != d: + assert_equal(d, c) + + +def test_sub_128(): + with exc_iter(INT128_VALUES, INT128_VALUES) as it: + for a, b in it: + c = a - b + if not (INT128_MIN <= c <= INT128_MAX): + assert_raises(OverflowError, mt.extint_sub_128, a, b) + else: + d = mt.extint_sub_128(a, b) + if c != d: + assert_equal(d, c) + + +def test_neg_128(): + with exc_iter(INT128_VALUES) as it: + for a, in it: + b = -a + c = mt.extint_neg_128(a) + if b != c: + assert_equal(c, b) + + +def test_shl_128(): + with exc_iter(INT128_VALUES) as it: + for a, in it: + if a < 0: + b = -(((-a) << 1) & (2**128-1)) + else: + b = (a << 1) & (2**128-1) + c = mt.extint_shl_128(a) + if b != c: + assert_equal(c, b) + + +def test_shr_128(): + with exc_iter(INT128_VALUES) as it: + for a, in it: + if a < 0: + b = -((-a) >> 1) + else: + b = a >> 1 + c = mt.extint_shr_128(a) + if b != c: + assert_equal(c, b) + + +def test_gt_128(): + with exc_iter(INT128_VALUES, INT128_VALUES) as it: + for a, b in it: + c = a > b + d = mt.extint_gt_128(a, b) + if c != d: + assert_equal(d, c) + + +@dec.slow +def test_divmod_128_64(): + with exc_iter(INT128_VALUES, INT64_POS_VALUES) as it: + for a, b in it: + if a >= 0: + c, cr = divmod(a, b) + else: + c, cr = divmod(-a, b) + c = -c + cr = -cr + + d, dr = mt.extint_divmod_128_64(a, b) + + if c != d or d != dr or b*d + dr != a: + assert_equal(d, c) + assert_equal(dr, cr) + assert_equal(b*d + dr, a) + + +def test_floordiv_128_64(): + with exc_iter(INT128_VALUES, INT64_POS_VALUES) as it: + for a, b in it: + c = a // b + d = mt.extint_floordiv_128_64(a, b) + + if c != d: + assert_equal(d, c) + + +def test_ceildiv_128_64(): + with exc_iter(INT128_VALUES, INT64_POS_VALUES) as it: + for a, b in it: + c = (a + b - 1) // b + d = mt.extint_ceildiv_128_64(a, b) + + if c != d: + assert_equal(d, c) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_function_base.py b/numpy/core/tests/test_function_base.py new file mode 100644 index 0000000..bffe523 --- /dev/null +++ b/numpy/core/tests/test_function_base.py @@ -0,0 +1,325 @@ +from __future__ import division, absolute_import, print_function + +from numpy import (logspace, linspace, geomspace, dtype, array, sctypes, + arange, isnan, ndarray, sqrt, nextafter) +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, + assert_array_equal, assert_allclose, suppress_warnings +) + + +class PhysicalQuantity(float): + def __new__(cls, value): + return float.__new__(cls, value) + + def __add__(self, x): + assert_(isinstance(x, PhysicalQuantity)) + return PhysicalQuantity(float(x) + float(self)) + __radd__ = __add__ + + def __sub__(self, x): + assert_(isinstance(x, PhysicalQuantity)) + return PhysicalQuantity(float(self) - float(x)) + + def __rsub__(self, x): + assert_(isinstance(x, PhysicalQuantity)) + return PhysicalQuantity(float(x) - float(self)) + + def __mul__(self, x): + return PhysicalQuantity(float(x) * float(self)) + __rmul__ = __mul__ + + def __div__(self, x): + return PhysicalQuantity(float(self) / float(x)) + + def __rdiv__(self, x): + return PhysicalQuantity(float(x) / float(self)) + + +class PhysicalQuantity2(ndarray): + __array_priority__ = 10 + + +class TestLogspace(object): + + def test_basic(self): + y = logspace(0, 6) + assert_(len(y) == 50) + y = logspace(0, 6, num=100) + assert_(y[-1] == 10 ** 6) + y = logspace(0, 6, endpoint=0) + assert_(y[-1] < 10 ** 6) + y = logspace(0, 6, num=7) + assert_array_equal(y, [1, 10, 100, 1e3, 1e4, 1e5, 1e6]) + + def test_dtype(self): + y = logspace(0, 6, dtype='float32') + assert_equal(y.dtype, dtype('float32')) + y = logspace(0, 6, dtype='float64') + assert_equal(y.dtype, dtype('float64')) + y = logspace(0, 6, dtype='int32') + assert_equal(y.dtype, dtype('int32')) + + def test_physical_quantities(self): + a = PhysicalQuantity(1.0) + b = PhysicalQuantity(5.0) + assert_equal(logspace(a, b), logspace(1.0, 5.0)) + + def test_subclass(self): + a = array(1).view(PhysicalQuantity2) + b = array(7).view(PhysicalQuantity2) + ls = logspace(a, b) + assert type(ls) is PhysicalQuantity2 + assert_equal(ls, logspace(1.0, 7.0)) + ls = logspace(a, b, 1) + assert type(ls) is PhysicalQuantity2 + assert_equal(ls, logspace(1.0, 7.0, 1)) + + +class TestGeomspace(object): + + def test_basic(self): + y = geomspace(1, 1e6) + assert_(len(y) == 50) + y = geomspace(1, 1e6, num=100) + assert_(y[-1] == 10 ** 6) + y = geomspace(1, 1e6, endpoint=False) + assert_(y[-1] < 10 ** 6) + y = geomspace(1, 1e6, num=7) + assert_array_equal(y, [1, 10, 100, 1e3, 1e4, 1e5, 1e6]) + + y = geomspace(8, 2, num=3) + assert_allclose(y, [8, 4, 2]) + assert_array_equal(y.imag, 0) + + y = geomspace(-1, -100, num=3) + assert_array_equal(y, [-1, -10, -100]) + assert_array_equal(y.imag, 0) + + y = geomspace(-100, -1, num=3) + assert_array_equal(y, [-100, -10, -1]) + assert_array_equal(y.imag, 0) + + def test_complex(self): + # Purely imaginary + y = geomspace(1j, 16j, num=5) + assert_allclose(y, [1j, 2j, 4j, 8j, 16j]) + assert_array_equal(y.real, 0) + + y = geomspace(-4j, -324j, num=5) + assert_allclose(y, [-4j, -12j, -36j, -108j, -324j]) + assert_array_equal(y.real, 0) + + y = geomspace(1+1j, 1000+1000j, num=4) + assert_allclose(y, [1+1j, 10+10j, 100+100j, 1000+1000j]) + + y = geomspace(-1+1j, -1000+1000j, num=4) + assert_allclose(y, [-1+1j, -10+10j, -100+100j, -1000+1000j]) + + # Logarithmic spirals + y = geomspace(-1, 1, num=3, dtype=complex) + assert_allclose(y, [-1, 1j, +1]) + + y = geomspace(0+3j, -3+0j, 3) + assert_allclose(y, [0+3j, -3/sqrt(2)+3j/sqrt(2), -3+0j]) + y = geomspace(0+3j, 3+0j, 3) + assert_allclose(y, [0+3j, 3/sqrt(2)+3j/sqrt(2), 3+0j]) + y = geomspace(-3+0j, 0-3j, 3) + assert_allclose(y, [-3+0j, -3/sqrt(2)-3j/sqrt(2), 0-3j]) + y = geomspace(0+3j, -3+0j, 3) + assert_allclose(y, [0+3j, -3/sqrt(2)+3j/sqrt(2), -3+0j]) + y = geomspace(-2-3j, 5+7j, 7) + assert_allclose(y, [-2-3j, -0.29058977-4.15771027j, + 2.08885354-4.34146838j, 4.58345529-3.16355218j, + 6.41401745-0.55233457j, 6.75707386+3.11795092j, + 5+7j]) + + # Type promotion should prevent the -5 from becoming a NaN + y = geomspace(3j, -5, 2) + assert_allclose(y, [3j, -5]) + y = geomspace(-5, 3j, 2) + assert_allclose(y, [-5, 3j]) + + def test_dtype(self): + y = geomspace(1, 1e6, dtype='float32') + assert_equal(y.dtype, dtype('float32')) + y = geomspace(1, 1e6, dtype='float64') + assert_equal(y.dtype, dtype('float64')) + y = geomspace(1, 1e6, dtype='int32') + assert_equal(y.dtype, dtype('int32')) + + # Native types + y = geomspace(1, 1e6, dtype=float) + assert_equal(y.dtype, dtype('float_')) + y = geomspace(1, 1e6, dtype=complex) + assert_equal(y.dtype, dtype('complex')) + + def test_array_scalar(self): + lim1 = array([120, 100], dtype="int8") + lim2 = array([-120, -100], dtype="int8") + lim3 = array([1200, 1000], dtype="uint16") + t1 = geomspace(lim1[0], lim1[1], 5) + t2 = geomspace(lim2[0], lim2[1], 5) + t3 = geomspace(lim3[0], lim3[1], 5) + t4 = geomspace(120.0, 100.0, 5) + t5 = geomspace(-120.0, -100.0, 5) + t6 = geomspace(1200.0, 1000.0, 5) + + # t3 uses float32, t6 uses float64 + assert_allclose(t1, t4, rtol=1e-2) + assert_allclose(t2, t5, rtol=1e-2) + assert_allclose(t3, t6, rtol=1e-5) + + def test_physical_quantities(self): + a = PhysicalQuantity(1.0) + b = PhysicalQuantity(5.0) + assert_equal(geomspace(a, b), geomspace(1.0, 5.0)) + + def test_subclass(self): + a = array(1).view(PhysicalQuantity2) + b = array(7).view(PhysicalQuantity2) + gs = geomspace(a, b) + assert type(gs) is PhysicalQuantity2 + assert_equal(gs, geomspace(1.0, 7.0)) + gs = geomspace(a, b, 1) + assert type(gs) is PhysicalQuantity2 + assert_equal(gs, geomspace(1.0, 7.0, 1)) + + def test_bounds(self): + assert_raises(ValueError, geomspace, 0, 10) + assert_raises(ValueError, geomspace, 10, 0) + assert_raises(ValueError, geomspace, 0, 0) + + +class TestLinspace(object): + + def test_basic(self): + y = linspace(0, 10) + assert_(len(y) == 50) + y = linspace(2, 10, num=100) + assert_(y[-1] == 10) + y = linspace(2, 10, endpoint=0) + assert_(y[-1] < 10) + assert_raises(ValueError, linspace, 0, 10, num=-1) + + def test_corner(self): + y = list(linspace(0, 1, 1)) + assert_(y == [0.0], y) + with suppress_warnings() as sup: + sup.filter(DeprecationWarning, ".*safely interpreted as an integer") + y = list(linspace(0, 1, 2.5)) + assert_(y == [0.0, 1.0]) + + def test_type(self): + t1 = linspace(0, 1, 0).dtype + t2 = linspace(0, 1, 1).dtype + t3 = linspace(0, 1, 2).dtype + assert_equal(t1, t2) + assert_equal(t2, t3) + + def test_dtype(self): + y = linspace(0, 6, dtype='float32') + assert_equal(y.dtype, dtype('float32')) + y = linspace(0, 6, dtype='float64') + assert_equal(y.dtype, dtype('float64')) + y = linspace(0, 6, dtype='int32') + assert_equal(y.dtype, dtype('int32')) + + def test_array_scalar(self): + lim1 = array([-120, 100], dtype="int8") + lim2 = array([120, -100], dtype="int8") + lim3 = array([1200, 1000], dtype="uint16") + t1 = linspace(lim1[0], lim1[1], 5) + t2 = linspace(lim2[0], lim2[1], 5) + t3 = linspace(lim3[0], lim3[1], 5) + t4 = linspace(-120.0, 100.0, 5) + t5 = linspace(120.0, -100.0, 5) + t6 = linspace(1200.0, 1000.0, 5) + assert_equal(t1, t4) + assert_equal(t2, t5) + assert_equal(t3, t6) + + def test_complex(self): + lim1 = linspace(1 + 2j, 3 + 4j, 5) + t1 = array([1.0+2.j, 1.5+2.5j, 2.0+3j, 2.5+3.5j, 3.0+4j]) + lim2 = linspace(1j, 10, 5) + t2 = array([0.0+1.j, 2.5+0.75j, 5.0+0.5j, 7.5+0.25j, 10.0+0j]) + assert_equal(lim1, t1) + assert_equal(lim2, t2) + + def test_physical_quantities(self): + a = PhysicalQuantity(0.0) + b = PhysicalQuantity(1.0) + assert_equal(linspace(a, b), linspace(0.0, 1.0)) + + def test_subclass(self): + a = array(0).view(PhysicalQuantity2) + b = array(1).view(PhysicalQuantity2) + ls = linspace(a, b) + assert type(ls) is PhysicalQuantity2 + assert_equal(ls, linspace(0.0, 1.0)) + ls = linspace(a, b, 1) + assert type(ls) is PhysicalQuantity2 + assert_equal(ls, linspace(0.0, 1.0, 1)) + + def test_array_interface(self): + # Regression test for https://github.com/numpy/numpy/pull/6659 + # Ensure that start/stop can be objects that implement + # __array_interface__ and are convertible to numeric scalars + + class Arrayish(object): + """ + A generic object that supports the __array_interface__ and hence + can in principle be converted to a numeric scalar, but is not + otherwise recognized as numeric, but also happens to support + multiplication by floats. + + Data should be an object that implements the buffer interface, + and contains at least 4 bytes. + """ + + def __init__(self, data): + self._data = data + + @property + def __array_interface__(self): + # Ideally should be `'shape': ()` but the current interface + # does not allow that + return {'shape': (1,), 'typestr': ' 1) + assert_(info.minexp < -1) + assert_(info.maxexp > 1) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_half.py b/numpy/core/tests/test_half.py new file mode 100644 index 0000000..813cf95 --- /dev/null +++ b/numpy/core/tests/test_half.py @@ -0,0 +1,437 @@ +from __future__ import division, absolute_import, print_function + +import platform + +import numpy as np +from numpy import uint16, float16, float32, float64 +from numpy.testing import run_module_suite, assert_, assert_equal, dec + + +def assert_raises_fpe(strmatch, callable, *args, **kwargs): + try: + callable(*args, **kwargs) + except FloatingPointError as exc: + assert_(str(exc).find(strmatch) >= 0, + "Did not raise floating point %s error" % strmatch) + else: + assert_(False, + "Did not raise floating point %s error" % strmatch) + +class TestHalf(object): + def setup(self): + # An array of all possible float16 values + self.all_f16 = np.arange(0x10000, dtype=uint16) + self.all_f16.dtype = float16 + self.all_f32 = np.array(self.all_f16, dtype=float32) + self.all_f64 = np.array(self.all_f16, dtype=float64) + + # An array of all non-NaN float16 values, in sorted order + self.nonan_f16 = np.concatenate( + (np.arange(0xfc00, 0x7fff, -1, dtype=uint16), + np.arange(0x0000, 0x7c01, 1, dtype=uint16))) + self.nonan_f16.dtype = float16 + self.nonan_f32 = np.array(self.nonan_f16, dtype=float32) + self.nonan_f64 = np.array(self.nonan_f16, dtype=float64) + + # An array of all finite float16 values, in sorted order + self.finite_f16 = self.nonan_f16[1:-1] + self.finite_f32 = self.nonan_f32[1:-1] + self.finite_f64 = self.nonan_f64[1:-1] + + def test_half_conversions(self): + """Checks that all 16-bit values survive conversion + to/from 32-bit and 64-bit float""" + # Because the underlying routines preserve the NaN bits, every + # value is preserved when converting to/from other floats. + + # Convert from float32 back to float16 + b = np.array(self.all_f32, dtype=float16) + assert_equal(self.all_f16.view(dtype=uint16), + b.view(dtype=uint16)) + + # Convert from float64 back to float16 + b = np.array(self.all_f64, dtype=float16) + assert_equal(self.all_f16.view(dtype=uint16), + b.view(dtype=uint16)) + + # Convert float16 to longdouble and back + # This doesn't necessarily preserve the extra NaN bits, + # so exclude NaNs. + a_ld = np.array(self.nonan_f16, dtype=np.longdouble) + b = np.array(a_ld, dtype=float16) + assert_equal(self.nonan_f16.view(dtype=uint16), + b.view(dtype=uint16)) + + # Check the range for which all integers can be represented + i_int = np.arange(-2048, 2049) + i_f16 = np.array(i_int, dtype=float16) + j = np.array(i_f16, dtype=int) + assert_equal(i_int, j) + + def test_nans_infs(self): + with np.errstate(all='ignore'): + # Check some of the ufuncs + assert_equal(np.isnan(self.all_f16), np.isnan(self.all_f32)) + assert_equal(np.isinf(self.all_f16), np.isinf(self.all_f32)) + assert_equal(np.isfinite(self.all_f16), np.isfinite(self.all_f32)) + assert_equal(np.signbit(self.all_f16), np.signbit(self.all_f32)) + assert_equal(np.spacing(float16(65504)), np.inf) + + # Check comparisons of all values with NaN + nan = float16(np.nan) + + assert_(not (self.all_f16 == nan).any()) + assert_(not (nan == self.all_f16).any()) + + assert_((self.all_f16 != nan).all()) + assert_((nan != self.all_f16).all()) + + assert_(not (self.all_f16 < nan).any()) + assert_(not (nan < self.all_f16).any()) + + assert_(not (self.all_f16 <= nan).any()) + assert_(not (nan <= self.all_f16).any()) + + assert_(not (self.all_f16 > nan).any()) + assert_(not (nan > self.all_f16).any()) + + assert_(not (self.all_f16 >= nan).any()) + assert_(not (nan >= self.all_f16).any()) + + def test_half_values(self): + """Confirms a small number of known half values""" + a = np.array([1.0, -1.0, + 2.0, -2.0, + 0.0999755859375, 0.333251953125, # 1/10, 1/3 + 65504, -65504, # Maximum magnitude + 2.0**(-14), -2.0**(-14), # Minimum normal + 2.0**(-24), -2.0**(-24), # Minimum subnormal + 0, -1/1e1000, # Signed zeros + np.inf, -np.inf]) + b = np.array([0x3c00, 0xbc00, + 0x4000, 0xc000, + 0x2e66, 0x3555, + 0x7bff, 0xfbff, + 0x0400, 0x8400, + 0x0001, 0x8001, + 0x0000, 0x8000, + 0x7c00, 0xfc00], dtype=uint16) + b.dtype = float16 + assert_equal(a, b) + + def test_half_rounding(self): + """Checks that rounding when converting to half is correct""" + a = np.array([2.0**-25 + 2.0**-35, # Rounds to minimum subnormal + 2.0**-25, # Underflows to zero (nearest even mode) + 2.0**-26, # Underflows to zero + 1.0+2.0**-11 + 2.0**-16, # rounds to 1.0+2**(-10) + 1.0+2.0**-11, # rounds to 1.0 (nearest even mode) + 1.0+2.0**-12, # rounds to 1.0 + 65519, # rounds to 65504 + 65520], # rounds to inf + dtype=float64) + rounded = [2.0**-24, + 0.0, + 0.0, + 1.0+2.0**(-10), + 1.0, + 1.0, + 65504, + np.inf] + + # Check float64->float16 rounding + b = np.array(a, dtype=float16) + assert_equal(b, rounded) + + # Check float32->float16 rounding + a = np.array(a, dtype=float32) + b = np.array(a, dtype=float16) + assert_equal(b, rounded) + + def test_half_correctness(self): + """Take every finite float16, and check the casting functions with + a manual conversion.""" + + # Create an array of all finite float16s + a_bits = self.finite_f16.view(dtype=uint16) + + # Convert to 64-bit float manually + a_sgn = (-1.0)**((a_bits & 0x8000) >> 15) + a_exp = np.array((a_bits & 0x7c00) >> 10, dtype=np.int32) - 15 + a_man = (a_bits & 0x03ff) * 2.0**(-10) + # Implicit bit of normalized floats + a_man[a_exp != -15] += 1 + # Denormalized exponent is -14 + a_exp[a_exp == -15] = -14 + + a_manual = a_sgn * a_man * 2.0**a_exp + + a32_fail = np.nonzero(self.finite_f32 != a_manual)[0] + if len(a32_fail) != 0: + bad_index = a32_fail[0] + assert_equal(self.finite_f32, a_manual, + "First non-equal is half value %x -> %g != %g" % + (self.finite_f16[bad_index], + self.finite_f32[bad_index], + a_manual[bad_index])) + + a64_fail = np.nonzero(self.finite_f64 != a_manual)[0] + if len(a64_fail) != 0: + bad_index = a64_fail[0] + assert_equal(self.finite_f64, a_manual, + "First non-equal is half value %x -> %g != %g" % + (self.finite_f16[bad_index], + self.finite_f64[bad_index], + a_manual[bad_index])) + + def test_half_ordering(self): + """Make sure comparisons are working right""" + + # All non-NaN float16 values in reverse order + a = self.nonan_f16[::-1].copy() + + # 32-bit float copy + b = np.array(a, dtype=float32) + + # Should sort the same + a.sort() + b.sort() + assert_equal(a, b) + + # Comparisons should work + assert_((a[:-1] <= a[1:]).all()) + assert_(not (a[:-1] > a[1:]).any()) + assert_((a[1:] >= a[:-1]).all()) + assert_(not (a[1:] < a[:-1]).any()) + # All != except for +/-0 + assert_equal(np.nonzero(a[:-1] < a[1:])[0].size, a.size-2) + assert_equal(np.nonzero(a[1:] > a[:-1])[0].size, a.size-2) + + def test_half_funcs(self): + """Test the various ArrFuncs""" + + # fill + assert_equal(np.arange(10, dtype=float16), + np.arange(10, dtype=float32)) + + # fillwithscalar + a = np.zeros((5,), dtype=float16) + a.fill(1) + assert_equal(a, np.ones((5,), dtype=float16)) + + # nonzero and copyswap + a = np.array([0, 0, -1, -1/1e20, 0, 2.0**-24, 7.629e-6], dtype=float16) + assert_equal(a.nonzero()[0], + [2, 5, 6]) + a = a.byteswap().newbyteorder() + assert_equal(a.nonzero()[0], + [2, 5, 6]) + + # dot + a = np.arange(0, 10, 0.5, dtype=float16) + b = np.ones((20,), dtype=float16) + assert_equal(np.dot(a, b), + 95) + + # argmax + a = np.array([0, -np.inf, -2, 0.5, 12.55, 7.3, 2.1, 12.4], dtype=float16) + assert_equal(a.argmax(), + 4) + a = np.array([0, -np.inf, -2, np.inf, 12.55, np.nan, 2.1, 12.4], dtype=float16) + assert_equal(a.argmax(), + 5) + + # getitem + a = np.arange(10, dtype=float16) + for i in range(10): + assert_equal(a.item(i), i) + + def test_spacing_nextafter(self): + """Test np.spacing and np.nextafter""" + # All non-negative finite #'s + a = np.arange(0x7c00, dtype=uint16) + hinf = np.array((np.inf,), dtype=float16) + a_f16 = a.view(dtype=float16) + + assert_equal(np.spacing(a_f16[:-1]), a_f16[1:]-a_f16[:-1]) + + assert_equal(np.nextafter(a_f16[:-1], hinf), a_f16[1:]) + assert_equal(np.nextafter(a_f16[0], -hinf), -a_f16[1]) + assert_equal(np.nextafter(a_f16[1:], -hinf), a_f16[:-1]) + + # switch to negatives + a |= 0x8000 + + assert_equal(np.spacing(a_f16[0]), np.spacing(a_f16[1])) + assert_equal(np.spacing(a_f16[1:]), a_f16[:-1]-a_f16[1:]) + + assert_equal(np.nextafter(a_f16[0], hinf), -a_f16[1]) + assert_equal(np.nextafter(a_f16[1:], hinf), a_f16[:-1]) + assert_equal(np.nextafter(a_f16[:-1], -hinf), a_f16[1:]) + + def test_half_ufuncs(self): + """Test the various ufuncs""" + + a = np.array([0, 1, 2, 4, 2], dtype=float16) + b = np.array([-2, 5, 1, 4, 3], dtype=float16) + c = np.array([0, -1, -np.inf, np.nan, 6], dtype=float16) + + assert_equal(np.add(a, b), [-2, 6, 3, 8, 5]) + assert_equal(np.subtract(a, b), [2, -4, 1, 0, -1]) + assert_equal(np.multiply(a, b), [0, 5, 2, 16, 6]) + assert_equal(np.divide(a, b), [0, 0.199951171875, 2, 1, 0.66650390625]) + + assert_equal(np.equal(a, b), [False, False, False, True, False]) + assert_equal(np.not_equal(a, b), [True, True, True, False, True]) + assert_equal(np.less(a, b), [False, True, False, False, True]) + assert_equal(np.less_equal(a, b), [False, True, False, True, True]) + assert_equal(np.greater(a, b), [True, False, True, False, False]) + assert_equal(np.greater_equal(a, b), [True, False, True, True, False]) + assert_equal(np.logical_and(a, b), [False, True, True, True, True]) + assert_equal(np.logical_or(a, b), [True, True, True, True, True]) + assert_equal(np.logical_xor(a, b), [True, False, False, False, False]) + assert_equal(np.logical_not(a), [True, False, False, False, False]) + + assert_equal(np.isnan(c), [False, False, False, True, False]) + assert_equal(np.isinf(c), [False, False, True, False, False]) + assert_equal(np.isfinite(c), [True, True, False, False, True]) + assert_equal(np.signbit(b), [True, False, False, False, False]) + + assert_equal(np.copysign(b, a), [2, 5, 1, 4, 3]) + + assert_equal(np.maximum(a, b), [0, 5, 2, 4, 3]) + x = np.maximum(b, c) + assert_(np.isnan(x[3])) + x[3] = 0 + assert_equal(x, [0, 5, 1, 0, 6]) + assert_equal(np.minimum(a, b), [-2, 1, 1, 4, 2]) + x = np.minimum(b, c) + assert_(np.isnan(x[3])) + x[3] = 0 + assert_equal(x, [-2, -1, -np.inf, 0, 3]) + assert_equal(np.fmax(a, b), [0, 5, 2, 4, 3]) + assert_equal(np.fmax(b, c), [0, 5, 1, 4, 6]) + assert_equal(np.fmin(a, b), [-2, 1, 1, 4, 2]) + assert_equal(np.fmin(b, c), [-2, -1, -np.inf, 4, 3]) + + assert_equal(np.floor_divide(a, b), [0, 0, 2, 1, 0]) + assert_equal(np.remainder(a, b), [0, 1, 0, 0, 2]) + assert_equal(np.divmod(a, b), ([0, 0, 2, 1, 0], [0, 1, 0, 0, 2])) + assert_equal(np.square(b), [4, 25, 1, 16, 9]) + assert_equal(np.reciprocal(b), [-0.5, 0.199951171875, 1, 0.25, 0.333251953125]) + assert_equal(np.ones_like(b), [1, 1, 1, 1, 1]) + assert_equal(np.conjugate(b), b) + assert_equal(np.absolute(b), [2, 5, 1, 4, 3]) + assert_equal(np.negative(b), [2, -5, -1, -4, -3]) + assert_equal(np.positive(b), b) + assert_equal(np.sign(b), [-1, 1, 1, 1, 1]) + assert_equal(np.modf(b), ([0, 0, 0, 0, 0], b)) + assert_equal(np.frexp(b), ([-0.5, 0.625, 0.5, 0.5, 0.75], [2, 3, 1, 3, 2])) + assert_equal(np.ldexp(b, [0, 1, 2, 4, 2]), [-2, 10, 4, 64, 12]) + + def test_half_coercion(self): + """Test that half gets coerced properly with the other types""" + a16 = np.array((1,), dtype=float16) + a32 = np.array((1,), dtype=float32) + b16 = float16(1) + b32 = float32(1) + + assert_equal(np.power(a16, 2).dtype, float16) + assert_equal(np.power(a16, 2.0).dtype, float16) + assert_equal(np.power(a16, b16).dtype, float16) + assert_equal(np.power(a16, b32).dtype, float16) + assert_equal(np.power(a16, a16).dtype, float16) + assert_equal(np.power(a16, a32).dtype, float32) + + assert_equal(np.power(b16, 2).dtype, float64) + assert_equal(np.power(b16, 2.0).dtype, float64) + assert_equal(np.power(b16, b16).dtype, float16) + assert_equal(np.power(b16, b32).dtype, float32) + assert_equal(np.power(b16, a16).dtype, float16) + assert_equal(np.power(b16, a32).dtype, float32) + + assert_equal(np.power(a32, a16).dtype, float32) + assert_equal(np.power(a32, b16).dtype, float32) + assert_equal(np.power(b32, a16).dtype, float16) + assert_equal(np.power(b32, b16).dtype, float32) + + @dec.skipif(platform.machine() == "armv5tel", "See gh-413.") + def test_half_fpe(self): + with np.errstate(all='raise'): + sx16 = np.array((1e-4,), dtype=float16) + bx16 = np.array((1e4,), dtype=float16) + sy16 = float16(1e-4) + by16 = float16(1e4) + + # Underflow errors + assert_raises_fpe('underflow', lambda a, b:a*b, sx16, sx16) + assert_raises_fpe('underflow', lambda a, b:a*b, sx16, sy16) + assert_raises_fpe('underflow', lambda a, b:a*b, sy16, sx16) + assert_raises_fpe('underflow', lambda a, b:a*b, sy16, sy16) + assert_raises_fpe('underflow', lambda a, b:a/b, sx16, bx16) + assert_raises_fpe('underflow', lambda a, b:a/b, sx16, by16) + assert_raises_fpe('underflow', lambda a, b:a/b, sy16, bx16) + assert_raises_fpe('underflow', lambda a, b:a/b, sy16, by16) + assert_raises_fpe('underflow', lambda a, b:a/b, + float16(2.**-14), float16(2**11)) + assert_raises_fpe('underflow', lambda a, b:a/b, + float16(-2.**-14), float16(2**11)) + assert_raises_fpe('underflow', lambda a, b:a/b, + float16(2.**-14+2**-24), float16(2)) + assert_raises_fpe('underflow', lambda a, b:a/b, + float16(-2.**-14-2**-24), float16(2)) + assert_raises_fpe('underflow', lambda a, b:a/b, + float16(2.**-14+2**-23), float16(4)) + + # Overflow errors + assert_raises_fpe('overflow', lambda a, b:a*b, bx16, bx16) + assert_raises_fpe('overflow', lambda a, b:a*b, bx16, by16) + assert_raises_fpe('overflow', lambda a, b:a*b, by16, bx16) + assert_raises_fpe('overflow', lambda a, b:a*b, by16, by16) + assert_raises_fpe('overflow', lambda a, b:a/b, bx16, sx16) + assert_raises_fpe('overflow', lambda a, b:a/b, bx16, sy16) + assert_raises_fpe('overflow', lambda a, b:a/b, by16, sx16) + assert_raises_fpe('overflow', lambda a, b:a/b, by16, sy16) + assert_raises_fpe('overflow', lambda a, b:a+b, + float16(65504), float16(17)) + assert_raises_fpe('overflow', lambda a, b:a-b, + float16(-65504), float16(17)) + assert_raises_fpe('overflow', np.nextafter, float16(65504), float16(np.inf)) + assert_raises_fpe('overflow', np.nextafter, float16(-65504), float16(-np.inf)) + assert_raises_fpe('overflow', np.spacing, float16(65504)) + + # Invalid value errors + assert_raises_fpe('invalid', np.divide, float16(np.inf), float16(np.inf)) + assert_raises_fpe('invalid', np.spacing, float16(np.inf)) + assert_raises_fpe('invalid', np.spacing, float16(np.nan)) + assert_raises_fpe('invalid', np.nextafter, float16(np.inf), float16(0)) + assert_raises_fpe('invalid', np.nextafter, float16(-np.inf), float16(0)) + assert_raises_fpe('invalid', np.nextafter, float16(0), float16(np.nan)) + + # These should not raise + float16(65472)+float16(32) + float16(2**-13)/float16(2) + float16(2**-14)/float16(2**10) + np.spacing(float16(-65504)) + np.nextafter(float16(65504), float16(-np.inf)) + np.nextafter(float16(-65504), float16(np.inf)) + float16(2**-14)/float16(2**10) + float16(-2**-14)/float16(2**10) + float16(2**-14+2**-23)/float16(2) + float16(-2**-14-2**-23)/float16(2) + + def test_half_array_interface(self): + """Test that half is compatible with __array_interface__""" + class Dummy: + pass + + a = np.ones((1,), dtype=float16) + b = Dummy() + b.__array_interface__ = a.__array_interface__ + c = np.array(b) + assert_(c.dtype == float16) + assert_equal(a, c) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_indexerrors.py b/numpy/core/tests/test_indexerrors.py new file mode 100644 index 0000000..50919ff --- /dev/null +++ b/numpy/core/tests/test_indexerrors.py @@ -0,0 +1,126 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import run_module_suite, assert_raises + +class TestIndexErrors(object): + '''Tests to exercise indexerrors not covered by other tests.''' + + def test_arraytypes_fasttake(self): + 'take from a 0-length dimension' + x = np.empty((2, 3, 0, 4)) + assert_raises(IndexError, x.take, [0], axis=2) + assert_raises(IndexError, x.take, [1], axis=2) + assert_raises(IndexError, x.take, [0], axis=2, mode='wrap') + assert_raises(IndexError, x.take, [0], axis=2, mode='clip') + + def test_take_from_object(self): + # Check exception taking from object array + d = np.zeros(5, dtype=object) + assert_raises(IndexError, d.take, [6]) + + # Check exception taking from 0-d array + d = np.zeros((5, 0), dtype=object) + assert_raises(IndexError, d.take, [1], axis=1) + assert_raises(IndexError, d.take, [0], axis=1) + assert_raises(IndexError, d.take, [0]) + assert_raises(IndexError, d.take, [0], mode='wrap') + assert_raises(IndexError, d.take, [0], mode='clip') + + def test_multiindex_exceptions(self): + a = np.empty(5, dtype=object) + assert_raises(IndexError, a.item, 20) + a = np.empty((5, 0), dtype=object) + assert_raises(IndexError, a.item, (0, 0)) + + a = np.empty(5, dtype=object) + assert_raises(IndexError, a.itemset, 20, 0) + a = np.empty((5, 0), dtype=object) + assert_raises(IndexError, a.itemset, (0, 0), 0) + + def test_put_exceptions(self): + a = np.zeros((5, 5)) + assert_raises(IndexError, a.put, 100, 0) + a = np.zeros((5, 5), dtype=object) + assert_raises(IndexError, a.put, 100, 0) + a = np.zeros((5, 5, 0)) + assert_raises(IndexError, a.put, 100, 0) + a = np.zeros((5, 5, 0), dtype=object) + assert_raises(IndexError, a.put, 100, 0) + + def test_iterators_exceptions(self): + "cases in iterators.c" + def assign(obj, ind, val): + obj[ind] = val + + a = np.zeros([1, 2, 3]) + assert_raises(IndexError, lambda: a[0, 5, None, 2]) + assert_raises(IndexError, lambda: a[0, 5, 0, 2]) + assert_raises(IndexError, lambda: assign(a, (0, 5, None, 2), 1)) + assert_raises(IndexError, lambda: assign(a, (0, 5, 0, 2), 1)) + + a = np.zeros([1, 0, 3]) + assert_raises(IndexError, lambda: a[0, 0, None, 2]) + assert_raises(IndexError, lambda: assign(a, (0, 0, None, 2), 1)) + + a = np.zeros([1, 2, 3]) + assert_raises(IndexError, lambda: a.flat[10]) + assert_raises(IndexError, lambda: assign(a.flat, 10, 5)) + a = np.zeros([1, 0, 3]) + assert_raises(IndexError, lambda: a.flat[10]) + assert_raises(IndexError, lambda: assign(a.flat, 10, 5)) + + a = np.zeros([1, 2, 3]) + assert_raises(IndexError, lambda: a.flat[np.array(10)]) + assert_raises(IndexError, lambda: assign(a.flat, np.array(10), 5)) + a = np.zeros([1, 0, 3]) + assert_raises(IndexError, lambda: a.flat[np.array(10)]) + assert_raises(IndexError, lambda: assign(a.flat, np.array(10), 5)) + + a = np.zeros([1, 2, 3]) + assert_raises(IndexError, lambda: a.flat[np.array([10])]) + assert_raises(IndexError, lambda: assign(a.flat, np.array([10]), 5)) + a = np.zeros([1, 0, 3]) + assert_raises(IndexError, lambda: a.flat[np.array([10])]) + assert_raises(IndexError, lambda: assign(a.flat, np.array([10]), 5)) + + def test_mapping(self): + "cases from mapping.c" + + def assign(obj, ind, val): + obj[ind] = val + + a = np.zeros((0, 10)) + assert_raises(IndexError, lambda: a[12]) + + a = np.zeros((3, 5)) + assert_raises(IndexError, lambda: a[(10, 20)]) + assert_raises(IndexError, lambda: assign(a, (10, 20), 1)) + a = np.zeros((3, 0)) + assert_raises(IndexError, lambda: a[(1, 0)]) + assert_raises(IndexError, lambda: assign(a, (1, 0), 1)) + + a = np.zeros((10,)) + assert_raises(IndexError, lambda: assign(a, 10, 1)) + a = np.zeros((0,)) + assert_raises(IndexError, lambda: assign(a, 10, 1)) + + a = np.zeros((3, 5)) + assert_raises(IndexError, lambda: a[(1, [1, 20])]) + assert_raises(IndexError, lambda: assign(a, (1, [1, 20]), 1)) + a = np.zeros((3, 0)) + assert_raises(IndexError, lambda: a[(1, [0, 1])]) + assert_raises(IndexError, lambda: assign(a, (1, [0, 1]), 1)) + + def test_methods(self): + "cases from methods.c" + + a = np.zeros((3, 3)) + assert_raises(IndexError, lambda: a.item(100)) + assert_raises(IndexError, lambda: a.itemset(100, 1)) + a = np.zeros((0, 3)) + assert_raises(IndexError, lambda: a.item(100)) + assert_raises(IndexError, lambda: a.itemset(100, 1)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py new file mode 100644 index 0000000..df9eca6 --- /dev/null +++ b/numpy/core/tests/test_indexing.py @@ -0,0 +1,1318 @@ +from __future__ import division, absolute_import, print_function + +import sys +import warnings +import functools +import operator + +import numpy as np +from numpy.core.multiarray_tests import array_indexing +from itertools import product +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, + assert_array_equal, assert_warns, dec, HAS_REFCOUNT, suppress_warnings, +) + + +try: + cdll = None + if hasattr(sys, 'gettotalrefcount'): + try: + cdll = np.ctypeslib.load_library('multiarray_d', np.core.multiarray.__file__) + except OSError: + pass + if cdll is None: + cdll = np.ctypeslib.load_library('multiarray', np.core.multiarray.__file__) + _HAS_CTYPE = True +except ImportError: + _HAS_CTYPE = False + + +class TestIndexing(object): + def test_index_no_floats(self): + a = np.array([[[5]]]) + + assert_raises(IndexError, lambda: a[0.0]) + assert_raises(IndexError, lambda: a[0, 0.0]) + assert_raises(IndexError, lambda: a[0.0, 0]) + assert_raises(IndexError, lambda: a[0.0,:]) + assert_raises(IndexError, lambda: a[:, 0.0]) + assert_raises(IndexError, lambda: a[:, 0.0,:]) + assert_raises(IndexError, lambda: a[0.0,:,:]) + assert_raises(IndexError, lambda: a[0, 0, 0.0]) + assert_raises(IndexError, lambda: a[0.0, 0, 0]) + assert_raises(IndexError, lambda: a[0, 0.0, 0]) + assert_raises(IndexError, lambda: a[-1.4]) + assert_raises(IndexError, lambda: a[0, -1.4]) + assert_raises(IndexError, lambda: a[-1.4, 0]) + assert_raises(IndexError, lambda: a[-1.4,:]) + assert_raises(IndexError, lambda: a[:, -1.4]) + assert_raises(IndexError, lambda: a[:, -1.4,:]) + assert_raises(IndexError, lambda: a[-1.4,:,:]) + assert_raises(IndexError, lambda: a[0, 0, -1.4]) + assert_raises(IndexError, lambda: a[-1.4, 0, 0]) + assert_raises(IndexError, lambda: a[0, -1.4, 0]) + assert_raises(IndexError, lambda: a[0.0:, 0.0]) + assert_raises(IndexError, lambda: a[0.0:, 0.0,:]) + + def test_slicing_no_floats(self): + a = np.array([[5]]) + + # start as float. + assert_raises(TypeError, lambda: a[0.0:]) + assert_raises(TypeError, lambda: a[0:, 0.0:2]) + assert_raises(TypeError, lambda: a[0.0::2, :0]) + assert_raises(TypeError, lambda: a[0.0:1:2,:]) + assert_raises(TypeError, lambda: a[:, 0.0:]) + # stop as float. + assert_raises(TypeError, lambda: a[:0.0]) + assert_raises(TypeError, lambda: a[:0, 1:2.0]) + assert_raises(TypeError, lambda: a[:0.0:2, :0]) + assert_raises(TypeError, lambda: a[:0.0,:]) + assert_raises(TypeError, lambda: a[:, 0:4.0:2]) + # step as float. + assert_raises(TypeError, lambda: a[::1.0]) + assert_raises(TypeError, lambda: a[0:, :2:2.0]) + assert_raises(TypeError, lambda: a[1::4.0, :0]) + assert_raises(TypeError, lambda: a[::5.0,:]) + assert_raises(TypeError, lambda: a[:, 0:4:2.0]) + # mixed. + assert_raises(TypeError, lambda: a[1.0:2:2.0]) + assert_raises(TypeError, lambda: a[1.0::2.0]) + assert_raises(TypeError, lambda: a[0:, :2.0:2.0]) + assert_raises(TypeError, lambda: a[1.0:1:4.0, :0]) + assert_raises(TypeError, lambda: a[1.0:5.0:5.0,:]) + assert_raises(TypeError, lambda: a[:, 0.4:4.0:2.0]) + # should still get the DeprecationWarning if step = 0. + assert_raises(TypeError, lambda: a[::0.0]) + + def test_index_no_array_to_index(self): + # No non-scalar arrays. + a = np.array([[[1]]]) + + assert_raises(TypeError, lambda: a[a:a:a]) + + def test_none_index(self): + # `None` index adds newaxis + a = np.array([1, 2, 3]) + assert_equal(a[None], a[np.newaxis]) + assert_equal(a[None].ndim, a.ndim + 1) + + def test_empty_tuple_index(self): + # Empty tuple index creates a view + a = np.array([1, 2, 3]) + assert_equal(a[()], a) + assert_(a[()].base is a) + a = np.array(0) + assert_(isinstance(a[()], np.int_)) + + def test_void_scalar_empty_tuple(self): + s = np.zeros((), dtype='V4') + assert_equal(s[()].dtype, s.dtype) + assert_equal(s[()], s) + assert_equal(type(s[...]), np.ndarray) + + def test_same_kind_index_casting(self): + # Indexes should be cast with same-kind and not safe, even if that + # is somewhat unsafe. So test various different code paths. + index = np.arange(5) + u_index = index.astype(np.uintp) + arr = np.arange(10) + + assert_array_equal(arr[index], arr[u_index]) + arr[u_index] = np.arange(5) + assert_array_equal(arr, np.arange(10)) + + arr = np.arange(10).reshape(5, 2) + assert_array_equal(arr[index], arr[u_index]) + + arr[u_index] = np.arange(5)[:,None] + assert_array_equal(arr, np.arange(5)[:,None].repeat(2, axis=1)) + + arr = np.arange(25).reshape(5, 5) + assert_array_equal(arr[u_index, u_index], arr[index, index]) + + def test_empty_fancy_index(self): + # Empty list index creates an empty array + # with the same dtype (but with weird shape) + a = np.array([1, 2, 3]) + assert_equal(a[[]], []) + assert_equal(a[[]].dtype, a.dtype) + + b = np.array([], dtype=np.intp) + assert_equal(a[[]], []) + assert_equal(a[[]].dtype, a.dtype) + + b = np.array([]) + assert_raises(IndexError, a.__getitem__, b) + + def test_ellipsis_index(self): + a = np.array([[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]) + assert_(a[...] is not a) + assert_equal(a[...], a) + # `a[...]` was `a` in numpy <1.9. + assert_(a[...].base is a) + + # Slicing with ellipsis can skip an + # arbitrary number of dimensions + assert_equal(a[0, ...], a[0]) + assert_equal(a[0, ...], a[0,:]) + assert_equal(a[..., 0], a[:, 0]) + + # Slicing with ellipsis always results + # in an array, not a scalar + assert_equal(a[0, ..., 1], np.array(2)) + + # Assignment with `(Ellipsis,)` on 0-d arrays + b = np.array(1) + b[(Ellipsis,)] = 2 + assert_equal(b, 2) + + def test_single_int_index(self): + # Single integer index selects one row + a = np.array([[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]) + + assert_equal(a[0], [1, 2, 3]) + assert_equal(a[-1], [7, 8, 9]) + + # Index out of bounds produces IndexError + assert_raises(IndexError, a.__getitem__, 1 << 30) + # Index overflow produces IndexError + assert_raises(IndexError, a.__getitem__, 1 << 64) + + def test_single_bool_index(self): + # Single boolean index + a = np.array([[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]) + + assert_equal(a[np.array(True)], a[None]) + assert_equal(a[np.array(False)], a[None][0:0]) + + def test_boolean_shape_mismatch(self): + arr = np.ones((5, 4, 3)) + + index = np.array([True]) + assert_raises(IndexError, arr.__getitem__, index) + + index = np.array([False] * 6) + assert_raises(IndexError, arr.__getitem__, index) + + index = np.zeros((4, 4), dtype=bool) + assert_raises(IndexError, arr.__getitem__, index) + + assert_raises(IndexError, arr.__getitem__, (slice(None), index)) + + + def test_boolean_indexing_onedim(self): + # Indexing a 2-dimensional array with + # boolean array of length one + a = np.array([[ 0., 0., 0.]]) + b = np.array([ True], dtype=bool) + assert_equal(a[b], a) + # boolean assignment + a[b] = 1. + assert_equal(a, [[1., 1., 1.]]) + + def test_boolean_assignment_value_mismatch(self): + # A boolean assignment should fail when the shape of the values + # cannot be broadcast to the subscription. (see also gh-3458) + a = np.arange(4) + + def f(a, v): + a[a > -1] = v + + assert_raises(ValueError, f, a, []) + assert_raises(ValueError, f, a, [1, 2, 3]) + assert_raises(ValueError, f, a[:1], [1, 2, 3]) + + def test_boolean_assignment_needs_api(self): + # See also gh-7666 + # This caused a segfault on Python 2 due to the GIL not being + # held when the iterator does not need it, but the transfer function + # does + arr = np.zeros(1000) + indx = np.zeros(1000, dtype=bool) + indx[:100] = True + arr[indx] = np.ones(100, dtype=object) + + expected = np.zeros(1000) + expected[:100] = 1 + assert_array_equal(arr, expected) + + def test_boolean_indexing_twodim(self): + # Indexing a 2-dimensional array with + # 2-dimensional boolean array + a = np.array([[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]) + b = np.array([[ True, False, True], + [False, True, False], + [ True, False, True]]) + assert_equal(a[b], [1, 3, 5, 7, 9]) + assert_equal(a[b[1]], [[4, 5, 6]]) + assert_equal(a[b[0]], a[b[2]]) + + # boolean assignment + a[b] = 0 + assert_equal(a, [[0, 2, 0], + [4, 0, 6], + [0, 8, 0]]) + + def test_reverse_strides_and_subspace_bufferinit(self): + # This tests that the strides are not reversed for simple and + # subspace fancy indexing. + a = np.ones(5) + b = np.zeros(5, dtype=np.intp)[::-1] + c = np.arange(5)[::-1] + + a[b] = c + # If the strides are not reversed, the 0 in the arange comes last. + assert_equal(a[0], 0) + + # This also tests that the subspace buffer is initialized: + a = np.ones((5, 2)) + c = np.arange(10).reshape(5, 2)[::-1] + a[b, :] = c + assert_equal(a[0], [0, 1]) + + def test_reversed_strides_result_allocation(self): + # Test a bug when calculating the output strides for a result array + # when the subspace size was 1 (and test other cases as well) + a = np.arange(10)[:, None] + i = np.arange(10)[::-1] + assert_array_equal(a[i], a[i.copy('C')]) + + a = np.arange(20).reshape(-1, 2) + + def test_uncontiguous_subspace_assignment(self): + # During development there was a bug activating a skip logic + # based on ndim instead of size. + a = np.full((3, 4, 2), -1) + b = np.full((3, 4, 2), -1) + + a[[0, 1]] = np.arange(2 * 4 * 2).reshape(2, 4, 2).T + b[[0, 1]] = np.arange(2 * 4 * 2).reshape(2, 4, 2).T.copy() + + assert_equal(a, b) + + def test_too_many_fancy_indices_special_case(self): + # Just documents behaviour, this is a small limitation. + a = np.ones((1,) * 32) # 32 is NPY_MAXDIMS + assert_raises(IndexError, a.__getitem__, (np.array([0]),) * 32) + + def test_scalar_array_bool(self): + # NumPy bools can be used as boolean index (python ones as of yet not) + a = np.array(1) + assert_equal(a[np.bool_(True)], a[np.array(True)]) + assert_equal(a[np.bool_(False)], a[np.array(False)]) + + # After deprecating bools as integers: + #a = np.array([0,1,2]) + #assert_equal(a[True, :], a[None, :]) + #assert_equal(a[:, True], a[:, None]) + # + #assert_(not np.may_share_memory(a, a[True, :])) + + def test_everything_returns_views(self): + # Before `...` would return a itself. + a = np.arange(5) + + assert_(a is not a[()]) + assert_(a is not a[...]) + assert_(a is not a[:]) + + def test_broaderrors_indexing(self): + a = np.zeros((5, 5)) + assert_raises(IndexError, a.__getitem__, ([0, 1], [0, 1, 2])) + assert_raises(IndexError, a.__setitem__, ([0, 1], [0, 1, 2]), 0) + + def test_trivial_fancy_out_of_bounds(self): + a = np.zeros(5) + ind = np.ones(20, dtype=np.intp) + ind[-1] = 10 + assert_raises(IndexError, a.__getitem__, ind) + assert_raises(IndexError, a.__setitem__, ind, 0) + ind = np.ones(20, dtype=np.intp) + ind[0] = 11 + assert_raises(IndexError, a.__getitem__, ind) + assert_raises(IndexError, a.__setitem__, ind, 0) + + def test_nonbaseclass_values(self): + class SubClass(np.ndarray): + def __array_finalize__(self, old): + # Have array finalize do funny things + self.fill(99) + + a = np.zeros((5, 5)) + s = a.copy().view(type=SubClass) + s.fill(1) + + a[[0, 1, 2, 3, 4], :] = s + assert_((a == 1).all()) + + # Subspace is last, so transposing might want to finalize + a[:, [0, 1, 2, 3, 4]] = s + assert_((a == 1).all()) + + a.fill(0) + a[...] = s + assert_((a == 1).all()) + + def test_subclass_writeable(self): + d = np.rec.array([('NGC1001', 11), ('NGC1002', 1.), ('NGC1003', 1.)], + dtype=[('target', 'S20'), ('V_mag', '>f4')]) + ind = np.array([False, True, True], dtype=bool) + assert_(d[ind].flags.writeable) + ind = np.array([0, 1]) + assert_(d[ind].flags.writeable) + assert_(d[...].flags.writeable) + assert_(d[0].flags.writeable) + + def test_memory_order(self): + # This is not necessary to preserve. Memory layouts for + # more complex indices are not as simple. + a = np.arange(10) + b = np.arange(10).reshape(5,2).T + assert_(a[b].flags.f_contiguous) + + # Takes a different implementation branch: + a = a.reshape(-1, 1) + assert_(a[b, 0].flags.f_contiguous) + + def test_scalar_return_type(self): + # Full scalar indices should return scalars and object + # arrays should not call PyArray_Return on their items + class Zero(object): + # The most basic valid indexing + def __index__(self): + return 0 + + z = Zero() + + class ArrayLike(object): + # Simple array, should behave like the array + def __array__(self): + return np.array(0) + + a = np.zeros(()) + assert_(isinstance(a[()], np.float_)) + a = np.zeros(1) + assert_(isinstance(a[z], np.float_)) + a = np.zeros((1, 1)) + assert_(isinstance(a[z, np.array(0)], np.float_)) + assert_(isinstance(a[z, ArrayLike()], np.float_)) + + # And object arrays do not call it too often: + b = np.array(0) + a = np.array(0, dtype=object) + a[()] = b + assert_(isinstance(a[()], np.ndarray)) + a = np.array([b, None]) + assert_(isinstance(a[z], np.ndarray)) + a = np.array([[b, None]]) + assert_(isinstance(a[z, np.array(0)], np.ndarray)) + assert_(isinstance(a[z, ArrayLike()], np.ndarray)) + + def test_small_regressions(self): + # Reference count of intp for index checks + a = np.array([0]) + if HAS_REFCOUNT: + refcount = sys.getrefcount(np.dtype(np.intp)) + # item setting always checks indices in separate function: + a[np.array([0], dtype=np.intp)] = 1 + a[np.array([0], dtype=np.uint8)] = 1 + assert_raises(IndexError, a.__setitem__, + np.array([1], dtype=np.intp), 1) + assert_raises(IndexError, a.__setitem__, + np.array([1], dtype=np.uint8), 1) + + if HAS_REFCOUNT: + assert_equal(sys.getrefcount(np.dtype(np.intp)), refcount) + + def test_unaligned(self): + v = (np.zeros(64, dtype=np.int8) + ord('a'))[1:-7] + d = v.view(np.dtype("S8")) + # unaligned source + x = (np.zeros(16, dtype=np.int8) + ord('a'))[1:-7] + x = x.view(np.dtype("S8")) + x[...] = np.array("b" * 8, dtype="S") + b = np.arange(d.size) + #trivial + assert_equal(d[b], d) + d[b] = x + # nontrivial + # unaligned index array + b = np.zeros(d.size + 1).view(np.int8)[1:-(np.intp(0).itemsize - 1)] + b = b.view(np.intp)[:d.size] + b[...] = np.arange(d.size) + assert_equal(d[b.astype(np.int16)], d) + d[b.astype(np.int16)] = x + # boolean + d[b % 2 == 0] + d[b % 2 == 0] = x[::2] + + def test_tuple_subclass(self): + arr = np.ones((5, 5)) + + # A tuple subclass should also be an nd-index + class TupleSubclass(tuple): + pass + index = ([1], [1]) + index = TupleSubclass(index) + assert_(arr[index].shape == (1,)) + # Unlike the non nd-index: + assert_(arr[index,].shape != (1,)) + + def test_broken_sequence_not_nd_index(self): + # See gh-5063: + # If we have an object which claims to be a sequence, but fails + # on item getting, this should not be converted to an nd-index (tuple) + # If this object happens to be a valid index otherwise, it should work + # This object here is very dubious and probably bad though: + class SequenceLike(object): + def __index__(self): + return 0 + + def __len__(self): + return 1 + + def __getitem__(self, item): + raise IndexError('Not possible') + + arr = np.arange(10) + assert_array_equal(arr[SequenceLike()], arr[SequenceLike(),]) + + # also test that field indexing does not segfault + # for a similar reason, by indexing a structured array + arr = np.zeros((1,), dtype=[('f1', 'i8'), ('f2', 'i8')]) + assert_array_equal(arr[SequenceLike()], arr[SequenceLike(),]) + + def test_indexing_array_weird_strides(self): + # See also gh-6221 + # the shapes used here come from the issue and create the correct + # size for the iterator buffering size. + x = np.ones(10) + x2 = np.ones((10, 2)) + ind = np.arange(10)[:, None, None, None] + ind = np.broadcast_to(ind, (10, 55, 4, 4)) + + # single advanced index case + assert_array_equal(x[ind], x[ind.copy()]) + # higher dimensional advanced index + zind = np.zeros(4, dtype=np.intp) + assert_array_equal(x2[ind, zind], x2[ind.copy(), zind]) + + def test_indexing_array_negative_strides(self): + # From gh-8264, + # core dumps if negative strides are used in iteration + arro = np.zeros((4, 4)) + arr = arro[::-1, ::-1] + + slices = [slice(None), [0, 1, 2, 3]] + arr[slices] = 10 + assert_array_equal(arr, 10.) + +class TestFieldIndexing(object): + def test_scalar_return_type(self): + # Field access on an array should return an array, even if it + # is 0-d. + a = np.zeros((), [('a','f8')]) + assert_(isinstance(a['a'], np.ndarray)) + assert_(isinstance(a[['a']], np.ndarray)) + + +class TestBroadcastedAssignments(object): + def assign(self, a, ind, val): + a[ind] = val + return a + + def test_prepending_ones(self): + a = np.zeros((3, 2)) + + a[...] = np.ones((1, 3, 2)) + # Fancy with subspace with and without transpose + a[[0, 1, 2], :] = np.ones((1, 3, 2)) + a[:, [0, 1]] = np.ones((1, 3, 2)) + # Fancy without subspace (with broadcasting) + a[[[0], [1], [2]], [0, 1]] = np.ones((1, 3, 2)) + + def test_prepend_not_one(self): + assign = self.assign + s_ = np.s_ + a = np.zeros(5) + + # Too large and not only ones. + assert_raises(ValueError, assign, a, s_[...], np.ones((2, 1))) + assert_raises(ValueError, assign, a, s_[[1, 2, 3],], np.ones((2, 1))) + assert_raises(ValueError, assign, a, s_[[[1], [2]],], np.ones((2,2,1))) + + def test_simple_broadcasting_errors(self): + assign = self.assign + s_ = np.s_ + a = np.zeros((5, 1)) + + assert_raises(ValueError, assign, a, s_[...], np.zeros((5, 2))) + assert_raises(ValueError, assign, a, s_[...], np.zeros((5, 0))) + assert_raises(ValueError, assign, a, s_[:, [0]], np.zeros((5, 2))) + assert_raises(ValueError, assign, a, s_[:, [0]], np.zeros((5, 0))) + assert_raises(ValueError, assign, a, s_[[0], :], np.zeros((2, 1))) + + def test_index_is_larger(self): + # Simple case of fancy index broadcasting of the index. + a = np.zeros((5, 5)) + a[[[0], [1], [2]], [0, 1, 2]] = [2, 3, 4] + + assert_((a[:3, :3] == [2, 3, 4]).all()) + + def test_broadcast_subspace(self): + a = np.zeros((100, 100)) + v = np.arange(100)[:,None] + b = np.arange(100)[::-1] + a[b] = v + assert_((a[::-1] == v).all()) + + +class TestSubclasses(object): + def test_basic(self): + class SubClass(np.ndarray): + pass + + s = np.arange(5).view(SubClass) + assert_(isinstance(s[:3], SubClass)) + assert_(s[:3].base is s) + + assert_(isinstance(s[[0, 1, 2]], SubClass)) + assert_(isinstance(s[s > 0], SubClass)) + + def test_matrix_fancy(self): + # The matrix class messes with the shape. While this is always + # weird (getitem is not used, it does not have setitem nor knows + # about fancy indexing), this tests gh-3110 + m = np.matrix([[1, 2], [3, 4]]) + + assert_(isinstance(m[[0,1,0], :], np.matrix)) + + # gh-3110. Note the transpose currently because matrices do *not* + # support dimension fixing for fancy indexing correctly. + x = np.asmatrix(np.arange(50).reshape(5,10)) + assert_equal(x[:2, np.array(-1)], x[:2, -1].T) + + def test_finalize_gets_full_info(self): + # Array finalize should be called on the filled array. + class SubClass(np.ndarray): + def __array_finalize__(self, old): + self.finalize_status = np.array(self) + self.old = old + + s = np.arange(10).view(SubClass) + new_s = s[:3] + assert_array_equal(new_s.finalize_status, new_s) + assert_array_equal(new_s.old, s) + + new_s = s[[0,1,2,3]] + assert_array_equal(new_s.finalize_status, new_s) + assert_array_equal(new_s.old, s) + + new_s = s[s > 0] + assert_array_equal(new_s.finalize_status, new_s) + assert_array_equal(new_s.old, s) + + @dec.skipif(not HAS_REFCOUNT) + def test_slice_decref_getsetslice(self): + # See gh-10066, a temporary slice object should be discarted. + # This test is only really interesting on Python 2 since + # it goes through `__set/getslice__` here and can probably be + # removed. Use 0:7 to make sure it is never None:7. + class KeepIndexObject(np.ndarray): + def __getitem__(self, indx): + self.indx = indx + if indx == slice(0, 7): + raise ValueError + + def __setitem__(self, indx, val): + self.indx = indx + if indx == slice(0, 4): + raise ValueError + + k = np.array([1]).view(KeepIndexObject) + k[0:5] + assert_equal(k.indx, slice(0, 5)) + assert_equal(sys.getrefcount(k.indx), 2) + try: + k[0:7] + raise AssertionError + except ValueError: + # The exception holds a reference to the slice so clear on Py2 + if hasattr(sys, 'exc_clear'): + with suppress_warnings() as sup: + sup.filter(DeprecationWarning) + sys.exc_clear() + assert_equal(k.indx, slice(0, 7)) + assert_equal(sys.getrefcount(k.indx), 2) + + k[0:3] = 6 + assert_equal(k.indx, slice(0, 3)) + assert_equal(sys.getrefcount(k.indx), 2) + try: + k[0:4] = 2 + raise AssertionError + except ValueError: + # The exception holds a reference to the slice so clear on Py2 + if hasattr(sys, 'exc_clear'): + with suppress_warnings() as sup: + sup.filter(DeprecationWarning) + sys.exc_clear() + assert_equal(k.indx, slice(0, 4)) + assert_equal(sys.getrefcount(k.indx), 2) + + +class TestFancyIndexingCast(object): + def test_boolean_index_cast_assign(self): + # Setup the boolean index and float arrays. + shape = (8, 63) + bool_index = np.zeros(shape).astype(bool) + bool_index[0, 1] = True + zero_array = np.zeros(shape) + + # Assigning float is fine. + zero_array[bool_index] = np.array([1]) + assert_equal(zero_array[0, 1], 1) + + # Fancy indexing works, although we get a cast warning. + assert_warns(np.ComplexWarning, + zero_array.__setitem__, ([0], [1]), np.array([2 + 1j])) + assert_equal(zero_array[0, 1], 2) # No complex part + + # Cast complex to float, throwing away the imaginary portion. + assert_warns(np.ComplexWarning, + zero_array.__setitem__, bool_index, np.array([1j])) + assert_equal(zero_array[0, 1], 0) + +class TestFancyIndexingEquivalence(object): + def test_object_assign(self): + # Check that the field and object special case using copyto is active. + # The right hand side cannot be converted to an array here. + a = np.arange(5, dtype=object) + b = a.copy() + a[:3] = [1, (1,2), 3] + b[[0, 1, 2]] = [1, (1,2), 3] + assert_array_equal(a, b) + + # test same for subspace fancy indexing + b = np.arange(5, dtype=object)[None, :] + b[[0], :3] = [[1, (1,2), 3]] + assert_array_equal(a, b[0]) + + # Check that swapping of axes works. + # There was a bug that made the later assignment throw a ValueError + # do to an incorrectly transposed temporary right hand side (gh-5714) + b = b.T + b[:3, [0]] = [[1], [(1,2)], [3]] + assert_array_equal(a, b[:, 0]) + + # Another test for the memory order of the subspace + arr = np.ones((3, 4, 5), dtype=object) + # Equivalent slicing assignment for comparison + cmp_arr = arr.copy() + cmp_arr[:1, ...] = [[[1], [2], [3], [4]]] + arr[[0], ...] = [[[1], [2], [3], [4]]] + assert_array_equal(arr, cmp_arr) + arr = arr.copy('F') + arr[[0], ...] = [[[1], [2], [3], [4]]] + assert_array_equal(arr, cmp_arr) + + def test_cast_equivalence(self): + # Yes, normal slicing uses unsafe casting. + a = np.arange(5) + b = a.copy() + + a[:3] = np.array(['2', '-3', '-1']) + b[[0, 2, 1]] = np.array(['2', '-1', '-3']) + assert_array_equal(a, b) + + # test the same for subspace fancy indexing + b = np.arange(5)[None, :] + b[[0], :3] = np.array([['2', '-3', '-1']]) + assert_array_equal(a, b[0]) + + +class TestMultiIndexingAutomated(object): + """ + These tests use code to mimic the C-Code indexing for selection. + + NOTE: + + * This still lacks tests for complex item setting. + * If you change behavior of indexing, you might want to modify + these tests to try more combinations. + * Behavior was written to match numpy version 1.8. (though a + first version matched 1.7.) + * Only tuple indices are supported by the mimicking code. + (and tested as of writing this) + * Error types should match most of the time as long as there + is only one error. For multiple errors, what gets raised + will usually not be the same one. They are *not* tested. + + Update 2016-11-30: It is probably not worth maintaining this test + indefinitely and it can be dropped if maintenance becomes a burden. + + """ + + def setup(self): + self.a = np.arange(np.prod([3, 1, 5, 6])).reshape(3, 1, 5, 6) + self.b = np.empty((3, 0, 5, 6)) + self.complex_indices = ['skip', Ellipsis, + 0, + # Boolean indices, up to 3-d for some special cases of eating up + # dimensions, also need to test all False + np.array([True, False, False]), + np.array([[True, False], [False, True]]), + np.array([[[False, False], [False, False]]]), + # Some slices: + slice(-5, 5, 2), + slice(1, 1, 100), + slice(4, -1, -2), + slice(None, None, -3), + # Some Fancy indexes: + np.empty((0, 1, 1), dtype=np.intp), # empty and can be broadcast + np.array([0, 1, -2]), + np.array([[2], [0], [1]]), + np.array([[0, -1], [0, 1]], dtype=np.dtype('intp').newbyteorder()), + np.array([2, -1], dtype=np.int8), + np.zeros([1]*31, dtype=int), # trigger too large array. + np.array([0., 1.])] # invalid datatype + # Some simpler indices that still cover a bit more + self.simple_indices = [Ellipsis, None, -1, [1], np.array([True]), + 'skip'] + # Very simple ones to fill the rest: + self.fill_indices = [slice(None, None), 0] + + def _get_multi_index(self, arr, indices): + """Mimic multi dimensional indexing. + + Parameters + ---------- + arr : ndarray + Array to be indexed. + indices : tuple of index objects + + Returns + ------- + out : ndarray + An array equivalent to the indexing operation (but always a copy). + `arr[indices]` should be identical. + no_copy : bool + Whether the indexing operation requires a copy. If this is `True`, + `np.may_share_memory(arr, arr[indicies])` should be `True` (with + some exceptions for scalars and possibly 0-d arrays). + + Notes + ----- + While the function may mostly match the errors of normal indexing this + is generally not the case. + """ + in_indices = list(indices) + indices = [] + # if False, this is a fancy or boolean index + no_copy = True + # number of fancy/scalar indexes that are not consecutive + num_fancy = 0 + # number of dimensions indexed by a "fancy" index + fancy_dim = 0 + # NOTE: This is a funny twist (and probably OK to change). + # The boolean array has illegal indexes, but this is + # allowed if the broadcast fancy-indices are 0-sized. + # This variable is to catch that case. + error_unless_broadcast_to_empty = False + + # We need to handle Ellipsis and make arrays from indices, also + # check if this is fancy indexing (set no_copy). + ndim = 0 + ellipsis_pos = None # define here mostly to replace all but first. + for i, indx in enumerate(in_indices): + if indx is None: + continue + if isinstance(indx, np.ndarray) and indx.dtype == bool: + no_copy = False + if indx.ndim == 0: + raise IndexError + # boolean indices can have higher dimensions + ndim += indx.ndim + fancy_dim += indx.ndim + continue + if indx is Ellipsis: + if ellipsis_pos is None: + ellipsis_pos = i + continue # do not increment ndim counter + raise IndexError + if isinstance(indx, slice): + ndim += 1 + continue + if not isinstance(indx, np.ndarray): + # This could be open for changes in numpy. + # numpy should maybe raise an error if casting to intp + # is not safe. It rejects np.array([1., 2.]) but not + # [1., 2.] as index (same for ie. np.take). + # (Note the importance of empty lists if changing this here) + indx = np.array(indx, dtype=np.intp) + in_indices[i] = indx + elif indx.dtype.kind != 'b' and indx.dtype.kind != 'i': + raise IndexError('arrays used as indices must be of ' + 'integer (or boolean) type') + if indx.ndim != 0: + no_copy = False + ndim += 1 + fancy_dim += 1 + + if arr.ndim - ndim < 0: + # we can't take more dimensions then we have, not even for 0-d + # arrays. since a[()] makes sense, but not a[(),]. We will + # raise an error later on, unless a broadcasting error occurs + # first. + raise IndexError + + if ndim == 0 and None not in in_indices: + # Well we have no indexes or one Ellipsis. This is legal. + return arr.copy(), no_copy + + if ellipsis_pos is not None: + in_indices[ellipsis_pos:ellipsis_pos+1] = ([slice(None, None)] * + (arr.ndim - ndim)) + + for ax, indx in enumerate(in_indices): + if isinstance(indx, slice): + # convert to an index array + indx = np.arange(*indx.indices(arr.shape[ax])) + indices.append(['s', indx]) + continue + elif indx is None: + # this is like taking a slice with one element from a new axis: + indices.append(['n', np.array([0], dtype=np.intp)]) + arr = arr.reshape((arr.shape[:ax] + (1,) + arr.shape[ax:])) + continue + if isinstance(indx, np.ndarray) and indx.dtype == bool: + if indx.shape != arr.shape[ax:ax+indx.ndim]: + raise IndexError + + try: + flat_indx = np.ravel_multi_index(np.nonzero(indx), + arr.shape[ax:ax+indx.ndim], mode='raise') + except Exception: + error_unless_broadcast_to_empty = True + # fill with 0s instead, and raise error later + flat_indx = np.array([0]*indx.sum(), dtype=np.intp) + # concatenate axis into a single one: + if indx.ndim != 0: + arr = arr.reshape((arr.shape[:ax] + + (np.prod(arr.shape[ax:ax+indx.ndim]),) + + arr.shape[ax+indx.ndim:])) + indx = flat_indx + else: + # This could be changed, a 0-d boolean index can + # make sense (even outside the 0-d indexed array case) + # Note that originally this is could be interpreted as + # integer in the full integer special case. + raise IndexError + else: + # If the index is a singleton, the bounds check is done + # before the broadcasting. This used to be different in <1.9 + if indx.ndim == 0: + if indx >= arr.shape[ax] or indx < -arr.shape[ax]: + raise IndexError + if indx.ndim == 0: + # The index is a scalar. This used to be two fold, but if + # fancy indexing was active, the check was done later, + # possibly after broadcasting it away (1.7. or earlier). + # Now it is always done. + if indx >= arr.shape[ax] or indx < - arr.shape[ax]: + raise IndexError + if (len(indices) > 0 and + indices[-1][0] == 'f' and + ax != ellipsis_pos): + # NOTE: There could still have been a 0-sized Ellipsis + # between them. Checked that with ellipsis_pos. + indices[-1].append(indx) + else: + # We have a fancy index that is not after an existing one. + # NOTE: A 0-d array triggers this as well, while one may + # expect it to not trigger it, since a scalar would not be + # considered fancy indexing. + num_fancy += 1 + indices.append(['f', indx]) + + if num_fancy > 1 and not no_copy: + # We have to flush the fancy indexes left + new_indices = indices[:] + axes = list(range(arr.ndim)) + fancy_axes = [] + new_indices.insert(0, ['f']) + ni = 0 + ai = 0 + for indx in indices: + ni += 1 + if indx[0] == 'f': + new_indices[0].extend(indx[1:]) + del new_indices[ni] + ni -= 1 + for ax in range(ai, ai + len(indx[1:])): + fancy_axes.append(ax) + axes.remove(ax) + ai += len(indx) - 1 # axis we are at + indices = new_indices + # and now we need to transpose arr: + arr = arr.transpose(*(fancy_axes + axes)) + + # We only have one 'f' index now and arr is transposed accordingly. + # Now handle newaxis by reshaping... + ax = 0 + for indx in indices: + if indx[0] == 'f': + if len(indx) == 1: + continue + # First of all, reshape arr to combine fancy axes into one: + orig_shape = arr.shape + orig_slice = orig_shape[ax:ax + len(indx[1:])] + arr = arr.reshape((arr.shape[:ax] + + (np.prod(orig_slice).astype(int),) + + arr.shape[ax + len(indx[1:]):])) + + # Check if broadcasting works + res = np.broadcast(*indx[1:]) + # unfortunately the indices might be out of bounds. So check + # that first, and use mode='wrap' then. However only if + # there are any indices... + if res.size != 0: + if error_unless_broadcast_to_empty: + raise IndexError + for _indx, _size in zip(indx[1:], orig_slice): + if _indx.size == 0: + continue + if np.any(_indx >= _size) or np.any(_indx < -_size): + raise IndexError + if len(indx[1:]) == len(orig_slice): + if np.product(orig_slice) == 0: + # Work around for a crash or IndexError with 'wrap' + # in some 0-sized cases. + try: + mi = np.ravel_multi_index(indx[1:], orig_slice, + mode='raise') + except Exception: + # This happens with 0-sized orig_slice (sometimes?) + # here it is a ValueError, but indexing gives a: + raise IndexError('invalid index into 0-sized') + else: + mi = np.ravel_multi_index(indx[1:], orig_slice, + mode='wrap') + else: + # Maybe never happens... + raise ValueError + arr = arr.take(mi.ravel(), axis=ax) + arr = arr.reshape((arr.shape[:ax] + + mi.shape + + arr.shape[ax+1:])) + ax += mi.ndim + continue + + # If we are here, we have a 1D array for take: + arr = arr.take(indx[1], axis=ax) + ax += 1 + + return arr, no_copy + + def _check_multi_index(self, arr, index): + """Check a multi index item getting and simple setting. + + Parameters + ---------- + arr : ndarray + Array to be indexed, must be a reshaped arange. + index : tuple of indexing objects + Index being tested. + """ + # Test item getting + try: + mimic_get, no_copy = self._get_multi_index(arr, index) + except Exception as e: + if HAS_REFCOUNT: + prev_refcount = sys.getrefcount(arr) + assert_raises(Exception, arr.__getitem__, index) + assert_raises(Exception, arr.__setitem__, index, 0) + if HAS_REFCOUNT: + assert_equal(prev_refcount, sys.getrefcount(arr)) + return + + self._compare_index_result(arr, index, mimic_get, no_copy) + + def _check_single_index(self, arr, index): + """Check a single index item getting and simple setting. + + Parameters + ---------- + arr : ndarray + Array to be indexed, must be an arange. + index : indexing object + Index being tested. Must be a single index and not a tuple + of indexing objects (see also `_check_multi_index`). + """ + try: + mimic_get, no_copy = self._get_multi_index(arr, (index,)) + except Exception as e: + if HAS_REFCOUNT: + prev_refcount = sys.getrefcount(arr) + assert_raises(Exception, arr.__getitem__, index) + assert_raises(Exception, arr.__setitem__, index, 0) + if HAS_REFCOUNT: + assert_equal(prev_refcount, sys.getrefcount(arr)) + return + + self._compare_index_result(arr, index, mimic_get, no_copy) + + def _compare_index_result(self, arr, index, mimic_get, no_copy): + """Compare mimicked result to indexing result. + """ + arr = arr.copy() + indexed_arr = arr[index] + assert_array_equal(indexed_arr, mimic_get) + # Check if we got a view, unless its a 0-sized or 0-d array. + # (then its not a view, and that does not matter) + if indexed_arr.size != 0 and indexed_arr.ndim != 0: + assert_(np.may_share_memory(indexed_arr, arr) == no_copy) + # Check reference count of the original array + if HAS_REFCOUNT: + if no_copy: + # refcount increases by one: + assert_equal(sys.getrefcount(arr), 3) + else: + assert_equal(sys.getrefcount(arr), 2) + + # Test non-broadcast setitem: + b = arr.copy() + b[index] = mimic_get + 1000 + if b.size == 0: + return # nothing to compare here... + if no_copy and indexed_arr.ndim != 0: + # change indexed_arr in-place to manipulate original: + indexed_arr += 1000 + assert_array_equal(arr, b) + return + # Use the fact that the array is originally an arange: + arr.flat[indexed_arr.ravel()] += 1000 + assert_array_equal(arr, b) + + def test_boolean(self): + a = np.array(5) + assert_equal(a[np.array(True)], 5) + a[np.array(True)] = 1 + assert_equal(a, 1) + # NOTE: This is different from normal broadcasting, as + # arr[boolean_array] works like in a multi index. Which means + # it is aligned to the left. This is probably correct for + # consistency with arr[boolean_array,] also no broadcasting + # is done at all + self._check_multi_index( + self.a, (np.zeros_like(self.a, dtype=bool),)) + self._check_multi_index( + self.a, (np.zeros_like(self.a, dtype=bool)[..., 0],)) + self._check_multi_index( + self.a, (np.zeros_like(self.a, dtype=bool)[None, ...],)) + + def test_multidim(self): + # Automatically test combinations with complex indexes on 2nd (or 1st) + # spot and the simple ones in one other spot. + with warnings.catch_warnings(): + # This is so that np.array(True) is not accepted in a full integer + # index, when running the file separately. + warnings.filterwarnings('error', '', DeprecationWarning) + warnings.filterwarnings('error', '', np.VisibleDeprecationWarning) + + def isskip(idx): + return isinstance(idx, str) and idx == "skip" + + for simple_pos in [0, 2, 3]: + tocheck = [self.fill_indices, self.complex_indices, + self.fill_indices, self.fill_indices] + tocheck[simple_pos] = self.simple_indices + for index in product(*tocheck): + index = tuple(i for i in index if not isskip(i)) + self._check_multi_index(self.a, index) + self._check_multi_index(self.b, index) + + # Check very simple item getting: + self._check_multi_index(self.a, (0, 0, 0, 0)) + self._check_multi_index(self.b, (0, 0, 0, 0)) + # Also check (simple cases of) too many indices: + assert_raises(IndexError, self.a.__getitem__, (0, 0, 0, 0, 0)) + assert_raises(IndexError, self.a.__setitem__, (0, 0, 0, 0, 0), 0) + assert_raises(IndexError, self.a.__getitem__, (0, 0, [1], 0, 0)) + assert_raises(IndexError, self.a.__setitem__, (0, 0, [1], 0, 0), 0) + + def test_1d(self): + a = np.arange(10) + with warnings.catch_warnings(): + warnings.filterwarnings('error', '', np.VisibleDeprecationWarning) + for index in self.complex_indices: + self._check_single_index(a, index) + +class TestFloatNonIntegerArgument(object): + """ + These test that ``TypeError`` is raised when you try to use + non-integers as arguments to for indexing and slicing e.g. ``a[0.0:5]`` + and ``a[0.5]``, or other functions like ``array.reshape(1., -1)``. + + """ + def test_valid_indexing(self): + # These should raise no errors. + a = np.array([[[5]]]) + + a[np.array([0])] + a[[0, 0]] + a[:, [0, 0]] + a[:, 0,:] + a[:,:,:] + + def test_valid_slicing(self): + # These should raise no errors. + a = np.array([[[5]]]) + + a[::] + a[0:] + a[:2] + a[0:2] + a[::2] + a[1::2] + a[:2:2] + a[1:2:2] + + def test_non_integer_argument_errors(self): + a = np.array([[5]]) + + assert_raises(TypeError, np.reshape, a, (1., 1., -1)) + assert_raises(TypeError, np.reshape, a, (np.array(1.), -1)) + assert_raises(TypeError, np.take, a, [0], 1.) + assert_raises(TypeError, np.take, a, [0], np.float64(1.)) + + def test_non_integer_sequence_multiplication(self): + # NumPy scalar sequence multiply should not work with non-integers + def mult(a, b): + return a * b + + assert_raises(TypeError, mult, [1], np.float_(3)) + # following should be OK + mult([1], np.int_(3)) + + def test_reduce_axis_float_index(self): + d = np.zeros((3,3,3)) + assert_raises(TypeError, np.min, d, 0.5) + assert_raises(TypeError, np.min, d, (0.5, 1)) + assert_raises(TypeError, np.min, d, (1, 2.2)) + assert_raises(TypeError, np.min, d, (.2, 1.2)) + + +class TestBooleanIndexing(object): + # Using a boolean as integer argument/indexing is an error. + def test_bool_as_int_argument_errors(self): + a = np.array([[[1]]]) + + assert_raises(TypeError, np.reshape, a, (True, -1)) + assert_raises(TypeError, np.reshape, a, (np.bool_(True), -1)) + # Note that operator.index(np.array(True)) does not work, a boolean + # array is thus also deprecated, but not with the same message: + assert_raises(TypeError, operator.index, np.array(True)) + assert_warns(DeprecationWarning, operator.index, np.True_) + assert_raises(TypeError, np.take, args=(a, [0], False)) + + def test_boolean_indexing_weirdness(self): + # Weird boolean indexing things + a = np.ones((2, 3, 4)) + a[False, True, ...].shape == (0, 2, 3, 4) + a[True, [0, 1], True, True, [1], [[2]]] == (1, 2) + assert_raises(IndexError, lambda: a[False, [0, 1], ...]) + + +class TestArrayToIndexDeprecation(object): + """Creating an an index from array not 0-D is an error. + + """ + def test_array_to_index_error(self): + # so no exception is expected. The raising is effectively tested above. + a = np.array([[[1]]]) + + assert_raises(TypeError, operator.index, np.array([1])) + assert_raises(TypeError, np.reshape, a, (a, -1)) + assert_raises(TypeError, np.take, a, [0], a) + + +class TestNonIntegerArrayLike(object): + """Tests that array_likes only valid if can safely cast to integer. + + For instance, lists give IndexError when they cannot be safely cast to + an integer. + + """ + def test_basic(self): + a = np.arange(10) + + assert_raises(IndexError, a.__getitem__, [0.5, 1.5]) + assert_raises(IndexError, a.__getitem__, (['1', '2'],)) + + # The following is valid + a.__getitem__([]) + + +class TestMultipleEllipsisError(object): + """An index can only have a single ellipsis. + + """ + def test_basic(self): + a = np.arange(10) + assert_raises(IndexError, lambda: a[..., ...]) + assert_raises(IndexError, a.__getitem__, ((Ellipsis,) * 2,)) + assert_raises(IndexError, a.__getitem__, ((Ellipsis,) * 3,)) + + +class TestCApiAccess(object): + def test_getitem(self): + subscript = functools.partial(array_indexing, 0) + + # 0-d arrays don't work: + assert_raises(IndexError, subscript, np.ones(()), 0) + # Out of bound values: + assert_raises(IndexError, subscript, np.ones(10), 11) + assert_raises(IndexError, subscript, np.ones(10), -11) + assert_raises(IndexError, subscript, np.ones((10, 10)), 11) + assert_raises(IndexError, subscript, np.ones((10, 10)), -11) + + a = np.arange(10) + assert_array_equal(a[4], subscript(a, 4)) + a = a.reshape(5, 2) + assert_array_equal(a[-4], subscript(a, -4)) + + def test_setitem(self): + assign = functools.partial(array_indexing, 1) + + # Deletion is impossible: + assert_raises(ValueError, assign, np.ones(10), 0) + # 0-d arrays don't work: + assert_raises(IndexError, assign, np.ones(()), 0, 0) + # Out of bound values: + assert_raises(IndexError, assign, np.ones(10), 11, 0) + assert_raises(IndexError, assign, np.ones(10), -11, 0) + assert_raises(IndexError, assign, np.ones((10, 10)), 11, 0) + assert_raises(IndexError, assign, np.ones((10, 10)), -11, 0) + + a = np.arange(10) + assign(a, 4, 10) + assert_(a[4] == 10) + + a = a.reshape(5, 2) + assign(a, 4, 10) + assert_array_equal(a[-1], [10, 10]) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_item_selection.py b/numpy/core/tests/test_item_selection.py new file mode 100644 index 0000000..642da42 --- /dev/null +++ b/numpy/core/tests/test_item_selection.py @@ -0,0 +1,92 @@ +from __future__ import division, absolute_import, print_function + +import sys + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_raises, + assert_array_equal, HAS_REFCOUNT +) + + +class TestTake(object): + def test_simple(self): + a = [[1, 2], [3, 4]] + a_str = [[b'1', b'2'], [b'3', b'4']] + modes = ['raise', 'wrap', 'clip'] + indices = [-1, 4] + index_arrays = [np.empty(0, dtype=np.intp), + np.empty(tuple(), dtype=np.intp), + np.empty((1, 1), dtype=np.intp)] + real_indices = {'raise': {-1: 1, 4: IndexError}, + 'wrap': {-1: 1, 4: 0}, + 'clip': {-1: 0, 4: 1}} + # Currently all types but object, use the same function generation. + # So it should not be necessary to test all. However test also a non + # refcounted struct on top of object. + types = int, object, np.dtype([('', 'i', 2)]) + for t in types: + # ta works, even if the array may be odd if buffer interface is used + ta = np.array(a if np.issubdtype(t, np.number) else a_str, dtype=t) + tresult = list(ta.T.copy()) + for index_array in index_arrays: + if index_array.size != 0: + tresult[0].shape = (2,) + index_array.shape + tresult[1].shape = (2,) + index_array.shape + for mode in modes: + for index in indices: + real_index = real_indices[mode][index] + if real_index is IndexError and index_array.size != 0: + index_array.put(0, index) + assert_raises(IndexError, ta.take, index_array, + mode=mode, axis=1) + elif index_array.size != 0: + index_array.put(0, index) + res = ta.take(index_array, mode=mode, axis=1) + assert_array_equal(res, tresult[real_index]) + else: + res = ta.take(index_array, mode=mode, axis=1) + assert_(res.shape == (2,) + index_array.shape) + + def test_refcounting(self): + objects = [object() for i in range(10)] + for mode in ('raise', 'clip', 'wrap'): + a = np.array(objects) + b = np.array([2, 2, 4, 5, 3, 5]) + a.take(b, out=a[:6], mode=mode) + del a + if HAS_REFCOUNT: + assert_(all(sys.getrefcount(o) == 3 for o in objects)) + # not contiguous, example: + a = np.array(objects * 2)[::2] + a.take(b, out=a[:6], mode=mode) + del a + if HAS_REFCOUNT: + assert_(all(sys.getrefcount(o) == 3 for o in objects)) + + def test_unicode_mode(self): + d = np.arange(10) + k = b'\xc3\xa4'.decode("UTF8") + assert_raises(ValueError, d.take, 5, mode=k) + + def test_empty_partition(self): + # In reference to github issue #6530 + a_original = np.array([0, 2, 4, 6, 8, 10]) + a = a_original.copy() + + # An empty partition should be a successful no-op + a.partition(np.array([], dtype=np.int16)) + + assert_array_equal(a, a_original) + + def test_empty_argpartition(self): + # In reference to github issue #6530 + a = np.array([0, 2, 4, 6, 8, 10]) + a = a.argpartition(np.array([], dtype=np.int16)) + + b = np.array([0, 1, 2, 3, 4, 5]) + assert_array_equal(a, b) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_longdouble.py b/numpy/core/tests/test_longdouble.py new file mode 100644 index 0000000..625d40c --- /dev/null +++ b/numpy/core/tests/test_longdouble.py @@ -0,0 +1,212 @@ +from __future__ import division, absolute_import, print_function + +import locale + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, dec, assert_raises, + assert_array_equal, temppath, +) +from .test_print import in_foreign_locale + +LD_INFO = np.finfo(np.longdouble) +longdouble_longer_than_double = (LD_INFO.eps < np.finfo(np.double).eps) + + +_o = 1 + LD_INFO.eps +string_to_longdouble_inaccurate = (_o != np.longdouble(repr(_o))) +del _o + + +def test_scalar_extraction(): + """Confirm that extracting a value doesn't convert to python float""" + o = 1 + LD_INFO.eps + a = np.array([o, o, o]) + assert_equal(a[1], o) + + +# Conversions string -> long double + +# 0.1 not exactly representable in base 2 floating point. +repr_precision = len(repr(np.longdouble(0.1))) +# +2 from macro block starting around line 842 in scalartypes.c.src. +@dec.skipif(LD_INFO.precision + 2 >= repr_precision, + "repr precision not enough to show eps") +def test_repr_roundtrip(): + # We will only see eps in repr if within printing precision. + o = 1 + LD_INFO.eps + assert_equal(np.longdouble(repr(o)), o, "repr was %s" % repr(o)) + + +def test_unicode(): + np.longdouble(u"1.2") + + +def test_string(): + np.longdouble("1.2") + + +def test_bytes(): + np.longdouble(b"1.2") + + +@in_foreign_locale +def test_fromstring_foreign_repr(): + f = 1.234 + a = np.fromstring(repr(f), dtype=float, sep=" ") + assert_equal(a[0], f) + + +@dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") +def test_repr_roundtrip_bytes(): + o = 1 + LD_INFO.eps + assert_equal(np.longdouble(repr(o).encode("ascii")), o) + + +@in_foreign_locale +def test_repr_roundtrip_foreign(): + o = 1.5 + assert_equal(o, np.longdouble(repr(o))) + + +def test_bogus_string(): + assert_raises(ValueError, np.longdouble, "spam") + assert_raises(ValueError, np.longdouble, "1.0 flub") + + +@dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") +def test_fromstring(): + o = 1 + LD_INFO.eps + s = (" " + repr(o))*5 + a = np.array([o]*5) + assert_equal(np.fromstring(s, sep=" ", dtype=np.longdouble), a, + err_msg="reading '%s'" % s) + + +@in_foreign_locale +def test_fromstring_best_effort_float(): + assert_equal(np.fromstring("1,234", dtype=float, sep=" "), + np.array([1.])) + + +@in_foreign_locale +def test_fromstring_best_effort(): + assert_equal(np.fromstring("1,234", dtype=np.longdouble, sep=" "), + np.array([1.])) + + +def test_fromstring_bogus(): + assert_equal(np.fromstring("1. 2. 3. flop 4.", dtype=float, sep=" "), + np.array([1., 2., 3.])) + + +def test_fromstring_empty(): + assert_equal(np.fromstring("xxxxx", sep="x"), + np.array([])) + + +def test_fromstring_missing(): + assert_equal(np.fromstring("1xx3x4x5x6", sep="x"), + np.array([1])) + + +class TestFileBased(object): + + ldbl = 1 + LD_INFO.eps + tgt = np.array([ldbl]*5) + out = ''.join([repr(t) + '\n' for t in tgt]) + + def test_fromfile_bogus(self): + with temppath() as path: + with open(path, 'wt') as f: + f.write("1. 2. 3. flop 4.\n") + res = np.fromfile(path, dtype=float, sep=" ") + assert_equal(res, np.array([1., 2., 3.])) + + @dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") + def test_fromfile(self): + with temppath() as path: + with open(path, 'wt') as f: + f.write(self.out) + res = np.fromfile(path, dtype=np.longdouble, sep="\n") + assert_equal(res, self.tgt) + + @dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") + def test_genfromtxt(self): + with temppath() as path: + with open(path, 'wt') as f: + f.write(self.out) + res = np.genfromtxt(path, dtype=np.longdouble) + assert_equal(res, self.tgt) + + @dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") + def test_loadtxt(self): + with temppath() as path: + with open(path, 'wt') as f: + f.write(self.out) + res = np.loadtxt(path, dtype=np.longdouble) + assert_equal(res, self.tgt) + + @dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") + def test_tofile_roundtrip(self): + with temppath() as path: + self.tgt.tofile(path, sep=" ") + res = np.fromfile(path, dtype=np.longdouble, sep=" ") + assert_equal(res, self.tgt) + + +@in_foreign_locale +def test_fromstring_foreign(): + s = "1.234" + a = np.fromstring(s, dtype=np.longdouble, sep=" ") + assert_equal(a[0], np.longdouble(s)) + + +@in_foreign_locale +def test_fromstring_foreign_sep(): + a = np.array([1, 2, 3, 4]) + b = np.fromstring("1,2,3,4,", dtype=np.longdouble, sep=",") + assert_array_equal(a, b) + + +@in_foreign_locale +def test_fromstring_foreign_value(): + b = np.fromstring("1,234", dtype=np.longdouble, sep=" ") + assert_array_equal(b[0], 1) + + +# Conversions long double -> string + + +def test_repr_exact(): + o = 1 + LD_INFO.eps + assert_(repr(o) != '1') + + +@dec.knownfailureif(longdouble_longer_than_double, "BUG #2376") +@dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") +def test_format(): + o = 1 + LD_INFO.eps + assert_("{0:.40g}".format(o) != '1') + + +@dec.knownfailureif(longdouble_longer_than_double, "BUG #2376") +@dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") +def test_percent(): + o = 1 + LD_INFO.eps + assert_("%.40g" % o != '1') + + +@dec.knownfailureif(longdouble_longer_than_double, "array repr problem") +@dec.knownfailureif(string_to_longdouble_inaccurate, "Need strtold_l") +def test_array_repr(): + o = 1 + LD_INFO.eps + a = np.array([o]) + b = np.array([1], dtype=np.longdouble) + if not np.all(a != b): + raise ValueError("precision loss creating arrays") + assert_(repr(a) != repr(b)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_machar.py b/numpy/core/tests/test_machar.py new file mode 100644 index 0000000..7acb02e --- /dev/null +++ b/numpy/core/tests/test_machar.py @@ -0,0 +1,36 @@ +""" +Test machar. Given recent changes to hardcode type data, we might want to get +rid of both MachAr and this test at some point. + +""" +from __future__ import division, absolute_import, print_function + +from numpy.core.machar import MachAr +import numpy.core.numerictypes as ntypes +from numpy import errstate, array +from numpy.testing import run_module_suite + +class TestMachAr(object): + def _run_machar_highprec(self): + # Instantiate MachAr instance with high enough precision to cause + # underflow + try: + hiprec = ntypes.float96 + MachAr(lambda v:array([v], hiprec)) + except AttributeError: + # Fixme, this needs to raise a 'skip' exception. + "Skipping test: no ntypes.float96 available on this platform." + + def test_underlow(self): + # Regression test for #759: + # instantiating MachAr for dtype = np.float96 raises spurious warning. + with errstate(all='raise'): + try: + self._run_machar_highprec() + except FloatingPointError as e: + msg = "Caught %s exception, should not have been raised." % e + raise AssertionError(msg) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_mem_overlap.py b/numpy/core/tests/test_mem_overlap.py new file mode 100644 index 0000000..53d56b5 --- /dev/null +++ b/numpy/core/tests/test_mem_overlap.py @@ -0,0 +1,953 @@ +from __future__ import division, absolute_import, print_function + +import sys +import itertools + +import numpy as np +from numpy.testing import (run_module_suite, assert_, assert_raises, assert_equal, + assert_array_equal, assert_allclose, dec) + +from numpy.core.multiarray_tests import solve_diophantine, internal_overlap +from numpy.core import umath_tests +from numpy.lib.stride_tricks import as_strided +from numpy.compat import long + +if sys.version_info[0] >= 3: + xrange = range + + +ndims = 2 +size = 10 +shape = tuple([size] * ndims) + +MAY_SHARE_BOUNDS = 0 +MAY_SHARE_EXACT = -1 + + +def _indices_for_nelems(nelems): + """Returns slices of length nelems, from start onwards, in direction sign.""" + + if nelems == 0: + return [size // 2] # int index + + res = [] + for step in (1, 2): + for sign in (-1, 1): + start = size // 2 - nelems * step * sign // 2 + stop = start + nelems * step * sign + res.append(slice(start, stop, step * sign)) + + return res + + +def _indices_for_axis(): + """Returns (src, dst) pairs of indices.""" + + res = [] + for nelems in (0, 2, 3): + ind = _indices_for_nelems(nelems) + + # no itertools.product available in Py2.4 + res.extend([(a, b) for a in ind for b in ind]) # all assignments of size "nelems" + + return res + + +def _indices(ndims): + """Returns ((axis0_src, axis0_dst), (axis1_src, axis1_dst), ... ) index pairs.""" + + ind = _indices_for_axis() + + # no itertools.product available in Py2.4 + + res = [[]] + for i in range(ndims): + newres = [] + for elem in ind: + for others in res: + newres.append([elem] + others) + res = newres + + return res + + +def _check_assignment(srcidx, dstidx): + """Check assignment arr[dstidx] = arr[srcidx] works.""" + + arr = np.arange(np.product(shape)).reshape(shape) + + cpy = arr.copy() + + cpy[dstidx] = arr[srcidx] + arr[dstidx] = arr[srcidx] + + assert_(np.all(arr == cpy), + 'assigning arr[%s] = arr[%s]' % (dstidx, srcidx)) + + +def test_overlapping_assignments(): + # Test automatically generated assignments which overlap in memory. + + inds = _indices(ndims) + + for ind in inds: + srcidx = tuple([a[0] for a in ind]) + dstidx = tuple([a[1] for a in ind]) + + yield _check_assignment, srcidx, dstidx + + +@dec.slow +def test_diophantine_fuzz(): + # Fuzz test the diophantine solver + rng = np.random.RandomState(1234) + + max_int = np.iinfo(np.intp).max + + for ndim in range(10): + feasible_count = 0 + infeasible_count = 0 + + min_count = 500//(ndim + 1) + + while min(feasible_count, infeasible_count) < min_count: + # Ensure big and small integer problems + A_max = 1 + rng.randint(0, 11, dtype=np.intp)**6 + U_max = rng.randint(0, 11, dtype=np.intp)**6 + + A_max = min(max_int, A_max) + U_max = min(max_int-1, U_max) + + A = tuple(int(rng.randint(1, A_max+1, dtype=np.intp)) + for j in range(ndim)) + U = tuple(int(rng.randint(0, U_max+2, dtype=np.intp)) + for j in range(ndim)) + + b_ub = min(max_int-2, sum(a*ub for a, ub in zip(A, U))) + b = rng.randint(-1, b_ub+2, dtype=np.intp) + + if ndim == 0 and feasible_count < min_count: + b = 0 + + X = solve_diophantine(A, U, b) + + if X is None: + # Check the simplified decision problem agrees + X_simplified = solve_diophantine(A, U, b, simplify=1) + assert_(X_simplified is None, (A, U, b, X_simplified)) + + # Check no solution exists (provided the problem is + # small enough so that brute force checking doesn't + # take too long) + try: + ranges = tuple(xrange(0, a*ub+1, a) for a, ub in zip(A, U)) + except OverflowError: + # xrange on 32-bit Python 2 may overflow + continue + + size = 1 + for r in ranges: + size *= len(r) + if size < 100000: + assert_(not any(sum(w) == b for w in itertools.product(*ranges))) + infeasible_count += 1 + else: + # Check the simplified decision problem agrees + X_simplified = solve_diophantine(A, U, b, simplify=1) + assert_(X_simplified is not None, (A, U, b, X_simplified)) + + # Check validity + assert_(sum(a*x for a, x in zip(A, X)) == b) + assert_(all(0 <= x <= ub for x, ub in zip(X, U))) + feasible_count += 1 + + +def test_diophantine_overflow(): + # Smoke test integer overflow detection + max_intp = np.iinfo(np.intp).max + max_int64 = np.iinfo(np.int64).max + + if max_int64 <= max_intp: + # Check that the algorithm works internally in 128-bit; + # solving this problem requires large intermediate numbers + A = (max_int64//2, max_int64//2 - 10) + U = (max_int64//2, max_int64//2 - 10) + b = 2*(max_int64//2) - 10 + + assert_equal(solve_diophantine(A, U, b), (1, 1)) + + +def check_may_share_memory_exact(a, b): + got = np.may_share_memory(a, b, max_work=MAY_SHARE_EXACT) + + assert_equal(np.may_share_memory(a, b), + np.may_share_memory(a, b, max_work=MAY_SHARE_BOUNDS)) + + a.fill(0) + b.fill(0) + a.fill(1) + exact = b.any() + + err_msg = "" + if got != exact: + err_msg = " " + "\n ".join([ + "base_a - base_b = %r" % (a.__array_interface__['data'][0] - b.__array_interface__['data'][0],), + "shape_a = %r" % (a.shape,), + "shape_b = %r" % (b.shape,), + "strides_a = %r" % (a.strides,), + "strides_b = %r" % (b.strides,), + "size_a = %r" % (a.size,), + "size_b = %r" % (b.size,) + ]) + + assert_equal(got, exact, err_msg=err_msg) + + +def test_may_share_memory_manual(): + # Manual test cases for may_share_memory + + # Base arrays + xs0 = [ + np.zeros([13, 21, 23, 22], dtype=np.int8), + np.zeros([13, 21, 23*2, 22], dtype=np.int8)[:,:,::2,:] + ] + + # Generate all negative stride combinations + xs = [] + for x in xs0: + for ss in itertools.product(*(([slice(None), slice(None, None, -1)],)*4)): + xp = x[ss] + xs.append(xp) + + for x in xs: + # The default is a simple extent check + assert_(np.may_share_memory(x[:,0,:], x[:,1,:])) + assert_(np.may_share_memory(x[:,0,:], x[:,1,:], max_work=None)) + + # Exact checks + check_may_share_memory_exact(x[:,0,:], x[:,1,:]) + check_may_share_memory_exact(x[:,::7], x[:,3::3]) + + try: + xp = x.ravel() + if xp.flags.owndata: + continue + xp = xp.view(np.int16) + except ValueError: + continue + + # 0-size arrays cannot overlap + check_may_share_memory_exact(x.ravel()[6:6], + xp.reshape(13, 21, 23, 11)[:,::7]) + + # Test itemsize is dealt with + check_may_share_memory_exact(x[:,::7], + xp.reshape(13, 21, 23, 11)) + check_may_share_memory_exact(x[:,::7], + xp.reshape(13, 21, 23, 11)[:,3::3]) + check_may_share_memory_exact(x.ravel()[6:7], + xp.reshape(13, 21, 23, 11)[:,::7]) + + # Check unit size + x = np.zeros([1], dtype=np.int8) + check_may_share_memory_exact(x, x) + check_may_share_memory_exact(x, x.copy()) + + +def iter_random_view_pairs(x, same_steps=True, equal_size=False): + rng = np.random.RandomState(1234) + + if equal_size and same_steps: + raise ValueError() + + def random_slice(n, step): + start = rng.randint(0, n+1, dtype=np.intp) + stop = rng.randint(start, n+1, dtype=np.intp) + if rng.randint(0, 2, dtype=np.intp) == 0: + stop, start = start, stop + step *= -1 + return slice(start, stop, step) + + def random_slice_fixed_size(n, step, size): + start = rng.randint(0, n+1 - size*step) + stop = start + (size-1)*step + 1 + if rng.randint(0, 2) == 0: + stop, start = start-1, stop-1 + if stop < 0: + stop = None + step *= -1 + return slice(start, stop, step) + + # First a few regular views + yield x, x + for j in range(1, 7, 3): + yield x[j:], x[:-j] + yield x[...,j:], x[...,:-j] + + # An array with zero stride internal overlap + strides = list(x.strides) + strides[0] = 0 + xp = as_strided(x, shape=x.shape, strides=strides) + yield x, xp + yield xp, xp + + # An array with non-zero stride internal overlap + strides = list(x.strides) + if strides[0] > 1: + strides[0] = 1 + xp = as_strided(x, shape=x.shape, strides=strides) + yield x, xp + yield xp, xp + + # Then discontiguous views + while True: + steps = tuple(rng.randint(1, 11, dtype=np.intp) + if rng.randint(0, 5, dtype=np.intp) == 0 else 1 + for j in range(x.ndim)) + s1 = tuple(random_slice(p, s) for p, s in zip(x.shape, steps)) + + t1 = np.arange(x.ndim) + rng.shuffle(t1) + + if equal_size: + t2 = t1 + else: + t2 = np.arange(x.ndim) + rng.shuffle(t2) + + a = x[s1] + + if equal_size: + if a.size == 0: + continue + + steps2 = tuple(rng.randint(1, max(2, p//(1+pa))) + if rng.randint(0, 5) == 0 else 1 + for p, s, pa in zip(x.shape, s1, a.shape)) + s2 = tuple(random_slice_fixed_size(p, s, pa) + for p, s, pa in zip(x.shape, steps2, a.shape)) + elif same_steps: + steps2 = steps + else: + steps2 = tuple(rng.randint(1, 11, dtype=np.intp) + if rng.randint(0, 5, dtype=np.intp) == 0 else 1 + for j in range(x.ndim)) + + if not equal_size: + s2 = tuple(random_slice(p, s) for p, s in zip(x.shape, steps2)) + + a = a.transpose(t1) + b = x[s2].transpose(t2) + + yield a, b + + +def check_may_share_memory_easy_fuzz(get_max_work, same_steps, min_count): + # Check that overlap problems with common strides are solved with + # little work. + x = np.zeros([17,34,71,97], dtype=np.int16) + + feasible = 0 + infeasible = 0 + + pair_iter = iter_random_view_pairs(x, same_steps) + + while min(feasible, infeasible) < min_count: + a, b = next(pair_iter) + + bounds_overlap = np.may_share_memory(a, b) + may_share_answer = np.may_share_memory(a, b) + easy_answer = np.may_share_memory(a, b, max_work=get_max_work(a, b)) + exact_answer = np.may_share_memory(a, b, max_work=MAY_SHARE_EXACT) + + if easy_answer != exact_answer: + # assert_equal is slow... + assert_equal(easy_answer, exact_answer) + + if may_share_answer != bounds_overlap: + assert_equal(may_share_answer, bounds_overlap) + + if bounds_overlap: + if exact_answer: + feasible += 1 + else: + infeasible += 1 + + +@dec.slow +def test_may_share_memory_easy_fuzz(): + # Check that overlap problems with common strides are always + # solved with little work. + + check_may_share_memory_easy_fuzz(get_max_work=lambda a, b: 1, + same_steps=True, + min_count=2000) + + +@dec.slow +def test_may_share_memory_harder_fuzz(): + # Overlap problems with not necessarily common strides take more + # work. + # + # The work bound below can't be reduced much. Harder problems can + # also exist but not be detected here, as the set of problems + # comes from RNG. + + check_may_share_memory_easy_fuzz(get_max_work=lambda a, b: max(a.size, b.size)//2, + same_steps=False, + min_count=2000) + + +def test_shares_memory_api(): + x = np.zeros([4, 5, 6], dtype=np.int8) + + assert_equal(np.shares_memory(x, x), True) + assert_equal(np.shares_memory(x, x.copy()), False) + + a = x[:,::2,::3] + b = x[:,::3,::2] + assert_equal(np.shares_memory(a, b), True) + assert_equal(np.shares_memory(a, b, max_work=None), True) + assert_raises(np.TooHardError, np.shares_memory, a, b, max_work=1) + assert_raises(np.TooHardError, np.shares_memory, a, b, max_work=long(1)) + + +def test_may_share_memory_bad_max_work(): + x = np.zeros([1]) + assert_raises(OverflowError, np.may_share_memory, x, x, max_work=10**100) + assert_raises(OverflowError, np.shares_memory, x, x, max_work=10**100) + + +def test_internal_overlap_diophantine(): + def check(A, U, exists=None): + X = solve_diophantine(A, U, 0, require_ub_nontrivial=1) + + if exists is None: + exists = (X is not None) + + if X is not None: + assert_(sum(a*x for a, x in zip(A, X)) == sum(a*u//2 for a, u in zip(A, U))) + assert_(all(0 <= x <= u for x, u in zip(X, U))) + assert_(any(x != u//2 for x, u in zip(X, U))) + + if exists: + assert_(X is not None, repr(X)) + else: + assert_(X is None, repr(X)) + + # Smoke tests + check((3, 2), (2*2, 3*2), exists=True) + check((3*2, 2), (15*2, (3-1)*2), exists=False) + + +def test_internal_overlap_slices(): + # Slicing an array never generates internal overlap + + x = np.zeros([17,34,71,97], dtype=np.int16) + + rng = np.random.RandomState(1234) + + def random_slice(n, step): + start = rng.randint(0, n+1, dtype=np.intp) + stop = rng.randint(start, n+1, dtype=np.intp) + if rng.randint(0, 2, dtype=np.intp) == 0: + stop, start = start, stop + step *= -1 + return slice(start, stop, step) + + cases = 0 + min_count = 5000 + + while cases < min_count: + steps = tuple(rng.randint(1, 11, dtype=np.intp) + if rng.randint(0, 5, dtype=np.intp) == 0 else 1 + for j in range(x.ndim)) + t1 = np.arange(x.ndim) + rng.shuffle(t1) + s1 = tuple(random_slice(p, s) for p, s in zip(x.shape, steps)) + a = x[s1].transpose(t1) + + assert_(not internal_overlap(a)) + cases += 1 + + +def check_internal_overlap(a, manual_expected=None): + got = internal_overlap(a) + + # Brute-force check + m = set() + ranges = tuple(xrange(n) for n in a.shape) + for v in itertools.product(*ranges): + offset = sum(s*w for s, w in zip(a.strides, v)) + if offset in m: + expected = True + break + else: + m.add(offset) + else: + expected = False + + # Compare + if got != expected: + assert_equal(got, expected, err_msg=repr((a.strides, a.shape))) + if manual_expected is not None and expected != manual_expected: + assert_equal(expected, manual_expected) + return got + + +def test_internal_overlap_manual(): + # Stride tricks can construct arrays with internal overlap + + # We don't care about memory bounds, the array is not + # read/write accessed + x = np.arange(1).astype(np.int8) + + # Check low-dimensional special cases + + check_internal_overlap(x, False) # 1-dim + check_internal_overlap(x.reshape([]), False) # 0-dim + + a = as_strided(x, strides=(3, 4), shape=(4, 4)) + check_internal_overlap(a, False) + + a = as_strided(x, strides=(3, 4), shape=(5, 4)) + check_internal_overlap(a, True) + + a = as_strided(x, strides=(0,), shape=(0,)) + check_internal_overlap(a, False) + + a = as_strided(x, strides=(0,), shape=(1,)) + check_internal_overlap(a, False) + + a = as_strided(x, strides=(0,), shape=(2,)) + check_internal_overlap(a, True) + + a = as_strided(x, strides=(0, -9993), shape=(87, 22)) + check_internal_overlap(a, True) + + a = as_strided(x, strides=(0, -9993), shape=(1, 22)) + check_internal_overlap(a, False) + + a = as_strided(x, strides=(0, -9993), shape=(0, 22)) + check_internal_overlap(a, False) + + +def test_internal_overlap_fuzz(): + # Fuzz check; the brute-force check is fairly slow + + x = np.arange(1).astype(np.int8) + + overlap = 0 + no_overlap = 0 + min_count = 100 + + rng = np.random.RandomState(1234) + + while min(overlap, no_overlap) < min_count: + ndim = rng.randint(1, 4, dtype=np.intp) + + strides = tuple(rng.randint(-1000, 1000, dtype=np.intp) + for j in range(ndim)) + shape = tuple(rng.randint(1, 30, dtype=np.intp) + for j in range(ndim)) + + a = as_strided(x, strides=strides, shape=shape) + result = check_internal_overlap(a) + + if result: + overlap += 1 + else: + no_overlap += 1 + + +def test_non_ndarray_inputs(): + # Regression check for gh-5604 + + class MyArray(object): + def __init__(self, data): + self.data = data + + @property + def __array_interface__(self): + return self.data.__array_interface__ + + class MyArray2(object): + def __init__(self, data): + self.data = data + + def __array__(self): + return self.data + + for cls in [MyArray, MyArray2]: + x = np.arange(5) + + assert_(np.may_share_memory(cls(x[::2]), x[1::2])) + assert_(not np.shares_memory(cls(x[::2]), x[1::2])) + + assert_(np.shares_memory(cls(x[1::3]), x[::2])) + assert_(np.may_share_memory(cls(x[1::3]), x[::2])) + + +def view_element_first_byte(x): + """Construct an array viewing the first byte of each element of `x`""" + from numpy.lib.stride_tricks import DummyArray + interface = dict(x.__array_interface__) + interface['typestr'] = '|b1' + interface['descr'] = [('', '|b1')] + return np.asarray(DummyArray(interface, x)) + + +def assert_copy_equivalent(operation, args, out, **kwargs): + """ + Check that operation(*args, out=out) produces results + equivalent to out[...] = operation(*args, out=out.copy()) + """ + + kwargs['out'] = out + kwargs2 = dict(kwargs) + kwargs2['out'] = out.copy() + + out_orig = out.copy() + out[...] = operation(*args, **kwargs2) + expected = out.copy() + out[...] = out_orig + + got = operation(*args, **kwargs).copy() + + if (got != expected).any(): + assert_equal(got, expected) + + +class TestUFunc(object): + """ + Test ufunc call memory overlap handling + """ + + def check_unary_fuzz(self, operation, get_out_axis_size, dtype=np.int16, + count=5000): + shapes = [7, 13, 8, 21, 29, 32] + + rng = np.random.RandomState(1234) + + for ndim in range(1, 6): + x = rng.randint(0, 2**16, size=shapes[:ndim]).astype(dtype) + + it = iter_random_view_pairs(x, same_steps=False, equal_size=True) + + min_count = count // (ndim + 1)**2 + + overlapping = 0 + while overlapping < min_count: + a, b = next(it) + + a_orig = a.copy() + b_orig = b.copy() + + if get_out_axis_size is None: + assert_copy_equivalent(operation, [a], out=b) + + if np.shares_memory(a, b): + overlapping += 1 + else: + for axis in itertools.chain(range(ndim), [None]): + a[...] = a_orig + b[...] = b_orig + + # Determine size for reduction axis (None if scalar) + outsize, scalarize = get_out_axis_size(a, b, axis) + if outsize == 'skip': + continue + + # Slice b to get an output array of the correct size + sl = [slice(None)] * ndim + if axis is None: + if outsize is None: + sl = [slice(0, 1)] + [0]*(ndim - 1) + else: + sl = [slice(0, outsize)] + [0]*(ndim - 1) + else: + if outsize is None: + k = b.shape[axis]//2 + if ndim == 1: + sl[axis] = slice(k, k + 1) + else: + sl[axis] = k + else: + assert b.shape[axis] >= outsize + sl[axis] = slice(0, outsize) + b_out = b[tuple(sl)] + + if scalarize: + b_out = b_out.reshape([]) + + if np.shares_memory(a, b_out): + overlapping += 1 + + # Check result + assert_copy_equivalent(operation, [a], out=b_out, axis=axis) + + @dec.slow + def test_unary_ufunc_call_fuzz(self): + self.check_unary_fuzz(np.invert, None, np.int16) + + def test_binary_ufunc_accumulate_fuzz(self): + def get_out_axis_size(a, b, axis): + if axis is None: + if a.ndim == 1: + return a.size, False + else: + return 'skip', False # accumulate doesn't support this + else: + return a.shape[axis], False + + self.check_unary_fuzz(np.add.accumulate, get_out_axis_size, + dtype=np.int16, count=500) + + def test_binary_ufunc_reduce_fuzz(self): + def get_out_axis_size(a, b, axis): + return None, (axis is None or a.ndim == 1) + + self.check_unary_fuzz(np.add.reduce, get_out_axis_size, + dtype=np.int16, count=500) + + def test_binary_ufunc_reduceat_fuzz(self): + def get_out_axis_size(a, b, axis): + if axis is None: + if a.ndim == 1: + return a.size, False + else: + return 'skip', False # reduceat doesn't support this + else: + return a.shape[axis], False + + def do_reduceat(a, out, axis): + if axis is None: + size = len(a) + step = size//len(out) + else: + size = a.shape[axis] + step = a.shape[axis] // out.shape[axis] + idx = np.arange(0, size, step) + return np.add.reduceat(a, idx, out=out, axis=axis) + + self.check_unary_fuzz(do_reduceat, get_out_axis_size, + dtype=np.int16, count=500) + + def test_binary_ufunc_reduceat_manual(self): + def check(ufunc, a, ind, out): + c1 = ufunc.reduceat(a.copy(), ind.copy(), out=out.copy()) + c2 = ufunc.reduceat(a, ind, out=out) + assert_array_equal(c1, c2) + + # Exactly same input/output arrays + a = np.arange(10000, dtype=np.int16) + check(np.add, a, a[::-1].copy(), a) + + # Overlap with index + a = np.arange(10000, dtype=np.int16) + check(np.add, a, a[::-1], a) + + def test_unary_gufunc_fuzz(self): + shapes = [7, 13, 8, 21, 29, 32] + gufunc = umath_tests.euclidean_pdist + + rng = np.random.RandomState(1234) + + for ndim in range(2, 6): + x = rng.rand(*shapes[:ndim]) + + it = iter_random_view_pairs(x, same_steps=False, equal_size=True) + + min_count = 500 // (ndim + 1)**2 + + overlapping = 0 + while overlapping < min_count: + a, b = next(it) + + if min(a.shape[-2:]) < 2 or min(b.shape[-2:]) < 2 or a.shape[-1] < 2: + continue + + # Ensure the shapes are so that euclidean_pdist is happy + if b.shape[-1] > b.shape[-2]: + b = b[...,0,:] + else: + b = b[...,:,0] + + n = a.shape[-2] + p = n * (n - 1) // 2 + if p <= b.shape[-1] and p > 0: + b = b[...,:p] + else: + n = max(2, int(np.sqrt(b.shape[-1]))//2) + p = n * (n - 1) // 2 + a = a[...,:n,:] + b = b[...,:p] + + # Call + if np.shares_memory(a, b): + overlapping += 1 + + with np.errstate(over='ignore', invalid='ignore'): + assert_copy_equivalent(gufunc, [a], out=b) + + def test_ufunc_at_manual(self): + def check(ufunc, a, ind, b=None): + a0 = a.copy() + if b is None: + ufunc.at(a0, ind.copy()) + c1 = a0.copy() + ufunc.at(a, ind) + c2 = a.copy() + else: + ufunc.at(a0, ind.copy(), b.copy()) + c1 = a0.copy() + ufunc.at(a, ind, b) + c2 = a.copy() + assert_array_equal(c1, c2) + + # Overlap with index + a = np.arange(10000, dtype=np.int16) + check(np.invert, a[::-1], a) + + # Overlap with second data array + a = np.arange(100, dtype=np.int16) + ind = np.arange(0, 100, 2, dtype=np.int16) + check(np.add, a, ind, a[25:75]) + + def test_unary_ufunc_1d_manual(self): + # Exercise branches in PyArray_EQUIVALENTLY_ITERABLE + + def check(a, b): + a_orig = a.copy() + b_orig = b.copy() + + b0 = b.copy() + c1 = ufunc(a, out=b0) + c2 = ufunc(a, out=b) + assert_array_equal(c1, c2) + + # Trigger "fancy ufunc loop" code path + mask = view_element_first_byte(b).view(np.bool_) + + a[...] = a_orig + b[...] = b_orig + c1 = ufunc(a, out=b.copy(), where=mask.copy()).copy() + + a[...] = a_orig + b[...] = b_orig + c2 = ufunc(a, out=b, where=mask.copy()).copy() + + # Also, mask overlapping with output + a[...] = a_orig + b[...] = b_orig + c3 = ufunc(a, out=b, where=mask).copy() + + assert_array_equal(c1, c2) + assert_array_equal(c1, c3) + + dtypes = [np.int8, np.int16, np.int32, np.int64, np.float32, + np.float64, np.complex64, np.complex128] + dtypes = [np.dtype(x) for x in dtypes] + + for dtype in dtypes: + if np.issubdtype(dtype, np.integer): + ufunc = np.invert + else: + ufunc = np.reciprocal + + n = 1000 + k = 10 + indices = [ + np.index_exp[:n], + np.index_exp[k:k+n], + np.index_exp[n-1::-1], + np.index_exp[k+n-1:k-1:-1], + np.index_exp[:2*n:2], + np.index_exp[k:k+2*n:2], + np.index_exp[2*n-1::-2], + np.index_exp[k+2*n-1:k-1:-2], + ] + + for xi, yi in itertools.product(indices, indices): + v = np.arange(1, 1 + n*2 + k, dtype=dtype) + x = v[xi] + y = v[yi] + + with np.errstate(all='ignore'): + check(x, y) + + # Scalar cases + check(x[:1], y) + check(x[-1:], y) + check(x[:1].reshape([]), y) + check(x[-1:].reshape([]), y) + + def test_unary_ufunc_where_same(self): + # Check behavior at wheremask overlap + ufunc = np.invert + + def check(a, out, mask): + c1 = ufunc(a, out=out.copy(), where=mask.copy()) + c2 = ufunc(a, out=out, where=mask) + assert_array_equal(c1, c2) + + # Check behavior with same input and output arrays + x = np.arange(100).astype(np.bool_) + check(x, x, x) + check(x, x.copy(), x) + check(x, x, x.copy()) + + @dec.slow + def test_binary_ufunc_1d_manual(self): + ufunc = np.add + + def check(a, b, c): + c0 = c.copy() + c1 = ufunc(a, b, out=c0) + c2 = ufunc(a, b, out=c) + assert_array_equal(c1, c2) + + for dtype in [np.int8, np.int16, np.int32, np.int64, + np.float32, np.float64, np.complex64, np.complex128]: + # Check different data dependency orders + + n = 1000 + k = 10 + + indices = [] + for p in [1, 2]: + indices.extend([ + np.index_exp[:p*n:p], + np.index_exp[k:k+p*n:p], + np.index_exp[p*n-1::-p], + np.index_exp[k+p*n-1:k-1:-p], + ]) + + for x, y, z in itertools.product(indices, indices, indices): + v = np.arange(6*n).astype(dtype) + x = v[x] + y = v[y] + z = v[z] + + check(x, y, z) + + # Scalar cases + check(x[:1], y, z) + check(x[-1:], y, z) + check(x[:1].reshape([]), y, z) + check(x[-1:].reshape([]), y, z) + check(x, y[:1], z) + check(x, y[-1:], z) + check(x, y[:1].reshape([]), z) + check(x, y[-1:].reshape([]), z) + + def test_inplace_op_simple_manual(self): + rng = np.random.RandomState(1234) + x = rng.rand(200, 200) # bigger than bufsize + + x += x.T + assert_array_equal(x - x.T, 0) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_memmap.py b/numpy/core/tests/test_memmap.py new file mode 100644 index 0000000..1cd09ab --- /dev/null +++ b/numpy/core/tests/test_memmap.py @@ -0,0 +1,200 @@ +from __future__ import division, absolute_import, print_function + +import sys +import os +import shutil +from tempfile import NamedTemporaryFile, TemporaryFile, mktemp, mkdtemp +import mmap + +from numpy import ( + memmap, sum, average, product, ndarray, isscalar, add, subtract, multiply) +from numpy.compat import Path + +from numpy import arange, allclose, asarray +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal, + dec, suppress_warnings +) + +class TestMemmap(object): + def setup(self): + self.tmpfp = NamedTemporaryFile(prefix='mmap') + self.tempdir = mkdtemp() + self.shape = (3, 4) + self.dtype = 'float32' + self.data = arange(12, dtype=self.dtype) + self.data.resize(self.shape) + + def teardown(self): + self.tmpfp.close() + shutil.rmtree(self.tempdir) + + def test_roundtrip(self): + # Write data to file + fp = memmap(self.tmpfp, dtype=self.dtype, mode='w+', + shape=self.shape) + fp[:] = self.data[:] + del fp # Test __del__ machinery, which handles cleanup + + # Read data back from file + newfp = memmap(self.tmpfp, dtype=self.dtype, mode='r', + shape=self.shape) + assert_(allclose(self.data, newfp)) + assert_array_equal(self.data, newfp) + assert_equal(newfp.flags.writeable, False) + + def test_open_with_filename(self): + tmpname = mktemp('', 'mmap', dir=self.tempdir) + fp = memmap(tmpname, dtype=self.dtype, mode='w+', + shape=self.shape) + fp[:] = self.data[:] + del fp + + def test_unnamed_file(self): + with TemporaryFile() as f: + fp = memmap(f, dtype=self.dtype, shape=self.shape) + del fp + + def test_attributes(self): + offset = 1 + mode = "w+" + fp = memmap(self.tmpfp, dtype=self.dtype, mode=mode, + shape=self.shape, offset=offset) + assert_equal(offset, fp.offset) + assert_equal(mode, fp.mode) + del fp + + def test_filename(self): + tmpname = mktemp('', 'mmap', dir=self.tempdir) + fp = memmap(tmpname, dtype=self.dtype, mode='w+', + shape=self.shape) + abspath = os.path.abspath(tmpname) + fp[:] = self.data[:] + assert_equal(abspath, fp.filename) + b = fp[:1] + assert_equal(abspath, b.filename) + del b + del fp + + @dec.skipif(Path is None, "No pathlib.Path") + def test_path(self): + tmpname = mktemp('', 'mmap', dir=self.tempdir) + fp = memmap(Path(tmpname), dtype=self.dtype, mode='w+', + shape=self.shape) + abspath = os.path.realpath(os.path.abspath(tmpname)) + fp[:] = self.data[:] + assert_equal(abspath, str(fp.filename.resolve())) + b = fp[:1] + assert_equal(abspath, str(b.filename.resolve())) + del b + del fp + + def test_filename_fileobj(self): + fp = memmap(self.tmpfp, dtype=self.dtype, mode="w+", + shape=self.shape) + assert_equal(fp.filename, self.tmpfp.name) + + @dec.knownfailureif(sys.platform == 'gnu0', "This test is known to fail on hurd") + def test_flush(self): + fp = memmap(self.tmpfp, dtype=self.dtype, mode='w+', + shape=self.shape) + fp[:] = self.data[:] + assert_equal(fp[0], self.data[0]) + fp.flush() + + def test_del(self): + # Make sure a view does not delete the underlying mmap + fp_base = memmap(self.tmpfp, dtype=self.dtype, mode='w+', + shape=self.shape) + fp_base[0] = 5 + fp_view = fp_base[0:1] + assert_equal(fp_view[0], 5) + del fp_view + # Should still be able to access and assign values after + # deleting the view + assert_equal(fp_base[0], 5) + fp_base[0] = 6 + assert_equal(fp_base[0], 6) + + def test_arithmetic_drops_references(self): + fp = memmap(self.tmpfp, dtype=self.dtype, mode='w+', + shape=self.shape) + tmp = (fp + 10) + if isinstance(tmp, memmap): + assert_(tmp._mmap is not fp._mmap) + + def test_indexing_drops_references(self): + fp = memmap(self.tmpfp, dtype=self.dtype, mode='w+', + shape=self.shape) + tmp = fp[[(1, 2), (2, 3)]] + if isinstance(tmp, memmap): + assert_(tmp._mmap is not fp._mmap) + + def test_slicing_keeps_references(self): + fp = memmap(self.tmpfp, dtype=self.dtype, mode='w+', + shape=self.shape) + assert_(fp[:2, :2]._mmap is fp._mmap) + + def test_view(self): + fp = memmap(self.tmpfp, dtype=self.dtype, shape=self.shape) + new1 = fp.view() + new2 = new1.view() + assert_(new1.base is fp) + assert_(new2.base is fp) + new_array = asarray(fp) + assert_(new_array.base is fp) + + def test_ufunc_return_ndarray(self): + fp = memmap(self.tmpfp, dtype=self.dtype, shape=self.shape) + fp[:] = self.data + + with suppress_warnings() as sup: + sup.filter(FutureWarning, "np.average currently does not preserve") + for unary_op in [sum, average, product]: + result = unary_op(fp) + assert_(isscalar(result)) + assert_(result.__class__ is self.data[0, 0].__class__) + + assert_(unary_op(fp, axis=0).__class__ is ndarray) + assert_(unary_op(fp, axis=1).__class__ is ndarray) + + for binary_op in [add, subtract, multiply]: + assert_(binary_op(fp, self.data).__class__ is ndarray) + assert_(binary_op(self.data, fp).__class__ is ndarray) + assert_(binary_op(fp, fp).__class__ is ndarray) + + fp += 1 + assert(fp.__class__ is memmap) + add(fp, 1, out=fp) + assert(fp.__class__ is memmap) + + def test_getitem(self): + fp = memmap(self.tmpfp, dtype=self.dtype, shape=self.shape) + fp[:] = self.data + + assert_(fp[1:, :-1].__class__ is memmap) + # Fancy indexing returns a copy that is not memmapped + assert_(fp[[0, 1]].__class__ is ndarray) + + def test_memmap_subclass(self): + class MemmapSubClass(memmap): + pass + + fp = MemmapSubClass(self.tmpfp, dtype=self.dtype, shape=self.shape) + fp[:] = self.data + + # We keep previous behavior for subclasses of memmap, i.e. the + # ufunc and __getitem__ output is never turned into a ndarray + assert_(sum(fp, axis=0).__class__ is MemmapSubClass) + assert_(sum(fp).__class__ is MemmapSubClass) + assert_(fp[1:, :-1].__class__ is MemmapSubClass) + assert(fp[[0, 1]].__class__ is MemmapSubClass) + + def test_mmap_offset_greater_than_allocation_granularity(self): + size = 5 * mmap.ALLOCATIONGRANULARITY + offset = mmap.ALLOCATIONGRANULARITY + 1 + fp = memmap(self.tmpfp, shape=size, mode='w+', offset=offset) + assert_(fp.offset == offset) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py new file mode 100644 index 0000000..ab1f0e2 --- /dev/null +++ b/numpy/core/tests/test_multiarray.py @@ -0,0 +1,7406 @@ +from __future__ import division, absolute_import, print_function + +import collections +import tempfile +import sys +import shutil +import warnings +import operator +import io +import itertools +import functools +import ctypes +import os +import gc +from contextlib import contextmanager +if sys.version_info[0] >= 3: + import builtins +else: + import __builtin__ as builtins +from decimal import Decimal +from unittest import TestCase + +import numpy as np +from numpy.compat import strchar, unicode +from numpy.core.tests.test_print import in_foreign_locale +from numpy.core.multiarray_tests import ( + test_neighborhood_iterator, test_neighborhood_iterator_oob, + test_pydatamem_seteventhook_start, test_pydatamem_seteventhook_end, + test_inplace_increment, get_buffer_info, test_as_c_array, + ) +from numpy.testing import ( + run_module_suite, assert_, assert_raises, assert_warns, + assert_equal, assert_almost_equal, assert_array_equal, assert_raises_regex, + assert_array_almost_equal, assert_allclose, IS_PYPY, HAS_REFCOUNT, + assert_array_less, runstring, dec, SkipTest, temppath, suppress_warnings + ) + +# Need to test an object that does not fully implement math interface +from datetime import timedelta, datetime + + +if sys.version_info[:2] > (3, 2): + # In Python 3.3 the representation of empty shape, strides and sub-offsets + # is an empty tuple instead of None. + # http://docs.python.org/dev/whatsnew/3.3.html#api-changes + EMPTY = () +else: + EMPTY = None + + +def _aligned_zeros(shape, dtype=float, order="C", align=None): + """Allocate a new ndarray with aligned memory.""" + dtype = np.dtype(dtype) + if dtype == np.dtype(object): + # Can't do this, fall back to standard allocation (which + # should always be sufficiently aligned) + if align is not None: + raise ValueError("object array alignment not supported") + return np.zeros(shape, dtype=dtype, order=order) + if align is None: + align = dtype.alignment + if not hasattr(shape, '__len__'): + shape = (shape,) + size = functools.reduce(operator.mul, shape) * dtype.itemsize + buf = np.empty(size + align + 1, np.uint8) + offset = buf.__array_interface__['data'][0] % align + if offset != 0: + offset = align - offset + # Note: slices producing 0-size arrays do not necessarily change + # data pointer --- so we use and allocate size+1 + buf = buf[offset:offset+size+1][:-1] + data = np.ndarray(shape, dtype, buf, order=order) + data.fill(0) + return data + + +class TestFlags(object): + def setup(self): + self.a = np.arange(10) + + def test_writeable(self): + mydict = locals() + self.a.flags.writeable = False + assert_raises(ValueError, runstring, 'self.a[0] = 3', mydict) + assert_raises(ValueError, runstring, 'self.a[0:1].itemset(3)', mydict) + self.a.flags.writeable = True + self.a[0] = 5 + self.a[0] = 0 + + def test_otherflags(self): + assert_equal(self.a.flags.carray, True) + assert_equal(self.a.flags['C'], True) + assert_equal(self.a.flags.farray, False) + assert_equal(self.a.flags.behaved, True) + assert_equal(self.a.flags.fnc, False) + assert_equal(self.a.flags.forc, True) + assert_equal(self.a.flags.owndata, True) + assert_equal(self.a.flags.writeable, True) + assert_equal(self.a.flags.aligned, True) + with assert_warns(DeprecationWarning): + assert_equal(self.a.flags.updateifcopy, False) + with assert_warns(DeprecationWarning): + assert_equal(self.a.flags['U'], False) + assert_equal(self.a.flags['UPDATEIFCOPY'], False) + assert_equal(self.a.flags.writebackifcopy, False) + assert_equal(self.a.flags['X'], False) + assert_equal(self.a.flags['WRITEBACKIFCOPY'], False) + + + def test_string_align(self): + a = np.zeros(4, dtype=np.dtype('|S4')) + assert_(a.flags.aligned) + # not power of two are accessed byte-wise and thus considered aligned + a = np.zeros(5, dtype=np.dtype('|S4')) + assert_(a.flags.aligned) + + def test_void_align(self): + a = np.zeros(4, dtype=np.dtype([("a", "i4"), ("b", "i4")])) + assert_(a.flags.aligned) + + +class TestHash(object): + # see #3793 + def test_int(self): + for st, ut, s in [(np.int8, np.uint8, 8), + (np.int16, np.uint16, 16), + (np.int32, np.uint32, 32), + (np.int64, np.uint64, 64)]: + for i in range(1, s): + assert_equal(hash(st(-2**i)), hash(-2**i), + err_msg="%r: -2**%d" % (st, i)) + assert_equal(hash(st(2**(i - 1))), hash(2**(i - 1)), + err_msg="%r: 2**%d" % (st, i - 1)) + assert_equal(hash(st(2**i - 1)), hash(2**i - 1), + err_msg="%r: 2**%d - 1" % (st, i)) + + i = max(i - 1, 1) + assert_equal(hash(ut(2**(i - 1))), hash(2**(i - 1)), + err_msg="%r: 2**%d" % (ut, i - 1)) + assert_equal(hash(ut(2**i - 1)), hash(2**i - 1), + err_msg="%r: 2**%d - 1" % (ut, i)) + + +class TestAttributes(object): + def setup(self): + self.one = np.arange(10) + self.two = np.arange(20).reshape(4, 5) + self.three = np.arange(60, dtype=np.float64).reshape(2, 5, 6) + + def test_attributes(self): + assert_equal(self.one.shape, (10,)) + assert_equal(self.two.shape, (4, 5)) + assert_equal(self.three.shape, (2, 5, 6)) + self.three.shape = (10, 3, 2) + assert_equal(self.three.shape, (10, 3, 2)) + self.three.shape = (2, 5, 6) + assert_equal(self.one.strides, (self.one.itemsize,)) + num = self.two.itemsize + assert_equal(self.two.strides, (5*num, num)) + num = self.three.itemsize + assert_equal(self.three.strides, (30*num, 6*num, num)) + assert_equal(self.one.ndim, 1) + assert_equal(self.two.ndim, 2) + assert_equal(self.three.ndim, 3) + num = self.two.itemsize + assert_equal(self.two.size, 20) + assert_equal(self.two.nbytes, 20*num) + assert_equal(self.two.itemsize, self.two.dtype.itemsize) + assert_equal(self.two.base, np.arange(20)) + + def test_dtypeattr(self): + assert_equal(self.one.dtype, np.dtype(np.int_)) + assert_equal(self.three.dtype, np.dtype(np.float_)) + assert_equal(self.one.dtype.char, 'l') + assert_equal(self.three.dtype.char, 'd') + assert_(self.three.dtype.str[0] in '<>') + assert_equal(self.one.dtype.str[1], 'i') + assert_equal(self.three.dtype.str[1], 'f') + + def test_int_subclassing(self): + # Regression test for https://github.com/numpy/numpy/pull/3526 + + numpy_int = np.int_(0) + + if sys.version_info[0] >= 3: + # On Py3k int_ should not inherit from int, because it's not + # fixed-width anymore + assert_equal(isinstance(numpy_int, int), False) + else: + # Otherwise, it should inherit from int... + assert_equal(isinstance(numpy_int, int), True) + + # ... and fast-path checks on C-API level should also work + from numpy.core.multiarray_tests import test_int_subclass + assert_equal(test_int_subclass(numpy_int), True) + + def test_stridesattr(self): + x = self.one + + def make_array(size, offset, strides): + return np.ndarray(size, buffer=x, dtype=int, + offset=offset*x.itemsize, + strides=strides*x.itemsize) + + assert_equal(make_array(4, 4, -1), np.array([4, 3, 2, 1])) + assert_raises(ValueError, make_array, 4, 4, -2) + assert_raises(ValueError, make_array, 4, 2, -1) + assert_raises(ValueError, make_array, 8, 3, 1) + assert_equal(make_array(8, 3, 0), np.array([3]*8)) + # Check behavior reported in gh-2503: + assert_raises(ValueError, make_array, (2, 3), 5, np.array([-2, -3])) + make_array(0, 0, 10) + + def test_set_stridesattr(self): + x = self.one + + def make_array(size, offset, strides): + try: + r = np.ndarray([size], dtype=int, buffer=x, + offset=offset*x.itemsize) + except Exception as e: + raise RuntimeError(e) + r.strides = strides = strides*x.itemsize + return r + + assert_equal(make_array(4, 4, -1), np.array([4, 3, 2, 1])) + assert_equal(make_array(7, 3, 1), np.array([3, 4, 5, 6, 7, 8, 9])) + assert_raises(ValueError, make_array, 4, 4, -2) + assert_raises(ValueError, make_array, 4, 2, -1) + assert_raises(RuntimeError, make_array, 8, 3, 1) + # Check that the true extent of the array is used. + # Test relies on as_strided base not exposing a buffer. + x = np.lib.stride_tricks.as_strided(np.arange(1), (10, 10), (0, 0)) + + def set_strides(arr, strides): + arr.strides = strides + + assert_raises(ValueError, set_strides, x, (10*x.itemsize, x.itemsize)) + + # Test for offset calculations: + x = np.lib.stride_tricks.as_strided(np.arange(10, dtype=np.int8)[-1], + shape=(10,), strides=(-1,)) + assert_raises(ValueError, set_strides, x[::-1], -1) + a = x[::-1] + a.strides = 1 + a[::2].strides = 2 + + def test_fill(self): + for t in "?bhilqpBHILQPfdgFDGO": + x = np.empty((3, 2, 1), t) + y = np.empty((3, 2, 1), t) + x.fill(1) + y[...] = 1 + assert_equal(x, y) + + def test_fill_max_uint64(self): + x = np.empty((3, 2, 1), dtype=np.uint64) + y = np.empty((3, 2, 1), dtype=np.uint64) + value = 2**64 - 1 + y[...] = value + x.fill(value) + assert_array_equal(x, y) + + def test_fill_struct_array(self): + # Filling from a scalar + x = np.array([(0, 0.0), (1, 1.0)], dtype='i4,f8') + x.fill(x[0]) + assert_equal(x['f1'][1], x['f1'][0]) + # Filling from a tuple that can be converted + # to a scalar + x = np.zeros(2, dtype=[('a', 'f8'), ('b', 'i4')]) + x.fill((3.5, -2)) + assert_array_equal(x['a'], [3.5, 3.5]) + assert_array_equal(x['b'], [-2, -2]) + + +class TestArrayConstruction(object): + def test_array(self): + d = np.ones(6) + r = np.array([d, d]) + assert_equal(r, np.ones((2, 6))) + + d = np.ones(6) + tgt = np.ones((2, 6)) + r = np.array([d, d]) + assert_equal(r, tgt) + tgt[1] = 2 + r = np.array([d, d + 1]) + assert_equal(r, tgt) + + d = np.ones(6) + r = np.array([[d, d]]) + assert_equal(r, np.ones((1, 2, 6))) + + d = np.ones(6) + r = np.array([[d, d], [d, d]]) + assert_equal(r, np.ones((2, 2, 6))) + + d = np.ones((6, 6)) + r = np.array([d, d]) + assert_equal(r, np.ones((2, 6, 6))) + + d = np.ones((6, )) + r = np.array([[d, d + 1], d + 2]) + assert_equal(len(r), 2) + assert_equal(r[0], [d, d + 1]) + assert_equal(r[1], d + 2) + + tgt = np.ones((2, 3), dtype=bool) + tgt[0, 2] = False + tgt[1, 0:2] = False + r = np.array([[True, True, False], [False, False, True]]) + assert_equal(r, tgt) + r = np.array([[True, False], [True, False], [False, True]]) + assert_equal(r, tgt.T) + + def test_array_empty(self): + assert_raises(TypeError, np.array) + + def test_array_copy_false(self): + d = np.array([1, 2, 3]) + e = np.array(d, copy=False) + d[1] = 3 + assert_array_equal(e, [1, 3, 3]) + e = np.array(d, copy=False, order='F') + d[1] = 4 + assert_array_equal(e, [1, 4, 3]) + e[2] = 7 + assert_array_equal(d, [1, 4, 7]) + + def test_array_copy_true(self): + d = np.array([[1,2,3], [1, 2, 3]]) + e = np.array(d, copy=True) + d[0, 1] = 3 + e[0, 2] = -7 + assert_array_equal(e, [[1, 2, -7], [1, 2, 3]]) + assert_array_equal(d, [[1, 3, 3], [1, 2, 3]]) + e = np.array(d, copy=True, order='F') + d[0, 1] = 5 + e[0, 2] = 7 + assert_array_equal(e, [[1, 3, 7], [1, 2, 3]]) + assert_array_equal(d, [[1, 5, 3], [1,2,3]]) + + def test_array_cont(self): + d = np.ones(10)[::2] + assert_(np.ascontiguousarray(d).flags.c_contiguous) + assert_(np.ascontiguousarray(d).flags.f_contiguous) + assert_(np.asfortranarray(d).flags.c_contiguous) + assert_(np.asfortranarray(d).flags.f_contiguous) + d = np.ones((10, 10))[::2,::2] + assert_(np.ascontiguousarray(d).flags.c_contiguous) + assert_(np.asfortranarray(d).flags.f_contiguous) + + +class TestAssignment(object): + def test_assignment_broadcasting(self): + a = np.arange(6).reshape(2, 3) + + # Broadcasting the input to the output + a[...] = np.arange(3) + assert_equal(a, [[0, 1, 2], [0, 1, 2]]) + a[...] = np.arange(2).reshape(2, 1) + assert_equal(a, [[0, 0, 0], [1, 1, 1]]) + + # For compatibility with <= 1.5, a limited version of broadcasting + # the output to the input. + # + # This behavior is inconsistent with NumPy broadcasting + # in general, because it only uses one of the two broadcasting + # rules (adding a new "1" dimension to the left of the shape), + # applied to the output instead of an input. In NumPy 2.0, this kind + # of broadcasting assignment will likely be disallowed. + a[...] = np.arange(6)[::-1].reshape(1, 2, 3) + assert_equal(a, [[5, 4, 3], [2, 1, 0]]) + # The other type of broadcasting would require a reduction operation. + + def assign(a, b): + a[...] = b + + assert_raises(ValueError, assign, a, np.arange(12).reshape(2, 2, 3)) + + def test_assignment_errors(self): + # Address issue #2276 + class C: + pass + a = np.zeros(1) + + def assign(v): + a[0] = v + + assert_raises((AttributeError, TypeError), assign, C()) + assert_raises(ValueError, assign, [1]) + + def test_unicode_assignment(self): + # gh-5049 + from numpy.core.numeric import set_string_function + + @contextmanager + def inject_str(s): + """ replace ndarray.__str__ temporarily """ + set_string_function(lambda x: s, repr=False) + try: + yield + finally: + set_string_function(None, repr=False) + + a1d = np.array([u'test']) + a0d = np.array(u'done') + with inject_str(u'bad'): + a1d[0] = a0d # previously this would invoke __str__ + assert_equal(a1d[0], u'done') + + # this would crash for the same reason + np.array([np.array(u'\xe5\xe4\xf6')]) + + def test_stringlike_empty_list(self): + # gh-8902 + u = np.array([u'done']) + b = np.array([b'done']) + + class bad_sequence(object): + def __getitem__(self): pass + def __len__(self): raise RuntimeError + + assert_raises(ValueError, operator.setitem, u, 0, []) + assert_raises(ValueError, operator.setitem, b, 0, []) + + assert_raises(ValueError, operator.setitem, u, 0, bad_sequence()) + assert_raises(ValueError, operator.setitem, b, 0, bad_sequence()) + + def test_longdouble_assignment(self): + # only relevant if longdouble is larger than float + # we're looking for loss of precision + + for dtype in (np.longdouble, np.longcomplex): + # gh-8902 + tinyb = np.nextafter(np.longdouble(0), 1).astype(dtype) + tinya = np.nextafter(np.longdouble(0), -1).astype(dtype) + + # construction + tiny1d = np.array([tinya]) + assert_equal(tiny1d[0], tinya) + + # scalar = scalar + tiny1d[0] = tinyb + assert_equal(tiny1d[0], tinyb) + + # 0d = scalar + tiny1d[0, ...] = tinya + assert_equal(tiny1d[0], tinya) + + # 0d = 0d + tiny1d[0, ...] = tinyb[...] + assert_equal(tiny1d[0], tinyb) + + # scalar = 0d + tiny1d[0] = tinyb[...] + assert_equal(tiny1d[0], tinyb) + + arr = np.array([np.array(tinya)]) + assert_equal(arr[0], tinya) + + def test_cast_to_string(self): + # cast to str should do "str(scalar)", not "str(scalar.item())" + # Example: In python2, str(float) is truncated, so we want to avoid + # str(np.float64(...).item()) as this would incorrectly truncate. + a = np.zeros(1, dtype='S20') + a[:] = np.array(['1.12345678901234567890'], dtype='f8') + assert_equal(a[0], b"1.1234567890123457") + + +class TestDtypedescr(object): + def test_construction(self): + d1 = np.dtype('i4') + assert_equal(d1, np.dtype(np.int32)) + d2 = np.dtype('f8') + assert_equal(d2, np.dtype(np.float64)) + + def test_byteorders(self): + assert_(np.dtype('i4')) + assert_(np.dtype([('a', 'i4')])) + + def test_structured_non_void(self): + fields = [('a', '= 3) + def test_sequence_long(self): + assert_equal(np.array([long(4), long(4)]).dtype, np.long) + assert_equal(np.array([long(4), 2**80]).dtype, object) + assert_equal(np.array([long(4), 2**80, long(4)]).dtype, object) + assert_equal(np.array([2**80, long(4)]).dtype, object) + + def test_non_sequence_sequence(self): + """Should not segfault. + + Class Fail breaks the sequence protocol for new style classes, i.e., + those derived from object. Class Map is a mapping type indicated by + raising a ValueError. At some point we may raise a warning instead + of an error in the Fail case. + + """ + class Fail(object): + def __len__(self): + return 1 + + def __getitem__(self, index): + raise ValueError() + + class Map(object): + def __len__(self): + return 1 + + def __getitem__(self, index): + raise KeyError() + + a = np.array([Map()]) + assert_(a.shape == (1,)) + assert_(a.dtype == np.dtype(object)) + assert_raises(ValueError, np.array, [Fail()]) + + def test_no_len_object_type(self): + # gh-5100, want object array from iterable object without len() + class Point2: + def __init__(self): + pass + + def __getitem__(self, ind): + if ind in [0, 1]: + return ind + else: + raise IndexError() + d = np.array([Point2(), Point2(), Point2()]) + assert_equal(d.dtype, np.dtype(object)) + + def test_false_len_sequence(self): + # gh-7264, segfault for this example + class C: + def __getitem__(self, i): + raise IndexError + def __len__(self): + return 42 + + assert_raises(ValueError, np.array, C()) # segfault? + + def test_failed_len_sequence(self): + # gh-7393 + class A(object): + def __init__(self, data): + self._data = data + def __getitem__(self, item): + return type(self)(self._data[item]) + def __len__(self): + return len(self._data) + + # len(d) should give 3, but len(d[0]) will fail + d = A([1,2,3]) + assert_equal(len(np.array(d)), 3) + + def test_array_too_big(self): + # Test that array creation succeeds for arrays addressable by intp + # on the byte level and fails for too large arrays. + buf = np.zeros(100) + + max_bytes = np.iinfo(np.intp).max + for dtype in ["intp", "S20", "b"]: + dtype = np.dtype(dtype) + itemsize = dtype.itemsize + + np.ndarray(buffer=buf, strides=(0,), + shape=(max_bytes//itemsize,), dtype=dtype) + assert_raises(ValueError, np.ndarray, buffer=buf, strides=(0,), + shape=(max_bytes//itemsize + 1,), dtype=dtype) + + +class TestStructured(object): + def test_subarray_field_access(self): + a = np.zeros((3, 5), dtype=[('a', ('i4', (2, 2)))]) + a['a'] = np.arange(60).reshape(3, 5, 2, 2) + + # Since the subarray is always in C-order, a transpose + # does not swap the subarray: + assert_array_equal(a.T['a'], a['a'].transpose(1, 0, 2, 3)) + + # In Fortran order, the subarray gets appended + # like in all other cases, not prepended as a special case + b = a.copy(order='F') + assert_equal(a['a'].shape, b['a'].shape) + assert_equal(a.T['a'].shape, a.T.copy()['a'].shape) + + def test_subarray_comparison(self): + # Check that comparisons between record arrays with + # multi-dimensional field types work properly + a = np.rec.fromrecords( + [([1, 2, 3], 'a', [[1, 2], [3, 4]]), ([3, 3, 3], 'b', [[0, 0], [0, 0]])], + dtype=[('a', ('f4', 3)), ('b', object), ('c', ('i4', (2, 2)))]) + b = a.copy() + assert_equal(a == b, [True, True]) + assert_equal(a != b, [False, False]) + b[1].b = 'c' + assert_equal(a == b, [True, False]) + assert_equal(a != b, [False, True]) + for i in range(3): + b[0].a = a[0].a + b[0].a[i] = 5 + assert_equal(a == b, [False, False]) + assert_equal(a != b, [True, True]) + for i in range(2): + for j in range(2): + b = a.copy() + b[0].c[i, j] = 10 + assert_equal(a == b, [False, True]) + assert_equal(a != b, [True, False]) + + # Check that broadcasting with a subarray works + a = np.array([[(0,)], [(1,)]], dtype=[('a', 'f8')]) + b = np.array([(0,), (0,), (1,)], dtype=[('a', 'f8')]) + assert_equal(a == b, [[True, True, False], [False, False, True]]) + assert_equal(b == a, [[True, True, False], [False, False, True]]) + a = np.array([[(0,)], [(1,)]], dtype=[('a', 'f8', (1,))]) + b = np.array([(0,), (0,), (1,)], dtype=[('a', 'f8', (1,))]) + assert_equal(a == b, [[True, True, False], [False, False, True]]) + assert_equal(b == a, [[True, True, False], [False, False, True]]) + a = np.array([[([0, 0],)], [([1, 1],)]], dtype=[('a', 'f8', (2,))]) + b = np.array([([0, 0],), ([0, 1],), ([1, 1],)], dtype=[('a', 'f8', (2,))]) + assert_equal(a == b, [[True, False, False], [False, False, True]]) + assert_equal(b == a, [[True, False, False], [False, False, True]]) + + # Check that broadcasting Fortran-style arrays with a subarray work + a = np.array([[([0, 0],)], [([1, 1],)]], dtype=[('a', 'f8', (2,))], order='F') + b = np.array([([0, 0],), ([0, 1],), ([1, 1],)], dtype=[('a', 'f8', (2,))]) + assert_equal(a == b, [[True, False, False], [False, False, True]]) + assert_equal(b == a, [[True, False, False], [False, False, True]]) + + # Check that incompatible sub-array shapes don't result to broadcasting + x = np.zeros((1,), dtype=[('a', ('f4', (1, 2))), ('b', 'i1')]) + y = np.zeros((1,), dtype=[('a', ('f4', (2,))), ('b', 'i1')]) + # This comparison invokes deprecated behaviour, and will probably + # start raising an error eventually. What we really care about in this + # test is just that it doesn't return True. + with suppress_warnings() as sup: + sup.filter(FutureWarning, "elementwise == comparison failed") + assert_equal(x == y, False) + + x = np.zeros((1,), dtype=[('a', ('f4', (2, 1))), ('b', 'i1')]) + y = np.zeros((1,), dtype=[('a', ('f4', (2,))), ('b', 'i1')]) + # This comparison invokes deprecated behaviour, and will probably + # start raising an error eventually. What we really care about in this + # test is just that it doesn't return True. + with suppress_warnings() as sup: + sup.filter(FutureWarning, "elementwise == comparison failed") + assert_equal(x == y, False) + + # Check that structured arrays that are different only in + # byte-order work + a = np.array([(5, 42), (10, 1)], dtype=[('a', '>i8'), ('b', 'f8')]) + assert_equal(a == b, [False, True]) + + def test_casting(self): + # Check that casting a structured array to change its byte order + # works + a = np.array([(1,)], dtype=[('a', 'i4')], casting='unsafe')) + b = a.astype([('a', '>i4')]) + assert_equal(b, a.byteswap().newbyteorder()) + assert_equal(a['a'][0], b['a'][0]) + + # Check that equality comparison works on structured arrays if + # they are 'equiv'-castable + a = np.array([(5, 42), (10, 1)], dtype=[('a', '>i4'), ('b', 'f8')]) + assert_(np.can_cast(a.dtype, b.dtype, casting='equiv')) + assert_equal(a == b, [True, True]) + + # Check that 'equiv' casting can change byte order + assert_(np.can_cast(a.dtype, b.dtype, casting='equiv')) + c = a.astype(b.dtype, casting='equiv') + assert_equal(a == c, [True, True]) + + # Check that 'safe' casting can change byte order and up-cast + # fields + t = [('a', 'f8')] + assert_(np.can_cast(a.dtype, t, casting='safe')) + c = a.astype(t, casting='safe') + assert_equal((c == np.array([(5, 42), (10, 1)], dtype=t)), + [True, True]) + + # Check that 'same_kind' casting can change byte order and + # change field widths within a "kind" + t = [('a', 'f4')] + assert_(np.can_cast(a.dtype, t, casting='same_kind')) + c = a.astype(t, casting='same_kind') + assert_equal((c == np.array([(5, 42), (10, 1)], dtype=t)), + [True, True]) + + # Check that casting fails if the casting rule should fail on + # any of the fields + t = [('a', '>i8'), ('b', 'i2'), ('b', 'i8'), ('b', 'i4')] + assert_(not np.can_cast(a.dtype, t, casting=casting)) + t = [('a', '>i4'), ('b', ' false + for n in range(3): + v = np.array(b'', (dtype, n)) + assert_equal(bool(v), False) + assert_equal(bool(v[()]), False) + assert_equal(v.astype(bool), False) + assert_(isinstance(v.astype(bool), np.ndarray)) + assert_(v[()].astype(bool) is np.False_) + + # anything else -> true + for n in range(1, 4): + for val in [b'a', b'0', b' ']: + v = np.array(val, (dtype, n)) + assert_equal(bool(v), True) + assert_equal(bool(v[()]), True) + assert_equal(v.astype(bool), True) + assert_(isinstance(v.astype(bool), np.ndarray)) + assert_(v[()].astype(bool) is np.True_) + + def test_cast_from_void(self): + self._test_cast_from_flexible(np.void) + + @dec.knownfailureif(True, "See gh-9847") + def test_cast_from_unicode(self): + self._test_cast_from_flexible(np.unicode_) + + @dec.knownfailureif(True, "See gh-9847") + def test_cast_from_bytes(self): + self._test_cast_from_flexible(np.bytes_) + + +class TestZeroSizeFlexible(object): + @staticmethod + def _zeros(shape, dtype=str): + dtype = np.dtype(dtype) + if dtype == np.void: + return np.zeros(shape, dtype=(dtype, 0)) + + # not constructable directly + dtype = np.dtype([('x', dtype, 0)]) + return np.zeros(shape, dtype=dtype)['x'] + + def test_create(self): + zs = self._zeros(10, bytes) + assert_equal(zs.itemsize, 0) + zs = self._zeros(10, np.void) + assert_equal(zs.itemsize, 0) + zs = self._zeros(10, unicode) + assert_equal(zs.itemsize, 0) + + def _test_sort_partition(self, name, kinds, **kwargs): + # Previously, these would all hang + for dt in [bytes, np.void, unicode]: + zs = self._zeros(10, dt) + sort_method = getattr(zs, name) + sort_func = getattr(np, name) + for kind in kinds: + sort_method(kind=kind, **kwargs) + sort_func(zs, kind=kind, **kwargs) + + def test_sort(self): + self._test_sort_partition('sort', kinds='qhm') + + def test_argsort(self): + self._test_sort_partition('argsort', kinds='qhm') + + def test_partition(self): + self._test_sort_partition('partition', kinds=['introselect'], kth=2) + + def test_argpartition(self): + self._test_sort_partition('argpartition', kinds=['introselect'], kth=2) + + def test_resize(self): + # previously an error + for dt in [bytes, np.void, unicode]: + zs = self._zeros(10, dt) + zs.resize(25) + zs.resize((10, 10)) + + def test_view(self): + for dt in [bytes, np.void, unicode]: + zs = self._zeros(10, dt) + + # viewing as itself should be allowed + assert_equal(zs.view(dt).dtype, np.dtype(dt)) + + # viewing as any non-empty type gives an empty result + assert_equal(zs.view((dt, 1)).shape, (0,)) + + def test_pickle(self): + import pickle + for dt in [bytes, np.void, unicode]: + zs = self._zeros(10, dt) + p = pickle.dumps(zs) + zs2 = pickle.loads(p) + + assert_equal(zs.dtype, zs2.dtype) + + +class TestMethods(object): + def test_compress(self): + tgt = [[5, 6, 7, 8, 9]] + arr = np.arange(10).reshape(2, 5) + out = arr.compress([0, 1], axis=0) + assert_equal(out, tgt) + + tgt = [[1, 3], [6, 8]] + out = arr.compress([0, 1, 0, 1, 0], axis=1) + assert_equal(out, tgt) + + tgt = [[1], [6]] + arr = np.arange(10).reshape(2, 5) + out = arr.compress([0, 1], axis=1) + assert_equal(out, tgt) + + arr = np.arange(10).reshape(2, 5) + out = arr.compress([0, 1]) + assert_equal(out, 1) + + def test_choose(self): + x = 2*np.ones((3,), dtype=int) + y = 3*np.ones((3,), dtype=int) + x2 = 2*np.ones((2, 3), dtype=int) + y2 = 3*np.ones((2, 3), dtype=int) + ind = np.array([0, 0, 1]) + + A = ind.choose((x, y)) + assert_equal(A, [2, 2, 3]) + + A = ind.choose((x2, y2)) + assert_equal(A, [[2, 2, 3], [2, 2, 3]]) + + A = ind.choose((x, y2)) + assert_equal(A, [[2, 2, 3], [2, 2, 3]]) + + def test_prod(self): + ba = [1, 2, 10, 11, 6, 5, 4] + ba2 = [[1, 2, 3, 4], [5, 6, 7, 9], [10, 3, 4, 5]] + + for ctype in [np.int16, np.uint16, np.int32, np.uint32, + np.float32, np.float64, np.complex64, np.complex128]: + a = np.array(ba, ctype) + a2 = np.array(ba2, ctype) + if ctype in ['1', 'b']: + assert_raises(ArithmeticError, a.prod) + assert_raises(ArithmeticError, a2.prod, axis=1) + else: + assert_equal(a.prod(axis=0), 26400) + assert_array_equal(a2.prod(axis=0), + np.array([50, 36, 84, 180], ctype)) + assert_array_equal(a2.prod(axis=-1), + np.array([24, 1890, 600], ctype)) + + def test_repeat(self): + m = np.array([1, 2, 3, 4, 5, 6]) + m_rect = m.reshape((2, 3)) + + A = m.repeat([1, 3, 2, 1, 1, 2]) + assert_equal(A, [1, 2, 2, 2, 3, + 3, 4, 5, 6, 6]) + + A = m.repeat(2) + assert_equal(A, [1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6]) + + A = m_rect.repeat([2, 1], axis=0) + assert_equal(A, [[1, 2, 3], + [1, 2, 3], + [4, 5, 6]]) + + A = m_rect.repeat([1, 3, 2], axis=1) + assert_equal(A, [[1, 2, 2, 2, 3, 3], + [4, 5, 5, 5, 6, 6]]) + + A = m_rect.repeat(2, axis=0) + assert_equal(A, [[1, 2, 3], + [1, 2, 3], + [4, 5, 6], + [4, 5, 6]]) + + A = m_rect.repeat(2, axis=1) + assert_equal(A, [[1, 1, 2, 2, 3, 3], + [4, 4, 5, 5, 6, 6]]) + + def test_reshape(self): + arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) + + tgt = [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]] + assert_equal(arr.reshape(2, 6), tgt) + + tgt = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] + assert_equal(arr.reshape(3, 4), tgt) + + tgt = [[1, 10, 8, 6], [4, 2, 11, 9], [7, 5, 3, 12]] + assert_equal(arr.reshape((3, 4), order='F'), tgt) + + tgt = [[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]] + assert_equal(arr.T.reshape((3, 4), order='C'), tgt) + + def test_round(self): + def check_round(arr, expected, *round_args): + assert_equal(arr.round(*round_args), expected) + # With output array + out = np.zeros_like(arr) + res = arr.round(*round_args, out=out) + assert_equal(out, expected) + assert_equal(out, res) + + check_round(np.array([1.2, 1.5]), [1, 2]) + check_round(np.array(1.5), 2) + check_round(np.array([12.2, 15.5]), [10, 20], -1) + check_round(np.array([12.15, 15.51]), [12.2, 15.5], 1) + # Complex rounding + check_round(np.array([4.5 + 1.5j]), [4 + 2j]) + check_round(np.array([12.5 + 15.5j]), [10 + 20j], -1) + + def test_squeeze(self): + a = np.array([[[1], [2], [3]]]) + assert_equal(a.squeeze(), [1, 2, 3]) + assert_equal(a.squeeze(axis=(0,)), [[1], [2], [3]]) + assert_raises(ValueError, a.squeeze, axis=(1,)) + assert_equal(a.squeeze(axis=(2,)), [[1, 2, 3]]) + + def test_transpose(self): + a = np.array([[1, 2], [3, 4]]) + assert_equal(a.transpose(), [[1, 3], [2, 4]]) + assert_raises(ValueError, lambda: a.transpose(0)) + assert_raises(ValueError, lambda: a.transpose(0, 0)) + assert_raises(ValueError, lambda: a.transpose(0, 1, 2)) + + def test_sort(self): + # test ordering for floats and complex containing nans. It is only + # necessary to check the less-than comparison, so sorts that + # only follow the insertion sort path are sufficient. We only + # test doubles and complex doubles as the logic is the same. + + # check doubles + msg = "Test real sort order with nans" + a = np.array([np.nan, 1, 0]) + b = np.sort(a) + assert_equal(b, a[::-1], msg) + # check complex + msg = "Test complex sort order with nans" + a = np.zeros(9, dtype=np.complex128) + a.real += [np.nan, np.nan, np.nan, 1, 0, 1, 1, 0, 0] + a.imag += [np.nan, 1, 0, np.nan, np.nan, 1, 0, 1, 0] + b = np.sort(a) + assert_equal(b, a[::-1], msg) + + # all c scalar sorts use the same code with different types + # so it suffices to run a quick check with one type. The number + # of sorted items must be greater than ~50 to check the actual + # algorithm because quick and merge sort fall over to insertion + # sort for small arrays. + a = np.arange(101) + b = a[::-1].copy() + for kind in ['q', 'm', 'h']: + msg = "scalar sort, kind=%s" % kind + c = a.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + c = b.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + + # test complex sorts. These use the same code as the scalars + # but the compare function differs. + ai = a*1j + 1 + bi = b*1j + 1 + for kind in ['q', 'm', 'h']: + msg = "complex sort, real part == 1, kind=%s" % kind + c = ai.copy() + c.sort(kind=kind) + assert_equal(c, ai, msg) + c = bi.copy() + c.sort(kind=kind) + assert_equal(c, ai, msg) + ai = a + 1j + bi = b + 1j + for kind in ['q', 'm', 'h']: + msg = "complex sort, imag part == 1, kind=%s" % kind + c = ai.copy() + c.sort(kind=kind) + assert_equal(c, ai, msg) + c = bi.copy() + c.sort(kind=kind) + assert_equal(c, ai, msg) + + # test sorting of complex arrays requiring byte-swapping, gh-5441 + for endianess in '<>': + for dt in np.typecodes['Complex']: + arr = np.array([1+3.j, 2+2.j, 3+1.j], dtype=endianess + dt) + c = arr.copy() + c.sort() + msg = 'byte-swapped complex sort, dtype={0}'.format(dt) + assert_equal(c, arr, msg) + + # test string sorts. + s = 'aaaaaaaa' + a = np.array([s + chr(i) for i in range(101)]) + b = a[::-1].copy() + for kind in ['q', 'm', 'h']: + msg = "string sort, kind=%s" % kind + c = a.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + c = b.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + + # test unicode sorts. + s = 'aaaaaaaa' + a = np.array([s + chr(i) for i in range(101)], dtype=np.unicode) + b = a[::-1].copy() + for kind in ['q', 'm', 'h']: + msg = "unicode sort, kind=%s" % kind + c = a.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + c = b.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + + # test object array sorts. + a = np.empty((101,), dtype=object) + a[:] = list(range(101)) + b = a[::-1] + for kind in ['q', 'h', 'm']: + msg = "object sort, kind=%s" % kind + c = a.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + c = b.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + + # test record array sorts. + dt = np.dtype([('f', float), ('i', int)]) + a = np.array([(i, i) for i in range(101)], dtype=dt) + b = a[::-1] + for kind in ['q', 'h', 'm']: + msg = "object sort, kind=%s" % kind + c = a.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + c = b.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + + # test datetime64 sorts. + a = np.arange(0, 101, dtype='datetime64[D]') + b = a[::-1] + for kind in ['q', 'h', 'm']: + msg = "datetime64 sort, kind=%s" % kind + c = a.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + c = b.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + + # test timedelta64 sorts. + a = np.arange(0, 101, dtype='timedelta64[D]') + b = a[::-1] + for kind in ['q', 'h', 'm']: + msg = "timedelta64 sort, kind=%s" % kind + c = a.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + c = b.copy() + c.sort(kind=kind) + assert_equal(c, a, msg) + + # check axis handling. This should be the same for all type + # specific sorts, so we only check it for one type and one kind + a = np.array([[3, 2], [1, 0]]) + b = np.array([[1, 0], [3, 2]]) + c = np.array([[2, 3], [0, 1]]) + d = a.copy() + d.sort(axis=0) + assert_equal(d, b, "test sort with axis=0") + d = a.copy() + d.sort(axis=1) + assert_equal(d, c, "test sort with axis=1") + d = a.copy() + d.sort() + assert_equal(d, c, "test sort with default axis") + + # check axis handling for multidimensional empty arrays + a = np.array([]) + a.shape = (3, 2, 1, 0) + for axis in range(-a.ndim, a.ndim): + msg = 'test empty array sort with axis={0}'.format(axis) + assert_equal(np.sort(a, axis=axis), a, msg) + msg = 'test empty array sort with axis=None' + assert_equal(np.sort(a, axis=None), a.ravel(), msg) + + # test generic class with bogus ordering, + # should not segfault. + class Boom(object): + def __lt__(self, other): + return True + + a = np.array([Boom()]*100, dtype=object) + for kind in ['q', 'm', 'h']: + msg = "bogus comparison object sort, kind=%s" % kind + c.sort(kind=kind) + + def test_void_sort(self): + # gh-8210 - previously segfaulted + for i in range(4): + arr = np.empty(1000, 'V4') + arr[::-1].sort() + + dt = np.dtype([('val', 'i4', (1,))]) + for i in range(4): + arr = np.empty(1000, dt) + arr[::-1].sort() + + def test_sort_raises(self): + #gh-9404 + arr = np.array([0, datetime.now(), 1], dtype=object) + for kind in ['q', 'm', 'h']: + assert_raises(TypeError, arr.sort, kind=kind) + #gh-3879 + class Raiser(object): + def raises_anything(*args, **kwargs): + raise TypeError("SOMETHING ERRORED") + __eq__ = __ne__ = __lt__ = __gt__ = __ge__ = __le__ = raises_anything + arr = np.array([[Raiser(), n] for n in range(10)]).reshape(-1) + np.random.shuffle(arr) + for kind in ['q', 'm', 'h']: + assert_raises(TypeError, arr.sort, kind=kind) + + def test_sort_degraded(self): + # test degraded dataset would take minutes to run with normal qsort + d = np.arange(1000000) + do = d.copy() + x = d + # create a median of 3 killer where each median is the sorted second + # last element of the quicksort partition + while x.size > 3: + mid = x.size // 2 + x[mid], x[-2] = x[-2], x[mid] + x = x[:-2] + + assert_equal(np.sort(d), do) + assert_equal(d[np.argsort(d)], do) + + def test_copy(self): + def assert_fortran(arr): + assert_(arr.flags.fortran) + assert_(arr.flags.f_contiguous) + assert_(not arr.flags.c_contiguous) + + def assert_c(arr): + assert_(not arr.flags.fortran) + assert_(not arr.flags.f_contiguous) + assert_(arr.flags.c_contiguous) + + a = np.empty((2, 2), order='F') + # Test copying a Fortran array + assert_c(a.copy()) + assert_c(a.copy('C')) + assert_fortran(a.copy('F')) + assert_fortran(a.copy('A')) + + # Now test starting with a C array. + a = np.empty((2, 2), order='C') + assert_c(a.copy()) + assert_c(a.copy('C')) + assert_fortran(a.copy('F')) + assert_c(a.copy('A')) + + def test_sort_order(self): + # Test sorting an array with fields + x1 = np.array([21, 32, 14]) + x2 = np.array(['my', 'first', 'name']) + x3 = np.array([3.1, 4.5, 6.2]) + r = np.rec.fromarrays([x1, x2, x3], names='id,word,number') + + r.sort(order=['id']) + assert_equal(r.id, np.array([14, 21, 32])) + assert_equal(r.word, np.array(['name', 'my', 'first'])) + assert_equal(r.number, np.array([6.2, 3.1, 4.5])) + + r.sort(order=['word']) + assert_equal(r.id, np.array([32, 21, 14])) + assert_equal(r.word, np.array(['first', 'my', 'name'])) + assert_equal(r.number, np.array([4.5, 3.1, 6.2])) + + r.sort(order=['number']) + assert_equal(r.id, np.array([21, 32, 14])) + assert_equal(r.word, np.array(['my', 'first', 'name'])) + assert_equal(r.number, np.array([3.1, 4.5, 6.2])) + + assert_raises_regex(ValueError, 'duplicate', + lambda: r.sort(order=['id', 'id'])) + + if sys.byteorder == 'little': + strtype = '>i2' + else: + strtype = '': + for dt in np.typecodes['Complex']: + arr = np.array([1+3.j, 2+2.j, 3+1.j], dtype=endianess + dt) + msg = 'byte-swapped complex argsort, dtype={0}'.format(dt) + assert_equal(arr.argsort(), + np.arange(len(arr), dtype=np.intp), msg) + + # test string argsorts. + s = 'aaaaaaaa' + a = np.array([s + chr(i) for i in range(101)]) + b = a[::-1].copy() + r = np.arange(101) + rr = r[::-1] + for kind in ['q', 'm', 'h']: + msg = "string argsort, kind=%s" % kind + assert_equal(a.copy().argsort(kind=kind), r, msg) + assert_equal(b.copy().argsort(kind=kind), rr, msg) + + # test unicode argsorts. + s = 'aaaaaaaa' + a = np.array([s + chr(i) for i in range(101)], dtype=np.unicode) + b = a[::-1] + r = np.arange(101) + rr = r[::-1] + for kind in ['q', 'm', 'h']: + msg = "unicode argsort, kind=%s" % kind + assert_equal(a.copy().argsort(kind=kind), r, msg) + assert_equal(b.copy().argsort(kind=kind), rr, msg) + + # test object array argsorts. + a = np.empty((101,), dtype=object) + a[:] = list(range(101)) + b = a[::-1] + r = np.arange(101) + rr = r[::-1] + for kind in ['q', 'm', 'h']: + msg = "object argsort, kind=%s" % kind + assert_equal(a.copy().argsort(kind=kind), r, msg) + assert_equal(b.copy().argsort(kind=kind), rr, msg) + + # test structured array argsorts. + dt = np.dtype([('f', float), ('i', int)]) + a = np.array([(i, i) for i in range(101)], dtype=dt) + b = a[::-1] + r = np.arange(101) + rr = r[::-1] + for kind in ['q', 'm', 'h']: + msg = "structured array argsort, kind=%s" % kind + assert_equal(a.copy().argsort(kind=kind), r, msg) + assert_equal(b.copy().argsort(kind=kind), rr, msg) + + # test datetime64 argsorts. + a = np.arange(0, 101, dtype='datetime64[D]') + b = a[::-1] + r = np.arange(101) + rr = r[::-1] + for kind in ['q', 'h', 'm']: + msg = "datetime64 argsort, kind=%s" % kind + assert_equal(a.copy().argsort(kind=kind), r, msg) + assert_equal(b.copy().argsort(kind=kind), rr, msg) + + # test timedelta64 argsorts. + a = np.arange(0, 101, dtype='timedelta64[D]') + b = a[::-1] + r = np.arange(101) + rr = r[::-1] + for kind in ['q', 'h', 'm']: + msg = "timedelta64 argsort, kind=%s" % kind + assert_equal(a.copy().argsort(kind=kind), r, msg) + assert_equal(b.copy().argsort(kind=kind), rr, msg) + + # check axis handling. This should be the same for all type + # specific argsorts, so we only check it for one type and one kind + a = np.array([[3, 2], [1, 0]]) + b = np.array([[1, 1], [0, 0]]) + c = np.array([[1, 0], [1, 0]]) + assert_equal(a.copy().argsort(axis=0), b) + assert_equal(a.copy().argsort(axis=1), c) + assert_equal(a.copy().argsort(), c) + + # check axis handling for multidimensional empty arrays + a = np.array([]) + a.shape = (3, 2, 1, 0) + for axis in range(-a.ndim, a.ndim): + msg = 'test empty array argsort with axis={0}'.format(axis) + assert_equal(np.argsort(a, axis=axis), + np.zeros_like(a, dtype=np.intp), msg) + msg = 'test empty array argsort with axis=None' + assert_equal(np.argsort(a, axis=None), + np.zeros_like(a.ravel(), dtype=np.intp), msg) + + # check that stable argsorts are stable + r = np.arange(100) + # scalars + a = np.zeros(100) + assert_equal(a.argsort(kind='m'), r) + # complex + a = np.zeros(100, dtype=complex) + assert_equal(a.argsort(kind='m'), r) + # string + a = np.array(['aaaaaaaaa' for i in range(100)]) + assert_equal(a.argsort(kind='m'), r) + # unicode + a = np.array(['aaaaaaaaa' for i in range(100)], dtype=np.unicode) + assert_equal(a.argsort(kind='m'), r) + + def test_sort_unicode_kind(self): + d = np.arange(10) + k = b'\xc3\xa4'.decode("UTF8") + assert_raises(ValueError, d.sort, kind=k) + assert_raises(ValueError, d.argsort, kind=k) + + def test_searchsorted(self): + # test for floats and complex containing nans. The logic is the + # same for all float types so only test double types for now. + # The search sorted routines use the compare functions for the + # array type, so this checks if that is consistent with the sort + # order. + + # check double + a = np.array([0, 1, np.nan]) + msg = "Test real searchsorted with nans, side='l'" + b = a.searchsorted(a, side='l') + assert_equal(b, np.arange(3), msg) + msg = "Test real searchsorted with nans, side='r'" + b = a.searchsorted(a, side='r') + assert_equal(b, np.arange(1, 4), msg) + # check double complex + a = np.zeros(9, dtype=np.complex128) + a.real += [0, 0, 1, 1, 0, 1, np.nan, np.nan, np.nan] + a.imag += [0, 1, 0, 1, np.nan, np.nan, 0, 1, np.nan] + msg = "Test complex searchsorted with nans, side='l'" + b = a.searchsorted(a, side='l') + assert_equal(b, np.arange(9), msg) + msg = "Test complex searchsorted with nans, side='r'" + b = a.searchsorted(a, side='r') + assert_equal(b, np.arange(1, 10), msg) + msg = "Test searchsorted with little endian, side='l'" + a = np.array([0, 128], dtype=' p[:, i]).all(), + msg="%d: %r < %r" % (i, p[:, i], p[:, i + 1:].T)) + aae(p, d1[np.arange(d1.shape[0])[:, None], + np.argpartition(d1, i, axis=1, kind=k)]) + + p = np.partition(d0, i, axis=0, kind=k) + aae(p[i, :], np.array([i] * d1.shape[0], dtype=dt)) + # array_less does not seem to work right + at((p[:i, :] <= p[i, :]).all(), + msg="%d: %r <= %r" % (i, p[i, :], p[:i, :])) + at((p[i + 1:, :] > p[i, :]).all(), + msg="%d: %r < %r" % (i, p[i, :], p[:, i + 1:])) + aae(p, d0[np.argpartition(d0, i, axis=0, kind=k), + np.arange(d0.shape[1])[None, :]]) + + # check inplace + dc = d.copy() + dc.partition(i, kind=k) + assert_equal(dc, np.partition(d, i, kind=k)) + dc = d0.copy() + dc.partition(i, axis=0, kind=k) + assert_equal(dc, np.partition(d0, i, axis=0, kind=k)) + dc = d1.copy() + dc.partition(i, axis=1, kind=k) + assert_equal(dc, np.partition(d1, i, axis=1, kind=k)) + + def assert_partitioned(self, d, kth): + prev = 0 + for k in np.sort(kth): + assert_array_less(d[prev:k], d[k], err_msg='kth %d' % k) + assert_((d[k:] >= d[k]).all(), + msg="kth %d, %r not greater equal %d" % (k, d[k:], d[k])) + prev = k + 1 + + def test_partition_iterative(self): + d = np.arange(17) + kth = (0, 1, 2, 429, 231) + assert_raises(ValueError, d.partition, kth) + assert_raises(ValueError, d.argpartition, kth) + d = np.arange(10).reshape((2, 5)) + assert_raises(ValueError, d.partition, kth, axis=0) + assert_raises(ValueError, d.partition, kth, axis=1) + assert_raises(ValueError, np.partition, d, kth, axis=1) + assert_raises(ValueError, np.partition, d, kth, axis=None) + + d = np.array([3, 4, 2, 1]) + p = np.partition(d, (0, 3)) + self.assert_partitioned(p, (0, 3)) + self.assert_partitioned(d[np.argpartition(d, (0, 3))], (0, 3)) + + assert_array_equal(p, np.partition(d, (-3, -1))) + assert_array_equal(p, d[np.argpartition(d, (-3, -1))]) + + d = np.arange(17) + np.random.shuffle(d) + d.partition(range(d.size)) + assert_array_equal(np.arange(17), d) + np.random.shuffle(d) + assert_array_equal(np.arange(17), d[d.argpartition(range(d.size))]) + + # test unsorted kth + d = np.arange(17) + np.random.shuffle(d) + keys = np.array([1, 3, 8, -2]) + np.random.shuffle(d) + p = np.partition(d, keys) + self.assert_partitioned(p, keys) + p = d[np.argpartition(d, keys)] + self.assert_partitioned(p, keys) + np.random.shuffle(keys) + assert_array_equal(np.partition(d, keys), p) + assert_array_equal(d[np.argpartition(d, keys)], p) + + # equal kth + d = np.arange(20)[::-1] + self.assert_partitioned(np.partition(d, [5]*4), [5]) + self.assert_partitioned(np.partition(d, [5]*4 + [6, 13]), + [5]*4 + [6, 13]) + self.assert_partitioned(d[np.argpartition(d, [5]*4)], [5]) + self.assert_partitioned(d[np.argpartition(d, [5]*4 + [6, 13])], + [5]*4 + [6, 13]) + + d = np.arange(12) + np.random.shuffle(d) + d1 = np.tile(np.arange(12), (4, 1)) + map(np.random.shuffle, d1) + d0 = np.transpose(d1) + + kth = (1, 6, 7, -1) + p = np.partition(d1, kth, axis=1) + pa = d1[np.arange(d1.shape[0])[:, None], + d1.argpartition(kth, axis=1)] + assert_array_equal(p, pa) + for i in range(d1.shape[0]): + self.assert_partitioned(p[i,:], kth) + p = np.partition(d0, kth, axis=0) + pa = d0[np.argpartition(d0, kth, axis=0), + np.arange(d0.shape[1])[None,:]] + assert_array_equal(p, pa) + for i in range(d0.shape[1]): + self.assert_partitioned(p[:, i], kth) + + def test_partition_cdtype(self): + d = np.array([('Galahad', 1.7, 38), ('Arthur', 1.8, 41), + ('Lancelot', 1.9, 38)], + dtype=[('name', '|S10'), ('height', ' (numpy ufunc, has_in_place_version, preferred_dtype) + ops = { + 'add': (np.add, True, float), + 'sub': (np.subtract, True, float), + 'mul': (np.multiply, True, float), + 'truediv': (np.true_divide, True, float), + 'floordiv': (np.floor_divide, True, float), + 'mod': (np.remainder, True, float), + 'divmod': (np.divmod, False, float), + 'pow': (np.power, True, int), + 'lshift': (np.left_shift, True, int), + 'rshift': (np.right_shift, True, int), + 'and': (np.bitwise_and, True, int), + 'xor': (np.bitwise_xor, True, int), + 'or': (np.bitwise_or, True, int), + # 'ge': (np.less_equal, False), + # 'gt': (np.less, False), + # 'le': (np.greater_equal, False), + # 'lt': (np.greater, False), + # 'eq': (np.equal, False), + # 'ne': (np.not_equal, False), + } + + class Coerced(Exception): + pass + + def array_impl(self): + raise Coerced + + def op_impl(self, other): + return "forward" + + def rop_impl(self, other): + return "reverse" + + def iop_impl(self, other): + return "in-place" + + def array_ufunc_impl(self, ufunc, method, *args, **kwargs): + return ("__array_ufunc__", ufunc, method, args, kwargs) + + # Create an object with the given base, in the given module, with a + # bunch of placeholder __op__ methods, and optionally a + # __array_ufunc__ and __array_priority__. + def make_obj(base, array_priority=False, array_ufunc=False, + alleged_module="__main__"): + class_namespace = {"__array__": array_impl} + if array_priority is not False: + class_namespace["__array_priority__"] = array_priority + for op in ops: + class_namespace["__{0}__".format(op)] = op_impl + class_namespace["__r{0}__".format(op)] = rop_impl + class_namespace["__i{0}__".format(op)] = iop_impl + if array_ufunc is not False: + class_namespace["__array_ufunc__"] = array_ufunc + eval_namespace = {"base": base, + "class_namespace": class_namespace, + "__name__": alleged_module, + } + MyType = eval("type('MyType', (base,), class_namespace)", + eval_namespace) + if issubclass(MyType, np.ndarray): + # Use this range to avoid special case weirdnesses around + # divide-by-0, pow(x, 2), overflow due to pow(big, big), etc. + return np.arange(3, 5).view(MyType) + else: + return MyType() + + def check(obj, binop_override_expected, ufunc_override_expected, + inplace_override_expected, check_scalar=True): + for op, (ufunc, has_inplace, dtype) in ops.items(): + err_msg = ('op: %s, ufunc: %s, has_inplace: %s, dtype: %s' + % (op, ufunc, has_inplace, dtype)) + check_objs = [np.arange(3, 5, dtype=dtype)] + if check_scalar: + check_objs.append(check_objs[0][0]) + for arr in check_objs: + arr_method = getattr(arr, "__{0}__".format(op)) + + def first_out_arg(result): + if op == "divmod": + assert_(isinstance(result, tuple)) + return result[0] + else: + return result + + # arr __op__ obj + if binop_override_expected: + assert_equal(arr_method(obj), NotImplemented, err_msg) + elif ufunc_override_expected: + assert_equal(arr_method(obj)[0], "__array_ufunc__", + err_msg) + else: + if (isinstance(obj, np.ndarray) and + (type(obj).__array_ufunc__ is + np.ndarray.__array_ufunc__)): + # __array__ gets ignored + res = first_out_arg(arr_method(obj)) + assert_(res.__class__ is obj.__class__, err_msg) + else: + assert_raises((TypeError, Coerced), + arr_method, obj, err_msg=err_msg) + # obj __op__ arr + arr_rmethod = getattr(arr, "__r{0}__".format(op)) + if ufunc_override_expected: + res = arr_rmethod(obj) + assert_equal(res[0], "__array_ufunc__", + err_msg=err_msg) + assert_equal(res[1], ufunc, err_msg=err_msg) + else: + if (isinstance(obj, np.ndarray) and + (type(obj).__array_ufunc__ is + np.ndarray.__array_ufunc__)): + # __array__ gets ignored + res = first_out_arg(arr_rmethod(obj)) + assert_(res.__class__ is obj.__class__, err_msg) + else: + # __array_ufunc__ = "asdf" creates a TypeError + assert_raises((TypeError, Coerced), + arr_rmethod, obj, err_msg=err_msg) + + # arr __iop__ obj + # array scalars don't have in-place operators + if has_inplace and isinstance(arr, np.ndarray): + arr_imethod = getattr(arr, "__i{0}__".format(op)) + if inplace_override_expected: + assert_equal(arr_method(obj), NotImplemented, + err_msg=err_msg) + elif ufunc_override_expected: + res = arr_imethod(obj) + assert_equal(res[0], "__array_ufunc__", err_msg) + assert_equal(res[1], ufunc, err_msg) + assert_(type(res[-1]["out"]) is tuple, err_msg) + assert_(res[-1]["out"][0] is arr, err_msg) + else: + if (isinstance(obj, np.ndarray) and + (type(obj).__array_ufunc__ is + np.ndarray.__array_ufunc__)): + # __array__ gets ignored + assert_(arr_imethod(obj) is arr, err_msg) + else: + assert_raises((TypeError, Coerced), + arr_imethod, obj, + err_msg=err_msg) + + op_fn = getattr(operator, op, None) + if op_fn is None: + op_fn = getattr(operator, op + "_", None) + if op_fn is None: + op_fn = getattr(builtins, op) + assert_equal(op_fn(obj, arr), "forward", err_msg) + if not isinstance(obj, np.ndarray): + if binop_override_expected: + assert_equal(op_fn(arr, obj), "reverse", err_msg) + elif ufunc_override_expected: + assert_equal(op_fn(arr, obj)[0], "__array_ufunc__", + err_msg) + if ufunc_override_expected: + assert_equal(ufunc(obj, arr)[0], "__array_ufunc__", + err_msg) + + # No array priority, no array_ufunc -> nothing called + check(make_obj(object), False, False, False) + # Negative array priority, no array_ufunc -> nothing called + # (has to be very negative, because scalar priority is -1000000.0) + check(make_obj(object, array_priority=-2**30), False, False, False) + # Positive array priority, no array_ufunc -> binops and iops only + check(make_obj(object, array_priority=1), True, False, True) + # ndarray ignores array_priority for ndarray subclasses + check(make_obj(np.ndarray, array_priority=1), False, False, False, + check_scalar=False) + # Positive array_priority and array_ufunc -> array_ufunc only + check(make_obj(object, array_priority=1, + array_ufunc=array_ufunc_impl), False, True, False) + check(make_obj(np.ndarray, array_priority=1, + array_ufunc=array_ufunc_impl), False, True, False) + # array_ufunc set to None -> defer binops only + check(make_obj(object, array_ufunc=None), True, False, False) + check(make_obj(np.ndarray, array_ufunc=None), True, False, False, + check_scalar=False) + + def test_ufunc_override_normalize_signature(self): + # gh-5674 + class SomeClass(object): + def __array_ufunc__(self, ufunc, method, *inputs, **kw): + return kw + + a = SomeClass() + kw = np.add(a, [1]) + assert_('sig' not in kw and 'signature' not in kw) + kw = np.add(a, [1], sig='ii->i') + assert_('sig' not in kw and 'signature' in kw) + assert_equal(kw['signature'], 'ii->i') + kw = np.add(a, [1], signature='ii->i') + assert_('sig' not in kw and 'signature' in kw) + assert_equal(kw['signature'], 'ii->i') + + def test_array_ufunc_index(self): + # Check that index is set appropriately, also if only an output + # is passed on (latter is another regression tests for github bug 4753) + # This also checks implicitly that 'out' is always a tuple. + class CheckIndex(object): + def __array_ufunc__(self, ufunc, method, *inputs, **kw): + for i, a in enumerate(inputs): + if a is self: + return i + # calls below mean we must be in an output. + for j, a in enumerate(kw['out']): + if a is self: + return (j,) + + a = CheckIndex() + dummy = np.arange(2.) + # 1 input, 1 output + assert_equal(np.sin(a), 0) + assert_equal(np.sin(dummy, a), (0,)) + assert_equal(np.sin(dummy, out=a), (0,)) + assert_equal(np.sin(dummy, out=(a,)), (0,)) + assert_equal(np.sin(a, a), 0) + assert_equal(np.sin(a, out=a), 0) + assert_equal(np.sin(a, out=(a,)), 0) + # 1 input, 2 outputs + assert_equal(np.modf(dummy, a), (0,)) + assert_equal(np.modf(dummy, None, a), (1,)) + assert_equal(np.modf(dummy, dummy, a), (1,)) + assert_equal(np.modf(dummy, out=(a, None)), (0,)) + assert_equal(np.modf(dummy, out=(a, dummy)), (0,)) + assert_equal(np.modf(dummy, out=(None, a)), (1,)) + assert_equal(np.modf(dummy, out=(dummy, a)), (1,)) + assert_equal(np.modf(a, out=(dummy, a)), 0) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', DeprecationWarning) + assert_equal(np.modf(dummy, out=a), (0,)) + assert_(w[0].category is DeprecationWarning) + assert_raises(ValueError, np.modf, dummy, out=(a,)) + + # 2 inputs, 1 output + assert_equal(np.add(a, dummy), 0) + assert_equal(np.add(dummy, a), 1) + assert_equal(np.add(dummy, dummy, a), (0,)) + assert_equal(np.add(dummy, a, a), 1) + assert_equal(np.add(dummy, dummy, out=a), (0,)) + assert_equal(np.add(dummy, dummy, out=(a,)), (0,)) + assert_equal(np.add(a, dummy, out=a), 0) + + def test_out_override(self): + # regression test for github bug 4753 + class OutClass(np.ndarray): + def __array_ufunc__(self, ufunc, method, *inputs, **kw): + if 'out' in kw: + tmp_kw = kw.copy() + tmp_kw.pop('out') + func = getattr(ufunc, method) + kw['out'][0][...] = func(*inputs, **tmp_kw) + + A = np.array([0]).view(OutClass) + B = np.array([5]) + C = np.array([6]) + np.multiply(C, B, A) + assert_equal(A[0], 30) + assert_(isinstance(A, OutClass)) + A[0] = 0 + np.multiply(C, B, out=A) + assert_equal(A[0], 30) + assert_(isinstance(A, OutClass)) + + def test_pow_override_with_errors(self): + # regression test for gh-9112 + class PowerOnly(np.ndarray): + def __array_ufunc__(self, ufunc, method, *inputs, **kw): + if ufunc is not np.power: + raise NotImplementedError + return "POWER!" + # explicit cast to float, to ensure the fast power path is taken. + a = np.array(5., dtype=np.float64).view(PowerOnly) + assert_equal(a ** 2.5, "POWER!") + with assert_raises(NotImplementedError): + a ** 0.5 + with assert_raises(NotImplementedError): + a ** 0 + with assert_raises(NotImplementedError): + a ** 1 + with assert_raises(NotImplementedError): + a ** -1 + with assert_raises(NotImplementedError): + a ** 2 + + +class TestTemporaryElide(object): + # elision is only triggered on relatively large arrays + + def test_extension_incref_elide(self): + # test extension (e.g. cython) calling PyNumber_* slots without + # increasing the reference counts + # + # def incref_elide(a): + # d = input.copy() # refcount 1 + # return d, d + d # PyNumber_Add without increasing refcount + from numpy.core.multiarray_tests import incref_elide + d = np.ones(100000) + orig, res = incref_elide(d) + d + d + # the return original should not be changed to an inplace operation + assert_array_equal(orig, d) + assert_array_equal(res, d + d) + + def test_extension_incref_elide_stack(self): + # scanning if the refcount == 1 object is on the python stack to check + # that we are called directly from python is flawed as object may still + # be above the stack pointer and we have no access to the top of it + # + # def incref_elide_l(d): + # return l[4] + l[4] # PyNumber_Add without increasing refcount + from numpy.core.multiarray_tests import incref_elide_l + # padding with 1 makes sure the object on the stack is not overwriten + l = [1, 1, 1, 1, np.ones(100000)] + res = incref_elide_l(l) + # the return original should not be changed to an inplace operation + assert_array_equal(l[4], np.ones(100000)) + assert_array_equal(res, l[4] + l[4]) + + def test_temporary_with_cast(self): + # check that we don't elide into a temporary which would need casting + d = np.ones(200000, dtype=np.int64) + assert_equal(((d + d) + 2**222).dtype, np.dtype('O')) + + r = ((d + d) / 2) + assert_equal(r.dtype, np.dtype('f8')) + + r = np.true_divide((d + d), 2) + assert_equal(r.dtype, np.dtype('f8')) + + r = ((d + d) / 2.) + assert_equal(r.dtype, np.dtype('f8')) + + r = ((d + d) // 2) + assert_equal(r.dtype, np.dtype(np.int64)) + + # commutative elision into the astype result + f = np.ones(100000, dtype=np.float32) + assert_equal(((f + f) + f.astype(np.float64)).dtype, np.dtype('f8')) + + # no elision into lower type + d = f.astype(np.float64) + assert_equal(((f + f) + d).dtype, d.dtype) + l = np.ones(100000, dtype=np.longdouble) + assert_equal(((d + d) + l).dtype, l.dtype) + + # test unary abs with different output dtype + for dt in (np.complex64, np.complex128, np.clongdouble): + c = np.ones(100000, dtype=dt) + r = abs(c * 2.0) + assert_equal(r.dtype, np.dtype('f%d' % (c.itemsize // 2))) + + def test_elide_broadcast(self): + # test no elision on broadcast to higher dimension + # only triggers elision code path in debug mode as triggering it in + # normal mode needs 256kb large matching dimension, so a lot of memory + d = np.ones((2000, 1), dtype=int) + b = np.ones((2000), dtype=bool) + r = (1 - d) + b + assert_equal(r, 1) + assert_equal(r.shape, (2000, 2000)) + + def test_elide_scalar(self): + # check inplace op does not create ndarray from scalars + a = np.bool_() + assert_(type(~(a & a)) is np.bool_) + + def test_elide_scalar_readonly(self): + # The imaginary part of a real array is readonly. This needs to go + # through fast_scalar_power which is only called for powers of + # +1, -1, 0, 0.5, and 2, so use 2. Also need valid refcount for + # elision which can be gotten for the imaginary part of a real + # array. Should not error. + a = np.empty(100000, dtype=np.float64) + a.imag ** 2 + + def test_elide_readonly(self): + # don't try to elide readonly temporaries + r = np.asarray(np.broadcast_to(np.zeros(1), 100000).flat) * 0.0 + assert_equal(r, 0) + + def test_elide_updateifcopy(self): + a = np.ones(2**20)[::2] + b = a.flat.__array__() + 1 + del b + assert_equal(a, 1) + + +class TestCAPI(object): + def test_IsPythonScalar(self): + from numpy.core.multiarray_tests import IsPythonScalar + assert_(IsPythonScalar(b'foobar')) + assert_(IsPythonScalar(1)) + assert_(IsPythonScalar(2**80)) + assert_(IsPythonScalar(2.)) + assert_(IsPythonScalar("a")) + + +class TestSubscripting(object): + def test_test_zero_rank(self): + x = np.array([1, 2, 3]) + assert_(isinstance(x[0], np.int_)) + if sys.version_info[0] < 3: + assert_(isinstance(x[0], int)) + assert_(type(x[0, ...]) is np.ndarray) + + +class TestPickling(object): + def test_roundtrip(self): + import pickle + carray = np.array([[2, 9], [7, 0], [3, 8]]) + DATA = [ + carray, + np.transpose(carray), + np.array([('xxx', 1, 2.0)], dtype=[('a', (str, 3)), ('b', int), + ('c', float)]) + ] + + for a in DATA: + assert_equal(a, pickle.loads(a.dumps()), err_msg="%r" % a) + + def _loads(self, obj): + if sys.version_info[0] >= 3: + return np.loads(obj, encoding='latin1') + else: + return np.loads(obj) + + # version 0 pickles, using protocol=2 to pickle + # version 0 doesn't have a version field + def test_version0_int8(self): + s = b'\x80\x02cnumpy.core._internal\n_reconstruct\nq\x01cnumpy\nndarray\nq\x02K\x00\x85U\x01b\x87Rq\x03(K\x04\x85cnumpy\ndtype\nq\x04U\x02i1K\x00K\x01\x87Rq\x05(U\x01|NNJ\xff\xff\xff\xffJ\xff\xff\xff\xfftb\x89U\x04\x01\x02\x03\x04tb.' + a = np.array([1, 2, 3, 4], dtype=np.int8) + p = self._loads(s) + assert_equal(a, p) + + def test_version0_float32(self): + s = b'\x80\x02cnumpy.core._internal\n_reconstruct\nq\x01cnumpy\nndarray\nq\x02K\x00\x85U\x01b\x87Rq\x03(K\x04\x85cnumpy\ndtype\nq\x04U\x02f4K\x00K\x01\x87Rq\x05(U\x01= g2, [g1[i] >= g2[i] for i in [0, 1, 2]]) + assert_array_equal(g1 < g2, [g1[i] < g2[i] for i in [0, 1, 2]]) + assert_array_equal(g1 > g2, [g1[i] > g2[i] for i in [0, 1, 2]]) + + def test_mixed(self): + g1 = np.array(["spam", "spa", "spammer", "and eggs"]) + g2 = "spam" + assert_array_equal(g1 == g2, [x == g2 for x in g1]) + assert_array_equal(g1 != g2, [x != g2 for x in g1]) + assert_array_equal(g1 < g2, [x < g2 for x in g1]) + assert_array_equal(g1 > g2, [x > g2 for x in g1]) + assert_array_equal(g1 <= g2, [x <= g2 for x in g1]) + assert_array_equal(g1 >= g2, [x >= g2 for x in g1]) + + def test_unicode(self): + g1 = np.array([u"This", u"is", u"example"]) + g2 = np.array([u"This", u"was", u"example"]) + assert_array_equal(g1 == g2, [g1[i] == g2[i] for i in [0, 1, 2]]) + assert_array_equal(g1 != g2, [g1[i] != g2[i] for i in [0, 1, 2]]) + assert_array_equal(g1 <= g2, [g1[i] <= g2[i] for i in [0, 1, 2]]) + assert_array_equal(g1 >= g2, [g1[i] >= g2[i] for i in [0, 1, 2]]) + assert_array_equal(g1 < g2, [g1[i] < g2[i] for i in [0, 1, 2]]) + assert_array_equal(g1 > g2, [g1[i] > g2[i] for i in [0, 1, 2]]) + + +class TestArgmax(object): + + nan_arr = [ + ([0, 1, 2, 3, np.nan], 4), + ([0, 1, 2, np.nan, 3], 3), + ([np.nan, 0, 1, 2, 3], 0), + ([np.nan, 0, np.nan, 2, 3], 0), + ([0, 1, 2, 3, complex(0, np.nan)], 4), + ([0, 1, 2, 3, complex(np.nan, 0)], 4), + ([0, 1, 2, complex(np.nan, 0), 3], 3), + ([0, 1, 2, complex(0, np.nan), 3], 3), + ([complex(0, np.nan), 0, 1, 2, 3], 0), + ([complex(np.nan, np.nan), 0, 1, 2, 3], 0), + ([complex(np.nan, 0), complex(np.nan, 2), complex(np.nan, 1)], 0), + ([complex(np.nan, np.nan), complex(np.nan, 2), complex(np.nan, 1)], 0), + ([complex(np.nan, 0), complex(np.nan, 2), complex(np.nan, np.nan)], 0), + + ([complex(0, 0), complex(0, 2), complex(0, 1)], 1), + ([complex(1, 0), complex(0, 2), complex(0, 1)], 0), + ([complex(1, 0), complex(0, 2), complex(1, 1)], 2), + + ([np.datetime64('1923-04-14T12:43:12'), + np.datetime64('1994-06-21T14:43:15'), + np.datetime64('2001-10-15T04:10:32'), + np.datetime64('1995-11-25T16:02:16'), + np.datetime64('2005-01-04T03:14:12'), + np.datetime64('2041-12-03T14:05:03')], 5), + ([np.datetime64('1935-09-14T04:40:11'), + np.datetime64('1949-10-12T12:32:11'), + np.datetime64('2010-01-03T05:14:12'), + np.datetime64('2015-11-20T12:20:59'), + np.datetime64('1932-09-23T10:10:13'), + np.datetime64('2014-10-10T03:50:30')], 3), + # Assorted tests with NaTs + ([np.datetime64('NaT'), + np.datetime64('NaT'), + np.datetime64('2010-01-03T05:14:12'), + np.datetime64('NaT'), + np.datetime64('2015-09-23T10:10:13'), + np.datetime64('1932-10-10T03:50:30')], 4), + ([np.datetime64('2059-03-14T12:43:12'), + np.datetime64('1996-09-21T14:43:15'), + np.datetime64('NaT'), + np.datetime64('2022-12-25T16:02:16'), + np.datetime64('1963-10-04T03:14:12'), + np.datetime64('2013-05-08T18:15:23')], 0), + ([np.timedelta64(2, 's'), + np.timedelta64(1, 's'), + np.timedelta64('NaT', 's'), + np.timedelta64(3, 's')], 3), + ([np.timedelta64('NaT', 's')] * 3, 0), + + ([timedelta(days=5, seconds=14), timedelta(days=2, seconds=35), + timedelta(days=-1, seconds=23)], 0), + ([timedelta(days=1, seconds=43), timedelta(days=10, seconds=5), + timedelta(days=5, seconds=14)], 1), + ([timedelta(days=10, seconds=24), timedelta(days=10, seconds=5), + timedelta(days=10, seconds=43)], 2), + + ([False, False, False, False, True], 4), + ([False, False, False, True, False], 3), + ([True, False, False, False, False], 0), + ([True, False, True, False, False], 0), + ] + + def test_all(self): + a = np.random.normal(0, 1, (4, 5, 6, 7, 8)) + for i in range(a.ndim): + amax = a.max(i) + aargmax = a.argmax(i) + axes = list(range(a.ndim)) + axes.remove(i) + assert_(np.all(amax == aargmax.choose(*a.transpose(i,*axes)))) + + def test_combinations(self): + for arr, pos in self.nan_arr: + with suppress_warnings() as sup: + sup.filter(RuntimeWarning, + "invalid value encountered in reduce") + max_val = np.max(arr) + + assert_equal(np.argmax(arr), pos, err_msg="%r" % arr) + assert_equal(arr[np.argmax(arr)], max_val, err_msg="%r" % arr) + + def test_output_shape(self): + # see also gh-616 + a = np.ones((10, 5)) + # Check some simple shape mismatches + out = np.ones(11, dtype=np.int_) + assert_raises(ValueError, a.argmax, -1, out) + + out = np.ones((2, 5), dtype=np.int_) + assert_raises(ValueError, a.argmax, -1, out) + + # these could be relaxed possibly (used to allow even the previous) + out = np.ones((1, 10), dtype=np.int_) + assert_raises(ValueError, a.argmax, -1, out) + + out = np.ones(10, dtype=np.int_) + a.argmax(-1, out=out) + assert_equal(out, a.argmax(-1)) + + def test_argmax_unicode(self): + d = np.zeros(6031, dtype='= cmin)) + assert_(np.all(x <= cmax)) + + def _clip_type(self, type_group, array_max, + clip_min, clip_max, inplace=False, + expected_min=None, expected_max=None): + if expected_min is None: + expected_min = clip_min + if expected_max is None: + expected_max = clip_max + + for T in np.sctypes[type_group]: + if sys.byteorder == 'little': + byte_orders = ['=', '>'] + else: + byte_orders = ['<', '='] + + for byteorder in byte_orders: + dtype = np.dtype(T).newbyteorder(byteorder) + + x = (np.random.random(1000) * array_max).astype(dtype) + if inplace: + x.clip(clip_min, clip_max, x) + else: + x = x.clip(clip_min, clip_max) + byteorder = '=' + + if x.dtype.byteorder == '|': + byteorder = '|' + assert_equal(x.dtype.byteorder, byteorder) + self._check_range(x, expected_min, expected_max) + return x + + def test_basic(self): + for inplace in [False, True]: + self._clip_type( + 'float', 1024, -12.8, 100.2, inplace=inplace) + self._clip_type( + 'float', 1024, 0, 0, inplace=inplace) + + self._clip_type( + 'int', 1024, -120, 100.5, inplace=inplace) + self._clip_type( + 'int', 1024, 0, 0, inplace=inplace) + + self._clip_type( + 'uint', 1024, 0, 0, inplace=inplace) + self._clip_type( + 'uint', 1024, -120, 100, inplace=inplace, expected_min=0) + + def test_record_array(self): + rec = np.array([(-5, 2.0, 3.0), (5.0, 4.0, 3.0)], + dtype=[('x', '= 3)) + x = val.clip(min=3) + assert_(np.all(x >= 3)) + x = val.clip(max=4) + assert_(np.all(x <= 4)) + + def test_nan(self): + input_arr = np.array([-2., np.nan, 0.5, 3., 0.25, np.nan]) + result = input_arr.clip(-1, 1) + expected = np.array([-1., np.nan, 0.5, 1., 0.25, np.nan]) + assert_array_equal(result, expected) + + +class TestCompress(object): + def test_axis(self): + tgt = [[5, 6, 7, 8, 9]] + arr = np.arange(10).reshape(2, 5) + out = np.compress([0, 1], arr, axis=0) + assert_equal(out, tgt) + + tgt = [[1, 3], [6, 8]] + out = np.compress([0, 1, 0, 1, 0], arr, axis=1) + assert_equal(out, tgt) + + def test_truncate(self): + tgt = [[1], [6]] + arr = np.arange(10).reshape(2, 5) + out = np.compress([0, 1], arr, axis=1) + assert_equal(out, tgt) + + def test_flatten(self): + arr = np.arange(10).reshape(2, 5) + out = np.compress([0, 1], arr) + assert_equal(out, 1) + + +class TestPutmask(object): + def tst_basic(self, x, T, mask, val): + np.putmask(x, mask, val) + assert_equal(x[mask], T(val)) + assert_equal(x.dtype, T) + + def test_ip_types(self): + unchecked_types = [bytes, unicode, np.void, object] + + x = np.random.random(1000)*100 + mask = x < 40 + + for val in [-100, 0, 15]: + for types in np.sctypes.values(): + for T in types: + if T not in unchecked_types: + yield self.tst_basic, x.copy().astype(T), T, mask, val + + def test_mask_size(self): + assert_raises(ValueError, np.putmask, np.array([1, 2, 3]), [True], 5) + + def tst_byteorder(self, dtype): + x = np.array([1, 2, 3], dtype) + np.putmask(x, [True, False, True], -1) + assert_array_equal(x, [-1, 2, -1]) + + def test_ip_byteorder(self): + for dtype in ('>i4', 'f8'), ('z', 'i4', 'f8'), ('z', ' 16MB + d = np.zeros(4 * 1024 ** 2) + d.tofile(self.filename) + assert_equal(os.path.getsize(self.filename), d.nbytes) + assert_array_equal(d, np.fromfile(self.filename)) + # check offset + with open(self.filename, "r+b") as f: + f.seek(d.nbytes) + d.tofile(f) + assert_equal(os.path.getsize(self.filename), d.nbytes * 2) + # check append mode (gh-8329) + open(self.filename, "w").close() # delete file contents + with open(self.filename, "ab") as f: + d.tofile(f) + assert_array_equal(d, np.fromfile(self.filename)) + with open(self.filename, "ab") as f: + d.tofile(f) + assert_equal(os.path.getsize(self.filename), d.nbytes * 2) + + + def test_io_open_buffered_fromfile(self): + # gh-6632 + self.x.tofile(self.filename) + with io.open(self.filename, 'rb', buffering=-1) as f: + y = np.fromfile(f, dtype=self.dtype) + assert_array_equal(y, self.x.flat) + + def test_file_position_after_fromfile(self): + # gh-4118 + sizes = [io.DEFAULT_BUFFER_SIZE//8, + io.DEFAULT_BUFFER_SIZE, + io.DEFAULT_BUFFER_SIZE*8] + + for size in sizes: + f = open(self.filename, 'wb') + f.seek(size-1) + f.write(b'\0') + f.close() + + for mode in ['rb', 'r+b']: + err_msg = "%d %s" % (size, mode) + + f = open(self.filename, mode) + f.read(2) + np.fromfile(f, dtype=np.float64, count=1) + pos = f.tell() + f.close() + assert_equal(pos, 10, err_msg=err_msg) + + def test_file_position_after_tofile(self): + # gh-4118 + sizes = [io.DEFAULT_BUFFER_SIZE//8, + io.DEFAULT_BUFFER_SIZE, + io.DEFAULT_BUFFER_SIZE*8] + + for size in sizes: + err_msg = "%d" % (size,) + + f = open(self.filename, 'wb') + f.seek(size-1) + f.write(b'\0') + f.seek(10) + f.write(b'12') + np.array([0], dtype=np.float64).tofile(f) + pos = f.tell() + f.close() + assert_equal(pos, 10 + 2 + 8, err_msg=err_msg) + + f = open(self.filename, 'r+b') + f.read(2) + f.seek(0, 1) # seek between read&write required by ANSI C + np.array([0], dtype=np.float64).tofile(f) + pos = f.tell() + f.close() + assert_equal(pos, 10, err_msg=err_msg) + + def _check_from(self, s, value, **kw): + if 'sep' not in kw: + y = np.frombuffer(s, **kw) + else: + y = np.fromstring(s, **kw) + assert_array_equal(y, value) + + f = open(self.filename, 'wb') + f.write(s) + f.close() + y = np.fromfile(self.filename, **kw) + assert_array_equal(y, value) + + def test_nan(self): + self._check_from( + b"nan +nan -nan NaN nan(foo) +NaN(BAR) -NAN(q_u_u_x_)", + [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], + sep=' ') + + def test_inf(self): + self._check_from( + b"inf +inf -inf infinity -Infinity iNfInItY -inF", + [np.inf, np.inf, -np.inf, np.inf, -np.inf, np.inf, -np.inf], + sep=' ') + + def test_numbers(self): + self._check_from(b"1.234 -1.234 .3 .3e55 -123133.1231e+133", + [1.234, -1.234, .3, .3e55, -123133.1231e+133], sep=' ') + + def test_binary(self): + self._check_from(b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@\x00\x00\x80@', + np.array([1, 2, 3, 4]), + dtype=' 1 minute on mechanical hard drive + def test_big_binary(self): + """Test workarounds for 32-bit limited fwrite, fseek, and ftell + calls in windows. These normally would hang doing something like this. + See http://projects.scipy.org/numpy/ticket/1660""" + if sys.platform != 'win32': + return + try: + # before workarounds, only up to 2**32-1 worked + fourgbplus = 2**32 + 2**16 + testbytes = np.arange(8, dtype=np.int8) + n = len(testbytes) + flike = tempfile.NamedTemporaryFile() + f = flike.file + np.tile(testbytes, fourgbplus // testbytes.nbytes).tofile(f) + flike.seek(0) + a = np.fromfile(f, dtype=np.int8) + flike.close() + assert_(len(a) == fourgbplus) + # check only start and end for speed: + assert_((a[:n] == testbytes).all()) + assert_((a[-n:] == testbytes).all()) + except (MemoryError, ValueError): + pass + + def test_string(self): + self._check_from(b'1,2,3,4', [1., 2., 3., 4.], sep=',') + + def test_counted_string(self): + self._check_from(b'1,2,3,4', [1., 2., 3., 4.], count=4, sep=',') + self._check_from(b'1,2,3,4', [1., 2., 3.], count=3, sep=',') + self._check_from(b'1,2,3,4', [1., 2., 3., 4.], count=-1, sep=',') + + def test_string_with_ws(self): + self._check_from(b'1 2 3 4 ', [1, 2, 3, 4], dtype=int, sep=' ') + + def test_counted_string_with_ws(self): + self._check_from(b'1 2 3 4 ', [1, 2, 3], count=3, dtype=int, + sep=' ') + + def test_ascii(self): + self._check_from(b'1 , 2 , 3 , 4', [1., 2., 3., 4.], sep=',') + self._check_from(b'1,2,3,4', [1., 2., 3., 4.], dtype=float, sep=',') + + def test_malformed(self): + self._check_from(b'1.234 1,234', [1.234, 1.], sep=' ') + + def test_long_sep(self): + self._check_from(b'1_x_3_x_4_x_5', [1, 3, 4, 5], sep='_x_') + + def test_dtype(self): + v = np.array([1, 2, 3, 4], dtype=np.int_) + self._check_from(b'1,2,3,4', v, sep=',', dtype=np.int_) + + def test_dtype_bool(self): + # can't use _check_from because fromstring can't handle True/False + v = np.array([True, False, True, False], dtype=np.bool_) + s = b'1,0,-2.3,0' + f = open(self.filename, 'wb') + f.write(s) + f.close() + y = np.fromfile(self.filename, sep=',', dtype=np.bool_) + assert_(y.dtype == '?') + assert_array_equal(y, v) + + def test_tofile_sep(self): + x = np.array([1.51, 2, 3.51, 4], dtype=float) + f = open(self.filename, 'w') + x.tofile(f, sep=',') + f.close() + f = open(self.filename, 'r') + s = f.read() + f.close() + #assert_equal(s, '1.51,2.0,3.51,4.0') + y = np.array([float(p) for p in s.split(',')]) + assert_array_equal(x,y) + + def test_tofile_format(self): + x = np.array([1.51, 2, 3.51, 4], dtype=float) + f = open(self.filename, 'w') + x.tofile(f, sep=',', format='%.2f') + f.close() + f = open(self.filename, 'r') + s = f.read() + f.close() + assert_equal(s, '1.51,2.00,3.51,4.00') + + def test_locale(self): + in_foreign_locale(self.test_numbers)() + in_foreign_locale(self.test_nan)() + in_foreign_locale(self.test_inf)() + in_foreign_locale(self.test_counted_string)() + in_foreign_locale(self.test_ascii)() + in_foreign_locale(self.test_malformed)() + in_foreign_locale(self.test_tofile_sep)() + in_foreign_locale(self.test_tofile_format)() + + +class TestFromBuffer(object): + def tst_basic(self, buffer, expected, kwargs): + assert_array_equal(np.frombuffer(buffer,**kwargs), expected) + + def test_ip_basic(self): + for byteorder in ['<', '>']: + for dtype in [float, int, complex]: + dt = np.dtype(dtype).newbyteorder(byteorder) + x = (np.random.random((4, 7))*5).astype(dt) + buf = x.tobytes() + yield self.tst_basic, buf, x.flat, {'dtype':dt} + + def test_empty(self): + yield self.tst_basic, b'', np.array([]), {} + + +class TestFlat(object): + def setup(self): + a0 = np.arange(20.0) + a = a0.reshape(4, 5) + a0.shape = (4, 5) + a.flags.writeable = False + self.a = a + self.b = a[::2, ::2] + self.a0 = a0 + self.b0 = a0[::2, ::2] + + def test_contiguous(self): + testpassed = False + try: + self.a.flat[12] = 100.0 + except ValueError: + testpassed = True + assert_(testpassed) + assert_(self.a.flat[12] == 12.0) + + def test_discontiguous(self): + testpassed = False + try: + self.b.flat[4] = 100.0 + except ValueError: + testpassed = True + assert_(testpassed) + assert_(self.b.flat[4] == 12.0) + + def test___array__(self): + c = self.a.flat.__array__() + d = self.b.flat.__array__() + e = self.a0.flat.__array__() + f = self.b0.flat.__array__() + + assert_(c.flags.writeable is False) + assert_(d.flags.writeable is False) + # for 1.14 all are set to non-writeable on the way to replacing the + # UPDATEIFCOPY array returned for non-contiguous arrays. + assert_(e.flags.writeable is True) + assert_(f.flags.writeable is False) + with assert_warns(DeprecationWarning): + assert_(c.flags.updateifcopy is False) + with assert_warns(DeprecationWarning): + assert_(d.flags.updateifcopy is False) + with assert_warns(DeprecationWarning): + assert_(e.flags.updateifcopy is False) + with assert_warns(DeprecationWarning): + # UPDATEIFCOPY is removed. + assert_(f.flags.updateifcopy is False) + assert_(c.flags.writebackifcopy is False) + assert_(d.flags.writebackifcopy is False) + assert_(e.flags.writebackifcopy is False) + assert_(f.flags.writebackifcopy is False) + + +class TestResize(object): + def test_basic(self): + x = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + if IS_PYPY: + x.resize((5, 5), refcheck=False) + else: + x.resize((5, 5)) + assert_array_equal(x.flat[:9], + np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]).flat) + assert_array_equal(x[9:].flat, 0) + + def test_check_reference(self): + x = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + y = x + assert_raises(ValueError, x.resize, (5, 1)) + del y # avoid pyflakes unused variable warning. + + def test_int_shape(self): + x = np.eye(3) + if IS_PYPY: + x.resize(3, refcheck=False) + else: + x.resize(3) + assert_array_equal(x, np.eye(3)[0,:]) + + def test_none_shape(self): + x = np.eye(3) + x.resize(None) + assert_array_equal(x, np.eye(3)) + x.resize() + assert_array_equal(x, np.eye(3)) + + def test_0d_shape(self): + # to it multiple times to test it does not break alloc cache gh-9216 + for i in range(10): + x = np.empty((1,)) + x.resize(()) + assert_equal(x.shape, ()) + assert_equal(x.size, 1) + x = np.empty(()) + x.resize((1,)) + assert_equal(x.shape, (1,)) + assert_equal(x.size, 1) + + def test_invalid_arguments(self): + assert_raises(TypeError, np.eye(3).resize, 'hi') + assert_raises(ValueError, np.eye(3).resize, -1) + assert_raises(TypeError, np.eye(3).resize, order=1) + assert_raises(TypeError, np.eye(3).resize, refcheck='hi') + + def test_freeform_shape(self): + x = np.eye(3) + if IS_PYPY: + x.resize(3, 2, 1, refcheck=False) + else: + x.resize(3, 2, 1) + assert_(x.shape == (3, 2, 1)) + + def test_zeros_appended(self): + x = np.eye(3) + if IS_PYPY: + x.resize(2, 3, 3, refcheck=False) + else: + x.resize(2, 3, 3) + assert_array_equal(x[0], np.eye(3)) + assert_array_equal(x[1], np.zeros((3, 3))) + + def test_obj_obj(self): + # check memory is initialized on resize, gh-4857 + a = np.ones(10, dtype=[('k', object, 2)]) + if IS_PYPY: + a.resize(15, refcheck=False) + else: + a.resize(15,) + assert_equal(a.shape, (15,)) + assert_array_equal(a['k'][-5:], 0) + assert_array_equal(a['k'][:-5], 1) + + def test_empty_view(self): + # check that sizes containing a zero don't trigger a reallocate for + # already empty arrays + x = np.zeros((10, 0), int) + x_view = x[...] + x_view.resize((0, 10)) + x_view.resize((0, 100)) + + +class TestRecord(object): + def test_field_rename(self): + dt = np.dtype([('f', float), ('i', int)]) + dt.names = ['p', 'q'] + assert_equal(dt.names, ['p', 'q']) + + def test_multiple_field_name_occurrence(self): + def test_assign(): + dtype = np.dtype([("A", "f8"), ("B", "f8"), ("A", "f8")]) + + # Error raised when multiple fields have the same name + assert_raises(ValueError, test_assign) + + if sys.version_info[0] >= 3: + def test_bytes_fields(self): + # Bytes are not allowed in field names and not recognized in titles + # on Py3 + assert_raises(TypeError, np.dtype, [(b'a', int)]) + assert_raises(TypeError, np.dtype, [(('b', b'a'), int)]) + + dt = np.dtype([((b'a', 'b'), int)]) + assert_raises(TypeError, dt.__getitem__, b'a') + + x = np.array([(1,), (2,), (3,)], dtype=dt) + assert_raises(IndexError, x.__getitem__, b'a') + + y = x[0] + assert_raises(IndexError, y.__getitem__, b'a') + + def test_multiple_field_name_unicode(self): + def test_assign_unicode(): + dt = np.dtype([("\u20B9", "f8"), + ("B", "f8"), + ("\u20B9", "f8")]) + + # Error raised when multiple fields have the same name(unicode included) + assert_raises(ValueError, test_assign_unicode) + + else: + def test_unicode_field_titles(self): + # Unicode field titles are added to field dict on Py2 + title = u'b' + dt = np.dtype([((title, 'a'), int)]) + dt[title] + dt['a'] + x = np.array([(1,), (2,), (3,)], dtype=dt) + x[title] + x['a'] + y = x[0] + y[title] + y['a'] + + def test_unicode_field_names(self): + # Unicode field names are not allowed on Py2 + title = u'b' + assert_raises(TypeError, np.dtype, [(title, int)]) + assert_raises(TypeError, np.dtype, [(('a', title), int)]) + + def test_field_names(self): + # Test unicode and 8-bit / byte strings can be used + a = np.zeros((1,), dtype=[('f1', 'i4'), + ('f2', 'i4'), + ('f3', [('sf1', 'i4')])]) + is_py3 = sys.version_info[0] >= 3 + if is_py3: + funcs = (str,) + # byte string indexing fails gracefully + assert_raises(IndexError, a.__setitem__, b'f1', 1) + assert_raises(IndexError, a.__getitem__, b'f1') + assert_raises(IndexError, a['f1'].__setitem__, b'sf1', 1) + assert_raises(IndexError, a['f1'].__getitem__, b'sf1') + else: + funcs = (str, unicode) + for func in funcs: + b = a.copy() + fn1 = func('f1') + b[fn1] = 1 + assert_equal(b[fn1], 1) + fnn = func('not at all') + assert_raises(ValueError, b.__setitem__, fnn, 1) + assert_raises(ValueError, b.__getitem__, fnn) + b[0][fn1] = 2 + assert_equal(b[fn1], 2) + # Subfield + assert_raises(ValueError, b[0].__setitem__, fnn, 1) + assert_raises(ValueError, b[0].__getitem__, fnn) + # Subfield + fn3 = func('f3') + sfn1 = func('sf1') + b[fn3][sfn1] = 1 + assert_equal(b[fn3][sfn1], 1) + assert_raises(ValueError, b[fn3].__setitem__, fnn, 1) + assert_raises(ValueError, b[fn3].__getitem__, fnn) + # multiple subfields + fn2 = func('f2') + b[fn2] = 3 + with suppress_warnings() as sup: + sup.filter(FutureWarning, + "Numpy has detected that you .*") + + assert_equal(b[['f1', 'f2']][0].tolist(), (2, 3)) + assert_equal(b[['f2', 'f1']][0].tolist(), (3, 2)) + assert_equal(b[['f1', 'f3']][0].tolist(), (2, (1,))) + # view of subfield view/copy + assert_equal(b[['f1', 'f2']][0].view(('i4', 2)).tolist(), + (2, 3)) + assert_equal(b[['f2', 'f1']][0].view(('i4', 2)).tolist(), + (3, 2)) + view_dtype = [('f1', 'i4'), ('f3', [('', 'i4')])] + assert_equal(b[['f1', 'f3']][0].view(view_dtype).tolist(), + (2, (1,))) + + # non-ascii unicode field indexing is well behaved + if not is_py3: + raise SkipTest('non ascii unicode field indexing skipped; ' + 'raises segfault on python 2.x') + else: + assert_raises(ValueError, a.__setitem__, u'\u03e0', 1) + assert_raises(ValueError, a.__getitem__, u'\u03e0') + + def test_field_names_deprecation(self): + + def collect_warnings(f, *args, **kwargs): + with warnings.catch_warnings(record=True) as log: + warnings.simplefilter("always") + f(*args, **kwargs) + return [w.category for w in log] + + a = np.zeros((1,), dtype=[('f1', 'i4'), + ('f2', 'i4'), + ('f3', [('sf1', 'i4')])]) + a['f1'][0] = 1 + a['f2'][0] = 2 + a['f3'][0] = (3,) + b = np.zeros((1,), dtype=[('f1', 'i4'), + ('f2', 'i4'), + ('f3', [('sf1', 'i4')])]) + b['f1'][0] = 1 + b['f2'][0] = 2 + b['f3'][0] = (3,) + + # All the different functions raise a warning, but not an error + assert_equal(collect_warnings(a[['f1', 'f2']].__setitem__, 0, (10, 20)), + [FutureWarning]) + # For <=1.12 a is not modified, but it will be in 1.13 + assert_equal(a, b) + + # Views also warn + subset = a[['f1', 'f2']] + subset_view = subset.view() + assert_equal(collect_warnings(subset_view['f1'].__setitem__, 0, 10), + [FutureWarning]) + # But the write goes through: + assert_equal(subset['f1'][0], 10) + # Only one warning per multiple field indexing, though (even if there + # are multiple views involved): + assert_equal(collect_warnings(subset['f1'].__setitem__, 0, 10), []) + + # make sure views of a multi-field index warn too + c = np.zeros(3, dtype='i8,i8,i8') + assert_equal(collect_warnings(c[['f0', 'f2']].view, 'i8,i8'), + [FutureWarning]) + + + def test_record_hash(self): + a = np.array([(1, 2), (1, 2)], dtype='i1,i2') + a.flags.writeable = False + b = np.array([(1, 2), (3, 4)], dtype=[('num1', 'i1'), ('num2', 'i2')]) + b.flags.writeable = False + c = np.array([(1, 2), (3, 4)], dtype='i1,i2') + c.flags.writeable = False + assert_(hash(a[0]) == hash(a[1])) + assert_(hash(a[0]) == hash(b[0])) + assert_(hash(a[0]) != hash(b[1])) + assert_(hash(c[0]) == hash(a[0]) and c[0] == a[0]) + + def test_record_no_hash(self): + a = np.array([(1, 2), (1, 2)], dtype='i1,i2') + assert_raises(TypeError, hash, a[0]) + + def test_empty_structure_creation(self): + # make sure these do not raise errors (gh-5631) + np.array([()], dtype={'names': [], 'formats': [], + 'offsets': [], 'itemsize': 12}) + np.array([(), (), (), (), ()], dtype={'names': [], 'formats': [], + 'offsets': [], 'itemsize': 12}) + +class TestView(object): + def test_basic(self): + x = np.array([(1, 2, 3, 4), (5, 6, 7, 8)], + dtype=[('r', np.int8), ('g', np.int8), + ('b', np.int8), ('a', np.int8)]) + # We must be specific about the endianness here: + y = x.view(dtype=' 0) + assert_(issubclass(w[0].category, RuntimeWarning)) + + def test_empty(self): + A = np.zeros((0, 3)) + for f in self.funcs: + for axis in [0, None]: + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + assert_(np.isnan(f(A, axis=axis)).all()) + assert_(len(w) > 0) + assert_(issubclass(w[0].category, RuntimeWarning)) + for axis in [1]: + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + assert_equal(f(A, axis=axis), np.zeros([])) + + def test_mean_values(self): + for mat in [self.rmat, self.cmat, self.omat]: + for axis in [0, 1]: + tgt = mat.sum(axis=axis) + res = _mean(mat, axis=axis) * mat.shape[axis] + assert_almost_equal(res, tgt) + for axis in [None]: + tgt = mat.sum(axis=axis) + res = _mean(mat, axis=axis) * np.prod(mat.shape) + assert_almost_equal(res, tgt) + + def test_mean_float16(self): + # This fail if the sum inside mean is done in float16 instead + # of float32. + assert_(_mean(np.ones(100000, dtype='float16')) == 1) + + def test_var_values(self): + for mat in [self.rmat, self.cmat, self.omat]: + for axis in [0, 1, None]: + msqr = _mean(mat * mat.conj(), axis=axis) + mean = _mean(mat, axis=axis) + tgt = msqr - mean * mean.conjugate() + res = _var(mat, axis=axis) + assert_almost_equal(res, tgt) + + def test_std_values(self): + for mat in [self.rmat, self.cmat, self.omat]: + for axis in [0, 1, None]: + tgt = np.sqrt(_var(mat, axis=axis)) + res = _std(mat, axis=axis) + assert_almost_equal(res, tgt) + + def test_subclass(self): + class TestArray(np.ndarray): + def __new__(cls, data, info): + result = np.array(data) + result = result.view(cls) + result.info = info + return result + + def __array_finalize__(self, obj): + self.info = getattr(obj, "info", '') + + dat = TestArray([[1, 2, 3, 4], [5, 6, 7, 8]], 'jubba') + res = dat.mean(1) + assert_(res.info == dat.info) + res = dat.std(1) + assert_(res.info == dat.info) + res = dat.var(1) + assert_(res.info == dat.info) + +class TestVdot(object): + def test_basic(self): + dt_numeric = np.typecodes['AllFloat'] + np.typecodes['AllInteger'] + dt_complex = np.typecodes['Complex'] + + # test real + a = np.eye(3) + for dt in dt_numeric + 'O': + b = a.astype(dt) + res = np.vdot(b, b) + assert_(np.isscalar(res)) + assert_equal(np.vdot(b, b), 3) + + # test complex + a = np.eye(3) * 1j + for dt in dt_complex + 'O': + b = a.astype(dt) + res = np.vdot(b, b) + assert_(np.isscalar(res)) + assert_equal(np.vdot(b, b), 3) + + # test boolean + b = np.eye(3, dtype=bool) + res = np.vdot(b, b) + assert_(np.isscalar(res)) + assert_equal(np.vdot(b, b), True) + + def test_vdot_array_order(self): + a = np.array([[1, 2], [3, 4]], order='C') + b = np.array([[1, 2], [3, 4]], order='F') + res = np.vdot(a, a) + + # integer arrays are exact + assert_equal(np.vdot(a, b), res) + assert_equal(np.vdot(b, a), res) + assert_equal(np.vdot(b, b), res) + + def test_vdot_uncontiguous(self): + for size in [2, 1000]: + # Different sizes match different branches in vdot. + a = np.zeros((size, 2, 2)) + b = np.zeros((size, 2, 2)) + a[:, 0, 0] = np.arange(size) + b[:, 0, 0] = np.arange(size) + 1 + # Make a and b uncontiguous: + a = a[..., 0] + b = b[..., 0] + + assert_equal(np.vdot(a, b), + np.vdot(a.flatten(), b.flatten())) + assert_equal(np.vdot(a, b.copy()), + np.vdot(a.flatten(), b.flatten())) + assert_equal(np.vdot(a.copy(), b), + np.vdot(a.flatten(), b.flatten())) + assert_equal(np.vdot(a.copy('F'), b), + np.vdot(a.flatten(), b.flatten())) + assert_equal(np.vdot(a, b.copy('F')), + np.vdot(a.flatten(), b.flatten())) + + +class TestDot(object): + def setup(self): + np.random.seed(128) + self.A = np.random.rand(4, 2) + self.b1 = np.random.rand(2, 1) + self.b2 = np.random.rand(2) + self.b3 = np.random.rand(1, 2) + self.b4 = np.random.rand(4) + self.N = 7 + + def test_dotmatmat(self): + A = self.A + res = np.dot(A.transpose(), A) + tgt = np.array([[1.45046013, 0.86323640], + [0.86323640, 0.84934569]]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotmatvec(self): + A, b1 = self.A, self.b1 + res = np.dot(A, b1) + tgt = np.array([[0.32114320], [0.04889721], + [0.15696029], [0.33612621]]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotmatvec2(self): + A, b2 = self.A, self.b2 + res = np.dot(A, b2) + tgt = np.array([0.29677940, 0.04518649, 0.14468333, 0.31039293]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotvecmat(self): + A, b4 = self.A, self.b4 + res = np.dot(b4, A) + tgt = np.array([1.23495091, 1.12222648]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotvecmat2(self): + b3, A = self.b3, self.A + res = np.dot(b3, A.transpose()) + tgt = np.array([[0.58793804, 0.08957460, 0.30605758, 0.62716383]]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotvecmat3(self): + A, b4 = self.A, self.b4 + res = np.dot(A.transpose(), b4) + tgt = np.array([1.23495091, 1.12222648]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotvecvecouter(self): + b1, b3 = self.b1, self.b3 + res = np.dot(b1, b3) + tgt = np.array([[0.20128610, 0.08400440], [0.07190947, 0.03001058]]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotvecvecinner(self): + b1, b3 = self.b1, self.b3 + res = np.dot(b3, b1) + tgt = np.array([[ 0.23129668]]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotcolumnvect1(self): + b1 = np.ones((3, 1)) + b2 = [5.3] + res = np.dot(b1, b2) + tgt = np.array([5.3, 5.3, 5.3]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotcolumnvect2(self): + b1 = np.ones((3, 1)).transpose() + b2 = [6.2] + res = np.dot(b2, b1) + tgt = np.array([6.2, 6.2, 6.2]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotvecscalar(self): + np.random.seed(100) + b1 = np.random.rand(1, 1) + b2 = np.random.rand(1, 4) + res = np.dot(b1, b2) + tgt = np.array([[0.15126730, 0.23068496, 0.45905553, 0.00256425]]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_dotvecscalar2(self): + np.random.seed(100) + b1 = np.random.rand(4, 1) + b2 = np.random.rand(1, 1) + res = np.dot(b1, b2) + tgt = np.array([[0.00256425],[0.00131359],[0.00200324],[ 0.00398638]]) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_all(self): + dims = [(), (1,), (1, 1)] + dout = [(), (1,), (1, 1), (1,), (), (1,), (1, 1), (1,), (1, 1)] + for dim, (dim1, dim2) in zip(dout, itertools.product(dims, dims)): + b1 = np.zeros(dim1) + b2 = np.zeros(dim2) + res = np.dot(b1, b2) + tgt = np.zeros(dim) + assert_(res.shape == tgt.shape) + assert_almost_equal(res, tgt, decimal=self.N) + + def test_vecobject(self): + class Vec(object): + def __init__(self, sequence=None): + if sequence is None: + sequence = [] + self.array = np.array(sequence) + + def __add__(self, other): + out = Vec() + out.array = self.array + other.array + return out + + def __sub__(self, other): + out = Vec() + out.array = self.array - other.array + return out + + def __mul__(self, other): # with scalar + out = Vec(self.array.copy()) + out.array *= other + return out + + def __rmul__(self, other): + return self*other + + U_non_cont = np.transpose([[1., 1.], [1., 2.]]) + U_cont = np.ascontiguousarray(U_non_cont) + x = np.array([Vec([1., 0.]), Vec([0., 1.])]) + zeros = np.array([Vec([0., 0.]), Vec([0., 0.])]) + zeros_test = np.dot(U_cont, x) - np.dot(U_non_cont, x) + assert_equal(zeros[0].array, zeros_test[0].array) + assert_equal(zeros[1].array, zeros_test[1].array) + + def test_dot_2args(self): + from numpy.core.multiarray import dot + + a = np.array([[1, 2], [3, 4]], dtype=float) + b = np.array([[1, 0], [1, 1]], dtype=float) + c = np.array([[3, 2], [7, 4]], dtype=float) + + d = dot(a, b) + assert_allclose(c, d) + + def test_dot_3args(self): + from numpy.core.multiarray import dot + + np.random.seed(22) + f = np.random.random_sample((1024, 16)) + v = np.random.random_sample((16, 32)) + + r = np.empty((1024, 32)) + for i in range(12): + dot(f, v, r) + if HAS_REFCOUNT: + assert_equal(sys.getrefcount(r), 2) + r2 = dot(f, v, out=None) + assert_array_equal(r2, r) + assert_(r is dot(f, v, out=r)) + + v = v[:, 0].copy() # v.shape == (16,) + r = r[:, 0].copy() # r.shape == (1024,) + r2 = dot(f, v) + assert_(r is dot(f, v, r)) + assert_array_equal(r2, r) + + def test_dot_3args_errors(self): + from numpy.core.multiarray import dot + + np.random.seed(22) + f = np.random.random_sample((1024, 16)) + v = np.random.random_sample((16, 32)) + + r = np.empty((1024, 31)) + assert_raises(ValueError, dot, f, v, r) + + r = np.empty((1024,)) + assert_raises(ValueError, dot, f, v, r) + + r = np.empty((32,)) + assert_raises(ValueError, dot, f, v, r) + + r = np.empty((32, 1024)) + assert_raises(ValueError, dot, f, v, r) + assert_raises(ValueError, dot, f, v, r.T) + + r = np.empty((1024, 64)) + assert_raises(ValueError, dot, f, v, r[:, ::2]) + assert_raises(ValueError, dot, f, v, r[:, :32]) + + r = np.empty((1024, 32), dtype=np.float32) + assert_raises(ValueError, dot, f, v, r) + + r = np.empty((1024, 32), dtype=int) + assert_raises(ValueError, dot, f, v, r) + + def test_dot_array_order(self): + a = np.array([[1, 2], [3, 4]], order='C') + b = np.array([[1, 2], [3, 4]], order='F') + res = np.dot(a, a) + + # integer arrays are exact + assert_equal(np.dot(a, b), res) + assert_equal(np.dot(b, a), res) + assert_equal(np.dot(b, b), res) + + def test_dot_scalar_and_matrix_of_objects(self): + # Ticket #2469 + arr = np.matrix([1, 2], dtype=object) + desired = np.matrix([[3, 6]], dtype=object) + assert_equal(np.dot(arr, 3), desired) + assert_equal(np.dot(3, arr), desired) + + def test_accelerate_framework_sgemv_fix(self): + + def aligned_array(shape, align, dtype, order='C'): + d = dtype(0) + N = np.prod(shape) + tmp = np.zeros(N * d.nbytes + align, dtype=np.uint8) + address = tmp.__array_interface__["data"][0] + for offset in range(align): + if (address + offset) % align == 0: + break + tmp = tmp[offset:offset+N*d.nbytes].view(dtype=dtype) + return tmp.reshape(shape, order=order) + + def as_aligned(arr, align, dtype, order='C'): + aligned = aligned_array(arr.shape, align, dtype, order) + aligned[:] = arr[:] + return aligned + + def assert_dot_close(A, X, desired): + assert_allclose(np.dot(A, X), desired, rtol=1e-5, atol=1e-7) + + m = aligned_array(100, 15, np.float32) + s = aligned_array((100, 100), 15, np.float32) + np.dot(s, m) # this will always segfault if the bug is present + + testdata = itertools.product((15,32), (10000,), (200,89), ('C','F')) + for align, m, n, a_order in testdata: + # Calculation in double precision + A_d = np.random.rand(m, n) + X_d = np.random.rand(n) + desired = np.dot(A_d, X_d) + # Calculation with aligned single precision + A_f = as_aligned(A_d, align, np.float32, order=a_order) + X_f = as_aligned(X_d, align, np.float32) + assert_dot_close(A_f, X_f, desired) + # Strided A rows + A_d_2 = A_d[::2] + desired = np.dot(A_d_2, X_d) + A_f_2 = A_f[::2] + assert_dot_close(A_f_2, X_f, desired) + # Strided A columns, strided X vector + A_d_22 = A_d_2[:, ::2] + X_d_2 = X_d[::2] + desired = np.dot(A_d_22, X_d_2) + A_f_22 = A_f_2[:, ::2] + X_f_2 = X_f[::2] + assert_dot_close(A_f_22, X_f_2, desired) + # Check the strides are as expected + if a_order == 'F': + assert_equal(A_f_22.strides, (8, 8 * m)) + else: + assert_equal(A_f_22.strides, (8 * n, 8)) + assert_equal(X_f_2.strides, (8,)) + # Strides in A rows + cols only + X_f_2c = as_aligned(X_f_2, align, np.float32) + assert_dot_close(A_f_22, X_f_2c, desired) + # Strides just in A cols + A_d_12 = A_d[:, ::2] + desired = np.dot(A_d_12, X_d_2) + A_f_12 = A_f[:, ::2] + assert_dot_close(A_f_12, X_f_2c, desired) + # Strides in A cols and X + assert_dot_close(A_f_12, X_f_2, desired) + + +class MatmulCommon(object): + """Common tests for '@' operator and numpy.matmul. + + Do not derive from TestCase to avoid nose running it. + + """ + # Should work with these types. Will want to add + # "O" at some point + types = "?bhilqBHILQefdgFDG" + + def test_exceptions(self): + dims = [ + ((1,), (2,)), # mismatched vector vector + ((2, 1,), (2,)), # mismatched matrix vector + ((2,), (1, 2)), # mismatched vector matrix + ((1, 2), (3, 1)), # mismatched matrix matrix + ((1,), ()), # vector scalar + ((), (1)), # scalar vector + ((1, 1), ()), # matrix scalar + ((), (1, 1)), # scalar matrix + ((2, 2, 1), (3, 1, 2)), # cannot broadcast + ] + + for dt, (dm1, dm2) in itertools.product(self.types, dims): + a = np.ones(dm1, dtype=dt) + b = np.ones(dm2, dtype=dt) + assert_raises(ValueError, self.matmul, a, b) + + def test_shapes(self): + dims = [ + ((1, 1), (2, 1, 1)), # broadcast first argument + ((2, 1, 1), (1, 1)), # broadcast second argument + ((2, 1, 1), (2, 1, 1)), # matrix stack sizes match + ] + + for dt, (dm1, dm2) in itertools.product(self.types, dims): + a = np.ones(dm1, dtype=dt) + b = np.ones(dm2, dtype=dt) + res = self.matmul(a, b) + assert_(res.shape == (2, 1, 1)) + + # vector vector returns scalars. + for dt in self.types: + a = np.ones((2,), dtype=dt) + b = np.ones((2,), dtype=dt) + c = self.matmul(a, b) + assert_(np.array(c).shape == ()) + + def test_result_types(self): + mat = np.ones((1,1)) + vec = np.ones((1,)) + for dt in self.types: + m = mat.astype(dt) + v = vec.astype(dt) + for arg in [(m, v), (v, m), (m, m)]: + res = self.matmul(*arg) + assert_(res.dtype == dt) + + # vector vector returns scalars + res = self.matmul(v, v) + assert_(type(res) is np.dtype(dt).type) + + def test_vector_vector_values(self): + vec = np.array([1, 2]) + tgt = 5 + for dt in self.types[1:]: + v1 = vec.astype(dt) + res = self.matmul(v1, v1) + assert_equal(res, tgt) + + # boolean type + vec = np.array([True, True], dtype='?') + res = self.matmul(vec, vec) + assert_equal(res, True) + + def test_vector_matrix_values(self): + vec = np.array([1, 2]) + mat1 = np.array([[1, 2], [3, 4]]) + mat2 = np.stack([mat1]*2, axis=0) + tgt1 = np.array([7, 10]) + tgt2 = np.stack([tgt1]*2, axis=0) + for dt in self.types[1:]: + v = vec.astype(dt) + m1 = mat1.astype(dt) + m2 = mat2.astype(dt) + res = self.matmul(v, m1) + assert_equal(res, tgt1) + res = self.matmul(v, m2) + assert_equal(res, tgt2) + + # boolean type + vec = np.array([True, False]) + mat1 = np.array([[True, False], [False, True]]) + mat2 = np.stack([mat1]*2, axis=0) + tgt1 = np.array([True, False]) + tgt2 = np.stack([tgt1]*2, axis=0) + + res = self.matmul(vec, mat1) + assert_equal(res, tgt1) + res = self.matmul(vec, mat2) + assert_equal(res, tgt2) + + def test_matrix_vector_values(self): + vec = np.array([1, 2]) + mat1 = np.array([[1, 2], [3, 4]]) + mat2 = np.stack([mat1]*2, axis=0) + tgt1 = np.array([5, 11]) + tgt2 = np.stack([tgt1]*2, axis=0) + for dt in self.types[1:]: + v = vec.astype(dt) + m1 = mat1.astype(dt) + m2 = mat2.astype(dt) + res = self.matmul(m1, v) + assert_equal(res, tgt1) + res = self.matmul(m2, v) + assert_equal(res, tgt2) + + # boolean type + vec = np.array([True, False]) + mat1 = np.array([[True, False], [False, True]]) + mat2 = np.stack([mat1]*2, axis=0) + tgt1 = np.array([True, False]) + tgt2 = np.stack([tgt1]*2, axis=0) + + res = self.matmul(vec, mat1) + assert_equal(res, tgt1) + res = self.matmul(vec, mat2) + assert_equal(res, tgt2) + + def test_matrix_matrix_values(self): + mat1 = np.array([[1, 2], [3, 4]]) + mat2 = np.array([[1, 0], [1, 1]]) + mat12 = np.stack([mat1, mat2], axis=0) + mat21 = np.stack([mat2, mat1], axis=0) + tgt11 = np.array([[7, 10], [15, 22]]) + tgt12 = np.array([[3, 2], [7, 4]]) + tgt21 = np.array([[1, 2], [4, 6]]) + tgt12_21 = np.stack([tgt12, tgt21], axis=0) + tgt11_12 = np.stack((tgt11, tgt12), axis=0) + tgt11_21 = np.stack((tgt11, tgt21), axis=0) + for dt in self.types[1:]: + m1 = mat1.astype(dt) + m2 = mat2.astype(dt) + m12 = mat12.astype(dt) + m21 = mat21.astype(dt) + + # matrix @ matrix + res = self.matmul(m1, m2) + assert_equal(res, tgt12) + res = self.matmul(m2, m1) + assert_equal(res, tgt21) + + # stacked @ matrix + res = self.matmul(m12, m1) + assert_equal(res, tgt11_21) + + # matrix @ stacked + res = self.matmul(m1, m12) + assert_equal(res, tgt11_12) + + # stacked @ stacked + res = self.matmul(m12, m21) + assert_equal(res, tgt12_21) + + # boolean type + m1 = np.array([[1, 1], [0, 0]], dtype=np.bool_) + m2 = np.array([[1, 0], [1, 1]], dtype=np.bool_) + m12 = np.stack([m1, m2], axis=0) + m21 = np.stack([m2, m1], axis=0) + tgt11 = m1 + tgt12 = m1 + tgt21 = np.array([[1, 1], [1, 1]], dtype=np.bool_) + tgt12_21 = np.stack([tgt12, tgt21], axis=0) + tgt11_12 = np.stack((tgt11, tgt12), axis=0) + tgt11_21 = np.stack((tgt11, tgt21), axis=0) + + # matrix @ matrix + res = self.matmul(m1, m2) + assert_equal(res, tgt12) + res = self.matmul(m2, m1) + assert_equal(res, tgt21) + + # stacked @ matrix + res = self.matmul(m12, m1) + assert_equal(res, tgt11_21) + + # matrix @ stacked + res = self.matmul(m1, m12) + assert_equal(res, tgt11_12) + + # stacked @ stacked + res = self.matmul(m12, m21) + assert_equal(res, tgt12_21) + + +class TestMatmul(MatmulCommon): + matmul = np.matmul + + def test_out_arg(self): + a = np.ones((2, 2), dtype=float) + b = np.ones((2, 2), dtype=float) + tgt = np.full((2,2), 2, dtype=float) + + # test as positional argument + msg = "out positional argument" + out = np.zeros((2, 2), dtype=float) + self.matmul(a, b, out) + assert_array_equal(out, tgt, err_msg=msg) + + # test as keyword argument + msg = "out keyword argument" + out = np.zeros((2, 2), dtype=float) + self.matmul(a, b, out=out) + assert_array_equal(out, tgt, err_msg=msg) + + # test out with not allowed type cast (safe casting) + # einsum and cblas raise different error types, so + # use Exception. + msg = "out argument with illegal cast" + out = np.zeros((2, 2), dtype=np.int32) + assert_raises(Exception, self.matmul, a, b, out=out) + + # skip following tests for now, cblas does not allow non-contiguous + # outputs and consistency with dot would require same type, + # dimensions, subtype, and c_contiguous. + + # test out with allowed type cast + # msg = "out argument with allowed cast" + # out = np.zeros((2, 2), dtype=np.complex128) + # self.matmul(a, b, out=out) + # assert_array_equal(out, tgt, err_msg=msg) + + # test out non-contiguous + # msg = "out argument with non-contiguous layout" + # c = np.zeros((2, 2, 2), dtype=float) + # self.matmul(a, b, out=c[..., 0]) + # assert_array_equal(c, tgt, err_msg=msg) + + +if sys.version_info[:2] >= (3, 5): + class TestMatmulOperator(MatmulCommon): + import operator + matmul = operator.matmul + + def test_array_priority_override(self): + + class A(object): + __array_priority__ = 1000 + + def __matmul__(self, other): + return "A" + + def __rmatmul__(self, other): + return "A" + + a = A() + b = np.ones(2) + assert_equal(self.matmul(a, b), "A") + assert_equal(self.matmul(b, a), "A") + + def test_matmul_inplace(): + # It would be nice to support in-place matmul eventually, but for now + # we don't have a working implementation, so better just to error out + # and nudge people to writing "a = a @ b". + a = np.eye(3) + b = np.eye(3) + assert_raises(TypeError, a.__imatmul__, b) + import operator + assert_raises(TypeError, operator.imatmul, a, b) + # we avoid writing the token `exec` so as not to crash python 2's + # parser + exec_ = getattr(builtins, "exec") + assert_raises(TypeError, exec_, "a @= b", globals(), locals()) + + +class TestInner(object): + + def test_inner_type_mismatch(self): + c = 1. + A = np.array((1,1), dtype='i,i') + + assert_raises(TypeError, np.inner, c, A) + assert_raises(TypeError, np.inner, A, c) + + def test_inner_scalar_and_vector(self): + for dt in np.typecodes['AllInteger'] + np.typecodes['AllFloat'] + '?': + sca = np.array(3, dtype=dt)[()] + vec = np.array([1, 2], dtype=dt) + desired = np.array([3, 6], dtype=dt) + assert_equal(np.inner(vec, sca), desired) + assert_equal(np.inner(sca, vec), desired) + + def test_inner_scalar_and_matrix(self): + for dt in np.typecodes['AllInteger'] + np.typecodes['AllFloat'] + '?': + sca = np.array(3, dtype=dt)[()] + arr = np.matrix([[1, 2], [3, 4]], dtype=dt) + desired = np.matrix([[3, 6], [9, 12]], dtype=dt) + assert_equal(np.inner(arr, sca), desired) + assert_equal(np.inner(sca, arr), desired) + + def test_inner_scalar_and_matrix_of_objects(self): + # Ticket #4482 + arr = np.matrix([1, 2], dtype=object) + desired = np.matrix([[3, 6]], dtype=object) + assert_equal(np.inner(arr, 3), desired) + assert_equal(np.inner(3, arr), desired) + + def test_vecself(self): + # Ticket 844. + # Inner product of a vector with itself segfaults or give + # meaningless result + a = np.zeros(shape=(1, 80), dtype=np.float64) + p = np.inner(a, a) + assert_almost_equal(p, 0, decimal=14) + + def test_inner_product_with_various_contiguities(self): + # github issue 6532 + for dt in np.typecodes['AllInteger'] + np.typecodes['AllFloat'] + '?': + # check an inner product involving a matrix transpose + A = np.array([[1, 2], [3, 4]], dtype=dt) + B = np.array([[1, 3], [2, 4]], dtype=dt) + C = np.array([1, 1], dtype=dt) + desired = np.array([4, 6], dtype=dt) + assert_equal(np.inner(A.T, C), desired) + assert_equal(np.inner(C, A.T), desired) + assert_equal(np.inner(B, C), desired) + assert_equal(np.inner(C, B), desired) + # check a matrix product + desired = np.array([[7, 10], [15, 22]], dtype=dt) + assert_equal(np.inner(A, B), desired) + # check the syrk vs. gemm paths + desired = np.array([[5, 11], [11, 25]], dtype=dt) + assert_equal(np.inner(A, A), desired) + assert_equal(np.inner(A, A.copy()), desired) + # check an inner product involving an aliased and reversed view + a = np.arange(5).astype(dt) + b = a[::-1] + desired = np.array(10, dtype=dt).item() + assert_equal(np.inner(b, a), desired) + + def test_3d_tensor(self): + for dt in np.typecodes['AllInteger'] + np.typecodes['AllFloat'] + '?': + a = np.arange(24).reshape(2,3,4).astype(dt) + b = np.arange(24, 48).reshape(2,3,4).astype(dt) + desired = np.array( + [[[[ 158, 182, 206], + [ 230, 254, 278]], + + [[ 566, 654, 742], + [ 830, 918, 1006]], + + [[ 974, 1126, 1278], + [1430, 1582, 1734]]], + + [[[1382, 1598, 1814], + [2030, 2246, 2462]], + + [[1790, 2070, 2350], + [2630, 2910, 3190]], + + [[2198, 2542, 2886], + [3230, 3574, 3918]]]], + dtype=dt + ) + assert_equal(np.inner(a, b), desired) + assert_equal(np.inner(b, a).transpose(2,3,0,1), desired) + + +class TestAlen(object): + def test_basic(self): + m = np.array([1, 2, 3]) + assert_equal(np.alen(m), 3) + + m = np.array([[1, 2, 3], [4, 5, 7]]) + assert_equal(np.alen(m), 2) + + m = [1, 2, 3] + assert_equal(np.alen(m), 3) + + m = [[1, 2, 3], [4, 5, 7]] + assert_equal(np.alen(m), 2) + + def test_singleton(self): + assert_equal(np.alen(5), 1) + + +class TestChoose(object): + def setup(self): + self.x = 2*np.ones((3,), dtype=int) + self.y = 3*np.ones((3,), dtype=int) + self.x2 = 2*np.ones((2, 3), dtype=int) + self.y2 = 3*np.ones((2, 3), dtype=int) + self.ind = [0, 0, 1] + + def test_basic(self): + A = np.choose(self.ind, (self.x, self.y)) + assert_equal(A, [2, 2, 3]) + + def test_broadcast1(self): + A = np.choose(self.ind, (self.x2, self.y2)) + assert_equal(A, [[2, 2, 3], [2, 2, 3]]) + + def test_broadcast2(self): + A = np.choose(self.ind, (self.x, self.y2)) + assert_equal(A, [[2, 2, 3], [2, 2, 3]]) + + +class TestRepeat(object): + def setup(self): + self.m = np.array([1, 2, 3, 4, 5, 6]) + self.m_rect = self.m.reshape((2, 3)) + + def test_basic(self): + A = np.repeat(self.m, [1, 3, 2, 1, 1, 2]) + assert_equal(A, [1, 2, 2, 2, 3, + 3, 4, 5, 6, 6]) + + def test_broadcast1(self): + A = np.repeat(self.m, 2) + assert_equal(A, [1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6]) + + def test_axis_spec(self): + A = np.repeat(self.m_rect, [2, 1], axis=0) + assert_equal(A, [[1, 2, 3], + [1, 2, 3], + [4, 5, 6]]) + + A = np.repeat(self.m_rect, [1, 3, 2], axis=1) + assert_equal(A, [[1, 2, 2, 2, 3, 3], + [4, 5, 5, 5, 6, 6]]) + + def test_broadcast2(self): + A = np.repeat(self.m_rect, 2, axis=0) + assert_equal(A, [[1, 2, 3], + [1, 2, 3], + [4, 5, 6], + [4, 5, 6]]) + + A = np.repeat(self.m_rect, 2, axis=1) + assert_equal(A, [[1, 1, 2, 2, 3, 3], + [4, 4, 5, 5, 6, 6]]) + + +# TODO: test for multidimensional +NEIGH_MODE = {'zero': 0, 'one': 1, 'constant': 2, 'circular': 3, 'mirror': 4} + + +class TestNeighborhoodIter(object): + # Simple, 2d tests + def _test_simple2d(self, dt): + # Test zero and one padding for simple data type + x = np.array([[0, 1], [2, 3]], dtype=dt) + r = [np.array([[0, 0, 0], [0, 0, 1]], dtype=dt), + np.array([[0, 0, 0], [0, 1, 0]], dtype=dt), + np.array([[0, 0, 1], [0, 2, 3]], dtype=dt), + np.array([[0, 1, 0], [2, 3, 0]], dtype=dt)] + l = test_neighborhood_iterator(x, [-1, 0, -1, 1], x[0], + NEIGH_MODE['zero']) + assert_array_equal(l, r) + + r = [np.array([[1, 1, 1], [1, 0, 1]], dtype=dt), + np.array([[1, 1, 1], [0, 1, 1]], dtype=dt), + np.array([[1, 0, 1], [1, 2, 3]], dtype=dt), + np.array([[0, 1, 1], [2, 3, 1]], dtype=dt)] + l = test_neighborhood_iterator(x, [-1, 0, -1, 1], x[0], + NEIGH_MODE['one']) + assert_array_equal(l, r) + + r = [np.array([[4, 4, 4], [4, 0, 1]], dtype=dt), + np.array([[4, 4, 4], [0, 1, 4]], dtype=dt), + np.array([[4, 0, 1], [4, 2, 3]], dtype=dt), + np.array([[0, 1, 4], [2, 3, 4]], dtype=dt)] + l = test_neighborhood_iterator(x, [-1, 0, -1, 1], 4, + NEIGH_MODE['constant']) + assert_array_equal(l, r) + + def test_simple2d(self): + self._test_simple2d(float) + + def test_simple2d_object(self): + self._test_simple2d(Decimal) + + def _test_mirror2d(self, dt): + x = np.array([[0, 1], [2, 3]], dtype=dt) + r = [np.array([[0, 0, 1], [0, 0, 1]], dtype=dt), + np.array([[0, 1, 1], [0, 1, 1]], dtype=dt), + np.array([[0, 0, 1], [2, 2, 3]], dtype=dt), + np.array([[0, 1, 1], [2, 3, 3]], dtype=dt)] + l = test_neighborhood_iterator(x, [-1, 0, -1, 1], x[0], + NEIGH_MODE['mirror']) + assert_array_equal(l, r) + + def test_mirror2d(self): + self._test_mirror2d(float) + + def test_mirror2d_object(self): + self._test_mirror2d(Decimal) + + # Simple, 1d tests + def _test_simple(self, dt): + # Test padding with constant values + x = np.linspace(1, 5, 5).astype(dt) + r = [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 0]] + l = test_neighborhood_iterator(x, [-1, 1], x[0], NEIGH_MODE['zero']) + assert_array_equal(l, r) + + r = [[1, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 1]] + l = test_neighborhood_iterator(x, [-1, 1], x[0], NEIGH_MODE['one']) + assert_array_equal(l, r) + + r = [[x[4], 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, x[4]]] + l = test_neighborhood_iterator(x, [-1, 1], x[4], NEIGH_MODE['constant']) + assert_array_equal(l, r) + + def test_simple_float(self): + self._test_simple(float) + + def test_simple_object(self): + self._test_simple(Decimal) + + # Test mirror modes + def _test_mirror(self, dt): + x = np.linspace(1, 5, 5).astype(dt) + r = np.array([[2, 1, 1, 2, 3], [1, 1, 2, 3, 4], [1, 2, 3, 4, 5], + [2, 3, 4, 5, 5], [3, 4, 5, 5, 4]], dtype=dt) + l = test_neighborhood_iterator(x, [-2, 2], x[1], NEIGH_MODE['mirror']) + assert_([i.dtype == dt for i in l]) + assert_array_equal(l, r) + + def test_mirror(self): + self._test_mirror(float) + + def test_mirror_object(self): + self._test_mirror(Decimal) + + # Circular mode + def _test_circular(self, dt): + x = np.linspace(1, 5, 5).astype(dt) + r = np.array([[4, 5, 1, 2, 3], [5, 1, 2, 3, 4], [1, 2, 3, 4, 5], + [2, 3, 4, 5, 1], [3, 4, 5, 1, 2]], dtype=dt) + l = test_neighborhood_iterator(x, [-2, 2], x[0], NEIGH_MODE['circular']) + assert_array_equal(l, r) + + def test_circular(self): + self._test_circular(float) + + def test_circular_object(self): + self._test_circular(Decimal) + +# Test stacking neighborhood iterators +class TestStackedNeighborhoodIter(object): + # Simple, 1d test: stacking 2 constant-padded neigh iterators + def test_simple_const(self): + dt = np.float64 + # Test zero and one padding for simple data type + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([0], dtype=dt), + np.array([0], dtype=dt), + np.array([1], dtype=dt), + np.array([2], dtype=dt), + np.array([3], dtype=dt), + np.array([0], dtype=dt), + np.array([0], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-2, 4], NEIGH_MODE['zero'], + [0, 0], NEIGH_MODE['zero']) + assert_array_equal(l, r) + + r = [np.array([1, 0, 1], dtype=dt), + np.array([0, 1, 2], dtype=dt), + np.array([1, 2, 3], dtype=dt), + np.array([2, 3, 0], dtype=dt), + np.array([3, 0, 1], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['zero'], + [-1, 1], NEIGH_MODE['one']) + assert_array_equal(l, r) + + # 2nd simple, 1d test: stacking 2 neigh iterators, mixing const padding and + # mirror padding + def test_simple_mirror(self): + dt = np.float64 + # Stacking zero on top of mirror + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([0, 1, 1], dtype=dt), + np.array([1, 1, 2], dtype=dt), + np.array([1, 2, 3], dtype=dt), + np.array([2, 3, 3], dtype=dt), + np.array([3, 3, 0], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['mirror'], + [-1, 1], NEIGH_MODE['zero']) + assert_array_equal(l, r) + + # Stacking mirror on top of zero + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([1, 0, 0], dtype=dt), + np.array([0, 0, 1], dtype=dt), + np.array([0, 1, 2], dtype=dt), + np.array([1, 2, 3], dtype=dt), + np.array([2, 3, 0], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['zero'], + [-2, 0], NEIGH_MODE['mirror']) + assert_array_equal(l, r) + + # Stacking mirror on top of zero: 2nd + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([0, 1, 2], dtype=dt), + np.array([1, 2, 3], dtype=dt), + np.array([2, 3, 0], dtype=dt), + np.array([3, 0, 0], dtype=dt), + np.array([0, 0, 3], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['zero'], + [0, 2], NEIGH_MODE['mirror']) + assert_array_equal(l, r) + + # Stacking mirror on top of zero: 3rd + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([1, 0, 0, 1, 2], dtype=dt), + np.array([0, 0, 1, 2, 3], dtype=dt), + np.array([0, 1, 2, 3, 0], dtype=dt), + np.array([1, 2, 3, 0, 0], dtype=dt), + np.array([2, 3, 0, 0, 3], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['zero'], + [-2, 2], NEIGH_MODE['mirror']) + assert_array_equal(l, r) + + # 3rd simple, 1d test: stacking 2 neigh iterators, mixing const padding and + # circular padding + def test_simple_circular(self): + dt = np.float64 + # Stacking zero on top of mirror + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([0, 3, 1], dtype=dt), + np.array([3, 1, 2], dtype=dt), + np.array([1, 2, 3], dtype=dt), + np.array([2, 3, 1], dtype=dt), + np.array([3, 1, 0], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['circular'], + [-1, 1], NEIGH_MODE['zero']) + assert_array_equal(l, r) + + # Stacking mirror on top of zero + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([3, 0, 0], dtype=dt), + np.array([0, 0, 1], dtype=dt), + np.array([0, 1, 2], dtype=dt), + np.array([1, 2, 3], dtype=dt), + np.array([2, 3, 0], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['zero'], + [-2, 0], NEIGH_MODE['circular']) + assert_array_equal(l, r) + + # Stacking mirror on top of zero: 2nd + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([0, 1, 2], dtype=dt), + np.array([1, 2, 3], dtype=dt), + np.array([2, 3, 0], dtype=dt), + np.array([3, 0, 0], dtype=dt), + np.array([0, 0, 1], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['zero'], + [0, 2], NEIGH_MODE['circular']) + assert_array_equal(l, r) + + # Stacking mirror on top of zero: 3rd + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([3, 0, 0, 1, 2], dtype=dt), + np.array([0, 0, 1, 2, 3], dtype=dt), + np.array([0, 1, 2, 3, 0], dtype=dt), + np.array([1, 2, 3, 0, 0], dtype=dt), + np.array([2, 3, 0, 0, 1], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [-1, 3], NEIGH_MODE['zero'], + [-2, 2], NEIGH_MODE['circular']) + assert_array_equal(l, r) + + # 4th simple, 1d test: stacking 2 neigh iterators, but with lower iterator + # being strictly within the array + def test_simple_strict_within(self): + dt = np.float64 + # Stacking zero on top of zero, first neighborhood strictly inside the + # array + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([1, 2, 3, 0], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [1, 1], NEIGH_MODE['zero'], + [-1, 2], NEIGH_MODE['zero']) + assert_array_equal(l, r) + + # Stacking mirror on top of zero, first neighborhood strictly inside the + # array + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([1, 2, 3, 3], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [1, 1], NEIGH_MODE['zero'], + [-1, 2], NEIGH_MODE['mirror']) + assert_array_equal(l, r) + + # Stacking mirror on top of zero, first neighborhood strictly inside the + # array + x = np.array([1, 2, 3], dtype=dt) + r = [np.array([1, 2, 3, 1], dtype=dt)] + l = test_neighborhood_iterator_oob(x, [1, 1], NEIGH_MODE['zero'], + [-1, 2], NEIGH_MODE['circular']) + assert_array_equal(l, r) + +class TestWarnings(object): + + def test_complex_warning(self): + x = np.array([1, 2]) + y = np.array([1-2j, 1+2j]) + + with warnings.catch_warnings(): + warnings.simplefilter("error", np.ComplexWarning) + assert_raises(np.ComplexWarning, x.__setitem__, slice(None), y) + assert_equal(x, [1, 2]) + + +class TestMinScalarType(object): + + def test_usigned_shortshort(self): + dt = np.min_scalar_type(2**8-1) + wanted = np.dtype('uint8') + assert_equal(wanted, dt) + + def test_usigned_short(self): + dt = np.min_scalar_type(2**16-1) + wanted = np.dtype('uint16') + assert_equal(wanted, dt) + + def test_usigned_int(self): + dt = np.min_scalar_type(2**32-1) + wanted = np.dtype('uint32') + assert_equal(wanted, dt) + + def test_usigned_longlong(self): + dt = np.min_scalar_type(2**63-1) + wanted = np.dtype('uint64') + assert_equal(wanted, dt) + + def test_object(self): + dt = np.min_scalar_type(2**64) + wanted = np.dtype('O') + assert_equal(wanted, dt) + + +from numpy.core._internal import _dtype_from_pep3118 + + +class TestPEP3118Dtype(object): + def _check(self, spec, wanted): + dt = np.dtype(wanted) + actual = _dtype_from_pep3118(spec) + assert_equal(actual, dt, + err_msg="spec %r != dtype %r" % (spec, wanted)) + + def test_native_padding(self): + align = np.dtype('i').alignment + for j in range(8): + if j == 0: + s = 'bi' + else: + s = 'b%dxi' % j + self._check('@'+s, {'f0': ('i1', 0), + 'f1': ('i', align*(1 + j//align))}) + self._check('='+s, {'f0': ('i1', 0), + 'f1': ('i', 1+j)}) + + def test_native_padding_2(self): + # Native padding should work also for structs and sub-arrays + self._check('x3T{xi}', {'f0': (({'f0': ('i', 4)}, (3,)), 4)}) + self._check('^x3T{xi}', {'f0': (({'f0': ('i', 1)}, (3,)), 1)}) + + def test_trailing_padding(self): + # Trailing padding should be included, *and*, the item size + # should match the alignment if in aligned mode + align = np.dtype('i').alignment + size = np.dtype('i').itemsize + + def aligned(n): + return align*(1 + (n-1)//align) + + base = dict(formats=['i'], names=['f0']) + + self._check('ix', dict(itemsize=aligned(size + 1), **base)) + self._check('ixx', dict(itemsize=aligned(size + 2), **base)) + self._check('ixxx', dict(itemsize=aligned(size + 3), **base)) + self._check('ixxxx', dict(itemsize=aligned(size + 4), **base)) + self._check('i7x', dict(itemsize=aligned(size + 7), **base)) + + self._check('^ix', dict(itemsize=size + 1, **base)) + self._check('^ixx', dict(itemsize=size + 2, **base)) + self._check('^ixxx', dict(itemsize=size + 3, **base)) + self._check('^ixxxx', dict(itemsize=size + 4, **base)) + self._check('^i7x', dict(itemsize=size + 7, **base)) + + def test_native_padding_3(self): + dt = np.dtype( + [('a', 'b'), ('b', 'i'), + ('sub', np.dtype('b,i')), ('c', 'i')], + align=True) + self._check("T{b:a:xxxi:b:T{b:f0:=i:f1:}:sub:xxxi:c:}", dt) + + dt = np.dtype( + [('a', 'b'), ('b', 'i'), ('c', 'b'), ('d', 'b'), + ('e', 'b'), ('sub', np.dtype('b,i', align=True))]) + self._check("T{b:a:=i:b:b:c:b:d:b:e:T{b:f0:xxxi:f1:}:sub:}", dt) + + def test_padding_with_array_inside_struct(self): + dt = np.dtype( + [('a', 'b'), ('b', 'i'), ('c', 'b', (3,)), + ('d', 'i')], + align=True) + self._check("T{b:a:xxxi:b:3b:c:xi:d:}", dt) + + def test_byteorder_inside_struct(self): + # The byte order after @T{=i} should be '=', not '@'. + # Check this by noting the absence of native alignment. + self._check('@T{^i}xi', {'f0': ({'f0': ('i', 0)}, 0), + 'f1': ('i', 5)}) + + def test_intra_padding(self): + # Natively aligned sub-arrays may require some internal padding + align = np.dtype('i').alignment + size = np.dtype('i').itemsize + + def aligned(n): + return (align*(1 + (n-1)//align)) + + self._check('(3)T{ix}', (dict( + names=['f0'], + formats=['i'], + offsets=[0], + itemsize=aligned(size + 1) + ), (3,))) + + def test_char_vs_string(self): + dt = np.dtype('c') + self._check('c', dt) + + dt = np.dtype([('f0', 'S1', (4,)), ('f1', 'S4')]) + self._check('4c4s', dt) + + def test_field_order(self): + # gh-9053 - previously, we relied on dictionary key order + self._check("(0)I:a:f:b:", [('a', 'I', (0,)), ('b', 'f')]) + self._check("(0)I:b:f:a:", [('b', 'I', (0,)), ('a', 'f')]) + + def test_unnamed_fields(self): + self._check('ii', [('f0', 'i'), ('f1', 'i')]) + self._check('ii:f0:', [('f1', 'i'), ('f0', 'i')]) + + self._check('i', 'i') + self._check('i:f0:', [('f0', 'i')]) + +class TestNewBufferProtocol(object): + def _check_roundtrip(self, obj): + obj = np.asarray(obj) + x = memoryview(obj) + y = np.asarray(x) + y2 = np.array(x) + assert_(not y.flags.owndata) + assert_(y2.flags.owndata) + + assert_equal(y.dtype, obj.dtype) + assert_equal(y.shape, obj.shape) + assert_array_equal(obj, y) + + assert_equal(y2.dtype, obj.dtype) + assert_equal(y2.shape, obj.shape) + assert_array_equal(obj, y2) + + def test_roundtrip(self): + x = np.array([1, 2, 3, 4, 5], dtype='i4') + self._check_roundtrip(x) + + x = np.array([[1, 2], [3, 4]], dtype=np.float64) + self._check_roundtrip(x) + + x = np.zeros((3, 3, 3), dtype=np.float32)[:, 0,:] + self._check_roundtrip(x) + + dt = [('a', 'b'), + ('b', 'h'), + ('c', 'i'), + ('d', 'l'), + ('dx', 'q'), + ('e', 'B'), + ('f', 'H'), + ('g', 'I'), + ('h', 'L'), + ('hx', 'Q'), + ('i', np.single), + ('j', np.double), + ('k', np.longdouble), + ('ix', np.csingle), + ('jx', np.cdouble), + ('kx', np.clongdouble), + ('l', 'S4'), + ('m', 'U4'), + ('n', 'V3'), + ('o', '?'), + ('p', np.half), + ] + x = np.array( + [(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + b'aaaa', 'bbbb', b'xxx', True, 1.0)], + dtype=dt) + self._check_roundtrip(x) + + x = np.array(([[1, 2], [3, 4]],), dtype=[('a', (int, (2, 2)))]) + self._check_roundtrip(x) + + x = np.array([1, 2, 3], dtype='>i2') + self._check_roundtrip(x) + + x = np.array([1, 2, 3], dtype='') + x = np.zeros(4, dtype=dt) + self._check_roundtrip(x) + + def test_roundtrip_scalar(self): + # Issue #4015. + self._check_roundtrip(0) + + def test_export_simple_1d(self): + x = np.array([1, 2, 3, 4, 5], dtype='i') + y = memoryview(x) + assert_equal(y.format, 'i') + assert_equal(y.shape, (5,)) + assert_equal(y.ndim, 1) + assert_equal(y.strides, (4,)) + assert_equal(y.suboffsets, EMPTY) + assert_equal(y.itemsize, 4) + + def test_export_simple_nd(self): + x = np.array([[1, 2], [3, 4]], dtype=np.float64) + y = memoryview(x) + assert_equal(y.format, 'd') + assert_equal(y.shape, (2, 2)) + assert_equal(y.ndim, 2) + assert_equal(y.strides, (16, 8)) + assert_equal(y.suboffsets, EMPTY) + assert_equal(y.itemsize, 8) + + def test_export_discontiguous(self): + x = np.zeros((3, 3, 3), dtype=np.float32)[:, 0,:] + y = memoryview(x) + assert_equal(y.format, 'f') + assert_equal(y.shape, (3, 3)) + assert_equal(y.ndim, 2) + assert_equal(y.strides, (36, 4)) + assert_equal(y.suboffsets, EMPTY) + assert_equal(y.itemsize, 4) + + def test_export_record(self): + dt = [('a', 'b'), + ('b', 'h'), + ('c', 'i'), + ('d', 'l'), + ('dx', 'q'), + ('e', 'B'), + ('f', 'H'), + ('g', 'I'), + ('h', 'L'), + ('hx', 'Q'), + ('i', np.single), + ('j', np.double), + ('k', np.longdouble), + ('ix', np.csingle), + ('jx', np.cdouble), + ('kx', np.clongdouble), + ('l', 'S4'), + ('m', 'U4'), + ('n', 'V3'), + ('o', '?'), + ('p', np.half), + ] + x = np.array( + [(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + b'aaaa', 'bbbb', b' ', True, 1.0)], + dtype=dt) + y = memoryview(x) + assert_equal(y.shape, (1,)) + assert_equal(y.ndim, 1) + assert_equal(y.suboffsets, EMPTY) + + sz = sum([np.dtype(b).itemsize for a, b in dt]) + if np.dtype('l').itemsize == 4: + assert_equal(y.format, 'T{b:a:=h:b:i:c:l:d:q:dx:B:e:@H:f:=I:g:L:h:Q:hx:f:i:d:j:^g:k:=Zf:ix:Zd:jx:^Zg:kx:4s:l:=4w:m:3x:n:?:o:@e:p:}') + else: + assert_equal(y.format, 'T{b:a:=h:b:i:c:q:d:q:dx:B:e:@H:f:=I:g:Q:h:Q:hx:f:i:d:j:^g:k:=Zf:ix:Zd:jx:^Zg:kx:4s:l:=4w:m:3x:n:?:o:@e:p:}') + # Cannot test if NPY_RELAXED_STRIDES_CHECKING changes the strides + if not (np.ones(1).strides[0] == np.iinfo(np.intp).max): + assert_equal(y.strides, (sz,)) + assert_equal(y.itemsize, sz) + + def test_export_subarray(self): + x = np.array(([[1, 2], [3, 4]],), dtype=[('a', ('i', (2, 2)))]) + y = memoryview(x) + assert_equal(y.format, 'T{(2,2)i:a:}') + assert_equal(y.shape, EMPTY) + assert_equal(y.ndim, 0) + assert_equal(y.strides, EMPTY) + assert_equal(y.suboffsets, EMPTY) + assert_equal(y.itemsize, 16) + + def test_export_endian(self): + x = np.array([1, 2, 3], dtype='>i') + y = memoryview(x) + if sys.byteorder == 'little': + assert_equal(y.format, '>i') + else: + assert_equal(y.format, 'i') + + x = np.array([1, 2, 3], dtype=' np.array(0, dtype=dt1), "type %s failed" % (dt1,)) + assert_(not 1 < np.array(0, dtype=dt1), "type %s failed" % (dt1,)) + + for dt2 in np.typecodes['AllInteger']: + assert_(np.array(1, dtype=dt1) > np.array(0, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1) < np.array(0, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + + # Unsigned integers + for dt1 in 'BHILQP': + assert_(-1 < np.array(1, dtype=dt1), "type %s failed" % (dt1,)) + assert_(not -1 > np.array(1, dtype=dt1), "type %s failed" % (dt1,)) + assert_(-1 != np.array(1, dtype=dt1), "type %s failed" % (dt1,)) + + # Unsigned vs signed + for dt2 in 'bhilqp': + assert_(np.array(1, dtype=dt1) > np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1) < np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(np.array(1, dtype=dt1) != np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + + # Signed integers and floats + for dt1 in 'bhlqp' + np.typecodes['Float']: + assert_(1 > np.array(-1, dtype=dt1), "type %s failed" % (dt1,)) + assert_(not 1 < np.array(-1, dtype=dt1), "type %s failed" % (dt1,)) + assert_(-1 == np.array(-1, dtype=dt1), "type %s failed" % (dt1,)) + + for dt2 in 'bhlqp' + np.typecodes['Float']: + assert_(np.array(1, dtype=dt1) > np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1) < np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(np.array(-1, dtype=dt1) == np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + + def test_to_bool_scalar(self): + assert_equal(bool(np.array([False])), False) + assert_equal(bool(np.array([True])), True) + assert_equal(bool(np.array([[42]])), True) + assert_raises(ValueError, bool, np.array([1, 2])) + + class NotConvertible(object): + def __bool__(self): + raise NotImplementedError + __nonzero__ = __bool__ # python 2 + + assert_raises(NotImplementedError, bool, np.array(NotConvertible())) + assert_raises(NotImplementedError, bool, np.array([NotConvertible()])) + + self_containing = np.array([None]) + self_containing[0] = self_containing + try: + Error = RecursionError + except NameError: + Error = RuntimeError # python < 3.5 + assert_raises(Error, bool, self_containing) # previously stack overflow + + def test_to_int_scalar(self): + # gh-9972 means that these aren't always the same + int_funcs = (int, lambda x: x.__int__()) + for int_func in int_funcs: + assert_equal(int_func(np.array([1])), 1) + assert_equal(int_func(np.array([0])), 0) + assert_equal(int_func(np.array([[42]])), 42) + assert_raises(TypeError, int_func, np.array([1, 2])) + + # gh-9972 + assert_equal(4, int_func(np.array('4'))) + assert_equal(5, int_func(np.bytes_(b'5'))) + assert_equal(6, int_func(np.unicode_(u'6'))) + + class HasTrunc: + def __trunc__(self): + return 3 + assert_equal(3, int_func(np.array(HasTrunc()))) + assert_equal(3, int_func(np.array([HasTrunc()]))) + + class NotConvertible(object): + def __int__(self): + raise NotImplementedError + assert_raises(NotImplementedError, + int_func, np.array(NotConvertible())) + assert_raises(NotImplementedError, + int_func, np.array([NotConvertible()])) + + +class TestWhere(object): + def test_basic(self): + dts = [bool, np.int16, np.int32, np.int64, np.double, np.complex128, + np.longdouble, np.clongdouble] + for dt in dts: + c = np.ones(53, dtype=bool) + assert_equal(np.where( c, dt(0), dt(1)), dt(0)) + assert_equal(np.where(~c, dt(0), dt(1)), dt(1)) + assert_equal(np.where(True, dt(0), dt(1)), dt(0)) + assert_equal(np.where(False, dt(0), dt(1)), dt(1)) + d = np.ones_like(c).astype(dt) + e = np.zeros_like(d) + r = d.astype(dt) + c[7] = False + r[7] = e[7] + assert_equal(np.where(c, e, e), e) + assert_equal(np.where(c, d, e), r) + assert_equal(np.where(c, d, e[0]), r) + assert_equal(np.where(c, d[0], e), r) + assert_equal(np.where(c[::2], d[::2], e[::2]), r[::2]) + assert_equal(np.where(c[1::2], d[1::2], e[1::2]), r[1::2]) + assert_equal(np.where(c[::3], d[::3], e[::3]), r[::3]) + assert_equal(np.where(c[1::3], d[1::3], e[1::3]), r[1::3]) + assert_equal(np.where(c[::-2], d[::-2], e[::-2]), r[::-2]) + assert_equal(np.where(c[::-3], d[::-3], e[::-3]), r[::-3]) + assert_equal(np.where(c[1::-3], d[1::-3], e[1::-3]), r[1::-3]) + + def test_exotic(self): + # object + assert_array_equal(np.where(True, None, None), np.array(None)) + # zero sized + m = np.array([], dtype=bool).reshape(0, 3) + b = np.array([], dtype=np.float64).reshape(0, 3) + assert_array_equal(np.where(m, 0, b), np.array([]).reshape(0, 3)) + + # object cast + d = np.array([-1.34, -0.16, -0.54, -0.31, -0.08, -0.95, 0.000, 0.313, + 0.547, -0.18, 0.876, 0.236, 1.969, 0.310, 0.699, 1.013, + 1.267, 0.229, -1.39, 0.487]) + nan = float('NaN') + e = np.array(['5z', '0l', nan, 'Wz', nan, nan, 'Xq', 'cs', nan, nan, + 'QN', nan, nan, 'Fd', nan, nan, 'kp', nan, '36', 'i1'], + dtype=object) + m = np.array([0, 0, 1, 0, 1, 1, 0, 0, 1, 1, + 0, 1, 1, 0, 1, 1, 0, 1, 0, 0], dtype=bool) + + r = e[:] + r[np.where(m)] = d[np.where(m)] + assert_array_equal(np.where(m, d, e), r) + + r = e[:] + r[np.where(~m)] = d[np.where(~m)] + assert_array_equal(np.where(m, e, d), r) + + assert_array_equal(np.where(m, e, e), e) + + # minimal dtype result with NaN scalar (e.g required by pandas) + d = np.array([1., 2.], dtype=np.float32) + e = float('NaN') + assert_equal(np.where(True, d, e).dtype, np.float32) + e = float('Infinity') + assert_equal(np.where(True, d, e).dtype, np.float32) + e = float('-Infinity') + assert_equal(np.where(True, d, e).dtype, np.float32) + # also check upcast + e = float(1e150) + assert_equal(np.where(True, d, e).dtype, np.float64) + + def test_ndim(self): + c = [True, False] + a = np.zeros((2, 25)) + b = np.ones((2, 25)) + r = np.where(np.array(c)[:,np.newaxis], a, b) + assert_array_equal(r[0], a[0]) + assert_array_equal(r[1], b[0]) + + a = a.T + b = b.T + r = np.where(c, a, b) + assert_array_equal(r[:,0], a[:,0]) + assert_array_equal(r[:,1], b[:,0]) + + def test_dtype_mix(self): + c = np.array([False, True, False, False, False, False, True, False, + False, False, True, False]) + a = np.uint32(1) + b = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.], + dtype=np.float64) + r = np.array([5., 1., 3., 2., -1., -4., 1., -10., 10., 1., 1., 3.], + dtype=np.float64) + assert_equal(np.where(c, a, b), r) + + a = a.astype(np.float32) + b = b.astype(np.int64) + assert_equal(np.where(c, a, b), r) + + # non bool mask + c = c.astype(int) + c[c != 0] = 34242324 + assert_equal(np.where(c, a, b), r) + # invert + tmpmask = c != 0 + c[c == 0] = 41247212 + c[tmpmask] = 0 + assert_equal(np.where(c, b, a), r) + + def test_foreign(self): + c = np.array([False, True, False, False, False, False, True, False, + False, False, True, False]) + r = np.array([5., 1., 3., 2., -1., -4., 1., -10., 10., 1., 1., 3.], + dtype=np.float64) + a = np.ones(1, dtype='>i4') + b = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.], + dtype=np.float64) + assert_equal(np.where(c, a, b), r) + + b = b.astype('>f8') + assert_equal(np.where(c, a, b), r) + + a = a.astype('i4') + assert_equal(np.where(c, a, b), r) + + def test_error(self): + c = [True, True] + a = np.ones((4, 5)) + b = np.ones((5, 5)) + assert_raises(ValueError, np.where, c, a, a) + assert_raises(ValueError, np.where, c[0], a, b) + + def test_string(self): + # gh-4778 check strings are properly filled with nulls + a = np.array("abc") + b = np.array("x" * 753) + assert_equal(np.where(True, a, b), "abc") + assert_equal(np.where(False, b, a), "abc") + + # check native datatype sized strings + a = np.array("abcd") + b = np.array("x" * 8) + assert_equal(np.where(True, a, b), "abcd") + assert_equal(np.where(False, b, a), "abcd") + + def test_empty_result(self): + # pass empty where result through an assignment which reads the data of + # empty arrays, error detectable with valgrind, see gh-8922 + x = np.zeros((1, 1)) + ibad = np.vstack(np.where(x == 99.)) + assert_array_equal(ibad, + np.atleast_2d(np.array([[],[]], dtype=np.intp))) + + def test_largedim(self): + # invalid read regression gh-9304 + shape = [10, 2, 3, 4, 5, 6] + np.random.seed(2) + array = np.random.rand(*shape) + + for i in range(10): + benchmark = array.nonzero() + result = array.nonzero() + assert_array_equal(benchmark, result) + + +if not IS_PYPY: + # sys.getsizeof() is not valid on PyPy + class TestSizeOf(object): + + def test_empty_array(self): + x = np.array([]) + assert_(sys.getsizeof(x) > 0) + + def check_array(self, dtype): + elem_size = dtype(0).itemsize + + for length in [10, 50, 100, 500]: + x = np.arange(length, dtype=dtype) + assert_(sys.getsizeof(x) > length * elem_size) + + def test_array_int32(self): + self.check_array(np.int32) + + def test_array_int64(self): + self.check_array(np.int64) + + def test_array_float32(self): + self.check_array(np.float32) + + def test_array_float64(self): + self.check_array(np.float64) + + def test_view(self): + d = np.ones(100) + assert_(sys.getsizeof(d[...]) < sys.getsizeof(d)) + + def test_reshape(self): + d = np.ones(100) + assert_(sys.getsizeof(d) < sys.getsizeof(d.reshape(100, 1, 1).copy())) + + def test_resize(self): + d = np.ones(100) + old = sys.getsizeof(d) + d.resize(50) + assert_(old > sys.getsizeof(d)) + d.resize(150) + assert_(old < sys.getsizeof(d)) + + def test_error(self): + d = np.ones(100) + assert_raises(TypeError, d.__sizeof__, "a") + + +class TestHashing(object): + + def test_arrays_not_hashable(self): + x = np.ones(3) + assert_raises(TypeError, hash, x) + + def test_collections_hashable(self): + x = np.array([]) + assert_(not isinstance(x, collections.Hashable)) + + +class TestArrayPriority(object): + # This will go away when __array_priority__ is settled, meanwhile + # it serves to check unintended changes. + op = operator + binary_ops = [ + op.pow, op.add, op.sub, op.mul, op.floordiv, op.truediv, op.mod, + op.and_, op.or_, op.xor, op.lshift, op.rshift, op.mod, op.gt, + op.ge, op.lt, op.le, op.ne, op.eq + ] + + # See #7949. Dont use "/" operator With -3 switch, since python reports it + # as a DeprecationWarning + if sys.version_info[0] < 3 and not sys.py3kwarning: + binary_ops.append(op.div) + + class Foo(np.ndarray): + __array_priority__ = 100. + + def __new__(cls, *args, **kwargs): + return np.array(*args, **kwargs).view(cls) + + class Bar(np.ndarray): + __array_priority__ = 101. + + def __new__(cls, *args, **kwargs): + return np.array(*args, **kwargs).view(cls) + + class Other(object): + __array_priority__ = 1000. + + def _all(self, other): + return self.__class__() + + __add__ = __radd__ = _all + __sub__ = __rsub__ = _all + __mul__ = __rmul__ = _all + __pow__ = __rpow__ = _all + __div__ = __rdiv__ = _all + __mod__ = __rmod__ = _all + __truediv__ = __rtruediv__ = _all + __floordiv__ = __rfloordiv__ = _all + __and__ = __rand__ = _all + __xor__ = __rxor__ = _all + __or__ = __ror__ = _all + __lshift__ = __rlshift__ = _all + __rshift__ = __rrshift__ = _all + __eq__ = _all + __ne__ = _all + __gt__ = _all + __ge__ = _all + __lt__ = _all + __le__ = _all + + def test_ndarray_subclass(self): + a = np.array([1, 2]) + b = self.Bar([1, 2]) + for f in self.binary_ops: + msg = repr(f) + assert_(isinstance(f(a, b), self.Bar), msg) + assert_(isinstance(f(b, a), self.Bar), msg) + + def test_ndarray_other(self): + a = np.array([1, 2]) + b = self.Other() + for f in self.binary_ops: + msg = repr(f) + assert_(isinstance(f(a, b), self.Other), msg) + assert_(isinstance(f(b, a), self.Other), msg) + + def test_subclass_subclass(self): + a = self.Foo([1, 2]) + b = self.Bar([1, 2]) + for f in self.binary_ops: + msg = repr(f) + assert_(isinstance(f(a, b), self.Bar), msg) + assert_(isinstance(f(b, a), self.Bar), msg) + + def test_subclass_other(self): + a = self.Foo([1, 2]) + b = self.Other() + for f in self.binary_ops: + msg = repr(f) + assert_(isinstance(f(a, b), self.Other), msg) + assert_(isinstance(f(b, a), self.Other), msg) + + +class TestBytestringArrayNonzero(object): + + def test_empty_bstring_array_is_falsey(self): + assert_(not np.array([''], dtype=str)) + + def test_whitespace_bstring_array_is_falsey(self): + a = np.array(['spam'], dtype=str) + a[0] = ' \0\0' + assert_(not a) + + def test_all_null_bstring_array_is_falsey(self): + a = np.array(['spam'], dtype=str) + a[0] = '\0\0\0\0' + assert_(not a) + + def test_null_inside_bstring_array_is_truthy(self): + a = np.array(['spam'], dtype=str) + a[0] = ' \0 \0' + assert_(a) + + +class TestUnicodeArrayNonzero(object): + + def test_empty_ustring_array_is_falsey(self): + assert_(not np.array([''], dtype=np.unicode)) + + def test_whitespace_ustring_array_is_falsey(self): + a = np.array(['eggs'], dtype=np.unicode) + a[0] = ' \0\0' + assert_(not a) + + def test_all_null_ustring_array_is_falsey(self): + a = np.array(['eggs'], dtype=np.unicode) + a[0] = '\0\0\0\0' + assert_(not a) + + def test_null_inside_ustring_array_is_truthy(self): + a = np.array(['eggs'], dtype=np.unicode) + a[0] = ' \0 \0' + assert_(a) + + +class TestFormat(object): + + def test_0d(self): + a = np.array(np.pi) + assert_equal('{:0.3g}'.format(a), '3.14') + assert_equal('{:0.3g}'.format(a[()]), '3.14') + + def test_1d_no_format(self): + a = np.array([np.pi]) + assert_equal('{}'.format(a), str(a)) + + def test_1d_format(self): + # until gh-5543, ensure that the behaviour matches what it used to be + a = np.array([np.pi]) + if sys.version_info[:2] >= (3, 4): + assert_raises(TypeError, '{:30}'.format, a) + else: + with suppress_warnings() as sup: + sup.filter(PendingDeprecationWarning) + res = '{:30}'.format(a) + dst = object.__format__(a, '30') + assert_equal(res, dst) + + +class TestCTypes(object): + + def test_ctypes_is_available(self): + test_arr = np.array([[1, 2, 3], [4, 5, 6]]) + + assert_equal(ctypes, test_arr.ctypes._ctypes) + assert_equal(tuple(test_arr.ctypes.shape), (2, 3)) + + def test_ctypes_is_not_available(self): + from numpy.core import _internal + _internal.ctypes = None + try: + test_arr = np.array([[1, 2, 3], [4, 5, 6]]) + + assert_(isinstance(test_arr.ctypes._ctypes, + _internal._missing_ctypes)) + assert_equal(tuple(test_arr.ctypes.shape), (2, 3)) + finally: + _internal.ctypes = ctypes + + +class TestWritebackIfCopy(TestCase): + # all these tests use the WRITEBACKIFCOPY mechanism + def test_argmax_with_out(self): + mat = np.eye(5) + out = np.empty(5, dtype='i2') + res = np.argmax(mat, 0, out=out) + assert_equal(res, range(5)) + + def test_argmin_with_out(self): + mat = -np.eye(5) + out = np.empty(5, dtype='i2') + res = np.argmin(mat, 0, out=out) + assert_equal(res, range(5)) + + def test_clip_with_out(self): + mat = np.eye(5) + out = np.eye(5, dtype='i2') + res = np.clip(mat, a_min=-10, a_max=0, out=out) + assert_equal(np.sum(out), 0) + + def test_insert_noncontiguous(self): + a = np.arange(6).reshape(2,3).T # force non-c-contiguous + # uses arr_insert + np.place(a, a>2, [44, 55]) + assert_equal(a, np.array([[0, 44], [1, 55], [2, 44]])) + + def test_put_noncontiguous(self): + a = np.arange(6).reshape(2,3).T # force non-c-contiguous + np.put(a, [0, 2], [44, 55]) + assert_equal(a, np.array([[44, 3], [55, 4], [2, 5]])) + + def test_putmask_noncontiguous(self): + a = np.arange(6).reshape(2,3).T # force non-c-contiguous + # uses arr_putmask + np.putmask(a, a>2, a**2) + assert_equal(a, np.array([[0, 9], [1, 16], [2, 25]])) + + def test_take_mode_raise(self): + a = np.arange(6, dtype='int') + out = np.empty(2, dtype='int') + np.take(a, [0, 2], out=out, mode='raise') + assert_equal(out, np.array([0, 2])) + + def test_choose_mod_raise(self): + a = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]]) + out = np.empty((3,3), dtype='int') + choices = [-10, 10] + np.choose(a, choices, out=out, mode='raise') + assert_equal(out, np.array([[ 10, -10, 10], + [-10, 10, -10], + [ 10, -10, 10]])) + + def test_flatiter__array__(self): + a = np.arange(9).reshape(3,3) + b = a.T.flat + c = b.__array__() + # triggers the WRITEBACKIFCOPY resolution, assuming refcount semantics + del c + + def test_dot_out(self): + # if HAVE_CBLAS, will use WRITEBACKIFCOPY + a = np.arange(9, dtype=float).reshape(3,3) + b = np.dot(a, a, out=a) + assert_equal(b, np.array([[15, 18, 21], [42, 54, 66], [69, 90, 111]])) + + def test_view_assign(self): + from numpy.core.multiarray_tests import npy_create_writebackifcopy, npy_resolve + + arr = np.arange(9).reshape(3, 3).T + arr_wb = npy_create_writebackifcopy(arr) + assert_(arr_wb.flags.writebackifcopy) + assert_(arr_wb.base is arr) + arr_wb[...] = -100 + npy_resolve(arr_wb) + # arr changes after resolve, even though we assigned to arr_wb + assert_equal(arr, -100) + # after resolve, the two arrays no longer reference each other + assert_(arr_wb.ctypes.data != 0) + assert_equal(arr_wb.base, None) + # assigning to arr_wb does not get transfered to arr + arr_wb[...] = 100 + assert_equal(arr, -100) + + + def test_view_discard_refcount(self): + from numpy.core.multiarray_tests import npy_create_writebackifcopy, npy_discard + + arr = np.arange(9).reshape(3, 3).T + orig = arr.copy() + if HAS_REFCOUNT: + arr_cnt = sys.getrefcount(arr) + arr_wb = npy_create_writebackifcopy(arr) + assert_(arr_wb.flags.writebackifcopy) + assert_(arr_wb.base is arr) + arr_wb[...] = -100 + npy_discard(arr_wb) + # arr remains unchanged after discard + assert_equal(arr, orig) + # after discard, the two arrays no longer reference each other + assert_(arr_wb.ctypes.data != 0) + assert_equal(arr_wb.base, None) + if HAS_REFCOUNT: + assert_equal(arr_cnt, sys.getrefcount(arr)) + # assigning to arr_wb does not get transfered to arr + arr_wb[...] = 100 + assert_equal(arr, orig) + + +class TestArange(object): + def test_infinite(self): + assert_raises_regex( + ValueError, "size exceeded", + np.arange, 0, np.inf + ) + + def test_nan_step(self): + assert_raises_regex( + ValueError, "cannot compute length", + np.arange, 0, 1, np.nan + ) + + def test_zero_step(self): + assert_raises(ZeroDivisionError, np.arange, 0, 10, 0) + assert_raises(ZeroDivisionError, np.arange, 0.0, 10.0, 0.0) + + # empty range + assert_raises(ZeroDivisionError, np.arange, 0, 0, 0) + assert_raises(ZeroDivisionError, np.arange, 0.0, 0.0, 0.0) + + +def test_orderconverter_with_nonASCII_unicode_ordering(): + # gh-7475 + a = np.arange(5) + assert_raises(ValueError, a.flatten, order=u'\xe2') + + +def test_equal_override(): + # gh-9153: ndarray.__eq__ uses special logic for structured arrays, which + # did not respect overrides with __array_priority__ or __array_ufunc__. + # The PR fixed this for __array_priority__ and __array_ufunc__ = None. + class MyAlwaysEqual(object): + def __eq__(self, other): + return "eq" + + def __ne__(self, other): + return "ne" + + class MyAlwaysEqualOld(MyAlwaysEqual): + __array_priority__ = 10000 + + class MyAlwaysEqualNew(MyAlwaysEqual): + __array_ufunc__ = None + + array = np.array([(0, 1), (2, 3)], dtype='i4,i4') + for my_always_equal_cls in MyAlwaysEqualOld, MyAlwaysEqualNew: + my_always_equal = my_always_equal_cls() + assert_equal(my_always_equal == array, 'eq') + assert_equal(array == my_always_equal, 'eq') + assert_equal(my_always_equal != array, 'ne') + assert_equal(array != my_always_equal, 'ne') + + +def test_npymath_complex(): + # Smoketest npymath functions + from numpy.core.multiarray_tests import ( + npy_cabs, npy_carg) + + funcs = {npy_cabs: np.absolute, + npy_carg: np.angle} + vals = (1, np.inf, -np.inf, np.nan) + types = (np.complex64, np.complex128, np.clongdouble) + + for fun, npfun in funcs.items(): + for x, y in itertools.product(vals, vals): + for t in types: + z = t(complex(x, y)) + got = fun(z) + expected = npfun(z) + assert_allclose(got, expected) + + +def test_npymath_real(): + # Smoketest npymath functions + from numpy.core.multiarray_tests import ( + npy_log10, npy_cosh, npy_sinh, npy_tan, npy_tanh) + + funcs = {npy_log10: np.log10, + npy_cosh: np.cosh, + npy_sinh: np.sinh, + npy_tan: np.tan, + npy_tanh: np.tanh} + vals = (1, np.inf, -np.inf, np.nan) + types = (np.float32, np.float64, np.longdouble) + + with np.errstate(all='ignore'): + for fun, npfun in funcs.items(): + for x, t in itertools.product(vals, types): + z = t(x) + got = fun(z) + expected = npfun(z) + assert_allclose(got, expected) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_nditer.py b/numpy/core/tests/test_nditer.py new file mode 100644 index 0000000..f3f8706 --- /dev/null +++ b/numpy/core/tests/test_nditer.py @@ -0,0 +1,2715 @@ +from __future__ import division, absolute_import, print_function + +import sys +import warnings + +import numpy as np +from numpy import array, arange, nditer, all +from numpy.core.multiarray_tests import test_nditer_too_large +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal, + assert_raises, assert_warns, dec, HAS_REFCOUNT, suppress_warnings + ) + + +def iter_multi_index(i): + ret = [] + while not i.finished: + ret.append(i.multi_index) + i.iternext() + return ret + +def iter_indices(i): + ret = [] + while not i.finished: + ret.append(i.index) + i.iternext() + return ret + +def iter_iterindices(i): + ret = [] + while not i.finished: + ret.append(i.iterindex) + i.iternext() + return ret + +@dec.skipif(not HAS_REFCOUNT, "python does not have sys.getrefcount") +def test_iter_refcount(): + # Make sure the iterator doesn't leak + + # Basic + a = arange(6) + dt = np.dtype('f4').newbyteorder() + rc_a = sys.getrefcount(a) + rc_dt = sys.getrefcount(dt) + it = nditer(a, [], + [['readwrite', 'updateifcopy']], + casting='unsafe', + op_dtypes=[dt]) + assert_(not it.iterationneedsapi) + assert_(sys.getrefcount(a) > rc_a) + assert_(sys.getrefcount(dt) > rc_dt) + it = None + assert_equal(sys.getrefcount(a), rc_a) + assert_equal(sys.getrefcount(dt), rc_dt) + + # With a copy + a = arange(6, dtype='f4') + dt = np.dtype('f4') + rc_a = sys.getrefcount(a) + rc_dt = sys.getrefcount(dt) + it = nditer(a, [], + [['readwrite']], + op_dtypes=[dt]) + rc2_a = sys.getrefcount(a) + rc2_dt = sys.getrefcount(dt) + it2 = it.copy() + assert_(sys.getrefcount(a) > rc2_a) + assert_(sys.getrefcount(dt) > rc2_dt) + it = None + assert_equal(sys.getrefcount(a), rc2_a) + assert_equal(sys.getrefcount(dt), rc2_dt) + it2 = None + assert_equal(sys.getrefcount(a), rc_a) + assert_equal(sys.getrefcount(dt), rc_dt) + + del it2 # avoid pyflakes unused variable warning + +def test_iter_best_order(): + # The iterator should always find the iteration order + # with increasing memory addresses + + # Test the ordering for 1-D to 5-D shapes + for shape in [(5,), (3, 4), (2, 3, 4), (2, 3, 4, 3), (2, 3, 2, 2, 3)]: + a = arange(np.prod(shape)) + # Test each combination of positive and negative strides + for dirs in range(2**len(shape)): + dirs_index = [slice(None)]*len(shape) + for bit in range(len(shape)): + if ((2**bit) & dirs): + dirs_index[bit] = slice(None, None, -1) + dirs_index = tuple(dirs_index) + + aview = a.reshape(shape)[dirs_index] + # C-order + i = nditer(aview, [], [['readonly']]) + assert_equal([x for x in i], a) + # Fortran-order + i = nditer(aview.T, [], [['readonly']]) + assert_equal([x for x in i], a) + # Other order + if len(shape) > 2: + i = nditer(aview.swapaxes(0, 1), [], [['readonly']]) + assert_equal([x for x in i], a) + +def test_iter_c_order(): + # Test forcing C order + + # Test the ordering for 1-D to 5-D shapes + for shape in [(5,), (3, 4), (2, 3, 4), (2, 3, 4, 3), (2, 3, 2, 2, 3)]: + a = arange(np.prod(shape)) + # Test each combination of positive and negative strides + for dirs in range(2**len(shape)): + dirs_index = [slice(None)]*len(shape) + for bit in range(len(shape)): + if ((2**bit) & dirs): + dirs_index[bit] = slice(None, None, -1) + dirs_index = tuple(dirs_index) + + aview = a.reshape(shape)[dirs_index] + # C-order + i = nditer(aview, order='C') + assert_equal([x for x in i], aview.ravel(order='C')) + # Fortran-order + i = nditer(aview.T, order='C') + assert_equal([x for x in i], aview.T.ravel(order='C')) + # Other order + if len(shape) > 2: + i = nditer(aview.swapaxes(0, 1), order='C') + assert_equal([x for x in i], + aview.swapaxes(0, 1).ravel(order='C')) + +def test_iter_f_order(): + # Test forcing F order + + # Test the ordering for 1-D to 5-D shapes + for shape in [(5,), (3, 4), (2, 3, 4), (2, 3, 4, 3), (2, 3, 2, 2, 3)]: + a = arange(np.prod(shape)) + # Test each combination of positive and negative strides + for dirs in range(2**len(shape)): + dirs_index = [slice(None)]*len(shape) + for bit in range(len(shape)): + if ((2**bit) & dirs): + dirs_index[bit] = slice(None, None, -1) + dirs_index = tuple(dirs_index) + + aview = a.reshape(shape)[dirs_index] + # C-order + i = nditer(aview, order='F') + assert_equal([x for x in i], aview.ravel(order='F')) + # Fortran-order + i = nditer(aview.T, order='F') + assert_equal([x for x in i], aview.T.ravel(order='F')) + # Other order + if len(shape) > 2: + i = nditer(aview.swapaxes(0, 1), order='F') + assert_equal([x for x in i], + aview.swapaxes(0, 1).ravel(order='F')) + +def test_iter_c_or_f_order(): + # Test forcing any contiguous (C or F) order + + # Test the ordering for 1-D to 5-D shapes + for shape in [(5,), (3, 4), (2, 3, 4), (2, 3, 4, 3), (2, 3, 2, 2, 3)]: + a = arange(np.prod(shape)) + # Test each combination of positive and negative strides + for dirs in range(2**len(shape)): + dirs_index = [slice(None)]*len(shape) + for bit in range(len(shape)): + if ((2**bit) & dirs): + dirs_index[bit] = slice(None, None, -1) + dirs_index = tuple(dirs_index) + + aview = a.reshape(shape)[dirs_index] + # C-order + i = nditer(aview, order='A') + assert_equal([x for x in i], aview.ravel(order='A')) + # Fortran-order + i = nditer(aview.T, order='A') + assert_equal([x for x in i], aview.T.ravel(order='A')) + # Other order + if len(shape) > 2: + i = nditer(aview.swapaxes(0, 1), order='A') + assert_equal([x for x in i], + aview.swapaxes(0, 1).ravel(order='A')) + +def test_iter_best_order_multi_index_1d(): + # The multi-indices should be correct with any reordering + + a = arange(4) + # 1D order + i = nditer(a, ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(0,), (1,), (2,), (3,)]) + # 1D reversed order + i = nditer(a[::-1], ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(3,), (2,), (1,), (0,)]) + +def test_iter_best_order_multi_index_2d(): + # The multi-indices should be correct with any reordering + + a = arange(6) + # 2D C-order + i = nditer(a.reshape(2, 3), ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]) + # 2D Fortran-order + i = nditer(a.reshape(2, 3).copy(order='F'), ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(0, 0), (1, 0), (0, 1), (1, 1), (0, 2), (1, 2)]) + # 2D reversed C-order + i = nditer(a.reshape(2, 3)[::-1], ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(1, 0), (1, 1), (1, 2), (0, 0), (0, 1), (0, 2)]) + i = nditer(a.reshape(2, 3)[:, ::-1], ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(0, 2), (0, 1), (0, 0), (1, 2), (1, 1), (1, 0)]) + i = nditer(a.reshape(2, 3)[::-1, ::-1], ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(1, 2), (1, 1), (1, 0), (0, 2), (0, 1), (0, 0)]) + # 2D reversed Fortran-order + i = nditer(a.reshape(2, 3).copy(order='F')[::-1], ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(1, 0), (0, 0), (1, 1), (0, 1), (1, 2), (0, 2)]) + i = nditer(a.reshape(2, 3).copy(order='F')[:, ::-1], + ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(0, 2), (1, 2), (0, 1), (1, 1), (0, 0), (1, 0)]) + i = nditer(a.reshape(2, 3).copy(order='F')[::-1, ::-1], + ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), [(1, 2), (0, 2), (1, 1), (0, 1), (1, 0), (0, 0)]) + +def test_iter_best_order_multi_index_3d(): + # The multi-indices should be correct with any reordering + + a = arange(12) + # 3D C-order + i = nditer(a.reshape(2, 3, 2), ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), + [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (0, 2, 0), (0, 2, 1), + (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (1, 2, 0), (1, 2, 1)]) + # 3D Fortran-order + i = nditer(a.reshape(2, 3, 2).copy(order='F'), ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), + [(0, 0, 0), (1, 0, 0), (0, 1, 0), (1, 1, 0), (0, 2, 0), (1, 2, 0), + (0, 0, 1), (1, 0, 1), (0, 1, 1), (1, 1, 1), (0, 2, 1), (1, 2, 1)]) + # 3D reversed C-order + i = nditer(a.reshape(2, 3, 2)[::-1], ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), + [(1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (1, 2, 0), (1, 2, 1), + (0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (0, 2, 0), (0, 2, 1)]) + i = nditer(a.reshape(2, 3, 2)[:, ::-1], ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), + [(0, 2, 0), (0, 2, 1), (0, 1, 0), (0, 1, 1), (0, 0, 0), (0, 0, 1), + (1, 2, 0), (1, 2, 1), (1, 1, 0), (1, 1, 1), (1, 0, 0), (1, 0, 1)]) + i = nditer(a.reshape(2, 3, 2)[:,:, ::-1], ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), + [(0, 0, 1), (0, 0, 0), (0, 1, 1), (0, 1, 0), (0, 2, 1), (0, 2, 0), + (1, 0, 1), (1, 0, 0), (1, 1, 1), (1, 1, 0), (1, 2, 1), (1, 2, 0)]) + # 3D reversed Fortran-order + i = nditer(a.reshape(2, 3, 2).copy(order='F')[::-1], + ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), + [(1, 0, 0), (0, 0, 0), (1, 1, 0), (0, 1, 0), (1, 2, 0), (0, 2, 0), + (1, 0, 1), (0, 0, 1), (1, 1, 1), (0, 1, 1), (1, 2, 1), (0, 2, 1)]) + i = nditer(a.reshape(2, 3, 2).copy(order='F')[:, ::-1], + ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), + [(0, 2, 0), (1, 2, 0), (0, 1, 0), (1, 1, 0), (0, 0, 0), (1, 0, 0), + (0, 2, 1), (1, 2, 1), (0, 1, 1), (1, 1, 1), (0, 0, 1), (1, 0, 1)]) + i = nditer(a.reshape(2, 3, 2).copy(order='F')[:,:, ::-1], + ['multi_index'], [['readonly']]) + assert_equal(iter_multi_index(i), + [(0, 0, 1), (1, 0, 1), (0, 1, 1), (1, 1, 1), (0, 2, 1), (1, 2, 1), + (0, 0, 0), (1, 0, 0), (0, 1, 0), (1, 1, 0), (0, 2, 0), (1, 2, 0)]) + +def test_iter_best_order_c_index_1d(): + # The C index should be correct with any reordering + + a = arange(4) + # 1D order + i = nditer(a, ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [0, 1, 2, 3]) + # 1D reversed order + i = nditer(a[::-1], ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [3, 2, 1, 0]) + +def test_iter_best_order_c_index_2d(): + # The C index should be correct with any reordering + + a = arange(6) + # 2D C-order + i = nditer(a.reshape(2, 3), ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [0, 1, 2, 3, 4, 5]) + # 2D Fortran-order + i = nditer(a.reshape(2, 3).copy(order='F'), + ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [0, 3, 1, 4, 2, 5]) + # 2D reversed C-order + i = nditer(a.reshape(2, 3)[::-1], ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [3, 4, 5, 0, 1, 2]) + i = nditer(a.reshape(2, 3)[:, ::-1], ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [2, 1, 0, 5, 4, 3]) + i = nditer(a.reshape(2, 3)[::-1, ::-1], ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [5, 4, 3, 2, 1, 0]) + # 2D reversed Fortran-order + i = nditer(a.reshape(2, 3).copy(order='F')[::-1], + ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [3, 0, 4, 1, 5, 2]) + i = nditer(a.reshape(2, 3).copy(order='F')[:, ::-1], + ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [2, 5, 1, 4, 0, 3]) + i = nditer(a.reshape(2, 3).copy(order='F')[::-1, ::-1], + ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), [5, 2, 4, 1, 3, 0]) + +def test_iter_best_order_c_index_3d(): + # The C index should be correct with any reordering + + a = arange(12) + # 3D C-order + i = nditer(a.reshape(2, 3, 2), ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) + # 3D Fortran-order + i = nditer(a.reshape(2, 3, 2).copy(order='F'), + ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), + [0, 6, 2, 8, 4, 10, 1, 7, 3, 9, 5, 11]) + # 3D reversed C-order + i = nditer(a.reshape(2, 3, 2)[::-1], ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), + [6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5]) + i = nditer(a.reshape(2, 3, 2)[:, ::-1], ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), + [4, 5, 2, 3, 0, 1, 10, 11, 8, 9, 6, 7]) + i = nditer(a.reshape(2, 3, 2)[:,:, ::-1], ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), + [1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10]) + # 3D reversed Fortran-order + i = nditer(a.reshape(2, 3, 2).copy(order='F')[::-1], + ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), + [6, 0, 8, 2, 10, 4, 7, 1, 9, 3, 11, 5]) + i = nditer(a.reshape(2, 3, 2).copy(order='F')[:, ::-1], + ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), + [4, 10, 2, 8, 0, 6, 5, 11, 3, 9, 1, 7]) + i = nditer(a.reshape(2, 3, 2).copy(order='F')[:,:, ::-1], + ['c_index'], [['readonly']]) + assert_equal(iter_indices(i), + [1, 7, 3, 9, 5, 11, 0, 6, 2, 8, 4, 10]) + +def test_iter_best_order_f_index_1d(): + # The Fortran index should be correct with any reordering + + a = arange(4) + # 1D order + i = nditer(a, ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [0, 1, 2, 3]) + # 1D reversed order + i = nditer(a[::-1], ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [3, 2, 1, 0]) + +def test_iter_best_order_f_index_2d(): + # The Fortran index should be correct with any reordering + + a = arange(6) + # 2D C-order + i = nditer(a.reshape(2, 3), ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [0, 2, 4, 1, 3, 5]) + # 2D Fortran-order + i = nditer(a.reshape(2, 3).copy(order='F'), + ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [0, 1, 2, 3, 4, 5]) + # 2D reversed C-order + i = nditer(a.reshape(2, 3)[::-1], ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [1, 3, 5, 0, 2, 4]) + i = nditer(a.reshape(2, 3)[:, ::-1], ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [4, 2, 0, 5, 3, 1]) + i = nditer(a.reshape(2, 3)[::-1, ::-1], ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [5, 3, 1, 4, 2, 0]) + # 2D reversed Fortran-order + i = nditer(a.reshape(2, 3).copy(order='F')[::-1], + ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [1, 0, 3, 2, 5, 4]) + i = nditer(a.reshape(2, 3).copy(order='F')[:, ::-1], + ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [4, 5, 2, 3, 0, 1]) + i = nditer(a.reshape(2, 3).copy(order='F')[::-1, ::-1], + ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), [5, 4, 3, 2, 1, 0]) + +def test_iter_best_order_f_index_3d(): + # The Fortran index should be correct with any reordering + + a = arange(12) + # 3D C-order + i = nditer(a.reshape(2, 3, 2), ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), + [0, 6, 2, 8, 4, 10, 1, 7, 3, 9, 5, 11]) + # 3D Fortran-order + i = nditer(a.reshape(2, 3, 2).copy(order='F'), + ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) + # 3D reversed C-order + i = nditer(a.reshape(2, 3, 2)[::-1], ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), + [1, 7, 3, 9, 5, 11, 0, 6, 2, 8, 4, 10]) + i = nditer(a.reshape(2, 3, 2)[:, ::-1], ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), + [4, 10, 2, 8, 0, 6, 5, 11, 3, 9, 1, 7]) + i = nditer(a.reshape(2, 3, 2)[:,:, ::-1], ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), + [6, 0, 8, 2, 10, 4, 7, 1, 9, 3, 11, 5]) + # 3D reversed Fortran-order + i = nditer(a.reshape(2, 3, 2).copy(order='F')[::-1], + ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), + [1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10]) + i = nditer(a.reshape(2, 3, 2).copy(order='F')[:, ::-1], + ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), + [4, 5, 2, 3, 0, 1, 10, 11, 8, 9, 6, 7]) + i = nditer(a.reshape(2, 3, 2).copy(order='F')[:,:, ::-1], + ['f_index'], [['readonly']]) + assert_equal(iter_indices(i), + [6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5]) + +def test_iter_no_inner_full_coalesce(): + # Check no_inner iterators which coalesce into a single inner loop + + for shape in [(5,), (3, 4), (2, 3, 4), (2, 3, 4, 3), (2, 3, 2, 2, 3)]: + size = np.prod(shape) + a = arange(size) + # Test each combination of forward and backwards indexing + for dirs in range(2**len(shape)): + dirs_index = [slice(None)]*len(shape) + for bit in range(len(shape)): + if ((2**bit) & dirs): + dirs_index[bit] = slice(None, None, -1) + dirs_index = tuple(dirs_index) + + aview = a.reshape(shape)[dirs_index] + # C-order + i = nditer(aview, ['external_loop'], [['readonly']]) + assert_equal(i.ndim, 1) + assert_equal(i[0].shape, (size,)) + # Fortran-order + i = nditer(aview.T, ['external_loop'], [['readonly']]) + assert_equal(i.ndim, 1) + assert_equal(i[0].shape, (size,)) + # Other order + if len(shape) > 2: + i = nditer(aview.swapaxes(0, 1), + ['external_loop'], [['readonly']]) + assert_equal(i.ndim, 1) + assert_equal(i[0].shape, (size,)) + +def test_iter_no_inner_dim_coalescing(): + # Check no_inner iterators whose dimensions may not coalesce completely + + # Skipping the last element in a dimension prevents coalescing + # with the next-bigger dimension + a = arange(24).reshape(2, 3, 4)[:,:, :-1] + i = nditer(a, ['external_loop'], [['readonly']]) + assert_equal(i.ndim, 2) + assert_equal(i[0].shape, (3,)) + a = arange(24).reshape(2, 3, 4)[:, :-1,:] + i = nditer(a, ['external_loop'], [['readonly']]) + assert_equal(i.ndim, 2) + assert_equal(i[0].shape, (8,)) + a = arange(24).reshape(2, 3, 4)[:-1,:,:] + i = nditer(a, ['external_loop'], [['readonly']]) + assert_equal(i.ndim, 1) + assert_equal(i[0].shape, (12,)) + + # Even with lots of 1-sized dimensions, should still coalesce + a = arange(24).reshape(1, 1, 2, 1, 1, 3, 1, 1, 4, 1, 1) + i = nditer(a, ['external_loop'], [['readonly']]) + assert_equal(i.ndim, 1) + assert_equal(i[0].shape, (24,)) + +def test_iter_dim_coalescing(): + # Check that the correct number of dimensions are coalesced + + # Tracking a multi-index disables coalescing + a = arange(24).reshape(2, 3, 4) + i = nditer(a, ['multi_index'], [['readonly']]) + assert_equal(i.ndim, 3) + + # A tracked index can allow coalescing if it's compatible with the array + a3d = arange(24).reshape(2, 3, 4) + i = nditer(a3d, ['c_index'], [['readonly']]) + assert_equal(i.ndim, 1) + i = nditer(a3d.swapaxes(0, 1), ['c_index'], [['readonly']]) + assert_equal(i.ndim, 3) + i = nditer(a3d.T, ['c_index'], [['readonly']]) + assert_equal(i.ndim, 3) + i = nditer(a3d.T, ['f_index'], [['readonly']]) + assert_equal(i.ndim, 1) + i = nditer(a3d.T.swapaxes(0, 1), ['f_index'], [['readonly']]) + assert_equal(i.ndim, 3) + + # When C or F order is forced, coalescing may still occur + a3d = arange(24).reshape(2, 3, 4) + i = nditer(a3d, order='C') + assert_equal(i.ndim, 1) + i = nditer(a3d.T, order='C') + assert_equal(i.ndim, 3) + i = nditer(a3d, order='F') + assert_equal(i.ndim, 3) + i = nditer(a3d.T, order='F') + assert_equal(i.ndim, 1) + i = nditer(a3d, order='A') + assert_equal(i.ndim, 1) + i = nditer(a3d.T, order='A') + assert_equal(i.ndim, 1) + +def test_iter_broadcasting(): + # Standard NumPy broadcasting rules + + # 1D with scalar + i = nditer([arange(6), np.int32(2)], ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 6) + assert_equal(i.shape, (6,)) + + # 2D with scalar + i = nditer([arange(6).reshape(2, 3), np.int32(2)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 6) + assert_equal(i.shape, (2, 3)) + # 2D with 1D + i = nditer([arange(6).reshape(2, 3), arange(3)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 6) + assert_equal(i.shape, (2, 3)) + i = nditer([arange(2).reshape(2, 1), arange(3)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 6) + assert_equal(i.shape, (2, 3)) + # 2D with 2D + i = nditer([arange(2).reshape(2, 1), arange(3).reshape(1, 3)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 6) + assert_equal(i.shape, (2, 3)) + + # 3D with scalar + i = nditer([np.int32(2), arange(24).reshape(4, 2, 3)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + # 3D with 1D + i = nditer([arange(3), arange(24).reshape(4, 2, 3)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + i = nditer([arange(3), arange(8).reshape(4, 2, 1)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + # 3D with 2D + i = nditer([arange(6).reshape(2, 3), arange(24).reshape(4, 2, 3)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + i = nditer([arange(2).reshape(2, 1), arange(24).reshape(4, 2, 3)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + i = nditer([arange(3).reshape(1, 3), arange(8).reshape(4, 2, 1)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + # 3D with 3D + i = nditer([arange(2).reshape(1, 2, 1), arange(3).reshape(1, 1, 3), + arange(4).reshape(4, 1, 1)], + ['multi_index'], [['readonly']]*3) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + i = nditer([arange(6).reshape(1, 2, 3), arange(4).reshape(4, 1, 1)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + i = nditer([arange(24).reshape(4, 2, 3), arange(12).reshape(4, 1, 3)], + ['multi_index'], [['readonly']]*2) + assert_equal(i.itersize, 24) + assert_equal(i.shape, (4, 2, 3)) + +def test_iter_itershape(): + # Check that allocated outputs work with a specified shape + a = np.arange(6, dtype='i2').reshape(2, 3) + i = nditer([a, None], [], [['readonly'], ['writeonly', 'allocate']], + op_axes=[[0, 1, None], None], + itershape=(-1, -1, 4)) + assert_equal(i.operands[1].shape, (2, 3, 4)) + assert_equal(i.operands[1].strides, (24, 8, 2)) + + i = nditer([a.T, None], [], [['readonly'], ['writeonly', 'allocate']], + op_axes=[[0, 1, None], None], + itershape=(-1, -1, 4)) + assert_equal(i.operands[1].shape, (3, 2, 4)) + assert_equal(i.operands[1].strides, (8, 24, 2)) + + i = nditer([a.T, None], [], [['readonly'], ['writeonly', 'allocate']], + order='F', + op_axes=[[0, 1, None], None], + itershape=(-1, -1, 4)) + assert_equal(i.operands[1].shape, (3, 2, 4)) + assert_equal(i.operands[1].strides, (2, 6, 12)) + + # If we specify 1 in the itershape, it shouldn't allow broadcasting + # of that dimension to a bigger value + assert_raises(ValueError, nditer, [a, None], [], + [['readonly'], ['writeonly', 'allocate']], + op_axes=[[0, 1, None], None], + itershape=(-1, 1, 4)) + # Test bug that for no op_axes but itershape, they are NULLed correctly + i = np.nditer([np.ones(2), None, None], itershape=(2,)) + +def test_iter_broadcasting_errors(): + # Check that errors are thrown for bad broadcasting shapes + + # 1D with 1D + assert_raises(ValueError, nditer, [arange(2), arange(3)], + [], [['readonly']]*2) + # 2D with 1D + assert_raises(ValueError, nditer, + [arange(6).reshape(2, 3), arange(2)], + [], [['readonly']]*2) + # 2D with 2D + assert_raises(ValueError, nditer, + [arange(6).reshape(2, 3), arange(9).reshape(3, 3)], + [], [['readonly']]*2) + assert_raises(ValueError, nditer, + [arange(6).reshape(2, 3), arange(4).reshape(2, 2)], + [], [['readonly']]*2) + # 3D with 3D + assert_raises(ValueError, nditer, + [arange(36).reshape(3, 3, 4), arange(24).reshape(2, 3, 4)], + [], [['readonly']]*2) + assert_raises(ValueError, nditer, + [arange(8).reshape(2, 4, 1), arange(24).reshape(2, 3, 4)], + [], [['readonly']]*2) + + # Verify that the error message mentions the right shapes + try: + nditer([arange(2).reshape(1, 2, 1), + arange(3).reshape(1, 3), + arange(6).reshape(2, 3)], + [], + [['readonly'], ['readonly'], ['writeonly', 'no_broadcast']]) + raise AssertionError('Should have raised a broadcast error') + except ValueError as e: + msg = str(e) + # The message should contain the shape of the 3rd operand + assert_(msg.find('(2,3)') >= 0, + 'Message "%s" doesn\'t contain operand shape (2,3)' % msg) + # The message should contain the broadcast shape + assert_(msg.find('(1,2,3)') >= 0, + 'Message "%s" doesn\'t contain broadcast shape (1,2,3)' % msg) + + try: + nditer([arange(6).reshape(2, 3), arange(2)], + [], + [['readonly'], ['readonly']], + op_axes=[[0, 1], [0, np.newaxis]], + itershape=(4, 3)) + raise AssertionError('Should have raised a broadcast error') + except ValueError as e: + msg = str(e) + # The message should contain "shape->remappedshape" for each operand + assert_(msg.find('(2,3)->(2,3)') >= 0, + 'Message "%s" doesn\'t contain operand shape (2,3)->(2,3)' % msg) + assert_(msg.find('(2,)->(2,newaxis)') >= 0, + ('Message "%s" doesn\'t contain remapped operand shape' + + '(2,)->(2,newaxis)') % msg) + # The message should contain the itershape parameter + assert_(msg.find('(4,3)') >= 0, + 'Message "%s" doesn\'t contain itershape parameter (4,3)' % msg) + + try: + nditer([np.zeros((2, 1, 1)), np.zeros((2,))], + [], + [['writeonly', 'no_broadcast'], ['readonly']]) + raise AssertionError('Should have raised a broadcast error') + except ValueError as e: + msg = str(e) + # The message should contain the shape of the bad operand + assert_(msg.find('(2,1,1)') >= 0, + 'Message "%s" doesn\'t contain operand shape (2,1,1)' % msg) + # The message should contain the broadcast shape + assert_(msg.find('(2,1,2)') >= 0, + 'Message "%s" doesn\'t contain the broadcast shape (2,1,2)' % msg) + +def test_iter_flags_errors(): + # Check that bad combinations of flags produce errors + + a = arange(6) + + # Not enough operands + assert_raises(ValueError, nditer, [], [], []) + # Too many operands + assert_raises(ValueError, nditer, [a]*100, [], [['readonly']]*100) + # Bad global flag + assert_raises(ValueError, nditer, [a], ['bad flag'], [['readonly']]) + # Bad op flag + assert_raises(ValueError, nditer, [a], [], [['readonly', 'bad flag']]) + # Bad order parameter + assert_raises(ValueError, nditer, [a], [], [['readonly']], order='G') + # Bad casting parameter + assert_raises(ValueError, nditer, [a], [], [['readonly']], casting='noon') + # op_flags must match ops + assert_raises(ValueError, nditer, [a]*3, [], [['readonly']]*2) + # Cannot track both a C and an F index + assert_raises(ValueError, nditer, a, + ['c_index', 'f_index'], [['readonly']]) + # Inner iteration and multi-indices/indices are incompatible + assert_raises(ValueError, nditer, a, + ['external_loop', 'multi_index'], [['readonly']]) + assert_raises(ValueError, nditer, a, + ['external_loop', 'c_index'], [['readonly']]) + assert_raises(ValueError, nditer, a, + ['external_loop', 'f_index'], [['readonly']]) + # Must specify exactly one of readwrite/readonly/writeonly per operand + assert_raises(ValueError, nditer, a, [], [[]]) + assert_raises(ValueError, nditer, a, [], [['readonly', 'writeonly']]) + assert_raises(ValueError, nditer, a, [], [['readonly', 'readwrite']]) + assert_raises(ValueError, nditer, a, [], [['writeonly', 'readwrite']]) + assert_raises(ValueError, nditer, a, + [], [['readonly', 'writeonly', 'readwrite']]) + # Python scalars are always readonly + assert_raises(TypeError, nditer, 1.5, [], [['writeonly']]) + assert_raises(TypeError, nditer, 1.5, [], [['readwrite']]) + # Array scalars are always readonly + assert_raises(TypeError, nditer, np.int32(1), [], [['writeonly']]) + assert_raises(TypeError, nditer, np.int32(1), [], [['readwrite']]) + # Check readonly array + a.flags.writeable = False + assert_raises(ValueError, nditer, a, [], [['writeonly']]) + assert_raises(ValueError, nditer, a, [], [['readwrite']]) + a.flags.writeable = True + # Multi-indices available only with the multi_index flag + i = nditer(arange(6), [], [['readonly']]) + assert_raises(ValueError, lambda i:i.multi_index, i) + # Index available only with an index flag + assert_raises(ValueError, lambda i:i.index, i) + # GotoCoords and GotoIndex incompatible with buffering or no_inner + + def assign_multi_index(i): + i.multi_index = (0,) + + def assign_index(i): + i.index = 0 + + def assign_iterindex(i): + i.iterindex = 0 + + def assign_iterrange(i): + i.iterrange = (0, 1) + i = nditer(arange(6), ['external_loop']) + assert_raises(ValueError, assign_multi_index, i) + assert_raises(ValueError, assign_index, i) + assert_raises(ValueError, assign_iterindex, i) + assert_raises(ValueError, assign_iterrange, i) + i = nditer(arange(6), ['buffered']) + assert_raises(ValueError, assign_multi_index, i) + assert_raises(ValueError, assign_index, i) + assert_raises(ValueError, assign_iterrange, i) + # Can't iterate if size is zero + assert_raises(ValueError, nditer, np.array([])) + +def test_iter_slice(): + a, b, c = np.arange(3), np.arange(3), np.arange(3.) + i = nditer([a, b, c], [], ['readwrite']) + i[0:2] = (3, 3) + assert_equal(a, [3, 1, 2]) + assert_equal(b, [3, 1, 2]) + assert_equal(c, [0, 1, 2]) + i[1] = 12 + assert_equal(i[0:2], [3, 12]) + +def test_iter_nbo_align_contig(): + # Check that byte order, alignment, and contig changes work + + # Byte order change by requesting a specific dtype + a = np.arange(6, dtype='f4') + au = a.byteswap().newbyteorder() + assert_(a.dtype.byteorder != au.dtype.byteorder) + i = nditer(au, [], [['readwrite', 'updateifcopy']], + casting='equiv', + op_dtypes=[np.dtype('f4')]) + assert_equal(i.dtypes[0].byteorder, a.dtype.byteorder) + assert_equal(i.operands[0].dtype.byteorder, a.dtype.byteorder) + assert_equal(i.operands[0], a) + i.operands[0][:] = 2 + i = None + assert_equal(au, [2]*6) + + # Byte order change by requesting NBO + a = np.arange(6, dtype='f4') + au = a.byteswap().newbyteorder() + assert_(a.dtype.byteorder != au.dtype.byteorder) + i = nditer(au, [], [['readwrite', 'updateifcopy', 'nbo']], casting='equiv') + assert_equal(i.dtypes[0].byteorder, a.dtype.byteorder) + assert_equal(i.operands[0].dtype.byteorder, a.dtype.byteorder) + assert_equal(i.operands[0], a) + i.operands[0][:] = 2 + i = None + assert_equal(au, [2]*6) + + # Unaligned input + a = np.zeros((6*4+1,), dtype='i1')[1:] + a.dtype = 'f4' + a[:] = np.arange(6, dtype='f4') + assert_(not a.flags.aligned) + # Without 'aligned', shouldn't copy + i = nditer(a, [], [['readonly']]) + assert_(not i.operands[0].flags.aligned) + assert_equal(i.operands[0], a) + # With 'aligned', should make a copy + i = nditer(a, [], [['readwrite', 'updateifcopy', 'aligned']]) + assert_(i.operands[0].flags.aligned) + assert_equal(i.operands[0], a) + i.operands[0][:] = 3 + i = None + assert_equal(a, [3]*6) + + # Discontiguous input + a = arange(12) + # If it is contiguous, shouldn't copy + i = nditer(a[:6], [], [['readonly']]) + assert_(i.operands[0].flags.contiguous) + assert_equal(i.operands[0], a[:6]) + # If it isn't contiguous, should buffer + i = nditer(a[::2], ['buffered', 'external_loop'], + [['readonly', 'contig']], + buffersize=10) + assert_(i[0].flags.contiguous) + assert_equal(i[0], a[::2]) + +def test_iter_array_cast(): + # Check that arrays are cast as requested + + # No cast 'f4' -> 'f4' + a = np.arange(6, dtype='f4').reshape(2, 3) + i = nditer(a, [], [['readwrite']], op_dtypes=[np.dtype('f4')]) + assert_equal(i.operands[0], a) + assert_equal(i.operands[0].dtype, np.dtype('f4')) + + # Byte-order cast ' '>f4' + a = np.arange(6, dtype='f4')]) + assert_equal(i.operands[0], a) + assert_equal(i.operands[0].dtype, np.dtype('>f4')) + + # Safe case 'f4' -> 'f8' + a = np.arange(24, dtype='f4').reshape(2, 3, 4).swapaxes(1, 2) + i = nditer(a, [], [['readonly', 'copy']], + casting='safe', + op_dtypes=[np.dtype('f8')]) + assert_equal(i.operands[0], a) + assert_equal(i.operands[0].dtype, np.dtype('f8')) + # The memory layout of the temporary should match a (a is (48,4,16)) + # except negative strides get flipped to positive strides. + assert_equal(i.operands[0].strides, (96, 8, 32)) + a = a[::-1,:, ::-1] + i = nditer(a, [], [['readonly', 'copy']], + casting='safe', + op_dtypes=[np.dtype('f8')]) + assert_equal(i.operands[0], a) + assert_equal(i.operands[0].dtype, np.dtype('f8')) + assert_equal(i.operands[0].strides, (96, 8, 32)) + + # Same-kind cast 'f8' -> 'f4' -> 'f8' + a = np.arange(24, dtype='f8').reshape(2, 3, 4).T + i = nditer(a, [], + [['readwrite', 'updateifcopy']], + casting='same_kind', + op_dtypes=[np.dtype('f4')]) + assert_equal(i.operands[0], a) + assert_equal(i.operands[0].dtype, np.dtype('f4')) + assert_equal(i.operands[0].strides, (4, 16, 48)) + # Check that UPDATEIFCOPY is activated + i.operands[0][2, 1, 1] = -12.5 + assert_(a[2, 1, 1] != -12.5) + i = None + assert_equal(a[2, 1, 1], -12.5) + + a = np.arange(6, dtype='i4')[::-2] + i = nditer(a, [], + [['writeonly', 'updateifcopy']], + casting='unsafe', + op_dtypes=[np.dtype('f4')]) + assert_equal(i.operands[0].dtype, np.dtype('f4')) + # Even though the stride was negative in 'a', it + # becomes positive in the temporary + assert_equal(i.operands[0].strides, (4,)) + i.operands[0][:] = [1, 2, 3] + i = None + assert_equal(a, [1, 2, 3]) + +def test_iter_array_cast_errors(): + # Check that invalid casts are caught + + # Need to enable copying for casts to occur + assert_raises(TypeError, nditer, arange(2, dtype='f4'), [], + [['readonly']], op_dtypes=[np.dtype('f8')]) + # Also need to allow casting for casts to occur + assert_raises(TypeError, nditer, arange(2, dtype='f4'), [], + [['readonly', 'copy']], casting='no', + op_dtypes=[np.dtype('f8')]) + assert_raises(TypeError, nditer, arange(2, dtype='f4'), [], + [['readonly', 'copy']], casting='equiv', + op_dtypes=[np.dtype('f8')]) + assert_raises(TypeError, nditer, arange(2, dtype='f8'), [], + [['writeonly', 'updateifcopy']], + casting='no', + op_dtypes=[np.dtype('f4')]) + assert_raises(TypeError, nditer, arange(2, dtype='f8'), [], + [['writeonly', 'updateifcopy']], + casting='equiv', + op_dtypes=[np.dtype('f4')]) + # ' '>f4' should not work with casting='no' + assert_raises(TypeError, nditer, arange(2, dtype='f4')]) + # 'f4' -> 'f8' is a safe cast, but 'f8' -> 'f4' isn't + assert_raises(TypeError, nditer, arange(2, dtype='f4'), [], + [['readwrite', 'updateifcopy']], + casting='safe', + op_dtypes=[np.dtype('f8')]) + assert_raises(TypeError, nditer, arange(2, dtype='f8'), [], + [['readwrite', 'updateifcopy']], + casting='safe', + op_dtypes=[np.dtype('f4')]) + # 'f4' -> 'i4' is neither a safe nor a same-kind cast + assert_raises(TypeError, nditer, arange(2, dtype='f4'), [], + [['readonly', 'copy']], + casting='same_kind', + op_dtypes=[np.dtype('i4')]) + assert_raises(TypeError, nditer, arange(2, dtype='i4'), [], + [['writeonly', 'updateifcopy']], + casting='same_kind', + op_dtypes=[np.dtype('f4')]) + +def test_iter_scalar_cast(): + # Check that scalars are cast as requested + + # No cast 'f4' -> 'f4' + i = nditer(np.float32(2.5), [], [['readonly']], + op_dtypes=[np.dtype('f4')]) + assert_equal(i.dtypes[0], np.dtype('f4')) + assert_equal(i.value.dtype, np.dtype('f4')) + assert_equal(i.value, 2.5) + # Safe cast 'f4' -> 'f8' + i = nditer(np.float32(2.5), [], + [['readonly', 'copy']], + casting='safe', + op_dtypes=[np.dtype('f8')]) + assert_equal(i.dtypes[0], np.dtype('f8')) + assert_equal(i.value.dtype, np.dtype('f8')) + assert_equal(i.value, 2.5) + # Same-kind cast 'f8' -> 'f4' + i = nditer(np.float64(2.5), [], + [['readonly', 'copy']], + casting='same_kind', + op_dtypes=[np.dtype('f4')]) + assert_equal(i.dtypes[0], np.dtype('f4')) + assert_equal(i.value.dtype, np.dtype('f4')) + assert_equal(i.value, 2.5) + # Unsafe cast 'f8' -> 'i4' + i = nditer(np.float64(3.0), [], + [['readonly', 'copy']], + casting='unsafe', + op_dtypes=[np.dtype('i4')]) + assert_equal(i.dtypes[0], np.dtype('i4')) + assert_equal(i.value.dtype, np.dtype('i4')) + assert_equal(i.value, 3) + # Readonly scalars may be cast even without setting COPY or BUFFERED + i = nditer(3, [], [['readonly']], op_dtypes=[np.dtype('f8')]) + assert_equal(i[0].dtype, np.dtype('f8')) + assert_equal(i[0], 3.) + +def test_iter_scalar_cast_errors(): + # Check that invalid casts are caught + + # Need to allow copying/buffering for write casts of scalars to occur + assert_raises(TypeError, nditer, np.float32(2), [], + [['readwrite']], op_dtypes=[np.dtype('f8')]) + assert_raises(TypeError, nditer, 2.5, [], + [['readwrite']], op_dtypes=[np.dtype('f4')]) + # 'f8' -> 'f4' isn't a safe cast if the value would overflow + assert_raises(TypeError, nditer, np.float64(1e60), [], + [['readonly']], + casting='safe', + op_dtypes=[np.dtype('f4')]) + # 'f4' -> 'i4' is neither a safe nor a same-kind cast + assert_raises(TypeError, nditer, np.float32(2), [], + [['readonly']], + casting='same_kind', + op_dtypes=[np.dtype('i4')]) + +def test_iter_object_arrays_basic(): + # Check that object arrays work + + obj = {'a':3,'b':'d'} + a = np.array([[1, 2, 3], None, obj, None], dtype='O') + if HAS_REFCOUNT: + rc = sys.getrefcount(obj) + + # Need to allow references for object arrays + assert_raises(TypeError, nditer, a) + if HAS_REFCOUNT: + assert_equal(sys.getrefcount(obj), rc) + + i = nditer(a, ['refs_ok'], ['readonly']) + vals = [x_[()] for x_ in i] + assert_equal(np.array(vals, dtype='O'), a) + vals, i, x = [None]*3 + if HAS_REFCOUNT: + assert_equal(sys.getrefcount(obj), rc) + + i = nditer(a.reshape(2, 2).T, ['refs_ok', 'buffered'], + ['readonly'], order='C') + assert_(i.iterationneedsapi) + vals = [x_[()] for x_ in i] + assert_equal(np.array(vals, dtype='O'), a.reshape(2, 2).ravel(order='F')) + vals, i, x = [None]*3 + if HAS_REFCOUNT: + assert_equal(sys.getrefcount(obj), rc) + + i = nditer(a.reshape(2, 2).T, ['refs_ok', 'buffered'], + ['readwrite'], order='C') + for x in i: + x[...] = None + vals, i, x = [None]*3 + if HAS_REFCOUNT: + assert_(sys.getrefcount(obj) == rc-1) + assert_equal(a, np.array([None]*4, dtype='O')) + +def test_iter_object_arrays_conversions(): + # Conversions to/from objects + a = np.arange(6, dtype='O') + i = nditer(a, ['refs_ok', 'buffered'], ['readwrite'], + casting='unsafe', op_dtypes='i4') + for x in i: + x[...] += 1 + assert_equal(a, np.arange(6)+1) + + a = np.arange(6, dtype='i4') + i = nditer(a, ['refs_ok', 'buffered'], ['readwrite'], + casting='unsafe', op_dtypes='O') + for x in i: + x[...] += 1 + assert_equal(a, np.arange(6)+1) + + # Non-contiguous object array + a = np.zeros((6,), dtype=[('p', 'i1'), ('a', 'O')]) + a = a['a'] + a[:] = np.arange(6) + i = nditer(a, ['refs_ok', 'buffered'], ['readwrite'], + casting='unsafe', op_dtypes='i4') + for x in i: + x[...] += 1 + assert_equal(a, np.arange(6)+1) + + #Non-contiguous value array + a = np.zeros((6,), dtype=[('p', 'i1'), ('a', 'i4')]) + a = a['a'] + a[:] = np.arange(6) + 98172488 + i = nditer(a, ['refs_ok', 'buffered'], ['readwrite'], + casting='unsafe', op_dtypes='O') + ob = i[0][()] + if HAS_REFCOUNT: + rc = sys.getrefcount(ob) + for x in i: + x[...] += 1 + if HAS_REFCOUNT: + assert_(sys.getrefcount(ob) == rc-1) + assert_equal(a, np.arange(6)+98172489) + +def test_iter_common_dtype(): + # Check that the iterator finds a common data type correctly + + i = nditer([array([3], dtype='f4'), array([0], dtype='f8')], + ['common_dtype'], + [['readonly', 'copy']]*2, + casting='safe') + assert_equal(i.dtypes[0], np.dtype('f8')) + assert_equal(i.dtypes[1], np.dtype('f8')) + i = nditer([array([3], dtype='i4'), array([0], dtype='f4')], + ['common_dtype'], + [['readonly', 'copy']]*2, + casting='safe') + assert_equal(i.dtypes[0], np.dtype('f8')) + assert_equal(i.dtypes[1], np.dtype('f8')) + i = nditer([array([3], dtype='f4'), array(0, dtype='f8')], + ['common_dtype'], + [['readonly', 'copy']]*2, + casting='same_kind') + assert_equal(i.dtypes[0], np.dtype('f4')) + assert_equal(i.dtypes[1], np.dtype('f4')) + i = nditer([array([3], dtype='u4'), array(0, dtype='i4')], + ['common_dtype'], + [['readonly', 'copy']]*2, + casting='safe') + assert_equal(i.dtypes[0], np.dtype('u4')) + assert_equal(i.dtypes[1], np.dtype('u4')) + i = nditer([array([3], dtype='u4'), array(-12, dtype='i4')], + ['common_dtype'], + [['readonly', 'copy']]*2, + casting='safe') + assert_equal(i.dtypes[0], np.dtype('i8')) + assert_equal(i.dtypes[1], np.dtype('i8')) + i = nditer([array([3], dtype='u4'), array(-12, dtype='i4'), + array([2j], dtype='c8'), array([9], dtype='f8')], + ['common_dtype'], + [['readonly', 'copy']]*4, + casting='safe') + assert_equal(i.dtypes[0], np.dtype('c16')) + assert_equal(i.dtypes[1], np.dtype('c16')) + assert_equal(i.dtypes[2], np.dtype('c16')) + assert_equal(i.dtypes[3], np.dtype('c16')) + assert_equal(i.value, (3, -12, 2j, 9)) + + # When allocating outputs, other outputs aren't factored in + i = nditer([array([3], dtype='i4'), None, array([2j], dtype='c16')], [], + [['readonly', 'copy'], + ['writeonly', 'allocate'], + ['writeonly']], + casting='safe') + assert_equal(i.dtypes[0], np.dtype('i4')) + assert_equal(i.dtypes[1], np.dtype('i4')) + assert_equal(i.dtypes[2], np.dtype('c16')) + # But, if common data types are requested, they are + i = nditer([array([3], dtype='i4'), None, array([2j], dtype='c16')], + ['common_dtype'], + [['readonly', 'copy'], + ['writeonly', 'allocate'], + ['writeonly']], + casting='safe') + assert_equal(i.dtypes[0], np.dtype('c16')) + assert_equal(i.dtypes[1], np.dtype('c16')) + assert_equal(i.dtypes[2], np.dtype('c16')) + +def test_iter_copy_if_overlap(): + # Ensure the iterator makes copies on read/write overlap, if requested + + # Copy not needed, 1 op + for flag in ['readonly', 'writeonly', 'readwrite']: + a = arange(10) + i = nditer([a], ['copy_if_overlap'], [[flag]]) + assert_(i.operands[0] is a) + + # Copy needed, 2 ops, read-write overlap + x = arange(10) + a = x[1:] + b = x[:-1] + i = nditer([a, b], ['copy_if_overlap'], [['readonly'], ['readwrite']]) + assert_(not np.shares_memory(*i.operands)) + + # Copy not needed with elementwise, 2 ops, exactly same arrays + x = arange(10) + a = x + b = x + i = nditer([a, b], ['copy_if_overlap'], [['readonly', 'overlap_assume_elementwise'], + ['readwrite', 'overlap_assume_elementwise']]) + assert_(i.operands[0] is a and i.operands[1] is b) + i = nditer([a, b], ['copy_if_overlap'], [['readonly'], ['readwrite']]) + assert_(i.operands[0] is a and not np.shares_memory(i.operands[1], b)) + + # Copy not needed, 2 ops, no overlap + x = arange(10) + a = x[::2] + b = x[1::2] + i = nditer([a, b], ['copy_if_overlap'], [['readonly'], ['writeonly']]) + assert_(i.operands[0] is a and i.operands[1] is b) + + # Copy needed, 2 ops, read-write overlap + x = arange(4, dtype=np.int8) + a = x[3:] + b = x.view(np.int32)[:1] + i = nditer([a, b], ['copy_if_overlap'], [['readonly'], ['writeonly']]) + assert_(not np.shares_memory(*i.operands)) + + # Copy needed, 3 ops, read-write overlap + for flag in ['writeonly', 'readwrite']: + x = np.ones([10, 10]) + a = x + b = x.T + c = x + i = nditer([a, b, c], ['copy_if_overlap'], + [['readonly'], ['readonly'], [flag]]) + a2, b2, c2 = i.operands + assert_(not np.shares_memory(a2, c2)) + assert_(not np.shares_memory(b2, c2)) + + # Copy not needed, 3 ops, read-only overlap + x = np.ones([10, 10]) + a = x + b = x.T + c = x + i = nditer([a, b, c], ['copy_if_overlap'], + [['readonly'], ['readonly'], ['readonly']]) + a2, b2, c2 = i.operands + assert_(a is a2) + assert_(b is b2) + assert_(c is c2) + + # Copy not needed, 3 ops, read-only overlap + x = np.ones([10, 10]) + a = x + b = np.ones([10, 10]) + c = x.T + i = nditer([a, b, c], ['copy_if_overlap'], + [['readonly'], ['writeonly'], ['readonly']]) + a2, b2, c2 = i.operands + assert_(a is a2) + assert_(b is b2) + assert_(c is c2) + + # Copy not needed, 3 ops, write-only overlap + x = np.arange(7) + a = x[:3] + b = x[3:6] + c = x[4:7] + i = nditer([a, b, c], ['copy_if_overlap'], + [['readonly'], ['writeonly'], ['writeonly']]) + a2, b2, c2 = i.operands + assert_(a is a2) + assert_(b is b2) + assert_(c is c2) + +def test_iter_op_axes(): + # Check that custom axes work + + # Reverse the axes + a = arange(6).reshape(2, 3) + i = nditer([a, a.T], [], [['readonly']]*2, op_axes=[[0, 1], [1, 0]]) + assert_(all([x == y for (x, y) in i])) + a = arange(24).reshape(2, 3, 4) + i = nditer([a.T, a], [], [['readonly']]*2, op_axes=[[2, 1, 0], None]) + assert_(all([x == y for (x, y) in i])) + + # Broadcast 1D to any dimension + a = arange(1, 31).reshape(2, 3, 5) + b = arange(1, 3) + i = nditer([a, b], [], [['readonly']]*2, op_axes=[None, [0, -1, -1]]) + assert_equal([x*y for (x, y) in i], (a*b.reshape(2, 1, 1)).ravel()) + b = arange(1, 4) + i = nditer([a, b], [], [['readonly']]*2, op_axes=[None, [-1, 0, -1]]) + assert_equal([x*y for (x, y) in i], (a*b.reshape(1, 3, 1)).ravel()) + b = arange(1, 6) + i = nditer([a, b], [], [['readonly']]*2, + op_axes=[None, [np.newaxis, np.newaxis, 0]]) + assert_equal([x*y for (x, y) in i], (a*b.reshape(1, 1, 5)).ravel()) + + # Inner product-style broadcasting + a = arange(24).reshape(2, 3, 4) + b = arange(40).reshape(5, 2, 4) + i = nditer([a, b], ['multi_index'], [['readonly']]*2, + op_axes=[[0, 1, -1, -1], [-1, -1, 0, 1]]) + assert_equal(i.shape, (2, 3, 5, 2)) + + # Matrix product-style broadcasting + a = arange(12).reshape(3, 4) + b = arange(20).reshape(4, 5) + i = nditer([a, b], ['multi_index'], [['readonly']]*2, + op_axes=[[0, -1], [-1, 1]]) + assert_equal(i.shape, (3, 5)) + +def test_iter_op_axes_errors(): + # Check that custom axes throws errors for bad inputs + + # Wrong number of items in op_axes + a = arange(6).reshape(2, 3) + assert_raises(ValueError, nditer, [a, a], [], [['readonly']]*2, + op_axes=[[0], [1], [0]]) + # Out of bounds items in op_axes + assert_raises(ValueError, nditer, [a, a], [], [['readonly']]*2, + op_axes=[[2, 1], [0, 1]]) + assert_raises(ValueError, nditer, [a, a], [], [['readonly']]*2, + op_axes=[[0, 1], [2, -1]]) + # Duplicate items in op_axes + assert_raises(ValueError, nditer, [a, a], [], [['readonly']]*2, + op_axes=[[0, 0], [0, 1]]) + assert_raises(ValueError, nditer, [a, a], [], [['readonly']]*2, + op_axes=[[0, 1], [1, 1]]) + + # Different sized arrays in op_axes + assert_raises(ValueError, nditer, [a, a], [], [['readonly']]*2, + op_axes=[[0, 1], [0, 1, 0]]) + + # Non-broadcastable dimensions in the result + assert_raises(ValueError, nditer, [a, a], [], [['readonly']]*2, + op_axes=[[0, 1], [1, 0]]) + +def test_iter_copy(): + # Check that copying the iterator works correctly + a = arange(24).reshape(2, 3, 4) + + # Simple iterator + i = nditer(a) + j = i.copy() + assert_equal([x[()] for x in i], [x[()] for x in j]) + + i.iterindex = 3 + j = i.copy() + assert_equal([x[()] for x in i], [x[()] for x in j]) + + # Buffered iterator + i = nditer(a, ['buffered', 'ranged'], order='F', buffersize=3) + j = i.copy() + assert_equal([x[()] for x in i], [x[()] for x in j]) + + i.iterindex = 3 + j = i.copy() + assert_equal([x[()] for x in i], [x[()] for x in j]) + + i.iterrange = (3, 9) + j = i.copy() + assert_equal([x[()] for x in i], [x[()] for x in j]) + + i.iterrange = (2, 18) + next(i) + next(i) + j = i.copy() + assert_equal([x[()] for x in i], [x[()] for x in j]) + + # Casting iterator + i = nditer(a, ['buffered'], order='F', casting='unsafe', + op_dtypes='f8', buffersize=5) + j = i.copy() + i = None + assert_equal([x[()] for x in j], a.ravel(order='F')) + + a = arange(24, dtype='cast->swap + + a = np.arange(10, dtype='f4').newbyteorder().byteswap() + i = nditer(a, ['buffered', 'external_loop'], + [['readwrite', 'nbo', 'aligned']], + casting='same_kind', + op_dtypes=[np.dtype('f8').newbyteorder()], + buffersize=3) + for v in i: + v[...] *= 2 + + assert_equal(a, 2*np.arange(10, dtype='f4')) + + with suppress_warnings() as sup: + sup.filter(np.ComplexWarning) + + a = np.arange(10, dtype='f8').newbyteorder().byteswap() + i = nditer(a, ['buffered', 'external_loop'], + [['readwrite', 'nbo', 'aligned']], + casting='unsafe', + op_dtypes=[np.dtype('c8').newbyteorder()], + buffersize=3) + for v in i: + v[...] *= 2 + + assert_equal(a, 2*np.arange(10, dtype='f8')) + +def test_iter_buffered_cast_byteswapped_complex(): + # Test that buffering can handle a cast which requires swap->cast->copy + + a = np.arange(10, dtype='c8').newbyteorder().byteswap() + a += 2j + i = nditer(a, ['buffered', 'external_loop'], + [['readwrite', 'nbo', 'aligned']], + casting='same_kind', + op_dtypes=[np.dtype('c16')], + buffersize=3) + for v in i: + v[...] *= 2 + assert_equal(a, 2*np.arange(10, dtype='c8') + 4j) + + a = np.arange(10, dtype='c8') + a += 2j + i = nditer(a, ['buffered', 'external_loop'], + [['readwrite', 'nbo', 'aligned']], + casting='same_kind', + op_dtypes=[np.dtype('c16').newbyteorder()], + buffersize=3) + for v in i: + v[...] *= 2 + assert_equal(a, 2*np.arange(10, dtype='c8') + 4j) + + a = np.arange(10, dtype=np.clongdouble).newbyteorder().byteswap() + a += 2j + i = nditer(a, ['buffered', 'external_loop'], + [['readwrite', 'nbo', 'aligned']], + casting='same_kind', + op_dtypes=[np.dtype('c16')], + buffersize=3) + for v in i: + v[...] *= 2 + assert_equal(a, 2*np.arange(10, dtype=np.clongdouble) + 4j) + + a = np.arange(10, dtype=np.longdouble).newbyteorder().byteswap() + i = nditer(a, ['buffered', 'external_loop'], + [['readwrite', 'nbo', 'aligned']], + casting='same_kind', + op_dtypes=[np.dtype('f4')], + buffersize=7) + for v in i: + v[...] *= 2 + assert_equal(a, 2*np.arange(10, dtype=np.longdouble)) + +def test_iter_buffered_cast_structured_type(): + # Tests buffering of structured types + + # simple -> struct type (duplicates the value) + sdt = [('a', 'f4'), ('b', 'i8'), ('c', 'c8', (2, 3)), ('d', 'O')] + a = np.arange(3, dtype='f4') + 0.5 + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt) + vals = [np.array(x) for x in i] + assert_equal(vals[0]['a'], 0.5) + assert_equal(vals[0]['b'], 0) + assert_equal(vals[0]['c'], [[(0.5)]*3]*2) + assert_equal(vals[0]['d'], 0.5) + assert_equal(vals[1]['a'], 1.5) + assert_equal(vals[1]['b'], 1) + assert_equal(vals[1]['c'], [[(1.5)]*3]*2) + assert_equal(vals[1]['d'], 1.5) + assert_equal(vals[0].dtype, np.dtype(sdt)) + + # object -> struct type + sdt = [('a', 'f4'), ('b', 'i8'), ('c', 'c8', (2, 3)), ('d', 'O')] + a = np.zeros((3,), dtype='O') + a[0] = (0.5, 0.5, [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5]], 0.5) + a[1] = (1.5, 1.5, [[1.5, 1.5, 1.5], [1.5, 1.5, 1.5]], 1.5) + a[2] = (2.5, 2.5, [[2.5, 2.5, 2.5], [2.5, 2.5, 2.5]], 2.5) + if HAS_REFCOUNT: + rc = sys.getrefcount(a[0]) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt) + vals = [x.copy() for x in i] + assert_equal(vals[0]['a'], 0.5) + assert_equal(vals[0]['b'], 0) + assert_equal(vals[0]['c'], [[(0.5)]*3]*2) + assert_equal(vals[0]['d'], 0.5) + assert_equal(vals[1]['a'], 1.5) + assert_equal(vals[1]['b'], 1) + assert_equal(vals[1]['c'], [[(1.5)]*3]*2) + assert_equal(vals[1]['d'], 1.5) + assert_equal(vals[0].dtype, np.dtype(sdt)) + vals, i, x = [None]*3 + if HAS_REFCOUNT: + assert_equal(sys.getrefcount(a[0]), rc) + + # single-field struct type -> simple + sdt = [('a', 'f4')] + a = np.array([(5.5,), (8,)], dtype=sdt) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes='i4') + assert_equal([x_[()] for x_ in i], [5, 8]) + + # make sure multi-field struct type -> simple doesn't work + sdt = [('a', 'f4'), ('b', 'i8'), ('d', 'O')] + a = np.array([(5.5, 7, 'test'), (8, 10, 11)], dtype=sdt) + assert_raises(ValueError, lambda: ( + nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes='i4'))) + + # struct type -> struct type (field-wise copy) + sdt1 = [('a', 'f4'), ('b', 'i8'), ('d', 'O')] + sdt2 = [('d', 'u2'), ('a', 'O'), ('b', 'f8')] + a = np.array([(1, 2, 3), (4, 5, 6)], dtype=sdt1) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + assert_equal([np.array(x_) for x_ in i], + [np.array((1, 2, 3), dtype=sdt2), + np.array((4, 5, 6), dtype=sdt2)]) + + # make sure struct type -> struct type with different + # number of fields fails + sdt1 = [('a', 'f4'), ('b', 'i8'), ('d', 'O')] + sdt2 = [('b', 'O'), ('a', 'f8')] + a = np.array([(1, 2, 3), (4, 5, 6)], dtype=sdt1) + + assert_raises(ValueError, lambda : ( + nditer(a, ['buffered', 'refs_ok'], ['readwrite'], + casting='unsafe', + op_dtypes=sdt2))) + + +def test_iter_buffered_cast_subarray(): + # Tests buffering of subarrays + + # one element -> many (copies it to all) + sdt1 = [('a', 'f4')] + sdt2 = [('a', 'f8', (3, 2, 2))] + a = np.zeros((6,), dtype=sdt1) + a['a'] = np.arange(6) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + for x, count in zip(i, list(range(6))): + assert_(np.all(x['a'] == count)) + + # one element -> many -> back (copies it to all) + sdt1 = [('a', 'O', (1, 1))] + sdt2 = [('a', 'O', (3, 2, 2))] + a = np.zeros((6,), dtype=sdt1) + a['a'][:, 0, 0] = np.arange(6) + i = nditer(a, ['buffered', 'refs_ok'], ['readwrite'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_(np.all(x['a'] == count)) + x['a'][0] += 2 + count += 1 + assert_equal(a['a'], np.arange(6).reshape(6, 1, 1)+2) + + # many -> one element -> back (copies just element 0) + sdt1 = [('a', 'O', (3, 2, 2))] + sdt2 = [('a', 'O', (1,))] + a = np.zeros((6,), dtype=sdt1) + a['a'][:, 0, 0, 0] = np.arange(6) + i = nditer(a, ['buffered', 'refs_ok'], ['readwrite'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'], count) + x['a'] += 2 + count += 1 + assert_equal(a['a'], np.arange(6).reshape(6, 1, 1, 1)*np.ones((1, 3, 2, 2))+2) + + # many -> one element -> back (copies just element 0) + sdt1 = [('a', 'f8', (3, 2, 2))] + sdt2 = [('a', 'O', (1,))] + a = np.zeros((6,), dtype=sdt1) + a['a'][:, 0, 0, 0] = np.arange(6) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'], count) + count += 1 + + # many -> one element (copies just element 0) + sdt1 = [('a', 'O', (3, 2, 2))] + sdt2 = [('a', 'f4', (1,))] + a = np.zeros((6,), dtype=sdt1) + a['a'][:, 0, 0, 0] = np.arange(6) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'], count) + count += 1 + + # many -> matching shape (straightforward copy) + sdt1 = [('a', 'O', (3, 2, 2))] + sdt2 = [('a', 'f4', (3, 2, 2))] + a = np.zeros((6,), dtype=sdt1) + a['a'] = np.arange(6*3*2*2).reshape(6, 3, 2, 2) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'], a[count]['a']) + count += 1 + + # vector -> smaller vector (truncates) + sdt1 = [('a', 'f8', (6,))] + sdt2 = [('a', 'f4', (2,))] + a = np.zeros((6,), dtype=sdt1) + a['a'] = np.arange(6*6).reshape(6, 6) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'], a[count]['a'][:2]) + count += 1 + + # vector -> bigger vector (pads with zeros) + sdt1 = [('a', 'f8', (2,))] + sdt2 = [('a', 'f4', (6,))] + a = np.zeros((6,), dtype=sdt1) + a['a'] = np.arange(6*2).reshape(6, 2) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'][:2], a[count]['a']) + assert_equal(x['a'][2:], [0, 0, 0, 0]) + count += 1 + + # vector -> matrix (broadcasts) + sdt1 = [('a', 'f8', (2,))] + sdt2 = [('a', 'f4', (2, 2))] + a = np.zeros((6,), dtype=sdt1) + a['a'] = np.arange(6*2).reshape(6, 2) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'][0], a[count]['a']) + assert_equal(x['a'][1], a[count]['a']) + count += 1 + + # vector -> matrix (broadcasts and zero-pads) + sdt1 = [('a', 'f8', (2, 1))] + sdt2 = [('a', 'f4', (3, 2))] + a = np.zeros((6,), dtype=sdt1) + a['a'] = np.arange(6*2).reshape(6, 2, 1) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'][:2, 0], a[count]['a'][:, 0]) + assert_equal(x['a'][:2, 1], a[count]['a'][:, 0]) + assert_equal(x['a'][2,:], [0, 0]) + count += 1 + + # matrix -> matrix (truncates and zero-pads) + sdt1 = [('a', 'f8', (2, 3))] + sdt2 = [('a', 'f4', (3, 2))] + a = np.zeros((6,), dtype=sdt1) + a['a'] = np.arange(6*2*3).reshape(6, 2, 3) + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', + op_dtypes=sdt2) + assert_equal(i[0].dtype, np.dtype(sdt2)) + count = 0 + for x in i: + assert_equal(x['a'][:2, 0], a[count]['a'][:, 0]) + assert_equal(x['a'][:2, 1], a[count]['a'][:, 1]) + assert_equal(x['a'][2,:], [0, 0]) + count += 1 + +def test_iter_buffering_badwriteback(): + # Writing back from a buffer cannot combine elements + + # a needs write buffering, but had a broadcast dimension + a = np.arange(6).reshape(2, 3, 1) + b = np.arange(12).reshape(2, 3, 2) + assert_raises(ValueError, nditer, [a, b], + ['buffered', 'external_loop'], + [['readwrite'], ['writeonly']], + order='C') + + # But if a is readonly, it's fine + nditer([a, b], ['buffered', 'external_loop'], + [['readonly'], ['writeonly']], + order='C') + + # If a has just one element, it's fine too (constant 0 stride, a reduction) + a = np.arange(1).reshape(1, 1, 1) + nditer([a, b], ['buffered', 'external_loop', 'reduce_ok'], + [['readwrite'], ['writeonly']], + order='C') + + # check that it fails on other dimensions too + a = np.arange(6).reshape(1, 3, 2) + assert_raises(ValueError, nditer, [a, b], + ['buffered', 'external_loop'], + [['readwrite'], ['writeonly']], + order='C') + a = np.arange(4).reshape(2, 1, 2) + assert_raises(ValueError, nditer, [a, b], + ['buffered', 'external_loop'], + [['readwrite'], ['writeonly']], + order='C') + +def test_iter_buffering_string(): + # Safe casting disallows shrinking strings + a = np.array(['abc', 'a', 'abcd'], dtype=np.bytes_) + assert_equal(a.dtype, np.dtype('S4')) + assert_raises(TypeError, nditer, a, ['buffered'], ['readonly'], + op_dtypes='S2') + i = nditer(a, ['buffered'], ['readonly'], op_dtypes='S6') + assert_equal(i[0], b'abc') + assert_equal(i[0].dtype, np.dtype('S6')) + + a = np.array(['abc', 'a', 'abcd'], dtype=np.unicode) + assert_equal(a.dtype, np.dtype('U4')) + assert_raises(TypeError, nditer, a, ['buffered'], ['readonly'], + op_dtypes='U2') + i = nditer(a, ['buffered'], ['readonly'], op_dtypes='U6') + assert_equal(i[0], u'abc') + assert_equal(i[0].dtype, np.dtype('U6')) + +def test_iter_buffering_growinner(): + # Test that the inner loop grows when no buffering is needed + a = np.arange(30) + i = nditer(a, ['buffered', 'growinner', 'external_loop'], + buffersize=5) + # Should end up with just one inner loop here + assert_equal(i[0].size, a.size) + + +@dec.slow +def test_iter_buffered_reduce_reuse(): + # large enough array for all views, including negative strides. + a = np.arange(2*3**5)[3**5:3**5+1] + flags = ['buffered', 'delay_bufalloc', 'multi_index', 'reduce_ok', 'refs_ok'] + op_flags = [('readonly',), ('readwrite', 'allocate')] + op_axes_list = [[(0, 1, 2), (0, 1, -1)], [(0, 1, 2), (0, -1, -1)]] + # wrong dtype to force buffering + op_dtypes = [float, a.dtype] + + def get_params(): + for xs in range(-3**2, 3**2 + 1): + for ys in range(xs, 3**2 + 1): + for op_axes in op_axes_list: + # last stride is reduced and because of that not + # important for this test, as it is the inner stride. + strides = (xs * a.itemsize, ys * a.itemsize, a.itemsize) + arr = np.lib.stride_tricks.as_strided(a, (3, 3, 3), strides) + + for skip in [0, 1]: + yield arr, op_axes, skip + + for arr, op_axes, skip in get_params(): + nditer2 = np.nditer([arr.copy(), None], + op_axes=op_axes, flags=flags, op_flags=op_flags, + op_dtypes=op_dtypes) + nditer2.operands[-1][...] = 0 + nditer2.reset() + nditer2.iterindex = skip + + for (a2_in, b2_in) in nditer2: + b2_in += a2_in.astype(np.int_) + + comp_res = nditer2.operands[-1] + + for bufsize in range(0, 3**3): + nditer1 = np.nditer([arr, None], + op_axes=op_axes, flags=flags, op_flags=op_flags, + buffersize=bufsize, op_dtypes=op_dtypes) + nditer1.operands[-1][...] = 0 + nditer1.reset() + nditer1.iterindex = skip + + for (a1_in, b1_in) in nditer1: + b1_in += a1_in.astype(np.int_) + + res = nditer1.operands[-1] + assert_array_equal(res, comp_res) + + +def test_iter_no_broadcast(): + # Test that the no_broadcast flag works + a = np.arange(24).reshape(2, 3, 4) + b = np.arange(6).reshape(2, 3, 1) + c = np.arange(12).reshape(3, 4) + + nditer([a, b, c], [], + [['readonly', 'no_broadcast'], + ['readonly'], ['readonly']]) + assert_raises(ValueError, nditer, [a, b, c], [], + [['readonly'], ['readonly', 'no_broadcast'], ['readonly']]) + assert_raises(ValueError, nditer, [a, b, c], [], + [['readonly'], ['readonly'], ['readonly', 'no_broadcast']]) + + +class TestIterNested(object): + + def test_basic(self): + # Test nested iteration basic usage + a = arange(12).reshape(2, 3, 2) + + i, j = np.nested_iters(a, [[0], [1, 2]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]) + + i, j = np.nested_iters(a, [[0, 1], [2]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]) + + i, j = np.nested_iters(a, [[0, 2], [1]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 2, 4], [1, 3, 5], [6, 8, 10], [7, 9, 11]]) + + def test_reorder(self): + # Test nested iteration basic usage + a = arange(12).reshape(2, 3, 2) + + # In 'K' order (default), it gets reordered + i, j = np.nested_iters(a, [[0], [2, 1]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]) + + i, j = np.nested_iters(a, [[1, 0], [2]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]) + + i, j = np.nested_iters(a, [[2, 0], [1]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 2, 4], [1, 3, 5], [6, 8, 10], [7, 9, 11]]) + + # In 'C' order, it doesn't + i, j = np.nested_iters(a, [[0], [2, 1]], order='C') + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 2, 4, 1, 3, 5], [6, 8, 10, 7, 9, 11]]) + + i, j = np.nested_iters(a, [[1, 0], [2]], order='C') + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1], [6, 7], [2, 3], [8, 9], [4, 5], [10, 11]]) + + i, j = np.nested_iters(a, [[2, 0], [1]], order='C') + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 2, 4], [6, 8, 10], [1, 3, 5], [7, 9, 11]]) + + def test_flip_axes(self): + # Test nested iteration with negative axes + a = arange(12).reshape(2, 3, 2)[::-1, ::-1, ::-1] + + # In 'K' order (default), the axes all get flipped + i, j = np.nested_iters(a, [[0], [1, 2]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]) + + i, j = np.nested_iters(a, [[0, 1], [2]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]) + + i, j = np.nested_iters(a, [[0, 2], [1]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 2, 4], [1, 3, 5], [6, 8, 10], [7, 9, 11]]) + + # In 'C' order, flipping axes is disabled + i, j = np.nested_iters(a, [[0], [1, 2]], order='C') + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[11, 10, 9, 8, 7, 6], [5, 4, 3, 2, 1, 0]]) + + i, j = np.nested_iters(a, [[0, 1], [2]], order='C') + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[11, 10], [9, 8], [7, 6], [5, 4], [3, 2], [1, 0]]) + + i, j = np.nested_iters(a, [[0, 2], [1]], order='C') + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[11, 9, 7], [10, 8, 6], [5, 3, 1], [4, 2, 0]]) + + def test_broadcast(self): + # Test nested iteration with broadcasting + a = arange(2).reshape(2, 1) + b = arange(3).reshape(1, 3) + + i, j = np.nested_iters([a, b], [[0], [1]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[[0, 0], [0, 1], [0, 2]], [[1, 0], [1, 1], [1, 2]]]) + + i, j = np.nested_iters([a, b], [[1], [0]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[[0, 0], [1, 0]], [[0, 1], [1, 1]], [[0, 2], [1, 2]]]) + + def test_dtype_copy(self): + # Test nested iteration with a copy to change dtype + + # copy + a = arange(6, dtype='i4').reshape(2, 3) + i, j = np.nested_iters(a, [[0], [1]], + op_flags=['readonly', 'copy'], + op_dtypes='f8') + assert_equal(j[0].dtype, np.dtype('f8')) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1, 2], [3, 4, 5]]) + vals = None + + # updateifcopy + a = arange(6, dtype='f4').reshape(2, 3) + i, j = np.nested_iters(a, [[0], [1]], + op_flags=['readwrite', 'updateifcopy'], + casting='same_kind', + op_dtypes='f8') + assert_equal(j[0].dtype, np.dtype('f8')) + for x in i: + for y in j: + y[...] += 1 + assert_equal(a, [[0, 1, 2], [3, 4, 5]]) + i, j, x, y = (None,)*4 # force the updateifcopy + assert_equal(a, [[1, 2, 3], [4, 5, 6]]) + + def test_dtype_buffered(self): + # Test nested iteration with buffering to change dtype + + a = arange(6, dtype='f4').reshape(2, 3) + i, j = np.nested_iters(a, [[0], [1]], + flags=['buffered'], + op_flags=['readwrite'], + casting='same_kind', + op_dtypes='f8') + assert_equal(j[0].dtype, np.dtype('f8')) + for x in i: + for y in j: + y[...] += 1 + assert_equal(a, [[1, 2, 3], [4, 5, 6]]) + + def test_0d(self): + a = np.arange(12).reshape(2, 3, 2) + i, j = np.nested_iters(a, [[], [1, 0, 2]]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]]) + + i, j = np.nested_iters(a, [[1, 0, 2], []]) + vals = [] + for x in i: + vals.append([y for y in j]) + assert_equal(vals, [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]]) + + i, j, k = np.nested_iters(a, [[2, 0], [], [1]]) + vals = [] + for x in i: + for y in j: + vals.append([z for z in k]) + assert_equal(vals, [[0, 2, 4], [1, 3, 5], [6, 8, 10], [7, 9, 11]]) + + +def test_iter_reduction_error(): + + a = np.arange(6) + assert_raises(ValueError, nditer, [a, None], [], + [['readonly'], ['readwrite', 'allocate']], + op_axes=[[0], [-1]]) + + a = np.arange(6).reshape(2, 3) + assert_raises(ValueError, nditer, [a, None], ['external_loop'], + [['readonly'], ['readwrite', 'allocate']], + op_axes=[[0, 1], [-1, -1]]) + +def test_iter_reduction(): + # Test doing reductions with the iterator + + a = np.arange(6) + i = nditer([a, None], ['reduce_ok'], + [['readonly'], ['readwrite', 'allocate']], + op_axes=[[0], [-1]]) + # Need to initialize the output operand to the addition unit + i.operands[1][...] = 0 + # Do the reduction + for x, y in i: + y[...] += x + # Since no axes were specified, should have allocated a scalar + assert_equal(i.operands[1].ndim, 0) + assert_equal(i.operands[1], np.sum(a)) + + a = np.arange(6).reshape(2, 3) + i = nditer([a, None], ['reduce_ok', 'external_loop'], + [['readonly'], ['readwrite', 'allocate']], + op_axes=[[0, 1], [-1, -1]]) + # Need to initialize the output operand to the addition unit + i.operands[1][...] = 0 + # Reduction shape/strides for the output + assert_equal(i[1].shape, (6,)) + assert_equal(i[1].strides, (0,)) + # Do the reduction + for x, y in i: + # Use a for loop instead of ``y[...] += x`` + # (equivalent to ``y[...] = y[...].copy() + x``), + # because y has zero strides we use for the reduction + for j in range(len(y)): + y[j] += x[j] + # Since no axes were specified, should have allocated a scalar + assert_equal(i.operands[1].ndim, 0) + assert_equal(i.operands[1], np.sum(a)) + + # This is a tricky reduction case for the buffering double loop + # to handle + a = np.ones((2, 3, 5)) + it1 = nditer([a, None], ['reduce_ok', 'external_loop'], + [['readonly'], ['readwrite', 'allocate']], + op_axes=[None, [0, -1, 1]]) + it2 = nditer([a, None], ['reduce_ok', 'external_loop', + 'buffered', 'delay_bufalloc'], + [['readonly'], ['readwrite', 'allocate']], + op_axes=[None, [0, -1, 1]], buffersize=10) + it1.operands[1].fill(0) + it2.operands[1].fill(0) + it2.reset() + for x in it1: + x[1][...] += x[0] + for x in it2: + x[1][...] += x[0] + assert_equal(it1.operands[1], it2.operands[1]) + assert_equal(it2.operands[1].sum(), a.size) + +def test_iter_buffering_reduction(): + # Test doing buffered reductions with the iterator + + a = np.arange(6) + b = np.array(0., dtype='f8').byteswap().newbyteorder() + i = nditer([a, b], ['reduce_ok', 'buffered'], + [['readonly'], ['readwrite', 'nbo']], + op_axes=[[0], [-1]]) + assert_equal(i[1].dtype, np.dtype('f8')) + assert_(i[1].dtype != b.dtype) + # Do the reduction + for x, y in i: + y[...] += x + # Since no axes were specified, should have allocated a scalar + assert_equal(b, np.sum(a)) + + a = np.arange(6).reshape(2, 3) + b = np.array([0, 0], dtype='f8').byteswap().newbyteorder() + i = nditer([a, b], ['reduce_ok', 'external_loop', 'buffered'], + [['readonly'], ['readwrite', 'nbo']], + op_axes=[[0, 1], [0, -1]]) + # Reduction shape/strides for the output + assert_equal(i[1].shape, (3,)) + assert_equal(i[1].strides, (0,)) + # Do the reduction + for x, y in i: + # Use a for loop instead of ``y[...] += x`` + # (equivalent to ``y[...] = y[...].copy() + x``), + # because y has zero strides we use for the reduction + for j in range(len(y)): + y[j] += x[j] + assert_equal(b, np.sum(a, axis=1)) + + # Iterator inner double loop was wrong on this one + p = np.arange(2) + 1 + it = np.nditer([p, None], + ['delay_bufalloc', 'reduce_ok', 'buffered', 'external_loop'], + [['readonly'], ['readwrite', 'allocate']], + op_axes=[[-1, 0], [-1, -1]], + itershape=(2, 2)) + it.operands[1].fill(0) + it.reset() + assert_equal(it[0], [1, 2, 1, 2]) + + # Iterator inner loop should take argument contiguity into account + x = np.ones((7, 13, 8), np.int8)[4:6,1:11:6,1:5].transpose(1, 2, 0) + x[...] = np.arange(x.size).reshape(x.shape) + y_base = np.arange(4*4, dtype=np.int8).reshape(4, 4) + y_base_copy = y_base.copy() + y = y_base[::2,:,None] + + it = np.nditer([y, x], + ['buffered', 'external_loop', 'reduce_ok'], + [['readwrite'], ['readonly']]) + for a, b in it: + a.fill(2) + + assert_equal(y_base[1::2], y_base_copy[1::2]) + assert_equal(y_base[::2], 2) + +def test_iter_buffering_reduction_reuse_reduce_loops(): + # There was a bug triggering reuse of the reduce loop inappropriately, + # which caused processing to happen in unnecessarily small chunks + # and overran the buffer. + + a = np.zeros((2, 7)) + b = np.zeros((1, 7)) + it = np.nditer([a, b], flags=['reduce_ok', 'external_loop', 'buffered'], + op_flags=[['readonly'], ['readwrite']], + buffersize=5) + + bufsizes = [] + for x, y in it: + bufsizes.append(x.shape[0]) + assert_equal(bufsizes, [5, 2, 5, 2]) + assert_equal(sum(bufsizes), a.size) + +def test_iter_writemasked_badinput(): + a = np.zeros((2, 3)) + b = np.zeros((3,)) + m = np.array([[True, True, False], [False, True, False]]) + m2 = np.array([True, True, False]) + m3 = np.array([0, 1, 1], dtype='u1') + mbad1 = np.array([0, 1, 1], dtype='i1') + mbad2 = np.array([0, 1, 1], dtype='f4') + + # Need an 'arraymask' if any operand is 'writemasked' + assert_raises(ValueError, nditer, [a, m], [], + [['readwrite', 'writemasked'], ['readonly']]) + + # A 'writemasked' operand must not be readonly + assert_raises(ValueError, nditer, [a, m], [], + [['readonly', 'writemasked'], ['readonly', 'arraymask']]) + + # 'writemasked' and 'arraymask' may not be used together + assert_raises(ValueError, nditer, [a, m], [], + [['readonly'], ['readwrite', 'arraymask', 'writemasked']]) + + # 'arraymask' may only be specified once + assert_raises(ValueError, nditer, [a, m, m2], [], + [['readwrite', 'writemasked'], + ['readonly', 'arraymask'], + ['readonly', 'arraymask']]) + + # An 'arraymask' with nothing 'writemasked' also doesn't make sense + assert_raises(ValueError, nditer, [a, m], [], + [['readwrite'], ['readonly', 'arraymask']]) + + # A writemasked reduction requires a similarly smaller mask + assert_raises(ValueError, nditer, [a, b, m], ['reduce_ok'], + [['readonly'], + ['readwrite', 'writemasked'], + ['readonly', 'arraymask']]) + # But this should work with a smaller/equal mask to the reduction operand + np.nditer([a, b, m2], ['reduce_ok'], + [['readonly'], + ['readwrite', 'writemasked'], + ['readonly', 'arraymask']]) + # The arraymask itself cannot be a reduction + assert_raises(ValueError, nditer, [a, b, m2], ['reduce_ok'], + [['readonly'], + ['readwrite', 'writemasked'], + ['readwrite', 'arraymask']]) + + # A uint8 mask is ok too + np.nditer([a, m3], ['buffered'], + [['readwrite', 'writemasked'], + ['readonly', 'arraymask']], + op_dtypes=['f4', None], + casting='same_kind') + # An int8 mask isn't ok + assert_raises(TypeError, np.nditer, [a, mbad1], ['buffered'], + [['readwrite', 'writemasked'], + ['readonly', 'arraymask']], + op_dtypes=['f4', None], + casting='same_kind') + # A float32 mask isn't ok + assert_raises(TypeError, np.nditer, [a, mbad2], ['buffered'], + [['readwrite', 'writemasked'], + ['readonly', 'arraymask']], + op_dtypes=['f4', None], + casting='same_kind') + +def test_iter_writemasked(): + a = np.zeros((3,), dtype='f8') + msk = np.array([True, True, False]) + + # When buffering is unused, 'writemasked' effectively does nothing. + # It's up to the user of the iterator to obey the requested semantics. + it = np.nditer([a, msk], [], + [['readwrite', 'writemasked'], + ['readonly', 'arraymask']]) + for x, m in it: + x[...] = 1 + # Because we violated the semantics, all the values became 1 + assert_equal(a, [1, 1, 1]) + + # Even if buffering is enabled, we still may be accessing the array + # directly. + it = np.nditer([a, msk], ['buffered'], + [['readwrite', 'writemasked'], + ['readonly', 'arraymask']]) + for x, m in it: + x[...] = 2.5 + # Because we violated the semantics, all the values became 2.5 + assert_equal(a, [2.5, 2.5, 2.5]) + + # If buffering will definitely happening, for instance because of + # a cast, only the items selected by the mask will be copied back from + # the buffer. + it = np.nditer([a, msk], ['buffered'], + [['readwrite', 'writemasked'], + ['readonly', 'arraymask']], + op_dtypes=['i8', None], + casting='unsafe') + for x, m in it: + x[...] = 3 + # Even though we violated the semantics, only the selected values + # were copied back + assert_equal(a, [3, 3, 2.5]) + +def test_iter_non_writable_attribute_deletion(): + it = np.nditer(np.ones(2)) + attr = ["value", "shape", "operands", "itviews", "has_delayed_bufalloc", + "iterationneedsapi", "has_multi_index", "has_index", "dtypes", + "ndim", "nop", "itersize", "finished"] + + for s in attr: + assert_raises(AttributeError, delattr, it, s) + + +def test_iter_writable_attribute_deletion(): + it = np.nditer(np.ones(2)) + attr = [ "multi_index", "index", "iterrange", "iterindex"] + for s in attr: + assert_raises(AttributeError, delattr, it, s) + + +def test_iter_element_deletion(): + it = np.nditer(np.ones(3)) + try: + del it[1] + del it[1:2] + except TypeError: + pass + except Exception: + raise AssertionError + +def test_iter_allocated_array_dtypes(): + # If the dtype of an allocated output has a shape, the shape gets + # tacked onto the end of the result. + it = np.nditer(([1, 3, 20], None), op_dtypes=[None, ('i4', (2,))]) + for a, b in it: + b[0] = a - 1 + b[1] = a + 1 + assert_equal(it.operands[1], [[0, 2], [2, 4], [19, 21]]) + + # Make sure this works for scalars too + it = np.nditer((10, 2, None), op_dtypes=[None, None, ('i4', (2, 2))]) + for a, b, c in it: + c[0, 0] = a - b + c[0, 1] = a + b + c[1, 0] = a * b + c[1, 1] = a / b + assert_equal(it.operands[2], [[8, 12], [20, 5]]) + + +def test_0d_iter(): + # Basic test for iteration of 0-d arrays: + i = nditer([2, 3], ['multi_index'], [['readonly']]*2) + assert_equal(i.ndim, 0) + assert_equal(next(i), (2, 3)) + assert_equal(i.multi_index, ()) + assert_equal(i.iterindex, 0) + assert_raises(StopIteration, next, i) + # test reset: + i.reset() + assert_equal(next(i), (2, 3)) + assert_raises(StopIteration, next, i) + + # test forcing to 0-d + i = nditer(np.arange(5), ['multi_index'], [['readonly']], op_axes=[()]) + assert_equal(i.ndim, 0) + assert_equal(len(i), 1) + # note that itershape=(), still behaves like None due to the conversions + + # Test a more complex buffered casting case (same as another test above) + sdt = [('a', 'f4'), ('b', 'i8'), ('c', 'c8', (2, 3)), ('d', 'O')] + a = np.array(0.5, dtype='f4') + i = nditer(a, ['buffered', 'refs_ok'], ['readonly'], + casting='unsafe', op_dtypes=sdt) + vals = next(i) + assert_equal(vals['a'], 0.5) + assert_equal(vals['b'], 0) + assert_equal(vals['c'], [[(0.5)]*3]*2) + assert_equal(vals['d'], 0.5) + + +def test_iter_too_large(): + # The total size of the iterator must not exceed the maximum intp due + # to broadcasting. Dividing by 1024 will keep it small enough to + # give a legal array. + size = np.iinfo(np.intp).max // 1024 + arr = np.lib.stride_tricks.as_strided(np.zeros(1), (size,), (0,)) + assert_raises(ValueError, nditer, (arr, arr[:, None])) + # test the same for multiindex. That may get more interesting when + # removing 0 dimensional axis is allowed (since an iterator can grow then) + assert_raises(ValueError, nditer, + (arr, arr[:, None]), flags=['multi_index']) + + +def test_iter_too_large_with_multiindex(): + # When a multi index is being tracked, the error is delayed this + # checks the delayed error messages and getting below that by + # removing an axis. + base_size = 2**10 + num = 1 + while base_size**num < np.iinfo(np.intp).max: + num += 1 + + shape_template = [1, 1] * num + arrays = [] + for i in range(num): + shape = shape_template[:] + shape[i * 2] = 2**10 + arrays.append(np.empty(shape)) + arrays = tuple(arrays) + + # arrays are now too large to be broadcast. The different modes test + # different nditer functionality with or without GIL. + for mode in range(6): + assert_raises(ValueError, test_nditer_too_large, arrays, -1, mode) + # but if we do nothing with the nditer, it can be constructed: + test_nditer_too_large(arrays, -1, 7) + + # When an axis is removed, things should work again (half the time): + for i in range(num): + for mode in range(6): + # an axis with size 1024 is removed: + test_nditer_too_large(arrays, i*2, mode) + # an axis with size 1 is removed: + assert_raises(ValueError, test_nditer_too_large, + arrays, i*2 + 1, mode) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py new file mode 100644 index 0000000..2cbcab2 --- /dev/null +++ b/numpy/core/tests/test_numeric.py @@ -0,0 +1,2739 @@ +from __future__ import division, absolute_import, print_function + +import sys +import warnings +import itertools +import platform +from decimal import Decimal + +import numpy as np +from numpy.core import umath +from numpy.random import rand, randint, randn +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, + assert_raises_regex, assert_array_equal, assert_almost_equal, + assert_array_almost_equal, dec, HAS_REFCOUNT, suppress_warnings +) + + +class TestResize(object): + def test_copies(self): + A = np.array([[1, 2], [3, 4]]) + Ar1 = np.array([[1, 2, 3, 4], [1, 2, 3, 4]]) + assert_equal(np.resize(A, (2, 4)), Ar1) + + Ar2 = np.array([[1, 2], [3, 4], [1, 2], [3, 4]]) + assert_equal(np.resize(A, (4, 2)), Ar2) + + Ar3 = np.array([[1, 2, 3], [4, 1, 2], [3, 4, 1], [2, 3, 4]]) + assert_equal(np.resize(A, (4, 3)), Ar3) + + def test_zeroresize(self): + A = np.array([[1, 2], [3, 4]]) + Ar = np.resize(A, (0,)) + assert_array_equal(Ar, np.array([])) + assert_equal(A.dtype, Ar.dtype) + + Ar = np.resize(A, (0, 2)) + assert_equal(Ar.shape, (0, 2)) + + Ar = np.resize(A, (2, 0)) + assert_equal(Ar.shape, (2, 0)) + + def test_reshape_from_zero(self): + # See also gh-6740 + A = np.zeros(0, dtype=[('a', np.float32, 1)]) + Ar = np.resize(A, (2, 1)) + assert_array_equal(Ar, np.zeros((2, 1), Ar.dtype)) + assert_equal(A.dtype, Ar.dtype) + + +class TestNonarrayArgs(object): + # check that non-array arguments to functions wrap them in arrays + def test_choose(self): + choices = [[0, 1, 2], + [3, 4, 5], + [5, 6, 7]] + tgt = [5, 1, 5] + a = [2, 0, 1] + + out = np.choose(a, choices) + assert_equal(out, tgt) + + def test_clip(self): + arr = [-1, 5, 2, 3, 10, -4, -9] + out = np.clip(arr, 2, 7) + tgt = [2, 5, 2, 3, 7, 2, 2] + assert_equal(out, tgt) + + def test_compress(self): + arr = [[0, 1, 2, 3, 4], + [5, 6, 7, 8, 9]] + tgt = [[5, 6, 7, 8, 9]] + out = np.compress([0, 1], arr, axis=0) + assert_equal(out, tgt) + + def test_count_nonzero(self): + arr = [[0, 1, 7, 0, 0], + [3, 0, 0, 2, 19]] + tgt = np.array([2, 3]) + out = np.count_nonzero(arr, axis=1) + assert_equal(out, tgt) + + def test_cumproduct(self): + A = [[1, 2, 3], [4, 5, 6]] + assert_(np.all(np.cumproduct(A) == np.array([1, 2, 6, 24, 120, 720]))) + + def test_diagonal(self): + a = [[0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11]] + out = np.diagonal(a) + tgt = [0, 5, 10] + + assert_equal(out, tgt) + + def test_mean(self): + A = [[1, 2, 3], [4, 5, 6]] + assert_(np.mean(A) == 3.5) + assert_(np.all(np.mean(A, 0) == np.array([2.5, 3.5, 4.5]))) + assert_(np.all(np.mean(A, 1) == np.array([2., 5.]))) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_(np.isnan(np.mean([]))) + assert_(w[0].category is RuntimeWarning) + + def test_ptp(self): + a = [3, 4, 5, 10, -3, -5, 6.0] + assert_equal(np.ptp(a, axis=0), 15.0) + + def test_prod(self): + arr = [[1, 2, 3, 4], + [5, 6, 7, 9], + [10, 3, 4, 5]] + tgt = [24, 1890, 600] + + assert_equal(np.prod(arr, axis=-1), tgt) + + def test_ravel(self): + a = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]] + tgt = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + assert_equal(np.ravel(a), tgt) + + def test_repeat(self): + a = [1, 2, 3] + tgt = [1, 1, 2, 2, 3, 3] + + out = np.repeat(a, 2) + assert_equal(out, tgt) + + def test_reshape(self): + arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]] + tgt = [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]] + assert_equal(np.reshape(arr, (2, 6)), tgt) + + def test_round(self): + arr = [1.56, 72.54, 6.35, 3.25] + tgt = [1.6, 72.5, 6.4, 3.2] + assert_equal(np.around(arr, decimals=1), tgt) + + def test_searchsorted(self): + arr = [-8, -5, -1, 3, 6, 10] + out = np.searchsorted(arr, 0) + assert_equal(out, 3) + + def test_size(self): + A = [[1, 2, 3], [4, 5, 6]] + assert_(np.size(A) == 6) + assert_(np.size(A, 0) == 2) + assert_(np.size(A, 1) == 3) + + def test_squeeze(self): + A = [[[1, 1, 1], [2, 2, 2], [3, 3, 3]]] + assert_(np.squeeze(A).shape == (3, 3)) + + def test_std(self): + A = [[1, 2, 3], [4, 5, 6]] + assert_almost_equal(np.std(A), 1.707825127659933) + assert_almost_equal(np.std(A, 0), np.array([1.5, 1.5, 1.5])) + assert_almost_equal(np.std(A, 1), np.array([0.81649658, 0.81649658])) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_(np.isnan(np.std([]))) + assert_(w[0].category is RuntimeWarning) + + def test_swapaxes(self): + tgt = [[[0, 4], [2, 6]], [[1, 5], [3, 7]]] + a = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]] + out = np.swapaxes(a, 0, 2) + assert_equal(out, tgt) + + def test_sum(self): + m = [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]] + tgt = [[6], [15], [24]] + out = np.sum(m, axis=1, keepdims=True) + + assert_equal(tgt, out) + + def test_take(self): + tgt = [2, 3, 5] + indices = [1, 2, 4] + a = [1, 2, 3, 4, 5] + + out = np.take(a, indices) + assert_equal(out, tgt) + + def test_trace(self): + c = [[1, 2], [3, 4], [5, 6]] + assert_equal(np.trace(c), 5) + + def test_transpose(self): + arr = [[1, 2], [3, 4], [5, 6]] + tgt = [[1, 3, 5], [2, 4, 6]] + assert_equal(np.transpose(arr, (1, 0)), tgt) + + def test_var(self): + A = [[1, 2, 3], [4, 5, 6]] + assert_almost_equal(np.var(A), 2.9166666666666665) + assert_almost_equal(np.var(A, 0), np.array([2.25, 2.25, 2.25])) + assert_almost_equal(np.var(A, 1), np.array([0.66666667, 0.66666667])) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_(np.isnan(np.var([]))) + assert_(w[0].category is RuntimeWarning) + + +class TestIsscalar(object): + def test_isscalar(self): + assert_(np.isscalar(3.1)) + assert_(np.isscalar(np.int16(12345))) + assert_(np.isscalar(False)) + assert_(np.isscalar('numpy')) + assert_(not np.isscalar([3.1])) + assert_(not np.isscalar(None)) + + # PEP 3141 + from fractions import Fraction + assert_(np.isscalar(Fraction(5, 17))) + from numbers import Number + assert_(np.isscalar(Number())) + + +class TestBoolScalar(object): + def test_logical(self): + f = np.False_ + t = np.True_ + s = "xyz" + assert_((t and s) is s) + assert_((f and s) is f) + + def test_bitwise_or(self): + f = np.False_ + t = np.True_ + assert_((t | t) is t) + assert_((f | t) is t) + assert_((t | f) is t) + assert_((f | f) is f) + + def test_bitwise_and(self): + f = np.False_ + t = np.True_ + assert_((t & t) is t) + assert_((f & t) is f) + assert_((t & f) is f) + assert_((f & f) is f) + + def test_bitwise_xor(self): + f = np.False_ + t = np.True_ + assert_((t ^ t) is f) + assert_((f ^ t) is t) + assert_((t ^ f) is t) + assert_((f ^ f) is f) + + +class TestBoolArray(object): + def setup(self): + # offset for simd tests + self.t = np.array([True] * 41, dtype=bool)[1::] + self.f = np.array([False] * 41, dtype=bool)[1::] + self.o = np.array([False] * 42, dtype=bool)[2::] + self.nm = self.f.copy() + self.im = self.t.copy() + self.nm[3] = True + self.nm[-2] = True + self.im[3] = False + self.im[-2] = False + + def test_all_any(self): + assert_(self.t.all()) + assert_(self.t.any()) + assert_(not self.f.all()) + assert_(not self.f.any()) + assert_(self.nm.any()) + assert_(self.im.any()) + assert_(not self.nm.all()) + assert_(not self.im.all()) + # check bad element in all positions + for i in range(256 - 7): + d = np.array([False] * 256, dtype=bool)[7::] + d[i] = True + assert_(np.any(d)) + e = np.array([True] * 256, dtype=bool)[7::] + e[i] = False + assert_(not np.all(e)) + assert_array_equal(e, ~d) + # big array test for blocked libc loops + for i in list(range(9, 6000, 507)) + [7764, 90021, -10]: + d = np.array([False] * 100043, dtype=bool) + d[i] = True + assert_(np.any(d), msg="%r" % i) + e = np.array([True] * 100043, dtype=bool) + e[i] = False + assert_(not np.all(e), msg="%r" % i) + + def test_logical_not_abs(self): + assert_array_equal(~self.t, self.f) + assert_array_equal(np.abs(~self.t), self.f) + assert_array_equal(np.abs(~self.f), self.t) + assert_array_equal(np.abs(self.f), self.f) + assert_array_equal(~np.abs(self.f), self.t) + assert_array_equal(~np.abs(self.t), self.f) + assert_array_equal(np.abs(~self.nm), self.im) + np.logical_not(self.t, out=self.o) + assert_array_equal(self.o, self.f) + np.abs(self.t, out=self.o) + assert_array_equal(self.o, self.t) + + def test_logical_and_or_xor(self): + assert_array_equal(self.t | self.t, self.t) + assert_array_equal(self.f | self.f, self.f) + assert_array_equal(self.t | self.f, self.t) + assert_array_equal(self.f | self.t, self.t) + np.logical_or(self.t, self.t, out=self.o) + assert_array_equal(self.o, self.t) + assert_array_equal(self.t & self.t, self.t) + assert_array_equal(self.f & self.f, self.f) + assert_array_equal(self.t & self.f, self.f) + assert_array_equal(self.f & self.t, self.f) + np.logical_and(self.t, self.t, out=self.o) + assert_array_equal(self.o, self.t) + assert_array_equal(self.t ^ self.t, self.f) + assert_array_equal(self.f ^ self.f, self.f) + assert_array_equal(self.t ^ self.f, self.t) + assert_array_equal(self.f ^ self.t, self.t) + np.logical_xor(self.t, self.t, out=self.o) + assert_array_equal(self.o, self.f) + + assert_array_equal(self.nm & self.t, self.nm) + assert_array_equal(self.im & self.f, False) + assert_array_equal(self.nm & True, self.nm) + assert_array_equal(self.im & False, self.f) + assert_array_equal(self.nm | self.t, self.t) + assert_array_equal(self.im | self.f, self.im) + assert_array_equal(self.nm | True, self.t) + assert_array_equal(self.im | False, self.im) + assert_array_equal(self.nm ^ self.t, self.im) + assert_array_equal(self.im ^ self.f, self.im) + assert_array_equal(self.nm ^ True, self.im) + assert_array_equal(self.im ^ False, self.im) + + +class TestBoolCmp(object): + def setup(self): + self.f = np.ones(256, dtype=np.float32) + self.ef = np.ones(self.f.size, dtype=bool) + self.d = np.ones(128, dtype=np.float64) + self.ed = np.ones(self.d.size, dtype=bool) + # generate values for all permutation of 256bit simd vectors + s = 0 + for i in range(32): + self.f[s:s+8] = [i & 2**x for x in range(8)] + self.ef[s:s+8] = [(i & 2**x) != 0 for x in range(8)] + s += 8 + s = 0 + for i in range(16): + self.d[s:s+4] = [i & 2**x for x in range(4)] + self.ed[s:s+4] = [(i & 2**x) != 0 for x in range(4)] + s += 4 + + self.nf = self.f.copy() + self.nd = self.d.copy() + self.nf[self.ef] = np.nan + self.nd[self.ed] = np.nan + + self.inff = self.f.copy() + self.infd = self.d.copy() + self.inff[::3][self.ef[::3]] = np.inf + self.infd[::3][self.ed[::3]] = np.inf + self.inff[1::3][self.ef[1::3]] = -np.inf + self.infd[1::3][self.ed[1::3]] = -np.inf + self.inff[2::3][self.ef[2::3]] = np.nan + self.infd[2::3][self.ed[2::3]] = np.nan + self.efnonan = self.ef.copy() + self.efnonan[2::3] = False + self.ednonan = self.ed.copy() + self.ednonan[2::3] = False + + self.signf = self.f.copy() + self.signd = self.d.copy() + self.signf[self.ef] *= -1. + self.signd[self.ed] *= -1. + self.signf[1::6][self.ef[1::6]] = -np.inf + self.signd[1::6][self.ed[1::6]] = -np.inf + self.signf[3::6][self.ef[3::6]] = -np.nan + self.signd[3::6][self.ed[3::6]] = -np.nan + self.signf[4::6][self.ef[4::6]] = -0. + self.signd[4::6][self.ed[4::6]] = -0. + + def test_float(self): + # offset for alignment test + for i in range(4): + assert_array_equal(self.f[i:] > 0, self.ef[i:]) + assert_array_equal(self.f[i:] - 1 >= 0, self.ef[i:]) + assert_array_equal(self.f[i:] == 0, ~self.ef[i:]) + assert_array_equal(-self.f[i:] < 0, self.ef[i:]) + assert_array_equal(-self.f[i:] + 1 <= 0, self.ef[i:]) + r = self.f[i:] != 0 + assert_array_equal(r, self.ef[i:]) + r2 = self.f[i:] != np.zeros_like(self.f[i:]) + r3 = 0 != self.f[i:] + assert_array_equal(r, r2) + assert_array_equal(r, r3) + # check bool == 0x1 + assert_array_equal(r.view(np.int8), r.astype(np.int8)) + assert_array_equal(r2.view(np.int8), r2.astype(np.int8)) + assert_array_equal(r3.view(np.int8), r3.astype(np.int8)) + + # isnan on amd64 takes the same code path + assert_array_equal(np.isnan(self.nf[i:]), self.ef[i:]) + assert_array_equal(np.isfinite(self.nf[i:]), ~self.ef[i:]) + assert_array_equal(np.isfinite(self.inff[i:]), ~self.ef[i:]) + assert_array_equal(np.isinf(self.inff[i:]), self.efnonan[i:]) + assert_array_equal(np.signbit(self.signf[i:]), self.ef[i:]) + + def test_double(self): + # offset for alignment test + for i in range(2): + assert_array_equal(self.d[i:] > 0, self.ed[i:]) + assert_array_equal(self.d[i:] - 1 >= 0, self.ed[i:]) + assert_array_equal(self.d[i:] == 0, ~self.ed[i:]) + assert_array_equal(-self.d[i:] < 0, self.ed[i:]) + assert_array_equal(-self.d[i:] + 1 <= 0, self.ed[i:]) + r = self.d[i:] != 0 + assert_array_equal(r, self.ed[i:]) + r2 = self.d[i:] != np.zeros_like(self.d[i:]) + r3 = 0 != self.d[i:] + assert_array_equal(r, r2) + assert_array_equal(r, r3) + # check bool == 0x1 + assert_array_equal(r.view(np.int8), r.astype(np.int8)) + assert_array_equal(r2.view(np.int8), r2.astype(np.int8)) + assert_array_equal(r3.view(np.int8), r3.astype(np.int8)) + + # isnan on amd64 takes the same code path + assert_array_equal(np.isnan(self.nd[i:]), self.ed[i:]) + assert_array_equal(np.isfinite(self.nd[i:]), ~self.ed[i:]) + assert_array_equal(np.isfinite(self.infd[i:]), ~self.ed[i:]) + assert_array_equal(np.isinf(self.infd[i:]), self.ednonan[i:]) + assert_array_equal(np.signbit(self.signd[i:]), self.ed[i:]) + + +class TestSeterr(object): + def test_default(self): + err = np.geterr() + assert_equal(err, + dict(divide='warn', + invalid='warn', + over='warn', + under='ignore') + ) + + def test_set(self): + with np.errstate(): + err = np.seterr() + old = np.seterr(divide='print') + assert_(err == old) + new = np.seterr() + assert_(new['divide'] == 'print') + np.seterr(over='raise') + assert_(np.geterr()['over'] == 'raise') + assert_(new['divide'] == 'print') + np.seterr(**old) + assert_(np.geterr() == old) + + @dec.skipif(platform.machine() == "armv5tel", "See gh-413.") + def test_divide_err(self): + with np.errstate(divide='raise'): + try: + np.array([1.]) / np.array([0.]) + except FloatingPointError: + pass + else: + self.fail() + np.seterr(divide='ignore') + np.array([1.]) / np.array([0.]) + + def test_errobj(self): + olderrobj = np.geterrobj() + self.called = 0 + try: + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + with np.errstate(divide='warn'): + np.seterrobj([20000, 1, None]) + np.array([1.]) / np.array([0.]) + assert_equal(len(w), 1) + + def log_err(*args): + self.called += 1 + extobj_err = args + assert_(len(extobj_err) == 2) + assert_("divide" in extobj_err[0]) + + with np.errstate(divide='ignore'): + np.seterrobj([20000, 3, log_err]) + np.array([1.]) / np.array([0.]) + assert_equal(self.called, 1) + + np.seterrobj(olderrobj) + with np.errstate(divide='ignore'): + np.divide(1., 0., extobj=[20000, 3, log_err]) + assert_equal(self.called, 2) + finally: + np.seterrobj(olderrobj) + del self.called + + def test_errobj_noerrmask(self): + # errmask = 0 has a special code path for the default + olderrobj = np.geterrobj() + try: + # set errobj to something non default + np.seterrobj([umath.UFUNC_BUFSIZE_DEFAULT, + umath.ERR_DEFAULT + 1, None]) + # call a ufunc + np.isnan(np.array([6])) + # same with the default, lots of times to get rid of possible + # pre-existing stack in the code + for i in range(10000): + np.seterrobj([umath.UFUNC_BUFSIZE_DEFAULT, umath.ERR_DEFAULT, + None]) + np.isnan(np.array([6])) + finally: + np.seterrobj(olderrobj) + + +class TestFloatExceptions(object): + def assert_raises_fpe(self, fpeerr, flop, x, y): + ftype = type(x) + try: + flop(x, y) + assert_(False, + "Type %s did not raise fpe error '%s'." % (ftype, fpeerr)) + except FloatingPointError as exc: + assert_(str(exc).find(fpeerr) >= 0, + "Type %s raised wrong fpe error '%s'." % (ftype, exc)) + + def assert_op_raises_fpe(self, fpeerr, flop, sc1, sc2): + # Check that fpe exception is raised. + # + # Given a floating operation `flop` and two scalar values, check that + # the operation raises the floating point exception specified by + # `fpeerr`. Tests all variants with 0-d array scalars as well. + + self.assert_raises_fpe(fpeerr, flop, sc1, sc2) + self.assert_raises_fpe(fpeerr, flop, sc1[()], sc2) + self.assert_raises_fpe(fpeerr, flop, sc1, sc2[()]) + self.assert_raises_fpe(fpeerr, flop, sc1[()], sc2[()]) + + @dec.knownfailureif(True, "See ticket #2350") + def test_floating_exceptions(self): + # Test basic arithmetic function errors + with np.errstate(all='raise'): + # Test for all real and complex float types + for typecode in np.typecodes['AllFloat']: + ftype = np.obj2sctype(typecode) + if np.dtype(ftype).kind == 'f': + # Get some extreme values for the type + fi = np.finfo(ftype) + ft_tiny = fi.tiny + ft_max = fi.max + ft_eps = fi.eps + underflow = 'underflow' + divbyzero = 'divide by zero' + else: + # 'c', complex, corresponding real dtype + rtype = type(ftype(0).real) + fi = np.finfo(rtype) + ft_tiny = ftype(fi.tiny) + ft_max = ftype(fi.max) + ft_eps = ftype(fi.eps) + # The complex types raise different exceptions + underflow = '' + divbyzero = '' + overflow = 'overflow' + invalid = 'invalid' + + self.assert_raises_fpe(underflow, + lambda a, b: a/b, ft_tiny, ft_max) + self.assert_raises_fpe(underflow, + lambda a, b: a*b, ft_tiny, ft_tiny) + self.assert_raises_fpe(overflow, + lambda a, b: a*b, ft_max, ftype(2)) + self.assert_raises_fpe(overflow, + lambda a, b: a/b, ft_max, ftype(0.5)) + self.assert_raises_fpe(overflow, + lambda a, b: a+b, ft_max, ft_max*ft_eps) + self.assert_raises_fpe(overflow, + lambda a, b: a-b, -ft_max, ft_max*ft_eps) + self.assert_raises_fpe(overflow, + np.power, ftype(2), ftype(2**fi.nexp)) + self.assert_raises_fpe(divbyzero, + lambda a, b: a/b, ftype(1), ftype(0)) + self.assert_raises_fpe(invalid, + lambda a, b: a/b, ftype(np.inf), ftype(np.inf)) + self.assert_raises_fpe(invalid, + lambda a, b: a/b, ftype(0), ftype(0)) + self.assert_raises_fpe(invalid, + lambda a, b: a-b, ftype(np.inf), ftype(np.inf)) + self.assert_raises_fpe(invalid, + lambda a, b: a+b, ftype(np.inf), ftype(-np.inf)) + self.assert_raises_fpe(invalid, + lambda a, b: a*b, ftype(0), ftype(np.inf)) + + def test_warnings(self): + # test warning code path + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + with np.errstate(all="warn"): + np.divide(1, 0.) + assert_equal(len(w), 1) + assert_("divide by zero" in str(w[0].message)) + np.array(1e300) * np.array(1e300) + assert_equal(len(w), 2) + assert_("overflow" in str(w[-1].message)) + np.array(np.inf) - np.array(np.inf) + assert_equal(len(w), 3) + assert_("invalid value" in str(w[-1].message)) + np.array(1e-300) * np.array(1e-300) + assert_equal(len(w), 4) + assert_("underflow" in str(w[-1].message)) + + +class TestTypes(object): + def check_promotion_cases(self, promote_func): + # tests that the scalars get coerced correctly. + b = np.bool_(0) + i8, i16, i32, i64 = np.int8(0), np.int16(0), np.int32(0), np.int64(0) + u8, u16, u32, u64 = np.uint8(0), np.uint16(0), np.uint32(0), np.uint64(0) + f32, f64, fld = np.float32(0), np.float64(0), np.longdouble(0) + c64, c128, cld = np.complex64(0), np.complex128(0), np.clongdouble(0) + + # coercion within the same kind + assert_equal(promote_func(i8, i16), np.dtype(np.int16)) + assert_equal(promote_func(i32, i8), np.dtype(np.int32)) + assert_equal(promote_func(i16, i64), np.dtype(np.int64)) + assert_equal(promote_func(u8, u32), np.dtype(np.uint32)) + assert_equal(promote_func(f32, f64), np.dtype(np.float64)) + assert_equal(promote_func(fld, f32), np.dtype(np.longdouble)) + assert_equal(promote_func(f64, fld), np.dtype(np.longdouble)) + assert_equal(promote_func(c128, c64), np.dtype(np.complex128)) + assert_equal(promote_func(cld, c128), np.dtype(np.clongdouble)) + assert_equal(promote_func(c64, fld), np.dtype(np.clongdouble)) + + # coercion between kinds + assert_equal(promote_func(b, i32), np.dtype(np.int32)) + assert_equal(promote_func(b, u8), np.dtype(np.uint8)) + assert_equal(promote_func(i8, u8), np.dtype(np.int16)) + assert_equal(promote_func(u8, i32), np.dtype(np.int32)) + assert_equal(promote_func(i64, u32), np.dtype(np.int64)) + assert_equal(promote_func(u64, i32), np.dtype(np.float64)) + assert_equal(promote_func(i32, f32), np.dtype(np.float64)) + assert_equal(promote_func(i64, f32), np.dtype(np.float64)) + assert_equal(promote_func(f32, i16), np.dtype(np.float32)) + assert_equal(promote_func(f32, u32), np.dtype(np.float64)) + assert_equal(promote_func(f32, c64), np.dtype(np.complex64)) + assert_equal(promote_func(c128, f32), np.dtype(np.complex128)) + assert_equal(promote_func(cld, f64), np.dtype(np.clongdouble)) + + # coercion between scalars and 1-D arrays + assert_equal(promote_func(np.array([b]), i8), np.dtype(np.int8)) + assert_equal(promote_func(np.array([b]), u8), np.dtype(np.uint8)) + assert_equal(promote_func(np.array([b]), i32), np.dtype(np.int32)) + assert_equal(promote_func(np.array([b]), u32), np.dtype(np.uint32)) + assert_equal(promote_func(np.array([i8]), i64), np.dtype(np.int8)) + assert_equal(promote_func(u64, np.array([i32])), np.dtype(np.int32)) + assert_equal(promote_func(i64, np.array([u32])), np.dtype(np.uint32)) + assert_equal(promote_func(np.int32(-1), np.array([u64])), + np.dtype(np.float64)) + assert_equal(promote_func(f64, np.array([f32])), np.dtype(np.float32)) + assert_equal(promote_func(fld, np.array([f32])), np.dtype(np.float32)) + assert_equal(promote_func(np.array([f64]), fld), np.dtype(np.float64)) + assert_equal(promote_func(fld, np.array([c64])), + np.dtype(np.complex64)) + assert_equal(promote_func(c64, np.array([f64])), + np.dtype(np.complex128)) + assert_equal(promote_func(np.complex64(3j), np.array([f64])), + np.dtype(np.complex128)) + + # coercion between scalars and 1-D arrays, where + # the scalar has greater kind than the array + assert_equal(promote_func(np.array([b]), f64), np.dtype(np.float64)) + assert_equal(promote_func(np.array([b]), i64), np.dtype(np.int64)) + assert_equal(promote_func(np.array([b]), u64), np.dtype(np.uint64)) + assert_equal(promote_func(np.array([i8]), f64), np.dtype(np.float64)) + assert_equal(promote_func(np.array([u16]), f64), np.dtype(np.float64)) + + # uint and int are treated as the same "kind" for + # the purposes of array-scalar promotion. + assert_equal(promote_func(np.array([u16]), i32), np.dtype(np.uint16)) + + # float and complex are treated as the same "kind" for + # the purposes of array-scalar promotion, so that you can do + # (0j + float32array) to get a complex64 array instead of + # a complex128 array. + assert_equal(promote_func(np.array([f32]), c128), + np.dtype(np.complex64)) + + def test_coercion(self): + def res_type(a, b): + return np.add(a, b).dtype + + self.check_promotion_cases(res_type) + + # Use-case: float/complex scalar * bool/int8 array + # shouldn't narrow the float/complex type + for a in [np.array([True, False]), np.array([-3, 12], dtype=np.int8)]: + b = 1.234 * a + assert_equal(b.dtype, np.dtype('f8'), "array type %s" % a.dtype) + b = np.longdouble(1.234) * a + assert_equal(b.dtype, np.dtype(np.longdouble), + "array type %s" % a.dtype) + b = np.float64(1.234) * a + assert_equal(b.dtype, np.dtype('f8'), "array type %s" % a.dtype) + b = np.float32(1.234) * a + assert_equal(b.dtype, np.dtype('f4'), "array type %s" % a.dtype) + b = np.float16(1.234) * a + assert_equal(b.dtype, np.dtype('f2'), "array type %s" % a.dtype) + + b = 1.234j * a + assert_equal(b.dtype, np.dtype('c16'), "array type %s" % a.dtype) + b = np.clongdouble(1.234j) * a + assert_equal(b.dtype, np.dtype(np.clongdouble), + "array type %s" % a.dtype) + b = np.complex128(1.234j) * a + assert_equal(b.dtype, np.dtype('c16'), "array type %s" % a.dtype) + b = np.complex64(1.234j) * a + assert_equal(b.dtype, np.dtype('c8'), "array type %s" % a.dtype) + + # The following use-case is problematic, and to resolve its + # tricky side-effects requires more changes. + # + # Use-case: (1-t)*a, where 't' is a boolean array and 'a' is + # a float32, shouldn't promote to float64 + # + # a = np.array([1.0, 1.5], dtype=np.float32) + # t = np.array([True, False]) + # b = t*a + # assert_equal(b, [1.0, 0.0]) + # assert_equal(b.dtype, np.dtype('f4')) + # b = (1-t)*a + # assert_equal(b, [0.0, 1.5]) + # assert_equal(b.dtype, np.dtype('f4')) + # + # Probably ~t (bitwise negation) is more proper to use here, + # but this is arguably less intuitive to understand at a glance, and + # would fail if 't' is actually an integer array instead of boolean: + # + # b = (~t)*a + # assert_equal(b, [0.0, 1.5]) + # assert_equal(b.dtype, np.dtype('f4')) + + def test_result_type(self): + self.check_promotion_cases(np.result_type) + assert_(np.result_type(None) == np.dtype(None)) + + def test_promote_types_endian(self): + # promote_types should always return native-endian types + assert_equal(np.promote_types('i8', '>i8'), np.dtype('i8')) + + assert_equal(np.promote_types('>i8', '>U16'), np.dtype('U21')) + assert_equal(np.promote_types('U16', '>i8'), np.dtype('U21')) + assert_equal(np.promote_types('S5', '>U8'), np.dtype('U8')) + assert_equal(np.promote_types('U8', '>S5'), np.dtype('U8')) + assert_equal(np.promote_types('U8', '>U5'), np.dtype('U8')) + + assert_equal(np.promote_types('M8', '>M8'), np.dtype('M8')) + assert_equal(np.promote_types('m8', '>m8'), np.dtype('m8')) + + def test_promote_types_strings(self): + assert_equal(np.promote_types('bool', 'S'), np.dtype('S5')) + assert_equal(np.promote_types('b', 'S'), np.dtype('S4')) + assert_equal(np.promote_types('u1', 'S'), np.dtype('S3')) + assert_equal(np.promote_types('u2', 'S'), np.dtype('S5')) + assert_equal(np.promote_types('u4', 'S'), np.dtype('S10')) + assert_equal(np.promote_types('u8', 'S'), np.dtype('S20')) + assert_equal(np.promote_types('i1', 'S'), np.dtype('S4')) + assert_equal(np.promote_types('i2', 'S'), np.dtype('S6')) + assert_equal(np.promote_types('i4', 'S'), np.dtype('S11')) + assert_equal(np.promote_types('i8', 'S'), np.dtype('S21')) + assert_equal(np.promote_types('bool', 'U'), np.dtype('U5')) + assert_equal(np.promote_types('b', 'U'), np.dtype('U4')) + assert_equal(np.promote_types('u1', 'U'), np.dtype('U3')) + assert_equal(np.promote_types('u2', 'U'), np.dtype('U5')) + assert_equal(np.promote_types('u4', 'U'), np.dtype('U10')) + assert_equal(np.promote_types('u8', 'U'), np.dtype('U20')) + assert_equal(np.promote_types('i1', 'U'), np.dtype('U4')) + assert_equal(np.promote_types('i2', 'U'), np.dtype('U6')) + assert_equal(np.promote_types('i4', 'U'), np.dtype('U11')) + assert_equal(np.promote_types('i8', 'U'), np.dtype('U21')) + assert_equal(np.promote_types('bool', 'S1'), np.dtype('S5')) + assert_equal(np.promote_types('bool', 'S30'), np.dtype('S30')) + assert_equal(np.promote_types('b', 'S1'), np.dtype('S4')) + assert_equal(np.promote_types('b', 'S30'), np.dtype('S30')) + assert_equal(np.promote_types('u1', 'S1'), np.dtype('S3')) + assert_equal(np.promote_types('u1', 'S30'), np.dtype('S30')) + assert_equal(np.promote_types('u2', 'S1'), np.dtype('S5')) + assert_equal(np.promote_types('u2', 'S30'), np.dtype('S30')) + assert_equal(np.promote_types('u4', 'S1'), np.dtype('S10')) + assert_equal(np.promote_types('u4', 'S30'), np.dtype('S30')) + assert_equal(np.promote_types('u8', 'S1'), np.dtype('S20')) + assert_equal(np.promote_types('u8', 'S30'), np.dtype('S30')) + + def test_can_cast(self): + assert_(np.can_cast(np.int32, np.int64)) + assert_(np.can_cast(np.float64, complex)) + assert_(not np.can_cast(complex, float)) + + assert_(np.can_cast('i8', 'f8')) + assert_(not np.can_cast('i8', 'f4')) + assert_(np.can_cast('i4', 'S11')) + + assert_(np.can_cast('i8', 'i8', 'no')) + assert_(not np.can_cast('i8', 'no')) + + assert_(np.can_cast('i8', 'equiv')) + assert_(not np.can_cast('i8', 'equiv')) + + assert_(np.can_cast('i8', 'safe')) + assert_(not np.can_cast('i4', 'safe')) + + assert_(np.can_cast('i4', 'same_kind')) + assert_(not np.can_cast('u4', 'same_kind')) + + assert_(np.can_cast('u4', 'unsafe')) + + assert_(np.can_cast('bool', 'S5')) + assert_(not np.can_cast('bool', 'S4')) + + assert_(np.can_cast('b', 'S4')) + assert_(not np.can_cast('b', 'S3')) + + assert_(np.can_cast('u1', 'S3')) + assert_(not np.can_cast('u1', 'S2')) + assert_(np.can_cast('u2', 'S5')) + assert_(not np.can_cast('u2', 'S4')) + assert_(np.can_cast('u4', 'S10')) + assert_(not np.can_cast('u4', 'S9')) + assert_(np.can_cast('u8', 'S20')) + assert_(not np.can_cast('u8', 'S19')) + + assert_(np.can_cast('i1', 'S4')) + assert_(not np.can_cast('i1', 'S3')) + assert_(np.can_cast('i2', 'S6')) + assert_(not np.can_cast('i2', 'S5')) + assert_(np.can_cast('i4', 'S11')) + assert_(not np.can_cast('i4', 'S10')) + assert_(np.can_cast('i8', 'S21')) + assert_(not np.can_cast('i8', 'S20')) + + assert_(np.can_cast('bool', 'S5')) + assert_(not np.can_cast('bool', 'S4')) + + assert_(np.can_cast('b', 'U4')) + assert_(not np.can_cast('b', 'U3')) + + assert_(np.can_cast('u1', 'U3')) + assert_(not np.can_cast('u1', 'U2')) + assert_(np.can_cast('u2', 'U5')) + assert_(not np.can_cast('u2', 'U4')) + assert_(np.can_cast('u4', 'U10')) + assert_(not np.can_cast('u4', 'U9')) + assert_(np.can_cast('u8', 'U20')) + assert_(not np.can_cast('u8', 'U19')) + + assert_(np.can_cast('i1', 'U4')) + assert_(not np.can_cast('i1', 'U3')) + assert_(np.can_cast('i2', 'U6')) + assert_(not np.can_cast('i2', 'U5')) + assert_(np.can_cast('i4', 'U11')) + assert_(not np.can_cast('i4', 'U10')) + assert_(np.can_cast('i8', 'U21')) + assert_(not np.can_cast('i8', 'U20')) + + assert_raises(TypeError, np.can_cast, 'i4', None) + assert_raises(TypeError, np.can_cast, None, 'i4') + + # Also test keyword arguments + assert_(np.can_cast(from_=np.int32, to=np.int64)) + + def test_can_cast_values(self): + # gh-5917 + for dt in np.sctypes['int'] + np.sctypes['uint']: + ii = np.iinfo(dt) + assert_(np.can_cast(ii.min, dt)) + assert_(np.can_cast(ii.max, dt)) + assert_(not np.can_cast(ii.min - 1, dt)) + assert_(not np.can_cast(ii.max + 1, dt)) + + for dt in np.sctypes['float']: + fi = np.finfo(dt) + assert_(np.can_cast(fi.min, dt)) + assert_(np.can_cast(fi.max, dt)) + + +# Custom exception class to test exception propagation in fromiter +class NIterError(Exception): + pass + + +class TestFromiter(object): + def makegen(self): + for x in range(24): + yield x**2 + + def test_types(self): + ai32 = np.fromiter(self.makegen(), np.int32) + ai64 = np.fromiter(self.makegen(), np.int64) + af = np.fromiter(self.makegen(), float) + assert_(ai32.dtype == np.dtype(np.int32)) + assert_(ai64.dtype == np.dtype(np.int64)) + assert_(af.dtype == np.dtype(float)) + + def test_lengths(self): + expected = np.array(list(self.makegen())) + a = np.fromiter(self.makegen(), int) + a20 = np.fromiter(self.makegen(), int, 20) + assert_(len(a) == len(expected)) + assert_(len(a20) == 20) + assert_raises(ValueError, np.fromiter, + self.makegen(), int, len(expected) + 10) + + def test_values(self): + expected = np.array(list(self.makegen())) + a = np.fromiter(self.makegen(), int) + a20 = np.fromiter(self.makegen(), int, 20) + assert_(np.alltrue(a == expected, axis=0)) + assert_(np.alltrue(a20 == expected[:20], axis=0)) + + def load_data(self, n, eindex): + # Utility method for the issue 2592 tests. + # Raise an exception at the desired index in the iterator. + for e in range(n): + if e == eindex: + raise NIterError('error at index %s' % eindex) + yield e + + def test_2592(self): + # Test iteration exceptions are correctly raised. + count, eindex = 10, 5 + assert_raises(NIterError, np.fromiter, + self.load_data(count, eindex), dtype=int, count=count) + + def test_2592_edge(self): + # Test iter. exceptions, edge case (exception at end of iterator). + count = 10 + eindex = count-1 + assert_raises(NIterError, np.fromiter, + self.load_data(count, eindex), dtype=int, count=count) + + +class TestNonzero(object): + def test_nonzero_trivial(self): + assert_equal(np.count_nonzero(np.array([])), 0) + assert_equal(np.count_nonzero(np.array([], dtype='?')), 0) + assert_equal(np.nonzero(np.array([])), ([],)) + + assert_equal(np.count_nonzero(np.array(0)), 0) + assert_equal(np.count_nonzero(np.array(0, dtype='?')), 0) + assert_equal(np.nonzero(np.array(0)), ([],)) + assert_equal(np.count_nonzero(np.array(1)), 1) + assert_equal(np.count_nonzero(np.array(1, dtype='?')), 1) + assert_equal(np.nonzero(np.array(1)), ([0],)) + + def test_nonzero_onedim(self): + x = np.array([1, 0, 2, -1, 0, 0, 8]) + assert_equal(np.count_nonzero(x), 4) + assert_equal(np.count_nonzero(x), 4) + assert_equal(np.nonzero(x), ([0, 2, 3, 6],)) + + x = np.array([(1, 2), (0, 0), (1, 1), (-1, 3), (0, 7)], + dtype=[('a', 'i4'), ('b', 'i2')]) + assert_equal(np.count_nonzero(x['a']), 3) + assert_equal(np.count_nonzero(x['b']), 4) + assert_equal(np.nonzero(x['a']), ([0, 2, 3],)) + assert_equal(np.nonzero(x['b']), ([0, 2, 3, 4],)) + + def test_nonzero_twodim(self): + x = np.array([[0, 1, 0], [2, 0, 3]]) + assert_equal(np.count_nonzero(x), 3) + assert_equal(np.nonzero(x), ([0, 1, 1], [1, 0, 2])) + + x = np.eye(3) + assert_equal(np.count_nonzero(x), 3) + assert_equal(np.nonzero(x), ([0, 1, 2], [0, 1, 2])) + + x = np.array([[(0, 1), (0, 0), (1, 11)], + [(1, 1), (1, 0), (0, 0)], + [(0, 0), (1, 5), (0, 1)]], dtype=[('a', 'f4'), ('b', 'u1')]) + assert_equal(np.count_nonzero(x['a']), 4) + assert_equal(np.count_nonzero(x['b']), 5) + assert_equal(np.nonzero(x['a']), ([0, 1, 1, 2], [2, 0, 1, 1])) + assert_equal(np.nonzero(x['b']), ([0, 0, 1, 2, 2], [0, 2, 0, 1, 2])) + + assert_(not x['a'].T.flags.aligned) + assert_equal(np.count_nonzero(x['a'].T), 4) + assert_equal(np.count_nonzero(x['b'].T), 5) + assert_equal(np.nonzero(x['a'].T), ([0, 1, 1, 2], [1, 1, 2, 0])) + assert_equal(np.nonzero(x['b'].T), ([0, 0, 1, 2, 2], [0, 1, 2, 0, 2])) + + def test_sparse(self): + # test special sparse condition boolean code path + for i in range(20): + c = np.zeros(200, dtype=bool) + c[i::20] = True + assert_equal(np.nonzero(c)[0], np.arange(i, 200 + i, 20)) + + c = np.zeros(400, dtype=bool) + c[10 + i:20 + i] = True + c[20 + i*2] = True + assert_equal(np.nonzero(c)[0], + np.concatenate((np.arange(10 + i, 20 + i), [20 + i*2]))) + + def test_return_type(self): + class C(np.ndarray): + pass + + for view in (C, np.ndarray): + for nd in range(1, 4): + shape = tuple(range(2, 2+nd)) + x = np.arange(np.prod(shape)).reshape(shape).view(view) + for nzx in (np.nonzero(x), x.nonzero()): + for nzx_i in nzx: + assert_(type(nzx_i) is np.ndarray) + assert_(nzx_i.flags.writeable) + + def test_count_nonzero_axis(self): + # Basic check of functionality + m = np.array([[0, 1, 7, 0, 0], [3, 0, 0, 2, 19]]) + + expected = np.array([1, 1, 1, 1, 1]) + assert_equal(np.count_nonzero(m, axis=0), expected) + + expected = np.array([2, 3]) + assert_equal(np.count_nonzero(m, axis=1), expected) + + assert_raises(ValueError, np.count_nonzero, m, axis=(1, 1)) + assert_raises(TypeError, np.count_nonzero, m, axis='foo') + assert_raises(np.AxisError, np.count_nonzero, m, axis=3) + assert_raises(TypeError, np.count_nonzero, + m, axis=np.array([[1], [2]])) + + def test_count_nonzero_axis_all_dtypes(self): + # More thorough test that the axis argument is respected + # for all dtypes and responds correctly when presented with + # either integer or tuple arguments for axis + msg = "Mismatch for dtype: %s" + + def assert_equal_w_dt(a, b, err_msg): + assert_equal(a.dtype, b.dtype, err_msg=err_msg) + assert_equal(a, b, err_msg=err_msg) + + for dt in np.typecodes['All']: + err_msg = msg % (np.dtype(dt).name,) + + if dt != 'V': + if dt != 'M': + m = np.zeros((3, 3), dtype=dt) + n = np.ones(1, dtype=dt) + + m[0, 0] = n[0] + m[1, 0] = n[0] + + else: # np.zeros doesn't work for np.datetime64 + m = np.array(['1970-01-01'] * 9) + m = m.reshape((3, 3)) + + m[0, 0] = '1970-01-12' + m[1, 0] = '1970-01-12' + m = m.astype(dt) + + expected = np.array([2, 0, 0], dtype=np.intp) + assert_equal_w_dt(np.count_nonzero(m, axis=0), + expected, err_msg=err_msg) + + expected = np.array([1, 1, 0], dtype=np.intp) + assert_equal_w_dt(np.count_nonzero(m, axis=1), + expected, err_msg=err_msg) + + expected = np.array(2) + assert_equal(np.count_nonzero(m, axis=(0, 1)), + expected, err_msg=err_msg) + assert_equal(np.count_nonzero(m, axis=None), + expected, err_msg=err_msg) + assert_equal(np.count_nonzero(m), + expected, err_msg=err_msg) + + if dt == 'V': + # There are no 'nonzero' objects for np.void, so the testing + # setup is slightly different for this dtype + m = np.array([np.void(1)] * 6).reshape((2, 3)) + + expected = np.array([0, 0, 0], dtype=np.intp) + assert_equal_w_dt(np.count_nonzero(m, axis=0), + expected, err_msg=err_msg) + + expected = np.array([0, 0], dtype=np.intp) + assert_equal_w_dt(np.count_nonzero(m, axis=1), + expected, err_msg=err_msg) + + expected = np.array(0) + assert_equal(np.count_nonzero(m, axis=(0, 1)), + expected, err_msg=err_msg) + assert_equal(np.count_nonzero(m, axis=None), + expected, err_msg=err_msg) + assert_equal(np.count_nonzero(m), + expected, err_msg=err_msg) + + def test_count_nonzero_axis_consistent(self): + # Check that the axis behaviour for valid axes in + # non-special cases is consistent (and therefore + # correct) by checking it against an integer array + # that is then casted to the generic object dtype + from itertools import combinations, permutations + + axis = (0, 1, 2, 3) + size = (5, 5, 5, 5) + msg = "Mismatch for axis: %s" + + rng = np.random.RandomState(1234) + m = rng.randint(-100, 100, size=size) + n = m.astype(object) + + for length in range(len(axis)): + for combo in combinations(axis, length): + for perm in permutations(combo): + assert_equal( + np.count_nonzero(m, axis=perm), + np.count_nonzero(n, axis=perm), + err_msg=msg % (perm,)) + + def test_countnonzero_axis_empty(self): + a = np.array([[0, 0, 1], [1, 0, 1]]) + assert_equal(np.count_nonzero(a, axis=()), a.astype(bool)) + + def test_array_method(self): + # Tests that the array method + # call to nonzero works + m = np.array([[1, 0, 0], [4, 0, 6]]) + tgt = [[0, 1, 1], [0, 0, 2]] + + assert_equal(m.nonzero(), tgt) + + def test_nonzero_invalid_object(self): + # gh-9295 + a = np.array([np.array([1, 2]), 3]) + assert_raises(ValueError, np.nonzero, a) + + class BoolErrors: + def __bool__(self): + raise ValueError("Not allowed") + def __nonzero__(self): + raise ValueError("Not allowed") + + assert_raises(ValueError, np.nonzero, np.array([BoolErrors()])) + + +class TestIndex(object): + def test_boolean(self): + a = rand(3, 5, 8) + V = rand(5, 8) + g1 = randint(0, 5, size=15) + g2 = randint(0, 8, size=15) + V[g1, g2] = -V[g1, g2] + assert_((np.array([a[0][V > 0], a[1][V > 0], a[2][V > 0]]) == a[:, V > 0]).all()) + + def test_boolean_edgecase(self): + a = np.array([], dtype='int32') + b = np.array([], dtype='bool') + c = a[b] + assert_equal(c, []) + assert_equal(c.dtype, np.dtype('int32')) + + +class TestBinaryRepr(object): + def test_zero(self): + assert_equal(np.binary_repr(0), '0') + + def test_positive(self): + assert_equal(np.binary_repr(10), '1010') + assert_equal(np.binary_repr(12522), + '11000011101010') + assert_equal(np.binary_repr(10736848), + '101000111101010011010000') + + def test_negative(self): + assert_equal(np.binary_repr(-1), '-1') + assert_equal(np.binary_repr(-10), '-1010') + assert_equal(np.binary_repr(-12522), + '-11000011101010') + assert_equal(np.binary_repr(-10736848), + '-101000111101010011010000') + + def test_sufficient_width(self): + assert_equal(np.binary_repr(0, width=5), '00000') + assert_equal(np.binary_repr(10, width=7), '0001010') + assert_equal(np.binary_repr(-5, width=7), '1111011') + + def test_neg_width_boundaries(self): + # see gh-8670 + + # Ensure that the example in the issue does not + # break before proceeding to a more thorough test. + assert_equal(np.binary_repr(-128, width=8), '10000000') + + for width in range(1, 11): + num = -2**(width - 1) + exp = '1' + (width - 1) * '0' + assert_equal(np.binary_repr(num, width=width), exp) + + +class TestBaseRepr(object): + def test_base3(self): + assert_equal(np.base_repr(3**5, 3), '100000') + + def test_positive(self): + assert_equal(np.base_repr(12, 10), '12') + assert_equal(np.base_repr(12, 10, 4), '000012') + assert_equal(np.base_repr(12, 4), '30') + assert_equal(np.base_repr(3731624803700888, 36), '10QR0ROFCEW') + + def test_negative(self): + assert_equal(np.base_repr(-12, 10), '-12') + assert_equal(np.base_repr(-12, 10, 4), '-000012') + assert_equal(np.base_repr(-12, 4), '-30') + + def test_base_range(self): + with assert_raises(ValueError): + np.base_repr(1, 1) + with assert_raises(ValueError): + np.base_repr(1, 37) + + +class TestArrayComparisons(object): + def test_array_equal(self): + res = np.array_equal(np.array([1, 2]), np.array([1, 2])) + assert_(res) + assert_(type(res) is bool) + res = np.array_equal(np.array([1, 2]), np.array([1, 2, 3])) + assert_(not res) + assert_(type(res) is bool) + res = np.array_equal(np.array([1, 2]), np.array([3, 4])) + assert_(not res) + assert_(type(res) is bool) + res = np.array_equal(np.array([1, 2]), np.array([1, 3])) + assert_(not res) + assert_(type(res) is bool) + res = np.array_equal(np.array(['a'], dtype='S1'), np.array(['a'], dtype='S1')) + assert_(res) + assert_(type(res) is bool) + res = np.array_equal(np.array([('a', 1)], dtype='S1,u4'), + np.array([('a', 1)], dtype='S1,u4')) + assert_(res) + assert_(type(res) is bool) + + def test_none_compares_elementwise(self): + a = np.array([None, 1, None], dtype=object) + assert_equal(a == None, [True, False, True]) + assert_equal(a != None, [False, True, False]) + + a = np.ones(3) + assert_equal(a == None, [False, False, False]) + assert_equal(a != None, [True, True, True]) + + + def test_array_equiv(self): + res = np.array_equiv(np.array([1, 2]), np.array([1, 2])) + assert_(res) + assert_(type(res) is bool) + res = np.array_equiv(np.array([1, 2]), np.array([1, 2, 3])) + assert_(not res) + assert_(type(res) is bool) + res = np.array_equiv(np.array([1, 2]), np.array([3, 4])) + assert_(not res) + assert_(type(res) is bool) + res = np.array_equiv(np.array([1, 2]), np.array([1, 3])) + assert_(not res) + assert_(type(res) is bool) + + res = np.array_equiv(np.array([1, 1]), np.array([1])) + assert_(res) + assert_(type(res) is bool) + res = np.array_equiv(np.array([1, 1]), np.array([[1], [1]])) + assert_(res) + assert_(type(res) is bool) + res = np.array_equiv(np.array([1, 2]), np.array([2])) + assert_(not res) + assert_(type(res) is bool) + res = np.array_equiv(np.array([1, 2]), np.array([[1], [2]])) + assert_(not res) + assert_(type(res) is bool) + res = np.array_equiv(np.array([1, 2]), np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])) + assert_(not res) + assert_(type(res) is bool) + + +def assert_array_strict_equal(x, y): + assert_array_equal(x, y) + # Check flags, 32 bit arches typically don't provide 16 byte alignment + if ((x.dtype.alignment <= 8 or + np.intp().dtype.itemsize != 4) and + sys.platform != 'win32'): + assert_(x.flags == y.flags) + else: + assert_(x.flags.owndata == y.flags.owndata) + assert_(x.flags.writeable == y.flags.writeable) + assert_(x.flags.c_contiguous == y.flags.c_contiguous) + assert_(x.flags.f_contiguous == y.flags.f_contiguous) + assert_(x.flags.writebackifcopy == y.flags.writebackifcopy) + # check endianness + assert_(x.dtype.isnative == y.dtype.isnative) + + +class TestClip(object): + def setup(self): + self.nr = 5 + self.nc = 3 + + def fastclip(self, a, m, M, out=None): + if out is None: + return a.clip(m, M) + else: + return a.clip(m, M, out) + + def clip(self, a, m, M, out=None): + # use slow-clip + selector = np.less(a, m) + 2*np.greater(a, M) + return selector.choose((a, m, M), out=out) + + # Handy functions + def _generate_data(self, n, m): + return randn(n, m) + + def _generate_data_complex(self, n, m): + return randn(n, m) + 1.j * rand(n, m) + + def _generate_flt_data(self, n, m): + return (randn(n, m)).astype(np.float32) + + def _neg_byteorder(self, a): + a = np.asarray(a) + if sys.byteorder == 'little': + a = a.astype(a.dtype.newbyteorder('>')) + else: + a = a.astype(a.dtype.newbyteorder('<')) + return a + + def _generate_non_native_data(self, n, m): + data = randn(n, m) + data = self._neg_byteorder(data) + assert_(not data.dtype.isnative) + return data + + def _generate_int_data(self, n, m): + return (10 * rand(n, m)).astype(np.int64) + + def _generate_int32_data(self, n, m): + return (10 * rand(n, m)).astype(np.int32) + + # Now the real test cases + def test_simple_double(self): + # Test native double input with scalar min/max. + a = self._generate_data(self.nr, self.nc) + m = 0.1 + M = 0.6 + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_strict_equal(ac, act) + + def test_simple_int(self): + # Test native int input with scalar min/max. + a = self._generate_int_data(self.nr, self.nc) + a = a.astype(int) + m = -2 + M = 4 + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_strict_equal(ac, act) + + def test_array_double(self): + # Test native double input with array min/max. + a = self._generate_data(self.nr, self.nc) + m = np.zeros(a.shape) + M = m + 0.5 + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_strict_equal(ac, act) + + def test_simple_nonnative(self): + # Test non native double input with scalar min/max. + # Test native double input with non native double scalar min/max. + a = self._generate_non_native_data(self.nr, self.nc) + m = -0.5 + M = 0.6 + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_equal(ac, act) + + # Test native double input with non native double scalar min/max. + a = self._generate_data(self.nr, self.nc) + m = -0.5 + M = self._neg_byteorder(0.6) + assert_(not M.dtype.isnative) + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_equal(ac, act) + + def test_simple_complex(self): + # Test native complex input with native double scalar min/max. + # Test native input with complex double scalar min/max. + a = 3 * self._generate_data_complex(self.nr, self.nc) + m = -0.5 + M = 1. + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_strict_equal(ac, act) + + # Test native input with complex double scalar min/max. + a = 3 * self._generate_data(self.nr, self.nc) + m = -0.5 + 1.j + M = 1. + 2.j + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_strict_equal(ac, act) + + def test_clip_complex(self): + # Address Issue gh-5354 for clipping complex arrays + # Test native complex input without explicit min/max + # ie, either min=None or max=None + a = np.ones(10, dtype=complex) + m = a.min() + M = a.max() + am = self.fastclip(a, m, None) + aM = self.fastclip(a, None, M) + assert_array_strict_equal(am, a) + assert_array_strict_equal(aM, a) + + def test_clip_non_contig(self): + # Test clip for non contiguous native input and native scalar min/max. + a = self._generate_data(self.nr * 2, self.nc * 3) + a = a[::2, ::3] + assert_(not a.flags['F_CONTIGUOUS']) + assert_(not a.flags['C_CONTIGUOUS']) + ac = self.fastclip(a, -1.6, 1.7) + act = self.clip(a, -1.6, 1.7) + assert_array_strict_equal(ac, act) + + def test_simple_out(self): + # Test native double input with scalar min/max. + a = self._generate_data(self.nr, self.nc) + m = -0.5 + M = 0.6 + ac = np.zeros(a.shape) + act = np.zeros(a.shape) + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_simple_int32_inout(self): + # Test native int32 input with double min/max and int32 out. + a = self._generate_int32_data(self.nr, self.nc) + m = np.float64(0) + M = np.float64(2) + ac = np.zeros(a.shape, dtype=np.int32) + act = ac.copy() + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_simple_int64_out(self): + # Test native int32 input with int32 scalar min/max and int64 out. + a = self._generate_int32_data(self.nr, self.nc) + m = np.int32(-1) + M = np.int32(1) + ac = np.zeros(a.shape, dtype=np.int64) + act = ac.copy() + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_simple_int64_inout(self): + # Test native int32 input with double array min/max and int32 out. + a = self._generate_int32_data(self.nr, self.nc) + m = np.zeros(a.shape, np.float64) + M = np.float64(1) + ac = np.zeros(a.shape, dtype=np.int32) + act = ac.copy() + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_simple_int32_out(self): + # Test native double input with scalar min/max and int out. + a = self._generate_data(self.nr, self.nc) + m = -1.0 + M = 2.0 + ac = np.zeros(a.shape, dtype=np.int32) + act = ac.copy() + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_simple_inplace_01(self): + # Test native double input with array min/max in-place. + a = self._generate_data(self.nr, self.nc) + ac = a.copy() + m = np.zeros(a.shape) + M = 1.0 + self.fastclip(a, m, M, a) + self.clip(a, m, M, ac) + assert_array_strict_equal(a, ac) + + def test_simple_inplace_02(self): + # Test native double input with scalar min/max in-place. + a = self._generate_data(self.nr, self.nc) + ac = a.copy() + m = -0.5 + M = 0.6 + self.fastclip(a, m, M, a) + self.clip(a, m, M, ac) + assert_array_strict_equal(a, ac) + + def test_noncontig_inplace(self): + # Test non contiguous double input with double scalar min/max in-place. + a = self._generate_data(self.nr * 2, self.nc * 3) + a = a[::2, ::3] + assert_(not a.flags['F_CONTIGUOUS']) + assert_(not a.flags['C_CONTIGUOUS']) + ac = a.copy() + m = -0.5 + M = 0.6 + self.fastclip(a, m, M, a) + self.clip(a, m, M, ac) + assert_array_equal(a, ac) + + def test_type_cast_01(self): + # Test native double input with scalar min/max. + a = self._generate_data(self.nr, self.nc) + m = -0.5 + M = 0.6 + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_strict_equal(ac, act) + + def test_type_cast_02(self): + # Test native int32 input with int32 scalar min/max. + a = self._generate_int_data(self.nr, self.nc) + a = a.astype(np.int32) + m = -2 + M = 4 + ac = self.fastclip(a, m, M) + act = self.clip(a, m, M) + assert_array_strict_equal(ac, act) + + def test_type_cast_03(self): + # Test native int32 input with float64 scalar min/max. + a = self._generate_int32_data(self.nr, self.nc) + m = -2 + M = 4 + ac = self.fastclip(a, np.float64(m), np.float64(M)) + act = self.clip(a, np.float64(m), np.float64(M)) + assert_array_strict_equal(ac, act) + + def test_type_cast_04(self): + # Test native int32 input with float32 scalar min/max. + a = self._generate_int32_data(self.nr, self.nc) + m = np.float32(-2) + M = np.float32(4) + act = self.fastclip(a, m, M) + ac = self.clip(a, m, M) + assert_array_strict_equal(ac, act) + + def test_type_cast_05(self): + # Test native int32 with double arrays min/max. + a = self._generate_int_data(self.nr, self.nc) + m = -0.5 + M = 1. + ac = self.fastclip(a, m * np.zeros(a.shape), M) + act = self.clip(a, m * np.zeros(a.shape), M) + assert_array_strict_equal(ac, act) + + def test_type_cast_06(self): + # Test native with NON native scalar min/max. + a = self._generate_data(self.nr, self.nc) + m = 0.5 + m_s = self._neg_byteorder(m) + M = 1. + act = self.clip(a, m_s, M) + ac = self.fastclip(a, m_s, M) + assert_array_strict_equal(ac, act) + + def test_type_cast_07(self): + # Test NON native with native array min/max. + a = self._generate_data(self.nr, self.nc) + m = -0.5 * np.ones(a.shape) + M = 1. + a_s = self._neg_byteorder(a) + assert_(not a_s.dtype.isnative) + act = a_s.clip(m, M) + ac = self.fastclip(a_s, m, M) + assert_array_strict_equal(ac, act) + + def test_type_cast_08(self): + # Test NON native with native scalar min/max. + a = self._generate_data(self.nr, self.nc) + m = -0.5 + M = 1. + a_s = self._neg_byteorder(a) + assert_(not a_s.dtype.isnative) + ac = self.fastclip(a_s, m, M) + act = a_s.clip(m, M) + assert_array_strict_equal(ac, act) + + def test_type_cast_09(self): + # Test native with NON native array min/max. + a = self._generate_data(self.nr, self.nc) + m = -0.5 * np.ones(a.shape) + M = 1. + m_s = self._neg_byteorder(m) + assert_(not m_s.dtype.isnative) + ac = self.fastclip(a, m_s, M) + act = self.clip(a, m_s, M) + assert_array_strict_equal(ac, act) + + def test_type_cast_10(self): + # Test native int32 with float min/max and float out for output argument. + a = self._generate_int_data(self.nr, self.nc) + b = np.zeros(a.shape, dtype=np.float32) + m = np.float32(-0.5) + M = np.float32(1) + act = self.clip(a, m, M, out=b) + ac = self.fastclip(a, m, M, out=b) + assert_array_strict_equal(ac, act) + + def test_type_cast_11(self): + # Test non native with native scalar, min/max, out non native + a = self._generate_non_native_data(self.nr, self.nc) + b = a.copy() + b = b.astype(b.dtype.newbyteorder('>')) + bt = b.copy() + m = -0.5 + M = 1. + self.fastclip(a, m, M, out=b) + self.clip(a, m, M, out=bt) + assert_array_strict_equal(b, bt) + + def test_type_cast_12(self): + # Test native int32 input and min/max and float out + a = self._generate_int_data(self.nr, self.nc) + b = np.zeros(a.shape, dtype=np.float32) + m = np.int32(0) + M = np.int32(1) + act = self.clip(a, m, M, out=b) + ac = self.fastclip(a, m, M, out=b) + assert_array_strict_equal(ac, act) + + def test_clip_with_out_simple(self): + # Test native double input with scalar min/max + a = self._generate_data(self.nr, self.nc) + m = -0.5 + M = 0.6 + ac = np.zeros(a.shape) + act = np.zeros(a.shape) + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_clip_with_out_simple2(self): + # Test native int32 input with double min/max and int32 out + a = self._generate_int32_data(self.nr, self.nc) + m = np.float64(0) + M = np.float64(2) + ac = np.zeros(a.shape, dtype=np.int32) + act = ac.copy() + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_clip_with_out_simple_int32(self): + # Test native int32 input with int32 scalar min/max and int64 out + a = self._generate_int32_data(self.nr, self.nc) + m = np.int32(-1) + M = np.int32(1) + ac = np.zeros(a.shape, dtype=np.int64) + act = ac.copy() + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_clip_with_out_array_int32(self): + # Test native int32 input with double array min/max and int32 out + a = self._generate_int32_data(self.nr, self.nc) + m = np.zeros(a.shape, np.float64) + M = np.float64(1) + ac = np.zeros(a.shape, dtype=np.int32) + act = ac.copy() + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_clip_with_out_array_outint32(self): + # Test native double input with scalar min/max and int out + a = self._generate_data(self.nr, self.nc) + m = -1.0 + M = 2.0 + ac = np.zeros(a.shape, dtype=np.int32) + act = ac.copy() + self.fastclip(a, m, M, ac) + self.clip(a, m, M, act) + assert_array_strict_equal(ac, act) + + def test_clip_inplace_array(self): + # Test native double input with array min/max + a = self._generate_data(self.nr, self.nc) + ac = a.copy() + m = np.zeros(a.shape) + M = 1.0 + self.fastclip(a, m, M, a) + self.clip(a, m, M, ac) + assert_array_strict_equal(a, ac) + + def test_clip_inplace_simple(self): + # Test native double input with scalar min/max + a = self._generate_data(self.nr, self.nc) + ac = a.copy() + m = -0.5 + M = 0.6 + self.fastclip(a, m, M, a) + self.clip(a, m, M, ac) + assert_array_strict_equal(a, ac) + + def test_clip_func_takes_out(self): + # Ensure that the clip() function takes an out=argument. + a = self._generate_data(self.nr, self.nc) + ac = a.copy() + m = -0.5 + M = 0.6 + a2 = np.clip(a, m, M, out=a) + self.clip(a, m, M, ac) + assert_array_strict_equal(a2, ac) + assert_(a2 is a) + + def test_clip_nan(self): + d = np.arange(7.) + assert_equal(d.clip(min=np.nan), d) + assert_equal(d.clip(max=np.nan), d) + assert_equal(d.clip(min=np.nan, max=np.nan), d) + assert_equal(d.clip(min=-2, max=np.nan), d) + assert_equal(d.clip(min=np.nan, max=10), d) + + +class TestAllclose(object): + rtol = 1e-5 + atol = 1e-8 + + def setup(self): + self.olderr = np.seterr(invalid='ignore') + + def teardown(self): + np.seterr(**self.olderr) + + def tst_allclose(self, x, y): + assert_(np.allclose(x, y), "%s and %s not close" % (x, y)) + + def tst_not_allclose(self, x, y): + assert_(not np.allclose(x, y), "%s and %s shouldn't be close" % (x, y)) + + def test_ip_allclose(self): + # Parametric test factory. + arr = np.array([100, 1000]) + aran = np.arange(125).reshape((5, 5, 5)) + + atol = self.atol + rtol = self.rtol + + data = [([1, 0], [1, 0]), + ([atol], [0]), + ([1], [1+rtol+atol]), + (arr, arr + arr*rtol), + (arr, arr + arr*rtol + atol*2), + (aran, aran + aran*rtol), + (np.inf, np.inf), + (np.inf, [np.inf])] + + for (x, y) in data: + yield (self.tst_allclose, x, y) + + def test_ip_not_allclose(self): + # Parametric test factory. + aran = np.arange(125).reshape((5, 5, 5)) + + atol = self.atol + rtol = self.rtol + + data = [([np.inf, 0], [1, np.inf]), + ([np.inf, 0], [1, 0]), + ([np.inf, np.inf], [1, np.inf]), + ([np.inf, np.inf], [1, 0]), + ([-np.inf, 0], [np.inf, 0]), + ([np.nan, 0], [np.nan, 0]), + ([atol*2], [0]), + ([1], [1+rtol+atol*2]), + (aran, aran + aran*atol + atol*2), + (np.array([np.inf, 1]), np.array([0, np.inf]))] + + for (x, y) in data: + yield (self.tst_not_allclose, x, y) + + def test_no_parameter_modification(self): + x = np.array([np.inf, 1]) + y = np.array([0, np.inf]) + np.allclose(x, y) + assert_array_equal(x, np.array([np.inf, 1])) + assert_array_equal(y, np.array([0, np.inf])) + + def test_min_int(self): + # Could make problems because of abs(min_int) == min_int + min_int = np.iinfo(np.int_).min + a = np.array([min_int], dtype=np.int_) + assert_(np.allclose(a, a)) + + def test_equalnan(self): + x = np.array([1.0, np.nan]) + assert_(np.allclose(x, x, equal_nan=True)) + + def test_return_class_is_ndarray(self): + # Issue gh-6475 + # Check that allclose does not preserve subtypes + class Foo(np.ndarray): + def __new__(cls, *args, **kwargs): + return np.array(*args, **kwargs).view(cls) + + a = Foo([1]) + assert_(type(np.allclose(a, a)) is bool) + + +class TestIsclose(object): + rtol = 1e-5 + atol = 1e-8 + + def setup(self): + atol = self.atol + rtol = self.rtol + arr = np.array([100, 1000]) + aran = np.arange(125).reshape((5, 5, 5)) + + self.all_close_tests = [ + ([1, 0], [1, 0]), + ([atol], [0]), + ([1], [1 + rtol + atol]), + (arr, arr + arr*rtol), + (arr, arr + arr*rtol + atol), + (aran, aran + aran*rtol), + (np.inf, np.inf), + (np.inf, [np.inf]), + ([np.inf, -np.inf], [np.inf, -np.inf]), + ] + self.none_close_tests = [ + ([np.inf, 0], [1, np.inf]), + ([np.inf, -np.inf], [1, 0]), + ([np.inf, np.inf], [1, -np.inf]), + ([np.inf, np.inf], [1, 0]), + ([np.nan, 0], [np.nan, -np.inf]), + ([atol*2], [0]), + ([1], [1 + rtol + atol*2]), + (aran, aran + rtol*1.1*aran + atol*1.1), + (np.array([np.inf, 1]), np.array([0, np.inf])), + ] + self.some_close_tests = [ + ([np.inf, 0], [np.inf, atol*2]), + ([atol, 1, 1e6*(1 + 2*rtol) + atol], [0, np.nan, 1e6]), + (np.arange(3), [0, 1, 2.1]), + (np.nan, [np.nan, np.nan, np.nan]), + ([0], [atol, np.inf, -np.inf, np.nan]), + (0, [atol, np.inf, -np.inf, np.nan]), + ] + self.some_close_results = [ + [True, False], + [True, False, False], + [True, True, False], + [False, False, False], + [True, False, False, False], + [True, False, False, False], + ] + + def test_ip_isclose(self): + self.setup() + tests = self.some_close_tests + results = self.some_close_results + for (x, y), result in zip(tests, results): + yield (assert_array_equal, np.isclose(x, y), result) + + def tst_all_isclose(self, x, y): + assert_(np.all(np.isclose(x, y)), "%s and %s not close" % (x, y)) + + def tst_none_isclose(self, x, y): + msg = "%s and %s shouldn't be close" + assert_(not np.any(np.isclose(x, y)), msg % (x, y)) + + def tst_isclose_allclose(self, x, y): + msg = "isclose.all() and allclose aren't same for %s and %s" + msg2 = "isclose and allclose aren't same for %s and %s" + if np.isscalar(x) and np.isscalar(y): + assert_(np.isclose(x, y) == np.allclose(x, y), msg=msg2 % (x, y)) + else: + assert_array_equal(np.isclose(x, y).all(), np.allclose(x, y), msg % (x, y)) + + def test_ip_all_isclose(self): + self.setup() + for (x, y) in self.all_close_tests: + yield (self.tst_all_isclose, x, y) + + def test_ip_none_isclose(self): + self.setup() + for (x, y) in self.none_close_tests: + yield (self.tst_none_isclose, x, y) + + def test_ip_isclose_allclose(self): + self.setup() + tests = (self.all_close_tests + self.none_close_tests + + self.some_close_tests) + for (x, y) in tests: + yield (self.tst_isclose_allclose, x, y) + + def test_equal_nan(self): + assert_array_equal(np.isclose(np.nan, np.nan, equal_nan=True), [True]) + arr = np.array([1.0, np.nan]) + assert_array_equal(np.isclose(arr, arr, equal_nan=True), [True, True]) + + def test_masked_arrays(self): + # Make sure to test the output type when arguments are interchanged. + + x = np.ma.masked_where([True, True, False], np.arange(3)) + assert_(type(x) is type(np.isclose(2, x))) + assert_(type(x) is type(np.isclose(x, 2))) + + x = np.ma.masked_where([True, True, False], [np.nan, np.inf, np.nan]) + assert_(type(x) is type(np.isclose(np.inf, x))) + assert_(type(x) is type(np.isclose(x, np.inf))) + + x = np.ma.masked_where([True, True, False], [np.nan, np.nan, np.nan]) + y = np.isclose(np.nan, x, equal_nan=True) + assert_(type(x) is type(y)) + # Ensure that the mask isn't modified... + assert_array_equal([True, True, False], y.mask) + y = np.isclose(x, np.nan, equal_nan=True) + assert_(type(x) is type(y)) + # Ensure that the mask isn't modified... + assert_array_equal([True, True, False], y.mask) + + x = np.ma.masked_where([True, True, False], [np.nan, np.nan, np.nan]) + y = np.isclose(x, x, equal_nan=True) + assert_(type(x) is type(y)) + # Ensure that the mask isn't modified... + assert_array_equal([True, True, False], y.mask) + + def test_scalar_return(self): + assert_(np.isscalar(np.isclose(1, 1))) + + def test_no_parameter_modification(self): + x = np.array([np.inf, 1]) + y = np.array([0, np.inf]) + np.isclose(x, y) + assert_array_equal(x, np.array([np.inf, 1])) + assert_array_equal(y, np.array([0, np.inf])) + + def test_non_finite_scalar(self): + # GH7014, when two scalars are compared the output should also be a + # scalar + assert_(np.isclose(np.inf, -np.inf) is np.False_) + assert_(np.isclose(0, np.inf) is np.False_) + assert_(type(np.isclose(0, np.inf)) is np.bool_) + + +class TestStdVar(object): + def setup(self): + self.A = np.array([1, -1, 1, -1]) + self.real_var = 1 + + def test_basic(self): + assert_almost_equal(np.var(self.A), self.real_var) + assert_almost_equal(np.std(self.A)**2, self.real_var) + + def test_scalars(self): + assert_equal(np.var(1), 0) + assert_equal(np.std(1), 0) + + def test_ddof1(self): + assert_almost_equal(np.var(self.A, ddof=1), + self.real_var*len(self.A)/float(len(self.A)-1)) + assert_almost_equal(np.std(self.A, ddof=1)**2, + self.real_var*len(self.A)/float(len(self.A)-1)) + + def test_ddof2(self): + assert_almost_equal(np.var(self.A, ddof=2), + self.real_var*len(self.A)/float(len(self.A)-2)) + assert_almost_equal(np.std(self.A, ddof=2)**2, + self.real_var*len(self.A)/float(len(self.A)-2)) + + def test_out_scalar(self): + d = np.arange(10) + out = np.array(0.) + r = np.std(d, out=out) + assert_(r is out) + assert_array_equal(r, out) + r = np.var(d, out=out) + assert_(r is out) + assert_array_equal(r, out) + r = np.mean(d, out=out) + assert_(r is out) + assert_array_equal(r, out) + + +class TestStdVarComplex(object): + def test_basic(self): + A = np.array([1, 1.j, -1, -1.j]) + real_var = 1 + assert_almost_equal(np.var(A), real_var) + assert_almost_equal(np.std(A)**2, real_var) + + def test_scalars(self): + assert_equal(np.var(1j), 0) + assert_equal(np.std(1j), 0) + + +class TestCreationFuncs(object): + # Test ones, zeros, empty and full. + + def setup(self): + dtypes = {np.dtype(tp) for tp in itertools.chain(*np.sctypes.values())} + # void, bytes, str + variable_sized = {tp for tp in dtypes if tp.str.endswith('0')} + self.dtypes = sorted(dtypes - variable_sized | + {np.dtype(tp.str.replace("0", str(i))) + for tp in variable_sized for i in range(1, 10)}, + key=lambda dtype: dtype.str) + self.orders = {'C': 'c_contiguous', 'F': 'f_contiguous'} + self.ndims = 10 + + def check_function(self, func, fill_value=None): + par = ((0, 1, 2), + range(self.ndims), + self.orders, + self.dtypes) + fill_kwarg = {} + if fill_value is not None: + fill_kwarg = {'fill_value': fill_value} + + for size, ndims, order, dtype in itertools.product(*par): + shape = ndims * [size] + + # do not fill void type + if fill_kwarg and dtype.str.startswith('|V'): + continue + + arr = func(shape, order=order, dtype=dtype, + **fill_kwarg) + + assert_equal(arr.dtype, dtype) + assert_(getattr(arr.flags, self.orders[order])) + + if fill_value is not None: + if dtype.str.startswith('|S'): + val = str(fill_value) + else: + val = fill_value + assert_equal(arr, dtype.type(val)) + + def test_zeros(self): + self.check_function(np.zeros) + + def test_ones(self): + self.check_function(np.zeros) + + def test_empty(self): + self.check_function(np.empty) + + def test_full(self): + self.check_function(np.full, 0) + self.check_function(np.full, 1) + + @dec.skipif(not HAS_REFCOUNT, "python has no sys.getrefcount") + def test_for_reference_leak(self): + # Make sure we have an object for reference + dim = 1 + beg = sys.getrefcount(dim) + np.zeros([dim]*10) + assert_(sys.getrefcount(dim) == beg) + np.ones([dim]*10) + assert_(sys.getrefcount(dim) == beg) + np.empty([dim]*10) + assert_(sys.getrefcount(dim) == beg) + np.full([dim]*10, 0) + assert_(sys.getrefcount(dim) == beg) + + +class TestLikeFuncs(object): + '''Test ones_like, zeros_like, empty_like and full_like''' + + def setup(self): + self.data = [ + # Array scalars + (np.array(3.), None), + (np.array(3), 'f8'), + # 1D arrays + (np.arange(6, dtype='f4'), None), + (np.arange(6), 'c16'), + # 2D C-layout arrays + (np.arange(6).reshape(2, 3), None), + (np.arange(6).reshape(3, 2), 'i1'), + # 2D F-layout arrays + (np.arange(6).reshape((2, 3), order='F'), None), + (np.arange(6).reshape((3, 2), order='F'), 'i1'), + # 3D C-layout arrays + (np.arange(24).reshape(2, 3, 4), None), + (np.arange(24).reshape(4, 3, 2), 'f4'), + # 3D F-layout arrays + (np.arange(24).reshape((2, 3, 4), order='F'), None), + (np.arange(24).reshape((4, 3, 2), order='F'), 'f4'), + # 3D non-C/F-layout arrays + (np.arange(24).reshape(2, 3, 4).swapaxes(0, 1), None), + (np.arange(24).reshape(4, 3, 2).swapaxes(0, 1), '?'), + ] + + def compare_array_value(self, dz, value, fill_value): + if value is not None: + if fill_value: + try: + z = dz.dtype.type(value) + except OverflowError: + pass + else: + assert_(np.all(dz == z)) + else: + assert_(np.all(dz == value)) + + def check_like_function(self, like_function, value, fill_value=False): + if fill_value: + fill_kwarg = {'fill_value': value} + else: + fill_kwarg = {} + for d, dtype in self.data: + # default (K) order, dtype + dz = like_function(d, dtype=dtype, **fill_kwarg) + assert_equal(dz.shape, d.shape) + assert_equal(np.array(dz.strides)*d.dtype.itemsize, + np.array(d.strides)*dz.dtype.itemsize) + assert_equal(d.flags.c_contiguous, dz.flags.c_contiguous) + assert_equal(d.flags.f_contiguous, dz.flags.f_contiguous) + if dtype is None: + assert_equal(dz.dtype, d.dtype) + else: + assert_equal(dz.dtype, np.dtype(dtype)) + self.compare_array_value(dz, value, fill_value) + + # C order, default dtype + dz = like_function(d, order='C', dtype=dtype, **fill_kwarg) + assert_equal(dz.shape, d.shape) + assert_(dz.flags.c_contiguous) + if dtype is None: + assert_equal(dz.dtype, d.dtype) + else: + assert_equal(dz.dtype, np.dtype(dtype)) + self.compare_array_value(dz, value, fill_value) + + # F order, default dtype + dz = like_function(d, order='F', dtype=dtype, **fill_kwarg) + assert_equal(dz.shape, d.shape) + assert_(dz.flags.f_contiguous) + if dtype is None: + assert_equal(dz.dtype, d.dtype) + else: + assert_equal(dz.dtype, np.dtype(dtype)) + self.compare_array_value(dz, value, fill_value) + + # A order + dz = like_function(d, order='A', dtype=dtype, **fill_kwarg) + assert_equal(dz.shape, d.shape) + if d.flags.f_contiguous: + assert_(dz.flags.f_contiguous) + else: + assert_(dz.flags.c_contiguous) + if dtype is None: + assert_equal(dz.dtype, d.dtype) + else: + assert_equal(dz.dtype, np.dtype(dtype)) + self.compare_array_value(dz, value, fill_value) + + # Test the 'subok' parameter + a = np.matrix([[1, 2], [3, 4]]) + + b = like_function(a, **fill_kwarg) + assert_(type(b) is np.matrix) + + b = like_function(a, subok=False, **fill_kwarg) + assert_(type(b) is not np.matrix) + + def test_ones_like(self): + self.check_like_function(np.ones_like, 1) + + def test_zeros_like(self): + self.check_like_function(np.zeros_like, 0) + + def test_empty_like(self): + self.check_like_function(np.empty_like, None) + + def test_filled_like(self): + self.check_like_function(np.full_like, 0, True) + self.check_like_function(np.full_like, 1, True) + self.check_like_function(np.full_like, 1000, True) + self.check_like_function(np.full_like, 123.456, True) + self.check_like_function(np.full_like, np.inf, True) + + +class TestCorrelate(object): + def _setup(self, dt): + self.x = np.array([1, 2, 3, 4, 5], dtype=dt) + self.xs = np.arange(1, 20)[::3] + self.y = np.array([-1, -2, -3], dtype=dt) + self.z1 = np.array([ -3., -8., -14., -20., -26., -14., -5.], dtype=dt) + self.z1_4 = np.array([-2., -5., -8., -11., -14., -5.], dtype=dt) + self.z1r = np.array([-15., -22., -22., -16., -10., -4., -1.], dtype=dt) + self.z2 = np.array([-5., -14., -26., -20., -14., -8., -3.], dtype=dt) + self.z2r = np.array([-1., -4., -10., -16., -22., -22., -15.], dtype=dt) + self.zs = np.array([-3., -14., -30., -48., -66., -84., + -102., -54., -19.], dtype=dt) + + def test_float(self): + self._setup(float) + z = np.correlate(self.x, self.y, 'full') + assert_array_almost_equal(z, self.z1) + z = np.correlate(self.x, self.y[:-1], 'full') + assert_array_almost_equal(z, self.z1_4) + z = np.correlate(self.y, self.x, 'full') + assert_array_almost_equal(z, self.z2) + z = np.correlate(self.x[::-1], self.y, 'full') + assert_array_almost_equal(z, self.z1r) + z = np.correlate(self.y, self.x[::-1], 'full') + assert_array_almost_equal(z, self.z2r) + z = np.correlate(self.xs, self.y, 'full') + assert_array_almost_equal(z, self.zs) + + def test_object(self): + self._setup(Decimal) + z = np.correlate(self.x, self.y, 'full') + assert_array_almost_equal(z, self.z1) + z = np.correlate(self.y, self.x, 'full') + assert_array_almost_equal(z, self.z2) + + def test_no_overwrite(self): + d = np.ones(100) + k = np.ones(3) + np.correlate(d, k) + assert_array_equal(d, np.ones(100)) + assert_array_equal(k, np.ones(3)) + + def test_complex(self): + x = np.array([1, 2, 3, 4+1j], dtype=complex) + y = np.array([-1, -2j, 3+1j], dtype=complex) + r_z = np.array([3-1j, 6, 8+1j, 11+5j, -5+8j, -4-1j], dtype=complex) + r_z = r_z[::-1].conjugate() + z = np.correlate(y, x, mode='full') + assert_array_almost_equal(z, r_z) + + +class TestConvolve(object): + def test_object(self): + d = [1.] * 100 + k = [1.] * 3 + assert_array_almost_equal(np.convolve(d, k)[2:-2], np.full(98, 3)) + + def test_no_overwrite(self): + d = np.ones(100) + k = np.ones(3) + np.convolve(d, k) + assert_array_equal(d, np.ones(100)) + assert_array_equal(k, np.ones(3)) + + +class TestArgwhere(object): + def test_2D(self): + x = np.arange(6).reshape((2, 3)) + assert_array_equal(np.argwhere(x > 1), + [[0, 2], + [1, 0], + [1, 1], + [1, 2]]) + + def test_list(self): + assert_equal(np.argwhere([4, 0, 2, 1, 3]), [[0], [2], [3], [4]]) + + +class TestStringFunction(object): + + def test_set_string_function(self): + a = np.array([1]) + np.set_string_function(lambda x: "FOO", repr=True) + assert_equal(repr(a), "FOO") + np.set_string_function(None, repr=True) + assert_equal(repr(a), "array([1])") + + np.set_string_function(lambda x: "FOO", repr=False) + assert_equal(str(a), "FOO") + np.set_string_function(None, repr=False) + assert_equal(str(a), "[1]") + + +class TestRoll(object): + def test_roll1d(self): + x = np.arange(10) + xr = np.roll(x, 2) + assert_equal(xr, np.array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])) + + def test_roll2d(self): + x2 = np.reshape(np.arange(10), (2, 5)) + x2r = np.roll(x2, 1) + assert_equal(x2r, np.array([[9, 0, 1, 2, 3], [4, 5, 6, 7, 8]])) + + x2r = np.roll(x2, 1, axis=0) + assert_equal(x2r, np.array([[5, 6, 7, 8, 9], [0, 1, 2, 3, 4]])) + + x2r = np.roll(x2, 1, axis=1) + assert_equal(x2r, np.array([[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]])) + + # Roll multiple axes at once. + x2r = np.roll(x2, 1, axis=(0, 1)) + assert_equal(x2r, np.array([[9, 5, 6, 7, 8], [4, 0, 1, 2, 3]])) + + x2r = np.roll(x2, (1, 0), axis=(0, 1)) + assert_equal(x2r, np.array([[5, 6, 7, 8, 9], [0, 1, 2, 3, 4]])) + + x2r = np.roll(x2, (-1, 0), axis=(0, 1)) + assert_equal(x2r, np.array([[5, 6, 7, 8, 9], [0, 1, 2, 3, 4]])) + + x2r = np.roll(x2, (0, 1), axis=(0, 1)) + assert_equal(x2r, np.array([[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]])) + + x2r = np.roll(x2, (0, -1), axis=(0, 1)) + assert_equal(x2r, np.array([[1, 2, 3, 4, 0], [6, 7, 8, 9, 5]])) + + x2r = np.roll(x2, (1, 1), axis=(0, 1)) + assert_equal(x2r, np.array([[9, 5, 6, 7, 8], [4, 0, 1, 2, 3]])) + + x2r = np.roll(x2, (-1, -1), axis=(0, 1)) + assert_equal(x2r, np.array([[6, 7, 8, 9, 5], [1, 2, 3, 4, 0]])) + + # Roll the same axis multiple times. + x2r = np.roll(x2, 1, axis=(0, 0)) + assert_equal(x2r, np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])) + + x2r = np.roll(x2, 1, axis=(1, 1)) + assert_equal(x2r, np.array([[3, 4, 0, 1, 2], [8, 9, 5, 6, 7]])) + + # Roll more than one turn in either direction. + x2r = np.roll(x2, 6, axis=1) + assert_equal(x2r, np.array([[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]])) + + x2r = np.roll(x2, -4, axis=1) + assert_equal(x2r, np.array([[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]])) + + def test_roll_empty(self): + x = np.array([]) + assert_equal(np.roll(x, 1), np.array([])) + + +class TestRollaxis(object): + + # expected shape indexed by (axis, start) for array of + # shape (1, 2, 3, 4) + tgtshape = {(0, 0): (1, 2, 3, 4), (0, 1): (1, 2, 3, 4), + (0, 2): (2, 1, 3, 4), (0, 3): (2, 3, 1, 4), + (0, 4): (2, 3, 4, 1), + (1, 0): (2, 1, 3, 4), (1, 1): (1, 2, 3, 4), + (1, 2): (1, 2, 3, 4), (1, 3): (1, 3, 2, 4), + (1, 4): (1, 3, 4, 2), + (2, 0): (3, 1, 2, 4), (2, 1): (1, 3, 2, 4), + (2, 2): (1, 2, 3, 4), (2, 3): (1, 2, 3, 4), + (2, 4): (1, 2, 4, 3), + (3, 0): (4, 1, 2, 3), (3, 1): (1, 4, 2, 3), + (3, 2): (1, 2, 4, 3), (3, 3): (1, 2, 3, 4), + (3, 4): (1, 2, 3, 4)} + + def test_exceptions(self): + a = np.arange(1*2*3*4).reshape(1, 2, 3, 4) + assert_raises(np.AxisError, np.rollaxis, a, -5, 0) + assert_raises(np.AxisError, np.rollaxis, a, 0, -5) + assert_raises(np.AxisError, np.rollaxis, a, 4, 0) + assert_raises(np.AxisError, np.rollaxis, a, 0, 5) + + def test_results(self): + a = np.arange(1*2*3*4).reshape(1, 2, 3, 4).copy() + aind = np.indices(a.shape) + assert_(a.flags['OWNDATA']) + for (i, j) in self.tgtshape: + # positive axis, positive start + res = np.rollaxis(a, axis=i, start=j) + i0, i1, i2, i3 = aind[np.array(res.shape) - 1] + assert_(np.all(res[i0, i1, i2, i3] == a)) + assert_(res.shape == self.tgtshape[(i, j)], str((i,j))) + assert_(not res.flags['OWNDATA']) + + # negative axis, positive start + ip = i + 1 + res = np.rollaxis(a, axis=-ip, start=j) + i0, i1, i2, i3 = aind[np.array(res.shape) - 1] + assert_(np.all(res[i0, i1, i2, i3] == a)) + assert_(res.shape == self.tgtshape[(4 - ip, j)]) + assert_(not res.flags['OWNDATA']) + + # positive axis, negative start + jp = j + 1 if j < 4 else j + res = np.rollaxis(a, axis=i, start=-jp) + i0, i1, i2, i3 = aind[np.array(res.shape) - 1] + assert_(np.all(res[i0, i1, i2, i3] == a)) + assert_(res.shape == self.tgtshape[(i, 4 - jp)]) + assert_(not res.flags['OWNDATA']) + + # negative axis, negative start + ip = i + 1 + jp = j + 1 if j < 4 else j + res = np.rollaxis(a, axis=-ip, start=-jp) + i0, i1, i2, i3 = aind[np.array(res.shape) - 1] + assert_(np.all(res[i0, i1, i2, i3] == a)) + assert_(res.shape == self.tgtshape[(4 - ip, 4 - jp)]) + assert_(not res.flags['OWNDATA']) + + +class TestMoveaxis(object): + def test_move_to_end(self): + x = np.random.randn(5, 6, 7) + for source, expected in [(0, (6, 7, 5)), + (1, (5, 7, 6)), + (2, (5, 6, 7)), + (-1, (5, 6, 7))]: + actual = np.moveaxis(x, source, -1).shape + assert_(actual, expected) + + def test_move_new_position(self): + x = np.random.randn(1, 2, 3, 4) + for source, destination, expected in [ + (0, 1, (2, 1, 3, 4)), + (1, 2, (1, 3, 2, 4)), + (1, -1, (1, 3, 4, 2)), + ]: + actual = np.moveaxis(x, source, destination).shape + assert_(actual, expected) + + def test_preserve_order(self): + x = np.zeros((1, 2, 3, 4)) + for source, destination in [ + (0, 0), + (3, -1), + (-1, 3), + ([0, -1], [0, -1]), + ([2, 0], [2, 0]), + (range(4), range(4)), + ]: + actual = np.moveaxis(x, source, destination).shape + assert_(actual, (1, 2, 3, 4)) + + def test_move_multiples(self): + x = np.zeros((0, 1, 2, 3)) + for source, destination, expected in [ + ([0, 1], [2, 3], (2, 3, 0, 1)), + ([2, 3], [0, 1], (2, 3, 0, 1)), + ([0, 1, 2], [2, 3, 0], (2, 3, 0, 1)), + ([3, 0], [1, 0], (0, 3, 1, 2)), + ([0, 3], [0, 1], (0, 3, 1, 2)), + ]: + actual = np.moveaxis(x, source, destination).shape + assert_(actual, expected) + + def test_errors(self): + x = np.random.randn(1, 2, 3) + assert_raises_regex(np.AxisError, 'source.*out of bounds', + np.moveaxis, x, 3, 0) + assert_raises_regex(np.AxisError, 'source.*out of bounds', + np.moveaxis, x, -4, 0) + assert_raises_regex(np.AxisError, 'destination.*out of bounds', + np.moveaxis, x, 0, 5) + assert_raises_regex(ValueError, 'repeated axis in `source`', + np.moveaxis, x, [0, 0], [0, 1]) + assert_raises_regex(ValueError, 'repeated axis in `destination`', + np.moveaxis, x, [0, 1], [1, 1]) + assert_raises_regex(ValueError, 'must have the same number', + np.moveaxis, x, 0, [0, 1]) + assert_raises_regex(ValueError, 'must have the same number', + np.moveaxis, x, [0, 1], [0]) + + def test_array_likes(self): + x = np.ma.zeros((1, 2, 3)) + result = np.moveaxis(x, 0, 0) + assert_(x.shape, result.shape) + assert_(isinstance(result, np.ma.MaskedArray)) + + x = [1, 2, 3] + result = np.moveaxis(x, 0, 0) + assert_(x, list(result)) + assert_(isinstance(result, np.ndarray)) + + +class TestCross(object): + def test_2x2(self): + u = [1, 2] + v = [3, 4] + z = -2 + cp = np.cross(u, v) + assert_equal(cp, z) + cp = np.cross(v, u) + assert_equal(cp, -z) + + def test_2x3(self): + u = [1, 2] + v = [3, 4, 5] + z = np.array([10, -5, -2]) + cp = np.cross(u, v) + assert_equal(cp, z) + cp = np.cross(v, u) + assert_equal(cp, -z) + + def test_3x3(self): + u = [1, 2, 3] + v = [4, 5, 6] + z = np.array([-3, 6, -3]) + cp = np.cross(u, v) + assert_equal(cp, z) + cp = np.cross(v, u) + assert_equal(cp, -z) + + def test_broadcasting(self): + # Ticket #2624 (Trac #2032) + u = np.tile([1, 2], (11, 1)) + v = np.tile([3, 4], (11, 1)) + z = -2 + assert_equal(np.cross(u, v), z) + assert_equal(np.cross(v, u), -z) + assert_equal(np.cross(u, u), 0) + + u = np.tile([1, 2], (11, 1)).T + v = np.tile([3, 4, 5], (11, 1)) + z = np.tile([10, -5, -2], (11, 1)) + assert_equal(np.cross(u, v, axisa=0), z) + assert_equal(np.cross(v, u.T), -z) + assert_equal(np.cross(v, v), 0) + + u = np.tile([1, 2, 3], (11, 1)).T + v = np.tile([3, 4], (11, 1)).T + z = np.tile([-12, 9, -2], (11, 1)) + assert_equal(np.cross(u, v, axisa=0, axisb=0), z) + assert_equal(np.cross(v.T, u.T), -z) + assert_equal(np.cross(u.T, u.T), 0) + + u = np.tile([1, 2, 3], (5, 1)) + v = np.tile([4, 5, 6], (5, 1)).T + z = np.tile([-3, 6, -3], (5, 1)) + assert_equal(np.cross(u, v, axisb=0), z) + assert_equal(np.cross(v.T, u), -z) + assert_equal(np.cross(u, u), 0) + + def test_broadcasting_shapes(self): + u = np.ones((2, 1, 3)) + v = np.ones((5, 3)) + assert_equal(np.cross(u, v).shape, (2, 5, 3)) + u = np.ones((10, 3, 5)) + v = np.ones((2, 5)) + assert_equal(np.cross(u, v, axisa=1, axisb=0).shape, (10, 5, 3)) + assert_raises(np.AxisError, np.cross, u, v, axisa=1, axisb=2) + assert_raises(np.AxisError, np.cross, u, v, axisa=3, axisb=0) + u = np.ones((10, 3, 5, 7)) + v = np.ones((5, 7, 2)) + assert_equal(np.cross(u, v, axisa=1, axisc=2).shape, (10, 5, 3, 7)) + assert_raises(np.AxisError, np.cross, u, v, axisa=-5, axisb=2) + assert_raises(np.AxisError, np.cross, u, v, axisa=1, axisb=-4) + # gh-5885 + u = np.ones((3, 4, 2)) + for axisc in range(-2, 2): + assert_equal(np.cross(u, u, axisc=axisc).shape, (3, 4)) + + +def test_outer_out_param(): + arr1 = np.ones((5,)) + arr2 = np.ones((2,)) + arr3 = np.linspace(-2, 2, 5) + out1 = np.ndarray(shape=(5,5)) + out2 = np.ndarray(shape=(2, 5)) + res1 = np.outer(arr1, arr3, out1) + assert_equal(res1, out1) + assert_equal(np.outer(arr2, arr3, out2), out2) + + +class TestRequire(object): + flag_names = ['C', 'C_CONTIGUOUS', 'CONTIGUOUS', + 'F', 'F_CONTIGUOUS', 'FORTRAN', + 'A', 'ALIGNED', + 'W', 'WRITEABLE', + 'O', 'OWNDATA'] + + def generate_all_false(self, dtype): + arr = np.zeros((2, 2), [('junk', 'i1'), ('a', dtype)]) + arr.setflags(write=False) + a = arr['a'] + assert_(not a.flags['C']) + assert_(not a.flags['F']) + assert_(not a.flags['O']) + assert_(not a.flags['W']) + assert_(not a.flags['A']) + return a + + def set_and_check_flag(self, flag, dtype, arr): + if dtype is None: + dtype = arr.dtype + b = np.require(arr, dtype, [flag]) + assert_(b.flags[flag]) + assert_(b.dtype == dtype) + + # a further call to np.require ought to return the same array + # unless OWNDATA is specified. + c = np.require(b, None, [flag]) + if flag[0] != 'O': + assert_(c is b) + else: + assert_(c.flags[flag]) + + def test_require_each(self): + + id = ['f8', 'i4'] + fd = [None, 'f8', 'c16'] + for idtype, fdtype, flag in itertools.product(id, fd, self.flag_names): + a = self.generate_all_false(idtype) + yield self.set_and_check_flag, flag, fdtype, a + + def test_unknown_requirement(self): + a = self.generate_all_false('f8') + assert_raises(KeyError, np.require, a, None, 'Q') + + def test_non_array_input(self): + a = np.require([1, 2, 3, 4], 'i4', ['C', 'A', 'O']) + assert_(a.flags['O']) + assert_(a.flags['C']) + assert_(a.flags['A']) + assert_(a.dtype == 'i4') + assert_equal(a, [1, 2, 3, 4]) + + def test_C_and_F_simul(self): + a = self.generate_all_false('f8') + assert_raises(ValueError, np.require, a, None, ['C', 'F']) + + def test_ensure_array(self): + class ArraySubclass(np.ndarray): + pass + + a = ArraySubclass((2, 2)) + b = np.require(a, None, ['E']) + assert_(type(b) is np.ndarray) + + def test_preserve_subtype(self): + class ArraySubclass(np.ndarray): + pass + + for flag in self.flag_names: + a = ArraySubclass((2, 2)) + yield self.set_and_check_flag, flag, None, a + + +class TestBroadcast(object): + def test_broadcast_in_args(self): + # gh-5881 + arrs = [np.empty((6, 7)), np.empty((5, 6, 1)), np.empty((7,)), + np.empty((5, 1, 7))] + mits = [np.broadcast(*arrs), + np.broadcast(np.broadcast(*arrs[:2]), np.broadcast(*arrs[2:])), + np.broadcast(arrs[0], np.broadcast(*arrs[1:-1]), arrs[-1])] + for mit in mits: + assert_equal(mit.shape, (5, 6, 7)) + assert_equal(mit.ndim, 3) + assert_equal(mit.nd, 3) + assert_equal(mit.numiter, 4) + for a, ia in zip(arrs, mit.iters): + assert_(a is ia.base) + + def test_broadcast_single_arg(self): + # gh-6899 + arrs = [np.empty((5, 6, 7))] + mit = np.broadcast(*arrs) + assert_equal(mit.shape, (5, 6, 7)) + assert_equal(mit.ndim, 3) + assert_equal(mit.nd, 3) + assert_equal(mit.numiter, 1) + assert_(arrs[0] is mit.iters[0].base) + + def test_number_of_arguments(self): + arr = np.empty((5,)) + for j in range(35): + arrs = [arr] * j + if j < 1 or j > 32: + assert_raises(ValueError, np.broadcast, *arrs) + else: + mit = np.broadcast(*arrs) + assert_equal(mit.numiter, j) + + +class TestKeepdims(object): + + class sub_array(np.ndarray): + def sum(self, axis=None, dtype=None, out=None): + return np.ndarray.sum(self, axis, dtype, out, keepdims=True) + + def test_raise(self): + sub_class = self.sub_array + x = np.arange(30).view(sub_class) + assert_raises(TypeError, np.sum, x, keepdims=True) + + +class TestTensordot(object): + + def test_zero_dimension(self): + # Test resolution to issue #5663 + a = np.ndarray((3,0)) + b = np.ndarray((0,4)) + td = np.tensordot(a, b, (1, 0)) + assert_array_equal(td, np.dot(a, b)) + assert_array_equal(td, np.einsum('ij,jk', a, b)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_numerictypes.py b/numpy/core/tests/test_numerictypes.py new file mode 100644 index 0000000..8831cd1 --- /dev/null +++ b/numpy/core/tests/test_numerictypes.py @@ -0,0 +1,413 @@ +from __future__ import division, absolute_import, print_function + +import sys +import itertools + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises +) + +# 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., (b'nn', [6j, 4j], [6., 4.], [1, 2]), b'NN', True), b'cc', (u'NN', 6j), [[6., 4.], [6., 4.]], 8), + ([4, 3], (7j, 7., (b'oo', [7j, 5j], [7., 5.], [2, 1]), b'OO', False), b'dd', (u'OO', 7j), [[7., 5.], [7., 5.]], 9), + ] + + +byteorder = {'little':'<', 'big':'>'}[sys.byteorder] + +def normalize_descr(descr): + "Normalize a description adding the platform byteorder." + + out = [] + for item in descr: + dtype = item[1] + if isinstance(dtype, str): + if dtype[0] not in ['|', '<', '>']: + onebyte = dtype[1:] == "1" + if onebyte or dtype[0] in ['S', 'V', 'b']: + dtype = "|" + dtype + else: + dtype = byteorder + dtype + if len(item) > 2 and np.prod(item[2]) > 1: + nitem = (item[0], dtype, item[2]) + else: + nitem = (item[0], dtype) + out.append(nitem) + elif isinstance(item[1], list): + l = [] + for j in normalize_descr(item[1]): + l.append(j) + out.append((item[0], l)) + else: + raise ValueError("Expected a str or list and got %s" % + (type(item))) + return out + + +############################################################ +# Creation tests +############################################################ + +class CreateZeros(object): + """Check the creation of heterogeneous arrays zero-valued""" + + def test_zeros0D(self): + """Check creation of 0-dimensional objects""" + h = np.zeros((), dtype=self._descr) + assert_(normalize_descr(self._descr) == h.dtype.descr) + assert_(h.dtype.fields['x'][0].name[:4] == 'void') + assert_(h.dtype.fields['x'][0].char == 'V') + assert_(h.dtype.fields['x'][0].type == np.void) + # A small check that data is ok + assert_equal(h['z'], np.zeros((), dtype='u1')) + + def test_zerosSD(self): + """Check creation of single-dimensional objects""" + h = np.zeros((2,), dtype=self._descr) + assert_(normalize_descr(self._descr) == h.dtype.descr) + assert_(h.dtype['y'].name[:4] == 'void') + assert_(h.dtype['y'].char == 'V') + assert_(h.dtype['y'].type == np.void) + # A small check that data is ok + assert_equal(h['z'], np.zeros((2,), dtype='u1')) + + def test_zerosMD(self): + """Check creation of multi-dimensional objects""" + h = np.zeros((2, 3), dtype=self._descr) + assert_(normalize_descr(self._descr) == h.dtype.descr) + assert_(h.dtype['z'].name == 'uint8') + assert_(h.dtype['z'].char == 'B') + assert_(h.dtype['z'].type == np.uint8) + # A small check that data is ok + assert_equal(h['z'], np.zeros((2, 3), dtype='u1')) + + +class TestCreateZerosPlain(CreateZeros): + """Check the creation of heterogeneous arrays zero-valued (plain)""" + _descr = Pdescr + +class TestCreateZerosNested(CreateZeros): + """Check the creation of heterogeneous arrays zero-valued (nested)""" + _descr = Ndescr + + +class CreateValues(object): + """Check the creation of heterogeneous arrays with values""" + + def test_tuple(self): + """Check creation from tuples""" + h = np.array(self._buffer, dtype=self._descr) + assert_(normalize_descr(self._descr) == h.dtype.descr) + if self.multiple_rows: + assert_(h.shape == (2,)) + else: + assert_(h.shape == ()) + + def test_list_of_tuple(self): + """Check creation from list of tuples""" + h = np.array([self._buffer], dtype=self._descr) + assert_(normalize_descr(self._descr) == h.dtype.descr) + if self.multiple_rows: + assert_(h.shape == (1, 2)) + else: + assert_(h.shape == (1,)) + + def test_list_of_list_of_tuple(self): + """Check creation from list of list of tuples""" + h = np.array([[self._buffer]], dtype=self._descr) + assert_(normalize_descr(self._descr) == h.dtype.descr) + if self.multiple_rows: + assert_(h.shape == (1, 1, 2)) + else: + assert_(h.shape == (1, 1)) + + +class TestCreateValuesPlainSingle(CreateValues): + """Check the creation of heterogeneous arrays (plain, single row)""" + _descr = Pdescr + multiple_rows = 0 + _buffer = PbufferT[0] + +class TestCreateValuesPlainMultiple(CreateValues): + """Check the creation of heterogeneous arrays (plain, multiple rows)""" + _descr = Pdescr + multiple_rows = 1 + _buffer = PbufferT + +class TestCreateValuesNestedSingle(CreateValues): + """Check the creation of heterogeneous arrays (nested, single row)""" + _descr = Ndescr + multiple_rows = 0 + _buffer = NbufferT[0] + +class TestCreateValuesNestedMultiple(CreateValues): + """Check the creation of heterogeneous arrays (nested, multiple rows)""" + _descr = Ndescr + multiple_rows = 1 + _buffer = NbufferT + + +############################################################ +# Reading tests +############################################################ + +class ReadValuesPlain(object): + """Check the reading of values in heterogeneous arrays (plain)""" + + def test_access_fields(self): + h = np.array(self._buffer, dtype=self._descr) + if not self.multiple_rows: + assert_(h.shape == ()) + assert_equal(h['x'], np.array(self._buffer[0], dtype='i4')) + assert_equal(h['y'], np.array(self._buffer[1], dtype='f8')) + assert_equal(h['z'], np.array(self._buffer[2], dtype='u1')) + else: + assert_(len(h) == 2) + assert_equal(h['x'], np.array([self._buffer[0][0], + self._buffer[1][0]], dtype='i4')) + assert_equal(h['y'], np.array([self._buffer[0][1], + self._buffer[1][1]], dtype='f8')) + assert_equal(h['z'], np.array([self._buffer[0][2], + self._buffer[1][2]], dtype='u1')) + + +class TestReadValuesPlainSingle(ReadValuesPlain): + """Check the creation of heterogeneous arrays (plain, single row)""" + _descr = Pdescr + multiple_rows = 0 + _buffer = PbufferT[0] + +class TestReadValuesPlainMultiple(ReadValuesPlain): + """Check the values of heterogeneous arrays (plain, multiple rows)""" + _descr = Pdescr + multiple_rows = 1 + _buffer = PbufferT + +class ReadValuesNested(object): + """Check the reading of values in heterogeneous arrays (nested)""" + + def test_access_top_fields(self): + """Check reading the top fields of a nested array""" + h = np.array(self._buffer, dtype=self._descr) + if not self.multiple_rows: + assert_(h.shape == ()) + assert_equal(h['x'], np.array(self._buffer[0], dtype='i4')) + assert_equal(h['y'], np.array(self._buffer[4], dtype='f8')) + assert_equal(h['z'], np.array(self._buffer[5], dtype='u1')) + else: + assert_(len(h) == 2) + assert_equal(h['x'], np.array([self._buffer[0][0], + self._buffer[1][0]], dtype='i4')) + assert_equal(h['y'], np.array([self._buffer[0][4], + self._buffer[1][4]], dtype='f8')) + assert_equal(h['z'], np.array([self._buffer[0][5], + self._buffer[1][5]], dtype='u1')) + + def test_nested1_acessors(self): + """Check reading the nested fields of a nested array (1st level)""" + h = np.array(self._buffer, dtype=self._descr) + if not self.multiple_rows: + assert_equal(h['Info']['value'], + np.array(self._buffer[1][0], dtype='c16')) + assert_equal(h['Info']['y2'], + np.array(self._buffer[1][1], dtype='f8')) + assert_equal(h['info']['Name'], + np.array(self._buffer[3][0], dtype='U2')) + assert_equal(h['info']['Value'], + np.array(self._buffer[3][1], dtype='c16')) + else: + assert_equal(h['Info']['value'], + np.array([self._buffer[0][1][0], + self._buffer[1][1][0]], + dtype='c16')) + assert_equal(h['Info']['y2'], + np.array([self._buffer[0][1][1], + self._buffer[1][1][1]], + dtype='f8')) + assert_equal(h['info']['Name'], + np.array([self._buffer[0][3][0], + self._buffer[1][3][0]], + dtype='U2')) + assert_equal(h['info']['Value'], + np.array([self._buffer[0][3][1], + self._buffer[1][3][1]], + dtype='c16')) + + def test_nested2_acessors(self): + """Check reading the nested fields of a nested array (2nd level)""" + h = np.array(self._buffer, dtype=self._descr) + if not self.multiple_rows: + assert_equal(h['Info']['Info2']['value'], + np.array(self._buffer[1][2][1], dtype='c16')) + assert_equal(h['Info']['Info2']['z3'], + np.array(self._buffer[1][2][3], dtype='u4')) + else: + assert_equal(h['Info']['Info2']['value'], + np.array([self._buffer[0][1][2][1], + self._buffer[1][1][2][1]], + dtype='c16')) + assert_equal(h['Info']['Info2']['z3'], + np.array([self._buffer[0][1][2][3], + self._buffer[1][1][2][3]], + dtype='u4')) + + def test_nested1_descriptor(self): + """Check access nested descriptors of a nested array (1st level)""" + h = np.array(self._buffer, dtype=self._descr) + assert_(h.dtype['Info']['value'].name == 'complex128') + assert_(h.dtype['Info']['y2'].name == 'float64') + if sys.version_info[0] >= 3: + assert_(h.dtype['info']['Name'].name == 'str256') + else: + assert_(h.dtype['info']['Name'].name == 'unicode256') + assert_(h.dtype['info']['Value'].name == 'complex128') + + def test_nested2_descriptor(self): + """Check access nested descriptors of a nested array (2nd level)""" + h = np.array(self._buffer, dtype=self._descr) + assert_(h.dtype['Info']['Info2']['value'].name == 'void256') + assert_(h.dtype['Info']['Info2']['z3'].name == 'void64') + + +class TestReadValuesNestedSingle(ReadValuesNested): + """Check the values of heterogeneous arrays (nested, single row)""" + _descr = Ndescr + multiple_rows = False + _buffer = NbufferT[0] + +class TestReadValuesNestedMultiple(ReadValuesNested): + """Check the values of heterogeneous arrays (nested, multiple rows)""" + _descr = Ndescr + multiple_rows = True + _buffer = NbufferT + +class TestEmptyField(object): + def test_assign(self): + a = np.arange(10, dtype=np.float32) + a.dtype = [("int", "<0i4"), ("float", "<2f4")] + assert_(a['int'].shape == (5, 0)) + assert_(a['float'].shape == (5, 2)) + +class TestCommonType(object): + def test_scalar_loses1(self): + res = np.find_common_type(['f4', 'f4', 'i2'], ['f8']) + assert_(res == 'f4') + + def test_scalar_loses2(self): + res = np.find_common_type(['f4', 'f4'], ['i8']) + assert_(res == 'f4') + + def test_scalar_wins(self): + res = np.find_common_type(['f4', 'f4', 'i2'], ['c8']) + assert_(res == 'c8') + + def test_scalar_wins2(self): + res = np.find_common_type(['u4', 'i4', 'i4'], ['f4']) + assert_(res == 'f8') + + def test_scalar_wins3(self): # doesn't go up to 'f16' on purpose + res = np.find_common_type(['u8', 'i8', 'i8'], ['f8']) + assert_(res == 'f8') + +class TestMultipleFields(object): + def setup(self): + self.ary = np.array([(1, 2, 3, 4), (5, 6, 7, 8)], dtype='i4,f4,i2,c8') + + def _bad_call(self): + return self.ary['f0', 'f1'] + + def test_no_tuple(self): + assert_raises(IndexError, self._bad_call) + + def test_return(self): + res = self.ary[['f0', 'f2']].tolist() + assert_(res == [(1, 3), (5, 7)]) + + +class TestIsSubDType(object): + # scalar types can be promoted into dtypes + wrappers = [np.dtype, lambda x: x] + + def test_both_abstract(self): + assert_(np.issubdtype(np.floating, np.inexact)) + assert_(not np.issubdtype(np.inexact, np.floating)) + + def test_same(self): + for cls in (np.float32, np.int32): + for w1, w2 in itertools.product(self.wrappers, repeat=2): + assert_(np.issubdtype(w1(cls), w2(cls))) + + def test_subclass(self): + # note we cannot promote floating to a dtype, as it would turn into a + # concrete type + for w in self.wrappers: + assert_(np.issubdtype(w(np.float32), np.floating)) + assert_(np.issubdtype(w(np.float64), np.floating)) + + def test_subclass_backwards(self): + for w in self.wrappers: + assert_(not np.issubdtype(np.floating, w(np.float32))) + assert_(not np.issubdtype(np.floating, w(np.float64))) + + def test_sibling_class(self): + for w1, w2 in itertools.product(self.wrappers, repeat=2): + assert_(not np.issubdtype(w1(np.float32), w2(np.float64))) + assert_(not np.issubdtype(w1(np.float64), w2(np.float32))) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_print.py b/numpy/core/tests/test_print.py new file mode 100644 index 0000000..4b5c5f8 --- /dev/null +++ b/numpy/core/tests/test_print.py @@ -0,0 +1,246 @@ +from __future__ import division, absolute_import, print_function + +import sys +import locale +import nose + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, SkipTest +) + + +if sys.version_info[0] >= 3: + from io import StringIO +else: + from StringIO import StringIO + +_REF = {np.inf: 'inf', -np.inf: '-inf', np.nan: 'nan'} + + +def check_float_type(tp): + for x in [0, 1, -1, 1e20]: + assert_equal(str(tp(x)), str(float(x)), + err_msg='Failed str formatting for type %s' % tp) + + if tp(1e16).itemsize > 4: + assert_equal(str(tp(1e16)), str(float('1e16')), + err_msg='Failed str formatting for type %s' % tp) + else: + ref = '1e+16' + assert_equal(str(tp(1e16)), ref, + err_msg='Failed str formatting for type %s' % tp) + +def test_float_types(): + """ Check formatting. + + This is only for the str function, and only for simple types. + The precision of np.float32 and np.longdouble aren't the same as the + python float precision. + + """ + for t in [np.float32, np.double, np.longdouble]: + yield check_float_type, t + +def check_nan_inf_float(tp): + for x in [np.inf, -np.inf, np.nan]: + assert_equal(str(tp(x)), _REF[x], + err_msg='Failed str formatting for type %s' % tp) + +def test_nan_inf_float(): + """ Check formatting of nan & inf. + + This is only for the str function, and only for simple types. + The precision of np.float32 and np.longdouble aren't the same as the + python float precision. + + """ + for t in [np.float32, np.double, np.longdouble]: + yield check_nan_inf_float, t + +def check_complex_type(tp): + for x in [0, 1, -1, 1e20]: + assert_equal(str(tp(x)), str(complex(x)), + err_msg='Failed str formatting for type %s' % tp) + assert_equal(str(tp(x*1j)), str(complex(x*1j)), + err_msg='Failed str formatting for type %s' % tp) + assert_equal(str(tp(x + x*1j)), str(complex(x + x*1j)), + err_msg='Failed str formatting for type %s' % tp) + + if tp(1e16).itemsize > 8: + assert_equal(str(tp(1e16)), str(complex(1e16)), + err_msg='Failed str formatting for type %s' % tp) + else: + ref = '(1e+16+0j)' + assert_equal(str(tp(1e16)), ref, + err_msg='Failed str formatting for type %s' % tp) + +def test_complex_types(): + """Check formatting of complex types. + + This is only for the str function, and only for simple types. + The precision of np.float32 and np.longdouble aren't the same as the + python float precision. + + """ + for t in [np.complex64, np.cdouble, np.clongdouble]: + yield check_complex_type, t + +def test_complex_inf_nan(): + """Check inf/nan formatting of complex types.""" + TESTS = { + complex(np.inf, 0): "(inf+0j)", + complex(0, np.inf): "infj", + complex(-np.inf, 0): "(-inf+0j)", + complex(0, -np.inf): "-infj", + complex(np.inf, 1): "(inf+1j)", + complex(1, np.inf): "(1+infj)", + complex(-np.inf, 1): "(-inf+1j)", + complex(1, -np.inf): "(1-infj)", + complex(np.nan, 0): "(nan+0j)", + complex(0, np.nan): "nanj", + complex(-np.nan, 0): "(nan+0j)", + complex(0, -np.nan): "nanj", + complex(np.nan, 1): "(nan+1j)", + complex(1, np.nan): "(1+nanj)", + complex(-np.nan, 1): "(nan+1j)", + complex(1, -np.nan): "(1+nanj)", + } + for tp in [np.complex64, np.cdouble, np.clongdouble]: + for c, s in TESTS.items(): + yield _check_complex_inf_nan, c, s, tp + +def _check_complex_inf_nan(c, s, dtype): + assert_equal(str(dtype(c)), s) + +# print tests +def _test_redirected_print(x, tp, ref=None): + file = StringIO() + file_tp = StringIO() + stdout = sys.stdout + try: + sys.stdout = file_tp + print(tp(x)) + sys.stdout = file + if ref: + print(ref) + else: + print(x) + finally: + sys.stdout = stdout + + assert_equal(file.getvalue(), file_tp.getvalue(), + err_msg='print failed for type%s' % tp) + +def check_float_type_print(tp): + for x in [0, 1, -1, 1e20]: + _test_redirected_print(float(x), tp) + + for x in [np.inf, -np.inf, np.nan]: + _test_redirected_print(float(x), tp, _REF[x]) + + if tp(1e16).itemsize > 4: + _test_redirected_print(float(1e16), tp) + else: + ref = '1e+16' + _test_redirected_print(float(1e16), tp, ref) + +def check_complex_type_print(tp): + # We do not create complex with inf/nan directly because the feature is + # missing in python < 2.6 + for x in [0, 1, -1, 1e20]: + _test_redirected_print(complex(x), tp) + + if tp(1e16).itemsize > 8: + _test_redirected_print(complex(1e16), tp) + else: + ref = '(1e+16+0j)' + _test_redirected_print(complex(1e16), tp, ref) + + _test_redirected_print(complex(np.inf, 1), tp, '(inf+1j)') + _test_redirected_print(complex(-np.inf, 1), tp, '(-inf+1j)') + _test_redirected_print(complex(-np.nan, 1), tp, '(nan+1j)') + +def test_float_type_print(): + """Check formatting when using print """ + for t in [np.float32, np.double, np.longdouble]: + yield check_float_type_print, t + +def test_complex_type_print(): + """Check formatting when using print """ + for t in [np.complex64, np.cdouble, np.clongdouble]: + yield check_complex_type_print, t + +def test_scalar_format(): + """Test the str.format method with NumPy scalar types""" + tests = [('{0}', True, np.bool_), + ('{0}', False, np.bool_), + ('{0:d}', 130, np.uint8), + ('{0:d}', 50000, np.uint16), + ('{0:d}', 3000000000, np.uint32), + ('{0:d}', 15000000000000000000, np.uint64), + ('{0:d}', -120, np.int8), + ('{0:d}', -30000, np.int16), + ('{0:d}', -2000000000, np.int32), + ('{0:d}', -7000000000000000000, np.int64), + ('{0:g}', 1.5, np.float16), + ('{0:g}', 1.5, np.float32), + ('{0:g}', 1.5, np.float64), + ('{0:g}', 1.5, np.longdouble), + ('{0:g}', 1.5+0.5j, np.complex64), + ('{0:g}', 1.5+0.5j, np.complex128), + ('{0:g}', 1.5+0.5j, np.clongdouble)] + + for (fmat, val, valtype) in tests: + try: + assert_equal(fmat.format(val), fmat.format(valtype(val)), + "failed with val %s, type %s" % (val, valtype)) + except ValueError as e: + assert_(False, + "format raised exception (fmt='%s', val=%s, type=%s, exc='%s')" % + (fmat, repr(val), repr(valtype), str(e))) + + +# Locale tests: scalar types formatting should be independent of the locale +def in_foreign_locale(func): + """ + Swap LC_NUMERIC locale to one in which the decimal point is ',' and not '.' + If not possible, raise SkipTest + + """ + if sys.platform == 'win32': + locales = ['FRENCH'] + else: + locales = ['fr_FR', 'fr_FR.UTF-8', 'fi_FI', 'fi_FI.UTF-8'] + + def wrapper(*args, **kwargs): + curloc = locale.getlocale(locale.LC_NUMERIC) + try: + for loc in locales: + try: + locale.setlocale(locale.LC_NUMERIC, loc) + break + except locale.Error: + pass + else: + raise SkipTest("Skipping locale test, because " + "French locale not found") + return func(*args, **kwargs) + finally: + locale.setlocale(locale.LC_NUMERIC, locale=curloc) + return nose.tools.make_decorator(func)(wrapper) + +@in_foreign_locale +def test_locale_single(): + assert_equal(str(np.float32(1.2)), str(float(1.2))) + +@in_foreign_locale +def test_locale_double(): + assert_equal(str(np.double(1.2)), str(float(1.2))) + +@in_foreign_locale +def test_locale_longdouble(): + assert_equal(str(np.longdouble('1.2')), str(float(1.2))) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py new file mode 100644 index 0000000..3c17445 --- /dev/null +++ b/numpy/core/tests/test_records.py @@ -0,0 +1,429 @@ +from __future__ import division, absolute_import, print_function + +import sys +import collections +import pickle +import warnings +import textwrap +from os import path + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal, + assert_array_almost_equal, assert_raises, assert_warns + ) + + +class TestFromrecords(object): + def test_fromrecords(self): + r = np.rec.fromrecords([[456, 'dbe', 1.2], [2, 'de', 1.3]], + names='col1,col2,col3') + assert_equal(r[0].item(), (456, 'dbe', 1.2)) + assert_equal(r['col1'].dtype.kind, 'i') + if sys.version_info[0] >= 3: + assert_equal(r['col2'].dtype.kind, 'U') + assert_equal(r['col2'].dtype.itemsize, 12) + else: + assert_equal(r['col2'].dtype.kind, 'S') + assert_equal(r['col2'].dtype.itemsize, 3) + assert_equal(r['col3'].dtype.kind, 'f') + + def test_fromrecords_0len(self): + """ Verify fromrecords works with a 0-length input """ + dtype = [('a', float), ('b', float)] + r = np.rec.fromrecords([], dtype=dtype) + assert_equal(r.shape, (0,)) + + def test_fromrecords_2d(self): + data = [ + [(1, 2), (3, 4), (5, 6)], + [(6, 5), (4, 3), (2, 1)] + ] + expected_a = [[1, 3, 5], [6, 4, 2]] + expected_b = [[2, 4, 6], [5, 3, 1]] + + # try with dtype + r1 = np.rec.fromrecords(data, dtype=[('a', int), ('b', int)]) + assert_equal(r1['a'], expected_a) + assert_equal(r1['b'], expected_b) + + # try with names + r2 = np.rec.fromrecords(data, names=['a', 'b']) + assert_equal(r2['a'], expected_a) + assert_equal(r2['b'], expected_b) + + assert_equal(r1, r2) + + def test_fromrecords_list_of_lists(self): + # gh-10870 : For numpy 1.14 we keep the deprecated behavior + # that 1d list-of-lists input is accepted by fromrecords + expected = np.rec.array([(1, 1.5), (2, 2.5)], dtype='i8,f8') + with assert_warns(FutureWarning): + r = np.rec.fromrecords([[1, 1.5], [2, 2.5]], dtype='i8,f8') + assert_equal(r, expected) + + def test_method_array(self): + r = np.rec.array(b'abcdefg' * 100, formats='i2,a3,i4', shape=3, byteorder='big') + assert_equal(r[1].item(), (25444, b'efg', 1633837924)) + + def test_method_array2(self): + r = np.rec.array([(1, 11, 'a'), (2, 22, 'b'), (3, 33, 'c'), (4, 44, 'd'), (5, 55, 'ex'), + (6, 66, 'f'), (7, 77, 'g')], formats='u1,f4,a1') + assert_equal(r[1].item(), (2, 22.0, b'b')) + + def test_recarray_slices(self): + r = np.rec.array([(1, 11, 'a'), (2, 22, 'b'), (3, 33, 'c'), (4, 44, 'd'), (5, 55, 'ex'), + (6, 66, 'f'), (7, 77, 'g')], formats='u1,f4,a1') + assert_equal(r[1::2][1].item(), (4, 44.0, b'd')) + + def test_recarray_fromarrays(self): + x1 = np.array([1, 2, 3, 4]) + x2 = np.array(['a', 'dd', 'xyz', '12']) + x3 = np.array([1.1, 2, 3, 4]) + r = np.rec.fromarrays([x1, x2, x3], names='a,b,c') + assert_equal(r[1].item(), (2, 'dd', 2.0)) + x1[1] = 34 + assert_equal(r.a, np.array([1, 2, 3, 4])) + + def test_recarray_fromfile(self): + data_dir = path.join(path.dirname(__file__), 'data') + filename = path.join(data_dir, 'recarray_from_file.fits') + fd = open(filename, 'rb') + fd.seek(2880 * 2) + r1 = np.rec.fromfile(fd, formats='f8,i4,a5', shape=3, byteorder='big') + fd.seek(2880 * 2) + r2 = np.rec.array(fd, formats='f8,i4,a5', shape=3, byteorder='big') + fd.close() + assert_equal(r1, r2) + + def test_recarray_from_obj(self): + count = 10 + a = np.zeros(count, dtype='O') + b = np.zeros(count, dtype='f8') + c = np.zeros(count, dtype='f8') + for i in range(len(a)): + a[i] = list(range(1, 10)) + + mine = np.rec.fromarrays([a, b, c], names='date,data1,data2') + for i in range(len(a)): + assert_((mine.date[i] == list(range(1, 10)))) + assert_((mine.data1[i] == 0.0)) + assert_((mine.data2[i] == 0.0)) + + def test_recarray_repr(self): + a = np.array([(1, 0.1), (2, 0.2)], + dtype=[('foo', ' 2) & (a < 6)) + xb = np.where((b > 2) & (b < 6)) + ya = ((a > 2) & (a < 6)) + yb = ((b > 2) & (b < 6)) + assert_array_almost_equal(xa, ya.nonzero()) + assert_array_almost_equal(xb, yb.nonzero()) + assert_(np.all(a[ya] > 0.5)) + assert_(np.all(b[yb] > 0.5)) + + def test_endian_where(self): + # GitHub issue #369 + net = np.zeros(3, dtype='>f4') + net[1] = 0.00458849 + net[2] = 0.605202 + max_net = net.max() + test = np.where(net <= 0., max_net, net) + correct = np.array([ 0.60520202, 0.00458849, 0.60520202]) + assert_array_almost_equal(test, correct) + + def test_endian_recarray(self): + # Ticket #2185 + dt = np.dtype([ + ('head', '>u4'), + ('data', '>u4', 2), + ]) + buf = np.recarray(1, dtype=dt) + buf[0]['head'] = 1 + buf[0]['data'][:] = [1, 1] + + h = buf[0]['head'] + d = buf[0]['data'][0] + buf[0]['head'] = h + buf[0]['data'][0] = d + assert_(buf[0]['head'] == 1) + + def test_mem_dot(self): + # Ticket #106 + x = np.random.randn(0, 1) + y = np.random.randn(10, 1) + # Dummy array to detect bad memory access: + _z = np.ones(10) + _dummy = np.empty((0, 10)) + z = np.lib.stride_tricks.as_strided(_z, _dummy.shape, _dummy.strides) + np.dot(x, np.transpose(y), out=z) + assert_equal(_z, np.ones(10)) + # Do the same for the built-in dot: + np.core.multiarray.dot(x, np.transpose(y), out=z) + assert_equal(_z, np.ones(10)) + + def test_arange_endian(self): + # Ticket #111 + ref = np.arange(10) + x = np.arange(10, dtype='= (3, 4): + # encoding='bytes' was added in Py3.4 + for original, data in test_data: + result = pickle.loads(data, encoding='bytes') + assert_equal(result, original) + + if isinstance(result, np.ndarray) and result.dtype.names: + for name in result.dtype.names: + assert_(isinstance(name, str)) + + def test_pickle_dtype(self): + # Ticket #251 + pickle.dumps(float) + + def test_swap_real(self): + # Ticket #265 + assert_equal(np.arange(4, dtype='>c8').imag.max(), 0.0) + assert_equal(np.arange(4, dtype=' 1 and x['two'] > 2) + + def test_method_args(self): + # Make sure methods and functions have same default axis + # keyword and arguments + funcs1 = ['argmax', 'argmin', 'sum', ('product', 'prod'), + ('sometrue', 'any'), + ('alltrue', 'all'), 'cumsum', ('cumproduct', 'cumprod'), + 'ptp', 'cumprod', 'prod', 'std', 'var', 'mean', + 'round', 'min', 'max', 'argsort', 'sort'] + funcs2 = ['compress', 'take', 'repeat'] + + for func in funcs1: + arr = np.random.rand(8, 7) + arr2 = arr.copy() + if isinstance(func, tuple): + func_meth = func[1] + func = func[0] + else: + func_meth = func + res1 = getattr(arr, func_meth)() + res2 = getattr(np, func)(arr2) + if res1 is None: + res1 = arr + + if res1.dtype.kind in 'uib': + assert_((res1 == res2).all(), func) + else: + assert_(abs(res1-res2).max() < 1e-8, func) + + for func in funcs2: + arr1 = np.random.rand(8, 7) + arr2 = np.random.rand(8, 7) + res1 = None + if func == 'compress': + arr1 = arr1.ravel() + res1 = getattr(arr2, func)(arr1) + else: + arr2 = (15*arr2).astype(int).ravel() + if res1 is None: + res1 = getattr(arr1, func)(arr2) + res2 = getattr(np, func)(arr1, arr2) + assert_(abs(res1-res2).max() < 1e-8, func) + + def test_mem_lexsort_strings(self): + # Ticket #298 + lst = ['abc', 'cde', 'fgh'] + np.lexsort((lst,)) + + def test_fancy_index(self): + # Ticket #302 + x = np.array([1, 2])[np.array([0])] + assert_equal(x.shape, (1,)) + + def test_recarray_copy(self): + # Ticket #312 + dt = [('x', np.int16), ('y', np.float64)] + ra = np.array([(1, 2.3)], dtype=dt) + rb = np.rec.array(ra, dtype=dt) + rb['x'] = 2. + assert_(ra['x'] != rb['x']) + + def test_rec_fromarray(self): + # Ticket #322 + x1 = np.array([[1, 2], [3, 4], [5, 6]]) + x2 = np.array(['a', 'dd', 'xyz']) + x3 = np.array([1.1, 2, 3]) + np.rec.fromarrays([x1, x2, x3], formats="(2,)i4,a3,f8") + + def test_object_array_assign(self): + x = np.empty((2, 2), object) + x.flat[2] = (1, 2, 3) + assert_equal(x.flat[2], (1, 2, 3)) + + def test_ndmin_float64(self): + # Ticket #324 + x = np.array([1, 2, 3], dtype=np.float64) + assert_equal(np.array(x, dtype=np.float32, ndmin=2).ndim, 2) + assert_equal(np.array(x, dtype=np.float64, ndmin=2).ndim, 2) + + def test_ndmin_order(self): + # Issue #465 and related checks + assert_(np.array([1, 2], order='C', ndmin=3).flags.c_contiguous) + assert_(np.array([1, 2], order='F', ndmin=3).flags.f_contiguous) + assert_(np.array(np.ones((2, 2), order='F'), ndmin=3).flags.f_contiguous) + assert_(np.array(np.ones((2, 2), order='C'), ndmin=3).flags.c_contiguous) + + def test_mem_axis_minimization(self): + # Ticket #327 + data = np.arange(5) + data = np.add.outer(data, data) + + def test_mem_float_imag(self): + # Ticket #330 + np.float64(1.0).imag + + def test_dtype_tuple(self): + # Ticket #334 + assert_(np.dtype('i4') == np.dtype(('i4', ()))) + + def test_dtype_posttuple(self): + # Ticket #335 + np.dtype([('col1', '()i4')]) + + def test_numeric_carray_compare(self): + # Ticket #341 + assert_equal(np.array(['X'], 'c'), b'X') + + def test_string_array_size(self): + # Ticket #342 + assert_raises(ValueError, + np.array, [['X'], ['X', 'X', 'X']], '|S1') + + def test_dtype_repr(self): + # Ticket #344 + dt1 = np.dtype(('uint32', 2)) + dt2 = np.dtype(('uint32', (2,))) + assert_equal(dt1.__repr__(), dt2.__repr__()) + + def test_reshape_order(self): + # Make sure reshape order works. + a = np.arange(6).reshape(2, 3, order='F') + assert_equal(a, [[0, 2, 4], [1, 3, 5]]) + a = np.array([[1, 2], [3, 4], [5, 6], [7, 8]]) + b = a[:, 1] + assert_equal(b.reshape(2, 2, order='F'), [[2, 6], [4, 8]]) + + def test_reshape_zero_strides(self): + # Issue #380, test reshaping of zero strided arrays + a = np.ones(1) + a = np.lib.stride_tricks.as_strided(a, shape=(5,), strides=(0,)) + assert_(a.reshape(5, 1).strides[0] == 0) + + def test_reshape_zero_size(self): + # GitHub Issue #2700, setting shape failed for 0-sized arrays + a = np.ones((0, 2)) + a.shape = (-1, 2) + + # Cannot test if NPY_RELAXED_STRIDES_CHECKING changes the strides. + # With NPY_RELAXED_STRIDES_CHECKING the test becomes superfluous. + @dec.skipif(np.ones(1).strides[0] == np.iinfo(np.intp).max) + def test_reshape_trailing_ones_strides(self): + # GitHub issue gh-2949, bad strides for trailing ones of new shape + a = np.zeros(12, dtype=np.int32)[::2] # not contiguous + strides_c = (16, 8, 8, 8) + strides_f = (8, 24, 48, 48) + assert_equal(a.reshape(3, 2, 1, 1).strides, strides_c) + assert_equal(a.reshape(3, 2, 1, 1, order='F').strides, strides_f) + assert_equal(np.array(0, dtype=np.int32).reshape(1, 1).strides, (4, 4)) + + def test_repeat_discont(self): + # Ticket #352 + a = np.arange(12).reshape(4, 3)[:, 2] + assert_equal(a.repeat(3), [2, 2, 2, 5, 5, 5, 8, 8, 8, 11, 11, 11]) + + def test_array_index(self): + # Make sure optimization is not called in this case. + a = np.array([1, 2, 3]) + a2 = np.array([[1, 2, 3]]) + assert_equal(a[np.where(a == 3)], a2[np.where(a2 == 3)]) + + def test_object_argmax(self): + a = np.array([1, 2, 3], dtype=object) + assert_(a.argmax() == 2) + + def test_recarray_fields(self): + # Ticket #372 + dt0 = np.dtype([('f0', 'i4'), ('f1', 'i4')]) + dt1 = np.dtype([('f0', 'i8'), ('f1', 'i8')]) + for a in [np.array([(1, 2), (3, 4)], "i4,i4"), + np.rec.array([(1, 2), (3, 4)], "i4,i4"), + np.rec.array([(1, 2), (3, 4)]), + np.rec.fromarrays([(1, 2), (3, 4)], "i4,i4"), + np.rec.fromarrays([(1, 2), (3, 4)])]: + assert_(a.dtype in [dt0, dt1]) + + def test_random_shuffle(self): + # Ticket #374 + a = np.arange(5).reshape((5, 1)) + b = a.copy() + np.random.shuffle(b) + assert_equal(np.sort(b, axis=0), a) + + def test_refcount_vdot(self): + # Changeset #3443 + _assert_valid_refcount(np.vdot) + + def test_startswith(self): + ca = np.char.array(['Hi', 'There']) + assert_equal(ca.startswith('H'), [True, False]) + + def test_noncommutative_reduce_accumulate(self): + # Ticket #413 + tosubtract = np.arange(5) + todivide = np.array([2.0, 0.5, 0.25]) + assert_equal(np.subtract.reduce(tosubtract), -10) + assert_equal(np.divide.reduce(todivide), 16.0) + assert_array_equal(np.subtract.accumulate(tosubtract), + np.array([0, -1, -3, -6, -10])) + assert_array_equal(np.divide.accumulate(todivide), + np.array([2., 4., 16.])) + + def test_convolve_empty(self): + # Convolve should raise an error for empty input array. + assert_raises(ValueError, np.convolve, [], [1]) + assert_raises(ValueError, np.convolve, [1], []) + + def test_multidim_byteswap(self): + # Ticket #449 + r = np.array([(1, (0, 1, 2))], dtype="i2,3i2") + assert_array_equal(r.byteswap(), + np.array([(256, (0, 256, 512))], r.dtype)) + + def test_string_NULL(self): + # Changeset 3557 + assert_equal(np.array("a\x00\x0b\x0c\x00").item(), + 'a\x00\x0b\x0c') + + def test_junk_in_string_fields_of_recarray(self): + # Ticket #483 + r = np.array([[b'abc']], dtype=[('var1', '|S20')]) + assert_(asbytes(r['var1'][0][0]) == b'abc') + + def test_take_output(self): + # Ensure that 'take' honours output parameter. + x = np.arange(12).reshape((3, 4)) + a = np.take(x, [0, 2], axis=1) + b = np.zeros_like(a) + np.take(x, [0, 2], axis=1, out=b) + assert_array_equal(a, b) + + def test_take_object_fail(self): + # Issue gh-3001 + d = 123. + a = np.array([d, 1], dtype=object) + if HAS_REFCOUNT: + ref_d = sys.getrefcount(d) + try: + a.take([0, 100]) + except IndexError: + pass + if HAS_REFCOUNT: + assert_(ref_d == sys.getrefcount(d)) + + def test_array_str_64bit(self): + # Ticket #501 + s = np.array([1, np.nan], dtype=np.float64) + with np.errstate(all='raise'): + np.array_str(s) # Should succeed + + def test_frompyfunc_endian(self): + # Ticket #503 + from math import radians + uradians = np.frompyfunc(radians, 1, 1) + big_endian = np.array([83.4, 83.5], dtype='>f8') + little_endian = np.array([83.4, 83.5], dtype=' object + # casting succeeds + def rs(): + x = np.ones([484, 286]) + y = np.zeros([484, 286]) + x |= y + + assert_raises(TypeError, rs) + + def test_unicode_scalar(self): + # Ticket #600 + x = np.array(["DROND", "DROND1"], dtype="U6") + el = x[1] + new = pickle.loads(pickle.dumps(el)) + assert_equal(new, el) + + def test_arange_non_native_dtype(self): + # Ticket #616 + for T in ('>f4', ' 0)] = v + + assert_raises(IndexError, ia, x, s, np.zeros(9, dtype=float)) + assert_raises(IndexError, ia, x, s, np.zeros(11, dtype=float)) + + # Old special case (different code path): + assert_raises(ValueError, ia, x.flat, s, np.zeros(9, dtype=float)) + assert_raises(ValueError, ia, x.flat, s, np.zeros(11, dtype=float)) + + def test_mem_scalar_indexing(self): + # Ticket #603 + x = np.array([0], dtype=float) + index = np.array(0, dtype=np.int32) + x[index] + + def test_binary_repr_0_width(self): + assert_equal(np.binary_repr(0, width=3), '000') + + def test_fromstring(self): + assert_equal(np.fromstring("12:09:09", dtype=int, sep=":"), + [12, 9, 9]) + + def test_searchsorted_variable_length(self): + x = np.array(['a', 'aa', 'b']) + y = np.array(['d', 'e']) + assert_equal(x.searchsorted(y), [3, 3]) + + def test_string_argsort_with_zeros(self): + # Check argsort for strings containing zeros. + x = np.frombuffer(b"\x00\x02\x00\x01", dtype="|S2") + assert_array_equal(x.argsort(kind='m'), np.array([1, 0])) + assert_array_equal(x.argsort(kind='q'), np.array([1, 0])) + + def test_string_sort_with_zeros(self): + # Check sort for strings containing zeros. + x = np.frombuffer(b"\x00\x02\x00\x01", dtype="|S2") + y = np.frombuffer(b"\x00\x01\x00\x02", dtype="|S2") + assert_array_equal(np.sort(x, kind="q"), y) + + def test_copy_detection_zero_dim(self): + # Ticket #658 + np.indices((0, 3, 4)).T.reshape(-1, 3) + + def test_flat_byteorder(self): + # Ticket #657 + x = np.arange(10) + assert_array_equal(x.astype('>i4'), x.astype('i4').flat[:], x.astype('i4')): + x = np.array([-1, 0, 1], dtype=dt) + assert_equal(x.flat[0].dtype, x[0].dtype) + + def test_copy_detection_corner_case(self): + # Ticket #658 + np.indices((0, 3, 4)).T.reshape(-1, 3) + + # Cannot test if NPY_RELAXED_STRIDES_CHECKING changes the strides. + # With NPY_RELAXED_STRIDES_CHECKING the test becomes superfluous, + # 0-sized reshape itself is tested elsewhere. + @dec.skipif(np.ones(1).strides[0] == np.iinfo(np.intp).max) + def test_copy_detection_corner_case2(self): + # Ticket #771: strides are not set correctly when reshaping 0-sized + # arrays + b = np.indices((0, 3, 4)).T.reshape(-1, 3) + assert_equal(b.strides, (3 * b.itemsize, b.itemsize)) + + def test_object_array_refcounting(self): + # Ticket #633 + if not hasattr(sys, 'getrefcount'): + return + + # NB. this is probably CPython-specific + + cnt = sys.getrefcount + + a = object() + b = object() + c = object() + + cnt0_a = cnt(a) + cnt0_b = cnt(b) + cnt0_c = cnt(c) + + # -- 0d -> 1-d broadcast slice assignment + + arr = np.zeros(5, dtype=np.object_) + + arr[:] = a + assert_equal(cnt(a), cnt0_a + 5) + + arr[:] = b + assert_equal(cnt(a), cnt0_a) + assert_equal(cnt(b), cnt0_b + 5) + + arr[:2] = c + assert_equal(cnt(b), cnt0_b + 3) + assert_equal(cnt(c), cnt0_c + 2) + + del arr + + # -- 1-d -> 2-d broadcast slice assignment + + arr = np.zeros((5, 2), dtype=np.object_) + arr0 = np.zeros(2, dtype=np.object_) + + arr0[0] = a + assert_(cnt(a) == cnt0_a + 1) + arr0[1] = b + assert_(cnt(b) == cnt0_b + 1) + + arr[:, :] = arr0 + assert_(cnt(a) == cnt0_a + 6) + assert_(cnt(b) == cnt0_b + 6) + + arr[:, 0] = None + assert_(cnt(a) == cnt0_a + 1) + + del arr, arr0 + + # -- 2-d copying + flattening + + arr = np.zeros((5, 2), dtype=np.object_) + + arr[:, 0] = a + arr[:, 1] = b + assert_(cnt(a) == cnt0_a + 5) + assert_(cnt(b) == cnt0_b + 5) + + arr2 = arr.copy() + assert_(cnt(a) == cnt0_a + 10) + assert_(cnt(b) == cnt0_b + 10) + + arr2 = arr[:, 0].copy() + assert_(cnt(a) == cnt0_a + 10) + assert_(cnt(b) == cnt0_b + 5) + + arr2 = arr.flatten() + assert_(cnt(a) == cnt0_a + 10) + assert_(cnt(b) == cnt0_b + 10) + + del arr, arr2 + + # -- concatenate, repeat, take, choose + + arr1 = np.zeros((5, 1), dtype=np.object_) + arr2 = np.zeros((5, 1), dtype=np.object_) + + arr1[...] = a + arr2[...] = b + assert_(cnt(a) == cnt0_a + 5) + assert_(cnt(b) == cnt0_b + 5) + + tmp = np.concatenate((arr1, arr2)) + assert_(cnt(a) == cnt0_a + 5 + 5) + assert_(cnt(b) == cnt0_b + 5 + 5) + + tmp = arr1.repeat(3, axis=0) + assert_(cnt(a) == cnt0_a + 5 + 3*5) + + tmp = arr1.take([1, 2, 3], axis=0) + assert_(cnt(a) == cnt0_a + 5 + 3) + + x = np.array([[0], [1], [0], [1], [1]], int) + tmp = x.choose(arr1, arr2) + assert_(cnt(a) == cnt0_a + 5 + 2) + assert_(cnt(b) == cnt0_b + 5 + 3) + + del tmp # Avoid pyflakes unused variable warning + + def test_mem_custom_float_to_array(self): + # Ticket 702 + class MyFloat(object): + def __float__(self): + return 1.0 + + tmp = np.atleast_1d([MyFloat()]) + tmp.astype(float) # Should succeed + + def test_object_array_refcount_self_assign(self): + # Ticket #711 + class VictimObject(object): + deleted = False + + def __del__(self): + self.deleted = True + + d = VictimObject() + arr = np.zeros(5, dtype=np.object_) + arr[:] = d + del d + arr[:] = arr # refcount of 'd' might hit zero here + assert_(not arr[0].deleted) + arr[:] = arr # trying to induce a segfault by doing it again... + assert_(not arr[0].deleted) + + def test_mem_fromiter_invalid_dtype_string(self): + x = [1, 2, 3] + assert_raises(ValueError, + np.fromiter, [xi for xi in x], dtype='S') + + def test_reduce_big_object_array(self): + # Ticket #713 + oldsize = np.setbufsize(10*16) + a = np.array([None]*161, object) + assert_(not np.any(a)) + np.setbufsize(oldsize) + + def test_mem_0d_array_index(self): + # Ticket #714 + np.zeros(10)[np.array(0)] + + def test_nonnative_endian_fill(self): + # Non-native endian arrays were incorrectly filled with scalars + # before r5034. + if sys.byteorder == 'little': + dtype = np.dtype('>i4') + else: + dtype = np.dtype('= 3: + f = open(filename, 'rb') + xp = pickle.load(f, encoding='latin1') + f.close() + else: + f = open(filename) + xp = pickle.load(f) + f.close() + xpd = xp.astype(np.float64) + assert_((xp.__array_interface__['data'][0] != + xpd.__array_interface__['data'][0])) + + def test_compress_small_type(self): + # Ticket #789, changeset 5217. + # compress with out argument segfaulted if cannot cast safely + import numpy as np + a = np.array([[1, 2], [3, 4]]) + b = np.zeros((2, 1), dtype=np.single) + try: + a.compress([True, False], axis=1, out=b) + raise AssertionError("compress with an out which cannot be " + "safely casted should not return " + "successfully") + except TypeError: + pass + + def test_attributes(self): + # Ticket #791 + class TestArray(np.ndarray): + def __new__(cls, data, info): + result = np.array(data) + result = result.view(cls) + result.info = info + return result + + def __array_finalize__(self, obj): + self.info = getattr(obj, 'info', '') + + dat = TestArray([[1, 2, 3, 4], [5, 6, 7, 8]], 'jubba') + assert_(dat.info == 'jubba') + dat.resize((4, 2)) + assert_(dat.info == 'jubba') + dat.sort() + assert_(dat.info == 'jubba') + dat.fill(2) + assert_(dat.info == 'jubba') + dat.put([2, 3, 4], [6, 3, 4]) + assert_(dat.info == 'jubba') + dat.setfield(4, np.int32, 0) + assert_(dat.info == 'jubba') + dat.setflags() + assert_(dat.info == 'jubba') + assert_(dat.all(1).info == 'jubba') + assert_(dat.any(1).info == 'jubba') + assert_(dat.argmax(1).info == 'jubba') + assert_(dat.argmin(1).info == 'jubba') + assert_(dat.argsort(1).info == 'jubba') + assert_(dat.astype(TestArray).info == 'jubba') + assert_(dat.byteswap().info == 'jubba') + assert_(dat.clip(2, 7).info == 'jubba') + assert_(dat.compress([0, 1, 1]).info == 'jubba') + assert_(dat.conj().info == 'jubba') + assert_(dat.conjugate().info == 'jubba') + assert_(dat.copy().info == 'jubba') + dat2 = TestArray([2, 3, 1, 0], 'jubba') + choices = [[0, 1, 2, 3], [10, 11, 12, 13], + [20, 21, 22, 23], [30, 31, 32, 33]] + assert_(dat2.choose(choices).info == 'jubba') + assert_(dat.cumprod(1).info == 'jubba') + assert_(dat.cumsum(1).info == 'jubba') + assert_(dat.diagonal().info == 'jubba') + assert_(dat.flatten().info == 'jubba') + assert_(dat.getfield(np.int32, 0).info == 'jubba') + assert_(dat.imag.info == 'jubba') + assert_(dat.max(1).info == 'jubba') + assert_(dat.mean(1).info == 'jubba') + assert_(dat.min(1).info == 'jubba') + assert_(dat.newbyteorder().info == 'jubba') + assert_(dat.prod(1).info == 'jubba') + assert_(dat.ptp(1).info == 'jubba') + assert_(dat.ravel().info == 'jubba') + assert_(dat.real.info == 'jubba') + assert_(dat.repeat(2).info == 'jubba') + assert_(dat.reshape((2, 4)).info == 'jubba') + assert_(dat.round().info == 'jubba') + assert_(dat.squeeze().info == 'jubba') + assert_(dat.std(1).info == 'jubba') + assert_(dat.sum(1).info == 'jubba') + assert_(dat.swapaxes(0, 1).info == 'jubba') + assert_(dat.take([2, 3, 5]).info == 'jubba') + assert_(dat.transpose().info == 'jubba') + assert_(dat.T.info == 'jubba') + assert_(dat.var(1).info == 'jubba') + assert_(dat.view(TestArray).info == 'jubba') + # These methods do not preserve subclasses + assert_(type(dat.nonzero()[0]) is np.ndarray) + assert_(type(dat.nonzero()[1]) is np.ndarray) + + def test_recarray_tolist(self): + # Ticket #793, changeset r5215 + # Comparisons fail for NaN, so we can't use random memory + # for the test. + buf = np.zeros(40, dtype=np.int8) + a = np.recarray(2, formats="i4,f8,f8", names="id,x,y", buf=buf) + b = a.tolist() + assert_( a[0].tolist() == b[0]) + assert_( a[1].tolist() == b[1]) + + def test_nonscalar_item_method(self): + # Make sure that .item() fails graciously when it should + a = np.arange(5) + assert_raises(ValueError, a.item) + + def test_char_array_creation(self): + a = np.array('123', dtype='c') + b = np.array([b'1', b'2', b'3']) + assert_equal(a, b) + + def test_unaligned_unicode_access(self): + # Ticket #825 + for i in range(1, 9): + msg = 'unicode offset: %d chars' % i + t = np.dtype([('a', 'S%d' % i), ('b', 'U2')]) + x = np.array([(b'a', u'b')], dtype=t) + if sys.version_info[0] >= 3: + assert_equal(str(x), "[(b'a', 'b')]", err_msg=msg) + else: + assert_equal(str(x), "[('a', u'b')]", err_msg=msg) + + def test_sign_for_complex_nan(self): + # Ticket 794. + with np.errstate(invalid='ignore'): + C = np.array([-np.inf, -2+1j, 0, 2-1j, np.inf, np.nan]) + have = np.sign(C) + want = np.array([-1+0j, -1+0j, 0+0j, 1+0j, 1+0j, np.nan]) + assert_equal(have, want) + + def test_for_equal_names(self): + # Ticket #674 + dt = np.dtype([('foo', float), ('bar', float)]) + a = np.zeros(10, dt) + b = list(a.dtype.names) + b[0] = "notfoo" + a.dtype.names = b + assert_(a.dtype.names[0] == "notfoo") + assert_(a.dtype.names[1] == "bar") + + def test_for_object_scalar_creation(self): + # Ticket #816 + a = np.object_() + b = np.object_(3) + b2 = np.object_(3.0) + c = np.object_([4, 5]) + d = np.object_([None, {}, []]) + assert_(a is None) + assert_(type(b) is int) + assert_(type(b2) is float) + assert_(type(c) is np.ndarray) + assert_(c.dtype == object) + assert_(d.dtype == object) + + def test_array_resize_method_system_error(self): + # Ticket #840 - order should be an invalid keyword. + x = np.array([[0, 1], [2, 3]]) + assert_raises(TypeError, x.resize, (2, 2), order='C') + + def test_for_zero_length_in_choose(self): + "Ticket #882" + a = np.array(1) + assert_raises(ValueError, lambda x: x.choose([]), a) + + def test_array_ndmin_overflow(self): + "Ticket #947." + assert_raises(ValueError, lambda: np.array([1], ndmin=33)) + + def test_void_scalar_with_titles(self): + # No ticket + data = [('john', 4), ('mary', 5)] + dtype1 = [(('source:yy', 'name'), 'O'), (('source:xx', 'id'), int)] + arr = np.array(data, dtype=dtype1) + assert_(arr[0][0] == 'john') + assert_(arr[0][1] == 4) + + def test_void_scalar_constructor(self): + #Issue #1550 + + #Create test string data, construct void scalar from data and assert + #that void scalar contains original data. + test_string = np.array("test") + test_string_void_scalar = np.core.multiarray.scalar( + np.dtype(("V", test_string.dtype.itemsize)), test_string.tobytes()) + + assert_(test_string_void_scalar.view(test_string.dtype) == test_string) + + #Create record scalar, construct from data and assert that + #reconstructed scalar is correct. + test_record = np.ones((), "i,i") + test_record_void_scalar = np.core.multiarray.scalar( + test_record.dtype, test_record.tobytes()) + + assert_(test_record_void_scalar == test_record) + + #Test pickle and unpickle of void and record scalars + assert_(pickle.loads(pickle.dumps(test_string)) == test_string) + assert_(pickle.loads(pickle.dumps(test_record)) == test_record) + + def test_blasdot_uninitialized_memory(self): + # Ticket #950 + for m in [0, 1, 2]: + for n in [0, 1, 2]: + for k in range(3): + # Try to ensure that x->data contains non-zero floats + x = np.array([123456789e199], dtype=np.float64) + if IS_PYPY: + x.resize((m, 0), refcheck=False) + else: + x.resize((m, 0)) + y = np.array([123456789e199], dtype=np.float64) + if IS_PYPY: + y.resize((0, n), refcheck=False) + else: + y.resize((0, n)) + + # `dot` should just return zero (m, n) matrix + z = np.dot(x, y) + assert_(np.all(z == 0)) + assert_(z.shape == (m, n)) + + def test_zeros(self): + # Regression test for #1061. + # Set a size which cannot fit into a 64 bits signed integer + sz = 2 ** 64 + good = 'Maximum allowed dimension exceeded' + try: + np.empty(sz) + except ValueError as e: + if not str(e) == good: + self.fail("Got msg '%s', expected '%s'" % (e, good)) + except Exception as e: + self.fail("Got exception of type %s instead of ValueError" % type(e)) + + def test_huge_arange(self): + # Regression test for #1062. + # Set a size which cannot fit into a 64 bits signed integer + sz = 2 ** 64 + good = 'Maximum allowed size exceeded' + try: + np.arange(sz) + assert_(np.size == sz) + except ValueError as e: + if not str(e) == good: + self.fail("Got msg '%s', expected '%s'" % (e, good)) + except Exception as e: + self.fail("Got exception of type %s instead of ValueError" % type(e)) + + def test_fromiter_bytes(self): + # Ticket #1058 + a = np.fromiter(list(range(10)), dtype='b') + b = np.fromiter(list(range(10)), dtype='B') + assert_(np.alltrue(a == np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))) + assert_(np.alltrue(b == np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))) + + def test_array_from_sequence_scalar_array(self): + # Ticket #1078: segfaults when creating an array with a sequence of + # 0d arrays. + a = np.array((np.ones(2), np.array(2))) + assert_equal(a.shape, (2,)) + assert_equal(a.dtype, np.dtype(object)) + assert_equal(a[0], np.ones(2)) + assert_equal(a[1], np.array(2)) + + a = np.array(((1,), np.array(1))) + assert_equal(a.shape, (2,)) + assert_equal(a.dtype, np.dtype(object)) + assert_equal(a[0], (1,)) + assert_equal(a[1], np.array(1)) + + def test_array_from_sequence_scalar_array2(self): + # Ticket #1081: weird array with strange input... + t = np.array([np.array([]), np.array(0, object)]) + assert_equal(t.shape, (2,)) + assert_equal(t.dtype, np.dtype(object)) + + def test_array_too_big(self): + # Ticket #1080. + assert_raises(ValueError, np.zeros, [975]*7, np.int8) + assert_raises(ValueError, np.zeros, [26244]*5, np.int8) + + def test_dtype_keyerrors_(self): + # Ticket #1106. + dt = np.dtype([('f1', np.uint)]) + assert_raises(KeyError, dt.__getitem__, "f2") + assert_raises(IndexError, dt.__getitem__, 1) + assert_raises(TypeError, dt.__getitem__, 0.0) + + def test_lexsort_buffer_length(self): + # Ticket #1217, don't segfault. + a = np.ones(100, dtype=np.int8) + b = np.ones(100, dtype=np.int32) + i = np.lexsort((a[::-1], b)) + assert_equal(i, np.arange(100, dtype=int)) + + def test_object_array_to_fixed_string(self): + # Ticket #1235. + a = np.array(['abcdefgh', 'ijklmnop'], dtype=np.object_) + b = np.array(a, dtype=(np.str_, 8)) + assert_equal(a, b) + c = np.array(a, dtype=(np.str_, 5)) + assert_equal(c, np.array(['abcde', 'ijklm'])) + d = np.array(a, dtype=(np.str_, 12)) + assert_equal(a, d) + e = np.empty((2, ), dtype=(np.str_, 8)) + e[:] = a[:] + assert_equal(a, e) + + def test_unicode_to_string_cast(self): + # Ticket #1240. + a = np.array([[u'abc', u'\u03a3'], + [u'asdf', u'erw']], + dtype='U') + assert_raises(UnicodeEncodeError, np.array, a, 'S4') + + def test_mixed_string_unicode_array_creation(self): + a = np.array(['1234', u'123']) + assert_(a.itemsize == 16) + a = np.array([u'123', '1234']) + assert_(a.itemsize == 16) + a = np.array(['1234', u'123', '12345']) + assert_(a.itemsize == 20) + a = np.array([u'123', '1234', u'12345']) + assert_(a.itemsize == 20) + a = np.array([u'123', '1234', u'1234']) + assert_(a.itemsize == 16) + + def test_misaligned_objects_segfault(self): + # Ticket #1198 and #1267 + a1 = np.zeros((10,), dtype='O,c') + a2 = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'], 'S10') + a1['f0'] = a2 + repr(a1) + np.argmax(a1['f0']) + a1['f0'][1] = "FOO" + a1['f0'] = "FOO" + np.array(a1['f0'], dtype='S') + np.nonzero(a1['f0']) + a1.sort() + copy.deepcopy(a1) + + def test_misaligned_scalars_segfault(self): + # Ticket #1267 + s1 = np.array(('a', 'Foo'), dtype='c,O') + s2 = np.array(('b', 'Bar'), dtype='c,O') + s1['f1'] = s2['f1'] + s1['f1'] = 'Baz' + + def test_misaligned_dot_product_objects(self): + # Ticket #1267 + # This didn't require a fix, but it's worth testing anyway, because + # it may fail if .dot stops enforcing the arrays to be BEHAVED + a = np.array([[(1, 'a'), (0, 'a')], [(0, 'a'), (1, 'a')]], dtype='O,c') + b = np.array([[(4, 'a'), (1, 'a')], [(2, 'a'), (2, 'a')]], dtype='O,c') + np.dot(a['f0'], b['f0']) + + def test_byteswap_complex_scalar(self): + # Ticket #1259 and gh-441 + for dtype in [np.dtype('<'+t) for t in np.typecodes['Complex']]: + z = np.array([2.2-1.1j], dtype) + x = z[0] # always native-endian + y = x.byteswap() + if x.dtype.byteorder == z.dtype.byteorder: + # little-endian machine + assert_equal(x, np.frombuffer(y.tobytes(), dtype=dtype.newbyteorder())) + else: + # big-endian machine + assert_equal(x, np.frombuffer(y.tobytes(), dtype=dtype)) + # double check real and imaginary parts: + assert_equal(x.real, y.real.byteswap()) + assert_equal(x.imag, y.imag.byteswap()) + + def test_structured_arrays_with_objects1(self): + # Ticket #1299 + stra = 'aaaa' + strb = 'bbbb' + x = np.array([[(0, stra), (1, strb)]], 'i8,O') + x[x.nonzero()] = x.ravel()[:1] + assert_(x[0, 1] == x[0, 0]) + + @dec.skipif(not HAS_REFCOUNT, "python has no sys.getrefcount") + def test_structured_arrays_with_objects2(self): + # Ticket #1299 second test + stra = 'aaaa' + strb = 'bbbb' + numb = sys.getrefcount(strb) + numa = sys.getrefcount(stra) + x = np.array([[(0, stra), (1, strb)]], 'i8,O') + x[x.nonzero()] = x.ravel()[:1] + assert_(sys.getrefcount(strb) == numb) + assert_(sys.getrefcount(stra) == numa + 2) + + def test_duplicate_title_and_name(self): + # Ticket #1254 + dtspec = [(('a', 'a'), 'i'), ('b', 'i')] + assert_raises(ValueError, np.dtype, dtspec) + + def test_signed_integer_division_overflow(self): + # Ticket #1317. + def test_type(t): + min = np.array([np.iinfo(t).min]) + min //= -1 + + with np.errstate(divide="ignore"): + for t in (np.int8, np.int16, np.int32, np.int64, int, np.long): + test_type(t) + + def test_buffer_hashlib(self): + try: + from hashlib import md5 + except ImportError: + from md5 import new as md5 + + x = np.array([1, 2, 3], dtype=np.dtype('c') + + def test_log1p_compiler_shenanigans(self): + # Check if log1p is behaving on 32 bit intel systems. + assert_(np.isfinite(np.log1p(np.exp2(-53)))) + + def test_fromiter_comparison(self): + a = np.fromiter(list(range(10)), dtype='b') + b = np.fromiter(list(range(10)), dtype='B') + assert_(np.alltrue(a == np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))) + assert_(np.alltrue(b == np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))) + + def test_fromstring_crash(self): + # Ticket #1345: the following should not cause a crash + np.fromstring(b'aa, aa, 1.0', sep=',') + + def test_ticket_1539(self): + dtypes = [x for x in np.typeDict.values() + if (issubclass(x, np.number) + and not issubclass(x, np.timedelta64))] + a = np.array([], np.bool_) # not x[0] because it is unordered + failures = [] + + for x in dtypes: + b = a.astype(x) + for y in dtypes: + c = a.astype(y) + try: + np.dot(b, c) + except TypeError: + failures.append((x, y)) + if failures: + raise AssertionError("Failures: %r" % failures) + + def test_ticket_1538(self): + x = np.finfo(np.float32) + for name in 'eps epsneg max min resolution tiny'.split(): + assert_equal(type(getattr(x, name)), np.float32, + err_msg=name) + + def test_ticket_1434(self): + # Check that the out= argument in var and std has an effect + data = np.array(((1, 2, 3), (4, 5, 6), (7, 8, 9))) + out = np.zeros((3,)) + + ret = data.var(axis=1, out=out) + assert_(ret is out) + assert_array_equal(ret, data.var(axis=1)) + + ret = data.std(axis=1, out=out) + assert_(ret is out) + assert_array_equal(ret, data.std(axis=1)) + + def test_complex_nan_maximum(self): + cnan = complex(0, np.nan) + assert_equal(np.maximum(1, cnan), cnan) + + def test_subclass_int_tuple_assignment(self): + # ticket #1563 + class Subclass(np.ndarray): + def __new__(cls, i): + return np.ones((i,)).view(cls) + + x = Subclass(5) + x[(0,)] = 2 # shouldn't raise an exception + assert_equal(x[0], 2) + + def test_ufunc_no_unnecessary_views(self): + # ticket #1548 + class Subclass(np.ndarray): + pass + x = np.array([1, 2, 3]).view(Subclass) + y = np.add(x, x, x) + assert_equal(id(x), id(y)) + + @dec.skipif(not HAS_REFCOUNT, "python has no sys.getrefcount") + def test_take_refcount(self): + # ticket #939 + a = np.arange(16, dtype=float) + a.shape = (4, 4) + lut = np.ones((5 + 3, 4), float) + rgba = np.empty(shape=a.shape + (4,), dtype=lut.dtype) + c1 = sys.getrefcount(rgba) + try: + lut.take(a, axis=0, mode='clip', out=rgba) + except TypeError: + pass + c2 = sys.getrefcount(rgba) + assert_equal(c1, c2) + + def test_fromfile_tofile_seeks(self): + # On Python 3, tofile/fromfile used to get (#1610) the Python + # file handle out of sync + f0 = tempfile.NamedTemporaryFile() + f = f0.file + f.write(np.arange(255, dtype='u1').tobytes()) + + f.seek(20) + ret = np.fromfile(f, count=4, dtype='u1') + assert_equal(ret, np.array([20, 21, 22, 23], dtype='u1')) + assert_equal(f.tell(), 24) + + f.seek(40) + np.array([1, 2, 3], dtype='u1').tofile(f) + assert_equal(f.tell(), 43) + + f.seek(40) + data = f.read(3) + assert_equal(data, b"\x01\x02\x03") + + f.seek(80) + f.read(4) + data = np.fromfile(f, dtype='u1', count=4) + assert_equal(data, np.array([84, 85, 86, 87], dtype='u1')) + + f.close() + + def test_complex_scalar_warning(self): + for tp in [np.csingle, np.cdouble, np.clongdouble]: + x = tp(1+2j) + assert_warns(np.ComplexWarning, float, x) + with suppress_warnings() as sup: + sup.filter(np.ComplexWarning) + assert_equal(float(x), float(x.real)) + + def test_complex_scalar_complex_cast(self): + for tp in [np.csingle, np.cdouble, np.clongdouble]: + x = tp(1+2j) + assert_equal(complex(x), 1+2j) + + def test_complex_boolean_cast(self): + # Ticket #2218 + for tp in [np.csingle, np.cdouble, np.clongdouble]: + x = np.array([0, 0+0.5j, 0.5+0j], dtype=tp) + assert_equal(x.astype(bool), np.array([0, 1, 1], dtype=bool)) + assert_(np.any(x)) + assert_(np.all(x[1:])) + + def test_uint_int_conversion(self): + x = 2**64 - 1 + assert_equal(int(np.uint64(x)), x) + + def test_duplicate_field_names_assign(self): + ra = np.fromiter(((i*3, i*2) for i in range(10)), dtype='i8,f8') + ra.dtype.names = ('f1', 'f2') + repr(ra) # should not cause a segmentation fault + assert_raises(ValueError, setattr, ra.dtype, 'names', ('f1', 'f1')) + + def test_eq_string_and_object_array(self): + # From e-mail thread "__eq__ with str and object" (Keith Goodman) + a1 = np.array(['a', 'b'], dtype=object) + a2 = np.array(['a', 'c']) + assert_array_equal(a1 == a2, [True, False]) + assert_array_equal(a2 == a1, [True, False]) + + def test_nonzero_byteswap(self): + a = np.array([0x80000000, 0x00000080, 0], dtype=np.uint32) + a.dtype = np.float32 + assert_equal(a.nonzero()[0], [1]) + a = a.byteswap().newbyteorder() + assert_equal(a.nonzero()[0], [1]) # [0] if nonzero() ignores swap + + def test_find_common_type_boolean(self): + # Ticket #1695 + assert_(np.find_common_type([], ['?', '?']) == '?') + + def test_empty_mul(self): + a = np.array([1.]) + a[1:1] *= 2 + assert_equal(a, [1.]) + + def test_array_side_effect(self): + # The second use of itemsize was throwing an exception because in + # ctors.c, discover_itemsize was calling PyObject_Length without + # checking the return code. This failed to get the length of the + # number 2, and the exception hung around until something checked + # PyErr_Occurred() and returned an error. + assert_equal(np.dtype('S10').itemsize, 10) + np.array([['abc', 2], ['long ', '0123456789']], dtype=np.string_) + assert_equal(np.dtype('S10').itemsize, 10) + + def test_any_float(self): + # all and any for floats + a = np.array([0.1, 0.9]) + assert_(np.any(a)) + assert_(np.all(a)) + + def test_large_float_sum(self): + a = np.arange(10000, dtype='f') + assert_equal(a.sum(dtype='d'), a.astype('d').sum()) + + def test_ufunc_casting_out(self): + a = np.array(1.0, dtype=np.float32) + b = np.array(1.0, dtype=np.float64) + c = np.array(1.0, dtype=np.float32) + np.add(a, b, out=c) + assert_equal(c, 2.0) + + def test_array_scalar_contiguous(self): + # Array scalars are both C and Fortran contiguous + assert_(np.array(1.0).flags.c_contiguous) + assert_(np.array(1.0).flags.f_contiguous) + assert_(np.array(np.float32(1.0)).flags.c_contiguous) + assert_(np.array(np.float32(1.0)).flags.f_contiguous) + + def test_squeeze_contiguous(self): + # Similar to GitHub issue #387 + a = np.zeros((1, 2)).squeeze() + b = np.zeros((2, 2, 2), order='F')[:, :, ::2].squeeze() + assert_(a.flags.c_contiguous) + assert_(a.flags.f_contiguous) + assert_(b.flags.f_contiguous) + + def test_reduce_contiguous(self): + # GitHub issue #387 + a = np.add.reduce(np.zeros((2, 1, 2)), (0, 1)) + b = np.add.reduce(np.zeros((2, 1, 2)), 1) + assert_(a.flags.c_contiguous) + assert_(a.flags.f_contiguous) + assert_(b.flags.c_contiguous) + + def test_object_array_self_reference(self): + # Object arrays with references to themselves can cause problems + a = np.array(0, dtype=object) + a[()] = a + assert_raises(RecursionError, int, a) + assert_raises(RecursionError, long, a) + assert_raises(RecursionError, float, a) + if sys.version_info.major == 2: + # in python 3, this falls back on operator.index, which fails on + # on dtype=object + assert_raises(RecursionError, oct, a) + assert_raises(RecursionError, hex, a) + a[()] = None + + def test_object_array_circular_reference(self): + # Test the same for a circular reference. + a = np.array(0, dtype=object) + b = np.array(0, dtype=object) + a[()] = b + b[()] = a + assert_raises(RecursionError, int, a) + # NumPy has no tp_traverse currently, so circular references + # cannot be detected. So resolve it: + a[()] = None + + # This was causing a to become like the above + a = np.array(0, dtype=object) + a[...] += 1 + assert_equal(a, 1) + + def test_object_array_nested(self): + # but is fine with a reference to a different array + a = np.array(0, dtype=object) + b = np.array(0, dtype=object) + a[()] = b + assert_equal(int(a), int(0)) + assert_equal(long(a), long(0)) + assert_equal(float(a), float(0)) + if sys.version_info.major == 2: + # in python 3, this falls back on operator.index, which fails on + # on dtype=object + assert_equal(oct(a), oct(0)) + assert_equal(hex(a), hex(0)) + + + def test_object_array_self_copy(self): + # An object array being copied into itself DECREF'ed before INCREF'ing + # causing segmentation faults (gh-3787) + a = np.array(object(), dtype=object) + np.copyto(a, a) + if HAS_REFCOUNT: + assert_(sys.getrefcount(a[()]) == 2) + a[()].__class__ # will segfault if object was deleted + + def test_zerosize_accumulate(self): + "Ticket #1733" + x = np.array([[42, 0]], dtype=np.uint32) + assert_equal(np.add.accumulate(x[:-1, 0]), []) + + def test_objectarray_setfield(self): + # Setfield should not overwrite Object fields with non-Object data + x = np.array([1, 2, 3], dtype=object) + assert_raises(TypeError, x.setfield, 4, np.int32, 0) + + def test_setting_rank0_string(self): + "Ticket #1736" + s1 = b"hello1" + s2 = b"hello2" + a = np.zeros((), dtype="S10") + a[()] = s1 + assert_equal(a, np.array(s1)) + a[()] = np.array(s2) + assert_equal(a, np.array(s2)) + + a = np.zeros((), dtype='f4') + a[()] = 3 + assert_equal(a, np.array(3)) + a[()] = np.array(4) + assert_equal(a, np.array(4)) + + def test_string_astype(self): + "Ticket #1748" + s1 = b'black' + s2 = b'white' + s3 = b'other' + a = np.array([[s1], [s2], [s3]]) + assert_equal(a.dtype, np.dtype('S5')) + b = a.astype(np.dtype('S0')) + assert_equal(b.dtype, np.dtype('S5')) + + def test_ticket_1756(self): + # Ticket #1756 + s = b'0123456789abcdef' + a = np.array([s]*5) + for i in range(1, 17): + a1 = np.array(a, "|S%d" % i) + a2 = np.array([s[:i]]*5) + assert_equal(a1, a2) + + def test_fields_strides(self): + "gh-2355" + r = np.frombuffer(b'abcdefghijklmnop'*4*3, dtype='i4,(2,3)u2') + assert_equal(r[0:3:2]['f1'], r['f1'][0:3:2]) + assert_equal(r[0:3:2]['f1'][0], r[0:3:2][0]['f1']) + assert_equal(r[0:3:2]['f1'][0][()], r[0:3:2][0]['f1'][()]) + assert_equal(r[0:3:2]['f1'][0].strides, r[0:3:2][0]['f1'].strides) + + def test_alignment_update(self): + # Check that alignment flag is updated on stride setting + a = np.arange(10) + assert_(a.flags.aligned) + a.strides = 3 + assert_(not a.flags.aligned) + + def test_ticket_1770(self): + "Should not segfault on python 3k" + import numpy as np + try: + a = np.zeros((1,), dtype=[('f1', 'f')]) + a['f1'] = 1 + a['f2'] = 1 + except ValueError: + pass + except Exception: + raise AssertionError + + def test_ticket_1608(self): + "x.flat shouldn't modify data" + x = np.array([[1, 2], [3, 4]]).T + np.array(x.flat) + assert_equal(x, [[1, 3], [2, 4]]) + + def test_pickle_string_overwrite(self): + import re + + data = np.array([1], dtype='b') + blob = pickle.dumps(data, protocol=1) + data = pickle.loads(blob) + + # Check that loads does not clobber interned strings + s = re.sub("a(.)", "\x01\\1", "a_") + assert_equal(s[0], "\x01") + data[0] = 0xbb + s = re.sub("a(.)", "\x01\\1", "a_") + assert_equal(s[0], "\x01") + + def test_pickle_bytes_overwrite(self): + if sys.version_info[0] >= 3: + data = np.array([1], dtype='b') + data = pickle.loads(pickle.dumps(data)) + data[0] = 0xdd + bytestring = "\x01 ".encode('ascii') + assert_equal(bytestring[0:1], '\x01'.encode('ascii')) + + def test_pickle_py2_array_latin1_hack(self): + # Check that unpickling hacks in Py3 that support + # encoding='latin1' work correctly. + + # Python2 output for pickle.dumps(numpy.array([129], dtype='b')) + data = (b"cnumpy.core.multiarray\n_reconstruct\np0\n(cnumpy\nndarray\np1\n(I0\n" + b"tp2\nS'b'\np3\ntp4\nRp5\n(I1\n(I1\ntp6\ncnumpy\ndtype\np7\n(S'i1'\np8\n" + b"I0\nI1\ntp9\nRp10\n(I3\nS'|'\np11\nNNNI-1\nI-1\nI0\ntp12\nbI00\nS'\\x81'\n" + b"p13\ntp14\nb.") + if sys.version_info[0] >= 3: + # This should work: + result = pickle.loads(data, encoding='latin1') + assert_array_equal(result, np.array([129], dtype='b')) + # Should not segfault: + assert_raises(Exception, pickle.loads, data, encoding='koi8-r') + + def test_pickle_py2_scalar_latin1_hack(self): + # Check that scalar unpickling hack in Py3 that supports + # encoding='latin1' work correctly. + + # Python2 output for pickle.dumps(...) + datas = [ + # (original, python2_pickle, koi8r_validity) + (np.unicode_('\u6bd2'), + (b"cnumpy.core.multiarray\nscalar\np0\n(cnumpy\ndtype\np1\n" + b"(S'U1'\np2\nI0\nI1\ntp3\nRp4\n(I3\nS'<'\np5\nNNNI4\nI4\nI0\n" + b"tp6\nbS'\\xd2k\\x00\\x00'\np7\ntp8\nRp9\n."), + 'invalid'), + + (np.float64(9e123), + (b"cnumpy.core.multiarray\nscalar\np0\n(cnumpy\ndtype\np1\n(S'f8'\n" + b"p2\nI0\nI1\ntp3\nRp4\n(I3\nS'<'\np5\nNNNI-1\nI-1\nI0\ntp6\n" + b"bS'O\\x81\\xb7Z\\xaa:\\xabY'\np7\ntp8\nRp9\n."), + 'invalid'), + + (np.bytes_(b'\x9c'), # different 8-bit code point in KOI8-R vs latin1 + (b"cnumpy.core.multiarray\nscalar\np0\n(cnumpy\ndtype\np1\n(S'S1'\np2\n" + b"I0\nI1\ntp3\nRp4\n(I3\nS'|'\np5\nNNNI1\nI1\nI0\ntp6\nbS'\\x9c'\np7\n" + b"tp8\nRp9\n."), + 'different'), + ] + if sys.version_info[0] >= 3: + for original, data, koi8r_validity in datas: + result = pickle.loads(data, encoding='latin1') + assert_equal(result, original) + + # Decoding under non-latin1 encoding (e.g.) KOI8-R can + # produce bad results, but should not segfault. + if koi8r_validity == 'different': + # Unicode code points happen to lie within latin1, + # but are different in koi8-r, resulting to silent + # bogus results + result = pickle.loads(data, encoding='koi8-r') + assert_(result != original) + elif koi8r_validity == 'invalid': + # Unicode code points outside latin1, so results + # to an encoding exception + assert_raises(ValueError, pickle.loads, data, encoding='koi8-r') + else: + raise ValueError(koi8r_validity) + + def test_structured_type_to_object(self): + a_rec = np.array([(0, 1), (3, 2)], dtype='i4,i8') + a_obj = np.empty((2,), dtype=object) + a_obj[0] = (0, 1) + a_obj[1] = (3, 2) + # astype records -> object + assert_equal(a_rec.astype(object), a_obj) + # '=' records -> object + b = np.empty_like(a_obj) + b[...] = a_rec + assert_equal(b, a_obj) + # '=' object -> records + b = np.empty_like(a_rec) + b[...] = a_obj + assert_equal(b, a_rec) + + def test_assign_obj_listoflists(self): + # Ticket # 1870 + # The inner list should get assigned to the object elements + a = np.zeros(4, dtype=object) + b = a.copy() + a[0] = [1] + a[1] = [2] + a[2] = [3] + a[3] = [4] + b[...] = [[1], [2], [3], [4]] + assert_equal(a, b) + # The first dimension should get broadcast + a = np.zeros((2, 2), dtype=object) + a[...] = [[1, 2]] + assert_equal(a, [[1, 2], [1, 2]]) + + def test_memoryleak(self): + # Ticket #1917 - ensure that array data doesn't leak + for i in range(1000): + # 100MB times 1000 would give 100GB of memory usage if it leaks + a = np.empty((100000000,), dtype='i1') + del a + + @dec.skipif(not HAS_REFCOUNT, "python has no sys.getrefcount") + def test_ufunc_reduce_memoryleak(self): + a = np.arange(6) + acnt = sys.getrefcount(a) + np.add.reduce(a) + assert_equal(sys.getrefcount(a), acnt) + + def test_search_sorted_invalid_arguments(self): + # Ticket #2021, should not segfault. + x = np.arange(0, 4, dtype='datetime64[D]') + assert_raises(TypeError, x.searchsorted, 1) + + def test_string_truncation(self): + # Ticket #1990 - Data can be truncated in creation of an array from a + # mixed sequence of numeric values and strings + for val in [True, 1234, 123.4, complex(1, 234)]: + for tostr in [asunicode, asbytes]: + b = np.array([val, tostr('xx')]) + assert_equal(tostr(b[0]), tostr(val)) + b = np.array([tostr('xx'), val]) + assert_equal(tostr(b[1]), tostr(val)) + + # test also with longer strings + b = np.array([val, tostr('xxxxxxxxxx')]) + assert_equal(tostr(b[0]), tostr(val)) + b = np.array([tostr('xxxxxxxxxx'), val]) + assert_equal(tostr(b[1]), tostr(val)) + + def test_string_truncation_ucs2(self): + # Ticket #2081. Python compiled with two byte unicode + # can lead to truncation if itemsize is not properly + # adjusted for NumPy's four byte unicode. + if sys.version_info[0] >= 3: + a = np.array(['abcd']) + else: + a = np.array([u'abcd']) + assert_equal(a.dtype.itemsize, 16) + + def test_unique_stable(self): + # Ticket #2063 must always choose stable sort for argsort to + # get consistent results + v = np.array(([0]*5 + [1]*6 + [2]*6)*4) + res = np.unique(v, return_index=True) + tgt = (np.array([0, 1, 2]), np.array([ 0, 5, 11])) + assert_equal(res, tgt) + + def test_unicode_alloc_dealloc_match(self): + # Ticket #1578, the mismatch only showed up when running + # python-debug for python versions >= 2.7, and then as + # a core dump and error message. + a = np.array(['abc'], dtype=np.unicode)[0] + del a + + def test_refcount_error_in_clip(self): + # Ticket #1588 + a = np.zeros((2,), dtype='>i2').clip(min=0) + x = a + a + # This used to segfault: + y = str(x) + # Check the final string: + assert_(y == "[0 0]") + + def test_searchsorted_wrong_dtype(self): + # Ticket #2189, it used to segfault, so we check that it raises the + # proper exception. + a = np.array([('a', 1)], dtype='S1, int') + assert_raises(TypeError, np.searchsorted, a, 1.2) + # Ticket #2066, similar problem: + dtype = np.format_parser(['i4', 'i4'], [], []) + a = np.recarray((2, ), dtype) + assert_raises(TypeError, np.searchsorted, a, 1) + + def test_complex64_alignment(self): + # Issue gh-2668 (trac 2076), segfault on sparc due to misalignment + dtt = np.complex64 + arr = np.arange(10, dtype=dtt) + # 2D array + arr2 = np.reshape(arr, (2, 5)) + # Fortran write followed by (C or F) read caused bus error + data_str = arr2.tobytes('F') + data_back = np.ndarray(arr2.shape, + arr2.dtype, + buffer=data_str, + order='F') + assert_array_equal(arr2, data_back) + + def test_structured_count_nonzero(self): + arr = np.array([0, 1]).astype('i4, (2)i4')[:1] + count = np.count_nonzero(arr) + assert_equal(count, 0) + + def test_copymodule_preserves_f_contiguity(self): + a = np.empty((2, 2), order='F') + b = copy.copy(a) + c = copy.deepcopy(a) + assert_(b.flags.fortran) + assert_(b.flags.f_contiguous) + assert_(c.flags.fortran) + assert_(c.flags.f_contiguous) + + def test_fortran_order_buffer(self): + import numpy as np + a = np.array([['Hello', 'Foob']], dtype='U5', order='F') + arr = np.ndarray(shape=[1, 2, 5], dtype='U1', buffer=a) + arr2 = np.array([[[u'H', u'e', u'l', u'l', u'o'], + [u'F', u'o', u'o', u'b', u'']]]) + assert_array_equal(arr, arr2) + + def test_assign_from_sequence_error(self): + # Ticket #4024. + arr = np.array([1, 2, 3]) + assert_raises(ValueError, arr.__setitem__, slice(None), [9, 9]) + arr.__setitem__(slice(None), [9]) + assert_equal(arr, [9, 9, 9]) + + def test_format_on_flex_array_element(self): + # Ticket #4369. + dt = np.dtype([('date', '= 3: + assert_raises(TypeError, f, lhs, rhs) + elif not sys.py3kwarning: + # With -3 switch in python 2, DeprecationWarning is raised + # which we are not interested in + f(lhs, rhs) + assert_(not op.eq(lhs, rhs)) + assert_(op.ne(lhs, rhs)) + + def test_richcompare_scalar_and_subclass(self): + # gh-4709 + class Foo(np.ndarray): + def __eq__(self, other): + return "OK" + + x = np.array([1, 2, 3]).view(Foo) + assert_equal(10 == x, "OK") + assert_equal(np.int32(10) == x, "OK") + assert_equal(np.array([10]) == x, "OK") + + def test_pickle_empty_string(self): + # gh-3926 + + import pickle + test_string = np.string_('') + assert_equal(pickle.loads(pickle.dumps(test_string)), test_string) + + def test_frompyfunc_many_args(self): + # gh-5672 + + def passer(*args): + pass + + assert_raises(ValueError, np.frompyfunc, passer, 32, 1) + + def test_repeat_broadcasting(self): + # gh-5743 + a = np.arange(60).reshape(3, 4, 5) + for axis in chain(range(-a.ndim, a.ndim), [None]): + assert_equal(a.repeat(2, axis=axis), a.repeat([2], axis=axis)) + + def test_frompyfunc_nout_0(self): + # gh-2014 + + def f(x): + x[0], x[-1] = x[-1], x[0] + + uf = np.frompyfunc(f, 1, 0) + a = np.array([[1, 2, 3], [4, 5], [6, 7, 8, 9]]) + assert_equal(uf(a), ()) + assert_array_equal(a, [[3, 2, 1], [5, 4], [9, 7, 8, 6]]) + + @dec.skipif(not HAS_REFCOUNT, "python has no sys.getrefcount") + def test_leak_in_structured_dtype_comparison(self): + # gh-6250 + recordtype = np.dtype([('a', np.float64), + ('b', np.int32), + ('d', (str, 5))]) + + # Simple case + a = np.zeros(2, dtype=recordtype) + for i in range(100): + a == a + assert_(sys.getrefcount(a) < 10) + + # The case in the bug report. + before = sys.getrefcount(a) + u, v = a[0], a[1] + u == v + del u, v + gc.collect() + after = sys.getrefcount(a) + assert_equal(before, after) + + def test_empty_percentile(self): + # gh-6530 / gh-6553 + assert_array_equal(np.percentile(np.arange(10), []), np.array([])) + + def test_void_compare_segfault(self): + # gh-6922. The following should not segfault + a = np.ones(3, dtype=[('object', 'O'), ('int', '= 3) or + (sys.platform == "win32" and + platform.architecture()[0] == "64bit"), + "numpy.intp('0xff', 16) not supported on Py3, " + "as it does not inherit from Python int") + def test_intp(self): + # Ticket #99 + i_width = np.int_(0).nbytes*2 - 1 + np.intp('0x' + 'f'*i_width, 16) + assert_raises(OverflowError, np.intp, '0x' + 'f'*(i_width+1), 16) + assert_raises(ValueError, np.intp, '0x1', 32) + assert_equal(255, np.intp('0xFF', 16)) + + +class TestFromInt(object): + def test_intp(self): + # Ticket #99 + assert_equal(1024, np.intp(1024)) + + def test_uint64_from_negative(self): + assert_equal(np.uint64(-2), np.uint64(18446744073709551614)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_scalarinherit.py b/numpy/core/tests/test_scalarinherit.py new file mode 100644 index 0000000..c5cd266 --- /dev/null +++ b/numpy/core/tests/test_scalarinherit.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +""" Test printing of scalar types. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import run_module_suite, assert_ + + +class A(object): + pass +class B(A, np.float64): + pass + +class C(B): + pass +class D(C, B): + pass + +class B0(np.float64, A): + pass +class C0(B0): + pass + +class TestInherit(object): + def test_init(self): + x = B(1.0) + assert_(str(x) == '1.0') + y = C(2.0) + assert_(str(y) == '2.0') + z = D(3.0) + assert_(str(z) == '3.0') + + def test_init2(self): + x = B0(1.0) + assert_(str(x) == '1.0') + y = C0(2.0) + assert_(str(y) == '2.0') + + +class TestCharacter(object): + def test_char_radd(self): + # GH issue 9620, reached gentype_add and raise TypeError + np_s = np.string_('abc') + np_u = np.unicode_('abc') + s = b'def' + u = u'def' + assert_(np_s.__radd__(np_s) is NotImplemented) + assert_(np_s.__radd__(np_u) is NotImplemented) + assert_(np_s.__radd__(s) is NotImplemented) + assert_(np_s.__radd__(u) is NotImplemented) + assert_(np_u.__radd__(np_s) is NotImplemented) + assert_(np_u.__radd__(np_u) is NotImplemented) + assert_(np_u.__radd__(s) is NotImplemented) + assert_(np_u.__radd__(u) is NotImplemented) + assert_(s + np_s == b'defabc') + assert_(u + np_u == u'defabc') + + + class Mystr(str, np.generic): + # would segfault + pass + + ret = s + Mystr('abc') + assert_(type(ret) is type(s)) + + def test_char_repeat(self): + np_s = np.string_('abc') + np_u = np.unicode_('abc') + np_i = np.int(5) + res_np = np_s * np_i + res_s = b'abc' * 5 + assert_(res_np == res_s) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py new file mode 100644 index 0000000..0e1f011 --- /dev/null +++ b/numpy/core/tests/test_scalarmath.py @@ -0,0 +1,656 @@ +from __future__ import division, absolute_import, print_function + +import sys +import warnings +import itertools +import operator +import platform + +import numpy as np +from numpy.testing import ( + run_module_suite, + assert_, assert_equal, assert_raises, + assert_almost_equal, assert_allclose, assert_array_equal, + IS_PYPY, suppress_warnings, dec, _gen_alignment_data, +) + +types = [np.bool_, np.byte, np.ubyte, np.short, np.ushort, np.intc, np.uintc, + np.int_, np.uint, np.longlong, np.ulonglong, + np.single, np.double, np.longdouble, np.csingle, + np.cdouble, np.clongdouble] + +floating_types = np.floating.__subclasses__() +complex_floating_types = np.complexfloating.__subclasses__() + + +# This compares scalarmath against ufuncs. + +class TestTypes(object): + def test_types(self): + for atype in types: + a = atype(1) + assert_(a == 1, "error with %r: got %r" % (atype, a)) + + def test_type_add(self): + # list of types + for k, atype in enumerate(types): + a_scalar = atype(3) + a_array = np.array([3], dtype=atype) + for l, btype in enumerate(types): + b_scalar = btype(1) + b_array = np.array([1], dtype=btype) + c_scalar = a_scalar + b_scalar + c_array = a_array + b_array + # It was comparing the type numbers, but the new ufunc + # function-finding mechanism finds the lowest function + # to which both inputs can be cast - which produces 'l' + # when you do 'q' + 'b'. The old function finding mechanism + # skipped ahead based on the first argument, but that + # does not produce properly symmetric results... + assert_equal(c_scalar.dtype, c_array.dtype, + "error with types (%d/'%c' + %d/'%c')" % + (k, np.dtype(atype).char, l, np.dtype(btype).char)) + + def test_type_create(self): + for k, atype in enumerate(types): + a = np.array([1, 2, 3], atype) + b = atype([1, 2, 3]) + assert_equal(a, b) + + def test_leak(self): + # test leak of scalar objects + # a leak would show up in valgrind as still-reachable of ~2.6MB + for i in range(200000): + np.add(1, 1) + + +class TestBaseMath(object): + def test_blocked(self): + # test alignments offsets for simd instructions + # alignments for vz + 2 * (vs - 1) + 1 + for dt, sz in [(np.float32, 11), (np.float64, 7), (np.int32, 11)]: + for out, inp1, inp2, msg in _gen_alignment_data(dtype=dt, + type='binary', + max_size=sz): + exp1 = np.ones_like(inp1) + inp1[...] = np.ones_like(inp1) + inp2[...] = np.zeros_like(inp2) + assert_almost_equal(np.add(inp1, inp2), exp1, err_msg=msg) + assert_almost_equal(np.add(inp1, 2), exp1 + 2, err_msg=msg) + assert_almost_equal(np.add(1, inp2), exp1, err_msg=msg) + + np.add(inp1, inp2, out=out) + assert_almost_equal(out, exp1, err_msg=msg) + + inp2[...] += np.arange(inp2.size, dtype=dt) + 1 + assert_almost_equal(np.square(inp2), + np.multiply(inp2, inp2), err_msg=msg) + # skip true divide for ints + if dt != np.int32 or (sys.version_info.major < 3 and not sys.py3kwarning): + assert_almost_equal(np.reciprocal(inp2), + np.divide(1, inp2), err_msg=msg) + + inp1[...] = np.ones_like(inp1) + np.add(inp1, 2, out=out) + assert_almost_equal(out, exp1 + 2, err_msg=msg) + inp2[...] = np.ones_like(inp2) + np.add(2, inp2, out=out) + assert_almost_equal(out, exp1 + 2, err_msg=msg) + + def test_lower_align(self): + # check data that is not aligned to element size + # i.e doubles are aligned to 4 bytes on i386 + d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64) + o = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64) + assert_almost_equal(d + d, d * 2) + np.add(d, d, out=o) + np.add(np.ones_like(d), d, out=o) + np.add(d, np.ones_like(d), out=o) + np.add(np.ones_like(d), d) + np.add(d, np.ones_like(d)) + + +class TestPower(object): + def test_small_types(self): + for t in [np.int8, np.int16, np.float16]: + a = t(3) + b = a ** 4 + assert_(b == 81, "error with %r: got %r" % (t, b)) + + def test_large_types(self): + for t in [np.int32, np.int64, np.float32, np.float64, np.longdouble]: + a = t(51) + b = a ** 4 + msg = "error with %r: got %r" % (t, b) + if np.issubdtype(t, np.integer): + assert_(b == 6765201, msg) + else: + assert_almost_equal(b, 6765201, err_msg=msg) + + def test_integers_to_negative_integer_power(self): + # Note that the combination of uint64 with a signed integer + # has common type np.float64. The other combinations should all + # raise a ValueError for integer ** negative integer. + exp = [np.array(-1, dt)[()] for dt in 'bhilq'] + + # 1 ** -1 possible special case + base = [np.array(1, dt)[()] for dt in 'bhilqBHILQ'] + for i1, i2 in itertools.product(base, exp): + if i1.dtype.name != 'uint64': + assert_raises(ValueError, operator.pow, i1, i2) + else: + res = operator.pow(i1, i2) + assert_(res.dtype.type is np.float64) + assert_almost_equal(res, 1.) + + # -1 ** -1 possible special case + base = [np.array(-1, dt)[()] for dt in 'bhilq'] + for i1, i2 in itertools.product(base, exp): + if i1.dtype.name != 'uint64': + assert_raises(ValueError, operator.pow, i1, i2) + else: + res = operator.pow(i1, i2) + assert_(res.dtype.type is np.float64) + assert_almost_equal(res, -1.) + + # 2 ** -1 perhaps generic + base = [np.array(2, dt)[()] for dt in 'bhilqBHILQ'] + for i1, i2 in itertools.product(base, exp): + if i1.dtype.name != 'uint64': + assert_raises(ValueError, operator.pow, i1, i2) + else: + res = operator.pow(i1, i2) + assert_(res.dtype.type is np.float64) + assert_almost_equal(res, .5) + + def test_mixed_types(self): + typelist = [np.int8, np.int16, np.float16, + np.float32, np.float64, np.int8, + np.int16, np.int32, np.int64] + for t1 in typelist: + for t2 in typelist: + a = t1(3) + b = t2(2) + result = a**b + msg = ("error with %r and %r:" + "got %r, expected %r") % (t1, t2, result, 9) + if np.issubdtype(np.dtype(result), np.integer): + assert_(result == 9, msg) + else: + assert_almost_equal(result, 9, err_msg=msg) + + def test_modular_power(self): + # modular power is not implemented, so ensure it errors + a = 5 + b = 4 + c = 10 + expected = pow(a, b, c) + for t in (np.int32, np.float32, np.complex64): + # note that 3-operand power only dispatches on the first argument + assert_raises(TypeError, operator.pow, t(a), b, c) + assert_raises(TypeError, operator.pow, np.array(t(a)), b, c) + + +def floordiv_and_mod(x, y): + return (x // y, x % y) + + +def _signs(dt): + if dt in np.typecodes['UnsignedInteger']: + return (+1,) + else: + return (+1, -1) + + +class TestModulus(object): + + def test_modulus_basic(self): + dt = np.typecodes['AllInteger'] + np.typecodes['Float'] + for op in [floordiv_and_mod, divmod]: + for dt1, dt2 in itertools.product(dt, dt): + for sg1, sg2 in itertools.product(_signs(dt1), _signs(dt2)): + fmt = 'op: %s, dt1: %s, dt2: %s, sg1: %s, sg2: %s' + msg = fmt % (op.__name__, dt1, dt2, sg1, sg2) + a = np.array(sg1*71, dtype=dt1)[()] + b = np.array(sg2*19, dtype=dt2)[()] + div, rem = op(a, b) + assert_equal(div*b + rem, a, err_msg=msg) + if sg2 == -1: + assert_(b < rem <= 0, msg) + else: + assert_(b > rem >= 0, msg) + + def test_float_modulus_exact(self): + # test that float results are exact for small integers. This also + # holds for the same integers scaled by powers of two. + nlst = list(range(-127, 0)) + plst = list(range(1, 128)) + dividend = nlst + [0] + plst + divisor = nlst + plst + arg = list(itertools.product(dividend, divisor)) + tgt = list(divmod(*t) for t in arg) + + a, b = np.array(arg, dtype=int).T + # convert exact integer results from Python to float so that + # signed zero can be used, it is checked. + tgtdiv, tgtrem = np.array(tgt, dtype=float).T + tgtdiv = np.where((tgtdiv == 0.0) & ((b < 0) ^ (a < 0)), -0.0, tgtdiv) + tgtrem = np.where((tgtrem == 0.0) & (b < 0), -0.0, tgtrem) + + for op in [floordiv_and_mod, divmod]: + for dt in np.typecodes['Float']: + msg = 'op: %s, dtype: %s' % (op.__name__, dt) + fa = a.astype(dt) + fb = b.astype(dt) + # use list comprehension so a_ and b_ are scalars + div, rem = zip(*[op(a_, b_) for a_, b_ in zip(fa, fb)]) + assert_equal(div, tgtdiv, err_msg=msg) + assert_equal(rem, tgtrem, err_msg=msg) + + def test_float_modulus_roundoff(self): + # gh-6127 + dt = np.typecodes['Float'] + for op in [floordiv_and_mod, divmod]: + for dt1, dt2 in itertools.product(dt, dt): + for sg1, sg2 in itertools.product((+1, -1), (+1, -1)): + fmt = 'op: %s, dt1: %s, dt2: %s, sg1: %s, sg2: %s' + msg = fmt % (op.__name__, dt1, dt2, sg1, sg2) + a = np.array(sg1*78*6e-8, dtype=dt1)[()] + b = np.array(sg2*6e-8, dtype=dt2)[()] + div, rem = op(a, b) + # Equal assertion should hold when fmod is used + assert_equal(div*b + rem, a, err_msg=msg) + if sg2 == -1: + assert_(b < rem <= 0, msg) + else: + assert_(b > rem >= 0, msg) + + def test_float_modulus_corner_cases(self): + # Check remainder magnitude. + for dt in np.typecodes['Float']: + b = np.array(1.0, dtype=dt) + a = np.nextafter(np.array(0.0, dtype=dt), -b) + rem = operator.mod(a, b) + assert_(rem <= b, 'dt: %s' % dt) + rem = operator.mod(-a, -b) + assert_(rem >= -b, 'dt: %s' % dt) + + # Check nans, inf + with suppress_warnings() as sup: + sup.filter(RuntimeWarning, "invalid value encountered in remainder") + for dt in np.typecodes['Float']: + fone = np.array(1.0, dtype=dt) + fzer = np.array(0.0, dtype=dt) + finf = np.array(np.inf, dtype=dt) + fnan = np.array(np.nan, dtype=dt) + rem = operator.mod(fone, fzer) + assert_(np.isnan(rem), 'dt: %s' % dt) + # MSVC 2008 returns NaN here, so disable the check. + #rem = operator.mod(fone, finf) + #assert_(rem == fone, 'dt: %s' % dt) + rem = operator.mod(fone, fnan) + assert_(np.isnan(rem), 'dt: %s' % dt) + rem = operator.mod(finf, fone) + assert_(np.isnan(rem), 'dt: %s' % dt) + + +class TestComplexDivision(object): + def test_zero_division(self): + with np.errstate(all="ignore"): + for t in [np.complex64, np.complex128]: + a = t(0.0) + b = t(1.0) + assert_(np.isinf(b/a)) + b = t(complex(np.inf, np.inf)) + assert_(np.isinf(b/a)) + b = t(complex(np.inf, np.nan)) + assert_(np.isinf(b/a)) + b = t(complex(np.nan, np.inf)) + assert_(np.isinf(b/a)) + b = t(complex(np.nan, np.nan)) + assert_(np.isnan(b/a)) + b = t(0.) + assert_(np.isnan(b/a)) + + def test_signed_zeros(self): + with np.errstate(all="ignore"): + for t in [np.complex64, np.complex128]: + # tupled (numerator, denominator, expected) + # for testing as expected == numerator/denominator + data = ( + (( 0.0,-1.0), ( 0.0, 1.0), (-1.0,-0.0)), + (( 0.0,-1.0), ( 0.0,-1.0), ( 1.0,-0.0)), + (( 0.0,-1.0), (-0.0,-1.0), ( 1.0, 0.0)), + (( 0.0,-1.0), (-0.0, 1.0), (-1.0, 0.0)), + (( 0.0, 1.0), ( 0.0,-1.0), (-1.0, 0.0)), + (( 0.0,-1.0), ( 0.0,-1.0), ( 1.0,-0.0)), + ((-0.0,-1.0), ( 0.0,-1.0), ( 1.0,-0.0)), + ((-0.0, 1.0), ( 0.0,-1.0), (-1.0,-0.0)) + ) + for cases in data: + n = cases[0] + d = cases[1] + ex = cases[2] + result = t(complex(n[0], n[1])) / t(complex(d[0], d[1])) + # check real and imag parts separately to avoid comparison + # in array context, which does not account for signed zeros + assert_equal(result.real, ex[0]) + assert_equal(result.imag, ex[1]) + + def test_branches(self): + with np.errstate(all="ignore"): + for t in [np.complex64, np.complex128]: + # tupled (numerator, denominator, expected) + # for testing as expected == numerator/denominator + data = list() + + # trigger branch: real(fabs(denom)) > imag(fabs(denom)) + # followed by else condition as neither are == 0 + data.append((( 2.0, 1.0), ( 2.0, 1.0), (1.0, 0.0))) + + # trigger branch: real(fabs(denom)) > imag(fabs(denom)) + # followed by if condition as both are == 0 + # is performed in test_zero_division(), so this is skipped + + # trigger else if branch: real(fabs(denom)) < imag(fabs(denom)) + data.append((( 1.0, 2.0), ( 1.0, 2.0), (1.0, 0.0))) + + for cases in data: + n = cases[0] + d = cases[1] + ex = cases[2] + result = t(complex(n[0], n[1])) / t(complex(d[0], d[1])) + # check real and imag parts separately to avoid comparison + # in array context, which does not account for signed zeros + assert_equal(result.real, ex[0]) + assert_equal(result.imag, ex[1]) + + +class TestConversion(object): + def test_int_from_long(self): + l = [1e6, 1e12, 1e18, -1e6, -1e12, -1e18] + li = [10**6, 10**12, 10**18, -10**6, -10**12, -10**18] + for T in [None, np.float64, np.int64]: + a = np.array(l, dtype=T) + assert_equal([int(_m) for _m in a], li) + + a = np.array(l[:3], dtype=np.uint64) + assert_equal([int(_m) for _m in a], li[:3]) + + def test_iinfo_long_values(self): + for code in 'bBhH': + res = np.array(np.iinfo(code).max + 1, dtype=code) + tgt = np.iinfo(code).min + assert_(res == tgt) + + for code in np.typecodes['AllInteger']: + res = np.array(np.iinfo(code).max, dtype=code) + tgt = np.iinfo(code).max + assert_(res == tgt) + + for code in np.typecodes['AllInteger']: + res = np.typeDict[code](np.iinfo(code).max) + tgt = np.iinfo(code).max + assert_(res == tgt) + + def test_int_raise_behaviour(self): + def overflow_error_func(dtype): + np.typeDict[dtype](np.iinfo(dtype).max + 1) + + for code in 'lLqQ': + assert_raises(OverflowError, overflow_error_func, code) + + def test_int_from_infinite_longdouble(self): + # gh-627 + x = np.longdouble(np.inf) + assert_raises(OverflowError, int, x) + with suppress_warnings() as sup: + sup.record(np.ComplexWarning) + x = np.clongdouble(np.inf) + assert_raises(OverflowError, int, x) + assert_equal(len(sup.log), 1) + + @dec.knownfailureif(not IS_PYPY, + "__int__ is not the same as int in cpython (gh-9972)") + def test_int_from_infinite_longdouble___int__(self): + x = np.longdouble(np.inf) + assert_raises(OverflowError, x.__int__) + with suppress_warnings() as sup: + sup.record(np.ComplexWarning) + x = np.clongdouble(np.inf) + assert_raises(OverflowError, x.__int__) + assert_equal(len(sup.log), 1) + + @dec.knownfailureif(platform.machine().startswith("ppc64")) + @dec.skipif(np.finfo(np.double) == np.finfo(np.longdouble)) + def test_int_from_huge_longdouble(self): + # Produce a longdouble that would overflow a double, + # use exponent that avoids bug in Darwin pow function. + exp = np.finfo(np.double).maxexp - 1 + huge_ld = 2 * 1234 * np.longdouble(2) ** exp + huge_i = 2 * 1234 * 2 ** exp + assert_(huge_ld != np.inf) + assert_equal(int(huge_ld), huge_i) + + def test_int_from_longdouble(self): + x = np.longdouble(1.5) + assert_equal(int(x), 1) + x = np.longdouble(-10.5) + assert_equal(int(x), -10) + + def test_numpy_scalar_relational_operators(self): + # All integer + for dt1 in np.typecodes['AllInteger']: + assert_(1 > np.array(0, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(not 1 < np.array(0, dtype=dt1)[()], "type %s failed" % (dt1,)) + + for dt2 in np.typecodes['AllInteger']: + assert_(np.array(1, dtype=dt1)[()] > np.array(0, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1)[()] < np.array(0, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + + #Unsigned integers + for dt1 in 'BHILQP': + assert_(-1 < np.array(1, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(not -1 > np.array(1, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(-1 != np.array(1, dtype=dt1)[()], "type %s failed" % (dt1,)) + + #unsigned vs signed + for dt2 in 'bhilqp': + assert_(np.array(1, dtype=dt1)[()] > np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1)[()] < np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(np.array(1, dtype=dt1)[()] != np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + + #Signed integers and floats + for dt1 in 'bhlqp' + np.typecodes['Float']: + assert_(1 > np.array(-1, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(not 1 < np.array(-1, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(-1 == np.array(-1, dtype=dt1)[()], "type %s failed" % (dt1,)) + + for dt2 in 'bhlqp' + np.typecodes['Float']: + assert_(np.array(1, dtype=dt1)[()] > np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1)[()] < np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(np.array(-1, dtype=dt1)[()] == np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + + def test_scalar_comparison_to_none(self): + # Scalars should just return False and not give a warnings. + # The comparisons are flagged by pep8, ignore that. + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', FutureWarning) + assert_(not np.float32(1) == None) + assert_(not np.str_('test') == None) + # This is dubious (see below): + assert_(not np.datetime64('NaT') == None) + + assert_(np.float32(1) != None) + assert_(np.str_('test') != None) + # This is dubious (see below): + assert_(np.datetime64('NaT') != None) + assert_(len(w) == 0) + + # For documentation purposes, this is why the datetime is dubious. + # At the time of deprecation this was no behaviour change, but + # it has to be considered when the deprecations are done. + assert_(np.equal(np.datetime64('NaT'), None)) + + +#class TestRepr(object): +# def test_repr(self): +# for t in types: +# val = t(1197346475.0137341) +# val_repr = repr(val) +# val2 = eval(val_repr) +# assert_equal( val, val2 ) + + +class TestRepr(object): + def _test_type_repr(self, t): + finfo = np.finfo(t) + last_fraction_bit_idx = finfo.nexp + finfo.nmant + last_exponent_bit_idx = finfo.nexp + storage_bytes = np.dtype(t).itemsize*8 + # could add some more types to the list below + for which in ['small denorm', 'small norm']: + # Values from http://en.wikipedia.org/wiki/IEEE_754 + constr = np.array([0x00]*storage_bytes, dtype=np.uint8) + if which == 'small denorm': + byte = last_fraction_bit_idx // 8 + bytebit = 7-(last_fraction_bit_idx % 8) + constr[byte] = 1 << bytebit + elif which == 'small norm': + byte = last_exponent_bit_idx // 8 + bytebit = 7-(last_exponent_bit_idx % 8) + constr[byte] = 1 << bytebit + else: + raise ValueError('hmm') + val = constr.view(t)[0] + val_repr = repr(val) + val2 = t(eval(val_repr)) + if not (val2 == 0 and val < 1e-100): + assert_equal(val, val2) + + def test_float_repr(self): + # long double test cannot work, because eval goes through a python + # float + for t in [np.float32, np.float64]: + yield self._test_type_repr, t + + +if not IS_PYPY: + # sys.getsizeof() is not valid on PyPy + class TestSizeOf(object): + + def test_equal_nbytes(self): + for type in types: + x = type(0) + assert_(sys.getsizeof(x) > x.nbytes) + + def test_error(self): + d = np.float32() + assert_raises(TypeError, d.__sizeof__, "a") + + +class TestMultiply(object): + def test_seq_repeat(self): + # Test that basic sequences get repeated when multiplied with + # numpy integers. And errors are raised when multiplied with others. + # Some of this behaviour may be controversial and could be open for + # change. + for seq_type in (list, tuple): + seq = seq_type([1, 2, 3]) + for numpy_type in np.typecodes["AllInteger"]: + i = np.dtype(numpy_type).type(2) + assert_equal(seq * i, seq * int(i)) + assert_equal(i * seq, int(i) * seq) + + for numpy_type in np.typecodes["All"].replace("V", ""): + if numpy_type in np.typecodes["AllInteger"]: + continue + i = np.dtype(numpy_type).type() + assert_raises(TypeError, operator.mul, seq, i) + assert_raises(TypeError, operator.mul, i, seq) + + def test_no_seq_repeat_basic_array_like(self): + # Test that an array-like which does not know how to be multiplied + # does not attempt sequence repeat (raise TypeError). + # See also gh-7428. + class ArrayLike(object): + def __init__(self, arr): + self.arr = arr + def __array__(self): + return self.arr + + # Test for simple ArrayLike above and memoryviews (original report) + for arr_like in (ArrayLike(np.ones(3)), memoryview(np.ones(3))): + assert_array_equal(arr_like * np.float32(3.), np.full(3, 3.)) + assert_array_equal(np.float32(3.) * arr_like, np.full(3, 3.)) + assert_array_equal(arr_like * np.int_(3), np.full(3, 3)) + assert_array_equal(np.int_(3) * arr_like, np.full(3, 3)) + + +class TestNegative(object): + def test_exceptions(self): + a = np.ones((), dtype=np.bool_)[()] + assert_raises(TypeError, operator.neg, a) + + def test_result(self): + types = np.typecodes['AllInteger'] + np.typecodes['AllFloat'] + with suppress_warnings() as sup: + sup.filter(RuntimeWarning) + for dt in types: + a = np.ones((), dtype=dt)[()] + assert_equal(operator.neg(a) + a, 0) + + +class TestSubtract(object): + def test_exceptions(self): + a = np.ones((), dtype=np.bool_)[()] + assert_raises(TypeError, operator.sub, a, a) + + def test_result(self): + types = np.typecodes['AllInteger'] + np.typecodes['AllFloat'] + with suppress_warnings() as sup: + sup.filter(RuntimeWarning) + for dt in types: + a = np.ones((), dtype=dt)[()] + assert_equal(operator.sub(a, a), 0) + + +class TestAbs(object): + def _test_abs_func(self, absfunc): + for tp in floating_types + complex_floating_types: + x = tp(-1.5) + assert_equal(absfunc(x), 1.5) + x = tp(0.0) + res = absfunc(x) + # assert_equal() checks zero signedness + assert_equal(res, 0.0) + x = tp(-0.0) + res = absfunc(x) + assert_equal(res, 0.0) + + x = tp(np.finfo(tp).max) + assert_equal(absfunc(x), x.real) + + x = tp(np.finfo(tp).tiny) + assert_equal(absfunc(x), x.real) + + x = tp(np.finfo(tp).min) + assert_equal(absfunc(x), -x.real) + + def test_builtin_abs(self): + self._test_abs_func(abs) + + def test_numpy_abs(self): + self._test_abs_func(np.abs) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_scalarprint.py b/numpy/core/tests/test_scalarprint.py new file mode 100644 index 0000000..6177461 --- /dev/null +++ b/numpy/core/tests/test_scalarprint.py @@ -0,0 +1,234 @@ +# -*- coding: utf-8 -*- +""" Test printing of scalar types. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import assert_, assert_equal, run_module_suite +import sys, tempfile + + +class TestRealScalars(object): + def test_str(self): + svals = [0.0, -0.0, 1, -1, np.inf, -np.inf, np.nan] + styps = [np.float16, np.float32, np.float64, np.longdouble] + wanted = [ + ['0.0', '0.0', '0.0', '0.0' ], + ['-0.0', '-0.0', '-0.0', '-0.0'], + ['1.0', '1.0', '1.0', '1.0' ], + ['-1.0', '-1.0', '-1.0', '-1.0'], + ['inf', 'inf', 'inf', 'inf' ], + ['-inf', '-inf', '-inf', '-inf'], + ['nan', 'nan', 'nan', 'nan']] + + for wants, val in zip(wanted, svals): + for want, styp in zip(wants, styps): + msg = 'for str({}({}))'.format(np.dtype(styp).name, repr(val)) + assert_equal(str(styp(val)), want, err_msg=msg) + + def test_scalar_cutoffs(self): + # test that both the str and repr of np.float64 behaves + # like python floats in python3. Note that in python2 + # the str has truncated digits, but we do not do this + def check(v): + # we compare str to repr, to avoid python2 truncation behavior + assert_equal(str(np.float64(v)), repr(v)) + assert_equal(repr(np.float64(v)), repr(v)) + + # check we use the same number of significant digits + check(1.12345678901234567890) + check(0.0112345678901234567890) + + # check switch from scientific output to positional and back + check(1e-5) + check(1e-4) + check(1e15) + check(1e16) + + def test_py2_float_print(self): + # gh-10753 + # In python2, the python float type implements an obsolte method + # tp_print, which overrides tp_repr and tp_str when using the "print" + # keyword/method to output to a "real file" (ie, not a StringIO). Make + # sure we don't inherit it. + x = np.double(0.1999999999999) + f = tempfile.TemporaryFile('r+t') # must output to real file, not StringIO + print(x, file=f) + f.seek(0) + output = f.read() + f.close() + assert_equal(output, '0.1999999999999\n') + # (compare to "print 0.1999999999999" printing "0.2" in python2) + + def test_dragon4(self): + # these tests are adapted from Ryan Juckett's dragon4 implementation, + # see dragon4.c for details. + + fpos32 = lambda x, **k: np.format_float_positional(np.float32(x), **k) + fsci32 = lambda x, **k: np.format_float_scientific(np.float32(x), **k) + fpos64 = lambda x, **k: np.format_float_positional(np.float64(x), **k) + fsci64 = lambda x, **k: np.format_float_scientific(np.float64(x), **k) + + preckwd = lambda prec: {'unique': False, 'precision': prec} + + assert_equal(fpos32('1.0'), "1.") + assert_equal(fsci32('1.0'), "1.e+00") + assert_equal(fpos32('10.234'), "10.234") + assert_equal(fpos32('-10.234'), "-10.234") + assert_equal(fsci32('10.234'), "1.0234e+01") + assert_equal(fsci32('-10.234'), "-1.0234e+01") + assert_equal(fpos32('1000.0'), "1000.") + assert_equal(fpos32('1.0', precision=0), "1.") + assert_equal(fsci32('1.0', precision=0), "1.e+00") + assert_equal(fpos32('10.234', precision=0), "10.") + assert_equal(fpos32('-10.234', precision=0), "-10.") + assert_equal(fsci32('10.234', precision=0), "1.e+01") + assert_equal(fsci32('-10.234', precision=0), "-1.e+01") + assert_equal(fpos32('10.234', precision=2), "10.23") + assert_equal(fsci32('-10.234', precision=2), "-1.02e+01") + assert_equal(fsci64('9.9999999999999995e-08', **preckwd(16)), + '9.9999999999999995e-08') + assert_equal(fsci64('9.8813129168249309e-324', **preckwd(16)), + '9.8813129168249309e-324') + assert_equal(fsci64('9.9999999999999694e-311', **preckwd(16)), + '9.9999999999999694e-311') + + + # test rounding + # 3.1415927410 is closest float32 to np.pi + assert_equal(fpos32('3.14159265358979323846', **preckwd(10)), + "3.1415927410") + assert_equal(fsci32('3.14159265358979323846', **preckwd(10)), + "3.1415927410e+00") + assert_equal(fpos64('3.14159265358979323846', **preckwd(10)), + "3.1415926536") + assert_equal(fsci64('3.14159265358979323846', **preckwd(10)), + "3.1415926536e+00") + # 299792448 is closest float32 to 299792458 + assert_equal(fpos32('299792458.0', **preckwd(5)), "299792448.00000") + assert_equal(fsci32('299792458.0', **preckwd(5)), "2.99792e+08") + assert_equal(fpos64('299792458.0', **preckwd(5)), "299792458.00000") + assert_equal(fsci64('299792458.0', **preckwd(5)), "2.99792e+08") + + assert_equal(fpos32('3.14159265358979323846', **preckwd(25)), + "3.1415927410125732421875000") + assert_equal(fpos64('3.14159265358979323846', **preckwd(50)), + "3.14159265358979311599796346854418516159057617187500") + assert_equal(fpos64('3.14159265358979323846'), "3.141592653589793") + + + # smallest numbers + assert_equal(fpos32(0.5**(126 + 23), unique=False, precision=149), + "0.00000000000000000000000000000000000000000000140129846432" + "4817070923729583289916131280261941876515771757068283889791" + "08268586060148663818836212158203125") + assert_equal(fpos64(0.5**(1022 + 52), unique=False, precision=1074), + "0.00000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000049406564584124654417656" + "8792868221372365059802614324764425585682500675507270208751" + "8652998363616359923797965646954457177309266567103559397963" + "9877479601078187812630071319031140452784581716784898210368" + "8718636056998730723050006387409153564984387312473397273169" + "6151400317153853980741262385655911710266585566867681870395" + "6031062493194527159149245532930545654440112748012970999954" + "1931989409080416563324524757147869014726780159355238611550" + "1348035264934720193790268107107491703332226844753335720832" + "4319360923828934583680601060115061698097530783422773183292" + "4790498252473077637592724787465608477820373446969953364701" + "7972677717585125660551199131504891101451037862738167250955" + "8373897335989936648099411642057026370902792427675445652290" + "87538682506419718265533447265625") + + # largest numbers + assert_equal(fpos32(np.finfo(np.float32).max, **preckwd(0)), + "340282346638528859811704183484516925440.") + assert_equal(fpos64(np.finfo(np.float64).max, **preckwd(0)), + "1797693134862315708145274237317043567980705675258449965989" + "1747680315726078002853876058955863276687817154045895351438" + "2464234321326889464182768467546703537516986049910576551282" + "0762454900903893289440758685084551339423045832369032229481" + "6580855933212334827479782620414472316873817718091929988125" + "0404026184124858368.") + # Warning: In unique mode only the integer digits necessary for + # uniqueness are computed, the rest are 0. Should we change this? + assert_equal(fpos32(np.finfo(np.float32).max, precision=0), + "340282350000000000000000000000000000000.") + + # test trailing zeros + assert_equal(fpos32('1.0', unique=False, precision=3), "1.000") + assert_equal(fpos64('1.0', unique=False, precision=3), "1.000") + assert_equal(fsci32('1.0', unique=False, precision=3), "1.000e+00") + assert_equal(fsci64('1.0', unique=False, precision=3), "1.000e+00") + assert_equal(fpos32('1.5', unique=False, precision=3), "1.500") + assert_equal(fpos64('1.5', unique=False, precision=3), "1.500") + assert_equal(fsci32('1.5', unique=False, precision=3), "1.500e+00") + assert_equal(fsci64('1.5', unique=False, precision=3), "1.500e+00") + # gh-10713 + assert_equal(fpos64('324', unique=False, precision=5, fractional=False), "324.00") + + def test_dragon4_interface(self): + tps = [np.float16, np.float32, np.float64] + if hasattr(np, 'float128'): + tps.append(np.float128) + + fpos = np.format_float_positional + fsci = np.format_float_scientific + + for tp in tps: + # test padding + assert_equal(fpos(tp('1.0'), pad_left=4, pad_right=4), " 1. ") + assert_equal(fpos(tp('-1.0'), pad_left=4, pad_right=4), " -1. ") + assert_equal(fpos(tp('-10.2'), + pad_left=4, pad_right=4), " -10.2 ") + + # test exp_digits + assert_equal(fsci(tp('1.23e1'), exp_digits=5), "1.23e+00001") + + # test fixed (non-unique) mode + assert_equal(fpos(tp('1.0'), unique=False, precision=4), "1.0000") + assert_equal(fsci(tp('1.0'), unique=False, precision=4), + "1.0000e+00") + + # test trimming + # trim of 'k' or '.' only affects non-unique mode, since unique + # mode will not output trailing 0s. + assert_equal(fpos(tp('1.'), unique=False, precision=4, trim='k'), + "1.0000") + + assert_equal(fpos(tp('1.'), unique=False, precision=4, trim='.'), + "1.") + assert_equal(fpos(tp('1.2'), unique=False, precision=4, trim='.'), + "1.2" if tp != np.float16 else "1.2002") + + assert_equal(fpos(tp('1.'), unique=False, precision=4, trim='0'), + "1.0") + assert_equal(fpos(tp('1.2'), unique=False, precision=4, trim='0'), + "1.2" if tp != np.float16 else "1.2002") + assert_equal(fpos(tp('1.'), trim='0'), "1.0") + + assert_equal(fpos(tp('1.'), unique=False, precision=4, trim='-'), + "1") + assert_equal(fpos(tp('1.2'), unique=False, precision=4, trim='-'), + "1.2" if tp != np.float16 else "1.2002") + assert_equal(fpos(tp('1.'), trim='-'), "1") + + def float32_roundtrip(self): + # gh-9360 + x = np.float32(1024 - 2**-14) + y = np.float32(1024 - 2**-13) + assert_(repr(x) != repr(y)) + assert_equal(np.float32(repr(x)), x) + assert_equal(np.float32(repr(y)), y) + + def float64_vs_python(self): + # gh-2643, gh-6136, gh-6908 + assert_equal(repr(np.float64(0.1)), repr(0.1)) + assert_(repr(np.float64(0.20000000000000004)) != repr(0.2)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_shape_base.py b/numpy/core/tests/test_shape_base.py new file mode 100644 index 0000000..deb2a40 --- /dev/null +++ b/numpy/core/tests/test_shape_base.py @@ -0,0 +1,587 @@ +from __future__ import division, absolute_import, print_function + +import warnings +import numpy as np +from numpy.core import (array, arange, atleast_1d, atleast_2d, atleast_3d, + block, vstack, hstack, newaxis, concatenate, stack) +from numpy.testing import (assert_, assert_raises, + assert_array_equal, assert_equal, run_module_suite, + assert_raises_regex, assert_almost_equal) + +from numpy.compat import long + +class TestAtleast1d(object): + def test_0D_array(self): + a = array(1) + b = array(2) + res = [atleast_1d(a), atleast_1d(b)] + desired = [array([1]), array([2])] + assert_array_equal(res, desired) + + def test_1D_array(self): + a = array([1, 2]) + b = array([2, 3]) + res = [atleast_1d(a), atleast_1d(b)] + desired = [array([1, 2]), array([2, 3])] + assert_array_equal(res, desired) + + def test_2D_array(self): + a = array([[1, 2], [1, 2]]) + b = array([[2, 3], [2, 3]]) + res = [atleast_1d(a), atleast_1d(b)] + desired = [a, b] + assert_array_equal(res, desired) + + def test_3D_array(self): + a = array([[1, 2], [1, 2]]) + b = array([[2, 3], [2, 3]]) + a = array([a, a]) + b = array([b, b]) + res = [atleast_1d(a), atleast_1d(b)] + desired = [a, b] + assert_array_equal(res, desired) + + def test_r1array(self): + """ Test to make sure equivalent Travis O's r1array function + """ + assert_(atleast_1d(3).shape == (1,)) + assert_(atleast_1d(3j).shape == (1,)) + assert_(atleast_1d(long(3)).shape == (1,)) + assert_(atleast_1d(3.0).shape == (1,)) + assert_(atleast_1d([[2, 3], [4, 5]]).shape == (2, 2)) + + +class TestAtleast2d(object): + def test_0D_array(self): + a = array(1) + b = array(2) + res = [atleast_2d(a), atleast_2d(b)] + desired = [array([[1]]), array([[2]])] + assert_array_equal(res, desired) + + def test_1D_array(self): + a = array([1, 2]) + b = array([2, 3]) + res = [atleast_2d(a), atleast_2d(b)] + desired = [array([[1, 2]]), array([[2, 3]])] + assert_array_equal(res, desired) + + def test_2D_array(self): + a = array([[1, 2], [1, 2]]) + b = array([[2, 3], [2, 3]]) + res = [atleast_2d(a), atleast_2d(b)] + desired = [a, b] + assert_array_equal(res, desired) + + def test_3D_array(self): + a = array([[1, 2], [1, 2]]) + b = array([[2, 3], [2, 3]]) + a = array([a, a]) + b = array([b, b]) + res = [atleast_2d(a), atleast_2d(b)] + desired = [a, b] + assert_array_equal(res, desired) + + def test_r2array(self): + """ Test to make sure equivalent Travis O's r2array function + """ + assert_(atleast_2d(3).shape == (1, 1)) + assert_(atleast_2d([3j, 1]).shape == (1, 2)) + assert_(atleast_2d([[[3, 1], [4, 5]], [[3, 5], [1, 2]]]).shape == (2, 2, 2)) + + +class TestAtleast3d(object): + def test_0D_array(self): + a = array(1) + b = array(2) + res = [atleast_3d(a), atleast_3d(b)] + desired = [array([[[1]]]), array([[[2]]])] + assert_array_equal(res, desired) + + def test_1D_array(self): + a = array([1, 2]) + b = array([2, 3]) + res = [atleast_3d(a), atleast_3d(b)] + desired = [array([[[1], [2]]]), array([[[2], [3]]])] + assert_array_equal(res, desired) + + def test_2D_array(self): + a = array([[1, 2], [1, 2]]) + b = array([[2, 3], [2, 3]]) + res = [atleast_3d(a), atleast_3d(b)] + desired = [a[:,:, newaxis], b[:,:, newaxis]] + assert_array_equal(res, desired) + + def test_3D_array(self): + a = array([[1, 2], [1, 2]]) + b = array([[2, 3], [2, 3]]) + a = array([a, a]) + b = array([b, b]) + res = [atleast_3d(a), atleast_3d(b)] + desired = [a, b] + assert_array_equal(res, desired) + + +class TestHstack(object): + def test_non_iterable(self): + assert_raises(TypeError, hstack, 1) + + def test_empty_input(self): + assert_raises(ValueError, hstack, ()) + + def test_0D_array(self): + a = array(1) + b = array(2) + res = hstack([a, b]) + desired = array([1, 2]) + assert_array_equal(res, desired) + + def test_1D_array(self): + a = array([1]) + b = array([2]) + res = hstack([a, b]) + desired = array([1, 2]) + assert_array_equal(res, desired) + + def test_2D_array(self): + a = array([[1], [2]]) + b = array([[1], [2]]) + res = hstack([a, b]) + desired = array([[1, 1], [2, 2]]) + assert_array_equal(res, desired) + + +class TestVstack(object): + def test_non_iterable(self): + assert_raises(TypeError, vstack, 1) + + def test_empty_input(self): + assert_raises(ValueError, vstack, ()) + + def test_0D_array(self): + a = array(1) + b = array(2) + res = vstack([a, b]) + desired = array([[1], [2]]) + assert_array_equal(res, desired) + + def test_1D_array(self): + a = array([1]) + b = array([2]) + res = vstack([a, b]) + desired = array([[1], [2]]) + assert_array_equal(res, desired) + + def test_2D_array(self): + a = array([[1], [2]]) + b = array([[1], [2]]) + res = vstack([a, b]) + desired = array([[1], [2], [1], [2]]) + assert_array_equal(res, desired) + + def test_2D_array2(self): + a = array([1, 2]) + b = array([1, 2]) + res = vstack([a, b]) + desired = array([[1, 2], [1, 2]]) + assert_array_equal(res, desired) + + +class TestConcatenate(object): + def test_exceptions(self): + # test axis must be in bounds + for ndim in [1, 2, 3]: + a = np.ones((1,)*ndim) + np.concatenate((a, a), axis=0) # OK + assert_raises(np.AxisError, np.concatenate, (a, a), axis=ndim) + assert_raises(np.AxisError, np.concatenate, (a, a), axis=-(ndim + 1)) + + # Scalars cannot be concatenated + assert_raises(ValueError, concatenate, (0,)) + assert_raises(ValueError, concatenate, (np.array(0),)) + + # test shapes must match except for concatenation axis + a = np.ones((1, 2, 3)) + b = np.ones((2, 2, 3)) + axis = list(range(3)) + for i in range(3): + np.concatenate((a, b), axis=axis[0]) # OK + assert_raises(ValueError, np.concatenate, (a, b), axis=axis[1]) + assert_raises(ValueError, np.concatenate, (a, b), axis=axis[2]) + a = np.moveaxis(a, -1, 0) + b = np.moveaxis(b, -1, 0) + axis.append(axis.pop(0)) + + # No arrays to concatenate raises ValueError + assert_raises(ValueError, concatenate, ()) + + def test_concatenate_axis_None(self): + a = np.arange(4, dtype=np.float64).reshape((2, 2)) + b = list(range(3)) + c = ['x'] + r = np.concatenate((a, a), axis=None) + assert_equal(r.dtype, a.dtype) + assert_equal(r.ndim, 1) + r = np.concatenate((a, b), axis=None) + assert_equal(r.size, a.size + len(b)) + assert_equal(r.dtype, a.dtype) + r = np.concatenate((a, b, c), axis=None) + d = array(['0.0', '1.0', '2.0', '3.0', + '0', '1', '2', 'x']) + assert_array_equal(r, d) + + out = np.zeros(a.size + len(b)) + r = np.concatenate((a, b), axis=None) + rout = np.concatenate((a, b), axis=None, out=out) + assert_(out is rout) + assert_equal(r, rout) + + def test_large_concatenate_axis_None(self): + # When no axis is given, concatenate uses flattened versions. + # This also had a bug with many arrays (see gh-5979). + x = np.arange(1, 100) + r = np.concatenate(x, None) + assert_array_equal(x, r) + + # This should probably be deprecated: + r = np.concatenate(x, 100) # axis is >= MAXDIMS + assert_array_equal(x, r) + + def test_concatenate(self): + # Test concatenate function + # One sequence returns unmodified (but as array) + r4 = list(range(4)) + assert_array_equal(concatenate((r4,)), r4) + # Any sequence + assert_array_equal(concatenate((tuple(r4),)), r4) + assert_array_equal(concatenate((array(r4),)), r4) + # 1D default concatenation + r3 = list(range(3)) + assert_array_equal(concatenate((r4, r3)), r4 + r3) + # Mixed sequence types + assert_array_equal(concatenate((tuple(r4), r3)), r4 + r3) + assert_array_equal(concatenate((array(r4), r3)), r4 + r3) + # Explicit axis specification + assert_array_equal(concatenate((r4, r3), 0), r4 + r3) + # Including negative + assert_array_equal(concatenate((r4, r3), -1), r4 + r3) + # 2D + a23 = array([[10, 11, 12], [13, 14, 15]]) + a13 = array([[0, 1, 2]]) + res = array([[10, 11, 12], [13, 14, 15], [0, 1, 2]]) + assert_array_equal(concatenate((a23, a13)), res) + assert_array_equal(concatenate((a23, a13), 0), res) + assert_array_equal(concatenate((a23.T, a13.T), 1), res.T) + assert_array_equal(concatenate((a23.T, a13.T), -1), res.T) + # Arrays much match shape + assert_raises(ValueError, concatenate, (a23.T, a13.T), 0) + # 3D + res = arange(2 * 3 * 7).reshape((2, 3, 7)) + a0 = res[..., :4] + a1 = res[..., 4:6] + a2 = res[..., 6:] + assert_array_equal(concatenate((a0, a1, a2), 2), res) + assert_array_equal(concatenate((a0, a1, a2), -1), res) + assert_array_equal(concatenate((a0.T, a1.T, a2.T), 0), res.T) + + out = res.copy() + rout = concatenate((a0, a1, a2), 2, out=out) + assert_(out is rout) + assert_equal(res, rout) + + def test_bad_out_shape(self): + a = array([1, 2]) + b = array([3, 4]) + + assert_raises(ValueError, concatenate, (a, b), out=np.empty(5)) + assert_raises(ValueError, concatenate, (a, b), out=np.empty((4,1))) + assert_raises(ValueError, concatenate, (a, b), out=np.empty((1,4))) + concatenate((a, b), out=np.empty(4)) + + def test_out_dtype(self): + out = np.empty(4, np.float32) + res = concatenate((array([1, 2]), array([3, 4])), out=out) + assert_(out is res) + + out = np.empty(4, np.complex64) + res = concatenate((array([0.1, 0.2]), array([0.3, 0.4])), out=out) + assert_(out is res) + + # invalid cast + out = np.empty(4, np.int32) + assert_raises(TypeError, concatenate, + (array([0.1, 0.2]), array([0.3, 0.4])), out=out) + + +def test_stack(): + # non-iterable input + assert_raises(TypeError, stack, 1) + + # 0d input + for input_ in [(1, 2, 3), + [np.int32(1), np.int32(2), np.int32(3)], + [np.array(1), np.array(2), np.array(3)]]: + assert_array_equal(stack(input_), [1, 2, 3]) + # 1d input examples + a = np.array([1, 2, 3]) + b = np.array([4, 5, 6]) + r1 = array([[1, 2, 3], [4, 5, 6]]) + assert_array_equal(np.stack((a, b)), r1) + assert_array_equal(np.stack((a, b), axis=1), r1.T) + # all input types + assert_array_equal(np.stack(list([a, b])), r1) + assert_array_equal(np.stack(array([a, b])), r1) + # all shapes for 1d input + arrays = [np.random.randn(3) for _ in range(10)] + axes = [0, 1, -1, -2] + expected_shapes = [(10, 3), (3, 10), (3, 10), (10, 3)] + for axis, expected_shape in zip(axes, expected_shapes): + assert_equal(np.stack(arrays, axis).shape, expected_shape) + assert_raises_regex(np.AxisError, 'out of bounds', stack, arrays, axis=2) + assert_raises_regex(np.AxisError, 'out of bounds', stack, arrays, axis=-3) + # all shapes for 2d input + arrays = [np.random.randn(3, 4) for _ in range(10)] + axes = [0, 1, 2, -1, -2, -3] + expected_shapes = [(10, 3, 4), (3, 10, 4), (3, 4, 10), + (3, 4, 10), (3, 10, 4), (10, 3, 4)] + for axis, expected_shape in zip(axes, expected_shapes): + assert_equal(np.stack(arrays, axis).shape, expected_shape) + # empty arrays + assert_(stack([[], [], []]).shape == (3, 0)) + assert_(stack([[], [], []], axis=1).shape == (0, 3)) + # edge cases + assert_raises_regex(ValueError, 'need at least one array', stack, []) + assert_raises_regex(ValueError, 'must have the same shape', + stack, [1, np.arange(3)]) + assert_raises_regex(ValueError, 'must have the same shape', + stack, [np.arange(3), 1]) + assert_raises_regex(ValueError, 'must have the same shape', + stack, [np.arange(3), 1], axis=1) + assert_raises_regex(ValueError, 'must have the same shape', + stack, [np.zeros((3, 3)), np.zeros(3)], axis=1) + assert_raises_regex(ValueError, 'must have the same shape', + stack, [np.arange(2), np.arange(3)]) + # np.matrix + m = np.matrix([[1, 2], [3, 4]]) + assert_raises_regex(ValueError, 'shape too large to be a matrix', + stack, [m, m]) + + +class TestBlock(object): + def test_block_simple_row_wise(self): + a_2d = np.ones((2, 2)) + b_2d = 2 * a_2d + desired = np.array([[1, 1, 2, 2], + [1, 1, 2, 2]]) + result = block([a_2d, b_2d]) + assert_equal(desired, result) + + def test_block_simple_column_wise(self): + a_2d = np.ones((2, 2)) + b_2d = 2 * a_2d + expected = np.array([[1, 1], + [1, 1], + [2, 2], + [2, 2]]) + result = block([[a_2d], [b_2d]]) + assert_equal(expected, result) + + def test_block_with_1d_arrays_row_wise(self): + # # # 1-D vectors are treated as row arrays + a = np.array([1, 2, 3]) + b = np.array([2, 3, 4]) + expected = np.array([1, 2, 3, 2, 3, 4]) + result = block([a, b]) + assert_equal(expected, result) + + def test_block_with_1d_arrays_multiple_rows(self): + a = np.array([1, 2, 3]) + b = np.array([2, 3, 4]) + expected = np.array([[1, 2, 3, 2, 3, 4], + [1, 2, 3, 2, 3, 4]]) + result = block([[a, b], [a, b]]) + assert_equal(expected, result) + + def test_block_with_1d_arrays_column_wise(self): + # # # 1-D vectors are treated as row arrays + a_1d = np.array([1, 2, 3]) + b_1d = np.array([2, 3, 4]) + expected = np.array([[1, 2, 3], + [2, 3, 4]]) + result = block([[a_1d], [b_1d]]) + assert_equal(expected, result) + + def test_block_mixed_1d_and_2d(self): + a_2d = np.ones((2, 2)) + b_1d = np.array([2, 2]) + result = block([[a_2d], [b_1d]]) + expected = np.array([[1, 1], + [1, 1], + [2, 2]]) + assert_equal(expected, result) + + def test_block_complicated(self): + # a bit more complicated + one_2d = np.array([[1, 1, 1]]) + two_2d = np.array([[2, 2, 2]]) + three_2d = np.array([[3, 3, 3, 3, 3, 3]]) + four_1d = np.array([4, 4, 4, 4, 4, 4]) + five_0d = np.array(5) + six_1d = np.array([6, 6, 6, 6, 6]) + zero_2d = np.zeros((2, 6)) + + expected = np.array([[1, 1, 1, 2, 2, 2], + [3, 3, 3, 3, 3, 3], + [4, 4, 4, 4, 4, 4], + [5, 6, 6, 6, 6, 6], + [0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0]]) + + result = block([[one_2d, two_2d], + [three_2d], + [four_1d], + [five_0d, six_1d], + [zero_2d]]) + assert_equal(result, expected) + + def test_nested(self): + one = np.array([1, 1, 1]) + two = np.array([[2, 2, 2], [2, 2, 2], [2, 2, 2]]) + three = np.array([3, 3, 3]) + four = np.array([4, 4, 4]) + five = np.array(5) + six = np.array([6, 6, 6, 6, 6]) + zero = np.zeros((2, 6)) + + result = np.block([ + [ + np.block([ + [one], + [three], + [four] + ]), + two + ], + [five, six], + [zero] + ]) + expected = np.array([[1, 1, 1, 2, 2, 2], + [3, 3, 3, 2, 2, 2], + [4, 4, 4, 2, 2, 2], + [5, 6, 6, 6, 6, 6], + [0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0]]) + + assert_equal(result, expected) + + def test_3d(self): + a000 = np.ones((2, 2, 2), int) * 1 + + a100 = np.ones((3, 2, 2), int) * 2 + a010 = np.ones((2, 3, 2), int) * 3 + a001 = np.ones((2, 2, 3), int) * 4 + + a011 = np.ones((2, 3, 3), int) * 5 + a101 = np.ones((3, 2, 3), int) * 6 + a110 = np.ones((3, 3, 2), int) * 7 + + a111 = np.ones((3, 3, 3), int) * 8 + + result = np.block([ + [ + [a000, a001], + [a010, a011], + ], + [ + [a100, a101], + [a110, a111], + ] + ]) + expected = array([[[1, 1, 4, 4, 4], + [1, 1, 4, 4, 4], + [3, 3, 5, 5, 5], + [3, 3, 5, 5, 5], + [3, 3, 5, 5, 5]], + + [[1, 1, 4, 4, 4], + [1, 1, 4, 4, 4], + [3, 3, 5, 5, 5], + [3, 3, 5, 5, 5], + [3, 3, 5, 5, 5]], + + [[2, 2, 6, 6, 6], + [2, 2, 6, 6, 6], + [7, 7, 8, 8, 8], + [7, 7, 8, 8, 8], + [7, 7, 8, 8, 8]], + + [[2, 2, 6, 6, 6], + [2, 2, 6, 6, 6], + [7, 7, 8, 8, 8], + [7, 7, 8, 8, 8], + [7, 7, 8, 8, 8]], + + [[2, 2, 6, 6, 6], + [2, 2, 6, 6, 6], + [7, 7, 8, 8, 8], + [7, 7, 8, 8, 8], + [7, 7, 8, 8, 8]]]) + + assert_array_equal(result, expected) + + def test_block_with_mismatched_shape(self): + a = np.array([0, 0]) + b = np.eye(2) + assert_raises(ValueError, np.block, [a, b]) + assert_raises(ValueError, np.block, [b, a]) + + def test_no_lists(self): + assert_equal(np.block(1), np.array(1)) + assert_equal(np.block(np.eye(3)), np.eye(3)) + + def test_invalid_nesting(self): + msg = 'depths are mismatched' + assert_raises_regex(ValueError, msg, np.block, [1, [2]]) + assert_raises_regex(ValueError, msg, np.block, [1, []]) + assert_raises_regex(ValueError, msg, np.block, [[1], 2]) + assert_raises_regex(ValueError, msg, np.block, [[], 2]) + assert_raises_regex(ValueError, msg, np.block, [ + [[1], [2]], + [[3, 4]], + [5] # missing brackets + ]) + + def test_empty_lists(self): + assert_raises_regex(ValueError, 'empty', np.block, []) + assert_raises_regex(ValueError, 'empty', np.block, [[]]) + assert_raises_regex(ValueError, 'empty', np.block, [[1], []]) + + def test_tuple(self): + assert_raises_regex(TypeError, 'tuple', np.block, ([1, 2], [3, 4])) + assert_raises_regex(TypeError, 'tuple', np.block, [(1, 2), (3, 4)]) + + def test_different_ndims(self): + a = 1. + b = 2 * np.ones((1, 2)) + c = 3 * np.ones((1, 1, 3)) + + result = np.block([a, b, c]) + expected = np.array([[[1., 2., 2., 3., 3., 3.]]]) + + assert_equal(result, expected) + + def test_different_ndims_depths(self): + a = 1. + b = 2 * np.ones((1, 2)) + c = 3 * np.ones((1, 2, 3)) + + result = np.block([[a, b], [c]]) + expected = np.array([[[1., 2., 2.], + [3., 3., 3.], + [3., 3., 3.]]]) + + assert_equal(result, expected) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py new file mode 100644 index 0000000..57e0ec2 --- /dev/null +++ b/numpy/core/tests/test_ufunc.py @@ -0,0 +1,1384 @@ +from __future__ import division, absolute_import, print_function + +import warnings +import itertools + +import numpy as np +import numpy.core.umath_tests as umt +import numpy.core.operand_flag_tests as opflag_tests +from numpy.core.test_rational import rational, test_add, test_add_rationals +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, + assert_array_equal, assert_almost_equal, assert_array_almost_equal, + assert_no_warnings, assert_allclose, +) + + +class TestUfuncKwargs(object): + def test_kwarg_exact(self): + assert_raises(TypeError, np.add, 1, 2, castingx='safe') + assert_raises(TypeError, np.add, 1, 2, dtypex=int) + assert_raises(TypeError, np.add, 1, 2, extobjx=[4096]) + assert_raises(TypeError, np.add, 1, 2, outx=None) + assert_raises(TypeError, np.add, 1, 2, sigx='ii->i') + assert_raises(TypeError, np.add, 1, 2, signaturex='ii->i') + assert_raises(TypeError, np.add, 1, 2, subokx=False) + assert_raises(TypeError, np.add, 1, 2, wherex=[True]) + + def test_sig_signature(self): + assert_raises(ValueError, np.add, 1, 2, sig='ii->i', + signature='ii->i') + + def test_sig_dtype(self): + assert_raises(RuntimeError, np.add, 1, 2, sig='ii->i', + dtype=int) + assert_raises(RuntimeError, np.add, 1, 2, signature='ii->i', + dtype=int) + + +class TestUfunc(object): + def test_pickle(self): + import pickle + assert_(pickle.loads(pickle.dumps(np.sin)) is np.sin) + + # Check that ufunc not defined in the top level numpy namespace such as + # numpy.core.test_rational.test_add can also be pickled + assert_(pickle.loads(pickle.dumps(test_add)) is test_add) + + def test_pickle_withstring(self): + import pickle + astring = (b"cnumpy.core\n_ufunc_reconstruct\np0\n" + b"(S'numpy.core.umath'\np1\nS'cos'\np2\ntp3\nRp4\n.") + assert_(pickle.loads(astring) is np.cos) + + def test_reduceat_shifting_sum(self): + L = 6 + x = np.arange(L) + idx = np.array(list(zip(np.arange(L - 2), np.arange(L - 2) + 2))).ravel() + assert_array_equal(np.add.reduceat(x, idx)[::2], [1, 3, 5, 7]) + + def test_generic_loops(self): + """Test generic loops. + + The loops to be tested are: + + PyUFunc_ff_f_As_dd_d + PyUFunc_ff_f + PyUFunc_dd_d + PyUFunc_gg_g + PyUFunc_FF_F_As_DD_D + PyUFunc_DD_D + PyUFunc_FF_F + PyUFunc_GG_G + PyUFunc_OO_O + PyUFunc_OO_O_method + PyUFunc_f_f_As_d_d + PyUFunc_d_d + PyUFunc_f_f + PyUFunc_g_g + PyUFunc_F_F_As_D_D + PyUFunc_F_F + PyUFunc_D_D + PyUFunc_G_G + PyUFunc_O_O + PyUFunc_O_O_method + PyUFunc_On_Om + + Where: + + f -- float + d -- double + g -- long double + F -- complex float + D -- complex double + G -- complex long double + O -- python object + + It is difficult to assure that each of these loops is entered from the + Python level as the special cased loops are a moving target and the + corresponding types are architecture dependent. We probably need to + define C level testing ufuncs to get at them. For the time being, I've + just looked at the signatures registered in the build directory to find + relevant functions. + + Fixme, currently untested: + + PyUFunc_ff_f_As_dd_d + PyUFunc_FF_F_As_DD_D + PyUFunc_f_f_As_d_d + PyUFunc_F_F_As_D_D + PyUFunc_On_Om + + """ + fone = np.exp + ftwo = lambda x, y: x**y + fone_val = 1 + ftwo_val = 1 + # check unary PyUFunc_f_f. + msg = "PyUFunc_f_f" + x = np.zeros(10, dtype=np.single)[0::2] + assert_almost_equal(fone(x), fone_val, err_msg=msg) + # check unary PyUFunc_d_d. + msg = "PyUFunc_d_d" + x = np.zeros(10, dtype=np.double)[0::2] + assert_almost_equal(fone(x), fone_val, err_msg=msg) + # check unary PyUFunc_g_g. + msg = "PyUFunc_g_g" + x = np.zeros(10, dtype=np.longdouble)[0::2] + assert_almost_equal(fone(x), fone_val, err_msg=msg) + # check unary PyUFunc_F_F. + msg = "PyUFunc_F_F" + x = np.zeros(10, dtype=np.csingle)[0::2] + assert_almost_equal(fone(x), fone_val, err_msg=msg) + # check unary PyUFunc_D_D. + msg = "PyUFunc_D_D" + x = np.zeros(10, dtype=np.cdouble)[0::2] + assert_almost_equal(fone(x), fone_val, err_msg=msg) + # check unary PyUFunc_G_G. + msg = "PyUFunc_G_G" + x = np.zeros(10, dtype=np.clongdouble)[0::2] + assert_almost_equal(fone(x), fone_val, err_msg=msg) + + # check binary PyUFunc_ff_f. + msg = "PyUFunc_ff_f" + x = np.ones(10, dtype=np.single)[0::2] + assert_almost_equal(ftwo(x, x), ftwo_val, err_msg=msg) + # check binary PyUFunc_dd_d. + msg = "PyUFunc_dd_d" + x = np.ones(10, dtype=np.double)[0::2] + assert_almost_equal(ftwo(x, x), ftwo_val, err_msg=msg) + # check binary PyUFunc_gg_g. + msg = "PyUFunc_gg_g" + x = np.ones(10, dtype=np.longdouble)[0::2] + assert_almost_equal(ftwo(x, x), ftwo_val, err_msg=msg) + # check binary PyUFunc_FF_F. + msg = "PyUFunc_FF_F" + x = np.ones(10, dtype=np.csingle)[0::2] + assert_almost_equal(ftwo(x, x), ftwo_val, err_msg=msg) + # check binary PyUFunc_DD_D. + msg = "PyUFunc_DD_D" + x = np.ones(10, dtype=np.cdouble)[0::2] + assert_almost_equal(ftwo(x, x), ftwo_val, err_msg=msg) + # check binary PyUFunc_GG_G. + msg = "PyUFunc_GG_G" + x = np.ones(10, dtype=np.clongdouble)[0::2] + assert_almost_equal(ftwo(x, x), ftwo_val, err_msg=msg) + + # class to use in testing object method loops + class foo(object): + def conjugate(self): + return np.bool_(1) + + def logical_xor(self, obj): + return np.bool_(1) + + # check unary PyUFunc_O_O + msg = "PyUFunc_O_O" + x = np.ones(10, dtype=object)[0::2] + assert_(np.all(np.abs(x) == 1), msg) + # check unary PyUFunc_O_O_method + msg = "PyUFunc_O_O_method" + x = np.zeros(10, dtype=object)[0::2] + for i in range(len(x)): + x[i] = foo() + assert_(np.all(np.conjugate(x) == True), msg) + + # check binary PyUFunc_OO_O + msg = "PyUFunc_OO_O" + x = np.ones(10, dtype=object)[0::2] + assert_(np.all(np.add(x, x) == 2), msg) + # check binary PyUFunc_OO_O_method + msg = "PyUFunc_OO_O_method" + x = np.zeros(10, dtype=object)[0::2] + for i in range(len(x)): + x[i] = foo() + assert_(np.all(np.logical_xor(x, x)), msg) + + # check PyUFunc_On_Om + # fixme -- I don't know how to do this yet + + def test_all_ufunc(self): + """Try to check presence and results of all ufuncs. + + The list of ufuncs comes from generate_umath.py and is as follows: + + ===== ==== ============= =============== ======================== + done args function types notes + ===== ==== ============= =============== ======================== + n 1 conjugate nums + O + n 1 absolute nums + O complex -> real + n 1 negative nums + O + n 1 sign nums + O -> int + n 1 invert bool + ints + O flts raise an error + n 1 degrees real + M cmplx raise an error + n 1 radians real + M cmplx raise an error + n 1 arccos flts + M + n 1 arccosh flts + M + n 1 arcsin flts + M + n 1 arcsinh flts + M + n 1 arctan flts + M + n 1 arctanh flts + M + n 1 cos flts + M + n 1 sin flts + M + n 1 tan flts + M + n 1 cosh flts + M + n 1 sinh flts + M + n 1 tanh flts + M + n 1 exp flts + M + n 1 expm1 flts + M + n 1 log flts + M + n 1 log10 flts + M + n 1 log1p flts + M + n 1 sqrt flts + M real x < 0 raises error + n 1 ceil real + M + n 1 trunc real + M + n 1 floor real + M + n 1 fabs real + M + n 1 rint flts + M + n 1 isnan flts -> bool + n 1 isinf flts -> bool + n 1 isfinite flts -> bool + n 1 signbit real -> bool + n 1 modf real -> (frac, int) + n 1 logical_not bool + nums + M -> bool + n 2 left_shift ints + O flts raise an error + n 2 right_shift ints + O flts raise an error + n 2 add bool + nums + O boolean + is || + n 2 subtract bool + nums + O boolean - is ^ + n 2 multiply bool + nums + O boolean * is & + n 2 divide nums + O + n 2 floor_divide nums + O + n 2 true_divide nums + O bBhH -> f, iIlLqQ -> d + n 2 fmod nums + M + n 2 power nums + O + n 2 greater bool + nums + O -> bool + n 2 greater_equal bool + nums + O -> bool + n 2 less bool + nums + O -> bool + n 2 less_equal bool + nums + O -> bool + n 2 equal bool + nums + O -> bool + n 2 not_equal bool + nums + O -> bool + n 2 logical_and bool + nums + M -> bool + n 2 logical_or bool + nums + M -> bool + n 2 logical_xor bool + nums + M -> bool + n 2 maximum bool + nums + O + n 2 minimum bool + nums + O + n 2 bitwise_and bool + ints + O flts raise an error + n 2 bitwise_or bool + ints + O flts raise an error + n 2 bitwise_xor bool + ints + O flts raise an error + n 2 arctan2 real + M + n 2 remainder ints + real + O + n 2 hypot real + M + ===== ==== ============= =============== ======================== + + Types other than those listed will be accepted, but they are cast to + the smallest compatible type for which the function is defined. The + casting rules are: + + bool -> int8 -> float32 + ints -> double + + """ + pass + + def test_signature(self): + # the arguments to test_signature are: nin, nout, core_signature + # pass + assert_equal(umt.test_signature(2, 1, "(i),(i)->()"), 1) + + # pass. empty core signature; treat as plain ufunc (with trivial core) + assert_equal(umt.test_signature(2, 1, "(),()->()"), 0) + + # in the following calls, a ValueError should be raised because + # of error in core signature + # FIXME These should be using assert_raises + + # error: extra parenthesis + msg = "core_sig: extra parenthesis" + try: + ret = umt.test_signature(2, 1, "((i)),(i)->()") + assert_equal(ret, None, err_msg=msg) + except ValueError: + pass + + # error: parenthesis matching + msg = "core_sig: parenthesis matching" + try: + ret = umt.test_signature(2, 1, "(i),)i(->()") + assert_equal(ret, None, err_msg=msg) + except ValueError: + pass + + # error: incomplete signature. letters outside of parenthesis are ignored + msg = "core_sig: incomplete signature" + try: + ret = umt.test_signature(2, 1, "(i),->()") + assert_equal(ret, None, err_msg=msg) + except ValueError: + pass + + # error: incomplete signature. 2 output arguments are specified + msg = "core_sig: incomplete signature" + try: + ret = umt.test_signature(2, 2, "(i),(i)->()") + assert_equal(ret, None, err_msg=msg) + except ValueError: + pass + + # more complicated names for variables + assert_equal(umt.test_signature(2, 1, "(i1,i2),(J_1)->(_kAB)"), 1) + + def test_get_signature(self): + assert_equal(umt.inner1d.signature, "(i),(i)->()") + + def test_forced_sig(self): + a = 0.5*np.arange(3, dtype='f8') + assert_equal(np.add(a, 0.5), [0.5, 1, 1.5]) + assert_equal(np.add(a, 0.5, sig='i', casting='unsafe'), [0, 0, 1]) + assert_equal(np.add(a, 0.5, sig='ii->i', casting='unsafe'), [0, 0, 1]) + assert_equal(np.add(a, 0.5, sig=('i4',), casting='unsafe'), [0, 0, 1]) + assert_equal(np.add(a, 0.5, sig=('i4', 'i4', 'i4'), + casting='unsafe'), [0, 0, 1]) + + b = np.zeros((3,), dtype='f8') + np.add(a, 0.5, out=b) + assert_equal(b, [0.5, 1, 1.5]) + b[:] = 0 + np.add(a, 0.5, sig='i', out=b, casting='unsafe') + assert_equal(b, [0, 0, 1]) + b[:] = 0 + np.add(a, 0.5, sig='ii->i', out=b, casting='unsafe') + assert_equal(b, [0, 0, 1]) + b[:] = 0 + np.add(a, 0.5, sig=('i4',), out=b, casting='unsafe') + assert_equal(b, [0, 0, 1]) + b[:] = 0 + np.add(a, 0.5, sig=('i4', 'i4', 'i4'), out=b, casting='unsafe') + assert_equal(b, [0, 0, 1]) + + def test_true_divide(self): + a = np.array(10) + b = np.array(20) + tgt = np.array(0.5) + + for tc in 'bhilqBHILQefdgFDG': + dt = np.dtype(tc) + aa = a.astype(dt) + bb = b.astype(dt) + + # Check result value and dtype. + for x, y in itertools.product([aa, -aa], [bb, -bb]): + + # Check with no output type specified + if tc in 'FDG': + tgt = complex(x)/complex(y) + else: + tgt = float(x)/float(y) + + res = np.true_divide(x, y) + rtol = max(np.finfo(res).resolution, 1e-15) + assert_allclose(res, tgt, rtol=rtol) + + if tc in 'bhilqBHILQ': + assert_(res.dtype.name == 'float64') + else: + assert_(res.dtype.name == dt.name ) + + # Check with output type specified. This also checks for the + # incorrect casts in issue gh-3484 because the unary '-' does + # not change types, even for unsigned types, Hence casts in the + # ufunc from signed to unsigned and vice versa will lead to + # errors in the values. + for tcout in 'bhilqBHILQ': + dtout = np.dtype(tcout) + assert_raises(TypeError, np.true_divide, x, y, dtype=dtout) + + for tcout in 'efdg': + dtout = np.dtype(tcout) + if tc in 'FDG': + # Casting complex to float is not allowed + assert_raises(TypeError, np.true_divide, x, y, dtype=dtout) + else: + tgt = float(x)/float(y) + rtol = max(np.finfo(dtout).resolution, 1e-15) + atol = max(np.finfo(dtout).tiny, 3e-308) + # Some test values result in invalid for float16. + with np.errstate(invalid='ignore'): + res = np.true_divide(x, y, dtype=dtout) + if not np.isfinite(res) and tcout == 'e': + continue + assert_allclose(res, tgt, rtol=rtol, atol=atol) + assert_(res.dtype.name == dtout.name) + + for tcout in 'FDG': + dtout = np.dtype(tcout) + tgt = complex(x)/complex(y) + rtol = max(np.finfo(dtout).resolution, 1e-15) + atol = max(np.finfo(dtout).tiny, 3e-308) + res = np.true_divide(x, y, dtype=dtout) + if not np.isfinite(res): + continue + assert_allclose(res, tgt, rtol=rtol, atol=atol) + assert_(res.dtype.name == dtout.name) + + # Check booleans + a = np.ones((), dtype=np.bool_) + res = np.true_divide(a, a) + assert_(res == 1.0) + assert_(res.dtype.name == 'float64') + res = np.true_divide(~a, a) + assert_(res == 0.0) + assert_(res.dtype.name == 'float64') + + def test_sum_stability(self): + a = np.ones(500, dtype=np.float32) + assert_almost_equal((a / 10.).sum() - a.size / 10., 0, 4) + + a = np.ones(500, dtype=np.float64) + assert_almost_equal((a / 10.).sum() - a.size / 10., 0, 13) + + def test_sum(self): + for dt in (int, np.float16, np.float32, np.float64, np.longdouble): + for v in (0, 1, 2, 7, 8, 9, 15, 16, 19, 127, + 128, 1024, 1235): + tgt = dt(v * (v + 1) / 2) + d = np.arange(1, v + 1, dtype=dt) + + # warning if sum overflows, which it does in float16 + overflow = not np.isfinite(tgt) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + assert_almost_equal(np.sum(d), tgt) + assert_equal(len(w), 1 * overflow) + + assert_almost_equal(np.sum(d[::-1]), tgt) + assert_equal(len(w), 2 * overflow) + + d = np.ones(500, dtype=dt) + assert_almost_equal(np.sum(d[::2]), 250.) + assert_almost_equal(np.sum(d[1::2]), 250.) + assert_almost_equal(np.sum(d[::3]), 167.) + assert_almost_equal(np.sum(d[1::3]), 167.) + assert_almost_equal(np.sum(d[::-2]), 250.) + assert_almost_equal(np.sum(d[-1::-2]), 250.) + assert_almost_equal(np.sum(d[::-3]), 167.) + assert_almost_equal(np.sum(d[-1::-3]), 167.) + # sum with first reduction entry != 0 + d = np.ones((1,), dtype=dt) + d += d + assert_almost_equal(d, 2.) + + def test_sum_complex(self): + for dt in (np.complex64, np.complex128, np.clongdouble): + for v in (0, 1, 2, 7, 8, 9, 15, 16, 19, 127, + 128, 1024, 1235): + tgt = dt(v * (v + 1) / 2) - dt((v * (v + 1) / 2) * 1j) + d = np.empty(v, dtype=dt) + d.real = np.arange(1, v + 1) + d.imag = -np.arange(1, v + 1) + assert_almost_equal(np.sum(d), tgt) + assert_almost_equal(np.sum(d[::-1]), tgt) + + d = np.ones(500, dtype=dt) + 1j + assert_almost_equal(np.sum(d[::2]), 250. + 250j) + assert_almost_equal(np.sum(d[1::2]), 250. + 250j) + assert_almost_equal(np.sum(d[::3]), 167. + 167j) + assert_almost_equal(np.sum(d[1::3]), 167. + 167j) + assert_almost_equal(np.sum(d[::-2]), 250. + 250j) + assert_almost_equal(np.sum(d[-1::-2]), 250. + 250j) + assert_almost_equal(np.sum(d[::-3]), 167. + 167j) + assert_almost_equal(np.sum(d[-1::-3]), 167. + 167j) + # sum with first reduction entry != 0 + d = np.ones((1,), dtype=dt) + 1j + d += d + assert_almost_equal(d, 2. + 2j) + + def test_inner1d(self): + a = np.arange(6).reshape((2, 3)) + assert_array_equal(umt.inner1d(a, a), np.sum(a*a, axis=-1)) + a = np.arange(6) + assert_array_equal(umt.inner1d(a, a), np.sum(a*a)) + + def test_broadcast(self): + msg = "broadcast" + a = np.arange(4).reshape((2, 1, 2)) + b = np.arange(4).reshape((1, 2, 2)) + assert_array_equal(umt.inner1d(a, b), np.sum(a*b, axis=-1), err_msg=msg) + msg = "extend & broadcast loop dimensions" + b = np.arange(4).reshape((2, 2)) + assert_array_equal(umt.inner1d(a, b), np.sum(a*b, axis=-1), err_msg=msg) + # Broadcast in core dimensions should fail + a = np.arange(8).reshape((4, 2)) + b = np.arange(4).reshape((4, 1)) + assert_raises(ValueError, umt.inner1d, a, b) + # Extend core dimensions should fail + a = np.arange(8).reshape((4, 2)) + b = np.array(7) + assert_raises(ValueError, umt.inner1d, a, b) + # Broadcast should fail + a = np.arange(2).reshape((2, 1, 1)) + b = np.arange(3).reshape((3, 1, 1)) + assert_raises(ValueError, umt.inner1d, a, b) + + def test_type_cast(self): + msg = "type cast" + a = np.arange(6, dtype='short').reshape((2, 3)) + assert_array_equal(umt.inner1d(a, a), np.sum(a*a, axis=-1), + err_msg=msg) + msg = "type cast on one argument" + a = np.arange(6).reshape((2, 3)) + b = a + 0.1 + assert_array_almost_equal(umt.inner1d(a, b), np.sum(a*b, axis=-1), + err_msg=msg) + + def test_endian(self): + msg = "big endian" + a = np.arange(6, dtype='>i4').reshape((2, 3)) + assert_array_equal(umt.inner1d(a, a), np.sum(a*a, axis=-1), + err_msg=msg) + msg = "little endian" + a = np.arange(6, dtype='(p) + assert_raises(ValueError, umt.euclidean_pdist, a) + + def test_object_logical(self): + a = np.array([3, None, True, False, "test", ""], dtype=object) + assert_equal(np.logical_or(a, None), + np.array([x or None for x in a], dtype=object)) + assert_equal(np.logical_or(a, True), + np.array([x or True for x in a], dtype=object)) + assert_equal(np.logical_or(a, 12), + np.array([x or 12 for x in a], dtype=object)) + assert_equal(np.logical_or(a, "blah"), + np.array([x or "blah" for x in a], dtype=object)) + + assert_equal(np.logical_and(a, None), + np.array([x and None for x in a], dtype=object)) + assert_equal(np.logical_and(a, True), + np.array([x and True for x in a], dtype=object)) + assert_equal(np.logical_and(a, 12), + np.array([x and 12 for x in a], dtype=object)) + assert_equal(np.logical_and(a, "blah"), + np.array([x and "blah" for x in a], dtype=object)) + + assert_equal(np.logical_not(a), + np.array([not x for x in a], dtype=object)) + + assert_equal(np.logical_or.reduce(a), 3) + assert_equal(np.logical_and.reduce(a), None) + + def test_object_array_reduction(self): + # Reductions on object arrays + a = np.array(['a', 'b', 'c'], dtype=object) + assert_equal(np.sum(a), 'abc') + assert_equal(np.max(a), 'c') + assert_equal(np.min(a), 'a') + a = np.array([True, False, True], dtype=object) + assert_equal(np.sum(a), 2) + assert_equal(np.prod(a), 0) + assert_equal(np.any(a), True) + assert_equal(np.all(a), False) + assert_equal(np.max(a), True) + assert_equal(np.min(a), False) + assert_equal(np.array([[1]], dtype=object).sum(), 1) + assert_equal(np.array([[[1, 2]]], dtype=object).sum((0, 1)), [1, 2]) + + def test_object_array_accumulate_inplace(self): + # Checks that in-place accumulates work, see also gh-7402 + arr = np.ones(4, dtype=object) + arr[:] = [[1] for i in range(4)] + # Twice reproduced also for tuples: + np.add.accumulate(arr, out=arr) + np.add.accumulate(arr, out=arr) + assert_array_equal(arr, np.array([[1]*i for i in [1, 3, 6, 10]])) + + # And the same if the axis argument is used + arr = np.ones((2, 4), dtype=object) + arr[0, :] = [[2] for i in range(4)] + np.add.accumulate(arr, out=arr, axis=-1) + np.add.accumulate(arr, out=arr, axis=-1) + assert_array_equal(arr[0, :], np.array([[2]*i for i in [1, 3, 6, 10]])) + + def test_object_array_reduceat_inplace(self): + # Checks that in-place reduceats work, see also gh-7465 + arr = np.empty(4, dtype=object) + arr[:] = [[1] for i in range(4)] + out = np.empty(4, dtype=object) + out[:] = [[1] for i in range(4)] + np.add.reduceat(arr, np.arange(4), out=arr) + np.add.reduceat(arr, np.arange(4), out=arr) + assert_array_equal(arr, out) + + # And the same if the axis argument is used + arr = np.ones((2, 4), dtype=object) + arr[0, :] = [[2] for i in range(4)] + out = np.ones((2, 4), dtype=object) + out[0, :] = [[2] for i in range(4)] + np.add.reduceat(arr, np.arange(4), out=arr, axis=-1) + np.add.reduceat(arr, np.arange(4), out=arr, axis=-1) + assert_array_equal(arr, out) + + def test_object_scalar_multiply(self): + # Tickets #2469 and #4482 + arr = np.matrix([1, 2], dtype=object) + desired = np.matrix([[3, 6]], dtype=object) + assert_equal(np.multiply(arr, 3), desired) + assert_equal(np.multiply(3, arr), desired) + + def test_zerosize_reduction(self): + # Test with default dtype and object dtype + for a in [[], np.array([], dtype=object)]: + assert_equal(np.sum(a), 0) + assert_equal(np.prod(a), 1) + assert_equal(np.any(a), False) + assert_equal(np.all(a), True) + assert_raises(ValueError, np.max, a) + assert_raises(ValueError, np.min, a) + + def test_axis_out_of_bounds(self): + a = np.array([False, False]) + assert_raises(np.AxisError, a.all, axis=1) + a = np.array([False, False]) + assert_raises(np.AxisError, a.all, axis=-2) + + a = np.array([False, False]) + assert_raises(np.AxisError, a.any, axis=1) + a = np.array([False, False]) + assert_raises(np.AxisError, a.any, axis=-2) + + def test_scalar_reduction(self): + # The functions 'sum', 'prod', etc allow specifying axis=0 + # even for scalars + assert_equal(np.sum(3, axis=0), 3) + assert_equal(np.prod(3.5, axis=0), 3.5) + assert_equal(np.any(True, axis=0), True) + assert_equal(np.all(False, axis=0), False) + assert_equal(np.max(3, axis=0), 3) + assert_equal(np.min(2.5, axis=0), 2.5) + + # Check scalar behaviour for ufuncs without an identity + assert_equal(np.power.reduce(3), 3) + + # Make sure that scalars are coming out from this operation + assert_(type(np.prod(np.float32(2.5), axis=0)) is np.float32) + assert_(type(np.sum(np.float32(2.5), axis=0)) is np.float32) + assert_(type(np.max(np.float32(2.5), axis=0)) is np.float32) + assert_(type(np.min(np.float32(2.5), axis=0)) is np.float32) + + # check if scalars/0-d arrays get cast + assert_(type(np.any(0, axis=0)) is np.bool_) + + # assert that 0-d arrays get wrapped + class MyArray(np.ndarray): + pass + a = np.array(1).view(MyArray) + assert_(type(np.any(a)) is MyArray) + + def test_casting_out_param(self): + # Test that it's possible to do casts on output + a = np.ones((200, 100), np.int64) + b = np.ones((200, 100), np.int64) + c = np.ones((200, 100), np.float64) + np.add(a, b, out=c) + assert_equal(c, 2) + + a = np.zeros(65536) + b = np.zeros(65536, dtype=np.float32) + np.subtract(a, 0, out=b) + assert_equal(b, 0) + + def test_where_param(self): + # Test that the where= ufunc parameter works with regular arrays + a = np.arange(7) + b = np.ones(7) + c = np.zeros(7) + np.add(a, b, out=c, where=(a % 2 == 1)) + assert_equal(c, [0, 2, 0, 4, 0, 6, 0]) + + a = np.arange(4).reshape(2, 2) + 2 + np.power(a, [2, 3], out=a, where=[[0, 1], [1, 0]]) + assert_equal(a, [[2, 27], [16, 5]]) + # Broadcasting the where= parameter + np.subtract(a, 2, out=a, where=[True, False]) + assert_equal(a, [[0, 27], [14, 5]]) + + def test_where_param_buffer_output(self): + # This test is temporarily skipped because it requires + # adding masking features to the nditer to work properly + + # With casting on output + a = np.ones(10, np.int64) + b = np.ones(10, np.int64) + c = 1.5 * np.ones(10, np.float64) + np.add(a, b, out=c, where=[1, 0, 0, 1, 0, 0, 1, 1, 1, 0]) + assert_equal(c, [2, 1.5, 1.5, 2, 1.5, 1.5, 2, 2, 2, 1.5]) + + def test_where_param_alloc(self): + # With casting and allocated output + a = np.array([1], dtype=np.int64) + m = np.array([True], dtype=bool) + assert_equal(np.sqrt(a, where=m), [1]) + + # No casting and allocated output + a = np.array([1], dtype=np.float64) + m = np.array([True], dtype=bool) + assert_equal(np.sqrt(a, where=m), [1]) + + def check_identityless_reduction(self, a): + # np.minimum.reduce is a identityless reduction + + # Verify that it sees the zero at various positions + a[...] = 1 + a[1, 0, 0] = 0 + assert_equal(np.minimum.reduce(a, axis=None), 0) + assert_equal(np.minimum.reduce(a, axis=(0, 1)), [0, 1, 1, 1]) + assert_equal(np.minimum.reduce(a, axis=(0, 2)), [0, 1, 1]) + assert_equal(np.minimum.reduce(a, axis=(1, 2)), [1, 0]) + assert_equal(np.minimum.reduce(a, axis=0), + [[0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=1), + [[1, 1, 1, 1], [0, 1, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=2), + [[1, 1, 1], [0, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=()), a) + + a[...] = 1 + a[0, 1, 0] = 0 + assert_equal(np.minimum.reduce(a, axis=None), 0) + assert_equal(np.minimum.reduce(a, axis=(0, 1)), [0, 1, 1, 1]) + assert_equal(np.minimum.reduce(a, axis=(0, 2)), [1, 0, 1]) + assert_equal(np.minimum.reduce(a, axis=(1, 2)), [0, 1]) + assert_equal(np.minimum.reduce(a, axis=0), + [[1, 1, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=1), + [[0, 1, 1, 1], [1, 1, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=2), + [[1, 0, 1], [1, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=()), a) + + a[...] = 1 + a[0, 0, 1] = 0 + assert_equal(np.minimum.reduce(a, axis=None), 0) + assert_equal(np.minimum.reduce(a, axis=(0, 1)), [1, 0, 1, 1]) + assert_equal(np.minimum.reduce(a, axis=(0, 2)), [0, 1, 1]) + assert_equal(np.minimum.reduce(a, axis=(1, 2)), [0, 1]) + assert_equal(np.minimum.reduce(a, axis=0), + [[1, 0, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=1), + [[1, 0, 1, 1], [1, 1, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=2), + [[0, 1, 1], [1, 1, 1]]) + assert_equal(np.minimum.reduce(a, axis=()), a) + + def test_identityless_reduction_corder(self): + a = np.empty((2, 3, 4), order='C') + self.check_identityless_reduction(a) + + def test_identityless_reduction_forder(self): + a = np.empty((2, 3, 4), order='F') + self.check_identityless_reduction(a) + + def test_identityless_reduction_otherorder(self): + a = np.empty((2, 4, 3), order='C').swapaxes(1, 2) + self.check_identityless_reduction(a) + + def test_identityless_reduction_noncontig(self): + a = np.empty((3, 5, 4), order='C').swapaxes(1, 2) + a = a[1:, 1:, 1:] + self.check_identityless_reduction(a) + + def test_identityless_reduction_noncontig_unaligned(self): + a = np.empty((3*4*5*8 + 1,), dtype='i1') + a = a[1:].view(dtype='f8') + a.shape = (3, 4, 5) + a = a[1:, 1:, 1:] + self.check_identityless_reduction(a) + + def test_identityless_reduction_nonreorderable(self): + a = np.array([[8.0, 2.0, 2.0], [1.0, 0.5, 0.25]]) + + res = np.divide.reduce(a, axis=0) + assert_equal(res, [8.0, 4.0, 8.0]) + + res = np.divide.reduce(a, axis=1) + assert_equal(res, [2.0, 8.0]) + + res = np.divide.reduce(a, axis=()) + assert_equal(res, a) + + assert_raises(ValueError, np.divide.reduce, a, axis=(0, 1)) + + def test_reduce_zero_axis(self): + # If we have a n x m array and do a reduction with axis=1, then we are + # doing n reductions, and each reduction takes an m-element array. For + # a reduction operation without an identity, then: + # n > 0, m > 0: fine + # n = 0, m > 0: fine, doing 0 reductions of m-element arrays + # n > 0, m = 0: can't reduce a 0-element array, ValueError + # n = 0, m = 0: can't reduce a 0-element array, ValueError (for + # consistency with the above case) + # This test doesn't actually look at return values, it just checks to + # make sure that error we get an error in exactly those cases where we + # expect one, and assumes the calculations themselves are done + # correctly. + + def ok(f, *args, **kwargs): + f(*args, **kwargs) + + def err(f, *args, **kwargs): + assert_raises(ValueError, f, *args, **kwargs) + + def t(expect, func, n, m): + expect(func, np.zeros((n, m)), axis=1) + expect(func, np.zeros((m, n)), axis=0) + expect(func, np.zeros((n // 2, n // 2, m)), axis=2) + expect(func, np.zeros((n // 2, m, n // 2)), axis=1) + expect(func, np.zeros((n, m // 2, m // 2)), axis=(1, 2)) + expect(func, np.zeros((m // 2, n, m // 2)), axis=(0, 2)) + expect(func, np.zeros((m // 3, m // 3, m // 3, + n // 2, n // 2)), + axis=(0, 1, 2)) + # Check what happens if the inner (resp. outer) dimensions are a + # mix of zero and non-zero: + expect(func, np.zeros((10, m, n)), axis=(0, 1)) + expect(func, np.zeros((10, n, m)), axis=(0, 2)) + expect(func, np.zeros((m, 10, n)), axis=0) + expect(func, np.zeros((10, m, n)), axis=1) + expect(func, np.zeros((10, n, m)), axis=2) + + # np.maximum is just an arbitrary ufunc with no reduction identity + assert_equal(np.maximum.identity, None) + t(ok, np.maximum.reduce, 30, 30) + t(ok, np.maximum.reduce, 0, 30) + t(err, np.maximum.reduce, 30, 0) + t(err, np.maximum.reduce, 0, 0) + err(np.maximum.reduce, []) + np.maximum.reduce(np.zeros((0, 0)), axis=()) + + # all of the combinations are fine for a reduction that has an + # identity + t(ok, np.add.reduce, 30, 30) + t(ok, np.add.reduce, 0, 30) + t(ok, np.add.reduce, 30, 0) + t(ok, np.add.reduce, 0, 0) + np.add.reduce([]) + np.add.reduce(np.zeros((0, 0)), axis=()) + + # OTOH, accumulate always makes sense for any combination of n and m, + # because it maps an m-element array to an m-element array. These + # tests are simpler because accumulate doesn't accept multiple axes. + for uf in (np.maximum, np.add): + uf.accumulate(np.zeros((30, 0)), axis=0) + uf.accumulate(np.zeros((0, 30)), axis=0) + uf.accumulate(np.zeros((30, 30)), axis=0) + uf.accumulate(np.zeros((0, 0)), axis=0) + + def test_safe_casting(self): + # In old versions of numpy, in-place operations used the 'unsafe' + # casting rules. In versions >= 1.10, 'same_kind' is the + # default and an exception is raised instead of a warning. + # when 'same_kind' is not satisfied. + a = np.array([1, 2, 3], dtype=int) + # Non-in-place addition is fine + assert_array_equal(assert_no_warnings(np.add, a, 1.1), + [2.1, 3.1, 4.1]) + assert_raises(TypeError, np.add, a, 1.1, out=a) + + def add_inplace(a, b): + a += b + + assert_raises(TypeError, add_inplace, a, 1.1) + # Make sure that explicitly overriding the exception is allowed: + assert_no_warnings(np.add, a, 1.1, out=a, casting="unsafe") + assert_array_equal(a, [2, 3, 4]) + + def test_ufunc_custom_out(self): + # Test ufunc with built in input types and custom output type + + a = np.array([0, 1, 2], dtype='i8') + b = np.array([0, 1, 2], dtype='i8') + c = np.empty(3, dtype=rational) + + # Output must be specified so numpy knows what + # ufunc signature to look for + result = test_add(a, b, c) + assert_equal(result, np.array([0, 2, 4], dtype=rational)) + + # no output type should raise TypeError + assert_raises(TypeError, test_add, a, b) + + def test_operand_flags(self): + a = np.arange(16, dtype='l').reshape(4, 4) + b = np.arange(9, dtype='l').reshape(3, 3) + opflag_tests.inplace_add(a[:-1, :-1], b) + assert_equal(a, np.array([[0, 2, 4, 3], [7, 9, 11, 7], + [14, 16, 18, 11], [12, 13, 14, 15]], dtype='l')) + + a = np.array(0) + opflag_tests.inplace_add(a, 3) + assert_equal(a, 3) + opflag_tests.inplace_add(a, [3, 4]) + assert_equal(a, 10) + + def test_struct_ufunc(self): + import numpy.core.struct_ufunc_test as struct_ufunc + + a = np.array([(1, 2, 3)], dtype='u8,u8,u8') + b = np.array([(1, 2, 3)], dtype='u8,u8,u8') + + result = struct_ufunc.add_triplet(a, b) + assert_equal(result, np.array([(2, 4, 6)], dtype='u8,u8,u8')) + + def test_custom_ufunc(self): + a = np.array([rational(1, 2), rational(1, 3), rational(1, 4)], + dtype=rational) + b = np.array([rational(1, 2), rational(1, 3), rational(1, 4)], + dtype=rational) + + result = test_add_rationals(a, b) + expected = np.array([rational(1), rational(2, 3), rational(1, 2)], + dtype=rational) + assert_equal(result, expected) + + def test_custom_ufunc_forced_sig(self): + # gh-9351 - looking for a non-first userloop would previously hang + assert_raises(TypeError, + np.multiply, rational(1), 1, signature=(rational, int, None)) + + def test_custom_array_like(self): + + class MyThing(object): + __array_priority__ = 1000 + + rmul_count = 0 + getitem_count = 0 + + def __init__(self, shape): + self.shape = shape + + def __len__(self): + return self.shape[0] + + def __getitem__(self, i): + MyThing.getitem_count += 1 + if not isinstance(i, tuple): + i = (i,) + if len(i) > self.ndim: + raise IndexError("boo") + + return MyThing(self.shape[len(i):]) + + def __rmul__(self, other): + MyThing.rmul_count += 1 + return self + + np.float64(5)*MyThing((3, 3)) + assert_(MyThing.rmul_count == 1, MyThing.rmul_count) + assert_(MyThing.getitem_count <= 2, MyThing.getitem_count) + + def test_inplace_fancy_indexing(self): + + a = np.arange(10) + np.add.at(a, [2, 5, 2], 1) + assert_equal(a, [0, 1, 4, 3, 4, 6, 6, 7, 8, 9]) + + a = np.arange(10) + b = np.array([100, 100, 100]) + np.add.at(a, [2, 5, 2], b) + assert_equal(a, [0, 1, 202, 3, 4, 105, 6, 7, 8, 9]) + + a = np.arange(9).reshape(3, 3) + b = np.array([[100, 100, 100], [200, 200, 200], [300, 300, 300]]) + np.add.at(a, (slice(None), [1, 2, 1]), b) + assert_equal(a, [[0, 201, 102], [3, 404, 205], [6, 607, 308]]) + + a = np.arange(27).reshape(3, 3, 3) + b = np.array([100, 200, 300]) + np.add.at(a, (slice(None), slice(None), [1, 2, 1]), b) + assert_equal(a, + [[[0, 401, 202], + [3, 404, 205], + [6, 407, 208]], + + [[9, 410, 211], + [12, 413, 214], + [15, 416, 217]], + + [[18, 419, 220], + [21, 422, 223], + [24, 425, 226]]]) + + a = np.arange(9).reshape(3, 3) + b = np.array([[100, 100, 100], [200, 200, 200], [300, 300, 300]]) + np.add.at(a, ([1, 2, 1], slice(None)), b) + assert_equal(a, [[0, 1, 2], [403, 404, 405], [206, 207, 208]]) + + a = np.arange(27).reshape(3, 3, 3) + b = np.array([100, 200, 300]) + np.add.at(a, (slice(None), [1, 2, 1], slice(None)), b) + assert_equal(a, + [[[0, 1, 2], + [203, 404, 605], + [106, 207, 308]], + + [[9, 10, 11], + [212, 413, 614], + [115, 216, 317]], + + [[18, 19, 20], + [221, 422, 623], + [124, 225, 326]]]) + + a = np.arange(9).reshape(3, 3) + b = np.array([100, 200, 300]) + np.add.at(a, (0, [1, 2, 1]), b) + assert_equal(a, [[0, 401, 202], [3, 4, 5], [6, 7, 8]]) + + a = np.arange(27).reshape(3, 3, 3) + b = np.array([100, 200, 300]) + np.add.at(a, ([1, 2, 1], 0, slice(None)), b) + assert_equal(a, + [[[0, 1, 2], + [3, 4, 5], + [6, 7, 8]], + + [[209, 410, 611], + [12, 13, 14], + [15, 16, 17]], + + [[118, 219, 320], + [21, 22, 23], + [24, 25, 26]]]) + + a = np.arange(27).reshape(3, 3, 3) + b = np.array([100, 200, 300]) + np.add.at(a, (slice(None), slice(None), slice(None)), b) + assert_equal(a, + [[[100, 201, 302], + [103, 204, 305], + [106, 207, 308]], + + [[109, 210, 311], + [112, 213, 314], + [115, 216, 317]], + + [[118, 219, 320], + [121, 222, 323], + [124, 225, 326]]]) + + a = np.arange(10) + np.negative.at(a, [2, 5, 2]) + assert_equal(a, [0, 1, 2, 3, 4, -5, 6, 7, 8, 9]) + + # Test 0-dim array + a = np.array(0) + np.add.at(a, (), 1) + assert_equal(a, 1) + + assert_raises(IndexError, np.add.at, a, 0, 1) + assert_raises(IndexError, np.add.at, a, [], 1) + + # Test mixed dtypes + a = np.arange(10) + np.power.at(a, [1, 2, 3, 2], 3.5) + assert_equal(a, np.array([0, 1, 4414, 46, 4, 5, 6, 7, 8, 9])) + + # Test boolean indexing and boolean ufuncs + a = np.arange(10) + index = a % 2 == 0 + np.equal.at(a, index, [0, 2, 4, 6, 8]) + assert_equal(a, [1, 1, 1, 3, 1, 5, 1, 7, 1, 9]) + + # Test unary operator + a = np.arange(10, dtype='u4') + np.invert.at(a, [2, 5, 2]) + assert_equal(a, [0, 1, 2, 3, 4, 5 ^ 0xffffffff, 6, 7, 8, 9]) + + # Test empty subspace + orig = np.arange(4) + a = orig[:, None][:, 0:0] + np.add.at(a, [0, 1], 3) + assert_array_equal(orig, np.arange(4)) + + # Test with swapped byte order + index = np.array([1, 2, 1], np.dtype('i').newbyteorder()) + values = np.array([1, 2, 3, 4], np.dtype('f').newbyteorder()) + np.add.at(values, index, 3) + assert_array_equal(values, [1, 8, 6, 4]) + + # Test exception thrown + values = np.array(['a', 1], dtype=object) + assert_raises(TypeError, np.add.at, values, [0, 1], 1) + assert_array_equal(values, np.array(['a', 1], dtype=object)) + + # Test multiple output ufuncs raise error, gh-5665 + assert_raises(ValueError, np.modf.at, np.arange(10), [1]) + + def test_reduce_arguments(self): + f = np.add.reduce + d = np.ones((5,2), dtype=int) + o = np.ones((2,), dtype=d.dtype) + r = o * 5 + assert_equal(f(d), r) + # a, axis=0, dtype=None, out=None, keepdims=False + assert_equal(f(d, axis=0), r) + assert_equal(f(d, 0), r) + assert_equal(f(d, 0, dtype=None), r) + assert_equal(f(d, 0, dtype='i'), r) + assert_equal(f(d, 0, 'i'), r) + assert_equal(f(d, 0, None), r) + assert_equal(f(d, 0, None, out=None), r) + assert_equal(f(d, 0, None, out=o), r) + assert_equal(f(d, 0, None, o), r) + assert_equal(f(d, 0, None, None), r) + assert_equal(f(d, 0, None, None, keepdims=False), r) + assert_equal(f(d, 0, None, None, True), r.reshape((1,) + r.shape)) + # multiple keywords + assert_equal(f(d, axis=0, dtype=None, out=None, keepdims=False), r) + assert_equal(f(d, 0, dtype=None, out=None, keepdims=False), r) + assert_equal(f(d, 0, None, out=None, keepdims=False), r) + + # too little + assert_raises(TypeError, f) + # too much + assert_raises(TypeError, f, d, 0, None, None, False, 1) + # invalid axis + assert_raises(TypeError, f, d, "invalid") + assert_raises(TypeError, f, d, axis="invalid") + assert_raises(TypeError, f, d, axis="invalid", dtype=None, + keepdims=True) + # invalid dtype + assert_raises(TypeError, f, d, 0, "invalid") + assert_raises(TypeError, f, d, dtype="invalid") + assert_raises(TypeError, f, d, dtype="invalid", out=None) + # invalid out + assert_raises(TypeError, f, d, 0, None, "invalid") + assert_raises(TypeError, f, d, out="invalid") + assert_raises(TypeError, f, d, out="invalid", dtype=None) + # keepdims boolean, no invalid value + # assert_raises(TypeError, f, d, 0, None, None, "invalid") + # assert_raises(TypeError, f, d, keepdims="invalid", axis=0, dtype=None) + # invalid mix + assert_raises(TypeError, f, d, 0, keepdims="invalid", dtype="invalid", + out=None) + + # invalid keyord + assert_raises(TypeError, f, d, axis=0, dtype=None, invalid=0) + assert_raises(TypeError, f, d, invalid=0) + assert_raises(TypeError, f, d, 0, keepdims=True, invalid="invalid", + out=None) + assert_raises(TypeError, f, d, axis=0, dtype=None, keepdims=True, + out=None, invalid=0) + assert_raises(TypeError, f, d, axis=0, dtype=None, + out=None, invalid=0) + + def test_structured_equal(self): + # https://github.com/numpy/numpy/issues/4855 + + class MyA(np.ndarray): + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + return getattr(ufunc, method)(*(input.view(np.ndarray) + for input in inputs), **kwargs) + a = np.arange(12.).reshape(4,3) + ra = a.view(dtype=('f8,f8,f8')).squeeze() + mra = ra.view(MyA) + + target = np.array([ True, False, False, False], dtype=bool) + assert_equal(np.all(target == (mra == ra[0])), True) + + def test_NotImplemented_not_returned(self): + # See gh-5964 and gh-2091. Some of these functions are not operator + # related and were fixed for other reasons in the past. + binary_funcs = [ + np.power, np.add, np.subtract, np.multiply, np.divide, + np.true_divide, np.floor_divide, np.bitwise_and, np.bitwise_or, + np.bitwise_xor, np.left_shift, np.right_shift, np.fmax, + np.fmin, np.fmod, np.hypot, np.logaddexp, np.logaddexp2, + np.logical_and, np.logical_or, np.logical_xor, np.maximum, + np.minimum, np.mod + ] + + # These functions still return NotImplemented. Will be fixed in + # future. + # bad = [np.greater, np.greater_equal, np.less, np.less_equal, np.not_equal] + + a = np.array('1') + b = 1 + for f in binary_funcs: + assert_raises(TypeError, f, a, b) + + def test_reduce_noncontig_output(self): + # Check that reduction deals with non-contiguous output arrays + # appropriately. + # + # gh-8036 + + x = np.arange(7*13*8, dtype=np.int16).reshape(7, 13, 8) + x = x[4:6,1:11:6,1:5].transpose(1, 2, 0) + y_base = np.arange(4*4, dtype=np.int16).reshape(4, 4) + y = y_base[::2,:] + + y_base_copy = y_base.copy() + + r0 = np.add.reduce(x, out=y.copy(), axis=2) + r1 = np.add.reduce(x, out=y, axis=2) + + # The results should match, and y_base shouldn't get clobbered + assert_equal(r0, r1) + assert_equal(y_base[1,:], y_base_copy[1,:]) + assert_equal(y_base[3,:], y_base_copy[3,:]) + + def test_no_doc_string(self): + # gh-9337 + assert_('\n' not in umt.inner1d_no_doc.__doc__) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py new file mode 100644 index 0000000..bebeddc --- /dev/null +++ b/numpy/core/tests/test_umath.py @@ -0,0 +1,2676 @@ +from __future__ import division, absolute_import, print_function + +import sys +import platform +import warnings +import fnmatch +import itertools + +import numpy.core.umath as ncu +from numpy.core import umath_tests as ncu_tests +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, + assert_raises_regex, assert_array_equal, assert_almost_equal, + assert_array_almost_equal, dec, assert_allclose, assert_no_warnings, + suppress_warnings, _gen_alignment_data, +) + + +def on_powerpc(): + """ True if we are running on a Power PC platform.""" + return platform.processor() == 'powerpc' or \ + platform.machine().startswith('ppc') + + +class _FilterInvalids(object): + def setUp(self): + self.olderr = np.seterr(invalid='ignore') + + def tearDown(self): + np.seterr(**self.olderr) + + +class TestConstants(object): + def test_pi(self): + assert_allclose(ncu.pi, 3.141592653589793, 1e-15) + + def test_e(self): + assert_allclose(ncu.e, 2.718281828459045, 1e-15) + + def test_euler_gamma(self): + assert_allclose(ncu.euler_gamma, 0.5772156649015329, 1e-15) + + +class TestOut(object): + def test_out_subok(self): + for subok in (True, False): + a = np.array(0.5) + o = np.empty(()) + + r = np.add(a, 2, o, subok=subok) + assert_(r is o) + r = np.add(a, 2, out=o, subok=subok) + assert_(r is o) + r = np.add(a, 2, out=(o,), subok=subok) + assert_(r is o) + + d = np.array(5.7) + o1 = np.empty(()) + o2 = np.empty((), dtype=np.int32) + + r1, r2 = np.frexp(d, o1, None, subok=subok) + assert_(r1 is o1) + r1, r2 = np.frexp(d, None, o2, subok=subok) + assert_(r2 is o2) + r1, r2 = np.frexp(d, o1, o2, subok=subok) + assert_(r1 is o1) + assert_(r2 is o2) + + r1, r2 = np.frexp(d, out=(o1, None), subok=subok) + assert_(r1 is o1) + r1, r2 = np.frexp(d, out=(None, o2), subok=subok) + assert_(r2 is o2) + r1, r2 = np.frexp(d, out=(o1, o2), subok=subok) + assert_(r1 is o1) + assert_(r2 is o2) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', DeprecationWarning) + r1, r2 = np.frexp(d, out=o1, subok=subok) + assert_(r1 is o1) + assert_(w[0].category is DeprecationWarning) + + assert_raises(ValueError, np.add, a, 2, o, o, subok=subok) + assert_raises(ValueError, np.add, a, 2, o, out=o, subok=subok) + assert_raises(ValueError, np.add, a, 2, None, out=o, subok=subok) + assert_raises(ValueError, np.add, a, 2, out=(o, o), subok=subok) + assert_raises(ValueError, np.add, a, 2, out=(), subok=subok) + assert_raises(TypeError, np.add, a, 2, [], subok=subok) + assert_raises(TypeError, np.add, a, 2, out=[], subok=subok) + assert_raises(TypeError, np.add, a, 2, out=([],), subok=subok) + o.flags.writeable = False + assert_raises(ValueError, np.add, a, 2, o, subok=subok) + assert_raises(ValueError, np.add, a, 2, out=o, subok=subok) + assert_raises(ValueError, np.add, a, 2, out=(o,), subok=subok) + + def test_out_wrap_subok(self): + class ArrayWrap(np.ndarray): + __array_priority__ = 10 + + def __new__(cls, arr): + return np.asarray(arr).view(cls).copy() + + def __array_wrap__(self, arr, context): + return arr.view(type(self)) + + for subok in (True, False): + a = ArrayWrap([0.5]) + + r = np.add(a, 2, subok=subok) + if subok: + assert_(isinstance(r, ArrayWrap)) + else: + assert_(type(r) == np.ndarray) + + r = np.add(a, 2, None, subok=subok) + if subok: + assert_(isinstance(r, ArrayWrap)) + else: + assert_(type(r) == np.ndarray) + + r = np.add(a, 2, out=None, subok=subok) + if subok: + assert_(isinstance(r, ArrayWrap)) + else: + assert_(type(r) == np.ndarray) + + r = np.add(a, 2, out=(None,), subok=subok) + if subok: + assert_(isinstance(r, ArrayWrap)) + else: + assert_(type(r) == np.ndarray) + + d = ArrayWrap([5.7]) + o1 = np.empty((1,)) + o2 = np.empty((1,), dtype=np.int32) + + r1, r2 = np.frexp(d, o1, subok=subok) + if subok: + assert_(isinstance(r2, ArrayWrap)) + else: + assert_(type(r2) == np.ndarray) + + r1, r2 = np.frexp(d, o1, None, subok=subok) + if subok: + assert_(isinstance(r2, ArrayWrap)) + else: + assert_(type(r2) == np.ndarray) + + r1, r2 = np.frexp(d, None, o2, subok=subok) + if subok: + assert_(isinstance(r1, ArrayWrap)) + else: + assert_(type(r1) == np.ndarray) + + r1, r2 = np.frexp(d, out=(o1, None), subok=subok) + if subok: + assert_(isinstance(r2, ArrayWrap)) + else: + assert_(type(r2) == np.ndarray) + + r1, r2 = np.frexp(d, out=(None, o2), subok=subok) + if subok: + assert_(isinstance(r1, ArrayWrap)) + else: + assert_(type(r1) == np.ndarray) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', DeprecationWarning) + r1, r2 = np.frexp(d, out=o1, subok=subok) + if subok: + assert_(isinstance(r2, ArrayWrap)) + else: + assert_(type(r2) == np.ndarray) + assert_(w[0].category is DeprecationWarning) + + +class TestComparisons(object): + def test_ignore_object_identity_in_equal(self): + # Check error raised when comparing identical objects whose comparison + # is not a simple boolean, e.g., arrays that are compared elementwise. + a = np.array([np.array([1, 2, 3]), None], dtype=object) + assert_raises(ValueError, np.equal, a, a) + + # Check error raised when comparing identical non-comparable objects. + class FunkyType(object): + def __eq__(self, other): + raise TypeError("I won't compare") + + a = np.array([FunkyType()]) + assert_raises(TypeError, np.equal, a, a) + + # Check identity doesn't override comparison mismatch. + a = np.array([np.nan], dtype=object) + assert_equal(np.equal(a, a), [False]) + + def test_ignore_object_identity_in_not_equal(self): + # Check error raised when comparing identical objects whose comparison + # is not a simple boolean, e.g., arrays that are compared elementwise. + a = np.array([np.array([1, 2, 3]), None], dtype=object) + assert_raises(ValueError, np.not_equal, a, a) + + # Check error raised when comparing identical non-comparable objects. + class FunkyType(object): + def __ne__(self, other): + raise TypeError("I won't compare") + + a = np.array([FunkyType()]) + assert_raises(TypeError, np.not_equal, a, a) + + # Check identity doesn't override comparison mismatch. + a = np.array([np.nan], dtype=object) + assert_equal(np.not_equal(a, a), [True]) + + +class TestAdd(object): + def test_reduce_alignment(self): + # gh-9876 + # make sure arrays with weird strides work with the optimizations in + # pairwise_sum_@TYPE@. On x86, the 'b' field will count as aligned at a + # 4 byte offset, even though its itemsize is 8. + a = np.zeros(2, dtype=[('a', np.int32), ('b', np.float64)]) + a['a'] = -1 + assert_equal(a['b'].sum(), 0) + + +class TestDivision(object): + def test_division_int(self): + # int division should follow Python + x = np.array([5, 10, 90, 100, -5, -10, -90, -100, -120]) + if 5 / 10 == 0.5: + assert_equal(x / 100, [0.05, 0.1, 0.9, 1, + -0.05, -0.1, -0.9, -1, -1.2]) + else: + assert_equal(x / 100, [0, 0, 0, 1, -1, -1, -1, -1, -2]) + assert_equal(x // 100, [0, 0, 0, 1, -1, -1, -1, -1, -2]) + assert_equal(x % 100, [5, 10, 90, 0, 95, 90, 10, 0, 80]) + + def test_division_complex(self): + # check that implementation is correct + msg = "Complex division implementation check" + x = np.array([1. + 1.*1j, 1. + .5*1j, 1. + 2.*1j], dtype=np.complex128) + assert_almost_equal(x**2/x, x, err_msg=msg) + # check overflow, underflow + msg = "Complex division overflow/underflow check" + x = np.array([1.e+110, 1.e-110], dtype=np.complex128) + y = x**2/x + assert_almost_equal(y/x, [1, 1], err_msg=msg) + + def test_zero_division_complex(self): + with np.errstate(invalid="ignore", divide="ignore"): + x = np.array([0.0], dtype=np.complex128) + y = 1.0/x + assert_(np.isinf(y)[0]) + y = complex(np.inf, np.nan)/x + assert_(np.isinf(y)[0]) + y = complex(np.nan, np.inf)/x + assert_(np.isinf(y)[0]) + y = complex(np.inf, np.inf)/x + assert_(np.isinf(y)[0]) + y = 0.0/x + assert_(np.isnan(y)[0]) + + def test_floor_division_complex(self): + # check that implementation is correct + msg = "Complex floor division implementation check" + x = np.array([.9 + 1j, -.1 + 1j, .9 + .5*1j, .9 + 2.*1j], dtype=np.complex128) + y = np.array([0., -1., 0., 0.], dtype=np.complex128) + assert_equal(np.floor_divide(x**2, x), y, err_msg=msg) + # check overflow, underflow + msg = "Complex floor division overflow/underflow check" + x = np.array([1.e+110, 1.e-110], dtype=np.complex128) + y = np.floor_divide(x**2, x) + assert_equal(y, [1.e+110, 0], err_msg=msg) + + +def floor_divide_and_remainder(x, y): + return (np.floor_divide(x, y), np.remainder(x, y)) + + +def _signs(dt): + if dt in np.typecodes['UnsignedInteger']: + return (+1,) + else: + return (+1, -1) + + +class TestRemainder(object): + + def test_remainder_basic(self): + dt = np.typecodes['AllInteger'] + np.typecodes['Float'] + for op in [floor_divide_and_remainder, np.divmod]: + for dt1, dt2 in itertools.product(dt, dt): + for sg1, sg2 in itertools.product(_signs(dt1), _signs(dt2)): + fmt = 'op: %s, dt1: %s, dt2: %s, sg1: %s, sg2: %s' + msg = fmt % (op.__name__, dt1, dt2, sg1, sg2) + a = np.array(sg1*71, dtype=dt1) + b = np.array(sg2*19, dtype=dt2) + div, rem = op(a, b) + assert_equal(div*b + rem, a, err_msg=msg) + if sg2 == -1: + assert_(b < rem <= 0, msg) + else: + assert_(b > rem >= 0, msg) + + def test_float_remainder_exact(self): + # test that float results are exact for small integers. This also + # holds for the same integers scaled by powers of two. + nlst = list(range(-127, 0)) + plst = list(range(1, 128)) + dividend = nlst + [0] + plst + divisor = nlst + plst + arg = list(itertools.product(dividend, divisor)) + tgt = list(divmod(*t) for t in arg) + + a, b = np.array(arg, dtype=int).T + # convert exact integer results from Python to float so that + # signed zero can be used, it is checked. + tgtdiv, tgtrem = np.array(tgt, dtype=float).T + tgtdiv = np.where((tgtdiv == 0.0) & ((b < 0) ^ (a < 0)), -0.0, tgtdiv) + tgtrem = np.where((tgtrem == 0.0) & (b < 0), -0.0, tgtrem) + + for op in [floor_divide_and_remainder, np.divmod]: + for dt in np.typecodes['Float']: + msg = 'op: %s, dtype: %s' % (op.__name__, dt) + fa = a.astype(dt) + fb = b.astype(dt) + div, rem = op(fa, fb) + assert_equal(div, tgtdiv, err_msg=msg) + assert_equal(rem, tgtrem, err_msg=msg) + + def test_float_remainder_roundoff(self): + # gh-6127 + dt = np.typecodes['Float'] + for op in [floor_divide_and_remainder, np.divmod]: + for dt1, dt2 in itertools.product(dt, dt): + for sg1, sg2 in itertools.product((+1, -1), (+1, -1)): + fmt = 'op: %s, dt1: %s, dt2: %s, sg1: %s, sg2: %s' + msg = fmt % (op.__name__, dt1, dt2, sg1, sg2) + a = np.array(sg1*78*6e-8, dtype=dt1) + b = np.array(sg2*6e-8, dtype=dt2) + div, rem = op(a, b) + # Equal assertion should hold when fmod is used + assert_equal(div*b + rem, a, err_msg=msg) + if sg2 == -1: + assert_(b < rem <= 0, msg) + else: + assert_(b > rem >= 0, msg) + + def test_float_remainder_corner_cases(self): + # Check remainder magnitude. + for dt in np.typecodes['Float']: + b = np.array(1.0, dtype=dt) + a = np.nextafter(np.array(0.0, dtype=dt), -b) + rem = np.remainder(a, b) + assert_(rem <= b, 'dt: %s' % dt) + rem = np.remainder(-a, -b) + assert_(rem >= -b, 'dt: %s' % dt) + + # Check nans, inf + with suppress_warnings() as sup: + sup.filter(RuntimeWarning, "invalid value encountered in remainder") + for dt in np.typecodes['Float']: + fone = np.array(1.0, dtype=dt) + fzer = np.array(0.0, dtype=dt) + finf = np.array(np.inf, dtype=dt) + fnan = np.array(np.nan, dtype=dt) + rem = np.remainder(fone, fzer) + assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem)) + # MSVC 2008 returns NaN here, so disable the check. + #rem = np.remainder(fone, finf) + #assert_(rem == fone, 'dt: %s, rem: %s' % (dt, rem)) + rem = np.remainder(fone, fnan) + assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem)) + rem = np.remainder(finf, fone) + assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem)) + + +class TestCbrt(object): + def test_cbrt_scalar(self): + assert_almost_equal((np.cbrt(np.float32(-2.5)**3)), -2.5) + + def test_cbrt(self): + x = np.array([1., 2., -3., np.inf, -np.inf]) + assert_almost_equal(np.cbrt(x**3), x) + + assert_(np.isnan(np.cbrt(np.nan))) + assert_equal(np.cbrt(np.inf), np.inf) + assert_equal(np.cbrt(-np.inf), -np.inf) + + +class TestPower(object): + def test_power_float(self): + x = np.array([1., 2., 3.]) + assert_equal(x**0, [1., 1., 1.]) + assert_equal(x**1, x) + assert_equal(x**2, [1., 4., 9.]) + y = x.copy() + y **= 2 + assert_equal(y, [1., 4., 9.]) + assert_almost_equal(x**(-1), [1., 0.5, 1./3]) + assert_almost_equal(x**(0.5), [1., ncu.sqrt(2), ncu.sqrt(3)]) + + for out, inp, msg in _gen_alignment_data(dtype=np.float32, + type='unary', + max_size=11): + exp = [ncu.sqrt(i) for i in inp] + assert_almost_equal(inp**(0.5), exp, err_msg=msg) + np.sqrt(inp, out=out) + assert_equal(out, exp, err_msg=msg) + + for out, inp, msg in _gen_alignment_data(dtype=np.float64, + type='unary', + max_size=7): + exp = [ncu.sqrt(i) for i in inp] + assert_almost_equal(inp**(0.5), exp, err_msg=msg) + np.sqrt(inp, out=out) + assert_equal(out, exp, err_msg=msg) + + def test_power_complex(self): + x = np.array([1+2j, 2+3j, 3+4j]) + assert_equal(x**0, [1., 1., 1.]) + assert_equal(x**1, x) + assert_almost_equal(x**2, [-3+4j, -5+12j, -7+24j]) + assert_almost_equal(x**3, [(1+2j)**3, (2+3j)**3, (3+4j)**3]) + assert_almost_equal(x**4, [(1+2j)**4, (2+3j)**4, (3+4j)**4]) + assert_almost_equal(x**(-1), [1/(1+2j), 1/(2+3j), 1/(3+4j)]) + assert_almost_equal(x**(-2), [1/(1+2j)**2, 1/(2+3j)**2, 1/(3+4j)**2]) + assert_almost_equal(x**(-3), [(-11+2j)/125, (-46-9j)/2197, + (-117-44j)/15625]) + assert_almost_equal(x**(0.5), [ncu.sqrt(1+2j), ncu.sqrt(2+3j), + ncu.sqrt(3+4j)]) + norm = 1./((x**14)[0]) + assert_almost_equal(x**14 * norm, + [i * norm for i in [-76443+16124j, 23161315+58317492j, + 5583548873 + 2465133864j]]) + + # Ticket #836 + def assert_complex_equal(x, y): + assert_array_equal(x.real, y.real) + assert_array_equal(x.imag, y.imag) + + for z in [complex(0, np.inf), complex(1, np.inf)]: + z = np.array([z], dtype=np.complex_) + with np.errstate(invalid="ignore"): + assert_complex_equal(z**1, z) + assert_complex_equal(z**2, z*z) + assert_complex_equal(z**3, z*z*z) + + def test_power_zero(self): + # ticket #1271 + zero = np.array([0j]) + one = np.array([1+0j]) + cnan = np.array([complex(np.nan, np.nan)]) + # FIXME cinf not tested. + #cinf = np.array([complex(np.inf, 0)]) + + def assert_complex_equal(x, y): + x, y = np.asarray(x), np.asarray(y) + assert_array_equal(x.real, y.real) + assert_array_equal(x.imag, y.imag) + + # positive powers + for p in [0.33, 0.5, 1, 1.5, 2, 3, 4, 5, 6.6]: + assert_complex_equal(np.power(zero, p), zero) + + # zero power + assert_complex_equal(np.power(zero, 0), one) + with np.errstate(invalid="ignore"): + assert_complex_equal(np.power(zero, 0+1j), cnan) + + # negative power + for p in [0.33, 0.5, 1, 1.5, 2, 3, 4, 5, 6.6]: + assert_complex_equal(np.power(zero, -p), cnan) + assert_complex_equal(np.power(zero, -1+0.2j), cnan) + + def test_fast_power(self): + x = np.array([1, 2, 3], np.int16) + res = x**2.0 + assert_((x**2.00001).dtype is res.dtype) + assert_array_equal(res, [1, 4, 9]) + # check the inplace operation on the casted copy doesn't mess with x + assert_(not np.may_share_memory(res, x)) + assert_array_equal(x, [1, 2, 3]) + + # Check that the fast path ignores 1-element not 0-d arrays + res = x ** np.array([[[2]]]) + assert_equal(res.shape, (1, 1, 3)) + + def test_integer_power(self): + a = np.array([15, 15], 'i8') + b = np.power(a, a) + assert_equal(b, [437893890380859375, 437893890380859375]) + + def test_integer_power_with_integer_zero_exponent(self): + dtypes = np.typecodes['Integer'] + for dt in dtypes: + arr = np.arange(-10, 10, dtype=dt) + assert_equal(np.power(arr, 0), np.ones_like(arr)) + + dtypes = np.typecodes['UnsignedInteger'] + for dt in dtypes: + arr = np.arange(10, dtype=dt) + assert_equal(np.power(arr, 0), np.ones_like(arr)) + + def test_integer_power_of_1(self): + dtypes = np.typecodes['AllInteger'] + for dt in dtypes: + arr = np.arange(10, dtype=dt) + assert_equal(np.power(1, arr), np.ones_like(arr)) + + def test_integer_power_of_zero(self): + dtypes = np.typecodes['AllInteger'] + for dt in dtypes: + arr = np.arange(1, 10, dtype=dt) + assert_equal(np.power(0, arr), np.zeros_like(arr)) + + def test_integer_to_negative_power(self): + dtypes = np.typecodes['Integer'] + for dt in dtypes: + a = np.array([0, 1, 2, 3], dtype=dt) + b = np.array([0, 1, 2, -3], dtype=dt) + one = np.array(1, dtype=dt) + minusone = np.array(-1, dtype=dt) + assert_raises(ValueError, np.power, a, b) + assert_raises(ValueError, np.power, a, minusone) + assert_raises(ValueError, np.power, one, b) + assert_raises(ValueError, np.power, one, minusone) + + +class TestFloat_power(object): + def test_type_conversion(self): + arg_type = '?bhilBHILefdgFDG' + res_type = 'ddddddddddddgDDG' + for dtin, dtout in zip(arg_type, res_type): + msg = "dtin: %s, dtout: %s" % (dtin, dtout) + arg = np.ones(1, dtype=dtin) + res = np.float_power(arg, arg) + assert_(res.dtype.name == np.dtype(dtout).name, msg) + + +class TestLog2(object): + def test_log2_values(self): + x = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + y = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + for dt in ['f', 'd', 'g']: + xf = np.array(x, dtype=dt) + yf = np.array(y, dtype=dt) + assert_almost_equal(np.log2(xf), yf) + + def test_log2_ints(self): + # a good log2 implementation should provide this, + # might fail on OS with bad libm + for i in range(1, 65): + v = np.log2(2.**i) + assert_equal(v, float(i), err_msg='at exponent %d' % i) + + def test_log2_special(self): + assert_equal(np.log2(1.), 0.) + assert_equal(np.log2(np.inf), np.inf) + assert_(np.isnan(np.log2(np.nan))) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_(np.isnan(np.log2(-1.))) + assert_(np.isnan(np.log2(-np.inf))) + assert_equal(np.log2(0.), -np.inf) + assert_(w[0].category is RuntimeWarning) + assert_(w[1].category is RuntimeWarning) + assert_(w[2].category is RuntimeWarning) + + +class TestExp2(object): + def test_exp2_values(self): + x = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + y = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + for dt in ['f', 'd', 'g']: + xf = np.array(x, dtype=dt) + yf = np.array(y, dtype=dt) + assert_almost_equal(np.exp2(yf), xf) + + +class TestLogAddExp2(_FilterInvalids): + # Need test for intermediate precisions + def test_logaddexp2_values(self): + x = [1, 2, 3, 4, 5] + y = [5, 4, 3, 2, 1] + z = [6, 6, 6, 6, 6] + for dt, dec_ in zip(['f', 'd', 'g'], [6, 15, 15]): + xf = np.log2(np.array(x, dtype=dt)) + yf = np.log2(np.array(y, dtype=dt)) + zf = np.log2(np.array(z, dtype=dt)) + assert_almost_equal(np.logaddexp2(xf, yf), zf, decimal=dec_) + + def test_logaddexp2_range(self): + x = [1000000, -1000000, 1000200, -1000200] + y = [1000200, -1000200, 1000000, -1000000] + z = [1000200, -1000000, 1000200, -1000000] + for dt in ['f', 'd', 'g']: + logxf = np.array(x, dtype=dt) + logyf = np.array(y, dtype=dt) + logzf = np.array(z, dtype=dt) + assert_almost_equal(np.logaddexp2(logxf, logyf), logzf) + + def test_inf(self): + inf = np.inf + x = [inf, -inf, inf, -inf, inf, 1, -inf, 1] + y = [inf, inf, -inf, -inf, 1, inf, 1, -inf] + z = [inf, inf, inf, -inf, inf, inf, 1, 1] + with np.errstate(invalid='raise'): + for dt in ['f', 'd', 'g']: + logxf = np.array(x, dtype=dt) + logyf = np.array(y, dtype=dt) + logzf = np.array(z, dtype=dt) + assert_equal(np.logaddexp2(logxf, logyf), logzf) + + def test_nan(self): + assert_(np.isnan(np.logaddexp2(np.nan, np.inf))) + assert_(np.isnan(np.logaddexp2(np.inf, np.nan))) + assert_(np.isnan(np.logaddexp2(np.nan, 0))) + assert_(np.isnan(np.logaddexp2(0, np.nan))) + assert_(np.isnan(np.logaddexp2(np.nan, np.nan))) + + +class TestLog(object): + def test_log_values(self): + x = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + y = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + for dt in ['f', 'd', 'g']: + log2_ = 0.69314718055994530943 + xf = np.array(x, dtype=dt) + yf = np.array(y, dtype=dt)*log2_ + assert_almost_equal(np.log(xf), yf) + + +class TestExp(object): + def test_exp_values(self): + x = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + y = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + for dt in ['f', 'd', 'g']: + log2_ = 0.69314718055994530943 + xf = np.array(x, dtype=dt) + yf = np.array(y, dtype=dt)*log2_ + assert_almost_equal(np.exp(yf), xf) + + +class TestLogAddExp(_FilterInvalids): + def test_logaddexp_values(self): + x = [1, 2, 3, 4, 5] + y = [5, 4, 3, 2, 1] + z = [6, 6, 6, 6, 6] + for dt, dec_ in zip(['f', 'd', 'g'], [6, 15, 15]): + xf = np.log(np.array(x, dtype=dt)) + yf = np.log(np.array(y, dtype=dt)) + zf = np.log(np.array(z, dtype=dt)) + assert_almost_equal(np.logaddexp(xf, yf), zf, decimal=dec_) + + def test_logaddexp_range(self): + x = [1000000, -1000000, 1000200, -1000200] + y = [1000200, -1000200, 1000000, -1000000] + z = [1000200, -1000000, 1000200, -1000000] + for dt in ['f', 'd', 'g']: + logxf = np.array(x, dtype=dt) + logyf = np.array(y, dtype=dt) + logzf = np.array(z, dtype=dt) + assert_almost_equal(np.logaddexp(logxf, logyf), logzf) + + def test_inf(self): + inf = np.inf + x = [inf, -inf, inf, -inf, inf, 1, -inf, 1] + y = [inf, inf, -inf, -inf, 1, inf, 1, -inf] + z = [inf, inf, inf, -inf, inf, inf, 1, 1] + with np.errstate(invalid='raise'): + for dt in ['f', 'd', 'g']: + logxf = np.array(x, dtype=dt) + logyf = np.array(y, dtype=dt) + logzf = np.array(z, dtype=dt) + assert_equal(np.logaddexp(logxf, logyf), logzf) + + def test_nan(self): + assert_(np.isnan(np.logaddexp(np.nan, np.inf))) + assert_(np.isnan(np.logaddexp(np.inf, np.nan))) + assert_(np.isnan(np.logaddexp(np.nan, 0))) + assert_(np.isnan(np.logaddexp(0, np.nan))) + assert_(np.isnan(np.logaddexp(np.nan, np.nan))) + + +class TestLog1p(object): + def test_log1p(self): + assert_almost_equal(ncu.log1p(0.2), ncu.log(1.2)) + assert_almost_equal(ncu.log1p(1e-6), ncu.log(1+1e-6)) + + def test_special(self): + with np.errstate(invalid="ignore", divide="ignore"): + assert_equal(ncu.log1p(np.nan), np.nan) + assert_equal(ncu.log1p(np.inf), np.inf) + assert_equal(ncu.log1p(-1.), -np.inf) + assert_equal(ncu.log1p(-2.), np.nan) + assert_equal(ncu.log1p(-np.inf), np.nan) + + +class TestExpm1(object): + def test_expm1(self): + assert_almost_equal(ncu.expm1(0.2), ncu.exp(0.2)-1) + assert_almost_equal(ncu.expm1(1e-6), ncu.exp(1e-6)-1) + + def test_special(self): + assert_equal(ncu.expm1(np.inf), np.inf) + assert_equal(ncu.expm1(0.), 0.) + assert_equal(ncu.expm1(-0.), -0.) + assert_equal(ncu.expm1(np.inf), np.inf) + assert_equal(ncu.expm1(-np.inf), -1.) + + +class TestHypot(object): + def test_simple(self): + assert_almost_equal(ncu.hypot(1, 1), ncu.sqrt(2)) + assert_almost_equal(ncu.hypot(0, 0), 0) + + def test_reduce(self): + assert_almost_equal(ncu.hypot.reduce([3.0, 4.0]), 5.0) + assert_almost_equal(ncu.hypot.reduce([3.0, 4.0, 0]), 5.0) + assert_almost_equal(ncu.hypot.reduce([9.0, 12.0, 20.0]), 25.0) + assert_equal(ncu.hypot.reduce([]), 0.0) + + +def assert_hypot_isnan(x, y): + with np.errstate(invalid='ignore'): + assert_(np.isnan(ncu.hypot(x, y)), + "hypot(%s, %s) is %s, not nan" % (x, y, ncu.hypot(x, y))) + + +def assert_hypot_isinf(x, y): + with np.errstate(invalid='ignore'): + assert_(np.isinf(ncu.hypot(x, y)), + "hypot(%s, %s) is %s, not inf" % (x, y, ncu.hypot(x, y))) + + +class TestHypotSpecialValues(object): + def test_nan_outputs(self): + assert_hypot_isnan(np.nan, np.nan) + assert_hypot_isnan(np.nan, 1) + + def test_nan_outputs2(self): + assert_hypot_isinf(np.nan, np.inf) + assert_hypot_isinf(np.inf, np.nan) + assert_hypot_isinf(np.inf, 0) + assert_hypot_isinf(0, np.inf) + assert_hypot_isinf(np.inf, np.inf) + assert_hypot_isinf(np.inf, 23.0) + + def test_no_fpe(self): + assert_no_warnings(ncu.hypot, np.inf, 0) + + +def assert_arctan2_isnan(x, y): + assert_(np.isnan(ncu.arctan2(x, y)), "arctan(%s, %s) is %s, not nan" % (x, y, ncu.arctan2(x, y))) + + +def assert_arctan2_ispinf(x, y): + assert_((np.isinf(ncu.arctan2(x, y)) and ncu.arctan2(x, y) > 0), "arctan(%s, %s) is %s, not +inf" % (x, y, ncu.arctan2(x, y))) + + +def assert_arctan2_isninf(x, y): + assert_((np.isinf(ncu.arctan2(x, y)) and ncu.arctan2(x, y) < 0), "arctan(%s, %s) is %s, not -inf" % (x, y, ncu.arctan2(x, y))) + + +def assert_arctan2_ispzero(x, y): + assert_((ncu.arctan2(x, y) == 0 and not np.signbit(ncu.arctan2(x, y))), "arctan(%s, %s) is %s, not +0" % (x, y, ncu.arctan2(x, y))) + + +def assert_arctan2_isnzero(x, y): + assert_((ncu.arctan2(x, y) == 0 and np.signbit(ncu.arctan2(x, y))), "arctan(%s, %s) is %s, not -0" % (x, y, ncu.arctan2(x, y))) + + +class TestArctan2SpecialValues(object): + def test_one_one(self): + # atan2(1, 1) returns pi/4. + assert_almost_equal(ncu.arctan2(1, 1), 0.25 * np.pi) + assert_almost_equal(ncu.arctan2(-1, 1), -0.25 * np.pi) + assert_almost_equal(ncu.arctan2(1, -1), 0.75 * np.pi) + + def test_zero_nzero(self): + # atan2(+-0, -0) returns +-pi. + assert_almost_equal(ncu.arctan2(np.PZERO, np.NZERO), np.pi) + assert_almost_equal(ncu.arctan2(np.NZERO, np.NZERO), -np.pi) + + def test_zero_pzero(self): + # atan2(+-0, +0) returns +-0. + assert_arctan2_ispzero(np.PZERO, np.PZERO) + assert_arctan2_isnzero(np.NZERO, np.PZERO) + + def test_zero_negative(self): + # atan2(+-0, x) returns +-pi for x < 0. + assert_almost_equal(ncu.arctan2(np.PZERO, -1), np.pi) + assert_almost_equal(ncu.arctan2(np.NZERO, -1), -np.pi) + + def test_zero_positive(self): + # atan2(+-0, x) returns +-0 for x > 0. + assert_arctan2_ispzero(np.PZERO, 1) + assert_arctan2_isnzero(np.NZERO, 1) + + def test_positive_zero(self): + # atan2(y, +-0) returns +pi/2 for y > 0. + assert_almost_equal(ncu.arctan2(1, np.PZERO), 0.5 * np.pi) + assert_almost_equal(ncu.arctan2(1, np.NZERO), 0.5 * np.pi) + + def test_negative_zero(self): + # atan2(y, +-0) returns -pi/2 for y < 0. + assert_almost_equal(ncu.arctan2(-1, np.PZERO), -0.5 * np.pi) + assert_almost_equal(ncu.arctan2(-1, np.NZERO), -0.5 * np.pi) + + def test_any_ninf(self): + # atan2(+-y, -infinity) returns +-pi for finite y > 0. + assert_almost_equal(ncu.arctan2(1, np.NINF), np.pi) + assert_almost_equal(ncu.arctan2(-1, np.NINF), -np.pi) + + def test_any_pinf(self): + # atan2(+-y, +infinity) returns +-0 for finite y > 0. + assert_arctan2_ispzero(1, np.inf) + assert_arctan2_isnzero(-1, np.inf) + + def test_inf_any(self): + # atan2(+-infinity, x) returns +-pi/2 for finite x. + assert_almost_equal(ncu.arctan2( np.inf, 1), 0.5 * np.pi) + assert_almost_equal(ncu.arctan2(-np.inf, 1), -0.5 * np.pi) + + def test_inf_ninf(self): + # atan2(+-infinity, -infinity) returns +-3*pi/4. + assert_almost_equal(ncu.arctan2( np.inf, -np.inf), 0.75 * np.pi) + assert_almost_equal(ncu.arctan2(-np.inf, -np.inf), -0.75 * np.pi) + + def test_inf_pinf(self): + # atan2(+-infinity, +infinity) returns +-pi/4. + assert_almost_equal(ncu.arctan2( np.inf, np.inf), 0.25 * np.pi) + assert_almost_equal(ncu.arctan2(-np.inf, np.inf), -0.25 * np.pi) + + def test_nan_any(self): + # atan2(nan, x) returns nan for any x, including inf + assert_arctan2_isnan(np.nan, np.inf) + assert_arctan2_isnan(np.inf, np.nan) + assert_arctan2_isnan(np.nan, np.nan) + + +class TestLdexp(object): + def _check_ldexp(self, tp): + assert_almost_equal(ncu.ldexp(np.array(2., np.float32), + np.array(3, tp)), 16.) + assert_almost_equal(ncu.ldexp(np.array(2., np.float64), + np.array(3, tp)), 16.) + assert_almost_equal(ncu.ldexp(np.array(2., np.longdouble), + np.array(3, tp)), 16.) + + def test_ldexp(self): + # The default Python int type should work + assert_almost_equal(ncu.ldexp(2., 3), 16.) + # The following int types should all be accepted + self._check_ldexp(np.int8) + self._check_ldexp(np.int16) + self._check_ldexp(np.int32) + self._check_ldexp('i') + self._check_ldexp('l') + + def test_ldexp_overflow(self): + # silence warning emitted on overflow + with np.errstate(over="ignore"): + imax = np.iinfo(np.dtype('l')).max + imin = np.iinfo(np.dtype('l')).min + assert_equal(ncu.ldexp(2., imax), np.inf) + assert_equal(ncu.ldexp(2., imin), 0) + + +class TestMaximum(_FilterInvalids): + def test_reduce(self): + dflt = np.typecodes['AllFloat'] + dint = np.typecodes['AllInteger'] + seq1 = np.arange(11) + seq2 = seq1[::-1] + func = np.maximum.reduce + for dt in dint: + tmp1 = seq1.astype(dt) + tmp2 = seq2.astype(dt) + assert_equal(func(tmp1), 10) + assert_equal(func(tmp2), 10) + for dt in dflt: + tmp1 = seq1.astype(dt) + tmp2 = seq2.astype(dt) + assert_equal(func(tmp1), 10) + assert_equal(func(tmp2), 10) + tmp1[::2] = np.nan + tmp2[::2] = np.nan + assert_equal(func(tmp1), np.nan) + assert_equal(func(tmp2), np.nan) + + def test_reduce_complex(self): + assert_equal(np.maximum.reduce([1, 2j]), 1) + assert_equal(np.maximum.reduce([1+3j, 2j]), 1+3j) + + def test_float_nans(self): + nan = np.nan + arg1 = np.array([0, nan, nan]) + arg2 = np.array([nan, 0, nan]) + out = np.array([nan, nan, nan]) + assert_equal(np.maximum(arg1, arg2), out) + + def test_object_nans(self): + # Multiple checks to give this a chance to + # fail if cmp is used instead of rich compare. + # Failure cannot be guaranteed. + for i in range(1): + x = np.array(float('nan'), object) + y = 1.0 + z = np.array(float('nan'), object) + assert_(np.maximum(x, y) == 1.0) + assert_(np.maximum(z, y) == 1.0) + + def test_complex_nans(self): + nan = np.nan + for cnan in [complex(nan, 0), complex(0, nan), complex(nan, nan)]: + arg1 = np.array([0, cnan, cnan], dtype=complex) + arg2 = np.array([cnan, 0, cnan], dtype=complex) + out = np.array([nan, nan, nan], dtype=complex) + assert_equal(np.maximum(arg1, arg2), out) + + def test_object_array(self): + arg1 = np.arange(5, dtype=object) + arg2 = arg1 + 1 + assert_equal(np.maximum(arg1, arg2), arg2) + + +class TestMinimum(_FilterInvalids): + def test_reduce(self): + dflt = np.typecodes['AllFloat'] + dint = np.typecodes['AllInteger'] + seq1 = np.arange(11) + seq2 = seq1[::-1] + func = np.minimum.reduce + for dt in dint: + tmp1 = seq1.astype(dt) + tmp2 = seq2.astype(dt) + assert_equal(func(tmp1), 0) + assert_equal(func(tmp2), 0) + for dt in dflt: + tmp1 = seq1.astype(dt) + tmp2 = seq2.astype(dt) + assert_equal(func(tmp1), 0) + assert_equal(func(tmp2), 0) + tmp1[::2] = np.nan + tmp2[::2] = np.nan + assert_equal(func(tmp1), np.nan) + assert_equal(func(tmp2), np.nan) + + def test_reduce_complex(self): + assert_equal(np.minimum.reduce([1, 2j]), 2j) + assert_equal(np.minimum.reduce([1+3j, 2j]), 2j) + + def test_float_nans(self): + nan = np.nan + arg1 = np.array([0, nan, nan]) + arg2 = np.array([nan, 0, nan]) + out = np.array([nan, nan, nan]) + assert_equal(np.minimum(arg1, arg2), out) + + def test_object_nans(self): + # Multiple checks to give this a chance to + # fail if cmp is used instead of rich compare. + # Failure cannot be guaranteed. + for i in range(1): + x = np.array(float('nan'), object) + y = 1.0 + z = np.array(float('nan'), object) + assert_(np.minimum(x, y) == 1.0) + assert_(np.minimum(z, y) == 1.0) + + def test_complex_nans(self): + nan = np.nan + for cnan in [complex(nan, 0), complex(0, nan), complex(nan, nan)]: + arg1 = np.array([0, cnan, cnan], dtype=complex) + arg2 = np.array([cnan, 0, cnan], dtype=complex) + out = np.array([nan, nan, nan], dtype=complex) + assert_equal(np.minimum(arg1, arg2), out) + + def test_object_array(self): + arg1 = np.arange(5, dtype=object) + arg2 = arg1 + 1 + assert_equal(np.minimum(arg1, arg2), arg1) + + +class TestFmax(_FilterInvalids): + def test_reduce(self): + dflt = np.typecodes['AllFloat'] + dint = np.typecodes['AllInteger'] + seq1 = np.arange(11) + seq2 = seq1[::-1] + func = np.fmax.reduce + for dt in dint: + tmp1 = seq1.astype(dt) + tmp2 = seq2.astype(dt) + assert_equal(func(tmp1), 10) + assert_equal(func(tmp2), 10) + for dt in dflt: + tmp1 = seq1.astype(dt) + tmp2 = seq2.astype(dt) + assert_equal(func(tmp1), 10) + assert_equal(func(tmp2), 10) + tmp1[::2] = np.nan + tmp2[::2] = np.nan + assert_equal(func(tmp1), 9) + assert_equal(func(tmp2), 9) + + def test_reduce_complex(self): + assert_equal(np.fmax.reduce([1, 2j]), 1) + assert_equal(np.fmax.reduce([1+3j, 2j]), 1+3j) + + def test_float_nans(self): + nan = np.nan + arg1 = np.array([0, nan, nan]) + arg2 = np.array([nan, 0, nan]) + out = np.array([0, 0, nan]) + assert_equal(np.fmax(arg1, arg2), out) + + def test_complex_nans(self): + nan = np.nan + for cnan in [complex(nan, 0), complex(0, nan), complex(nan, nan)]: + arg1 = np.array([0, cnan, cnan], dtype=complex) + arg2 = np.array([cnan, 0, cnan], dtype=complex) + out = np.array([0, 0, nan], dtype=complex) + assert_equal(np.fmax(arg1, arg2), out) + + +class TestFmin(_FilterInvalids): + def test_reduce(self): + dflt = np.typecodes['AllFloat'] + dint = np.typecodes['AllInteger'] + seq1 = np.arange(11) + seq2 = seq1[::-1] + func = np.fmin.reduce + for dt in dint: + tmp1 = seq1.astype(dt) + tmp2 = seq2.astype(dt) + assert_equal(func(tmp1), 0) + assert_equal(func(tmp2), 0) + for dt in dflt: + tmp1 = seq1.astype(dt) + tmp2 = seq2.astype(dt) + assert_equal(func(tmp1), 0) + assert_equal(func(tmp2), 0) + tmp1[::2] = np.nan + tmp2[::2] = np.nan + assert_equal(func(tmp1), 1) + assert_equal(func(tmp2), 1) + + def test_reduce_complex(self): + assert_equal(np.fmin.reduce([1, 2j]), 2j) + assert_equal(np.fmin.reduce([1+3j, 2j]), 2j) + + def test_float_nans(self): + nan = np.nan + arg1 = np.array([0, nan, nan]) + arg2 = np.array([nan, 0, nan]) + out = np.array([0, 0, nan]) + assert_equal(np.fmin(arg1, arg2), out) + + def test_complex_nans(self): + nan = np.nan + for cnan in [complex(nan, 0), complex(0, nan), complex(nan, nan)]: + arg1 = np.array([0, cnan, cnan], dtype=complex) + arg2 = np.array([cnan, 0, cnan], dtype=complex) + out = np.array([0, 0, nan], dtype=complex) + assert_equal(np.fmin(arg1, arg2), out) + + +class TestBool(object): + def test_exceptions(self): + a = np.ones(1, dtype=np.bool_) + assert_raises(TypeError, np.negative, a) + assert_raises(TypeError, np.positive, a) + assert_raises(TypeError, np.subtract, a, a) + + def test_truth_table_logical(self): + # 2, 3 and 4 serves as true values + input1 = [0, 0, 3, 2] + input2 = [0, 4, 0, 2] + + typecodes = (np.typecodes['AllFloat'] + + np.typecodes['AllInteger'] + + '?') # boolean + for dtype in map(np.dtype, typecodes): + arg1 = np.asarray(input1, dtype=dtype) + arg2 = np.asarray(input2, dtype=dtype) + + # OR + out = [False, True, True, True] + for func in (np.logical_or, np.maximum): + assert_equal(func(arg1, arg2).astype(bool), out) + # AND + out = [False, False, False, True] + for func in (np.logical_and, np.minimum): + assert_equal(func(arg1, arg2).astype(bool), out) + # XOR + out = [False, True, True, False] + for func in (np.logical_xor, np.not_equal): + assert_equal(func(arg1, arg2).astype(bool), out) + + def test_truth_table_bitwise(self): + arg1 = [False, False, True, True] + arg2 = [False, True, False, True] + + out = [False, True, True, True] + assert_equal(np.bitwise_or(arg1, arg2), out) + + out = [False, False, False, True] + assert_equal(np.bitwise_and(arg1, arg2), out) + + out = [False, True, True, False] + assert_equal(np.bitwise_xor(arg1, arg2), out) + + def test_reduce(self): + none = np.array([0, 0, 0, 0], bool) + some = np.array([1, 0, 1, 1], bool) + every = np.array([1, 1, 1, 1], bool) + empty = np.array([], bool) + + arrs = [none, some, every, empty] + + for arr in arrs: + assert_equal(np.logical_and.reduce(arr), all(arr)) + + for arr in arrs: + assert_equal(np.logical_or.reduce(arr), any(arr)) + + for arr in arrs: + assert_equal(np.logical_xor.reduce(arr), arr.sum() % 2 == 1) + + +class TestBitwiseUFuncs(object): + + bitwise_types = [np.dtype(c) for c in '?' + 'bBhHiIlLqQ' + 'O'] + + def test_values(self): + for dt in self.bitwise_types: + zeros = np.array([0], dtype=dt) + ones = np.array([-1], dtype=dt) + msg = "dt = '%s'" % dt.char + + assert_equal(np.bitwise_not(zeros), ones, err_msg=msg) + assert_equal(np.bitwise_not(ones), zeros, err_msg=msg) + + assert_equal(np.bitwise_or(zeros, zeros), zeros, err_msg=msg) + assert_equal(np.bitwise_or(zeros, ones), ones, err_msg=msg) + assert_equal(np.bitwise_or(ones, zeros), ones, err_msg=msg) + assert_equal(np.bitwise_or(ones, ones), ones, err_msg=msg) + + assert_equal(np.bitwise_xor(zeros, zeros), zeros, err_msg=msg) + assert_equal(np.bitwise_xor(zeros, ones), ones, err_msg=msg) + assert_equal(np.bitwise_xor(ones, zeros), ones, err_msg=msg) + assert_equal(np.bitwise_xor(ones, ones), zeros, err_msg=msg) + + assert_equal(np.bitwise_and(zeros, zeros), zeros, err_msg=msg) + assert_equal(np.bitwise_and(zeros, ones), zeros, err_msg=msg) + assert_equal(np.bitwise_and(ones, zeros), zeros, err_msg=msg) + assert_equal(np.bitwise_and(ones, ones), ones, err_msg=msg) + + def test_types(self): + for dt in self.bitwise_types: + zeros = np.array([0], dtype=dt) + ones = np.array([-1], dtype=dt) + msg = "dt = '%s'" % dt.char + + assert_(np.bitwise_not(zeros).dtype == dt, msg) + assert_(np.bitwise_or(zeros, zeros).dtype == dt, msg) + assert_(np.bitwise_xor(zeros, zeros).dtype == dt, msg) + assert_(np.bitwise_and(zeros, zeros).dtype == dt, msg) + + + def test_identity(self): + assert_(np.bitwise_or.identity == 0, 'bitwise_or') + assert_(np.bitwise_xor.identity == 0, 'bitwise_xor') + assert_(np.bitwise_and.identity == -1, 'bitwise_and') + + def test_reduction(self): + binary_funcs = (np.bitwise_or, np.bitwise_xor, np.bitwise_and) + + for dt in self.bitwise_types: + zeros = np.array([0], dtype=dt) + ones = np.array([-1], dtype=dt) + for f in binary_funcs: + msg = "dt: '%s', f: '%s'" % (dt, f) + assert_equal(f.reduce(zeros), zeros, err_msg=msg) + assert_equal(f.reduce(ones), ones, err_msg=msg) + + # Test empty reduction, no object dtype + for dt in self.bitwise_types[:-1]: + # No object array types + empty = np.array([], dtype=dt) + for f in binary_funcs: + msg = "dt: '%s', f: '%s'" % (dt, f) + tgt = np.array(f.identity, dtype=dt) + res = f.reduce(empty) + assert_equal(res, tgt, err_msg=msg) + assert_(res.dtype == tgt.dtype, msg) + + # Empty object arrays use the identity. Note that the types may + # differ, the actual type used is determined by the assign_identity + # function and is not the same as the type returned by the identity + # method. + for f in binary_funcs: + msg = "dt: '%s'" % (f,) + empty = np.array([], dtype=object) + tgt = f.identity + res = f.reduce(empty) + assert_equal(res, tgt, err_msg=msg) + + # Non-empty object arrays do not use the identity + for f in binary_funcs: + msg = "dt: '%s'" % (f,) + btype = np.array([True], dtype=object) + assert_(type(f.reduce(btype)) is bool, msg) + + +class TestInt(object): + def test_logical_not(self): + x = np.ones(10, dtype=np.int16) + o = np.ones(10 * 2, dtype=bool) + tgt = o.copy() + tgt[::2] = False + os = o[::2] + assert_array_equal(np.logical_not(x, out=os), False) + assert_array_equal(o, tgt) + + +class TestFloatingPoint(object): + def test_floating_point(self): + assert_equal(ncu.FLOATING_POINT_SUPPORT, 1) + + +class TestDegrees(object): + def test_degrees(self): + assert_almost_equal(ncu.degrees(np.pi), 180.0) + assert_almost_equal(ncu.degrees(-0.5*np.pi), -90.0) + + +class TestRadians(object): + def test_radians(self): + assert_almost_equal(ncu.radians(180.0), np.pi) + assert_almost_equal(ncu.radians(-90.0), -0.5*np.pi) + + +class TestHeavside(object): + def test_heaviside(self): + x = np.array([[-30.0, -0.1, 0.0, 0.2], [7.5, np.nan, np.inf, -np.inf]]) + expectedhalf = np.array([[0.0, 0.0, 0.5, 1.0], [1.0, np.nan, 1.0, 0.0]]) + expected1 = expectedhalf.copy() + expected1[0, 2] = 1 + + h = ncu.heaviside(x, 0.5) + assert_equal(h, expectedhalf) + + h = ncu.heaviside(x, 1.0) + assert_equal(h, expected1) + + x = x.astype(np.float32) + + h = ncu.heaviside(x, np.float32(0.5)) + assert_equal(h, expectedhalf.astype(np.float32)) + + h = ncu.heaviside(x, np.float32(1.0)) + assert_equal(h, expected1.astype(np.float32)) + + +class TestSign(object): + def test_sign(self): + a = np.array([np.inf, -np.inf, np.nan, 0.0, 3.0, -3.0]) + out = np.zeros(a.shape) + tgt = np.array([1., -1., np.nan, 0.0, 1.0, -1.0]) + + with np.errstate(invalid='ignore'): + res = ncu.sign(a) + assert_equal(res, tgt) + res = ncu.sign(a, out) + assert_equal(res, tgt) + assert_equal(out, tgt) + + def test_sign_dtype_object(self): + # In reference to github issue #6229 + + foo = np.array([-.1, 0, .1]) + a = np.sign(foo.astype(object)) + b = np.sign(foo) + + assert_array_equal(a, b) + + def test_sign_dtype_nan_object(self): + # In reference to github issue #6229 + def test_nan(): + foo = np.array([np.nan]) + a = np.sign(foo.astype(object)) + + assert_raises(TypeError, test_nan) + +class TestMinMax(object): + def test_minmax_blocked(self): + # simd tests on max/min, test all alignments, slow but important + # for 2 * vz + 2 * (vs - 1) + 1 (unrolled once) + for dt, sz in [(np.float32, 15), (np.float64, 7)]: + for out, inp, msg in _gen_alignment_data(dtype=dt, type='unary', + max_size=sz): + for i in range(inp.size): + inp[:] = np.arange(inp.size, dtype=dt) + inp[i] = np.nan + emsg = lambda: '%r\n%s' % (inp, msg) + with suppress_warnings() as sup: + sup.filter(RuntimeWarning, + "invalid value encountered in reduce") + assert_(np.isnan(inp.max()), msg=emsg) + assert_(np.isnan(inp.min()), msg=emsg) + + inp[i] = 1e10 + assert_equal(inp.max(), 1e10, err_msg=msg) + inp[i] = -1e10 + assert_equal(inp.min(), -1e10, err_msg=msg) + + def test_lower_align(self): + # check data that is not aligned to element size + # i.e doubles are aligned to 4 bytes on i386 + d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64) + assert_equal(d.max(), d[0]) + assert_equal(d.min(), d[0]) + + +class TestAbsoluteNegative(object): + def test_abs_neg_blocked(self): + # simd tests on abs, test all alignments for vz + 2 * (vs - 1) + 1 + for dt, sz in [(np.float32, 11), (np.float64, 5)]: + for out, inp, msg in _gen_alignment_data(dtype=dt, type='unary', + max_size=sz): + tgt = [ncu.absolute(i) for i in inp] + np.absolute(inp, out=out) + assert_equal(out, tgt, err_msg=msg) + assert_((out >= 0).all()) + + tgt = [-1*(i) for i in inp] + np.negative(inp, out=out) + assert_equal(out, tgt, err_msg=msg) + + for v in [np.nan, -np.inf, np.inf]: + for i in range(inp.size): + d = np.arange(inp.size, dtype=dt) + inp[:] = -d + inp[i] = v + d[i] = -v if v == -np.inf else v + assert_array_equal(np.abs(inp), d, err_msg=msg) + np.abs(inp, out=out) + assert_array_equal(out, d, err_msg=msg) + + assert_array_equal(-inp, -1*inp, err_msg=msg) + d = -1 * inp + np.negative(inp, out=out) + assert_array_equal(out, d, err_msg=msg) + + def test_lower_align(self): + # check data that is not aligned to element size + # i.e doubles are aligned to 4 bytes on i386 + d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64) + assert_equal(np.abs(d), d) + assert_equal(np.negative(d), -d) + np.negative(d, out=d) + np.negative(np.ones_like(d), out=d) + np.abs(d, out=d) + np.abs(np.ones_like(d), out=d) + + +class TestPositive(object): + def test_valid(self): + valid_dtypes = [int, float, complex, object] + for dtype in valid_dtypes: + x = np.arange(5, dtype=dtype) + result = np.positive(x) + assert_equal(x, result, err_msg=str(dtype)) + + def test_invalid(self): + with assert_raises(TypeError): + np.positive(True) + with assert_raises(TypeError): + np.positive(np.datetime64('2000-01-01')) + with assert_raises(TypeError): + np.positive(np.array(['foo'], dtype=str)) + with assert_raises(TypeError): + np.positive(np.array(['bar'], dtype=object)) + + +class TestSpecialMethods(object): + def test_wrap(self): + + class with_wrap(object): + def __array__(self): + return np.zeros(1) + + def __array_wrap__(self, arr, context): + r = with_wrap() + r.arr = arr + r.context = context + return r + + a = with_wrap() + x = ncu.minimum(a, a) + assert_equal(x.arr, np.zeros(1)) + func, args, i = x.context + assert_(func is ncu.minimum) + assert_equal(len(args), 2) + assert_equal(args[0], a) + assert_equal(args[1], a) + assert_equal(i, 0) + + def test_wrap_with_iterable(self): + # test fix for bug #1026: + + class with_wrap(np.ndarray): + __array_priority__ = 10 + + def __new__(cls): + return np.asarray(1).view(cls).copy() + + def __array_wrap__(self, arr, context): + return arr.view(type(self)) + + a = with_wrap() + x = ncu.multiply(a, (1, 2, 3)) + assert_(isinstance(x, with_wrap)) + assert_array_equal(x, np.array((1, 2, 3))) + + def test_priority_with_scalar(self): + # test fix for bug #826: + + class A(np.ndarray): + __array_priority__ = 10 + + def __new__(cls): + return np.asarray(1.0, 'float64').view(cls).copy() + + a = A() + x = np.float64(1)*a + assert_(isinstance(x, A)) + assert_array_equal(x, np.array(1)) + + def test_old_wrap(self): + + class with_wrap(object): + def __array__(self): + return np.zeros(1) + + def __array_wrap__(self, arr): + r = with_wrap() + r.arr = arr + return r + + a = with_wrap() + x = ncu.minimum(a, a) + assert_equal(x.arr, np.zeros(1)) + + def test_priority(self): + + class A(object): + def __array__(self): + return np.zeros(1) + + def __array_wrap__(self, arr, context): + r = type(self)() + r.arr = arr + r.context = context + return r + + class B(A): + __array_priority__ = 20. + + class C(A): + __array_priority__ = 40. + + x = np.zeros(1) + a = A() + b = B() + c = C() + f = ncu.minimum + assert_(type(f(x, x)) is np.ndarray) + assert_(type(f(x, a)) is A) + assert_(type(f(x, b)) is B) + assert_(type(f(x, c)) is C) + assert_(type(f(a, x)) is A) + assert_(type(f(b, x)) is B) + assert_(type(f(c, x)) is C) + + assert_(type(f(a, a)) is A) + assert_(type(f(a, b)) is B) + assert_(type(f(b, a)) is B) + assert_(type(f(b, b)) is B) + assert_(type(f(b, c)) is C) + assert_(type(f(c, b)) is C) + assert_(type(f(c, c)) is C) + + assert_(type(ncu.exp(a) is A)) + assert_(type(ncu.exp(b) is B)) + assert_(type(ncu.exp(c) is C)) + + def test_failing_wrap(self): + + class A(object): + def __array__(self): + return np.zeros(1) + + def __array_wrap__(self, arr, context): + raise RuntimeError + + a = A() + assert_raises(RuntimeError, ncu.maximum, a, a) + + def test_none_wrap(self): + # Tests that issue #8507 is resolved. Previously, this would segfault + + class A(object): + def __array__(self): + return np.zeros(1) + + def __array_wrap__(self, arr, context=None): + return None + + a = A() + assert_equal(ncu.maximum(a, a), None) + + def test_default_prepare(self): + + class with_wrap(object): + __array_priority__ = 10 + + def __array__(self): + return np.zeros(1) + + def __array_wrap__(self, arr, context): + return arr + + a = with_wrap() + x = ncu.minimum(a, a) + assert_equal(x, np.zeros(1)) + assert_equal(type(x), np.ndarray) + + def test_prepare(self): + + class with_prepare(np.ndarray): + __array_priority__ = 10 + + def __array_prepare__(self, arr, context): + # make sure we can return a new + return np.array(arr).view(type=with_prepare) + + a = np.array(1).view(type=with_prepare) + x = np.add(a, a) + assert_equal(x, np.array(2)) + assert_equal(type(x), with_prepare) + + def test_prepare_out(self): + + class with_prepare(np.ndarray): + __array_priority__ = 10 + + def __array_prepare__(self, arr, context): + return np.array(arr).view(type=with_prepare) + + a = np.array([1]).view(type=with_prepare) + x = np.add(a, a, a) + # Returned array is new, because of the strange + # __array_prepare__ above + assert_(not np.shares_memory(x, a)) + assert_equal(x, np.array([2])) + assert_equal(type(x), with_prepare) + + def test_failing_prepare(self): + + class A(object): + def __array__(self): + return np.zeros(1) + + def __array_prepare__(self, arr, context=None): + raise RuntimeError + + a = A() + assert_raises(RuntimeError, ncu.maximum, a, a) + + def test_array_with_context(self): + + class A(object): + def __array__(self, dtype=None, context=None): + func, args, i = context + self.func = func + self.args = args + self.i = i + return np.zeros(1) + + class B(object): + def __array__(self, dtype=None): + return np.zeros(1, dtype) + + class C(object): + def __array__(self): + return np.zeros(1) + + a = A() + ncu.maximum(np.zeros(1), a) + assert_(a.func is ncu.maximum) + assert_equal(a.args[0], 0) + assert_(a.args[1] is a) + assert_(a.i == 1) + assert_equal(ncu.maximum(a, B()), 0) + assert_equal(ncu.maximum(a, C()), 0) + + def test_ufunc_override(self): + + class A(object): + def __array_ufunc__(self, func, method, *inputs, **kwargs): + return self, func, method, inputs, kwargs + + a = A() + b = np.matrix([1]) + res0 = np.multiply(a, b) + res1 = np.multiply(b, b, out=a) + + # self + assert_equal(res0[0], a) + assert_equal(res1[0], a) + assert_equal(res0[1], np.multiply) + assert_equal(res1[1], np.multiply) + assert_equal(res0[2], '__call__') + assert_equal(res1[2], '__call__') + assert_equal(res0[3], (a, b)) + assert_equal(res1[3], (b, b)) + assert_equal(res0[4], {}) + assert_equal(res1[4], {'out': (a,)}) + + def test_ufunc_override_mro(self): + + # Some multi arg functions for testing. + def tres_mul(a, b, c): + return a * b * c + + def quatro_mul(a, b, c, d): + return a * b * c * d + + # Make these into ufuncs. + three_mul_ufunc = np.frompyfunc(tres_mul, 3, 1) + four_mul_ufunc = np.frompyfunc(quatro_mul, 4, 1) + + class A(object): + def __array_ufunc__(self, func, method, *inputs, **kwargs): + return "A" + + class ASub(A): + def __array_ufunc__(self, func, method, *inputs, **kwargs): + return "ASub" + + class B(object): + def __array_ufunc__(self, func, method, *inputs, **kwargs): + return "B" + + class C(object): + def __array_ufunc__(self, func, method, *inputs, **kwargs): + return NotImplemented + + class CSub(C): + def __array_ufunc__(self, func, method, *inputs, **kwargs): + return NotImplemented + + a = A() + a_sub = ASub() + b = B() + c = C() + c_sub = CSub() + + # Standard + res = np.multiply(a, a_sub) + assert_equal(res, "ASub") + res = np.multiply(a_sub, b) + assert_equal(res, "ASub") + + # With 1 NotImplemented + res = np.multiply(c, a) + assert_equal(res, "A") + + # Both NotImplemented. + assert_raises(TypeError, np.multiply, c, c_sub) + assert_raises(TypeError, np.multiply, c_sub, c) + assert_raises(TypeError, np.multiply, 2, c) + + # Ternary testing. + assert_equal(three_mul_ufunc(a, 1, 2), "A") + assert_equal(three_mul_ufunc(1, a, 2), "A") + assert_equal(three_mul_ufunc(1, 2, a), "A") + + assert_equal(three_mul_ufunc(a, a, 6), "A") + assert_equal(three_mul_ufunc(a, 2, a), "A") + assert_equal(three_mul_ufunc(a, 2, b), "A") + assert_equal(three_mul_ufunc(a, 2, a_sub), "ASub") + assert_equal(three_mul_ufunc(a, a_sub, 3), "ASub") + assert_equal(three_mul_ufunc(c, a_sub, 3), "ASub") + assert_equal(three_mul_ufunc(1, a_sub, c), "ASub") + + assert_equal(three_mul_ufunc(a, b, c), "A") + assert_equal(three_mul_ufunc(a, b, c_sub), "A") + assert_equal(three_mul_ufunc(1, 2, b), "B") + + assert_raises(TypeError, three_mul_ufunc, 1, 2, c) + assert_raises(TypeError, three_mul_ufunc, c_sub, 2, c) + assert_raises(TypeError, three_mul_ufunc, c_sub, 2, 3) + + # Quaternary testing. + assert_equal(four_mul_ufunc(a, 1, 2, 3), "A") + assert_equal(four_mul_ufunc(1, a, 2, 3), "A") + assert_equal(four_mul_ufunc(1, 1, a, 3), "A") + assert_equal(four_mul_ufunc(1, 1, 2, a), "A") + + assert_equal(four_mul_ufunc(a, b, 2, 3), "A") + assert_equal(four_mul_ufunc(1, a, 2, b), "A") + assert_equal(four_mul_ufunc(b, 1, a, 3), "B") + assert_equal(four_mul_ufunc(a_sub, 1, 2, a), "ASub") + assert_equal(four_mul_ufunc(a, 1, 2, a_sub), "ASub") + + assert_raises(TypeError, four_mul_ufunc, 1, 2, 3, c) + assert_raises(TypeError, four_mul_ufunc, 1, 2, c_sub, c) + assert_raises(TypeError, four_mul_ufunc, 1, c, c_sub, c) + + def test_ufunc_override_methods(self): + + class A(object): + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + return self, ufunc, method, inputs, kwargs + + # __call__ + a = A() + res = np.multiply.__call__(1, a, foo='bar', answer=42) + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], '__call__') + assert_equal(res[3], (1, a)) + assert_equal(res[4], {'foo': 'bar', 'answer': 42}) + + # __call__, wrong args + assert_raises(TypeError, np.multiply, a) + assert_raises(TypeError, np.multiply, a, a, a, a) + assert_raises(TypeError, np.multiply, a, a, sig='a', signature='a') + + # reduce, positional args + res = np.multiply.reduce(a, 'axis0', 'dtype0', 'out0', 'keep0') + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], 'reduce') + assert_equal(res[3], (a,)) + assert_equal(res[4], {'dtype':'dtype0', + 'out': ('out0',), + 'keepdims': 'keep0', + 'axis': 'axis0'}) + + # reduce, kwargs + res = np.multiply.reduce(a, axis='axis0', dtype='dtype0', out='out0', + keepdims='keep0') + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], 'reduce') + assert_equal(res[3], (a,)) + assert_equal(res[4], {'dtype':'dtype0', + 'out': ('out0',), + 'keepdims': 'keep0', + 'axis': 'axis0'}) + + # reduce, output equal to None removed, but not other explicit ones, + # even if they are at their default value. + res = np.multiply.reduce(a, 0, None, None, False) + assert_equal(res[4], {'axis': 0, 'dtype': None, 'keepdims': False}) + res = np.multiply.reduce(a, out=None, axis=0, keepdims=True) + assert_equal(res[4], {'axis': 0, 'keepdims': True}) + res = np.multiply.reduce(a, None, out=(None,), dtype=None) + assert_equal(res[4], {'axis': None, 'dtype': None}) + + # reduce, wrong args + assert_raises(ValueError, np.multiply.reduce, a, out=()) + assert_raises(ValueError, np.multiply.reduce, a, out=('out0', 'out1')) + assert_raises(TypeError, np.multiply.reduce, a, 'axis0', axis='axis0') + + # accumulate, pos args + res = np.multiply.accumulate(a, 'axis0', 'dtype0', 'out0') + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], 'accumulate') + assert_equal(res[3], (a,)) + assert_equal(res[4], {'dtype':'dtype0', + 'out': ('out0',), + 'axis': 'axis0'}) + + # accumulate, kwargs + res = np.multiply.accumulate(a, axis='axis0', dtype='dtype0', + out='out0') + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], 'accumulate') + assert_equal(res[3], (a,)) + assert_equal(res[4], {'dtype':'dtype0', + 'out': ('out0',), + 'axis': 'axis0'}) + + # accumulate, output equal to None removed. + res = np.multiply.accumulate(a, 0, None, None) + assert_equal(res[4], {'axis': 0, 'dtype': None}) + res = np.multiply.accumulate(a, out=None, axis=0, dtype='dtype1') + assert_equal(res[4], {'axis': 0, 'dtype': 'dtype1'}) + res = np.multiply.accumulate(a, None, out=(None,), dtype=None) + assert_equal(res[4], {'axis': None, 'dtype': None}) + + # accumulate, wrong args + assert_raises(ValueError, np.multiply.accumulate, a, out=()) + assert_raises(ValueError, np.multiply.accumulate, a, + out=('out0', 'out1')) + assert_raises(TypeError, np.multiply.accumulate, a, + 'axis0', axis='axis0') + + # reduceat, pos args + res = np.multiply.reduceat(a, [4, 2], 'axis0', 'dtype0', 'out0') + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], 'reduceat') + assert_equal(res[3], (a, [4, 2])) + assert_equal(res[4], {'dtype':'dtype0', + 'out': ('out0',), + 'axis': 'axis0'}) + + # reduceat, kwargs + res = np.multiply.reduceat(a, [4, 2], axis='axis0', dtype='dtype0', + out='out0') + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], 'reduceat') + assert_equal(res[3], (a, [4, 2])) + assert_equal(res[4], {'dtype':'dtype0', + 'out': ('out0',), + 'axis': 'axis0'}) + + # reduceat, output equal to None removed. + res = np.multiply.reduceat(a, [4, 2], 0, None, None) + assert_equal(res[4], {'axis': 0, 'dtype': None}) + res = np.multiply.reduceat(a, [4, 2], axis=None, out=None, dtype='dt') + assert_equal(res[4], {'axis': None, 'dtype': 'dt'}) + res = np.multiply.reduceat(a, [4, 2], None, None, out=(None,)) + assert_equal(res[4], {'axis': None, 'dtype': None}) + + # reduceat, wrong args + assert_raises(ValueError, np.multiply.reduce, a, [4, 2], out=()) + assert_raises(ValueError, np.multiply.reduce, a, [4, 2], + out=('out0', 'out1')) + assert_raises(TypeError, np.multiply.reduce, a, [4, 2], + 'axis0', axis='axis0') + + # outer + res = np.multiply.outer(a, 42) + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], 'outer') + assert_equal(res[3], (a, 42)) + assert_equal(res[4], {}) + + # outer, wrong args + assert_raises(TypeError, np.multiply.outer, a) + assert_raises(TypeError, np.multiply.outer, a, a, a, a) + + # at + res = np.multiply.at(a, [4, 2], 'b0') + assert_equal(res[0], a) + assert_equal(res[1], np.multiply) + assert_equal(res[2], 'at') + assert_equal(res[3], (a, [4, 2], 'b0')) + + # at, wrong args + assert_raises(TypeError, np.multiply.at, a) + assert_raises(TypeError, np.multiply.at, a, a, a, a) + + def test_ufunc_override_out(self): + + class A(object): + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + return kwargs + + class B(object): + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + return kwargs + + a = A() + b = B() + res0 = np.multiply(a, b, 'out_arg') + res1 = np.multiply(a, b, out='out_arg') + res2 = np.multiply(2, b, 'out_arg') + res3 = np.multiply(3, b, out='out_arg') + res4 = np.multiply(a, 4, 'out_arg') + res5 = np.multiply(a, 5, out='out_arg') + + assert_equal(res0['out'][0], 'out_arg') + assert_equal(res1['out'][0], 'out_arg') + assert_equal(res2['out'][0], 'out_arg') + assert_equal(res3['out'][0], 'out_arg') + assert_equal(res4['out'][0], 'out_arg') + assert_equal(res5['out'][0], 'out_arg') + + # ufuncs with multiple output modf and frexp. + res6 = np.modf(a, 'out0', 'out1') + res7 = np.frexp(a, 'out0', 'out1') + assert_equal(res6['out'][0], 'out0') + assert_equal(res6['out'][1], 'out1') + assert_equal(res7['out'][0], 'out0') + assert_equal(res7['out'][1], 'out1') + + # While we're at it, check that default output is never passed on. + assert_(np.sin(a, None) == {}) + assert_(np.sin(a, out=None) == {}) + assert_(np.sin(a, out=(None,)) == {}) + assert_(np.modf(a, None) == {}) + assert_(np.modf(a, None, None) == {}) + assert_(np.modf(a, out=(None, None)) == {}) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', DeprecationWarning) + assert_(np.modf(a, out=None) == {}) + assert_(w[0].category is DeprecationWarning) + + # don't give positional and output argument, or too many arguments. + # wrong number of arguments in the tuple is an error too. + assert_raises(TypeError, np.multiply, a, b, 'one', out='two') + assert_raises(TypeError, np.multiply, a, b, 'one', 'two') + assert_raises(ValueError, np.multiply, a, b, out=('one', 'two')) + assert_raises(ValueError, np.multiply, a, out=()) + assert_raises(TypeError, np.modf, a, 'one', out=('two', 'three')) + assert_raises(TypeError, np.modf, a, 'one', 'two', 'three') + assert_raises(ValueError, np.modf, a, out=('one', 'two', 'three')) + assert_raises(ValueError, np.modf, a, out=('one',)) + + def test_ufunc_override_exception(self): + + class A(object): + def __array_ufunc__(self, *a, **kwargs): + raise ValueError("oops") + + a = A() + assert_raises(ValueError, np.negative, 1, out=a) + assert_raises(ValueError, np.negative, a) + assert_raises(ValueError, np.divide, 1., a) + + def test_ufunc_override_not_implemented(self): + + class A(object): + def __array_ufunc__(self, *args, **kwargs): + return NotImplemented + + msg = ("operand type(s) all returned NotImplemented from " + "__array_ufunc__(, '__call__', <*>): 'A'") + with assert_raises_regex(TypeError, fnmatch.translate(msg)): + np.negative(A()) + + msg = ("operand type(s) all returned NotImplemented from " + "__array_ufunc__(, '__call__', <*>, , " + "out=(1,)): 'A', 'object', 'int'") + with assert_raises_regex(TypeError, fnmatch.translate(msg)): + np.add(A(), object(), out=1) + + def test_ufunc_override_disabled(self): + + class OptOut(object): + __array_ufunc__ = None + + opt_out = OptOut() + + # ufuncs always raise + msg = "operand 'OptOut' does not support ufuncs" + with assert_raises_regex(TypeError, msg): + np.add(opt_out, 1) + with assert_raises_regex(TypeError, msg): + np.add(1, opt_out) + with assert_raises_regex(TypeError, msg): + np.negative(opt_out) + + # opt-outs still hold even when other arguments have pathological + # __array_ufunc__ implementations + + class GreedyArray(object): + def __array_ufunc__(self, *args, **kwargs): + return self + + greedy = GreedyArray() + assert_(np.negative(greedy) is greedy) + with assert_raises_regex(TypeError, msg): + np.add(greedy, opt_out) + with assert_raises_regex(TypeError, msg): + np.add(greedy, 1, out=opt_out) + + def test_gufunc_override(self): + # gufunc are just ufunc instances, but follow a different path, + # so check __array_ufunc__ overrides them properly. + class A(object): + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + return self, ufunc, method, inputs, kwargs + + inner1d = ncu_tests.inner1d + a = A() + res = inner1d(a, a) + assert_equal(res[0], a) + assert_equal(res[1], inner1d) + assert_equal(res[2], '__call__') + assert_equal(res[3], (a, a)) + assert_equal(res[4], {}) + + res = inner1d(1, 1, out=a) + assert_equal(res[0], a) + assert_equal(res[1], inner1d) + assert_equal(res[2], '__call__') + assert_equal(res[3], (1, 1)) + assert_equal(res[4], {'out': (a,)}) + + # wrong number of arguments in the tuple is an error too. + assert_raises(TypeError, inner1d, a, out='two') + assert_raises(TypeError, inner1d, a, a, 'one', out='two') + assert_raises(TypeError, inner1d, a, a, 'one', 'two') + assert_raises(ValueError, inner1d, a, a, out=('one', 'two')) + assert_raises(ValueError, inner1d, a, a, out=()) + + def test_ufunc_override_with_super(self): + # NOTE: this class is given as an example in doc/subclassing.py; + # if you make any changes here, do update it there too. + class A(np.ndarray): + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + args = [] + in_no = [] + for i, input_ in enumerate(inputs): + if isinstance(input_, A): + in_no.append(i) + args.append(input_.view(np.ndarray)) + else: + args.append(input_) + + outputs = kwargs.pop('out', None) + out_no = [] + if outputs: + out_args = [] + for j, output in enumerate(outputs): + if isinstance(output, A): + out_no.append(j) + out_args.append(output.view(np.ndarray)) + else: + out_args.append(output) + kwargs['out'] = tuple(out_args) + else: + outputs = (None,) * ufunc.nout + + info = {} + if in_no: + info['inputs'] = in_no + if out_no: + info['outputs'] = out_no + + results = super(A, self).__array_ufunc__(ufunc, method, + *args, **kwargs) + if results is NotImplemented: + return NotImplemented + + if method == 'at': + if isinstance(inputs[0], A): + inputs[0].info = info + return + + if ufunc.nout == 1: + results = (results,) + + results = tuple((np.asarray(result).view(A) + if output is None else output) + for result, output in zip(results, outputs)) + if results and isinstance(results[0], A): + results[0].info = info + + return results[0] if len(results) == 1 else results + + class B(object): + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + if any(isinstance(input_, A) for input_ in inputs): + return "A!" + else: + return NotImplemented + + d = np.arange(5.) + # 1 input, 1 output + a = np.arange(5.).view(A) + b = np.sin(a) + check = np.sin(d) + assert_(np.all(check == b)) + assert_equal(b.info, {'inputs': [0]}) + b = np.sin(d, out=(a,)) + assert_(np.all(check == b)) + assert_equal(b.info, {'outputs': [0]}) + assert_(b is a) + a = np.arange(5.).view(A) + b = np.sin(a, out=a) + assert_(np.all(check == b)) + assert_equal(b.info, {'inputs': [0], 'outputs': [0]}) + + # 1 input, 2 outputs + a = np.arange(5.).view(A) + b1, b2 = np.modf(a) + assert_equal(b1.info, {'inputs': [0]}) + b1, b2 = np.modf(d, out=(None, a)) + assert_(b2 is a) + assert_equal(b1.info, {'outputs': [1]}) + a = np.arange(5.).view(A) + b = np.arange(5.).view(A) + c1, c2 = np.modf(a, out=(a, b)) + assert_(c1 is a) + assert_(c2 is b) + assert_equal(c1.info, {'inputs': [0], 'outputs': [0, 1]}) + + # 2 input, 1 output + a = np.arange(5.).view(A) + b = np.arange(5.).view(A) + c = np.add(a, b, out=a) + assert_(c is a) + assert_equal(c.info, {'inputs': [0, 1], 'outputs': [0]}) + # some tests with a non-ndarray subclass + a = np.arange(5.) + b = B() + assert_(a.__array_ufunc__(np.add, '__call__', a, b) is NotImplemented) + assert_(b.__array_ufunc__(np.add, '__call__', a, b) is NotImplemented) + assert_raises(TypeError, np.add, a, b) + a = a.view(A) + assert_(a.__array_ufunc__(np.add, '__call__', a, b) is NotImplemented) + assert_(b.__array_ufunc__(np.add, '__call__', a, b) == "A!") + assert_(np.add(a, b) == "A!") + # regression check for gh-9102 -- tests ufunc.reduce implicitly. + d = np.array([[1, 2, 3], [1, 2, 3]]) + a = d.view(A) + c = a.any() + check = d.any() + assert_equal(c, check) + assert_(c.info, {'inputs': [0]}) + c = a.max() + check = d.max() + assert_equal(c, check) + assert_(c.info, {'inputs': [0]}) + b = np.array(0).view(A) + c = a.max(out=b) + assert_equal(c, check) + assert_(c is b) + assert_(c.info, {'inputs': [0], 'outputs': [0]}) + check = a.max(axis=0) + b = np.zeros_like(check).view(A) + c = a.max(axis=0, out=b) + assert_equal(c, check) + assert_(c is b) + assert_(c.info, {'inputs': [0], 'outputs': [0]}) + # simple explicit tests of reduce, accumulate, reduceat + check = np.add.reduce(d, axis=1) + c = np.add.reduce(a, axis=1) + assert_equal(c, check) + assert_(c.info, {'inputs': [0]}) + b = np.zeros_like(c) + c = np.add.reduce(a, 1, None, b) + assert_equal(c, check) + assert_(c is b) + assert_(c.info, {'inputs': [0], 'outputs': [0]}) + check = np.add.accumulate(d, axis=0) + c = np.add.accumulate(a, axis=0) + assert_equal(c, check) + assert_(c.info, {'inputs': [0]}) + b = np.zeros_like(c) + c = np.add.accumulate(a, 0, None, b) + assert_equal(c, check) + assert_(c is b) + assert_(c.info, {'inputs': [0], 'outputs': [0]}) + indices = [0, 2, 1] + check = np.add.reduceat(d, indices, axis=1) + c = np.add.reduceat(a, indices, axis=1) + assert_equal(c, check) + assert_(c.info, {'inputs': [0]}) + b = np.zeros_like(c) + c = np.add.reduceat(a, indices, 1, None, b) + assert_equal(c, check) + assert_(c is b) + assert_(c.info, {'inputs': [0], 'outputs': [0]}) + # and a few tests for at + d = np.array([[1, 2, 3], [1, 2, 3]]) + check = d.copy() + a = d.copy().view(A) + np.add.at(check, ([0, 1], [0, 2]), 1.) + np.add.at(a, ([0, 1], [0, 2]), 1.) + assert_equal(a, check) + assert_(a.info, {'inputs': [0]}) + b = np.array(1.).view(A) + a = d.copy().view(A) + np.add.at(a, ([0, 1], [0, 2]), b) + assert_equal(a, check) + assert_(a.info, {'inputs': [0, 2]}) + + +class TestChoose(object): + def test_mixed(self): + c = np.array([True, True]) + a = np.array([True, True]) + assert_equal(np.choose(c, (a, 1)), np.array([1, 1])) + + +def is_longdouble_finfo_bogus(): + info = np.finfo(np.longcomplex) + return not np.isfinite(np.log10(info.tiny/info.eps)) + + +class TestComplexFunctions(object): + funcs = [np.arcsin, np.arccos, np.arctan, np.arcsinh, np.arccosh, + np.arctanh, np.sin, np.cos, np.tan, np.exp, + np.exp2, np.log, np.sqrt, np.log10, np.log2, + np.log1p] + + def test_it(self): + for f in self.funcs: + if f is np.arccosh: + x = 1.5 + else: + x = .5 + fr = f(x) + fz = f(complex(x)) + assert_almost_equal(fz.real, fr, err_msg='real part %s' % f) + assert_almost_equal(fz.imag, 0., err_msg='imag part %s' % f) + + def test_precisions_consistent(self): + z = 1 + 1j + for f in self.funcs: + fcf = f(np.csingle(z)) + fcd = f(np.cdouble(z)) + fcl = f(np.clongdouble(z)) + assert_almost_equal(fcf, fcd, decimal=6, err_msg='fch-fcd %s' % f) + assert_almost_equal(fcl, fcd, decimal=15, err_msg='fch-fcl %s' % f) + + def test_branch_cuts(self): + # check branch cuts and continuity on them + yield _check_branch_cut, np.log, -0.5, 1j, 1, -1, True + yield _check_branch_cut, np.log2, -0.5, 1j, 1, -1, True + yield _check_branch_cut, np.log10, -0.5, 1j, 1, -1, True + yield _check_branch_cut, np.log1p, -1.5, 1j, 1, -1, True + yield _check_branch_cut, np.sqrt, -0.5, 1j, 1, -1, True + + yield _check_branch_cut, np.arcsin, [ -2, 2], [1j, 1j], 1, -1, True + yield _check_branch_cut, np.arccos, [ -2, 2], [1j, 1j], 1, -1, True + yield _check_branch_cut, np.arctan, [0-2j, 2j], [1, 1], -1, 1, True + + yield _check_branch_cut, np.arcsinh, [0-2j, 2j], [1, 1], -1, 1, True + yield _check_branch_cut, np.arccosh, [ -1, 0.5], [1j, 1j], 1, -1, True + yield _check_branch_cut, np.arctanh, [ -2, 2], [1j, 1j], 1, -1, True + + # check against bogus branch cuts: assert continuity between quadrants + yield _check_branch_cut, np.arcsin, [0-2j, 2j], [ 1, 1], 1, 1 + yield _check_branch_cut, np.arccos, [0-2j, 2j], [ 1, 1], 1, 1 + yield _check_branch_cut, np.arctan, [ -2, 2], [1j, 1j], 1, 1 + + yield _check_branch_cut, np.arcsinh, [ -2, 2, 0], [1j, 1j, 1], 1, 1 + yield _check_branch_cut, np.arccosh, [0-2j, 2j, 2], [1, 1, 1j], 1, 1 + yield _check_branch_cut, np.arctanh, [0-2j, 2j, 0], [1, 1, 1j], 1, 1 + + def test_branch_cuts_complex64(self): + # check branch cuts and continuity on them + yield _check_branch_cut, np.log, -0.5, 1j, 1, -1, True, np.complex64 + yield _check_branch_cut, np.log2, -0.5, 1j, 1, -1, True, np.complex64 + yield _check_branch_cut, np.log10, -0.5, 1j, 1, -1, True, np.complex64 + yield _check_branch_cut, np.log1p, -1.5, 1j, 1, -1, True, np.complex64 + yield _check_branch_cut, np.sqrt, -0.5, 1j, 1, -1, True, np.complex64 + + yield _check_branch_cut, np.arcsin, [ -2, 2], [1j, 1j], 1, -1, True, np.complex64 + yield _check_branch_cut, np.arccos, [ -2, 2], [1j, 1j], 1, -1, True, np.complex64 + yield _check_branch_cut, np.arctan, [0-2j, 2j], [1, 1], -1, 1, True, np.complex64 + + yield _check_branch_cut, np.arcsinh, [0-2j, 2j], [1, 1], -1, 1, True, np.complex64 + yield _check_branch_cut, np.arccosh, [ -1, 0.5], [1j, 1j], 1, -1, True, np.complex64 + yield _check_branch_cut, np.arctanh, [ -2, 2], [1j, 1j], 1, -1, True, np.complex64 + + # check against bogus branch cuts: assert continuity between quadrants + yield _check_branch_cut, np.arcsin, [0-2j, 2j], [ 1, 1], 1, 1, False, np.complex64 + yield _check_branch_cut, np.arccos, [0-2j, 2j], [ 1, 1], 1, 1, False, np.complex64 + yield _check_branch_cut, np.arctan, [ -2, 2], [1j, 1j], 1, 1, False, np.complex64 + + yield _check_branch_cut, np.arcsinh, [ -2, 2, 0], [1j, 1j, 1], 1, 1, False, np.complex64 + yield _check_branch_cut, np.arccosh, [0-2j, 2j, 2], [1, 1, 1j], 1, 1, False, np.complex64 + yield _check_branch_cut, np.arctanh, [0-2j, 2j, 0], [1, 1, 1j], 1, 1, False, np.complex64 + + def test_against_cmath(self): + import cmath + + points = [-1-1j, -1+1j, +1-1j, +1+1j] + name_map = {'arcsin': 'asin', 'arccos': 'acos', 'arctan': 'atan', + 'arcsinh': 'asinh', 'arccosh': 'acosh', 'arctanh': 'atanh'} + atol = 4*np.finfo(complex).eps + for func in self.funcs: + fname = func.__name__.split('.')[-1] + cname = name_map.get(fname, fname) + try: + cfunc = getattr(cmath, cname) + except AttributeError: + continue + for p in points: + a = complex(func(np.complex_(p))) + b = cfunc(p) + assert_(abs(a - b) < atol, "%s %s: %s; cmath: %s" % (fname, p, a, b)) + + def check_loss_of_precision(self, dtype): + """Check loss of precision in complex arc* functions""" + + # Check against known-good functions + + info = np.finfo(dtype) + real_dtype = dtype(0.).real.dtype + eps = info.eps + + def check(x, rtol): + x = x.astype(real_dtype) + + z = x.astype(dtype) + d = np.absolute(np.arcsinh(x)/np.arcsinh(z).real - 1) + assert_(np.all(d < rtol), (np.argmax(d), x[np.argmax(d)], d.max(), + 'arcsinh')) + + z = (1j*x).astype(dtype) + d = np.absolute(np.arcsinh(x)/np.arcsin(z).imag - 1) + assert_(np.all(d < rtol), (np.argmax(d), x[np.argmax(d)], d.max(), + 'arcsin')) + + z = x.astype(dtype) + d = np.absolute(np.arctanh(x)/np.arctanh(z).real - 1) + assert_(np.all(d < rtol), (np.argmax(d), x[np.argmax(d)], d.max(), + 'arctanh')) + + z = (1j*x).astype(dtype) + d = np.absolute(np.arctanh(x)/np.arctan(z).imag - 1) + assert_(np.all(d < rtol), (np.argmax(d), x[np.argmax(d)], d.max(), + 'arctan')) + + # The switchover was chosen as 1e-3; hence there can be up to + # ~eps/1e-3 of relative cancellation error before it + + x_series = np.logspace(-20, -3.001, 200) + x_basic = np.logspace(-2.999, 0, 10, endpoint=False) + + if dtype is np.longcomplex: + # It's not guaranteed that the system-provided arc functions + # are accurate down to a few epsilons. (Eg. on Linux 64-bit) + # So, give more leeway for long complex tests here: + check(x_series, 50*eps) + else: + check(x_series, 2.1*eps) + check(x_basic, 2*eps/1e-3) + + # Check a few points + + z = np.array([1e-5*(1+1j)], dtype=dtype) + p = 9.999999999333333333e-6 + 1.000000000066666666e-5j + d = np.absolute(1-np.arctanh(z)/p) + assert_(np.all(d < 1e-15)) + + p = 1.0000000000333333333e-5 + 9.999999999666666667e-6j + d = np.absolute(1-np.arcsinh(z)/p) + assert_(np.all(d < 1e-15)) + + p = 9.999999999333333333e-6j + 1.000000000066666666e-5 + d = np.absolute(1-np.arctan(z)/p) + assert_(np.all(d < 1e-15)) + + p = 1.0000000000333333333e-5j + 9.999999999666666667e-6 + d = np.absolute(1-np.arcsin(z)/p) + assert_(np.all(d < 1e-15)) + + # Check continuity across switchover points + + def check(func, z0, d=1): + z0 = np.asarray(z0, dtype=dtype) + zp = z0 + abs(z0) * d * eps * 2 + zm = z0 - abs(z0) * d * eps * 2 + assert_(np.all(zp != zm), (zp, zm)) + + # NB: the cancellation error at the switchover is at least eps + good = (abs(func(zp) - func(zm)) < 2*eps) + assert_(np.all(good), (func, z0[~good])) + + for func in (np.arcsinh, np.arcsinh, np.arcsin, np.arctanh, np.arctan): + pts = [rp+1j*ip for rp in (-1e-3, 0, 1e-3) for ip in(-1e-3, 0, 1e-3) + if rp != 0 or ip != 0] + check(func, pts, 1) + check(func, pts, 1j) + check(func, pts, 1+1j) + + def test_loss_of_precision(self): + for dtype in [np.complex64, np.complex_]: + yield self.check_loss_of_precision, dtype + + @dec.knownfailureif(is_longdouble_finfo_bogus(), "Bogus long double finfo") + def test_loss_of_precision_longcomplex(self): + self.check_loss_of_precision(np.longcomplex) + + +class TestAttributes(object): + def test_attributes(self): + add = ncu.add + assert_equal(add.__name__, 'add') + assert_(add.ntypes >= 18) # don't fail if types added + assert_('ii->i' in add.types) + assert_equal(add.nin, 2) + assert_equal(add.nout, 1) + assert_equal(add.identity, 0) + + def test_doc(self): + # don't bother checking the long list of kwargs, which are likely to + # change + assert_(ncu.add.__doc__.startswith( + "add(x1, x2, /, out=None, *, where=True")) + assert_(ncu.frexp.__doc__.startswith( + "frexp(x[, out1, out2], / [, out=(None, None)], *, where=True")) + + +class TestSubclass(object): + + def test_subclass_op(self): + + class simple(np.ndarray): + def __new__(subtype, shape): + self = np.ndarray.__new__(subtype, shape, dtype=object) + self.fill(0) + return self + + a = simple((3, 4)) + assert_equal(a+a, a) + +def _check_branch_cut(f, x0, dx, re_sign=1, im_sign=-1, sig_zero_ok=False, + dtype=complex): + """ + Check for a branch cut in a function. + + Assert that `x0` lies on a branch cut of function `f` and `f` is + continuous from the direction `dx`. + + Parameters + ---------- + f : func + Function to check + x0 : array-like + Point on branch cut + dx : array-like + Direction to check continuity in + re_sign, im_sign : {1, -1} + Change of sign of the real or imaginary part expected + sig_zero_ok : bool + Whether to check if the branch cut respects signed zero (if applicable) + dtype : dtype + Dtype to check (should be complex) + + """ + x0 = np.atleast_1d(x0).astype(dtype) + dx = np.atleast_1d(dx).astype(dtype) + + if np.dtype(dtype).char == 'F': + scale = np.finfo(dtype).eps * 1e2 + atol = np.float32(1e-2) + else: + scale = np.finfo(dtype).eps * 1e3 + atol = 1e-4 + + y0 = f(x0) + yp = f(x0 + dx*scale*np.absolute(x0)/np.absolute(dx)) + ym = f(x0 - dx*scale*np.absolute(x0)/np.absolute(dx)) + + assert_(np.all(np.absolute(y0.real - yp.real) < atol), (y0, yp)) + assert_(np.all(np.absolute(y0.imag - yp.imag) < atol), (y0, yp)) + assert_(np.all(np.absolute(y0.real - ym.real*re_sign) < atol), (y0, ym)) + assert_(np.all(np.absolute(y0.imag - ym.imag*im_sign) < atol), (y0, ym)) + + if sig_zero_ok: + # check that signed zeros also work as a displacement + jr = (x0.real == 0) & (dx.real != 0) + ji = (x0.imag == 0) & (dx.imag != 0) + if np.any(jr): + x = x0[jr] + x.real = np.NZERO + ym = f(x) + assert_(np.all(np.absolute(y0[jr].real - ym.real*re_sign) < atol), (y0[jr], ym)) + assert_(np.all(np.absolute(y0[jr].imag - ym.imag*im_sign) < atol), (y0[jr], ym)) + + if np.any(ji): + x = x0[ji] + x.imag = np.NZERO + ym = f(x) + assert_(np.all(np.absolute(y0[ji].real - ym.real*re_sign) < atol), (y0[ji], ym)) + assert_(np.all(np.absolute(y0[ji].imag - ym.imag*im_sign) < atol), (y0[ji], ym)) + +def test_copysign(): + assert_(np.copysign(1, -1) == -1) + with np.errstate(divide="ignore"): + assert_(1 / np.copysign(0, -1) < 0) + assert_(1 / np.copysign(0, 1) > 0) + assert_(np.signbit(np.copysign(np.nan, -1))) + assert_(not np.signbit(np.copysign(np.nan, 1))) + +def _test_nextafter(t): + one = t(1) + two = t(2) + zero = t(0) + eps = np.finfo(t).eps + assert_(np.nextafter(one, two) - one == eps) + assert_(np.nextafter(one, zero) - one < 0) + assert_(np.isnan(np.nextafter(np.nan, one))) + assert_(np.isnan(np.nextafter(one, np.nan))) + assert_(np.nextafter(one, one) == one) + +def test_nextafter(): + return _test_nextafter(np.float64) + +def test_nextafterf(): + return _test_nextafter(np.float32) + +@dec.knownfailureif(sys.platform == 'win32', + "Long double support buggy on win32, ticket 1664.") +def test_nextafterl(): + return _test_nextafter(np.longdouble) + +def test_nextafter_0(): + for t, direction in itertools.product(np.sctypes['float'], (1, -1)): + tiny = np.finfo(t).tiny + assert_(0. < direction * np.nextafter(t(0), t(direction)) < tiny) + assert_equal(np.nextafter(t(0), t(direction)) / t(2.1), direction * 0.0) + +def _test_spacing(t): + one = t(1) + eps = np.finfo(t).eps + nan = t(np.nan) + inf = t(np.inf) + with np.errstate(invalid='ignore'): + assert_(np.spacing(one) == eps) + assert_(np.isnan(np.spacing(nan))) + assert_(np.isnan(np.spacing(inf))) + assert_(np.isnan(np.spacing(-inf))) + assert_(np.spacing(t(1e30)) != 0) + +def test_spacing(): + return _test_spacing(np.float64) + +def test_spacingf(): + return _test_spacing(np.float32) + +@dec.knownfailureif(sys.platform == 'win32', + "Long double support buggy on win32, ticket 1664.") +def test_spacingl(): + return _test_spacing(np.longdouble) + +def test_spacing_gfortran(): + # Reference from this fortran file, built with gfortran 4.3.3 on linux + # 32bits: + # PROGRAM test_spacing + # INTEGER, PARAMETER :: SGL = SELECTED_REAL_KIND(p=6, r=37) + # INTEGER, PARAMETER :: DBL = SELECTED_REAL_KIND(p=13, r=200) + # + # WRITE(*,*) spacing(0.00001_DBL) + # WRITE(*,*) spacing(1.0_DBL) + # WRITE(*,*) spacing(1000._DBL) + # WRITE(*,*) spacing(10500._DBL) + # + # WRITE(*,*) spacing(0.00001_SGL) + # WRITE(*,*) spacing(1.0_SGL) + # WRITE(*,*) spacing(1000._SGL) + # WRITE(*,*) spacing(10500._SGL) + # END PROGRAM + ref = {np.float64: [1.69406589450860068E-021, + 2.22044604925031308E-016, + 1.13686837721616030E-013, + 1.81898940354585648E-012], + np.float32: [9.09494702E-13, + 1.19209290E-07, + 6.10351563E-05, + 9.76562500E-04]} + + for dt, dec_ in zip([np.float32, np.float64], (10, 20)): + x = np.array([1e-5, 1, 1000, 10500], dtype=dt) + assert_array_almost_equal(np.spacing(x), ref[dt], decimal=dec_) + +def test_nextafter_vs_spacing(): + # XXX: spacing does not handle long double yet + for t in [np.float32, np.float64]: + for _f in [1, 1e-5, 1000]: + f = t(_f) + f1 = t(_f + 1) + assert_(np.nextafter(f, f1) - f == np.spacing(f)) + +def test_pos_nan(): + """Check np.nan is a positive nan.""" + assert_(np.signbit(np.nan) == 0) + +def test_reduceat(): + """Test bug in reduceat when structured arrays are not copied.""" + db = np.dtype([('name', 'S11'), ('time', np.int64), ('value', np.float32)]) + a = np.empty([100], dtype=db) + a['name'] = 'Simple' + a['time'] = 10 + a['value'] = 100 + indx = [0, 7, 15, 25] + + h2 = [] + val1 = indx[0] + for val2 in indx[1:]: + h2.append(np.add.reduce(a['value'][val1:val2])) + val1 = val2 + h2.append(np.add.reduce(a['value'][val1:])) + h2 = np.array(h2) + + # test buffered -- this should work + h1 = np.add.reduceat(a['value'], indx) + assert_array_almost_equal(h1, h2) + + # This is when the error occurs. + # test no buffer + np.setbufsize(32) + h1 = np.add.reduceat(a['value'], indx) + np.setbufsize(np.UFUNC_BUFSIZE_DEFAULT) + assert_array_almost_equal(h1, h2) + +def test_reduceat_empty(): + """Reduceat should work with empty arrays""" + indices = np.array([], 'i4') + x = np.array([], 'f8') + result = np.add.reduceat(x, indices) + assert_equal(result.dtype, x.dtype) + assert_equal(result.shape, (0,)) + # Another case with a slightly different zero-sized shape + x = np.ones((5, 2)) + result = np.add.reduceat(x, [], axis=0) + assert_equal(result.dtype, x.dtype) + assert_equal(result.shape, (0, 2)) + result = np.add.reduceat(x, [], axis=1) + assert_equal(result.dtype, x.dtype) + assert_equal(result.shape, (5, 0)) + +def test_complex_nan_comparisons(): + nans = [complex(np.nan, 0), complex(0, np.nan), complex(np.nan, np.nan)] + fins = [complex(1, 0), complex(-1, 0), complex(0, 1), complex(0, -1), + complex(1, 1), complex(-1, -1), complex(0, 0)] + + with np.errstate(invalid='ignore'): + for x in nans + fins: + x = np.array([x]) + for y in nans + fins: + y = np.array([y]) + + if np.isfinite(x) and np.isfinite(y): + continue + + assert_equal(x < y, False, err_msg="%r < %r" % (x, y)) + assert_equal(x > y, False, err_msg="%r > %r" % (x, y)) + assert_equal(x <= y, False, err_msg="%r <= %r" % (x, y)) + assert_equal(x >= y, False, err_msg="%r >= %r" % (x, y)) + assert_equal(x == y, False, err_msg="%r == %r" % (x, y)) + + +def test_rint_big_int(): + # np.rint bug for large integer values on Windows 32-bit and MKL + # https://github.com/numpy/numpy/issues/6685 + val = 4607998452777363968 + # This is exactly representable in floating point + assert_equal(val, int(float(val))) + # Rint should not change the value + assert_equal(val, np.rint(val)) + + +def test_signaling_nan_exceptions(): + with assert_no_warnings(): + a = np.ndarray(shape=(), dtype='float32', buffer=b'\x00\xe0\xbf\xff') + np.isnan(a) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_umath_complex.py b/numpy/core/tests/test_umath_complex.py new file mode 100644 index 0000000..fb3b657 --- /dev/null +++ b/numpy/core/tests/test_umath_complex.py @@ -0,0 +1,538 @@ +from __future__ import division, absolute_import, print_function + +import sys +import platform + +import numpy as np +import numpy.core.umath as ncu +from numpy.testing import ( + run_module_suite, assert_raises, assert_equal, assert_array_equal, + assert_almost_equal, dec +) + +# TODO: branch cuts (use Pauli code) +# TODO: conj 'symmetry' +# TODO: FPU exceptions + +# At least on Windows the results of many complex functions are not conforming +# to the C99 standard. See ticket 1574. +# Ditto for Solaris (ticket 1642) and OS X on PowerPC. +with np.errstate(all='ignore'): + functions_seem_flaky = ((np.exp(complex(np.inf, 0)).imag != 0) + or (np.log(complex(np.NZERO, 0)).imag != np.pi)) +# TODO: replace with a check on whether platform-provided C99 funcs are used +skip_complex_tests = (not sys.platform.startswith('linux') or functions_seem_flaky) + +def platform_skip(func): + return dec.skipif(skip_complex_tests, + "Numpy is using complex functions (e.g. sqrt) provided by your" + "platform's C library. However, they do not seem to behave according" + "to C99 -- so C99 tests are skipped.")(func) + + +class TestCexp(object): + def test_simple(self): + check = check_complex_value + f = np.exp + + yield check, f, 1, 0, np.exp(1), 0, False + yield check, f, 0, 1, np.cos(1), np.sin(1), False + + ref = np.exp(1) * complex(np.cos(1), np.sin(1)) + yield check, f, 1, 1, ref.real, ref.imag, False + + @platform_skip + def test_special_values(self): + # C99: Section G 6.3.1 + + check = check_complex_value + f = np.exp + + # cexp(+-0 + 0i) is 1 + 0i + yield check, f, np.PZERO, 0, 1, 0, False + yield check, f, np.NZERO, 0, 1, 0, False + + # cexp(x + infi) is nan + nani for finite x and raises 'invalid' FPU + # exception + yield check, f, 1, np.inf, np.nan, np.nan + yield check, f, -1, np.inf, np.nan, np.nan + yield check, f, 0, np.inf, np.nan, np.nan + + # cexp(inf + 0i) is inf + 0i + yield check, f, np.inf, 0, np.inf, 0 + + # cexp(-inf + yi) is +0 * (cos(y) + i sin(y)) for finite y + yield check, f, -np.inf, 1, np.PZERO, np.PZERO + yield check, f, -np.inf, 0.75 * np.pi, np.NZERO, np.PZERO + + # cexp(inf + yi) is +inf * (cos(y) + i sin(y)) for finite y + yield check, f, np.inf, 1, np.inf, np.inf + yield check, f, np.inf, 0.75 * np.pi, -np.inf, np.inf + + # cexp(-inf + inf i) is +-0 +- 0i (signs unspecified) + def _check_ninf_inf(dummy): + msgform = "cexp(-inf, inf) is (%f, %f), expected (+-0, +-0)" + with np.errstate(invalid='ignore'): + z = f(np.array(complex(-np.inf, np.inf))) + if z.real != 0 or z.imag != 0: + raise AssertionError(msgform % (z.real, z.imag)) + + yield _check_ninf_inf, None + + # cexp(inf + inf i) is +-inf + NaNi and raised invalid FPU ex. + def _check_inf_inf(dummy): + msgform = "cexp(inf, inf) is (%f, %f), expected (+-inf, nan)" + with np.errstate(invalid='ignore'): + z = f(np.array(complex(np.inf, np.inf))) + if not np.isinf(z.real) or not np.isnan(z.imag): + raise AssertionError(msgform % (z.real, z.imag)) + + yield _check_inf_inf, None + + # cexp(-inf + nan i) is +-0 +- 0i + def _check_ninf_nan(dummy): + msgform = "cexp(-inf, nan) is (%f, %f), expected (+-0, +-0)" + with np.errstate(invalid='ignore'): + z = f(np.array(complex(-np.inf, np.nan))) + if z.real != 0 or z.imag != 0: + raise AssertionError(msgform % (z.real, z.imag)) + + yield _check_ninf_nan, None + + # cexp(inf + nan i) is +-inf + nan + def _check_inf_nan(dummy): + msgform = "cexp(-inf, nan) is (%f, %f), expected (+-inf, nan)" + with np.errstate(invalid='ignore'): + z = f(np.array(complex(np.inf, np.nan))) + if not np.isinf(z.real) or not np.isnan(z.imag): + raise AssertionError(msgform % (z.real, z.imag)) + + yield _check_inf_nan, None + + # cexp(nan + yi) is nan + nani for y != 0 (optional: raises invalid FPU + # ex) + yield check, f, np.nan, 1, np.nan, np.nan + yield check, f, np.nan, -1, np.nan, np.nan + + yield check, f, np.nan, np.inf, np.nan, np.nan + yield check, f, np.nan, -np.inf, np.nan, np.nan + + # cexp(nan + nani) is nan + nani + yield check, f, np.nan, np.nan, np.nan, np.nan + + @dec.knownfailureif(True, "cexp(nan + 0I) is wrong on most implementations") + def test_special_values2(self): + # XXX: most implementations get it wrong here (including glibc <= 2.10) + # cexp(nan + 0i) is nan + 0i + check = check_complex_value + f = np.exp + + yield check, f, np.nan, 0, np.nan, 0 + +class TestClog(object): + def test_simple(self): + x = np.array([1+0j, 1+2j]) + y_r = np.log(np.abs(x)) + 1j * np.angle(x) + y = np.log(x) + for i in range(len(x)): + assert_almost_equal(y[i], y_r[i]) + + @platform_skip + @dec.skipif(platform.machine() == "armv5tel", "See gh-413.") + def test_special_values(self): + xl = [] + yl = [] + + # From C99 std (Sec 6.3.2) + # XXX: check exceptions raised + # --- raise for invalid fails. + + # clog(-0 + i0) returns -inf + i pi and raises the 'divide-by-zero' + # floating-point exception. + with np.errstate(divide='raise'): + x = np.array([np.NZERO], dtype=complex) + y = complex(-np.inf, np.pi) + assert_raises(FloatingPointError, np.log, x) + with np.errstate(divide='ignore'): + assert_almost_equal(np.log(x), y) + + xl.append(x) + yl.append(y) + + # clog(+0 + i0) returns -inf + i0 and raises the 'divide-by-zero' + # floating-point exception. + with np.errstate(divide='raise'): + x = np.array([0], dtype=complex) + y = complex(-np.inf, 0) + assert_raises(FloatingPointError, np.log, x) + with np.errstate(divide='ignore'): + assert_almost_equal(np.log(x), y) + + xl.append(x) + yl.append(y) + + # clog(x + i inf returns +inf + i pi /2, for finite x. + x = np.array([complex(1, np.inf)], dtype=complex) + y = complex(np.inf, 0.5 * np.pi) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + x = np.array([complex(-1, np.inf)], dtype=complex) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(x + iNaN) returns NaN + iNaN and optionally raises the + # 'invalid' floating- point exception, for finite x. + with np.errstate(invalid='raise'): + x = np.array([complex(1., np.nan)], dtype=complex) + y = complex(np.nan, np.nan) + #assert_raises(FloatingPointError, np.log, x) + with np.errstate(invalid='ignore'): + assert_almost_equal(np.log(x), y) + + xl.append(x) + yl.append(y) + + with np.errstate(invalid='raise'): + x = np.array([np.inf + 1j * np.nan], dtype=complex) + #assert_raises(FloatingPointError, np.log, x) + with np.errstate(invalid='ignore'): + assert_almost_equal(np.log(x), y) + + xl.append(x) + yl.append(y) + + # clog(- inf + iy) returns +inf + ipi , for finite positive-signed y. + x = np.array([-np.inf + 1j], dtype=complex) + y = complex(np.inf, np.pi) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(+ inf + iy) returns +inf + i0, for finite positive-signed y. + x = np.array([np.inf + 1j], dtype=complex) + y = complex(np.inf, 0) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(- inf + i inf) returns +inf + i3pi /4. + x = np.array([complex(-np.inf, np.inf)], dtype=complex) + y = complex(np.inf, 0.75 * np.pi) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(+ inf + i inf) returns +inf + ipi /4. + x = np.array([complex(np.inf, np.inf)], dtype=complex) + y = complex(np.inf, 0.25 * np.pi) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(+/- inf + iNaN) returns +inf + iNaN. + x = np.array([complex(np.inf, np.nan)], dtype=complex) + y = complex(np.inf, np.nan) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + x = np.array([complex(-np.inf, np.nan)], dtype=complex) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(NaN + iy) returns NaN + iNaN and optionally raises the + # 'invalid' floating-point exception, for finite y. + x = np.array([complex(np.nan, 1)], dtype=complex) + y = complex(np.nan, np.nan) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(NaN + i inf) returns +inf + iNaN. + x = np.array([complex(np.nan, np.inf)], dtype=complex) + y = complex(np.inf, np.nan) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(NaN + iNaN) returns NaN + iNaN. + x = np.array([complex(np.nan, np.nan)], dtype=complex) + y = complex(np.nan, np.nan) + assert_almost_equal(np.log(x), y) + xl.append(x) + yl.append(y) + + # clog(conj(z)) = conj(clog(z)). + xa = np.array(xl, dtype=complex) + ya = np.array(yl, dtype=complex) + with np.errstate(divide='ignore'): + for i in range(len(xa)): + assert_almost_equal(np.log(xa[i].conj()), ya[i].conj()) + +class TestCsqrt(object): + + def test_simple(self): + # sqrt(1) + yield check_complex_value, np.sqrt, 1, 0, 1, 0 + + # sqrt(1i) + yield check_complex_value, np.sqrt, 0, 1, 0.5*np.sqrt(2), 0.5*np.sqrt(2), False + + # sqrt(-1) + yield check_complex_value, np.sqrt, -1, 0, 0, 1 + + def test_simple_conjugate(self): + ref = np.conj(np.sqrt(complex(1, 1))) + + def f(z): + return np.sqrt(np.conj(z)) + yield check_complex_value, f, 1, 1, ref.real, ref.imag, False + + #def test_branch_cut(self): + # _check_branch_cut(f, -1, 0, 1, -1) + + @platform_skip + def test_special_values(self): + # C99: Sec G 6.4.2 + + check = check_complex_value + f = np.sqrt + + # csqrt(+-0 + 0i) is 0 + 0i + yield check, f, np.PZERO, 0, 0, 0 + yield check, f, np.NZERO, 0, 0, 0 + + # csqrt(x + infi) is inf + infi for any x (including NaN) + yield check, f, 1, np.inf, np.inf, np.inf + yield check, f, -1, np.inf, np.inf, np.inf + + yield check, f, np.PZERO, np.inf, np.inf, np.inf + yield check, f, np.NZERO, np.inf, np.inf, np.inf + yield check, f, np.inf, np.inf, np.inf, np.inf + yield check, f, -np.inf, np.inf, np.inf, np.inf + yield check, f, -np.nan, np.inf, np.inf, np.inf + + # csqrt(x + nani) is nan + nani for any finite x + yield check, f, 1, np.nan, np.nan, np.nan + yield check, f, -1, np.nan, np.nan, np.nan + yield check, f, 0, np.nan, np.nan, np.nan + + # csqrt(-inf + yi) is +0 + infi for any finite y > 0 + yield check, f, -np.inf, 1, np.PZERO, np.inf + + # csqrt(inf + yi) is +inf + 0i for any finite y > 0 + yield check, f, np.inf, 1, np.inf, np.PZERO + + # csqrt(-inf + nani) is nan +- infi (both +i infi are valid) + def _check_ninf_nan(dummy): + msgform = "csqrt(-inf, nan) is (%f, %f), expected (nan, +-inf)" + z = np.sqrt(np.array(complex(-np.inf, np.nan))) + #Fixme: ugly workaround for isinf bug. + with np.errstate(invalid='ignore'): + if not (np.isnan(z.real) and np.isinf(z.imag)): + raise AssertionError(msgform % (z.real, z.imag)) + + yield _check_ninf_nan, None + + # csqrt(+inf + nani) is inf + nani + yield check, f, np.inf, np.nan, np.inf, np.nan + + # csqrt(nan + yi) is nan + nani for any finite y (infinite handled in x + # + nani) + yield check, f, np.nan, 0, np.nan, np.nan + yield check, f, np.nan, 1, np.nan, np.nan + yield check, f, np.nan, np.nan, np.nan, np.nan + + # XXX: check for conj(csqrt(z)) == csqrt(conj(z)) (need to fix branch + # cuts first) + +class TestCpow(object): + def setUp(self): + self.olderr = np.seterr(invalid='ignore') + + def tearDown(self): + np.seterr(**self.olderr) + + def test_simple(self): + x = np.array([1+1j, 0+2j, 1+2j, np.inf, np.nan]) + y_r = x ** 2 + y = np.power(x, 2) + for i in range(len(x)): + assert_almost_equal(y[i], y_r[i]) + + def test_scalar(self): + x = np.array([1, 1j, 2, 2.5+.37j, np.inf, np.nan]) + y = np.array([1, 1j, -0.5+1.5j, -0.5+1.5j, 2, 3]) + lx = list(range(len(x))) + # Compute the values for complex type in python + p_r = [complex(x[i]) ** complex(y[i]) for i in lx] + # Substitute a result allowed by C99 standard + p_r[4] = complex(np.inf, np.nan) + # Do the same with numpy complex scalars + n_r = [x[i] ** y[i] for i in lx] + for i in lx: + assert_almost_equal(n_r[i], p_r[i], err_msg='Loop %d\n' % i) + + def test_array(self): + x = np.array([1, 1j, 2, 2.5+.37j, np.inf, np.nan]) + y = np.array([1, 1j, -0.5+1.5j, -0.5+1.5j, 2, 3]) + lx = list(range(len(x))) + # Compute the values for complex type in python + p_r = [complex(x[i]) ** complex(y[i]) for i in lx] + # Substitute a result allowed by C99 standard + p_r[4] = complex(np.inf, np.nan) + # Do the same with numpy arrays + n_r = x ** y + for i in lx: + assert_almost_equal(n_r[i], p_r[i], err_msg='Loop %d\n' % i) + +class TestCabs(object): + def setUp(self): + self.olderr = np.seterr(invalid='ignore') + + def tearDown(self): + np.seterr(**self.olderr) + + def test_simple(self): + x = np.array([1+1j, 0+2j, 1+2j, np.inf, np.nan]) + y_r = np.array([np.sqrt(2.), 2, np.sqrt(5), np.inf, np.nan]) + y = np.abs(x) + for i in range(len(x)): + assert_almost_equal(y[i], y_r[i]) + + def test_fabs(self): + # Test that np.abs(x +- 0j) == np.abs(x) (as mandated by C99 for cabs) + x = np.array([1+0j], dtype=complex) + assert_array_equal(np.abs(x), np.real(x)) + + x = np.array([complex(1, np.NZERO)], dtype=complex) + assert_array_equal(np.abs(x), np.real(x)) + + x = np.array([complex(np.inf, np.NZERO)], dtype=complex) + assert_array_equal(np.abs(x), np.real(x)) + + x = np.array([complex(np.nan, np.NZERO)], dtype=complex) + assert_array_equal(np.abs(x), np.real(x)) + + def test_cabs_inf_nan(self): + x, y = [], [] + + # cabs(+-nan + nani) returns nan + x.append(np.nan) + y.append(np.nan) + yield check_real_value, np.abs, np.nan, np.nan, np.nan + + x.append(np.nan) + y.append(-np.nan) + yield check_real_value, np.abs, -np.nan, np.nan, np.nan + + # According to C99 standard, if exactly one of the real/part is inf and + # the other nan, then cabs should return inf + x.append(np.inf) + y.append(np.nan) + yield check_real_value, np.abs, np.inf, np.nan, np.inf + + x.append(-np.inf) + y.append(np.nan) + yield check_real_value, np.abs, -np.inf, np.nan, np.inf + + # cabs(conj(z)) == conj(cabs(z)) (= cabs(z)) + def f(a): + return np.abs(np.conj(a)) + + def g(a, b): + return np.abs(complex(a, b)) + + xa = np.array(x, dtype=complex) + for i in range(len(xa)): + ref = g(x[i], y[i]) + yield check_real_value, f, x[i], y[i], ref + +class TestCarg(object): + def test_simple(self): + check_real_value(ncu._arg, 1, 0, 0, False) + check_real_value(ncu._arg, 0, 1, 0.5*np.pi, False) + + check_real_value(ncu._arg, 1, 1, 0.25*np.pi, False) + check_real_value(ncu._arg, np.PZERO, np.PZERO, np.PZERO) + + @dec.knownfailureif(True, + "Complex arithmetic with signed zero is buggy on most implementation") + def test_zero(self): + # carg(-0 +- 0i) returns +- pi + yield check_real_value, ncu._arg, np.NZERO, np.PZERO, np.pi, False + yield check_real_value, ncu._arg, np.NZERO, np.NZERO, -np.pi, False + + # carg(+0 +- 0i) returns +- 0 + yield check_real_value, ncu._arg, np.PZERO, np.PZERO, np.PZERO + yield check_real_value, ncu._arg, np.PZERO, np.NZERO, np.NZERO + + # carg(x +- 0i) returns +- 0 for x > 0 + yield check_real_value, ncu._arg, 1, np.PZERO, np.PZERO, False + yield check_real_value, ncu._arg, 1, np.NZERO, np.NZERO, False + + # carg(x +- 0i) returns +- pi for x < 0 + yield check_real_value, ncu._arg, -1, np.PZERO, np.pi, False + yield check_real_value, ncu._arg, -1, np.NZERO, -np.pi, False + + # carg(+- 0 + yi) returns pi/2 for y > 0 + yield check_real_value, ncu._arg, np.PZERO, 1, 0.5 * np.pi, False + yield check_real_value, ncu._arg, np.NZERO, 1, 0.5 * np.pi, False + + # carg(+- 0 + yi) returns -pi/2 for y < 0 + yield check_real_value, ncu._arg, np.PZERO, -1, 0.5 * np.pi, False + yield check_real_value, ncu._arg, np.NZERO, -1, -0.5 * np.pi, False + + #def test_branch_cuts(self): + # _check_branch_cut(ncu._arg, -1, 1j, -1, 1) + + def test_special_values(self): + # carg(-np.inf +- yi) returns +-pi for finite y > 0 + yield check_real_value, ncu._arg, -np.inf, 1, np.pi, False + yield check_real_value, ncu._arg, -np.inf, -1, -np.pi, False + + # carg(np.inf +- yi) returns +-0 for finite y > 0 + yield check_real_value, ncu._arg, np.inf, 1, np.PZERO, False + yield check_real_value, ncu._arg, np.inf, -1, np.NZERO, False + + # carg(x +- np.infi) returns +-pi/2 for finite x + yield check_real_value, ncu._arg, 1, np.inf, 0.5 * np.pi, False + yield check_real_value, ncu._arg, 1, -np.inf, -0.5 * np.pi, False + + # carg(-np.inf +- np.infi) returns +-3pi/4 + yield check_real_value, ncu._arg, -np.inf, np.inf, 0.75 * np.pi, False + yield check_real_value, ncu._arg, -np.inf, -np.inf, -0.75 * np.pi, False + + # carg(np.inf +- np.infi) returns +-pi/4 + yield check_real_value, ncu._arg, np.inf, np.inf, 0.25 * np.pi, False + yield check_real_value, ncu._arg, np.inf, -np.inf, -0.25 * np.pi, False + + # carg(x + yi) returns np.nan if x or y is nan + yield check_real_value, ncu._arg, np.nan, 0, np.nan, False + yield check_real_value, ncu._arg, 0, np.nan, np.nan, False + + yield check_real_value, ncu._arg, np.nan, np.inf, np.nan, False + yield check_real_value, ncu._arg, np.inf, np.nan, np.nan, False + +def check_real_value(f, x1, y1, x, exact=True): + z1 = np.array([complex(x1, y1)]) + if exact: + assert_equal(f(z1), x) + else: + assert_almost_equal(f(z1), x) + +def check_complex_value(f, x1, y1, x2, y2, exact=True): + z1 = np.array([complex(x1, y1)]) + z2 = complex(x2, y2) + with np.errstate(invalid='ignore'): + if exact: + assert_equal(f(z1), z2) + else: + assert_almost_equal(f(z1), z2) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/core/tests/test_unicode.py b/numpy/core/tests/test_unicode.py new file mode 100644 index 0000000..8c502ca --- /dev/null +++ b/numpy/core/tests/test_unicode.py @@ -0,0 +1,401 @@ +from __future__ import division, absolute_import, print_function + +import sys + +import numpy as np +from numpy.compat import unicode +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal) + +# Guess the UCS length for this python interpreter +if sys.version_info[:2] >= (3, 3): + # Python 3.3 uses a flexible string representation + ucs4 = False + + def buffer_length(arr): + if isinstance(arr, unicode): + arr = str(arr) + if not arr: + charmax = 0 + else: + charmax = max([ord(c) for c in arr]) + if charmax < 256: + size = 1 + elif charmax < 65536: + size = 2 + else: + size = 4 + return size * len(arr) + v = memoryview(arr) + if v.shape is None: + return len(v) * v.itemsize + else: + return np.prod(v.shape) * v.itemsize +else: + if len(buffer(u'u')) == 4: + ucs4 = True + else: + ucs4 = False + + def buffer_length(arr): + if isinstance(arr, np.ndarray): + return len(arr.data) + return len(buffer(arr)) + +# In both cases below we need to make sure that the byte swapped value (as +# UCS4) is still a valid unicode: +# Value that can be represented in UCS2 interpreters +ucs2_value = u'\u0900' +# Value that cannot be represented in UCS2 interpreters (but can in UCS4) +ucs4_value = u'\U00100900' + + +def test_string_cast(): + str_arr = np.array(["1234", "1234\0\0"], dtype='S') + uni_arr1 = str_arr.astype('>U') + uni_arr2 = str_arr.astype('>> _lib = np.ctypeslib.load_library('libmystuff', '.') #doctest: +SKIP + +Our result type, an ndarray that must be of type double, be 1-dimensional +and is C-contiguous in memory: + +>>> array_1d_double = np.ctypeslib.ndpointer( +... dtype=np.double, +... ndim=1, flags='CONTIGUOUS') #doctest: +SKIP + +Our C-function typically takes an array and updates its values +in-place. For example:: + + void foo_func(double* x, int length) + { + int i; + for (i = 0; i < length; i++) { + x[i] = i*i; + } + } + +We wrap it using: + +>>> _lib.foo_func.restype = None #doctest: +SKIP +>>> _lib.foo_func.argtypes = [array_1d_double, c_int] #doctest: +SKIP + +Then, we're ready to call ``foo_func``: + +>>> out = np.empty(15, dtype=np.double) +>>> _lib.foo_func(out, len(out)) #doctest: +SKIP + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['load_library', 'ndpointer', 'test', 'ctypes_load_library', + 'c_intp', 'as_ctypes', 'as_array'] + +import sys, os +from numpy import integer, ndarray, dtype as _dtype, deprecate, array +from numpy.core.multiarray import _flagdict, flagsobj + +try: + import ctypes +except ImportError: + ctypes = None + +if ctypes is None: + def _dummy(*args, **kwds): + """ + Dummy object that raises an ImportError if ctypes is not available. + + Raises + ------ + ImportError + If ctypes is not available. + + """ + raise ImportError("ctypes is not available.") + ctypes_load_library = _dummy + load_library = _dummy + as_ctypes = _dummy + as_array = _dummy + from numpy import intp as c_intp + _ndptr_base = object +else: + import numpy.core._internal as nic + c_intp = nic._getintp_ctype() + del nic + _ndptr_base = ctypes.c_void_p + + # Adapted from Albert Strasheim + def load_library(libname, loader_path): + """ + It is possible to load a library using + >>> lib = ctypes.cdll[] + + But there are cross-platform considerations, such as library file extensions, + plus the fact Windows will just load the first library it finds with that name. + NumPy supplies the load_library function as a convenience. + + Parameters + ---------- + libname : str + Name of the library, which can have 'lib' as a prefix, + but without an extension. + loader_path : str + Where the library can be found. + + Returns + ------- + ctypes.cdll[libpath] : library object + A ctypes library object + + Raises + ------ + OSError + If there is no library with the expected extension, or the + library is defective and cannot be loaded. + """ + if ctypes.__version__ < '1.0.1': + import warnings + warnings.warn("All features of ctypes interface may not work " \ + "with ctypes < 1.0.1", stacklevel=2) + + ext = os.path.splitext(libname)[1] + if not ext: + # Try to load library with platform-specific name, otherwise + # default to libname.[so|pyd]. Sometimes, these files are built + # erroneously on non-linux platforms. + from numpy.distutils.misc_util import get_shared_lib_extension + so_ext = get_shared_lib_extension() + libname_ext = [libname + so_ext] + # mac, windows and linux >= py3.2 shared library and loadable + # module have different extensions so try both + so_ext2 = get_shared_lib_extension(is_python_ext=True) + if not so_ext2 == so_ext: + libname_ext.insert(0, libname + so_ext2) + else: + libname_ext = [libname] + + loader_path = os.path.abspath(loader_path) + if not os.path.isdir(loader_path): + libdir = os.path.dirname(loader_path) + else: + libdir = loader_path + + for ln in libname_ext: + libpath = os.path.join(libdir, ln) + if os.path.exists(libpath): + try: + return ctypes.cdll[libpath] + except OSError: + ## defective lib file + raise + ## if no successful return in the libname_ext loop: + raise OSError("no file with expected extension") + + ctypes_load_library = deprecate(load_library, 'ctypes_load_library', + 'load_library') + +def _num_fromflags(flaglist): + num = 0 + for val in flaglist: + num += _flagdict[val] + return num + +_flagnames = ['C_CONTIGUOUS', 'F_CONTIGUOUS', 'ALIGNED', 'WRITEABLE', + 'OWNDATA', 'UPDATEIFCOPY', 'WRITEBACKIFCOPY'] +def _flags_fromnum(num): + res = [] + for key in _flagnames: + value = _flagdict[key] + if (num & value): + res.append(key) + return res + + +class _ndptr(_ndptr_base): + + def _check_retval_(self): + """This method is called when this class is used as the .restype + attribute for a shared-library function. It constructs a numpy + array from a void pointer.""" + return array(self) + + @property + def __array_interface__(self): + return {'descr': self._dtype_.descr, + '__ref': self, + 'strides': None, + 'shape': self._shape_, + 'version': 3, + 'typestr': self._dtype_.descr[0][1], + 'data': (self.value, False), + } + + @classmethod + def from_param(cls, obj): + if not isinstance(obj, ndarray): + raise TypeError("argument must be an ndarray") + if cls._dtype_ is not None \ + and obj.dtype != cls._dtype_: + raise TypeError("array must have data type %s" % cls._dtype_) + if cls._ndim_ is not None \ + and obj.ndim != cls._ndim_: + raise TypeError("array must have %d dimension(s)" % cls._ndim_) + if cls._shape_ is not None \ + and obj.shape != cls._shape_: + raise TypeError("array must have shape %s" % str(cls._shape_)) + if cls._flags_ is not None \ + and ((obj.flags.num & cls._flags_) != cls._flags_): + raise TypeError("array must have flags %s" % + _flags_fromnum(cls._flags_)) + return obj.ctypes + + +# Factory for an array-checking class with from_param defined for +# use with ctypes argtypes mechanism +_pointer_type_cache = {} +def ndpointer(dtype=None, ndim=None, shape=None, flags=None): + """ + Array-checking restype/argtypes. + + An ndpointer instance is used to describe an ndarray in restypes + and argtypes specifications. This approach is more flexible than + using, for example, ``POINTER(c_double)``, since several restrictions + can be specified, which are verified upon calling the ctypes function. + These include data type, number of dimensions, shape and flags. If a + given array does not satisfy the specified restrictions, + a ``TypeError`` is raised. + + Parameters + ---------- + dtype : data-type, optional + Array data-type. + ndim : int, optional + Number of array dimensions. + shape : tuple of ints, optional + Array shape. + flags : str or tuple of str + Array flags; may be one or more of: + + - C_CONTIGUOUS / C / CONTIGUOUS + - F_CONTIGUOUS / F / FORTRAN + - OWNDATA / O + - WRITEABLE / W + - ALIGNED / A + - WRITEBACKIFCOPY / X + - UPDATEIFCOPY / U + + Returns + ------- + klass : ndpointer type object + A type object, which is an ``_ndtpr`` instance containing + dtype, ndim, shape and flags information. + + Raises + ------ + TypeError + If a given array does not satisfy the specified restrictions. + + Examples + -------- + >>> clib.somefunc.argtypes = [np.ctypeslib.ndpointer(dtype=np.float64, + ... ndim=1, + ... flags='C_CONTIGUOUS')] + ... #doctest: +SKIP + >>> clib.somefunc(np.array([1, 2, 3], dtype=np.float64)) + ... #doctest: +SKIP + + """ + + if dtype is not None: + dtype = _dtype(dtype) + num = None + if flags is not None: + if isinstance(flags, str): + flags = flags.split(',') + elif isinstance(flags, (int, integer)): + num = flags + flags = _flags_fromnum(num) + elif isinstance(flags, flagsobj): + num = flags.num + flags = _flags_fromnum(num) + if num is None: + try: + flags = [x.strip().upper() for x in flags] + except Exception: + raise TypeError("invalid flags specification") + num = _num_fromflags(flags) + try: + return _pointer_type_cache[(dtype, ndim, shape, num)] + except KeyError: + pass + if dtype is None: + name = 'any' + elif dtype.names: + name = str(id(dtype)) + else: + name = dtype.str + if ndim is not None: + name += "_%dd" % ndim + if shape is not None: + try: + strshape = [str(x) for x in shape] + except TypeError: + strshape = [str(shape)] + shape = (shape,) + shape = tuple(shape) + name += "_"+"x".join(strshape) + if flags is not None: + name += "_"+"_".join(flags) + else: + flags = [] + klass = type("ndpointer_%s"%name, (_ndptr,), + {"_dtype_": dtype, + "_shape_" : shape, + "_ndim_" : ndim, + "_flags_" : num}) + _pointer_type_cache[(dtype, shape, ndim, num)] = klass + return klass + +if ctypes is not None: + ct = ctypes + ################################################################ + # simple types + + # maps the numpy typecodes like ' t_obj: + return True + except OSError: + # no object counts as newer (shouldn't happen if dep_file exists) + return True + + return False + + +def replace_method(klass, method_name, func): + if sys.version_info[0] < 3: + m = types.MethodType(func, None, klass) + else: + # Py3k does not have unbound method anymore, MethodType does not work + m = lambda self, *args, **kw: func(self, *args, **kw) + setattr(klass, method_name, m) + + +###################################################################### +## Method that subclasses may redefine. But don't call this method, +## it i private to CCompiler class and may return unexpected +## results if used elsewhere. So, you have been warned.. + +def CCompiler_find_executables(self): + """ + Does nothing here, but is called by the get_version method and can be + overridden by subclasses. In particular it is redefined in the `FCompiler` + class where more documentation can be found. + + """ + pass + + +replace_method(CCompiler, 'find_executables', CCompiler_find_executables) + + +# Using customized CCompiler.spawn. +def CCompiler_spawn(self, cmd, display=None): + """ + Execute a command in a sub-process. + + Parameters + ---------- + cmd : str + The command to execute. + display : str or sequence of str, optional + The text to add to the log file kept by `numpy.distutils`. + If not given, `display` is equal to `cmd`. + + Returns + ------- + None + + Raises + ------ + DistutilsExecError + If the command failed, i.e. the exit status was not 0. + + """ + if display is None: + display = cmd + if is_sequence(display): + display = ' '.join(list(display)) + log.info(display) + s, o = exec_command(cmd) + if s: + if is_sequence(cmd): + cmd = ' '.join(list(cmd)) + try: + print(o) + except UnicodeError: + # When installing through pip, `o` can contain non-ascii chars + pass + if re.search('Too many open files', o): + msg = '\nTry rerunning setup command until build succeeds.' + else: + msg = '' + raise DistutilsExecError('Command "%s" failed with exit status %d%s' % (cmd, s, msg)) + +replace_method(CCompiler, 'spawn', CCompiler_spawn) + +def CCompiler_object_filenames(self, source_filenames, strip_dir=0, output_dir=''): + """ + Return the name of the object files for the given source files. + + Parameters + ---------- + source_filenames : list of str + The list of paths to source files. Paths can be either relative or + absolute, this is handled transparently. + strip_dir : bool, optional + Whether to strip the directory from the returned paths. If True, + the file name prepended by `output_dir` is returned. Default is False. + output_dir : str, optional + If given, this path is prepended to the returned paths to the + object files. + + Returns + ------- + obj_names : list of str + The list of paths to the object files corresponding to the source + files in `source_filenames`. + + """ + if output_dir is None: + output_dir = '' + obj_names = [] + for src_name in source_filenames: + base, ext = os.path.splitext(os.path.normpath(src_name)) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / + if base.startswith('..'): + # Resolve starting relative path components, middle ones + # (if any) have been handled by os.path.normpath above. + i = base.rfind('..')+2 + d = base[:i] + d = os.path.basename(os.path.abspath(d)) + base = d + base[i:] + if ext not in self.src_extensions: + raise UnknownFileError("unknown file type '%s' (from '%s')" % (ext, src_name)) + if strip_dir: + base = os.path.basename(base) + obj_name = os.path.join(output_dir, base + self.obj_extension) + obj_names.append(obj_name) + return obj_names + +replace_method(CCompiler, 'object_filenames', CCompiler_object_filenames) + +def CCompiler_compile(self, sources, output_dir=None, macros=None, + include_dirs=None, debug=0, extra_preargs=None, + extra_postargs=None, depends=None): + """ + Compile one or more source files. + + Please refer to the Python distutils API reference for more details. + + Parameters + ---------- + sources : list of str + A list of filenames + output_dir : str, optional + Path to the output directory. + macros : list of tuples + A list of macro definitions. + include_dirs : list of str, optional + The directories to add to the default include file search path for + this compilation only. + debug : bool, optional + Whether or not to output debug symbols in or alongside the object + file(s). + extra_preargs, extra_postargs : ? + Extra pre- and post-arguments. + depends : list of str, optional + A list of file names that all targets depend on. + + Returns + ------- + objects : list of str + A list of object file names, one per source file `sources`. + + Raises + ------ + CompileError + If compilation fails. + + """ + # This method is effective only with Python >=2.3 distutils. + # Any changes here should be applied also to fcompiler.compile + # method to support pre Python 2.3 distutils. + global _job_semaphore + + jobs = get_num_build_jobs() + + # setup semaphore to not exceed number of compile jobs when parallelized at + # extension level (python >= 3.5) + with _global_lock: + if _job_semaphore is None: + _job_semaphore = threading.Semaphore(jobs) + + if not sources: + return [] + # FIXME:RELATIVE_IMPORT + if sys.version_info[0] < 3: + from .fcompiler import FCompiler, is_f_file, has_f90_header + else: + from numpy.distutils.fcompiler import (FCompiler, is_f_file, + has_f90_header) + if isinstance(self, FCompiler): + display = [] + for fc in ['f77', 'f90', 'fix']: + fcomp = getattr(self, 'compiler_'+fc) + if fcomp is None: + continue + display.append("Fortran %s compiler: %s" % (fc, ' '.join(fcomp))) + display = '\n'.join(display) + else: + ccomp = self.compiler_so + display = "C compiler: %s\n" % (' '.join(ccomp),) + log.info(display) + macros, objects, extra_postargs, pp_opts, build = \ + self._setup_compile(output_dir, macros, include_dirs, sources, + depends, extra_postargs) + cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) + display = "compile options: '%s'" % (' '.join(cc_args)) + if extra_postargs: + display += "\nextra options: '%s'" % (' '.join(extra_postargs)) + log.info(display) + + def single_compile(args): + obj, (src, ext) = args + if not _needs_build(obj, cc_args, extra_postargs, pp_opts): + return + + # check if we are currently already processing the same object + # happens when using the same source in multiple extensions + while True: + # need explicit lock as there is no atomic check and add with GIL + with _global_lock: + # file not being worked on, start working + if obj not in _processing_files: + _processing_files.add(obj) + break + # wait for the processing to end + time.sleep(0.1) + + try: + # retrieve slot from our #job semaphore and build + with _job_semaphore: + self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) + finally: + # register being done processing + with _global_lock: + _processing_files.remove(obj) + + + if isinstance(self, FCompiler): + objects_to_build = list(build.keys()) + f77_objects, other_objects = [], [] + for obj in objects: + if obj in objects_to_build: + src, ext = build[obj] + if self.compiler_type=='absoft': + obj = cyg2win32(obj) + src = cyg2win32(src) + if is_f_file(src) and not has_f90_header(src): + f77_objects.append((obj, (src, ext))) + else: + other_objects.append((obj, (src, ext))) + + # f77 objects can be built in parallel + build_items = f77_objects + # build f90 modules serial, module files are generated during + # compilation and may be used by files later in the list so the + # ordering is important + for o in other_objects: + single_compile(o) + else: + build_items = build.items() + + if len(build) > 1 and jobs > 1: + # build parallel + import multiprocessing.pool + pool = multiprocessing.pool.ThreadPool(jobs) + pool.map(single_compile, build_items) + pool.close() + else: + # build serial + for o in build_items: + single_compile(o) + + # Return *all* object filenames, not just the ones we just built. + return objects + +replace_method(CCompiler, 'compile', CCompiler_compile) + +def CCompiler_customize_cmd(self, cmd, ignore=()): + """ + Customize compiler using distutils command. + + Parameters + ---------- + cmd : class instance + An instance inheriting from `distutils.cmd.Command`. + ignore : sequence of str, optional + List of `CCompiler` commands (without ``'set_'``) that should not be + altered. Strings that are checked for are: + ``('include_dirs', 'define', 'undef', 'libraries', 'library_dirs', + 'rpath', 'link_objects')``. + + Returns + ------- + None + + """ + log.info('customize %s using %s' % (self.__class__.__name__, + cmd.__class__.__name__)) + def allow(attr): + return getattr(cmd, attr, None) is not None and attr not in ignore + + if allow('include_dirs'): + self.set_include_dirs(cmd.include_dirs) + if allow('define'): + for (name, value) in cmd.define: + self.define_macro(name, value) + if allow('undef'): + for macro in cmd.undef: + self.undefine_macro(macro) + if allow('libraries'): + self.set_libraries(self.libraries + cmd.libraries) + if allow('library_dirs'): + self.set_library_dirs(self.library_dirs + cmd.library_dirs) + if allow('rpath'): + self.set_runtime_library_dirs(cmd.rpath) + if allow('link_objects'): + self.set_link_objects(cmd.link_objects) + +replace_method(CCompiler, 'customize_cmd', CCompiler_customize_cmd) + +def _compiler_to_string(compiler): + props = [] + mx = 0 + keys = list(compiler.executables.keys()) + for key in ['version', 'libraries', 'library_dirs', + 'object_switch', 'compile_switch', + 'include_dirs', 'define', 'undef', 'rpath', 'link_objects']: + if key not in keys: + keys.append(key) + for key in keys: + if hasattr(compiler, key): + v = getattr(compiler, key) + mx = max(mx, len(key)) + props.append((key, repr(v))) + lines = [] + format = '%-' + repr(mx+1) + 's = %s' + for prop in props: + lines.append(format % prop) + return '\n'.join(lines) + +def CCompiler_show_customization(self): + """ + Print the compiler customizations to stdout. + + Parameters + ---------- + None + + Returns + ------- + None + + Notes + ----- + Printing is only done if the distutils log threshold is < 2. + + """ + if 0: + for attrname in ['include_dirs', 'define', 'undef', + 'libraries', 'library_dirs', + 'rpath', 'link_objects']: + attr = getattr(self, attrname, None) + if not attr: + continue + log.info("compiler '%s' is set to %s" % (attrname, attr)) + try: + self.get_version() + except Exception: + pass + if log._global_log.threshold<2: + print('*'*80) + print(self.__class__) + print(_compiler_to_string(self)) + print('*'*80) + +replace_method(CCompiler, 'show_customization', CCompiler_show_customization) + +def CCompiler_customize(self, dist, need_cxx=0): + """ + Do any platform-specific customization of a compiler instance. + + This method calls `distutils.sysconfig.customize_compiler` for + platform-specific customization, as well as optionally remove a flag + to suppress spurious warnings in case C++ code is being compiled. + + Parameters + ---------- + dist : object + This parameter is not used for anything. + need_cxx : bool, optional + Whether or not C++ has to be compiled. If so (True), the + ``"-Wstrict-prototypes"`` option is removed to prevent spurious + warnings. Default is False. + + Returns + ------- + None + + Notes + ----- + All the default options used by distutils can be extracted with:: + + from distutils import sysconfig + sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', + 'CCSHARED', 'LDSHARED', 'SO') + + """ + # See FCompiler.customize for suggested usage. + log.info('customize %s' % (self.__class__.__name__)) + customize_compiler(self) + if need_cxx: + # In general, distutils uses -Wstrict-prototypes, but this option is + # not valid for C++ code, only for C. Remove it if it's there to + # avoid a spurious warning on every compilation. + try: + self.compiler_so.remove('-Wstrict-prototypes') + except (AttributeError, ValueError): + pass + + if hasattr(self, 'compiler') and 'cc' in self.compiler[0]: + if not self.compiler_cxx: + if self.compiler[0].startswith('gcc'): + a, b = 'gcc', 'g++' + else: + a, b = 'cc', 'c++' + self.compiler_cxx = [self.compiler[0].replace(a, b)]\ + + self.compiler[1:] + else: + if hasattr(self, 'compiler'): + log.warn("#### %s #######" % (self.compiler,)) + if not hasattr(self, 'compiler_cxx'): + log.warn('Missing compiler_cxx fix for ' + self.__class__.__name__) + + + # check if compiler supports gcc style automatic dependencies + # run on every extension so skip for known good compilers + if hasattr(self, 'compiler') and ('gcc' in self.compiler[0] or + 'g++' in self.compiler[0] or + 'clang' in self.compiler[0]): + self._auto_depends = True + elif os.name == 'posix': + import tempfile + import shutil + tmpdir = tempfile.mkdtemp() + try: + fn = os.path.join(tmpdir, "file.c") + with open(fn, "w") as f: + f.write("int a;\n") + self.compile([fn], output_dir=tmpdir, + extra_preargs=['-MMD', '-MF', fn + '.d']) + self._auto_depends = True + except CompileError: + self._auto_depends = False + finally: + shutil.rmtree(tmpdir) + + return + +replace_method(CCompiler, 'customize', CCompiler_customize) + +def simple_version_match(pat=r'[-.\d]+', ignore='', start=''): + """ + Simple matching of version numbers, for use in CCompiler and FCompiler. + + Parameters + ---------- + pat : str, optional + A regular expression matching version numbers. + Default is ``r'[-.\\d]+'``. + ignore : str, optional + A regular expression matching patterns to skip. + Default is ``''``, in which case nothing is skipped. + start : str, optional + A regular expression matching the start of where to start looking + for version numbers. + Default is ``''``, in which case searching is started at the + beginning of the version string given to `matcher`. + + Returns + ------- + matcher : callable + A function that is appropriate to use as the ``.version_match`` + attribute of a `CCompiler` class. `matcher` takes a single parameter, + a version string. + + """ + def matcher(self, version_string): + # version string may appear in the second line, so getting rid + # of new lines: + version_string = version_string.replace('\n', ' ') + pos = 0 + if start: + m = re.match(start, version_string) + if not m: + return None + pos = m.end() + while True: + m = re.search(pat, version_string[pos:]) + if not m: + return None + if ignore and re.match(ignore, m.group(0)): + pos = m.end() + continue + break + return m.group(0) + return matcher + +def CCompiler_get_version(self, force=False, ok_status=[0]): + """ + Return compiler version, or None if compiler is not available. + + Parameters + ---------- + force : bool, optional + If True, force a new determination of the version, even if the + compiler already has a version attribute. Default is False. + ok_status : list of int, optional + The list of status values returned by the version look-up process + for which a version string is returned. If the status value is not + in `ok_status`, None is returned. Default is ``[0]``. + + Returns + ------- + version : str or None + Version string, in the format of `distutils.version.LooseVersion`. + + """ + if not force and hasattr(self, 'version'): + return self.version + self.find_executables() + try: + version_cmd = self.version_cmd + except AttributeError: + return None + if not version_cmd or not version_cmd[0]: + return None + try: + matcher = self.version_match + except AttributeError: + try: + pat = self.version_pattern + except AttributeError: + return None + def matcher(version_string): + m = re.match(pat, version_string) + if not m: + return None + version = m.group('version') + return version + + status, output = exec_command(version_cmd, use_tee=0) + + version = None + if status in ok_status: + version = matcher(output) + if version: + version = LooseVersion(version) + self.version = version + return version + +replace_method(CCompiler, 'get_version', CCompiler_get_version) + +def CCompiler_cxx_compiler(self): + """ + Return the C++ compiler. + + Parameters + ---------- + None + + Returns + ------- + cxx : class instance + The C++ compiler, as a `CCompiler` instance. + + """ + if self.compiler_type in ('msvc', 'intelw', 'intelemw'): + return self + + cxx = copy(self) + cxx.compiler_so = [cxx.compiler_cxx[0]] + cxx.compiler_so[1:] + if sys.platform.startswith('aix') and 'ld_so_aix' in cxx.linker_so[0]: + # AIX needs the ld_so_aix script included with Python + cxx.linker_so = [cxx.linker_so[0], cxx.compiler_cxx[0]] \ + + cxx.linker_so[2:] + else: + cxx.linker_so = [cxx.compiler_cxx[0]] + cxx.linker_so[1:] + return cxx + +replace_method(CCompiler, 'cxx_compiler', CCompiler_cxx_compiler) + +compiler_class['intel'] = ('intelccompiler', 'IntelCCompiler', + "Intel C Compiler for 32-bit applications") +compiler_class['intele'] = ('intelccompiler', 'IntelItaniumCCompiler', + "Intel C Itanium Compiler for Itanium-based applications") +compiler_class['intelem'] = ('intelccompiler', 'IntelEM64TCCompiler', + "Intel C Compiler for 64-bit applications") +compiler_class['intelw'] = ('intelccompiler', 'IntelCCompilerW', + "Intel C Compiler for 32-bit applications on Windows") +compiler_class['intelemw'] = ('intelccompiler', 'IntelEM64TCCompilerW', + "Intel C Compiler for 64-bit applications on Windows") +compiler_class['pathcc'] = ('pathccompiler', 'PathScaleCCompiler', + "PathScale Compiler for SiCortex-based applications") +ccompiler._default_compilers += (('linux.*', 'intel'), + ('linux.*', 'intele'), + ('linux.*', 'intelem'), + ('linux.*', 'pathcc'), + ('nt', 'intelw'), + ('nt', 'intelemw')) + +if sys.platform == 'win32': + compiler_class['mingw32'] = ('mingw32ccompiler', 'Mingw32CCompiler', + "Mingw32 port of GNU C Compiler for Win32"\ + "(for MSC built Python)") + if mingw32(): + # On windows platforms, we want to default to mingw32 (gcc) + # because msvc can't build blitz stuff. + log.info('Setting mingw32 as default compiler for nt.') + ccompiler._default_compilers = (('nt', 'mingw32'),) \ + + ccompiler._default_compilers + + +_distutils_new_compiler = new_compiler +def new_compiler (plat=None, + compiler=None, + verbose=0, + dry_run=0, + force=0): + # Try first C compilers from numpy.distutils. + if plat is None: + plat = os.name + try: + if compiler is None: + compiler = get_default_compiler(plat) + (module_name, class_name, long_description) = compiler_class[compiler] + except KeyError: + msg = "don't know how to compile C/C++ code on platform '%s'" % plat + if compiler is not None: + msg = msg + " with '%s' compiler" % compiler + raise DistutilsPlatformError(msg) + module_name = "numpy.distutils." + module_name + try: + __import__ (module_name) + except ImportError: + msg = str(get_exception()) + log.info('%s in numpy.distutils; trying from distutils', + str(msg)) + module_name = module_name[6:] + try: + __import__(module_name) + except ImportError: + msg = str(get_exception()) + raise DistutilsModuleError("can't compile C/C++ code: unable to load module '%s'" % \ + module_name) + try: + module = sys.modules[module_name] + klass = vars(module)[class_name] + except KeyError: + raise DistutilsModuleError(("can't compile C/C++ code: unable to find class '%s' " + + "in module '%s'") % (class_name, module_name)) + compiler = klass(None, dry_run, force) + log.debug('new_compiler returns %s' % (klass)) + return compiler + +ccompiler.new_compiler = new_compiler + +_distutils_gen_lib_options = gen_lib_options +def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries): + library_dirs = quote_args(library_dirs) + runtime_library_dirs = quote_args(runtime_library_dirs) + r = _distutils_gen_lib_options(compiler, library_dirs, + runtime_library_dirs, libraries) + lib_opts = [] + for i in r: + if is_sequence(i): + lib_opts.extend(list(i)) + else: + lib_opts.append(i) + return lib_opts +ccompiler.gen_lib_options = gen_lib_options + +# Also fix up the various compiler modules, which do +# from distutils.ccompiler import gen_lib_options +# Don't bother with mwerks, as we don't support Classic Mac. +for _cc in ['msvc9', 'msvc', '_msvc', 'bcpp', 'cygwinc', 'emxc', 'unixc']: + _m = sys.modules.get('distutils.' + _cc + 'compiler') + if _m is not None: + setattr(_m, 'gen_lib_options', gen_lib_options) + +_distutils_gen_preprocess_options = gen_preprocess_options +def gen_preprocess_options (macros, include_dirs): + include_dirs = quote_args(include_dirs) + return _distutils_gen_preprocess_options(macros, include_dirs) +ccompiler.gen_preprocess_options = gen_preprocess_options + +##Fix distutils.util.split_quoted: +# NOTE: I removed this fix in revision 4481 (see ticket #619), but it appears +# that removing this fix causes f2py problems on Windows XP (see ticket #723). +# Specifically, on WinXP when gfortran is installed in a directory path, which +# contains spaces, then f2py is unable to find it. +import string +_wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace) +_squote_re = re.compile(r"'(?:[^'\\]|\\.)*'") +_dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"') +_has_white_re = re.compile(r'\s') +def split_quoted(s): + s = s.strip() + words = [] + pos = 0 + + while s: + m = _wordchars_re.match(s, pos) + end = m.end() + if end == len(s): + words.append(s[:end]) + break + + if s[end] in string.whitespace: # unescaped, unquoted whitespace: now + words.append(s[:end]) # we definitely have a word delimiter + s = s[end:].lstrip() + pos = 0 + + elif s[end] == '\\': # preserve whatever is being escaped; + # will become part of the current word + s = s[:end] + s[end+1:] + pos = end+1 + + else: + if s[end] == "'": # slurp singly-quoted string + m = _squote_re.match(s, end) + elif s[end] == '"': # slurp doubly-quoted string + m = _dquote_re.match(s, end) + else: + raise RuntimeError("this can't happen (bad char '%c')" % s[end]) + + if m is None: + raise ValueError("bad string (mismatched %s quotes?)" % s[end]) + + (beg, end) = m.span() + if _has_white_re.search(s[beg+1:end-1]): + s = s[:beg] + s[beg+1:end-1] + s[end:] + pos = m.end() - 2 + else: + # Keeping quotes when a quoted word does not contain + # white-space. XXX: send a patch to distutils + pos = m.end() + + if pos >= len(s): + words.append(s) + break + + return words +ccompiler.split_quoted = split_quoted +##Fix distutils.util.split_quoted: diff --git a/numpy/distutils/command/__init__.py b/numpy/distutils/command/__init__.py new file mode 100644 index 0000000..76a2600 --- /dev/null +++ b/numpy/distutils/command/__init__.py @@ -0,0 +1,43 @@ +"""distutils.command + +Package containing implementation of all the standard Distutils +commands. + +""" +from __future__ import division, absolute_import, print_function + +def test_na_writable_attributes_deletion(): + a = np.NA(2) + attr = ['payload', 'dtype'] + for s in attr: + assert_raises(AttributeError, delattr, a, s) + + +__revision__ = "$Id: __init__.py,v 1.3 2005/05/16 11:08:49 pearu Exp $" + +distutils_all = [ #'build_py', + 'clean', + 'install_clib', + 'install_scripts', + 'bdist', + 'bdist_dumb', + 'bdist_wininst', + ] + +__import__('distutils.command', globals(), locals(), distutils_all) + +__all__ = ['build', + 'config_compiler', + 'config', + 'build_src', + 'build_py', + 'build_ext', + 'build_clib', + 'build_scripts', + 'install', + 'install_data', + 'install_headers', + 'install_lib', + 'bdist_rpm', + 'sdist', + ] + distutils_all diff --git a/numpy/distutils/command/autodist.py b/numpy/distutils/command/autodist.py new file mode 100644 index 0000000..d5e7896 --- /dev/null +++ b/numpy/distutils/command/autodist.py @@ -0,0 +1,96 @@ +"""This module implements additional tests ala autoconf which can be useful. + +""" +from __future__ import division, absolute_import, print_function + + +# We put them here since they could be easily reused outside numpy.distutils + +def check_inline(cmd): + """Return the inline identifier (may be empty).""" + cmd._check_compiler() + body = """ +#ifndef __cplusplus +static %(inline)s int static_func (void) +{ + return 0; +} +%(inline)s int nostatic_func (void) +{ + return 0; +} +#endif""" + + for kw in ['inline', '__inline__', '__inline']: + st = cmd.try_compile(body % {'inline': kw}, None, None) + if st: + return kw + + return '' + +def check_restrict(cmd): + """Return the restrict identifier (may be empty).""" + cmd._check_compiler() + body = """ +static int static_func (char * %(restrict)s a) +{ + return 0; +} +""" + + for kw in ['restrict', '__restrict__', '__restrict']: + st = cmd.try_compile(body % {'restrict': kw}, None, None) + if st: + return kw + + return '' + +def check_compiler_gcc4(cmd): + """Return True if the C compiler is GCC 4.x.""" + cmd._check_compiler() + body = """ +int +main() +{ +#if (! defined __GNUC__) || (__GNUC__ < 4) +#error gcc >= 4 required +#endif + return 0; +} +""" + return cmd.try_compile(body, None, None) + + +def check_gcc_function_attribute(cmd, attribute, name): + """Return True if the given function attribute is supported.""" + cmd._check_compiler() + body = """ +#pragma GCC diagnostic error "-Wattributes" +#pragma clang diagnostic error "-Wattributes" + +int %s %s(void*); + +int +main() +{ + return 0; +} +""" % (attribute, name) + return cmd.try_compile(body, None, None) != 0 + +def check_gcc_variable_attribute(cmd, attribute): + """Return True if the given variable attribute is supported.""" + cmd._check_compiler() + body = """ +#pragma GCC diagnostic error "-Wattributes" +#pragma clang diagnostic error "-Wattributes" + +int %s foo; + +int +main() +{ + return 0; +} +""" % (attribute, ) + return cmd.try_compile(body, None, None) != 0 diff --git a/numpy/distutils/command/bdist_rpm.py b/numpy/distutils/command/bdist_rpm.py new file mode 100644 index 0000000..3e52a50 --- /dev/null +++ b/numpy/distutils/command/bdist_rpm.py @@ -0,0 +1,24 @@ +from __future__ import division, absolute_import, print_function + +import os +import sys +if 'setuptools' in sys.modules: + from setuptools.command.bdist_rpm import bdist_rpm as old_bdist_rpm +else: + from distutils.command.bdist_rpm import bdist_rpm as old_bdist_rpm + +class bdist_rpm(old_bdist_rpm): + + def _make_spec_file(self): + spec_file = old_bdist_rpm._make_spec_file(self) + + # Replace hardcoded setup.py script name + # with the real setup script name. + setup_py = os.path.basename(sys.argv[0]) + if setup_py == 'setup.py': + return spec_file + new_spec_file = [] + for line in spec_file: + line = line.replace('setup.py', setup_py) + new_spec_file.append(line) + return new_spec_file diff --git a/numpy/distutils/command/build.py b/numpy/distutils/command/build.py new file mode 100644 index 0000000..3d71015 --- /dev/null +++ b/numpy/distutils/command/build.py @@ -0,0 +1,47 @@ +from __future__ import division, absolute_import, print_function + +import os +import sys +from distutils.command.build import build as old_build +from distutils.util import get_platform +from numpy.distutils.command.config_compiler import show_fortran_compilers + +class build(old_build): + + sub_commands = [('config_cc', lambda *args: True), + ('config_fc', lambda *args: True), + ('build_src', old_build.has_ext_modules), + ] + old_build.sub_commands + + user_options = old_build.user_options + [ + ('fcompiler=', None, + "specify the Fortran compiler type"), + ('parallel=', 'j', + "number of parallel jobs"), + ] + + help_options = old_build.help_options + [ + ('help-fcompiler', None, "list available Fortran compilers", + show_fortran_compilers), + ] + + def initialize_options(self): + old_build.initialize_options(self) + self.fcompiler = None + self.parallel = None + + def finalize_options(self): + if self.parallel: + try: + self.parallel = int(self.parallel) + except ValueError: + raise ValueError("--parallel/-j argument must be an integer") + build_scripts = self.build_scripts + old_build.finalize_options(self) + plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3]) + if build_scripts is None: + self.build_scripts = os.path.join(self.build_base, + 'scripts' + plat_specifier) + + def run(self): + old_build.run(self) diff --git a/numpy/distutils/command/build_clib.py b/numpy/distutils/command/build_clib.py new file mode 100644 index 0000000..910493a --- /dev/null +++ b/numpy/distutils/command/build_clib.py @@ -0,0 +1,323 @@ +""" Modified version of build_clib that handles fortran source files. +""" +from __future__ import division, absolute_import, print_function + +import os +from glob import glob +import shutil +from distutils.command.build_clib import build_clib as old_build_clib +from distutils.errors import DistutilsSetupError, DistutilsError, \ + DistutilsFileError + +from numpy.distutils import log +from distutils.dep_util import newer_group +from numpy.distutils.misc_util import filter_sources, has_f_sources,\ + has_cxx_sources, all_strings, get_lib_source_files, is_sequence, \ + get_numpy_include_dirs + +# Fix Python distutils bug sf #1718574: +_l = old_build_clib.user_options +for _i in range(len(_l)): + if _l[_i][0] in ['build-clib', 'build-temp']: + _l[_i] = (_l[_i][0] + '=',) + _l[_i][1:] +# + + +class build_clib(old_build_clib): + + description = "build C/C++/F libraries used by Python extensions" + + user_options = old_build_clib.user_options + [ + ('fcompiler=', None, + "specify the Fortran compiler type"), + ('inplace', 'i', 'Build in-place'), + ('parallel=', 'j', + "number of parallel jobs"), + ] + + boolean_options = old_build_clib.boolean_options + ['inplace'] + + def initialize_options(self): + old_build_clib.initialize_options(self) + self.fcompiler = None + self.inplace = 0 + self.parallel = None + + def finalize_options(self): + if self.parallel: + try: + self.parallel = int(self.parallel) + except ValueError: + raise ValueError("--parallel/-j argument must be an integer") + old_build_clib.finalize_options(self) + self.set_undefined_options('build', ('parallel', 'parallel')) + + def have_f_sources(self): + for (lib_name, build_info) in self.libraries: + if has_f_sources(build_info.get('sources', [])): + return True + return False + + def have_cxx_sources(self): + for (lib_name, build_info) in self.libraries: + if has_cxx_sources(build_info.get('sources', [])): + return True + return False + + def run(self): + if not self.libraries: + return + + # Make sure that library sources are complete. + languages = [] + + # Make sure that extension sources are complete. + self.run_command('build_src') + + for (lib_name, build_info) in self.libraries: + l = build_info.get('language', None) + if l and l not in languages: + languages.append(l) + + from distutils.ccompiler import new_compiler + self.compiler = new_compiler(compiler=self.compiler, + dry_run=self.dry_run, + force=self.force) + self.compiler.customize(self.distribution, + need_cxx=self.have_cxx_sources()) + + libraries = self.libraries + self.libraries = None + self.compiler.customize_cmd(self) + self.libraries = libraries + + self.compiler.show_customization() + + if self.have_f_sources(): + from numpy.distutils.fcompiler import new_fcompiler + self._f_compiler = new_fcompiler(compiler=self.fcompiler, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90='f90' in languages, + c_compiler=self.compiler) + if self._f_compiler is not None: + self._f_compiler.customize(self.distribution) + + libraries = self.libraries + self.libraries = None + self._f_compiler.customize_cmd(self) + self.libraries = libraries + + self._f_compiler.show_customization() + else: + self._f_compiler = None + + self.build_libraries(self.libraries) + + if self.inplace: + for l in self.distribution.installed_libraries: + libname = self.compiler.library_filename(l.name) + source = os.path.join(self.build_clib, libname) + target = os.path.join(l.target_dir, libname) + self.mkpath(l.target_dir) + shutil.copy(source, target) + + def get_source_files(self): + self.check_library_list(self.libraries) + filenames = [] + for lib in self.libraries: + filenames.extend(get_lib_source_files(lib)) + return filenames + + def build_libraries(self, libraries): + for (lib_name, build_info) in libraries: + self.build_a_library(build_info, lib_name, libraries) + + def build_a_library(self, build_info, lib_name, libraries): + # default compilers + compiler = self.compiler + fcompiler = self._f_compiler + + sources = build_info.get('sources') + if sources is None or not is_sequence(sources): + raise DistutilsSetupError(("in 'libraries' option (library '%s'), " + + "'sources' must be present and must be " + + "a list of source filenames") % lib_name) + sources = list(sources) + + c_sources, cxx_sources, f_sources, fmodule_sources \ + = filter_sources(sources) + requiref90 = not not fmodule_sources or \ + build_info.get('language', 'c') == 'f90' + + # save source type information so that build_ext can use it. + source_languages = [] + if c_sources: + source_languages.append('c') + if cxx_sources: + source_languages.append('c++') + if requiref90: + source_languages.append('f90') + elif f_sources: + source_languages.append('f77') + build_info['source_languages'] = source_languages + + lib_file = compiler.library_filename(lib_name, + output_dir=self.build_clib) + depends = sources + build_info.get('depends', []) + if not (self.force or newer_group(depends, lib_file, 'newer')): + log.debug("skipping '%s' library (up-to-date)", lib_name) + return + else: + log.info("building '%s' library", lib_name) + + config_fc = build_info.get('config_fc', {}) + if fcompiler is not None and config_fc: + log.info('using additional config_fc from setup script ' + 'for fortran compiler: %s' + % (config_fc,)) + from numpy.distutils.fcompiler import new_fcompiler + fcompiler = new_fcompiler(compiler=fcompiler.compiler_type, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90=requiref90, + c_compiler=self.compiler) + if fcompiler is not None: + dist = self.distribution + base_config_fc = dist.get_option_dict('config_fc').copy() + base_config_fc.update(config_fc) + fcompiler.customize(base_config_fc) + + # check availability of Fortran compilers + if (f_sources or fmodule_sources) and fcompiler is None: + raise DistutilsError("library %s has Fortran sources" + " but no Fortran compiler found" % (lib_name)) + + if fcompiler is not None: + fcompiler.extra_f77_compile_args = build_info.get( + 'extra_f77_compile_args') or [] + fcompiler.extra_f90_compile_args = build_info.get( + 'extra_f90_compile_args') or [] + + macros = build_info.get('macros') + include_dirs = build_info.get('include_dirs') + if include_dirs is None: + include_dirs = [] + extra_postargs = build_info.get('extra_compiler_args') or [] + + include_dirs.extend(get_numpy_include_dirs()) + # where compiled F90 module files are: + module_dirs = build_info.get('module_dirs') or [] + module_build_dir = os.path.dirname(lib_file) + if requiref90: + self.mkpath(module_build_dir) + + if compiler.compiler_type == 'msvc': + # this hack works around the msvc compiler attributes + # problem, msvc uses its own convention :( + c_sources += cxx_sources + cxx_sources = [] + + objects = [] + if c_sources: + log.info("compiling C sources") + objects = compiler.compile(c_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs) + + if cxx_sources: + log.info("compiling C++ sources") + cxx_compiler = compiler.cxx_compiler() + cxx_objects = cxx_compiler.compile(cxx_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs) + objects.extend(cxx_objects) + + if f_sources or fmodule_sources: + extra_postargs = [] + f_objects = [] + + if requiref90: + if fcompiler.module_dir_switch is None: + existing_modules = glob('*.mod') + extra_postargs += fcompiler.module_options( + module_dirs, module_build_dir) + + if fmodule_sources: + log.info("compiling Fortran 90 module sources") + f_objects += fcompiler.compile(fmodule_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs) + + if requiref90 and self._f_compiler.module_dir_switch is None: + # move new compiled F90 module files to module_build_dir + for f in glob('*.mod'): + if f in existing_modules: + continue + t = os.path.join(module_build_dir, f) + if os.path.abspath(f) == os.path.abspath(t): + continue + if os.path.isfile(t): + os.remove(t) + try: + self.move_file(f, module_build_dir) + except DistutilsFileError: + log.warn('failed to move %r to %r' + % (f, module_build_dir)) + + if f_sources: + log.info("compiling Fortran sources") + f_objects += fcompiler.compile(f_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs) + else: + f_objects = [] + + if f_objects and not fcompiler.can_ccompiler_link(compiler): + # Default linker cannot link Fortran object files, and results + # need to be wrapped later. Instead of creating a real static + # library, just keep track of the object files. + listfn = os.path.join(self.build_clib, + lib_name + '.fobjects') + with open(listfn, 'w') as f: + f.write("\n".join(os.path.abspath(obj) for obj in f_objects)) + + listfn = os.path.join(self.build_clib, + lib_name + '.cobjects') + with open(listfn, 'w') as f: + f.write("\n".join(os.path.abspath(obj) for obj in objects)) + + # create empty "library" file for dependency tracking + lib_fname = os.path.join(self.build_clib, + lib_name + compiler.static_lib_extension) + with open(lib_fname, 'wb') as f: + pass + else: + # assume that default linker is suitable for + # linking Fortran object files + objects.extend(f_objects) + compiler.create_static_lib(objects, lib_name, + output_dir=self.build_clib, + debug=self.debug) + + # fix library dependencies + clib_libraries = build_info.get('libraries', []) + for lname, binfo in libraries: + if lname in clib_libraries: + clib_libraries.extend(binfo.get('libraries', [])) + if clib_libraries: + build_info['libraries'] = clib_libraries diff --git a/numpy/distutils/command/build_ext.py b/numpy/distutils/command/build_ext.py new file mode 100644 index 0000000..05fc740 --- /dev/null +++ b/numpy/distutils/command/build_ext.py @@ -0,0 +1,586 @@ +""" Modified version of build_ext that handles fortran source files. + +""" +from __future__ import division, absolute_import, print_function + +import os +import sys +import shutil +from glob import glob + +from distutils.dep_util import newer_group +from distutils.command.build_ext import build_ext as old_build_ext +from distutils.errors import DistutilsFileError, DistutilsSetupError,\ + DistutilsError +from distutils.file_util import copy_file + +from numpy.distutils import log +from numpy.distutils.exec_command import exec_command +from numpy.distutils.system_info import combine_paths, system_info +from numpy.distutils.misc_util import filter_sources, has_f_sources, \ + has_cxx_sources, get_ext_source_files, \ + get_numpy_include_dirs, is_sequence, get_build_architecture, \ + msvc_version +from numpy.distutils.command.config_compiler import show_fortran_compilers + + + +class build_ext (old_build_ext): + + description = "build C/C++/F extensions (compile/link to build directory)" + + user_options = old_build_ext.user_options + [ + ('fcompiler=', None, + "specify the Fortran compiler type"), + ('parallel=', 'j', + "number of parallel jobs"), + ] + + help_options = old_build_ext.help_options + [ + ('help-fcompiler', None, "list available Fortran compilers", + show_fortran_compilers), + ] + + def initialize_options(self): + old_build_ext.initialize_options(self) + self.fcompiler = None + self.parallel = None + + def finalize_options(self): + if self.parallel: + try: + self.parallel = int(self.parallel) + except ValueError: + raise ValueError("--parallel/-j argument must be an integer") + + # Ensure that self.include_dirs and self.distribution.include_dirs + # refer to the same list object. finalize_options will modify + # self.include_dirs, but self.distribution.include_dirs is used + # during the actual build. + # self.include_dirs is None unless paths are specified with + # --include-dirs. + # The include paths will be passed to the compiler in the order: + # numpy paths, --include-dirs paths, Python include path. + if isinstance(self.include_dirs, str): + self.include_dirs = self.include_dirs.split(os.pathsep) + incl_dirs = self.include_dirs or [] + if self.distribution.include_dirs is None: + self.distribution.include_dirs = [] + self.include_dirs = self.distribution.include_dirs + self.include_dirs.extend(incl_dirs) + + old_build_ext.finalize_options(self) + self.set_undefined_options('build', ('parallel', 'parallel')) + + def run(self): + if not self.extensions: + return + + # Make sure that extension sources are complete. + self.run_command('build_src') + + if self.distribution.has_c_libraries(): + if self.inplace: + if self.distribution.have_run.get('build_clib'): + log.warn('build_clib already run, it is too late to ' + 'ensure in-place build of build_clib') + build_clib = self.distribution.get_command_obj( + 'build_clib') + else: + build_clib = self.distribution.get_command_obj( + 'build_clib') + build_clib.inplace = 1 + build_clib.ensure_finalized() + build_clib.run() + self.distribution.have_run['build_clib'] = 1 + + else: + self.run_command('build_clib') + build_clib = self.get_finalized_command('build_clib') + self.library_dirs.append(build_clib.build_clib) + else: + build_clib = None + + # Not including C libraries to the list of + # extension libraries automatically to prevent + # bogus linking commands. Extensions must + # explicitly specify the C libraries that they use. + + from distutils.ccompiler import new_compiler + from numpy.distutils.fcompiler import new_fcompiler + + compiler_type = self.compiler + # Initialize C compiler: + self.compiler = new_compiler(compiler=compiler_type, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force) + self.compiler.customize(self.distribution) + self.compiler.customize_cmd(self) + self.compiler.show_customization() + + # Setup directory for storing generated extra DLL files on Windows + self.extra_dll_dir = os.path.join(self.build_temp, 'extra-dll') + if not os.path.isdir(self.extra_dll_dir): + os.makedirs(self.extra_dll_dir) + + # Create mapping of libraries built by build_clib: + clibs = {} + if build_clib is not None: + for libname, build_info in build_clib.libraries or []: + if libname in clibs and clibs[libname] != build_info: + log.warn('library %r defined more than once,' + ' overwriting build_info\n%s... \nwith\n%s...' + % (libname, repr(clibs[libname])[:300], repr(build_info)[:300])) + clibs[libname] = build_info + # .. and distribution libraries: + for libname, build_info in self.distribution.libraries or []: + if libname in clibs: + # build_clib libraries have a precedence before distribution ones + continue + clibs[libname] = build_info + + # Determine if C++/Fortran 77/Fortran 90 compilers are needed. + # Update extension libraries, library_dirs, and macros. + all_languages = set() + for ext in self.extensions: + ext_languages = set() + c_libs = [] + c_lib_dirs = [] + macros = [] + for libname in ext.libraries: + if libname in clibs: + binfo = clibs[libname] + c_libs += binfo.get('libraries', []) + c_lib_dirs += binfo.get('library_dirs', []) + for m in binfo.get('macros', []): + if m not in macros: + macros.append(m) + + for l in clibs.get(libname, {}).get('source_languages', []): + ext_languages.add(l) + if c_libs: + new_c_libs = ext.libraries + c_libs + log.info('updating extension %r libraries from %r to %r' + % (ext.name, ext.libraries, new_c_libs)) + ext.libraries = new_c_libs + ext.library_dirs = ext.library_dirs + c_lib_dirs + if macros: + log.info('extending extension %r defined_macros with %r' + % (ext.name, macros)) + ext.define_macros = ext.define_macros + macros + + # determine extension languages + if has_f_sources(ext.sources): + ext_languages.add('f77') + if has_cxx_sources(ext.sources): + ext_languages.add('c++') + l = ext.language or self.compiler.detect_language(ext.sources) + if l: + ext_languages.add(l) + # reset language attribute for choosing proper linker + if 'c++' in ext_languages: + ext_language = 'c++' + elif 'f90' in ext_languages: + ext_language = 'f90' + elif 'f77' in ext_languages: + ext_language = 'f77' + else: + ext_language = 'c' # default + if l and l != ext_language and ext.language: + log.warn('resetting extension %r language from %r to %r.' % + (ext.name, l, ext_language)) + ext.language = ext_language + # global language + all_languages.update(ext_languages) + + need_f90_compiler = 'f90' in all_languages + need_f77_compiler = 'f77' in all_languages + need_cxx_compiler = 'c++' in all_languages + + # Initialize C++ compiler: + if need_cxx_compiler: + self._cxx_compiler = new_compiler(compiler=compiler_type, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force) + compiler = self._cxx_compiler + compiler.customize(self.distribution, need_cxx=need_cxx_compiler) + compiler.customize_cmd(self) + compiler.show_customization() + self._cxx_compiler = compiler.cxx_compiler() + else: + self._cxx_compiler = None + + # Initialize Fortran 77 compiler: + if need_f77_compiler: + ctype = self.fcompiler + self._f77_compiler = new_fcompiler(compiler=self.fcompiler, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90=False, + c_compiler=self.compiler) + fcompiler = self._f77_compiler + if fcompiler: + ctype = fcompiler.compiler_type + fcompiler.customize(self.distribution) + if fcompiler and fcompiler.get_version(): + fcompiler.customize_cmd(self) + fcompiler.show_customization() + else: + self.warn('f77_compiler=%s is not available.' % + (ctype)) + self._f77_compiler = None + else: + self._f77_compiler = None + + # Initialize Fortran 90 compiler: + if need_f90_compiler: + ctype = self.fcompiler + self._f90_compiler = new_fcompiler(compiler=self.fcompiler, + verbose=self.verbose, + dry_run=self.dry_run, + force=self.force, + requiref90=True, + c_compiler=self.compiler) + fcompiler = self._f90_compiler + if fcompiler: + ctype = fcompiler.compiler_type + fcompiler.customize(self.distribution) + if fcompiler and fcompiler.get_version(): + fcompiler.customize_cmd(self) + fcompiler.show_customization() + else: + self.warn('f90_compiler=%s is not available.' % + (ctype)) + self._f90_compiler = None + else: + self._f90_compiler = None + + # Build extensions + self.build_extensions() + + # Copy over any extra DLL files + runtime_lib_dir = os.path.join( + self.build_lib, self.distribution.get_name(), '.libs') + for fn in os.listdir(self.extra_dll_dir): + if not fn.lower().endswith('.dll'): + continue + if not os.path.isdir(runtime_lib_dir): + os.makedirs(runtime_lib_dir) + runtime_lib = os.path.join(self.extra_dll_dir, fn) + copy_file(runtime_lib, runtime_lib_dir) + + def swig_sources(self, sources): + # Do nothing. Swig sources have beed handled in build_src command. + return sources + + def build_extension(self, ext): + sources = ext.sources + if sources is None or not is_sequence(sources): + raise DistutilsSetupError( + ("in 'ext_modules' option (extension '%s'), " + + "'sources' must be present and must be " + + "a list of source filenames") % ext.name) + sources = list(sources) + + if not sources: + return + + fullname = self.get_ext_fullname(ext.name) + if self.inplace: + modpath = fullname.split('.') + package = '.'.join(modpath[0:-1]) + base = modpath[-1] + build_py = self.get_finalized_command('build_py') + package_dir = build_py.get_package_dir(package) + ext_filename = os.path.join(package_dir, + self.get_ext_filename(base)) + else: + ext_filename = os.path.join(self.build_lib, + self.get_ext_filename(fullname)) + depends = sources + ext.depends + + if not (self.force or newer_group(depends, ext_filename, 'newer')): + log.debug("skipping '%s' extension (up-to-date)", ext.name) + return + else: + log.info("building '%s' extension", ext.name) + + extra_args = ext.extra_compile_args or [] + macros = ext.define_macros[:] + for undef in ext.undef_macros: + macros.append((undef,)) + + c_sources, cxx_sources, f_sources, fmodule_sources = \ + filter_sources(ext.sources) + + if self.compiler.compiler_type == 'msvc': + if cxx_sources: + # Needed to compile kiva.agg._agg extension. + extra_args.append('/Zm1000') + # this hack works around the msvc compiler attributes + # problem, msvc uses its own convention :( + c_sources += cxx_sources + cxx_sources = [] + + # Set Fortran/C++ compilers for compilation and linking. + if ext.language == 'f90': + fcompiler = self._f90_compiler + elif ext.language == 'f77': + fcompiler = self._f77_compiler + else: # in case ext.language is c++, for instance + fcompiler = self._f90_compiler or self._f77_compiler + if fcompiler is not None: + fcompiler.extra_f77_compile_args = (ext.extra_f77_compile_args or []) if hasattr( + ext, 'extra_f77_compile_args') else [] + fcompiler.extra_f90_compile_args = (ext.extra_f90_compile_args or []) if hasattr( + ext, 'extra_f90_compile_args') else [] + cxx_compiler = self._cxx_compiler + + # check for the availability of required compilers + if cxx_sources and cxx_compiler is None: + raise DistutilsError("extension %r has C++ sources" + "but no C++ compiler found" % (ext.name)) + if (f_sources or fmodule_sources) and fcompiler is None: + raise DistutilsError("extension %r has Fortran sources " + "but no Fortran compiler found" % (ext.name)) + if ext.language in ['f77', 'f90'] and fcompiler is None: + self.warn("extension %r has Fortran libraries " + "but no Fortran linker found, using default linker" % (ext.name)) + if ext.language == 'c++' and cxx_compiler is None: + self.warn("extension %r has C++ libraries " + "but no C++ linker found, using default linker" % (ext.name)) + + kws = {'depends': ext.depends} + output_dir = self.build_temp + + include_dirs = ext.include_dirs + get_numpy_include_dirs() + + c_objects = [] + if c_sources: + log.info("compiling C sources") + c_objects = self.compiler.compile(c_sources, + output_dir=output_dir, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_args, + **kws) + + if cxx_sources: + log.info("compiling C++ sources") + c_objects += cxx_compiler.compile(cxx_sources, + output_dir=output_dir, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_args, + **kws) + + extra_postargs = [] + f_objects = [] + if fmodule_sources: + log.info("compiling Fortran 90 module sources") + module_dirs = ext.module_dirs[:] + module_build_dir = os.path.join( + self.build_temp, os.path.dirname( + self.get_ext_filename(fullname))) + + self.mkpath(module_build_dir) + if fcompiler.module_dir_switch is None: + existing_modules = glob('*.mod') + extra_postargs += fcompiler.module_options( + module_dirs, module_build_dir) + f_objects += fcompiler.compile(fmodule_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs, + depends=ext.depends) + + if fcompiler.module_dir_switch is None: + for f in glob('*.mod'): + if f in existing_modules: + continue + t = os.path.join(module_build_dir, f) + if os.path.abspath(f) == os.path.abspath(t): + continue + if os.path.isfile(t): + os.remove(t) + try: + self.move_file(f, module_build_dir) + except DistutilsFileError: + log.warn('failed to move %r to %r' % + (f, module_build_dir)) + if f_sources: + log.info("compiling Fortran sources") + f_objects += fcompiler.compile(f_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs, + depends=ext.depends) + + if f_objects and not fcompiler.can_ccompiler_link(self.compiler): + unlinkable_fobjects = f_objects + objects = c_objects + else: + unlinkable_fobjects = [] + objects = c_objects + f_objects + + if ext.extra_objects: + objects.extend(ext.extra_objects) + extra_args = ext.extra_link_args or [] + libraries = self.get_libraries(ext)[:] + library_dirs = ext.library_dirs[:] + + linker = self.compiler.link_shared_object + # Always use system linker when using MSVC compiler. + if self.compiler.compiler_type in ('msvc', 'intelw', 'intelemw'): + # expand libraries with fcompiler libraries as we are + # not using fcompiler linker + self._libs_with_msvc_and_fortran( + fcompiler, libraries, library_dirs) + + elif ext.language in ['f77', 'f90'] and fcompiler is not None: + linker = fcompiler.link_shared_object + if ext.language == 'c++' and cxx_compiler is not None: + linker = cxx_compiler.link_shared_object + + if fcompiler is not None: + objects, libraries = self._process_unlinkable_fobjects( + objects, libraries, + fcompiler, library_dirs, + unlinkable_fobjects) + + linker(objects, ext_filename, + libraries=libraries, + library_dirs=library_dirs, + runtime_library_dirs=ext.runtime_library_dirs, + extra_postargs=extra_args, + export_symbols=self.get_export_symbols(ext), + debug=self.debug, + build_temp=self.build_temp, + target_lang=ext.language) + + def _add_dummy_mingwex_sym(self, c_sources): + build_src = self.get_finalized_command("build_src").build_src + build_clib = self.get_finalized_command("build_clib").build_clib + objects = self.compiler.compile([os.path.join(build_src, + "gfortran_vs2003_hack.c")], + output_dir=self.build_temp) + self.compiler.create_static_lib( + objects, "_gfortran_workaround", output_dir=build_clib, debug=self.debug) + + def _process_unlinkable_fobjects(self, objects, libraries, + fcompiler, library_dirs, + unlinkable_fobjects): + libraries = list(libraries) + objects = list(objects) + unlinkable_fobjects = list(unlinkable_fobjects) + + # Expand possible fake static libraries to objects + for lib in list(libraries): + for libdir in library_dirs: + fake_lib = os.path.join(libdir, lib + '.fobjects') + if os.path.isfile(fake_lib): + # Replace fake static library + libraries.remove(lib) + with open(fake_lib, 'r') as f: + unlinkable_fobjects.extend(f.read().splitlines()) + + # Expand C objects + c_lib = os.path.join(libdir, lib + '.cobjects') + with open(c_lib, 'r') as f: + objects.extend(f.read().splitlines()) + + # Wrap unlinkable objects to a linkable one + if unlinkable_fobjects: + fobjects = [os.path.relpath(obj) for obj in unlinkable_fobjects] + wrapped = fcompiler.wrap_unlinkable_objects( + fobjects, output_dir=self.build_temp, + extra_dll_dir=self.extra_dll_dir) + objects.extend(wrapped) + + return objects, libraries + + def _libs_with_msvc_and_fortran(self, fcompiler, c_libraries, + c_library_dirs): + if fcompiler is None: + return + + for libname in c_libraries: + if libname.startswith('msvc'): + continue + fileexists = False + for libdir in c_library_dirs or []: + libfile = os.path.join(libdir, '%s.lib' % (libname)) + if os.path.isfile(libfile): + fileexists = True + break + if fileexists: + continue + # make g77-compiled static libs available to MSVC + fileexists = False + for libdir in c_library_dirs: + libfile = os.path.join(libdir, 'lib%s.a' % (libname)) + if os.path.isfile(libfile): + # copy libname.a file to name.lib so that MSVC linker + # can find it + libfile2 = os.path.join(self.build_temp, libname + '.lib') + copy_file(libfile, libfile2) + if self.build_temp not in c_library_dirs: + c_library_dirs.append(self.build_temp) + fileexists = True + break + if fileexists: + continue + log.warn('could not find library %r in directories %s' + % (libname, c_library_dirs)) + + # Always use system linker when using MSVC compiler. + f_lib_dirs = [] + for dir in fcompiler.library_dirs: + # correct path when compiling in Cygwin but with normal Win + # Python + if dir.startswith('/usr/lib'): + s, o = exec_command(['cygpath', '-w', dir], use_tee=False) + if not s: + dir = o + f_lib_dirs.append(dir) + c_library_dirs.extend(f_lib_dirs) + + # make g77-compiled static libs available to MSVC + for lib in fcompiler.libraries: + if not lib.startswith('msvc'): + c_libraries.append(lib) + p = combine_paths(f_lib_dirs, 'lib' + lib + '.a') + if p: + dst_name = os.path.join(self.build_temp, lib + '.lib') + if not os.path.isfile(dst_name): + copy_file(p[0], dst_name) + if self.build_temp not in c_library_dirs: + c_library_dirs.append(self.build_temp) + + def get_source_files(self): + self.check_extensions_list(self.extensions) + filenames = [] + for ext in self.extensions: + filenames.extend(get_ext_source_files(ext)) + return filenames + + def get_outputs(self): + self.check_extensions_list(self.extensions) + + outputs = [] + for ext in self.extensions: + if not ext.sources: + continue + fullname = self.get_ext_fullname(ext.name) + outputs.append(os.path.join(self.build_lib, + self.get_ext_filename(fullname))) + return outputs diff --git a/numpy/distutils/command/build_py.py b/numpy/distutils/command/build_py.py new file mode 100644 index 0000000..54dcde4 --- /dev/null +++ b/numpy/distutils/command/build_py.py @@ -0,0 +1,33 @@ +from __future__ import division, absolute_import, print_function + +from distutils.command.build_py import build_py as old_build_py +from numpy.distutils.misc_util import is_string + +class build_py(old_build_py): + + def run(self): + build_src = self.get_finalized_command('build_src') + if build_src.py_modules_dict and self.packages is None: + self.packages = list(build_src.py_modules_dict.keys ()) + old_build_py.run(self) + + def find_package_modules(self, package, package_dir): + modules = old_build_py.find_package_modules(self, package, package_dir) + + # Find build_src generated *.py files. + build_src = self.get_finalized_command('build_src') + modules += build_src.py_modules_dict.get(package, []) + + return modules + + def find_modules(self): + old_py_modules = self.py_modules[:] + new_py_modules = [_m for _m in self.py_modules if is_string(_m)] + self.py_modules[:] = new_py_modules + modules = old_build_py.find_modules(self) + self.py_modules[:] = old_py_modules + + return modules + + # XXX: Fix find_source_files for item in py_modules such that item is 3-tuple + # and item[2] is source file. diff --git a/numpy/distutils/command/build_scripts.py b/numpy/distutils/command/build_scripts.py new file mode 100644 index 0000000..c8b25fc --- /dev/null +++ b/numpy/distutils/command/build_scripts.py @@ -0,0 +1,51 @@ +""" Modified version of build_scripts that handles building scripts from functions. + +""" +from __future__ import division, absolute_import, print_function + +from distutils.command.build_scripts import build_scripts as old_build_scripts +from numpy.distutils import log +from numpy.distutils.misc_util import is_string + +class build_scripts(old_build_scripts): + + def generate_scripts(self, scripts): + new_scripts = [] + func_scripts = [] + for script in scripts: + if is_string(script): + new_scripts.append(script) + else: + func_scripts.append(script) + if not func_scripts: + return new_scripts + + build_dir = self.build_dir + self.mkpath(build_dir) + for func in func_scripts: + script = func(build_dir) + if not script: + continue + if is_string(script): + log.info(" adding '%s' to scripts" % (script,)) + new_scripts.append(script) + else: + [log.info(" adding '%s' to scripts" % (s,)) for s in script] + new_scripts.extend(list(script)) + return new_scripts + + def run (self): + if not self.scripts: + return + + self.scripts = self.generate_scripts(self.scripts) + # Now make sure that the distribution object has this list of scripts. + # setuptools' develop command requires that this be a list of filenames, + # not functions. + self.distribution.scripts = self.scripts + + return old_build_scripts.run(self) + + def get_source_files(self): + from numpy.distutils.misc_util import get_script_files + return get_script_files(self.scripts) diff --git a/numpy/distutils/command/build_src.py b/numpy/distutils/command/build_src.py new file mode 100644 index 0000000..9def378 --- /dev/null +++ b/numpy/distutils/command/build_src.py @@ -0,0 +1,776 @@ +""" Build swig and f2py sources. +""" +from __future__ import division, absolute_import, print_function + +import os +import re +import sys +import shlex +import copy + +from distutils.command import build_ext +from distutils.dep_util import newer_group, newer +from distutils.util import get_platform +from distutils.errors import DistutilsError, DistutilsSetupError + + +# this import can't be done here, as it uses numpy stuff only available +# after it's installed +#import numpy.f2py +from numpy.distutils import log +from numpy.distutils.misc_util import ( + fortran_ext_match, appendpath, is_string, is_sequence, get_cmd + ) +from numpy.distutils.from_template import process_file as process_f_file +from numpy.distutils.conv_template import process_file as process_c_file + +def subst_vars(target, source, d): + """Substitute any occurrence of @foo@ by d['foo'] from source file into + target.""" + var = re.compile('@([a-zA-Z_]+)@') + fs = open(source, 'r') + try: + ft = open(target, 'w') + try: + for l in fs: + m = var.search(l) + if m: + ft.write(l.replace('@%s@' % m.group(1), d[m.group(1)])) + else: + ft.write(l) + finally: + ft.close() + finally: + fs.close() + +class build_src(build_ext.build_ext): + + description = "build sources from SWIG, F2PY files or a function" + + user_options = [ + ('build-src=', 'd', "directory to \"build\" sources to"), + ('f2py-opts=', None, "list of f2py command line options"), + ('swig=', None, "path to the SWIG executable"), + ('swig-opts=', None, "list of SWIG command line options"), + ('swig-cpp', None, "make SWIG create C++ files (default is autodetected from sources)"), + ('f2pyflags=', None, "additional flags to f2py (use --f2py-opts= instead)"), # obsolete + ('swigflags=', None, "additional flags to swig (use --swig-opts= instead)"), # obsolete + ('force', 'f', "forcibly build everything (ignore file timestamps)"), + ('inplace', 'i', + "ignore build-lib and put compiled extensions into the source " + + "directory alongside your pure Python modules"), + ] + + boolean_options = ['force', 'inplace'] + + help_options = [] + + def initialize_options(self): + self.extensions = None + self.package = None + self.py_modules = None + self.py_modules_dict = None + self.build_src = None + self.build_lib = None + self.build_base = None + self.force = None + self.inplace = None + self.package_dir = None + self.f2pyflags = None # obsolete + self.f2py_opts = None + self.swigflags = None # obsolete + self.swig_opts = None + self.swig_cpp = None + self.swig = None + + def finalize_options(self): + self.set_undefined_options('build', + ('build_base', 'build_base'), + ('build_lib', 'build_lib'), + ('force', 'force')) + if self.package is None: + self.package = self.distribution.ext_package + self.extensions = self.distribution.ext_modules + self.libraries = self.distribution.libraries or [] + self.py_modules = self.distribution.py_modules or [] + self.data_files = self.distribution.data_files or [] + + if self.build_src is None: + plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3]) + self.build_src = os.path.join(self.build_base, 'src'+plat_specifier) + + # py_modules_dict is used in build_py.find_package_modules + self.py_modules_dict = {} + + if self.f2pyflags: + if self.f2py_opts: + log.warn('ignoring --f2pyflags as --f2py-opts already used') + else: + self.f2py_opts = self.f2pyflags + self.f2pyflags = None + if self.f2py_opts is None: + self.f2py_opts = [] + else: + self.f2py_opts = shlex.split(self.f2py_opts) + + if self.swigflags: + if self.swig_opts: + log.warn('ignoring --swigflags as --swig-opts already used') + else: + self.swig_opts = self.swigflags + self.swigflags = None + + if self.swig_opts is None: + self.swig_opts = [] + else: + self.swig_opts = shlex.split(self.swig_opts) + + # use options from build_ext command + build_ext = self.get_finalized_command('build_ext') + if self.inplace is None: + self.inplace = build_ext.inplace + if self.swig_cpp is None: + self.swig_cpp = build_ext.swig_cpp + for c in ['swig', 'swig_opt']: + o = '--'+c.replace('_', '-') + v = getattr(build_ext, c, None) + if v: + if getattr(self, c): + log.warn('both build_src and build_ext define %s option' % (o)) + else: + log.info('using "%s=%s" option from build_ext command' % (o, v)) + setattr(self, c, v) + + def run(self): + log.info("build_src") + if not (self.extensions or self.libraries): + return + self.build_sources() + + def build_sources(self): + + if self.inplace: + self.get_package_dir = \ + self.get_finalized_command('build_py').get_package_dir + + self.build_py_modules_sources() + + for libname_info in self.libraries: + self.build_library_sources(*libname_info) + + if self.extensions: + self.check_extensions_list(self.extensions) + + for ext in self.extensions: + self.build_extension_sources(ext) + + self.build_data_files_sources() + self.build_npy_pkg_config() + + def build_data_files_sources(self): + if not self.data_files: + return + log.info('building data_files sources') + from numpy.distutils.misc_util import get_data_files + new_data_files = [] + for data in self.data_files: + if isinstance(data, str): + new_data_files.append(data) + elif isinstance(data, tuple): + d, files = data + if self.inplace: + build_dir = self.get_package_dir('.'.join(d.split(os.sep))) + else: + build_dir = os.path.join(self.build_src, d) + funcs = [f for f in files if hasattr(f, '__call__')] + files = [f for f in files if not hasattr(f, '__call__')] + for f in funcs: + if f.__code__.co_argcount==1: + s = f(build_dir) + else: + s = f() + if s is not None: + if isinstance(s, list): + files.extend(s) + elif isinstance(s, str): + files.append(s) + else: + raise TypeError(repr(s)) + filenames = get_data_files((d, files)) + new_data_files.append((d, filenames)) + else: + raise TypeError(repr(data)) + self.data_files[:] = new_data_files + + + def _build_npy_pkg_config(self, info, gd): + import shutil + template, install_dir, subst_dict = info + template_dir = os.path.dirname(template) + for k, v in gd.items(): + subst_dict[k] = v + + if self.inplace == 1: + generated_dir = os.path.join(template_dir, install_dir) + else: + generated_dir = os.path.join(self.build_src, template_dir, + install_dir) + generated = os.path.basename(os.path.splitext(template)[0]) + generated_path = os.path.join(generated_dir, generated) + if not os.path.exists(generated_dir): + os.makedirs(generated_dir) + + subst_vars(generated_path, template, subst_dict) + + # Where to install relatively to install prefix + full_install_dir = os.path.join(template_dir, install_dir) + return full_install_dir, generated_path + + def build_npy_pkg_config(self): + log.info('build_src: building npy-pkg config files') + + # XXX: another ugly workaround to circumvent distutils brain damage. We + # need the install prefix here, but finalizing the options of the + # install command when only building sources cause error. Instead, we + # copy the install command instance, and finalize the copy so that it + # does not disrupt how distutils want to do things when with the + # original install command instance. + install_cmd = copy.copy(get_cmd('install')) + if not install_cmd.finalized == 1: + install_cmd.finalize_options() + build_npkg = False + gd = {} + if self.inplace == 1: + top_prefix = '.' + build_npkg = True + elif hasattr(install_cmd, 'install_libbase'): + top_prefix = install_cmd.install_libbase + build_npkg = True + + if build_npkg: + for pkg, infos in self.distribution.installed_pkg_config.items(): + pkg_path = self.distribution.package_dir[pkg] + prefix = os.path.join(os.path.abspath(top_prefix), pkg_path) + d = {'prefix': prefix} + for info in infos: + install_dir, generated = self._build_npy_pkg_config(info, d) + self.distribution.data_files.append((install_dir, + [generated])) + + def build_py_modules_sources(self): + if not self.py_modules: + return + log.info('building py_modules sources') + new_py_modules = [] + for source in self.py_modules: + if is_sequence(source) and len(source)==3: + package, module_base, source = source + if self.inplace: + build_dir = self.get_package_dir(package) + else: + build_dir = os.path.join(self.build_src, + os.path.join(*package.split('.'))) + if hasattr(source, '__call__'): + target = os.path.join(build_dir, module_base + '.py') + source = source(target) + if source is None: + continue + modules = [(package, module_base, source)] + if package not in self.py_modules_dict: + self.py_modules_dict[package] = [] + self.py_modules_dict[package] += modules + else: + new_py_modules.append(source) + self.py_modules[:] = new_py_modules + + def build_library_sources(self, lib_name, build_info): + sources = list(build_info.get('sources', [])) + + if not sources: + return + + log.info('building library "%s" sources' % (lib_name)) + + sources = self.generate_sources(sources, (lib_name, build_info)) + + sources = self.template_sources(sources, (lib_name, build_info)) + + sources, h_files = self.filter_h_files(sources) + + if h_files: + log.info('%s - nothing done with h_files = %s', + self.package, h_files) + + #for f in h_files: + # self.distribution.headers.append((lib_name,f)) + + build_info['sources'] = sources + return + + def build_extension_sources(self, ext): + + sources = list(ext.sources) + + log.info('building extension "%s" sources' % (ext.name)) + + fullname = self.get_ext_fullname(ext.name) + + modpath = fullname.split('.') + package = '.'.join(modpath[0:-1]) + + if self.inplace: + self.ext_target_dir = self.get_package_dir(package) + + sources = self.generate_sources(sources, ext) + sources = self.template_sources(sources, ext) + sources = self.swig_sources(sources, ext) + sources = self.f2py_sources(sources, ext) + sources = self.pyrex_sources(sources, ext) + + sources, py_files = self.filter_py_files(sources) + + if package not in self.py_modules_dict: + self.py_modules_dict[package] = [] + modules = [] + for f in py_files: + module = os.path.splitext(os.path.basename(f))[0] + modules.append((package, module, f)) + self.py_modules_dict[package] += modules + + sources, h_files = self.filter_h_files(sources) + + if h_files: + log.info('%s - nothing done with h_files = %s', + package, h_files) + #for f in h_files: + # self.distribution.headers.append((package,f)) + + ext.sources = sources + + def generate_sources(self, sources, extension): + new_sources = [] + func_sources = [] + for source in sources: + if is_string(source): + new_sources.append(source) + else: + func_sources.append(source) + if not func_sources: + return new_sources + if self.inplace and not is_sequence(extension): + build_dir = self.ext_target_dir + else: + if is_sequence(extension): + name = extension[0] + # if 'include_dirs' not in extension[1]: + # extension[1]['include_dirs'] = [] + # incl_dirs = extension[1]['include_dirs'] + else: + name = extension.name + # incl_dirs = extension.include_dirs + #if self.build_src not in incl_dirs: + # incl_dirs.append(self.build_src) + build_dir = os.path.join(*([self.build_src]\ + +name.split('.')[:-1])) + self.mkpath(build_dir) + for func in func_sources: + source = func(extension, build_dir) + if not source: + continue + if is_sequence(source): + [log.info(" adding '%s' to sources." % (s,)) for s in source] + new_sources.extend(source) + else: + log.info(" adding '%s' to sources." % (source,)) + new_sources.append(source) + + return new_sources + + def filter_py_files(self, sources): + return self.filter_files(sources, ['.py']) + + def filter_h_files(self, sources): + return self.filter_files(sources, ['.h', '.hpp', '.inc']) + + def filter_files(self, sources, exts = []): + new_sources = [] + files = [] + for source in sources: + (base, ext) = os.path.splitext(source) + if ext in exts: + files.append(source) + else: + new_sources.append(source) + return new_sources, files + + def template_sources(self, sources, extension): + new_sources = [] + if is_sequence(extension): + depends = extension[1].get('depends') + include_dirs = extension[1].get('include_dirs') + else: + depends = extension.depends + include_dirs = extension.include_dirs + for source in sources: + (base, ext) = os.path.splitext(source) + if ext == '.src': # Template file + if self.inplace: + target_dir = os.path.dirname(base) + else: + target_dir = appendpath(self.build_src, os.path.dirname(base)) + self.mkpath(target_dir) + target_file = os.path.join(target_dir, os.path.basename(base)) + if (self.force or newer_group([source] + depends, target_file)): + if _f_pyf_ext_match(base): + log.info("from_template:> %s" % (target_file)) + outstr = process_f_file(source) + else: + log.info("conv_template:> %s" % (target_file)) + outstr = process_c_file(source) + fid = open(target_file, 'w') + fid.write(outstr) + fid.close() + if _header_ext_match(target_file): + d = os.path.dirname(target_file) + if d not in include_dirs: + log.info(" adding '%s' to include_dirs." % (d)) + include_dirs.append(d) + new_sources.append(target_file) + else: + new_sources.append(source) + return new_sources + + def pyrex_sources(self, sources, extension): + """Pyrex not supported; this remains for Cython support (see below)""" + new_sources = [] + ext_name = extension.name.split('.')[-1] + for source in sources: + (base, ext) = os.path.splitext(source) + if ext == '.pyx': + target_file = self.generate_a_pyrex_source(base, ext_name, + source, + extension) + new_sources.append(target_file) + else: + new_sources.append(source) + return new_sources + + def generate_a_pyrex_source(self, base, ext_name, source, extension): + """Pyrex is not supported, but some projects monkeypatch this method. + + That allows compiling Cython code, see gh-6955. + This method will remain here for compatibility reasons. + """ + return [] + + def f2py_sources(self, sources, extension): + new_sources = [] + f2py_sources = [] + f_sources = [] + f2py_targets = {} + target_dirs = [] + ext_name = extension.name.split('.')[-1] + skip_f2py = 0 + + for source in sources: + (base, ext) = os.path.splitext(source) + if ext == '.pyf': # F2PY interface file + if self.inplace: + target_dir = os.path.dirname(base) + else: + target_dir = appendpath(self.build_src, os.path.dirname(base)) + if os.path.isfile(source): + name = get_f2py_modulename(source) + if name != ext_name: + raise DistutilsSetupError('mismatch of extension names: %s ' + 'provides %r but expected %r' % ( + source, name, ext_name)) + target_file = os.path.join(target_dir, name+'module.c') + else: + log.debug(' source %s does not exist: skipping f2py\'ing.' \ + % (source)) + name = ext_name + skip_f2py = 1 + target_file = os.path.join(target_dir, name+'module.c') + if not os.path.isfile(target_file): + log.warn(' target %s does not exist:\n '\ + 'Assuming %smodule.c was generated with '\ + '"build_src --inplace" command.' \ + % (target_file, name)) + target_dir = os.path.dirname(base) + target_file = os.path.join(target_dir, name+'module.c') + if not os.path.isfile(target_file): + raise DistutilsSetupError("%r missing" % (target_file,)) + log.info(' Yes! Using %r as up-to-date target.' \ + % (target_file)) + target_dirs.append(target_dir) + f2py_sources.append(source) + f2py_targets[source] = target_file + new_sources.append(target_file) + elif fortran_ext_match(ext): + f_sources.append(source) + else: + new_sources.append(source) + + if not (f2py_sources or f_sources): + return new_sources + + for d in target_dirs: + self.mkpath(d) + + f2py_options = extension.f2py_options + self.f2py_opts + + if self.distribution.libraries: + for name, build_info in self.distribution.libraries: + if name in extension.libraries: + f2py_options.extend(build_info.get('f2py_options', [])) + + log.info("f2py options: %s" % (f2py_options)) + + if f2py_sources: + if len(f2py_sources) != 1: + raise DistutilsSetupError( + 'only one .pyf file is allowed per extension module but got'\ + ' more: %r' % (f2py_sources,)) + source = f2py_sources[0] + target_file = f2py_targets[source] + target_dir = os.path.dirname(target_file) or '.' + depends = [source] + extension.depends + if (self.force or newer_group(depends, target_file, 'newer')) \ + and not skip_f2py: + log.info("f2py: %s" % (source)) + import numpy.f2py + numpy.f2py.run_main(f2py_options + + ['--build-dir', target_dir, source]) + else: + log.debug(" skipping '%s' f2py interface (up-to-date)" % (source)) + else: + #XXX TODO: --inplace support for sdist command + if is_sequence(extension): + name = extension[0] + else: name = extension.name + target_dir = os.path.join(*([self.build_src]\ + +name.split('.')[:-1])) + target_file = os.path.join(target_dir, ext_name + 'module.c') + new_sources.append(target_file) + depends = f_sources + extension.depends + if (self.force or newer_group(depends, target_file, 'newer')) \ + and not skip_f2py: + log.info("f2py:> %s" % (target_file)) + self.mkpath(target_dir) + import numpy.f2py + numpy.f2py.run_main(f2py_options + ['--lower', + '--build-dir', target_dir]+\ + ['-m', ext_name]+f_sources) + else: + log.debug(" skipping f2py fortran files for '%s' (up-to-date)"\ + % (target_file)) + + if not os.path.isfile(target_file): + raise DistutilsError("f2py target file %r not generated" % (target_file,)) + + build_dir = os.path.join(self.build_src, target_dir) + target_c = os.path.join(build_dir, 'fortranobject.c') + target_h = os.path.join(build_dir, 'fortranobject.h') + log.info(" adding '%s' to sources." % (target_c)) + new_sources.append(target_c) + if build_dir not in extension.include_dirs: + log.info(" adding '%s' to include_dirs." % (build_dir)) + extension.include_dirs.append(build_dir) + + if not skip_f2py: + import numpy.f2py + d = os.path.dirname(numpy.f2py.__file__) + source_c = os.path.join(d, 'src', 'fortranobject.c') + source_h = os.path.join(d, 'src', 'fortranobject.h') + if newer(source_c, target_c) or newer(source_h, target_h): + self.mkpath(os.path.dirname(target_c)) + self.copy_file(source_c, target_c) + self.copy_file(source_h, target_h) + else: + if not os.path.isfile(target_c): + raise DistutilsSetupError("f2py target_c file %r not found" % (target_c,)) + if not os.path.isfile(target_h): + raise DistutilsSetupError("f2py target_h file %r not found" % (target_h,)) + + for name_ext in ['-f2pywrappers.f', '-f2pywrappers2.f90']: + filename = os.path.join(target_dir, ext_name + name_ext) + if os.path.isfile(filename): + log.info(" adding '%s' to sources." % (filename)) + f_sources.append(filename) + + return new_sources + f_sources + + def swig_sources(self, sources, extension): + # Assuming SWIG 1.3.14 or later. See compatibility note in + # http://www.swig.org/Doc1.3/Python.html#Python_nn6 + + new_sources = [] + swig_sources = [] + swig_targets = {} + target_dirs = [] + py_files = [] # swig generated .py files + target_ext = '.c' + if '-c++' in extension.swig_opts: + typ = 'c++' + is_cpp = True + extension.swig_opts.remove('-c++') + elif self.swig_cpp: + typ = 'c++' + is_cpp = True + else: + typ = None + is_cpp = False + skip_swig = 0 + ext_name = extension.name.split('.')[-1] + + for source in sources: + (base, ext) = os.path.splitext(source) + if ext == '.i': # SWIG interface file + # the code below assumes that the sources list + # contains not more than one .i SWIG interface file + if self.inplace: + target_dir = os.path.dirname(base) + py_target_dir = self.ext_target_dir + else: + target_dir = appendpath(self.build_src, os.path.dirname(base)) + py_target_dir = target_dir + if os.path.isfile(source): + name = get_swig_modulename(source) + if name != ext_name[1:]: + raise DistutilsSetupError( + 'mismatch of extension names: %s provides %r' + ' but expected %r' % (source, name, ext_name[1:])) + if typ is None: + typ = get_swig_target(source) + is_cpp = typ=='c++' + else: + typ2 = get_swig_target(source) + if typ2 is None: + log.warn('source %r does not define swig target, assuming %s swig target' \ + % (source, typ)) + elif typ!=typ2: + log.warn('expected %r but source %r defines %r swig target' \ + % (typ, source, typ2)) + if typ2=='c++': + log.warn('resetting swig target to c++ (some targets may have .c extension)') + is_cpp = True + else: + log.warn('assuming that %r has c++ swig target' % (source)) + if is_cpp: + target_ext = '.cpp' + target_file = os.path.join(target_dir, '%s_wrap%s' \ + % (name, target_ext)) + else: + log.warn(' source %s does not exist: skipping swig\'ing.' \ + % (source)) + name = ext_name[1:] + skip_swig = 1 + target_file = _find_swig_target(target_dir, name) + if not os.path.isfile(target_file): + log.warn(' target %s does not exist:\n '\ + 'Assuming %s_wrap.{c,cpp} was generated with '\ + '"build_src --inplace" command.' \ + % (target_file, name)) + target_dir = os.path.dirname(base) + target_file = _find_swig_target(target_dir, name) + if not os.path.isfile(target_file): + raise DistutilsSetupError("%r missing" % (target_file,)) + log.warn(' Yes! Using %r as up-to-date target.' \ + % (target_file)) + target_dirs.append(target_dir) + new_sources.append(target_file) + py_files.append(os.path.join(py_target_dir, name+'.py')) + swig_sources.append(source) + swig_targets[source] = new_sources[-1] + else: + new_sources.append(source) + + if not swig_sources: + return new_sources + + if skip_swig: + return new_sources + py_files + + for d in target_dirs: + self.mkpath(d) + + swig = self.swig or self.find_swig() + swig_cmd = [swig, "-python"] + extension.swig_opts + if is_cpp: + swig_cmd.append('-c++') + for d in extension.include_dirs: + swig_cmd.append('-I'+d) + for source in swig_sources: + target = swig_targets[source] + depends = [source] + extension.depends + if self.force or newer_group(depends, target, 'newer'): + log.info("%s: %s" % (os.path.basename(swig) \ + + (is_cpp and '++' or ''), source)) + self.spawn(swig_cmd + self.swig_opts \ + + ["-o", target, '-outdir', py_target_dir, source]) + else: + log.debug(" skipping '%s' swig interface (up-to-date)" \ + % (source)) + + return new_sources + py_files + +_f_pyf_ext_match = re.compile(r'.*[.](f90|f95|f77|for|ftn|f|pyf)\Z', re.I).match +_header_ext_match = re.compile(r'.*[.](inc|h|hpp)\Z', re.I).match + +#### SWIG related auxiliary functions #### +_swig_module_name_match = re.compile(r'\s*%module\s*(.*\(\s*package\s*=\s*"(?P[\w_]+)".*\)|)\s*(?P[\w_]+)', + re.I).match +_has_c_header = re.compile(r'-[*]-\s*c\s*-[*]-', re.I).search +_has_cpp_header = re.compile(r'-[*]-\s*c[+][+]\s*-[*]-', re.I).search + +def get_swig_target(source): + f = open(source, 'r') + result = None + line = f.readline() + if _has_cpp_header(line): + result = 'c++' + if _has_c_header(line): + result = 'c' + f.close() + return result + +def get_swig_modulename(source): + f = open(source, 'r') + name = None + for line in f: + m = _swig_module_name_match(line) + if m: + name = m.group('name') + break + f.close() + return name + +def _find_swig_target(target_dir, name): + for ext in ['.cpp', '.c']: + target = os.path.join(target_dir, '%s_wrap%s' % (name, ext)) + if os.path.isfile(target): + break + return target + +#### F2PY related auxiliary functions #### + +_f2py_module_name_match = re.compile(r'\s*python\s*module\s*(?P[\w_]+)', + re.I).match +_f2py_user_module_name_match = re.compile(r'\s*python\s*module\s*(?P[\w_]*?' + r'__user__[\w_]*)', re.I).match + +def get_f2py_modulename(source): + name = None + f = open(source) + for line in f: + m = _f2py_module_name_match(line) + if m: + if _f2py_user_module_name_match(line): # skip *__user__* names + continue + name = m.group('name') + break + f.close() + return name + +########################################## diff --git a/numpy/distutils/command/config.py b/numpy/distutils/command/config.py new file mode 100644 index 0000000..a7368a7 --- /dev/null +++ b/numpy/distutils/command/config.py @@ -0,0 +1,482 @@ +# Added Fortran compiler support to config. Currently useful only for +# try_compile call. try_run works but is untested for most of Fortran +# compilers (they must define linker_exe first). +# Pearu Peterson +from __future__ import division, absolute_import, print_function + +import os, signal +import warnings +import sys + +from distutils.command.config import config as old_config +from distutils.command.config import LANG_EXT +from distutils import log +from distutils.file_util import copy_file +from distutils.ccompiler import CompileError, LinkError +import distutils +from numpy.distutils.exec_command import exec_command +from numpy.distutils.mingw32ccompiler import generate_manifest +from numpy.distutils.command.autodist import (check_gcc_function_attribute, + check_gcc_variable_attribute, + check_inline, + check_restrict, + check_compiler_gcc4) +from numpy.distutils.compat import get_exception + +LANG_EXT['f77'] = '.f' +LANG_EXT['f90'] = '.f90' + +class config(old_config): + old_config.user_options += [ + ('fcompiler=', None, "specify the Fortran compiler type"), + ] + + def initialize_options(self): + self.fcompiler = None + old_config.initialize_options(self) + + def _check_compiler (self): + old_config._check_compiler(self) + from numpy.distutils.fcompiler import FCompiler, new_fcompiler + + if sys.platform == 'win32' and (self.compiler.compiler_type in + ('msvc', 'intelw', 'intelemw')): + # XXX: hack to circumvent a python 2.6 bug with msvc9compiler: + # initialize call query_vcvarsall, which throws an IOError, and + # causes an error along the way without much information. We try to + # catch it here, hoping it is early enough, and print an helpful + # message instead of Error: None. + if not self.compiler.initialized: + try: + self.compiler.initialize() + except IOError: + e = get_exception() + msg = """\ +Could not initialize compiler instance: do you have Visual Studio +installed? If you are trying to build with MinGW, please use "python setup.py +build -c mingw32" instead. If you have Visual Studio installed, check it is +correctly installed, and the right version (VS 2008 for python 2.6, 2.7 and 3.2, +VS 2010 for >= 3.3). + +Original exception was: %s, and the Compiler class was %s +============================================================================""" \ + % (e, self.compiler.__class__.__name__) + print ("""\ +============================================================================""") + raise distutils.errors.DistutilsPlatformError(msg) + + # After MSVC is initialized, add an explicit /MANIFEST to linker + # flags. See issues gh-4245 and gh-4101 for details. Also + # relevant are issues 4431 and 16296 on the Python bug tracker. + from distutils import msvc9compiler + if msvc9compiler.get_build_version() >= 10: + for ldflags in [self.compiler.ldflags_shared, + self.compiler.ldflags_shared_debug]: + if '/MANIFEST' not in ldflags: + ldflags.append('/MANIFEST') + + if not isinstance(self.fcompiler, FCompiler): + self.fcompiler = new_fcompiler(compiler=self.fcompiler, + dry_run=self.dry_run, force=1, + c_compiler=self.compiler) + if self.fcompiler is not None: + self.fcompiler.customize(self.distribution) + if self.fcompiler.get_version(): + self.fcompiler.customize_cmd(self) + self.fcompiler.show_customization() + + def _wrap_method(self, mth, lang, args): + from distutils.ccompiler import CompileError + from distutils.errors import DistutilsExecError + save_compiler = self.compiler + if lang in ['f77', 'f90']: + self.compiler = self.fcompiler + try: + ret = mth(*((self,)+args)) + except (DistutilsExecError, CompileError): + msg = str(get_exception()) + self.compiler = save_compiler + raise CompileError + self.compiler = save_compiler + return ret + + def _compile (self, body, headers, include_dirs, lang): + return self._wrap_method(old_config._compile, lang, + (body, headers, include_dirs, lang)) + + def _link (self, body, + headers, include_dirs, + libraries, library_dirs, lang): + if self.compiler.compiler_type=='msvc': + libraries = (libraries or [])[:] + library_dirs = (library_dirs or [])[:] + if lang in ['f77', 'f90']: + lang = 'c' # always use system linker when using MSVC compiler + if self.fcompiler: + for d in self.fcompiler.library_dirs or []: + # correct path when compiling in Cygwin but with + # normal Win Python + if d.startswith('/usr/lib'): + s, o = exec_command(['cygpath', '-w', d], + use_tee=False) + if not s: d = o + library_dirs.append(d) + for libname in self.fcompiler.libraries or []: + if libname not in libraries: + libraries.append(libname) + for libname in libraries: + if libname.startswith('msvc'): continue + fileexists = False + for libdir in library_dirs or []: + libfile = os.path.join(libdir, '%s.lib' % (libname)) + if os.path.isfile(libfile): + fileexists = True + break + if fileexists: continue + # make g77-compiled static libs available to MSVC + fileexists = False + for libdir in library_dirs: + libfile = os.path.join(libdir, 'lib%s.a' % (libname)) + if os.path.isfile(libfile): + # copy libname.a file to name.lib so that MSVC linker + # can find it + libfile2 = os.path.join(libdir, '%s.lib' % (libname)) + copy_file(libfile, libfile2) + self.temp_files.append(libfile2) + fileexists = True + break + if fileexists: continue + log.warn('could not find library %r in directories %s' \ + % (libname, library_dirs)) + elif self.compiler.compiler_type == 'mingw32': + generate_manifest(self) + return self._wrap_method(old_config._link, lang, + (body, headers, include_dirs, + libraries, library_dirs, lang)) + + def check_header(self, header, include_dirs=None, library_dirs=None, lang='c'): + self._check_compiler() + return self.try_compile( + "/* we need a dummy line to make distutils happy */", + [header], include_dirs) + + def check_decl(self, symbol, + headers=None, include_dirs=None): + self._check_compiler() + body = """ +int main(void) +{ +#ifndef %s + (void) %s; +#endif + ; + return 0; +}""" % (symbol, symbol) + + return self.try_compile(body, headers, include_dirs) + + def check_macro_true(self, symbol, + headers=None, include_dirs=None): + self._check_compiler() + body = """ +int main(void) +{ +#if %s +#else +#error false or undefined macro +#endif + ; + return 0; +}""" % (symbol,) + + return self.try_compile(body, headers, include_dirs) + + def check_type(self, type_name, headers=None, include_dirs=None, + library_dirs=None): + """Check type availability. Return True if the type can be compiled, + False otherwise""" + self._check_compiler() + + # First check the type can be compiled + body = r""" +int main(void) { + if ((%(name)s *) 0) + return 0; + if (sizeof (%(name)s)) + return 0; +} +""" % {'name': type_name} + + st = False + try: + try: + self._compile(body % {'type': type_name}, + headers, include_dirs, 'c') + st = True + except distutils.errors.CompileError: + st = False + finally: + self._clean() + + return st + + def check_type_size(self, type_name, headers=None, include_dirs=None, library_dirs=None, expected=None): + """Check size of a given type.""" + self._check_compiler() + + # First check the type can be compiled + body = r""" +typedef %(type)s npy_check_sizeof_type; +int main (void) +{ + static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) >= 0)]; + test_array [0] = 0 + + ; + return 0; +} +""" + self._compile(body % {'type': type_name}, + headers, include_dirs, 'c') + self._clean() + + if expected: + body = r""" +typedef %(type)s npy_check_sizeof_type; +int main (void) +{ + static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) == %(size)s)]; + test_array [0] = 0 + + ; + return 0; +} +""" + for size in expected: + try: + self._compile(body % {'type': type_name, 'size': size}, + headers, include_dirs, 'c') + self._clean() + return size + except CompileError: + pass + + # this fails to *compile* if size > sizeof(type) + body = r""" +typedef %(type)s npy_check_sizeof_type; +int main (void) +{ + static int test_array [1 - 2 * !(((long) (sizeof (npy_check_sizeof_type))) <= %(size)s)]; + test_array [0] = 0 + + ; + return 0; +} +""" + + # The principle is simple: we first find low and high bounds of size + # for the type, where low/high are looked up on a log scale. Then, we + # do a binary search to find the exact size between low and high + low = 0 + mid = 0 + while True: + try: + self._compile(body % {'type': type_name, 'size': mid}, + headers, include_dirs, 'c') + self._clean() + break + except CompileError: + #log.info("failure to test for bound %d" % mid) + low = mid + 1 + mid = 2 * mid + 1 + + high = mid + # Binary search: + while low != high: + mid = (high - low) // 2 + low + try: + self._compile(body % {'type': type_name, 'size': mid}, + headers, include_dirs, 'c') + self._clean() + high = mid + except CompileError: + low = mid + 1 + return low + + def check_func(self, func, + headers=None, include_dirs=None, + libraries=None, library_dirs=None, + decl=False, call=False, call_args=None): + # clean up distutils's config a bit: add void to main(), and + # return a value. + self._check_compiler() + body = [] + if decl: + if type(decl) == str: + body.append(decl) + else: + body.append("int %s (void);" % func) + # Handle MSVC intrinsics: force MS compiler to make a function call. + # Useful to test for some functions when built with optimization on, to + # avoid build error because the intrinsic and our 'fake' test + # declaration do not match. + body.append("#ifdef _MSC_VER") + body.append("#pragma function(%s)" % func) + body.append("#endif") + body.append("int main (void) {") + if call: + if call_args is None: + call_args = '' + body.append(" %s(%s);" % (func, call_args)) + else: + body.append(" %s;" % func) + body.append(" return 0;") + body.append("}") + body = '\n'.join(body) + "\n" + + return self.try_link(body, headers, include_dirs, + libraries, library_dirs) + + def check_funcs_once(self, funcs, + headers=None, include_dirs=None, + libraries=None, library_dirs=None, + decl=False, call=False, call_args=None): + """Check a list of functions at once. + + This is useful to speed up things, since all the functions in the funcs + list will be put in one compilation unit. + + Arguments + --------- + funcs : seq + list of functions to test + include_dirs : seq + list of header paths + libraries : seq + list of libraries to link the code snippet to + library_dirs : seq + list of library paths + decl : dict + for every (key, value), the declaration in the value will be + used for function in key. If a function is not in the + dictionay, no declaration will be used. + call : dict + for every item (f, value), if the value is True, a call will be + done to the function f. + """ + self._check_compiler() + body = [] + if decl: + for f, v in decl.items(): + if v: + body.append("int %s (void);" % f) + + # Handle MS intrinsics. See check_func for more info. + body.append("#ifdef _MSC_VER") + for func in funcs: + body.append("#pragma function(%s)" % func) + body.append("#endif") + + body.append("int main (void) {") + if call: + for f in funcs: + if f in call and call[f]: + if not (call_args and f in call_args and call_args[f]): + args = '' + else: + args = call_args[f] + body.append(" %s(%s);" % (f, args)) + else: + body.append(" %s;" % f) + else: + for f in funcs: + body.append(" %s;" % f) + body.append(" return 0;") + body.append("}") + body = '\n'.join(body) + "\n" + + return self.try_link(body, headers, include_dirs, + libraries, library_dirs) + + def check_inline(self): + """Return the inline keyword recognized by the compiler, empty string + otherwise.""" + return check_inline(self) + + def check_restrict(self): + """Return the restrict keyword recognized by the compiler, empty string + otherwise.""" + return check_restrict(self) + + def check_compiler_gcc4(self): + """Return True if the C compiler is gcc >= 4.""" + return check_compiler_gcc4(self) + + def check_gcc_function_attribute(self, attribute, name): + return check_gcc_function_attribute(self, attribute, name) + + def check_gcc_variable_attribute(self, attribute): + return check_gcc_variable_attribute(self, attribute) + + def get_output(self, body, headers=None, include_dirs=None, + libraries=None, library_dirs=None, + lang="c", use_tee=None): + """Try to compile, link to an executable, and run a program + built from 'body' and 'headers'. Returns the exit status code + of the program and its output. + """ + # 2008-11-16, RemoveMe + warnings.warn("\n+++++++++++++++++++++++++++++++++++++++++++++++++\n" \ + "Usage of get_output is deprecated: please do not \n" \ + "use it anymore, and avoid configuration checks \n" \ + "involving running executable on the target machine.\n" \ + "+++++++++++++++++++++++++++++++++++++++++++++++++\n", + DeprecationWarning, stacklevel=2) + from distutils.ccompiler import CompileError, LinkError + self._check_compiler() + exitcode, output = 255, '' + try: + grabber = GrabStdout() + try: + src, obj, exe = self._link(body, headers, include_dirs, + libraries, library_dirs, lang) + grabber.restore() + except Exception: + output = grabber.data + grabber.restore() + raise + exe = os.path.join('.', exe) + exitstatus, output = exec_command(exe, execute_in='.', + use_tee=use_tee) + if hasattr(os, 'WEXITSTATUS'): + exitcode = os.WEXITSTATUS(exitstatus) + if os.WIFSIGNALED(exitstatus): + sig = os.WTERMSIG(exitstatus) + log.error('subprocess exited with signal %d' % (sig,)) + if sig == signal.SIGINT: + # control-C + raise KeyboardInterrupt + else: + exitcode = exitstatus + log.info("success!") + except (CompileError, LinkError): + log.info("failure.") + self._clean() + return exitcode, output + +class GrabStdout(object): + + def __init__(self): + self.sys_stdout = sys.stdout + self.data = '' + sys.stdout = self + + def write (self, data): + self.sys_stdout.write(data) + self.data += data + + def flush (self): + self.sys_stdout.flush() + + def restore(self): + sys.stdout = self.sys_stdout diff --git a/numpy/distutils/command/config_compiler.py b/numpy/distutils/command/config_compiler.py new file mode 100644 index 0000000..5e638fe --- /dev/null +++ b/numpy/distutils/command/config_compiler.py @@ -0,0 +1,125 @@ +from __future__ import division, absolute_import, print_function + +from distutils.core import Command +from numpy.distutils import log + +#XXX: Linker flags + +def show_fortran_compilers(_cache=[]): + # Using cache to prevent infinite recursion + if _cache: return + _cache.append(1) + from numpy.distutils.fcompiler import show_fcompilers + import distutils.core + dist = distutils.core._setup_distribution + show_fcompilers(dist) + +class config_fc(Command): + """ Distutils command to hold user specified options + to Fortran compilers. + + config_fc command is used by the FCompiler.customize() method. + """ + + description = "specify Fortran 77/Fortran 90 compiler information" + + user_options = [ + ('fcompiler=', None, "specify Fortran compiler type"), + ('f77exec=', None, "specify F77 compiler command"), + ('f90exec=', None, "specify F90 compiler command"), + ('f77flags=', None, "specify F77 compiler flags"), + ('f90flags=', None, "specify F90 compiler flags"), + ('opt=', None, "specify optimization flags"), + ('arch=', None, "specify architecture specific optimization flags"), + ('debug', 'g', "compile with debugging information"), + ('noopt', None, "compile without optimization"), + ('noarch', None, "compile without arch-dependent optimization"), + ] + + help_options = [ + ('help-fcompiler', None, "list available Fortran compilers", + show_fortran_compilers), + ] + + boolean_options = ['debug', 'noopt', 'noarch'] + + def initialize_options(self): + self.fcompiler = None + self.f77exec = None + self.f90exec = None + self.f77flags = None + self.f90flags = None + self.opt = None + self.arch = None + self.debug = None + self.noopt = None + self.noarch = None + + def finalize_options(self): + log.info('unifing config_fc, config, build_clib, build_ext, build commands --fcompiler options') + build_clib = self.get_finalized_command('build_clib') + build_ext = self.get_finalized_command('build_ext') + config = self.get_finalized_command('config') + build = self.get_finalized_command('build') + cmd_list = [self, config, build_clib, build_ext, build] + for a in ['fcompiler']: + l = [] + for c in cmd_list: + v = getattr(c, a) + if v is not None: + if not isinstance(v, str): v = v.compiler_type + if v not in l: l.append(v) + if not l: v1 = None + else: v1 = l[0] + if len(l)>1: + log.warn(' commands have different --%s options: %s'\ + ', using first in list as default' % (a, l)) + if v1: + for c in cmd_list: + if getattr(c, a) is None: setattr(c, a, v1) + + def run(self): + # Do nothing. + return + +class config_cc(Command): + """ Distutils command to hold user specified options + to C/C++ compilers. + """ + + description = "specify C/C++ compiler information" + + user_options = [ + ('compiler=', None, "specify C/C++ compiler type"), + ] + + def initialize_options(self): + self.compiler = None + + def finalize_options(self): + log.info('unifing config_cc, config, build_clib, build_ext, build commands --compiler options') + build_clib = self.get_finalized_command('build_clib') + build_ext = self.get_finalized_command('build_ext') + config = self.get_finalized_command('config') + build = self.get_finalized_command('build') + cmd_list = [self, config, build_clib, build_ext, build] + for a in ['compiler']: + l = [] + for c in cmd_list: + v = getattr(c, a) + if v is not None: + if not isinstance(v, str): v = v.compiler_type + if v not in l: l.append(v) + if not l: v1 = None + else: v1 = l[0] + if len(l)>1: + log.warn(' commands have different --%s options: %s'\ + ', using first in list as default' % (a, l)) + if v1: + for c in cmd_list: + if getattr(c, a) is None: setattr(c, a, v1) + return + + def run(self): + # Do nothing. + return diff --git a/numpy/distutils/command/develop.py b/numpy/distutils/command/develop.py new file mode 100644 index 0000000..1410ab2 --- /dev/null +++ b/numpy/distutils/command/develop.py @@ -0,0 +1,17 @@ +""" Override the develop command from setuptools so we can ensure that our +generated files (from build_src or build_scripts) are properly converted to real +files with filenames. + +""" +from __future__ import division, absolute_import, print_function + +from setuptools.command.develop import develop as old_develop + +class develop(old_develop): + __doc__ = old_develop.__doc__ + def install_for_development(self): + # Build sources in-place, too. + self.reinitialize_command('build_src', inplace=1) + # Make sure scripts are built. + self.run_command('build_scripts') + old_develop.install_for_development(self) diff --git a/numpy/distutils/command/egg_info.py b/numpy/distutils/command/egg_info.py new file mode 100644 index 0000000..18673ec --- /dev/null +++ b/numpy/distutils/command/egg_info.py @@ -0,0 +1,27 @@ +from __future__ import division, absolute_import, print_function + +import sys + +from setuptools.command.egg_info import egg_info as _egg_info + +class egg_info(_egg_info): + def run(self): + if 'sdist' in sys.argv: + import warnings + import textwrap + msg = textwrap.dedent(""" + `build_src` is being run, this may lead to missing + files in your sdist! You want to use distutils.sdist + instead of the setuptools version: + + from distutils.command.sdist import sdist + cmdclass={'sdist': sdist}" + + See numpy's setup.py or gh-7131 for details.""") + warnings.warn(msg, UserWarning, stacklevel=2) + + # We need to ensure that build_src has been executed in order to give + # setuptools' egg_info command real filenames instead of functions which + # generate files. + self.run_command("build_src") + _egg_info.run(self) diff --git a/numpy/distutils/command/install.py b/numpy/distutils/command/install.py new file mode 100644 index 0000000..a1dd477 --- /dev/null +++ b/numpy/distutils/command/install.py @@ -0,0 +1,82 @@ +from __future__ import division, absolute_import, print_function + +import sys +if 'setuptools' in sys.modules: + import setuptools.command.install as old_install_mod + have_setuptools = True +else: + import distutils.command.install as old_install_mod + have_setuptools = False +from distutils.file_util import write_file + +old_install = old_install_mod.install + +class install(old_install): + + # Always run install_clib - the command is cheap, so no need to bypass it; + # but it's not run by setuptools -- so it's run again in install_data + sub_commands = old_install.sub_commands + [ + ('install_clib', lambda x: True) + ] + + def finalize_options (self): + old_install.finalize_options(self) + self.install_lib = self.install_libbase + + def setuptools_run(self): + """ The setuptools version of the .run() method. + + We must pull in the entire code so we can override the level used in the + _getframe() call since we wrap this call by one more level. + """ + from distutils.command.install import install as distutils_install + + # Explicit request for old-style install? Just do it + if self.old_and_unmanageable or self.single_version_externally_managed: + return distutils_install.run(self) + + # Attempt to detect whether we were called from setup() or by another + # command. If we were called by setup(), our caller will be the + # 'run_command' method in 'distutils.dist', and *its* caller will be + # the 'run_commands' method. If we were called any other way, our + # immediate caller *might* be 'run_command', but it won't have been + # called by 'run_commands'. This is slightly kludgy, but seems to + # work. + # + caller = sys._getframe(3) + caller_module = caller.f_globals.get('__name__', '') + caller_name = caller.f_code.co_name + + if caller_module != 'distutils.dist' or caller_name!='run_commands': + # We weren't called from the command line or setup(), so we + # should run in backward-compatibility mode to support bdist_* + # commands. + distutils_install.run(self) + else: + self.do_egg_install() + + def run(self): + if not have_setuptools: + r = old_install.run(self) + else: + r = self.setuptools_run() + if self.record: + # bdist_rpm fails when INSTALLED_FILES contains + # paths with spaces. Such paths must be enclosed + # with double-quotes. + f = open(self.record, 'r') + lines = [] + need_rewrite = False + for l in f: + l = l.rstrip() + if ' ' in l: + need_rewrite = True + l = '"%s"' % (l) + lines.append(l) + f.close() + if need_rewrite: + self.execute(write_file, + (self.record, lines), + "re-writing list of installed files to '%s'" % + self.record) + return r diff --git a/numpy/distutils/command/install_clib.py b/numpy/distutils/command/install_clib.py new file mode 100644 index 0000000..662aa00 --- /dev/null +++ b/numpy/distutils/command/install_clib.py @@ -0,0 +1,39 @@ +from __future__ import division, absolute_import, print_function + +import os +from distutils.core import Command +from distutils.ccompiler import new_compiler +from numpy.distutils.misc_util import get_cmd + +class install_clib(Command): + description = "Command to install installable C libraries" + + user_options = [] + + def initialize_options(self): + self.install_dir = None + self.outfiles = [] + + def finalize_options(self): + self.set_undefined_options('install', ('install_lib', 'install_dir')) + + def run (self): + build_clib_cmd = get_cmd("build_clib") + build_dir = build_clib_cmd.build_clib + + # We need the compiler to get the library name -> filename association + if not build_clib_cmd.compiler: + compiler = new_compiler(compiler=None) + compiler.customize(self.distribution) + else: + compiler = build_clib_cmd.compiler + + for l in self.distribution.installed_libraries: + target_dir = os.path.join(self.install_dir, l.target_dir) + name = compiler.library_filename(l.name) + source = os.path.join(build_dir, name) + self.mkpath(target_dir) + self.outfiles.append(self.copy_file(source, target_dir)[0]) + + def get_outputs(self): + return self.outfiles diff --git a/numpy/distutils/command/install_data.py b/numpy/distutils/command/install_data.py new file mode 100644 index 0000000..996cf7e --- /dev/null +++ b/numpy/distutils/command/install_data.py @@ -0,0 +1,26 @@ +from __future__ import division, absolute_import, print_function + +import sys +have_setuptools = ('setuptools' in sys.modules) + +from distutils.command.install_data import install_data as old_install_data + +#data installer with improved intelligence over distutils +#data files are copied into the project directory instead +#of willy-nilly +class install_data (old_install_data): + + def run(self): + old_install_data.run(self) + + if have_setuptools: + # Run install_clib again, since setuptools does not run sub-commands + # of install automatically + self.run_command('install_clib') + + def finalize_options (self): + self.set_undefined_options('install', + ('install_lib', 'install_dir'), + ('root', 'root'), + ('force', 'force'), + ) diff --git a/numpy/distutils/command/install_headers.py b/numpy/distutils/command/install_headers.py new file mode 100644 index 0000000..f3f58aa --- /dev/null +++ b/numpy/distutils/command/install_headers.py @@ -0,0 +1,27 @@ +from __future__ import division, absolute_import, print_function + +import os +from distutils.command.install_headers import install_headers as old_install_headers + +class install_headers (old_install_headers): + + def run (self): + headers = self.distribution.headers + if not headers: + return + + prefix = os.path.dirname(self.install_dir) + for header in headers: + if isinstance(header, tuple): + # Kind of a hack, but I don't know where else to change this... + if header[0] == 'numpy.core': + header = ('numpy', header[1]) + if os.path.splitext(header[1])[1] == '.inc': + continue + d = os.path.join(*([prefix]+header[0].split('.'))) + header = header[1] + else: + d = self.install_dir + self.mkpath(d) + (out, _) = self.copy_file(header, d) + self.outfiles.append(out) diff --git a/numpy/distutils/command/sdist.py b/numpy/distutils/command/sdist.py new file mode 100644 index 0000000..bfaab1c --- /dev/null +++ b/numpy/distutils/command/sdist.py @@ -0,0 +1,29 @@ +from __future__ import division, absolute_import, print_function + +import sys +if 'setuptools' in sys.modules: + from setuptools.command.sdist import sdist as old_sdist +else: + from distutils.command.sdist import sdist as old_sdist + +from numpy.distutils.misc_util import get_data_files + +class sdist(old_sdist): + + def add_defaults (self): + old_sdist.add_defaults(self) + + dist = self.distribution + + if dist.has_data_files(): + for data in dist.data_files: + self.filelist.extend(get_data_files(data)) + + if dist.has_headers(): + headers = [] + for h in dist.headers: + if isinstance(h, str): headers.append(h) + else: headers.append(h[1]) + self.filelist.extend(headers) + + return diff --git a/numpy/distutils/compat.py b/numpy/distutils/compat.py new file mode 100644 index 0000000..9a81cd3 --- /dev/null +++ b/numpy/distutils/compat.py @@ -0,0 +1,10 @@ +"""Small modules to cope with python 2 vs 3 incompatibilities inside +numpy.distutils + +""" +from __future__ import division, absolute_import, print_function + +import sys + +def get_exception(): + return sys.exc_info()[1] diff --git a/numpy/distutils/conv_template.py b/numpy/distutils/conv_template.py new file mode 100644 index 0000000..a426110 --- /dev/null +++ b/numpy/distutils/conv_template.py @@ -0,0 +1,337 @@ +#!/usr/bin/env python +""" +takes templated file .xxx.src and produces .xxx file where .xxx is +.i or .c or .h, using the following template rules + +/**begin repeat -- on a line by itself marks the start of a repeated code + segment +/**end repeat**/ -- on a line by itself marks it's end + +After the /**begin repeat and before the */, all the named templates are placed +these should all have the same number of replacements + +Repeat blocks can be nested, with each nested block labeled with its depth, +i.e. +/**begin repeat1 + *.... + */ +/**end repeat1**/ + +When using nested loops, you can optionally exclude particular +combinations of the variables using (inside the comment portion of the inner loop): + + :exclude: var1=value1, var2=value2, ... + +This will exclude the pattern where var1 is value1 and var2 is value2 when +the result is being generated. + + +In the main body each replace will use one entry from the list of named replacements + + Note that all #..# forms in a block must have the same number of + comma-separated entries. + +Example: + + An input file containing + + /**begin repeat + * #a = 1,2,3# + * #b = 1,2,3# + */ + + /**begin repeat1 + * #c = ted, jim# + */ + @a@, @b@, @c@ + /**end repeat1**/ + + /**end repeat**/ + + produces + + line 1 "template.c.src" + + /* + ********************************************************************* + ** This file was autogenerated from a template DO NOT EDIT!!** + ** Changes should be made to the original source (.src) file ** + ********************************************************************* + */ + + #line 9 + 1, 1, ted + + #line 9 + 1, 1, jim + + #line 9 + 2, 2, ted + + #line 9 + 2, 2, jim + + #line 9 + 3, 3, ted + + #line 9 + 3, 3, jim + +""" +from __future__ import division, absolute_import, print_function + + +__all__ = ['process_str', 'process_file'] + +import os +import sys +import re + +from numpy.distutils.compat import get_exception + +# names for replacement that are already global. +global_names = {} + +# header placed at the front of head processed file +header =\ +""" +/* + ***************************************************************************** + ** This file was autogenerated from a template DO NOT EDIT!!!! ** + ** Changes should be made to the original source (.src) file ** + ***************************************************************************** + */ + +""" +# Parse string for repeat loops +def parse_structure(astr, level): + """ + The returned line number is from the beginning of the string, starting + at zero. Returns an empty list if no loops found. + + """ + if level == 0 : + loopbeg = "/**begin repeat" + loopend = "/**end repeat**/" + else : + loopbeg = "/**begin repeat%d" % level + loopend = "/**end repeat%d**/" % level + + ind = 0 + line = 0 + spanlist = [] + while True: + start = astr.find(loopbeg, ind) + if start == -1: + break + start2 = astr.find("*/", start) + start2 = astr.find("\n", start2) + fini1 = astr.find(loopend, start2) + fini2 = astr.find("\n", fini1) + line += astr.count("\n", ind, start2+1) + spanlist.append((start, start2+1, fini1, fini2+1, line)) + line += astr.count("\n", start2+1, fini2) + ind = fini2 + spanlist.sort() + return spanlist + + +def paren_repl(obj): + torep = obj.group(1) + numrep = obj.group(2) + return ','.join([torep]*int(numrep)) + +parenrep = re.compile(r"[(]([^)]*)[)]\*(\d+)") +plainrep = re.compile(r"([^*]+)\*(\d+)") +def parse_values(astr): + # replaces all occurrences of '(a,b,c)*4' in astr + # with 'a,b,c,a,b,c,a,b,c,a,b,c'. Empty braces generate + # empty values, i.e., ()*4 yields ',,,'. The result is + # split at ',' and a list of values returned. + astr = parenrep.sub(paren_repl, astr) + # replaces occurrences of xxx*3 with xxx, xxx, xxx + astr = ','.join([plainrep.sub(paren_repl, x.strip()) + for x in astr.split(',')]) + return astr.split(',') + + +stripast = re.compile(r"\n\s*\*?") +named_re = re.compile(r"#\s*(\w*)\s*=([^#]*)#") +exclude_vars_re = re.compile(r"(\w*)=(\w*)") +exclude_re = re.compile(":exclude:") +def parse_loop_header(loophead) : + """Find all named replacements in the header + + Returns a list of dictionaries, one for each loop iteration, + where each key is a name to be substituted and the corresponding + value is the replacement string. + + Also return a list of exclusions. The exclusions are dictionaries + of key value pairs. There can be more than one exclusion. + [{'var1':'value1', 'var2', 'value2'[,...]}, ...] + + """ + # Strip out '\n' and leading '*', if any, in continuation lines. + # This should not effect code previous to this change as + # continuation lines were not allowed. + loophead = stripast.sub("", loophead) + # parse out the names and lists of values + names = [] + reps = named_re.findall(loophead) + nsub = None + for rep in reps: + name = rep[0] + vals = parse_values(rep[1]) + size = len(vals) + if nsub is None : + nsub = size + elif nsub != size : + msg = "Mismatch in number of values, %d != %d\n%s = %s" + raise ValueError(msg % (nsub, size, name, vals)) + names.append((name, vals)) + + + # Find any exclude variables + excludes = [] + + for obj in exclude_re.finditer(loophead): + span = obj.span() + # find next newline + endline = loophead.find('\n', span[1]) + substr = loophead[span[1]:endline] + ex_names = exclude_vars_re.findall(substr) + excludes.append(dict(ex_names)) + + # generate list of dictionaries, one for each template iteration + dlist = [] + if nsub is None : + raise ValueError("No substitution variables found") + for i in range(nsub) : + tmp = {} + for name, vals in names : + tmp[name] = vals[i] + dlist.append(tmp) + return dlist + +replace_re = re.compile(r"@([\w]+)@") +def parse_string(astr, env, level, line) : + lineno = "#line %d\n" % line + + # local function for string replacement, uses env + def replace(match): + name = match.group(1) + try : + val = env[name] + except KeyError: + msg = 'line %d: no definition of key "%s"'%(line, name) + raise ValueError(msg) + return val + + code = [lineno] + struct = parse_structure(astr, level) + if struct : + # recurse over inner loops + oldend = 0 + newlevel = level + 1 + for sub in struct: + pref = astr[oldend:sub[0]] + head = astr[sub[0]:sub[1]] + text = astr[sub[1]:sub[2]] + oldend = sub[3] + newline = line + sub[4] + code.append(replace_re.sub(replace, pref)) + try : + envlist = parse_loop_header(head) + except ValueError: + e = get_exception() + msg = "line %d: %s" % (newline, e) + raise ValueError(msg) + for newenv in envlist : + newenv.update(env) + newcode = parse_string(text, newenv, newlevel, newline) + code.extend(newcode) + suff = astr[oldend:] + code.append(replace_re.sub(replace, suff)) + else : + # replace keys + code.append(replace_re.sub(replace, astr)) + code.append('\n') + return ''.join(code) + +def process_str(astr): + code = [header] + code.extend(parse_string(astr, global_names, 0, 1)) + return ''.join(code) + + +include_src_re = re.compile(r"(\n|\A)#include\s*['\"]" + r"(?P[\w\d./\\]+[.]src)['\"]", re.I) + +def resolve_includes(source): + d = os.path.dirname(source) + fid = open(source) + lines = [] + for line in fid: + m = include_src_re.match(line) + if m: + fn = m.group('name') + if not os.path.isabs(fn): + fn = os.path.join(d, fn) + if os.path.isfile(fn): + print('Including file', fn) + lines.extend(resolve_includes(fn)) + else: + lines.append(line) + else: + lines.append(line) + fid.close() + return lines + +def process_file(source): + lines = resolve_includes(source) + sourcefile = os.path.normcase(source).replace("\\", "\\\\") + try: + code = process_str(''.join(lines)) + except ValueError: + e = get_exception() + raise ValueError('In "%s" loop at %s' % (sourcefile, e)) + return '#line 1 "%s"\n%s' % (sourcefile, code) + + +def unique_key(adict): + # this obtains a unique key given a dictionary + # currently it works by appending together n of the letters of the + # current keys and increasing n until a unique key is found + # -- not particularly quick + allkeys = list(adict.keys()) + done = False + n = 1 + while not done: + newkey = "".join([x[:n] for x in allkeys]) + if newkey in allkeys: + n += 1 + else: + done = True + return newkey + + +if __name__ == "__main__": + + try: + file = sys.argv[1] + except IndexError: + fid = sys.stdin + outfile = sys.stdout + else: + fid = open(file, 'r') + (base, ext) = os.path.splitext(file) + newname = base + outfile = open(newname, 'w') + + allstr = fid.read() + try: + writestr = process_str(allstr) + except ValueError: + e = get_exception() + raise ValueError("In %s loop at %s" % (file, e)) + outfile.write(writestr) diff --git a/numpy/distutils/core.py b/numpy/distutils/core.py new file mode 100644 index 0000000..d9e1253 --- /dev/null +++ b/numpy/distutils/core.py @@ -0,0 +1,215 @@ +from __future__ import division, absolute_import, print_function + +import sys +from distutils.core import * + +if 'setuptools' in sys.modules: + have_setuptools = True + from setuptools import setup as old_setup + # easy_install imports math, it may be picked up from cwd + from setuptools.command import easy_install + try: + # very old versions of setuptools don't have this + from setuptools.command import bdist_egg + except ImportError: + have_setuptools = False +else: + from distutils.core import setup as old_setup + have_setuptools = False + +import warnings +import distutils.core +import distutils.dist + +from numpy.distutils.extension import Extension +from numpy.distutils.numpy_distribution import NumpyDistribution +from numpy.distutils.command import config, config_compiler, \ + build, build_py, build_ext, build_clib, build_src, build_scripts, \ + sdist, install_data, install_headers, install, bdist_rpm, \ + install_clib +from numpy.distutils.misc_util import get_data_files, is_sequence, is_string + +numpy_cmdclass = {'build': build.build, + 'build_src': build_src.build_src, + 'build_scripts': build_scripts.build_scripts, + 'config_cc': config_compiler.config_cc, + 'config_fc': config_compiler.config_fc, + 'config': config.config, + 'build_ext': build_ext.build_ext, + 'build_py': build_py.build_py, + 'build_clib': build_clib.build_clib, + 'sdist': sdist.sdist, + 'install_data': install_data.install_data, + 'install_headers': install_headers.install_headers, + 'install_clib': install_clib.install_clib, + 'install': install.install, + 'bdist_rpm': bdist_rpm.bdist_rpm, + } +if have_setuptools: + # Use our own versions of develop and egg_info to ensure that build_src is + # handled appropriately. + from numpy.distutils.command import develop, egg_info + numpy_cmdclass['bdist_egg'] = bdist_egg.bdist_egg + numpy_cmdclass['develop'] = develop.develop + numpy_cmdclass['easy_install'] = easy_install.easy_install + numpy_cmdclass['egg_info'] = egg_info.egg_info + +def _dict_append(d, **kws): + for k, v in kws.items(): + if k not in d: + d[k] = v + continue + dv = d[k] + if isinstance(dv, tuple): + d[k] = dv + tuple(v) + elif isinstance(dv, list): + d[k] = dv + list(v) + elif isinstance(dv, dict): + _dict_append(dv, **v) + elif is_string(dv): + d[k] = dv + v + else: + raise TypeError(repr(type(dv))) + +def _command_line_ok(_cache=[]): + """ Return True if command line does not contain any + help or display requests. + """ + if _cache: + return _cache[0] + ok = True + display_opts = ['--'+n for n in Distribution.display_option_names] + for o in Distribution.display_options: + if o[1]: + display_opts.append('-'+o[1]) + for arg in sys.argv: + if arg.startswith('--help') or arg=='-h' or arg in display_opts: + ok = False + break + _cache.append(ok) + return ok + +def get_distribution(always=False): + dist = distutils.core._setup_distribution + # XXX Hack to get numpy installable with easy_install. + # The problem is easy_install runs it's own setup(), which + # sets up distutils.core._setup_distribution. However, + # when our setup() runs, that gets overwritten and lost. + # We can't use isinstance, as the DistributionWithoutHelpCommands + # class is local to a function in setuptools.command.easy_install + if dist is not None and \ + 'DistributionWithoutHelpCommands' in repr(dist): + dist = None + if always and dist is None: + dist = NumpyDistribution() + return dist + +def setup(**attr): + + cmdclass = numpy_cmdclass.copy() + + new_attr = attr.copy() + if 'cmdclass' in new_attr: + cmdclass.update(new_attr['cmdclass']) + new_attr['cmdclass'] = cmdclass + + if 'configuration' in new_attr: + # To avoid calling configuration if there are any errors + # or help request in command in the line. + configuration = new_attr.pop('configuration') + + old_dist = distutils.core._setup_distribution + old_stop = distutils.core._setup_stop_after + distutils.core._setup_distribution = None + distutils.core._setup_stop_after = "commandline" + try: + dist = setup(**new_attr) + finally: + distutils.core._setup_distribution = old_dist + distutils.core._setup_stop_after = old_stop + if dist.help or not _command_line_ok(): + # probably displayed help, skip running any commands + return dist + + # create setup dictionary and append to new_attr + config = configuration() + if hasattr(config, 'todict'): + config = config.todict() + _dict_append(new_attr, **config) + + # Move extension source libraries to libraries + libraries = [] + for ext in new_attr.get('ext_modules', []): + new_libraries = [] + for item in ext.libraries: + if is_sequence(item): + lib_name, build_info = item + _check_append_ext_library(libraries, lib_name, build_info) + new_libraries.append(lib_name) + elif is_string(item): + new_libraries.append(item) + else: + raise TypeError("invalid description of extension module " + "library %r" % (item,)) + ext.libraries = new_libraries + if libraries: + if 'libraries' not in new_attr: + new_attr['libraries'] = [] + for item in libraries: + _check_append_library(new_attr['libraries'], item) + + # sources in ext_modules or libraries may contain header files + if ('ext_modules' in new_attr or 'libraries' in new_attr) \ + and 'headers' not in new_attr: + new_attr['headers'] = [] + + # Use our custom NumpyDistribution class instead of distutils' one + new_attr['distclass'] = NumpyDistribution + + return old_setup(**new_attr) + +def _check_append_library(libraries, item): + for libitem in libraries: + if is_sequence(libitem): + if is_sequence(item): + if item[0]==libitem[0]: + if item[1] is libitem[1]: + return + warnings.warn("[0] libraries list contains %r with" + " different build_info" % (item[0],), + stacklevel=2) + break + else: + if item==libitem[0]: + warnings.warn("[1] libraries list contains %r with" + " no build_info" % (item[0],), + stacklevel=2) + break + else: + if is_sequence(item): + if item[0]==libitem: + warnings.warn("[2] libraries list contains %r with" + " no build_info" % (item[0],), + stacklevel=2) + break + else: + if item==libitem: + return + libraries.append(item) + +def _check_append_ext_library(libraries, lib_name, build_info): + for item in libraries: + if is_sequence(item): + if item[0]==lib_name: + if item[1] is build_info: + return + warnings.warn("[3] libraries list contains %r with" + " different build_info" % (lib_name,), + stacklevel=2) + break + elif item==lib_name: + warnings.warn("[4] libraries list contains %r with" + " no build_info" % (lib_name,), + stacklevel=2) + break + libraries.append((lib_name, build_info)) diff --git a/numpy/distutils/cpuinfo.py b/numpy/distutils/cpuinfo.py new file mode 100644 index 0000000..5802993 --- /dev/null +++ b/numpy/distutils/cpuinfo.py @@ -0,0 +1,693 @@ +#!/usr/bin/env python +""" +cpuinfo + +Copyright 2002 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy (BSD style) license. See LICENSE.txt that came with +this distribution for specifics. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['cpu'] + +import sys, re, types +import os + +if sys.version_info[0] >= 3: + from subprocess import getstatusoutput +else: + from commands import getstatusoutput + +import warnings +import platform + +from numpy.distutils.compat import get_exception + +def getoutput(cmd, successful_status=(0,), stacklevel=1): + try: + status, output = getstatusoutput(cmd) + except EnvironmentError: + e = get_exception() + warnings.warn(str(e), UserWarning, stacklevel=stacklevel) + return False, "" + if os.WIFEXITED(status) and os.WEXITSTATUS(status) in successful_status: + return True, output + return False, output + +def command_info(successful_status=(0,), stacklevel=1, **kw): + info = {} + for key in kw: + ok, output = getoutput(kw[key], successful_status=successful_status, + stacklevel=stacklevel+1) + if ok: + info[key] = output.strip() + return info + +def command_by_line(cmd, successful_status=(0,), stacklevel=1): + ok, output = getoutput(cmd, successful_status=successful_status, + stacklevel=stacklevel+1) + if not ok: + return + for line in output.splitlines(): + yield line.strip() + +def key_value_from_command(cmd, sep, successful_status=(0,), + stacklevel=1): + d = {} + for line in command_by_line(cmd, successful_status=successful_status, + stacklevel=stacklevel+1): + l = [s.strip() for s in line.split(sep, 1)] + if len(l) == 2: + d[l[0]] = l[1] + return d + +class CPUInfoBase(object): + """Holds CPU information and provides methods for requiring + the availability of various CPU features. + """ + + def _try_call(self, func): + try: + return func() + except Exception: + pass + + def __getattr__(self, name): + if not name.startswith('_'): + if hasattr(self, '_'+name): + attr = getattr(self, '_'+name) + if isinstance(attr, types.MethodType): + return lambda func=self._try_call,attr=attr : func(attr) + else: + return lambda : None + raise AttributeError(name) + + def _getNCPUs(self): + return 1 + + def __get_nbits(self): + abits = platform.architecture()[0] + nbits = re.compile(r'(\d+)bit').search(abits).group(1) + return nbits + + def _is_32bit(self): + return self.__get_nbits() == '32' + + def _is_64bit(self): + return self.__get_nbits() == '64' + +class LinuxCPUInfo(CPUInfoBase): + + info = None + + def __init__(self): + if self.info is not None: + return + info = [ {} ] + ok, output = getoutput('uname -m') + if ok: + info[0]['uname_m'] = output.strip() + try: + fo = open('/proc/cpuinfo') + except EnvironmentError: + e = get_exception() + warnings.warn(str(e), UserWarning, stacklevel=2) + else: + for line in fo: + name_value = [s.strip() for s in line.split(':', 1)] + if len(name_value) != 2: + continue + name, value = name_value + if not info or name in info[-1]: # next processor + info.append({}) + info[-1][name] = value + fo.close() + self.__class__.info = info + + def _not_impl(self): pass + + # Athlon + + def _is_AMD(self): + return self.info[0]['vendor_id']=='AuthenticAMD' + + def _is_AthlonK6_2(self): + return self._is_AMD() and self.info[0]['model'] == '2' + + def _is_AthlonK6_3(self): + return self._is_AMD() and self.info[0]['model'] == '3' + + def _is_AthlonK6(self): + return re.match(r'.*?AMD-K6', self.info[0]['model name']) is not None + + def _is_AthlonK7(self): + return re.match(r'.*?AMD-K7', self.info[0]['model name']) is not None + + def _is_AthlonMP(self): + return re.match(r'.*?Athlon\(tm\) MP\b', + self.info[0]['model name']) is not None + + def _is_AMD64(self): + return self.is_AMD() and self.info[0]['family'] == '15' + + def _is_Athlon64(self): + return re.match(r'.*?Athlon\(tm\) 64\b', + self.info[0]['model name']) is not None + + def _is_AthlonHX(self): + return re.match(r'.*?Athlon HX\b', + self.info[0]['model name']) is not None + + def _is_Opteron(self): + return re.match(r'.*?Opteron\b', + self.info[0]['model name']) is not None + + def _is_Hammer(self): + return re.match(r'.*?Hammer\b', + self.info[0]['model name']) is not None + + # Alpha + + def _is_Alpha(self): + return self.info[0]['cpu']=='Alpha' + + def _is_EV4(self): + return self.is_Alpha() and self.info[0]['cpu model'] == 'EV4' + + def _is_EV5(self): + return self.is_Alpha() and self.info[0]['cpu model'] == 'EV5' + + def _is_EV56(self): + return self.is_Alpha() and self.info[0]['cpu model'] == 'EV56' + + def _is_PCA56(self): + return self.is_Alpha() and self.info[0]['cpu model'] == 'PCA56' + + # Intel + + #XXX + _is_i386 = _not_impl + + def _is_Intel(self): + return self.info[0]['vendor_id']=='GenuineIntel' + + def _is_i486(self): + return self.info[0]['cpu']=='i486' + + def _is_i586(self): + return self.is_Intel() and self.info[0]['cpu family'] == '5' + + def _is_i686(self): + return self.is_Intel() and self.info[0]['cpu family'] == '6' + + def _is_Celeron(self): + return re.match(r'.*?Celeron', + self.info[0]['model name']) is not None + + def _is_Pentium(self): + return re.match(r'.*?Pentium', + self.info[0]['model name']) is not None + + def _is_PentiumII(self): + return re.match(r'.*?Pentium.*?II\b', + self.info[0]['model name']) is not None + + def _is_PentiumPro(self): + return re.match(r'.*?PentiumPro\b', + self.info[0]['model name']) is not None + + def _is_PentiumMMX(self): + return re.match(r'.*?Pentium.*?MMX\b', + self.info[0]['model name']) is not None + + def _is_PentiumIII(self): + return re.match(r'.*?Pentium.*?III\b', + self.info[0]['model name']) is not None + + def _is_PentiumIV(self): + return re.match(r'.*?Pentium.*?(IV|4)\b', + self.info[0]['model name']) is not None + + def _is_PentiumM(self): + return re.match(r'.*?Pentium.*?M\b', + self.info[0]['model name']) is not None + + def _is_Prescott(self): + return self.is_PentiumIV() and self.has_sse3() + + def _is_Nocona(self): + return self.is_Intel() \ + and (self.info[0]['cpu family'] == '6' \ + or self.info[0]['cpu family'] == '15' ) \ + and (self.has_sse3() and not self.has_ssse3())\ + and re.match(r'.*?\blm\b', self.info[0]['flags']) is not None + + def _is_Core2(self): + return self.is_64bit() and self.is_Intel() and \ + re.match(r'.*?Core\(TM\)2\b', \ + self.info[0]['model name']) is not None + + def _is_Itanium(self): + return re.match(r'.*?Itanium\b', + self.info[0]['family']) is not None + + def _is_XEON(self): + return re.match(r'.*?XEON\b', + self.info[0]['model name'], re.IGNORECASE) is not None + + _is_Xeon = _is_XEON + + # Varia + + def _is_singleCPU(self): + return len(self.info) == 1 + + def _getNCPUs(self): + return len(self.info) + + def _has_fdiv_bug(self): + return self.info[0]['fdiv_bug']=='yes' + + def _has_f00f_bug(self): + return self.info[0]['f00f_bug']=='yes' + + def _has_mmx(self): + return re.match(r'.*?\bmmx\b', self.info[0]['flags']) is not None + + def _has_sse(self): + return re.match(r'.*?\bsse\b', self.info[0]['flags']) is not None + + def _has_sse2(self): + return re.match(r'.*?\bsse2\b', self.info[0]['flags']) is not None + + def _has_sse3(self): + return re.match(r'.*?\bpni\b', self.info[0]['flags']) is not None + + def _has_ssse3(self): + return re.match(r'.*?\bssse3\b', self.info[0]['flags']) is not None + + def _has_3dnow(self): + return re.match(r'.*?\b3dnow\b', self.info[0]['flags']) is not None + + def _has_3dnowext(self): + return re.match(r'.*?\b3dnowext\b', self.info[0]['flags']) is not None + +class IRIXCPUInfo(CPUInfoBase): + info = None + + def __init__(self): + if self.info is not None: + return + info = key_value_from_command('sysconf', sep=' ', + successful_status=(0, 1)) + self.__class__.info = info + + def _not_impl(self): pass + + def _is_singleCPU(self): + return self.info.get('NUM_PROCESSORS') == '1' + + def _getNCPUs(self): + return int(self.info.get('NUM_PROCESSORS', 1)) + + def __cputype(self, n): + return self.info.get('PROCESSORS').split()[0].lower() == 'r%s' % (n) + def _is_r2000(self): return self.__cputype(2000) + def _is_r3000(self): return self.__cputype(3000) + def _is_r3900(self): return self.__cputype(3900) + def _is_r4000(self): return self.__cputype(4000) + def _is_r4100(self): return self.__cputype(4100) + def _is_r4300(self): return self.__cputype(4300) + def _is_r4400(self): return self.__cputype(4400) + def _is_r4600(self): return self.__cputype(4600) + def _is_r4650(self): return self.__cputype(4650) + def _is_r5000(self): return self.__cputype(5000) + def _is_r6000(self): return self.__cputype(6000) + def _is_r8000(self): return self.__cputype(8000) + def _is_r10000(self): return self.__cputype(10000) + def _is_r12000(self): return self.__cputype(12000) + def _is_rorion(self): return self.__cputype('orion') + + def get_ip(self): + try: return self.info.get('MACHINE') + except Exception: pass + def __machine(self, n): + return self.info.get('MACHINE').lower() == 'ip%s' % (n) + def _is_IP19(self): return self.__machine(19) + def _is_IP20(self): return self.__machine(20) + def _is_IP21(self): return self.__machine(21) + def _is_IP22(self): return self.__machine(22) + def _is_IP22_4k(self): return self.__machine(22) and self._is_r4000() + def _is_IP22_5k(self): return self.__machine(22) and self._is_r5000() + def _is_IP24(self): return self.__machine(24) + def _is_IP25(self): return self.__machine(25) + def _is_IP26(self): return self.__machine(26) + def _is_IP27(self): return self.__machine(27) + def _is_IP28(self): return self.__machine(28) + def _is_IP30(self): return self.__machine(30) + def _is_IP32(self): return self.__machine(32) + def _is_IP32_5k(self): return self.__machine(32) and self._is_r5000() + def _is_IP32_10k(self): return self.__machine(32) and self._is_r10000() + + +class DarwinCPUInfo(CPUInfoBase): + info = None + + def __init__(self): + if self.info is not None: + return + info = command_info(arch='arch', + machine='machine') + info['sysctl_hw'] = key_value_from_command('sysctl hw', sep='=') + self.__class__.info = info + + def _not_impl(self): pass + + def _getNCPUs(self): + return int(self.info['sysctl_hw'].get('hw.ncpu', 1)) + + def _is_Power_Macintosh(self): + return self.info['sysctl_hw']['hw.machine']=='Power Macintosh' + + def _is_i386(self): + return self.info['arch']=='i386' + def _is_ppc(self): + return self.info['arch']=='ppc' + + def __machine(self, n): + return self.info['machine'] == 'ppc%s'%n + def _is_ppc601(self): return self.__machine(601) + def _is_ppc602(self): return self.__machine(602) + def _is_ppc603(self): return self.__machine(603) + def _is_ppc603e(self): return self.__machine('603e') + def _is_ppc604(self): return self.__machine(604) + def _is_ppc604e(self): return self.__machine('604e') + def _is_ppc620(self): return self.__machine(620) + def _is_ppc630(self): return self.__machine(630) + def _is_ppc740(self): return self.__machine(740) + def _is_ppc7400(self): return self.__machine(7400) + def _is_ppc7450(self): return self.__machine(7450) + def _is_ppc750(self): return self.__machine(750) + def _is_ppc403(self): return self.__machine(403) + def _is_ppc505(self): return self.__machine(505) + def _is_ppc801(self): return self.__machine(801) + def _is_ppc821(self): return self.__machine(821) + def _is_ppc823(self): return self.__machine(823) + def _is_ppc860(self): return self.__machine(860) + + +class SunOSCPUInfo(CPUInfoBase): + + info = None + + def __init__(self): + if self.info is not None: + return + info = command_info(arch='arch', + mach='mach', + uname_i='uname_i', + isainfo_b='isainfo -b', + isainfo_n='isainfo -n', + ) + info['uname_X'] = key_value_from_command('uname -X', sep='=') + for line in command_by_line('psrinfo -v 0'): + m = re.match(r'\s*The (?P

    [\w\d]+) processor operates at', line) + if m: + info['processor'] = m.group('p') + break + self.__class__.info = info + + def _not_impl(self): pass + + def _is_i386(self): + return self.info['isainfo_n']=='i386' + def _is_sparc(self): + return self.info['isainfo_n']=='sparc' + def _is_sparcv9(self): + return self.info['isainfo_n']=='sparcv9' + + def _getNCPUs(self): + return int(self.info['uname_X'].get('NumCPU', 1)) + + def _is_sun4(self): + return self.info['arch']=='sun4' + + def _is_SUNW(self): + return re.match(r'SUNW', self.info['uname_i']) is not None + def _is_sparcstation5(self): + return re.match(r'.*SPARCstation-5', self.info['uname_i']) is not None + def _is_ultra1(self): + return re.match(r'.*Ultra-1', self.info['uname_i']) is not None + def _is_ultra250(self): + return re.match(r'.*Ultra-250', self.info['uname_i']) is not None + def _is_ultra2(self): + return re.match(r'.*Ultra-2', self.info['uname_i']) is not None + def _is_ultra30(self): + return re.match(r'.*Ultra-30', self.info['uname_i']) is not None + def _is_ultra4(self): + return re.match(r'.*Ultra-4', self.info['uname_i']) is not None + def _is_ultra5_10(self): + return re.match(r'.*Ultra-5_10', self.info['uname_i']) is not None + def _is_ultra5(self): + return re.match(r'.*Ultra-5', self.info['uname_i']) is not None + def _is_ultra60(self): + return re.match(r'.*Ultra-60', self.info['uname_i']) is not None + def _is_ultra80(self): + return re.match(r'.*Ultra-80', self.info['uname_i']) is not None + def _is_ultraenterprice(self): + return re.match(r'.*Ultra-Enterprise', self.info['uname_i']) is not None + def _is_ultraenterprice10k(self): + return re.match(r'.*Ultra-Enterprise-10000', self.info['uname_i']) is not None + def _is_sunfire(self): + return re.match(r'.*Sun-Fire', self.info['uname_i']) is not None + def _is_ultra(self): + return re.match(r'.*Ultra', self.info['uname_i']) is not None + + def _is_cpusparcv7(self): + return self.info['processor']=='sparcv7' + def _is_cpusparcv8(self): + return self.info['processor']=='sparcv8' + def _is_cpusparcv9(self): + return self.info['processor']=='sparcv9' + +class Win32CPUInfo(CPUInfoBase): + + info = None + pkey = r"HARDWARE\DESCRIPTION\System\CentralProcessor" + # XXX: what does the value of + # HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0 + # mean? + + def __init__(self): + if self.info is not None: + return + info = [] + try: + #XXX: Bad style to use so long `try:...except:...`. Fix it! + if sys.version_info[0] >= 3: + import winreg + else: + import _winreg as winreg + + prgx = re.compile(r"family\s+(?P\d+)\s+model\s+(?P\d+)" + r"\s+stepping\s+(?P\d+)", re.IGNORECASE) + chnd=winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, self.pkey) + pnum=0 + while True: + try: + proc=winreg.EnumKey(chnd, pnum) + except winreg.error: + break + else: + pnum+=1 + info.append({"Processor":proc}) + phnd=winreg.OpenKey(chnd, proc) + pidx=0 + while True: + try: + name, value, vtpe=winreg.EnumValue(phnd, pidx) + except winreg.error: + break + else: + pidx=pidx+1 + info[-1][name]=value + if name=="Identifier": + srch=prgx.search(value) + if srch: + info[-1]["Family"]=int(srch.group("FML")) + info[-1]["Model"]=int(srch.group("MDL")) + info[-1]["Stepping"]=int(srch.group("STP")) + except Exception: + print(sys.exc_info()[1], '(ignoring)') + self.__class__.info = info + + def _not_impl(self): pass + + # Athlon + + def _is_AMD(self): + return self.info[0]['VendorIdentifier']=='AuthenticAMD' + + def _is_Am486(self): + return self.is_AMD() and self.info[0]['Family']==4 + + def _is_Am5x86(self): + return self.is_AMD() and self.info[0]['Family']==4 + + def _is_AMDK5(self): + return self.is_AMD() and self.info[0]['Family']==5 \ + and self.info[0]['Model'] in [0, 1, 2, 3] + + def _is_AMDK6(self): + return self.is_AMD() and self.info[0]['Family']==5 \ + and self.info[0]['Model'] in [6, 7] + + def _is_AMDK6_2(self): + return self.is_AMD() and self.info[0]['Family']==5 \ + and self.info[0]['Model']==8 + + def _is_AMDK6_3(self): + return self.is_AMD() and self.info[0]['Family']==5 \ + and self.info[0]['Model']==9 + + def _is_AMDK7(self): + return self.is_AMD() and self.info[0]['Family'] == 6 + + # To reliably distinguish between the different types of AMD64 chips + # (Athlon64, Operton, Athlon64 X2, Semperon, Turion 64, etc.) would + # require looking at the 'brand' from cpuid + + def _is_AMD64(self): + return self.is_AMD() and self.info[0]['Family'] == 15 + + # Intel + + def _is_Intel(self): + return self.info[0]['VendorIdentifier']=='GenuineIntel' + + def _is_i386(self): + return self.info[0]['Family']==3 + + def _is_i486(self): + return self.info[0]['Family']==4 + + def _is_i586(self): + return self.is_Intel() and self.info[0]['Family']==5 + + def _is_i686(self): + return self.is_Intel() and self.info[0]['Family']==6 + + def _is_Pentium(self): + return self.is_Intel() and self.info[0]['Family']==5 + + def _is_PentiumMMX(self): + return self.is_Intel() and self.info[0]['Family']==5 \ + and self.info[0]['Model']==4 + + def _is_PentiumPro(self): + return self.is_Intel() and self.info[0]['Family']==6 \ + and self.info[0]['Model']==1 + + def _is_PentiumII(self): + return self.is_Intel() and self.info[0]['Family']==6 \ + and self.info[0]['Model'] in [3, 5, 6] + + def _is_PentiumIII(self): + return self.is_Intel() and self.info[0]['Family']==6 \ + and self.info[0]['Model'] in [7, 8, 9, 10, 11] + + def _is_PentiumIV(self): + return self.is_Intel() and self.info[0]['Family']==15 + + def _is_PentiumM(self): + return self.is_Intel() and self.info[0]['Family'] == 6 \ + and self.info[0]['Model'] in [9, 13, 14] + + def _is_Core2(self): + return self.is_Intel() and self.info[0]['Family'] == 6 \ + and self.info[0]['Model'] in [15, 16, 17] + + # Varia + + def _is_singleCPU(self): + return len(self.info) == 1 + + def _getNCPUs(self): + return len(self.info) + + def _has_mmx(self): + if self.is_Intel(): + return (self.info[0]['Family']==5 and self.info[0]['Model']==4) \ + or (self.info[0]['Family'] in [6, 15]) + elif self.is_AMD(): + return self.info[0]['Family'] in [5, 6, 15] + else: + return False + + def _has_sse(self): + if self.is_Intel(): + return (self.info[0]['Family']==6 and \ + self.info[0]['Model'] in [7, 8, 9, 10, 11]) \ + or self.info[0]['Family']==15 + elif self.is_AMD(): + return (self.info[0]['Family']==6 and \ + self.info[0]['Model'] in [6, 7, 8, 10]) \ + or self.info[0]['Family']==15 + else: + return False + + def _has_sse2(self): + if self.is_Intel(): + return self.is_Pentium4() or self.is_PentiumM() \ + or self.is_Core2() + elif self.is_AMD(): + return self.is_AMD64() + else: + return False + + def _has_3dnow(self): + return self.is_AMD() and self.info[0]['Family'] in [5, 6, 15] + + def _has_3dnowext(self): + return self.is_AMD() and self.info[0]['Family'] in [6, 15] + +if sys.platform.startswith('linux'): # variations: linux2,linux-i386 (any others?) + cpuinfo = LinuxCPUInfo +elif sys.platform.startswith('irix'): + cpuinfo = IRIXCPUInfo +elif sys.platform == 'darwin': + cpuinfo = DarwinCPUInfo +elif sys.platform.startswith('sunos'): + cpuinfo = SunOSCPUInfo +elif sys.platform.startswith('win32'): + cpuinfo = Win32CPUInfo +elif sys.platform.startswith('cygwin'): + cpuinfo = LinuxCPUInfo +#XXX: other OS's. Eg. use _winreg on Win32. Or os.uname on unices. +else: + cpuinfo = CPUInfoBase + +cpu = cpuinfo() + +#if __name__ == "__main__": +# +# cpu.is_blaa() +# cpu.is_Intel() +# cpu.is_Alpha() +# +# print('CPU information:'), +# for name in dir(cpuinfo): +# if name[0]=='_' and name[1]!='_': +# r = getattr(cpu,name[1:])() +# if r: +# if r!=1: +# print('%s=%s' %(name[1:],r)) +# else: +# print(name[1:]), +# print() diff --git a/numpy/distutils/environment.py b/numpy/distutils/environment.py new file mode 100644 index 0000000..3798e16 --- /dev/null +++ b/numpy/distutils/environment.py @@ -0,0 +1,72 @@ +from __future__ import division, absolute_import, print_function + +import os +from distutils.dist import Distribution + +__metaclass__ = type + +class EnvironmentConfig(object): + def __init__(self, distutils_section='ALL', **kw): + self._distutils_section = distutils_section + self._conf_keys = kw + self._conf = None + self._hook_handler = None + + def dump_variable(self, name): + conf_desc = self._conf_keys[name] + hook, envvar, confvar, convert = conf_desc + if not convert: + convert = lambda x : x + print('%s.%s:' % (self._distutils_section, name)) + v = self._hook_handler(name, hook) + print(' hook : %s' % (convert(v),)) + if envvar: + v = os.environ.get(envvar, None) + print(' environ: %s' % (convert(v),)) + if confvar and self._conf: + v = self._conf.get(confvar, (None, None))[1] + print(' config : %s' % (convert(v),)) + + def dump_variables(self): + for name in self._conf_keys: + self.dump_variable(name) + + def __getattr__(self, name): + try: + conf_desc = self._conf_keys[name] + except KeyError: + raise AttributeError(name) + return self._get_var(name, conf_desc) + + def get(self, name, default=None): + try: + conf_desc = self._conf_keys[name] + except KeyError: + return default + var = self._get_var(name, conf_desc) + if var is None: + var = default + return var + + def _get_var(self, name, conf_desc): + hook, envvar, confvar, convert = conf_desc + var = self._hook_handler(name, hook) + if envvar is not None: + var = os.environ.get(envvar, var) + if confvar is not None and self._conf: + var = self._conf.get(confvar, (None, var))[1] + if convert is not None: + var = convert(var) + return var + + def clone(self, hook_handler): + ec = self.__class__(distutils_section=self._distutils_section, + **self._conf_keys) + ec._hook_handler = hook_handler + return ec + + def use_distribution(self, dist): + if isinstance(dist, Distribution): + self._conf = dist.get_option_dict(self._distutils_section) + else: + self._conf = dist diff --git a/numpy/distutils/exec_command.py b/numpy/distutils/exec_command.py new file mode 100644 index 0000000..8faf4b2 --- /dev/null +++ b/numpy/distutils/exec_command.py @@ -0,0 +1,275 @@ +""" +exec_command + +Implements exec_command function that is (almost) equivalent to +commands.getstatusoutput function but on NT, DOS systems the +returned status is actually correct (though, the returned status +values may be different by a factor). In addition, exec_command +takes keyword arguments for (re-)defining environment variables. + +Provides functions: + + exec_command --- execute command in a specified directory and + in the modified environment. + find_executable --- locate a command using info from environment + variable PATH. Equivalent to posix `which` + command. + +Author: Pearu Peterson +Created: 11 January 2003 + +Requires: Python 2.x + +Successfully tested on: + +======== ============ ================================================= +os.name sys.platform comments +======== ============ ================================================= +posix linux2 Debian (sid) Linux, Python 2.1.3+, 2.2.3+, 2.3.3 + PyCrust 0.9.3, Idle 1.0.2 +posix linux2 Red Hat 9 Linux, Python 2.1.3, 2.2.2, 2.3.2 +posix sunos5 SunOS 5.9, Python 2.2, 2.3.2 +posix darwin Darwin 7.2.0, Python 2.3 +nt win32 Windows Me + Python 2.3(EE), Idle 1.0, PyCrust 0.7.2 + Python 2.1.1 Idle 0.8 +nt win32 Windows 98, Python 2.1.1. Idle 0.8 +nt win32 Cygwin 98-4.10, Python 2.1.1(MSC) - echo tests + fail i.e. redefining environment variables may + not work. FIXED: don't use cygwin echo! + Comment: also `cmd /c echo` will not work + but redefining environment variables do work. +posix cygwin Cygwin 98-4.10, Python 2.3.3(cygming special) +nt win32 Windows XP, Python 2.3.3 +======== ============ ================================================= + +Known bugs: + +* Tests, that send messages to stderr, fail when executed from MSYS prompt + because the messages are lost at some point. + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['exec_command', 'find_executable'] + +import os +import sys +import subprocess + +from numpy.distutils.misc_util import is_sequence, make_temp_file +from numpy.distutils import log + +def temp_file_name(): + fo, name = make_temp_file() + fo.close() + return name + +def get_pythonexe(): + pythonexe = sys.executable + if os.name in ['nt', 'dos']: + fdir, fn = os.path.split(pythonexe) + fn = fn.upper().replace('PYTHONW', 'PYTHON') + pythonexe = os.path.join(fdir, fn) + assert os.path.isfile(pythonexe), '%r is not a file' % (pythonexe,) + return pythonexe + +def find_executable(exe, path=None, _cache={}): + """Return full path of a executable or None. + + Symbolic links are not followed. + """ + key = exe, path + try: + return _cache[key] + except KeyError: + pass + log.debug('find_executable(%r)' % exe) + orig_exe = exe + + if path is None: + path = os.environ.get('PATH', os.defpath) + if os.name=='posix': + realpath = os.path.realpath + else: + realpath = lambda a:a + + if exe.startswith('"'): + exe = exe[1:-1] + + suffixes = [''] + if os.name in ['nt', 'dos', 'os2']: + fn, ext = os.path.splitext(exe) + extra_suffixes = ['.exe', '.com', '.bat'] + if ext.lower() not in extra_suffixes: + suffixes = extra_suffixes + + if os.path.isabs(exe): + paths = [''] + else: + paths = [ os.path.abspath(p) for p in path.split(os.pathsep) ] + + for path in paths: + fn = os.path.join(path, exe) + for s in suffixes: + f_ext = fn+s + if not os.path.islink(f_ext): + f_ext = realpath(f_ext) + if os.path.isfile(f_ext) and os.access(f_ext, os.X_OK): + log.info('Found executable %s' % f_ext) + _cache[key] = f_ext + return f_ext + + log.warn('Could not locate executable %s' % orig_exe) + return None + +############################################################ + +def _preserve_environment( names ): + log.debug('_preserve_environment(%r)' % (names)) + env = {} + for name in names: + env[name] = os.environ.get(name) + return env + +def _update_environment( **env ): + log.debug('_update_environment(...)') + for name, value in env.items(): + os.environ[name] = value or '' + +def _supports_fileno(stream): + """ + Returns True if 'stream' supports the file descriptor and allows fileno(). + """ + if hasattr(stream, 'fileno'): + try: + stream.fileno() + return True + except IOError: + return False + else: + return False + +def exec_command(command, execute_in='', use_shell=None, use_tee=None, + _with_python = 1, **env ): + """ + Return (status,output) of executed command. + + Parameters + ---------- + command : str + A concatenated string of executable and arguments. + execute_in : str + Before running command ``cd execute_in`` and after ``cd -``. + use_shell : {bool, None}, optional + If True, execute ``sh -c command``. Default None (True) + use_tee : {bool, None}, optional + If True use tee. Default None (True) + + + Returns + ------- + res : str + Both stdout and stderr messages. + + Notes + ----- + On NT, DOS systems the returned status is correct for external commands. + Wild cards will not work for non-posix systems or when use_shell=0. + + """ + log.debug('exec_command(%r,%s)' % (command,\ + ','.join(['%s=%r'%kv for kv in env.items()]))) + + if use_tee is None: + use_tee = os.name=='posix' + if use_shell is None: + use_shell = os.name=='posix' + execute_in = os.path.abspath(execute_in) + oldcwd = os.path.abspath(os.getcwd()) + + if __name__[-12:] == 'exec_command': + exec_dir = os.path.dirname(os.path.abspath(__file__)) + elif os.path.isfile('exec_command.py'): + exec_dir = os.path.abspath('.') + else: + exec_dir = os.path.abspath(sys.argv[0]) + if os.path.isfile(exec_dir): + exec_dir = os.path.dirname(exec_dir) + + if oldcwd!=execute_in: + os.chdir(execute_in) + log.debug('New cwd: %s' % execute_in) + else: + log.debug('Retaining cwd: %s' % oldcwd) + + oldenv = _preserve_environment( list(env.keys()) ) + _update_environment( **env ) + + try: + st = _exec_command(command, + use_shell=use_shell, + use_tee=use_tee, + **env) + finally: + if oldcwd!=execute_in: + os.chdir(oldcwd) + log.debug('Restored cwd to %s' % oldcwd) + _update_environment(**oldenv) + + return st + + +def _exec_command(command, use_shell=None, use_tee = None, **env): + """ + Internal workhorse for exec_command(). + """ + if use_shell is None: + use_shell = os.name=='posix' + if use_tee is None: + use_tee = os.name=='posix' + + if os.name == 'posix' and use_shell: + # On POSIX, subprocess always uses /bin/sh, override + sh = os.environ.get('SHELL', '/bin/sh') + if is_sequence(command): + command = [sh, '-c', ' '.join(command)] + else: + command = [sh, '-c', command] + use_shell = False + + elif os.name == 'nt' and is_sequence(command): + # On Windows, join the string for CreateProcess() ourselves as + # subprocess does it a bit differently + command = ' '.join(_quote_arg(arg) for arg in command) + + # Inherit environment by default + env = env or None + try: + proc = subprocess.Popen(command, shell=use_shell, env=env, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True) + except EnvironmentError: + # Return 127, as os.spawn*() and /bin/sh do + return 127, '' + text, err = proc.communicate() + # Another historical oddity + if text[-1:] == '\n': + text = text[:-1] + if use_tee and text: + print(text) + return proc.returncode, text + + +def _quote_arg(arg): + """ + Quote the argument for safe use in a shell command line. + """ + # If there is a quote in the string, assume relevants parts of the + # string are already quoted (e.g. '-I"C:\\Program Files\\..."') + if '"' not in arg and ' ' in arg: + return '"%s"' % arg + return arg + +############################################################ diff --git a/numpy/distutils/extension.py b/numpy/distutils/extension.py new file mode 100644 index 0000000..935f3ee --- /dev/null +++ b/numpy/distutils/extension.py @@ -0,0 +1,93 @@ +"""distutils.extension + +Provides the Extension class, used to describe C/C++ extension +modules in setup scripts. + +Overridden to support f2py. + +""" +from __future__ import division, absolute_import, print_function + +import sys +import re +from distutils.extension import Extension as old_Extension + +if sys.version_info[0] >= 3: + basestring = str + + +cxx_ext_re = re.compile(r'.*[.](cpp|cxx|cc)\Z', re.I).match +fortran_pyf_ext_re = re.compile(r'.*[.](f90|f95|f77|for|ftn|f|pyf)\Z', re.I).match + +class Extension(old_Extension): + def __init__ ( + self, name, sources, + include_dirs=None, + define_macros=None, + undef_macros=None, + library_dirs=None, + libraries=None, + runtime_library_dirs=None, + extra_objects=None, + extra_compile_args=None, + extra_link_args=None, + export_symbols=None, + swig_opts=None, + depends=None, + language=None, + f2py_options=None, + module_dirs=None, + extra_f77_compile_args=None, + extra_f90_compile_args=None,): + + old_Extension.__init__( + self, name, [], + include_dirs=include_dirs, + define_macros=define_macros, + undef_macros=undef_macros, + library_dirs=library_dirs, + libraries=libraries, + runtime_library_dirs=runtime_library_dirs, + extra_objects=extra_objects, + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args, + export_symbols=export_symbols) + + # Avoid assert statements checking that sources contains strings: + self.sources = sources + + # Python 2.4 distutils new features + self.swig_opts = swig_opts or [] + # swig_opts is assumed to be a list. Here we handle the case where it + # is specified as a string instead. + if isinstance(self.swig_opts, basestring): + import warnings + msg = "swig_opts is specified as a string instead of a list" + warnings.warn(msg, SyntaxWarning, stacklevel=2) + self.swig_opts = self.swig_opts.split() + + # Python 2.3 distutils new features + self.depends = depends or [] + self.language = language + + # numpy_distutils features + self.f2py_options = f2py_options or [] + self.module_dirs = module_dirs or [] + self.extra_f77_compile_args = extra_f77_compile_args or [] + self.extra_f90_compile_args = extra_f90_compile_args or [] + + return + + def has_cxx_sources(self): + for source in self.sources: + if cxx_ext_re(str(source)): + return True + return False + + def has_f2py_sources(self): + for source in self.sources: + if fortran_pyf_ext_re(source): + return True + return False + +# class Extension diff --git a/numpy/distutils/fcompiler/__init__.py b/numpy/distutils/fcompiler/__init__.py new file mode 100644 index 0000000..c926e73 --- /dev/null +++ b/numpy/distutils/fcompiler/__init__.py @@ -0,0 +1,1020 @@ +"""numpy.distutils.fcompiler + +Contains FCompiler, an abstract base class that defines the interface +for the numpy.distutils Fortran compiler abstraction model. + +Terminology: + +To be consistent, where the term 'executable' is used, it means the single +file, like 'gcc', that is executed, and should be a string. In contrast, +'command' means the entire command line, like ['gcc', '-c', 'file.c'], and +should be a list. + +But note that FCompiler.executables is actually a dictionary of commands. + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['FCompiler', 'new_fcompiler', 'show_fcompilers', + 'dummy_fortran_file'] + +import os +import sys +import re +import types + +from numpy.compat import open_latin1 + +from distutils.sysconfig import get_python_lib +from distutils.fancy_getopt import FancyGetopt +from distutils.errors import DistutilsModuleError, \ + DistutilsExecError, CompileError, LinkError, DistutilsPlatformError +from distutils.util import split_quoted, strtobool + +from numpy.distutils.ccompiler import CCompiler, gen_lib_options +from numpy.distutils import log +from numpy.distutils.misc_util import is_string, all_strings, is_sequence, \ + make_temp_file, get_shared_lib_extension +from numpy.distutils.environment import EnvironmentConfig +from numpy.distutils.exec_command import find_executable +from numpy.distutils.compat import get_exception + +__metaclass__ = type + +class CompilerNotFound(Exception): + pass + +def flaglist(s): + if is_string(s): + return split_quoted(s) + else: + return s + +def str2bool(s): + if is_string(s): + return strtobool(s) + return bool(s) + +def is_sequence_of_strings(seq): + return is_sequence(seq) and all_strings(seq) + +class FCompiler(CCompiler): + """Abstract base class to define the interface that must be implemented + by real Fortran compiler classes. + + Methods that subclasses may redefine: + + update_executables(), find_executables(), get_version() + get_flags(), get_flags_opt(), get_flags_arch(), get_flags_debug() + get_flags_f77(), get_flags_opt_f77(), get_flags_arch_f77(), + get_flags_debug_f77(), get_flags_f90(), get_flags_opt_f90(), + get_flags_arch_f90(), get_flags_debug_f90(), + get_flags_fix(), get_flags_linker_so() + + DON'T call these methods (except get_version) after + constructing a compiler instance or inside any other method. + All methods, except update_executables() and find_executables(), + may call the get_version() method. + + After constructing a compiler instance, always call customize(dist=None) + method that finalizes compiler construction and makes the following + attributes available: + compiler_f77 + compiler_f90 + compiler_fix + linker_so + archiver + ranlib + libraries + library_dirs + """ + + # These are the environment variables and distutils keys used. + # Each configuration description is + # (, , , ) + # The hook names are handled by the self._environment_hook method. + # - names starting with 'self.' call methods in this class + # - names starting with 'exe.' return the key in the executables dict + # - names like 'flags.YYY' return self.get_flag_YYY() + # convert is either None or a function to convert a string to the + # appropriate type used. + + distutils_vars = EnvironmentConfig( + distutils_section='config_fc', + noopt = (None, None, 'noopt', str2bool), + noarch = (None, None, 'noarch', str2bool), + debug = (None, None, 'debug', str2bool), + verbose = (None, None, 'verbose', str2bool), + ) + + command_vars = EnvironmentConfig( + distutils_section='config_fc', + compiler_f77 = ('exe.compiler_f77', 'F77', 'f77exec', None), + compiler_f90 = ('exe.compiler_f90', 'F90', 'f90exec', None), + compiler_fix = ('exe.compiler_fix', 'F90', 'f90exec', None), + version_cmd = ('exe.version_cmd', None, None, None), + linker_so = ('exe.linker_so', 'LDSHARED', 'ldshared', None), + linker_exe = ('exe.linker_exe', 'LD', 'ld', None), + archiver = (None, 'AR', 'ar', None), + ranlib = (None, 'RANLIB', 'ranlib', None), + ) + + flag_vars = EnvironmentConfig( + distutils_section='config_fc', + f77 = ('flags.f77', 'F77FLAGS', 'f77flags', flaglist), + f90 = ('flags.f90', 'F90FLAGS', 'f90flags', flaglist), + free = ('flags.free', 'FREEFLAGS', 'freeflags', flaglist), + fix = ('flags.fix', None, None, flaglist), + opt = ('flags.opt', 'FOPT', 'opt', flaglist), + opt_f77 = ('flags.opt_f77', None, None, flaglist), + opt_f90 = ('flags.opt_f90', None, None, flaglist), + arch = ('flags.arch', 'FARCH', 'arch', flaglist), + arch_f77 = ('flags.arch_f77', None, None, flaglist), + arch_f90 = ('flags.arch_f90', None, None, flaglist), + debug = ('flags.debug', 'FDEBUG', 'fdebug', flaglist), + debug_f77 = ('flags.debug_f77', None, None, flaglist), + debug_f90 = ('flags.debug_f90', None, None, flaglist), + flags = ('self.get_flags', 'FFLAGS', 'fflags', flaglist), + linker_so = ('flags.linker_so', 'LDFLAGS', 'ldflags', flaglist), + linker_exe = ('flags.linker_exe', 'LDFLAGS', 'ldflags', flaglist), + ar = ('flags.ar', 'ARFLAGS', 'arflags', flaglist), + ) + + language_map = {'.f': 'f77', + '.for': 'f77', + '.F': 'f77', # XXX: needs preprocessor + '.ftn': 'f77', + '.f77': 'f77', + '.f90': 'f90', + '.F90': 'f90', # XXX: needs preprocessor + '.f95': 'f90', + } + language_order = ['f90', 'f77'] + + + # These will be set by the subclass + + compiler_type = None + compiler_aliases = () + version_pattern = None + + possible_executables = [] + executables = { + 'version_cmd': ["f77", "-v"], + 'compiler_f77': ["f77"], + 'compiler_f90': ["f90"], + 'compiler_fix': ["f90", "-fixed"], + 'linker_so': ["f90", "-shared"], + 'linker_exe': ["f90"], + 'archiver': ["ar", "-cr"], + 'ranlib': None, + } + + # If compiler does not support compiling Fortran 90 then it can + # suggest using another compiler. For example, gnu would suggest + # gnu95 compiler type when there are F90 sources. + suggested_f90_compiler = None + + compile_switch = "-c" + object_switch = "-o " # Ending space matters! It will be stripped + # but if it is missing then object_switch + # will be prefixed to object file name by + # string concatenation. + library_switch = "-o " # Ditto! + + # Switch to specify where module files are created and searched + # for USE statement. Normally it is a string and also here ending + # space matters. See above. + module_dir_switch = None + + # Switch to specify where module files are searched for USE statement. + module_include_switch = '-I' + + pic_flags = [] # Flags to create position-independent code + + src_extensions = ['.for', '.ftn', '.f77', '.f', '.f90', '.f95', '.F', '.F90', '.FOR'] + obj_extension = ".o" + + shared_lib_extension = get_shared_lib_extension() + static_lib_extension = ".a" # or .lib + static_lib_format = "lib%s%s" # or %s%s + shared_lib_format = "%s%s" + exe_extension = "" + + _exe_cache = {} + + _executable_keys = ['version_cmd', 'compiler_f77', 'compiler_f90', + 'compiler_fix', 'linker_so', 'linker_exe', 'archiver', + 'ranlib'] + + # This will be set by new_fcompiler when called in + # command/{build_ext.py, build_clib.py, config.py} files. + c_compiler = None + + # extra_{f77,f90}_compile_args are set by build_ext.build_extension method + extra_f77_compile_args = [] + extra_f90_compile_args = [] + + def __init__(self, *args, **kw): + CCompiler.__init__(self, *args, **kw) + self.distutils_vars = self.distutils_vars.clone(self._environment_hook) + self.command_vars = self.command_vars.clone(self._environment_hook) + self.flag_vars = self.flag_vars.clone(self._environment_hook) + self.executables = self.executables.copy() + for e in self._executable_keys: + if e not in self.executables: + self.executables[e] = None + + # Some methods depend on .customize() being called first, so + # this keeps track of whether that's happened yet. + self._is_customised = False + + def __copy__(self): + obj = self.__new__(self.__class__) + obj.__dict__.update(self.__dict__) + obj.distutils_vars = obj.distutils_vars.clone(obj._environment_hook) + obj.command_vars = obj.command_vars.clone(obj._environment_hook) + obj.flag_vars = obj.flag_vars.clone(obj._environment_hook) + obj.executables = obj.executables.copy() + return obj + + def copy(self): + return self.__copy__() + + # Use properties for the attributes used by CCompiler. Setting them + # as attributes from the self.executables dictionary is error-prone, + # so we get them from there each time. + def _command_property(key): + def fget(self): + assert self._is_customised + return self.executables[key] + return property(fget=fget) + version_cmd = _command_property('version_cmd') + compiler_f77 = _command_property('compiler_f77') + compiler_f90 = _command_property('compiler_f90') + compiler_fix = _command_property('compiler_fix') + linker_so = _command_property('linker_so') + linker_exe = _command_property('linker_exe') + archiver = _command_property('archiver') + ranlib = _command_property('ranlib') + + # Make our terminology consistent. + def set_executable(self, key, value): + self.set_command(key, value) + + def set_commands(self, **kw): + for k, v in kw.items(): + self.set_command(k, v) + + def set_command(self, key, value): + if not key in self._executable_keys: + raise ValueError( + "unknown executable '%s' for class %s" % + (key, self.__class__.__name__)) + if is_string(value): + value = split_quoted(value) + assert value is None or is_sequence_of_strings(value[1:]), (key, value) + self.executables[key] = value + + ###################################################################### + ## Methods that subclasses may redefine. But don't call these methods! + ## They are private to FCompiler class and may return unexpected + ## results if used elsewhere. So, you have been warned.. + + def find_executables(self): + """Go through the self.executables dictionary, and attempt to + find and assign appropriate executables. + + Executable names are looked for in the environment (environment + variables, the distutils.cfg, and command line), the 0th-element of + the command list, and the self.possible_executables list. + + Also, if the 0th element is "" or "", the Fortran 77 + or the Fortran 90 compiler executable is used, unless overridden + by an environment setting. + + Subclasses should call this if overridden. + """ + assert self._is_customised + exe_cache = self._exe_cache + def cached_find_executable(exe): + if exe in exe_cache: + return exe_cache[exe] + fc_exe = find_executable(exe) + exe_cache[exe] = exe_cache[fc_exe] = fc_exe + return fc_exe + def verify_command_form(name, value): + if value is not None and not is_sequence_of_strings(value): + raise ValueError( + "%s value %r is invalid in class %s" % + (name, value, self.__class__.__name__)) + def set_exe(exe_key, f77=None, f90=None): + cmd = self.executables.get(exe_key, None) + if not cmd: + return None + # Note that we get cmd[0] here if the environment doesn't + # have anything set + exe_from_environ = getattr(self.command_vars, exe_key) + if not exe_from_environ: + possibles = [f90, f77] + self.possible_executables + else: + possibles = [exe_from_environ] + self.possible_executables + + seen = set() + unique_possibles = [] + for e in possibles: + if e == '': + e = f77 + elif e == '': + e = f90 + if not e or e in seen: + continue + seen.add(e) + unique_possibles.append(e) + + for exe in unique_possibles: + fc_exe = cached_find_executable(exe) + if fc_exe: + cmd[0] = fc_exe + return fc_exe + self.set_command(exe_key, None) + return None + + ctype = self.compiler_type + f90 = set_exe('compiler_f90') + if not f90: + f77 = set_exe('compiler_f77') + if f77: + log.warn('%s: no Fortran 90 compiler found' % ctype) + else: + raise CompilerNotFound('%s: f90 nor f77' % ctype) + else: + f77 = set_exe('compiler_f77', f90=f90) + if not f77: + log.warn('%s: no Fortran 77 compiler found' % ctype) + set_exe('compiler_fix', f90=f90) + + set_exe('linker_so', f77=f77, f90=f90) + set_exe('linker_exe', f77=f77, f90=f90) + set_exe('version_cmd', f77=f77, f90=f90) + set_exe('archiver') + set_exe('ranlib') + + def update_executables(elf): + """Called at the beginning of customisation. Subclasses should + override this if they need to set up the executables dictionary. + + Note that self.find_executables() is run afterwards, so the + self.executables dictionary values can contain or as + the command, which will be replaced by the found F77 or F90 + compiler. + """ + pass + + def get_flags(self): + """List of flags common to all compiler types.""" + return [] + self.pic_flags + + def _get_command_flags(self, key): + cmd = self.executables.get(key, None) + if cmd is None: + return [] + return cmd[1:] + + def get_flags_f77(self): + """List of Fortran 77 specific flags.""" + return self._get_command_flags('compiler_f77') + def get_flags_f90(self): + """List of Fortran 90 specific flags.""" + return self._get_command_flags('compiler_f90') + def get_flags_free(self): + """List of Fortran 90 free format specific flags.""" + return [] + def get_flags_fix(self): + """List of Fortran 90 fixed format specific flags.""" + return self._get_command_flags('compiler_fix') + def get_flags_linker_so(self): + """List of linker flags to build a shared library.""" + return self._get_command_flags('linker_so') + def get_flags_linker_exe(self): + """List of linker flags to build an executable.""" + return self._get_command_flags('linker_exe') + def get_flags_ar(self): + """List of archiver flags. """ + return self._get_command_flags('archiver') + def get_flags_opt(self): + """List of architecture independent compiler flags.""" + return [] + def get_flags_arch(self): + """List of architecture dependent compiler flags.""" + return [] + def get_flags_debug(self): + """List of compiler flags to compile with debugging information.""" + return [] + + get_flags_opt_f77 = get_flags_opt_f90 = get_flags_opt + get_flags_arch_f77 = get_flags_arch_f90 = get_flags_arch + get_flags_debug_f77 = get_flags_debug_f90 = get_flags_debug + + def get_libraries(self): + """List of compiler libraries.""" + return self.libraries[:] + def get_library_dirs(self): + """List of compiler library directories.""" + return self.library_dirs[:] + + def get_version(self, force=False, ok_status=[0]): + assert self._is_customised + version = CCompiler.get_version(self, force=force, ok_status=ok_status) + if version is None: + raise CompilerNotFound() + return version + + + ############################################################ + + ## Public methods: + + def customize(self, dist = None): + """Customize Fortran compiler. + + This method gets Fortran compiler specific information from + (i) class definition, (ii) environment, (iii) distutils config + files, and (iv) command line (later overrides earlier). + + This method should be always called after constructing a + compiler instance. But not in __init__ because Distribution + instance is needed for (iii) and (iv). + """ + log.info('customize %s' % (self.__class__.__name__)) + + self._is_customised = True + + self.distutils_vars.use_distribution(dist) + self.command_vars.use_distribution(dist) + self.flag_vars.use_distribution(dist) + + self.update_executables() + + # find_executables takes care of setting the compiler commands, + # version_cmd, linker_so, linker_exe, ar, and ranlib + self.find_executables() + + noopt = self.distutils_vars.get('noopt', False) + noarch = self.distutils_vars.get('noarch', noopt) + debug = self.distutils_vars.get('debug', False) + + f77 = self.command_vars.compiler_f77 + f90 = self.command_vars.compiler_f90 + + f77flags = [] + f90flags = [] + freeflags = [] + fixflags = [] + + if f77: + f77flags = self.flag_vars.f77 + if f90: + f90flags = self.flag_vars.f90 + freeflags = self.flag_vars.free + # XXX Assuming that free format is default for f90 compiler. + fix = self.command_vars.compiler_fix + if fix: + fixflags = self.flag_vars.fix + f90flags + + oflags, aflags, dflags = [], [], [] + # examine get_flags__ for extra flags + # only add them if the method is different from get_flags_ + def get_flags(tag, flags): + # note that self.flag_vars. calls self.get_flags_() + flags.extend(getattr(self.flag_vars, tag)) + this_get = getattr(self, 'get_flags_' + tag) + for name, c, flagvar in [('f77', f77, f77flags), + ('f90', f90, f90flags), + ('f90', fix, fixflags)]: + t = '%s_%s' % (tag, name) + if c and this_get is not getattr(self, 'get_flags_' + t): + flagvar.extend(getattr(self.flag_vars, t)) + if not noopt: + get_flags('opt', oflags) + if not noarch: + get_flags('arch', aflags) + if debug: + get_flags('debug', dflags) + + fflags = self.flag_vars.flags + dflags + oflags + aflags + + if f77: + self.set_commands(compiler_f77=[f77]+f77flags+fflags) + if f90: + self.set_commands(compiler_f90=[f90]+freeflags+f90flags+fflags) + if fix: + self.set_commands(compiler_fix=[fix]+fixflags+fflags) + + + #XXX: Do we need LDSHARED->SOSHARED, LDFLAGS->SOFLAGS + linker_so = self.linker_so + if linker_so: + linker_so_flags = self.flag_vars.linker_so + if sys.platform.startswith('aix'): + python_lib = get_python_lib(standard_lib=1) + ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix') + python_exp = os.path.join(python_lib, 'config', 'python.exp') + linker_so = [ld_so_aix] + linker_so + ['-bI:'+python_exp] + self.set_commands(linker_so=linker_so+linker_so_flags) + + linker_exe = self.linker_exe + if linker_exe: + linker_exe_flags = self.flag_vars.linker_exe + self.set_commands(linker_exe=linker_exe+linker_exe_flags) + + ar = self.command_vars.archiver + if ar: + arflags = self.flag_vars.ar + self.set_commands(archiver=[ar]+arflags) + + self.set_library_dirs(self.get_library_dirs()) + self.set_libraries(self.get_libraries()) + + def dump_properties(self): + """Print out the attributes of a compiler instance.""" + props = [] + for key in list(self.executables.keys()) + \ + ['version', 'libraries', 'library_dirs', + 'object_switch', 'compile_switch']: + if hasattr(self, key): + v = getattr(self, key) + props.append((key, None, '= '+repr(v))) + props.sort() + + pretty_printer = FancyGetopt(props) + for l in pretty_printer.generate_help("%s instance properties:" \ + % (self.__class__.__name__)): + if l[:4]==' --': + l = ' ' + l[4:] + print(l) + + ################### + + def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + """Compile 'src' to product 'obj'.""" + src_flags = {} + if is_f_file(src) and not has_f90_header(src): + flavor = ':f77' + compiler = self.compiler_f77 + src_flags = get_f77flags(src) + extra_compile_args = self.extra_f77_compile_args or [] + elif is_free_format(src): + flavor = ':f90' + compiler = self.compiler_f90 + if compiler is None: + raise DistutilsExecError('f90 not supported by %s needed for %s'\ + % (self.__class__.__name__, src)) + extra_compile_args = self.extra_f90_compile_args or [] + else: + flavor = ':fix' + compiler = self.compiler_fix + if compiler is None: + raise DistutilsExecError('f90 (fixed) not supported by %s needed for %s'\ + % (self.__class__.__name__, src)) + extra_compile_args = self.extra_f90_compile_args or [] + if self.object_switch[-1]==' ': + o_args = [self.object_switch.strip(), obj] + else: + o_args = [self.object_switch.strip()+obj] + + assert self.compile_switch.strip() + s_args = [self.compile_switch, src] + + if extra_compile_args: + log.info('extra %s options: %r' \ + % (flavor[1:], ' '.join(extra_compile_args))) + + extra_flags = src_flags.get(self.compiler_type, []) + if extra_flags: + log.info('using compile options from source: %r' \ + % ' '.join(extra_flags)) + + command = compiler + cc_args + extra_flags + s_args + o_args \ + + extra_postargs + extra_compile_args + + display = '%s: %s' % (os.path.basename(compiler[0]) + flavor, + src) + try: + self.spawn(command, display=display) + except DistutilsExecError: + msg = str(get_exception()) + raise CompileError(msg) + + def module_options(self, module_dirs, module_build_dir): + options = [] + if self.module_dir_switch is not None: + if self.module_dir_switch[-1]==' ': + options.extend([self.module_dir_switch.strip(), module_build_dir]) + else: + options.append(self.module_dir_switch.strip()+module_build_dir) + else: + print('XXX: module_build_dir=%r option ignored' % (module_build_dir)) + print('XXX: Fix module_dir_switch for ', self.__class__.__name__) + if self.module_include_switch is not None: + for d in [module_build_dir]+module_dirs: + options.append('%s%s' % (self.module_include_switch, d)) + else: + print('XXX: module_dirs=%r option ignored' % (module_dirs)) + print('XXX: Fix module_include_switch for ', self.__class__.__name__) + return options + + def library_option(self, lib): + return "-l" + lib + def library_dir_option(self, dir): + return "-L" + dir + + def link(self, target_desc, objects, + output_filename, output_dir=None, libraries=None, + library_dirs=None, runtime_library_dirs=None, + export_symbols=None, debug=0, extra_preargs=None, + extra_postargs=None, build_temp=None, target_lang=None): + objects, output_dir = self._fix_object_args(objects, output_dir) + libraries, library_dirs, runtime_library_dirs = \ + self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) + + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, + libraries) + if is_string(output_dir): + output_filename = os.path.join(output_dir, output_filename) + elif output_dir is not None: + raise TypeError("'output_dir' must be a string or None") + + if self._need_link(objects, output_filename): + if self.library_switch[-1]==' ': + o_args = [self.library_switch.strip(), output_filename] + else: + o_args = [self.library_switch.strip()+output_filename] + + if is_string(self.objects): + ld_args = objects + [self.objects] + else: + ld_args = objects + self.objects + ld_args = ld_args + lib_opts + o_args + if debug: + ld_args[:0] = ['-g'] + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend(extra_postargs) + self.mkpath(os.path.dirname(output_filename)) + if target_desc == CCompiler.EXECUTABLE: + linker = self.linker_exe[:] + else: + linker = self.linker_so[:] + command = linker + ld_args + try: + self.spawn(command) + except DistutilsExecError: + msg = str(get_exception()) + raise LinkError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + + def _environment_hook(self, name, hook_name): + if hook_name is None: + return None + if is_string(hook_name): + if hook_name.startswith('self.'): + hook_name = hook_name[5:] + hook = getattr(self, hook_name) + return hook() + elif hook_name.startswith('exe.'): + hook_name = hook_name[4:] + var = self.executables[hook_name] + if var: + return var[0] + else: + return None + elif hook_name.startswith('flags.'): + hook_name = hook_name[6:] + hook = getattr(self, 'get_flags_' + hook_name) + return hook() + else: + return hook_name() + + def can_ccompiler_link(self, ccompiler): + """ + Check if the given C compiler can link objects produced by + this compiler. + """ + return True + + def wrap_unlinkable_objects(self, objects, output_dir, extra_dll_dir): + """ + Convert a set of object files that are not compatible with the default + linker, to a file that is compatible. + + Parameters + ---------- + objects : list + List of object files to include. + output_dir : str + Output directory to place generated object files. + extra_dll_dir : str + Output directory to place extra DLL files that need to be + included on Windows. + + Returns + ------- + converted_objects : list of str + List of converted object files. + Note that the number of output files is not necessarily + the same as inputs. + + """ + raise NotImplementedError() + + ## class FCompiler + +_default_compilers = ( + # sys.platform mappings + ('win32', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95', + 'intelvem', 'intelem', 'flang')), + ('cygwin.*', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95')), + ('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'absoft', 'nag', 'vast', 'compaq', + 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor')), + ('darwin.*', ('gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg')), + ('sunos.*', ('sun', 'gnu', 'gnu95', 'g95')), + ('irix.*', ('mips', 'gnu', 'gnu95',)), + ('aix.*', ('ibm', 'gnu', 'gnu95',)), + # os.name mappings + ('posix', ('gnu', 'gnu95',)), + ('nt', ('gnu', 'gnu95',)), + ('mac', ('gnu95', 'gnu', 'pg')), + ) + +fcompiler_class = None +fcompiler_aliases = None + +def load_all_fcompiler_classes(): + """Cache all the FCompiler classes found in modules in the + numpy.distutils.fcompiler package. + """ + from glob import glob + global fcompiler_class, fcompiler_aliases + if fcompiler_class is not None: + return + pys = os.path.join(os.path.dirname(__file__), '*.py') + fcompiler_class = {} + fcompiler_aliases = {} + for fname in glob(pys): + module_name, ext = os.path.splitext(os.path.basename(fname)) + module_name = 'numpy.distutils.fcompiler.' + module_name + __import__ (module_name) + module = sys.modules[module_name] + if hasattr(module, 'compilers'): + for cname in module.compilers: + klass = getattr(module, cname) + desc = (klass.compiler_type, klass, klass.description) + fcompiler_class[klass.compiler_type] = desc + for alias in klass.compiler_aliases: + if alias in fcompiler_aliases: + raise ValueError("alias %r defined for both %s and %s" + % (alias, klass.__name__, + fcompiler_aliases[alias][1].__name__)) + fcompiler_aliases[alias] = desc + +def _find_existing_fcompiler(compiler_types, + osname=None, platform=None, + requiref90=False, + c_compiler=None): + from numpy.distutils.core import get_distribution + dist = get_distribution(always=True) + for compiler_type in compiler_types: + v = None + try: + c = new_fcompiler(plat=platform, compiler=compiler_type, + c_compiler=c_compiler) + c.customize(dist) + v = c.get_version() + if requiref90 and c.compiler_f90 is None: + v = None + new_compiler = c.suggested_f90_compiler + if new_compiler: + log.warn('Trying %r compiler as suggested by %r ' + 'compiler for f90 support.' % (compiler_type, + new_compiler)) + c = new_fcompiler(plat=platform, compiler=new_compiler, + c_compiler=c_compiler) + c.customize(dist) + v = c.get_version() + if v is not None: + compiler_type = new_compiler + if requiref90 and c.compiler_f90 is None: + raise ValueError('%s does not support compiling f90 codes, ' + 'skipping.' % (c.__class__.__name__)) + except DistutilsModuleError: + log.debug("_find_existing_fcompiler: compiler_type='%s' raised DistutilsModuleError", compiler_type) + except CompilerNotFound: + log.debug("_find_existing_fcompiler: compiler_type='%s' not found", compiler_type) + if v is not None: + return compiler_type + return None + +def available_fcompilers_for_platform(osname=None, platform=None): + if osname is None: + osname = os.name + if platform is None: + platform = sys.platform + matching_compiler_types = [] + for pattern, compiler_type in _default_compilers: + if re.match(pattern, platform) or re.match(pattern, osname): + for ct in compiler_type: + if ct not in matching_compiler_types: + matching_compiler_types.append(ct) + if not matching_compiler_types: + matching_compiler_types.append('gnu') + return matching_compiler_types + +def get_default_fcompiler(osname=None, platform=None, requiref90=False, + c_compiler=None): + """Determine the default Fortran compiler to use for the given + platform.""" + matching_compiler_types = available_fcompilers_for_platform(osname, + platform) + log.info("get_default_fcompiler: matching types: '%s'", + matching_compiler_types) + compiler_type = _find_existing_fcompiler(matching_compiler_types, + osname=osname, + platform=platform, + requiref90=requiref90, + c_compiler=c_compiler) + return compiler_type + +# Flag to avoid rechecking for Fortran compiler every time +failed_fcompilers = set() + +def new_fcompiler(plat=None, + compiler=None, + verbose=0, + dry_run=0, + force=0, + requiref90=False, + c_compiler = None): + """Generate an instance of some FCompiler subclass for the supplied + platform/compiler combination. + """ + global failed_fcompilers + fcompiler_key = (plat, compiler) + if fcompiler_key in failed_fcompilers: + return None + + load_all_fcompiler_classes() + if plat is None: + plat = os.name + if compiler is None: + compiler = get_default_fcompiler(plat, requiref90=requiref90, + c_compiler=c_compiler) + if compiler in fcompiler_class: + module_name, klass, long_description = fcompiler_class[compiler] + elif compiler in fcompiler_aliases: + module_name, klass, long_description = fcompiler_aliases[compiler] + else: + msg = "don't know how to compile Fortran code on platform '%s'" % plat + if compiler is not None: + msg = msg + " with '%s' compiler." % compiler + msg = msg + " Supported compilers are: %s)" \ + % (','.join(fcompiler_class.keys())) + log.warn(msg) + failed_fcompilers.add(fcompiler_key) + return None + + compiler = klass(verbose=verbose, dry_run=dry_run, force=force) + compiler.c_compiler = c_compiler + return compiler + +def show_fcompilers(dist=None): + """Print list of available compilers (used by the "--help-fcompiler" + option to "config_fc"). + """ + if dist is None: + from distutils.dist import Distribution + from numpy.distutils.command.config_compiler import config_fc + dist = Distribution() + dist.script_name = os.path.basename(sys.argv[0]) + dist.script_args = ['config_fc'] + sys.argv[1:] + try: + dist.script_args.remove('--help-fcompiler') + except ValueError: + pass + dist.cmdclass['config_fc'] = config_fc + dist.parse_config_files() + dist.parse_command_line() + compilers = [] + compilers_na = [] + compilers_ni = [] + if not fcompiler_class: + load_all_fcompiler_classes() + platform_compilers = available_fcompilers_for_platform() + for compiler in platform_compilers: + v = None + log.set_verbosity(-2) + try: + c = new_fcompiler(compiler=compiler, verbose=dist.verbose) + c.customize(dist) + v = c.get_version() + except (DistutilsModuleError, CompilerNotFound): + e = get_exception() + log.debug("show_fcompilers: %s not found" % (compiler,)) + log.debug(repr(e)) + + if v is None: + compilers_na.append(("fcompiler="+compiler, None, + fcompiler_class[compiler][2])) + else: + c.dump_properties() + compilers.append(("fcompiler="+compiler, None, + fcompiler_class[compiler][2] + ' (%s)' % v)) + + compilers_ni = list(set(fcompiler_class.keys()) - set(platform_compilers)) + compilers_ni = [("fcompiler="+fc, None, fcompiler_class[fc][2]) + for fc in compilers_ni] + + compilers.sort() + compilers_na.sort() + compilers_ni.sort() + pretty_printer = FancyGetopt(compilers) + pretty_printer.print_help("Fortran compilers found:") + pretty_printer = FancyGetopt(compilers_na) + pretty_printer.print_help("Compilers available for this " + "platform, but not found:") + if compilers_ni: + pretty_printer = FancyGetopt(compilers_ni) + pretty_printer.print_help("Compilers not available on this platform:") + print("For compiler details, run 'config_fc --verbose' setup command.") + + +def dummy_fortran_file(): + fo, name = make_temp_file(suffix='.f') + fo.write(" subroutine dummy()\n end\n") + fo.close() + return name[:-2] + + +is_f_file = re.compile(r'.*[.](for|ftn|f77|f)\Z', re.I).match +_has_f_header = re.compile(r'-[*]-\s*fortran\s*-[*]-', re.I).search +_has_f90_header = re.compile(r'-[*]-\s*f90\s*-[*]-', re.I).search +_has_fix_header = re.compile(r'-[*]-\s*fix\s*-[*]-', re.I).search +_free_f90_start = re.compile(r'[^c*!]\s*[^\s\d\t]', re.I).match + +def is_free_format(file): + """Check if file is in free format Fortran.""" + # f90 allows both fixed and free format, assuming fixed unless + # signs of free format are detected. + result = 0 + f = open_latin1(file, 'r') + line = f.readline() + n = 10000 # the number of non-comment lines to scan for hints + if _has_f_header(line): + n = 0 + elif _has_f90_header(line): + n = 0 + result = 1 + while n>0 and line: + line = line.rstrip() + if line and line[0]!='!': + n -= 1 + if (line[0]!='\t' and _free_f90_start(line[:5])) or line[-1:]=='&': + result = 1 + break + line = f.readline() + f.close() + return result + +def has_f90_header(src): + f = open_latin1(src, 'r') + line = f.readline() + f.close() + return _has_f90_header(line) or _has_fix_header(line) + +_f77flags_re = re.compile(r'(c|)f77flags\s*\(\s*(?P\w+)\s*\)\s*=\s*(?P.*)', re.I) +def get_f77flags(src): + """ + Search the first 20 lines of fortran 77 code for line pattern + `CF77FLAGS()=` + Return a dictionary {:}. + """ + flags = {} + f = open_latin1(src, 'r') + i = 0 + for line in f: + i += 1 + if i>20: break + m = _f77flags_re.match(line) + if not m: continue + fcname = m.group('fcname').strip() + fflags = m.group('fflags').strip() + flags[fcname] = split_quoted(fflags) + f.close() + return flags + +# TODO: implement get_f90flags and use it in _compile similarly to get_f77flags + +if __name__ == '__main__': + show_fcompilers() diff --git a/numpy/distutils/fcompiler/absoft.py b/numpy/distutils/fcompiler/absoft.py new file mode 100644 index 0000000..2c3edfe --- /dev/null +++ b/numpy/distutils/fcompiler/absoft.py @@ -0,0 +1,158 @@ + +# http://www.absoft.com/literature/osxuserguide.pdf +# http://www.absoft.com/documentation.html + +# Notes: +# - when using -g77 then use -DUNDERSCORE_G77 to compile f2py +# generated extension modules (works for f2py v2.45.241_1936 and up) +from __future__ import division, absolute_import, print_function + +import os + +from numpy.distutils.cpuinfo import cpu +from numpy.distutils.fcompiler import FCompiler, dummy_fortran_file +from numpy.distutils.misc_util import cyg2win32 + +compilers = ['AbsoftFCompiler'] + +class AbsoftFCompiler(FCompiler): + + compiler_type = 'absoft' + description = 'Absoft Corp Fortran Compiler' + #version_pattern = r'FORTRAN 77 Compiler (?P[^\s*,]*).*?Absoft Corp' + version_pattern = r'(f90:.*?(Absoft Pro FORTRAN Version|FORTRAN 77 Compiler|Absoft Fortran Compiler Version|Copyright Absoft Corporation.*?Version))'+\ + r' (?P[^\s*,]*)(.*?Absoft Corp|)' + + # on windows: f90 -V -c dummy.f + # f90: Copyright Absoft Corporation 1994-1998 mV2; Cray Research, Inc. 1994-1996 CF90 (2.x.x.x f36t87) Version 2.3 Wed Apr 19, 2006 13:05:16 + + # samt5735(8)$ f90 -V -c dummy.f + # f90: Copyright Absoft Corporation 1994-2002; Absoft Pro FORTRAN Version 8.0 + # Note that fink installs g77 as f77, so need to use f90 for detection. + + executables = { + 'version_cmd' : None, # set by update_executables + 'compiler_f77' : ["f77"], + 'compiler_fix' : ["f90"], + 'compiler_f90' : ["f90"], + 'linker_so' : [""], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + if os.name=='nt': + library_switch = '/out:' #No space after /out:! + + module_dir_switch = None + module_include_switch = '-p' + + def update_executables(self): + f = cyg2win32(dummy_fortran_file()) + self.executables['version_cmd'] = ['', '-V', '-c', + f+'.f', '-o', f+'.o'] + + def get_flags_linker_so(self): + if os.name=='nt': + opt = ['/dll'] + # The "-K shared" switches are being left in for pre-9.0 versions + # of Absoft though I don't think versions earlier than 9 can + # actually be used to build shared libraries. In fact, version + # 8 of Absoft doesn't recognize "-K shared" and will fail. + elif self.get_version() >= '9.0': + opt = ['-shared'] + else: + opt = ["-K", "shared"] + return opt + + def library_dir_option(self, dir): + if os.name=='nt': + return ['-link', '/PATH:"%s"' % (dir)] + return "-L" + dir + + def library_option(self, lib): + if os.name=='nt': + return '%s.lib' % (lib) + return "-l" + lib + + def get_library_dirs(self): + opt = FCompiler.get_library_dirs(self) + d = os.environ.get('ABSOFT') + if d: + if self.get_version() >= '10.0': + # use shared libraries, the static libraries were not compiled -fPIC + prefix = 'sh' + else: + prefix = '' + if cpu.is_64bit(): + suffix = '64' + else: + suffix = '' + opt.append(os.path.join(d, '%slib%s' % (prefix, suffix))) + return opt + + def get_libraries(self): + opt = FCompiler.get_libraries(self) + if self.get_version() >= '11.0': + opt.extend(['af90math', 'afio', 'af77math', 'amisc']) + elif self.get_version() >= '10.0': + opt.extend(['af90math', 'afio', 'af77math', 'U77']) + elif self.get_version() >= '8.0': + opt.extend(['f90math', 'fio', 'f77math', 'U77']) + else: + opt.extend(['fio', 'f90math', 'fmath', 'U77']) + if os.name =='nt': + opt.append('COMDLG32') + return opt + + def get_flags(self): + opt = FCompiler.get_flags(self) + if os.name != 'nt': + opt.extend(['-s']) + if self.get_version(): + if self.get_version()>='8.2': + opt.append('-fpic') + return opt + + def get_flags_f77(self): + opt = FCompiler.get_flags_f77(self) + opt.extend(['-N22', '-N90', '-N110']) + v = self.get_version() + if os.name == 'nt': + if v and v>='8.0': + opt.extend(['-f', '-N15']) + else: + opt.append('-f') + if v: + if v<='4.6': + opt.append('-B108') + else: + # Though -N15 is undocumented, it works with + # Absoft 8.0 on Linux + opt.append('-N15') + return opt + + def get_flags_f90(self): + opt = FCompiler.get_flags_f90(self) + opt.extend(["-YCFRL=1", "-YCOM_NAMES=LCS", "-YCOM_PFX", "-YEXT_PFX", + "-YCOM_SFX=_", "-YEXT_SFX=_", "-YEXT_NAMES=LCS"]) + if self.get_version(): + if self.get_version()>'4.6': + opt.extend(["-YDEALLOC=ALL"]) + return opt + + def get_flags_fix(self): + opt = FCompiler.get_flags_fix(self) + opt.extend(["-YCFRL=1", "-YCOM_NAMES=LCS", "-YCOM_PFX", "-YEXT_PFX", + "-YCOM_SFX=_", "-YEXT_SFX=_", "-YEXT_NAMES=LCS"]) + opt.extend(["-f", "fixed"]) + return opt + + def get_flags_opt(self): + opt = ['-O'] + return opt + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='absoft').get_version()) diff --git a/numpy/distutils/fcompiler/compaq.py b/numpy/distutils/fcompiler/compaq.py new file mode 100644 index 0000000..07d5027 --- /dev/null +++ b/numpy/distutils/fcompiler/compaq.py @@ -0,0 +1,126 @@ + +#http://www.compaq.com/fortran/docs/ +from __future__ import division, absolute_import, print_function + +import os +import sys + +from numpy.distutils.fcompiler import FCompiler +from numpy.distutils.compat import get_exception +from distutils.errors import DistutilsPlatformError + +compilers = ['CompaqFCompiler'] +if os.name != 'posix' or sys.platform[:6] == 'cygwin' : + # Otherwise we'd get a false positive on posix systems with + # case-insensitive filesystems (like darwin), because we'll pick + # up /bin/df + compilers.append('CompaqVisualFCompiler') + +class CompaqFCompiler(FCompiler): + + compiler_type = 'compaq' + description = 'Compaq Fortran Compiler' + version_pattern = r'Compaq Fortran (?P[^\s]*).*' + + if sys.platform[:5]=='linux': + fc_exe = 'fort' + else: + fc_exe = 'f90' + + executables = { + 'version_cmd' : ['', "-version"], + 'compiler_f77' : [fc_exe, "-f77rtl", "-fixed"], + 'compiler_fix' : [fc_exe, "-fixed"], + 'compiler_f90' : [fc_exe], + 'linker_so' : [''], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + module_dir_switch = '-module ' # not tested + module_include_switch = '-I' + + def get_flags(self): + return ['-assume no2underscore', '-nomixed_str_len_arg'] + def get_flags_debug(self): + return ['-g', '-check bounds'] + def get_flags_opt(self): + return ['-O4', '-align dcommons', '-assume bigarrays', + '-assume nozsize', '-math_library fast'] + def get_flags_arch(self): + return ['-arch host', '-tune host'] + def get_flags_linker_so(self): + if sys.platform[:5]=='linux': + return ['-shared'] + return ['-shared', '-Wl,-expect_unresolved,*'] + +class CompaqVisualFCompiler(FCompiler): + + compiler_type = 'compaqv' + description = 'DIGITAL or Compaq Visual Fortran Compiler' + version_pattern = (r'(DIGITAL|Compaq) Visual Fortran Optimizing Compiler' + r' Version (?P[^\s]*).*') + + compile_switch = '/compile_only' + object_switch = '/object:' + library_switch = '/OUT:' #No space after /OUT:! + + static_lib_extension = ".lib" + static_lib_format = "%s%s" + module_dir_switch = '/module:' + module_include_switch = '/I' + + ar_exe = 'lib.exe' + fc_exe = 'DF' + + if sys.platform=='win32': + from numpy.distutils.msvccompiler import MSVCCompiler + + try: + m = MSVCCompiler() + m.initialize() + ar_exe = m.lib + except DistutilsPlatformError: + pass + except AttributeError: + msg = get_exception() + if '_MSVCCompiler__root' in str(msg): + print('Ignoring "%s" (I think it is msvccompiler.py bug)' % (msg)) + else: + raise + except IOError: + e = get_exception() + if not "vcvarsall.bat" in str(e): + print("Unexpected IOError in", __file__) + raise e + except ValueError: + e = get_exception() + if not "path']" in str(e): + print("Unexpected ValueError in", __file__) + raise e + + executables = { + 'version_cmd' : ['', "/what"], + 'compiler_f77' : [fc_exe, "/f77rtl", "/fixed"], + 'compiler_fix' : [fc_exe, "/fixed"], + 'compiler_f90' : [fc_exe], + 'linker_so' : [''], + 'archiver' : [ar_exe, "/OUT:"], + 'ranlib' : None + } + + def get_flags(self): + return ['/nologo', '/MD', '/WX', '/iface=(cref,nomixed_str_len_arg)', + '/names:lowercase', '/assume:underscore'] + def get_flags_opt(self): + return ['/Ox', '/fast', '/optimize:5', '/unroll:0', '/math_library:fast'] + def get_flags_arch(self): + return ['/threads'] + def get_flags_debug(self): + return ['/debug'] + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='compaq').get_version()) diff --git a/numpy/distutils/fcompiler/g95.py b/numpy/distutils/fcompiler/g95.py new file mode 100644 index 0000000..e7c659b --- /dev/null +++ b/numpy/distutils/fcompiler/g95.py @@ -0,0 +1,44 @@ +# http://g95.sourceforge.net/ +from __future__ import division, absolute_import, print_function + +from numpy.distutils.fcompiler import FCompiler + +compilers = ['G95FCompiler'] + +class G95FCompiler(FCompiler): + compiler_type = 'g95' + description = 'G95 Fortran Compiler' + +# version_pattern = r'G95 \((GCC (?P[\d.]+)|.*?) \(g95!\) (?P.*)\).*' + # $ g95 --version + # G95 (GCC 4.0.3 (g95!) May 22 2006) + + version_pattern = r'G95 \((GCC (?P[\d.]+)|.*?) \(g95 (?P.*)!\) (?P.*)\).*' + # $ g95 --version + # G95 (GCC 4.0.3 (g95 0.90!) Aug 22 2006) + + executables = { + 'version_cmd' : ["", "--version"], + 'compiler_f77' : ["g95", "-ffixed-form"], + 'compiler_fix' : ["g95", "-ffixed-form"], + 'compiler_f90' : ["g95"], + 'linker_so' : ["", "-shared"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + pic_flags = ['-fpic'] + module_dir_switch = '-fmod=' + module_include_switch = '-I' + + def get_flags(self): + return ['-fno-second-underscore'] + def get_flags_opt(self): + return ['-O'] + def get_flags_debug(self): + return ['-g'] + +if __name__ == '__main__': + from distutils import log + from numpy.distutils import customized_fcompiler + log.set_verbosity(2) + print(customized_fcompiler('g95').get_version()) diff --git a/numpy/distutils/fcompiler/gnu.py b/numpy/distutils/fcompiler/gnu.py new file mode 100644 index 0000000..0ebbe79 --- /dev/null +++ b/numpy/distutils/fcompiler/gnu.py @@ -0,0 +1,539 @@ +from __future__ import division, absolute_import, print_function + +import re +import os +import sys +import warnings +import platform +import tempfile +import hashlib +import base64 +from subprocess import Popen, PIPE, STDOUT +from copy import copy +from numpy.distutils.fcompiler import FCompiler +from numpy.distutils.exec_command import exec_command +from numpy.distutils.compat import get_exception +from numpy.distutils.system_info import system_info + +compilers = ['GnuFCompiler', 'Gnu95FCompiler'] + +TARGET_R = re.compile(r"Target: ([a-zA-Z0-9_\-]*)") + +# XXX: handle cross compilation + + +def is_win64(): + return sys.platform == "win32" and platform.architecture()[0] == "64bit" + + +if is_win64(): + #_EXTRAFLAGS = ["-fno-leading-underscore"] + _EXTRAFLAGS = [] +else: + _EXTRAFLAGS = [] + + +class GnuFCompiler(FCompiler): + compiler_type = 'gnu' + compiler_aliases = ('g77', ) + description = 'GNU Fortran 77 compiler' + + def gnu_version_match(self, version_string): + """Handle the different versions of GNU fortran compilers""" + # Strip warning(s) that may be emitted by gfortran + while version_string.startswith('gfortran: warning'): + version_string = version_string[version_string.find('\n') + 1:] + + # Gfortran versions from after 2010 will output a simple string + # (usually "x.y", "x.y.z" or "x.y.z-q") for ``-dumpversion``; older + # gfortrans may still return long version strings (``-dumpversion`` was + # an alias for ``--version``) + if len(version_string) <= 20: + # Try to find a valid version string + m = re.search(r'([0-9.]+)', version_string) + if m: + # g77 provides a longer version string that starts with GNU + # Fortran + if version_string.startswith('GNU Fortran'): + return ('g77', m.group(1)) + + # gfortran only outputs a version string such as #.#.#, so check + # if the match is at the start of the string + elif m.start() == 0: + return ('gfortran', m.group(1)) + else: + # Output probably from --version, try harder: + m = re.search(r'GNU Fortran\s+95.*?([0-9-.]+)', version_string) + if m: + return ('gfortran', m.group(1)) + m = re.search( + r'GNU Fortran.*?\-?([0-9-.]+\.[0-9-.]+)', version_string) + if m: + v = m.group(1) + if v.startswith('0') or v.startswith('2') or v.startswith('3'): + # the '0' is for early g77's + return ('g77', v) + else: + # at some point in the 4.x series, the ' 95' was dropped + # from the version string + return ('gfortran', v) + + # If still nothing, raise an error to make the problem easy to find. + err = 'A valid Fortran version was not found in this string:\n' + raise ValueError(err + version_string) + + def version_match(self, version_string): + v = self.gnu_version_match(version_string) + if not v or v[0] != 'g77': + return None + return v[1] + + possible_executables = ['g77', 'f77'] + executables = { + 'version_cmd' : [None, "-dumpversion"], + 'compiler_f77' : [None, "-g", "-Wall", "-fno-second-underscore"], + 'compiler_f90' : None, # Use --fcompiler=gnu95 for f90 codes + 'compiler_fix' : None, + 'linker_so' : [None, "-g", "-Wall"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"], + 'linker_exe' : [None, "-g", "-Wall"] + } + module_dir_switch = None + module_include_switch = None + + # Cygwin: f771: warning: -fPIC ignored for target (all code is + # position independent) + if os.name != 'nt' and sys.platform != 'cygwin': + pic_flags = ['-fPIC'] + + # use -mno-cygwin for g77 when Python is not Cygwin-Python + if sys.platform == 'win32': + for key in ['version_cmd', 'compiler_f77', 'linker_so', 'linker_exe']: + executables[key].append('-mno-cygwin') + + g2c = 'g2c' + suggested_f90_compiler = 'gnu95' + + def get_flags_linker_so(self): + opt = self.linker_so[1:] + if sys.platform == 'darwin': + target = os.environ.get('MACOSX_DEPLOYMENT_TARGET', None) + # If MACOSX_DEPLOYMENT_TARGET is set, we simply trust the value + # and leave it alone. But, distutils will complain if the + # environment's value is different from the one in the Python + # Makefile used to build Python. We let disutils handle this + # error checking. + if not target: + # If MACOSX_DEPLOYMENT_TARGET is not set in the environment, + # we try to get it first from the Python Makefile and then we + # fall back to setting it to 10.3 to maximize the set of + # versions we can work with. This is a reasonable default + # even when using the official Python dist and those derived + # from it. + import distutils.sysconfig as sc + g = {} + try: + get_makefile_filename = sc.get_makefile_filename + except AttributeError: + pass # i.e. PyPy + else: + filename = get_makefile_filename() + sc.parse_makefile(filename, g) + target = g.get('MACOSX_DEPLOYMENT_TARGET', '10.3') + os.environ['MACOSX_DEPLOYMENT_TARGET'] = target + if target == '10.3': + s = 'Env. variable MACOSX_DEPLOYMENT_TARGET set to 10.3' + warnings.warn(s, stacklevel=2) + + opt.extend(['-undefined', 'dynamic_lookup', '-bundle']) + else: + opt.append("-shared") + if sys.platform.startswith('sunos'): + # SunOS often has dynamically loaded symbols defined in the + # static library libg2c.a The linker doesn't like this. To + # ignore the problem, use the -mimpure-text flag. It isn't + # the safest thing, but seems to work. 'man gcc' says: + # ".. Instead of using -mimpure-text, you should compile all + # source code with -fpic or -fPIC." + opt.append('-mimpure-text') + return opt + + def get_libgcc_dir(self): + status, output = exec_command( + self.compiler_f77 + ['-print-libgcc-file-name'], use_tee=0) + if not status: + return os.path.dirname(output) + return None + + def get_libgfortran_dir(self): + if sys.platform[:5] == 'linux': + libgfortran_name = 'libgfortran.so' + elif sys.platform == 'darwin': + libgfortran_name = 'libgfortran.dylib' + else: + libgfortran_name = None + + libgfortran_dir = None + if libgfortran_name: + find_lib_arg = ['-print-file-name={0}'.format(libgfortran_name)] + status, output = exec_command( + self.compiler_f77 + find_lib_arg, use_tee=0) + if not status: + libgfortran_dir = os.path.dirname(output) + return libgfortran_dir + + def get_library_dirs(self): + opt = [] + if sys.platform[:5] != 'linux': + d = self.get_libgcc_dir() + if d: + # if windows and not cygwin, libg2c lies in a different folder + if sys.platform == 'win32' and not d.startswith('/usr/lib'): + d = os.path.normpath(d) + path = os.path.join(d, "lib%s.a" % self.g2c) + if not os.path.exists(path): + root = os.path.join(d, *((os.pardir, ) * 4)) + d2 = os.path.abspath(os.path.join(root, 'lib')) + path = os.path.join(d2, "lib%s.a" % self.g2c) + if os.path.exists(path): + opt.append(d2) + opt.append(d) + # For Macports / Linux, libgfortran and libgcc are not co-located + lib_gfortran_dir = self.get_libgfortran_dir() + if lib_gfortran_dir: + opt.append(lib_gfortran_dir) + return opt + + def get_libraries(self): + opt = [] + d = self.get_libgcc_dir() + if d is not None: + g2c = self.g2c + '-pic' + f = self.static_lib_format % (g2c, self.static_lib_extension) + if not os.path.isfile(os.path.join(d, f)): + g2c = self.g2c + else: + g2c = self.g2c + + if g2c is not None: + opt.append(g2c) + c_compiler = self.c_compiler + if sys.platform == 'win32' and c_compiler and \ + c_compiler.compiler_type == 'msvc': + opt.append('gcc') + if sys.platform == 'darwin': + opt.append('cc_dynamic') + return opt + + def get_flags_debug(self): + return ['-g'] + + def get_flags_opt(self): + v = self.get_version() + if v and v <= '3.3.3': + # With this compiler version building Fortran BLAS/LAPACK + # with -O3 caused failures in lib.lapack heevr,syevr tests. + opt = ['-O2'] + else: + opt = ['-O3'] + opt.append('-funroll-loops') + return opt + + def _c_arch_flags(self): + """ Return detected arch flags from CFLAGS """ + from distutils import sysconfig + try: + cflags = sysconfig.get_config_vars()['CFLAGS'] + except KeyError: + return [] + arch_re = re.compile(r"-arch\s+(\w+)") + arch_flags = [] + for arch in arch_re.findall(cflags): + arch_flags += ['-arch', arch] + return arch_flags + + def get_flags_arch(self): + return [] + + def runtime_library_dir_option(self, dir): + sep = ',' if sys.platform == 'darwin' else '=' + return '-Wl,-rpath%s"%s"' % (sep, dir) + + +class Gnu95FCompiler(GnuFCompiler): + compiler_type = 'gnu95' + compiler_aliases = ('gfortran', ) + description = 'GNU Fortran 95 compiler' + + def version_match(self, version_string): + v = self.gnu_version_match(version_string) + if not v or v[0] != 'gfortran': + return None + v = v[1] + if v >= '4.': + # gcc-4 series releases do not support -mno-cygwin option + pass + else: + # use -mno-cygwin flag for gfortran when Python is not + # Cygwin-Python + if sys.platform == 'win32': + for key in [ + 'version_cmd', 'compiler_f77', 'compiler_f90', + 'compiler_fix', 'linker_so', 'linker_exe' + ]: + self.executables[key].append('-mno-cygwin') + return v + + possible_executables = ['gfortran', 'f95'] + executables = { + 'version_cmd' : ["", "-dumpversion"], + 'compiler_f77' : [None, "-Wall", "-g", "-ffixed-form", + "-fno-second-underscore"] + _EXTRAFLAGS, + 'compiler_f90' : [None, "-Wall", "-g", + "-fno-second-underscore"] + _EXTRAFLAGS, + 'compiler_fix' : [None, "-Wall", "-g","-ffixed-form", + "-fno-second-underscore"] + _EXTRAFLAGS, + 'linker_so' : ["", "-Wall", "-g"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"], + 'linker_exe' : [None, "-Wall"] + } + + module_dir_switch = '-J' + module_include_switch = '-I' + + g2c = 'gfortran' + + def _universal_flags(self, cmd): + """Return a list of -arch flags for every supported architecture.""" + if not sys.platform == 'darwin': + return [] + arch_flags = [] + # get arches the C compiler gets. + c_archs = self._c_arch_flags() + if "i386" in c_archs: + c_archs[c_archs.index("i386")] = "i686" + # check the arches the Fortran compiler supports, and compare with + # arch flags from C compiler + for arch in ["ppc", "i686", "x86_64", "ppc64"]: + if _can_target(cmd, arch) and arch in c_archs: + arch_flags.extend(["-arch", arch]) + return arch_flags + + def get_flags(self): + flags = GnuFCompiler.get_flags(self) + arch_flags = self._universal_flags(self.compiler_f90) + if arch_flags: + flags[:0] = arch_flags + return flags + + def get_flags_linker_so(self): + flags = GnuFCompiler.get_flags_linker_so(self) + arch_flags = self._universal_flags(self.linker_so) + if arch_flags: + flags[:0] = arch_flags + return flags + + def get_library_dirs(self): + opt = GnuFCompiler.get_library_dirs(self) + if sys.platform == 'win32': + c_compiler = self.c_compiler + if c_compiler and c_compiler.compiler_type == "msvc": + target = self.get_target() + if target: + d = os.path.normpath(self.get_libgcc_dir()) + root = os.path.join(d, *((os.pardir, ) * 4)) + path = os.path.join(root, "lib") + mingwdir = os.path.normpath(path) + if os.path.exists(os.path.join(mingwdir, "libmingwex.a")): + opt.append(mingwdir) + # For Macports / Linux, libgfortran and libgcc are not co-located + lib_gfortran_dir = self.get_libgfortran_dir() + if lib_gfortran_dir: + opt.append(lib_gfortran_dir) + return opt + + def get_libraries(self): + opt = GnuFCompiler.get_libraries(self) + if sys.platform == 'darwin': + opt.remove('cc_dynamic') + if sys.platform == 'win32': + c_compiler = self.c_compiler + if c_compiler and c_compiler.compiler_type == "msvc": + if "gcc" in opt: + i = opt.index("gcc") + opt.insert(i + 1, "mingwex") + opt.insert(i + 1, "mingw32") + c_compiler = self.c_compiler + if c_compiler and c_compiler.compiler_type == "msvc": + return [] + else: + pass + return opt + + def get_target(self): + status, output = exec_command(self.compiler_f77 + ['-v'], use_tee=0) + if not status: + m = TARGET_R.search(output) + if m: + return m.group(1) + return "" + + def _hash_files(self, filenames): + h = hashlib.sha1() + for fn in filenames: + with open(fn, 'rb') as f: + while True: + block = f.read(131072) + if not block: + break + h.update(block) + text = base64.b32encode(h.digest()) + if sys.version_info[0] >= 3: + text = text.decode('ascii') + return text.rstrip('=') + + def _link_wrapper_lib(self, objects, output_dir, extra_dll_dir, + chained_dlls, is_archive): + """Create a wrapper shared library for the given objects + + Return an MSVC-compatible lib + """ + + c_compiler = self.c_compiler + if c_compiler.compiler_type != "msvc": + raise ValueError("This method only supports MSVC") + + object_hash = self._hash_files(list(objects) + list(chained_dlls)) + + if is_win64(): + tag = 'win_amd64' + else: + tag = 'win32' + + basename = 'lib' + os.path.splitext( + os.path.basename(objects[0]))[0][:8] + root_name = basename + '.' + object_hash + '.gfortran-' + tag + dll_name = root_name + '.dll' + def_name = root_name + '.def' + lib_name = root_name + '.lib' + dll_path = os.path.join(extra_dll_dir, dll_name) + def_path = os.path.join(output_dir, def_name) + lib_path = os.path.join(output_dir, lib_name) + + if os.path.isfile(lib_path): + # Nothing to do + return lib_path, dll_path + + if is_archive: + objects = (["-Wl,--whole-archive"] + list(objects) + + ["-Wl,--no-whole-archive"]) + self.link_shared_object( + objects, + dll_name, + output_dir=extra_dll_dir, + extra_postargs=list(chained_dlls) + [ + '-Wl,--allow-multiple-definition', + '-Wl,--output-def,' + def_path, + '-Wl,--export-all-symbols', + '-Wl,--enable-auto-import', + '-static', + '-mlong-double-64', + ]) + + # No PowerPC! + if is_win64(): + specifier = '/MACHINE:X64' + else: + specifier = '/MACHINE:X86' + + # MSVC specific code + lib_args = ['/def:' + def_path, '/OUT:' + lib_path, specifier] + if not c_compiler.initialized: + c_compiler.initialize() + c_compiler.spawn([c_compiler.lib] + lib_args) + + return lib_path, dll_path + + def can_ccompiler_link(self, compiler): + # MSVC cannot link objects compiled by GNU fortran + return compiler.compiler_type not in ("msvc", ) + + def wrap_unlinkable_objects(self, objects, output_dir, extra_dll_dir): + """ + Convert a set of object files that are not compatible with the default + linker, to a file that is compatible. + """ + if self.c_compiler.compiler_type == "msvc": + # Compile a DLL and return the lib for the DLL as + # the object. Also keep track of previous DLLs that + # we have compiled so that we can link against them. + + # If there are .a archives, assume they are self-contained + # static libraries, and build separate DLLs for each + archives = [] + plain_objects = [] + for obj in objects: + if obj.lower().endswith('.a'): + archives.append(obj) + else: + plain_objects.append(obj) + + chained_libs = [] + chained_dlls = [] + for archive in archives[::-1]: + lib, dll = self._link_wrapper_lib( + [archive], + output_dir, + extra_dll_dir, + chained_dlls=chained_dlls, + is_archive=True) + chained_libs.insert(0, lib) + chained_dlls.insert(0, dll) + + if not plain_objects: + return chained_libs + + lib, dll = self._link_wrapper_lib( + plain_objects, + output_dir, + extra_dll_dir, + chained_dlls=chained_dlls, + is_archive=False) + return [lib] + chained_libs + else: + raise ValueError("Unsupported C compiler") + + +def _can_target(cmd, arch): + """Return true if the architecture supports the -arch flag""" + newcmd = cmd[:] + fid, filename = tempfile.mkstemp(suffix=".f") + os.close(fid) + try: + d = os.path.dirname(filename) + output = os.path.splitext(filename)[0] + ".o" + try: + newcmd.extend(["-arch", arch, "-c", filename]) + p = Popen(newcmd, stderr=STDOUT, stdout=PIPE, cwd=d) + p.communicate() + return p.returncode == 0 + finally: + if os.path.exists(output): + os.remove(output) + finally: + os.remove(filename) + return False + + +if __name__ == '__main__': + from distutils import log + from numpy.distutils import customized_fcompiler + log.set_verbosity(2) + + print(customized_fcompiler('gnu').get_version()) + try: + print(customized_fcompiler('g95').get_version()) + except Exception: + print(get_exception()) diff --git a/numpy/distutils/fcompiler/hpux.py b/numpy/distutils/fcompiler/hpux.py new file mode 100644 index 0000000..51bad54 --- /dev/null +++ b/numpy/distutils/fcompiler/hpux.py @@ -0,0 +1,43 @@ +from __future__ import division, absolute_import, print_function + +from numpy.distutils.fcompiler import FCompiler + +compilers = ['HPUXFCompiler'] + +class HPUXFCompiler(FCompiler): + + compiler_type = 'hpux' + description = 'HP Fortran 90 Compiler' + version_pattern = r'HP F90 (?P[^\s*,]*)' + + executables = { + 'version_cmd' : ["f90", "+version"], + 'compiler_f77' : ["f90"], + 'compiler_fix' : ["f90"], + 'compiler_f90' : ["f90"], + 'linker_so' : ["ld", "-b"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + module_dir_switch = None #XXX: fix me + module_include_switch = None #XXX: fix me + pic_flags = ['+Z'] + def get_flags(self): + return self.pic_flags + ['+ppu', '+DD64'] + def get_flags_opt(self): + return ['-O3'] + def get_libraries(self): + return ['m'] + def get_library_dirs(self): + opt = ['/usr/lib/hpux64'] + return opt + def get_version(self, force=0, ok_status=[256, 0, 1]): + # XXX status==256 may indicate 'unrecognized option' or + # 'no input file'. So, version_cmd needs more work. + return FCompiler.get_version(self, force, ok_status) + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(10) + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='hpux').get_version()) diff --git a/numpy/distutils/fcompiler/ibm.py b/numpy/distutils/fcompiler/ibm.py new file mode 100644 index 0000000..d0c2202 --- /dev/null +++ b/numpy/distutils/fcompiler/ibm.py @@ -0,0 +1,95 @@ +from __future__ import division, absolute_import, print_function + +import os +import re +import sys + +from numpy.distutils.fcompiler import FCompiler +from numpy.distutils.exec_command import exec_command, find_executable +from numpy.distutils.misc_util import make_temp_file +from distutils import log + +compilers = ['IBMFCompiler'] + +class IBMFCompiler(FCompiler): + compiler_type = 'ibm' + description = 'IBM XL Fortran Compiler' + version_pattern = r'(xlf\(1\)\s*|)IBM XL Fortran ((Advanced Edition |)Version |Enterprise Edition V|for AIX, V)(?P[^\s*]*)' + #IBM XL Fortran Enterprise Edition V10.1 for AIX \nVersion: 10.01.0000.0004 + + executables = { + 'version_cmd' : ["", "-qversion"], + 'compiler_f77' : ["xlf"], + 'compiler_fix' : ["xlf90", "-qfixed"], + 'compiler_f90' : ["xlf90"], + 'linker_so' : ["xlf95"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + def get_version(self,*args,**kwds): + version = FCompiler.get_version(self,*args,**kwds) + + if version is None and sys.platform.startswith('aix'): + # use lslpp to find out xlf version + lslpp = find_executable('lslpp') + xlf = find_executable('xlf') + if os.path.exists(xlf) and os.path.exists(lslpp): + s, o = exec_command(lslpp + ' -Lc xlfcmp') + m = re.search(r'xlfcmp:(?P\d+([.]\d+)+)', o) + if m: version = m.group('version') + + xlf_dir = '/etc/opt/ibmcmp/xlf' + if version is None and os.path.isdir(xlf_dir): + # linux: + # If the output of xlf does not contain version info + # (that's the case with xlf 8.1, for instance) then + # let's try another method: + l = sorted(os.listdir(xlf_dir)) + l.reverse() + l = [d for d in l if os.path.isfile(os.path.join(xlf_dir, d, 'xlf.cfg'))] + if l: + from distutils.version import LooseVersion + self.version = version = LooseVersion(l[0]) + return version + + def get_flags(self): + return ['-qextname'] + + def get_flags_debug(self): + return ['-g'] + + def get_flags_linker_so(self): + opt = [] + if sys.platform=='darwin': + opt.append('-Wl,-bundle,-flat_namespace,-undefined,suppress') + else: + opt.append('-bshared') + version = self.get_version(ok_status=[0, 40]) + if version is not None: + if sys.platform.startswith('aix'): + xlf_cfg = '/etc/xlf.cfg' + else: + xlf_cfg = '/etc/opt/ibmcmp/xlf/%s/xlf.cfg' % version + fo, new_cfg = make_temp_file(suffix='_xlf.cfg') + log.info('Creating '+new_cfg) + fi = open(xlf_cfg, 'r') + crt1_match = re.compile(r'\s*crt\s*[=]\s*(?P.*)/crt1.o').match + for line in fi: + m = crt1_match(line) + if m: + fo.write('crt = %s/bundle1.o\n' % (m.group('path'))) + else: + fo.write(line) + fi.close() + fo.close() + opt.append('-F'+new_cfg) + return opt + + def get_flags_opt(self): + return ['-O3'] + +if __name__ == '__main__': + from numpy.distutils import customized_fcompiler + log.set_verbosity(2) + print(customized_fcompiler(compiler='ibm').get_version()) diff --git a/numpy/distutils/fcompiler/intel.py b/numpy/distutils/fcompiler/intel.py new file mode 100644 index 0000000..217eac8 --- /dev/null +++ b/numpy/distutils/fcompiler/intel.py @@ -0,0 +1,219 @@ +# http://developer.intel.com/software/products/compilers/flin/ +from __future__ import division, absolute_import, print_function + +import sys + +from numpy.distutils.ccompiler import simple_version_match +from numpy.distutils.fcompiler import FCompiler, dummy_fortran_file + +compilers = ['IntelFCompiler', 'IntelVisualFCompiler', + 'IntelItaniumFCompiler', 'IntelItaniumVisualFCompiler', + 'IntelEM64VisualFCompiler', 'IntelEM64TFCompiler'] + + +def intel_version_match(type): + # Match against the important stuff in the version string + return simple_version_match(start=r'Intel.*?Fortran.*?(?:%s).*?Version' % (type,)) + + +class BaseIntelFCompiler(FCompiler): + def update_executables(self): + f = dummy_fortran_file() + self.executables['version_cmd'] = ['', '-FI', '-V', '-c', + f + '.f', '-o', f + '.o'] + + def runtime_library_dir_option(self, dir): + return '-Wl,-rpath="%s"' % dir + + +class IntelFCompiler(BaseIntelFCompiler): + + compiler_type = 'intel' + compiler_aliases = ('ifort',) + description = 'Intel Fortran Compiler for 32-bit apps' + version_match = intel_version_match('32-bit|IA-32') + + possible_executables = ['ifort', 'ifc'] + + executables = { + 'version_cmd' : None, # set by update_executables + 'compiler_f77' : [None, "-72", "-w90", "-w95"], + 'compiler_f90' : [None], + 'compiler_fix' : [None, "-FI"], + 'linker_so' : ["", "-shared"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + pic_flags = ['-fPIC'] + module_dir_switch = '-module ' # Don't remove ending space! + module_include_switch = '-I' + + def get_flags_free(self): + return ['-FR'] + + def get_flags(self): + return ['-fPIC'] + + def get_flags_opt(self): # Scipy test failures with -O2 + v = self.get_version() + mpopt = 'openmp' if v and v < '15' else 'qopenmp' + return ['-fp-model strict -O1 -{}'.format(mpopt)] + + def get_flags_arch(self): + return [] + + def get_flags_linker_so(self): + opt = FCompiler.get_flags_linker_so(self) + v = self.get_version() + if v and v >= '8.0': + opt.append('-nofor_main') + if sys.platform == 'darwin': + # Here, it's -dynamiclib + try: + idx = opt.index('-shared') + opt.remove('-shared') + except ValueError: + idx = 0 + opt[idx:idx] = ['-dynamiclib', '-Wl,-undefined,dynamic_lookup'] + return opt + + +class IntelItaniumFCompiler(IntelFCompiler): + compiler_type = 'intele' + compiler_aliases = () + description = 'Intel Fortran Compiler for Itanium apps' + + version_match = intel_version_match('Itanium|IA-64') + + possible_executables = ['ifort', 'efort', 'efc'] + + executables = { + 'version_cmd' : None, + 'compiler_f77' : [None, "-FI", "-w90", "-w95"], + 'compiler_fix' : [None, "-FI"], + 'compiler_f90' : [None], + 'linker_so' : ['', "-shared"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + +class IntelEM64TFCompiler(IntelFCompiler): + compiler_type = 'intelem' + compiler_aliases = () + description = 'Intel Fortran Compiler for 64-bit apps' + + version_match = intel_version_match('EM64T-based|Intel\\(R\\) 64|64|IA-64|64-bit') + + possible_executables = ['ifort', 'efort', 'efc'] + + executables = { + 'version_cmd' : None, + 'compiler_f77' : [None, "-FI"], + 'compiler_fix' : [None, "-FI"], + 'compiler_f90' : [None], + 'linker_so' : ['', "-shared"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + def get_flags(self): + return ['-fPIC'] + + def get_flags_opt(self): # Scipy test failures with -O2 + v = self.get_version() + mpopt = 'openmp' if v and v < '15' else 'qopenmp' + return ['-fp-model strict -O1 -{}'.format(mpopt)] + + def get_flags_arch(self): + return [''] + +# Is there no difference in the version string between the above compilers +# and the Visual compilers? + + +class IntelVisualFCompiler(BaseIntelFCompiler): + compiler_type = 'intelv' + description = 'Intel Visual Fortran Compiler for 32-bit apps' + version_match = intel_version_match('32-bit|IA-32') + + def update_executables(self): + f = dummy_fortran_file() + self.executables['version_cmd'] = ['', '/FI', '/c', + f + '.f', '/o', f + '.o'] + + ar_exe = 'lib.exe' + possible_executables = ['ifort', 'ifl'] + + executables = { + 'version_cmd' : None, + 'compiler_f77' : [None], + 'compiler_fix' : [None], + 'compiler_f90' : [None], + 'linker_so' : [None], + 'archiver' : [ar_exe, "/verbose", "/OUT:"], + 'ranlib' : None + } + + compile_switch = '/c ' + object_switch = '/Fo' # No space after /Fo! + library_switch = '/OUT:' # No space after /OUT:! + module_dir_switch = '/module:' # No space after /module: + module_include_switch = '/I' + + def get_flags(self): + opt = ['/nologo', '/MD', '/nbs', '/names:lowercase', '/assume:underscore'] + return opt + + def get_flags_free(self): + return [] + + def get_flags_debug(self): + return ['/4Yb', '/d2'] + + def get_flags_opt(self): + return ['/O1'] # Scipy test failures with /O2 + + def get_flags_arch(self): + return ["/arch:IA32", "/QaxSSE3"] + + def runtime_library_dir_option(self, dir): + raise NotImplementedError + + +class IntelItaniumVisualFCompiler(IntelVisualFCompiler): + compiler_type = 'intelev' + description = 'Intel Visual Fortran Compiler for Itanium apps' + + version_match = intel_version_match('Itanium') + + possible_executables = ['efl'] # XXX this is a wild guess + ar_exe = IntelVisualFCompiler.ar_exe + + executables = { + 'version_cmd' : None, + 'compiler_f77' : [None, "-FI", "-w90", "-w95"], + 'compiler_fix' : [None, "-FI", "-4L72", "-w"], + 'compiler_f90' : [None], + 'linker_so' : ['', "-shared"], + 'archiver' : [ar_exe, "/verbose", "/OUT:"], + 'ranlib' : None + } + + +class IntelEM64VisualFCompiler(IntelVisualFCompiler): + compiler_type = 'intelvem' + description = 'Intel Visual Fortran Compiler for 64-bit apps' + + version_match = simple_version_match(start=r'Intel\(R\).*?64,') + + def get_flags_arch(self): + return [''] + + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='intel').get_version()) diff --git a/numpy/distutils/fcompiler/lahey.py b/numpy/distutils/fcompiler/lahey.py new file mode 100644 index 0000000..1beb662 --- /dev/null +++ b/numpy/distutils/fcompiler/lahey.py @@ -0,0 +1,47 @@ +from __future__ import division, absolute_import, print_function + +import os + +from numpy.distutils.fcompiler import FCompiler + +compilers = ['LaheyFCompiler'] + +class LaheyFCompiler(FCompiler): + + compiler_type = 'lahey' + description = 'Lahey/Fujitsu Fortran 95 Compiler' + version_pattern = r'Lahey/Fujitsu Fortran 95 Compiler Release (?P[^\s*]*)' + + executables = { + 'version_cmd' : ["", "--version"], + 'compiler_f77' : ["lf95", "--fix"], + 'compiler_fix' : ["lf95", "--fix"], + 'compiler_f90' : ["lf95"], + 'linker_so' : ["lf95", "-shared"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + module_dir_switch = None #XXX Fix me + module_include_switch = None #XXX Fix me + + def get_flags_opt(self): + return ['-O'] + def get_flags_debug(self): + return ['-g', '--chk', '--chkglobal'] + def get_library_dirs(self): + opt = [] + d = os.environ.get('LAHEY') + if d: + opt.append(os.path.join(d, 'lib')) + return opt + def get_libraries(self): + opt = [] + opt.extend(['fj9f6', 'fj9i6', 'fj9ipp', 'fj9e6']) + return opt + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='lahey').get_version()) diff --git a/numpy/distutils/fcompiler/mips.py b/numpy/distutils/fcompiler/mips.py new file mode 100644 index 0000000..da337b2 --- /dev/null +++ b/numpy/distutils/fcompiler/mips.py @@ -0,0 +1,56 @@ +from __future__ import division, absolute_import, print_function + +from numpy.distutils.cpuinfo import cpu +from numpy.distutils.fcompiler import FCompiler + +compilers = ['MIPSFCompiler'] + +class MIPSFCompiler(FCompiler): + + compiler_type = 'mips' + description = 'MIPSpro Fortran Compiler' + version_pattern = r'MIPSpro Compilers: Version (?P[^\s*,]*)' + + executables = { + 'version_cmd' : ["", "-version"], + 'compiler_f77' : ["f77", "-f77"], + 'compiler_fix' : ["f90", "-fixedform"], + 'compiler_f90' : ["f90"], + 'linker_so' : ["f90", "-shared"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : None + } + module_dir_switch = None #XXX: fix me + module_include_switch = None #XXX: fix me + pic_flags = ['-KPIC'] + + def get_flags(self): + return self.pic_flags + ['-n32'] + def get_flags_opt(self): + return ['-O3'] + def get_flags_arch(self): + opt = [] + for a in '19 20 21 22_4k 22_5k 24 25 26 27 28 30 32_5k 32_10k'.split(): + if getattr(cpu, 'is_IP%s'%a)(): + opt.append('-TARG:platform=IP%s' % a) + break + return opt + def get_flags_arch_f77(self): + r = None + if cpu.is_r10000(): r = 10000 + elif cpu.is_r12000(): r = 12000 + elif cpu.is_r8000(): r = 8000 + elif cpu.is_r5000(): r = 5000 + elif cpu.is_r4000(): r = 4000 + if r is not None: + return ['r%s' % (r)] + return [] + def get_flags_arch_f90(self): + r = self.get_flags_arch_f77() + if r: + r[0] = '-' + r[0] + return r + +if __name__ == '__main__': + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='mips').get_version()) diff --git a/numpy/distutils/fcompiler/nag.py b/numpy/distutils/fcompiler/nag.py new file mode 100644 index 0000000..cb71d54 --- /dev/null +++ b/numpy/distutils/fcompiler/nag.py @@ -0,0 +1,84 @@ +from __future__ import division, absolute_import, print_function + +import sys +import re +from numpy.distutils.fcompiler import FCompiler + +compilers = ['NAGFCompiler', 'NAGFORCompiler'] + +class BaseNAGFCompiler(FCompiler): + version_pattern = r'NAG.* Release (?P[^(\s]*)' + + def version_match(self, version_string): + m = re.search(self.version_pattern, version_string) + if m: + return m.group('version') + else: + return None + + def get_flags_linker_so(self): + return ["-Wl,-shared"] + def get_flags_opt(self): + return ['-O4'] + def get_flags_arch(self): + return [''] + +class NAGFCompiler(BaseNAGFCompiler): + + compiler_type = 'nag' + description = 'NAGWare Fortran 95 Compiler' + + executables = { + 'version_cmd' : ["", "-V"], + 'compiler_f77' : ["f95", "-fixed"], + 'compiler_fix' : ["f95", "-fixed"], + 'compiler_f90' : ["f95"], + 'linker_so' : [""], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + def get_flags_linker_so(self): + if sys.platform == 'darwin': + return ['-unsharedf95', '-Wl,-bundle,-flat_namespace,-undefined,suppress'] + return BaseNAGFCompiler.get_flags_linker_so(self) + def get_flags_arch(self): + version = self.get_version() + if version and version < '5.1': + return ['-target=native'] + else: + return BaseNAGFCompiler.get_flags_arch(self) + def get_flags_debug(self): + return ['-g', '-gline', '-g90', '-nan', '-C'] + +class NAGFORCompiler(BaseNAGFCompiler): + + compiler_type = 'nagfor' + description = 'NAG Fortran Compiler' + + executables = { + 'version_cmd' : ["nagfor", "-V"], + 'compiler_f77' : ["nagfor", "-fixed"], + 'compiler_fix' : ["nagfor", "-fixed"], + 'compiler_f90' : ["nagfor"], + 'linker_so' : ["nagfor"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + + def get_flags_debug(self): + version = self.get_version() + if version and version > '6.1': + return ['-g', '-u', '-nan', '-C=all', '-thread_safe', + '-kind=unique', '-Warn=allocation', '-Warn=subnormal'] + else: + return ['-g', '-nan', '-C=all', '-u', '-thread_safe'] + + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + compiler = customized_fcompiler(compiler='nagfor') + print(compiler.get_version()) + print(compiler.get_flags_debug()) diff --git a/numpy/distutils/fcompiler/none.py b/numpy/distutils/fcompiler/none.py new file mode 100644 index 0000000..bdeea15 --- /dev/null +++ b/numpy/distutils/fcompiler/none.py @@ -0,0 +1,30 @@ +from __future__ import division, absolute_import, print_function + +from numpy.distutils.fcompiler import FCompiler +from numpy.distutils import customized_fcompiler + +compilers = ['NoneFCompiler'] + +class NoneFCompiler(FCompiler): + + compiler_type = 'none' + description = 'Fake Fortran compiler' + + executables = {'compiler_f77': None, + 'compiler_f90': None, + 'compiler_fix': None, + 'linker_so': None, + 'linker_exe': None, + 'archiver': None, + 'ranlib': None, + 'version_cmd': None, + } + + def find_executables(self): + pass + + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + print(customized_fcompiler(compiler='none').get_version()) diff --git a/numpy/distutils/fcompiler/pathf95.py b/numpy/distutils/fcompiler/pathf95.py new file mode 100644 index 0000000..5de86f6 --- /dev/null +++ b/numpy/distutils/fcompiler/pathf95.py @@ -0,0 +1,35 @@ +from __future__ import division, absolute_import, print_function + +from numpy.distutils.fcompiler import FCompiler + +compilers = ['PathScaleFCompiler'] + +class PathScaleFCompiler(FCompiler): + + compiler_type = 'pathf95' + description = 'PathScale Fortran Compiler' + version_pattern = r'PathScale\(TM\) Compiler Suite: Version (?P[\d.]+)' + + executables = { + 'version_cmd' : ["pathf95", "-version"], + 'compiler_f77' : ["pathf95", "-fixedform"], + 'compiler_fix' : ["pathf95", "-fixedform"], + 'compiler_f90' : ["pathf95"], + 'linker_so' : ["pathf95", "-shared"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + pic_flags = ['-fPIC'] + module_dir_switch = '-module ' # Don't remove ending space! + module_include_switch = '-I' + + def get_flags_opt(self): + return ['-O3'] + def get_flags_debug(self): + return ['-g'] + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='pathf95').get_version()) diff --git a/numpy/distutils/fcompiler/pg.py b/numpy/distutils/fcompiler/pg.py new file mode 100644 index 0000000..e6c816b --- /dev/null +++ b/numpy/distutils/fcompiler/pg.py @@ -0,0 +1,141 @@ +# http://www.pgroup.com +from __future__ import division, absolute_import, print_function + +import sys +import os + +from numpy.distutils.fcompiler import FCompiler, dummy_fortran_file +from sys import platform +from os.path import join, dirname, normpath + +compilers = ['PGroupFCompiler', 'PGroupFlangCompiler'] + + +class PGroupFCompiler(FCompiler): + + compiler_type = 'pg' + description = 'Portland Group Fortran Compiler' + version_pattern = r'\s*pg(f77|f90|hpf|fortran) (?P[\d.-]+).*' + + if platform == 'darwin': + executables = { + 'version_cmd': ["", "-V"], + 'compiler_f77': ["pgfortran", "-dynamiclib"], + 'compiler_fix': ["pgfortran", "-Mfixed", "-dynamiclib"], + 'compiler_f90': ["pgfortran", "-dynamiclib"], + 'linker_so': ["libtool"], + 'archiver': ["ar", "-cr"], + 'ranlib': ["ranlib"] + } + pic_flags = [''] + else: + executables = { + 'version_cmd': ["", "-V"], + 'compiler_f77': ["pgfortran"], + 'compiler_fix': ["pgfortran", "-Mfixed"], + 'compiler_f90': ["pgfortran"], + 'linker_so': ["pgfortran", "-shared", "-fpic"], + 'archiver': ["ar", "-cr"], + 'ranlib': ["ranlib"] + } + pic_flags = ['-fpic'] + + module_dir_switch = '-module ' + module_include_switch = '-I' + + def get_flags(self): + opt = ['-Minform=inform', '-Mnosecond_underscore'] + return self.pic_flags + opt + + def get_flags_opt(self): + return ['-fast'] + + def get_flags_debug(self): + return ['-g'] + + if platform == 'darwin': + def get_flags_linker_so(self): + return ["-dynamic", '-undefined', 'dynamic_lookup'] + + def runtime_library_dir_option(self, dir): + return '-R"%s"' % dir + + +if sys.version_info >= (3, 5): + import subprocess + import shlex + import functools + + class PGroupFlangCompiler(FCompiler): + compiler_type = 'flang' + description = 'Portland Group Fortran LLVM Compiler' + version_pattern = r'\s*(flang|clang) version (?P[\d.-]+).*' + + ar_exe = 'lib.exe' + possible_executables = ['flang'] + + executables = { + 'version_cmd': ["", "--version"], + 'compiler_f77': ["flang"], + 'compiler_fix': ["flang"], + 'compiler_f90': ["flang"], + 'linker_so': [None], + 'archiver': [ar_exe, "/verbose", "/OUT:"], + 'ranlib': None + } + + library_switch = '/OUT:' # No space after /OUT:! + module_dir_switch = '-module ' # Don't remove ending space! + + def get_libraries(self): + opt = FCompiler.get_libraries(self) + opt.extend(['flang', 'flangrti', 'ompstub']) + return opt + + @functools.lru_cache(maxsize=128) + def get_library_dirs(self): + """List of compiler library directories.""" + opt = FCompiler.get_library_dirs(self) + flang_dir = dirname(self.executables['compiler_f77'][0]) + opt.append(normpath(join(flang_dir, '..', 'lib'))) + + return opt + + def get_flags(self): + return [] + + def get_flags_free(self): + return [] + + def get_flags_debug(self): + return ['-g'] + + def get_flags_opt(self): + return ['-O3'] + + def get_flags_arch(self): + return [] + + def runtime_library_dir_option(self, dir): + raise NotImplementedError + +else: + from numpy.distutils.fcompiler import CompilerNotFound + + # No point in supporting on older Pythons because not ABI compatible + class PGroupFlangCompiler(FCompiler): + compiler_type = 'flang' + description = 'Portland Group Fortran LLVM Compiler' + + def get_version(self): + raise CompilerNotFound('Flang unsupported on Python < 3.5') + + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + if 'flang' in sys.argv: + print(customized_fcompiler(compiler='flang').get_version()) + else: + print(customized_fcompiler(compiler='pg').get_version()) diff --git a/numpy/distutils/fcompiler/sun.py b/numpy/distutils/fcompiler/sun.py new file mode 100644 index 0000000..d477d33 --- /dev/null +++ b/numpy/distutils/fcompiler/sun.py @@ -0,0 +1,53 @@ +from __future__ import division, absolute_import, print_function + +from numpy.distutils.ccompiler import simple_version_match +from numpy.distutils.fcompiler import FCompiler + +compilers = ['SunFCompiler'] + +class SunFCompiler(FCompiler): + + compiler_type = 'sun' + description = 'Sun or Forte Fortran 95 Compiler' + # ex: + # f90: Sun WorkShop 6 update 2 Fortran 95 6.2 Patch 111690-10 2003/08/28 + version_match = simple_version_match( + start=r'f9[05]: (Sun|Forte|WorkShop).*Fortran 95') + + executables = { + 'version_cmd' : ["", "-V"], + 'compiler_f77' : ["f90"], + 'compiler_fix' : ["f90", "-fixed"], + 'compiler_f90' : ["f90"], + 'linker_so' : ["", "-Bdynamic", "-G"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + module_dir_switch = '-moddir=' + module_include_switch = '-M' + pic_flags = ['-xcode=pic32'] + + def get_flags_f77(self): + ret = ["-ftrap=%none"] + if (self.get_version() or '') >= '7': + ret.append("-f77") + else: + ret.append("-fixed") + return ret + def get_opt(self): + return ['-fast', '-dalign'] + def get_arch(self): + return ['-xtarget=generic'] + def get_libraries(self): + opt = [] + opt.extend(['fsu', 'sunmath', 'mvec']) + return opt + + def runtime_library_dir_option(self, dir): + return '-R"%s"' % dir + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='sun').get_version()) diff --git a/numpy/distutils/fcompiler/vast.py b/numpy/distutils/fcompiler/vast.py new file mode 100644 index 0000000..adc1591 --- /dev/null +++ b/numpy/distutils/fcompiler/vast.py @@ -0,0 +1,54 @@ +from __future__ import division, absolute_import, print_function + +import os + +from numpy.distutils.fcompiler.gnu import GnuFCompiler + +compilers = ['VastFCompiler'] + +class VastFCompiler(GnuFCompiler): + compiler_type = 'vast' + compiler_aliases = () + description = 'Pacific-Sierra Research Fortran 90 Compiler' + version_pattern = (r'\s*Pacific-Sierra Research vf90 ' + r'(Personal|Professional)\s+(?P[^\s]*)') + + # VAST f90 does not support -o with -c. So, object files are created + # to the current directory and then moved to build directory + object_switch = ' && function _mvfile { mv -v `basename $1` $1 ; } && _mvfile ' + + executables = { + 'version_cmd' : ["vf90", "-v"], + 'compiler_f77' : ["g77"], + 'compiler_fix' : ["f90", "-Wv,-ya"], + 'compiler_f90' : ["f90"], + 'linker_so' : [""], + 'archiver' : ["ar", "-cr"], + 'ranlib' : ["ranlib"] + } + module_dir_switch = None #XXX Fix me + module_include_switch = None #XXX Fix me + + def find_executables(self): + pass + + def get_version_cmd(self): + f90 = self.compiler_f90[0] + d, b = os.path.split(f90) + vf90 = os.path.join(d, 'v'+b) + return vf90 + + def get_flags_arch(self): + vast_version = self.get_version() + gnu = GnuFCompiler() + gnu.customize(None) + self.version = gnu.get_version() + opt = GnuFCompiler.get_flags_arch(self) + self.version = vast_version + return opt + +if __name__ == '__main__': + from distutils import log + log.set_verbosity(2) + from numpy.distutils import customized_fcompiler + print(customized_fcompiler(compiler='vast').get_version()) diff --git a/numpy/distutils/from_template.py b/numpy/distutils/from_template.py new file mode 100644 index 0000000..b19c7cc --- /dev/null +++ b/numpy/distutils/from_template.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python +""" + +process_file(filename) + + takes templated file .xxx.src and produces .xxx file where .xxx + is .pyf .f90 or .f using the following template rules: + + '<..>' denotes a template. + + All function and subroutine blocks in a source file with names that + contain '<..>' will be replicated according to the rules in '<..>'. + + The number of comma-separated words in '<..>' will determine the number of + replicates. + + '<..>' may have two different forms, named and short. For example, + + named: + where anywhere inside a block '

    ' will be replaced with + 'd', 's', 'z', and 'c' for each replicate of the block. + + <_c> is already defined: <_c=s,d,c,z> + <_t> is already defined: <_t=real,double precision,complex,double complex> + + short: + , a short form of the named, useful when no

    appears inside + a block. + + In general, '<..>' contains a comma separated list of arbitrary + expressions. If these expression must contain a comma|leftarrow|rightarrow, + then prepend the comma|leftarrow|rightarrow with a backslash. + + If an expression matches '\\' then it will be replaced + by -th expression. + + Note that all '<..>' forms in a block must have the same number of + comma-separated entries. + + Predefined named template rules: + + + + + + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['process_str', 'process_file'] + +import os +import sys +import re + +routine_start_re = re.compile(r'(\n|\A)(( (\$|\*))|)\s*(subroutine|function)\b', re.I) +routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)', re.I) +function_start_re = re.compile(r'\n (\$|\*)\s*function\b', re.I) + +def parse_structure(astr): + """ Return a list of tuples for each function or subroutine each + tuple is the start and end of a subroutine or function to be + expanded. + """ + + spanlist = [] + ind = 0 + while True: + m = routine_start_re.search(astr, ind) + if m is None: + break + start = m.start() + if function_start_re.match(astr, start, m.end()): + while True: + i = astr.rfind('\n', ind, start) + if i==-1: + break + start = i + if astr[i:i+7]!='\n $': + break + start += 1 + m = routine_end_re.search(astr, m.end()) + ind = end = m and m.end()-1 or len(astr) + spanlist.append((start, end)) + return spanlist + +template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>") +named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>") +list_re = re.compile(r"<\s*((.*?))\s*>") + +def find_repl_patterns(astr): + reps = named_re.findall(astr) + names = {} + for rep in reps: + name = rep[0].strip() or unique_key(names) + repl = rep[1].replace(r'\,', '@comma@') + thelist = conv(repl) + names[name] = thelist + return names + +item_re = re.compile(r"\A\\(?P\d+)\Z") +def conv(astr): + b = astr.split(',') + l = [x.strip() for x in b] + for i in range(len(l)): + m = item_re.match(l[i]) + if m: + j = int(m.group('index')) + l[i] = l[j] + return ','.join(l) + +def unique_key(adict): + """ Obtain a unique key given a dictionary.""" + allkeys = list(adict.keys()) + done = False + n = 1 + while not done: + newkey = '__l%s' % (n) + if newkey in allkeys: + n += 1 + else: + done = True + return newkey + + +template_name_re = re.compile(r'\A\s*(\w[\w\d]*)\s*\Z') +def expand_sub(substr, names): + substr = substr.replace(r'\>', '@rightarrow@') + substr = substr.replace(r'\<', '@leftarrow@') + lnames = find_repl_patterns(substr) + substr = named_re.sub(r"<\1>", substr) # get rid of definition templates + + def listrepl(mobj): + thelist = conv(mobj.group(1).replace(r'\,', '@comma@')) + if template_name_re.match(thelist): + return "<%s>" % (thelist) + name = None + for key in lnames.keys(): # see if list is already in dictionary + if lnames[key] == thelist: + name = key + if name is None: # this list is not in the dictionary yet + name = unique_key(lnames) + lnames[name] = thelist + return "<%s>" % name + + substr = list_re.sub(listrepl, substr) # convert all lists to named templates + # newnames are constructed as needed + + numsubs = None + base_rule = None + rules = {} + for r in template_re.findall(substr): + if r not in rules: + thelist = lnames.get(r, names.get(r, None)) + if thelist is None: + raise ValueError('No replicates found for <%s>' % (r)) + if r not in names and not thelist.startswith('_'): + names[r] = thelist + rule = [i.replace('@comma@', ',') for i in thelist.split(',')] + num = len(rule) + + if numsubs is None: + numsubs = num + rules[r] = rule + base_rule = r + elif num == numsubs: + rules[r] = rule + else: + print("Mismatch in number of replacements (base <%s=%s>)" + " for <%s=%s>. Ignoring." % + (base_rule, ','.join(rules[base_rule]), r, thelist)) + if not rules: + return substr + + def namerepl(mobj): + name = mobj.group(1) + return rules.get(name, (k+1)*[name])[k] + + newstr = '' + for k in range(numsubs): + newstr += template_re.sub(namerepl, substr) + '\n\n' + + newstr = newstr.replace('@rightarrow@', '>') + newstr = newstr.replace('@leftarrow@', '<') + return newstr + +def process_str(allstr): + newstr = allstr + writestr = '' #_head # using _head will break free-format files + + struct = parse_structure(newstr) + + oldend = 0 + names = {} + names.update(_special_names) + for sub in struct: + writestr += newstr[oldend:sub[0]] + names.update(find_repl_patterns(newstr[oldend:sub[0]])) + writestr += expand_sub(newstr[sub[0]:sub[1]], names) + oldend = sub[1] + writestr += newstr[oldend:] + + return writestr + +include_src_re = re.compile(r"(\n|\A)\s*include\s*['\"](?P[\w\d./\\]+[.]src)['\"]", re.I) + +def resolve_includes(source): + d = os.path.dirname(source) + fid = open(source) + lines = [] + for line in fid: + m = include_src_re.match(line) + if m: + fn = m.group('name') + if not os.path.isabs(fn): + fn = os.path.join(d, fn) + if os.path.isfile(fn): + print('Including file', fn) + lines.extend(resolve_includes(fn)) + else: + lines.append(line) + else: + lines.append(line) + fid.close() + return lines + +def process_file(source): + lines = resolve_includes(source) + return process_str(''.join(lines)) + +_special_names = find_repl_patterns(''' +<_c=s,d,c,z> +<_t=real,double precision,complex,double complex> + + + + + +''') + +if __name__ == "__main__": + + try: + file = sys.argv[1] + except IndexError: + fid = sys.stdin + outfile = sys.stdout + else: + fid = open(file, 'r') + (base, ext) = os.path.splitext(file) + newname = base + outfile = open(newname, 'w') + + allstr = fid.read() + writestr = process_str(allstr) + outfile.write(writestr) diff --git a/numpy/distutils/info.py b/numpy/distutils/info.py new file mode 100644 index 0000000..2f53106 --- /dev/null +++ b/numpy/distutils/info.py @@ -0,0 +1,6 @@ +""" +Enhanced distutils with Fortran compilers support and more. +""" +from __future__ import division, absolute_import, print_function + +postpone_import = True diff --git a/numpy/distutils/intelccompiler.py b/numpy/distutils/intelccompiler.py new file mode 100644 index 0000000..3386775 --- /dev/null +++ b/numpy/distutils/intelccompiler.py @@ -0,0 +1,113 @@ +from __future__ import division, absolute_import, print_function + +import platform + +from distutils.unixccompiler import UnixCCompiler +from numpy.distutils.exec_command import find_executable +from numpy.distutils.ccompiler import simple_version_match +if platform.system() == 'Windows': + from numpy.distutils.msvc9compiler import MSVCCompiler + + +class IntelCCompiler(UnixCCompiler): + """A modified Intel compiler compatible with a GCC-built Python.""" + compiler_type = 'intel' + cc_exe = 'icc' + cc_args = 'fPIC' + + def __init__(self, verbose=0, dry_run=0, force=0): + UnixCCompiler.__init__(self, verbose, dry_run, force) + + v = self.get_version() + mpopt = 'openmp' if v and v < '15' else 'qopenmp' + self.cc_exe = ('icc -fPIC -fp-model strict -O3 ' + '-fomit-frame-pointer -{}').format(mpopt) + compiler = self.cc_exe + + if platform.system() == 'Darwin': + shared_flag = '-Wl,-undefined,dynamic_lookup' + else: + shared_flag = '-shared' + self.set_executables(compiler=compiler, + compiler_so=compiler, + compiler_cxx=compiler, + archiver='xiar' + ' cru', + linker_exe=compiler + ' -shared-intel', + linker_so=compiler + ' ' + shared_flag + + ' -shared-intel') + + +class IntelItaniumCCompiler(IntelCCompiler): + compiler_type = 'intele' + + # On Itanium, the Intel Compiler used to be called ecc, let's search for + # it (now it's also icc, so ecc is last in the search). + for cc_exe in map(find_executable, ['icc', 'ecc']): + if cc_exe: + break + + +class IntelEM64TCCompiler(UnixCCompiler): + """ + A modified Intel x86_64 compiler compatible with a 64bit GCC-built Python. + """ + compiler_type = 'intelem' + cc_exe = 'icc -m64' + cc_args = '-fPIC' + + def __init__(self, verbose=0, dry_run=0, force=0): + UnixCCompiler.__init__(self, verbose, dry_run, force) + + v = self.get_version() + mpopt = 'openmp' if v and v < '15' else 'qopenmp' + self.cc_exe = ('icc -m64 -fPIC -fp-model strict -O3 ' + '-fomit-frame-pointer -{}').format(mpopt) + compiler = self.cc_exe + + if platform.system() == 'Darwin': + shared_flag = '-Wl,-undefined,dynamic_lookup' + else: + shared_flag = '-shared' + self.set_executables(compiler=compiler, + compiler_so=compiler, + compiler_cxx=compiler, + archiver='xiar' + ' cru', + linker_exe=compiler + ' -shared-intel', + linker_so=compiler + ' ' + shared_flag + + ' -shared-intel') + + +if platform.system() == 'Windows': + class IntelCCompilerW(MSVCCompiler): + """ + A modified Intel compiler compatible with an MSVC-built Python. + """ + compiler_type = 'intelw' + compiler_cxx = 'icl' + + def __init__(self, verbose=0, dry_run=0, force=0): + MSVCCompiler.__init__(self, verbose, dry_run, force) + version_match = simple_version_match(start=r'Intel\(R\).*?32,') + self.__version = version_match + + def initialize(self, plat_name=None): + MSVCCompiler.initialize(self, plat_name) + self.cc = self.find_exe('icl.exe') + self.lib = self.find_exe('xilib') + self.linker = self.find_exe('xilink') + self.compile_options = ['/nologo', '/O3', '/MD', '/W3', + '/Qstd=c99'] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', + '/Qstd=c99', '/Z7', '/D_DEBUG'] + + class IntelEM64TCCompilerW(IntelCCompilerW): + """ + A modified Intel x86_64 compiler compatible with + a 64bit MSVC-built Python. + """ + compiler_type = 'intelemw' + + def __init__(self, verbose=0, dry_run=0, force=0): + MSVCCompiler.__init__(self, verbose, dry_run, force) + version_match = simple_version_match(start=r'Intel\(R\).*?64,') + self.__version = version_match diff --git a/numpy/distutils/lib2def.py b/numpy/distutils/lib2def.py new file mode 100644 index 0000000..0a53645 --- /dev/null +++ b/numpy/distutils/lib2def.py @@ -0,0 +1,116 @@ +from __future__ import division, absolute_import, print_function + +import re +import sys +import os +import subprocess + +__doc__ = """This module generates a DEF file from the symbols in +an MSVC-compiled DLL import library. It correctly discriminates between +data and functions. The data is collected from the output of the program +nm(1). + +Usage: + python lib2def.py [libname.lib] [output.def] +or + python lib2def.py [libname.lib] > output.def + +libname.lib defaults to python.lib and output.def defaults to stdout + +Author: Robert Kern +Last Update: April 30, 1999 +""" + +__version__ = '0.1a' + +py_ver = "%d%d" % tuple(sys.version_info[:2]) + +DEFAULT_NM = 'nm -Cs' + +DEF_HEADER = """LIBRARY python%s.dll +;CODE PRELOAD MOVEABLE DISCARDABLE +;DATA PRELOAD SINGLE + +EXPORTS +""" % py_ver +# the header of the DEF file + +FUNC_RE = re.compile(r"^(.*) in python%s\.dll" % py_ver, re.MULTILINE) +DATA_RE = re.compile(r"^_imp__(.*) in python%s\.dll" % py_ver, re.MULTILINE) + +def parse_cmd(): + """Parses the command-line arguments. + +libfile, deffile = parse_cmd()""" + if len(sys.argv) == 3: + if sys.argv[1][-4:] == '.lib' and sys.argv[2][-4:] == '.def': + libfile, deffile = sys.argv[1:] + elif sys.argv[1][-4:] == '.def' and sys.argv[2][-4:] == '.lib': + deffile, libfile = sys.argv[1:] + else: + print("I'm assuming that your first argument is the library") + print("and the second is the DEF file.") + elif len(sys.argv) == 2: + if sys.argv[1][-4:] == '.def': + deffile = sys.argv[1] + libfile = 'python%s.lib' % py_ver + elif sys.argv[1][-4:] == '.lib': + deffile = None + libfile = sys.argv[1] + else: + libfile = 'python%s.lib' % py_ver + deffile = None + return libfile, deffile + +def getnm(nm_cmd = ['nm', '-Cs', 'python%s.lib' % py_ver]): + """Returns the output of nm_cmd via a pipe. + +nm_output = getnam(nm_cmd = 'nm -Cs py_lib')""" + f = subprocess.Popen(nm_cmd, shell=True, stdout=subprocess.PIPE, universal_newlines=True) + nm_output = f.stdout.read() + f.stdout.close() + return nm_output + +def parse_nm(nm_output): + """Returns a tuple of lists: dlist for the list of data +symbols and flist for the list of function symbols. + +dlist, flist = parse_nm(nm_output)""" + data = DATA_RE.findall(nm_output) + func = FUNC_RE.findall(nm_output) + + flist = [] + for sym in data: + if sym in func and (sym[:2] == 'Py' or sym[:3] == '_Py' or sym[:4] == 'init'): + flist.append(sym) + + dlist = [] + for sym in data: + if sym not in flist and (sym[:2] == 'Py' or sym[:3] == '_Py'): + dlist.append(sym) + + dlist.sort() + flist.sort() + return dlist, flist + +def output_def(dlist, flist, header, file = sys.stdout): + """Outputs the final DEF file to a file defaulting to stdout. + +output_def(dlist, flist, header, file = sys.stdout)""" + for data_sym in dlist: + header = header + '\t%s DATA\n' % data_sym + header = header + '\n' # blank line + for func_sym in flist: + header = header + '\t%s\n' % func_sym + file.write(header) + +if __name__ == '__main__': + libfile, deffile = parse_cmd() + if deffile is None: + deffile = sys.stdout + else: + deffile = open(deffile, 'w') + nm_cmd = [str(DEFAULT_NM), str(libfile)] + nm_output = getnm(nm_cmd) + dlist, flist = parse_nm(nm_output) + output_def(dlist, flist, DEF_HEADER, deffile) diff --git a/numpy/distutils/line_endings.py b/numpy/distutils/line_endings.py new file mode 100644 index 0000000..5ecb104 --- /dev/null +++ b/numpy/distutils/line_endings.py @@ -0,0 +1,76 @@ +""" Functions for converting from DOS to UNIX line endings + +""" +from __future__ import division, absolute_import, print_function + +import sys, re, os + +def dos2unix(file): + "Replace CRLF with LF in argument files. Print names of changed files." + if os.path.isdir(file): + print(file, "Directory!") + return + + data = open(file, "rb").read() + if '\0' in data: + print(file, "Binary!") + return + + newdata = re.sub("\r\n", "\n", data) + if newdata != data: + print('dos2unix:', file) + f = open(file, "wb") + f.write(newdata) + f.close() + return file + else: + print(file, 'ok') + +def dos2unix_one_dir(modified_files, dir_name, file_names): + for file in file_names: + full_path = os.path.join(dir_name, file) + file = dos2unix(full_path) + if file is not None: + modified_files.append(file) + +def dos2unix_dir(dir_name): + modified_files = [] + os.path.walk(dir_name, dos2unix_one_dir, modified_files) + return modified_files +#---------------------------------- + +def unix2dos(file): + "Replace LF with CRLF in argument files. Print names of changed files." + if os.path.isdir(file): + print(file, "Directory!") + return + + data = open(file, "rb").read() + if '\0' in data: + print(file, "Binary!") + return + newdata = re.sub("\r\n", "\n", data) + newdata = re.sub("\n", "\r\n", newdata) + if newdata != data: + print('unix2dos:', file) + f = open(file, "wb") + f.write(newdata) + f.close() + return file + else: + print(file, 'ok') + +def unix2dos_one_dir(modified_files, dir_name, file_names): + for file in file_names: + full_path = os.path.join(dir_name, file) + unix2dos(full_path) + if file is not None: + modified_files.append(file) + +def unix2dos_dir(dir_name): + modified_files = [] + os.path.walk(dir_name, unix2dos_one_dir, modified_files) + return modified_files + +if __name__ == "__main__": + dos2unix_dir(sys.argv[1]) diff --git a/numpy/distutils/log.py b/numpy/distutils/log.py new file mode 100644 index 0000000..37f9fe5 --- /dev/null +++ b/numpy/distutils/log.py @@ -0,0 +1,93 @@ +# Colored log, requires Python 2.3 or up. +from __future__ import division, absolute_import, print_function + +import sys +from distutils.log import * +from distutils.log import Log as old_Log +from distutils.log import _global_log + +if sys.version_info[0] < 3: + from .misc_util import (red_text, default_text, cyan_text, green_text, + is_sequence, is_string) +else: + from numpy.distutils.misc_util import (red_text, default_text, cyan_text, + green_text, is_sequence, is_string) + + +def _fix_args(args,flag=1): + if is_string(args): + return args.replace('%', '%%') + if flag and is_sequence(args): + return tuple([_fix_args(a, flag=0) for a in args]) + return args + + +class Log(old_Log): + def _log(self, level, msg, args): + if level >= self.threshold: + if args: + msg = msg % _fix_args(args) + if 0: + if msg.startswith('copying ') and msg.find(' -> ') != -1: + return + if msg.startswith('byte-compiling '): + return + print(_global_color_map[level](msg)) + sys.stdout.flush() + + def good(self, msg, *args): + """ + If we log WARN messages, log this message as a 'nice' anti-warn + message. + + """ + if WARN >= self.threshold: + if args: + print(green_text(msg % _fix_args(args))) + else: + print(green_text(msg)) + sys.stdout.flush() + + +_global_log.__class__ = Log + +good = _global_log.good + +def set_threshold(level, force=False): + prev_level = _global_log.threshold + if prev_level > DEBUG or force: + # If we're running at DEBUG, don't change the threshold, as there's + # likely a good reason why we're running at this level. + _global_log.threshold = level + if level <= DEBUG: + info('set_threshold: setting threshold to DEBUG level,' + ' it can be changed only with force argument') + else: + info('set_threshold: not changing threshold from DEBUG level' + ' %s to %s' % (prev_level, level)) + return prev_level + + +def set_verbosity(v, force=False): + prev_level = _global_log.threshold + if v < 0: + set_threshold(ERROR, force) + elif v == 0: + set_threshold(WARN, force) + elif v == 1: + set_threshold(INFO, force) + elif v >= 2: + set_threshold(DEBUG, force) + return {FATAL:-2,ERROR:-1,WARN:0,INFO:1,DEBUG:2}.get(prev_level, 1) + + +_global_color_map = { + DEBUG:cyan_text, + INFO:default_text, + WARN:red_text, + ERROR:red_text, + FATAL:red_text +} + +# don't use INFO,.. flags in set_verbosity, these flags are for set_threshold. +set_verbosity(0, force=True) diff --git a/numpy/distutils/mingw/gfortran_vs2003_hack.c b/numpy/distutils/mingw/gfortran_vs2003_hack.c new file mode 100644 index 0000000..15ed7e6 --- /dev/null +++ b/numpy/distutils/mingw/gfortran_vs2003_hack.c @@ -0,0 +1,6 @@ +int _get_output_format(void) +{ + return 0; +} + +int _imp____lc_codepage = 0; diff --git a/numpy/distutils/mingw32ccompiler.py b/numpy/distutils/mingw32ccompiler.py new file mode 100644 index 0000000..ce9cd61 --- /dev/null +++ b/numpy/distutils/mingw32ccompiler.py @@ -0,0 +1,657 @@ +""" +Support code for building Python extensions on Windows. + + # NT stuff + # 1. Make sure libpython.a exists for gcc. If not, build it. + # 2. Force windows to use gcc (we're struggling with MSVC and g77 support) + # 3. Force windows to use g77 + +""" +from __future__ import division, absolute_import, print_function + +import os +import sys +import subprocess +import re + +# Overwrite certain distutils.ccompiler functions: +import numpy.distutils.ccompiler + +if sys.version_info[0] < 3: + from . import log +else: + from numpy.distutils import log +# NT stuff +# 1. Make sure libpython.a exists for gcc. If not, build it. +# 2. Force windows to use gcc (we're struggling with MSVC and g77 support) +# --> this is done in numpy/distutils/ccompiler.py +# 3. Force windows to use g77 + +import distutils.cygwinccompiler +from distutils.version import StrictVersion +from numpy.distutils.ccompiler import gen_preprocess_options, gen_lib_options +from distutils.unixccompiler import UnixCCompiler +from distutils.msvccompiler import get_build_version as get_build_msvc_version +from distutils.errors import (DistutilsExecError, CompileError, + UnknownFileError) +from numpy.distutils.misc_util import (msvc_runtime_library, + msvc_runtime_version, + msvc_runtime_major, + get_build_architecture) + +def get_msvcr_replacement(): + """Replacement for outdated version of get_msvcr from cygwinccompiler""" + msvcr = msvc_runtime_library() + return [] if msvcr is None else [msvcr] + +# monkey-patch cygwinccompiler with our updated version from misc_util +# to avoid getting an exception raised on Python 3.5 +distutils.cygwinccompiler.get_msvcr = get_msvcr_replacement + +# Useful to generate table of symbols from a dll +_START = re.compile(r'\[Ordinal/Name Pointer\] Table') +_TABLE = re.compile(r'^\s+\[([\s*[0-9]*)\] ([a-zA-Z0-9_]*)') + +# the same as cygwin plus some additional parameters +class Mingw32CCompiler(distutils.cygwinccompiler.CygwinCCompiler): + """ A modified MingW32 compiler compatible with an MSVC built Python. + + """ + + compiler_type = 'mingw32' + + def __init__ (self, + verbose=0, + dry_run=0, + force=0): + + distutils.cygwinccompiler.CygwinCCompiler.__init__ (self, verbose, + dry_run, force) + + # we need to support 3.2 which doesn't match the standard + # get_versions methods regex + if self.gcc_version is None: + import re + p = subprocess.Popen(['gcc', '-dumpversion'], shell=True, + stdout=subprocess.PIPE) + out_string = p.stdout.read() + p.stdout.close() + result = re.search(r'(\d+\.\d+)', out_string) + if result: + self.gcc_version = StrictVersion(result.group(1)) + + # A real mingw32 doesn't need to specify a different entry point, + # but cygwin 2.91.57 in no-cygwin-mode needs it. + if self.gcc_version <= "2.91.57": + entry_point = '--entry _DllMain@12' + else: + entry_point = '' + + if self.linker_dll == 'dllwrap': + # Commented out '--driver-name g++' part that fixes weird + # g++.exe: g++: No such file or directory + # error (mingw 1.0 in Enthon24 tree, gcc-3.4.5). + # If the --driver-name part is required for some environment + # then make the inclusion of this part specific to that + # environment. + self.linker = 'dllwrap' # --driver-name g++' + elif self.linker_dll == 'gcc': + self.linker = 'g++' + + # **changes: eric jones 4/11/01 + # 1. Check for import library on Windows. Build if it doesn't exist. + + build_import_library() + + # Check for custom msvc runtime library on Windows. Build if it doesn't exist. + msvcr_success = build_msvcr_library() + msvcr_dbg_success = build_msvcr_library(debug=True) + if msvcr_success or msvcr_dbg_success: + # add preprocessor statement for using customized msvcr lib + self.define_macro('NPY_MINGW_USE_CUSTOM_MSVCR') + + # Define the MSVC version as hint for MinGW + msvcr_version = msvc_runtime_version() + if msvcr_version: + self.define_macro('__MSVCRT_VERSION__', '0x%04i' % msvcr_version) + + # MS_WIN64 should be defined when building for amd64 on windows, + # but python headers define it only for MS compilers, which has all + # kind of bad consequences, like using Py_ModuleInit4 instead of + # Py_ModuleInit4_64, etc... So we add it here + if get_build_architecture() == 'AMD64': + if self.gcc_version < "4.0": + self.set_executables( + compiler='gcc -g -DDEBUG -DMS_WIN64 -mno-cygwin -O0 -Wall', + compiler_so='gcc -g -DDEBUG -DMS_WIN64 -mno-cygwin -O0' + ' -Wall -Wstrict-prototypes', + linker_exe='gcc -g -mno-cygwin', + linker_so='gcc -g -mno-cygwin -shared') + else: + # gcc-4 series releases do not support -mno-cygwin option + self.set_executables( + compiler='gcc -g -DDEBUG -DMS_WIN64 -O0 -Wall', + compiler_so='gcc -g -DDEBUG -DMS_WIN64 -O0 -Wall -Wstrict-prototypes', + linker_exe='gcc -g', + linker_so='gcc -g -shared') + else: + if self.gcc_version <= "3.0.0": + self.set_executables( + compiler='gcc -mno-cygwin -O2 -w', + compiler_so='gcc -mno-cygwin -mdll -O2 -w' + ' -Wstrict-prototypes', + linker_exe='g++ -mno-cygwin', + linker_so='%s -mno-cygwin -mdll -static %s' % + (self.linker, entry_point)) + elif self.gcc_version < "4.0": + self.set_executables( + compiler='gcc -mno-cygwin -O2 -Wall', + compiler_so='gcc -mno-cygwin -O2 -Wall' + ' -Wstrict-prototypes', + linker_exe='g++ -mno-cygwin', + linker_so='g++ -mno-cygwin -shared') + else: + # gcc-4 series releases do not support -mno-cygwin option + self.set_executables(compiler='gcc -O2 -Wall', + compiler_so='gcc -O2 -Wall -Wstrict-prototypes', + linker_exe='g++ ', + linker_so='g++ -shared') + # added for python2.3 support + # we can't pass it through set_executables because pre 2.2 would fail + self.compiler_cxx = ['g++'] + + # Maybe we should also append -mthreads, but then the finished dlls + # need another dll (mingwm10.dll see Mingw32 docs) (-mthreads: Support + # thread-safe exception handling on `Mingw32') + + # no additional libraries needed + #self.dll_libraries=[] + return + + # __init__ () + + def link(self, + target_desc, + objects, + output_filename, + output_dir, + libraries, + library_dirs, + runtime_library_dirs, + export_symbols = None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None): + # Include the appropriate MSVC runtime library if Python was built + # with MSVC >= 7.0 (MinGW standard is msvcrt) + runtime_library = msvc_runtime_library() + if runtime_library: + if not libraries: + libraries = [] + libraries.append(runtime_library) + args = (self, + target_desc, + objects, + output_filename, + output_dir, + libraries, + library_dirs, + runtime_library_dirs, + None, #export_symbols, we do this in our def-file + debug, + extra_preargs, + extra_postargs, + build_temp, + target_lang) + if self.gcc_version < "3.0.0": + func = distutils.cygwinccompiler.CygwinCCompiler.link + else: + func = UnixCCompiler.link + func(*args[:func.__code__.co_argcount]) + return + + def object_filenames (self, + source_filenames, + strip_dir=0, + output_dir=''): + if output_dir is None: output_dir = '' + obj_names = [] + for src_name in source_filenames: + # use normcase to make sure '.rc' is really '.rc' and not '.RC' + (base, ext) = os.path.splitext (os.path.normcase(src_name)) + + # added these lines to strip off windows drive letters + # without it, .o files are placed next to .c files + # instead of the build directory + drv, base = os.path.splitdrive(base) + if drv: + base = base[1:] + + if ext not in (self.src_extensions + ['.rc', '.res']): + raise UnknownFileError( + "unknown file type '%s' (from '%s')" % \ + (ext, src_name)) + if strip_dir: + base = os.path.basename (base) + if ext == '.res' or ext == '.rc': + # these need to be compiled to object files + obj_names.append (os.path.join (output_dir, + base + ext + self.obj_extension)) + else: + obj_names.append (os.path.join (output_dir, + base + self.obj_extension)) + return obj_names + + # object_filenames () + + +def find_python_dll(): + # We can't do much here: + # - find it in the virtualenv (sys.prefix) + # - find it in python main dir (sys.base_prefix, if in a virtualenv) + # - sys.real_prefix is main dir for virtualenvs in Python 2.7 + # - in system32, + # - ortherwise (Sxs), I don't know how to get it. + stems = [sys.prefix] + if hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix: + stems.append(sys.base_prefix) + elif hasattr(sys, 'real_prefix') and sys.real_prefix != sys.prefix: + stems.append(sys.real_prefix) + + sub_dirs = ['', 'lib', 'bin'] + # generate possible combinations of directory trees and sub-directories + lib_dirs = [] + for stem in stems: + for folder in sub_dirs: + lib_dirs.append(os.path.join(stem, folder)) + + # add system directory as well + if 'SYSTEMROOT' in os.environ: + lib_dirs.append(os.path.join(os.environ['SYSTEMROOT'], 'System32')) + + # search in the file system for possible candidates + major_version, minor_version = tuple(sys.version_info[:2]) + patterns = ['python%d%d.dll'] + + for pat in patterns: + dllname = pat % (major_version, minor_version) + print("Looking for %s" % dllname) + for folder in lib_dirs: + dll = os.path.join(folder, dllname) + if os.path.exists(dll): + return dll + + raise ValueError("%s not found in %s" % (dllname, lib_dirs)) + +def dump_table(dll): + st = subprocess.Popen(["objdump.exe", "-p", dll], stdout=subprocess.PIPE) + return st.stdout.readlines() + +def generate_def(dll, dfile): + """Given a dll file location, get all its exported symbols and dump them + into the given def file. + + The .def file will be overwritten""" + dump = dump_table(dll) + for i in range(len(dump)): + if _START.match(dump[i].decode()): + break + else: + raise ValueError("Symbol table not found") + + syms = [] + for j in range(i+1, len(dump)): + m = _TABLE.match(dump[j].decode()) + if m: + syms.append((int(m.group(1).strip()), m.group(2))) + else: + break + + if len(syms) == 0: + log.warn('No symbols found in %s' % dll) + + d = open(dfile, 'w') + d.write('LIBRARY %s\n' % os.path.basename(dll)) + d.write(';CODE PRELOAD MOVEABLE DISCARDABLE\n') + d.write(';DATA PRELOAD SINGLE\n') + d.write('\nEXPORTS\n') + for s in syms: + #d.write('@%d %s\n' % (s[0], s[1])) + d.write('%s\n' % s[1]) + d.close() + +def find_dll(dll_name): + + arch = {'AMD64' : 'amd64', + 'Intel' : 'x86'}[get_build_architecture()] + + def _find_dll_in_winsxs(dll_name): + # Walk through the WinSxS directory to find the dll. + winsxs_path = os.path.join(os.environ.get('WINDIR', r'C:\WINDOWS'), + 'winsxs') + if not os.path.exists(winsxs_path): + return None + for root, dirs, files in os.walk(winsxs_path): + if dll_name in files and arch in root: + return os.path.join(root, dll_name) + return None + + def _find_dll_in_path(dll_name): + # First, look in the Python directory, then scan PATH for + # the given dll name. + for path in [sys.prefix] + os.environ['PATH'].split(';'): + filepath = os.path.join(path, dll_name) + if os.path.exists(filepath): + return os.path.abspath(filepath) + + return _find_dll_in_winsxs(dll_name) or _find_dll_in_path(dll_name) + +def build_msvcr_library(debug=False): + if os.name != 'nt': + return False + + # If the version number is None, then we couldn't find the MSVC runtime at + # all, because we are running on a Python distribution which is customed + # compiled; trust that the compiler is the same as the one available to us + # now, and that it is capable of linking with the correct runtime without + # any extra options. + msvcr_ver = msvc_runtime_major() + if msvcr_ver is None: + log.debug('Skip building import library: ' + 'Runtime is not compiled with MSVC') + return False + + # Skip using a custom library for versions < MSVC 8.0 + if msvcr_ver < 80: + log.debug('Skip building msvcr library:' + ' custom functionality not present') + return False + + msvcr_name = msvc_runtime_library() + if debug: + msvcr_name += 'd' + + # Skip if custom library already exists + out_name = "lib%s.a" % msvcr_name + out_file = os.path.join(sys.prefix, 'libs', out_name) + if os.path.isfile(out_file): + log.debug('Skip building msvcr library: "%s" exists' % + (out_file,)) + return True + + # Find the msvcr dll + msvcr_dll_name = msvcr_name + '.dll' + dll_file = find_dll(msvcr_dll_name) + if not dll_file: + log.warn('Cannot build msvcr library: "%s" not found' % + msvcr_dll_name) + return False + + def_name = "lib%s.def" % msvcr_name + def_file = os.path.join(sys.prefix, 'libs', def_name) + + log.info('Building msvcr library: "%s" (from %s)' \ + % (out_file, dll_file)) + + # Generate a symbol definition file from the msvcr dll + generate_def(dll_file, def_file) + + # Create a custom mingw library for the given symbol definitions + cmd = ['dlltool', '-d', def_file, '-l', out_file] + retcode = subprocess.call(cmd) + + # Clean up symbol definitions + os.remove(def_file) + + return (not retcode) + +def build_import_library(): + if os.name != 'nt': + return + + arch = get_build_architecture() + if arch == 'AMD64': + return _build_import_library_amd64() + elif arch == 'Intel': + return _build_import_library_x86() + else: + raise ValueError("Unhandled arch %s" % arch) + +def _check_for_import_lib(): + """Check if an import library for the Python runtime already exists.""" + major_version, minor_version = tuple(sys.version_info[:2]) + + # patterns for the file name of the library itself + patterns = ['libpython%d%d.a', + 'libpython%d%d.dll.a', + 'libpython%d.%d.dll.a'] + + # directory trees that may contain the library + stems = [sys.prefix] + if hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix: + stems.append(sys.base_prefix) + elif hasattr(sys, 'real_prefix') and sys.real_prefix != sys.prefix: + stems.append(sys.real_prefix) + + # possible subdirectories within those trees where it is placed + sub_dirs = ['libs', 'lib'] + + # generate a list of candidate locations + candidates = [] + for pat in patterns: + filename = pat % (major_version, minor_version) + for stem_dir in stems: + for folder in sub_dirs: + candidates.append(os.path.join(stem_dir, folder, filename)) + + # test the filesystem to see if we can find any of these + for fullname in candidates: + if os.path.isfile(fullname): + # already exists, in location given + return (True, fullname) + + # needs to be built, preferred location given first + return (False, candidates[0]) + +def _build_import_library_amd64(): + out_exists, out_file = _check_for_import_lib() + if out_exists: + log.debug('Skip building import library: "%s" exists', out_file) + return + + # get the runtime dll for which we are building import library + dll_file = find_python_dll() + log.info('Building import library (arch=AMD64): "%s" (from %s)' % + (out_file, dll_file)) + + # generate symbol list from this library + def_name = "python%d%d.def" % tuple(sys.version_info[:2]) + def_file = os.path.join(sys.prefix, 'libs', def_name) + generate_def(dll_file, def_file) + + # generate import library from this symbol list + cmd = ['dlltool', '-d', def_file, '-l', out_file] + subprocess.Popen(cmd) + +def _build_import_library_x86(): + """ Build the import libraries for Mingw32-gcc on Windows + """ + out_exists, out_file = _check_for_import_lib() + if out_exists: + log.debug('Skip building import library: "%s" exists', out_file) + return + + lib_name = "python%d%d.lib" % tuple(sys.version_info[:2]) + lib_file = os.path.join(sys.prefix, 'libs', lib_name) + if not os.path.isfile(lib_file): + # didn't find library file in virtualenv, try base distribution, too, + # and use that instead if found there. for Python 2.7 venvs, the base + # directory is in attribute real_prefix instead of base_prefix. + if hasattr(sys, 'base_prefix'): + base_lib = os.path.join(sys.base_prefix, 'libs', lib_name) + elif hasattr(sys, 'real_prefix'): + base_lib = os.path.join(sys.real_prefix, 'libs', lib_name) + else: + base_lib = '' # os.path.isfile('') == False + + if os.path.isfile(base_lib): + lib_file = base_lib + else: + log.warn('Cannot build import library: "%s" not found', lib_file) + return + log.info('Building import library (ARCH=x86): "%s"', out_file) + + from numpy.distutils import lib2def + + def_name = "python%d%d.def" % tuple(sys.version_info[:2]) + def_file = os.path.join(sys.prefix, 'libs', def_name) + nm_cmd = '%s %s' % (lib2def.DEFAULT_NM, lib_file) + nm_output = lib2def.getnm(nm_cmd) + dlist, flist = lib2def.parse_nm(nm_output) + lib2def.output_def(dlist, flist, lib2def.DEF_HEADER, open(def_file, 'w')) + + dll_name = find_python_dll () + args = (dll_name, def_file, out_file) + cmd = 'dlltool --dllname "%s" --def "%s" --output-lib "%s"' % args + status = os.system(cmd) + # for now, fail silently + if status: + log.warn('Failed to build import library for gcc. Linking will fail.') + return + +#===================================== +# Dealing with Visual Studio MANIFESTS +#===================================== + +# Functions to deal with visual studio manifests. Manifest are a mechanism to +# enforce strong DLL versioning on windows, and has nothing to do with +# distutils MANIFEST. manifests are XML files with version info, and used by +# the OS loader; they are necessary when linking against a DLL not in the +# system path; in particular, official python 2.6 binary is built against the +# MS runtime 9 (the one from VS 2008), which is not available on most windows +# systems; python 2.6 installer does install it in the Win SxS (Side by side) +# directory, but this requires the manifest for this to work. This is a big +# mess, thanks MS for a wonderful system. + +# XXX: ideally, we should use exactly the same version as used by python. I +# submitted a patch to get this version, but it was only included for python +# 2.6.1 and above. So for versions below, we use a "best guess". +_MSVCRVER_TO_FULLVER = {} +if sys.platform == 'win32': + try: + import msvcrt + # I took one version in my SxS directory: no idea if it is the good + # one, and we can't retrieve it from python + _MSVCRVER_TO_FULLVER['80'] = "8.0.50727.42" + _MSVCRVER_TO_FULLVER['90'] = "9.0.21022.8" + # Value from msvcrt.CRT_ASSEMBLY_VERSION under Python 3.3.0 + # on Windows XP: + _MSVCRVER_TO_FULLVER['100'] = "10.0.30319.460" + if hasattr(msvcrt, "CRT_ASSEMBLY_VERSION"): + major, minor, rest = msvcrt.CRT_ASSEMBLY_VERSION.split(".", 2) + _MSVCRVER_TO_FULLVER[major + minor] = msvcrt.CRT_ASSEMBLY_VERSION + del major, minor, rest + except ImportError: + # If we are here, means python was not built with MSVC. Not sure what + # to do in that case: manifest building will fail, but it should not be + # used in that case anyway + log.warn('Cannot import msvcrt: using manifest will not be possible') + +def msvc_manifest_xml(maj, min): + """Given a major and minor version of the MSVCR, returns the + corresponding XML file.""" + try: + fullver = _MSVCRVER_TO_FULLVER[str(maj * 10 + min)] + except KeyError: + raise ValueError("Version %d,%d of MSVCRT not supported yet" % + (maj, min)) + # Don't be fooled, it looks like an XML, but it is not. In particular, it + # should not have any space before starting, and its size should be + # divisible by 4, most likely for alignement constraints when the xml is + # embedded in the binary... + # This template was copied directly from the python 2.6 binary (using + # strings.exe from mingw on python.exe). + template = """\ + + + + + + + + + + + + + +""" + + return template % {'fullver': fullver, 'maj': maj, 'min': min} + +def manifest_rc(name, type='dll'): + """Return the rc file used to generate the res file which will be embedded + as manifest for given manifest file name, of given type ('dll' or + 'exe'). + + Parameters + ---------- + name : str + name of the manifest file to embed + type : str {'dll', 'exe'} + type of the binary which will embed the manifest + + """ + if type == 'dll': + rctype = 2 + elif type == 'exe': + rctype = 1 + else: + raise ValueError("Type %s not supported" % type) + + return """\ +#include "winuser.h" +%d RT_MANIFEST %s""" % (rctype, name) + +def check_embedded_msvcr_match_linked(msver): + """msver is the ms runtime version used for the MANIFEST.""" + # check msvcr major version are the same for linking and + # embedding + maj = msvc_runtime_major() + if maj: + if not maj == int(msver): + raise ValueError( + "Discrepancy between linked msvcr " \ + "(%d) and the one about to be embedded " \ + "(%d)" % (int(msver), maj)) + +def configtest_name(config): + base = os.path.basename(config._gen_temp_sourcefile("yo", [], "c")) + return os.path.splitext(base)[0] + +def manifest_name(config): + # Get configest name (including suffix) + root = configtest_name(config) + exext = config.compiler.exe_extension + return root + exext + ".manifest" + +def rc_name(config): + # Get configtest name (including suffix) + root = configtest_name(config) + return root + ".rc" + +def generate_manifest(config): + msver = get_build_msvc_version() + if msver is not None: + if msver >= 8: + check_embedded_msvcr_match_linked(msver) + ma = int(msver) + mi = int((msver - ma) * 10) + # Write the manifest file + manxml = msvc_manifest_xml(ma, mi) + man = open(manifest_name(config), "w") + config.temp_files.append(manifest_name(config)) + man.write(manxml) + man.close() diff --git a/numpy/distutils/misc_util.py b/numpy/distutils/misc_util.py new file mode 100644 index 0000000..d6c284a --- /dev/null +++ b/numpy/distutils/misc_util.py @@ -0,0 +1,2325 @@ +from __future__ import division, absolute_import, print_function + +import os +import re +import sys +import copy +import glob +import atexit +import tempfile +import subprocess +import shutil + +import distutils +from distutils.errors import DistutilsError +from distutils.msvccompiler import get_build_architecture +try: + from threading import local as tlocal +except ImportError: + from dummy_threading import local as tlocal + +# stores temporary directory of each thread to only create one per thread +_tdata = tlocal() + +# store all created temporary directories so they can be deleted on exit +_tmpdirs = [] +def clean_up_temporary_directory(): + if _tmpdirs is not None: + for d in _tmpdirs: + try: + shutil.rmtree(d) + except OSError: + pass + +atexit.register(clean_up_temporary_directory) + +from numpy.distutils.compat import get_exception +from numpy.compat import basestring +from numpy.compat import npy_load_module + +__all__ = ['Configuration', 'get_numpy_include_dirs', 'default_config_dict', + 'dict_append', 'appendpath', 'generate_config_py', + 'get_cmd', 'allpath', 'get_mathlibs', + 'terminal_has_colors', 'red_text', 'green_text', 'yellow_text', + 'blue_text', 'cyan_text', 'cyg2win32', 'mingw32', 'all_strings', + 'has_f_sources', 'has_cxx_sources', 'filter_sources', + 'get_dependencies', 'is_local_src_dir', 'get_ext_source_files', + 'get_script_files', 'get_lib_source_files', 'get_data_files', + 'dot_join', 'get_frame', 'minrelpath', 'njoin', + 'is_sequence', 'is_string', 'as_list', 'gpaths', 'get_language', + 'quote_args', 'get_build_architecture', 'get_info', 'get_pkg_info', + 'get_num_build_jobs'] + +class InstallableLib(object): + """ + Container to hold information on an installable library. + + Parameters + ---------- + name : str + Name of the installed library. + build_info : dict + Dictionary holding build information. + target_dir : str + Absolute path specifying where to install the library. + + See Also + -------- + Configuration.add_installed_library + + Notes + ----- + The three parameters are stored as attributes with the same names. + + """ + def __init__(self, name, build_info, target_dir): + self.name = name + self.build_info = build_info + self.target_dir = target_dir + + +def get_num_build_jobs(): + """ + Get number of parallel build jobs set by the --parallel command line + argument of setup.py + If the command did not receive a setting the environment variable + NPY_NUM_BUILD_JOBS checked and if that is unset it returns 1. + + Returns + ------- + out : int + number of parallel jobs that can be run + + """ + from numpy.distutils.core import get_distribution + envjobs = int(os.environ.get("NPY_NUM_BUILD_JOBS", 1)) + dist = get_distribution() + # may be None during configuration + if dist is None: + return envjobs + + # any of these three may have the job set, take the largest + cmdattr = (getattr(dist.get_command_obj('build'), 'parallel', None), + getattr(dist.get_command_obj('build_ext'), 'parallel', None), + getattr(dist.get_command_obj('build_clib'), 'parallel', None)) + if all(x is None for x in cmdattr): + return envjobs + else: + return max(x for x in cmdattr if x is not None) + +def quote_args(args): + # don't used _nt_quote_args as it does not check if + # args items already have quotes or not. + args = list(args) + for i in range(len(args)): + a = args[i] + if ' ' in a and a[0] not in '"\'': + args[i] = '"%s"' % (a) + return args + +def allpath(name): + "Convert a /-separated pathname to one using the OS's path separator." + splitted = name.split('/') + return os.path.join(*splitted) + +def rel_path(path, parent_path): + """Return path relative to parent_path.""" + # Use realpath to avoid issues with symlinked dirs (see gh-7707) + pd = os.path.realpath(os.path.abspath(parent_path)) + apath = os.path.realpath(os.path.abspath(path)) + if len(apath) < len(pd): + return path + if apath == pd: + return '' + if pd == apath[:len(pd)]: + assert apath[len(pd)] in [os.sep], repr((path, apath[len(pd)])) + path = apath[len(pd)+1:] + return path + +def get_path_from_frame(frame, parent_path=None): + """Return path of the module given a frame object from the call stack. + + Returned path is relative to parent_path when given, + otherwise it is absolute path. + """ + + # First, try to find if the file name is in the frame. + try: + caller_file = eval('__file__', frame.f_globals, frame.f_locals) + d = os.path.dirname(os.path.abspath(caller_file)) + except NameError: + # __file__ is not defined, so let's try __name__. We try this second + # because setuptools spoofs __name__ to be '__main__' even though + # sys.modules['__main__'] might be something else, like easy_install(1). + caller_name = eval('__name__', frame.f_globals, frame.f_locals) + __import__(caller_name) + mod = sys.modules[caller_name] + if hasattr(mod, '__file__'): + d = os.path.dirname(os.path.abspath(mod.__file__)) + else: + # we're probably running setup.py as execfile("setup.py") + # (likely we're building an egg) + d = os.path.abspath('.') + # hmm, should we use sys.argv[0] like in __builtin__ case? + + if parent_path is not None: + d = rel_path(d, parent_path) + + return d or '.' + +def njoin(*path): + """Join two or more pathname components + + - convert a /-separated pathname to one using the OS's path separator. + - resolve `..` and `.` from path. + + Either passing n arguments as in njoin('a','b'), or a sequence + of n names as in njoin(['a','b']) is handled, or a mixture of such arguments. + """ + paths = [] + for p in path: + if is_sequence(p): + # njoin(['a', 'b'], 'c') + paths.append(njoin(*p)) + else: + assert is_string(p) + paths.append(p) + path = paths + if not path: + # njoin() + joined = '' + else: + # njoin('a', 'b') + joined = os.path.join(*path) + if os.path.sep != '/': + joined = joined.replace('/', os.path.sep) + return minrelpath(joined) + +def get_mathlibs(path=None): + """Return the MATHLIB line from numpyconfig.h + """ + if path is not None: + config_file = os.path.join(path, '_numpyconfig.h') + else: + # Look for the file in each of the numpy include directories. + dirs = get_numpy_include_dirs() + for path in dirs: + fn = os.path.join(path, '_numpyconfig.h') + if os.path.exists(fn): + config_file = fn + break + else: + raise DistutilsError('_numpyconfig.h not found in numpy include ' + 'dirs %r' % (dirs,)) + + fid = open(config_file) + mathlibs = [] + s = '#define MATHLIB' + for line in fid: + if line.startswith(s): + value = line[len(s):].strip() + if value: + mathlibs.extend(value.split(',')) + fid.close() + return mathlibs + +def minrelpath(path): + """Resolve `..` and '.' from path. + """ + if not is_string(path): + return path + if '.' not in path: + return path + l = path.split(os.sep) + while l: + try: + i = l.index('.', 1) + except ValueError: + break + del l[i] + j = 1 + while l: + try: + i = l.index('..', j) + except ValueError: + break + if l[i-1]=='..': + j += 1 + else: + del l[i], l[i-1] + j = 1 + if not l: + return '' + return os.sep.join(l) + +def _fix_paths(paths, local_path, include_non_existing): + assert is_sequence(paths), repr(type(paths)) + new_paths = [] + assert not is_string(paths), repr(paths) + for n in paths: + if is_string(n): + if '*' in n or '?' in n: + p = glob.glob(n) + p2 = glob.glob(njoin(local_path, n)) + if p2: + new_paths.extend(p2) + elif p: + new_paths.extend(p) + else: + if include_non_existing: + new_paths.append(n) + print('could not resolve pattern in %r: %r' % + (local_path, n)) + else: + n2 = njoin(local_path, n) + if os.path.exists(n2): + new_paths.append(n2) + else: + if os.path.exists(n): + new_paths.append(n) + elif include_non_existing: + new_paths.append(n) + if not os.path.exists(n): + print('non-existing path in %r: %r' % + (local_path, n)) + + elif is_sequence(n): + new_paths.extend(_fix_paths(n, local_path, include_non_existing)) + else: + new_paths.append(n) + return [minrelpath(p) for p in new_paths] + +def gpaths(paths, local_path='', include_non_existing=True): + """Apply glob to paths and prepend local_path if needed. + """ + if is_string(paths): + paths = (paths,) + return _fix_paths(paths, local_path, include_non_existing) + +def make_temp_file(suffix='', prefix='', text=True): + if not hasattr(_tdata, 'tempdir'): + _tdata.tempdir = tempfile.mkdtemp() + _tmpdirs.append(_tdata.tempdir) + fid, name = tempfile.mkstemp(suffix=suffix, + prefix=prefix, + dir=_tdata.tempdir, + text=text) + fo = os.fdopen(fid, 'w') + return fo, name + +# Hooks for colored terminal output. +# See also http://www.livinglogic.de/Python/ansistyle +def terminal_has_colors(): + if sys.platform=='cygwin' and 'USE_COLOR' not in os.environ: + # Avoid importing curses that causes illegal operation + # with a message: + # PYTHON2 caused an invalid page fault in + # module CYGNURSES7.DLL as 015f:18bbfc28 + # Details: Python 2.3.3 [GCC 3.3.1 (cygming special)] + # ssh to Win32 machine from debian + # curses.version is 2.2 + # CYGWIN_98-4.10, release 1.5.7(0.109/3/2)) + return 0 + if hasattr(sys.stdout, 'isatty') and sys.stdout.isatty(): + try: + import curses + curses.setupterm() + if (curses.tigetnum("colors") >= 0 + and curses.tigetnum("pairs") >= 0 + and ((curses.tigetstr("setf") is not None + and curses.tigetstr("setb") is not None) + or (curses.tigetstr("setaf") is not None + and curses.tigetstr("setab") is not None) + or curses.tigetstr("scp") is not None)): + return 1 + except Exception: + pass + return 0 + +if terminal_has_colors(): + _colour_codes = dict(black=0, red=1, green=2, yellow=3, + blue=4, magenta=5, cyan=6, white=7, default=9) + def colour_text(s, fg=None, bg=None, bold=False): + seq = [] + if bold: + seq.append('1') + if fg: + fgcode = 30 + _colour_codes.get(fg.lower(), 0) + seq.append(str(fgcode)) + if bg: + bgcode = 40 + _colour_codes.get(fg.lower(), 7) + seq.append(str(bgcode)) + if seq: + return '\x1b[%sm%s\x1b[0m' % (';'.join(seq), s) + else: + return s +else: + def colour_text(s, fg=None, bg=None): + return s + +def default_text(s): + return colour_text(s, 'default') +def red_text(s): + return colour_text(s, 'red') +def green_text(s): + return colour_text(s, 'green') +def yellow_text(s): + return colour_text(s, 'yellow') +def cyan_text(s): + return colour_text(s, 'cyan') +def blue_text(s): + return colour_text(s, 'blue') + +######################### + +def cyg2win32(path): + if sys.platform=='cygwin' and path.startswith('/cygdrive'): + path = path[10] + ':' + os.path.normcase(path[11:]) + return path + +def mingw32(): + """Return true when using mingw32 environment. + """ + if sys.platform=='win32': + if os.environ.get('OSTYPE', '')=='msys': + return True + if os.environ.get('MSYSTEM', '')=='MINGW32': + return True + return False + +def msvc_runtime_version(): + "Return version of MSVC runtime library, as defined by __MSC_VER__ macro" + msc_pos = sys.version.find('MSC v.') + if msc_pos != -1: + msc_ver = int(sys.version[msc_pos+6:msc_pos+10]) + else: + msc_ver = None + return msc_ver + +def msvc_runtime_library(): + "Return name of MSVC runtime library if Python was built with MSVC >= 7" + ver = msvc_runtime_major () + if ver: + if ver < 140: + return "msvcr%i" % ver + else: + return "vcruntime%i" % ver + else: + return None + +def msvc_runtime_major(): + "Return major version of MSVC runtime coded like get_build_msvc_version" + major = {1300: 70, # MSVC 7.0 + 1310: 71, # MSVC 7.1 + 1400: 80, # MSVC 8 + 1500: 90, # MSVC 9 (aka 2008) + 1600: 100, # MSVC 10 (aka 2010) + 1900: 140, # MSVC 14 (aka 2015) + }.get(msvc_runtime_version(), None) + return major + +######################### + +#XXX need support for .C that is also C++ +cxx_ext_match = re.compile(r'.*[.](cpp|cxx|cc)\Z', re.I).match +fortran_ext_match = re.compile(r'.*[.](f90|f95|f77|for|ftn|f)\Z', re.I).match +f90_ext_match = re.compile(r'.*[.](f90|f95)\Z', re.I).match +f90_module_name_match = re.compile(r'\s*module\s*(?P[\w_]+)', re.I).match +def _get_f90_modules(source): + """Return a list of Fortran f90 module names that + given source file defines. + """ + if not f90_ext_match(source): + return [] + modules = [] + f = open(source, 'r') + for line in f: + m = f90_module_name_match(line) + if m: + name = m.group('name') + modules.append(name) + # break # XXX can we assume that there is one module per file? + f.close() + return modules + +def is_string(s): + return isinstance(s, basestring) + +def all_strings(lst): + """Return True if all items in lst are string objects. """ + for item in lst: + if not is_string(item): + return False + return True + +def is_sequence(seq): + if is_string(seq): + return False + try: + len(seq) + except Exception: + return False + return True + +def is_glob_pattern(s): + return is_string(s) and ('*' in s or '?' is s) + +def as_list(seq): + if is_sequence(seq): + return list(seq) + else: + return [seq] + +def get_language(sources): + # not used in numpy/scipy packages, use build_ext.detect_language instead + """Determine language value (c,f77,f90) from sources """ + language = None + for source in sources: + if isinstance(source, str): + if f90_ext_match(source): + language = 'f90' + break + elif fortran_ext_match(source): + language = 'f77' + return language + +def has_f_sources(sources): + """Return True if sources contains Fortran files """ + for source in sources: + if fortran_ext_match(source): + return True + return False + +def has_cxx_sources(sources): + """Return True if sources contains C++ files """ + for source in sources: + if cxx_ext_match(source): + return True + return False + +def filter_sources(sources): + """Return four lists of filenames containing + C, C++, Fortran, and Fortran 90 module sources, + respectively. + """ + c_sources = [] + cxx_sources = [] + f_sources = [] + fmodule_sources = [] + for source in sources: + if fortran_ext_match(source): + modules = _get_f90_modules(source) + if modules: + fmodule_sources.append(source) + else: + f_sources.append(source) + elif cxx_ext_match(source): + cxx_sources.append(source) + else: + c_sources.append(source) + return c_sources, cxx_sources, f_sources, fmodule_sources + + +def _get_headers(directory_list): + # get *.h files from list of directories + headers = [] + for d in directory_list: + head = glob.glob(os.path.join(d, "*.h")) #XXX: *.hpp files?? + headers.extend(head) + return headers + +def _get_directories(list_of_sources): + # get unique directories from list of sources. + direcs = [] + for f in list_of_sources: + d = os.path.split(f) + if d[0] != '' and not d[0] in direcs: + direcs.append(d[0]) + return direcs + +def _commandline_dep_string(cc_args, extra_postargs, pp_opts): + """ + Return commandline representation used to determine if a file needs + to be recompiled + """ + cmdline = 'commandline: ' + cmdline += ' '.join(cc_args) + cmdline += ' '.join(extra_postargs) + cmdline += ' '.join(pp_opts) + '\n' + return cmdline + + +def get_dependencies(sources): + #XXX scan sources for include statements + return _get_headers(_get_directories(sources)) + +def is_local_src_dir(directory): + """Return true if directory is local directory. + """ + if not is_string(directory): + return False + abs_dir = os.path.abspath(directory) + c = os.path.commonprefix([os.getcwd(), abs_dir]) + new_dir = abs_dir[len(c):].split(os.sep) + if new_dir and not new_dir[0]: + new_dir = new_dir[1:] + if new_dir and new_dir[0]=='build': + return False + new_dir = os.sep.join(new_dir) + return os.path.isdir(new_dir) + +def general_source_files(top_path): + pruned_directories = {'CVS':1, '.svn':1, 'build':1} + prune_file_pat = re.compile(r'(?:[~#]|\.py[co]|\.o)$') + for dirpath, dirnames, filenames in os.walk(top_path, topdown=True): + pruned = [ d for d in dirnames if d not in pruned_directories ] + dirnames[:] = pruned + for f in filenames: + if not prune_file_pat.search(f): + yield os.path.join(dirpath, f) + +def general_source_directories_files(top_path): + """Return a directory name relative to top_path and + files contained. + """ + pruned_directories = ['CVS', '.svn', 'build'] + prune_file_pat = re.compile(r'(?:[~#]|\.py[co]|\.o)$') + for dirpath, dirnames, filenames in os.walk(top_path, topdown=True): + pruned = [ d for d in dirnames if d not in pruned_directories ] + dirnames[:] = pruned + for d in dirnames: + dpath = os.path.join(dirpath, d) + rpath = rel_path(dpath, top_path) + files = [] + for f in os.listdir(dpath): + fn = os.path.join(dpath, f) + if os.path.isfile(fn) and not prune_file_pat.search(fn): + files.append(fn) + yield rpath, files + dpath = top_path + rpath = rel_path(dpath, top_path) + filenames = [os.path.join(dpath, f) for f in os.listdir(dpath) \ + if not prune_file_pat.search(f)] + files = [f for f in filenames if os.path.isfile(f)] + yield rpath, files + + +def get_ext_source_files(ext): + # Get sources and any include files in the same directory. + filenames = [] + sources = [_m for _m in ext.sources if is_string(_m)] + filenames.extend(sources) + filenames.extend(get_dependencies(sources)) + for d in ext.depends: + if is_local_src_dir(d): + filenames.extend(list(general_source_files(d))) + elif os.path.isfile(d): + filenames.append(d) + return filenames + +def get_script_files(scripts): + scripts = [_m for _m in scripts if is_string(_m)] + return scripts + +def get_lib_source_files(lib): + filenames = [] + sources = lib[1].get('sources', []) + sources = [_m for _m in sources if is_string(_m)] + filenames.extend(sources) + filenames.extend(get_dependencies(sources)) + depends = lib[1].get('depends', []) + for d in depends: + if is_local_src_dir(d): + filenames.extend(list(general_source_files(d))) + elif os.path.isfile(d): + filenames.append(d) + return filenames + +def get_shared_lib_extension(is_python_ext=False): + """Return the correct file extension for shared libraries. + + Parameters + ---------- + is_python_ext : bool, optional + Whether the shared library is a Python extension. Default is False. + + Returns + ------- + so_ext : str + The shared library extension. + + Notes + ----- + For Python shared libs, `so_ext` will typically be '.so' on Linux and OS X, + and '.pyd' on Windows. For Python >= 3.2 `so_ext` has a tag prepended on + POSIX systems according to PEP 3149. For Python 3.2 this is implemented on + Linux, but not on OS X. + + """ + confvars = distutils.sysconfig.get_config_vars() + # SO is deprecated in 3.3.1, use EXT_SUFFIX instead + so_ext = confvars.get('EXT_SUFFIX', None) + if so_ext is None: + so_ext = confvars.get('SO', '') + + if not is_python_ext: + # hardcode known values, config vars (including SHLIB_SUFFIX) are + # unreliable (see #3182) + # darwin, windows and debug linux are wrong in 3.3.1 and older + if (sys.platform.startswith('linux') or + sys.platform.startswith('gnukfreebsd')): + so_ext = '.so' + elif sys.platform.startswith('darwin'): + so_ext = '.dylib' + elif sys.platform.startswith('win'): + so_ext = '.dll' + else: + # fall back to config vars for unknown platforms + # fix long extension for Python >=3.2, see PEP 3149. + if 'SOABI' in confvars: + # Does nothing unless SOABI config var exists + so_ext = so_ext.replace('.' + confvars.get('SOABI'), '', 1) + + return so_ext + +def get_data_files(data): + if is_string(data): + return [data] + sources = data[1] + filenames = [] + for s in sources: + if hasattr(s, '__call__'): + continue + if is_local_src_dir(s): + filenames.extend(list(general_source_files(s))) + elif is_string(s): + if os.path.isfile(s): + filenames.append(s) + else: + print('Not existing data file:', s) + else: + raise TypeError(repr(s)) + return filenames + +def dot_join(*args): + return '.'.join([a for a in args if a]) + +def get_frame(level=0): + """Return frame object from call stack with given level. + """ + try: + return sys._getframe(level+1) + except AttributeError: + frame = sys.exc_info()[2].tb_frame + for _ in range(level+1): + frame = frame.f_back + return frame + + +###################### + +class Configuration(object): + + _list_keys = ['packages', 'ext_modules', 'data_files', 'include_dirs', + 'libraries', 'headers', 'scripts', 'py_modules', + 'installed_libraries', 'define_macros'] + _dict_keys = ['package_dir', 'installed_pkg_config'] + _extra_keys = ['name', 'version'] + + numpy_include_dirs = [] + + def __init__(self, + package_name=None, + parent_name=None, + top_path=None, + package_path=None, + caller_level=1, + setup_name='setup.py', + **attrs): + """Construct configuration instance of a package. + + package_name -- name of the package + Ex.: 'distutils' + parent_name -- name of the parent package + Ex.: 'numpy' + top_path -- directory of the toplevel package + Ex.: the directory where the numpy package source sits + package_path -- directory of package. Will be computed by magic from the + directory of the caller module if not specified + Ex.: the directory where numpy.distutils is + caller_level -- frame level to caller namespace, internal parameter. + """ + self.name = dot_join(parent_name, package_name) + self.version = None + + caller_frame = get_frame(caller_level) + self.local_path = get_path_from_frame(caller_frame, top_path) + # local_path -- directory of a file (usually setup.py) that + # defines a configuration() function. + # local_path -- directory of a file (usually setup.py) that + # defines a configuration() function. + if top_path is None: + top_path = self.local_path + self.local_path = '' + if package_path is None: + package_path = self.local_path + elif os.path.isdir(njoin(self.local_path, package_path)): + package_path = njoin(self.local_path, package_path) + if not os.path.isdir(package_path or '.'): + raise ValueError("%r is not a directory" % (package_path,)) + self.top_path = top_path + self.package_path = package_path + # this is the relative path in the installed package + self.path_in_package = os.path.join(*self.name.split('.')) + + self.list_keys = self._list_keys[:] + self.dict_keys = self._dict_keys[:] + + for n in self.list_keys: + v = copy.copy(attrs.get(n, [])) + setattr(self, n, as_list(v)) + + for n in self.dict_keys: + v = copy.copy(attrs.get(n, {})) + setattr(self, n, v) + + known_keys = self.list_keys + self.dict_keys + self.extra_keys = self._extra_keys[:] + for n in attrs.keys(): + if n in known_keys: + continue + a = attrs[n] + setattr(self, n, a) + if isinstance(a, list): + self.list_keys.append(n) + elif isinstance(a, dict): + self.dict_keys.append(n) + else: + self.extra_keys.append(n) + + if os.path.exists(njoin(package_path, '__init__.py')): + self.packages.append(self.name) + self.package_dir[self.name] = package_path + + self.options = dict( + ignore_setup_xxx_py = False, + assume_default_configuration = False, + delegate_options_to_subpackages = False, + quiet = False, + ) + + caller_instance = None + for i in range(1, 3): + try: + f = get_frame(i) + except ValueError: + break + try: + caller_instance = eval('self', f.f_globals, f.f_locals) + break + except NameError: + pass + if isinstance(caller_instance, self.__class__): + if caller_instance.options['delegate_options_to_subpackages']: + self.set_options(**caller_instance.options) + + self.setup_name = setup_name + + def todict(self): + """ + Return a dictionary compatible with the keyword arguments of distutils + setup function. + + Examples + -------- + >>> setup(**config.todict()) #doctest: +SKIP + """ + + self._optimize_data_files() + d = {} + known_keys = self.list_keys + self.dict_keys + self.extra_keys + for n in known_keys: + a = getattr(self, n) + if a: + d[n] = a + return d + + def info(self, message): + if not self.options['quiet']: + print(message) + + def warn(self, message): + sys.stderr.write('Warning: %s' % (message,)) + + def set_options(self, **options): + """ + Configure Configuration instance. + + The following options are available: + - ignore_setup_xxx_py + - assume_default_configuration + - delegate_options_to_subpackages + - quiet + + """ + for key, value in options.items(): + if key in self.options: + self.options[key] = value + else: + raise ValueError('Unknown option: '+key) + + def get_distribution(self): + """Return the distutils distribution object for self.""" + from numpy.distutils.core import get_distribution + return get_distribution() + + def _wildcard_get_subpackage(self, subpackage_name, + parent_name, + caller_level = 1): + l = subpackage_name.split('.') + subpackage_path = njoin([self.local_path]+l) + dirs = [_m for _m in glob.glob(subpackage_path) if os.path.isdir(_m)] + config_list = [] + for d in dirs: + if not os.path.isfile(njoin(d, '__init__.py')): + continue + if 'build' in d.split(os.sep): + continue + n = '.'.join(d.split(os.sep)[-len(l):]) + c = self.get_subpackage(n, + parent_name = parent_name, + caller_level = caller_level+1) + config_list.extend(c) + return config_list + + def _get_configuration_from_setup_py(self, setup_py, + subpackage_name, + subpackage_path, + parent_name, + caller_level = 1): + # In case setup_py imports local modules: + sys.path.insert(0, os.path.dirname(setup_py)) + try: + setup_name = os.path.splitext(os.path.basename(setup_py))[0] + n = dot_join(self.name, subpackage_name, setup_name) + setup_module = npy_load_module('_'.join(n.split('.')), + setup_py, + ('.py', 'U', 1)) + if not hasattr(setup_module, 'configuration'): + if not self.options['assume_default_configuration']: + self.warn('Assuming default configuration '\ + '(%s does not define configuration())'\ + % (setup_module)) + config = Configuration(subpackage_name, parent_name, + self.top_path, subpackage_path, + caller_level = caller_level + 1) + else: + pn = dot_join(*([parent_name] + subpackage_name.split('.')[:-1])) + args = (pn,) + def fix_args_py2(args): + if setup_module.configuration.__code__.co_argcount > 1: + args = args + (self.top_path,) + return args + def fix_args_py3(args): + if setup_module.configuration.__code__.co_argcount > 1: + args = args + (self.top_path,) + return args + if sys.version_info[0] < 3: + args = fix_args_py2(args) + else: + args = fix_args_py3(args) + config = setup_module.configuration(*args) + if config.name!=dot_join(parent_name, subpackage_name): + self.warn('Subpackage %r configuration returned as %r' % \ + (dot_join(parent_name, subpackage_name), config.name)) + finally: + del sys.path[0] + return config + + def get_subpackage(self,subpackage_name, + subpackage_path=None, + parent_name=None, + caller_level = 1): + """Return list of subpackage configurations. + + Parameters + ---------- + subpackage_name : str or None + Name of the subpackage to get the configuration. '*' in + subpackage_name is handled as a wildcard. + subpackage_path : str + If None, then the path is assumed to be the local path plus the + subpackage_name. If a setup.py file is not found in the + subpackage_path, then a default configuration is used. + parent_name : str + Parent name. + """ + if subpackage_name is None: + if subpackage_path is None: + raise ValueError( + "either subpackage_name or subpackage_path must be specified") + subpackage_name = os.path.basename(subpackage_path) + + # handle wildcards + l = subpackage_name.split('.') + if subpackage_path is None and '*' in subpackage_name: + return self._wildcard_get_subpackage(subpackage_name, + parent_name, + caller_level = caller_level+1) + assert '*' not in subpackage_name, repr((subpackage_name, subpackage_path, parent_name)) + if subpackage_path is None: + subpackage_path = njoin([self.local_path] + l) + else: + subpackage_path = njoin([subpackage_path] + l[:-1]) + subpackage_path = self.paths([subpackage_path])[0] + setup_py = njoin(subpackage_path, self.setup_name) + if not self.options['ignore_setup_xxx_py']: + if not os.path.isfile(setup_py): + setup_py = njoin(subpackage_path, + 'setup_%s.py' % (subpackage_name)) + if not os.path.isfile(setup_py): + if not self.options['assume_default_configuration']: + self.warn('Assuming default configuration '\ + '(%s/{setup_%s,setup}.py was not found)' \ + % (os.path.dirname(setup_py), subpackage_name)) + config = Configuration(subpackage_name, parent_name, + self.top_path, subpackage_path, + caller_level = caller_level+1) + else: + config = self._get_configuration_from_setup_py( + setup_py, + subpackage_name, + subpackage_path, + parent_name, + caller_level = caller_level + 1) + if config: + return [config] + else: + return [] + + def add_subpackage(self,subpackage_name, + subpackage_path=None, + standalone = False): + """Add a sub-package to the current Configuration instance. + + This is useful in a setup.py script for adding sub-packages to a + package. + + Parameters + ---------- + subpackage_name : str + name of the subpackage + subpackage_path : str + if given, the subpackage path such as the subpackage is in + subpackage_path / subpackage_name. If None,the subpackage is + assumed to be located in the local path / subpackage_name. + standalone : bool + """ + + if standalone: + parent_name = None + else: + parent_name = self.name + config_list = self.get_subpackage(subpackage_name, subpackage_path, + parent_name = parent_name, + caller_level = 2) + if not config_list: + self.warn('No configuration returned, assuming unavailable.') + for config in config_list: + d = config + if isinstance(config, Configuration): + d = config.todict() + assert isinstance(d, dict), repr(type(d)) + + self.info('Appending %s configuration to %s' \ + % (d.get('name'), self.name)) + self.dict_append(**d) + + dist = self.get_distribution() + if dist is not None: + self.warn('distutils distribution has been initialized,'\ + ' it may be too late to add a subpackage '+ subpackage_name) + + def add_data_dir(self, data_path): + """Recursively add files under data_path to data_files list. + + Recursively add files under data_path to the list of data_files to be + installed (and distributed). The data_path can be either a relative + path-name, or an absolute path-name, or a 2-tuple where the first + argument shows where in the install directory the data directory + should be installed to. + + Parameters + ---------- + data_path : seq or str + Argument can be either + + * 2-sequence (, ) + * path to data directory where python datadir suffix defaults + to package dir. + + Notes + ----- + Rules for installation paths:: + + foo/bar -> (foo/bar, foo/bar) -> parent/foo/bar + (gun, foo/bar) -> parent/gun + foo/* -> (foo/a, foo/a), (foo/b, foo/b) -> parent/foo/a, parent/foo/b + (gun, foo/*) -> (gun, foo/a), (gun, foo/b) -> gun + (gun/*, foo/*) -> parent/gun/a, parent/gun/b + /foo/bar -> (bar, /foo/bar) -> parent/bar + (gun, /foo/bar) -> parent/gun + (fun/*/gun/*, sun/foo/bar) -> parent/fun/foo/gun/bar + + Examples + -------- + For example suppose the source directory contains fun/foo.dat and + fun/bar/car.dat: + + >>> self.add_data_dir('fun') #doctest: +SKIP + >>> self.add_data_dir(('sun', 'fun')) #doctest: +SKIP + >>> self.add_data_dir(('gun', '/full/path/to/fun'))#doctest: +SKIP + + Will install data-files to the locations:: + + / + fun/ + foo.dat + bar/ + car.dat + sun/ + foo.dat + bar/ + car.dat + gun/ + foo.dat + car.dat + + """ + if is_sequence(data_path): + d, data_path = data_path + else: + d = None + if is_sequence(data_path): + [self.add_data_dir((d, p)) for p in data_path] + return + if not is_string(data_path): + raise TypeError("not a string: %r" % (data_path,)) + if d is None: + if os.path.isabs(data_path): + return self.add_data_dir((os.path.basename(data_path), data_path)) + return self.add_data_dir((data_path, data_path)) + paths = self.paths(data_path, include_non_existing=False) + if is_glob_pattern(data_path): + if is_glob_pattern(d): + pattern_list = allpath(d).split(os.sep) + pattern_list.reverse() + # /a/*//b/ -> /a/*/b + rl = list(range(len(pattern_list)-1)); rl.reverse() + for i in rl: + if not pattern_list[i]: + del pattern_list[i] + # + for path in paths: + if not os.path.isdir(path): + print('Not a directory, skipping', path) + continue + rpath = rel_path(path, self.local_path) + path_list = rpath.split(os.sep) + path_list.reverse() + target_list = [] + i = 0 + for s in pattern_list: + if is_glob_pattern(s): + if i>=len(path_list): + raise ValueError('cannot fill pattern %r with %r' \ + % (d, path)) + target_list.append(path_list[i]) + else: + assert s==path_list[i], repr((s, path_list[i], data_path, d, path, rpath)) + target_list.append(s) + i += 1 + if path_list[i:]: + self.warn('mismatch of pattern_list=%s and path_list=%s'\ + % (pattern_list, path_list)) + target_list.reverse() + self.add_data_dir((os.sep.join(target_list), path)) + else: + for path in paths: + self.add_data_dir((d, path)) + return + assert not is_glob_pattern(d), repr(d) + + dist = self.get_distribution() + if dist is not None and dist.data_files is not None: + data_files = dist.data_files + else: + data_files = self.data_files + + for path in paths: + for d1, f in list(general_source_directories_files(path)): + target_path = os.path.join(self.path_in_package, d, d1) + data_files.append((target_path, f)) + + def _optimize_data_files(self): + data_dict = {} + for p, files in self.data_files: + if p not in data_dict: + data_dict[p] = set() + for f in files: + data_dict[p].add(f) + self.data_files[:] = [(p, list(files)) for p, files in data_dict.items()] + + def add_data_files(self,*files): + """Add data files to configuration data_files. + + Parameters + ---------- + files : sequence + Argument(s) can be either + + * 2-sequence (,) + * paths to data files where python datadir prefix defaults + to package dir. + + Notes + ----- + The form of each element of the files sequence is very flexible + allowing many combinations of where to get the files from the package + and where they should ultimately be installed on the system. The most + basic usage is for an element of the files argument sequence to be a + simple filename. This will cause that file from the local path to be + installed to the installation path of the self.name package (package + path). The file argument can also be a relative path in which case the + entire relative path will be installed into the package directory. + Finally, the file can be an absolute path name in which case the file + will be found at the absolute path name but installed to the package + path. + + This basic behavior can be augmented by passing a 2-tuple in as the + file argument. The first element of the tuple should specify the + relative path (under the package install directory) where the + remaining sequence of files should be installed to (it has nothing to + do with the file-names in the source distribution). The second element + of the tuple is the sequence of files that should be installed. The + files in this sequence can be filenames, relative paths, or absolute + paths. For absolute paths the file will be installed in the top-level + package installation directory (regardless of the first argument). + Filenames and relative path names will be installed in the package + install directory under the path name given as the first element of + the tuple. + + Rules for installation paths: + + #. file.txt -> (., file.txt)-> parent/file.txt + #. foo/file.txt -> (foo, foo/file.txt) -> parent/foo/file.txt + #. /foo/bar/file.txt -> (., /foo/bar/file.txt) -> parent/file.txt + #. *.txt -> parent/a.txt, parent/b.txt + #. foo/*.txt -> parent/foo/a.txt, parent/foo/b.txt + #. */*.txt -> (*, */*.txt) -> parent/c/a.txt, parent/d/b.txt + #. (sun, file.txt) -> parent/sun/file.txt + #. (sun, bar/file.txt) -> parent/sun/file.txt + #. (sun, /foo/bar/file.txt) -> parent/sun/file.txt + #. (sun, *.txt) -> parent/sun/a.txt, parent/sun/b.txt + #. (sun, bar/*.txt) -> parent/sun/a.txt, parent/sun/b.txt + #. (sun/*, */*.txt) -> parent/sun/c/a.txt, parent/d/b.txt + + An additional feature is that the path to a data-file can actually be + a function that takes no arguments and returns the actual path(s) to + the data-files. This is useful when the data files are generated while + building the package. + + Examples + -------- + Add files to the list of data_files to be included with the package. + + >>> self.add_data_files('foo.dat', + ... ('fun', ['gun.dat', 'nun/pun.dat', '/tmp/sun.dat']), + ... 'bar/cat.dat', + ... '/full/path/to/can.dat') #doctest: +SKIP + + will install these data files to:: + + / + foo.dat + fun/ + gun.dat + nun/ + pun.dat + sun.dat + bar/ + car.dat + can.dat + + where is the package (or sub-package) + directory such as '/usr/lib/python2.4/site-packages/mypackage' ('C: + \\Python2.4 \\Lib \\site-packages \\mypackage') or + '/usr/lib/python2.4/site- packages/mypackage/mysubpackage' ('C: + \\Python2.4 \\Lib \\site-packages \\mypackage \\mysubpackage'). + """ + + if len(files)>1: + for f in files: + self.add_data_files(f) + return + assert len(files)==1 + if is_sequence(files[0]): + d, files = files[0] + else: + d = None + if is_string(files): + filepat = files + elif is_sequence(files): + if len(files)==1: + filepat = files[0] + else: + for f in files: + self.add_data_files((d, f)) + return + else: + raise TypeError(repr(type(files))) + + if d is None: + if hasattr(filepat, '__call__'): + d = '' + elif os.path.isabs(filepat): + d = '' + else: + d = os.path.dirname(filepat) + self.add_data_files((d, files)) + return + + paths = self.paths(filepat, include_non_existing=False) + if is_glob_pattern(filepat): + if is_glob_pattern(d): + pattern_list = d.split(os.sep) + pattern_list.reverse() + for path in paths: + path_list = path.split(os.sep) + path_list.reverse() + path_list.pop() # filename + target_list = [] + i = 0 + for s in pattern_list: + if is_glob_pattern(s): + target_list.append(path_list[i]) + i += 1 + else: + target_list.append(s) + target_list.reverse() + self.add_data_files((os.sep.join(target_list), path)) + else: + self.add_data_files((d, paths)) + return + assert not is_glob_pattern(d), repr((d, filepat)) + + dist = self.get_distribution() + if dist is not None and dist.data_files is not None: + data_files = dist.data_files + else: + data_files = self.data_files + + data_files.append((os.path.join(self.path_in_package, d), paths)) + + ### XXX Implement add_py_modules + + def add_define_macros(self, macros): + """Add define macros to configuration + + Add the given sequence of macro name and value duples to the beginning + of the define_macros list This list will be visible to all extension + modules of the current package. + """ + dist = self.get_distribution() + if dist is not None: + if not hasattr(dist, 'define_macros'): + dist.define_macros = [] + dist.define_macros.extend(macros) + else: + self.define_macros.extend(macros) + + + def add_include_dirs(self,*paths): + """Add paths to configuration include directories. + + Add the given sequence of paths to the beginning of the include_dirs + list. This list will be visible to all extension modules of the + current package. + """ + include_dirs = self.paths(paths) + dist = self.get_distribution() + if dist is not None: + if dist.include_dirs is None: + dist.include_dirs = [] + dist.include_dirs.extend(include_dirs) + else: + self.include_dirs.extend(include_dirs) + + def add_headers(self,*files): + """Add installable headers to configuration. + + Add the given sequence of files to the beginning of the headers list. + By default, headers will be installed under // directory. If an item of files + is a tuple, then its first argument specifies the actual installation + location relative to the path. + + Parameters + ---------- + files : str or seq + Argument(s) can be either: + + * 2-sequence (,) + * path(s) to header file(s) where python includedir suffix will + default to package name. + """ + headers = [] + for path in files: + if is_string(path): + [headers.append((self.name, p)) for p in self.paths(path)] + else: + if not isinstance(path, (tuple, list)) or len(path) != 2: + raise TypeError(repr(path)) + [headers.append((path[0], p)) for p in self.paths(path[1])] + dist = self.get_distribution() + if dist is not None: + if dist.headers is None: + dist.headers = [] + dist.headers.extend(headers) + else: + self.headers.extend(headers) + + def paths(self,*paths,**kws): + """Apply glob to paths and prepend local_path if needed. + + Applies glob.glob(...) to each path in the sequence (if needed) and + pre-pends the local_path if needed. Because this is called on all + source lists, this allows wildcard characters to be specified in lists + of sources for extension modules and libraries and scripts and allows + path-names be relative to the source directory. + + """ + include_non_existing = kws.get('include_non_existing', True) + return gpaths(paths, + local_path = self.local_path, + include_non_existing=include_non_existing) + + def _fix_paths_dict(self, kw): + for k in kw.keys(): + v = kw[k] + if k in ['sources', 'depends', 'include_dirs', 'library_dirs', + 'module_dirs', 'extra_objects']: + new_v = self.paths(v) + kw[k] = new_v + + def add_extension(self,name,sources,**kw): + """Add extension to configuration. + + Create and add an Extension instance to the ext_modules list. This + method also takes the following optional keyword arguments that are + passed on to the Extension constructor. + + Parameters + ---------- + name : str + name of the extension + sources : seq + list of the sources. The list of sources may contain functions + (called source generators) which must take an extension instance + and a build directory as inputs and return a source file or list of + source files or None. If None is returned then no sources are + generated. If the Extension instance has no sources after + processing all source generators, then no extension module is + built. + include_dirs : + define_macros : + undef_macros : + library_dirs : + libraries : + runtime_library_dirs : + extra_objects : + extra_compile_args : + extra_link_args : + extra_f77_compile_args : + extra_f90_compile_args : + export_symbols : + swig_opts : + depends : + The depends list contains paths to files or directories that the + sources of the extension module depend on. If any path in the + depends list is newer than the extension module, then the module + will be rebuilt. + language : + f2py_options : + module_dirs : + extra_info : dict or list + dict or list of dict of keywords to be appended to keywords. + + Notes + ----- + The self.paths(...) method is applied to all lists that may contain + paths. + """ + ext_args = copy.copy(kw) + ext_args['name'] = dot_join(self.name, name) + ext_args['sources'] = sources + + if 'extra_info' in ext_args: + extra_info = ext_args['extra_info'] + del ext_args['extra_info'] + if isinstance(extra_info, dict): + extra_info = [extra_info] + for info in extra_info: + assert isinstance(info, dict), repr(info) + dict_append(ext_args,**info) + + self._fix_paths_dict(ext_args) + + # Resolve out-of-tree dependencies + libraries = ext_args.get('libraries', []) + libnames = [] + ext_args['libraries'] = [] + for libname in libraries: + if isinstance(libname, tuple): + self._fix_paths_dict(libname[1]) + + # Handle library names of the form libname@relative/path/to/library + if '@' in libname: + lname, lpath = libname.split('@', 1) + lpath = os.path.abspath(njoin(self.local_path, lpath)) + if os.path.isdir(lpath): + c = self.get_subpackage(None, lpath, + caller_level = 2) + if isinstance(c, Configuration): + c = c.todict() + for l in [l[0] for l in c.get('libraries', [])]: + llname = l.split('__OF__', 1)[0] + if llname == lname: + c.pop('name', None) + dict_append(ext_args,**c) + break + continue + libnames.append(libname) + + ext_args['libraries'] = libnames + ext_args['libraries'] + ext_args['define_macros'] = \ + self.define_macros + ext_args.get('define_macros', []) + + from numpy.distutils.core import Extension + ext = Extension(**ext_args) + self.ext_modules.append(ext) + + dist = self.get_distribution() + if dist is not None: + self.warn('distutils distribution has been initialized,'\ + ' it may be too late to add an extension '+name) + return ext + + def add_library(self,name,sources,**build_info): + """ + Add library to configuration. + + Parameters + ---------- + name : str + Name of the extension. + sources : sequence + List of the sources. The list of sources may contain functions + (called source generators) which must take an extension instance + and a build directory as inputs and return a source file or list of + source files or None. If None is returned then no sources are + generated. If the Extension instance has no sources after + processing all source generators, then no extension module is + built. + build_info : dict, optional + The following keys are allowed: + + * depends + * macros + * include_dirs + * extra_compiler_args + * extra_f77_compile_args + * extra_f90_compile_args + * f2py_options + * language + + """ + self._add_library(name, sources, None, build_info) + + dist = self.get_distribution() + if dist is not None: + self.warn('distutils distribution has been initialized,'\ + ' it may be too late to add a library '+ name) + + def _add_library(self, name, sources, install_dir, build_info): + """Common implementation for add_library and add_installed_library. Do + not use directly""" + build_info = copy.copy(build_info) + name = name #+ '__OF__' + self.name + build_info['sources'] = sources + + # Sometimes, depends is not set up to an empty list by default, and if + # depends is not given to add_library, distutils barfs (#1134) + if not 'depends' in build_info: + build_info['depends'] = [] + + self._fix_paths_dict(build_info) + + # Add to libraries list so that it is build with build_clib + self.libraries.append((name, build_info)) + + def add_installed_library(self, name, sources, install_dir, build_info=None): + """ + Similar to add_library, but the specified library is installed. + + Most C libraries used with `distutils` are only used to build python + extensions, but libraries built through this method will be installed + so that they can be reused by third-party packages. + + Parameters + ---------- + name : str + Name of the installed library. + sources : sequence + List of the library's source files. See `add_library` for details. + install_dir : str + Path to install the library, relative to the current sub-package. + build_info : dict, optional + The following keys are allowed: + + * depends + * macros + * include_dirs + * extra_compiler_args + * extra_f77_compile_args + * extra_f90_compile_args + * f2py_options + * language + + Returns + ------- + None + + See Also + -------- + add_library, add_npy_pkg_config, get_info + + Notes + ----- + The best way to encode the options required to link against the specified + C libraries is to use a "libname.ini" file, and use `get_info` to + retrieve the required options (see `add_npy_pkg_config` for more + information). + + """ + if not build_info: + build_info = {} + + install_dir = os.path.join(self.package_path, install_dir) + self._add_library(name, sources, install_dir, build_info) + self.installed_libraries.append(InstallableLib(name, build_info, install_dir)) + + def add_npy_pkg_config(self, template, install_dir, subst_dict=None): + """ + Generate and install a npy-pkg config file from a template. + + The config file generated from `template` is installed in the + given install directory, using `subst_dict` for variable substitution. + + Parameters + ---------- + template : str + The path of the template, relatively to the current package path. + install_dir : str + Where to install the npy-pkg config file, relatively to the current + package path. + subst_dict : dict, optional + If given, any string of the form ``@key@`` will be replaced by + ``subst_dict[key]`` in the template file when installed. The install + prefix is always available through the variable ``@prefix@``, since the + install prefix is not easy to get reliably from setup.py. + + See also + -------- + add_installed_library, get_info + + Notes + ----- + This works for both standard installs and in-place builds, i.e. the + ``@prefix@`` refer to the source directory for in-place builds. + + Examples + -------- + :: + + config.add_npy_pkg_config('foo.ini.in', 'lib', {'foo': bar}) + + Assuming the foo.ini.in file has the following content:: + + [meta] + Name=@foo@ + Version=1.0 + Description=dummy description + + [default] + Cflags=-I@prefix@/include + Libs= + + The generated file will have the following content:: + + [meta] + Name=bar + Version=1.0 + Description=dummy description + + [default] + Cflags=-Iprefix_dir/include + Libs= + + and will be installed as foo.ini in the 'lib' subpath. + + """ + if subst_dict is None: + subst_dict = {} + basename = os.path.splitext(template)[0] + template = os.path.join(self.package_path, template) + + if self.name in self.installed_pkg_config: + self.installed_pkg_config[self.name].append((template, install_dir, + subst_dict)) + else: + self.installed_pkg_config[self.name] = [(template, install_dir, + subst_dict)] + + + def add_scripts(self,*files): + """Add scripts to configuration. + + Add the sequence of files to the beginning of the scripts list. + Scripts will be installed under the /bin/ directory. + + """ + scripts = self.paths(files) + dist = self.get_distribution() + if dist is not None: + if dist.scripts is None: + dist.scripts = [] + dist.scripts.extend(scripts) + else: + self.scripts.extend(scripts) + + def dict_append(self,**dict): + for key in self.list_keys: + a = getattr(self, key) + a.extend(dict.get(key, [])) + for key in self.dict_keys: + a = getattr(self, key) + a.update(dict.get(key, {})) + known_keys = self.list_keys + self.dict_keys + self.extra_keys + for key in dict.keys(): + if key not in known_keys: + a = getattr(self, key, None) + if a and a==dict[key]: continue + self.warn('Inheriting attribute %r=%r from %r' \ + % (key, dict[key], dict.get('name', '?'))) + setattr(self, key, dict[key]) + self.extra_keys.append(key) + elif key in self.extra_keys: + self.info('Ignoring attempt to set %r (from %r to %r)' \ + % (key, getattr(self, key), dict[key])) + elif key in known_keys: + # key is already processed above + pass + else: + raise ValueError("Don't know about key=%r" % (key)) + + def __str__(self): + from pprint import pformat + known_keys = self.list_keys + self.dict_keys + self.extra_keys + s = '<'+5*'-' + '\n' + s += 'Configuration of '+self.name+':\n' + known_keys.sort() + for k in known_keys: + a = getattr(self, k, None) + if a: + s += '%s = %s\n' % (k, pformat(a)) + s += 5*'-' + '>' + return s + + def get_config_cmd(self): + """ + Returns the numpy.distutils config command instance. + """ + cmd = get_cmd('config') + cmd.ensure_finalized() + cmd.dump_source = 0 + cmd.noisy = 0 + old_path = os.environ.get('PATH') + if old_path: + path = os.pathsep.join(['.', old_path]) + os.environ['PATH'] = path + return cmd + + def get_build_temp_dir(self): + """ + Return a path to a temporary directory where temporary files should be + placed. + """ + cmd = get_cmd('build') + cmd.ensure_finalized() + return cmd.build_temp + + def have_f77c(self): + """Check for availability of Fortran 77 compiler. + + Use it inside source generating function to ensure that + setup distribution instance has been initialized. + + Notes + ----- + True if a Fortran 77 compiler is available (because a simple Fortran 77 + code was able to be compiled successfully). + """ + simple_fortran_subroutine = ''' + subroutine simple + end + ''' + config_cmd = self.get_config_cmd() + flag = config_cmd.try_compile(simple_fortran_subroutine, lang='f77') + return flag + + def have_f90c(self): + """Check for availability of Fortran 90 compiler. + + Use it inside source generating function to ensure that + setup distribution instance has been initialized. + + Notes + ----- + True if a Fortran 90 compiler is available (because a simple Fortran + 90 code was able to be compiled successfully) + """ + simple_fortran_subroutine = ''' + subroutine simple + end + ''' + config_cmd = self.get_config_cmd() + flag = config_cmd.try_compile(simple_fortran_subroutine, lang='f90') + return flag + + def append_to(self, extlib): + """Append libraries, include_dirs to extension or library item. + """ + if is_sequence(extlib): + lib_name, build_info = extlib + dict_append(build_info, + libraries=self.libraries, + include_dirs=self.include_dirs) + else: + from numpy.distutils.core import Extension + assert isinstance(extlib, Extension), repr(extlib) + extlib.libraries.extend(self.libraries) + extlib.include_dirs.extend(self.include_dirs) + + def _get_svn_revision(self, path): + """Return path's SVN revision number. + """ + revision = None + m = None + cwd = os.getcwd() + try: + os.chdir(path or '.') + p = subprocess.Popen(['svnversion'], shell=True, + stdout=subprocess.PIPE, stderr=None, + close_fds=True) + sout = p.stdout + m = re.match(r'(?P\d+)', sout.read()) + except Exception: + pass + os.chdir(cwd) + if m: + revision = int(m.group('revision')) + return revision + if sys.platform=='win32' and os.environ.get('SVN_ASP_DOT_NET_HACK', None): + entries = njoin(path, '_svn', 'entries') + else: + entries = njoin(path, '.svn', 'entries') + if os.path.isfile(entries): + f = open(entries) + fstr = f.read() + f.close() + if fstr[:5] == '\d+)"', fstr) + if m: + revision = int(m.group('revision')) + else: # non-xml entries file --- check to be sure that + m = re.search(r'dir[\n\r]+(?P\d+)', fstr) + if m: + revision = int(m.group('revision')) + return revision + + def _get_hg_revision(self, path): + """Return path's Mercurial revision number. + """ + revision = None + m = None + cwd = os.getcwd() + try: + os.chdir(path or '.') + p = subprocess.Popen(['hg identify --num'], shell=True, + stdout=subprocess.PIPE, stderr=None, + close_fds=True) + sout = p.stdout + m = re.match(r'(?P\d+)', sout.read()) + except Exception: + pass + os.chdir(cwd) + if m: + revision = int(m.group('revision')) + return revision + branch_fn = njoin(path, '.hg', 'branch') + branch_cache_fn = njoin(path, '.hg', 'branch.cache') + + if os.path.isfile(branch_fn): + branch0 = None + f = open(branch_fn) + revision0 = f.read().strip() + f.close() + + branch_map = {} + for line in file(branch_cache_fn, 'r'): + branch1, revision1 = line.split()[:2] + if revision1==revision0: + branch0 = branch1 + try: + revision1 = int(revision1) + except ValueError: + continue + branch_map[branch1] = revision1 + + revision = branch_map.get(branch0) + return revision + + + def get_version(self, version_file=None, version_variable=None): + """Try to get version string of a package. + + Return a version string of the current package or None if the version + information could not be detected. + + Notes + ----- + This method scans files named + __version__.py, _version.py, version.py, and + __svn_version__.py for string variables version, __version__, and + _version, until a version number is found. + """ + version = getattr(self, 'version', None) + if version is not None: + return version + + # Get version from version file. + if version_file is None: + files = ['__version__.py', + self.name.split('.')[-1]+'_version.py', + 'version.py', + '__svn_version__.py', + '__hg_version__.py'] + else: + files = [version_file] + if version_variable is None: + version_vars = ['version', + '__version__', + self.name.split('.')[-1]+'_version'] + else: + version_vars = [version_variable] + for f in files: + fn = njoin(self.local_path, f) + if os.path.isfile(fn): + info = ('.py', 'U', 1) + name = os.path.splitext(os.path.basename(fn))[0] + n = dot_join(self.name, name) + try: + version_module = npy_load_module('_'.join(n.split('.')), + fn, info) + except ImportError: + msg = get_exception() + self.warn(str(msg)) + version_module = None + if version_module is None: + continue + + for a in version_vars: + version = getattr(version_module, a, None) + if version is not None: + break + if version is not None: + break + + if version is not None: + self.version = version + return version + + # Get version as SVN or Mercurial revision number + revision = self._get_svn_revision(self.local_path) + if revision is None: + revision = self._get_hg_revision(self.local_path) + + if revision is not None: + version = str(revision) + self.version = version + + return version + + def make_svn_version_py(self, delete=True): + """Appends a data function to the data_files list that will generate + __svn_version__.py file to the current package directory. + + Generate package __svn_version__.py file from SVN revision number, + it will be removed after python exits but will be available + when sdist, etc commands are executed. + + Notes + ----- + If __svn_version__.py existed before, nothing is done. + + This is + intended for working with source directories that are in an SVN + repository. + """ + target = njoin(self.local_path, '__svn_version__.py') + revision = self._get_svn_revision(self.local_path) + if os.path.isfile(target) or revision is None: + return + else: + def generate_svn_version_py(): + if not os.path.isfile(target): + version = str(revision) + self.info('Creating %s (version=%r)' % (target, version)) + f = open(target, 'w') + f.write('version = %r\n' % (version)) + f.close() + + import atexit + def rm_file(f=target,p=self.info): + if delete: + try: os.remove(f); p('removed '+f) + except OSError: pass + try: os.remove(f+'c'); p('removed '+f+'c') + except OSError: pass + + atexit.register(rm_file) + + return target + + self.add_data_files(('', generate_svn_version_py())) + + def make_hg_version_py(self, delete=True): + """Appends a data function to the data_files list that will generate + __hg_version__.py file to the current package directory. + + Generate package __hg_version__.py file from Mercurial revision, + it will be removed after python exits but will be available + when sdist, etc commands are executed. + + Notes + ----- + If __hg_version__.py existed before, nothing is done. + + This is intended for working with source directories that are + in an Mercurial repository. + """ + target = njoin(self.local_path, '__hg_version__.py') + revision = self._get_hg_revision(self.local_path) + if os.path.isfile(target) or revision is None: + return + else: + def generate_hg_version_py(): + if not os.path.isfile(target): + version = str(revision) + self.info('Creating %s (version=%r)' % (target, version)) + f = open(target, 'w') + f.write('version = %r\n' % (version)) + f.close() + + import atexit + def rm_file(f=target,p=self.info): + if delete: + try: os.remove(f); p('removed '+f) + except OSError: pass + try: os.remove(f+'c'); p('removed '+f+'c') + except OSError: pass + + atexit.register(rm_file) + + return target + + self.add_data_files(('', generate_hg_version_py())) + + def make_config_py(self,name='__config__'): + """Generate package __config__.py file containing system_info + information used during building the package. + + This file is installed to the + package installation directory. + + """ + self.py_modules.append((self.name, name, generate_config_py)) + + def get_info(self,*names): + """Get resources information. + + Return information (from system_info.get_info) for all of the names in + the argument list in a single dictionary. + """ + from .system_info import get_info, dict_append + info_dict = {} + for a in names: + dict_append(info_dict,**get_info(a)) + return info_dict + + +def get_cmd(cmdname, _cache={}): + if cmdname not in _cache: + import distutils.core + dist = distutils.core._setup_distribution + if dist is None: + from distutils.errors import DistutilsInternalError + raise DistutilsInternalError( + 'setup distribution instance not initialized') + cmd = dist.get_command_obj(cmdname) + _cache[cmdname] = cmd + return _cache[cmdname] + +def get_numpy_include_dirs(): + # numpy_include_dirs are set by numpy/core/setup.py, otherwise [] + include_dirs = Configuration.numpy_include_dirs[:] + if not include_dirs: + import numpy + include_dirs = [ numpy.get_include() ] + # else running numpy/core/setup.py + return include_dirs + +def get_npy_pkg_dir(): + """Return the path where to find the npy-pkg-config directory.""" + # XXX: import here for bootstrapping reasons + import numpy + d = os.path.join(os.path.dirname(numpy.__file__), + 'core', 'lib', 'npy-pkg-config') + return d + +def get_pkg_info(pkgname, dirs=None): + """ + Return library info for the given package. + + Parameters + ---------- + pkgname : str + Name of the package (should match the name of the .ini file, without + the extension, e.g. foo for the file foo.ini). + dirs : sequence, optional + If given, should be a sequence of additional directories where to look + for npy-pkg-config files. Those directories are searched prior to the + NumPy directory. + + Returns + ------- + pkginfo : class instance + The `LibraryInfo` instance containing the build information. + + Raises + ------ + PkgNotFound + If the package is not found. + + See Also + -------- + Configuration.add_npy_pkg_config, Configuration.add_installed_library, + get_info + + """ + from numpy.distutils.npy_pkg_config import read_config + + if dirs: + dirs.append(get_npy_pkg_dir()) + else: + dirs = [get_npy_pkg_dir()] + return read_config(pkgname, dirs) + +def get_info(pkgname, dirs=None): + """ + Return an info dict for a given C library. + + The info dict contains the necessary options to use the C library. + + Parameters + ---------- + pkgname : str + Name of the package (should match the name of the .ini file, without + the extension, e.g. foo for the file foo.ini). + dirs : sequence, optional + If given, should be a sequence of additional directories where to look + for npy-pkg-config files. Those directories are searched prior to the + NumPy directory. + + Returns + ------- + info : dict + The dictionary with build information. + + Raises + ------ + PkgNotFound + If the package is not found. + + See Also + -------- + Configuration.add_npy_pkg_config, Configuration.add_installed_library, + get_pkg_info + + Examples + -------- + To get the necessary information for the npymath library from NumPy: + + >>> npymath_info = np.distutils.misc_util.get_info('npymath') + >>> npymath_info #doctest: +SKIP + {'define_macros': [], 'libraries': ['npymath'], 'library_dirs': + ['.../numpy/core/lib'], 'include_dirs': ['.../numpy/core/include']} + + This info dict can then be used as input to a `Configuration` instance:: + + config.add_extension('foo', sources=['foo.c'], extra_info=npymath_info) + + """ + from numpy.distutils.npy_pkg_config import parse_flags + pkg_info = get_pkg_info(pkgname, dirs) + + # Translate LibraryInfo instance into a build_info dict + info = parse_flags(pkg_info.cflags()) + for k, v in parse_flags(pkg_info.libs()).items(): + info[k].extend(v) + + # add_extension extra_info argument is ANAL + info['define_macros'] = info['macros'] + del info['macros'] + del info['ignored'] + + return info + +def is_bootstrapping(): + if sys.version_info[0] >= 3: + import builtins + else: + import __builtin__ as builtins + + try: + builtins.__NUMPY_SETUP__ + return True + except AttributeError: + return False + __NUMPY_SETUP__ = False + + +######################### + +def default_config_dict(name = None, parent_name = None, local_path=None): + """Return a configuration dictionary for usage in + configuration() function defined in file setup_.py. + """ + import warnings + warnings.warn('Use Configuration(%r,%r,top_path=%r) instead of '\ + 'deprecated default_config_dict(%r,%r,%r)' + % (name, parent_name, local_path, + name, parent_name, local_path, + ), stacklevel=2) + c = Configuration(name, parent_name, local_path) + return c.todict() + + +def dict_append(d, **kws): + for k, v in kws.items(): + if k in d: + ov = d[k] + if isinstance(ov, str): + d[k] = v + else: + d[k].extend(v) + else: + d[k] = v + +def appendpath(prefix, path): + if os.path.sep != '/': + prefix = prefix.replace('/', os.path.sep) + path = path.replace('/', os.path.sep) + drive = '' + if os.path.isabs(path): + drive = os.path.splitdrive(prefix)[0] + absprefix = os.path.splitdrive(os.path.abspath(prefix))[1] + pathdrive, path = os.path.splitdrive(path) + d = os.path.commonprefix([absprefix, path]) + if os.path.join(absprefix[:len(d)], absprefix[len(d):]) != absprefix \ + or os.path.join(path[:len(d)], path[len(d):]) != path: + # Handle invalid paths + d = os.path.dirname(d) + subpath = path[len(d):] + if os.path.isabs(subpath): + subpath = subpath[1:] + else: + subpath = path + return os.path.normpath(njoin(drive + prefix, subpath)) + +def generate_config_py(target): + """Generate config.py file containing system_info information + used during building the package. + + Usage: + config['py_modules'].append((packagename, '__config__',generate_config_py)) + """ + from numpy.distutils.system_info import system_info + from distutils.dir_util import mkpath + mkpath(os.path.dirname(target)) + f = open(target, 'w') + f.write('# This file is generated by numpy\'s %s\n' % (os.path.basename(sys.argv[0]))) + f.write('# It contains system_info results at the time of building this package.\n') + f.write('__all__ = ["get_info","show"]\n\n') + + # For gfortran+msvc combination, extra shared libraries may exist + f.write(""" +import os +import sys + +extra_dll_dir = os.path.join(os.path.dirname(__file__), '.libs') +if sys.platform == 'win32' and os.path.isdir(extra_dll_dir): + os.environ.setdefault('PATH', '') + os.environ['PATH'] += os.pathsep + extra_dll_dir +""") + + for k, i in system_info.saved_results.items(): + f.write('%s=%r\n' % (k, i)) + f.write(r''' +def get_info(name): + g = globals() + return g.get(name, g.get(name + "_info", {})) + +def show(): + for name,info_dict in globals().items(): + if name[0] == "_" or type(info_dict) is not type({}): continue + print(name + ":") + if not info_dict: + print(" NOT AVAILABLE") + for k,v in info_dict.items(): + v = str(v) + if k == "sources" and len(v) > 200: + v = v[:60] + " ...\n... " + v[-60:] + print(" %s = %s" % (k,v)) + ''') + + f.close() + return target + +def msvc_version(compiler): + """Return version major and minor of compiler instance if it is + MSVC, raise an exception otherwise.""" + if not compiler.compiler_type == "msvc": + raise ValueError("Compiler instance is not msvc (%s)"\ + % compiler.compiler_type) + return compiler._MSVCCompiler__version diff --git a/numpy/distutils/msvc9compiler.py b/numpy/distutils/msvc9compiler.py new file mode 100644 index 0000000..e9cc334 --- /dev/null +++ b/numpy/distutils/msvc9compiler.py @@ -0,0 +1,65 @@ +from __future__ import division, absolute_import, print_function + +import os +from distutils.msvc9compiler import MSVCCompiler as _MSVCCompiler + +from .system_info import platform_bits + + +def _merge(old, new): + """Concatenate two environment paths avoiding repeats. + + Here `old` is the environment string before the base class initialize + function is called and `new` is the string after the call. The new string + will be a fixed string if it is not obtained from the current environment, + or the same as the old string if obtained from the same environment. The aim + here is not to append the new string if it is already contained in the old + string so as to limit the growth of the environment string. + + Parameters + ---------- + old : string + Previous environment string. + new : string + New environment string. + + Returns + ------- + ret : string + Updated environment string. + + """ + if not old: + return new + if new in old: + return old + + # Neither new nor old is empty. Give old priority. + return ';'.join([old, new]) + + +class MSVCCompiler(_MSVCCompiler): + def __init__(self, verbose=0, dry_run=0, force=0): + _MSVCCompiler.__init__(self, verbose, dry_run, force) + + def initialize(self, plat_name=None): + # The 'lib' and 'include' variables may be overwritten + # by MSVCCompiler.initialize, so save them for later merge. + environ_lib = os.getenv('lib') + environ_include = os.getenv('include') + _MSVCCompiler.initialize(self, plat_name) + + # Merge current and previous values of 'lib' and 'include' + os.environ['lib'] = _merge(environ_lib, os.environ['lib']) + os.environ['include'] = _merge(environ_include, os.environ['include']) + + # msvc9 building for 32 bits requires SSE2 to work around a + # compiler bug. + if platform_bits == 32: + self.compile_options += ['/arch:SSE2'] + self.compile_options_debug += ['/arch:SSE2'] + + def manifest_setup_ldargs(self, output_filename, build_temp, ld_args): + ld_args.append('/MANIFEST') + _MSVCCompiler.manifest_setup_ldargs(self, output_filename, + build_temp, ld_args) diff --git a/numpy/distutils/msvccompiler.py b/numpy/distutils/msvccompiler.py new file mode 100644 index 0000000..903d751 --- /dev/null +++ b/numpy/distutils/msvccompiler.py @@ -0,0 +1,60 @@ +from __future__ import division, absolute_import, print_function + +import os +from distutils.msvccompiler import MSVCCompiler as _MSVCCompiler + +from .system_info import platform_bits + + +def _merge(old, new): + """Concatenate two environment paths avoiding repeats. + + Here `old` is the environment string before the base class initialize + function is called and `new` is the string after the call. The new string + will be a fixed string if it is not obtained from the current enviroment, + or the same as the old string if obtained from the same enviroment. The aim + here is not to append the new string if it is already contained in the old + string so as to limit the growth of the environment string. + + Parameters + ---------- + old : string + Previous enviroment string. + new : string + New environment string. + + Returns + ------- + ret : string + Updated environment string. + + """ + if new in old: + return old + if not old: + return new + + # Neither new nor old is empty. Give old priority. + return ';'.join([old, new]) + + +class MSVCCompiler(_MSVCCompiler): + def __init__(self, verbose=0, dry_run=0, force=0): + _MSVCCompiler.__init__(self, verbose, dry_run, force) + + def initialize(self): + # The 'lib' and 'include' variables may be overwritten + # by MSVCCompiler.initialize, so save them for later merge. + environ_lib = os.getenv('lib', '') + environ_include = os.getenv('include', '') + _MSVCCompiler.initialize(self) + + # Merge current and previous values of 'lib' and 'include' + os.environ['lib'] = _merge(environ_lib, os.environ['lib']) + os.environ['include'] = _merge(environ_include, os.environ['include']) + + # msvc9 building for 32 bits requires SSE2 to work around a + # compiler bug. + if platform_bits == 32: + self.compile_options += ['/arch:SSE2'] + self.compile_options_debug += ['/arch:SSE2'] diff --git a/numpy/distutils/npy_pkg_config.py b/numpy/distutils/npy_pkg_config.py new file mode 100644 index 0000000..6fe5176 --- /dev/null +++ b/numpy/distutils/npy_pkg_config.py @@ -0,0 +1,446 @@ +from __future__ import division, absolute_import, print_function + +import sys +import re +import os + +if sys.version_info[0] < 3: + from ConfigParser import RawConfigParser, NoOptionError +else: + from configparser import RawConfigParser, NoOptionError + +__all__ = ['FormatError', 'PkgNotFound', 'LibraryInfo', 'VariableSet', + 'read_config', 'parse_flags'] + +_VAR = re.compile(r'\$\{([a-zA-Z0-9_-]+)\}') + +class FormatError(IOError): + """ + Exception thrown when there is a problem parsing a configuration file. + + """ + def __init__(self, msg): + self.msg = msg + + def __str__(self): + return self.msg + +class PkgNotFound(IOError): + """Exception raised when a package can not be located.""" + def __init__(self, msg): + self.msg = msg + + def __str__(self): + return self.msg + +def parse_flags(line): + """ + Parse a line from a config file containing compile flags. + + Parameters + ---------- + line : str + A single line containing one or more compile flags. + + Returns + ------- + d : dict + Dictionary of parsed flags, split into relevant categories. + These categories are the keys of `d`: + + * 'include_dirs' + * 'library_dirs' + * 'libraries' + * 'macros' + * 'ignored' + + """ + d = {'include_dirs': [], 'library_dirs': [], 'libraries': [], + 'macros': [], 'ignored': []} + + flags = (' ' + line).split(' -') + for flag in flags: + flag = '-' + flag + if len(flag) > 0: + if flag.startswith('-I'): + d['include_dirs'].append(flag[2:].strip()) + elif flag.startswith('-L'): + d['library_dirs'].append(flag[2:].strip()) + elif flag.startswith('-l'): + d['libraries'].append(flag[2:].strip()) + elif flag.startswith('-D'): + d['macros'].append(flag[2:].strip()) + else: + d['ignored'].append(flag) + + return d + +def _escape_backslash(val): + return val.replace('\\', '\\\\') + +class LibraryInfo(object): + """ + Object containing build information about a library. + + Parameters + ---------- + name : str + The library name. + description : str + Description of the library. + version : str + Version string. + sections : dict + The sections of the configuration file for the library. The keys are + the section headers, the values the text under each header. + vars : class instance + A `VariableSet` instance, which contains ``(name, value)`` pairs for + variables defined in the configuration file for the library. + requires : sequence, optional + The required libraries for the library to be installed. + + Notes + ----- + All input parameters (except "sections" which is a method) are available as + attributes of the same name. + + """ + def __init__(self, name, description, version, sections, vars, requires=None): + self.name = name + self.description = description + if requires: + self.requires = requires + else: + self.requires = [] + self.version = version + self._sections = sections + self.vars = vars + + def sections(self): + """ + Return the section headers of the config file. + + Parameters + ---------- + None + + Returns + ------- + keys : list of str + The list of section headers. + + """ + return list(self._sections.keys()) + + def cflags(self, section="default"): + val = self.vars.interpolate(self._sections[section]['cflags']) + return _escape_backslash(val) + + def libs(self, section="default"): + val = self.vars.interpolate(self._sections[section]['libs']) + return _escape_backslash(val) + + def __str__(self): + m = ['Name: %s' % self.name, 'Description: %s' % self.description] + if self.requires: + m.append('Requires:') + else: + m.append('Requires: %s' % ",".join(self.requires)) + m.append('Version: %s' % self.version) + + return "\n".join(m) + +class VariableSet(object): + """ + Container object for the variables defined in a config file. + + `VariableSet` can be used as a plain dictionary, with the variable names + as keys. + + Parameters + ---------- + d : dict + Dict of items in the "variables" section of the configuration file. + + """ + def __init__(self, d): + self._raw_data = dict([(k, v) for k, v in d.items()]) + + self._re = {} + self._re_sub = {} + + self._init_parse() + + def _init_parse(self): + for k, v in self._raw_data.items(): + self._init_parse_var(k, v) + + def _init_parse_var(self, name, value): + self._re[name] = re.compile(r'\$\{%s\}' % name) + self._re_sub[name] = value + + def interpolate(self, value): + # Brute force: we keep interpolating until there is no '${var}' anymore + # or until interpolated string is equal to input string + def _interpolate(value): + for k in self._re.keys(): + value = self._re[k].sub(self._re_sub[k], value) + return value + while _VAR.search(value): + nvalue = _interpolate(value) + if nvalue == value: + break + value = nvalue + + return value + + def variables(self): + """ + Return the list of variable names. + + Parameters + ---------- + None + + Returns + ------- + names : list of str + The names of all variables in the `VariableSet` instance. + + """ + return list(self._raw_data.keys()) + + # Emulate a dict to set/get variables values + def __getitem__(self, name): + return self._raw_data[name] + + def __setitem__(self, name, value): + self._raw_data[name] = value + self._init_parse_var(name, value) + +def parse_meta(config): + if not config.has_section('meta'): + raise FormatError("No meta section found !") + + d = {} + for name, value in config.items('meta'): + d[name] = value + + for k in ['name', 'description', 'version']: + if not k in d: + raise FormatError("Option %s (section [meta]) is mandatory, " + "but not found" % k) + + if not 'requires' in d: + d['requires'] = [] + + return d + +def parse_variables(config): + if not config.has_section('variables'): + raise FormatError("No variables section found !") + + d = {} + + for name, value in config.items("variables"): + d[name] = value + + return VariableSet(d) + +def parse_sections(config): + return meta_d, r + +def pkg_to_filename(pkg_name): + return "%s.ini" % pkg_name + +def parse_config(filename, dirs=None): + if dirs: + filenames = [os.path.join(d, filename) for d in dirs] + else: + filenames = [filename] + + config = RawConfigParser() + + n = config.read(filenames) + if not len(n) >= 1: + raise PkgNotFound("Could not find file(s) %s" % str(filenames)) + + # Parse meta and variables sections + meta = parse_meta(config) + + vars = {} + if config.has_section('variables'): + for name, value in config.items("variables"): + vars[name] = _escape_backslash(value) + + # Parse "normal" sections + secs = [s for s in config.sections() if not s in ['meta', 'variables']] + sections = {} + + requires = {} + for s in secs: + d = {} + if config.has_option(s, "requires"): + requires[s] = config.get(s, 'requires') + + for name, value in config.items(s): + d[name] = value + sections[s] = d + + return meta, vars, sections, requires + +def _read_config_imp(filenames, dirs=None): + def _read_config(f): + meta, vars, sections, reqs = parse_config(f, dirs) + # recursively add sections and variables of required libraries + for rname, rvalue in reqs.items(): + nmeta, nvars, nsections, nreqs = _read_config(pkg_to_filename(rvalue)) + + # Update var dict for variables not in 'top' config file + for k, v in nvars.items(): + if not k in vars: + vars[k] = v + + # Update sec dict + for oname, ovalue in nsections[rname].items(): + if ovalue: + sections[rname][oname] += ' %s' % ovalue + + return meta, vars, sections, reqs + + meta, vars, sections, reqs = _read_config(filenames) + + # FIXME: document this. If pkgname is defined in the variables section, and + # there is no pkgdir variable defined, pkgdir is automatically defined to + # the path of pkgname. This requires the package to be imported to work + if not 'pkgdir' in vars and "pkgname" in vars: + pkgname = vars["pkgname"] + if not pkgname in sys.modules: + raise ValueError("You should import %s to get information on %s" % + (pkgname, meta["name"])) + + mod = sys.modules[pkgname] + vars["pkgdir"] = _escape_backslash(os.path.dirname(mod.__file__)) + + return LibraryInfo(name=meta["name"], description=meta["description"], + version=meta["version"], sections=sections, vars=VariableSet(vars)) + +# Trivial cache to cache LibraryInfo instances creation. To be really +# efficient, the cache should be handled in read_config, since a same file can +# be parsed many time outside LibraryInfo creation, but I doubt this will be a +# problem in practice +_CACHE = {} +def read_config(pkgname, dirs=None): + """ + Return library info for a package from its configuration file. + + Parameters + ---------- + pkgname : str + Name of the package (should match the name of the .ini file, without + the extension, e.g. foo for the file foo.ini). + dirs : sequence, optional + If given, should be a sequence of directories - usually including + the NumPy base directory - where to look for npy-pkg-config files. + + Returns + ------- + pkginfo : class instance + The `LibraryInfo` instance containing the build information. + + Raises + ------ + PkgNotFound + If the package is not found. + + See Also + -------- + misc_util.get_info, misc_util.get_pkg_info + + Examples + -------- + >>> npymath_info = np.distutils.npy_pkg_config.read_config('npymath') + >>> type(npymath_info) + + >>> print(npymath_info) + Name: npymath + Description: Portable, core math library implementing C99 standard + Requires: + Version: 0.1 #random + + """ + try: + return _CACHE[pkgname] + except KeyError: + v = _read_config_imp(pkg_to_filename(pkgname), dirs) + _CACHE[pkgname] = v + return v + +# TODO: +# - implements version comparison (modversion + atleast) + +# pkg-config simple emulator - useful for debugging, and maybe later to query +# the system +if __name__ == '__main__': + import sys + from optparse import OptionParser + import glob + + parser = OptionParser() + parser.add_option("--cflags", dest="cflags", action="store_true", + help="output all preprocessor and compiler flags") + parser.add_option("--libs", dest="libs", action="store_true", + help="output all linker flags") + parser.add_option("--use-section", dest="section", + help="use this section instead of default for options") + parser.add_option("--version", dest="version", action="store_true", + help="output version") + parser.add_option("--atleast-version", dest="min_version", + help="Minimal version") + parser.add_option("--list-all", dest="list_all", action="store_true", + help="Minimal version") + parser.add_option("--define-variable", dest="define_variable", + help="Replace variable with the given value") + + (options, args) = parser.parse_args(sys.argv) + + if len(args) < 2: + raise ValueError("Expect package name on the command line:") + + if options.list_all: + files = glob.glob("*.ini") + for f in files: + info = read_config(f) + print("%s\t%s - %s" % (info.name, info.name, info.description)) + + pkg_name = args[1] + import os + d = os.environ.get('NPY_PKG_CONFIG_PATH') + if d: + info = read_config(pkg_name, ['numpy/core/lib/npy-pkg-config', '.', d]) + else: + info = read_config(pkg_name, ['numpy/core/lib/npy-pkg-config', '.']) + + if options.section: + section = options.section + else: + section = "default" + + if options.define_variable: + m = re.search(r'([\S]+)=([\S]+)', options.define_variable) + if not m: + raise ValueError("--define-variable option should be of " \ + "the form --define-variable=foo=bar") + else: + name = m.group(1) + value = m.group(2) + info.vars[name] = value + + if options.cflags: + print(info.cflags(section)) + if options.libs: + print(info.libs(section)) + if options.version: + print(info.version) + if options.min_version: + print(info.version >= options.min_version) diff --git a/numpy/distutils/numpy_distribution.py b/numpy/distutils/numpy_distribution.py new file mode 100644 index 0000000..6ae19d1 --- /dev/null +++ b/numpy/distutils/numpy_distribution.py @@ -0,0 +1,19 @@ +# XXX: Handle setuptools ? +from __future__ import division, absolute_import, print_function + +from distutils.core import Distribution + +# This class is used because we add new files (sconscripts, and so on) with the +# scons command +class NumpyDistribution(Distribution): + def __init__(self, attrs = None): + # A list of (sconscripts, pre_hook, post_hook, src, parent_names) + self.scons_data = [] + # A list of installable libraries + self.installed_libraries = [] + # A dict of pkg_config files to generate/install + self.installed_pkg_config = {} + Distribution.__init__(self, attrs) + + def has_scons_scripts(self): + return bool(self.scons_data) diff --git a/numpy/distutils/pathccompiler.py b/numpy/distutils/pathccompiler.py new file mode 100644 index 0000000..fc9872d --- /dev/null +++ b/numpy/distutils/pathccompiler.py @@ -0,0 +1,23 @@ +from __future__ import division, absolute_import, print_function + +from distutils.unixccompiler import UnixCCompiler + +class PathScaleCCompiler(UnixCCompiler): + + """ + PathScale compiler compatible with an gcc built Python. + """ + + compiler_type = 'pathcc' + cc_exe = 'pathcc' + cxx_exe = 'pathCC' + + def __init__ (self, verbose=0, dry_run=0, force=0): + UnixCCompiler.__init__ (self, verbose, dry_run, force) + cc_compiler = self.cc_exe + cxx_compiler = self.cxx_exe + self.set_executables(compiler=cc_compiler, + compiler_so=cc_compiler, + compiler_cxx=cxx_compiler, + linker_exe=cc_compiler, + linker_so=cc_compiler + ' -shared') diff --git a/numpy/distutils/setup.py b/numpy/distutils/setup.py new file mode 100644 index 0000000..82a53bd --- /dev/null +++ b/numpy/distutils/setup.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +from __future__ import division, print_function + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('distutils', parent_package, top_path) + config.add_subpackage('command') + config.add_subpackage('fcompiler') + config.add_data_dir('tests') + config.add_data_files('site.cfg') + config.add_data_files('mingw/gfortran_vs2003_hack.c') + config.make_config_py() + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py new file mode 100644 index 0000000..93a8e6f --- /dev/null +++ b/numpy/distutils/system_info.py @@ -0,0 +1,2540 @@ +#!/usr/bin/env python +""" +This file defines a set of system_info classes for getting +information about various resources (libraries, library directories, +include directories, etc.) in the system. Currently, the following +classes are available: + + atlas_info + atlas_threads_info + atlas_blas_info + atlas_blas_threads_info + lapack_atlas_info + lapack_atlas_threads_info + atlas_3_10_info + atlas_3_10_threads_info + atlas_3_10_blas_info, + atlas_3_10_blas_threads_info, + lapack_atlas_3_10_info + lapack_atlas_3_10_threads_info + blas_info + lapack_info + openblas_info + blis_info + blas_opt_info # usage recommended + lapack_opt_info # usage recommended + fftw_info,dfftw_info,sfftw_info + fftw_threads_info,dfftw_threads_info,sfftw_threads_info + djbfft_info + x11_info + lapack_src_info + blas_src_info + numpy_info + numarray_info + numpy_info + boost_python_info + agg2_info + wx_info + gdk_pixbuf_xlib_2_info + gdk_pixbuf_2_info + gdk_x11_2_info + gtkp_x11_2_info + gtkp_2_info + xft_info + freetype2_info + umfpack_info + +Usage: + info_dict = get_info() + where is a string 'atlas','x11','fftw','lapack','blas', + 'lapack_src', 'blas_src', etc. For a complete list of allowed names, + see the definition of get_info() function below. + + Returned info_dict is a dictionary which is compatible with + distutils.setup keyword arguments. If info_dict == {}, then the + asked resource is not available (system_info could not find it). + + Several *_info classes specify an environment variable to specify + the locations of software. When setting the corresponding environment + variable to 'None' then the software will be ignored, even when it + is available in system. + +Global parameters: + system_info.search_static_first - search static libraries (.a) + in precedence to shared ones (.so, .sl) if enabled. + system_info.verbosity - output the results to stdout if enabled. + +The file 'site.cfg' is looked for in + +1) Directory of main setup.py file being run. +2) Home directory of user running the setup.py file as ~/.numpy-site.cfg +3) System wide directory (location of this file...) + +The first one found is used to get system configuration options The +format is that used by ConfigParser (i.e., Windows .INI style). The +section ALL has options that are the default for each section. The +available sections are fftw, atlas, and x11. Appropriate defaults are +used if nothing is specified. + +The order of finding the locations of resources is the following: + 1. environment variable + 2. section in site.cfg + 3. ALL section in site.cfg +Only the first complete match is returned. + +Example: +---------- +[ALL] +library_dirs = /usr/lib:/usr/local/lib:/opt/lib +include_dirs = /usr/include:/usr/local/include:/opt/include +src_dirs = /usr/local/src:/opt/src +# search static libraries (.a) in preference to shared ones (.so) +search_static_first = 0 + +[fftw] +fftw_libs = rfftw, fftw +fftw_opt_libs = rfftw_threaded, fftw_threaded +# if the above aren't found, look for {s,d}fftw_libs and {s,d}fftw_opt_libs + +[atlas] +library_dirs = /usr/lib/3dnow:/usr/lib/3dnow/atlas +# for overriding the names of the atlas libraries +atlas_libs = lapack, f77blas, cblas, atlas + +[x11] +library_dirs = /usr/X11R6/lib +include_dirs = /usr/X11R6/include +---------- + +Authors: + Pearu Peterson , February 2002 + David M. Cooke , April 2002 + +Copyright 2002 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy (BSD style) license. See LICENSE.txt that came with +this distribution for specifics. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + +""" +from __future__ import division, absolute_import, print_function + +import sys +import os +import re +import copy +import warnings +import atexit +from glob import glob +from functools import reduce +if sys.version_info[0] < 3: + from ConfigParser import NoOptionError + from ConfigParser import RawConfigParser as ConfigParser +else: + from configparser import NoOptionError + from configparser import RawConfigParser as ConfigParser +# It seems that some people are importing ConfigParser from here so is +# good to keep its class name. Use of RawConfigParser is needed in +# order to be able to load path names with percent in them, like +# `feature%2Fcool` which is common on git flow branch names. + +from distutils.errors import DistutilsError +from distutils.dist import Distribution +import distutils.sysconfig +from distutils import log +from distutils.util import get_platform + +from numpy.distutils.exec_command import ( + find_executable, exec_command, get_pythonexe) +from numpy.distutils.misc_util import (is_sequence, is_string, + get_shared_lib_extension) +from numpy.distutils.command.config import config as cmd_config +from numpy.distutils.compat import get_exception +from numpy.distutils import customized_ccompiler +import distutils.ccompiler +import tempfile +import shutil + + +# Determine number of bits +import platform +_bits = {'32bit': 32, '64bit': 64} +platform_bits = _bits[platform.architecture()[0]] + + +def libpaths(paths, bits): + """Return a list of library paths valid on 32 or 64 bit systems. + + Inputs: + paths : sequence + A sequence of strings (typically paths) + bits : int + An integer, the only valid values are 32 or 64. A ValueError exception + is raised otherwise. + + Examples: + + Consider a list of directories + >>> paths = ['/usr/X11R6/lib','/usr/X11/lib','/usr/lib'] + + For a 32-bit platform, this is already valid: + >>> np.distutils.system_info.libpaths(paths,32) + ['/usr/X11R6/lib', '/usr/X11/lib', '/usr/lib'] + + On 64 bits, we prepend the '64' postfix + >>> np.distutils.system_info.libpaths(paths,64) + ['/usr/X11R6/lib64', '/usr/X11R6/lib', '/usr/X11/lib64', '/usr/X11/lib', + '/usr/lib64', '/usr/lib'] + """ + if bits not in (32, 64): + raise ValueError("Invalid bit size in libpaths: 32 or 64 only") + + # Handle 32bit case + if bits == 32: + return paths + + # Handle 64bit case + out = [] + for p in paths: + out.extend([p + '64', p]) + + return out + + +if sys.platform == 'win32': + default_lib_dirs = ['C:\\', + os.path.join(distutils.sysconfig.EXEC_PREFIX, + 'libs')] + default_runtime_dirs = [] + default_include_dirs = [] + default_src_dirs = ['.'] + default_x11_lib_dirs = [] + default_x11_include_dirs = [] + _include_dirs = [ + 'include', + 'include/suitesparse', + ] + _lib_dirs = [ + 'lib', + ] + + _include_dirs = [d.replace('/', os.sep) for d in _include_dirs] + _lib_dirs = [d.replace('/', os.sep) for d in _lib_dirs] + def add_system_root(library_root): + """Add a package manager root to the include directories""" + global default_lib_dirs + global default_include_dirs + + library_root = os.path.normpath(library_root) + + default_lib_dirs.extend( + os.path.join(library_root, d) for d in _lib_dirs) + default_include_dirs.extend( + os.path.join(library_root, d) for d in _include_dirs) + + if sys.version_info >= (3, 3): + # VCpkg is the de-facto package manager on windows for C/C++ + # libraries. If it is on the PATH, then we append its paths here. + # We also don't re-implement shutil.which for Python 2.7 because + # vcpkg doesn't support MSVC 2008. + vcpkg = shutil.which('vcpkg') + if vcpkg: + vcpkg_dir = os.path.dirname(vcpkg) + if platform.architecture() == '32bit': + specifier = 'x86' + else: + specifier = 'x64' + + vcpkg_installed = os.path.join(vcpkg_dir, 'installed') + for vcpkg_root in [ + os.path.join(vcpkg_installed, specifier + '-windows'), + os.path.join(vcpkg_installed, specifier + '-windows-static'), + ]: + add_system_root(vcpkg_root) + + # Conda is another popular package manager that provides libraries + conda = shutil.which('conda') + if conda: + conda_dir = os.path.dirname(conda) + add_system_root(os.path.join(conda_dir, '..', 'Library')) + add_system_root(os.path.join(conda_dir, 'Library')) + +else: + default_lib_dirs = libpaths(['/usr/local/lib', '/opt/lib', '/usr/lib', + '/opt/local/lib', '/sw/lib'], platform_bits) + default_runtime_dirs = [] + default_include_dirs = ['/usr/local/include', + '/opt/include', '/usr/include', + # path of umfpack under macports + '/opt/local/include/ufsparse', + '/opt/local/include', '/sw/include', + '/usr/include/suitesparse'] + default_src_dirs = ['.', '/usr/local/src', '/opt/src', '/sw/src'] + + default_x11_lib_dirs = libpaths(['/usr/X11R6/lib', '/usr/X11/lib', + '/usr/lib'], platform_bits) + default_x11_include_dirs = ['/usr/X11R6/include', '/usr/X11/include', + '/usr/include'] + + if os.path.exists('/usr/lib/X11'): + globbed_x11_dir = glob('/usr/lib/*/libX11.so') + if globbed_x11_dir: + x11_so_dir = os.path.split(globbed_x11_dir[0])[0] + default_x11_lib_dirs.extend([x11_so_dir, '/usr/lib/X11']) + default_x11_include_dirs.extend(['/usr/lib/X11/include', + '/usr/include/X11']) + + import subprocess as sp + tmp = None + try: + # Explicitly open/close file to avoid ResourceWarning when + # tests are run in debug mode Python 3. + tmp = open(os.devnull, 'w') + p = sp.Popen(["gcc", "-print-multiarch"], stdout=sp.PIPE, + stderr=tmp) + except (OSError, DistutilsError): + # OSError if gcc is not installed, or SandboxViolation (DistutilsError + # subclass) if an old setuptools bug is triggered (see gh-3160). + pass + else: + triplet = str(p.communicate()[0].decode().strip()) + if p.returncode == 0: + # gcc supports the "-print-multiarch" option + default_x11_lib_dirs += [os.path.join("/usr/lib/", triplet)] + default_lib_dirs += [os.path.join("/usr/lib/", triplet)] + finally: + if tmp is not None: + tmp.close() + +if os.path.join(sys.prefix, 'lib') not in default_lib_dirs: + default_lib_dirs.insert(0, os.path.join(sys.prefix, 'lib')) + default_include_dirs.append(os.path.join(sys.prefix, 'include')) + default_src_dirs.append(os.path.join(sys.prefix, 'src')) + +default_lib_dirs = [_m for _m in default_lib_dirs if os.path.isdir(_m)] +default_runtime_dirs = [_m for _m in default_runtime_dirs if os.path.isdir(_m)] +default_include_dirs = [_m for _m in default_include_dirs if os.path.isdir(_m)] +default_src_dirs = [_m for _m in default_src_dirs if os.path.isdir(_m)] + +so_ext = get_shared_lib_extension() + + +def get_standard_file(fname): + """Returns a list of files named 'fname' from + 1) System-wide directory (directory-location of this module) + 2) Users HOME directory (os.environ['HOME']) + 3) Local directory + """ + # System-wide file + filenames = [] + try: + f = __file__ + except NameError: + f = sys.argv[0] + else: + sysfile = os.path.join(os.path.split(os.path.abspath(f))[0], + fname) + if os.path.isfile(sysfile): + filenames.append(sysfile) + + # Home directory + # And look for the user config file + try: + f = os.path.expanduser('~') + except KeyError: + pass + else: + user_file = os.path.join(f, fname) + if os.path.isfile(user_file): + filenames.append(user_file) + + # Local file + if os.path.isfile(fname): + filenames.append(os.path.abspath(fname)) + + return filenames + + +def get_info(name, notfound_action=0): + """ + notfound_action: + 0 - do nothing + 1 - display warning message + 2 - raise error + """ + cl = {'atlas': atlas_info, # use lapack_opt or blas_opt instead + 'atlas_threads': atlas_threads_info, # ditto + 'atlas_blas': atlas_blas_info, + 'atlas_blas_threads': atlas_blas_threads_info, + 'lapack_atlas': lapack_atlas_info, # use lapack_opt instead + 'lapack_atlas_threads': lapack_atlas_threads_info, # ditto + 'atlas_3_10': atlas_3_10_info, # use lapack_opt or blas_opt instead + 'atlas_3_10_threads': atlas_3_10_threads_info, # ditto + 'atlas_3_10_blas': atlas_3_10_blas_info, + 'atlas_3_10_blas_threads': atlas_3_10_blas_threads_info, + 'lapack_atlas_3_10': lapack_atlas_3_10_info, # use lapack_opt instead + 'lapack_atlas_3_10_threads': lapack_atlas_3_10_threads_info, # ditto + 'mkl': mkl_info, + # openblas which may or may not have embedded lapack + 'openblas': openblas_info, # use blas_opt instead + # openblas with embedded lapack + 'openblas_lapack': openblas_lapack_info, # use blas_opt instead + 'openblas_clapack': openblas_clapack_info, # use blas_opt instead + 'blis': blis_info, # use blas_opt instead + 'lapack_mkl': lapack_mkl_info, # use lapack_opt instead + 'blas_mkl': blas_mkl_info, # use blas_opt instead + 'x11': x11_info, + 'fft_opt': fft_opt_info, + 'fftw': fftw_info, + 'fftw2': fftw2_info, + 'fftw3': fftw3_info, + 'dfftw': dfftw_info, + 'sfftw': sfftw_info, + 'fftw_threads': fftw_threads_info, + 'dfftw_threads': dfftw_threads_info, + 'sfftw_threads': sfftw_threads_info, + 'djbfft': djbfft_info, + 'blas': blas_info, # use blas_opt instead + 'lapack': lapack_info, # use lapack_opt instead + 'lapack_src': lapack_src_info, + 'blas_src': blas_src_info, + 'numpy': numpy_info, + 'f2py': f2py_info, + 'Numeric': Numeric_info, + 'numeric': Numeric_info, + 'numarray': numarray_info, + 'numerix': numerix_info, + 'lapack_opt': lapack_opt_info, + 'blas_opt': blas_opt_info, + 'boost_python': boost_python_info, + 'agg2': agg2_info, + 'wx': wx_info, + 'gdk_pixbuf_xlib_2': gdk_pixbuf_xlib_2_info, + 'gdk-pixbuf-xlib-2.0': gdk_pixbuf_xlib_2_info, + 'gdk_pixbuf_2': gdk_pixbuf_2_info, + 'gdk-pixbuf-2.0': gdk_pixbuf_2_info, + 'gdk': gdk_info, + 'gdk_2': gdk_2_info, + 'gdk-2.0': gdk_2_info, + 'gdk_x11_2': gdk_x11_2_info, + 'gdk-x11-2.0': gdk_x11_2_info, + 'gtkp_x11_2': gtkp_x11_2_info, + 'gtk+-x11-2.0': gtkp_x11_2_info, + 'gtkp_2': gtkp_2_info, + 'gtk+-2.0': gtkp_2_info, + 'xft': xft_info, + 'freetype2': freetype2_info, + 'umfpack': umfpack_info, + 'amd': amd_info, + }.get(name.lower(), system_info) + return cl().get_info(notfound_action) + + +class NotFoundError(DistutilsError): + """Some third-party program or library is not found.""" + + +class AtlasNotFoundError(NotFoundError): + """ + Atlas (http://math-atlas.sourceforge.net/) libraries not found. + Directories to search for the libraries can be specified in the + numpy/distutils/site.cfg file (section [atlas]) or by setting + the ATLAS environment variable.""" + + +class LapackNotFoundError(NotFoundError): + """ + Lapack (http://www.netlib.org/lapack/) libraries not found. + Directories to search for the libraries can be specified in the + numpy/distutils/site.cfg file (section [lapack]) or by setting + the LAPACK environment variable.""" + + +class LapackSrcNotFoundError(LapackNotFoundError): + """ + Lapack (http://www.netlib.org/lapack/) sources not found. + Directories to search for the sources can be specified in the + numpy/distutils/site.cfg file (section [lapack_src]) or by setting + the LAPACK_SRC environment variable.""" + + +class BlasNotFoundError(NotFoundError): + """ + Blas (http://www.netlib.org/blas/) libraries not found. + Directories to search for the libraries can be specified in the + numpy/distutils/site.cfg file (section [blas]) or by setting + the BLAS environment variable.""" + + +class BlasSrcNotFoundError(BlasNotFoundError): + """ + Blas (http://www.netlib.org/blas/) sources not found. + Directories to search for the sources can be specified in the + numpy/distutils/site.cfg file (section [blas_src]) or by setting + the BLAS_SRC environment variable.""" + + +class FFTWNotFoundError(NotFoundError): + """ + FFTW (http://www.fftw.org/) libraries not found. + Directories to search for the libraries can be specified in the + numpy/distutils/site.cfg file (section [fftw]) or by setting + the FFTW environment variable.""" + + +class DJBFFTNotFoundError(NotFoundError): + """ + DJBFFT (http://cr.yp.to/djbfft.html) libraries not found. + Directories to search for the libraries can be specified in the + numpy/distutils/site.cfg file (section [djbfft]) or by setting + the DJBFFT environment variable.""" + + +class NumericNotFoundError(NotFoundError): + """ + Numeric (http://www.numpy.org/) module not found. + Get it from above location, install it, and retry setup.py.""" + + +class X11NotFoundError(NotFoundError): + """X11 libraries not found.""" + + +class UmfpackNotFoundError(NotFoundError): + """ + UMFPACK sparse solver (http://www.cise.ufl.edu/research/sparse/umfpack/) + not found. Directories to search for the libraries can be specified in the + numpy/distutils/site.cfg file (section [umfpack]) or by setting + the UMFPACK environment variable.""" + + +class system_info(object): + + """ get_info() is the only public method. Don't use others. + """ + section = 'ALL' + dir_env_var = None + search_static_first = 0 # XXX: disabled by default, may disappear in + # future unless it is proved to be useful. + verbosity = 1 + saved_results = {} + + notfounderror = NotFoundError + + def __init__(self, + default_lib_dirs=default_lib_dirs, + default_include_dirs=default_include_dirs, + verbosity=1, + ): + self.__class__.info = {} + self.local_prefixes = [] + defaults = {'library_dirs': os.pathsep.join(default_lib_dirs), + 'include_dirs': os.pathsep.join(default_include_dirs), + 'runtime_library_dirs': os.pathsep.join(default_runtime_dirs), + 'rpath': '', + 'src_dirs': os.pathsep.join(default_src_dirs), + 'search_static_first': str(self.search_static_first), + 'extra_compile_args': '', 'extra_link_args': ''} + self.cp = ConfigParser(defaults) + self.files = [] + self.files.extend(get_standard_file('.numpy-site.cfg')) + self.files.extend(get_standard_file('site.cfg')) + self.parse_config_files() + + if self.section is not None: + self.search_static_first = self.cp.getboolean( + self.section, 'search_static_first') + assert isinstance(self.search_static_first, int) + + def parse_config_files(self): + self.cp.read(self.files) + if not self.cp.has_section(self.section): + if self.section is not None: + self.cp.add_section(self.section) + + def calc_libraries_info(self): + libs = self.get_libraries() + dirs = self.get_lib_dirs() + # The extensions use runtime_library_dirs + r_dirs = self.get_runtime_lib_dirs() + # Intrinsic distutils use rpath, we simply append both entries + # as though they were one entry + r_dirs.extend(self.get_runtime_lib_dirs(key='rpath')) + info = {} + for lib in libs: + i = self.check_libs(dirs, [lib]) + if i is not None: + dict_append(info, **i) + else: + log.info('Library %s was not found. Ignoring' % (lib)) + + if r_dirs: + i = self.check_libs(r_dirs, [lib]) + if i is not None: + # Swap library keywords found to runtime_library_dirs + # the libraries are insisting on the user having defined + # them using the library_dirs, and not necessarily by + # runtime_library_dirs + del i['libraries'] + i['runtime_library_dirs'] = i.pop('library_dirs') + dict_append(info, **i) + else: + log.info('Runtime library %s was not found. Ignoring' % (lib)) + + return info + + def set_info(self, **info): + if info: + lib_info = self.calc_libraries_info() + dict_append(info, **lib_info) + # Update extra information + extra_info = self.calc_extra_info() + dict_append(info, **extra_info) + self.saved_results[self.__class__.__name__] = info + + def has_info(self): + return self.__class__.__name__ in self.saved_results + + def calc_extra_info(self): + """ Updates the information in the current information with + respect to these flags: + extra_compile_args + extra_link_args + """ + info = {} + for key in ['extra_compile_args', 'extra_link_args']: + # Get values + opt = self.cp.get(self.section, key) + if opt: + tmp = {key : [opt]} + dict_append(info, **tmp) + return info + + def get_info(self, notfound_action=0): + """ Return a dictonary with items that are compatible + with numpy.distutils.setup keyword arguments. + """ + flag = 0 + if not self.has_info(): + flag = 1 + log.info(self.__class__.__name__ + ':') + if hasattr(self, 'calc_info'): + self.calc_info() + if notfound_action: + if not self.has_info(): + if notfound_action == 1: + warnings.warn(self.notfounderror.__doc__, stacklevel=2) + elif notfound_action == 2: + raise self.notfounderror(self.notfounderror.__doc__) + else: + raise ValueError(repr(notfound_action)) + + if not self.has_info(): + log.info(' NOT AVAILABLE') + self.set_info() + else: + log.info(' FOUND:') + + res = self.saved_results.get(self.__class__.__name__) + if self.verbosity > 0 and flag: + for k, v in res.items(): + v = str(v) + if k in ['sources', 'libraries'] and len(v) > 270: + v = v[:120] + '...\n...\n...' + v[-120:] + log.info(' %s = %s', k, v) + log.info('') + + return copy.deepcopy(res) + + def get_paths(self, section, key): + dirs = self.cp.get(section, key).split(os.pathsep) + env_var = self.dir_env_var + if env_var: + if is_sequence(env_var): + e0 = env_var[-1] + for e in env_var: + if e in os.environ: + e0 = e + break + if not env_var[0] == e0: + log.info('Setting %s=%s' % (env_var[0], e0)) + env_var = e0 + if env_var and env_var in os.environ: + d = os.environ[env_var] + if d == 'None': + log.info('Disabled %s: %s', + self.__class__.__name__, '(%s is None)' + % (env_var,)) + return [] + if os.path.isfile(d): + dirs = [os.path.dirname(d)] + dirs + l = getattr(self, '_lib_names', []) + if len(l) == 1: + b = os.path.basename(d) + b = os.path.splitext(b)[0] + if b[:3] == 'lib': + log.info('Replacing _lib_names[0]==%r with %r' \ + % (self._lib_names[0], b[3:])) + self._lib_names[0] = b[3:] + else: + ds = d.split(os.pathsep) + ds2 = [] + for d in ds: + if os.path.isdir(d): + ds2.append(d) + for dd in ['include', 'lib']: + d1 = os.path.join(d, dd) + if os.path.isdir(d1): + ds2.append(d1) + dirs = ds2 + dirs + default_dirs = self.cp.get(self.section, key).split(os.pathsep) + dirs.extend(default_dirs) + ret = [] + for d in dirs: + if len(d) > 0 and not os.path.isdir(d): + warnings.warn('Specified path %s is invalid.' % d, stacklevel=2) + continue + + if d not in ret: + ret.append(d) + + log.debug('( %s = %s )', key, ':'.join(ret)) + return ret + + def get_lib_dirs(self, key='library_dirs'): + return self.get_paths(self.section, key) + + def get_runtime_lib_dirs(self, key='runtime_library_dirs'): + path = self.get_paths(self.section, key) + if path == ['']: + path = [] + return path + + def get_include_dirs(self, key='include_dirs'): + return self.get_paths(self.section, key) + + def get_src_dirs(self, key='src_dirs'): + return self.get_paths(self.section, key) + + def get_libs(self, key, default): + try: + libs = self.cp.get(self.section, key) + except NoOptionError: + if not default: + return [] + if is_string(default): + return [default] + return default + return [b for b in [a.strip() for a in libs.split(',')] if b] + + def get_libraries(self, key='libraries'): + if hasattr(self, '_lib_names'): + return self.get_libs(key, default=self._lib_names) + else: + return self.get_libs(key, '') + + def library_extensions(self): + c = customized_ccompiler() + static_exts = [] + if c.compiler_type != 'msvc': + # MSVC doesn't understand binutils + static_exts.append('.a') + if sys.platform == 'win32': + static_exts.append('.lib') # .lib is used by MSVC and others + if self.search_static_first: + exts = static_exts + [so_ext] + else: + exts = [so_ext] + static_exts + if sys.platform == 'cygwin': + exts.append('.dll.a') + if sys.platform == 'darwin': + exts.append('.dylib') + return exts + + def check_libs(self, lib_dirs, libs, opt_libs=[]): + """If static or shared libraries are available then return + their info dictionary. + + Checks for all libraries as shared libraries first, then + static (or vice versa if self.search_static_first is True). + """ + exts = self.library_extensions() + info = None + for ext in exts: + info = self._check_libs(lib_dirs, libs, opt_libs, [ext]) + if info is not None: + break + if not info: + log.info(' libraries %s not found in %s', ','.join(libs), + lib_dirs) + return info + + def check_libs2(self, lib_dirs, libs, opt_libs=[]): + """If static or shared libraries are available then return + their info dictionary. + + Checks each library for shared or static. + """ + exts = self.library_extensions() + info = self._check_libs(lib_dirs, libs, opt_libs, exts) + if not info: + log.info(' libraries %s not found in %s', ','.join(libs), + lib_dirs) + + return info + + def _find_lib(self, lib_dir, lib, exts): + assert is_string(lib_dir) + # under windows first try without 'lib' prefix + if sys.platform == 'win32': + lib_prefixes = ['', 'lib'] + else: + lib_prefixes = ['lib'] + # for each library name, see if we can find a file for it. + for ext in exts: + for prefix in lib_prefixes: + p = self.combine_paths(lib_dir, prefix + lib + ext) + if p: + break + if p: + assert len(p) == 1 + # ??? splitext on p[0] would do this for cygwin + # doesn't seem correct + if ext == '.dll.a': + lib += '.dll' + return lib + + return False + + def _find_libs(self, lib_dirs, libs, exts): + # make sure we preserve the order of libs, as it can be important + found_dirs, found_libs = [], [] + for lib in libs: + for lib_dir in lib_dirs: + found_lib = self._find_lib(lib_dir, lib, exts) + if found_lib: + found_libs.append(found_lib) + if lib_dir not in found_dirs: + found_dirs.append(lib_dir) + break + return found_dirs, found_libs + + def _check_libs(self, lib_dirs, libs, opt_libs, exts): + """Find mandatory and optional libs in expected paths. + + Missing optional libraries are silently forgotten. + """ + if not is_sequence(lib_dirs): + lib_dirs = [lib_dirs] + # First, try to find the mandatory libraries + found_dirs, found_libs = self._find_libs(lib_dirs, libs, exts) + if len(found_libs) > 0 and len(found_libs) == len(libs): + # Now, check for optional libraries + opt_found_dirs, opt_found_libs = self._find_libs(lib_dirs, opt_libs, exts) + found_libs.extend(opt_found_libs) + for lib_dir in opt_found_dirs: + if lib_dir not in found_dirs: + found_dirs.append(lib_dir) + info = {'libraries': found_libs, 'library_dirs': found_dirs} + return info + else: + return None + + def combine_paths(self, *args): + """Return a list of existing paths composed by all combinations + of items from the arguments. + """ + return combine_paths(*args, **{'verbosity': self.verbosity}) + + +class fft_opt_info(system_info): + + def calc_info(self): + info = {} + fftw_info = get_info('fftw3') or get_info('fftw2') or get_info('dfftw') + djbfft_info = get_info('djbfft') + if fftw_info: + dict_append(info, **fftw_info) + if djbfft_info: + dict_append(info, **djbfft_info) + self.set_info(**info) + return + + +class fftw_info(system_info): + #variables to override + section = 'fftw' + dir_env_var = 'FFTW' + notfounderror = FFTWNotFoundError + ver_info = [{'name':'fftw3', + 'libs':['fftw3'], + 'includes':['fftw3.h'], + 'macros':[('SCIPY_FFTW3_H', None)]}, + {'name':'fftw2', + 'libs':['rfftw', 'fftw'], + 'includes':['fftw.h', 'rfftw.h'], + 'macros':[('SCIPY_FFTW_H', None)]}] + + def calc_ver_info(self, ver_param): + """Returns True on successful version detection, else False""" + lib_dirs = self.get_lib_dirs() + incl_dirs = self.get_include_dirs() + libs = self.get_libs(self.section + '_libs', ver_param['libs']) + info = self.check_libs(lib_dirs, libs) + if info is not None: + flag = 0 + for d in incl_dirs: + if len(self.combine_paths(d, ver_param['includes'])) \ + == len(ver_param['includes']): + dict_append(info, include_dirs=[d]) + flag = 1 + incl_dirs = [d] + break + if flag: + dict_append(info, define_macros=ver_param['macros']) + else: + info = None + if info is not None: + self.set_info(**info) + return True + else: + log.info(' %s not found' % (ver_param['name'])) + return False + + def calc_info(self): + for i in self.ver_info: + if self.calc_ver_info(i): + break + + +class fftw2_info(fftw_info): + #variables to override + section = 'fftw' + dir_env_var = 'FFTW' + notfounderror = FFTWNotFoundError + ver_info = [{'name':'fftw2', + 'libs':['rfftw', 'fftw'], + 'includes':['fftw.h', 'rfftw.h'], + 'macros':[('SCIPY_FFTW_H', None)]} + ] + + +class fftw3_info(fftw_info): + #variables to override + section = 'fftw3' + dir_env_var = 'FFTW3' + notfounderror = FFTWNotFoundError + ver_info = [{'name':'fftw3', + 'libs':['fftw3'], + 'includes':['fftw3.h'], + 'macros':[('SCIPY_FFTW3_H', None)]}, + ] + + +class dfftw_info(fftw_info): + section = 'fftw' + dir_env_var = 'FFTW' + ver_info = [{'name':'dfftw', + 'libs':['drfftw', 'dfftw'], + 'includes':['dfftw.h', 'drfftw.h'], + 'macros':[('SCIPY_DFFTW_H', None)]}] + + +class sfftw_info(fftw_info): + section = 'fftw' + dir_env_var = 'FFTW' + ver_info = [{'name':'sfftw', + 'libs':['srfftw', 'sfftw'], + 'includes':['sfftw.h', 'srfftw.h'], + 'macros':[('SCIPY_SFFTW_H', None)]}] + + +class fftw_threads_info(fftw_info): + section = 'fftw' + dir_env_var = 'FFTW' + ver_info = [{'name':'fftw threads', + 'libs':['rfftw_threads', 'fftw_threads'], + 'includes':['fftw_threads.h', 'rfftw_threads.h'], + 'macros':[('SCIPY_FFTW_THREADS_H', None)]}] + + +class dfftw_threads_info(fftw_info): + section = 'fftw' + dir_env_var = 'FFTW' + ver_info = [{'name':'dfftw threads', + 'libs':['drfftw_threads', 'dfftw_threads'], + 'includes':['dfftw_threads.h', 'drfftw_threads.h'], + 'macros':[('SCIPY_DFFTW_THREADS_H', None)]}] + + +class sfftw_threads_info(fftw_info): + section = 'fftw' + dir_env_var = 'FFTW' + ver_info = [{'name':'sfftw threads', + 'libs':['srfftw_threads', 'sfftw_threads'], + 'includes':['sfftw_threads.h', 'srfftw_threads.h'], + 'macros':[('SCIPY_SFFTW_THREADS_H', None)]}] + + +class djbfft_info(system_info): + section = 'djbfft' + dir_env_var = 'DJBFFT' + notfounderror = DJBFFTNotFoundError + + def get_paths(self, section, key): + pre_dirs = system_info.get_paths(self, section, key) + dirs = [] + for d in pre_dirs: + dirs.extend(self.combine_paths(d, ['djbfft']) + [d]) + return [d for d in dirs if os.path.isdir(d)] + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + incl_dirs = self.get_include_dirs() + info = None + for d in lib_dirs: + p = self.combine_paths(d, ['djbfft.a']) + if p: + info = {'extra_objects': p} + break + p = self.combine_paths(d, ['libdjbfft.a', 'libdjbfft' + so_ext]) + if p: + info = {'libraries': ['djbfft'], 'library_dirs': [d]} + break + if info is None: + return + for d in incl_dirs: + if len(self.combine_paths(d, ['fftc8.h', 'fftfreq.h'])) == 2: + dict_append(info, include_dirs=[d], + define_macros=[('SCIPY_DJBFFT_H', None)]) + self.set_info(**info) + return + return + + +class mkl_info(system_info): + section = 'mkl' + dir_env_var = 'MKLROOT' + _lib_mkl = ['mkl_rt'] + + def get_mkl_rootdir(self): + mklroot = os.environ.get('MKLROOT', None) + if mklroot is not None: + return mklroot + paths = os.environ.get('LD_LIBRARY_PATH', '').split(os.pathsep) + ld_so_conf = '/etc/ld.so.conf' + if os.path.isfile(ld_so_conf): + with open(ld_so_conf, 'r') as f: + for d in f: + d = d.strip() + if d: + paths.append(d) + intel_mkl_dirs = [] + for path in paths: + path_atoms = path.split(os.sep) + for m in path_atoms: + if m.startswith('mkl'): + d = os.sep.join(path_atoms[:path_atoms.index(m) + 2]) + intel_mkl_dirs.append(d) + break + for d in paths: + dirs = glob(os.path.join(d, 'mkl', '*')) + dirs += glob(os.path.join(d, 'mkl*')) + for d in dirs: + if os.path.isdir(os.path.join(d, 'lib')): + return d + return None + + def __init__(self): + mklroot = self.get_mkl_rootdir() + if mklroot is None: + system_info.__init__(self) + else: + from .cpuinfo import cpu + if cpu.is_Itanium(): + plt = '64' + elif cpu.is_Intel() and cpu.is_64bit(): + plt = 'intel64' + else: + plt = '32' + system_info.__init__( + self, + default_lib_dirs=[os.path.join(mklroot, 'lib', plt)], + default_include_dirs=[os.path.join(mklroot, 'include')]) + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + incl_dirs = self.get_include_dirs() + mkl_libs = self.get_libs('mkl_libs', self._lib_mkl) + info = self.check_libs2(lib_dirs, mkl_libs) + if info is None: + return + dict_append(info, + define_macros=[('SCIPY_MKL_H', None), + ('HAVE_CBLAS', None)], + include_dirs=incl_dirs) + if sys.platform == 'win32': + pass # win32 has no pthread library + else: + dict_append(info, libraries=['pthread']) + self.set_info(**info) + + +class lapack_mkl_info(mkl_info): + pass + + +class blas_mkl_info(mkl_info): + pass + + +class atlas_info(system_info): + section = 'atlas' + dir_env_var = 'ATLAS' + _lib_names = ['f77blas', 'cblas'] + if sys.platform[:7] == 'freebsd': + _lib_atlas = ['atlas_r'] + _lib_lapack = ['alapack_r'] + else: + _lib_atlas = ['atlas'] + _lib_lapack = ['lapack'] + + notfounderror = AtlasNotFoundError + + def get_paths(self, section, key): + pre_dirs = system_info.get_paths(self, section, key) + dirs = [] + for d in pre_dirs: + dirs.extend(self.combine_paths(d, ['atlas*', 'ATLAS*', + 'sse', '3dnow', 'sse2']) + [d]) + return [d for d in dirs if os.path.isdir(d)] + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + info = {} + atlas_libs = self.get_libs('atlas_libs', + self._lib_names + self._lib_atlas) + lapack_libs = self.get_libs('lapack_libs', self._lib_lapack) + atlas = None + lapack = None + atlas_1 = None + for d in lib_dirs: + atlas = self.check_libs2(d, atlas_libs, []) + lapack_atlas = self.check_libs2(d, ['lapack_atlas'], []) + if atlas is not None: + lib_dirs2 = [d] + self.combine_paths(d, ['atlas*', 'ATLAS*']) + lapack = self.check_libs2(lib_dirs2, lapack_libs, []) + if lapack is not None: + break + if atlas: + atlas_1 = atlas + log.info(self.__class__) + if atlas is None: + atlas = atlas_1 + if atlas is None: + return + include_dirs = self.get_include_dirs() + h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) + h = h[0] + if h: + h = os.path.dirname(h) + dict_append(info, include_dirs=[h]) + info['language'] = 'c' + if lapack is not None: + dict_append(info, **lapack) + dict_append(info, **atlas) + elif 'lapack_atlas' in atlas['libraries']: + dict_append(info, **atlas) + dict_append(info, + define_macros=[('ATLAS_WITH_LAPACK_ATLAS', None)]) + self.set_info(**info) + return + else: + dict_append(info, **atlas) + dict_append(info, define_macros=[('ATLAS_WITHOUT_LAPACK', None)]) + message = """ +********************************************************************* + Could not find lapack library within the ATLAS installation. +********************************************************************* +""" + warnings.warn(message, stacklevel=2) + self.set_info(**info) + return + + # Check if lapack library is complete, only warn if it is not. + lapack_dir = lapack['library_dirs'][0] + lapack_name = lapack['libraries'][0] + lapack_lib = None + lib_prefixes = ['lib'] + if sys.platform == 'win32': + lib_prefixes.append('') + for e in self.library_extensions(): + for prefix in lib_prefixes: + fn = os.path.join(lapack_dir, prefix + lapack_name + e) + if os.path.exists(fn): + lapack_lib = fn + break + if lapack_lib: + break + if lapack_lib is not None: + sz = os.stat(lapack_lib)[6] + if sz <= 4000 * 1024: + message = """ +********************************************************************* + Lapack library (from ATLAS) is probably incomplete: + size of %s is %sk (expected >4000k) + + Follow the instructions in the KNOWN PROBLEMS section of the file + numpy/INSTALL.txt. +********************************************************************* +""" % (lapack_lib, sz / 1024) + warnings.warn(message, stacklevel=2) + else: + info['language'] = 'f77' + + atlas_version, atlas_extra_info = get_atlas_version(**atlas) + dict_append(info, **atlas_extra_info) + + self.set_info(**info) + + +class atlas_blas_info(atlas_info): + _lib_names = ['f77blas', 'cblas'] + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + info = {} + atlas_libs = self.get_libs('atlas_libs', + self._lib_names + self._lib_atlas) + atlas = self.check_libs2(lib_dirs, atlas_libs, []) + if atlas is None: + return + include_dirs = self.get_include_dirs() + h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) + h = h[0] + if h: + h = os.path.dirname(h) + dict_append(info, include_dirs=[h]) + info['language'] = 'c' + info['define_macros'] = [('HAVE_CBLAS', None)] + + atlas_version, atlas_extra_info = get_atlas_version(**atlas) + dict_append(atlas, **atlas_extra_info) + + dict_append(info, **atlas) + + self.set_info(**info) + return + + +class atlas_threads_info(atlas_info): + dir_env_var = ['PTATLAS', 'ATLAS'] + _lib_names = ['ptf77blas', 'ptcblas'] + + +class atlas_blas_threads_info(atlas_blas_info): + dir_env_var = ['PTATLAS', 'ATLAS'] + _lib_names = ['ptf77blas', 'ptcblas'] + + +class lapack_atlas_info(atlas_info): + _lib_names = ['lapack_atlas'] + atlas_info._lib_names + + +class lapack_atlas_threads_info(atlas_threads_info): + _lib_names = ['lapack_atlas'] + atlas_threads_info._lib_names + + +class atlas_3_10_info(atlas_info): + _lib_names = ['satlas'] + _lib_atlas = _lib_names + _lib_lapack = _lib_names + + +class atlas_3_10_blas_info(atlas_3_10_info): + _lib_names = ['satlas'] + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + info = {} + atlas_libs = self.get_libs('atlas_libs', + self._lib_names) + atlas = self.check_libs2(lib_dirs, atlas_libs, []) + if atlas is None: + return + include_dirs = self.get_include_dirs() + h = (self.combine_paths(lib_dirs + include_dirs, 'cblas.h') or [None]) + h = h[0] + if h: + h = os.path.dirname(h) + dict_append(info, include_dirs=[h]) + info['language'] = 'c' + info['define_macros'] = [('HAVE_CBLAS', None)] + + atlas_version, atlas_extra_info = get_atlas_version(**atlas) + dict_append(atlas, **atlas_extra_info) + + dict_append(info, **atlas) + + self.set_info(**info) + return + + +class atlas_3_10_threads_info(atlas_3_10_info): + dir_env_var = ['PTATLAS', 'ATLAS'] + _lib_names = ['tatlas'] + _lib_atlas = _lib_names + _lib_lapack = _lib_names + + +class atlas_3_10_blas_threads_info(atlas_3_10_blas_info): + dir_env_var = ['PTATLAS', 'ATLAS'] + _lib_names = ['tatlas'] + + +class lapack_atlas_3_10_info(atlas_3_10_info): + pass + + +class lapack_atlas_3_10_threads_info(atlas_3_10_threads_info): + pass + + +class lapack_info(system_info): + section = 'lapack' + dir_env_var = 'LAPACK' + _lib_names = ['lapack'] + notfounderror = LapackNotFoundError + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + + lapack_libs = self.get_libs('lapack_libs', self._lib_names) + info = self.check_libs(lib_dirs, lapack_libs, []) + if info is None: + return + info['language'] = 'f77' + self.set_info(**info) + + +class lapack_src_info(system_info): + section = 'lapack_src' + dir_env_var = 'LAPACK_SRC' + notfounderror = LapackSrcNotFoundError + + def get_paths(self, section, key): + pre_dirs = system_info.get_paths(self, section, key) + dirs = [] + for d in pre_dirs: + dirs.extend([d] + self.combine_paths(d, ['LAPACK*/SRC', 'SRC'])) + return [d for d in dirs if os.path.isdir(d)] + + def calc_info(self): + src_dirs = self.get_src_dirs() + src_dir = '' + for d in src_dirs: + if os.path.isfile(os.path.join(d, 'dgesv.f')): + src_dir = d + break + if not src_dir: + #XXX: Get sources from netlib. May be ask first. + return + # The following is extracted from LAPACK-3.0/SRC/Makefile. + # Added missing names from lapack-lite-3.1.1/SRC/Makefile + # while keeping removed names for Lapack-3.0 compatibility. + allaux = ''' + ilaenv ieeeck lsame lsamen xerbla + iparmq + ''' # *.f + laux = ''' + bdsdc bdsqr disna labad lacpy ladiv lae2 laebz laed0 laed1 + laed2 laed3 laed4 laed5 laed6 laed7 laed8 laed9 laeda laev2 + lagtf lagts lamch lamrg lanst lapy2 lapy3 larnv larrb larre + larrf lartg laruv las2 lascl lasd0 lasd1 lasd2 lasd3 lasd4 + lasd5 lasd6 lasd7 lasd8 lasd9 lasda lasdq lasdt laset lasq1 + lasq2 lasq3 lasq4 lasq5 lasq6 lasr lasrt lassq lasv2 pttrf + stebz stedc steqr sterf + + larra larrc larrd larr larrk larrj larrr laneg laisnan isnan + lazq3 lazq4 + ''' # [s|d]*.f + lasrc = ''' + gbbrd gbcon gbequ gbrfs gbsv gbsvx gbtf2 gbtrf gbtrs gebak + gebal gebd2 gebrd gecon geequ gees geesx geev geevx gegs gegv + gehd2 gehrd gelq2 gelqf gels gelsd gelss gelsx gelsy geql2 + geqlf geqp3 geqpf geqr2 geqrf gerfs gerq2 gerqf gesc2 gesdd + gesv gesvd gesvx getc2 getf2 getrf getri getrs ggbak ggbal + gges ggesx ggev ggevx ggglm gghrd gglse ggqrf ggrqf ggsvd + ggsvp gtcon gtrfs gtsv gtsvx gttrf gttrs gtts2 hgeqz hsein + hseqr labrd lacon laein lags2 lagtm lahqr lahrd laic1 lals0 + lalsa lalsd langb lange langt lanhs lansb lansp lansy lantb + lantp lantr lapll lapmt laqgb laqge laqp2 laqps laqsb laqsp + laqsy lar1v lar2v larf larfb larfg larft larfx largv larrv + lartv larz larzb larzt laswp lasyf latbs latdf latps latrd + latrs latrz latzm lauu2 lauum pbcon pbequ pbrfs pbstf pbsv + pbsvx pbtf2 pbtrf pbtrs pocon poequ porfs posv posvx potf2 + potrf potri potrs ppcon ppequ pprfs ppsv ppsvx pptrf pptri + pptrs ptcon pteqr ptrfs ptsv ptsvx pttrs ptts2 spcon sprfs + spsv spsvx sptrf sptri sptrs stegr stein sycon syrfs sysv + sysvx sytf2 sytrf sytri sytrs tbcon tbrfs tbtrs tgevc tgex2 + tgexc tgsen tgsja tgsna tgsy2 tgsyl tpcon tprfs tptri tptrs + trcon trevc trexc trrfs trsen trsna trsyl trti2 trtri trtrs + tzrqf tzrzf + + lacn2 lahr2 stemr laqr0 laqr1 laqr2 laqr3 laqr4 laqr5 + ''' # [s|c|d|z]*.f + sd_lasrc = ''' + laexc lag2 lagv2 laln2 lanv2 laqtr lasy2 opgtr opmtr org2l + org2r orgbr orghr orgl2 orglq orgql orgqr orgr2 orgrq orgtr + orm2l orm2r ormbr ormhr orml2 ormlq ormql ormqr ormr2 ormr3 + ormrq ormrz ormtr rscl sbev sbevd sbevx sbgst sbgv sbgvd sbgvx + sbtrd spev spevd spevx spgst spgv spgvd spgvx sptrd stev stevd + stevr stevx syev syevd syevr syevx sygs2 sygst sygv sygvd + sygvx sytd2 sytrd + ''' # [s|d]*.f + cz_lasrc = ''' + bdsqr hbev hbevd hbevx hbgst hbgv hbgvd hbgvx hbtrd hecon heev + heevd heevr heevx hegs2 hegst hegv hegvd hegvx herfs hesv + hesvx hetd2 hetf2 hetrd hetrf hetri hetrs hpcon hpev hpevd + hpevx hpgst hpgv hpgvd hpgvx hprfs hpsv hpsvx hptrd hptrf + hptri hptrs lacgv lacp2 lacpy lacrm lacrt ladiv laed0 laed7 + laed8 laesy laev2 lahef lanhb lanhe lanhp lanht laqhb laqhe + laqhp larcm larnv lartg lascl laset lasr lassq pttrf rot spmv + spr stedc steqr symv syr ung2l ung2r ungbr unghr ungl2 unglq + ungql ungqr ungr2 ungrq ungtr unm2l unm2r unmbr unmhr unml2 + unmlq unmql unmqr unmr2 unmr3 unmrq unmrz unmtr upgtr upmtr + ''' # [c|z]*.f + ####### + sclaux = laux + ' econd ' # s*.f + dzlaux = laux + ' secnd ' # d*.f + slasrc = lasrc + sd_lasrc # s*.f + dlasrc = lasrc + sd_lasrc # d*.f + clasrc = lasrc + cz_lasrc + ' srot srscl ' # c*.f + zlasrc = lasrc + cz_lasrc + ' drot drscl ' # z*.f + oclasrc = ' icmax1 scsum1 ' # *.f + ozlasrc = ' izmax1 dzsum1 ' # *.f + sources = ['s%s.f' % f for f in (sclaux + slasrc).split()] \ + + ['d%s.f' % f for f in (dzlaux + dlasrc).split()] \ + + ['c%s.f' % f for f in (clasrc).split()] \ + + ['z%s.f' % f for f in (zlasrc).split()] \ + + ['%s.f' % f for f in (allaux + oclasrc + ozlasrc).split()] + sources = [os.path.join(src_dir, f) for f in sources] + # Lapack 3.1: + src_dir2 = os.path.join(src_dir, '..', 'INSTALL') + sources += [os.path.join(src_dir2, p + 'lamch.f') for p in 'sdcz'] + # Lapack 3.2.1: + sources += [os.path.join(src_dir, p + 'larfp.f') for p in 'sdcz'] + sources += [os.path.join(src_dir, 'ila' + p + 'lr.f') for p in 'sdcz'] + sources += [os.path.join(src_dir, 'ila' + p + 'lc.f') for p in 'sdcz'] + # Should we check here actual existence of source files? + # Yes, the file listing is different between 3.0 and 3.1 + # versions. + sources = [f for f in sources if os.path.isfile(f)] + info = {'sources': sources, 'language': 'f77'} + self.set_info(**info) + +atlas_version_c_text = r''' +/* This file is generated from numpy/distutils/system_info.py */ +void ATL_buildinfo(void); +int main(void) { + ATL_buildinfo(); + return 0; +} +''' + +_cached_atlas_version = {} + + +def get_atlas_version(**config): + libraries = config.get('libraries', []) + library_dirs = config.get('library_dirs', []) + key = (tuple(libraries), tuple(library_dirs)) + if key in _cached_atlas_version: + return _cached_atlas_version[key] + c = cmd_config(Distribution()) + atlas_version = None + info = {} + try: + s, o = c.get_output(atlas_version_c_text, + libraries=libraries, library_dirs=library_dirs, + use_tee=(system_info.verbosity > 0)) + if s and re.search(r'undefined reference to `_gfortran', o, re.M): + s, o = c.get_output(atlas_version_c_text, + libraries=libraries + ['gfortran'], + library_dirs=library_dirs, + use_tee=(system_info.verbosity > 0)) + if not s: + warnings.warn(""" +***************************************************** +Linkage with ATLAS requires gfortran. Use + + python setup.py config_fc --fcompiler=gnu95 ... + +when building extension libraries that use ATLAS. +Make sure that -lgfortran is used for C++ extensions. +***************************************************** +""", stacklevel=2) + dict_append(info, language='f90', + define_macros=[('ATLAS_REQUIRES_GFORTRAN', None)]) + except Exception: # failed to get version from file -- maybe on Windows + # look at directory name + for o in library_dirs: + m = re.search(r'ATLAS_(?P\d+[.]\d+[.]\d+)_', o) + if m: + atlas_version = m.group('version') + if atlas_version is not None: + break + + # final choice --- look at ATLAS_VERSION environment + # variable + if atlas_version is None: + atlas_version = os.environ.get('ATLAS_VERSION', None) + if atlas_version: + dict_append(info, define_macros=[( + 'ATLAS_INFO', '"\\"%s\\""' % atlas_version) + ]) + else: + dict_append(info, define_macros=[('NO_ATLAS_INFO', -1)]) + return atlas_version or '?.?.?', info + + if not s: + m = re.search(r'ATLAS version (?P\d+[.]\d+[.]\d+)', o) + if m: + atlas_version = m.group('version') + if atlas_version is None: + if re.search(r'undefined symbol: ATL_buildinfo', o, re.M): + atlas_version = '3.2.1_pre3.3.6' + else: + log.info('Status: %d', s) + log.info('Output: %s', o) + + if atlas_version == '3.2.1_pre3.3.6': + dict_append(info, define_macros=[('NO_ATLAS_INFO', -2)]) + else: + dict_append(info, define_macros=[( + 'ATLAS_INFO', '"\\"%s\\""' % atlas_version) + ]) + result = _cached_atlas_version[key] = atlas_version, info + return result + + +class lapack_opt_info(system_info): + + notfounderror = LapackNotFoundError + + def calc_info(self): + + lapack_mkl_info = get_info('lapack_mkl') + if lapack_mkl_info: + self.set_info(**lapack_mkl_info) + return + + openblas_info = get_info('openblas_lapack') + if openblas_info: + self.set_info(**openblas_info) + return + + openblas_info = get_info('openblas_clapack') + if openblas_info: + self.set_info(**openblas_info) + return + + atlas_info = get_info('atlas_3_10_threads') + if not atlas_info: + atlas_info = get_info('atlas_3_10') + if not atlas_info: + atlas_info = get_info('atlas_threads') + if not atlas_info: + atlas_info = get_info('atlas') + + if sys.platform == 'darwin' and not (atlas_info or openblas_info or + lapack_mkl_info): + # Use the system lapack from Accelerate or vecLib under OSX + args = [] + link_args = [] + if get_platform()[-4:] == 'i386' or 'intel' in get_platform() or \ + 'x86_64' in get_platform() or \ + 'i386' in platform.platform(): + intel = 1 + else: + intel = 0 + if os.path.exists('/System/Library/Frameworks' + '/Accelerate.framework/'): + if intel: + args.extend(['-msse3']) + else: + args.extend(['-faltivec']) + link_args.extend(['-Wl,-framework', '-Wl,Accelerate']) + elif os.path.exists('/System/Library/Frameworks' + '/vecLib.framework/'): + if intel: + args.extend(['-msse3']) + else: + args.extend(['-faltivec']) + link_args.extend(['-Wl,-framework', '-Wl,vecLib']) + if args: + self.set_info(extra_compile_args=args, + extra_link_args=link_args, + define_macros=[('NO_ATLAS_INFO', 3), + ('HAVE_CBLAS', None)]) + return + + need_lapack = 0 + need_blas = 0 + info = {} + if atlas_info: + l = atlas_info.get('define_macros', []) + if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \ + or ('ATLAS_WITHOUT_LAPACK', None) in l: + need_lapack = 1 + info = atlas_info + + else: + warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2) + need_blas = 1 + need_lapack = 1 + dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) + + if need_lapack: + lapack_info = get_info('lapack') + #lapack_info = {} ## uncomment for testing + if lapack_info: + dict_append(info, **lapack_info) + else: + warnings.warn(LapackNotFoundError.__doc__, stacklevel=2) + lapack_src_info = get_info('lapack_src') + if not lapack_src_info: + warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=2) + return + dict_append(info, libraries=[('flapack_src', lapack_src_info)]) + + if need_blas: + blas_info = get_info('blas') + if blas_info: + dict_append(info, **blas_info) + else: + warnings.warn(BlasNotFoundError.__doc__, stacklevel=2) + blas_src_info = get_info('blas_src') + if not blas_src_info: + warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2) + return + dict_append(info, libraries=[('fblas_src', blas_src_info)]) + + self.set_info(**info) + return + + +class blas_opt_info(system_info): + + notfounderror = BlasNotFoundError + + def calc_info(self): + + blas_mkl_info = get_info('blas_mkl') + if blas_mkl_info: + self.set_info(**blas_mkl_info) + return + + blis_info = get_info('blis') + if blis_info: + self.set_info(**blis_info) + return + + openblas_info = get_info('openblas') + if openblas_info: + self.set_info(**openblas_info) + return + + atlas_info = get_info('atlas_3_10_blas_threads') + if not atlas_info: + atlas_info = get_info('atlas_3_10_blas') + if not atlas_info: + atlas_info = get_info('atlas_blas_threads') + if not atlas_info: + atlas_info = get_info('atlas_blas') + + if sys.platform == 'darwin' and not (atlas_info or openblas_info or + blas_mkl_info or blis_info): + # Use the system BLAS from Accelerate or vecLib under OSX + args = [] + link_args = [] + if get_platform()[-4:] == 'i386' or 'intel' in get_platform() or \ + 'x86_64' in get_platform() or \ + 'i386' in platform.platform(): + intel = 1 + else: + intel = 0 + if os.path.exists('/System/Library/Frameworks' + '/Accelerate.framework/'): + if intel: + args.extend(['-msse3']) + else: + args.extend(['-faltivec']) + args.extend([ + '-I/System/Library/Frameworks/vecLib.framework/Headers']) + link_args.extend(['-Wl,-framework', '-Wl,Accelerate']) + elif os.path.exists('/System/Library/Frameworks' + '/vecLib.framework/'): + if intel: + args.extend(['-msse3']) + else: + args.extend(['-faltivec']) + args.extend([ + '-I/System/Library/Frameworks/vecLib.framework/Headers']) + link_args.extend(['-Wl,-framework', '-Wl,vecLib']) + if args: + self.set_info(extra_compile_args=args, + extra_link_args=link_args, + define_macros=[('NO_ATLAS_INFO', 3), + ('HAVE_CBLAS', None)]) + return + + need_blas = 0 + info = {} + if atlas_info: + info = atlas_info + else: + warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2) + need_blas = 1 + dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) + + if need_blas: + blas_info = get_info('blas') + if blas_info: + dict_append(info, **blas_info) + else: + warnings.warn(BlasNotFoundError.__doc__, stacklevel=2) + blas_src_info = get_info('blas_src') + if not blas_src_info: + warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2) + return + dict_append(info, libraries=[('fblas_src', blas_src_info)]) + + self.set_info(**info) + return + + +class blas_info(system_info): + section = 'blas' + dir_env_var = 'BLAS' + _lib_names = ['blas'] + notfounderror = BlasNotFoundError + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + blas_libs = self.get_libs('blas_libs', self._lib_names) + info = self.check_libs(lib_dirs, blas_libs, []) + if info is None: + return + else: + info['include_dirs'] = self.get_include_dirs() + if platform.system() == 'Windows': + # The check for windows is needed because has_cblas uses the + # same compiler that was used to compile Python and msvc is + # often not installed when mingw is being used. This rough + # treatment is not desirable, but windows is tricky. + info['language'] = 'f77' # XXX: is it generally true? + else: + lib = self.has_cblas(info) + if lib is not None: + info['language'] = 'c' + info['libraries'] = [lib] + info['define_macros'] = [('HAVE_CBLAS', None)] + self.set_info(**info) + + def has_cblas(self, info): + # primitive cblas check by looking for the header and trying to link + # cblas or blas + res = False + c = customized_ccompiler() + tmpdir = tempfile.mkdtemp() + s = """#include + int main(int argc, const char *argv[]) + { + double a[4] = {1,2,3,4}; + double b[4] = {5,6,7,8}; + return cblas_ddot(4, a, 1, b, 1) > 10; + }""" + src = os.path.join(tmpdir, 'source.c') + try: + with open(src, 'wt') as f: + f.write(s) + + try: + # check we can compile (find headers) + obj = c.compile([src], output_dir=tmpdir, + include_dirs=self.get_include_dirs()) + + # check we can link (find library) + # some systems have separate cblas and blas libs. First + # check for cblas lib, and if not present check for blas lib. + try: + c.link_executable(obj, os.path.join(tmpdir, "a.out"), + libraries=["cblas"], + library_dirs=info['library_dirs'], + extra_postargs=info.get('extra_link_args', [])) + res = "cblas" + except distutils.ccompiler.LinkError: + c.link_executable(obj, os.path.join(tmpdir, "a.out"), + libraries=["blas"], + library_dirs=info['library_dirs'], + extra_postargs=info.get('extra_link_args', [])) + res = "blas" + except distutils.ccompiler.CompileError: + res = None + finally: + shutil.rmtree(tmpdir) + return res + + +class openblas_info(blas_info): + section = 'openblas' + dir_env_var = 'OPENBLAS' + _lib_names = ['openblas'] + notfounderror = BlasNotFoundError + + def check_embedded_lapack(self, info): + return True + + def calc_info(self): + c = customized_ccompiler() + + lib_dirs = self.get_lib_dirs() + + openblas_libs = self.get_libs('libraries', self._lib_names) + if openblas_libs == self._lib_names: # backward compat with 1.8.0 + openblas_libs = self.get_libs('openblas_libs', self._lib_names) + + info = self.check_libs(lib_dirs, openblas_libs, []) + + if c.compiler_type == "msvc" and info is None: + from numpy.distutils.fcompiler import new_fcompiler + f = new_fcompiler(c_compiler=c) + if f and f.compiler_type == 'gnu95': + # Try gfortran-compatible library files + info = self.check_msvc_gfortran_libs(lib_dirs, openblas_libs) + # Skip lapack check, we'd need build_ext to do it + assume_lapack = True + elif info: + assume_lapack = False + info['language'] = 'c' + + if info is None: + return + + # Add extra info for OpenBLAS + extra_info = self.calc_extra_info() + dict_append(info, **extra_info) + + if not (assume_lapack or self.check_embedded_lapack(info)): + return + + info['define_macros'] = [('HAVE_CBLAS', None)] + self.set_info(**info) + + def check_msvc_gfortran_libs(self, library_dirs, libraries): + # First, find the full path to each library directory + library_paths = [] + for library in libraries: + for library_dir in library_dirs: + # MinGW static ext will be .a + fullpath = os.path.join(library_dir, library + '.a') + if os.path.isfile(fullpath): + library_paths.append(fullpath) + break + else: + return None + + # Generate numpy.distutils virtual static library file + tmpdir = os.path.join(os.getcwd(), 'build', 'openblas') + if not os.path.isdir(tmpdir): + os.makedirs(tmpdir) + + info = {'library_dirs': [tmpdir], + 'libraries': ['openblas'], + 'language': 'f77'} + + fake_lib_file = os.path.join(tmpdir, 'openblas.fobjects') + fake_clib_file = os.path.join(tmpdir, 'openblas.cobjects') + with open(fake_lib_file, 'w') as f: + f.write("\n".join(library_paths)) + with open(fake_clib_file, 'w') as f: + pass + + return info + +class openblas_lapack_info(openblas_info): + section = 'openblas' + dir_env_var = 'OPENBLAS' + _lib_names = ['openblas'] + notfounderror = BlasNotFoundError + + def check_embedded_lapack(self, info): + res = False + c = customized_ccompiler() + + tmpdir = tempfile.mkdtemp() + s = """void zungqr_(); + int main(int argc, const char *argv[]) + { + zungqr_(); + return 0; + }""" + src = os.path.join(tmpdir, 'source.c') + out = os.path.join(tmpdir, 'a.out') + # Add the additional "extra" arguments + try: + extra_args = info['extra_link_args'] + except Exception: + extra_args = [] + if sys.version_info < (3, 5) and sys.version_info > (3, 0) and c.compiler_type == "msvc": + extra_args.append("/MANIFEST") + try: + with open(src, 'wt') as f: + f.write(s) + obj = c.compile([src], output_dir=tmpdir) + try: + c.link_executable(obj, out, libraries=info['libraries'], + library_dirs=info['library_dirs'], + extra_postargs=extra_args) + res = True + except distutils.ccompiler.LinkError: + res = False + finally: + shutil.rmtree(tmpdir) + return res + +class openblas_clapack_info(openblas_lapack_info): + _lib_names = ['openblas', 'lapack'] + +class blis_info(blas_info): + section = 'blis' + dir_env_var = 'BLIS' + _lib_names = ['blis'] + notfounderror = BlasNotFoundError + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + blis_libs = self.get_libs('libraries', self._lib_names) + if blis_libs == self._lib_names: + blis_libs = self.get_libs('blis_libs', self._lib_names) + + info = self.check_libs2(lib_dirs, blis_libs, []) + if info is None: + return + + # Add include dirs + incl_dirs = self.get_include_dirs() + dict_append(info, + language='c', + define_macros=[('HAVE_CBLAS', None)], + include_dirs=incl_dirs) + self.set_info(**info) + + +class blas_src_info(system_info): + section = 'blas_src' + dir_env_var = 'BLAS_SRC' + notfounderror = BlasSrcNotFoundError + + def get_paths(self, section, key): + pre_dirs = system_info.get_paths(self, section, key) + dirs = [] + for d in pre_dirs: + dirs.extend([d] + self.combine_paths(d, ['blas'])) + return [d for d in dirs if os.path.isdir(d)] + + def calc_info(self): + src_dirs = self.get_src_dirs() + src_dir = '' + for d in src_dirs: + if os.path.isfile(os.path.join(d, 'daxpy.f')): + src_dir = d + break + if not src_dir: + #XXX: Get sources from netlib. May be ask first. + return + blas1 = ''' + caxpy csscal dnrm2 dzasum saxpy srotg zdotc ccopy cswap drot + dznrm2 scasum srotm zdotu cdotc dasum drotg icamax scnrm2 + srotmg zdrot cdotu daxpy drotm idamax scopy sscal zdscal crotg + dcabs1 drotmg isamax sdot sswap zrotg cscal dcopy dscal izamax + snrm2 zaxpy zscal csrot ddot dswap sasum srot zcopy zswap + scabs1 + ''' + blas2 = ''' + cgbmv chpmv ctrsv dsymv dtrsv sspr2 strmv zhemv ztpmv cgemv + chpr dgbmv dsyr lsame ssymv strsv zher ztpsv cgerc chpr2 dgemv + dsyr2 sgbmv ssyr xerbla zher2 ztrmv cgeru ctbmv dger dtbmv + sgemv ssyr2 zgbmv zhpmv ztrsv chbmv ctbsv dsbmv dtbsv sger + stbmv zgemv zhpr chemv ctpmv dspmv dtpmv ssbmv stbsv zgerc + zhpr2 cher ctpsv dspr dtpsv sspmv stpmv zgeru ztbmv cher2 + ctrmv dspr2 dtrmv sspr stpsv zhbmv ztbsv + ''' + blas3 = ''' + cgemm csymm ctrsm dsyrk sgemm strmm zhemm zsyr2k chemm csyr2k + dgemm dtrmm ssymm strsm zher2k zsyrk cher2k csyrk dsymm dtrsm + ssyr2k zherk ztrmm cherk ctrmm dsyr2k ssyrk zgemm zsymm ztrsm + ''' + sources = [os.path.join(src_dir, f + '.f') \ + for f in (blas1 + blas2 + blas3).split()] + #XXX: should we check here actual existence of source files? + sources = [f for f in sources if os.path.isfile(f)] + info = {'sources': sources, 'language': 'f77'} + self.set_info(**info) + + +class x11_info(system_info): + section = 'x11' + notfounderror = X11NotFoundError + + def __init__(self): + system_info.__init__(self, + default_lib_dirs=default_x11_lib_dirs, + default_include_dirs=default_x11_include_dirs) + + def calc_info(self): + if sys.platform in ['win32']: + return + lib_dirs = self.get_lib_dirs() + include_dirs = self.get_include_dirs() + x11_libs = self.get_libs('x11_libs', ['X11']) + info = self.check_libs(lib_dirs, x11_libs, []) + if info is None: + return + inc_dir = None + for d in include_dirs: + if self.combine_paths(d, 'X11/X.h'): + inc_dir = d + break + if inc_dir is not None: + dict_append(info, include_dirs=[inc_dir]) + self.set_info(**info) + + +class _numpy_info(system_info): + section = 'Numeric' + modulename = 'Numeric' + notfounderror = NumericNotFoundError + + def __init__(self): + include_dirs = [] + try: + module = __import__(self.modulename) + prefix = [] + for name in module.__file__.split(os.sep): + if name == 'lib': + break + prefix.append(name) + + # Ask numpy for its own include path before attempting + # anything else + try: + include_dirs.append(getattr(module, 'get_include')()) + except AttributeError: + pass + + include_dirs.append(distutils.sysconfig.get_python_inc( + prefix=os.sep.join(prefix))) + except ImportError: + pass + py_incl_dir = distutils.sysconfig.get_python_inc() + include_dirs.append(py_incl_dir) + py_pincl_dir = distutils.sysconfig.get_python_inc(plat_specific=True) + if py_pincl_dir not in include_dirs: + include_dirs.append(py_pincl_dir) + for d in default_include_dirs: + d = os.path.join(d, os.path.basename(py_incl_dir)) + if d not in include_dirs: + include_dirs.append(d) + system_info.__init__(self, + default_lib_dirs=[], + default_include_dirs=include_dirs) + + def calc_info(self): + try: + module = __import__(self.modulename) + except ImportError: + return + info = {} + macros = [] + for v in ['__version__', 'version']: + vrs = getattr(module, v, None) + if vrs is None: + continue + macros = [(self.modulename.upper() + '_VERSION', + '"\\"%s\\""' % (vrs)), + (self.modulename.upper(), None)] + break + dict_append(info, define_macros=macros) + include_dirs = self.get_include_dirs() + inc_dir = None + for d in include_dirs: + if self.combine_paths(d, + os.path.join(self.modulename, + 'arrayobject.h')): + inc_dir = d + break + if inc_dir is not None: + dict_append(info, include_dirs=[inc_dir]) + if info: + self.set_info(**info) + return + + +class numarray_info(_numpy_info): + section = 'numarray' + modulename = 'numarray' + + +class Numeric_info(_numpy_info): + section = 'Numeric' + modulename = 'Numeric' + + +class numpy_info(_numpy_info): + section = 'numpy' + modulename = 'numpy' + + +class numerix_info(system_info): + section = 'numerix' + + def calc_info(self): + which = None, None + if os.getenv("NUMERIX"): + which = os.getenv("NUMERIX"), "environment var" + # If all the above fail, default to numpy. + if which[0] is None: + which = "numpy", "defaulted" + try: + import numpy + which = "numpy", "defaulted" + except ImportError: + msg1 = str(get_exception()) + try: + import Numeric + which = "numeric", "defaulted" + except ImportError: + msg2 = str(get_exception()) + try: + import numarray + which = "numarray", "defaulted" + except ImportError: + msg3 = str(get_exception()) + log.info(msg1) + log.info(msg2) + log.info(msg3) + which = which[0].strip().lower(), which[1] + if which[0] not in ["numeric", "numarray", "numpy"]: + raise ValueError("numerix selector must be either 'Numeric' " + "or 'numarray' or 'numpy' but the value obtained" + " from the %s was '%s'." % (which[1], which[0])) + os.environ['NUMERIX'] = which[0] + self.set_info(**get_info(which[0])) + + +class f2py_info(system_info): + def calc_info(self): + try: + import numpy.f2py as f2py + except ImportError: + return + f2py_dir = os.path.join(os.path.dirname(f2py.__file__), 'src') + self.set_info(sources=[os.path.join(f2py_dir, 'fortranobject.c')], + include_dirs=[f2py_dir]) + return + + +class boost_python_info(system_info): + section = 'boost_python' + dir_env_var = 'BOOST' + + def get_paths(self, section, key): + pre_dirs = system_info.get_paths(self, section, key) + dirs = [] + for d in pre_dirs: + dirs.extend([d] + self.combine_paths(d, ['boost*'])) + return [d for d in dirs if os.path.isdir(d)] + + def calc_info(self): + src_dirs = self.get_src_dirs() + src_dir = '' + for d in src_dirs: + if os.path.isfile(os.path.join(d, 'libs', 'python', 'src', + 'module.cpp')): + src_dir = d + break + if not src_dir: + return + py_incl_dirs = [distutils.sysconfig.get_python_inc()] + py_pincl_dir = distutils.sysconfig.get_python_inc(plat_specific=True) + if py_pincl_dir not in py_incl_dirs: + py_incl_dirs.append(py_pincl_dir) + srcs_dir = os.path.join(src_dir, 'libs', 'python', 'src') + bpl_srcs = glob(os.path.join(srcs_dir, '*.cpp')) + bpl_srcs += glob(os.path.join(srcs_dir, '*', '*.cpp')) + info = {'libraries': [('boost_python_src', + {'include_dirs': [src_dir] + py_incl_dirs, + 'sources':bpl_srcs} + )], + 'include_dirs': [src_dir], + } + if info: + self.set_info(**info) + return + + +class agg2_info(system_info): + section = 'agg2' + dir_env_var = 'AGG2' + + def get_paths(self, section, key): + pre_dirs = system_info.get_paths(self, section, key) + dirs = [] + for d in pre_dirs: + dirs.extend([d] + self.combine_paths(d, ['agg2*'])) + return [d for d in dirs if os.path.isdir(d)] + + def calc_info(self): + src_dirs = self.get_src_dirs() + src_dir = '' + for d in src_dirs: + if os.path.isfile(os.path.join(d, 'src', 'agg_affine_matrix.cpp')): + src_dir = d + break + if not src_dir: + return + if sys.platform == 'win32': + agg2_srcs = glob(os.path.join(src_dir, 'src', 'platform', + 'win32', 'agg_win32_bmp.cpp')) + else: + agg2_srcs = glob(os.path.join(src_dir, 'src', '*.cpp')) + agg2_srcs += [os.path.join(src_dir, 'src', 'platform', + 'X11', + 'agg_platform_support.cpp')] + + info = {'libraries': + [('agg2_src', + {'sources': agg2_srcs, + 'include_dirs': [os.path.join(src_dir, 'include')], + } + )], + 'include_dirs': [os.path.join(src_dir, 'include')], + } + if info: + self.set_info(**info) + return + + +class _pkg_config_info(system_info): + section = None + config_env_var = 'PKG_CONFIG' + default_config_exe = 'pkg-config' + append_config_exe = '' + version_macro_name = None + release_macro_name = None + version_flag = '--modversion' + cflags_flag = '--cflags' + + def get_config_exe(self): + if self.config_env_var in os.environ: + return os.environ[self.config_env_var] + return self.default_config_exe + + def get_config_output(self, config_exe, option): + cmd = config_exe + ' ' + self.append_config_exe + ' ' + option + s, o = exec_command(cmd, use_tee=0) + if not s: + return o + + def calc_info(self): + config_exe = find_executable(self.get_config_exe()) + if not config_exe: + log.warn('File not found: %s. Cannot determine %s info.' \ + % (config_exe, self.section)) + return + info = {} + macros = [] + libraries = [] + library_dirs = [] + include_dirs = [] + extra_link_args = [] + extra_compile_args = [] + version = self.get_config_output(config_exe, self.version_flag) + if version: + macros.append((self.__class__.__name__.split('.')[-1].upper(), + '"\\"%s\\""' % (version))) + if self.version_macro_name: + macros.append((self.version_macro_name + '_%s' + % (version.replace('.', '_')), None)) + if self.release_macro_name: + release = self.get_config_output(config_exe, '--release') + if release: + macros.append((self.release_macro_name + '_%s' + % (release.replace('.', '_')), None)) + opts = self.get_config_output(config_exe, '--libs') + if opts: + for opt in opts.split(): + if opt[:2] == '-l': + libraries.append(opt[2:]) + elif opt[:2] == '-L': + library_dirs.append(opt[2:]) + else: + extra_link_args.append(opt) + opts = self.get_config_output(config_exe, self.cflags_flag) + if opts: + for opt in opts.split(): + if opt[:2] == '-I': + include_dirs.append(opt[2:]) + elif opt[:2] == '-D': + if '=' in opt: + n, v = opt[2:].split('=') + macros.append((n, v)) + else: + macros.append((opt[2:], None)) + else: + extra_compile_args.append(opt) + if macros: + dict_append(info, define_macros=macros) + if libraries: + dict_append(info, libraries=libraries) + if library_dirs: + dict_append(info, library_dirs=library_dirs) + if include_dirs: + dict_append(info, include_dirs=include_dirs) + if extra_link_args: + dict_append(info, extra_link_args=extra_link_args) + if extra_compile_args: + dict_append(info, extra_compile_args=extra_compile_args) + if info: + self.set_info(**info) + return + + +class wx_info(_pkg_config_info): + section = 'wx' + config_env_var = 'WX_CONFIG' + default_config_exe = 'wx-config' + append_config_exe = '' + version_macro_name = 'WX_VERSION' + release_macro_name = 'WX_RELEASE' + version_flag = '--version' + cflags_flag = '--cxxflags' + + +class gdk_pixbuf_xlib_2_info(_pkg_config_info): + section = 'gdk_pixbuf_xlib_2' + append_config_exe = 'gdk-pixbuf-xlib-2.0' + version_macro_name = 'GDK_PIXBUF_XLIB_VERSION' + + +class gdk_pixbuf_2_info(_pkg_config_info): + section = 'gdk_pixbuf_2' + append_config_exe = 'gdk-pixbuf-2.0' + version_macro_name = 'GDK_PIXBUF_VERSION' + + +class gdk_x11_2_info(_pkg_config_info): + section = 'gdk_x11_2' + append_config_exe = 'gdk-x11-2.0' + version_macro_name = 'GDK_X11_VERSION' + + +class gdk_2_info(_pkg_config_info): + section = 'gdk_2' + append_config_exe = 'gdk-2.0' + version_macro_name = 'GDK_VERSION' + + +class gdk_info(_pkg_config_info): + section = 'gdk' + append_config_exe = 'gdk' + version_macro_name = 'GDK_VERSION' + + +class gtkp_x11_2_info(_pkg_config_info): + section = 'gtkp_x11_2' + append_config_exe = 'gtk+-x11-2.0' + version_macro_name = 'GTK_X11_VERSION' + + +class gtkp_2_info(_pkg_config_info): + section = 'gtkp_2' + append_config_exe = 'gtk+-2.0' + version_macro_name = 'GTK_VERSION' + + +class xft_info(_pkg_config_info): + section = 'xft' + append_config_exe = 'xft' + version_macro_name = 'XFT_VERSION' + + +class freetype2_info(_pkg_config_info): + section = 'freetype2' + append_config_exe = 'freetype2' + version_macro_name = 'FREETYPE2_VERSION' + + +class amd_info(system_info): + section = 'amd' + dir_env_var = 'AMD' + _lib_names = ['amd'] + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + + amd_libs = self.get_libs('amd_libs', self._lib_names) + info = self.check_libs(lib_dirs, amd_libs, []) + if info is None: + return + + include_dirs = self.get_include_dirs() + + inc_dir = None + for d in include_dirs: + p = self.combine_paths(d, 'amd.h') + if p: + inc_dir = os.path.dirname(p[0]) + break + if inc_dir is not None: + dict_append(info, include_dirs=[inc_dir], + define_macros=[('SCIPY_AMD_H', None)], + swig_opts=['-I' + inc_dir]) + + self.set_info(**info) + return + + +class umfpack_info(system_info): + section = 'umfpack' + dir_env_var = 'UMFPACK' + notfounderror = UmfpackNotFoundError + _lib_names = ['umfpack'] + + def calc_info(self): + lib_dirs = self.get_lib_dirs() + + umfpack_libs = self.get_libs('umfpack_libs', self._lib_names) + info = self.check_libs(lib_dirs, umfpack_libs, []) + if info is None: + return + + include_dirs = self.get_include_dirs() + + inc_dir = None + for d in include_dirs: + p = self.combine_paths(d, ['', 'umfpack'], 'umfpack.h') + if p: + inc_dir = os.path.dirname(p[0]) + break + if inc_dir is not None: + dict_append(info, include_dirs=[inc_dir], + define_macros=[('SCIPY_UMFPACK_H', None)], + swig_opts=['-I' + inc_dir]) + + amd = get_info('amd') + dict_append(info, **get_info('amd')) + + self.set_info(**info) + return + + +def combine_paths(*args, **kws): + """ Return a list of existing paths composed by all combinations of + items from arguments. + """ + r = [] + for a in args: + if not a: + continue + if is_string(a): + a = [a] + r.append(a) + args = r + if not args: + return [] + if len(args) == 1: + result = reduce(lambda a, b: a + b, map(glob, args[0]), []) + elif len(args) == 2: + result = [] + for a0 in args[0]: + for a1 in args[1]: + result.extend(glob(os.path.join(a0, a1))) + else: + result = combine_paths(*(combine_paths(args[0], args[1]) + args[2:])) + log.debug('(paths: %s)', ','.join(result)) + return result + +language_map = {'c': 0, 'c++': 1, 'f77': 2, 'f90': 3} +inv_language_map = {0: 'c', 1: 'c++', 2: 'f77', 3: 'f90'} + + +def dict_append(d, **kws): + languages = [] + for k, v in kws.items(): + if k == 'language': + languages.append(v) + continue + if k in d: + if k in ['library_dirs', 'include_dirs', + 'extra_compile_args', 'extra_link_args', + 'runtime_library_dirs', 'define_macros']: + [d[k].append(vv) for vv in v if vv not in d[k]] + else: + d[k].extend(v) + else: + d[k] = v + if languages: + l = inv_language_map[max([language_map.get(l, 0) for l in languages])] + d['language'] = l + return + + +def parseCmdLine(argv=(None,)): + import optparse + parser = optparse.OptionParser("usage: %prog [-v] [info objs]") + parser.add_option('-v', '--verbose', action='store_true', dest='verbose', + default=False, + help='be verbose and print more messages') + + opts, args = parser.parse_args(args=argv[1:]) + return opts, args + + +def show_all(argv=None): + import inspect + if argv is None: + argv = sys.argv + opts, args = parseCmdLine(argv) + if opts.verbose: + log.set_threshold(log.DEBUG) + else: + log.set_threshold(log.INFO) + show_only = [] + for n in args: + if n[-5:] != '_info': + n = n + '_info' + show_only.append(n) + show_all = not show_only + _gdict_ = globals().copy() + for name, c in _gdict_.items(): + if not inspect.isclass(c): + continue + if not issubclass(c, system_info) or c is system_info: + continue + if not show_all: + if name not in show_only: + continue + del show_only[show_only.index(name)] + conf = c() + conf.verbosity = 2 + r = conf.get_info() + if show_only: + log.info('Info classes not defined: %s', ','.join(show_only)) + +if __name__ == "__main__": + show_all() diff --git a/numpy/distutils/tests/__init__.py b/numpy/distutils/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/distutils/tests/__init__.py diff --git a/numpy/distutils/tests/test_exec_command.py b/numpy/distutils/tests/test_exec_command.py new file mode 100644 index 0000000..5e7b3f3 --- /dev/null +++ b/numpy/distutils/tests/test_exec_command.py @@ -0,0 +1,219 @@ +from __future__ import division, absolute_import, print_function + +import os +import sys +from tempfile import TemporaryFile + +from numpy.distutils import exec_command +from numpy.distutils.exec_command import get_pythonexe +from numpy.testing import run_module_suite, tempdir, assert_ + +# In python 3 stdout, stderr are text (unicode compliant) devices, so to +# emulate them import StringIO from the io module. +if sys.version_info[0] >= 3: + from io import StringIO +else: + from StringIO import StringIO + +class redirect_stdout(object): + """Context manager to redirect stdout for exec_command test.""" + def __init__(self, stdout=None): + self._stdout = stdout or sys.stdout + + def __enter__(self): + self.old_stdout = sys.stdout + sys.stdout = self._stdout + + def __exit__(self, exc_type, exc_value, traceback): + self._stdout.flush() + sys.stdout = self.old_stdout + # note: closing sys.stdout won't close it. + self._stdout.close() + +class redirect_stderr(object): + """Context manager to redirect stderr for exec_command test.""" + def __init__(self, stderr=None): + self._stderr = stderr or sys.stderr + + def __enter__(self): + self.old_stderr = sys.stderr + sys.stderr = self._stderr + + def __exit__(self, exc_type, exc_value, traceback): + self._stderr.flush() + sys.stderr = self.old_stderr + # note: closing sys.stderr won't close it. + self._stderr.close() + +class emulate_nonposix(object): + """Context manager to emulate os.name != 'posix' """ + def __init__(self, osname='non-posix'): + self._new_name = osname + + def __enter__(self): + self._old_name = os.name + os.name = self._new_name + + def __exit__(self, exc_type, exc_value, traceback): + os.name = self._old_name + + +def test_exec_command_stdout(): + # Regression test for gh-2999 and gh-2915. + # There are several packages (nose, scipy.weave.inline, Sage inline + # Fortran) that replace stdout, in which case it doesn't have a fileno + # method. This is tested here, with a do-nothing command that fails if the + # presence of fileno() is assumed in exec_command. + + # The code has a special case for posix systems, so if we are on posix test + # both that the special case works and that the generic code works. + + # Test posix version: + with redirect_stdout(StringIO()): + with redirect_stderr(TemporaryFile()): + exec_command.exec_command("cd '.'") + + if os.name == 'posix': + # Test general (non-posix) version: + with emulate_nonposix(): + with redirect_stdout(StringIO()): + with redirect_stderr(TemporaryFile()): + exec_command.exec_command("cd '.'") + +def test_exec_command_stderr(): + # Test posix version: + with redirect_stdout(TemporaryFile(mode='w+')): + with redirect_stderr(StringIO()): + exec_command.exec_command("cd '.'") + + if os.name == 'posix': + # Test general (non-posix) version: + with emulate_nonposix(): + with redirect_stdout(TemporaryFile()): + with redirect_stderr(StringIO()): + exec_command.exec_command("cd '.'") + + +class TestExecCommand(object): + def setup(self): + self.pyexe = get_pythonexe() + + def check_nt(self, **kws): + s, o = exec_command.exec_command('cmd /C echo path=%path%') + assert_(s == 0) + assert_(o != '') + + s, o = exec_command.exec_command( + '"%s" -c "import sys;sys.stderr.write(sys.platform)"' % self.pyexe) + assert_(s == 0) + assert_(o == 'win32') + + def check_posix(self, **kws): + s, o = exec_command.exec_command("echo Hello", **kws) + assert_(s == 0) + assert_(o == 'Hello') + + s, o = exec_command.exec_command('echo $AAA', **kws) + assert_(s == 0) + assert_(o == '') + + s, o = exec_command.exec_command('echo "$AAA"', AAA='Tere', **kws) + assert_(s == 0) + assert_(o == 'Tere') + + s, o = exec_command.exec_command('echo "$AAA"', **kws) + assert_(s == 0) + assert_(o == '') + + if 'BBB' not in os.environ: + os.environ['BBB'] = 'Hi' + s, o = exec_command.exec_command('echo "$BBB"', **kws) + assert_(s == 0) + assert_(o == 'Hi') + + s, o = exec_command.exec_command('echo "$BBB"', BBB='Hey', **kws) + assert_(s == 0) + assert_(o == 'Hey') + + s, o = exec_command.exec_command('echo "$BBB"', **kws) + assert_(s == 0) + assert_(o == 'Hi') + + del os.environ['BBB'] + + s, o = exec_command.exec_command('echo "$BBB"', **kws) + assert_(s == 0) + assert_(o == '') + + + s, o = exec_command.exec_command('this_is_not_a_command', **kws) + assert_(s != 0) + assert_(o != '') + + s, o = exec_command.exec_command('echo path=$PATH', **kws) + assert_(s == 0) + assert_(o != '') + + s, o = exec_command.exec_command( + '"%s" -c "import sys,os;sys.stderr.write(os.name)"' % + self.pyexe, **kws) + assert_(s == 0) + assert_(o == 'posix') + + def check_basic(self, *kws): + s, o = exec_command.exec_command( + '"%s" -c "raise \'Ignore me.\'"' % self.pyexe, **kws) + assert_(s != 0) + assert_(o != '') + + s, o = exec_command.exec_command( + '"%s" -c "import sys;sys.stderr.write(\'0\');' + 'sys.stderr.write(\'1\');sys.stderr.write(\'2\')"' % + self.pyexe, **kws) + assert_(s == 0) + assert_(o == '012') + + s, o = exec_command.exec_command( + '"%s" -c "import sys;sys.exit(15)"' % self.pyexe, **kws) + assert_(s == 15) + assert_(o == '') + + s, o = exec_command.exec_command( + '"%s" -c "print(\'Heipa\'")' % self.pyexe, **kws) + assert_(s == 0) + assert_(o == 'Heipa') + + def check_execute_in(self, **kws): + with tempdir() as tmpdir: + fn = "file" + tmpfile = os.path.join(tmpdir, fn) + f = open(tmpfile, 'w') + f.write('Hello') + f.close() + + s, o = exec_command.exec_command( + '"%s" -c "f = open(\'%s\', \'r\'); f.close()"' % + (self.pyexe, fn), **kws) + assert_(s != 0) + assert_(o != '') + s, o = exec_command.exec_command( + '"%s" -c "f = open(\'%s\', \'r\'); print(f.read()); ' + 'f.close()"' % (self.pyexe, fn), execute_in=tmpdir, **kws) + assert_(s == 0) + assert_(o == 'Hello') + + def test_basic(self): + with redirect_stdout(StringIO()): + with redirect_stderr(StringIO()): + if os.name == "posix": + self.check_posix(use_tee=0) + self.check_posix(use_tee=1) + elif os.name == "nt": + self.check_nt(use_tee=0) + self.check_nt(use_tee=1) + self.check_execute_in(use_tee=0) + self.check_execute_in(use_tee=1) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/distutils/tests/test_fcompiler_gnu.py b/numpy/distutils/tests/test_fcompiler_gnu.py new file mode 100644 index 0000000..6595205 --- /dev/null +++ b/numpy/distutils/tests/test_fcompiler_gnu.py @@ -0,0 +1,61 @@ +from __future__ import division, absolute_import, print_function + +from numpy.testing import assert_, run_module_suite + +import numpy.distutils.fcompiler + +g77_version_strings = [ + ('GNU Fortran 0.5.25 20010319 (prerelease)', '0.5.25'), + ('GNU Fortran (GCC 3.2) 3.2 20020814 (release)', '3.2'), + ('GNU Fortran (GCC) 3.3.3 20040110 (prerelease) (Debian)', '3.3.3'), + ('GNU Fortran (GCC) 3.3.3 (Debian 20040401)', '3.3.3'), + ('GNU Fortran (GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) 3.2.2' + ' 20030222 (Red Hat Linux 3.2.2-5)', '3.2.2'), +] + +gfortran_version_strings = [ + ('GNU Fortran 95 (GCC 4.0.3 20051023 (prerelease) (Debian 4.0.2-3))', + '4.0.3'), + ('GNU Fortran 95 (GCC) 4.1.0', '4.1.0'), + ('GNU Fortran 95 (GCC) 4.2.0 20060218 (experimental)', '4.2.0'), + ('GNU Fortran (GCC) 4.3.0 20070316 (experimental)', '4.3.0'), + ('GNU Fortran (rubenvb-4.8.0) 4.8.0', '4.8.0'), + ('4.8.0', '4.8.0'), + ('4.0.3-7', '4.0.3'), + ("gfortran: warning: couldn't understand kern.osversion '14.1.0\n4.9.1", + '4.9.1'), + ("gfortran: warning: couldn't understand kern.osversion '14.1.0\n" + "gfortran: warning: yet another warning\n4.9.1", + '4.9.1'), + ('GNU Fortran (crosstool-NG 8a21ab48) 7.2.0', '7.2.0') +] + +class TestG77Versions(object): + def test_g77_version(self): + fc = numpy.distutils.fcompiler.new_fcompiler(compiler='gnu') + for vs, version in g77_version_strings: + v = fc.version_match(vs) + assert_(v == version, (vs, v)) + + def test_not_g77(self): + fc = numpy.distutils.fcompiler.new_fcompiler(compiler='gnu') + for vs, _ in gfortran_version_strings: + v = fc.version_match(vs) + assert_(v is None, (vs, v)) + +class TestGFortranVersions(object): + def test_gfortran_version(self): + fc = numpy.distutils.fcompiler.new_fcompiler(compiler='gnu95') + for vs, version in gfortran_version_strings: + v = fc.version_match(vs) + assert_(v == version, (vs, v)) + + def test_not_gfortran(self): + fc = numpy.distutils.fcompiler.new_fcompiler(compiler='gnu95') + for vs, _ in g77_version_strings: + v = fc.version_match(vs) + assert_(v is None, (vs, v)) + + +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/distutils/tests/test_fcompiler_intel.py b/numpy/distutils/tests/test_fcompiler_intel.py new file mode 100644 index 0000000..b13a017 --- /dev/null +++ b/numpy/distutils/tests/test_fcompiler_intel.py @@ -0,0 +1,36 @@ +from __future__ import division, absolute_import, print_function + +import numpy.distutils.fcompiler +from numpy.testing import run_module_suite, assert_ + + +intel_32bit_version_strings = [ + ("Intel(R) Fortran Intel(R) 32-bit Compiler Professional for applications" + "running on Intel(R) 32, Version 11.1", '11.1'), +] + +intel_64bit_version_strings = [ + ("Intel(R) Fortran IA-64 Compiler Professional for applications" + "running on IA-64, Version 11.0", '11.0'), + ("Intel(R) Fortran Intel(R) 64 Compiler Professional for applications" + "running on Intel(R) 64, Version 11.1", '11.1') +] + +class TestIntelFCompilerVersions(object): + def test_32bit_version(self): + fc = numpy.distutils.fcompiler.new_fcompiler(compiler='intel') + for vs, version in intel_32bit_version_strings: + v = fc.version_match(vs) + assert_(v == version) + + +class TestIntelEM64TFCompilerVersions(object): + def test_64bit_version(self): + fc = numpy.distutils.fcompiler.new_fcompiler(compiler='intelem') + for vs, version in intel_64bit_version_strings: + v = fc.version_match(vs) + assert_(v == version) + + +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/distutils/tests/test_fcompiler_nagfor.py b/numpy/distutils/tests/test_fcompiler_nagfor.py new file mode 100644 index 0000000..d45d3e3 --- /dev/null +++ b/numpy/distutils/tests/test_fcompiler_nagfor.py @@ -0,0 +1,29 @@ +from __future__ import division, absolute_import, print_function + +from numpy.testing import assert_, run_module_suite + +import numpy.distutils.fcompiler + +nag_version_strings = [('nagfor', 'NAG Fortran Compiler Release ' + '6.2(Chiyoda) Build 6200', '6.2'), + ('nagfor', 'NAG Fortran Compiler Release ' + '6.1(Tozai) Build 6136', '6.1'), + ('nagfor', 'NAG Fortran Compiler Release ' + '6.0(Hibiya) Build 1021', '6.0'), + ('nagfor', 'NAG Fortran Compiler Release ' + '5.3.2(971)', '5.3.2'), + ('nag', 'NAGWare Fortran 95 compiler Release 5.1' + '(347,355-367,375,380-383,389,394,399,401-402,407,' + '431,435,437,446,459-460,463,472,494,496,503,508,' + '511,517,529,555,557,565)', '5.1')] + +class TestNagFCompilerVersions(object): + def test_version_match(self): + for comp, vs, version in nag_version_strings: + fc = numpy.distutils.fcompiler.new_fcompiler(compiler=comp) + v = fc.version_match(vs) + assert_(v == version) + + +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/distutils/tests/test_misc_util.py b/numpy/distutils/tests/test_misc_util.py new file mode 100644 index 0000000..dd4dbc8 --- /dev/null +++ b/numpy/distutils/tests/test_misc_util.py @@ -0,0 +1,85 @@ +from __future__ import division, absolute_import, print_function + +from os.path import join, sep, dirname + +from numpy.distutils.misc_util import ( + appendpath, minrelpath, gpaths, get_shared_lib_extension, get_info +) +from numpy.testing import ( + run_module_suite, assert_, assert_equal +) + +ajoin = lambda *paths: join(*((sep,)+paths)) + +class TestAppendpath(object): + + def test_1(self): + assert_equal(appendpath('prefix', 'name'), join('prefix', 'name')) + assert_equal(appendpath('/prefix', 'name'), ajoin('prefix', 'name')) + assert_equal(appendpath('/prefix', '/name'), ajoin('prefix', 'name')) + assert_equal(appendpath('prefix', '/name'), join('prefix', 'name')) + + def test_2(self): + assert_equal(appendpath('prefix/sub', 'name'), + join('prefix', 'sub', 'name')) + assert_equal(appendpath('prefix/sub', 'sup/name'), + join('prefix', 'sub', 'sup', 'name')) + assert_equal(appendpath('/prefix/sub', '/prefix/name'), + ajoin('prefix', 'sub', 'name')) + + def test_3(self): + assert_equal(appendpath('/prefix/sub', '/prefix/sup/name'), + ajoin('prefix', 'sub', 'sup', 'name')) + assert_equal(appendpath('/prefix/sub/sub2', '/prefix/sup/sup2/name'), + ajoin('prefix', 'sub', 'sub2', 'sup', 'sup2', 'name')) + assert_equal(appendpath('/prefix/sub/sub2', '/prefix/sub/sup/name'), + ajoin('prefix', 'sub', 'sub2', 'sup', 'name')) + +class TestMinrelpath(object): + + def test_1(self): + n = lambda path: path.replace('/', sep) + assert_equal(minrelpath(n('aa/bb')), n('aa/bb')) + assert_equal(minrelpath('..'), '..') + assert_equal(minrelpath(n('aa/..')), '') + assert_equal(minrelpath(n('aa/../bb')), 'bb') + assert_equal(minrelpath(n('aa/bb/..')), 'aa') + assert_equal(minrelpath(n('aa/bb/../..')), '') + assert_equal(minrelpath(n('aa/bb/../cc/../dd')), n('aa/dd')) + assert_equal(minrelpath(n('.././..')), n('../..')) + assert_equal(minrelpath(n('aa/bb/.././../dd')), n('dd')) + +class TestGpaths(object): + + def test_gpaths(self): + local_path = minrelpath(join(dirname(__file__), '..')) + ls = gpaths('command/*.py', local_path) + assert_(join(local_path, 'command', 'build_src.py') in ls, repr(ls)) + f = gpaths('system_info.py', local_path) + assert_(join(local_path, 'system_info.py') == f[0], repr(f)) + +class TestSharedExtension(object): + + def test_get_shared_lib_extension(self): + import sys + ext = get_shared_lib_extension(is_python_ext=False) + if sys.platform.startswith('linux'): + assert_equal(ext, '.so') + elif sys.platform.startswith('gnukfreebsd'): + assert_equal(ext, '.so') + elif sys.platform.startswith('darwin'): + assert_equal(ext, '.dylib') + elif sys.platform.startswith('win'): + assert_equal(ext, '.dll') + # just check for no crash + assert_(get_shared_lib_extension(is_python_ext=True)) + + +def test_installed_npymath_ini(): + # Regression test for gh-7707. If npymath.ini wasn't installed, then this + # will give an error. + info = get_info('npymath') + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/distutils/tests/test_npy_pkg_config.py b/numpy/distutils/tests/test_npy_pkg_config.py new file mode 100644 index 0000000..29891b6 --- /dev/null +++ b/numpy/distutils/tests/test_npy_pkg_config.py @@ -0,0 +1,90 @@ +from __future__ import division, absolute_import, print_function + +import os + +from numpy.distutils.npy_pkg_config import read_config, parse_flags +from numpy.testing import run_module_suite, temppath, assert_ + +simple = """\ +[meta] +Name = foo +Description = foo lib +Version = 0.1 + +[default] +cflags = -I/usr/include +libs = -L/usr/lib +""" +simple_d = {'cflags': '-I/usr/include', 'libflags': '-L/usr/lib', + 'version': '0.1', 'name': 'foo'} + +simple_variable = """\ +[meta] +Name = foo +Description = foo lib +Version = 0.1 + +[variables] +prefix = /foo/bar +libdir = ${prefix}/lib +includedir = ${prefix}/include + +[default] +cflags = -I${includedir} +libs = -L${libdir} +""" +simple_variable_d = {'cflags': '-I/foo/bar/include', 'libflags': '-L/foo/bar/lib', + 'version': '0.1', 'name': 'foo'} + +class TestLibraryInfo(object): + def test_simple(self): + with temppath('foo.ini') as path: + with open(path, 'w') as f: + f.write(simple) + pkg = os.path.splitext(path)[0] + out = read_config(pkg) + + assert_(out.cflags() == simple_d['cflags']) + assert_(out.libs() == simple_d['libflags']) + assert_(out.name == simple_d['name']) + assert_(out.version == simple_d['version']) + + def test_simple_variable(self): + with temppath('foo.ini') as path: + with open(path, 'w') as f: + f.write(simple_variable) + pkg = os.path.splitext(path)[0] + out = read_config(pkg) + + assert_(out.cflags() == simple_variable_d['cflags']) + assert_(out.libs() == simple_variable_d['libflags']) + assert_(out.name == simple_variable_d['name']) + assert_(out.version == simple_variable_d['version']) + out.vars['prefix'] = '/Users/david' + assert_(out.cflags() == '-I/Users/david/include') + +class TestParseFlags(object): + def test_simple_cflags(self): + d = parse_flags("-I/usr/include") + assert_(d['include_dirs'] == ['/usr/include']) + + d = parse_flags("-I/usr/include -DFOO") + assert_(d['include_dirs'] == ['/usr/include']) + assert_(d['macros'] == ['FOO']) + + d = parse_flags("-I /usr/include -DFOO") + assert_(d['include_dirs'] == ['/usr/include']) + assert_(d['macros'] == ['FOO']) + + def test_simple_lflags(self): + d = parse_flags("-L/usr/lib -lfoo -L/usr/lib -lbar") + assert_(d['library_dirs'] == ['/usr/lib', '/usr/lib']) + assert_(d['libraries'] == ['foo', 'bar']) + + d = parse_flags("-L /usr/lib -lfoo -L/usr/lib -lbar") + assert_(d['library_dirs'] == ['/usr/lib', '/usr/lib']) + assert_(d['libraries'] == ['foo', 'bar']) + + +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/distutils/tests/test_system_info.py b/numpy/distutils/tests/test_system_info.py new file mode 100644 index 0000000..50befa1 --- /dev/null +++ b/numpy/distutils/tests/test_system_info.py @@ -0,0 +1,239 @@ +from __future__ import division, print_function + +import os +import shutil +from tempfile import mkstemp, mkdtemp +from subprocess import Popen, PIPE +from distutils.errors import DistutilsError + +from numpy.distutils import ccompiler, customized_ccompiler +from numpy.testing import ( + run_module_suite, assert_, assert_equal, dec + ) +from numpy.distutils.system_info import system_info, ConfigParser +from numpy.distutils.system_info import default_lib_dirs, default_include_dirs + + +def get_class(name, notfound_action=1): + """ + notfound_action: + 0 - do nothing + 1 - display warning message + 2 - raise error + """ + cl = {'temp1': Temp1Info, + 'temp2': Temp2Info + }.get(name.lower(), _system_info) + return cl() + +simple_site = """ +[ALL] +library_dirs = {dir1:s}{pathsep:s}{dir2:s} +libraries = {lib1:s},{lib2:s} +extra_compile_args = -I/fake/directory +runtime_library_dirs = {dir1:s} + +[temp1] +library_dirs = {dir1:s} +libraries = {lib1:s} +runtime_library_dirs = {dir1:s} + +[temp2] +library_dirs = {dir2:s} +libraries = {lib2:s} +extra_link_args = -Wl,-rpath={lib2:s} +rpath = {dir2:s} +""" +site_cfg = simple_site + +fakelib_c_text = """ +/* This file is generated from numpy/distutils/testing/test_system_info.py */ +#include +void foo(void) { + printf("Hello foo"); +} +void bar(void) { + printf("Hello bar"); +} +""" + +def have_compiler(): + """ Return True if there appears to be an executable compiler + """ + compiler = customized_ccompiler() + try: + cmd = compiler.compiler # Unix compilers + except AttributeError: + try: + if not compiler.initialized: + compiler.initialize() # MSVC is different + except (DistutilsError, ValueError): + return False + cmd = [compiler.cc] + try: + p = Popen(cmd, stdout=PIPE, stderr=PIPE) + p.stdout.close() + p.stderr.close() + p.wait() + except OSError: + return False + return True + + +HAVE_COMPILER = have_compiler() + + +class _system_info(system_info): + + def __init__(self, + default_lib_dirs=default_lib_dirs, + default_include_dirs=default_include_dirs, + verbosity=1, + ): + self.__class__.info = {} + self.local_prefixes = [] + defaults = {'library_dirs': '', + 'include_dirs': '', + 'runtime_library_dirs': '', + 'rpath': '', + 'src_dirs': '', + 'search_static_first': "0", + 'extra_compile_args': '', + 'extra_link_args': ''} + self.cp = ConfigParser(defaults) + # We have to parse the config files afterwards + # to have a consistent temporary filepath + + def _check_libs(self, lib_dirs, libs, opt_libs, exts): + """Override _check_libs to return with all dirs """ + info = {'libraries': libs, 'library_dirs': lib_dirs} + return info + + +class Temp1Info(_system_info): + """For testing purposes""" + section = 'temp1' + + +class Temp2Info(_system_info): + """For testing purposes""" + section = 'temp2' + + +class TestSystemInfoReading(object): + + def setup(self): + """ Create the libraries """ + # Create 2 sources and 2 libraries + self._dir1 = mkdtemp() + self._src1 = os.path.join(self._dir1, 'foo.c') + self._lib1 = os.path.join(self._dir1, 'libfoo.so') + self._dir2 = mkdtemp() + self._src2 = os.path.join(self._dir2, 'bar.c') + self._lib2 = os.path.join(self._dir2, 'libbar.so') + # Update local site.cfg + global simple_site, site_cfg + site_cfg = simple_site.format(**{ + 'dir1': self._dir1, + 'lib1': self._lib1, + 'dir2': self._dir2, + 'lib2': self._lib2, + 'pathsep': os.pathsep + }) + # Write site.cfg + fd, self._sitecfg = mkstemp() + os.close(fd) + with open(self._sitecfg, 'w') as fd: + fd.write(site_cfg) + # Write the sources + with open(self._src1, 'w') as fd: + fd.write(fakelib_c_text) + with open(self._src2, 'w') as fd: + fd.write(fakelib_c_text) + # We create all class-instances + + def site_and_parse(c, site_cfg): + c.files = [site_cfg] + c.parse_config_files() + return c + self.c_default = site_and_parse(get_class('default'), self._sitecfg) + self.c_temp1 = site_and_parse(get_class('temp1'), self._sitecfg) + self.c_temp2 = site_and_parse(get_class('temp2'), self._sitecfg) + + def tearDown(self): + # Do each removal separately + try: + shutil.rmtree(self._dir1) + except Exception: + pass + try: + shutil.rmtree(self._dir2) + except Exception: + pass + try: + os.remove(self._sitecfg) + except Exception: + pass + + def test_all(self): + # Read in all information in the ALL block + tsi = self.c_default + assert_equal(tsi.get_lib_dirs(), [self._dir1, self._dir2]) + assert_equal(tsi.get_libraries(), [self._lib1, self._lib2]) + assert_equal(tsi.get_runtime_lib_dirs(), [self._dir1]) + extra = tsi.calc_extra_info() + assert_equal(extra['extra_compile_args'], ['-I/fake/directory']) + + def test_temp1(self): + # Read in all information in the temp1 block + tsi = self.c_temp1 + assert_equal(tsi.get_lib_dirs(), [self._dir1]) + assert_equal(tsi.get_libraries(), [self._lib1]) + assert_equal(tsi.get_runtime_lib_dirs(), [self._dir1]) + + def test_temp2(self): + # Read in all information in the temp2 block + tsi = self.c_temp2 + assert_equal(tsi.get_lib_dirs(), [self._dir2]) + assert_equal(tsi.get_libraries(), [self._lib2]) + # Now from rpath and not runtime_library_dirs + assert_equal(tsi.get_runtime_lib_dirs(key='rpath'), [self._dir2]) + extra = tsi.calc_extra_info() + assert_equal(extra['extra_link_args'], ['-Wl,-rpath=' + self._lib2]) + + @dec.skipif(not HAVE_COMPILER) + def test_compile1(self): + # Compile source and link the first source + c = customized_ccompiler() + previousDir = os.getcwd() + try: + # Change directory to not screw up directories + os.chdir(self._dir1) + c.compile([os.path.basename(self._src1)], output_dir=self._dir1) + # Ensure that the object exists + assert_(os.path.isfile(self._src1.replace('.c', '.o')) or + os.path.isfile(self._src1.replace('.c', '.obj'))) + finally: + os.chdir(previousDir) + + @dec.skipif(not HAVE_COMPILER) + @dec.skipif('msvc' in repr(ccompiler.new_compiler())) + def test_compile2(self): + # Compile source and link the second source + tsi = self.c_temp2 + c = customized_ccompiler() + extra_link_args = tsi.calc_extra_info()['extra_link_args'] + previousDir = os.getcwd() + try: + # Change directory to not screw up directories + os.chdir(self._dir2) + c.compile([os.path.basename(self._src2)], output_dir=self._dir2, + extra_postargs=extra_link_args) + # Ensure that the object exists + assert_(os.path.isfile(self._src2.replace('.c', '.o'))) + finally: + os.chdir(previousDir) + + +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/distutils/unixccompiler.py b/numpy/distutils/unixccompiler.py new file mode 100644 index 0000000..6ed5eec --- /dev/null +++ b/numpy/distutils/unixccompiler.py @@ -0,0 +1,138 @@ +""" +unixccompiler - can handle very long argument lists for ar. + +""" +from __future__ import division, absolute_import, print_function + +import os + +from distutils.errors import DistutilsExecError, CompileError +from distutils.unixccompiler import * +from numpy.distutils.ccompiler import replace_method +from numpy.distutils.compat import get_exception +from numpy.distutils.misc_util import _commandline_dep_string + +if sys.version_info[0] < 3: + from . import log +else: + from numpy.distutils import log + +# Note that UnixCCompiler._compile appeared in Python 2.3 +def UnixCCompiler__compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + """Compile a single source files with a Unix-style compiler.""" + # HP ad-hoc fix, see ticket 1383 + ccomp = self.compiler_so + if ccomp[0] == 'aCC': + # remove flags that will trigger ANSI-C mode for aCC + if '-Ae' in ccomp: + ccomp.remove('-Ae') + if '-Aa' in ccomp: + ccomp.remove('-Aa') + # add flags for (almost) sane C++ handling + ccomp += ['-AA'] + self.compiler_so = ccomp + # ensure OPT environment variable is read + if 'OPT' in os.environ: + from distutils.sysconfig import get_config_vars + opt = " ".join(os.environ['OPT'].split()) + gcv_opt = " ".join(get_config_vars('OPT')[0].split()) + ccomp_s = " ".join(self.compiler_so) + if opt not in ccomp_s: + ccomp_s = ccomp_s.replace(gcv_opt, opt) + self.compiler_so = ccomp_s.split() + llink_s = " ".join(self.linker_so) + if opt not in llink_s: + self.linker_so = llink_s.split() + opt.split() + + display = '%s: %s' % (os.path.basename(self.compiler_so[0]), src) + + # gcc style automatic dependencies, outputs a makefile (-MF) that lists + # all headers needed by a c file as a side effect of compilation (-MMD) + if getattr(self, '_auto_depends', False): + deps = ['-MMD', '-MF', obj + '.d'] + else: + deps = [] + + try: + self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + deps + + extra_postargs, display = display) + except DistutilsExecError: + msg = str(get_exception()) + raise CompileError(msg) + + # add commandline flags to dependency file + with open(obj + '.d', 'a') as f: + f.write(_commandline_dep_string(cc_args, extra_postargs, pp_opts)) + +replace_method(UnixCCompiler, '_compile', UnixCCompiler__compile) + + +def UnixCCompiler_create_static_lib(self, objects, output_libname, + output_dir=None, debug=0, target_lang=None): + """ + Build a static library in a separate sub-process. + + Parameters + ---------- + objects : list or tuple of str + List of paths to object files used to build the static library. + output_libname : str + The library name as an absolute or relative (if `output_dir` is used) + path. + output_dir : str, optional + The path to the output directory. Default is None, in which case + the ``output_dir`` attribute of the UnixCCompiler instance. + debug : bool, optional + This parameter is not used. + target_lang : str, optional + This parameter is not used. + + Returns + ------- + None + + """ + objects, output_dir = self._fix_object_args(objects, output_dir) + + output_filename = \ + self.library_filename(output_libname, output_dir=output_dir) + + if self._need_link(objects, output_filename): + try: + # previous .a may be screwed up; best to remove it first + # and recreate. + # Also, ar on OS X doesn't handle updating universal archives + os.unlink(output_filename) + except (IOError, OSError): + pass + self.mkpath(os.path.dirname(output_filename)) + tmp_objects = objects + self.objects + while tmp_objects: + objects = tmp_objects[:50] + tmp_objects = tmp_objects[50:] + display = '%s: adding %d object files to %s' % ( + os.path.basename(self.archiver[0]), + len(objects), output_filename) + self.spawn(self.archiver + [output_filename] + objects, + display = display) + + # Not many Unices required ranlib anymore -- SunOS 4.x is, I + # think the only major Unix that does. Maybe we need some + # platform intelligence here to skip ranlib if it's not + # needed -- or maybe Python's configure script took care of + # it for us, hence the check for leading colon. + if self.ranlib: + display = '%s:@ %s' % (os.path.basename(self.ranlib[0]), + output_filename) + try: + self.spawn(self.ranlib + [output_filename], + display = display) + except DistutilsExecError: + msg = str(get_exception()) + raise LibError(msg) + else: + log.debug("skipping %s (up-to-date)", output_filename) + return + +replace_method(UnixCCompiler, 'create_static_lib', + UnixCCompiler_create_static_lib) diff --git a/numpy/doc/__init__.py b/numpy/doc/__init__.py new file mode 100644 index 0000000..b6f1fa7 --- /dev/null +++ b/numpy/doc/__init__.py @@ -0,0 +1,28 @@ +from __future__ import division, absolute_import, print_function + +import os + +ref_dir = os.path.join(os.path.dirname(__file__)) + +__all__ = sorted(f[:-3] for f in os.listdir(ref_dir) if f.endswith('.py') and + not f.startswith('__')) + +for f in __all__: + __import__(__name__ + '.' + f) + +del f, ref_dir + +__doc__ = """\ +Topical documentation +===================== + +The following topics are available: +%s + +You can view them by + +>>> help(np.doc.TOPIC) #doctest: +SKIP + +""" % '\n- '.join([''] + __all__) + +__all__.extend(['__doc__']) diff --git a/numpy/doc/basics.py b/numpy/doc/basics.py new file mode 100644 index 0000000..4d3ab04 --- /dev/null +++ b/numpy/doc/basics.py @@ -0,0 +1,185 @@ +""" +============ +Array basics +============ + +Array types and conversions between types +========================================= + +NumPy supports a much greater variety of numerical types than Python does. +This section shows which are available, and how to modify an array's data-type. + +============ ========================================================== +Data type Description +============ ========================================================== +``bool_`` Boolean (True or False) stored as a byte +``int_`` Default integer type (same as C ``long``; normally either + ``int64`` or ``int32``) +intc Identical to C ``int`` (normally ``int32`` or ``int64``) +intp Integer used for indexing (same as C ``ssize_t``; normally + either ``int32`` or ``int64``) +int8 Byte (-128 to 127) +int16 Integer (-32768 to 32767) +int32 Integer (-2147483648 to 2147483647) +int64 Integer (-9223372036854775808 to 9223372036854775807) +uint8 Unsigned integer (0 to 255) +uint16 Unsigned integer (0 to 65535) +uint32 Unsigned integer (0 to 4294967295) +uint64 Unsigned integer (0 to 18446744073709551615) +``float_`` Shorthand for ``float64``. +float16 Half precision float: sign bit, 5 bits exponent, + 10 bits mantissa +float32 Single precision float: sign bit, 8 bits exponent, + 23 bits mantissa +float64 Double precision float: sign bit, 11 bits exponent, + 52 bits mantissa +``complex_`` Shorthand for ``complex128``. +complex64 Complex number, represented by two 32-bit floats (real + and imaginary components) +complex128 Complex number, represented by two 64-bit floats (real + and imaginary components) +============ ========================================================== + +Additionally to ``intc`` the platform dependent C integer types ``short``, +``long``, ``longlong`` and their unsigned versions are defined. + +NumPy numerical types are instances of ``dtype`` (data-type) objects, each +having unique characteristics. Once you have imported NumPy using + + :: + + >>> import numpy as np + +the dtypes are available as ``np.bool_``, ``np.float32``, etc. + +Advanced types, not listed in the table above, are explored in +section :ref:`structured_arrays`. + +There are 5 basic numerical types representing booleans (bool), integers (int), +unsigned integers (uint) floating point (float) and complex. Those with numbers +in their name indicate the bitsize of the type (i.e. how many bits are needed +to represent a single value in memory). Some types, such as ``int`` and +``intp``, have differing bitsizes, dependent on the platforms (e.g. 32-bit +vs. 64-bit machines). This should be taken into account when interfacing +with low-level code (such as C or Fortran) where the raw memory is addressed. + +Data-types can be used as functions to convert python numbers to array scalars +(see the array scalar section for an explanation), python sequences of numbers +to arrays of that type, or as arguments to the dtype keyword that many numpy +functions or methods accept. Some examples:: + + >>> import numpy as np + >>> x = np.float32(1.0) + >>> x + 1.0 + >>> y = np.int_([1,2,4]) + >>> y + array([1, 2, 4]) + >>> z = np.arange(3, dtype=np.uint8) + >>> z + array([0, 1, 2], dtype=uint8) + +Array types can also be referred to by character codes, mostly to retain +backward compatibility with older packages such as Numeric. Some +documentation may still refer to these, for example:: + + >>> np.array([1, 2, 3], dtype='f') + array([ 1., 2., 3.], dtype=float32) + +We recommend using dtype objects instead. + +To convert the type of an array, use the .astype() method (preferred) or +the type itself as a function. For example: :: + + >>> z.astype(float) #doctest: +NORMALIZE_WHITESPACE + array([ 0., 1., 2.]) + >>> np.int8(z) + array([0, 1, 2], dtype=int8) + +Note that, above, we use the *Python* float object as a dtype. NumPy knows +that ``int`` refers to ``np.int_``, ``bool`` means ``np.bool_``, +that ``float`` is ``np.float_`` and ``complex`` is ``np.complex_``. +The other data-types do not have Python equivalents. + +To determine the type of an array, look at the dtype attribute:: + + >>> z.dtype + dtype('uint8') + +dtype objects also contain information about the type, such as its bit-width +and its byte-order. The data type can also be used indirectly to query +properties of the type, such as whether it is an integer:: + + >>> d = np.dtype(int) + >>> d + dtype('int32') + + >>> np.issubdtype(d, np.integer) + True + + >>> np.issubdtype(d, np.floating) + False + + +Array Scalars +============= + +NumPy generally returns elements of arrays as array scalars (a scalar +with an associated dtype). Array scalars differ from Python scalars, but +for the most part they can be used interchangeably (the primary +exception is for versions of Python older than v2.x, where integer array +scalars cannot act as indices for lists and tuples). There are some +exceptions, such as when code requires very specific attributes of a scalar +or when it checks specifically whether a value is a Python scalar. Generally, +problems are easily fixed by explicitly converting array scalars +to Python scalars, using the corresponding Python type function +(e.g., ``int``, ``float``, ``complex``, ``str``, ``unicode``). + +The primary advantage of using array scalars is that +they preserve the array type (Python may not have a matching scalar type +available, e.g. ``int16``). Therefore, the use of array scalars ensures +identical behaviour between arrays and scalars, irrespective of whether the +value is inside an array or not. NumPy scalars also have many of the same +methods arrays do. + +Extended Precision +================== + +Python's floating-point numbers are usually 64-bit floating-point numbers, +nearly equivalent to ``np.float64``. In some unusual situations it may be +useful to use floating-point numbers with more precision. Whether this +is possible in numpy depends on the hardware and on the development +environment: specifically, x86 machines provide hardware floating-point +with 80-bit precision, and while most C compilers provide this as their +``long double`` type, MSVC (standard for Windows builds) makes +``long double`` identical to ``double`` (64 bits). NumPy makes the +compiler's ``long double`` available as ``np.longdouble`` (and +``np.clongdouble`` for the complex numbers). You can find out what your +numpy provides with ``np.finfo(np.longdouble)``. + +NumPy does not provide a dtype with more precision than C +``long double``\\s; in particular, the 128-bit IEEE quad precision +data type (FORTRAN's ``REAL*16``\\) is not available. + +For efficient memory alignment, ``np.longdouble`` is usually stored +padded with zero bits, either to 96 or 128 bits. Which is more efficient +depends on hardware and development environment; typically on 32-bit +systems they are padded to 96 bits, while on 64-bit systems they are +typically padded to 128 bits. ``np.longdouble`` is padded to the system +default; ``np.float96`` and ``np.float128`` are provided for users who +want specific padding. In spite of the names, ``np.float96`` and +``np.float128`` provide only as much precision as ``np.longdouble``, +that is, 80 bits on most x86 machines and 64 bits in standard +Windows builds. + +Be warned that even if ``np.longdouble`` offers more precision than +python ``float``, it is easy to lose that extra precision, since +python often forces values to pass through ``float``. For example, +the ``%`` formatting operator requires its arguments to be converted +to standard python types, and it is therefore impossible to preserve +extended precision even if many decimal places are requested. It can +be useful to test your code with the value +``1 + np.finfo(np.longdouble).eps``. + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/broadcasting.py b/numpy/doc/broadcasting.py new file mode 100644 index 0000000..717914c --- /dev/null +++ b/numpy/doc/broadcasting.py @@ -0,0 +1,178 @@ +""" +======================== +Broadcasting over arrays +======================== + +The term broadcasting describes how numpy treats arrays with different +shapes during arithmetic operations. Subject to certain constraints, +the smaller array is "broadcast" across the larger array so that they +have compatible shapes. Broadcasting provides a means of vectorizing +array operations so that looping occurs in C instead of Python. It does +this without making needless copies of data and usually leads to +efficient algorithm implementations. There are, however, cases where +broadcasting is a bad idea because it leads to inefficient use of memory +that slows computation. + +NumPy operations are usually done on pairs of arrays on an +element-by-element basis. In the simplest case, the two arrays must +have exactly the same shape, as in the following example: + + >>> a = np.array([1.0, 2.0, 3.0]) + >>> b = np.array([2.0, 2.0, 2.0]) + >>> a * b + array([ 2., 4., 6.]) + +NumPy's broadcasting rule relaxes this constraint when the arrays' +shapes meet certain constraints. The simplest broadcasting example occurs +when an array and a scalar value are combined in an operation: + +>>> a = np.array([1.0, 2.0, 3.0]) +>>> b = 2.0 +>>> a * b +array([ 2., 4., 6.]) + +The result is equivalent to the previous example where ``b`` was an array. +We can think of the scalar ``b`` being *stretched* during the arithmetic +operation into an array with the same shape as ``a``. The new elements in +``b`` are simply copies of the original scalar. The stretching analogy is +only conceptual. NumPy is smart enough to use the original scalar value +without actually making copies, so that broadcasting operations are as +memory and computationally efficient as possible. + +The code in the second example is more efficient than that in the first +because broadcasting moves less memory around during the multiplication +(``b`` is a scalar rather than an array). + +General Broadcasting Rules +========================== +When operating on two arrays, NumPy compares their shapes element-wise. +It starts with the trailing dimensions, and works its way forward. Two +dimensions are compatible when + +1) they are equal, or +2) one of them is 1 + +If these conditions are not met, a +``ValueError: frames are not aligned`` exception is thrown, indicating that +the arrays have incompatible shapes. The size of the resulting array +is the maximum size along each dimension of the input arrays. + +Arrays do not need to have the same *number* of dimensions. For example, +if you have a ``256x256x3`` array of RGB values, and you want to scale +each color in the image by a different value, you can multiply the image +by a one-dimensional array with 3 values. Lining up the sizes of the +trailing axes of these arrays according to the broadcast rules, shows that +they are compatible:: + + Image (3d array): 256 x 256 x 3 + Scale (1d array): 3 + Result (3d array): 256 x 256 x 3 + +When either of the dimensions compared is one, the other is +used. In other words, dimensions with size 1 are stretched or "copied" +to match the other. + +In the following example, both the ``A`` and ``B`` arrays have axes with +length one that are expanded to a larger size during the broadcast +operation:: + + A (4d array): 8 x 1 x 6 x 1 + B (3d array): 7 x 1 x 5 + Result (4d array): 8 x 7 x 6 x 5 + +Here are some more examples:: + + A (2d array): 5 x 4 + B (1d array): 1 + Result (2d array): 5 x 4 + + A (2d array): 5 x 4 + B (1d array): 4 + Result (2d array): 5 x 4 + + A (3d array): 15 x 3 x 5 + B (3d array): 15 x 1 x 5 + Result (3d array): 15 x 3 x 5 + + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 5 + Result (3d array): 15 x 3 x 5 + + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 1 + Result (3d array): 15 x 3 x 5 + +Here are examples of shapes that do not broadcast:: + + A (1d array): 3 + B (1d array): 4 # trailing dimensions do not match + + A (2d array): 2 x 1 + B (3d array): 8 x 4 x 3 # second from last dimensions mismatched + +An example of broadcasting in practice:: + + >>> x = np.arange(4) + >>> xx = x.reshape(4,1) + >>> y = np.ones(5) + >>> z = np.ones((3,4)) + + >>> x.shape + (4,) + + >>> y.shape + (5,) + + >>> x + y + : shape mismatch: objects cannot be broadcast to a single shape + + >>> xx.shape + (4, 1) + + >>> y.shape + (5,) + + >>> (xx + y).shape + (4, 5) + + >>> xx + y + array([[ 1., 1., 1., 1., 1.], + [ 2., 2., 2., 2., 2.], + [ 3., 3., 3., 3., 3.], + [ 4., 4., 4., 4., 4.]]) + + >>> x.shape + (4,) + + >>> z.shape + (3, 4) + + >>> (x + z).shape + (3, 4) + + >>> x + z + array([[ 1., 2., 3., 4.], + [ 1., 2., 3., 4.], + [ 1., 2., 3., 4.]]) + +Broadcasting provides a convenient way of taking the outer product (or +any other outer operation) of two arrays. The following example shows an +outer addition operation of two 1-d arrays:: + + >>> a = np.array([0.0, 10.0, 20.0, 30.0]) + >>> b = np.array([1.0, 2.0, 3.0]) + >>> a[:, np.newaxis] + b + array([[ 1., 2., 3.], + [ 11., 12., 13.], + [ 21., 22., 23.], + [ 31., 32., 33.]]) + +Here the ``newaxis`` index operator inserts a new axis into ``a``, +making it a two-dimensional ``4x1`` array. Combining the ``4x1`` array +with ``b``, which has shape ``(3,)``, yields a ``4x3`` array. + +See `this article `_ +for illustrations of broadcasting concepts. + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/byteswapping.py b/numpy/doc/byteswapping.py new file mode 100644 index 0000000..d67e2cf --- /dev/null +++ b/numpy/doc/byteswapping.py @@ -0,0 +1,156 @@ +""" + +============================= + Byteswapping and byte order +============================= + +Introduction to byte ordering and ndarrays +========================================== + +The ``ndarray`` is an object that provide a python array interface to data +in memory. + +It often happens that the memory that you want to view with an array is +not of the same byte ordering as the computer on which you are running +Python. + +For example, I might be working on a computer with a little-endian CPU - +such as an Intel Pentium, but I have loaded some data from a file +written by a computer that is big-endian. Let's say I have loaded 4 +bytes from a file written by a Sun (big-endian) computer. I know that +these 4 bytes represent two 16-bit integers. On a big-endian machine, a +two-byte integer is stored with the Most Significant Byte (MSB) first, +and then the Least Significant Byte (LSB). Thus the bytes are, in memory order: + +#. MSB integer 1 +#. LSB integer 1 +#. MSB integer 2 +#. LSB integer 2 + +Let's say the two integers were in fact 1 and 770. Because 770 = 256 * +3 + 2, the 4 bytes in memory would contain respectively: 0, 1, 3, 2. +The bytes I have loaded from the file would have these contents: + +>>> big_end_str = chr(0) + chr(1) + chr(3) + chr(2) +>>> big_end_str +'\\x00\\x01\\x03\\x02' + +We might want to use an ``ndarray`` to access these integers. In that +case, we can create an array around this memory, and tell numpy that +there are two integers, and that they are 16 bit and big-endian: + +>>> import numpy as np +>>> big_end_arr = np.ndarray(shape=(2,),dtype='>i2', buffer=big_end_str) +>>> big_end_arr[0] +1 +>>> big_end_arr[1] +770 + +Note the array ``dtype`` above of ``>i2``. The ``>`` means 'big-endian' +(``<`` is little-endian) and ``i2`` means 'signed 2-byte integer'. For +example, if our data represented a single unsigned 4-byte little-endian +integer, the dtype string would be ``>> little_end_u4 = np.ndarray(shape=(1,),dtype='>> little_end_u4[0] == 1 * 256**1 + 3 * 256**2 + 2 * 256**3 +True + +Returning to our ``big_end_arr`` - in this case our underlying data is +big-endian (data endianness) and we've set the dtype to match (the dtype +is also big-endian). However, sometimes you need to flip these around. + +.. warning:: + + Scalars currently do not include byte order information, so extracting + a scalar from an array will return an integer in native byte order. + Hence: + + >>> big_end_arr[0].dtype.byteorder == little_end_u4[0].dtype.byteorder + True + +Changing byte ordering +====================== + +As you can imagine from the introduction, there are two ways you can +affect the relationship between the byte ordering of the array and the +underlying memory it is looking at: + +* Change the byte-ordering information in the array dtype so that it + interprets the underlying data as being in a different byte order. + This is the role of ``arr.newbyteorder()`` +* Change the byte-ordering of the underlying data, leaving the dtype + interpretation as it was. This is what ``arr.byteswap()`` does. + +The common situations in which you need to change byte ordering are: + +#. Your data and dtype endianess don't match, and you want to change + the dtype so that it matches the data. +#. Your data and dtype endianess don't match, and you want to swap the + data so that they match the dtype +#. Your data and dtype endianess match, but you want the data swapped + and the dtype to reflect this + +Data and dtype endianness don't match, change dtype to match data +----------------------------------------------------------------- + +We make something where they don't match: + +>>> wrong_end_dtype_arr = np.ndarray(shape=(2,),dtype='>> wrong_end_dtype_arr[0] +256 + +The obvious fix for this situation is to change the dtype so it gives +the correct endianness: + +>>> fixed_end_dtype_arr = wrong_end_dtype_arr.newbyteorder() +>>> fixed_end_dtype_arr[0] +1 + +Note the array has not changed in memory: + +>>> fixed_end_dtype_arr.tobytes() == big_end_str +True + +Data and type endianness don't match, change data to match dtype +---------------------------------------------------------------- + +You might want to do this if you need the data in memory to be a certain +ordering. For example you might be writing the memory out to a file +that needs a certain byte ordering. + +>>> fixed_end_mem_arr = wrong_end_dtype_arr.byteswap() +>>> fixed_end_mem_arr[0] +1 + +Now the array *has* changed in memory: + +>>> fixed_end_mem_arr.tobytes() == big_end_str +False + +Data and dtype endianness match, swap data and dtype +---------------------------------------------------- + +You may have a correctly specified array dtype, but you need the array +to have the opposite byte order in memory, and you want the dtype to +match so the array values make sense. In this case you just do both of +the previous operations: + +>>> swapped_end_arr = big_end_arr.byteswap().newbyteorder() +>>> swapped_end_arr[0] +1 +>>> swapped_end_arr.tobytes() == big_end_str +False + +An easier way of casting the data to a specific dtype and byte ordering +can be achieved with the ndarray astype method: + +>>> swapped_end_arr = big_end_arr.astype('>> swapped_end_arr[0] +1 +>>> swapped_end_arr.tobytes() == big_end_str +False + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/constants.py b/numpy/doc/constants.py new file mode 100644 index 0000000..6246813 --- /dev/null +++ b/numpy/doc/constants.py @@ -0,0 +1,393 @@ +""" +========= +Constants +========= + +NumPy includes several constants: + +%(constant_list)s +""" +# +# Note: the docstring is autogenerated. +# +from __future__ import division, absolute_import, print_function + +import textwrap, re + +# Maintain same format as in numpy.add_newdocs +constants = [] +def add_newdoc(module, name, doc): + constants.append((name, doc)) + +add_newdoc('numpy', 'Inf', + """ + IEEE 754 floating point representation of (positive) infinity. + + Use `inf` because `Inf`, `Infinity`, `PINF` and `infty` are aliases for + `inf`. For more details, see `inf`. + + See Also + -------- + inf + + """) + +add_newdoc('numpy', 'Infinity', + """ + IEEE 754 floating point representation of (positive) infinity. + + Use `inf` because `Inf`, `Infinity`, `PINF` and `infty` are aliases for + `inf`. For more details, see `inf`. + + See Also + -------- + inf + + """) + +add_newdoc('numpy', 'NAN', + """ + IEEE 754 floating point representation of Not a Number (NaN). + + `NaN` and `NAN` are equivalent definitions of `nan`. Please use + `nan` instead of `NAN`. + + See Also + -------- + nan + + """) + +add_newdoc('numpy', 'NINF', + """ + IEEE 754 floating point representation of negative infinity. + + Returns + ------- + y : float + A floating point representation of negative infinity. + + See Also + -------- + isinf : Shows which elements are positive or negative infinity + + isposinf : Shows which elements are positive infinity + + isneginf : Shows which elements are negative infinity + + isnan : Shows which elements are Not a Number + + isfinite : Shows which elements are finite (not one of Not a Number, + positive infinity and negative 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. + Also that positive infinity is not equivalent to negative infinity. But + infinity is equivalent to positive infinity. + + Examples + -------- + >>> np.NINF + -inf + >>> np.log(0) + -inf + + """) + +add_newdoc('numpy', 'NZERO', + """ + IEEE 754 floating point representation of negative zero. + + Returns + ------- + y : float + A floating point representation of negative zero. + + See Also + -------- + PZERO : Defines positive zero. + + isinf : Shows which elements are positive or negative infinity. + + isposinf : Shows which elements are positive infinity. + + isneginf : Shows which elements are negative infinity. + + isnan : Shows which elements are Not a Number. + + isfinite : Shows which elements are finite - not one of + Not a Number, positive infinity and negative infinity. + + Notes + ----- + NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic + (IEEE 754). Negative zero is considered to be a finite number. + + Examples + -------- + >>> np.NZERO + -0.0 + >>> np.PZERO + 0.0 + + >>> np.isfinite([np.NZERO]) + array([ True]) + >>> np.isnan([np.NZERO]) + array([False]) + >>> np.isinf([np.NZERO]) + array([False]) + + """) + +add_newdoc('numpy', 'NaN', + """ + IEEE 754 floating point representation of Not a Number (NaN). + + `NaN` and `NAN` are equivalent definitions of `nan`. Please use + `nan` instead of `NaN`. + + See Also + -------- + nan + + """) + +add_newdoc('numpy', 'PINF', + """ + IEEE 754 floating point representation of (positive) infinity. + + Use `inf` because `Inf`, `Infinity`, `PINF` and `infty` are aliases for + `inf`. For more details, see `inf`. + + See Also + -------- + inf + + """) + +add_newdoc('numpy', 'PZERO', + """ + IEEE 754 floating point representation of positive zero. + + Returns + ------- + y : float + A floating point representation of positive zero. + + See Also + -------- + NZERO : Defines negative zero. + + isinf : Shows which elements are positive or negative infinity. + + isposinf : Shows which elements are positive infinity. + + isneginf : Shows which elements are negative infinity. + + isnan : Shows which elements are Not a Number. + + isfinite : Shows which elements are finite - not one of + Not a Number, positive infinity and negative infinity. + + Notes + ----- + NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic + (IEEE 754). Positive zero is considered to be a finite number. + + Examples + -------- + >>> np.PZERO + 0.0 + >>> np.NZERO + -0.0 + + >>> np.isfinite([np.PZERO]) + array([ True]) + >>> np.isnan([np.PZERO]) + array([False]) + >>> np.isinf([np.PZERO]) + array([False]) + + """) + +add_newdoc('numpy', 'e', + """ + Euler's constant, base of natural logarithms, Napier's constant. + + ``e = 2.71828182845904523536028747135266249775724709369995...`` + + See Also + -------- + exp : Exponential function + log : Natural logarithm + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/Napier_constant + + """) + +add_newdoc('numpy', 'inf', + """ + IEEE 754 floating point representation of (positive) infinity. + + Returns + ------- + y : float + A floating point representation of positive infinity. + + See Also + -------- + isinf : Shows which elements are positive or negative infinity + + isposinf : Shows which elements are positive infinity + + isneginf : Shows which elements are negative infinity + + isnan : Shows which elements are Not a Number + + isfinite : Shows which elements are finite (not one of Not a Number, + positive infinity and negative 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. + Also that positive infinity is not equivalent to negative infinity. But + infinity is equivalent to positive infinity. + + `Inf`, `Infinity`, `PINF` and `infty` are aliases for `inf`. + + Examples + -------- + >>> np.inf + inf + >>> np.array([1]) / 0. + array([ Inf]) + + """) + +add_newdoc('numpy', 'infty', + """ + IEEE 754 floating point representation of (positive) infinity. + + Use `inf` because `Inf`, `Infinity`, `PINF` and `infty` are aliases for + `inf`. For more details, see `inf`. + + See Also + -------- + inf + + """) + +add_newdoc('numpy', 'nan', + """ + IEEE 754 floating point representation of Not a Number (NaN). + + Returns + ------- + y : A floating point representation of Not a Number. + + See Also + -------- + isnan : Shows which elements are Not a Number. + isfinite : Shows which elements are finite (not one of + Not a Number, positive infinity and negative 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. + + `NaN` and `NAN` are aliases of `nan`. + + Examples + -------- + >>> np.nan + nan + >>> np.log(-1) + nan + >>> np.log([-1, 1, 2]) + array([ NaN, 0. , 0.69314718]) + + """) + +add_newdoc('numpy', 'newaxis', + """ + A convenient alias for None, useful for indexing arrays. + + See Also + -------- + `numpy.doc.indexing` + + Examples + -------- + >>> newaxis is None + True + >>> x = np.arange(3) + >>> x + array([0, 1, 2]) + >>> x[:, newaxis] + array([[0], + [1], + [2]]) + >>> x[:, newaxis, newaxis] + array([[[0]], + [[1]], + [[2]]]) + >>> x[:, newaxis] * x + array([[0, 0, 0], + [0, 1, 2], + [0, 2, 4]]) + + Outer product, same as ``outer(x, y)``: + + >>> y = np.arange(3, 6) + >>> x[:, newaxis] * y + array([[ 0, 0, 0], + [ 3, 4, 5], + [ 6, 8, 10]]) + + ``x[newaxis, :]`` is equivalent to ``x[newaxis]`` and ``x[None]``: + + >>> x[newaxis, :].shape + (1, 3) + >>> x[newaxis].shape + (1, 3) + >>> x[None].shape + (1, 3) + >>> x[:, newaxis].shape + (3, 1) + + """) + +if __doc__: + constants_str = [] + constants.sort() + for name, doc in constants: + s = textwrap.dedent(doc).replace("\n", "\n ") + + # Replace sections by rubrics + lines = s.split("\n") + new_lines = [] + for line in lines: + m = re.match(r'^(\s+)[-=]+\s*$', line) + if m and new_lines: + prev = textwrap.dedent(new_lines.pop()) + new_lines.append('%s.. rubric:: %s' % (m.group(1), prev)) + new_lines.append('') + else: + new_lines.append(line) + s = "\n".join(new_lines) + + # Done. + constants_str.append(""".. const:: %s\n %s""" % (name, s)) + constants_str = "\n".join(constants_str) + + __doc__ = __doc__ % dict(constant_list=constants_str) + del constants_str, name, doc + del line, lines, new_lines, m, s, prev + +del constants, add_newdoc diff --git a/numpy/doc/creation.py b/numpy/doc/creation.py new file mode 100644 index 0000000..7de1c19 --- /dev/null +++ b/numpy/doc/creation.py @@ -0,0 +1,144 @@ +""" +============== +Array Creation +============== + +Introduction +============ + +There are 5 general mechanisms for creating arrays: + +1) Conversion from other Python structures (e.g., lists, tuples) +2) Intrinsic numpy array array creation objects (e.g., arange, ones, zeros, + etc.) +3) Reading arrays from disk, either from standard or custom formats +4) Creating arrays from raw bytes through the use of strings or buffers +5) Use of special library functions (e.g., random) + +This section will not cover means of replicating, joining, or otherwise +expanding or mutating existing arrays. Nor will it cover creating object +arrays or structured arrays. Both of those are covered in their own sections. + +Converting Python array_like Objects to NumPy Arrays +==================================================== + +In general, numerical data arranged in an array-like structure in Python can +be converted to arrays through the use of the array() function. The most +obvious examples are lists and tuples. See the documentation for array() for +details for its use. Some objects may support the array-protocol and allow +conversion to arrays this way. A simple way to find out if the object can be +converted to a numpy array using array() is simply to try it interactively and +see if it works! (The Python Way). + +Examples: :: + + >>> x = np.array([2,3,1,0]) + >>> x = np.array([2, 3, 1, 0]) + >>> x = np.array([[1,2.0],[0,0],(1+1j,3.)]) # note mix of tuple and lists, + and types + >>> x = np.array([[ 1.+0.j, 2.+0.j], [ 0.+0.j, 0.+0.j], [ 1.+1.j, 3.+0.j]]) + +Intrinsic NumPy Array Creation +============================== + +NumPy has built-in functions for creating arrays from scratch: + +zeros(shape) will create an array filled with 0 values with the specified +shape. The default dtype is float64. + +``>>> np.zeros((2, 3)) +array([[ 0., 0., 0.], [ 0., 0., 0.]])`` + +ones(shape) will create an array filled with 1 values. It is identical to +zeros in all other respects. + +arange() will create arrays with regularly incrementing values. Check the +docstring for complete information on the various ways it can be used. A few +examples will be given here: :: + + >>> np.arange(10) + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> np.arange(2, 10, dtype=float) + array([ 2., 3., 4., 5., 6., 7., 8., 9.]) + >>> np.arange(2, 3, 0.1) + array([ 2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9]) + +Note that there are some subtleties regarding the last usage that the user +should be aware of that are described in the arange docstring. + +linspace() will create arrays with a specified number of elements, and +spaced equally between the specified beginning and end values. For +example: :: + + >>> np.linspace(1., 4., 6) + array([ 1. , 1.6, 2.2, 2.8, 3.4, 4. ]) + +The advantage of this creation function is that one can guarantee the +number of elements and the starting and end point, which arange() +generally will not do for arbitrary start, stop, and step values. + +indices() will create a set of arrays (stacked as a one-higher dimensioned +array), one per dimension with each representing variation in that dimension. +An example illustrates much better than a verbal description: :: + + >>> np.indices((3,3)) + array([[[0, 0, 0], [1, 1, 1], [2, 2, 2]], [[0, 1, 2], [0, 1, 2], [0, 1, 2]]]) + +This is particularly useful for evaluating functions of multiple dimensions on +a regular grid. + +Reading Arrays From Disk +======================== + +This is presumably the most common case of large array creation. The details, +of course, depend greatly on the format of data on disk and so this section +can only give general pointers on how to handle various formats. + +Standard Binary Formats +----------------------- + +Various fields have standard formats for array data. The following lists the +ones with known python libraries to read them and return numpy arrays (there +may be others for which it is possible to read and convert to numpy arrays so +check the last section as well) +:: + + HDF5: h5py + FITS: Astropy + +Examples of formats that cannot be read directly but for which it is not hard to +convert are those formats supported by libraries like PIL (able to read and +write many image formats such as jpg, png, etc). + +Common ASCII Formats +------------------------ + +Comma Separated Value files (CSV) are widely used (and an export and import +option for programs like Excel). There are a number of ways of reading these +files in Python. There are CSV functions in Python and functions in pylab +(part of matplotlib). + +More generic ascii files can be read using the io package in scipy. + +Custom Binary Formats +--------------------- + +There are a variety of approaches one can use. If the file has a relatively +simple format then one can write a simple I/O library and use the numpy +fromfile() function and .tofile() method to read and write numpy arrays +directly (mind your byteorder though!) If a good C or C++ library exists that +read the data, one can wrap that library with a variety of techniques though +that certainly is much more work and requires significantly more advanced +knowledge to interface with C or C++. + +Use of Special Libraries +------------------------ + +There are libraries that can be used to generate arrays for special purposes +and it isn't possible to enumerate all of them. The most common uses are use +of the many array generation functions in random that can generate arrays of +random values, and some utility functions to generate special matrices (e.g. +diagonal). + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/glossary.py b/numpy/doc/glossary.py new file mode 100644 index 0000000..9b7d613 --- /dev/null +++ b/numpy/doc/glossary.py @@ -0,0 +1,424 @@ +""" +======== +Glossary +======== + +.. glossary:: + + along an axis + Axes are defined for arrays with more than one dimension. A + 2-dimensional array has two corresponding axes: the first running + vertically downwards across rows (axis 0), and the second running + horizontally across columns (axis 1). + + Many operations can take place along one of these axes. For example, + we can sum each row of an array, in which case we operate along + columns, or axis 1:: + + >>> x = np.arange(12).reshape((3,4)) + + >>> x + array([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + + >>> x.sum(axis=1) + array([ 6, 22, 38]) + + array + A homogeneous container of numerical elements. Each element in the + array occupies a fixed amount of memory (hence homogeneous), and + can be a numerical element of a single type (such as float, int + or complex) or a combination (such as ``(float, int, float)``). Each + array has an associated data-type (or ``dtype``), which describes + the numerical type of its elements:: + + >>> x = np.array([1, 2, 3], float) + + >>> x + array([ 1., 2., 3.]) + + >>> x.dtype # floating point number, 64 bits of memory per element + dtype('float64') + + + # More complicated data type: each array element is a combination of + # and integer and a floating point number + >>> np.array([(1, 2.0), (3, 4.0)], dtype=[('x', int), ('y', float)]) + array([(1, 2.0), (3, 4.0)], + dtype=[('x', '>> x = np.array([1, 2, 3]) + >>> x.shape + (3,) + + BLAS + `Basic Linear Algebra Subprograms `_ + + broadcast + NumPy can do operations on arrays whose shapes are mismatched:: + + >>> x = np.array([1, 2]) + >>> y = np.array([[3], [4]]) + + >>> x + array([1, 2]) + + >>> y + array([[3], + [4]]) + + >>> x + y + array([[4, 5], + [5, 6]]) + + See `numpy.doc.broadcasting` for more information. + + C order + See `row-major` + + column-major + A way to represent items in a N-dimensional array in the 1-dimensional + computer memory. In column-major order, the leftmost index "varies the + fastest": for example the array:: + + [[1, 2, 3], + [4, 5, 6]] + + is represented in the column-major order as:: + + [1, 4, 2, 5, 3, 6] + + Column-major order is also known as the Fortran order, as the Fortran + programming language uses it. + + decorator + An operator that transforms a function. For example, a ``log`` + decorator may be defined to print debugging information upon + function execution:: + + >>> def log(f): + ... def new_logging_func(*args, **kwargs): + ... print("Logging call with parameters:", args, kwargs) + ... return f(*args, **kwargs) + ... + ... return new_logging_func + + Now, when we define a function, we can "decorate" it using ``log``:: + + >>> @log + ... def add(a, b): + ... return a + b + + Calling ``add`` then yields: + + >>> add(1, 2) + Logging call with parameters: (1, 2) {} + 3 + + dictionary + Resembling a language dictionary, which provides a mapping between + words and descriptions thereof, a Python dictionary is a mapping + between two objects:: + + >>> x = {1: 'one', 'two': [1, 2]} + + Here, `x` is a dictionary mapping keys to values, in this case + the integer 1 to the string "one", and the string "two" to + the list ``[1, 2]``. The values may be accessed using their + corresponding keys:: + + >>> x[1] + 'one' + + >>> x['two'] + [1, 2] + + Note that dictionaries are not stored in any specific order. Also, + most mutable (see *immutable* below) objects, such as lists, may not + be used as keys. + + For more information on dictionaries, read the + `Python tutorial `_. + + Fortran order + See `column-major` + + flattened + Collapsed to a one-dimensional array. See `numpy.ndarray.flatten` + for details. + + immutable + An object that cannot be modified after execution is called + immutable. Two common examples are strings and tuples. + + instance + A class definition gives the blueprint for constructing an object:: + + >>> class House(object): + ... wall_colour = 'white' + + Yet, we have to *build* a house before it exists:: + + >>> h = House() # build a house + + Now, ``h`` is called a ``House`` instance. An instance is therefore + a specific realisation of a class. + + iterable + A sequence that allows "walking" (iterating) over items, typically + using a loop such as:: + + >>> x = [1, 2, 3] + >>> [item**2 for item in x] + [1, 4, 9] + + It is often used in combination with ``enumerate``:: + >>> keys = ['a','b','c'] + >>> for n, k in enumerate(keys): + ... print("Key %d: %s" % (n, k)) + ... + Key 0: a + Key 1: b + Key 2: c + + list + A Python container that can hold any number of objects or items. + The items do not have to be of the same type, and can even be + lists themselves:: + + >>> x = [2, 2.0, "two", [2, 2.0]] + + The list `x` contains 4 items, each which can be accessed individually:: + + >>> x[2] # the string 'two' + 'two' + + >>> x[3] # a list, containing an integer 2 and a float 2.0 + [2, 2.0] + + It is also possible to select more than one item at a time, + using *slicing*:: + + >>> x[0:2] # or, equivalently, x[:2] + [2, 2.0] + + In code, arrays are often conveniently expressed as nested lists:: + + + >>> np.array([[1, 2], [3, 4]]) + array([[1, 2], + [3, 4]]) + + For more information, read the section on lists in the `Python + tutorial `_. For a mapping + type (key-value), see *dictionary*. + + mask + A boolean array, used to select only certain elements for an operation:: + + >>> x = np.arange(5) + >>> x + array([0, 1, 2, 3, 4]) + + >>> mask = (x > 2) + >>> mask + array([False, False, False, True, True]) + + >>> x[mask] = -1 + >>> x + array([ 0, 1, 2, -1, -1]) + + masked array + Array that suppressed values indicated by a mask:: + + >>> x = np.ma.masked_array([np.nan, 2, np.nan], [True, False, True]) + >>> x + masked_array(data = [-- 2.0 --], + mask = [ True False True], + fill_value = 1e+20) + + + >>> x + [1, 2, 3] + masked_array(data = [-- 4.0 --], + mask = [ True False True], + fill_value = 1e+20) + + + + Masked arrays are often used when operating on arrays containing + missing or invalid entries. + + matrix + A 2-dimensional ndarray that preserves its two-dimensional nature + throughout operations. It has certain special operations, such as ``*`` + (matrix multiplication) and ``**`` (matrix power), defined:: + + >>> x = np.mat([[1, 2], [3, 4]]) + >>> x + matrix([[1, 2], + [3, 4]]) + + >>> x**2 + matrix([[ 7, 10], + [15, 22]]) + + method + A function associated with an object. For example, each ndarray has a + method called ``repeat``:: + + >>> x = np.array([1, 2, 3]) + >>> x.repeat(2) + array([1, 1, 2, 2, 3, 3]) + + ndarray + See *array*. + + record array + An :term:`ndarray` with :term:`structured data type`_ which has been + subclassed as ``np.recarray`` and whose dtype is of type ``np.record``, + making the fields of its data type to be accessible by attribute. + + reference + If ``a`` is a reference to ``b``, then ``(a is b) == True``. Therefore, + ``a`` and ``b`` are different names for the same Python object. + + row-major + A way to represent items in a N-dimensional array in the 1-dimensional + computer memory. In row-major order, the rightmost index "varies + the fastest": for example the array:: + + [[1, 2, 3], + [4, 5, 6]] + + is represented in the row-major order as:: + + [1, 2, 3, 4, 5, 6] + + Row-major order is also known as the C order, as the C programming + language uses it. New NumPy arrays are by default in row-major order. + + self + Often seen in method signatures, ``self`` refers to the instance + of the associated class. For example: + + >>> class Paintbrush(object): + ... color = 'blue' + ... + ... def paint(self): + ... print("Painting the city %s!" % self.color) + ... + >>> p = Paintbrush() + >>> p.color = 'red' + >>> p.paint() # self refers to 'p' + Painting the city red! + + slice + Used to select only certain elements from a sequence:: + + >>> x = range(5) + >>> x + [0, 1, 2, 3, 4] + + >>> x[1:3] # slice from 1 to 3 (excluding 3 itself) + [1, 2] + + >>> x[1:5:2] # slice from 1 to 5, but skipping every second element + [1, 3] + + >>> x[::-1] # slice a sequence in reverse + [4, 3, 2, 1, 0] + + Arrays may have more than one dimension, each which can be sliced + individually:: + + >>> x = np.array([[1, 2], [3, 4]]) + >>> x + array([[1, 2], + [3, 4]]) + + >>> x[:, 1] + array([2, 4]) + + structured data type + A data type composed of other datatypes + + tuple + A sequence that may contain a variable number of types of any + kind. A tuple is immutable, i.e., once constructed it cannot be + changed. Similar to a list, it can be indexed and sliced:: + + >>> x = (1, 'one', [1, 2]) + >>> x + (1, 'one', [1, 2]) + + >>> x[0] + 1 + + >>> x[:2] + (1, 'one') + + A useful concept is "tuple unpacking", which allows variables to + be assigned to the contents of a tuple:: + + >>> x, y = (1, 2) + >>> x, y = 1, 2 + + This is often used when a function returns multiple values: + + >>> def return_many(): + ... return 1, 'alpha', None + + >>> a, b, c = return_many() + >>> a, b, c + (1, 'alpha', None) + + >>> a + 1 + >>> b + 'alpha' + + ufunc + Universal function. A fast element-wise array operation. Examples include + ``add``, ``sin`` and ``logical_or``. + + view + An array that does not own its data, but refers to another array's + data instead. For example, we may create a view that only shows + every second element of another array:: + + >>> x = np.arange(5) + >>> x + array([0, 1, 2, 3, 4]) + + >>> y = x[::2] + >>> y + array([0, 2, 4]) + + >>> x[0] = 3 # changing x changes y as well, since y is a view on x + >>> y + array([3, 2, 4]) + + wrapper + Python is a high-level (highly abstracted, or English-like) language. + This abstraction comes at a price in execution speed, and sometimes + it becomes necessary to use lower level languages to do fast + computations. A wrapper is code that provides a bridge between + high and the low level languages, allowing, e.g., Python to execute + code written in C or Fortran. + + Examples include ctypes, SWIG and Cython (which wraps C and C++) + and f2py (which wraps Fortran). + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/indexing.py b/numpy/doc/indexing.py new file mode 100644 index 0000000..5f50331 --- /dev/null +++ b/numpy/doc/indexing.py @@ -0,0 +1,439 @@ +"""============== +Array indexing +============== + +Array indexing refers to any use of the square brackets ([]) to index +array values. There are many options to indexing, which give numpy +indexing great power, but with power comes some complexity and the +potential for confusion. This section is just an overview of the +various options and issues related to indexing. Aside from single +element indexing, the details on most of these options are to be +found in related sections. + +Assignment vs referencing +========================= + +Most of the following examples show the use of indexing when +referencing data in an array. The examples work just as well +when assigning to an array. See the section at the end for +specific examples and explanations on how assignments work. + +Single element indexing +======================= + +Single element indexing for a 1-D array is what one expects. It work +exactly like that for other standard Python sequences. It is 0-based, +and accepts negative indices for indexing from the end of the array. :: + + >>> x = np.arange(10) + >>> x[2] + 2 + >>> x[-2] + 8 + +Unlike lists and tuples, numpy arrays support multidimensional indexing +for multidimensional arrays. That means that it is not necessary to +separate each dimension's index into its own set of square brackets. :: + + >>> x.shape = (2,5) # now x is 2-dimensional + >>> x[1,3] + 8 + >>> x[1,-1] + 9 + +Note that if one indexes a multidimensional array with fewer indices +than dimensions, one gets a subdimensional array. For example: :: + + >>> x[0] + array([0, 1, 2, 3, 4]) + +That is, each index specified selects the array corresponding to the +rest of the dimensions selected. In the above example, choosing 0 +means that the remaining dimension of length 5 is being left unspecified, +and that what is returned is an array of that dimensionality and size. +It must be noted that the returned array is not a copy of the original, +but points to the same values in memory as does the original array. +In this case, the 1-D array at the first position (0) is returned. +So using a single index on the returned array, results in a single +element being returned. That is: :: + + >>> x[0][2] + 2 + +So note that ``x[0,2] = x[0][2]`` though the second case is more +inefficient as a new temporary array is created after the first index +that is subsequently indexed by 2. + +Note to those used to IDL or Fortran memory order as it relates to +indexing. NumPy uses C-order indexing. That means that the last +index usually represents the most rapidly changing memory location, +unlike Fortran or IDL, where the first index represents the most +rapidly changing location in memory. This difference represents a +great potential for confusion. + +Other indexing options +====================== + +It is possible to slice and stride arrays to extract arrays of the +same number of dimensions, but of different sizes than the original. +The slicing and striding works exactly the same way it does for lists +and tuples except that they can be applied to multiple dimensions as +well. A few examples illustrates best: :: + + >>> x = np.arange(10) + >>> x[2:5] + array([2, 3, 4]) + >>> x[:-7] + array([0, 1, 2]) + >>> x[1:7:2] + array([1, 3, 5]) + >>> y = np.arange(35).reshape(5,7) + >>> y[1:5:2,::3] + array([[ 7, 10, 13], + [21, 24, 27]]) + +Note that slices of arrays do not copy the internal array data but +also produce new views of the original data. + +It is possible to index arrays with other arrays for the purposes of +selecting lists of values out of arrays into new arrays. There are +two different ways of accomplishing this. One uses one or more arrays +of index values. The other involves giving a boolean array of the proper +shape to indicate the values to be selected. Index arrays are a very +powerful tool that allow one to avoid looping over individual elements in +arrays and thus greatly improve performance. + +It is possible to use special features to effectively increase the +number of dimensions in an array through indexing so the resulting +array aquires the shape needed for use in an expression or with a +specific function. + +Index arrays +============ + +NumPy arrays may be indexed with other arrays (or any other sequence- +like object that can be converted to an array, such as lists, with the +exception of tuples; see the end of this document for why this is). The +use of index arrays ranges from simple, straightforward cases to +complex, hard-to-understand cases. For all cases of index arrays, what +is returned is a copy of the original data, not a view as one gets for +slices. + +Index arrays must be of integer type. Each value in the array indicates +which value in the array to use in place of the index. To illustrate: :: + + >>> x = np.arange(10,1,-1) + >>> x + array([10, 9, 8, 7, 6, 5, 4, 3, 2]) + >>> x[np.array([3, 3, 1, 8])] + array([7, 7, 9, 2]) + + +The index array consisting of the values 3, 3, 1 and 8 correspondingly +create an array of length 4 (same as the index array) where each index +is replaced by the value the index array has in the array being indexed. + +Negative values are permitted and work as they do with single indices +or slices: :: + + >>> x[np.array([3,3,-3,8])] + array([7, 7, 4, 2]) + +It is an error to have index values out of bounds: :: + + >>> x[np.array([3, 3, 20, 8])] + : index 20 out of bounds 0<=index<9 + +Generally speaking, what is returned when index arrays are used is +an array with the same shape as the index array, but with the type +and values of the array being indexed. As an example, we can use a +multidimensional index array instead: :: + + >>> x[np.array([[1,1],[2,3]])] + array([[9, 9], + [8, 7]]) + +Indexing Multi-dimensional arrays +================================= + +Things become more complex when multidimensional arrays are indexed, +particularly with multidimensional index arrays. These tend to be +more unusual uses, but they are permitted, and they are useful for some +problems. We'll start with the simplest multidimensional case (using +the array y from the previous examples): :: + + >>> y[np.array([0,2,4]), np.array([0,1,2])] + array([ 0, 15, 30]) + +In this case, if the index arrays have a matching shape, and there is +an index array for each dimension of the array being indexed, the +resultant array has the same shape as the index arrays, and the values +correspond to the index set for each position in the index arrays. In +this example, the first index value is 0 for both index arrays, and +thus the first value of the resultant array is y[0,0]. The next value +is y[2,1], and the last is y[4,2]. + +If the index arrays do not have the same shape, there is an attempt to +broadcast them to the same shape. If they cannot be broadcast to the +same shape, an exception is raised: :: + + >>> y[np.array([0,2,4]), np.array([0,1])] + : shape mismatch: objects cannot be + broadcast to a single shape + +The broadcasting mechanism permits index arrays to be combined with +scalars for other indices. The effect is that the scalar value is used +for all the corresponding values of the index arrays: :: + + >>> y[np.array([0,2,4]), 1] + array([ 1, 15, 29]) + +Jumping to the next level of complexity, it is possible to only +partially index an array with index arrays. It takes a bit of thought +to understand what happens in such cases. For example if we just use +one index array with y: :: + + >>> y[np.array([0,2,4])] + array([[ 0, 1, 2, 3, 4, 5, 6], + [14, 15, 16, 17, 18, 19, 20], + [28, 29, 30, 31, 32, 33, 34]]) + +What results is the construction of a new array where each value of +the index array selects one row from the array being indexed and the +resultant array has the resulting shape (number of index elements, +size of row). + +An example of where this may be useful is for a color lookup table +where we want to map the values of an image into RGB triples for +display. The lookup table could have a shape (nlookup, 3). Indexing +such an array with an image with shape (ny, nx) with dtype=np.uint8 +(or any integer type so long as values are with the bounds of the +lookup table) will result in an array of shape (ny, nx, 3) where a +triple of RGB values is associated with each pixel location. + +In general, the shape of the resultant array will be the concatenation +of the shape of the index array (or the shape that all the index arrays +were broadcast to) with the shape of any unused dimensions (those not +indexed) in the array being indexed. + +Boolean or "mask" index arrays +============================== + +Boolean arrays used as indices are treated in a different manner +entirely than index arrays. Boolean arrays must be of the same shape +as the initial dimensions of the array being indexed. In the +most straightforward case, the boolean array has the same shape: :: + + >>> b = y>20 + >>> y[b] + array([21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]) + +Unlike in the case of integer index arrays, in the boolean case, the +result is a 1-D array containing all the elements in the indexed array +corresponding to all the true elements in the boolean array. The +elements in the indexed array are always iterated and returned in +:term:`row-major` (C-style) order. The result is also identical to +``y[np.nonzero(b)]``. As with index arrays, what is returned is a copy +of the data, not a view as one gets with slices. + +The result will be multidimensional if y has more dimensions than b. +For example: :: + + >>> b[:,5] # use a 1-D boolean whose first dim agrees with the first dim of y + array([False, False, False, True, True]) + >>> y[b[:,5]] + array([[21, 22, 23, 24, 25, 26, 27], + [28, 29, 30, 31, 32, 33, 34]]) + +Here the 4th and 5th rows are selected from the indexed array and +combined to make a 2-D array. + +In general, when the boolean array has fewer dimensions than the array +being indexed, this is equivalent to y[b, ...], which means +y is indexed by b followed by as many : as are needed to fill +out the rank of y. +Thus the shape of the result is one dimension containing the number +of True elements of the boolean array, followed by the remaining +dimensions of the array being indexed. + +For example, using a 2-D boolean array of shape (2,3) +with four True elements to select rows from a 3-D array of shape +(2,3,5) results in a 2-D result of shape (4,5): :: + + >>> x = np.arange(30).reshape(2,3,5) + >>> x + array([[[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]], + [[15, 16, 17, 18, 19], + [20, 21, 22, 23, 24], + [25, 26, 27, 28, 29]]]) + >>> b = np.array([[True, True, False], [False, True, True]]) + >>> x[b] + array([[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [20, 21, 22, 23, 24], + [25, 26, 27, 28, 29]]) + +For further details, consult the numpy reference documentation on array indexing. + +Combining index arrays with slices +================================== + +Index arrays may be combined with slices. For example: :: + + >>> y[np.array([0,2,4]),1:3] + array([[ 1, 2], + [15, 16], + [29, 30]]) + +In effect, the slice is converted to an index array +np.array([[1,2]]) (shape (1,2)) that is broadcast with the index array +to produce a resultant array of shape (3,2). + +Likewise, slicing can be combined with broadcasted boolean indices: :: + + >>> y[b[:,5],1:3] + array([[22, 23], + [29, 30]]) + +Structural indexing tools +========================= + +To facilitate easy matching of array shapes with expressions and in +assignments, the np.newaxis object can be used within array indices +to add new dimensions with a size of 1. For example: :: + + >>> y.shape + (5, 7) + >>> y[:,np.newaxis,:].shape + (5, 1, 7) + +Note that there are no new elements in the array, just that the +dimensionality is increased. This can be handy to combine two +arrays in a way that otherwise would require explicitly reshaping +operations. For example: :: + + >>> x = np.arange(5) + >>> x[:,np.newaxis] + x[np.newaxis,:] + array([[0, 1, 2, 3, 4], + [1, 2, 3, 4, 5], + [2, 3, 4, 5, 6], + [3, 4, 5, 6, 7], + [4, 5, 6, 7, 8]]) + +The ellipsis syntax maybe used to indicate selecting in full any +remaining unspecified dimensions. For example: :: + + >>> z = np.arange(81).reshape(3,3,3,3) + >>> z[1,...,2] + array([[29, 32, 35], + [38, 41, 44], + [47, 50, 53]]) + +This is equivalent to: :: + + >>> z[1,:,:,2] + array([[29, 32, 35], + [38, 41, 44], + [47, 50, 53]]) + +Assigning values to indexed arrays +================================== + +As mentioned, one can select a subset of an array to assign to using +a single index, slices, and index and mask arrays. The value being +assigned to the indexed array must be shape consistent (the same shape +or broadcastable to the shape the index produces). For example, it is +permitted to assign a constant to a slice: :: + + >>> x = np.arange(10) + >>> x[2:7] = 1 + +or an array of the right size: :: + + >>> x[2:7] = np.arange(5) + +Note that assignments may result in changes if assigning +higher types to lower types (like floats to ints) or even +exceptions (assigning complex to floats or ints): :: + + >>> x[1] = 1.2 + >>> x[1] + 1 + >>> x[1] = 1.2j + : can't convert complex to long; use + long(abs(z)) + + +Unlike some of the references (such as array and mask indices) +assignments are always made to the original data in the array +(indeed, nothing else would make sense!). Note though, that some +actions may not work as one may naively expect. This particular +example is often surprising to people: :: + + >>> x = np.arange(0, 50, 10) + >>> x + array([ 0, 10, 20, 30, 40]) + >>> x[np.array([1, 1, 3, 1])] += 1 + >>> x + array([ 0, 11, 20, 31, 40]) + +Where people expect that the 1st location will be incremented by 3. +In fact, it will only be incremented by 1. The reason is because +a new array is extracted from the original (as a temporary) containing +the values at 1, 1, 3, 1, then the value 1 is added to the temporary, +and then the temporary is assigned back to the original array. Thus +the value of the array at x[1]+1 is assigned to x[1] three times, +rather than being incremented 3 times. + +Dealing with variable numbers of indices within programs +======================================================== + +The index syntax is very powerful but limiting when dealing with +a variable number of indices. For example, if you want to write +a function that can handle arguments with various numbers of +dimensions without having to write special case code for each +number of possible dimensions, how can that be done? If one +supplies to the index a tuple, the tuple will be interpreted +as a list of indices. For example (using the previous definition +for the array z): :: + + >>> indices = (1,1,1,1) + >>> z[indices] + 40 + +So one can use code to construct tuples of any number of indices +and then use these within an index. + +Slices can be specified within programs by using the slice() function +in Python. For example: :: + + >>> indices = (1,1,1,slice(0,2)) # same as [1,1,1,0:2] + >>> z[indices] + array([39, 40]) + +Likewise, ellipsis can be specified by code by using the Ellipsis +object: :: + + >>> indices = (1, Ellipsis, 1) # same as [1,...,1] + >>> z[indices] + array([[28, 31, 34], + [37, 40, 43], + [46, 49, 52]]) + +For this reason it is possible to use the output from the np.nonzero() +function directly as an index since it always returns a tuple of index +arrays. + +Because the special treatment of tuples, they are not automatically +converted to an array as a list would be. As an example: :: + + >>> z[[1,1,1,1]] # produces a large array + array([[[[27, 28, 29], + [30, 31, 32], ... + >>> z[(1,1,1,1)] # returns a single value + 40 + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/internals.py b/numpy/doc/internals.py new file mode 100644 index 0000000..a14fee7 --- /dev/null +++ b/numpy/doc/internals.py @@ -0,0 +1,163 @@ +""" +=============== +Array Internals +=============== + +Internal organization of numpy arrays +===================================== + +It helps to understand a bit about how numpy arrays are handled under the covers to help understand numpy better. This section will not go into great detail. Those wishing to understand the full details are referred to Travis Oliphant's book "Guide to NumPy". + +NumPy arrays consist of two major components, the raw array data (from now on, +referred to as the data buffer), and the information about the raw array data. +The data buffer is typically what people think of as arrays in C or Fortran, +a contiguous (and fixed) block of memory containing fixed sized data items. +NumPy also contains a significant set of data that describes how to interpret +the data in the data buffer. This extra information contains (among other things): + + 1) The basic data element's size in bytes + 2) The start of the data within the data buffer (an offset relative to the + beginning of the data buffer). + 3) The number of dimensions and the size of each dimension + 4) The separation between elements for each dimension (the 'stride'). This + does not have to be a multiple of the element size + 5) The byte order of the data (which may not be the native byte order) + 6) Whether the buffer is read-only + 7) Information (via the dtype object) about the interpretation of the basic + data element. The basic data element may be as simple as a int or a float, + or it may be a compound object (e.g., struct-like), a fixed character field, + or Python object pointers. + 8) Whether the array is to interpreted as C-order or Fortran-order. + +This arrangement allow for very flexible use of arrays. One thing that it allows +is simple changes of the metadata to change the interpretation of the array buffer. +Changing the byteorder of the array is a simple change involving no rearrangement +of the data. The shape of the array can be changed very easily without changing +anything in the data buffer or any data copying at all + +Among other things that are made possible is one can create a new array metadata +object that uses the same data buffer +to create a new view of that data buffer that has a different interpretation +of the buffer (e.g., different shape, offset, byte order, strides, etc) but +shares the same data bytes. Many operations in numpy do just this such as +slices. Other operations, such as transpose, don't move data elements +around in the array, but rather change the information about the shape and strides so that the indexing of the array changes, but the data in the doesn't move. + +Typically these new versions of the array metadata but the same data buffer are +new 'views' into the data buffer. There is a different ndarray object, but it +uses the same data buffer. This is why it is necessary to force copies through +use of the .copy() method if one really wants to make a new and independent +copy of the data buffer. + +New views into arrays mean the object reference counts for the data buffer +increase. Simply doing away with the original array object will not remove the +data buffer if other views of it still exist. + +Multidimensional Array Indexing Order Issues +============================================ + +What is the right way to index +multi-dimensional arrays? Before you jump to conclusions about the one and +true way to index multi-dimensional arrays, it pays to understand why this is +a confusing issue. This section will try to explain in detail how numpy +indexing works and why we adopt the convention we do for images, and when it +may be appropriate to adopt other conventions. + +The first thing to understand is +that there are two conflicting conventions for indexing 2-dimensional arrays. +Matrix notation uses the first index to indicate which row is being selected and +the second index to indicate which column is selected. This is opposite the +geometrically oriented-convention for images where people generally think the +first index represents x position (i.e., column) and the second represents y +position (i.e., row). This alone is the source of much confusion; +matrix-oriented users and image-oriented users expect two different things with +regard to indexing. + +The second issue to understand is how indices correspond +to the order the array is stored in memory. In Fortran the first index is the +most rapidly varying index when moving through the elements of a two +dimensional array as it is stored in memory. If you adopt the matrix +convention for indexing, then this means the matrix is stored one column at a +time (since the first index moves to the next row as it changes). Thus Fortran +is considered a Column-major language. C has just the opposite convention. In +C, the last index changes most rapidly as one moves through the array as +stored in memory. Thus C is a Row-major language. The matrix is stored by +rows. Note that in both cases it presumes that the matrix convention for +indexing is being used, i.e., for both Fortran and C, the first index is the +row. Note this convention implies that the indexing convention is invariant +and that the data order changes to keep that so. + +But that's not the only way +to look at it. Suppose one has large two-dimensional arrays (images or +matrices) stored in data files. Suppose the data are stored by rows rather than +by columns. If we are to preserve our index convention (whether matrix or +image) that means that depending on the language we use, we may be forced to +reorder the data if it is read into memory to preserve our indexing +convention. For example if we read row-ordered data into memory without +reordering, it will match the matrix indexing convention for C, but not for +Fortran. Conversely, it will match the image indexing convention for Fortran, +but not for C. For C, if one is using data stored in row order, and one wants +to preserve the image index convention, the data must be reordered when +reading into memory. + +In the end, which you do for Fortran or C depends on +which is more important, not reordering data or preserving the indexing +convention. For large images, reordering data is potentially expensive, and +often the indexing convention is inverted to avoid that. + +The situation with +numpy makes this issue yet more complicated. The internal machinery of numpy +arrays is flexible enough to accept any ordering of indices. One can simply +reorder indices by manipulating the internal stride information for arrays +without reordering the data at all. NumPy will know how to map the new index +order to the data without moving the data. + +So if this is true, why not choose +the index order that matches what you most expect? In particular, why not define +row-ordered images to use the image convention? (This is sometimes referred +to as the Fortran convention vs the C convention, thus the 'C' and 'FORTRAN' +order options for array ordering in numpy.) The drawback of doing this is +potential performance penalties. It's common to access the data sequentially, +either implicitly in array operations or explicitly by looping over rows of an +image. When that is done, then the data will be accessed in non-optimal order. +As the first index is incremented, what is actually happening is that elements +spaced far apart in memory are being sequentially accessed, with usually poor +memory access speeds. For example, for a two dimensional image 'im' defined so +that im[0, 10] represents the value at x=0, y=10. To be consistent with usual +Python behavior then im[0] would represent a column at x=0. Yet that data +would be spread over the whole array since the data are stored in row order. +Despite the flexibility of numpy's indexing, it can't really paper over the fact +basic operations are rendered inefficient because of data order or that getting +contiguous subarrays is still awkward (e.g., im[:,0] for the first row, vs +im[0]), thus one can't use an idiom such as for row in im; for col in im does +work, but doesn't yield contiguous column data. + +As it turns out, numpy is +smart enough when dealing with ufuncs to determine which index is the most +rapidly varying one in memory and uses that for the innermost loop. Thus for +ufuncs there is no large intrinsic advantage to either approach in most cases. +On the other hand, use of .flat with an FORTRAN ordered array will lead to +non-optimal memory access as adjacent elements in the flattened array (iterator, +actually) are not contiguous in memory. + +Indeed, the fact is that Python +indexing on lists and other sequences naturally leads to an outside-to inside +ordering (the first index gets the largest grouping, the next the next largest, +and the last gets the smallest element). Since image data are normally stored +by rows, this corresponds to position within rows being the last item indexed. + +If you do want to use Fortran ordering realize that +there are two approaches to consider: 1) accept that the first index is just not +the most rapidly changing in memory and have all your I/O routines reorder +your data when going from memory to disk or visa versa, or use numpy's +mechanism for mapping the first index to the most rapidly varying data. We +recommend the former if possible. The disadvantage of the latter is that many +of numpy's functions will yield arrays without Fortran ordering unless you are +careful to use the 'order' keyword. Doing this would be highly inconvenient. + +Otherwise we recommend simply learning to reverse the usual order of indices +when accessing elements of an array. Granted, it goes against the grain, but +it is more in line with Python semantics and the natural order of the data. + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/misc.py b/numpy/doc/misc.py new file mode 100644 index 0000000..5d6708a --- /dev/null +++ b/numpy/doc/misc.py @@ -0,0 +1,227 @@ +""" +============= +Miscellaneous +============= + +IEEE 754 Floating Point Special Values +-------------------------------------- + +Special values defined in numpy: nan, inf, + +NaNs can be used as a poor-man's mask (if you don't care what the +original value was) + +Note: cannot use equality to test NaNs. E.g.: :: + + >>> myarr = np.array([1., 0., np.nan, 3.]) + >>> np.nonzero(myarr == np.nan) + (array([], dtype=int64),) + >>> np.nan == np.nan # is always False! Use special numpy functions instead. + False + >>> myarr[myarr == np.nan] = 0. # doesn't work + >>> myarr + array([ 1., 0., NaN, 3.]) + >>> myarr[np.isnan(myarr)] = 0. # use this instead find + >>> myarr + array([ 1., 0., 0., 3.]) + +Other related special value functions: :: + + isinf(): True if value is inf + isfinite(): True if not nan or inf + nan_to_num(): Map nan to 0, inf to max float, -inf to min float + +The following corresponds to the usual functions except that nans are excluded +from the results: :: + + nansum() + nanmax() + nanmin() + nanargmax() + nanargmin() + + >>> x = np.arange(10.) + >>> x[3] = np.nan + >>> x.sum() + nan + >>> np.nansum(x) + 42.0 + +How numpy handles numerical exceptions +-------------------------------------- + +The default is to ``'warn'`` for ``invalid``, ``divide``, and ``overflow`` +and ``'ignore'`` for ``underflow``. But this can be changed, and it can be +set individually for different kinds of exceptions. The different behaviors +are: + + - 'ignore' : Take no action when the exception occurs. + - 'warn' : Print a `RuntimeWarning` (via the Python `warnings` module). + - 'raise' : Raise a `FloatingPointError`. + - 'call' : Call a function specified using the `seterrcall` function. + - 'print' : Print a warning directly to ``stdout``. + - 'log' : Record error in a Log object specified by `seterrcall`. + +These behaviors can be set for all kinds of errors or specific ones: + + - all : apply to all numeric exceptions + - invalid : when NaNs are generated + - divide : divide by zero (for integers as well!) + - overflow : floating point overflows + - underflow : floating point underflows + +Note that integer divide-by-zero is handled by the same machinery. +These behaviors are set on a per-thread basis. + +Examples +-------- + +:: + + >>> oldsettings = np.seterr(all='warn') + >>> np.zeros(5,dtype=np.float32)/0. + invalid value encountered in divide + >>> j = np.seterr(under='ignore') + >>> np.array([1.e-100])**10 + >>> j = np.seterr(invalid='raise') + >>> np.sqrt(np.array([-1.])) + FloatingPointError: invalid value encountered in sqrt + >>> def errorhandler(errstr, errflag): + ... print("saw stupid error!") + >>> np.seterrcall(errorhandler) + + >>> j = np.seterr(all='call') + >>> np.zeros(5, dtype=np.int32)/0 + FloatingPointError: invalid value encountered in divide + saw stupid error! + >>> j = np.seterr(**oldsettings) # restore previous + ... # error-handling settings + +Interfacing to C +---------------- +Only a survey of the choices. Little detail on how each works. + +1) Bare metal, wrap your own C-code manually. + + - Plusses: + + - Efficient + - No dependencies on other tools + + - Minuses: + + - Lots of learning overhead: + + - need to learn basics of Python C API + - need to learn basics of numpy C API + - need to learn how to handle reference counting and love it. + + - Reference counting often difficult to get right. + + - getting it wrong leads to memory leaks, and worse, segfaults + + - API will change for Python 3.0! + +2) Cython + + - Plusses: + + - avoid learning C API's + - no dealing with reference counting + - can code in pseudo python and generate C code + - can also interface to existing C code + - should shield you from changes to Python C api + - has become the de-facto standard within the scientific Python community + - fast indexing support for arrays + + - Minuses: + + - Can write code in non-standard form which may become obsolete + - Not as flexible as manual wrapping + +3) ctypes + + - Plusses: + + - part of Python standard library + - good for interfacing to existing sharable libraries, particularly + Windows DLLs + - avoids API/reference counting issues + - good numpy support: arrays have all these in their ctypes + attribute: :: + + a.ctypes.data a.ctypes.get_strides + a.ctypes.data_as a.ctypes.shape + a.ctypes.get_as_parameter a.ctypes.shape_as + a.ctypes.get_data a.ctypes.strides + a.ctypes.get_shape a.ctypes.strides_as + + - Minuses: + + - can't use for writing code to be turned into C extensions, only a wrapper + tool. + +4) SWIG (automatic wrapper generator) + + - Plusses: + + - around a long time + - multiple scripting language support + - C++ support + - Good for wrapping large (many functions) existing C libraries + + - Minuses: + + - generates lots of code between Python and the C code + - can cause performance problems that are nearly impossible to optimize + out + - interface files can be hard to write + - doesn't necessarily avoid reference counting issues or needing to know + API's + +5) scipy.weave + + - Plusses: + + - can turn many numpy expressions into C code + - dynamic compiling and loading of generated C code + - can embed pure C code in Python module and have weave extract, generate + interfaces and compile, etc. + + - Minuses: + + - Future very uncertain: it's the only part of Scipy not ported to Python 3 + and is effectively deprecated in favor of Cython. + +6) Psyco + + - Plusses: + + - Turns pure python into efficient machine code through jit-like + optimizations + - very fast when it optimizes well + + - Minuses: + + - Only on intel (windows?) + - Doesn't do much for numpy? + +Interfacing to Fortran: +----------------------- +The clear choice to wrap Fortran code is +`f2py `_. + +Pyfort is an older alternative, but not supported any longer. +Fwrap is a newer project that looked promising but isn't being developed any +longer. + +Interfacing to C++: +------------------- + 1) Cython + 2) CXX + 3) Boost.python + 4) SWIG + 5) SIP (used mainly in PyQT) + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/structured_arrays.py b/numpy/doc/structured_arrays.py new file mode 100644 index 0000000..c87eef9 --- /dev/null +++ b/numpy/doc/structured_arrays.py @@ -0,0 +1,605 @@ +""" +================= +Structured Arrays +================= + +Introduction +============ + +Structured arrays are ndarrays whose datatype is a composition of simpler +datatypes organized as a sequence of named :term:`fields `. For example, +:: + + >>> x = np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)], + ... dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')]) + >>> x + array([('Rex', 9, 81.0), ('Fido', 3, 27.0)], + dtype=[('name', 'S10'), ('age', '>> x[1] + ('Fido', 3, 27.0) + +You can access and modify individual fields of a structured array by indexing +with the field name:: + + >>> x['age'] + array([9, 3], dtype=int32) + >>> x['age'] = 5 + >>> x + array([('Rex', 5, 81.0), ('Fido', 5, 27.0)], + dtype=[('name', 'S10'), ('age', '` reference page, and in +summary they are: + +1. A list of tuples, one tuple per field + + Each tuple has the form ``(fieldname, datatype, shape)`` where shape is + optional. ``fieldname`` is a string (or tuple if titles are used, see + :ref:`Field Titles ` below), ``datatype`` may be any object + convertible to a datatype, and ``shape`` is a tuple of integers specifying + subarray shape. + + >>> np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2,2))]) + dtype=[('x', '>> np.dtype([('x', 'f4'),('', 'i4'),('z', 'i8')]) + dtype([('x', '` may be used in a string and separated by + commas. The itemsize and byte offsets of the fields are determined + automatically, and the field names are given the default names ``f0``, + ``f1``, etc. :: + + >>> np.dtype('i8,f4,S3') + dtype([('f0', '>> np.dtype('3int8, float32, (2,3)float64') + dtype([('f0', 'i1', 3), ('f1', '>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4','f4']}) + dtype([('col1', '>> np.dtype({'names': ['col1', 'col2'], + ... 'formats': ['i4','f4'], + ... 'offsets': [0, 4], + ... 'itemsize': 12}) + dtype({'names':['col1','col2'], 'formats':['` below. + +4. A dictionary of field names + + The use of this form of specification is discouraged, but documented here + because older numpy code may use it. The keys of the dictionary are the + field names and the values are tuples specifying type and offset:: + + >>> np.dtype=({'col1': ('i1',0), 'col2': ('f4',1)}) + dtype([(('col1'), 'i1'), (('col2'), '>f4')]) + + This form is discouraged because Python dictionaries do not preserve order + in Python versions before Python 3.6, and the order of the fields in a + structured dtype has meaning. :ref:`Field Titles ` may be + specified by using a 3-tuple, see below. + +Manipulating and Displaying Structured Datatypes +------------------------------------------------ + +The list of field names of a structured datatype can be found in the ``names`` +attribute of the dtype object:: + + >>> d = np.dtype([('x', 'i8'), ('y', 'f4')]) + >>> d.names + ('x', 'y') + +The field names may be modified by assigning to the ``names`` attribute using a +sequence of strings of the same length. + +The dtype object also has a dictionary-like attribute, ``fields``, whose keys +are the field names (and :ref:`Field Titles `, see below) and whose +values are tuples containing the dtype and byte offset of each field. :: + + >>> d.fields + mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)}) + +Both the ``names`` and ``fields`` attributes will equal ``None`` for +unstructured arrays. + +The string representation of a structured datatype is shown in the "list of +tuples" form if possible, otherwise numpy falls back to using the more general +dictionary form. + +.. _offsets-and-alignment: + +Automatic Byte Offsets and Alignment +------------------------------------ + +Numpy uses one of two methods to automatically determine the field byte offsets +and the overall itemsize of a structured datatype, depending on whether +``align=True`` was specified as a keyword argument to :func:`numpy.dtype`. + +By default (``align=False``), numpy will pack the fields together such that +each field starts at the byte offset the previous field ended, and the fields +are contiguous in memory. :: + + >>> def print_offsets(d): + ... print("offsets:", [d.fields[name][1] for name in d.names]) + ... print("itemsize:", d.itemsize) + >>> print_offsets(np.dtype('u1,u1,i4,u1,i8,u2')) + offsets: [0, 1, 2, 6, 7, 15] + itemsize: 17 + +If ``align=True`` is set, numpy will pad the structure in the same way many C +compilers would pad a C-struct. Aligned structures can give a performance +improvement in some cases, at the cost of increased datatype size. Padding +bytes are inserted between fields such that each field's byte offset will be a +multiple of that field's alignment, which is usually equal to the field's size +in bytes for simple datatypes, see :c:member:`PyArray_Descr.alignment`. The +structure will also have trailing padding added so that its itemsize is a +multiple of the largest field's alignment. :: + + >>> print_offsets(np.dtype('u1,u1,i4,u1,i8,u2', align=True)) + offsets: [0, 1, 4, 8, 16, 24] + itemsize: 32 + +Note that although almost all modern C compilers pad in this way by default, +padding in C structs is C-implementation-dependent so this memory layout is not +guaranteed to exactly match that of a corresponding struct in a C program. Some +work may be needed, either on the numpy side or the C side, to obtain exact +correspondence. + +If offsets were specified using the optional ``offsets`` key in the +dictionary-based dtype specification, setting ``align=True`` will check that +each field's offset is a multiple of its size and that the itemsize is a +multiple of the largest field size, and raise an exception if not. + +If the offsets of the fields and itemsize of a structured array satisfy the +alignment conditions, the array will have the ``ALIGNED`` :ref:`flag +` set. + +A convenience function :func:`numpy.lib.recfunctions.repack_fields` converts an +aligned dtype or array to a packed one and vice versa. It takes either a dtype +or structured ndarray as an argument, and returns a copy with fields re-packed, +with or without padding bytes. + +.. _titles: + +Field Titles +------------ + +In addition to field names, fields may also have an associated :term:`title`, +an alternate name, which is sometimes used as an additional description or +alias for the field. The title may be used to index an array, just like a +field name. + +To add titles when using the list-of-tuples form of dtype specification, the +field name may be be specified as a tuple of two strings instead of a single +string, which will be the field's title and field name respectively. For +example:: + + >>> np.dtype([(('my title', 'name'), 'f4')]) + +When using the first form of dictionary-based specification, the titles may be +supplied as an extra ``'titles'`` key as described above. When using the second +(discouraged) dictionary-based specification, the title can be supplied by +providing a 3-element tuple ``(datatype, offset, title)`` instead of the usual +2-element tuple:: + + >>> np.dtype({'name': ('i4', 0, 'my title')}) + +The ``dtype.fields`` dictionary will contain :term:`titles` as keys, if any +titles are used. This means effectively that a field with a title will be +represented twice in the fields dictionary. The tuple values for these fields +will also have a third element, the field title. Because of this, and because +the ``names`` attribute preserves the field order while the ``fields`` +attribute may not, it is recommended to iterate through the fields of a dtype +using the ``names`` attribute of the dtype, which will not list titles, as +in:: + + >>> for name in d.names: + ... print(d.fields[name][:2]) + +Union types +----------- + +Structured datatypes are implemented in numpy to have base type +:class:`numpy.void` by default, but it is possible to interpret other numpy +types as structured types using the ``(base_dtype, dtype)`` form of dtype +specification described in +:ref:`Data Type Objects `. Here, ``base_dtype`` is +the desired underlying dtype, and fields and flags will be copied from +``dtype``. This dtype is similar to a 'union' in C. + +Indexing and Assignment to Structured arrays +============================================= + +Assigning data to a Structured Array +------------------------------------ + +There are a number of ways to assign values to a structured array: Using python +tuples, using scalar values, or using other structured arrays. + +Assignment from Python Native Types (Tuples) +``````````````````````````````````````````` + +The simplest way to assign values to a structured array is using python tuples. +Each assigned value should be a tuple of length equal to the number of fields +in the array, and not a list or array as these will trigger numpy's +broadcasting rules. The tuple's elements are assigned to the successive fields +of the array, from left to right:: + + >>> x = np.array([(1,2,3),(4,5,6)], dtype='i8,f4,f8') + >>> x[1] = (7,8,9) + >>> x + array([(1, 2., 3.), (7, 8., 9.)], + dtype=[('f0', '>> x = np.zeros(2, dtype='i8,f4,?,S1') + >>> x[:] = 3 + >>> x + array([(3, 3.0, True, b'3'), (3, 3.0, True, b'3')], + dtype=[('f0', '>> x[:] = np.arange(2) + >>> x + array([(0, 0.0, False, b'0'), (1, 1.0, True, b'1')], + dtype=[('f0', '>> twofield = np.zeros(2, dtype=[('A', 'i4'), ('B', 'i4')]) + >>> onefield = np.zeros(2, dtype=[('A', 'i4')]) + >>> nostruct = np.zeros(2, dtype='i4') + >>> nostruct[:] = twofield + ValueError: Can't cast from structure to non-structure, except if the structure only has a single field. + >>> nostruct[:] = onefield + >>> nostruct + array([0, 0], dtype=int32) + +Assignment from other Structured Arrays +``````````````````````````````````````` + +Assignment between two structured arrays occurs as if the source elements had +been converted to tuples and then assigned to the destination elements. That +is, the first field of the source array is assigned to the first field of the +destination array, and the second field likewise, and so on, regardless of +field names. Structured arrays with a different number of fields cannot be +assigned to each other. Bytes of the destination structure which are not +included in any of the fields are unaffected. :: + + >>> a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')]) + >>> b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')]) + >>> b[:] = a + >>> b + array([(0.0, b'0.0', b''), (0.0, b'0.0', b''), (0.0, b'0.0', b'')], + dtype=[('x', '>> x = np.array([(1,2),(3,4)], dtype=[('foo', 'i8'), ('bar', 'f4')]) + >>> x['foo'] + array([1, 3]) + >>> x['foo'] = 10 + >>> x + array([(10, 2.), (10, 4.)], + dtype=[('foo', '>> y = x['bar'] + >>> y[:] = 10 + >>> x + array([(10, 5.), (10, 5.)], + dtype=[('foo', '>> y.dtype, y.shape, y.strides + (dtype('float32'), (2,), (12,)) + +Accessing Multiple Fields +``````````````````````````` + +One can index and assign to a structured array with a multi-field index, where +the index is a list of field names. + +.. warning:: + The behavior of multi-field indexes will change from Numpy 1.14 to Numpy + 1.15. + +In Numpy 1.15, the result of indexing with a multi-field index will be a view +into the original array, as follows:: + + >>> a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')]) + >>> a[['a', 'c']] + array([(0, 0.), (0, 0.), (0, 0.)], + dtype={'names':['a','c'], 'formats':['>> a[['a','c']].view('i8') # will fail in Numpy 1.15 + ValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype + + will need to be changed. This code has raised a ``FutureWarning`` since + Numpy 1.12. + + The following is a recommended fix, which will behave identically in Numpy + 1.14 and Numpy 1.15:: + + >>> from numpy.lib.recfunctions import repack_fields + >>> repack_fields(a[['a','c']]).view('i8') # supported 1.14 and 1.15 + array([0, 0, 0]) + +Assigning to an array with a multi-field index will behave the same in Numpy +1.14 and Numpy 1.15. In both versions the assignment will modify the original +array:: + + >>> a[['a', 'c']] = (2, 3) + >>> a + array([(2, 0, 3.0), (2, 0, 3.0), (2, 0, 3.0)], + dtype=[('a', '>> a[['a', 'c']] = a[['c', 'a']] + +Indexing with an Integer to get a Structured Scalar +``````````````````````````````````````````````````` + +Indexing a single element of a structured array (with an integer index) returns +a structured scalar:: + + >>> x = np.array([(1, 2., 3.)], dtype='i,f,f') + >>> scalar = x[0] + >>> scalar + (1, 2., 3.) + >>> type(scalar) + numpy.void + +Unlike other numpy scalars, structured scalars are mutable and act like views +into the original array, such that modifying the scalar will modify the +original array. Structured scalars also support access and assignment by field +name:: + + >>> x = np.array([(1,2),(3,4)], dtype=[('foo', 'i8'), ('bar', 'f4')]) + >>> s = x[0] + >>> s['bar'] = 100 + >>> x + array([(1, 100.), (3, 4.)], + dtype=[('foo', '>> scalar = np.array([(1, 2., 3.)], dtype='i,f,f')[0] + >>> scalar[0] + 1 + >>> scalar[1] = 4 + +Thus, tuples might be thought of as the native Python equivalent to numpy's +structured types, much like native python integers are the equivalent to +numpy's integer types. Structured scalars may be converted to a tuple by +calling :func:`ndarray.item`:: + + >>> scalar.item(), type(scalar.item()) + ((1, 2.0, 3.0), tuple) + +Viewing Structured Arrays Containing Objects +-------------------------------------------- + +In order to prevent clobbering object pointers in fields of +:class:`numpy.object` type, numpy currently does not allow views of structured +arrays containing objects. + +Structure Comparison +-------------------- + +If the dtypes of two void structured arrays are equal, testing the equality of +the arrays will result in a boolean array with the dimensions of the original +arrays, with elements set to ``True`` where all fields of the corresponding +structures are equal. Structured dtypes are equal if the field names, +dtypes and titles are the same, ignoring endianness, and the fields are in +the same order:: + + >>> a = np.zeros(2, dtype=[('a', 'i4'), ('b', 'i4')]) + >>> b = np.ones(2, dtype=[('a', 'i4'), ('b', 'i4')]) + >>> a == b + array([False, False]) + +Currently, if the dtypes of two void structured arrays are not equivalent the +comparison fails, returning the scalar value ``False``. This behavior is +deprecated as of numpy 1.10 and will raise an error or perform elementwise +comparison in the future. + +The ``<`` and ``>`` operators always return ``False`` when comparing void +structured arrays, and arithmetic and bitwise operations are not supported. + +Record Arrays +============= + +As an optional convenience numpy provides an ndarray subclass, +:class:`numpy.recarray`, and associated helper functions in the +:mod:`numpy.rec` submodule, that allows access to fields of structured arrays +by attribute instead of only by index. Record arrays also use a special +datatype, :class:`numpy.record`, that allows field access by attribute on the +structured scalars obtained from the array. + +The simplest way to create a record array is with :func:`numpy.rec.array`:: + + >>> recordarr = np.rec.array([(1,2.,'Hello'),(2,3.,"World")], + ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')]) + >>> recordarr.bar + array([ 2., 3.], dtype=float32) + >>> recordarr[1:2] + rec.array([(2, 3.0, 'World')], + dtype=[('foo', '>> recordarr[1:2].foo + array([2], dtype=int32) + >>> recordarr.foo[1:2] + array([2], dtype=int32) + >>> recordarr[1].baz + 'World' + +:func:`numpy.rec.array` can convert a wide variety of arguments into record +arrays, including structured arrays:: + + >>> arr = array([(1,2.,'Hello'),(2,3.,"World")], + ... dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')]) + >>> recordarr = np.rec.array(arr) + +The :mod:`numpy.rec` module provides a number of other convenience functions for +creating record arrays, see :ref:`record array creation routines +`. + +A record array representation of a structured array can be obtained using the +appropriate :ref:`view`:: + + >>> arr = np.array([(1,2.,'Hello'),(2,3.,"World")], + ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'a10')]) + >>> recordarr = arr.view(dtype=dtype((np.record, arr.dtype)), + ... type=np.recarray) + +For convenience, viewing an ndarray as type :class:`np.recarray` will +automatically convert to :class:`np.record` datatype, so the dtype can be left +out of the view:: + + >>> recordarr = arr.view(np.recarray) + >>> recordarr.dtype + dtype((numpy.record, [('foo', '>> arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray) + +Record array fields accessed by index or by attribute are returned as a record +array if the field has a structured type but as a plain ndarray otherwise. :: + + >>> recordarr = np.rec.array([('Hello', (1,2)),("World", (3,4))], + ... dtype=[('foo', 'S6'),('bar', [('A', int), ('B', int)])]) + >>> type(recordarr.foo) + + >>> type(recordarr.bar) + + +Note that if a field has the same name as an ndarray attribute, the ndarray +attribute takes precedence. Such fields will be inaccessible by attribute but +will still be accessible by index. + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/subclassing.py b/numpy/doc/subclassing.py new file mode 100644 index 0000000..c342788 --- /dev/null +++ b/numpy/doc/subclassing.py @@ -0,0 +1,752 @@ +"""============================= +Subclassing ndarray in python +============================= + +Introduction +------------ + +Subclassing ndarray is relatively simple, but it has some complications +compared to other Python objects. On this page we explain the machinery +that allows you to subclass ndarray, and the implications for +implementing a subclass. + +ndarrays and object creation +============================ + +Subclassing ndarray is complicated by the fact that new instances of +ndarray classes can come about in three different ways. These are: + +#. Explicit constructor call - as in ``MySubClass(params)``. This is + the usual route to Python instance creation. +#. View casting - casting an existing ndarray as a given subclass +#. New from template - creating a new instance from a template + instance. Examples include returning slices from a subclassed array, + creating return types from ufuncs, and copying arrays. See + :ref:`new-from-template` for more details + +The last two are characteristics of ndarrays - in order to support +things like array slicing. The complications of subclassing ndarray are +due to the mechanisms numpy has to support these latter two routes of +instance creation. + +.. _view-casting: + +View casting +------------ + +*View casting* is the standard ndarray mechanism by which you take an +ndarray of any subclass, and return a view of the array as another +(specified) subclass: + +>>> import numpy as np +>>> # create a completely useless ndarray subclass +>>> class C(np.ndarray): pass +>>> # create a standard ndarray +>>> arr = np.zeros((3,)) +>>> # take a view of it, as our useless subclass +>>> c_arr = arr.view(C) +>>> type(c_arr) + + +.. _new-from-template: + +Creating new from template +-------------------------- + +New instances of an ndarray subclass can also come about by a very +similar mechanism to :ref:`view-casting`, when numpy finds it needs to +create a new instance from a template instance. The most obvious place +this has to happen is when you are taking slices of subclassed arrays. +For example: + +>>> v = c_arr[1:] +>>> type(v) # the view is of type 'C' + +>>> v is c_arr # but it's a new instance +False + +The slice is a *view* onto the original ``c_arr`` data. So, when we +take a view from the ndarray, we return a new ndarray, of the same +class, that points to the data in the original. + +There are other points in the use of ndarrays where we need such views, +such as copying arrays (``c_arr.copy()``), creating ufunc output arrays +(see also :ref:`array-wrap`), and reducing methods (like +``c_arr.mean()``. + +Relationship of view casting and new-from-template +-------------------------------------------------- + +These paths both use the same machinery. We make the distinction here, +because they result in different input to your methods. Specifically, +:ref:`view-casting` means you have created a new instance of your array +type from any potential subclass of ndarray. :ref:`new-from-template` +means you have created a new instance of your class from a pre-existing +instance, allowing you - for example - to copy across attributes that +are particular to your subclass. + +Implications for subclassing +---------------------------- + +If we subclass ndarray, we need to deal not only with explicit +construction of our array type, but also :ref:`view-casting` or +:ref:`new-from-template`. NumPy has the machinery to do this, and this +machinery that makes subclassing slightly non-standard. + +There are two aspects to the machinery that ndarray uses to support +views and new-from-template in subclasses. + +The first is the use of the ``ndarray.__new__`` method for the main work +of object initialization, rather then the more usual ``__init__`` +method. The second is the use of the ``__array_finalize__`` method to +allow subclasses to clean up after the creation of views and new +instances from templates. + +A brief Python primer on ``__new__`` and ``__init__`` +===================================================== + +``__new__`` is a standard Python method, and, if present, is called +before ``__init__`` when we create a class instance. See the `python +__new__ documentation +`_ for more detail. + +For example, consider the following Python code: + +.. testcode:: + + class C(object): + def __new__(cls, *args): + print('Cls in __new__:', cls) + print('Args in __new__:', args) + return object.__new__(cls, *args) + + def __init__(self, *args): + print('type(self) in __init__:', type(self)) + print('Args in __init__:', args) + +meaning that we get: + +>>> c = C('hello') +Cls in __new__: +Args in __new__: ('hello',) +type(self) in __init__: +Args in __init__: ('hello',) + +When we call ``C('hello')``, the ``__new__`` method gets its own class +as first argument, and the passed argument, which is the string +``'hello'``. After python calls ``__new__``, it usually (see below) +calls our ``__init__`` method, with the output of ``__new__`` as the +first argument (now a class instance), and the passed arguments +following. + +As you can see, the object can be initialized in the ``__new__`` +method or the ``__init__`` method, or both, and in fact ndarray does +not have an ``__init__`` method, because all the initialization is +done in the ``__new__`` method. + +Why use ``__new__`` rather than just the usual ``__init__``? Because +in some cases, as for ndarray, we want to be able to return an object +of some other class. Consider the following: + +.. testcode:: + + class D(C): + def __new__(cls, *args): + print('D cls is:', cls) + print('D args in __new__:', args) + return C.__new__(C, *args) + + def __init__(self, *args): + # we never get here + print('In D __init__') + +meaning that: + +>>> obj = D('hello') +D cls is: +D args in __new__: ('hello',) +Cls in __new__: +Args in __new__: ('hello',) +>>> type(obj) + + +The definition of ``C`` is the same as before, but for ``D``, the +``__new__`` method returns an instance of class ``C`` rather than +``D``. Note that the ``__init__`` method of ``D`` does not get +called. In general, when the ``__new__`` method returns an object of +class other than the class in which it is defined, the ``__init__`` +method of that class is not called. + +This is how subclasses of the ndarray class are able to return views +that preserve the class type. When taking a view, the standard +ndarray machinery creates the new ndarray object with something +like:: + + obj = ndarray.__new__(subtype, shape, ... + +where ``subdtype`` is the subclass. Thus the returned view is of the +same class as the subclass, rather than being of class ``ndarray``. + +That solves the problem of returning views of the same type, but now +we have a new problem. The machinery of ndarray can set the class +this way, in its standard methods for taking views, but the ndarray +``__new__`` method knows nothing of what we have done in our own +``__new__`` method in order to set attributes, and so on. (Aside - +why not call ``obj = subdtype.__new__(...`` then? Because we may not +have a ``__new__`` method with the same call signature). + +The role of ``__array_finalize__`` +================================== + +``__array_finalize__`` is the mechanism that numpy provides to allow +subclasses to handle the various ways that new instances get created. + +Remember that subclass instances can come about in these three ways: + +#. explicit constructor call (``obj = MySubClass(params)``). This will + call the usual sequence of ``MySubClass.__new__`` then (if it exists) + ``MySubClass.__init__``. +#. :ref:`view-casting` +#. :ref:`new-from-template` + +Our ``MySubClass.__new__`` method only gets called in the case of the +explicit constructor call, so we can't rely on ``MySubClass.__new__`` or +``MySubClass.__init__`` to deal with the view casting and +new-from-template. It turns out that ``MySubClass.__array_finalize__`` +*does* get called for all three methods of object creation, so this is +where our object creation housekeeping usually goes. + +* For the explicit constructor call, our subclass will need to create a + new ndarray instance of its own class. In practice this means that + we, the authors of the code, will need to make a call to + ``ndarray.__new__(MySubClass,...)``, a class-hierarchy prepared call to + ``super(MySubClass, cls).__new__(cls, ...)``, or do view casting of an + existing array (see below) +* For view casting and new-from-template, the equivalent of + ``ndarray.__new__(MySubClass,...`` is called, at the C level. + +The arguments that ``__array_finalize__`` receives differ for the three +methods of instance creation above. + +The following code allows us to look at the call sequences and arguments: + +.. testcode:: + + import numpy as np + + class C(np.ndarray): + def __new__(cls, *args, **kwargs): + print('In __new__ with class %s' % cls) + return super(C, cls).__new__(cls, *args, **kwargs) + + def __init__(self, *args, **kwargs): + # in practice you probably will not need or want an __init__ + # method for your subclass + print('In __init__ with class %s' % self.__class__) + + def __array_finalize__(self, obj): + print('In array_finalize:') + print(' self type is %s' % type(self)) + print(' obj type is %s' % type(obj)) + + +Now: + +>>> # Explicit constructor +>>> c = C((10,)) +In __new__ with class +In array_finalize: + self type is + obj type is +In __init__ with class +>>> # View casting +>>> a = np.arange(10) +>>> cast_a = a.view(C) +In array_finalize: + self type is + obj type is +>>> # Slicing (example of new-from-template) +>>> cv = c[:1] +In array_finalize: + self type is + obj type is + +The signature of ``__array_finalize__`` is:: + + def __array_finalize__(self, obj): + +One sees that the ``super`` call, which goes to +``ndarray.__new__``, passes ``__array_finalize__`` the new object, of our +own class (``self``) as well as the object from which the view has been +taken (``obj``). As you can see from the output above, the ``self`` is +always a newly created instance of our subclass, and the type of ``obj`` +differs for the three instance creation methods: + +* When called from the explicit constructor, ``obj`` is ``None`` +* When called from view casting, ``obj`` can be an instance of any + subclass of ndarray, including our own. +* When called in new-from-template, ``obj`` is another instance of our + own subclass, that we might use to update the new ``self`` instance. + +Because ``__array_finalize__`` is the only method that always sees new +instances being created, it is the sensible place to fill in instance +defaults for new object attributes, among other tasks. + +This may be clearer with an example. + +Simple example - adding an extra attribute to ndarray +----------------------------------------------------- + +.. testcode:: + + import numpy as np + + class InfoArray(np.ndarray): + + def __new__(subtype, shape, dtype=float, buffer=None, offset=0, + strides=None, order=None, info=None): + # Create the ndarray instance of our type, given the usual + # ndarray input arguments. This will call the standard + # ndarray constructor, but return an object of our type. + # It also triggers a call to InfoArray.__array_finalize__ + obj = super(InfoArray, subtype).__new__(subtype, shape, dtype, + buffer, offset, strides, + order) + # set the new 'info' attribute to the value passed + obj.info = info + # Finally, we must return the newly created object: + return obj + + def __array_finalize__(self, obj): + # ``self`` is a new object resulting from + # ndarray.__new__(InfoArray, ...), therefore it only has + # attributes that the ndarray.__new__ constructor gave it - + # i.e. those of a standard ndarray. + # + # We could have got to the ndarray.__new__ call in 3 ways: + # From an explicit constructor - e.g. InfoArray(): + # obj is None + # (we're in the middle of the InfoArray.__new__ + # constructor, and self.info will be set when we return to + # InfoArray.__new__) + if obj is None: return + # From view casting - e.g arr.view(InfoArray): + # obj is arr + # (type(obj) can be InfoArray) + # From new-from-template - e.g infoarr[:3] + # type(obj) is InfoArray + # + # Note that it is here, rather than in the __new__ method, + # that we set the default value for 'info', because this + # method sees all creation of default objects - with the + # InfoArray.__new__ constructor, but also with + # arr.view(InfoArray). + self.info = getattr(obj, 'info', None) + # We do not need to return anything + + +Using the object looks like this: + + >>> obj = InfoArray(shape=(3,)) # explicit constructor + >>> type(obj) + + >>> obj.info is None + True + >>> obj = InfoArray(shape=(3,), info='information') + >>> obj.info + 'information' + >>> v = obj[1:] # new-from-template - here - slicing + >>> type(v) + + >>> v.info + 'information' + >>> arr = np.arange(10) + >>> cast_arr = arr.view(InfoArray) # view casting + >>> type(cast_arr) + + >>> cast_arr.info is None + True + +This class isn't very useful, because it has the same constructor as the +bare ndarray object, including passing in buffers and shapes and so on. +We would probably prefer the constructor to be able to take an already +formed ndarray from the usual numpy calls to ``np.array`` and return an +object. + +Slightly more realistic example - attribute added to existing array +------------------------------------------------------------------- + +Here is a class that takes a standard ndarray that already exists, casts +as our type, and adds an extra attribute. + +.. testcode:: + + import numpy as np + + class RealisticInfoArray(np.ndarray): + + def __new__(cls, input_array, info=None): + # Input array is an already formed ndarray instance + # We first cast to be our class type + obj = np.asarray(input_array).view(cls) + # add the new attribute to the created instance + obj.info = info + # Finally, we must return the newly created object: + return obj + + def __array_finalize__(self, obj): + # see InfoArray.__array_finalize__ for comments + if obj is None: return + self.info = getattr(obj, 'info', None) + + +So: + + >>> arr = np.arange(5) + >>> obj = RealisticInfoArray(arr, info='information') + >>> type(obj) + + >>> obj.info + 'information' + >>> v = obj[1:] + >>> type(v) + + >>> v.info + 'information' + +.. _array-ufunc: + +``__array_ufunc__`` for ufuncs +------------------------------ + + .. versionadded:: 1.13 + +A subclass can override what happens when executing numpy ufuncs on it by +overriding the default ``ndarray.__array_ufunc__`` method. This method is +executed *instead* of the ufunc and should return either the result of the +operation, or :obj:`NotImplemented` if the operation requested is not +implemented. + +The signature of ``__array_ufunc__`` is:: + + def __array_ufunc__(ufunc, method, *inputs, **kwargs): + + - *ufunc* is the ufunc object that was called. + - *method* is a string indicating how the Ufunc was called, either + ``"__call__"`` to indicate it was called directly, or one of its + :ref:`methods`: ``"reduce"``, ``"accumulate"``, + ``"reduceat"``, ``"outer"``, or ``"at"``. + - *inputs* is a tuple of the input arguments to the ``ufunc`` + - *kwargs* contains any optional or keyword arguments passed to the + function. This includes any ``out`` arguments, which are always + contained in a tuple. + +A typical implementation would convert any inputs or ouputs that are +instances of one's own class, pass everything on to a superclass using +``super()``, and finally return the results after possible +back-conversion. An example, taken from the test case +``test_ufunc_override_with_super`` in ``core/tests/test_umath.py``, is the +following. + +.. testcode:: + + input numpy as np + + class A(np.ndarray): + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + args = [] + in_no = [] + for i, input_ in enumerate(inputs): + if isinstance(input_, A): + in_no.append(i) + args.append(input_.view(np.ndarray)) + else: + args.append(input_) + + outputs = kwargs.pop('out', None) + out_no = [] + if outputs: + out_args = [] + for j, output in enumerate(outputs): + if isinstance(output, A): + out_no.append(j) + out_args.append(output.view(np.ndarray)) + else: + out_args.append(output) + kwargs['out'] = tuple(out_args) + else: + outputs = (None,) * ufunc.nout + + info = {} + if in_no: + info['inputs'] = in_no + if out_no: + info['outputs'] = out_no + + results = super(A, self).__array_ufunc__(ufunc, method, + *args, **kwargs) + if results is NotImplemented: + return NotImplemented + + if method == 'at': + if isinstance(inputs[0], A): + inputs[0].info = info + return + + if ufunc.nout == 1: + results = (results,) + + results = tuple((np.asarray(result).view(A) + if output is None else output) + for result, output in zip(results, outputs)) + if results and isinstance(results[0], A): + results[0].info = info + + return results[0] if len(results) == 1 else results + +So, this class does not actually do anything interesting: it just +converts any instances of its own to regular ndarray (otherwise, we'd +get infinite recursion!), and adds an ``info`` dictionary that tells +which inputs and outputs it converted. Hence, e.g., + +>>> a = np.arange(5.).view(A) +>>> b = np.sin(a) +>>> b.info +{'inputs': [0]} +>>> b = np.sin(np.arange(5.), out=(a,)) +>>> b.info +{'outputs': [0]} +>>> a = np.arange(5.).view(A) +>>> b = np.ones(1).view(A) +>>> c = a + b +>>> c.info +{'inputs': [0, 1]} +>>> a += b +>>> a.info +{'inputs': [0, 1], 'outputs': [0]} + +Note that another approach would be to to use ``getattr(ufunc, +methods)(*inputs, **kwargs)`` instead of the ``super`` call. For this example, +the result would be identical, but there is a difference if another operand +also defines ``__array_ufunc__``. E.g., lets assume that we evalulate +``np.add(a, b)``, where ``b`` is an instance of another class ``B`` that has +an override. If you use ``super`` as in the example, +``ndarray.__array_ufunc__`` will notice that ``b`` has an override, which +means it cannot evaluate the result itself. Thus, it will return +`NotImplemented` and so will our class ``A``. Then, control will be passed +over to ``b``, which either knows how to deal with us and produces a result, +or does not and returns `NotImplemented`, raising a ``TypeError``. + +If instead, we replace our ``super`` call with ``getattr(ufunc, method)``, we +effectively do ``np.add(a.view(np.ndarray), b)``. Again, ``B.__array_ufunc__`` +will be called, but now it sees an ``ndarray`` as the other argument. Likely, +it will know how to handle this, and return a new instance of the ``B`` class +to us. Our example class is not set up to handle this, but it might well be +the best approach if, e.g., one were to re-implement ``MaskedArray`` using +``__array_ufunc__``. + +As a final note: if the ``super`` route is suited to a given class, an +advantage of using it is that it helps in constructing class hierarchies. +E.g., suppose that our other class ``B`` also used the ``super`` in its +``__array_ufunc__`` implementation, and we created a class ``C`` that depended +on both, i.e., ``class C(A, B)`` (with, for simplicity, not another +``__array_ufunc__`` override). Then any ufunc on an instance of ``C`` would +pass on to ``A.__array_ufunc__``, the ``super`` call in ``A`` would go to +``B.__array_ufunc__``, and the ``super`` call in ``B`` would go to +``ndarray.__array_ufunc__``, thus allowing ``A`` and ``B`` to collaborate. + +.. _array-wrap: + +``__array_wrap__`` for ufuncs and other functions +------------------------------------------------- + +Prior to numpy 1.13, the behaviour of ufuncs could only be tuned using +``__array_wrap__`` and ``__array_prepare__``. These two allowed one to +change the output type of a ufunc, but, in constrast to +``__array_ufunc__``, did not allow one to make any changes to the inputs. +It is hoped to eventually deprecate these, but ``__array_wrap__`` is also +used by other numpy functions and methods, such as ``squeeze``, so at the +present time is still needed for full functionality. + +Conceptually, ``__array_wrap__`` "wraps up the action" in the sense of +allowing a subclass to set the type of the return value and update +attributes and metadata. Let's show how this works with an example. First +we return to the simpler example subclass, but with a different name and +some print statements: + +.. testcode:: + + import numpy as np + + class MySubClass(np.ndarray): + + def __new__(cls, input_array, info=None): + obj = np.asarray(input_array).view(cls) + obj.info = info + return obj + + def __array_finalize__(self, obj): + print('In __array_finalize__:') + print(' self is %s' % repr(self)) + print(' obj is %s' % repr(obj)) + if obj is None: return + self.info = getattr(obj, 'info', None) + + def __array_wrap__(self, out_arr, context=None): + print('In __array_wrap__:') + print(' self is %s' % repr(self)) + print(' arr is %s' % repr(out_arr)) + # then just call the parent + return super(MySubClass, self).__array_wrap__(self, out_arr, context) + +We run a ufunc on an instance of our new array: + +>>> obj = MySubClass(np.arange(5), info='spam') +In __array_finalize__: + self is MySubClass([0, 1, 2, 3, 4]) + obj is array([0, 1, 2, 3, 4]) +>>> arr2 = np.arange(5)+1 +>>> ret = np.add(arr2, obj) +In __array_wrap__: + self is MySubClass([0, 1, 2, 3, 4]) + arr is array([1, 3, 5, 7, 9]) +In __array_finalize__: + self is MySubClass([1, 3, 5, 7, 9]) + obj is MySubClass([0, 1, 2, 3, 4]) +>>> ret +MySubClass([1, 3, 5, 7, 9]) +>>> ret.info +'spam' + +Note that the ufunc (``np.add``) has called the ``__array_wrap__`` method +with arguments ``self`` as ``obj``, and ``out_arr`` as the (ndarray) result +of the addition. In turn, the default ``__array_wrap__`` +(``ndarray.__array_wrap__``) has cast the result to class ``MySubClass``, +and called ``__array_finalize__`` - hence the copying of the ``info`` +attribute. This has all happened at the C level. + +But, we could do anything we wanted: + +.. testcode:: + + class SillySubClass(np.ndarray): + + def __array_wrap__(self, arr, context=None): + return 'I lost your data' + +>>> arr1 = np.arange(5) +>>> obj = arr1.view(SillySubClass) +>>> arr2 = np.arange(5) +>>> ret = np.multiply(obj, arr2) +>>> ret +'I lost your data' + +So, by defining a specific ``__array_wrap__`` method for our subclass, +we can tweak the output from ufuncs. The ``__array_wrap__`` method +requires ``self``, then an argument - which is the result of the ufunc - +and an optional parameter *context*. This parameter is returned by +ufuncs as a 3-element tuple: (name of the ufunc, arguments of the ufunc, +domain of the ufunc), but is not set by other numpy functions. Though, +as seen above, it is possible to do otherwise, ``__array_wrap__`` should +return an instance of its containing class. See the masked array +subclass for an implementation. + +In addition to ``__array_wrap__``, which is called on the way out of the +ufunc, there is also an ``__array_prepare__`` method which is called on +the way into the ufunc, after the output arrays are created but before any +computation has been performed. The default implementation does nothing +but pass through the array. ``__array_prepare__`` should not attempt to +access the array data or resize the array, it is intended for setting the +output array type, updating attributes and metadata, and performing any +checks based on the input that may be desired before computation begins. +Like ``__array_wrap__``, ``__array_prepare__`` must return an ndarray or +subclass thereof or raise an error. + +Extra gotchas - custom ``__del__`` methods and ndarray.base +----------------------------------------------------------- + +One of the problems that ndarray solves is keeping track of memory +ownership of ndarrays and their views. Consider the case where we have +created an ndarray, ``arr`` and have taken a slice with ``v = arr[1:]``. +The two objects are looking at the same memory. NumPy keeps track of +where the data came from for a particular array or view, with the +``base`` attribute: + +>>> # A normal ndarray, that owns its own data +>>> arr = np.zeros((4,)) +>>> # In this case, base is None +>>> arr.base is None +True +>>> # We take a view +>>> v1 = arr[1:] +>>> # base now points to the array that it derived from +>>> v1.base is arr +True +>>> # Take a view of a view +>>> v2 = v1[1:] +>>> # base points to the view it derived from +>>> v2.base is v1 +True + +In general, if the array owns its own memory, as for ``arr`` in this +case, then ``arr.base`` will be None - there are some exceptions to this +- see the numpy book for more details. + +The ``base`` attribute is useful in being able to tell whether we have +a view or the original array. This in turn can be useful if we need +to know whether or not to do some specific cleanup when the subclassed +array is deleted. For example, we may only want to do the cleanup if +the original array is deleted, but not the views. For an example of +how this can work, have a look at the ``memmap`` class in +``numpy.core``. + +Subclassing and Downstream Compatibility +---------------------------------------- + +When sub-classing ``ndarray`` or creating duck-types that mimic the ``ndarray`` +interface, it is your responsibility to decide how aligned your APIs will be +with those of numpy. For convenience, many numpy functions that have a corresponding +``ndarray`` method (e.g., ``sum``, ``mean``, ``take``, ``reshape``) work by checking +if the first argument to a function has a method of the same name. If it exists, the +method is called instead of coercing the arguments to a numpy array. + +For example, if you want your sub-class or duck-type to be compatible with +numpy's ``sum`` function, the method signature for this object's ``sum`` method +should be the following: + +.. testcode:: + + def sum(self, axis=None, dtype=None, out=None, keepdims=False): + ... + +This is the exact same method signature for ``np.sum``, so now if a user calls +``np.sum`` on this object, numpy will call the object's own ``sum`` method and +pass in these arguments enumerated above in the signature, and no errors will +be raised because the signatures are completely compatible with each other. + +If, however, you decide to deviate from this signature and do something like this: + +.. testcode:: + + def sum(self, axis=None, dtype=None): + ... + +This object is no longer compatible with ``np.sum`` because if you call ``np.sum``, +it will pass in unexpected arguments ``out`` and ``keepdims``, causing a TypeError +to be raised. + +If you wish to maintain compatibility with numpy and its subsequent versions (which +might add new keyword arguments) but do not want to surface all of numpy's arguments, +your function's signature should accept ``**kwargs``. For example: + +.. testcode:: + + def sum(self, axis=None, dtype=None, **unused_kwargs): + ... + +This object is now compatible with ``np.sum`` again because any extraneous arguments +(i.e. keywords that are not ``axis`` or ``dtype``) will be hidden away in the +``**unused_kwargs`` parameter. + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/doc/ufuncs.py b/numpy/doc/ufuncs.py new file mode 100644 index 0000000..a112e55 --- /dev/null +++ b/numpy/doc/ufuncs.py @@ -0,0 +1,138 @@ +""" +=================== +Universal Functions +=================== + +Ufuncs are, generally speaking, mathematical functions or operations that are +applied element-by-element to the contents of an array. That is, the result +in each output array element only depends on the value in the corresponding +input array (or arrays) and on no other array elements. NumPy comes with a +large suite of ufuncs, and scipy extends that suite substantially. The simplest +example is the addition operator: :: + + >>> np.array([0,2,3,4]) + np.array([1,1,-1,2]) + array([1, 3, 2, 6]) + +The unfunc module lists all the available ufuncs in numpy. Documentation on +the specific ufuncs may be found in those modules. This documentation is +intended to address the more general aspects of unfuncs common to most of +them. All of the ufuncs that make use of Python operators (e.g., +, -, etc.) +have equivalent functions defined (e.g. add() for +) + +Type coercion +============= + +What happens when a binary operator (e.g., +,-,\\*,/, etc) deals with arrays of +two different types? What is the type of the result? Typically, the result is +the higher of the two types. For example: :: + + float32 + float64 -> float64 + int8 + int32 -> int32 + int16 + float32 -> float32 + float32 + complex64 -> complex64 + +There are some less obvious cases generally involving mixes of types +(e.g. uints, ints and floats) where equal bit sizes for each are not +capable of saving all the information in a different type of equivalent +bit size. Some examples are int32 vs float32 or uint32 vs int32. +Generally, the result is the higher type of larger size than both +(if available). So: :: + + int32 + float32 -> float64 + uint32 + int32 -> int64 + +Finally, the type coercion behavior when expressions involve Python +scalars is different than that seen for arrays. Since Python has a +limited number of types, combining a Python int with a dtype=np.int8 +array does not coerce to the higher type but instead, the type of the +array prevails. So the rules for Python scalars combined with arrays is +that the result will be that of the array equivalent the Python scalar +if the Python scalar is of a higher 'kind' than the array (e.g., float +vs. int), otherwise the resultant type will be that of the array. +For example: :: + + Python int + int8 -> int8 + Python float + int8 -> float64 + +ufunc methods +============= + +Binary ufuncs support 4 methods. + +**.reduce(arr)** applies the binary operator to elements of the array in + sequence. For example: :: + + >>> np.add.reduce(np.arange(10)) # adds all elements of array + 45 + +For multidimensional arrays, the first dimension is reduced by default: :: + + >>> np.add.reduce(np.arange(10).reshape(2,5)) + array([ 5, 7, 9, 11, 13]) + +The axis keyword can be used to specify different axes to reduce: :: + + >>> np.add.reduce(np.arange(10).reshape(2,5),axis=1) + array([10, 35]) + +**.accumulate(arr)** applies the binary operator and generates an an +equivalently shaped array that includes the accumulated amount for each +element of the array. A couple examples: :: + + >>> np.add.accumulate(np.arange(10)) + array([ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45]) + >>> np.multiply.accumulate(np.arange(1,9)) + array([ 1, 2, 6, 24, 120, 720, 5040, 40320]) + +The behavior for multidimensional arrays is the same as for .reduce(), +as is the use of the axis keyword). + +**.reduceat(arr,indices)** allows one to apply reduce to selected parts + of an array. It is a difficult method to understand. See the documentation + at: + +**.outer(arr1,arr2)** generates an outer operation on the two arrays arr1 and + arr2. It will work on multidimensional arrays (the shape of the result is + the concatenation of the two input shapes.: :: + + >>> np.multiply.outer(np.arange(3),np.arange(4)) + array([[0, 0, 0, 0], + [0, 1, 2, 3], + [0, 2, 4, 6]]) + +Output arguments +================ + +All ufuncs accept an optional output array. The array must be of the expected +output shape. Beware that if the type of the output array is of a different +(and lower) type than the output result, the results may be silently truncated +or otherwise corrupted in the downcast to the lower type. This usage is useful +when one wants to avoid creating large temporary arrays and instead allows one +to reuse the same array memory repeatedly (at the expense of not being able to +use more convenient operator notation in expressions). Note that when the +output argument is used, the ufunc still returns a reference to the result. + + >>> x = np.arange(2) + >>> np.add(np.arange(2),np.arange(2.),x) + array([0, 2]) + >>> x + array([0, 2]) + +and & or as ufuncs +================== + +Invariably people try to use the python 'and' and 'or' as logical operators +(and quite understandably). But these operators do not behave as normal +operators since Python treats these quite differently. They cannot be +overloaded with array equivalents. Thus using 'and' or 'or' with an array +results in an error. There are two alternatives: + + 1) use the ufunc functions logical_and() and logical_or(). + 2) use the bitwise operators & and \\|. The drawback of these is that if + the arguments to these operators are not boolean arrays, the result is + likely incorrect. On the other hand, most usages of logical_and and + logical_or are with boolean arrays. As long as one is careful, this is + a convenient way to apply these operators. + +""" +from __future__ import division, absolute_import, print_function diff --git a/numpy/dual.py b/numpy/dual.py new file mode 100644 index 0000000..8b91da2 --- /dev/null +++ b/numpy/dual.py @@ -0,0 +1,71 @@ +""" +Aliases for functions which may be accelerated by Scipy. + +Scipy_ can be built to use accelerated or otherwise improved libraries +for FFTs, linear algebra, and special functions. This module allows +developers to transparently support these accelerated functions when +scipy is available but still support users who have only installed +NumPy. + +.. _Scipy : http://www.scipy.org + +""" +from __future__ import division, absolute_import, print_function + +# This module should be used for functions both in numpy and scipy if +# you want to use the numpy version if available but the scipy version +# otherwise. +# Usage --- from numpy.dual import fft, inv + +__all__ = ['fft', 'ifft', 'fftn', 'ifftn', 'fft2', 'ifft2', + 'norm', 'inv', 'svd', 'solve', 'det', 'eig', 'eigvals', + 'eigh', 'eigvalsh', 'lstsq', 'pinv', 'cholesky', 'i0'] + +import numpy.linalg as linpkg +import numpy.fft as fftpkg +from numpy.lib import i0 +import sys + + +fft = fftpkg.fft +ifft = fftpkg.ifft +fftn = fftpkg.fftn +ifftn = fftpkg.ifftn +fft2 = fftpkg.fft2 +ifft2 = fftpkg.ifft2 + +norm = linpkg.norm +inv = linpkg.inv +svd = linpkg.svd +solve = linpkg.solve +det = linpkg.det +eig = linpkg.eig +eigvals = linpkg.eigvals +eigh = linpkg.eigh +eigvalsh = linpkg.eigvalsh +lstsq = linpkg.lstsq +pinv = linpkg.pinv +cholesky = linpkg.cholesky + +_restore_dict = {} + +def register_func(name, func): + if name not in __all__: + raise ValueError("%s not a dual function." % name) + f = sys._getframe(0).f_globals + _restore_dict[name] = f[name] + f[name] = func + +def restore_func(name): + if name not in __all__: + raise ValueError("%s not a dual function." % name) + try: + val = _restore_dict[name] + except KeyError: + return + else: + sys._getframe(0).f_globals[name] = val + +def restore_all(): + for name in _restore_dict.keys(): + restore_func(name) diff --git a/numpy/f2py/__init__.py b/numpy/f2py/__init__.py new file mode 100644 index 0000000..250c432 --- /dev/null +++ b/numpy/f2py/__init__.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +"""Fortran to Python Interface Generator. + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['run_main', 'compile', 'f2py_testing'] + +import sys + +from . import f2py2e +from . import f2py_testing +from . import diagnose + +run_main = f2py2e.run_main +main = f2py2e.main + + +def compile(source, + modulename='untitled', + extra_args='', + verbose=True, + source_fn=None, + extension='.f' + ): + """ + Build extension module from processing source with f2py. + + Parameters + ---------- + source : str + Fortran source of module / subroutine to compile + modulename : str, optional + The name of the compiled python module + extra_args : str, optional + Additional parameters passed to f2py + verbose : bool, optional + Print f2py output to screen + source_fn : str, optional + Name of the file where the fortran source is written. + The default is to use a temporary file with the extension + provided by the `extension` parameter + extension : {'.f', '.f90'}, optional + Filename extension if `source_fn` is not provided. + The extension tells which fortran standard is used. + The default is `.f`, which implies F77 standard. + + .. versionadded:: 1.11.0 + + """ + from numpy.distutils.exec_command import exec_command + import tempfile + if source_fn is None: + f = tempfile.NamedTemporaryFile(suffix=extension) + else: + f = open(source_fn, 'w') + + try: + f.write(source) + f.flush() + + args = ' -c -m {} {} {}'.format(modulename, f.name, extra_args) + c = '{} -c "import numpy.f2py as f2py2e;f2py2e.main()" {}' + c = c.format(sys.executable, args) + status, output = exec_command(c) + if verbose: + print(output) + finally: + f.close() + return status + +from numpy.testing import _numpy_tester +test = _numpy_tester().test +bench = _numpy_tester().bench diff --git a/numpy/f2py/__main__.py b/numpy/f2py/__main__.py new file mode 100644 index 0000000..cb8f261 --- /dev/null +++ b/numpy/f2py/__main__.py @@ -0,0 +1,27 @@ +# See http://cens.ioc.ee/projects/f2py2e/ +from __future__ import division, print_function + +import os +import sys +for mode in ["g3-numpy", "2e-numeric", "2e-numarray", "2e-numpy"]: + try: + i = sys.argv.index("--" + mode) + del sys.argv[i] + break + except ValueError: + pass +os.environ["NO_SCIPY_IMPORT"] = "f2py" +if mode == "g3-numpy": + sys.stderr.write("G3 f2py support is not implemented, yet.\\n") + sys.exit(1) +elif mode == "2e-numeric": + from f2py2e import main +elif mode == "2e-numarray": + sys.argv.append("-DNUMARRAY") + from f2py2e import main +elif mode == "2e-numpy": + from numpy.f2py import main +else: + sys.stderr.write("Unknown mode: " + repr(mode) + "\\n") + sys.exit(1) +main() diff --git a/numpy/f2py/__version__.py b/numpy/f2py/__version__.py new file mode 100644 index 0000000..49a2199 --- /dev/null +++ b/numpy/f2py/__version__.py @@ -0,0 +1,10 @@ +from __future__ import division, absolute_import, print_function + +major = 2 + +try: + from __svn_version__ import version + version_info = (major, version) + version = '%s_%s' % version_info +except (ImportError, ValueError): + version = str(major) diff --git a/numpy/f2py/auxfuncs.py b/numpy/f2py/auxfuncs.py new file mode 100644 index 0000000..404bdbd --- /dev/null +++ b/numpy/f2py/auxfuncs.py @@ -0,0 +1,854 @@ +#!/usr/bin/env python +""" + +Auxiliary functions for f2py2e. + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy (BSD style) LICENSE. + + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/07/24 19:01:55 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +import pprint +import sys +import types +from functools import reduce + +from . import __version__ +from . import cfuncs + +__all__ = [ + 'applyrules', 'debugcapi', 'dictappend', 'errmess', 'gentitle', + 'getargs2', 'getcallprotoargument', 'getcallstatement', + 'getfortranname', 'getpymethoddef', 'getrestdoc', 'getusercode', + 'getusercode1', 'hasbody', 'hascallstatement', 'hascommon', + 'hasexternals', 'hasinitvalue', 'hasnote', 'hasresultnote', + 'isallocatable', 'isarray', 'isarrayofstrings', 'iscomplex', + 'iscomplexarray', 'iscomplexfunction', 'iscomplexfunction_warn', + 'isdouble', 'isdummyroutine', 'isexternal', 'isfunction', + 'isfunction_wrap', 'isint1array', 'isinteger', 'isintent_aux', + 'isintent_c', 'isintent_callback', 'isintent_copy', 'isintent_dict', + 'isintent_hide', 'isintent_in', 'isintent_inout', 'isintent_inplace', + 'isintent_nothide', 'isintent_out', 'isintent_overwrite', 'islogical', + 'islogicalfunction', 'islong_complex', 'islong_double', + 'islong_doublefunction', 'islong_long', 'islong_longfunction', + 'ismodule', 'ismoduleroutine', 'isoptional', 'isprivate', 'isrequired', + 'isroutine', 'isscalar', 'issigned_long_longarray', 'isstring', + 'isstringarray', 'isstringfunction', 'issubroutine', + 'issubroutine_wrap', 'isthreadsafe', 'isunsigned', 'isunsigned_char', + 'isunsigned_chararray', 'isunsigned_long_long', + 'isunsigned_long_longarray', 'isunsigned_short', + 'isunsigned_shortarray', 'l_and', 'l_not', 'l_or', 'outmess', + 'replace', 'show', 'stripcomma', 'throw_error', +] + + +f2py_version = __version__.version + + +errmess = sys.stderr.write +show = pprint.pprint + +options = {} +debugoptions = [] +wrapfuncs = 1 + + +def outmess(t): + if options.get('verbose', 1): + sys.stdout.write(t) + + +def debugcapi(var): + return 'capi' in debugoptions + + +def _isstring(var): + return 'typespec' in var and var['typespec'] == 'character' and \ + not isexternal(var) + + +def isstring(var): + return _isstring(var) and not isarray(var) + + +def ischaracter(var): + return isstring(var) and 'charselector' not in var + + +def isstringarray(var): + return isarray(var) and _isstring(var) + + +def isarrayofstrings(var): + # leaving out '*' for now so that `character*(*) a(m)` and `character + # a(m,*)` are treated differently. Luckily `character**` is illegal. + return isstringarray(var) and var['dimension'][-1] == '(*)' + + +def isarray(var): + return 'dimension' in var and not isexternal(var) + + +def isscalar(var): + return not (isarray(var) or isstring(var) or isexternal(var)) + + +def iscomplex(var): + return isscalar(var) and \ + var.get('typespec') in ['complex', 'double complex'] + + +def islogical(var): + return isscalar(var) and var.get('typespec') == 'logical' + + +def isinteger(var): + return isscalar(var) and var.get('typespec') == 'integer' + + +def isreal(var): + return isscalar(var) and var.get('typespec') == 'real' + + +def get_kind(var): + try: + return var['kindselector']['*'] + except KeyError: + try: + return var['kindselector']['kind'] + except KeyError: + pass + + +def islong_long(var): + if not isscalar(var): + return 0 + if var.get('typespec') not in ['integer', 'logical']: + return 0 + return get_kind(var) == '8' + + +def isunsigned_char(var): + if not isscalar(var): + return 0 + if var.get('typespec') != 'integer': + return 0 + return get_kind(var) == '-1' + + +def isunsigned_short(var): + if not isscalar(var): + return 0 + if var.get('typespec') != 'integer': + return 0 + return get_kind(var) == '-2' + + +def isunsigned(var): + if not isscalar(var): + return 0 + if var.get('typespec') != 'integer': + return 0 + return get_kind(var) == '-4' + + +def isunsigned_long_long(var): + if not isscalar(var): + return 0 + if var.get('typespec') != 'integer': + return 0 + return get_kind(var) == '-8' + + +def isdouble(var): + if not isscalar(var): + return 0 + if not var.get('typespec') == 'real': + return 0 + return get_kind(var) == '8' + + +def islong_double(var): + if not isscalar(var): + return 0 + if not var.get('typespec') == 'real': + return 0 + return get_kind(var) == '16' + + +def islong_complex(var): + if not iscomplex(var): + return 0 + return get_kind(var) == '32' + + +def iscomplexarray(var): + return isarray(var) and \ + var.get('typespec') in ['complex', 'double complex'] + + +def isint1array(var): + return isarray(var) and var.get('typespec') == 'integer' \ + and get_kind(var) == '1' + + +def isunsigned_chararray(var): + return isarray(var) and var.get('typespec') in ['integer', 'logical']\ + and get_kind(var) == '-1' + + +def isunsigned_shortarray(var): + return isarray(var) and var.get('typespec') in ['integer', 'logical']\ + and get_kind(var) == '-2' + + +def isunsignedarray(var): + return isarray(var) and var.get('typespec') in ['integer', 'logical']\ + and get_kind(var) == '-4' + + +def isunsigned_long_longarray(var): + return isarray(var) and var.get('typespec') in ['integer', 'logical']\ + and get_kind(var) == '-8' + + +def issigned_chararray(var): + return isarray(var) and var.get('typespec') in ['integer', 'logical']\ + and get_kind(var) == '1' + + +def issigned_shortarray(var): + return isarray(var) and var.get('typespec') in ['integer', 'logical']\ + and get_kind(var) == '2' + + +def issigned_array(var): + return isarray(var) and var.get('typespec') in ['integer', 'logical']\ + and get_kind(var) == '4' + + +def issigned_long_longarray(var): + return isarray(var) and var.get('typespec') in ['integer', 'logical']\ + and get_kind(var) == '8' + + +def isallocatable(var): + return 'attrspec' in var and 'allocatable' in var['attrspec'] + + +def ismutable(var): + return not ('dimension' not in var or isstring(var)) + + +def ismoduleroutine(rout): + return 'modulename' in rout + + +def ismodule(rout): + return 'block' in rout and 'module' == rout['block'] + + +def isfunction(rout): + return 'block' in rout and 'function' == rout['block'] + +def isfunction_wrap(rout): + if isintent_c(rout): + return 0 + return wrapfuncs and isfunction(rout) and (not isexternal(rout)) + + +def issubroutine(rout): + return 'block' in rout and 'subroutine' == rout['block'] + + +def issubroutine_wrap(rout): + if isintent_c(rout): + return 0 + return issubroutine(rout) and hasassumedshape(rout) + + +def hasassumedshape(rout): + if rout.get('hasassumedshape'): + return True + for a in rout['args']: + for d in rout['vars'].get(a, {}).get('dimension', []): + if d == ':': + rout['hasassumedshape'] = True + return True + return False + + +def isroutine(rout): + return isfunction(rout) or issubroutine(rout) + + +def islogicalfunction(rout): + if not isfunction(rout): + return 0 + if 'result' in rout: + a = rout['result'] + else: + a = rout['name'] + if a in rout['vars']: + return islogical(rout['vars'][a]) + return 0 + + +def islong_longfunction(rout): + if not isfunction(rout): + return 0 + if 'result' in rout: + a = rout['result'] + else: + a = rout['name'] + if a in rout['vars']: + return islong_long(rout['vars'][a]) + return 0 + + +def islong_doublefunction(rout): + if not isfunction(rout): + return 0 + if 'result' in rout: + a = rout['result'] + else: + a = rout['name'] + if a in rout['vars']: + return islong_double(rout['vars'][a]) + return 0 + + +def iscomplexfunction(rout): + if not isfunction(rout): + return 0 + if 'result' in rout: + a = rout['result'] + else: + a = rout['name'] + if a in rout['vars']: + return iscomplex(rout['vars'][a]) + return 0 + + +def iscomplexfunction_warn(rout): + if iscomplexfunction(rout): + outmess("""\ + ************************************************************** + Warning: code with a function returning complex value + may not work correctly with your Fortran compiler. + Run the following test before using it in your applications: + $(f2py install dir)/test-site/{b/runme_scalar,e/runme} + When using GNU gcc/g77 compilers, codes should work correctly. + **************************************************************\n""") + return 1 + return 0 + + +def isstringfunction(rout): + if not isfunction(rout): + return 0 + if 'result' in rout: + a = rout['result'] + else: + a = rout['name'] + if a in rout['vars']: + return isstring(rout['vars'][a]) + return 0 + + +def hasexternals(rout): + return 'externals' in rout and rout['externals'] + + +def isthreadsafe(rout): + return 'f2pyenhancements' in rout and \ + 'threadsafe' in rout['f2pyenhancements'] + + +def hasvariables(rout): + return 'vars' in rout and rout['vars'] + + +def isoptional(var): + return ('attrspec' in var and 'optional' in var['attrspec'] and + 'required' not in var['attrspec']) and isintent_nothide(var) + + +def isexternal(var): + return 'attrspec' in var and 'external' in var['attrspec'] + + +def isrequired(var): + return not isoptional(var) and isintent_nothide(var) + + +def isintent_in(var): + if 'intent' not in var: + return 1 + if 'hide' in var['intent']: + return 0 + if 'inplace' in var['intent']: + return 0 + if 'in' in var['intent']: + return 1 + if 'out' in var['intent']: + return 0 + if 'inout' in var['intent']: + return 0 + if 'outin' in var['intent']: + return 0 + return 1 + + +def isintent_inout(var): + return ('intent' in var and ('inout' in var['intent'] or + 'outin' in var['intent']) and 'in' not in var['intent'] and + 'hide' not in var['intent'] and 'inplace' not in var['intent']) + + +def isintent_out(var): + return 'out' in var.get('intent', []) + + +def isintent_hide(var): + return ('intent' in var and ('hide' in var['intent'] or + ('out' in var['intent'] and 'in' not in var['intent'] and + (not l_or(isintent_inout, isintent_inplace)(var))))) + +def isintent_nothide(var): + return not isintent_hide(var) + + +def isintent_c(var): + return 'c' in var.get('intent', []) + + +def isintent_cache(var): + return 'cache' in var.get('intent', []) + + +def isintent_copy(var): + return 'copy' in var.get('intent', []) + + +def isintent_overwrite(var): + return 'overwrite' in var.get('intent', []) + + +def isintent_callback(var): + return 'callback' in var.get('intent', []) + + +def isintent_inplace(var): + return 'inplace' in var.get('intent', []) + + +def isintent_aux(var): + return 'aux' in var.get('intent', []) + + +def isintent_aligned4(var): + return 'aligned4' in var.get('intent', []) + + +def isintent_aligned8(var): + return 'aligned8' in var.get('intent', []) + + +def isintent_aligned16(var): + return 'aligned16' in var.get('intent', []) + +isintent_dict = {isintent_in: 'INTENT_IN', isintent_inout: 'INTENT_INOUT', + isintent_out: 'INTENT_OUT', isintent_hide: 'INTENT_HIDE', + isintent_cache: 'INTENT_CACHE', + isintent_c: 'INTENT_C', isoptional: 'OPTIONAL', + isintent_inplace: 'INTENT_INPLACE', + isintent_aligned4: 'INTENT_ALIGNED4', + isintent_aligned8: 'INTENT_ALIGNED8', + isintent_aligned16: 'INTENT_ALIGNED16', + } + + +def isprivate(var): + return 'attrspec' in var and 'private' in var['attrspec'] + + +def hasinitvalue(var): + return '=' in var + + +def hasinitvalueasstring(var): + if not hasinitvalue(var): + return 0 + return var['='][0] in ['"', "'"] + + +def hasnote(var): + return 'note' in var + + +def hasresultnote(rout): + if not isfunction(rout): + return 0 + if 'result' in rout: + a = rout['result'] + else: + a = rout['name'] + if a in rout['vars']: + return hasnote(rout['vars'][a]) + return 0 + + +def hascommon(rout): + return 'common' in rout + + +def containscommon(rout): + if hascommon(rout): + return 1 + if hasbody(rout): + for b in rout['body']: + if containscommon(b): + return 1 + return 0 + + +def containsmodule(block): + if ismodule(block): + return 1 + if not hasbody(block): + return 0 + for b in block['body']: + if containsmodule(b): + return 1 + return 0 + + +def hasbody(rout): + return 'body' in rout + + +def hascallstatement(rout): + return getcallstatement(rout) is not None + + +def istrue(var): + return 1 + + +def isfalse(var): + return 0 + + +class F2PYError(Exception): + pass + + +class throw_error(object): + + def __init__(self, mess): + self.mess = mess + + def __call__(self, var): + mess = '\n\n var = %s\n Message: %s\n' % (var, self.mess) + raise F2PYError(mess) + + +def l_and(*f): + l, l2 = 'lambda v', [] + for i in range(len(f)): + l = '%s,f%d=f[%d]' % (l, i, i) + l2.append('f%d(v)' % (i)) + return eval('%s:%s' % (l, ' and '.join(l2))) + + +def l_or(*f): + l, l2 = 'lambda v', [] + for i in range(len(f)): + l = '%s,f%d=f[%d]' % (l, i, i) + l2.append('f%d(v)' % (i)) + return eval('%s:%s' % (l, ' or '.join(l2))) + + +def l_not(f): + return eval('lambda v,f=f:not f(v)') + + +def isdummyroutine(rout): + try: + return rout['f2pyenhancements']['fortranname'] == '' + except KeyError: + return 0 + + +def getfortranname(rout): + try: + name = rout['f2pyenhancements']['fortranname'] + if name == '': + raise KeyError + if not name: + errmess('Failed to use fortranname from %s\n' % + (rout['f2pyenhancements'])) + raise KeyError + except KeyError: + name = rout['name'] + return name + + +def getmultilineblock(rout, blockname, comment=1, counter=0): + try: + r = rout['f2pyenhancements'].get(blockname) + except KeyError: + return + if not r: + return + if counter > 0 and isinstance(r, str): + return + if isinstance(r, list): + if counter >= len(r): + return + r = r[counter] + if r[:3] == "'''": + if comment: + r = '\t/* start ' + blockname + \ + ' multiline (' + repr(counter) + ') */\n' + r[3:] + else: + r = r[3:] + if r[-3:] == "'''": + if comment: + r = r[:-3] + '\n\t/* end multiline (' + repr(counter) + ')*/' + else: + r = r[:-3] + else: + errmess("%s multiline block should end with `'''`: %s\n" + % (blockname, repr(r))) + return r + + +def getcallstatement(rout): + return getmultilineblock(rout, 'callstatement') + + +def getcallprotoargument(rout, cb_map={}): + r = getmultilineblock(rout, 'callprotoargument', comment=0) + if r: + return r + if hascallstatement(rout): + outmess( + 'warning: callstatement is defined without callprotoargument\n') + return + from .capi_maps import getctype + arg_types, arg_types2 = [], [] + if l_and(isstringfunction, l_not(isfunction_wrap))(rout): + arg_types.extend(['char*', 'size_t']) + for n in rout['args']: + var = rout['vars'][n] + if isintent_callback(var): + continue + if n in cb_map: + ctype = cb_map[n] + '_typedef' + else: + ctype = getctype(var) + if l_and(isintent_c, l_or(isscalar, iscomplex))(var): + pass + elif isstring(var): + pass + else: + ctype = ctype + '*' + if isstring(var) or isarrayofstrings(var): + arg_types2.append('size_t') + arg_types.append(ctype) + + proto_args = ','.join(arg_types + arg_types2) + if not proto_args: + proto_args = 'void' + return proto_args + + +def getusercode(rout): + return getmultilineblock(rout, 'usercode') + + +def getusercode1(rout): + return getmultilineblock(rout, 'usercode', counter=1) + + +def getpymethoddef(rout): + return getmultilineblock(rout, 'pymethoddef') + + +def getargs(rout): + sortargs, args = [], [] + if 'args' in rout: + args = rout['args'] + if 'sortvars' in rout: + for a in rout['sortvars']: + if a in args: + sortargs.append(a) + for a in args: + if a not in sortargs: + sortargs.append(a) + else: + sortargs = rout['args'] + return args, sortargs + + +def getargs2(rout): + sortargs, args = [], rout.get('args', []) + auxvars = [a for a in rout['vars'].keys() if isintent_aux(rout['vars'][a]) + and a not in args] + args = auxvars + args + if 'sortvars' in rout: + for a in rout['sortvars']: + if a in args: + sortargs.append(a) + for a in args: + if a not in sortargs: + sortargs.append(a) + else: + sortargs = auxvars + rout['args'] + return args, sortargs + + +def getrestdoc(rout): + if 'f2pymultilines' not in rout: + return None + k = None + if rout['block'] == 'python module': + k = rout['block'], rout['name'] + return rout['f2pymultilines'].get(k, None) + + +def gentitle(name): + l = (80 - len(name) - 6) // 2 + return '/*%s %s %s*/' % (l * '*', name, l * '*') + + +def flatlist(l): + if isinstance(l, list): + return reduce(lambda x, y, f=flatlist: x + f(y), l, []) + return [l] + + +def stripcomma(s): + if s and s[-1] == ',': + return s[:-1] + return s + + +def replace(str, d, defaultsep=''): + if isinstance(d, list): + return [replace(str, _m, defaultsep) for _m in d] + if isinstance(str, list): + return [replace(_m, d, defaultsep) for _m in str] + for k in 2 * list(d.keys()): + if k == 'separatorsfor': + continue + if 'separatorsfor' in d and k in d['separatorsfor']: + sep = d['separatorsfor'][k] + else: + sep = defaultsep + if isinstance(d[k], list): + str = str.replace('#%s#' % (k), sep.join(flatlist(d[k]))) + else: + str = str.replace('#%s#' % (k), d[k]) + return str + + +def dictappend(rd, ar): + if isinstance(ar, list): + for a in ar: + rd = dictappend(rd, a) + return rd + for k in ar.keys(): + if k[0] == '_': + continue + if k in rd: + if isinstance(rd[k], str): + rd[k] = [rd[k]] + if isinstance(rd[k], list): + if isinstance(ar[k], list): + rd[k] = rd[k] + ar[k] + else: + rd[k].append(ar[k]) + elif isinstance(rd[k], dict): + if isinstance(ar[k], dict): + if k == 'separatorsfor': + for k1 in ar[k].keys(): + if k1 not in rd[k]: + rd[k][k1] = ar[k][k1] + else: + rd[k] = dictappend(rd[k], ar[k]) + else: + rd[k] = ar[k] + return rd + + +def applyrules(rules, d, var={}): + ret = {} + if isinstance(rules, list): + for r in rules: + rr = applyrules(r, d, var) + ret = dictappend(ret, rr) + if '_break' in rr: + break + return ret + if '_check' in rules and (not rules['_check'](var)): + return ret + if 'need' in rules: + res = applyrules({'needs': rules['need']}, d, var) + if 'needs' in res: + cfuncs.append_needs(res['needs']) + + for k in rules.keys(): + if k == 'separatorsfor': + ret[k] = rules[k] + continue + if isinstance(rules[k], str): + ret[k] = replace(rules[k], d) + elif isinstance(rules[k], list): + ret[k] = [] + for i in rules[k]: + ar = applyrules({k: i}, d, var) + if k in ar: + ret[k].append(ar[k]) + elif k[0] == '_': + continue + elif isinstance(rules[k], dict): + ret[k] = [] + for k1 in rules[k].keys(): + if isinstance(k1, types.FunctionType) and k1(var): + if isinstance(rules[k][k1], list): + for i in rules[k][k1]: + if isinstance(i, dict): + res = applyrules({'supertext': i}, d, var) + if 'supertext' in res: + i = res['supertext'] + else: + i = '' + ret[k].append(replace(i, d)) + else: + i = rules[k][k1] + if isinstance(i, dict): + res = applyrules({'supertext': i}, d) + if 'supertext' in res: + i = res['supertext'] + else: + i = '' + ret[k].append(replace(i, d)) + else: + errmess('applyrules: ignoring rule %s.\n' % repr(rules[k])) + if isinstance(ret[k], list): + if len(ret[k]) == 1: + ret[k] = ret[k][0] + if ret[k] == []: + del ret[k] + return ret diff --git a/numpy/f2py/capi_maps.py b/numpy/f2py/capi_maps.py new file mode 100644 index 0000000..64829d3 --- /dev/null +++ b/numpy/f2py/capi_maps.py @@ -0,0 +1,840 @@ +#!/usr/bin/env python +""" + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/05/06 10:57:33 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +__version__ = "$Revision: 1.60 $"[10:-1] + +from . import __version__ +f2py_version = __version__.version + +import copy +import re +import os +import sys +from .crackfortran import markoutercomma +from . import cb_rules + +# The eviroment provided by auxfuncs.py is needed for some calls to eval. +# As the needed functions cannot be determined by static inspection of the +# code, it is safest to use import * pending a major refactoring of f2py. +from .auxfuncs import * + +__all__ = [ + 'getctype', 'getstrlength', 'getarrdims', 'getpydocsign', + 'getarrdocsign', 'getinit', 'sign2map', 'routsign2map', 'modsign2map', + 'cb_sign2map', 'cb_routsign2map', 'common_sign2map' +] + + +# Numarray and Numeric users should set this False +using_newcore = True + +depargs = [] +lcb_map = {} +lcb2_map = {} +# forced casting: mainly caused by the fact that Python or Numeric +# C/APIs do not support the corresponding C types. +c2py_map = {'double': 'float', + 'float': 'float', # forced casting + 'long_double': 'float', # forced casting + 'char': 'int', # forced casting + 'signed_char': 'int', # forced casting + 'unsigned_char': 'int', # forced casting + 'short': 'int', # forced casting + 'unsigned_short': 'int', # forced casting + 'int': 'int', # (forced casting) + 'long': 'int', + 'long_long': 'long', + 'unsigned': 'int', # forced casting + 'complex_float': 'complex', # forced casting + 'complex_double': 'complex', + 'complex_long_double': 'complex', # forced casting + 'string': 'string', + } +c2capi_map = {'double': 'NPY_DOUBLE', + 'float': 'NPY_FLOAT', + 'long_double': 'NPY_DOUBLE', # forced casting + 'char': 'NPY_STRING', + 'unsigned_char': 'NPY_UBYTE', + 'signed_char': 'NPY_BYTE', + 'short': 'NPY_SHORT', + 'unsigned_short': 'NPY_USHORT', + 'int': 'NPY_INT', + 'unsigned': 'NPY_UINT', + 'long': 'NPY_LONG', + 'long_long': 'NPY_LONG', # forced casting + 'complex_float': 'NPY_CFLOAT', + 'complex_double': 'NPY_CDOUBLE', + 'complex_long_double': 'NPY_CDOUBLE', # forced casting + 'string': 'NPY_STRING'} + +# These new maps aren't used anyhere yet, but should be by default +# unless building numeric or numarray extensions. +if using_newcore: + c2capi_map = {'double': 'NPY_DOUBLE', + 'float': 'NPY_FLOAT', + 'long_double': 'NPY_LONGDOUBLE', + 'char': 'NPY_BYTE', + 'unsigned_char': 'NPY_UBYTE', + 'signed_char': 'NPY_BYTE', + 'short': 'NPY_SHORT', + 'unsigned_short': 'NPY_USHORT', + 'int': 'NPY_INT', + 'unsigned': 'NPY_UINT', + 'long': 'NPY_LONG', + 'unsigned_long': 'NPY_ULONG', + 'long_long': 'NPY_LONGLONG', + 'unsigned_long_long': 'NPY_ULONGLONG', + 'complex_float': 'NPY_CFLOAT', + 'complex_double': 'NPY_CDOUBLE', + 'complex_long_double': 'NPY_CDOUBLE', + 'string':'NPY_STRING' + + } +c2pycode_map = {'double': 'd', + 'float': 'f', + 'long_double': 'd', # forced casting + 'char': '1', + 'signed_char': '1', + 'unsigned_char': 'b', + 'short': 's', + 'unsigned_short': 'w', + 'int': 'i', + 'unsigned': 'u', + 'long': 'l', + 'long_long': 'L', + 'complex_float': 'F', + 'complex_double': 'D', + 'complex_long_double': 'D', # forced casting + 'string': 'c' + } +if using_newcore: + c2pycode_map = {'double': 'd', + 'float': 'f', + 'long_double': 'g', + 'char': 'b', + 'unsigned_char': 'B', + 'signed_char': 'b', + 'short': 'h', + 'unsigned_short': 'H', + 'int': 'i', + 'unsigned': 'I', + 'long': 'l', + 'unsigned_long': 'L', + 'long_long': 'q', + 'unsigned_long_long': 'Q', + 'complex_float': 'F', + 'complex_double': 'D', + 'complex_long_double': 'G', + 'string': 'S'} +c2buildvalue_map = {'double': 'd', + 'float': 'f', + 'char': 'b', + 'signed_char': 'b', + 'short': 'h', + 'int': 'i', + 'long': 'l', + 'long_long': 'L', + 'complex_float': 'N', + 'complex_double': 'N', + 'complex_long_double': 'N', + 'string': 'z'} + +if sys.version_info[0] >= 3: + # Bytes, not Unicode strings + c2buildvalue_map['string'] = 'y' + +if using_newcore: + # c2buildvalue_map=??? + pass + +f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double', + '12': 'long_double', '16': 'long_double'}, + 'integer': {'': 'int', '1': 'signed_char', '2': 'short', + '4': 'int', '8': 'long_long', + '-1': 'unsigned_char', '-2': 'unsigned_short', + '-4': 'unsigned', '-8': 'unsigned_long_long'}, + 'complex': {'': 'complex_float', '8': 'complex_float', + '16': 'complex_double', '24': 'complex_long_double', + '32': 'complex_long_double'}, + 'complexkind': {'': 'complex_float', '4': 'complex_float', + '8': 'complex_double', '12': 'complex_long_double', + '16': 'complex_long_double'}, + 'logical': {'': 'int', '1': 'char', '2': 'short', '4': 'int', + '8': 'long_long'}, + 'double complex': {'': 'complex_double'}, + 'double precision': {'': 'double'}, + 'byte': {'': 'char'}, + 'character': {'': 'string'} + } + +if os.path.isfile('.f2py_f2cmap'): + # User defined additions to f2cmap_all. + # .f2py_f2cmap must contain a dictionary of dictionaries, only. For + # example, {'real':{'low':'float'}} means that Fortran 'real(low)' is + # interpreted as C 'float'. This feature is useful for F90/95 users if + # they use PARAMETERSs in type specifications. + try: + outmess('Reading .f2py_f2cmap ...\n') + f = open('.f2py_f2cmap', 'r') + d = eval(f.read(), {}, {}) + f.close() + for k, d1 in list(d.items()): + for k1 in list(d1.keys()): + d1[k1.lower()] = d1[k1] + d[k.lower()] = d[k] + for k in list(d.keys()): + if k not in f2cmap_all: + f2cmap_all[k] = {} + for k1 in list(d[k].keys()): + if d[k][k1] in c2py_map: + if k1 in f2cmap_all[k]: + outmess( + "\tWarning: redefinition of {'%s':{'%s':'%s'->'%s'}}\n" % (k, k1, f2cmap_all[k][k1], d[k][k1])) + f2cmap_all[k][k1] = d[k][k1] + outmess('\tMapping "%s(kind=%s)" to "%s"\n' % + (k, k1, d[k][k1])) + else: + errmess("\tIgnoring map {'%s':{'%s':'%s'}}: '%s' must be in %s\n" % ( + k, k1, d[k][k1], d[k][k1], list(c2py_map.keys()))) + outmess('Successfully applied user defined changes from .f2py_f2cmap\n') + except Exception as msg: + errmess( + 'Failed to apply user defined changes from .f2py_f2cmap: %s. Skipping.\n' % (msg)) + +cformat_map = {'double': '%g', + 'float': '%g', + 'long_double': '%Lg', + 'char': '%d', + 'signed_char': '%d', + 'unsigned_char': '%hhu', + 'short': '%hd', + 'unsigned_short': '%hu', + 'int': '%d', + 'unsigned': '%u', + 'long': '%ld', + 'unsigned_long': '%lu', + 'long_long': '%ld', + 'complex_float': '(%g,%g)', + 'complex_double': '(%g,%g)', + 'complex_long_double': '(%Lg,%Lg)', + 'string': '%s', + } + +# Auxiliary functions + + +def getctype(var): + """ + Determines C type + """ + ctype = 'void' + if isfunction(var): + if 'result' in var: + a = var['result'] + else: + a = var['name'] + if a in var['vars']: + return getctype(var['vars'][a]) + else: + errmess('getctype: function %s has no return value?!\n' % a) + elif issubroutine(var): + return ctype + elif 'typespec' in var and var['typespec'].lower() in f2cmap_all: + typespec = var['typespec'].lower() + f2cmap = f2cmap_all[typespec] + ctype = f2cmap[''] # default type + if 'kindselector' in var: + if '*' in var['kindselector']: + try: + ctype = f2cmap[var['kindselector']['*']] + except KeyError: + errmess('getctype: "%s %s %s" not supported.\n' % + (var['typespec'], '*', var['kindselector']['*'])) + elif 'kind' in var['kindselector']: + if typespec + 'kind' in f2cmap_all: + f2cmap = f2cmap_all[typespec + 'kind'] + try: + ctype = f2cmap[var['kindselector']['kind']] + except KeyError: + if typespec in f2cmap_all: + f2cmap = f2cmap_all[typespec] + try: + ctype = f2cmap[str(var['kindselector']['kind'])] + except KeyError: + errmess('getctype: "%s(kind=%s)" is mapped to C "%s" (to override define dict(%s = dict(%s="")) in %s/.f2py_f2cmap file).\n' + % (typespec, var['kindselector']['kind'], ctype, + typespec, var['kindselector']['kind'], os.getcwd())) + + else: + if not isexternal(var): + errmess( + 'getctype: No C-type found in "%s", assuming void.\n' % var) + return ctype + + +def getstrlength(var): + if isstringfunction(var): + if 'result' in var: + a = var['result'] + else: + a = var['name'] + if a in var['vars']: + return getstrlength(var['vars'][a]) + else: + errmess('getstrlength: function %s has no return value?!\n' % a) + if not isstring(var): + errmess( + 'getstrlength: expected a signature of a string but got: %s\n' % (repr(var))) + len = '1' + if 'charselector' in var: + a = var['charselector'] + if '*' in a: + len = a['*'] + elif 'len' in a: + len = a['len'] + if re.match(r'\(\s*([*]|[:])\s*\)', len) or re.match(r'([*]|[:])', len): + if isintent_hide(var): + errmess('getstrlength:intent(hide): expected a string with defined length but got: %s\n' % ( + repr(var))) + len = '-1' + return len + + +def getarrdims(a, var, verbose=0): + global depargs + ret = {} + if isstring(var) and not isarray(var): + ret['dims'] = getstrlength(var) + ret['size'] = ret['dims'] + ret['rank'] = '1' + elif isscalar(var): + ret['size'] = '1' + ret['rank'] = '0' + ret['dims'] = '' + elif isarray(var): + dim = copy.copy(var['dimension']) + ret['size'] = '*'.join(dim) + try: + ret['size'] = repr(eval(ret['size'])) + except Exception: + pass + ret['dims'] = ','.join(dim) + ret['rank'] = repr(len(dim)) + ret['rank*[-1]'] = repr(len(dim) * [-1])[1:-1] + for i in range(len(dim)): # solve dim for dependecies + v = [] + if dim[i] in depargs: + v = [dim[i]] + else: + for va in depargs: + if re.match(r'.*?\b%s\b.*' % va, dim[i]): + v.append(va) + for va in v: + if depargs.index(va) > depargs.index(a): + dim[i] = '*' + break + ret['setdims'], i = '', -1 + for d in dim: + i = i + 1 + if d not in ['*', ':', '(*)', '(:)']: + ret['setdims'] = '%s#varname#_Dims[%d]=%s,' % ( + ret['setdims'], i, d) + if ret['setdims']: + ret['setdims'] = ret['setdims'][:-1] + ret['cbsetdims'], i = '', -1 + for d in var['dimension']: + i = i + 1 + if d not in ['*', ':', '(*)', '(:)']: + ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % ( + ret['cbsetdims'], i, d) + elif isintent_in(var): + outmess('getarrdims:warning: assumed shape array, using 0 instead of %r\n' + % (d)) + ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % ( + ret['cbsetdims'], i, 0) + elif verbose: + errmess( + 'getarrdims: If in call-back function: array argument %s must have bounded dimensions: got %s\n' % (repr(a), repr(d))) + if ret['cbsetdims']: + ret['cbsetdims'] = ret['cbsetdims'][:-1] +# if not isintent_c(var): +# var['dimension'].reverse() + return ret + + +def getpydocsign(a, var): + global lcb_map + if isfunction(var): + if 'result' in var: + af = var['result'] + else: + af = var['name'] + if af in var['vars']: + return getpydocsign(af, var['vars'][af]) + else: + errmess('getctype: function %s has no return value?!\n' % af) + return '', '' + sig, sigout = a, a + opt = '' + if isintent_in(var): + opt = 'input' + elif isintent_inout(var): + opt = 'in/output' + out_a = a + if isintent_out(var): + for k in var['intent']: + if k[:4] == 'out=': + out_a = k[4:] + break + init = '' + ctype = getctype(var) + + if hasinitvalue(var): + init, showinit = getinit(a, var) + init = ', optional\\n Default: %s' % showinit + if isscalar(var): + if isintent_inout(var): + sig = '%s : %s rank-0 array(%s,\'%s\')%s' % (a, opt, c2py_map[ctype], + c2pycode_map[ctype], init) + else: + sig = '%s : %s %s%s' % (a, opt, c2py_map[ctype], init) + sigout = '%s : %s' % (out_a, c2py_map[ctype]) + elif isstring(var): + if isintent_inout(var): + sig = '%s : %s rank-0 array(string(len=%s),\'c\')%s' % ( + a, opt, getstrlength(var), init) + else: + sig = '%s : %s string(len=%s)%s' % ( + a, opt, getstrlength(var), init) + sigout = '%s : string(len=%s)' % (out_a, getstrlength(var)) + elif isarray(var): + dim = var['dimension'] + rank = repr(len(dim)) + sig = '%s : %s rank-%s array(\'%s\') with bounds (%s)%s' % (a, opt, rank, + c2pycode_map[ + ctype], + ','.join(dim), init) + if a == out_a: + sigout = '%s : rank-%s array(\'%s\') with bounds (%s)'\ + % (a, rank, c2pycode_map[ctype], ','.join(dim)) + else: + sigout = '%s : rank-%s array(\'%s\') with bounds (%s) and %s storage'\ + % (out_a, rank, c2pycode_map[ctype], ','.join(dim), a) + elif isexternal(var): + ua = '' + if a in lcb_map and lcb_map[a] in lcb2_map and 'argname' in lcb2_map[lcb_map[a]]: + ua = lcb2_map[lcb_map[a]]['argname'] + if not ua == a: + ua = ' => %s' % ua + else: + ua = '' + sig = '%s : call-back function%s' % (a, ua) + sigout = sig + else: + errmess( + 'getpydocsign: Could not resolve docsignature for "%s".\\n' % a) + return sig, sigout + + +def getarrdocsign(a, var): + ctype = getctype(var) + if isstring(var) and (not isarray(var)): + sig = '%s : rank-0 array(string(len=%s),\'c\')' % (a, + getstrlength(var)) + elif isscalar(var): + sig = '%s : rank-0 array(%s,\'%s\')' % (a, c2py_map[ctype], + c2pycode_map[ctype],) + elif isarray(var): + dim = var['dimension'] + rank = repr(len(dim)) + sig = '%s : rank-%s array(\'%s\') with bounds (%s)' % (a, rank, + c2pycode_map[ + ctype], + ','.join(dim)) + return sig + + +def getinit(a, var): + if isstring(var): + init, showinit = '""', "''" + else: + init, showinit = '', '' + if hasinitvalue(var): + init = var['='] + showinit = init + if iscomplex(var) or iscomplexarray(var): + ret = {} + + try: + v = var["="] + if ',' in v: + ret['init.r'], ret['init.i'] = markoutercomma( + v[1:-1]).split('@,@') + else: + v = eval(v, {}, {}) + ret['init.r'], ret['init.i'] = str(v.real), str(v.imag) + except Exception: + raise ValueError( + 'getinit: expected complex number `(r,i)\' but got `%s\' as initial value of %r.' % (init, a)) + if isarray(var): + init = '(capi_c.r=%s,capi_c.i=%s,capi_c)' % ( + ret['init.r'], ret['init.i']) + elif isstring(var): + if not init: + init, showinit = '""', "''" + if init[0] == "'": + init = '"%s"' % (init[1:-1].replace('"', '\\"')) + if init[0] == '"': + showinit = "'%s'" % (init[1:-1]) + return init, showinit + + +def sign2map(a, var): + """ + varname,ctype,atype + init,init.r,init.i,pytype + vardebuginfo,vardebugshowvalue,varshowvalue + varrfromat + intent + """ + global lcb_map, cb_map + out_a = a + if isintent_out(var): + for k in var['intent']: + if k[:4] == 'out=': + out_a = k[4:] + break + ret = {'varname': a, 'outvarname': out_a, 'ctype': getctype(var)} + intent_flags = [] + for f, s in isintent_dict.items(): + if f(var): + intent_flags.append('F2PY_%s' % s) + if intent_flags: + # XXX: Evaluate intent_flags here. + ret['intent'] = '|'.join(intent_flags) + else: + ret['intent'] = 'F2PY_INTENT_IN' + if isarray(var): + ret['varrformat'] = 'N' + elif ret['ctype'] in c2buildvalue_map: + ret['varrformat'] = c2buildvalue_map[ret['ctype']] + else: + ret['varrformat'] = 'O' + ret['init'], ret['showinit'] = getinit(a, var) + if hasinitvalue(var) and iscomplex(var) and not isarray(var): + ret['init.r'], ret['init.i'] = markoutercomma( + ret['init'][1:-1]).split('@,@') + if isexternal(var): + ret['cbnamekey'] = a + if a in lcb_map: + ret['cbname'] = lcb_map[a] + ret['maxnofargs'] = lcb2_map[lcb_map[a]]['maxnofargs'] + ret['nofoptargs'] = lcb2_map[lcb_map[a]]['nofoptargs'] + ret['cbdocstr'] = lcb2_map[lcb_map[a]]['docstr'] + ret['cblatexdocstr'] = lcb2_map[lcb_map[a]]['latexdocstr'] + else: + ret['cbname'] = a + errmess('sign2map: Confused: external %s is not in lcb_map%s.\n' % ( + a, list(lcb_map.keys()))) + if isstring(var): + ret['length'] = getstrlength(var) + if isarray(var): + ret = dictappend(ret, getarrdims(a, var)) + dim = copy.copy(var['dimension']) + if ret['ctype'] in c2capi_map: + ret['atype'] = c2capi_map[ret['ctype']] + # Debug info + if debugcapi(var): + il = [isintent_in, 'input', isintent_out, 'output', + isintent_inout, 'inoutput', isrequired, 'required', + isoptional, 'optional', isintent_hide, 'hidden', + iscomplex, 'complex scalar', + l_and(isscalar, l_not(iscomplex)), 'scalar', + isstring, 'string', isarray, 'array', + iscomplexarray, 'complex array', isstringarray, 'string array', + iscomplexfunction, 'complex function', + l_and(isfunction, l_not(iscomplexfunction)), 'function', + isexternal, 'callback', + isintent_callback, 'callback', + isintent_aux, 'auxiliary', + ] + rl = [] + for i in range(0, len(il), 2): + if il[i](var): + rl.append(il[i + 1]) + if isstring(var): + rl.append('slen(%s)=%s' % (a, ret['length'])) + if isarray(var): + ddim = ','.join( + map(lambda x, y: '%s|%s' % (x, y), var['dimension'], dim)) + rl.append('dims(%s)' % ddim) + if isexternal(var): + ret['vardebuginfo'] = 'debug-capi:%s=>%s:%s' % ( + a, ret['cbname'], ','.join(rl)) + else: + ret['vardebuginfo'] = 'debug-capi:%s %s=%s:%s' % ( + ret['ctype'], a, ret['showinit'], ','.join(rl)) + if isscalar(var): + if ret['ctype'] in cformat_map: + ret['vardebugshowvalue'] = 'debug-capi:%s=%s' % ( + a, cformat_map[ret['ctype']]) + if isstring(var): + ret['vardebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % ( + a, a) + if isexternal(var): + ret['vardebugshowvalue'] = 'debug-capi:%s=%%p' % (a) + if ret['ctype'] in cformat_map: + ret['varshowvalue'] = '#name#:%s=%s' % (a, cformat_map[ret['ctype']]) + ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']]) + if isstring(var): + ret['varshowvalue'] = '#name#:slen(%s)=%%d %s=\\"%%s\\"' % (a, a) + ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var) + if hasnote(var): + ret['note'] = var['note'] + return ret + + +def routsign2map(rout): + """ + name,NAME,begintitle,endtitle + rname,ctype,rformat + routdebugshowvalue + """ + global lcb_map + name = rout['name'] + fname = getfortranname(rout) + ret = {'name': name, + 'texname': name.replace('_', '\\_'), + 'name_lower': name.lower(), + 'NAME': name.upper(), + 'begintitle': gentitle(name), + 'endtitle': gentitle('end of %s' % name), + 'fortranname': fname, + 'FORTRANNAME': fname.upper(), + 'callstatement': getcallstatement(rout) or '', + 'usercode': getusercode(rout) or '', + 'usercode1': getusercode1(rout) or '', + } + if '_' in fname: + ret['F_FUNC'] = 'F_FUNC_US' + else: + ret['F_FUNC'] = 'F_FUNC' + if '_' in name: + ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC_US' + else: + ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC' + lcb_map = {} + if 'use' in rout: + for u in rout['use'].keys(): + if u in cb_rules.cb_map: + for un in cb_rules.cb_map[u]: + ln = un[0] + if 'map' in rout['use'][u]: + for k in rout['use'][u]['map'].keys(): + if rout['use'][u]['map'][k] == un[0]: + ln = k + break + lcb_map[ln] = un[1] + elif 'externals' in rout and rout['externals']: + errmess('routsign2map: Confused: function %s has externals %s but no "use" statement.\n' % ( + ret['name'], repr(rout['externals']))) + ret['callprotoargument'] = getcallprotoargument(rout, lcb_map) or '' + if isfunction(rout): + if 'result' in rout: + a = rout['result'] + else: + a = rout['name'] + ret['rname'] = a + ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout) + ret['ctype'] = getctype(rout['vars'][a]) + if hasresultnote(rout): + ret['resultnote'] = rout['vars'][a]['note'] + rout['vars'][a]['note'] = ['See elsewhere.'] + if ret['ctype'] in c2buildvalue_map: + ret['rformat'] = c2buildvalue_map[ret['ctype']] + else: + ret['rformat'] = 'O' + errmess('routsign2map: no c2buildvalue key for type %s\n' % + (repr(ret['ctype']))) + if debugcapi(rout): + if ret['ctype'] in cformat_map: + ret['routdebugshowvalue'] = 'debug-capi:%s=%s' % ( + a, cformat_map[ret['ctype']]) + if isstringfunction(rout): + ret['routdebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % ( + a, a) + if isstringfunction(rout): + ret['rlength'] = getstrlength(rout['vars'][a]) + if ret['rlength'] == '-1': + errmess('routsign2map: expected explicit specification of the length of the string returned by the fortran function %s; taking 10.\n' % ( + repr(rout['name']))) + ret['rlength'] = '10' + if hasnote(rout): + ret['note'] = rout['note'] + rout['note'] = ['See elsewhere.'] + return ret + + +def modsign2map(m): + """ + modulename + """ + if ismodule(m): + ret = {'f90modulename': m['name'], + 'F90MODULENAME': m['name'].upper(), + 'texf90modulename': m['name'].replace('_', '\\_')} + else: + ret = {'modulename': m['name'], + 'MODULENAME': m['name'].upper(), + 'texmodulename': m['name'].replace('_', '\\_')} + ret['restdoc'] = getrestdoc(m) or [] + if hasnote(m): + ret['note'] = m['note'] + ret['usercode'] = getusercode(m) or '' + ret['usercode1'] = getusercode1(m) or '' + if m['body']: + ret['interface_usercode'] = getusercode(m['body'][0]) or '' + else: + ret['interface_usercode'] = '' + ret['pymethoddef'] = getpymethoddef(m) or '' + if 'coutput' in m: + ret['coutput'] = m['coutput'] + if 'f2py_wrapper_output' in m: + ret['f2py_wrapper_output'] = m['f2py_wrapper_output'] + return ret + + +def cb_sign2map(a, var, index=None): + ret = {'varname': a} + if index is None or 1: # disable 7712 patch + ret['varname_i'] = ret['varname'] + else: + ret['varname_i'] = ret['varname'] + '_' + str(index) + ret['ctype'] = getctype(var) + if ret['ctype'] in c2capi_map: + ret['atype'] = c2capi_map[ret['ctype']] + if ret['ctype'] in cformat_map: + ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']]) + if isarray(var): + ret = dictappend(ret, getarrdims(a, var)) + ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var) + if hasnote(var): + ret['note'] = var['note'] + var['note'] = ['See elsewhere.'] + return ret + + +def cb_routsign2map(rout, um): + """ + name,begintitle,endtitle,argname + ctype,rctype,maxnofargs,nofoptargs,returncptr + """ + ret = {'name': 'cb_%s_in_%s' % (rout['name'], um), + 'returncptr': ''} + if isintent_callback(rout): + if '_' in rout['name']: + F_FUNC = 'F_FUNC_US' + else: + F_FUNC = 'F_FUNC' + ret['callbackname'] = '%s(%s,%s)' \ + % (F_FUNC, + rout['name'].lower(), + rout['name'].upper(), + ) + ret['static'] = 'extern' + else: + ret['callbackname'] = ret['name'] + ret['static'] = 'static' + ret['argname'] = rout['name'] + ret['begintitle'] = gentitle(ret['name']) + ret['endtitle'] = gentitle('end of %s' % ret['name']) + ret['ctype'] = getctype(rout) + ret['rctype'] = 'void' + if ret['ctype'] == 'string': + ret['rctype'] = 'void' + else: + ret['rctype'] = ret['ctype'] + if ret['rctype'] != 'void': + if iscomplexfunction(rout): + ret['returncptr'] = """ +#ifdef F2PY_CB_RETURNCOMPLEX +return_value= +#endif +""" + else: + ret['returncptr'] = 'return_value=' + if ret['ctype'] in cformat_map: + ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']]) + if isstringfunction(rout): + ret['strlength'] = getstrlength(rout) + if isfunction(rout): + if 'result' in rout: + a = rout['result'] + else: + a = rout['name'] + if hasnote(rout['vars'][a]): + ret['note'] = rout['vars'][a]['note'] + rout['vars'][a]['note'] = ['See elsewhere.'] + ret['rname'] = a + ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout) + if iscomplexfunction(rout): + ret['rctype'] = """ +#ifdef F2PY_CB_RETURNCOMPLEX +#ctype# +#else +void +#endif +""" + else: + if hasnote(rout): + ret['note'] = rout['note'] + rout['note'] = ['See elsewhere.'] + nofargs = 0 + nofoptargs = 0 + if 'args' in rout and 'vars' in rout: + for a in rout['args']: + var = rout['vars'][a] + if l_or(isintent_in, isintent_inout)(var): + nofargs = nofargs + 1 + if isoptional(var): + nofoptargs = nofoptargs + 1 + ret['maxnofargs'] = repr(nofargs) + ret['nofoptargs'] = repr(nofoptargs) + if hasnote(rout) and isfunction(rout) and 'result' in rout: + ret['routnote'] = rout['note'] + rout['note'] = ['See elsewhere.'] + return ret + + +def common_sign2map(a, var): # obsolute + ret = {'varname': a, 'ctype': getctype(var)} + if isstringarray(var): + ret['ctype'] = 'char' + if ret['ctype'] in c2capi_map: + ret['atype'] = c2capi_map[ret['ctype']] + if ret['ctype'] in cformat_map: + ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']]) + if isarray(var): + ret = dictappend(ret, getarrdims(a, var)) + elif isstring(var): + ret['size'] = getstrlength(var) + ret['rank'] = '1' + ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var) + if hasnote(var): + ret['note'] = var['note'] + var['note'] = ['See elsewhere.'] + # for strings this returns 0-rank but actually is 1-rank + ret['arrdocstr'] = getarrdocsign(a, var) + return ret diff --git a/numpy/f2py/cb_rules.py b/numpy/f2py/cb_rules.py new file mode 100644 index 0000000..183d7c2 --- /dev/null +++ b/numpy/f2py/cb_rules.py @@ -0,0 +1,578 @@ +#!/usr/bin/env python +""" + +Build call-back mechanism for f2py2e. + +Copyright 2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/07/20 11:27:58 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +from . import __version__ +from .auxfuncs import ( + applyrules, debugcapi, dictappend, errmess, getargs, hasnote, isarray, + iscomplex, iscomplexarray, iscomplexfunction, isfunction, isintent_c, + isintent_hide, isintent_in, isintent_inout, isintent_nothide, + isintent_out, isoptional, isrequired, isscalar, isstring, + isstringfunction, issubroutine, l_and, l_not, l_or, outmess, replace, + stripcomma, throw_error +) +from . import cfuncs + +f2py_version = __version__.version + + +################## Rules for callback function ############## + +cb_routine_rules = { + 'cbtypedefs': 'typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);', + 'body': """ +#begintitle# +PyObject *#name#_capi = NULL;/*was Py_None*/ +PyTupleObject *#name#_args_capi = NULL; +int #name#_nofargs = 0; +jmp_buf #name#_jmpbuf; +/*typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);*/ +#static# #rctype# #callbackname# (#optargs##args##strarglens##noargs#) { +\tPyTupleObject *capi_arglist = #name#_args_capi; +\tPyObject *capi_return = NULL; +\tPyObject *capi_tmp = NULL; +\tPyObject *capi_arglist_list = NULL; +\tint capi_j,capi_i = 0; +\tint capi_longjmp_ok = 1; +#decl# +#ifdef F2PY_REPORT_ATEXIT +f2py_cb_start_clock(); +#endif +\tCFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\"); +\tCFUNCSMESSPY(\"cb:#name#_capi=\",#name#_capi); +\tif (#name#_capi==NULL) { +\t\tcapi_longjmp_ok = 0; +\t\t#name#_capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\"); +\t} +\tif (#name#_capi==NULL) { +\t\tPyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\"); +\t\tgoto capi_fail; +\t} +\tif (F2PyCapsule_Check(#name#_capi)) { +\t#name#_typedef #name#_cptr; +\t#name#_cptr = F2PyCapsule_AsVoidPtr(#name#_capi); +\t#returncptr#(*#name#_cptr)(#optargs_nm##args_nm##strarglens_nm#); +\t#return# +\t} +\tif (capi_arglist==NULL) { +\t\tcapi_longjmp_ok = 0; +\t\tcapi_tmp = PyObject_GetAttrString(#modulename#_module,\"#argname#_extra_args\"); +\t\tif (capi_tmp) { +\t\t\tcapi_arglist = (PyTupleObject *)PySequence_Tuple(capi_tmp); +\t\t\tif (capi_arglist==NULL) { +\t\t\t\tPyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#argname#_extra_args to tuple.\\n\"); +\t\t\t\tgoto capi_fail; +\t\t\t} +\t\t} else { +\t\t\tPyErr_Clear(); +\t\t\tcapi_arglist = (PyTupleObject *)Py_BuildValue(\"()\"); +\t\t} +\t} +\tif (capi_arglist == NULL) { +\t\tPyErr_SetString(#modulename#_error,\"Callback #argname# argument list is not set.\\n\"); +\t\tgoto capi_fail; +\t} +#setdims# +#ifdef PYPY_VERSION +#define CAPI_ARGLIST_SETITEM(idx, value) PyList_SetItem((PyObject *)capi_arglist_list, idx, value) +\tcapi_arglist_list = PySequence_List(capi_arglist); +\tif (capi_arglist_list == NULL) goto capi_fail; +#else +#define CAPI_ARGLIST_SETITEM(idx, value) PyTuple_SetItem((PyObject *)capi_arglist, idx, value) +#endif +#pyobjfrom# +#undef CAPI_ARGLIST_SETITEM +#ifdef PYPY_VERSION +\tCFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist_list); +#else +\tCFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist); +#endif +\tCFUNCSMESS(\"cb:Call-back calling Python function #argname#.\\n\"); +#ifdef F2PY_REPORT_ATEXIT +f2py_cb_start_call_clock(); +#endif +#ifdef PYPY_VERSION +\tcapi_return = PyObject_CallObject(#name#_capi,(PyObject *)capi_arglist_list); +\tPy_DECREF(capi_arglist_list); +\tcapi_arglist_list = NULL; +#else +\tcapi_return = PyObject_CallObject(#name#_capi,(PyObject *)capi_arglist); +#endif +#ifdef F2PY_REPORT_ATEXIT +f2py_cb_stop_call_clock(); +#endif +\tCFUNCSMESSPY(\"cb:capi_return=\",capi_return); +\tif (capi_return == NULL) { +\t\tfprintf(stderr,\"capi_return is NULL\\n\"); +\t\tgoto capi_fail; +\t} +\tif (capi_return == Py_None) { +\t\tPy_DECREF(capi_return); +\t\tcapi_return = Py_BuildValue(\"()\"); +\t} +\telse if (!PyTuple_Check(capi_return)) { +\t\tcapi_return = Py_BuildValue(\"(N)\",capi_return); +\t} +\tcapi_j = PyTuple_Size(capi_return); +\tcapi_i = 0; +#frompyobj# +\tCFUNCSMESS(\"cb:#name#:successful\\n\"); +\tPy_DECREF(capi_return); +#ifdef F2PY_REPORT_ATEXIT +f2py_cb_stop_clock(); +#endif +\tgoto capi_return_pt; +capi_fail: +\tfprintf(stderr,\"Call-back #name# failed.\\n\"); +\tPy_XDECREF(capi_return); +\tPy_XDECREF(capi_arglist_list); +\tif (capi_longjmp_ok) +\t\tlongjmp(#name#_jmpbuf,-1); +capi_return_pt: +\t; +#return# +} +#endtitle# +""", + 'need': ['setjmp.h', 'CFUNCSMESS'], + 'maxnofargs': '#maxnofargs#', + 'nofoptargs': '#nofoptargs#', + 'docstr': """\ +\tdef #argname#(#docsignature#): return #docreturn#\\n\\ +#docstrsigns#""", + 'latexdocstr': """ +{{}\\verb@def #argname#(#latexdocsignature#): return #docreturn#@{}} +#routnote# + +#latexdocstrsigns#""", + 'docstrshort': 'def #argname#(#docsignature#): return #docreturn#' +} +cb_rout_rules = [ + { # Init + 'separatorsfor': {'decl': '\n', + 'args': ',', 'optargs': '', 'pyobjfrom': '\n', 'freemem': '\n', + 'args_td': ',', 'optargs_td': '', + 'args_nm': ',', 'optargs_nm': '', + 'frompyobj': '\n', 'setdims': '\n', + 'docstrsigns': '\\n"\n"', + 'latexdocstrsigns': '\n', + 'latexdocstrreq': '\n', 'latexdocstropt': '\n', + 'latexdocstrout': '\n', 'latexdocstrcbs': '\n', + }, + 'decl': '/*decl*/', 'pyobjfrom': '/*pyobjfrom*/', 'frompyobj': '/*frompyobj*/', + 'args': [], 'optargs': '', 'return': '', 'strarglens': '', 'freemem': '/*freemem*/', + 'args_td': [], 'optargs_td': '', 'strarglens_td': '', + 'args_nm': [], 'optargs_nm': '', 'strarglens_nm': '', + 'noargs': '', + 'setdims': '/*setdims*/', + 'docstrsigns': '', 'latexdocstrsigns': '', + 'docstrreq': '\tRequired arguments:', + 'docstropt': '\tOptional arguments:', + 'docstrout': '\tReturn objects:', + 'docstrcbs': '\tCall-back functions:', + 'docreturn': '', 'docsign': '', 'docsignopt': '', + 'latexdocstrreq': '\\noindent Required arguments:', + 'latexdocstropt': '\\noindent Optional arguments:', + 'latexdocstrout': '\\noindent Return objects:', + 'latexdocstrcbs': '\\noindent Call-back functions:', + 'routnote': {hasnote: '--- #note#', l_not(hasnote): ''}, + }, { # Function + 'decl': '\t#ctype# return_value;', + 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting return_value->");'}, + '\tif (capi_j>capi_i)\n\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n");', + {debugcapi: + '\tfprintf(stderr,"#showvalueformat#.\\n",return_value);'} + ], + 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'}, 'GETSCALARFROMPYTUPLE'], + 'return': '\treturn return_value;', + '_check': l_and(isfunction, l_not(isstringfunction), l_not(iscomplexfunction)) + }, + { # String function + 'pyobjfrom': {debugcapi: '\tfprintf(stderr,"debug-capi:cb:#name#:%d:\\n",return_value_len);'}, + 'args': '#ctype# return_value,int return_value_len', + 'args_nm': 'return_value,&return_value_len', + 'args_td': '#ctype# ,int', + 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting return_value->\\"");'}, + """\tif (capi_j>capi_i) +\t\tGETSTRFROMPYTUPLE(capi_return,capi_i++,return_value,return_value_len);""", + {debugcapi: + '\tfprintf(stderr,"#showvalueformat#\\".\\n",return_value);'} + ], + 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'}, + 'string.h', 'GETSTRFROMPYTUPLE'], + 'return': 'return;', + '_check': isstringfunction + }, + { # Complex function + 'optargs': """ +#ifndef F2PY_CB_RETURNCOMPLEX +#ctype# *return_value +#endif +""", + 'optargs_nm': """ +#ifndef F2PY_CB_RETURNCOMPLEX +return_value +#endif +""", + 'optargs_td': """ +#ifndef F2PY_CB_RETURNCOMPLEX +#ctype# * +#endif +""", + 'decl': """ +#ifdef F2PY_CB_RETURNCOMPLEX +\t#ctype# return_value; +#endif +""", + 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting return_value->");'}, + """\ +\tif (capi_j>capi_i) +#ifdef F2PY_CB_RETURNCOMPLEX +\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\"); +#else +\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\"); +#endif +""", + {debugcapi: """ +#ifdef F2PY_CB_RETURNCOMPLEX +\tfprintf(stderr,\"#showvalueformat#.\\n\",(return_value).r,(return_value).i); +#else +\tfprintf(stderr,\"#showvalueformat#.\\n\",(*return_value).r,(*return_value).i); +#endif + +"""} + ], + 'return': """ +#ifdef F2PY_CB_RETURNCOMPLEX +\treturn return_value; +#else +\treturn; +#endif +""", + 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'}, + 'string.h', 'GETSCALARFROMPYTUPLE', '#ctype#'], + '_check': iscomplexfunction + }, + {'docstrout': '\t\t#pydocsignout#', + 'latexdocstrout': ['\\item[]{{}\\verb@#pydocsignout#@{}}', + {hasnote: '--- #note#'}], + 'docreturn': '#rname#,', + '_check': isfunction}, + {'_check': issubroutine, 'return': 'return;'} +] + +cb_arg_rules = [ + { # Doc + 'docstropt': {l_and(isoptional, isintent_nothide): '\t\t#pydocsign#'}, + 'docstrreq': {l_and(isrequired, isintent_nothide): '\t\t#pydocsign#'}, + 'docstrout': {isintent_out: '\t\t#pydocsignout#'}, + 'latexdocstropt': {l_and(isoptional, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}', + {hasnote: '--- #note#'}]}, + 'latexdocstrreq': {l_and(isrequired, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}', + {hasnote: '--- #note#'}]}, + 'latexdocstrout': {isintent_out: ['\\item[]{{}\\verb@#pydocsignout#@{}}', + {l_and(hasnote, isintent_hide): '--- #note#', + l_and(hasnote, isintent_nothide): '--- See above.'}]}, + 'docsign': {l_and(isrequired, isintent_nothide): '#varname#,'}, + 'docsignopt': {l_and(isoptional, isintent_nothide): '#varname#,'}, + 'depend': '' + }, + { + 'args': { + l_and(isscalar, isintent_c): '#ctype# #varname_i#', + l_and(isscalar, l_not(isintent_c)): '#ctype# *#varname_i#_cb_capi', + isarray: '#ctype# *#varname_i#', + isstring: '#ctype# #varname_i#' + }, + 'args_nm': { + l_and(isscalar, isintent_c): '#varname_i#', + l_and(isscalar, l_not(isintent_c)): '#varname_i#_cb_capi', + isarray: '#varname_i#', + isstring: '#varname_i#' + }, + 'args_td': { + l_and(isscalar, isintent_c): '#ctype#', + l_and(isscalar, l_not(isintent_c)): '#ctype# *', + isarray: '#ctype# *', + isstring: '#ctype#' + }, + # untested with multiple args + 'strarglens': {isstring: ',int #varname_i#_cb_len'}, + 'strarglens_td': {isstring: ',int'}, # untested with multiple args + # untested with multiple args + 'strarglens_nm': {isstring: ',#varname_i#_cb_len'}, + }, + { # Scalars + 'decl': {l_not(isintent_c): '\t#ctype# #varname_i#=(*#varname_i#_cb_capi);'}, + 'error': {l_and(isintent_c, isintent_out, + throw_error('intent(c,out) is forbidden for callback scalar arguments')): + ''}, + 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting #varname#->");'}, + {isintent_out: + '\tif (capi_j>capi_i)\n\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,#varname_i#_cb_capi,#ctype#,"#ctype#_from_pyobj failed in converting argument #varname# of call-back function #name# to C #ctype#\\n");'}, + {l_and(debugcapi, l_and(l_not(iscomplex), isintent_c)): + '\tfprintf(stderr,"#showvalueformat#.\\n",#varname_i#);'}, + {l_and(debugcapi, l_and(l_not(iscomplex), l_not( isintent_c))): + '\tfprintf(stderr,"#showvalueformat#.\\n",*#varname_i#_cb_capi);'}, + {l_and(debugcapi, l_and(iscomplex, isintent_c)): + '\tfprintf(stderr,"#showvalueformat#.\\n",(#varname_i#).r,(#varname_i#).i);'}, + {l_and(debugcapi, l_and(iscomplex, l_not( isintent_c))): + '\tfprintf(stderr,"#showvalueformat#.\\n",(*#varname_i#_cb_capi).r,(*#varname_i#_cb_capi).i);'}, + ], + 'need': [{isintent_out: ['#ctype#_from_pyobj', 'GETSCALARFROMPYTUPLE']}, + {debugcapi: 'CFUNCSMESS'}], + '_check': isscalar + }, { + 'pyobjfrom': [{isintent_in: """\ +\tif (#name#_nofargs>capi_i) +\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1(#varname_i#))) +\t\t\tgoto capi_fail;"""}, + {isintent_inout: """\ +\tif (#name#_nofargs>capi_i) +\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#_cb_capi))) +\t\t\tgoto capi_fail;"""}], + 'need': [{isintent_in: 'pyobj_from_#ctype#1'}, + {isintent_inout: 'pyarr_from_p_#ctype#1'}, + {iscomplex: '#ctype#'}], + '_check': l_and(isscalar, isintent_nothide), + '_optional': '' + }, { # String + 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting #varname#->\\"");'}, + """\tif (capi_j>capi_i) +\t\tGETSTRFROMPYTUPLE(capi_return,capi_i++,#varname_i#,#varname_i#_cb_len);""", + {debugcapi: + '\tfprintf(stderr,"#showvalueformat#\\":%d:.\\n",#varname_i#,#varname_i#_cb_len);'}, + ], + 'need': ['#ctype#', 'GETSTRFROMPYTUPLE', + {debugcapi: 'CFUNCSMESS'}, 'string.h'], + '_check': l_and(isstring, isintent_out) + }, { + 'pyobjfrom': [{debugcapi: '\tfprintf(stderr,"debug-capi:cb:#varname#=\\"#showvalueformat#\\":%d:\\n",#varname_i#,#varname_i#_cb_len);'}, + {isintent_in: """\ +\tif (#name#_nofargs>capi_i) +\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1size(#varname_i#,#varname_i#_cb_len))) +\t\t\tgoto capi_fail;"""}, + {isintent_inout: """\ +\tif (#name#_nofargs>capi_i) { +\t\tint #varname_i#_cb_dims[] = {#varname_i#_cb_len}; +\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#,#varname_i#_cb_dims))) +\t\t\tgoto capi_fail; +\t}"""}], + 'need': [{isintent_in: 'pyobj_from_#ctype#1size'}, + {isintent_inout: 'pyarr_from_p_#ctype#1'}], + '_check': l_and(isstring, isintent_nothide), + '_optional': '' + }, + # Array ... + { + 'decl': '\tnpy_intp #varname_i#_Dims[#rank#] = {#rank*[-1]#};', + 'setdims': '\t#cbsetdims#;', + '_check': isarray, + '_depend': '' + }, + { + 'pyobjfrom': [{debugcapi: '\tfprintf(stderr,"debug-capi:cb:#varname#\\n");'}, + {isintent_c: """\ +\tif (#name#_nofargs>capi_i) { +\t\tint itemsize_ = #atype# == NPY_STRING ? 1 : 0; +\t\t/*XXX: Hmm, what will destroy this array??? */ +\t\tPyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,itemsize_,NPY_ARRAY_CARRAY,NULL); +""", + l_not(isintent_c): """\ +\tif (#name#_nofargs>capi_i) { +\t\tint itemsize_ = #atype# == NPY_STRING ? 1 : 0; +\t\t/*XXX: Hmm, what will destroy this array??? */ +\t\tPyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,itemsize_,NPY_ARRAY_FARRAY,NULL); +""", + }, + """ +\t\tif (tmp_arr==NULL) +\t\t\tgoto capi_fail; +\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,(PyObject *)tmp_arr)) +\t\t\tgoto capi_fail; +}"""], + '_check': l_and(isarray, isintent_nothide, l_or(isintent_in, isintent_inout)), + '_optional': '', + }, { + 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting #varname#->");'}, + """\tif (capi_j>capi_i) { +\t\tPyArrayObject *rv_cb_arr = NULL; +\t\tif ((capi_tmp = PyTuple_GetItem(capi_return,capi_i++))==NULL) goto capi_fail; +\t\trv_cb_arr = array_from_pyobj(#atype#,#varname_i#_Dims,#rank#,F2PY_INTENT_IN""", + {isintent_c: '|F2PY_INTENT_C'}, + """,capi_tmp); +\t\tif (rv_cb_arr == NULL) { +\t\t\tfprintf(stderr,\"rv_cb_arr is NULL\\n\"); +\t\t\tgoto capi_fail; +\t\t} +\t\tMEMCOPY(#varname_i#,PyArray_DATA(rv_cb_arr),PyArray_NBYTES(rv_cb_arr)); +\t\tif (capi_tmp != (PyObject *)rv_cb_arr) { +\t\t\tPy_DECREF(rv_cb_arr); +\t\t} +\t}""", + {debugcapi: '\tfprintf(stderr,"<-.\\n");'}, + ], + 'need': ['MEMCOPY', {iscomplexarray: '#ctype#'}], + '_check': l_and(isarray, isintent_out) + }, { + 'docreturn': '#varname#,', + '_check': isintent_out + } +] + +################## Build call-back module ############# +cb_map = {} + + +def buildcallbacks(m): + global cb_map + cb_map[m['name']] = [] + for bi in m['body']: + if bi['block'] == 'interface': + for b in bi['body']: + if b: + buildcallback(b, m['name']) + else: + errmess('warning: empty body for %s\n' % (m['name'])) + + +def buildcallback(rout, um): + global cb_map + from . import capi_maps + + outmess('\tConstructing call-back function "cb_%s_in_%s"\n' % + (rout['name'], um)) + args, depargs = getargs(rout) + capi_maps.depargs = depargs + var = rout['vars'] + vrd = capi_maps.cb_routsign2map(rout, um) + rd = dictappend({}, vrd) + cb_map[um].append([rout['name'], rd['name']]) + for r in cb_rout_rules: + if ('_check' in r and r['_check'](rout)) or ('_check' not in r): + ar = applyrules(r, vrd, rout) + rd = dictappend(rd, ar) + savevrd = {} + for i, a in enumerate(args): + vrd = capi_maps.cb_sign2map(a, var[a], index=i) + savevrd[a] = vrd + for r in cb_arg_rules: + if '_depend' in r: + continue + if '_optional' in r and isoptional(var[a]): + continue + if ('_check' in r and r['_check'](var[a])) or ('_check' not in r): + ar = applyrules(r, vrd, var[a]) + rd = dictappend(rd, ar) + if '_break' in r: + break + for a in args: + vrd = savevrd[a] + for r in cb_arg_rules: + if '_depend' in r: + continue + if ('_optional' not in r) or ('_optional' in r and isrequired(var[a])): + continue + if ('_check' in r and r['_check'](var[a])) or ('_check' not in r): + ar = applyrules(r, vrd, var[a]) + rd = dictappend(rd, ar) + if '_break' in r: + break + for a in depargs: + vrd = savevrd[a] + for r in cb_arg_rules: + if '_depend' not in r: + continue + if '_optional' in r: + continue + if ('_check' in r and r['_check'](var[a])) or ('_check' not in r): + ar = applyrules(r, vrd, var[a]) + rd = dictappend(rd, ar) + if '_break' in r: + break + if 'args' in rd and 'optargs' in rd: + if isinstance(rd['optargs'], list): + rd['optargs'] = rd['optargs'] + [""" +#ifndef F2PY_CB_RETURNCOMPLEX +, +#endif +"""] + rd['optargs_nm'] = rd['optargs_nm'] + [""" +#ifndef F2PY_CB_RETURNCOMPLEX +, +#endif +"""] + rd['optargs_td'] = rd['optargs_td'] + [""" +#ifndef F2PY_CB_RETURNCOMPLEX +, +#endif +"""] + if isinstance(rd['docreturn'], list): + rd['docreturn'] = stripcomma( + replace('#docreturn#', {'docreturn': rd['docreturn']})) + optargs = stripcomma(replace('#docsignopt#', + {'docsignopt': rd['docsignopt']} + )) + if optargs == '': + rd['docsignature'] = stripcomma( + replace('#docsign#', {'docsign': rd['docsign']})) + else: + rd['docsignature'] = replace('#docsign#[#docsignopt#]', + {'docsign': rd['docsign'], + 'docsignopt': optargs, + }) + rd['latexdocsignature'] = rd['docsignature'].replace('_', '\\_') + rd['latexdocsignature'] = rd['latexdocsignature'].replace(',', ', ') + rd['docstrsigns'] = [] + rd['latexdocstrsigns'] = [] + for k in ['docstrreq', 'docstropt', 'docstrout', 'docstrcbs']: + if k in rd and isinstance(rd[k], list): + rd['docstrsigns'] = rd['docstrsigns'] + rd[k] + k = 'latex' + k + if k in rd and isinstance(rd[k], list): + rd['latexdocstrsigns'] = rd['latexdocstrsigns'] + rd[k][0:1] +\ + ['\\begin{description}'] + rd[k][1:] +\ + ['\\end{description}'] + if 'args' not in rd: + rd['args'] = '' + rd['args_td'] = '' + rd['args_nm'] = '' + if not (rd.get('args') or rd.get('optargs') or rd.get('strarglens')): + rd['noargs'] = 'void' + + ar = applyrules(cb_routine_rules, rd) + cfuncs.callbacks[rd['name']] = ar['body'] + if isinstance(ar['need'], str): + ar['need'] = [ar['need']] + + if 'need' in rd: + for t in cfuncs.typedefs.keys(): + if t in rd['need']: + ar['need'].append(t) + + cfuncs.typedefs_generated[rd['name'] + '_typedef'] = ar['cbtypedefs'] + ar['need'].append(rd['name'] + '_typedef') + cfuncs.needs[rd['name']] = ar['need'] + + capi_maps.lcb2_map[rd['name']] = {'maxnofargs': ar['maxnofargs'], + 'nofoptargs': ar['nofoptargs'], + 'docstr': ar['docstr'], + 'latexdocstr': ar['latexdocstr'], + 'argname': rd['argname'] + } + outmess('\t %s\n' % (ar['docstrshort'])) + return +################## Build call-back function ############# diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py new file mode 100644 index 0000000..3b7f694 --- /dev/null +++ b/numpy/f2py/cfuncs.py @@ -0,0 +1,1262 @@ +#!/usr/bin/env python +""" + +C declarations, CPP macros, and C functions for f2py2e. +Only required declarations/macros/functions will be used. + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/05/06 11:42:34 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +import sys +import copy + +from . import __version__ + +f2py_version = __version__.version +errmess = sys.stderr.write + +##################### Definitions ################## + +outneeds = {'includes0': [], 'includes': [], 'typedefs': [], 'typedefs_generated': [], + 'userincludes': [], + 'cppmacros': [], 'cfuncs': [], 'callbacks': [], 'f90modhooks': [], + 'commonhooks': []} +needs = {} +includes0 = {'includes0': '/*need_includes0*/'} +includes = {'includes': '/*need_includes*/'} +userincludes = {'userincludes': '/*need_userincludes*/'} +typedefs = {'typedefs': '/*need_typedefs*/'} +typedefs_generated = {'typedefs_generated': '/*need_typedefs_generated*/'} +cppmacros = {'cppmacros': '/*need_cppmacros*/'} +cfuncs = {'cfuncs': '/*need_cfuncs*/'} +callbacks = {'callbacks': '/*need_callbacks*/'} +f90modhooks = {'f90modhooks': '/*need_f90modhooks*/', + 'initf90modhooksstatic': '/*initf90modhooksstatic*/', + 'initf90modhooksdynamic': '/*initf90modhooksdynamic*/', + } +commonhooks = {'commonhooks': '/*need_commonhooks*/', + 'initcommonhooks': '/*need_initcommonhooks*/', + } + +############ Includes ################### + +includes0['math.h'] = '#include ' +includes0['string.h'] = '#include ' +includes0['setjmp.h'] = '#include ' + +includes['Python.h'] = '#include "Python.h"' +needs['arrayobject.h'] = ['Python.h'] +includes['arrayobject.h'] = '''#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API +#include "arrayobject.h"''' + +includes['arrayobject.h'] = '#include "fortranobject.h"' +includes['stdarg.h'] = '#include ' + +############# Type definitions ############### + +typedefs['unsigned_char'] = 'typedef unsigned char unsigned_char;' +typedefs['unsigned_short'] = 'typedef unsigned short unsigned_short;' +typedefs['unsigned_long'] = 'typedef unsigned long unsigned_long;' +typedefs['signed_char'] = 'typedef signed char signed_char;' +typedefs['long_long'] = """\ +#ifdef _WIN32 +typedef __int64 long_long; +#else +typedef long long long_long; +typedef unsigned long long unsigned_long_long; +#endif +""" +typedefs['unsigned_long_long'] = """\ +#ifdef _WIN32 +typedef __uint64 long_long; +#else +typedef unsigned long long unsigned_long_long; +#endif +""" +typedefs['long_double'] = """\ +#ifndef _LONG_DOUBLE +typedef long double long_double; +#endif +""" +typedefs[ + 'complex_long_double'] = 'typedef struct {long double r,i;} complex_long_double;' +typedefs['complex_float'] = 'typedef struct {float r,i;} complex_float;' +typedefs['complex_double'] = 'typedef struct {double r,i;} complex_double;' +typedefs['string'] = """typedef char * string;""" + + +############### CPP macros #################### +cppmacros['CFUNCSMESS'] = """\ +#ifdef DEBUGCFUNCS +#define CFUNCSMESS(mess) fprintf(stderr,\"debug-capi:\"mess); +#define CFUNCSMESSPY(mess,obj) CFUNCSMESS(mess) \\ + PyObject_Print((PyObject *)obj,stderr,Py_PRINT_RAW);\\ + fprintf(stderr,\"\\n\"); +#else +#define CFUNCSMESS(mess) +#define CFUNCSMESSPY(mess,obj) +#endif +""" +cppmacros['F_FUNC'] = """\ +#if defined(PREPEND_FORTRAN) +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) _##F +#else +#define F_FUNC(f,F) _##f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) _##F##_ +#else +#define F_FUNC(f,F) _##f##_ +#endif +#endif +#else +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) F +#else +#define F_FUNC(f,F) f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) F##_ +#else +#define F_FUNC(f,F) f##_ +#endif +#endif +#endif +#if defined(UNDERSCORE_G77) +#define F_FUNC_US(f,F) F_FUNC(f##_,F##_) +#else +#define F_FUNC_US(f,F) F_FUNC(f,F) +#endif +""" +cppmacros['F_WRAPPEDFUNC'] = """\ +#if defined(PREPEND_FORTRAN) +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_WRAPPEDFUNC(f,F) _F2PYWRAP##F +#else +#define F_WRAPPEDFUNC(f,F) _f2pywrap##f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_WRAPPEDFUNC(f,F) _F2PYWRAP##F##_ +#else +#define F_WRAPPEDFUNC(f,F) _f2pywrap##f##_ +#endif +#endif +#else +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_WRAPPEDFUNC(f,F) F2PYWRAP##F +#else +#define F_WRAPPEDFUNC(f,F) f2pywrap##f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_WRAPPEDFUNC(f,F) F2PYWRAP##F##_ +#else +#define F_WRAPPEDFUNC(f,F) f2pywrap##f##_ +#endif +#endif +#endif +#if defined(UNDERSCORE_G77) +#define F_WRAPPEDFUNC_US(f,F) F_WRAPPEDFUNC(f##_,F##_) +#else +#define F_WRAPPEDFUNC_US(f,F) F_WRAPPEDFUNC(f,F) +#endif +""" +cppmacros['F_MODFUNC'] = """\ +#if defined(F90MOD2CCONV1) /*E.g. Compaq Fortran */ +#if defined(NO_APPEND_FORTRAN) +#define F_MODFUNCNAME(m,f) $ ## m ## $ ## f +#else +#define F_MODFUNCNAME(m,f) $ ## m ## $ ## f ## _ +#endif +#endif + +#if defined(F90MOD2CCONV2) /*E.g. IBM XL Fortran, not tested though */ +#if defined(NO_APPEND_FORTRAN) +#define F_MODFUNCNAME(m,f) __ ## m ## _MOD_ ## f +#else +#define F_MODFUNCNAME(m,f) __ ## m ## _MOD_ ## f ## _ +#endif +#endif + +#if defined(F90MOD2CCONV3) /*E.g. MIPSPro Compilers */ +#if defined(NO_APPEND_FORTRAN) +#define F_MODFUNCNAME(m,f) f ## .in. ## m +#else +#define F_MODFUNCNAME(m,f) f ## .in. ## m ## _ +#endif +#endif +/* +#if defined(UPPERCASE_FORTRAN) +#define F_MODFUNC(m,M,f,F) F_MODFUNCNAME(M,F) +#else +#define F_MODFUNC(m,M,f,F) F_MODFUNCNAME(m,f) +#endif +*/ + +#define F_MODFUNC(m,f) (*(f2pymodstruct##m##.##f)) +""" +cppmacros['SWAPUNSAFE'] = """\ +#define SWAP(a,b) (size_t)(a) = ((size_t)(a) ^ (size_t)(b));\\ + (size_t)(b) = ((size_t)(a) ^ (size_t)(b));\\ + (size_t)(a) = ((size_t)(a) ^ (size_t)(b)) +""" +cppmacros['SWAP'] = """\ +#define SWAP(a,b,t) {\\ + t *c;\\ + c = a;\\ + a = b;\\ + b = c;} +""" +# cppmacros['ISCONTIGUOUS']='#define ISCONTIGUOUS(m) (PyArray_FLAGS(m) & +# NPY_ARRAY_C_CONTIGUOUS)' +cppmacros['PRINTPYOBJERR'] = """\ +#define PRINTPYOBJERR(obj)\\ + fprintf(stderr,\"#modulename#.error is related to \");\\ + PyObject_Print((PyObject *)obj,stderr,Py_PRINT_RAW);\\ + fprintf(stderr,\"\\n\"); +""" +cppmacros['MINMAX'] = """\ +#ifndef max +#define max(a,b) ((a > b) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) ((a < b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a > b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a < b) ? (a) : (b)) +#endif +""" +needs['len..'] = ['f2py_size'] +cppmacros['len..'] = """\ +#define rank(var) var ## _Rank +#define shape(var,dim) var ## _Dims[dim] +#define old_rank(var) (PyArray_NDIM((PyArrayObject *)(capi_ ## var ## _tmp))) +#define old_shape(var,dim) PyArray_DIM(((PyArrayObject *)(capi_ ## var ## _tmp)),dim) +#define fshape(var,dim) shape(var,rank(var)-dim-1) +#define len(var) shape(var,0) +#define flen(var) fshape(var,0) +#define old_size(var) PyArray_SIZE((PyArrayObject *)(capi_ ## var ## _tmp)) +/* #define index(i) capi_i ## i */ +#define slen(var) capi_ ## var ## _len +#define size(var, ...) f2py_size((PyArrayObject *)(capi_ ## var ## _tmp), ## __VA_ARGS__, -1) +""" +needs['f2py_size'] = ['stdarg.h'] +cfuncs['f2py_size'] = """\ +static int f2py_size(PyArrayObject* var, ...) +{ + npy_int sz = 0; + npy_int dim; + npy_int rank; + va_list argp; + va_start(argp, var); + dim = va_arg(argp, npy_int); + if (dim==-1) + { + sz = PyArray_SIZE(var); + } + else + { + rank = PyArray_NDIM(var); + if (dim>=1 && dim<=rank) + sz = PyArray_DIM(var, dim-1); + else + fprintf(stderr, \"f2py_size: 2nd argument value=%d fails to satisfy 1<=value<=%d. Result will be 0.\\n\", dim, rank); + } + va_end(argp); + return sz; +} +""" + +cppmacros[ + 'pyobj_from_char1'] = '#define pyobj_from_char1(v) (PyInt_FromLong(v))' +cppmacros[ + 'pyobj_from_short1'] = '#define pyobj_from_short1(v) (PyInt_FromLong(v))' +needs['pyobj_from_int1'] = ['signed_char'] +cppmacros['pyobj_from_int1'] = '#define pyobj_from_int1(v) (PyInt_FromLong(v))' +cppmacros[ + 'pyobj_from_long1'] = '#define pyobj_from_long1(v) (PyLong_FromLong(v))' +needs['pyobj_from_long_long1'] = ['long_long'] +cppmacros['pyobj_from_long_long1'] = """\ +#ifdef HAVE_LONG_LONG +#define pyobj_from_long_long1(v) (PyLong_FromLongLong(v)) +#else +#warning HAVE_LONG_LONG is not available. Redefining pyobj_from_long_long. +#define pyobj_from_long_long1(v) (PyLong_FromLong(v)) +#endif +""" +needs['pyobj_from_long_double1'] = ['long_double'] +cppmacros[ + 'pyobj_from_long_double1'] = '#define pyobj_from_long_double1(v) (PyFloat_FromDouble(v))' +cppmacros[ + 'pyobj_from_double1'] = '#define pyobj_from_double1(v) (PyFloat_FromDouble(v))' +cppmacros[ + 'pyobj_from_float1'] = '#define pyobj_from_float1(v) (PyFloat_FromDouble(v))' +needs['pyobj_from_complex_long_double1'] = ['complex_long_double'] +cppmacros[ + 'pyobj_from_complex_long_double1'] = '#define pyobj_from_complex_long_double1(v) (PyComplex_FromDoubles(v.r,v.i))' +needs['pyobj_from_complex_double1'] = ['complex_double'] +cppmacros[ + 'pyobj_from_complex_double1'] = '#define pyobj_from_complex_double1(v) (PyComplex_FromDoubles(v.r,v.i))' +needs['pyobj_from_complex_float1'] = ['complex_float'] +cppmacros[ + 'pyobj_from_complex_float1'] = '#define pyobj_from_complex_float1(v) (PyComplex_FromDoubles(v.r,v.i))' +needs['pyobj_from_string1'] = ['string'] +cppmacros[ + 'pyobj_from_string1'] = '#define pyobj_from_string1(v) (PyString_FromString((char *)v))' +needs['pyobj_from_string1size'] = ['string'] +cppmacros[ + 'pyobj_from_string1size'] = '#define pyobj_from_string1size(v,len) (PyUString_FromStringAndSize((char *)v, len))' +needs['TRYPYARRAYTEMPLATE'] = ['PRINTPYOBJERR'] +cppmacros['TRYPYARRAYTEMPLATE'] = """\ +/* New SciPy */ +#define TRYPYARRAYTEMPLATECHAR case NPY_STRING: *(char *)(PyArray_DATA(arr))=*v; break; +#define TRYPYARRAYTEMPLATELONG case NPY_LONG: *(long *)(PyArray_DATA(arr))=*v; break; +#define TRYPYARRAYTEMPLATEOBJECT case NPY_OBJECT: PyArray_SETITEM(arr,PyArray_DATA(arr),pyobj_from_ ## ctype ## 1(*v)); break; + +#define TRYPYARRAYTEMPLATE(ctype,typecode) \\ + PyArrayObject *arr = NULL;\\ + if (!obj) return -2;\\ + if (!PyArray_Check(obj)) return -1;\\ + if (!(arr=(PyArrayObject *)obj)) {fprintf(stderr,\"TRYPYARRAYTEMPLATE:\");PRINTPYOBJERR(obj);return 0;}\\ + if (PyArray_DESCR(arr)->type==typecode) {*(ctype *)(PyArray_DATA(arr))=*v; return 1;}\\ + switch (PyArray_TYPE(arr)) {\\ + case NPY_DOUBLE: *(double *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_INT: *(int *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_LONG: *(long *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_FLOAT: *(float *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_CDOUBLE: *(double *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_CFLOAT: *(float *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_BOOL: *(npy_bool *)(PyArray_DATA(arr))=(*v!=0); break;\\ + case NPY_UBYTE: *(unsigned char *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_BYTE: *(signed char *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_SHORT: *(short *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_USHORT: *(npy_ushort *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_UINT: *(npy_uint *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_ULONG: *(npy_ulong *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_LONGLONG: *(npy_longlong *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_ULONGLONG: *(npy_ulonglong *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_LONGDOUBLE: *(npy_longdouble *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_CLONGDOUBLE: *(npy_longdouble *)(PyArray_DATA(arr))=*v; break;\\ + case NPY_OBJECT: PyArray_SETITEM(arr, PyArray_DATA(arr), pyobj_from_ ## ctype ## 1(*v)); break;\\ + default: return -2;\\ + };\\ + return 1 +""" + +needs['TRYCOMPLEXPYARRAYTEMPLATE'] = ['PRINTPYOBJERR'] +cppmacros['TRYCOMPLEXPYARRAYTEMPLATE'] = """\ +#define TRYCOMPLEXPYARRAYTEMPLATEOBJECT case NPY_OBJECT: PyArray_SETITEM(arr, PyArray_DATA(arr), pyobj_from_complex_ ## ctype ## 1((*v))); break; +#define TRYCOMPLEXPYARRAYTEMPLATE(ctype,typecode)\\ + PyArrayObject *arr = NULL;\\ + if (!obj) return -2;\\ + if (!PyArray_Check(obj)) return -1;\\ + if (!(arr=(PyArrayObject *)obj)) {fprintf(stderr,\"TRYCOMPLEXPYARRAYTEMPLATE:\");PRINTPYOBJERR(obj);return 0;}\\ + if (PyArray_DESCR(arr)->type==typecode) {\\ + *(ctype *)(PyArray_DATA(arr))=(*v).r;\\ + *(ctype *)(PyArray_DATA(arr)+sizeof(ctype))=(*v).i;\\ + return 1;\\ + }\\ + switch (PyArray_TYPE(arr)) {\\ + case NPY_CDOUBLE: *(double *)(PyArray_DATA(arr))=(*v).r;*(double *)(PyArray_DATA(arr)+sizeof(double))=(*v).i;break;\\ + case NPY_CFLOAT: *(float *)(PyArray_DATA(arr))=(*v).r;*(float *)(PyArray_DATA(arr)+sizeof(float))=(*v).i;break;\\ + case NPY_DOUBLE: *(double *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_LONG: *(long *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_FLOAT: *(float *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_INT: *(int *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_SHORT: *(short *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_UBYTE: *(unsigned char *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_BYTE: *(signed char *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_BOOL: *(npy_bool *)(PyArray_DATA(arr))=((*v).r!=0 && (*v).i!=0); break;\\ + case NPY_USHORT: *(npy_ushort *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_UINT: *(npy_uint *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_ULONG: *(npy_ulong *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_LONGLONG: *(npy_longlong *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_ULONGLONG: *(npy_ulonglong *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_LONGDOUBLE: *(npy_longdouble *)(PyArray_DATA(arr))=(*v).r; break;\\ + case NPY_CLONGDOUBLE: *(npy_longdouble *)(PyArray_DATA(arr))=(*v).r;*(npy_longdouble *)(PyArray_DATA(arr)+sizeof(npy_longdouble))=(*v).i;break;\\ + case NPY_OBJECT: PyArray_SETITEM(arr, PyArray_DATA(arr), pyobj_from_complex_ ## ctype ## 1((*v))); break;\\ + default: return -2;\\ + };\\ + return -1; +""" +# cppmacros['NUMFROMARROBJ']="""\ +# define NUMFROMARROBJ(typenum,ctype) \\ +# if (PyArray_Check(obj)) arr = (PyArrayObject *)obj;\\ +# else arr = (PyArrayObject *)PyArray_ContiguousFromObject(obj,typenum,0,0);\\ +# if (arr) {\\ +# if (PyArray_TYPE(arr)==NPY_OBJECT) {\\ +# if (!ctype ## _from_pyobj(v,(PyArray_DESCR(arr)->getitem)(PyArray_DATA(arr)),\"\"))\\ +# goto capi_fail;\\ +# } else {\\ +# (PyArray_DESCR(arr)->cast[typenum])(PyArray_DATA(arr),1,(char*)v,1,1);\\ +# }\\ +# if ((PyObject *)arr != obj) { Py_DECREF(arr); }\\ +# return 1;\\ +# } +# """ +# XXX: Note that CNUMFROMARROBJ is identical with NUMFROMARROBJ +# cppmacros['CNUMFROMARROBJ']="""\ +# define CNUMFROMARROBJ(typenum,ctype) \\ +# if (PyArray_Check(obj)) arr = (PyArrayObject *)obj;\\ +# else arr = (PyArrayObject *)PyArray_ContiguousFromObject(obj,typenum,0,0);\\ +# if (arr) {\\ +# if (PyArray_TYPE(arr)==NPY_OBJECT) {\\ +# if (!ctype ## _from_pyobj(v,(PyArray_DESCR(arr)->getitem)(PyArray_DATA(arr)),\"\"))\\ +# goto capi_fail;\\ +# } else {\\ +# (PyArray_DESCR(arr)->cast[typenum])((void *)(PyArray_DATA(arr)),1,(void *)(v),1,1);\\ +# }\\ +# if ((PyObject *)arr != obj) { Py_DECREF(arr); }\\ +# return 1;\\ +# } +# """ + + +needs['GETSTRFROMPYTUPLE'] = ['STRINGCOPYN', 'PRINTPYOBJERR'] +cppmacros['GETSTRFROMPYTUPLE'] = """\ +#define GETSTRFROMPYTUPLE(tuple,index,str,len) {\\ + PyObject *rv_cb_str = PyTuple_GetItem((tuple),(index));\\ + if (rv_cb_str == NULL)\\ + goto capi_fail;\\ + if (PyString_Check(rv_cb_str)) {\\ + str[len-1]='\\0';\\ + STRINGCOPYN((str),PyString_AS_STRING((PyStringObject*)rv_cb_str),(len));\\ + } else {\\ + PRINTPYOBJERR(rv_cb_str);\\ + PyErr_SetString(#modulename#_error,\"string object expected\");\\ + goto capi_fail;\\ + }\\ + } +""" +cppmacros['GETSCALARFROMPYTUPLE'] = """\ +#define GETSCALARFROMPYTUPLE(tuple,index,var,ctype,mess) {\\ + if ((capi_tmp = PyTuple_GetItem((tuple),(index)))==NULL) goto capi_fail;\\ + if (!(ctype ## _from_pyobj((var),capi_tmp,mess)))\\ + goto capi_fail;\\ + } +""" + +cppmacros['FAILNULL'] = """\\ +#define FAILNULL(p) do { \\ + if ((p) == NULL) { \\ + PyErr_SetString(PyExc_MemoryError, "NULL pointer found"); \\ + goto capi_fail; \\ + } \\ +} while (0) +""" +needs['MEMCOPY'] = ['string.h', 'FAILNULL'] +cppmacros['MEMCOPY'] = """\ +#define MEMCOPY(to,from,n)\\ + do { FAILNULL(to); FAILNULL(from); (void)memcpy(to,from,n); } while (0) +""" +cppmacros['STRINGMALLOC'] = """\ +#define STRINGMALLOC(str,len)\\ + if ((str = (string)malloc(sizeof(char)*(len+1))) == NULL) {\\ + PyErr_SetString(PyExc_MemoryError, \"out of memory\");\\ + goto capi_fail;\\ + } else {\\ + (str)[len] = '\\0';\\ + } +""" +cppmacros['STRINGFREE'] = """\ +#define STRINGFREE(str) do {if (!(str == NULL)) free(str);} while (0) +""" +needs['STRINGCOPYN'] = ['string.h', 'FAILNULL'] +cppmacros['STRINGCOPYN'] = """\ +#define STRINGCOPYN(to,from,buf_size) \\ + do { \\ + int _m = (buf_size); \\ + char *_to = (to); \\ + char *_from = (from); \\ + FAILNULL(_to); FAILNULL(_from); \\ + (void)strncpy(_to, _from, sizeof(char)*_m); \\ + _to[_m-1] = '\\0'; \\ + /* Padding with spaces instead of nulls */ \\ + for (_m -= 2; _m >= 0 && _to[_m] == '\\0'; _m--) { \\ + _to[_m] = ' '; \\ + } \\ + } while (0) +""" +needs['STRINGCOPY'] = ['string.h', 'FAILNULL'] +cppmacros['STRINGCOPY'] = """\ +#define STRINGCOPY(to,from)\\ + do { FAILNULL(to); FAILNULL(from); (void)strcpy(to,from); } while (0) +""" +cppmacros['CHECKGENERIC'] = """\ +#define CHECKGENERIC(check,tcheck,name) \\ + if (!(check)) {\\ + PyErr_SetString(#modulename#_error,\"(\"tcheck\") failed for \"name);\\ + /*goto capi_fail;*/\\ + } else """ +cppmacros['CHECKARRAY'] = """\ +#define CHECKARRAY(check,tcheck,name) \\ + if (!(check)) {\\ + PyErr_SetString(#modulename#_error,\"(\"tcheck\") failed for \"name);\\ + /*goto capi_fail;*/\\ + } else """ +cppmacros['CHECKSTRING'] = """\ +#define CHECKSTRING(check,tcheck,name,show,var)\\ + if (!(check)) {\\ + char errstring[256];\\ + sprintf(errstring, \"%s: \"show, \"(\"tcheck\") failed for \"name, slen(var), var);\\ + PyErr_SetString(#modulename#_error, errstring);\\ + /*goto capi_fail;*/\\ + } else """ +cppmacros['CHECKSCALAR'] = """\ +#define CHECKSCALAR(check,tcheck,name,show,var)\\ + if (!(check)) {\\ + char errstring[256];\\ + sprintf(errstring, \"%s: \"show, \"(\"tcheck\") failed for \"name, var);\\ + PyErr_SetString(#modulename#_error,errstring);\\ + /*goto capi_fail;*/\\ + } else """ +# cppmacros['CHECKDIMS']="""\ +# define CHECKDIMS(dims,rank) \\ +# for (int i=0;i<(rank);i++)\\ +# if (dims[i]<0) {\\ +# fprintf(stderr,\"Unspecified array argument requires a complete dimension specification.\\n\");\\ +# goto capi_fail;\\ +# } +# """ +cppmacros[ + 'ARRSIZE'] = '#define ARRSIZE(dims,rank) (_PyArray_multiply_list(dims,rank))' +cppmacros['OLDPYNUM'] = """\ +#ifdef OLDPYNUM +#error You need to intall Numeric Python version 13 or higher. Get it from http:/sourceforge.net/project/?group_id=1369 +#endif +""" +################# C functions ############### + +cfuncs['calcarrindex'] = """\ +static int calcarrindex(int *i,PyArrayObject *arr) { + int k,ii = i[0]; + for (k=1; k < PyArray_NDIM(arr); k++) + ii += (ii*(PyArray_DIM(arr,k) - 1)+i[k]); /* assuming contiguous arr */ + return ii; +}""" +cfuncs['calcarrindextr'] = """\ +static int calcarrindextr(int *i,PyArrayObject *arr) { + int k,ii = i[PyArray_NDIM(arr)-1]; + for (k=1; k < PyArray_NDIM(arr); k++) + ii += (ii*(PyArray_DIM(arr,PyArray_NDIM(arr)-k-1) - 1)+i[PyArray_NDIM(arr)-k-1]); /* assuming contiguous arr */ + return ii; +}""" +cfuncs['forcomb'] = """\ +static struct { int nd;npy_intp *d;int *i,*i_tr,tr; } forcombcache; +static int initforcomb(npy_intp *dims,int nd,int tr) { + int k; + if (dims==NULL) return 0; + if (nd<0) return 0; + forcombcache.nd = nd; + forcombcache.d = dims; + forcombcache.tr = tr; + if ((forcombcache.i = (int *)malloc(sizeof(int)*nd))==NULL) return 0; + if ((forcombcache.i_tr = (int *)malloc(sizeof(int)*nd))==NULL) return 0; + for (k=1;k= 0x03000000 + else if (PyUnicode_Check(obj)) { + tmp = PyUnicode_AsASCIIString(obj); + } + else { + PyObject *tmp2; + tmp2 = PyObject_Str(obj); + if (tmp2) { + tmp = PyUnicode_AsASCIIString(tmp2); + Py_DECREF(tmp2); + } + else { + tmp = NULL; + } + } +#else + else { + tmp = PyObject_Str(obj); + } +#endif + if (tmp == NULL) goto capi_fail; + if (*len == -1) + *len = PyString_GET_SIZE(tmp); + STRINGMALLOC(*str,*len); + STRINGCOPYN(*str,PyString_AS_STRING(tmp),*len+1); + Py_DECREF(tmp); + return 1; +capi_fail: + Py_XDECREF(tmp); + { + PyObject* err = PyErr_Occurred(); + if (err==NULL) err = #modulename#_error; + PyErr_SetString(err,errmess); + } + return 0; +} +""" +needs['char_from_pyobj'] = ['int_from_pyobj'] +cfuncs['char_from_pyobj'] = """\ +static int char_from_pyobj(char* v,PyObject *obj,const char *errmess) { + int i=0; + if (int_from_pyobj(&i,obj,errmess)) { + *v = (char)i; + return 1; + } + return 0; +} +""" +needs['signed_char_from_pyobj'] = ['int_from_pyobj', 'signed_char'] +cfuncs['signed_char_from_pyobj'] = """\ +static int signed_char_from_pyobj(signed_char* v,PyObject *obj,const char *errmess) { + int i=0; + if (int_from_pyobj(&i,obj,errmess)) { + *v = (signed_char)i; + return 1; + } + return 0; +} +""" +needs['short_from_pyobj'] = ['int_from_pyobj'] +cfuncs['short_from_pyobj'] = """\ +static int short_from_pyobj(short* v,PyObject *obj,const char *errmess) { + int i=0; + if (int_from_pyobj(&i,obj,errmess)) { + *v = (short)i; + return 1; + } + return 0; +} +""" +cfuncs['int_from_pyobj'] = """\ +static int int_from_pyobj(int* v,PyObject *obj,const char *errmess) { + PyObject* tmp = NULL; + if (PyInt_Check(obj)) { + *v = (int)PyInt_AS_LONG(obj); + return 1; + } + tmp = PyNumber_Int(obj); + if (tmp) { + *v = PyInt_AS_LONG(tmp); + Py_DECREF(tmp); + return 1; + } + if (PyComplex_Check(obj)) + tmp = PyObject_GetAttrString(obj,\"real\"); + else if (PyString_Check(obj) || PyUnicode_Check(obj)) + /*pass*/; + else if (PySequence_Check(obj)) + tmp = PySequence_GetItem(obj,0); + if (tmp) { + PyErr_Clear(); + if (int_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;} + Py_DECREF(tmp); + } + { + PyObject* err = PyErr_Occurred(); + if (err==NULL) err = #modulename#_error; + PyErr_SetString(err,errmess); + } + return 0; +} +""" +cfuncs['long_from_pyobj'] = """\ +static int long_from_pyobj(long* v,PyObject *obj,const char *errmess) { + PyObject* tmp = NULL; + if (PyInt_Check(obj)) { + *v = PyInt_AS_LONG(obj); + return 1; + } + tmp = PyNumber_Int(obj); + if (tmp) { + *v = PyInt_AS_LONG(tmp); + Py_DECREF(tmp); + return 1; + } + if (PyComplex_Check(obj)) + tmp = PyObject_GetAttrString(obj,\"real\"); + else if (PyString_Check(obj) || PyUnicode_Check(obj)) + /*pass*/; + else if (PySequence_Check(obj)) + tmp = PySequence_GetItem(obj,0); + if (tmp) { + PyErr_Clear(); + if (long_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;} + Py_DECREF(tmp); + } + { + PyObject* err = PyErr_Occurred(); + if (err==NULL) err = #modulename#_error; + PyErr_SetString(err,errmess); + } + return 0; +} +""" +needs['long_long_from_pyobj'] = ['long_long'] +cfuncs['long_long_from_pyobj'] = """\ +static int long_long_from_pyobj(long_long* v,PyObject *obj,const char *errmess) { + PyObject* tmp = NULL; + if (PyLong_Check(obj)) { + *v = PyLong_AsLongLong(obj); + return (!PyErr_Occurred()); + } + if (PyInt_Check(obj)) { + *v = (long_long)PyInt_AS_LONG(obj); + return 1; + } + tmp = PyNumber_Long(obj); + if (tmp) { + *v = PyLong_AsLongLong(tmp); + Py_DECREF(tmp); + return (!PyErr_Occurred()); + } + if (PyComplex_Check(obj)) + tmp = PyObject_GetAttrString(obj,\"real\"); + else if (PyString_Check(obj) || PyUnicode_Check(obj)) + /*pass*/; + else if (PySequence_Check(obj)) + tmp = PySequence_GetItem(obj,0); + if (tmp) { + PyErr_Clear(); + if (long_long_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;} + Py_DECREF(tmp); + } + { + PyObject* err = PyErr_Occurred(); + if (err==NULL) err = #modulename#_error; + PyErr_SetString(err,errmess); + } + return 0; +} +""" +needs['long_double_from_pyobj'] = ['double_from_pyobj', 'long_double'] +cfuncs['long_double_from_pyobj'] = """\ +static int long_double_from_pyobj(long_double* v,PyObject *obj,const char *errmess) { + double d=0; + if (PyArray_CheckScalar(obj)){ + if PyArray_IsScalar(obj, LongDouble) { + PyArray_ScalarAsCtype(obj, v); + return 1; + } + else if (PyArray_Check(obj) && PyArray_TYPE(obj)==NPY_LONGDOUBLE) { + (*v) = *((npy_longdouble *)PyArray_DATA(obj)); + return 1; + } + } + if (double_from_pyobj(&d,obj,errmess)) { + *v = (long_double)d; + return 1; + } + return 0; +} +""" +cfuncs['double_from_pyobj'] = """\ +static int double_from_pyobj(double* v,PyObject *obj,const char *errmess) { + PyObject* tmp = NULL; + if (PyFloat_Check(obj)) { +#ifdef __sgi + *v = PyFloat_AsDouble(obj); +#else + *v = PyFloat_AS_DOUBLE(obj); +#endif + return 1; + } + tmp = PyNumber_Float(obj); + if (tmp) { +#ifdef __sgi + *v = PyFloat_AsDouble(tmp); +#else + *v = PyFloat_AS_DOUBLE(tmp); +#endif + Py_DECREF(tmp); + return 1; + } + if (PyComplex_Check(obj)) + tmp = PyObject_GetAttrString(obj,\"real\"); + else if (PyString_Check(obj) || PyUnicode_Check(obj)) + /*pass*/; + else if (PySequence_Check(obj)) + tmp = PySequence_GetItem(obj,0); + if (tmp) { + PyErr_Clear(); + if (double_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;} + Py_DECREF(tmp); + } + { + PyObject* err = PyErr_Occurred(); + if (err==NULL) err = #modulename#_error; + PyErr_SetString(err,errmess); + } + return 0; +} +""" +needs['float_from_pyobj'] = ['double_from_pyobj'] +cfuncs['float_from_pyobj'] = """\ +static int float_from_pyobj(float* v,PyObject *obj,const char *errmess) { + double d=0.0; + if (double_from_pyobj(&d,obj,errmess)) { + *v = (float)d; + return 1; + } + return 0; +} +""" +needs['complex_long_double_from_pyobj'] = ['complex_long_double', 'long_double', + 'complex_double_from_pyobj'] +cfuncs['complex_long_double_from_pyobj'] = """\ +static int complex_long_double_from_pyobj(complex_long_double* v,PyObject *obj,const char *errmess) { + complex_double cd={0.0,0.0}; + if (PyArray_CheckScalar(obj)){ + if PyArray_IsScalar(obj, CLongDouble) { + PyArray_ScalarAsCtype(obj, v); + return 1; + } + else if (PyArray_Check(obj) && PyArray_TYPE(obj)==NPY_CLONGDOUBLE) { + (*v).r = ((npy_clongdouble *)PyArray_DATA(obj))->real; + (*v).i = ((npy_clongdouble *)PyArray_DATA(obj))->imag; + return 1; + } + } + if (complex_double_from_pyobj(&cd,obj,errmess)) { + (*v).r = (long_double)cd.r; + (*v).i = (long_double)cd.i; + return 1; + } + return 0; +} +""" +needs['complex_double_from_pyobj'] = ['complex_double'] +cfuncs['complex_double_from_pyobj'] = """\ +static int complex_double_from_pyobj(complex_double* v,PyObject *obj,const char *errmess) { + Py_complex c; + if (PyComplex_Check(obj)) { + c=PyComplex_AsCComplex(obj); + (*v).r=c.real, (*v).i=c.imag; + return 1; + } + if (PyArray_IsScalar(obj, ComplexFloating)) { + if (PyArray_IsScalar(obj, CFloat)) { + npy_cfloat new; + PyArray_ScalarAsCtype(obj, &new); + (*v).r = (double)new.real; + (*v).i = (double)new.imag; + } + else if (PyArray_IsScalar(obj, CLongDouble)) { + npy_clongdouble new; + PyArray_ScalarAsCtype(obj, &new); + (*v).r = (double)new.real; + (*v).i = (double)new.imag; + } + else { /* if (PyArray_IsScalar(obj, CDouble)) */ + PyArray_ScalarAsCtype(obj, v); + } + return 1; + } + if (PyArray_CheckScalar(obj)) { /* 0-dim array or still array scalar */ + PyObject *arr; + if (PyArray_Check(obj)) { + arr = PyArray_Cast((PyArrayObject *)obj, NPY_CDOUBLE); + } + else { + arr = PyArray_FromScalar(obj, PyArray_DescrFromType(NPY_CDOUBLE)); + } + if (arr==NULL) return 0; + (*v).r = ((npy_cdouble *)PyArray_DATA(arr))->real; + (*v).i = ((npy_cdouble *)PyArray_DATA(arr))->imag; + return 1; + } + /* Python does not provide PyNumber_Complex function :-( */ + (*v).i=0.0; + if (PyFloat_Check(obj)) { +#ifdef __sgi + (*v).r = PyFloat_AsDouble(obj); +#else + (*v).r = PyFloat_AS_DOUBLE(obj); +#endif + return 1; + } + if (PyInt_Check(obj)) { + (*v).r = (double)PyInt_AS_LONG(obj); + return 1; + } + if (PyLong_Check(obj)) { + (*v).r = PyLong_AsDouble(obj); + return (!PyErr_Occurred()); + } + if (PySequence_Check(obj) && !(PyString_Check(obj) || PyUnicode_Check(obj))) { + PyObject *tmp = PySequence_GetItem(obj,0); + if (tmp) { + if (complex_double_from_pyobj(v,tmp,errmess)) { + Py_DECREF(tmp); + return 1; + } + Py_DECREF(tmp); + } + } + { + PyObject* err = PyErr_Occurred(); + if (err==NULL) + err = PyExc_TypeError; + PyErr_SetString(err,errmess); + } + return 0; +} +""" +needs['complex_float_from_pyobj'] = [ + 'complex_float', 'complex_double_from_pyobj'] +cfuncs['complex_float_from_pyobj'] = """\ +static int complex_float_from_pyobj(complex_float* v,PyObject *obj,const char *errmess) { + complex_double cd={0.0,0.0}; + if (complex_double_from_pyobj(&cd,obj,errmess)) { + (*v).r = (float)cd.r; + (*v).i = (float)cd.i; + return 1; + } + return 0; +} +""" +needs['try_pyarr_from_char'] = ['pyobj_from_char1', 'TRYPYARRAYTEMPLATE'] +cfuncs[ + 'try_pyarr_from_char'] = 'static int try_pyarr_from_char(PyObject* obj,char* v) {\n TRYPYARRAYTEMPLATE(char,\'c\');\n}\n' +needs['try_pyarr_from_signed_char'] = ['TRYPYARRAYTEMPLATE', 'unsigned_char'] +cfuncs[ + 'try_pyarr_from_unsigned_char'] = 'static int try_pyarr_from_unsigned_char(PyObject* obj,unsigned_char* v) {\n TRYPYARRAYTEMPLATE(unsigned_char,\'b\');\n}\n' +needs['try_pyarr_from_signed_char'] = ['TRYPYARRAYTEMPLATE', 'signed_char'] +cfuncs[ + 'try_pyarr_from_signed_char'] = 'static int try_pyarr_from_signed_char(PyObject* obj,signed_char* v) {\n TRYPYARRAYTEMPLATE(signed_char,\'1\');\n}\n' +needs['try_pyarr_from_short'] = ['pyobj_from_short1', 'TRYPYARRAYTEMPLATE'] +cfuncs[ + 'try_pyarr_from_short'] = 'static int try_pyarr_from_short(PyObject* obj,short* v) {\n TRYPYARRAYTEMPLATE(short,\'s\');\n}\n' +needs['try_pyarr_from_int'] = ['pyobj_from_int1', 'TRYPYARRAYTEMPLATE'] +cfuncs[ + 'try_pyarr_from_int'] = 'static int try_pyarr_from_int(PyObject* obj,int* v) {\n TRYPYARRAYTEMPLATE(int,\'i\');\n}\n' +needs['try_pyarr_from_long'] = ['pyobj_from_long1', 'TRYPYARRAYTEMPLATE'] +cfuncs[ + 'try_pyarr_from_long'] = 'static int try_pyarr_from_long(PyObject* obj,long* v) {\n TRYPYARRAYTEMPLATE(long,\'l\');\n}\n' +needs['try_pyarr_from_long_long'] = [ + 'pyobj_from_long_long1', 'TRYPYARRAYTEMPLATE', 'long_long'] +cfuncs[ + 'try_pyarr_from_long_long'] = 'static int try_pyarr_from_long_long(PyObject* obj,long_long* v) {\n TRYPYARRAYTEMPLATE(long_long,\'L\');\n}\n' +needs['try_pyarr_from_float'] = ['pyobj_from_float1', 'TRYPYARRAYTEMPLATE'] +cfuncs[ + 'try_pyarr_from_float'] = 'static int try_pyarr_from_float(PyObject* obj,float* v) {\n TRYPYARRAYTEMPLATE(float,\'f\');\n}\n' +needs['try_pyarr_from_double'] = ['pyobj_from_double1', 'TRYPYARRAYTEMPLATE'] +cfuncs[ + 'try_pyarr_from_double'] = 'static int try_pyarr_from_double(PyObject* obj,double* v) {\n TRYPYARRAYTEMPLATE(double,\'d\');\n}\n' +needs['try_pyarr_from_complex_float'] = [ + 'pyobj_from_complex_float1', 'TRYCOMPLEXPYARRAYTEMPLATE', 'complex_float'] +cfuncs[ + 'try_pyarr_from_complex_float'] = 'static int try_pyarr_from_complex_float(PyObject* obj,complex_float* v) {\n TRYCOMPLEXPYARRAYTEMPLATE(float,\'F\');\n}\n' +needs['try_pyarr_from_complex_double'] = [ + 'pyobj_from_complex_double1', 'TRYCOMPLEXPYARRAYTEMPLATE', 'complex_double'] +cfuncs[ + 'try_pyarr_from_complex_double'] = 'static int try_pyarr_from_complex_double(PyObject* obj,complex_double* v) {\n TRYCOMPLEXPYARRAYTEMPLATE(double,\'D\');\n}\n' + +needs['create_cb_arglist'] = ['CFUNCSMESS', 'PRINTPYOBJERR', 'MINMAX'] +cfuncs['create_cb_arglist'] = """\ +static int create_cb_arglist(PyObject* fun,PyTupleObject* xa,const int maxnofargs,const int nofoptargs,int *nofargs,PyTupleObject **args,const char *errmess) { + PyObject *tmp = NULL; + PyObject *tmp_fun = NULL; + int tot,opt,ext,siz,i,di=0; + CFUNCSMESS(\"create_cb_arglist\\n\"); + tot=opt=ext=siz=0; + /* Get the total number of arguments */ + if (PyFunction_Check(fun)) + tmp_fun = fun; + else { + di = 1; + if (PyObject_HasAttrString(fun,\"im_func\")) { + tmp_fun = PyObject_GetAttrString(fun,\"im_func\"); + } + else if (PyObject_HasAttrString(fun,\"__call__\")) { + tmp = PyObject_GetAttrString(fun,\"__call__\"); + if (PyObject_HasAttrString(tmp,\"im_func\")) + tmp_fun = PyObject_GetAttrString(tmp,\"im_func\"); + else { + tmp_fun = fun; /* built-in function */ + tot = maxnofargs; + if (xa != NULL) + tot += PyTuple_Size((PyObject *)xa); + } + Py_XDECREF(tmp); + } + else if (PyFortran_Check(fun) || PyFortran_Check1(fun)) { + tot = maxnofargs; + if (xa != NULL) + tot += PyTuple_Size((PyObject *)xa); + tmp_fun = fun; + } + else if (F2PyCapsule_Check(fun)) { + tot = maxnofargs; + if (xa != NULL) + ext = PyTuple_Size((PyObject *)xa); + if(ext>0) { + fprintf(stderr,\"extra arguments tuple cannot be used with CObject call-back\\n\"); + goto capi_fail; + } + tmp_fun = fun; + } + } +if (tmp_fun==NULL) { +fprintf(stderr,\"Call-back argument must be function|instance|instance.__call__|f2py-function but got %s.\\n\",(fun==NULL?\"NULL\":Py_TYPE(fun)->tp_name)); +goto capi_fail; +} +#if PY_VERSION_HEX >= 0x03000000 + if (PyObject_HasAttrString(tmp_fun,\"__code__\")) { + if (PyObject_HasAttrString(tmp = PyObject_GetAttrString(tmp_fun,\"__code__\"),\"co_argcount\")) +#else + if (PyObject_HasAttrString(tmp_fun,\"func_code\")) { + if (PyObject_HasAttrString(tmp = PyObject_GetAttrString(tmp_fun,\"func_code\"),\"co_argcount\")) +#endif + tot = PyInt_AsLong(PyObject_GetAttrString(tmp,\"co_argcount\")) - di; + Py_XDECREF(tmp); + } + /* Get the number of optional arguments */ +#if PY_VERSION_HEX >= 0x03000000 + if (PyObject_HasAttrString(tmp_fun,\"__defaults__\")) { + if (PyTuple_Check(tmp = PyObject_GetAttrString(tmp_fun,\"__defaults__\"))) +#else + if (PyObject_HasAttrString(tmp_fun,\"func_defaults\")) { + if (PyTuple_Check(tmp = PyObject_GetAttrString(tmp_fun,\"func_defaults\"))) +#endif + opt = PyTuple_Size(tmp); + Py_XDECREF(tmp); + } + /* Get the number of extra arguments */ + if (xa != NULL) + ext = PyTuple_Size((PyObject *)xa); + /* Calculate the size of call-backs argument list */ + siz = MIN(maxnofargs+ext,tot); + *nofargs = MAX(0,siz-ext); +#ifdef DEBUGCFUNCS + fprintf(stderr,\"debug-capi:create_cb_arglist:maxnofargs(-nofoptargs),tot,opt,ext,siz,nofargs=%d(-%d),%d,%d,%d,%d,%d\\n\",maxnofargs,nofoptargs,tot,opt,ext,siz,*nofargs); +#endif + if (siz 0: + if outneeds[n][0] not in needs: + out.append(outneeds[n][0]) + del outneeds[n][0] + else: + flag = 0 + for k in outneeds[n][1:]: + if k in needs[outneeds[n][0]]: + flag = 1 + break + if flag: + outneeds[n] = outneeds[n][1:] + [outneeds[n][0]] + else: + out.append(outneeds[n][0]) + del outneeds[n][0] + if saveout and (0 not in map(lambda x, y: x == y, saveout, outneeds[n])) \ + and outneeds[n] != []: + print(n, saveout) + errmess( + 'get_needs: no progress in sorting needs, probably circular dependence, skipping.\n') + out = out + saveout + break + saveout = copy.copy(outneeds[n]) + if out == []: + out = [n] + res[n] = out + return res diff --git a/numpy/f2py/common_rules.py b/numpy/f2py/common_rules.py new file mode 100644 index 0000000..1940d42 --- /dev/null +++ b/numpy/f2py/common_rules.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +""" + +Build common block mechanism for f2py2e. + +Copyright 2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/05/06 10:57:33 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +__version__ = "$Revision: 1.19 $"[10:-1] + +from . import __version__ +f2py_version = __version__.version + +from .auxfuncs import ( + hasbody, hascommon, hasnote, isintent_hide, outmess +) +from . import capi_maps +from . import func2subr +from .crackfortran import rmbadname + + +def findcommonblocks(block, top=1): + ret = [] + if hascommon(block): + for n in block['common'].keys(): + vars = {} + for v in block['common'][n]: + vars[v] = block['vars'][v] + ret.append((n, block['common'][n], vars)) + elif hasbody(block): + for b in block['body']: + ret = ret + findcommonblocks(b, 0) + if top: + tret = [] + names = [] + for t in ret: + if t[0] not in names: + names.append(t[0]) + tret.append(t) + return tret + return ret + + +def buildhooks(m): + ret = {'commonhooks': [], 'initcommonhooks': [], + 'docs': ['"COMMON blocks:\\n"']} + fwrap = [''] + + def fadd(line, s=fwrap): + s[0] = '%s\n %s' % (s[0], line) + chooks = [''] + + def cadd(line, s=chooks): + s[0] = '%s\n%s' % (s[0], line) + ihooks = [''] + + def iadd(line, s=ihooks): + s[0] = '%s\n%s' % (s[0], line) + doc = [''] + + def dadd(line, s=doc): + s[0] = '%s\n%s' % (s[0], line) + for (name, vnames, vars) in findcommonblocks(m): + lower_name = name.lower() + hnames, inames = [], [] + for n in vnames: + if isintent_hide(vars[n]): + hnames.append(n) + else: + inames.append(n) + if hnames: + outmess('\t\tConstructing COMMON block support for "%s"...\n\t\t %s\n\t\t Hidden: %s\n' % ( + name, ','.join(inames), ','.join(hnames))) + else: + outmess('\t\tConstructing COMMON block support for "%s"...\n\t\t %s\n' % ( + name, ','.join(inames))) + fadd('subroutine f2pyinit%s(setupfunc)' % name) + fadd('external setupfunc') + for n in vnames: + fadd(func2subr.var2fixfortran(vars, n)) + if name == '_BLNK_': + fadd('common %s' % (','.join(vnames))) + else: + fadd('common /%s/ %s' % (name, ','.join(vnames))) + fadd('call setupfunc(%s)' % (','.join(inames))) + fadd('end\n') + cadd('static FortranDataDef f2py_%s_def[] = {' % (name)) + idims = [] + for n in inames: + ct = capi_maps.getctype(vars[n]) + at = capi_maps.c2capi_map[ct] + dm = capi_maps.getarrdims(n, vars[n]) + if dm['dims']: + idims.append('(%s)' % (dm['dims'])) + else: + idims.append('') + dms = dm['dims'].strip() + if not dms: + dms = '-1' + cadd('\t{\"%s\",%s,{{%s}},%s},' % (n, dm['rank'], dms, at)) + cadd('\t{NULL}\n};') + inames1 = rmbadname(inames) + inames1_tps = ','.join(['char *' + s for s in inames1]) + cadd('static void f2py_setup_%s(%s) {' % (name, inames1_tps)) + cadd('\tint i_f2py=0;') + for n in inames1: + cadd('\tf2py_%s_def[i_f2py++].data = %s;' % (name, n)) + cadd('}') + if '_' in lower_name: + F_FUNC = 'F_FUNC_US' + else: + F_FUNC = 'F_FUNC' + cadd('extern void %s(f2pyinit%s,F2PYINIT%s)(void(*)(%s));' + % (F_FUNC, lower_name, name.upper(), + ','.join(['char*'] * len(inames1)))) + cadd('static void f2py_init_%s(void) {' % name) + cadd('\t%s(f2pyinit%s,F2PYINIT%s)(f2py_setup_%s);' + % (F_FUNC, lower_name, name.upper(), name)) + cadd('}\n') + iadd('\tF2PyDict_SetItemString(d, \"%s\", PyFortranObject_New(f2py_%s_def,f2py_init_%s));' % ( + name, name, name)) + tname = name.replace('_', '\\_') + dadd('\\subsection{Common block \\texttt{%s}}\n' % (tname)) + dadd('\\begin{description}') + for n in inames: + dadd('\\item[]{{}\\verb@%s@{}}' % + (capi_maps.getarrdocsign(n, vars[n]))) + if hasnote(vars[n]): + note = vars[n]['note'] + if isinstance(note, list): + note = '\n'.join(note) + dadd('--- %s' % (note)) + dadd('\\end{description}') + ret['docs'].append( + '"\t/%s/ %s\\n"' % (name, ','.join(map(lambda v, d: v + d, inames, idims)))) + ret['commonhooks'] = chooks + ret['initcommonhooks'] = ihooks + ret['latexdoc'] = doc[0] + if len(ret['docs']) <= 1: + ret['docs'] = '' + return ret, fwrap[0] diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py new file mode 100755 index 0000000..677f4ba --- /dev/null +++ b/numpy/f2py/crackfortran.py @@ -0,0 +1,3340 @@ +#!/usr/bin/env python +""" +crackfortran --- read fortran (77,90) code and extract declaration information. + +Copyright 1999-2004 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/09/27 07:13:49 $ +Pearu Peterson + + +Usage of crackfortran: +====================== +Command line keys: -quiet,-verbose,-fix,-f77,-f90,-show,-h + -m ,--ignore-contains +Functions: crackfortran, crack2fortran +The following Fortran statements/constructions are supported +(or will be if needed): + block data,byte,call,character,common,complex,contains,data, + dimension,double complex,double precision,end,external,function, + implicit,integer,intent,interface,intrinsic, + logical,module,optional,parameter,private,public, + program,real,(sequence?),subroutine,type,use,virtual, + include,pythonmodule +Note: 'virtual' is mapped to 'dimension'. +Note: 'implicit integer (z) static (z)' is 'implicit static (z)' (this is minor bug). +Note: code after 'contains' will be ignored until its scope ends. +Note: 'common' statement is extended: dimensions are moved to variable definitions +Note: f2py directive: f2py is read as +Note: pythonmodule is introduced to represent Python module + +Usage: + `postlist=crackfortran(files,funcs)` + `postlist` contains declaration information read from the list of files `files`. + `crack2fortran(postlist)` returns a fortran code to be saved to pyf-file + + `postlist` has the following structure: + *** it is a list of dictionaries containing `blocks': + B = {'block','body','vars','parent_block'[,'name','prefix','args','result', + 'implicit','externals','interfaced','common','sortvars', + 'commonvars','note']} + B['block'] = 'interface' | 'function' | 'subroutine' | 'module' | + 'program' | 'block data' | 'type' | 'pythonmodule' + B['body'] --- list containing `subblocks' with the same structure as `blocks' + B['parent_block'] --- dictionary of a parent block: + C['body'][]['parent_block'] is C + B['vars'] --- dictionary of variable definitions + B['sortvars'] --- dictionary of variable definitions sorted by dependence (independent first) + B['name'] --- name of the block (not if B['block']=='interface') + B['prefix'] --- prefix string (only if B['block']=='function') + B['args'] --- list of argument names if B['block']== 'function' | 'subroutine' + B['result'] --- name of the return value (only if B['block']=='function') + B['implicit'] --- dictionary {'a':,'b':...} | None + B['externals'] --- list of variables being external + B['interfaced'] --- list of variables being external and defined + B['common'] --- dictionary of common blocks (list of objects) + B['commonvars'] --- list of variables used in common blocks (dimensions are moved to variable definitions) + B['from'] --- string showing the 'parents' of the current block + B['use'] --- dictionary of modules used in current block: + {:{['only':<0|1>],['map':{:,...}]}} + B['note'] --- list of LaTeX comments on the block + B['f2pyenhancements'] --- optional dictionary + {'threadsafe':'','fortranname':, + 'callstatement':|, + 'callprotoargument':, + 'usercode':|, + 'pymethoddef:' + } + B['entry'] --- dictionary {entryname:argslist,..} + B['varnames'] --- list of variable names given in the order of reading the + Fortran code, useful for derived types. + B['saved_interface'] --- a string of scanned routine signature, defines explicit interface + *** Variable definition is a dictionary + D = B['vars'][] = + {'typespec'[,'attrspec','kindselector','charselector','=','typename']} + D['typespec'] = 'byte' | 'character' | 'complex' | 'double complex' | + 'double precision' | 'integer' | 'logical' | 'real' | 'type' + D['attrspec'] --- list of attributes (e.g. 'dimension()', + 'external','intent(in|out|inout|hide|c|callback|cache|aligned4|aligned8|aligned16)', + 'optional','required', etc) + K = D['kindselector'] = {['*','kind']} (only if D['typespec'] = + 'complex' | 'integer' | 'logical' | 'real' ) + C = D['charselector'] = {['*','len','kind']} + (only if D['typespec']=='character') + D['='] --- initialization expression string + D['typename'] --- name of the type if D['typespec']=='type' + D['dimension'] --- list of dimension bounds + D['intent'] --- list of intent specifications + D['depend'] --- list of variable names on which current variable depends on + D['check'] --- list of C-expressions; if C-expr returns zero, exception is raised + D['note'] --- list of LaTeX comments on the variable + *** Meaning of kind/char selectors (few examples): + D['typespec>']*K['*'] + D['typespec'](kind=K['kind']) + character*C['*'] + character(len=C['len'],kind=C['kind']) + (see also fortran type declaration statement formats below) + +Fortran 90 type declaration statement format (F77 is subset of F90) +==================================================================== +(Main source: IBM XL Fortran 5.1 Language Reference Manual) +type declaration = [[]::] + = byte | + character[] | + complex[] | + double complex | + double precision | + integer[] | + logical[] | + real[] | + type() + = * | + ([len=][,[kind=]]) | + (kind=[,len=]) + = * | + ([kind=]) + = comma separated list of attributes. + Only the following attributes are used in + building up the interface: + external + (parameter --- affects '=' key) + optional + intent + Other attributes are ignored. + = in | out | inout + = comma separated list of dimension bounds. + = [[*][()] | [()]*] + [// | =] [,] + +In addition, the following attributes are used: check,depend,note + +TODO: + * Apply 'parameter' attribute (e.g. 'integer parameter :: i=2' 'real x(i)' + -> 'real x(2)') + The above may be solved by creating appropriate preprocessor program, for example. + +""" +from __future__ import division, absolute_import, print_function + +import sys +import string +import fileinput +import re +import os +import copy +import platform + +from . import __version__ + +# The eviroment provided by auxfuncs.py is needed for some calls to eval. +# As the needed functions cannot be determined by static inspection of the +# code, it is safest to use import * pending a major refactoring of f2py. +from .auxfuncs import * + + +f2py_version = __version__.version + +# Global flags: +strictf77 = 1 # Ignore `!' comments unless line[0]=='!' +sourcecodeform = 'fix' # 'fix','free' +quiet = 0 # Be verbose if 0 (Obsolete: not used any more) +verbose = 1 # Be quiet if 0, extra verbose if > 1. +tabchar = 4 * ' ' +pyffilename = '' +f77modulename = '' +skipemptyends = 0 # for old F77 programs without 'program' statement +ignorecontains = 1 +dolowercase = 1 +debug = [] + +# Global variables +beginpattern = '' +currentfilename = '' +expectbegin = 1 +f90modulevars = {} +filepositiontext = '' +gotnextfile = 1 +groupcache = None +groupcounter = 0 +grouplist = {groupcounter: []} +groupname = '' +include_paths = [] +neededmodule = -1 +onlyfuncs = [] +previous_context = None +skipblocksuntil = -1 +skipfuncs = [] +skipfunctions = [] +usermodules = [] + + +def reset_global_f2py_vars(): + global groupcounter, grouplist, neededmodule, expectbegin + global skipblocksuntil, usermodules, f90modulevars, gotnextfile + global filepositiontext, currentfilename, skipfunctions, skipfuncs + global onlyfuncs, include_paths, previous_context + global strictf77, sourcecodeform, quiet, verbose, tabchar, pyffilename + global f77modulename, skipemptyends, ignorecontains, dolowercase, debug + + # flags + strictf77 = 1 + sourcecodeform = 'fix' + quiet = 0 + verbose = 1 + tabchar = 4 * ' ' + pyffilename = '' + f77modulename = '' + skipemptyends = 0 + ignorecontains = 1 + dolowercase = 1 + debug = [] + # variables + groupcounter = 0 + grouplist = {groupcounter: []} + neededmodule = -1 + expectbegin = 1 + skipblocksuntil = -1 + usermodules = [] + f90modulevars = {} + gotnextfile = 1 + filepositiontext = '' + currentfilename = '' + skipfunctions = [] + skipfuncs = [] + onlyfuncs = [] + include_paths = [] + previous_context = None + + +def outmess(line, flag=1): + global filepositiontext + + if not verbose: + return + if not quiet: + if flag: + sys.stdout.write(filepositiontext) + sys.stdout.write(line) + +re._MAXCACHE = 50 +defaultimplicitrules = {} +for c in "abcdefghopqrstuvwxyz$_": + defaultimplicitrules[c] = {'typespec': 'real'} +for c in "ijklmn": + defaultimplicitrules[c] = {'typespec': 'integer'} +del c +badnames = {} +invbadnames = {} +for n in ['int', 'double', 'float', 'char', 'short', 'long', 'void', 'case', 'while', + 'return', 'signed', 'unsigned', 'if', 'for', 'typedef', 'sizeof', 'union', + 'struct', 'static', 'register', 'new', 'break', 'do', 'goto', 'switch', + 'continue', 'else', 'inline', 'extern', 'delete', 'const', 'auto', + 'len', 'rank', 'shape', 'index', 'slen', 'size', '_i', + 'max', 'min', + 'flen', 'fshape', + 'string', 'complex_double', 'float_double', 'stdin', 'stderr', 'stdout', + 'type', 'default']: + badnames[n] = n + '_bn' + invbadnames[n + '_bn'] = n + + +def rmbadname1(name): + if name in badnames: + errmess('rmbadname1: Replacing "%s" with "%s".\n' % + (name, badnames[name])) + return badnames[name] + return name + + +def rmbadname(names): + return [rmbadname1(_m) for _m in names] + + +def undo_rmbadname1(name): + if name in invbadnames: + errmess('undo_rmbadname1: Replacing "%s" with "%s".\n' + % (name, invbadnames[name])) + return invbadnames[name] + return name + + +def undo_rmbadname(names): + return [undo_rmbadname1(_m) for _m in names] + + +def getextension(name): + i = name.rfind('.') + if i == -1: + return '' + if '\\' in name[i:]: + return '' + if '/' in name[i:]: + return '' + return name[i + 1:] + +is_f_file = re.compile(r'.*[.](for|ftn|f77|f)\Z', re.I).match +_has_f_header = re.compile(r'-[*]-\s*fortran\s*-[*]-', re.I).search +_has_f90_header = re.compile(r'-[*]-\s*f90\s*-[*]-', re.I).search +_has_fix_header = re.compile(r'-[*]-\s*fix\s*-[*]-', re.I).search +_free_f90_start = re.compile(r'[^c*]\s*[^\s\d\t]', re.I).match + + +def is_free_format(file): + """Check if file is in free format Fortran.""" + # f90 allows both fixed and free format, assuming fixed unless + # signs of free format are detected. + result = 0 + with open(file, 'r') as f: + line = f.readline() + n = 15 # the number of non-comment lines to scan for hints + if _has_f_header(line): + n = 0 + elif _has_f90_header(line): + n = 0 + result = 1 + while n > 0 and line: + if line[0] != '!' and line.strip(): + n -= 1 + if (line[0] != '\t' and _free_f90_start(line[:5])) or line[-2:-1] == '&': + result = 1 + break + line = f.readline() + return result + + +# Read fortran (77,90) code +def readfortrancode(ffile, dowithline=show, istop=1): + """ + Read fortran codes from files and + 1) Get rid of comments, line continuations, and empty lines; lower cases. + 2) Call dowithline(line) on every line. + 3) Recursively call itself when statement \"include ''\" is met. + """ + global gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77 + global beginpattern, quiet, verbose, dolowercase, include_paths + + if not istop: + saveglobals = gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\ + beginpattern, quiet, verbose, dolowercase + if ffile == []: + return + localdolowercase = dolowercase + cont = 0 + finalline = '' + ll = '' + commentline = re.compile( + r'(?P([^"]*["][^"]*["][^"!]*|[^\']*\'[^\']*\'[^\'!]*|[^!\'"]*))!{1}(?P.*)') + includeline = re.compile( + r'\s*include\s*(\'|")(?P[^\'"]*)(\'|")', re.I) + cont1 = re.compile(r'(?P.*)&\s*\Z') + cont2 = re.compile(r'(\s*&|)(?P.*)') + mline_mark = re.compile(r".*?'''") + if istop: + dowithline('', -1) + ll, l1 = '', '' + spacedigits = [' '] + [str(_m) for _m in range(10)] + filepositiontext = '' + fin = fileinput.FileInput(ffile) + while True: + l = fin.readline() + if not l: + break + if fin.isfirstline(): + filepositiontext = '' + currentfilename = fin.filename() + gotnextfile = 1 + l1 = l + strictf77 = 0 + sourcecodeform = 'fix' + ext = os.path.splitext(currentfilename)[1] + if is_f_file(currentfilename) and \ + not (_has_f90_header(l) or _has_fix_header(l)): + strictf77 = 1 + elif is_free_format(currentfilename) and not _has_fix_header(l): + sourcecodeform = 'free' + if strictf77: + beginpattern = beginpattern77 + else: + beginpattern = beginpattern90 + outmess('\tReading file %s (format:%s%s)\n' + % (repr(currentfilename), sourcecodeform, + strictf77 and ',strict' or '')) + + l = l.expandtabs().replace('\xa0', ' ') + # Get rid of newline characters + while not l == '': + if l[-1] not in "\n\r\f": + break + l = l[:-1] + if not strictf77: + r = commentline.match(l) + if r: + l = r.group('line') + ' ' # Strip comments starting with `!' + rl = r.group('rest') + if rl[:4].lower() == 'f2py': # f2py directive + l = l + 4 * ' ' + r = commentline.match(rl[4:]) + if r: + l = l + r.group('line') + else: + l = l + rl[4:] + if l.strip() == '': # Skip empty line + cont = 0 + continue + if sourcecodeform == 'fix': + if l[0] in ['*', 'c', '!', 'C', '#']: + if l[1:5].lower() == 'f2py': # f2py directive + l = ' ' + l[5:] + else: # Skip comment line + cont = 0 + continue + elif strictf77: + if len(l) > 72: + l = l[:72] + if not (l[0] in spacedigits): + raise Exception('readfortrancode: Found non-(space,digit) char ' + 'in the first column.\n\tAre you sure that ' + 'this code is in fix form?\n\tline=%s' % repr(l)) + + if (not cont or strictf77) and (len(l) > 5 and not l[5] == ' '): + # Continuation of a previous line + ll = ll + l[6:] + finalline = '' + origfinalline = '' + else: + if not strictf77: + # F90 continuation + r = cont1.match(l) + if r: + l = r.group('line') # Continuation follows .. + if cont: + ll = ll + cont2.match(l).group('line') + finalline = '' + origfinalline = '' + else: + # clean up line beginning from possible digits. + l = ' ' + l[5:] + if localdolowercase: + finalline = ll.lower() + else: + finalline = ll + origfinalline = ll + ll = l + cont = (r is not None) + else: + # clean up line beginning from possible digits. + l = ' ' + l[5:] + if localdolowercase: + finalline = ll.lower() + else: + finalline = ll + origfinalline = ll + ll = l + + elif sourcecodeform == 'free': + if not cont and ext == '.pyf' and mline_mark.match(l): + l = l + '\n' + while True: + lc = fin.readline() + if not lc: + errmess( + 'Unexpected end of file when reading multiline\n') + break + l = l + lc + if mline_mark.match(lc): + break + l = l.rstrip() + r = cont1.match(l) + if r: + l = r.group('line') # Continuation follows .. + if cont: + ll = ll + cont2.match(l).group('line') + finalline = '' + origfinalline = '' + else: + if localdolowercase: + finalline = ll.lower() + else: + finalline = ll + origfinalline = ll + ll = l + cont = (r is not None) + else: + raise ValueError( + "Flag sourcecodeform must be either 'fix' or 'free': %s" % repr(sourcecodeform)) + filepositiontext = 'Line #%d in %s:"%s"\n\t' % ( + fin.filelineno() - 1, currentfilename, l1) + m = includeline.match(origfinalline) + if m: + fn = m.group('name') + if os.path.isfile(fn): + readfortrancode(fn, dowithline=dowithline, istop=0) + else: + include_dirs = [ + os.path.dirname(currentfilename)] + include_paths + foundfile = 0 + for inc_dir in include_dirs: + fn1 = os.path.join(inc_dir, fn) + if os.path.isfile(fn1): + foundfile = 1 + readfortrancode(fn1, dowithline=dowithline, istop=0) + break + if not foundfile: + outmess('readfortrancode: could not find include file %s in %s. Ignoring.\n' % ( + repr(fn), os.pathsep.join(include_dirs))) + else: + dowithline(finalline) + l1 = ll + if localdolowercase: + finalline = ll.lower() + else: + finalline = ll + origfinalline = ll + filepositiontext = 'Line #%d in %s:"%s"\n\t' % ( + fin.filelineno() - 1, currentfilename, l1) + m = includeline.match(origfinalline) + if m: + fn = m.group('name') + if os.path.isfile(fn): + readfortrancode(fn, dowithline=dowithline, istop=0) + else: + include_dirs = [os.path.dirname(currentfilename)] + include_paths + foundfile = 0 + for inc_dir in include_dirs: + fn1 = os.path.join(inc_dir, fn) + if os.path.isfile(fn1): + foundfile = 1 + readfortrancode(fn1, dowithline=dowithline, istop=0) + break + if not foundfile: + outmess('readfortrancode: could not find include file %s in %s. Ignoring.\n' % ( + repr(fn), os.pathsep.join(include_dirs))) + else: + dowithline(finalline) + filepositiontext = '' + fin.close() + if istop: + dowithline('', 1) + else: + gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\ + beginpattern, quiet, verbose, dolowercase = saveglobals + +# Crack line +beforethisafter = r'\s*(?P%s(?=\s*(\b(%s)\b)))' + \ + r'\s*(?P(\b(%s)\b))' + \ + r'\s*(?P%s)\s*\Z' +## +fortrantypes = r'character|logical|integer|real|complex|double\s*(precision\s*(complex|)|complex)|type(?=\s*\([\w\s,=(*)]*\))|byte' +typespattern = re.compile( + beforethisafter % ('', fortrantypes, fortrantypes, '.*'), re.I), 'type' +typespattern4implicit = re.compile(beforethisafter % ( + '', fortrantypes + '|static|automatic|undefined', fortrantypes + '|static|automatic|undefined', '.*'), re.I) +# +functionpattern = re.compile(beforethisafter % ( + r'([a-z]+[\w\s(=*+-/)]*?|)', 'function', 'function', '.*'), re.I), 'begin' +subroutinepattern = re.compile(beforethisafter % ( + r'[a-z\s]*?', 'subroutine', 'subroutine', '.*'), re.I), 'begin' +# modulepattern=re.compile(beforethisafter%('[a-z\s]*?','module','module','.*'),re.I),'begin' +# +groupbegins77 = r'program|block\s*data' +beginpattern77 = re.compile( + beforethisafter % ('', groupbegins77, groupbegins77, '.*'), re.I), 'begin' +groupbegins90 = groupbegins77 + \ + r'|module(?!\s*procedure)|python\s*module|interface|type(?!\s*\()' +beginpattern90 = re.compile( + beforethisafter % ('', groupbegins90, groupbegins90, '.*'), re.I), 'begin' +groupends = r'end|endprogram|endblockdata|endmodule|endpythonmodule|endinterface' +endpattern = re.compile( + beforethisafter % ('', groupends, groupends, r'[\w\s]*'), re.I), 'end' +# endifs='end\s*(if|do|where|select|while|forall)' +endifs = r'(end\s*(if|do|where|select|while|forall))|(module\s*procedure)' +endifpattern = re.compile( + beforethisafter % (r'[\w]*?', endifs, endifs, r'[\w\s]*'), re.I), 'endif' +# +implicitpattern = re.compile( + beforethisafter % ('', 'implicit', 'implicit', '.*'), re.I), 'implicit' +dimensionpattern = re.compile(beforethisafter % ( + '', 'dimension|virtual', 'dimension|virtual', '.*'), re.I), 'dimension' +externalpattern = re.compile( + beforethisafter % ('', 'external', 'external', '.*'), re.I), 'external' +optionalpattern = re.compile( + beforethisafter % ('', 'optional', 'optional', '.*'), re.I), 'optional' +requiredpattern = re.compile( + beforethisafter % ('', 'required', 'required', '.*'), re.I), 'required' +publicpattern = re.compile( + beforethisafter % ('', 'public', 'public', '.*'), re.I), 'public' +privatepattern = re.compile( + beforethisafter % ('', 'private', 'private', '.*'), re.I), 'private' +intrisicpattern = re.compile( + beforethisafter % ('', 'intrisic', 'intrisic', '.*'), re.I), 'intrisic' +intentpattern = re.compile(beforethisafter % ( + '', 'intent|depend|note|check', 'intent|depend|note|check', r'\s*\(.*?\).*'), re.I), 'intent' +parameterpattern = re.compile( + beforethisafter % ('', 'parameter', 'parameter', r'\s*\(.*'), re.I), 'parameter' +datapattern = re.compile( + beforethisafter % ('', 'data', 'data', '.*'), re.I), 'data' +callpattern = re.compile( + beforethisafter % ('', 'call', 'call', '.*'), re.I), 'call' +entrypattern = re.compile( + beforethisafter % ('', 'entry', 'entry', '.*'), re.I), 'entry' +callfunpattern = re.compile( + beforethisafter % ('', 'callfun', 'callfun', '.*'), re.I), 'callfun' +commonpattern = re.compile( + beforethisafter % ('', 'common', 'common', '.*'), re.I), 'common' +usepattern = re.compile( + beforethisafter % ('', 'use', 'use', '.*'), re.I), 'use' +containspattern = re.compile( + beforethisafter % ('', 'contains', 'contains', ''), re.I), 'contains' +formatpattern = re.compile( + beforethisafter % ('', 'format', 'format', '.*'), re.I), 'format' +# Non-fortran and f2py-specific statements +f2pyenhancementspattern = re.compile(beforethisafter % ('', 'threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef', + 'threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef', '.*'), re.I | re.S), 'f2pyenhancements' +multilinepattern = re.compile( + r"\s*(?P''')(?P.*?)(?P''')\s*\Z", re.S), 'multiline' +## + + +def _simplifyargs(argsline): + a = [] + for n in markoutercomma(argsline).split('@,@'): + for r in '(),': + n = n.replace(r, '_') + a.append(n) + return ','.join(a) + +crackline_re_1 = re.compile(r'\s*(?P\b[a-z]+[\w]*\b)\s*[=].*', re.I) + + +def crackline(line, reset=0): + """ + reset=-1 --- initialize + reset=0 --- crack the line + reset=1 --- final check if mismatch of blocks occurred + + Cracked data is saved in grouplist[0]. + """ + global beginpattern, groupcounter, groupname, groupcache, grouplist + global filepositiontext, currentfilename, neededmodule, expectbegin + global skipblocksuntil, skipemptyends, previous_context, gotnextfile + + if ';' in line and not (f2pyenhancementspattern[0].match(line) or + multilinepattern[0].match(line)): + for l in line.split(';'): + # XXX: non-zero reset values need testing + assert reset == 0, repr(reset) + crackline(l, reset) + return + if reset < 0: + groupcounter = 0 + groupname = {groupcounter: ''} + groupcache = {groupcounter: {}} + grouplist = {groupcounter: []} + groupcache[groupcounter]['body'] = [] + groupcache[groupcounter]['vars'] = {} + groupcache[groupcounter]['block'] = '' + groupcache[groupcounter]['name'] = '' + neededmodule = -1 + skipblocksuntil = -1 + return + if reset > 0: + fl = 0 + if f77modulename and neededmodule == groupcounter: + fl = 2 + while groupcounter > fl: + outmess('crackline: groupcounter=%s groupname=%s\n' % + (repr(groupcounter), repr(groupname))) + outmess( + 'crackline: Mismatch of blocks encountered. Trying to fix it by assuming "end" statement.\n') + grouplist[groupcounter - 1].append(groupcache[groupcounter]) + grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter = groupcounter - 1 + if f77modulename and neededmodule == groupcounter: + grouplist[groupcounter - 1].append(groupcache[groupcounter]) + grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter = groupcounter - 1 # end interface + grouplist[groupcounter - 1].append(groupcache[groupcounter]) + grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter = groupcounter - 1 # end module + neededmodule = -1 + return + if line == '': + return + flag = 0 + for pat in [dimensionpattern, externalpattern, intentpattern, optionalpattern, + requiredpattern, + parameterpattern, datapattern, publicpattern, privatepattern, + intrisicpattern, + endifpattern, endpattern, + formatpattern, + beginpattern, functionpattern, subroutinepattern, + implicitpattern, typespattern, commonpattern, + callpattern, usepattern, containspattern, + entrypattern, + f2pyenhancementspattern, + multilinepattern + ]: + m = pat[0].match(line) + if m: + break + flag = flag + 1 + if not m: + re_1 = crackline_re_1 + if 0 <= skipblocksuntil <= groupcounter: + return + if 'externals' in groupcache[groupcounter]: + for name in groupcache[groupcounter]['externals']: + if name in invbadnames: + name = invbadnames[name] + if 'interfaced' in groupcache[groupcounter] and name in groupcache[groupcounter]['interfaced']: + continue + m1 = re.match( + r'(?P[^"]*)\b%s\b\s*@\(@(?P[^@]*)@\)@.*\Z' % name, markouterparen(line), re.I) + if m1: + m2 = re_1.match(m1.group('before')) + a = _simplifyargs(m1.group('args')) + if m2: + line = 'callfun %s(%s) result (%s)' % ( + name, a, m2.group('result')) + else: + line = 'callfun %s(%s)' % (name, a) + m = callfunpattern[0].match(line) + if not m: + outmess( + 'crackline: could not resolve function call for line=%s.\n' % repr(line)) + return + analyzeline(m, 'callfun', line) + return + if verbose > 1 or (verbose == 1 and currentfilename.lower().endswith('.pyf')): + previous_context = None + outmess('crackline:%d: No pattern for line\n' % (groupcounter)) + return + elif pat[1] == 'end': + if 0 <= skipblocksuntil < groupcounter: + groupcounter = groupcounter - 1 + if skipblocksuntil <= groupcounter: + return + if groupcounter <= 0: + raise Exception('crackline: groupcounter(=%s) is nonpositive. ' + 'Check the blocks.' + % (groupcounter)) + m1 = beginpattern[0].match((line)) + if (m1) and (not m1.group('this') == groupname[groupcounter]): + raise Exception('crackline: End group %s does not match with ' + 'previous Begin group %s\n\t%s' % + (repr(m1.group('this')), repr(groupname[groupcounter]), + filepositiontext) + ) + if skipblocksuntil == groupcounter: + skipblocksuntil = -1 + grouplist[groupcounter - 1].append(groupcache[groupcounter]) + grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter = groupcounter - 1 + if not skipemptyends: + expectbegin = 1 + elif pat[1] == 'begin': + if 0 <= skipblocksuntil <= groupcounter: + groupcounter = groupcounter + 1 + return + gotnextfile = 0 + analyzeline(m, pat[1], line) + expectbegin = 0 + elif pat[1] == 'endif': + pass + elif pat[1] == 'contains': + if ignorecontains: + return + if 0 <= skipblocksuntil <= groupcounter: + return + skipblocksuntil = groupcounter + else: + if 0 <= skipblocksuntil <= groupcounter: + return + analyzeline(m, pat[1], line) + + +def markouterparen(line): + l = '' + f = 0 + for c in line: + if c == '(': + f = f + 1 + if f == 1: + l = l + '@(@' + continue + elif c == ')': + f = f - 1 + if f == 0: + l = l + '@)@' + continue + l = l + c + return l + + +def markoutercomma(line, comma=','): + l = '' + f = 0 + cc = '' + for c in line: + if (not cc or cc == ')') and c == '(': + f = f + 1 + cc = ')' + elif not cc and c == '\'' and (not l or l[-1] != '\\'): + f = f + 1 + cc = '\'' + elif c == cc: + f = f - 1 + if f == 0: + cc = '' + elif c == comma and f == 0: + l = l + '@' + comma + '@' + continue + l = l + c + assert not f, repr((f, line, l, cc)) + return l + + +def unmarkouterparen(line): + r = line.replace('@(@', '(').replace('@)@', ')') + return r + + +def appenddecl(decl, decl2, force=1): + if not decl: + decl = {} + if not decl2: + return decl + if decl is decl2: + return decl + for k in list(decl2.keys()): + if k == 'typespec': + if force or k not in decl: + decl[k] = decl2[k] + elif k == 'attrspec': + for l in decl2[k]: + decl = setattrspec(decl, l, force) + elif k == 'kindselector': + decl = setkindselector(decl, decl2[k], force) + elif k == 'charselector': + decl = setcharselector(decl, decl2[k], force) + elif k in ['=', 'typename']: + if force or k not in decl: + decl[k] = decl2[k] + elif k == 'note': + pass + elif k in ['intent', 'check', 'dimension', 'optional', 'required']: + errmess('appenddecl: "%s" not implemented.\n' % k) + else: + raise Exception('appenddecl: Unknown variable definition key:' + + str(k)) + return decl + +selectpattern = re.compile( + r'\s*(?P(@\(@.*?@\)@|[*][\d*]+|[*]\s*@\(@.*?@\)@|))(?P.*)\Z', re.I) +nameargspattern = re.compile( + r'\s*(?P\b[\w$]+\b)\s*(@\(@\s*(?P[\w\s,]*)\s*@\)@|)\s*((result(\s*@\(@\s*(?P\b[\w$]+\b)\s*@\)@|))|(bind\s*@\(@\s*(?P.*)\s*@\)@))*\s*\Z', re.I) +callnameargspattern = re.compile( + r'\s*(?P\b[\w$]+\b)\s*@\(@\s*(?P.*)\s*@\)@\s*\Z', re.I) +real16pattern = re.compile( + r'([-+]?(?:\d+(?:\.\d*)?|\d*\.\d+))[dD]((?:[-+]?\d+)?)') +real8pattern = re.compile( + r'([-+]?((?:\d+(?:\.\d*)?|\d*\.\d+))[eE]((?:[-+]?\d+)?)|(\d+\.\d*))') + +_intentcallbackpattern = re.compile(r'intent\s*\(.*?\bcallback\b', re.I) + + +def _is_intent_callback(vdecl): + for a in vdecl.get('attrspec', []): + if _intentcallbackpattern.match(a): + return 1 + return 0 + + +def _resolvenameargspattern(line): + line = markouterparen(line) + m1 = nameargspattern.match(line) + if m1: + return m1.group('name'), m1.group('args'), m1.group('result'), m1.group('bind') + m1 = callnameargspattern.match(line) + if m1: + return m1.group('name'), m1.group('args'), None, None + return None, [], None, None + + +def analyzeline(m, case, line): + global groupcounter, groupname, groupcache, grouplist, filepositiontext + global currentfilename, f77modulename, neededinterface, neededmodule + global expectbegin, gotnextfile, previous_context + + block = m.group('this') + if case != 'multiline': + previous_context = None + if expectbegin and case not in ['begin', 'call', 'callfun', 'type'] \ + and not skipemptyends and groupcounter < 1: + newname = os.path.basename(currentfilename).split('.')[0] + outmess( + 'analyzeline: no group yet. Creating program group with name "%s".\n' % newname) + gotnextfile = 0 + groupcounter = groupcounter + 1 + groupname[groupcounter] = 'program' + groupcache[groupcounter] = {} + grouplist[groupcounter] = [] + groupcache[groupcounter]['body'] = [] + groupcache[groupcounter]['vars'] = {} + groupcache[groupcounter]['block'] = 'program' + groupcache[groupcounter]['name'] = newname + groupcache[groupcounter]['from'] = 'fromsky' + expectbegin = 0 + if case in ['begin', 'call', 'callfun']: + # Crack line => block,name,args,result + block = block.lower() + if re.match(r'block\s*data', block, re.I): + block = 'block data' + if re.match(r'python\s*module', block, re.I): + block = 'python module' + name, args, result, bind = _resolvenameargspattern(m.group('after')) + if name is None: + if block == 'block data': + name = '_BLOCK_DATA_' + else: + name = '' + if block not in ['interface', 'block data']: + outmess('analyzeline: No name/args pattern found for line.\n') + + previous_context = (block, name, groupcounter) + if args: + args = rmbadname([x.strip() + for x in markoutercomma(args).split('@,@')]) + else: + args = [] + if '' in args: + while '' in args: + args.remove('') + outmess( + 'analyzeline: argument list is malformed (missing argument).\n') + + # end of crack line => block,name,args,result + needmodule = 0 + needinterface = 0 + + if case in ['call', 'callfun']: + needinterface = 1 + if 'args' not in groupcache[groupcounter]: + return + if name not in groupcache[groupcounter]['args']: + return + for it in grouplist[groupcounter]: + if it['name'] == name: + return + if name in groupcache[groupcounter]['interfaced']: + return + block = {'call': 'subroutine', 'callfun': 'function'}[case] + if f77modulename and neededmodule == -1 and groupcounter <= 1: + neededmodule = groupcounter + 2 + needmodule = 1 + if block != 'interface': + needinterface = 1 + # Create new block(s) + groupcounter = groupcounter + 1 + groupcache[groupcounter] = {} + grouplist[groupcounter] = [] + if needmodule: + if verbose > 1: + outmess('analyzeline: Creating module block %s\n' % + repr(f77modulename), 0) + groupname[groupcounter] = 'module' + groupcache[groupcounter]['block'] = 'python module' + groupcache[groupcounter]['name'] = f77modulename + groupcache[groupcounter]['from'] = '' + groupcache[groupcounter]['body'] = [] + groupcache[groupcounter]['externals'] = [] + groupcache[groupcounter]['interfaced'] = [] + groupcache[groupcounter]['vars'] = {} + groupcounter = groupcounter + 1 + groupcache[groupcounter] = {} + grouplist[groupcounter] = [] + if needinterface: + if verbose > 1: + outmess('analyzeline: Creating additional interface block (groupcounter=%s).\n' % ( + groupcounter), 0) + groupname[groupcounter] = 'interface' + groupcache[groupcounter]['block'] = 'interface' + groupcache[groupcounter]['name'] = 'unknown_interface' + groupcache[groupcounter]['from'] = '%s:%s' % ( + groupcache[groupcounter - 1]['from'], groupcache[groupcounter - 1]['name']) + groupcache[groupcounter]['body'] = [] + groupcache[groupcounter]['externals'] = [] + groupcache[groupcounter]['interfaced'] = [] + groupcache[groupcounter]['vars'] = {} + groupcounter = groupcounter + 1 + groupcache[groupcounter] = {} + grouplist[groupcounter] = [] + groupname[groupcounter] = block + groupcache[groupcounter]['block'] = block + if not name: + name = 'unknown_' + block + groupcache[groupcounter]['prefix'] = m.group('before') + groupcache[groupcounter]['name'] = rmbadname1(name) + groupcache[groupcounter]['result'] = result + if groupcounter == 1: + groupcache[groupcounter]['from'] = currentfilename + else: + if f77modulename and groupcounter == 3: + groupcache[groupcounter]['from'] = '%s:%s' % ( + groupcache[groupcounter - 1]['from'], currentfilename) + else: + groupcache[groupcounter]['from'] = '%s:%s' % ( + groupcache[groupcounter - 1]['from'], groupcache[groupcounter - 1]['name']) + for k in list(groupcache[groupcounter].keys()): + if not groupcache[groupcounter][k]: + del groupcache[groupcounter][k] + + groupcache[groupcounter]['args'] = args + groupcache[groupcounter]['body'] = [] + groupcache[groupcounter]['externals'] = [] + groupcache[groupcounter]['interfaced'] = [] + groupcache[groupcounter]['vars'] = {} + groupcache[groupcounter]['entry'] = {} + # end of creation + if block == 'type': + groupcache[groupcounter]['varnames'] = [] + + if case in ['call', 'callfun']: # set parents variables + if name not in groupcache[groupcounter - 2]['externals']: + groupcache[groupcounter - 2]['externals'].append(name) + groupcache[groupcounter]['vars'] = copy.deepcopy( + groupcache[groupcounter - 2]['vars']) + try: + del groupcache[groupcounter]['vars'][name][ + groupcache[groupcounter]['vars'][name]['attrspec'].index('external')] + except Exception: + pass + if block in ['function', 'subroutine']: # set global attributes + try: + groupcache[groupcounter]['vars'][name] = appenddecl( + groupcache[groupcounter]['vars'][name], groupcache[groupcounter - 2]['vars']['']) + except Exception: + pass + if case == 'callfun': # return type + if result and result in groupcache[groupcounter]['vars']: + if not name == result: + groupcache[groupcounter]['vars'][name] = appenddecl( + groupcache[groupcounter]['vars'][name], groupcache[groupcounter]['vars'][result]) + # if groupcounter>1: # name is interfaced + try: + groupcache[groupcounter - 2]['interfaced'].append(name) + except Exception: + pass + if block == 'function': + t = typespattern[0].match(m.group('before') + ' ' + name) + if t: + typespec, selector, attr, edecl = cracktypespec0( + t.group('this'), t.group('after')) + updatevars(typespec, selector, attr, edecl) + + if case in ['call', 'callfun']: + grouplist[groupcounter - 1].append(groupcache[groupcounter]) + grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter = groupcounter - 1 # end routine + grouplist[groupcounter - 1].append(groupcache[groupcounter]) + grouplist[groupcounter - 1][-1]['body'] = grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter = groupcounter - 1 # end interface + + elif case == 'entry': + name, args, result, bind = _resolvenameargspattern(m.group('after')) + if name is not None: + if args: + args = rmbadname([x.strip() + for x in markoutercomma(args).split('@,@')]) + else: + args = [] + assert result is None, repr(result) + groupcache[groupcounter]['entry'][name] = args + previous_context = ('entry', name, groupcounter) + elif case == 'type': + typespec, selector, attr, edecl = cracktypespec0( + block, m.group('after')) + last_name = updatevars(typespec, selector, attr, edecl) + if last_name is not None: + previous_context = ('variable', last_name, groupcounter) + elif case in ['dimension', 'intent', 'optional', 'required', 'external', 'public', 'private', 'intrisic']: + edecl = groupcache[groupcounter]['vars'] + ll = m.group('after').strip() + i = ll.find('::') + if i < 0 and case == 'intent': + i = markouterparen(ll).find('@)@') - 2 + ll = ll[:i + 1] + '::' + ll[i + 1:] + i = ll.find('::') + if ll[i:] == '::' and 'args' in groupcache[groupcounter]: + outmess('All arguments will have attribute %s%s\n' % + (m.group('this'), ll[:i])) + ll = ll + ','.join(groupcache[groupcounter]['args']) + if i < 0: + i = 0 + pl = '' + else: + pl = ll[:i].strip() + ll = ll[i + 2:] + ch = markoutercomma(pl).split('@,@') + if len(ch) > 1: + pl = ch[0] + outmess('analyzeline: cannot handle multiple attributes without type specification. Ignoring %r.\n' % ( + ','.join(ch[1:]))) + last_name = None + + for e in [x.strip() for x in markoutercomma(ll).split('@,@')]: + m1 = namepattern.match(e) + if not m1: + if case in ['public', 'private']: + k = '' + else: + print(m.groupdict()) + outmess('analyzeline: no name pattern found in %s statement for %s. Skipping.\n' % ( + case, repr(e))) + continue + else: + k = rmbadname1(m1.group('name')) + if k not in edecl: + edecl[k] = {} + if case == 'dimension': + ap = case + m1.group('after') + if case == 'intent': + ap = m.group('this') + pl + if _intentcallbackpattern.match(ap): + if k not in groupcache[groupcounter]['args']: + if groupcounter > 1: + if '__user__' not in groupcache[groupcounter - 2]['name']: + outmess( + 'analyzeline: missing __user__ module (could be nothing)\n') + # fixes ticket 1693 + if k != groupcache[groupcounter]['name']: + outmess('analyzeline: appending intent(callback) %s' + ' to %s arguments\n' % (k, groupcache[groupcounter]['name'])) + groupcache[groupcounter]['args'].append(k) + else: + errmess( + 'analyzeline: intent(callback) %s is ignored' % (k)) + else: + errmess('analyzeline: intent(callback) %s is already' + ' in argument list' % (k)) + if case in ['optional', 'required', 'public', 'external', 'private', 'intrisic']: + ap = case + if 'attrspec' in edecl[k]: + edecl[k]['attrspec'].append(ap) + else: + edecl[k]['attrspec'] = [ap] + if case == 'external': + if groupcache[groupcounter]['block'] == 'program': + outmess('analyzeline: ignoring program arguments\n') + continue + if k not in groupcache[groupcounter]['args']: + continue + if 'externals' not in groupcache[groupcounter]: + groupcache[groupcounter]['externals'] = [] + groupcache[groupcounter]['externals'].append(k) + last_name = k + groupcache[groupcounter]['vars'] = edecl + if last_name is not None: + previous_context = ('variable', last_name, groupcounter) + elif case == 'parameter': + edecl = groupcache[groupcounter]['vars'] + ll = m.group('after').strip()[1:-1] + last_name = None + for e in markoutercomma(ll).split('@,@'): + try: + k, initexpr = [x.strip() for x in e.split('=')] + except Exception: + outmess( + 'analyzeline: could not extract name,expr in parameter statement "%s" of "%s"\n' % (e, ll)) + continue + params = get_parameters(edecl) + k = rmbadname1(k) + if k not in edecl: + edecl[k] = {} + if '=' in edecl[k] and (not edecl[k]['='] == initexpr): + outmess('analyzeline: Overwriting the value of parameter "%s" ("%s") with "%s".\n' % ( + k, edecl[k]['='], initexpr)) + t = determineexprtype(initexpr, params) + if t: + if t.get('typespec') == 'real': + tt = list(initexpr) + for m in real16pattern.finditer(initexpr): + tt[m.start():m.end()] = list( + initexpr[m.start():m.end()].lower().replace('d', 'e')) + initexpr = ''.join(tt) + elif t.get('typespec') == 'complex': + initexpr = initexpr[1:].lower().replace('d', 'e').\ + replace(',', '+1j*(') + try: + v = eval(initexpr, {}, params) + except (SyntaxError, NameError, TypeError) as msg: + errmess('analyzeline: Failed to evaluate %r. Ignoring: %s\n' + % (initexpr, msg)) + continue + edecl[k]['='] = repr(v) + if 'attrspec' in edecl[k]: + edecl[k]['attrspec'].append('parameter') + else: + edecl[k]['attrspec'] = ['parameter'] + last_name = k + groupcache[groupcounter]['vars'] = edecl + if last_name is not None: + previous_context = ('variable', last_name, groupcounter) + elif case == 'implicit': + if m.group('after').strip().lower() == 'none': + groupcache[groupcounter]['implicit'] = None + elif m.group('after'): + if 'implicit' in groupcache[groupcounter]: + impl = groupcache[groupcounter]['implicit'] + else: + impl = {} + if impl is None: + outmess( + 'analyzeline: Overwriting earlier "implicit none" statement.\n') + impl = {} + for e in markoutercomma(m.group('after')).split('@,@'): + decl = {} + m1 = re.match( + r'\s*(?P.*?)\s*(\(\s*(?P[a-z-, ]+)\s*\)\s*|)\Z', e, re.I) + if not m1: + outmess( + 'analyzeline: could not extract info of implicit statement part "%s"\n' % (e)) + continue + m2 = typespattern4implicit.match(m1.group('this')) + if not m2: + outmess( + 'analyzeline: could not extract types pattern of implicit statement part "%s"\n' % (e)) + continue + typespec, selector, attr, edecl = cracktypespec0( + m2.group('this'), m2.group('after')) + kindselect, charselect, typename = cracktypespec( + typespec, selector) + decl['typespec'] = typespec + decl['kindselector'] = kindselect + decl['charselector'] = charselect + decl['typename'] = typename + for k in list(decl.keys()): + if not decl[k]: + del decl[k] + for r in markoutercomma(m1.group('after')).split('@,@'): + if '-' in r: + try: + begc, endc = [x.strip() for x in r.split('-')] + except Exception: + outmess( + 'analyzeline: expected "-" instead of "%s" in range list of implicit statement\n' % r) + continue + else: + begc = endc = r.strip() + if not len(begc) == len(endc) == 1: + outmess( + 'analyzeline: expected "-" instead of "%s" in range list of implicit statement (2)\n' % r) + continue + for o in range(ord(begc), ord(endc) + 1): + impl[chr(o)] = decl + groupcache[groupcounter]['implicit'] = impl + elif case == 'data': + ll = [] + dl = '' + il = '' + f = 0 + fc = 1 + inp = 0 + for c in m.group('after'): + if not inp: + if c == "'": + fc = not fc + if c == '/' and fc: + f = f + 1 + continue + if c == '(': + inp = inp + 1 + elif c == ')': + inp = inp - 1 + if f == 0: + dl = dl + c + elif f == 1: + il = il + c + elif f == 2: + dl = dl.strip() + if dl.startswith(','): + dl = dl[1:].strip() + ll.append([dl, il]) + dl = c + il = '' + f = 0 + if f == 2: + dl = dl.strip() + if dl.startswith(','): + dl = dl[1:].strip() + ll.append([dl, il]) + vars = {} + if 'vars' in groupcache[groupcounter]: + vars = groupcache[groupcounter]['vars'] + last_name = None + for l in ll: + l = [x.strip() for x in l] + if l[0][0] == ',': + l[0] = l[0][1:] + if l[0][0] == '(': + outmess( + 'analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % l[0]) + continue + i = 0 + j = 0 + llen = len(l[1]) + for v in rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')]): + if v[0] == '(': + outmess( + 'analyzeline: implied-DO list "%s" is not supported. Skipping.\n' % v) + # XXX: subsequent init expressions may get wrong values. + # Ignoring since data statements are irrelevant for + # wrapping. + continue + fc = 0 + while (i < llen) and (fc or not l[1][i] == ','): + if l[1][i] == "'": + fc = not fc + i = i + 1 + i = i + 1 + if v not in vars: + vars[v] = {} + if '=' in vars[v] and not vars[v]['='] == l[1][j:i - 1]: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n' % ( + v, vars[v]['='], l[1][j:i - 1])) + vars[v]['='] = l[1][j:i - 1] + j = i + last_name = v + groupcache[groupcounter]['vars'] = vars + if last_name is not None: + previous_context = ('variable', last_name, groupcounter) + elif case == 'common': + line = m.group('after').strip() + if not line[0] == '/': + line = '//' + line + cl = [] + f = 0 + bn = '' + ol = '' + for c in line: + if c == '/': + f = f + 1 + continue + if f >= 3: + bn = bn.strip() + if not bn: + bn = '_BLNK_' + cl.append([bn, ol]) + f = f - 2 + bn = '' + ol = '' + if f % 2: + bn = bn + c + else: + ol = ol + c + bn = bn.strip() + if not bn: + bn = '_BLNK_' + cl.append([bn, ol]) + commonkey = {} + if 'common' in groupcache[groupcounter]: + commonkey = groupcache[groupcounter]['common'] + for c in cl: + if c[0] not in commonkey: + commonkey[c[0]] = [] + for i in [x.strip() for x in markoutercomma(c[1]).split('@,@')]: + if i: + commonkey[c[0]].append(i) + groupcache[groupcounter]['common'] = commonkey + previous_context = ('common', bn, groupcounter) + elif case == 'use': + m1 = re.match( + r'\A\s*(?P\b[\w]+\b)\s*((,(\s*\bonly\b\s*:|(?P))\s*(?P.*))|)\s*\Z', m.group('after'), re.I) + if m1: + mm = m1.groupdict() + if 'use' not in groupcache[groupcounter]: + groupcache[groupcounter]['use'] = {} + name = m1.group('name') + groupcache[groupcounter]['use'][name] = {} + isonly = 0 + if 'list' in mm and mm['list'] is not None: + if 'notonly' in mm and mm['notonly'] is None: + isonly = 1 + groupcache[groupcounter]['use'][name]['only'] = isonly + ll = [x.strip() for x in mm['list'].split(',')] + rl = {} + for l in ll: + if '=' in l: + m2 = re.match( + r'\A\s*(?P\b[\w]+\b)\s*=\s*>\s*(?P\b[\w]+\b)\s*\Z', l, re.I) + if m2: + rl[m2.group('local').strip()] = m2.group( + 'use').strip() + else: + outmess( + 'analyzeline: Not local=>use pattern found in %s\n' % repr(l)) + else: + rl[l] = l + groupcache[groupcounter]['use'][name]['map'] = rl + else: + pass + else: + print(m.groupdict()) + outmess('analyzeline: Could not crack the use statement.\n') + elif case in ['f2pyenhancements']: + if 'f2pyenhancements' not in groupcache[groupcounter]: + groupcache[groupcounter]['f2pyenhancements'] = {} + d = groupcache[groupcounter]['f2pyenhancements'] + if m.group('this') == 'usercode' and 'usercode' in d: + if isinstance(d['usercode'], str): + d['usercode'] = [d['usercode']] + d['usercode'].append(m.group('after')) + else: + d[m.group('this')] = m.group('after') + elif case == 'multiline': + if previous_context is None: + if verbose: + outmess('analyzeline: No context for multiline block.\n') + return + gc = groupcounter + appendmultiline(groupcache[gc], + previous_context[:2], + m.group('this')) + else: + if verbose > 1: + print(m.groupdict()) + outmess('analyzeline: No code implemented for line.\n') + + +def appendmultiline(group, context_name, ml): + if 'f2pymultilines' not in group: + group['f2pymultilines'] = {} + d = group['f2pymultilines'] + if context_name not in d: + d[context_name] = [] + d[context_name].append(ml) + return + + +def cracktypespec0(typespec, ll): + selector = None + attr = None + if re.match(r'double\s*complex', typespec, re.I): + typespec = 'double complex' + elif re.match(r'double\s*precision', typespec, re.I): + typespec = 'double precision' + else: + typespec = typespec.strip().lower() + m1 = selectpattern.match(markouterparen(ll)) + if not m1: + outmess( + 'cracktypespec0: no kind/char_selector pattern found for line.\n') + return + d = m1.groupdict() + for k in list(d.keys()): + d[k] = unmarkouterparen(d[k]) + if typespec in ['complex', 'integer', 'logical', 'real', 'character', 'type']: + selector = d['this'] + ll = d['after'] + i = ll.find('::') + if i >= 0: + attr = ll[:i].strip() + ll = ll[i + 2:] + return typespec, selector, attr, ll +##### +namepattern = re.compile(r'\s*(?P\b[\w]+\b)\s*(?P.*)\s*\Z', re.I) +kindselector = re.compile( + r'\s*(\(\s*(kind\s*=)?\s*(?P.*)\s*\)|[*]\s*(?P.*?))\s*\Z', re.I) +charselector = re.compile( + r'\s*(\((?P.*)\)|[*]\s*(?P.*))\s*\Z', re.I) +lenkindpattern = re.compile( + r'\s*(kind\s*=\s*(?P.*?)\s*(@,@\s*len\s*=\s*(?P.*)|)|(len\s*=\s*|)(?P.*?)\s*(@,@\s*(kind\s*=\s*|)(?P.*)|))\s*\Z', re.I) +lenarraypattern = re.compile( + r'\s*(@\(@\s*(?!/)\s*(?P.*?)\s*@\)@\s*[*]\s*(?P.*?)|([*]\s*(?P.*?)|)\s*(@\(@\s*(?!/)\s*(?P.*?)\s*@\)@|))\s*(=\s*(?P.*?)|(@\(@|)/\s*(?P.*?)\s*/(@\)@|)|)\s*\Z', re.I) + + +def removespaces(expr): + expr = expr.strip() + if len(expr) <= 1: + return expr + expr2 = expr[0] + for i in range(1, len(expr) - 1): + if (expr[i] == ' ' and + ((expr[i + 1] in "()[]{}=+-/* ") or + (expr[i - 1] in "()[]{}=+-/* "))): + continue + expr2 = expr2 + expr[i] + expr2 = expr2 + expr[-1] + return expr2 + + +def markinnerspaces(line): + l = '' + f = 0 + cc = '\'' + cb = '' + for c in line: + if cb == '\\' and c in ['\\', '\'', '"']: + l = l + c + cb = c + continue + if f == 0 and c in ['\'', '"']: + cc = c + if c == cc: + f = f + 1 + elif c == cc: + f = f - 1 + elif c == ' ' and f == 1: + l = l + '@_@' + continue + l = l + c + cb = c + return l + + +def updatevars(typespec, selector, attrspec, entitydecl): + global groupcache, groupcounter + + last_name = None + kindselect, charselect, typename = cracktypespec(typespec, selector) + if attrspec: + attrspec = [x.strip() for x in markoutercomma(attrspec).split('@,@')] + l = [] + c = re.compile(r'(?P[a-zA-Z]+)') + for a in attrspec: + if not a: + continue + m = c.match(a) + if m: + s = m.group('start').lower() + a = s + a[len(s):] + l.append(a) + attrspec = l + el = [x.strip() for x in markoutercomma(entitydecl).split('@,@')] + el1 = [] + for e in el: + for e1 in [x.strip() for x in markoutercomma(removespaces(markinnerspaces(e)), comma=' ').split('@ @')]: + if e1: + el1.append(e1.replace('@_@', ' ')) + for e in el1: + m = namepattern.match(e) + if not m: + outmess( + 'updatevars: no name pattern found for entity=%s. Skipping.\n' % (repr(e))) + continue + ename = rmbadname1(m.group('name')) + edecl = {} + if ename in groupcache[groupcounter]['vars']: + edecl = groupcache[groupcounter]['vars'][ename].copy() + not_has_typespec = 'typespec' not in edecl + if not_has_typespec: + edecl['typespec'] = typespec + elif typespec and (not typespec == edecl['typespec']): + outmess('updatevars: attempt to change the type of "%s" ("%s") to "%s". Ignoring.\n' % ( + ename, edecl['typespec'], typespec)) + if 'kindselector' not in edecl: + edecl['kindselector'] = copy.copy(kindselect) + elif kindselect: + for k in list(kindselect.keys()): + if k in edecl['kindselector'] and (not kindselect[k] == edecl['kindselector'][k]): + outmess('updatevars: attempt to change the kindselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % ( + k, ename, edecl['kindselector'][k], kindselect[k])) + else: + edecl['kindselector'][k] = copy.copy(kindselect[k]) + if 'charselector' not in edecl and charselect: + if not_has_typespec: + edecl['charselector'] = charselect + else: + errmess('updatevars:%s: attempt to change empty charselector to %r. Ignoring.\n' + % (ename, charselect)) + elif charselect: + for k in list(charselect.keys()): + if k in edecl['charselector'] and (not charselect[k] == edecl['charselector'][k]): + outmess('updatevars: attempt to change the charselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % ( + k, ename, edecl['charselector'][k], charselect[k])) + else: + edecl['charselector'][k] = copy.copy(charselect[k]) + if 'typename' not in edecl: + edecl['typename'] = typename + elif typename and (not edecl['typename'] == typename): + outmess('updatevars: attempt to change the typename of "%s" ("%s") to "%s". Ignoring.\n' % ( + ename, edecl['typename'], typename)) + if 'attrspec' not in edecl: + edecl['attrspec'] = copy.copy(attrspec) + elif attrspec: + for a in attrspec: + if a not in edecl['attrspec']: + edecl['attrspec'].append(a) + else: + edecl['typespec'] = copy.copy(typespec) + edecl['kindselector'] = copy.copy(kindselect) + edecl['charselector'] = copy.copy(charselect) + edecl['typename'] = typename + edecl['attrspec'] = copy.copy(attrspec) + if m.group('after'): + m1 = lenarraypattern.match(markouterparen(m.group('after'))) + if m1: + d1 = m1.groupdict() + for lk in ['len', 'array', 'init']: + if d1[lk + '2'] is not None: + d1[lk] = d1[lk + '2'] + del d1[lk + '2'] + for k in list(d1.keys()): + if d1[k] is not None: + d1[k] = unmarkouterparen(d1[k]) + else: + del d1[k] + if 'len' in d1 and 'array' in d1: + if d1['len'] == '': + d1['len'] = d1['array'] + del d1['array'] + else: + d1['array'] = d1['array'] + ',' + d1['len'] + del d1['len'] + errmess('updatevars: "%s %s" is mapped to "%s %s(%s)"\n' % ( + typespec, e, typespec, ename, d1['array'])) + if 'array' in d1: + dm = 'dimension(%s)' % d1['array'] + if 'attrspec' not in edecl or (not edecl['attrspec']): + edecl['attrspec'] = [dm] + else: + edecl['attrspec'].append(dm) + for dm1 in edecl['attrspec']: + if dm1[:9] == 'dimension' and dm1 != dm: + del edecl['attrspec'][-1] + errmess('updatevars:%s: attempt to change %r to %r. Ignoring.\n' + % (ename, dm1, dm)) + break + + if 'len' in d1: + if typespec in ['complex', 'integer', 'logical', 'real']: + if ('kindselector' not in edecl) or (not edecl['kindselector']): + edecl['kindselector'] = {} + edecl['kindselector']['*'] = d1['len'] + elif typespec == 'character': + if ('charselector' not in edecl) or (not edecl['charselector']): + edecl['charselector'] = {} + if 'len' in edecl['charselector']: + del edecl['charselector']['len'] + edecl['charselector']['*'] = d1['len'] + if 'init' in d1: + if '=' in edecl and (not edecl['='] == d1['init']): + outmess('updatevars: attempt to change the init expression of "%s" ("%s") to "%s". Ignoring.\n' % ( + ename, edecl['='], d1['init'])) + else: + edecl['='] = d1['init'] + else: + outmess('updatevars: could not crack entity declaration "%s". Ignoring.\n' % ( + ename + m.group('after'))) + for k in list(edecl.keys()): + if not edecl[k]: + del edecl[k] + groupcache[groupcounter]['vars'][ename] = edecl + if 'varnames' in groupcache[groupcounter]: + groupcache[groupcounter]['varnames'].append(ename) + last_name = ename + return last_name + + +def cracktypespec(typespec, selector): + kindselect = None + charselect = None + typename = None + if selector: + if typespec in ['complex', 'integer', 'logical', 'real']: + kindselect = kindselector.match(selector) + if not kindselect: + outmess( + 'cracktypespec: no kindselector pattern found for %s\n' % (repr(selector))) + return + kindselect = kindselect.groupdict() + kindselect['*'] = kindselect['kind2'] + del kindselect['kind2'] + for k in list(kindselect.keys()): + if not kindselect[k]: + del kindselect[k] + for k, i in list(kindselect.items()): + kindselect[k] = rmbadname1(i) + elif typespec == 'character': + charselect = charselector.match(selector) + if not charselect: + outmess( + 'cracktypespec: no charselector pattern found for %s\n' % (repr(selector))) + return + charselect = charselect.groupdict() + charselect['*'] = charselect['charlen'] + del charselect['charlen'] + if charselect['lenkind']: + lenkind = lenkindpattern.match( + markoutercomma(charselect['lenkind'])) + lenkind = lenkind.groupdict() + for lk in ['len', 'kind']: + if lenkind[lk + '2']: + lenkind[lk] = lenkind[lk + '2'] + charselect[lk] = lenkind[lk] + del lenkind[lk + '2'] + del charselect['lenkind'] + for k in list(charselect.keys()): + if not charselect[k]: + del charselect[k] + for k, i in list(charselect.items()): + charselect[k] = rmbadname1(i) + elif typespec == 'type': + typename = re.match(r'\s*\(\s*(?P\w+)\s*\)', selector, re.I) + if typename: + typename = typename.group('name') + else: + outmess('cracktypespec: no typename found in %s\n' % + (repr(typespec + selector))) + else: + outmess('cracktypespec: no selector used for %s\n' % + (repr(selector))) + return kindselect, charselect, typename +###### + + +def setattrspec(decl, attr, force=0): + if not decl: + decl = {} + if not attr: + return decl + if 'attrspec' not in decl: + decl['attrspec'] = [attr] + return decl + if force: + decl['attrspec'].append(attr) + if attr in decl['attrspec']: + return decl + if attr == 'static' and 'automatic' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr == 'automatic' and 'static' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr == 'public' and 'private' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr == 'private' and 'public' not in decl['attrspec']: + decl['attrspec'].append(attr) + else: + decl['attrspec'].append(attr) + return decl + + +def setkindselector(decl, sel, force=0): + if not decl: + decl = {} + if not sel: + return decl + if 'kindselector' not in decl: + decl['kindselector'] = sel + return decl + for k in list(sel.keys()): + if force or k not in decl['kindselector']: + decl['kindselector'][k] = sel[k] + return decl + + +def setcharselector(decl, sel, force=0): + if not decl: + decl = {} + if not sel: + return decl + if 'charselector' not in decl: + decl['charselector'] = sel + return decl + for k in list(sel.keys()): + if force or k not in decl['charselector']: + decl['charselector'][k] = sel[k] + return decl + + +def getblockname(block, unknown='unknown'): + if 'name' in block: + return block['name'] + return unknown + +# post processing + + +def setmesstext(block): + global filepositiontext + + try: + filepositiontext = 'In: %s:%s\n' % (block['from'], block['name']) + except Exception: + pass + + +def get_usedict(block): + usedict = {} + if 'parent_block' in block: + usedict = get_usedict(block['parent_block']) + if 'use' in block: + usedict.update(block['use']) + return usedict + + +def get_useparameters(block, param_map=None): + global f90modulevars + + if param_map is None: + param_map = {} + usedict = get_usedict(block) + if not usedict: + return param_map + for usename, mapping in list(usedict.items()): + usename = usename.lower() + if usename not in f90modulevars: + outmess('get_useparameters: no module %s info used by %s\n' % + (usename, block.get('name'))) + continue + mvars = f90modulevars[usename] + params = get_parameters(mvars) + if not params: + continue + # XXX: apply mapping + if mapping: + errmess('get_useparameters: mapping for %s not impl.' % (mapping)) + for k, v in list(params.items()): + if k in param_map: + outmess('get_useparameters: overriding parameter %s with' + ' value from module %s' % (repr(k), repr(usename))) + param_map[k] = v + + return param_map + + +def postcrack2(block, tab='', param_map=None): + global f90modulevars + + if not f90modulevars: + return block + if isinstance(block, list): + ret = [] + for g in block: + g = postcrack2(g, tab=tab + '\t', param_map=param_map) + ret.append(g) + return ret + setmesstext(block) + outmess('%sBlock: %s\n' % (tab, block['name']), 0) + + if param_map is None: + param_map = get_useparameters(block) + + if param_map is not None and 'vars' in block: + vars = block['vars'] + for n in list(vars.keys()): + var = vars[n] + if 'kindselector' in var: + kind = var['kindselector'] + if 'kind' in kind: + val = kind['kind'] + if val in param_map: + kind['kind'] = param_map[val] + new_body = [] + for b in block['body']: + b = postcrack2(b, tab=tab + '\t', param_map=param_map) + new_body.append(b) + block['body'] = new_body + + return block + + +def postcrack(block, args=None, tab=''): + """ + TODO: + function return values + determine expression types if in argument list + """ + global usermodules, onlyfunctions + + if isinstance(block, list): + gret = [] + uret = [] + for g in block: + setmesstext(g) + g = postcrack(g, tab=tab + '\t') + # sort user routines to appear first + if 'name' in g and '__user__' in g['name']: + uret.append(g) + else: + gret.append(g) + return uret + gret + setmesstext(block) + if not isinstance(block, dict) and 'block' not in block: + raise Exception('postcrack: Expected block dictionary instead of ' + + str(block)) + if 'name' in block and not block['name'] == 'unknown_interface': + outmess('%sBlock: %s\n' % (tab, block['name']), 0) + block = analyzeargs(block) + block = analyzecommon(block) + block['vars'] = analyzevars(block) + block['sortvars'] = sortvarnames(block['vars']) + if 'args' in block and block['args']: + args = block['args'] + block['body'] = analyzebody(block, args, tab=tab) + + userisdefined = [] + if 'use' in block: + useblock = block['use'] + for k in list(useblock.keys()): + if '__user__' in k: + userisdefined.append(k) + else: + useblock = {} + name = '' + if 'name' in block: + name = block['name'] + # and not userisdefined: # Build a __user__ module + if 'externals' in block and block['externals']: + interfaced = [] + if 'interfaced' in block: + interfaced = block['interfaced'] + mvars = copy.copy(block['vars']) + if name: + mname = name + '__user__routines' + else: + mname = 'unknown__user__routines' + if mname in userisdefined: + i = 1 + while '%s_%i' % (mname, i) in userisdefined: + i = i + 1 + mname = '%s_%i' % (mname, i) + interface = {'block': 'interface', 'body': [], + 'vars': {}, 'name': name + '_user_interface'} + for e in block['externals']: + if e in interfaced: + edef = [] + j = -1 + for b in block['body']: + j = j + 1 + if b['block'] == 'interface': + i = -1 + for bb in b['body']: + i = i + 1 + if 'name' in bb and bb['name'] == e: + edef = copy.copy(bb) + del b['body'][i] + break + if edef: + if not b['body']: + del block['body'][j] + del interfaced[interfaced.index(e)] + break + interface['body'].append(edef) + else: + if e in mvars and not isexternal(mvars[e]): + interface['vars'][e] = mvars[e] + if interface['vars'] or interface['body']: + block['interfaced'] = interfaced + mblock = {'block': 'python module', 'body': [ + interface], 'vars': {}, 'name': mname, 'interfaced': block['externals']} + useblock[mname] = {} + usermodules.append(mblock) + if useblock: + block['use'] = useblock + return block + + +def sortvarnames(vars): + indep = [] + dep = [] + for v in list(vars.keys()): + if 'depend' in vars[v] and vars[v]['depend']: + dep.append(v) + else: + indep.append(v) + n = len(dep) + i = 0 + while dep: # XXX: How to catch dependence cycles correctly? + v = dep[0] + fl = 0 + for w in dep[1:]: + if w in vars[v]['depend']: + fl = 1 + break + if fl: + dep = dep[1:] + [v] + i = i + 1 + if i > n: + errmess('sortvarnames: failed to compute dependencies because' + ' of cyclic dependencies between ' + + ', '.join(dep) + '\n') + indep = indep + dep + break + else: + indep.append(v) + dep = dep[1:] + n = len(dep) + i = 0 + return indep + + +def analyzecommon(block): + if not hascommon(block): + return block + commonvars = [] + for k in list(block['common'].keys()): + comvars = [] + for e in block['common'][k]: + m = re.match( + r'\A\s*\b(?P.*?)\b\s*(\((?P.*?)\)|)\s*\Z', e, re.I) + if m: + dims = [] + if m.group('dims'): + dims = [x.strip() + for x in markoutercomma(m.group('dims')).split('@,@')] + n = rmbadname1(m.group('name').strip()) + if n in block['vars']: + if 'attrspec' in block['vars'][n]: + block['vars'][n]['attrspec'].append( + 'dimension(%s)' % (','.join(dims))) + else: + block['vars'][n]['attrspec'] = [ + 'dimension(%s)' % (','.join(dims))] + else: + if dims: + block['vars'][n] = { + 'attrspec': ['dimension(%s)' % (','.join(dims))]} + else: + block['vars'][n] = {} + if n not in commonvars: + commonvars.append(n) + else: + n = e + errmess( + 'analyzecommon: failed to extract "[()]" from "%s" in common /%s/.\n' % (e, k)) + comvars.append(n) + block['common'][k] = comvars + if 'commonvars' not in block: + block['commonvars'] = commonvars + else: + block['commonvars'] = block['commonvars'] + commonvars + return block + + +def analyzebody(block, args, tab=''): + global usermodules, skipfuncs, onlyfuncs, f90modulevars + + setmesstext(block) + body = [] + for b in block['body']: + b['parent_block'] = block + if b['block'] in ['function', 'subroutine']: + if args is not None and b['name'] not in args: + continue + else: + as_ = b['args'] + if b['name'] in skipfuncs: + continue + if onlyfuncs and b['name'] not in onlyfuncs: + continue + b['saved_interface'] = crack2fortrangen( + b, '\n' + ' ' * 6, as_interface=True) + + else: + as_ = args + b = postcrack(b, as_, tab=tab + '\t') + if b['block'] == 'interface' and not b['body']: + if 'f2pyenhancements' not in b: + continue + if b['block'].replace(' ', '') == 'pythonmodule': + usermodules.append(b) + else: + if b['block'] == 'module': + f90modulevars[b['name']] = b['vars'] + body.append(b) + return body + + +def buildimplicitrules(block): + setmesstext(block) + implicitrules = defaultimplicitrules + attrrules = {} + if 'implicit' in block: + if block['implicit'] is None: + implicitrules = None + if verbose > 1: + outmess( + 'buildimplicitrules: no implicit rules for routine %s.\n' % repr(block['name'])) + else: + for k in list(block['implicit'].keys()): + if block['implicit'][k].get('typespec') not in ['static', 'automatic']: + implicitrules[k] = block['implicit'][k] + else: + attrrules[k] = block['implicit'][k]['typespec'] + return implicitrules, attrrules + + +def myeval(e, g=None, l=None): + r = eval(e, g, l) + if type(r) in [type(0), type(0.0)]: + return r + raise ValueError('r=%r' % (r)) + +getlincoef_re_1 = re.compile(r'\A\b\w+\b\Z', re.I) + + +def getlincoef(e, xset): # e = a*x+b ; x in xset + try: + c = int(myeval(e, {}, {})) + return 0, c, None + except Exception: + pass + if getlincoef_re_1.match(e): + return 1, 0, e + len_e = len(e) + for x in xset: + if len(x) > len_e: + continue + if re.search(r'\w\s*\([^)]*\b' + x + r'\b', e): + # skip function calls having x as an argument, e.g max(1, x) + continue + re_1 = re.compile(r'(?P.*?)\b' + x + r'\b(?P.*)', re.I) + m = re_1.match(e) + if m: + try: + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s' % ( + m1.group('before'), 0, m1.group('after')) + m1 = re_1.match(ee) + b = myeval(ee, {}, {}) + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s' % ( + m1.group('before'), 1, m1.group('after')) + m1 = re_1.match(ee) + a = myeval(ee, {}, {}) - b + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s' % ( + m1.group('before'), 0.5, m1.group('after')) + m1 = re_1.match(ee) + c = myeval(ee, {}, {}) + # computing another point to be sure that expression is linear + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s' % ( + m1.group('before'), 1.5, m1.group('after')) + m1 = re_1.match(ee) + c2 = myeval(ee, {}, {}) + if (a * 0.5 + b == c and a * 1.5 + b == c2): + return a, b, x + except Exception: + pass + break + return None, None, None + +_varname_match = re.compile(r'\A[a-z]\w*\Z').match + + +def getarrlen(dl, args, star='*'): + edl = [] + try: + edl.append(myeval(dl[0], {}, {})) + except Exception: + edl.append(dl[0]) + try: + edl.append(myeval(dl[1], {}, {})) + except Exception: + edl.append(dl[1]) + if isinstance(edl[0], int): + p1 = 1 - edl[0] + if p1 == 0: + d = str(dl[1]) + elif p1 < 0: + d = '%s-%s' % (dl[1], -p1) + else: + d = '%s+%s' % (dl[1], p1) + elif isinstance(edl[1], int): + p1 = 1 + edl[1] + if p1 == 0: + d = '-(%s)' % (dl[0]) + else: + d = '%s-(%s)' % (p1, dl[0]) + else: + d = '%s-(%s)+1' % (dl[1], dl[0]) + try: + return repr(myeval(d, {}, {})), None, None + except Exception: + pass + d1, d2 = getlincoef(dl[0], args), getlincoef(dl[1], args) + if None not in [d1[0], d2[0]]: + if (d1[0], d2[0]) == (0, 0): + return repr(d2[1] - d1[1] + 1), None, None + b = d2[1] - d1[1] + 1 + d1 = (d1[0], 0, d1[2]) + d2 = (d2[0], b, d2[2]) + if d1[0] == 0 and d2[2] in args: + if b < 0: + return '%s * %s - %s' % (d2[0], d2[2], -b), d2[2], '+%s)/(%s)' % (-b, d2[0]) + elif b: + return '%s * %s + %s' % (d2[0], d2[2], b), d2[2], '-%s)/(%s)' % (b, d2[0]) + else: + return '%s * %s' % (d2[0], d2[2]), d2[2], ')/(%s)' % (d2[0]) + if d2[0] == 0 and d1[2] in args: + + if b < 0: + return '%s * %s - %s' % (-d1[0], d1[2], -b), d1[2], '+%s)/(%s)' % (-b, -d1[0]) + elif b: + return '%s * %s + %s' % (-d1[0], d1[2], b), d1[2], '-%s)/(%s)' % (b, -d1[0]) + else: + return '%s * %s' % (-d1[0], d1[2]), d1[2], ')/(%s)' % (-d1[0]) + if d1[2] == d2[2] and d1[2] in args: + a = d2[0] - d1[0] + if not a: + return repr(b), None, None + if b < 0: + return '%s * %s - %s' % (a, d1[2], -b), d2[2], '+%s)/(%s)' % (-b, a) + elif b: + return '%s * %s + %s' % (a, d1[2], b), d2[2], '-%s)/(%s)' % (b, a) + else: + return '%s * %s' % (a, d1[2]), d2[2], ')/(%s)' % (a) + if d1[0] == d2[0] == 1: + c = str(d1[2]) + if c not in args: + if _varname_match(c): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c)) + c = '(%s)' % c + if b == 0: + d = '%s-%s' % (d2[2], c) + elif b < 0: + d = '%s-%s-%s' % (d2[2], c, -b) + else: + d = '%s-%s+%s' % (d2[2], c, b) + elif d1[0] == 0: + c2 = str(d2[2]) + if c2 not in args: + if _varname_match(c2): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c2)) + c2 = '(%s)' % c2 + if d2[0] == 1: + pass + elif d2[0] == -1: + c2 = '-%s' % c2 + else: + c2 = '%s*%s' % (d2[0], c2) + + if b == 0: + d = c2 + elif b < 0: + d = '%s-%s' % (c2, -b) + else: + d = '%s+%s' % (c2, b) + elif d2[0] == 0: + c1 = str(d1[2]) + if c1 not in args: + if _varname_match(c1): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c1)) + c1 = '(%s)' % c1 + if d1[0] == 1: + c1 = '-%s' % c1 + elif d1[0] == -1: + c1 = '+%s' % c1 + elif d1[0] < 0: + c1 = '+%s*%s' % (-d1[0], c1) + else: + c1 = '-%s*%s' % (d1[0], c1) + + if b == 0: + d = c1 + elif b < 0: + d = '%s-%s' % (c1, -b) + else: + d = '%s+%s' % (c1, b) + else: + c1 = str(d1[2]) + if c1 not in args: + if _varname_match(c1): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c1)) + c1 = '(%s)' % c1 + if d1[0] == 1: + c1 = '-%s' % c1 + elif d1[0] == -1: + c1 = '+%s' % c1 + elif d1[0] < 0: + c1 = '+%s*%s' % (-d1[0], c1) + else: + c1 = '-%s*%s' % (d1[0], c1) + + c2 = str(d2[2]) + if c2 not in args: + if _varname_match(c2): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c2)) + c2 = '(%s)' % c2 + if d2[0] == 1: + pass + elif d2[0] == -1: + c2 = '-%s' % c2 + else: + c2 = '%s*%s' % (d2[0], c2) + + if b == 0: + d = '%s%s' % (c2, c1) + elif b < 0: + d = '%s%s-%s' % (c2, c1, -b) + else: + d = '%s%s+%s' % (c2, c1, b) + return d, None, None + +word_pattern = re.compile(r'\b[a-z][\w$]*\b', re.I) + + +def _get_depend_dict(name, vars, deps): + if name in vars: + words = vars[name].get('depend', []) + + if '=' in vars[name] and not isstring(vars[name]): + for word in word_pattern.findall(vars[name]['=']): + if word not in words and word in vars: + words.append(word) + for word in words[:]: + for w in deps.get(word, []) \ + or _get_depend_dict(word, vars, deps): + if w not in words: + words.append(w) + else: + outmess('_get_depend_dict: no dependence info for %s\n' % (repr(name))) + words = [] + deps[name] = words + return words + + +def _calc_depend_dict(vars): + names = list(vars.keys()) + depend_dict = {} + for n in names: + _get_depend_dict(n, vars, depend_dict) + return depend_dict + + +def get_sorted_names(vars): + """ + """ + depend_dict = _calc_depend_dict(vars) + names = [] + for name in list(depend_dict.keys()): + if not depend_dict[name]: + names.append(name) + del depend_dict[name] + while depend_dict: + for name, lst in list(depend_dict.items()): + new_lst = [n for n in lst if n in depend_dict] + if not new_lst: + names.append(name) + del depend_dict[name] + else: + depend_dict[name] = new_lst + return [name for name in names if name in vars] + + +def _kind_func(string): + # XXX: return something sensible. + if string[0] in "'\"": + string = string[1:-1] + if real16pattern.match(string): + return 8 + elif real8pattern.match(string): + return 4 + return 'kind(' + string + ')' + + +def _selected_int_kind_func(r): + # XXX: This should be processor dependent + m = 10 ** r + if m <= 2 ** 8: + return 1 + if m <= 2 ** 16: + return 2 + if m <= 2 ** 32: + return 4 + if m <= 2 ** 63: + return 8 + if m <= 2 ** 128: + return 16 + return -1 + + +def _selected_real_kind_func(p, r=0, radix=0): + # XXX: This should be processor dependent + # This is only good for 0 <= p <= 20 + if p < 7: + return 4 + if p < 16: + return 8 + machine = platform.machine().lower() + if machine.startswith('power') or machine.startswith('ppc64'): + if p <= 20: + return 16 + else: + if p < 19: + return 10 + elif p <= 20: + return 16 + return -1 + + +def get_parameters(vars, global_params={}): + params = copy.copy(global_params) + g_params = copy.copy(global_params) + for name, func in [('kind', _kind_func), + ('selected_int_kind', _selected_int_kind_func), + ('selected_real_kind', _selected_real_kind_func), ]: + if name not in g_params: + g_params[name] = func + param_names = [] + for n in get_sorted_names(vars): + if 'attrspec' in vars[n] and 'parameter' in vars[n]['attrspec']: + param_names.append(n) + kind_re = re.compile(r'\bkind\s*\(\s*(?P.*)\s*\)', re.I) + selected_int_kind_re = re.compile( + r'\bselected_int_kind\s*\(\s*(?P.*)\s*\)', re.I) + selected_kind_re = re.compile( + r'\bselected_(int|real)_kind\s*\(\s*(?P.*)\s*\)', re.I) + for n in param_names: + if '=' in vars[n]: + v = vars[n]['='] + if islogical(vars[n]): + v = v.lower() + for repl in [ + ('.false.', 'False'), + ('.true.', 'True'), + # TODO: test .eq., .neq., etc replacements. + ]: + v = v.replace(*repl) + v = kind_re.sub(r'kind("\1")', v) + v = selected_int_kind_re.sub(r'selected_int_kind(\1)', v) + + # We need to act according to the data. + # The easy case is if the data has a kind-specifier, + # then we may easily remove those specifiers. + # However, it may be that the user uses other specifiers...(!) + is_replaced = False + if 'kindselector' in vars[n]: + if 'kind' in vars[n]['kindselector']: + orig_v_len = len(v) + v = v.replace('_' + vars[n]['kindselector']['kind'], '') + # Again, this will be true if even a single specifier + # has been replaced, see comment above. + is_replaced = len(v) < orig_v_len + + if not is_replaced: + if not selected_kind_re.match(v): + v_ = v.split('_') + # In case there are additive parameters + if len(v_) > 1: + v = ''.join(v_[:-1]).lower().replace(v_[-1].lower(), '') + + # Currently this will not work for complex numbers. + # There is missing code for extracting a complex number, + # which may be defined in either of these: + # a) (Re, Im) + # b) cmplx(Re, Im) + # c) dcmplx(Re, Im) + # d) cmplx(Re, Im, ) + + if isdouble(vars[n]): + tt = list(v) + for m in real16pattern.finditer(v): + tt[m.start():m.end()] = list( + v[m.start():m.end()].lower().replace('d', 'e')) + v = ''.join(tt) + + elif iscomplex(vars[n]): + # FIXME complex numbers may also have exponents + if v[0] == '(' and v[-1] == ')': + # FIXME, unused l looks like potential bug + l = markoutercomma(v[1:-1]).split('@,@') + + try: + params[n] = eval(v, g_params, params) + except Exception as msg: + params[n] = v + outmess('get_parameters: got "%s" on %s\n' % (msg, repr(v))) + if isstring(vars[n]) and isinstance(params[n], int): + params[n] = chr(params[n]) + nl = n.lower() + if nl != n: + params[nl] = params[n] + else: + print(vars[n]) + outmess( + 'get_parameters:parameter %s does not have value?!\n' % (repr(n))) + return params + + +def _eval_length(length, params): + if length in ['(:)', '(*)', '*']: + return '(*)' + return _eval_scalar(length, params) + +_is_kind_number = re.compile(r'\d+_').match + + +def _eval_scalar(value, params): + if _is_kind_number(value): + value = value.split('_')[0] + try: + value = str(eval(value, {}, params)) + except (NameError, SyntaxError): + return value + except Exception as msg: + errmess('"%s" in evaluating %r ' + '(available names: %s)\n' + % (msg, value, list(params.keys()))) + return value + + +def analyzevars(block): + global f90modulevars + + setmesstext(block) + implicitrules, attrrules = buildimplicitrules(block) + vars = copy.copy(block['vars']) + if block['block'] == 'function' and block['name'] not in vars: + vars[block['name']] = {} + if '' in block['vars']: + del vars[''] + if 'attrspec' in block['vars']['']: + gen = block['vars']['']['attrspec'] + for n in list(vars.keys()): + for k in ['public', 'private']: + if k in gen: + vars[n] = setattrspec(vars[n], k) + svars = [] + args = block['args'] + for a in args: + try: + vars[a] + svars.append(a) + except KeyError: + pass + for n in list(vars.keys()): + if n not in args: + svars.append(n) + + params = get_parameters(vars, get_useparameters(block)) + + dep_matches = {} + name_match = re.compile(r'\w[\w\d_$]*').match + for v in list(vars.keys()): + m = name_match(v) + if m: + n = v[m.start():m.end()] + try: + dep_matches[n] + except KeyError: + dep_matches[n] = re.compile(r'.*\b%s\b' % (v), re.I).match + for n in svars: + if n[0] in list(attrrules.keys()): + vars[n] = setattrspec(vars[n], attrrules[n[0]]) + if 'typespec' not in vars[n]: + if not('attrspec' in vars[n] and 'external' in vars[n]['attrspec']): + if implicitrules: + ln0 = n[0].lower() + for k in list(implicitrules[ln0].keys()): + if k == 'typespec' and implicitrules[ln0][k] == 'undefined': + continue + if k not in vars[n]: + vars[n][k] = implicitrules[ln0][k] + elif k == 'attrspec': + for l in implicitrules[ln0][k]: + vars[n] = setattrspec(vars[n], l) + elif n in block['args']: + outmess('analyzevars: typespec of variable %s is not defined in routine %s.\n' % ( + repr(n), block['name'])) + + if 'charselector' in vars[n]: + if 'len' in vars[n]['charselector']: + l = vars[n]['charselector']['len'] + try: + l = str(eval(l, {}, params)) + except Exception: + pass + vars[n]['charselector']['len'] = l + + if 'kindselector' in vars[n]: + if 'kind' in vars[n]['kindselector']: + l = vars[n]['kindselector']['kind'] + try: + l = str(eval(l, {}, params)) + except Exception: + pass + vars[n]['kindselector']['kind'] = l + + savelindims = {} + if 'attrspec' in vars[n]: + attr = vars[n]['attrspec'] + attr.reverse() + vars[n]['attrspec'] = [] + dim, intent, depend, check, note = None, None, None, None, None + for a in attr: + if a[:9] == 'dimension': + dim = (a[9:].strip())[1:-1] + elif a[:6] == 'intent': + intent = (a[6:].strip())[1:-1] + elif a[:6] == 'depend': + depend = (a[6:].strip())[1:-1] + elif a[:5] == 'check': + check = (a[5:].strip())[1:-1] + elif a[:4] == 'note': + note = (a[4:].strip())[1:-1] + else: + vars[n] = setattrspec(vars[n], a) + if intent: + if 'intent' not in vars[n]: + vars[n]['intent'] = [] + for c in [x.strip() for x in markoutercomma(intent).split('@,@')]: + # Remove spaces so that 'in out' becomes 'inout' + tmp = c.replace(' ', '') + if tmp not in vars[n]['intent']: + vars[n]['intent'].append(tmp) + intent = None + if note: + note = note.replace('\\n\\n', '\n\n') + note = note.replace('\\n ', '\n') + if 'note' not in vars[n]: + vars[n]['note'] = [note] + else: + vars[n]['note'].append(note) + note = None + if depend is not None: + if 'depend' not in vars[n]: + vars[n]['depend'] = [] + for c in rmbadname([x.strip() for x in markoutercomma(depend).split('@,@')]): + if c not in vars[n]['depend']: + vars[n]['depend'].append(c) + depend = None + if check is not None: + if 'check' not in vars[n]: + vars[n]['check'] = [] + for c in [x.strip() for x in markoutercomma(check).split('@,@')]: + if c not in vars[n]['check']: + vars[n]['check'].append(c) + check = None + if dim and 'dimension' not in vars[n]: + vars[n]['dimension'] = [] + for d in rmbadname([x.strip() for x in markoutercomma(dim).split('@,@')]): + star = '*' + if d == ':': + star = ':' + if d in params: + d = str(params[d]) + for p in list(params.keys()): + re_1 = re.compile(r'(?P.*?)\b' + p + r'\b(?P.*)', re.I) + m = re_1.match(d) + while m: + d = m.group('before') + \ + str(params[p]) + m.group('after') + m = re_1.match(d) + if d == star: + dl = [star] + else: + dl = markoutercomma(d, ':').split('@:@') + if len(dl) == 2 and '*' in dl: # e.g. dimension(5:*) + dl = ['*'] + d = '*' + if len(dl) == 1 and not dl[0] == star: + dl = ['1', dl[0]] + if len(dl) == 2: + d, v, di = getarrlen(dl, list(block['vars'].keys())) + if d[:4] == '1 * ': + d = d[4:] + if di and di[-4:] == '/(1)': + di = di[:-4] + if v: + savelindims[d] = v, di + vars[n]['dimension'].append(d) + if 'dimension' in vars[n]: + if isintent_c(vars[n]): + shape_macro = 'shape' + else: + shape_macro = 'shape' # 'fshape' + if isstringarray(vars[n]): + if 'charselector' in vars[n]: + d = vars[n]['charselector'] + if '*' in d: + d = d['*'] + errmess('analyzevars: character array "character*%s %s(%s)" is considered as "character %s(%s)"; "intent(c)" is forced.\n' + % (d, n, + ','.join(vars[n]['dimension']), + n, ','.join(vars[n]['dimension'] + [d]))) + vars[n]['dimension'].append(d) + del vars[n]['charselector'] + if 'intent' not in vars[n]: + vars[n]['intent'] = [] + if 'c' not in vars[n]['intent']: + vars[n]['intent'].append('c') + else: + errmess( + "analyzevars: charselector=%r unhandled." % (d)) + if 'check' not in vars[n] and 'args' in block and n in block['args']: + flag = 'depend' not in vars[n] + if flag: + vars[n]['depend'] = [] + vars[n]['check'] = [] + if 'dimension' in vars[n]: + #/----< no check + i = -1 + ni = len(vars[n]['dimension']) + for d in vars[n]['dimension']: + ddeps = [] # dependecies of 'd' + ad = '' + pd = '' + if d not in vars: + if d in savelindims: + pd, ad = '(', savelindims[d][1] + d = savelindims[d][0] + else: + for r in block['args']: + if r not in vars: + continue + if re.match(r'.*?\b' + r + r'\b', d, re.I): + ddeps.append(r) + if d in vars: + if 'attrspec' in vars[d]: + for aa in vars[d]['attrspec']: + if aa[:6] == 'depend': + ddeps += aa[6:].strip()[1:-1].split(',') + if 'depend' in vars[d]: + ddeps = ddeps + vars[d]['depend'] + i = i + 1 + if d in vars and ('depend' not in vars[d]) \ + and ('=' not in vars[d]) and (d not in vars[n]['depend']) \ + and l_or(isintent_in, isintent_inout, isintent_inplace)(vars[n]): + vars[d]['depend'] = [n] + if ni > 1: + vars[d]['='] = '%s%s(%s,%s)%s' % ( + pd, shape_macro, n, i, ad) + else: + vars[d]['='] = '%slen(%s)%s' % (pd, n, ad) + # /---< no check + if 1 and 'check' not in vars[d]: + if ni > 1: + vars[d]['check'] = ['%s%s(%s,%i)%s==%s' + % (pd, shape_macro, n, i, ad, d)] + else: + vars[d]['check'] = [ + '%slen(%s)%s>=%s' % (pd, n, ad, d)] + if 'attrspec' not in vars[d]: + vars[d]['attrspec'] = ['optional'] + if ('optional' not in vars[d]['attrspec']) and\ + ('required' not in vars[d]['attrspec']): + vars[d]['attrspec'].append('optional') + elif d not in ['*', ':']: + #/----< no check + if flag: + if d in vars: + if n not in ddeps: + vars[n]['depend'].append(d) + else: + vars[n]['depend'] = vars[n]['depend'] + ddeps + elif isstring(vars[n]): + length = '1' + if 'charselector' in vars[n]: + if '*' in vars[n]['charselector']: + length = _eval_length(vars[n]['charselector']['*'], + params) + vars[n]['charselector']['*'] = length + elif 'len' in vars[n]['charselector']: + length = _eval_length(vars[n]['charselector']['len'], + params) + del vars[n]['charselector']['len'] + vars[n]['charselector']['*'] = length + + if not vars[n]['check']: + del vars[n]['check'] + if flag and not vars[n]['depend']: + del vars[n]['depend'] + if '=' in vars[n]: + if 'attrspec' not in vars[n]: + vars[n]['attrspec'] = [] + if ('optional' not in vars[n]['attrspec']) and \ + ('required' not in vars[n]['attrspec']): + vars[n]['attrspec'].append('optional') + if 'depend' not in vars[n]: + vars[n]['depend'] = [] + for v, m in list(dep_matches.items()): + if m(vars[n]['=']): + vars[n]['depend'].append(v) + if not vars[n]['depend']: + del vars[n]['depend'] + if isscalar(vars[n]): + vars[n]['='] = _eval_scalar(vars[n]['='], params) + + for n in list(vars.keys()): + if n == block['name']: # n is block name + if 'note' in vars[n]: + block['note'] = vars[n]['note'] + if block['block'] == 'function': + if 'result' in block and block['result'] in vars: + vars[n] = appenddecl(vars[n], vars[block['result']]) + if 'prefix' in block: + pr = block['prefix'] + ispure = 0 + isrec = 1 + pr1 = pr.replace('pure', '') + ispure = (not pr == pr1) + pr = pr1.replace('recursive', '') + isrec = (not pr == pr1) + m = typespattern[0].match(pr) + if m: + typespec, selector, attr, edecl = cracktypespec0( + m.group('this'), m.group('after')) + kindselect, charselect, typename = cracktypespec( + typespec, selector) + vars[n]['typespec'] = typespec + if kindselect: + if 'kind' in kindselect: + try: + kindselect['kind'] = eval( + kindselect['kind'], {}, params) + except Exception: + pass + vars[n]['kindselector'] = kindselect + if charselect: + vars[n]['charselector'] = charselect + if typename: + vars[n]['typename'] = typename + if ispure: + vars[n] = setattrspec(vars[n], 'pure') + if isrec: + vars[n] = setattrspec(vars[n], 'recursive') + else: + outmess( + 'analyzevars: prefix (%s) were not used\n' % repr(block['prefix'])) + if not block['block'] in ['module', 'pythonmodule', 'python module', 'block data']: + if 'commonvars' in block: + neededvars = copy.copy(block['args'] + block['commonvars']) + else: + neededvars = copy.copy(block['args']) + for n in list(vars.keys()): + if l_or(isintent_callback, isintent_aux)(vars[n]): + neededvars.append(n) + if 'entry' in block: + neededvars.extend(list(block['entry'].keys())) + for k in list(block['entry'].keys()): + for n in block['entry'][k]: + if n not in neededvars: + neededvars.append(n) + if block['block'] == 'function': + if 'result' in block: + neededvars.append(block['result']) + else: + neededvars.append(block['name']) + if block['block'] in ['subroutine', 'function']: + name = block['name'] + if name in vars and 'intent' in vars[name]: + block['intent'] = vars[name]['intent'] + if block['block'] == 'type': + neededvars.extend(list(vars.keys())) + for n in list(vars.keys()): + if n not in neededvars: + del vars[n] + return vars + +analyzeargs_re_1 = re.compile(r'\A[a-z]+[\w$]*\Z', re.I) + + +def expr2name(a, block, args=[]): + orig_a = a + a_is_expr = not analyzeargs_re_1.match(a) + if a_is_expr: # `a` is an expression + implicitrules, attrrules = buildimplicitrules(block) + at = determineexprtype(a, block['vars'], implicitrules) + na = 'e_' + for c in a: + c = c.lower() + if c not in string.ascii_lowercase + string.digits: + c = '_' + na = na + c + if na[-1] == '_': + na = na + 'e' + else: + na = na + '_e' + a = na + while a in block['vars'] or a in block['args']: + a = a + 'r' + if a in args: + k = 1 + while a + str(k) in args: + k = k + 1 + a = a + str(k) + if a_is_expr: + block['vars'][a] = at + else: + if a not in block['vars']: + if orig_a in block['vars']: + block['vars'][a] = block['vars'][orig_a] + else: + block['vars'][a] = {} + if 'externals' in block and orig_a in block['externals'] + block['interfaced']: + block['vars'][a] = setattrspec(block['vars'][a], 'external') + return a + + +def analyzeargs(block): + setmesstext(block) + implicitrules, attrrules = buildimplicitrules(block) + if 'args' not in block: + block['args'] = [] + args = [] + for a in block['args']: + a = expr2name(a, block, args) + args.append(a) + block['args'] = args + if 'entry' in block: + for k, args1 in list(block['entry'].items()): + for a in args1: + if a not in block['vars']: + block['vars'][a] = {} + + for b in block['body']: + if b['name'] in args: + if 'externals' not in block: + block['externals'] = [] + if b['name'] not in block['externals']: + block['externals'].append(b['name']) + if 'result' in block and block['result'] not in block['vars']: + block['vars'][block['result']] = {} + return block + +determineexprtype_re_1 = re.compile(r'\A\(.+?[,].+?\)\Z', re.I) +determineexprtype_re_2 = re.compile(r'\A[+-]?\d+(_(?P[\w]+)|)\Z', re.I) +determineexprtype_re_3 = re.compile( + r'\A[+-]?[\d.]+[\d+\-de.]*(_(?P[\w]+)|)\Z', re.I) +determineexprtype_re_4 = re.compile(r'\A\(.*\)\Z', re.I) +determineexprtype_re_5 = re.compile(r'\A(?P\w+)\s*\(.*?\)\s*\Z', re.I) + + +def _ensure_exprdict(r): + if isinstance(r, int): + return {'typespec': 'integer'} + if isinstance(r, float): + return {'typespec': 'real'} + if isinstance(r, complex): + return {'typespec': 'complex'} + if isinstance(r, dict): + return r + raise AssertionError(repr(r)) + + +def determineexprtype(expr, vars, rules={}): + if expr in vars: + return _ensure_exprdict(vars[expr]) + expr = expr.strip() + if determineexprtype_re_1.match(expr): + return {'typespec': 'complex'} + m = determineexprtype_re_2.match(expr) + if m: + if 'name' in m.groupdict() and m.group('name'): + outmess( + 'determineexprtype: selected kind types not supported (%s)\n' % repr(expr)) + return {'typespec': 'integer'} + m = determineexprtype_re_3.match(expr) + if m: + if 'name' in m.groupdict() and m.group('name'): + outmess( + 'determineexprtype: selected kind types not supported (%s)\n' % repr(expr)) + return {'typespec': 'real'} + for op in ['+', '-', '*', '/']: + for e in [x.strip() for x in markoutercomma(expr, comma=op).split('@' + op + '@')]: + if e in vars: + return _ensure_exprdict(vars[e]) + t = {} + if determineexprtype_re_4.match(expr): # in parenthesis + t = determineexprtype(expr[1:-1], vars, rules) + else: + m = determineexprtype_re_5.match(expr) + if m: + rn = m.group('name') + t = determineexprtype(m.group('name'), vars, rules) + if t and 'attrspec' in t: + del t['attrspec'] + if not t: + if rn[0] in rules: + return _ensure_exprdict(rules[rn[0]]) + if expr[0] in '\'"': + return {'typespec': 'character', 'charselector': {'*': '*'}} + if not t: + outmess( + 'determineexprtype: could not determine expressions (%s) type.\n' % (repr(expr))) + return t + +###### + + +def crack2fortrangen(block, tab='\n', as_interface=False): + global skipfuncs, onlyfuncs + + setmesstext(block) + ret = '' + if isinstance(block, list): + for g in block: + if g and g['block'] in ['function', 'subroutine']: + if g['name'] in skipfuncs: + continue + if onlyfuncs and g['name'] not in onlyfuncs: + continue + ret = ret + crack2fortrangen(g, tab, as_interface=as_interface) + return ret + prefix = '' + name = '' + args = '' + blocktype = block['block'] + if blocktype == 'program': + return '' + argsl = [] + if 'name' in block: + name = block['name'] + if 'args' in block: + vars = block['vars'] + for a in block['args']: + a = expr2name(a, block, argsl) + if not isintent_callback(vars[a]): + argsl.append(a) + if block['block'] == 'function' or argsl: + args = '(%s)' % ','.join(argsl) + f2pyenhancements = '' + if 'f2pyenhancements' in block: + for k in list(block['f2pyenhancements'].keys()): + f2pyenhancements = '%s%s%s %s' % ( + f2pyenhancements, tab + tabchar, k, block['f2pyenhancements'][k]) + intent_lst = block.get('intent', [])[:] + if blocktype == 'function' and 'callback' in intent_lst: + intent_lst.remove('callback') + if intent_lst: + f2pyenhancements = '%s%sintent(%s) %s' %\ + (f2pyenhancements, tab + tabchar, + ','.join(intent_lst), name) + use = '' + if 'use' in block: + use = use2fortran(block['use'], tab + tabchar) + common = '' + if 'common' in block: + common = common2fortran(block['common'], tab + tabchar) + if name == 'unknown_interface': + name = '' + result = '' + if 'result' in block: + result = ' result (%s)' % block['result'] + if block['result'] not in argsl: + argsl.append(block['result']) + body = crack2fortrangen(block['body'], tab + tabchar) + vars = vars2fortran( + block, block['vars'], argsl, tab + tabchar, as_interface=as_interface) + mess = '' + if 'from' in block and not as_interface: + mess = '! in %s' % block['from'] + if 'entry' in block: + entry_stmts = '' + for k, i in list(block['entry'].items()): + entry_stmts = '%s%sentry %s(%s)' \ + % (entry_stmts, tab + tabchar, k, ','.join(i)) + body = body + entry_stmts + if blocktype == 'block data' and name == '_BLOCK_DATA_': + name = '' + ret = '%s%s%s %s%s%s %s%s%s%s%s%s%send %s %s' % ( + tab, prefix, blocktype, name, args, result, mess, f2pyenhancements, use, vars, common, body, tab, blocktype, name) + return ret + + +def common2fortran(common, tab=''): + ret = '' + for k in list(common.keys()): + if k == '_BLNK_': + ret = '%s%scommon %s' % (ret, tab, ','.join(common[k])) + else: + ret = '%s%scommon /%s/ %s' % (ret, tab, k, ','.join(common[k])) + return ret + + +def use2fortran(use, tab=''): + ret = '' + for m in list(use.keys()): + ret = '%s%suse %s,' % (ret, tab, m) + if use[m] == {}: + if ret and ret[-1] == ',': + ret = ret[:-1] + continue + if 'only' in use[m] and use[m]['only']: + ret = '%s only:' % (ret) + if 'map' in use[m] and use[m]['map']: + c = ' ' + for k in list(use[m]['map'].keys()): + if k == use[m]['map'][k]: + ret = '%s%s%s' % (ret, c, k) + c = ',' + else: + ret = '%s%s%s=>%s' % (ret, c, k, use[m]['map'][k]) + c = ',' + if ret and ret[-1] == ',': + ret = ret[:-1] + return ret + + +def true_intent_list(var): + lst = var['intent'] + ret = [] + for intent in lst: + try: + c = eval('isintent_%s(var)' % intent) + except NameError: + c = 0 + if c: + ret.append(intent) + return ret + + +def vars2fortran(block, vars, args, tab='', as_interface=False): + """ + TODO: + public sub + ... + """ + setmesstext(block) + ret = '' + nout = [] + for a in args: + if a in block['vars']: + nout.append(a) + if 'commonvars' in block: + for a in block['commonvars']: + if a in vars: + if a not in nout: + nout.append(a) + else: + errmess( + 'vars2fortran: Confused?!: "%s" is not defined in vars.\n' % a) + if 'varnames' in block: + nout.extend(block['varnames']) + if not as_interface: + for a in list(vars.keys()): + if a not in nout: + nout.append(a) + for a in nout: + if 'depend' in vars[a]: + for d in vars[a]['depend']: + if d in vars and 'depend' in vars[d] and a in vars[d]['depend']: + errmess( + 'vars2fortran: Warning: cross-dependence between variables "%s" and "%s"\n' % (a, d)) + if 'externals' in block and a in block['externals']: + if isintent_callback(vars[a]): + ret = '%s%sintent(callback) %s' % (ret, tab, a) + ret = '%s%sexternal %s' % (ret, tab, a) + if isoptional(vars[a]): + ret = '%s%soptional %s' % (ret, tab, a) + if a in vars and 'typespec' not in vars[a]: + continue + cont = 1 + for b in block['body']: + if a == b['name'] and b['block'] == 'function': + cont = 0 + break + if cont: + continue + if a not in vars: + show(vars) + outmess('vars2fortran: No definition for argument "%s".\n' % a) + continue + if a == block['name'] and not block['block'] == 'function': + continue + if 'typespec' not in vars[a]: + if 'attrspec' in vars[a] and 'external' in vars[a]['attrspec']: + if a in args: + ret = '%s%sexternal %s' % (ret, tab, a) + continue + show(vars[a]) + outmess('vars2fortran: No typespec for argument "%s".\n' % a) + continue + vardef = vars[a]['typespec'] + if vardef == 'type' and 'typename' in vars[a]: + vardef = '%s(%s)' % (vardef, vars[a]['typename']) + selector = {} + if 'kindselector' in vars[a]: + selector = vars[a]['kindselector'] + elif 'charselector' in vars[a]: + selector = vars[a]['charselector'] + if '*' in selector: + if selector['*'] in ['*', ':']: + vardef = '%s*(%s)' % (vardef, selector['*']) + else: + vardef = '%s*%s' % (vardef, selector['*']) + else: + if 'len' in selector: + vardef = '%s(len=%s' % (vardef, selector['len']) + if 'kind' in selector: + vardef = '%s,kind=%s)' % (vardef, selector['kind']) + else: + vardef = '%s)' % (vardef) + elif 'kind' in selector: + vardef = '%s(kind=%s)' % (vardef, selector['kind']) + c = ' ' + if 'attrspec' in vars[a]: + attr = [] + for l in vars[a]['attrspec']: + if l not in ['external']: + attr.append(l) + if attr: + vardef = '%s, %s' % (vardef, ','.join(attr)) + c = ',' + if 'dimension' in vars[a]: + vardef = '%s%sdimension(%s)' % ( + vardef, c, ','.join(vars[a]['dimension'])) + c = ',' + if 'intent' in vars[a]: + lst = true_intent_list(vars[a]) + if lst: + vardef = '%s%sintent(%s)' % (vardef, c, ','.join(lst)) + c = ',' + if 'check' in vars[a]: + vardef = '%s%scheck(%s)' % (vardef, c, ','.join(vars[a]['check'])) + c = ',' + if 'depend' in vars[a]: + vardef = '%s%sdepend(%s)' % ( + vardef, c, ','.join(vars[a]['depend'])) + c = ',' + if '=' in vars[a]: + v = vars[a]['='] + if vars[a]['typespec'] in ['complex', 'double complex']: + try: + v = eval(v) + v = '(%s,%s)' % (v.real, v.imag) + except Exception: + pass + vardef = '%s :: %s=%s' % (vardef, a, v) + else: + vardef = '%s :: %s' % (vardef, a) + ret = '%s%s%s' % (ret, tab, vardef) + return ret +###### + + +def crackfortran(files): + global usermodules + + outmess('Reading fortran codes...\n', 0) + readfortrancode(files, crackline) + outmess('Post-processing...\n', 0) + usermodules = [] + postlist = postcrack(grouplist[0]) + outmess('Post-processing (stage 2)...\n', 0) + postlist = postcrack2(postlist) + return usermodules + postlist + + +def crack2fortran(block): + global f2py_version + + pyf = crack2fortrangen(block) + '\n' + header = """! -*- f90 -*- +! Note: the context of this file is case sensitive. +""" + footer = """ +! This file was auto-generated with f2py (version:%s). +! See http://cens.ioc.ee/projects/f2py2e/ +""" % (f2py_version) + return header + pyf + footer + +if __name__ == "__main__": + files = [] + funcs = [] + f = 1 + f2 = 0 + f3 = 0 + showblocklist = 0 + for l in sys.argv[1:]: + if l == '': + pass + elif l[0] == ':': + f = 0 + elif l == '-quiet': + quiet = 1 + verbose = 0 + elif l == '-verbose': + verbose = 2 + quiet = 0 + elif l == '-fix': + if strictf77: + outmess( + 'Use option -f90 before -fix if Fortran 90 code is in fix form.\n', 0) + skipemptyends = 1 + sourcecodeform = 'fix' + elif l == '-skipemptyends': + skipemptyends = 1 + elif l == '--ignore-contains': + ignorecontains = 1 + elif l == '-f77': + strictf77 = 1 + sourcecodeform = 'fix' + elif l == '-f90': + strictf77 = 0 + sourcecodeform = 'free' + skipemptyends = 1 + elif l == '-h': + f2 = 1 + elif l == '-show': + showblocklist = 1 + elif l == '-m': + f3 = 1 + elif l[0] == '-': + errmess('Unknown option %s\n' % repr(l)) + elif f2: + f2 = 0 + pyffilename = l + elif f3: + f3 = 0 + f77modulename = l + elif f: + try: + open(l).close() + files.append(l) + except IOError as detail: + errmess('IOError: %s\n' % str(detail)) + else: + funcs.append(l) + if not strictf77 and f77modulename and not skipemptyends: + outmess("""\ + Warning: You have specifyied module name for non Fortran 77 code + that should not need one (expect if you are scanning F90 code + for non module blocks but then you should use flag -skipemptyends + and also be sure that the files do not contain programs without program statement). +""", 0) + + postlist = crackfortran(files, funcs) + if pyffilename: + outmess('Writing fortran code to file %s\n' % repr(pyffilename), 0) + pyf = crack2fortran(postlist) + with open(pyffilename, 'w') as f: + f.write(pyf) + if showblocklist: + show(postlist) diff --git a/numpy/f2py/diagnose.py b/numpy/f2py/diagnose.py new file mode 100644 index 0000000..0241fed --- /dev/null +++ b/numpy/f2py/diagnose.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python +from __future__ import division, absolute_import, print_function + +import os +import sys +import tempfile + + +def run_command(cmd): + print('Running %r:' % (cmd)) + os.system(cmd) + print('------') + + +def run(): + _path = os.getcwd() + os.chdir(tempfile.gettempdir()) + print('------') + print('os.name=%r' % (os.name)) + print('------') + print('sys.platform=%r' % (sys.platform)) + print('------') + print('sys.version:') + print(sys.version) + print('------') + print('sys.prefix:') + print(sys.prefix) + print('------') + print('sys.path=%r' % (':'.join(sys.path))) + print('------') + + try: + import numpy + has_newnumpy = 1 + except ImportError: + print('Failed to import new numpy:', sys.exc_info()[1]) + has_newnumpy = 0 + + try: + from numpy.f2py import f2py2e + has_f2py2e = 1 + except ImportError: + print('Failed to import f2py2e:', sys.exc_info()[1]) + has_f2py2e = 0 + + try: + import numpy.distutils + has_numpy_distutils = 2 + except ImportError: + try: + import numpy_distutils + has_numpy_distutils = 1 + except ImportError: + print('Failed to import numpy_distutils:', sys.exc_info()[1]) + has_numpy_distutils = 0 + + if has_newnumpy: + try: + print('Found new numpy version %r in %s' % + (numpy.__version__, numpy.__file__)) + except Exception as msg: + print('error:', msg) + print('------') + + if has_f2py2e: + try: + print('Found f2py2e version %r in %s' % + (f2py2e.__version__.version, f2py2e.__file__)) + except Exception as msg: + print('error:', msg) + print('------') + + if has_numpy_distutils: + try: + if has_numpy_distutils == 2: + print('Found numpy.distutils version %r in %r' % ( + numpy.distutils.__version__, + numpy.distutils.__file__)) + else: + print('Found numpy_distutils version %r in %r' % ( + numpy_distutils.numpy_distutils_version.numpy_distutils_version, + numpy_distutils.__file__)) + print('------') + except Exception as msg: + print('error:', msg) + print('------') + try: + if has_numpy_distutils == 1: + print( + 'Importing numpy_distutils.command.build_flib ...', end=' ') + import numpy_distutils.command.build_flib as build_flib + print('ok') + print('------') + try: + print( + 'Checking availability of supported Fortran compilers:') + for compiler_class in build_flib.all_compilers: + compiler_class(verbose=1).is_available() + print('------') + except Exception as msg: + print('error:', msg) + print('------') + except Exception as msg: + print( + 'error:', msg, '(ignore it, build_flib is obsolute for numpy.distutils 0.2.2 and up)') + print('------') + try: + if has_numpy_distutils == 2: + print('Importing numpy.distutils.fcompiler ...', end=' ') + import numpy.distutils.fcompiler as fcompiler + else: + print('Importing numpy_distutils.fcompiler ...', end=' ') + import numpy_distutils.fcompiler as fcompiler + print('ok') + print('------') + try: + print('Checking availability of supported Fortran compilers:') + fcompiler.show_fcompilers() + print('------') + except Exception as msg: + print('error:', msg) + print('------') + except Exception as msg: + print('error:', msg) + print('------') + try: + if has_numpy_distutils == 2: + print('Importing numpy.distutils.cpuinfo ...', end=' ') + from numpy.distutils.cpuinfo import cpuinfo + print('ok') + print('------') + else: + try: + print( + 'Importing numpy_distutils.command.cpuinfo ...', end=' ') + from numpy_distutils.command.cpuinfo import cpuinfo + print('ok') + print('------') + except Exception as msg: + print('error:', msg, '(ignore it)') + print('Importing numpy_distutils.cpuinfo ...', end=' ') + from numpy_distutils.cpuinfo import cpuinfo + print('ok') + print('------') + cpu = cpuinfo() + print('CPU information:', end=' ') + for name in dir(cpuinfo): + if name[0] == '_' and name[1] != '_' and getattr(cpu, name[1:])(): + print(name[1:], end=' ') + print('------') + except Exception as msg: + print('error:', msg) + print('------') + os.chdir(_path) +if __name__ == "__main__": + run() diff --git a/numpy/f2py/f2py2e.py b/numpy/f2py/f2py2e.py new file mode 100755 index 0000000..254f999 --- /dev/null +++ b/numpy/f2py/f2py2e.py @@ -0,0 +1,656 @@ +#!/usr/bin/env python +""" + +f2py2e - Fortran to Python C/API generator. 2nd Edition. + See __usage__ below. + +Copyright 1999--2011 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/05/06 08:31:19 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +import sys +import os +import pprint +import re + +from . import crackfortran +from . import rules +from . import cb_rules +from . import auxfuncs +from . import cfuncs +from . import f90mod_rules +from . import __version__ + +f2py_version = __version__.version +errmess = sys.stderr.write +# outmess=sys.stdout.write +show = pprint.pprint +outmess = auxfuncs.outmess + +try: + from numpy import __version__ as numpy_version +except ImportError: + numpy_version = 'N/A' + +__usage__ = """\ +Usage: + +1) To construct extension module sources: + + f2py [] [[[only:]||[skip:]] \\ + ] \\ + [: ...] + +2) To compile fortran files and build extension modules: + + f2py -c [, , ] + +3) To generate signature files: + + f2py -h ...< same options as in (1) > + +Description: This program generates a Python C/API file (module.c) + that contains wrappers for given fortran functions so that they + can be called from Python. With the -c option the corresponding + extension modules are built. + +Options: + + --2d-numpy Use numpy.f2py tool with NumPy support. [DEFAULT] + --2d-numeric Use f2py2e tool with Numeric support. + --2d-numarray Use f2py2e tool with Numarray support. + --g3-numpy Use 3rd generation f2py from the separate f2py package. + [NOT AVAILABLE YET] + + -h Write signatures of the fortran routines to file + and exit. You can then edit and use it instead + of . If ==stdout then the + signatures are printed to stdout. + Names of fortran routines for which Python C/API + functions will be generated. Default is all that are found + in . + Paths to fortran/signature files that will be scanned for + in order to determine their signatures. + skip: Ignore fortran functions that follow until `:'. + only: Use only fortran functions that follow until `:'. + : Get back to mode. + + -m Name of the module; f2py generates a Python/C API + file module.c or extension module . + Default is 'untitled'. + + --[no-]lower Do [not] lower the cases in . By default, + --lower is assumed with -h key, and --no-lower without -h key. + + --build-dir All f2py generated files are created in . + Default is tempfile.mkdtemp(). + + --overwrite-signature Overwrite existing signature file. + + --[no-]latex-doc Create (or not) module.tex. + Default is --no-latex-doc. + --short-latex Create 'incomplete' LaTeX document (without commands + \\documentclass, \\tableofcontents, and \\begin{document}, + \\end{document}). + + --[no-]rest-doc Create (or not) module.rst. + Default is --no-rest-doc. + + --debug-capi Create C/API code that reports the state of the wrappers + during runtime. Useful for debugging. + + --[no-]wrap-functions Create Fortran subroutine wrappers to Fortran 77 + functions. --wrap-functions is default because it ensures + maximum portability/compiler independence. + + --include-paths ::... Search include files from the given + directories. + + --help-link [..] List system resources found by system_info.py. See also + --link- switch below. [..] is optional list + of resources names. E.g. try 'f2py --help-link lapack_opt'. + + --quiet Run quietly. + --verbose Run with extra verbosity. + -v Print f2py version ID and exit. + + +numpy.distutils options (only effective with -c): + + --fcompiler= Specify Fortran compiler type by vendor + --compiler= Specify C compiler type (as defined by distutils) + + --help-fcompiler List available Fortran compilers and exit + --f77exec= Specify the path to F77 compiler + --f90exec= Specify the path to F90 compiler + --f77flags= Specify F77 compiler flags + --f90flags= Specify F90 compiler flags + --opt= Specify optimization flags + --arch= Specify architecture specific optimization flags + --noopt Compile without optimization + --noarch Compile without arch-dependent optimization + --debug Compile with debugging information + +Extra options (only effective with -c): + + --link- Link extension module with as defined + by numpy.distutils/system_info.py. E.g. to link + with optimized LAPACK libraries (vecLib on MacOSX, + ATLAS elsewhere), use --link-lapack_opt. + See also --help-link switch. + + -L/path/to/lib/ -l + -D -U + -I/path/to/include/ + .o .so .a + + Using the following macros may be required with non-gcc Fortran + compilers: + -DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN + -DUNDERSCORE_G77 + + When using -DF2PY_REPORT_ATEXIT, a performance report of F2PY + interface is printed out at exit (platforms: Linux). + + When using -DF2PY_REPORT_ON_ARRAY_COPY=, a message is + sent to stderr whenever F2PY interface makes a copy of an + array. Integer sets the threshold for array sizes when + a message should be shown. + +Version: %s +numpy Version: %s +Requires: Python 2.3 or higher. +License: NumPy license (see LICENSE.txt in the NumPy source code) +Copyright 1999 - 2011 Pearu Peterson all rights reserved. +http://cens.ioc.ee/projects/f2py2e/""" % (f2py_version, numpy_version) + + +def scaninputline(inputline): + files, skipfuncs, onlyfuncs, debug = [], [], [], [] + f, f2, f3, f5, f6, f7, f8, f9 = 1, 0, 0, 0, 0, 0, 0, 0 + verbose = 1 + dolc = -1 + dolatexdoc = 0 + dorestdoc = 0 + wrapfuncs = 1 + buildpath = '.' + include_paths = [] + signsfile, modulename = None, None + options = {'buildpath': buildpath, + 'coutput': None, + 'f2py_wrapper_output': None} + for l in inputline: + if l == '': + pass + elif l == 'only:': + f = 0 + elif l == 'skip:': + f = -1 + elif l == ':': + f = 1 + elif l[:8] == '--debug-': + debug.append(l[8:]) + elif l == '--lower': + dolc = 1 + elif l == '--build-dir': + f6 = 1 + elif l == '--no-lower': + dolc = 0 + elif l == '--quiet': + verbose = 0 + elif l == '--verbose': + verbose += 1 + elif l == '--latex-doc': + dolatexdoc = 1 + elif l == '--no-latex-doc': + dolatexdoc = 0 + elif l == '--rest-doc': + dorestdoc = 1 + elif l == '--no-rest-doc': + dorestdoc = 0 + elif l == '--wrap-functions': + wrapfuncs = 1 + elif l == '--no-wrap-functions': + wrapfuncs = 0 + elif l == '--short-latex': + options['shortlatex'] = 1 + elif l == '--coutput': + f8 = 1 + elif l == '--f2py-wrapper-output': + f9 = 1 + elif l == '--overwrite-signature': + options['h-overwrite'] = 1 + elif l == '-h': + f2 = 1 + elif l == '-m': + f3 = 1 + elif l[:2] == '-v': + print(f2py_version) + sys.exit() + elif l == '--show-compilers': + f5 = 1 + elif l[:8] == '-include': + cfuncs.outneeds['userincludes'].append(l[9:-1]) + cfuncs.userincludes[l[9:-1]] = '#include ' + l[8:] + elif l[:15] in '--include_paths': + outmess( + 'f2py option --include_paths is deprecated, use --include-paths instead.\n') + f7 = 1 + elif l[:15] in '--include-paths': + f7 = 1 + elif l[0] == '-': + errmess('Unknown option %s\n' % repr(l)) + sys.exit() + elif f2: + f2 = 0 + signsfile = l + elif f3: + f3 = 0 + modulename = l + elif f6: + f6 = 0 + buildpath = l + elif f7: + f7 = 0 + include_paths.extend(l.split(os.pathsep)) + elif f8: + f8 = 0 + options["coutput"] = l + elif f9: + f9 = 0 + options["f2py_wrapper_output"] = l + elif f == 1: + try: + open(l).close() + files.append(l) + except IOError as detail: + errmess('IOError: %s. Skipping file "%s".\n' % + (str(detail), l)) + elif f == -1: + skipfuncs.append(l) + elif f == 0: + onlyfuncs.append(l) + if not f5 and not files and not modulename: + print(__usage__) + sys.exit() + if not os.path.isdir(buildpath): + if not verbose: + outmess('Creating build directory %s' % (buildpath)) + os.mkdir(buildpath) + if signsfile: + signsfile = os.path.join(buildpath, signsfile) + if signsfile and os.path.isfile(signsfile) and 'h-overwrite' not in options: + errmess( + 'Signature file "%s" exists!!! Use --overwrite-signature to overwrite.\n' % (signsfile)) + sys.exit() + + options['debug'] = debug + options['verbose'] = verbose + if dolc == -1 and not signsfile: + options['do-lower'] = 0 + else: + options['do-lower'] = dolc + if modulename: + options['module'] = modulename + if signsfile: + options['signsfile'] = signsfile + if onlyfuncs: + options['onlyfuncs'] = onlyfuncs + if skipfuncs: + options['skipfuncs'] = skipfuncs + options['dolatexdoc'] = dolatexdoc + options['dorestdoc'] = dorestdoc + options['wrapfuncs'] = wrapfuncs + options['buildpath'] = buildpath + options['include_paths'] = include_paths + return files, options + + +def callcrackfortran(files, options): + rules.options = options + crackfortran.debug = options['debug'] + crackfortran.verbose = options['verbose'] + if 'module' in options: + crackfortran.f77modulename = options['module'] + if 'skipfuncs' in options: + crackfortran.skipfuncs = options['skipfuncs'] + if 'onlyfuncs' in options: + crackfortran.onlyfuncs = options['onlyfuncs'] + crackfortran.include_paths[:] = options['include_paths'] + crackfortran.dolowercase = options['do-lower'] + postlist = crackfortran.crackfortran(files) + if 'signsfile' in options: + outmess('Saving signatures to file "%s"\n' % (options['signsfile'])) + pyf = crackfortran.crack2fortran(postlist) + if options['signsfile'][-6:] == 'stdout': + sys.stdout.write(pyf) + else: + f = open(options['signsfile'], 'w') + f.write(pyf) + f.close() + if options["coutput"] is None: + for mod in postlist: + mod["coutput"] = "%smodule.c" % mod["name"] + else: + for mod in postlist: + mod["coutput"] = options["coutput"] + if options["f2py_wrapper_output"] is None: + for mod in postlist: + mod["f2py_wrapper_output"] = "%s-f2pywrappers.f" % mod["name"] + else: + for mod in postlist: + mod["f2py_wrapper_output"] = options["f2py_wrapper_output"] + return postlist + + +def buildmodules(lst): + cfuncs.buildcfuncs() + outmess('Building modules...\n') + modules, mnames, isusedby = [], [], {} + for i in range(len(lst)): + if '__user__' in lst[i]['name']: + cb_rules.buildcallbacks(lst[i]) + else: + if 'use' in lst[i]: + for u in lst[i]['use'].keys(): + if u not in isusedby: + isusedby[u] = [] + isusedby[u].append(lst[i]['name']) + modules.append(lst[i]) + mnames.append(lst[i]['name']) + ret = {} + for i in range(len(mnames)): + if mnames[i] in isusedby: + outmess('\tSkipping module "%s" which is used by %s.\n' % ( + mnames[i], ','.join(['"%s"' % s for s in isusedby[mnames[i]]]))) + else: + um = [] + if 'use' in modules[i]: + for u in modules[i]['use'].keys(): + if u in isusedby and u in mnames: + um.append(modules[mnames.index(u)]) + else: + outmess( + '\tModule "%s" uses nonexisting "%s" which will be ignored.\n' % (mnames[i], u)) + ret[mnames[i]] = {} + dict_append(ret[mnames[i]], rules.buildmodule(modules[i], um)) + return ret + + +def dict_append(d_out, d_in): + for (k, v) in d_in.items(): + if k not in d_out: + d_out[k] = [] + if isinstance(v, list): + d_out[k] = d_out[k] + v + else: + d_out[k].append(v) + + +def run_main(comline_list): + """Run f2py as if string.join(comline_list,' ') is used as a command line. + In case of using -h flag, return None. + """ + crackfortran.reset_global_f2py_vars() + f2pydir = os.path.dirname(os.path.abspath(cfuncs.__file__)) + fobjhsrc = os.path.join(f2pydir, 'src', 'fortranobject.h') + fobjcsrc = os.path.join(f2pydir, 'src', 'fortranobject.c') + files, options = scaninputline(comline_list) + auxfuncs.options = options + postlist = callcrackfortran(files, options) + isusedby = {} + for i in range(len(postlist)): + if 'use' in postlist[i]: + for u in postlist[i]['use'].keys(): + if u not in isusedby: + isusedby[u] = [] + isusedby[u].append(postlist[i]['name']) + for i in range(len(postlist)): + if postlist[i]['block'] == 'python module' and '__user__' in postlist[i]['name']: + if postlist[i]['name'] in isusedby: + # if not quiet: + outmess('Skipping Makefile build for module "%s" which is used by %s\n' % ( + postlist[i]['name'], ','.join(['"%s"' % s for s in isusedby[postlist[i]['name']]]))) + if 'signsfile' in options: + if options['verbose'] > 1: + outmess( + 'Stopping. Edit the signature file and then run f2py on the signature file: ') + outmess('%s %s\n' % + (os.path.basename(sys.argv[0]), options['signsfile'])) + return + for i in range(len(postlist)): + if postlist[i]['block'] != 'python module': + if 'python module' not in options: + errmess( + 'Tip: If your original code is Fortran source then you must use -m option.\n') + raise TypeError('All blocks must be python module blocks but got %s' % ( + repr(postlist[i]['block']))) + auxfuncs.debugoptions = options['debug'] + f90mod_rules.options = options + auxfuncs.wrapfuncs = options['wrapfuncs'] + + ret = buildmodules(postlist) + + for mn in ret.keys(): + dict_append(ret[mn], {'csrc': fobjcsrc, 'h': fobjhsrc}) + return ret + + +def filter_files(prefix, suffix, files, remove_prefix=None): + """ + Filter files by prefix and suffix. + """ + filtered, rest = [], [] + match = re.compile(prefix + r'.*' + suffix + r'\Z').match + if remove_prefix: + ind = len(prefix) + else: + ind = 0 + for file in [x.strip() for x in files]: + if match(file): + filtered.append(file[ind:]) + else: + rest.append(file) + return filtered, rest + + +def get_prefix(module): + p = os.path.dirname(os.path.dirname(module.__file__)) + return p + + +def run_compile(): + """ + Do it all in one call! + """ + import tempfile + + i = sys.argv.index('-c') + del sys.argv[i] + + remove_build_dir = 0 + try: + i = sys.argv.index('--build-dir') + except ValueError: + i = None + if i is not None: + build_dir = sys.argv[i + 1] + del sys.argv[i + 1] + del sys.argv[i] + else: + remove_build_dir = 1 + build_dir = tempfile.mkdtemp() + + _reg1 = re.compile(r'[-][-]link[-]') + sysinfo_flags = [_m for _m in sys.argv[1:] if _reg1.match(_m)] + sys.argv = [_m for _m in sys.argv if _m not in sysinfo_flags] + if sysinfo_flags: + sysinfo_flags = [f[7:] for f in sysinfo_flags] + + _reg2 = re.compile( + r'[-][-]((no[-]|)(wrap[-]functions|lower)|debug[-]capi|quiet)|[-]include') + f2py_flags = [_m for _m in sys.argv[1:] if _reg2.match(_m)] + sys.argv = [_m for _m in sys.argv if _m not in f2py_flags] + f2py_flags2 = [] + fl = 0 + for a in sys.argv[1:]: + if a in ['only:', 'skip:']: + fl = 1 + elif a == ':': + fl = 0 + if fl or a == ':': + f2py_flags2.append(a) + if f2py_flags2 and f2py_flags2[-1] != ':': + f2py_flags2.append(':') + f2py_flags.extend(f2py_flags2) + + sys.argv = [_m for _m in sys.argv if _m not in f2py_flags2] + _reg3 = re.compile( + r'[-][-]((f(90)?compiler([-]exec|)|compiler)=|help[-]compiler)') + flib_flags = [_m for _m in sys.argv[1:] if _reg3.match(_m)] + sys.argv = [_m for _m in sys.argv if _m not in flib_flags] + _reg4 = re.compile( + r'[-][-]((f(77|90)(flags|exec)|opt|arch)=|(debug|noopt|noarch|help[-]fcompiler))') + fc_flags = [_m for _m in sys.argv[1:] if _reg4.match(_m)] + sys.argv = [_m for _m in sys.argv if _m not in fc_flags] + + if 1: + del_list = [] + for s in flib_flags: + v = '--fcompiler=' + if s[:len(v)] == v: + from numpy.distutils import fcompiler + fcompiler.load_all_fcompiler_classes() + allowed_keys = list(fcompiler.fcompiler_class.keys()) + nv = ov = s[len(v):].lower() + if ov not in allowed_keys: + vmap = {} # XXX + try: + nv = vmap[ov] + except KeyError: + if ov not in vmap.values(): + print('Unknown vendor: "%s"' % (s[len(v):])) + nv = ov + i = flib_flags.index(s) + flib_flags[i] = '--fcompiler=' + nv + continue + for s in del_list: + i = flib_flags.index(s) + del flib_flags[i] + assert len(flib_flags) <= 2, repr(flib_flags) + + _reg5 = re.compile(r'[-][-](verbose)') + setup_flags = [_m for _m in sys.argv[1:] if _reg5.match(_m)] + sys.argv = [_m for _m in sys.argv if _m not in setup_flags] + + if '--quiet' in f2py_flags: + setup_flags.append('--quiet') + + modulename = 'untitled' + sources = sys.argv[1:] + + for optname in ['--include_paths', '--include-paths']: + if optname in sys.argv: + i = sys.argv.index(optname) + f2py_flags.extend(sys.argv[i:i + 2]) + del sys.argv[i + 1], sys.argv[i] + sources = sys.argv[1:] + + if '-m' in sys.argv: + i = sys.argv.index('-m') + modulename = sys.argv[i + 1] + del sys.argv[i + 1], sys.argv[i] + sources = sys.argv[1:] + else: + from numpy.distutils.command.build_src import get_f2py_modulename + pyf_files, sources = filter_files('', '[.]pyf([.]src|)', sources) + sources = pyf_files + sources + for f in pyf_files: + modulename = get_f2py_modulename(f) + if modulename: + break + + extra_objects, sources = filter_files('', '[.](o|a|so)', sources) + include_dirs, sources = filter_files('-I', '', sources, remove_prefix=1) + library_dirs, sources = filter_files('-L', '', sources, remove_prefix=1) + libraries, sources = filter_files('-l', '', sources, remove_prefix=1) + undef_macros, sources = filter_files('-U', '', sources, remove_prefix=1) + define_macros, sources = filter_files('-D', '', sources, remove_prefix=1) + for i in range(len(define_macros)): + name_value = define_macros[i].split('=', 1) + if len(name_value) == 1: + name_value.append(None) + if len(name_value) == 2: + define_macros[i] = tuple(name_value) + else: + print('Invalid use of -D:', name_value) + + from numpy.distutils.system_info import get_info + + num_info = {} + if num_info: + include_dirs.extend(num_info.get('include_dirs', [])) + + from numpy.distutils.core import setup, Extension + ext_args = {'name': modulename, 'sources': sources, + 'include_dirs': include_dirs, + 'library_dirs': library_dirs, + 'libraries': libraries, + 'define_macros': define_macros, + 'undef_macros': undef_macros, + 'extra_objects': extra_objects, + 'f2py_options': f2py_flags, + } + + if sysinfo_flags: + from numpy.distutils.misc_util import dict_append + for n in sysinfo_flags: + i = get_info(n) + if not i: + outmess('No %s resources found in system' + ' (try `f2py --help-link`)\n' % (repr(n))) + dict_append(ext_args, **i) + + ext = Extension(**ext_args) + sys.argv = [sys.argv[0]] + setup_flags + sys.argv.extend(['build', + '--build-temp', build_dir, + '--build-base', build_dir, + '--build-platlib', '.']) + if fc_flags: + sys.argv.extend(['config_fc'] + fc_flags) + if flib_flags: + sys.argv.extend(['build_ext'] + flib_flags) + + setup(ext_modules=[ext]) + + if remove_build_dir and os.path.exists(build_dir): + import shutil + outmess('Removing build directory %s\n' % (build_dir)) + shutil.rmtree(build_dir) + + +def main(): + if '--help-link' in sys.argv[1:]: + sys.argv.remove('--help-link') + from numpy.distutils.system_info import show_all + show_all() + return + if '-c' in sys.argv[1:]: + run_compile() + else: + run_main(sys.argv[1:]) + +# if __name__ == "__main__": +# main() + + +# EOF diff --git a/numpy/f2py/f2py_testing.py b/numpy/f2py/f2py_testing.py new file mode 100644 index 0000000..f5d5fa6 --- /dev/null +++ b/numpy/f2py/f2py_testing.py @@ -0,0 +1,48 @@ +from __future__ import division, absolute_import, print_function + +import sys +import re + +from numpy.testing import jiffies, memusage + + +def cmdline(): + m = re.compile(r'\A\d+\Z') + args = [] + repeat = 1 + for a in sys.argv[1:]: + if m.match(a): + repeat = eval(a) + else: + args.append(a) + f2py_opts = ' '.join(args) + return repeat, f2py_opts + + +def run(runtest, test_functions, repeat=1): + l = [(t, repr(t.__doc__.split('\n')[1].strip())) for t in test_functions] + start_memusage = memusage() + diff_memusage = None + start_jiffies = jiffies() + i = 0 + while i < repeat: + i += 1 + for t, fname in l: + runtest(t) + if start_memusage is None: + continue + if diff_memusage is None: + diff_memusage = memusage() - start_memusage + else: + diff_memusage2 = memusage() - start_memusage + if diff_memusage2 != diff_memusage: + print('memory usage change at step %i:' % i, + diff_memusage2 - diff_memusage, + fname) + diff_memusage = diff_memusage2 + current_memusage = memusage() + print('run', repeat * len(test_functions), 'tests', + 'in %.2f seconds' % ((jiffies() - start_jiffies) / 100.0)) + if start_memusage: + print('initial virtual memory size:', start_memusage, 'bytes') + print('current virtual memory size:', current_memusage, 'bytes') diff --git a/numpy/f2py/f90mod_rules.py b/numpy/f2py/f90mod_rules.py new file mode 100644 index 0000000..85eae80 --- /dev/null +++ b/numpy/f2py/f90mod_rules.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python +""" + +Build F90 module support for f2py2e. + +Copyright 2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/02/03 19:30:23 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +__version__ = "$Revision: 1.27 $"[10:-1] + +f2py_version = 'See `f2py -v`' + +import numpy as np + +from . import capi_maps +from . import func2subr +from .crackfortran import undo_rmbadname, undo_rmbadname1 + +# The eviroment provided by auxfuncs.py is needed for some calls to eval. +# As the needed functions cannot be determined by static inspection of the +# code, it is safest to use import * pending a major refactoring of f2py. +from .auxfuncs import * + +options = {} + + +def findf90modules(m): + if ismodule(m): + return [m] + if not hasbody(m): + return [] + ret = [] + for b in m['body']: + if ismodule(b): + ret.append(b) + else: + ret = ret + findf90modules(b) + return ret + +fgetdims1 = """\ + external f2pysetdata + logical ns + integer r,i + integer(%d) s(*) + ns = .FALSE. + if (allocated(d)) then + do i=1,r + if ((size(d,i).ne.s(i)).and.(s(i).ge.0)) then + ns = .TRUE. + end if + end do + if (ns) then + deallocate(d) + end if + end if + if ((.not.allocated(d)).and.(s(1).ge.1)) then""" % np.intp().itemsize + +fgetdims2 = """\ + end if + if (allocated(d)) then + do i=1,r + s(i) = size(d,i) + end do + end if + flag = 1 + call f2pysetdata(d,allocated(d))""" + +fgetdims2_sa = """\ + end if + if (allocated(d)) then + do i=1,r + s(i) = size(d,i) + end do + !s(r) must be equal to len(d(1)) + end if + flag = 2 + call f2pysetdata(d,allocated(d))""" + + +def buildhooks(pymod): + global fgetdims1, fgetdims2 + from . import rules + ret = {'f90modhooks': [], 'initf90modhooks': [], 'body': [], + 'need': ['F_FUNC', 'arrayobject.h'], + 'separatorsfor': {'includes0': '\n', 'includes': '\n'}, + 'docs': ['"Fortran 90/95 modules:\\n"'], + 'latexdoc': []} + fhooks = [''] + + def fadd(line, s=fhooks): + s[0] = '%s\n %s' % (s[0], line) + doc = [''] + + def dadd(line, s=doc): + s[0] = '%s\n%s' % (s[0], line) + for m in findf90modules(pymod): + sargs, fargs, efargs, modobjs, notvars, onlyvars = [], [], [], [], [ + m['name']], [] + sargsp = [] + ifargs = [] + mfargs = [] + if hasbody(m): + for b in m['body']: + notvars.append(b['name']) + for n in m['vars'].keys(): + var = m['vars'][n] + if (n not in notvars) and (not l_or(isintent_hide, isprivate)(var)): + onlyvars.append(n) + mfargs.append(n) + outmess('\t\tConstructing F90 module support for "%s"...\n' % + (m['name'])) + if onlyvars: + outmess('\t\t Variables: %s\n' % (' '.join(onlyvars))) + chooks = [''] + + def cadd(line, s=chooks): + s[0] = '%s\n%s' % (s[0], line) + ihooks = [''] + + def iadd(line, s=ihooks): + s[0] = '%s\n%s' % (s[0], line) + + vrd = capi_maps.modsign2map(m) + cadd('static FortranDataDef f2py_%s_def[] = {' % (m['name'])) + dadd('\\subsection{Fortran 90/95 module \\texttt{%s}}\n' % (m['name'])) + if hasnote(m): + note = m['note'] + if isinstance(note, list): + note = '\n'.join(note) + dadd(note) + if onlyvars: + dadd('\\begin{description}') + for n in onlyvars: + var = m['vars'][n] + modobjs.append(n) + ct = capi_maps.getctype(var) + at = capi_maps.c2capi_map[ct] + dm = capi_maps.getarrdims(n, var) + dms = dm['dims'].replace('*', '-1').strip() + dms = dms.replace(':', '-1').strip() + if not dms: + dms = '-1' + use_fgetdims2 = fgetdims2 + if isstringarray(var): + if 'charselector' in var and 'len' in var['charselector']: + cadd('\t{"%s",%s,{{%s,%s}},%s},' + % (undo_rmbadname1(n), dm['rank'], dms, var['charselector']['len'], at)) + use_fgetdims2 = fgetdims2_sa + else: + cadd('\t{"%s",%s,{{%s}},%s},' % + (undo_rmbadname1(n), dm['rank'], dms, at)) + else: + cadd('\t{"%s",%s,{{%s}},%s},' % + (undo_rmbadname1(n), dm['rank'], dms, at)) + dadd('\\item[]{{}\\verb@%s@{}}' % + (capi_maps.getarrdocsign(n, var))) + if hasnote(var): + note = var['note'] + if isinstance(note, list): + note = '\n'.join(note) + dadd('--- %s' % (note)) + if isallocatable(var): + fargs.append('f2py_%s_getdims_%s' % (m['name'], n)) + efargs.append(fargs[-1]) + sargs.append( + 'void (*%s)(int*,int*,void(*)(char*,int*),int*)' % (n)) + sargsp.append('void (*)(int*,int*,void(*)(char*,int*),int*)') + iadd('\tf2py_%s_def[i_f2py++].func = %s;' % (m['name'], n)) + fadd('subroutine %s(r,s,f2pysetdata,flag)' % (fargs[-1])) + fadd('use %s, only: d => %s\n' % + (m['name'], undo_rmbadname1(n))) + fadd('integer flag\n') + fhooks[0] = fhooks[0] + fgetdims1 + dms = eval('range(1,%s+1)' % (dm['rank'])) + fadd(' allocate(d(%s))\n' % + (','.join(['s(%s)' % i for i in dms]))) + fhooks[0] = fhooks[0] + use_fgetdims2 + fadd('end subroutine %s' % (fargs[-1])) + else: + fargs.append(n) + sargs.append('char *%s' % (n)) + sargsp.append('char*') + iadd('\tf2py_%s_def[i_f2py++].data = %s;' % (m['name'], n)) + if onlyvars: + dadd('\\end{description}') + if hasbody(m): + for b in m['body']: + if not isroutine(b): + print('Skipping', b['block'], b['name']) + continue + modobjs.append('%s()' % (b['name'])) + b['modulename'] = m['name'] + api, wrap = rules.buildapi(b) + if isfunction(b): + fhooks[0] = fhooks[0] + wrap + fargs.append('f2pywrap_%s_%s' % (m['name'], b['name'])) + ifargs.append(func2subr.createfuncwrapper(b, signature=1)) + else: + if wrap: + fhooks[0] = fhooks[0] + wrap + fargs.append('f2pywrap_%s_%s' % (m['name'], b['name'])) + ifargs.append( + func2subr.createsubrwrapper(b, signature=1)) + else: + fargs.append(b['name']) + mfargs.append(fargs[-1]) + api['externroutines'] = [] + ar = applyrules(api, vrd) + ar['docs'] = [] + ar['docshort'] = [] + ret = dictappend(ret, ar) + cadd('\t{"%s",-1,{{-1}},0,NULL,(void *)f2py_rout_#modulename#_%s_%s,doc_f2py_rout_#modulename#_%s_%s},' % + (b['name'], m['name'], b['name'], m['name'], b['name'])) + sargs.append('char *%s' % (b['name'])) + sargsp.append('char *') + iadd('\tf2py_%s_def[i_f2py++].data = %s;' % + (m['name'], b['name'])) + cadd('\t{NULL}\n};\n') + iadd('}') + ihooks[0] = 'static void f2py_setup_%s(%s) {\n\tint i_f2py=0;%s' % ( + m['name'], ','.join(sargs), ihooks[0]) + if '_' in m['name']: + F_FUNC = 'F_FUNC_US' + else: + F_FUNC = 'F_FUNC' + iadd('extern void %s(f2pyinit%s,F2PYINIT%s)(void (*)(%s));' + % (F_FUNC, m['name'], m['name'].upper(), ','.join(sargsp))) + iadd('static void f2py_init_%s(void) {' % (m['name'])) + iadd('\t%s(f2pyinit%s,F2PYINIT%s)(f2py_setup_%s);' + % (F_FUNC, m['name'], m['name'].upper(), m['name'])) + iadd('}\n') + ret['f90modhooks'] = ret['f90modhooks'] + chooks + ihooks + ret['initf90modhooks'] = ['\tPyDict_SetItemString(d, "%s", PyFortranObject_New(f2py_%s_def,f2py_init_%s));' % ( + m['name'], m['name'], m['name'])] + ret['initf90modhooks'] + fadd('') + fadd('subroutine f2pyinit%s(f2pysetupfunc)' % (m['name'])) + if mfargs: + for a in undo_rmbadname(mfargs): + fadd('use %s, only : %s' % (m['name'], a)) + if ifargs: + fadd(' '.join(['interface'] + ifargs)) + fadd('end interface') + fadd('external f2pysetupfunc') + if efargs: + for a in undo_rmbadname(efargs): + fadd('external %s' % (a)) + fadd('call f2pysetupfunc(%s)' % (','.join(undo_rmbadname(fargs)))) + fadd('end subroutine f2pyinit%s\n' % (m['name'])) + + dadd('\n'.join(ret['latexdoc']).replace( + r'\subsection{', r'\subsubsection{')) + + ret['latexdoc'] = [] + ret['docs'].append('"\t%s --- %s"' % (m['name'], + ','.join(undo_rmbadname(modobjs)))) + + ret['routine_defs'] = '' + ret['doc'] = [] + ret['docshort'] = [] + ret['latexdoc'] = doc[0] + if len(ret['docs']) <= 1: + ret['docs'] = '' + return ret, fhooks[0] diff --git a/numpy/f2py/func2subr.py b/numpy/f2py/func2subr.py new file mode 100644 index 0000000..6010d5a --- /dev/null +++ b/numpy/f2py/func2subr.py @@ -0,0 +1,299 @@ +#!/usr/bin/env python +""" + +Rules for building C/API module with f2py2e. + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2004/11/26 11:13:06 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +__version__ = "$Revision: 1.16 $"[10:-1] + +f2py_version = 'See `f2py -v`' + +import copy + +from .auxfuncs import ( + getfortranname, isexternal, isfunction, isfunction_wrap, isintent_in, + isintent_out, islogicalfunction, ismoduleroutine, isscalar, + issubroutine, issubroutine_wrap, outmess, show +) + + +def var2fixfortran(vars, a, fa=None, f90mode=None): + if fa is None: + fa = a + if a not in vars: + show(vars) + outmess('var2fixfortran: No definition for argument "%s".\n' % a) + return '' + if 'typespec' not in vars[a]: + show(vars[a]) + outmess('var2fixfortran: No typespec for argument "%s".\n' % a) + return '' + vardef = vars[a]['typespec'] + if vardef == 'type' and 'typename' in vars[a]: + vardef = '%s(%s)' % (vardef, vars[a]['typename']) + selector = {} + lk = '' + if 'kindselector' in vars[a]: + selector = vars[a]['kindselector'] + lk = 'kind' + elif 'charselector' in vars[a]: + selector = vars[a]['charselector'] + lk = 'len' + if '*' in selector: + if f90mode: + if selector['*'] in ['*', ':', '(*)']: + vardef = '%s(len=*)' % (vardef) + else: + vardef = '%s(%s=%s)' % (vardef, lk, selector['*']) + else: + if selector['*'] in ['*', ':']: + vardef = '%s*(%s)' % (vardef, selector['*']) + else: + vardef = '%s*%s' % (vardef, selector['*']) + else: + if 'len' in selector: + vardef = '%s(len=%s' % (vardef, selector['len']) + if 'kind' in selector: + vardef = '%s,kind=%s)' % (vardef, selector['kind']) + else: + vardef = '%s)' % (vardef) + elif 'kind' in selector: + vardef = '%s(kind=%s)' % (vardef, selector['kind']) + + vardef = '%s %s' % (vardef, fa) + if 'dimension' in vars[a]: + vardef = '%s(%s)' % (vardef, ','.join(vars[a]['dimension'])) + return vardef + + +def createfuncwrapper(rout, signature=0): + assert isfunction(rout) + + extra_args = [] + vars = rout['vars'] + for a in rout['args']: + v = rout['vars'][a] + for i, d in enumerate(v.get('dimension', [])): + if d == ':': + dn = 'f2py_%s_d%s' % (a, i) + dv = dict(typespec='integer', intent=['hide']) + dv['='] = 'shape(%s, %s)' % (a, i) + extra_args.append(dn) + vars[dn] = dv + v['dimension'][i] = dn + rout['args'].extend(extra_args) + need_interface = bool(extra_args) + + ret = [''] + + def add(line, ret=ret): + ret[0] = '%s\n %s' % (ret[0], line) + name = rout['name'] + fortranname = getfortranname(rout) + f90mode = ismoduleroutine(rout) + newname = '%sf2pywrap' % (name) + + if newname not in vars: + vars[newname] = vars[name] + args = [newname] + rout['args'][1:] + else: + args = [newname] + rout['args'] + + l = var2fixfortran(vars, name, newname, f90mode) + if l[:13] == 'character*(*)': + if f90mode: + l = 'character(len=10)' + l[13:] + else: + l = 'character*10' + l[13:] + charselect = vars[name]['charselector'] + if charselect.get('*', '') == '(*)': + charselect['*'] = '10' + sargs = ', '.join(args) + if f90mode: + add('subroutine f2pywrap_%s_%s (%s)' % + (rout['modulename'], name, sargs)) + if not signature: + add('use %s, only : %s' % (rout['modulename'], fortranname)) + else: + add('subroutine f2pywrap%s (%s)' % (name, sargs)) + if not need_interface: + add('external %s' % (fortranname)) + l = l + ', ' + fortranname + if need_interface: + for line in rout['saved_interface'].split('\n'): + if line.lstrip().startswith('use '): + add(line) + + args = args[1:] + dumped_args = [] + for a in args: + if isexternal(vars[a]): + add('external %s' % (a)) + dumped_args.append(a) + for a in args: + if a in dumped_args: + continue + if isscalar(vars[a]): + add(var2fixfortran(vars, a, f90mode=f90mode)) + dumped_args.append(a) + for a in args: + if a in dumped_args: + continue + if isintent_in(vars[a]): + add(var2fixfortran(vars, a, f90mode=f90mode)) + dumped_args.append(a) + for a in args: + if a in dumped_args: + continue + add(var2fixfortran(vars, a, f90mode=f90mode)) + + add(l) + + if need_interface: + if f90mode: + # f90 module already defines needed interface + pass + else: + add('interface') + add(rout['saved_interface'].lstrip()) + add('end interface') + + sargs = ', '.join([a for a in args if a not in extra_args]) + + if not signature: + if islogicalfunction(rout): + add('%s = .not.(.not.%s(%s))' % (newname, fortranname, sargs)) + else: + add('%s = %s(%s)' % (newname, fortranname, sargs)) + if f90mode: + add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name)) + else: + add('end') + return ret[0] + + +def createsubrwrapper(rout, signature=0): + assert issubroutine(rout) + + extra_args = [] + vars = rout['vars'] + for a in rout['args']: + v = rout['vars'][a] + for i, d in enumerate(v.get('dimension', [])): + if d == ':': + dn = 'f2py_%s_d%s' % (a, i) + dv = dict(typespec='integer', intent=['hide']) + dv['='] = 'shape(%s, %s)' % (a, i) + extra_args.append(dn) + vars[dn] = dv + v['dimension'][i] = dn + rout['args'].extend(extra_args) + need_interface = bool(extra_args) + + ret = [''] + + def add(line, ret=ret): + ret[0] = '%s\n %s' % (ret[0], line) + name = rout['name'] + fortranname = getfortranname(rout) + f90mode = ismoduleroutine(rout) + + args = rout['args'] + + sargs = ', '.join(args) + if f90mode: + add('subroutine f2pywrap_%s_%s (%s)' % + (rout['modulename'], name, sargs)) + if not signature: + add('use %s, only : %s' % (rout['modulename'], fortranname)) + else: + add('subroutine f2pywrap%s (%s)' % (name, sargs)) + if not need_interface: + add('external %s' % (fortranname)) + + if need_interface: + for line in rout['saved_interface'].split('\n'): + if line.lstrip().startswith('use '): + add(line) + + dumped_args = [] + for a in args: + if isexternal(vars[a]): + add('external %s' % (a)) + dumped_args.append(a) + for a in args: + if a in dumped_args: + continue + if isscalar(vars[a]): + add(var2fixfortran(vars, a, f90mode=f90mode)) + dumped_args.append(a) + for a in args: + if a in dumped_args: + continue + add(var2fixfortran(vars, a, f90mode=f90mode)) + + if need_interface: + if f90mode: + # f90 module already defines needed interface + pass + else: + add('interface') + add(rout['saved_interface'].lstrip()) + add('end interface') + + sargs = ', '.join([a for a in args if a not in extra_args]) + + if not signature: + add('call %s(%s)' % (fortranname, sargs)) + if f90mode: + add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name)) + else: + add('end') + return ret[0] + + +def assubr(rout): + if isfunction_wrap(rout): + fortranname = getfortranname(rout) + name = rout['name'] + outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n' % ( + name, fortranname)) + rout = copy.copy(rout) + fname = name + rname = fname + if 'result' in rout: + rname = rout['result'] + rout['vars'][fname] = rout['vars'][rname] + fvar = rout['vars'][fname] + if not isintent_out(fvar): + if 'intent' not in fvar: + fvar['intent'] = [] + fvar['intent'].append('out') + flag = 1 + for i in fvar['intent']: + if i.startswith('out='): + flag = 0 + break + if flag: + fvar['intent'].append('out=%s' % (rname)) + rout['args'][:] = [fname] + rout['args'] + return rout, createfuncwrapper(rout) + if issubroutine_wrap(rout): + fortranname = getfortranname(rout) + name = rout['name'] + outmess('\t\tCreating wrapper for Fortran subroutine "%s"("%s")...\n' % ( + name, fortranname)) + rout = copy.copy(rout) + return rout, createsubrwrapper(rout) + return rout, '' diff --git a/numpy/f2py/info.py b/numpy/f2py/info.py new file mode 100644 index 0000000..c895c5d --- /dev/null +++ b/numpy/f2py/info.py @@ -0,0 +1,6 @@ +"""Fortran to Python Interface Generator. + +""" +from __future__ import division, absolute_import, print_function + +postpone_import = True diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py new file mode 100644 index 0000000..36e2222 --- /dev/null +++ b/numpy/f2py/rules.py @@ -0,0 +1,1473 @@ +#!/usr/bin/env python +""" + +Rules for building C/API module with f2py2e. + +Here is a skeleton of a new wrapper function (13Dec2001): + +wrapper_function(args) + declarations + get_python_arguments, say, `a' and `b' + + get_a_from_python + if (successful) { + + get_b_from_python + if (successful) { + + callfortran + if (successful) { + + put_a_to_python + if (successful) { + + put_b_to_python + if (successful) { + + buildvalue = ... + + } + + } + + } + + } + cleanup_b + + } + cleanup_a + + return buildvalue + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/08/30 08:58:42 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +__version__ = "$Revision: 1.129 $"[10:-1] + +from . import __version__ +f2py_version = __version__.version + +import os +import time +import copy + +from .auxfuncs import ( + applyrules, debugcapi, dictappend, errmess, gentitle, getargs2, + hascallstatement, hasexternals, hasinitvalue, hasnote, hasresultnote, + isarray, isarrayofstrings, iscomplex, iscomplexarray, + iscomplexfunction, iscomplexfunction_warn, isdummyroutine, isexternal, + isfunction, isfunction_wrap, isint1array, isintent_aux, isintent_c, + isintent_callback, isintent_copy, isintent_hide, isintent_inout, + isintent_nothide, isintent_out, isintent_overwrite, islogical, + islong_complex, islong_double, islong_doublefunction, islong_long, + islong_longfunction, ismoduleroutine, isoptional, isrequired, isscalar, + issigned_long_longarray, isstring, isstringarray, isstringfunction, + issubroutine, issubroutine_wrap, isthreadsafe, isunsigned, + isunsigned_char, isunsigned_chararray, isunsigned_long_long, + isunsigned_long_longarray, isunsigned_short, isunsigned_shortarray, + l_and, l_not, l_or, outmess, replace, stripcomma, +) + +from . import capi_maps +from . import cfuncs +from . import common_rules +from . import use_rules +from . import f90mod_rules +from . import func2subr + +options = {} +sepdict = {} +#for k in ['need_cfuncs']: sepdict[k]=',' +for k in ['decl', + 'frompyobj', + 'cleanupfrompyobj', + 'topyarr', 'method', + 'pyobjfrom', 'closepyobjfrom', + 'freemem', + 'userincludes', + 'includes0', 'includes', 'typedefs', 'typedefs_generated', + 'cppmacros', 'cfuncs', 'callbacks', + 'latexdoc', + 'restdoc', + 'routine_defs', 'externroutines', + 'initf2pywraphooks', + 'commonhooks', 'initcommonhooks', + 'f90modhooks', 'initf90modhooks']: + sepdict[k] = '\n' + +#################### Rules for C/API module ################# + +generationtime = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) +module_rules = { + 'modulebody': """\ +/* File: #modulename#module.c + * This file is auto-generated with f2py (version:#f2py_version#). + * f2py is a Fortran to Python Interface Generator (FPIG), Second Edition, + * written by Pearu Peterson . + * Generation date: """ + time.asctime(time.gmtime(generationtime)) + """ + * Do not edit this file directly unless you know what you are doing!!! + */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +""" + gentitle("See f2py2e/cfuncs.py: includes") + """ +#includes# +#includes0# + +""" + gentitle("See f2py2e/rules.py: mod_rules['modulebody']") + """ +static PyObject *#modulename#_error; +static PyObject *#modulename#_module; + +""" + gentitle("See f2py2e/cfuncs.py: typedefs") + """ +#typedefs# + +""" + gentitle("See f2py2e/cfuncs.py: typedefs_generated") + """ +#typedefs_generated# + +""" + gentitle("See f2py2e/cfuncs.py: cppmacros") + """ +#cppmacros# + +""" + gentitle("See f2py2e/cfuncs.py: cfuncs") + """ +#cfuncs# + +""" + gentitle("See f2py2e/cfuncs.py: userincludes") + """ +#userincludes# + +""" + gentitle("See f2py2e/capi_rules.py: usercode") + """ +#usercode# + +/* See f2py2e/rules.py */ +#externroutines# + +""" + gentitle("See f2py2e/capi_rules.py: usercode1") + """ +#usercode1# + +""" + gentitle("See f2py2e/cb_rules.py: buildcallback") + """ +#callbacks# + +""" + gentitle("See f2py2e/rules.py: buildapi") + """ +#body# + +""" + gentitle("See f2py2e/f90mod_rules.py: buildhooks") + """ +#f90modhooks# + +""" + gentitle("See f2py2e/rules.py: module_rules['modulebody']") + """ + +""" + gentitle("See f2py2e/common_rules.py: buildhooks") + """ +#commonhooks# + +""" + gentitle("See f2py2e/rules.py") + """ + +static FortranDataDef f2py_routine_defs[] = { +#routine_defs# +\t{NULL} +}; + +static PyMethodDef f2py_module_methods[] = { +#pymethoddef# +\t{NULL,NULL} +}; + +#if PY_VERSION_HEX >= 0x03000000 +static struct PyModuleDef moduledef = { +\tPyModuleDef_HEAD_INIT, +\t"#modulename#", +\tNULL, +\t-1, +\tf2py_module_methods, +\tNULL, +\tNULL, +\tNULL, +\tNULL +}; +#endif + +#if PY_VERSION_HEX >= 0x03000000 +#define RETVAL m +PyMODINIT_FUNC PyInit_#modulename#(void) { +#else +#define RETVAL +PyMODINIT_FUNC init#modulename#(void) { +#endif +\tint i; +\tPyObject *m,*d, *s; +#if PY_VERSION_HEX >= 0x03000000 +\tm = #modulename#_module = PyModule_Create(&moduledef); +#else +\tm = #modulename#_module = Py_InitModule(\"#modulename#\", f2py_module_methods); +#endif +\tPy_TYPE(&PyFortran_Type) = &PyType_Type; +\timport_array(); +\tif (PyErr_Occurred()) +\t\t{PyErr_SetString(PyExc_ImportError, \"can't initialize module #modulename# (failed to import numpy)\"); return RETVAL;} +\td = PyModule_GetDict(m); +\ts = PyString_FromString(\"$R""" + """evision: $\"); +\tPyDict_SetItemString(d, \"__version__\", s); +#if PY_VERSION_HEX >= 0x03000000 +\ts = PyUnicode_FromString( +#else +\ts = PyString_FromString( +#endif +\t\t\"This module '#modulename#' is auto-generated with f2py (version:#f2py_version#).\\nFunctions:\\n\"\n#docs#\".\"); +\tPyDict_SetItemString(d, \"__doc__\", s); +\t#modulename#_error = PyErr_NewException (\"#modulename#.error\", NULL, NULL); +\tPy_DECREF(s); +\tfor(i=0;f2py_routine_defs[i].name!=NULL;i++) +\t\tPyDict_SetItemString(d, f2py_routine_defs[i].name,PyFortranObject_NewAsAttr(&f2py_routine_defs[i])); +#initf2pywraphooks# +#initf90modhooks# +#initcommonhooks# +#interface_usercode# + +#ifdef F2PY_REPORT_ATEXIT +\tif (! PyErr_Occurred()) +\t\ton_exit(f2py_report_on_exit,(void*)\"#modulename#\"); +#endif + +\treturn RETVAL; +} +#ifdef __cplusplus +} +#endif +""", + 'separatorsfor': {'latexdoc': '\n\n', + 'restdoc': '\n\n'}, + 'latexdoc': ['\\section{Module \\texttt{#texmodulename#}}\n', + '#modnote#\n', + '#latexdoc#'], + 'restdoc': ['Module #modulename#\n' + '=' * 80, + '\n#restdoc#'] +} + +defmod_rules = [ + {'body': '/*eof body*/', + 'method': '/*eof method*/', + 'externroutines': '/*eof externroutines*/', + 'routine_defs': '/*eof routine_defs*/', + 'initf90modhooks': '/*eof initf90modhooks*/', + 'initf2pywraphooks': '/*eof initf2pywraphooks*/', + 'initcommonhooks': '/*eof initcommonhooks*/', + 'latexdoc': '', + 'restdoc': '', + 'modnote': {hasnote: '#note#', l_not(hasnote): ''}, + } +] + +routine_rules = { + 'separatorsfor': sepdict, + 'body': """ +#begintitle# +static char doc_#apiname#[] = \"\\\n#docreturn##name#(#docsignatureshort#)\\n\\nWrapper for ``#name#``.\\\n\\n#docstrsigns#\"; +/* #declfortranroutine# */ +static PyObject *#apiname#(const PyObject *capi_self, + PyObject *capi_args, + PyObject *capi_keywds, + #functype# (*f2py_func)(#callprotoargument#)) { +\tPyObject * volatile capi_buildvalue = NULL; +\tvolatile int f2py_success = 1; +#decl# +\tstatic char *capi_kwlist[] = {#kwlist##kwlistopt##kwlistxa#NULL}; +#usercode# +#routdebugenter# +#ifdef F2PY_REPORT_ATEXIT +f2py_start_clock(); +#endif +\tif (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\\ +\t\t\"#argformat##keyformat##xaformat#:#pyname#\",\\ +\t\tcapi_kwlist#args_capi##keys_capi##keys_xa#))\n\t\treturn NULL; +#frompyobj# +/*end of frompyobj*/ +#ifdef F2PY_REPORT_ATEXIT +f2py_start_call_clock(); +#endif +#callfortranroutine# +if (PyErr_Occurred()) + f2py_success = 0; +#ifdef F2PY_REPORT_ATEXIT +f2py_stop_call_clock(); +#endif +/*end of callfortranroutine*/ +\t\tif (f2py_success) { +#pyobjfrom# +/*end of pyobjfrom*/ +\t\tCFUNCSMESS(\"Building return value.\\n\"); +\t\tcapi_buildvalue = Py_BuildValue(\"#returnformat#\"#return#); +/*closepyobjfrom*/ +#closepyobjfrom# +\t\t} /*if (f2py_success) after callfortranroutine*/ +/*cleanupfrompyobj*/ +#cleanupfrompyobj# +\tif (capi_buildvalue == NULL) { +#routdebugfailure# +\t} else { +#routdebugleave# +\t} +\tCFUNCSMESS(\"Freeing memory.\\n\"); +#freemem# +#ifdef F2PY_REPORT_ATEXIT +f2py_stop_clock(); +#endif +\treturn capi_buildvalue; +} +#endtitle# +""", + 'routine_defs': '#routine_def#', + 'initf2pywraphooks': '#initf2pywraphook#', + 'externroutines': '#declfortranroutine#', + 'doc': '#docreturn##name#(#docsignature#)', + 'docshort': '#docreturn##name#(#docsignatureshort#)', + 'docs': '"\t#docreturn##name#(#docsignature#)\\n"\n', + 'need': ['arrayobject.h', 'CFUNCSMESS', 'MINMAX'], + 'cppmacros': {debugcapi: '#define DEBUGCFUNCS'}, + 'latexdoc': ['\\subsection{Wrapper function \\texttt{#texname#}}\n', + """ +\\noindent{{}\\verb@#docreturn##name#@{}}\\texttt{(#latexdocsignatureshort#)} +#routnote# + +#latexdocstrsigns# +"""], + 'restdoc': ['Wrapped function ``#name#``\n' + '-' * 80, + + ] +} + +################## Rules for C/API function ############## + +rout_rules = [ + { # Init + 'separatorsfor': {'callfortranroutine': '\n', 'routdebugenter': '\n', 'decl': '\n', + 'routdebugleave': '\n', 'routdebugfailure': '\n', + 'setjmpbuf': ' || ', + 'docstrreq': '\n', 'docstropt': '\n', 'docstrout': '\n', + 'docstrcbs': '\n', 'docstrsigns': '\\n"\n"', + 'latexdocstrsigns': '\n', + 'latexdocstrreq': '\n', 'latexdocstropt': '\n', + 'latexdocstrout': '\n', 'latexdocstrcbs': '\n', + }, + 'kwlist': '', 'kwlistopt': '', 'callfortran': '', 'callfortranappend': '', + 'docsign': '', 'docsignopt': '', 'decl': '/*decl*/', + 'freemem': '/*freemem*/', + 'docsignshort': '', 'docsignoptshort': '', + 'docstrsigns': '', 'latexdocstrsigns': '', + 'docstrreq': '\\nParameters\\n----------', + 'docstropt': '\\nOther Parameters\\n----------------', + 'docstrout': '\\nReturns\\n-------', + 'docstrcbs': '\\nNotes\\n-----\\nCall-back functions::\\n', + 'latexdocstrreq': '\\noindent Required arguments:', + 'latexdocstropt': '\\noindent Optional arguments:', + 'latexdocstrout': '\\noindent Return objects:', + 'latexdocstrcbs': '\\noindent Call-back functions:', + 'args_capi': '', 'keys_capi': '', 'functype': '', + 'frompyobj': '/*frompyobj*/', + # this list will be reversed + 'cleanupfrompyobj': ['/*end of cleanupfrompyobj*/'], + 'pyobjfrom': '/*pyobjfrom*/', + # this list will be reversed + 'closepyobjfrom': ['/*end of closepyobjfrom*/'], + 'topyarr': '/*topyarr*/', 'routdebugleave': '/*routdebugleave*/', + 'routdebugenter': '/*routdebugenter*/', + 'routdebugfailure': '/*routdebugfailure*/', + 'callfortranroutine': '/*callfortranroutine*/', + 'argformat': '', 'keyformat': '', 'need_cfuncs': '', + 'docreturn': '', 'return': '', 'returnformat': '', 'rformat': '', + 'kwlistxa': '', 'keys_xa': '', 'xaformat': '', 'docsignxa': '', 'docsignxashort': '', + 'initf2pywraphook': '', + 'routnote': {hasnote: '--- #note#', l_not(hasnote): ''}, + }, { + 'apiname': 'f2py_rout_#modulename#_#name#', + 'pyname': '#modulename#.#name#', + 'decl': '', + '_check': l_not(ismoduleroutine) + }, { + 'apiname': 'f2py_rout_#modulename#_#f90modulename#_#name#', + 'pyname': '#modulename#.#f90modulename#.#name#', + 'decl': '', + '_check': ismoduleroutine + }, { # Subroutine + 'functype': 'void', + 'declfortranroutine': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);', + l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): 'extern void #fortranname#(#callprotoargument#);', + ismoduleroutine: '', + isdummyroutine: '' + }, + 'routine_def': {l_not(l_or(ismoduleroutine, isintent_c, isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},', + l_and(l_not(ismoduleroutine), isdummyroutine): '\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},', + }, + 'need': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'F_FUNC'}, + 'callfortranroutine': [ + {debugcapi: [ + """\tfprintf(stderr,\"debug-capi:Fortran subroutine `#fortranname#(#callfortran#)\'\\n\");"""]}, + {hasexternals: """\ +\t\tif (#setjmpbuf#) { +\t\t\tf2py_success = 0; +\t\t} else {"""}, + {isthreadsafe: '\t\t\tPy_BEGIN_ALLOW_THREADS'}, + {hascallstatement: '''\t\t\t\t#callstatement#; +\t\t\t\t/*(*f2py_func)(#callfortran#);*/'''}, + {l_not(l_or(hascallstatement, isdummyroutine)) + : '\t\t\t\t(*f2py_func)(#callfortran#);'}, + {isthreadsafe: '\t\t\tPy_END_ALLOW_THREADS'}, + {hasexternals: """\t\t}"""} + ], + '_check': l_and(issubroutine, l_not(issubroutine_wrap)), + }, { # Wrapped function + 'functype': 'void', + 'declfortranroutine': {l_not(l_or(ismoduleroutine, isdummyroutine)): 'extern void #F_WRAPPEDFUNC#(#name_lower#,#NAME#)(#callprotoargument#);', + isdummyroutine: '', + }, + + 'routine_def': {l_not(l_or(ismoduleroutine, isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#F_WRAPPEDFUNC#(#name_lower#,#NAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + isdummyroutine: '\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},', + }, + 'initf2pywraphook': {l_not(l_or(ismoduleroutine, isdummyroutine)): ''' + { + extern #ctype# #F_FUNC#(#name_lower#,#NAME#)(void); + PyObject* o = PyDict_GetItemString(d,"#name#"); + PyObject_SetAttrString(o,"_cpointer", F2PyCapsule_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL)); +#if PY_VERSION_HEX >= 0x03000000 + PyObject_SetAttrString(o,"__name__", PyUnicode_FromString("#name#")); +#else + PyObject_SetAttrString(o,"__name__", PyString_FromString("#name#")); +#endif + } + '''}, + 'need': {l_not(l_or(ismoduleroutine, isdummyroutine)): ['F_WRAPPEDFUNC', 'F_FUNC']}, + 'callfortranroutine': [ + {debugcapi: [ + """\tfprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]}, + {hasexternals: """\ +\tif (#setjmpbuf#) { +\t\tf2py_success = 0; +\t} else {"""}, + {isthreadsafe: '\tPy_BEGIN_ALLOW_THREADS'}, + {l_not(l_or(hascallstatement, isdummyroutine)) + : '\t(*f2py_func)(#callfortran#);'}, + {hascallstatement: + '\t#callstatement#;\n\t/*(*f2py_func)(#callfortran#);*/'}, + {isthreadsafe: '\tPy_END_ALLOW_THREADS'}, + {hasexternals: '\t}'} + ], + '_check': isfunction_wrap, + }, { # Wrapped subroutine + 'functype': 'void', + 'declfortranroutine': {l_not(l_or(ismoduleroutine, isdummyroutine)): 'extern void #F_WRAPPEDFUNC#(#name_lower#,#NAME#)(#callprotoargument#);', + isdummyroutine: '', + }, + + 'routine_def': {l_not(l_or(ismoduleroutine, isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#F_WRAPPEDFUNC#(#name_lower#,#NAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + isdummyroutine: '\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},', + }, + 'initf2pywraphook': {l_not(l_or(ismoduleroutine, isdummyroutine)): ''' + { + extern void #F_FUNC#(#name_lower#,#NAME#)(void); + PyObject* o = PyDict_GetItemString(d,"#name#"); + PyObject_SetAttrString(o,"_cpointer", F2PyCapsule_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL)); +#if PY_VERSION_HEX >= 0x03000000 + PyObject_SetAttrString(o,"__name__", PyUnicode_FromString("#name#")); +#else + PyObject_SetAttrString(o,"__name__", PyString_FromString("#name#")); +#endif + } + '''}, + 'need': {l_not(l_or(ismoduleroutine, isdummyroutine)): ['F_WRAPPEDFUNC', 'F_FUNC']}, + 'callfortranroutine': [ + {debugcapi: [ + """\tfprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]}, + {hasexternals: """\ +\tif (#setjmpbuf#) { +\t\tf2py_success = 0; +\t} else {"""}, + {isthreadsafe: '\tPy_BEGIN_ALLOW_THREADS'}, + {l_not(l_or(hascallstatement, isdummyroutine)) + : '\t(*f2py_func)(#callfortran#);'}, + {hascallstatement: + '\t#callstatement#;\n\t/*(*f2py_func)(#callfortran#);*/'}, + {isthreadsafe: '\tPy_END_ALLOW_THREADS'}, + {hasexternals: '\t}'} + ], + '_check': issubroutine_wrap, + }, { # Function + 'functype': '#ctype#', + 'docreturn': {l_not(isintent_hide): '#rname#,'}, + 'docstrout': '#pydocsignout#', + 'latexdocstrout': ['\\item[]{{}\\verb@#pydocsignout#@{}}', + {hasresultnote: '--- #resultnote#'}], + 'callfortranroutine': [{l_and(debugcapi, isstringfunction): """\ +#ifdef USESCOMPAQFORTRAN +\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callcompaqfortran#)\\n\"); +#else +\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\"); +#endif +"""}, + {l_and(debugcapi, l_not(isstringfunction)): """\ +\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\"); +"""} + ], + '_check': l_and(isfunction, l_not(isfunction_wrap)) + }, { # Scalar function + 'declfortranroutine': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'extern #ctype# #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);', + l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): 'extern #ctype# #fortranname#(#callprotoargument#);', + isdummyroutine: '' + }, + 'routine_def': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},', + isdummyroutine: '\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},', + }, + 'decl': [{iscomplexfunction_warn: '\t#ctype# #name#_return_value={0,0};', + l_not(iscomplexfunction): '\t#ctype# #name#_return_value=0;'}, + {iscomplexfunction: + '\tPyObject *#name#_return_value_capi = Py_None;'} + ], + 'callfortranroutine': [ + {hasexternals: """\ +\tif (#setjmpbuf#) { +\t\tf2py_success = 0; +\t} else {"""}, + {isthreadsafe: '\tPy_BEGIN_ALLOW_THREADS'}, + {hascallstatement: '''\t#callstatement#; +/*\t#name#_return_value = (*f2py_func)(#callfortran#);*/ +'''}, + {l_not(l_or(hascallstatement, isdummyroutine)) + : '\t#name#_return_value = (*f2py_func)(#callfortran#);'}, + {isthreadsafe: '\tPy_END_ALLOW_THREADS'}, + {hasexternals: '\t}'}, + {l_and(debugcapi, iscomplexfunction) + : '\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value.r,#name#_return_value.i);'}, + {l_and(debugcapi, l_not(iscomplexfunction)): '\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value);'}], + 'pyobjfrom': {iscomplexfunction: '\t#name#_return_value_capi = pyobj_from_#ctype#1(#name#_return_value);'}, + 'need': [{l_not(isdummyroutine): 'F_FUNC'}, + {iscomplexfunction: 'pyobj_from_#ctype#1'}, + {islong_longfunction: 'long_long'}, + {islong_doublefunction: 'long_double'}], + 'returnformat': {l_not(isintent_hide): '#rformat#'}, + 'return': {iscomplexfunction: ',#name#_return_value_capi', + l_not(l_or(iscomplexfunction, isintent_hide)): ',#name#_return_value'}, + '_check': l_and(isfunction, l_not(isstringfunction), l_not(isfunction_wrap)) + }, { # String function # in use for --no-wrap + 'declfortranroutine': 'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);', + 'routine_def': {l_not(l_or(ismoduleroutine, isintent_c)): + '\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + l_and(l_not(ismoduleroutine), isintent_c): + '\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},' + }, + 'decl': ['\t#ctype# #name#_return_value = NULL;', + '\tint #name#_return_value_len = 0;'], + 'callfortran':'#name#_return_value,#name#_return_value_len,', + 'callfortranroutine':['\t#name#_return_value_len = #rlength#;', + '\tif ((#name#_return_value = (string)malloc(sizeof(char)*(#name#_return_value_len+1))) == NULL) {', + '\t\tPyErr_SetString(PyExc_MemoryError, \"out of memory\");', + '\t\tf2py_success = 0;', + '\t} else {', + "\t\t(#name#_return_value)[#name#_return_value_len] = '\\0';", + '\t}', + '\tif (f2py_success) {', + {hasexternals: """\ +\t\tif (#setjmpbuf#) { +\t\t\tf2py_success = 0; +\t\t} else {"""}, + {isthreadsafe: '\t\tPy_BEGIN_ALLOW_THREADS'}, + """\ +#ifdef USESCOMPAQFORTRAN +\t\t(*f2py_func)(#callcompaqfortran#); +#else +\t\t(*f2py_func)(#callfortran#); +#endif +""", + {isthreadsafe: '\t\tPy_END_ALLOW_THREADS'}, + {hasexternals: '\t\t}'}, + {debugcapi: + '\t\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value_len,#name#_return_value);'}, + '\t} /* if (f2py_success) after (string)malloc */', + ], + 'returnformat': '#rformat#', + 'return': ',#name#_return_value', + 'freemem': '\tSTRINGFREE(#name#_return_value);', + 'need': ['F_FUNC', '#ctype#', 'STRINGFREE'], + '_check':l_and(isstringfunction, l_not(isfunction_wrap)) # ???obsolete + }, + { # Debugging + 'routdebugenter': '\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#(#docsignature#)\\n");', + 'routdebugleave': '\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: successful.\\n");', + 'routdebugfailure': '\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: failure.\\n");', + '_check': debugcapi + } +] + +################ Rules for arguments ################## + +typedef_need_dict = {islong_long: 'long_long', + islong_double: 'long_double', + islong_complex: 'complex_long_double', + isunsigned_char: 'unsigned_char', + isunsigned_short: 'unsigned_short', + isunsigned: 'unsigned', + isunsigned_long_long: 'unsigned_long_long', + isunsigned_chararray: 'unsigned_char', + isunsigned_shortarray: 'unsigned_short', + isunsigned_long_longarray: 'unsigned_long_long', + issigned_long_longarray: 'long_long', + } + +aux_rules = [ + { + 'separatorsfor': sepdict + }, + { # Common + 'frompyobj': ['\t/* Processing auxiliary variable #varname# */', + {debugcapi: '\tfprintf(stderr,"#vardebuginfo#\\n");'}, ], + 'cleanupfrompyobj': '\t/* End of cleaning variable #varname# */', + 'need': typedef_need_dict, + }, + # Scalars (not complex) + { # Common + 'decl': '\t#ctype# #varname# = 0;', + 'need': {hasinitvalue: 'math.h'}, + 'frompyobj': {hasinitvalue: '\t#varname# = #init#;'}, + '_check': l_and(isscalar, l_not(iscomplex)), + }, + { + 'return': ',#varname#', + 'docstrout': '#pydocsignout#', + 'docreturn': '#outvarname#,', + 'returnformat': '#varrformat#', + '_check': l_and(isscalar, l_not(iscomplex), isintent_out), + }, + # Complex scalars + { # Common + 'decl': '\t#ctype# #varname#;', + 'frompyobj': {hasinitvalue: '\t#varname#.r = #init.r#, #varname#.i = #init.i#;'}, + '_check': iscomplex + }, + # String + { # Common + 'decl': ['\t#ctype# #varname# = NULL;', + '\tint slen(#varname#);', + ], + 'need':['len..'], + '_check':isstring + }, + # Array + { # Common + 'decl': ['\t#ctype# *#varname# = NULL;', + '\tnpy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};', + '\tconst int #varname#_Rank = #rank#;', + ], + 'need':['len..', {hasinitvalue: 'forcomb'}, {hasinitvalue: 'CFUNCSMESS'}], + '_check': isarray + }, + # Scalararray + { # Common + '_check': l_and(isarray, l_not(iscomplexarray)) + }, { # Not hidden + '_check': l_and(isarray, l_not(iscomplexarray), isintent_nothide) + }, + # Integer*1 array + {'need': '#ctype#', + '_check': isint1array, + '_depend': '' + }, + # Integer*-1 array + {'need': '#ctype#', + '_check': isunsigned_chararray, + '_depend': '' + }, + # Integer*-2 array + {'need': '#ctype#', + '_check': isunsigned_shortarray, + '_depend': '' + }, + # Integer*-8 array + {'need': '#ctype#', + '_check': isunsigned_long_longarray, + '_depend': '' + }, + # Complexarray + {'need': '#ctype#', + '_check': iscomplexarray, + '_depend': '' + }, + # Stringarray + { + 'callfortranappend': {isarrayofstrings: 'flen(#varname#),'}, + 'need': 'string', + '_check': isstringarray + } +] + +arg_rules = [ + { + 'separatorsfor': sepdict + }, + { # Common + 'frompyobj': ['\t/* Processing variable #varname# */', + {debugcapi: '\tfprintf(stderr,"#vardebuginfo#\\n");'}, ], + 'cleanupfrompyobj': '\t/* End of cleaning variable #varname# */', + '_depend': '', + 'need': typedef_need_dict, + }, + # Doc signatures + { + 'docstropt': {l_and(isoptional, isintent_nothide): '#pydocsign#'}, + 'docstrreq': {l_and(isrequired, isintent_nothide): '#pydocsign#'}, + 'docstrout': {isintent_out: '#pydocsignout#'}, + 'latexdocstropt': {l_and(isoptional, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}', + {hasnote: '--- #note#'}]}, + 'latexdocstrreq': {l_and(isrequired, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}', + {hasnote: '--- #note#'}]}, + 'latexdocstrout': {isintent_out: ['\\item[]{{}\\verb@#pydocsignout#@{}}', + {l_and(hasnote, isintent_hide): '--- #note#', + l_and(hasnote, isintent_nothide): '--- See above.'}]}, + 'depend': '' + }, + # Required/Optional arguments + { + 'kwlist': '"#varname#",', + 'docsign': '#varname#,', + '_check': l_and(isintent_nothide, l_not(isoptional)) + }, + { + 'kwlistopt': '"#varname#",', + 'docsignopt': '#varname#=#showinit#,', + 'docsignoptshort': '#varname#,', + '_check': l_and(isintent_nothide, isoptional) + }, + # Docstring/BuildValue + { + 'docreturn': '#outvarname#,', + 'returnformat': '#varrformat#', + '_check': isintent_out + }, + # Externals (call-back functions) + { # Common + 'docsignxa': {isintent_nothide: '#varname#_extra_args=(),'}, + 'docsignxashort': {isintent_nothide: '#varname#_extra_args,'}, + 'docstropt': {isintent_nothide: '#varname#_extra_args : input tuple, optional\\n Default: ()'}, + 'docstrcbs': '#cbdocstr#', + 'latexdocstrcbs': '\\item[] #cblatexdocstr#', + 'latexdocstropt': {isintent_nothide: '\\item[]{{}\\verb@#varname#_extra_args := () input tuple@{}} --- Extra arguments for call-back function {{}\\verb@#varname#@{}}.'}, + 'decl': ['\tPyObject *#varname#_capi = Py_None;', + '\tPyTupleObject *#varname#_xa_capi = NULL;', + '\tPyTupleObject *#varname#_args_capi = NULL;', + '\tint #varname#_nofargs_capi = 0;', + {l_not(isintent_callback): + '\t#cbname#_typedef #varname#_cptr;'} + ], + 'kwlistxa': {isintent_nothide: '"#varname#_extra_args",'}, + 'argformat': {isrequired: 'O'}, + 'keyformat': {isoptional: 'O'}, + 'xaformat': {isintent_nothide: 'O!'}, + 'args_capi': {isrequired: ',&#varname#_capi'}, + 'keys_capi': {isoptional: ',&#varname#_capi'}, + 'keys_xa': ',&PyTuple_Type,&#varname#_xa_capi', + 'setjmpbuf': '(setjmp(#cbname#_jmpbuf))', + 'callfortran': {l_not(isintent_callback): '#varname#_cptr,'}, + 'need': ['#cbname#', 'setjmp.h'], + '_check':isexternal + }, + { + 'frompyobj': [{l_not(isintent_callback): """\ +if(F2PyCapsule_Check(#varname#_capi)) { + #varname#_cptr = F2PyCapsule_AsVoidPtr(#varname#_capi); +} else { + #varname#_cptr = #cbname#; +} +"""}, {isintent_callback: """\ +if (#varname#_capi==Py_None) { + #varname#_capi = PyObject_GetAttrString(#modulename#_module,\"#varname#\"); + if (#varname#_capi) { + if (#varname#_xa_capi==NULL) { + if (PyObject_HasAttrString(#modulename#_module,\"#varname#_extra_args\")) { + PyObject* capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#varname#_extra_args\"); + if (capi_tmp) + #varname#_xa_capi = (PyTupleObject *)PySequence_Tuple(capi_tmp); + else + #varname#_xa_capi = (PyTupleObject *)Py_BuildValue(\"()\"); + if (#varname#_xa_capi==NULL) { + PyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#varname#_extra_args to tuple.\\n\"); + return NULL; + } + } + } + } + if (#varname#_capi==NULL) { + PyErr_SetString(#modulename#_error,\"Callback #varname# not defined (as an argument or module #modulename# attribute).\\n\"); + return NULL; + } +} +"""}, + """\ +\t#varname#_nofargs_capi = #cbname#_nofargs; +\tif (create_cb_arglist(#varname#_capi,#varname#_xa_capi,#maxnofargs#,#nofoptargs#,&#cbname#_nofargs,&#varname#_args_capi,\"failed in processing argument list for call-back #varname#.\")) { +\t\tjmp_buf #varname#_jmpbuf;""", + {debugcapi: ["""\ +\t\tfprintf(stderr,\"debug-capi:Assuming %d arguments; at most #maxnofargs#(-#nofoptargs#) is expected.\\n\",#cbname#_nofargs); +\t\tCFUNCSMESSPY(\"for #varname#=\",#cbname#_capi);""", + {l_not(isintent_callback): """\t\tfprintf(stderr,\"#vardebugshowvalue# (call-back in C).\\n\",#cbname#);"""}]}, + """\ +\t\tCFUNCSMESS(\"Saving jmpbuf for `#varname#`.\\n\"); +\t\tSWAP(#varname#_capi,#cbname#_capi,PyObject); +\t\tSWAP(#varname#_args_capi,#cbname#_args_capi,PyTupleObject); +\t\tmemcpy(&#varname#_jmpbuf,&#cbname#_jmpbuf,sizeof(jmp_buf));""", + ], + 'cleanupfrompyobj': + """\ +\t\tCFUNCSMESS(\"Restoring jmpbuf for `#varname#`.\\n\"); +\t\t#cbname#_capi = #varname#_capi; +\t\tPy_DECREF(#cbname#_args_capi); +\t\t#cbname#_args_capi = #varname#_args_capi; +\t\t#cbname#_nofargs = #varname#_nofargs_capi; +\t\tmemcpy(&#cbname#_jmpbuf,&#varname#_jmpbuf,sizeof(jmp_buf)); +\t}""", + 'need': ['SWAP', 'create_cb_arglist'], + '_check':isexternal, + '_depend':'' + }, + # Scalars (not complex) + { # Common + 'decl': '\t#ctype# #varname# = 0;', + 'pyobjfrom': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'}, + 'callfortran': {isintent_c: '#varname#,', l_not(isintent_c): '&#varname#,'}, + 'return': {isintent_out: ',#varname#'}, + '_check': l_and(isscalar, l_not(iscomplex)) + }, { + 'need': {hasinitvalue: 'math.h'}, + '_check': l_and(isscalar, l_not(iscomplex)), + }, { # Not hidden + 'decl': '\tPyObject *#varname#_capi = Py_None;', + 'argformat': {isrequired: 'O'}, + 'keyformat': {isoptional: 'O'}, + 'args_capi': {isrequired: ',&#varname#_capi'}, + 'keys_capi': {isoptional: ',&#varname#_capi'}, + 'pyobjfrom': {isintent_inout: """\ +\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#); +\tif (f2py_success) {"""}, + 'closepyobjfrom': {isintent_inout: "\t} /*if (f2py_success) of #varname# pyobjfrom*/"}, + 'need': {isintent_inout: 'try_pyarr_from_#ctype#'}, + '_check': l_and(isscalar, l_not(iscomplex), isintent_nothide) + }, { + 'frompyobj': [ + # hasinitvalue... + # if pyobj is None: + # varname = init + # else + # from_pyobj(varname) + # + # isoptional and noinitvalue... + # if pyobj is not None: + # from_pyobj(varname) + # else: + # varname is uninitialized + # + # ... + # from_pyobj(varname) + # + {hasinitvalue: '\tif (#varname#_capi == Py_None) #varname# = #init#; else', + '_depend': ''}, + {l_and(isoptional, l_not(hasinitvalue)): '\tif (#varname#_capi != Py_None)', + '_depend': ''}, + {l_not(islogical): '''\ +\t\tf2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#"); +\tif (f2py_success) {'''}, + {islogical: '''\ +\t\t#varname# = (#ctype#)PyObject_IsTrue(#varname#_capi); +\t\tf2py_success = 1; +\tif (f2py_success) {'''}, + ], + 'cleanupfrompyobj': '\t} /*if (f2py_success) of #varname#*/', + 'need': {l_not(islogical): '#ctype#_from_pyobj'}, + '_check': l_and(isscalar, l_not(iscomplex), isintent_nothide), + '_depend': '' + }, { # Hidden + 'frompyobj': {hasinitvalue: '\t#varname# = #init#;'}, + 'need': typedef_need_dict, + '_check': l_and(isscalar, l_not(iscomplex), isintent_hide), + '_depend': '' + }, { # Common + 'frompyobj': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'}, + '_check': l_and(isscalar, l_not(iscomplex)), + '_depend': '' + }, + # Complex scalars + { # Common + 'decl': '\t#ctype# #varname#;', + 'callfortran': {isintent_c: '#varname#,', l_not(isintent_c): '&#varname#,'}, + 'pyobjfrom': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'}, + 'return': {isintent_out: ',#varname#_capi'}, + '_check': iscomplex + }, { # Not hidden + 'decl': '\tPyObject *#varname#_capi = Py_None;', + 'argformat': {isrequired: 'O'}, + 'keyformat': {isoptional: 'O'}, + 'args_capi': {isrequired: ',&#varname#_capi'}, + 'keys_capi': {isoptional: ',&#varname#_capi'}, + 'need': {isintent_inout: 'try_pyarr_from_#ctype#'}, + 'pyobjfrom': {isintent_inout: """\ +\t\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#); +\t\tif (f2py_success) {"""}, + 'closepyobjfrom': {isintent_inout: "\t\t} /*if (f2py_success) of #varname# pyobjfrom*/"}, + '_check': l_and(iscomplex, isintent_nothide) + }, { + 'frompyobj': [{hasinitvalue: '\tif (#varname#_capi==Py_None) {#varname#.r = #init.r#, #varname#.i = #init.i#;} else'}, + {l_and(isoptional, l_not(hasinitvalue)) + : '\tif (#varname#_capi != Py_None)'}, + '\t\tf2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");' + '\n\tif (f2py_success) {'], + 'cleanupfrompyobj': '\t} /*if (f2py_success) of #varname# frompyobj*/', + 'need': ['#ctype#_from_pyobj'], + '_check': l_and(iscomplex, isintent_nothide), + '_depend': '' + }, { # Hidden + 'decl': {isintent_out: '\tPyObject *#varname#_capi = Py_None;'}, + '_check': l_and(iscomplex, isintent_hide) + }, { + 'frompyobj': {hasinitvalue: '\t#varname#.r = #init.r#, #varname#.i = #init.i#;'}, + '_check': l_and(iscomplex, isintent_hide), + '_depend': '' + }, { # Common + 'pyobjfrom': {isintent_out: '\t#varname#_capi = pyobj_from_#ctype#1(#varname#);'}, + 'need': ['pyobj_from_#ctype#1'], + '_check': iscomplex + }, { + 'frompyobj': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'}, + '_check': iscomplex, + '_depend': '' + }, + # String + { # Common + 'decl': ['\t#ctype# #varname# = NULL;', + '\tint slen(#varname#);', + '\tPyObject *#varname#_capi = Py_None;'], + 'callfortran':'#varname#,', + 'callfortranappend':'slen(#varname#),', + 'pyobjfrom':{debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'}, + 'return': {isintent_out: ',#varname#'}, + 'need': ['len..'], # 'STRINGFREE'], + '_check':isstring + }, { # Common + 'frompyobj': """\ +\tslen(#varname#) = #length#; +\tf2py_success = #ctype#_from_pyobj(&#varname#,&slen(#varname#),#init#,#varname#_capi,\"#ctype#_from_pyobj failed in converting #nth# `#varname#\' of #pyname# to C #ctype#\"); +\tif (f2py_success) {""", + 'cleanupfrompyobj': """\ +\t\tSTRINGFREE(#varname#); +\t} /*if (f2py_success) of #varname#*/""", + 'need': ['#ctype#_from_pyobj', 'len..', 'STRINGFREE'], + '_check':isstring, + '_depend':'' + }, { # Not hidden + 'argformat': {isrequired: 'O'}, + 'keyformat': {isoptional: 'O'}, + 'args_capi': {isrequired: ',&#varname#_capi'}, + 'keys_capi': {isoptional: ',&#varname#_capi'}, + 'pyobjfrom': {isintent_inout: '''\ +\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi,#varname#); +\tif (f2py_success) {'''}, + 'closepyobjfrom': {isintent_inout: '\t} /*if (f2py_success) of #varname# pyobjfrom*/'}, + 'need': {isintent_inout: 'try_pyarr_from_#ctype#'}, + '_check': l_and(isstring, isintent_nothide) + }, { # Hidden + '_check': l_and(isstring, isintent_hide) + }, { + 'frompyobj': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'}, + '_check': isstring, + '_depend': '' + }, + # Array + { # Common + 'decl': ['\t#ctype# *#varname# = NULL;', + '\tnpy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};', + '\tconst int #varname#_Rank = #rank#;', + '\tPyArrayObject *capi_#varname#_tmp = NULL;', + '\tint capi_#varname#_intent = 0;', + ], + 'callfortran':'#varname#,', + 'return':{isintent_out: ',capi_#varname#_tmp'}, + 'need': 'len..', + '_check': isarray + }, { # intent(overwrite) array + 'decl': '\tint capi_overwrite_#varname# = 1;', + 'kwlistxa': '"overwrite_#varname#",', + 'xaformat': 'i', + 'keys_xa': ',&capi_overwrite_#varname#', + 'docsignxa': 'overwrite_#varname#=1,', + 'docsignxashort': 'overwrite_#varname#,', + 'docstropt': 'overwrite_#varname# : input int, optional\\n Default: 1', + '_check': l_and(isarray, isintent_overwrite), + }, { + 'frompyobj': '\tcapi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);', + '_check': l_and(isarray, isintent_overwrite), + '_depend': '', + }, + { # intent(copy) array + 'decl': '\tint capi_overwrite_#varname# = 0;', + 'kwlistxa': '"overwrite_#varname#",', + 'xaformat': 'i', + 'keys_xa': ',&capi_overwrite_#varname#', + 'docsignxa': 'overwrite_#varname#=0,', + 'docsignxashort': 'overwrite_#varname#,', + 'docstropt': 'overwrite_#varname# : input int, optional\\n Default: 0', + '_check': l_and(isarray, isintent_copy), + }, { + 'frompyobj': '\tcapi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);', + '_check': l_and(isarray, isintent_copy), + '_depend': '', + }, { + 'need': [{hasinitvalue: 'forcomb'}, {hasinitvalue: 'CFUNCSMESS'}], + '_check': isarray, + '_depend': '' + }, { # Not hidden + 'decl': '\tPyObject *#varname#_capi = Py_None;', + 'argformat': {isrequired: 'O'}, + 'keyformat': {isoptional: 'O'}, + 'args_capi': {isrequired: ',&#varname#_capi'}, + 'keys_capi': {isoptional: ',&#varname#_capi'}, + '_check': l_and(isarray, isintent_nothide) + }, { + 'frompyobj': ['\t#setdims#;', + '\tcapi_#varname#_intent |= #intent#;', + {isintent_hide: + '\tcapi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,Py_None);'}, + {isintent_nothide: + '\tcapi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,#varname#_capi);'}, + """\ +\tif (capi_#varname#_tmp == NULL) { +\t\tif (!PyErr_Occurred()) +\t\t\tPyErr_SetString(#modulename#_error,\"failed in converting #nth# `#varname#\' of #pyname# to C/Fortran array\" ); +\t} else { +\t\t#varname# = (#ctype# *)(PyArray_DATA(capi_#varname#_tmp)); +""", + {hasinitvalue: [ + {isintent_nothide: + '\tif (#varname#_capi == Py_None) {'}, + {isintent_hide: '\t{'}, + {iscomplexarray: '\t\t#ctype# capi_c;'}, + """\ +\t\tint *_i,capi_i=0; +\t\tCFUNCSMESS(\"#name#: Initializing #varname#=#init#\\n\"); +\t\tif (initforcomb(PyArray_DIMS(capi_#varname#_tmp),PyArray_NDIM(capi_#varname#_tmp),1)) { +\t\t\twhile ((_i = nextforcomb())) +\t\t\t\t#varname#[capi_i++] = #init#; /* fortran way */ +\t\t} else { +\t\t\tif (!PyErr_Occurred()) +\t\t\t\tPyErr_SetString(#modulename#_error,\"Initialization of #nth# #varname# failed (initforcomb).\"); +\t\t\tf2py_success = 0; +\t\t} +\t} +\tif (f2py_success) {"""]}, + ], + 'cleanupfrompyobj': [ # note that this list will be reversed + '\t} /*if (capi_#varname#_tmp == NULL) ... else of #varname#*/', + {l_not(l_or(isintent_out, isintent_hide)): """\ +\tif((PyObject *)capi_#varname#_tmp!=#varname#_capi) { +\t\tPy_XDECREF(capi_#varname#_tmp); }"""}, + {l_and(isintent_hide, l_not(isintent_out)) + : """\t\tPy_XDECREF(capi_#varname#_tmp);"""}, + {hasinitvalue: '\t} /*if (f2py_success) of #varname# init*/'}, + ], + '_check': isarray, + '_depend': '' + }, + # Scalararray + { # Common + '_check': l_and(isarray, l_not(iscomplexarray)) + }, { # Not hidden + '_check': l_and(isarray, l_not(iscomplexarray), isintent_nothide) + }, + # Integer*1 array + {'need': '#ctype#', + '_check': isint1array, + '_depend': '' + }, + # Integer*-1 array + {'need': '#ctype#', + '_check': isunsigned_chararray, + '_depend': '' + }, + # Integer*-2 array + {'need': '#ctype#', + '_check': isunsigned_shortarray, + '_depend': '' + }, + # Integer*-8 array + {'need': '#ctype#', + '_check': isunsigned_long_longarray, + '_depend': '' + }, + # Complexarray + {'need': '#ctype#', + '_check': iscomplexarray, + '_depend': '' + }, + # Stringarray + { + 'callfortranappend': {isarrayofstrings: 'flen(#varname#),'}, + 'need': 'string', + '_check': isstringarray + } +] + +################# Rules for checking ############### + +check_rules = [ + { + 'frompyobj': {debugcapi: '\tfprintf(stderr,\"debug-capi:Checking `#check#\'\\n\");'}, + 'need': 'len..' + }, { + 'frompyobj': '\tCHECKSCALAR(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {', + 'cleanupfrompyobj': '\t} /*CHECKSCALAR(#check#)*/', + 'need': 'CHECKSCALAR', + '_check': l_and(isscalar, l_not(iscomplex)), + '_break': '' + }, { + 'frompyobj': '\tCHECKSTRING(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {', + 'cleanupfrompyobj': '\t} /*CHECKSTRING(#check#)*/', + 'need': 'CHECKSTRING', + '_check': isstring, + '_break': '' + }, { + 'need': 'CHECKARRAY', + 'frompyobj': '\tCHECKARRAY(#check#,\"#check#\",\"#nth# #varname#\") {', + 'cleanupfrompyobj': '\t} /*CHECKARRAY(#check#)*/', + '_check': isarray, + '_break': '' + }, { + 'need': 'CHECKGENERIC', + 'frompyobj': '\tCHECKGENERIC(#check#,\"#check#\",\"#nth# #varname#\") {', + 'cleanupfrompyobj': '\t} /*CHECKGENERIC(#check#)*/', + } +] + +########## Applying the rules. No need to modify what follows ############# + +#################### Build C/API module ####################### + + +def buildmodule(m, um): + """ + Return + """ + global f2py_version, options + outmess('\tBuilding module "%s"...\n' % (m['name'])) + ret = {} + mod_rules = defmod_rules[:] + vrd = capi_maps.modsign2map(m) + rd = dictappend({'f2py_version': f2py_version}, vrd) + funcwrappers = [] + funcwrappers2 = [] # F90 codes + for n in m['interfaced']: + nb = None + for bi in m['body']: + if not bi['block'] == 'interface': + errmess('buildmodule: Expected interface block. Skipping.\n') + continue + for b in bi['body']: + if b['name'] == n: + nb = b + break + + if not nb: + errmess( + 'buildmodule: Could not found the body of interfaced routine "%s". Skipping.\n' % (n)) + continue + nb_list = [nb] + if 'entry' in nb: + for k, a in nb['entry'].items(): + nb1 = copy.deepcopy(nb) + del nb1['entry'] + nb1['name'] = k + nb1['args'] = a + nb_list.append(nb1) + for nb in nb_list: + api, wrap = buildapi(nb) + if wrap: + if ismoduleroutine(nb): + funcwrappers2.append(wrap) + else: + funcwrappers.append(wrap) + ar = applyrules(api, vrd) + rd = dictappend(rd, ar) + + # Construct COMMON block support + cr, wrap = common_rules.buildhooks(m) + if wrap: + funcwrappers.append(wrap) + ar = applyrules(cr, vrd) + rd = dictappend(rd, ar) + + # Construct F90 module support + mr, wrap = f90mod_rules.buildhooks(m) + if wrap: + funcwrappers2.append(wrap) + ar = applyrules(mr, vrd) + rd = dictappend(rd, ar) + + for u in um: + ar = use_rules.buildusevars(u, m['use'][u['name']]) + rd = dictappend(rd, ar) + + needs = cfuncs.get_needs() + code = {} + for n in needs.keys(): + code[n] = [] + for k in needs[n]: + c = '' + if k in cfuncs.includes0: + c = cfuncs.includes0[k] + elif k in cfuncs.includes: + c = cfuncs.includes[k] + elif k in cfuncs.userincludes: + c = cfuncs.userincludes[k] + elif k in cfuncs.typedefs: + c = cfuncs.typedefs[k] + elif k in cfuncs.typedefs_generated: + c = cfuncs.typedefs_generated[k] + elif k in cfuncs.cppmacros: + c = cfuncs.cppmacros[k] + elif k in cfuncs.cfuncs: + c = cfuncs.cfuncs[k] + elif k in cfuncs.callbacks: + c = cfuncs.callbacks[k] + elif k in cfuncs.f90modhooks: + c = cfuncs.f90modhooks[k] + elif k in cfuncs.commonhooks: + c = cfuncs.commonhooks[k] + else: + errmess('buildmodule: unknown need %s.\n' % (repr(k))) + continue + code[n].append(c) + mod_rules.append(code) + for r in mod_rules: + if ('_check' in r and r['_check'](m)) or ('_check' not in r): + ar = applyrules(r, vrd, m) + rd = dictappend(rd, ar) + ar = applyrules(module_rules, rd) + + fn = os.path.join(options['buildpath'], vrd['coutput']) + ret['csrc'] = fn + f = open(fn, 'w') + f.write(ar['modulebody'].replace('\t', 2 * ' ')) + f.close() + outmess('\tWrote C/API module "%s" to file "%s"\n' % (m['name'], fn)) + + if options['dorestdoc']: + fn = os.path.join( + options['buildpath'], vrd['modulename'] + 'module.rest') + f = open(fn, 'w') + f.write('.. -*- rest -*-\n') + f.write('\n'.join(ar['restdoc'])) + f.close() + outmess('\tReST Documentation is saved to file "%s/%smodule.rest"\n' % + (options['buildpath'], vrd['modulename'])) + if options['dolatexdoc']: + fn = os.path.join( + options['buildpath'], vrd['modulename'] + 'module.tex') + ret['ltx'] = fn + f = open(fn, 'w') + f.write( + '%% This file is auto-generated with f2py (version:%s)\n' % (f2py_version)) + if 'shortlatex' not in options: + f.write( + '\\documentclass{article}\n\\usepackage{a4wide}\n\\begin{document}\n\\tableofcontents\n\n') + f.write('\n'.join(ar['latexdoc'])) + if 'shortlatex' not in options: + f.write('\\end{document}') + f.close() + outmess('\tDocumentation is saved to file "%s/%smodule.tex"\n' % + (options['buildpath'], vrd['modulename'])) + if funcwrappers: + wn = os.path.join(options['buildpath'], vrd['f2py_wrapper_output']) + ret['fsrc'] = wn + f = open(wn, 'w') + f.write('C -*- fortran -*-\n') + f.write( + 'C This file is autogenerated with f2py (version:%s)\n' % (f2py_version)) + f.write( + 'C It contains Fortran 77 wrappers to fortran functions.\n') + lines = [] + for l in ('\n\n'.join(funcwrappers) + '\n').split('\n'): + if l and l[0] == ' ': + while len(l) >= 66: + lines.append(l[:66] + '\n &') + l = l[66:] + lines.append(l + '\n') + else: + lines.append(l + '\n') + lines = ''.join(lines).replace('\n &\n', '\n') + f.write(lines) + f.close() + outmess('\tFortran 77 wrappers are saved to "%s"\n' % (wn)) + if funcwrappers2: + wn = os.path.join( + options['buildpath'], '%s-f2pywrappers2.f90' % (vrd['modulename'])) + ret['fsrc'] = wn + f = open(wn, 'w') + f.write('! -*- f90 -*-\n') + f.write( + '! This file is autogenerated with f2py (version:%s)\n' % (f2py_version)) + f.write( + '! It contains Fortran 90 wrappers to fortran functions.\n') + lines = [] + for l in ('\n\n'.join(funcwrappers2) + '\n').split('\n'): + if len(l) > 72 and l[0] == ' ': + lines.append(l[:72] + '&\n &') + l = l[72:] + while len(l) > 66: + lines.append(l[:66] + '&\n &') + l = l[66:] + lines.append(l + '\n') + else: + lines.append(l + '\n') + lines = ''.join(lines).replace('\n &\n', '\n') + f.write(lines) + f.close() + outmess('\tFortran 90 wrappers are saved to "%s"\n' % (wn)) + return ret + +################## Build C/API function ############# + +stnd = {1: 'st', 2: 'nd', 3: 'rd', 4: 'th', 5: 'th', + 6: 'th', 7: 'th', 8: 'th', 9: 'th', 0: 'th'} + + +def buildapi(rout): + rout, wrap = func2subr.assubr(rout) + args, depargs = getargs2(rout) + capi_maps.depargs = depargs + var = rout['vars'] + + if ismoduleroutine(rout): + outmess('\t\t\tConstructing wrapper function "%s.%s"...\n' % + (rout['modulename'], rout['name'])) + else: + outmess('\t\tConstructing wrapper function "%s"...\n' % (rout['name'])) + # Routine + vrd = capi_maps.routsign2map(rout) + rd = dictappend({}, vrd) + for r in rout_rules: + if ('_check' in r and r['_check'](rout)) or ('_check' not in r): + ar = applyrules(r, vrd, rout) + rd = dictappend(rd, ar) + + # Args + nth, nthk = 0, 0 + savevrd = {} + for a in args: + vrd = capi_maps.sign2map(a, var[a]) + if isintent_aux(var[a]): + _rules = aux_rules + else: + _rules = arg_rules + if not isintent_hide(var[a]): + if not isoptional(var[a]): + nth = nth + 1 + vrd['nth'] = repr(nth) + stnd[nth % 10] + ' argument' + else: + nthk = nthk + 1 + vrd['nth'] = repr(nthk) + stnd[nthk % 10] + ' keyword' + else: + vrd['nth'] = 'hidden' + savevrd[a] = vrd + for r in _rules: + if '_depend' in r: + continue + if ('_check' in r and r['_check'](var[a])) or ('_check' not in r): + ar = applyrules(r, vrd, var[a]) + rd = dictappend(rd, ar) + if '_break' in r: + break + for a in depargs: + if isintent_aux(var[a]): + _rules = aux_rules + else: + _rules = arg_rules + vrd = savevrd[a] + for r in _rules: + if '_depend' not in r: + continue + if ('_check' in r and r['_check'](var[a])) or ('_check' not in r): + ar = applyrules(r, vrd, var[a]) + rd = dictappend(rd, ar) + if '_break' in r: + break + if 'check' in var[a]: + for c in var[a]['check']: + vrd['check'] = c + ar = applyrules(check_rules, vrd, var[a]) + rd = dictappend(rd, ar) + if isinstance(rd['cleanupfrompyobj'], list): + rd['cleanupfrompyobj'].reverse() + if isinstance(rd['closepyobjfrom'], list): + rd['closepyobjfrom'].reverse() + rd['docsignature'] = stripcomma(replace('#docsign##docsignopt##docsignxa#', + {'docsign': rd['docsign'], + 'docsignopt': rd['docsignopt'], + 'docsignxa': rd['docsignxa']})) + optargs = stripcomma(replace('#docsignopt##docsignxa#', + {'docsignxa': rd['docsignxashort'], + 'docsignopt': rd['docsignoptshort']} + )) + if optargs == '': + rd['docsignatureshort'] = stripcomma( + replace('#docsign#', {'docsign': rd['docsign']})) + else: + rd['docsignatureshort'] = replace('#docsign#[#docsignopt#]', + {'docsign': rd['docsign'], + 'docsignopt': optargs, + }) + rd['latexdocsignatureshort'] = rd['docsignatureshort'].replace('_', '\\_') + rd['latexdocsignatureshort'] = rd[ + 'latexdocsignatureshort'].replace(',', ', ') + cfs = stripcomma(replace('#callfortran##callfortranappend#', { + 'callfortran': rd['callfortran'], 'callfortranappend': rd['callfortranappend']})) + if len(rd['callfortranappend']) > 1: + rd['callcompaqfortran'] = stripcomma(replace('#callfortran# 0,#callfortranappend#', { + 'callfortran': rd['callfortran'], 'callfortranappend': rd['callfortranappend']})) + else: + rd['callcompaqfortran'] = cfs + rd['callfortran'] = cfs + if isinstance(rd['docreturn'], list): + rd['docreturn'] = stripcomma( + replace('#docreturn#', {'docreturn': rd['docreturn']})) + ' = ' + rd['docstrsigns'] = [] + rd['latexdocstrsigns'] = [] + for k in ['docstrreq', 'docstropt', 'docstrout', 'docstrcbs']: + if k in rd and isinstance(rd[k], list): + rd['docstrsigns'] = rd['docstrsigns'] + rd[k] + k = 'latex' + k + if k in rd and isinstance(rd[k], list): + rd['latexdocstrsigns'] = rd['latexdocstrsigns'] + rd[k][0:1] +\ + ['\\begin{description}'] + rd[k][1:] +\ + ['\\end{description}'] + + # Workaround for Python 2.6, 2.6.1 bug: http://bugs.python.org/issue4720 + if rd['keyformat'] or rd['xaformat']: + argformat = rd['argformat'] + if isinstance(argformat, list): + argformat.append('|') + else: + assert isinstance(argformat, str), repr( + (argformat, type(argformat))) + rd['argformat'] += '|' + + ar = applyrules(routine_rules, rd) + if ismoduleroutine(rout): + outmess('\t\t\t %s\n' % (ar['docshort'])) + else: + outmess('\t\t %s\n' % (ar['docshort'])) + return ar, wrap + + +#################### EOF rules.py ####################### diff --git a/numpy/f2py/setup.py b/numpy/f2py/setup.py new file mode 100644 index 0000000..3204129 --- /dev/null +++ b/numpy/f2py/setup.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +""" +setup.py for installing F2PY + +Usage: + python setup.py install + +Copyright 2001-2005 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Revision: 1.32 $ +$Date: 2005/01/30 17:22:14 $ +Pearu Peterson + +""" +from __future__ import division, print_function + +__version__ = "$Id: setup.py,v 1.32 2005/01/30 17:22:14 pearu Exp $" + +import os +import sys +from distutils.dep_util import newer +from numpy.distutils import log +from numpy.distutils.core import setup +from numpy.distutils.misc_util import Configuration + +from __version__ import version + + +def _get_f2py_shebang(): + """ Return shebang line for f2py script + + If we are building a binary distribution format, then the shebang line + should be ``#!python`` rather than ``#!`` followed by the contents of + ``sys.executable``. + """ + if set(('bdist_wheel', 'bdist_egg', 'bdist_wininst', + 'bdist_rpm')).intersection(sys.argv): + return '#!python' + return '#!' + sys.executable + + +def configuration(parent_package='', top_path=None): + config = Configuration('f2py', parent_package, top_path) + + config.add_data_dir('tests') + + config.add_data_files('src/fortranobject.c', + 'src/fortranobject.h', + ) + + config.make_svn_version_py() + + def generate_f2py_py(build_dir): + f2py_exe = 'f2py' + os.path.basename(sys.executable)[6:] + if f2py_exe[-4:] == '.exe': + f2py_exe = f2py_exe[:-4] + '.py' + if 'bdist_wininst' in sys.argv and f2py_exe[-3:] != '.py': + f2py_exe = f2py_exe + '.py' + target = os.path.join(build_dir, f2py_exe) + if newer(__file__, target): + log.info('Creating %s', target) + f = open(target, 'w') + f.write(_get_f2py_shebang() + '\n') + mainloc = os.path.join(os.path.dirname(__file__), "__main__.py") + with open(mainloc) as mf: + f.write(mf.read()) + f.close() + return target + + config.add_scripts(generate_f2py_py) + + log.info('F2PY Version %s', config.get_version()) + + return config + +if __name__ == "__main__": + + config = configuration(top_path='') + print('F2PY Version', version) + config = config.todict() + + config['download_url'] = "http://cens.ioc.ee/projects/f2py2e/2.x"\ + "/F2PY-2-latest.tar.gz" + config['classifiers'] = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: NumPy License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: C', + 'Programming Language :: Fortran', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering', + 'Topic :: Software Development :: Code Generators', + ] + setup(version=version, + description="F2PY - Fortran to Python Interface Generaton", + author="Pearu Peterson", + author_email="pearu@cens.ioc.ee", + maintainer="Pearu Peterson", + maintainer_email="pearu@cens.ioc.ee", + license="BSD", + platforms="Unix, Windows (mingw|cygwin), Mac OSX", + long_description="""\ +The Fortran to Python Interface Generator, or F2PY for short, is a +command line tool (f2py) for generating Python C/API modules for +wrapping Fortran 77/90/95 subroutines, accessing common blocks from +Python, and calling Python functions from Fortran (call-backs). +Interfacing subroutines/data from Fortran 90/95 modules is supported.""", + url="http://cens.ioc.ee/projects/f2py2e/", + keywords=['Fortran', 'f2py'], + **config) diff --git a/numpy/f2py/src/fortranobject.c b/numpy/f2py/src/fortranobject.c new file mode 100644 index 0000000..96b08ea --- /dev/null +++ b/numpy/f2py/src/fortranobject.c @@ -0,0 +1,1088 @@ +#define FORTRANOBJECT_C +#include "fortranobject.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* + This file implements: FortranObject, array_from_pyobj, copy_ND_array + + Author: Pearu Peterson + $Revision: 1.52 $ + $Date: 2005/07/11 07:44:20 $ +*/ + +int +F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj) +{ + if (obj==NULL) { + fprintf(stderr, "Error loading %s\n", name); + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + return -1; + } + return PyDict_SetItemString(dict, name, obj); +} + +/************************* FortranObject *******************************/ + +typedef PyObject *(*fortranfunc)(PyObject *,PyObject *,PyObject *,void *); + +PyObject * +PyFortranObject_New(FortranDataDef* defs, f2py_void_func init) { + int i; + PyFortranObject *fp = NULL; + PyObject *v = NULL; + if (init!=NULL) /* Initialize F90 module objects */ + (*(init))(); + if ((fp = PyObject_New(PyFortranObject, &PyFortran_Type))==NULL) return NULL; + if ((fp->dict = PyDict_New())==NULL) return NULL; + fp->len = 0; + while (defs[fp->len].name != NULL) fp->len++; + if (fp->len == 0) goto fail; + fp->defs = defs; + for (i=0;ilen;i++) + if (fp->defs[i].rank == -1) { /* Is Fortran routine */ + v = PyFortranObject_NewAsAttr(&(fp->defs[i])); + if (v==NULL) return NULL; + PyDict_SetItemString(fp->dict,fp->defs[i].name,v); + } else + if ((fp->defs[i].data)!=NULL) { /* Is Fortran variable or array (not allocatable) */ + if (fp->defs[i].type == NPY_STRING) { + int n = fp->defs[i].rank-1; + v = PyArray_New(&PyArray_Type, n, fp->defs[i].dims.d, + NPY_STRING, NULL, fp->defs[i].data, fp->defs[i].dims.d[n], + NPY_ARRAY_FARRAY, NULL); + } + else { + v = PyArray_New(&PyArray_Type, fp->defs[i].rank, fp->defs[i].dims.d, + fp->defs[i].type, NULL, fp->defs[i].data, 0, NPY_ARRAY_FARRAY, + NULL); + } + if (v==NULL) return NULL; + PyDict_SetItemString(fp->dict,fp->defs[i].name,v); + } + Py_XDECREF(v); + return (PyObject *)fp; + fail: + Py_XDECREF(v); + return NULL; +} + +PyObject * +PyFortranObject_NewAsAttr(FortranDataDef* defs) { /* used for calling F90 module routines */ + PyFortranObject *fp = NULL; + fp = PyObject_New(PyFortranObject, &PyFortran_Type); + if (fp == NULL) return NULL; + if ((fp->dict = PyDict_New())==NULL) return NULL; + fp->len = 1; + fp->defs = defs; + return (PyObject *)fp; +} + +/* Fortran methods */ + +static void +fortran_dealloc(PyFortranObject *fp) { + Py_XDECREF(fp->dict); + PyMem_Del(fp); +} + + +#if PY_VERSION_HEX >= 0x03000000 +#else +static PyMethodDef fortran_methods[] = { + {NULL, NULL} /* sentinel */ +}; +#endif + + +/* Returns number of bytes consumed from buf, or -1 on error. */ +static Py_ssize_t +format_def(char *buf, Py_ssize_t size, FortranDataDef def) +{ + char *p = buf; + int i, n; + + n = PyOS_snprintf(p, size, "array(%" NPY_INTP_FMT, def.dims.d[0]); + if (n < 0 || n >= size) { + return -1; + } + p += n; + size -= n; + + for (i = 1; i < def.rank; i++) { + n = PyOS_snprintf(p, size, ",%" NPY_INTP_FMT, def.dims.d[i]); + if (n < 0 || n >= size) { + return -1; + } + p += n; + size -= n; + } + + if (size <= 0) { + return -1; + } + + *p++ = ')'; + size--; + + if (def.data == NULL) { + static const char notalloc[] = ", not allocated"; + if (size < sizeof(notalloc)) { + return -1; + } + memcpy(p, notalloc, sizeof(notalloc)); + } + + return p - buf; +} + +static PyObject * +fortran_doc(FortranDataDef def) +{ + char *buf, *p; + PyObject *s = NULL; + Py_ssize_t n, origsize, size = 100; + + if (def.doc != NULL) { + size += strlen(def.doc); + } + origsize = size; + buf = p = (char *)PyMem_Malloc(size); + if (buf == NULL) { + return PyErr_NoMemory(); + } + + if (def.rank == -1) { + if (def.doc) { + n = strlen(def.doc); + if (n > size) { + goto fail; + } + memcpy(p, def.doc, n); + p += n; + size -= n; + } + else { + n = PyOS_snprintf(p, size, "%s - no docs available", def.name); + if (n < 0 || n >= size) { + goto fail; + } + p += n; + size -= n; + } + } + else { + PyArray_Descr *d = PyArray_DescrFromType(def.type); + n = PyOS_snprintf(p, size, "'%c'-", d->type); + Py_DECREF(d); + if (n < 0 || n >= size) { + goto fail; + } + p += n; + size -= n; + + if (def.data == NULL) { + n = format_def(p, size, def) == -1; + if (n < 0) { + goto fail; + } + p += n; + size -= n; + } + else if (def.rank > 0) { + n = format_def(p, size, def); + if (n < 0) { + goto fail; + } + p += n; + size -= n; + } + else { + n = strlen("scalar"); + if (size < n) { + goto fail; + } + memcpy(p, "scalar", n); + p += n; + size -= n; + } + } + if (size <= 1) { + goto fail; + } + *p++ = '\n'; + size--; + + /* p now points one beyond the last character of the string in buf */ +#if PY_VERSION_HEX >= 0x03000000 + s = PyUnicode_FromStringAndSize(buf, p - buf); +#else + s = PyString_FromStringAndSize(buf, p - buf); +#endif + + PyMem_Free(buf); + return s; + + fail: + fprintf(stderr, "fortranobject.c: fortran_doc: len(p)=%zd>%zd=size:" + " too long docstring required, increase size\n", + p - buf, origsize); + PyMem_Free(buf); + return NULL; +} + +static FortranDataDef *save_def; /* save pointer of an allocatable array */ +static void set_data(char *d,npy_intp *f) { /* callback from Fortran */ + if (*f) /* In fortran f=allocated(d) */ + save_def->data = d; + else + save_def->data = NULL; + /* printf("set_data: d=%p,f=%d\n",d,*f); */ +} + +static PyObject * +fortran_getattr(PyFortranObject *fp, char *name) { + int i,j,k,flag; + if (fp->dict != NULL) { + PyObject *v = PyDict_GetItemString(fp->dict, name); + if (v != NULL) { + Py_INCREF(v); + return v; + } + } + for (i=0,j=1;ilen && (j=strcmp(name,fp->defs[i].name));i++); + if (j==0) + if (fp->defs[i].rank!=-1) { /* F90 allocatable array */ + if (fp->defs[i].func==NULL) return NULL; + for(k=0;kdefs[i].rank;++k) + fp->defs[i].dims.d[k]=-1; + save_def = &fp->defs[i]; + (*(fp->defs[i].func))(&fp->defs[i].rank,fp->defs[i].dims.d,set_data,&flag); + if (flag==2) + k = fp->defs[i].rank + 1; + else + k = fp->defs[i].rank; + if (fp->defs[i].data !=NULL) { /* array is allocated */ + PyObject *v = PyArray_New(&PyArray_Type, k, fp->defs[i].dims.d, + fp->defs[i].type, NULL, fp->defs[i].data, 0, NPY_ARRAY_FARRAY, + NULL); + if (v==NULL) return NULL; + /* Py_INCREF(v); */ + return v; + } else { /* array is not allocated */ + Py_RETURN_NONE; + } + } + if (strcmp(name,"__dict__")==0) { + Py_INCREF(fp->dict); + return fp->dict; + } + if (strcmp(name,"__doc__")==0) { +#if PY_VERSION_HEX >= 0x03000000 + PyObject *s = PyUnicode_FromString(""), *s2, *s3; + for (i=0;ilen;i++) { + s2 = fortran_doc(fp->defs[i]); + s3 = PyUnicode_Concat(s, s2); + Py_DECREF(s2); + Py_DECREF(s); + s = s3; + } +#else + PyObject *s = PyString_FromString(""); + for (i=0;ilen;i++) + PyString_ConcatAndDel(&s,fortran_doc(fp->defs[i])); +#endif + if (PyDict_SetItemString(fp->dict, name, s)) + return NULL; + return s; + } + if ((strcmp(name,"_cpointer")==0) && (fp->len==1)) { + PyObject *cobj = F2PyCapsule_FromVoidPtr((void *)(fp->defs[0].data),NULL); + if (PyDict_SetItemString(fp->dict, name, cobj)) + return NULL; + return cobj; + } +#if PY_VERSION_HEX >= 0x03000000 + if (1) { + PyObject *str, *ret; + str = PyUnicode_FromString(name); + ret = PyObject_GenericGetAttr((PyObject *)fp, str); + Py_DECREF(str); + return ret; + } +#else + return Py_FindMethod(fortran_methods, (PyObject *)fp, name); +#endif +} + +static int +fortran_setattr(PyFortranObject *fp, char *name, PyObject *v) { + int i,j,flag; + PyArrayObject *arr = NULL; + for (i=0,j=1;ilen && (j=strcmp(name,fp->defs[i].name));i++); + if (j==0) { + if (fp->defs[i].rank==-1) { + PyErr_SetString(PyExc_AttributeError,"over-writing fortran routine"); + return -1; + } + if (fp->defs[i].func!=NULL) { /* is allocatable array */ + npy_intp dims[F2PY_MAX_DIMS]; + int k; + save_def = &fp->defs[i]; + if (v!=Py_None) { /* set new value (reallocate if needed -- + see f2py generated code for more + details ) */ + for(k=0;kdefs[i].rank;k++) dims[k]=-1; + if ((arr = array_from_pyobj(fp->defs[i].type,dims,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL) + return -1; + (*(fp->defs[i].func))(&fp->defs[i].rank,PyArray_DIMS(arr),set_data,&flag); + } else { /* deallocate */ + for(k=0;kdefs[i].rank;k++) dims[k]=0; + (*(fp->defs[i].func))(&fp->defs[i].rank,dims,set_data,&flag); + for(k=0;kdefs[i].rank;k++) dims[k]=-1; + } + memcpy(fp->defs[i].dims.d,dims,fp->defs[i].rank*sizeof(npy_intp)); + } else { /* not allocatable array */ + if ((arr = array_from_pyobj(fp->defs[i].type,fp->defs[i].dims.d,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL) + return -1; + } + if (fp->defs[i].data!=NULL) { /* copy Python object to Fortran array */ + npy_intp s = PyArray_MultiplyList(fp->defs[i].dims.d,PyArray_NDIM(arr)); + if (s==-1) + s = PyArray_MultiplyList(PyArray_DIMS(arr),PyArray_NDIM(arr)); + if (s<0 || + (memcpy(fp->defs[i].data,PyArray_DATA(arr),s*PyArray_ITEMSIZE(arr)))==NULL) { + if ((PyObject*)arr!=v) { + Py_DECREF(arr); + } + return -1; + } + if ((PyObject*)arr!=v) { + Py_DECREF(arr); + } + } else return (fp->defs[i].func==NULL?-1:0); + return 0; /* successful */ + } + if (fp->dict == NULL) { + fp->dict = PyDict_New(); + if (fp->dict == NULL) + return -1; + } + if (v == NULL) { + int rv = PyDict_DelItemString(fp->dict, name); + if (rv < 0) + PyErr_SetString(PyExc_AttributeError,"delete non-existing fortran attribute"); + return rv; + } + else + return PyDict_SetItemString(fp->dict, name, v); +} + +static PyObject* +fortran_call(PyFortranObject *fp, PyObject *arg, PyObject *kw) { + int i = 0; + /* printf("fortran call + name=%s,func=%p,data=%p,%p\n",fp->defs[i].name, + fp->defs[i].func,fp->defs[i].data,&fp->defs[i].data); */ + if (fp->defs[i].rank==-1) {/* is Fortran routine */ + if (fp->defs[i].func==NULL) { + PyErr_Format(PyExc_RuntimeError, "no function to call"); + return NULL; + } + else if (fp->defs[i].data==NULL) + /* dummy routine */ + return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw,NULL); + else + return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw, + (void *)fp->defs[i].data); + } + PyErr_Format(PyExc_TypeError, "this fortran object is not callable"); + return NULL; +} + +static PyObject * +fortran_repr(PyFortranObject *fp) +{ + PyObject *name = NULL, *repr = NULL; + name = PyObject_GetAttrString((PyObject *)fp, "__name__"); + PyErr_Clear(); +#if PY_VERSION_HEX >= 0x03000000 + if (name != NULL && PyUnicode_Check(name)) { + repr = PyUnicode_FromFormat("", name); + } + else { + repr = PyUnicode_FromString(""); + } +#else + if (name != NULL && PyString_Check(name)) { + repr = PyString_FromFormat("", PyString_AsString(name)); + } + else { + repr = PyString_FromString(""); + } +#endif + Py_XDECREF(name); + return repr; +} + + +PyTypeObject PyFortran_Type = { +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ +#endif + "fortran", /*tp_name*/ + sizeof(PyFortranObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)fortran_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)fortran_getattr, /*tp_getattr*/ + (setattrfunc)fortran_setattr, /*tp_setattr*/ + 0, /*tp_compare/tp_reserved*/ + (reprfunc)fortran_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + (ternaryfunc)fortran_call, /*tp_call*/ +}; + +/************************* f2py_report_atexit *******************************/ + +#ifdef F2PY_REPORT_ATEXIT +static int passed_time = 0; +static int passed_counter = 0; +static int passed_call_time = 0; +static struct timeb start_time; +static struct timeb stop_time; +static struct timeb start_call_time; +static struct timeb stop_call_time; +static int cb_passed_time = 0; +static int cb_passed_counter = 0; +static int cb_passed_call_time = 0; +static struct timeb cb_start_time; +static struct timeb cb_stop_time; +static struct timeb cb_start_call_time; +static struct timeb cb_stop_call_time; + +extern void f2py_start_clock(void) { ftime(&start_time); } +extern +void f2py_start_call_clock(void) { + f2py_stop_clock(); + ftime(&start_call_time); +} +extern +void f2py_stop_clock(void) { + ftime(&stop_time); + passed_time += 1000*(stop_time.time - start_time.time); + passed_time += stop_time.millitm - start_time.millitm; +} +extern +void f2py_stop_call_clock(void) { + ftime(&stop_call_time); + passed_call_time += 1000*(stop_call_time.time - start_call_time.time); + passed_call_time += stop_call_time.millitm - start_call_time.millitm; + passed_counter += 1; + f2py_start_clock(); +} + +extern void f2py_cb_start_clock(void) { ftime(&cb_start_time); } +extern +void f2py_cb_start_call_clock(void) { + f2py_cb_stop_clock(); + ftime(&cb_start_call_time); +} +extern +void f2py_cb_stop_clock(void) { + ftime(&cb_stop_time); + cb_passed_time += 1000*(cb_stop_time.time - cb_start_time.time); + cb_passed_time += cb_stop_time.millitm - cb_start_time.millitm; +} +extern +void f2py_cb_stop_call_clock(void) { + ftime(&cb_stop_call_time); + cb_passed_call_time += 1000*(cb_stop_call_time.time - cb_start_call_time.time); + cb_passed_call_time += cb_stop_call_time.millitm - cb_start_call_time.millitm; + cb_passed_counter += 1; + f2py_cb_start_clock(); +} + +static int f2py_report_on_exit_been_here = 0; +extern +void f2py_report_on_exit(int exit_flag,void *name) { + if (f2py_report_on_exit_been_here) { + fprintf(stderr," %s\n",(char*)name); + return; + } + f2py_report_on_exit_been_here = 1; + fprintf(stderr," /-----------------------\\\n"); + fprintf(stderr," < F2PY performance report >\n"); + fprintf(stderr," \\-----------------------/\n"); + fprintf(stderr,"Overall time spent in ...\n"); + fprintf(stderr,"(a) wrapped (Fortran/C) functions : %8d msec\n", + passed_call_time); + fprintf(stderr,"(b) f2py interface, %6d calls : %8d msec\n", + passed_counter,passed_time); + fprintf(stderr,"(c) call-back (Python) functions : %8d msec\n", + cb_passed_call_time); + fprintf(stderr,"(d) f2py call-back interface, %6d calls : %8d msec\n", + cb_passed_counter,cb_passed_time); + + fprintf(stderr,"(e) wrapped (Fortran/C) functions (acctual) : %8d msec\n\n", + passed_call_time-cb_passed_call_time-cb_passed_time); + fprintf(stderr,"Use -DF2PY_REPORT_ATEXIT_DISABLE to disable this message.\n"); + fprintf(stderr,"Exit status: %d\n",exit_flag); + fprintf(stderr,"Modules : %s\n",(char*)name); +} +#endif + +/********************** report on array copy ****************************/ + +#ifdef F2PY_REPORT_ON_ARRAY_COPY +static void f2py_report_on_array_copy(PyArrayObject* arr) { + const npy_intp arr_size = PyArray_Size((PyObject *)arr); + if (arr_size>F2PY_REPORT_ON_ARRAY_COPY) { + fprintf(stderr,"copied an array: size=%ld, elsize=%"NPY_INTP_FMT"\n", + arr_size, (npy_intp)PyArray_ITEMSIZE(arr)); + } +} +static void f2py_report_on_array_copy_fromany(void) { + fprintf(stderr,"created an array from object\n"); +} + +#define F2PY_REPORT_ON_ARRAY_COPY_FROMARR f2py_report_on_array_copy((PyArrayObject *)arr) +#define F2PY_REPORT_ON_ARRAY_COPY_FROMANY f2py_report_on_array_copy_fromany() +#else +#define F2PY_REPORT_ON_ARRAY_COPY_FROMARR +#define F2PY_REPORT_ON_ARRAY_COPY_FROMANY +#endif + + +/************************* array_from_obj *******************************/ + +/* + * File: array_from_pyobj.c + * + * Description: + * ------------ + * Provides array_from_pyobj function that returns a contigious array + * object with the given dimensions and required storage order, either + * in row-major (C) or column-major (Fortran) order. The function + * array_from_pyobj is very flexible about its Python object argument + * that can be any number, list, tuple, or array. + * + * array_from_pyobj is used in f2py generated Python extension + * modules. + * + * Author: Pearu Peterson + * Created: 13-16 January 2002 + * $Id: fortranobject.c,v 1.52 2005/07/11 07:44:20 pearu Exp $ + */ + +static int check_and_fix_dimensions(const PyArrayObject* arr, + const int rank, + npy_intp *dims); + +static int +count_negative_dimensions(const int rank, + const npy_intp *dims) { + int i=0,r=0; + while (iflags,size); + printf("\tstrides = "); + dump_dims(rank,arr->strides); + printf("\tdimensions = "); + dump_dims(rank,arr->dimensions); +} +#endif + +#define SWAPTYPE(a,b,t) {t c; c = (a); (a) = (b); (b) = c; } + +static int swap_arrays(PyArrayObject* obj1, PyArrayObject* obj2) { + PyArrayObject_fields *arr1 = (PyArrayObject_fields*) obj1, + *arr2 = (PyArrayObject_fields*) obj2; + SWAPTYPE(arr1->data,arr2->data,char*); + SWAPTYPE(arr1->nd,arr2->nd,int); + SWAPTYPE(arr1->dimensions,arr2->dimensions,npy_intp*); + SWAPTYPE(arr1->strides,arr2->strides,npy_intp*); + SWAPTYPE(arr1->base,arr2->base,PyObject*); + SWAPTYPE(arr1->descr,arr2->descr,PyArray_Descr*); + SWAPTYPE(arr1->flags,arr2->flags,int); + /* SWAPTYPE(arr1->weakreflist,arr2->weakreflist,PyObject*); */ + return 0; +} + +#define ARRAY_ISCOMPATIBLE(arr,type_num) \ + ( (PyArray_ISINTEGER(arr) && PyTypeNum_ISINTEGER(type_num)) \ + ||(PyArray_ISFLOAT(arr) && PyTypeNum_ISFLOAT(type_num)) \ + ||(PyArray_ISCOMPLEX(arr) && PyTypeNum_ISCOMPLEX(type_num)) \ + ||(PyArray_ISBOOL(arr) && PyTypeNum_ISBOOL(type_num)) \ + ) + +extern +PyArrayObject* array_from_pyobj(const int type_num, + npy_intp *dims, + const int rank, + const int intent, + PyObject *obj) { + /* Note about reference counting + ----------------------------- + If the caller returns the array to Python, it must be done with + Py_BuildValue("N",arr). + Otherwise, if obj!=arr then the caller must call Py_DECREF(arr). + + Note on intent(cache,out,..) + --------------------- + Don't expect correct data when returning intent(cache) array. + + */ + char mess[200]; + PyArrayObject *arr = NULL; + PyArray_Descr *descr; + char typechar; + int elsize; + + if ((intent & F2PY_INTENT_HIDE) + || ((intent & F2PY_INTENT_CACHE) && (obj==Py_None)) + || ((intent & F2PY_OPTIONAL) && (obj==Py_None)) + ) { + /* intent(cache), optional, intent(hide) */ + if (count_negative_dimensions(rank,dims) > 0) { + int i; + strcpy(mess, "failed to create intent(cache|hide)|optional array" + "-- must have defined dimensions but got ("); + for(i=0;ielsize = 1; + descr->type = NPY_CHARLTR; + } + elsize = descr->elsize; + typechar = descr->type; + Py_DECREF(descr); + if (PyArray_Check(obj)) { + arr = (PyArrayObject *)obj; + + if (intent & F2PY_INTENT_CACHE) { + /* intent(cache) */ + if (PyArray_ISONESEGMENT(arr) + && PyArray_ITEMSIZE(arr)>=elsize) { + if (check_and_fix_dimensions(arr, rank, dims)) { + return NULL; + } + if (intent & F2PY_INTENT_OUT) + Py_INCREF(arr); + return arr; + } + strcpy(mess, "failed to initialize intent(cache) array"); + if (!PyArray_ISONESEGMENT(arr)) + strcat(mess, " -- input must be in one segment"); + if (PyArray_ITEMSIZE(arr)type,typechar); + if (!(F2PY_CHECK_ALIGNMENT(arr, intent))) + sprintf(mess+strlen(mess)," -- input not %d-aligned", F2PY_GET_ALIGNMENT(intent)); + PyErr_SetString(PyExc_ValueError,mess); + return NULL; + } + + /* here we have always intent(in) or intent(inplace) */ + + { + PyArrayObject * retarr; + retarr = (PyArrayObject *) \ + PyArray_New(&PyArray_Type, PyArray_NDIM(arr), PyArray_DIMS(arr), type_num, + NULL,NULL,1, + !(intent&F2PY_INTENT_C), + NULL); + if (retarr==NULL) + return NULL; + F2PY_REPORT_ON_ARRAY_COPY_FROMARR; + if (PyArray_CopyInto(retarr, arr)) { + Py_DECREF(retarr); + return NULL; + } + if (intent & F2PY_INTENT_INPLACE) { + if (swap_arrays(arr,retarr)) + return NULL; /* XXX: set exception */ + Py_XDECREF(retarr); + if (intent & F2PY_INTENT_OUT) + Py_INCREF(arr); + } else { + arr = retarr; + } + } + return arr; + } + + if ((intent & F2PY_INTENT_INOUT) || + (intent & F2PY_INTENT_INPLACE) || + (intent & F2PY_INTENT_CACHE)) { + PyErr_SetString(PyExc_TypeError, + "failed to initialize intent(inout|inplace|cache) " + "array, input not an array"); + return NULL; + } + + { + PyArray_Descr * descr = PyArray_DescrFromType(type_num); + /* compatibility with NPY_CHAR */ + if (type_num == NPY_STRING) { + PyArray_DESCR_REPLACE(descr); + if (descr == NULL) { + return NULL; + } + descr->elsize = 1; + descr->type = NPY_CHARLTR; + } + F2PY_REPORT_ON_ARRAY_COPY_FROMANY; + arr = (PyArrayObject *) \ + PyArray_FromAny(obj, descr, 0,0, + ((intent & F2PY_INTENT_C)?NPY_ARRAY_CARRAY:NPY_ARRAY_FARRAY) \ + | NPY_ARRAY_FORCECAST, NULL); + if (arr==NULL) + return NULL; + if (check_and_fix_dimensions(arr, rank, dims)) { + return NULL; + } + return arr; + } + +} + +/*****************************************/ +/* Helper functions for array_from_pyobj */ +/*****************************************/ + +static +int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp *dims) +{ + /* + This function fills in blanks (that are -1's) in dims list using + the dimensions from arr. It also checks that non-blank dims will + match with the corresponding values in arr dimensions. + + Returns 0 if the function is successful. + + If an error condition is detected, an exception is set and 1 is returned. + */ + const npy_intp arr_size = (PyArray_NDIM(arr))?PyArray_Size((PyObject *)arr):1; +#ifdef DEBUG_COPY_ND_ARRAY + dump_attrs(arr); + printf("check_and_fix_dimensions:init: dims="); + dump_dims(rank,dims); +#endif + if (rank > PyArray_NDIM(arr)) { /* [1,2] -> [[1],[2]]; 1 -> [[1]] */ + npy_intp new_size = 1; + int free_axe = -1; + int i; + npy_intp d; + /* Fill dims where -1 or 0; check dimensions; calc new_size; */ + for(i=0;i= 0) { + if (d>1 && dims[i]!=d) { + PyErr_Format(PyExc_ValueError, + "%d-th dimension must be fixed to %" + NPY_INTP_FMT " but got %" NPY_INTP_FMT "\n", + i, dims[i], d); + return 1; + } + if (!dims[i]) dims[i] = 1; + } else { + dims[i] = d ? d : 1; + } + new_size *= dims[i]; + } + for(i=PyArray_NDIM(arr);i1) { + PyErr_Format(PyExc_ValueError, + "%d-th dimension must be %" NPY_INTP_FMT + " but got 0 (not defined).\n", + i, dims[i]); + return 1; + } else if (free_axe<0) + free_axe = i; + else + dims[i] = 1; + if (free_axe>=0) { + dims[free_axe] = arr_size/new_size; + new_size *= dims[free_axe]; + } + if (new_size != arr_size) { + PyErr_Format(PyExc_ValueError, + "unexpected array size: new_size=%" NPY_INTP_FMT + ", got array with arr_size=%" NPY_INTP_FMT + " (maybe too many free indices)\n", + new_size, arr_size); + return 1; + } + } else if (rank==PyArray_NDIM(arr)) { + npy_intp new_size = 1; + int i; + npy_intp d; + for (i=0; i=0) { + if (d > 1 && d!=dims[i]) { + PyErr_Format(PyExc_ValueError, + "%d-th dimension must be fixed to %" + NPY_INTP_FMT " but got %" NPY_INTP_FMT "\n", + i, dims[i], d); + return 1; + } + if (!dims[i]) dims[i] = 1; + } else dims[i] = d; + new_size *= dims[i]; + } + if (new_size != arr_size) { + PyErr_Format(PyExc_ValueError, + "unexpected array size: new_size=%" NPY_INTP_FMT + ", got array with arr_size=%" NPY_INTP_FMT "\n", + new_size, arr_size); + return 1; + } + } else { /* [[1,2]] -> [[1],[2]] */ + int i,j; + npy_intp d; + int effrank; + npy_intp size; + for (i=0,effrank=0;i1) ++effrank; + if (dims[rank-1]>=0) + if (effrank>rank) { + PyErr_Format(PyExc_ValueError, + "too many axes: %d (effrank=%d), " + "expected rank=%d\n", + PyArray_NDIM(arr), effrank, rank); + return 1; + } + + for (i=0,j=0;i=PyArray_NDIM(arr)) d = 1; + else d = PyArray_DIM(arr,j++); + if (dims[i]>=0) { + if (d>1 && d!=dims[i]) { + PyErr_Format(PyExc_ValueError, + "%d-th dimension must be fixed to %" + NPY_INTP_FMT " but got %" NPY_INTP_FMT + " (real index=%d)\n", + i, dims[i], d, j-1); + return 1; + } + if (!dims[i]) dims[i] = 1; + } else + dims[i] = d; + } + + for (i=rank;i [1,2,3,4] */ + while (j=PyArray_NDIM(arr)) d = 1; + else d = PyArray_DIM(arr,j++); + dims[rank-1] *= d; + } + for (i=0,size=1;i= 0x03000000 +#define PyString_Check PyBytes_Check +#define PyString_GET_SIZE PyBytes_GET_SIZE +#define PyString_AS_STRING PyBytes_AS_STRING +#define PyString_FromString PyBytes_FromString +#define PyUString_FromStringAndSize PyUnicode_FromStringAndSize +#define PyString_ConcatAndDel PyBytes_ConcatAndDel +#define PyString_AsString PyBytes_AsString + +#define PyInt_Check PyLong_Check +#define PyInt_FromLong PyLong_FromLong +#define PyInt_AS_LONG PyLong_AsLong +#define PyInt_AsLong PyLong_AsLong + +#define PyNumber_Int PyNumber_Long + +#else + +#define PyUString_FromStringAndSize PyString_FromStringAndSize +#endif + + +#ifdef F2PY_REPORT_ATEXIT +#include + extern void f2py_start_clock(void); + extern void f2py_stop_clock(void); + extern void f2py_start_call_clock(void); + extern void f2py_stop_call_clock(void); + extern void f2py_cb_start_clock(void); + extern void f2py_cb_stop_clock(void); + extern void f2py_cb_start_call_clock(void); + extern void f2py_cb_stop_call_clock(void); + extern void f2py_report_on_exit(int,void*); +#endif + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +/* Fortran object interface */ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +PyFortranObject represents various Fortran objects: +Fortran (module) routines, COMMON blocks, module data. + +Author: Pearu Peterson +*/ + +#define F2PY_MAX_DIMS 40 + +typedef void (*f2py_set_data_func)(char*,npy_intp*); +typedef void (*f2py_void_func)(void); +typedef void (*f2py_init_func)(int*,npy_intp*,f2py_set_data_func,int*); + + /*typedef void* (*f2py_c_func)(void*,...);*/ + +typedef void *(*f2pycfunc)(void); + +typedef struct { + char *name; /* attribute (array||routine) name */ + int rank; /* array rank, 0 for scalar, max is F2PY_MAX_DIMS, + || rank=-1 for Fortran routine */ + struct {npy_intp d[F2PY_MAX_DIMS];} dims; /* dimensions of the array, || not used */ + int type; /* PyArray_ || not used */ + char *data; /* pointer to array || Fortran routine */ + f2py_init_func func; /* initialization function for + allocatable arrays: + func(&rank,dims,set_ptr_func,name,len(name)) + || C/API wrapper for Fortran routine */ + char *doc; /* documentation string; only recommended + for routines. */ +} FortranDataDef; + +typedef struct { + PyObject_HEAD + int len; /* Number of attributes */ + FortranDataDef *defs; /* An array of FortranDataDef's */ + PyObject *dict; /* Fortran object attribute dictionary */ +} PyFortranObject; + +#define PyFortran_Check(op) (Py_TYPE(op) == &PyFortran_Type) +#define PyFortran_Check1(op) (0==strcmp(Py_TYPE(op)->tp_name,"fortran")) + + extern PyTypeObject PyFortran_Type; + extern int F2PyDict_SetItemString(PyObject* dict, char *name, PyObject *obj); + extern PyObject * PyFortranObject_New(FortranDataDef* defs, f2py_void_func init); + extern PyObject * PyFortranObject_NewAsAttr(FortranDataDef* defs); + +#if PY_VERSION_HEX >= 0x03000000 + +PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *)); +void * F2PyCapsule_AsVoidPtr(PyObject *obj); +int F2PyCapsule_Check(PyObject *ptr); + +#else + +PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(void *)); +void * F2PyCapsule_AsVoidPtr(PyObject *ptr); +int F2PyCapsule_Check(PyObject *ptr); + +#endif + +#define ISCONTIGUOUS(m) (PyArray_FLAGS(m) & NPY_ARRAY_C_CONTIGUOUS) +#define F2PY_INTENT_IN 1 +#define F2PY_INTENT_INOUT 2 +#define F2PY_INTENT_OUT 4 +#define F2PY_INTENT_HIDE 8 +#define F2PY_INTENT_CACHE 16 +#define F2PY_INTENT_COPY 32 +#define F2PY_INTENT_C 64 +#define F2PY_OPTIONAL 128 +#define F2PY_INTENT_INPLACE 256 +#define F2PY_INTENT_ALIGNED4 512 +#define F2PY_INTENT_ALIGNED8 1024 +#define F2PY_INTENT_ALIGNED16 2048 + +#define ARRAY_ISALIGNED(ARR, SIZE) ((size_t)(PyArray_DATA(ARR)) % (SIZE) == 0) +#define F2PY_ALIGN4(intent) (intent & F2PY_INTENT_ALIGNED4) +#define F2PY_ALIGN8(intent) (intent & F2PY_INTENT_ALIGNED8) +#define F2PY_ALIGN16(intent) (intent & F2PY_INTENT_ALIGNED16) + +#define F2PY_GET_ALIGNMENT(intent) \ + (F2PY_ALIGN4(intent) ? 4 : \ + (F2PY_ALIGN8(intent) ? 8 : \ + (F2PY_ALIGN16(intent) ? 16 : 1) )) +#define F2PY_CHECK_ALIGNMENT(arr, intent) ARRAY_ISALIGNED(arr, F2PY_GET_ALIGNMENT(intent)) + + extern PyArrayObject* array_from_pyobj(const int type_num, + npy_intp *dims, + const int rank, + const int intent, + PyObject *obj); + extern int copy_ND_array(const PyArrayObject *in, PyArrayObject *out); + +#ifdef DEBUG_COPY_ND_ARRAY + extern void dump_attrs(const PyArrayObject* arr); +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FORTRANOBJECT_H */ diff --git a/numpy/f2py/tests/__init__.py b/numpy/f2py/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/f2py/tests/__init__.py diff --git a/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c b/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c new file mode 100644 index 0000000..22801ab --- /dev/null +++ b/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c @@ -0,0 +1,224 @@ +/* File: wrapmodule.c + * This file is auto-generated with f2py (version:2_1330). + * Hand edited by Pearu. + * f2py is a Fortran to Python Interface Generator (FPIG), Second Edition, + * written by Pearu Peterson . + * See http://cens.ioc.ee/projects/f2py2e/ + * Generation date: Fri Oct 21 22:41:12 2005 + * $Revision:$ + * $Date:$ + * Do not edit this file directly unless you know what you are doing!!! + */ +#ifdef __cplusplus +extern "C" { +#endif + +/*********************** See f2py2e/cfuncs.py: includes ***********************/ +#include "Python.h" +#include "fortranobject.h" +#include + +static PyObject *wrap_error; +static PyObject *wrap_module; + +/************************************ call ************************************/ +static char doc_f2py_rout_wrap_call[] = "\ +Function signature:\n\ + arr = call(type_num,dims,intent,obj)\n\ +Required arguments:\n" +" type_num : input int\n" +" dims : input int-sequence\n" +" intent : input int\n" +" obj : input python object\n" +"Return objects:\n" +" arr : array"; +static PyObject *f2py_rout_wrap_call(PyObject *capi_self, + PyObject *capi_args) { + PyObject * volatile capi_buildvalue = NULL; + int type_num = 0; + npy_intp *dims = NULL; + PyObject *dims_capi = Py_None; + int rank = 0; + int intent = 0; + PyArrayObject *capi_arr_tmp = NULL; + PyObject *arr_capi = Py_None; + int i; + + if (!PyArg_ParseTuple(capi_args,"iOiO|:wrap.call",\ + &type_num,&dims_capi,&intent,&arr_capi)) + return NULL; + rank = PySequence_Length(dims_capi); + dims = malloc(rank*sizeof(npy_intp)); + for (i=0;ikind, + PyArray_DESCR(arr)->type, + PyArray_TYPE(arr), + PyArray_ITEMSIZE(arr), + PyArray_DESCR(arr)->alignment, + PyArray_FLAGS(arr), + PyArray_ITEMSIZE(arr)); +} + +static PyMethodDef f2py_module_methods[] = { + + {"call",f2py_rout_wrap_call,METH_VARARGS,doc_f2py_rout_wrap_call}, + {"array_attrs",f2py_rout_wrap_attrs,METH_VARARGS,doc_f2py_rout_wrap_attrs}, + {NULL,NULL} +}; + +#if PY_VERSION_HEX >= 0x03000000 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "test_array_from_pyobj_ext", + NULL, + -1, + f2py_module_methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#if PY_VERSION_HEX >= 0x03000000 +#define RETVAL m +PyMODINIT_FUNC PyInit_test_array_from_pyobj_ext(void) { +#else +#define RETVAL +PyMODINIT_FUNC inittest_array_from_pyobj_ext(void) { +#endif + PyObject *m,*d, *s; +#if PY_VERSION_HEX >= 0x03000000 + m = wrap_module = PyModule_Create(&moduledef); +#else + m = wrap_module = Py_InitModule("test_array_from_pyobj_ext", f2py_module_methods); +#endif + Py_TYPE(&PyFortran_Type) = &PyType_Type; + import_array(); + if (PyErr_Occurred()) + Py_FatalError("can't initialize module wrap (failed to import numpy)"); + d = PyModule_GetDict(m); + s = PyString_FromString("This module 'wrap' is auto-generated with f2py (version:2_1330).\nFunctions:\n" +" arr = call(type_num,dims,intent,obj)\n" +"."); + PyDict_SetItemString(d, "__doc__", s); + wrap_error = PyErr_NewException ("wrap.error", NULL, NULL); + Py_DECREF(s); + PyDict_SetItemString(d, "F2PY_INTENT_IN", PyInt_FromLong(F2PY_INTENT_IN)); + PyDict_SetItemString(d, "F2PY_INTENT_INOUT", PyInt_FromLong(F2PY_INTENT_INOUT)); + PyDict_SetItemString(d, "F2PY_INTENT_OUT", PyInt_FromLong(F2PY_INTENT_OUT)); + PyDict_SetItemString(d, "F2PY_INTENT_HIDE", PyInt_FromLong(F2PY_INTENT_HIDE)); + PyDict_SetItemString(d, "F2PY_INTENT_CACHE", PyInt_FromLong(F2PY_INTENT_CACHE)); + PyDict_SetItemString(d, "F2PY_INTENT_COPY", PyInt_FromLong(F2PY_INTENT_COPY)); + PyDict_SetItemString(d, "F2PY_INTENT_C", PyInt_FromLong(F2PY_INTENT_C)); + PyDict_SetItemString(d, "F2PY_OPTIONAL", PyInt_FromLong(F2PY_OPTIONAL)); + PyDict_SetItemString(d, "F2PY_INTENT_INPLACE", PyInt_FromLong(F2PY_INTENT_INPLACE)); + PyDict_SetItemString(d, "NPY_BOOL", PyInt_FromLong(NPY_BOOL)); + PyDict_SetItemString(d, "NPY_BYTE", PyInt_FromLong(NPY_BYTE)); + PyDict_SetItemString(d, "NPY_UBYTE", PyInt_FromLong(NPY_UBYTE)); + PyDict_SetItemString(d, "NPY_SHORT", PyInt_FromLong(NPY_SHORT)); + PyDict_SetItemString(d, "NPY_USHORT", PyInt_FromLong(NPY_USHORT)); + PyDict_SetItemString(d, "NPY_INT", PyInt_FromLong(NPY_INT)); + PyDict_SetItemString(d, "NPY_UINT", PyInt_FromLong(NPY_UINT)); + PyDict_SetItemString(d, "NPY_INTP", PyInt_FromLong(NPY_INTP)); + PyDict_SetItemString(d, "NPY_UINTP", PyInt_FromLong(NPY_UINTP)); + PyDict_SetItemString(d, "NPY_LONG", PyInt_FromLong(NPY_LONG)); + PyDict_SetItemString(d, "NPY_ULONG", PyInt_FromLong(NPY_ULONG)); + PyDict_SetItemString(d, "NPY_LONGLONG", PyInt_FromLong(NPY_LONGLONG)); + PyDict_SetItemString(d, "NPY_ULONGLONG", PyInt_FromLong(NPY_ULONGLONG)); + PyDict_SetItemString(d, "NPY_FLOAT", PyInt_FromLong(NPY_FLOAT)); + PyDict_SetItemString(d, "NPY_DOUBLE", PyInt_FromLong(NPY_DOUBLE)); + PyDict_SetItemString(d, "NPY_LONGDOUBLE", PyInt_FromLong(NPY_LONGDOUBLE)); + PyDict_SetItemString(d, "NPY_CFLOAT", PyInt_FromLong(NPY_CFLOAT)); + PyDict_SetItemString(d, "NPY_CDOUBLE", PyInt_FromLong(NPY_CDOUBLE)); + PyDict_SetItemString(d, "NPY_CLONGDOUBLE", PyInt_FromLong(NPY_CLONGDOUBLE)); + PyDict_SetItemString(d, "NPY_OBJECT", PyInt_FromLong(NPY_OBJECT)); + PyDict_SetItemString(d, "NPY_STRING", PyInt_FromLong(NPY_STRING)); + PyDict_SetItemString(d, "NPY_UNICODE", PyInt_FromLong(NPY_UNICODE)); + PyDict_SetItemString(d, "NPY_VOID", PyInt_FromLong(NPY_VOID)); + PyDict_SetItemString(d, "NPY_NTYPES", PyInt_FromLong(NPY_NTYPES)); + PyDict_SetItemString(d, "NPY_NOTYPE", PyInt_FromLong(NPY_NOTYPE)); + PyDict_SetItemString(d, "NPY_USERDEF", PyInt_FromLong(NPY_USERDEF)); + + PyDict_SetItemString(d, "CONTIGUOUS", PyInt_FromLong(NPY_ARRAY_C_CONTIGUOUS)); + PyDict_SetItemString(d, "FORTRAN", PyInt_FromLong(NPY_ARRAY_F_CONTIGUOUS)); + PyDict_SetItemString(d, "OWNDATA", PyInt_FromLong(NPY_ARRAY_OWNDATA)); + PyDict_SetItemString(d, "FORCECAST", PyInt_FromLong(NPY_ARRAY_FORCECAST)); + PyDict_SetItemString(d, "ENSURECOPY", PyInt_FromLong(NPY_ARRAY_ENSURECOPY)); + PyDict_SetItemString(d, "ENSUREARRAY", PyInt_FromLong(NPY_ARRAY_ENSUREARRAY)); + PyDict_SetItemString(d, "ALIGNED", PyInt_FromLong(NPY_ARRAY_ALIGNED)); + PyDict_SetItemString(d, "WRITEABLE", PyInt_FromLong(NPY_ARRAY_WRITEABLE)); + PyDict_SetItemString(d, "UPDATEIFCOPY", PyInt_FromLong(NPY_ARRAY_UPDATEIFCOPY)); + PyDict_SetItemString(d, "WRITEBACKIFCOPY", PyInt_FromLong(NPY_ARRAY_WRITEBACKIFCOPY)); + + PyDict_SetItemString(d, "BEHAVED", PyInt_FromLong(NPY_ARRAY_BEHAVED)); + PyDict_SetItemString(d, "BEHAVED_NS", PyInt_FromLong(NPY_ARRAY_BEHAVED_NS)); + PyDict_SetItemString(d, "CARRAY", PyInt_FromLong(NPY_ARRAY_CARRAY)); + PyDict_SetItemString(d, "FARRAY", PyInt_FromLong(NPY_ARRAY_FARRAY)); + PyDict_SetItemString(d, "CARRAY_RO", PyInt_FromLong(NPY_ARRAY_CARRAY_RO)); + PyDict_SetItemString(d, "FARRAY_RO", PyInt_FromLong(NPY_ARRAY_FARRAY_RO)); + PyDict_SetItemString(d, "DEFAULT", PyInt_FromLong(NPY_ARRAY_DEFAULT)); + PyDict_SetItemString(d, "UPDATE_ALL", PyInt_FromLong(NPY_ARRAY_UPDATE_ALL)); + + if (PyErr_Occurred()) + Py_FatalError("can't initialize module wrap"); + +#ifdef F2PY_REPORT_ATEXIT + on_exit(f2py_report_on_exit,(void*)"array_from_pyobj.wrap.call"); +#endif + + return RETVAL; +} +#ifdef __cplusplus +} +#endif diff --git a/numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap b/numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap new file mode 100644 index 0000000..2665f89 --- /dev/null +++ b/numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap @@ -0,0 +1 @@ +dict(real=dict(rk="double")) diff --git a/numpy/f2py/tests/src/assumed_shape/foo_free.f90 b/numpy/f2py/tests/src/assumed_shape/foo_free.f90 new file mode 100644 index 0000000..b301710 --- /dev/null +++ b/numpy/f2py/tests/src/assumed_shape/foo_free.f90 @@ -0,0 +1,34 @@ + +subroutine sum(x, res) + implicit none + real, intent(in) :: x(:) + real, intent(out) :: res + + integer :: i + + !print *, "sum: size(x) = ", size(x) + + res = 0.0 + + do i = 1, size(x) + res = res + x(i) + enddo + +end subroutine sum + +function fsum(x) result (res) + implicit none + real, intent(in) :: x(:) + real :: res + + integer :: i + + !print *, "fsum: size(x) = ", size(x) + + res = 0.0 + + do i = 1, size(x) + res = res + x(i) + enddo + +end function fsum diff --git a/numpy/f2py/tests/src/assumed_shape/foo_mod.f90 b/numpy/f2py/tests/src/assumed_shape/foo_mod.f90 new file mode 100644 index 0000000..cbe6317 --- /dev/null +++ b/numpy/f2py/tests/src/assumed_shape/foo_mod.f90 @@ -0,0 +1,41 @@ + +module mod + +contains + +subroutine sum(x, res) + implicit none + real, intent(in) :: x(:) + real, intent(out) :: res + + integer :: i + + !print *, "sum: size(x) = ", size(x) + + res = 0.0 + + do i = 1, size(x) + res = res + x(i) + enddo + +end subroutine sum + +function fsum(x) result (res) + implicit none + real, intent(in) :: x(:) + real :: res + + integer :: i + + !print *, "fsum: size(x) = ", size(x) + + res = 0.0 + + do i = 1, size(x) + res = res + x(i) + enddo + +end function fsum + + +end module mod diff --git a/numpy/f2py/tests/src/assumed_shape/foo_use.f90 b/numpy/f2py/tests/src/assumed_shape/foo_use.f90 new file mode 100644 index 0000000..337465a --- /dev/null +++ b/numpy/f2py/tests/src/assumed_shape/foo_use.f90 @@ -0,0 +1,19 @@ +subroutine sum_with_use(x, res) + use precision + + implicit none + + real(kind=rk), intent(in) :: x(:) + real(kind=rk), intent(out) :: res + + integer :: i + + !print *, "size(x) = ", size(x) + + res = 0.0 + + do i = 1, size(x) + res = res + x(i) + enddo + + end subroutine diff --git a/numpy/f2py/tests/src/assumed_shape/precision.f90 b/numpy/f2py/tests/src/assumed_shape/precision.f90 new file mode 100644 index 0000000..ed6c70c --- /dev/null +++ b/numpy/f2py/tests/src/assumed_shape/precision.f90 @@ -0,0 +1,4 @@ +module precision + integer, parameter :: rk = selected_real_kind(8) + integer, parameter :: ik = selected_real_kind(4) +end module diff --git a/numpy/f2py/tests/src/common/block.f b/numpy/f2py/tests/src/common/block.f new file mode 100644 index 0000000..7ea7968 --- /dev/null +++ b/numpy/f2py/tests/src/common/block.f @@ -0,0 +1,11 @@ + SUBROUTINE INITCB + DOUBLE PRECISION LONG + CHARACTER STRING + INTEGER OK + + COMMON /BLOCK/ LONG, STRING, OK + LONG = 1.0 + STRING = '2' + OK = 3 + RETURN + END diff --git a/numpy/f2py/tests/src/kind/foo.f90 b/numpy/f2py/tests/src/kind/foo.f90 new file mode 100644 index 0000000..d3d15cf --- /dev/null +++ b/numpy/f2py/tests/src/kind/foo.f90 @@ -0,0 +1,20 @@ + + +subroutine selectedrealkind(p, r, res) + implicit none + + integer, intent(in) :: p, r + !f2py integer :: r=0 + integer, intent(out) :: res + res = selected_real_kind(p, r) + +end subroutine + +subroutine selectedintkind(p, res) + implicit none + + integer, intent(in) :: p + integer, intent(out) :: res + res = selected_int_kind(p) + +end subroutine diff --git a/numpy/f2py/tests/src/mixed/foo.f b/numpy/f2py/tests/src/mixed/foo.f new file mode 100644 index 0000000..c347425 --- /dev/null +++ b/numpy/f2py/tests/src/mixed/foo.f @@ -0,0 +1,5 @@ + subroutine bar11(a) +cf2py intent(out) a + integer a + a = 11 + end diff --git a/numpy/f2py/tests/src/mixed/foo_fixed.f90 b/numpy/f2py/tests/src/mixed/foo_fixed.f90 new file mode 100644 index 0000000..7543a6a --- /dev/null +++ b/numpy/f2py/tests/src/mixed/foo_fixed.f90 @@ -0,0 +1,8 @@ + module foo_fixed + contains + subroutine bar12(a) +!f2py intent(out) a + integer a + a = 12 + end subroutine bar12 + end module foo_fixed diff --git a/numpy/f2py/tests/src/mixed/foo_free.f90 b/numpy/f2py/tests/src/mixed/foo_free.f90 new file mode 100644 index 0000000..c1b641f --- /dev/null +++ b/numpy/f2py/tests/src/mixed/foo_free.f90 @@ -0,0 +1,8 @@ +module foo_free +contains + subroutine bar13(a) + !f2py intent(out) a + integer a + a = 13 + end subroutine bar13 +end module foo_free diff --git a/numpy/f2py/tests/src/parameter/constant_both.f90 b/numpy/f2py/tests/src/parameter/constant_both.f90 new file mode 100644 index 0000000..ac90ced --- /dev/null +++ b/numpy/f2py/tests/src/parameter/constant_both.f90 @@ -0,0 +1,57 @@ +! Check that parameters are correct intercepted. +! Constants with comma separations are commonly +! used, for instance Pi = 3._dp +subroutine foo(x) + implicit none + integer, parameter :: sp = selected_real_kind(6) + integer, parameter :: dp = selected_real_kind(15) + integer, parameter :: ii = selected_int_kind(9) + integer, parameter :: il = selected_int_kind(18) + real(dp), intent(inout) :: x + dimension x(3) + real(sp), parameter :: three_s = 3._sp + real(dp), parameter :: three_d = 3._dp + integer(ii), parameter :: three_i = 3_ii + integer(il), parameter :: three_l = 3_il + x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l + x(2) = x(2) * three_s + x(3) = x(3) * three_l + return +end subroutine + + +subroutine foo_no(x) + implicit none + integer, parameter :: sp = selected_real_kind(6) + integer, parameter :: dp = selected_real_kind(15) + integer, parameter :: ii = selected_int_kind(9) + integer, parameter :: il = selected_int_kind(18) + real(dp), intent(inout) :: x + dimension x(3) + real(sp), parameter :: three_s = 3. + real(dp), parameter :: three_d = 3. + integer(ii), parameter :: three_i = 3 + integer(il), parameter :: three_l = 3 + x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l + x(2) = x(2) * three_s + x(3) = x(3) * three_l + return +end subroutine + +subroutine foo_sum(x) + implicit none + integer, parameter :: sp = selected_real_kind(6) + integer, parameter :: dp = selected_real_kind(15) + integer, parameter :: ii = selected_int_kind(9) + integer, parameter :: il = selected_int_kind(18) + real(dp), intent(inout) :: x + dimension x(3) + real(sp), parameter :: three_s = 2._sp + 1._sp + real(dp), parameter :: three_d = 1._dp + 2._dp + integer(ii), parameter :: three_i = 2_ii + 1_ii + integer(il), parameter :: three_l = 1_il + 2_il + x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l + x(2) = x(2) * three_s + x(3) = x(3) * three_l + return +end subroutine diff --git a/numpy/f2py/tests/src/parameter/constant_compound.f90 b/numpy/f2py/tests/src/parameter/constant_compound.f90 new file mode 100644 index 0000000..e51f5e9 --- /dev/null +++ b/numpy/f2py/tests/src/parameter/constant_compound.f90 @@ -0,0 +1,15 @@ +! Check that parameters are correct intercepted. +! Constants with comma separations are commonly +! used, for instance Pi = 3._dp +subroutine foo_compound_int(x) + implicit none + integer, parameter :: ii = selected_int_kind(9) + integer(ii), intent(inout) :: x + dimension x(3) + integer(ii), parameter :: three = 3_ii + integer(ii), parameter :: two = 2_ii + integer(ii), parameter :: six = three * 1_ii * two + + x(1) = x(1) + x(2) + x(3) * six + return +end subroutine diff --git a/numpy/f2py/tests/src/parameter/constant_integer.f90 b/numpy/f2py/tests/src/parameter/constant_integer.f90 new file mode 100644 index 0000000..aaa83d2 --- /dev/null +++ b/numpy/f2py/tests/src/parameter/constant_integer.f90 @@ -0,0 +1,22 @@ +! Check that parameters are correct intercepted. +! Constants with comma separations are commonly +! used, for instance Pi = 3._dp +subroutine foo_int(x) + implicit none + integer, parameter :: ii = selected_int_kind(9) + integer(ii), intent(inout) :: x + dimension x(3) + integer(ii), parameter :: three = 3_ii + x(1) = x(1) + x(2) + x(3) * three + return +end subroutine + +subroutine foo_long(x) + implicit none + integer, parameter :: ii = selected_int_kind(18) + integer(ii), intent(inout) :: x + dimension x(3) + integer(ii), parameter :: three = 3_ii + x(1) = x(1) + x(2) + x(3) * three + return +end subroutine diff --git a/numpy/f2py/tests/src/parameter/constant_non_compound.f90 b/numpy/f2py/tests/src/parameter/constant_non_compound.f90 new file mode 100644 index 0000000..62c9a5b --- /dev/null +++ b/numpy/f2py/tests/src/parameter/constant_non_compound.f90 @@ -0,0 +1,23 @@ +! Check that parameters are correct intercepted. +! Specifically that types of constants without +! compound kind specs are correctly inferred +! adapted Gibbs iteration code from pymc +! for this test case +subroutine foo_non_compound_int(x) + implicit none + integer, parameter :: ii = selected_int_kind(9) + + integer(ii) maxiterates + parameter (maxiterates=2) + + integer(ii) maxseries + parameter (maxseries=2) + + integer(ii) wasize + parameter (wasize=maxiterates*maxseries) + integer(ii), intent(inout) :: x + dimension x(wasize) + + x(1) = x(1) + x(2) + x(3) + x(4) * wasize + return +end subroutine diff --git a/numpy/f2py/tests/src/parameter/constant_real.f90 b/numpy/f2py/tests/src/parameter/constant_real.f90 new file mode 100644 index 0000000..02ac9dd --- /dev/null +++ b/numpy/f2py/tests/src/parameter/constant_real.f90 @@ -0,0 +1,23 @@ +! Check that parameters are correct intercepted. +! Constants with comma separations are commonly +! used, for instance Pi = 3._dp +subroutine foo_single(x) + implicit none + integer, parameter :: rp = selected_real_kind(6) + real(rp), intent(inout) :: x + dimension x(3) + real(rp), parameter :: three = 3._rp + x(1) = x(1) + x(2) + x(3) * three + return +end subroutine + +subroutine foo_double(x) + implicit none + integer, parameter :: rp = selected_real_kind(15) + real(rp), intent(inout) :: x + dimension x(3) + real(rp), parameter :: three = 3._rp + x(1) = x(1) + x(2) + x(3) * three + return +end subroutine + diff --git a/numpy/f2py/tests/src/regression/inout.f90 b/numpy/f2py/tests/src/regression/inout.f90 new file mode 100644 index 0000000..80cdad9 --- /dev/null +++ b/numpy/f2py/tests/src/regression/inout.f90 @@ -0,0 +1,9 @@ +! Check that intent(in out) translates as intent(inout). +! The separation seems to be a common usage. + subroutine foo(x) + implicit none + real(4), intent(in out) :: x + dimension x(3) + x(1) = x(1) + x(2) + x(3) + return + end diff --git a/numpy/f2py/tests/src/size/foo.f90 b/numpy/f2py/tests/src/size/foo.f90 new file mode 100644 index 0000000..5b66f8c --- /dev/null +++ b/numpy/f2py/tests/src/size/foo.f90 @@ -0,0 +1,44 @@ + +subroutine foo(a, n, m, b) + implicit none + + real, intent(in) :: a(n, m) + integer, intent(in) :: n, m + real, intent(out) :: b(size(a, 1)) + + integer :: i + + do i = 1, size(b) + b(i) = sum(a(i,:)) + enddo +end subroutine + +subroutine trans(x,y) + implicit none + real, intent(in), dimension(:,:) :: x + real, intent(out), dimension( size(x,2), size(x,1) ) :: y + integer :: N, M, i, j + N = size(x,1) + M = size(x,2) + DO i=1,N + do j=1,M + y(j,i) = x(i,j) + END DO + END DO +end subroutine trans + +subroutine flatten(x,y) + implicit none + real, intent(in), dimension(:,:) :: x + real, intent(out), dimension( size(x) ) :: y + integer :: N, M, i, j, k + N = size(x,1) + M = size(x,2) + k = 1 + DO i=1,N + do j=1,M + y(k) = x(i,j) + k = k + 1 + END DO + END DO +end subroutine flatten diff --git a/numpy/f2py/tests/src/string/char.f90 b/numpy/f2py/tests/src/string/char.f90 new file mode 100644 index 0000000..bb7985c --- /dev/null +++ b/numpy/f2py/tests/src/string/char.f90 @@ -0,0 +1,29 @@ +MODULE char_test + +CONTAINS + +SUBROUTINE change_strings(strings, n_strs, out_strings) + IMPLICIT NONE + + ! Inputs + INTEGER, INTENT(IN) :: n_strs + CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings + CHARACTER, INTENT(OUT), DIMENSION(2,n_strs) :: out_strings + +!f2py INTEGER, INTENT(IN) :: n_strs +!f2py CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings +!f2py CHARACTER, INTENT(OUT), DIMENSION(2,n_strs) :: strings + + ! Misc. + INTEGER*4 :: j + + + DO j=1, n_strs + out_strings(1,j) = strings(1,j) + out_strings(2,j) = 'A' + END DO + +END SUBROUTINE change_strings + +END MODULE char_test + diff --git a/numpy/f2py/tests/test_array_from_pyobj.py b/numpy/f2py/tests/test_array_from_pyobj.py new file mode 100644 index 0000000..776ec34 --- /dev/null +++ b/numpy/f2py/tests/test_array_from_pyobj.py @@ -0,0 +1,589 @@ +from __future__ import division, absolute_import, print_function + +import unittest +import os +import sys +import copy + +from numpy import ( + array, alltrue, ndarray, zeros, dtype, intp, clongdouble +) +from numpy.testing import ( + run_module_suite, assert_, assert_equal, SkipTest +) +from numpy.core.multiarray import typeinfo +from . import util + +wrap = None + + +def setup_module(): + """ + Build the required testing extension module + + """ + global wrap + + # Check compiler availability first + if not util.has_c_compiler(): + raise SkipTest("No C compiler available") + + if wrap is None: + config_code = """ + config.add_extension('test_array_from_pyobj_ext', + sources=['wrapmodule.c', 'fortranobject.c'], + define_macros=[]) + """ + d = os.path.dirname(__file__) + src = [os.path.join(d, 'src', 'array_from_pyobj', 'wrapmodule.c'), + os.path.join(d, '..', 'src', 'fortranobject.c'), + os.path.join(d, '..', 'src', 'fortranobject.h')] + wrap = util.build_module_distutils(src, config_code, + 'test_array_from_pyobj_ext') + + +def flags_info(arr): + flags = wrap.array_attrs(arr)[6] + return flags2names(flags) + + +def flags2names(flags): + info = [] + for flagname in ['CONTIGUOUS', 'FORTRAN', 'OWNDATA', 'ENSURECOPY', + 'ENSUREARRAY', 'ALIGNED', 'NOTSWAPPED', 'WRITEABLE', + 'WRITEBACKIFCOPY', 'UPDATEIFCOPY', 'BEHAVED', 'BEHAVED_RO', + 'CARRAY', 'FARRAY' + ]: + if abs(flags) & getattr(wrap, flagname, 0): + info.append(flagname) + return info + + +class Intent(object): + + def __init__(self, intent_list=[]): + self.intent_list = intent_list[:] + flags = 0 + for i in intent_list: + if i == 'optional': + flags |= wrap.F2PY_OPTIONAL + else: + flags |= getattr(wrap, 'F2PY_INTENT_' + i.upper()) + self.flags = flags + + def __getattr__(self, name): + name = name.lower() + if name == 'in_': + name = 'in' + return self.__class__(self.intent_list + [name]) + + def __str__(self): + return 'intent(%s)' % (','.join(self.intent_list)) + + def __repr__(self): + return 'Intent(%r)' % (self.intent_list) + + def is_intent(self, *names): + for name in names: + if name not in self.intent_list: + return False + return True + + def is_intent_exact(self, *names): + return len(self.intent_list) == len(names) and self.is_intent(*names) + +intent = Intent() + +_type_names = ['BOOL', 'BYTE', 'UBYTE', 'SHORT', 'USHORT', 'INT', 'UINT', + 'LONG', 'ULONG', 'LONGLONG', 'ULONGLONG', + 'FLOAT', 'DOUBLE', 'CFLOAT'] + +_cast_dict = {'BOOL': ['BOOL']} +_cast_dict['BYTE'] = _cast_dict['BOOL'] + ['BYTE'] +_cast_dict['UBYTE'] = _cast_dict['BOOL'] + ['UBYTE'] +_cast_dict['BYTE'] = ['BYTE'] +_cast_dict['UBYTE'] = ['UBYTE'] +_cast_dict['SHORT'] = _cast_dict['BYTE'] + ['UBYTE', 'SHORT'] +_cast_dict['USHORT'] = _cast_dict['UBYTE'] + ['BYTE', 'USHORT'] +_cast_dict['INT'] = _cast_dict['SHORT'] + ['USHORT', 'INT'] +_cast_dict['UINT'] = _cast_dict['USHORT'] + ['SHORT', 'UINT'] + +_cast_dict['LONG'] = _cast_dict['INT'] + ['LONG'] +_cast_dict['ULONG'] = _cast_dict['UINT'] + ['ULONG'] + +_cast_dict['LONGLONG'] = _cast_dict['LONG'] + ['LONGLONG'] +_cast_dict['ULONGLONG'] = _cast_dict['ULONG'] + ['ULONGLONG'] + +_cast_dict['FLOAT'] = _cast_dict['SHORT'] + ['USHORT', 'FLOAT'] +_cast_dict['DOUBLE'] = _cast_dict['INT'] + ['UINT', 'FLOAT', 'DOUBLE'] + +_cast_dict['CFLOAT'] = _cast_dict['FLOAT'] + ['CFLOAT'] + +# 32 bit system malloc typically does not provide the alignment required by +# 16 byte long double types this means the inout intent cannot be satisfied +# and several tests fail as the alignment flag can be randomly true or fals +# when numpy gains an aligned allocator the tests could be enabled again +if ((intp().dtype.itemsize != 4 or clongdouble().dtype.alignment <= 8) and + sys.platform != 'win32'): + _type_names.extend(['LONGDOUBLE', 'CDOUBLE', 'CLONGDOUBLE']) + _cast_dict['LONGDOUBLE'] = _cast_dict['LONG'] + \ + ['ULONG', 'FLOAT', 'DOUBLE', 'LONGDOUBLE'] + _cast_dict['CLONGDOUBLE'] = _cast_dict['LONGDOUBLE'] + \ + ['CFLOAT', 'CDOUBLE', 'CLONGDOUBLE'] + _cast_dict['CDOUBLE'] = _cast_dict['DOUBLE'] + ['CFLOAT', 'CDOUBLE'] + + +class Type(object): + _type_cache = {} + + def __new__(cls, name): + if isinstance(name, dtype): + dtype0 = name + name = None + for n, i in typeinfo.items(): + if isinstance(i, tuple) and dtype0.type is i[-1]: + name = n + break + obj = cls._type_cache.get(name.upper(), None) + if obj is not None: + return obj + obj = object.__new__(cls) + obj._init(name) + cls._type_cache[name.upper()] = obj + return obj + + def _init(self, name): + self.NAME = name.upper() + self.type_num = getattr(wrap, 'NPY_' + self.NAME) + assert_equal(self.type_num, typeinfo[self.NAME][1]) + self.dtype = typeinfo[self.NAME][-1] + self.elsize = typeinfo[self.NAME][2] / 8 + self.dtypechar = typeinfo[self.NAME][0] + + def cast_types(self): + return [self.__class__(_m) for _m in _cast_dict[self.NAME]] + + def all_types(self): + return [self.__class__(_m) for _m in _type_names] + + def smaller_types(self): + bits = typeinfo[self.NAME][3] + types = [] + for name in _type_names: + if typeinfo[name][3] < bits: + types.append(Type(name)) + return types + + def equal_types(self): + bits = typeinfo[self.NAME][3] + types = [] + for name in _type_names: + if name == self.NAME: + continue + if typeinfo[name][3] == bits: + types.append(Type(name)) + return types + + def larger_types(self): + bits = typeinfo[self.NAME][3] + types = [] + for name in _type_names: + if typeinfo[name][3] > bits: + types.append(Type(name)) + return types + + +class Array(object): + + def __init__(self, typ, dims, intent, obj): + self.type = typ + self.dims = dims + self.intent = intent + self.obj_copy = copy.deepcopy(obj) + self.obj = obj + + # arr.dtypechar may be different from typ.dtypechar + self.arr = wrap.call(typ.type_num, dims, intent.flags, obj) + + assert_(isinstance(self.arr, ndarray), repr(type(self.arr))) + + self.arr_attr = wrap.array_attrs(self.arr) + + if len(dims) > 1: + if self.intent.is_intent('c'): + assert_(intent.flags & wrap.F2PY_INTENT_C) + assert_(not self.arr.flags['FORTRAN'], + repr((self.arr.flags, getattr(obj, 'flags', None)))) + assert_(self.arr.flags['CONTIGUOUS']) + assert_(not self.arr_attr[6] & wrap.FORTRAN) + else: + assert_(not intent.flags & wrap.F2PY_INTENT_C) + assert_(self.arr.flags['FORTRAN']) + assert_(not self.arr.flags['CONTIGUOUS']) + assert_(self.arr_attr[6] & wrap.FORTRAN) + + if obj is None: + self.pyarr = None + self.pyarr_attr = None + return + + if intent.is_intent('cache'): + assert_(isinstance(obj, ndarray), repr(type(obj))) + self.pyarr = array(obj).reshape(*dims).copy() + else: + self.pyarr = array(array(obj, dtype=typ.dtypechar).reshape(*dims), + order=self.intent.is_intent('c') and 'C' or 'F') + assert_(self.pyarr.dtype == typ, + repr((self.pyarr.dtype, typ))) + assert_(self.pyarr.flags['OWNDATA'], (obj, intent)) + self.pyarr_attr = wrap.array_attrs(self.pyarr) + + if len(dims) > 1: + if self.intent.is_intent('c'): + assert_(not self.pyarr.flags['FORTRAN']) + assert_(self.pyarr.flags['CONTIGUOUS']) + assert_(not self.pyarr_attr[6] & wrap.FORTRAN) + else: + assert_(self.pyarr.flags['FORTRAN']) + assert_(not self.pyarr.flags['CONTIGUOUS']) + assert_(self.pyarr_attr[6] & wrap.FORTRAN) + + assert_(self.arr_attr[1] == self.pyarr_attr[1]) # nd + assert_(self.arr_attr[2] == self.pyarr_attr[2]) # dimensions + if self.arr_attr[1] <= 1: + assert_(self.arr_attr[3] == self.pyarr_attr[3], + repr((self.arr_attr[3], self.pyarr_attr[3], + self.arr.tobytes(), self.pyarr.tobytes()))) # strides + assert_(self.arr_attr[5][-2:] == self.pyarr_attr[5][-2:], + repr((self.arr_attr[5], self.pyarr_attr[5]))) # descr + assert_(self.arr_attr[6] == self.pyarr_attr[6], + repr((self.arr_attr[6], self.pyarr_attr[6], + flags2names(0 * self.arr_attr[6] - self.pyarr_attr[6]), + flags2names(self.arr_attr[6]), intent))) # flags + + if intent.is_intent('cache'): + assert_(self.arr_attr[5][3] >= self.type.elsize, + repr((self.arr_attr[5][3], self.type.elsize))) + else: + assert_(self.arr_attr[5][3] == self.type.elsize, + repr((self.arr_attr[5][3], self.type.elsize))) + assert_(self.arr_equal(self.pyarr, self.arr)) + + if isinstance(self.obj, ndarray): + if typ.elsize == Type(obj.dtype).elsize: + if not intent.is_intent('copy') and self.arr_attr[1] <= 1: + assert_(self.has_shared_memory()) + + def arr_equal(self, arr1, arr2): + if arr1.shape != arr2.shape: + return False + s = arr1 == arr2 + return alltrue(s.flatten()) + + def __str__(self): + return str(self.arr) + + def has_shared_memory(self): + """Check that created array shares data with input array. + """ + if self.obj is self.arr: + return True + if not isinstance(self.obj, ndarray): + return False + obj_attr = wrap.array_attrs(self.obj) + return obj_attr[0] == self.arr_attr[0] + + +class TestIntent(object): + + def test_in_out(self): + assert_equal(str(intent.in_.out), 'intent(in,out)') + assert_(intent.in_.c.is_intent('c')) + assert_(not intent.in_.c.is_intent_exact('c')) + assert_(intent.in_.c.is_intent_exact('c', 'in')) + assert_(intent.in_.c.is_intent_exact('in', 'c')) + assert_(not intent.in_.is_intent('c')) + + +class _test_shared_memory(object): + num2seq = [1, 2] + num23seq = [[1, 2, 3], [4, 5, 6]] + + def test_in_from_2seq(self): + a = self.array([2], intent.in_, self.num2seq) + assert_(not a.has_shared_memory()) + + def test_in_from_2casttype(self): + for t in self.type.cast_types(): + obj = array(self.num2seq, dtype=t.dtype) + a = self.array([len(self.num2seq)], intent.in_, obj) + if t.elsize == self.type.elsize: + assert_( + a.has_shared_memory(), repr((self.type.dtype, t.dtype))) + else: + assert_(not a.has_shared_memory(), repr(t.dtype)) + + def test_inout_2seq(self): + obj = array(self.num2seq, dtype=self.type.dtype) + a = self.array([len(self.num2seq)], intent.inout, obj) + assert_(a.has_shared_memory()) + + try: + a = self.array([2], intent.in_.inout, self.num2seq) + except TypeError as msg: + if not str(msg).startswith('failed to initialize intent' + '(inout|inplace|cache) array'): + raise + else: + raise SystemError('intent(inout) should have failed on sequence') + + def test_f_inout_23seq(self): + obj = array(self.num23seq, dtype=self.type.dtype, order='F') + shape = (len(self.num23seq), len(self.num23seq[0])) + a = self.array(shape, intent.in_.inout, obj) + assert_(a.has_shared_memory()) + + obj = array(self.num23seq, dtype=self.type.dtype, order='C') + shape = (len(self.num23seq), len(self.num23seq[0])) + try: + a = self.array(shape, intent.in_.inout, obj) + except ValueError as msg: + if not str(msg).startswith('failed to initialize intent' + '(inout) array'): + raise + else: + raise SystemError( + 'intent(inout) should have failed on improper array') + + def test_c_inout_23seq(self): + obj = array(self.num23seq, dtype=self.type.dtype) + shape = (len(self.num23seq), len(self.num23seq[0])) + a = self.array(shape, intent.in_.c.inout, obj) + assert_(a.has_shared_memory()) + + def test_in_copy_from_2casttype(self): + for t in self.type.cast_types(): + obj = array(self.num2seq, dtype=t.dtype) + a = self.array([len(self.num2seq)], intent.in_.copy, obj) + assert_(not a.has_shared_memory(), repr(t.dtype)) + + def test_c_in_from_23seq(self): + a = self.array([len(self.num23seq), len(self.num23seq[0])], + intent.in_, self.num23seq) + assert_(not a.has_shared_memory()) + + def test_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq, dtype=t.dtype) + a = self.array([len(self.num23seq), len(self.num23seq[0])], + intent.in_, obj) + assert_(not a.has_shared_memory(), repr(t.dtype)) + + def test_f_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq, dtype=t.dtype, order='F') + a = self.array([len(self.num23seq), len(self.num23seq[0])], + intent.in_, obj) + if t.elsize == self.type.elsize: + assert_(a.has_shared_memory(), repr(t.dtype)) + else: + assert_(not a.has_shared_memory(), repr(t.dtype)) + + def test_c_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq, dtype=t.dtype) + a = self.array([len(self.num23seq), len(self.num23seq[0])], + intent.in_.c, obj) + if t.elsize == self.type.elsize: + assert_(a.has_shared_memory(), repr(t.dtype)) + else: + assert_(not a.has_shared_memory(), repr(t.dtype)) + + def test_f_copy_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq, dtype=t.dtype, order='F') + a = self.array([len(self.num23seq), len(self.num23seq[0])], + intent.in_.copy, obj) + assert_(not a.has_shared_memory(), repr(t.dtype)) + + def test_c_copy_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq, dtype=t.dtype) + a = self.array([len(self.num23seq), len(self.num23seq[0])], + intent.in_.c.copy, obj) + assert_(not a.has_shared_memory(), repr(t.dtype)) + + def test_in_cache_from_2casttype(self): + for t in self.type.all_types(): + if t.elsize != self.type.elsize: + continue + obj = array(self.num2seq, dtype=t.dtype) + shape = (len(self.num2seq),) + a = self.array(shape, intent.in_.c.cache, obj) + assert_(a.has_shared_memory(), repr(t.dtype)) + + a = self.array(shape, intent.in_.cache, obj) + assert_(a.has_shared_memory(), repr(t.dtype)) + + obj = array(self.num2seq, dtype=t.dtype, order='F') + a = self.array(shape, intent.in_.c.cache, obj) + assert_(a.has_shared_memory(), repr(t.dtype)) + + a = self.array(shape, intent.in_.cache, obj) + assert_(a.has_shared_memory(), repr(t.dtype)) + + try: + a = self.array(shape, intent.in_.cache, obj[::-1]) + except ValueError as msg: + if not str(msg).startswith('failed to initialize' + ' intent(cache) array'): + raise + else: + raise SystemError( + 'intent(cache) should have failed on multisegmented array') + + def test_in_cache_from_2casttype_failure(self): + for t in self.type.all_types(): + if t.elsize >= self.type.elsize: + continue + obj = array(self.num2seq, dtype=t.dtype) + shape = (len(self.num2seq),) + try: + self.array(shape, intent.in_.cache, obj) # Should succeed + except ValueError as msg: + if not str(msg).startswith('failed to initialize' + ' intent(cache) array'): + raise + else: + raise SystemError( + 'intent(cache) should have failed on smaller array') + + def test_cache_hidden(self): + shape = (2,) + a = self.array(shape, intent.cache.hide, None) + assert_(a.arr.shape == shape) + + shape = (2, 3) + a = self.array(shape, intent.cache.hide, None) + assert_(a.arr.shape == shape) + + shape = (-1, 3) + try: + a = self.array(shape, intent.cache.hide, None) + except ValueError as msg: + if not str(msg).startswith('failed to create intent' + '(cache|hide)|optional array'): + raise + else: + raise SystemError( + 'intent(cache) should have failed on undefined dimensions') + + def test_hidden(self): + shape = (2,) + a = self.array(shape, intent.hide, None) + assert_(a.arr.shape == shape) + assert_(a.arr_equal(a.arr, zeros(shape, dtype=self.type.dtype))) + + shape = (2, 3) + a = self.array(shape, intent.hide, None) + assert_(a.arr.shape == shape) + assert_(a.arr_equal(a.arr, zeros(shape, dtype=self.type.dtype))) + assert_(a.arr.flags['FORTRAN'] and not a.arr.flags['CONTIGUOUS']) + + shape = (2, 3) + a = self.array(shape, intent.c.hide, None) + assert_(a.arr.shape == shape) + assert_(a.arr_equal(a.arr, zeros(shape, dtype=self.type.dtype))) + assert_(not a.arr.flags['FORTRAN'] and a.arr.flags['CONTIGUOUS']) + + shape = (-1, 3) + try: + a = self.array(shape, intent.hide, None) + except ValueError as msg: + if not str(msg).startswith('failed to create intent' + '(cache|hide)|optional array'): + raise + else: + raise SystemError('intent(hide) should have failed' + ' on undefined dimensions') + + def test_optional_none(self): + shape = (2,) + a = self.array(shape, intent.optional, None) + assert_(a.arr.shape == shape) + assert_(a.arr_equal(a.arr, zeros(shape, dtype=self.type.dtype))) + + shape = (2, 3) + a = self.array(shape, intent.optional, None) + assert_(a.arr.shape == shape) + assert_(a.arr_equal(a.arr, zeros(shape, dtype=self.type.dtype))) + assert_(a.arr.flags['FORTRAN'] and not a.arr.flags['CONTIGUOUS']) + + shape = (2, 3) + a = self.array(shape, intent.c.optional, None) + assert_(a.arr.shape == shape) + assert_(a.arr_equal(a.arr, zeros(shape, dtype=self.type.dtype))) + assert_(not a.arr.flags['FORTRAN'] and a.arr.flags['CONTIGUOUS']) + + def test_optional_from_2seq(self): + obj = self.num2seq + shape = (len(obj),) + a = self.array(shape, intent.optional, obj) + assert_(a.arr.shape == shape) + assert_(not a.has_shared_memory()) + + def test_optional_from_23seq(self): + obj = self.num23seq + shape = (len(obj), len(obj[0])) + a = self.array(shape, intent.optional, obj) + assert_(a.arr.shape == shape) + assert_(not a.has_shared_memory()) + + a = self.array(shape, intent.optional.c, obj) + assert_(a.arr.shape == shape) + assert_(not a.has_shared_memory()) + + def test_inplace(self): + obj = array(self.num23seq, dtype=self.type.dtype) + assert_(not obj.flags['FORTRAN'] and obj.flags['CONTIGUOUS']) + shape = obj.shape + a = self.array(shape, intent.inplace, obj) + assert_(obj[1][2] == a.arr[1][2], repr((obj, a.arr))) + a.arr[1][2] = 54 + assert_(obj[1][2] == a.arr[1][2] == + array(54, dtype=self.type.dtype), repr((obj, a.arr))) + assert_(a.arr is obj) + assert_(obj.flags['FORTRAN']) # obj attributes are changed inplace! + assert_(not obj.flags['CONTIGUOUS']) + + def test_inplace_from_casttype(self): + for t in self.type.cast_types(): + if t is self.type: + continue + obj = array(self.num23seq, dtype=t.dtype) + assert_(obj.dtype.type == t.dtype) + assert_(obj.dtype.type is not self.type.dtype) + assert_(not obj.flags['FORTRAN'] and obj.flags['CONTIGUOUS']) + shape = obj.shape + a = self.array(shape, intent.inplace, obj) + assert_(obj[1][2] == a.arr[1][2], repr((obj, a.arr))) + a.arr[1][2] = 54 + assert_(obj[1][2] == a.arr[1][2] == + array(54, dtype=self.type.dtype), repr((obj, a.arr))) + assert_(a.arr is obj) + assert_(obj.flags['FORTRAN']) # obj attributes changed inplace! + assert_(not obj.flags['CONTIGUOUS']) + assert_(obj.dtype.type is self.type.dtype) # obj changed inplace! + + +for t in _type_names: + exec('''\ +class TestGen_%s(_test_shared_memory): + def setup(self): + self.type = Type(%r) + array = lambda self,dims,intent,obj: Array(Type(%r),dims,intent,obj) +''' % (t, t, t)) + +if __name__ == "__main__": + setup_module() + run_module_suite() diff --git a/numpy/f2py/tests/test_assumed_shape.py b/numpy/f2py/tests/test_assumed_shape.py new file mode 100644 index 0000000..371aab7 --- /dev/null +++ b/numpy/f2py/tests/test_assumed_shape.py @@ -0,0 +1,35 @@ +from __future__ import division, absolute_import, print_function + +import os + +from numpy.testing import run_module_suite, assert_, dec +from . import util + + +def _path(*a): + return os.path.join(*((os.path.dirname(__file__),) + a)) + + +class TestAssumedShapeSumExample(util.F2PyTest): + sources = [_path('src', 'assumed_shape', 'foo_free.f90'), + _path('src', 'assumed_shape', 'foo_use.f90'), + _path('src', 'assumed_shape', 'precision.f90'), + _path('src', 'assumed_shape', 'foo_mod.f90'), + ] + + @dec.slow + def test_all(self): + r = self.module.fsum([1, 2]) + assert_(r == 3, repr(r)) + r = self.module.sum([1, 2]) + assert_(r == 3, repr(r)) + r = self.module.sum_with_use([1, 2]) + assert_(r == 3, repr(r)) + + r = self.module.mod.sum([1, 2]) + assert_(r == 3, repr(r)) + r = self.module.mod.fsum([1, 2]) + assert_(r == 3, repr(r)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_block_docstring.py b/numpy/f2py/tests/test_block_docstring.py new file mode 100644 index 0000000..eb11201 --- /dev/null +++ b/numpy/f2py/tests/test_block_docstring.py @@ -0,0 +1,25 @@ +from __future__ import division, absolute_import, print_function + +import textwrap +import sys +from . import util + +from numpy.testing import run_module_suite, assert_equal, dec + +class TestBlockDocString(util.F2PyTest): + code = """ + SUBROUTINE FOO() + INTEGER BAR(2, 3) + + COMMON /BLOCK/ BAR + RETURN + END + """ + + @dec.knownfailureif(sys.platform=='win32', msg='Fails with MinGW64 Gfortran (Issue #9673)') + def test_block_docstring(self): + expected = "'i'-array(2,3)\n" + assert_equal(self.module.block.__doc__, expected) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py new file mode 100644 index 0000000..1b9a582 --- /dev/null +++ b/numpy/f2py/tests/test_callback.py @@ -0,0 +1,168 @@ +from __future__ import division, absolute_import, print_function + +import math +import textwrap +import sys + +import numpy as np +from numpy.testing import run_module_suite, assert_, assert_equal, dec +from . import util + + +class TestF77Callback(util.F2PyTest): + code = """ + subroutine t(fun,a) + integer a +cf2py intent(out) a + external fun + call fun(a) + end + + subroutine func(a) +cf2py intent(in,out) a + integer a + a = a + 11 + end + + subroutine func0(a) +cf2py intent(out) a + integer a + a = 11 + end + + subroutine t2(a) +cf2py intent(callback) fun + integer a +cf2py intent(out) a + external fun + call fun(a) + end + + subroutine string_callback(callback, a) + external callback + double precision callback + double precision a + character*1 r +cf2py intent(out) a + r = 'r' + a = callback(r) + end + + subroutine string_callback_array(callback, cu, lencu, a) + external callback + integer callback + integer lencu + character*8 cu(lencu) + integer a +cf2py intent(out) a + + a = callback(cu, lencu) + end + """ + + @dec.slow + def test_all(self): + for name in "t,t2".split(","): + self.check_function(name) + + @dec.slow + def test_docstring(self): + expected = """ + a = t(fun,[fun_extra_args]) + + Wrapper for ``t``. + + Parameters + ---------- + fun : call-back function + + Other Parameters + ---------------- + fun_extra_args : input tuple, optional + Default: () + + Returns + ------- + a : int + + Notes + ----- + Call-back functions:: + + def fun(): return a + Return objects: + a : int + """ + assert_equal(self.module.t.__doc__, textwrap.dedent(expected).lstrip()) + + def check_function(self, name): + t = getattr(self.module, name) + r = t(lambda: 4) + assert_(r == 4, repr(r)) + r = t(lambda a: 5, fun_extra_args=(6,)) + assert_(r == 5, repr(r)) + r = t(lambda a: a, fun_extra_args=(6,)) + assert_(r == 6, repr(r)) + r = t(lambda a: 5 + a, fun_extra_args=(7,)) + assert_(r == 12, repr(r)) + r = t(lambda a: math.degrees(a), fun_extra_args=(math.pi,)) + assert_(r == 180, repr(r)) + r = t(math.degrees, fun_extra_args=(math.pi,)) + assert_(r == 180, repr(r)) + + r = t(self.module.func, fun_extra_args=(6,)) + assert_(r == 17, repr(r)) + r = t(self.module.func0) + assert_(r == 11, repr(r)) + r = t(self.module.func0._cpointer) + assert_(r == 11, repr(r)) + + class A(object): + + def __call__(self): + return 7 + + def mth(self): + return 9 + a = A() + r = t(a) + assert_(r == 7, repr(r)) + r = t(a.mth) + assert_(r == 9, repr(r)) + + @dec.knownfailureif(sys.platform=='win32', + msg='Fails with MinGW64 Gfortran (Issue #9673)') + def test_string_callback(self): + + def callback(code): + if code == 'r': + return 0 + else: + return 1 + + f = getattr(self.module, 'string_callback') + r = f(callback) + assert_(r == 0, repr(r)) + + @dec.knownfailureif(sys.platform=='win32', + msg='Fails with MinGW64 Gfortran (Issue #9673)') + def test_string_callback_array(self): + # See gh-10027 + cu = np.zeros((1, 8), 'S1') + + def callback(cu, lencu): + if cu.shape != (lencu, 8): + return 1 + if cu.dtype != 'S1': + return 2 + if not np.all(cu == b''): + return 3 + return 0 + + f = getattr(self.module, 'string_callback_array') + res = f(callback, cu, len(cu)) + assert_(res == 0, repr(res)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_common.py b/numpy/f2py/tests/test_common.py new file mode 100644 index 0000000..81082e5 --- /dev/null +++ b/numpy/f2py/tests/test_common.py @@ -0,0 +1,27 @@ +from __future__ import division, absolute_import, print_function + +import os +import sys +import numpy as np +from . import util + +from numpy.testing import run_module_suite, assert_array_equal, dec + +def _path(*a): + return os.path.join(*((os.path.dirname(__file__),) + a)) + +class TestCommonBlock(util.F2PyTest): + sources = [_path('src', 'common', 'block.f')] + + @dec.knownfailureif(sys.platform=='win32', msg='Fails with MinGW64 Gfortran (Issue #9673)') + def test_common_block(self): + self.module.initcb() + assert_array_equal(self.module.block.long_bn, + np.array(1.0, dtype=np.float64)) + assert_array_equal(self.module.block.string_bn, + np.array('2', dtype='|S1')) + assert_array_equal(self.module.block.ok, + np.array(3, dtype=np.int32)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_kind.py b/numpy/f2py/tests/test_kind.py new file mode 100644 index 0000000..7cfe2e9 --- /dev/null +++ b/numpy/f2py/tests/test_kind.py @@ -0,0 +1,36 @@ +from __future__ import division, absolute_import, print_function + +import os + +from numpy.testing import run_module_suite, assert_, dec +from numpy.f2py.crackfortran import ( + _selected_int_kind_func as selected_int_kind, + _selected_real_kind_func as selected_real_kind +) +from . import util + + +def _path(*a): + return os.path.join(*((os.path.dirname(__file__),) + a)) + + +class TestKind(util.F2PyTest): + sources = [_path('src', 'kind', 'foo.f90')] + + @dec.slow + def test_all(self): + selectedrealkind = self.module.selectedrealkind + selectedintkind = self.module.selectedintkind + + for i in range(40): + assert_(selectedintkind(i) in [selected_int_kind(i), -1], + 'selectedintkind(%s): expected %r but got %r' % + (i, selected_int_kind(i), selectedintkind(i))) + + for i in range(20): + assert_(selectedrealkind(i) in [selected_real_kind(i), -1], + 'selectedrealkind(%s): expected %r but got %r' % + (i, selected_real_kind(i), selectedrealkind(i))) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_mixed.py b/numpy/f2py/tests/test_mixed.py new file mode 100644 index 0000000..c145a4b --- /dev/null +++ b/numpy/f2py/tests/test_mixed.py @@ -0,0 +1,40 @@ +from __future__ import division, absolute_import, print_function + +import os +import textwrap + +from numpy.testing import run_module_suite, assert_, assert_equal, dec +from . import util + + +def _path(*a): + return os.path.join(*((os.path.dirname(__file__),) + a)) + + +class TestMixed(util.F2PyTest): + sources = [_path('src', 'mixed', 'foo.f'), + _path('src', 'mixed', 'foo_fixed.f90'), + _path('src', 'mixed', 'foo_free.f90')] + + @dec.slow + def test_all(self): + assert_(self.module.bar11() == 11) + assert_(self.module.foo_fixed.bar12() == 12) + assert_(self.module.foo_free.bar13() == 13) + + @dec.slow + def test_docstring(self): + expected = """ + a = bar11() + + Wrapper for ``bar11``. + + Returns + ------- + a : int + """ + assert_equal(self.module.bar11.__doc__, + textwrap.dedent(expected).lstrip()) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_parameter.py b/numpy/f2py/tests/test_parameter.py new file mode 100644 index 0000000..285b693 --- /dev/null +++ b/numpy/f2py/tests/test_parameter.py @@ -0,0 +1,122 @@ +from __future__ import division, absolute_import, print_function + +import os +import math + +import numpy as np +from numpy.testing import run_module_suite, dec, assert_raises, assert_equal + +from . import util + + +def _path(*a): + return os.path.join(*((os.path.dirname(__file__),) + a)) + + +class TestParameters(util.F2PyTest): + # Check that intent(in out) translates as intent(inout) + sources = [_path('src', 'parameter', 'constant_real.f90'), + _path('src', 'parameter', 'constant_integer.f90'), + _path('src', 'parameter', 'constant_both.f90'), + _path('src', 'parameter', 'constant_compound.f90'), + _path('src', 'parameter', 'constant_non_compound.f90'), + ] + + @dec.slow + def test_constant_real_single(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.float32)[::2] + assert_raises(ValueError, self.module.foo_single, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.float32) + self.module.foo_single(x) + assert_equal(x, [0 + 1 + 2*3, 1, 2]) + + @dec.slow + def test_constant_real_double(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.float64)[::2] + assert_raises(ValueError, self.module.foo_double, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.float64) + self.module.foo_double(x) + assert_equal(x, [0 + 1 + 2*3, 1, 2]) + + @dec.slow + def test_constant_compound_int(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.int32)[::2] + assert_raises(ValueError, self.module.foo_compound_int, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.int32) + self.module.foo_compound_int(x) + assert_equal(x, [0 + 1 + 2*6, 1, 2]) + + @dec.slow + def test_constant_non_compound_int(self): + # check values + x = np.arange(4, dtype=np.int32) + self.module.foo_non_compound_int(x) + assert_equal(x, [0 + 1 + 2 + 3*4, 1, 2, 3]) + + @dec.slow + def test_constant_integer_int(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.int32)[::2] + assert_raises(ValueError, self.module.foo_int, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.int32) + self.module.foo_int(x) + assert_equal(x, [0 + 1 + 2*3, 1, 2]) + + @dec.slow + def test_constant_integer_long(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.int64)[::2] + assert_raises(ValueError, self.module.foo_long, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.int64) + self.module.foo_long(x) + assert_equal(x, [0 + 1 + 2*3, 1, 2]) + + @dec.slow + def test_constant_both(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.float64)[::2] + assert_raises(ValueError, self.module.foo, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.float64) + self.module.foo(x) + assert_equal(x, [0 + 1*3*3 + 2*3*3, 1*3, 2*3]) + + @dec.slow + def test_constant_no(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.float64)[::2] + assert_raises(ValueError, self.module.foo_no, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.float64) + self.module.foo_no(x) + assert_equal(x, [0 + 1*3*3 + 2*3*3, 1*3, 2*3]) + + @dec.slow + def test_constant_sum(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.float64)[::2] + assert_raises(ValueError, self.module.foo_sum, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.float64) + self.module.foo_sum(x) + assert_equal(x, [0 + 1*3*3 + 2*3*3, 1*3, 2*3]) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_regression.py b/numpy/f2py/tests/test_regression.py new file mode 100644 index 0000000..c34a578 --- /dev/null +++ b/numpy/f2py/tests/test_regression.py @@ -0,0 +1,33 @@ +from __future__ import division, absolute_import, print_function + +import os +import math + +import numpy as np +from numpy.testing import run_module_suite, dec, assert_raises, assert_equal + +from . import util + + +def _path(*a): + return os.path.join(*((os.path.dirname(__file__),) + a)) + + +class TestIntentInOut(util.F2PyTest): + # Check that intent(in out) translates as intent(inout) + sources = [_path('src', 'regression', 'inout.f90')] + + @dec.slow + def test_inout(self): + # non-contiguous should raise error + x = np.arange(6, dtype=np.float32)[::2] + assert_raises(ValueError, self.module.foo, x) + + # check values with contiguous array + x = np.arange(3, dtype=np.float32) + self.module.foo(x) + assert_equal(x, [3, 1, 2]) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_return_character.py b/numpy/f2py/tests/test_return_character.py new file mode 100644 index 0000000..217b2c9 --- /dev/null +++ b/numpy/f2py/tests/test_return_character.py @@ -0,0 +1,147 @@ +from __future__ import division, absolute_import, print_function + +from numpy import array +from numpy.testing import run_module_suite, assert_, dec +from . import util + + +class TestReturnCharacter(util.F2PyTest): + + def check_function(self, t): + tname = t.__doc__.split()[0] + if tname in ['t0', 't1', 's0', 's1']: + assert_(t(23) == b'2') + r = t('ab') + assert_(r == b'a', repr(r)) + r = t(array('ab')) + assert_(r == b'a', repr(r)) + r = t(array(77, 'u1')) + assert_(r == b'M', repr(r)) + #assert_(_raises(ValueError, t, array([77,87]))) + #assert_(_raises(ValueError, t, array(77))) + elif tname in ['ts', 'ss']: + assert_(t(23) == b'23 ', repr(t(23))) + assert_(t('123456789abcdef') == b'123456789a') + elif tname in ['t5', 's5']: + assert_(t(23) == b'23 ', repr(t(23))) + assert_(t('ab') == b'ab ', repr(t('ab'))) + assert_(t('123456789abcdef') == b'12345') + else: + raise NotImplementedError + + +class TestF77ReturnCharacter(TestReturnCharacter): + code = """ + function t0(value) + character value + character t0 + t0 = value + end + function t1(value) + character*1 value + character*1 t1 + t1 = value + end + function t5(value) + character*5 value + character*5 t5 + t5 = value + end + function ts(value) + character*(*) value + character*(*) ts + ts = value + end + + subroutine s0(t0,value) + character value + character t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s1(t1,value) + character*1 value + character*1 t1 +cf2py intent(out) t1 + t1 = value + end + subroutine s5(t5,value) + character*5 value + character*5 t5 +cf2py intent(out) t5 + t5 = value + end + subroutine ss(ts,value) + character*(*) value + character*10 ts +cf2py intent(out) ts + ts = value + end + """ + + @dec.slow + def test_all(self): + for name in "t0,t1,t5,s0,s1,s5,ss".split(","): + self.check_function(getattr(self.module, name)) + + +class TestF90ReturnCharacter(TestReturnCharacter): + suffix = ".f90" + code = """ +module f90_return_char + contains + function t0(value) + character :: value + character :: t0 + t0 = value + end function t0 + function t1(value) + character(len=1) :: value + character(len=1) :: t1 + t1 = value + end function t1 + function t5(value) + character(len=5) :: value + character(len=5) :: t5 + t5 = value + end function t5 + function ts(value) + character(len=*) :: value + character(len=10) :: ts + ts = value + end function ts + + subroutine s0(t0,value) + character :: value + character :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s1(t1,value) + character(len=1) :: value + character(len=1) :: t1 +!f2py intent(out) t1 + t1 = value + end subroutine s1 + subroutine s5(t5,value) + character(len=5) :: value + character(len=5) :: t5 +!f2py intent(out) t5 + t5 = value + end subroutine s5 + subroutine ss(ts,value) + character(len=*) :: value + character(len=10) :: ts +!f2py intent(out) ts + ts = value + end subroutine ss +end module f90_return_char + """ + + @dec.slow + def test_all(self): + for name in "t0,t1,t5,ts,s0,s1,s5,ss".split(","): + self.check_function(getattr(self.module.f90_return_char, name)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_return_complex.py b/numpy/f2py/tests/test_return_complex.py new file mode 100644 index 0000000..73ced8e --- /dev/null +++ b/numpy/f2py/tests/test_return_complex.py @@ -0,0 +1,170 @@ +from __future__ import division, absolute_import, print_function + +from numpy import array +from numpy.compat import long +from numpy.testing import run_module_suite, assert_, assert_raises, dec +from . import util + + +class TestReturnComplex(util.F2PyTest): + + def check_function(self, t): + tname = t.__doc__.split()[0] + if tname in ['t0', 't8', 's0', 's8']: + err = 1e-5 + else: + err = 0.0 + assert_(abs(t(234j) - 234.0j) <= err) + assert_(abs(t(234.6) - 234.6) <= err) + assert_(abs(t(long(234)) - 234.0) <= err) + assert_(abs(t(234.6 + 3j) - (234.6 + 3j)) <= err) + #assert_( abs(t('234')-234.)<=err) + #assert_( abs(t('234.6')-234.6)<=err) + assert_(abs(t(-234) + 234.) <= err) + assert_(abs(t([234]) - 234.) <= err) + assert_(abs(t((234,)) - 234.) <= err) + assert_(abs(t(array(234)) - 234.) <= err) + assert_(abs(t(array(23 + 4j, 'F')) - (23 + 4j)) <= err) + assert_(abs(t(array([234])) - 234.) <= err) + assert_(abs(t(array([[234]])) - 234.) <= err) + assert_(abs(t(array([234], 'b')) + 22.) <= err) + assert_(abs(t(array([234], 'h')) - 234.) <= err) + assert_(abs(t(array([234], 'i')) - 234.) <= err) + assert_(abs(t(array([234], 'l')) - 234.) <= err) + assert_(abs(t(array([234], 'q')) - 234.) <= err) + assert_(abs(t(array([234], 'f')) - 234.) <= err) + assert_(abs(t(array([234], 'd')) - 234.) <= err) + assert_(abs(t(array([234 + 3j], 'F')) - (234 + 3j)) <= err) + assert_(abs(t(array([234], 'D')) - 234.) <= err) + + #assert_raises(TypeError, t, array([234], 'a1')) + assert_raises(TypeError, t, 'abc') + + assert_raises(IndexError, t, []) + assert_raises(IndexError, t, ()) + + assert_raises(TypeError, t, t) + assert_raises(TypeError, t, {}) + + try: + r = t(10 ** 400) + assert_(repr(r) in ['(inf+0j)', '(Infinity+0j)'], repr(r)) + except OverflowError: + pass + + +class TestF77ReturnComplex(TestReturnComplex): + code = """ + function t0(value) + complex value + complex t0 + t0 = value + end + function t8(value) + complex*8 value + complex*8 t8 + t8 = value + end + function t16(value) + complex*16 value + complex*16 t16 + t16 = value + end + function td(value) + double complex value + double complex td + td = value + end + + subroutine s0(t0,value) + complex value + complex t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s8(t8,value) + complex*8 value + complex*8 t8 +cf2py intent(out) t8 + t8 = value + end + subroutine s16(t16,value) + complex*16 value + complex*16 t16 +cf2py intent(out) t16 + t16 = value + end + subroutine sd(td,value) + double complex value + double complex td +cf2py intent(out) td + td = value + end + """ + + @dec.slow + def test_all(self): + for name in "t0,t8,t16,td,s0,s8,s16,sd".split(","): + self.check_function(getattr(self.module, name)) + + +class TestF90ReturnComplex(TestReturnComplex): + suffix = ".f90" + code = """ +module f90_return_complex + contains + function t0(value) + complex :: value + complex :: t0 + t0 = value + end function t0 + function t8(value) + complex(kind=4) :: value + complex(kind=4) :: t8 + t8 = value + end function t8 + function t16(value) + complex(kind=8) :: value + complex(kind=8) :: t16 + t16 = value + end function t16 + function td(value) + double complex :: value + double complex :: td + td = value + end function td + + subroutine s0(t0,value) + complex :: value + complex :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s8(t8,value) + complex(kind=4) :: value + complex(kind=4) :: t8 +!f2py intent(out) t8 + t8 = value + end subroutine s8 + subroutine s16(t16,value) + complex(kind=8) :: value + complex(kind=8) :: t16 +!f2py intent(out) t16 + t16 = value + end subroutine s16 + subroutine sd(td,value) + double complex :: value + double complex :: td +!f2py intent(out) td + td = value + end subroutine sd +end module f90_return_complex + """ + + @dec.slow + def test_all(self): + for name in "t0,t8,t16,td,s0,s8,s16,sd".split(","): + self.check_function(getattr(self.module.f90_return_complex, name)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_return_integer.py b/numpy/f2py/tests/test_return_integer.py new file mode 100644 index 0000000..df8fc7c --- /dev/null +++ b/numpy/f2py/tests/test_return_integer.py @@ -0,0 +1,180 @@ +from __future__ import division, absolute_import, print_function + +from numpy import array +from numpy.compat import long +from numpy.testing import run_module_suite, assert_, assert_raises, dec +from . import util + + +class TestReturnInteger(util.F2PyTest): + + def check_function(self, t): + assert_(t(123) == 123, repr(t(123))) + assert_(t(123.6) == 123) + assert_(t(long(123)) == 123) + assert_(t('123') == 123) + assert_(t(-123) == -123) + assert_(t([123]) == 123) + assert_(t((123,)) == 123) + assert_(t(array(123)) == 123) + assert_(t(array([123])) == 123) + assert_(t(array([[123]])) == 123) + assert_(t(array([123], 'b')) == 123) + assert_(t(array([123], 'h')) == 123) + assert_(t(array([123], 'i')) == 123) + assert_(t(array([123], 'l')) == 123) + assert_(t(array([123], 'B')) == 123) + assert_(t(array([123], 'f')) == 123) + assert_(t(array([123], 'd')) == 123) + + #assert_raises(ValueError, t, array([123],'S3')) + assert_raises(ValueError, t, 'abc') + + assert_raises(IndexError, t, []) + assert_raises(IndexError, t, ()) + + assert_raises(Exception, t, t) + assert_raises(Exception, t, {}) + + if t.__doc__.split()[0] in ['t8', 's8']: + assert_raises(OverflowError, t, 100000000000000000000000) + assert_raises(OverflowError, t, 10000000011111111111111.23) + + +class TestF77ReturnInteger(TestReturnInteger): + code = """ + function t0(value) + integer value + integer t0 + t0 = value + end + function t1(value) + integer*1 value + integer*1 t1 + t1 = value + end + function t2(value) + integer*2 value + integer*2 t2 + t2 = value + end + function t4(value) + integer*4 value + integer*4 t4 + t4 = value + end + function t8(value) + integer*8 value + integer*8 t8 + t8 = value + end + + subroutine s0(t0,value) + integer value + integer t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s1(t1,value) + integer*1 value + integer*1 t1 +cf2py intent(out) t1 + t1 = value + end + subroutine s2(t2,value) + integer*2 value + integer*2 t2 +cf2py intent(out) t2 + t2 = value + end + subroutine s4(t4,value) + integer*4 value + integer*4 t4 +cf2py intent(out) t4 + t4 = value + end + subroutine s8(t8,value) + integer*8 value + integer*8 t8 +cf2py intent(out) t8 + t8 = value + end + """ + + @dec.slow + def test_all(self): + for name in "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","): + self.check_function(getattr(self.module, name)) + + +class TestF90ReturnInteger(TestReturnInteger): + suffix = ".f90" + code = """ +module f90_return_integer + contains + function t0(value) + integer :: value + integer :: t0 + t0 = value + end function t0 + function t1(value) + integer(kind=1) :: value + integer(kind=1) :: t1 + t1 = value + end function t1 + function t2(value) + integer(kind=2) :: value + integer(kind=2) :: t2 + t2 = value + end function t2 + function t4(value) + integer(kind=4) :: value + integer(kind=4) :: t4 + t4 = value + end function t4 + function t8(value) + integer(kind=8) :: value + integer(kind=8) :: t8 + t8 = value + end function t8 + + subroutine s0(t0,value) + integer :: value + integer :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s1(t1,value) + integer(kind=1) :: value + integer(kind=1) :: t1 +!f2py intent(out) t1 + t1 = value + end subroutine s1 + subroutine s2(t2,value) + integer(kind=2) :: value + integer(kind=2) :: t2 +!f2py intent(out) t2 + t2 = value + end subroutine s2 + subroutine s4(t4,value) + integer(kind=4) :: value + integer(kind=4) :: t4 +!f2py intent(out) t4 + t4 = value + end subroutine s4 + subroutine s8(t8,value) + integer(kind=8) :: value + integer(kind=8) :: t8 +!f2py intent(out) t8 + t8 = value + end subroutine s8 +end module f90_return_integer + """ + + @dec.slow + def test_all(self): + for name in "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","): + self.check_function(getattr(self.module.f90_return_integer, name)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_return_logical.py b/numpy/f2py/tests/test_return_logical.py new file mode 100644 index 0000000..221dc3c --- /dev/null +++ b/numpy/f2py/tests/test_return_logical.py @@ -0,0 +1,189 @@ +from __future__ import division, absolute_import, print_function + +from numpy import array +from numpy.compat import long +from numpy.testing import run_module_suite, assert_, assert_raises, dec +from . import util + + +class TestReturnLogical(util.F2PyTest): + + def check_function(self, t): + assert_(t(True) == 1, repr(t(True))) + assert_(t(False) == 0, repr(t(False))) + assert_(t(0) == 0) + assert_(t(None) == 0) + assert_(t(0.0) == 0) + assert_(t(0j) == 0) + assert_(t(1j) == 1) + assert_(t(234) == 1) + assert_(t(234.6) == 1) + assert_(t(long(234)) == 1) + assert_(t(234.6 + 3j) == 1) + assert_(t('234') == 1) + assert_(t('aaa') == 1) + assert_(t('') == 0) + assert_(t([]) == 0) + assert_(t(()) == 0) + assert_(t({}) == 0) + assert_(t(t) == 1) + assert_(t(-234) == 1) + assert_(t(10 ** 100) == 1) + assert_(t([234]) == 1) + assert_(t((234,)) == 1) + assert_(t(array(234)) == 1) + assert_(t(array([234])) == 1) + assert_(t(array([[234]])) == 1) + assert_(t(array([234], 'b')) == 1) + assert_(t(array([234], 'h')) == 1) + assert_(t(array([234], 'i')) == 1) + assert_(t(array([234], 'l')) == 1) + assert_(t(array([234], 'f')) == 1) + assert_(t(array([234], 'd')) == 1) + assert_(t(array([234 + 3j], 'F')) == 1) + assert_(t(array([234], 'D')) == 1) + assert_(t(array(0)) == 0) + assert_(t(array([0])) == 0) + assert_(t(array([[0]])) == 0) + assert_(t(array([0j])) == 0) + assert_(t(array([1])) == 1) + assert_raises(ValueError, t, array([0, 0])) + + +class TestF77ReturnLogical(TestReturnLogical): + code = """ + function t0(value) + logical value + logical t0 + t0 = value + end + function t1(value) + logical*1 value + logical*1 t1 + t1 = value + end + function t2(value) + logical*2 value + logical*2 t2 + t2 = value + end + function t4(value) + logical*4 value + logical*4 t4 + t4 = value + end +c function t8(value) +c logical*8 value +c logical*8 t8 +c t8 = value +c end + + subroutine s0(t0,value) + logical value + logical t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s1(t1,value) + logical*1 value + logical*1 t1 +cf2py intent(out) t1 + t1 = value + end + subroutine s2(t2,value) + logical*2 value + logical*2 t2 +cf2py intent(out) t2 + t2 = value + end + subroutine s4(t4,value) + logical*4 value + logical*4 t4 +cf2py intent(out) t4 + t4 = value + end +c subroutine s8(t8,value) +c logical*8 value +c logical*8 t8 +cf2py intent(out) t8 +c t8 = value +c end + """ + + @dec.slow + def test_all(self): + for name in "t0,t1,t2,t4,s0,s1,s2,s4".split(","): + self.check_function(getattr(self.module, name)) + + +class TestF90ReturnLogical(TestReturnLogical): + suffix = ".f90" + code = """ +module f90_return_logical + contains + function t0(value) + logical :: value + logical :: t0 + t0 = value + end function t0 + function t1(value) + logical(kind=1) :: value + logical(kind=1) :: t1 + t1 = value + end function t1 + function t2(value) + logical(kind=2) :: value + logical(kind=2) :: t2 + t2 = value + end function t2 + function t4(value) + logical(kind=4) :: value + logical(kind=4) :: t4 + t4 = value + end function t4 + function t8(value) + logical(kind=8) :: value + logical(kind=8) :: t8 + t8 = value + end function t8 + + subroutine s0(t0,value) + logical :: value + logical :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s1(t1,value) + logical(kind=1) :: value + logical(kind=1) :: t1 +!f2py intent(out) t1 + t1 = value + end subroutine s1 + subroutine s2(t2,value) + logical(kind=2) :: value + logical(kind=2) :: t2 +!f2py intent(out) t2 + t2 = value + end subroutine s2 + subroutine s4(t4,value) + logical(kind=4) :: value + logical(kind=4) :: t4 +!f2py intent(out) t4 + t4 = value + end subroutine s4 + subroutine s8(t8,value) + logical(kind=8) :: value + logical(kind=8) :: t8 +!f2py intent(out) t8 + t8 = value + end subroutine s8 +end module f90_return_logical + """ + + @dec.slow + def test_all(self): + for name in "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","): + self.check_function(getattr(self.module.f90_return_logical, name)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_return_real.py b/numpy/f2py/tests/test_return_real.py new file mode 100644 index 0000000..a815490 --- /dev/null +++ b/numpy/f2py/tests/test_return_real.py @@ -0,0 +1,206 @@ +from __future__ import division, absolute_import, print_function + +from numpy import array +from numpy.compat import long +from numpy.testing import run_module_suite, assert_, assert_raises, dec +from . import util + + +class TestReturnReal(util.F2PyTest): + + def check_function(self, t): + if t.__doc__.split()[0] in ['t0', 't4', 's0', 's4']: + err = 1e-5 + else: + err = 0.0 + assert_(abs(t(234) - 234.0) <= err) + assert_(abs(t(234.6) - 234.6) <= err) + assert_(abs(t(long(234)) - 234.0) <= err) + assert_(abs(t('234') - 234) <= err) + assert_(abs(t('234.6') - 234.6) <= err) + assert_(abs(t(-234) + 234) <= err) + assert_(abs(t([234]) - 234) <= err) + assert_(abs(t((234,)) - 234.) <= err) + assert_(abs(t(array(234)) - 234.) <= err) + assert_(abs(t(array([234])) - 234.) <= err) + assert_(abs(t(array([[234]])) - 234.) <= err) + assert_(abs(t(array([234], 'b')) + 22) <= err) + assert_(abs(t(array([234], 'h')) - 234.) <= err) + assert_(abs(t(array([234], 'i')) - 234.) <= err) + assert_(abs(t(array([234], 'l')) - 234.) <= err) + assert_(abs(t(array([234], 'B')) - 234.) <= err) + assert_(abs(t(array([234], 'f')) - 234.) <= err) + assert_(abs(t(array([234], 'd')) - 234.) <= err) + if t.__doc__.split()[0] in ['t0', 't4', 's0', 's4']: + assert_(t(1e200) == t(1e300)) # inf + + #assert_raises(ValueError, t, array([234], 'S1')) + assert_raises(ValueError, t, 'abc') + + assert_raises(IndexError, t, []) + assert_raises(IndexError, t, ()) + + assert_raises(Exception, t, t) + assert_raises(Exception, t, {}) + + try: + r = t(10 ** 400) + assert_(repr(r) in ['inf', 'Infinity'], repr(r)) + except OverflowError: + pass + + +class TestCReturnReal(TestReturnReal): + suffix = ".pyf" + module_name = "c_ext_return_real" + code = """ +python module c_ext_return_real +usercode \'\'\' +float t4(float value) { return value; } +void s4(float *t4, float value) { *t4 = value; } +double t8(double value) { return value; } +void s8(double *t8, double value) { *t8 = value; } +\'\'\' +interface + function t4(value) + real*4 intent(c) :: t4,value + end + function t8(value) + real*8 intent(c) :: t8,value + end + subroutine s4(t4,value) + intent(c) s4 + real*4 intent(out) :: t4 + real*4 intent(c) :: value + end + subroutine s8(t8,value) + intent(c) s8 + real*8 intent(out) :: t8 + real*8 intent(c) :: value + end +end interface +end python module c_ext_return_real + """ + + @dec.slow + def test_all(self): + for name in "t4,t8,s4,s8".split(","): + self.check_function(getattr(self.module, name)) + + +class TestF77ReturnReal(TestReturnReal): + code = """ + function t0(value) + real value + real t0 + t0 = value + end + function t4(value) + real*4 value + real*4 t4 + t4 = value + end + function t8(value) + real*8 value + real*8 t8 + t8 = value + end + function td(value) + double precision value + double precision td + td = value + end + + subroutine s0(t0,value) + real value + real t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s4(t4,value) + real*4 value + real*4 t4 +cf2py intent(out) t4 + t4 = value + end + subroutine s8(t8,value) + real*8 value + real*8 t8 +cf2py intent(out) t8 + t8 = value + end + subroutine sd(td,value) + double precision value + double precision td +cf2py intent(out) td + td = value + end + """ + + @dec.slow + def test_all(self): + for name in "t0,t4,t8,td,s0,s4,s8,sd".split(","): + self.check_function(getattr(self.module, name)) + + +class TestF90ReturnReal(TestReturnReal): + suffix = ".f90" + code = """ +module f90_return_real + contains + function t0(value) + real :: value + real :: t0 + t0 = value + end function t0 + function t4(value) + real(kind=4) :: value + real(kind=4) :: t4 + t4 = value + end function t4 + function t8(value) + real(kind=8) :: value + real(kind=8) :: t8 + t8 = value + end function t8 + function td(value) + double precision :: value + double precision :: td + td = value + end function td + + subroutine s0(t0,value) + real :: value + real :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s4(t4,value) + real(kind=4) :: value + real(kind=4) :: t4 +!f2py intent(out) t4 + t4 = value + end subroutine s4 + subroutine s8(t8,value) + real(kind=8) :: value + real(kind=8) :: t8 +!f2py intent(out) t8 + t8 = value + end subroutine s8 + subroutine sd(td,value) + double precision :: value + double precision :: td +!f2py intent(out) td + td = value + end subroutine sd +end module f90_return_real + """ + + @dec.slow + def test_all(self): + for name in "t0,t4,t8,td,s0,s4,s8,sd".split(","): + self.check_function(getattr(self.module.f90_return_real, name)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_size.py b/numpy/f2py/tests/test_size.py new file mode 100644 index 0000000..1fcad05 --- /dev/null +++ b/numpy/f2py/tests/test_size.py @@ -0,0 +1,53 @@ +from __future__ import division, absolute_import, print_function + +import os + +from numpy.testing import run_module_suite, assert_equal, dec +from . import util + + +def _path(*a): + return os.path.join(*((os.path.dirname(__file__),) + a)) + + +class TestSizeSumExample(util.F2PyTest): + sources = [_path('src', 'size', 'foo.f90')] + + @dec.slow + def test_all(self): + r = self.module.foo([[]]) + assert_equal(r, [0], repr(r)) + + r = self.module.foo([[1, 2]]) + assert_equal(r, [3], repr(r)) + + r = self.module.foo([[1, 2], [3, 4]]) + assert_equal(r, [3, 7], repr(r)) + + r = self.module.foo([[1, 2], [3, 4], [5, 6]]) + assert_equal(r, [3, 7, 11], repr(r)) + + @dec.slow + def test_transpose(self): + r = self.module.trans([[]]) + assert_equal(r.T, [[]], repr(r)) + + r = self.module.trans([[1, 2]]) + assert_equal(r, [[1], [2]], repr(r)) + + r = self.module.trans([[1, 2, 3], [4, 5, 6]]) + assert_equal(r, [[1, 4], [2, 5], [3, 6]], repr(r)) + + @dec.slow + def test_flatten(self): + r = self.module.flatten([[]]) + assert_equal(r, [], repr(r)) + + r = self.module.flatten([[1, 2]]) + assert_equal(r, [1, 2], repr(r)) + + r = self.module.flatten([[1, 2, 3], [4, 5, 6]]) + assert_equal(r, [1, 2, 3, 4, 5, 6], repr(r)) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/test_string.py b/numpy/f2py/tests/test_string.py new file mode 100644 index 0000000..065861c --- /dev/null +++ b/numpy/f2py/tests/test_string.py @@ -0,0 +1,26 @@ +from __future__ import division, absolute_import, print_function + +import os + +from numpy.testing import run_module_suite, assert_array_equal, dec +import numpy as np +from . import util + + +def _path(*a): + return os.path.join(*((os.path.dirname(__file__),) + a)) + +class TestString(util.F2PyTest): + sources = [_path('src', 'string', 'char.f90')] + + @dec.slow + def test_char(self): + strings = np.array(['ab', 'cd', 'ef'], dtype='c').T + inp, out = self.module.char_test.change_strings(strings, strings.shape[1]) + assert_array_equal(inp, strings) + expected = strings.copy() + expected[1, :] = 'AAA' + assert_array_equal(out, expected) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/f2py/tests/util.py b/numpy/f2py/tests/util.py new file mode 100644 index 0000000..881b328 --- /dev/null +++ b/numpy/f2py/tests/util.py @@ -0,0 +1,359 @@ +""" +Utility functions for + +- building and importing modules on test time, using a temporary location +- detecting if compilers are present + +""" +from __future__ import division, absolute_import, print_function + +import os +import sys +import subprocess +import tempfile +import shutil +import atexit +import textwrap +import re +import random +import numpy.f2py + +from numpy.compat import asbytes, asstr +from numpy.testing import SkipTest, temppath, dec +from importlib import import_module + +try: + from hashlib import md5 +except ImportError: + from md5 import new as md5 + +# +# Maintaining a temporary module directory +# + +_module_dir = None + + +def _cleanup(): + global _module_dir + if _module_dir is not None: + try: + sys.path.remove(_module_dir) + except ValueError: + pass + try: + shutil.rmtree(_module_dir) + except (IOError, OSError): + pass + _module_dir = None + + +def get_module_dir(): + global _module_dir + if _module_dir is None: + _module_dir = tempfile.mkdtemp() + atexit.register(_cleanup) + if _module_dir not in sys.path: + sys.path.insert(0, _module_dir) + return _module_dir + + +def get_temp_module_name(): + # Assume single-threaded, and the module dir usable only by this thread + d = get_module_dir() + for j in range(5403, 9999999): + name = "_test_ext_module_%d" % j + fn = os.path.join(d, name) + if name not in sys.modules and not os.path.isfile(fn + '.py'): + return name + raise RuntimeError("Failed to create a temporary module name") + + +def _memoize(func): + memo = {} + + def wrapper(*a, **kw): + key = repr((a, kw)) + if key not in memo: + try: + memo[key] = func(*a, **kw) + except Exception as e: + memo[key] = e + raise + ret = memo[key] + if isinstance(ret, Exception): + raise ret + return ret + wrapper.__name__ = func.__name__ + return wrapper + +# +# Building modules +# + + +@_memoize +def build_module(source_files, options=[], skip=[], only=[], module_name=None): + """ + Compile and import a f2py module, built from the given files. + + """ + + code = ("import sys; sys.path = %s; import numpy.f2py as f2py2e; " + "f2py2e.main()" % repr(sys.path)) + + d = get_module_dir() + + # Copy files + dst_sources = [] + for fn in source_files: + if not os.path.isfile(fn): + raise RuntimeError("%s is not a file" % fn) + dst = os.path.join(d, os.path.basename(fn)) + shutil.copyfile(fn, dst) + dst_sources.append(dst) + + fn = os.path.join(os.path.dirname(fn), '.f2py_f2cmap') + if os.path.isfile(fn): + dst = os.path.join(d, os.path.basename(fn)) + if not os.path.isfile(dst): + shutil.copyfile(fn, dst) + + # Prepare options + if module_name is None: + module_name = get_temp_module_name() + f2py_opts = ['-c', '-m', module_name] + options + dst_sources + if skip: + f2py_opts += ['skip:'] + skip + if only: + f2py_opts += ['only:'] + only + + # Build + cwd = os.getcwd() + try: + os.chdir(d) + cmd = [sys.executable, '-c', code] + f2py_opts + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, err = p.communicate() + if p.returncode != 0: + raise RuntimeError("Running f2py failed: %s\n%s" + % (cmd[4:], asstr(out))) + finally: + os.chdir(cwd) + + # Partial cleanup + for fn in dst_sources: + os.unlink(fn) + + # Import + return import_module(module_name) + + +@_memoize +def build_code(source_code, options=[], skip=[], only=[], suffix=None, + module_name=None): + """ + Compile and import Fortran code using f2py. + + """ + if suffix is None: + suffix = '.f' + with temppath(suffix=suffix) as path: + with open(path, 'w') as f: + f.write(source_code) + return build_module([path], options=options, skip=skip, only=only, + module_name=module_name) + +# +# Check if compilers are available at all... +# + +_compiler_status = None + + +def _get_compiler_status(): + global _compiler_status + if _compiler_status is not None: + return _compiler_status + + _compiler_status = (False, False, False) + + # XXX: this is really ugly. But I don't know how to invoke Distutils + # in a safer way... + code = """ +import os +import sys +sys.path = %(syspath)s + +def configuration(parent_name='',top_path=None): + global config + from numpy.distutils.misc_util import Configuration + config = Configuration('', parent_name, top_path) + return config + +from numpy.distutils.core import setup +setup(configuration=configuration) + +config_cmd = config.get_config_cmd() +have_c = config_cmd.try_compile('void foo() {}') +print('COMPILERS:%%d,%%d,%%d' %% (have_c, + config.have_f77c(), + config.have_f90c())) +sys.exit(99) +""" + code = code % dict(syspath=repr(sys.path)) + + with temppath(suffix='.py') as script: + with open(script, 'w') as f: + f.write(code) + + cmd = [sys.executable, script, 'config'] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, err = p.communicate() + + m = re.search(br'COMPILERS:(\d+),(\d+),(\d+)', out) + if m: + _compiler_status = (bool(int(m.group(1))), bool(int(m.group(2))), + bool(int(m.group(3)))) + # Finished + return _compiler_status + + +def has_c_compiler(): + return _get_compiler_status()[0] + + +def has_f77_compiler(): + return _get_compiler_status()[1] + + +def has_f90_compiler(): + return _get_compiler_status()[2] + +# +# Building with distutils +# + + +@_memoize +def build_module_distutils(source_files, config_code, module_name, **kw): + """ + Build a module via distutils and import it. + + """ + from numpy.distutils.misc_util import Configuration + from numpy.distutils.core import setup + + d = get_module_dir() + + # Copy files + dst_sources = [] + for fn in source_files: + if not os.path.isfile(fn): + raise RuntimeError("%s is not a file" % fn) + dst = os.path.join(d, os.path.basename(fn)) + shutil.copyfile(fn, dst) + dst_sources.append(dst) + + # Build script + config_code = textwrap.dedent(config_code).replace("\n", "\n ") + + code = """\ +import os +import sys +sys.path = %(syspath)s + +def configuration(parent_name='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('', parent_name, top_path) + %(config_code)s + return config + +if __name__ == "__main__": + from numpy.distutils.core import setup + setup(configuration=configuration) +""" % dict(config_code=config_code, syspath=repr(sys.path)) + + script = os.path.join(d, get_temp_module_name() + '.py') + dst_sources.append(script) + f = open(script, 'wb') + f.write(asbytes(code)) + f.close() + + # Build + cwd = os.getcwd() + try: + os.chdir(d) + cmd = [sys.executable, script, 'build_ext', '-i'] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, err = p.communicate() + if p.returncode != 0: + raise RuntimeError("Running distutils build failed: %s\n%s" + % (cmd[4:], asstr(out))) + finally: + os.chdir(cwd) + + # Partial cleanup + for fn in dst_sources: + os.unlink(fn) + + # Import + __import__(module_name) + return sys.modules[module_name] + +# +# Unittest convenience +# + + +class F2PyTest(object): + code = None + sources = None + options = [] + skip = [] + only = [] + suffix = '.f' + module = None + module_name = None + + @dec.knownfailureif(sys.platform=='win32', msg='Fails with MinGW64 Gfortran (Issue #9673)') + def setup(self): + if self.module is not None: + return + + # Check compiler availability first + if not has_c_compiler(): + raise SkipTest("No C compiler available") + + codes = [] + if self.sources: + codes.extend(self.sources) + if self.code is not None: + codes.append(self.suffix) + + needs_f77 = False + needs_f90 = False + for fn in codes: + if fn.endswith('.f'): + needs_f77 = True + elif fn.endswith('.f90'): + needs_f90 = True + if needs_f77 and not has_f77_compiler(): + raise SkipTest("No Fortran 77 compiler available") + if needs_f90 and not has_f90_compiler(): + raise SkipTest("No Fortran 90 compiler available") + + # Build the module + if self.code is not None: + self.module = build_code(self.code, options=self.options, + skip=self.skip, only=self.only, + suffix=self.suffix, + module_name=self.module_name) + + if self.sources is not None: + self.module = build_module(self.sources, options=self.options, + skip=self.skip, only=self.only, + module_name=self.module_name) diff --git a/numpy/f2py/use_rules.py b/numpy/f2py/use_rules.py new file mode 100644 index 0000000..6f44f16 --- /dev/null +++ b/numpy/f2py/use_rules.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +""" + +Build 'use others module data' mechanism for f2py2e. + +Unfinished. + +Copyright 2000 Pearu Peterson all rights reserved, +Pearu Peterson +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2000/09/10 12:35:43 $ +Pearu Peterson + +""" +from __future__ import division, absolute_import, print_function + +__version__ = "$Revision: 1.3 $"[10:-1] + +f2py_version = 'See `f2py -v`' + + +from .auxfuncs import ( + applyrules, dictappend, gentitle, hasnote, outmess +) + + +usemodule_rules = { + 'body': """ +#begintitle# +static char doc_#apiname#[] = \"\\\nVariable wrapper signature:\\n\\ +\t #name# = get_#name#()\\n\\ +Arguments:\\n\\ +#docstr#\"; +extern F_MODFUNC(#usemodulename#,#USEMODULENAME#,#realname#,#REALNAME#); +static PyObject *#apiname#(PyObject *capi_self, PyObject *capi_args) { +/*#decl#*/ +\tif (!PyArg_ParseTuple(capi_args, \"\")) goto capi_fail; +printf(\"c: %d\\n\",F_MODFUNC(#usemodulename#,#USEMODULENAME#,#realname#,#REALNAME#)); +\treturn Py_BuildValue(\"\"); +capi_fail: +\treturn NULL; +} +""", + 'method': '\t{\"get_#name#\",#apiname#,METH_VARARGS|METH_KEYWORDS,doc_#apiname#},', + 'need': ['F_MODFUNC'] +} + +################ + + +def buildusevars(m, r): + ret = {} + outmess( + '\t\tBuilding use variable hooks for module "%s" (feature only for F90/F95)...\n' % (m['name'])) + varsmap = {} + revmap = {} + if 'map' in r: + for k in r['map'].keys(): + if r['map'][k] in revmap: + outmess('\t\t\tVariable "%s<=%s" is already mapped by "%s". Skipping.\n' % ( + r['map'][k], k, revmap[r['map'][k]])) + else: + revmap[r['map'][k]] = k + if 'only' in r and r['only']: + for v in r['map'].keys(): + if r['map'][v] in m['vars']: + + if revmap[r['map'][v]] == v: + varsmap[v] = r['map'][v] + else: + outmess('\t\t\tIgnoring map "%s=>%s". See above.\n' % + (v, r['map'][v])) + else: + outmess( + '\t\t\tNo definition for variable "%s=>%s". Skipping.\n' % (v, r['map'][v])) + else: + for v in m['vars'].keys(): + if v in revmap: + varsmap[v] = revmap[v] + else: + varsmap[v] = v + for v in varsmap.keys(): + ret = dictappend(ret, buildusevar(v, varsmap[v], m['vars'], m['name'])) + return ret + + +def buildusevar(name, realname, vars, usemodulename): + outmess('\t\t\tConstructing wrapper function for variable "%s=>%s"...\n' % ( + name, realname)) + ret = {} + vrd = {'name': name, + 'realname': realname, + 'REALNAME': realname.upper(), + 'usemodulename': usemodulename, + 'USEMODULENAME': usemodulename.upper(), + 'texname': name.replace('_', '\\_'), + 'begintitle': gentitle('%s=>%s' % (name, realname)), + 'endtitle': gentitle('end of %s=>%s' % (name, realname)), + 'apiname': '#modulename#_use_%s_from_%s' % (realname, usemodulename) + } + nummap = {0: 'Ro', 1: 'Ri', 2: 'Rii', 3: 'Riii', 4: 'Riv', + 5: 'Rv', 6: 'Rvi', 7: 'Rvii', 8: 'Rviii', 9: 'Rix'} + vrd['texnamename'] = name + for i in nummap.keys(): + vrd['texnamename'] = vrd['texnamename'].replace(repr(i), nummap[i]) + if hasnote(vars[realname]): + vrd['note'] = vars[realname]['note'] + rd = dictappend({}, vrd) + + print(name, realname, vars[realname]) + ret = applyrules(usemodule_rules, rd) + return ret diff --git a/numpy/fft/__init__.py b/numpy/fft/__init__.py new file mode 100644 index 0000000..72d61a7 --- /dev/null +++ b/numpy/fft/__init__.py @@ -0,0 +1,11 @@ +from __future__ import division, absolute_import, print_function + +# To get sub-modules +from .info import __doc__ + +from .fftpack import * +from .helper import * + +from numpy.testing import _numpy_tester +test = _numpy_tester().test +bench = _numpy_tester().bench diff --git a/numpy/fft/fftpack.c b/numpy/fft/fftpack.c new file mode 100644 index 0000000..277f49f --- /dev/null +++ b/numpy/fft/fftpack.c @@ -0,0 +1,1501 @@ +/* + * fftpack.c : A set of FFT routines in C. + * Algorithmically based on Fortran-77 FFTPACK by Paul N. Swarztrauber (Version 4, 1985). +*/ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include +#include +#include +#include + +#define DOUBLE +#ifdef DOUBLE +#define Treal double +#else +#define Treal float +#endif + + +#define ref(u,a) u[a] + +#define MAXFAC 13 /* maximum number of factors in factorization of n */ +#define NSPECIAL 4 /* number of factors for which we have special-case routines */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ---------------------------------------------------------------------- + passf2, passf3, passf4, passf5, passf. Complex FFT passes fwd and bwd. +----------------------------------------------------------------------- */ + +static void passf2(int ido, int l1, const Treal cc[], Treal ch[], const Treal wa1[], int isign) + /* isign==+1 for backward transform */ + { + int i, k, ah, ac; + Treal ti2, tr2; + if (ido <= 2) { + for (k=0; k= l1) { + for (j=1; j idp) idlj -= idp; + war = wa[idlj - 2]; + wai = wa[idlj-1]; + for (ik=0; ik= l1) { + for (j=1; j= l1) { + for (k=0; k= l1) { + for (j=1; j= l1) { + for (k=0; k= l1) { + for (j=1; j= l1) { + for (j=1; j 5) { + wa[i1-1] = wa[i-1]; + wa[i1] = wa[i]; + } + } + l1 = l2; + } + } /* cffti1 */ + + +NPY_VISIBILITY_HIDDEN void npy_cffti(int n, Treal wsave[]) + { + int iw1, iw2; + if (n == 1) return; + iw1 = 2*n; + iw2 = iw1 + 2*n; + cffti1(n, wsave+iw1, (int*)(wsave+iw2)); + } /* npy_cffti */ + + /* ------------------------------------------------------------------- +rfftf1, rfftb1, npy_rfftf, npy_rfftb, rffti1, npy_rffti. Treal FFTs. +---------------------------------------------------------------------- */ + +static void rfftf1(int n, Treal c[], Treal ch[], const Treal wa[], const int ifac[MAXFAC+2]) + { + int i; + int k1, l1, l2, na, kh, nf, ip, iw, ix2, ix3, ix4, ido, idl1; + Treal *cinput, *coutput; + nf = ifac[1]; + na = 1; + l2 = n; + iw = n-1; + for (k1 = 1; k1 <= nf; ++k1) { + kh = nf - k1; + ip = ifac[kh + 2]; + l1 = l2 / ip; + ido = n / l2; + idl1 = ido*l1; + iw -= (ip - 1)*ido; + na = !na; + if (na) { + cinput = ch; + coutput = c; + } else { + cinput = c; + coutput = ch; + } + switch (ip) { + case 4: + ix2 = iw + ido; + ix3 = ix2 + ido; + radf4(ido, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3]); + break; + case 2: + radf2(ido, l1, cinput, coutput, &wa[iw]); + break; + case 3: + ix2 = iw + ido; + radf3(ido, l1, cinput, coutput, &wa[iw], &wa[ix2]); + break; + case 5: + ix2 = iw + ido; + ix3 = ix2 + ido; + ix4 = ix3 + ido; + radf5(ido, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4]); + break; + default: + if (ido == 1) + na = !na; + if (na == 0) { + radfg(ido, ip, l1, idl1, c, ch, &wa[iw]); + na = 1; + } else { + radfg(ido, ip, l1, idl1, ch, c, &wa[iw]); + na = 0; + } + } + l2 = l1; + } + if (na == 1) return; + for (i = 0; i < n; i++) c[i] = ch[i]; + } /* rfftf1 */ + + +static void rfftb1(int n, Treal c[], Treal ch[], const Treal wa[], const int ifac[MAXFAC+2]) + { + int i; + int k1, l1, l2, na, nf, ip, iw, ix2, ix3, ix4, ido, idl1; + Treal *cinput, *coutput; + nf = ifac[1]; + na = 0; + l1 = 1; + iw = 0; + for (k1=1; k1<=nf; k1++) { + ip = ifac[k1 + 1]; + l2 = ip*l1; + ido = n / l2; + idl1 = ido*l1; + if (na) { + cinput = ch; + coutput = c; + } else { + cinput = c; + coutput = ch; + } + switch (ip) { + case 4: + ix2 = iw + ido; + ix3 = ix2 + ido; + radb4(ido, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3]); + na = !na; + break; + case 2: + radb2(ido, l1, cinput, coutput, &wa[iw]); + na = !na; + break; + case 3: + ix2 = iw + ido; + radb3(ido, l1, cinput, coutput, &wa[iw], &wa[ix2]); + na = !na; + break; + case 5: + ix2 = iw + ido; + ix3 = ix2 + ido; + ix4 = ix3 + ido; + radb5(ido, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4]); + na = !na; + break; + default: + radbg(ido, ip, l1, idl1, cinput, coutput, &wa[iw]); + if (ido == 1) na = !na; + } + l1 = l2; + iw += (ip - 1)*ido; + } + if (na == 0) return; + for (i=0; i n: + index = [slice(None)]*len(s) + index[axis] = slice(0, n) + a = a[index] + else: + index = [slice(None)]*len(s) + index[axis] = slice(0, s[axis]) + s[axis] = n + z = zeros(s, a.dtype.char) + z[index] = a + a = z + + if axis != -1: + a = swapaxes(a, axis, -1) + r = work_function(a, wsave) + if axis != -1: + r = swapaxes(r, axis, -1) + + # As soon as we put wsave back into the cache, another thread could pick it + # up and start using it, so we must not do this until after we're + # completely done using it ourselves. + fft_cache.put_twiddle_factors(n, wsave) + + return r + + +def _unitary(norm): + if norm not in (None, "ortho"): + raise ValueError("Invalid norm value %s, should be None or \"ortho\"." + % norm) + return norm is not None + + +def fft(a, n=None, axis=-1, norm=None): + """ + Compute the one-dimensional discrete Fourier Transform. + + This function computes the one-dimensional *n*-point discrete Fourier + Transform (DFT) with the efficient Fast Fourier Transform (FFT) + algorithm [CT]. + + Parameters + ---------- + a : array_like + Input array, can be complex. + n : int, optional + Length of the transformed axis of the output. + If `n` is smaller than the length of the input, the input is cropped. + If it is larger, the input is padded with zeros. If `n` is not given, + the length of the input along the axis specified by `axis` is used. + axis : int, optional + Axis over which to compute the FFT. If not given, the last axis is + used. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axis + indicated by `axis`, or the last one if `axis` is not specified. + + Raises + ------ + IndexError + if `axes` is larger than the last axis of `a`. + + See Also + -------- + numpy.fft : for definition of the DFT and conventions used. + ifft : The inverse of `fft`. + fft2 : The two-dimensional FFT. + fftn : The *n*-dimensional FFT. + rfftn : The *n*-dimensional FFT of real input. + fftfreq : Frequency bins for given FFT parameters. + + Notes + ----- + FFT (Fast Fourier Transform) refers to a way the discrete Fourier + Transform (DFT) can be calculated efficiently, by using symmetries in the + calculated terms. The symmetry is highest when `n` is a power of 2, and + the transform is therefore most efficient for these sizes. + + The DFT is defined, with the conventions used in this implementation, in + the documentation for the `numpy.fft` module. + + References + ---------- + .. [CT] Cooley, James W., and John W. Tukey, 1965, "An algorithm for the + machine calculation of complex Fourier series," *Math. Comput.* + 19: 297-301. + + Examples + -------- + >>> np.fft.fft(np.exp(2j * np.pi * np.arange(8) / 8)) + array([ -3.44505240e-16 +1.14383329e-17j, + 8.00000000e+00 -5.71092652e-15j, + 2.33482938e-16 +1.22460635e-16j, + 1.64863782e-15 +1.77635684e-15j, + 9.95839695e-17 +2.33482938e-16j, + 0.00000000e+00 +1.66837030e-15j, + 1.14383329e-17 +1.22460635e-16j, + -1.64863782e-15 +1.77635684e-15j]) + + In this example, real input has an FFT which is Hermitian, i.e., symmetric + in the real part and anti-symmetric in the imaginary part, as described in + the `numpy.fft` documentation: + + >>> import matplotlib.pyplot as plt + >>> t = np.arange(256) + >>> sp = np.fft.fft(np.sin(t)) + >>> freq = np.fft.fftfreq(t.shape[-1]) + >>> plt.plot(freq, sp.real, freq, sp.imag) + [, ] + >>> plt.show() + + """ + + a = asarray(a).astype(complex, copy=False) + if n is None: + n = a.shape[axis] + output = _raw_fft(a, n, axis, fftpack.cffti, fftpack.cfftf, _fft_cache) + if _unitary(norm): + output *= 1 / sqrt(n) + return output + + +def ifft(a, n=None, axis=-1, norm=None): + """ + Compute the one-dimensional inverse discrete Fourier Transform. + + This function computes the inverse of the one-dimensional *n*-point + discrete Fourier transform computed by `fft`. In other words, + ``ifft(fft(a)) == a`` to within numerical accuracy. + For a general description of the algorithm and definitions, + see `numpy.fft`. + + The input should be ordered in the same way as is returned by `fft`, + i.e., + + * ``a[0]`` should contain the zero frequency term, + * ``a[1:n//2]`` should contain the positive-frequency terms, + * ``a[n//2 + 1:]`` should contain the negative-frequency terms, in + increasing order starting from the most negative frequency. + + For an even number of input points, ``A[n//2]`` represents the sum of + the values at the positive and negative Nyquist frequencies, as the two + are aliased together. See `numpy.fft` for details. + + Parameters + ---------- + a : array_like + Input array, can be complex. + n : int, optional + Length of the transformed axis of the output. + If `n` is smaller than the length of the input, the input is cropped. + If it is larger, the input is padded with zeros. If `n` is not given, + the length of the input along the axis specified by `axis` is used. + See notes about padding issues. + axis : int, optional + Axis over which to compute the inverse DFT. If not given, the last + axis is used. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axis + indicated by `axis`, or the last one if `axis` is not specified. + + Raises + ------ + IndexError + If `axes` is larger than the last axis of `a`. + + See Also + -------- + numpy.fft : An introduction, with definitions and general explanations. + fft : The one-dimensional (forward) FFT, of which `ifft` is the inverse + ifft2 : The two-dimensional inverse FFT. + ifftn : The n-dimensional inverse FFT. + + Notes + ----- + If the input parameter `n` is larger than the size of the input, the input + is padded by appending zeros at the end. Even though this is the common + approach, it might lead to surprising results. If a different padding is + desired, it must be performed before calling `ifft`. + + Examples + -------- + >>> np.fft.ifft([0, 4, 0, 0]) + array([ 1.+0.j, 0.+1.j, -1.+0.j, 0.-1.j]) + + Create and plot a band-limited signal with random phases: + + >>> import matplotlib.pyplot as plt + >>> t = np.arange(400) + >>> n = np.zeros((400,), dtype=complex) + >>> n[40:60] = np.exp(1j*np.random.uniform(0, 2*np.pi, (20,))) + >>> s = np.fft.ifft(n) + >>> plt.plot(t, s.real, 'b-', t, s.imag, 'r--') + ... + >>> plt.legend(('real', 'imaginary')) + ... + >>> plt.show() + + """ + # The copy may be required for multithreading. + a = array(a, copy=True, dtype=complex) + if n is None: + n = a.shape[axis] + unitary = _unitary(norm) + output = _raw_fft(a, n, axis, fftpack.cffti, fftpack.cfftb, _fft_cache) + return output * (1 / (sqrt(n) if unitary else n)) + + +def rfft(a, n=None, axis=-1, norm=None): + """ + Compute the one-dimensional discrete Fourier Transform for real input. + + This function computes the one-dimensional *n*-point discrete Fourier + Transform (DFT) of a real-valued array by means of an efficient algorithm + called the Fast Fourier Transform (FFT). + + Parameters + ---------- + a : array_like + Input array + n : int, optional + Number of points along transformation axis in the input to use. + If `n` is smaller than the length of the input, the input is cropped. + If it is larger, the input is padded with zeros. If `n` is not given, + the length of the input along the axis specified by `axis` is used. + axis : int, optional + Axis over which to compute the FFT. If not given, the last axis is + used. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axis + indicated by `axis`, or the last one if `axis` is not specified. + If `n` is even, the length of the transformed axis is ``(n/2)+1``. + If `n` is odd, the length is ``(n+1)/2``. + + Raises + ------ + IndexError + If `axis` is larger than the last axis of `a`. + + See Also + -------- + numpy.fft : For definition of the DFT and conventions used. + irfft : The inverse of `rfft`. + fft : The one-dimensional FFT of general (complex) input. + fftn : The *n*-dimensional FFT. + rfftn : The *n*-dimensional FFT of real input. + + Notes + ----- + When the DFT is computed for purely real input, the output is + Hermitian-symmetric, i.e. the negative frequency terms are just the complex + conjugates of the corresponding positive-frequency terms, and the + negative-frequency terms are therefore redundant. This function does not + compute the negative frequency terms, and the length of the transformed + axis of the output is therefore ``n//2 + 1``. + + When ``A = rfft(a)`` and fs is the sampling frequency, ``A[0]`` contains + the zero-frequency term 0*fs, which is real due to Hermitian symmetry. + + If `n` is even, ``A[-1]`` contains the term representing both positive + and negative Nyquist frequency (+fs/2 and -fs/2), and must also be purely + real. If `n` is odd, there is no term at fs/2; ``A[-1]`` contains + the largest positive frequency (fs/2*(n-1)/n), and is complex in the + general case. + + If the input `a` contains an imaginary part, it is silently discarded. + + Examples + -------- + >>> np.fft.fft([0, 1, 0, 0]) + array([ 1.+0.j, 0.-1.j, -1.+0.j, 0.+1.j]) + >>> np.fft.rfft([0, 1, 0, 0]) + array([ 1.+0.j, 0.-1.j, -1.+0.j]) + + Notice how the final element of the `fft` output is the complex conjugate + of the second element, for real input. For `rfft`, this symmetry is + exploited to compute only the non-negative frequency terms. + + """ + # The copy may be required for multithreading. + a = array(a, copy=True, dtype=float) + output = _raw_fft(a, n, axis, fftpack.rffti, fftpack.rfftf, + _real_fft_cache) + if _unitary(norm): + if n is None: + n = a.shape[axis] + output *= 1 / sqrt(n) + return output + + +def irfft(a, n=None, axis=-1, norm=None): + """ + Compute the inverse of the n-point DFT for real input. + + This function computes the inverse of the one-dimensional *n*-point + discrete Fourier Transform of real input computed by `rfft`. + In other words, ``irfft(rfft(a), len(a)) == a`` to within numerical + accuracy. (See Notes below for why ``len(a)`` is necessary here.) + + The input is expected to be in the form returned by `rfft`, i.e. the + real zero-frequency term followed by the complex positive frequency terms + in order of increasing frequency. Since the discrete Fourier Transform of + real input is Hermitian-symmetric, the negative frequency terms are taken + to be the complex conjugates of the corresponding positive frequency terms. + + Parameters + ---------- + a : array_like + The input array. + n : int, optional + Length of the transformed axis of the output. + For `n` output points, ``n//2+1`` input points are necessary. If the + input is longer than this, it is cropped. If it is shorter than this, + it is padded with zeros. If `n` is not given, it is determined from + the length of the input along the axis specified by `axis`. + axis : int, optional + Axis over which to compute the inverse FFT. If not given, the last + axis is used. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : ndarray + The truncated or zero-padded input, transformed along the axis + indicated by `axis`, or the last one if `axis` is not specified. + The length of the transformed axis is `n`, or, if `n` is not given, + ``2*(m-1)`` where ``m`` is the length of the transformed axis of the + input. To get an odd number of output points, `n` must be specified. + + Raises + ------ + IndexError + If `axis` is larger than the last axis of `a`. + + See Also + -------- + numpy.fft : For definition of the DFT and conventions used. + rfft : The one-dimensional FFT of real input, of which `irfft` is inverse. + fft : The one-dimensional FFT. + irfft2 : The inverse of the two-dimensional FFT of real input. + irfftn : The inverse of the *n*-dimensional FFT of real input. + + Notes + ----- + Returns the real valued `n`-point inverse discrete Fourier transform + of `a`, where `a` contains the non-negative frequency terms of a + Hermitian-symmetric sequence. `n` is the length of the result, not the + input. + + If you specify an `n` such that `a` must be zero-padded or truncated, the + extra/removed values will be added/removed at high frequencies. One can + thus resample a series to `m` points via Fourier interpolation by: + ``a_resamp = irfft(rfft(a), m)``. + + Examples + -------- + >>> np.fft.ifft([1, -1j, -1, 1j]) + array([ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]) + >>> np.fft.irfft([1, -1j, -1]) + array([ 0., 1., 0., 0.]) + + Notice how the last term in the input to the ordinary `ifft` is the + complex conjugate of the second term, and the output has zero imaginary + part everywhere. When calling `irfft`, the negative frequencies are not + specified, and the output array is purely real. + + """ + # The copy may be required for multithreading. + a = array(a, copy=True, dtype=complex) + if n is None: + n = (a.shape[axis] - 1) * 2 + unitary = _unitary(norm) + output = _raw_fft(a, n, axis, fftpack.rffti, fftpack.rfftb, + _real_fft_cache) + return output * (1 / (sqrt(n) if unitary else n)) + + +def hfft(a, n=None, axis=-1, norm=None): + """ + Compute the FFT of a signal that has Hermitian symmetry, i.e., a real + spectrum. + + Parameters + ---------- + a : array_like + The input array. + n : int, optional + Length of the transformed axis of the output. For `n` output + points, ``n//2 + 1`` input points are necessary. If the input is + longer than this, it is cropped. If it is shorter than this, it is + padded with zeros. If `n` is not given, it is determined from the + length of the input along the axis specified by `axis`. + axis : int, optional + Axis over which to compute the FFT. If not given, the last + axis is used. + norm : {None, "ortho"}, optional + Normalization mode (see `numpy.fft`). Default is None. + + .. versionadded:: 1.10.0 + + Returns + ------- + out : ndarray + The truncated or zero-padded input, transformed along the axis + indicated by `axis`, or the last one if `axis` is not specified. + The length of the transformed axis is `n`, or, if `n` is not given, + ``2*m - 2`` where ``m`` is the length of the transformed axis of + the input. To get an odd number of output points, `n` must be + specified, for instance as ``2*m - 1`` in the typical case, + + Raises + ------ + IndexError + If `axis` is larger than the last axis of `a`. + + See also + -------- + rfft : Compute the one-dimensional FFT for real input. + ihfft : The inverse of `hfft`. + + Notes + ----- + `hfft`/`ihfft` are a pair analogous to `rfft`/`irfft`, but for the + opposite case: here the signal has Hermitian symmetry in the time + domain and is real in the frequency domain. So here it's `hfft` for + which you must supply the length of the result if it is to be odd. + + * even: ``ihfft(hfft(a, 2*len(a) - 2) == a``, within roundoff error, + * odd: ``ihfft(hfft(a, 2*len(a) - 1) == a``, within roundoff error. + + Examples + -------- + >>> signal = np.array([1, 2, 3, 4, 3, 2]) + >>> np.fft.fft(signal) + array([ 15.+0.j, -4.+0.j, 0.+0.j, -1.-0.j, 0.+0.j, -4.+0.j]) + >>> np.fft.hfft(signal[:4]) # Input first half of signal + array([ 15., -4., 0., -1., 0., -4.]) + >>> np.fft.hfft(signal, 6) # Input entire signal and truncate + array([ 15., -4., 0., -1., 0., -4.]) + + + >>> signal = np.array([[1, 1.j], [-1.j, 2]]) + >>> np.conj(signal.T) - signal # check Hermitian symmetry + array([[ 0.-0.j, 0.+0.j], + [ 0.+0.j, 0.-0.j]]) + >>> freq_spectrum = np.fft.hfft(signal) + >>> freq_spectrum + array([[ 1., 1.], + [ 2., -2.]]) + + """ + # The copy may be required for multithreading. + a = array(a, copy=True, dtype=complex) + if n is None: + n = (a.shape[axis] - 1) * 2 + unitary = _unitary(norm) + return irfft(conjugate(a), n, axis) * (sqrt(n) if unitary else n) + + +def ihfft(a, n=None, axis=-1, norm=None): + """ + Compute the inverse FFT of a signal that has Hermitian symmetry. + + Parameters + ---------- + a : array_like + Input array. + n : int, optional + Length of the inverse FFT, the number of points along + transformation axis in the input to use. If `n` is smaller than + the length of the input, the input is cropped. If it is larger, + the input is padded with zeros. If `n` is not given, the length of + the input along the axis specified by `axis` is used. + axis : int, optional + Axis over which to compute the inverse FFT. If not given, the last + axis is used. + norm : {None, "ortho"}, optional + Normalization mode (see `numpy.fft`). Default is None. + + .. versionadded:: 1.10.0 + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axis + indicated by `axis`, or the last one if `axis` is not specified. + The length of the transformed axis is ``n//2 + 1``. + + See also + -------- + hfft, irfft + + Notes + ----- + `hfft`/`ihfft` are a pair analogous to `rfft`/`irfft`, but for the + opposite case: here the signal has Hermitian symmetry in the time + domain and is real in the frequency domain. So here it's `hfft` for + which you must supply the length of the result if it is to be odd: + + * even: ``ihfft(hfft(a, 2*len(a) - 2) == a``, within roundoff error, + * odd: ``ihfft(hfft(a, 2*len(a) - 1) == a``, within roundoff error. + + Examples + -------- + >>> spectrum = np.array([ 15, -4, 0, -1, 0, -4]) + >>> np.fft.ifft(spectrum) + array([ 1.+0.j, 2.-0.j, 3.+0.j, 4.+0.j, 3.+0.j, 2.-0.j]) + >>> np.fft.ihfft(spectrum) + array([ 1.-0.j, 2.-0.j, 3.-0.j, 4.-0.j]) + + """ + # The copy may be required for multithreading. + a = array(a, copy=True, dtype=float) + if n is None: + n = a.shape[axis] + unitary = _unitary(norm) + output = conjugate(rfft(a, n, axis)) + return output * (1 / (sqrt(n) if unitary else n)) + + +def _cook_nd_args(a, s=None, axes=None, invreal=0): + if s is None: + shapeless = 1 + if axes is None: + s = list(a.shape) + else: + s = take(a.shape, axes) + else: + shapeless = 0 + s = list(s) + if axes is None: + axes = list(range(-len(s), 0)) + if len(s) != len(axes): + raise ValueError("Shape and axes have different lengths.") + if invreal and shapeless: + s[-1] = (a.shape[axes[-1]] - 1) * 2 + return s, axes + + +def _raw_fftnd(a, s=None, axes=None, function=fft, norm=None): + a = asarray(a) + s, axes = _cook_nd_args(a, s, axes) + itl = list(range(len(axes))) + itl.reverse() + for ii in itl: + a = function(a, n=s[ii], axis=axes[ii], norm=norm) + return a + + +def fftn(a, s=None, axes=None, norm=None): + """ + Compute the N-dimensional discrete Fourier Transform. + + This function computes the *N*-dimensional discrete Fourier Transform over + any number of axes in an *M*-dimensional array by means of the Fast Fourier + Transform (FFT). + + Parameters + ---------- + a : array_like + Input array, can be complex. + s : sequence of ints, optional + Shape (length of each transformed axis) of the output + (``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.). + This corresponds to ``n`` for ``fft(x, n)``. + Along any axis, if the given shape is smaller than that of the input, + the input is cropped. If it is larger, the input is padded with zeros. + if `s` is not given, the shape of the input along the axes specified + by `axes` is used. + axes : sequence of ints, optional + Axes over which to compute the FFT. If not given, the last ``len(s)`` + axes are used, or all axes if `s` is also not specified. + Repeated indices in `axes` means that the transform over that axis is + performed multiple times. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axes + indicated by `axes`, or by a combination of `s` and `a`, + as explained in the parameters section above. + + Raises + ------ + ValueError + If `s` and `axes` have different length. + IndexError + If an element of `axes` is larger than than the number of axes of `a`. + + See Also + -------- + numpy.fft : Overall view of discrete Fourier transforms, with definitions + and conventions used. + ifftn : The inverse of `fftn`, the inverse *n*-dimensional FFT. + fft : The one-dimensional FFT, with definitions and conventions used. + rfftn : The *n*-dimensional FFT of real input. + fft2 : The two-dimensional FFT. + fftshift : Shifts zero-frequency terms to centre of array + + Notes + ----- + The output, analogously to `fft`, contains the term for zero frequency in + the low-order corner of all axes, the positive frequency terms in the + first half of all axes, the term for the Nyquist frequency in the middle + of all axes and the negative frequency terms in the second half of all + axes, in order of decreasingly negative frequency. + + See `numpy.fft` for details, definitions and conventions used. + + Examples + -------- + >>> a = np.mgrid[:3, :3, :3][0] + >>> np.fft.fftn(a, axes=(1, 2)) + array([[[ 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j]], + [[ 9.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j]], + [[ 18.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j]]]) + >>> np.fft.fftn(a, (2, 2), axes=(0, 1)) + array([[[ 2.+0.j, 2.+0.j, 2.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j]], + [[-2.+0.j, -2.+0.j, -2.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j]]]) + + >>> import matplotlib.pyplot as plt + >>> [X, Y] = np.meshgrid(2 * np.pi * np.arange(200) / 12, + ... 2 * np.pi * np.arange(200) / 34) + >>> S = np.sin(X) + np.cos(Y) + np.random.uniform(0, 1, X.shape) + >>> FS = np.fft.fftn(S) + >>> plt.imshow(np.log(np.abs(np.fft.fftshift(FS))**2)) + + >>> plt.show() + + """ + + return _raw_fftnd(a, s, axes, fft, norm) + + +def ifftn(a, s=None, axes=None, norm=None): + """ + Compute the N-dimensional inverse discrete Fourier Transform. + + This function computes the inverse of the N-dimensional discrete + Fourier Transform over any number of axes in an M-dimensional array by + means of the Fast Fourier Transform (FFT). In other words, + ``ifftn(fftn(a)) == a`` to within numerical accuracy. + For a description of the definitions and conventions used, see `numpy.fft`. + + The input, analogously to `ifft`, should be ordered in the same way as is + returned by `fftn`, i.e. it should have the term for zero frequency + in all axes in the low-order corner, the positive frequency terms in the + first half of all axes, the term for the Nyquist frequency in the middle + of all axes and the negative frequency terms in the second half of all + axes, in order of decreasingly negative frequency. + + Parameters + ---------- + a : array_like + Input array, can be complex. + s : sequence of ints, optional + Shape (length of each transformed axis) of the output + (``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.). + This corresponds to ``n`` for ``ifft(x, n)``. + Along any axis, if the given shape is smaller than that of the input, + the input is cropped. If it is larger, the input is padded with zeros. + if `s` is not given, the shape of the input along the axes specified + by `axes` is used. See notes for issue on `ifft` zero padding. + axes : sequence of ints, optional + Axes over which to compute the IFFT. If not given, the last ``len(s)`` + axes are used, or all axes if `s` is also not specified. + Repeated indices in `axes` means that the inverse transform over that + axis is performed multiple times. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axes + indicated by `axes`, or by a combination of `s` or `a`, + as explained in the parameters section above. + + Raises + ------ + ValueError + If `s` and `axes` have different length. + IndexError + If an element of `axes` is larger than than the number of axes of `a`. + + See Also + -------- + numpy.fft : Overall view of discrete Fourier transforms, with definitions + and conventions used. + fftn : The forward *n*-dimensional FFT, of which `ifftn` is the inverse. + ifft : The one-dimensional inverse FFT. + ifft2 : The two-dimensional inverse FFT. + ifftshift : Undoes `fftshift`, shifts zero-frequency terms to beginning + of array. + + Notes + ----- + See `numpy.fft` for definitions and conventions used. + + Zero-padding, analogously with `ifft`, is performed by appending zeros to + the input along the specified dimension. Although this is the common + approach, it might lead to surprising results. If another form of zero + padding is desired, it must be performed before `ifftn` is called. + + Examples + -------- + >>> a = np.eye(4) + >>> np.fft.ifftn(np.fft.fftn(a, axes=(0,)), axes=(1,)) + array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]]) + + + Create and plot an image with band-limited frequency content: + + >>> import matplotlib.pyplot as plt + >>> n = np.zeros((200,200), dtype=complex) + >>> n[60:80, 20:40] = np.exp(1j*np.random.uniform(0, 2*np.pi, (20, 20))) + >>> im = np.fft.ifftn(n).real + >>> plt.imshow(im) + + >>> plt.show() + + """ + + return _raw_fftnd(a, s, axes, ifft, norm) + + +def fft2(a, s=None, axes=(-2, -1), norm=None): + """ + Compute the 2-dimensional discrete Fourier Transform + + This function computes the *n*-dimensional discrete Fourier Transform + over any axes in an *M*-dimensional array by means of the + Fast Fourier Transform (FFT). By default, the transform is computed over + the last two axes of the input array, i.e., a 2-dimensional FFT. + + Parameters + ---------- + a : array_like + Input array, can be complex + s : sequence of ints, optional + Shape (length of each transformed axis) of the output + (``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.). + This corresponds to ``n`` for ``fft(x, n)``. + Along each axis, if the given shape is smaller than that of the input, + the input is cropped. If it is larger, the input is padded with zeros. + if `s` is not given, the shape of the input along the axes specified + by `axes` is used. + axes : sequence of ints, optional + Axes over which to compute the FFT. If not given, the last two + axes are used. A repeated index in `axes` means the transform over + that axis is performed multiple times. A one-element sequence means + that a one-dimensional FFT is performed. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axes + indicated by `axes`, or the last two axes if `axes` is not given. + + Raises + ------ + ValueError + If `s` and `axes` have different length, or `axes` not given and + ``len(s) != 2``. + IndexError + If an element of `axes` is larger than than the number of axes of `a`. + + See Also + -------- + numpy.fft : Overall view of discrete Fourier transforms, with definitions + and conventions used. + ifft2 : The inverse two-dimensional FFT. + fft : The one-dimensional FFT. + fftn : The *n*-dimensional FFT. + fftshift : Shifts zero-frequency terms to the center of the array. + For two-dimensional input, swaps first and third quadrants, and second + and fourth quadrants. + + Notes + ----- + `fft2` is just `fftn` with a different default for `axes`. + + The output, analogously to `fft`, contains the term for zero frequency in + the low-order corner of the transformed axes, the positive frequency terms + in the first half of these axes, the term for the Nyquist frequency in the + middle of the axes and the negative frequency terms in the second half of + the axes, in order of decreasingly negative frequency. + + See `fftn` for details and a plotting example, and `numpy.fft` for + definitions and conventions used. + + + Examples + -------- + >>> a = np.mgrid[:5, :5][0] + >>> np.fft.fft2(a) + array([[ 50.0 +0.j , 0.0 +0.j , 0.0 +0.j , + 0.0 +0.j , 0.0 +0.j ], + [-12.5+17.20477401j, 0.0 +0.j , 0.0 +0.j , + 0.0 +0.j , 0.0 +0.j ], + [-12.5 +4.0614962j , 0.0 +0.j , 0.0 +0.j , + 0.0 +0.j , 0.0 +0.j ], + [-12.5 -4.0614962j , 0.0 +0.j , 0.0 +0.j , + 0.0 +0.j , 0.0 +0.j ], + [-12.5-17.20477401j, 0.0 +0.j , 0.0 +0.j , + 0.0 +0.j , 0.0 +0.j ]]) + + """ + + return _raw_fftnd(a, s, axes, fft, norm) + + +def ifft2(a, s=None, axes=(-2, -1), norm=None): + """ + Compute the 2-dimensional inverse discrete Fourier Transform. + + This function computes the inverse of the 2-dimensional discrete Fourier + Transform over any number of axes in an M-dimensional array by means of + the Fast Fourier Transform (FFT). In other words, ``ifft2(fft2(a)) == a`` + to within numerical accuracy. By default, the inverse transform is + computed over the last two axes of the input array. + + The input, analogously to `ifft`, should be ordered in the same way as is + returned by `fft2`, i.e. it should have the term for zero frequency + in the low-order corner of the two axes, the positive frequency terms in + the first half of these axes, the term for the Nyquist frequency in the + middle of the axes and the negative frequency terms in the second half of + both axes, in order of decreasingly negative frequency. + + Parameters + ---------- + a : array_like + Input array, can be complex. + s : sequence of ints, optional + Shape (length of each axis) of the output (``s[0]`` refers to axis 0, + ``s[1]`` to axis 1, etc.). This corresponds to `n` for ``ifft(x, n)``. + Along each axis, if the given shape is smaller than that of the input, + the input is cropped. If it is larger, the input is padded with zeros. + if `s` is not given, the shape of the input along the axes specified + by `axes` is used. See notes for issue on `ifft` zero padding. + axes : sequence of ints, optional + Axes over which to compute the FFT. If not given, the last two + axes are used. A repeated index in `axes` means the transform over + that axis is performed multiple times. A one-element sequence means + that a one-dimensional FFT is performed. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axes + indicated by `axes`, or the last two axes if `axes` is not given. + + Raises + ------ + ValueError + If `s` and `axes` have different length, or `axes` not given and + ``len(s) != 2``. + IndexError + If an element of `axes` is larger than than the number of axes of `a`. + + See Also + -------- + numpy.fft : Overall view of discrete Fourier transforms, with definitions + and conventions used. + fft2 : The forward 2-dimensional FFT, of which `ifft2` is the inverse. + ifftn : The inverse of the *n*-dimensional FFT. + fft : The one-dimensional FFT. + ifft : The one-dimensional inverse FFT. + + Notes + ----- + `ifft2` is just `ifftn` with a different default for `axes`. + + See `ifftn` for details and a plotting example, and `numpy.fft` for + definition and conventions used. + + Zero-padding, analogously with `ifft`, is performed by appending zeros to + the input along the specified dimension. Although this is the common + approach, it might lead to surprising results. If another form of zero + padding is desired, it must be performed before `ifft2` is called. + + Examples + -------- + >>> a = 4 * np.eye(4) + >>> np.fft.ifft2(a) + array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], + [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], + [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]]) + + """ + + return _raw_fftnd(a, s, axes, ifft, norm) + + +def rfftn(a, s=None, axes=None, norm=None): + """ + Compute the N-dimensional discrete Fourier Transform for real input. + + This function computes the N-dimensional discrete Fourier Transform over + any number of axes in an M-dimensional real array by means of the Fast + Fourier Transform (FFT). By default, all axes are transformed, with the + real transform performed over the last axis, while the remaining + transforms are complex. + + Parameters + ---------- + a : array_like + Input array, taken to be real. + s : sequence of ints, optional + Shape (length along each transformed axis) to use from the input. + (``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.). + The final element of `s` corresponds to `n` for ``rfft(x, n)``, while + for the remaining axes, it corresponds to `n` for ``fft(x, n)``. + Along any axis, if the given shape is smaller than that of the input, + the input is cropped. If it is larger, the input is padded with zeros. + if `s` is not given, the shape of the input along the axes specified + by `axes` is used. + axes : sequence of ints, optional + Axes over which to compute the FFT. If not given, the last ``len(s)`` + axes are used, or all axes if `s` is also not specified. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : complex ndarray + The truncated or zero-padded input, transformed along the axes + indicated by `axes`, or by a combination of `s` and `a`, + as explained in the parameters section above. + The length of the last axis transformed will be ``s[-1]//2+1``, + while the remaining transformed axes will have lengths according to + `s`, or unchanged from the input. + + Raises + ------ + ValueError + If `s` and `axes` have different length. + IndexError + If an element of `axes` is larger than than the number of axes of `a`. + + See Also + -------- + irfftn : The inverse of `rfftn`, i.e. the inverse of the n-dimensional FFT + of real input. + fft : The one-dimensional FFT, with definitions and conventions used. + rfft : The one-dimensional FFT of real input. + fftn : The n-dimensional FFT. + rfft2 : The two-dimensional FFT of real input. + + Notes + ----- + The transform for real input is performed over the last transformation + axis, as by `rfft`, then the transform over the remaining axes is + performed as by `fftn`. The order of the output is as for `rfft` for the + final transformation axis, and as for `fftn` for the remaining + transformation axes. + + See `fft` for details, definitions and conventions used. + + Examples + -------- + >>> a = np.ones((2, 2, 2)) + >>> np.fft.rfftn(a) + array([[[ 8.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j]], + [[ 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j]]]) + + >>> np.fft.rfftn(a, axes=(2, 0)) + array([[[ 4.+0.j, 0.+0.j], + [ 4.+0.j, 0.+0.j]], + [[ 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j]]]) + + """ + # The copy may be required for multithreading. + a = array(a, copy=True, dtype=float) + s, axes = _cook_nd_args(a, s, axes) + a = rfft(a, s[-1], axes[-1], norm) + for ii in range(len(axes)-1): + a = fft(a, s[ii], axes[ii], norm) + return a + + +def rfft2(a, s=None, axes=(-2, -1), norm=None): + """ + Compute the 2-dimensional FFT of a real array. + + Parameters + ---------- + a : array + Input array, taken to be real. + s : sequence of ints, optional + Shape of the FFT. + axes : sequence of ints, optional + Axes over which to compute the FFT. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : ndarray + The result of the real 2-D FFT. + + See Also + -------- + rfftn : Compute the N-dimensional discrete Fourier Transform for real + input. + + Notes + ----- + This is really just `rfftn` with different default behavior. + For more details see `rfftn`. + + """ + + return rfftn(a, s, axes, norm) + + +def irfftn(a, s=None, axes=None, norm=None): + """ + Compute the inverse of the N-dimensional FFT of real input. + + This function computes the inverse of the N-dimensional discrete + Fourier Transform for real input over any number of axes in an + M-dimensional array by means of the Fast Fourier Transform (FFT). In + other words, ``irfftn(rfftn(a), a.shape) == a`` to within numerical + accuracy. (The ``a.shape`` is necessary like ``len(a)`` is for `irfft`, + and for the same reason.) + + The input should be ordered in the same way as is returned by `rfftn`, + i.e. as for `irfft` for the final transformation axis, and as for `ifftn` + along all the other axes. + + Parameters + ---------- + a : array_like + Input array. + s : sequence of ints, optional + Shape (length of each transformed axis) of the output + (``s[0]`` refers to axis 0, ``s[1]`` to axis 1, etc.). `s` is also the + number of input points used along this axis, except for the last axis, + where ``s[-1]//2+1`` points of the input are used. + Along any axis, if the shape indicated by `s` is smaller than that of + the input, the input is cropped. If it is larger, the input is padded + with zeros. If `s` is not given, the shape of the input along the + axes specified by `axes` is used. + axes : sequence of ints, optional + Axes over which to compute the inverse FFT. If not given, the last + `len(s)` axes are used, or all axes if `s` is also not specified. + Repeated indices in `axes` means that the inverse transform over that + axis is performed multiple times. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : ndarray + The truncated or zero-padded input, transformed along the axes + indicated by `axes`, or by a combination of `s` or `a`, + as explained in the parameters section above. + The length of each transformed axis is as given by the corresponding + element of `s`, or the length of the input in every axis except for the + last one if `s` is not given. In the final transformed axis the length + of the output when `s` is not given is ``2*(m-1)`` where ``m`` is the + length of the final transformed axis of the input. To get an odd + number of output points in the final axis, `s` must be specified. + + Raises + ------ + ValueError + If `s` and `axes` have different length. + IndexError + If an element of `axes` is larger than than the number of axes of `a`. + + See Also + -------- + rfftn : The forward n-dimensional FFT of real input, + of which `ifftn` is the inverse. + fft : The one-dimensional FFT, with definitions and conventions used. + irfft : The inverse of the one-dimensional FFT of real input. + irfft2 : The inverse of the two-dimensional FFT of real input. + + Notes + ----- + See `fft` for definitions and conventions used. + + See `rfft` for definitions and conventions used for real input. + + Examples + -------- + >>> a = np.zeros((3, 2, 2)) + >>> a[0, 0, 0] = 3 * 2 * 2 + >>> np.fft.irfftn(a) + array([[[ 1., 1.], + [ 1., 1.]], + [[ 1., 1.], + [ 1., 1.]], + [[ 1., 1.], + [ 1., 1.]]]) + + """ + # The copy may be required for multithreading. + a = array(a, copy=True, dtype=complex) + s, axes = _cook_nd_args(a, s, axes, invreal=1) + for ii in range(len(axes)-1): + a = ifft(a, s[ii], axes[ii], norm) + a = irfft(a, s[-1], axes[-1], norm) + return a + + +def irfft2(a, s=None, axes=(-2, -1), norm=None): + """ + Compute the 2-dimensional inverse FFT of a real array. + + Parameters + ---------- + a : array_like + The input array + s : sequence of ints, optional + Shape of the inverse FFT. + axes : sequence of ints, optional + The axes over which to compute the inverse fft. + Default is the last two axes. + norm : {None, "ortho"}, optional + .. versionadded:: 1.10.0 + + Normalization mode (see `numpy.fft`). Default is None. + + Returns + ------- + out : ndarray + The result of the inverse real 2-D FFT. + + See Also + -------- + irfftn : Compute the inverse of the N-dimensional FFT of real input. + + Notes + ----- + This is really `irfftn` with different defaults. + For more details see `irfftn`. + + """ + + return irfftn(a, s, axes, norm) diff --git a/numpy/fft/fftpack_litemodule.c b/numpy/fft/fftpack_litemodule.c new file mode 100644 index 0000000..dfa0d21 --- /dev/null +++ b/numpy/fft/fftpack_litemodule.c @@ -0,0 +1,363 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" +#include "numpy/arrayobject.h" +#include "fftpack.h" + +static PyObject *ErrorObject; + +static const char fftpack_cfftf__doc__[] = ""; + +static PyObject * +fftpack_cfftf(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyObject *op1, *op2; + PyArrayObject *data; + PyArray_Descr *descr; + double *wsave, *dptr; + npy_intp nsave; + int npts, nrepeats, i; + + if(!PyArg_ParseTuple(args, "OO:cfftf", &op1, &op2)) { + return NULL; + } + data = (PyArrayObject *)PyArray_CopyFromObject(op1, + NPY_CDOUBLE, 1, 0); + if (data == NULL) { + return NULL; + } + descr = PyArray_DescrFromType(NPY_DOUBLE); + if (PyArray_AsCArray(&op2, (void *)&wsave, &nsave, 1, descr) == -1) { + goto fail; + } + if (data == NULL) { + goto fail; + } + + npts = PyArray_DIM(data, PyArray_NDIM(data) - 1); + if (nsave != npts*4 + 15) { + PyErr_SetString(ErrorObject, "invalid work array for fft size"); + goto fail; + } + + nrepeats = PyArray_SIZE(data)/npts; + dptr = (double *)PyArray_DATA(data); + Py_BEGIN_ALLOW_THREADS; + NPY_SIGINT_ON; + for (i = 0; i < nrepeats; i++) { + npy_cfftf(npts, dptr, wsave); + dptr += npts*2; + } + NPY_SIGINT_OFF; + Py_END_ALLOW_THREADS; + PyArray_Free(op2, (char *)wsave); + return (PyObject *)data; + +fail: + PyArray_Free(op2, (char *)wsave); + Py_DECREF(data); + return NULL; +} + +static const char fftpack_cfftb__doc__[] = ""; + +static PyObject * +fftpack_cfftb(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyObject *op1, *op2; + PyArrayObject *data; + PyArray_Descr *descr; + double *wsave, *dptr; + npy_intp nsave; + int npts, nrepeats, i; + + if(!PyArg_ParseTuple(args, "OO:cfftb", &op1, &op2)) { + return NULL; + } + data = (PyArrayObject *)PyArray_CopyFromObject(op1, + NPY_CDOUBLE, 1, 0); + if (data == NULL) { + return NULL; + } + descr = PyArray_DescrFromType(NPY_DOUBLE); + if (PyArray_AsCArray(&op2, (void *)&wsave, &nsave, 1, descr) == -1) { + goto fail; + } + if (data == NULL) { + goto fail; + } + + npts = PyArray_DIM(data, PyArray_NDIM(data) - 1); + if (nsave != npts*4 + 15) { + PyErr_SetString(ErrorObject, "invalid work array for fft size"); + goto fail; + } + + nrepeats = PyArray_SIZE(data)/npts; + dptr = (double *)PyArray_DATA(data); + Py_BEGIN_ALLOW_THREADS; + NPY_SIGINT_ON; + for (i = 0; i < nrepeats; i++) { + npy_cfftb(npts, dptr, wsave); + dptr += npts*2; + } + NPY_SIGINT_OFF; + Py_END_ALLOW_THREADS; + PyArray_Free(op2, (char *)wsave); + return (PyObject *)data; + +fail: + PyArray_Free(op2, (char *)wsave); + Py_DECREF(data); + return NULL; +} + +static const char fftpack_cffti__doc__[] = ""; + +static PyObject * +fftpack_cffti(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyArrayObject *op; + npy_intp dim; + long n; + + if (!PyArg_ParseTuple(args, "l:cffti", &n)) { + return NULL; + } + /*Magic size needed by npy_cffti*/ + dim = 4*n + 15; + /*Create a 1 dimensional array of dimensions of type double*/ + op = (PyArrayObject *)PyArray_SimpleNew(1, &dim, NPY_DOUBLE); + if (op == NULL) { + return NULL; + } + + Py_BEGIN_ALLOW_THREADS; + NPY_SIGINT_ON; + npy_cffti(n, (double *)PyArray_DATA((PyArrayObject*)op)); + NPY_SIGINT_OFF; + Py_END_ALLOW_THREADS; + + return (PyObject *)op; +} + +static const char fftpack_rfftf__doc__[] = ""; + +static PyObject * +fftpack_rfftf(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyObject *op1, *op2; + PyArrayObject *data, *ret; + PyArray_Descr *descr; + double *wsave = NULL, *dptr, *rptr; + npy_intp nsave; + int npts, nrepeats, i, rstep; + + if(!PyArg_ParseTuple(args, "OO:rfftf", &op1, &op2)) { + return NULL; + } + data = (PyArrayObject *)PyArray_ContiguousFromObject(op1, + NPY_DOUBLE, 1, 0); + if (data == NULL) { + return NULL; + } + /* FIXME, direct access changing contents of data->dimensions */ + npts = PyArray_DIM(data, PyArray_NDIM(data) - 1); + PyArray_DIMS(data)[PyArray_NDIM(data) - 1] = npts/2 + 1; + ret = (PyArrayObject *)PyArray_Zeros(PyArray_NDIM(data), + PyArray_DIMS(data), PyArray_DescrFromType(NPY_CDOUBLE), 0); + if (ret == NULL) { + goto fail; + } + PyArray_DIMS(data)[PyArray_NDIM(data) - 1] = npts; + rstep = PyArray_DIM(ret, PyArray_NDIM(ret) - 1)*2; + + descr = PyArray_DescrFromType(NPY_DOUBLE); + if (PyArray_AsCArray(&op2, (void *)&wsave, &nsave, 1, descr) == -1) { + goto fail; + } + if (data == NULL || ret == NULL) { + goto fail; + } + if (nsave != npts*2+15) { + PyErr_SetString(ErrorObject, "invalid work array for fft size"); + goto fail; + } + + nrepeats = PyArray_SIZE(data)/npts; + rptr = (double *)PyArray_DATA(ret); + dptr = (double *)PyArray_DATA(data); + + Py_BEGIN_ALLOW_THREADS; + NPY_SIGINT_ON; + for (i = 0; i < nrepeats; i++) { + memcpy((char *)(rptr+1), dptr, npts*sizeof(double)); + npy_rfftf(npts, rptr+1, wsave); + rptr[0] = rptr[1]; + rptr[1] = 0.0; + rptr += rstep; + dptr += npts; + } + NPY_SIGINT_OFF; + Py_END_ALLOW_THREADS; + PyArray_Free(op2, (char *)wsave); + Py_DECREF(data); + return (PyObject *)ret; + +fail: + PyArray_Free(op2, (char *)wsave); + Py_XDECREF(data); + Py_XDECREF(ret); + return NULL; +} + +static const char fftpack_rfftb__doc__[] = ""; + +static PyObject * +fftpack_rfftb(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyObject *op1, *op2; + PyArrayObject *data, *ret; + PyArray_Descr *descr; + double *wsave, *dptr, *rptr; + npy_intp nsave; + int npts, nrepeats, i; + + if(!PyArg_ParseTuple(args, "OO:rfftb", &op1, &op2)) { + return NULL; + } + data = (PyArrayObject *)PyArray_ContiguousFromObject(op1, + NPY_CDOUBLE, 1, 0); + if (data == NULL) { + return NULL; + } + npts = PyArray_DIM(data, PyArray_NDIM(data) - 1); + ret = (PyArrayObject *)PyArray_Zeros(PyArray_NDIM(data), PyArray_DIMS(data), + PyArray_DescrFromType(NPY_DOUBLE), 0); + + descr = PyArray_DescrFromType(NPY_DOUBLE); + if (PyArray_AsCArray(&op2, (void *)&wsave, &nsave, 1, descr) == -1) { + goto fail; + } + if (data == NULL || ret == NULL) { + goto fail; + } + if (nsave != npts*2 + 15) { + PyErr_SetString(ErrorObject, "invalid work array for fft size"); + goto fail; + } + + nrepeats = PyArray_SIZE(ret)/npts; + rptr = (double *)PyArray_DATA(ret); + dptr = (double *)PyArray_DATA(data); + + Py_BEGIN_ALLOW_THREADS; + NPY_SIGINT_ON; + for (i = 0; i < nrepeats; i++) { + memcpy((char *)(rptr + 1), (dptr + 2), (npts - 1)*sizeof(double)); + rptr[0] = dptr[0]; + npy_rfftb(npts, rptr, wsave); + rptr += npts; + dptr += npts*2; + } + NPY_SIGINT_OFF; + Py_END_ALLOW_THREADS; + PyArray_Free(op2, (char *)wsave); + Py_DECREF(data); + return (PyObject *)ret; + +fail: + PyArray_Free(op2, (char *)wsave); + Py_XDECREF(data); + Py_XDECREF(ret); + return NULL; +} + +static const char fftpack_rffti__doc__[] = ""; + +static PyObject * +fftpack_rffti(PyObject *NPY_UNUSED(self), PyObject *args) +{ + PyArrayObject *op; + npy_intp dim; + long n; + + if (!PyArg_ParseTuple(args, "l:rffti", &n)) { + return NULL; + } + /*Magic size needed by npy_rffti*/ + dim = 2*n + 15; + /*Create a 1 dimensional array of dimensions of type double*/ + op = (PyArrayObject *)PyArray_SimpleNew(1, &dim, NPY_DOUBLE); + if (op == NULL) { + return NULL; + } + Py_BEGIN_ALLOW_THREADS; + NPY_SIGINT_ON; + npy_rffti(n, (double *)PyArray_DATA((PyArrayObject*)op)); + NPY_SIGINT_OFF; + Py_END_ALLOW_THREADS; + + return (PyObject *)op; +} + + +/* List of methods defined in the module */ + +static struct PyMethodDef fftpack_methods[] = { + {"cfftf", fftpack_cfftf, 1, fftpack_cfftf__doc__}, + {"cfftb", fftpack_cfftb, 1, fftpack_cfftb__doc__}, + {"cffti", fftpack_cffti, 1, fftpack_cffti__doc__}, + {"rfftf", fftpack_rfftf, 1, fftpack_rfftf__doc__}, + {"rfftb", fftpack_rfftb, 1, fftpack_rfftb__doc__}, + {"rffti", fftpack_rffti, 1, fftpack_rffti__doc__}, + {NULL, NULL, 0, NULL} /* sentinel */ +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "fftpack_lite", + NULL, + -1, + fftpack_methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +/* Initialization function for the module */ +#if PY_MAJOR_VERSION >= 3 +#define RETVAL m +PyMODINIT_FUNC PyInit_fftpack_lite(void) +#else +#define RETVAL +PyMODINIT_FUNC +initfftpack_lite(void) +#endif +{ + PyObject *m,*d; +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); +#else + static const char fftpack_module_documentation[] = ""; + + m = Py_InitModule4("fftpack_lite", fftpack_methods, + fftpack_module_documentation, + (PyObject*)NULL,PYTHON_API_VERSION); +#endif + + /* Import the array object */ + import_array(); + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + ErrorObject = PyErr_NewException("fftpack.error", NULL, NULL); + PyDict_SetItemString(d, "error", ErrorObject); + + /* XXXX Add constants here */ + + return RETVAL; +} diff --git a/numpy/fft/helper.py b/numpy/fft/helper.py new file mode 100644 index 0000000..0856d67 --- /dev/null +++ b/numpy/fft/helper.py @@ -0,0 +1,323 @@ +""" +Discrete Fourier Transforms - helper.py + +""" +from __future__ import division, absolute_import, print_function + +import collections +import threading + +from numpy.compat import integer_types +from numpy.core import ( + asarray, concatenate, arange, take, integer, empty + ) + +# Created by Pearu Peterson, September 2002 + +__all__ = ['fftshift', 'ifftshift', 'fftfreq', 'rfftfreq'] + +integer_types = integer_types + (integer,) + + +def fftshift(x, axes=None): + """ + Shift the zero-frequency component to the center of the spectrum. + + This function swaps half-spaces for all axes listed (defaults to all). + Note that ``y[0]`` is the Nyquist component only if ``len(x)`` is even. + + Parameters + ---------- + x : array_like + Input array. + axes : int or shape tuple, optional + Axes over which to shift. Default is None, which shifts all axes. + + Returns + ------- + y : ndarray + The shifted array. + + See Also + -------- + ifftshift : The inverse of `fftshift`. + + Examples + -------- + >>> freqs = np.fft.fftfreq(10, 0.1) + >>> freqs + array([ 0., 1., 2., 3., 4., -5., -4., -3., -2., -1.]) + >>> np.fft.fftshift(freqs) + array([-5., -4., -3., -2., -1., 0., 1., 2., 3., 4.]) + + Shift the zero-frequency component only along the second axis: + + >>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3) + >>> freqs + array([[ 0., 1., 2.], + [ 3., 4., -4.], + [-3., -2., -1.]]) + >>> np.fft.fftshift(freqs, axes=(1,)) + array([[ 2., 0., 1.], + [-4., 3., 4.], + [-1., -3., -2.]]) + + """ + tmp = asarray(x) + ndim = tmp.ndim + if axes is None: + axes = list(range(ndim)) + elif isinstance(axes, integer_types): + axes = (axes,) + y = tmp + for k in axes: + n = tmp.shape[k] + p2 = (n+1)//2 + mylist = concatenate((arange(p2, n), arange(p2))) + y = take(y, mylist, k) + return y + + +def ifftshift(x, axes=None): + """ + The inverse of `fftshift`. Although identical for even-length `x`, the + functions differ by one sample for odd-length `x`. + + Parameters + ---------- + x : array_like + Input array. + axes : int or shape tuple, optional + Axes over which to calculate. Defaults to None, which shifts all axes. + + Returns + ------- + y : ndarray + The shifted array. + + See Also + -------- + fftshift : Shift zero-frequency component to the center of the spectrum. + + Examples + -------- + >>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3) + >>> freqs + array([[ 0., 1., 2.], + [ 3., 4., -4.], + [-3., -2., -1.]]) + >>> np.fft.ifftshift(np.fft.fftshift(freqs)) + array([[ 0., 1., 2.], + [ 3., 4., -4.], + [-3., -2., -1.]]) + + """ + tmp = asarray(x) + ndim = tmp.ndim + if axes is None: + axes = list(range(ndim)) + elif isinstance(axes, integer_types): + axes = (axes,) + y = tmp + for k in axes: + n = tmp.shape[k] + p2 = n-(n+1)//2 + mylist = concatenate((arange(p2, n), arange(p2))) + y = take(y, mylist, k) + return y + + +def fftfreq(n, d=1.0): + """ + Return the Discrete Fourier Transform sample frequencies. + + The returned float array `f` contains the frequency bin centers in cycles + per unit of the sample spacing (with zero at the start). For instance, if + the sample spacing is in seconds, then the frequency unit is cycles/second. + + Given a window length `n` and a sample spacing `d`:: + + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd + + Parameters + ---------- + n : int + Window length. + d : scalar, optional + Sample spacing (inverse of the sampling rate). Defaults to 1. + + Returns + ------- + f : ndarray + Array of length `n` containing the sample frequencies. + + Examples + -------- + >>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5], dtype=float) + >>> fourier = np.fft.fft(signal) + >>> n = signal.size + >>> timestep = 0.1 + >>> freq = np.fft.fftfreq(n, d=timestep) + >>> freq + array([ 0. , 1.25, 2.5 , 3.75, -5. , -3.75, -2.5 , -1.25]) + + """ + if not isinstance(n, integer_types): + raise ValueError("n should be an integer") + val = 1.0 / (n * d) + results = empty(n, int) + N = (n-1)//2 + 1 + p1 = arange(0, N, dtype=int) + results[:N] = p1 + p2 = arange(-(n//2), 0, dtype=int) + results[N:] = p2 + return results * val + #return hstack((arange(0,(n-1)/2 + 1), arange(-(n/2),0))) / (n*d) + + +def rfftfreq(n, d=1.0): + """ + Return the Discrete Fourier Transform sample frequencies + (for usage with rfft, irfft). + + The returned float array `f` contains the frequency bin centers in cycles + per unit of the sample spacing (with zero at the start). For instance, if + the sample spacing is in seconds, then the frequency unit is cycles/second. + + Given a window length `n` and a sample spacing `d`:: + + f = [0, 1, ..., n/2-1, n/2] / (d*n) if n is even + f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) if n is odd + + Unlike `fftfreq` (but like `scipy.fftpack.rfftfreq`) + the Nyquist frequency component is considered to be positive. + + Parameters + ---------- + n : int + Window length. + d : scalar, optional + Sample spacing (inverse of the sampling rate). Defaults to 1. + + Returns + ------- + f : ndarray + Array of length ``n//2 + 1`` containing the sample frequencies. + + Examples + -------- + >>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5, -3, 4], dtype=float) + >>> fourier = np.fft.rfft(signal) + >>> n = signal.size + >>> sample_rate = 100 + >>> freq = np.fft.fftfreq(n, d=1./sample_rate) + >>> freq + array([ 0., 10., 20., 30., 40., -50., -40., -30., -20., -10.]) + >>> freq = np.fft.rfftfreq(n, d=1./sample_rate) + >>> freq + array([ 0., 10., 20., 30., 40., 50.]) + + """ + if not isinstance(n, integer_types): + raise ValueError("n should be an integer") + val = 1.0/(n*d) + N = n//2 + 1 + results = arange(0, N, dtype=int) + return results * val + + +class _FFTCache(object): + """ + Cache for the FFT twiddle factors as an LRU (least recently used) cache. + + Parameters + ---------- + max_size_in_mb : int + Maximum memory usage of the cache before items are being evicted. + max_item_count : int + Maximum item count of the cache before items are being evicted. + + Notes + ----- + Items will be evicted if either limit has been reached upon getting and + setting. The maximum memory usages is not strictly the given + ``max_size_in_mb`` but rather + ``max(max_size_in_mb, 1.5 * size_of_largest_item)``. Thus the cache will + never be completely cleared - at least one item will remain and a single + large item can cause the cache to retain several smaller items even if the + given maximum cache size has been exceeded. + """ + def __init__(self, max_size_in_mb, max_item_count): + self._max_size_in_bytes = max_size_in_mb * 1024 ** 2 + self._max_item_count = max_item_count + self._dict = collections.OrderedDict() + self._lock = threading.Lock() + + def put_twiddle_factors(self, n, factors): + """ + Store twiddle factors for an FFT of length n in the cache. + + Putting multiple twiddle factors for a certain n will store it multiple + times. + + Parameters + ---------- + n : int + Data length for the FFT. + factors : ndarray + The actual twiddle values. + """ + with self._lock: + # Pop + later add to move it to the end for LRU behavior. + # Internally everything is stored in a dictionary whose values are + # lists. + try: + value = self._dict.pop(n) + except KeyError: + value = [] + value.append(factors) + self._dict[n] = value + self._prune_cache() + + def pop_twiddle_factors(self, n): + """ + Pop twiddle factors for an FFT of length n from the cache. + + Will return None if the requested twiddle factors are not available in + the cache. + + Parameters + ---------- + n : int + Data length for the FFT. + + Returns + ------- + out : ndarray or None + The retrieved twiddle factors if available, else None. + """ + with self._lock: + if n not in self._dict or not self._dict[n]: + return None + # Pop + later add to move it to the end for LRU behavior. + all_values = self._dict.pop(n) + value = all_values.pop() + # Only put pack if there are still some arrays left in the list. + if all_values: + self._dict[n] = all_values + return value + + def _prune_cache(self): + # Always keep at least one item. + while len(self._dict) > 1 and ( + len(self._dict) > self._max_item_count or self._check_size()): + self._dict.popitem(last=False) + + def _check_size(self): + item_sizes = [sum(_j.nbytes for _j in _i) + for _i in self._dict.values() if _i] + if not item_sizes: + return False + max_size = max(self._max_size_in_bytes, 1.5 * max(item_sizes)) + return sum(item_sizes) > max_size diff --git a/numpy/fft/info.py b/numpy/fft/info.py new file mode 100644 index 0000000..cb6526b --- /dev/null +++ b/numpy/fft/info.py @@ -0,0 +1,187 @@ +""" +Discrete Fourier Transform (:mod:`numpy.fft`) +============================================= + +.. currentmodule:: numpy.fft + +Standard FFTs +------------- + +.. autosummary:: + :toctree: generated/ + + fft Discrete Fourier transform. + ifft Inverse discrete Fourier transform. + fft2 Discrete Fourier transform in two dimensions. + ifft2 Inverse discrete Fourier transform in two dimensions. + fftn Discrete Fourier transform in N-dimensions. + ifftn Inverse discrete Fourier transform in N dimensions. + +Real FFTs +--------- + +.. autosummary:: + :toctree: generated/ + + rfft Real discrete Fourier transform. + irfft Inverse real discrete Fourier transform. + rfft2 Real discrete Fourier transform in two dimensions. + irfft2 Inverse real discrete Fourier transform in two dimensions. + rfftn Real discrete Fourier transform in N dimensions. + irfftn Inverse real discrete Fourier transform in N dimensions. + +Hermitian FFTs +-------------- + +.. autosummary:: + :toctree: generated/ + + hfft Hermitian discrete Fourier transform. + ihfft Inverse Hermitian discrete Fourier transform. + +Helper routines +--------------- + +.. autosummary:: + :toctree: generated/ + + fftfreq Discrete Fourier Transform sample frequencies. + rfftfreq DFT sample frequencies (for usage with rfft, irfft). + fftshift Shift zero-frequency component to center of spectrum. + ifftshift Inverse of fftshift. + + +Background information +---------------------- + +Fourier analysis is fundamentally a method for expressing a function as a +sum of periodic components, and for recovering the function from those +components. When both the function and its Fourier transform are +replaced with discretized counterparts, it is called the discrete Fourier +transform (DFT). The DFT has become a mainstay of numerical computing in +part because of a very fast algorithm for computing it, called the Fast +Fourier Transform (FFT), which was known to Gauss (1805) and was brought +to light in its current form by Cooley and Tukey [CT]_. Press et al. [NR]_ +provide an accessible introduction to Fourier analysis and its +applications. + +Because the discrete Fourier transform separates its input into +components that contribute at discrete frequencies, it has a great number +of applications in digital signal processing, e.g., for filtering, and in +this context the discretized input to the transform is customarily +referred to as a *signal*, which exists in the *time domain*. The output +is called a *spectrum* or *transform* and exists in the *frequency +domain*. + +Implementation details +---------------------- + +There are many ways to define the DFT, varying in the sign of the +exponent, normalization, etc. In this implementation, the DFT is defined +as + +.. math:: + A_k = \\sum_{m=0}^{n-1} a_m \\exp\\left\\{-2\\pi i{mk \\over n}\\right\\} + \\qquad k = 0,\\ldots,n-1. + +The DFT is in general defined for complex inputs and outputs, and a +single-frequency component at linear frequency :math:`f` is +represented by a complex exponential +:math:`a_m = \\exp\\{2\\pi i\\,f m\\Delta t\\}`, where :math:`\\Delta t` +is the sampling interval. + +The values in the result follow so-called "standard" order: If ``A = +fft(a, n)``, then ``A[0]`` contains the zero-frequency term (the sum of +the signal), which is always purely real for real inputs. Then ``A[1:n/2]`` +contains the positive-frequency terms, and ``A[n/2+1:]`` contains the +negative-frequency terms, in order of decreasingly negative frequency. +For an even number of input points, ``A[n/2]`` represents both positive and +negative Nyquist frequency, and is also purely real for real input. For +an odd number of input points, ``A[(n-1)/2]`` contains the largest positive +frequency, while ``A[(n+1)/2]`` contains the largest negative frequency. +The routine ``np.fft.fftfreq(n)`` returns an array giving the frequencies +of corresponding elements in the output. The routine +``np.fft.fftshift(A)`` shifts transforms and their frequencies to put the +zero-frequency components in the middle, and ``np.fft.ifftshift(A)`` undoes +that shift. + +When the input `a` is a time-domain signal and ``A = fft(a)``, ``np.abs(A)`` +is its amplitude spectrum and ``np.abs(A)**2`` is its power spectrum. +The phase spectrum is obtained by ``np.angle(A)``. + +The inverse DFT is defined as + +.. math:: + a_m = \\frac{1}{n}\\sum_{k=0}^{n-1}A_k\\exp\\left\\{2\\pi i{mk\\over n}\\right\\} + \\qquad m = 0,\\ldots,n-1. + +It differs from the forward transform by the sign of the exponential +argument and the default normalization by :math:`1/n`. + +Normalization +------------- +The default normalization has the direct transforms unscaled and the inverse +transforms are scaled by :math:`1/n`. It is possible to obtain unitary +transforms by setting the keyword argument ``norm`` to ``"ortho"`` (default is +`None`) so that both direct and inverse transforms will be scaled by +:math:`1/\\sqrt{n}`. + +Real and Hermitian transforms +----------------------------- + +When the input is purely real, its transform is Hermitian, i.e., the +component at frequency :math:`f_k` is the complex conjugate of the +component at frequency :math:`-f_k`, which means that for real +inputs there is no information in the negative frequency components that +is not already available from the positive frequency components. +The family of `rfft` functions is +designed to operate on real inputs, and exploits this symmetry by +computing only the positive frequency components, up to and including the +Nyquist frequency. Thus, ``n`` input points produce ``n/2+1`` complex +output points. The inverses of this family assumes the same symmetry of +its input, and for an output of ``n`` points uses ``n/2+1`` input points. + +Correspondingly, when the spectrum is purely real, the signal is +Hermitian. The `hfft` family of functions exploits this symmetry by +using ``n/2+1`` complex points in the input (time) domain for ``n`` real +points in the frequency domain. + +In higher dimensions, FFTs are used, e.g., for image analysis and +filtering. The computational efficiency of the FFT means that it can +also be a faster way to compute large convolutions, using the property +that a convolution in the time domain is equivalent to a point-by-point +multiplication in the frequency domain. + +Higher dimensions +----------------- + +In two dimensions, the DFT is defined as + +.. math:: + A_{kl} = \\sum_{m=0}^{M-1} \\sum_{n=0}^{N-1} + a_{mn}\\exp\\left\\{-2\\pi i \\left({mk\\over M}+{nl\\over N}\\right)\\right\\} + \\qquad k = 0, \\ldots, M-1;\\quad l = 0, \\ldots, N-1, + +which extends in the obvious way to higher dimensions, and the inverses +in higher dimensions also extend in the same way. + +References +---------- + +.. [CT] Cooley, James W., and John W. Tukey, 1965, "An algorithm for the + machine calculation of complex Fourier series," *Math. Comput.* + 19: 297-301. + +.. [NR] Press, W., Teukolsky, S., Vetterline, W.T., and Flannery, B.P., + 2007, *Numerical Recipes: The Art of Scientific Computing*, ch. + 12-13. Cambridge Univ. Press, Cambridge, UK. + +Examples +-------- + +For examples, see the various functions. + +""" +from __future__ import division, absolute_import, print_function + +depends = ['core'] diff --git a/numpy/fft/setup.py b/numpy/fft/setup.py new file mode 100644 index 0000000..cd99a82 --- /dev/null +++ b/numpy/fft/setup.py @@ -0,0 +1,19 @@ +from __future__ import division, print_function + + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('fft', parent_package, top_path) + + config.add_data_dir('tests') + + # Configure fftpack_lite + config.add_extension('fftpack_lite', + sources=['fftpack_litemodule.c', 'fftpack.c'] + ) + + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/fft/tests/__init__.py b/numpy/fft/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/fft/tests/__init__.py diff --git a/numpy/fft/tests/test_fftpack.py b/numpy/fft/tests/test_fftpack.py new file mode 100644 index 0000000..7ac0488 --- /dev/null +++ b/numpy/fft/tests/test_fftpack.py @@ -0,0 +1,190 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.random import random +from numpy.testing import ( + run_module_suite, assert_array_almost_equal, assert_array_equal, + assert_raises, + ) +import threading +import sys +if sys.version_info[0] >= 3: + import queue +else: + import Queue as queue + + +def fft1(x): + L = len(x) + phase = -2j*np.pi*(np.arange(L)/float(L)) + phase = np.arange(L).reshape(-1, 1) * phase + return np.sum(x*np.exp(phase), axis=1) + + +class TestFFTShift(object): + + def test_fft_n(self): + assert_raises(ValueError, np.fft.fft, [1, 2, 3], 0) + + +class TestFFT1D(object): + + def test_fft(self): + x = random(30) + 1j*random(30) + assert_array_almost_equal(fft1(x), np.fft.fft(x)) + assert_array_almost_equal(fft1(x) / np.sqrt(30), + np.fft.fft(x, norm="ortho")) + + def test_ifft(self): + x = random(30) + 1j*random(30) + assert_array_almost_equal(x, np.fft.ifft(np.fft.fft(x))) + assert_array_almost_equal( + x, np.fft.ifft(np.fft.fft(x, norm="ortho"), norm="ortho")) + + def test_fft2(self): + x = random((30, 20)) + 1j*random((30, 20)) + assert_array_almost_equal(np.fft.fft(np.fft.fft(x, axis=1), axis=0), + np.fft.fft2(x)) + assert_array_almost_equal(np.fft.fft2(x) / np.sqrt(30 * 20), + np.fft.fft2(x, norm="ortho")) + + def test_ifft2(self): + x = random((30, 20)) + 1j*random((30, 20)) + assert_array_almost_equal(np.fft.ifft(np.fft.ifft(x, axis=1), axis=0), + np.fft.ifft2(x)) + assert_array_almost_equal(np.fft.ifft2(x) * np.sqrt(30 * 20), + np.fft.ifft2(x, norm="ortho")) + + def test_fftn(self): + x = random((30, 20, 10)) + 1j*random((30, 20, 10)) + assert_array_almost_equal( + np.fft.fft(np.fft.fft(np.fft.fft(x, axis=2), axis=1), axis=0), + np.fft.fftn(x)) + assert_array_almost_equal(np.fft.fftn(x) / np.sqrt(30 * 20 * 10), + np.fft.fftn(x, norm="ortho")) + + def test_ifftn(self): + x = random((30, 20, 10)) + 1j*random((30, 20, 10)) + assert_array_almost_equal( + np.fft.ifft(np.fft.ifft(np.fft.ifft(x, axis=2), axis=1), axis=0), + np.fft.ifftn(x)) + assert_array_almost_equal(np.fft.ifftn(x) * np.sqrt(30 * 20 * 10), + np.fft.ifftn(x, norm="ortho")) + + def test_rfft(self): + x = random(30) + for n in [x.size, 2*x.size]: + for norm in [None, 'ortho']: + assert_array_almost_equal( + np.fft.fft(x, n=n, norm=norm)[:(n//2 + 1)], + np.fft.rfft(x, n=n, norm=norm)) + assert_array_almost_equal(np.fft.rfft(x, n=n) / np.sqrt(n), + np.fft.rfft(x, n=n, norm="ortho")) + + def test_irfft(self): + x = random(30) + assert_array_almost_equal(x, np.fft.irfft(np.fft.rfft(x))) + assert_array_almost_equal( + x, np.fft.irfft(np.fft.rfft(x, norm="ortho"), norm="ortho")) + + def test_rfft2(self): + x = random((30, 20)) + assert_array_almost_equal(np.fft.fft2(x)[:, :11], np.fft.rfft2(x)) + assert_array_almost_equal(np.fft.rfft2(x) / np.sqrt(30 * 20), + np.fft.rfft2(x, norm="ortho")) + + def test_irfft2(self): + x = random((30, 20)) + assert_array_almost_equal(x, np.fft.irfft2(np.fft.rfft2(x))) + assert_array_almost_equal( + x, np.fft.irfft2(np.fft.rfft2(x, norm="ortho"), norm="ortho")) + + def test_rfftn(self): + x = random((30, 20, 10)) + assert_array_almost_equal(np.fft.fftn(x)[:, :, :6], np.fft.rfftn(x)) + assert_array_almost_equal(np.fft.rfftn(x) / np.sqrt(30 * 20 * 10), + np.fft.rfftn(x, norm="ortho")) + + def test_irfftn(self): + x = random((30, 20, 10)) + assert_array_almost_equal(x, np.fft.irfftn(np.fft.rfftn(x))) + assert_array_almost_equal( + x, np.fft.irfftn(np.fft.rfftn(x, norm="ortho"), norm="ortho")) + + def test_hfft(self): + x = random(14) + 1j*random(14) + x_herm = np.concatenate((random(1), x, random(1))) + x = np.concatenate((x_herm, x[::-1].conj())) + assert_array_almost_equal(np.fft.fft(x), np.fft.hfft(x_herm)) + assert_array_almost_equal(np.fft.hfft(x_herm) / np.sqrt(30), + np.fft.hfft(x_herm, norm="ortho")) + + def test_ihttf(self): + x = random(14) + 1j*random(14) + x_herm = np.concatenate((random(1), x, random(1))) + x = np.concatenate((x_herm, x[::-1].conj())) + assert_array_almost_equal(x_herm, np.fft.ihfft(np.fft.hfft(x_herm))) + assert_array_almost_equal( + x_herm, np.fft.ihfft(np.fft.hfft(x_herm, norm="ortho"), + norm="ortho")) + + def test_all_1d_norm_preserving(self): + # verify that round-trip transforms are norm-preserving + x = random(30) + x_norm = np.linalg.norm(x) + n = x.size * 2 + func_pairs = [(np.fft.fft, np.fft.ifft), + (np.fft.rfft, np.fft.irfft), + # hfft: order so the first function takes x.size samples + # (necessary for comparison to x_norm above) + (np.fft.ihfft, np.fft.hfft), + ] + for forw, back in func_pairs: + for n in [x.size, 2*x.size]: + for norm in [None, 'ortho']: + tmp = forw(x, n=n, norm=norm) + tmp = back(tmp, n=n, norm=norm) + assert_array_almost_equal(x_norm, + np.linalg.norm(tmp)) + +class TestFFTThreadSafe(object): + threads = 16 + input_shape = (800, 200) + + def _test_mtsame(self, func, *args): + def worker(args, q): + q.put(func(*args)) + + q = queue.Queue() + expected = func(*args) + + # Spin off a bunch of threads to call the same function simultaneously + t = [threading.Thread(target=worker, args=(args, q)) + for i in range(self.threads)] + [x.start() for x in t] + + [x.join() for x in t] + # Make sure all threads returned the correct value + for i in range(self.threads): + assert_array_equal(q.get(timeout=5), expected, + 'Function returned wrong value in multithreaded context') + + def test_fft(self): + a = np.ones(self.input_shape) * 1+0j + self._test_mtsame(np.fft.fft, a) + + def test_ifft(self): + a = np.ones(self.input_shape) * 1+0j + self._test_mtsame(np.fft.ifft, a) + + def test_rfft(self): + a = np.ones(self.input_shape) + self._test_mtsame(np.fft.rfft, a) + + def test_irfft(self): + a = np.ones(self.input_shape) * 1+0j + self._test_mtsame(np.fft.irfft, a) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/fft/tests/test_helper.py b/numpy/fft/tests/test_helper.py new file mode 100644 index 0000000..f02edf7 --- /dev/null +++ b/numpy/fft/tests/test_helper.py @@ -0,0 +1,158 @@ +"""Test functions for fftpack.helper module + +Copied from fftpack.helper by Pearu Peterson, October 2005 + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_array_almost_equal, assert_equal, + ) +from numpy import fft +from numpy import pi +from numpy.fft.helper import _FFTCache + + +class TestFFTShift(object): + + def test_definition(self): + x = [0, 1, 2, 3, 4, -4, -3, -2, -1] + y = [-4, -3, -2, -1, 0, 1, 2, 3, 4] + assert_array_almost_equal(fft.fftshift(x), y) + assert_array_almost_equal(fft.ifftshift(y), x) + x = [0, 1, 2, 3, 4, -5, -4, -3, -2, -1] + y = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4] + assert_array_almost_equal(fft.fftshift(x), y) + assert_array_almost_equal(fft.ifftshift(y), x) + + def test_inverse(self): + for n in [1, 4, 9, 100, 211]: + x = np.random.random((n,)) + assert_array_almost_equal(fft.ifftshift(fft.fftshift(x)), x) + + def test_axes_keyword(self): + freqs = [[0, 1, 2], [3, 4, -4], [-3, -2, -1]] + shifted = [[-1, -3, -2], [2, 0, 1], [-4, 3, 4]] + assert_array_almost_equal(fft.fftshift(freqs, axes=(0, 1)), shifted) + assert_array_almost_equal(fft.fftshift(freqs, axes=0), + fft.fftshift(freqs, axes=(0,))) + assert_array_almost_equal(fft.ifftshift(shifted, axes=(0, 1)), freqs) + assert_array_almost_equal(fft.ifftshift(shifted, axes=0), + fft.ifftshift(shifted, axes=(0,))) + + +class TestFFTFreq(object): + + def test_definition(self): + x = [0, 1, 2, 3, 4, -4, -3, -2, -1] + assert_array_almost_equal(9*fft.fftfreq(9), x) + assert_array_almost_equal(9*pi*fft.fftfreq(9, pi), x) + x = [0, 1, 2, 3, 4, -5, -4, -3, -2, -1] + assert_array_almost_equal(10*fft.fftfreq(10), x) + assert_array_almost_equal(10*pi*fft.fftfreq(10, pi), x) + + +class TestRFFTFreq(object): + + def test_definition(self): + x = [0, 1, 2, 3, 4] + assert_array_almost_equal(9*fft.rfftfreq(9), x) + assert_array_almost_equal(9*pi*fft.rfftfreq(9, pi), x) + x = [0, 1, 2, 3, 4, 5] + assert_array_almost_equal(10*fft.rfftfreq(10), x) + assert_array_almost_equal(10*pi*fft.rfftfreq(10, pi), x) + + +class TestIRFFTN(object): + + def test_not_last_axis_success(self): + ar, ai = np.random.random((2, 16, 8, 32)) + a = ar + 1j*ai + + axes = (-2,) + + # Should not raise error + fft.irfftn(a, axes=axes) + + +class TestFFTCache(object): + + def test_basic_behaviour(self): + c = _FFTCache(max_size_in_mb=1, max_item_count=4) + + # Put + c.put_twiddle_factors(1, np.ones(2, dtype=np.float32)) + c.put_twiddle_factors(2, np.zeros(2, dtype=np.float32)) + + # Get + assert_array_almost_equal(c.pop_twiddle_factors(1), + np.ones(2, dtype=np.float32)) + assert_array_almost_equal(c.pop_twiddle_factors(2), + np.zeros(2, dtype=np.float32)) + + # Nothing should be left. + assert_equal(len(c._dict), 0) + + # Now put everything in twice so it can be retrieved once and each will + # still have one item left. + for _ in range(2): + c.put_twiddle_factors(1, np.ones(2, dtype=np.float32)) + c.put_twiddle_factors(2, np.zeros(2, dtype=np.float32)) + assert_array_almost_equal(c.pop_twiddle_factors(1), + np.ones(2, dtype=np.float32)) + assert_array_almost_equal(c.pop_twiddle_factors(2), + np.zeros(2, dtype=np.float32)) + assert_equal(len(c._dict), 2) + + def test_automatic_pruning(self): + # That's around 2600 single precision samples. + c = _FFTCache(max_size_in_mb=0.01, max_item_count=4) + + c.put_twiddle_factors(1, np.ones(200, dtype=np.float32)) + c.put_twiddle_factors(2, np.ones(200, dtype=np.float32)) + assert_equal(list(c._dict.keys()), [1, 2]) + + # This is larger than the limit but should still be kept. + c.put_twiddle_factors(3, np.ones(3000, dtype=np.float32)) + assert_equal(list(c._dict.keys()), [1, 2, 3]) + # Add one more. + c.put_twiddle_factors(4, np.ones(3000, dtype=np.float32)) + # The other three should no longer exist. + assert_equal(list(c._dict.keys()), [4]) + + # Now test the max item count pruning. + c = _FFTCache(max_size_in_mb=0.01, max_item_count=2) + c.put_twiddle_factors(2, np.empty(2)) + c.put_twiddle_factors(1, np.empty(2)) + # Can still be accessed. + assert_equal(list(c._dict.keys()), [2, 1]) + + c.put_twiddle_factors(3, np.empty(2)) + # 1 and 3 can still be accessed - c[2] has been touched least recently + # and is thus evicted. + assert_equal(list(c._dict.keys()), [1, 3]) + + # One last test. We will add a single large item that is slightly + # bigger then the cache size. Some small items can still be added. + c = _FFTCache(max_size_in_mb=0.01, max_item_count=5) + c.put_twiddle_factors(1, np.ones(3000, dtype=np.float32)) + c.put_twiddle_factors(2, np.ones(2, dtype=np.float32)) + c.put_twiddle_factors(3, np.ones(2, dtype=np.float32)) + c.put_twiddle_factors(4, np.ones(2, dtype=np.float32)) + assert_equal(list(c._dict.keys()), [1, 2, 3, 4]) + + # One more big item. This time it is 6 smaller ones but they are + # counted as one big item. + for _ in range(6): + c.put_twiddle_factors(5, np.ones(500, dtype=np.float32)) + # '1' no longer in the cache. Rest still in the cache. + assert_equal(list(c._dict.keys()), [2, 3, 4, 5]) + + # Another big item - should now be the only item in the cache. + c.put_twiddle_factors(6, np.ones(4000, dtype=np.float32)) + assert_equal(list(c._dict.keys()), [6]) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/__init__.py b/numpy/lib/__init__.py new file mode 100644 index 0000000..d85a179 --- /dev/null +++ b/numpy/lib/__init__.py @@ -0,0 +1,49 @@ +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 . 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 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__ + +from numpy.testing import _numpy_tester +test = _numpy_tester().test +bench = _numpy_tester().bench diff --git a/numpy/lib/_datasource.py b/numpy/lib/_datasource.py new file mode 100644 index 0000000..6f1295f --- /dev/null +++ b/numpy/lib/_datasource.py @@ -0,0 +1,787 @@ +"""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 shutil +import io + +_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 + raise ValueError("bz2 text files not supported in python2") + else: + 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) + + +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') + + >>> 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 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) diff --git a/numpy/lib/_iotools.py b/numpy/lib/_iotools.py new file mode 100644 index 0000000..27143e5 --- /dev/null +++ b/numpy/lib/_iotools.py @@ -0,0 +1,949 @@ +"""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, asbytes_nested, 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): + 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 = set(['']) + 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', '>> np.lib._iotools.easy_dtype("i4, f8", defaultfmt="field_%03i") + dtype([('field_000', '>> np.lib._iotools.easy_dtype((int, float, float), names="a,b,c") + dtype([('a', '>> np.lib._iotools.easy_dtype(float, names="a,b,c") + dtype([('a', ' 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 diff --git a/numpy/lib/_version.py b/numpy/lib/_version.py new file mode 100644 index 0000000..0019c56 --- /dev/null +++ b/numpy/lib/_version.py @@ -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 diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py new file mode 100644 index 0000000..153b4af --- /dev/null +++ b/numpy/lib/arraypad.py @@ -0,0 +1,1485 @@ +""" +The arraypad module contains a group of functions to pad values onto the edges +of an n-dimensional array. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np + + +__all__ = ['pad'] + + +############################################################################### +# Private utility functions. + + +def _arange_ndarray(arr, shape, axis, reverse=False): + """ + Create an ndarray of `shape` with increments along specified `axis` + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + shape : tuple of ints + Shape of desired array. Should be equivalent to `arr.shape` except + `shape[axis]` which may have any positive value. + axis : int + Axis to increment along. + reverse : bool + If False, increment in a positive fashion from 1 to `shape[axis]`, + inclusive. If True, the bounds are the same but the order reversed. + + Returns + ------- + padarr : ndarray + Output array sized to pad `arr` along `axis`, with linear range from + 1 to `shape[axis]` along specified `axis`. + + Notes + ----- + The range is deliberately 1-indexed for this specific use case. Think of + this algorithm as broadcasting `np.arange` to a single `axis` of an + arbitrarily shaped ndarray. + + """ + initshape = tuple(1 if i != axis else shape[axis] + for (i, x) in enumerate(arr.shape)) + if not reverse: + padarr = np.arange(1, shape[axis] + 1) + else: + padarr = np.arange(shape[axis], 0, -1) + padarr = padarr.reshape(initshape) + for i, dim in enumerate(shape): + if padarr.shape[i] != dim: + padarr = padarr.repeat(dim, axis=i) + return padarr + + +def _round_ifneeded(arr, dtype): + """ + Rounds arr inplace if destination dtype is integer. + + Parameters + ---------- + arr : ndarray + Input array. + dtype : dtype + The dtype of the destination array. + + """ + if np.issubdtype(dtype, np.integer): + arr.round(out=arr) + + +def _prepend_const(arr, pad_amt, val, axis=-1): + """ + Prepend constant `val` along `axis` of `arr`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to prepend. + val : scalar + Constant value to use. For best results should be of type `arr.dtype`; + if not `arr.dtype` will be cast to `arr.dtype`. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` constant `val` prepended along `axis`. + + """ + if pad_amt == 0: + return arr + padshape = tuple(x if i != axis else pad_amt + for (i, x) in enumerate(arr.shape)) + if val == 0: + return np.concatenate((np.zeros(padshape, dtype=arr.dtype), arr), + axis=axis) + else: + return np.concatenate(((np.zeros(padshape) + val).astype(arr.dtype), + arr), axis=axis) + + +def _append_const(arr, pad_amt, val, axis=-1): + """ + Append constant `val` along `axis` of `arr`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to append. + val : scalar + Constant value to use. For best results should be of type `arr.dtype`; + if not `arr.dtype` will be cast to `arr.dtype`. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` constant `val` appended along `axis`. + + """ + if pad_amt == 0: + return arr + padshape = tuple(x if i != axis else pad_amt + for (i, x) in enumerate(arr.shape)) + if val == 0: + return np.concatenate((arr, np.zeros(padshape, dtype=arr.dtype)), + axis=axis) + else: + return np.concatenate( + (arr, (np.zeros(padshape) + val).astype(arr.dtype)), axis=axis) + + +def _prepend_edge(arr, pad_amt, axis=-1): + """ + Prepend `pad_amt` to `arr` along `axis` by extending edge values. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to prepend. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, extended by `pad_amt` edge values appended along `axis`. + + """ + if pad_amt == 0: + return arr + + edge_slice = tuple(slice(None) if i != axis else 0 + for (i, x) in enumerate(arr.shape)) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + edge_arr = arr[edge_slice].reshape(pad_singleton) + return np.concatenate((edge_arr.repeat(pad_amt, axis=axis), arr), + axis=axis) + + +def _append_edge(arr, pad_amt, axis=-1): + """ + Append `pad_amt` to `arr` along `axis` by extending edge values. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to append. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, extended by `pad_amt` edge values prepended along + `axis`. + + """ + if pad_amt == 0: + return arr + + edge_slice = tuple(slice(None) if i != axis else arr.shape[axis] - 1 + for (i, x) in enumerate(arr.shape)) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + edge_arr = arr[edge_slice].reshape(pad_singleton) + return np.concatenate((arr, edge_arr.repeat(pad_amt, axis=axis)), + axis=axis) + + +def _prepend_ramp(arr, pad_amt, end, axis=-1): + """ + Prepend linear ramp along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to prepend. + end : scalar + Constal value to use. For best results should be of type `arr.dtype`; + if not `arr.dtype` will be cast to `arr.dtype`. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values prepended along `axis`. The + prepended region ramps linearly from the edge value to `end`. + + """ + if pad_amt == 0: + return arr + + # Generate shape for final concatenated array + padshape = tuple(x if i != axis else pad_amt + for (i, x) in enumerate(arr.shape)) + + # Generate an n-dimensional array incrementing along `axis` + ramp_arr = _arange_ndarray(arr, padshape, axis, + reverse=True).astype(np.float64) + + # Appropriate slicing to extract n-dimensional edge along `axis` + edge_slice = tuple(slice(None) if i != axis else 0 + for (i, x) in enumerate(arr.shape)) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract edge, reshape to original rank, and extend along `axis` + edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis) + + # Linear ramp + slope = (end - edge_pad) / float(pad_amt) + ramp_arr = ramp_arr * slope + ramp_arr += edge_pad + _round_ifneeded(ramp_arr, arr.dtype) + + # Ramp values will most likely be float, cast them to the same type as arr + return np.concatenate((ramp_arr.astype(arr.dtype), arr), axis=axis) + + +def _append_ramp(arr, pad_amt, end, axis=-1): + """ + Append linear ramp along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to append. + end : scalar + Constal value to use. For best results should be of type `arr.dtype`; + if not `arr.dtype` will be cast to `arr.dtype`. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values appended along `axis`. The + appended region ramps linearly from the edge value to `end`. + + """ + if pad_amt == 0: + return arr + + # Generate shape for final concatenated array + padshape = tuple(x if i != axis else pad_amt + for (i, x) in enumerate(arr.shape)) + + # Generate an n-dimensional array incrementing along `axis` + ramp_arr = _arange_ndarray(arr, padshape, axis, + reverse=False).astype(np.float64) + + # Slice a chunk from the edge to calculate stats on + edge_slice = tuple(slice(None) if i != axis else -1 + for (i, x) in enumerate(arr.shape)) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract edge, reshape to original rank, and extend along `axis` + edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis) + + # Linear ramp + slope = (end - edge_pad) / float(pad_amt) + ramp_arr = ramp_arr * slope + ramp_arr += edge_pad + _round_ifneeded(ramp_arr, arr.dtype) + + # Ramp values will most likely be float, cast them to the same type as arr + return np.concatenate((arr, ramp_arr.astype(arr.dtype)), axis=axis) + + +def _prepend_max(arr, pad_amt, num, axis=-1): + """ + Prepend `pad_amt` maximum values along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to prepend. + num : int + Depth into `arr` along `axis` to calculate maximum. + Range: [1, `arr.shape[axis]`] or None (entire axis) + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values appended along `axis`. The + prepended region is the maximum of the first `num` values along + `axis`. + + """ + if pad_amt == 0: + return arr + + # Equivalent to edge padding for single value, so do that instead + if num == 1: + return _prepend_edge(arr, pad_amt, axis) + + # Use entire array if `num` is too large + if num is not None: + if num >= arr.shape[axis]: + num = None + + # Slice a chunk from the edge to calculate stats on + max_slice = tuple(slice(None) if i != axis else slice(num) + for (i, x) in enumerate(arr.shape)) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract slice, calculate max, reshape to add singleton dimension back + max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton) + + # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt` + return np.concatenate((max_chunk.repeat(pad_amt, axis=axis), arr), + axis=axis) + + +def _append_max(arr, pad_amt, num, axis=-1): + """ + Pad one `axis` of `arr` with the maximum of the last `num` elements. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to append. + num : int + Depth into `arr` along `axis` to calculate maximum. + Range: [1, `arr.shape[axis]`] or None (entire axis) + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values appended along `axis`. The + appended region is the maximum of the final `num` values along `axis`. + + """ + if pad_amt == 0: + return arr + + # Equivalent to edge padding for single value, so do that instead + if num == 1: + return _append_edge(arr, pad_amt, axis) + + # Use entire array if `num` is too large + if num is not None: + if num >= arr.shape[axis]: + num = None + + # Slice a chunk from the edge to calculate stats on + end = arr.shape[axis] - 1 + if num is not None: + max_slice = tuple( + slice(None) if i != axis else slice(end, end - num, -1) + for (i, x) in enumerate(arr.shape)) + else: + max_slice = tuple(slice(None) for x in arr.shape) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract slice, calculate max, reshape to add singleton dimension back + max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton) + + # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt` + return np.concatenate((arr, max_chunk.repeat(pad_amt, axis=axis)), + axis=axis) + + +def _prepend_mean(arr, pad_amt, num, axis=-1): + """ + Prepend `pad_amt` mean values along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to prepend. + num : int + Depth into `arr` along `axis` to calculate mean. + Range: [1, `arr.shape[axis]`] or None (entire axis) + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values prepended along `axis`. The + prepended region is the mean of the first `num` values along `axis`. + + """ + if pad_amt == 0: + return arr + + # Equivalent to edge padding for single value, so do that instead + if num == 1: + return _prepend_edge(arr, pad_amt, axis) + + # Use entire array if `num` is too large + if num is not None: + if num >= arr.shape[axis]: + num = None + + # Slice a chunk from the edge to calculate stats on + mean_slice = tuple(slice(None) if i != axis else slice(num) + for (i, x) in enumerate(arr.shape)) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract slice, calculate mean, reshape to add singleton dimension back + mean_chunk = arr[mean_slice].mean(axis).reshape(pad_singleton) + _round_ifneeded(mean_chunk, arr.dtype) + + # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt` + return np.concatenate((mean_chunk.repeat(pad_amt, axis).astype(arr.dtype), + arr), axis=axis) + + +def _append_mean(arr, pad_amt, num, axis=-1): + """ + Append `pad_amt` mean values along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to append. + num : int + Depth into `arr` along `axis` to calculate mean. + Range: [1, `arr.shape[axis]`] or None (entire axis) + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values appended along `axis`. The + appended region is the maximum of the final `num` values along `axis`. + + """ + if pad_amt == 0: + return arr + + # Equivalent to edge padding for single value, so do that instead + if num == 1: + return _append_edge(arr, pad_amt, axis) + + # Use entire array if `num` is too large + if num is not None: + if num >= arr.shape[axis]: + num = None + + # Slice a chunk from the edge to calculate stats on + end = arr.shape[axis] - 1 + if num is not None: + mean_slice = tuple( + slice(None) if i != axis else slice(end, end - num, -1) + for (i, x) in enumerate(arr.shape)) + else: + mean_slice = tuple(slice(None) for x in arr.shape) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract slice, calculate mean, reshape to add singleton dimension back + mean_chunk = arr[mean_slice].mean(axis=axis).reshape(pad_singleton) + _round_ifneeded(mean_chunk, arr.dtype) + + # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt` + return np.concatenate( + (arr, mean_chunk.repeat(pad_amt, axis).astype(arr.dtype)), axis=axis) + + +def _prepend_med(arr, pad_amt, num, axis=-1): + """ + Prepend `pad_amt` median values along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to prepend. + num : int + Depth into `arr` along `axis` to calculate median. + Range: [1, `arr.shape[axis]`] or None (entire axis) + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values prepended along `axis`. The + prepended region is the median of the first `num` values along `axis`. + + """ + if pad_amt == 0: + return arr + + # Equivalent to edge padding for single value, so do that instead + if num == 1: + return _prepend_edge(arr, pad_amt, axis) + + # Use entire array if `num` is too large + if num is not None: + if num >= arr.shape[axis]: + num = None + + # Slice a chunk from the edge to calculate stats on + med_slice = tuple(slice(None) if i != axis else slice(num) + for (i, x) in enumerate(arr.shape)) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract slice, calculate median, reshape to add singleton dimension back + med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton) + _round_ifneeded(med_chunk, arr.dtype) + + # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt` + return np.concatenate( + (med_chunk.repeat(pad_amt, axis).astype(arr.dtype), arr), axis=axis) + + +def _append_med(arr, pad_amt, num, axis=-1): + """ + Append `pad_amt` median values along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to append. + num : int + Depth into `arr` along `axis` to calculate median. + Range: [1, `arr.shape[axis]`] or None (entire axis) + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values appended along `axis`. The + appended region is the median of the final `num` values along `axis`. + + """ + if pad_amt == 0: + return arr + + # Equivalent to edge padding for single value, so do that instead + if num == 1: + return _append_edge(arr, pad_amt, axis) + + # Use entire array if `num` is too large + if num is not None: + if num >= arr.shape[axis]: + num = None + + # Slice a chunk from the edge to calculate stats on + end = arr.shape[axis] - 1 + if num is not None: + med_slice = tuple( + slice(None) if i != axis else slice(end, end - num, -1) + for (i, x) in enumerate(arr.shape)) + else: + med_slice = tuple(slice(None) for x in arr.shape) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract slice, calculate median, reshape to add singleton dimension back + med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton) + _round_ifneeded(med_chunk, arr.dtype) + + # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt` + return np.concatenate( + (arr, med_chunk.repeat(pad_amt, axis).astype(arr.dtype)), axis=axis) + + +def _prepend_min(arr, pad_amt, num, axis=-1): + """ + Prepend `pad_amt` minimum values along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to prepend. + num : int + Depth into `arr` along `axis` to calculate minimum. + Range: [1, `arr.shape[axis]`] or None (entire axis) + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values prepended along `axis`. The + prepended region is the minimum of the first `num` values along + `axis`. + + """ + if pad_amt == 0: + return arr + + # Equivalent to edge padding for single value, so do that instead + if num == 1: + return _prepend_edge(arr, pad_amt, axis) + + # Use entire array if `num` is too large + if num is not None: + if num >= arr.shape[axis]: + num = None + + # Slice a chunk from the edge to calculate stats on + min_slice = tuple(slice(None) if i != axis else slice(num) + for (i, x) in enumerate(arr.shape)) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract slice, calculate min, reshape to add singleton dimension back + min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton) + + # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt` + return np.concatenate((min_chunk.repeat(pad_amt, axis=axis), arr), + axis=axis) + + +def _append_min(arr, pad_amt, num, axis=-1): + """ + Append `pad_amt` median values along `axis`. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : int + Amount of padding to append. + num : int + Depth into `arr` along `axis` to calculate minimum. + Range: [1, `arr.shape[axis]`] or None (entire axis) + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt` values appended along `axis`. The + appended region is the minimum of the final `num` values along `axis`. + + """ + if pad_amt == 0: + return arr + + # Equivalent to edge padding for single value, so do that instead + if num == 1: + return _append_edge(arr, pad_amt, axis) + + # Use entire array if `num` is too large + if num is not None: + if num >= arr.shape[axis]: + num = None + + # Slice a chunk from the edge to calculate stats on + end = arr.shape[axis] - 1 + if num is not None: + min_slice = tuple( + slice(None) if i != axis else slice(end, end - num, -1) + for (i, x) in enumerate(arr.shape)) + else: + min_slice = tuple(slice(None) for x in arr.shape) + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + + # Extract slice, calculate min, reshape to add singleton dimension back + min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton) + + # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt` + return np.concatenate((arr, min_chunk.repeat(pad_amt, axis=axis)), + axis=axis) + + +def _pad_ref(arr, pad_amt, method, axis=-1): + """ + Pad `axis` of `arr` by reflection. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : tuple of ints, length 2 + Padding to (prepend, append) along `axis`. + method : str + Controls method of reflection; options are 'even' or 'odd'. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` + values appended along `axis`. Both regions are padded with reflected + values from the original array. + + Notes + ----- + This algorithm does not pad with repetition, i.e. the edges are not + repeated in the reflection. For that behavior, use `mode='symmetric'`. + + The modes 'reflect', 'symmetric', and 'wrap' must be padded with a + single function, lest the indexing tricks in non-integer multiples of the + original shape would violate repetition in the final iteration. + + """ + # Implicit booleanness to test for zero (or None) in any scalar type + if pad_amt[0] == 0 and pad_amt[1] == 0: + return arr + + ########################################################################## + # Prepended region + + # Slice off a reverse indexed chunk from near edge to pad `arr` before + ref_slice = tuple(slice(None) if i != axis else slice(pad_amt[0], 0, -1) + for (i, x) in enumerate(arr.shape)) + + ref_chunk1 = arr[ref_slice] + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + if pad_amt[0] == 1: + ref_chunk1 = ref_chunk1.reshape(pad_singleton) + + # Memory/computationally more expensive, only do this if `method='odd'` + if 'odd' in method and pad_amt[0] > 0: + edge_slice1 = tuple(slice(None) if i != axis else 0 + for (i, x) in enumerate(arr.shape)) + edge_chunk = arr[edge_slice1].reshape(pad_singleton) + ref_chunk1 = 2 * edge_chunk - ref_chunk1 + del edge_chunk + + ########################################################################## + # Appended region + + # Slice off a reverse indexed chunk from far edge to pad `arr` after + start = arr.shape[axis] - pad_amt[1] - 1 + end = arr.shape[axis] - 1 + ref_slice = tuple(slice(None) if i != axis else slice(start, end) + for (i, x) in enumerate(arr.shape)) + rev_idx = tuple(slice(None) if i != axis else slice(None, None, -1) + for (i, x) in enumerate(arr.shape)) + ref_chunk2 = arr[ref_slice][rev_idx] + + if pad_amt[1] == 1: + ref_chunk2 = ref_chunk2.reshape(pad_singleton) + + if 'odd' in method: + edge_slice2 = tuple(slice(None) if i != axis else -1 + for (i, x) in enumerate(arr.shape)) + edge_chunk = arr[edge_slice2].reshape(pad_singleton) + ref_chunk2 = 2 * edge_chunk - ref_chunk2 + del edge_chunk + + # Concatenate `arr` with both chunks, extending along `axis` + return np.concatenate((ref_chunk1, arr, ref_chunk2), axis=axis) + + +def _pad_sym(arr, pad_amt, method, axis=-1): + """ + Pad `axis` of `arr` by symmetry. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : tuple of ints, length 2 + Padding to (prepend, append) along `axis`. + method : str + Controls method of symmetry; options are 'even' or 'odd'. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` + values appended along `axis`. Both regions are padded with symmetric + values from the original array. + + Notes + ----- + This algorithm DOES pad with repetition, i.e. the edges are repeated. + For padding without repeated edges, use `mode='reflect'`. + + The modes 'reflect', 'symmetric', and 'wrap' must be padded with a + single function, lest the indexing tricks in non-integer multiples of the + original shape would violate repetition in the final iteration. + + """ + # Implicit booleanness to test for zero (or None) in any scalar type + if pad_amt[0] == 0 and pad_amt[1] == 0: + return arr + + ########################################################################## + # Prepended region + + # Slice off a reverse indexed chunk from near edge to pad `arr` before + sym_slice = tuple(slice(None) if i != axis else slice(0, pad_amt[0]) + for (i, x) in enumerate(arr.shape)) + rev_idx = tuple(slice(None) if i != axis else slice(None, None, -1) + for (i, x) in enumerate(arr.shape)) + sym_chunk1 = arr[sym_slice][rev_idx] + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + if pad_amt[0] == 1: + sym_chunk1 = sym_chunk1.reshape(pad_singleton) + + # Memory/computationally more expensive, only do this if `method='odd'` + if 'odd' in method and pad_amt[0] > 0: + edge_slice1 = tuple(slice(None) if i != axis else 0 + for (i, x) in enumerate(arr.shape)) + edge_chunk = arr[edge_slice1].reshape(pad_singleton) + sym_chunk1 = 2 * edge_chunk - sym_chunk1 + del edge_chunk + + ########################################################################## + # Appended region + + # Slice off a reverse indexed chunk from far edge to pad `arr` after + start = arr.shape[axis] - pad_amt[1] + end = arr.shape[axis] + sym_slice = tuple(slice(None) if i != axis else slice(start, end) + for (i, x) in enumerate(arr.shape)) + sym_chunk2 = arr[sym_slice][rev_idx] + + if pad_amt[1] == 1: + sym_chunk2 = sym_chunk2.reshape(pad_singleton) + + if 'odd' in method: + edge_slice2 = tuple(slice(None) if i != axis else -1 + for (i, x) in enumerate(arr.shape)) + edge_chunk = arr[edge_slice2].reshape(pad_singleton) + sym_chunk2 = 2 * edge_chunk - sym_chunk2 + del edge_chunk + + # Concatenate `arr` with both chunks, extending along `axis` + return np.concatenate((sym_chunk1, arr, sym_chunk2), axis=axis) + + +def _pad_wrap(arr, pad_amt, axis=-1): + """ + Pad `axis` of `arr` via wrapping. + + Parameters + ---------- + arr : ndarray + Input array of arbitrary shape. + pad_amt : tuple of ints, length 2 + Padding to (prepend, append) along `axis`. + axis : int + Axis along which to pad `arr`. + + Returns + ------- + padarr : ndarray + Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` + values appended along `axis`. Both regions are padded wrapped values + from the opposite end of `axis`. + + Notes + ----- + This method of padding is also known as 'tile' or 'tiling'. + + The modes 'reflect', 'symmetric', and 'wrap' must be padded with a + single function, lest the indexing tricks in non-integer multiples of the + original shape would violate repetition in the final iteration. + + """ + # Implicit booleanness to test for zero (or None) in any scalar type + if pad_amt[0] == 0 and pad_amt[1] == 0: + return arr + + ########################################################################## + # Prepended region + + # Slice off a reverse indexed chunk from near edge to pad `arr` before + start = arr.shape[axis] - pad_amt[0] + end = arr.shape[axis] + wrap_slice = tuple(slice(None) if i != axis else slice(start, end) + for (i, x) in enumerate(arr.shape)) + wrap_chunk1 = arr[wrap_slice] + + # Shape to restore singleton dimension after slicing + pad_singleton = tuple(x if i != axis else 1 + for (i, x) in enumerate(arr.shape)) + if pad_amt[0] == 1: + wrap_chunk1 = wrap_chunk1.reshape(pad_singleton) + + ########################################################################## + # Appended region + + # Slice off a reverse indexed chunk from far edge to pad `arr` after + wrap_slice = tuple(slice(None) if i != axis else slice(0, pad_amt[1]) + for (i, x) in enumerate(arr.shape)) + wrap_chunk2 = arr[wrap_slice] + + if pad_amt[1] == 1: + wrap_chunk2 = wrap_chunk2.reshape(pad_singleton) + + # Concatenate `arr` with both chunks, extending along `axis` + return np.concatenate((wrap_chunk1, arr, wrap_chunk2), axis=axis) + + +def _normalize_shape(ndarray, shape, cast_to_int=True): + """ + Private function which does some checks and normalizes the possibly + much simpler representations of 'pad_width', 'stat_length', + 'constant_values', 'end_values'. + + Parameters + ---------- + narray : ndarray + Input ndarray + shape : {sequence, array_like, float, int}, optional + The width of padding (pad_width), the number of elements on the + edge of the narray used for statistics (stat_length), the constant + value(s) to use when filling padded regions (constant_values), or the + endpoint target(s) for linear ramps (end_values). + ((before_1, after_1), ... (before_N, after_N)) unique number of + elements for each axis where `N` is rank of `narray`. + ((before, after),) yields same before and after constants for each + axis. + (constant,) or val is a shortcut for before = after = constant for + all axes. + cast_to_int : bool, optional + Controls if values in ``shape`` will be rounded and cast to int + before being returned. + + Returns + ------- + normalized_shape : tuple of tuples + val => ((val, val), (val, val), ...) + [[val1, val2], [val3, val4], ...] => ((val1, val2), (val3, val4), ...) + ((val1, val2), (val3, val4), ...) => no change + [[val1, val2], ] => ((val1, val2), (val1, val2), ...) + ((val1, val2), ) => ((val1, val2), (val1, val2), ...) + [[val , ], ] => ((val, val), (val, val), ...) + ((val , ), ) => ((val, val), (val, val), ...) + + """ + ndims = ndarray.ndim + + # Shortcut shape=None + if shape is None: + return ((None, None), ) * ndims + + # Convert any input `info` to a NumPy array + shape_arr = np.asarray(shape) + + try: + shape_arr = np.broadcast_to(shape_arr, (ndims, 2)) + except ValueError: + fmt = "Unable to create correctly shaped tuple from %s" + raise ValueError(fmt % (shape,)) + + # Cast if necessary + if cast_to_int is True: + shape_arr = np.round(shape_arr).astype(int) + + # Convert list of lists to tuple of tuples + return tuple(tuple(axis) for axis in shape_arr.tolist()) + + +def _validate_lengths(narray, number_elements): + """ + Private function which does some checks and reformats pad_width and + stat_length using _normalize_shape. + + Parameters + ---------- + narray : ndarray + Input ndarray + number_elements : {sequence, int}, optional + The width of padding (pad_width) or the number of elements on the edge + of the narray used for statistics (stat_length). + ((before_1, after_1), ... (before_N, after_N)) unique number of + elements for each axis. + ((before, after),) yields same before and after constants for each + axis. + (constant,) or int is a shortcut for before = after = constant for all + axes. + + Returns + ------- + _validate_lengths : tuple of tuples + int => ((int, int), (int, int), ...) + [[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...) + ((int1, int2), (int3, int4), ...) => no change + [[int1, int2], ] => ((int1, int2), (int1, int2), ...) + ((int1, int2), ) => ((int1, int2), (int1, int2), ...) + [[int , ], ] => ((int, int), (int, int), ...) + ((int , ), ) => ((int, int), (int, int), ...) + + """ + normshp = _normalize_shape(narray, number_elements) + for i in normshp: + chk = [1 if x is None else x for x in i] + chk = [1 if x >= 0 else -1 for x in chk] + if (chk[0] < 0) or (chk[1] < 0): + fmt = "%s cannot contain negative values." + raise ValueError(fmt % (number_elements,)) + return normshp + + +############################################################################### +# Public functions + + +def pad(array, pad_width, mode, **kwargs): + """ + Pads an array. + + Parameters + ---------- + array : array_like of rank N + Input array + pad_width : {sequence, array_like, int} + Number of values padded to the edges of each axis. + ((before_1, after_1), ... (before_N, after_N)) unique pad widths + for each axis. + ((before, after),) yields same before and after pad for each axis. + (pad,) or int is a shortcut for before = after = pad width for all + axes. + mode : str or function + One of the following string values or a user supplied function. + + 'constant' + Pads with a constant value. + 'edge' + Pads with the edge values of array. + 'linear_ramp' + Pads with the linear ramp between end_value and the + array edge value. + 'maximum' + Pads with the maximum value of all or part of the + vector along each axis. + 'mean' + Pads with the mean value of all or part of the + vector along each axis. + 'median' + Pads with the median value of all or part of the + vector along each axis. + 'minimum' + Pads with the minimum value of all or part of the + vector along each axis. + 'reflect' + Pads with the reflection of the vector mirrored on + the first and last values of the vector along each + axis. + 'symmetric' + Pads with the reflection of the vector mirrored + along the edge of the array. + 'wrap' + Pads with the wrap of the vector along the axis. + The first values are used to pad the end and the + end values are used to pad the beginning. + + Padding function, see Notes. + stat_length : sequence or int, optional + Used in 'maximum', 'mean', 'median', and 'minimum'. Number of + values at edge of each axis used to calculate the statistic value. + + ((before_1, after_1), ... (before_N, after_N)) unique statistic + lengths for each axis. + + ((before, after),) yields same before and after statistic lengths + for each axis. + + (stat_length,) or int is a shortcut for before = after = statistic + length for all axes. + + Default is ``None``, to use the entire axis. + constant_values : sequence or int, optional + Used in 'constant'. The values to set the padded values for each + axis. + + ((before_1, after_1), ... (before_N, after_N)) unique pad constants + for each axis. + + ((before, after),) yields same before and after constants for each + axis. + + (constant,) or int is a shortcut for before = after = constant for + all axes. + + Default is 0. + end_values : sequence or int, optional + Used in 'linear_ramp'. The values used for the ending value of the + linear_ramp and that will form the edge of the padded array. + + ((before_1, after_1), ... (before_N, after_N)) unique end values + for each axis. + + ((before, after),) yields same before and after end values for each + axis. + + (constant,) or int is a shortcut for before = after = end value for + all axes. + + Default is 0. + reflect_type : {'even', 'odd'}, optional + Used in 'reflect', and 'symmetric'. The 'even' style is the + default with an unaltered reflection around the edge value. For + the 'odd' style, the extented part of the array is created by + subtracting the reflected values from two times the edge value. + + Returns + ------- + pad : ndarray + Padded array of rank equal to `array` with shape increased + according to `pad_width`. + + Notes + ----- + .. versionadded:: 1.7.0 + + For an array with rank greater than 1, some of the padding of later + axes is calculated from padding of previous axes. This is easiest to + think about with a rank 2 array where the corners of the padded array + are calculated by using padded values from the first axis. + + The padding function, if used, should return a rank 1 array equal in + length to the vector argument with padded values replaced. It has the + following signature:: + + padding_func(vector, iaxis_pad_width, iaxis, kwargs) + + where + + vector : ndarray + A rank 1 array already padded with zeros. Padded values are + vector[:pad_tuple[0]] and vector[-pad_tuple[1]:]. + iaxis_pad_width : tuple + A 2-tuple of ints, iaxis_pad_width[0] represents the number of + values padded at the beginning of vector where + iaxis_pad_width[1] represents the number of values padded at + the end of vector. + iaxis : int + The axis currently being calculated. + kwargs : dict + Any keyword arguments the function requires. + + Examples + -------- + >>> a = [1, 2, 3, 4, 5] + >>> np.pad(a, (2,3), 'constant', constant_values=(4, 6)) + array([4, 4, 1, 2, 3, 4, 5, 6, 6, 6]) + + >>> np.pad(a, (2, 3), 'edge') + array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5]) + + >>> np.pad(a, (2, 3), 'linear_ramp', end_values=(5, -4)) + array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4]) + + >>> np.pad(a, (2,), 'maximum') + array([5, 5, 1, 2, 3, 4, 5, 5, 5]) + + >>> np.pad(a, (2,), 'mean') + array([3, 3, 1, 2, 3, 4, 5, 3, 3]) + + >>> np.pad(a, (2,), 'median') + array([3, 3, 1, 2, 3, 4, 5, 3, 3]) + + >>> a = [[1, 2], [3, 4]] + >>> np.pad(a, ((3, 2), (2, 3)), 'minimum') + array([[1, 1, 1, 2, 1, 1, 1], + [1, 1, 1, 2, 1, 1, 1], + [1, 1, 1, 2, 1, 1, 1], + [1, 1, 1, 2, 1, 1, 1], + [3, 3, 3, 4, 3, 3, 3], + [1, 1, 1, 2, 1, 1, 1], + [1, 1, 1, 2, 1, 1, 1]]) + + >>> a = [1, 2, 3, 4, 5] + >>> np.pad(a, (2, 3), 'reflect') + array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2]) + + >>> np.pad(a, (2, 3), 'reflect', reflect_type='odd') + array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]) + + >>> np.pad(a, (2, 3), 'symmetric') + array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3]) + + >>> np.pad(a, (2, 3), 'symmetric', reflect_type='odd') + array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7]) + + >>> np.pad(a, (2, 3), 'wrap') + array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3]) + + >>> def pad_with(vector, pad_width, iaxis, kwargs): + ... pad_value = kwargs.get('padder', 10) + ... vector[:pad_width[0]] = pad_value + ... vector[-pad_width[1]:] = pad_value + ... return vector + >>> a = np.arange(6) + >>> a = a.reshape((2, 3)) + >>> np.pad(a, 2, pad_with) + array([[10, 10, 10, 10, 10, 10, 10], + [10, 10, 10, 10, 10, 10, 10], + [10, 10, 0, 1, 2, 10, 10], + [10, 10, 3, 4, 5, 10, 10], + [10, 10, 10, 10, 10, 10, 10], + [10, 10, 10, 10, 10, 10, 10]]) + >>> np.pad(a, 2, pad_with, padder=100) + array([[100, 100, 100, 100, 100, 100, 100], + [100, 100, 100, 100, 100, 100, 100], + [100, 100, 0, 1, 2, 100, 100], + [100, 100, 3, 4, 5, 100, 100], + [100, 100, 100, 100, 100, 100, 100], + [100, 100, 100, 100, 100, 100, 100]]) + """ + if not np.asarray(pad_width).dtype.kind == 'i': + raise TypeError('`pad_width` must be of integral type.') + + narray = np.array(array) + pad_width = _validate_lengths(narray, pad_width) + + allowedkwargs = { + 'constant': ['constant_values'], + 'edge': [], + 'linear_ramp': ['end_values'], + 'maximum': ['stat_length'], + 'mean': ['stat_length'], + 'median': ['stat_length'], + 'minimum': ['stat_length'], + 'reflect': ['reflect_type'], + 'symmetric': ['reflect_type'], + 'wrap': [], + } + + kwdefaults = { + 'stat_length': None, + 'constant_values': 0, + 'end_values': 0, + 'reflect_type': 'even', + } + + if isinstance(mode, np.compat.basestring): + # Make sure have allowed kwargs appropriate for mode + for key in kwargs: + if key not in allowedkwargs[mode]: + raise ValueError('%s keyword not in allowed keywords %s' % + (key, allowedkwargs[mode])) + + # Set kwarg defaults + for kw in allowedkwargs[mode]: + kwargs.setdefault(kw, kwdefaults[kw]) + + # Need to only normalize particular keywords. + for i in kwargs: + if i == 'stat_length': + kwargs[i] = _validate_lengths(narray, kwargs[i]) + if i in ['end_values', 'constant_values']: + kwargs[i] = _normalize_shape(narray, kwargs[i], + cast_to_int=False) + else: + # Drop back to old, slower np.apply_along_axis mode for user-supplied + # vector function + function = mode + + # Create a new padded array + rank = list(range(narray.ndim)) + total_dim_increase = [np.sum(pad_width[i]) for i in rank] + offset_slices = [slice(pad_width[i][0], + pad_width[i][0] + narray.shape[i]) + for i in rank] + new_shape = np.array(narray.shape) + total_dim_increase + newmat = np.zeros(new_shape, narray.dtype) + + # Insert the original array into the padded array + newmat[offset_slices] = narray + + # This is the core of pad ... + for iaxis in rank: + np.apply_along_axis(function, + iaxis, + newmat, + pad_width[iaxis], + iaxis, + kwargs) + return newmat + + # If we get here, use new padding method + newmat = narray.copy() + + # API preserved, but completely new algorithm which pads by building the + # entire block to pad before/after `arr` with in one step, for each axis. + if mode == 'constant': + for axis, ((pad_before, pad_after), (before_val, after_val)) \ + in enumerate(zip(pad_width, kwargs['constant_values'])): + newmat = _prepend_const(newmat, pad_before, before_val, axis) + newmat = _append_const(newmat, pad_after, after_val, axis) + + elif mode == 'edge': + for axis, (pad_before, pad_after) in enumerate(pad_width): + newmat = _prepend_edge(newmat, pad_before, axis) + newmat = _append_edge(newmat, pad_after, axis) + + elif mode == 'linear_ramp': + for axis, ((pad_before, pad_after), (before_val, after_val)) \ + in enumerate(zip(pad_width, kwargs['end_values'])): + newmat = _prepend_ramp(newmat, pad_before, before_val, axis) + newmat = _append_ramp(newmat, pad_after, after_val, axis) + + elif mode == 'maximum': + for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ + in enumerate(zip(pad_width, kwargs['stat_length'])): + newmat = _prepend_max(newmat, pad_before, chunk_before, axis) + newmat = _append_max(newmat, pad_after, chunk_after, axis) + + elif mode == 'mean': + for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ + in enumerate(zip(pad_width, kwargs['stat_length'])): + newmat = _prepend_mean(newmat, pad_before, chunk_before, axis) + newmat = _append_mean(newmat, pad_after, chunk_after, axis) + + elif mode == 'median': + for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ + in enumerate(zip(pad_width, kwargs['stat_length'])): + newmat = _prepend_med(newmat, pad_before, chunk_before, axis) + newmat = _append_med(newmat, pad_after, chunk_after, axis) + + elif mode == 'minimum': + for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ + in enumerate(zip(pad_width, kwargs['stat_length'])): + newmat = _prepend_min(newmat, pad_before, chunk_before, axis) + newmat = _append_min(newmat, pad_after, chunk_after, axis) + + elif mode == 'reflect': + for axis, (pad_before, pad_after) in enumerate(pad_width): + if narray.shape[axis] == 0: + # Axes with non-zero padding cannot be empty. + if pad_before > 0 or pad_after > 0: + raise ValueError("There aren't any elements to reflect" + " in axis {} of `array`".format(axis)) + # Skip zero padding on empty axes. + continue + + # Recursive padding along any axis where `pad_amt` is too large + # for indexing tricks. We can only safely pad the original axis + # length, to keep the period of the reflections consistent. + if ((pad_before > 0) or + (pad_after > 0)) and newmat.shape[axis] == 1: + # Extending singleton dimension for 'reflect' is legacy + # behavior; it really should raise an error. + newmat = _prepend_edge(newmat, pad_before, axis) + newmat = _append_edge(newmat, pad_after, axis) + continue + + method = kwargs['reflect_type'] + safe_pad = newmat.shape[axis] - 1 + while ((pad_before > safe_pad) or (pad_after > safe_pad)): + pad_iter_b = min(safe_pad, + safe_pad * (pad_before // safe_pad)) + pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) + newmat = _pad_ref(newmat, (pad_iter_b, + pad_iter_a), method, axis) + pad_before -= pad_iter_b + pad_after -= pad_iter_a + safe_pad += pad_iter_b + pad_iter_a + newmat = _pad_ref(newmat, (pad_before, pad_after), method, axis) + + elif mode == 'symmetric': + for axis, (pad_before, pad_after) in enumerate(pad_width): + # Recursive padding along any axis where `pad_amt` is too large + # for indexing tricks. We can only safely pad the original axis + # length, to keep the period of the reflections consistent. + method = kwargs['reflect_type'] + safe_pad = newmat.shape[axis] + while ((pad_before > safe_pad) or + (pad_after > safe_pad)): + pad_iter_b = min(safe_pad, + safe_pad * (pad_before // safe_pad)) + pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) + newmat = _pad_sym(newmat, (pad_iter_b, + pad_iter_a), method, axis) + pad_before -= pad_iter_b + pad_after -= pad_iter_a + safe_pad += pad_iter_b + pad_iter_a + newmat = _pad_sym(newmat, (pad_before, pad_after), method, axis) + + elif mode == 'wrap': + for axis, (pad_before, pad_after) in enumerate(pad_width): + # Recursive padding along any axis where `pad_amt` is too large + # for indexing tricks. We can only safely pad the original axis + # length, to keep the period of the reflections consistent. + safe_pad = newmat.shape[axis] + while ((pad_before > safe_pad) or + (pad_after > safe_pad)): + pad_iter_b = min(safe_pad, + safe_pad * (pad_before // safe_pad)) + pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) + newmat = _pad_wrap(newmat, (pad_iter_b, pad_iter_a), axis) + + pad_before -= pad_iter_b + pad_after -= pad_iter_a + safe_pad += pad_iter_b + pad_iter_a + newmat = _pad_wrap(newmat, (pad_before, pad_after), axis) + + return newmat diff --git a/numpy/lib/arraysetops.py b/numpy/lib/arraysetops.py new file mode 100644 index 0000000..c02b841 --- /dev/null +++ b/numpy/lib/arraysetops.py @@ -0,0 +1,664 @@ +""" +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 numpy as np + + +__all__ = [ + 'ediff1d', 'intersect1d', 'setxor1d', 'union1d', 'setdiff1d', 'unique', + 'in1d', 'isin' + ] + + +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() + + # 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).ravel() + l_begin = len(to_begin) + + if to_end is None: + l_end = 0 + else: + to_end = np.asanyarray(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 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, and 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: + return _unique1d(ar, return_index, return_inverse, return_counts) + if not (-ar.ndim <= axis < ar.ndim): + raise ValueError('Invalid axis kwarg specified for unique') + + ar = np.swapaxes(ar, axis, 0) + orig_shape, orig_dtype = ar.shape, ar.dtype + # Must reshape to a contiguous 2D array for this to work... + 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) + if not (return_index or return_inverse or return_counts): + return reshape_uniq(output) + else: + uniq = reshape_uniq(output[0]) + return (uniq,) + output[1:] + +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 + optional_returns = optional_indices or return_counts + + if ar.size == 0: + if not optional_returns: + ret = ar + else: + ret = (ar,) + if return_index: + ret += (np.empty(0, np.intp),) + if return_inverse: + ret += (np.empty(0, np.intp),) + if return_counts: + ret += (np.empty(0, np.intp),) + return ret + + if optional_indices: + perm = ar.argsort(kind='mergesort' if return_index else 'quicksort') + aux = ar[perm] + else: + ar.sort() + aux = ar + flag = np.concatenate(([True], aux[1:] != aux[:-1])) + + if not optional_returns: + ret = aux[flag] + else: + ret = (aux[flag],) + if return_index: + ret += (perm[flag],) + if return_inverse: + iflag = np.cumsum(flag) - 1 + inv_idx = np.empty(ar.shape, dtype=np.intp) + inv_idx[perm] = iflag + ret += (inv_idx,) + if return_counts: + idx = np.concatenate(np.nonzero(flag) + ([ar.size],)) + ret += (np.diff(idx),) + return ret + +def intersect1d(ar1, ar2, assume_unique=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. + assume_unique : bool + If True, the input arrays are both assumed to be unique, which + can speed up the calculation. Default is False. + + Returns + ------- + intersect1d : ndarray + Sorted 1D array of common and unique elements. + + 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]) + """ + if not assume_unique: + # Might be faster than unique( intersect1d( ar1, ar2 ) )? + ar1 = unique(ar1) + ar2 = unique(ar2) + aux = np.concatenate((ar1, ar2)) + aux.sort() + return aux[:-1][aux[1:] == aux[:-1]] + +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(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(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]) + >>> 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(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(ar1, ar2, assume_unique=False): + """ + Find the set difference of two arrays. + + Return the sorted, 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 + Sorted 1D array of values in `ar1` that are not in `ar2`. + + 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)] diff --git a/numpy/lib/arrayterator.py b/numpy/lib/arrayterator.py new file mode 100644 index 0000000..f2d4fe9 --- /dev/null +++ b/numpy/lib/arrayterator.py @@ -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 + + """ + 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 diff --git a/numpy/lib/financial.py b/numpy/lib/financial.py new file mode 100644 index 0000000..06fa1bd --- /dev/null +++ b/numpy/lib/financial.py @@ -0,0 +1,761 @@ +"""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 numpy as np + +__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(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(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(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(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(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(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)) + +# 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. +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(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(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(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 diff --git a/numpy/lib/format.py b/numpy/lib/format.py new file mode 100644 index 0000000..363bb21 --- /dev/null +++ b/numpy/lib/format.py @@ -0,0 +1,832 @@ +""" +Define 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 reasons for creating it and a comparison of +alternatives, is described fully in the "npy-format" NEP. + +""" +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, basestring + +if sys.version_info[0] >= 3: + import pickle +else: + import cPickle as 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 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('= 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 = '= 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 + 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 not isinstance(filename, basestring): + raise ValueError("Filename must be a string. 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(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(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 diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py new file mode 100644 index 0000000..c9a2335 --- /dev/null +++ b/numpy/lib/function_base.py @@ -0,0 +1,5166 @@ +from __future__ import division, absolute_import, print_function + +import collections +import re +import sys +import warnings +import operator + +import numpy as np +import numpy.core.numeric as _nx +from numpy.core import linspace, atleast_1d, atleast_2d, transpose +from numpy.core.numeric import ( + ones, zeros, arange, concatenate, array, asarray, asanyarray, empty, + empty_like, ndarray, around, floor, ceil, take, dot, where, intp, + integer, isscalar, absolute, AxisError + ) +from numpy.core.umath import ( + pi, multiply, add, arctan2, frompyfunc, cos, less_equal, sqrt, sin, + mod, exp, log10, not_equal, subtract + ) +from numpy.core.fromnumeric import ( + ravel, nonzero, sort, partition, mean, any, sum + ) +from numpy.core.numerictypes import typecodes, number +from numpy.lib.twodim_base import diag +from .utils import deprecate +from numpy.core.multiarray import ( + _insert, add_docstring, digitize, bincount, normalize_axis_index, + interp as compiled_interp, interp_complex as compiled_interp_complex + ) +from numpy.core.umath import _add_newdoc_ufunc as add_newdoc_ufunc +from numpy.compat import long +from numpy.compat.py3k import basestring + +if sys.version_info[0] < 3: + # Force range to be a generator, for np.delete's usage. + range = xrange + import __builtin__ as builtins +else: + import builtins + + +__all__ = [ + 'select', 'piecewise', 'trim_zeros', 'copy', 'iterable', 'percentile', + 'diff', 'gradient', 'angle', 'unwrap', 'sort_complex', 'disp', 'flip', + 'rot90', 'extract', 'place', 'vectorize', 'asarray_chkfinite', 'average', + 'histogram', 'histogramdd', 'bincount', 'digitize', 'cov', 'corrcoef', + 'msort', 'median', 'sinc', 'hamming', 'hanning', 'bartlett', + 'blackman', 'kaiser', 'trapz', 'i0', 'add_newdoc', 'add_docstring', + 'meshgrid', 'delete', 'insert', 'append', 'interp', 'add_newdoc_ufunc' + ] + + +def rot90(m, k=1, axes=(0,1)): + """ + Rotate an array by 90 degrees in the plane specified by axes. + + Rotation direction is from the first towards the second axis. + + Parameters + ---------- + m : array_like + Array of two or more dimensions. + k : integer + Number of times the array is rotated by 90 degrees. + axes: (2,) array_like + The array is rotated in the plane defined by the axes. + Axes must be different. + + .. versionadded:: 1.12.0 + + Returns + ------- + y : ndarray + A rotated view of `m`. + + See Also + -------- + flip : Reverse the order of elements in an array along the given axis. + fliplr : Flip an array horizontally. + flipud : Flip an array vertically. + + Notes + ----- + rot90(m, k=1, axes=(1,0)) is the reverse of rot90(m, k=1, axes=(0,1)) + rot90(m, k=1, axes=(1,0)) is equivalent to rot90(m, k=-1, axes=(0,1)) + + Examples + -------- + >>> m = np.array([[1,2],[3,4]], int) + >>> m + array([[1, 2], + [3, 4]]) + >>> np.rot90(m) + array([[2, 4], + [1, 3]]) + >>> np.rot90(m, 2) + array([[4, 3], + [2, 1]]) + >>> m = np.arange(8).reshape((2,2,2)) + >>> np.rot90(m, 1, (1,2)) + array([[[1, 3], + [0, 2]], + + [[5, 7], + [4, 6]]]) + + """ + axes = tuple(axes) + if len(axes) != 2: + raise ValueError("len(axes) must be 2.") + + m = asanyarray(m) + + if axes[0] == axes[1] or absolute(axes[0] - axes[1]) == m.ndim: + raise ValueError("Axes must be different.") + + if (axes[0] >= m.ndim or axes[0] < -m.ndim + or axes[1] >= m.ndim or axes[1] < -m.ndim): + raise ValueError("Axes={} out of range for array of ndim={}." + .format(axes, m.ndim)) + + k %= 4 + + if k == 0: + return m[:] + if k == 2: + return flip(flip(m, axes[0]), axes[1]) + + axes_list = arange(0, m.ndim) + (axes_list[axes[0]], axes_list[axes[1]]) = (axes_list[axes[1]], + axes_list[axes[0]]) + + if k == 1: + return transpose(flip(m,axes[1]), axes_list) + else: + # k == 3 + return flip(transpose(m, axes_list), axes[1]) + + +def flip(m, axis): + """ + Reverse the order of elements in an array along the given axis. + + The shape of the array is preserved, but the elements are reordered. + + .. versionadded:: 1.12.0 + + Parameters + ---------- + m : array_like + Input array. + axis : integer + Axis in array, which entries are reversed. + + + Returns + ------- + out : array_like + A view of `m` with the entries of axis reversed. Since a view is + returned, this operation is done in constant time. + + See Also + -------- + flipud : Flip an array vertically (axis=0). + fliplr : Flip an array horizontally (axis=1). + + Notes + ----- + flip(m, 0) is equivalent to flipud(m). + flip(m, 1) is equivalent to fliplr(m). + flip(m, n) corresponds to ``m[...,::-1,...]`` with ``::-1`` at position n. + + Examples + -------- + >>> A = np.arange(8).reshape((2,2,2)) + >>> A + array([[[0, 1], + [2, 3]], + + [[4, 5], + [6, 7]]]) + + >>> flip(A, 0) + array([[[4, 5], + [6, 7]], + + [[0, 1], + [2, 3]]]) + + >>> flip(A, 1) + array([[[2, 3], + [0, 1]], + + [[6, 7], + [4, 5]]]) + + >>> A = np.random.randn(3,4,5) + >>> np.all(flip(A,2) == A[:,:,::-1,...]) + True + """ + if not hasattr(m, 'ndim'): + m = asarray(m) + indexer = [slice(None)] * m.ndim + try: + indexer[axis] = slice(None, None, -1) + except IndexError: + raise ValueError("axis=%i is invalid for the %i-dimensional input array" + % (axis, m.ndim)) + return m[tuple(indexer)] + + +def iterable(y): + """ + Check whether or not an object can be iterated over. + + Parameters + ---------- + y : object + Input object. + + Returns + ------- + b : bool + Return ``True`` if the object has an iterator method or is a + sequence and ``False`` otherwise. + + + Examples + -------- + >>> np.iterable([1, 2, 3]) + True + >>> np.iterable(2) + False + + """ + try: + iter(y) + except TypeError: + return False + return True + + +def _hist_bin_sqrt(x): + """ + Square root histogram bin estimator. + + Bin width is inversely proportional to the data size. Used by many + programs for its simplicity. + + Parameters + ---------- + x : array_like + Input data that is to be histogrammed, trimmed to range. May not + be empty. + + Returns + ------- + h : An estimate of the optimal bin width for the given data. + """ + return x.ptp() / np.sqrt(x.size) + + +def _hist_bin_sturges(x): + """ + Sturges histogram bin estimator. + + A very simplistic estimator based on the assumption of normality of + the data. This estimator has poor performance for non-normal data, + which becomes especially obvious for large data sets. The estimate + depends only on size of the data. + + Parameters + ---------- + x : array_like + Input data that is to be histogrammed, trimmed to range. May not + be empty. + + Returns + ------- + h : An estimate of the optimal bin width for the given data. + """ + return x.ptp() / (np.log2(x.size) + 1.0) + + +def _hist_bin_rice(x): + """ + Rice histogram bin estimator. + + Another simple estimator with no normality assumption. It has better + performance for large data than Sturges, but tends to overestimate + the number of bins. The number of bins is proportional to the cube + root of data size (asymptotically optimal). The estimate depends + only on size of the data. + + Parameters + ---------- + x : array_like + Input data that is to be histogrammed, trimmed to range. May not + be empty. + + Returns + ------- + h : An estimate of the optimal bin width for the given data. + """ + return x.ptp() / (2.0 * x.size ** (1.0 / 3)) + + +def _hist_bin_scott(x): + """ + Scott histogram bin estimator. + + The binwidth is proportional to the standard deviation of the data + and inversely proportional to the cube root of data size + (asymptotically optimal). + + Parameters + ---------- + x : array_like + Input data that is to be histogrammed, trimmed to range. May not + be empty. + + Returns + ------- + h : An estimate of the optimal bin width for the given data. + """ + return (24.0 * np.pi**0.5 / x.size)**(1.0 / 3.0) * np.std(x) + + +def _hist_bin_doane(x): + """ + Doane's histogram bin estimator. + + Improved version of Sturges' formula which works better for + non-normal data. See + stats.stackexchange.com/questions/55134/doanes-formula-for-histogram-binning + + Parameters + ---------- + x : array_like + Input data that is to be histogrammed, trimmed to range. May not + be empty. + + Returns + ------- + h : An estimate of the optimal bin width for the given data. + """ + if x.size > 2: + sg1 = np.sqrt(6.0 * (x.size - 2) / ((x.size + 1.0) * (x.size + 3))) + sigma = np.std(x) + if sigma > 0.0: + # These three operations add up to + # g1 = np.mean(((x - np.mean(x)) / sigma)**3) + # but use only one temp array instead of three + temp = x - np.mean(x) + np.true_divide(temp, sigma, temp) + np.power(temp, 3, temp) + g1 = np.mean(temp) + return x.ptp() / (1.0 + np.log2(x.size) + + np.log2(1.0 + np.absolute(g1) / sg1)) + return 0.0 + + +def _hist_bin_fd(x): + """ + The Freedman-Diaconis histogram bin estimator. + + The Freedman-Diaconis rule uses interquartile range (IQR) to + estimate binwidth. It is considered a variation of the Scott rule + with more robustness as the IQR is less affected by outliers than + the standard deviation. However, the IQR depends on fewer points + than the standard deviation, so it is less accurate, especially for + long tailed distributions. + + If the IQR is 0, this function returns 1 for the number of bins. + Binwidth is inversely proportional to the cube root of data size + (asymptotically optimal). + + Parameters + ---------- + x : array_like + Input data that is to be histogrammed, trimmed to range. May not + be empty. + + Returns + ------- + h : An estimate of the optimal bin width for the given data. + """ + iqr = np.subtract(*np.percentile(x, [75, 25])) + return 2.0 * iqr * x.size ** (-1.0 / 3.0) + + +def _hist_bin_auto(x): + """ + Histogram bin estimator that uses the minimum width of the + Freedman-Diaconis and Sturges estimators. + + The FD estimator is usually the most robust method, but its width + estimate tends to be too large for small `x`. The Sturges estimator + is quite good for small (<1000) datasets and is the default in the R + language. This method gives good off the shelf behaviour. + + Parameters + ---------- + x : array_like + Input data that is to be histogrammed, trimmed to range. May not + be empty. + + Returns + ------- + h : An estimate of the optimal bin width for the given data. + + See Also + -------- + _hist_bin_fd, _hist_bin_sturges + """ + # There is no need to check for zero here. If ptp is, so is IQR and + # vice versa. Either both are zero or neither one is. + return min(_hist_bin_fd(x), _hist_bin_sturges(x)) + + +# Private dict initialized at module load time +_hist_bin_selectors = {'auto': _hist_bin_auto, + 'doane': _hist_bin_doane, + 'fd': _hist_bin_fd, + 'rice': _hist_bin_rice, + 'scott': _hist_bin_scott, + 'sqrt': _hist_bin_sqrt, + 'sturges': _hist_bin_sturges} + + +def histogram(a, bins=10, range=None, normed=False, weights=None, + density=None): + r""" + Compute the histogram of a set of data. + + Parameters + ---------- + a : array_like + Input data. The histogram is computed over the flattened array. + bins : int or sequence of scalars or str, optional + If `bins` is an int, it defines the number of equal-width + bins in the given range (10, by default). If `bins` is a + sequence, it defines the bin edges, including the rightmost + edge, allowing for non-uniform bin widths. + + .. versionadded:: 1.11.0 + + If `bins` is a string from the list below, `histogram` will use + the method chosen to calculate the optimal bin width and + consequently the number of bins (see `Notes` for more detail on + the estimators) from the data that falls within the requested + range. While the bin width will be optimal for the actual data + in the range, the number of bins will be computed to fill the + entire range, including the empty portions. For visualisation, + using the 'auto' option is suggested. Weighted data is not + supported for automated bin size selection. + + 'auto' + Maximum of the 'sturges' and 'fd' estimators. Provides good + all around performance. + + 'fd' (Freedman Diaconis Estimator) + Robust (resilient to outliers) estimator that takes into + account data variability and data size. + + 'doane' + An improved version of Sturges' estimator that works better + with non-normal datasets. + + 'scott' + Less robust estimator that that takes into account data + variability and data size. + + 'rice' + Estimator does not take variability into account, only data + size. Commonly overestimates number of bins required. + + 'sturges' + R's default method, only accounts for data size. Only + optimal for gaussian data and underestimates number of bins + for large non-gaussian datasets. + + 'sqrt' + Square root (of data size) estimator, used by Excel and + other programs for its speed and simplicity. + + range : (float, float), optional + The lower and upper range of the bins. If not provided, range + is simply ``(a.min(), a.max())``. Values outside the range are + ignored. The first element of the range must be less than or + equal to the second. `range` affects the automatic bin + computation as well. While bin width is computed to be optimal + based on the actual data within `range`, the bin count will fill + the entire range including portions containing no data. + normed : bool, optional + This keyword is deprecated in NumPy 1.6.0 due to confusing/buggy + behavior. It will be removed in NumPy 2.0.0. Use the ``density`` + keyword instead. If ``False``, the result will contain the + number of samples in each bin. If ``True``, the result is the + value of the probability *density* function at the bin, + normalized such that the *integral* over the range is 1. Note + that this latter behavior is known to be buggy with unequal bin + widths; use ``density`` instead. + weights : array_like, optional + An array of weights, of the same shape as `a`. Each value in + `a` only contributes its associated weight towards the bin count + (instead of 1). If `density` is True, the weights are + normalized, so that the integral of the density over the range + remains 1. + density : bool, optional + If ``False``, the result will contain the number of samples in + each bin. If ``True``, the result is the value of the + probability *density* function at the bin, normalized such that + the *integral* over the range is 1. Note that the sum of the + histogram values will not be equal to 1 unless bins of unity + width are chosen; it is not a probability *mass* function. + + Overrides the ``normed`` keyword if given. + + Returns + ------- + hist : array + The values of the histogram. See `density` and `weights` for a + description of the possible semantics. + bin_edges : array of dtype float + Return the bin edges ``(length(hist)+1)``. + + + See Also + -------- + histogramdd, bincount, searchsorted, digitize + + Notes + ----- + All but the last (righthand-most) bin is half-open. In other words, + if `bins` is:: + + [1, 2, 3, 4] + + then the first bin is ``[1, 2)`` (including 1, but excluding 2) and + the second ``[2, 3)``. The last bin, however, is ``[3, 4]``, which + *includes* 4. + + .. versionadded:: 1.11.0 + + The methods to estimate the optimal number of bins are well founded + in literature, and are inspired by the choices R provides for + histogram visualisation. Note that having the number of bins + proportional to :math:`n^{1/3}` is asymptotically optimal, which is + why it appears in most estimators. These are simply plug-in methods + that give good starting points for number of bins. In the equations + below, :math:`h` is the binwidth and :math:`n_h` is the number of + bins. All estimators that compute bin counts are recast to bin width + using the `ptp` of the data. The final bin count is obtained from + ``np.round(np.ceil(range / h))`. + + 'Auto' (maximum of the 'Sturges' and 'FD' estimators) + A compromise to get a good value. For small datasets the Sturges + value will usually be chosen, while larger datasets will usually + default to FD. Avoids the overly conservative behaviour of FD + and Sturges for small and large datasets respectively. + Switchover point is usually :math:`a.size \approx 1000`. + + 'FD' (Freedman Diaconis Estimator) + .. math:: h = 2 \frac{IQR}{n^{1/3}} + + The binwidth is proportional to the interquartile range (IQR) + and inversely proportional to cube root of a.size. Can be too + conservative for small datasets, but is quite good for large + datasets. The IQR is very robust to outliers. + + 'Scott' + .. math:: h = \sigma \sqrt[3]{\frac{24 * \sqrt{\pi}}{n}} + + The binwidth is proportional to the standard deviation of the + data and inversely proportional to cube root of ``x.size``. Can + be too conservative for small datasets, but is quite good for + large datasets. The standard deviation is not very robust to + outliers. Values are very similar to the Freedman-Diaconis + estimator in the absence of outliers. + + 'Rice' + .. math:: n_h = 2n^{1/3} + + The number of bins is only proportional to cube root of + ``a.size``. It tends to overestimate the number of bins and it + does not take into account data variability. + + 'Sturges' + .. math:: n_h = \log _{2}n+1 + + The number of bins is the base 2 log of ``a.size``. This + estimator assumes normality of data and is too conservative for + larger, non-normal datasets. This is the default method in R's + ``hist`` method. + + 'Doane' + .. math:: n_h = 1 + \log_{2}(n) + + \log_{2}(1 + \frac{|g_1|}{\sigma_{g_1}}) + + g_1 = mean[(\frac{x - \mu}{\sigma})^3] + + \sigma_{g_1} = \sqrt{\frac{6(n - 2)}{(n + 1)(n + 3)}} + + An improved version of Sturges' formula that produces better + estimates for non-normal datasets. This estimator attempts to + account for the skew of the data. + + 'Sqrt' + .. math:: n_h = \sqrt n + The simplest and fastest estimator. Only takes into account the + data size. + + Examples + -------- + >>> np.histogram([1, 2, 1], bins=[0, 1, 2, 3]) + (array([0, 2, 1]), array([0, 1, 2, 3])) + >>> np.histogram(np.arange(4), bins=np.arange(5), density=True) + (array([ 0.25, 0.25, 0.25, 0.25]), array([0, 1, 2, 3, 4])) + >>> np.histogram([[1, 2, 1], [1, 0, 1]], bins=[0,1,2,3]) + (array([1, 4, 1]), array([0, 1, 2, 3])) + + >>> a = np.arange(5) + >>> hist, bin_edges = np.histogram(a, density=True) + >>> hist + array([ 0.5, 0. , 0.5, 0. , 0. , 0.5, 0. , 0.5, 0. , 0.5]) + >>> hist.sum() + 2.4999999999999996 + >>> np.sum(hist * np.diff(bin_edges)) + 1.0 + + .. versionadded:: 1.11.0 + + Automated Bin Selection Methods example, using 2 peak random data + with 2000 points: + + >>> import matplotlib.pyplot as plt + >>> rng = np.random.RandomState(10) # deterministic random data + >>> a = np.hstack((rng.normal(size=1000), + ... rng.normal(loc=5, scale=2, size=1000))) + >>> plt.hist(a, bins='auto') # arguments are passed to np.histogram + >>> plt.title("Histogram with 'auto' bins") + >>> plt.show() + + """ + a = asarray(a) + if weights is not None: + weights = asarray(weights) + if weights.shape != a.shape: + raise ValueError( + 'weights should have the same shape as a.') + weights = weights.ravel() + a = a.ravel() + + # Do not modify the original value of range so we can check for `None` + if range is None: + if a.size == 0: + # handle empty arrays. Can't determine range, so use 0-1. + first_edge, last_edge = 0.0, 1.0 + else: + first_edge, last_edge = a.min() + 0.0, a.max() + 0.0 + else: + first_edge, last_edge = [mi + 0.0 for mi in range] + if first_edge > last_edge: + raise ValueError( + 'max must be larger than min in range parameter.') + if not np.all(np.isfinite([first_edge, last_edge])): + raise ValueError( + 'range parameter must be finite.') + if first_edge == last_edge: + first_edge -= 0.5 + last_edge += 0.5 + + # density overrides the normed keyword + if density is not None: + normed = False + + # parse the overloaded bins argument + n_equal_bins = None + bin_edges = None + + if isinstance(bins, basestring): + bin_name = bins + # if `bins` is a string for an automatic method, + # this will replace it with the number of bins calculated + if bin_name not in _hist_bin_selectors: + raise ValueError( + "{!r} is not a valid estimator for `bins`".format(bin_name)) + if weights is not None: + raise TypeError("Automated estimation of the number of " + "bins is not supported for weighted data") + # Make a reference to `a` + b = a + # Update the reference if the range needs truncation + if range is not None: + keep = (a >= first_edge) + keep &= (a <= last_edge) + if not np.logical_and.reduce(keep): + b = a[keep] + + if b.size == 0: + n_equal_bins = 1 + else: + # Do not call selectors on empty arrays + width = _hist_bin_selectors[bin_name](b) + if width: + n_equal_bins = int(np.ceil((last_edge - first_edge) / width)) + else: + # Width can be zero for some estimators, e.g. FD when + # the IQR of the data is zero. + n_equal_bins = 1 + + elif np.ndim(bins) == 0: + try: + n_equal_bins = operator.index(bins) + except TypeError: + raise TypeError( + '`bins` must be an integer, a string, or an array') + if n_equal_bins < 1: + raise ValueError('`bins` must be positive, when an integer') + + elif np.ndim(bins) == 1: + bin_edges = np.asarray(bins) + if np.any(bin_edges[:-1] > bin_edges[1:]): + raise ValueError( + '`bins` must increase monotonically, when an array') + + else: + raise ValueError('`bins` must be 1d, when an array') + + del bins + + # compute the bins if only the count was specified + if n_equal_bins is not None: + bin_edges = linspace( + first_edge, last_edge, n_equal_bins + 1, endpoint=True) + + # Histogram is an integer or a float array depending on the weights. + if weights is None: + ntype = np.dtype(np.intp) + else: + ntype = weights.dtype + + # We set a block size, as this allows us to iterate over chunks when + # computing histograms, to minimize memory usage. + BLOCK = 65536 + + # The fast path uses bincount, but that only works for certain types + # of weight + simple_weights = ( + weights is None or + np.can_cast(weights.dtype, np.double) or + np.can_cast(weights.dtype, complex) + ) + + if n_equal_bins is not None and simple_weights: + # Fast algorithm for equal bins + # We now convert values of a to bin indices, under the assumption of + # equal bin widths (which is valid here). + + # Initialize empty histogram + n = np.zeros(n_equal_bins, ntype) + + # Pre-compute histogram scaling factor + norm = n_equal_bins / (last_edge - first_edge) + + # We iterate over blocks here for two reasons: the first is that for + # large arrays, it is actually faster (for example for a 10^8 array it + # is 2x as fast) and it results in a memory footprint 3x lower in the + # limit of large arrays. + for i in arange(0, len(a), BLOCK): + tmp_a = a[i:i+BLOCK] + if weights is None: + tmp_w = None + else: + tmp_w = weights[i:i + BLOCK] + + # Only include values in the right range + keep = (tmp_a >= first_edge) + keep &= (tmp_a <= last_edge) + if not np.logical_and.reduce(keep): + tmp_a = tmp_a[keep] + if tmp_w is not None: + tmp_w = tmp_w[keep] + tmp_a_data = tmp_a.astype(float) + tmp_a = tmp_a_data - first_edge + tmp_a *= norm + + # Compute the bin indices, and for values that lie exactly on + # last_edge we need to subtract one + indices = tmp_a.astype(np.intp) + indices[indices == n_equal_bins] -= 1 + + # The index computation is not guaranteed to give exactly + # consistent results within ~1 ULP of the bin edges. + decrement = tmp_a_data < bin_edges[indices] + indices[decrement] -= 1 + # The last bin includes the right edge. The other bins do not. + increment = ((tmp_a_data >= bin_edges[indices + 1]) + & (indices != n_equal_bins - 1)) + indices[increment] += 1 + + # We now compute the histogram using bincount + if ntype.kind == 'c': + n.real += np.bincount(indices, weights=tmp_w.real, + minlength=n_equal_bins) + n.imag += np.bincount(indices, weights=tmp_w.imag, + minlength=n_equal_bins) + else: + n += np.bincount(indices, weights=tmp_w, + minlength=n_equal_bins).astype(ntype) + else: + # Compute via cumulative histogram + cum_n = np.zeros(bin_edges.shape, ntype) + if weights is None: + for i in arange(0, len(a), BLOCK): + sa = sort(a[i:i+BLOCK]) + cum_n += np.r_[sa.searchsorted(bin_edges[:-1], 'left'), + sa.searchsorted(bin_edges[-1], 'right')] + else: + zero = array(0, dtype=ntype) + for i in arange(0, len(a), BLOCK): + tmp_a = a[i:i+BLOCK] + tmp_w = weights[i:i+BLOCK] + sorting_index = np.argsort(tmp_a) + sa = tmp_a[sorting_index] + sw = tmp_w[sorting_index] + cw = np.concatenate(([zero], sw.cumsum())) + bin_index = np.r_[sa.searchsorted(bin_edges[:-1], 'left'), + sa.searchsorted(bin_edges[-1], 'right')] + cum_n += cw[bin_index] + + n = np.diff(cum_n) + + if density: + db = array(np.diff(bin_edges), float) + return n/db/n.sum(), bin_edges + elif normed: + # deprecated, buggy behavior. Remove for NumPy 2.0.0 + db = array(np.diff(bin_edges), float) + return n/(n*db).sum(), bin_edges + else: + return n, bin_edges + + +def histogramdd(sample, bins=10, range=None, normed=False, weights=None): + """ + Compute the multidimensional histogram of some data. + + Parameters + ---------- + sample : array_like + The data to be histogrammed. It must be an (N,D) array or data + that can be converted to such. The rows of the resulting array + are the coordinates of points in a D dimensional polytope. + bins : sequence or int, optional + The bin specification: + + * A sequence of arrays describing the bin edges along each dimension. + * The number of bins for each dimension (nx, ny, ... =bins) + * The number of bins for all dimensions (nx=ny=...=bins). + + range : sequence, optional + A sequence of lower and upper bin edges to be used if the edges are + not given explicitly in `bins`. Defaults to the minimum and maximum + values along each dimension. + normed : bool, optional + If False, returns the number of samples in each bin. If True, + returns the bin density ``bin_count / sample_count / bin_volume``. + weights : (N,) array_like, optional + An array of values `w_i` weighing each sample `(x_i, y_i, z_i, ...)`. + Weights are normalized to 1 if normed is True. If normed is False, + the values of the returned histogram are equal to the sum of the + weights belonging to the samples falling into each bin. + + Returns + ------- + H : ndarray + The multidimensional histogram of sample x. See normed and weights + for the different possible semantics. + edges : list + A list of D arrays describing the bin edges for each dimension. + + See Also + -------- + histogram: 1-D histogram + histogram2d: 2-D histogram + + Examples + -------- + >>> r = np.random.randn(100,3) + >>> H, edges = np.histogramdd(r, bins = (5, 8, 4)) + >>> H.shape, edges[0].size, edges[1].size, edges[2].size + ((5, 8, 4), 6, 9, 5) + + """ + + try: + # Sample is an ND-array. + N, D = sample.shape + except (AttributeError, ValueError): + # Sample is a sequence of 1D arrays. + sample = atleast_2d(sample).T + N, D = sample.shape + + nbin = empty(D, int) + edges = D*[None] + dedges = D*[None] + if weights is not None: + weights = asarray(weights) + + try: + M = len(bins) + if M != D: + raise ValueError( + 'The dimension of bins must be equal to the dimension of the ' + ' sample x.') + except TypeError: + # bins is an integer + bins = D*[bins] + + # Select range for each dimension + # Used only if number of bins is given. + if range is None: + # Handle empty input. Range can't be determined in that case, use 0-1. + if N == 0: + smin = zeros(D) + smax = ones(D) + else: + smin = atleast_1d(array(sample.min(0), float)) + smax = atleast_1d(array(sample.max(0), float)) + else: + if not np.all(np.isfinite(range)): + raise ValueError( + 'range parameter must be finite.') + smin = zeros(D) + smax = zeros(D) + for i in arange(D): + smin[i], smax[i] = range[i] + + # Make sure the bins have a finite width. + for i in arange(len(smin)): + if smin[i] == smax[i]: + smin[i] = smin[i] - .5 + smax[i] = smax[i] + .5 + + # avoid rounding issues for comparisons when dealing with inexact types + if np.issubdtype(sample.dtype, np.inexact): + edge_dt = sample.dtype + else: + edge_dt = float + # Create edge arrays + for i in arange(D): + if isscalar(bins[i]): + if bins[i] < 1: + raise ValueError( + "Element at index %s in `bins` should be a positive " + "integer." % i) + nbin[i] = bins[i] + 2 # +2 for outlier bins + edges[i] = linspace(smin[i], smax[i], nbin[i]-1, dtype=edge_dt) + else: + edges[i] = asarray(bins[i], edge_dt) + nbin[i] = len(edges[i]) + 1 # +1 for outlier bins + dedges[i] = diff(edges[i]) + if np.any(np.asarray(dedges[i]) <= 0): + raise ValueError( + "Found bin edge of size <= 0. Did you specify `bins` with" + "non-monotonic sequence?") + + nbin = asarray(nbin) + + # Handle empty input. + if N == 0: + return np.zeros(nbin-2), edges + + # Compute the bin number each sample falls into. + Ncount = {} + for i in arange(D): + Ncount[i] = digitize(sample[:, i], edges[i]) + + # Using digitize, values that fall on an edge are put in the right bin. + # For the rightmost bin, we want values equal to the right edge to be + # counted in the last bin, and not as an outlier. + for i in arange(D): + # Rounding precision + mindiff = dedges[i].min() + if not np.isinf(mindiff): + decimal = int(-log10(mindiff)) + 6 + # Find which points are on the rightmost edge. + not_smaller_than_edge = (sample[:, i] >= edges[i][-1]) + on_edge = (around(sample[:, i], decimal) == + around(edges[i][-1], decimal)) + # Shift these points one bin to the left. + Ncount[i][nonzero(on_edge & not_smaller_than_edge)[0]] -= 1 + + # Flattened histogram matrix (1D) + # Reshape is used so that overlarge arrays + # will raise an error. + hist = zeros(nbin, float).reshape(-1) + + # Compute the sample indices in the flattened histogram matrix. + ni = nbin.argsort() + xy = zeros(N, int) + for i in arange(0, D-1): + xy += Ncount[ni[i]] * nbin[ni[i+1:]].prod() + xy += Ncount[ni[-1]] + + # Compute the number of repetitions in xy and assign it to the + # flattened histmat. + if len(xy) == 0: + return zeros(nbin-2, int), edges + + flatcount = bincount(xy, weights) + a = arange(len(flatcount)) + hist[a] = flatcount + + # Shape into a proper matrix + hist = hist.reshape(sort(nbin)) + for i in arange(nbin.size): + j = ni.argsort()[i] + hist = hist.swapaxes(i, j) + ni[i], ni[j] = ni[j], ni[i] + + # Remove outliers (indices 0 and -1 for each dimension). + core = D*[slice(1, -1)] + hist = hist[core] + + # Normalize if normed is True + if normed: + s = hist.sum() + for i in arange(D): + shape = ones(D, int) + shape[i] = nbin[i] - 2 + hist = hist / dedges[i].reshape(shape) + hist /= s + + if (hist.shape != nbin - 2).any(): + raise RuntimeError( + "Internal Shape Error") + return hist, edges + + +def average(a, axis=None, weights=None, returned=False): + """ + Compute the weighted average along the specified axis. + + Parameters + ---------- + a : array_like + Array containing data to be averaged. If `a` is not an array, a + conversion is attempted. + axis : None or int or tuple of ints, optional + Axis or axes along which to average `a`. The default, + axis=None, will average over all of the elements of the input array. + If axis is negative it counts from the last to the first axis. + + .. versionadded:: 1.7.0 + + If axis is a tuple of ints, averaging is performed on all of the axes + specified in the tuple instead of a single axis or all the axes as + before. + weights : array_like, optional + An array of weights associated with the values in `a`. Each value in + `a` contributes to the average according to its associated weight. + The weights array can either be 1-D (in which case its length must be + the size of `a` along the given axis) or of the same shape as `a`. + If `weights=None`, then all data in `a` are assumed to have a + weight equal to one. + returned : bool, optional + Default is `False`. If `True`, the tuple (`average`, `sum_of_weights`) + is returned, otherwise only the average is returned. + If `weights=None`, `sum_of_weights` is equivalent to the number of + elements over which the average is taken. + + + Returns + ------- + average, [sum_of_weights] : array_type or double + Return the average along the specified axis. When returned is `True`, + return a tuple with the average as the first element and the sum + of the weights as the second element. The return type is `Float` + if `a` is of integer type, otherwise it is of the same type as `a`. + `sum_of_weights` is of the same type as `average`. + + Raises + ------ + ZeroDivisionError + When all weights along axis are zero. See `numpy.ma.average` for a + version robust to this type of error. + TypeError + When the length of 1D `weights` is not the same as the shape of `a` + along axis. + + See Also + -------- + mean + + ma.average : average for masked arrays -- useful if your data contains + "missing" values + + Examples + -------- + >>> data = range(1,5) + >>> data + [1, 2, 3, 4] + >>> np.average(data) + 2.5 + >>> np.average(range(1,11), weights=range(10,0,-1)) + 4.0 + + >>> data = np.arange(6).reshape((3,2)) + >>> data + array([[0, 1], + [2, 3], + [4, 5]]) + >>> np.average(data, axis=1, weights=[1./4, 3./4]) + array([ 0.75, 2.75, 4.75]) + >>> np.average(data, weights=[1./4, 3./4]) + Traceback (most recent call last): + ... + TypeError: Axis must be specified when shapes of a and weights differ. + + """ + a = np.asanyarray(a) + + if weights is None: + avg = a.mean(axis) + scl = avg.dtype.type(a.size/avg.size) + else: + wgt = np.asanyarray(weights) + + if issubclass(a.dtype.type, (np.integer, np.bool_)): + result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8') + else: + result_dtype = np.result_type(a.dtype, wgt.dtype) + + # Sanity checks + if a.shape != wgt.shape: + if axis is None: + raise TypeError( + "Axis must be specified when shapes of a and weights " + "differ.") + if wgt.ndim != 1: + raise TypeError( + "1D weights expected when shapes of a and weights differ.") + if wgt.shape[0] != a.shape[axis]: + raise ValueError( + "Length of weights not compatible with specified axis.") + + # setup wgt to broadcast along axis + wgt = np.broadcast_to(wgt, (a.ndim-1)*(1,) + wgt.shape) + wgt = wgt.swapaxes(-1, axis) + + scl = wgt.sum(axis=axis, dtype=result_dtype) + if np.any(scl == 0.0): + raise ZeroDivisionError( + "Weights sum to zero, can't be normalized") + + avg = np.multiply(a, wgt, dtype=result_dtype).sum(axis)/scl + + if returned: + if scl.shape != avg.shape: + scl = np.broadcast_to(scl, avg.shape).copy() + return avg, scl + else: + return avg + + +def asarray_chkfinite(a, dtype=None, order=None): + """Convert the input to an array, checking for NaNs or Infs. + + Parameters + ---------- + a : array_like + Input data, in any form that can be converted to an array. This + includes lists, lists of tuples, tuples, tuples of tuples, tuples + of lists and ndarrays. Success requires no NaNs or Infs. + dtype : data-type, optional + By default, the data-type is inferred from the input data. + order : {'C', 'F'}, optional + Whether to use row-major (C-style) or + column-major (Fortran-style) memory representation. + Defaults to 'C'. + + Returns + ------- + out : ndarray + Array interpretation of `a`. No copy is performed if the input + is already an ndarray. If `a` is a subclass of ndarray, a base + class ndarray is returned. + + Raises + ------ + ValueError + Raises ValueError if `a` contains NaN (Not a Number) or Inf (Infinity). + + See Also + -------- + asarray : Create and array. + asanyarray : Similar function which passes through subclasses. + ascontiguousarray : Convert input to a contiguous array. + asfarray : Convert input to a floating point ndarray. + asfortranarray : Convert input to an ndarray with column-major + memory order. + fromiter : Create an array from an iterator. + fromfunction : Construct an array by executing a function on grid + positions. + + Examples + -------- + Convert a list into an array. If all elements are finite + ``asarray_chkfinite`` is identical to ``asarray``. + + >>> a = [1, 2] + >>> np.asarray_chkfinite(a, dtype=float) + array([1., 2.]) + + Raises ValueError if array_like contains Nans or Infs. + + >>> a = [1, 2, np.inf] + >>> try: + ... np.asarray_chkfinite(a) + ... except ValueError: + ... print('ValueError') + ... + ValueError + + """ + a = asarray(a, dtype=dtype, order=order) + if a.dtype.char in typecodes['AllFloat'] and not np.isfinite(a).all(): + raise ValueError( + "array must not contain infs or NaNs") + return a + + +def piecewise(x, condlist, funclist, *args, **kw): + """ + Evaluate a piecewise-defined function. + + Given a set of conditions and corresponding functions, evaluate each + function on the input data wherever its condition is true. + + Parameters + ---------- + x : ndarray or scalar + The input domain. + condlist : list of bool arrays or bool scalars + Each boolean array corresponds to a function in `funclist`. Wherever + `condlist[i]` is True, `funclist[i](x)` is used as the output value. + + Each boolean array in `condlist` selects a piece of `x`, + and should therefore be of the same shape as `x`. + + The length of `condlist` must correspond to that of `funclist`. + If one extra function is given, i.e. if + ``len(funclist) == len(condlist) + 1``, then that extra function + is the default value, used wherever all conditions are false. + funclist : list of callables, f(x,*args,**kw), or scalars + Each function is evaluated over `x` wherever its corresponding + condition is True. It should take a 1d array as input and give an 1d + array or a scalar value as output. If, instead of a callable, + a scalar is provided then a constant function (``lambda x: scalar``) is + assumed. + args : tuple, optional + Any further arguments given to `piecewise` are passed to the functions + upon execution, i.e., if called ``piecewise(..., ..., 1, 'a')``, then + each function is called as ``f(x, 1, 'a')``. + kw : dict, optional + Keyword arguments used in calling `piecewise` are passed to the + functions upon execution, i.e., if called + ``piecewise(..., ..., alpha=1)``, then each function is called as + ``f(x, alpha=1)``. + + Returns + ------- + out : ndarray + The output is the same shape and type as x and is found by + calling the functions in `funclist` on the appropriate portions of `x`, + as defined by the boolean arrays in `condlist`. Portions not covered + by any condition have a default value of 0. + + + See Also + -------- + choose, select, where + + Notes + ----- + This is similar to choose or select, except that functions are + evaluated on elements of `x` that satisfy the corresponding condition from + `condlist`. + + The result is:: + + |-- + |funclist[0](x[condlist[0]]) + out = |funclist[1](x[condlist[1]]) + |... + |funclist[n2](x[condlist[n2]]) + |-- + + Examples + -------- + Define the sigma function, which is -1 for ``x < 0`` and +1 for ``x >= 0``. + + >>> x = np.linspace(-2.5, 2.5, 6) + >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) + array([-1., -1., -1., 1., 1., 1.]) + + Define the absolute value, which is ``-x`` for ``x <0`` and ``x`` for + ``x >= 0``. + + >>> np.piecewise(x, [x < 0, x >= 0], [lambda x: -x, lambda x: x]) + array([ 2.5, 1.5, 0.5, 0.5, 1.5, 2.5]) + + Apply the same function to a scalar value. + + >>> y = -2 + >>> np.piecewise(y, [y < 0, y >= 0], [lambda x: -x, lambda x: x]) + array(2) + + """ + x = asanyarray(x) + n2 = len(funclist) + + # undocumented: single condition is promoted to a list of one condition + if isscalar(condlist) or ( + not isinstance(condlist[0], (list, ndarray)) and x.ndim != 0): + condlist = [condlist] + + condlist = array(condlist, dtype=bool) + n = len(condlist) + + if n == n2 - 1: # compute the "otherwise" condition. + condelse = ~np.any(condlist, axis=0, keepdims=True) + condlist = np.concatenate([condlist, condelse], axis=0) + n += 1 + elif n != n2: + raise ValueError( + "with {} condition(s), either {} or {} functions are expected" + .format(n, n, n+1) + ) + + y = zeros(x.shape, x.dtype) + for k in range(n): + item = funclist[k] + if not isinstance(item, collections.Callable): + y[condlist[k]] = item + else: + vals = x[condlist[k]] + if vals.size > 0: + y[condlist[k]] = item(vals, *args, **kw) + + return y + + +def select(condlist, choicelist, default=0): + """ + Return an array drawn from elements in choicelist, depending on conditions. + + Parameters + ---------- + condlist : list of bool ndarrays + The list of conditions which determine from which array in `choicelist` + the output elements are taken. When multiple conditions are satisfied, + the first one encountered in `condlist` is used. + choicelist : list of ndarrays + The list of arrays from which the output elements are taken. It has + to be of the same length as `condlist`. + default : scalar, optional + The element inserted in `output` when all conditions evaluate to False. + + Returns + ------- + output : ndarray + The output at position m is the m-th element of the array in + `choicelist` where the m-th element of the corresponding array in + `condlist` is True. + + See Also + -------- + where : Return elements from one of two arrays depending on condition. + take, choose, compress, diag, diagonal + + Examples + -------- + >>> x = np.arange(10) + >>> condlist = [x<3, x>5] + >>> choicelist = [x, x**2] + >>> np.select(condlist, choicelist) + array([ 0, 1, 2, 0, 0, 0, 36, 49, 64, 81]) + + """ + # Check the size of condlist and choicelist are the same, or abort. + if len(condlist) != len(choicelist): + raise ValueError( + 'list of cases must be same length as list of conditions') + + # Now that the dtype is known, handle the deprecated select([], []) case + if len(condlist) == 0: + # 2014-02-24, 1.9 + warnings.warn("select with an empty condition list is not possible" + "and will be deprecated", + DeprecationWarning, stacklevel=2) + return np.asarray(default)[()] + + choicelist = [np.asarray(choice) for choice in choicelist] + choicelist.append(np.asarray(default)) + + # need to get the result type before broadcasting for correct scalar + # behaviour + dtype = np.result_type(*choicelist) + + # Convert conditions to arrays and broadcast conditions and choices + # as the shape is needed for the result. Doing it separately optimizes + # for example when all choices are scalars. + condlist = np.broadcast_arrays(*condlist) + choicelist = np.broadcast_arrays(*choicelist) + + # If cond array is not an ndarray in boolean format or scalar bool, abort. + deprecated_ints = False + for i in range(len(condlist)): + cond = condlist[i] + if cond.dtype.type is not np.bool_: + if np.issubdtype(cond.dtype, np.integer): + # A previous implementation accepted int ndarrays accidentally. + # Supported here deliberately, but deprecated. + condlist[i] = condlist[i].astype(bool) + deprecated_ints = True + else: + raise ValueError( + 'invalid entry in choicelist: should be boolean ndarray') + + if deprecated_ints: + # 2014-02-24, 1.9 + msg = "select condlists containing integer ndarrays is deprecated " \ + "and will be removed in the future. Use `.astype(bool)` to " \ + "convert to bools." + warnings.warn(msg, DeprecationWarning, stacklevel=2) + + if choicelist[0].ndim == 0: + # This may be common, so avoid the call. + result_shape = condlist[0].shape + else: + result_shape = np.broadcast_arrays(condlist[0], choicelist[0])[0].shape + + result = np.full(result_shape, choicelist[-1], dtype) + + # Use np.copyto to burn each choicelist array onto result, using the + # corresponding condlist as a boolean mask. This is done in reverse + # order since the first choice should take precedence. + choicelist = choicelist[-2::-1] + condlist = condlist[::-1] + for choice, cond in zip(choicelist, condlist): + np.copyto(result, choice, where=cond) + + return result + + +def copy(a, order='K'): + """ + Return an array copy of the given object. + + Parameters + ---------- + a : array_like + Input data. + order : {'C', 'F', 'A', 'K'}, optional + Controls the memory layout of the copy. 'C' means C-order, + 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, + 'C' otherwise. 'K' means match the layout of `a` as closely + as possible. (Note that this function and :meth:`ndarray.copy` are very + similar, but have different default values for their order= + arguments.) + + Returns + ------- + arr : ndarray + Array interpretation of `a`. + + Notes + ----- + This is equivalent to: + + >>> np.array(a, copy=True) #doctest: +SKIP + + Examples + -------- + Create an array x, with a reference y and a copy z: + + >>> x = np.array([1, 2, 3]) + >>> y = x + >>> z = np.copy(x) + + Note that, when we modify x, y changes, but not z: + + >>> x[0] = 10 + >>> x[0] == y[0] + True + >>> x[0] == z[0] + False + + """ + return array(a, order=order, copy=True) + +# Basic operations + + +def gradient(f, *varargs, **kwargs): + """ + Return the gradient of an N-dimensional array. + + The gradient is computed using second order accurate central differences + in the interior points and either first or second order accurate one-sides + (forward or backwards) differences at the boundaries. + The returned gradient hence has the same shape as the input array. + + Parameters + ---------- + f : array_like + An N-dimensional array containing samples of a scalar function. + varargs : list of scalar or array, optional + Spacing between f values. Default unitary spacing for all dimensions. + Spacing can be specified using: + + 1. single scalar to specify a sample distance for all dimensions. + 2. N scalars to specify a constant sample distance for each dimension. + i.e. `dx`, `dy`, `dz`, ... + 3. N arrays to specify the coordinates of the values along each + dimension of F. The length of the array must match the size of + the corresponding dimension + 4. Any combination of N scalars/arrays with the meaning of 2. and 3. + + If `axis` is given, the number of varargs must equal the number of axes. + Default: 1. + + edge_order : {1, 2}, optional + Gradient is calculated using N-th order accurate differences + at the boundaries. Default: 1. + + .. versionadded:: 1.9.1 + + axis : None or int or tuple of ints, optional + Gradient is calculated only along the given axis or axes + The default (axis = None) is to calculate the gradient for all the axes + of the input array. axis may be negative, in which case it counts from + the last to the first axis. + + .. versionadded:: 1.11.0 + + Returns + ------- + gradient : ndarray or list of ndarray + A set of ndarrays (or a single ndarray if there is only one dimension) + corresponding to the derivatives of f with respect to each dimension. + Each derivative has the same shape as f. + + Examples + -------- + >>> f = np.array([1, 2, 4, 7, 11, 16], dtype=float) + >>> np.gradient(f) + array([ 1. , 1.5, 2.5, 3.5, 4.5, 5. ]) + >>> np.gradient(f, 2) + array([ 0.5 , 0.75, 1.25, 1.75, 2.25, 2.5 ]) + + Spacing can be also specified with an array that represents the coordinates + of the values F along the dimensions. + For instance a uniform spacing: + + >>> x = np.arange(f.size) + >>> np.gradient(f, x) + array([ 1. , 1.5, 2.5, 3.5, 4.5, 5. ]) + + Or a non uniform one: + + >>> x = np.array([0., 1., 1.5, 3.5, 4., 6.], dtype=float) + >>> np.gradient(f, x) + array([ 1. , 3. , 3.5, 6.7, 6.9, 2.5]) + + For two dimensional arrays, the return will be two arrays ordered by + axis. In this example the first array stands for the gradient in + rows and the second one in columns direction: + + >>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=float)) + [array([[ 2., 2., -1.], + [ 2., 2., -1.]]), array([[ 1. , 2.5, 4. ], + [ 1. , 1. , 1. ]])] + + In this example the spacing is also specified: + uniform for axis=0 and non uniform for axis=1 + + >>> dx = 2. + >>> y = [1., 1.5, 3.5] + >>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=float), dx, y) + [array([[ 1. , 1. , -0.5], + [ 1. , 1. , -0.5]]), array([[ 2. , 2. , 2. ], + [ 2. , 1.7, 0.5]])] + + It is possible to specify how boundaries are treated using `edge_order` + + >>> x = np.array([0, 1, 2, 3, 4]) + >>> f = x**2 + >>> np.gradient(f, edge_order=1) + array([ 1., 2., 4., 6., 7.]) + >>> np.gradient(f, edge_order=2) + array([-0., 2., 4., 6., 8.]) + + The `axis` keyword can be used to specify a subset of axes of which the + gradient is calculated + + >>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=float), axis=0) + array([[ 2., 2., -1.], + [ 2., 2., -1.]]) + + Notes + ----- + Assuming that :math:`f\\in C^{3}` (i.e., :math:`f` has at least 3 continuous + derivatives) and let be :math:`h_{*}` a non homogeneous stepsize, the + spacing the finite difference coefficients are computed by minimising + the consistency error :math:`\\eta_{i}`: + + .. math:: + + \\eta_{i} = f_{i}^{\\left(1\\right)} - + \\left[ \\alpha f\\left(x_{i}\\right) + + \\beta f\\left(x_{i} + h_{d}\\right) + + \\gamma f\\left(x_{i}-h_{s}\\right) + \\right] + + By substituting :math:`f(x_{i} + h_{d})` and :math:`f(x_{i} - h_{s})` + with their Taylor series expansion, this translates into solving + the following the linear system: + + .. math:: + + \\left\\{ + \\begin{array}{r} + \\alpha+\\beta+\\gamma=0 \\\\ + -\\beta h_{d}+\\gamma h_{s}=1 \\\\ + \\beta h_{d}^{2}+\\gamma h_{s}^{2}=0 + \\end{array} + \\right. + + The resulting approximation of :math:`f_{i}^{(1)}` is the following: + + .. math:: + + \\hat f_{i}^{(1)} = + \\frac{ + h_{s}^{2}f\\left(x_{i} + h_{d}\\right) + + \\left(h_{d}^{2} - h_{s}^{2}\\right)f\\left(x_{i}\\right) + - h_{d}^{2}f\\left(x_{i}-h_{s}\\right)} + { h_{s}h_{d}\\left(h_{d} + h_{s}\\right)} + + \\mathcal{O}\\left(\\frac{h_{d}h_{s}^{2} + + h_{s}h_{d}^{2}}{h_{d} + + h_{s}}\\right) + + It is worth noting that if :math:`h_{s}=h_{d}` + (i.e., data are evenly spaced) + we find the standard second order approximation: + + .. math:: + + \\hat f_{i}^{(1)}= + \\frac{f\\left(x_{i+1}\\right) - f\\left(x_{i-1}\\right)}{2h} + + \\mathcal{O}\\left(h^{2}\\right) + + With a similar procedure the forward/backward approximations used for + boundaries can be derived. + + References + ---------- + .. [1] Quarteroni A., Sacco R., Saleri F. (2007) Numerical Mathematics + (Texts in Applied Mathematics). New York: Springer. + .. [2] Durran D. R. (1999) Numerical Methods for Wave Equations + in Geophysical Fluid Dynamics. New York: Springer. + .. [3] Fornberg B. (1988) Generation of Finite Difference Formulas on + Arbitrarily Spaced Grids, + Mathematics of Computation 51, no. 184 : 699-706. + `PDF `_. + """ + f = np.asanyarray(f) + N = f.ndim # number of dimensions + + axes = kwargs.pop('axis', None) + if axes is None: + axes = tuple(range(N)) + else: + axes = _nx.normalize_axis_tuple(axes, N) + + len_axes = len(axes) + n = len(varargs) + if n == 0: + # no spacing argument - use 1 in all axes + dx = [1.0] * len_axes + elif n == 1 and np.ndim(varargs[0]) == 0: + # single scalar for all axes + dx = varargs * len_axes + elif n == len_axes: + # scalar or 1d array for each axis + dx = list(varargs) + for i, distances in enumerate(dx): + if np.ndim(distances) == 0: + continue + elif np.ndim(distances) != 1: + raise ValueError("distances must be either scalars or 1d") + if len(distances) != f.shape[axes[i]]: + raise ValueError("when 1d, distances must match " + "the length of the corresponding dimension") + diffx = np.diff(distances) + # if distances are constant reduce to the scalar case + # since it brings a consistent speedup + if (diffx == diffx[0]).all(): + diffx = diffx[0] + dx[i] = diffx + else: + raise TypeError("invalid number of arguments") + + edge_order = kwargs.pop('edge_order', 1) + if kwargs: + raise TypeError('"{}" are not valid keyword arguments.'.format( + '", "'.join(kwargs.keys()))) + if edge_order > 2: + raise ValueError("'edge_order' greater than 2 not supported") + + # use central differences on interior and one-sided differences on the + # endpoints. This preserves second order-accuracy over the full domain. + + outvals = [] + + # create slice objects --- initially all are [:, :, ..., :] + slice1 = [slice(None)]*N + slice2 = [slice(None)]*N + slice3 = [slice(None)]*N + slice4 = [slice(None)]*N + + otype = f.dtype + if otype.type is np.datetime64: + # the timedelta dtype with the same unit information + otype = np.dtype(otype.name.replace('datetime', 'timedelta')) + # view as timedelta to allow addition + f = f.view(otype) + elif otype.type is np.timedelta64: + pass + elif np.issubdtype(otype, np.inexact): + pass + else: + # all other types convert to floating point + otype = np.double + + for axis, ax_dx in zip(axes, dx): + if f.shape[axis] < edge_order + 1: + raise ValueError( + "Shape of array too small to calculate a numerical gradient, " + "at least (edge_order + 1) elements are required.") + # result allocation + out = np.empty_like(f, dtype=otype) + + # spacing for the current axis + uniform_spacing = np.ndim(ax_dx) == 0 + + # Numerical differentiation: 2nd order interior + slice1[axis] = slice(1, -1) + slice2[axis] = slice(None, -2) + slice3[axis] = slice(1, -1) + slice4[axis] = slice(2, None) + + if uniform_spacing: + out[slice1] = (f[slice4] - f[slice2]) / (2. * ax_dx) + else: + dx1 = ax_dx[0:-1] + dx2 = ax_dx[1:] + a = -(dx2)/(dx1 * (dx1 + dx2)) + b = (dx2 - dx1) / (dx1 * dx2) + c = dx1 / (dx2 * (dx1 + dx2)) + # fix the shape for broadcasting + shape = np.ones(N, dtype=int) + shape[axis] = -1 + a.shape = b.shape = c.shape = shape + # 1D equivalent -- out[1:-1] = a * f[:-2] + b * f[1:-1] + c * f[2:] + out[slice1] = a * f[slice2] + b * f[slice3] + c * f[slice4] + + # Numerical differentiation: 1st order edges + if edge_order == 1: + slice1[axis] = 0 + slice2[axis] = 1 + slice3[axis] = 0 + dx_0 = ax_dx if uniform_spacing else ax_dx[0] + # 1D equivalent -- out[0] = (f[1] - f[0]) / (x[1] - x[0]) + out[slice1] = (f[slice2] - f[slice3]) / dx_0 + + slice1[axis] = -1 + slice2[axis] = -1 + slice3[axis] = -2 + dx_n = ax_dx if uniform_spacing else ax_dx[-1] + # 1D equivalent -- out[-1] = (f[-1] - f[-2]) / (x[-1] - x[-2]) + out[slice1] = (f[slice2] - f[slice3]) / dx_n + + # Numerical differentiation: 2nd order edges + else: + slice1[axis] = 0 + slice2[axis] = 0 + slice3[axis] = 1 + slice4[axis] = 2 + if uniform_spacing: + a = -1.5 / ax_dx + b = 2. / ax_dx + c = -0.5 / ax_dx + else: + dx1 = ax_dx[0] + dx2 = ax_dx[1] + a = -(2. * dx1 + dx2)/(dx1 * (dx1 + dx2)) + b = (dx1 + dx2) / (dx1 * dx2) + c = - dx1 / (dx2 * (dx1 + dx2)) + # 1D equivalent -- out[0] = a * f[0] + b * f[1] + c * f[2] + out[slice1] = a * f[slice2] + b * f[slice3] + c * f[slice4] + + slice1[axis] = -1 + slice2[axis] = -3 + slice3[axis] = -2 + slice4[axis] = -1 + if uniform_spacing: + a = 0.5 / ax_dx + b = -2. / ax_dx + c = 1.5 / ax_dx + else: + dx1 = ax_dx[-2] + dx2 = ax_dx[-1] + a = (dx2) / (dx1 * (dx1 + dx2)) + b = - (dx2 + dx1) / (dx1 * dx2) + c = (2. * dx2 + dx1) / (dx2 * (dx1 + dx2)) + # 1D equivalent -- out[-1] = a * f[-3] + b * f[-2] + c * f[-1] + out[slice1] = a * f[slice2] + b * f[slice3] + c * f[slice4] + + outvals.append(out) + + # reset the slice object in this dimension to ":" + slice1[axis] = slice(None) + slice2[axis] = slice(None) + slice3[axis] = slice(None) + slice4[axis] = slice(None) + + if len_axes == 1: + return outvals[0] + else: + return outvals + + +def diff(a, n=1, axis=-1): + """ + Calculate the n-th discrete difference along the given axis. + + The first difference is given by ``out[n] = a[n+1] - a[n]`` along + the given axis, higher differences are calculated by using `diff` + recursively. + + Parameters + ---------- + a : array_like + Input array + n : int, optional + The number of times values are differenced. If zero, the input + is returned as-is. + axis : int, optional + The axis along which the difference is taken, default is the + last axis. + + Returns + ------- + diff : ndarray + The n-th differences. The shape of the output is the same as `a` + except along `axis` where the dimension is smaller by `n`. The + type of the output is the same as the type of the difference + between any two elements of `a`. This is the same as the type of + `a` in most cases. A notable exception is `datetime64`, which + results in a `timedelta64` output array. + + See Also + -------- + gradient, ediff1d, cumsum + + Notes + ----- + Type is preserved for boolean arrays, so the result will contain + `False` when consecutive elements are the same and `True` when they + differ. + + For unsigned integer arrays, the results will also be unsigned. This + should not be surprising, as the result is consistent with + calculating the difference directly: + + >>> u8_arr = np.array([1, 0], dtype=np.uint8) + >>> np.diff(u8_arr) + array([255], dtype=uint8) + >>> u8_arr[1,...] - u8_arr[0,...] + array(255, np.uint8) + + If this is not desirable, then the array should be cast to a larger + integer type first: + + >>> i16_arr = u8_arr.astype(np.int16) + >>> np.diff(i16_arr) + array([-1], dtype=int16) + + Examples + -------- + >>> x = np.array([1, 2, 4, 7, 0]) + >>> np.diff(x) + array([ 1, 2, 3, -7]) + >>> np.diff(x, n=2) + array([ 1, 1, -10]) + + >>> x = np.array([[1, 3, 6, 10], [0, 5, 6, 8]]) + >>> np.diff(x) + array([[2, 3, 4], + [5, 1, 2]]) + >>> np.diff(x, axis=0) + array([[-1, 2, 0, -2]]) + + >>> x = np.arange('1066-10-13', '1066-10-16', dtype=np.datetime64) + >>> np.diff(x) + array([1, 1], dtype='timedelta64[D]') + + """ + if n == 0: + return a + if n < 0: + raise ValueError( + "order must be non-negative but got " + repr(n)) + + a = asanyarray(a) + nd = a.ndim + axis = normalize_axis_index(axis, nd) + + slice1 = [slice(None)] * nd + slice2 = [slice(None)] * nd + slice1[axis] = slice(1, None) + slice2[axis] = slice(None, -1) + slice1 = tuple(slice1) + slice2 = tuple(slice2) + + op = not_equal if a.dtype == np.bool_ else subtract + for _ in range(n): + a = op(a[slice1], a[slice2]) + + return a + + +def interp(x, xp, fp, left=None, right=None, period=None): + """ + One-dimensional linear interpolation. + + Returns the one-dimensional piecewise linear interpolant to a function + with given values at discrete data-points. + + Parameters + ---------- + x : array_like + The x-coordinates of the interpolated values. + + xp : 1-D sequence of floats + The x-coordinates of the data points, must be increasing if argument + `period` is not specified. Otherwise, `xp` is internally sorted after + normalizing the periodic boundaries with ``xp = xp % period``. + + fp : 1-D sequence of float or complex + The y-coordinates of the data points, same length as `xp`. + + left : optional float or complex corresponding to fp + Value to return for `x < xp[0]`, default is `fp[0]`. + + right : optional float or complex corresponding to fp + Value to return for `x > xp[-1]`, default is `fp[-1]`. + + period : None or float, optional + A period for the x-coordinates. This parameter allows the proper + interpolation of angular x-coordinates. Parameters `left` and `right` + are ignored if `period` is specified. + + .. versionadded:: 1.10.0 + + Returns + ------- + y : float or complex (corresponding to fp) or ndarray + The interpolated values, same shape as `x`. + + Raises + ------ + ValueError + If `xp` and `fp` have different length + If `xp` or `fp` are not 1-D sequences + If `period == 0` + + Notes + ----- + Does not check that the x-coordinate sequence `xp` is increasing. + If `xp` is not increasing, the results are nonsense. + A simple check for increasing is:: + + np.all(np.diff(xp) > 0) + + Examples + -------- + >>> xp = [1, 2, 3] + >>> fp = [3, 2, 0] + >>> np.interp(2.5, xp, fp) + 1.0 + >>> np.interp([0, 1, 1.5, 2.72, 3.14], xp, fp) + array([ 3. , 3. , 2.5 , 0.56, 0. ]) + >>> UNDEF = -99.0 + >>> np.interp(3.14, xp, fp, right=UNDEF) + -99.0 + + Plot an interpolant to the sine function: + + >>> x = np.linspace(0, 2*np.pi, 10) + >>> y = np.sin(x) + >>> xvals = np.linspace(0, 2*np.pi, 50) + >>> yinterp = np.interp(xvals, x, y) + >>> import matplotlib.pyplot as plt + >>> plt.plot(x, y, 'o') + [] + >>> plt.plot(xvals, yinterp, '-x') + [] + >>> plt.show() + + Interpolation with periodic x-coordinates: + + >>> x = [-180, -170, -185, 185, -10, -5, 0, 365] + >>> xp = [190, -190, 350, -350] + >>> fp = [5, 10, 3, 4] + >>> np.interp(x, xp, fp, period=360) + array([7.5, 5., 8.75, 6.25, 3., 3.25, 3.5, 3.75]) + + Complex interpolation + >>> x = [1.5, 4.0] + >>> xp = [2,3,5] + >>> fp = [1.0j, 0, 2+3j] + >>> np.interp(x, xp, fp) + array([ 0.+1.j , 1.+1.5j]) + + """ + + fp = np.asarray(fp) + + if np.iscomplexobj(fp): + interp_func = compiled_interp_complex + input_dtype = np.complex128 + else: + interp_func = compiled_interp + input_dtype = np.float64 + + if period is None: + if isinstance(x, (float, int, number)): + return interp_func([x], xp, fp, left, right).item() + elif isinstance(x, np.ndarray) and x.ndim == 0: + return interp_func([x], xp, fp, left, right).item() + else: + return interp_func(x, xp, fp, left, right) + else: + if period == 0: + raise ValueError("period must be a non-zero value") + period = abs(period) + left = None + right = None + return_array = True + if isinstance(x, (float, int, number)): + return_array = False + x = [x] + x = np.asarray(x, dtype=np.float64) + xp = np.asarray(xp, dtype=np.float64) + fp = np.asarray(fp, dtype=input_dtype) + + if xp.ndim != 1 or fp.ndim != 1: + raise ValueError("Data points must be 1-D sequences") + if xp.shape[0] != fp.shape[0]: + raise ValueError("fp and xp are not of the same length") + # normalizing periodic boundaries + x = x % period + xp = xp % period + asort_xp = np.argsort(xp) + xp = xp[asort_xp] + fp = fp[asort_xp] + xp = np.concatenate((xp[-1:]-period, xp, xp[0:1]+period)) + fp = np.concatenate((fp[-1:], fp, fp[0:1])) + + if return_array: + return interp_func(x, xp, fp, left, right) + else: + return interp_func(x, xp, fp, left, right).item() + + +def angle(z, deg=0): + """ + Return the angle of the complex argument. + + Parameters + ---------- + z : array_like + A complex number or sequence of complex numbers. + deg : bool, optional + Return angle in degrees if True, radians if False (default). + + Returns + ------- + angle : ndarray or scalar + The counterclockwise angle from the positive real axis on + the complex plane, with dtype as numpy.float64. + + See Also + -------- + arctan2 + absolute + + Examples + -------- + >>> np.angle([1.0, 1.0j, 1+1j]) # in radians + array([ 0. , 1.57079633, 0.78539816]) + >>> np.angle(1+1j, deg=True) # in degrees + 45.0 + + """ + if deg: + fact = 180/pi + else: + fact = 1.0 + z = asarray(z) + if (issubclass(z.dtype.type, _nx.complexfloating)): + zimag = z.imag + zreal = z.real + else: + zimag = 0 + zreal = z + return arctan2(zimag, zreal) * fact + + +def unwrap(p, discont=pi, axis=-1): + """ + Unwrap by changing deltas between values to 2*pi complement. + + Unwrap radian phase `p` by changing absolute jumps greater than + `discont` to their 2*pi complement along the given axis. + + Parameters + ---------- + p : array_like + Input array. + discont : float, optional + Maximum discontinuity between values, default is ``pi``. + axis : int, optional + Axis along which unwrap will operate, default is the last axis. + + Returns + ------- + out : ndarray + Output array. + + See Also + -------- + rad2deg, deg2rad + + Notes + ----- + If the discontinuity in `p` is smaller than ``pi``, but larger than + `discont`, no unwrapping is done because taking the 2*pi complement + would only make the discontinuity larger. + + Examples + -------- + >>> phase = np.linspace(0, np.pi, num=5) + >>> phase[3:] += np.pi + >>> phase + array([ 0. , 0.78539816, 1.57079633, 5.49778714, 6.28318531]) + >>> np.unwrap(phase) + array([ 0. , 0.78539816, 1.57079633, -0.78539816, 0. ]) + + """ + p = asarray(p) + nd = p.ndim + dd = diff(p, axis=axis) + slice1 = [slice(None, None)]*nd # full slices + slice1[axis] = slice(1, None) + ddmod = mod(dd + pi, 2*pi) - pi + _nx.copyto(ddmod, pi, where=(ddmod == -pi) & (dd > 0)) + ph_correct = ddmod - dd + _nx.copyto(ph_correct, 0, where=abs(dd) < discont) + up = array(p, copy=True, dtype='d') + up[slice1] = p[slice1] + ph_correct.cumsum(axis) + return up + + +def sort_complex(a): + """ + Sort a complex array using the real part first, then the imaginary part. + + Parameters + ---------- + a : array_like + Input array + + Returns + ------- + out : complex ndarray + Always returns a sorted complex array. + + Examples + -------- + >>> np.sort_complex([5, 3, 6, 2, 1]) + array([ 1.+0.j, 2.+0.j, 3.+0.j, 5.+0.j, 6.+0.j]) + + >>> np.sort_complex([1 + 2j, 2 - 1j, 3 - 2j, 3 - 3j, 3 + 5j]) + array([ 1.+2.j, 2.-1.j, 3.-3.j, 3.-2.j, 3.+5.j]) + + """ + b = array(a, copy=True) + b.sort() + if not issubclass(b.dtype.type, _nx.complexfloating): + if b.dtype.char in 'bhBH': + return b.astype('F') + elif b.dtype.char == 'g': + return b.astype('G') + else: + return b.astype('D') + else: + return b + + +def trim_zeros(filt, trim='fb'): + """ + Trim the leading and/or trailing zeros from a 1-D array or sequence. + + Parameters + ---------- + filt : 1-D array or sequence + Input array. + trim : str, optional + A string with 'f' representing trim from front and 'b' to trim from + back. Default is 'fb', trim zeros from both front and back of the + array. + + Returns + ------- + trimmed : 1-D array or sequence + The result of trimming the input. The input data type is preserved. + + Examples + -------- + >>> a = np.array((0, 0, 0, 1, 2, 3, 0, 2, 1, 0)) + >>> np.trim_zeros(a) + array([1, 2, 3, 0, 2, 1]) + + >>> np.trim_zeros(a, 'b') + array([0, 0, 0, 1, 2, 3, 0, 2, 1]) + + The input data type is preserved, list/tuple in means list/tuple out. + + >>> np.trim_zeros([0, 1, 2, 0]) + [1, 2] + + """ + first = 0 + trim = trim.upper() + if 'F' in trim: + for i in filt: + if i != 0.: + break + else: + first = first + 1 + last = len(filt) + if 'B' in trim: + for i in filt[::-1]: + if i != 0.: + break + else: + last = last - 1 + return filt[first:last] + + +@deprecate +def unique(x): + """ + This function is deprecated. Use numpy.lib.arraysetops.unique() + instead. + """ + try: + tmp = x.flatten() + if tmp.size == 0: + return tmp + tmp.sort() + idx = concatenate(([True], tmp[1:] != tmp[:-1])) + return tmp[idx] + except AttributeError: + items = sorted(set(x)) + return asarray(items) + + +def extract(condition, arr): + """ + Return the elements of an array that satisfy some condition. + + This is equivalent to ``np.compress(ravel(condition), ravel(arr))``. If + `condition` is boolean ``np.extract`` is equivalent to ``arr[condition]``. + + Note that `place` does the exact opposite of `extract`. + + Parameters + ---------- + condition : array_like + An array whose nonzero or True entries indicate the elements of `arr` + to extract. + arr : array_like + Input array of the same size as `condition`. + + Returns + ------- + extract : ndarray + Rank 1 array of values from `arr` where `condition` is True. + + See Also + -------- + take, put, copyto, compress, place + + Examples + -------- + >>> arr = np.arange(12).reshape((3, 4)) + >>> arr + array([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> condition = np.mod(arr, 3)==0 + >>> condition + array([[ True, False, False, True], + [False, False, True, False], + [False, True, False, False]]) + >>> np.extract(condition, arr) + array([0, 3, 6, 9]) + + + If `condition` is boolean: + + >>> arr[condition] + array([0, 3, 6, 9]) + + """ + return _nx.take(ravel(arr), nonzero(ravel(condition))[0]) + + +def place(arr, mask, vals): + """ + Change elements of an array based on conditional and input values. + + Similar to ``np.copyto(arr, vals, where=mask)``, the difference is that + `place` uses the first N elements of `vals`, where N is the number of + True values in `mask`, while `copyto` uses the elements where `mask` + is True. + + Note that `extract` does the exact opposite of `place`. + + Parameters + ---------- + arr : ndarray + Array to put data into. + mask : array_like + Boolean mask array. Must have the same size as `a`. + vals : 1-D sequence + Values to put into `a`. Only the first N elements are used, where + N is the number of True values in `mask`. If `vals` is smaller + than N, it will be repeated, and if elements of `a` are to be masked, + this sequence must be non-empty. + + See Also + -------- + copyto, put, take, extract + + Examples + -------- + >>> arr = np.arange(6).reshape(2, 3) + >>> np.place(arr, arr>2, [44, 55]) + >>> arr + array([[ 0, 1, 2], + [44, 55, 44]]) + + """ + if not isinstance(arr, np.ndarray): + raise TypeError("argument 1 must be numpy.ndarray, " + "not {name}".format(name=type(arr).__name__)) + + return _insert(arr, mask, vals) + + +def disp(mesg, device=None, linefeed=True): + """ + Display a message on a device. + + Parameters + ---------- + mesg : str + Message to display. + device : object + Device to write message. If None, defaults to ``sys.stdout`` which is + very similar to ``print``. `device` needs to have ``write()`` and + ``flush()`` methods. + linefeed : bool, optional + Option whether to print a line feed or not. Defaults to True. + + Raises + ------ + AttributeError + If `device` does not have a ``write()`` or ``flush()`` method. + + Examples + -------- + Besides ``sys.stdout``, a file-like object can also be used as it has + both required methods: + + >>> from StringIO import StringIO + >>> buf = StringIO() + >>> np.disp('"Display" in a file', device=buf) + >>> buf.getvalue() + '"Display" in a file\\n' + + """ + if device is None: + device = sys.stdout + if linefeed: + device.write('%s\n' % mesg) + else: + device.write('%s' % mesg) + device.flush() + return + + +# See http://docs.scipy.org/doc/numpy/reference/c-api.generalized-ufuncs.html +_DIMENSION_NAME = r'\w+' +_CORE_DIMENSION_LIST = '(?:{0:}(?:,{0:})*)?'.format(_DIMENSION_NAME) +_ARGUMENT = r'\({}\)'.format(_CORE_DIMENSION_LIST) +_ARGUMENT_LIST = '{0:}(?:,{0:})*'.format(_ARGUMENT) +_SIGNATURE = '^{0:}->{0:}$'.format(_ARGUMENT_LIST) + + +def _parse_gufunc_signature(signature): + """ + Parse string signatures for a generalized universal function. + + Arguments + --------- + signature : string + Generalized universal function signature, e.g., ``(m,n),(n,p)->(m,p)`` + for ``np.matmul``. + + Returns + ------- + Tuple of input and output core dimensions parsed from the signature, each + of the form List[Tuple[str, ...]]. + """ + if not re.match(_SIGNATURE, signature): + raise ValueError( + 'not a valid gufunc signature: {}'.format(signature)) + return tuple([tuple(re.findall(_DIMENSION_NAME, arg)) + for arg in re.findall(_ARGUMENT, arg_list)] + for arg_list in signature.split('->')) + + +def _update_dim_sizes(dim_sizes, arg, core_dims): + """ + Incrementally check and update core dimension sizes for a single argument. + + Arguments + --------- + dim_sizes : Dict[str, int] + Sizes of existing core dimensions. Will be updated in-place. + arg : ndarray + Argument to examine. + core_dims : Tuple[str, ...] + Core dimensions for this argument. + """ + if not core_dims: + return + + num_core_dims = len(core_dims) + if arg.ndim < num_core_dims: + raise ValueError( + '%d-dimensional argument does not have enough ' + 'dimensions for all core dimensions %r' + % (arg.ndim, core_dims)) + + core_shape = arg.shape[-num_core_dims:] + for dim, size in zip(core_dims, core_shape): + if dim in dim_sizes: + if size != dim_sizes[dim]: + raise ValueError( + 'inconsistent size for core dimension %r: %r vs %r' + % (dim, size, dim_sizes[dim])) + else: + dim_sizes[dim] = size + + +def _parse_input_dimensions(args, input_core_dims): + """ + Parse broadcast and core dimensions for vectorize with a signature. + + Arguments + --------- + args : Tuple[ndarray, ...] + Tuple of input arguments to examine. + input_core_dims : List[Tuple[str, ...]] + List of core dimensions corresponding to each input. + + Returns + ------- + broadcast_shape : Tuple[int, ...] + Common shape to broadcast all non-core dimensions to. + dim_sizes : Dict[str, int] + Common sizes for named core dimensions. + """ + broadcast_args = [] + dim_sizes = {} + for arg, core_dims in zip(args, input_core_dims): + _update_dim_sizes(dim_sizes, arg, core_dims) + ndim = arg.ndim - len(core_dims) + dummy_array = np.lib.stride_tricks.as_strided(0, arg.shape[:ndim]) + broadcast_args.append(dummy_array) + broadcast_shape = np.lib.stride_tricks._broadcast_shape(*broadcast_args) + return broadcast_shape, dim_sizes + + +def _calculate_shapes(broadcast_shape, dim_sizes, list_of_core_dims): + """Helper for calculating broadcast shapes with core dimensions.""" + return [broadcast_shape + tuple(dim_sizes[dim] for dim in core_dims) + for core_dims in list_of_core_dims] + + +def _create_arrays(broadcast_shape, dim_sizes, list_of_core_dims, dtypes): + """Helper for creating output arrays in vectorize.""" + shapes = _calculate_shapes(broadcast_shape, dim_sizes, list_of_core_dims) + arrays = tuple(np.empty(shape, dtype=dtype) + for shape, dtype in zip(shapes, dtypes)) + return arrays + + +class vectorize(object): + """ + vectorize(pyfunc, otypes=None, doc=None, excluded=None, cache=False, + signature=None) + + Generalized function class. + + Define a vectorized function which takes a nested sequence of objects or + numpy arrays as inputs and returns an single or tuple of numpy array as + output. The vectorized function evaluates `pyfunc` over successive tuples + of the input arrays like the python map function, except it uses the + broadcasting rules of numpy. + + The data type of the output of `vectorized` is determined by calling + the function with the first element of the input. This can be avoided + by specifying the `otypes` argument. + + Parameters + ---------- + pyfunc : callable + A python function or method. + otypes : str or list of dtypes, optional + The output data type. It must be specified as either a string of + typecode characters or a list of data type specifiers. There should + be one data type specifier for each output. + doc : str, optional + The docstring for the function. If `None`, the docstring will be the + ``pyfunc.__doc__``. + excluded : set, optional + Set of strings or integers representing the positional or keyword + arguments for which the function will not be vectorized. These will be + passed directly to `pyfunc` unmodified. + + .. versionadded:: 1.7.0 + + cache : bool, optional + If `True`, then cache the first function call that determines the number + of outputs if `otypes` is not provided. + + .. versionadded:: 1.7.0 + + signature : string, optional + Generalized universal function signature, e.g., ``(m,n),(n)->(m)`` for + vectorized matrix-vector multiplication. If provided, ``pyfunc`` will + be called with (and expected to return) arrays with shapes given by the + size of corresponding core dimensions. By default, ``pyfunc`` is + assumed to take scalars as input and output. + + .. versionadded:: 1.12.0 + + Returns + ------- + vectorized : callable + Vectorized function. + + Examples + -------- + >>> def myfunc(a, b): + ... "Return a-b if a>b, otherwise return a+b" + ... if a > b: + ... return a - b + ... else: + ... return a + b + + >>> vfunc = np.vectorize(myfunc) + >>> vfunc([1, 2, 3, 4], 2) + array([3, 4, 1, 2]) + + The docstring is taken from the input function to `vectorize` unless it + is specified: + + >>> vfunc.__doc__ + 'Return a-b if a>b, otherwise return a+b' + >>> vfunc = np.vectorize(myfunc, doc='Vectorized `myfunc`') + >>> vfunc.__doc__ + 'Vectorized `myfunc`' + + The output type is determined by evaluating the first element of the input, + unless it is specified: + + >>> out = vfunc([1, 2, 3, 4], 2) + >>> type(out[0]) + + >>> vfunc = np.vectorize(myfunc, otypes=[float]) + >>> out = vfunc([1, 2, 3, 4], 2) + >>> type(out[0]) + + + The `excluded` argument can be used to prevent vectorizing over certain + arguments. This can be useful for array-like arguments of a fixed length + such as the coefficients for a polynomial as in `polyval`: + + >>> def mypolyval(p, x): + ... _p = list(p) + ... res = _p.pop(0) + ... while _p: + ... res = res*x + _p.pop(0) + ... return res + >>> vpolyval = np.vectorize(mypolyval, excluded=['p']) + >>> vpolyval(p=[1, 2, 3], x=[0, 1]) + array([3, 6]) + + Positional arguments may also be excluded by specifying their position: + + >>> vpolyval.excluded.add(0) + >>> vpolyval([1, 2, 3], x=[0, 1]) + array([3, 6]) + + The `signature` argument allows for vectorizing functions that act on + non-scalar arrays of fixed length. For example, you can use it for a + vectorized calculation of Pearson correlation coefficient and its p-value: + + >>> import scipy.stats + >>> pearsonr = np.vectorize(scipy.stats.pearsonr, + ... signature='(n),(n)->(),()') + >>> pearsonr([[0, 1, 2, 3]], [[1, 2, 3, 4], [4, 3, 2, 1]]) + (array([ 1., -1.]), array([ 0., 0.])) + + Or for a vectorized convolution: + + >>> convolve = np.vectorize(np.convolve, signature='(n),(m)->(k)') + >>> convolve(np.eye(4), [1, 2, 1]) + array([[ 1., 2., 1., 0., 0., 0.], + [ 0., 1., 2., 1., 0., 0.], + [ 0., 0., 1., 2., 1., 0.], + [ 0., 0., 0., 1., 2., 1.]]) + + See Also + -------- + frompyfunc : Takes an arbitrary Python function and returns a ufunc + + Notes + ----- + The `vectorize` function is provided primarily for convenience, not for + performance. The implementation is essentially a for loop. + + If `otypes` is not specified, then a call to the function with the + first argument will be used to determine the number of outputs. The + results of this call will be cached if `cache` is `True` to prevent + calling the function twice. However, to implement the cache, the + original function must be wrapped which will slow down subsequent + calls, so only do this if your function is expensive. + + The new keyword argument interface and `excluded` argument support + further degrades performance. + + References + ---------- + .. [1] NumPy Reference, section `Generalized Universal Function API + `_. + """ + + def __init__(self, pyfunc, otypes=None, doc=None, excluded=None, + cache=False, signature=None): + self.pyfunc = pyfunc + self.cache = cache + self.signature = signature + self._ufunc = None # Caching to improve default performance + + if doc is None: + self.__doc__ = pyfunc.__doc__ + else: + self.__doc__ = doc + + if isinstance(otypes, str): + for char in otypes: + if char not in typecodes['All']: + raise ValueError("Invalid otype specified: %s" % (char,)) + elif iterable(otypes): + otypes = ''.join([_nx.dtype(x).char for x in otypes]) + elif otypes is not None: + raise ValueError("Invalid otype specification") + self.otypes = otypes + + # Excluded variable support + if excluded is None: + excluded = set() + self.excluded = set(excluded) + + if signature is not None: + self._in_and_out_core_dims = _parse_gufunc_signature(signature) + else: + self._in_and_out_core_dims = None + + def __call__(self, *args, **kwargs): + """ + Return arrays with the results of `pyfunc` broadcast (vectorized) over + `args` and `kwargs` not in `excluded`. + """ + excluded = self.excluded + if not kwargs and not excluded: + func = self.pyfunc + vargs = args + else: + # The wrapper accepts only positional arguments: we use `names` and + # `inds` to mutate `the_args` and `kwargs` to pass to the original + # function. + nargs = len(args) + + names = [_n for _n in kwargs if _n not in excluded] + inds = [_i for _i in range(nargs) if _i not in excluded] + the_args = list(args) + + def func(*vargs): + for _n, _i in enumerate(inds): + the_args[_i] = vargs[_n] + kwargs.update(zip(names, vargs[len(inds):])) + return self.pyfunc(*the_args, **kwargs) + + vargs = [args[_i] for _i in inds] + vargs.extend([kwargs[_n] for _n in names]) + + return self._vectorize_call(func=func, args=vargs) + + def _get_ufunc_and_otypes(self, func, args): + """Return (ufunc, otypes).""" + # frompyfunc will fail if args is empty + if not args: + raise ValueError('args can not be empty') + + if self.otypes is not None: + otypes = self.otypes + nout = len(otypes) + + # Note logic here: We only *use* self._ufunc if func is self.pyfunc + # even though we set self._ufunc regardless. + if func is self.pyfunc and self._ufunc is not None: + ufunc = self._ufunc + else: + ufunc = self._ufunc = frompyfunc(func, len(args), nout) + else: + # Get number of outputs and output types by calling the function on + # the first entries of args. We also cache the result to prevent + # the subsequent call when the ufunc is evaluated. + # Assumes that ufunc first evaluates the 0th elements in the input + # arrays (the input values are not checked to ensure this) + args = [asarray(arg) for arg in args] + if builtins.any(arg.size == 0 for arg in args): + raise ValueError('cannot call `vectorize` on size 0 inputs ' + 'unless `otypes` is set') + + inputs = [arg.flat[0] for arg in args] + outputs = func(*inputs) + + # Performance note: profiling indicates that -- for simple + # functions at least -- this wrapping can almost double the + # execution time. + # Hence we make it optional. + if self.cache: + _cache = [outputs] + + def _func(*vargs): + if _cache: + return _cache.pop() + else: + return func(*vargs) + else: + _func = func + + if isinstance(outputs, tuple): + nout = len(outputs) + else: + nout = 1 + outputs = (outputs,) + + otypes = ''.join([asarray(outputs[_k]).dtype.char + for _k in range(nout)]) + + # Performance note: profiling indicates that creating the ufunc is + # not a significant cost compared with wrapping so it seems not + # worth trying to cache this. + ufunc = frompyfunc(_func, len(args), nout) + + return ufunc, otypes + + def _vectorize_call(self, func, args): + """Vectorized call to `func` over positional `args`.""" + if self.signature is not None: + res = self._vectorize_call_with_signature(func, args) + elif not args: + res = func() + else: + ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args) + + # Convert args to object arrays first + inputs = [array(a, copy=False, subok=True, dtype=object) + for a in args] + + outputs = ufunc(*inputs) + + if ufunc.nout == 1: + res = array(outputs, copy=False, subok=True, dtype=otypes[0]) + else: + res = tuple([array(x, copy=False, subok=True, dtype=t) + for x, t in zip(outputs, otypes)]) + return res + + def _vectorize_call_with_signature(self, func, args): + """Vectorized call over positional arguments with a signature.""" + input_core_dims, output_core_dims = self._in_and_out_core_dims + + if len(args) != len(input_core_dims): + raise TypeError('wrong number of positional arguments: ' + 'expected %r, got %r' + % (len(input_core_dims), len(args))) + args = tuple(asanyarray(arg) for arg in args) + + broadcast_shape, dim_sizes = _parse_input_dimensions( + args, input_core_dims) + input_shapes = _calculate_shapes(broadcast_shape, dim_sizes, + input_core_dims) + args = [np.broadcast_to(arg, shape, subok=True) + for arg, shape in zip(args, input_shapes)] + + outputs = None + otypes = self.otypes + nout = len(output_core_dims) + + for index in np.ndindex(*broadcast_shape): + results = func(*(arg[index] for arg in args)) + + n_results = len(results) if isinstance(results, tuple) else 1 + + if nout != n_results: + raise ValueError( + 'wrong number of outputs from pyfunc: expected %r, got %r' + % (nout, n_results)) + + if nout == 1: + results = (results,) + + if outputs is None: + for result, core_dims in zip(results, output_core_dims): + _update_dim_sizes(dim_sizes, result, core_dims) + + if otypes is None: + otypes = [asarray(result).dtype for result in results] + + outputs = _create_arrays(broadcast_shape, dim_sizes, + output_core_dims, otypes) + + for output, result in zip(outputs, results): + output[index] = result + + if outputs is None: + # did not call the function even once + if otypes is None: + raise ValueError('cannot call `vectorize` on size 0 inputs ' + 'unless `otypes` is set') + if builtins.any(dim not in dim_sizes + for dims in output_core_dims + for dim in dims): + raise ValueError('cannot call `vectorize` with a signature ' + 'including new output dimensions on size 0 ' + 'inputs') + outputs = _create_arrays(broadcast_shape, dim_sizes, + output_core_dims, otypes) + + return outputs[0] if nout == 1 else outputs + + +def cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None, + aweights=None): + """ + Estimate a covariance matrix, given data and weights. + + Covariance indicates the level to which two variables vary together. + If we examine N-dimensional samples, :math:`X = [x_1, x_2, ... x_N]^T`, + then the covariance matrix element :math:`C_{ij}` is the covariance of + :math:`x_i` and :math:`x_j`. The element :math:`C_{ii}` is the variance + of :math:`x_i`. + + See the notes for an outline of the algorithm. + + Parameters + ---------- + m : array_like + A 1-D or 2-D array containing multiple variables and observations. + Each row of `m` represents a variable, and each column a single + observation of all those variables. Also see `rowvar` below. + y : array_like, optional + An additional set of variables and observations. `y` has the same form + as that of `m`. + rowvar : bool, optional + If `rowvar` is True (default), then each row represents a + variable, with observations in the columns. Otherwise, the relationship + is transposed: each column represents a variable, while the rows + contain observations. + bias : bool, optional + Default normalization (False) is by ``(N - 1)``, where ``N`` is the + number of observations given (unbiased estimate). If `bias` is True, + then normalization is by ``N``. These values can be overridden by using + the keyword ``ddof`` in numpy versions >= 1.5. + ddof : int, optional + If not ``None`` the default value implied by `bias` is overridden. + Note that ``ddof=1`` will return the unbiased estimate, even if both + `fweights` and `aweights` are specified, and ``ddof=0`` will return + the simple average. See the notes for the details. The default value + is ``None``. + + .. versionadded:: 1.5 + fweights : array_like, int, optional + 1-D array of integer freguency weights; the number of times each + observation vector should be repeated. + + .. versionadded:: 1.10 + aweights : array_like, optional + 1-D array of observation vector weights. These relative weights are + typically large for observations considered "important" and smaller for + observations considered less "important". If ``ddof=0`` the array of + weights can be used to assign probabilities to observation vectors. + + .. versionadded:: 1.10 + + Returns + ------- + out : ndarray + The covariance matrix of the variables. + + See Also + -------- + corrcoef : Normalized covariance matrix + + Notes + ----- + Assume that the observations are in the columns of the observation + array `m` and let ``f = fweights`` and ``a = aweights`` for brevity. The + steps to compute the weighted covariance are as follows:: + + >>> w = f * a + >>> v1 = np.sum(w) + >>> v2 = np.sum(w * a) + >>> m -= np.sum(m * w, axis=1, keepdims=True) / v1 + >>> cov = np.dot(m * w, m.T) * v1 / (v1**2 - ddof * v2) + + Note that when ``a == 1``, the normalization factor + ``v1 / (v1**2 - ddof * v2)`` goes over to ``1 / (np.sum(f) - ddof)`` + as it should. + + Examples + -------- + Consider two variables, :math:`x_0` and :math:`x_1`, which + correlate perfectly, but in opposite directions: + + >>> x = np.array([[0, 2], [1, 1], [2, 0]]).T + >>> x + array([[0, 1, 2], + [2, 1, 0]]) + + Note how :math:`x_0` increases while :math:`x_1` decreases. The covariance + matrix shows this clearly: + + >>> np.cov(x) + array([[ 1., -1.], + [-1., 1.]]) + + Note that element :math:`C_{0,1}`, which shows the correlation between + :math:`x_0` and :math:`x_1`, is negative. + + Further, note how `x` and `y` are combined: + + >>> x = [-2.1, -1, 4.3] + >>> y = [3, 1.1, 0.12] + >>> X = np.stack((x, y), axis=0) + >>> print(np.cov(X)) + [[ 11.71 -4.286 ] + [ -4.286 2.14413333]] + >>> print(np.cov(x, y)) + [[ 11.71 -4.286 ] + [ -4.286 2.14413333]] + >>> print(np.cov(x)) + 11.71 + + """ + # Check inputs + if ddof is not None and ddof != int(ddof): + raise ValueError( + "ddof must be integer") + + # Handles complex arrays too + m = np.asarray(m) + if m.ndim > 2: + raise ValueError("m has more than 2 dimensions") + + if y is None: + dtype = np.result_type(m, np.float64) + else: + y = np.asarray(y) + if y.ndim > 2: + raise ValueError("y has more than 2 dimensions") + dtype = np.result_type(m, y, np.float64) + + X = array(m, ndmin=2, dtype=dtype) + if not rowvar and X.shape[0] != 1: + X = X.T + if X.shape[0] == 0: + return np.array([]).reshape(0, 0) + if y is not None: + y = array(y, copy=False, ndmin=2, dtype=dtype) + if not rowvar and y.shape[0] != 1: + y = y.T + X = np.concatenate((X, y), axis=0) + + if ddof is None: + if bias == 0: + ddof = 1 + else: + ddof = 0 + + # Get the product of frequencies and weights + w = None + if fweights is not None: + fweights = np.asarray(fweights, dtype=float) + if not np.all(fweights == np.around(fweights)): + raise TypeError( + "fweights must be integer") + if fweights.ndim > 1: + raise RuntimeError( + "cannot handle multidimensional fweights") + if fweights.shape[0] != X.shape[1]: + raise RuntimeError( + "incompatible numbers of samples and fweights") + if any(fweights < 0): + raise ValueError( + "fweights cannot be negative") + w = fweights + if aweights is not None: + aweights = np.asarray(aweights, dtype=float) + if aweights.ndim > 1: + raise RuntimeError( + "cannot handle multidimensional aweights") + if aweights.shape[0] != X.shape[1]: + raise RuntimeError( + "incompatible numbers of samples and aweights") + if any(aweights < 0): + raise ValueError( + "aweights cannot be negative") + if w is None: + w = aweights + else: + w *= aweights + + avg, w_sum = average(X, axis=1, weights=w, returned=True) + w_sum = w_sum[0] + + # Determine the normalization + if w is None: + fact = X.shape[1] - ddof + elif ddof == 0: + fact = w_sum + elif aweights is None: + fact = w_sum - ddof + else: + fact = w_sum - ddof*sum(w*aweights)/w_sum + + if fact <= 0: + warnings.warn("Degrees of freedom <= 0 for slice", + RuntimeWarning, stacklevel=2) + fact = 0.0 + + X -= avg[:, None] + if w is None: + X_T = X.T + else: + X_T = (X*w).T + c = dot(X, X_T.conj()) + c *= 1. / np.float64(fact) + return c.squeeze() + + +def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, ddof=np._NoValue): + """ + Return Pearson product-moment correlation coefficients. + + Please refer to the documentation for `cov` for more detail. The + relationship between the correlation coefficient matrix, `R`, and the + covariance matrix, `C`, is + + .. math:: R_{ij} = \\frac{ C_{ij} } { \\sqrt{ C_{ii} * C_{jj} } } + + The values of `R` are between -1 and 1, inclusive. + + Parameters + ---------- + x : array_like + A 1-D or 2-D array containing multiple variables and observations. + Each row of `x` represents a variable, and each column a single + observation of all those variables. Also see `rowvar` below. + y : array_like, optional + An additional set of variables and observations. `y` has the same + shape as `x`. + rowvar : bool, optional + If `rowvar` is True (default), then each row represents a + variable, with observations in the columns. Otherwise, the relationship + is transposed: each column represents a variable, while the rows + contain observations. + bias : _NoValue, optional + Has no effect, do not use. + + .. deprecated:: 1.10.0 + ddof : _NoValue, optional + Has no effect, do not use. + + .. deprecated:: 1.10.0 + + Returns + ------- + R : ndarray + The correlation coefficient matrix of the variables. + + See Also + -------- + cov : Covariance matrix + + Notes + ----- + Due to floating point rounding the resulting array may not be Hermitian, + the diagonal elements may not be 1, and the elements may not satisfy the + inequality abs(a) <= 1. The real and imaginary parts are clipped to the + interval [-1, 1] in an attempt to improve on that situation but is not + much help in the complex case. + + This function accepts but discards arguments `bias` and `ddof`. This is + for backwards compatibility with previous versions of this function. These + arguments had no effect on the return values of the function and can be + safely ignored in this and previous versions of numpy. + + """ + if bias is not np._NoValue or ddof is not np._NoValue: + # 2015-03-15, 1.10 + warnings.warn('bias and ddof have no effect and are deprecated', + DeprecationWarning, stacklevel=2) + c = cov(x, y, rowvar) + try: + d = diag(c) + except ValueError: + # scalar covariance + # nan if incorrect value (nan, inf, 0), 1 otherwise + return c / c + stddev = sqrt(d.real) + c /= stddev[:, None] + c /= stddev[None, :] + + # Clip real and imaginary parts to [-1, 1]. This does not guarantee + # abs(a[i,j]) <= 1 for complex arrays, but is the best we can do without + # excessive work. + np.clip(c.real, -1, 1, out=c.real) + if np.iscomplexobj(c): + np.clip(c.imag, -1, 1, out=c.imag) + + return c + + +def blackman(M): + """ + Return the Blackman window. + + The Blackman window is a taper formed by using the first three + terms of a summation of cosines. It was designed to have close to the + minimal leakage possible. It is close to optimal, only slightly worse + than a Kaiser window. + + Parameters + ---------- + M : int + Number of points in the output window. If zero or less, an empty + array is returned. + + Returns + ------- + out : ndarray + The window, with the maximum value normalized to one (the value one + appears only if the number of samples is odd). + + See Also + -------- + bartlett, hamming, hanning, kaiser + + Notes + ----- + The Blackman window is defined as + + .. math:: w(n) = 0.42 - 0.5 \\cos(2\\pi n/M) + 0.08 \\cos(4\\pi n/M) + + Most references to the Blackman window come from the signal processing + literature, where it is used as one of many windowing functions for + smoothing values. It is also known as an apodization (which means + "removing the foot", i.e. smoothing discontinuities at the beginning + and end of the sampled signal) or tapering function. It is known as a + "near optimal" tapering function, almost as good (by some measures) + as the kaiser window. + + References + ---------- + Blackman, R.B. and Tukey, J.W., (1958) The measurement of power spectra, + Dover Publications, New York. + + Oppenheim, A.V., and R.W. Schafer. Discrete-Time Signal Processing. + Upper Saddle River, NJ: Prentice-Hall, 1999, pp. 468-471. + + Examples + -------- + >>> np.blackman(12) + array([ -1.38777878e-17, 3.26064346e-02, 1.59903635e-01, + 4.14397981e-01, 7.36045180e-01, 9.67046769e-01, + 9.67046769e-01, 7.36045180e-01, 4.14397981e-01, + 1.59903635e-01, 3.26064346e-02, -1.38777878e-17]) + + + Plot the window and the frequency response: + + >>> from numpy.fft import fft, fftshift + >>> window = np.blackman(51) + >>> plt.plot(window) + [] + >>> plt.title("Blackman window") + + >>> plt.ylabel("Amplitude") + + >>> plt.xlabel("Sample") + + >>> plt.show() + + >>> plt.figure() + + >>> A = fft(window, 2048) / 25.5 + >>> mag = np.abs(fftshift(A)) + >>> freq = np.linspace(-0.5, 0.5, len(A)) + >>> response = 20 * np.log10(mag) + >>> response = np.clip(response, -100, 100) + >>> plt.plot(freq, response) + [] + >>> plt.title("Frequency response of Blackman window") + + >>> plt.ylabel("Magnitude [dB]") + + >>> plt.xlabel("Normalized frequency [cycles per sample]") + + >>> plt.axis('tight') + (-0.5, 0.5, -100.0, ...) + >>> plt.show() + + """ + if M < 1: + return array([]) + if M == 1: + return ones(1, float) + n = arange(0, M) + return 0.42 - 0.5*cos(2.0*pi*n/(M-1)) + 0.08*cos(4.0*pi*n/(M-1)) + + +def bartlett(M): + """ + Return the Bartlett window. + + The Bartlett window is very similar to a triangular window, except + that the end points are at zero. It is often used in signal + processing for tapering a signal, without generating too much + ripple in the frequency domain. + + Parameters + ---------- + M : int + Number of points in the output window. If zero or less, an + empty array is returned. + + Returns + ------- + out : array + The triangular window, with the maximum value normalized to one + (the value one appears only if the number of samples is odd), with + the first and last samples equal to zero. + + See Also + -------- + blackman, hamming, hanning, kaiser + + Notes + ----- + The Bartlett window is defined as + + .. math:: w(n) = \\frac{2}{M-1} \\left( + \\frac{M-1}{2} - \\left|n - \\frac{M-1}{2}\\right| + \\right) + + Most references to the Bartlett window come from the signal + processing literature, where it is used as one of many windowing + functions for smoothing values. Note that convolution with this + window produces linear interpolation. It is also known as an + apodization (which means"removing the foot", i.e. smoothing + discontinuities at the beginning and end of the sampled signal) or + tapering function. The fourier transform of the Bartlett is the product + of two sinc functions. + Note the excellent discussion in Kanasewich. + + References + ---------- + .. [1] M.S. Bartlett, "Periodogram Analysis and Continuous Spectra", + Biometrika 37, 1-16, 1950. + .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", + The University of Alberta Press, 1975, pp. 109-110. + .. [3] A.V. Oppenheim and R.W. Schafer, "Discrete-Time Signal + Processing", Prentice-Hall, 1999, pp. 468-471. + .. [4] Wikipedia, "Window function", + http://en.wikipedia.org/wiki/Window_function + .. [5] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, + "Numerical Recipes", Cambridge University Press, 1986, page 429. + + Examples + -------- + >>> np.bartlett(12) + array([ 0. , 0.18181818, 0.36363636, 0.54545455, 0.72727273, + 0.90909091, 0.90909091, 0.72727273, 0.54545455, 0.36363636, + 0.18181818, 0. ]) + + Plot the window and its frequency response (requires SciPy and matplotlib): + + >>> from numpy.fft import fft, fftshift + >>> window = np.bartlett(51) + >>> plt.plot(window) + [] + >>> plt.title("Bartlett window") + + >>> plt.ylabel("Amplitude") + + >>> plt.xlabel("Sample") + + >>> plt.show() + + >>> plt.figure() + + >>> A = fft(window, 2048) / 25.5 + >>> mag = np.abs(fftshift(A)) + >>> freq = np.linspace(-0.5, 0.5, len(A)) + >>> response = 20 * np.log10(mag) + >>> response = np.clip(response, -100, 100) + >>> plt.plot(freq, response) + [] + >>> plt.title("Frequency response of Bartlett window") + + >>> plt.ylabel("Magnitude [dB]") + + >>> plt.xlabel("Normalized frequency [cycles per sample]") + + >>> plt.axis('tight') + (-0.5, 0.5, -100.0, ...) + >>> plt.show() + + """ + if M < 1: + return array([]) + if M == 1: + return ones(1, float) + n = arange(0, M) + return where(less_equal(n, (M-1)/2.0), 2.0*n/(M-1), 2.0 - 2.0*n/(M-1)) + + +def hanning(M): + """ + Return the Hanning window. + + The Hanning window is a taper formed by using a weighted cosine. + + Parameters + ---------- + M : int + Number of points in the output window. If zero or less, an + empty array is returned. + + Returns + ------- + out : ndarray, shape(M,) + The window, with the maximum value normalized to one (the value + one appears only if `M` is odd). + + See Also + -------- + bartlett, blackman, hamming, kaiser + + Notes + ----- + The Hanning window is defined as + + .. math:: w(n) = 0.5 - 0.5cos\\left(\\frac{2\\pi{n}}{M-1}\\right) + \\qquad 0 \\leq n \\leq M-1 + + The Hanning was named for Julius von Hann, an Austrian meteorologist. + It is also known as the Cosine Bell. Some authors prefer that it be + called a Hann window, to help avoid confusion with the very similar + Hamming window. + + Most references to the Hanning window come from the signal processing + literature, where it is used as one of many windowing functions for + smoothing values. It is also known as an apodization (which means + "removing the foot", i.e. smoothing discontinuities at the beginning + and end of the sampled signal) or tapering function. + + References + ---------- + .. [1] Blackman, R.B. and Tukey, J.W., (1958) The measurement of power + spectra, Dover Publications, New York. + .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", + The University of Alberta Press, 1975, pp. 106-108. + .. [3] Wikipedia, "Window function", + http://en.wikipedia.org/wiki/Window_function + .. [4] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, + "Numerical Recipes", Cambridge University Press, 1986, page 425. + + Examples + -------- + >>> np.hanning(12) + array([ 0. , 0.07937323, 0.29229249, 0.57115742, 0.82743037, + 0.97974649, 0.97974649, 0.82743037, 0.57115742, 0.29229249, + 0.07937323, 0. ]) + + Plot the window and its frequency response: + + >>> from numpy.fft import fft, fftshift + >>> window = np.hanning(51) + >>> plt.plot(window) + [] + >>> plt.title("Hann window") + + >>> plt.ylabel("Amplitude") + + >>> plt.xlabel("Sample") + + >>> plt.show() + + >>> plt.figure() + + >>> A = fft(window, 2048) / 25.5 + >>> mag = np.abs(fftshift(A)) + >>> freq = np.linspace(-0.5, 0.5, len(A)) + >>> response = 20 * np.log10(mag) + >>> response = np.clip(response, -100, 100) + >>> plt.plot(freq, response) + [] + >>> plt.title("Frequency response of the Hann window") + + >>> plt.ylabel("Magnitude [dB]") + + >>> plt.xlabel("Normalized frequency [cycles per sample]") + + >>> plt.axis('tight') + (-0.5, 0.5, -100.0, ...) + >>> plt.show() + + """ + if M < 1: + return array([]) + if M == 1: + return ones(1, float) + n = arange(0, M) + return 0.5 - 0.5*cos(2.0*pi*n/(M-1)) + + +def hamming(M): + """ + Return the Hamming window. + + The Hamming window is a taper formed by using a weighted cosine. + + Parameters + ---------- + M : int + Number of points in the output window. If zero or less, an + empty array is returned. + + Returns + ------- + out : ndarray + The window, with the maximum value normalized to one (the value + one appears only if the number of samples is odd). + + See Also + -------- + bartlett, blackman, hanning, kaiser + + Notes + ----- + The Hamming window is defined as + + .. math:: w(n) = 0.54 - 0.46cos\\left(\\frac{2\\pi{n}}{M-1}\\right) + \\qquad 0 \\leq n \\leq M-1 + + The Hamming was named for R. W. Hamming, an associate of J. W. Tukey + and is described in Blackman and Tukey. It was recommended for + smoothing the truncated autocovariance function in the time domain. + Most references to the Hamming window come from the signal processing + literature, where it is used as one of many windowing functions for + smoothing values. It is also known as an apodization (which means + "removing the foot", i.e. smoothing discontinuities at the beginning + and end of the sampled signal) or tapering function. + + References + ---------- + .. [1] Blackman, R.B. and Tukey, J.W., (1958) The measurement of power + spectra, Dover Publications, New York. + .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", The + University of Alberta Press, 1975, pp. 109-110. + .. [3] Wikipedia, "Window function", + http://en.wikipedia.org/wiki/Window_function + .. [4] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, + "Numerical Recipes", Cambridge University Press, 1986, page 425. + + Examples + -------- + >>> np.hamming(12) + array([ 0.08 , 0.15302337, 0.34890909, 0.60546483, 0.84123594, + 0.98136677, 0.98136677, 0.84123594, 0.60546483, 0.34890909, + 0.15302337, 0.08 ]) + + Plot the window and the frequency response: + + >>> from numpy.fft import fft, fftshift + >>> window = np.hamming(51) + >>> plt.plot(window) + [] + >>> plt.title("Hamming window") + + >>> plt.ylabel("Amplitude") + + >>> plt.xlabel("Sample") + + >>> plt.show() + + >>> plt.figure() + + >>> A = fft(window, 2048) / 25.5 + >>> mag = np.abs(fftshift(A)) + >>> freq = np.linspace(-0.5, 0.5, len(A)) + >>> response = 20 * np.log10(mag) + >>> response = np.clip(response, -100, 100) + >>> plt.plot(freq, response) + [] + >>> plt.title("Frequency response of Hamming window") + + >>> plt.ylabel("Magnitude [dB]") + + >>> plt.xlabel("Normalized frequency [cycles per sample]") + + >>> plt.axis('tight') + (-0.5, 0.5, -100.0, ...) + >>> plt.show() + + """ + if M < 1: + return array([]) + if M == 1: + return ones(1, float) + n = arange(0, M) + return 0.54 - 0.46*cos(2.0*pi*n/(M-1)) + +## Code from cephes for i0 + +_i0A = [ + -4.41534164647933937950E-18, + 3.33079451882223809783E-17, + -2.43127984654795469359E-16, + 1.71539128555513303061E-15, + -1.16853328779934516808E-14, + 7.67618549860493561688E-14, + -4.85644678311192946090E-13, + 2.95505266312963983461E-12, + -1.72682629144155570723E-11, + 9.67580903537323691224E-11, + -5.18979560163526290666E-10, + 2.65982372468238665035E-9, + -1.30002500998624804212E-8, + 6.04699502254191894932E-8, + -2.67079385394061173391E-7, + 1.11738753912010371815E-6, + -4.41673835845875056359E-6, + 1.64484480707288970893E-5, + -5.75419501008210370398E-5, + 1.88502885095841655729E-4, + -5.76375574538582365885E-4, + 1.63947561694133579842E-3, + -4.32430999505057594430E-3, + 1.05464603945949983183E-2, + -2.37374148058994688156E-2, + 4.93052842396707084878E-2, + -9.49010970480476444210E-2, + 1.71620901522208775349E-1, + -3.04682672343198398683E-1, + 6.76795274409476084995E-1 + ] + +_i0B = [ + -7.23318048787475395456E-18, + -4.83050448594418207126E-18, + 4.46562142029675999901E-17, + 3.46122286769746109310E-17, + -2.82762398051658348494E-16, + -3.42548561967721913462E-16, + 1.77256013305652638360E-15, + 3.81168066935262242075E-15, + -9.55484669882830764870E-15, + -4.15056934728722208663E-14, + 1.54008621752140982691E-14, + 3.85277838274214270114E-13, + 7.18012445138366623367E-13, + -1.79417853150680611778E-12, + -1.32158118404477131188E-11, + -3.14991652796324136454E-11, + 1.18891471078464383424E-11, + 4.94060238822496958910E-10, + 3.39623202570838634515E-9, + 2.26666899049817806459E-8, + 2.04891858946906374183E-7, + 2.89137052083475648297E-6, + 6.88975834691682398426E-5, + 3.36911647825569408990E-3, + 8.04490411014108831608E-1 + ] + + +def _chbevl(x, vals): + b0 = vals[0] + b1 = 0.0 + + for i in range(1, len(vals)): + b2 = b1 + b1 = b0 + b0 = x*b1 - b2 + vals[i] + + return 0.5*(b0 - b2) + + +def _i0_1(x): + return exp(x) * _chbevl(x/2.0-2, _i0A) + + +def _i0_2(x): + return exp(x) * _chbevl(32.0/x - 2.0, _i0B) / sqrt(x) + + +def i0(x): + """ + Modified Bessel function of the first kind, order 0. + + Usually denoted :math:`I_0`. This function does broadcast, but will *not* + "up-cast" int dtype arguments unless accompanied by at least one float or + complex dtype argument (see Raises below). + + Parameters + ---------- + x : array_like, dtype float or complex + Argument of the Bessel function. + + Returns + ------- + out : ndarray, shape = x.shape, dtype = x.dtype + The modified Bessel function evaluated at each of the elements of `x`. + + Raises + ------ + TypeError: array cannot be safely cast to required type + If argument consists exclusively of int dtypes. + + See Also + -------- + scipy.special.iv, scipy.special.ive + + Notes + ----- + We use the algorithm published by Clenshaw [1]_ and referenced by + Abramowitz and Stegun [2]_, for which the function domain is + partitioned into the two intervals [0,8] and (8,inf), and Chebyshev + polynomial expansions are employed in each interval. Relative error on + the domain [0,30] using IEEE arithmetic is documented [3]_ as having a + peak of 5.8e-16 with an rms of 1.4e-16 (n = 30000). + + References + ---------- + .. [1] C. W. Clenshaw, "Chebyshev series for mathematical functions", in + *National Physical Laboratory Mathematical Tables*, vol. 5, London: + Her Majesty's Stationery Office, 1962. + .. [2] M. Abramowitz and I. A. Stegun, *Handbook of Mathematical + Functions*, 10th printing, New York: Dover, 1964, pp. 379. + http://www.math.sfu.ca/~cbm/aands/page_379.htm + .. [3] http://kobesearch.cpan.org/htdocs/Math-Cephes/Math/Cephes.html + + Examples + -------- + >>> np.i0([0.]) + array(1.0) + >>> np.i0([0., 1. + 2j]) + array([ 1.00000000+0.j , 0.18785373+0.64616944j]) + + """ + x = atleast_1d(x).copy() + y = empty_like(x) + ind = (x < 0) + x[ind] = -x[ind] + ind = (x <= 8.0) + y[ind] = _i0_1(x[ind]) + ind2 = ~ind + y[ind2] = _i0_2(x[ind2]) + return y.squeeze() + +## End of cephes code for i0 + + +def kaiser(M, beta): + """ + Return the Kaiser window. + + The Kaiser window is a taper formed by using a Bessel function. + + Parameters + ---------- + M : int + Number of points in the output window. If zero or less, an + empty array is returned. + beta : float + Shape parameter for window. + + Returns + ------- + out : array + The window, with the maximum value normalized to one (the value + one appears only if the number of samples is odd). + + See Also + -------- + bartlett, blackman, hamming, hanning + + Notes + ----- + The Kaiser window is defined as + + .. math:: w(n) = I_0\\left( \\beta \\sqrt{1-\\frac{4n^2}{(M-1)^2}} + \\right)/I_0(\\beta) + + with + + .. math:: \\quad -\\frac{M-1}{2} \\leq n \\leq \\frac{M-1}{2}, + + where :math:`I_0` is the modified zeroth-order Bessel function. + + The Kaiser was named for Jim Kaiser, who discovered a simple + approximation to the DPSS window based on Bessel functions. The Kaiser + window is a very good approximation to the Digital Prolate Spheroidal + Sequence, or Slepian window, which is the transform which maximizes the + energy in the main lobe of the window relative to total energy. + + The Kaiser can approximate many other windows by varying the beta + parameter. + + ==== ======================= + beta Window shape + ==== ======================= + 0 Rectangular + 5 Similar to a Hamming + 6 Similar to a Hanning + 8.6 Similar to a Blackman + ==== ======================= + + A beta value of 14 is probably a good starting point. Note that as beta + gets large, the window narrows, and so the number of samples needs to be + large enough to sample the increasingly narrow spike, otherwise NaNs will + get returned. + + Most references to the Kaiser window come from the signal processing + literature, where it is used as one of many windowing functions for + smoothing values. It is also known as an apodization (which means + "removing the foot", i.e. smoothing discontinuities at the beginning + and end of the sampled signal) or tapering function. + + References + ---------- + .. [1] J. F. Kaiser, "Digital Filters" - Ch 7 in "Systems analysis by + digital computer", Editors: F.F. Kuo and J.F. Kaiser, p 218-285. + John Wiley and Sons, New York, (1966). + .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", The + University of Alberta Press, 1975, pp. 177-178. + .. [3] Wikipedia, "Window function", + http://en.wikipedia.org/wiki/Window_function + + Examples + -------- + >>> np.kaiser(12, 14) + array([ 7.72686684e-06, 3.46009194e-03, 4.65200189e-02, + 2.29737120e-01, 5.99885316e-01, 9.45674898e-01, + 9.45674898e-01, 5.99885316e-01, 2.29737120e-01, + 4.65200189e-02, 3.46009194e-03, 7.72686684e-06]) + + + Plot the window and the frequency response: + + >>> from numpy.fft import fft, fftshift + >>> window = np.kaiser(51, 14) + >>> plt.plot(window) + [] + >>> plt.title("Kaiser window") + + >>> plt.ylabel("Amplitude") + + >>> plt.xlabel("Sample") + + >>> plt.show() + + >>> plt.figure() + + >>> A = fft(window, 2048) / 25.5 + >>> mag = np.abs(fftshift(A)) + >>> freq = np.linspace(-0.5, 0.5, len(A)) + >>> response = 20 * np.log10(mag) + >>> response = np.clip(response, -100, 100) + >>> plt.plot(freq, response) + [] + >>> plt.title("Frequency response of Kaiser window") + + >>> plt.ylabel("Magnitude [dB]") + + >>> plt.xlabel("Normalized frequency [cycles per sample]") + + >>> plt.axis('tight') + (-0.5, 0.5, -100.0, ...) + >>> plt.show() + + """ + from numpy.dual import i0 + if M == 1: + return np.array([1.]) + n = arange(0, M) + alpha = (M-1)/2.0 + return i0(beta * sqrt(1-((n-alpha)/alpha)**2.0))/i0(float(beta)) + + +def sinc(x): + """ + Return the sinc function. + + The sinc function is :math:`\\sin(\\pi x)/(\\pi x)`. + + Parameters + ---------- + x : ndarray + Array (possibly multi-dimensional) of values for which to to + calculate ``sinc(x)``. + + Returns + ------- + out : ndarray + ``sinc(x)``, which has the same shape as the input. + + Notes + ----- + ``sinc(0)`` is the limit value 1. + + The name sinc is short for "sine cardinal" or "sinus cardinalis". + + The sinc function is used in various signal processing applications, + including in anti-aliasing, in the construction of a Lanczos resampling + filter, and in interpolation. + + For bandlimited interpolation of discrete-time signals, the ideal + interpolation kernel is proportional to the sinc function. + + References + ---------- + .. [1] Weisstein, Eric W. "Sinc Function." From MathWorld--A Wolfram Web + Resource. http://mathworld.wolfram.com/SincFunction.html + .. [2] Wikipedia, "Sinc function", + http://en.wikipedia.org/wiki/Sinc_function + + Examples + -------- + >>> x = np.linspace(-4, 4, 41) + >>> np.sinc(x) + array([ -3.89804309e-17, -4.92362781e-02, -8.40918587e-02, + -8.90384387e-02, -5.84680802e-02, 3.89804309e-17, + 6.68206631e-02, 1.16434881e-01, 1.26137788e-01, + 8.50444803e-02, -3.89804309e-17, -1.03943254e-01, + -1.89206682e-01, -2.16236208e-01, -1.55914881e-01, + 3.89804309e-17, 2.33872321e-01, 5.04551152e-01, + 7.56826729e-01, 9.35489284e-01, 1.00000000e+00, + 9.35489284e-01, 7.56826729e-01, 5.04551152e-01, + 2.33872321e-01, 3.89804309e-17, -1.55914881e-01, + -2.16236208e-01, -1.89206682e-01, -1.03943254e-01, + -3.89804309e-17, 8.50444803e-02, 1.26137788e-01, + 1.16434881e-01, 6.68206631e-02, 3.89804309e-17, + -5.84680802e-02, -8.90384387e-02, -8.40918587e-02, + -4.92362781e-02, -3.89804309e-17]) + + >>> plt.plot(x, np.sinc(x)) + [] + >>> plt.title("Sinc Function") + + >>> plt.ylabel("Amplitude") + + >>> plt.xlabel("X") + + >>> plt.show() + + It works in 2-D as well: + + >>> x = np.linspace(-4, 4, 401) + >>> xx = np.outer(x, x) + >>> plt.imshow(np.sinc(xx)) + + + """ + x = np.asanyarray(x) + y = pi * where(x == 0, 1.0e-20, x) + return sin(y)/y + + +def msort(a): + """ + Return a copy of an array sorted along the first axis. + + Parameters + ---------- + a : array_like + Array to be sorted. + + Returns + ------- + sorted_array : ndarray + Array of the same type and shape as `a`. + + See Also + -------- + sort + + Notes + ----- + ``np.msort(a)`` is equivalent to ``np.sort(a, axis=0)``. + + """ + b = array(a, subok=True, copy=True) + b.sort(0) + return b + + +def _ureduce(a, func, **kwargs): + """ + Internal Function. + Call `func` with `a` as first argument swapping the axes to use extended + axis on functions that don't support it natively. + + Returns result and a.shape with axis dims set to 1. + + Parameters + ---------- + a : array_like + Input array or object that can be converted to an array. + func : callable + Reduction function capable of receiving a single axis argument. + It is is called with `a` as first argument followed by `kwargs`. + kwargs : keyword arguments + additional keyword arguments to pass to `func`. + + Returns + ------- + result : tuple + Result of func(a, **kwargs) and a.shape with axis dims set to 1 + which can be used to reshape the result to the same shape a ufunc with + keepdims=True would produce. + + """ + a = np.asanyarray(a) + axis = kwargs.get('axis', None) + if axis is not None: + keepdim = list(a.shape) + nd = a.ndim + axis = _nx.normalize_axis_tuple(axis, nd) + + for ax in axis: + keepdim[ax] = 1 + + if len(axis) == 1: + kwargs['axis'] = axis[0] + else: + keep = set(range(nd)) - set(axis) + nkeep = len(keep) + # swap axis that should not be reduced to front + for i, s in enumerate(sorted(keep)): + a = a.swapaxes(i, s) + # merge reduced axis + a = a.reshape(a.shape[:nkeep] + (-1,)) + kwargs['axis'] = -1 + keepdim = tuple(keepdim) + else: + keepdim = (1,) * a.ndim + + r = func(a, **kwargs) + return r, keepdim + + +def median(a, axis=None, out=None, overwrite_input=False, keepdims=False): + """ + Compute the median along the specified axis. + + Returns the median of the array elements. + + Parameters + ---------- + a : array_like + Input array or object that can be converted to an array. + axis : {int, sequence of int, None}, optional + Axis or axes along which the medians are computed. The default + is to compute the median along a flattened version of the array. + A sequence of axes is supported since version 1.9.0. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output, + but the type (of the output) will be cast if necessary. + overwrite_input : bool, optional + If True, then allow use of memory of input array `a` for + calculations. The input array will be modified by the call to + `median`. This will save memory when you do not need to preserve + the contents of the input array. Treat the input as undefined, + but it will probably be fully or partially sorted. Default is + False. If `overwrite_input` is ``True`` and `a` is not already an + `ndarray`, an error will be raised. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `arr`. + + .. versionadded:: 1.9.0 + + Returns + ------- + median : ndarray + A new array holding the result. If the input contains integers + or floats smaller than ``float64``, then the output data-type is + ``np.float64``. Otherwise, the data-type of the output is the + same as that of the input. If `out` is specified, that array is + returned instead. + + See Also + -------- + mean, percentile + + Notes + ----- + Given a vector ``V`` of length ``N``, the median of ``V`` is the + middle value of a sorted copy of ``V``, ``V_sorted`` - i + e., ``V_sorted[(N-1)/2]``, when ``N`` is odd, and the average of the + two middle values of ``V_sorted`` when ``N`` is even. + + Examples + -------- + >>> a = np.array([[10, 7, 4], [3, 2, 1]]) + >>> a + array([[10, 7, 4], + [ 3, 2, 1]]) + >>> np.median(a) + 3.5 + >>> np.median(a, axis=0) + array([ 6.5, 4.5, 2.5]) + >>> np.median(a, axis=1) + array([ 7., 2.]) + >>> m = np.median(a, axis=0) + >>> out = np.zeros_like(m) + >>> np.median(a, axis=0, out=m) + array([ 6.5, 4.5, 2.5]) + >>> m + array([ 6.5, 4.5, 2.5]) + >>> b = a.copy() + >>> np.median(b, axis=1, overwrite_input=True) + array([ 7., 2.]) + >>> assert not np.all(a==b) + >>> b = a.copy() + >>> np.median(b, axis=None, overwrite_input=True) + 3.5 + >>> assert not np.all(a==b) + + """ + r, k = _ureduce(a, func=_median, axis=axis, out=out, + overwrite_input=overwrite_input) + if keepdims: + return r.reshape(k) + else: + return r + +def _median(a, axis=None, out=None, overwrite_input=False): + # can't be reasonably be implemented in terms of percentile as we have to + # call mean to not break astropy + a = np.asanyarray(a) + + # Set the partition indexes + if axis is None: + sz = a.size + else: + sz = a.shape[axis] + if sz % 2 == 0: + szh = sz // 2 + kth = [szh - 1, szh] + else: + kth = [(sz - 1) // 2] + # Check if the array contains any nan's + if np.issubdtype(a.dtype, np.inexact): + kth.append(-1) + + if overwrite_input: + if axis is None: + part = a.ravel() + part.partition(kth) + else: + a.partition(kth, axis=axis) + part = a + else: + part = partition(a, kth, axis=axis) + + if part.shape == (): + # make 0-D arrays work + return part.item() + if axis is None: + axis = 0 + + indexer = [slice(None)] * part.ndim + index = part.shape[axis] // 2 + if part.shape[axis] % 2 == 1: + # index with slice to allow mean (below) to work + indexer[axis] = slice(index, index+1) + else: + indexer[axis] = slice(index-1, index+1) + + # Check if the array contains any nan's + if np.issubdtype(a.dtype, np.inexact) and sz > 0: + # warn and return nans like mean would + rout = mean(part[indexer], axis=axis, out=out) + return np.lib.utils._median_nancheck(part, rout, axis, out) + else: + # if there are no nans + # Use mean in odd and even case to coerce data type + # and check, use out array. + return mean(part[indexer], axis=axis, out=out) + + +def percentile(a, q, axis=None, out=None, + overwrite_input=False, interpolation='linear', keepdims=False): + """ + Compute the qth percentile of the data along the specified axis. + + Returns the qth percentile(s) of the array elements. + + Parameters + ---------- + a : array_like + Input array or object that can be converted to an array. + q : float in range of [0,100] (or sequence of floats) + Percentile to compute, which must be between 0 and 100 inclusive. + axis : {int, sequence of int, None}, optional + Axis or axes along which the percentiles are computed. The + default is to compute the percentile(s) along a flattened + version of the array. A sequence of axes is supported since + version 1.9.0. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output, + but the type (of the output) will be cast if necessary. + overwrite_input : bool, optional + If True, then allow use of memory of input array `a` + calculations. The input array will be modified by the call to + `percentile`. This will save memory when you do not need to + preserve the contents of the input array. In this case you + should not make any assumptions about the contents of the input + `a` after this function completes -- treat it as undefined. + Default is False. If `a` is not already an array, this parameter + will have no effect as `a` will be converted to an array + internally regardless of the value of this parameter. + interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'} + This optional parameter specifies the interpolation method to + use when the desired quantile lies between two data points + ``i < j``: + * linear: ``i + (j - i) * fraction``, where ``fraction`` + is the fractional part of the index surrounded by ``i`` + and ``j``. + * lower: ``i``. + * higher: ``j``. + * nearest: ``i`` or ``j``, whichever is nearest. + * midpoint: ``(i + j) / 2``. + + .. versionadded:: 1.9.0 + keepdims : bool, optional + If this is set to True, the axes which are reduced are left in + the result as dimensions with size one. With this option, the + result will broadcast correctly against the original array `a`. + + .. versionadded:: 1.9.0 + + Returns + ------- + percentile : scalar or ndarray + If `q` is a single percentile and `axis=None`, then the result + is a scalar. If multiple percentiles are given, first axis of + the result corresponds to the percentiles. The other axes are + the axes that remain after the reduction of `a`. If the input + contains integers or floats smaller than ``float64``, the output + data-type is ``float64``. Otherwise, the output data-type is the + same as that of the input. If `out` is specified, that array is + returned instead. + + See Also + -------- + mean, median, nanpercentile + + Notes + ----- + Given a vector ``V`` of length ``N``, the ``q``-th percentile of + ``V`` is the value ``q/100`` of the way from the minimum to the + maximum in a sorted copy of ``V``. The values and distances of + the two nearest neighbors as well as the `interpolation` parameter + will determine the percentile if the normalized ranking does not + match the location of ``q`` exactly. This function is the same as + the median if ``q=50``, the same as the minimum if ``q=0`` and the + same as the maximum if ``q=100``. + + Examples + -------- + >>> a = np.array([[10, 7, 4], [3, 2, 1]]) + >>> a + array([[10, 7, 4], + [ 3, 2, 1]]) + >>> np.percentile(a, 50) + 3.5 + >>> np.percentile(a, 50, axis=0) + array([[ 6.5, 4.5, 2.5]]) + >>> np.percentile(a, 50, axis=1) + array([ 7., 2.]) + >>> np.percentile(a, 50, axis=1, keepdims=True) + array([[ 7.], + [ 2.]]) + + >>> m = np.percentile(a, 50, axis=0) + >>> out = np.zeros_like(m) + >>> np.percentile(a, 50, axis=0, out=out) + array([[ 6.5, 4.5, 2.5]]) + >>> m + array([[ 6.5, 4.5, 2.5]]) + + >>> b = a.copy() + >>> np.percentile(b, 50, axis=1, overwrite_input=True) + array([ 7., 2.]) + >>> assert not np.all(a == b) + + """ + q = array(q, dtype=np.float64, copy=True) + r, k = _ureduce(a, func=_percentile, q=q, axis=axis, out=out, + overwrite_input=overwrite_input, + interpolation=interpolation) + if keepdims: + return r.reshape(q.shape + k) + else: + return r + + +def _percentile(a, q, axis=None, out=None, + overwrite_input=False, interpolation='linear', keepdims=False): + a = asarray(a) + if q.ndim == 0: + # Do not allow 0-d arrays because following code fails for scalar + zerod = True + q = q[None] + else: + zerod = False + + # avoid expensive reductions, relevant for arrays with < O(1000) elements + if q.size < 10: + for i in range(q.size): + if q[i] < 0. or q[i] > 100.: + raise ValueError("Percentiles must be in the range [0,100]") + q[i] /= 100. + else: + # faster than any() + if np.count_nonzero(q < 0.) or np.count_nonzero(q > 100.): + raise ValueError("Percentiles must be in the range [0,100]") + q /= 100. + + # prepare a for partioning + if overwrite_input: + if axis is None: + ap = a.ravel() + else: + ap = a + else: + if axis is None: + ap = a.flatten() + else: + ap = a.copy() + + if axis is None: + axis = 0 + + Nx = ap.shape[axis] + indices = q * (Nx - 1) + + # round fractional indices according to interpolation method + if interpolation == 'lower': + indices = floor(indices).astype(intp) + elif interpolation == 'higher': + indices = ceil(indices).astype(intp) + elif interpolation == 'midpoint': + indices = 0.5 * (floor(indices) + ceil(indices)) + elif interpolation == 'nearest': + indices = around(indices).astype(intp) + elif interpolation == 'linear': + pass # keep index as fraction and interpolate + else: + raise ValueError( + "interpolation can only be 'linear', 'lower' 'higher', " + "'midpoint', or 'nearest'") + + n = np.array(False, dtype=bool) # check for nan's flag + if indices.dtype == intp: # take the points along axis + # Check if the array contains any nan's + if np.issubdtype(a.dtype, np.inexact): + indices = concatenate((indices, [-1])) + + ap.partition(indices, axis=axis) + # ensure axis with qth is first + ap = np.moveaxis(ap, axis, 0) + axis = 0 + + # Check if the array contains any nan's + if np.issubdtype(a.dtype, np.inexact): + indices = indices[:-1] + n = np.isnan(ap[-1:, ...]) + + if zerod: + indices = indices[0] + r = take(ap, indices, axis=axis, out=out) + + + else: # weight the points above and below the indices + indices_below = floor(indices).astype(intp) + indices_above = indices_below + 1 + indices_above[indices_above > Nx - 1] = Nx - 1 + + # Check if the array contains any nan's + if np.issubdtype(a.dtype, np.inexact): + indices_above = concatenate((indices_above, [-1])) + + weights_above = indices - indices_below + weights_below = 1.0 - weights_above + + weights_shape = [1, ] * ap.ndim + weights_shape[axis] = len(indices) + weights_below.shape = weights_shape + weights_above.shape = weights_shape + + ap.partition(concatenate((indices_below, indices_above)), axis=axis) + + # ensure axis with qth is first + ap = np.moveaxis(ap, axis, 0) + weights_below = np.moveaxis(weights_below, axis, 0) + weights_above = np.moveaxis(weights_above, axis, 0) + axis = 0 + + # Check if the array contains any nan's + if np.issubdtype(a.dtype, np.inexact): + indices_above = indices_above[:-1] + n = np.isnan(ap[-1:, ...]) + + x1 = take(ap, indices_below, axis=axis) * weights_below + x2 = take(ap, indices_above, axis=axis) * weights_above + + # ensure axis with qth is first + x1 = np.moveaxis(x1, axis, 0) + x2 = np.moveaxis(x2, axis, 0) + + if zerod: + x1 = x1.squeeze(0) + x2 = x2.squeeze(0) + + if out is not None: + r = add(x1, x2, out=out) + else: + r = add(x1, x2) + + if np.any(n): + warnings.warn("Invalid value encountered in percentile", + RuntimeWarning, stacklevel=3) + if zerod: + if ap.ndim == 1: + if out is not None: + out[...] = a.dtype.type(np.nan) + r = out + else: + r = a.dtype.type(np.nan) + else: + r[..., n.squeeze(0)] = a.dtype.type(np.nan) + else: + if r.ndim == 1: + r[:] = a.dtype.type(np.nan) + else: + r[..., n.repeat(q.size, 0)] = a.dtype.type(np.nan) + + return r + + +def trapz(y, x=None, dx=1.0, axis=-1): + """ + Integrate along the given axis using the composite trapezoidal rule. + + Integrate `y` (`x`) along given axis. + + Parameters + ---------- + y : array_like + Input array to integrate. + x : array_like, optional + The sample points corresponding to the `y` values. If `x` is None, + the sample points are assumed to be evenly spaced `dx` apart. The + default is None. + dx : scalar, optional + The spacing between sample points when `x` is None. The default is 1. + axis : int, optional + The axis along which to integrate. + + Returns + ------- + trapz : float + Definite integral as approximated by trapezoidal rule. + + See Also + -------- + sum, cumsum + + Notes + ----- + Image [2]_ illustrates trapezoidal rule -- y-axis locations of points + will be taken from `y` array, by default x-axis distances between + points will be 1.0, alternatively they can be provided with `x` array + or with `dx` scalar. Return value will be equal to combined area under + the red lines. + + + References + ---------- + .. [1] Wikipedia page: http://en.wikipedia.org/wiki/Trapezoidal_rule + + .. [2] Illustration image: + http://en.wikipedia.org/wiki/File:Composite_trapezoidal_rule_illustration.png + + Examples + -------- + >>> np.trapz([1,2,3]) + 4.0 + >>> np.trapz([1,2,3], x=[4,6,8]) + 8.0 + >>> np.trapz([1,2,3], dx=2) + 8.0 + >>> a = np.arange(6).reshape(2, 3) + >>> a + array([[0, 1, 2], + [3, 4, 5]]) + >>> np.trapz(a, axis=0) + array([ 1.5, 2.5, 3.5]) + >>> np.trapz(a, axis=1) + array([ 2., 8.]) + + """ + y = asanyarray(y) + if x is None: + d = dx + else: + x = asanyarray(x) + if x.ndim == 1: + d = diff(x) + # reshape to correct shape + shape = [1]*y.ndim + shape[axis] = d.shape[0] + d = d.reshape(shape) + else: + d = diff(x, axis=axis) + nd = y.ndim + slice1 = [slice(None)]*nd + slice2 = [slice(None)]*nd + slice1[axis] = slice(1, None) + slice2[axis] = slice(None, -1) + try: + ret = (d * (y[slice1] + y[slice2]) / 2.0).sum(axis) + except ValueError: + # Operations didn't work, cast to ndarray + d = np.asarray(d) + y = np.asarray(y) + ret = add.reduce(d * (y[slice1]+y[slice2])/2.0, axis) + return ret + + +#always succeed +def add_newdoc(place, obj, doc): + """ + Adds documentation to obj which is in module place. + + If doc is a string add it to obj as a docstring + + If doc is a tuple, then the first element is interpreted as + an attribute of obj and the second as the docstring + (method, docstring) + + If doc is a list, then each element of the list should be a + sequence of length two --> [(method1, docstring1), + (method2, docstring2), ...] + + This routine never raises an error. + + This routine cannot modify read-only docstrings, as appear + in new-style classes or built-in functions. Because this + routine never raises an error the caller must check manually + that the docstrings were changed. + """ + try: + new = getattr(__import__(place, globals(), {}, [obj]), obj) + if isinstance(doc, str): + add_docstring(new, doc.strip()) + elif isinstance(doc, tuple): + add_docstring(getattr(new, doc[0]), doc[1].strip()) + elif isinstance(doc, list): + for val in doc: + add_docstring(getattr(new, val[0]), val[1].strip()) + except Exception: + pass + + +# Based on scitools meshgrid +def meshgrid(*xi, **kwargs): + """ + Return coordinate matrices from coordinate vectors. + + Make N-D coordinate arrays for vectorized evaluations of + N-D scalar/vector fields over N-D grids, given + one-dimensional coordinate arrays x1, x2,..., xn. + + .. versionchanged:: 1.9 + 1-D and 0-D cases are allowed. + + Parameters + ---------- + x1, x2,..., xn : array_like + 1-D arrays representing the coordinates of a grid. + indexing : {'xy', 'ij'}, optional + Cartesian ('xy', default) or matrix ('ij') indexing of output. + See Notes for more details. + + .. versionadded:: 1.7.0 + sparse : bool, optional + If True a sparse grid is returned in order to conserve memory. + Default is False. + + .. versionadded:: 1.7.0 + copy : bool, optional + If False, a view into the original arrays are returned in order to + conserve memory. Default is True. Please note that + ``sparse=False, copy=False`` will likely return non-contiguous + arrays. Furthermore, more than one element of a broadcast array + may refer to a single memory location. If you need to write to the + arrays, make copies first. + + .. versionadded:: 1.7.0 + + Returns + ------- + X1, X2,..., XN : ndarray + For vectors `x1`, `x2`,..., 'xn' with lengths ``Ni=len(xi)`` , + return ``(N1, N2, N3,...Nn)`` shaped arrays if indexing='ij' + or ``(N2, N1, N3,...Nn)`` shaped arrays if indexing='xy' + with the elements of `xi` repeated to fill the matrix along + the first dimension for `x1`, the second for `x2` and so on. + + Notes + ----- + This function supports both indexing conventions through the indexing + keyword argument. Giving the string 'ij' returns a meshgrid with + matrix indexing, while 'xy' returns a meshgrid with Cartesian indexing. + In the 2-D case with inputs of length M and N, the outputs are of shape + (N, M) for 'xy' indexing and (M, N) for 'ij' indexing. In the 3-D case + with inputs of length M, N and P, outputs are of shape (N, M, P) for + 'xy' indexing and (M, N, P) for 'ij' indexing. The difference is + illustrated by the following code snippet:: + + xv, yv = np.meshgrid(x, y, sparse=False, indexing='ij') + for i in range(nx): + for j in range(ny): + # treat xv[i,j], yv[i,j] + + xv, yv = np.meshgrid(x, y, sparse=False, indexing='xy') + for i in range(nx): + for j in range(ny): + # treat xv[j,i], yv[j,i] + + In the 1-D and 0-D case, the indexing and sparse keywords have no effect. + + See Also + -------- + index_tricks.mgrid : Construct a multi-dimensional "meshgrid" + using indexing notation. + index_tricks.ogrid : Construct an open multi-dimensional "meshgrid" + using indexing notation. + + Examples + -------- + >>> nx, ny = (3, 2) + >>> x = np.linspace(0, 1, nx) + >>> y = np.linspace(0, 1, ny) + >>> xv, yv = np.meshgrid(x, y) + >>> xv + array([[ 0. , 0.5, 1. ], + [ 0. , 0.5, 1. ]]) + >>> yv + array([[ 0., 0., 0.], + [ 1., 1., 1.]]) + >>> xv, yv = np.meshgrid(x, y, sparse=True) # make sparse output arrays + >>> xv + array([[ 0. , 0.5, 1. ]]) + >>> yv + array([[ 0.], + [ 1.]]) + + `meshgrid` is very useful to evaluate functions on a grid. + + >>> x = np.arange(-5, 5, 0.1) + >>> y = np.arange(-5, 5, 0.1) + >>> xx, yy = np.meshgrid(x, y, sparse=True) + >>> z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2) + >>> h = plt.contourf(x,y,z) + + """ + ndim = len(xi) + + copy_ = kwargs.pop('copy', True) + sparse = kwargs.pop('sparse', False) + indexing = kwargs.pop('indexing', 'xy') + + if kwargs: + raise TypeError("meshgrid() got an unexpected keyword argument '%s'" + % (list(kwargs)[0],)) + + if indexing not in ['xy', 'ij']: + raise ValueError( + "Valid values for `indexing` are 'xy' and 'ij'.") + + s0 = (1,) * ndim + output = [np.asanyarray(x).reshape(s0[:i] + (-1,) + s0[i + 1:]) + for i, x in enumerate(xi)] + + if indexing == 'xy' and ndim > 1: + # switch first and second axis + output[0].shape = (1, -1) + s0[2:] + output[1].shape = (-1, 1) + s0[2:] + + if not sparse: + # Return the full N-D matrix (not only the 1-D vector) + output = np.broadcast_arrays(*output, subok=True) + + if copy_: + output = [x.copy() for x in output] + + return output + + +def delete(arr, obj, axis=None): + """ + Return a new array with sub-arrays along an axis deleted. For a one + dimensional array, this returns those entries not returned by + `arr[obj]`. + + Parameters + ---------- + arr : array_like + Input array. + obj : slice, int or array of ints + Indicate which sub-arrays to remove. + axis : int, optional + The axis along which to delete the subarray defined by `obj`. + If `axis` is None, `obj` is applied to the flattened array. + + Returns + ------- + out : ndarray + A copy of `arr` with the elements specified by `obj` removed. Note + that `delete` does not occur in-place. If `axis` is None, `out` is + a flattened array. + + See Also + -------- + insert : Insert elements into an array. + append : Append elements at the end of an array. + + Notes + ----- + Often it is preferable to use a boolean mask. For example: + + >>> mask = np.ones(len(arr), dtype=bool) + >>> mask[[0,2,4]] = False + >>> result = arr[mask,...] + + Is equivalent to `np.delete(arr, [0,2,4], axis=0)`, but allows further + use of `mask`. + + Examples + -------- + >>> arr = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) + >>> arr + array([[ 1, 2, 3, 4], + [ 5, 6, 7, 8], + [ 9, 10, 11, 12]]) + >>> np.delete(arr, 1, 0) + array([[ 1, 2, 3, 4], + [ 9, 10, 11, 12]]) + + >>> np.delete(arr, np.s_[::2], 1) + array([[ 2, 4], + [ 6, 8], + [10, 12]]) + >>> np.delete(arr, [1,3,5], None) + array([ 1, 3, 5, 7, 8, 9, 10, 11, 12]) + + """ + wrap = None + if type(arr) is not ndarray: + try: + wrap = arr.__array_wrap__ + except AttributeError: + pass + + arr = asarray(arr) + ndim = arr.ndim + arrorder = 'F' if arr.flags.fnc else 'C' + if axis is None: + if ndim != 1: + arr = arr.ravel() + ndim = arr.ndim + axis = -1 + + if ndim == 0: + # 2013-09-24, 1.9 + warnings.warn( + "in the future the special handling of scalars will be removed " + "from delete and raise an error", DeprecationWarning, stacklevel=2) + if wrap: + return wrap(arr) + else: + return arr.copy(order=arrorder) + + axis = normalize_axis_index(axis, ndim) + + slobj = [slice(None)]*ndim + N = arr.shape[axis] + newshape = list(arr.shape) + + if isinstance(obj, slice): + start, stop, step = obj.indices(N) + xr = range(start, stop, step) + numtodel = len(xr) + + if numtodel <= 0: + if wrap: + return wrap(arr.copy(order=arrorder)) + else: + return arr.copy(order=arrorder) + + # Invert if step is negative: + if step < 0: + step = -step + start = xr[-1] + stop = xr[0] + 1 + + newshape[axis] -= numtodel + new = empty(newshape, arr.dtype, arrorder) + # copy initial chunk + if start == 0: + pass + else: + slobj[axis] = slice(None, start) + new[slobj] = arr[slobj] + # copy end chunck + if stop == N: + pass + else: + slobj[axis] = slice(stop-numtodel, None) + slobj2 = [slice(None)]*ndim + slobj2[axis] = slice(stop, None) + new[slobj] = arr[slobj2] + # copy middle pieces + if step == 1: + pass + else: # use array indexing. + keep = ones(stop-start, dtype=bool) + keep[:stop-start:step] = False + slobj[axis] = slice(start, stop-numtodel) + slobj2 = [slice(None)]*ndim + slobj2[axis] = slice(start, stop) + arr = arr[slobj2] + slobj2[axis] = keep + new[slobj] = arr[slobj2] + if wrap: + return wrap(new) + else: + return new + + _obj = obj + obj = np.asarray(obj) + # After removing the special handling of booleans and out of + # bounds values, the conversion to the array can be removed. + if obj.dtype == bool: + warnings.warn("in the future insert will treat boolean arrays and " + "array-likes as boolean index instead of casting it " + "to integer", FutureWarning, stacklevel=2) + obj = obj.astype(intp) + if isinstance(_obj, (int, long, integer)): + # optimization for a single value + obj = obj.item() + if (obj < -N or obj >= N): + raise IndexError( + "index %i is out of bounds for axis %i with " + "size %i" % (obj, axis, N)) + if (obj < 0): + obj += N + newshape[axis] -= 1 + new = empty(newshape, arr.dtype, arrorder) + slobj[axis] = slice(None, obj) + new[slobj] = arr[slobj] + slobj[axis] = slice(obj, None) + slobj2 = [slice(None)]*ndim + slobj2[axis] = slice(obj+1, None) + new[slobj] = arr[slobj2] + else: + if obj.size == 0 and not isinstance(_obj, np.ndarray): + obj = obj.astype(intp) + if not np.can_cast(obj, intp, 'same_kind'): + # obj.size = 1 special case always failed and would just + # give superfluous warnings. + # 2013-09-24, 1.9 + warnings.warn( + "using a non-integer array as obj in delete will result in an " + "error in the future", DeprecationWarning, stacklevel=2) + obj = obj.astype(intp) + keep = ones(N, dtype=bool) + + # Test if there are out of bound indices, this is deprecated + inside_bounds = (obj < N) & (obj >= -N) + if not inside_bounds.all(): + # 2013-09-24, 1.9 + warnings.warn( + "in the future out of bounds indices will raise an error " + "instead of being ignored by `numpy.delete`.", + DeprecationWarning, stacklevel=2) + obj = obj[inside_bounds] + positive_indices = obj >= 0 + if not positive_indices.all(): + warnings.warn( + "in the future negative indices will not be ignored by " + "`numpy.delete`.", FutureWarning, stacklevel=2) + obj = obj[positive_indices] + + keep[obj, ] = False + slobj[axis] = keep + new = arr[slobj] + + if wrap: + return wrap(new) + else: + return new + + +def insert(arr, obj, values, axis=None): + """ + Insert values along the given axis before the given indices. + + Parameters + ---------- + arr : array_like + Input array. + obj : int, slice or sequence of ints + Object that defines the index or indices before which `values` is + inserted. + + .. versionadded:: 1.8.0 + + Support for multiple insertions when `obj` is a single scalar or a + sequence with one element (similar to calling insert multiple + times). + values : array_like + Values to insert into `arr`. If the type of `values` is different + from that of `arr`, `values` is converted to the type of `arr`. + `values` should be shaped so that ``arr[...,obj,...] = values`` + is legal. + axis : int, optional + Axis along which to insert `values`. If `axis` is None then `arr` + is flattened first. + + Returns + ------- + out : ndarray + A copy of `arr` with `values` inserted. Note that `insert` + does not occur in-place: a new array is returned. If + `axis` is None, `out` is a flattened array. + + See Also + -------- + append : Append elements at the end of an array. + concatenate : Join a sequence of arrays along an existing axis. + delete : Delete elements from an array. + + Notes + ----- + Note that for higher dimensional inserts `obj=0` behaves very different + from `obj=[0]` just like `arr[:,0,:] = values` is different from + `arr[:,[0],:] = values`. + + Examples + -------- + >>> a = np.array([[1, 1], [2, 2], [3, 3]]) + >>> a + array([[1, 1], + [2, 2], + [3, 3]]) + >>> np.insert(a, 1, 5) + array([1, 5, 1, 2, 2, 3, 3]) + >>> np.insert(a, 1, 5, axis=1) + array([[1, 5, 1], + [2, 5, 2], + [3, 5, 3]]) + + Difference between sequence and scalars: + + >>> np.insert(a, [1], [[1],[2],[3]], axis=1) + array([[1, 1, 1], + [2, 2, 2], + [3, 3, 3]]) + >>> np.array_equal(np.insert(a, 1, [1, 2, 3], axis=1), + ... np.insert(a, [1], [[1],[2],[3]], axis=1)) + True + + >>> b = a.flatten() + >>> b + array([1, 1, 2, 2, 3, 3]) + >>> np.insert(b, [2, 2], [5, 6]) + array([1, 1, 5, 6, 2, 2, 3, 3]) + + >>> np.insert(b, slice(2, 4), [5, 6]) + array([1, 1, 5, 2, 6, 2, 3, 3]) + + >>> np.insert(b, [2, 2], [7.13, False]) # type casting + array([1, 1, 7, 0, 2, 2, 3, 3]) + + >>> x = np.arange(8).reshape(2, 4) + >>> idx = (1, 3) + >>> np.insert(x, idx, 999, axis=1) + array([[ 0, 999, 1, 2, 999, 3], + [ 4, 999, 5, 6, 999, 7]]) + + """ + wrap = None + if type(arr) is not ndarray: + try: + wrap = arr.__array_wrap__ + except AttributeError: + pass + + arr = asarray(arr) + ndim = arr.ndim + arrorder = 'F' if arr.flags.fnc else 'C' + if axis is None: + if ndim != 1: + arr = arr.ravel() + ndim = arr.ndim + axis = ndim - 1 + elif ndim == 0: + # 2013-09-24, 1.9 + warnings.warn( + "in the future the special handling of scalars will be removed " + "from insert and raise an error", DeprecationWarning, stacklevel=2) + arr = arr.copy(order=arrorder) + arr[...] = values + if wrap: + return wrap(arr) + else: + return arr + else: + axis = normalize_axis_index(axis, ndim) + slobj = [slice(None)]*ndim + N = arr.shape[axis] + newshape = list(arr.shape) + + if isinstance(obj, slice): + # turn it into a range object + indices = arange(*obj.indices(N), **{'dtype': intp}) + else: + # need to copy obj, because indices will be changed in-place + indices = np.array(obj) + if indices.dtype == bool: + # See also delete + warnings.warn( + "in the future insert will treat boolean arrays and " + "array-likes as a boolean index instead of casting it to " + "integer", FutureWarning, stacklevel=2) + indices = indices.astype(intp) + # Code after warning period: + #if obj.ndim != 1: + # raise ValueError('boolean array argument obj to insert ' + # 'must be one dimensional') + #indices = np.flatnonzero(obj) + elif indices.ndim > 1: + raise ValueError( + "index array argument obj to insert must be one dimensional " + "or scalar") + if indices.size == 1: + index = indices.item() + if index < -N or index > N: + raise IndexError( + "index %i is out of bounds for axis %i with " + "size %i" % (obj, axis, N)) + if (index < 0): + index += N + + # There are some object array corner cases here, but we cannot avoid + # that: + values = array(values, copy=False, ndmin=arr.ndim, dtype=arr.dtype) + if indices.ndim == 0: + # broadcasting is very different here, since a[:,0,:] = ... behaves + # very different from a[:,[0],:] = ...! This changes values so that + # it works likes the second case. (here a[:,0:1,:]) + values = np.moveaxis(values, 0, axis) + numnew = values.shape[axis] + newshape[axis] += numnew + new = empty(newshape, arr.dtype, arrorder) + slobj[axis] = slice(None, index) + new[slobj] = arr[slobj] + slobj[axis] = slice(index, index+numnew) + new[slobj] = values + slobj[axis] = slice(index+numnew, None) + slobj2 = [slice(None)] * ndim + slobj2[axis] = slice(index, None) + new[slobj] = arr[slobj2] + if wrap: + return wrap(new) + return new + elif indices.size == 0 and not isinstance(obj, np.ndarray): + # Can safely cast the empty list to intp + indices = indices.astype(intp) + + if not np.can_cast(indices, intp, 'same_kind'): + # 2013-09-24, 1.9 + warnings.warn( + "using a non-integer array as obj in insert will result in an " + "error in the future", DeprecationWarning, stacklevel=2) + indices = indices.astype(intp) + + indices[indices < 0] += N + + numnew = len(indices) + order = indices.argsort(kind='mergesort') # stable sort + indices[order] += np.arange(numnew) + + newshape[axis] += numnew + old_mask = ones(newshape[axis], dtype=bool) + old_mask[indices] = False + + new = empty(newshape, arr.dtype, arrorder) + slobj2 = [slice(None)]*ndim + slobj[axis] = indices + slobj2[axis] = old_mask + new[slobj] = values + new[slobj2] = arr + + if wrap: + return wrap(new) + return new + + +def append(arr, values, axis=None): + """ + Append values to the end of an array. + + Parameters + ---------- + arr : array_like + Values are appended to a copy of this array. + values : array_like + These values are appended to a copy of `arr`. It must be of the + correct shape (the same shape as `arr`, excluding `axis`). If + `axis` is not specified, `values` can be any shape and will be + flattened before use. + axis : int, optional + The axis along which `values` are appended. If `axis` is not + given, both `arr` and `values` are flattened before use. + + Returns + ------- + append : ndarray + A copy of `arr` with `values` appended to `axis`. Note that + `append` does not occur in-place: a new array is allocated and + filled. If `axis` is None, `out` is a flattened array. + + See Also + -------- + insert : Insert elements into an array. + delete : Delete elements from an array. + + Examples + -------- + >>> np.append([1, 2, 3], [[4, 5, 6], [7, 8, 9]]) + array([1, 2, 3, 4, 5, 6, 7, 8, 9]) + + When `axis` is specified, `values` must have the correct shape. + + >>> np.append([[1, 2, 3], [4, 5, 6]], [[7, 8, 9]], axis=0) + array([[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]) + >>> np.append([[1, 2, 3], [4, 5, 6]], [7, 8, 9], axis=0) + Traceback (most recent call last): + ... + ValueError: arrays must have same number of dimensions + + """ + arr = asanyarray(arr) + if axis is None: + if arr.ndim != 1: + arr = arr.ravel() + values = ravel(values) + axis = arr.ndim-1 + return concatenate((arr, values), axis=axis) diff --git a/numpy/lib/index_tricks.py b/numpy/lib/index_tricks.py new file mode 100644 index 0000000..650b37f --- /dev/null +++ b/numpy/lib/index_tricks.py @@ -0,0 +1,885 @@ +from __future__ import division, absolute_import, print_function + +import sys +import math + +import numpy.core.numeric as _nx +from numpy.core.numeric import ( + asarray, ScalarType, array, alltrue, cumprod, arange + ) +from numpy.core.numerictypes import find_common_type, issubdtype + +from . import function_base +import numpy.matrixlib as matrixlib +from .function_base import diff +from numpy.core.multiarray import ravel_multi_index, unravel_index +from numpy.lib.stride_tricks import as_strided + + +__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_(*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`:: + + mgrid = nd_grid(sparse=False) + ogrid = nd_grid(sparse=True) + + Users should use these pre-defined instances instead of using `nd_grid` + directly. + + Examples + -------- + >>> mgrid = np.lib.index_tricks.nd_grid() + >>> 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]]]) + >>> mgrid[-1:1:5j] + array([-1. , -0.5, 0. , 0.5, 1. ]) + + >>> ogrid = np.lib.index_tricks.nd_grid(sparse=True) + >>> ogrid[0:5,0:5] + [array([[0], + [1], + [2], + [3], + [4]]), array([[0, 1, 2, 3, 4]])] + + """ + + 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][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) + + def __len__(self): + return 0 + +mgrid = nd_grid(sparse=False) +ogrid = nd_grid(sparse=True) +mgrid.__doc__ = None # set in numpy.add_newdocs +ogrid.__doc__ = None # set in numpy.add_newdocs + +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 = function_base.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: + newobj = item + if ndmin > 1: + tempobj = array(newobj, copy=False, subok=True) + newobj = array(newobj, copy=False, subok=True, + ndmin=ndmin) + if trans1d != -1 and tempobj.ndim < ndmin: + k2 = ndmin-tempobj.ndim + if (trans1d < 0): + trans1d += k2 + 1 + defaxes = list(range(ndmin)) + k1 = trans1d + axes = defaxes[:k1] + defaxes[k2:] + \ + defaxes[k1:k2] + newobj = newobj.transpose(axes) + del tempobj + 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() + +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__ + + +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 +# 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(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 + + +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 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) diff --git a/numpy/lib/info.py b/numpy/lib/info.py new file mode 100644 index 0000000..8815a52 --- /dev/null +++ b/numpy/lib/info.py @@ -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 = ['*'] diff --git a/numpy/lib/mixins.py b/numpy/lib/mixins.py new file mode 100644 index 0000000..fbdc2ed --- /dev/null +++ b/numpy/lib/mixins.py @@ -0,0 +1,181 @@ +"""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. + + This class does not yet implement the special operators corresponding + to ``matmul`` (``@``), because ``np.matmul`` is not yet a NumPy ufunc. + + 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 :ref:`A Mechanism for Overriding Ufuncs + `. + + 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. + """ + # 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') + 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') diff --git a/numpy/lib/nanfunctions.py b/numpy/lib/nanfunctions.py new file mode 100644 index 0000000..b3f3bfc --- /dev/null +++ b/numpy/lib/nanfunctions.py @@ -0,0 +1,1439 @@ +""" +Functions that ignore NaN. + +Functions +--------- + +- `nanmin` -- minimum non-NaN value +- `nanmax` -- maximum non-NaN value +- `nanargmin` -- index of minimum non-NaN value +- `nanargmax` -- index of maximum non-NaN value +- `nansum` -- sum of non-NaN values +- `nanprod` -- product of non-NaN values +- `nancumsum` -- cumulative sum of non-NaN values +- `nancumprod` -- cumulative product of non-NaN values +- `nanmean` -- mean of non-NaN values +- `nanvar` -- variance of non-NaN values +- `nanstd` -- standard deviation of non-NaN values +- `nanmedian` -- median of non-NaN values +- `nanpercentile` -- qth percentile of non-NaN values + +""" +from __future__ import division, absolute_import, print_function + +import warnings +import numpy as np +from numpy.lib.function_base import _ureduce as _ureduce + + +__all__ = [ + 'nansum', 'nanmax', 'nanmin', 'nanargmax', 'nanargmin', 'nanmean', + 'nanmedian', 'nanpercentile', 'nanvar', 'nanstd', 'nanprod', + 'nancumsum', 'nancumprod' + ] + + +def _replace_nan(a, val): + """ + If `a` is of inexact type, make a copy of `a`, replace NaNs with + the `val` value, and return the copy together with a boolean mask + marking the locations where NaNs were present. If `a` is not of + inexact type, do nothing and return `a` together with a mask of None. + + Note that scalars will end up as array scalars, which is important + for using the result as the value of the out argument in some + operations. + + Parameters + ---------- + a : array-like + Input array. + val : float + NaN values are set to val before doing the operation. + + Returns + ------- + y : ndarray + If `a` is of inexact type, return a copy of `a` with the NaNs + replaced by the fill value, otherwise return `a`. + mask: {bool, None} + If `a` is of inexact type, return a boolean mask marking locations of + NaNs, otherwise return None. + + """ + a = np.array(a, subok=True, copy=True) + + if a.dtype == np.object_: + # object arrays do not support `isnan` (gh-9009), so make a guess + mask = a != a + elif issubclass(a.dtype.type, np.inexact): + mask = np.isnan(a) + else: + mask = None + + if mask is not None: + np.copyto(a, val, where=mask) + + return a, mask + + +def _copyto(a, val, mask): + """ + Replace values in `a` with NaN where `mask` is True. This differs from + copyto in that it will deal with the case where `a` is a numpy scalar. + + Parameters + ---------- + a : ndarray or numpy scalar + Array or numpy scalar some of whose values are to be replaced + by val. + val : numpy scalar + Value used a replacement. + mask : ndarray, scalar + Boolean array. Where True the corresponding element of `a` is + replaced by `val`. Broadcasts. + + Returns + ------- + res : ndarray, scalar + Array with elements replaced or scalar `val`. + + """ + if isinstance(a, np.ndarray): + np.copyto(a, val, where=mask, casting='unsafe') + else: + a = a.dtype.type(val) + return a + + +def _remove_nan_1d(arr1d, overwrite_input=False): + """ + Equivalent to arr1d[~arr1d.isnan()], but in a different order + + Presumably faster as it incurs fewer copies + + Parameters + ---------- + arr1d : ndarray + Array to remove nans from + overwrite_input : bool + True if `arr1d` can be modified in place + + Returns + ------- + res : ndarray + Array with nan elements removed + overwrite_input : bool + True if `res` can be modified in place, given the constraint on the + input + """ + + c = np.isnan(arr1d) + s = np.nonzero(c)[0] + if s.size == arr1d.size: + warnings.warn("All-NaN slice encountered", RuntimeWarning, stacklevel=4) + return arr1d[:0], True + elif s.size == 0: + return arr1d, overwrite_input + else: + if not overwrite_input: + arr1d = arr1d.copy() + # select non-nans at end of array + enonan = arr1d[-s.size:][~c[-s.size:]] + # fill nans in beginning of array with non-nans of end + arr1d[s[:enonan.size]] = enonan + + return arr1d[:-s.size], True + + +def _divide_by_count(a, b, out=None): + """ + Compute a/b ignoring invalid results. If `a` is an array the division + is done in place. If `a` is a scalar, then its type is preserved in the + output. If out is None, then then a is used instead so that the + division is in place. Note that this is only called with `a` an inexact + type. + + Parameters + ---------- + a : {ndarray, numpy scalar} + Numerator. Expected to be of inexact type but not checked. + b : {ndarray, numpy scalar} + Denominator. + out : ndarray, optional + Alternate output array in which to place the result. The default + is ``None``; if provided, it must have the same shape as the + expected output, but the type will be cast if necessary. + + Returns + ------- + ret : {ndarray, numpy scalar} + The return value is a/b. If `a` was an ndarray the division is done + in place. If `a` is a numpy scalar, the division preserves its type. + + """ + with np.errstate(invalid='ignore', divide='ignore'): + if isinstance(a, np.ndarray): + if out is None: + return np.divide(a, b, out=a, casting='unsafe') + else: + return np.divide(a, b, out=out, casting='unsafe') + else: + if out is None: + return a.dtype.type(a / b) + else: + # This is questionable, but currently a numpy scalar can + # be output to a zero dimensional array. + return np.divide(a, b, out=out, casting='unsafe') + + +def nanmin(a, axis=None, out=None, keepdims=np._NoValue): + """ + Return minimum of an array or minimum along an axis, ignoring any NaNs. + When all-NaN slices are encountered a ``RuntimeWarning`` is raised and + Nan is returned for that slice. + + Parameters + ---------- + a : array_like + Array containing numbers whose minimum is desired. If `a` is not an + array, a conversion is attempted. + axis : int, optional + Axis along which the minimum is computed. The default is to compute + the minimum of the flattened array. + out : ndarray, optional + Alternate output array in which to place the result. The default + is ``None``; if provided, it must have the same shape as the + expected output, but the type will be cast if necessary. See + `doc.ufuncs` for details. + + .. versionadded:: 1.8.0 + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `a`. + + If the value is anything but the default, then + `keepdims` will be passed through to the `min` method + of sub-classes of `ndarray`. If the sub-classes methods + does not implement `keepdims` any exceptions will be raised. + + .. versionadded:: 1.8.0 + + Returns + ------- + nanmin : ndarray + An array with the same shape as `a`, with the specified axis + removed. If `a` is a 0-d array, or if axis is None, an ndarray + scalar is returned. The same dtype as `a` is returned. + + See Also + -------- + nanmax : + The maximum value of an array along a given axis, ignoring any NaNs. + amin : + The minimum value of an array along a given axis, propagating any NaNs. + fmin : + Element-wise minimum of two arrays, ignoring any NaNs. + minimum : + Element-wise minimum of two arrays, propagating any NaNs. + isnan : + Shows which elements are Not a Number (NaN). + isfinite: + Shows which elements are neither NaN nor infinity. + + amax, fmax, maximum + + 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. + Positive infinity is treated as a very large number and negative + infinity is treated as a very small (i.e. negative) number. + + If the input has a integer type the function is equivalent to np.min. + + Examples + -------- + >>> a = np.array([[1, 2], [3, np.nan]]) + >>> np.nanmin(a) + 1.0 + >>> np.nanmin(a, axis=0) + array([ 1., 2.]) + >>> np.nanmin(a, axis=1) + array([ 1., 3.]) + + When positive infinity and negative infinity are present: + + >>> np.nanmin([1, 2, np.nan, np.inf]) + 1.0 + >>> np.nanmin([1, 2, np.nan, np.NINF]) + -inf + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + if type(a) is np.ndarray and a.dtype != np.object_: + # Fast, but not safe for subclasses of ndarray, or object arrays, + # which do not implement isnan (gh-9009), or fmin correctly (gh-8975) + res = np.fmin.reduce(a, axis=axis, out=out, **kwargs) + if np.isnan(res).any(): + warnings.warn("All-NaN slice encountered", RuntimeWarning, stacklevel=2) + else: + # Slow, but safe for subclasses of ndarray + a, mask = _replace_nan(a, +np.inf) + res = np.amin(a, axis=axis, out=out, **kwargs) + if mask is None: + return res + + # Check for all-NaN axis + mask = np.all(mask, axis=axis, **kwargs) + if np.any(mask): + res = _copyto(res, np.nan, mask) + warnings.warn("All-NaN axis encountered", RuntimeWarning, stacklevel=2) + return res + + +def nanmax(a, axis=None, out=None, keepdims=np._NoValue): + """ + Return the maximum of an array or maximum along an axis, ignoring any + NaNs. When all-NaN slices are encountered a ``RuntimeWarning`` is + raised and NaN is returned for that slice. + + Parameters + ---------- + a : array_like + Array containing numbers whose maximum is desired. If `a` is not an + array, a conversion is attempted. + axis : int, optional + Axis along which the maximum is computed. The default is to compute + the maximum of the flattened array. + out : ndarray, optional + Alternate output array in which to place the result. The default + is ``None``; if provided, it must have the same shape as the + expected output, but the type will be cast if necessary. See + `doc.ufuncs` for details. + + .. versionadded:: 1.8.0 + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `a`. + + If the value is anything but the default, then + `keepdims` will be passed through to the `max` method + of sub-classes of `ndarray`. If the sub-classes methods + does not implement `keepdims` any exceptions will be raised. + + .. versionadded:: 1.8.0 + + Returns + ------- + nanmax : ndarray + An array with the same shape as `a`, with the specified axis removed. + If `a` is a 0-d array, or if axis is None, an ndarray scalar is + returned. The same dtype as `a` is returned. + + See Also + -------- + nanmin : + The minimum value of an array along a given axis, ignoring any NaNs. + amax : + The maximum value of an array along a given axis, propagating any NaNs. + fmax : + Element-wise maximum of two arrays, ignoring any NaNs. + maximum : + Element-wise maximum of two arrays, propagating any NaNs. + isnan : + Shows which elements are Not a Number (NaN). + isfinite: + Shows which elements are neither NaN nor infinity. + + amin, fmin, minimum + + 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. + Positive infinity is treated as a very large number and negative + infinity is treated as a very small (i.e. negative) number. + + If the input has a integer type the function is equivalent to np.max. + + Examples + -------- + >>> a = np.array([[1, 2], [3, np.nan]]) + >>> np.nanmax(a) + 3.0 + >>> np.nanmax(a, axis=0) + array([ 3., 2.]) + >>> np.nanmax(a, axis=1) + array([ 2., 3.]) + + When positive infinity and negative infinity are present: + + >>> np.nanmax([1, 2, np.nan, np.NINF]) + 2.0 + >>> np.nanmax([1, 2, np.nan, np.inf]) + inf + + """ + kwargs = {} + if keepdims is not np._NoValue: + kwargs['keepdims'] = keepdims + if type(a) is np.ndarray and a.dtype != np.object_: + # Fast, but not safe for subclasses of ndarray, or object arrays, + # which do not implement isnan (gh-9009), or fmax correctly (gh-8975) + res = np.fmax.reduce(a, axis=axis, out=out, **kwargs) + if np.isnan(res).any(): + warnings.warn("All-NaN slice encountered", RuntimeWarning, stacklevel=2) + else: + # Slow, but safe for subclasses of ndarray + a, mask = _replace_nan(a, -np.inf) + res = np.amax(a, axis=axis, out=out, **kwargs) + if mask is None: + return res + + # Check for all-NaN axis + mask = np.all(mask, axis=axis, **kwargs) + if np.any(mask): + res = _copyto(res, np.nan, mask) + warnings.warn("All-NaN axis encountered", RuntimeWarning, stacklevel=2) + return res + + +def nanargmin(a, axis=None): + """ + Return the indices of the minimum values in the specified axis ignoring + NaNs. For all-NaN slices ``ValueError`` is raised. Warning: the results + cannot be trusted if a slice contains only NaNs and Infs. + + Parameters + ---------- + a : array_like + Input data. + axis : int, optional + Axis along which to operate. By default flattened input is used. + + Returns + ------- + index_array : ndarray + An array of indices or a single index value. + + See Also + -------- + argmin, nanargmax + + Examples + -------- + >>> a = np.array([[np.nan, 4], [2, 3]]) + >>> np.argmin(a) + 0 + >>> np.nanargmin(a) + 2 + >>> np.nanargmin(a, axis=0) + array([1, 1]) + >>> np.nanargmin(a, axis=1) + array([1, 0]) + + """ + a, mask = _replace_nan(a, np.inf) + res = np.argmin(a, axis=axis) + if mask is not None: + mask = np.all(mask, axis=axis) + if np.any(mask): + raise ValueError("All-NaN slice encountered") + return res + + +def nanargmax(a, axis=None): + """ + Return the indices of the maximum values in the specified axis ignoring + NaNs. For all-NaN slices ``ValueError`` is raised. Warning: the + results cannot be trusted if a slice contains only NaNs and -Infs. + + + Parameters + ---------- + a : array_like + Input data. + axis : int, optional + Axis along which to operate. By default flattened input is used. + + Returns + ------- + index_array : ndarray + An array of indices or a single index value. + + See Also + -------- + argmax, nanargmin + + Examples + -------- + >>> a = np.array([[np.nan, 4], [2, 3]]) + >>> np.argmax(a) + 0 + >>> np.nanargmax(a) + 1 + >>> np.nanargmax(a, axis=0) + array([1, 0]) + >>> np.nanargmax(a, axis=1) + array([1, 1]) + + """ + a, mask = _replace_nan(a, -np.inf) + res = np.argmax(a, axis=axis) + if mask is not None: + mask = np.all(mask, axis=axis) + if np.any(mask): + raise ValueError("All-NaN slice encountered") + return res + + +def nansum(a, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Return the sum of array elements over a given axis treating Not a + Numbers (NaNs) as zero. + + In NumPy versions <= 1.8.0 Nan is returned for slices that are all-NaN or + empty. In later versions zero is returned. + + Parameters + ---------- + a : array_like + Array containing numbers whose sum is desired. If `a` is not an + array, a conversion is attempted. + axis : int, optional + Axis along which the sum is computed. The default is to compute the + sum of the flattened array. + dtype : data-type, optional + The type of the returned array and of the accumulator in which the + elements are summed. By default, the dtype of `a` is used. An + exception is when `a` has an integer type with less precision than + the platform (u)intp. In that case, the default will be either + (u)int32 or (u)int64 depending on whether the platform is 32 or 64 + bits. For inexact inputs, dtype must be inexact. + + .. versionadded:: 1.8.0 + out : ndarray, optional + Alternate output array in which to place the result. The default + is ``None``. If provided, it must have the same shape as the + expected output, but the type will be cast if necessary. See + `doc.ufuncs` for details. The casting of NaN to integer can yield + unexpected results. + + .. versionadded:: 1.8.0 + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `a`. + + + If the value is anything but the default, then + `keepdims` will be passed through to the `mean` or `sum` methods + of sub-classes of `ndarray`. If the sub-classes methods + does not implement `keepdims` any exceptions will be raised. + + .. versionadded:: 1.8.0 + + Returns + ------- + nansum : ndarray. + A new array holding the result is returned unless `out` is + specified, in which it is returned. The result has the same + size as `a`, and the same shape as `a` if `axis` is not None + or `a` is a 1-d array. + + See Also + -------- + numpy.sum : Sum across array propagating NaNs. + isnan : Show which elements are NaN. + isfinite: Show which elements are not NaN or +/-inf. + + Notes + ----- + If both positive and negative infinity are present, the sum will be Not + A Number (NaN). + + Examples + -------- + >>> np.nansum(1) + 1 + >>> np.nansum([1]) + 1 + >>> np.nansum([1, np.nan]) + 1.0 + >>> a = np.array([[1, 1], [1, np.nan]]) + >>> np.nansum(a) + 3.0 + >>> np.nansum(a, axis=0) + array([ 2., 1.]) + >>> np.nansum([1, np.nan, np.inf]) + inf + >>> np.nansum([1, np.nan, np.NINF]) + -inf + >>> np.nansum([1, np.nan, np.inf, -np.inf]) # both +/- infinity present + nan + + """ + a, mask = _replace_nan(a, 0) + return np.sum(a, axis=axis, dtype=dtype, out=out, keepdims=keepdims) + + +def nanprod(a, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Return the product of array elements over a given axis treating Not a + Numbers (NaNs) as ones. + + One is returned for slices that are all-NaN or empty. + + .. versionadded:: 1.10.0 + + Parameters + ---------- + a : array_like + Array containing numbers whose product is desired. If `a` is not an + array, a conversion is attempted. + axis : int, optional + Axis along which the product is computed. The default is to compute + the product of the flattened array. + dtype : data-type, optional + The type of the returned array and of the accumulator in which the + elements are summed. By default, the dtype of `a` is used. An + exception is when `a` has an integer type with less precision than + the platform (u)intp. In that case, the default will be either + (u)int32 or (u)int64 depending on whether the platform is 32 or 64 + bits. For inexact inputs, dtype must be inexact. + out : ndarray, optional + Alternate output array in which to place the result. The default + is ``None``. If provided, it must have the same shape as the + expected output, but the type will be cast if necessary. See + `doc.ufuncs` for details. The casting of NaN to integer can yield + unexpected results. + keepdims : bool, optional + If True, the axes which are reduced are left in the result as + dimensions with size one. With this option, the result will + broadcast correctly against the original `arr`. + + Returns + ------- + nanprod : ndarray + A new array holding the result is returned unless `out` is + specified, in which case it is returned. + + See Also + -------- + numpy.prod : Product across array propagating NaNs. + isnan : Show which elements are NaN. + + Examples + -------- + >>> np.nanprod(1) + 1 + >>> np.nanprod([1]) + 1 + >>> np.nanprod([1, np.nan]) + 1.0 + >>> a = np.array([[1, 2], [3, np.nan]]) + >>> np.nanprod(a) + 6.0 + >>> np.nanprod(a, axis=0) + array([ 3., 2.]) + + """ + a, mask = _replace_nan(a, 1) + return np.prod(a, axis=axis, dtype=dtype, out=out, keepdims=keepdims) + + +def nancumsum(a, axis=None, dtype=None, out=None): + """ + Return the cumulative sum of array elements over a given axis treating Not a + Numbers (NaNs) as zero. The cumulative sum does not change when NaNs are + encountered and leading NaNs are replaced by zeros. + + Zeros are returned for slices that are all-NaN or empty. + + .. versionadded:: 1.12.0 + + Parameters + ---------- + a : array_like + Input array. + axis : int, optional + Axis along which the cumulative sum is computed. The default + (None) is to compute the cumsum over the flattened array. + dtype : dtype, optional + Type of the returned array and of the accumulator in which the + elements are summed. If `dtype` is not specified, it defaults + to the dtype of `a`, unless `a` has an integer dtype with a + precision less than that of the default platform integer. In + that case, the default platform integer is used. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output + but the type will be cast if necessary. See `doc.ufuncs` + (Section "Output arguments") for more details. + + Returns + ------- + nancumsum : ndarray. + A new array holding the result is returned unless `out` is + specified, in which it is returned. The result has the same + size as `a`, and the same shape as `a` if `axis` is not None + or `a` is a 1-d array. + + See Also + -------- + numpy.cumsum : Cumulative sum across array propagating NaNs. + isnan : Show which elements are NaN. + + Examples + -------- + >>> np.nancumsum(1) + array([1]) + >>> np.nancumsum([1]) + array([1]) + >>> np.nancumsum([1, np.nan]) + array([ 1., 1.]) + >>> a = np.array([[1, 2], [3, np.nan]]) + >>> np.nancumsum(a) + array([ 1., 3., 6., 6.]) + >>> np.nancumsum(a, axis=0) + array([[ 1., 2.], + [ 4., 2.]]) + >>> np.nancumsum(a, axis=1) + array([[ 1., 3.], + [ 3., 3.]]) + + """ + a, mask = _replace_nan(a, 0) + return np.cumsum(a, axis=axis, dtype=dtype, out=out) + + +def nancumprod(a, axis=None, dtype=None, out=None): + """ + Return the cumulative product of array elements over a given axis treating Not a + Numbers (NaNs) as one. The cumulative product does not change when NaNs are + encountered and leading NaNs are replaced by ones. + + Ones are returned for slices that are all-NaN or empty. + + .. versionadded:: 1.12.0 + + Parameters + ---------- + a : array_like + Input array. + axis : int, optional + Axis along which the cumulative product is computed. By default + the input is flattened. + dtype : dtype, optional + Type of the returned array, as well as of the accumulator in which + the elements are multiplied. If *dtype* is not specified, it + defaults to the dtype of `a`, unless `a` has an integer dtype with + a precision less than that of the default platform integer. In + that case, the default platform integer is used instead. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output + but the type of the resulting values will be cast if necessary. + + Returns + ------- + nancumprod : ndarray + A new array holding the result is returned unless `out` is + specified, in which case it is returned. + + See Also + -------- + numpy.cumprod : Cumulative product across array propagating NaNs. + isnan : Show which elements are NaN. + + Examples + -------- + >>> np.nancumprod(1) + array([1]) + >>> np.nancumprod([1]) + array([1]) + >>> np.nancumprod([1, np.nan]) + array([ 1., 1.]) + >>> a = np.array([[1, 2], [3, np.nan]]) + >>> np.nancumprod(a) + array([ 1., 2., 6., 6.]) + >>> np.nancumprod(a, axis=0) + array([[ 1., 2.], + [ 3., 2.]]) + >>> np.nancumprod(a, axis=1) + array([[ 1., 2.], + [ 3., 3.]]) + + """ + a, mask = _replace_nan(a, 1) + return np.cumprod(a, axis=axis, dtype=dtype, out=out) + + +def nanmean(a, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Compute the arithmetic mean along the specified axis, ignoring NaNs. + + Returns the average of the array elements. The average is taken over + the flattened array by default, otherwise over the specified axis. + `float64` intermediate and return values are used for integer inputs. + + For all-NaN slices, NaN is returned and a `RuntimeWarning` is raised. + + .. versionadded:: 1.8.0 + + Parameters + ---------- + a : array_like + Array containing numbers whose mean is desired. If `a` is not an + array, a conversion is attempted. + axis : int, optional + Axis along which the means are computed. The default is to compute + the mean of the flattened array. + dtype : data-type, optional + Type to use in computing the mean. For integer inputs, the default + is `float64`; for inexact inputs, it is the same as the input + dtype. + out : ndarray, optional + Alternate output array in which to place the result. The default + is ``None``; if provided, it must have the same shape as the + expected output, but the type will be cast if necessary. See + `doc.ufuncs` for details. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `a`. + + If the value is anything but the default, then + `keepdims` will be passed through to the `mean` or `sum` methods + of sub-classes of `ndarray`. If the sub-classes methods + does not implement `keepdims` any exceptions will be raised. + + Returns + ------- + m : ndarray, see dtype parameter above + If `out=None`, returns a new array containing the mean values, + otherwise a reference to the output array is returned. Nan is + returned for slices that contain only NaNs. + + See Also + -------- + average : Weighted average + mean : Arithmetic mean taken while not ignoring NaNs + var, nanvar + + Notes + ----- + The arithmetic mean is the sum of the non-NaN elements along the axis + divided by the number of non-NaN elements. + + Note that for floating-point input, the mean is computed using the same + precision the input has. Depending on the input data, this can cause + the results to be inaccurate, especially for `float32`. Specifying a + higher-precision accumulator using the `dtype` keyword can alleviate + this issue. + + Examples + -------- + >>> a = np.array([[1, np.nan], [3, 4]]) + >>> np.nanmean(a) + 2.6666666666666665 + >>> np.nanmean(a, axis=0) + array([ 2., 4.]) + >>> np.nanmean(a, axis=1) + array([ 1., 3.5]) + + """ + arr, mask = _replace_nan(a, 0) + if mask is None: + return np.mean(arr, axis=axis, dtype=dtype, out=out, keepdims=keepdims) + + if dtype is not None: + dtype = np.dtype(dtype) + if dtype is not None and not issubclass(dtype.type, np.inexact): + raise TypeError("If a is inexact, then dtype must be inexact") + if out is not None and not issubclass(out.dtype.type, np.inexact): + raise TypeError("If a is inexact, then out must be inexact") + + cnt = np.sum(~mask, axis=axis, dtype=np.intp, keepdims=keepdims) + tot = np.sum(arr, axis=axis, dtype=dtype, out=out, keepdims=keepdims) + avg = _divide_by_count(tot, cnt, out=out) + + isbad = (cnt == 0) + if isbad.any(): + warnings.warn("Mean of empty slice", RuntimeWarning, stacklevel=2) + # NaN is the only possible bad value, so no further + # action is needed to handle bad results. + return avg + + +def _nanmedian1d(arr1d, overwrite_input=False): + """ + Private function for rank 1 arrays. Compute the median ignoring NaNs. + See nanmedian for parameter usage + """ + arr1d, overwrite_input = _remove_nan_1d(arr1d, + overwrite_input=overwrite_input) + if arr1d.size == 0: + return np.nan + + return np.median(arr1d, overwrite_input=overwrite_input) + + +def _nanmedian(a, axis=None, out=None, overwrite_input=False): + """ + Private function that doesn't support extended axis or keepdims. + These methods are extended to this function using _ureduce + See nanmedian for parameter usage + + """ + if axis is None or a.ndim == 1: + part = a.ravel() + if out is None: + return _nanmedian1d(part, overwrite_input) + else: + out[...] = _nanmedian1d(part, overwrite_input) + return out + else: + # for small medians use sort + indexing which is still faster than + # apply_along_axis + # benchmarked with shuffled (50, 50, x) containing a few NaN + if a.shape[axis] < 600: + return _nanmedian_small(a, axis, out, overwrite_input) + result = np.apply_along_axis(_nanmedian1d, axis, a, overwrite_input) + if out is not None: + out[...] = result + return result + + +def _nanmedian_small(a, axis=None, out=None, overwrite_input=False): + """ + sort + indexing median, faster for small medians along multiple + dimensions due to the high overhead of apply_along_axis + + see nanmedian for parameter usage + """ + a = np.ma.masked_array(a, np.isnan(a)) + m = np.ma.median(a, axis=axis, overwrite_input=overwrite_input) + for i in range(np.count_nonzero(m.mask.ravel())): + warnings.warn("All-NaN slice encountered", RuntimeWarning, stacklevel=3) + if out is not None: + out[...] = m.filled(np.nan) + return out + return m.filled(np.nan) + + +def nanmedian(a, axis=None, out=None, overwrite_input=False, keepdims=np._NoValue): + """ + Compute the median along the specified axis, while ignoring NaNs. + + Returns the median of the array elements. + + .. versionadded:: 1.9.0 + + Parameters + ---------- + a : array_like + Input array or object that can be converted to an array. + axis : {int, sequence of int, None}, optional + Axis or axes along which the medians are computed. The default + is to compute the median along a flattened version of the array. + A sequence of axes is supported since version 1.9.0. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output, + but the type (of the output) will be cast if necessary. + overwrite_input : bool, optional + If True, then allow use of memory of input array `a` for + calculations. The input array will be modified by the call to + `median`. This will save memory when you do not need to preserve + the contents of the input array. Treat the input as undefined, + but it will probably be fully or partially sorted. Default is + False. If `overwrite_input` is ``True`` and `a` is not already an + `ndarray`, an error will be raised. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `a`. + + If this is anything but the default value it will be passed + through (in the special case of an empty array) to the + `mean` function of the underlying array. If the array is + a sub-class and `mean` does not have the kwarg `keepdims` this + will raise a RuntimeError. + + Returns + ------- + median : ndarray + A new array holding the result. If the input contains integers + or floats smaller than ``float64``, then the output data-type is + ``np.float64``. Otherwise, the data-type of the output is the + same as that of the input. If `out` is specified, that array is + returned instead. + + See Also + -------- + mean, median, percentile + + Notes + ----- + Given a vector ``V`` of length ``N``, the median of ``V`` is the + middle value of a sorted copy of ``V``, ``V_sorted`` - i.e., + ``V_sorted[(N-1)/2]``, when ``N`` is odd and the average of the two + middle values of ``V_sorted`` when ``N`` is even. + + Examples + -------- + >>> a = np.array([[10.0, 7, 4], [3, 2, 1]]) + >>> a[0, 1] = np.nan + >>> a + array([[ 10., nan, 4.], + [ 3., 2., 1.]]) + >>> np.median(a) + nan + >>> np.nanmedian(a) + 3.0 + >>> np.nanmedian(a, axis=0) + array([ 6.5, 2., 2.5]) + >>> np.median(a, axis=1) + array([ 7., 2.]) + >>> b = a.copy() + >>> np.nanmedian(b, axis=1, overwrite_input=True) + array([ 7., 2.]) + >>> assert not np.all(a==b) + >>> b = a.copy() + >>> np.nanmedian(b, axis=None, overwrite_input=True) + 3.0 + >>> assert not np.all(a==b) + + """ + a = np.asanyarray(a) + # apply_along_axis in _nanmedian doesn't handle empty arrays well, + # so deal them upfront + if a.size == 0: + return np.nanmean(a, axis, out=out, keepdims=keepdims) + + r, k = _ureduce(a, func=_nanmedian, axis=axis, out=out, + overwrite_input=overwrite_input) + if keepdims and keepdims is not np._NoValue: + return r.reshape(k) + else: + return r + + +def nanpercentile(a, q, axis=None, out=None, overwrite_input=False, + interpolation='linear', keepdims=np._NoValue): + """ + Compute the qth percentile of the data along the specified axis, + while ignoring nan values. + + Returns the qth percentile(s) of the array elements. + + .. versionadded:: 1.9.0 + + Parameters + ---------- + a : array_like + Input array or object that can be converted to an array. + q : float in range of [0,100] (or sequence of floats) + Percentile to compute, which must be between 0 and 100 + inclusive. + axis : {int, sequence of int, None}, optional + Axis or axes along which the percentiles are computed. The + default is to compute the percentile(s) along a flattened + version of the array. A sequence of axes is supported since + version 1.9.0. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output, + but the type (of the output) will be cast if necessary. + overwrite_input : bool, optional + If True, then allow use of memory of input array `a` for + calculations. The input array will be modified by the call to + `percentile`. This will save memory when you do not need to + preserve the contents of the input array. In this case you + should not make any assumptions about the contents of the input + `a` after this function completes -- treat it as undefined. + Default is False. If `a` is not already an array, this parameter + will have no effect as `a` will be converted to an array + internally regardless of the value of this parameter. + interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'} + This optional parameter specifies the interpolation method to + use when the desired quantile lies between two data points + ``i < j``: + * linear: ``i + (j - i) * fraction``, where ``fraction`` is + the fractional part of the index surrounded by ``i`` and + ``j``. + * lower: ``i``. + * higher: ``j``. + * nearest: ``i`` or ``j``, whichever is nearest. + * midpoint: ``(i + j) / 2``. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left in + the result as dimensions with size one. With this option, the + result will broadcast correctly against the original array `a`. + + If this is anything but the default value it will be passed + through (in the special case of an empty array) to the + `mean` function of the underlying array. If the array is + a sub-class and `mean` does not have the kwarg `keepdims` this + will raise a RuntimeError. + + Returns + ------- + percentile : scalar or ndarray + If `q` is a single percentile and `axis=None`, then the result + is a scalar. If multiple percentiles are given, first axis of + the result corresponds to the percentiles. The other axes are + the axes that remain after the reduction of `a`. If the input + contains integers or floats smaller than ``float64``, the output + data-type is ``float64``. Otherwise, the output data-type is the + same as that of the input. If `out` is specified, that array is + returned instead. + + See Also + -------- + nanmean, nanmedian, percentile, median, mean + + Notes + ----- + Given a vector ``V`` of length ``N``, the ``q``-th percentile of + ``V`` is the value ``q/100`` of the way from the minimum to the + maximum in a sorted copy of ``V``. The values and distances of + the two nearest neighbors as well as the `interpolation` parameter + will determine the percentile if the normalized ranking does not + match the location of ``q`` exactly. This function is the same as + the median if ``q=50``, the same as the minimum if ``q=0`` and the + same as the maximum if ``q=100``. + + Examples + -------- + >>> a = np.array([[10., 7., 4.], [3., 2., 1.]]) + >>> a[0][1] = np.nan + >>> a + array([[ 10., nan, 4.], + [ 3., 2., 1.]]) + >>> np.percentile(a, 50) + nan + >>> np.nanpercentile(a, 50) + 3.5 + >>> np.nanpercentile(a, 50, axis=0) + array([ 6.5, 2., 2.5]) + >>> np.nanpercentile(a, 50, axis=1, keepdims=True) + array([[ 7.], + [ 2.]]) + >>> m = np.nanpercentile(a, 50, axis=0) + >>> out = np.zeros_like(m) + >>> np.nanpercentile(a, 50, axis=0, out=out) + array([ 6.5, 2., 2.5]) + >>> m + array([ 6.5, 2. , 2.5]) + + >>> b = a.copy() + >>> np.nanpercentile(b, 50, axis=1, overwrite_input=True) + array([ 7., 2.]) + >>> assert not np.all(a==b) + + """ + + a = np.asanyarray(a) + q = np.asanyarray(q) + # apply_along_axis in _nanpercentile doesn't handle empty arrays well, + # so deal them upfront + if a.size == 0: + return np.nanmean(a, axis, out=out, keepdims=keepdims) + + r, k = _ureduce(a, func=_nanpercentile, q=q, axis=axis, out=out, + overwrite_input=overwrite_input, + interpolation=interpolation) + if keepdims and keepdims is not np._NoValue: + return r.reshape(q.shape + k) + else: + return r + + +def _nanpercentile(a, q, axis=None, out=None, overwrite_input=False, + interpolation='linear'): + """ + Private function that doesn't support extended axis or keepdims. + These methods are extended to this function using _ureduce + See nanpercentile for parameter usage + + """ + if axis is None or a.ndim == 1: + part = a.ravel() + result = _nanpercentile1d(part, q, overwrite_input, interpolation) + else: + result = np.apply_along_axis(_nanpercentile1d, axis, a, q, + overwrite_input, interpolation) + # apply_along_axis fills in collapsed axis with results. + # Move that axis to the beginning to match percentile's + # convention. + if q.ndim != 0: + result = np.moveaxis(result, axis, 0) + + if out is not None: + out[...] = result + return result + + +def _nanpercentile1d(arr1d, q, overwrite_input=False, interpolation='linear'): + """ + Private function for rank 1 arrays. Compute percentile ignoring NaNs. + See nanpercentile for parameter usage + """ + arr1d, overwrite_input = _remove_nan_1d(arr1d, + overwrite_input=overwrite_input) + if arr1d.size == 0: + return np.full(q.shape, np.nan)[()] # convert to scalar + + return np.percentile(arr1d, q, overwrite_input=overwrite_input, + interpolation=interpolation) + + +def nanvar(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue): + """ + Compute the variance along the specified axis, while ignoring NaNs. + + Returns the variance of the array elements, a measure of the spread of + a distribution. The variance is computed for the flattened array by + default, otherwise over the specified axis. + + For all-NaN slices or slices with zero degrees of freedom, NaN is + returned and a `RuntimeWarning` is raised. + + .. versionadded:: 1.8.0 + + Parameters + ---------- + a : array_like + Array containing numbers whose variance is desired. If `a` is not an + array, a conversion is attempted. + axis : int, optional + Axis along which the variance is computed. The default is to compute + the variance of the flattened array. + dtype : data-type, optional + Type to use in computing the variance. For arrays of integer type + the default is `float32`; for arrays of float types it is the same as + the array type. + out : ndarray, optional + Alternate output array in which to place the result. It must have + the same shape as the expected output, but the type is cast if + necessary. + ddof : int, optional + "Delta Degrees of Freedom": the divisor used in the calculation is + ``N - ddof``, where ``N`` represents the number of non-NaN + elements. By default `ddof` is zero. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `a`. + + + Returns + ------- + variance : ndarray, see dtype parameter above + If `out` is None, return a new array containing the variance, + otherwise return a reference to the output array. If ddof is >= the + number of non-NaN elements in a slice or the slice contains only + NaNs, then the result for that slice is NaN. + + See Also + -------- + std : Standard deviation + mean : Average + var : Variance while not ignoring NaNs + nanstd, nanmean + numpy.doc.ufuncs : Section "Output arguments" + + Notes + ----- + The variance is the average of the squared deviations from the mean, + i.e., ``var = mean(abs(x - x.mean())**2)``. + + The mean is normally calculated as ``x.sum() / N``, where ``N = len(x)``. + If, however, `ddof` is specified, the divisor ``N - ddof`` is used + instead. In standard statistical practice, ``ddof=1`` provides an + unbiased estimator of the variance of a hypothetical infinite + population. ``ddof=0`` provides a maximum likelihood estimate of the + variance for normally distributed variables. + + Note that for complex numbers, the absolute value is taken before + squaring, so that the result is always real and nonnegative. + + For floating-point input, the variance is computed using the same + precision the input has. Depending on the input data, this can cause + the results to be inaccurate, especially for `float32` (see example + below). Specifying a higher-accuracy accumulator using the ``dtype`` + keyword can alleviate this issue. + + For this function to work on sub-classes of ndarray, they must define + `sum` with the kwarg `keepdims` + + Examples + -------- + >>> a = np.array([[1, np.nan], [3, 4]]) + >>> np.var(a) + 1.5555555555555554 + >>> np.nanvar(a, axis=0) + array([ 1., 0.]) + >>> np.nanvar(a, axis=1) + array([ 0., 0.25]) + + """ + arr, mask = _replace_nan(a, 0) + if mask is None: + return np.var(arr, axis=axis, dtype=dtype, out=out, ddof=ddof, + keepdims=keepdims) + + if dtype is not None: + dtype = np.dtype(dtype) + if dtype is not None and not issubclass(dtype.type, np.inexact): + raise TypeError("If a is inexact, then dtype must be inexact") + if out is not None and not issubclass(out.dtype.type, np.inexact): + raise TypeError("If a is inexact, then out must be inexact") + + # Compute mean + if type(arr) is np.matrix: + _keepdims = np._NoValue + else: + _keepdims = True + # we need to special case matrix for reverse compatibility + # in order for this to work, these sums need to be called with + # keepdims=True, however matrix now raises an error in this case, but + # the reason that it drops the keepdims kwarg is to force keepdims=True + # so this used to work by serendipity. + cnt = np.sum(~mask, axis=axis, dtype=np.intp, keepdims=_keepdims) + avg = np.sum(arr, axis=axis, dtype=dtype, keepdims=_keepdims) + avg = _divide_by_count(avg, cnt) + + # Compute squared deviation from mean. + np.subtract(arr, avg, out=arr, casting='unsafe') + arr = _copyto(arr, 0, mask) + if issubclass(arr.dtype.type, np.complexfloating): + sqr = np.multiply(arr, arr.conj(), out=arr).real + else: + sqr = np.multiply(arr, arr, out=arr) + + # Compute variance. + var = np.sum(sqr, axis=axis, dtype=dtype, out=out, keepdims=keepdims) + if var.ndim < cnt.ndim: + # Subclasses of ndarray may ignore keepdims, so check here. + cnt = cnt.squeeze(axis) + dof = cnt - ddof + var = _divide_by_count(var, dof) + + isbad = (dof <= 0) + if np.any(isbad): + warnings.warn("Degrees of freedom <= 0 for slice.", RuntimeWarning, stacklevel=2) + # NaN, inf, or negative numbers are all possible bad + # values, so explicitly replace them with NaN. + var = _copyto(var, np.nan, isbad) + return var + + +def nanstd(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue): + """ + Compute the standard deviation along the specified axis, while + ignoring NaNs. + + Returns the standard deviation, a measure of the spread of a + distribution, of the non-NaN array elements. The standard deviation is + computed for the flattened array by default, otherwise over the + specified axis. + + For all-NaN slices or slices with zero degrees of freedom, NaN is + returned and a `RuntimeWarning` is raised. + + .. versionadded:: 1.8.0 + + Parameters + ---------- + a : array_like + Calculate the standard deviation of the non-NaN values. + axis : int, optional + Axis along which the standard deviation is computed. The default is + to compute the standard deviation of the flattened array. + dtype : dtype, optional + Type to use in computing the standard deviation. For arrays of + integer type the default is float64, for arrays of float types it + is the same as the array type. + out : ndarray, optional + Alternative output array in which to place the result. It must have + the same shape as the expected output but the type (of the + calculated values) will be cast if necessary. + ddof : int, optional + Means Delta Degrees of Freedom. The divisor used in calculations + is ``N - ddof``, where ``N`` represents the number of non-NaN + elements. By default `ddof` is zero. + + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the original `a`. + + If this value is anything but the default it is passed through + as-is to the relevant functions of the sub-classes. If these + functions do not have a `keepdims` kwarg, a RuntimeError will + be raised. + + Returns + ------- + standard_deviation : ndarray, see dtype parameter above. + If `out` is None, return a new array containing the standard + deviation, otherwise return a reference to the output array. If + ddof is >= the number of non-NaN elements in a slice or the slice + contains only NaNs, then the result for that slice is NaN. + + See Also + -------- + var, mean, std + nanvar, nanmean + numpy.doc.ufuncs : Section "Output arguments" + + Notes + ----- + The standard deviation is the square root of the average of the squared + deviations from the mean: ``std = sqrt(mean(abs(x - x.mean())**2))``. + + The average squared deviation is normally calculated as + ``x.sum() / N``, where ``N = len(x)``. If, however, `ddof` is + specified, the divisor ``N - ddof`` is used instead. In standard + statistical practice, ``ddof=1`` provides an unbiased estimator of the + variance of the infinite population. ``ddof=0`` provides a maximum + likelihood estimate of the variance for normally distributed variables. + The standard deviation computed in this function is the square root of + the estimated variance, so even with ``ddof=1``, it will not be an + unbiased estimate of the standard deviation per se. + + Note that, for complex numbers, `std` takes the absolute value before + squaring, so that the result is always real and nonnegative. + + For floating-point input, the *std* is computed using the same + precision the input has. Depending on the input data, this can cause + the results to be inaccurate, especially for float32 (see example + below). Specifying a higher-accuracy accumulator using the `dtype` + keyword can alleviate this issue. + + Examples + -------- + >>> a = np.array([[1, np.nan], [3, 4]]) + >>> np.nanstd(a) + 1.247219128924647 + >>> np.nanstd(a, axis=0) + array([ 1., 0.]) + >>> np.nanstd(a, axis=1) + array([ 0., 0.5]) + + """ + var = nanvar(a, axis=axis, dtype=dtype, out=out, ddof=ddof, + keepdims=keepdims) + if isinstance(var, np.ndarray): + std = np.sqrt(var, out=var) + else: + std = var.dtype.type(np.sqrt(var)) + return std diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py new file mode 100644 index 0000000..76b135c --- /dev/null +++ b/numpy/lib/npyio.py @@ -0,0 +1,2274 @@ +from __future__ import division, absolute_import, print_function + +import io +import sys +import os +import re +import itertools +import warnings +import weakref +from operator import itemgetter, index as opindex + +import numpy as np +from . import format +from ._datasource import DataSource +from numpy.core.multiarray import packbits, unpackbits +from ._iotools import ( + LineSplitter, NameValidator, StringConverter, ConverterError, + ConverterLockError, ConversionWarning, _is_string_like, + has_nested_fields, flatten_dtype, easy_dtype, _decode_line + ) + +from numpy.compat import ( + asbytes, asstr, asunicode, asbytes_nested, bytes, basestring, unicode, + is_pathlib_path + ) + +if sys.version_info[0] >= 3: + import pickle +else: + import cPickle as pickle + from future_builtins import map + +loads = pickle.loads + +__all__ = [ + 'savetxt', 'loadtxt', 'genfromtxt', 'ndfromtxt', 'mafromtxt', + 'recfromtxt', 'recfromcsv', 'load', 'loads', 'save', 'savez', + 'savez_compressed', 'packbits', 'unpackbits', 'fromregex', 'DataSource' + ] + + +class BagObj(object): + """ + BagObj(obj) + + Convert attribute look-ups to getitems on the object passed in. + + Parameters + ---------- + obj : class instance + Object on which attribute look-up is performed. + + Examples + -------- + >>> from numpy.lib.npyio import BagObj as BO + >>> class BagDemo(object): + ... def __getitem__(self, key): # An instance of BagObj(BagDemo) + ... # will call this method when any + ... # attribute look-up is required + ... result = "Doesn't matter what you want, " + ... return result + "you're gonna get this" + ... + >>> demo_obj = BagDemo() + >>> bagobj = BO(demo_obj) + >>> bagobj.hello_there + "Doesn't matter what you want, you're gonna get this" + >>> bagobj.I_can_be_anything + "Doesn't matter what you want, you're gonna get this" + + """ + + def __init__(self, obj): + # Use weakref to make NpzFile objects collectable by refcount + self._obj = weakref.proxy(obj) + + def __getattribute__(self, key): + try: + return object.__getattribute__(self, '_obj')[key] + except KeyError: + raise AttributeError(key) + + def __dir__(self): + """ + Enables dir(bagobj) to list the files in an NpzFile. + + This also enables tab-completion in an interpreter or IPython. + """ + return object.__getattribute__(self, '_obj').keys() + + +def zipfile_factory(file, *args, **kwargs): + """ + Create a ZipFile. + + Allows for Zip64, and the `file` argument can accept file, str, or + pathlib.Path objects. `args` and `kwargs` are passed to the zipfile.ZipFile + constructor. + """ + if is_pathlib_path(file): + file = str(file) + import zipfile + kwargs['allowZip64'] = True + return zipfile.ZipFile(file, *args, **kwargs) + + +class NpzFile(object): + """ + NpzFile(fid) + + A dictionary-like object with lazy-loading of files in the zipped + archive provided on construction. + + `NpzFile` is used to load files in the NumPy ``.npz`` data archive + format. It assumes that files in the archive have a ``.npy`` extension, + other files are ignored. + + The arrays and file strings are lazily loaded on either + getitem access using ``obj['key']`` or attribute lookup using + ``obj.f.key``. A list of all files (without ``.npy`` extensions) can + be obtained with ``obj.files`` and the ZipFile object itself using + ``obj.zip``. + + Attributes + ---------- + files : list of str + List of all files in the archive with a ``.npy`` extension. + zip : ZipFile instance + The ZipFile object initialized with the zipped archive. + f : BagObj instance + An object on which attribute can be performed as an alternative + to getitem access on the `NpzFile` instance itself. + allow_pickle : bool, optional + Allow loading pickled data. Default: True + pickle_kwargs : dict, optional + Additional keyword arguments to pass on to pickle.load. + These are only useful when loading object arrays saved on + Python 2 when using Python 3. + + Parameters + ---------- + fid : file or str + The zipped archive to open. This is either a file-like object + or a string containing the path to the archive. + own_fid : bool, optional + Whether NpzFile should close the file handle. + Requires that `fid` is a file-like object. + + Examples + -------- + >>> from tempfile import TemporaryFile + >>> outfile = TemporaryFile() + >>> x = np.arange(10) + >>> y = np.sin(x) + >>> np.savez(outfile, x=x, y=y) + >>> outfile.seek(0) + + >>> npz = np.load(outfile) + >>> isinstance(npz, np.lib.io.NpzFile) + True + >>> npz.files + ['y', 'x'] + >>> npz['x'] # getitem access + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> npz.f.x # attribute lookup + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + + """ + + def __init__(self, fid, own_fid=False, allow_pickle=True, + pickle_kwargs=None): + # Import is postponed to here since zipfile depends on gzip, an + # optional component of the so-called standard library. + _zip = zipfile_factory(fid) + self._files = _zip.namelist() + self.files = [] + self.allow_pickle = allow_pickle + self.pickle_kwargs = pickle_kwargs + for x in self._files: + if x.endswith('.npy'): + self.files.append(x[:-4]) + else: + self.files.append(x) + self.zip = _zip + self.f = BagObj(self) + if own_fid: + self.fid = fid + else: + self.fid = None + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + + def close(self): + """ + Close the file. + + """ + if self.zip is not None: + self.zip.close() + self.zip = None + if self.fid is not None: + self.fid.close() + self.fid = None + self.f = None # break reference cycle + + def __del__(self): + self.close() + + def __getitem__(self, key): + # FIXME: This seems like it will copy strings around + # more than is strictly necessary. The zipfile + # will read the string and then + # the format.read_array will copy the string + # to another place in memory. + # It would be better if the zipfile could read + # (or at least uncompress) the data + # directly into the array memory. + member = 0 + if key in self._files: + member = 1 + elif key in self.files: + member = 1 + key += '.npy' + if member: + bytes = self.zip.open(key) + magic = bytes.read(len(format.MAGIC_PREFIX)) + bytes.close() + if magic == format.MAGIC_PREFIX: + bytes = self.zip.open(key) + return format.read_array(bytes, + allow_pickle=self.allow_pickle, + pickle_kwargs=self.pickle_kwargs) + else: + return self.zip.read(key) + else: + raise KeyError("%s is not a file in the archive" % key) + + def __iter__(self): + return iter(self.files) + + def items(self): + """ + Return a list of tuples, with each tuple (filename, array in file). + + """ + return [(f, self[f]) for f in self.files] + + def iteritems(self): + """Generator that returns tuples (filename, array in file).""" + for f in self.files: + yield (f, self[f]) + + def keys(self): + """Return files in the archive with a ``.npy`` extension.""" + return self.files + + def iterkeys(self): + """Return an iterator over the files in the archive.""" + return self.__iter__() + + def __contains__(self, key): + return self.files.__contains__(key) + + +def load(file, mmap_mode=None, allow_pickle=True, fix_imports=True, + encoding='ASCII'): + """ + Load arrays or pickled objects from ``.npy``, ``.npz`` or pickled files. + + Parameters + ---------- + file : file-like object, string, or pathlib.Path + The file to read. File-like objects must support the + ``seek()`` and ``read()`` methods. Pickled files require that the + file-like object support the ``readline()`` method as well. + mmap_mode : {None, 'r+', 'r', 'w+', 'c'}, optional + If not None, then memory-map the file, using the given mode (see + `numpy.memmap` for a detailed description of the modes). A + memory-mapped array is kept on disk. However, it can be accessed + and sliced like any ndarray. Memory mapping is especially useful + for accessing small fragments of large files without reading the + entire file into memory. + allow_pickle : bool, optional + Allow loading pickled object arrays stored in npy files. Reasons for + disallowing pickles include security, as loading pickled data can + execute arbitrary code. If pickles are disallowed, loading object + arrays will fail. + Default: True + fix_imports : bool, optional + Only useful when loading Python 2 generated pickled files on Python 3, + which includes npy/npz files containing object arrays. If `fix_imports` + is True, pickle will try to map the old Python 2 names to the new names + used in Python 3. + encoding : str, optional + What encoding to use when reading Python 2 strings. Only useful when + loading Python 2 generated pickled files in Python 3, which includes + npy/npz files containing object arrays. Values other than 'latin1', + 'ASCII', and 'bytes' are not allowed, as they can corrupt numerical + data. Default: 'ASCII' + + Returns + ------- + result : array, tuple, dict, etc. + Data stored in the file. For ``.npz`` files, the returned instance + of NpzFile class must be closed to avoid leaking file descriptors. + + Raises + ------ + IOError + If the input file does not exist or cannot be read. + ValueError + The file contains an object array, but allow_pickle=False given. + + See Also + -------- + save, savez, savez_compressed, loadtxt + memmap : Create a memory-map to an array stored in a file on disk. + lib.format.open_memmap : Create or load a memory-mapped ``.npy`` file. + + Notes + ----- + - If the file contains pickle data, then whatever object is stored + in the pickle is returned. + - If the file is a ``.npy`` file, then a single array is returned. + - If the file is a ``.npz`` file, then a dictionary-like object is + returned, containing ``{filename: array}`` key-value pairs, one for + each file in the archive. + - If the file is a ``.npz`` file, the returned value supports the + context manager protocol in a similar fashion to the open function:: + + with load('foo.npz') as data: + a = data['a'] + + The underlying file descriptor is closed when exiting the 'with' + block. + + Examples + -------- + Store data to disk, and load it again: + + >>> np.save('/tmp/123', np.array([[1, 2, 3], [4, 5, 6]])) + >>> np.load('/tmp/123.npy') + array([[1, 2, 3], + [4, 5, 6]]) + + Store compressed data to disk, and load it again: + + >>> a=np.array([[1, 2, 3], [4, 5, 6]]) + >>> b=np.array([1, 2]) + >>> np.savez('/tmp/123.npz', a=a, b=b) + >>> data = np.load('/tmp/123.npz') + >>> data['a'] + array([[1, 2, 3], + [4, 5, 6]]) + >>> data['b'] + array([1, 2]) + >>> data.close() + + Mem-map the stored array, and then access the second row + directly from disk: + + >>> X = np.load('/tmp/123.npy', mmap_mode='r') + >>> X[1, :] + memmap([4, 5, 6]) + + """ + own_fid = False + if isinstance(file, basestring): + fid = open(file, "rb") + own_fid = True + elif is_pathlib_path(file): + fid = file.open("rb") + own_fid = True + else: + fid = file + + if encoding not in ('ASCII', 'latin1', 'bytes'): + # The 'encoding' value for pickle also affects what encoding + # the serialized binary data of NumPy arrays is loaded + # in. Pickle does not pass on the encoding information to + # NumPy. The unpickling code in numpy.core.multiarray is + # written to assume that unicode data appearing where binary + # should be is in 'latin1'. 'bytes' is also safe, as is 'ASCII'. + # + # Other encoding values can corrupt binary data, and we + # purposefully disallow them. For the same reason, the errors= + # argument is not exposed, as values other than 'strict' + # result can similarly silently corrupt numerical data. + raise ValueError("encoding must be 'ASCII', 'latin1', or 'bytes'") + + if sys.version_info[0] >= 3: + pickle_kwargs = dict(encoding=encoding, fix_imports=fix_imports) + else: + # Nothing to do on Python 2 + pickle_kwargs = {} + + try: + # Code to distinguish from NumPy binary files and pickles. + _ZIP_PREFIX = b'PK\x03\x04' + N = len(format.MAGIC_PREFIX) + magic = fid.read(N) + # If the file size is less than N, we need to make sure not + # to seek past the beginning of the file + fid.seek(-min(N, len(magic)), 1) # back-up + if magic.startswith(_ZIP_PREFIX): + # zip-file (assume .npz) + # Transfer file ownership to NpzFile + tmp = own_fid + own_fid = False + return NpzFile(fid, own_fid=tmp, allow_pickle=allow_pickle, + pickle_kwargs=pickle_kwargs) + elif magic == format.MAGIC_PREFIX: + # .npy file + if mmap_mode: + return format.open_memmap(file, mode=mmap_mode) + else: + return format.read_array(fid, allow_pickle=allow_pickle, + pickle_kwargs=pickle_kwargs) + else: + # Try a pickle + if not allow_pickle: + raise ValueError("allow_pickle=False, but file does not contain " + "non-pickled data") + try: + return pickle.load(fid, **pickle_kwargs) + except Exception: + raise IOError( + "Failed to interpret file %s as a pickle" % repr(file)) + finally: + if own_fid: + fid.close() + + +def save(file, arr, allow_pickle=True, fix_imports=True): + """ + Save an array to a binary file in NumPy ``.npy`` format. + + Parameters + ---------- + file : file, str, or pathlib.Path + File or filename to which the data is saved. If file is a file-object, + then the filename is unchanged. If file is a string or Path, a ``.npy`` + extension will be appended to the file name if it does not already + have one. + arr : array_like + Array data to be saved. + allow_pickle : bool, optional + Allow saving object arrays using Python pickles. Reasons for disallowing + pickles include security (loading pickled data can execute arbitrary + code) and portability (pickled objects may not be loadable on different + Python installations, for example if the stored objects require libraries + that are not available, and not all pickled data is compatible between + Python 2 and Python 3). + Default: True + fix_imports : bool, optional + Only useful in forcing objects in object arrays on Python 3 to be + pickled in a Python 2 compatible way. If `fix_imports` is True, pickle + will try to map the new Python 3 names to the old module names used in + Python 2, so that the pickle data stream is readable with Python 2. + + See Also + -------- + savez : Save several arrays into a ``.npz`` archive + savetxt, load + + Notes + ----- + For a description of the ``.npy`` format, see the module docstring + of `numpy.lib.format` or the NumPy Enhancement Proposal + http://docs.scipy.org/doc/numpy/neps/npy-format.html + + Examples + -------- + >>> from tempfile import TemporaryFile + >>> outfile = TemporaryFile() + + >>> x = np.arange(10) + >>> np.save(outfile, x) + + >>> outfile.seek(0) # Only needed here to simulate closing & reopening file + >>> np.load(outfile) + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + + """ + own_fid = False + if isinstance(file, basestring): + if not file.endswith('.npy'): + file = file + '.npy' + fid = open(file, "wb") + own_fid = True + elif is_pathlib_path(file): + if not file.name.endswith('.npy'): + file = file.parent / (file.name + '.npy') + fid = file.open("wb") + own_fid = True + else: + fid = file + + if sys.version_info[0] >= 3: + pickle_kwargs = dict(fix_imports=fix_imports) + else: + # Nothing to do on Python 2 + pickle_kwargs = None + + try: + arr = np.asanyarray(arr) + format.write_array(fid, arr, allow_pickle=allow_pickle, + pickle_kwargs=pickle_kwargs) + finally: + if own_fid: + fid.close() + + +def savez(file, *args, **kwds): + """ + Save several arrays into a single file in uncompressed ``.npz`` format. + + If arguments are passed in with no keywords, the corresponding variable + names, in the ``.npz`` file, are 'arr_0', 'arr_1', etc. If keyword + arguments are given, the corresponding variable names, in the ``.npz`` + file will match the keyword names. + + Parameters + ---------- + file : str or file + Either the file name (string) or an open file (file-like object) + where the data will be saved. If file is a string or a Path, the + ``.npz`` extension will be appended to the file name if it is not + already there. + args : Arguments, optional + Arrays to save to the file. Since it is not possible for Python to + know the names of the arrays outside `savez`, the arrays will be saved + with names "arr_0", "arr_1", and so on. These arguments can be any + expression. + kwds : Keyword arguments, optional + Arrays to save to the file. Arrays will be saved in the file with the + keyword names. + + Returns + ------- + None + + See Also + -------- + save : Save a single array to a binary file in NumPy format. + savetxt : Save an array to a file as plain text. + savez_compressed : Save several arrays into a compressed ``.npz`` archive + + Notes + ----- + The ``.npz`` file format is a zipped archive of files named after the + variables they contain. The archive is not compressed and each file + in the archive contains one variable in ``.npy`` format. For a + description of the ``.npy`` format, see `numpy.lib.format` or the + NumPy Enhancement Proposal + http://docs.scipy.org/doc/numpy/neps/npy-format.html + + When opening the saved ``.npz`` file with `load` a `NpzFile` object is + returned. This is a dictionary-like object which can be queried for + its list of arrays (with the ``.files`` attribute), and for the arrays + themselves. + + Examples + -------- + >>> from tempfile import TemporaryFile + >>> outfile = TemporaryFile() + >>> x = np.arange(10) + >>> y = np.sin(x) + + Using `savez` with \\*args, the arrays are saved with default names. + + >>> np.savez(outfile, x, y) + >>> outfile.seek(0) # Only needed here to simulate closing & reopening file + >>> npzfile = np.load(outfile) + >>> npzfile.files + ['arr_1', 'arr_0'] + >>> npzfile['arr_0'] + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + + Using `savez` with \\**kwds, the arrays are saved with the keyword names. + + >>> outfile = TemporaryFile() + >>> np.savez(outfile, x=x, y=y) + >>> outfile.seek(0) + >>> npzfile = np.load(outfile) + >>> npzfile.files + ['y', 'x'] + >>> npzfile['x'] + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + + """ + _savez(file, args, kwds, False) + + +def savez_compressed(file, *args, **kwds): + """ + Save several arrays into a single file in compressed ``.npz`` format. + + If keyword arguments are given, then filenames are taken from the keywords. + If arguments are passed in with no keywords, then stored file names are + arr_0, arr_1, etc. + + Parameters + ---------- + file : str or file + Either the file name (string) or an open file (file-like object) + where the data will be saved. If file is a string or a Path, the + ``.npz`` extension will be appended to the file name if it is not + already there. + args : Arguments, optional + Arrays to save to the file. Since it is not possible for Python to + know the names of the arrays outside `savez`, the arrays will be saved + with names "arr_0", "arr_1", and so on. These arguments can be any + expression. + kwds : Keyword arguments, optional + Arrays to save to the file. Arrays will be saved in the file with the + keyword names. + + Returns + ------- + None + + See Also + -------- + numpy.save : Save a single array to a binary file in NumPy format. + numpy.savetxt : Save an array to a file as plain text. + numpy.savez : Save several arrays into an uncompressed ``.npz`` file format + numpy.load : Load the files created by savez_compressed. + + Notes + ----- + The ``.npz`` file format is a zipped archive of files named after the + variables they contain. The archive is compressed with + ``zipfile.ZIP_DEFLATED`` and each file in the archive contains one variable + in ``.npy`` format. For a description of the ``.npy`` format, see + `numpy.lib.format` or the NumPy Enhancement Proposal + http://docs.scipy.org/doc/numpy/neps/npy-format.html + + When opening the saved ``.npz`` file with `load` a `NpzFile` object is + returned. This is a dictionary-like object which can be queried for + its list of arrays (with the ``.files`` attribute), and for the arrays + themselves. + + Examples + -------- + >>> test_array = np.random.rand(3, 2) + >>> test_vector = np.random.rand(4) + >>> np.savez_compressed('/tmp/123', a=test_array, b=test_vector) + >>> loaded = np.load('/tmp/123.npz') + >>> print(np.array_equal(test_array, loaded['a'])) + True + >>> print(np.array_equal(test_vector, loaded['b'])) + True + + """ + _savez(file, args, kwds, True) + + +def _savez(file, args, kwds, compress, allow_pickle=True, pickle_kwargs=None): + # Import is postponed to here since zipfile depends on gzip, an optional + # component of the so-called standard library. + import zipfile + + if isinstance(file, basestring): + if not file.endswith('.npz'): + file = file + '.npz' + elif is_pathlib_path(file): + if not file.name.endswith('.npz'): + file = file.parent / (file.name + '.npz') + + namedict = kwds + for i, val in enumerate(args): + key = 'arr_%d' % i + if key in namedict.keys(): + raise ValueError( + "Cannot use un-named variables and keyword %s" % key) + namedict[key] = val + + if compress: + compression = zipfile.ZIP_DEFLATED + else: + compression = zipfile.ZIP_STORED + + zipf = zipfile_factory(file, mode="w", compression=compression) + + if sys.version_info >= (3, 6): + # Since Python 3.6 it is possible to write directly to a ZIP file. + for key, val in namedict.items(): + fname = key + '.npy' + val = np.asanyarray(val) + force_zip64 = val.nbytes >= 2**30 + with zipf.open(fname, 'w', force_zip64=force_zip64) as fid: + format.write_array(fid, val, + allow_pickle=allow_pickle, + pickle_kwargs=pickle_kwargs) + else: + # Stage arrays in a temporary file on disk, before writing to zip. + + # Import deferred for startup time improvement + import tempfile + # Since target file might be big enough to exceed capacity of a global + # temporary directory, create temp file side-by-side with the target file. + file_dir, file_prefix = os.path.split(file) if _is_string_like(file) else (None, 'tmp') + fd, tmpfile = tempfile.mkstemp(prefix=file_prefix, dir=file_dir, suffix='-numpy.npy') + os.close(fd) + try: + for key, val in namedict.items(): + fname = key + '.npy' + fid = open(tmpfile, 'wb') + try: + format.write_array(fid, np.asanyarray(val), + allow_pickle=allow_pickle, + pickle_kwargs=pickle_kwargs) + fid.close() + fid = None + zipf.write(tmpfile, arcname=fname) + except IOError as exc: + raise IOError("Failed to write to %s: %s" % (tmpfile, exc)) + finally: + if fid: + fid.close() + finally: + os.remove(tmpfile) + + zipf.close() + + +def _getconv(dtype): + """ Find the correct dtype converter. Adapted from matplotlib """ + + def floatconv(x): + x.lower() + if '0x' in x: + return float.fromhex(x) + return float(x) + + typ = dtype.type + if issubclass(typ, np.bool_): + return lambda x: bool(int(x)) + if issubclass(typ, np.uint64): + return np.uint64 + if issubclass(typ, np.int64): + return np.int64 + if issubclass(typ, np.integer): + return lambda x: int(float(x)) + elif issubclass(typ, np.longdouble): + return np.longdouble + elif issubclass(typ, np.floating): + return floatconv + elif issubclass(typ, complex): + return lambda x: complex(asstr(x)) + elif issubclass(typ, np.bytes_): + return asbytes + elif issubclass(typ, np.unicode_): + return asunicode + else: + return asstr + +# amount of lines loadtxt reads in one chunk, can be overriden for testing +_loadtxt_chunksize = 50000 + +def loadtxt(fname, dtype=float, comments='#', delimiter=None, + converters=None, skiprows=0, usecols=None, unpack=False, + ndmin=0, encoding='bytes'): + """ + Load data from a text file. + + Each row in the text file must have the same number of values. + + Parameters + ---------- + fname : file, str, or pathlib.Path + File, filename, or generator to read. If the filename extension is + ``.gz`` or ``.bz2``, the file is first decompressed. Note that + generators should return byte strings for Python 3k. + dtype : data-type, optional + Data-type of the resulting array; default: float. If this is a + structured data-type, the resulting array will be 1-dimensional, and + each row will be interpreted as an element of the array. In this + case, the number of columns used must match the number of fields in + the data-type. + comments : str or sequence of str, optional + The characters or list of characters used to indicate the start of a + comment. For backwards compatibility, byte strings will be decoded as + 'latin1'. The default is '#'. + delimiter : str, optional + The string used to separate values. For backwards compatibility, byte + strings will be decoded as 'latin1'. The default is whitespace. + converters : dict, optional + A dictionary mapping column number to a function that will convert + that column to a float. E.g., if column 0 is a date string: + ``converters = {0: datestr2num}``. Converters can also be used to + provide a default value for missing data (but see also `genfromtxt`): + ``converters = {3: lambda s: float(s.strip() or 0)}``. Default: None. + skiprows : int, optional + Skip the first `skiprows` lines; default: 0. + usecols : int or sequence, optional + Which columns to read, with 0 being the first. For example, + usecols = (1,4,5) will extract the 2nd, 5th and 6th columns. + The default, None, results in all columns being read. + + .. versionchanged:: 1.11.0 + When a single column has to be read it is possible to use + an integer instead of a tuple. E.g ``usecols = 3`` reads the + fourth column the same way as `usecols = (3,)`` would. + unpack : bool, optional + If True, the returned array is transposed, so that arguments may be + unpacked using ``x, y, z = loadtxt(...)``. When used with a structured + data-type, arrays are returned for each field. Default is False. + ndmin : int, optional + The returned array will have at least `ndmin` dimensions. + Otherwise mono-dimensional axes will be squeezed. + Legal values: 0 (default), 1 or 2. + + .. versionadded:: 1.6.0 + encoding : str, optional + Encoding used to decode the inputfile. Does not apply to input streams. + The special value 'bytes' enables backward compatibility workarounds + that ensures you receive byte arrays as results if possible and passes + latin1 encoded strings to converters. Override this value to receive + unicode arrays and pass strings as input to converters. If set to None + the system default is used. The default value is 'bytes'. + + .. versionadded:: 1.14.0 + + Returns + ------- + out : ndarray + Data read from the text file. + + See Also + -------- + load, fromstring, fromregex + genfromtxt : Load data with missing values handled as specified. + scipy.io.loadmat : reads MATLAB data files + + Notes + ----- + This function aims to be a fast reader for simply formatted files. The + `genfromtxt` function provides more sophisticated handling of, e.g., + lines with missing values. + + .. versionadded:: 1.10.0 + + The strings produced by the Python float.hex method can be used as + input for floats. + + Examples + -------- + >>> from io import StringIO # StringIO behaves like a file object + >>> c = StringIO("0 1\\n2 3") + >>> np.loadtxt(c) + array([[ 0., 1.], + [ 2., 3.]]) + + >>> d = StringIO("M 21 72\\nF 35 58") + >>> np.loadtxt(d, dtype={'names': ('gender', 'age', 'weight'), + ... 'formats': ('S1', 'i4', 'f4')}) + array([('M', 21, 72.0), ('F', 35, 58.0)], + dtype=[('gender', '|S1'), ('age', '>> c = StringIO("1,0,2\\n3,0,4") + >>> x, y = np.loadtxt(c, delimiter=',', usecols=(0, 2), unpack=True) + >>> x + array([ 1., 3.]) + >>> y + array([ 2., 4.]) + + """ + # Type conversions for Py3 convenience + if comments is not None: + if isinstance(comments, (basestring, bytes)): + comments = [comments] + comments = [_decode_line(x) for x in comments] + # Compile regex for comments beforehand + comments = (re.escape(comment) for comment in comments) + regex_comments = re.compile('|'.join(comments)) + + if delimiter is not None: + delimiter = _decode_line(delimiter) + + user_converters = converters + + if encoding == 'bytes': + encoding = None + byte_converters = True + else: + byte_converters = False + + if usecols is not None: + # Allow usecols to be a single int or a sequence of ints + try: + usecols_as_list = list(usecols) + except TypeError: + usecols_as_list = [usecols] + for col_idx in usecols_as_list: + try: + opindex(col_idx) + except TypeError as e: + e.args = ( + "usecols must be an int or a sequence of ints but " + "it contains at least one element of type %s" % + type(col_idx), + ) + raise + # Fall back to existing code + usecols = usecols_as_list + + fown = False + try: + if is_pathlib_path(fname): + fname = str(fname) + if _is_string_like(fname): + fh = np.lib._datasource.open(fname, 'rt', encoding=encoding) + fencoding = getattr(fh, 'encoding', 'latin1') + fh = iter(fh) + fown = True + else: + fh = iter(fname) + fencoding = getattr(fname, 'encoding', 'latin1') + except TypeError: + raise ValueError('fname must be a string, file handle, or generator') + + # input may be a python2 io stream + if encoding is not None: + fencoding = encoding + # we must assume local encoding + # TOOD emit portability warning? + elif fencoding is None: + import locale + fencoding = locale.getpreferredencoding() + + # not to be confused with the flatten_dtype we import... + def flatten_dtype_internal(dt): + """Unpack a structured data-type, and produce re-packing info.""" + if dt.names is None: + # If the dtype is flattened, return. + # If the dtype has a shape, the dtype occurs + # in the list more than once. + shape = dt.shape + if len(shape) == 0: + return ([dt.base], None) + else: + packing = [(shape[-1], list)] + if len(shape) > 1: + for dim in dt.shape[-2::-1]: + packing = [(dim*packing[0][0], packing*dim)] + return ([dt.base] * int(np.prod(dt.shape)), packing) + else: + types = [] + packing = [] + for field in dt.names: + tp, bytes = dt.fields[field] + flat_dt, flat_packing = flatten_dtype_internal(tp) + types.extend(flat_dt) + # Avoid extra nesting for subarrays + if tp.ndim > 0: + packing.extend(flat_packing) + else: + packing.append((len(flat_dt), flat_packing)) + return (types, packing) + + def pack_items(items, packing): + """Pack items into nested lists based on re-packing info.""" + if packing is None: + return items[0] + elif packing is tuple: + return tuple(items) + elif packing is list: + return list(items) + else: + start = 0 + ret = [] + for length, subpacking in packing: + ret.append(pack_items(items[start:start+length], subpacking)) + start += length + return tuple(ret) + + def split_line(line): + """Chop off comments, strip, and split at delimiter. """ + line = _decode_line(line, encoding=encoding) + + if comments is not None: + line = regex_comments.split(line, maxsplit=1)[0] + line = line.strip('\r\n') + if line: + return line.split(delimiter) + else: + return [] + + def read_data(chunk_size): + """Parse each line, including the first. + + The file read, `fh`, is a global defined above. + + Parameters + ---------- + chunk_size : int + At most `chunk_size` lines are read at a time, with iteration + until all lines are read. + + """ + X = [] + for i, line in enumerate(itertools.chain([first_line], fh)): + vals = split_line(line) + if len(vals) == 0: + continue + if usecols: + vals = [vals[j] for j in usecols] + if len(vals) != N: + line_num = i + skiprows + 1 + raise ValueError("Wrong number of columns at line %d" + % line_num) + + # Convert each value according to its column and store + items = [conv(val) for (conv, val) in zip(converters, vals)] + + # Then pack it according to the dtype's nesting + items = pack_items(items, packing) + X.append(items) + if len(X) > chunk_size: + yield X + X = [] + if X: + yield X + + try: + # Make sure we're dealing with a proper dtype + dtype = np.dtype(dtype) + defconv = _getconv(dtype) + + # Skip the first `skiprows` lines + for i in range(skiprows): + next(fh) + + # Read until we find a line with some values, and use + # it to estimate the number of columns, N. + first_vals = None + try: + while not first_vals: + first_line = next(fh) + first_vals = split_line(first_line) + except StopIteration: + # End of lines reached + first_line = '' + first_vals = [] + warnings.warn('loadtxt: Empty input file: "%s"' % fname, stacklevel=2) + N = len(usecols or first_vals) + + dtype_types, packing = flatten_dtype_internal(dtype) + if len(dtype_types) > 1: + # We're dealing with a structured array, each field of + # the dtype matches a column + converters = [_getconv(dt) for dt in dtype_types] + else: + # All fields have the same dtype + converters = [defconv for i in range(N)] + if N > 1: + packing = [(N, tuple)] + + # By preference, use the converters specified by the user + for i, conv in (user_converters or {}).items(): + if usecols: + try: + i = usecols.index(i) + except ValueError: + # Unused converter specified + continue + if byte_converters: + # converters may use decode to workaround numpy's old behaviour, + # so encode the string again before passing to the user converter + def tobytes_first(x, conv): + if type(x) is bytes: + return conv(x) + return conv(x.encode("latin1")) + import functools + converters[i] = functools.partial(tobytes_first, conv=conv) + else: + converters[i] = conv + + converters = [conv if conv is not bytes else + lambda x: x.encode(fencoding) for conv in converters] + + # read data in chunks and fill it into an array via resize + # over-allocating and shrinking the array later may be faster but is + # probably not relevant compared to the cost of actually reading and + # converting the data + X = None + for x in read_data(_loadtxt_chunksize): + if X is None: + X = np.array(x, dtype) + else: + nshape = list(X.shape) + pos = nshape[0] + nshape[0] += len(x) + X.resize(nshape) + X[pos:, ...] = x + finally: + if fown: + fh.close() + # recursive closures have a cyclic reference to themselves, which + # requires gc to collect (gh-10620). To avoid this problem, for + # performance and PyPy friendliness, we break the cycle: + flatten_dtype_internal = None + pack_items = None + + if X is None: + X = np.array([], dtype) + + # Multicolumn data are returned with shape (1, N, M), i.e. + # (1, 1, M) for a single row - remove the singleton dimension there + if X.ndim == 3 and X.shape[:2] == (1, 1): + X.shape = (1, -1) + + # Verify that the array has at least dimensions `ndmin`. + # Check correctness of the values of `ndmin` + if ndmin not in [0, 1, 2]: + raise ValueError('Illegal value of ndmin keyword: %s' % ndmin) + # Tweak the size and shape of the arrays - remove extraneous dimensions + if X.ndim > ndmin: + X = np.squeeze(X) + # and ensure we have the minimum number of dimensions asked for + # - has to be in this order for the odd case ndmin=1, X.squeeze().ndim=0 + if X.ndim < ndmin: + if ndmin == 1: + X = np.atleast_1d(X) + elif ndmin == 2: + X = np.atleast_2d(X).T + + if unpack: + if len(dtype_types) > 1: + # For structured arrays, return an array for each field. + return [X[field] for field in dtype.names] + else: + return X.T + else: + return X + + +def savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', + footer='', comments='# ', encoding=None): + """ + Save an array to a text file. + + Parameters + ---------- + fname : filename or file handle + If the filename ends in ``.gz``, the file is automatically saved in + compressed gzip format. `loadtxt` understands gzipped files + transparently. + X : 1D or 2D array_like + Data to be saved to a text file. + fmt : str or sequence of strs, optional + A single format (%10.5f), a sequence of formats, or a + multi-format string, e.g. 'Iteration %d -- %10.5f', in which + case `delimiter` is ignored. For complex `X`, the legal options + for `fmt` are: + a) a single specifier, `fmt='%.4e'`, resulting in numbers formatted + like `' (%s+%sj)' % (fmt, fmt)` + b) a full string specifying every real and imaginary part, e.g. + `' %.4e %+.4ej %.4e %+.4ej %.4e %+.4ej'` for 3 columns + c) a list of specifiers, one per column - in this case, the real + and imaginary part must have separate specifiers, + e.g. `['%.3e + %.3ej', '(%.15e%+.15ej)']` for 2 columns + delimiter : str, optional + String or character separating columns. + newline : str, optional + String or character separating lines. + + .. versionadded:: 1.5.0 + header : str, optional + String that will be written at the beginning of the file. + + .. versionadded:: 1.7.0 + footer : str, optional + String that will be written at the end of the file. + + .. versionadded:: 1.7.0 + comments : str, optional + String that will be prepended to the ``header`` and ``footer`` strings, + to mark them as comments. Default: '# ', as expected by e.g. + ``numpy.loadtxt``. + + .. versionadded:: 1.7.0 + encoding : {None, str}, optional + Encoding used to encode the outputfile. Does not apply to output + streams. If the encoding is something other than 'bytes' or 'latin1' + you will not be able to load the file in NumPy versions < 1.14. Default + is 'latin1'. + + .. versionadded:: 1.14.0 + + + See Also + -------- + save : Save an array to a binary file in NumPy ``.npy`` format + savez : Save several arrays into an uncompressed ``.npz`` archive + savez_compressed : Save several arrays into a compressed ``.npz`` archive + + Notes + ----- + Further explanation of the `fmt` parameter + (``%[flag]width[.precision]specifier``): + + flags: + ``-`` : left justify + + ``+`` : Forces to precede result with + or -. + + ``0`` : Left pad the number with zeros instead of space (see width). + + width: + Minimum number of characters to be printed. The value is not truncated + if it has more characters. + + precision: + - For integer specifiers (eg. ``d,i,o,x``), the minimum number of + digits. + - For ``e, E`` and ``f`` specifiers, the number of digits to print + after the decimal point. + - For ``g`` and ``G``, the maximum number of significant digits. + - For ``s``, the maximum number of characters. + + specifiers: + ``c`` : character + + ``d`` or ``i`` : signed decimal integer + + ``e`` or ``E`` : scientific notation with ``e`` or ``E``. + + ``f`` : decimal floating point + + ``g,G`` : use the shorter of ``e,E`` or ``f`` + + ``o`` : signed octal + + ``s`` : string of characters + + ``u`` : unsigned decimal integer + + ``x,X`` : unsigned hexadecimal integer + + This explanation of ``fmt`` is not complete, for an exhaustive + specification see [1]_. + + References + ---------- + .. [1] `Format Specification Mini-Language + `_, Python Documentation. + + Examples + -------- + >>> x = y = z = np.arange(0.0,5.0,1.0) + >>> np.savetxt('test.out', x, delimiter=',') # X is an array + >>> np.savetxt('test.out', (x,y,z)) # x,y,z equal sized 1D arrays + >>> np.savetxt('test.out', x, fmt='%1.4e') # use exponential notation + + """ + + # Py3 conversions first + if isinstance(fmt, bytes): + fmt = asstr(fmt) + delimiter = asstr(delimiter) + + class WriteWrap(object): + """Convert to unicode in py2 or to bytes on bytestream inputs. + + """ + def __init__(self, fh, encoding): + self.fh = fh + self.encoding = encoding + self.do_write = self.first_write + + def close(self): + self.fh.close() + + def write(self, v): + self.do_write(v) + + def write_bytes(self, v): + if isinstance(v, bytes): + self.fh.write(v) + else: + self.fh.write(v.encode(self.encoding)) + + def write_normal(self, v): + self.fh.write(asunicode(v)) + + def first_write(self, v): + try: + self.write_normal(v) + self.write = self.write_normal + except TypeError: + # input is probably a bytestream + self.write_bytes(v) + self.write = self.write_bytes + + own_fh = False + if is_pathlib_path(fname): + fname = str(fname) + if _is_string_like(fname): + # datasource doesn't support creating a new file ... + open(fname, 'wt').close() + fh = np.lib._datasource.open(fname, 'wt', encoding=encoding) + own_fh = True + # need to convert str to unicode for text io output + if sys.version_info[0] == 2: + fh = WriteWrap(fh, encoding or 'latin1') + elif hasattr(fname, 'write'): + # wrap to handle byte output streams + fh = WriteWrap(fname, encoding or 'latin1') + else: + raise ValueError('fname must be a string or file handle') + + try: + X = np.asarray(X) + + # Handle 1-dimensional arrays + if X.ndim == 0 or X.ndim > 2: + raise ValueError( + "Expected 1D or 2D array, got %dD array instead" % X.ndim) + elif X.ndim == 1: + # Common case -- 1d array of numbers + if X.dtype.names is None: + X = np.atleast_2d(X).T + ncol = 1 + + # Complex dtype -- each field indicates a separate column + else: + ncol = len(X.dtype.descr) + else: + ncol = X.shape[1] + + iscomplex_X = np.iscomplexobj(X) + # `fmt` can be a string with multiple insertion points or a + # list of formats. E.g. '%10.5f\t%10d' or ('%10.5f', '$10d') + if type(fmt) in (list, tuple): + if len(fmt) != ncol: + raise AttributeError('fmt has wrong shape. %s' % str(fmt)) + format = asstr(delimiter).join(map(asstr, fmt)) + elif isinstance(fmt, str): + n_fmt_chars = fmt.count('%') + error = ValueError('fmt has wrong number of %% formats: %s' % fmt) + if n_fmt_chars == 1: + if iscomplex_X: + fmt = [' (%s+%sj)' % (fmt, fmt), ] * ncol + else: + fmt = [fmt, ] * ncol + format = delimiter.join(fmt) + elif iscomplex_X and n_fmt_chars != (2 * ncol): + raise error + elif ((not iscomplex_X) and n_fmt_chars != ncol): + raise error + else: + format = fmt + else: + raise ValueError('invalid fmt: %r' % (fmt,)) + + if len(header) > 0: + header = header.replace('\n', '\n' + comments) + fh.write(comments + header + newline) + if iscomplex_X: + for row in X: + row2 = [] + for number in row: + row2.append(number.real) + row2.append(number.imag) + fh.write(format % tuple(row2) + newline) + else: + for row in X: + try: + v = format % tuple(row) + newline + except TypeError: + raise TypeError("Mismatch between array dtype ('%s') and " + "format specifier ('%s')" + % (str(X.dtype), format)) + fh.write(v) + + if len(footer) > 0: + footer = footer.replace('\n', '\n' + comments) + fh.write(comments + footer + newline) + finally: + if own_fh: + fh.close() + + +def fromregex(file, regexp, dtype, encoding=None): + """ + Construct an array from a text file, using regular expression parsing. + + The returned array is always a structured array, and is constructed from + all matches of the regular expression in the file. Groups in the regular + expression are converted to fields of the structured array. + + Parameters + ---------- + file : str or file + File name or file object to read. + regexp : str or regexp + Regular expression used to parse the file. + Groups in the regular expression correspond to fields in the dtype. + dtype : dtype or list of dtypes + Dtype for the structured array. + encoding : str, optional + Encoding used to decode the inputfile. Does not apply to input streams. + + .. versionadded:: 1.14.0 + + Returns + ------- + output : ndarray + The output array, containing the part of the content of `file` that + was matched by `regexp`. `output` is always a structured array. + + Raises + ------ + TypeError + When `dtype` is not a valid dtype for a structured array. + + See Also + -------- + fromstring, loadtxt + + Notes + ----- + Dtypes for structured arrays can be specified in several forms, but all + forms specify at least the data type and field name. For details see + `doc.structured_arrays`. + + Examples + -------- + >>> f = open('test.dat', 'w') + >>> f.write("1312 foo\\n1534 bar\\n444 qux") + >>> f.close() + + >>> regexp = r"(\\d+)\\s+(...)" # match [digits, whitespace, anything] + >>> output = np.fromregex('test.dat', regexp, + ... [('num', np.int64), ('key', 'S3')]) + >>> output + array([(1312L, 'foo'), (1534L, 'bar'), (444L, 'qux')], + dtype=[('num', '>> output['num'] + array([1312, 1534, 444], dtype=int64) + + """ + own_fh = False + if not hasattr(file, "read"): + file = np.lib._datasource.open(file, 'rt', encoding=encoding) + own_fh = True + + try: + if not isinstance(dtype, np.dtype): + dtype = np.dtype(dtype) + + content = file.read() + if isinstance(content, bytes) and not isinstance(regexp, bytes): + regexp = asbytes(regexp) + elif not isinstance(content, bytes) and isinstance(regexp, bytes): + regexp = asstr(regexp) + + if not hasattr(regexp, 'match'): + regexp = re.compile(regexp) + seq = regexp.findall(content) + if seq and not isinstance(seq[0], tuple): + # Only one group is in the regexp. + # Create the new array as a single data-type and then + # re-interpret as a single-field structured array. + newdtype = np.dtype(dtype[dtype.names[0]]) + output = np.array(seq, dtype=newdtype) + output.dtype = dtype + else: + output = np.array(seq, dtype=dtype) + + return output + finally: + if own_fh: + file.close() + + +#####-------------------------------------------------------------------------- +#---- --- ASCII functions --- +#####-------------------------------------------------------------------------- + + +def genfromtxt(fname, dtype=float, comments='#', delimiter=None, + skip_header=0, skip_footer=0, converters=None, + missing_values=None, filling_values=None, usecols=None, + names=None, excludelist=None, deletechars=None, + replace_space='_', autostrip=False, case_sensitive=True, + defaultfmt="f%i", unpack=None, usemask=False, loose=True, + invalid_raise=True, max_rows=None, encoding='bytes'): + """ + Load data from a text file, with missing values handled as specified. + + Each line past the first `skip_header` lines is split at the `delimiter` + character, and characters following the `comments` character are discarded. + + Parameters + ---------- + fname : file, str, pathlib.Path, list of str, generator + File, filename, list, or generator to read. If the filename + extension is `.gz` or `.bz2`, the file is first decompressed. Note + that generators must return byte strings in Python 3k. The strings + in a list or produced by a generator are treated as lines. + dtype : dtype, optional + Data type of the resulting array. + If None, the dtypes will be determined by the contents of each + column, individually. + comments : str, optional + The character used to indicate the start of a comment. + All the characters occurring on a line after a comment are discarded + delimiter : str, int, or sequence, optional + The string used to separate values. By default, any consecutive + whitespaces act as delimiter. An integer or sequence of integers + can also be provided as width(s) of each field. + skiprows : int, optional + `skiprows` was removed in numpy 1.10. Please use `skip_header` instead. + skip_header : int, optional + The number of lines to skip at the beginning of the file. + skip_footer : int, optional + The number of lines to skip at the end of the file. + converters : variable, optional + The set of functions that convert the data of a column to a value. + The converters can also be used to provide a default value + for missing data: ``converters = {3: lambda s: float(s or 0)}``. + missing : variable, optional + `missing` was removed in numpy 1.10. Please use `missing_values` + instead. + missing_values : variable, optional + The set of strings corresponding to missing data. + filling_values : variable, optional + The set of values to be used as default when the data are missing. + usecols : sequence, optional + Which columns to read, with 0 being the first. For example, + ``usecols = (1, 4, 5)`` will extract the 2nd, 5th and 6th columns. + names : {None, True, str, sequence}, optional + If `names` is True, the field names are read from the first line after + the first `skip_header` lines. This line can optionally be proceeded + by a comment delimeter. If `names` is a sequence or a single-string of + comma-separated names, the names will be used to define the field names + in a structured dtype. If `names` is None, the names of the dtype + fields will be used, if any. + 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` would become `file_`. + deletechars : str, optional + A string combining invalid characters that must be deleted from the + names. + defaultfmt : str, optional + A format used to define default field names, such as "f%i" or "f_%02i". + autostrip : bool, optional + Whether to automatically strip white spaces from the variables. + replace_space : char, optional + Character(s) used in replacement of white spaces in the variables + names. By default, use a '_'. + 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. + unpack : bool, optional + If True, the returned array is transposed, so that arguments may be + unpacked using ``x, y, z = loadtxt(...)`` + usemask : bool, optional + If True, return a masked array. + If False, return a regular array. + loose : bool, optional + If True, do not raise errors for invalid values. + invalid_raise : bool, optional + If True, an exception is raised if an inconsistency is detected in the + number of columns. + If False, a warning is emitted and the offending lines are skipped. + max_rows : int, optional + The maximum number of rows to read. Must not be used with skip_footer + at the same time. If given, the value must be at least 1. Default is + to read the entire file. + + .. versionadded:: 1.10.0 + encoding : str, optional + Encoding used to decode the inputfile. Does not apply when `fname` is + a file object. The special value 'bytes' enables backward compatibility + workarounds that ensure that you receive byte arrays when possible + and passes latin1 encoded strings to converters. Override this value to + receive unicode arrays and pass strings as input to converters. If set + to None the system default is used. The default value is 'bytes'. + + .. versionadded:: 1.14.0 + + Returns + ------- + out : ndarray + Data read from the text file. If `usemask` is True, this is a + masked array. + + See Also + -------- + numpy.loadtxt : equivalent function when no data is missing. + + Notes + ----- + * When spaces are used as delimiters, or when no delimiter has been given + as input, there should not be any missing data between two fields. + * When the variables are named (either by a flexible dtype or with `names`, + there must not be any header in the file (else a ValueError + exception is raised). + * Individual values are not stripped of spaces by default. + When using a custom converter, make sure the function does remove spaces. + + References + ---------- + .. [1] NumPy User Guide, section `I/O with NumPy + `_. + + Examples + --------- + >>> from io import StringIO + >>> import numpy as np + + Comma delimited file with mixed dtype + + >>> s = StringIO("1,1.3,abcde") + >>> data = np.genfromtxt(s, dtype=[('myint','i8'),('myfloat','f8'), + ... ('mystring','S5')], delimiter=",") + >>> data + array((1, 1.3, 'abcde'), + dtype=[('myint', '>> s.seek(0) # needed for StringIO example only + >>> data = np.genfromtxt(s, dtype=None, + ... names = ['myint','myfloat','mystring'], delimiter=",") + >>> data + array((1, 1.3, 'abcde'), + dtype=[('myint', '>> s.seek(0) + >>> data = np.genfromtxt(s, dtype="i8,f8,S5", + ... names=['myint','myfloat','mystring'], delimiter=",") + >>> data + array((1, 1.3, 'abcde'), + dtype=[('myint', '>> s = StringIO("11.3abcde") + >>> data = np.genfromtxt(s, dtype=None, names=['intvar','fltvar','strvar'], + ... delimiter=[1,3,5]) + >>> data + array((1, 1.3, 'abcde'), + dtype=[('intvar', ' nbcols): + descr = dtype.descr + dtype = np.dtype([descr[_] for _ in usecols]) + names = list(dtype.names) + # If `names` is not None, update the names + elif (names is not None) and (len(names) > nbcols): + names = [names[_] for _ in usecols] + elif (names is not None) and (dtype is not None): + names = list(dtype.names) + + # Process the missing values ............................... + # Rename missing_values for convenience + user_missing_values = missing_values or () + if isinstance(user_missing_values, bytes): + user_missing_values = user_missing_values.decode('latin1') + + # Define the list of missing_values (one column: one list) + missing_values = [list(['']) for _ in range(nbcols)] + + # We have a dictionary: process it field by field + if isinstance(user_missing_values, dict): + # Loop on the items + for (key, val) in user_missing_values.items(): + # Is the key a string ? + if _is_string_like(key): + try: + # Transform it into an integer + key = names.index(key) + except ValueError: + # We couldn't find it: the name must have been dropped + continue + # Redefine the key as needed if it's a column number + if usecols: + try: + key = usecols.index(key) + except ValueError: + pass + # Transform the value as a list of string + if isinstance(val, (list, tuple)): + val = [str(_) for _ in val] + else: + val = [str(val), ] + # Add the value(s) to the current list of missing + if key is None: + # None acts as default + for miss in missing_values: + miss.extend(val) + else: + missing_values[key].extend(val) + # We have a sequence : each item matches a column + elif isinstance(user_missing_values, (list, tuple)): + for (value, entry) in zip(user_missing_values, missing_values): + value = str(value) + if value not in entry: + entry.append(value) + # We have a string : apply it to all entries + elif isinstance(user_missing_values, basestring): + user_value = user_missing_values.split(",") + for entry in missing_values: + entry.extend(user_value) + # We have something else: apply it to all entries + else: + for entry in missing_values: + entry.extend([str(user_missing_values)]) + + # Process the filling_values ............................... + # Rename the input for convenience + user_filling_values = filling_values + if user_filling_values is None: + user_filling_values = [] + # Define the default + filling_values = [None] * nbcols + # We have a dictionary : update each entry individually + if isinstance(user_filling_values, dict): + for (key, val) in user_filling_values.items(): + if _is_string_like(key): + try: + # Transform it into an integer + key = names.index(key) + except ValueError: + # We couldn't find it: the name must have been dropped, + continue + # Redefine the key if it's a column number and usecols is defined + if usecols: + try: + key = usecols.index(key) + except ValueError: + pass + # Add the value to the list + filling_values[key] = val + # We have a sequence : update on a one-to-one basis + elif isinstance(user_filling_values, (list, tuple)): + n = len(user_filling_values) + if (n <= nbcols): + filling_values[:n] = user_filling_values + else: + filling_values = user_filling_values[:nbcols] + # We have something else : use it for all entries + else: + filling_values = [user_filling_values] * nbcols + + # Initialize the converters ................................ + if dtype is None: + # Note: we can't use a [...]*nbcols, as we would have 3 times the same + # ... converter, instead of 3 different converters. + converters = [StringConverter(None, missing_values=miss, default=fill) + for (miss, fill) in zip(missing_values, filling_values)] + else: + dtype_flat = flatten_dtype(dtype, flatten_base=True) + # Initialize the converters + if len(dtype_flat) > 1: + # Flexible type : get a converter from each dtype + zipit = zip(dtype_flat, missing_values, filling_values) + converters = [StringConverter(dt, locked=True, + missing_values=miss, default=fill) + for (dt, miss, fill) in zipit] + else: + # Set to a default converter (but w/ different missing values) + zipit = zip(missing_values, filling_values) + converters = [StringConverter(dtype, locked=True, + missing_values=miss, default=fill) + for (miss, fill) in zipit] + # Update the converters to use the user-defined ones + uc_update = [] + for (j, conv) in user_converters.items(): + # If the converter is specified by column names, use the index instead + if _is_string_like(j): + try: + j = names.index(j) + i = j + except ValueError: + continue + elif usecols: + try: + i = usecols.index(j) + except ValueError: + # Unused converter specified + continue + else: + i = j + # Find the value to test - first_line is not filtered by usecols: + if len(first_line): + testing_value = first_values[j] + else: + testing_value = None + if conv is bytes: + user_conv = asbytes + elif byte_converters: + # converters may use decode to workaround numpy's old behaviour, + # so encode the string again before passing to the user converter + def tobytes_first(x, conv): + if type(x) is bytes: + return conv(x) + return conv(x.encode("latin1")) + import functools + user_conv = functools.partial(tobytes_first, conv=conv) + else: + user_conv = conv + converters[i].update(user_conv, locked=True, + testing_value=testing_value, + default=filling_values[i], + missing_values=missing_values[i],) + uc_update.append((i, user_conv)) + # Make sure we have the corrected keys in user_converters... + user_converters.update(uc_update) + + # Fixme: possible error as following variable never used. + # miss_chars = [_.missing_values for _ in converters] + + # Initialize the output lists ... + # ... rows + rows = [] + append_to_rows = rows.append + # ... masks + if usemask: + masks = [] + append_to_masks = masks.append + # ... invalid + invalid = [] + append_to_invalid = invalid.append + + # Parse each line + for (i, line) in enumerate(itertools.chain([first_line, ], fhd)): + values = split_line(line) + nbvalues = len(values) + # Skip an empty line + if nbvalues == 0: + continue + if usecols: + # Select only the columns we need + try: + values = [values[_] for _ in usecols] + except IndexError: + append_to_invalid((i + skip_header + 1, nbvalues)) + continue + elif nbvalues != nbcols: + append_to_invalid((i + skip_header + 1, nbvalues)) + continue + # Store the values + append_to_rows(tuple(values)) + if usemask: + append_to_masks(tuple([v.strip() in m + for (v, m) in zip(values, + missing_values)])) + if len(rows) == max_rows: + break + + if own_fhd: + fhd.close() + + # Upgrade the converters (if needed) + if dtype is None: + for (i, converter) in enumerate(converters): + current_column = [itemgetter(i)(_m) for _m in rows] + try: + converter.iterupgrade(current_column) + except ConverterLockError: + errmsg = "Converter #%i is locked and cannot be upgraded: " % i + current_column = map(itemgetter(i), rows) + for (j, value) in enumerate(current_column): + try: + converter.upgrade(value) + except (ConverterError, ValueError): + errmsg += "(occurred line #%i for value '%s')" + errmsg %= (j + 1 + skip_header, value) + raise ConverterError(errmsg) + + # Check that we don't have invalid values + nbinvalid = len(invalid) + if nbinvalid > 0: + nbrows = len(rows) + nbinvalid - skip_footer + # Construct the error message + template = " Line #%%i (got %%i columns instead of %i)" % nbcols + if skip_footer > 0: + nbinvalid_skipped = len([_ for _ in invalid + if _[0] > nbrows + skip_header]) + invalid = invalid[:nbinvalid - nbinvalid_skipped] + skip_footer -= nbinvalid_skipped +# +# nbrows -= skip_footer +# errmsg = [template % (i, nb) +# for (i, nb) in invalid if i < nbrows] +# else: + errmsg = [template % (i, nb) + for (i, nb) in invalid] + if len(errmsg): + errmsg.insert(0, "Some errors were detected !") + errmsg = "\n".join(errmsg) + # Raise an exception ? + if invalid_raise: + raise ValueError(errmsg) + # Issue a warning ? + else: + warnings.warn(errmsg, ConversionWarning, stacklevel=2) + + # Strip the last skip_footer data + if skip_footer > 0: + rows = rows[:-skip_footer] + if usemask: + masks = masks[:-skip_footer] + + # Convert each value according to the converter: + # We want to modify the list in place to avoid creating a new one... + if loose: + rows = list( + zip(*[[conv._loose_call(_r) for _r in map(itemgetter(i), rows)] + for (i, conv) in enumerate(converters)])) + else: + rows = list( + zip(*[[conv._strict_call(_r) for _r in map(itemgetter(i), rows)] + for (i, conv) in enumerate(converters)])) + + # Reset the dtype + data = rows + if dtype is None: + # Get the dtypes from the types of the converters + column_types = [conv.type for conv in converters] + # Find the columns with strings... + strcolidx = [i for (i, v) in enumerate(column_types) + if v == np.unicode_] + + if byte_converters and strcolidx: + # convert strings back to bytes for backward compatibility + warnings.warn( + "Reading unicode strings without specifying the encoding " + "argument is deprecated. Set the encoding, use None for the " + "system default.", + np.VisibleDeprecationWarning, stacklevel=2) + def encode_unicode_cols(row_tup): + row = list(row_tup) + for i in strcolidx: + row[i] = row[i].encode('latin1') + return tuple(row) + + try: + data = [encode_unicode_cols(r) for r in data] + except UnicodeEncodeError: + pass + else: + for i in strcolidx: + column_types[i] = np.bytes_ + + # Update string types to be the right length + sized_column_types = column_types[:] + for i, col_type in enumerate(column_types): + if np.issubdtype(col_type, np.character): + n_chars = max(len(row[i]) for row in data) + sized_column_types[i] = (col_type, n_chars) + + if names is None: + # If the dtype is uniform (before sizing strings) + base = set([ + c_type + for c, c_type in zip(converters, column_types) + if c._checked]) + if len(base) == 1: + uniform_type, = base + (ddtype, mdtype) = (uniform_type, bool) + else: + ddtype = [(defaultfmt % i, dt) + for (i, dt) in enumerate(sized_column_types)] + if usemask: + mdtype = [(defaultfmt % i, bool) + for (i, dt) in enumerate(sized_column_types)] + else: + ddtype = list(zip(names, sized_column_types)) + mdtype = list(zip(names, [bool] * len(sized_column_types))) + output = np.array(data, dtype=ddtype) + if usemask: + outputmask = np.array(masks, dtype=mdtype) + else: + # Overwrite the initial dtype names if needed + if names and dtype.names: + dtype.names = names + # Case 1. We have a structured type + if len(dtype_flat) > 1: + # Nested dtype, eg [('a', int), ('b', [('b0', int), ('b1', 'f4')])] + # First, create the array using a flattened dtype: + # [('a', int), ('b1', int), ('b2', float)] + # Then, view the array using the specified dtype. + if 'O' in (_.char for _ in dtype_flat): + if has_nested_fields(dtype): + raise NotImplementedError( + "Nested fields involving objects are not supported...") + else: + output = np.array(data, dtype=dtype) + else: + rows = np.array(data, dtype=[('', _) for _ in dtype_flat]) + output = rows.view(dtype) + # Now, process the rowmasks the same way + if usemask: + rowmasks = np.array( + masks, dtype=np.dtype([('', bool) for t in dtype_flat])) + # Construct the new dtype + mdtype = make_mask_descr(dtype) + outputmask = rowmasks.view(mdtype) + # Case #2. We have a basic dtype + else: + # We used some user-defined converters + if user_converters: + ishomogeneous = True + descr = [] + for i, ttype in enumerate([conv.type for conv in converters]): + # Keep the dtype of the current converter + if i in user_converters: + ishomogeneous &= (ttype == dtype.type) + if np.issubdtype(ttype, np.character): + ttype = (ttype, max(len(row[i]) for row in data)) + descr.append(('', ttype)) + else: + descr.append(('', dtype)) + # So we changed the dtype ? + if not ishomogeneous: + # We have more than one field + if len(descr) > 1: + dtype = np.dtype(descr) + # We have only one field: drop the name if not needed. + else: + dtype = np.dtype(ttype) + # + output = np.array(data, dtype) + if usemask: + if dtype.names: + mdtype = [(_, bool) for _ in dtype.names] + else: + mdtype = bool + outputmask = np.array(masks, dtype=mdtype) + # Try to take care of the missing data we missed + names = output.dtype.names + if usemask and names: + for (name, conv) in zip(names, converters): + missing_values = [conv(_) for _ in conv.missing_values + if _ != ''] + for mval in missing_values: + outputmask[name] |= (output[name] == mval) + # Construct the final array + if usemask: + output = output.view(MaskedArray) + output._mask = outputmask + if unpack: + return output.squeeze().T + return output.squeeze() + + +def ndfromtxt(fname, **kwargs): + """ + Load ASCII data stored in a file and return it as a single array. + + Parameters + ---------- + fname, kwargs : For a description of input parameters, see `genfromtxt`. + + See Also + -------- + numpy.genfromtxt : generic function. + + """ + kwargs['usemask'] = False + return genfromtxt(fname, **kwargs) + + +def mafromtxt(fname, **kwargs): + """ + Load ASCII data stored in a text file and return a masked array. + + Parameters + ---------- + fname, kwargs : For a description of input parameters, see `genfromtxt`. + + See Also + -------- + numpy.genfromtxt : generic function to load ASCII data. + + """ + kwargs['usemask'] = True + return genfromtxt(fname, **kwargs) + + +def recfromtxt(fname, **kwargs): + """ + Load ASCII data from a file and return it in a record array. + + If ``usemask=False`` a standard `recarray` is returned, + if ``usemask=True`` a MaskedRecords array is returned. + + Parameters + ---------- + fname, kwargs : For a description of input parameters, see `genfromtxt`. + + See Also + -------- + numpy.genfromtxt : generic function + + Notes + ----- + By default, `dtype` is None, which means that the data-type of the output + array will be determined from the data. + + """ + kwargs.setdefault("dtype", None) + usemask = kwargs.get('usemask', False) + output = genfromtxt(fname, **kwargs) + if usemask: + from numpy.ma.mrecords import MaskedRecords + output = output.view(MaskedRecords) + else: + output = output.view(np.recarray) + return output + + +def recfromcsv(fname, **kwargs): + """ + Load ASCII data stored in a comma-separated file. + + The returned array is a record array (if ``usemask=False``, see + `recarray`) or a masked record array (if ``usemask=True``, + see `ma.mrecords.MaskedRecords`). + + Parameters + ---------- + fname, kwargs : For a description of input parameters, see `genfromtxt`. + + See Also + -------- + numpy.genfromtxt : generic function to load ASCII data. + + Notes + ----- + By default, `dtype` is None, which means that the data-type of the output + array will be determined from the data. + + """ + # Set default kwargs for genfromtxt as relevant to csv import. + kwargs.setdefault("case_sensitive", "lower") + kwargs.setdefault("names", True) + kwargs.setdefault("delimiter", ",") + kwargs.setdefault("dtype", None) + output = genfromtxt(fname, **kwargs) + + usemask = kwargs.get("usemask", False) + if usemask: + from numpy.ma.mrecords import MaskedRecords + output = output.view(MaskedRecords) + else: + output = output.view(np.recarray) + return output diff --git a/numpy/lib/polynomial.py b/numpy/lib/polynomial.py new file mode 100644 index 0000000..f49b7e2 --- /dev/null +++ b/numpy/lib/polynomial.py @@ -0,0 +1,1302 @@ +""" +Functions to operate on polynomials. + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['poly', 'roots', 'polyint', 'polyder', 'polyadd', + 'polysub', 'polymul', 'polydiv', 'polyval', 'poly1d', + 'polyfit', 'RankWarning'] + +import re +import warnings +import numpy.core.numeric as NX + +from numpy.core import (isscalar, abs, finfo, atleast_1d, hstack, dot, array, + ones) +from numpy.lib.twodim_base import diag, vander +from numpy.lib.function_base import trim_zeros +from numpy.lib.type_check import iscomplex, real, imag, mintypecode +from numpy.linalg import eigvals, lstsq, inv + +class RankWarning(UserWarning): + """ + Issued by `polyfit` when the Vandermonde matrix is rank deficient. + + For more information, a way to suppress the warning, and an example of + `RankWarning` being issued, see `polyfit`. + + """ + pass + +def poly(seq_of_zeros): + """ + Find the coefficients of a polynomial with the given sequence of roots. + + Returns the coefficients of the polynomial whose leading coefficient + is one for the given sequence of zeros (multiple roots must be included + in the sequence as many times as their multiplicity; see Examples). + A square matrix (or array, which will be treated as a matrix) can also + be given, in which case the coefficients of the characteristic polynomial + of the matrix are returned. + + Parameters + ---------- + seq_of_zeros : array_like, shape (N,) or (N, N) + A sequence of polynomial roots, or a square array or matrix object. + + Returns + ------- + c : ndarray + 1D array of polynomial coefficients from highest to lowest degree: + + ``c[0] * x**(N) + c[1] * x**(N-1) + ... + c[N-1] * x + c[N]`` + where c[0] always equals 1. + + Raises + ------ + ValueError + If input is the wrong shape (the input must be a 1-D or square + 2-D array). + + See Also + -------- + polyval : Compute polynomial values. + roots : Return the roots of a polynomial. + polyfit : Least squares polynomial fit. + poly1d : A one-dimensional polynomial class. + + Notes + ----- + Specifying the roots of a polynomial still leaves one degree of + freedom, typically represented by an undetermined leading + coefficient. [1]_ In the case of this function, that coefficient - + the first one in the returned array - is always taken as one. (If + for some reason you have one other point, the only automatic way + presently to leverage that information is to use ``polyfit``.) + + The characteristic polynomial, :math:`p_a(t)`, of an `n`-by-`n` + matrix **A** is given by + + :math:`p_a(t) = \\mathrm{det}(t\\, \\mathbf{I} - \\mathbf{A})`, + + where **I** is the `n`-by-`n` identity matrix. [2]_ + + References + ---------- + .. [1] M. Sullivan and M. Sullivan, III, "Algebra and Trignometry, + Enhanced With Graphing Utilities," Prentice-Hall, pg. 318, 1996. + + .. [2] G. Strang, "Linear Algebra and Its Applications, 2nd Edition," + Academic Press, pg. 182, 1980. + + Examples + -------- + Given a sequence of a polynomial's zeros: + + >>> np.poly((0, 0, 0)) # Multiple root example + array([1, 0, 0, 0]) + + The line above represents z**3 + 0*z**2 + 0*z + 0. + + >>> np.poly((-1./2, 0, 1./2)) + array([ 1. , 0. , -0.25, 0. ]) + + The line above represents z**3 - z/4 + + >>> np.poly((np.random.random(1.)[0], 0, np.random.random(1.)[0])) + array([ 1. , -0.77086955, 0.08618131, 0. ]) #random + + Given a square array object: + + >>> P = np.array([[0, 1./3], [-1./2, 0]]) + >>> np.poly(P) + array([ 1. , 0. , 0.16666667]) + + Or a square matrix object: + + >>> np.poly(np.matrix(P)) + array([ 1. , 0. , 0.16666667]) + + Note how in all cases the leading coefficient is always 1. + + """ + seq_of_zeros = atleast_1d(seq_of_zeros) + sh = seq_of_zeros.shape + + if len(sh) == 2 and sh[0] == sh[1] and sh[0] != 0: + seq_of_zeros = eigvals(seq_of_zeros) + elif len(sh) == 1: + dt = seq_of_zeros.dtype + # Let object arrays slip through, e.g. for arbitrary precision + if dt != object: + seq_of_zeros = seq_of_zeros.astype(mintypecode(dt.char)) + else: + raise ValueError("input must be 1d or non-empty square 2d array.") + + if len(seq_of_zeros) == 0: + return 1.0 + dt = seq_of_zeros.dtype + a = ones((1,), dtype=dt) + for k in range(len(seq_of_zeros)): + a = NX.convolve(a, array([1, -seq_of_zeros[k]], dtype=dt), + mode='full') + + if issubclass(a.dtype.type, NX.complexfloating): + # if complex roots are all complex conjugates, the roots are real. + roots = NX.asarray(seq_of_zeros, complex) + if NX.all(NX.sort(roots) == NX.sort(roots.conjugate())): + a = a.real.copy() + + return a + +def roots(p): + """ + Return the roots of a polynomial with coefficients given in p. + + The values in the rank-1 array `p` are coefficients of a polynomial. + If the length of `p` is n+1 then the polynomial is described by:: + + p[0] * x**n + p[1] * x**(n-1) + ... + p[n-1]*x + p[n] + + Parameters + ---------- + p : array_like + Rank-1 array of polynomial coefficients. + + Returns + ------- + out : ndarray + An array containing the roots of the polynomial. + + Raises + ------ + ValueError + When `p` cannot be converted to a rank-1 array. + + See also + -------- + poly : Find the coefficients of a polynomial with a given sequence + of roots. + polyval : Compute polynomial values. + polyfit : Least squares polynomial fit. + poly1d : A one-dimensional polynomial class. + + Notes + ----- + The algorithm relies on computing the eigenvalues of the + companion matrix [1]_. + + References + ---------- + .. [1] R. A. Horn & C. R. Johnson, *Matrix Analysis*. Cambridge, UK: + Cambridge University Press, 1999, pp. 146-7. + + Examples + -------- + >>> coeff = [3.2, 2, 1] + >>> np.roots(coeff) + array([-0.3125+0.46351241j, -0.3125-0.46351241j]) + + """ + # If input is scalar, this makes it an array + p = atleast_1d(p) + if p.ndim != 1: + raise ValueError("Input must be a rank-1 array.") + + # find non-zero array entries + non_zero = NX.nonzero(NX.ravel(p))[0] + + # Return an empty array if polynomial is all zeros + if len(non_zero) == 0: + return NX.array([]) + + # find the number of trailing zeros -- this is the number of roots at 0. + trailing_zeros = len(p) - non_zero[-1] - 1 + + # strip leading and trailing zeros + p = p[int(non_zero[0]):int(non_zero[-1])+1] + + # casting: if incoming array isn't floating point, make it floating point. + if not issubclass(p.dtype.type, (NX.floating, NX.complexfloating)): + p = p.astype(float) + + N = len(p) + if N > 1: + # build companion matrix and find its eigenvalues (the roots) + A = diag(NX.ones((N-2,), p.dtype), -1) + A[0,:] = -p[1:] / p[0] + roots = eigvals(A) + else: + roots = NX.array([]) + + # tack any zeros onto the back of the array + roots = hstack((roots, NX.zeros(trailing_zeros, roots.dtype))) + return roots + +def polyint(p, m=1, k=None): + """ + Return an antiderivative (indefinite integral) of a polynomial. + + The returned order `m` antiderivative `P` of polynomial `p` satisfies + :math:`\\frac{d^m}{dx^m}P(x) = p(x)` and is defined up to `m - 1` + integration constants `k`. The constants determine the low-order + polynomial part + + .. math:: \\frac{k_{m-1}}{0!} x^0 + \\ldots + \\frac{k_0}{(m-1)!}x^{m-1} + + of `P` so that :math:`P^{(j)}(0) = k_{m-j-1}`. + + Parameters + ---------- + p : array_like or poly1d + Polynomial to differentiate. + A sequence is interpreted as polynomial coefficients, see `poly1d`. + m : int, optional + Order of the antiderivative. (Default: 1) + k : list of `m` scalars or scalar, optional + Integration constants. They are given in the order of integration: + those corresponding to highest-order terms come first. + + If ``None`` (default), all constants are assumed to be zero. + If `m = 1`, a single scalar can be given instead of a list. + + See Also + -------- + polyder : derivative of a polynomial + poly1d.integ : equivalent method + + Examples + -------- + The defining property of the antiderivative: + + >>> p = np.poly1d([1,1,1]) + >>> P = np.polyint(p) + >>> P + poly1d([ 0.33333333, 0.5 , 1. , 0. ]) + >>> np.polyder(P) == p + True + + The integration constants default to zero, but can be specified: + + >>> P = np.polyint(p, 3) + >>> P(0) + 0.0 + >>> np.polyder(P)(0) + 0.0 + >>> np.polyder(P, 2)(0) + 0.0 + >>> P = np.polyint(p, 3, k=[6,5,3]) + >>> P + poly1d([ 0.01666667, 0.04166667, 0.16666667, 3. , 5. , 3. ]) + + Note that 3 = 6 / 2!, and that the constants are given in the order of + integrations. Constant of the highest-order polynomial term comes first: + + >>> np.polyder(P, 2)(0) + 6.0 + >>> np.polyder(P, 1)(0) + 5.0 + >>> P(0) + 3.0 + + """ + m = int(m) + if m < 0: + raise ValueError("Order of integral must be positive (see polyder)") + if k is None: + k = NX.zeros(m, float) + k = atleast_1d(k) + if len(k) == 1 and m > 1: + k = k[0]*NX.ones(m, float) + if len(k) < m: + raise ValueError( + "k must be a scalar or a rank-1 array of length 1 or >m.") + + truepoly = isinstance(p, poly1d) + p = NX.asarray(p) + if m == 0: + if truepoly: + return poly1d(p) + return p + else: + # Note: this must work also with object and integer arrays + y = NX.concatenate((p.__truediv__(NX.arange(len(p), 0, -1)), [k[0]])) + val = polyint(y, m - 1, k=k[1:]) + if truepoly: + return poly1d(val) + return val + +def polyder(p, m=1): + """ + Return the derivative of the specified order of a polynomial. + + Parameters + ---------- + p : poly1d or sequence + Polynomial to differentiate. + A sequence is interpreted as polynomial coefficients, see `poly1d`. + m : int, optional + Order of differentiation (default: 1) + + Returns + ------- + der : poly1d + A new polynomial representing the derivative. + + See Also + -------- + polyint : Anti-derivative of a polynomial. + poly1d : Class for one-dimensional polynomials. + + Examples + -------- + The derivative of the polynomial :math:`x^3 + x^2 + x^1 + 1` is: + + >>> p = np.poly1d([1,1,1,1]) + >>> p2 = np.polyder(p) + >>> p2 + poly1d([3, 2, 1]) + + which evaluates to: + + >>> p2(2.) + 17.0 + + We can verify this, approximating the derivative with + ``(f(x + h) - f(x))/h``: + + >>> (p(2. + 0.001) - p(2.)) / 0.001 + 17.007000999997857 + + The fourth-order derivative of a 3rd-order polynomial is zero: + + >>> np.polyder(p, 2) + poly1d([6, 2]) + >>> np.polyder(p, 3) + poly1d([6]) + >>> np.polyder(p, 4) + poly1d([ 0.]) + + """ + m = int(m) + if m < 0: + raise ValueError("Order of derivative must be positive (see polyint)") + + truepoly = isinstance(p, poly1d) + p = NX.asarray(p) + n = len(p) - 1 + y = p[:-1] * NX.arange(n, 0, -1) + if m == 0: + val = p + else: + val = polyder(y, m - 1) + if truepoly: + val = poly1d(val) + return val + +def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False): + """ + Least squares polynomial fit. + + Fit a polynomial ``p(x) = p[0] * x**deg + ... + p[deg]`` of degree `deg` + to points `(x, y)`. Returns a vector of coefficients `p` that minimises + the squared error. + + Parameters + ---------- + x : array_like, shape (M,) + x-coordinates of the M sample points ``(x[i], y[i])``. + y : array_like, shape (M,) or (M, K) + y-coordinates of the sample points. Several data sets of sample + points sharing the same x-coordinates can be fitted at once by + passing in a 2D-array that contains one dataset per column. + deg : int + Degree of the fitting polynomial + rcond : float, optional + Relative condition number of the fit. Singular values smaller than + this relative to the largest singular value will be ignored. The + default value is len(x)*eps, where eps is the relative precision of + the float type, about 2e-16 in most cases. + full : bool, optional + Switch determining nature of return value. When it is False (the + default) just the coefficients are returned, when True diagnostic + information from the singular value decomposition is also returned. + w : array_like, shape (M,), optional + Weights to apply to the y-coordinates of the sample points. For + gaussian uncertainties, use 1/sigma (not 1/sigma**2). + cov : bool, optional + Return the estimate and the covariance matrix of the estimate + If full is True, then cov is not returned. + + Returns + ------- + p : ndarray, shape (deg + 1,) or (deg + 1, K) + Polynomial coefficients, highest power first. If `y` was 2-D, the + coefficients for `k`-th data set are in ``p[:,k]``. + + residuals, rank, singular_values, rcond + Present only if `full` = True. Residuals of the least-squares fit, + the effective rank of the scaled Vandermonde coefficient matrix, + its singular values, and the specified value of `rcond`. For more + details, see `linalg.lstsq`. + + V : ndarray, shape (M,M) or (M,M,K) + Present only if `full` = False and `cov`=True. The covariance + matrix of the polynomial coefficient estimates. The diagonal of + this matrix are the variance estimates for each coefficient. If y + is a 2-D array, then the covariance matrix for the `k`-th data set + are in ``V[:,:,k]`` + + + Warns + ----- + RankWarning + The rank of the coefficient matrix in the least-squares fit is + deficient. The warning is only raised if `full` = False. + + The warnings can be turned off by + + >>> import warnings + >>> warnings.simplefilter('ignore', np.RankWarning) + + See Also + -------- + polyval : Compute polynomial values. + linalg.lstsq : Computes a least-squares fit. + scipy.interpolate.UnivariateSpline : Computes spline fits. + + Notes + ----- + The solution minimizes the squared error + + .. math :: + E = \\sum_{j=0}^k |p(x_j) - y_j|^2 + + in the equations:: + + x[0]**n * p[0] + ... + x[0] * p[n-1] + p[n] = y[0] + x[1]**n * p[0] + ... + x[1] * p[n-1] + p[n] = y[1] + ... + x[k]**n * p[0] + ... + x[k] * p[n-1] + p[n] = y[k] + + The coefficient matrix of the coefficients `p` is a Vandermonde matrix. + + `polyfit` issues a `RankWarning` when the least-squares fit is badly + conditioned. This implies that the best fit is not well-defined due + to numerical error. The results may be improved by lowering the polynomial + degree or by replacing `x` by `x` - `x`.mean(). The `rcond` parameter + can also be set to a value smaller than its default, but the resulting + fit may be spurious: including contributions from the small singular + values can add numerical noise to the result. + + Note that fitting polynomial coefficients is inherently badly conditioned + when the degree of the polynomial is large or the interval of sample points + is badly centered. The quality of the fit should always be checked in these + cases. When polynomial fits are not satisfactory, splines may be a good + alternative. + + References + ---------- + .. [1] Wikipedia, "Curve fitting", + http://en.wikipedia.org/wiki/Curve_fitting + .. [2] Wikipedia, "Polynomial interpolation", + http://en.wikipedia.org/wiki/Polynomial_interpolation + + Examples + -------- + >>> x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0]) + >>> y = np.array([0.0, 0.8, 0.9, 0.1, -0.8, -1.0]) + >>> z = np.polyfit(x, y, 3) + >>> z + array([ 0.08703704, -0.81349206, 1.69312169, -0.03968254]) + + It is convenient to use `poly1d` objects for dealing with polynomials: + + >>> p = np.poly1d(z) + >>> p(0.5) + 0.6143849206349179 + >>> p(3.5) + -0.34732142857143039 + >>> p(10) + 22.579365079365115 + + High-order polynomials may oscillate wildly: + + >>> p30 = np.poly1d(np.polyfit(x, y, 30)) + /... RankWarning: Polyfit may be poorly conditioned... + >>> p30(4) + -0.80000000000000204 + >>> p30(5) + -0.99999999999999445 + >>> p30(4.5) + -0.10547061179440398 + + Illustration: + + >>> import matplotlib.pyplot as plt + >>> xp = np.linspace(-2, 6, 100) + >>> _ = plt.plot(x, y, '.', xp, p(xp), '-', xp, p30(xp), '--') + >>> plt.ylim(-2,2) + (-2, 2) + >>> plt.show() + + """ + order = int(deg) + 1 + x = NX.asarray(x) + 0.0 + y = NX.asarray(y) + 0.0 + + # check arguments. + if deg < 0: + raise ValueError("expected deg >= 0") + if x.ndim != 1: + raise TypeError("expected 1D vector for x") + if x.size == 0: + raise TypeError("expected non-empty vector for x") + if y.ndim < 1 or y.ndim > 2: + raise TypeError("expected 1D or 2D array for y") + if x.shape[0] != y.shape[0]: + raise TypeError("expected x and y to have same length") + + # set rcond + if rcond is None: + rcond = len(x)*finfo(x.dtype).eps + + # set up least squares equation for powers of x + lhs = vander(x, order) + rhs = y + + # apply weighting + if w is not None: + w = NX.asarray(w) + 0.0 + if w.ndim != 1: + raise TypeError("expected a 1-d array for weights") + if w.shape[0] != y.shape[0]: + raise TypeError("expected w and y to have the same length") + lhs *= w[:, NX.newaxis] + if rhs.ndim == 2: + rhs *= w[:, NX.newaxis] + else: + rhs *= w + + # scale lhs to improve condition number and solve + scale = NX.sqrt((lhs*lhs).sum(axis=0)) + lhs /= scale + c, resids, rank, s = lstsq(lhs, rhs, rcond) + c = (c.T/scale).T # broadcast scale coefficients + + # warn on rank reduction, which indicates an ill conditioned matrix + if rank != order and not full: + msg = "Polyfit may be poorly conditioned" + warnings.warn(msg, RankWarning, stacklevel=2) + + if full: + return c, resids, rank, s, rcond + elif cov: + Vbase = inv(dot(lhs.T, lhs)) + Vbase /= NX.outer(scale, scale) + # Some literature ignores the extra -2.0 factor in the denominator, but + # it is included here because the covariance of Multivariate Student-T + # (which is implied by a Bayesian uncertainty analysis) includes it. + # Plus, it gives a slightly more conservative estimate of uncertainty. + if len(x) <= order + 2: + raise ValueError("the number of data points must exceed order + 2 " + "for Bayesian estimate the covariance matrix") + fac = resids / (len(x) - order - 2.0) + if y.ndim == 1: + return c, Vbase * fac + else: + return c, Vbase[:,:, NX.newaxis] * fac + else: + return c + + +def polyval(p, x): + """ + Evaluate a polynomial at specific values. + + If `p` is of length N, this function returns the value: + + ``p[0]*x**(N-1) + p[1]*x**(N-2) + ... + p[N-2]*x + p[N-1]`` + + If `x` is a sequence, then `p(x)` is returned for each element of `x`. + If `x` is another polynomial then the composite polynomial `p(x(t))` + is returned. + + Parameters + ---------- + p : array_like or poly1d object + 1D array of polynomial coefficients (including coefficients equal + to zero) from highest degree to the constant term, or an + instance of poly1d. + x : array_like or poly1d object + A number, an array of numbers, or an instance of poly1d, at + which to evaluate `p`. + + Returns + ------- + values : ndarray or poly1d + If `x` is a poly1d instance, the result is the composition of the two + polynomials, i.e., `x` is "substituted" in `p` and the simplified + result is returned. In addition, the type of `x` - array_like or + poly1d - governs the type of the output: `x` array_like => `values` + array_like, `x` a poly1d object => `values` is also. + + See Also + -------- + poly1d: A polynomial class. + + Notes + ----- + Horner's scheme [1]_ is used to evaluate the polynomial. Even so, + for polynomials of high degree the values may be inaccurate due to + rounding errors. Use carefully. + + References + ---------- + .. [1] I. N. Bronshtein, K. A. Semendyayev, and K. A. Hirsch (Eng. + trans. Ed.), *Handbook of Mathematics*, New York, Van Nostrand + Reinhold Co., 1985, pg. 720. + + Examples + -------- + >>> np.polyval([3,0,1], 5) # 3 * 5**2 + 0 * 5**1 + 1 + 76 + >>> np.polyval([3,0,1], np.poly1d(5)) + poly1d([ 76.]) + >>> np.polyval(np.poly1d([3,0,1]), 5) + 76 + >>> np.polyval(np.poly1d([3,0,1]), np.poly1d(5)) + poly1d([ 76.]) + + """ + p = NX.asarray(p) + if isinstance(x, poly1d): + y = 0 + else: + x = NX.asarray(x) + y = NX.zeros_like(x) + for i in range(len(p)): + y = y * x + p[i] + return y + +def polyadd(a1, a2): + """ + Find the sum of two polynomials. + + Returns the polynomial resulting from the sum of two input polynomials. + Each input must be either a poly1d object or a 1D sequence of polynomial + coefficients, from highest to lowest degree. + + Parameters + ---------- + a1, a2 : array_like or poly1d object + Input polynomials. + + Returns + ------- + out : ndarray or poly1d object + The sum of the inputs. If either input is a poly1d object, then the + output is also a poly1d object. Otherwise, it is a 1D array of + polynomial coefficients from highest to lowest degree. + + See Also + -------- + poly1d : A one-dimensional polynomial class. + poly, polyadd, polyder, polydiv, polyfit, polyint, polysub, polyval + + Examples + -------- + >>> np.polyadd([1, 2], [9, 5, 4]) + array([9, 6, 6]) + + Using poly1d objects: + + >>> p1 = np.poly1d([1, 2]) + >>> p2 = np.poly1d([9, 5, 4]) + >>> print(p1) + 1 x + 2 + >>> print(p2) + 2 + 9 x + 5 x + 4 + >>> print(np.polyadd(p1, p2)) + 2 + 9 x + 6 x + 6 + + """ + truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d)) + a1 = atleast_1d(a1) + a2 = atleast_1d(a2) + diff = len(a2) - len(a1) + if diff == 0: + val = a1 + a2 + elif diff > 0: + zr = NX.zeros(diff, a1.dtype) + val = NX.concatenate((zr, a1)) + a2 + else: + zr = NX.zeros(abs(diff), a2.dtype) + val = a1 + NX.concatenate((zr, a2)) + if truepoly: + val = poly1d(val) + return val + +def polysub(a1, a2): + """ + Difference (subtraction) of two polynomials. + + Given two polynomials `a1` and `a2`, returns ``a1 - a2``. + `a1` and `a2` can be either array_like sequences of the polynomials' + coefficients (including coefficients equal to zero), or `poly1d` objects. + + Parameters + ---------- + a1, a2 : array_like or poly1d + Minuend and subtrahend polynomials, respectively. + + Returns + ------- + out : ndarray or poly1d + Array or `poly1d` object of the difference polynomial's coefficients. + + See Also + -------- + polyval, polydiv, polymul, polyadd + + Examples + -------- + .. math:: (2 x^2 + 10 x - 2) - (3 x^2 + 10 x -4) = (-x^2 + 2) + + >>> np.polysub([2, 10, -2], [3, 10, -4]) + array([-1, 0, 2]) + + """ + truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d)) + a1 = atleast_1d(a1) + a2 = atleast_1d(a2) + diff = len(a2) - len(a1) + if diff == 0: + val = a1 - a2 + elif diff > 0: + zr = NX.zeros(diff, a1.dtype) + val = NX.concatenate((zr, a1)) - a2 + else: + zr = NX.zeros(abs(diff), a2.dtype) + val = a1 - NX.concatenate((zr, a2)) + if truepoly: + val = poly1d(val) + return val + + +def polymul(a1, a2): + """ + Find the product of two polynomials. + + Finds the polynomial resulting from the multiplication of the two input + polynomials. Each input must be either a poly1d object or a 1D sequence + of polynomial coefficients, from highest to lowest degree. + + Parameters + ---------- + a1, a2 : array_like or poly1d object + Input polynomials. + + Returns + ------- + out : ndarray or poly1d object + The polynomial resulting from the multiplication of the inputs. If + either inputs is a poly1d object, then the output is also a poly1d + object. Otherwise, it is a 1D array of polynomial coefficients from + highest to lowest degree. + + See Also + -------- + poly1d : A one-dimensional polynomial class. + poly, polyadd, polyder, polydiv, polyfit, polyint, polysub, + polyval + convolve : Array convolution. Same output as polymul, but has parameter + for overlap mode. + + Examples + -------- + >>> np.polymul([1, 2, 3], [9, 5, 1]) + array([ 9, 23, 38, 17, 3]) + + Using poly1d objects: + + >>> p1 = np.poly1d([1, 2, 3]) + >>> p2 = np.poly1d([9, 5, 1]) + >>> print(p1) + 2 + 1 x + 2 x + 3 + >>> print(p2) + 2 + 9 x + 5 x + 1 + >>> print(np.polymul(p1, p2)) + 4 3 2 + 9 x + 23 x + 38 x + 17 x + 3 + + """ + truepoly = (isinstance(a1, poly1d) or isinstance(a2, poly1d)) + a1, a2 = poly1d(a1), poly1d(a2) + val = NX.convolve(a1, a2) + if truepoly: + val = poly1d(val) + return val + +def polydiv(u, v): + """ + Returns the quotient and remainder of polynomial division. + + The input arrays are the coefficients (including any coefficients + equal to zero) of the "numerator" (dividend) and "denominator" + (divisor) polynomials, respectively. + + Parameters + ---------- + u : array_like or poly1d + Dividend polynomial's coefficients. + + v : array_like or poly1d + Divisor polynomial's coefficients. + + Returns + ------- + q : ndarray + Coefficients, including those equal to zero, of the quotient. + r : ndarray + Coefficients, including those equal to zero, of the remainder. + + See Also + -------- + poly, polyadd, polyder, polydiv, polyfit, polyint, polymul, polysub, + polyval + + Notes + ----- + Both `u` and `v` must be 0-d or 1-d (ndim = 0 or 1), but `u.ndim` need + not equal `v.ndim`. In other words, all four possible combinations - + ``u.ndim = v.ndim = 0``, ``u.ndim = v.ndim = 1``, + ``u.ndim = 1, v.ndim = 0``, and ``u.ndim = 0, v.ndim = 1`` - work. + + Examples + -------- + .. math:: \\frac{3x^2 + 5x + 2}{2x + 1} = 1.5x + 1.75, remainder 0.25 + + >>> x = np.array([3.0, 5.0, 2.0]) + >>> y = np.array([2.0, 1.0]) + >>> np.polydiv(x, y) + (array([ 1.5 , 1.75]), array([ 0.25])) + + """ + truepoly = (isinstance(u, poly1d) or isinstance(u, poly1d)) + u = atleast_1d(u) + 0.0 + v = atleast_1d(v) + 0.0 + # w has the common type + w = u[0] + v[0] + m = len(u) - 1 + n = len(v) - 1 + scale = 1. / v[0] + q = NX.zeros((max(m - n + 1, 1),), w.dtype) + r = u.copy() + for k in range(0, m-n+1): + d = scale * r[k] + q[k] = d + r[k:k+n+1] -= d*v + while NX.allclose(r[0], 0, rtol=1e-14) and (r.shape[-1] > 1): + r = r[1:] + if truepoly: + return poly1d(q), poly1d(r) + return q, r + +_poly_mat = re.compile(r"[*][*]([0-9]*)") +def _raise_power(astr, wrap=70): + n = 0 + line1 = '' + line2 = '' + output = ' ' + while True: + mat = _poly_mat.search(astr, n) + if mat is None: + break + span = mat.span() + power = mat.groups()[0] + partstr = astr[n:span[0]] + n = span[1] + toadd2 = partstr + ' '*(len(power)-1) + toadd1 = ' '*(len(partstr)-1) + power + if ((len(line2) + len(toadd2) > wrap) or + (len(line1) + len(toadd1) > wrap)): + output += line1 + "\n" + line2 + "\n " + line1 = toadd1 + line2 = toadd2 + else: + line2 += partstr + ' '*(len(power)-1) + line1 += ' '*(len(partstr)-1) + power + output += line1 + "\n" + line2 + return output + astr[n:] + + +class poly1d(object): + """ + A one-dimensional polynomial class. + + A convenience class, used to encapsulate "natural" operations on + polynomials so that said operations may take on their customary + form in code (see Examples). + + Parameters + ---------- + c_or_r : array_like + The polynomial's coefficients, in decreasing powers, or if + the value of the second parameter is True, the polynomial's + roots (values where the polynomial evaluates to 0). For example, + ``poly1d([1, 2, 3])`` returns an object that represents + :math:`x^2 + 2x + 3`, whereas ``poly1d([1, 2, 3], True)`` returns + one that represents :math:`(x-1)(x-2)(x-3) = x^3 - 6x^2 + 11x -6`. + r : bool, optional + If True, `c_or_r` specifies the polynomial's roots; the default + is False. + variable : str, optional + Changes the variable used when printing `p` from `x` to `variable` + (see Examples). + + Examples + -------- + Construct the polynomial :math:`x^2 + 2x + 3`: + + >>> p = np.poly1d([1, 2, 3]) + >>> print(np.poly1d(p)) + 2 + 1 x + 2 x + 3 + + Evaluate the polynomial at :math:`x = 0.5`: + + >>> p(0.5) + 4.25 + + Find the roots: + + >>> p.r + array([-1.+1.41421356j, -1.-1.41421356j]) + >>> p(p.r) + array([ -4.44089210e-16+0.j, -4.44089210e-16+0.j]) + + These numbers in the previous line represent (0, 0) to machine precision + + Show the coefficients: + + >>> p.c + array([1, 2, 3]) + + Display the order (the leading zero-coefficients are removed): + + >>> p.order + 2 + + Show the coefficient of the k-th power in the polynomial + (which is equivalent to ``p.c[-(i+1)]``): + + >>> p[1] + 2 + + Polynomials can be added, subtracted, multiplied, and divided + (returns quotient and remainder): + + >>> p * p + poly1d([ 1, 4, 10, 12, 9]) + + >>> (p**3 + 4) / p + (poly1d([ 1., 4., 10., 12., 9.]), poly1d([ 4.])) + + ``asarray(p)`` gives the coefficient array, so polynomials can be + used in all functions that accept arrays: + + >>> p**2 # square of polynomial + poly1d([ 1, 4, 10, 12, 9]) + + >>> np.square(p) # square of individual coefficients + array([1, 4, 9]) + + The variable used in the string representation of `p` can be modified, + using the `variable` parameter: + + >>> p = np.poly1d([1,2,3], variable='z') + >>> print(p) + 2 + 1 z + 2 z + 3 + + Construct a polynomial from its roots: + + >>> np.poly1d([1, 2], True) + poly1d([ 1, -3, 2]) + + This is the same polynomial as obtained by: + + >>> np.poly1d([1, -1]) * np.poly1d([1, -2]) + poly1d([ 1, -3, 2]) + + """ + __hash__ = None + + @property + def coeffs(self): + """ A copy of the polynomial coefficients """ + return self._coeffs.copy() + + @property + def variable(self): + """ The name of the polynomial variable """ + return self._variable + + # calculated attributes + @property + def order(self): + """ The order or degree of the polynomial """ + return len(self._coeffs) - 1 + + @property + def roots(self): + """ The roots of the polynomial, where self(x) == 0 """ + return roots(self._coeffs) + + # our internal _coeffs property need to be backed by __dict__['coeffs'] for + # scipy to work correctly. + @property + def _coeffs(self): + return self.__dict__['coeffs'] + @_coeffs.setter + def _coeffs(self, coeffs): + self.__dict__['coeffs'] = coeffs + + # alias attributes + r = roots + c = coef = coefficients = coeffs + o = order + + def __init__(self, c_or_r, r=False, variable=None): + if isinstance(c_or_r, poly1d): + self._variable = c_or_r._variable + self._coeffs = c_or_r._coeffs + + if set(c_or_r.__dict__) - set(self.__dict__): + msg = ("In the future extra properties will not be copied " + "across when constructing one poly1d from another") + warnings.warn(msg, FutureWarning, stacklevel=2) + self.__dict__.update(c_or_r.__dict__) + + if variable is not None: + self._variable = variable + return + if r: + c_or_r = poly(c_or_r) + c_or_r = atleast_1d(c_or_r) + if c_or_r.ndim > 1: + raise ValueError("Polynomial must be 1d only.") + c_or_r = trim_zeros(c_or_r, trim='f') + if len(c_or_r) == 0: + c_or_r = NX.array([0.]) + self._coeffs = c_or_r + if variable is None: + variable = 'x' + self._variable = variable + + def __array__(self, t=None): + if t: + return NX.asarray(self.coeffs, t) + else: + return NX.asarray(self.coeffs) + + def __repr__(self): + vals = repr(self.coeffs) + vals = vals[6:-1] + return "poly1d(%s)" % vals + + def __len__(self): + return self.order + + def __str__(self): + thestr = "0" + var = self.variable + + # Remove leading zeros + coeffs = self.coeffs[NX.logical_or.accumulate(self.coeffs != 0)] + N = len(coeffs)-1 + + def fmt_float(q): + s = '%.4g' % q + if s.endswith('.0000'): + s = s[:-5] + return s + + for k in range(len(coeffs)): + if not iscomplex(coeffs[k]): + coefstr = fmt_float(real(coeffs[k])) + elif real(coeffs[k]) == 0: + coefstr = '%sj' % fmt_float(imag(coeffs[k])) + else: + coefstr = '(%s + %sj)' % (fmt_float(real(coeffs[k])), + fmt_float(imag(coeffs[k]))) + + power = (N-k) + if power == 0: + if coefstr != '0': + newstr = '%s' % (coefstr,) + else: + if k == 0: + newstr = '0' + else: + newstr = '' + elif power == 1: + if coefstr == '0': + newstr = '' + elif coefstr == 'b': + newstr = var + else: + newstr = '%s %s' % (coefstr, var) + else: + if coefstr == '0': + newstr = '' + elif coefstr == 'b': + newstr = '%s**%d' % (var, power,) + else: + newstr = '%s %s**%d' % (coefstr, var, power) + + if k > 0: + if newstr != '': + if newstr.startswith('-'): + thestr = "%s - %s" % (thestr, newstr[1:]) + else: + thestr = "%s + %s" % (thestr, newstr) + else: + thestr = newstr + return _raise_power(thestr) + + def __call__(self, val): + return polyval(self.coeffs, val) + + def __neg__(self): + return poly1d(-self.coeffs) + + def __pos__(self): + return self + + def __mul__(self, other): + if isscalar(other): + return poly1d(self.coeffs * other) + else: + other = poly1d(other) + return poly1d(polymul(self.coeffs, other.coeffs)) + + def __rmul__(self, other): + if isscalar(other): + return poly1d(other * self.coeffs) + else: + other = poly1d(other) + return poly1d(polymul(self.coeffs, other.coeffs)) + + def __add__(self, other): + other = poly1d(other) + return poly1d(polyadd(self.coeffs, other.coeffs)) + + def __radd__(self, other): + other = poly1d(other) + return poly1d(polyadd(self.coeffs, other.coeffs)) + + def __pow__(self, val): + if not isscalar(val) or int(val) != val or val < 0: + raise ValueError("Power to non-negative integers only.") + res = [1] + for _ in range(val): + res = polymul(self.coeffs, res) + return poly1d(res) + + def __sub__(self, other): + other = poly1d(other) + return poly1d(polysub(self.coeffs, other.coeffs)) + + def __rsub__(self, other): + other = poly1d(other) + return poly1d(polysub(other.coeffs, self.coeffs)) + + def __div__(self, other): + if isscalar(other): + return poly1d(self.coeffs/other) + else: + other = poly1d(other) + return polydiv(self, other) + + __truediv__ = __div__ + + def __rdiv__(self, other): + if isscalar(other): + return poly1d(other/self.coeffs) + else: + other = poly1d(other) + return polydiv(other, self) + + __rtruediv__ = __rdiv__ + + def __eq__(self, other): + if not isinstance(other, poly1d): + return NotImplemented + if self.coeffs.shape != other.coeffs.shape: + return False + return (self.coeffs == other.coeffs).all() + + def __ne__(self, other): + if not isinstance(other, poly1d): + return NotImplemented + return not self.__eq__(other) + + + def __getitem__(self, val): + ind = self.order - val + if val > self.order: + return 0 + if val < 0: + return 0 + return self.coeffs[ind] + + def __setitem__(self, key, val): + ind = self.order - key + if key < 0: + raise ValueError("Does not support negative powers.") + if key > self.order: + zr = NX.zeros(key-self.order, self.coeffs.dtype) + self._coeffs = NX.concatenate((zr, self.coeffs)) + ind = 0 + self._coeffs[ind] = val + return + + def __iter__(self): + return iter(self.coeffs) + + def integ(self, m=1, k=0): + """ + Return an antiderivative (indefinite integral) of this polynomial. + + Refer to `polyint` for full documentation. + + See Also + -------- + polyint : equivalent function + + """ + return poly1d(polyint(self.coeffs, m=m, k=k)) + + def deriv(self, m=1): + """ + Return a derivative of this polynomial. + + Refer to `polyder` for full documentation. + + See Also + -------- + polyder : equivalent function + + """ + return poly1d(polyder(self.coeffs, m=m)) + +# Stuff to do on module import + +warnings.simplefilter('always', RankWarning) diff --git a/numpy/lib/recfunctions.py b/numpy/lib/recfunctions.py new file mode 100644 index 0000000..f0d97a3 --- /dev/null +++ b/numpy/lib/recfunctions.py @@ -0,0 +1,1142 @@ +""" +Collection of utilities to manipulate structured arrays. + +Most of these functions were initially implemented by John Hunter for +matplotlib. They have been rewritten and extended for convenience. + +""" +from __future__ import division, absolute_import, print_function + +import sys +import itertools +import numpy as np +import numpy.ma as ma +from numpy import ndarray, recarray +from numpy.ma import MaskedArray +from numpy.ma.mrecords import MaskedRecords +from numpy.lib._iotools import _is_string_like +from numpy.compat import basestring + +if sys.version_info[0] < 3: + from future_builtins import zip + +_check_fill_value = np.ma.core._check_fill_value + + +__all__ = [ + 'append_fields', 'drop_fields', 'find_duplicates', + 'get_fieldstructure', 'join_by', 'merge_arrays', + 'rec_append_fields', 'rec_drop_fields', 'rec_join', + 'recursive_fill_fields', 'rename_fields', 'stack_arrays', + ] + + +def recursive_fill_fields(input, output): + """ + Fills fields from output with fields from input, + with support for nested structures. + + Parameters + ---------- + input : ndarray + Input array. + output : ndarray + Output array. + + Notes + ----- + * `output` should be at least the same size as `input` + + Examples + -------- + >>> from numpy.lib import recfunctions as rfn + >>> a = np.array([(1, 10.), (2, 20.)], dtype=[('A', int), ('B', float)]) + >>> b = np.zeros((3,), dtype=a.dtype) + >>> rfn.recursive_fill_fields(a, b) + array([(1, 10.0), (2, 20.0), (0, 0.0)], + dtype=[('A', '>> dt = np.dtype([(('a', 'A'), int), ('b', float, 3)]) + >>> dt.descr + [(('a', 'A'), '>> get_fieldspec(dt) + [(('a', 'A'), dtype('int32')), ('b', dtype(('>> from numpy.lib import recfunctions as rfn + >>> rfn.get_names(np.empty((1,), dtype=int)) is None + True + >>> rfn.get_names(np.empty((1,), dtype=[('A',int), ('B', float)])) + ('A', 'B') + >>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])]) + >>> rfn.get_names(adtype) + ('a', ('b', ('ba', 'bb'))) + """ + listnames = [] + names = adtype.names + for name in names: + current = adtype[name] + if current.names: + listnames.append((name, tuple(get_names(current)))) + else: + listnames.append(name) + return tuple(listnames) or None + + +def get_names_flat(adtype): + """ + Returns the field names of the input datatype as a tuple. Nested structure + are flattend beforehand. + + Parameters + ---------- + adtype : dtype + Input datatype + + Examples + -------- + >>> from numpy.lib import recfunctions as rfn + >>> rfn.get_names_flat(np.empty((1,), dtype=int)) is None + True + >>> rfn.get_names_flat(np.empty((1,), dtype=[('A',int), ('B', float)])) + ('A', 'B') + >>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])]) + >>> rfn.get_names_flat(adtype) + ('a', 'b', 'ba', 'bb') + """ + listnames = [] + names = adtype.names + for name in names: + listnames.append(name) + current = adtype[name] + if current.names: + listnames.extend(get_names_flat(current)) + return tuple(listnames) or None + + +def flatten_descr(ndtype): + """ + Flatten a structured data-type description. + + Examples + -------- + >>> from numpy.lib import recfunctions as rfn + >>> ndtype = np.dtype([('a', '>> rfn.flatten_descr(ndtype) + (('a', dtype('int32')), ('ba', dtype('float64')), ('bb', dtype('int32'))) + + """ + names = ndtype.names + if names is None: + return (('', ndtype),) + else: + descr = [] + for field in names: + (typ, _) = ndtype.fields[field] + if typ.names: + descr.extend(flatten_descr(typ)) + else: + descr.append((field, typ)) + return tuple(descr) + + +def zip_dtype(seqarrays, flatten=False): + newdtype = [] + if flatten: + for a in seqarrays: + newdtype.extend(flatten_descr(a.dtype)) + else: + for a in seqarrays: + current = a.dtype + if current.names and len(current.names) <= 1: + # special case - dtypes of 0 or 1 field are flattened + newdtype.extend(get_fieldspec(current)) + else: + newdtype.append(('', current)) + return np.dtype(newdtype) + + +def zip_descr(seqarrays, flatten=False): + """ + Combine the dtype description of a series of arrays. + + Parameters + ---------- + seqarrays : sequence of arrays + Sequence of arrays + flatten : {boolean}, optional + Whether to collapse nested descriptions. + """ + return zip_dtype(seqarrays, flatten=flatten).descr + + +def get_fieldstructure(adtype, lastname=None, parents=None,): + """ + Returns a dictionary with fields indexing lists of their parent fields. + + This function is used to simplify access to fields nested in other fields. + + Parameters + ---------- + adtype : np.dtype + Input datatype + lastname : optional + Last processed field name (used internally during recursion). + parents : dictionary + Dictionary of parent fields (used interbally during recursion). + + Examples + -------- + >>> from numpy.lib import recfunctions as rfn + >>> ndtype = np.dtype([('A', int), + ... ('B', [('BA', int), + ... ('BB', [('BBA', int), ('BBB', int)])])]) + >>> rfn.get_fieldstructure(ndtype) + ... # XXX: possible regression, order of BBA and BBB is swapped + {'A': [], 'B': [], 'BA': ['B'], 'BB': ['B'], 'BBA': ['B', 'BB'], 'BBB': ['B', 'BB']} + + """ + if parents is None: + parents = {} + names = adtype.names + for name in names: + current = adtype[name] + if current.names: + if lastname: + parents[name] = [lastname, ] + else: + parents[name] = [] + parents.update(get_fieldstructure(current, name, parents)) + else: + lastparent = [_ for _ in (parents.get(lastname, []) or [])] + if lastparent: + lastparent.append(lastname) + elif lastname: + lastparent = [lastname, ] + parents[name] = lastparent or [] + return parents or None + + +def _izip_fields_flat(iterable): + """ + Returns an iterator of concatenated fields from a sequence of arrays, + collapsing any nested structure. + + """ + for element in iterable: + if isinstance(element, np.void): + for f in _izip_fields_flat(tuple(element)): + yield f + else: + yield element + + +def _izip_fields(iterable): + """ + Returns an iterator of concatenated fields from a sequence of arrays. + + """ + for element in iterable: + if (hasattr(element, '__iter__') and + not isinstance(element, basestring)): + for f in _izip_fields(element): + yield f + elif isinstance(element, np.void) and len(tuple(element)) == 1: + for f in _izip_fields(element): + yield f + else: + yield element + + +def izip_records(seqarrays, fill_value=None, flatten=True): + """ + Returns an iterator of concatenated items from a sequence of arrays. + + Parameters + ---------- + seqarrays : sequence of arrays + Sequence of arrays. + fill_value : {None, integer} + Value used to pad shorter iterables. + flatten : {True, False}, + Whether to + """ + + # Should we flatten the items, or just use a nested approach + if flatten: + zipfunc = _izip_fields_flat + else: + zipfunc = _izip_fields + + if sys.version_info[0] >= 3: + zip_longest = itertools.zip_longest + else: + zip_longest = itertools.izip_longest + + for tup in zip_longest(*seqarrays, fillvalue=fill_value): + yield tuple(zipfunc(tup)) + + +def _fix_output(output, usemask=True, asrecarray=False): + """ + Private function: return a recarray, a ndarray, a MaskedArray + or a MaskedRecords depending on the input parameters + """ + if not isinstance(output, MaskedArray): + usemask = False + if usemask: + if asrecarray: + output = output.view(MaskedRecords) + else: + output = ma.filled(output) + if asrecarray: + output = output.view(recarray) + return output + + +def _fix_defaults(output, defaults=None): + """ + Update the fill_value and masked data of `output` + from the default given in a dictionary defaults. + """ + names = output.dtype.names + (data, mask, fill_value) = (output.data, output.mask, output.fill_value) + for (k, v) in (defaults or {}).items(): + if k in names: + fill_value[k] = v + data[k][mask[k]] = v + return output + + +def merge_arrays(seqarrays, fill_value=-1, flatten=False, + usemask=False, asrecarray=False): + """ + Merge arrays field by field. + + Parameters + ---------- + seqarrays : sequence of ndarrays + Sequence of arrays + fill_value : {float}, optional + Filling value used to pad missing data on the shorter arrays. + flatten : {False, True}, optional + Whether to collapse nested fields. + usemask : {False, True}, optional + Whether to return a masked array or not. + asrecarray : {False, True}, optional + Whether to return a recarray (MaskedRecords) or not. + + Examples + -------- + >>> from numpy.lib import recfunctions as rfn + >>> rfn.merge_arrays((np.array([1, 2]), np.array([10., 20., 30.]))) + masked_array(data = [(1, 10.0) (2, 20.0) (--, 30.0)], + mask = [(False, False) (False, False) (True, False)], + fill_value = (999999, 1e+20), + dtype = [('f0', '>> rfn.merge_arrays((np.array([1, 2]), np.array([10., 20., 30.])), + ... usemask=False) + array([(1, 10.0), (2, 20.0), (-1, 30.0)], + dtype=[('f0', '>> rfn.merge_arrays((np.array([1, 2]).view([('a', int)]), + ... np.array([10., 20., 30.])), + ... usemask=False, asrecarray=True) + rec.array([(1, 10.0), (2, 20.0), (-1, 30.0)], + dtype=[('a', '>> from numpy.lib import recfunctions as rfn + >>> a = np.array([(1, (2, 3.0)), (4, (5, 6.0))], + ... dtype=[('a', int), ('b', [('ba', float), ('bb', int)])]) + >>> rfn.drop_fields(a, 'a') + array([((2.0, 3),), ((5.0, 6),)], + dtype=[('b', [('ba', '>> rfn.drop_fields(a, 'ba') + array([(1, (3,)), (4, (6,))], + dtype=[('a', '>> rfn.drop_fields(a, ['ba', 'bb']) + array([(1,), (4,)], + dtype=[('a', '>> from numpy.lib import recfunctions as rfn + >>> a = np.array([(1, (2, [3.0, 30.])), (4, (5, [6.0, 60.]))], + ... dtype=[('a', int),('b', [('ba', float), ('bb', (float, 2))])]) + >>> rfn.rename_fields(a, {'a':'A', 'bb':'BB'}) + array([(1, (2.0, [3.0, 30.0])), (4, (5.0, [6.0, 60.0]))], + dtype=[('A', ' 1: + data = merge_arrays(data, flatten=True, usemask=usemask, + fill_value=fill_value) + else: + data = data.pop() + # + output = ma.masked_all( + max(len(base), len(data)), + dtype=get_fieldspec(base.dtype) + get_fieldspec(data.dtype)) + output = recursive_fill_fields(base, output) + output = recursive_fill_fields(data, output) + # + return _fix_output(output, usemask=usemask, asrecarray=asrecarray) + + +def rec_append_fields(base, names, data, dtypes=None): + """ + Add new fields to an existing array. + + The names of the fields are given with the `names` arguments, + the corresponding values with the `data` arguments. + If a single field is appended, `names`, `data` and `dtypes` do not have + to be lists but just values. + + Parameters + ---------- + base : array + Input array to extend. + names : string, sequence + String or sequence of strings corresponding to the names + of the new fields. + data : array or sequence of arrays + Array or sequence of arrays storing the fields to add to the base. + dtypes : sequence of datatypes, optional + Datatype or sequence of datatypes. + If None, the datatypes are estimated from the `data`. + + See Also + -------- + append_fields + + Returns + ------- + appended_array : np.recarray + """ + return append_fields(base, names, data=data, dtypes=dtypes, + asrecarray=True, usemask=False) + +def repack_fields(a, align=False, recurse=False): + """ + Re-pack the fields of a structured array or dtype in memory. + + The memory layout of structured datatypes allows fields at arbitrary + byte offsets. This means the fields can be separated by padding bytes, + their offsets can be non-monotonically increasing, and they can overlap. + + This method removes any overlaps and reorders the fields in memory so they + have increasing byte offsets, and adds or removes padding bytes depending + on the `align` option, which behaves like the `align` option to `np.dtype`. + + If `align=False`, this method produces a "packed" memory layout in which + each field starts at the byte the previous field ended, and any padding + bytes are removed. + + If `align=True`, this methods produces an "aligned" memory layout in which + each field's offset is a multiple of its alignment, and the total itemsize + is a multiple of the largest alignment, by adding padding bytes as needed. + + Parameters + ---------- + a : ndarray or dtype + Structured array or dtype for which to repack the fields. + align : boolean + If true, use an "aligned" memory layout, otherwise use a "packed" layout. + recurse : boolean + If True, also repack nested structures. + + Returns + ------- + repacked : ndarray or dtype + Copy of `a` with fields repacked, or `a` itself if no repacking was + needed. + + Examples + -------- + + >>> def print_offsets(d): + ... print("offsets:", [d.fields[name][1] for name in d.names]) + ... print("itemsize:", d.itemsize) + ... + >>> dt = np.dtype('u1,i4,f4', align=True) + >>> dt + dtype({'names':['f0','f1','f2'], 'formats':['u1','>> print_offsets(dt) + offsets: [0, 4, 8] + itemsize: 16 + >>> packed_dt = repack_fields(dt) + >>> packed_dt + dtype([('f0', 'u1'), ('f1', '>> print_offsets(packed_dt) + offsets: [0, 1, 5] + itemsize: 13 + + """ + if not isinstance(a, np.dtype): + dt = repack_fields(a.dtype, align=align, recurse=recurse) + return a.astype(dt, copy=False) + + if a.names is None: + raise ValueError("a must be or have a structured dtype") + + fieldinfo = [] + for name in a.names: + tup = a.fields[name] + if recurse: + fmt = repack_fields(tup[0], align=align, recurse=True) + else: + fmt = tup[0] + if len(tup) == 3: + name = (tup[2], name) + fieldinfo.append((name, fmt)) + + dt = np.dtype(fieldinfo, align=align) + return np.dtype((a.type, dt)) + +def stack_arrays(arrays, defaults=None, usemask=True, asrecarray=False, + autoconvert=False): + """ + Superposes arrays fields by fields + + Parameters + ---------- + arrays : array or sequence + Sequence of input arrays. + defaults : dictionary, optional + Dictionary mapping field names to the corresponding default values. + usemask : {True, False}, optional + Whether to return a MaskedArray (or MaskedRecords is + `asrecarray==True`) or a ndarray. + asrecarray : {False, True}, optional + Whether to return a recarray (or MaskedRecords if `usemask==True`) + or just a flexible-type ndarray. + autoconvert : {False, True}, optional + Whether automatically cast the type of the field to the maximum. + + Examples + -------- + >>> from numpy.lib import recfunctions as rfn + >>> x = np.array([1, 2,]) + >>> rfn.stack_arrays(x) is x + True + >>> z = np.array([('A', 1), ('B', 2)], dtype=[('A', '|S3'), ('B', float)]) + >>> zz = np.array([('a', 10., 100.), ('b', 20., 200.), ('c', 30., 300.)], + ... dtype=[('A', '|S3'), ('B', float), ('C', float)]) + >>> test = rfn.stack_arrays((z,zz)) + >>> test + masked_array(data = [('A', 1.0, --) ('B', 2.0, --) ('a', 10.0, 100.0) ('b', 20.0, 200.0) + ('c', 30.0, 300.0)], + mask = [(False, False, True) (False, False, True) (False, False, False) + (False, False, False) (False, False, False)], + fill_value = ('N/A', 1e+20, 1e+20), + dtype = [('A', '|S3'), ('B', ' '%s'" % + (cdtype, fdtype)) + # Only one field: use concatenate + if len(newdescr) == 1: + output = ma.concatenate(seqarrays) + else: + # + output = ma.masked_all((np.sum(nrecords),), newdescr) + offset = np.cumsum(np.r_[0, nrecords]) + seen = [] + for (a, n, i, j) in zip(seqarrays, fldnames, offset[:-1], offset[1:]): + names = a.dtype.names + if names is None: + output['f%i' % len(seen)][i:j] = a + else: + for name in n: + output[name][i:j] = a[name] + if name not in seen: + seen.append(name) + # + return _fix_output(_fix_defaults(output, defaults), + usemask=usemask, asrecarray=asrecarray) + + +def find_duplicates(a, key=None, ignoremask=True, return_index=False): + """ + Find the duplicates in a structured array along a given key + + Parameters + ---------- + a : array-like + Input array + key : {string, None}, optional + Name of the fields along which to check the duplicates. + If None, the search is performed by records + ignoremask : {True, False}, optional + Whether masked data should be discarded or considered as duplicates. + return_index : {False, True}, optional + Whether to return the indices of the duplicated values. + + Examples + -------- + >>> from numpy.lib import recfunctions as rfn + >>> ndtype = [('a', int)] + >>> a = np.ma.array([1, 1, 1, 2, 2, 3, 3], + ... mask=[0, 0, 1, 0, 0, 0, 1]).view(ndtype) + >>> rfn.find_duplicates(a, ignoremask=True, return_index=True) + ... # XXX: judging by the output, the ignoremask flag has no effect + """ + a = np.asanyarray(a).ravel() + # Get a dictionary of fields + fields = get_fieldstructure(a.dtype) + # Get the sorting data (by selecting the corresponding field) + base = a + if key: + for f in fields[key]: + base = base[f] + base = base[key] + # Get the sorting indices and the sorted data + sortidx = base.argsort() + sortedbase = base[sortidx] + sorteddata = sortedbase.filled() + # Compare the sorting data + flag = (sorteddata[:-1] == sorteddata[1:]) + # If masked data must be ignored, set the flag to false where needed + if ignoremask: + sortedmask = sortedbase.recordmask + flag[sortedmask[1:]] = False + flag = np.concatenate(([False], flag)) + # We need to take the point on the left as well (else we're missing it) + flag[:-1] = flag[:-1] + flag[1:] + duplicates = a[sortidx][flag] + if return_index: + return (duplicates, sortidx[flag]) + else: + return duplicates + + +def join_by(key, r1, r2, jointype='inner', r1postfix='1', r2postfix='2', + defaults=None, usemask=True, asrecarray=False): + """ + Join arrays `r1` and `r2` on key `key`. + + The key should be either a string or a sequence of string corresponding + to the fields used to join the array. An exception is raised if the + `key` field cannot be found in the two input arrays. Neither `r1` nor + `r2` should have any duplicates along `key`: the presence of duplicates + will make the output quite unreliable. Note that duplicates are not + looked for by the algorithm. + + Parameters + ---------- + key : {string, sequence} + A string or a sequence of strings corresponding to the fields used + for comparison. + r1, r2 : arrays + Structured arrays. + jointype : {'inner', 'outer', 'leftouter'}, optional + If 'inner', returns the elements common to both r1 and r2. + If 'outer', returns the common elements as well as the elements of + r1 not in r2 and the elements of not in r2. + If 'leftouter', returns the common elements and the elements of r1 + not in r2. + r1postfix : string, optional + String appended to the names of the fields of r1 that are present + in r2 but absent of the key. + r2postfix : string, optional + String appended to the names of the fields of r2 that are present + in r1 but absent of the key. + defaults : {dictionary}, optional + Dictionary mapping field names to the corresponding default values. + usemask : {True, False}, optional + Whether to return a MaskedArray (or MaskedRecords is + `asrecarray==True`) or a ndarray. + asrecarray : {False, True}, optional + Whether to return a recarray (or MaskedRecords if `usemask==True`) + or just a flexible-type ndarray. + + Notes + ----- + * The output is sorted along the key. + * A temporary array is formed by dropping the fields not in the key for + the two arrays and concatenating the result. This array is then + sorted, and the common entries selected. The output is constructed by + filling the fields with the selected entries. Matching is not + preserved if there are some duplicates... + + """ + # Check jointype + if jointype not in ('inner', 'outer', 'leftouter'): + raise ValueError( + "The 'jointype' argument should be in 'inner', " + "'outer' or 'leftouter' (got '%s' instead)" % jointype + ) + # If we have a single key, put it in a tuple + if isinstance(key, basestring): + key = (key,) + + # Check the keys + if len(set(key)) != len(key): + dup = next(x for n,x in enumerate(key) if x in key[n+1:]) + raise ValueError("duplicate join key %r" % dup) + for name in key: + if name not in r1.dtype.names: + raise ValueError('r1 does not have key field %r' % name) + if name not in r2.dtype.names: + raise ValueError('r2 does not have key field %r' % name) + + # Make sure we work with ravelled arrays + r1 = r1.ravel() + r2 = r2.ravel() + # Fixme: nb2 below is never used. Commenting out for pyflakes. + # (nb1, nb2) = (len(r1), len(r2)) + nb1 = len(r1) + (r1names, r2names) = (r1.dtype.names, r2.dtype.names) + + # Check the names for collision + collisions = (set(r1names) & set(r2names)) - set(key) + if collisions and not (r1postfix or r2postfix): + msg = "r1 and r2 contain common names, r1postfix and r2postfix " + msg += "can't both be empty" + raise ValueError(msg) + + # Make temporary arrays of just the keys + # (use order of keys in `r1` for back-compatibility) + key1 = [ n for n in r1names if n in key ] + r1k = _keep_fields(r1, key1) + r2k = _keep_fields(r2, key1) + + # Concatenate the two arrays for comparison + aux = ma.concatenate((r1k, r2k)) + idx_sort = aux.argsort(order=key) + aux = aux[idx_sort] + # + # Get the common keys + flag_in = ma.concatenate(([False], aux[1:] == aux[:-1])) + flag_in[:-1] = flag_in[1:] + flag_in[:-1] + idx_in = idx_sort[flag_in] + idx_1 = idx_in[(idx_in < nb1)] + idx_2 = idx_in[(idx_in >= nb1)] - nb1 + (r1cmn, r2cmn) = (len(idx_1), len(idx_2)) + if jointype == 'inner': + (r1spc, r2spc) = (0, 0) + elif jointype == 'outer': + idx_out = idx_sort[~flag_in] + idx_1 = np.concatenate((idx_1, idx_out[(idx_out < nb1)])) + idx_2 = np.concatenate((idx_2, idx_out[(idx_out >= nb1)] - nb1)) + (r1spc, r2spc) = (len(idx_1) - r1cmn, len(idx_2) - r2cmn) + elif jointype == 'leftouter': + idx_out = idx_sort[~flag_in] + idx_1 = np.concatenate((idx_1, idx_out[(idx_out < nb1)])) + (r1spc, r2spc) = (len(idx_1) - r1cmn, 0) + # Select the entries from each input + (s1, s2) = (r1[idx_1], r2[idx_2]) + # + # Build the new description of the output array ....... + # Start with the key fields + ndtype = get_fieldspec(r1k.dtype) + + # Add the fields from r1 + for fname, fdtype in get_fieldspec(r1.dtype): + if fname not in key: + ndtype.append((fname, fdtype)) + + # Add the fields from r2 + for fname, fdtype in get_fieldspec(r2.dtype): + # Have we seen the current name already ? + # we need to rebuild this list every time + names = list(name for name, dtype in ndtype) + try: + nameidx = names.index(fname) + except ValueError: + #... we haven't: just add the description to the current list + ndtype.append((fname, fdtype)) + else: + # collision + _, cdtype = ndtype[nameidx] + if fname in key: + # The current field is part of the key: take the largest dtype + ndtype[nameidx] = (fname, max(fdtype, cdtype)) + else: + # The current field is not part of the key: add the suffixes, + # and place the new field adjacent to the old one + ndtype[nameidx:nameidx + 1] = [ + (fname + r1postfix, cdtype), + (fname + r2postfix, fdtype) + ] + # Rebuild a dtype from the new fields + ndtype = np.dtype(ndtype) + # Find the largest nb of common fields : + # r1cmn and r2cmn should be equal, but... + cmn = max(r1cmn, r2cmn) + # Construct an empty array + output = ma.masked_all((cmn + r1spc + r2spc,), dtype=ndtype) + names = output.dtype.names + for f in r1names: + selected = s1[f] + if f not in names or (f in r2names and not r2postfix and f not in key): + f += r1postfix + current = output[f] + current[:r1cmn] = selected[:r1cmn] + if jointype in ('outer', 'leftouter'): + current[cmn:cmn + r1spc] = selected[r1cmn:] + for f in r2names: + selected = s2[f] + if f not in names or (f in r1names and not r1postfix and f not in key): + f += r2postfix + current = output[f] + current[:r2cmn] = selected[:r2cmn] + if (jointype == 'outer') and r2spc: + current[-r2spc:] = selected[r2cmn:] + # Sort and finalize the output + output.sort(order=key) + kwargs = dict(usemask=usemask, asrecarray=asrecarray) + return _fix_output(_fix_defaults(output, defaults), **kwargs) + + +def rec_join(key, r1, r2, jointype='inner', r1postfix='1', r2postfix='2', + defaults=None): + """ + Join arrays `r1` and `r2` on keys. + Alternative to join_by, that always returns a np.recarray. + + See Also + -------- + join_by : equivalent function + """ + kwargs = dict(jointype=jointype, r1postfix=r1postfix, r2postfix=r2postfix, + defaults=defaults, usemask=False, asrecarray=True) + return join_by(key, r1, r2, **kwargs) diff --git a/numpy/lib/scimath.py b/numpy/lib/scimath.py new file mode 100644 index 0000000..e07caf8 --- /dev/null +++ b/numpy/lib/scimath.py @@ -0,0 +1,566 @@ +""" +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.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 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) + +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) + +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(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 : int + The base 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) + +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(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) + +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) + +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) + +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.matrix(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) diff --git a/numpy/lib/setup.py b/numpy/lib/setup.py new file mode 100644 index 0000000..d342410 --- /dev/null +++ b/numpy/lib/setup.py @@ -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) diff --git a/numpy/lib/shape_base.py b/numpy/lib/shape_base.py new file mode 100644 index 0000000..41ef28e --- /dev/null +++ b/numpy/lib/shape_base.py @@ -0,0 +1,932 @@ +from __future__ import division, absolute_import, print_function + +import warnings + +import numpy.core.numeric as _nx +from numpy.core.numeric import ( + asarray, zeros, outer, concatenate, array, asanyarray + ) +from numpy.core.fromnumeric import product, reshape, transpose +from numpy.core.multiarray import normalize_axis_index +from numpy.core import vstack, atleast_3d +from numpy.lib.index_tricks import ndindex +from numpy.matrixlib.defmatrix import matrix # this raises all the right alarm bells + + +__all__ = [ + 'column_stack', 'row_stack', 'dstack', 'array_split', 'split', + 'hsplit', 'vsplit', 'dsplit', 'apply_over_axes', 'expand_dims', + 'apply_along_axis', 'kron', 'tile', 'get_array_wrap' + ] + + +def apply_along_axis(func1d, axis, arr, *args, **kwargs): + """ + Apply a function to 1-D slices along the given axis. + + Execute `func1d(a, *args)` where `func1d` operates on 1-D arrays and `a` + is a 1-D slice of `arr` along `axis`. + + This is equivalent to (but faster than) the following use of `ndindex` and + `s_`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of indices:: + + Ni, Nk = a.shape[:axis], a.shape[axis+1:] + for ii in ndindex(Ni): + for kk in ndindex(Nk): + f = func1d(arr[ii + s_[:,] + kk]) + Nj = f.shape + for jj in ndindex(Nj): + out[ii + jj + kk] = f[jj] + + Equivalently, eliminating the inner loop, this can be expressed as:: + + Ni, Nk = a.shape[:axis], a.shape[axis+1:] + for ii in ndindex(Ni): + for kk in ndindex(Nk): + out[ii + s_[...,] + kk] = func1d(arr[ii + s_[:,] + kk]) + + Parameters + ---------- + func1d : function (M,) -> (Nj...) + This function should accept 1-D arrays. It is applied to 1-D + slices of `arr` along the specified axis. + axis : integer + Axis along which `arr` is sliced. + arr : ndarray (Ni..., M, Nk...) + Input array. + args : any + Additional arguments to `func1d`. + kwargs : any + Additional named arguments to `func1d`. + + .. versionadded:: 1.9.0 + + + Returns + ------- + out : ndarray (Ni..., Nj..., Nk...) + The output array. The shape of `out` is identical to the shape of + `arr`, except along the `axis` dimension. This axis is removed, and + replaced with new dimensions equal to the shape of the return value + of `func1d`. So if `func1d` returns a scalar `out` will have one + fewer dimensions than `arr`. + + See Also + -------- + apply_over_axes : Apply a function repeatedly over multiple axes. + + Examples + -------- + >>> def my_func(a): + ... \"\"\"Average first and last element of a 1-D array\"\"\" + ... return (a[0] + a[-1]) * 0.5 + >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) + >>> np.apply_along_axis(my_func, 0, b) + array([ 4., 5., 6.]) + >>> np.apply_along_axis(my_func, 1, b) + array([ 2., 5., 8.]) + + For a function that returns a 1D array, the number of dimensions in + `outarr` is the same as `arr`. + + >>> b = np.array([[8,1,7], [4,3,9], [5,2,6]]) + >>> np.apply_along_axis(sorted, 1, b) + array([[1, 7, 8], + [3, 4, 9], + [2, 5, 6]]) + + For a function that returns a higher dimensional array, those dimensions + are inserted in place of the `axis` dimension. + + >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) + >>> np.apply_along_axis(np.diag, -1, b) + array([[[1, 0, 0], + [0, 2, 0], + [0, 0, 3]], + [[4, 0, 0], + [0, 5, 0], + [0, 0, 6]], + [[7, 0, 0], + [0, 8, 0], + [0, 0, 9]]]) + """ + # handle negative axes + arr = asanyarray(arr) + nd = arr.ndim + axis = normalize_axis_index(axis, nd) + + # arr, with the iteration axis at the end + in_dims = list(range(nd)) + inarr_view = transpose(arr, in_dims[:axis] + in_dims[axis+1:] + [axis]) + + # compute indices for the iteration axes, and append a trailing ellipsis to + # prevent 0d arrays decaying to scalars, which fixes gh-8642 + inds = ndindex(inarr_view.shape[:-1]) + inds = (ind + (Ellipsis,) for ind in inds) + + # invoke the function on the first item + try: + ind0 = next(inds) + except StopIteration: + raise ValueError('Cannot apply_along_axis when any iteration dimensions are 0') + res = asanyarray(func1d(inarr_view[ind0], *args, **kwargs)) + + # build a buffer for storing evaluations of func1d. + # remove the requested axis, and add the new ones on the end. + # laid out so that each write is contiguous. + # for a tuple index inds, buff[inds] = func1d(inarr_view[inds]) + buff = zeros(inarr_view.shape[:-1] + res.shape, res.dtype) + + # permutation of axes such that out = buff.transpose(buff_permute) + buff_dims = list(range(buff.ndim)) + buff_permute = ( + buff_dims[0 : axis] + + buff_dims[buff.ndim-res.ndim : buff.ndim] + + buff_dims[axis : buff.ndim-res.ndim] + ) + + # matrices have a nasty __array_prepare__ and __array_wrap__ + if not isinstance(res, matrix): + buff = res.__array_prepare__(buff) + + # save the first result, then compute and save all remaining results + buff[ind0] = res + for ind in inds: + buff[ind] = asanyarray(func1d(inarr_view[ind], *args, **kwargs)) + + if not isinstance(res, matrix): + # wrap the array, to preserve subclasses + buff = res.__array_wrap__(buff) + + # finally, rotate the inserted axes back to where they belong + return transpose(buff, buff_permute) + + else: + # matrices have to be transposed first, because they collapse dimensions! + out_arr = transpose(buff, buff_permute) + return res.__array_wrap__(out_arr) + + +def apply_over_axes(func, a, axes): + """ + Apply a function repeatedly over multiple axes. + + `func` is called as `res = func(a, axis)`, where `axis` is the first + element of `axes`. The result `res` of the function call must have + either the same dimensions as `a` or one less dimension. If `res` + has one less dimension than `a`, a dimension is inserted before + `axis`. The call to `func` is then repeated for each axis in `axes`, + with `res` as the first argument. + + Parameters + ---------- + func : function + This function must take two arguments, `func(a, axis)`. + a : array_like + Input array. + axes : array_like + Axes over which `func` is applied; the elements must be integers. + + Returns + ------- + apply_over_axis : ndarray + The output array. The number of dimensions is the same as `a`, + but the shape can be different. This depends on whether `func` + changes the shape of its output with respect to its input. + + See Also + -------- + apply_along_axis : + Apply a function to 1-D slices of an array along the given axis. + + Notes + ------ + This function is equivalent to tuple axis arguments to reorderable ufuncs + with keepdims=True. Tuple axis arguments to ufuncs have been available since + version 1.7.0. + + Examples + -------- + >>> a = np.arange(24).reshape(2,3,4) + >>> a + array([[[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]], + [[12, 13, 14, 15], + [16, 17, 18, 19], + [20, 21, 22, 23]]]) + + Sum over axes 0 and 2. The result has same number of dimensions + as the original array: + + >>> np.apply_over_axes(np.sum, a, [0,2]) + array([[[ 60], + [ 92], + [124]]]) + + Tuple axis arguments to ufuncs are equivalent: + + >>> np.sum(a, axis=(0,2), keepdims=True) + array([[[ 60], + [ 92], + [124]]]) + + """ + val = asarray(a) + N = a.ndim + if array(axes).ndim == 0: + axes = (axes,) + for axis in axes: + if axis < 0: + axis = N + axis + args = (val, axis) + res = func(*args) + if res.ndim == val.ndim: + val = res + else: + res = expand_dims(res, axis) + if res.ndim == val.ndim: + val = res + else: + raise ValueError("function is not returning " + "an array of the correct shape") + return val + +def expand_dims(a, axis): + """ + Expand the shape of an array. + + Insert a new axis that will appear at the `axis` position in the expanded + array shape. + + .. note:: Previous to NumPy 1.13.0, neither ``axis < -a.ndim - 1`` nor + ``axis > a.ndim`` raised errors or put the new axis where documented. + Those axis values are now deprecated and will raise an AxisError in the + future. + + Parameters + ---------- + a : array_like + Input array. + axis : int + Position in the expanded axes where the new axis is placed. + + Returns + ------- + res : ndarray + Output array. The number of dimensions is one greater than that of + the input array. + + See Also + -------- + squeeze : The inverse operation, removing singleton dimensions + reshape : Insert, remove, and combine dimensions, and resize existing ones + doc.indexing, atleast_1d, atleast_2d, atleast_3d + + Examples + -------- + >>> x = np.array([1,2]) + >>> x.shape + (2,) + + The following is equivalent to ``x[np.newaxis,:]`` or ``x[np.newaxis]``: + + >>> y = np.expand_dims(x, axis=0) + >>> y + array([[1, 2]]) + >>> y.shape + (1, 2) + + >>> y = np.expand_dims(x, axis=1) # Equivalent to x[:,np.newaxis] + >>> y + array([[1], + [2]]) + >>> y.shape + (2, 1) + + Note that some examples may use ``None`` instead of ``np.newaxis``. These + are the same objects: + + >>> np.newaxis is None + True + + """ + a = asarray(a) + shape = a.shape + if axis > a.ndim or axis < -a.ndim - 1: + # 2017-05-17, 1.13.0 + warnings.warn("Both axis > a.ndim and axis < -a.ndim - 1 are " + "deprecated and will raise an AxisError in the future.", + DeprecationWarning, stacklevel=2) + # When the deprecation period expires, delete this if block, + if axis < 0: + axis = axis + a.ndim + 1 + # and uncomment the following line. + # axis = normalize_axis_index(axis, a.ndim + 1) + return a.reshape(shape[:axis] + (1,) + shape[axis:]) + +row_stack = vstack + +def column_stack(tup): + """ + Stack 1-D arrays as columns into a 2-D array. + + Take a sequence of 1-D arrays and stack them as columns + to make a single 2-D array. 2-D arrays are stacked as-is, + just like with `hstack`. 1-D arrays are turned into 2-D columns + first. + + Parameters + ---------- + tup : sequence of 1-D or 2-D arrays. + Arrays to stack. All of them must have the same first dimension. + + Returns + ------- + stacked : 2-D array + The array formed by stacking the given arrays. + + See Also + -------- + stack, hstack, vstack, concatenate + + Examples + -------- + >>> a = np.array((1,2,3)) + >>> b = np.array((2,3,4)) + >>> np.column_stack((a,b)) + array([[1, 2], + [2, 3], + [3, 4]]) + + """ + arrays = [] + for v in tup: + arr = array(v, copy=False, subok=True) + if arr.ndim < 2: + arr = array(arr, copy=False, subok=True, ndmin=2).T + arrays.append(arr) + return _nx.concatenate(arrays, 1) + +def dstack(tup): + """ + Stack arrays in sequence depth wise (along third axis). + + This is equivalent to concatenation along the third axis after 2-D arrays + of shape `(M,N)` have been reshaped to `(M,N,1)` and 1-D arrays of shape + `(N,)` have been reshaped to `(1,N,1)`. Rebuilds arrays divided by + `dsplit`. + + This function makes most sense for arrays with up to 3 dimensions. For + instance, for pixel-data with a height (first axis), width (second axis), + and r/g/b channels (third axis). The functions `concatenate`, `stack` and + `block` provide more general stacking and concatenation operations. + + Parameters + ---------- + tup : sequence of arrays + The arrays must have the same shape along all but the third axis. + 1-D or 2-D arrays must have the same shape. + + Returns + ------- + stacked : ndarray + The array formed by stacking the given arrays, will be at least 3-D. + + See Also + -------- + stack : Join a sequence of arrays along a new axis. + vstack : Stack along first axis. + hstack : Stack along second axis. + concatenate : Join a sequence of arrays along an existing axis. + dsplit : Split array along third axis. + + Examples + -------- + >>> a = np.array((1,2,3)) + >>> b = np.array((2,3,4)) + >>> np.dstack((a,b)) + array([[[1, 2], + [2, 3], + [3, 4]]]) + + >>> a = np.array([[1],[2],[3]]) + >>> b = np.array([[2],[3],[4]]) + >>> np.dstack((a,b)) + array([[[1, 2]], + [[2, 3]], + [[3, 4]]]) + + """ + return _nx.concatenate([atleast_3d(_m) for _m in tup], 2) + +def _replace_zero_by_x_arrays(sub_arys): + for i in range(len(sub_arys)): + if _nx.ndim(sub_arys[i]) == 0: + sub_arys[i] = _nx.empty(0, dtype=sub_arys[i].dtype) + elif _nx.sometrue(_nx.equal(_nx.shape(sub_arys[i]), 0)): + sub_arys[i] = _nx.empty(0, dtype=sub_arys[i].dtype) + return sub_arys + +def array_split(ary, indices_or_sections, axis=0): + """ + Split an array into multiple sub-arrays. + + Please refer to the ``split`` documentation. The only difference + between these functions is that ``array_split`` allows + `indices_or_sections` to be an integer that does *not* equally + divide the axis. For an array of length l that should be split + into n sections, it returns l % n sub-arrays of size l//n + 1 + and the rest of size l//n. + + See Also + -------- + split : Split array into multiple sub-arrays of equal size. + + Examples + -------- + >>> x = np.arange(8.0) + >>> np.array_split(x, 3) + [array([ 0., 1., 2.]), array([ 3., 4., 5.]), array([ 6., 7.])] + + >>> x = np.arange(7.0) + >>> np.array_split(x, 3) + [array([ 0., 1., 2.]), array([ 3., 4.]), array([ 5., 6.])] + + """ + try: + Ntotal = ary.shape[axis] + except AttributeError: + Ntotal = len(ary) + try: + # handle scalar case. + Nsections = len(indices_or_sections) + 1 + div_points = [0] + list(indices_or_sections) + [Ntotal] + except TypeError: + # indices_or_sections is a scalar, not an array. + Nsections = int(indices_or_sections) + if Nsections <= 0: + raise ValueError('number sections must be larger than 0.') + Neach_section, extras = divmod(Ntotal, Nsections) + section_sizes = ([0] + + extras * [Neach_section+1] + + (Nsections-extras) * [Neach_section]) + div_points = _nx.array(section_sizes).cumsum() + + sub_arys = [] + sary = _nx.swapaxes(ary, axis, 0) + for i in range(Nsections): + st = div_points[i] + end = div_points[i + 1] + sub_arys.append(_nx.swapaxes(sary[st:end], axis, 0)) + + return sub_arys + + +def split(ary,indices_or_sections,axis=0): + """ + Split an array into multiple sub-arrays. + + Parameters + ---------- + ary : ndarray + Array to be divided into sub-arrays. + indices_or_sections : int or 1-D array + If `indices_or_sections` is an integer, N, the array will be divided + into N equal arrays along `axis`. If such a split is not possible, + an error is raised. + + If `indices_or_sections` is a 1-D array of sorted integers, the entries + indicate where along `axis` the array is split. For example, + ``[2, 3]`` would, for ``axis=0``, result in + + - ary[:2] + - ary[2:3] + - ary[3:] + + If an index exceeds the dimension of the array along `axis`, + an empty sub-array is returned correspondingly. + axis : int, optional + The axis along which to split, default is 0. + + Returns + ------- + sub-arrays : list of ndarrays + A list of sub-arrays. + + Raises + ------ + ValueError + If `indices_or_sections` is given as an integer, but + a split does not result in equal division. + + See Also + -------- + array_split : Split an array into multiple sub-arrays of equal or + near-equal size. Does not raise an exception if + an equal division cannot be made. + hsplit : Split array into multiple sub-arrays horizontally (column-wise). + vsplit : Split array into multiple sub-arrays vertically (row wise). + dsplit : Split array into multiple sub-arrays along the 3rd axis (depth). + concatenate : Join a sequence of arrays along an existing axis. + stack : Join a sequence of arrays along a new axis. + hstack : Stack arrays in sequence horizontally (column wise). + vstack : Stack arrays in sequence vertically (row wise). + dstack : Stack arrays in sequence depth wise (along third dimension). + + Examples + -------- + >>> x = np.arange(9.0) + >>> np.split(x, 3) + [array([ 0., 1., 2.]), array([ 3., 4., 5.]), array([ 6., 7., 8.])] + + >>> x = np.arange(8.0) + >>> np.split(x, [3, 5, 6, 10]) + [array([ 0., 1., 2.]), + array([ 3., 4.]), + array([ 5.]), + array([ 6., 7.]), + array([], dtype=float64)] + + """ + try: + len(indices_or_sections) + except TypeError: + sections = indices_or_sections + N = ary.shape[axis] + if N % sections: + raise ValueError( + 'array split does not result in an equal division') + res = array_split(ary, indices_or_sections, axis) + return res + +def hsplit(ary, indices_or_sections): + """ + Split an array into multiple sub-arrays horizontally (column-wise). + + Please refer to the `split` documentation. `hsplit` is equivalent + to `split` with ``axis=1``, the array is always split along the second + axis regardless of the array dimension. + + See Also + -------- + split : Split an array into multiple sub-arrays of equal size. + + Examples + -------- + >>> x = np.arange(16.0).reshape(4, 4) + >>> x + array([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.], + [ 12., 13., 14., 15.]]) + >>> np.hsplit(x, 2) + [array([[ 0., 1.], + [ 4., 5.], + [ 8., 9.], + [ 12., 13.]]), + array([[ 2., 3.], + [ 6., 7.], + [ 10., 11.], + [ 14., 15.]])] + >>> np.hsplit(x, np.array([3, 6])) + [array([[ 0., 1., 2.], + [ 4., 5., 6.], + [ 8., 9., 10.], + [ 12., 13., 14.]]), + array([[ 3.], + [ 7.], + [ 11.], + [ 15.]]), + array([], dtype=float64)] + + With a higher dimensional array the split is still along the second axis. + + >>> x = np.arange(8.0).reshape(2, 2, 2) + >>> x + array([[[ 0., 1.], + [ 2., 3.]], + [[ 4., 5.], + [ 6., 7.]]]) + >>> np.hsplit(x, 2) + [array([[[ 0., 1.]], + [[ 4., 5.]]]), + array([[[ 2., 3.]], + [[ 6., 7.]]])] + + """ + if _nx.ndim(ary) == 0: + raise ValueError('hsplit only works on arrays of 1 or more dimensions') + if ary.ndim > 1: + return split(ary, indices_or_sections, 1) + else: + return split(ary, indices_or_sections, 0) + +def vsplit(ary, indices_or_sections): + """ + Split an array into multiple sub-arrays vertically (row-wise). + + Please refer to the ``split`` documentation. ``vsplit`` is equivalent + to ``split`` with `axis=0` (default), the array is always split along the + first axis regardless of the array dimension. + + See Also + -------- + split : Split an array into multiple sub-arrays of equal size. + + Examples + -------- + >>> x = np.arange(16.0).reshape(4, 4) + >>> x + array([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.], + [ 12., 13., 14., 15.]]) + >>> np.vsplit(x, 2) + [array([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.]]), + array([[ 8., 9., 10., 11.], + [ 12., 13., 14., 15.]])] + >>> np.vsplit(x, np.array([3, 6])) + [array([[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.], + [ 8., 9., 10., 11.]]), + array([[ 12., 13., 14., 15.]]), + array([], dtype=float64)] + + With a higher dimensional array the split is still along the first axis. + + >>> x = np.arange(8.0).reshape(2, 2, 2) + >>> x + array([[[ 0., 1.], + [ 2., 3.]], + [[ 4., 5.], + [ 6., 7.]]]) + >>> np.vsplit(x, 2) + [array([[[ 0., 1.], + [ 2., 3.]]]), + array([[[ 4., 5.], + [ 6., 7.]]])] + + """ + if _nx.ndim(ary) < 2: + raise ValueError('vsplit only works on arrays of 2 or more dimensions') + return split(ary, indices_or_sections, 0) + +def dsplit(ary, indices_or_sections): + """ + Split array into multiple sub-arrays along the 3rd axis (depth). + + Please refer to the `split` documentation. `dsplit` is equivalent + to `split` with ``axis=2``, the array is always split along the third + axis provided the array dimension is greater than or equal to 3. + + See Also + -------- + split : Split an array into multiple sub-arrays of equal size. + + Examples + -------- + >>> x = np.arange(16.0).reshape(2, 2, 4) + >>> x + array([[[ 0., 1., 2., 3.], + [ 4., 5., 6., 7.]], + [[ 8., 9., 10., 11.], + [ 12., 13., 14., 15.]]]) + >>> np.dsplit(x, 2) + [array([[[ 0., 1.], + [ 4., 5.]], + [[ 8., 9.], + [ 12., 13.]]]), + array([[[ 2., 3.], + [ 6., 7.]], + [[ 10., 11.], + [ 14., 15.]]])] + >>> np.dsplit(x, np.array([3, 6])) + [array([[[ 0., 1., 2.], + [ 4., 5., 6.]], + [[ 8., 9., 10.], + [ 12., 13., 14.]]]), + array([[[ 3.], + [ 7.]], + [[ 11.], + [ 15.]]]), + array([], dtype=float64)] + + """ + if _nx.ndim(ary) < 3: + raise ValueError('dsplit only works on arrays of 3 or more dimensions') + return split(ary, indices_or_sections, 2) + +def get_array_prepare(*args): + """Find the wrapper for the array with the highest priority. + + In case of ties, leftmost wins. If no wrapper is found, return None + """ + wrappers = sorted((getattr(x, '__array_priority__', 0), -i, + x.__array_prepare__) for i, x in enumerate(args) + if hasattr(x, '__array_prepare__')) + if wrappers: + return wrappers[-1][-1] + return None + +def get_array_wrap(*args): + """Find the wrapper for the array with the highest priority. + + In case of ties, leftmost wins. If no wrapper is found, return None + """ + wrappers = sorted((getattr(x, '__array_priority__', 0), -i, + x.__array_wrap__) for i, x in enumerate(args) + if hasattr(x, '__array_wrap__')) + if wrappers: + return wrappers[-1][-1] + return None + +def kron(a, b): + """ + Kronecker product of two arrays. + + Computes the Kronecker product, a composite array made of blocks of the + second array scaled by the first. + + Parameters + ---------- + a, b : array_like + + Returns + ------- + out : ndarray + + See Also + -------- + outer : The outer product + + Notes + ----- + The function assumes that the number of dimensions of `a` and `b` + are the same, if necessary prepending the smallest with ones. + If `a.shape = (r0,r1,..,rN)` and `b.shape = (s0,s1,...,sN)`, + the Kronecker product has shape `(r0*s0, r1*s1, ..., rN*SN)`. + The elements are products of elements from `a` and `b`, organized + explicitly by:: + + kron(a,b)[k0,k1,...,kN] = a[i0,i1,...,iN] * b[j0,j1,...,jN] + + where:: + + kt = it * st + jt, t = 0,...,N + + In the common 2-D case (N=1), the block structure can be visualized:: + + [[ a[0,0]*b, a[0,1]*b, ... , a[0,-1]*b ], + [ ... ... ], + [ a[-1,0]*b, a[-1,1]*b, ... , a[-1,-1]*b ]] + + + Examples + -------- + >>> np.kron([1,10,100], [5,6,7]) + array([ 5, 6, 7, 50, 60, 70, 500, 600, 700]) + >>> np.kron([5,6,7], [1,10,100]) + array([ 5, 50, 500, 6, 60, 600, 7, 70, 700]) + + >>> np.kron(np.eye(2), np.ones((2,2))) + array([[ 1., 1., 0., 0.], + [ 1., 1., 0., 0.], + [ 0., 0., 1., 1.], + [ 0., 0., 1., 1.]]) + + >>> a = np.arange(100).reshape((2,5,2,5)) + >>> b = np.arange(24).reshape((2,3,4)) + >>> c = np.kron(a,b) + >>> c.shape + (2, 10, 6, 20) + >>> I = (1,3,0,2) + >>> J = (0,2,1) + >>> J1 = (0,) + J # extend to ndim=4 + >>> S1 = (1,) + b.shape + >>> K = tuple(np.array(I) * np.array(S1) + np.array(J1)) + >>> c[K] == a[I]*b[J] + True + + """ + b = asanyarray(b) + a = array(a, copy=False, subok=True, ndmin=b.ndim) + ndb, nda = b.ndim, a.ndim + if (nda == 0 or ndb == 0): + return _nx.multiply(a, b) + as_ = a.shape + bs = b.shape + if not a.flags.contiguous: + a = reshape(a, as_) + if not b.flags.contiguous: + b = reshape(b, bs) + nd = ndb + if (ndb != nda): + if (ndb > nda): + as_ = (1,)*(ndb-nda) + as_ + else: + bs = (1,)*(nda-ndb) + bs + nd = nda + result = outer(a, b).reshape(as_+bs) + axis = nd-1 + for _ in range(nd): + result = concatenate(result, axis=axis) + wrapper = get_array_prepare(a, b) + if wrapper is not None: + result = wrapper(result) + wrapper = get_array_wrap(a, b) + if wrapper is not None: + result = wrapper(result) + return result + + +def tile(A, reps): + """ + Construct an array by repeating A the number of times given by reps. + + If `reps` has length ``d``, the result will have dimension of + ``max(d, A.ndim)``. + + If ``A.ndim < d``, `A` is promoted to be d-dimensional by prepending new + axes. So a shape (3,) array is promoted to (1, 3) for 2-D replication, + or shape (1, 1, 3) for 3-D replication. If this is not the desired + behavior, promote `A` to d-dimensions manually before calling this + function. + + If ``A.ndim > d``, `reps` is promoted to `A`.ndim by pre-pending 1's to it. + Thus for an `A` of shape (2, 3, 4, 5), a `reps` of (2, 2) is treated as + (1, 1, 2, 2). + + Note : Although tile may be used for broadcasting, it is strongly + recommended to use numpy's broadcasting operations and functions. + + Parameters + ---------- + A : array_like + The input array. + reps : array_like + The number of repetitions of `A` along each axis. + + Returns + ------- + c : ndarray + The tiled output array. + + See Also + -------- + repeat : Repeat elements of an array. + broadcast_to : Broadcast an array to a new shape + + Examples + -------- + >>> a = np.array([0, 1, 2]) + >>> np.tile(a, 2) + array([0, 1, 2, 0, 1, 2]) + >>> np.tile(a, (2, 2)) + array([[0, 1, 2, 0, 1, 2], + [0, 1, 2, 0, 1, 2]]) + >>> np.tile(a, (2, 1, 2)) + array([[[0, 1, 2, 0, 1, 2]], + [[0, 1, 2, 0, 1, 2]]]) + + >>> b = np.array([[1, 2], [3, 4]]) + >>> np.tile(b, 2) + array([[1, 2, 1, 2], + [3, 4, 3, 4]]) + >>> np.tile(b, (2, 1)) + array([[1, 2], + [3, 4], + [1, 2], + [3, 4]]) + + >>> c = np.array([1,2,3,4]) + >>> np.tile(c,(4,1)) + array([[1, 2, 3, 4], + [1, 2, 3, 4], + [1, 2, 3, 4], + [1, 2, 3, 4]]) + """ + try: + tup = tuple(reps) + except TypeError: + tup = (reps,) + d = len(tup) + if all(x == 1 for x in tup) and isinstance(A, _nx.ndarray): + # Fixes the problem that the function does not make a copy if A is a + # numpy array and the repetitions are 1 in all dimensions + return _nx.array(A, copy=True, subok=True, ndmin=d) + else: + # Note that no copy of zero-sized arrays is made. However since they + # have no data there is no risk of an inadvertent overwrite. + c = _nx.array(A, copy=False, subok=True, ndmin=d) + if (d < c.ndim): + tup = (1,)*(c.ndim-d) + tup + shape_out = tuple(s*t for s, t in zip(c.shape, tup)) + n = c.size + if n > 0: + for dim_in, nrep in zip(c.shape, tup): + if nrep != 1: + c = c.reshape(-1, n).repeat(nrep, 0) + n //= dim_in + return c.reshape(shape_out) diff --git a/numpy/lib/stride_tricks.py b/numpy/lib/stride_tricks.py new file mode 100644 index 0000000..6c240db --- /dev/null +++ b/numpy/lib/stride_tricks.py @@ -0,0 +1,258 @@ +""" +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 + +__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' + broadcast = np.nditer( + (array,), flags=['multi_index', 'refs_ok', 'zerosize_ok'] + extras, + op_flags=[op_flag], itershape=shape, order='C').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(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(*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([[1],[2],[3]]) + >>> np.broadcast_arrays(x, y) + [array([[1, 2, 3], + [1, 2, 3], + [1, 2, 3]]), array([[1, 1, 1], + [2, 2, 2], + [3, 3, 3]])] + + 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], + [1, 2, 3]]), array([[1, 1, 1], + [2, 2, 2], + [3, 3, 3]])] + + """ + # 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(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] diff --git a/numpy/lib/tests/__init__.py b/numpy/lib/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/lib/tests/__init__.py diff --git a/numpy/lib/tests/data/py2-objarr.npy b/numpy/lib/tests/data/py2-objarr.npy new file mode 100644 index 0000000..12936c9 Binary files /dev/null and b/numpy/lib/tests/data/py2-objarr.npy differ diff --git a/numpy/lib/tests/data/py2-objarr.npz b/numpy/lib/tests/data/py2-objarr.npz new file mode 100644 index 0000000..68a3b53 Binary files /dev/null and b/numpy/lib/tests/data/py2-objarr.npz differ diff --git a/numpy/lib/tests/data/py3-objarr.npy b/numpy/lib/tests/data/py3-objarr.npy new file mode 100644 index 0000000..6776074 Binary files /dev/null and b/numpy/lib/tests/data/py3-objarr.npy differ diff --git a/numpy/lib/tests/data/py3-objarr.npz b/numpy/lib/tests/data/py3-objarr.npz new file mode 100644 index 0000000..05eac0b Binary files /dev/null and b/numpy/lib/tests/data/py3-objarr.npz differ diff --git a/numpy/lib/tests/data/python3.npy b/numpy/lib/tests/data/python3.npy new file mode 100644 index 0000000..7c6997d Binary files /dev/null and b/numpy/lib/tests/data/python3.npy differ diff --git a/numpy/lib/tests/data/win64python2.npy b/numpy/lib/tests/data/win64python2.npy new file mode 100644 index 0000000..d9bc36a Binary files /dev/null and b/numpy/lib/tests/data/win64python2.npy differ diff --git a/numpy/lib/tests/test__datasource.py b/numpy/lib/tests/test__datasource.py new file mode 100644 index 0000000..a9cb157 --- /dev/null +++ b/numpy/lib/tests/test__datasource.py @@ -0,0 +1,348 @@ +from __future__ import division, absolute_import, print_function + +import os +import sys +from tempfile import mkdtemp, mkstemp, NamedTemporaryFile +from shutil import rmtree + +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises, SkipTest, + ) +import numpy.lib._datasource as datasource + +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(): + global old_urlopen + + old_urlopen = urllib_request.urlopen + urllib_request.urlopen = urlopen_stub + + +def teardown(): + 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. + raise SkipTest + # 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. + raise SkipTest + # 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) + + +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() + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test__iotools.py b/numpy/lib/tests/test__iotools.py new file mode 100644 index 0000000..54fac8d --- /dev/null +++ b/numpy/lib/tests/test__iotools.py @@ -0,0 +1,351 @@ +from __future__ import division, absolute_import, print_function + +import sys +import time +from datetime import date + +import numpy as np +from numpy.testing import ( + run_module_suite, 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']) + + 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, set(['', '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]) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test__version.py b/numpy/lib/tests/test__version.py new file mode 100644 index 0000000..993c9d5 --- /dev/null +++ b/numpy/lib/tests/test__version.py @@ -0,0 +1,70 @@ +"""Tests for the NumpyVersion class. + +""" +from __future__ import division, absolute_import, print_function + +from numpy.testing import assert_, run_module_suite, 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) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_arraypad.py b/numpy/lib/tests/test_arraypad.py new file mode 100644 index 0000000..fce4c45 --- /dev/null +++ b/numpy/lib/tests/test_arraypad.py @@ -0,0 +1,1096 @@ +"""Tests for the array padding functions. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import (assert_array_equal, assert_raises, assert_allclose,) +from numpy.lib import pad + + +class TestConditionalShortcuts(object): + def test_zero_padding_shortcuts(self): + test = np.arange(120).reshape(4, 5, 6) + pad_amt = [(0, 0) for axis in test.shape] + modes = ['constant', + 'edge', + 'linear_ramp', + 'maximum', + 'mean', + 'median', + 'minimum', + 'reflect', + 'symmetric', + 'wrap', + ] + for mode in modes: + assert_array_equal(test, pad(test, pad_amt, mode=mode)) + + def test_shallow_statistic_range(self): + test = np.arange(120).reshape(4, 5, 6) + pad_amt = [(1, 1) for axis in test.shape] + modes = ['maximum', + 'mean', + 'median', + 'minimum', + ] + for mode in modes: + assert_array_equal(pad(test, pad_amt, mode='edge'), + pad(test, pad_amt, mode=mode, stat_length=1)) + + def test_clip_statistic_range(self): + test = np.arange(30).reshape(5, 6) + pad_amt = [(3, 3) for axis in test.shape] + modes = ['maximum', + 'mean', + 'median', + 'minimum', + ] + for mode in modes: + assert_array_equal(pad(test, pad_amt, mode=mode), + pad(test, pad_amt, mode=mode, stat_length=30)) + + +class TestStatistic(object): + def test_check_mean_stat_length(self): + a = np.arange(100).astype('f') + a = pad(a, ((25, 20), ), 'mean', stat_length=((2, 3), )) + b = np.array( + [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, + + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., + 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., + 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., + 30., 31., 32., 33., 34., 35., 36., 37., 38., 39., + 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., + 50., 51., 52., 53., 54., 55., 56., 57., 58., 59., + 60., 61., 62., 63., 64., 65., 66., 67., 68., 69., + 70., 71., 72., 73., 74., 75., 76., 77., 78., 79., + 80., 81., 82., 83., 84., 85., 86., 87., 88., 89., + 90., 91., 92., 93., 94., 95., 96., 97., 98., 99., + + 98., 98., 98., 98., 98., 98., 98., 98., 98., 98., + 98., 98., 98., 98., 98., 98., 98., 98., 98., 98. + ]) + assert_array_equal(a, b) + + def test_check_maximum_1(self): + a = np.arange(100) + a = pad(a, (25, 20), 'maximum') + b = np.array( + [99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99] + ) + assert_array_equal(a, b) + + def test_check_maximum_2(self): + a = np.arange(100) + 1 + a = pad(a, (25, 20), 'maximum') + b = np.array( + [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100] + ) + assert_array_equal(a, b) + + def test_check_maximum_stat_length(self): + a = np.arange(100) + 1 + a = pad(a, (25, 20), 'maximum', stat_length=10) + b = np.array( + [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100] + ) + assert_array_equal(a, b) + + def test_check_minimum_1(self): + a = np.arange(100) + a = pad(a, (25, 20), 'minimum') + b = np.array( + [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, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ) + assert_array_equal(a, b) + + def test_check_minimum_2(self): + a = np.arange(100) + 2 + a = pad(a, (25, 20), 'minimum') + b = np.array( + [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, + + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] + ) + assert_array_equal(a, b) + + def test_check_minimum_stat_length(self): + a = np.arange(100) + 1 + a = pad(a, (25, 20), 'minimum', stat_length=10) + b = np.array( + [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91] + ) + assert_array_equal(a, b) + + def test_check_median(self): + a = np.arange(100).astype('f') + a = pad(a, (25, 20), 'median') + b = np.array( + [49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, + + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., + 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., + 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., + 30., 31., 32., 33., 34., 35., 36., 37., 38., 39., + 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., + 50., 51., 52., 53., 54., 55., 56., 57., 58., 59., + 60., 61., 62., 63., 64., 65., 66., 67., 68., 69., + 70., 71., 72., 73., 74., 75., 76., 77., 78., 79., + 80., 81., 82., 83., 84., 85., 86., 87., 88., 89., + 90., 91., 92., 93., 94., 95., 96., 97., 98., 99., + + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5] + ) + assert_array_equal(a, b) + + def test_check_median_01(self): + a = np.array([[3, 1, 4], [4, 5, 9], [9, 8, 2]]) + a = pad(a, 1, 'median') + b = np.array( + [[4, 4, 5, 4, 4], + + [3, 3, 1, 4, 3], + [5, 4, 5, 9, 5], + [8, 9, 8, 2, 8], + + [4, 4, 5, 4, 4]] + ) + assert_array_equal(a, b) + + def test_check_median_02(self): + a = np.array([[3, 1, 4], [4, 5, 9], [9, 8, 2]]) + a = pad(a.T, 1, 'median').T + b = np.array( + [[5, 4, 5, 4, 5], + + [3, 3, 1, 4, 3], + [5, 4, 5, 9, 5], + [8, 9, 8, 2, 8], + + [5, 4, 5, 4, 5]] + ) + assert_array_equal(a, b) + + def test_check_median_stat_length(self): + a = np.arange(100).astype('f') + a[1] = 2. + a[97] = 96. + a = pad(a, (25, 20), 'median', stat_length=(3, 5)) + b = np.array( + [ 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., + 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., + 2., 2., 2., 2., 2., + + 0., 2., 2., 3., 4., 5., 6., 7., 8., 9., + 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., + 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., + 30., 31., 32., 33., 34., 35., 36., 37., 38., 39., + 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., + 50., 51., 52., 53., 54., 55., 56., 57., 58., 59., + 60., 61., 62., 63., 64., 65., 66., 67., 68., 69., + 70., 71., 72., 73., 74., 75., 76., 77., 78., 79., + 80., 81., 82., 83., 84., 85., 86., 87., 88., 89., + 90., 91., 92., 93., 94., 95., 96., 96., 98., 99., + + 96., 96., 96., 96., 96., 96., 96., 96., 96., 96., + 96., 96., 96., 96., 96., 96., 96., 96., 96., 96.] + ) + assert_array_equal(a, b) + + def test_check_mean_shape_one(self): + a = [[4, 5, 6]] + a = pad(a, (5, 7), 'mean', stat_length=2) + b = np.array( + [[4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6], + [4, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6]] + ) + assert_array_equal(a, b) + + def test_check_mean_2(self): + a = np.arange(100).astype('f') + a = pad(a, (25, 20), 'mean') + b = np.array( + [49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, + + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., + 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., + 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., + 30., 31., 32., 33., 34., 35., 36., 37., 38., 39., + 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., + 50., 51., 52., 53., 54., 55., 56., 57., 58., 59., + 60., 61., 62., 63., 64., 65., 66., 67., 68., 69., + 70., 71., 72., 73., 74., 75., 76., 77., 78., 79., + 80., 81., 82., 83., 84., 85., 86., 87., 88., 89., + 90., 91., 92., 93., 94., 95., 96., 97., 98., 99., + + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, + 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5, 49.5] + ) + assert_array_equal(a, b) + + +class TestConstant(object): + def test_check_constant(self): + a = np.arange(100) + a = pad(a, (25, 20), 'constant', constant_values=(10, 20)) + b = np.array( + [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20] + ) + assert_array_equal(a, b) + + def test_check_constant_zeros(self): + a = np.arange(100) + a = pad(a, (25, 20), 'constant') + b = np.array( + [ 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, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ) + assert_array_equal(a, b) + + def test_check_constant_float(self): + # If input array is int, but constant_values are float, the dtype of + # the array to be padded is kept + arr = np.arange(30).reshape(5, 6) + test = pad(arr, (1, 2), mode='constant', + constant_values=1.1) + expected = np.array( + [[ 1, 1, 1, 1, 1, 1, 1, 1, 1], + + [ 1, 0, 1, 2, 3, 4, 5, 1, 1], + [ 1, 6, 7, 8, 9, 10, 11, 1, 1], + [ 1, 12, 13, 14, 15, 16, 17, 1, 1], + [ 1, 18, 19, 20, 21, 22, 23, 1, 1], + [ 1, 24, 25, 26, 27, 28, 29, 1, 1], + + [ 1, 1, 1, 1, 1, 1, 1, 1, 1], + [ 1, 1, 1, 1, 1, 1, 1, 1, 1]] + ) + assert_allclose(test, expected) + + def test_check_constant_float2(self): + # If input array is float, and constant_values are float, the dtype of + # the array to be padded is kept - here retaining the float constants + arr = np.arange(30).reshape(5, 6) + arr_float = arr.astype(np.float64) + test = pad(arr_float, ((1, 2), (1, 2)), mode='constant', + constant_values=1.1) + expected = np.array( + [[ 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1], + + [ 1.1, 0. , 1. , 2. , 3. , 4. , 5. , 1.1, 1.1], + [ 1.1, 6. , 7. , 8. , 9. , 10. , 11. , 1.1, 1.1], + [ 1.1, 12. , 13. , 14. , 15. , 16. , 17. , 1.1, 1.1], + [ 1.1, 18. , 19. , 20. , 21. , 22. , 23. , 1.1, 1.1], + [ 1.1, 24. , 25. , 26. , 27. , 28. , 29. , 1.1, 1.1], + + [ 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1], + [ 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1]] + ) + assert_allclose(test, expected) + + def test_check_constant_float3(self): + a = np.arange(100, dtype=float) + a = pad(a, (25, 20), 'constant', constant_values=(-1.1, -1.2)) + b = np.array( + [-1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, + -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, -1.1, + -1.1, -1.1, -1.1, -1.1, -1.1, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, + -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2, -1.2] + ) + assert_allclose(a, b) + + def test_check_constant_odd_pad_amount(self): + arr = np.arange(30).reshape(5, 6) + test = pad(arr, ((1,), (2,)), mode='constant', + constant_values=3) + expected = np.array( + [[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], + + [ 3, 3, 0, 1, 2, 3, 4, 5, 3, 3], + [ 3, 3, 6, 7, 8, 9, 10, 11, 3, 3], + [ 3, 3, 12, 13, 14, 15, 16, 17, 3, 3], + [ 3, 3, 18, 19, 20, 21, 22, 23, 3, 3], + [ 3, 3, 24, 25, 26, 27, 28, 29, 3, 3], + + [ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]] + ) + assert_allclose(test, expected) + + def test_check_constant_pad_2d(self): + arr = np.arange(4).reshape(2, 2) + test = np.lib.pad(arr, ((1, 2), (1, 3)), mode='constant', + constant_values=((1, 2), (3, 4))) + expected = np.array( + [[3, 1, 1, 4, 4, 4], + [3, 0, 1, 4, 4, 4], + [3, 2, 3, 4, 4, 4], + [3, 2, 2, 4, 4, 4], + [3, 2, 2, 4, 4, 4]] + ) + assert_allclose(test, expected) + + +class TestLinearRamp(object): + def test_check_simple(self): + a = np.arange(100).astype('f') + a = pad(a, (25, 20), 'linear_ramp', end_values=(4, 5)) + b = np.array( + [4.00, 3.84, 3.68, 3.52, 3.36, 3.20, 3.04, 2.88, 2.72, 2.56, + 2.40, 2.24, 2.08, 1.92, 1.76, 1.60, 1.44, 1.28, 1.12, 0.96, + 0.80, 0.64, 0.48, 0.32, 0.16, + + 0.00, 1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00, 9.00, + 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, + 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, + 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, + 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, + 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0, 58.0, 59.0, + 60.0, 61.0, 62.0, 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, + 70.0, 71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, + 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, + 90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, + + 94.3, 89.6, 84.9, 80.2, 75.5, 70.8, 66.1, 61.4, 56.7, 52.0, + 47.3, 42.6, 37.9, 33.2, 28.5, 23.8, 19.1, 14.4, 9.7, 5.] + ) + assert_allclose(a, b, rtol=1e-5, atol=1e-5) + + def test_check_2d(self): + arr = np.arange(20).reshape(4, 5).astype(np.float64) + test = pad(arr, (2, 2), mode='linear_ramp', end_values=(0, 0)) + expected = np.array( + [[0., 0., 0., 0., 0., 0., 0., 0., 0.], + [0., 0., 0., 0.5, 1., 1.5, 2., 1., 0.], + [0., 0., 0., 1., 2., 3., 4., 2., 0.], + [0., 2.5, 5., 6., 7., 8., 9., 4.5, 0.], + [0., 5., 10., 11., 12., 13., 14., 7., 0.], + [0., 7.5, 15., 16., 17., 18., 19., 9.5, 0.], + [0., 3.75, 7.5, 8., 8.5, 9., 9.5, 4.75, 0.], + [0., 0., 0., 0., 0., 0., 0., 0., 0.]]) + assert_allclose(test, expected) + + +class TestReflect(object): + def test_check_simple(self): + a = np.arange(100) + a = pad(a, (25, 20), 'reflect') + b = np.array( + [25, 24, 23, 22, 21, 20, 19, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, + 5, 4, 3, 2, 1, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, + 88, 87, 86, 85, 84, 83, 82, 81, 80, 79] + ) + assert_array_equal(a, b) + + def test_check_odd_method(self): + a = np.arange(100) + a = pad(a, (25, 20), 'reflect', reflect_type='odd') + b = np.array( + [-25, -24, -23, -22, -21, -20, -19, -18, -17, -16, + -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, + -5, -4, -3, -2, -1, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 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] + ) + assert_array_equal(a, b) + + def test_check_large_pad(self): + a = [[4, 5, 6], [6, 7, 8]] + a = pad(a, (5, 7), 'reflect') + b = np.array( + [[7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7, 8, 7, 6, 7], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5]] + ) + assert_array_equal(a, b) + + def test_check_shape(self): + a = [[4, 5, 6]] + a = pad(a, (5, 7), 'reflect') + b = np.array( + [[5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5], + [5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5, 6, 5, 4, 5]] + ) + assert_array_equal(a, b) + + def test_check_01(self): + a = pad([1, 2, 3], 2, 'reflect') + b = np.array([3, 2, 1, 2, 3, 2, 1]) + assert_array_equal(a, b) + + def test_check_02(self): + a = pad([1, 2, 3], 3, 'reflect') + b = np.array([2, 3, 2, 1, 2, 3, 2, 1, 2]) + assert_array_equal(a, b) + + def test_check_03(self): + a = pad([1, 2, 3], 4, 'reflect') + b = np.array([1, 2, 3, 2, 1, 2, 3, 2, 1, 2, 3]) + assert_array_equal(a, b) + + def test_check_padding_an_empty_array(self): + a = pad(np.zeros((0, 3)), ((0,), (1,)), mode='reflect') + b = np.zeros((0, 5)) + assert_array_equal(a, b) + + +class TestSymmetric(object): + def test_check_simple(self): + a = np.arange(100) + a = pad(a, (25, 20), 'symmetric') + b = np.array( + [24, 23, 22, 21, 20, 19, 18, 17, 16, 15, + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, + 4, 3, 2, 1, 0, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, + 89, 88, 87, 86, 85, 84, 83, 82, 81, 80] + ) + assert_array_equal(a, b) + + def test_check_odd_method(self): + a = np.arange(100) + a = pad(a, (25, 20), 'symmetric', reflect_type='odd') + b = np.array( + [-24, -23, -22, -21, -20, -19, -18, -17, -16, -15, + -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, + -4, -3, -2, -1, 0, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118] + ) + assert_array_equal(a, b) + + def test_check_large_pad(self): + a = [[4, 5, 6], [6, 7, 8]] + a = pad(a, (5, 7), 'symmetric') + b = np.array( + [[5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8], + [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8], + + [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8], + [7, 8, 8, 7, 6, 6, 7, 8, 8, 7, 6, 6, 7, 8, 8], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6]] + ) + + assert_array_equal(a, b) + + def test_check_large_pad_odd(self): + a = [[4, 5, 6], [6, 7, 8]] + a = pad(a, (5, 7), 'symmetric', reflect_type='odd') + b = np.array( + [[-3, -2, -2, -1, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6], + [-3, -2, -2, -1, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6], + [-1, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8], + [-1, 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8], + [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10], + + [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10], + [ 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12], + + [ 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12], + [ 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14], + [ 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14], + [ 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16], + [ 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16], + [ 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18], + [ 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18]] + ) + assert_array_equal(a, b) + + def test_check_shape(self): + a = [[4, 5, 6]] + a = pad(a, (5, 7), 'symmetric') + b = np.array( + [[5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6], + [5, 6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4, 5, 6, 6]] + ) + assert_array_equal(a, b) + + def test_check_01(self): + a = pad([1, 2, 3], 2, 'symmetric') + b = np.array([2, 1, 1, 2, 3, 3, 2]) + assert_array_equal(a, b) + + def test_check_02(self): + a = pad([1, 2, 3], 3, 'symmetric') + b = np.array([3, 2, 1, 1, 2, 3, 3, 2, 1]) + assert_array_equal(a, b) + + def test_check_03(self): + a = pad([1, 2, 3], 6, 'symmetric') + b = np.array([1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1, 2, 3]) + assert_array_equal(a, b) + + +class TestWrap(object): + def test_check_simple(self): + a = np.arange(100) + a = pad(a, (25, 20), 'wrap') + b = np.array( + [75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + ) + assert_array_equal(a, b) + + def test_check_large_pad(self): + a = np.arange(12) + a = np.reshape(a, (3, 4)) + a = pad(a, (10, 12), 'wrap') + b = np.array( + [[10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11], + [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, + 3, 0, 1, 2, 3, 0, 1, 2, 3], + [6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, + 7, 4, 5, 6, 7, 4, 5, 6, 7], + [10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, 11, 8, 9, 10, + 11, 8, 9, 10, 11, 8, 9, 10, 11]] + ) + assert_array_equal(a, b) + + def test_check_01(self): + a = pad([1, 2, 3], 3, 'wrap') + b = np.array([1, 2, 3, 1, 2, 3, 1, 2, 3]) + assert_array_equal(a, b) + + def test_check_02(self): + a = pad([1, 2, 3], 4, 'wrap') + b = np.array([3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1]) + assert_array_equal(a, b) + + +class TestStatLen(object): + def test_check_simple(self): + a = np.arange(30) + a = np.reshape(a, (6, 5)) + a = pad(a, ((2, 3), (3, 2)), mode='mean', stat_length=(3,)) + b = np.array( + [[6, 6, 6, 5, 6, 7, 8, 9, 8, 8], + [6, 6, 6, 5, 6, 7, 8, 9, 8, 8], + + [1, 1, 1, 0, 1, 2, 3, 4, 3, 3], + [6, 6, 6, 5, 6, 7, 8, 9, 8, 8], + [11, 11, 11, 10, 11, 12, 13, 14, 13, 13], + [16, 16, 16, 15, 16, 17, 18, 19, 18, 18], + [21, 21, 21, 20, 21, 22, 23, 24, 23, 23], + [26, 26, 26, 25, 26, 27, 28, 29, 28, 28], + + [21, 21, 21, 20, 21, 22, 23, 24, 23, 23], + [21, 21, 21, 20, 21, 22, 23, 24, 23, 23], + [21, 21, 21, 20, 21, 22, 23, 24, 23, 23]] + ) + assert_array_equal(a, b) + + +class TestEdge(object): + def test_check_simple(self): + a = np.arange(12) + a = np.reshape(a, (4, 3)) + a = pad(a, ((2, 3), (3, 2)), 'edge') + b = np.array( + [[0, 0, 0, 0, 1, 2, 2, 2], + [0, 0, 0, 0, 1, 2, 2, 2], + + [0, 0, 0, 0, 1, 2, 2, 2], + [3, 3, 3, 3, 4, 5, 5, 5], + [6, 6, 6, 6, 7, 8, 8, 8], + [9, 9, 9, 9, 10, 11, 11, 11], + + [9, 9, 9, 9, 10, 11, 11, 11], + [9, 9, 9, 9, 10, 11, 11, 11], + [9, 9, 9, 9, 10, 11, 11, 11]] + ) + assert_array_equal(a, b) + + def test_check_width_shape_1_2(self): + # Check a pad_width of the form ((1, 2),). + # Regression test for issue gh-7808. + a = np.array([1, 2, 3]) + padded = pad(a, ((1, 2),), 'edge') + expected = np.array([1, 1, 2, 3, 3, 3]) + assert_array_equal(padded, expected) + + a = np.array([[1, 2, 3], [4, 5, 6]]) + padded = pad(a, ((1, 2),), 'edge') + expected = pad(a, ((1, 2), (1, 2)), 'edge') + assert_array_equal(padded, expected) + + a = np.arange(24).reshape(2, 3, 4) + padded = pad(a, ((1, 2),), 'edge') + expected = pad(a, ((1, 2), (1, 2), (1, 2)), 'edge') + assert_array_equal(padded, expected) + + +class TestZeroPadWidth(object): + def test_zero_pad_width(self): + arr = np.arange(30) + arr = np.reshape(arr, (6, 5)) + for pad_width in (0, (0, 0), ((0, 0), (0, 0))): + assert_array_equal(arr, pad(arr, pad_width, mode='constant')) + + +class TestLegacyVectorFunction(object): + def test_legacy_vector_functionality(self): + def _padwithtens(vector, pad_width, iaxis, kwargs): + vector[:pad_width[0]] = 10 + vector[-pad_width[1]:] = 10 + return vector + + a = np.arange(6).reshape(2, 3) + a = pad(a, 2, _padwithtens) + b = np.array( + [[10, 10, 10, 10, 10, 10, 10], + [10, 10, 10, 10, 10, 10, 10], + + [10, 10, 0, 1, 2, 10, 10], + [10, 10, 3, 4, 5, 10, 10], + + [10, 10, 10, 10, 10, 10, 10], + [10, 10, 10, 10, 10, 10, 10]] + ) + assert_array_equal(a, b) + + +class TestNdarrayPadWidth(object): + def test_check_simple(self): + a = np.arange(12) + a = np.reshape(a, (4, 3)) + a = pad(a, np.array(((2, 3), (3, 2))), 'edge') + b = np.array( + [[0, 0, 0, 0, 1, 2, 2, 2], + [0, 0, 0, 0, 1, 2, 2, 2], + + [0, 0, 0, 0, 1, 2, 2, 2], + [3, 3, 3, 3, 4, 5, 5, 5], + [6, 6, 6, 6, 7, 8, 8, 8], + [9, 9, 9, 9, 10, 11, 11, 11], + + [9, 9, 9, 9, 10, 11, 11, 11], + [9, 9, 9, 9, 10, 11, 11, 11], + [9, 9, 9, 9, 10, 11, 11, 11]] + ) + assert_array_equal(a, b) + + +class TestUnicodeInput(object): + def test_unicode_mode(self): + constant_mode = u'constant' + a = np.pad([1], 2, mode=constant_mode) + b = np.array([0, 0, 1, 0, 0]) + assert_array_equal(a, b) + + +class TestValueError1(object): + def test_check_simple(self): + arr = np.arange(30) + arr = np.reshape(arr, (6, 5)) + kwargs = dict(mode='mean', stat_length=(3, )) + assert_raises(ValueError, pad, arr, ((2, 3), (3, 2), (4, 5)), + **kwargs) + + def test_check_negative_stat_length(self): + arr = np.arange(30) + arr = np.reshape(arr, (6, 5)) + kwargs = dict(mode='mean', stat_length=(-3, )) + assert_raises(ValueError, pad, arr, ((2, 3), (3, 2)), + **kwargs) + + def test_check_negative_pad_width(self): + arr = np.arange(30) + arr = np.reshape(arr, (6, 5)) + kwargs = dict(mode='mean', stat_length=(3, )) + assert_raises(ValueError, pad, arr, ((-2, 3), (3, 2)), + **kwargs) + + def test_check_empty_array(self): + assert_raises(ValueError, pad, [], 4, mode='reflect') + assert_raises(ValueError, pad, np.ndarray(0), 4, mode='reflect') + assert_raises(ValueError, pad, np.zeros((0, 3)), ((1,), (0,)), + mode='reflect') + + +class TestValueError2(object): + def test_check_negative_pad_amount(self): + arr = np.arange(30) + arr = np.reshape(arr, (6, 5)) + kwargs = dict(mode='mean', stat_length=(3, )) + assert_raises(ValueError, pad, arr, ((-2, 3), (3, 2)), + **kwargs) + + +class TestValueError3(object): + def test_check_kwarg_not_allowed(self): + arr = np.arange(30).reshape(5, 6) + assert_raises(ValueError, pad, arr, 4, mode='mean', + reflect_type='odd') + + def test_mode_not_set(self): + arr = np.arange(30).reshape(5, 6) + assert_raises(TypeError, pad, arr, 4) + + def test_malformed_pad_amount(self): + arr = np.arange(30).reshape(5, 6) + assert_raises(ValueError, pad, arr, (4, 5, 6, 7), mode='constant') + + def test_malformed_pad_amount2(self): + arr = np.arange(30).reshape(5, 6) + assert_raises(ValueError, pad, arr, ((3, 4, 5), (0, 1, 2)), + mode='constant') + + def test_pad_too_many_axes(self): + arr = np.arange(30).reshape(5, 6) + + # Attempt to pad using a 3D array equivalent + bad_shape = (((3,), (4,), (5,)), ((0,), (1,), (2,))) + assert_raises(ValueError, pad, arr, bad_shape, + mode='constant') + + +class TestTypeError1(object): + def test_float(self): + arr = np.arange(30) + assert_raises(TypeError, pad, arr, ((-2.1, 3), (3, 2))) + assert_raises(TypeError, pad, arr, np.array(((-2.1, 3), (3, 2)))) + + def test_str(self): + arr = np.arange(30) + assert_raises(TypeError, pad, arr, 'foo') + assert_raises(TypeError, pad, arr, np.array('foo')) + + def test_object(self): + class FooBar(object): + pass + arr = np.arange(30) + assert_raises(TypeError, pad, arr, FooBar()) + + def test_complex(self): + arr = np.arange(30) + assert_raises(TypeError, pad, arr, complex(1, -1)) + assert_raises(TypeError, pad, arr, np.array(complex(1, -1))) + + def test_check_wrong_pad_amount(self): + arr = np.arange(30) + arr = np.reshape(arr, (6, 5)) + kwargs = dict(mode='mean', stat_length=(3, )) + assert_raises(TypeError, pad, arr, ((2, 3, 4), (3, 2)), + **kwargs) + + +if __name__ == "__main__": + np.testing.run_module_suite() diff --git a/numpy/lib/tests/test_arraysetops.py b/numpy/lib/tests/test_arraysetops.py new file mode 100644 index 0000000..c293c7d --- /dev/null +++ b/numpy/lib/tests/test_arraysetops.py @@ -0,0 +1,508 @@ +"""Test functions for 1D array set operations. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_array_equal, assert_equal, assert_raises, + ) +from numpy.lib.arraysetops import ( + ediff1d, intersect1d, setxor1d, union1d, setdiff1d, unique, in1d, isin + ) + + +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_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])) + assert(isinstance(ediff1d(np.matrix(1)), np.matrix)) + assert(isinstance(ediff1d(np.matrix(1), to_begin=1), np.matrix)) + + 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_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(ValueError, unique, np.arange(10), axis=2) + assert_raises(ValueError, 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) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_arrayterator.py b/numpy/lib/tests/test_arrayterator.py new file mode 100644 index 0000000..64ad7f4 --- /dev/null +++ b/numpy/lib/tests/test_arrayterator.py @@ -0,0 +1,52 @@ +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)) + +if __name__ == '__main__': + from numpy.testing import run_module_suite + run_module_suite() diff --git a/numpy/lib/tests/test_financial.py b/numpy/lib/tests/test_financial.py new file mode 100644 index 0000000..c5e92db --- /dev/null +++ b/numpy/lib/tests/test_financial.py @@ -0,0 +1,345 @@ +from __future__ import division, absolute_import, print_function + +from decimal import Decimal + +import numpy as np +from numpy.testing import ( + run_module_suite, 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) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_format.py b/numpy/lib/tests/test_format.py new file mode 100644 index 0000000..2d2b4ce --- /dev/null +++ b/numpy/lib/tests/test_format.py @@ -0,0 +1,857 @@ +from __future__ import division, absolute_import, print_function + +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': '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': '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': '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': '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': '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" +''' + +import sys +import os +import shutil +import tempfile +import warnings +from io import BytesIO + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_array_equal, assert_raises, raises, + dec, SkipTest + ) +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) + yield assert_array_equal, arr, arr2 + + +def test_roundtrip_randsize(): + for arr in basic_arrays + record_arrays: + if arr.dtype != object: + arr2 = roundtrip_randsize(arr) + yield assert_array_equal, arr, arr2 + + +def test_roundtrip_truncated(): + for arr in basic_arrays: + if arr.dtype != object: + yield 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) + + +@dec.slow +def test_memmap_roundtrip(): + # Fixme: test crashes nose 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() + yield 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) + + +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)) + + +@dec.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: + try: + format.write_array(f, arr, version=version) + except ValueError: + pass + else: + raise AssertionError("we should have raised a ValueError for the bad version %r" % (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) + yield raises(ValueError)(format.read_magic), f + + +def test_read_version_1_0_bad_magic(): + for magic in bad_version_magic + malformed_magic: + f = BytesIO(magic) + yield 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'): + raise SkipTest("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: + raise SkipTest("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) + + +@dec.slow +@dec.skipif(np.dtype(np.intp).itemsize < 8, "test requires 64-bit system") +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: + raise SkipTest("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) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py new file mode 100644 index 0000000..8381c24 --- /dev/null +++ b/numpy/lib/tests/test_function_base.py @@ -0,0 +1,3498 @@ +from __future__ import division, absolute_import, print_function + +import operator +import warnings +import sys +import decimal + +import numpy as np +from numpy import ma +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal, + assert_almost_equal, assert_array_almost_equal, assert_raises, + assert_allclose, assert_array_max_ulp, assert_warns, assert_raises_regex, + dec, suppress_warnings, HAS_REFCOUNT, +) +import numpy.lib.function_base as nfb +from numpy.random import rand +from numpy.lib import ( + add_newdoc_ufunc, angle, average, bartlett, blackman, corrcoef, cov, + delete, diff, digitize, extract, flipud, gradient, hamming, hanning, + histogram, histogramdd, i0, insert, interp, kaiser, meshgrid, msort, + piecewise, place, rot90, select, setxor1d, sinc, split, trapz, trim_zeros, + unwrap, unique, vectorize +) + +from numpy.compat import long + + +def get_mat(n): + data = np.arange(n) + data = np.add.outer(data, data) + return data + + +class TestRot90(object): + def test_basic(self): + assert_raises(ValueError, rot90, np.ones(4)) + assert_raises(ValueError, rot90, np.ones((2,2,2)), axes=(0,1,2)) + assert_raises(ValueError, rot90, np.ones((2,2)), axes=(0,2)) + assert_raises(ValueError, rot90, np.ones((2,2)), axes=(1,1)) + assert_raises(ValueError, rot90, np.ones((2,2,2)), axes=(-2,1)) + + a = [[0, 1, 2], + [3, 4, 5]] + b1 = [[2, 5], + [1, 4], + [0, 3]] + b2 = [[5, 4, 3], + [2, 1, 0]] + b3 = [[3, 0], + [4, 1], + [5, 2]] + b4 = [[0, 1, 2], + [3, 4, 5]] + + for k in range(-3, 13, 4): + assert_equal(rot90(a, k=k), b1) + for k in range(-2, 13, 4): + assert_equal(rot90(a, k=k), b2) + for k in range(-1, 13, 4): + assert_equal(rot90(a, k=k), b3) + for k in range(0, 13, 4): + assert_equal(rot90(a, k=k), b4) + + assert_equal(rot90(rot90(a, axes=(0,1)), axes=(1,0)), a) + assert_equal(rot90(a, k=1, axes=(1,0)), rot90(a, k=-1, axes=(0,1))) + + def test_axes(self): + a = np.ones((50, 40, 3)) + assert_equal(rot90(a).shape, (40, 50, 3)) + assert_equal(rot90(a, axes=(0,2)), rot90(a, axes=(0,-1))) + assert_equal(rot90(a, axes=(1,2)), rot90(a, axes=(-2,-1))) + + def test_rotation_axes(self): + a = np.arange(8).reshape((2,2,2)) + + a_rot90_01 = [[[2, 3], + [6, 7]], + [[0, 1], + [4, 5]]] + a_rot90_12 = [[[1, 3], + [0, 2]], + [[5, 7], + [4, 6]]] + a_rot90_20 = [[[4, 0], + [6, 2]], + [[5, 1], + [7, 3]]] + a_rot90_10 = [[[4, 5], + [0, 1]], + [[6, 7], + [2, 3]]] + + assert_equal(rot90(a, axes=(0, 1)), a_rot90_01) + assert_equal(rot90(a, axes=(1, 0)), a_rot90_10) + assert_equal(rot90(a, axes=(1, 2)), a_rot90_12) + + for k in range(1,5): + assert_equal(rot90(a, k=k, axes=(2, 0)), + rot90(a_rot90_20, k=k-1, axes=(2, 0))) + + +class TestFlip(object): + + def test_axes(self): + assert_raises(ValueError, np.flip, np.ones(4), axis=1) + assert_raises(ValueError, np.flip, np.ones((4, 4)), axis=2) + assert_raises(ValueError, np.flip, np.ones((4, 4)), axis=-3) + + def test_basic_lr(self): + a = get_mat(4) + b = a[:, ::-1] + assert_equal(np.flip(a, 1), b) + a = [[0, 1, 2], + [3, 4, 5]] + b = [[2, 1, 0], + [5, 4, 3]] + assert_equal(np.flip(a, 1), b) + + def test_basic_ud(self): + a = get_mat(4) + b = a[::-1, :] + assert_equal(np.flip(a, 0), b) + a = [[0, 1, 2], + [3, 4, 5]] + b = [[3, 4, 5], + [0, 1, 2]] + assert_equal(np.flip(a, 0), b) + + def test_3d_swap_axis0(self): + a = np.array([[[0, 1], + [2, 3]], + [[4, 5], + [6, 7]]]) + + b = np.array([[[4, 5], + [6, 7]], + [[0, 1], + [2, 3]]]) + + assert_equal(np.flip(a, 0), b) + + def test_3d_swap_axis1(self): + a = np.array([[[0, 1], + [2, 3]], + [[4, 5], + [6, 7]]]) + + b = np.array([[[2, 3], + [0, 1]], + [[6, 7], + [4, 5]]]) + + assert_equal(np.flip(a, 1), b) + + def test_3d_swap_axis2(self): + a = np.array([[[0, 1], + [2, 3]], + [[4, 5], + [6, 7]]]) + + b = np.array([[[1, 0], + [3, 2]], + [[5, 4], + [7, 6]]]) + + assert_equal(np.flip(a, 2), b) + + def test_4d(self): + a = np.arange(2 * 3 * 4 * 5).reshape(2, 3, 4, 5) + for i in range(a.ndim): + assert_equal(np.flip(a, i), + np.flipud(a.swapaxes(0, i)).swapaxes(i, 0)) + + +class TestAny(object): + + def test_basic(self): + y1 = [0, 0, 1, 0] + y2 = [0, 0, 0, 0] + y3 = [1, 0, 1, 0] + assert_(np.any(y1)) + assert_(np.any(y3)) + assert_(not np.any(y2)) + + def test_nd(self): + y1 = [[0, 0, 0], [0, 1, 0], [1, 1, 0]] + assert_(np.any(y1)) + assert_array_equal(np.sometrue(y1, axis=0), [1, 1, 0]) + assert_array_equal(np.sometrue(y1, axis=1), [0, 1, 1]) + + +class TestAll(object): + + def test_basic(self): + y1 = [0, 1, 1, 0] + y2 = [0, 0, 0, 0] + y3 = [1, 1, 1, 1] + assert_(not np.all(y1)) + assert_(np.all(y3)) + assert_(not np.all(y2)) + assert_(np.all(~np.array(y2))) + + def test_nd(self): + y1 = [[0, 0, 1], [0, 1, 1], [1, 1, 1]] + assert_(not np.all(y1)) + assert_array_equal(np.alltrue(y1, axis=0), [0, 0, 1]) + assert_array_equal(np.alltrue(y1, axis=1), [0, 0, 1]) + + +class TestCopy(object): + + def test_basic(self): + a = np.array([[1, 2], [3, 4]]) + a_copy = np.copy(a) + assert_array_equal(a, a_copy) + a_copy[0, 0] = 10 + assert_equal(a[0, 0], 1) + assert_equal(a_copy[0, 0], 10) + + def test_order(self): + # It turns out that people rely on np.copy() preserving order by + # default; changing this broke scikit-learn: + # github.com/scikit-learn/scikit-learn/commit/7842748cf777412c506a8c0ed28090711d3a3783 # noqa + a = np.array([[1, 2], [3, 4]]) + assert_(a.flags.c_contiguous) + assert_(not a.flags.f_contiguous) + a_fort = np.array([[1, 2], [3, 4]], order="F") + assert_(not a_fort.flags.c_contiguous) + assert_(a_fort.flags.f_contiguous) + a_copy = np.copy(a) + assert_(a_copy.flags.c_contiguous) + assert_(not a_copy.flags.f_contiguous) + a_fort_copy = np.copy(a_fort) + assert_(not a_fort_copy.flags.c_contiguous) + assert_(a_fort_copy.flags.f_contiguous) + + +class TestAverage(object): + + def test_basic(self): + y1 = np.array([1, 2, 3]) + assert_(average(y1, axis=0) == 2.) + y2 = np.array([1., 2., 3.]) + assert_(average(y2, axis=0) == 2.) + y3 = [0., 0., 0.] + assert_(average(y3, axis=0) == 0.) + + y4 = np.ones((4, 4)) + y4[0, 1] = 0 + y4[1, 0] = 2 + assert_almost_equal(y4.mean(0), average(y4, 0)) + assert_almost_equal(y4.mean(1), average(y4, 1)) + + y5 = rand(5, 5) + assert_almost_equal(y5.mean(0), average(y5, 0)) + assert_almost_equal(y5.mean(1), average(y5, 1)) + + y6 = np.matrix(rand(5, 5)) + assert_array_equal(y6.mean(0), average(y6, 0)) + + def test_weights(self): + y = np.arange(10) + w = np.arange(10) + actual = average(y, weights=w) + desired = (np.arange(10) ** 2).sum() * 1. / np.arange(10).sum() + assert_almost_equal(actual, desired) + + y1 = np.array([[1, 2, 3], [4, 5, 6]]) + w0 = [1, 2] + actual = average(y1, weights=w0, axis=0) + desired = np.array([3., 4., 5.]) + assert_almost_equal(actual, desired) + + w1 = [0, 0, 1] + actual = average(y1, weights=w1, axis=1) + desired = np.array([3., 6.]) + assert_almost_equal(actual, desired) + + # This should raise an error. Can we test for that ? + # assert_equal(average(y1, weights=w1), 9./2.) + + # 2D Case + w2 = [[0, 0, 1], [0, 0, 2]] + desired = np.array([3., 6.]) + assert_array_equal(average(y1, weights=w2, axis=1), desired) + assert_equal(average(y1, weights=w2), 5.) + + y3 = rand(5).astype(np.float32) + w3 = rand(5).astype(np.float64) + + assert_(np.average(y3, weights=w3).dtype == np.result_type(y3, w3)) + + def test_returned(self): + y = np.array([[1, 2, 3], [4, 5, 6]]) + + # No weights + avg, scl = average(y, returned=True) + assert_equal(scl, 6.) + + avg, scl = average(y, 0, returned=True) + assert_array_equal(scl, np.array([2., 2., 2.])) + + avg, scl = average(y, 1, returned=True) + assert_array_equal(scl, np.array([3., 3.])) + + # With weights + w0 = [1, 2] + avg, scl = average(y, weights=w0, axis=0, returned=True) + assert_array_equal(scl, np.array([3., 3., 3.])) + + w1 = [1, 2, 3] + avg, scl = average(y, weights=w1, axis=1, returned=True) + assert_array_equal(scl, np.array([6., 6.])) + + w2 = [[0, 0, 1], [1, 2, 3]] + avg, scl = average(y, weights=w2, axis=1, returned=True) + assert_array_equal(scl, np.array([1., 6.])) + + def test_subclasses(self): + class subclass(np.ndarray): + pass + a = np.array([[1,2],[3,4]]).view(subclass) + w = np.array([[1,2],[3,4]]).view(subclass) + + assert_equal(type(np.average(a)), subclass) + assert_equal(type(np.average(a, weights=w)), subclass) + + # also test matrices + a = np.matrix([[1,2],[3,4]]) + w = np.matrix([[1,2],[3,4]]) + + r = np.average(a, axis=0, weights=w) + assert_equal(type(r), np.matrix) + assert_equal(r, [[2.5, 10.0/3]]) + + def test_upcasting(self): + types = [('i4', 'i4', 'f8'), ('i4', 'f4', 'f8'), ('f4', 'i4', 'f8'), + ('f4', 'f4', 'f4'), ('f4', 'f8', 'f8')] + for at, wt, rt in types: + a = np.array([[1,2],[3,4]], dtype=at) + w = np.array([[1,2],[3,4]], dtype=wt) + assert_equal(np.average(a, weights=w).dtype, np.dtype(rt)) + + def test_object_dtype(self): + a = np.array([decimal.Decimal(x) for x in range(10)]) + w = np.array([decimal.Decimal(1) for _ in range(10)]) + w /= w.sum() + assert_almost_equal(a.mean(0), average(a, weights=w)) + +class TestSelect(object): + choices = [np.array([1, 2, 3]), + np.array([4, 5, 6]), + np.array([7, 8, 9])] + conditions = [np.array([False, False, False]), + np.array([False, True, False]), + np.array([False, False, True])] + + def _select(self, cond, values, default=0): + output = [] + for m in range(len(cond)): + output += [V[m] for V, C in zip(values, cond) if C[m]] or [default] + return output + + def test_basic(self): + choices = self.choices + conditions = self.conditions + assert_array_equal(select(conditions, choices, default=15), + self._select(conditions, choices, default=15)) + + assert_equal(len(choices), 3) + assert_equal(len(conditions), 3) + + def test_broadcasting(self): + conditions = [np.array(True), np.array([False, True, False])] + choices = [1, np.arange(12).reshape(4, 3)] + assert_array_equal(select(conditions, choices), np.ones((4, 3))) + # default can broadcast too: + assert_equal(select([True], [0], default=[0]).shape, (1,)) + + def test_return_dtype(self): + assert_equal(select(self.conditions, self.choices, 1j).dtype, + np.complex_) + # But the conditions need to be stronger then the scalar default + # if it is scalar. + choices = [choice.astype(np.int8) for choice in self.choices] + assert_equal(select(self.conditions, choices).dtype, np.int8) + + d = np.array([1, 2, 3, np.nan, 5, 7]) + m = np.isnan(d) + assert_equal(select([m], [d]), [0, 0, 0, np.nan, 0, 0]) + + def test_deprecated_empty(self): + with warnings.catch_warnings(record=True): + warnings.simplefilter("always") + assert_equal(select([], [], 3j), 3j) + + with warnings.catch_warnings(): + warnings.simplefilter("always") + assert_warns(DeprecationWarning, select, [], []) + warnings.simplefilter("error") + assert_raises(DeprecationWarning, select, [], []) + + def test_non_bool_deprecation(self): + choices = self.choices + conditions = self.conditions[:] + with warnings.catch_warnings(): + warnings.filterwarnings("always") + conditions[0] = conditions[0].astype(np.int_) + assert_warns(DeprecationWarning, select, conditions, choices) + conditions[0] = conditions[0].astype(np.uint8) + assert_warns(DeprecationWarning, select, conditions, choices) + warnings.filterwarnings("error") + assert_raises(DeprecationWarning, select, conditions, choices) + + def test_many_arguments(self): + # This used to be limited by NPY_MAXARGS == 32 + conditions = [np.array([False])] * 100 + choices = [np.array([1])] * 100 + select(conditions, choices) + + +class TestInsert(object): + + def test_basic(self): + a = [1, 2, 3] + assert_equal(insert(a, 0, 1), [1, 1, 2, 3]) + assert_equal(insert(a, 3, 1), [1, 2, 3, 1]) + assert_equal(insert(a, [1, 1, 1], [1, 2, 3]), [1, 1, 2, 3, 2, 3]) + assert_equal(insert(a, 1, [1, 2, 3]), [1, 1, 2, 3, 2, 3]) + assert_equal(insert(a, [1, -1, 3], 9), [1, 9, 2, 9, 3, 9]) + assert_equal(insert(a, slice(-1, None, -1), 9), [9, 1, 9, 2, 9, 3]) + assert_equal(insert(a, [-1, 1, 3], [7, 8, 9]), [1, 8, 2, 7, 3, 9]) + b = np.array([0, 1], dtype=np.float64) + assert_equal(insert(b, 0, b[0]), [0., 0., 1.]) + assert_equal(insert(b, [], []), b) + # Bools will be treated differently in the future: + # assert_equal(insert(a, np.array([True]*4), 9), [9, 1, 9, 2, 9, 3, 9]) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', FutureWarning) + assert_equal( + insert(a, np.array([True] * 4), 9), [1, 9, 9, 9, 9, 2, 3]) + assert_(w[0].category is FutureWarning) + + def test_multidim(self): + a = [[1, 1, 1]] + r = [[2, 2, 2], + [1, 1, 1]] + assert_equal(insert(a, 0, [1]), [1, 1, 1, 1]) + assert_equal(insert(a, 0, [2, 2, 2], axis=0), r) + assert_equal(insert(a, 0, 2, axis=0), r) + assert_equal(insert(a, 2, 2, axis=1), [[1, 1, 2, 1]]) + + a = np.array([[1, 1], [2, 2], [3, 3]]) + b = np.arange(1, 4).repeat(3).reshape(3, 3) + c = np.concatenate( + (a[:, 0:1], np.arange(1, 4).repeat(3).reshape(3, 3).T, + a[:, 1:2]), axis=1) + assert_equal(insert(a, [1], [[1], [2], [3]], axis=1), b) + assert_equal(insert(a, [1], [1, 2, 3], axis=1), c) + # scalars behave differently, in this case exactly opposite: + assert_equal(insert(a, 1, [1, 2, 3], axis=1), b) + assert_equal(insert(a, 1, [[1], [2], [3]], axis=1), c) + + a = np.arange(4).reshape(2, 2) + assert_equal(insert(a[:, :1], 1, a[:, 1], axis=1), a) + assert_equal(insert(a[:1,:], 1, a[1,:], axis=0), a) + + # negative axis value + a = np.arange(24).reshape((2, 3, 4)) + assert_equal(insert(a, 1, a[:,:, 3], axis=-1), + insert(a, 1, a[:,:, 3], axis=2)) + assert_equal(insert(a, 1, a[:, 2,:], axis=-2), + insert(a, 1, a[:, 2,:], axis=1)) + + # invalid axis value + assert_raises(np.AxisError, insert, a, 1, a[:, 2, :], axis=3) + assert_raises(np.AxisError, insert, a, 1, a[:, 2, :], axis=-4) + + # negative axis value + a = np.arange(24).reshape((2, 3, 4)) + assert_equal(insert(a, 1, a[:, :, 3], axis=-1), + insert(a, 1, a[:, :, 3], axis=2)) + assert_equal(insert(a, 1, a[:, 2, :], axis=-2), + insert(a, 1, a[:, 2, :], axis=1)) + + def test_0d(self): + # This is an error in the future + a = np.array(1) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', DeprecationWarning) + assert_equal(insert(a, [], 2, axis=0), np.array(2)) + assert_(w[0].category is DeprecationWarning) + + def test_subclass(self): + class SubClass(np.ndarray): + pass + a = np.arange(10).view(SubClass) + assert_(isinstance(np.insert(a, 0, [0]), SubClass)) + assert_(isinstance(np.insert(a, [], []), SubClass)) + assert_(isinstance(np.insert(a, [0, 1], [1, 2]), SubClass)) + assert_(isinstance(np.insert(a, slice(1, 2), [1, 2]), SubClass)) + assert_(isinstance(np.insert(a, slice(1, -2, -1), []), SubClass)) + # This is an error in the future: + a = np.array(1).view(SubClass) + assert_(isinstance(np.insert(a, 0, [0]), SubClass)) + + def test_index_array_copied(self): + x = np.array([1, 1, 1]) + np.insert([0, 1, 2], x, [3, 4, 5]) + assert_equal(x, np.array([1, 1, 1])) + + def test_structured_array(self): + a = np.array([(1, 'a'), (2, 'b'), (3, 'c')], + dtype=[('foo', 'i'), ('bar', 'a1')]) + val = (4, 'd') + b = np.insert(a, 0, val) + assert_array_equal(b[0], np.array(val, dtype=b.dtype)) + val = [(4, 'd')] * 2 + b = np.insert(a, [0, 2], val) + assert_array_equal(b[[0, 3]], np.array(val, dtype=b.dtype)) + + +class TestAmax(object): + + def test_basic(self): + a = [3, 4, 5, 10, -3, -5, 6.0] + assert_equal(np.amax(a), 10.0) + b = [[3, 6.0, 9.0], + [4, 10.0, 5.0], + [8, 3.0, 2.0]] + assert_equal(np.amax(b, axis=0), [8.0, 10.0, 9.0]) + assert_equal(np.amax(b, axis=1), [9.0, 10.0, 8.0]) + + +class TestAmin(object): + + def test_basic(self): + a = [3, 4, 5, 10, -3, -5, 6.0] + assert_equal(np.amin(a), -5.0) + b = [[3, 6.0, 9.0], + [4, 10.0, 5.0], + [8, 3.0, 2.0]] + assert_equal(np.amin(b, axis=0), [3.0, 3.0, 2.0]) + assert_equal(np.amin(b, axis=1), [3.0, 4.0, 2.0]) + + +class TestPtp(object): + + def test_basic(self): + a = np.array([3, 4, 5, 10, -3, -5, 6.0]) + assert_equal(a.ptp(axis=0), 15.0) + b = np.array([[3, 6.0, 9.0], + [4, 10.0, 5.0], + [8, 3.0, 2.0]]) + assert_equal(b.ptp(axis=0), [5.0, 7.0, 7.0]) + assert_equal(b.ptp(axis=-1), [6.0, 6.0, 6.0]) + + +class TestCumsum(object): + + def test_basic(self): + ba = [1, 2, 10, 11, 6, 5, 4] + ba2 = [[1, 2, 3, 4], [5, 6, 7, 9], [10, 3, 4, 5]] + for ctype in [np.int8, np.uint8, np.int16, np.uint16, np.int32, + np.uint32, np.float32, np.float64, np.complex64, + np.complex128]: + a = np.array(ba, ctype) + a2 = np.array(ba2, ctype) + + tgt = np.array([1, 3, 13, 24, 30, 35, 39], ctype) + assert_array_equal(np.cumsum(a, axis=0), tgt) + + tgt = np.array( + [[1, 2, 3, 4], [6, 8, 10, 13], [16, 11, 14, 18]], ctype) + assert_array_equal(np.cumsum(a2, axis=0), tgt) + + tgt = np.array( + [[1, 3, 6, 10], [5, 11, 18, 27], [10, 13, 17, 22]], ctype) + assert_array_equal(np.cumsum(a2, axis=1), tgt) + + +class TestProd(object): + + def test_basic(self): + ba = [1, 2, 10, 11, 6, 5, 4] + ba2 = [[1, 2, 3, 4], [5, 6, 7, 9], [10, 3, 4, 5]] + for ctype in [np.int16, np.uint16, np.int32, np.uint32, + np.float32, np.float64, np.complex64, np.complex128]: + a = np.array(ba, ctype) + a2 = np.array(ba2, ctype) + if ctype in ['1', 'b']: + assert_raises(ArithmeticError, np.prod, a) + assert_raises(ArithmeticError, np.prod, a2, 1) + else: + assert_equal(a.prod(axis=0), 26400) + assert_array_equal(a2.prod(axis=0), + np.array([50, 36, 84, 180], ctype)) + assert_array_equal(a2.prod(axis=-1), + np.array([24, 1890, 600], ctype)) + + +class TestCumprod(object): + + def test_basic(self): + ba = [1, 2, 10, 11, 6, 5, 4] + ba2 = [[1, 2, 3, 4], [5, 6, 7, 9], [10, 3, 4, 5]] + for ctype in [np.int16, np.uint16, np.int32, np.uint32, + np.float32, np.float64, np.complex64, np.complex128]: + a = np.array(ba, ctype) + a2 = np.array(ba2, ctype) + if ctype in ['1', 'b']: + assert_raises(ArithmeticError, np.cumprod, a) + assert_raises(ArithmeticError, np.cumprod, a2, 1) + assert_raises(ArithmeticError, np.cumprod, a) + else: + assert_array_equal(np.cumprod(a, axis=-1), + np.array([1, 2, 20, 220, + 1320, 6600, 26400], ctype)) + assert_array_equal(np.cumprod(a2, axis=0), + np.array([[1, 2, 3, 4], + [5, 12, 21, 36], + [50, 36, 84, 180]], ctype)) + assert_array_equal(np.cumprod(a2, axis=-1), + np.array([[1, 2, 6, 24], + [5, 30, 210, 1890], + [10, 30, 120, 600]], ctype)) + + +class TestDiff(object): + + def test_basic(self): + x = [1, 4, 6, 7, 12] + out = np.array([3, 2, 1, 5]) + out2 = np.array([-1, -1, 4]) + out3 = np.array([0, 5]) + assert_array_equal(diff(x), out) + assert_array_equal(diff(x, n=2), out2) + assert_array_equal(diff(x, n=3), out3) + + x = [1.1, 2.2, 3.0, -0.2, -0.1] + out = np.array([1.1, 0.8, -3.2, 0.1]) + assert_almost_equal(diff(x), out) + + x = [True, True, False, False] + out = np.array([False, True, False]) + out2 = np.array([True, True]) + assert_array_equal(diff(x), out) + assert_array_equal(diff(x, n=2), out2) + + def test_axis(self): + x = np.zeros((10, 20, 30)) + x[:, 1::2, :] = 1 + exp = np.ones((10, 19, 30)) + exp[:, 1::2, :] = -1 + assert_array_equal(diff(x), np.zeros((10, 20, 29))) + assert_array_equal(diff(x, axis=-1), np.zeros((10, 20, 29))) + assert_array_equal(diff(x, axis=0), np.zeros((9, 20, 30))) + assert_array_equal(diff(x, axis=1), exp) + assert_array_equal(diff(x, axis=-2), exp) + assert_raises(np.AxisError, diff, x, axis=3) + assert_raises(np.AxisError, diff, x, axis=-4) + + def test_nd(self): + x = 20 * rand(10, 20, 30) + out1 = x[:, :, 1:] - x[:, :, :-1] + out2 = out1[:, :, 1:] - out1[:, :, :-1] + out3 = x[1:, :, :] - x[:-1, :, :] + out4 = out3[1:, :, :] - out3[:-1, :, :] + assert_array_equal(diff(x), out1) + assert_array_equal(diff(x, n=2), out2) + assert_array_equal(diff(x, axis=0), out3) + assert_array_equal(diff(x, n=2, axis=0), out4) + + def test_n(self): + x = list(range(3)) + assert_raises(ValueError, diff, x, n=-1) + output = [diff(x, n=n) for n in range(1, 5)] + expected = [[1, 1], [0], [], []] + assert_(diff(x, n=0) is x) + for n, (expected, out) in enumerate(zip(expected, output), start=1): + assert_(type(out) is np.ndarray) + assert_array_equal(out, expected) + assert_equal(out.dtype, np.int_) + assert_equal(len(out), max(0, len(x) - n)) + + def test_times(self): + x = np.arange('1066-10-13', '1066-10-16', dtype=np.datetime64) + expected = [ + np.array([1, 1], dtype='timedelta64[D]'), + np.array([0], dtype='timedelta64[D]'), + ] + expected.extend([np.array([], dtype='timedelta64[D]')] * 3) + for n, exp in enumerate(expected, start=1): + out = diff(x, n=n) + assert_array_equal(out, exp) + assert_equal(out.dtype, exp.dtype) + + def test_subclass(self): + x = ma.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]], + mask=[[False, False], [True, False], + [False, True], [True, True], [False, False]]) + out = diff(x) + assert_array_equal(out.data, [[1], [1], [1], [1], [1]]) + assert_array_equal(out.mask, [[False], [True], + [True], [True], [False]]) + assert_(type(out) is type(x)) + + out3 = diff(x, n=3) + assert_array_equal(out3.data, [[], [], [], [], []]) + assert_array_equal(out3.mask, [[], [], [], [], []]) + assert_(type(out3) is type(x)) + + +class TestDelete(object): + + def setup(self): + self.a = np.arange(5) + self.nd_a = np.arange(5).repeat(2).reshape(1, 5, 2) + + def _check_inverse_of_slicing(self, indices): + a_del = delete(self.a, indices) + nd_a_del = delete(self.nd_a, indices, axis=1) + msg = 'Delete failed for obj: %r' % indices + # NOTE: The cast should be removed after warning phase for bools + if not isinstance(indices, (slice, int, long, np.integer)): + indices = np.asarray(indices, dtype=np.intp) + indices = indices[(indices >= 0) & (indices < 5)] + assert_array_equal(setxor1d(a_del, self.a[indices, ]), self.a, + err_msg=msg) + xor = setxor1d(nd_a_del[0,:, 0], self.nd_a[0, indices, 0]) + assert_array_equal(xor, self.nd_a[0,:, 0], err_msg=msg) + + def test_slices(self): + lims = [-6, -2, 0, 1, 2, 4, 5] + steps = [-3, -1, 1, 3] + for start in lims: + for stop in lims: + for step in steps: + s = slice(start, stop, step) + self._check_inverse_of_slicing(s) + + def test_fancy(self): + # Deprecation/FutureWarning tests should be kept after change. + self._check_inverse_of_slicing(np.array([[0, 1], [2, 1]])) + with warnings.catch_warnings(): + warnings.filterwarnings('error', category=DeprecationWarning) + assert_raises(DeprecationWarning, delete, self.a, [100]) + assert_raises(DeprecationWarning, delete, self.a, [-100]) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=FutureWarning) + self._check_inverse_of_slicing([0, -1, 2, 2]) + obj = np.array([True, False, False], dtype=bool) + self._check_inverse_of_slicing(obj) + assert_(w[0].category is FutureWarning) + assert_(w[1].category is FutureWarning) + + def test_single(self): + self._check_inverse_of_slicing(0) + self._check_inverse_of_slicing(-4) + + def test_0d(self): + a = np.array(1) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', DeprecationWarning) + assert_equal(delete(a, [], axis=0), a) + assert_(w[0].category is DeprecationWarning) + + def test_subclass(self): + class SubClass(np.ndarray): + pass + a = self.a.view(SubClass) + assert_(isinstance(delete(a, 0), SubClass)) + assert_(isinstance(delete(a, []), SubClass)) + assert_(isinstance(delete(a, [0, 1]), SubClass)) + assert_(isinstance(delete(a, slice(1, 2)), SubClass)) + assert_(isinstance(delete(a, slice(1, -2)), SubClass)) + + def test_array_order_preserve(self): + # See gh-7113 + k = np.arange(10).reshape(2, 5, order='F') + m = delete(k, slice(60, None), axis=1) + + # 'k' is Fortran ordered, and 'm' should have the + # same ordering as 'k' and NOT become C ordered + assert_equal(m.flags.c_contiguous, k.flags.c_contiguous) + assert_equal(m.flags.f_contiguous, k.flags.f_contiguous) + + +class TestGradient(object): + + def test_basic(self): + v = [[1, 1], [3, 4]] + x = np.array(v) + dx = [np.array([[2., 3.], [2., 3.]]), + np.array([[0., 0.], [1., 1.]])] + assert_array_equal(gradient(x), dx) + assert_array_equal(gradient(v), dx) + + def test_args(self): + dx = np.cumsum(np.ones(5)) + dx_uneven = [1., 2., 5., 9., 11.] + f_2d = np.arange(25).reshape(5, 5) + + # distances must be scalars or have size equal to gradient[axis] + gradient(np.arange(5), 3.) + gradient(np.arange(5), np.array(3.)) + gradient(np.arange(5), dx) + # dy is set equal to dx because scalar + gradient(f_2d, 1.5) + gradient(f_2d, np.array(1.5)) + + gradient(f_2d, dx_uneven, dx_uneven) + # mix between even and uneven spaces and + # mix between scalar and vector + gradient(f_2d, dx, 2) + + # 2D but axis specified + gradient(f_2d, dx, axis=1) + + # 2d coordinate arguments are not yet allowed + assert_raises_regex(ValueError, '.*scalars or 1d', + gradient, f_2d, np.stack([dx]*2, axis=-1), 1) + + def test_badargs(self): + f_2d = np.arange(25).reshape(5, 5) + x = np.cumsum(np.ones(5)) + + # wrong sizes + assert_raises(ValueError, gradient, f_2d, x, np.ones(2)) + assert_raises(ValueError, gradient, f_2d, 1, np.ones(2)) + assert_raises(ValueError, gradient, f_2d, np.ones(2), np.ones(2)) + # wrong number of arguments + assert_raises(TypeError, gradient, f_2d, x) + assert_raises(TypeError, gradient, f_2d, x, axis=(0,1)) + assert_raises(TypeError, gradient, f_2d, x, x, x) + assert_raises(TypeError, gradient, f_2d, 1, 1, 1) + assert_raises(TypeError, gradient, f_2d, x, x, axis=1) + assert_raises(TypeError, gradient, f_2d, 1, 1, axis=1) + + def test_datetime64(self): + # Make sure gradient() can handle special types like datetime64 + x = np.array( + ['1910-08-16', '1910-08-11', '1910-08-10', '1910-08-12', + '1910-10-12', '1910-12-12', '1912-12-12'], + dtype='datetime64[D]') + dx = np.array( + [-5, -3, 0, 31, 61, 396, 731], + dtype='timedelta64[D]') + assert_array_equal(gradient(x), dx) + assert_(dx.dtype == np.dtype('timedelta64[D]')) + + def test_masked(self): + # Make sure that gradient supports subclasses like masked arrays + x = np.ma.array([[1, 1], [3, 4]], + mask=[[False, False], [False, False]]) + out = gradient(x)[0] + assert_equal(type(out), type(x)) + # And make sure that the output and input don't have aliased mask + # arrays + assert_(x.mask is not out.mask) + # Also check that edge_order=2 doesn't alter the original mask + x2 = np.ma.arange(5) + x2[2] = np.ma.masked + np.gradient(x2, edge_order=2) + assert_array_equal(x2.mask, [False, False, True, False, False]) + + def test_second_order_accurate(self): + # Testing that the relative numerical error is less that 3% for + # this example problem. This corresponds to second order + # accurate finite differences for all interior and boundary + # points. + x = np.linspace(0, 1, 10) + dx = x[1] - x[0] + y = 2 * x ** 3 + 4 * x ** 2 + 2 * x + analytical = 6 * x ** 2 + 8 * x + 2 + num_error = np.abs((np.gradient(y, dx, edge_order=2) / analytical) - 1) + assert_(np.all(num_error < 0.03) == True) + + # test with unevenly spaced + np.random.seed(0) + x = np.sort(np.random.random(10)) + y = 2 * x ** 3 + 4 * x ** 2 + 2 * x + analytical = 6 * x ** 2 + 8 * x + 2 + num_error = np.abs((np.gradient(y, x, edge_order=2) / analytical) - 1) + assert_(np.all(num_error < 0.03) == True) + + def test_spacing(self): + f = np.array([0, 2., 3., 4., 5., 5.]) + f = np.tile(f, (6,1)) + f.reshape(-1, 1) + x_uneven = np.array([0., 0.5, 1., 3., 5., 7.]) + x_even = np.arange(6.) + + fdx_even_ord1 = np.tile([2., 1.5, 1., 1., 0.5, 0.], (6,1)) + fdx_even_ord2 = np.tile([2.5, 1.5, 1., 1., 0.5, -0.5], (6,1)) + fdx_uneven_ord1 = np.tile([4., 3., 1.7, 0.5, 0.25, 0.], (6,1)) + fdx_uneven_ord2 = np.tile([5., 3., 1.7, 0.5, 0.25, -0.25], (6,1)) + + # evenly spaced + for edge_order, exp_res in [(1, fdx_even_ord1), (2, fdx_even_ord2)]: + res1 = gradient(f, 1., axis=(0,1), edge_order=edge_order) + res2 = gradient(f, x_even, x_even, + axis=(0,1), edge_order=edge_order) + res3 = gradient(f, x_even, x_even, + axis=None, edge_order=edge_order) + assert_array_equal(res1, res2) + assert_array_equal(res2, res3) + assert_almost_equal(res1[0], exp_res.T) + assert_almost_equal(res1[1], exp_res) + + res1 = gradient(f, 1., axis=0, edge_order=edge_order) + res2 = gradient(f, x_even, axis=0, edge_order=edge_order) + assert_(res1.shape == res2.shape) + assert_almost_equal(res2, exp_res.T) + + res1 = gradient(f, 1., axis=1, edge_order=edge_order) + res2 = gradient(f, x_even, axis=1, edge_order=edge_order) + assert_(res1.shape == res2.shape) + assert_array_equal(res2, exp_res) + + # unevenly spaced + for edge_order, exp_res in [(1, fdx_uneven_ord1), (2, fdx_uneven_ord2)]: + res1 = gradient(f, x_uneven, x_uneven, + axis=(0,1), edge_order=edge_order) + res2 = gradient(f, x_uneven, x_uneven, + axis=None, edge_order=edge_order) + assert_array_equal(res1, res2) + assert_almost_equal(res1[0], exp_res.T) + assert_almost_equal(res1[1], exp_res) + + res1 = gradient(f, x_uneven, axis=0, edge_order=edge_order) + assert_almost_equal(res1, exp_res.T) + + res1 = gradient(f, x_uneven, axis=1, edge_order=edge_order) + assert_almost_equal(res1, exp_res) + + # mixed + res1 = gradient(f, x_even, x_uneven, axis=(0,1), edge_order=1) + res2 = gradient(f, x_uneven, x_even, axis=(1,0), edge_order=1) + assert_array_equal(res1[0], res2[1]) + assert_array_equal(res1[1], res2[0]) + assert_almost_equal(res1[0], fdx_even_ord1.T) + assert_almost_equal(res1[1], fdx_uneven_ord1) + + res1 = gradient(f, x_even, x_uneven, axis=(0,1), edge_order=2) + res2 = gradient(f, x_uneven, x_even, axis=(1,0), edge_order=2) + assert_array_equal(res1[0], res2[1]) + assert_array_equal(res1[1], res2[0]) + assert_almost_equal(res1[0], fdx_even_ord2.T) + assert_almost_equal(res1[1], fdx_uneven_ord2) + + def test_specific_axes(self): + # Testing that gradient can work on a given axis only + v = [[1, 1], [3, 4]] + x = np.array(v) + dx = [np.array([[2., 3.], [2., 3.]]), + np.array([[0., 0.], [1., 1.]])] + assert_array_equal(gradient(x, axis=0), dx[0]) + assert_array_equal(gradient(x, axis=1), dx[1]) + assert_array_equal(gradient(x, axis=-1), dx[1]) + assert_array_equal(gradient(x, axis=(1, 0)), [dx[1], dx[0]]) + + # test axis=None which means all axes + assert_almost_equal(gradient(x, axis=None), [dx[0], dx[1]]) + # and is the same as no axis keyword given + assert_almost_equal(gradient(x, axis=None), gradient(x)) + + # test vararg order + assert_array_equal(gradient(x, 2, 3, axis=(1, 0)), + [dx[1]/2.0, dx[0]/3.0]) + # test maximal number of varargs + assert_raises(TypeError, gradient, x, 1, 2, axis=1) + + assert_raises(np.AxisError, gradient, x, axis=3) + assert_raises(np.AxisError, gradient, x, axis=-3) + # assert_raises(TypeError, gradient, x, axis=[1,]) + + def test_timedelta64(self): + # Make sure gradient() can handle special types like timedelta64 + x = np.array( + [-5, -3, 10, 12, 61, 321, 300], + dtype='timedelta64[D]') + dx = np.array( + [2, 7, 7, 25, 154, 119, -21], + dtype='timedelta64[D]') + assert_array_equal(gradient(x), dx) + assert_(dx.dtype == np.dtype('timedelta64[D]')) + + def test_inexact_dtypes(self): + for dt in [np.float16, np.float32, np.float64]: + # dtypes should not be promoted in a different way to what diff does + x = np.array([1, 2, 3], dtype=dt) + assert_equal(gradient(x).dtype, np.diff(x).dtype) + + def test_values(self): + # needs at least 2 points for edge_order ==1 + gradient(np.arange(2), edge_order=1) + # needs at least 3 points for edge_order ==1 + gradient(np.arange(3), edge_order=2) + + assert_raises(ValueError, gradient, np.arange(0), edge_order=1) + assert_raises(ValueError, gradient, np.arange(0), edge_order=2) + assert_raises(ValueError, gradient, np.arange(1), edge_order=1) + assert_raises(ValueError, gradient, np.arange(1), edge_order=2) + assert_raises(ValueError, gradient, np.arange(2), edge_order=2) + + +class TestAngle(object): + + def test_basic(self): + x = [1 + 3j, np.sqrt(2) / 2.0 + 1j * np.sqrt(2) / 2, + 1, 1j, -1, -1j, 1 - 3j, -1 + 3j] + y = angle(x) + yo = [ + np.arctan(3.0 / 1.0), + np.arctan(1.0), 0, np.pi / 2, np.pi, -np.pi / 2.0, + -np.arctan(3.0 / 1.0), np.pi - np.arctan(3.0 / 1.0)] + z = angle(x, deg=1) + zo = np.array(yo) * 180 / np.pi + assert_array_almost_equal(y, yo, 11) + assert_array_almost_equal(z, zo, 11) + + +class TestTrimZeros(object): + + """ + Only testing for integer splits. + + """ + + def test_basic(self): + a = np.array([0, 0, 1, 2, 3, 4, 0]) + res = trim_zeros(a) + assert_array_equal(res, np.array([1, 2, 3, 4])) + + def test_leading_skip(self): + a = np.array([0, 0, 1, 0, 2, 3, 4, 0]) + res = trim_zeros(a) + assert_array_equal(res, np.array([1, 0, 2, 3, 4])) + + def test_trailing_skip(self): + a = np.array([0, 0, 1, 0, 2, 3, 0, 4, 0]) + res = trim_zeros(a) + assert_array_equal(res, np.array([1, 0, 2, 3, 0, 4])) + + +class TestExtins(object): + + def test_basic(self): + a = np.array([1, 3, 2, 1, 2, 3, 3]) + b = extract(a > 1, a) + assert_array_equal(b, [3, 2, 2, 3, 3]) + + def test_place(self): + # Make sure that non-np.ndarray objects + # raise an error instead of doing nothing + assert_raises(TypeError, place, [1, 2, 3], [True, False], [0, 1]) + + a = np.array([1, 4, 3, 2, 5, 8, 7]) + place(a, [0, 1, 0, 1, 0, 1, 0], [2, 4, 6]) + assert_array_equal(a, [1, 2, 3, 4, 5, 6, 7]) + + place(a, np.zeros(7), []) + assert_array_equal(a, np.arange(1, 8)) + + place(a, [1, 0, 1, 0, 1, 0, 1], [8, 9]) + assert_array_equal(a, [8, 2, 9, 4, 8, 6, 9]) + assert_raises_regex(ValueError, "Cannot insert from an empty array", + lambda: place(a, [0, 0, 0, 0, 0, 1, 0], [])) + + # See Issue #6974 + a = np.array(['12', '34']) + place(a, [0, 1], '9') + assert_array_equal(a, ['12', '9']) + + def test_both(self): + a = rand(10) + mask = a > 0.5 + ac = a.copy() + c = extract(mask, a) + place(a, mask, 0) + place(a, mask, c) + assert_array_equal(a, ac) + + +class TestVectorize(object): + + def test_simple(self): + def addsubtract(a, b): + if a > b: + return a - b + else: + return a + b + + f = vectorize(addsubtract) + r = f([0, 3, 6, 9], [1, 3, 5, 7]) + assert_array_equal(r, [1, 6, 1, 2]) + + def test_scalar(self): + def addsubtract(a, b): + if a > b: + return a - b + else: + return a + b + + f = vectorize(addsubtract) + r = f([0, 3, 6, 9], 5) + assert_array_equal(r, [5, 8, 1, 4]) + + def test_large(self): + x = np.linspace(-3, 2, 10000) + f = vectorize(lambda x: x) + y = f(x) + assert_array_equal(y, x) + + def test_ufunc(self): + import math + f = vectorize(math.cos) + args = np.array([0, 0.5 * np.pi, np.pi, 1.5 * np.pi, 2 * np.pi]) + r1 = f(args) + r2 = np.cos(args) + assert_array_almost_equal(r1, r2) + + def test_keywords(self): + + def foo(a, b=1): + return a + b + + f = vectorize(foo) + args = np.array([1, 2, 3]) + r1 = f(args) + r2 = np.array([2, 3, 4]) + assert_array_equal(r1, r2) + r1 = f(args, 2) + r2 = np.array([3, 4, 5]) + assert_array_equal(r1, r2) + + def test_keywords_no_func_code(self): + # This needs to test a function that has keywords but + # no func_code attribute, since otherwise vectorize will + # inspect the func_code. + import random + try: + vectorize(random.randrange) # Should succeed + except Exception: + raise AssertionError() + + def test_keywords2_ticket_2100(self): + # Test kwarg support: enhancement ticket 2100 + + def foo(a, b=1): + return a + b + + f = vectorize(foo) + args = np.array([1, 2, 3]) + r1 = f(a=args) + r2 = np.array([2, 3, 4]) + assert_array_equal(r1, r2) + r1 = f(b=1, a=args) + assert_array_equal(r1, r2) + r1 = f(args, b=2) + r2 = np.array([3, 4, 5]) + assert_array_equal(r1, r2) + + def test_keywords3_ticket_2100(self): + # Test excluded with mixed positional and kwargs: ticket 2100 + def mypolyval(x, p): + _p = list(p) + res = _p.pop(0) + while _p: + res = res * x + _p.pop(0) + return res + + vpolyval = np.vectorize(mypolyval, excluded=['p', 1]) + ans = [3, 6] + assert_array_equal(ans, vpolyval(x=[0, 1], p=[1, 2, 3])) + assert_array_equal(ans, vpolyval([0, 1], p=[1, 2, 3])) + assert_array_equal(ans, vpolyval([0, 1], [1, 2, 3])) + + def test_keywords4_ticket_2100(self): + # Test vectorizing function with no positional args. + @vectorize + def f(**kw): + res = 1.0 + for _k in kw: + res *= kw[_k] + return res + + assert_array_equal(f(a=[1, 2], b=[3, 4]), [3, 8]) + + def test_keywords5_ticket_2100(self): + # Test vectorizing function with no kwargs args. + @vectorize + def f(*v): + return np.prod(v) + + assert_array_equal(f([1, 2], [3, 4]), [3, 8]) + + def test_coverage1_ticket_2100(self): + def foo(): + return 1 + + f = vectorize(foo) + assert_array_equal(f(), 1) + + def test_assigning_docstring(self): + def foo(x): + """Original documentation""" + return x + + f = vectorize(foo) + assert_equal(f.__doc__, foo.__doc__) + + doc = "Provided documentation" + f = vectorize(foo, doc=doc) + assert_equal(f.__doc__, doc) + + def test_UnboundMethod_ticket_1156(self): + # Regression test for issue 1156 + class Foo: + b = 2 + + def bar(self, a): + return a ** self.b + + assert_array_equal(vectorize(Foo().bar)(np.arange(9)), + np.arange(9) ** 2) + assert_array_equal(vectorize(Foo.bar)(Foo(), np.arange(9)), + np.arange(9) ** 2) + + def test_execution_order_ticket_1487(self): + # Regression test for dependence on execution order: issue 1487 + f1 = vectorize(lambda x: x) + res1a = f1(np.arange(3)) + res1b = f1(np.arange(0.1, 3)) + f2 = vectorize(lambda x: x) + res2b = f2(np.arange(0.1, 3)) + res2a = f2(np.arange(3)) + assert_equal(res1a, res2a) + assert_equal(res1b, res2b) + + def test_string_ticket_1892(self): + # Test vectorization over strings: issue 1892. + f = np.vectorize(lambda x: x) + s = '0123456789' * 10 + assert_equal(s, f(s)) + + def test_cache(self): + # Ensure that vectorized func called exactly once per argument. + _calls = [0] + + @vectorize + def f(x): + _calls[0] += 1 + return x ** 2 + + f.cache = True + x = np.arange(5) + assert_array_equal(f(x), x * x) + assert_equal(_calls[0], len(x)) + + def test_otypes(self): + f = np.vectorize(lambda x: x) + f.otypes = 'i' + x = np.arange(5) + assert_array_equal(f(x), x) + + def test_parse_gufunc_signature(self): + assert_equal(nfb._parse_gufunc_signature('(x)->()'), ([('x',)], [()])) + assert_equal(nfb._parse_gufunc_signature('(x,y)->()'), + ([('x', 'y')], [()])) + assert_equal(nfb._parse_gufunc_signature('(x),(y)->()'), + ([('x',), ('y',)], [()])) + assert_equal(nfb._parse_gufunc_signature('(x)->(y)'), + ([('x',)], [('y',)])) + assert_equal(nfb._parse_gufunc_signature('(x)->(y),()'), + ([('x',)], [('y',), ()])) + assert_equal(nfb._parse_gufunc_signature('(),(a,b,c),(d)->(d,e)'), + ([(), ('a', 'b', 'c'), ('d',)], [('d', 'e')])) + with assert_raises(ValueError): + nfb._parse_gufunc_signature('(x)(y)->()') + with assert_raises(ValueError): + nfb._parse_gufunc_signature('(x),(y)->') + with assert_raises(ValueError): + nfb._parse_gufunc_signature('((x))->(x)') + + def test_signature_simple(self): + def addsubtract(a, b): + if a > b: + return a - b + else: + return a + b + + f = vectorize(addsubtract, signature='(),()->()') + r = f([0, 3, 6, 9], [1, 3, 5, 7]) + assert_array_equal(r, [1, 6, 1, 2]) + + def test_signature_mean_last(self): + def mean(a): + return a.mean() + + f = vectorize(mean, signature='(n)->()') + r = f([[1, 3], [2, 4]]) + assert_array_equal(r, [2, 3]) + + def test_signature_center(self): + def center(a): + return a - a.mean() + + f = vectorize(center, signature='(n)->(n)') + r = f([[1, 3], [2, 4]]) + assert_array_equal(r, [[-1, 1], [-1, 1]]) + + def test_signature_two_outputs(self): + f = vectorize(lambda x: (x, x), signature='()->(),()') + r = f([1, 2, 3]) + assert_(isinstance(r, tuple) and len(r) == 2) + assert_array_equal(r[0], [1, 2, 3]) + assert_array_equal(r[1], [1, 2, 3]) + + def test_signature_outer(self): + f = vectorize(np.outer, signature='(a),(b)->(a,b)') + r = f([1, 2], [1, 2, 3]) + assert_array_equal(r, [[1, 2, 3], [2, 4, 6]]) + + r = f([[[1, 2]]], [1, 2, 3]) + assert_array_equal(r, [[[[1, 2, 3], [2, 4, 6]]]]) + + r = f([[1, 0], [2, 0]], [1, 2, 3]) + assert_array_equal(r, [[[1, 2, 3], [0, 0, 0]], + [[2, 4, 6], [0, 0, 0]]]) + + r = f([1, 2], [[1, 2, 3], [0, 0, 0]]) + assert_array_equal(r, [[[1, 2, 3], [2, 4, 6]], + [[0, 0, 0], [0, 0, 0]]]) + + def test_signature_computed_size(self): + f = vectorize(lambda x: x[:-1], signature='(n)->(m)') + r = f([1, 2, 3]) + assert_array_equal(r, [1, 2]) + + r = f([[1, 2, 3], [2, 3, 4]]) + assert_array_equal(r, [[1, 2], [2, 3]]) + + def test_signature_excluded(self): + + def foo(a, b=1): + return a + b + + f = vectorize(foo, signature='()->()', excluded={'b'}) + assert_array_equal(f([1, 2, 3]), [2, 3, 4]) + assert_array_equal(f([1, 2, 3], b=0), [1, 2, 3]) + + def test_signature_otypes(self): + f = vectorize(lambda x: x, signature='(n)->(n)', otypes=['float64']) + r = f([1, 2, 3]) + assert_equal(r.dtype, np.dtype('float64')) + assert_array_equal(r, [1, 2, 3]) + + def test_signature_invalid_inputs(self): + f = vectorize(operator.add, signature='(n),(n)->(n)') + with assert_raises_regex(TypeError, 'wrong number of positional'): + f([1, 2]) + with assert_raises_regex( + ValueError, 'does not have enough dimensions'): + f(1, 2) + with assert_raises_regex( + ValueError, 'inconsistent size for core dimension'): + f([1, 2], [1, 2, 3]) + + f = vectorize(operator.add, signature='()->()') + with assert_raises_regex(TypeError, 'wrong number of positional'): + f(1, 2) + + def test_signature_invalid_outputs(self): + + f = vectorize(lambda x: x[:-1], signature='(n)->(n)') + with assert_raises_regex( + ValueError, 'inconsistent size for core dimension'): + f([1, 2, 3]) + + f = vectorize(lambda x: x, signature='()->(),()') + with assert_raises_regex(ValueError, 'wrong number of outputs'): + f(1) + + f = vectorize(lambda x: (x, x), signature='()->()') + with assert_raises_regex(ValueError, 'wrong number of outputs'): + f([1, 2]) + + def test_size_zero_output(self): + # see issue 5868 + f = np.vectorize(lambda x: x) + x = np.zeros([0, 5], dtype=int) + with assert_raises_regex(ValueError, 'otypes'): + f(x) + + f.otypes = 'i' + assert_array_equal(f(x), x) + + f = np.vectorize(lambda x: x, signature='()->()') + with assert_raises_regex(ValueError, 'otypes'): + f(x) + + f = np.vectorize(lambda x: x, signature='()->()', otypes='i') + assert_array_equal(f(x), x) + + f = np.vectorize(lambda x: x, signature='(n)->(n)', otypes='i') + assert_array_equal(f(x), x) + + f = np.vectorize(lambda x: x, signature='(n)->(n)') + assert_array_equal(f(x.T), x.T) + + f = np.vectorize(lambda x: [x], signature='()->(n)', otypes='i') + with assert_raises_regex(ValueError, 'new output dimensions'): + f(x) + + +class TestDigitize(object): + + def test_forward(self): + x = np.arange(-6, 5) + bins = np.arange(-5, 5) + assert_array_equal(digitize(x, bins), np.arange(11)) + + def test_reverse(self): + x = np.arange(5, -6, -1) + bins = np.arange(5, -5, -1) + assert_array_equal(digitize(x, bins), np.arange(11)) + + def test_random(self): + x = rand(10) + bin = np.linspace(x.min(), x.max(), 10) + assert_(np.all(digitize(x, bin) != 0)) + + def test_right_basic(self): + x = [1, 5, 4, 10, 8, 11, 0] + bins = [1, 5, 10] + default_answer = [1, 2, 1, 3, 2, 3, 0] + assert_array_equal(digitize(x, bins), default_answer) + right_answer = [0, 1, 1, 2, 2, 3, 0] + assert_array_equal(digitize(x, bins, True), right_answer) + + def test_right_open(self): + x = np.arange(-6, 5) + bins = np.arange(-6, 4) + assert_array_equal(digitize(x, bins, True), np.arange(11)) + + def test_right_open_reverse(self): + x = np.arange(5, -6, -1) + bins = np.arange(4, -6, -1) + assert_array_equal(digitize(x, bins, True), np.arange(11)) + + def test_right_open_random(self): + x = rand(10) + bins = np.linspace(x.min(), x.max(), 10) + assert_(np.all(digitize(x, bins, True) != 10)) + + def test_monotonic(self): + x = [-1, 0, 1, 2] + bins = [0, 0, 1] + assert_array_equal(digitize(x, bins, False), [0, 2, 3, 3]) + assert_array_equal(digitize(x, bins, True), [0, 0, 2, 3]) + bins = [1, 1, 0] + assert_array_equal(digitize(x, bins, False), [3, 2, 0, 0]) + assert_array_equal(digitize(x, bins, True), [3, 3, 2, 0]) + bins = [1, 1, 1, 1] + assert_array_equal(digitize(x, bins, False), [0, 0, 4, 4]) + assert_array_equal(digitize(x, bins, True), [0, 0, 0, 4]) + bins = [0, 0, 1, 0] + assert_raises(ValueError, digitize, x, bins) + bins = [1, 1, 0, 1] + assert_raises(ValueError, digitize, x, bins) + + def test_casting_error(self): + x = [1, 2, 3 + 1.j] + bins = [1, 2, 3] + assert_raises(TypeError, digitize, x, bins) + x, bins = bins, x + assert_raises(TypeError, digitize, x, bins) + + def test_return_type(self): + # Functions returning indices should always return base ndarrays + class A(np.ndarray): + pass + a = np.arange(5).view(A) + b = np.arange(1, 3).view(A) + assert_(not isinstance(digitize(b, a, False), A)) + assert_(not isinstance(digitize(b, a, True), A)) + + +class TestUnwrap(object): + + def test_simple(self): + # check that unwrap removes jumps greather that 2*pi + assert_array_equal(unwrap([1, 1 + 2 * np.pi]), [1, 1]) + # check that unwrap maintans continuity + assert_(np.all(diff(unwrap(rand(10) * 100)) < np.pi)) + + +class TestFilterwindows(object): + + def test_hanning(self): + # check symmetry + w = hanning(10) + assert_array_almost_equal(w, flipud(w), 7) + # check known value + assert_almost_equal(np.sum(w, axis=0), 4.500, 4) + + def test_hamming(self): + # check symmetry + w = hamming(10) + assert_array_almost_equal(w, flipud(w), 7) + # check known value + assert_almost_equal(np.sum(w, axis=0), 4.9400, 4) + + def test_bartlett(self): + # check symmetry + w = bartlett(10) + assert_array_almost_equal(w, flipud(w), 7) + # check known value + assert_almost_equal(np.sum(w, axis=0), 4.4444, 4) + + def test_blackman(self): + # check symmetry + w = blackman(10) + assert_array_almost_equal(w, flipud(w), 7) + # check known value + assert_almost_equal(np.sum(w, axis=0), 3.7800, 4) + + +class TestTrapz(object): + + def test_simple(self): + x = np.arange(-10, 10, .1) + r = trapz(np.exp(-.5 * x ** 2) / np.sqrt(2 * np.pi), dx=0.1) + # check integral of normal equals 1 + assert_almost_equal(r, 1, 7) + + def test_ndim(self): + x = np.linspace(0, 1, 3) + y = np.linspace(0, 2, 8) + z = np.linspace(0, 3, 13) + + wx = np.ones_like(x) * (x[1] - x[0]) + wx[0] /= 2 + wx[-1] /= 2 + wy = np.ones_like(y) * (y[1] - y[0]) + wy[0] /= 2 + wy[-1] /= 2 + wz = np.ones_like(z) * (z[1] - z[0]) + wz[0] /= 2 + wz[-1] /= 2 + + q = x[:, None, None] + y[None,:, None] + z[None, None,:] + + qx = (q * wx[:, None, None]).sum(axis=0) + qy = (q * wy[None, :, None]).sum(axis=1) + qz = (q * wz[None, None, :]).sum(axis=2) + + # n-d `x` + r = trapz(q, x=x[:, None, None], axis=0) + assert_almost_equal(r, qx) + r = trapz(q, x=y[None,:, None], axis=1) + assert_almost_equal(r, qy) + r = trapz(q, x=z[None, None,:], axis=2) + assert_almost_equal(r, qz) + + # 1-d `x` + r = trapz(q, x=x, axis=0) + assert_almost_equal(r, qx) + r = trapz(q, x=y, axis=1) + assert_almost_equal(r, qy) + r = trapz(q, x=z, axis=2) + assert_almost_equal(r, qz) + + def test_masked(self): + # Testing that masked arrays behave as if the function is 0 where + # masked + x = np.arange(5) + y = x * x + mask = x == 2 + ym = np.ma.array(y, mask=mask) + r = 13.0 # sum(0.5 * (0 + 1) * 1.0 + 0.5 * (9 + 16)) + assert_almost_equal(trapz(ym, x), r) + + xm = np.ma.array(x, mask=mask) + assert_almost_equal(trapz(ym, xm), r) + + xm = np.ma.array(x, mask=mask) + assert_almost_equal(trapz(y, xm), r) + + def test_matrix(self): + # Test to make sure matrices give the same answer as ndarrays + x = np.linspace(0, 5) + y = x * x + r = trapz(y, x) + mx = np.matrix(x) + my = np.matrix(y) + mr = trapz(my, mx) + assert_almost_equal(mr, r) + + +class TestSinc(object): + + def test_simple(self): + assert_(sinc(0) == 1) + w = sinc(np.linspace(-1, 1, 100)) + # check symmetry + assert_array_almost_equal(w, flipud(w), 7) + + def test_array_like(self): + x = [0, 0.5] + y1 = sinc(np.array(x)) + y2 = sinc(list(x)) + y3 = sinc(tuple(x)) + assert_array_equal(y1, y2) + assert_array_equal(y1, y3) + + +class TestHistogram(object): + + def setup(self): + pass + + def teardown(self): + pass + + def test_simple(self): + n = 100 + v = 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): + # Check that the integral of the density equals 1. + n = 100 + v = rand(n) + a, b = histogram(v, normed=True) + area = np.sum(a * diff(b)) + assert_almost_equal(area, 1) + + # 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 * diff(b)) + assert_almost_equal(area, 1) + + def test_density(self): + # Check that the integral of the density equals 1. + n = 100 + v = rand(n) + a, b = histogram(v, density=True) + area = np.sum(a * 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 * diff(b)), 1) + + # 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], normed=True) + assert_almost_equal((h * diff(b)).sum(), 1, decimal=15) + + # Weights + w = np.arange(10) + .5 + h, b = histogram(a, range=[1, 9], weights=w, normed=True) + assert_equal((h * diff(b)).sum(), 1) + + h, b = histogram(a, bins=8, range=[1, 9], weights=w) + assert_equal(h, w[1:-1]) + + 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, normed=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_weights(self): + v = rand(100) + w = np.ones(100) * 5 + a, b = histogram(v) + na, nb = histogram(v, normed=True) + wa, wb = histogram(v, weights=w) + nwa, nwb = histogram(v, weights=w, normed=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], normed=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_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_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) + + +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'] + # 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}, + 500: {'fd': 8, 'scott': 8, 'rice': 16, 'sturges': 10, + 'doane': 12, 'sqrt': 23, 'auto': 10}, + 5000: {'fd': 17, 'scott': 17, 'rice': 35, 'sturges': 14, + 'doane': 17, 'sqrt': 71, 'auto': 17}} + + 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}, + 2: {'fd': 2, 'scott': 1, 'rice': 3, 'sturges': 2, + 'doane': 1, 'sqrt': 2}, + 3: {'fd': 2, 'scott': 2, 'rice': 3, 'sturges': 3, + 'doane': 3, 'sqrt': 2}} + + 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} + + 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_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} + + for estimator, numbins in outlier_resultdict.items(): + a, b = np.histogram(outlier_dataset, estimator) + assert_equal(len(a), numbins) + + 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}, + 500: {'fd': 15, 'scott': 16, 'rice': 32, + 'sturges': 20, 'auto': 20}, + 5000: {'fd': 33, 'scott': 33, 'rice': 69, + 'sturges': 27, 'auto': 33} + } + + 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, normed=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]], + normed=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 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 = 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 = rand(10, 4) + for b in bins: + H, edges = histogramdd(r, b) + assert_(H.shape == b) + + def test_weights(self): + v = rand(100, 2) + hist, edges = histogramdd(v) + n_hist, edges = histogramdd(v, normed=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, normed=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, 2, 3]]) + 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] == 1.) + 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]]) + + +class TestUnique(object): + + def test_simple(self): + x = np.array([4, 3, 2, 1, 1, 2, 3, 4, 0]) + assert_(np.all(unique(x) == [0, 1, 2, 3, 4])) + assert_(unique(np.array([1, 1, 1, 1, 1])) == np.array([1])) + x = ['widget', 'ham', 'foo', 'bar', 'foo', 'ham'] + assert_(np.all(unique(x) == ['bar', 'foo', 'ham', 'widget'])) + x = np.array([5 + 6j, 1 + 1j, 1 + 10j, 10, 5 + 6j]) + assert_(np.all(unique(x) == [1 + 1j, 1 + 10j, 5 + 6j, 10])) + + +class TestCheckFinite(object): + + def test_simple(self): + a = [1, 2, 3] + b = [1, 2, np.inf] + c = [1, 2, np.nan] + np.lib.asarray_chkfinite(a) + assert_raises(ValueError, np.lib.asarray_chkfinite, b) + assert_raises(ValueError, np.lib.asarray_chkfinite, c) + + def test_dtype_order(self): + # Regression test for missing dtype and order arguments + a = [1, 2, 3] + a = np.lib.asarray_chkfinite(a, order='F', dtype=np.float64) + assert_(a.dtype == np.float64) + + +class TestCorrCoef(object): + A = np.array( + [[0.15391142, 0.18045767, 0.14197213], + [0.70461506, 0.96474128, 0.27906989], + [0.9297531, 0.32296769, 0.19267156]]) + B = np.array( + [[0.10377691, 0.5417086, 0.49807457], + [0.82872117, 0.77801674, 0.39226705], + [0.9314666, 0.66800209, 0.03538394]]) + res1 = np.array( + [[1., 0.9379533, -0.04931983], + [0.9379533, 1., 0.30007991], + [-0.04931983, 0.30007991, 1.]]) + res2 = np.array( + [[1., 0.9379533, -0.04931983, 0.30151751, 0.66318558, 0.51532523], + [0.9379533, 1., 0.30007991, -0.04781421, 0.88157256, 0.78052386], + [-0.04931983, 0.30007991, 1., -0.96717111, 0.71483595, 0.83053601], + [0.30151751, -0.04781421, -0.96717111, 1., -0.51366032, -0.66173113], + [0.66318558, 0.88157256, 0.71483595, -0.51366032, 1., 0.98317823], + [0.51532523, 0.78052386, 0.83053601, -0.66173113, 0.98317823, 1.]]) + + def test_non_array(self): + assert_almost_equal(np.corrcoef([0, 1, 0], [1, 0, 1]), + [[1., -1.], [-1., 1.]]) + + def test_simple(self): + tgt1 = corrcoef(self.A) + assert_almost_equal(tgt1, self.res1) + assert_(np.all(np.abs(tgt1) <= 1.0)) + + tgt2 = corrcoef(self.A, self.B) + assert_almost_equal(tgt2, self.res2) + assert_(np.all(np.abs(tgt2) <= 1.0)) + + def test_ddof(self): + # ddof raises DeprecationWarning + with suppress_warnings() as sup: + warnings.simplefilter("always") + assert_warns(DeprecationWarning, corrcoef, self.A, ddof=-1) + sup.filter(DeprecationWarning) + # ddof has no or negligible effect on the function + assert_almost_equal(corrcoef(self.A, ddof=-1), self.res1) + assert_almost_equal(corrcoef(self.A, self.B, ddof=-1), self.res2) + assert_almost_equal(corrcoef(self.A, ddof=3), self.res1) + assert_almost_equal(corrcoef(self.A, self.B, ddof=3), self.res2) + + def test_bias(self): + # bias raises DeprecationWarning + with suppress_warnings() as sup: + warnings.simplefilter("always") + assert_warns(DeprecationWarning, corrcoef, self.A, self.B, 1, 0) + assert_warns(DeprecationWarning, corrcoef, self.A, bias=0) + sup.filter(DeprecationWarning) + # bias has no or negligible effect on the function + assert_almost_equal(corrcoef(self.A, bias=1), self.res1) + + def test_complex(self): + x = np.array([[1, 2, 3], [1j, 2j, 3j]]) + res = corrcoef(x) + tgt = np.array([[1., -1.j], [1.j, 1.]]) + assert_allclose(res, tgt) + assert_(np.all(np.abs(res) <= 1.0)) + + def test_xy(self): + x = np.array([[1, 2, 3]]) + y = np.array([[1j, 2j, 3j]]) + assert_allclose(np.corrcoef(x, y), np.array([[1., -1.j], [1.j, 1.]])) + + def test_empty(self): + with warnings.catch_warnings(record=True): + warnings.simplefilter('always', RuntimeWarning) + assert_array_equal(corrcoef(np.array([])), np.nan) + assert_array_equal(corrcoef(np.array([]).reshape(0, 2)), + np.array([]).reshape(0, 0)) + assert_array_equal(corrcoef(np.array([]).reshape(2, 0)), + np.array([[np.nan, np.nan], [np.nan, np.nan]])) + + def test_extreme(self): + x = [[1e-100, 1e100], [1e100, 1e-100]] + with np.errstate(all='raise'): + c = corrcoef(x) + assert_array_almost_equal(c, np.array([[1., -1.], [-1., 1.]])) + assert_(np.all(np.abs(c) <= 1.0)) + + +class TestCov(object): + x1 = np.array([[0, 2], [1, 1], [2, 0]]).T + res1 = np.array([[1., -1.], [-1., 1.]]) + x2 = np.array([0.0, 1.0, 2.0], ndmin=2) + frequencies = np.array([1, 4, 1]) + x2_repeats = np.array([[0.0], [1.0], [1.0], [1.0], [1.0], [2.0]]).T + res2 = np.array([[0.4, -0.4], [-0.4, 0.4]]) + unit_frequencies = np.ones(3, dtype=np.integer) + weights = np.array([1.0, 4.0, 1.0]) + res3 = np.array([[2. / 3., -2. / 3.], [-2. / 3., 2. / 3.]]) + unit_weights = np.ones(3) + x3 = np.array([0.3942, 0.5969, 0.7730, 0.9918, 0.7964]) + + def test_basic(self): + assert_allclose(cov(self.x1), self.res1) + + def test_complex(self): + x = np.array([[1, 2, 3], [1j, 2j, 3j]]) + assert_allclose(cov(x), np.array([[1., -1.j], [1.j, 1.]])) + + def test_xy(self): + x = np.array([[1, 2, 3]]) + y = np.array([[1j, 2j, 3j]]) + assert_allclose(cov(x, y), np.array([[1., -1.j], [1.j, 1.]])) + + def test_empty(self): + with warnings.catch_warnings(record=True): + warnings.simplefilter('always', RuntimeWarning) + assert_array_equal(cov(np.array([])), np.nan) + assert_array_equal(cov(np.array([]).reshape(0, 2)), + np.array([]).reshape(0, 0)) + assert_array_equal(cov(np.array([]).reshape(2, 0)), + np.array([[np.nan, np.nan], [np.nan, np.nan]])) + + def test_wrong_ddof(self): + with warnings.catch_warnings(record=True): + warnings.simplefilter('always', RuntimeWarning) + assert_array_equal(cov(self.x1, ddof=5), + np.array([[np.inf, -np.inf], + [-np.inf, np.inf]])) + + def test_1D_rowvar(self): + assert_allclose(cov(self.x3), cov(self.x3, rowvar=0)) + y = np.array([0.0780, 0.3107, 0.2111, 0.0334, 0.8501]) + assert_allclose(cov(self.x3, y), cov(self.x3, y, rowvar=0)) + + def test_1D_variance(self): + assert_allclose(cov(self.x3, ddof=1), np.var(self.x3, ddof=1)) + + def test_fweights(self): + assert_allclose(cov(self.x2, fweights=self.frequencies), + cov(self.x2_repeats)) + assert_allclose(cov(self.x1, fweights=self.frequencies), + self.res2) + assert_allclose(cov(self.x1, fweights=self.unit_frequencies), + self.res1) + nonint = self.frequencies + 0.5 + assert_raises(TypeError, cov, self.x1, fweights=nonint) + f = np.ones((2, 3), dtype=np.integer) + assert_raises(RuntimeError, cov, self.x1, fweights=f) + f = np.ones(2, dtype=np.integer) + assert_raises(RuntimeError, cov, self.x1, fweights=f) + f = -1 * np.ones(3, dtype=np.integer) + assert_raises(ValueError, cov, self.x1, fweights=f) + + def test_aweights(self): + assert_allclose(cov(self.x1, aweights=self.weights), self.res3) + assert_allclose(cov(self.x1, aweights=3.0 * self.weights), + cov(self.x1, aweights=self.weights)) + assert_allclose(cov(self.x1, aweights=self.unit_weights), self.res1) + w = np.ones((2, 3)) + assert_raises(RuntimeError, cov, self.x1, aweights=w) + w = np.ones(2) + assert_raises(RuntimeError, cov, self.x1, aweights=w) + w = -1.0 * np.ones(3) + assert_raises(ValueError, cov, self.x1, aweights=w) + + def test_unit_fweights_and_aweights(self): + assert_allclose(cov(self.x2, fweights=self.frequencies, + aweights=self.unit_weights), + cov(self.x2_repeats)) + assert_allclose(cov(self.x1, fweights=self.frequencies, + aweights=self.unit_weights), + self.res2) + assert_allclose(cov(self.x1, fweights=self.unit_frequencies, + aweights=self.unit_weights), + self.res1) + assert_allclose(cov(self.x1, fweights=self.unit_frequencies, + aweights=self.weights), + self.res3) + assert_allclose(cov(self.x1, fweights=self.unit_frequencies, + aweights=3.0 * self.weights), + cov(self.x1, aweights=self.weights)) + assert_allclose(cov(self.x1, fweights=self.unit_frequencies, + aweights=self.unit_weights), + self.res1) + + +class Test_I0(object): + + def test_simple(self): + assert_almost_equal( + i0(0.5), + np.array(1.0634833707413234)) + + A = np.array([0.49842636, 0.6969809, 0.22011976, 0.0155549]) + assert_almost_equal( + i0(A), + np.array([1.06307822, 1.12518299, 1.01214991, 1.00006049])) + + B = np.array([[0.827002, 0.99959078], + [0.89694769, 0.39298162], + [0.37954418, 0.05206293], + [0.36465447, 0.72446427], + [0.48164949, 0.50324519]]) + assert_almost_equal( + i0(B), + np.array([[1.17843223, 1.26583466], + [1.21147086, 1.03898290], + [1.03633899, 1.00067775], + [1.03352052, 1.13557954], + [1.05884290, 1.06432317]])) + + +class TestKaiser(object): + + def test_simple(self): + assert_(np.isfinite(kaiser(1, 1.0))) + assert_almost_equal(kaiser(0, 1.0), + np.array([])) + assert_almost_equal(kaiser(2, 1.0), + np.array([0.78984831, 0.78984831])) + assert_almost_equal(kaiser(5, 1.0), + np.array([0.78984831, 0.94503323, 1., + 0.94503323, 0.78984831])) + assert_almost_equal(kaiser(5, 1.56789), + np.array([0.58285404, 0.88409679, 1., + 0.88409679, 0.58285404])) + + def test_int_beta(self): + kaiser(3, 4) + + +class TestMsort(object): + + def test_simple(self): + A = np.array([[0.44567325, 0.79115165, 0.54900530], + [0.36844147, 0.37325583, 0.96098397], + [0.64864341, 0.52929049, 0.39172155]]) + assert_almost_equal( + msort(A), + np.array([[0.36844147, 0.37325583, 0.39172155], + [0.44567325, 0.52929049, 0.54900530], + [0.64864341, 0.79115165, 0.96098397]])) + + +class TestMeshgrid(object): + + def test_simple(self): + [X, Y] = meshgrid([1, 2, 3], [4, 5, 6, 7]) + assert_array_equal(X, np.array([[1, 2, 3], + [1, 2, 3], + [1, 2, 3], + [1, 2, 3]])) + assert_array_equal(Y, np.array([[4, 4, 4], + [5, 5, 5], + [6, 6, 6], + [7, 7, 7]])) + + def test_single_input(self): + [X] = meshgrid([1, 2, 3, 4]) + assert_array_equal(X, np.array([1, 2, 3, 4])) + + def test_no_input(self): + args = [] + assert_array_equal([], meshgrid(*args)) + assert_array_equal([], meshgrid(*args, copy=False)) + + def test_indexing(self): + x = [1, 2, 3] + y = [4, 5, 6, 7] + [X, Y] = meshgrid(x, y, indexing='ij') + assert_array_equal(X, np.array([[1, 1, 1, 1], + [2, 2, 2, 2], + [3, 3, 3, 3]])) + assert_array_equal(Y, np.array([[4, 5, 6, 7], + [4, 5, 6, 7], + [4, 5, 6, 7]])) + + # Test expected shapes: + z = [8, 9] + assert_(meshgrid(x, y)[0].shape == (4, 3)) + assert_(meshgrid(x, y, indexing='ij')[0].shape == (3, 4)) + assert_(meshgrid(x, y, z)[0].shape == (4, 3, 2)) + assert_(meshgrid(x, y, z, indexing='ij')[0].shape == (3, 4, 2)) + + assert_raises(ValueError, meshgrid, x, y, indexing='notvalid') + + def test_sparse(self): + [X, Y] = meshgrid([1, 2, 3], [4, 5, 6, 7], sparse=True) + assert_array_equal(X, np.array([[1, 2, 3]])) + assert_array_equal(Y, np.array([[4], [5], [6], [7]])) + + def test_invalid_arguments(self): + # Test that meshgrid complains about invalid arguments + # Regression test for issue #4755: + # https://github.com/numpy/numpy/issues/4755 + assert_raises(TypeError, meshgrid, + [1, 2, 3], [4, 5, 6, 7], indices='ij') + + def test_return_type(self): + # Test for appropriate dtype in returned arrays. + # Regression test for issue #5297 + # https://github.com/numpy/numpy/issues/5297 + x = np.arange(0, 10, dtype=np.float32) + y = np.arange(10, 20, dtype=np.float64) + + X, Y = np.meshgrid(x,y) + + assert_(X.dtype == x.dtype) + assert_(Y.dtype == y.dtype) + + # copy + X, Y = np.meshgrid(x,y, copy=True) + + assert_(X.dtype == x.dtype) + assert_(Y.dtype == y.dtype) + + # sparse + X, Y = np.meshgrid(x,y, sparse=True) + + assert_(X.dtype == x.dtype) + assert_(Y.dtype == y.dtype) + + def test_writeback(self): + # Issue 8561 + X = np.array([1.1, 2.2]) + Y = np.array([3.3, 4.4]) + x, y = np.meshgrid(X, Y, sparse=False, copy=True) + + x[0, :] = 0 + assert_equal(x[0, :], 0) + assert_equal(x[1, :], X) + + +class TestPiecewise(object): + + def test_simple(self): + # Condition is single bool list + x = piecewise([0, 0], [True, False], [1]) + assert_array_equal(x, [1, 0]) + + # List of conditions: single bool list + x = piecewise([0, 0], [[True, False]], [1]) + assert_array_equal(x, [1, 0]) + + # Conditions is single bool array + x = piecewise([0, 0], np.array([True, False]), [1]) + assert_array_equal(x, [1, 0]) + + # Condition is single int array + x = piecewise([0, 0], np.array([1, 0]), [1]) + assert_array_equal(x, [1, 0]) + + # List of conditions: int array + x = piecewise([0, 0], [np.array([1, 0])], [1]) + assert_array_equal(x, [1, 0]) + + x = piecewise([0, 0], [[False, True]], [lambda x:-1]) + assert_array_equal(x, [0, -1]) + + assert_raises_regex(ValueError, '1 or 2 functions are expected', + piecewise, [0, 0], [[False, True]], []) + assert_raises_regex(ValueError, '1 or 2 functions are expected', + piecewise, [0, 0], [[False, True]], [1, 2, 3]) + + def test_two_conditions(self): + x = piecewise([1, 2], [[True, False], [False, True]], [3, 4]) + assert_array_equal(x, [3, 4]) + + def test_scalar_domains_three_conditions(self): + x = piecewise(3, [True, False, False], [4, 2, 0]) + assert_equal(x, 4) + + def test_default(self): + # No value specified for x[1], should be 0 + x = piecewise([1, 2], [True, False], [2]) + assert_array_equal(x, [2, 0]) + + # Should set x[1] to 3 + x = piecewise([1, 2], [True, False], [2, 3]) + assert_array_equal(x, [2, 3]) + + def test_0d(self): + x = np.array(3) + y = piecewise(x, x > 3, [4, 0]) + assert_(y.ndim == 0) + assert_(y == 0) + + x = 5 + y = piecewise(x, [True, False], [1, 0]) + assert_(y.ndim == 0) + assert_(y == 1) + + # With 3 ranges (It was failing, before) + y = piecewise(x, [False, False, True], [1, 2, 3]) + assert_array_equal(y, 3) + + def test_0d_comparison(self): + x = 3 + y = piecewise(x, [x <= 3, x > 3], [4, 0]) # Should succeed. + assert_equal(y, 4) + + # With 3 ranges (It was failing, before) + x = 4 + y = piecewise(x, [x <= 3, (x > 3) * (x <= 5), x > 5], [1, 2, 3]) + assert_array_equal(y, 2) + + assert_raises_regex(ValueError, '2 or 3 functions are expected', + piecewise, x, [x <= 3, x > 3], [1]) + assert_raises_regex(ValueError, '2 or 3 functions are expected', + piecewise, x, [x <= 3, x > 3], [1, 1, 1, 1]) + + def test_0d_0d_condition(self): + x = np.array(3) + c = np.array(x > 3) + y = piecewise(x, [c], [1, 2]) + assert_equal(y, 2) + + def test_multidimensional_extrafunc(self): + x = np.array([[-2.5, -1.5, -0.5], + [0.5, 1.5, 2.5]]) + y = piecewise(x, [x < 0, x >= 2], [-1, 1, 3]) + assert_array_equal(y, np.array([[-1., -1., -1.], + [3., 3., 1.]])) + + +class TestBincount(object): + + def test_simple(self): + y = np.bincount(np.arange(4)) + assert_array_equal(y, np.ones(4)) + + def test_simple2(self): + y = np.bincount(np.array([1, 5, 2, 4, 1])) + assert_array_equal(y, np.array([0, 2, 1, 0, 1, 1])) + + def test_simple_weight(self): + x = np.arange(4) + w = np.array([0.2, 0.3, 0.5, 0.1]) + y = np.bincount(x, w) + assert_array_equal(y, w) + + def test_simple_weight2(self): + x = np.array([1, 2, 4, 5, 2]) + w = np.array([0.2, 0.3, 0.5, 0.1, 0.2]) + y = np.bincount(x, w) + assert_array_equal(y, np.array([0, 0.2, 0.5, 0, 0.5, 0.1])) + + def test_with_minlength(self): + x = np.array([0, 1, 0, 1, 1]) + y = np.bincount(x, minlength=3) + assert_array_equal(y, np.array([2, 3, 0])) + x = [] + y = np.bincount(x, minlength=0) + assert_array_equal(y, np.array([])) + + def test_with_minlength_smaller_than_maxvalue(self): + x = np.array([0, 1, 1, 2, 2, 3, 3]) + y = np.bincount(x, minlength=2) + assert_array_equal(y, np.array([1, 2, 2, 2])) + y = np.bincount(x, minlength=0) + assert_array_equal(y, np.array([1, 2, 2, 2])) + + def test_with_minlength_and_weights(self): + x = np.array([1, 2, 4, 5, 2]) + w = np.array([0.2, 0.3, 0.5, 0.1, 0.2]) + y = np.bincount(x, w, 8) + assert_array_equal(y, np.array([0, 0.2, 0.5, 0, 0.5, 0.1, 0, 0])) + + def test_empty(self): + x = np.array([], dtype=int) + y = np.bincount(x) + assert_array_equal(x, y) + + def test_empty_with_minlength(self): + x = np.array([], dtype=int) + y = np.bincount(x, minlength=5) + assert_array_equal(y, np.zeros(5, dtype=int)) + + def test_with_incorrect_minlength(self): + x = np.array([], dtype=int) + assert_raises_regex(TypeError, + "'str' object cannot be interpreted", + lambda: np.bincount(x, minlength="foobar")) + assert_raises_regex(ValueError, + "must not be negative", + lambda: np.bincount(x, minlength=-1)) + + x = np.arange(5) + assert_raises_regex(TypeError, + "'str' object cannot be interpreted", + lambda: np.bincount(x, minlength="foobar")) + assert_raises_regex(ValueError, + "must not be negative", + lambda: np.bincount(x, minlength=-1)) + + @dec.skipif(not HAS_REFCOUNT, "python has no sys.getrefcount") + def test_dtype_reference_leaks(self): + # gh-6805 + intp_refcount = sys.getrefcount(np.dtype(np.intp)) + double_refcount = sys.getrefcount(np.dtype(np.double)) + + for j in range(10): + np.bincount([1, 2, 3]) + assert_equal(sys.getrefcount(np.dtype(np.intp)), intp_refcount) + assert_equal(sys.getrefcount(np.dtype(np.double)), double_refcount) + + for j in range(10): + np.bincount([1, 2, 3], [4, 5, 6]) + assert_equal(sys.getrefcount(np.dtype(np.intp)), intp_refcount) + assert_equal(sys.getrefcount(np.dtype(np.double)), double_refcount) + + +class TestInterp(object): + + def test_exceptions(self): + assert_raises(ValueError, interp, 0, [], []) + assert_raises(ValueError, interp, 0, [0], [1, 2]) + assert_raises(ValueError, interp, 0, [0, 1], [1, 2], period=0) + assert_raises(ValueError, interp, 0, [], [], period=360) + assert_raises(ValueError, interp, 0, [0], [1, 2], period=360) + + def test_basic(self): + x = np.linspace(0, 1, 5) + y = np.linspace(0, 1, 5) + x0 = np.linspace(0, 1, 50) + assert_almost_equal(np.interp(x0, x, y), x0) + + def test_right_left_behavior(self): + # Needs range of sizes to test different code paths. + # size ==1 is special cased, 1 < size < 5 is linear search, and + # size >= 5 goes through local search and possibly binary search. + for size in range(1, 10): + xp = np.arange(size, dtype=np.double) + yp = np.ones(size, dtype=np.double) + incpts = np.array([-1, 0, size - 1, size], dtype=np.double) + decpts = incpts[::-1] + + incres = interp(incpts, xp, yp) + decres = interp(decpts, xp, yp) + inctgt = np.array([1, 1, 1, 1], dtype=float) + dectgt = inctgt[::-1] + assert_equal(incres, inctgt) + assert_equal(decres, dectgt) + + incres = interp(incpts, xp, yp, left=0) + decres = interp(decpts, xp, yp, left=0) + inctgt = np.array([0, 1, 1, 1], dtype=float) + dectgt = inctgt[::-1] + assert_equal(incres, inctgt) + assert_equal(decres, dectgt) + + incres = interp(incpts, xp, yp, right=2) + decres = interp(decpts, xp, yp, right=2) + inctgt = np.array([1, 1, 1, 2], dtype=float) + dectgt = inctgt[::-1] + assert_equal(incres, inctgt) + assert_equal(decres, dectgt) + + incres = interp(incpts, xp, yp, left=0, right=2) + decres = interp(decpts, xp, yp, left=0, right=2) + inctgt = np.array([0, 1, 1, 2], dtype=float) + dectgt = inctgt[::-1] + assert_equal(incres, inctgt) + assert_equal(decres, dectgt) + + def test_scalar_interpolation_point(self): + x = np.linspace(0, 1, 5) + y = np.linspace(0, 1, 5) + x0 = 0 + assert_almost_equal(np.interp(x0, x, y), x0) + x0 = .3 + assert_almost_equal(np.interp(x0, x, y), x0) + x0 = np.float32(.3) + assert_almost_equal(np.interp(x0, x, y), x0) + x0 = np.float64(.3) + assert_almost_equal(np.interp(x0, x, y), x0) + x0 = np.nan + assert_almost_equal(np.interp(x0, x, y), x0) + + def test_complex_interp(self): + # test complex interpolation + x = np.linspace(0, 1, 5) + y = np.linspace(0, 1, 5) + (1 + np.linspace(0, 1, 5))*1.0j + x0 = 0.3 + y0 = x0 + (1+x0)*1.0j + assert_almost_equal(np.interp(x0, x, y), y0) + # test complex left and right + x0 = -1 + left = 2 + 3.0j + assert_almost_equal(np.interp(x0, x, y, left=left), left) + x0 = 2.0 + right = 2 + 3.0j + assert_almost_equal(np.interp(x0, x, y, right=right), right) + # test complex periodic + x = [-180, -170, -185, 185, -10, -5, 0, 365] + xp = [190, -190, 350, -350] + fp = [5+1.0j, 10+2j, 3+3j, 4+4j] + y = [7.5+1.5j, 5.+1.0j, 8.75+1.75j, 6.25+1.25j, 3.+3j, 3.25+3.25j, + 3.5+3.5j, 3.75+3.75j] + assert_almost_equal(np.interp(x, xp, fp, period=360), y) + + def test_zero_dimensional_interpolation_point(self): + x = np.linspace(0, 1, 5) + y = np.linspace(0, 1, 5) + x0 = np.array(.3) + assert_almost_equal(np.interp(x0, x, y), x0) + x0 = np.array(.3, dtype=object) + assert_almost_equal(np.interp(x0, x, y), .3) + + def test_if_len_x_is_small(self): + xp = np.arange(0, 10, 0.0001) + fp = np.sin(xp) + assert_almost_equal(np.interp(np.pi, xp, fp), 0.0) + + def test_period(self): + x = [-180, -170, -185, 185, -10, -5, 0, 365] + xp = [190, -190, 350, -350] + fp = [5, 10, 3, 4] + y = [7.5, 5., 8.75, 6.25, 3., 3.25, 3.5, 3.75] + assert_almost_equal(np.interp(x, xp, fp, period=360), y) + x = np.array(x, order='F').reshape(2, -1) + y = np.array(y, order='C').reshape(2, -1) + assert_almost_equal(np.interp(x, xp, fp, period=360), y) + + +def compare_results(res, desired): + for i in range(len(desired)): + assert_array_equal(res[i], desired[i]) + + +class TestPercentile(object): + + def test_basic(self): + x = np.arange(8) * 0.5 + assert_equal(np.percentile(x, 0), 0.) + assert_equal(np.percentile(x, 100), 3.5) + assert_equal(np.percentile(x, 50), 1.75) + x[1] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(x, 0), np.nan) + assert_equal(np.percentile(x, 0, interpolation='nearest'), np.nan) + assert_(w[0].category is RuntimeWarning) + + def test_api(self): + d = np.ones(5) + np.percentile(d, 5, None, None, False) + np.percentile(d, 5, None, None, False, 'linear') + o = np.ones((1,)) + np.percentile(d, 5, None, o, False, 'linear') + + def test_2D(self): + x = np.array([[1, 1, 1], + [1, 1, 1], + [4, 4, 3], + [1, 1, 1], + [1, 1, 1]]) + assert_array_equal(np.percentile(x, 50, axis=0), [1, 1, 1]) + + def test_linear(self): + + # Test defaults + assert_equal(np.percentile(range(10), 50), 4.5) + + # explicitly specify interpolation_method 'linear' (the default) + assert_equal(np.percentile(range(10), 50, + interpolation='linear'), 4.5) + + def test_lower_higher(self): + + # interpolation_method 'lower'/'higher' + assert_equal(np.percentile(range(10), 50, + interpolation='lower'), 4) + assert_equal(np.percentile(range(10), 50, + interpolation='higher'), 5) + + def test_midpoint(self): + assert_equal(np.percentile(range(10), 51, + interpolation='midpoint'), 4.5) + assert_equal(np.percentile(range(11), 51, + interpolation='midpoint'), 5.5) + assert_equal(np.percentile(range(11), 50, + interpolation='midpoint'), 5) + + def test_nearest(self): + assert_equal(np.percentile(range(10), 51, + interpolation='nearest'), 5) + assert_equal(np.percentile(range(10), 49, + interpolation='nearest'), 4) + + def test_sequence(self): + x = np.arange(8) * 0.5 + assert_equal(np.percentile(x, [0, 100, 50]), [0, 3.5, 1.75]) + + def test_axis(self): + x = np.arange(12).reshape(3, 4) + + assert_equal(np.percentile(x, (25, 50, 100)), [2.75, 5.5, 11.0]) + + r0 = [[2, 3, 4, 5], [4, 5, 6, 7], [8, 9, 10, 11]] + assert_equal(np.percentile(x, (25, 50, 100), axis=0), r0) + + r1 = [[0.75, 1.5, 3], [4.75, 5.5, 7], [8.75, 9.5, 11]] + assert_equal(np.percentile(x, (25, 50, 100), axis=1), np.array(r1).T) + + # ensure qth axis is always first as with np.array(old_percentile(..)) + x = np.arange(3 * 4 * 5 * 6).reshape(3, 4, 5, 6) + assert_equal(np.percentile(x, (25, 50)).shape, (2,)) + assert_equal(np.percentile(x, (25, 50, 75)).shape, (3,)) + assert_equal(np.percentile(x, (25, 50), axis=0).shape, (2, 4, 5, 6)) + assert_equal(np.percentile(x, (25, 50), axis=1).shape, (2, 3, 5, 6)) + assert_equal(np.percentile(x, (25, 50), axis=2).shape, (2, 3, 4, 6)) + assert_equal(np.percentile(x, (25, 50), axis=3).shape, (2, 3, 4, 5)) + assert_equal( + np.percentile(x, (25, 50, 75), axis=1).shape, (3, 3, 5, 6)) + assert_equal(np.percentile(x, (25, 50), + interpolation="higher").shape, (2,)) + assert_equal(np.percentile(x, (25, 50, 75), + interpolation="higher").shape, (3,)) + assert_equal(np.percentile(x, (25, 50), axis=0, + interpolation="higher").shape, (2, 4, 5, 6)) + assert_equal(np.percentile(x, (25, 50), axis=1, + interpolation="higher").shape, (2, 3, 5, 6)) + assert_equal(np.percentile(x, (25, 50), axis=2, + interpolation="higher").shape, (2, 3, 4, 6)) + assert_equal(np.percentile(x, (25, 50), axis=3, + interpolation="higher").shape, (2, 3, 4, 5)) + assert_equal(np.percentile(x, (25, 50, 75), axis=1, + interpolation="higher").shape, (3, 3, 5, 6)) + + def test_scalar_q(self): + # test for no empty dimensions for compatibility with old percentile + x = np.arange(12).reshape(3, 4) + assert_equal(np.percentile(x, 50), 5.5) + assert_(np.isscalar(np.percentile(x, 50))) + r0 = np.array([4., 5., 6., 7.]) + assert_equal(np.percentile(x, 50, axis=0), r0) + assert_equal(np.percentile(x, 50, axis=0).shape, r0.shape) + r1 = np.array([1.5, 5.5, 9.5]) + assert_almost_equal(np.percentile(x, 50, axis=1), r1) + assert_equal(np.percentile(x, 50, axis=1).shape, r1.shape) + + out = np.empty(1) + assert_equal(np.percentile(x, 50, out=out), 5.5) + assert_equal(out, 5.5) + out = np.empty(4) + assert_equal(np.percentile(x, 50, axis=0, out=out), r0) + assert_equal(out, r0) + out = np.empty(3) + assert_equal(np.percentile(x, 50, axis=1, out=out), r1) + assert_equal(out, r1) + + # test for no empty dimensions for compatibility with old percentile + x = np.arange(12).reshape(3, 4) + assert_equal(np.percentile(x, 50, interpolation='lower'), 5.) + assert_(np.isscalar(np.percentile(x, 50))) + r0 = np.array([4., 5., 6., 7.]) + c0 = np.percentile(x, 50, interpolation='lower', axis=0) + assert_equal(c0, r0) + assert_equal(c0.shape, r0.shape) + r1 = np.array([1., 5., 9.]) + c1 = np.percentile(x, 50, interpolation='lower', axis=1) + assert_almost_equal(c1, r1) + assert_equal(c1.shape, r1.shape) + + out = np.empty((), dtype=x.dtype) + c = np.percentile(x, 50, interpolation='lower', out=out) + assert_equal(c, 5) + assert_equal(out, 5) + out = np.empty(4, dtype=x.dtype) + c = np.percentile(x, 50, interpolation='lower', axis=0, out=out) + assert_equal(c, r0) + assert_equal(out, r0) + out = np.empty(3, dtype=x.dtype) + c = np.percentile(x, 50, interpolation='lower', axis=1, out=out) + assert_equal(c, r1) + assert_equal(out, r1) + + def test_exception(self): + assert_raises(ValueError, np.percentile, [1, 2], 56, + interpolation='foobar') + assert_raises(ValueError, np.percentile, [1], 101) + assert_raises(ValueError, np.percentile, [1], -1) + assert_raises(ValueError, np.percentile, [1], list(range(50)) + [101]) + assert_raises(ValueError, np.percentile, [1], list(range(50)) + [-0.1]) + + def test_percentile_list(self): + assert_equal(np.percentile([1, 2, 3], 0), 1) + + def test_percentile_out(self): + x = np.array([1, 2, 3]) + y = np.zeros((3,)) + p = (1, 2, 3) + np.percentile(x, p, out=y) + assert_equal(y, np.percentile(x, p)) + + x = np.array([[1, 2, 3], + [4, 5, 6]]) + + y = np.zeros((3, 3)) + np.percentile(x, p, axis=0, out=y) + assert_equal(y, np.percentile(x, p, axis=0)) + + y = np.zeros((3, 2)) + np.percentile(x, p, axis=1, out=y) + assert_equal(y, np.percentile(x, p, axis=1)) + + x = np.arange(12).reshape(3, 4) + # q.dim > 1, float + r0 = np.array([[2., 3., 4., 5.], [4., 5., 6., 7.]]) + out = np.empty((2, 4)) + assert_equal(np.percentile(x, (25, 50), axis=0, out=out), r0) + assert_equal(out, r0) + r1 = np.array([[0.75, 4.75, 8.75], [1.5, 5.5, 9.5]]) + out = np.empty((2, 3)) + assert_equal(np.percentile(x, (25, 50), axis=1, out=out), r1) + assert_equal(out, r1) + + # q.dim > 1, int + r0 = np.array([[0, 1, 2, 3], [4, 5, 6, 7]]) + out = np.empty((2, 4), dtype=x.dtype) + c = np.percentile(x, (25, 50), interpolation='lower', axis=0, out=out) + assert_equal(c, r0) + assert_equal(out, r0) + r1 = np.array([[0, 4, 8], [1, 5, 9]]) + out = np.empty((2, 3), dtype=x.dtype) + c = np.percentile(x, (25, 50), interpolation='lower', axis=1, out=out) + assert_equal(c, r1) + assert_equal(out, r1) + + def test_percentile_empty_dim(self): + # empty dims are preserved + d = np.arange(11 * 2).reshape(11, 1, 2, 1) + assert_array_equal(np.percentile(d, 50, axis=0).shape, (1, 2, 1)) + assert_array_equal(np.percentile(d, 50, axis=1).shape, (11, 2, 1)) + assert_array_equal(np.percentile(d, 50, axis=2).shape, (11, 1, 1)) + assert_array_equal(np.percentile(d, 50, axis=3).shape, (11, 1, 2)) + assert_array_equal(np.percentile(d, 50, axis=-1).shape, (11, 1, 2)) + assert_array_equal(np.percentile(d, 50, axis=-2).shape, (11, 1, 1)) + assert_array_equal(np.percentile(d, 50, axis=-3).shape, (11, 2, 1)) + assert_array_equal(np.percentile(d, 50, axis=-4).shape, (1, 2, 1)) + + assert_array_equal(np.percentile(d, 50, axis=2, + interpolation='midpoint').shape, + (11, 1, 1)) + assert_array_equal(np.percentile(d, 50, axis=-2, + interpolation='midpoint').shape, + (11, 1, 1)) + + assert_array_equal(np.array(np.percentile(d, [10, 50], axis=0)).shape, + (2, 1, 2, 1)) + assert_array_equal(np.array(np.percentile(d, [10, 50], axis=1)).shape, + (2, 11, 2, 1)) + assert_array_equal(np.array(np.percentile(d, [10, 50], axis=2)).shape, + (2, 11, 1, 1)) + assert_array_equal(np.array(np.percentile(d, [10, 50], axis=3)).shape, + (2, 11, 1, 2)) + + def test_percentile_no_overwrite(self): + a = np.array([2, 3, 4, 1]) + np.percentile(a, [50], overwrite_input=False) + assert_equal(a, np.array([2, 3, 4, 1])) + + a = np.array([2, 3, 4, 1]) + np.percentile(a, [50]) + assert_equal(a, np.array([2, 3, 4, 1])) + + def test_no_p_overwrite(self): + p = np.linspace(0., 100., num=5) + np.percentile(np.arange(100.), p, interpolation="midpoint") + assert_array_equal(p, np.linspace(0., 100., num=5)) + p = np.linspace(0., 100., num=5).tolist() + np.percentile(np.arange(100.), p, interpolation="midpoint") + assert_array_equal(p, np.linspace(0., 100., num=5).tolist()) + + def test_percentile_overwrite(self): + a = np.array([2, 3, 4, 1]) + b = np.percentile(a, [50], overwrite_input=True) + assert_equal(b, np.array([2.5])) + + b = np.percentile([2, 3, 4, 1], [50], overwrite_input=True) + assert_equal(b, np.array([2.5])) + + def test_extended_axis(self): + o = np.random.normal(size=(71, 23)) + x = np.dstack([o] * 10) + assert_equal(np.percentile(x, 30, axis=(0, 1)), np.percentile(o, 30)) + x = np.moveaxis(x, -1, 0) + assert_equal(np.percentile(x, 30, axis=(-2, -1)), np.percentile(o, 30)) + x = x.swapaxes(0, 1).copy() + assert_equal(np.percentile(x, 30, axis=(0, -1)), np.percentile(o, 30)) + x = x.swapaxes(0, 1).copy() + + assert_equal(np.percentile(x, [25, 60], axis=(0, 1, 2)), + np.percentile(x, [25, 60], axis=None)) + assert_equal(np.percentile(x, [25, 60], axis=(0,)), + np.percentile(x, [25, 60], axis=0)) + + d = np.arange(3 * 5 * 7 * 11).reshape((3, 5, 7, 11)) + np.random.shuffle(d.ravel()) + assert_equal(np.percentile(d, 25, axis=(0, 1, 2))[0], + np.percentile(d[:,:,:, 0].flatten(), 25)) + assert_equal(np.percentile(d, [10, 90], axis=(0, 1, 3))[:, 1], + np.percentile(d[:,:, 1,:].flatten(), [10, 90])) + assert_equal(np.percentile(d, 25, axis=(3, 1, -4))[2], + np.percentile(d[:,:, 2,:].flatten(), 25)) + assert_equal(np.percentile(d, 25, axis=(3, 1, 2))[2], + np.percentile(d[2,:,:,:].flatten(), 25)) + assert_equal(np.percentile(d, 25, axis=(3, 2))[2, 1], + np.percentile(d[2, 1,:,:].flatten(), 25)) + assert_equal(np.percentile(d, 25, axis=(1, -2))[2, 1], + np.percentile(d[2,:,:, 1].flatten(), 25)) + assert_equal(np.percentile(d, 25, axis=(1, 3))[2, 2], + np.percentile(d[2,:, 2,:].flatten(), 25)) + + def test_extended_axis_invalid(self): + d = np.ones((3, 5, 7, 11)) + assert_raises(np.AxisError, np.percentile, d, axis=-5, q=25) + assert_raises(np.AxisError, np.percentile, d, axis=(0, -5), q=25) + assert_raises(np.AxisError, np.percentile, d, axis=4, q=25) + assert_raises(np.AxisError, np.percentile, d, axis=(0, 4), q=25) + # each of these refers to the same axis twice + assert_raises(ValueError, np.percentile, d, axis=(1, 1), q=25) + assert_raises(ValueError, np.percentile, d, axis=(-1, -1), q=25) + assert_raises(ValueError, np.percentile, d, axis=(3, -1), q=25) + + def test_keepdims(self): + d = np.ones((3, 5, 7, 11)) + assert_equal(np.percentile(d, 7, axis=None, keepdims=True).shape, + (1, 1, 1, 1)) + assert_equal(np.percentile(d, 7, axis=(0, 1), keepdims=True).shape, + (1, 1, 7, 11)) + assert_equal(np.percentile(d, 7, axis=(0, 3), keepdims=True).shape, + (1, 5, 7, 1)) + assert_equal(np.percentile(d, 7, axis=(1,), keepdims=True).shape, + (3, 1, 7, 11)) + assert_equal(np.percentile(d, 7, (0, 1, 2, 3), keepdims=True).shape, + (1, 1, 1, 1)) + assert_equal(np.percentile(d, 7, axis=(0, 1, 3), keepdims=True).shape, + (1, 1, 7, 1)) + + assert_equal(np.percentile(d, [1, 7], axis=(0, 1, 3), + keepdims=True).shape, (2, 1, 1, 7, 1)) + assert_equal(np.percentile(d, [1, 7], axis=(0, 3), + keepdims=True).shape, (2, 1, 5, 7, 1)) + + def test_out(self): + o = np.zeros((4,)) + d = np.ones((3, 4)) + assert_equal(np.percentile(d, 0, 0, out=o), o) + assert_equal(np.percentile(d, 0, 0, interpolation='nearest', out=o), o) + o = np.zeros((3,)) + assert_equal(np.percentile(d, 1, 1, out=o), o) + assert_equal(np.percentile(d, 1, 1, interpolation='nearest', out=o), o) + + o = np.zeros(()) + assert_equal(np.percentile(d, 2, out=o), o) + assert_equal(np.percentile(d, 2, interpolation='nearest', out=o), o) + + def test_out_nan(self): + with warnings.catch_warnings(record=True): + warnings.filterwarnings('always', '', RuntimeWarning) + o = np.zeros((4,)) + d = np.ones((3, 4)) + d[2, 1] = np.nan + assert_equal(np.percentile(d, 0, 0, out=o), o) + assert_equal( + np.percentile(d, 0, 0, interpolation='nearest', out=o), o) + o = np.zeros((3,)) + assert_equal(np.percentile(d, 1, 1, out=o), o) + assert_equal( + np.percentile(d, 1, 1, interpolation='nearest', out=o), o) + o = np.zeros(()) + assert_equal(np.percentile(d, 1, out=o), o) + assert_equal( + np.percentile(d, 1, interpolation='nearest', out=o), o) + + def test_nan_behavior(self): + a = np.arange(24, dtype=float) + a[2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(a, 0.3), np.nan) + assert_equal(np.percentile(a, 0.3, axis=0), np.nan) + assert_equal(np.percentile(a, [0.3, 0.6], axis=0), + np.array([np.nan] * 2)) + assert_(w[0].category is RuntimeWarning) + assert_(w[1].category is RuntimeWarning) + assert_(w[2].category is RuntimeWarning) + + a = np.arange(24, dtype=float).reshape(2, 3, 4) + a[1, 2, 3] = np.nan + a[1, 1, 2] = np.nan + + # no axis + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(a, 0.3), np.nan) + assert_equal(np.percentile(a, 0.3).ndim, 0) + assert_(w[0].category is RuntimeWarning) + + # axis0 zerod + b = np.percentile(np.arange(24, dtype=float).reshape(2, 3, 4), 0.3, 0) + b[2, 3] = np.nan + b[1, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(a, 0.3, 0), b) + + # axis0 not zerod + b = np.percentile(np.arange(24, dtype=float).reshape(2, 3, 4), + [0.3, 0.6], 0) + b[:, 2, 3] = np.nan + b[:, 1, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(a, [0.3, 0.6], 0), b) + + # axis1 zerod + b = np.percentile(np.arange(24, dtype=float).reshape(2, 3, 4), 0.3, 1) + b[1, 3] = np.nan + b[1, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(a, 0.3, 1), b) + # axis1 not zerod + b = np.percentile( + np.arange(24, dtype=float).reshape(2, 3, 4), [0.3, 0.6], 1) + b[:, 1, 3] = np.nan + b[:, 1, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(a, [0.3, 0.6], 1), b) + + # axis02 zerod + b = np.percentile( + np.arange(24, dtype=float).reshape(2, 3, 4), 0.3, (0, 2)) + b[1] = np.nan + b[2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(a, 0.3, (0, 2)), b) + # axis02 not zerod + b = np.percentile(np.arange(24, dtype=float).reshape(2, 3, 4), + [0.3, 0.6], (0, 2)) + b[:, 1] = np.nan + b[:, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile(a, [0.3, 0.6], (0, 2)), b) + # axis02 not zerod with nearest interpolation + b = np.percentile(np.arange(24, dtype=float).reshape(2, 3, 4), + [0.3, 0.6], (0, 2), interpolation='nearest') + b[:, 1] = np.nan + b[:, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.percentile( + a, [0.3, 0.6], (0, 2), interpolation='nearest'), b) + + +class TestMedian(object): + + def test_basic(self): + a0 = np.array(1) + a1 = np.arange(2) + a2 = np.arange(6).reshape(2, 3) + assert_equal(np.median(a0), 1) + assert_allclose(np.median(a1), 0.5) + assert_allclose(np.median(a2), 2.5) + assert_allclose(np.median(a2, axis=0), [1.5, 2.5, 3.5]) + assert_equal(np.median(a2, axis=1), [1, 4]) + assert_allclose(np.median(a2, axis=None), 2.5) + + a = np.array([0.0444502, 0.0463301, 0.141249, 0.0606775]) + assert_almost_equal((a[1] + a[3]) / 2., np.median(a)) + a = np.array([0.0463301, 0.0444502, 0.141249]) + assert_equal(a[0], np.median(a)) + a = np.array([0.0444502, 0.141249, 0.0463301]) + assert_equal(a[-1], np.median(a)) + # check array scalar result + assert_equal(np.median(a).ndim, 0) + a[1] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a).ndim, 0) + assert_(w[0].category is RuntimeWarning) + + def test_axis_keyword(self): + a3 = np.array([[2, 3], + [0, 1], + [6, 7], + [4, 5]]) + for a in [a3, np.random.randint(0, 100, size=(2, 3, 4))]: + orig = a.copy() + np.median(a, axis=None) + for ax in range(a.ndim): + np.median(a, axis=ax) + assert_array_equal(a, orig) + + assert_allclose(np.median(a3, axis=0), [3, 4]) + assert_allclose(np.median(a3.T, axis=1), [3, 4]) + assert_allclose(np.median(a3), 3.5) + assert_allclose(np.median(a3, axis=None), 3.5) + assert_allclose(np.median(a3.T), 3.5) + + def test_overwrite_keyword(self): + a3 = np.array([[2, 3], + [0, 1], + [6, 7], + [4, 5]]) + a0 = np.array(1) + a1 = np.arange(2) + a2 = np.arange(6).reshape(2, 3) + assert_allclose(np.median(a0.copy(), overwrite_input=True), 1) + assert_allclose(np.median(a1.copy(), overwrite_input=True), 0.5) + assert_allclose(np.median(a2.copy(), overwrite_input=True), 2.5) + assert_allclose(np.median(a2.copy(), overwrite_input=True, axis=0), + [1.5, 2.5, 3.5]) + assert_allclose( + np.median(a2.copy(), overwrite_input=True, axis=1), [1, 4]) + assert_allclose( + np.median(a2.copy(), overwrite_input=True, axis=None), 2.5) + assert_allclose( + np.median(a3.copy(), overwrite_input=True, axis=0), [3, 4]) + assert_allclose(np.median(a3.T.copy(), overwrite_input=True, axis=1), + [3, 4]) + + a4 = np.arange(3 * 4 * 5, dtype=np.float32).reshape((3, 4, 5)) + np.random.shuffle(a4.ravel()) + assert_allclose(np.median(a4, axis=None), + np.median(a4.copy(), axis=None, overwrite_input=True)) + assert_allclose(np.median(a4, axis=0), + np.median(a4.copy(), axis=0, overwrite_input=True)) + assert_allclose(np.median(a4, axis=1), + np.median(a4.copy(), axis=1, overwrite_input=True)) + assert_allclose(np.median(a4, axis=2), + np.median(a4.copy(), axis=2, overwrite_input=True)) + + def test_array_like(self): + x = [1, 2, 3] + assert_almost_equal(np.median(x), 2) + x2 = [x] + assert_almost_equal(np.median(x2), 2) + assert_allclose(np.median(x2, axis=0), x) + + def test_subclass(self): + # gh-3846 + class MySubClass(np.ndarray): + + def __new__(cls, input_array, info=None): + obj = np.asarray(input_array).view(cls) + obj.info = info + return obj + + def mean(self, axis=None, dtype=None, out=None): + return -7 + + a = MySubClass([1, 2, 3]) + assert_equal(np.median(a), -7) + + def test_out(self): + o = np.zeros((4,)) + d = np.ones((3, 4)) + assert_equal(np.median(d, 0, out=o), o) + o = np.zeros((3,)) + assert_equal(np.median(d, 1, out=o), o) + o = np.zeros(()) + assert_equal(np.median(d, out=o), o) + + def test_out_nan(self): + with warnings.catch_warnings(record=True): + warnings.filterwarnings('always', '', RuntimeWarning) + o = np.zeros((4,)) + d = np.ones((3, 4)) + d[2, 1] = np.nan + assert_equal(np.median(d, 0, out=o), o) + o = np.zeros((3,)) + assert_equal(np.median(d, 1, out=o), o) + o = np.zeros(()) + assert_equal(np.median(d, out=o), o) + + def test_nan_behavior(self): + a = np.arange(24, dtype=float) + a[2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a), np.nan) + assert_equal(np.median(a, axis=0), np.nan) + assert_(w[0].category is RuntimeWarning) + assert_(w[1].category is RuntimeWarning) + + a = np.arange(24, dtype=float).reshape(2, 3, 4) + a[1, 2, 3] = np.nan + a[1, 1, 2] = np.nan + + # no axis + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a), np.nan) + assert_equal(np.median(a).ndim, 0) + assert_(w[0].category is RuntimeWarning) + + # axis0 + b = np.median(np.arange(24, dtype=float).reshape(2, 3, 4), 0) + b[2, 3] = np.nan + b[1, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a, 0), b) + assert_equal(len(w), 1) + + # axis1 + b = np.median(np.arange(24, dtype=float).reshape(2, 3, 4), 1) + b[1, 3] = np.nan + b[1, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a, 1), b) + assert_equal(len(w), 1) + + # axis02 + b = np.median(np.arange(24, dtype=float).reshape(2, 3, 4), (0, 2)) + b[1] = np.nan + b[2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a, (0, 2)), b) + assert_equal(len(w), 1) + + def test_empty(self): + # empty arrays + a = np.array([], dtype=float) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a), np.nan) + assert_(w[0].category is RuntimeWarning) + + # multiple dimensions + a = np.array([], dtype=float, ndmin=3) + # no axis + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a), np.nan) + assert_(w[0].category is RuntimeWarning) + + # axis 0 and 1 + b = np.array([], dtype=float, ndmin=2) + assert_equal(np.median(a, axis=0), b) + assert_equal(np.median(a, axis=1), b) + + # axis 2 + b = np.array(np.nan, dtype=float, ndmin=2) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.median(a, axis=2), b) + assert_(w[0].category is RuntimeWarning) + + def test_object(self): + o = np.arange(7.) + assert_(type(np.median(o.astype(object))), float) + o[2] = np.nan + assert_(type(np.median(o.astype(object))), float) + + def test_extended_axis(self): + o = np.random.normal(size=(71, 23)) + x = np.dstack([o] * 10) + assert_equal(np.median(x, axis=(0, 1)), np.median(o)) + x = np.moveaxis(x, -1, 0) + assert_equal(np.median(x, axis=(-2, -1)), np.median(o)) + x = x.swapaxes(0, 1).copy() + assert_equal(np.median(x, axis=(0, -1)), np.median(o)) + + assert_equal(np.median(x, axis=(0, 1, 2)), np.median(x, axis=None)) + assert_equal(np.median(x, axis=(0, )), np.median(x, axis=0)) + assert_equal(np.median(x, axis=(-1, )), np.median(x, axis=-1)) + + d = np.arange(3 * 5 * 7 * 11).reshape((3, 5, 7, 11)) + np.random.shuffle(d.ravel()) + assert_equal(np.median(d, axis=(0, 1, 2))[0], + np.median(d[:,:,:, 0].flatten())) + assert_equal(np.median(d, axis=(0, 1, 3))[1], + np.median(d[:,:, 1,:].flatten())) + assert_equal(np.median(d, axis=(3, 1, -4))[2], + np.median(d[:,:, 2,:].flatten())) + assert_equal(np.median(d, axis=(3, 1, 2))[2], + np.median(d[2,:,:,:].flatten())) + assert_equal(np.median(d, axis=(3, 2))[2, 1], + np.median(d[2, 1,:,:].flatten())) + assert_equal(np.median(d, axis=(1, -2))[2, 1], + np.median(d[2,:,:, 1].flatten())) + assert_equal(np.median(d, axis=(1, 3))[2, 2], + np.median(d[2,:, 2,:].flatten())) + + def test_extended_axis_invalid(self): + d = np.ones((3, 5, 7, 11)) + assert_raises(np.AxisError, np.median, d, axis=-5) + assert_raises(np.AxisError, np.median, d, axis=(0, -5)) + assert_raises(np.AxisError, np.median, d, axis=4) + assert_raises(np.AxisError, np.median, d, axis=(0, 4)) + assert_raises(ValueError, np.median, d, axis=(1, 1)) + + def test_keepdims(self): + d = np.ones((3, 5, 7, 11)) + assert_equal(np.median(d, axis=None, keepdims=True).shape, + (1, 1, 1, 1)) + assert_equal(np.median(d, axis=(0, 1), keepdims=True).shape, + (1, 1, 7, 11)) + assert_equal(np.median(d, axis=(0, 3), keepdims=True).shape, + (1, 5, 7, 1)) + assert_equal(np.median(d, axis=(1,), keepdims=True).shape, + (3, 1, 7, 11)) + assert_equal(np.median(d, axis=(0, 1, 2, 3), keepdims=True).shape, + (1, 1, 1, 1)) + assert_equal(np.median(d, axis=(0, 1, 3), keepdims=True).shape, + (1, 1, 7, 1)) + + +class TestAdd_newdoc_ufunc(object): + + def test_ufunc_arg(self): + assert_raises(TypeError, add_newdoc_ufunc, 2, "blah") + assert_raises(ValueError, add_newdoc_ufunc, np.add, "blah") + + def test_string_arg(self): + assert_raises(TypeError, add_newdoc_ufunc, np.add, 3) + + +class TestAdd_newdoc(object): + + @dec.skipif(sys.flags.optimize == 2) + def test_add_doc(self): + # test np.add_newdoc + tgt = "Current flat index into the array." + assert_equal(np.core.flatiter.index.__doc__[:len(tgt)], tgt) + assert_(len(np.core.ufunc.identity.__doc__) > 300) + assert_(len(np.lib.index_tricks.mgrid.__doc__) > 300) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_index_tricks.py b/numpy/lib/tests/test_index_tricks.py new file mode 100644 index 0000000..1d5efef --- /dev/null +++ b/numpy/lib/tests/test_index_tricks.py @@ -0,0 +1,395 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal, + assert_almost_equal, assert_array_almost_equal, assert_raises, + assert_raises_regex + ) +from numpy.lib.index_tricks import ( + mgrid, 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)) + 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) + + +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_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_matrix(self): + a = [1, 2] + b = [3, 4] + + ab_r = np.r_['r', a, b] + ab_c = np.r_['c', a, b] + + assert_equal(type(ab_r), np.matrix) + assert_equal(type(ab_c), np.matrix) + + assert_equal(np.array(ab_r), [[1,2,3,4]]) + assert_equal(np.array(ab_c), [[1],[2],[3],[4]]) + + assert_raises(ValueError, lambda: np.r_['rc', a, b]) + + def test_matrix_scalar(self): + r = np.r_['r', [1, 2], 3] + assert_equal(type(r), np.matrix) + assert_equal(np.array(r), [[1,2,3]]) + + def test_matrix_builder(self): + a = np.array([1]) + b = np.array([2]) + c = np.array([3]) + d = np.array([4]) + actual = np.r_['a, b; c, d'] + expected = np.bmat([[a, b], [c, d]]) + + assert_equal(actual, expected) + assert_equal(type(actual), type(expected)) + + +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 ouputs 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]]) + + +def test_fill_diagonal(): + a = np.zeros((3, 3), int) + fill_diagonal(a, 5) + yield (assert_array_equal, a, + np.array([[5, 0, 0], + [0, 5, 0], + [0, 0, 5]])) + + #Test tall matrix + a = np.zeros((10, 3), int) + fill_diagonal(a, 5) + yield (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]])) + + #Test tall matrix wrap + a = np.zeros((10, 3), int) + fill_diagonal(a, 5, True) + yield (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]])) + + #Test wide matrix + a = np.zeros((3, 10), int) + fill_diagonal(a, 5) + yield (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]])) + + # The same function can operate on a 4-d array: + a = np.zeros((3, 3, 3, 3), int) + fill_diagonal(a, 4) + i = np.array([0, 1, 2]) + yield (assert_equal, np.where(a != 0), (i, i, i, i)) + + +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 + yield (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 + yield (assert_array_equal, a, + np.array([[[1, 0], + [0, 0]], + + [[0, 0], + [0, 1]]])) + + +def test_diag_indices_from(): + 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_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, []) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_io.py b/numpy/lib/tests/test_io.py new file mode 100644 index 0000000..2daa015 --- /dev/null +++ b/numpy/lib/tests/test_io.py @@ -0,0 +1,2381 @@ +from __future__ import division, absolute_import, print_function + +import sys +import gzip +import os +import threading +from tempfile import NamedTemporaryFile +import time +import warnings +import gc +import io +from io import BytesIO, StringIO +from datetime import datetime +import locale +import re + +import numpy as np +import numpy.ma as ma +from numpy.lib._iotools import ConverterError, ConversionWarning +from numpy.compat import asbytes, bytes, unicode, Path +from numpy.ma.testutils import assert_equal +from numpy.testing import ( + run_module_suite, assert_warns, assert_, SkipTest, + assert_raises_regex, assert_raises, assert_allclose, + assert_array_equal, temppath, tempdir, dec, IS_PYPY, suppress_warnings +) + + +class TextIO(BytesIO): + """Helper IO class. + + Writes encode strings to bytes if needed, reads return bytes. + This makes it easier to emulate files opened in binary mode + without needing to explicitly convert strings to bytes in + setting up the test data. + + """ + def __init__(self, s=""): + BytesIO.__init__(self, asbytes(s)) + + def write(self, s): + BytesIO.write(self, asbytes(s)) + + def writelines(self, lines): + BytesIO.writelines(self, [asbytes(s) for s in lines]) + + +MAJVER, MINVER = sys.version_info[:2] +IS_64BIT = sys.maxsize > 2**32 +try: + import bz2 + HAS_BZ2 = True +except ImportError: + HAS_BZ2 = False +try: + import lzma + HAS_LZMA = True +except ImportError: + HAS_LZMA = False + + +def strptime(s, fmt=None): + """ + This function is available in the datetime module only from Python >= + 2.5. + + """ + if type(s) == bytes: + s = s.decode("latin1") + return datetime(*time.strptime(s, fmt)[:3]) + + +class RoundtripTest(object): + def roundtrip(self, save_func, *args, **kwargs): + """ + save_func : callable + Function used to save arrays to file. + file_on_disk : bool + If true, store the file on disk, instead of in a + string buffer. + save_kwds : dict + Parameters passed to `save_func`. + load_kwds : dict + Parameters passed to `numpy.load`. + args : tuple of arrays + Arrays stored to file. + + """ + save_kwds = kwargs.get('save_kwds', {}) + load_kwds = kwargs.get('load_kwds', {}) + file_on_disk = kwargs.get('file_on_disk', False) + + if file_on_disk: + target_file = NamedTemporaryFile(delete=False) + load_file = target_file.name + else: + target_file = BytesIO() + load_file = target_file + + try: + arr = args + + save_func(target_file, *arr, **save_kwds) + target_file.flush() + target_file.seek(0) + + if sys.platform == 'win32' and not isinstance(target_file, BytesIO): + target_file.close() + + arr_reloaded = np.load(load_file, **load_kwds) + + self.arr = arr + self.arr_reloaded = arr_reloaded + finally: + if not isinstance(target_file, BytesIO): + target_file.close() + # holds an open file descriptor so it can't be deleted on win + if 'arr_reloaded' in locals(): + if not isinstance(arr_reloaded, np.lib.npyio.NpzFile): + os.remove(target_file.name) + + def check_roundtrips(self, a): + self.roundtrip(a) + self.roundtrip(a, file_on_disk=True) + self.roundtrip(np.asfortranarray(a)) + self.roundtrip(np.asfortranarray(a), file_on_disk=True) + if a.shape[0] > 1: + # neither C nor Fortran contiguous for 2D arrays or more + self.roundtrip(np.asfortranarray(a)[1:]) + self.roundtrip(np.asfortranarray(a)[1:], file_on_disk=True) + + def test_array(self): + a = np.array([], float) + self.check_roundtrips(a) + + a = np.array([[1, 2], [3, 4]], float) + self.check_roundtrips(a) + + a = np.array([[1, 2], [3, 4]], int) + self.check_roundtrips(a) + + a = np.array([[1 + 5j, 2 + 6j], [3 + 7j, 4 + 8j]], dtype=np.csingle) + self.check_roundtrips(a) + + a = np.array([[1 + 5j, 2 + 6j], [3 + 7j, 4 + 8j]], dtype=np.cdouble) + self.check_roundtrips(a) + + def test_array_object(self): + a = np.array([], object) + self.check_roundtrips(a) + + a = np.array([[1, 2], [3, 4]], object) + self.check_roundtrips(a) + + def test_1D(self): + a = np.array([1, 2, 3, 4], int) + self.roundtrip(a) + + @dec.knownfailureif(sys.platform == 'win32', "Fail on Win32") + def test_mmap(self): + a = np.array([[1, 2.5], [4, 7.3]]) + self.roundtrip(a, file_on_disk=True, load_kwds={'mmap_mode': 'r'}) + + a = np.asfortranarray([[1, 2.5], [4, 7.3]]) + self.roundtrip(a, file_on_disk=True, load_kwds={'mmap_mode': 'r'}) + + def test_record(self): + a = np.array([(1, 2), (3, 4)], dtype=[('x', 'i4'), ('y', 'i4')]) + self.check_roundtrips(a) + + @dec.slow + def test_format_2_0(self): + dt = [(("%d" % i) * 100, float) for i in range(500)] + a = np.ones(1000, dtype=dt) + with warnings.catch_warnings(record=True): + warnings.filterwarnings('always', '', UserWarning) + self.check_roundtrips(a) + + +class TestSaveLoad(RoundtripTest): + def roundtrip(self, *args, **kwargs): + RoundtripTest.roundtrip(self, np.save, *args, **kwargs) + assert_equal(self.arr[0], self.arr_reloaded) + assert_equal(self.arr[0].dtype, self.arr_reloaded.dtype) + assert_equal(self.arr[0].flags.fnc, self.arr_reloaded.flags.fnc) + + +class TestSavezLoad(RoundtripTest): + def roundtrip(self, *args, **kwargs): + RoundtripTest.roundtrip(self, np.savez, *args, **kwargs) + try: + for n, arr in enumerate(self.arr): + reloaded = self.arr_reloaded['arr_%d' % n] + assert_equal(arr, reloaded) + assert_equal(arr.dtype, reloaded.dtype) + assert_equal(arr.flags.fnc, reloaded.flags.fnc) + finally: + # delete tempfile, must be done here on windows + if self.arr_reloaded.fid: + self.arr_reloaded.fid.close() + os.remove(self.arr_reloaded.fid.name) + + @dec.skipif(not IS_64BIT, "Works only with 64bit systems") + @dec.slow + def test_big_arrays(self): + L = (1 << 31) + 100000 + a = np.empty(L, dtype=np.uint8) + with temppath(prefix="numpy_test_big_arrays_", suffix=".npz") as tmp: + np.savez(tmp, a=a) + del a + npfile = np.load(tmp) + a = npfile['a'] # Should succeed + npfile.close() + del a # Avoid pyflakes unused variable warning. + + def test_multiple_arrays(self): + a = np.array([[1, 2], [3, 4]], float) + b = np.array([[1 + 2j, 2 + 7j], [3 - 6j, 4 + 12j]], complex) + self.roundtrip(a, b) + + def test_named_arrays(self): + a = np.array([[1, 2], [3, 4]], float) + b = np.array([[1 + 2j, 2 + 7j], [3 - 6j, 4 + 12j]], complex) + c = BytesIO() + np.savez(c, file_a=a, file_b=b) + c.seek(0) + l = np.load(c) + assert_equal(a, l['file_a']) + assert_equal(b, l['file_b']) + + def test_BagObj(self): + a = np.array([[1, 2], [3, 4]], float) + b = np.array([[1 + 2j, 2 + 7j], [3 - 6j, 4 + 12j]], complex) + c = BytesIO() + np.savez(c, file_a=a, file_b=b) + c.seek(0) + l = np.load(c) + assert_equal(sorted(dir(l.f)), ['file_a','file_b']) + assert_equal(a, l.f.file_a) + assert_equal(b, l.f.file_b) + + def test_savez_filename_clashes(self): + # Test that issue #852 is fixed + # and savez functions in multithreaded environment + + def writer(error_list): + with temppath(suffix='.npz') as tmp: + arr = np.random.randn(500, 500) + try: + np.savez(tmp, arr=arr) + except OSError as err: + error_list.append(err) + + errors = [] + threads = [threading.Thread(target=writer, args=(errors,)) + for j in range(3)] + for t in threads: + t.start() + for t in threads: + t.join() + + if errors: + raise AssertionError(errors) + + def test_not_closing_opened_fid(self): + # Test that issue #2178 is fixed: + # verify could seek on 'loaded' file + with temppath(suffix='.npz') as tmp: + with open(tmp, 'wb') as fp: + np.savez(fp, data='LOVELY LOAD') + with open(tmp, 'rb', 10000) as fp: + fp.seek(0) + assert_(not fp.closed) + np.load(fp)['data'] + # fp must not get closed by .load + assert_(not fp.closed) + fp.seek(0) + assert_(not fp.closed) + + @dec.skipif(IS_PYPY, "context manager required on PyPy") + def test_closing_fid(self): + # Test that issue #1517 (too many opened files) remains closed + # It might be a "weak" test since failed to get triggered on + # e.g. Debian sid of 2012 Jul 05 but was reported to + # trigger the failure on Ubuntu 10.04: + # http://projects.scipy.org/numpy/ticket/1517#comment:2 + with temppath(suffix='.npz') as tmp: + np.savez(tmp, data='LOVELY LOAD') + # We need to check if the garbage collector can properly close + # numpy npz file returned by np.load when their reference count + # goes to zero. Python 3 running in debug mode raises a + # ResourceWarning when file closing is left to the garbage + # collector, so we catch the warnings. Because ResourceWarning + # is unknown in Python < 3.x, we take the easy way out and + # catch all warnings. + with suppress_warnings() as sup: + sup.filter(Warning) # TODO: specify exact message + for i in range(1, 1025): + try: + np.load(tmp)["data"] + except Exception as e: + msg = "Failed to load data from a file: %s" % e + raise AssertionError(msg) + + def test_closing_zipfile_after_load(self): + # Check that zipfile owns file and can close it. This needs to + # pass a file name to load for the test. On windows failure will + # cause a second error will be raised when the attempt to remove + # the open file is made. + prefix = 'numpy_test_closing_zipfile_after_load_' + with temppath(suffix='.npz', prefix=prefix) as tmp: + np.savez(tmp, lab='place holder') + data = np.load(tmp) + fp = data.zip.fp + data.close() + assert_(fp.closed) + + +class TestSaveTxt(object): + def test_array(self): + a = np.array([[1, 2], [3, 4]], float) + fmt = "%.18e" + c = BytesIO() + np.savetxt(c, a, fmt=fmt) + c.seek(0) + assert_equal(c.readlines(), + [asbytes((fmt + ' ' + fmt + '\n') % (1, 2)), + asbytes((fmt + ' ' + fmt + '\n') % (3, 4))]) + + a = np.array([[1, 2], [3, 4]], int) + c = BytesIO() + np.savetxt(c, a, fmt='%d') + c.seek(0) + assert_equal(c.readlines(), [b'1 2\n', b'3 4\n']) + + def test_1D(self): + a = np.array([1, 2, 3, 4], int) + c = BytesIO() + np.savetxt(c, a, fmt='%d') + c.seek(0) + lines = c.readlines() + assert_equal(lines, [b'1\n', b'2\n', b'3\n', b'4\n']) + + def test_0D_3D(self): + c = BytesIO() + assert_raises(ValueError, np.savetxt, c, np.array(1)) + assert_raises(ValueError, np.savetxt, c, np.array([[[1], [2]]])) + + + def test_record(self): + a = np.array([(1, 2), (3, 4)], dtype=[('x', 'i4'), ('y', 'i4')]) + c = BytesIO() + np.savetxt(c, a, fmt='%d') + c.seek(0) + assert_equal(c.readlines(), [b'1 2\n', b'3 4\n']) + + def test_delimiter(self): + a = np.array([[1., 2.], [3., 4.]]) + c = BytesIO() + np.savetxt(c, a, delimiter=',', fmt='%d') + c.seek(0) + assert_equal(c.readlines(), [b'1,2\n', b'3,4\n']) + + def test_format(self): + a = np.array([(1, 2), (3, 4)]) + c = BytesIO() + # Sequence of formats + np.savetxt(c, a, fmt=['%02d', '%3.1f']) + c.seek(0) + assert_equal(c.readlines(), [b'01 2.0\n', b'03 4.0\n']) + + # A single multiformat string + c = BytesIO() + np.savetxt(c, a, fmt='%02d : %3.1f') + c.seek(0) + lines = c.readlines() + assert_equal(lines, [b'01 : 2.0\n', b'03 : 4.0\n']) + + # Specify delimiter, should be overiden + c = BytesIO() + np.savetxt(c, a, fmt='%02d : %3.1f', delimiter=',') + c.seek(0) + lines = c.readlines() + assert_equal(lines, [b'01 : 2.0\n', b'03 : 4.0\n']) + + # Bad fmt, should raise a ValueError + c = BytesIO() + assert_raises(ValueError, np.savetxt, c, a, fmt=99) + + def test_header_footer(self): + # Test the functionality of the header and footer keyword argument. + + c = BytesIO() + a = np.array([(1, 2), (3, 4)], dtype=int) + test_header_footer = 'Test header / footer' + # Test the header keyword argument + np.savetxt(c, a, fmt='%1d', header=test_header_footer) + c.seek(0) + assert_equal(c.read(), + asbytes('# ' + test_header_footer + '\n1 2\n3 4\n')) + # Test the footer keyword argument + c = BytesIO() + np.savetxt(c, a, fmt='%1d', footer=test_header_footer) + c.seek(0) + assert_equal(c.read(), + asbytes('1 2\n3 4\n# ' + test_header_footer + '\n')) + # Test the commentstr keyword argument used on the header + c = BytesIO() + commentstr = '% ' + np.savetxt(c, a, fmt='%1d', + header=test_header_footer, comments=commentstr) + c.seek(0) + assert_equal(c.read(), + asbytes(commentstr + test_header_footer + '\n' + '1 2\n3 4\n')) + # Test the commentstr keyword argument used on the footer + c = BytesIO() + commentstr = '% ' + np.savetxt(c, a, fmt='%1d', + footer=test_header_footer, comments=commentstr) + c.seek(0) + assert_equal(c.read(), + asbytes('1 2\n3 4\n' + commentstr + test_header_footer + '\n')) + + def test_file_roundtrip(self): + with temppath() as name: + a = np.array([(1, 2), (3, 4)]) + np.savetxt(name, a) + b = np.loadtxt(name) + assert_array_equal(a, b) + + def test_complex_arrays(self): + ncols = 2 + nrows = 2 + a = np.zeros((ncols, nrows), dtype=np.complex128) + re = np.pi + im = np.e + a[:] = re + 1.0j * im + + # One format only + c = BytesIO() + np.savetxt(c, a, fmt=' %+.3e') + c.seek(0) + lines = c.readlines() + assert_equal( + lines, + [b' ( +3.142e+00+ +2.718e+00j) ( +3.142e+00+ +2.718e+00j)\n', + b' ( +3.142e+00+ +2.718e+00j) ( +3.142e+00+ +2.718e+00j)\n']) + + # One format for each real and imaginary part + c = BytesIO() + np.savetxt(c, a, fmt=' %+.3e' * 2 * ncols) + c.seek(0) + lines = c.readlines() + assert_equal( + lines, + [b' +3.142e+00 +2.718e+00 +3.142e+00 +2.718e+00\n', + b' +3.142e+00 +2.718e+00 +3.142e+00 +2.718e+00\n']) + + # One format for each complex number + c = BytesIO() + np.savetxt(c, a, fmt=['(%.3e%+.3ej)'] * ncols) + c.seek(0) + lines = c.readlines() + assert_equal( + lines, + [b'(3.142e+00+2.718e+00j) (3.142e+00+2.718e+00j)\n', + b'(3.142e+00+2.718e+00j) (3.142e+00+2.718e+00j)\n']) + + def test_custom_writer(self): + + class CustomWriter(list): + def write(self, text): + self.extend(text.split(b'\n')) + + w = CustomWriter() + a = np.array([(1, 2), (3, 4)]) + np.savetxt(w, a) + b = np.loadtxt(w) + assert_array_equal(a, b) + + def test_unicode(self): + utf8 = b'\xcf\x96'.decode('UTF-8') + a = np.array([utf8], dtype=np.unicode) + with tempdir() as tmpdir: + # set encoding as on windows it may not be unicode even on py3 + np.savetxt(os.path.join(tmpdir, 'test.csv'), a, fmt=['%s'], + encoding='UTF-8') + + def test_unicode_roundtrip(self): + utf8 = b'\xcf\x96'.decode('UTF-8') + a = np.array([utf8], dtype=np.unicode) + # our gz wrapper support encoding + suffixes = ['', '.gz'] + # stdlib 2 versions do not support encoding + if MAJVER > 2: + if HAS_BZ2: + suffixes.append('.bz2') + if HAS_LZMA: + suffixes.extend(['.xz', '.lzma']) + with tempdir() as tmpdir: + for suffix in suffixes: + np.savetxt(os.path.join(tmpdir, 'test.csv' + suffix), a, + fmt=['%s'], encoding='UTF-16-LE') + b = np.loadtxt(os.path.join(tmpdir, 'test.csv' + suffix), + encoding='UTF-16-LE', dtype=np.unicode) + assert_array_equal(a, b) + + def test_unicode_bytestream(self): + utf8 = b'\xcf\x96'.decode('UTF-8') + a = np.array([utf8], dtype=np.unicode) + s = BytesIO() + np.savetxt(s, a, fmt=['%s'], encoding='UTF-8') + s.seek(0) + assert_equal(s.read().decode('UTF-8'), utf8 + '\n') + + def test_unicode_stringstream(self): + utf8 = b'\xcf\x96'.decode('UTF-8') + a = np.array([utf8], dtype=np.unicode) + s = StringIO() + np.savetxt(s, a, fmt=['%s'], encoding='UTF-8') + s.seek(0) + assert_equal(s.read(), utf8 + '\n') + + +class LoadTxtBase(object): + def check_compressed(self, fopen, suffixes): + # Test that we can load data from a compressed file + wanted = np.arange(6).reshape((2, 3)) + linesep = ('\n', '\r\n', '\r') + for sep in linesep: + data = '0 1 2' + sep + '3 4 5' + for suffix in suffixes: + with temppath(suffix=suffix) as name: + with fopen(name, mode='wt', encoding='UTF-32-LE') as f: + f.write(data) + res = self.loadfunc(name, encoding='UTF-32-LE') + assert_array_equal(res, wanted) + with fopen(name, "rt", encoding='UTF-32-LE') as f: + res = self.loadfunc(f) + assert_array_equal(res, wanted) + + # Python2 .open does not support encoding + @dec.skipif(MAJVER == 2) + def test_compressed_gzip(self): + self.check_compressed(gzip.open, ('.gz',)) + + @dec.skipif(MAJVER == 2 or not HAS_BZ2) + def test_compressed_gzip(self): + self.check_compressed(bz2.open, ('.bz2',)) + + @dec.skipif(MAJVER == 2 or not HAS_LZMA) + def test_compressed_gzip(self): + self.check_compressed(lzma.open, ('.xz', '.lzma')) + + def test_encoding(self): + with temppath() as path: + with open(path, "wb") as f: + f.write('0.\n1.\n2.'.encode("UTF-16")) + x = self.loadfunc(path, encoding="UTF-16") + assert_array_equal(x, [0., 1., 2.]) + + def test_stringload(self): + # umlaute + nonascii = b'\xc3\xb6\xc3\xbc\xc3\xb6'.decode("UTF-8") + with temppath() as path: + with open(path, "wb") as f: + f.write(nonascii.encode("UTF-16")) + x = self.loadfunc(path, encoding="UTF-16", dtype=np.unicode) + assert_array_equal(x, nonascii) + + def test_binary_decode(self): + utf16 = b'\xff\xfeh\x04 \x00i\x04 \x00j\x04' + v = self.loadfunc(BytesIO(utf16), dtype=np.unicode, encoding='UTF-16') + assert_array_equal(v, np.array(utf16.decode('UTF-16').split())) + + def test_converters_decode(self): + # test converters that decode strings + c = TextIO() + c.write(b'\xcf\x96') + c.seek(0) + x = self.loadfunc(c, dtype=np.unicode, + converters={0: lambda x: x.decode('UTF-8')}) + a = np.array([b'\xcf\x96'.decode('UTF-8')]) + assert_array_equal(x, a) + + def test_converters_nodecode(self): + # test native string converters enabled by setting an encoding + utf8 = b'\xcf\x96'.decode('UTF-8') + with temppath() as path: + with io.open(path, 'wt', encoding='UTF-8') as f: + f.write(utf8) + x = self.loadfunc(path, dtype=np.unicode, + converters={0: lambda x: x + 't'}, + encoding='UTF-8') + a = np.array([utf8 + 't']) + assert_array_equal(x, a) + + +class TestLoadTxt(LoadTxtBase): + loadfunc = staticmethod(np.loadtxt) + + def setUp(self): + # lower chunksize for testing + self.orig_chunk = np.lib.npyio._loadtxt_chunksize + np.lib.npyio._loadtxt_chunksize = 1 + def tearDown(self): + np.lib.npyio._loadtxt_chunksize = self.orig_chunk + + def test_record(self): + c = TextIO() + c.write('1 2\n3 4') + c.seek(0) + x = np.loadtxt(c, dtype=[('x', np.int32), ('y', np.int32)]) + a = np.array([(1, 2), (3, 4)], dtype=[('x', 'i4'), ('y', 'i4')]) + assert_array_equal(x, a) + + d = TextIO() + d.write('M 64.0 75.0\nF 25.0 60.0') + d.seek(0) + mydescriptor = {'names': ('gender', 'age', 'weight'), + 'formats': ('S1', 'i4', 'f4')} + b = np.array([('M', 64.0, 75.0), + ('F', 25.0, 60.0)], dtype=mydescriptor) + y = np.loadtxt(d, dtype=mydescriptor) + assert_array_equal(y, b) + + def test_array(self): + c = TextIO() + c.write('1 2\n3 4') + + c.seek(0) + x = np.loadtxt(c, dtype=int) + a = np.array([[1, 2], [3, 4]], int) + assert_array_equal(x, a) + + c.seek(0) + x = np.loadtxt(c, dtype=float) + a = np.array([[1, 2], [3, 4]], float) + assert_array_equal(x, a) + + def test_1D(self): + c = TextIO() + c.write('1\n2\n3\n4\n') + c.seek(0) + x = np.loadtxt(c, dtype=int) + a = np.array([1, 2, 3, 4], int) + assert_array_equal(x, a) + + c = TextIO() + c.write('1,2,3,4\n') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',') + a = np.array([1, 2, 3, 4], int) + assert_array_equal(x, a) + + def test_missing(self): + c = TextIO() + c.write('1,2,3,,5\n') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',', + converters={3: lambda s: int(s or - 999)}) + a = np.array([1, 2, 3, -999, 5], int) + assert_array_equal(x, a) + + def test_converters_with_usecols(self): + c = TextIO() + c.write('1,2,3,,5\n6,7,8,9,10\n') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',', + converters={3: lambda s: int(s or - 999)}, + usecols=(1, 3,)) + a = np.array([[2, -999], [7, 9]], int) + assert_array_equal(x, a) + + def test_comments_unicode(self): + c = TextIO() + c.write('# comment\n1,2,3,5\n') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',', + comments=u'#') + a = np.array([1, 2, 3, 5], int) + assert_array_equal(x, a) + + def test_comments_byte(self): + c = TextIO() + c.write('# comment\n1,2,3,5\n') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',', + comments=b'#') + a = np.array([1, 2, 3, 5], int) + assert_array_equal(x, a) + + def test_comments_multiple(self): + c = TextIO() + c.write('# comment\n1,2,3\n@ comment2\n4,5,6 // comment3') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',', + comments=['#', '@', '//']) + a = np.array([[1, 2, 3], [4, 5, 6]], int) + assert_array_equal(x, a) + + def test_comments_multi_chars(self): + c = TextIO() + c.write('/* comment\n1,2,3,5\n') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',', + comments='/*') + a = np.array([1, 2, 3, 5], int) + assert_array_equal(x, a) + + # Check that '/*' is not transformed to ['/', '*'] + c = TextIO() + c.write('*/ comment\n1,2,3,5\n') + c.seek(0) + assert_raises(ValueError, np.loadtxt, c, dtype=int, delimiter=',', + comments='/*') + + def test_skiprows(self): + c = TextIO() + c.write('comment\n1,2,3,5\n') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',', + skiprows=1) + a = np.array([1, 2, 3, 5], int) + assert_array_equal(x, a) + + c = TextIO() + c.write('# comment\n1,2,3,5\n') + c.seek(0) + x = np.loadtxt(c, dtype=int, delimiter=',', + skiprows=1) + a = np.array([1, 2, 3, 5], int) + assert_array_equal(x, a) + + def test_usecols(self): + a = np.array([[1, 2], [3, 4]], float) + c = BytesIO() + np.savetxt(c, a) + c.seek(0) + x = np.loadtxt(c, dtype=float, usecols=(1,)) + assert_array_equal(x, a[:, 1]) + + a = np.array([[1, 2, 3], [3, 4, 5]], float) + c = BytesIO() + np.savetxt(c, a) + c.seek(0) + x = np.loadtxt(c, dtype=float, usecols=(1, 2)) + assert_array_equal(x, a[:, 1:]) + + # Testing with arrays instead of tuples. + c.seek(0) + x = np.loadtxt(c, dtype=float, usecols=np.array([1, 2])) + assert_array_equal(x, a[:, 1:]) + + # Testing with an integer instead of a sequence + for int_type in [int, np.int8, np.int16, + np.int32, np.int64, np.uint8, np.uint16, + np.uint32, np.uint64]: + to_read = int_type(1) + c.seek(0) + x = np.loadtxt(c, dtype=float, usecols=to_read) + assert_array_equal(x, a[:, 1]) + + # Testing with some crazy custom integer type + class CrazyInt(object): + def __index__(self): + return 1 + + crazy_int = CrazyInt() + c.seek(0) + x = np.loadtxt(c, dtype=float, usecols=crazy_int) + assert_array_equal(x, a[:, 1]) + + c.seek(0) + x = np.loadtxt(c, dtype=float, usecols=(crazy_int,)) + assert_array_equal(x, a[:, 1]) + + # Checking with dtypes defined converters. + data = '''JOE 70.1 25.3 + BOB 60.5 27.9 + ''' + c = TextIO(data) + names = ['stid', 'temp'] + dtypes = ['S4', 'f8'] + arr = np.loadtxt(c, usecols=(0, 2), dtype=list(zip(names, dtypes))) + assert_equal(arr['stid'], [b"JOE", b"BOB"]) + assert_equal(arr['temp'], [25.3, 27.9]) + + # Testing non-ints in usecols + c.seek(0) + bogus_idx = 1.5 + assert_raises_regex( + TypeError, + '^usecols must be.*%s' % type(bogus_idx), + np.loadtxt, c, usecols=bogus_idx + ) + + assert_raises_regex( + TypeError, + '^usecols must be.*%s' % type(bogus_idx), + np.loadtxt, c, usecols=[0, bogus_idx, 0] + ) + + def test_fancy_dtype(self): + c = TextIO() + c.write('1,2,3.0\n4,5,6.0\n') + c.seek(0) + dt = np.dtype([('x', int), ('y', [('t', int), ('s', float)])]) + x = np.loadtxt(c, dtype=dt, delimiter=',') + a = np.array([(1, (2, 3.0)), (4, (5, 6.0))], dt) + assert_array_equal(x, a) + + def test_shaped_dtype(self): + c = TextIO("aaaa 1.0 8.0 1 2 3 4 5 6") + dt = np.dtype([('name', 'S4'), ('x', float), ('y', float), + ('block', int, (2, 3))]) + x = np.loadtxt(c, dtype=dt) + a = np.array([('aaaa', 1.0, 8.0, [[1, 2, 3], [4, 5, 6]])], + dtype=dt) + assert_array_equal(x, a) + + def test_3d_shaped_dtype(self): + c = TextIO("aaaa 1.0 8.0 1 2 3 4 5 6 7 8 9 10 11 12") + dt = np.dtype([('name', 'S4'), ('x', float), ('y', float), + ('block', int, (2, 2, 3))]) + x = np.loadtxt(c, dtype=dt) + a = np.array([('aaaa', 1.0, 8.0, + [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])], + dtype=dt) + assert_array_equal(x, a) + + def test_str_dtype(self): + # see gh-8033 + c = ["str1", "str2"] + + for dt in (str, np.bytes_): + a = np.array(["str1", "str2"], dtype=dt) + x = np.loadtxt(c, dtype=dt) + assert_array_equal(x, a) + + def test_empty_file(self): + with suppress_warnings() as sup: + sup.filter(message="loadtxt: Empty input file:") + c = TextIO() + x = np.loadtxt(c) + assert_equal(x.shape, (0,)) + x = np.loadtxt(c, dtype=np.int64) + assert_equal(x.shape, (0,)) + assert_(x.dtype == np.int64) + + def test_unused_converter(self): + c = TextIO() + c.writelines(['1 21\n', '3 42\n']) + c.seek(0) + data = np.loadtxt(c, usecols=(1,), + converters={0: lambda s: int(s, 16)}) + assert_array_equal(data, [21, 42]) + + c.seek(0) + data = np.loadtxt(c, usecols=(1,), + converters={1: lambda s: int(s, 16)}) + assert_array_equal(data, [33, 66]) + + def test_dtype_with_object(self): + # Test using an explicit dtype with an object + data = """ 1; 2001-01-01 + 2; 2002-01-31 """ + ndtype = [('idx', int), ('code', object)] + func = lambda s: strptime(s.strip(), "%Y-%m-%d") + converters = {1: func} + test = np.loadtxt(TextIO(data), delimiter=";", dtype=ndtype, + converters=converters) + control = np.array( + [(1, datetime(2001, 1, 1)), (2, datetime(2002, 1, 31))], + dtype=ndtype) + assert_equal(test, control) + + def test_uint64_type(self): + tgt = (9223372043271415339, 9223372043271415853) + c = TextIO() + c.write("%s %s" % tgt) + c.seek(0) + res = np.loadtxt(c, dtype=np.uint64) + assert_equal(res, tgt) + + def test_int64_type(self): + tgt = (-9223372036854775807, 9223372036854775807) + c = TextIO() + c.write("%s %s" % tgt) + c.seek(0) + res = np.loadtxt(c, dtype=np.int64) + assert_equal(res, tgt) + + def test_from_float_hex(self): + # IEEE doubles and floats only, otherwise the float32 + # conversion may fail. + tgt = np.logspace(-10, 10, 5).astype(np.float32) + tgt = np.hstack((tgt, -tgt)).astype(float) + inp = '\n'.join(map(float.hex, tgt)) + c = TextIO() + c.write(inp) + for dt in [float, np.float32]: + c.seek(0) + res = np.loadtxt(c, dtype=dt) + assert_equal(res, tgt, err_msg="%s" % dt) + + def test_from_complex(self): + tgt = (complex(1, 1), complex(1, -1)) + c = TextIO() + c.write("%s %s" % tgt) + c.seek(0) + res = np.loadtxt(c, dtype=complex) + assert_equal(res, tgt) + + def test_universal_newline(self): + with temppath() as name: + with open(name, 'w') as f: + f.write('1 21\r3 42\r') + data = np.loadtxt(name) + assert_array_equal(data, [[1, 21], [3, 42]]) + + def test_empty_field_after_tab(self): + c = TextIO() + c.write('1 \t2 \t3\tstart \n4\t5\t6\t \n7\t8\t9.5\t') + c.seek(0) + dt = {'names': ('x', 'y', 'z', 'comment'), + 'formats': (' unicode upcast + utf8 = u'\u03d6' + latin1 = u'\xf6\xfc\xf6' + + # skip test if cannot encode utf8 test string with preferred + # encoding. The preferred encoding is assumed to be the default + # encoding of io.open. Will need to change this for PyTest, maybe + # using pytest.mark.xfail(raises=***). + try: + import locale + encoding = locale.getpreferredencoding() + utf8.encode(encoding) + except (UnicodeError, ImportError): + raise SkipTest('Skipping test_utf8_file_nodtype_unicode, ' + 'unable to encode utf8 in preferred encoding') + + with temppath() as path: + with io.open(path, "wt") as f: + f.write(u"norm1,norm2,norm3\n") + f.write(u"norm1," + latin1 + u",norm3\n") + f.write(u"test1,testNonethe" + utf8 + u",test3\n") + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', + np.VisibleDeprecationWarning) + test = np.genfromtxt(path, dtype=None, comments=None, + delimiter=',') + # Check for warning when encoding not specified. + assert_(w[0].category is np.VisibleDeprecationWarning) + ctl = np.array([ + ["norm1", "norm2", "norm3"], + ["norm1", latin1, "norm3"], + ["test1", "testNonethe" + utf8, "test3"]], + dtype=np.unicode) + assert_array_equal(test, ctl) + + def test_recfromtxt(self): + # + data = TextIO('A,B\n0,1\n2,3') + kwargs = dict(delimiter=",", missing_values="N/A", names=True) + test = np.recfromtxt(data, **kwargs) + control = np.array([(0, 1), (2, 3)], + dtype=[('A', int), ('B', int)]) + assert_(isinstance(test, np.recarray)) + assert_equal(test, control) + # + data = TextIO('A,B\n0,1\n2,N/A') + test = np.recfromtxt(data, dtype=None, usemask=True, **kwargs) + control = ma.array([(0, 1), (2, -1)], + mask=[(False, False), (False, True)], + dtype=[('A', int), ('B', int)]) + assert_equal(test, control) + assert_equal(test.mask, control.mask) + assert_equal(test.A, [0, 2]) + + def test_recfromcsv(self): + # + data = TextIO('A,B\n0,1\n2,3') + kwargs = dict(missing_values="N/A", names=True, case_sensitive=True) + test = np.recfromcsv(data, dtype=None, **kwargs) + control = np.array([(0, 1), (2, 3)], + dtype=[('A', int), ('B', int)]) + assert_(isinstance(test, np.recarray)) + assert_equal(test, control) + # + data = TextIO('A,B\n0,1\n2,N/A') + test = np.recfromcsv(data, dtype=None, usemask=True, **kwargs) + control = ma.array([(0, 1), (2, -1)], + mask=[(False, False), (False, True)], + dtype=[('A', int), ('B', int)]) + assert_equal(test, control) + assert_equal(test.mask, control.mask) + assert_equal(test.A, [0, 2]) + # + data = TextIO('A,B\n0,1\n2,3') + test = np.recfromcsv(data, missing_values='N/A',) + control = np.array([(0, 1), (2, 3)], + dtype=[('a', int), ('b', int)]) + assert_(isinstance(test, np.recarray)) + assert_equal(test, control) + # + data = TextIO('A,B\n0,1\n2,3') + dtype = [('a', int), ('b', float)] + test = np.recfromcsv(data, missing_values='N/A', dtype=dtype) + control = np.array([(0, 1), (2, 3)], + dtype=dtype) + assert_(isinstance(test, np.recarray)) + assert_equal(test, control) + + #gh-10394 + data = TextIO('color\n"red"\n"blue"') + test = np.recfromcsv(data, converters={0: lambda x: x.strip(b'\"')}) + control = np.array([('red',), ('blue',)], dtype=[('color', (bytes, 4))]) + assert_equal(test.dtype, control.dtype) + assert_equal(test, control) + + def test_max_rows(self): + # Test the `max_rows` keyword argument. + data = '1 2\n3 4\n5 6\n7 8\n9 10\n' + txt = TextIO(data) + a1 = np.genfromtxt(txt, max_rows=3) + a2 = np.genfromtxt(txt) + assert_equal(a1, [[1, 2], [3, 4], [5, 6]]) + assert_equal(a2, [[7, 8], [9, 10]]) + + # max_rows must be at least 1. + assert_raises(ValueError, np.genfromtxt, TextIO(data), max_rows=0) + + # An input with several invalid rows. + data = '1 1\n2 2\n0 \n3 3\n4 4\n5 \n6 \n7 \n' + + test = np.genfromtxt(TextIO(data), max_rows=2) + control = np.array([[1., 1.], [2., 2.]]) + assert_equal(test, control) + + # Test keywords conflict + assert_raises(ValueError, np.genfromtxt, TextIO(data), skip_footer=1, + max_rows=4) + + # Test with invalid value + assert_raises(ValueError, np.genfromtxt, TextIO(data), max_rows=4) + + # Test with invalid not raise + with suppress_warnings() as sup: + sup.filter(ConversionWarning) + + test = np.genfromtxt(TextIO(data), max_rows=4, invalid_raise=False) + control = np.array([[1., 1.], [2., 2.], [3., 3.], [4., 4.]]) + assert_equal(test, control) + + test = np.genfromtxt(TextIO(data), max_rows=5, invalid_raise=False) + control = np.array([[1., 1.], [2., 2.], [3., 3.], [4., 4.]]) + assert_equal(test, control) + + # Structured array with field names. + data = 'a b\n#c d\n1 1\n2 2\n#0 \n3 3\n4 4\n5 5\n' + + # Test with header, names and comments + txt = TextIO(data) + test = np.genfromtxt(txt, skip_header=1, max_rows=3, names=True) + control = np.array([(1.0, 1.0), (2.0, 2.0), (3.0, 3.0)], + dtype=[('c', ' should convert to float + # 2**34 = 17179869184 => should convert to int64 + # 2**10 = 1024 => should convert to int (int32 on 32-bit systems, + # int64 on 64-bit systems) + + data = TextIO('73786976294838206464 17179869184 1024') + + test = np.ndfromtxt(data, dtype=None) + + assert_equal(test.dtype.names, ['f0', 'f1', 'f2']) + + assert_(test.dtype['f0'] == float) + assert_(test.dtype['f1'] == np.int64) + assert_(test.dtype['f2'] == np.integer) + + assert_allclose(test['f0'], 73786976294838206464.) + assert_equal(test['f1'], 17179869184) + assert_equal(test['f2'], 1024) + + +class TestPathUsage(object): + # Test that pathlib.Path can be used + @dec.skipif(Path is None, "No pathlib.Path") + def test_loadtxt(self): + with temppath(suffix='.txt') as path: + path = Path(path) + a = np.array([[1.1, 2], [3, 4]]) + np.savetxt(path, a) + x = np.loadtxt(path) + assert_array_equal(x, a) + + @dec.skipif(Path is None, "No pathlib.Path") + def test_save_load(self): + # Test that pathlib.Path instances can be used with savez. + with temppath(suffix='.npy') as path: + path = Path(path) + a = np.array([[1, 2], [3, 4]], int) + np.save(path, a) + data = np.load(path) + assert_array_equal(data, a) + + @dec.skipif(Path is None, "No pathlib.Path") + def test_savez_load(self): + # Test that pathlib.Path instances can be used with savez. + with temppath(suffix='.npz') as path: + path = Path(path) + np.savez(path, lab='place holder') + with np.load(path) as data: + assert_array_equal(data['lab'], 'place holder') + + @dec.skipif(Path is None, "No pathlib.Path") + def test_savez_compressed_load(self): + # Test that pathlib.Path instances can be used with savez. + with temppath(suffix='.npz') as path: + path = Path(path) + np.savez_compressed(path, lab='place holder') + data = np.load(path) + assert_array_equal(data['lab'], 'place holder') + data.close() + + @dec.skipif(Path is None, "No pathlib.Path") + def test_genfromtxt(self): + with temppath(suffix='.txt') as path: + path = Path(path) + a = np.array([(1, 2), (3, 4)]) + np.savetxt(path, a) + data = np.genfromtxt(path) + assert_array_equal(a, data) + + @dec.skipif(Path is None, "No pathlib.Path") + def test_ndfromtxt(self): + # Test outputing a standard ndarray + with temppath(suffix='.txt') as path: + path = Path(path) + with path.open('w') as f: + f.write(u'1 2\n3 4') + + control = np.array([[1, 2], [3, 4]], dtype=int) + test = np.ndfromtxt(path, dtype=int) + assert_array_equal(test, control) + + @dec.skipif(Path is None, "No pathlib.Path") + def test_mafromtxt(self): + # From `test_fancy_dtype_alt` above + with temppath(suffix='.txt') as path: + path = Path(path) + with path.open('w') as f: + f.write(u'1,2,3.0\n4,5,6.0\n') + + test = np.mafromtxt(path, delimiter=',') + control = ma.array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)]) + assert_equal(test, control) + + @dec.skipif(Path is None, "No pathlib.Path") + def test_recfromtxt(self): + with temppath(suffix='.txt') as path: + path = Path(path) + with path.open('w') as f: + f.write(u'A,B\n0,1\n2,3') + + kwargs = dict(delimiter=",", missing_values="N/A", names=True) + test = np.recfromtxt(path, **kwargs) + control = np.array([(0, 1), (2, 3)], + dtype=[('A', int), ('B', int)]) + assert_(isinstance(test, np.recarray)) + assert_equal(test, control) + + @dec.skipif(Path is None, "No pathlib.Path") + def test_recfromcsv(self): + with temppath(suffix='.txt') as path: + path = Path(path) + with path.open('w') as f: + f.write(u'A,B\n0,1\n2,3') + + kwargs = dict(missing_values="N/A", names=True, case_sensitive=True) + test = np.recfromcsv(path, dtype=None, **kwargs) + control = np.array([(0, 1), (2, 3)], + dtype=[('A', int), ('B', int)]) + assert_(isinstance(test, np.recarray)) + assert_equal(test, control) + + +def test_gzip_load(): + a = np.random.random((5, 5)) + + s = BytesIO() + f = gzip.GzipFile(fileobj=s, mode="w") + + np.save(f, a) + f.close() + s.seek(0) + + f = gzip.GzipFile(fileobj=s, mode="r") + assert_array_equal(np.load(f), a) + + +def test_gzip_loadtxt(): + # Thanks to another windows brokeness, we can't use + # NamedTemporaryFile: a file created from this function cannot be + # reopened by another open call. So we first put the gzipped string + # of the test reference array, write it to a securely opened file, + # which is then read from by the loadtxt function + s = BytesIO() + g = gzip.GzipFile(fileobj=s, mode='w') + g.write(b'1 2 3\n') + g.close() + + s.seek(0) + with temppath(suffix='.gz') as name: + with open(name, 'wb') as f: + f.write(s.read()) + res = np.loadtxt(name) + s.close() + + assert_array_equal(res, [1, 2, 3]) + + +def test_gzip_loadtxt_from_string(): + s = BytesIO() + f = gzip.GzipFile(fileobj=s, mode="w") + f.write(b'1 2 3\n') + f.close() + s.seek(0) + + f = gzip.GzipFile(fileobj=s, mode="r") + assert_array_equal(np.loadtxt(f), [1, 2, 3]) + + +def test_npzfile_dict(): + s = BytesIO() + x = np.zeros((3, 3)) + y = np.zeros((3, 3)) + + np.savez(s, x=x, y=y) + s.seek(0) + + z = np.load(s) + + assert_('x' in z) + assert_('y' in z) + assert_('x' in z.keys()) + assert_('y' in z.keys()) + + for f, a in z.items(): + assert_(f in ['x', 'y']) + assert_equal(a.shape, (3, 3)) + + assert_(len(z.items()) == 2) + + for f in z: + assert_(f in ['x', 'y']) + + assert_('x' in z.keys()) + + +def test_load_refcount(): + # Check that objects returned by np.load are directly freed based on + # their refcount, rather than needing the gc to collect them. + + f = BytesIO() + np.savez(f, [1, 2, 3]) + f.seek(0) + + assert_(gc.isenabled()) + gc.disable() + try: + gc.collect() + np.load(f) + # gc.collect returns the number of unreachable objects in cycles that + # were found -- we are checking that no cycles were created by np.load + n_objects_in_cycles = gc.collect() + finally: + gc.enable() + assert_equal(n_objects_in_cycles, 0) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_mixins.py b/numpy/lib/tests/test_mixins.py new file mode 100644 index 0000000..94f06c3 --- /dev/null +++ b/numpy/lib/tests/test_mixins.py @@ -0,0 +1,219 @@ +from __future__ import division, absolute_import, print_function + +import numbers +import operator +import sys + +import numpy as np +from numpy.testing import ( + run_module_suite, 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_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) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_nanfunctions.py b/numpy/lib/tests/test_nanfunctions.py new file mode 100644 index 0000000..3d362fc --- /dev/null +++ b/numpy/lib/tests/test_nanfunctions.py @@ -0,0 +1,892 @@ +from __future__ import division, absolute_import, print_function + +import warnings + +import numpy as np +from numpy.testing import ( + run_module_suite, 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_matrices(self): + # Check that it works and that type and + # shape are preserved + mat = np.matrix(np.eye(3)) + for f in self.nanfuncs: + res = f(mat, axis=0) + assert_(isinstance(res, np.matrix)) + assert_(res.shape == (1, 3)) + res = f(mat, axis=1) + assert_(isinstance(res, np.matrix)) + assert_(res.shape == (3, 1)) + res = f(mat) + assert_(np.isscalar(res)) + # check that rows of nan are dealt with for subclasses (#4628) + mat[1] = np.nan + for f in self.nanfuncs: + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + res = f(mat, axis=0) + assert_(isinstance(res, np.matrix)) + assert_(not np.any(np.isnan(res))) + assert_(len(w) == 0) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + res = f(mat, axis=1) + assert_(isinstance(res, np.matrix)) + assert_(np.isnan(res[1, 0]) and not np.isnan(res[0, 0]) + and not np.isnan(res[2, 0])) + 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(mat) + assert_(np.isscalar(res)) + 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_matrices(self): + # Check that it works and that type and + # shape are preserved + mat = np.matrix(np.eye(3)) + for f in self.nanfuncs: + res = f(mat, axis=0) + assert_(isinstance(res, np.matrix)) + assert_(res.shape == (1, 3)) + res = f(mat, axis=1) + assert_(isinstance(res, np.matrix)) + assert_(res.shape == (3, 1)) + res = f(mat) + assert_(np.isscalar(res)) + + +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_matrices(self): + # Check that it works and that type and + # shape are preserved + mat = np.matrix(np.eye(3)) + for f in self.nanfuncs: + res = f(mat, axis=0) + assert_(isinstance(res, np.matrix)) + assert_(res.shape == (1, 3)) + res = f(mat, axis=1) + assert_(isinstance(res, np.matrix)) + assert_(res.shape == (3, 1)) + res = f(mat) + assert_(np.isscalar(res)) + + +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_matrices(self): + # Check that it works and that type and + # shape are preserved + mat = np.matrix(np.eye(3)) + for f in self.nanfuncs: + for axis in np.arange(2): + res = f(mat, axis=axis) + assert_(isinstance(res, np.matrix)) + assert_(res.shape == (3, 3)) + res = f(mat) + assert_(res.shape == (1, 3*3)) + + 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)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_packbits.py b/numpy/lib/tests/test_packbits.py new file mode 100644 index 0000000..965cbf6 --- /dev/null +++ b/numpy/lib/tests/test_packbits.py @@ -0,0 +1,274 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import ( + assert_array_equal, assert_equal, assert_raises, run_module_suite +) + + +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) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_polynomial.py b/numpy/lib/tests/test_polynomial.py new file mode 100644 index 0000000..9a46508 --- /dev/null +++ b/numpy/lib/tests/test_polynomial.py @@ -0,0 +1,241 @@ +from __future__ import division, absolute_import, print_function + +''' +>>> p = np.poly1d([1.,2,3]) +>>> p +poly1d([ 1., 2., 3.]) +>>> print(p) + 2 +1 x + 2 x + 3 +>>> q = np.poly1d([3.,2,1]) +>>> q +poly1d([ 3., 2., 1.]) +>>> print(q) + 2 +3 x + 2 x + 1 +>>> print(np.poly1d([1.89999+2j, -3j, -5.12345678, 2+1j])) + 3 2 +(1.9 + 2j) x - 3j x - 5.123 x + (2 + 1j) +>>> print(np.poly1d([-3, -2, -1])) + 2 +-3 x - 2 x - 1 + +>>> p(0) +3.0 +>>> p(5) +38.0 +>>> q(0) +1.0 +>>> q(5) +86.0 + +>>> p * q +poly1d([ 3., 8., 14., 8., 3.]) +>>> p / q +(poly1d([ 0.33333333]), poly1d([ 1.33333333, 2.66666667])) +>>> p + q +poly1d([ 4., 4., 4.]) +>>> p - q +poly1d([-2., 0., 2.]) +>>> p ** 4 +poly1d([ 1., 8., 36., 104., 214., 312., 324., 216., 81.]) + +>>> p(q) +poly1d([ 9., 12., 16., 8., 6.]) +>>> q(p) +poly1d([ 3., 12., 32., 40., 34.]) + +>>> np.asarray(p) +array([ 1., 2., 3.]) +>>> len(p) +2 + +>>> p[0], p[1], p[2], p[3] +(3.0, 2.0, 1.0, 0) + +>>> p.integ() +poly1d([ 0.33333333, 1. , 3. , 0. ]) +>>> p.integ(1) +poly1d([ 0.33333333, 1. , 3. , 0. ]) +>>> p.integ(5) +poly1d([ 0.00039683, 0.00277778, 0.025 , 0. , 0. , + 0. , 0. , 0. ]) +>>> p.deriv() +poly1d([ 2., 2.]) +>>> p.deriv(2) +poly1d([ 2.]) + +>>> q = np.poly1d([1.,2,3], variable='y') +>>> print(q) + 2 +1 y + 2 y + 3 +>>> q = np.poly1d([1.,2,3], variable='lambda') +>>> print(q) + 2 +1 lambda + 2 lambda + 3 + +>>> np.polydiv(np.poly1d([1,0,-1]), np.poly1d([1,1])) +(poly1d([ 1., -1.]), poly1d([ 0.])) + +''' +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal, + assert_almost_equal, assert_array_almost_equal, assert_raises, rundocs + ) + + +class TestDocs(object): + def test_doctests(self): + return rundocs() + + 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 Bayesian estimate requires the number of data points to exceed + # degree + 3. + assert_raises(ValueError, np.polyfit, + [0, 1, 3], [0, 1, 3], 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 = [[2.9388, -5.8776, 1.6327], + [-5.8776, 12.7347, -4.2449], + [1.6327, -4.2449, 2.3220]] + 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 = [[8.7929, -10.0103, 0.9756], + [-10.0103, 13.6134, -1.8178], + [0.9756, -1.8178, 0.6674]] + assert_almost_equal(val, cov2, 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) + + 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_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]) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_recfunctions.py b/numpy/lib/tests/test_recfunctions.py new file mode 100644 index 0000000..879cc2b --- /dev/null +++ b/numpy/lib/tests/test_recfunctions.py @@ -0,0 +1,846 @@ +from __future__ import division, absolute_import, print_function + +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 ( + run_module_suite, assert_, assert_raises, dec + ) +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) +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) + + +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) + try: + test = stack_arrays((a, b), autoconvert=False) + except TypeError: + pass + else: + raise AssertionError + + 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) + + @dec.knownfailureif(True) + def test_same_name_different_dtypes_key(self): + a_dtype = np.dtype([('key', 'S5'), ('value', '= 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() + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_shape_base.py b/numpy/lib/tests/test_shape_base.py new file mode 100644 index 0000000..d0afeef --- /dev/null +++ b/numpy/lib/tests/test_shape_base.py @@ -0,0 +1,575 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +import warnings + +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, + ) +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal, assert_raises, + assert_warns + ) + + +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): + # this test is particularly malicious because matrix + # refuses to become 1d + def double(row): + return row * 2 + m = np.matrix([[0, 1], [2, 3]]) + expected = np.matrix([[0, 2], [4, 6]]) + + result = apply_along_axis(double, 0, m) + assert_(isinstance(result, np.matrix)) + assert_array_equal(result, expected) + + result = apply_along_axis(double, 1, m) + assert_(isinstance(result, np.matrix)) + 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 assymmetric 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 assymmetric 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([ + [set([1, 11]), set([2, 22]), set([3, 33])], + [set([4, 44]), set([5, 55]), set([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) + + +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 + + 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) + + +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) + + +# 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): + a = np.ones([2, 2]) + m = np.asmatrix(a) + assert_equal(type(kron(a, a)), np.ndarray) + assert_equal(type(kron(m, m)), np.matrix) + assert_equal(type(kron(a, m)), np.matrix) + assert_equal(type(kron(m, a)), np.matrix) + + class myarray(np.ndarray): + __array_priority__ = 0.0 + + 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]) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_stride_tricks.py b/numpy/lib/tests/test_stride_tricks.py new file mode 100644 index 0000000..0599324 --- /dev/null +++ b/numpy/lib/tests/test_stride_tricks.py @@ -0,0 +1,438 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.core.test_rational import rational +from numpy.testing import ( + run_module_suite, assert_equal, assert_array_equal, + assert_raises, assert_ + ) +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_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) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_twodim_base.py b/numpy/lib/tests/test_twodim_base.py new file mode 100644 index 0000000..8183f7c --- /dev/null +++ b/numpy/lib/tests/test_twodim_base.py @@ -0,0 +1,513 @@ +"""Test functions for matrix module + +""" +from __future__ import division, absolute_import, print_function + +from numpy.testing import ( + run_module_suite, 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]], normed=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_norm(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]], normed=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) + yield assert_array_equal, b, [[1, 0], [1, 1]] + yield assert_array_equal, c, b.T + # should return the same dtype as the original array + yield assert_equal, b.dtype, a.dtype + yield 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) + yield assert_array_equal, a_triu_observed, a_triu_desired + yield assert_array_equal, a_tril_observed, a_tril_desired + yield assert_equal, a_triu_observed.dtype, a.dtype + yield 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: + yield (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) + yield (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]]) + yield (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). + yield (assert_array_equal, v, expected) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_type_check.py b/numpy/lib/tests/test_type_check.py new file mode 100644 index 0000000..8945b61 --- /dev/null +++ b/numpy/lib/tests/test_type_check.py @@ -0,0 +1,432 @@ +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, run_module_suite, 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 = ' 1e10) and assert_all(np.isfinite(vals[2])) + + # 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])) + + def test_integer(self): + vals = nan_to_num(1) + assert_all(vals == 1) + vals = nan_to_num([1]) + assert_array_equal(vals, np.array([1], int)) + + def test_complex_good(self): + vals = nan_to_num(1+1j) + assert_all(vals == 1+1j) + + 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)) + + 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)) + # 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)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_ufunclike.py b/numpy/lib/tests/test_ufunclike.py new file mode 100644 index 0000000..128ce37 --- /dev/null +++ b/numpy/lib/tests/test_ufunclike.py @@ -0,0 +1,96 @@ +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 ( + run_module_suite, assert_, assert_equal, assert_array_equal, assert_warns + ) + + +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) + + 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) + + 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): + obj.metadata = self.metadata + return obj + + 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) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/tests/test_utils.py b/numpy/lib/tests/test_utils.py new file mode 100644 index 0000000..92bcdc2 --- /dev/null +++ b/numpy/lib/tests/test_utils.py @@ -0,0 +1,71 @@ +from __future__ import division, absolute_import, print_function + +import sys +from numpy.core import arange +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_raises_regex, dec + ) +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 + + +@dec.skipif(sys.flags.optimize == 2) +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') + + +def test_byte_bounds(): + a = arange(12).reshape(3, 4) + low, high = utils.byte_bounds(a) + assert_equal(high - low, a.size * a.itemsize) + + +def test_assert_raises_regex_context_manager(): + with assert_raises_regex(ValueError, 'no deprecation warning'): + raise ValueError('no deprecation warning') + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/lib/twodim_base.py b/numpy/lib/twodim_base.py new file mode 100644 index 0000000..402c188 --- /dev/null +++ b/numpy/lib/twodim_base.py @@ -0,0 +1,948 @@ +""" Basic functions for manipulating 2d arrays + +""" +from __future__ import division, absolute_import, print_function + +from numpy.core.numeric import ( + absolute, asanyarray, arange, zeros, greater_equal, multiply, ones, + asarray, where, int8, int16, int32, int64, empty, promote_types, diagonal, + nonzero + ) +from numpy.core import iinfo, transpose + + +__all__ = [ + 'diag', 'diagflat', 'eye', 'fliplr', 'flipud', 'tri', 'triu', + 'tril', 'vander', 'histogram2d', 'mask_indices', 'tril_indices', + 'tril_indices_from', 'triu_indices', 'triu_indices_from', ] + + +i1 = iinfo(int8) +i2 = iinfo(int16) +i4 = iinfo(int32) + + +def _min_int(low, high): + """ get small int that fits the range """ + if high <= i1.max and low >= i1.min: + return int8 + if high <= i2.max and low >= i2.min: + return int16 + if high <= i4.max and low >= i4.min: + return int32 + return int64 + + +def fliplr(m): + """ + Flip array in the left/right direction. + + Flip the entries in each row in the left/right direction. + Columns are preserved, but appear in a different order than before. + + Parameters + ---------- + m : array_like + Input array, must be at least 2-D. + + Returns + ------- + f : ndarray + A view of `m` with the columns reversed. Since a view + is returned, this operation is :math:`\\mathcal O(1)`. + + See Also + -------- + flipud : Flip array in the up/down direction. + rot90 : Rotate array counterclockwise. + + Notes + ----- + Equivalent to m[:,::-1]. Requires the array to be at least 2-D. + + Examples + -------- + >>> A = np.diag([1.,2.,3.]) + >>> A + array([[ 1., 0., 0.], + [ 0., 2., 0.], + [ 0., 0., 3.]]) + >>> np.fliplr(A) + array([[ 0., 0., 1.], + [ 0., 2., 0.], + [ 3., 0., 0.]]) + + >>> A = np.random.randn(2,3,5) + >>> np.all(np.fliplr(A) == A[:,::-1,...]) + True + + """ + m = asanyarray(m) + if m.ndim < 2: + raise ValueError("Input must be >= 2-d.") + return m[:, ::-1] + + +def flipud(m): + """ + Flip array in the up/down direction. + + Flip the entries in each column in the up/down direction. + Rows are preserved, but appear in a different order than before. + + Parameters + ---------- + m : array_like + Input array. + + Returns + ------- + out : array_like + A view of `m` with the rows reversed. Since a view is + returned, this operation is :math:`\\mathcal O(1)`. + + See Also + -------- + fliplr : Flip array in the left/right direction. + rot90 : Rotate array counterclockwise. + + Notes + ----- + Equivalent to ``m[::-1,...]``. + Does not require the array to be two-dimensional. + + Examples + -------- + >>> A = np.diag([1.0, 2, 3]) + >>> A + array([[ 1., 0., 0.], + [ 0., 2., 0.], + [ 0., 0., 3.]]) + >>> np.flipud(A) + array([[ 0., 0., 3.], + [ 0., 2., 0.], + [ 1., 0., 0.]]) + + >>> A = np.random.randn(2,3,5) + >>> np.all(np.flipud(A) == A[::-1,...]) + True + + >>> np.flipud([1,2]) + array([2, 1]) + + """ + m = asanyarray(m) + if m.ndim < 1: + raise ValueError("Input must be >= 1-d.") + return m[::-1, ...] + + +def eye(N, M=None, k=0, dtype=float, order='C'): + """ + Return a 2-D array with ones on the diagonal and zeros elsewhere. + + Parameters + ---------- + N : int + Number of rows in the output. + M : int, optional + Number of columns in the output. If None, defaults to `N`. + k : int, optional + Index of the diagonal: 0 (the default) refers to the main diagonal, + a positive value refers to an upper diagonal, and a negative value + to a lower diagonal. + dtype : data-type, optional + Data-type of the returned array. + order : {'C', 'F'}, optional + Whether the output should be stored in row-major (C-style) or + column-major (Fortran-style) order in memory. + + .. versionadded:: 1.14.0 + + Returns + ------- + I : ndarray of shape (N,M) + An array where all elements are equal to zero, except for the `k`-th + diagonal, whose values are equal to one. + + See Also + -------- + identity : (almost) equivalent function + diag : diagonal 2-D array from a 1-D array specified by the user. + + Examples + -------- + >>> np.eye(2, dtype=int) + array([[1, 0], + [0, 1]]) + >>> np.eye(3, k=1) + array([[ 0., 1., 0.], + [ 0., 0., 1.], + [ 0., 0., 0.]]) + + """ + if M is None: + M = N + m = zeros((N, M), dtype=dtype, order=order) + if k >= M: + return m + if k >= 0: + i = k + else: + i = (-k) * M + m[:M-k].flat[i::M+1] = 1 + return m + + +def diag(v, k=0): + """ + Extract a diagonal or construct a diagonal array. + + See the more detailed documentation for ``numpy.diagonal`` if you use this + function to extract a diagonal and wish to write to the resulting array; + whether it returns a copy or a view depends on what version of numpy you + are using. + + Parameters + ---------- + v : array_like + If `v` is a 2-D array, return a copy of its `k`-th diagonal. + If `v` is a 1-D array, return a 2-D array with `v` on the `k`-th + diagonal. + k : int, optional + Diagonal in question. The default is 0. Use `k>0` for diagonals + above the main diagonal, and `k<0` for diagonals below the main + diagonal. + + Returns + ------- + out : ndarray + The extracted diagonal or constructed diagonal array. + + See Also + -------- + diagonal : Return specified diagonals. + diagflat : Create a 2-D array with the flattened input as a diagonal. + trace : Sum along diagonals. + triu : Upper triangle of an array. + tril : Lower triangle of an array. + + Examples + -------- + >>> x = np.arange(9).reshape((3,3)) + >>> x + array([[0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + + >>> np.diag(x) + array([0, 4, 8]) + >>> np.diag(x, k=1) + array([1, 5]) + >>> np.diag(x, k=-1) + array([3, 7]) + + >>> np.diag(np.diag(x)) + array([[0, 0, 0], + [0, 4, 0], + [0, 0, 8]]) + + """ + v = asanyarray(v) + s = v.shape + if len(s) == 1: + n = s[0]+abs(k) + res = zeros((n, n), v.dtype) + if k >= 0: + i = k + else: + i = (-k) * n + res[:n-k].flat[i::n+1] = v + return res + elif len(s) == 2: + return diagonal(v, k) + else: + raise ValueError("Input must be 1- or 2-d.") + + +def diagflat(v, k=0): + """ + Create a two-dimensional array with the flattened input as a diagonal. + + Parameters + ---------- + v : array_like + Input data, which is flattened and set as the `k`-th + diagonal of the output. + k : int, optional + Diagonal to set; 0, the default, corresponds to the "main" diagonal, + a positive (negative) `k` giving the number of the diagonal above + (below) the main. + + Returns + ------- + out : ndarray + The 2-D output array. + + See Also + -------- + diag : MATLAB work-alike for 1-D and 2-D arrays. + diagonal : Return specified diagonals. + trace : Sum along diagonals. + + Examples + -------- + >>> np.diagflat([[1,2], [3,4]]) + array([[1, 0, 0, 0], + [0, 2, 0, 0], + [0, 0, 3, 0], + [0, 0, 0, 4]]) + + >>> np.diagflat([1,2], 1) + array([[0, 1, 0], + [0, 0, 2], + [0, 0, 0]]) + + """ + try: + wrap = v.__array_wrap__ + except AttributeError: + wrap = None + v = asarray(v).ravel() + s = len(v) + n = s + abs(k) + res = zeros((n, n), v.dtype) + if (k >= 0): + i = arange(0, n-k) + fi = i+k+i*n + else: + i = arange(0, n+k) + fi = i+(i-k)*n + res.flat[fi] = v + if not wrap: + return res + return wrap(res) + + +def tri(N, M=None, k=0, dtype=float): + """ + An array with ones at and below the given diagonal and zeros elsewhere. + + Parameters + ---------- + N : int + Number of rows in the array. + M : int, optional + Number of columns in the array. + By default, `M` is taken equal to `N`. + k : int, optional + The sub-diagonal at and below which the array is filled. + `k` = 0 is the main diagonal, while `k` < 0 is below it, + and `k` > 0 is above. The default is 0. + dtype : dtype, optional + Data type of the returned array. The default is float. + + Returns + ------- + tri : ndarray of shape (N, M) + Array with its lower triangle filled with ones and zero elsewhere; + in other words ``T[i,j] == 1`` for ``i <= j + k``, 0 otherwise. + + Examples + -------- + >>> np.tri(3, 5, 2, dtype=int) + array([[1, 1, 1, 0, 0], + [1, 1, 1, 1, 0], + [1, 1, 1, 1, 1]]) + + >>> np.tri(3, 5, -1) + array([[ 0., 0., 0., 0., 0.], + [ 1., 0., 0., 0., 0.], + [ 1., 1., 0., 0., 0.]]) + + """ + if M is None: + M = N + + m = greater_equal.outer(arange(N, dtype=_min_int(0, N)), + arange(-k, M-k, dtype=_min_int(-k, M - k))) + + # Avoid making a copy if the requested type is already bool + m = m.astype(dtype, copy=False) + + return m + + +def tril(m, k=0): + """ + Lower triangle of an array. + + Return a copy of an array with elements above the `k`-th diagonal zeroed. + + Parameters + ---------- + m : array_like, shape (M, N) + Input array. + k : int, optional + Diagonal above which to zero elements. `k = 0` (the default) is the + main diagonal, `k < 0` is below it and `k > 0` is above. + + Returns + ------- + tril : ndarray, shape (M, N) + Lower triangle of `m`, of same shape and data-type as `m`. + + See Also + -------- + triu : same thing, only for the upper triangle + + Examples + -------- + >>> np.tril([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], -1) + array([[ 0, 0, 0], + [ 4, 0, 0], + [ 7, 8, 0], + [10, 11, 12]]) + + """ + m = asanyarray(m) + mask = tri(*m.shape[-2:], k=k, dtype=bool) + + return where(mask, m, zeros(1, m.dtype)) + + +def triu(m, k=0): + """ + Upper triangle of an array. + + Return a copy of a matrix with the elements below the `k`-th diagonal + zeroed. + + Please refer to the documentation for `tril` for further details. + + See Also + -------- + tril : lower triangle of an array + + Examples + -------- + >>> np.triu([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], -1) + array([[ 1, 2, 3], + [ 4, 5, 6], + [ 0, 8, 9], + [ 0, 0, 12]]) + + """ + m = asanyarray(m) + mask = tri(*m.shape[-2:], k=k-1, dtype=bool) + + return where(mask, zeros(1, m.dtype), m) + + +# Originally borrowed from John Hunter and matplotlib +def vander(x, N=None, increasing=False): + """ + Generate a Vandermonde matrix. + + The columns of the output matrix are powers of the input vector. The + order of the powers is determined by the `increasing` boolean argument. + Specifically, when `increasing` is False, the `i`-th output column is + the input vector raised element-wise to the power of ``N - i - 1``. Such + a matrix with a geometric progression in each row is named for Alexandre- + Theophile Vandermonde. + + Parameters + ---------- + x : array_like + 1-D input array. + N : int, optional + Number of columns in the output. If `N` is not specified, a square + array is returned (``N = len(x)``). + increasing : bool, optional + Order of the powers of the columns. If True, the powers increase + from left to right, if False (the default) they are reversed. + + .. versionadded:: 1.9.0 + + Returns + ------- + out : ndarray + Vandermonde matrix. If `increasing` is False, the first column is + ``x^(N-1)``, the second ``x^(N-2)`` and so forth. If `increasing` is + True, the columns are ``x^0, x^1, ..., x^(N-1)``. + + See Also + -------- + polynomial.polynomial.polyvander + + Examples + -------- + >>> x = np.array([1, 2, 3, 5]) + >>> N = 3 + >>> np.vander(x, N) + array([[ 1, 1, 1], + [ 4, 2, 1], + [ 9, 3, 1], + [25, 5, 1]]) + + >>> np.column_stack([x**(N-1-i) for i in range(N)]) + array([[ 1, 1, 1], + [ 4, 2, 1], + [ 9, 3, 1], + [25, 5, 1]]) + + >>> x = np.array([1, 2, 3, 5]) + >>> np.vander(x) + array([[ 1, 1, 1, 1], + [ 8, 4, 2, 1], + [ 27, 9, 3, 1], + [125, 25, 5, 1]]) + >>> np.vander(x, increasing=True) + array([[ 1, 1, 1, 1], + [ 1, 2, 4, 8], + [ 1, 3, 9, 27], + [ 1, 5, 25, 125]]) + + The determinant of a square Vandermonde matrix is the product + of the differences between the values of the input vector: + + >>> np.linalg.det(np.vander(x)) + 48.000000000000043 + >>> (5-3)*(5-2)*(5-1)*(3-2)*(3-1)*(2-1) + 48 + + """ + x = asarray(x) + if x.ndim != 1: + raise ValueError("x must be a one-dimensional array or sequence.") + if N is None: + N = len(x) + + v = empty((len(x), N), dtype=promote_types(x.dtype, int)) + tmp = v[:, ::-1] if not increasing else v + + if N > 0: + tmp[:, 0] = 1 + if N > 1: + tmp[:, 1:] = x[:, None] + multiply.accumulate(tmp[:, 1:], out=tmp[:, 1:], axis=1) + + return v + + +def histogram2d(x, y, bins=10, range=None, normed=False, weights=None): + """ + Compute the bi-dimensional histogram of two data samples. + + Parameters + ---------- + x : array_like, shape (N,) + An array containing the x coordinates of the points to be + histogrammed. + y : array_like, shape (N,) + An array containing the y coordinates of the points to be + histogrammed. + bins : int or array_like or [int, int] or [array, array], optional + The bin specification: + + * If int, the number of bins for the two dimensions (nx=ny=bins). + * If array_like, the bin edges for the two dimensions + (x_edges=y_edges=bins). + * If [int, int], the number of bins in each dimension + (nx, ny = bins). + * If [array, array], the bin edges in each dimension + (x_edges, y_edges = bins). + * A combination [int, array] or [array, int], where int + is the number of bins and array is the bin edges. + + range : array_like, shape(2,2), optional + The leftmost and rightmost edges of the bins along each dimension + (if not specified explicitly in the `bins` parameters): + ``[[xmin, xmax], [ymin, ymax]]``. All values outside of this range + will be considered outliers and not tallied in the histogram. + normed : bool, optional + If False, returns the number of samples in each bin. If True, + returns the bin density ``bin_count / sample_count / bin_area``. + weights : array_like, shape(N,), optional + An array of values ``w_i`` weighing each sample ``(x_i, y_i)``. + Weights are normalized to 1 if `normed` is True. If `normed` is + False, the values of the returned histogram are equal to the sum of + the weights belonging to the samples falling into each bin. + + Returns + ------- + H : ndarray, shape(nx, ny) + The bi-dimensional histogram of samples `x` and `y`. Values in `x` + are histogrammed along the first dimension and values in `y` are + histogrammed along the second dimension. + xedges : ndarray, shape(nx+1,) + The bin edges along the first dimension. + yedges : ndarray, shape(ny+1,) + The bin edges along the second dimension. + + See Also + -------- + histogram : 1D histogram + histogramdd : Multidimensional histogram + + Notes + ----- + When `normed` is True, then the returned histogram is the sample + density, defined such that the sum over bins of the product + ``bin_value * bin_area`` is 1. + + Please note that the histogram does not follow the Cartesian convention + where `x` values are on the abscissa and `y` values on the ordinate + axis. Rather, `x` is histogrammed along the first dimension of the + array (vertical), and `y` along the second dimension of the array + (horizontal). This ensures compatibility with `histogramdd`. + + Examples + -------- + >>> import matplotlib as mpl + >>> import matplotlib.pyplot as plt + + Construct a 2-D histogram with variable bin width. First define the bin + edges: + + >>> xedges = [0, 1, 3, 5] + >>> yedges = [0, 2, 3, 4, 6] + + Next we create a histogram H with random bin content: + + >>> x = np.random.normal(2, 1, 100) + >>> y = np.random.normal(1, 1, 100) + >>> H, xedges, yedges = np.histogram2d(x, y, bins=(xedges, yedges)) + >>> H = H.T # Let each row list bins with common y range. + + :func:`imshow ` can only display square bins: + + >>> fig = plt.figure(figsize=(7, 3)) + >>> ax = fig.add_subplot(131, title='imshow: square bins') + >>> plt.imshow(H, interpolation='nearest', origin='low', + ... extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]]) + + :func:`pcolormesh ` can display actual edges: + + >>> ax = fig.add_subplot(132, title='pcolormesh: actual edges', + ... aspect='equal') + >>> X, Y = np.meshgrid(xedges, yedges) + >>> ax.pcolormesh(X, Y, H) + + :class:`NonUniformImage ` can be used to + display actual bin edges with interpolation: + + >>> ax = fig.add_subplot(133, title='NonUniformImage: interpolated', + ... aspect='equal', xlim=xedges[[0, -1]], ylim=yedges[[0, -1]]) + >>> im = mpl.image.NonUniformImage(ax, interpolation='bilinear') + >>> xcenters = (xedges[:-1] + xedges[1:]) / 2 + >>> ycenters = (yedges[:-1] + yedges[1:]) / 2 + >>> im.set_data(xcenters, ycenters, H) + >>> ax.images.append(im) + >>> plt.show() + + """ + from numpy import histogramdd + + try: + N = len(bins) + except TypeError: + N = 1 + + if N != 1 and N != 2: + xedges = yedges = asarray(bins, float) + bins = [xedges, yedges] + hist, edges = histogramdd([x, y], bins, range, normed, weights) + return hist, edges[0], edges[1] + + +def mask_indices(n, mask_func, k=0): + """ + Return the indices to access (n, n) arrays, given a masking function. + + Assume `mask_func` is a function that, for a square array a of size + ``(n, n)`` with a possible offset argument `k`, when called as + ``mask_func(a, k)`` returns a new array with zeros in certain locations + (functions like `triu` or `tril` do precisely this). Then this function + returns the indices where the non-zero values would be located. + + Parameters + ---------- + n : int + The returned indices will be valid to access arrays of shape (n, n). + mask_func : callable + A function whose call signature is similar to that of `triu`, `tril`. + That is, ``mask_func(x, k)`` returns a boolean array, shaped like `x`. + `k` is an optional argument to the function. + k : scalar + An optional argument which is passed through to `mask_func`. Functions + like `triu`, `tril` take a second argument that is interpreted as an + offset. + + Returns + ------- + indices : tuple of arrays. + The `n` arrays of indices corresponding to the locations where + ``mask_func(np.ones((n, n)), k)`` is True. + + See Also + -------- + triu, tril, triu_indices, tril_indices + + Notes + ----- + .. versionadded:: 1.4.0 + + Examples + -------- + These are the indices that would allow you to access the upper triangular + part of any 3x3 array: + + >>> iu = np.mask_indices(3, np.triu) + + For example, if `a` is a 3x3 array: + + >>> a = np.arange(9).reshape(3, 3) + >>> a + array([[0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> a[iu] + array([0, 1, 2, 4, 5, 8]) + + An offset can be passed also to the masking function. This gets us the + indices starting on the first diagonal right of the main one: + + >>> iu1 = np.mask_indices(3, np.triu, 1) + + with which we now extract only three elements: + + >>> a[iu1] + array([1, 2, 5]) + + """ + m = ones((n, n), int) + a = mask_func(m, k) + return nonzero(a != 0) + + +def tril_indices(n, k=0, m=None): + """ + Return the indices for the lower-triangle of an (n, m) array. + + Parameters + ---------- + n : int + The row dimension of the arrays for which the returned + indices will be valid. + k : int, optional + Diagonal offset (see `tril` for details). + m : int, optional + .. versionadded:: 1.9.0 + + The column dimension of the arrays for which the returned + arrays will be valid. + By default `m` is taken equal to `n`. + + + Returns + ------- + inds : tuple of arrays + The indices for the triangle. The returned tuple contains two arrays, + each with the indices along one dimension of the array. + + See also + -------- + triu_indices : similar function, for upper-triangular. + mask_indices : generic function accepting an arbitrary mask function. + tril, triu + + Notes + ----- + .. versionadded:: 1.4.0 + + Examples + -------- + Compute two different sets of indices to access 4x4 arrays, one for the + lower triangular part starting at the main diagonal, and one starting two + diagonals further right: + + >>> il1 = np.tril_indices(4) + >>> il2 = np.tril_indices(4, 2) + + Here is how they can be used with a sample array: + + >>> 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]]) + + Both for indexing: + + >>> a[il1] + array([ 0, 4, 5, 8, 9, 10, 12, 13, 14, 15]) + + And for assigning values: + + >>> a[il1] = -1 + >>> a + array([[-1, 1, 2, 3], + [-1, -1, 6, 7], + [-1, -1, -1, 11], + [-1, -1, -1, -1]]) + + These cover almost the whole array (two diagonals right of the main one): + + >>> a[il2] = -10 + >>> a + array([[-10, -10, -10, 3], + [-10, -10, -10, -10], + [-10, -10, -10, -10], + [-10, -10, -10, -10]]) + + """ + return nonzero(tri(n, m, k=k, dtype=bool)) + + +def tril_indices_from(arr, k=0): + """ + Return the indices for the lower-triangle of arr. + + See `tril_indices` for full details. + + Parameters + ---------- + arr : array_like + The indices will be valid for square arrays whose dimensions are + the same as arr. + k : int, optional + Diagonal offset (see `tril` for details). + + See Also + -------- + tril_indices, tril + + Notes + ----- + .. versionadded:: 1.4.0 + + """ + if arr.ndim != 2: + raise ValueError("input array must be 2-d") + return tril_indices(arr.shape[-2], k=k, m=arr.shape[-1]) + + +def triu_indices(n, k=0, m=None): + """ + Return the indices for the upper-triangle of an (n, m) array. + + Parameters + ---------- + n : int + The size of the arrays for which the returned indices will + be valid. + k : int, optional + Diagonal offset (see `triu` for details). + m : int, optional + .. versionadded:: 1.9.0 + + The column dimension of the arrays for which the returned + arrays will be valid. + By default `m` is taken equal to `n`. + + + Returns + ------- + inds : tuple, shape(2) of ndarrays, shape(`n`) + The indices for the triangle. The returned tuple contains two arrays, + each with the indices along one dimension of the array. Can be used + to slice a ndarray of shape(`n`, `n`). + + See also + -------- + tril_indices : similar function, for lower-triangular. + mask_indices : generic function accepting an arbitrary mask function. + triu, tril + + Notes + ----- + .. versionadded:: 1.4.0 + + Examples + -------- + Compute two different sets of indices to access 4x4 arrays, one for the + upper triangular part starting at the main diagonal, and one starting two + diagonals further right: + + >>> iu1 = np.triu_indices(4) + >>> iu2 = np.triu_indices(4, 2) + + Here is how they can be used with a sample array: + + >>> 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]]) + + Both for indexing: + + >>> a[iu1] + array([ 0, 1, 2, 3, 5, 6, 7, 10, 11, 15]) + + And for assigning values: + + >>> a[iu1] = -1 + >>> a + array([[-1, -1, -1, -1], + [ 4, -1, -1, -1], + [ 8, 9, -1, -1], + [12, 13, 14, -1]]) + + These cover only a small part of the whole array (two diagonals right + of the main one): + + >>> a[iu2] = -10 + >>> a + array([[ -1, -1, -10, -10], + [ 4, -1, -1, -10], + [ 8, 9, -1, -1], + [ 12, 13, 14, -1]]) + + """ + return nonzero(~tri(n, m, k=k-1, dtype=bool)) + + +def triu_indices_from(arr, k=0): + """ + Return the indices for the upper-triangle of arr. + + See `triu_indices` for full details. + + Parameters + ---------- + arr : ndarray, shape(N, N) + The indices will be valid for square arrays. + k : int, optional + Diagonal offset (see `triu` for details). + + Returns + ------- + triu_indices_from : tuple, shape(2) of ndarray, shape(N) + Indices for the upper-triangle of `arr`. + + See Also + -------- + triu_indices, triu + + Notes + ----- + .. versionadded:: 1.4.0 + + """ + if arr.ndim != 2: + raise ValueError("input array must be 2-d") + return triu_indices(arr.shape[-2], k=k, m=arr.shape[-1]) diff --git a/numpy/lib/type_check.py b/numpy/lib/type_check.py new file mode 100644 index 0000000..5c7528d --- /dev/null +++ b/numpy/lib/type_check.py @@ -0,0 +1,625 @@ +"""Automatically adapted for numpy Sep 19, 2005 by convertcode.py + +""" +from __future__ import division, absolute_import, print_function + +__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, array, isnan, zeros +from .ufunclike import isneginf, isposinf + +_typecodes_by_elsize = 'GDFgdfQqLlIiHhBb?' + +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 = [] + for t in intersection: + i = _typecodes_by_elsize.index(t) + l.append((i, t)) + l.sort() + return l[0][1] + +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(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(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 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 # convet to array-scalar if needed + +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 + +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) + + +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(x, copy=True): + """ + Replace nan with zero and inf 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 : 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 + -------- + >>> 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 + if not issubclass(xtype, _nx.inexact): + return x + + iscomplex = issubclass(xtype, _nx.complexfloating) + isscalar = (x.ndim == 0) + + x = x[None] if isscalar else x + 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[0] if isscalar else x + +#----------------------------------------------------------------------------- + +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(a): + """ + Convert an array of size 1 to its scalar equivalent. + + 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 + + """ + 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' + } + +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(*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)) + + >>> np.common_type(np.arange(2, dtype=np.float32), np.arange(2)) + + >>> np.common_type(np.arange(4), np.array([45, 6.j]), np.array([45.0])) + + + """ + 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] diff --git a/numpy/lib/ufunclike.py b/numpy/lib/ufunclike.py new file mode 100644 index 0000000..e0bd951 --- /dev/null +++ b/numpy/lib/ufunclike.py @@ -0,0 +1,202 @@ +""" +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 +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 + + +@_deprecate_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 + +@_deprecate_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, or if first and second arguments have different shapes. + + 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]) + + """ + return nx.logical_and(nx.isinf(x), ~nx.signbit(x), out) + + +@_deprecate_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, or if first and second arguments have different shapes. + + 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]) + + """ + return nx.logical_and(nx.isinf(x), nx.signbit(x), out) diff --git a/numpy/lib/user_array.py b/numpy/lib/user_array.py new file mode 100644 index 0000000..f1510a7 --- /dev/null +++ b/numpy/lib/user_array.py @@ -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)) diff --git a/numpy/lib/utils.py b/numpy/lib/utils.py new file mode 100644 index 0000000..e18eda0 --- /dev/null +++ b/numpy/lib/utils.py @@ -0,0 +1,1162 @@ +from __future__ import division, absolute_import, print_function + +import os +import sys +import types +import re +import warnings + +from numpy.core.numerictypes import issubclass_, issubsctype, issubdtype +from numpy.core import ndarray, ufunc, asarray +import numpy as np + +# getargspec and formatargspec were removed in Python 3.6 +from numpy.compat import getargspec, formatargspec + +__all__ = [ + 'issubclass_', 'issubsctype', 'issubdtype', 'deprecate', + 'deprecate_with_doc', 'get_include', 'info', 'source', 'who', + 'lookfor', 'byte_bounds', 'safe_eval' + ] + +def get_include(): + """ + Return the directory that contains the NumPy \\*.h header files. + + Extension modules that need to compile against NumPy should use this + function to locate the appropriate include directory. + + Notes + ----- + When using ``distutils``, for example in ``setup.py``. + :: + + import numpy as np + ... + Extension('extension_name', ... + include_dirs=[np.get_include()]) + ... + + """ + import numpy + if numpy.show_config is None: + # running from numpy source directory + d = os.path.join(os.path.dirname(numpy.__file__), 'core', 'include') + else: + # using installed numpy core headers + import numpy.core as core + d = os.path.join(os.path.dirname(core.__file__), 'include') + return d + + +def _set_function_name(func, name): + func.__name__ = name + return func + + +class _Deprecate(object): + """ + Decorator class to deprecate old functions. + + Refer to `deprecate` for details. + + See Also + -------- + deprecate + + """ + + def __init__(self, old_name=None, new_name=None, message=None): + self.old_name = old_name + self.new_name = new_name + self.message = message + + def __call__(self, func, *args, **kwargs): + """ + Decorator call. Refer to ``decorate``. + + """ + old_name = self.old_name + new_name = self.new_name + message = self.message + + import warnings + if old_name is None: + try: + old_name = func.__name__ + except AttributeError: + old_name = func.__name__ + if new_name is None: + depdoc = "`%s` is deprecated!" % old_name + else: + depdoc = "`%s` is deprecated, use `%s` instead!" % \ + (old_name, new_name) + + if message is not None: + depdoc += "\n" + message + + def newfunc(*args,**kwds): + """`arrayrange` is deprecated, use `arange` instead!""" + warnings.warn(depdoc, DeprecationWarning, stacklevel=2) + return func(*args, **kwds) + + newfunc = _set_function_name(newfunc, old_name) + doc = func.__doc__ + if doc is None: + doc = depdoc + else: + doc = '\n\n'.join([depdoc, doc]) + newfunc.__doc__ = doc + try: + d = func.__dict__ + except AttributeError: + pass + else: + newfunc.__dict__.update(d) + return newfunc + +def deprecate(*args, **kwargs): + """ + Issues a DeprecationWarning, adds warning to `old_name`'s + docstring, rebinds ``old_name.__name__`` and returns the new + function object. + + This function may also be used as a decorator. + + Parameters + ---------- + func : function + The function to be deprecated. + old_name : str, optional + The name of the function to be deprecated. Default is None, in + which case the name of `func` is used. + new_name : str, optional + The new name for the function. Default is None, in which case the + deprecation message is that `old_name` is deprecated. If given, the + deprecation message is that `old_name` is deprecated and `new_name` + should be used instead. + message : str, optional + Additional explanation of the deprecation. Displayed in the + docstring after the warning. + + Returns + ------- + old_func : function + The deprecated function. + + Examples + -------- + Note that ``olduint`` returns a value after printing Deprecation + Warning: + + >>> olduint = np.deprecate(np.uint) + >>> olduint(6) + /usr/lib/python2.5/site-packages/numpy/lib/utils.py:114: + DeprecationWarning: uint32 is deprecated + warnings.warn(str1, DeprecationWarning, stacklevel=2) + 6 + + """ + # Deprecate may be run as a function or as a decorator + # If run as a function, we initialise the decorator class + # and execute its __call__ method. + + if args: + fn = args[0] + args = args[1:] + + # backward compatibility -- can be removed + # after next release + if 'newname' in kwargs: + kwargs['new_name'] = kwargs.pop('newname') + if 'oldname' in kwargs: + kwargs['old_name'] = kwargs.pop('oldname') + + return _Deprecate(*args, **kwargs)(fn) + else: + return _Deprecate(*args, **kwargs) + +deprecate_with_doc = lambda msg: _Deprecate(message=msg) + + +#-------------------------------------------- +# Determine if two arrays can share memory +#-------------------------------------------- + +def byte_bounds(a): + """ + Returns pointers to the end-points of an array. + + Parameters + ---------- + a : ndarray + Input array. It must conform to the Python-side of the array + interface. + + Returns + ------- + (low, high) : tuple of 2 integers + The first integer is the first byte of the array, the second + integer is just past the last byte of the array. If `a` is not + contiguous it will not use every byte between the (`low`, `high`) + values. + + Examples + -------- + >>> I = np.eye(2, dtype='f'); I.dtype + dtype('float32') + >>> low, high = np.byte_bounds(I) + >>> high - low == I.size*I.itemsize + True + >>> I = np.eye(2, dtype='G'); I.dtype + dtype('complex192') + >>> low, high = np.byte_bounds(I) + >>> high - low == I.size*I.itemsize + True + + """ + ai = a.__array_interface__ + a_data = ai['data'][0] + astrides = ai['strides'] + ashape = ai['shape'] + bytes_a = asarray(a).dtype.itemsize + + a_low = a_high = a_data + if astrides is None: + # contiguous case + a_high += a.size * bytes_a + else: + for shape, stride in zip(ashape, astrides): + if stride < 0: + a_low += (shape-1)*stride + else: + a_high += (shape-1)*stride + a_high += bytes_a + return a_low, a_high + + +#----------------------------------------------------------------------------- +# Function for output and information on the variables used. +#----------------------------------------------------------------------------- + + +def who(vardict=None): + """ + Print the NumPy arrays in the given dictionary. + + If there is no dictionary passed in or `vardict` is None then returns + NumPy arrays in the globals() dictionary (all NumPy arrays in the + namespace). + + Parameters + ---------- + vardict : dict, optional + A dictionary possibly containing ndarrays. Default is globals(). + + Returns + ------- + out : None + Returns 'None'. + + Notes + ----- + Prints out the name, shape, bytes and type of all of the ndarrays + present in `vardict`. + + Examples + -------- + >>> a = np.arange(10) + >>> b = np.ones(20) + >>> np.who() + Name Shape Bytes Type + =========================================================== + a 10 40 int32 + b 20 160 float64 + Upper bound on total bytes = 200 + + >>> d = {'x': np.arange(2.0), 'y': np.arange(3.0), 'txt': 'Some str', + ... 'idx':5} + >>> np.who(d) + Name Shape Bytes Type + =========================================================== + y 3 24 float64 + x 2 16 float64 + Upper bound on total bytes = 40 + + """ + if vardict is None: + frame = sys._getframe().f_back + vardict = frame.f_globals + sta = [] + cache = {} + for name in vardict.keys(): + if isinstance(vardict[name], ndarray): + var = vardict[name] + idv = id(var) + if idv in cache.keys(): + namestr = name + " (%s)" % cache[idv] + original = 0 + else: + cache[idv] = name + namestr = name + original = 1 + shapestr = " x ".join(map(str, var.shape)) + bytestr = str(var.nbytes) + sta.append([namestr, shapestr, bytestr, var.dtype.name, + original]) + + maxname = 0 + maxshape = 0 + maxbyte = 0 + totalbytes = 0 + for k in range(len(sta)): + val = sta[k] + if maxname < len(val[0]): + maxname = len(val[0]) + if maxshape < len(val[1]): + maxshape = len(val[1]) + if maxbyte < len(val[2]): + maxbyte = len(val[2]) + if val[4]: + totalbytes += int(val[2]) + + if len(sta) > 0: + sp1 = max(10, maxname) + sp2 = max(10, maxshape) + sp3 = max(10, maxbyte) + prval = "Name %s Shape %s Bytes %s Type" % (sp1*' ', sp2*' ', sp3*' ') + print(prval + "\n" + "="*(len(prval)+5) + "\n") + + for k in range(len(sta)): + val = sta[k] + print("%s %s %s %s %s %s %s" % (val[0], ' '*(sp1-len(val[0])+4), + val[1], ' '*(sp2-len(val[1])+5), + val[2], ' '*(sp3-len(val[2])+5), + val[3])) + print("\nUpper bound on total bytes = %d" % totalbytes) + return + +#----------------------------------------------------------------------------- + + +# NOTE: pydoc defines a help function which works similarly to this +# except it uses a pager to take over the screen. + +# combine name and arguments and split to multiple lines of width +# characters. End lines on a comma and begin argument list indented with +# the rest of the arguments. +def _split_line(name, arguments, width): + firstwidth = len(name) + k = firstwidth + newstr = name + sepstr = ", " + arglist = arguments.split(sepstr) + for argument in arglist: + if k == firstwidth: + addstr = "" + else: + addstr = sepstr + k = k + len(argument) + len(addstr) + if k > width: + k = firstwidth + 1 + len(argument) + newstr = newstr + ",\n" + " "*(firstwidth+2) + argument + else: + newstr = newstr + addstr + argument + return newstr + +_namedict = None +_dictlist = None + +# Traverse all module directories underneath globals +# to see if something is defined +def _makenamedict(module='numpy'): + module = __import__(module, globals(), locals(), []) + thedict = {module.__name__:module.__dict__} + dictlist = [module.__name__] + totraverse = [module.__dict__] + while True: + if len(totraverse) == 0: + break + thisdict = totraverse.pop(0) + for x in thisdict.keys(): + if isinstance(thisdict[x], types.ModuleType): + modname = thisdict[x].__name__ + if modname not in dictlist: + moddict = thisdict[x].__dict__ + dictlist.append(modname) + totraverse.append(moddict) + thedict[modname] = moddict + return thedict, dictlist + + +def _info(obj, output=sys.stdout): + """Provide information about ndarray obj. + + Parameters + ---------- + obj : ndarray + Must be ndarray, not checked. + output + Where printed output goes. + + Notes + ----- + Copied over from the numarray module prior to its removal. + Adapted somewhat as only numpy is an option now. + + Called by info. + + """ + extra = "" + tic = "" + bp = lambda x: x + cls = getattr(obj, '__class__', type(obj)) + nm = getattr(cls, '__name__', cls) + strides = obj.strides + endian = obj.dtype.byteorder + + print("class: ", nm, file=output) + print("shape: ", obj.shape, file=output) + print("strides: ", strides, file=output) + print("itemsize: ", obj.itemsize, file=output) + print("aligned: ", bp(obj.flags.aligned), file=output) + print("contiguous: ", bp(obj.flags.contiguous), file=output) + print("fortran: ", obj.flags.fortran, file=output) + print( + "data pointer: %s%s" % (hex(obj.ctypes._as_parameter_.value), extra), + file=output + ) + print("byteorder: ", end=' ', file=output) + if endian in ['|', '=']: + print("%s%s%s" % (tic, sys.byteorder, tic), file=output) + byteswap = False + elif endian == '>': + print("%sbig%s" % (tic, tic), file=output) + byteswap = sys.byteorder != "big" + else: + print("%slittle%s" % (tic, tic), file=output) + byteswap = sys.byteorder != "little" + print("byteswap: ", bp(byteswap), file=output) + print("type: %s" % obj.dtype, file=output) + + +def info(object=None, maxwidth=76, output=sys.stdout, toplevel='numpy'): + """ + Get help information for a function, class, or module. + + Parameters + ---------- + object : object or str, optional + Input object or name to get information about. If `object` is a + numpy object, its docstring is given. If it is a string, available + modules are searched for matching objects. If None, information + about `info` itself is returned. + maxwidth : int, optional + Printing width. + output : file like object, optional + File like object that the output is written to, default is + ``stdout``. The object has to be opened in 'w' or 'a' mode. + toplevel : str, optional + Start search at this level. + + See Also + -------- + source, lookfor + + Notes + ----- + When used interactively with an object, ``np.info(obj)`` is equivalent + to ``help(obj)`` on the Python prompt or ``obj?`` on the IPython + prompt. + + Examples + -------- + >>> np.info(np.polyval) # doctest: +SKIP + polyval(p, x) + Evaluate the polynomial p at x. + ... + + When using a string for `object` it is possible to get multiple results. + + >>> np.info('fft') # doctest: +SKIP + *** Found in numpy *** + Core FFT routines + ... + *** Found in numpy.fft *** + fft(a, n=None, axis=-1) + ... + *** Repeat reference found in numpy.fft.fftpack *** + *** Total of 3 references found. *** + + """ + global _namedict, _dictlist + # Local import to speed up numpy's import time. + import pydoc + import inspect + + if (hasattr(object, '_ppimport_importer') or + hasattr(object, '_ppimport_module')): + object = object._ppimport_module + elif hasattr(object, '_ppimport_attr'): + object = object._ppimport_attr + + if object is None: + info(info) + elif isinstance(object, ndarray): + _info(object, output=output) + elif isinstance(object, str): + if _namedict is None: + _namedict, _dictlist = _makenamedict(toplevel) + numfound = 0 + objlist = [] + for namestr in _dictlist: + try: + obj = _namedict[namestr][object] + if id(obj) in objlist: + print("\n " + "*** Repeat reference found in %s *** " % namestr, + file=output + ) + else: + objlist.append(id(obj)) + print(" *** Found in %s ***" % namestr, file=output) + info(obj) + print("-"*maxwidth, file=output) + numfound += 1 + except KeyError: + pass + if numfound == 0: + print("Help for %s not found." % object, file=output) + else: + print("\n " + "*** Total of %d references found. ***" % numfound, + file=output + ) + + elif inspect.isfunction(object): + name = object.__name__ + arguments = formatargspec(*getargspec(object)) + + if len(name+arguments) > maxwidth: + argstr = _split_line(name, arguments, maxwidth) + else: + argstr = name + arguments + + print(" " + argstr + "\n", file=output) + print(inspect.getdoc(object), file=output) + + elif inspect.isclass(object): + name = object.__name__ + arguments = "()" + try: + if hasattr(object, '__init__'): + arguments = formatargspec( + *getargspec(object.__init__.__func__) + ) + arglist = arguments.split(', ') + if len(arglist) > 1: + arglist[1] = "("+arglist[1] + arguments = ", ".join(arglist[1:]) + except Exception: + pass + + if len(name+arguments) > maxwidth: + argstr = _split_line(name, arguments, maxwidth) + else: + argstr = name + arguments + + print(" " + argstr + "\n", file=output) + doc1 = inspect.getdoc(object) + if doc1 is None: + if hasattr(object, '__init__'): + print(inspect.getdoc(object.__init__), file=output) + else: + print(inspect.getdoc(object), file=output) + + methods = pydoc.allmethods(object) + if methods != []: + print("\n\nMethods:\n", file=output) + for meth in methods: + if meth[0] == '_': + continue + thisobj = getattr(object, meth, None) + if thisobj is not None: + methstr, other = pydoc.splitdoc( + inspect.getdoc(thisobj) or "None" + ) + print(" %s -- %s" % (meth, methstr), file=output) + + elif (sys.version_info[0] < 3 + and isinstance(object, types.InstanceType)): + # check for __call__ method + # types.InstanceType is the type of the instances of oldstyle classes + print("Instance of class: ", object.__class__.__name__, file=output) + print(file=output) + if hasattr(object, '__call__'): + arguments = formatargspec( + *getargspec(object.__call__.__func__) + ) + arglist = arguments.split(', ') + if len(arglist) > 1: + arglist[1] = "("+arglist[1] + arguments = ", ".join(arglist[1:]) + else: + arguments = "()" + + if hasattr(object, 'name'): + name = "%s" % object.name + else: + name = "" + if len(name+arguments) > maxwidth: + argstr = _split_line(name, arguments, maxwidth) + else: + argstr = name + arguments + + print(" " + argstr + "\n", file=output) + doc = inspect.getdoc(object.__call__) + if doc is not None: + print(inspect.getdoc(object.__call__), file=output) + print(inspect.getdoc(object), file=output) + + else: + print(inspect.getdoc(object), file=output) + + elif inspect.ismethod(object): + name = object.__name__ + arguments = formatargspec( + *getargspec(object.__func__) + ) + arglist = arguments.split(', ') + if len(arglist) > 1: + arglist[1] = "("+arglist[1] + arguments = ", ".join(arglist[1:]) + else: + arguments = "()" + + if len(name+arguments) > maxwidth: + argstr = _split_line(name, arguments, maxwidth) + else: + argstr = name + arguments + + print(" " + argstr + "\n", file=output) + print(inspect.getdoc(object), file=output) + + elif hasattr(object, '__doc__'): + print(inspect.getdoc(object), file=output) + + +def source(object, output=sys.stdout): + """ + Print or write to a file the source code for a NumPy object. + + The source code is only returned for objects written in Python. Many + functions and classes are defined in C and will therefore not return + useful information. + + Parameters + ---------- + object : numpy object + Input object. This can be any object (function, class, module, + ...). + output : file object, optional + If `output` not supplied then source code is printed to screen + (sys.stdout). File object must be created with either write 'w' or + append 'a' modes. + + See Also + -------- + lookfor, info + + Examples + -------- + >>> np.source(np.interp) #doctest: +SKIP + In file: /usr/lib/python2.6/dist-packages/numpy/lib/function_base.py + def interp(x, xp, fp, left=None, right=None): + \"\"\".... (full docstring printed)\"\"\" + if isinstance(x, (float, int, number)): + return compiled_interp([x], xp, fp, left, right).item() + else: + return compiled_interp(x, xp, fp, left, right) + + The source code is only returned for objects written in Python. + + >>> np.source(np.array) #doctest: +SKIP + Not available for this object. + + """ + # Local import to speed up numpy's import time. + import inspect + try: + print("In file: %s\n" % inspect.getsourcefile(object), file=output) + print(inspect.getsource(object), file=output) + except Exception: + print("Not available for this object.", file=output) + + +# Cache for lookfor: {id(module): {name: (docstring, kind, index), ...}...} +# where kind: "func", "class", "module", "object" +# and index: index in breadth-first namespace traversal +_lookfor_caches = {} + +# regexp whose match indicates that the string may contain a function +# signature +_function_signature_re = re.compile(r"[a-z0-9_]+\(.*[,=].*\)", re.I) + +def lookfor(what, module=None, import_modules=True, regenerate=False, + output=None): + """ + Do a keyword search on docstrings. + + A list of of objects that matched the search is displayed, + sorted by relevance. All given keywords need to be found in the + docstring for it to be returned as a result, but the order does + not matter. + + Parameters + ---------- + what : str + String containing words to look for. + module : str or list, optional + Name of module(s) whose docstrings to go through. + import_modules : bool, optional + Whether to import sub-modules in packages. Default is True. + regenerate : bool, optional + Whether to re-generate the docstring cache. Default is False. + output : file-like, optional + File-like object to write the output to. If omitted, use a pager. + + See Also + -------- + source, info + + Notes + ----- + Relevance is determined only roughly, by checking if the keywords occur + in the function name, at the start of a docstring, etc. + + Examples + -------- + >>> np.lookfor('binary representation') + Search results for 'binary representation' + ------------------------------------------ + numpy.binary_repr + Return the binary representation of the input number as a string. + numpy.core.setup_common.long_double_representation + Given a binary dump as given by GNU od -b, look for long double + numpy.base_repr + Return a string representation of a number in the given base system. + ... + + """ + import pydoc + + # Cache + cache = _lookfor_generate_cache(module, import_modules, regenerate) + + # Search + # XXX: maybe using a real stemming search engine would be better? + found = [] + whats = str(what).lower().split() + if not whats: + return + + for name, (docstring, kind, index) in cache.items(): + if kind in ('module', 'object'): + # don't show modules or objects + continue + ok = True + doc = docstring.lower() + for w in whats: + if w not in doc: + ok = False + break + if ok: + found.append(name) + + # Relevance sort + # XXX: this is full Harrison-Stetson heuristics now, + # XXX: it probably could be improved + + kind_relevance = {'func': 1000, 'class': 1000, + 'module': -1000, 'object': -1000} + + def relevance(name, docstr, kind, index): + r = 0 + # do the keywords occur within the start of the docstring? + first_doc = "\n".join(docstr.lower().strip().split("\n")[:3]) + r += sum([200 for w in whats if w in first_doc]) + # do the keywords occur in the function name? + r += sum([30 for w in whats if w in name]) + # is the full name long? + r += -len(name) * 5 + # is the object of bad type? + r += kind_relevance.get(kind, -1000) + # is the object deep in namespace hierarchy? + r += -name.count('.') * 10 + r += max(-index / 100, -100) + return r + + def relevance_value(a): + return relevance(a, *cache[a]) + found.sort(key=relevance_value) + + # Pretty-print + s = "Search results for '%s'" % (' '.join(whats)) + help_text = [s, "-"*len(s)] + for name in found[::-1]: + doc, kind, ix = cache[name] + + doclines = [line.strip() for line in doc.strip().split("\n") + if line.strip()] + + # find a suitable short description + try: + first_doc = doclines[0].strip() + if _function_signature_re.search(first_doc): + first_doc = doclines[1].strip() + except IndexError: + first_doc = "" + help_text.append("%s\n %s" % (name, first_doc)) + + if not found: + help_text.append("Nothing found.") + + # Output + if output is not None: + output.write("\n".join(help_text)) + elif len(help_text) > 10: + pager = pydoc.getpager() + pager("\n".join(help_text)) + else: + print("\n".join(help_text)) + +def _lookfor_generate_cache(module, import_modules, regenerate): + """ + Generate docstring cache for given module. + + Parameters + ---------- + module : str, None, module + Module for which to generate docstring cache + import_modules : bool + Whether to import sub-modules in packages. + regenerate : bool + Re-generate the docstring cache + + Returns + ------- + cache : dict {obj_full_name: (docstring, kind, index), ...} + Docstring cache for the module, either cached one (regenerate=False) + or newly generated. + + """ + global _lookfor_caches + # Local import to speed up numpy's import time. + import inspect + + if sys.version_info[0] >= 3: + # In Python3 stderr, stdout are text files. + from io import StringIO + else: + from StringIO import StringIO + + if module is None: + module = "numpy" + + if isinstance(module, str): + try: + __import__(module) + except ImportError: + return {} + module = sys.modules[module] + elif isinstance(module, list) or isinstance(module, tuple): + cache = {} + for mod in module: + cache.update(_lookfor_generate_cache(mod, import_modules, + regenerate)) + return cache + + if id(module) in _lookfor_caches and not regenerate: + return _lookfor_caches[id(module)] + + # walk items and collect docstrings + cache = {} + _lookfor_caches[id(module)] = cache + seen = {} + index = 0 + stack = [(module.__name__, module)] + while stack: + name, item = stack.pop(0) + if id(item) in seen: + continue + seen[id(item)] = True + + index += 1 + kind = "object" + + if inspect.ismodule(item): + kind = "module" + try: + _all = item.__all__ + except AttributeError: + _all = None + + # import sub-packages + if import_modules and hasattr(item, '__path__'): + for pth in item.__path__: + for mod_path in os.listdir(pth): + this_py = os.path.join(pth, mod_path) + init_py = os.path.join(pth, mod_path, '__init__.py') + if (os.path.isfile(this_py) and + mod_path.endswith('.py')): + to_import = mod_path[:-3] + elif os.path.isfile(init_py): + to_import = mod_path + else: + continue + if to_import == '__init__': + continue + + try: + old_stdout = sys.stdout + old_stderr = sys.stderr + try: + sys.stdout = StringIO() + sys.stderr = StringIO() + __import__("%s.%s" % (name, to_import)) + finally: + sys.stdout = old_stdout + sys.stderr = old_stderr + # Catch SystemExit, too + except BaseException: + continue + + for n, v in _getmembers(item): + try: + item_name = getattr(v, '__name__', "%s.%s" % (name, n)) + mod_name = getattr(v, '__module__', None) + except NameError: + # ref. SWIG's global cvars + # NameError: Unknown C global variable + item_name = "%s.%s" % (name, n) + mod_name = None + if '.' not in item_name and mod_name: + item_name = "%s.%s" % (mod_name, item_name) + + if not item_name.startswith(name + '.'): + # don't crawl "foreign" objects + if isinstance(v, ufunc): + # ... unless they are ufuncs + pass + else: + continue + elif not (inspect.ismodule(v) or _all is None or n in _all): + continue + stack.append(("%s.%s" % (name, n), v)) + elif inspect.isclass(item): + kind = "class" + for n, v in _getmembers(item): + stack.append(("%s.%s" % (name, n), v)) + elif hasattr(item, "__call__"): + kind = "func" + + try: + doc = inspect.getdoc(item) + except NameError: + # ref SWIG's NameError: Unknown C global variable + doc = None + if doc is not None: + cache[name] = (doc, kind, index) + + return cache + +def _getmembers(item): + import inspect + try: + members = inspect.getmembers(item) + except Exception: + members = [(x, getattr(item, x)) for x in dir(item) + if hasattr(item, x)] + return members + +#----------------------------------------------------------------------------- + +# The following SafeEval class and company are adapted from Michael Spencer's +# ASPN Python Cookbook recipe: +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/364469 +# Accordingly it is mostly Copyright 2006 by Michael Spencer. +# The recipe, like most of the other ASPN Python Cookbook recipes was made +# available under the Python license. +# http://www.python.org/license + +# It has been modified to: +# * handle unary -/+ +# * support True/False/None +# * raise SyntaxError instead of a custom exception. + +class SafeEval(object): + """ + Object to evaluate constant string expressions. + + This includes strings with lists, dicts and tuples using the abstract + syntax tree created by ``compiler.parse``. + + .. deprecated:: 1.10.0 + + See Also + -------- + safe_eval + + """ + def __init__(self): + # 2014-10-15, 1.10 + warnings.warn("SafeEval is deprecated in 1.10 and will be removed.", + DeprecationWarning, stacklevel=2) + + def visit(self, node): + cls = node.__class__ + meth = getattr(self, 'visit' + cls.__name__, self.default) + return meth(node) + + def default(self, node): + raise SyntaxError("Unsupported source construct: %s" + % node.__class__) + + def visitExpression(self, node): + return self.visit(node.body) + + def visitNum(self, node): + return node.n + + def visitStr(self, node): + return node.s + + def visitBytes(self, node): + return node.s + + def visitDict(self, node,**kw): + return dict([(self.visit(k), self.visit(v)) + for k, v in zip(node.keys, node.values)]) + + def visitTuple(self, node): + return tuple([self.visit(i) for i in node.elts]) + + def visitList(self, node): + return [self.visit(i) for i in node.elts] + + def visitUnaryOp(self, node): + import ast + if isinstance(node.op, ast.UAdd): + return +self.visit(node.operand) + elif isinstance(node.op, ast.USub): + return -self.visit(node.operand) + else: + raise SyntaxError("Unknown unary op: %r" % node.op) + + def visitName(self, node): + if node.id == 'False': + return False + elif node.id == 'True': + return True + elif node.id == 'None': + return None + else: + raise SyntaxError("Unknown name: %s" % node.id) + + def visitNameConstant(self, node): + return node.value + + +def safe_eval(source): + """ + Protected string evaluation. + + Evaluate a string containing a Python literal expression without + allowing the execution of arbitrary non-literal code. + + Parameters + ---------- + source : str + The string to evaluate. + + Returns + ------- + obj : object + The result of evaluating `source`. + + Raises + ------ + SyntaxError + If the code has invalid Python syntax, or if it contains + non-literal code. + + Examples + -------- + >>> np.safe_eval('1') + 1 + >>> np.safe_eval('[1, 2, 3]') + [1, 2, 3] + >>> np.safe_eval('{"foo": ("bar", 10.0)}') + {'foo': ('bar', 10.0)} + + >>> np.safe_eval('import os') + Traceback (most recent call last): + ... + SyntaxError: invalid syntax + + >>> np.safe_eval('open("/home/user/.ssh/id_dsa").read()') + Traceback (most recent call last): + ... + SyntaxError: Unsupported source construct: compiler.ast.CallFunc + + """ + # Local import to speed up numpy's import time. + import ast + + return ast.literal_eval(source) + + +def _median_nancheck(data, result, axis, out): + """ + Utility function to check median result from data for NaN values at the end + and return NaN in that case. Input result can also be a MaskedArray. + + Parameters + ---------- + data : array + Input data to median function + result : Array or MaskedArray + Result of median function + axis : {int, sequence of int, None}, optional + Axis or axes along which the median was computed. + out : ndarray, optional + Output array in which to place the result. + Returns + ------- + median : scalar or ndarray + Median or NaN in axes which contained NaN in the input. + """ + if data.size == 0: + return result + data = np.moveaxis(data, axis, -1) + n = np.isnan(data[..., -1]) + # masked NaN values are ok + if np.ma.isMaskedArray(n): + n = n.filled(False) + if result.ndim == 0: + if n == True: + warnings.warn("Invalid value encountered in median", + RuntimeWarning, stacklevel=3) + if out is not None: + out[...] = data.dtype.type(np.nan) + result = out + else: + result = data.dtype.type(np.nan) + elif np.count_nonzero(n.ravel()) > 0: + warnings.warn("Invalid value encountered in median for" + + " %d results" % np.count_nonzero(n.ravel()), + RuntimeWarning, stacklevel=3) + result[n] = np.nan + return result + +#----------------------------------------------------------------------------- diff --git a/numpy/linalg/__init__.py b/numpy/linalg/__init__.py new file mode 100644 index 0000000..2537926 --- /dev/null +++ b/numpy/linalg/__init__.py @@ -0,0 +1,55 @@ +""" +Core Linear Algebra Tools +========================= + +=============== ========================================================== +Linear algebra basics +========================================================================== +norm Vector or matrix norm +inv Inverse of a square matrix +solve Solve a linear system of equations +det Determinant of a square matrix +slogdet Logarithm of the determinant of a square matrix +lstsq Solve linear least-squares problem +pinv Pseudo-inverse (Moore-Penrose) calculated using a singular + value decomposition +matrix_power Integer power of a square matrix +matrix_rank Calculate matrix rank using an SVD-based method +=============== ========================================================== + +=============== ========================================================== +Eigenvalues and decompositions +========================================================================== +eig Eigenvalues and vectors of a square matrix +eigh Eigenvalues and eigenvectors of a Hermitian matrix +eigvals Eigenvalues of a square matrix +eigvalsh Eigenvalues of a Hermitian matrix +qr QR decomposition of a matrix +svd Singular value decomposition of a matrix +cholesky Cholesky decomposition of a matrix +=============== ========================================================== + +=============== ========================================================== +Tensor operations +========================================================================== +tensorsolve Solve a linear tensor equation +tensorinv Calculate an inverse of a tensor +=============== ========================================================== + +=============== ========================================================== +Exceptions +========================================================================== +LinAlgError Indicates a failed linear algebra operation +=============== ========================================================== + +""" +from __future__ import division, absolute_import, print_function + +# To get sub-modules +from .info import __doc__ + +from .linalg import * + +from numpy.testing import _numpy_tester +test = _numpy_tester().test +bench = _numpy_tester().bench diff --git a/numpy/linalg/info.py b/numpy/linalg/info.py new file mode 100644 index 0000000..646ecda --- /dev/null +++ b/numpy/linalg/info.py @@ -0,0 +1,37 @@ +"""\ +Core Linear Algebra Tools +------------------------- +Linear algebra basics: + +- norm Vector or matrix norm +- inv Inverse of a square matrix +- solve Solve a linear system of equations +- det Determinant of a square matrix +- lstsq Solve linear least-squares problem +- pinv Pseudo-inverse (Moore-Penrose) calculated using a singular + value decomposition +- matrix_power Integer power of a square matrix + +Eigenvalues and decompositions: + +- eig Eigenvalues and vectors of a square matrix +- eigh Eigenvalues and eigenvectors of a Hermitian matrix +- eigvals Eigenvalues of a square matrix +- eigvalsh Eigenvalues of a Hermitian matrix +- qr QR decomposition of a matrix +- svd Singular value decomposition of a matrix +- cholesky Cholesky decomposition of a matrix + +Tensor operations: + +- tensorsolve Solve a linear tensor equation +- tensorinv Calculate an inverse of a tensor + +Exceptions: + +- LinAlgError Indicates a failed linear algebra operation + +""" +from __future__ import division, absolute_import, print_function + +depends = ['core'] diff --git a/numpy/linalg/lapack_lite/f2c.c b/numpy/linalg/lapack_lite/f2c.c new file mode 100644 index 0000000..1114bef --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c.c @@ -0,0 +1,764 @@ +/* + Functions here are copied from the source code for libf2c. + + Typically each function there is in its own file. + + We don't link against libf2c directly, because we can't guarantee + it is available, and shipping a static library isn't portable. +*/ + +#include +#include +#include +#include +#include "f2c.h" + + +extern void s_wsfe(cilist *f) {;} +extern void e_wsfe(void) {;} +extern void do_fio(integer *c, char *s, ftnlen l) {;} + +/* You'll want this if you redo the f2c_*.c files with the -C option + * to f2c for checking array subscripts. (It's not suggested you do that + * for production use, of course.) */ +extern int +s_rnge(char *var, int index, char *routine, int lineno) +{ + fprintf(stderr, "array index out-of-bounds for %s[%d] in routine %s:%d\n", + var, index, routine, lineno); + fflush(stderr); + abort(); +} + +#ifdef KR_headers +extern float sqrtf(); +double f__cabsf(real, imag) float real, imag; +#else +#undef abs + +double f__cabsf(float real, float imag) +#endif +{ +float temp; + +if(real < 0.0f) + real = -real; +if(imag < 0.0f) + imag = -imag; +if(imag > real){ + temp = real; + real = imag; + imag = temp; +} +if((imag+real) == real) + return((float)real); + +temp = imag/real; +temp = real*sqrtf(1.0 + temp*temp); /*overflow!!*/ +return(temp); +} + + +#ifdef KR_headers +extern double sqrt(); +double f__cabs(real, imag) double real, imag; +#else +#undef abs + +double f__cabs(double real, double imag) +#endif +{ +double temp; + +if(real < 0) + real = -real; +if(imag < 0) + imag = -imag; +if(imag > real){ + temp = real; + real = imag; + imag = temp; +} +if((imag+real) == real) + return((double)real); + +temp = imag/real; +temp = real*sqrt(1.0 + temp*temp); /*overflow!!*/ +return(temp); +} + + VOID +#ifdef KR_headers +r_cnjg(r, z) complex *r, *z; +#else +r_cnjg(complex *r, complex *z) +#endif +{ +r->r = z->r; +r->i = - z->i; +} + + VOID +#ifdef KR_headers +d_cnjg(r, z) doublecomplex *r, *z; +#else +d_cnjg(doublecomplex *r, doublecomplex *z) +#endif +{ +r->r = z->r; +r->i = - z->i; +} + + +#ifdef KR_headers +float r_imag(z) complex *z; +#else +float r_imag(complex *z) +#endif +{ +return(z->i); +} + +#ifdef KR_headers +double d_imag(z) doublecomplex *z; +#else +double d_imag(doublecomplex *z) +#endif +{ +return(z->i); +} + + +#define log10e 0.43429448190325182765 + +#ifdef KR_headers +float logf(); +float r_lg10(x) real *x; +#else +#undef abs + +float r_lg10(real *x) +#endif +{ +return( log10e * logf(*x) ); +} + +#ifdef KR_headers +double log(); +double d_lg10(x) doublereal *x; +#else +#undef abs + +double d_lg10(doublereal *x) +#endif +{ +return( log10e * log(*x) ); +} + +#ifdef KR_headers +double r_sign(a,b) real *a, *b; +#else +double r_sign(real *a, real *b) +#endif +{ +float x; +x = (*a >= 0.0f ? *a : - *a); +return( *b >= 0.0f ? x : -x); +} + +#ifdef KR_headers +double d_sign(a,b) doublereal *a, *b; +#else +double d_sign(doublereal *a, doublereal *b) +#endif +{ +double x; +x = (*a >= 0 ? *a : - *a); +return( *b >= 0 ? x : -x); +} + + +#ifdef KR_headers +double floor(); +integer i_dnnt(x) doublereal *x; +#else +#undef abs + +integer i_dnnt(doublereal *x) +#endif +{ +return( (*x)>=0 ? + floor(*x + .5) : -floor(.5 - *x) ); +} + + +#ifdef KR_headers +double floor(); +integer i_nint(x) real *x; +#else +#undef abs +integer i_nint(real *x) +#endif +{ +return (integer)(*x >= 0 ? floor(*x + .5) : -floor(.5 - *x)); +} + +#ifdef KR_headers +double pow(); +double pow_dd(ap, bp) doublereal *ap, *bp; +#else +#undef abs + +double pow_dd(doublereal *ap, doublereal *bp) +#endif +{ +return(pow(*ap, *bp) ); +} + + +#ifdef KR_headers +double pow_ri(ap, bp) real *ap; integer *bp; +#else +double pow_ri(real *ap, integer *bp) +#endif +{ +float pow, x; +integer n; +unsigned long u; + +pow = 1; +x = *ap; +n = *bp; + +if(n != 0) + { + if(n < 0) + { + n = -n; + x = 1.0f/x; + } + for(u = n; ; ) + { + if(u & 01) + pow *= x; + if(u >>= 1) + x *= x; + else + break; + } + } +return(pow); +} + +#ifdef KR_headers +double pow_di(ap, bp) doublereal *ap; integer *bp; +#else +double pow_di(doublereal *ap, integer *bp) +#endif +{ +double pow, x; +integer n; +unsigned long u; + +pow = 1; +x = *ap; +n = *bp; + +if(n != 0) + { + if(n < 0) + { + n = -n; + x = 1/x; + } + for(u = n; ; ) + { + if(u & 01) + pow *= x; + if(u >>= 1) + x *= x; + else + break; + } + } +return(pow); +} + +#ifdef KR_headers +VOID pow_zi(p, a, b) /* p = a**b */ + doublecomplex *p, *a; integer *b; +#else +extern void z_div(doublecomplex*, doublecomplex*, doublecomplex*); +void pow_zi(doublecomplex *p, doublecomplex *a, integer *b) /* p = a**b */ +#endif +{ + integer n; + unsigned long u; + double t; + doublecomplex q, x; + static doublecomplex one = {1.0, 0.0}; + + n = *b; + q.r = 1; + q.i = 0; + + if(n == 0) + goto done; + if(n < 0) + { + n = -n; + z_div(&x, &one, a); + } + else + { + x.r = a->r; + x.i = a->i; + } + + for(u = n; ; ) + { + if(u & 01) + { + t = q.r * x.r - q.i * x.i; + q.i = q.r * x.i + q.i * x.r; + q.r = t; + } + if(u >>= 1) + { + t = x.r * x.r - x.i * x.i; + x.i = 2 * x.r * x.i; + x.r = t; + } + else + break; + } + done: + p->i = q.i; + p->r = q.r; + } + +#ifdef KR_headers +VOID pow_ci(p, a, b) /* p = a**b */ + complex *p, *a; integer *b; +#else +extern void pow_zi(doublecomplex*, doublecomplex*, integer*); +void pow_ci(complex *p, complex *a, integer *b) /* p = a**b */ +#endif +{ +doublecomplex p1, a1; + +a1.r = a->r; +a1.i = a->i; + +pow_zi(&p1, &a1, b); + +p->r = p1.r; +p->i = p1.i; +} + +/* Unless compiled with -DNO_OVERWRITE, this variant of s_cat allows the + * target of a concatenation to appear on its right-hand side (contrary + * to the Fortran 77 Standard, but in accordance with Fortran 90). + */ +#define NO_OVERWRITE + + +#ifndef NO_OVERWRITE + +#undef abs +#ifdef KR_headers + extern char *F77_aloc(); + extern void free(); + extern void exit_(); +#else + + extern char *F77_aloc(ftnlen, char*); +#endif + +#endif /* NO_OVERWRITE */ + + VOID +#ifdef KR_headers +s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnlen rnp[], *np, ll; +#else +s_cat(char *lp, char *rpp[], ftnlen rnp[], ftnlen *np, ftnlen ll) +#endif +{ + ftnlen i, nc; + char *rp; + ftnlen n = *np; +#ifndef NO_OVERWRITE + ftnlen L, m; + char *lp0, *lp1; + + lp0 = 0; + lp1 = lp; + L = ll; + i = 0; + while(i < n) { + rp = rpp[i]; + m = rnp[i++]; + if (rp >= lp1 || rp + m <= lp) { + if ((L -= m) <= 0) { + n = i; + break; + } + lp1 += m; + continue; + } + lp0 = lp; + lp = lp1 = F77_aloc(L = ll, "s_cat"); + break; + } + lp1 = lp; +#endif /* NO_OVERWRITE */ + for(i = 0 ; i < n ; ++i) { + nc = ll; + if(rnp[i] < nc) + nc = rnp[i]; + ll -= nc; + rp = rpp[i]; + while(--nc >= 0) + *lp++ = *rp++; + } + while(--ll >= 0) + *lp++ = ' '; +#ifndef NO_OVERWRITE + if (lp0) { + memmove(lp0, lp1, L); + free(lp1); + } +#endif + } + + +/* compare two strings */ + +#ifdef KR_headers +integer s_cmp(a0, b0, la, lb) char *a0, *b0; ftnlen la, lb; +#else +integer s_cmp(char *a0, char *b0, ftnlen la, ftnlen lb) +#endif +{ +register unsigned char *a, *aend, *b, *bend; +a = (unsigned char *)a0; +b = (unsigned char *)b0; +aend = a + la; +bend = b + lb; + +if(la <= lb) + { + while(a < aend) + if(*a != *b) + return( *a - *b ); + else + { ++a; ++b; } + + while(b < bend) + if(*b != ' ') + return( ' ' - *b ); + else ++b; + } + +else + { + while(b < bend) + if(*a == *b) + { ++a; ++b; } + else + return( *a - *b ); + while(a < aend) + if(*a != ' ') + return(*a - ' '); + else ++a; + } +return(0); +} +/* Unless compiled with -DNO_OVERWRITE, this variant of s_copy allows the + * target of an assignment to appear on its right-hand side (contrary + * to the Fortran 77 Standard, but in accordance with Fortran 90), + * as in a(2:5) = a(4:7) . + */ + + + +/* assign strings: a = b */ + +#ifdef KR_headers +VOID s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb; +#else +void s_copy(register char *a, register char *b, ftnlen la, ftnlen lb) +#endif +{ + register char *aend, *bend; + + aend = a + la; + + if(la <= lb) +#ifndef NO_OVERWRITE + if (a <= b || a >= b + la) +#endif + while(a < aend) + *a++ = *b++; +#ifndef NO_OVERWRITE + else + for(b += la; a < aend; ) + *--aend = *--b; +#endif + + else { + bend = b + lb; +#ifndef NO_OVERWRITE + if (a <= b || a >= bend) +#endif + while(b < bend) + *a++ = *b++; +#ifndef NO_OVERWRITE + else { + a += lb; + while(b < bend) + *--a = *--bend; + a += lb; + } +#endif + while(a < aend) + *a++ = ' '; + } + } + + +#ifdef KR_headers +double f__cabsf(); +double c_abs(z) complex *z; +#else +double f__cabsf(float, float); +double c_abs(complex *z) +#endif +{ +return( f__cabsf( z->r, z->i ) ); +} + +#ifdef KR_headers +double f__cabs(); +double z_abs(z) doublecomplex *z; +#else +double f__cabs(double, double); +double z_abs(doublecomplex *z) +#endif +{ +return( f__cabs( z->r, z->i ) ); +} + + +#ifdef KR_headers +extern void sig_die(); +VOID c_div(c, a, b) complex *a, *b, *c; +#else +extern void sig_die(char*, int); +void c_div(complex *c, complex *a, complex *b) +#endif +{ +float ratio, den; +float abr, abi; + +if( (abr = b->r) < 0.f) + abr = - abr; +if( (abi = b->i) < 0.f) + abi = - abi; +if( abr <= abi ) + { + /*Let IEEE Infinties handle this ;( */ + /*if(abi == 0) + sig_die("complex division by zero", 1);*/ + ratio = b->r / b->i ; + den = b->i * (1 + ratio*ratio); + c->r = (a->r*ratio + a->i) / den; + c->i = (a->i*ratio - a->r) / den; + } + +else + { + ratio = b->i / b->r ; + den = b->r * (1.f + ratio*ratio); + c->r = (a->r + a->i*ratio) / den; + c->i = (a->i - a->r*ratio) / den; + } + +} + +#ifdef KR_headers +extern void sig_die(); +VOID z_div(c, a, b) doublecomplex *a, *b, *c; +#else +extern void sig_die(char*, int); +void z_div(doublecomplex *c, doublecomplex *a, doublecomplex *b) +#endif +{ +double ratio, den; +double abr, abi; + +if( (abr = b->r) < 0.) + abr = - abr; +if( (abi = b->i) < 0.) + abi = - abi; +if( abr <= abi ) + { + /*Let IEEE Infinties handle this ;( */ + /*if(abi == 0) + sig_die("complex division by zero", 1);*/ + ratio = b->r / b->i ; + den = b->i * (1 + ratio*ratio); + c->r = (a->r*ratio + a->i) / den; + c->i = (a->i*ratio - a->r) / den; + } + +else + { + ratio = b->i / b->r ; + den = b->r * (1 + ratio*ratio); + c->r = (a->r + a->i*ratio) / den; + c->i = (a->i - a->r*ratio) / den; + } + +} + + +#ifdef KR_headers +float sqrtf(), f__cabsf(); +VOID c_sqrt(r, z) complex *r, *z; +#else +#undef abs + +extern double f__cabsf(float, float); +void c_sqrt(complex *r, complex *z) +#endif +{ +float mag; + +if( (mag = f__cabsf(z->r, z->i)) == 0.f) + r->r = r->i = 0.f; +else if(z->r > 0.0f) + { + r->r = sqrtf(0.5f * (mag + z->r) ); + r->i = z->i / r->r / 2.0f; + } +else + { + r->i = sqrtf(0.5f * (mag - z->r) ); + if(z->i < 0.0f) + r->i = - r->i; + r->r = z->i / r->i / 2.0f; + } +} + + +#ifdef KR_headers +double sqrt(), f__cabs(); +VOID z_sqrt(r, z) doublecomplex *r, *z; +#else +#undef abs + +extern double f__cabs(double, double); +void z_sqrt(doublecomplex *r, doublecomplex *z) +#endif +{ +double mag; + +if( (mag = f__cabs(z->r, z->i)) == 0.) + r->r = r->i = 0.; +else if(z->r > 0) + { + r->r = sqrt(0.5 * (mag + z->r) ); + r->i = z->i / r->r / 2; + } +else + { + r->i = sqrt(0.5 * (mag - z->r) ); + if(z->i < 0) + r->i = - r->i; + r->r = z->i / r->i / 2; + } +} +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef KR_headers +integer pow_ii(ap, bp) integer *ap, *bp; +#else +integer pow_ii(integer *ap, integer *bp) +#endif +{ + integer pow, x, n; + unsigned long u; + + x = *ap; + n = *bp; + + if (n <= 0) { + if (n == 0 || x == 1) + return 1; + if (x != -1) + return x == 0 ? 1/x : 0; + n = -n; + } + u = n; + for(pow = 1; ; ) + { + if(u & 01) + pow *= x; + if(u >>= 1) + x *= x; + else + break; + } + return(pow); + } +#ifdef __cplusplus +} +#endif + +#ifdef KR_headers +extern void f_exit(); +VOID s_stop(s, n) char *s; ftnlen n; +#else +#undef abs +#undef min +#undef max +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +extern "C" { +#endif +void f_exit(void); + +int s_stop(char *s, ftnlen n) +#endif +{ +int i; + +if(n > 0) + { + fprintf(stderr, "STOP "); + for(i = 0; i= 0 ? (x) : -(x)) +#endif +#define dabs(x) (doublereal)abs(x) +#ifndef min +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#endif +#define dmin(a,b) (doublereal)min(a,b) +#define dmax(a,b) (doublereal)max(a,b) + +/* procedure parameter types for -A and -C++ */ + +#define F2C_proc_par_types 1 +#ifdef __cplusplus +typedef int /* Unknown procedure type */ (*U_fp)(...); +typedef shortint (*J_fp)(...); +typedef integer (*I_fp)(...); +typedef real (*R_fp)(...); +typedef doublereal (*D_fp)(...), (*E_fp)(...); +typedef /* Complex */ VOID (*C_fp)(...); +typedef /* Double Complex */ VOID (*Z_fp)(...); +typedef logical (*L_fp)(...); +typedef shortlogical (*K_fp)(...); +typedef /* Character */ VOID (*H_fp)(...); +typedef /* Subroutine */ int (*S_fp)(...); +#else +typedef int /* Unknown procedure type */ (*U_fp)(void); +typedef shortint (*J_fp)(void); +typedef integer (*I_fp)(void); +typedef real (*R_fp)(void); +typedef doublereal (*D_fp)(void), (*E_fp)(void); +typedef /* Complex */ VOID (*C_fp)(void); +typedef /* Double Complex */ VOID (*Z_fp)(void); +typedef logical (*L_fp)(void); +typedef shortlogical (*K_fp)(void); +typedef /* Character */ VOID (*H_fp)(void); +typedef /* Subroutine */ int (*S_fp)(void); +#endif +/* E_fp is for real functions when -R is not specified */ +typedef VOID C_f; /* complex function */ +typedef VOID H_f; /* character function */ +typedef VOID Z_f; /* double complex function */ +typedef doublereal E_f; /* real function with -R not specified */ + +/* undef any lower-case symbols that your C compiler predefines, e.g.: */ + +#ifndef Skip_f2c_Undefs +#undef cray +#undef gcos +#undef mc68010 +#undef mc68020 +#undef mips +#undef pdp11 +#undef sgi +#undef sparc +#undef sun +#undef sun2 +#undef sun3 +#undef sun4 +#undef u370 +#undef u3b +#undef u3b2 +#undef u3b5 +#undef unix +#undef vax +#endif + +/* https://anonscm.debian.org/cgit/collab-maint/libf2c2.git/tree/f2ch.add */ + +/* If you are using a C++ compiler, append the following to f2c.h + for compiling libF77 and libI77. */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int abort_(void); +extern double c_abs(complex *); +extern void c_cos(complex *, complex *); +extern void c_div(complex *, complex *, complex *); +extern void c_exp(complex *, complex *); +extern void c_log(complex *, complex *); +extern void c_sin(complex *, complex *); +extern void c_sqrt(complex *, complex *); +extern double d_abs(double *); +extern double d_acos(double *); +extern double d_asin(double *); +extern double d_atan(double *); +extern double d_atn2(double *, double *); +extern void d_cnjg(doublecomplex *, doublecomplex *); +extern double d_cos(double *); +extern double d_cosh(double *); +extern double d_dim(double *, double *); +extern double d_exp(double *); +extern double d_imag(doublecomplex *); +extern double d_int(double *); +extern double d_lg10(double *); +extern double d_log(double *); +extern double d_mod(double *, double *); +extern double d_nint(double *); +extern double d_prod(float *, float *); +extern double d_sign(double *, double *); +extern double d_sin(double *); +extern double d_sinh(double *); +extern double d_sqrt(double *); +extern double d_tan(double *); +extern double d_tanh(double *); +extern double derf_(double *); +extern double derfc_(double *); +extern void do_fio(ftnint *, char *, ftnlen); +extern integer do_lio(ftnint *, ftnint *, char *, ftnlen); +extern integer do_uio(ftnint *, char *, ftnlen); +extern integer e_rdfe(void); +extern integer e_rdue(void); +extern integer e_rsfe(void); +extern integer e_rsfi(void); +extern integer e_rsle(void); +extern integer e_rsli(void); +extern integer e_rsue(void); +extern integer e_wdfe(void); +extern integer e_wdue(void); +extern void e_wsfe(void); +extern integer e_wsfi(void); +extern integer e_wsle(void); +extern integer e_wsli(void); +extern integer e_wsue(void); +extern int ef1asc_(ftnint *, ftnlen *, ftnint *, ftnlen *); +extern integer ef1cmc_(ftnint *, ftnlen *, ftnint *, ftnlen *); + +extern double erf_(float *); +extern double erfc_(float *); +extern integer f_back(alist *); +extern integer f_clos(cllist *); +extern integer f_end(alist *); +extern void f_exit(void); +extern integer f_inqu(inlist *); +extern integer f_open(olist *); +extern integer f_rew(alist *); +extern int flush_(void); +extern void getarg_(integer *, char *, ftnlen); +extern void getenv_(char *, char *, ftnlen, ftnlen); +extern short h_abs(short *); +extern short h_dim(short *, short *); +extern short h_dnnt(double *); +extern short h_indx(char *, char *, ftnlen, ftnlen); +extern short h_len(char *, ftnlen); +extern short h_mod(short *, short *); +extern short h_nint(float *); +extern short h_sign(short *, short *); +extern short hl_ge(char *, char *, ftnlen, ftnlen); +extern short hl_gt(char *, char *, ftnlen, ftnlen); +extern short hl_le(char *, char *, ftnlen, ftnlen); +extern short hl_lt(char *, char *, ftnlen, ftnlen); +extern integer i_abs(integer *); +extern integer i_dim(integer *, integer *); +extern integer i_dnnt(double *); +extern integer i_indx(char *, char *, ftnlen, ftnlen); +extern integer i_len(char *, ftnlen); +extern integer i_mod(integer *, integer *); +extern integer i_nint(float *); +extern integer i_sign(integer *, integer *); +extern integer iargc_(void); +extern ftnlen l_ge(char *, char *, ftnlen, ftnlen); +extern ftnlen l_gt(char *, char *, ftnlen, ftnlen); +extern ftnlen l_le(char *, char *, ftnlen, ftnlen); +extern ftnlen l_lt(char *, char *, ftnlen, ftnlen); +extern void pow_ci(complex *, complex *, integer *); +extern double pow_dd(double *, double *); +extern double pow_di(double *, integer *); +extern short pow_hh(short *, shortint *); +extern integer pow_ii(integer *, integer *); +extern double pow_ri(float *, integer *); +extern void pow_zi(doublecomplex *, doublecomplex *, integer *); +extern void pow_zz(doublecomplex *, doublecomplex *, doublecomplex *); +extern double r_abs(float *); +extern double r_acos(float *); +extern double r_asin(float *); +extern double r_atan(float *); +extern double r_atn2(float *, float *); +extern void r_cnjg(complex *, complex *); +extern double r_cos(float *); +extern double r_cosh(float *); +extern double r_dim(float *, float *); +extern double r_exp(float *); +extern float r_imag(complex *); +extern double r_int(float *); +extern float r_lg10(real *); +extern double r_log(float *); +extern double r_mod(float *, float *); +extern double r_nint(float *); +extern double r_sign(float *, float *); +extern double r_sin(float *); +extern double r_sinh(float *); +extern double r_sqrt(float *); +extern double r_tan(float *); +extern double r_tanh(float *); +extern void s_cat(char *, char **, integer *, integer *, ftnlen); +extern integer s_cmp(char *, char *, ftnlen, ftnlen); +extern void s_copy(char *, char *, ftnlen, ftnlen); +extern int s_paus(char *, ftnlen); +extern integer s_rdfe(cilist *); +extern integer s_rdue(cilist *); +extern integer s_rnge(char *, integer, char *, integer); +extern integer s_rsfe(cilist *); +extern integer s_rsfi(icilist *); +extern integer s_rsle(cilist *); +extern integer s_rsli(icilist *); +extern integer s_rsne(cilist *); +extern integer s_rsni(icilist *); +extern integer s_rsue(cilist *); +extern int s_stop(char *, ftnlen); +extern integer s_wdfe(cilist *); +extern integer s_wdue(cilist *); +extern void s_wsfe( cilist *); +extern integer s_wsfi(icilist *); +extern integer s_wsle(cilist *); +extern integer s_wsli(icilist *); +extern integer s_wsne(cilist *); +extern integer s_wsni(icilist *); +extern integer s_wsue(cilist *); +extern void sig_die(char *, int); +extern integer signal_(integer *, void (*)(int)); +extern integer system_(char *, ftnlen); +extern double z_abs(doublecomplex *); +extern void z_cos(doublecomplex *, doublecomplex *); +extern void z_div(doublecomplex *, doublecomplex *, doublecomplex *); +extern void z_exp(doublecomplex *, doublecomplex *); +extern void z_log(doublecomplex *, doublecomplex *); +extern void z_sin(doublecomplex *, doublecomplex *); +extern void z_sqrt(doublecomplex *, doublecomplex *); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/numpy/linalg/lapack_lite/f2c_blas.c b/numpy/linalg/lapack_lite/f2c_blas.c new file mode 100644 index 0000000..3af506b --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c_blas.c @@ -0,0 +1,21615 @@ +/* +NOTE: This is generated code. Look in Misc/lapack_lite for information on + remaking this file. +*/ +#include "f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal dlamch_(char *); +#define EPSILON dlamch_("Epsilon") +#define SAFEMINIMUM dlamch_("Safe minimum") +#define PRECISION dlamch_("Precision") +#define BASE dlamch_("Base") +#endif + +extern doublereal dlapy2_(doublereal *x, doublereal *y); + +/* +f2c knows the exact rules for precedence, and so omits parentheses where not +strictly necessary. Since this is generated code, we don't really care if +it's readable, and we know what is written is correct. So don't warn about +them. +*/ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wparentheses" +#endif + + +/* Table of constant values */ + +static complex c_b21 = {1.f,0.f}; +static doublecomplex c_b1078 = {1.,0.}; + +/* Subroutine */ int caxpy_(integer *n, complex *ca, complex *cx, integer * + incx, complex *cy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + complex q__1, q__2; + + /* Local variables */ + static integer i__, ix, iy; + extern doublereal scabs1_(complex *); + + +/* + Purpose + ======= + + CAXPY constant times a vector plus a vector. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (scabs1_(ca) == 0.f) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + i__4 = ix; + q__2.r = ca->r * cx[i__4].r - ca->i * cx[i__4].i, q__2.i = ca->r * cx[ + i__4].i + ca->i * cx[i__4].r; + q__1.r = cy[i__3].r + q__2.r, q__1.i = cy[i__3].i + q__2.i; + cy[i__2].r = q__1.r, cy[i__2].i = q__1.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + i__4 = i__; + q__2.r = ca->r * cx[i__4].r - ca->i * cx[i__4].i, q__2.i = ca->r * cx[ + i__4].i + ca->i * cx[i__4].r; + q__1.r = cy[i__3].r + q__2.r, q__1.i = cy[i__3].i + q__2.i; + cy[i__2].r = q__1.r, cy[i__2].i = q__1.i; +/* L30: */ + } + return 0; +} /* caxpy_ */ + +/* Subroutine */ int ccopy_(integer *n, complex *cx, integer *incx, complex * + cy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + + /* Local variables */ + static integer i__, ix, iy; + + +/* + Purpose + ======= + + CCOPY copies a vector x to a vector y. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = ix; + cy[i__2].r = cx[i__3].r, cy[i__2].i = cx[i__3].i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + cy[i__2].r = cx[i__3].r, cy[i__2].i = cx[i__3].i; +/* L30: */ + } + return 0; +} /* ccopy_ */ + +/* Complex */ VOID cdotc_(complex * ret_val, integer *n, complex *cx, integer + *incx, complex *cy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, ix, iy; + static complex ctemp; + + +/* + Purpose + ======= + + forms the dot product of two vectors, conjugating the first + vector. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + ctemp.r = 0.f, ctemp.i = 0.f; + ret_val->r = 0.f, ret_val->i = 0.f; + if (*n <= 0) { + return ; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + r_cnjg(&q__3, &cx[ix]); + i__2 = iy; + q__2.r = q__3.r * cy[i__2].r - q__3.i * cy[i__2].i, q__2.i = q__3.r * + cy[i__2].i + q__3.i * cy[i__2].r; + q__1.r = ctemp.r + q__2.r, q__1.i = ctemp.i + q__2.i; + ctemp.r = q__1.r, ctemp.i = q__1.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + ret_val->r = ctemp.r, ret_val->i = ctemp.i; + return ; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + r_cnjg(&q__3, &cx[i__]); + i__2 = i__; + q__2.r = q__3.r * cy[i__2].r - q__3.i * cy[i__2].i, q__2.i = q__3.r * + cy[i__2].i + q__3.i * cy[i__2].r; + q__1.r = ctemp.r + q__2.r, q__1.i = ctemp.i + q__2.i; + ctemp.r = q__1.r, ctemp.i = q__1.i; +/* L30: */ + } + ret_val->r = ctemp.r, ret_val->i = ctemp.i; + return ; +} /* cdotc_ */ + +/* Complex */ VOID cdotu_(complex * ret_val, integer *n, complex *cx, integer + *incx, complex *cy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + complex q__1, q__2; + + /* Local variables */ + static integer i__, ix, iy; + static complex ctemp; + + +/* + Purpose + ======= + + CDOTU forms the dot product of two vectors. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + ctemp.r = 0.f, ctemp.i = 0.f; + ret_val->r = 0.f, ret_val->i = 0.f; + if (*n <= 0) { + return ; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + i__3 = iy; + q__2.r = cx[i__2].r * cy[i__3].r - cx[i__2].i * cy[i__3].i, q__2.i = + cx[i__2].r * cy[i__3].i + cx[i__2].i * cy[i__3].r; + q__1.r = ctemp.r + q__2.r, q__1.i = ctemp.i + q__2.i; + ctemp.r = q__1.r, ctemp.i = q__1.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + ret_val->r = ctemp.r, ret_val->i = ctemp.i; + return ; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + q__2.r = cx[i__2].r * cy[i__3].r - cx[i__2].i * cy[i__3].i, q__2.i = + cx[i__2].r * cy[i__3].i + cx[i__2].i * cy[i__3].r; + q__1.r = ctemp.r + q__2.r, q__1.i = ctemp.i + q__2.i; + ctemp.r = q__1.r, ctemp.i = q__1.i; +/* L30: */ + } + ret_val->r = ctemp.r, ret_val->i = ctemp.i; + return ; +} /* cdotu_ */ + +/* Subroutine */ int cgemm_(char *transa, char *transb, integer *m, integer * + n, integer *k, complex *alpha, complex *a, integer *lda, complex *b, + integer *ldb, complex *beta, complex *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3, i__4, i__5, i__6; + complex q__1, q__2, q__3, q__4; + + /* Local variables */ + static integer i__, j, l, info; + static logical nota, notb; + static complex temp; + static logical conja, conjb; + static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + CGEMM performs one of the matrix-matrix operations + + C := alpha*op( A )*op( B ) + beta*C, + + where op( X ) is one of + + op( X ) = X or op( X ) = X' or op( X ) = conjg( X' ), + + alpha and beta are scalars, and A, B and C are matrices, with op( A ) + an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. + + Arguments + ========== + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n', op( A ) = A. + + TRANSA = 'T' or 't', op( A ) = A'. + + TRANSA = 'C' or 'c', op( A ) = conjg( A' ). + + Unchanged on exit. + + TRANSB - CHARACTER*1. + On entry, TRANSB specifies the form of op( B ) to be used in + the matrix multiplication as follows: + + TRANSB = 'N' or 'n', op( B ) = B. + + TRANSB = 'T' or 't', op( B ) = B'. + + TRANSB = 'C' or 'c', op( B ) = conjg( B' ). + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix + op( A ) and of the matrix C. M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix + op( B ) and the number of columns of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry, K specifies the number of columns of the matrix + op( A ) and the number of rows of the matrix op( B ). K must + be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, ka ), where ka is + k when TRANSA = 'N' or 'n', and is m otherwise. + Before entry with TRANSA = 'N' or 'n', the leading m by k + part of the array A must contain the matrix A, otherwise + the leading k by m part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANSA = 'N' or 'n' then + LDA must be at least max( 1, m ), otherwise LDA must be at + least max( 1, k ). + Unchanged on exit. + + B - COMPLEX array of DIMENSION ( LDB, kb ), where kb is + n when TRANSB = 'N' or 'n', and is k otherwise. + Before entry with TRANSB = 'N' or 'n', the leading k by n + part of the array B must contain the matrix B, otherwise + the leading n by k part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANSB = 'N' or 'n' then + LDB must be at least max( 1, k ), otherwise LDB must be at + least max( 1, n ). + Unchanged on exit. + + BETA - COMPLEX . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + Unchanged on exit. + + C - COMPLEX array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n matrix + ( alpha*op( A )*op( B ) + beta*C ). + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Set NOTA and NOTB as true if A and B respectively are not + conjugated or transposed, set CONJA and CONJB as true if A and + B respectively are to be transposed but not conjugated and set + NROWA, NCOLA and NROWB as the number of rows and columns of A + and the number of rows of B respectively. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + nota = lsame_(transa, "N"); + notb = lsame_(transb, "N"); + conja = lsame_(transa, "C"); + conjb = lsame_(transb, "C"); + if (nota) { + nrowa = *m; + ncola = *k; + } else { + nrowa = *k; + ncola = *m; + } + if (notb) { + nrowb = *k; + } else { + nrowb = *n; + } + +/* Test the input parameters. */ + + info = 0; + if (! nota && ! conja && ! lsame_(transa, "T")) { + info = 1; + } else if (! notb && ! conjb && ! lsame_(transb, "T")) { + info = 2; + } else if (*m < 0) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < max(1,nrowa)) { + info = 8; + } else if (*ldb < max(1,nrowb)) { + info = 10; + } else if (*ldc < max(1,*m)) { + info = 13; + } + if (info != 0) { + xerbla_("CGEMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || (alpha->r == 0.f && alpha->i == 0.f || *k == 0) + && (beta->r == 1.f && beta->i == 0.f)) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (alpha->r == 0.f && alpha->i == 0.f) { + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = beta->r * c__[i__4].r - beta->i * c__[i__4].i, + q__1.i = beta->r * c__[i__4].i + beta->i * c__[ + i__4].r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L30: */ + } +/* L40: */ + } + } + return 0; + } + +/* Start the operations. */ + + if (notb) { + if (nota) { + +/* Form C := alpha*A*B + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (beta->r == 0.f && beta->i == 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L50: */ + } + } else if (beta->r != 1.f || beta->i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__1.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L60: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = l + j * b_dim1; + if (b[i__3].r != 0.f || b[i__3].i != 0.f) { + i__3 = l + j * b_dim1; + q__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3].i, + q__1.i = alpha->r * b[i__3].i + alpha->i * b[ + i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + q__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + q__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + q__1.r = c__[i__5].r + q__2.r, q__1.i = c__[i__5] + .i + q__2.i; + c__[i__4].r = q__1.r, c__[i__4].i = q__1.i; +/* L70: */ + } + } +/* L80: */ + } +/* L90: */ + } + } else if (conja) { + +/* Form C := alpha*conjg( A' )*B + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0.f, temp.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + r_cnjg(&q__3, &a[l + i__ * a_dim1]); + i__4 = l + j * b_dim1; + q__2.r = q__3.r * b[i__4].r - q__3.i * b[i__4].i, + q__2.i = q__3.r * b[i__4].i + q__3.i * b[i__4] + .r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L100: */ + } + if (beta->r == 0.f && beta->i == 0.f) { + i__3 = i__ + j * c_dim1; + q__1.r = alpha->r * temp.r - alpha->i * temp.i, + q__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + q__2.r = alpha->r * temp.r - alpha->i * temp.i, + q__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + q__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } +/* L110: */ + } +/* L120: */ + } + } else { + +/* Form C := alpha*A'*B + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0.f, temp.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + i__4 = l + i__ * a_dim1; + i__5 = l + j * b_dim1; + q__2.r = a[i__4].r * b[i__5].r - a[i__4].i * b[i__5] + .i, q__2.i = a[i__4].r * b[i__5].i + a[i__4] + .i * b[i__5].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L130: */ + } + if (beta->r == 0.f && beta->i == 0.f) { + i__3 = i__ + j * c_dim1; + q__1.r = alpha->r * temp.r - alpha->i * temp.i, + q__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + q__2.r = alpha->r * temp.r - alpha->i * temp.i, + q__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + q__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } +/* L140: */ + } +/* L150: */ + } + } + } else if (nota) { + if (conjb) { + +/* Form C := alpha*A*conjg( B' ) + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (beta->r == 0.f && beta->i == 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L160: */ + } + } else if (beta->r != 1.f || beta->i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__1.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L170: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * b_dim1; + if (b[i__3].r != 0.f || b[i__3].i != 0.f) { + r_cnjg(&q__2, &b[j + l * b_dim1]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, + q__1.i = alpha->r * q__2.i + alpha->i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + q__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + q__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + q__1.r = c__[i__5].r + q__2.r, q__1.i = c__[i__5] + .i + q__2.i; + c__[i__4].r = q__1.r, c__[i__4].i = q__1.i; +/* L180: */ + } + } +/* L190: */ + } +/* L200: */ + } + } else { + +/* Form C := alpha*A*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (beta->r == 0.f && beta->i == 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L210: */ + } + } else if (beta->r != 1.f || beta->i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__1.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L220: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * b_dim1; + if (b[i__3].r != 0.f || b[i__3].i != 0.f) { + i__3 = j + l * b_dim1; + q__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3].i, + q__1.i = alpha->r * b[i__3].i + alpha->i * b[ + i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + q__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + q__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + q__1.r = c__[i__5].r + q__2.r, q__1.i = c__[i__5] + .i + q__2.i; + c__[i__4].r = q__1.r, c__[i__4].i = q__1.i; +/* L230: */ + } + } +/* L240: */ + } +/* L250: */ + } + } + } else if (conja) { + if (conjb) { + +/* Form C := alpha*conjg( A' )*conjg( B' ) + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0.f, temp.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + r_cnjg(&q__3, &a[l + i__ * a_dim1]); + r_cnjg(&q__4, &b[j + l * b_dim1]); + q__2.r = q__3.r * q__4.r - q__3.i * q__4.i, q__2.i = + q__3.r * q__4.i + q__3.i * q__4.r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L260: */ + } + if (beta->r == 0.f && beta->i == 0.f) { + i__3 = i__ + j * c_dim1; + q__1.r = alpha->r * temp.r - alpha->i * temp.i, + q__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + q__2.r = alpha->r * temp.r - alpha->i * temp.i, + q__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + q__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } +/* L270: */ + } +/* L280: */ + } + } else { + +/* Form C := alpha*conjg( A' )*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0.f, temp.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + r_cnjg(&q__3, &a[l + i__ * a_dim1]); + i__4 = j + l * b_dim1; + q__2.r = q__3.r * b[i__4].r - q__3.i * b[i__4].i, + q__2.i = q__3.r * b[i__4].i + q__3.i * b[i__4] + .r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L290: */ + } + if (beta->r == 0.f && beta->i == 0.f) { + i__3 = i__ + j * c_dim1; + q__1.r = alpha->r * temp.r - alpha->i * temp.i, + q__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + q__2.r = alpha->r * temp.r - alpha->i * temp.i, + q__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + q__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } +/* L300: */ + } +/* L310: */ + } + } + } else { + if (conjb) { + +/* Form C := alpha*A'*conjg( B' ) + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0.f, temp.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + i__4 = l + i__ * a_dim1; + r_cnjg(&q__3, &b[j + l * b_dim1]); + q__2.r = a[i__4].r * q__3.r - a[i__4].i * q__3.i, + q__2.i = a[i__4].r * q__3.i + a[i__4].i * + q__3.r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L320: */ + } + if (beta->r == 0.f && beta->i == 0.f) { + i__3 = i__ + j * c_dim1; + q__1.r = alpha->r * temp.r - alpha->i * temp.i, + q__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + q__2.r = alpha->r * temp.r - alpha->i * temp.i, + q__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + q__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } +/* L330: */ + } +/* L340: */ + } + } else { + +/* Form C := alpha*A'*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0.f, temp.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + i__4 = l + i__ * a_dim1; + i__5 = j + l * b_dim1; + q__2.r = a[i__4].r * b[i__5].r - a[i__4].i * b[i__5] + .i, q__2.i = a[i__4].r * b[i__5].i + a[i__4] + .i * b[i__5].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L350: */ + } + if (beta->r == 0.f && beta->i == 0.f) { + i__3 = i__ + j * c_dim1; + q__1.r = alpha->r * temp.r - alpha->i * temp.i, + q__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + q__2.r = alpha->r * temp.r - alpha->i * temp.i, + q__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + q__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, q__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } +/* L360: */ + } +/* L370: */ + } + } + } + + return 0; + +/* End of CGEMM . */ + +} /* cgemm_ */ + +/* Subroutine */ int cgemv_(char *trans, integer *m, integer *n, complex * + alpha, complex *a, integer *lda, complex *x, integer *incx, complex * + beta, complex *y, integer *incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static complex temp; + static integer lenx, leny; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj; + + +/* + Purpose + ======= + + CGEMV performs one of the matrix-vector operations + + y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, or + + y := alpha*conjg( A' )*x + beta*y, + + where alpha and beta are scalars, x and y are vectors and A is an + m by n matrix. + + Arguments + ========== + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' y := alpha*A*x + beta*y. + + TRANS = 'T' or 't' y := alpha*A'*x + beta*y. + + TRANS = 'C' or 'c' y := alpha*conjg( A' )*x + beta*y. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + X - COMPLEX array of DIMENSION at least + ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. + Before entry, the incremented array X must contain the + vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - COMPLEX . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - COMPLEX array of DIMENSION at least + ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. + Before entry with BETA non-zero, the incremented array Y + must contain the vector y. On exit, Y is overwritten by the + updated vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(trans, "N") && ! lsame_(trans, "T") && ! lsame_(trans, "C") + ) { + info = 1; + } else if (*m < 0) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*lda < max(1,*m)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("CGEMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || alpha->r == 0.f && alpha->i == 0.f && (beta->r + == 1.f && beta->i == 0.f)) { + return 0; + } + + noconj = lsame_(trans, "T"); + +/* + Set LENX and LENY, the lengths of the vectors x and y, and set + up the start points in X and Y. +*/ + + if (lsame_(trans, "N")) { + lenx = *n; + leny = *m; + } else { + lenx = *m; + leny = *n; + } + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (lenx - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (leny - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. + + First form y := beta*y. +*/ + + if (beta->r != 1.f || beta->i != 0.f) { + if (*incy == 1) { + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + y[i__2].r = 0.f, y[i__2].i = 0.f; +/* L10: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + q__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + q__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; +/* L20: */ + } + } + } else { + iy = ky; + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + y[i__2].r = 0.f, y[i__2].i = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + q__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + q__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + iy += *incy; +/* L40: */ + } + } + } + } + if (alpha->r == 0.f && alpha->i == 0.f) { + return 0; + } + if (lsame_(trans, "N")) { + +/* Form y := alpha*A*x + y. */ + + jx = kx; + if (*incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + if (x[i__2].r != 0.f || x[i__2].i != 0.f) { + i__2 = jx; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + q__1.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + temp.r = q__1.r, temp.i = q__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__2.i = temp.r * a[i__5].i + temp.i * a[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; +/* L50: */ + } + } + jx += *incx; +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + if (x[i__2].r != 0.f || x[i__2].i != 0.f) { + i__2 = jx; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + q__1.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + temp.r = q__1.r, temp.i = q__1.i; + iy = ky; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = iy; + i__4 = iy; + i__5 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__2.i = temp.r * a[i__5].i + temp.i * a[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + iy += *incy; +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } else { + +/* Form y := alpha*A'*x + y or y := alpha*conjg( A' )*x + y. */ + + jy = ky; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp.r = 0.f, temp.i = 0.f; + if (noconj) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__; + q__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[i__4] + .i, q__2.i = a[i__3].r * x[i__4].i + a[i__3] + .i * x[i__4].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L90: */ + } + } else { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = i__; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, + q__2.i = q__3.r * x[i__3].i + q__3.i * x[i__3] + .r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L100: */ + } + } + i__2 = jy; + i__3 = jy; + q__2.r = alpha->r * temp.r - alpha->i * temp.i, q__2.i = + alpha->r * temp.i + alpha->i * temp.r; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + jy += *incy; +/* L110: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp.r = 0.f, temp.i = 0.f; + ix = kx; + if (noconj) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = ix; + q__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[i__4] + .i, q__2.i = a[i__3].r * x[i__4].i + a[i__3] + .i * x[i__4].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix += *incx; +/* L120: */ + } + } else { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = ix; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, + q__2.i = q__3.r * x[i__3].i + q__3.i * x[i__3] + .r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix += *incx; +/* L130: */ + } + } + i__2 = jy; + i__3 = jy; + q__2.r = alpha->r * temp.r - alpha->i * temp.i, q__2.i = + alpha->r * temp.i + alpha->i * temp.r; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + jy += *incy; +/* L140: */ + } + } + } + + return 0; + +/* End of CGEMV . */ + +} /* cgemv_ */ + +/* Subroutine */ int cgerc_(integer *m, integer *n, complex *alpha, complex * + x, integer *incx, complex *y, integer *incy, complex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1, q__2; + + /* Local variables */ + static integer i__, j, ix, jy, kx, info; + static complex temp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + CGERC performs the rank 1 operation + + A := alpha*x*conjg( y' ) + A, + + where alpha is a scalar, x is an m element vector, y is an n element + vector and A is an m by n matrix. + + Arguments + ========== + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - COMPLEX array of dimension at least + ( 1 + ( m - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the m + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - COMPLEX array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. On exit, A is + overwritten by the updated matrix. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (*m < 0) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("CGERC ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || alpha->r == 0.f && alpha->i == 0.f) { + return 0; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (*incy > 0) { + jy = 1; + } else { + jy = 1 - (*n - 1) * *incy; + } + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jy; + if (y[i__2].r != 0.f || y[i__2].i != 0.f) { + r_cnjg(&q__2, &y[jy]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, q__1.i = + alpha->r * q__2.i + alpha->i * q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = i__; + q__2.r = x[i__5].r * temp.r - x[i__5].i * temp.i, q__2.i = + x[i__5].r * temp.i + x[i__5].i * temp.r; + q__1.r = a[i__4].r + q__2.r, q__1.i = a[i__4].i + q__2.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L10: */ + } + } + jy += *incy; +/* L20: */ + } + } else { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*m - 1) * *incx; + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jy; + if (y[i__2].r != 0.f || y[i__2].i != 0.f) { + r_cnjg(&q__2, &y[jy]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, q__1.i = + alpha->r * q__2.i + alpha->i * q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = ix; + q__2.r = x[i__5].r * temp.r - x[i__5].i * temp.i, q__2.i = + x[i__5].r * temp.i + x[i__5].i * temp.r; + q__1.r = a[i__4].r + q__2.r, q__1.i = a[i__4].i + q__2.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + ix += *incx; +/* L30: */ + } + } + jy += *incy; +/* L40: */ + } + } + + return 0; + +/* End of CGERC . */ + +} /* cgerc_ */ + +/* Subroutine */ int cgeru_(integer *m, integer *n, complex *alpha, complex * + x, integer *incx, complex *y, integer *incy, complex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1, q__2; + + /* Local variables */ + static integer i__, j, ix, jy, kx, info; + static complex temp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + CGERU performs the rank 1 operation + + A := alpha*x*y' + A, + + where alpha is a scalar, x is an m element vector, y is an n element + vector and A is an m by n matrix. + + Arguments + ========== + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - COMPLEX array of dimension at least + ( 1 + ( m - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the m + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - COMPLEX array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. On exit, A is + overwritten by the updated matrix. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (*m < 0) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("CGERU ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || alpha->r == 0.f && alpha->i == 0.f) { + return 0; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (*incy > 0) { + jy = 1; + } else { + jy = 1 - (*n - 1) * *incy; + } + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jy; + if (y[i__2].r != 0.f || y[i__2].i != 0.f) { + i__2 = jy; + q__1.r = alpha->r * y[i__2].r - alpha->i * y[i__2].i, q__1.i = + alpha->r * y[i__2].i + alpha->i * y[i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = i__; + q__2.r = x[i__5].r * temp.r - x[i__5].i * temp.i, q__2.i = + x[i__5].r * temp.i + x[i__5].i * temp.r; + q__1.r = a[i__4].r + q__2.r, q__1.i = a[i__4].i + q__2.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L10: */ + } + } + jy += *incy; +/* L20: */ + } + } else { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*m - 1) * *incx; + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jy; + if (y[i__2].r != 0.f || y[i__2].i != 0.f) { + i__2 = jy; + q__1.r = alpha->r * y[i__2].r - alpha->i * y[i__2].i, q__1.i = + alpha->r * y[i__2].i + alpha->i * y[i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = ix; + q__2.r = x[i__5].r * temp.r - x[i__5].i * temp.i, q__2.i = + x[i__5].r * temp.i + x[i__5].i * temp.r; + q__1.r = a[i__4].r + q__2.r, q__1.i = a[i__4].i + q__2.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + ix += *incx; +/* L30: */ + } + } + jy += *incy; +/* L40: */ + } + } + + return 0; + +/* End of CGERU . */ + +} /* cgeru_ */ + +/* Subroutine */ int chemv_(char *uplo, integer *n, complex *alpha, complex * + a, integer *lda, complex *x, integer *incx, complex *beta, complex *y, + integer *incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + real r__1; + complex q__1, q__2, q__3, q__4; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static complex temp1, temp2; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + CHEMV performs the matrix-vector operation + + y := alpha*A*x + beta*y, + + where alpha and beta are scalars, x and y are n element vectors and + A is an n by n hermitian matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array A is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of A + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of A + is to be referenced. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular part of the hermitian matrix and the strictly + lower triangular part of A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular part of the hermitian matrix and the strictly + upper triangular part of A is not referenced. + Note that the imaginary parts of the diagonal elements need + not be set and are assumed to be zero. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - COMPLEX array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - COMPLEX . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - COMPLEX array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. On exit, Y is overwritten by the updated + vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*lda < max(1,*n)) { + info = 5; + } else if (*incx == 0) { + info = 7; + } else if (*incy == 0) { + info = 10; + } + if (info != 0) { + xerbla_("CHEMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || alpha->r == 0.f && alpha->i == 0.f && (beta->r == 1.f && + beta->i == 0.f)) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through the triangular part + of A. + + First form y := beta*y. +*/ + + if (beta->r != 1.f || beta->i != 0.f) { + if (*incy == 1) { + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + y[i__2].r = 0.f, y[i__2].i = 0.f; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + q__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + q__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; +/* L20: */ + } + } + } else { + iy = ky; + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + y[i__2].r = 0.f, y[i__2].i = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + q__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + q__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + iy += *incy; +/* L40: */ + } + } + } + } + if (alpha->r == 0.f && alpha->i == 0.f) { + return 0; + } + if (lsame_(uplo, "U")) { + +/* Form y when A is stored in upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + q__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + q__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = i__; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, q__2.i = + q__3.r * x[i__3].i + q__3.i * x[i__3].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L50: */ + } + i__2 = j; + i__3 = j; + i__4 = j + j * a_dim1; + r__1 = a[i__4].r; + q__3.r = r__1 * temp1.r, q__3.i = r__1 * temp1.i; + q__2.r = y[i__3].r + q__3.r, q__2.i = y[i__3].i + q__3.i; + q__4.r = alpha->r * temp2.r - alpha->i * temp2.i, q__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + ix = kx; + iy = ky; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = iy; + i__4 = iy; + i__5 = i__ + j * a_dim1; + q__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + q__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = ix; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, q__2.i = + q__3.r * x[i__3].i + q__3.i * x[i__3].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; + ix += *incx; + iy += *incy; +/* L70: */ + } + i__2 = jy; + i__3 = jy; + i__4 = j + j * a_dim1; + r__1 = a[i__4].r; + q__3.r = r__1 * temp1.r, q__3.i = r__1 * temp1.i; + q__2.r = y[i__3].r + q__3.r, q__2.i = y[i__3].i + q__3.i; + q__4.r = alpha->r * temp2.r - alpha->i * temp2.i, q__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + jx += *incx; + jy += *incy; +/* L80: */ + } + } + } else { + +/* Form y when A is stored in lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + i__2 = j; + i__3 = j; + i__4 = j + j * a_dim1; + r__1 = a[i__4].r; + q__2.r = r__1 * temp1.r, q__2.i = r__1 * temp1.i; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + q__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + q__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = i__; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, q__2.i = + q__3.r * x[i__3].i + q__3.i * x[i__3].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L90: */ + } + i__2 = j; + i__3 = j; + q__2.r = alpha->r * temp2.r - alpha->i * temp2.i, q__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + i__2 = jy; + i__3 = jy; + i__4 = j + j * a_dim1; + r__1 = a[i__4].r; + q__2.r = r__1 * temp1.r, q__2.i = r__1 * temp1.i; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + ix = jx; + iy = jy; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + iy += *incy; + i__3 = iy; + i__4 = iy; + i__5 = i__ + j * a_dim1; + q__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + q__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = ix; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, q__2.i = + q__3.r * x[i__3].i + q__3.i * x[i__3].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L110: */ + } + i__2 = jy; + i__3 = jy; + q__2.r = alpha->r * temp2.r - alpha->i * temp2.i, q__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + jx += *incx; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of CHEMV . */ + +} /* chemv_ */ + +/* Subroutine */ int cher2_(char *uplo, integer *n, complex *alpha, complex * + x, integer *incx, complex *y, integer *incy, complex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5, i__6; + real r__1; + complex q__1, q__2, q__3, q__4; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static complex temp1, temp2; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + CHER2 performs the hermitian rank 2 operation + + A := alpha*x*conjg( y' ) + conjg( alpha )*y*conjg( x' ) + A, + + where alpha is a scalar, x and y are n element vectors and A is an n + by n hermitian matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array A is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of A + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of A + is to be referenced. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - COMPLEX array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - COMPLEX array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular part of the hermitian matrix and the strictly + lower triangular part of A is not referenced. On exit, the + upper triangular part of the array A is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular part of the hermitian matrix and the strictly + upper triangular part of A is not referenced. On exit, the + lower triangular part of the array A is overwritten by the + lower triangular part of the updated matrix. + Note that the imaginary parts of the diagonal elements need + not be set, they are assumed to be zero, and on exit they + are set to zero. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*n)) { + info = 9; + } + if (info != 0) { + xerbla_("CHER2 ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || alpha->r == 0.f && alpha->i == 0.f) { + return 0; + } + +/* + Set up the start points in X and Y if the increments are not both + unity. +*/ + + if (*incx != 1 || *incy != 1) { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + jx = kx; + jy = ky; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through the triangular part + of A. +*/ + + if (lsame_(uplo, "U")) { + +/* Form A when A is stored in the upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + i__3 = j; + if (x[i__2].r != 0.f || x[i__2].i != 0.f || (y[i__3].r != 0.f + || y[i__3].i != 0.f)) { + r_cnjg(&q__2, &y[j]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, q__1.i = + alpha->r * q__2.i + alpha->i * q__2.r; + temp1.r = q__1.r, temp1.i = q__1.i; + i__2 = j; + q__2.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + q__2.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + r_cnjg(&q__1, &q__2); + temp2.r = q__1.r, temp2.i = q__1.i; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = i__; + q__3.r = x[i__5].r * temp1.r - x[i__5].i * temp1.i, + q__3.i = x[i__5].r * temp1.i + x[i__5].i * + temp1.r; + q__2.r = a[i__4].r + q__3.r, q__2.i = a[i__4].i + + q__3.i; + i__6 = i__; + q__4.r = y[i__6].r * temp2.r - y[i__6].i * temp2.i, + q__4.i = y[i__6].r * temp2.i + y[i__6].i * + temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L10: */ + } + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + i__4 = j; + q__2.r = x[i__4].r * temp1.r - x[i__4].i * temp1.i, + q__2.i = x[i__4].r * temp1.i + x[i__4].i * + temp1.r; + i__5 = j; + q__3.r = y[i__5].r * temp2.r - y[i__5].i * temp2.i, + q__3.i = y[i__5].r * temp2.i + y[i__5].i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + r__1 = a[i__3].r + q__1.r; + a[i__2].r = r__1, a[i__2].i = 0.f; + } else { + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + i__3 = jy; + if (x[i__2].r != 0.f || x[i__2].i != 0.f || (y[i__3].r != 0.f + || y[i__3].i != 0.f)) { + r_cnjg(&q__2, &y[jy]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, q__1.i = + alpha->r * q__2.i + alpha->i * q__2.r; + temp1.r = q__1.r, temp1.i = q__1.i; + i__2 = jx; + q__2.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + q__2.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + r_cnjg(&q__1, &q__2); + temp2.r = q__1.r, temp2.i = q__1.i; + ix = kx; + iy = ky; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = ix; + q__3.r = x[i__5].r * temp1.r - x[i__5].i * temp1.i, + q__3.i = x[i__5].r * temp1.i + x[i__5].i * + temp1.r; + q__2.r = a[i__4].r + q__3.r, q__2.i = a[i__4].i + + q__3.i; + i__6 = iy; + q__4.r = y[i__6].r * temp2.r - y[i__6].i * temp2.i, + q__4.i = y[i__6].r * temp2.i + y[i__6].i * + temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + ix += *incx; + iy += *incy; +/* L30: */ + } + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + i__4 = jx; + q__2.r = x[i__4].r * temp1.r - x[i__4].i * temp1.i, + q__2.i = x[i__4].r * temp1.i + x[i__4].i * + temp1.r; + i__5 = jy; + q__3.r = y[i__5].r * temp2.r - y[i__5].i * temp2.i, + q__3.i = y[i__5].r * temp2.i + y[i__5].i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + r__1 = a[i__3].r + q__1.r; + a[i__2].r = r__1, a[i__2].i = 0.f; + } else { + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + } + jx += *incx; + jy += *incy; +/* L40: */ + } + } + } else { + +/* Form A when A is stored in the lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + i__3 = j; + if (x[i__2].r != 0.f || x[i__2].i != 0.f || (y[i__3].r != 0.f + || y[i__3].i != 0.f)) { + r_cnjg(&q__2, &y[j]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, q__1.i = + alpha->r * q__2.i + alpha->i * q__2.r; + temp1.r = q__1.r, temp1.i = q__1.i; + i__2 = j; + q__2.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + q__2.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + r_cnjg(&q__1, &q__2); + temp2.r = q__1.r, temp2.i = q__1.i; + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + i__4 = j; + q__2.r = x[i__4].r * temp1.r - x[i__4].i * temp1.i, + q__2.i = x[i__4].r * temp1.i + x[i__4].i * + temp1.r; + i__5 = j; + q__3.r = y[i__5].r * temp2.r - y[i__5].i * temp2.i, + q__3.i = y[i__5].r * temp2.i + y[i__5].i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + r__1 = a[i__3].r + q__1.r; + a[i__2].r = r__1, a[i__2].i = 0.f; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = i__; + q__3.r = x[i__5].r * temp1.r - x[i__5].i * temp1.i, + q__3.i = x[i__5].r * temp1.i + x[i__5].i * + temp1.r; + q__2.r = a[i__4].r + q__3.r, q__2.i = a[i__4].i + + q__3.i; + i__6 = i__; + q__4.r = y[i__6].r * temp2.r - y[i__6].i * temp2.i, + q__4.i = y[i__6].r * temp2.i + y[i__6].i * + temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L50: */ + } + } else { + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + i__3 = jy; + if (x[i__2].r != 0.f || x[i__2].i != 0.f || (y[i__3].r != 0.f + || y[i__3].i != 0.f)) { + r_cnjg(&q__2, &y[jy]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, q__1.i = + alpha->r * q__2.i + alpha->i * q__2.r; + temp1.r = q__1.r, temp1.i = q__1.i; + i__2 = jx; + q__2.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + q__2.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + r_cnjg(&q__1, &q__2); + temp2.r = q__1.r, temp2.i = q__1.i; + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + i__4 = jx; + q__2.r = x[i__4].r * temp1.r - x[i__4].i * temp1.i, + q__2.i = x[i__4].r * temp1.i + x[i__4].i * + temp1.r; + i__5 = jy; + q__3.r = y[i__5].r * temp2.r - y[i__5].i * temp2.i, + q__3.i = y[i__5].r * temp2.i + y[i__5].i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + r__1 = a[i__3].r + q__1.r; + a[i__2].r = r__1, a[i__2].i = 0.f; + ix = jx; + iy = jy; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + iy += *incy; + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = ix; + q__3.r = x[i__5].r * temp1.r - x[i__5].i * temp1.i, + q__3.i = x[i__5].r * temp1.i + x[i__5].i * + temp1.r; + q__2.r = a[i__4].r + q__3.r, q__2.i = a[i__4].i + + q__3.i; + i__6 = iy; + q__4.r = y[i__6].r * temp2.r - y[i__6].i * temp2.i, + q__4.i = y[i__6].r * temp2.i + y[i__6].i * + temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L70: */ + } + } else { + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + } + jx += *incx; + jy += *incy; +/* L80: */ + } + } + } + + return 0; + +/* End of CHER2 . */ + +} /* cher2_ */ + +/* Subroutine */ int cher2k_(char *uplo, char *trans, integer *n, integer *k, + complex *alpha, complex *a, integer *lda, complex *b, integer *ldb, + real *beta, complex *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3, i__4, i__5, i__6, i__7; + real r__1; + complex q__1, q__2, q__3, q__4, q__5, q__6; + + /* Local variables */ + static integer i__, j, l, info; + static complex temp1, temp2; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + CHER2K performs one of the hermitian rank 2k operations + + C := alpha*A*conjg( B' ) + conjg( alpha )*B*conjg( A' ) + beta*C, + + or + + C := alpha*conjg( A' )*B + conjg( alpha )*conjg( B' )*A + beta*C, + + where alpha and beta are scalars with beta real, C is an n by n + hermitian matrix and A and B are n by k matrices in the first case + and k by n matrices in the second case. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*conjg( B' ) + + conjg( alpha )*B*conjg( A' ) + + beta*C. + + TRANS = 'C' or 'c' C := alpha*conjg( A' )*B + + conjg( alpha )*conjg( B' )*A + + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrices A and B, and on entry with + TRANS = 'C' or 'c', K specifies the number of rows of the + matrices A and B. K must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + B - COMPLEX array of DIMENSION ( LDB, kb ), where kb is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array B must contain the matrix B, otherwise + the leading k by n part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDB must be at least max( 1, n ), otherwise LDB must + be at least max( 1, k ). + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - COMPLEX array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the hermitian matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the hermitian matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + Note that the imaginary parts of the diagonal elements need + not be set, they are assumed to be zero, and on exit they + are set to zero. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + -- Modified 8-Nov-93 to set C(J,J) to REAL( C(J,J) ) when BETA = 1. + Ed Anderson, Cray Research Inc. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldb < max(1,nrowa)) { + info = 9; + } else if (*ldc < max(1,*n)) { + info = 12; + } + if (info != 0) { + xerbla_("CHER2K", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (alpha->r == 0.f && alpha->i == 0.f || *k == 0) && *beta == + 1.f) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (alpha->r == 0.f && alpha->i == 0.f) { + if (upper) { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = *beta * c__[i__4].r, q__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L30: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; +/* L40: */ + } + } + } else { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = *beta * c__[i__4].r, q__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* + Form C := alpha*A*conjg( B' ) + conjg( alpha )*B*conjg( A' ) + + C. +*/ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L90: */ + } + } else if (*beta != 1.f) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = *beta * c__[i__4].r, q__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L100: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * a_dim1; + i__4 = j + l * b_dim1; + if (a[i__3].r != 0.f || a[i__3].i != 0.f || (b[i__4].r != + 0.f || b[i__4].i != 0.f)) { + r_cnjg(&q__2, &b[j + l * b_dim1]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, + q__1.i = alpha->r * q__2.i + alpha->i * + q__2.r; + temp1.r = q__1.r, temp1.i = q__1.i; + i__3 = j + l * a_dim1; + q__2.r = alpha->r * a[i__3].r - alpha->i * a[i__3].i, + q__2.i = alpha->r * a[i__3].i + alpha->i * a[ + i__3].r; + r_cnjg(&q__1, &q__2); + temp2.r = q__1.r, temp2.i = q__1.i; + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + q__3.r = a[i__6].r * temp1.r - a[i__6].i * + temp1.i, q__3.i = a[i__6].r * temp1.i + a[ + i__6].i * temp1.r; + q__2.r = c__[i__5].r + q__3.r, q__2.i = c__[i__5] + .i + q__3.i; + i__7 = i__ + l * b_dim1; + q__4.r = b[i__7].r * temp2.r - b[i__7].i * + temp2.i, q__4.i = b[i__7].r * temp2.i + b[ + i__7].i * temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + + q__4.i; + c__[i__4].r = q__1.r, c__[i__4].i = q__1.i; +/* L110: */ + } + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + i__5 = j + l * a_dim1; + q__2.r = a[i__5].r * temp1.r - a[i__5].i * temp1.i, + q__2.i = a[i__5].r * temp1.i + a[i__5].i * + temp1.r; + i__6 = j + l * b_dim1; + q__3.r = b[i__6].r * temp2.r - b[i__6].i * temp2.i, + q__3.i = b[i__6].r * temp2.i + b[i__6].i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + r__1 = c__[i__4].r + q__1.r; + c__[i__3].r = r__1, c__[i__3].i = 0.f; + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L140: */ + } + } else if (*beta != 1.f) { + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = *beta * c__[i__4].r, q__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L150: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * a_dim1; + i__4 = j + l * b_dim1; + if (a[i__3].r != 0.f || a[i__3].i != 0.f || (b[i__4].r != + 0.f || b[i__4].i != 0.f)) { + r_cnjg(&q__2, &b[j + l * b_dim1]); + q__1.r = alpha->r * q__2.r - alpha->i * q__2.i, + q__1.i = alpha->r * q__2.i + alpha->i * + q__2.r; + temp1.r = q__1.r, temp1.i = q__1.i; + i__3 = j + l * a_dim1; + q__2.r = alpha->r * a[i__3].r - alpha->i * a[i__3].i, + q__2.i = alpha->r * a[i__3].i + alpha->i * a[ + i__3].r; + r_cnjg(&q__1, &q__2); + temp2.r = q__1.r, temp2.i = q__1.i; + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + q__3.r = a[i__6].r * temp1.r - a[i__6].i * + temp1.i, q__3.i = a[i__6].r * temp1.i + a[ + i__6].i * temp1.r; + q__2.r = c__[i__5].r + q__3.r, q__2.i = c__[i__5] + .i + q__3.i; + i__7 = i__ + l * b_dim1; + q__4.r = b[i__7].r * temp2.r - b[i__7].i * + temp2.i, q__4.i = b[i__7].r * temp2.i + b[ + i__7].i * temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + + q__4.i; + c__[i__4].r = q__1.r, c__[i__4].i = q__1.i; +/* L160: */ + } + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + i__5 = j + l * a_dim1; + q__2.r = a[i__5].r * temp1.r - a[i__5].i * temp1.i, + q__2.i = a[i__5].r * temp1.i + a[i__5].i * + temp1.r; + i__6 = j + l * b_dim1; + q__3.r = b[i__6].r * temp2.r - b[i__6].i * temp2.i, + q__3.i = b[i__6].r * temp2.i + b[i__6].i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + r__1 = c__[i__4].r + q__1.r; + c__[i__3].r = r__1, c__[i__3].i = 0.f; + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* + Form C := alpha*conjg( A' )*B + conjg( alpha )*conjg( B' )*A + + C. +*/ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + temp1.r = 0.f, temp1.i = 0.f; + temp2.r = 0.f, temp2.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + r_cnjg(&q__3, &a[l + i__ * a_dim1]); + i__4 = l + j * b_dim1; + q__2.r = q__3.r * b[i__4].r - q__3.i * b[i__4].i, + q__2.i = q__3.r * b[i__4].i + q__3.i * b[i__4] + .r; + q__1.r = temp1.r + q__2.r, q__1.i = temp1.i + q__2.i; + temp1.r = q__1.r, temp1.i = q__1.i; + r_cnjg(&q__3, &b[l + i__ * b_dim1]); + i__4 = l + j * a_dim1; + q__2.r = q__3.r * a[i__4].r - q__3.i * a[i__4].i, + q__2.i = q__3.r * a[i__4].i + q__3.i * a[i__4] + .r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L190: */ + } + if (i__ == j) { + if (*beta == 0.f) { + i__3 = j + j * c_dim1; + q__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + q__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + r_cnjg(&q__4, alpha); + q__3.r = q__4.r * temp2.r - q__4.i * temp2.i, + q__3.i = q__4.r * temp2.i + q__4.i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + r__1 = q__1.r; + c__[i__3].r = r__1, c__[i__3].i = 0.f; + } else { + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + q__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + q__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + r_cnjg(&q__4, alpha); + q__3.r = q__4.r * temp2.r - q__4.i * temp2.i, + q__3.i = q__4.r * temp2.i + q__4.i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + r__1 = *beta * c__[i__4].r + q__1.r; + c__[i__3].r = r__1, c__[i__3].i = 0.f; + } + } else { + if (*beta == 0.f) { + i__3 = i__ + j * c_dim1; + q__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + q__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + r_cnjg(&q__4, alpha); + q__3.r = q__4.r * temp2.r - q__4.i * temp2.i, + q__3.i = q__4.r * temp2.i + q__4.i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__3.r = *beta * c__[i__4].r, q__3.i = *beta * + c__[i__4].i; + q__4.r = alpha->r * temp1.r - alpha->i * temp1.i, + q__4.i = alpha->r * temp1.i + alpha->i * + temp1.r; + q__2.r = q__3.r + q__4.r, q__2.i = q__3.i + + q__4.i; + r_cnjg(&q__6, alpha); + q__5.r = q__6.r * temp2.r - q__6.i * temp2.i, + q__5.i = q__6.r * temp2.i + q__6.i * + temp2.r; + q__1.r = q__2.r + q__5.r, q__1.i = q__2.i + + q__5.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } + } +/* L200: */ + } +/* L210: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + temp1.r = 0.f, temp1.i = 0.f; + temp2.r = 0.f, temp2.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + r_cnjg(&q__3, &a[l + i__ * a_dim1]); + i__4 = l + j * b_dim1; + q__2.r = q__3.r * b[i__4].r - q__3.i * b[i__4].i, + q__2.i = q__3.r * b[i__4].i + q__3.i * b[i__4] + .r; + q__1.r = temp1.r + q__2.r, q__1.i = temp1.i + q__2.i; + temp1.r = q__1.r, temp1.i = q__1.i; + r_cnjg(&q__3, &b[l + i__ * b_dim1]); + i__4 = l + j * a_dim1; + q__2.r = q__3.r * a[i__4].r - q__3.i * a[i__4].i, + q__2.i = q__3.r * a[i__4].i + q__3.i * a[i__4] + .r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L220: */ + } + if (i__ == j) { + if (*beta == 0.f) { + i__3 = j + j * c_dim1; + q__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + q__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + r_cnjg(&q__4, alpha); + q__3.r = q__4.r * temp2.r - q__4.i * temp2.i, + q__3.i = q__4.r * temp2.i + q__4.i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + r__1 = q__1.r; + c__[i__3].r = r__1, c__[i__3].i = 0.f; + } else { + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + q__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + q__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + r_cnjg(&q__4, alpha); + q__3.r = q__4.r * temp2.r - q__4.i * temp2.i, + q__3.i = q__4.r * temp2.i + q__4.i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + r__1 = *beta * c__[i__4].r + q__1.r; + c__[i__3].r = r__1, c__[i__3].i = 0.f; + } + } else { + if (*beta == 0.f) { + i__3 = i__ + j * c_dim1; + q__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + q__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + r_cnjg(&q__4, alpha); + q__3.r = q__4.r * temp2.r - q__4.i * temp2.i, + q__3.i = q__4.r * temp2.i + q__4.i * + temp2.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__3.r = *beta * c__[i__4].r, q__3.i = *beta * + c__[i__4].i; + q__4.r = alpha->r * temp1.r - alpha->i * temp1.i, + q__4.i = alpha->r * temp1.i + alpha->i * + temp1.r; + q__2.r = q__3.r + q__4.r, q__2.i = q__3.i + + q__4.i; + r_cnjg(&q__6, alpha); + q__5.r = q__6.r * temp2.r - q__6.i * temp2.i, + q__5.i = q__6.r * temp2.i + q__6.i * + temp2.r; + q__1.r = q__2.r + q__5.r, q__1.i = q__2.i + + q__5.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } + } +/* L230: */ + } +/* L240: */ + } + } + } + + return 0; + +/* End of CHER2K. */ + +} /* cher2k_ */ + +/* Subroutine */ int cherk_(char *uplo, char *trans, integer *n, integer *k, + real *alpha, complex *a, integer *lda, real *beta, complex *c__, + integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3, i__4, i__5, + i__6; + real r__1; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, j, l, info; + static complex temp; + extern logical lsame_(char *, char *); + static integer nrowa; + static real rtemp; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + CHERK performs one of the hermitian rank k operations + + C := alpha*A*conjg( A' ) + beta*C, + + or + + C := alpha*conjg( A' )*A + beta*C, + + where alpha and beta are real scalars, C is an n by n hermitian + matrix and A is an n by k matrix in the first case and a k by n + matrix in the second case. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*conjg( A' ) + beta*C. + + TRANS = 'C' or 'c' C := alpha*conjg( A' )*A + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrix A, and on entry with + TRANS = 'C' or 'c', K specifies the number of rows of the + matrix A. K must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - COMPLEX array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the hermitian matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the hermitian matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + Note that the imaginary parts of the diagonal elements need + not be set, they are assumed to be zero, and on exit they + are set to zero. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + -- Modified 8-Nov-93 to set C(J,J) to REAL( C(J,J) ) when BETA = 1. + Ed Anderson, Cray Research Inc. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldc < max(1,*n)) { + info = 10; + } + if (info != 0) { + xerbla_("CHERK ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0.f || *k == 0) && *beta == 1.f) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.f) { + if (upper) { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = *beta * c__[i__4].r, q__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L30: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; +/* L40: */ + } + } + } else { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = *beta * c__[i__4].r, q__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* Form C := alpha*A*conjg( A' ) + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L90: */ + } + } else if (*beta != 1.f) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = *beta * c__[i__4].r, q__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L100: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * a_dim1; + if (a[i__3].r != 0.f || a[i__3].i != 0.f) { + r_cnjg(&q__2, &a[j + l * a_dim1]); + q__1.r = *alpha * q__2.r, q__1.i = *alpha * q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + q__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + q__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + q__1.r = c__[i__5].r + q__2.r, q__1.i = c__[i__5] + .i + q__2.i; + c__[i__4].r = q__1.r, c__[i__4].i = q__1.i; +/* L110: */ + } + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + i__5 = i__ + l * a_dim1; + q__1.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__1.i = temp.r * a[i__5].i + temp.i * a[i__5] + .r; + r__1 = c__[i__4].r + q__1.r; + c__[i__3].r = r__1, c__[i__3].i = 0.f; + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0.f, c__[i__3].i = 0.f; +/* L140: */ + } + } else if (*beta != 1.f) { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + q__1.r = *beta * c__[i__4].r, q__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L150: */ + } + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * a_dim1; + if (a[i__3].r != 0.f || a[i__3].i != 0.f) { + r_cnjg(&q__2, &a[j + l * a_dim1]); + q__1.r = *alpha * q__2.r, q__1.i = *alpha * q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + i__5 = j + l * a_dim1; + q__1.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__1.i = temp.r * a[i__5].i + temp.i * a[i__5] + .r; + r__1 = c__[i__4].r + q__1.r; + c__[i__3].r = r__1, c__[i__3].i = 0.f; + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + q__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + q__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + q__1.r = c__[i__5].r + q__2.r, q__1.i = c__[i__5] + .i + q__2.i; + c__[i__4].r = q__1.r, c__[i__4].i = q__1.i; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* Form C := alpha*conjg( A' )*A + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0.f, temp.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + r_cnjg(&q__3, &a[l + i__ * a_dim1]); + i__4 = l + j * a_dim1; + q__2.r = q__3.r * a[i__4].r - q__3.i * a[i__4].i, + q__2.i = q__3.r * a[i__4].i + q__3.i * a[i__4] + .r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L190: */ + } + if (*beta == 0.f) { + i__3 = i__ + j * c_dim1; + q__1.r = *alpha * temp.r, q__1.i = *alpha * temp.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + q__2.r = *alpha * temp.r, q__2.i = *alpha * temp.i; + i__4 = i__ + j * c_dim1; + q__3.r = *beta * c__[i__4].r, q__3.i = *beta * c__[ + i__4].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } +/* L200: */ + } + rtemp = 0.f; + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + r_cnjg(&q__3, &a[l + j * a_dim1]); + i__3 = l + j * a_dim1; + q__2.r = q__3.r * a[i__3].r - q__3.i * a[i__3].i, q__2.i = + q__3.r * a[i__3].i + q__3.i * a[i__3].r; + q__1.r = rtemp + q__2.r, q__1.i = q__2.i; + rtemp = q__1.r; +/* L210: */ + } + if (*beta == 0.f) { + i__2 = j + j * c_dim1; + r__1 = *alpha * rtemp; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *alpha * rtemp + *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } +/* L220: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + rtemp = 0.f; + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + r_cnjg(&q__3, &a[l + j * a_dim1]); + i__3 = l + j * a_dim1; + q__2.r = q__3.r * a[i__3].r - q__3.i * a[i__3].i, q__2.i = + q__3.r * a[i__3].i + q__3.i * a[i__3].r; + q__1.r = rtemp + q__2.r, q__1.i = q__2.i; + rtemp = q__1.r; +/* L230: */ + } + if (*beta == 0.f) { + i__2 = j + j * c_dim1; + r__1 = *alpha * rtemp; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + r__1 = *alpha * rtemp + *beta * c__[i__3].r; + c__[i__2].r = r__1, c__[i__2].i = 0.f; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + temp.r = 0.f, temp.i = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + r_cnjg(&q__3, &a[l + i__ * a_dim1]); + i__4 = l + j * a_dim1; + q__2.r = q__3.r * a[i__4].r - q__3.i * a[i__4].i, + q__2.i = q__3.r * a[i__4].i + q__3.i * a[i__4] + .r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L240: */ + } + if (*beta == 0.f) { + i__3 = i__ + j * c_dim1; + q__1.r = *alpha * temp.r, q__1.i = *alpha * temp.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } else { + i__3 = i__ + j * c_dim1; + q__2.r = *alpha * temp.r, q__2.i = *alpha * temp.i; + i__4 = i__ + j * c_dim1; + q__3.r = *beta * c__[i__4].r, q__3.i = *beta * c__[ + i__4].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; + } +/* L250: */ + } +/* L260: */ + } + } + } + + return 0; + +/* End of CHERK . */ + +} /* cherk_ */ + +/* Subroutine */ int cscal_(integer *n, complex *ca, complex *cx, integer * + incx) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + complex q__1; + + /* Local variables */ + static integer i__, nincx; + + +/* + Purpose + ======= + + CSCAL scales a vector by a constant. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cx; + + /* Function Body */ + if (*n <= 0 || *incx <= 0) { + return 0; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + nincx = *n * *incx; + i__1 = nincx; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + i__3 = i__; + i__4 = i__; + q__1.r = ca->r * cx[i__4].r - ca->i * cx[i__4].i, q__1.i = ca->r * cx[ + i__4].i + ca->i * cx[i__4].r; + cx[i__3].r = q__1.r, cx[i__3].i = q__1.i; +/* L10: */ + } + return 0; + +/* code for increment equal to 1 */ + +L20: + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__1 = i__; + i__3 = i__; + q__1.r = ca->r * cx[i__3].r - ca->i * cx[i__3].i, q__1.i = ca->r * cx[ + i__3].i + ca->i * cx[i__3].r; + cx[i__1].r = q__1.r, cx[i__1].i = q__1.i; +/* L30: */ + } + return 0; +} /* cscal_ */ + +/* Subroutine */ int csrot_(integer *n, complex *cx, integer *incx, complex * + cy, integer *incy, real *c__, real *s) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, ix, iy; + static complex ctemp; + + +/* + Purpose + ======= + + CSROT applies a plane rotation, where the cos and sin (c and s) are real + and the vectors cx and cy are complex. + jack dongarra, linpack, 3/11/78. + + Arguments + ========== + + N (input) INTEGER + On entry, N specifies the order of the vectors cx and cy. + N must be at least zero. + Unchanged on exit. + + CX (input) COMPLEX array, dimension at least + ( 1 + ( N - 1 )*abs( INCX ) ). + Before entry, the incremented array CX must contain the n + element vector cx. On exit, CX is overwritten by the updated + vector cx. + + INCX (input) INTEGER + On entry, INCX specifies the increment for the elements of + CX. INCX must not be zero. + Unchanged on exit. + + CY (input) COMPLEX array, dimension at least + ( 1 + ( N - 1 )*abs( INCY ) ). + Before entry, the incremented array CY must contain the n + element vector cy. On exit, CY is overwritten by the updated + vector cy. + + INCY (input) INTEGER + On entry, INCY specifies the increment for the elements of + CY. INCY must not be zero. + Unchanged on exit. + + C (input) REAL + On entry, C specifies the cosine, cos. + Unchanged on exit. + + S (input) REAL + On entry, S specifies the sine, sin. + Unchanged on exit. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments not equal + to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + q__2.r = *c__ * cx[i__2].r, q__2.i = *c__ * cx[i__2].i; + i__3 = iy; + q__3.r = *s * cy[i__3].r, q__3.i = *s * cy[i__3].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + ctemp.r = q__1.r, ctemp.i = q__1.i; + i__2 = iy; + i__3 = iy; + q__2.r = *c__ * cy[i__3].r, q__2.i = *c__ * cy[i__3].i; + i__4 = ix; + q__3.r = *s * cx[i__4].r, q__3.i = *s * cx[i__4].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - q__3.i; + cy[i__2].r = q__1.r, cy[i__2].i = q__1.i; + i__2 = ix; + cx[i__2].r = ctemp.r, cx[i__2].i = ctemp.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + q__2.r = *c__ * cx[i__2].r, q__2.i = *c__ * cx[i__2].i; + i__3 = i__; + q__3.r = *s * cy[i__3].r, q__3.i = *s * cy[i__3].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + ctemp.r = q__1.r, ctemp.i = q__1.i; + i__2 = i__; + i__3 = i__; + q__2.r = *c__ * cy[i__3].r, q__2.i = *c__ * cy[i__3].i; + i__4 = i__; + q__3.r = *s * cx[i__4].r, q__3.i = *s * cx[i__4].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - q__3.i; + cy[i__2].r = q__1.r, cy[i__2].i = q__1.i; + i__2 = i__; + cx[i__2].r = ctemp.r, cx[i__2].i = ctemp.i; +/* L30: */ + } + return 0; +} /* csrot_ */ + +/* Subroutine */ int csscal_(integer *n, real *sa, complex *cx, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + real r__1, r__2; + complex q__1; + + /* Local variables */ + static integer i__, nincx; + + +/* + Purpose + ======= + + CSSCAL scales a complex vector by a real constant. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cx; + + /* Function Body */ + if (*n <= 0 || *incx <= 0) { + return 0; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + nincx = *n * *incx; + i__1 = nincx; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + i__3 = i__; + i__4 = i__; + r__1 = *sa * cx[i__4].r; + r__2 = *sa * r_imag(&cx[i__]); + q__1.r = r__1, q__1.i = r__2; + cx[i__3].r = q__1.r, cx[i__3].i = q__1.i; +/* L10: */ + } + return 0; + +/* code for increment equal to 1 */ + +L20: + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__1 = i__; + i__3 = i__; + r__1 = *sa * cx[i__3].r; + r__2 = *sa * r_imag(&cx[i__]); + q__1.r = r__1, q__1.i = r__2; + cx[i__1].r = q__1.r, cx[i__1].i = q__1.i; +/* L30: */ + } + return 0; +} /* csscal_ */ + +/* Subroutine */ int cswap_(integer *n, complex *cx, integer *incx, complex * + cy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + + /* Local variables */ + static integer i__, ix, iy; + static complex ctemp; + + +/* + Purpose + ======= + + CSWAP interchanges two vectors. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments not equal + to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + ctemp.r = cx[i__2].r, ctemp.i = cx[i__2].i; + i__2 = ix; + i__3 = iy; + cx[i__2].r = cy[i__3].r, cx[i__2].i = cy[i__3].i; + i__2 = iy; + cy[i__2].r = ctemp.r, cy[i__2].i = ctemp.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + ctemp.r = cx[i__2].r, ctemp.i = cx[i__2].i; + i__2 = i__; + i__3 = i__; + cx[i__2].r = cy[i__3].r, cx[i__2].i = cy[i__3].i; + i__2 = i__; + cy[i__2].r = ctemp.r, cy[i__2].i = ctemp.i; +/* L30: */ + } + return 0; +} /* cswap_ */ + +/* Subroutine */ int ctrmm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, complex *alpha, complex *a, integer *lda, + complex *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4, i__5, + i__6; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, j, k, info; + static complex temp; + extern logical lsame_(char *, char *); + static logical lside; + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj, nounit; + + +/* + Purpose + ======= + + CTRMM performs one of the matrix-matrix operations + + B := alpha*op( A )*B, or B := alpha*B*op( A ) + + where alpha is a scalar, B is an m by n matrix, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A' or op( A ) = conjg( A' ). + + Arguments + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) multiplies B from + the left or right as follows: + + SIDE = 'L' or 'l' B := alpha*op( A )*B. + + SIDE = 'R' or 'r' B := alpha*B*op( A ). + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = conjg( A' ). + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - COMPLEX array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the matrix B, and on exit is overwritten by the + transformed matrix. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + noconj = lsame_(transa, "T"); + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("CTRMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (alpha->r == 0.f && alpha->i == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + b[i__3].r = 0.f, b[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*A*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + i__3 = k + j * b_dim1; + if (b[i__3].r != 0.f || b[i__3].i != 0.f) { + i__3 = k + j * b_dim1; + q__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3] + .i, q__1.i = alpha->r * b[i__3].i + + alpha->i * b[i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + i__3 = k - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = i__ + k * a_dim1; + q__2.r = temp.r * a[i__6].r - temp.i * a[i__6] + .i, q__2.i = temp.r * a[i__6].i + + temp.i * a[i__6].r; + q__1.r = b[i__5].r + q__2.r, q__1.i = b[i__5] + .i + q__2.i; + b[i__4].r = q__1.r, b[i__4].i = q__1.i; +/* L30: */ + } + if (nounit) { + i__3 = k + k * a_dim1; + q__1.r = temp.r * a[i__3].r - temp.i * a[i__3] + .i, q__1.i = temp.r * a[i__3].i + + temp.i * a[i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__3 = k + j * b_dim1; + b[i__3].r = temp.r, b[i__3].i = temp.i; + } +/* L40: */ + } +/* L50: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (k = *m; k >= 1; --k) { + i__2 = k + j * b_dim1; + if (b[i__2].r != 0.f || b[i__2].i != 0.f) { + i__2 = k + j * b_dim1; + q__1.r = alpha->r * b[i__2].r - alpha->i * b[i__2] + .i, q__1.i = alpha->r * b[i__2].i + + alpha->i * b[i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + i__2 = k + j * b_dim1; + b[i__2].r = temp.r, b[i__2].i = temp.i; + if (nounit) { + i__2 = k + j * b_dim1; + i__3 = k + j * b_dim1; + i__4 = k + k * a_dim1; + q__1.r = b[i__3].r * a[i__4].r - b[i__3].i * + a[i__4].i, q__1.i = b[i__3].r * a[ + i__4].i + b[i__3].i * a[i__4].r; + b[i__2].r = q__1.r, b[i__2].i = q__1.i; + } + i__2 = *m; + for (i__ = k + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = i__ + k * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5] + .i, q__2.i = temp.r * a[i__5].i + + temp.i * a[i__5].r; + q__1.r = b[i__4].r + q__2.r, q__1.i = b[i__4] + .i + q__2.i; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L60: */ + } + } +/* L70: */ + } +/* L80: */ + } + } + } else { + +/* Form B := alpha*A'*B or B := alpha*conjg( A' )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + i__2 = i__ + j * b_dim1; + temp.r = b[i__2].r, temp.i = b[i__2].i; + if (noconj) { + if (nounit) { + i__2 = i__ + i__ * a_dim1; + q__1.r = temp.r * a[i__2].r - temp.i * a[i__2] + .i, q__1.i = temp.r * a[i__2].i + + temp.i * a[i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = i__ - 1; + for (k = 1; k <= i__2; ++k) { + i__3 = k + i__ * a_dim1; + i__4 = k + j * b_dim1; + q__2.r = a[i__3].r * b[i__4].r - a[i__3].i * + b[i__4].i, q__2.i = a[i__3].r * b[ + i__4].i + a[i__3].i * b[i__4].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L90: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[i__ + i__ * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = i__ - 1; + for (k = 1; k <= i__2; ++k) { + r_cnjg(&q__3, &a[k + i__ * a_dim1]); + i__3 = k + j * b_dim1; + q__2.r = q__3.r * b[i__3].r - q__3.i * b[i__3] + .i, q__2.i = q__3.r * b[i__3].i + + q__3.i * b[i__3].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L100: */ + } + } + i__2 = i__ + j * b_dim1; + q__1.r = alpha->r * temp.r - alpha->i * temp.i, + q__1.i = alpha->r * temp.i + alpha->i * + temp.r; + b[i__2].r = q__1.r, b[i__2].i = q__1.i; +/* L110: */ + } +/* L120: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + temp.r = b[i__3].r, temp.i = b[i__3].i; + if (noconj) { + if (nounit) { + i__3 = i__ + i__ * a_dim1; + q__1.r = temp.r * a[i__3].r - temp.i * a[i__3] + .i, q__1.i = temp.r * a[i__3].i + + temp.i * a[i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__3 = *m; + for (k = i__ + 1; k <= i__3; ++k) { + i__4 = k + i__ * a_dim1; + i__5 = k + j * b_dim1; + q__2.r = a[i__4].r * b[i__5].r - a[i__4].i * + b[i__5].i, q__2.i = a[i__4].r * b[ + i__5].i + a[i__4].i * b[i__5].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L130: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[i__ + i__ * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__3 = *m; + for (k = i__ + 1; k <= i__3; ++k) { + r_cnjg(&q__3, &a[k + i__ * a_dim1]); + i__4 = k + j * b_dim1; + q__2.r = q__3.r * b[i__4].r - q__3.i * b[i__4] + .i, q__2.i = q__3.r * b[i__4].i + + q__3.i * b[i__4].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L140: */ + } + } + i__3 = i__ + j * b_dim1; + q__1.r = alpha->r * temp.r - alpha->i * temp.i, + q__1.i = alpha->r * temp.i + alpha->i * + temp.r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L150: */ + } +/* L160: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*A. */ + + if (upper) { + for (j = *n; j >= 1; --j) { + temp.r = alpha->r, temp.i = alpha->i; + if (nounit) { + i__1 = j + j * a_dim1; + q__1.r = temp.r * a[i__1].r - temp.i * a[i__1].i, + q__1.i = temp.r * a[i__1].i + temp.i * a[i__1] + .r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * b_dim1; + i__3 = i__ + j * b_dim1; + q__1.r = temp.r * b[i__3].r - temp.i * b[i__3].i, + q__1.i = temp.r * b[i__3].i + temp.i * b[i__3] + .r; + b[i__2].r = q__1.r, b[i__2].i = q__1.i; +/* L170: */ + } + i__1 = j - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = k + j * a_dim1; + if (a[i__2].r != 0.f || a[i__2].i != 0.f) { + i__2 = k + j * a_dim1; + q__1.r = alpha->r * a[i__2].r - alpha->i * a[i__2] + .i, q__1.i = alpha->r * a[i__2].i + + alpha->i * a[i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = i__ + k * b_dim1; + q__2.r = temp.r * b[i__5].r - temp.i * b[i__5] + .i, q__2.i = temp.r * b[i__5].i + + temp.i * b[i__5].r; + q__1.r = b[i__4].r + q__2.r, q__1.i = b[i__4] + .i + q__2.i; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L180: */ + } + } +/* L190: */ + } +/* L200: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp.r = alpha->r, temp.i = alpha->i; + if (nounit) { + i__2 = j + j * a_dim1; + q__1.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + q__1.i = temp.r * a[i__2].i + temp.i * a[i__2] + .r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + q__1.r = temp.r * b[i__4].r - temp.i * b[i__4].i, + q__1.i = temp.r * b[i__4].i + temp.i * b[i__4] + .r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L210: */ + } + i__2 = *n; + for (k = j + 1; k <= i__2; ++k) { + i__3 = k + j * a_dim1; + if (a[i__3].r != 0.f || a[i__3].i != 0.f) { + i__3 = k + j * a_dim1; + q__1.r = alpha->r * a[i__3].r - alpha->i * a[i__3] + .i, q__1.i = alpha->r * a[i__3].i + + alpha->i * a[i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = i__ + k * b_dim1; + q__2.r = temp.r * b[i__6].r - temp.i * b[i__6] + .i, q__2.i = temp.r * b[i__6].i + + temp.i * b[i__6].r; + q__1.r = b[i__5].r + q__2.r, q__1.i = b[i__5] + .i + q__2.i; + b[i__4].r = q__1.r, b[i__4].i = q__1.i; +/* L220: */ + } + } +/* L230: */ + } +/* L240: */ + } + } + } else { + +/* Form B := alpha*B*A' or B := alpha*B*conjg( A' ). */ + + if (upper) { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + i__2 = k - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = j + k * a_dim1; + if (a[i__3].r != 0.f || a[i__3].i != 0.f) { + if (noconj) { + i__3 = j + k * a_dim1; + q__1.r = alpha->r * a[i__3].r - alpha->i * a[ + i__3].i, q__1.i = alpha->r * a[i__3] + .i + alpha->i * a[i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + } else { + r_cnjg(&q__2, &a[j + k * a_dim1]); + q__1.r = alpha->r * q__2.r - alpha->i * + q__2.i, q__1.i = alpha->r * q__2.i + + alpha->i * q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = i__ + k * b_dim1; + q__2.r = temp.r * b[i__6].r - temp.i * b[i__6] + .i, q__2.i = temp.r * b[i__6].i + + temp.i * b[i__6].r; + q__1.r = b[i__5].r + q__2.r, q__1.i = b[i__5] + .i + q__2.i; + b[i__4].r = q__1.r, b[i__4].i = q__1.i; +/* L250: */ + } + } +/* L260: */ + } + temp.r = alpha->r, temp.i = alpha->i; + if (nounit) { + if (noconj) { + i__2 = k + k * a_dim1; + q__1.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + q__1.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + } else { + r_cnjg(&q__2, &a[k + k * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + } + if (temp.r != 1.f || temp.i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + k * b_dim1; + i__4 = i__ + k * b_dim1; + q__1.r = temp.r * b[i__4].r - temp.i * b[i__4].i, + q__1.i = temp.r * b[i__4].i + temp.i * b[ + i__4].r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L270: */ + } + } +/* L280: */ + } + } else { + for (k = *n; k >= 1; --k) { + i__1 = *n; + for (j = k + 1; j <= i__1; ++j) { + i__2 = j + k * a_dim1; + if (a[i__2].r != 0.f || a[i__2].i != 0.f) { + if (noconj) { + i__2 = j + k * a_dim1; + q__1.r = alpha->r * a[i__2].r - alpha->i * a[ + i__2].i, q__1.i = alpha->r * a[i__2] + .i + alpha->i * a[i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + } else { + r_cnjg(&q__2, &a[j + k * a_dim1]); + q__1.r = alpha->r * q__2.r - alpha->i * + q__2.i, q__1.i = alpha->r * q__2.i + + alpha->i * q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = i__ + k * b_dim1; + q__2.r = temp.r * b[i__5].r - temp.i * b[i__5] + .i, q__2.i = temp.r * b[i__5].i + + temp.i * b[i__5].r; + q__1.r = b[i__4].r + q__2.r, q__1.i = b[i__4] + .i + q__2.i; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L290: */ + } + } +/* L300: */ + } + temp.r = alpha->r, temp.i = alpha->i; + if (nounit) { + if (noconj) { + i__1 = k + k * a_dim1; + q__1.r = temp.r * a[i__1].r - temp.i * a[i__1].i, + q__1.i = temp.r * a[i__1].i + temp.i * a[ + i__1].r; + temp.r = q__1.r, temp.i = q__1.i; + } else { + r_cnjg(&q__2, &a[k + k * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + } + if (temp.r != 1.f || temp.i != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + k * b_dim1; + i__3 = i__ + k * b_dim1; + q__1.r = temp.r * b[i__3].r - temp.i * b[i__3].i, + q__1.i = temp.r * b[i__3].i + temp.i * b[ + i__3].r; + b[i__2].r = q__1.r, b[i__2].i = q__1.i; +/* L310: */ + } + } +/* L320: */ + } + } + } + } + + return 0; + +/* End of CTRMM . */ + +} /* ctrmm_ */ + +/* Subroutine */ int ctrmv_(char *uplo, char *trans, char *diag, integer *n, + complex *a, integer *lda, complex *x, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, j, ix, jx, kx, info; + static complex temp; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj, nounit; + + +/* + Purpose + ======= + + CTRMV performs one of the matrix-vector operations + + x := A*x, or x := A'*x, or x := conjg( A' )*x, + + where x is an n element vector and A is an n by n unit, or non-unit, + upper or lower triangular matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' x := A*x. + + TRANS = 'T' or 't' x := A'*x. + + TRANS = 'C' or 'c' x := conjg( A' )*x. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit + triangular as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - COMPLEX array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. On exit, X is overwritten with the + tranformed vector x. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < max(1,*n)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } + if (info != 0) { + xerbla_("CTRMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + noconj = lsame_(trans, "T"); + nounit = lsame_(diag, "N"); + +/* + Set up the start point in X if the increment is not unity. This + will be ( N - 1 )*INCX too small for descending loops. +*/ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (lsame_(trans, "N")) { + +/* Form x := A*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + if (x[i__2].r != 0.f || x[i__2].i != 0.f) { + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + q__1.r = x[i__4].r + q__2.r, q__1.i = x[i__4].i + + q__2.i; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; +/* L10: */ + } + if (nounit) { + i__2 = j; + i__3 = j; + i__4 = j + j * a_dim1; + q__1.r = x[i__3].r * a[i__4].r - x[i__3].i * a[ + i__4].i, q__1.i = x[i__3].r * a[i__4].i + + x[i__3].i * a[i__4].r; + x[i__2].r = q__1.r, x[i__2].i = q__1.i; + } + } +/* L20: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + if (x[i__2].r != 0.f || x[i__2].i != 0.f) { + i__2 = jx; + temp.r = x[i__2].r, temp.i = x[i__2].i; + ix = kx; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = ix; + i__4 = ix; + i__5 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + q__1.r = x[i__4].r + q__2.r, q__1.i = x[i__4].i + + q__2.i; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + ix += *incx; +/* L30: */ + } + if (nounit) { + i__2 = jx; + i__3 = jx; + i__4 = j + j * a_dim1; + q__1.r = x[i__3].r * a[i__4].r - x[i__3].i * a[ + i__4].i, q__1.i = x[i__3].r * a[i__4].i + + x[i__3].i * a[i__4].r; + x[i__2].r = q__1.r, x[i__2].i = q__1.i; + } + } + jx += *incx; +/* L40: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + if (x[i__1].r != 0.f || x[i__1].i != 0.f) { + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + i__2 = i__; + i__3 = i__; + i__4 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__4].r - temp.i * a[i__4].i, + q__2.i = temp.r * a[i__4].i + temp.i * a[ + i__4].r; + q__1.r = x[i__3].r + q__2.r, q__1.i = x[i__3].i + + q__2.i; + x[i__2].r = q__1.r, x[i__2].i = q__1.i; +/* L50: */ + } + if (nounit) { + i__1 = j; + i__2 = j; + i__3 = j + j * a_dim1; + q__1.r = x[i__2].r * a[i__3].r - x[i__2].i * a[ + i__3].i, q__1.i = x[i__2].r * a[i__3].i + + x[i__2].i * a[i__3].r; + x[i__1].r = q__1.r, x[i__1].i = q__1.i; + } + } +/* L60: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + i__1 = jx; + if (x[i__1].r != 0.f || x[i__1].i != 0.f) { + i__1 = jx; + temp.r = x[i__1].r, temp.i = x[i__1].i; + ix = kx; + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + i__2 = ix; + i__3 = ix; + i__4 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__4].r - temp.i * a[i__4].i, + q__2.i = temp.r * a[i__4].i + temp.i * a[ + i__4].r; + q__1.r = x[i__3].r + q__2.r, q__1.i = x[i__3].i + + q__2.i; + x[i__2].r = q__1.r, x[i__2].i = q__1.i; + ix -= *incx; +/* L70: */ + } + if (nounit) { + i__1 = jx; + i__2 = jx; + i__3 = j + j * a_dim1; + q__1.r = x[i__2].r * a[i__3].r - x[i__2].i * a[ + i__3].i, q__1.i = x[i__2].r * a[i__3].i + + x[i__2].i * a[i__3].r; + x[i__1].r = q__1.r, x[i__1].i = q__1.i; + } + } + jx -= *incx; +/* L80: */ + } + } + } + } else { + +/* Form x := A'*x or x := conjg( A' )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + if (noconj) { + if (nounit) { + i__1 = j + j * a_dim1; + q__1.r = temp.r * a[i__1].r - temp.i * a[i__1].i, + q__1.i = temp.r * a[i__1].i + temp.i * a[ + i__1].r; + temp.r = q__1.r, temp.i = q__1.i; + } + for (i__ = j - 1; i__ >= 1; --i__) { + i__1 = i__ + j * a_dim1; + i__2 = i__; + q__2.r = a[i__1].r * x[i__2].r - a[i__1].i * x[ + i__2].i, q__2.i = a[i__1].r * x[i__2].i + + a[i__1].i * x[i__2].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L90: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + for (i__ = j - 1; i__ >= 1; --i__) { + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__1 = i__; + q__2.r = q__3.r * x[i__1].r - q__3.i * x[i__1].i, + q__2.i = q__3.r * x[i__1].i + q__3.i * x[ + i__1].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L100: */ + } + } + i__1 = j; + x[i__1].r = temp.r, x[i__1].i = temp.i; +/* L110: */ + } + } else { + jx = kx + (*n - 1) * *incx; + for (j = *n; j >= 1; --j) { + i__1 = jx; + temp.r = x[i__1].r, temp.i = x[i__1].i; + ix = jx; + if (noconj) { + if (nounit) { + i__1 = j + j * a_dim1; + q__1.r = temp.r * a[i__1].r - temp.i * a[i__1].i, + q__1.i = temp.r * a[i__1].i + temp.i * a[ + i__1].r; + temp.r = q__1.r, temp.i = q__1.i; + } + for (i__ = j - 1; i__ >= 1; --i__) { + ix -= *incx; + i__1 = i__ + j * a_dim1; + i__2 = ix; + q__2.r = a[i__1].r * x[i__2].r - a[i__1].i * x[ + i__2].i, q__2.i = a[i__1].r * x[i__2].i + + a[i__1].i * x[i__2].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L120: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + for (i__ = j - 1; i__ >= 1; --i__) { + ix -= *incx; + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__1 = ix; + q__2.r = q__3.r * x[i__1].r - q__3.i * x[i__1].i, + q__2.i = q__3.r * x[i__1].i + q__3.i * x[ + i__1].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L130: */ + } + } + i__1 = jx; + x[i__1].r = temp.r, x[i__1].i = temp.i; + jx -= *incx; +/* L140: */ + } + } + } else { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + if (noconj) { + if (nounit) { + i__2 = j + j * a_dim1; + q__1.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + q__1.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__; + q__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[ + i__4].i, q__2.i = a[i__3].r * x[i__4].i + + a[i__3].i * x[i__4].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L150: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = i__; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, + q__2.i = q__3.r * x[i__3].i + q__3.i * x[ + i__3].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L160: */ + } + } + i__2 = j; + x[i__2].r = temp.r, x[i__2].i = temp.i; +/* L170: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + temp.r = x[i__2].r, temp.i = x[i__2].i; + ix = jx; + if (noconj) { + if (nounit) { + i__2 = j + j * a_dim1; + q__1.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + q__1.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + i__3 = i__ + j * a_dim1; + i__4 = ix; + q__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[ + i__4].i, q__2.i = a[i__3].r * x[i__4].i + + a[i__3].i * x[i__4].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L180: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = ix; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, + q__2.i = q__3.r * x[i__3].i + q__3.i * x[ + i__3].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L190: */ + } + } + i__2 = jx; + x[i__2].r = temp.r, x[i__2].i = temp.i; + jx += *incx; +/* L200: */ + } + } + } + } + + return 0; + +/* End of CTRMV . */ + +} /* ctrmv_ */ + +/* Subroutine */ int ctrsm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, complex *alpha, complex *a, integer *lda, + complex *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4, i__5, + i__6, i__7; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, j, k, info; + static complex temp; + extern logical lsame_(char *, char *); + static logical lside; + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj, nounit; + + +/* + Purpose + ======= + + CTRSM solves one of the matrix equations + + op( A )*X = alpha*B, or X*op( A ) = alpha*B, + + where alpha is a scalar, X and B are m by n matrices, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A' or op( A ) = conjg( A' ). + + The matrix X is overwritten on B. + + Arguments + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) appears on the left + or right of X as follows: + + SIDE = 'L' or 'l' op( A )*X = alpha*B. + + SIDE = 'R' or 'r' X*op( A ) = alpha*B. + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = conjg( A' ). + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - COMPLEX . + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - COMPLEX array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the right-hand side matrix B, and on exit is + overwritten by the solution matrix X. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + noconj = lsame_(transa, "T"); + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("CTRSM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (alpha->r == 0.f && alpha->i == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + b[i__3].r = 0.f, b[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*inv( A )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (alpha->r != 1.f || alpha->i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + q__1.r = alpha->r * b[i__4].r - alpha->i * b[i__4] + .i, q__1.i = alpha->r * b[i__4].i + + alpha->i * b[i__4].r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L30: */ + } + } + for (k = *m; k >= 1; --k) { + i__2 = k + j * b_dim1; + if (b[i__2].r != 0.f || b[i__2].i != 0.f) { + if (nounit) { + i__2 = k + j * b_dim1; + c_div(&q__1, &b[k + j * b_dim1], &a[k + k * + a_dim1]); + b[i__2].r = q__1.r, b[i__2].i = q__1.i; + } + i__2 = k - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = k + j * b_dim1; + i__6 = i__ + k * a_dim1; + q__2.r = b[i__5].r * a[i__6].r - b[i__5].i * + a[i__6].i, q__2.i = b[i__5].r * a[ + i__6].i + b[i__5].i * a[i__6].r; + q__1.r = b[i__4].r - q__2.r, q__1.i = b[i__4] + .i - q__2.i; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L40: */ + } + } +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (alpha->r != 1.f || alpha->i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + q__1.r = alpha->r * b[i__4].r - alpha->i * b[i__4] + .i, q__1.i = alpha->r * b[i__4].i + + alpha->i * b[i__4].r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L70: */ + } + } + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + i__3 = k + j * b_dim1; + if (b[i__3].r != 0.f || b[i__3].i != 0.f) { + if (nounit) { + i__3 = k + j * b_dim1; + c_div(&q__1, &b[k + j * b_dim1], &a[k + k * + a_dim1]); + b[i__3].r = q__1.r, b[i__3].i = q__1.i; + } + i__3 = *m; + for (i__ = k + 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = k + j * b_dim1; + i__7 = i__ + k * a_dim1; + q__2.r = b[i__6].r * a[i__7].r - b[i__6].i * + a[i__7].i, q__2.i = b[i__6].r * a[ + i__7].i + b[i__6].i * a[i__7].r; + q__1.r = b[i__5].r - q__2.r, q__1.i = b[i__5] + .i - q__2.i; + b[i__4].r = q__1.r, b[i__4].i = q__1.i; +/* L80: */ + } + } +/* L90: */ + } +/* L100: */ + } + } + } else { + +/* + Form B := alpha*inv( A' )*B + or B := alpha*inv( conjg( A' ) )*B. +*/ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + q__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3].i, + q__1.i = alpha->r * b[i__3].i + alpha->i * b[ + i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + if (noconj) { + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + i__4 = k + i__ * a_dim1; + i__5 = k + j * b_dim1; + q__2.r = a[i__4].r * b[i__5].r - a[i__4].i * + b[i__5].i, q__2.i = a[i__4].r * b[ + i__5].i + a[i__4].i * b[i__5].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L110: */ + } + if (nounit) { + c_div(&q__1, &temp, &a[i__ + i__ * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } + } else { + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + r_cnjg(&q__3, &a[k + i__ * a_dim1]); + i__4 = k + j * b_dim1; + q__2.r = q__3.r * b[i__4].r - q__3.i * b[i__4] + .i, q__2.i = q__3.r * b[i__4].i + + q__3.i * b[i__4].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L120: */ + } + if (nounit) { + r_cnjg(&q__2, &a[i__ + i__ * a_dim1]); + c_div(&q__1, &temp, &q__2); + temp.r = q__1.r, temp.i = q__1.i; + } + } + i__3 = i__ + j * b_dim1; + b[i__3].r = temp.r, b[i__3].i = temp.i; +/* L130: */ + } +/* L140: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + i__2 = i__ + j * b_dim1; + q__1.r = alpha->r * b[i__2].r - alpha->i * b[i__2].i, + q__1.i = alpha->r * b[i__2].i + alpha->i * b[ + i__2].r; + temp.r = q__1.r, temp.i = q__1.i; + if (noconj) { + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + i__3 = k + i__ * a_dim1; + i__4 = k + j * b_dim1; + q__2.r = a[i__3].r * b[i__4].r - a[i__3].i * + b[i__4].i, q__2.i = a[i__3].r * b[ + i__4].i + a[i__3].i * b[i__4].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L150: */ + } + if (nounit) { + c_div(&q__1, &temp, &a[i__ + i__ * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } + } else { + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + r_cnjg(&q__3, &a[k + i__ * a_dim1]); + i__3 = k + j * b_dim1; + q__2.r = q__3.r * b[i__3].r - q__3.i * b[i__3] + .i, q__2.i = q__3.r * b[i__3].i + + q__3.i * b[i__3].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L160: */ + } + if (nounit) { + r_cnjg(&q__2, &a[i__ + i__ * a_dim1]); + c_div(&q__1, &temp, &q__2); + temp.r = q__1.r, temp.i = q__1.i; + } + } + i__2 = i__ + j * b_dim1; + b[i__2].r = temp.r, b[i__2].i = temp.i; +/* L170: */ + } +/* L180: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*inv( A ). */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (alpha->r != 1.f || alpha->i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + q__1.r = alpha->r * b[i__4].r - alpha->i * b[i__4] + .i, q__1.i = alpha->r * b[i__4].i + + alpha->i * b[i__4].r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L190: */ + } + } + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + i__3 = k + j * a_dim1; + if (a[i__3].r != 0.f || a[i__3].i != 0.f) { + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = k + j * a_dim1; + i__7 = i__ + k * b_dim1; + q__2.r = a[i__6].r * b[i__7].r - a[i__6].i * + b[i__7].i, q__2.i = a[i__6].r * b[ + i__7].i + a[i__6].i * b[i__7].r; + q__1.r = b[i__5].r - q__2.r, q__1.i = b[i__5] + .i - q__2.i; + b[i__4].r = q__1.r, b[i__4].i = q__1.i; +/* L200: */ + } + } +/* L210: */ + } + if (nounit) { + c_div(&q__1, &c_b21, &a[j + j * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + q__1.r = temp.r * b[i__4].r - temp.i * b[i__4].i, + q__1.i = temp.r * b[i__4].i + temp.i * b[ + i__4].r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L220: */ + } + } +/* L230: */ + } + } else { + for (j = *n; j >= 1; --j) { + if (alpha->r != 1.f || alpha->i != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * b_dim1; + i__3 = i__ + j * b_dim1; + q__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3] + .i, q__1.i = alpha->r * b[i__3].i + + alpha->i * b[i__3].r; + b[i__2].r = q__1.r, b[i__2].i = q__1.i; +/* L240: */ + } + } + i__1 = *n; + for (k = j + 1; k <= i__1; ++k) { + i__2 = k + j * a_dim1; + if (a[i__2].r != 0.f || a[i__2].i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = k + j * a_dim1; + i__6 = i__ + k * b_dim1; + q__2.r = a[i__5].r * b[i__6].r - a[i__5].i * + b[i__6].i, q__2.i = a[i__5].r * b[ + i__6].i + a[i__5].i * b[i__6].r; + q__1.r = b[i__4].r - q__2.r, q__1.i = b[i__4] + .i - q__2.i; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L250: */ + } + } +/* L260: */ + } + if (nounit) { + c_div(&q__1, &c_b21, &a[j + j * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * b_dim1; + i__3 = i__ + j * b_dim1; + q__1.r = temp.r * b[i__3].r - temp.i * b[i__3].i, + q__1.i = temp.r * b[i__3].i + temp.i * b[ + i__3].r; + b[i__2].r = q__1.r, b[i__2].i = q__1.i; +/* L270: */ + } + } +/* L280: */ + } + } + } else { + +/* + Form B := alpha*B*inv( A' ) + or B := alpha*B*inv( conjg( A' ) ). +*/ + + if (upper) { + for (k = *n; k >= 1; --k) { + if (nounit) { + if (noconj) { + c_div(&q__1, &c_b21, &a[k + k * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } else { + r_cnjg(&q__2, &a[k + k * a_dim1]); + c_div(&q__1, &c_b21, &q__2); + temp.r = q__1.r, temp.i = q__1.i; + } + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + k * b_dim1; + i__3 = i__ + k * b_dim1; + q__1.r = temp.r * b[i__3].r - temp.i * b[i__3].i, + q__1.i = temp.r * b[i__3].i + temp.i * b[ + i__3].r; + b[i__2].r = q__1.r, b[i__2].i = q__1.i; +/* L290: */ + } + } + i__1 = k - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = j + k * a_dim1; + if (a[i__2].r != 0.f || a[i__2].i != 0.f) { + if (noconj) { + i__2 = j + k * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + } else { + r_cnjg(&q__1, &a[j + k * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = i__ + k * b_dim1; + q__2.r = temp.r * b[i__5].r - temp.i * b[i__5] + .i, q__2.i = temp.r * b[i__5].i + + temp.i * b[i__5].r; + q__1.r = b[i__4].r - q__2.r, q__1.i = b[i__4] + .i - q__2.i; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L300: */ + } + } +/* L310: */ + } + if (alpha->r != 1.f || alpha->i != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + k * b_dim1; + i__3 = i__ + k * b_dim1; + q__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3] + .i, q__1.i = alpha->r * b[i__3].i + + alpha->i * b[i__3].r; + b[i__2].r = q__1.r, b[i__2].i = q__1.i; +/* L320: */ + } + } +/* L330: */ + } + } else { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + if (nounit) { + if (noconj) { + c_div(&q__1, &c_b21, &a[k + k * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } else { + r_cnjg(&q__2, &a[k + k * a_dim1]); + c_div(&q__1, &c_b21, &q__2); + temp.r = q__1.r, temp.i = q__1.i; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + k * b_dim1; + i__4 = i__ + k * b_dim1; + q__1.r = temp.r * b[i__4].r - temp.i * b[i__4].i, + q__1.i = temp.r * b[i__4].i + temp.i * b[ + i__4].r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L340: */ + } + } + i__2 = *n; + for (j = k + 1; j <= i__2; ++j) { + i__3 = j + k * a_dim1; + if (a[i__3].r != 0.f || a[i__3].i != 0.f) { + if (noconj) { + i__3 = j + k * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + } else { + r_cnjg(&q__1, &a[j + k * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = i__ + k * b_dim1; + q__2.r = temp.r * b[i__6].r - temp.i * b[i__6] + .i, q__2.i = temp.r * b[i__6].i + + temp.i * b[i__6].r; + q__1.r = b[i__5].r - q__2.r, q__1.i = b[i__5] + .i - q__2.i; + b[i__4].r = q__1.r, b[i__4].i = q__1.i; +/* L350: */ + } + } +/* L360: */ + } + if (alpha->r != 1.f || alpha->i != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + k * b_dim1; + i__4 = i__ + k * b_dim1; + q__1.r = alpha->r * b[i__4].r - alpha->i * b[i__4] + .i, q__1.i = alpha->r * b[i__4].i + + alpha->i * b[i__4].r; + b[i__3].r = q__1.r, b[i__3].i = q__1.i; +/* L370: */ + } + } +/* L380: */ + } + } + } + } + + return 0; + +/* End of CTRSM . */ + +} /* ctrsm_ */ + +/* Subroutine */ int ctrsv_(char *uplo, char *trans, char *diag, integer *n, + complex *a, integer *lda, complex *x, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, j, ix, jx, kx, info; + static complex temp; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj, nounit; + + +/* + Purpose + ======= + + CTRSV solves one of the systems of equations + + A*x = b, or A'*x = b, or conjg( A' )*x = b, + + where b and x are n element vectors and A is an n by n unit, or + non-unit, upper or lower triangular matrix. + + No test for singularity or near-singularity is included in this + routine. Such tests must be performed before calling this routine. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the equations to be solved as + follows: + + TRANS = 'N' or 'n' A*x = b. + + TRANS = 'T' or 't' A'*x = b. + + TRANS = 'C' or 'c' conjg( A' )*x = b. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit + triangular as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + A - COMPLEX array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - COMPLEX array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element right-hand side vector b. On exit, X is overwritten + with the solution vector x. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < max(1,*n)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } + if (info != 0) { + xerbla_("CTRSV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + noconj = lsame_(trans, "T"); + nounit = lsame_(diag, "N"); + +/* + Set up the start point in X if the increment is not unity. This + will be ( N - 1 )*INCX too small for descending loops. +*/ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (lsame_(trans, "N")) { + +/* Form x := inv( A )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + if (x[i__1].r != 0.f || x[i__1].i != 0.f) { + if (nounit) { + i__1 = j; + c_div(&q__1, &x[j], &a[j + j * a_dim1]); + x[i__1].r = q__1.r, x[i__1].i = q__1.i; + } + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + for (i__ = j - 1; i__ >= 1; --i__) { + i__1 = i__; + i__2 = i__; + i__3 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__3].r - temp.i * a[i__3].i, + q__2.i = temp.r * a[i__3].i + temp.i * a[ + i__3].r; + q__1.r = x[i__2].r - q__2.r, q__1.i = x[i__2].i - + q__2.i; + x[i__1].r = q__1.r, x[i__1].i = q__1.i; +/* L10: */ + } + } +/* L20: */ + } + } else { + jx = kx + (*n - 1) * *incx; + for (j = *n; j >= 1; --j) { + i__1 = jx; + if (x[i__1].r != 0.f || x[i__1].i != 0.f) { + if (nounit) { + i__1 = jx; + c_div(&q__1, &x[jx], &a[j + j * a_dim1]); + x[i__1].r = q__1.r, x[i__1].i = q__1.i; + } + i__1 = jx; + temp.r = x[i__1].r, temp.i = x[i__1].i; + ix = jx; + for (i__ = j - 1; i__ >= 1; --i__) { + ix -= *incx; + i__1 = ix; + i__2 = ix; + i__3 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__3].r - temp.i * a[i__3].i, + q__2.i = temp.r * a[i__3].i + temp.i * a[ + i__3].r; + q__1.r = x[i__2].r - q__2.r, q__1.i = x[i__2].i - + q__2.i; + x[i__1].r = q__1.r, x[i__1].i = q__1.i; +/* L30: */ + } + } + jx -= *incx; +/* L40: */ + } + } + } else { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + if (x[i__2].r != 0.f || x[i__2].i != 0.f) { + if (nounit) { + i__2 = j; + c_div(&q__1, &x[j], &a[j + j * a_dim1]); + x[i__2].r = q__1.r, x[i__2].i = q__1.i; + } + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + q__1.r = x[i__4].r - q__2.r, q__1.i = x[i__4].i - + q__2.i; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; +/* L50: */ + } + } +/* L60: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + if (x[i__2].r != 0.f || x[i__2].i != 0.f) { + if (nounit) { + i__2 = jx; + c_div(&q__1, &x[jx], &a[j + j * a_dim1]); + x[i__2].r = q__1.r, x[i__2].i = q__1.i; + } + i__2 = jx; + temp.r = x[i__2].r, temp.i = x[i__2].i; + ix = jx; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + i__3 = ix; + i__4 = ix; + i__5 = i__ + j * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + q__1.r = x[i__4].r - q__2.r, q__1.i = x[i__4].i - + q__2.i; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } + } else { + +/* Form x := inv( A' )*x or x := inv( conjg( A' ) )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + if (noconj) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__; + q__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[ + i__4].i, q__2.i = a[i__3].r * x[i__4].i + + a[i__3].i * x[i__4].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L90: */ + } + if (nounit) { + c_div(&q__1, &temp, &a[j + j * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } + } else { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = i__; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, + q__2.i = q__3.r * x[i__3].i + q__3.i * x[ + i__3].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L100: */ + } + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + c_div(&q__1, &temp, &q__2); + temp.r = q__1.r, temp.i = q__1.i; + } + } + i__2 = j; + x[i__2].r = temp.r, x[i__2].i = temp.i; +/* L110: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + ix = kx; + i__2 = jx; + temp.r = x[i__2].r, temp.i = x[i__2].i; + if (noconj) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = ix; + q__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[ + i__4].i, q__2.i = a[i__3].r * x[i__4].i + + a[i__3].i * x[i__4].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix += *incx; +/* L120: */ + } + if (nounit) { + c_div(&q__1, &temp, &a[j + j * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } + } else { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__3 = ix; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, + q__2.i = q__3.r * x[i__3].i + q__3.i * x[ + i__3].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix += *incx; +/* L130: */ + } + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + c_div(&q__1, &temp, &q__2); + temp.r = q__1.r, temp.i = q__1.i; + } + } + i__2 = jx; + x[i__2].r = temp.r, x[i__2].i = temp.i; + jx += *incx; +/* L140: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + if (noconj) { + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + i__2 = i__ + j * a_dim1; + i__3 = i__; + q__2.r = a[i__2].r * x[i__3].r - a[i__2].i * x[ + i__3].i, q__2.i = a[i__2].r * x[i__3].i + + a[i__2].i * x[i__3].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L150: */ + } + if (nounit) { + c_div(&q__1, &temp, &a[j + j * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } + } else { + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__2 = i__; + q__2.r = q__3.r * x[i__2].r - q__3.i * x[i__2].i, + q__2.i = q__3.r * x[i__2].i + q__3.i * x[ + i__2].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L160: */ + } + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + c_div(&q__1, &temp, &q__2); + temp.r = q__1.r, temp.i = q__1.i; + } + } + i__1 = j; + x[i__1].r = temp.r, x[i__1].i = temp.i; +/* L170: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + ix = kx; + i__1 = jx; + temp.r = x[i__1].r, temp.i = x[i__1].i; + if (noconj) { + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + i__2 = i__ + j * a_dim1; + i__3 = ix; + q__2.r = a[i__2].r * x[i__3].r - a[i__2].i * x[ + i__3].i, q__2.i = a[i__2].r * x[i__3].i + + a[i__2].i * x[i__3].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix -= *incx; +/* L180: */ + } + if (nounit) { + c_div(&q__1, &temp, &a[j + j * a_dim1]); + temp.r = q__1.r, temp.i = q__1.i; + } + } else { + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + r_cnjg(&q__3, &a[i__ + j * a_dim1]); + i__2 = ix; + q__2.r = q__3.r * x[i__2].r - q__3.i * x[i__2].i, + q__2.i = q__3.r * x[i__2].i + q__3.i * x[ + i__2].r; + q__1.r = temp.r - q__2.r, q__1.i = temp.i - + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix -= *incx; +/* L190: */ + } + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + c_div(&q__1, &temp, &q__2); + temp.r = q__1.r, temp.i = q__1.i; + } + } + i__1 = jx; + x[i__1].r = temp.r, x[i__1].i = temp.i; + jx -= *incx; +/* L200: */ + } + } + } + } + + return 0; + +/* End of CTRSV . */ + +} /* ctrsv_ */ + +/* Subroutine */ int daxpy_(integer *n, doublereal *da, doublereal *dx, + integer *incx, doublereal *dy, integer *incy) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + + +/* + Purpose + ======= + + DAXPY constant times a vector plus a vector. + uses unrolled loops for increments equal to one. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --dy; + --dx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*da == 0.) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dy[iy] += *da * dx[ix]; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 4; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + dy[i__] += *da * dx[i__]; +/* L30: */ + } + if (*n < 4) { + return 0; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 4) { + dy[i__] += *da * dx[i__]; + dy[i__ + 1] += *da * dx[i__ + 1]; + dy[i__ + 2] += *da * dx[i__ + 2]; + dy[i__ + 3] += *da * dx[i__ + 3]; +/* L50: */ + } + return 0; +} /* daxpy_ */ + +doublereal dcabs1_(doublecomplex *z__) +{ + /* System generated locals */ + doublereal ret_val, d__1, d__2; + +/* + Purpose + ======= + + DCABS1 computes absolute value of a double complex number + + ===================================================================== +*/ + + + ret_val = (d__1 = z__->r, abs(d__1)) + (d__2 = d_imag(z__), abs(d__2)); + return ret_val; +} /* dcabs1_ */ + +/* Subroutine */ int dcopy_(integer *n, doublereal *dx, integer *incx, + doublereal *dy, integer *incy) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + + +/* + Purpose + ======= + + DCOPY copies a vector, x, to a vector, y. + uses unrolled loops for increments equal to one. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --dy; + --dx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dy[iy] = dx[ix]; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 7; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + dy[i__] = dx[i__]; +/* L30: */ + } + if (*n < 7) { + return 0; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 7) { + dy[i__] = dx[i__]; + dy[i__ + 1] = dx[i__ + 1]; + dy[i__ + 2] = dx[i__ + 2]; + dy[i__ + 3] = dx[i__ + 3]; + dy[i__ + 4] = dx[i__ + 4]; + dy[i__ + 5] = dx[i__ + 5]; + dy[i__ + 6] = dx[i__ + 6]; +/* L50: */ + } + return 0; +} /* dcopy_ */ + +doublereal ddot_(integer *n, doublereal *dx, integer *incx, doublereal *dy, + integer *incy) +{ + /* System generated locals */ + integer i__1; + doublereal ret_val; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + static doublereal dtemp; + + +/* + Purpose + ======= + + DDOT forms the dot product of two vectors. + uses unrolled loops for increments equal to one. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --dy; + --dx; + + /* Function Body */ + ret_val = 0.; + dtemp = 0.; + if (*n <= 0) { + return ret_val; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dtemp += dx[ix] * dy[iy]; + ix += *incx; + iy += *incy; +/* L10: */ + } + ret_val = dtemp; + return ret_val; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 5; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + dtemp += dx[i__] * dy[i__]; +/* L30: */ + } + if (*n < 5) { + goto L60; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 5) { + dtemp = dtemp + dx[i__] * dy[i__] + dx[i__ + 1] * dy[i__ + 1] + dx[ + i__ + 2] * dy[i__ + 2] + dx[i__ + 3] * dy[i__ + 3] + dx[i__ + + 4] * dy[i__ + 4]; +/* L50: */ + } +L60: + ret_val = dtemp; + return ret_val; +} /* ddot_ */ + +/* Subroutine */ int dgemm_(char *transa, char *transb, integer *m, integer * + n, integer *k, doublereal *alpha, doublereal *a, integer *lda, + doublereal *b, integer *ldb, doublereal *beta, doublereal *c__, + integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3; + + /* Local variables */ + static integer i__, j, l, info; + static logical nota, notb; + static doublereal temp; + static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + DGEMM performs one of the matrix-matrix operations + + C := alpha*op( A )*op( B ) + beta*C, + + where op( X ) is one of + + op( X ) = X or op( X ) = X', + + alpha and beta are scalars, and A, B and C are matrices, with op( A ) + an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. + + Arguments + ========== + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n', op( A ) = A. + + TRANSA = 'T' or 't', op( A ) = A'. + + TRANSA = 'C' or 'c', op( A ) = A'. + + Unchanged on exit. + + TRANSB - CHARACTER*1. + On entry, TRANSB specifies the form of op( B ) to be used in + the matrix multiplication as follows: + + TRANSB = 'N' or 'n', op( B ) = B. + + TRANSB = 'T' or 't', op( B ) = B'. + + TRANSB = 'C' or 'c', op( B ) = B'. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix + op( A ) and of the matrix C. M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix + op( B ) and the number of columns of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry, K specifies the number of columns of the matrix + op( A ) and the number of rows of the matrix op( B ). K must + be at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is + k when TRANSA = 'N' or 'n', and is m otherwise. + Before entry with TRANSA = 'N' or 'n', the leading m by k + part of the array A must contain the matrix A, otherwise + the leading k by m part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANSA = 'N' or 'n' then + LDA must be at least max( 1, m ), otherwise LDA must be at + least max( 1, k ). + Unchanged on exit. + + B - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is + n when TRANSB = 'N' or 'n', and is k otherwise. + Before entry with TRANSB = 'N' or 'n', the leading k by n + part of the array B must contain the matrix B, otherwise + the leading n by k part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANSB = 'N' or 'n' then + LDB must be at least max( 1, k ), otherwise LDB must be at + least max( 1, n ). + Unchanged on exit. + + BETA - DOUBLE PRECISION. + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + Unchanged on exit. + + C - DOUBLE PRECISION array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n matrix + ( alpha*op( A )*op( B ) + beta*C ). + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Set NOTA and NOTB as true if A and B respectively are not + transposed and set NROWA, NCOLA and NROWB as the number of rows + and columns of A and the number of rows of B respectively. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + nota = lsame_(transa, "N"); + notb = lsame_(transb, "N"); + if (nota) { + nrowa = *m; + ncola = *k; + } else { + nrowa = *k; + ncola = *m; + } + if (notb) { + nrowb = *k; + } else { + nrowb = *n; + } + +/* Test the input parameters. */ + + info = 0; + if (! nota && ! lsame_(transa, "C") && ! lsame_( + transa, "T")) { + info = 1; + } else if (! notb && ! lsame_(transb, "C") && ! + lsame_(transb, "T")) { + info = 2; + } else if (*m < 0) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < max(1,nrowa)) { + info = 8; + } else if (*ldb < max(1,nrowb)) { + info = 10; + } else if (*ldc < max(1,*m)) { + info = 13; + } + if (info != 0) { + xerbla_("DGEMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || (*alpha == 0. || *k == 0) && *beta == 1.) { + return 0; + } + +/* And if alpha.eq.zero. */ + + if (*alpha == 0.) { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + return 0; + } + +/* Start the operations. */ + + if (notb) { + if (nota) { + +/* Form C := alpha*A*B + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L50: */ + } + } else if (*beta != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L60: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (b[l + j * b_dim1] != 0.) { + temp = *alpha * b[l + j * b_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L70: */ + } + } +/* L80: */ + } +/* L90: */ + } + } else { + +/* Form C := alpha*A'*B + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * b[l + j * b_dim1]; +/* L100: */ + } + if (*beta == 0.) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L110: */ + } +/* L120: */ + } + } + } else { + if (nota) { + +/* Form C := alpha*A*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L130: */ + } + } else if (*beta != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L140: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (b[j + l * b_dim1] != 0.) { + temp = *alpha * b[j + l * b_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L150: */ + } + } +/* L160: */ + } +/* L170: */ + } + } else { + +/* Form C := alpha*A'*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * b[j + l * b_dim1]; +/* L180: */ + } + if (*beta == 0.) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L190: */ + } +/* L200: */ + } + } + } + + return 0; + +/* End of DGEMM . */ + +} /* dgemm_ */ + +/* Subroutine */ int dgemv_(char *trans, integer *m, integer *n, doublereal * + alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, + doublereal *beta, doublereal *y, integer *incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static doublereal temp; + static integer lenx, leny; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + DGEMV performs one of the matrix-vector operations + + y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, + + where alpha and beta are scalars, x and y are vectors and A is an + m by n matrix. + + Arguments + ========== + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' y := alpha*A*x + beta*y. + + TRANS = 'T' or 't' y := alpha*A'*x + beta*y. + + TRANS = 'C' or 'c' y := alpha*A'*x + beta*y. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + X - DOUBLE PRECISION array of DIMENSION at least + ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. + Before entry, the incremented array X must contain the + vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - DOUBLE PRECISION. + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - DOUBLE PRECISION array of DIMENSION at least + ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. + Before entry with BETA non-zero, the incremented array Y + must contain the vector y. On exit, Y is overwritten by the + updated vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(trans, "N") && ! lsame_(trans, "T") && ! lsame_(trans, "C") + ) { + info = 1; + } else if (*m < 0) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*lda < max(1,*m)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("DGEMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || *alpha == 0. && *beta == 1.) { + return 0; + } + +/* + Set LENX and LENY, the lengths of the vectors x and y, and set + up the start points in X and Y. +*/ + + if (lsame_(trans, "N")) { + lenx = *n; + leny = *m; + } else { + lenx = *m; + leny = *n; + } + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (lenx - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (leny - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. + + First form y := beta*y. +*/ + + if (*beta != 1.) { + if (*incy == 1) { + if (*beta == 0.) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.; +/* L10: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.; + iy += *incy; +/* L30: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.) { + return 0; + } + if (lsame_(trans, "N")) { + +/* Form y := alpha*A*x + y. */ + + jx = kx; + if (*incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.) { + temp = *alpha * x[jx]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + y[i__] += temp * a[i__ + j * a_dim1]; +/* L50: */ + } + } + jx += *incx; +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.) { + temp = *alpha * x[jx]; + iy = ky; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + y[iy] += temp * a[i__ + j * a_dim1]; + iy += *incy; +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } else { + +/* Form y := alpha*A'*x + y. */ + + jy = ky; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = 0.; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp += a[i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + y[jy] += *alpha * temp; + jy += *incy; +/* L100: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = 0.; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp += a[i__ + j * a_dim1] * x[ix]; + ix += *incx; +/* L110: */ + } + y[jy] += *alpha * temp; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of DGEMV . */ + +} /* dgemv_ */ + +/* Subroutine */ int dger_(integer *m, integer *n, doublereal *alpha, + doublereal *x, integer *incx, doublereal *y, integer *incy, + doublereal *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, jy, kx, info; + static doublereal temp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + DGER performs the rank 1 operation + + A := alpha*x*y' + A, + + where alpha is a scalar, x is an m element vector, y is an n element + vector and A is an m by n matrix. + + Arguments + ========== + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - DOUBLE PRECISION array of dimension at least + ( 1 + ( m - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the m + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - DOUBLE PRECISION array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. On exit, A is + overwritten by the updated matrix. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (*m < 0) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("DGER ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || *alpha == 0.) { + return 0; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (*incy > 0) { + jy = 1; + } else { + jy = 1 - (*n - 1) * *incy; + } + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (y[jy] != 0.) { + temp = *alpha * y[jy]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] += x[i__] * temp; +/* L10: */ + } + } + jy += *incy; +/* L20: */ + } + } else { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*m - 1) * *incx; + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (y[jy] != 0.) { + temp = *alpha * y[jy]; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] += x[ix] * temp; + ix += *incx; +/* L30: */ + } + } + jy += *incy; +/* L40: */ + } + } + + return 0; + +/* End of DGER . */ + +} /* dger_ */ + +doublereal dnrm2_(integer *n, doublereal *x, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2; + doublereal ret_val, d__1; + + /* Local variables */ + static integer ix; + static doublereal ssq, norm, scale, absxi; + + +/* + Purpose + ======= + + DNRM2 returns the euclidean norm of a vector via the function + name, so that + + DNRM2 := sqrt( x'*x ) + + Further Details + =============== + + -- This version written on 25-October-1982. + Modified on 14-October-1993 to inline the call to DLASSQ. + Sven Hammarling, Nag Ltd. + + ===================================================================== +*/ + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n < 1 || *incx < 1) { + norm = 0.; + } else if (*n == 1) { + norm = abs(x[1]); + } else { + scale = 0.; + ssq = 1.; +/* + The following loop is equivalent to this call to the LAPACK + auxiliary routine: + CALL DLASSQ( N, X, INCX, SCALE, SSQ ) +*/ + + i__1 = (*n - 1) * *incx + 1; + i__2 = *incx; + for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) { + if (x[ix] != 0.) { + absxi = (d__1 = x[ix], abs(d__1)); + if (scale < absxi) { +/* Computing 2nd power */ + d__1 = scale / absxi; + ssq = ssq * (d__1 * d__1) + 1.; + scale = absxi; + } else { +/* Computing 2nd power */ + d__1 = absxi / scale; + ssq += d__1 * d__1; + } + } +/* L10: */ + } + norm = scale * sqrt(ssq); + } + + ret_val = norm; + return ret_val; + +/* End of DNRM2. */ + +} /* dnrm2_ */ + +/* Subroutine */ int drot_(integer *n, doublereal *dx, integer *incx, + doublereal *dy, integer *incy, doublereal *c__, doublereal *s) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, ix, iy; + static doublereal dtemp; + + +/* + Purpose + ======= + + DROT applies a plane rotation. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --dy; + --dx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments not equal + to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dtemp = *c__ * dx[ix] + *s * dy[iy]; + dy[iy] = *c__ * dy[iy] - *s * dx[ix]; + dx[ix] = dtemp; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dtemp = *c__ * dx[i__] + *s * dy[i__]; + dy[i__] = *c__ * dy[i__] - *s * dx[i__]; + dx[i__] = dtemp; +/* L30: */ + } + return 0; +} /* drot_ */ + +/* Subroutine */ int dscal_(integer *n, doublereal *da, doublereal *dx, + integer *incx) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + static integer i__, m, mp1, nincx; + + +/* + Purpose + ======= + + DSCAL scales a vector by a constant. + uses unrolled loops for increment equal to one. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --dx; + + /* Function Body */ + if (*n <= 0 || *incx <= 0) { + return 0; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + nincx = *n * *incx; + i__1 = nincx; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + dx[i__] = *da * dx[i__]; +/* L10: */ + } + return 0; + +/* + code for increment equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 5; + if (m == 0) { + goto L40; + } + i__2 = m; + for (i__ = 1; i__ <= i__2; ++i__) { + dx[i__] = *da * dx[i__]; +/* L30: */ + } + if (*n < 5) { + return 0; + } +L40: + mp1 = m + 1; + i__2 = *n; + for (i__ = mp1; i__ <= i__2; i__ += 5) { + dx[i__] = *da * dx[i__]; + dx[i__ + 1] = *da * dx[i__ + 1]; + dx[i__ + 2] = *da * dx[i__ + 2]; + dx[i__ + 3] = *da * dx[i__ + 3]; + dx[i__ + 4] = *da * dx[i__ + 4]; +/* L50: */ + } + return 0; +} /* dscal_ */ + +/* Subroutine */ int dswap_(integer *n, doublereal *dx, integer *incx, + doublereal *dy, integer *incy) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + static doublereal dtemp; + + +/* + Purpose + ======= + + interchanges two vectors. + uses unrolled loops for increments equal one. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --dy; + --dx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments not equal + to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dtemp = dx[ix]; + dx[ix] = dy[iy]; + dy[iy] = dtemp; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 3; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + dtemp = dx[i__]; + dx[i__] = dy[i__]; + dy[i__] = dtemp; +/* L30: */ + } + if (*n < 3) { + return 0; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 3) { + dtemp = dx[i__]; + dx[i__] = dy[i__]; + dy[i__] = dtemp; + dtemp = dx[i__ + 1]; + dx[i__ + 1] = dy[i__ + 1]; + dy[i__ + 1] = dtemp; + dtemp = dx[i__ + 2]; + dx[i__ + 2] = dy[i__ + 2]; + dy[i__ + 2] = dtemp; +/* L50: */ + } + return 0; +} /* dswap_ */ + +/* Subroutine */ int dsymv_(char *uplo, integer *n, doublereal *alpha, + doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal + *beta, doublereal *y, integer *incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static doublereal temp1, temp2; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + DSYMV performs the matrix-vector operation + + y := alpha*A*x + beta*y, + + where alpha and beta are scalars, x and y are n element vectors and + A is an n by n symmetric matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array A is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of A + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of A + is to be referenced. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of A is not referenced. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - DOUBLE PRECISION array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - DOUBLE PRECISION. + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - DOUBLE PRECISION array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. On exit, Y is overwritten by the updated + vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*lda < max(1,*n)) { + info = 5; + } else if (*incx == 0) { + info = 7; + } else if (*incy == 0) { + info = 10; + } + if (info != 0) { + xerbla_("DSYMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || *alpha == 0. && *beta == 1.) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through the triangular part + of A. + + First form y := beta*y. +*/ + + if (*beta != 1.) { + if (*incy == 1) { + if (*beta == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.) { + return 0; + } + if (lsame_(uplo, "U")) { + +/* Form y when A is stored in upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + y[i__] += temp1 * a[i__ + j * a_dim1]; + temp2 += a[i__ + j * a_dim1] * x[i__]; +/* L50: */ + } + y[j] = y[j] + temp1 * a[j + j * a_dim1] + *alpha * temp2; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.; + ix = kx; + iy = ky; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + y[iy] += temp1 * a[i__ + j * a_dim1]; + temp2 += a[i__ + j * a_dim1] * x[ix]; + ix += *incx; + iy += *incy; +/* L70: */ + } + y[jy] = y[jy] + temp1 * a[j + j * a_dim1] + *alpha * temp2; + jx += *incx; + jy += *incy; +/* L80: */ + } + } + } else { + +/* Form y when A is stored in lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.; + y[j] += temp1 * a[j + j * a_dim1]; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + y[i__] += temp1 * a[i__ + j * a_dim1]; + temp2 += a[i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + y[j] += *alpha * temp2; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.; + y[jy] += temp1 * a[j + j * a_dim1]; + ix = jx; + iy = jy; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + iy += *incy; + y[iy] += temp1 * a[i__ + j * a_dim1]; + temp2 += a[i__ + j * a_dim1] * x[ix]; +/* L110: */ + } + y[jy] += *alpha * temp2; + jx += *incx; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of DSYMV . */ + +} /* dsymv_ */ + +/* Subroutine */ int dsyr2_(char *uplo, integer *n, doublereal *alpha, + doublereal *x, integer *incx, doublereal *y, integer *incy, + doublereal *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static doublereal temp1, temp2; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + DSYR2 performs the symmetric rank 2 operation + + A := alpha*x*y' + alpha*y*x' + A, + + where alpha is a scalar, x and y are n element vectors and A is an n + by n symmetric matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array A is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of A + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of A + is to be referenced. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - DOUBLE PRECISION array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - DOUBLE PRECISION array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of A is not referenced. On exit, the + upper triangular part of the array A is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of A is not referenced. On exit, the + lower triangular part of the array A is overwritten by the + lower triangular part of the updated matrix. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*n)) { + info = 9; + } + if (info != 0) { + xerbla_("DSYR2 ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || *alpha == 0.) { + return 0; + } + +/* + Set up the start points in X and Y if the increments are not both + unity. +*/ + + if (*incx != 1 || *incy != 1) { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + jx = kx; + jy = ky; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through the triangular part + of A. +*/ + + if (lsame_(uplo, "U")) { + +/* Form A when A is stored in the upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[j] != 0. || y[j] != 0.) { + temp1 = *alpha * y[j]; + temp2 = *alpha * x[j]; + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[i__] * + temp1 + y[i__] * temp2; +/* L10: */ + } + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0. || y[jy] != 0.) { + temp1 = *alpha * y[jy]; + temp2 = *alpha * x[jx]; + ix = kx; + iy = ky; + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[ix] * + temp1 + y[iy] * temp2; + ix += *incx; + iy += *incy; +/* L30: */ + } + } + jx += *incx; + jy += *incy; +/* L40: */ + } + } + } else { + +/* Form A when A is stored in the lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[j] != 0. || y[j] != 0.) { + temp1 = *alpha * y[j]; + temp2 = *alpha * x[j]; + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[i__] * + temp1 + y[i__] * temp2; +/* L50: */ + } + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0. || y[jy] != 0.) { + temp1 = *alpha * y[jy]; + temp2 = *alpha * x[jx]; + ix = jx; + iy = jy; + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[ix] * + temp1 + y[iy] * temp2; + ix += *incx; + iy += *incy; +/* L70: */ + } + } + jx += *incx; + jy += *incy; +/* L80: */ + } + } + } + + return 0; + +/* End of DSYR2 . */ + +} /* dsyr2_ */ + +/* Subroutine */ int dsyr2k_(char *uplo, char *trans, integer *n, integer *k, + doublereal *alpha, doublereal *a, integer *lda, doublereal *b, + integer *ldb, doublereal *beta, doublereal *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3; + + /* Local variables */ + static integer i__, j, l, info; + static doublereal temp1, temp2; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + DSYR2K performs one of the symmetric rank 2k operations + + C := alpha*A*B' + alpha*B*A' + beta*C, + + or + + C := alpha*A'*B + alpha*B'*A + beta*C, + + where alpha and beta are scalars, C is an n by n symmetric matrix + and A and B are n by k matrices in the first case and k by n + matrices in the second case. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*B' + alpha*B*A' + + beta*C. + + TRANS = 'T' or 't' C := alpha*A'*B + alpha*B'*A + + beta*C. + + TRANS = 'C' or 'c' C := alpha*A'*B + alpha*B'*A + + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrices A and B, and on entry with + TRANS = 'T' or 't' or 'C' or 'c', K specifies the number + of rows of the matrices A and B. K must be at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + B - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array B must contain the matrix B, otherwise + the leading k by n part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDB must be at least max( 1, n ), otherwise LDB must + be at least max( 1, k ). + Unchanged on exit. + + BETA - DOUBLE PRECISION. + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - DOUBLE PRECISION array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldb < max(1,nrowa)) { + info = 9; + } else if (*ldc < max(1,*n)) { + info = 12; + } + if (info != 0) { + xerbla_("DSYR2K", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0. || *k == 0) && *beta == 1.) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.) { + if (upper) { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + } else { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* Form C := alpha*A*B' + alpha*B*A' + C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L90: */ + } + } else if (*beta != 1.) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L100: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0. || b[j + l * b_dim1] != 0.) { + temp1 = *alpha * b[j + l * b_dim1]; + temp2 = *alpha * a[j + l * a_dim1]; + i__3 = j; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] = c__[i__ + j * c_dim1] + a[ + i__ + l * a_dim1] * temp1 + b[i__ + l * + b_dim1] * temp2; +/* L110: */ + } + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L140: */ + } + } else if (*beta != 1.) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L150: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0. || b[j + l * b_dim1] != 0.) { + temp1 = *alpha * b[j + l * b_dim1]; + temp2 = *alpha * a[j + l * a_dim1]; + i__3 = *n; + for (i__ = j; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] = c__[i__ + j * c_dim1] + a[ + i__ + l * a_dim1] * temp1 + b[i__ + l * + b_dim1] * temp2; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* Form C := alpha*A'*B + alpha*B'*A + C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + temp1 = 0.; + temp2 = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp1 += a[l + i__ * a_dim1] * b[l + j * b_dim1]; + temp2 += b[l + i__ * b_dim1] * a[l + j * a_dim1]; +/* L190: */ + } + if (*beta == 0.) { + c__[i__ + j * c_dim1] = *alpha * temp1 + *alpha * + temp2; + } else { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] + + *alpha * temp1 + *alpha * temp2; + } +/* L200: */ + } +/* L210: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + temp1 = 0.; + temp2 = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp1 += a[l + i__ * a_dim1] * b[l + j * b_dim1]; + temp2 += b[l + i__ * b_dim1] * a[l + j * a_dim1]; +/* L220: */ + } + if (*beta == 0.) { + c__[i__ + j * c_dim1] = *alpha * temp1 + *alpha * + temp2; + } else { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] + + *alpha * temp1 + *alpha * temp2; + } +/* L230: */ + } +/* L240: */ + } + } + } + + return 0; + +/* End of DSYR2K. */ + +} /* dsyr2k_ */ + +/* Subroutine */ int dsyrk_(char *uplo, char *trans, integer *n, integer *k, + doublereal *alpha, doublereal *a, integer *lda, doublereal *beta, + doublereal *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, l, info; + static doublereal temp; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + DSYRK performs one of the symmetric rank k operations + + C := alpha*A*A' + beta*C, + + or + + C := alpha*A'*A + beta*C, + + where alpha and beta are scalars, C is an n by n symmetric matrix + and A is an n by k matrix in the first case and a k by n matrix + in the second case. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*A' + beta*C. + + TRANS = 'T' or 't' C := alpha*A'*A + beta*C. + + TRANS = 'C' or 'c' C := alpha*A'*A + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrix A, and on entry with + TRANS = 'T' or 't' or 'C' or 'c', K specifies the number + of rows of the matrix A. K must be at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + BETA - DOUBLE PRECISION. + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - DOUBLE PRECISION array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldc < max(1,*n)) { + info = 10; + } + if (info != 0) { + xerbla_("DSYRK ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0. || *k == 0) && *beta == 1.) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.) { + if (upper) { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + } else { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* Form C := alpha*A*A' + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L90: */ + } + } else if (*beta != 1.) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L100: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0.) { + temp = *alpha * a[j + l * a_dim1]; + i__3 = j; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L110: */ + } + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.; +/* L140: */ + } + } else if (*beta != 1.) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L150: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0.) { + temp = *alpha * a[j + l * a_dim1]; + i__3 = *n; + for (i__ = j; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* Form C := alpha*A'*A + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * a[l + j * a_dim1]; +/* L190: */ + } + if (*beta == 0.) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L200: */ + } +/* L210: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + temp = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * a[l + j * a_dim1]; +/* L220: */ + } + if (*beta == 0.) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L230: */ + } +/* L240: */ + } + } + } + + return 0; + +/* End of DSYRK . */ + +} /* dsyrk_ */ + +/* Subroutine */ int dtrmm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, doublereal *alpha, doublereal *a, integer * + lda, doublereal *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, k, info; + static doublereal temp; + static logical lside; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical nounit; + + +/* + Purpose + ======= + + DTRMM performs one of the matrix-matrix operations + + B := alpha*op( A )*B, or B := alpha*B*op( A ), + + where alpha is a scalar, B is an m by n matrix, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A'. + + Arguments + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) multiplies B from + the left or right as follows: + + SIDE = 'L' or 'l' B := alpha*op( A )*B. + + SIDE = 'R' or 'r' B := alpha*B*op( A ). + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = A'. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - DOUBLE PRECISION array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the matrix B, and on exit is overwritten by the + transformed matrix. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("DTRMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = 0.; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*A*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + if (b[k + j * b_dim1] != 0.) { + temp = *alpha * b[k + j * b_dim1]; + i__3 = k - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] += temp * a[i__ + k * + a_dim1]; +/* L30: */ + } + if (nounit) { + temp *= a[k + k * a_dim1]; + } + b[k + j * b_dim1] = temp; + } +/* L40: */ + } +/* L50: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (k = *m; k >= 1; --k) { + if (b[k + j * b_dim1] != 0.) { + temp = *alpha * b[k + j * b_dim1]; + b[k + j * b_dim1] = temp; + if (nounit) { + b[k + j * b_dim1] *= a[k + k * a_dim1]; + } + i__2 = *m; + for (i__ = k + 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] += temp * a[i__ + k * + a_dim1]; +/* L60: */ + } + } +/* L70: */ + } +/* L80: */ + } + } + } else { + +/* Form B := alpha*A'*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + temp = b[i__ + j * b_dim1]; + if (nounit) { + temp *= a[i__ + i__ * a_dim1]; + } + i__2 = i__ - 1; + for (k = 1; k <= i__2; ++k) { + temp += a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L90: */ + } + b[i__ + j * b_dim1] = *alpha * temp; +/* L100: */ + } +/* L110: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = b[i__ + j * b_dim1]; + if (nounit) { + temp *= a[i__ + i__ * a_dim1]; + } + i__3 = *m; + for (k = i__ + 1; k <= i__3; ++k) { + temp += a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L120: */ + } + b[i__ + j * b_dim1] = *alpha * temp; +/* L130: */ + } +/* L140: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*A. */ + + if (upper) { + for (j = *n; j >= 1; --j) { + temp = *alpha; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L150: */ + } + i__1 = j - 1; + for (k = 1; k <= i__1; ++k) { + if (a[k + j * a_dim1] != 0.) { + temp = *alpha * a[k + j * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] += temp * b[i__ + k * + b_dim1]; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = *alpha; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L190: */ + } + i__2 = *n; + for (k = j + 1; k <= i__2; ++k) { + if (a[k + j * a_dim1] != 0.) { + temp = *alpha * a[k + j * a_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] += temp * b[i__ + k * + b_dim1]; +/* L200: */ + } + } +/* L210: */ + } +/* L220: */ + } + } + } else { + +/* Form B := alpha*B*A'. */ + + if (upper) { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + i__2 = k - 1; + for (j = 1; j <= i__2; ++j) { + if (a[j + k * a_dim1] != 0.) { + temp = *alpha * a[j + k * a_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] += temp * b[i__ + k * + b_dim1]; +/* L230: */ + } + } +/* L240: */ + } + temp = *alpha; + if (nounit) { + temp *= a[k + k * a_dim1]; + } + if (temp != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L250: */ + } + } +/* L260: */ + } + } else { + for (k = *n; k >= 1; --k) { + i__1 = *n; + for (j = k + 1; j <= i__1; ++j) { + if (a[j + k * a_dim1] != 0.) { + temp = *alpha * a[j + k * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] += temp * b[i__ + k * + b_dim1]; +/* L270: */ + } + } +/* L280: */ + } + temp = *alpha; + if (nounit) { + temp *= a[k + k * a_dim1]; + } + if (temp != 1.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L290: */ + } + } +/* L300: */ + } + } + } + } + + return 0; + +/* End of DTRMM . */ + +} /* dtrmm_ */ + +/* Subroutine */ int dtrmv_(char *uplo, char *trans, char *diag, integer *n, + doublereal *a, integer *lda, doublereal *x, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, jx, kx, info; + static doublereal temp; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical nounit; + + +/* + Purpose + ======= + + DTRMV performs one of the matrix-vector operations + + x := A*x, or x := A'*x, + + where x is an n element vector and A is an n by n unit, or non-unit, + upper or lower triangular matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' x := A*x. + + TRANS = 'T' or 't' x := A'*x. + + TRANS = 'C' or 'c' x := A'*x. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit + triangular as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - DOUBLE PRECISION array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. On exit, X is overwritten with the + tranformed vector x. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < max(1,*n)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } + if (info != 0) { + xerbla_("DTRMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + nounit = lsame_(diag, "N"); + +/* + Set up the start point in X if the increment is not unity. This + will be ( N - 1 )*INCX too small for descending loops. +*/ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (lsame_(trans, "N")) { + +/* Form x := A*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[j] != 0.) { + temp = x[j]; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + x[i__] += temp * a[i__ + j * a_dim1]; +/* L10: */ + } + if (nounit) { + x[j] *= a[j + j * a_dim1]; + } + } +/* L20: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.) { + temp = x[jx]; + ix = kx; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + x[ix] += temp * a[i__ + j * a_dim1]; + ix += *incx; +/* L30: */ + } + if (nounit) { + x[jx] *= a[j + j * a_dim1]; + } + } + jx += *incx; +/* L40: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + if (x[j] != 0.) { + temp = x[j]; + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + x[i__] += temp * a[i__ + j * a_dim1]; +/* L50: */ + } + if (nounit) { + x[j] *= a[j + j * a_dim1]; + } + } +/* L60: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + if (x[jx] != 0.) { + temp = x[jx]; + ix = kx; + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + x[ix] += temp * a[i__ + j * a_dim1]; + ix -= *incx; +/* L70: */ + } + if (nounit) { + x[jx] *= a[j + j * a_dim1]; + } + } + jx -= *incx; +/* L80: */ + } + } + } + } else { + +/* Form x := A'*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + temp = x[j]; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + for (i__ = j - 1; i__ >= 1; --i__) { + temp += a[i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + x[j] = temp; +/* L100: */ + } + } else { + jx = kx + (*n - 1) * *incx; + for (j = *n; j >= 1; --j) { + temp = x[jx]; + ix = jx; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + for (i__ = j - 1; i__ >= 1; --i__) { + ix -= *incx; + temp += a[i__ + j * a_dim1] * x[ix]; +/* L110: */ + } + x[jx] = temp; + jx -= *incx; +/* L120: */ + } + } + } else { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = x[j]; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + temp += a[i__ + j * a_dim1] * x[i__]; +/* L130: */ + } + x[j] = temp; +/* L140: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = x[jx]; + ix = jx; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + temp += a[i__ + j * a_dim1] * x[ix]; +/* L150: */ + } + x[jx] = temp; + jx += *incx; +/* L160: */ + } + } + } + } + + return 0; + +/* End of DTRMV . */ + +} /* dtrmv_ */ + +/* Subroutine */ int dtrsm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, doublereal *alpha, doublereal *a, integer * + lda, doublereal *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, k, info; + static doublereal temp; + static logical lside; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical nounit; + + +/* + Purpose + ======= + + DTRSM solves one of the matrix equations + + op( A )*X = alpha*B, or X*op( A ) = alpha*B, + + where alpha is a scalar, X and B are m by n matrices, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A'. + + The matrix X is overwritten on B. + + Arguments + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) appears on the left + or right of X as follows: + + SIDE = 'L' or 'l' op( A )*X = alpha*B. + + SIDE = 'R' or 'r' X*op( A ) = alpha*B. + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = A'. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION. + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - DOUBLE PRECISION array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - DOUBLE PRECISION array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the right-hand side matrix B, and on exit is + overwritten by the solution matrix X. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("DTRSM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = 0.; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*inv( A )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L30: */ + } + } + for (k = *m; k >= 1; --k) { + if (b[k + j * b_dim1] != 0.) { + if (nounit) { + b[k + j * b_dim1] /= a[k + k * a_dim1]; + } + i__2 = k - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[ + i__ + k * a_dim1]; +/* L40: */ + } + } +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L70: */ + } + } + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + if (b[k + j * b_dim1] != 0.) { + if (nounit) { + b[k + j * b_dim1] /= a[k + k * a_dim1]; + } + i__3 = *m; + for (i__ = k + 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[ + i__ + k * a_dim1]; +/* L80: */ + } + } +/* L90: */ + } +/* L100: */ + } + } + } else { + +/* Form B := alpha*inv( A' )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = *alpha * b[i__ + j * b_dim1]; + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L110: */ + } + if (nounit) { + temp /= a[i__ + i__ * a_dim1]; + } + b[i__ + j * b_dim1] = temp; +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + temp = *alpha * b[i__ + j * b_dim1]; + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L140: */ + } + if (nounit) { + temp /= a[i__ + i__ * a_dim1]; + } + b[i__ + j * b_dim1] = temp; +/* L150: */ + } +/* L160: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*inv( A ). */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L170: */ + } + } + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + if (a[k + j * a_dim1] != 0.) { + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[ + i__ + k * b_dim1]; +/* L180: */ + } + } +/* L190: */ + } + if (nounit) { + temp = 1. / a[j + j * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L200: */ + } + } +/* L210: */ + } + } else { + for (j = *n; j >= 1; --j) { + if (*alpha != 1.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L220: */ + } + } + i__1 = *n; + for (k = j + 1; k <= i__1; ++k) { + if (a[k + j * a_dim1] != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[ + i__ + k * b_dim1]; +/* L230: */ + } + } +/* L240: */ + } + if (nounit) { + temp = 1. / a[j + j * a_dim1]; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L250: */ + } + } +/* L260: */ + } + } + } else { + +/* Form B := alpha*B*inv( A' ). */ + + if (upper) { + for (k = *n; k >= 1; --k) { + if (nounit) { + temp = 1. / a[k + k * a_dim1]; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L270: */ + } + } + i__1 = k - 1; + for (j = 1; j <= i__1; ++j) { + if (a[j + k * a_dim1] != 0.) { + temp = a[j + k * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= temp * b[i__ + k * + b_dim1]; +/* L280: */ + } + } +/* L290: */ + } + if (*alpha != 1.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + k * b_dim1] = *alpha * b[i__ + k * b_dim1] + ; +/* L300: */ + } + } +/* L310: */ + } + } else { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + if (nounit) { + temp = 1. / a[k + k * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L320: */ + } + } + i__2 = *n; + for (j = k + 1; j <= i__2; ++j) { + if (a[j + k * a_dim1] != 0.) { + temp = a[j + k * a_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= temp * b[i__ + k * + b_dim1]; +/* L330: */ + } + } +/* L340: */ + } + if (*alpha != 1.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + k * b_dim1] = *alpha * b[i__ + k * b_dim1] + ; +/* L350: */ + } + } +/* L360: */ + } + } + } + } + + return 0; + +/* End of DTRSM . */ + +} /* dtrsm_ */ + +doublereal dzasum_(integer *n, doublecomplex *zx, integer *incx) +{ + /* System generated locals */ + integer i__1; + doublereal ret_val; + + /* Local variables */ + static integer i__, ix; + static doublereal stemp; + extern doublereal dcabs1_(doublecomplex *); + + +/* + Purpose + ======= + + DZASUM takes the sum of the absolute values. + + Further Details + =============== + + jack dongarra, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zx; + + /* Function Body */ + ret_val = 0.; + stemp = 0.; + if (*n <= 0 || *incx <= 0) { + return ret_val; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + ix = 1; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp += dcabs1_(&zx[ix]); + ix += *incx; +/* L10: */ + } + ret_val = stemp; + return ret_val; + +/* code for increment equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp += dcabs1_(&zx[i__]); +/* L30: */ + } + ret_val = stemp; + return ret_val; +} /* dzasum_ */ + +doublereal dznrm2_(integer *n, doublecomplex *x, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + doublereal ret_val, d__1; + + /* Local variables */ + static integer ix; + static doublereal ssq, temp, norm, scale; + + +/* + Purpose + ======= + + DZNRM2 returns the euclidean norm of a vector via the function + name, so that + + DZNRM2 := sqrt( conjg( x' )*x ) + + Further Details + =============== + + -- This version written on 25-October-1982. + Modified on 14-October-1993 to inline the call to ZLASSQ. + Sven Hammarling, Nag Ltd. + + ===================================================================== +*/ + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n < 1 || *incx < 1) { + norm = 0.; + } else { + scale = 0.; + ssq = 1.; +/* + The following loop is equivalent to this call to the LAPACK + auxiliary routine: + CALL ZLASSQ( N, X, INCX, SCALE, SSQ ) +*/ + + i__1 = (*n - 1) * *incx + 1; + i__2 = *incx; + for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) { + i__3 = ix; + if (x[i__3].r != 0.) { + i__3 = ix; + temp = (d__1 = x[i__3].r, abs(d__1)); + if (scale < temp) { +/* Computing 2nd power */ + d__1 = scale / temp; + ssq = ssq * (d__1 * d__1) + 1.; + scale = temp; + } else { +/* Computing 2nd power */ + d__1 = temp / scale; + ssq += d__1 * d__1; + } + } + if (d_imag(&x[ix]) != 0.) { + temp = (d__1 = d_imag(&x[ix]), abs(d__1)); + if (scale < temp) { +/* Computing 2nd power */ + d__1 = scale / temp; + ssq = ssq * (d__1 * d__1) + 1.; + scale = temp; + } else { +/* Computing 2nd power */ + d__1 = temp / scale; + ssq += d__1 * d__1; + } + } +/* L10: */ + } + norm = scale * sqrt(ssq); + } + + ret_val = norm; + return ret_val; + +/* End of DZNRM2. */ + +} /* dznrm2_ */ + +integer icamax_(integer *n, complex *cx, integer *incx) +{ + /* System generated locals */ + integer ret_val, i__1; + + /* Local variables */ + static integer i__, ix; + static real smax; + extern doublereal scabs1_(complex *); + + +/* + Purpose + ======= + + ICAMAX finds the index of element having max. absolute value. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cx; + + /* Function Body */ + ret_val = 0; + if (*n < 1 || *incx <= 0) { + return ret_val; + } + ret_val = 1; + if (*n == 1) { + return ret_val; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + ix = 1; + smax = scabs1_(&cx[1]); + ix += *incx; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if (scabs1_(&cx[ix]) <= smax) { + goto L5; + } + ret_val = i__; + smax = scabs1_(&cx[ix]); +L5: + ix += *incx; +/* L10: */ + } + return ret_val; + +/* code for increment equal to 1 */ + +L20: + smax = scabs1_(&cx[1]); + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if (scabs1_(&cx[i__]) <= smax) { + goto L30; + } + ret_val = i__; + smax = scabs1_(&cx[i__]); +L30: + ; + } + return ret_val; +} /* icamax_ */ + +integer idamax_(integer *n, doublereal *dx, integer *incx) +{ + /* System generated locals */ + integer ret_val, i__1; + doublereal d__1; + + /* Local variables */ + static integer i__, ix; + static doublereal dmax__; + + +/* + Purpose + ======= + + IDAMAX finds the index of element having max. absolute value. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --dx; + + /* Function Body */ + ret_val = 0; + if (*n < 1 || *incx <= 0) { + return ret_val; + } + ret_val = 1; + if (*n == 1) { + return ret_val; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + ix = 1; + dmax__ = abs(dx[1]); + ix += *incx; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if ((d__1 = dx[ix], abs(d__1)) <= dmax__) { + goto L5; + } + ret_val = i__; + dmax__ = (d__1 = dx[ix], abs(d__1)); +L5: + ix += *incx; +/* L10: */ + } + return ret_val; + +/* code for increment equal to 1 */ + +L20: + dmax__ = abs(dx[1]); + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if ((d__1 = dx[i__], abs(d__1)) <= dmax__) { + goto L30; + } + ret_val = i__; + dmax__ = (d__1 = dx[i__], abs(d__1)); +L30: + ; + } + return ret_val; +} /* idamax_ */ + +integer isamax_(integer *n, real *sx, integer *incx) +{ + /* System generated locals */ + integer ret_val, i__1; + real r__1; + + /* Local variables */ + static integer i__, ix; + static real smax; + + +/* + Purpose + ======= + + ISAMAX finds the index of element having max. absolute value. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --sx; + + /* Function Body */ + ret_val = 0; + if (*n < 1 || *incx <= 0) { + return ret_val; + } + ret_val = 1; + if (*n == 1) { + return ret_val; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + ix = 1; + smax = dabs(sx[1]); + ix += *incx; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if ((r__1 = sx[ix], dabs(r__1)) <= smax) { + goto L5; + } + ret_val = i__; + smax = (r__1 = sx[ix], dabs(r__1)); +L5: + ix += *incx; +/* L10: */ + } + return ret_val; + +/* code for increment equal to 1 */ + +L20: + smax = dabs(sx[1]); + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if ((r__1 = sx[i__], dabs(r__1)) <= smax) { + goto L30; + } + ret_val = i__; + smax = (r__1 = sx[i__], dabs(r__1)); +L30: + ; + } + return ret_val; +} /* isamax_ */ + +integer izamax_(integer *n, doublecomplex *zx, integer *incx) +{ + /* System generated locals */ + integer ret_val, i__1; + + /* Local variables */ + static integer i__, ix; + static doublereal smax; + extern doublereal dcabs1_(doublecomplex *); + + +/* + Purpose + ======= + + IZAMAX finds the index of element having max. absolute value. + + Further Details + =============== + + jack dongarra, 1/15/85. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zx; + + /* Function Body */ + ret_val = 0; + if (*n < 1 || *incx <= 0) { + return ret_val; + } + ret_val = 1; + if (*n == 1) { + return ret_val; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + ix = 1; + smax = dcabs1_(&zx[1]); + ix += *incx; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if (dcabs1_(&zx[ix]) <= smax) { + goto L5; + } + ret_val = i__; + smax = dcabs1_(&zx[ix]); +L5: + ix += *incx; +/* L10: */ + } + return ret_val; + +/* code for increment equal to 1 */ + +L20: + smax = dcabs1_(&zx[1]); + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + if (dcabs1_(&zx[i__]) <= smax) { + goto L30; + } + ret_val = i__; + smax = dcabs1_(&zx[i__]); +L30: + ; + } + return ret_val; +} /* izamax_ */ + +/* Subroutine */ int saxpy_(integer *n, real *sa, real *sx, integer *incx, + real *sy, integer *incy) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + + +/* + Purpose + ======= + + SAXPY constant times a vector plus a vector. + uses unrolled loop for increments equal to one. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --sy; + --sx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*sa == 0.f) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + sy[iy] += *sa * sx[ix]; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 4; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + sy[i__] += *sa * sx[i__]; +/* L30: */ + } + if (*n < 4) { + return 0; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 4) { + sy[i__] += *sa * sx[i__]; + sy[i__ + 1] += *sa * sx[i__ + 1]; + sy[i__ + 2] += *sa * sx[i__ + 2]; + sy[i__ + 3] += *sa * sx[i__ + 3]; +/* L50: */ + } + return 0; +} /* saxpy_ */ + +doublereal scabs1_(complex *z__) +{ + /* System generated locals */ + real ret_val, r__1, r__2; + + +/* + Purpose + ======= + + SCABS1 computes absolute value of a complex number + + ===================================================================== +*/ + + ret_val = (r__1 = z__->r, dabs(r__1)) + (r__2 = r_imag(z__), dabs(r__2)); + return ret_val; +} /* scabs1_ */ + +doublereal scasum_(integer *n, complex *cx, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + real ret_val, r__1, r__2; + + /* Local variables */ + static integer i__, nincx; + static real stemp; + + +/* + Purpose + ======= + + SCASUM takes the sum of the absolute values of a complex vector and + returns a single precision result. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --cx; + + /* Function Body */ + ret_val = 0.f; + stemp = 0.f; + if (*n <= 0 || *incx <= 0) { + return ret_val; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + nincx = *n * *incx; + i__1 = nincx; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + i__3 = i__; + stemp = stemp + (r__1 = cx[i__3].r, dabs(r__1)) + (r__2 = r_imag(&cx[ + i__]), dabs(r__2)); +/* L10: */ + } + ret_val = stemp; + return ret_val; + +/* code for increment equal to 1 */ + +L20: + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__1 = i__; + stemp = stemp + (r__1 = cx[i__1].r, dabs(r__1)) + (r__2 = r_imag(&cx[ + i__]), dabs(r__2)); +/* L30: */ + } + ret_val = stemp; + return ret_val; +} /* scasum_ */ + +doublereal scnrm2_(integer *n, complex *x, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + real ret_val, r__1; + + /* Local variables */ + static integer ix; + static real ssq, temp, norm, scale; + + +/* + Purpose + ======= + + SCNRM2 returns the euclidean norm of a vector via the function + name, so that + + SCNRM2 := sqrt( conjg( x' )*x ) + + Further Details + =============== + + -- This version written on 25-October-1982. + Modified on 14-October-1993 to inline the call to CLASSQ. + Sven Hammarling, Nag Ltd. + + ===================================================================== +*/ + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n < 1 || *incx < 1) { + norm = 0.f; + } else { + scale = 0.f; + ssq = 1.f; +/* + The following loop is equivalent to this call to the LAPACK + auxiliary routine: + CALL CLASSQ( N, X, INCX, SCALE, SSQ ) +*/ + + i__1 = (*n - 1) * *incx + 1; + i__2 = *incx; + for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) { + i__3 = ix; + if (x[i__3].r != 0.f) { + i__3 = ix; + temp = (r__1 = x[i__3].r, dabs(r__1)); + if (scale < temp) { +/* Computing 2nd power */ + r__1 = scale / temp; + ssq = ssq * (r__1 * r__1) + 1.f; + scale = temp; + } else { +/* Computing 2nd power */ + r__1 = temp / scale; + ssq += r__1 * r__1; + } + } + if (r_imag(&x[ix]) != 0.f) { + temp = (r__1 = r_imag(&x[ix]), dabs(r__1)); + if (scale < temp) { +/* Computing 2nd power */ + r__1 = scale / temp; + ssq = ssq * (r__1 * r__1) + 1.f; + scale = temp; + } else { +/* Computing 2nd power */ + r__1 = temp / scale; + ssq += r__1 * r__1; + } + } +/* L10: */ + } + norm = scale * sqrt(ssq); + } + + ret_val = norm; + return ret_val; + +/* End of SCNRM2. */ + +} /* scnrm2_ */ + +/* Subroutine */ int scopy_(integer *n, real *sx, integer *incx, real *sy, + integer *incy) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + + +/* + Purpose + ======= + + SCOPY copies a vector, x, to a vector, y. + uses unrolled loops for increments equal to 1. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --sy; + --sx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + sy[iy] = sx[ix]; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 7; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + sy[i__] = sx[i__]; +/* L30: */ + } + if (*n < 7) { + return 0; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 7) { + sy[i__] = sx[i__]; + sy[i__ + 1] = sx[i__ + 1]; + sy[i__ + 2] = sx[i__ + 2]; + sy[i__ + 3] = sx[i__ + 3]; + sy[i__ + 4] = sx[i__ + 4]; + sy[i__ + 5] = sx[i__ + 5]; + sy[i__ + 6] = sx[i__ + 6]; +/* L50: */ + } + return 0; +} /* scopy_ */ + +doublereal sdot_(integer *n, real *sx, integer *incx, real *sy, integer *incy) +{ + /* System generated locals */ + integer i__1; + real ret_val; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + static real stemp; + + +/* + Purpose + ======= + + SDOT forms the dot product of two vectors. + uses unrolled loops for increments equal to one. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --sy; + --sx; + + /* Function Body */ + stemp = 0.f; + ret_val = 0.f; + if (*n <= 0) { + return ret_val; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp += sx[ix] * sy[iy]; + ix += *incx; + iy += *incy; +/* L10: */ + } + ret_val = stemp; + return ret_val; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 5; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp += sx[i__] * sy[i__]; +/* L30: */ + } + if (*n < 5) { + goto L60; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 5) { + stemp = stemp + sx[i__] * sy[i__] + sx[i__ + 1] * sy[i__ + 1] + sx[ + i__ + 2] * sy[i__ + 2] + sx[i__ + 3] * sy[i__ + 3] + sx[i__ + + 4] * sy[i__ + 4]; +/* L50: */ + } +L60: + ret_val = stemp; + return ret_val; +} /* sdot_ */ + +/* Subroutine */ int sgemm_(char *transa, char *transb, integer *m, integer * + n, integer *k, real *alpha, real *a, integer *lda, real *b, integer * + ldb, real *beta, real *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3; + + /* Local variables */ + static integer i__, j, l, info; + static logical nota, notb; + static real temp; + static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SGEMM performs one of the matrix-matrix operations + + C := alpha*op( A )*op( B ) + beta*C, + + where op( X ) is one of + + op( X ) = X or op( X ) = X', + + alpha and beta are scalars, and A, B and C are matrices, with op( A ) + an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. + + Arguments + ========== + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n', op( A ) = A. + + TRANSA = 'T' or 't', op( A ) = A'. + + TRANSA = 'C' or 'c', op( A ) = A'. + + Unchanged on exit. + + TRANSB - CHARACTER*1. + On entry, TRANSB specifies the form of op( B ) to be used in + the matrix multiplication as follows: + + TRANSB = 'N' or 'n', op( B ) = B. + + TRANSB = 'T' or 't', op( B ) = B'. + + TRANSB = 'C' or 'c', op( B ) = B'. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix + op( A ) and of the matrix C. M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix + op( B ) and the number of columns of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry, K specifies the number of columns of the matrix + op( A ) and the number of rows of the matrix op( B ). K must + be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, ka ), where ka is + k when TRANSA = 'N' or 'n', and is m otherwise. + Before entry with TRANSA = 'N' or 'n', the leading m by k + part of the array A must contain the matrix A, otherwise + the leading k by m part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANSA = 'N' or 'n' then + LDA must be at least max( 1, m ), otherwise LDA must be at + least max( 1, k ). + Unchanged on exit. + + B - REAL array of DIMENSION ( LDB, kb ), where kb is + n when TRANSB = 'N' or 'n', and is k otherwise. + Before entry with TRANSB = 'N' or 'n', the leading k by n + part of the array B must contain the matrix B, otherwise + the leading n by k part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANSB = 'N' or 'n' then + LDB must be at least max( 1, k ), otherwise LDB must be at + least max( 1, n ). + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + Unchanged on exit. + + C - REAL array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n matrix + ( alpha*op( A )*op( B ) + beta*C ). + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Set NOTA and NOTB as true if A and B respectively are not + transposed and set NROWA, NCOLA and NROWB as the number of rows + and columns of A and the number of rows of B respectively. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + nota = lsame_(transa, "N"); + notb = lsame_(transb, "N"); + if (nota) { + nrowa = *m; + ncola = *k; + } else { + nrowa = *k; + ncola = *m; + } + if (notb) { + nrowb = *k; + } else { + nrowb = *n; + } + +/* Test the input parameters. */ + + info = 0; + if (! nota && ! lsame_(transa, "C") && ! lsame_( + transa, "T")) { + info = 1; + } else if (! notb && ! lsame_(transb, "C") && ! + lsame_(transb, "T")) { + info = 2; + } else if (*m < 0) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < max(1,nrowa)) { + info = 8; + } else if (*ldb < max(1,nrowb)) { + info = 10; + } else if (*ldc < max(1,*m)) { + info = 13; + } + if (info != 0) { + xerbla_("SGEMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || (*alpha == 0.f || *k == 0) && *beta == 1.f) { + return 0; + } + +/* And if alpha.eq.zero. */ + + if (*alpha == 0.f) { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + return 0; + } + +/* Start the operations. */ + + if (notb) { + if (nota) { + +/* Form C := alpha*A*B + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L50: */ + } + } else if (*beta != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L60: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (b[l + j * b_dim1] != 0.f) { + temp = *alpha * b[l + j * b_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L70: */ + } + } +/* L80: */ + } +/* L90: */ + } + } else { + +/* Form C := alpha*A'*B + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * b[l + j * b_dim1]; +/* L100: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L110: */ + } +/* L120: */ + } + } + } else { + if (nota) { + +/* Form C := alpha*A*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L130: */ + } + } else if (*beta != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L140: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (b[j + l * b_dim1] != 0.f) { + temp = *alpha * b[j + l * b_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L150: */ + } + } +/* L160: */ + } +/* L170: */ + } + } else { + +/* Form C := alpha*A'*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * b[j + l * b_dim1]; +/* L180: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L190: */ + } +/* L200: */ + } + } + } + + return 0; + +/* End of SGEMM . */ + +} /* sgemm_ */ + +/* Subroutine */ int sgemv_(char *trans, integer *m, integer *n, real *alpha, + real *a, integer *lda, real *x, integer *incx, real *beta, real *y, + integer *incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static real temp; + static integer lenx, leny; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SGEMV performs one of the matrix-vector operations + + y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, + + where alpha and beta are scalars, x and y are vectors and A is an + m by n matrix. + + Arguments + ========== + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' y := alpha*A*x + beta*y. + + TRANS = 'T' or 't' y := alpha*A'*x + beta*y. + + TRANS = 'C' or 'c' y := alpha*A'*x + beta*y. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + X - REAL array of DIMENSION at least + ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. + Before entry, the incremented array X must contain the + vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - REAL array of DIMENSION at least + ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. + Before entry with BETA non-zero, the incremented array Y + must contain the vector y. On exit, Y is overwritten by the + updated vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(trans, "N") && ! lsame_(trans, "T") && ! lsame_(trans, "C") + ) { + info = 1; + } else if (*m < 0) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*lda < max(1,*m)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("SGEMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || *alpha == 0.f && *beta == 1.f) { + return 0; + } + +/* + Set LENX and LENY, the lengths of the vectors x and y, and set + up the start points in X and Y. +*/ + + if (lsame_(trans, "N")) { + lenx = *n; + leny = *m; + } else { + lenx = *m; + leny = *n; + } + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (lenx - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (leny - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. + + First form y := beta*y. +*/ + + if (*beta != 1.f) { + if (*incy == 1) { + if (*beta == 0.f) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.f; +/* L10: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.f) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.f) { + return 0; + } + if (lsame_(trans, "N")) { + +/* Form y := alpha*A*x + y. */ + + jx = kx; + if (*incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.f) { + temp = *alpha * x[jx]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + y[i__] += temp * a[i__ + j * a_dim1]; +/* L50: */ + } + } + jx += *incx; +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.f) { + temp = *alpha * x[jx]; + iy = ky; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + y[iy] += temp * a[i__ + j * a_dim1]; + iy += *incy; +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } else { + +/* Form y := alpha*A'*x + y. */ + + jy = ky; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = 0.f; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp += a[i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + y[jy] += *alpha * temp; + jy += *incy; +/* L100: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = 0.f; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp += a[i__ + j * a_dim1] * x[ix]; + ix += *incx; +/* L110: */ + } + y[jy] += *alpha * temp; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of SGEMV . */ + +} /* sgemv_ */ + +/* Subroutine */ int sger_(integer *m, integer *n, real *alpha, real *x, + integer *incx, real *y, integer *incy, real *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, jy, kx, info; + static real temp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SGER performs the rank 1 operation + + A := alpha*x*y' + A, + + where alpha is a scalar, x is an m element vector, y is an n element + vector and A is an m by n matrix. + + Arguments + ========== + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - REAL array of dimension at least + ( 1 + ( m - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the m + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - REAL array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. On exit, A is + overwritten by the updated matrix. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (*m < 0) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("SGER ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || *alpha == 0.f) { + return 0; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (*incy > 0) { + jy = 1; + } else { + jy = 1 - (*n - 1) * *incy; + } + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (y[jy] != 0.f) { + temp = *alpha * y[jy]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] += x[i__] * temp; +/* L10: */ + } + } + jy += *incy; +/* L20: */ + } + } else { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*m - 1) * *incx; + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (y[jy] != 0.f) { + temp = *alpha * y[jy]; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] += x[ix] * temp; + ix += *incx; +/* L30: */ + } + } + jy += *incy; +/* L40: */ + } + } + + return 0; + +/* End of SGER . */ + +} /* sger_ */ + +doublereal snrm2_(integer *n, real *x, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2; + real ret_val, r__1; + + /* Local variables */ + static integer ix; + static real ssq, norm, scale, absxi; + + +/* + Purpose + ======= + + SNRM2 returns the euclidean norm of a vector via the function + name, so that + + SNRM2 := sqrt( x'*x ). + + Further Details + =============== + + -- This version written on 25-October-1982. + Modified on 14-October-1993 to inline the call to SLASSQ. + Sven Hammarling, Nag Ltd. + + ===================================================================== +*/ + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n < 1 || *incx < 1) { + norm = 0.f; + } else if (*n == 1) { + norm = dabs(x[1]); + } else { + scale = 0.f; + ssq = 1.f; +/* + The following loop is equivalent to this call to the LAPACK + auxiliary routine: + CALL SLASSQ( N, X, INCX, SCALE, SSQ ) +*/ + + i__1 = (*n - 1) * *incx + 1; + i__2 = *incx; + for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) { + if (x[ix] != 0.f) { + absxi = (r__1 = x[ix], dabs(r__1)); + if (scale < absxi) { +/* Computing 2nd power */ + r__1 = scale / absxi; + ssq = ssq * (r__1 * r__1) + 1.f; + scale = absxi; + } else { +/* Computing 2nd power */ + r__1 = absxi / scale; + ssq += r__1 * r__1; + } + } +/* L10: */ + } + norm = scale * sqrt(ssq); + } + + ret_val = norm; + return ret_val; + +/* End of SNRM2. */ + +} /* snrm2_ */ + +/* Subroutine */ int srot_(integer *n, real *sx, integer *incx, real *sy, + integer *incy, real *c__, real *s) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, ix, iy; + static real stemp; + + +/* + Purpose + ======= + + applies a plane rotation. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --sy; + --sx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments not equal + to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp = *c__ * sx[ix] + *s * sy[iy]; + sy[iy] = *c__ * sy[iy] - *s * sx[ix]; + sx[ix] = stemp; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp = *c__ * sx[i__] + *s * sy[i__]; + sy[i__] = *c__ * sy[i__] - *s * sx[i__]; + sx[i__] = stemp; +/* L30: */ + } + return 0; +} /* srot_ */ + +/* Subroutine */ int sscal_(integer *n, real *sa, real *sx, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + static integer i__, m, mp1, nincx; + + +/* + Purpose + ======= + + scales a vector by a constant. + uses unrolled loops for increment equal to 1. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --sx; + + /* Function Body */ + if (*n <= 0 || *incx <= 0) { + return 0; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + nincx = *n * *incx; + i__1 = nincx; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + sx[i__] = *sa * sx[i__]; +/* L10: */ + } + return 0; + +/* + code for increment equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 5; + if (m == 0) { + goto L40; + } + i__2 = m; + for (i__ = 1; i__ <= i__2; ++i__) { + sx[i__] = *sa * sx[i__]; +/* L30: */ + } + if (*n < 5) { + return 0; + } +L40: + mp1 = m + 1; + i__2 = *n; + for (i__ = mp1; i__ <= i__2; i__ += 5) { + sx[i__] = *sa * sx[i__]; + sx[i__ + 1] = *sa * sx[i__ + 1]; + sx[i__ + 2] = *sa * sx[i__ + 2]; + sx[i__ + 3] = *sa * sx[i__ + 3]; + sx[i__ + 4] = *sa * sx[i__ + 4]; +/* L50: */ + } + return 0; +} /* sscal_ */ + +/* Subroutine */ int sswap_(integer *n, real *sx, integer *incx, real *sy, + integer *incy) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + static real stemp; + + +/* + Purpose + ======= + + interchanges two vectors. + uses unrolled loops for increments equal to 1. + + Further Details + =============== + + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --sy; + --sx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments not equal + to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp = sx[ix]; + sx[ix] = sy[iy]; + sy[iy] = stemp; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 3; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp = sx[i__]; + sx[i__] = sy[i__]; + sy[i__] = stemp; +/* L30: */ + } + if (*n < 3) { + return 0; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 3) { + stemp = sx[i__]; + sx[i__] = sy[i__]; + sy[i__] = stemp; + stemp = sx[i__ + 1]; + sx[i__ + 1] = sy[i__ + 1]; + sy[i__ + 1] = stemp; + stemp = sx[i__ + 2]; + sx[i__ + 2] = sy[i__ + 2]; + sy[i__ + 2] = stemp; +/* L50: */ + } + return 0; +} /* sswap_ */ + +/* Subroutine */ int ssymv_(char *uplo, integer *n, real *alpha, real *a, + integer *lda, real *x, integer *incx, real *beta, real *y, integer * + incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static real temp1, temp2; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SSYMV performs the matrix-vector operation + + y := alpha*A*x + beta*y, + + where alpha and beta are scalars, x and y are n element vectors and + A is an n by n symmetric matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array A is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of A + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of A + is to be referenced. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of A is not referenced. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - REAL array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - REAL array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. On exit, Y is overwritten by the updated + vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*lda < max(1,*n)) { + info = 5; + } else if (*incx == 0) { + info = 7; + } else if (*incy == 0) { + info = 10; + } + if (info != 0) { + xerbla_("SSYMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || *alpha == 0.f && *beta == 1.f) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through the triangular part + of A. + + First form y := beta*y. +*/ + + if (*beta != 1.f) { + if (*incy == 1) { + if (*beta == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.f; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.f) { + return 0; + } + if (lsame_(uplo, "U")) { + +/* Form y when A is stored in upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.f; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + y[i__] += temp1 * a[i__ + j * a_dim1]; + temp2 += a[i__ + j * a_dim1] * x[i__]; +/* L50: */ + } + y[j] = y[j] + temp1 * a[j + j * a_dim1] + *alpha * temp2; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.f; + ix = kx; + iy = ky; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + y[iy] += temp1 * a[i__ + j * a_dim1]; + temp2 += a[i__ + j * a_dim1] * x[ix]; + ix += *incx; + iy += *incy; +/* L70: */ + } + y[jy] = y[jy] + temp1 * a[j + j * a_dim1] + *alpha * temp2; + jx += *incx; + jy += *incy; +/* L80: */ + } + } + } else { + +/* Form y when A is stored in lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.f; + y[j] += temp1 * a[j + j * a_dim1]; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + y[i__] += temp1 * a[i__ + j * a_dim1]; + temp2 += a[i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + y[j] += *alpha * temp2; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.f; + y[jy] += temp1 * a[j + j * a_dim1]; + ix = jx; + iy = jy; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + iy += *incy; + y[iy] += temp1 * a[i__ + j * a_dim1]; + temp2 += a[i__ + j * a_dim1] * x[ix]; +/* L110: */ + } + y[jy] += *alpha * temp2; + jx += *incx; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of SSYMV . */ + +} /* ssymv_ */ + +/* Subroutine */ int ssyr2_(char *uplo, integer *n, real *alpha, real *x, + integer *incx, real *y, integer *incy, real *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static real temp1, temp2; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SSYR2 performs the symmetric rank 2 operation + + A := alpha*x*y' + alpha*y*x' + A, + + where alpha is a scalar, x and y are n element vectors and A is an n + by n symmetric matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array A is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of A + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of A + is to be referenced. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - REAL array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - REAL array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of A is not referenced. On exit, the + upper triangular part of the array A is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of A is not referenced. On exit, the + lower triangular part of the array A is overwritten by the + lower triangular part of the updated matrix. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*n)) { + info = 9; + } + if (info != 0) { + xerbla_("SSYR2 ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || *alpha == 0.f) { + return 0; + } + +/* + Set up the start points in X and Y if the increments are not both + unity. +*/ + + if (*incx != 1 || *incy != 1) { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + jx = kx; + jy = ky; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through the triangular part + of A. +*/ + + if (lsame_(uplo, "U")) { + +/* Form A when A is stored in the upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[j] != 0.f || y[j] != 0.f) { + temp1 = *alpha * y[j]; + temp2 = *alpha * x[j]; + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[i__] * + temp1 + y[i__] * temp2; +/* L10: */ + } + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.f || y[jy] != 0.f) { + temp1 = *alpha * y[jy]; + temp2 = *alpha * x[jx]; + ix = kx; + iy = ky; + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[ix] * + temp1 + y[iy] * temp2; + ix += *incx; + iy += *incy; +/* L30: */ + } + } + jx += *incx; + jy += *incy; +/* L40: */ + } + } + } else { + +/* Form A when A is stored in the lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[j] != 0.f || y[j] != 0.f) { + temp1 = *alpha * y[j]; + temp2 = *alpha * x[j]; + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[i__] * + temp1 + y[i__] * temp2; +/* L50: */ + } + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.f || y[jy] != 0.f) { + temp1 = *alpha * y[jy]; + temp2 = *alpha * x[jx]; + ix = jx; + iy = jy; + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + j * a_dim1] + x[ix] * + temp1 + y[iy] * temp2; + ix += *incx; + iy += *incy; +/* L70: */ + } + } + jx += *incx; + jy += *incy; +/* L80: */ + } + } + } + + return 0; + +/* End of SSYR2 . */ + +} /* ssyr2_ */ + +/* Subroutine */ int ssyr2k_(char *uplo, char *trans, integer *n, integer *k, + real *alpha, real *a, integer *lda, real *b, integer *ldb, real *beta, + real *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3; + + /* Local variables */ + static integer i__, j, l, info; + static real temp1, temp2; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SSYR2K performs one of the symmetric rank 2k operations + + C := alpha*A*B' + alpha*B*A' + beta*C, + + or + + C := alpha*A'*B + alpha*B'*A + beta*C, + + where alpha and beta are scalars, C is an n by n symmetric matrix + and A and B are n by k matrices in the first case and k by n + matrices in the second case. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*B' + alpha*B*A' + + beta*C. + + TRANS = 'T' or 't' C := alpha*A'*B + alpha*B'*A + + beta*C. + + TRANS = 'C' or 'c' C := alpha*A'*B + alpha*B'*A + + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrices A and B, and on entry with + TRANS = 'T' or 't' or 'C' or 'c', K specifies the number + of rows of the matrices A and B. K must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + B - REAL array of DIMENSION ( LDB, kb ), where kb is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array B must contain the matrix B, otherwise + the leading k by n part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDB must be at least max( 1, n ), otherwise LDB must + be at least max( 1, k ). + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - REAL array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldb < max(1,nrowa)) { + info = 9; + } else if (*ldc < max(1,*n)) { + info = 12; + } + if (info != 0) { + xerbla_("SSYR2K", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0.f || *k == 0) && *beta == 1.f) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.f) { + if (upper) { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + } else { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* Form C := alpha*A*B' + alpha*B*A' + C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L90: */ + } + } else if (*beta != 1.f) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L100: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0.f || b[j + l * b_dim1] != 0.f) + { + temp1 = *alpha * b[j + l * b_dim1]; + temp2 = *alpha * a[j + l * a_dim1]; + i__3 = j; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] = c__[i__ + j * c_dim1] + a[ + i__ + l * a_dim1] * temp1 + b[i__ + l * + b_dim1] * temp2; +/* L110: */ + } + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L140: */ + } + } else if (*beta != 1.f) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L150: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0.f || b[j + l * b_dim1] != 0.f) + { + temp1 = *alpha * b[j + l * b_dim1]; + temp2 = *alpha * a[j + l * a_dim1]; + i__3 = *n; + for (i__ = j; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] = c__[i__ + j * c_dim1] + a[ + i__ + l * a_dim1] * temp1 + b[i__ + l * + b_dim1] * temp2; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* Form C := alpha*A'*B + alpha*B'*A + C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + temp1 = 0.f; + temp2 = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp1 += a[l + i__ * a_dim1] * b[l + j * b_dim1]; + temp2 += b[l + i__ * b_dim1] * a[l + j * a_dim1]; +/* L190: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp1 + *alpha * + temp2; + } else { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] + + *alpha * temp1 + *alpha * temp2; + } +/* L200: */ + } +/* L210: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + temp1 = 0.f; + temp2 = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp1 += a[l + i__ * a_dim1] * b[l + j * b_dim1]; + temp2 += b[l + i__ * b_dim1] * a[l + j * a_dim1]; +/* L220: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp1 + *alpha * + temp2; + } else { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] + + *alpha * temp1 + *alpha * temp2; + } +/* L230: */ + } +/* L240: */ + } + } + } + + return 0; + +/* End of SSYR2K. */ + +} /* ssyr2k_ */ + +/* Subroutine */ int ssyrk_(char *uplo, char *trans, integer *n, integer *k, + real *alpha, real *a, integer *lda, real *beta, real *c__, integer * + ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, l, info; + static real temp; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SSYRK performs one of the symmetric rank k operations + + C := alpha*A*A' + beta*C, + + or + + C := alpha*A'*A + beta*C, + + where alpha and beta are scalars, C is an n by n symmetric matrix + and A is an n by k matrix in the first case and a k by n matrix + in the second case. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*A' + beta*C. + + TRANS = 'T' or 't' C := alpha*A'*A + beta*C. + + TRANS = 'C' or 'c' C := alpha*A'*A + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrix A, and on entry with + TRANS = 'T' or 't' or 'C' or 'c', K specifies the number + of rows of the matrix A. K must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - REAL array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldc < max(1,*n)) { + info = 10; + } + if (info != 0) { + xerbla_("SSYRK ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0.f || *k == 0) && *beta == 1.f) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.f) { + if (upper) { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + } else { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* Form C := alpha*A*A' + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L90: */ + } + } else if (*beta != 1.f) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L100: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0.f) { + temp = *alpha * a[j + l * a_dim1]; + i__3 = j; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L110: */ + } + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L140: */ + } + } else if (*beta != 1.f) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L150: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0.f) { + temp = *alpha * a[j + l * a_dim1]; + i__3 = *n; + for (i__ = j; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* Form C := alpha*A'*A + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * a[l + j * a_dim1]; +/* L190: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L200: */ + } +/* L210: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + temp = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * a[l + j * a_dim1]; +/* L220: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L230: */ + } +/* L240: */ + } + } + } + + return 0; + +/* End of SSYRK . */ + +} /* ssyrk_ */ + +/* Subroutine */ int strmm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, real *alpha, real *a, integer *lda, real *b, + integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, k, info; + static real temp; + static logical lside; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical nounit; + + +/* + Purpose + ======= + + STRMM performs one of the matrix-matrix operations + + B := alpha*op( A )*B, or B := alpha*B*op( A ), + + where alpha is a scalar, B is an m by n matrix, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A'. + + Arguments + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) multiplies B from + the left or right as follows: + + SIDE = 'L' or 'l' B := alpha*op( A )*B. + + SIDE = 'R' or 'r' B := alpha*B*op( A ). + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = A'. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - REAL array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the matrix B, and on exit is overwritten by the + transformed matrix. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("STRMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*A*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + if (b[k + j * b_dim1] != 0.f) { + temp = *alpha * b[k + j * b_dim1]; + i__3 = k - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] += temp * a[i__ + k * + a_dim1]; +/* L30: */ + } + if (nounit) { + temp *= a[k + k * a_dim1]; + } + b[k + j * b_dim1] = temp; + } +/* L40: */ + } +/* L50: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (k = *m; k >= 1; --k) { + if (b[k + j * b_dim1] != 0.f) { + temp = *alpha * b[k + j * b_dim1]; + b[k + j * b_dim1] = temp; + if (nounit) { + b[k + j * b_dim1] *= a[k + k * a_dim1]; + } + i__2 = *m; + for (i__ = k + 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] += temp * a[i__ + k * + a_dim1]; +/* L60: */ + } + } +/* L70: */ + } +/* L80: */ + } + } + } else { + +/* Form B := alpha*A'*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + temp = b[i__ + j * b_dim1]; + if (nounit) { + temp *= a[i__ + i__ * a_dim1]; + } + i__2 = i__ - 1; + for (k = 1; k <= i__2; ++k) { + temp += a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L90: */ + } + b[i__ + j * b_dim1] = *alpha * temp; +/* L100: */ + } +/* L110: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = b[i__ + j * b_dim1]; + if (nounit) { + temp *= a[i__ + i__ * a_dim1]; + } + i__3 = *m; + for (k = i__ + 1; k <= i__3; ++k) { + temp += a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L120: */ + } + b[i__ + j * b_dim1] = *alpha * temp; +/* L130: */ + } +/* L140: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*A. */ + + if (upper) { + for (j = *n; j >= 1; --j) { + temp = *alpha; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L150: */ + } + i__1 = j - 1; + for (k = 1; k <= i__1; ++k) { + if (a[k + j * a_dim1] != 0.f) { + temp = *alpha * a[k + j * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] += temp * b[i__ + k * + b_dim1]; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = *alpha; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L190: */ + } + i__2 = *n; + for (k = j + 1; k <= i__2; ++k) { + if (a[k + j * a_dim1] != 0.f) { + temp = *alpha * a[k + j * a_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] += temp * b[i__ + k * + b_dim1]; +/* L200: */ + } + } +/* L210: */ + } +/* L220: */ + } + } + } else { + +/* Form B := alpha*B*A'. */ + + if (upper) { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + i__2 = k - 1; + for (j = 1; j <= i__2; ++j) { + if (a[j + k * a_dim1] != 0.f) { + temp = *alpha * a[j + k * a_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] += temp * b[i__ + k * + b_dim1]; +/* L230: */ + } + } +/* L240: */ + } + temp = *alpha; + if (nounit) { + temp *= a[k + k * a_dim1]; + } + if (temp != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L250: */ + } + } +/* L260: */ + } + } else { + for (k = *n; k >= 1; --k) { + i__1 = *n; + for (j = k + 1; j <= i__1; ++j) { + if (a[j + k * a_dim1] != 0.f) { + temp = *alpha * a[j + k * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] += temp * b[i__ + k * + b_dim1]; +/* L270: */ + } + } +/* L280: */ + } + temp = *alpha; + if (nounit) { + temp *= a[k + k * a_dim1]; + } + if (temp != 1.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L290: */ + } + } +/* L300: */ + } + } + } + } + + return 0; + +/* End of STRMM . */ + +} /* strmm_ */ + +/* Subroutine */ int strmv_(char *uplo, char *trans, char *diag, integer *n, + real *a, integer *lda, real *x, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, jx, kx, info; + static real temp; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical nounit; + + +/* + Purpose + ======= + + STRMV performs one of the matrix-vector operations + + x := A*x, or x := A'*x, + + where x is an n element vector and A is an n by n unit, or non-unit, + upper or lower triangular matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' x := A*x. + + TRANS = 'T' or 't' x := A'*x. + + TRANS = 'C' or 'c' x := A'*x. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit + triangular as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - REAL array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. On exit, X is overwritten with the + tranformed vector x. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < max(1,*n)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } + if (info != 0) { + xerbla_("STRMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + nounit = lsame_(diag, "N"); + +/* + Set up the start point in X if the increment is not unity. This + will be ( N - 1 )*INCX too small for descending loops. +*/ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (lsame_(trans, "N")) { + +/* Form x := A*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[j] != 0.f) { + temp = x[j]; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + x[i__] += temp * a[i__ + j * a_dim1]; +/* L10: */ + } + if (nounit) { + x[j] *= a[j + j * a_dim1]; + } + } +/* L20: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.f) { + temp = x[jx]; + ix = kx; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + x[ix] += temp * a[i__ + j * a_dim1]; + ix += *incx; +/* L30: */ + } + if (nounit) { + x[jx] *= a[j + j * a_dim1]; + } + } + jx += *incx; +/* L40: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + if (x[j] != 0.f) { + temp = x[j]; + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + x[i__] += temp * a[i__ + j * a_dim1]; +/* L50: */ + } + if (nounit) { + x[j] *= a[j + j * a_dim1]; + } + } +/* L60: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + if (x[jx] != 0.f) { + temp = x[jx]; + ix = kx; + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + x[ix] += temp * a[i__ + j * a_dim1]; + ix -= *incx; +/* L70: */ + } + if (nounit) { + x[jx] *= a[j + j * a_dim1]; + } + } + jx -= *incx; +/* L80: */ + } + } + } + } else { + +/* Form x := A'*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + temp = x[j]; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + for (i__ = j - 1; i__ >= 1; --i__) { + temp += a[i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + x[j] = temp; +/* L100: */ + } + } else { + jx = kx + (*n - 1) * *incx; + for (j = *n; j >= 1; --j) { + temp = x[jx]; + ix = jx; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + for (i__ = j - 1; i__ >= 1; --i__) { + ix -= *incx; + temp += a[i__ + j * a_dim1] * x[ix]; +/* L110: */ + } + x[jx] = temp; + jx -= *incx; +/* L120: */ + } + } + } else { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = x[j]; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + temp += a[i__ + j * a_dim1] * x[i__]; +/* L130: */ + } + x[j] = temp; +/* L140: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = x[jx]; + ix = jx; + if (nounit) { + temp *= a[j + j * a_dim1]; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + temp += a[i__ + j * a_dim1] * x[ix]; +/* L150: */ + } + x[jx] = temp; + jx += *incx; +/* L160: */ + } + } + } + } + + return 0; + +/* End of STRMV . */ + +} /* strmv_ */ + +/* Subroutine */ int strsm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, real *alpha, real *a, integer *lda, real *b, + integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, k, info; + static real temp; + static logical lside; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical nounit; + + +/* + Purpose + ======= + + STRSM solves one of the matrix equations + + op( A )*X = alpha*B, or X*op( A ) = alpha*B, + + where alpha is a scalar, X and B are m by n matrices, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A'. + + The matrix X is overwritten on B. + + Arguments + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) appears on the left + or right of X as follows: + + SIDE = 'L' or 'l' op( A )*X = alpha*B. + + SIDE = 'R' or 'r' X*op( A ) = alpha*B. + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = A'. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - REAL array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the right-hand side matrix B, and on exit is + overwritten by the solution matrix X. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("STRSM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*inv( A )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L30: */ + } + } + for (k = *m; k >= 1; --k) { + if (b[k + j * b_dim1] != 0.f) { + if (nounit) { + b[k + j * b_dim1] /= a[k + k * a_dim1]; + } + i__2 = k - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[ + i__ + k * a_dim1]; +/* L40: */ + } + } +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L70: */ + } + } + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + if (b[k + j * b_dim1] != 0.f) { + if (nounit) { + b[k + j * b_dim1] /= a[k + k * a_dim1]; + } + i__3 = *m; + for (i__ = k + 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[ + i__ + k * a_dim1]; +/* L80: */ + } + } +/* L90: */ + } +/* L100: */ + } + } + } else { + +/* Form B := alpha*inv( A' )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = *alpha * b[i__ + j * b_dim1]; + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L110: */ + } + if (nounit) { + temp /= a[i__ + i__ * a_dim1]; + } + b[i__ + j * b_dim1] = temp; +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + temp = *alpha * b[i__ + j * b_dim1]; + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L140: */ + } + if (nounit) { + temp /= a[i__ + i__ * a_dim1]; + } + b[i__ + j * b_dim1] = temp; +/* L150: */ + } +/* L160: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*inv( A ). */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L170: */ + } + } + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + if (a[k + j * a_dim1] != 0.f) { + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[ + i__ + k * b_dim1]; +/* L180: */ + } + } +/* L190: */ + } + if (nounit) { + temp = 1.f / a[j + j * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L200: */ + } + } +/* L210: */ + } + } else { + for (j = *n; j >= 1; --j) { + if (*alpha != 1.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L220: */ + } + } + i__1 = *n; + for (k = j + 1; k <= i__1; ++k) { + if (a[k + j * a_dim1] != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[ + i__ + k * b_dim1]; +/* L230: */ + } + } +/* L240: */ + } + if (nounit) { + temp = 1.f / a[j + j * a_dim1]; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L250: */ + } + } +/* L260: */ + } + } + } else { + +/* Form B := alpha*B*inv( A' ). */ + + if (upper) { + for (k = *n; k >= 1; --k) { + if (nounit) { + temp = 1.f / a[k + k * a_dim1]; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L270: */ + } + } + i__1 = k - 1; + for (j = 1; j <= i__1; ++j) { + if (a[j + k * a_dim1] != 0.f) { + temp = a[j + k * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= temp * b[i__ + k * + b_dim1]; +/* L280: */ + } + } +/* L290: */ + } + if (*alpha != 1.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + k * b_dim1] = *alpha * b[i__ + k * b_dim1] + ; +/* L300: */ + } + } +/* L310: */ + } + } else { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + if (nounit) { + temp = 1.f / a[k + k * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L320: */ + } + } + i__2 = *n; + for (j = k + 1; j <= i__2; ++j) { + if (a[j + k * a_dim1] != 0.f) { + temp = a[j + k * a_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= temp * b[i__ + k * + b_dim1]; +/* L330: */ + } + } +/* L340: */ + } + if (*alpha != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + k * b_dim1] = *alpha * b[i__ + k * b_dim1] + ; +/* L350: */ + } + } +/* L360: */ + } + } + } + } + + return 0; + +/* End of STRSM . */ + +} /* strsm_ */ + +/* Subroutine */ int zaxpy_(integer *n, doublecomplex *za, doublecomplex *zx, + integer *incx, doublecomplex *zy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, ix, iy; + extern doublereal dcabs1_(doublecomplex *); + + +/* + Purpose + ======= + + ZAXPY constant times a vector plus a vector. + + Further Details + =============== + + jack dongarra, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zy; + --zx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (dcabs1_(za) == 0.) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + i__4 = ix; + z__2.r = za->r * zx[i__4].r - za->i * zx[i__4].i, z__2.i = za->r * zx[ + i__4].i + za->i * zx[i__4].r; + z__1.r = zy[i__3].r + z__2.r, z__1.i = zy[i__3].i + z__2.i; + zy[i__2].r = z__1.r, zy[i__2].i = z__1.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + i__4 = i__; + z__2.r = za->r * zx[i__4].r - za->i * zx[i__4].i, z__2.i = za->r * zx[ + i__4].i + za->i * zx[i__4].r; + z__1.r = zy[i__3].r + z__2.r, z__1.i = zy[i__3].i + z__2.i; + zy[i__2].r = z__1.r, zy[i__2].i = z__1.i; +/* L30: */ + } + return 0; +} /* zaxpy_ */ + +/* Subroutine */ int zcopy_(integer *n, doublecomplex *zx, integer *incx, + doublecomplex *zy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + + /* Local variables */ + static integer i__, ix, iy; + + +/* + Purpose + ======= + + ZCOPY copies a vector, x, to a vector, y. + + Further Details + =============== + + jack dongarra, linpack, 4/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zy; + --zx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = ix; + zy[i__2].r = zx[i__3].r, zy[i__2].i = zx[i__3].i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + zy[i__2].r = zx[i__3].r, zy[i__2].i = zx[i__3].i; +/* L30: */ + } + return 0; +} /* zcopy_ */ + +/* Double Complex */ VOID zdotc_(doublecomplex * ret_val, integer *n, + doublecomplex *zx, integer *incx, doublecomplex *zy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, ix, iy; + static doublecomplex ztemp; + + +/* + Purpose + ======= + + ZDOTC forms the dot product of a vector. + + Further Details + =============== + + jack dongarra, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zy; + --zx; + + /* Function Body */ + ztemp.r = 0., ztemp.i = 0.; + ret_val->r = 0., ret_val->i = 0.; + if (*n <= 0) { + return ; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d_cnjg(&z__3, &zx[ix]); + i__2 = iy; + z__2.r = z__3.r * zy[i__2].r - z__3.i * zy[i__2].i, z__2.i = z__3.r * + zy[i__2].i + z__3.i * zy[i__2].r; + z__1.r = ztemp.r + z__2.r, z__1.i = ztemp.i + z__2.i; + ztemp.r = z__1.r, ztemp.i = z__1.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + ret_val->r = ztemp.r, ret_val->i = ztemp.i; + return ; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d_cnjg(&z__3, &zx[i__]); + i__2 = i__; + z__2.r = z__3.r * zy[i__2].r - z__3.i * zy[i__2].i, z__2.i = z__3.r * + zy[i__2].i + z__3.i * zy[i__2].r; + z__1.r = ztemp.r + z__2.r, z__1.i = ztemp.i + z__2.i; + ztemp.r = z__1.r, ztemp.i = z__1.i; +/* L30: */ + } + ret_val->r = ztemp.r, ret_val->i = ztemp.i; + return ; +} /* zdotc_ */ + +/* Double Complex */ VOID zdotu_(doublecomplex * ret_val, integer *n, + doublecomplex *zx, integer *incx, doublecomplex *zy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, ix, iy; + static doublecomplex ztemp; + + +/* + Purpose + ======= + + ZDOTU forms the dot product of two vectors. + + Further Details + =============== + + jack dongarra, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zy; + --zx; + + /* Function Body */ + ztemp.r = 0., ztemp.i = 0.; + ret_val->r = 0., ret_val->i = 0.; + if (*n <= 0) { + return ; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + i__3 = iy; + z__2.r = zx[i__2].r * zy[i__3].r - zx[i__2].i * zy[i__3].i, z__2.i = + zx[i__2].r * zy[i__3].i + zx[i__2].i * zy[i__3].r; + z__1.r = ztemp.r + z__2.r, z__1.i = ztemp.i + z__2.i; + ztemp.r = z__1.r, ztemp.i = z__1.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + ret_val->r = ztemp.r, ret_val->i = ztemp.i; + return ; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + z__2.r = zx[i__2].r * zy[i__3].r - zx[i__2].i * zy[i__3].i, z__2.i = + zx[i__2].r * zy[i__3].i + zx[i__2].i * zy[i__3].r; + z__1.r = ztemp.r + z__2.r, z__1.i = ztemp.i + z__2.i; + ztemp.r = z__1.r, ztemp.i = z__1.i; +/* L30: */ + } + ret_val->r = ztemp.r, ret_val->i = ztemp.i; + return ; +} /* zdotu_ */ + +/* Subroutine */ int zdrot_(integer *n, doublecomplex *cx, integer *incx, + doublecomplex *cy, integer *incy, doublereal *c__, doublereal *s) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, ix, iy; + static doublecomplex ctemp; + + +/* + Purpose + ======= + + Applies a plane rotation, where the cos and sin (c and s) are real + and the vectors cx and cy are complex. + jack dongarra, linpack, 3/11/78. + + Arguments + ========== + + N (input) INTEGER + On entry, N specifies the order of the vectors cx and cy. + N must be at least zero. + Unchanged on exit. + + CX (input) COMPLEX*16 array, dimension at least + ( 1 + ( N - 1 )*abs( INCX ) ). + Before entry, the incremented array CX must contain the n + element vector cx. On exit, CX is overwritten by the updated + vector cx. + + INCX (input) INTEGER + On entry, INCX specifies the increment for the elements of + CX. INCX must not be zero. + Unchanged on exit. + + CY (input) COMPLEX*16 array, dimension at least + ( 1 + ( N - 1 )*abs( INCY ) ). + Before entry, the incremented array CY must contain the n + element vector cy. On exit, CY is overwritten by the updated + vector cy. + + INCY (input) INTEGER + On entry, INCY specifies the increment for the elements of + CY. INCY must not be zero. + Unchanged on exit. + + C (input) DOUBLE PRECISION + On entry, C specifies the cosine, cos. + Unchanged on exit. + + S (input) DOUBLE PRECISION + On entry, S specifies the sine, sin. + Unchanged on exit. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments not equal + to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + z__2.r = *c__ * cx[i__2].r, z__2.i = *c__ * cx[i__2].i; + i__3 = iy; + z__3.r = *s * cy[i__3].r, z__3.i = *s * cy[i__3].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + ctemp.r = z__1.r, ctemp.i = z__1.i; + i__2 = iy; + i__3 = iy; + z__2.r = *c__ * cy[i__3].r, z__2.i = *c__ * cy[i__3].i; + i__4 = ix; + z__3.r = *s * cx[i__4].r, z__3.i = *s * cx[i__4].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - z__3.i; + cy[i__2].r = z__1.r, cy[i__2].i = z__1.i; + i__2 = ix; + cx[i__2].r = ctemp.r, cx[i__2].i = ctemp.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + z__2.r = *c__ * cx[i__2].r, z__2.i = *c__ * cx[i__2].i; + i__3 = i__; + z__3.r = *s * cy[i__3].r, z__3.i = *s * cy[i__3].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + ctemp.r = z__1.r, ctemp.i = z__1.i; + i__2 = i__; + i__3 = i__; + z__2.r = *c__ * cy[i__3].r, z__2.i = *c__ * cy[i__3].i; + i__4 = i__; + z__3.r = *s * cx[i__4].r, z__3.i = *s * cx[i__4].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - z__3.i; + cy[i__2].r = z__1.r, cy[i__2].i = z__1.i; + i__2 = i__; + cx[i__2].r = ctemp.r, cx[i__2].i = ctemp.i; +/* L30: */ + } + return 0; +} /* zdrot_ */ + +/* Subroutine */ int zdscal_(integer *n, doublereal *da, doublecomplex *zx, + integer *incx) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, ix; + + +/* + Purpose + ======= + + ZDSCAL scales a vector by a constant. + + Further Details + =============== + + jack dongarra, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zx; + + /* Function Body */ + if (*n <= 0 || *incx <= 0) { + return 0; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + ix = 1; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + z__2.r = *da, z__2.i = 0.; + i__3 = ix; + z__1.r = z__2.r * zx[i__3].r - z__2.i * zx[i__3].i, z__1.i = z__2.r * + zx[i__3].i + z__2.i * zx[i__3].r; + zx[i__2].r = z__1.r, zx[i__2].i = z__1.i; + ix += *incx; +/* L10: */ + } + return 0; + +/* code for increment equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + z__2.r = *da, z__2.i = 0.; + i__3 = i__; + z__1.r = z__2.r * zx[i__3].r - z__2.i * zx[i__3].i, z__1.i = z__2.r * + zx[i__3].i + z__2.i * zx[i__3].r; + zx[i__2].r = z__1.r, zx[i__2].i = z__1.i; +/* L30: */ + } + return 0; +} /* zdscal_ */ + +/* Subroutine */ int zgemm_(char *transa, char *transb, integer *m, integer * + n, integer *k, doublecomplex *alpha, doublecomplex *a, integer *lda, + doublecomplex *b, integer *ldb, doublecomplex *beta, doublecomplex * + c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3, i__4, i__5, i__6; + doublecomplex z__1, z__2, z__3, z__4; + + /* Local variables */ + static integer i__, j, l, info; + static logical nota, notb; + static doublecomplex temp; + static logical conja, conjb; + static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + ZGEMM performs one of the matrix-matrix operations + + C := alpha*op( A )*op( B ) + beta*C, + + where op( X ) is one of + + op( X ) = X or op( X ) = X' or op( X ) = conjg( X' ), + + alpha and beta are scalars, and A, B and C are matrices, with op( A ) + an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. + + Arguments + ========== + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n', op( A ) = A. + + TRANSA = 'T' or 't', op( A ) = A'. + + TRANSA = 'C' or 'c', op( A ) = conjg( A' ). + + Unchanged on exit. + + TRANSB - CHARACTER*1. + On entry, TRANSB specifies the form of op( B ) to be used in + the matrix multiplication as follows: + + TRANSB = 'N' or 'n', op( B ) = B. + + TRANSB = 'T' or 't', op( B ) = B'. + + TRANSB = 'C' or 'c', op( B ) = conjg( B' ). + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix + op( A ) and of the matrix C. M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix + op( B ) and the number of columns of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry, K specifies the number of columns of the matrix + op( A ) and the number of rows of the matrix op( B ). K must + be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, ka ), where ka is + k when TRANSA = 'N' or 'n', and is m otherwise. + Before entry with TRANSA = 'N' or 'n', the leading m by k + part of the array A must contain the matrix A, otherwise + the leading k by m part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANSA = 'N' or 'n' then + LDA must be at least max( 1, m ), otherwise LDA must be at + least max( 1, k ). + Unchanged on exit. + + B - COMPLEX*16 array of DIMENSION ( LDB, kb ), where kb is + n when TRANSB = 'N' or 'n', and is k otherwise. + Before entry with TRANSB = 'N' or 'n', the leading k by n + part of the array B must contain the matrix B, otherwise + the leading n by k part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANSB = 'N' or 'n' then + LDB must be at least max( 1, k ), otherwise LDB must be at + least max( 1, n ). + Unchanged on exit. + + BETA - COMPLEX*16 . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + Unchanged on exit. + + C - COMPLEX*16 array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n matrix + ( alpha*op( A )*op( B ) + beta*C ). + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Set NOTA and NOTB as true if A and B respectively are not + conjugated or transposed, set CONJA and CONJB as true if A and + B respectively are to be transposed but not conjugated and set + NROWA, NCOLA and NROWB as the number of rows and columns of A + and the number of rows of B respectively. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + nota = lsame_(transa, "N"); + notb = lsame_(transb, "N"); + conja = lsame_(transa, "C"); + conjb = lsame_(transb, "C"); + if (nota) { + nrowa = *m; + ncola = *k; + } else { + nrowa = *k; + ncola = *m; + } + if (notb) { + nrowb = *k; + } else { + nrowb = *n; + } + +/* Test the input parameters. */ + + info = 0; + if (! nota && ! conja && ! lsame_(transa, "T")) { + info = 1; + } else if (! notb && ! conjb && ! lsame_(transb, "T")) { + info = 2; + } else if (*m < 0) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < max(1,nrowa)) { + info = 8; + } else if (*ldb < max(1,nrowb)) { + info = 10; + } else if (*ldc < max(1,*m)) { + info = 13; + } + if (info != 0) { + xerbla_("ZGEMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || (alpha->r == 0. && alpha->i == 0. || *k == 0) && + (beta->r == 1. && beta->i == 0.)) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (alpha->r == 0. && alpha->i == 0.) { + if (beta->r == 0. && beta->i == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = beta->r * c__[i__4].r - beta->i * c__[i__4].i, + z__1.i = beta->r * c__[i__4].i + beta->i * c__[ + i__4].r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L30: */ + } +/* L40: */ + } + } + return 0; + } + +/* Start the operations. */ + + if (notb) { + if (nota) { + +/* Form C := alpha*A*B + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (beta->r == 0. && beta->i == 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L50: */ + } + } else if (beta->r != 1. || beta->i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__1.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L60: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = l + j * b_dim1; + if (b[i__3].r != 0. || b[i__3].i != 0.) { + i__3 = l + j * b_dim1; + z__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3].i, + z__1.i = alpha->r * b[i__3].i + alpha->i * b[ + i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + z__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + z__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + z__1.r = c__[i__5].r + z__2.r, z__1.i = c__[i__5] + .i + z__2.i; + c__[i__4].r = z__1.r, c__[i__4].i = z__1.i; +/* L70: */ + } + } +/* L80: */ + } +/* L90: */ + } + } else if (conja) { + +/* Form C := alpha*conjg( A' )*B + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0., temp.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + d_cnjg(&z__3, &a[l + i__ * a_dim1]); + i__4 = l + j * b_dim1; + z__2.r = z__3.r * b[i__4].r - z__3.i * b[i__4].i, + z__2.i = z__3.r * b[i__4].i + z__3.i * b[i__4] + .r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L100: */ + } + if (beta->r == 0. && beta->i == 0.) { + i__3 = i__ + j * c_dim1; + z__1.r = alpha->r * temp.r - alpha->i * temp.i, + z__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + z__2.r = alpha->r * temp.r - alpha->i * temp.i, + z__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + z__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } +/* L110: */ + } +/* L120: */ + } + } else { + +/* Form C := alpha*A'*B + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0., temp.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + i__4 = l + i__ * a_dim1; + i__5 = l + j * b_dim1; + z__2.r = a[i__4].r * b[i__5].r - a[i__4].i * b[i__5] + .i, z__2.i = a[i__4].r * b[i__5].i + a[i__4] + .i * b[i__5].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L130: */ + } + if (beta->r == 0. && beta->i == 0.) { + i__3 = i__ + j * c_dim1; + z__1.r = alpha->r * temp.r - alpha->i * temp.i, + z__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + z__2.r = alpha->r * temp.r - alpha->i * temp.i, + z__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + z__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } +/* L140: */ + } +/* L150: */ + } + } + } else if (nota) { + if (conjb) { + +/* Form C := alpha*A*conjg( B' ) + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (beta->r == 0. && beta->i == 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L160: */ + } + } else if (beta->r != 1. || beta->i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__1.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L170: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * b_dim1; + if (b[i__3].r != 0. || b[i__3].i != 0.) { + d_cnjg(&z__2, &b[j + l * b_dim1]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, + z__1.i = alpha->r * z__2.i + alpha->i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + z__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + z__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + z__1.r = c__[i__5].r + z__2.r, z__1.i = c__[i__5] + .i + z__2.i; + c__[i__4].r = z__1.r, c__[i__4].i = z__1.i; +/* L180: */ + } + } +/* L190: */ + } +/* L200: */ + } + } else { + +/* Form C := alpha*A*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (beta->r == 0. && beta->i == 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L210: */ + } + } else if (beta->r != 1. || beta->i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__1.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L220: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * b_dim1; + if (b[i__3].r != 0. || b[i__3].i != 0.) { + i__3 = j + l * b_dim1; + z__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3].i, + z__1.i = alpha->r * b[i__3].i + alpha->i * b[ + i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + z__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + z__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + z__1.r = c__[i__5].r + z__2.r, z__1.i = c__[i__5] + .i + z__2.i; + c__[i__4].r = z__1.r, c__[i__4].i = z__1.i; +/* L230: */ + } + } +/* L240: */ + } +/* L250: */ + } + } + } else if (conja) { + if (conjb) { + +/* Form C := alpha*conjg( A' )*conjg( B' ) + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0., temp.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + d_cnjg(&z__3, &a[l + i__ * a_dim1]); + d_cnjg(&z__4, &b[j + l * b_dim1]); + z__2.r = z__3.r * z__4.r - z__3.i * z__4.i, z__2.i = + z__3.r * z__4.i + z__3.i * z__4.r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L260: */ + } + if (beta->r == 0. && beta->i == 0.) { + i__3 = i__ + j * c_dim1; + z__1.r = alpha->r * temp.r - alpha->i * temp.i, + z__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + z__2.r = alpha->r * temp.r - alpha->i * temp.i, + z__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + z__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } +/* L270: */ + } +/* L280: */ + } + } else { + +/* Form C := alpha*conjg( A' )*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0., temp.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + d_cnjg(&z__3, &a[l + i__ * a_dim1]); + i__4 = j + l * b_dim1; + z__2.r = z__3.r * b[i__4].r - z__3.i * b[i__4].i, + z__2.i = z__3.r * b[i__4].i + z__3.i * b[i__4] + .r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L290: */ + } + if (beta->r == 0. && beta->i == 0.) { + i__3 = i__ + j * c_dim1; + z__1.r = alpha->r * temp.r - alpha->i * temp.i, + z__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + z__2.r = alpha->r * temp.r - alpha->i * temp.i, + z__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + z__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } +/* L300: */ + } +/* L310: */ + } + } + } else { + if (conjb) { + +/* Form C := alpha*A'*conjg( B' ) + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0., temp.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + i__4 = l + i__ * a_dim1; + d_cnjg(&z__3, &b[j + l * b_dim1]); + z__2.r = a[i__4].r * z__3.r - a[i__4].i * z__3.i, + z__2.i = a[i__4].r * z__3.i + a[i__4].i * + z__3.r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L320: */ + } + if (beta->r == 0. && beta->i == 0.) { + i__3 = i__ + j * c_dim1; + z__1.r = alpha->r * temp.r - alpha->i * temp.i, + z__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + z__2.r = alpha->r * temp.r - alpha->i * temp.i, + z__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + z__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } +/* L330: */ + } +/* L340: */ + } + } else { + +/* Form C := alpha*A'*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0., temp.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + i__4 = l + i__ * a_dim1; + i__5 = j + l * b_dim1; + z__2.r = a[i__4].r * b[i__5].r - a[i__4].i * b[i__5] + .i, z__2.i = a[i__4].r * b[i__5].i + a[i__4] + .i * b[i__5].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L350: */ + } + if (beta->r == 0. && beta->i == 0.) { + i__3 = i__ + j * c_dim1; + z__1.r = alpha->r * temp.r - alpha->i * temp.i, + z__1.i = alpha->r * temp.i + alpha->i * + temp.r; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + z__2.r = alpha->r * temp.r - alpha->i * temp.i, + z__2.i = alpha->r * temp.i + alpha->i * + temp.r; + i__4 = i__ + j * c_dim1; + z__3.r = beta->r * c__[i__4].r - beta->i * c__[i__4] + .i, z__3.i = beta->r * c__[i__4].i + beta->i * + c__[i__4].r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } +/* L360: */ + } +/* L370: */ + } + } + } + + return 0; + +/* End of ZGEMM . */ + +} /* zgemm_ */ + +/* Subroutine */ int zgemv_(char *trans, integer *m, integer *n, + doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex * + x, integer *incx, doublecomplex *beta, doublecomplex *y, integer * + incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static doublecomplex temp; + static integer lenx, leny; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj; + + +/* + Purpose + ======= + + ZGEMV performs one of the matrix-vector operations + + y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, or + + y := alpha*conjg( A' )*x + beta*y, + + where alpha and beta are scalars, x and y are vectors and A is an + m by n matrix. + + Arguments + ========== + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' y := alpha*A*x + beta*y. + + TRANS = 'T' or 't' y := alpha*A'*x + beta*y. + + TRANS = 'C' or 'c' y := alpha*conjg( A' )*x + beta*y. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + X - COMPLEX*16 array of DIMENSION at least + ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. + Before entry, the incremented array X must contain the + vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - COMPLEX*16 . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - COMPLEX*16 array of DIMENSION at least + ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. + Before entry with BETA non-zero, the incremented array Y + must contain the vector y. On exit, Y is overwritten by the + updated vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(trans, "N") && ! lsame_(trans, "T") && ! lsame_(trans, "C") + ) { + info = 1; + } else if (*m < 0) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*lda < max(1,*m)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("ZGEMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || alpha->r == 0. && alpha->i == 0. && (beta->r == + 1. && beta->i == 0.)) { + return 0; + } + + noconj = lsame_(trans, "T"); + +/* + Set LENX and LENY, the lengths of the vectors x and y, and set + up the start points in X and Y. +*/ + + if (lsame_(trans, "N")) { + lenx = *n; + leny = *m; + } else { + lenx = *m; + leny = *n; + } + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (lenx - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (leny - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. + + First form y := beta*y. +*/ + + if (beta->r != 1. || beta->i != 0.) { + if (*incy == 1) { + if (beta->r == 0. && beta->i == 0.) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + y[i__2].r = 0., y[i__2].i = 0.; +/* L10: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + z__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + z__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; +/* L20: */ + } + } + } else { + iy = ky; + if (beta->r == 0. && beta->i == 0.) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + y[i__2].r = 0., y[i__2].i = 0.; + iy += *incy; +/* L30: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + z__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + z__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + iy += *incy; +/* L40: */ + } + } + } + } + if (alpha->r == 0. && alpha->i == 0.) { + return 0; + } + if (lsame_(trans, "N")) { + +/* Form y := alpha*A*x + y. */ + + jx = kx; + if (*incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + if (x[i__2].r != 0. || x[i__2].i != 0.) { + i__2 = jx; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + z__1.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + temp.r = z__1.r, temp.i = z__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__2.i = temp.r * a[i__5].i + temp.i * a[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; +/* L50: */ + } + } + jx += *incx; +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + if (x[i__2].r != 0. || x[i__2].i != 0.) { + i__2 = jx; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + z__1.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + temp.r = z__1.r, temp.i = z__1.i; + iy = ky; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = iy; + i__4 = iy; + i__5 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__2.i = temp.r * a[i__5].i + temp.i * a[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + iy += *incy; +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } else { + +/* Form y := alpha*A'*x + y or y := alpha*conjg( A' )*x + y. */ + + jy = ky; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp.r = 0., temp.i = 0.; + if (noconj) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__; + z__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[i__4] + .i, z__2.i = a[i__3].r * x[i__4].i + a[i__3] + .i * x[i__4].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L90: */ + } + } else { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = i__; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, + z__2.i = z__3.r * x[i__3].i + z__3.i * x[i__3] + .r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L100: */ + } + } + i__2 = jy; + i__3 = jy; + z__2.r = alpha->r * temp.r - alpha->i * temp.i, z__2.i = + alpha->r * temp.i + alpha->i * temp.r; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + jy += *incy; +/* L110: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp.r = 0., temp.i = 0.; + ix = kx; + if (noconj) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = ix; + z__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[i__4] + .i, z__2.i = a[i__3].r * x[i__4].i + a[i__3] + .i * x[i__4].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix += *incx; +/* L120: */ + } + } else { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = ix; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, + z__2.i = z__3.r * x[i__3].i + z__3.i * x[i__3] + .r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix += *incx; +/* L130: */ + } + } + i__2 = jy; + i__3 = jy; + z__2.r = alpha->r * temp.r - alpha->i * temp.i, z__2.i = + alpha->r * temp.i + alpha->i * temp.r; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + jy += *incy; +/* L140: */ + } + } + } + + return 0; + +/* End of ZGEMV . */ + +} /* zgemv_ */ + +/* Subroutine */ int zgerc_(integer *m, integer *n, doublecomplex *alpha, + doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, + doublecomplex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, j, ix, jy, kx, info; + static doublecomplex temp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + ZGERC performs the rank 1 operation + + A := alpha*x*conjg( y' ) + A, + + where alpha is a scalar, x is an m element vector, y is an n element + vector and A is an m by n matrix. + + Arguments + ========== + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - COMPLEX*16 array of dimension at least + ( 1 + ( m - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the m + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - COMPLEX*16 array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. On exit, A is + overwritten by the updated matrix. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (*m < 0) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("ZGERC ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || alpha->r == 0. && alpha->i == 0.) { + return 0; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (*incy > 0) { + jy = 1; + } else { + jy = 1 - (*n - 1) * *incy; + } + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jy; + if (y[i__2].r != 0. || y[i__2].i != 0.) { + d_cnjg(&z__2, &y[jy]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, z__1.i = + alpha->r * z__2.i + alpha->i * z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = i__; + z__2.r = x[i__5].r * temp.r - x[i__5].i * temp.i, z__2.i = + x[i__5].r * temp.i + x[i__5].i * temp.r; + z__1.r = a[i__4].r + z__2.r, z__1.i = a[i__4].i + z__2.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L10: */ + } + } + jy += *incy; +/* L20: */ + } + } else { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*m - 1) * *incx; + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jy; + if (y[i__2].r != 0. || y[i__2].i != 0.) { + d_cnjg(&z__2, &y[jy]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, z__1.i = + alpha->r * z__2.i + alpha->i * z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = ix; + z__2.r = x[i__5].r * temp.r - x[i__5].i * temp.i, z__2.i = + x[i__5].r * temp.i + x[i__5].i * temp.r; + z__1.r = a[i__4].r + z__2.r, z__1.i = a[i__4].i + z__2.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + ix += *incx; +/* L30: */ + } + } + jy += *incy; +/* L40: */ + } + } + + return 0; + +/* End of ZGERC . */ + +} /* zgerc_ */ + +/* Subroutine */ int zgeru_(integer *m, integer *n, doublecomplex *alpha, + doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, + doublecomplex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, j, ix, jy, kx, info; + static doublecomplex temp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + ZGERU performs the rank 1 operation + + A := alpha*x*y' + A, + + where alpha is a scalar, x is an m element vector, y is an n element + vector and A is an m by n matrix. + + Arguments + ========== + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - COMPLEX*16 array of dimension at least + ( 1 + ( m - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the m + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - COMPLEX*16 array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. On exit, A is + overwritten by the updated matrix. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (*m < 0) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("ZGERU ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || alpha->r == 0. && alpha->i == 0.) { + return 0; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (*incy > 0) { + jy = 1; + } else { + jy = 1 - (*n - 1) * *incy; + } + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jy; + if (y[i__2].r != 0. || y[i__2].i != 0.) { + i__2 = jy; + z__1.r = alpha->r * y[i__2].r - alpha->i * y[i__2].i, z__1.i = + alpha->r * y[i__2].i + alpha->i * y[i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = i__; + z__2.r = x[i__5].r * temp.r - x[i__5].i * temp.i, z__2.i = + x[i__5].r * temp.i + x[i__5].i * temp.r; + z__1.r = a[i__4].r + z__2.r, z__1.i = a[i__4].i + z__2.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L10: */ + } + } + jy += *incy; +/* L20: */ + } + } else { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*m - 1) * *incx; + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jy; + if (y[i__2].r != 0. || y[i__2].i != 0.) { + i__2 = jy; + z__1.r = alpha->r * y[i__2].r - alpha->i * y[i__2].i, z__1.i = + alpha->r * y[i__2].i + alpha->i * y[i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = ix; + z__2.r = x[i__5].r * temp.r - x[i__5].i * temp.i, z__2.i = + x[i__5].r * temp.i + x[i__5].i * temp.r; + z__1.r = a[i__4].r + z__2.r, z__1.i = a[i__4].i + z__2.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + ix += *incx; +/* L30: */ + } + } + jy += *incy; +/* L40: */ + } + } + + return 0; + +/* End of ZGERU . */ + +} /* zgeru_ */ + +/* Subroutine */ int zhemv_(char *uplo, integer *n, doublecomplex *alpha, + doublecomplex *a, integer *lda, doublecomplex *x, integer *incx, + doublecomplex *beta, doublecomplex *y, integer *incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1; + doublecomplex z__1, z__2, z__3, z__4; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static doublecomplex temp1, temp2; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + ZHEMV performs the matrix-vector operation + + y := alpha*A*x + beta*y, + + where alpha and beta are scalars, x and y are n element vectors and + A is an n by n hermitian matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array A is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of A + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of A + is to be referenced. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular part of the hermitian matrix and the strictly + lower triangular part of A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular part of the hermitian matrix and the strictly + upper triangular part of A is not referenced. + Note that the imaginary parts of the diagonal elements need + not be set and are assumed to be zero. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - COMPLEX*16 array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - COMPLEX*16 . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - COMPLEX*16 array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. On exit, Y is overwritten by the updated + vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*lda < max(1,*n)) { + info = 5; + } else if (*incx == 0) { + info = 7; + } else if (*incy == 0) { + info = 10; + } + if (info != 0) { + xerbla_("ZHEMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || alpha->r == 0. && alpha->i == 0. && (beta->r == 1. && + beta->i == 0.)) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through the triangular part + of A. + + First form y := beta*y. +*/ + + if (beta->r != 1. || beta->i != 0.) { + if (*incy == 1) { + if (beta->r == 0. && beta->i == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + y[i__2].r = 0., y[i__2].i = 0.; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + z__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + z__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; +/* L20: */ + } + } + } else { + iy = ky; + if (beta->r == 0. && beta->i == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + y[i__2].r = 0., y[i__2].i = 0.; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + z__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + z__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + iy += *incy; +/* L40: */ + } + } + } + } + if (alpha->r == 0. && alpha->i == 0.) { + return 0; + } + if (lsame_(uplo, "U")) { + +/* Form y when A is stored in upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + z__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + z__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = i__; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, z__2.i = + z__3.r * x[i__3].i + z__3.i * x[i__3].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L50: */ + } + i__2 = j; + i__3 = j; + i__4 = j + j * a_dim1; + d__1 = a[i__4].r; + z__3.r = d__1 * temp1.r, z__3.i = d__1 * temp1.i; + z__2.r = y[i__3].r + z__3.r, z__2.i = y[i__3].i + z__3.i; + z__4.r = alpha->r * temp2.r - alpha->i * temp2.i, z__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + ix = kx; + iy = ky; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = iy; + i__4 = iy; + i__5 = i__ + j * a_dim1; + z__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + z__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = ix; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, z__2.i = + z__3.r * x[i__3].i + z__3.i * x[i__3].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; + ix += *incx; + iy += *incy; +/* L70: */ + } + i__2 = jy; + i__3 = jy; + i__4 = j + j * a_dim1; + d__1 = a[i__4].r; + z__3.r = d__1 * temp1.r, z__3.i = d__1 * temp1.i; + z__2.r = y[i__3].r + z__3.r, z__2.i = y[i__3].i + z__3.i; + z__4.r = alpha->r * temp2.r - alpha->i * temp2.i, z__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + jx += *incx; + jy += *incy; +/* L80: */ + } + } + } else { + +/* Form y when A is stored in lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + i__2 = j; + i__3 = j; + i__4 = j + j * a_dim1; + d__1 = a[i__4].r; + z__2.r = d__1 * temp1.r, z__2.i = d__1 * temp1.i; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + z__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + z__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = i__; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, z__2.i = + z__3.r * x[i__3].i + z__3.i * x[i__3].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L90: */ + } + i__2 = j; + i__3 = j; + z__2.r = alpha->r * temp2.r - alpha->i * temp2.i, z__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + i__2 = jy; + i__3 = jy; + i__4 = j + j * a_dim1; + d__1 = a[i__4].r; + z__2.r = d__1 * temp1.r, z__2.i = d__1 * temp1.i; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + ix = jx; + iy = jy; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + iy += *incy; + i__3 = iy; + i__4 = iy; + i__5 = i__ + j * a_dim1; + z__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + z__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = ix; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, z__2.i = + z__3.r * x[i__3].i + z__3.i * x[i__3].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L110: */ + } + i__2 = jy; + i__3 = jy; + z__2.r = alpha->r * temp2.r - alpha->i * temp2.i, z__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + jx += *incx; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of ZHEMV . */ + +} /* zhemv_ */ + +/* Subroutine */ int zher2_(char *uplo, integer *n, doublecomplex *alpha, + doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, + doublecomplex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5, i__6; + doublereal d__1; + doublecomplex z__1, z__2, z__3, z__4; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static doublecomplex temp1, temp2; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + ZHER2 performs the hermitian rank 2 operation + + A := alpha*x*conjg( y' ) + conjg( alpha )*y*conjg( x' ) + A, + + where alpha is a scalar, x and y are n element vectors and A is an n + by n hermitian matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array A is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of A + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of A + is to be referenced. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + X - COMPLEX*16 array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Y - COMPLEX*16 array of dimension at least + ( 1 + ( n - 1 )*abs( INCY ) ). + Before entry, the incremented array Y must contain the n + element vector y. + Unchanged on exit. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular part of the hermitian matrix and the strictly + lower triangular part of A is not referenced. On exit, the + upper triangular part of the array A is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular part of the hermitian matrix and the strictly + upper triangular part of A is not referenced. On exit, the + lower triangular part of the array A is overwritten by the + lower triangular part of the updated matrix. + Note that the imaginary parts of the diagonal elements need + not be set, they are assumed to be zero, and on exit they + are set to zero. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --x; + --y; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 5; + } else if (*incy == 0) { + info = 7; + } else if (*lda < max(1,*n)) { + info = 9; + } + if (info != 0) { + xerbla_("ZHER2 ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || alpha->r == 0. && alpha->i == 0.) { + return 0; + } + +/* + Set up the start points in X and Y if the increments are not both + unity. +*/ + + if (*incx != 1 || *incy != 1) { + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + jx = kx; + jy = ky; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through the triangular part + of A. +*/ + + if (lsame_(uplo, "U")) { + +/* Form A when A is stored in the upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + i__3 = j; + if (x[i__2].r != 0. || x[i__2].i != 0. || (y[i__3].r != 0. || + y[i__3].i != 0.)) { + d_cnjg(&z__2, &y[j]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, z__1.i = + alpha->r * z__2.i + alpha->i * z__2.r; + temp1.r = z__1.r, temp1.i = z__1.i; + i__2 = j; + z__2.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + z__2.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + d_cnjg(&z__1, &z__2); + temp2.r = z__1.r, temp2.i = z__1.i; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = i__; + z__3.r = x[i__5].r * temp1.r - x[i__5].i * temp1.i, + z__3.i = x[i__5].r * temp1.i + x[i__5].i * + temp1.r; + z__2.r = a[i__4].r + z__3.r, z__2.i = a[i__4].i + + z__3.i; + i__6 = i__; + z__4.r = y[i__6].r * temp2.r - y[i__6].i * temp2.i, + z__4.i = y[i__6].r * temp2.i + y[i__6].i * + temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L10: */ + } + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + i__4 = j; + z__2.r = x[i__4].r * temp1.r - x[i__4].i * temp1.i, + z__2.i = x[i__4].r * temp1.i + x[i__4].i * + temp1.r; + i__5 = j; + z__3.r = y[i__5].r * temp2.r - y[i__5].i * temp2.i, + z__3.i = y[i__5].r * temp2.i + y[i__5].i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + d__1 = a[i__3].r + z__1.r; + a[i__2].r = d__1, a[i__2].i = 0.; + } else { + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + i__3 = jy; + if (x[i__2].r != 0. || x[i__2].i != 0. || (y[i__3].r != 0. || + y[i__3].i != 0.)) { + d_cnjg(&z__2, &y[jy]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, z__1.i = + alpha->r * z__2.i + alpha->i * z__2.r; + temp1.r = z__1.r, temp1.i = z__1.i; + i__2 = jx; + z__2.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + z__2.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + d_cnjg(&z__1, &z__2); + temp2.r = z__1.r, temp2.i = z__1.i; + ix = kx; + iy = ky; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = ix; + z__3.r = x[i__5].r * temp1.r - x[i__5].i * temp1.i, + z__3.i = x[i__5].r * temp1.i + x[i__5].i * + temp1.r; + z__2.r = a[i__4].r + z__3.r, z__2.i = a[i__4].i + + z__3.i; + i__6 = iy; + z__4.r = y[i__6].r * temp2.r - y[i__6].i * temp2.i, + z__4.i = y[i__6].r * temp2.i + y[i__6].i * + temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + ix += *incx; + iy += *incy; +/* L30: */ + } + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + i__4 = jx; + z__2.r = x[i__4].r * temp1.r - x[i__4].i * temp1.i, + z__2.i = x[i__4].r * temp1.i + x[i__4].i * + temp1.r; + i__5 = jy; + z__3.r = y[i__5].r * temp2.r - y[i__5].i * temp2.i, + z__3.i = y[i__5].r * temp2.i + y[i__5].i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + d__1 = a[i__3].r + z__1.r; + a[i__2].r = d__1, a[i__2].i = 0.; + } else { + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + } + jx += *incx; + jy += *incy; +/* L40: */ + } + } + } else { + +/* Form A when A is stored in the lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + i__3 = j; + if (x[i__2].r != 0. || x[i__2].i != 0. || (y[i__3].r != 0. || + y[i__3].i != 0.)) { + d_cnjg(&z__2, &y[j]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, z__1.i = + alpha->r * z__2.i + alpha->i * z__2.r; + temp1.r = z__1.r, temp1.i = z__1.i; + i__2 = j; + z__2.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + z__2.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + d_cnjg(&z__1, &z__2); + temp2.r = z__1.r, temp2.i = z__1.i; + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + i__4 = j; + z__2.r = x[i__4].r * temp1.r - x[i__4].i * temp1.i, + z__2.i = x[i__4].r * temp1.i + x[i__4].i * + temp1.r; + i__5 = j; + z__3.r = y[i__5].r * temp2.r - y[i__5].i * temp2.i, + z__3.i = y[i__5].r * temp2.i + y[i__5].i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + d__1 = a[i__3].r + z__1.r; + a[i__2].r = d__1, a[i__2].i = 0.; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = i__; + z__3.r = x[i__5].r * temp1.r - x[i__5].i * temp1.i, + z__3.i = x[i__5].r * temp1.i + x[i__5].i * + temp1.r; + z__2.r = a[i__4].r + z__3.r, z__2.i = a[i__4].i + + z__3.i; + i__6 = i__; + z__4.r = y[i__6].r * temp2.r - y[i__6].i * temp2.i, + z__4.i = y[i__6].r * temp2.i + y[i__6].i * + temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L50: */ + } + } else { + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + i__3 = jy; + if (x[i__2].r != 0. || x[i__2].i != 0. || (y[i__3].r != 0. || + y[i__3].i != 0.)) { + d_cnjg(&z__2, &y[jy]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, z__1.i = + alpha->r * z__2.i + alpha->i * z__2.r; + temp1.r = z__1.r, temp1.i = z__1.i; + i__2 = jx; + z__2.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, + z__2.i = alpha->r * x[i__2].i + alpha->i * x[i__2] + .r; + d_cnjg(&z__1, &z__2); + temp2.r = z__1.r, temp2.i = z__1.i; + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + i__4 = jx; + z__2.r = x[i__4].r * temp1.r - x[i__4].i * temp1.i, + z__2.i = x[i__4].r * temp1.i + x[i__4].i * + temp1.r; + i__5 = jy; + z__3.r = y[i__5].r * temp2.r - y[i__5].i * temp2.i, + z__3.i = y[i__5].r * temp2.i + y[i__5].i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + d__1 = a[i__3].r + z__1.r; + a[i__2].r = d__1, a[i__2].i = 0.; + ix = jx; + iy = jy; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + iy += *incy; + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + i__5 = ix; + z__3.r = x[i__5].r * temp1.r - x[i__5].i * temp1.i, + z__3.i = x[i__5].r * temp1.i + x[i__5].i * + temp1.r; + z__2.r = a[i__4].r + z__3.r, z__2.i = a[i__4].i + + z__3.i; + i__6 = iy; + z__4.r = y[i__6].r * temp2.r - y[i__6].i * temp2.i, + z__4.i = y[i__6].r * temp2.i + y[i__6].i * + temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L70: */ + } + } else { + i__2 = j + j * a_dim1; + i__3 = j + j * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + } + jx += *incx; + jy += *incy; +/* L80: */ + } + } + } + + return 0; + +/* End of ZHER2 . */ + +} /* zher2_ */ + +/* Subroutine */ int zher2k_(char *uplo, char *trans, integer *n, integer *k, + doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex * + b, integer *ldb, doublereal *beta, doublecomplex *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3, i__4, i__5, i__6, i__7; + doublereal d__1; + doublecomplex z__1, z__2, z__3, z__4, z__5, z__6; + + /* Local variables */ + static integer i__, j, l, info; + static doublecomplex temp1, temp2; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + ZHER2K performs one of the hermitian rank 2k operations + + C := alpha*A*conjg( B' ) + conjg( alpha )*B*conjg( A' ) + beta*C, + + or + + C := alpha*conjg( A' )*B + conjg( alpha )*conjg( B' )*A + beta*C, + + where alpha and beta are scalars with beta real, C is an n by n + hermitian matrix and A and B are n by k matrices in the first case + and k by n matrices in the second case. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*conjg( B' ) + + conjg( alpha )*B*conjg( A' ) + + beta*C. + + TRANS = 'C' or 'c' C := alpha*conjg( A' )*B + + conjg( alpha )*conjg( B' )*A + + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrices A and B, and on entry with + TRANS = 'C' or 'c', K specifies the number of rows of the + matrices A and B. K must be at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + B - COMPLEX*16 array of DIMENSION ( LDB, kb ), where kb is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array B must contain the matrix B, otherwise + the leading k by n part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDB must be at least max( 1, n ), otherwise LDB must + be at least max( 1, k ). + Unchanged on exit. + + BETA - DOUBLE PRECISION . + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - COMPLEX*16 array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the hermitian matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the hermitian matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + Note that the imaginary parts of the diagonal elements need + not be set, they are assumed to be zero, and on exit they + are set to zero. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + -- Modified 8-Nov-93 to set C(J,J) to DBLE( C(J,J) ) when BETA = 1. + Ed Anderson, Cray Research Inc. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldb < max(1,nrowa)) { + info = 9; + } else if (*ldc < max(1,*n)) { + info = 12; + } + if (info != 0) { + xerbla_("ZHER2K", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (alpha->r == 0. && alpha->i == 0. || *k == 0) && *beta == + 1.) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (alpha->r == 0. && alpha->i == 0.) { + if (upper) { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = *beta * c__[i__4].r, z__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L30: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; +/* L40: */ + } + } + } else { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = *beta * c__[i__4].r, z__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* + Form C := alpha*A*conjg( B' ) + conjg( alpha )*B*conjg( A' ) + + C. +*/ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L90: */ + } + } else if (*beta != 1.) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = *beta * c__[i__4].r, z__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L100: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * a_dim1; + i__4 = j + l * b_dim1; + if (a[i__3].r != 0. || a[i__3].i != 0. || (b[i__4].r != + 0. || b[i__4].i != 0.)) { + d_cnjg(&z__2, &b[j + l * b_dim1]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, + z__1.i = alpha->r * z__2.i + alpha->i * + z__2.r; + temp1.r = z__1.r, temp1.i = z__1.i; + i__3 = j + l * a_dim1; + z__2.r = alpha->r * a[i__3].r - alpha->i * a[i__3].i, + z__2.i = alpha->r * a[i__3].i + alpha->i * a[ + i__3].r; + d_cnjg(&z__1, &z__2); + temp2.r = z__1.r, temp2.i = z__1.i; + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + z__3.r = a[i__6].r * temp1.r - a[i__6].i * + temp1.i, z__3.i = a[i__6].r * temp1.i + a[ + i__6].i * temp1.r; + z__2.r = c__[i__5].r + z__3.r, z__2.i = c__[i__5] + .i + z__3.i; + i__7 = i__ + l * b_dim1; + z__4.r = b[i__7].r * temp2.r - b[i__7].i * + temp2.i, z__4.i = b[i__7].r * temp2.i + b[ + i__7].i * temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + + z__4.i; + c__[i__4].r = z__1.r, c__[i__4].i = z__1.i; +/* L110: */ + } + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + i__5 = j + l * a_dim1; + z__2.r = a[i__5].r * temp1.r - a[i__5].i * temp1.i, + z__2.i = a[i__5].r * temp1.i + a[i__5].i * + temp1.r; + i__6 = j + l * b_dim1; + z__3.r = b[i__6].r * temp2.r - b[i__6].i * temp2.i, + z__3.i = b[i__6].r * temp2.i + b[i__6].i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + d__1 = c__[i__4].r + z__1.r; + c__[i__3].r = d__1, c__[i__3].i = 0.; + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L140: */ + } + } else if (*beta != 1.) { + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = *beta * c__[i__4].r, z__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L150: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * a_dim1; + i__4 = j + l * b_dim1; + if (a[i__3].r != 0. || a[i__3].i != 0. || (b[i__4].r != + 0. || b[i__4].i != 0.)) { + d_cnjg(&z__2, &b[j + l * b_dim1]); + z__1.r = alpha->r * z__2.r - alpha->i * z__2.i, + z__1.i = alpha->r * z__2.i + alpha->i * + z__2.r; + temp1.r = z__1.r, temp1.i = z__1.i; + i__3 = j + l * a_dim1; + z__2.r = alpha->r * a[i__3].r - alpha->i * a[i__3].i, + z__2.i = alpha->r * a[i__3].i + alpha->i * a[ + i__3].r; + d_cnjg(&z__1, &z__2); + temp2.r = z__1.r, temp2.i = z__1.i; + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + z__3.r = a[i__6].r * temp1.r - a[i__6].i * + temp1.i, z__3.i = a[i__6].r * temp1.i + a[ + i__6].i * temp1.r; + z__2.r = c__[i__5].r + z__3.r, z__2.i = c__[i__5] + .i + z__3.i; + i__7 = i__ + l * b_dim1; + z__4.r = b[i__7].r * temp2.r - b[i__7].i * + temp2.i, z__4.i = b[i__7].r * temp2.i + b[ + i__7].i * temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + + z__4.i; + c__[i__4].r = z__1.r, c__[i__4].i = z__1.i; +/* L160: */ + } + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + i__5 = j + l * a_dim1; + z__2.r = a[i__5].r * temp1.r - a[i__5].i * temp1.i, + z__2.i = a[i__5].r * temp1.i + a[i__5].i * + temp1.r; + i__6 = j + l * b_dim1; + z__3.r = b[i__6].r * temp2.r - b[i__6].i * temp2.i, + z__3.i = b[i__6].r * temp2.i + b[i__6].i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + d__1 = c__[i__4].r + z__1.r; + c__[i__3].r = d__1, c__[i__3].i = 0.; + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* + Form C := alpha*conjg( A' )*B + conjg( alpha )*conjg( B' )*A + + C. +*/ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + temp1.r = 0., temp1.i = 0.; + temp2.r = 0., temp2.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + d_cnjg(&z__3, &a[l + i__ * a_dim1]); + i__4 = l + j * b_dim1; + z__2.r = z__3.r * b[i__4].r - z__3.i * b[i__4].i, + z__2.i = z__3.r * b[i__4].i + z__3.i * b[i__4] + .r; + z__1.r = temp1.r + z__2.r, z__1.i = temp1.i + z__2.i; + temp1.r = z__1.r, temp1.i = z__1.i; + d_cnjg(&z__3, &b[l + i__ * b_dim1]); + i__4 = l + j * a_dim1; + z__2.r = z__3.r * a[i__4].r - z__3.i * a[i__4].i, + z__2.i = z__3.r * a[i__4].i + z__3.i * a[i__4] + .r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L190: */ + } + if (i__ == j) { + if (*beta == 0.) { + i__3 = j + j * c_dim1; + z__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + z__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + d_cnjg(&z__4, alpha); + z__3.r = z__4.r * temp2.r - z__4.i * temp2.i, + z__3.i = z__4.r * temp2.i + z__4.i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + d__1 = z__1.r; + c__[i__3].r = d__1, c__[i__3].i = 0.; + } else { + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + z__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + z__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + d_cnjg(&z__4, alpha); + z__3.r = z__4.r * temp2.r - z__4.i * temp2.i, + z__3.i = z__4.r * temp2.i + z__4.i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + d__1 = *beta * c__[i__4].r + z__1.r; + c__[i__3].r = d__1, c__[i__3].i = 0.; + } + } else { + if (*beta == 0.) { + i__3 = i__ + j * c_dim1; + z__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + z__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + d_cnjg(&z__4, alpha); + z__3.r = z__4.r * temp2.r - z__4.i * temp2.i, + z__3.i = z__4.r * temp2.i + z__4.i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__3.r = *beta * c__[i__4].r, z__3.i = *beta * + c__[i__4].i; + z__4.r = alpha->r * temp1.r - alpha->i * temp1.i, + z__4.i = alpha->r * temp1.i + alpha->i * + temp1.r; + z__2.r = z__3.r + z__4.r, z__2.i = z__3.i + + z__4.i; + d_cnjg(&z__6, alpha); + z__5.r = z__6.r * temp2.r - z__6.i * temp2.i, + z__5.i = z__6.r * temp2.i + z__6.i * + temp2.r; + z__1.r = z__2.r + z__5.r, z__1.i = z__2.i + + z__5.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } + } +/* L200: */ + } +/* L210: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + temp1.r = 0., temp1.i = 0.; + temp2.r = 0., temp2.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + d_cnjg(&z__3, &a[l + i__ * a_dim1]); + i__4 = l + j * b_dim1; + z__2.r = z__3.r * b[i__4].r - z__3.i * b[i__4].i, + z__2.i = z__3.r * b[i__4].i + z__3.i * b[i__4] + .r; + z__1.r = temp1.r + z__2.r, z__1.i = temp1.i + z__2.i; + temp1.r = z__1.r, temp1.i = z__1.i; + d_cnjg(&z__3, &b[l + i__ * b_dim1]); + i__4 = l + j * a_dim1; + z__2.r = z__3.r * a[i__4].r - z__3.i * a[i__4].i, + z__2.i = z__3.r * a[i__4].i + z__3.i * a[i__4] + .r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L220: */ + } + if (i__ == j) { + if (*beta == 0.) { + i__3 = j + j * c_dim1; + z__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + z__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + d_cnjg(&z__4, alpha); + z__3.r = z__4.r * temp2.r - z__4.i * temp2.i, + z__3.i = z__4.r * temp2.i + z__4.i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + d__1 = z__1.r; + c__[i__3].r = d__1, c__[i__3].i = 0.; + } else { + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + z__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + z__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + d_cnjg(&z__4, alpha); + z__3.r = z__4.r * temp2.r - z__4.i * temp2.i, + z__3.i = z__4.r * temp2.i + z__4.i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + d__1 = *beta * c__[i__4].r + z__1.r; + c__[i__3].r = d__1, c__[i__3].i = 0.; + } + } else { + if (*beta == 0.) { + i__3 = i__ + j * c_dim1; + z__2.r = alpha->r * temp1.r - alpha->i * temp1.i, + z__2.i = alpha->r * temp1.i + alpha->i * + temp1.r; + d_cnjg(&z__4, alpha); + z__3.r = z__4.r * temp2.r - z__4.i * temp2.i, + z__3.i = z__4.r * temp2.i + z__4.i * + temp2.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__3.r = *beta * c__[i__4].r, z__3.i = *beta * + c__[i__4].i; + z__4.r = alpha->r * temp1.r - alpha->i * temp1.i, + z__4.i = alpha->r * temp1.i + alpha->i * + temp1.r; + z__2.r = z__3.r + z__4.r, z__2.i = z__3.i + + z__4.i; + d_cnjg(&z__6, alpha); + z__5.r = z__6.r * temp2.r - z__6.i * temp2.i, + z__5.i = z__6.r * temp2.i + z__6.i * + temp2.r; + z__1.r = z__2.r + z__5.r, z__1.i = z__2.i + + z__5.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } + } +/* L230: */ + } +/* L240: */ + } + } + } + + return 0; + +/* End of ZHER2K. */ + +} /* zher2k_ */ + +/* Subroutine */ int zherk_(char *uplo, char *trans, integer *n, integer *k, + doublereal *alpha, doublecomplex *a, integer *lda, doublereal *beta, + doublecomplex *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3, i__4, i__5, + i__6; + doublereal d__1; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, j, l, info; + static doublecomplex temp; + extern logical lsame_(char *, char *); + static integer nrowa; + static doublereal rtemp; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + ZHERK performs one of the hermitian rank k operations + + C := alpha*A*conjg( A' ) + beta*C, + + or + + C := alpha*conjg( A' )*A + beta*C, + + where alpha and beta are real scalars, C is an n by n hermitian + matrix and A is an n by k matrix in the first case and a k by n + matrix in the second case. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*conjg( A' ) + beta*C. + + TRANS = 'C' or 'c' C := alpha*conjg( A' )*A + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrix A, and on entry with + TRANS = 'C' or 'c', K specifies the number of rows of the + matrix A. K must be at least zero. + Unchanged on exit. + + ALPHA - DOUBLE PRECISION . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + BETA - DOUBLE PRECISION. + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - COMPLEX*16 array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the hermitian matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the hermitian matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + Note that the imaginary parts of the diagonal elements need + not be set, they are assumed to be zero, and on exit they + are set to zero. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + -- Modified 8-Nov-93 to set C(J,J) to DBLE( C(J,J) ) when BETA = 1. + Ed Anderson, Cray Research Inc. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldc < max(1,*n)) { + info = 10; + } + if (info != 0) { + xerbla_("ZHERK ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0. || *k == 0) && *beta == 1.) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.) { + if (upper) { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = *beta * c__[i__4].r, z__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L30: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; +/* L40: */ + } + } + } else { + if (*beta == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = *beta * c__[i__4].r, z__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* Form C := alpha*A*conjg( A' ) + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L90: */ + } + } else if (*beta != 1.) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = *beta * c__[i__4].r, z__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L100: */ + } + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * a_dim1; + if (a[i__3].r != 0. || a[i__3].i != 0.) { + d_cnjg(&z__2, &a[j + l * a_dim1]); + z__1.r = *alpha * z__2.r, z__1.i = *alpha * z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + z__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + z__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + z__1.r = c__[i__5].r + z__2.r, z__1.i = c__[i__5] + .i + z__2.i; + c__[i__4].r = z__1.r, c__[i__4].i = z__1.i; +/* L110: */ + } + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + i__5 = i__ + l * a_dim1; + z__1.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__1.i = temp.r * a[i__5].i + temp.i * a[i__5] + .r; + d__1 = c__[i__4].r + z__1.r; + c__[i__3].r = d__1, c__[i__3].i = 0.; + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + c__[i__3].r = 0., c__[i__3].i = 0.; +/* L140: */ + } + } else if (*beta != 1.) { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + z__1.r = *beta * c__[i__4].r, z__1.i = *beta * c__[ + i__4].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L150: */ + } + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + i__3 = j + l * a_dim1; + if (a[i__3].r != 0. || a[i__3].i != 0.) { + d_cnjg(&z__2, &a[j + l * a_dim1]); + z__1.r = *alpha * z__2.r, z__1.i = *alpha * z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + i__3 = j + j * c_dim1; + i__4 = j + j * c_dim1; + i__5 = j + l * a_dim1; + z__1.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__1.i = temp.r * a[i__5].i + temp.i * a[i__5] + .r; + d__1 = c__[i__4].r + z__1.r; + c__[i__3].r = d__1, c__[i__3].i = 0.; + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * c_dim1; + i__6 = i__ + l * a_dim1; + z__2.r = temp.r * a[i__6].r - temp.i * a[i__6].i, + z__2.i = temp.r * a[i__6].i + temp.i * a[ + i__6].r; + z__1.r = c__[i__5].r + z__2.r, z__1.i = c__[i__5] + .i + z__2.i; + c__[i__4].r = z__1.r, c__[i__4].i = z__1.i; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* Form C := alpha*conjg( A' )*A + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + temp.r = 0., temp.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + d_cnjg(&z__3, &a[l + i__ * a_dim1]); + i__4 = l + j * a_dim1; + z__2.r = z__3.r * a[i__4].r - z__3.i * a[i__4].i, + z__2.i = z__3.r * a[i__4].i + z__3.i * a[i__4] + .r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L190: */ + } + if (*beta == 0.) { + i__3 = i__ + j * c_dim1; + z__1.r = *alpha * temp.r, z__1.i = *alpha * temp.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + z__2.r = *alpha * temp.r, z__2.i = *alpha * temp.i; + i__4 = i__ + j * c_dim1; + z__3.r = *beta * c__[i__4].r, z__3.i = *beta * c__[ + i__4].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } +/* L200: */ + } + rtemp = 0.; + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + d_cnjg(&z__3, &a[l + j * a_dim1]); + i__3 = l + j * a_dim1; + z__2.r = z__3.r * a[i__3].r - z__3.i * a[i__3].i, z__2.i = + z__3.r * a[i__3].i + z__3.i * a[i__3].r; + z__1.r = rtemp + z__2.r, z__1.i = z__2.i; + rtemp = z__1.r; +/* L210: */ + } + if (*beta == 0.) { + i__2 = j + j * c_dim1; + d__1 = *alpha * rtemp; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *alpha * rtemp + *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } +/* L220: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + rtemp = 0.; + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + d_cnjg(&z__3, &a[l + j * a_dim1]); + i__3 = l + j * a_dim1; + z__2.r = z__3.r * a[i__3].r - z__3.i * a[i__3].i, z__2.i = + z__3.r * a[i__3].i + z__3.i * a[i__3].r; + z__1.r = rtemp + z__2.r, z__1.i = z__2.i; + rtemp = z__1.r; +/* L230: */ + } + if (*beta == 0.) { + i__2 = j + j * c_dim1; + d__1 = *alpha * rtemp; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } else { + i__2 = j + j * c_dim1; + i__3 = j + j * c_dim1; + d__1 = *alpha * rtemp + *beta * c__[i__3].r; + c__[i__2].r = d__1, c__[i__2].i = 0.; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + temp.r = 0., temp.i = 0.; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + d_cnjg(&z__3, &a[l + i__ * a_dim1]); + i__4 = l + j * a_dim1; + z__2.r = z__3.r * a[i__4].r - z__3.i * a[i__4].i, + z__2.i = z__3.r * a[i__4].i + z__3.i * a[i__4] + .r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L240: */ + } + if (*beta == 0.) { + i__3 = i__ + j * c_dim1; + z__1.r = *alpha * temp.r, z__1.i = *alpha * temp.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } else { + i__3 = i__ + j * c_dim1; + z__2.r = *alpha * temp.r, z__2.i = *alpha * temp.i; + i__4 = i__ + j * c_dim1; + z__3.r = *beta * c__[i__4].r, z__3.i = *beta * c__[ + i__4].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; + } +/* L250: */ + } +/* L260: */ + } + } + } + + return 0; + +/* End of ZHERK . */ + +} /* zherk_ */ + +/* Subroutine */ int zscal_(integer *n, doublecomplex *za, doublecomplex *zx, + integer *incx) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__, ix; + + +/* + Purpose + ======= + + ZSCAL scales a vector by a constant. + + Further Details + =============== + + jack dongarra, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zx; + + /* Function Body */ + if (*n <= 0 || *incx <= 0) { + return 0; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + ix = 1; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + i__3 = ix; + z__1.r = za->r * zx[i__3].r - za->i * zx[i__3].i, z__1.i = za->r * zx[ + i__3].i + za->i * zx[i__3].r; + zx[i__2].r = z__1.r, zx[i__2].i = z__1.i; + ix += *incx; +/* L10: */ + } + return 0; + +/* code for increment equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + z__1.r = za->r * zx[i__3].r - za->i * zx[i__3].i, z__1.i = za->r * zx[ + i__3].i + za->i * zx[i__3].r; + zx[i__2].r = z__1.r, zx[i__2].i = z__1.i; +/* L30: */ + } + return 0; +} /* zscal_ */ + +/* Subroutine */ int zswap_(integer *n, doublecomplex *zx, integer *incx, + doublecomplex *zy, integer *incy) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + + /* Local variables */ + static integer i__, ix, iy; + static doublecomplex ztemp; + + +/* + Purpose + ======= + + ZSWAP interchanges two vectors. + + Further Details + =============== + + jack dongarra, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) + + ===================================================================== +*/ + + /* Parameter adjustments */ + --zy; + --zx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments not equal + to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + ztemp.r = zx[i__2].r, ztemp.i = zx[i__2].i; + i__2 = ix; + i__3 = iy; + zx[i__2].r = zy[i__3].r, zx[i__2].i = zy[i__3].i; + i__2 = iy; + zy[i__2].r = ztemp.r, zy[i__2].i = ztemp.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* code for both increments equal to 1 */ +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + ztemp.r = zx[i__2].r, ztemp.i = zx[i__2].i; + i__2 = i__; + i__3 = i__; + zx[i__2].r = zy[i__3].r, zx[i__2].i = zy[i__3].i; + i__2 = i__; + zy[i__2].r = ztemp.r, zy[i__2].i = ztemp.i; +/* L30: */ + } + return 0; +} /* zswap_ */ + +/* Subroutine */ int ztrmm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, doublecomplex *alpha, doublecomplex *a, + integer *lda, doublecomplex *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4, i__5, + i__6; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, j, k, info; + static doublecomplex temp; + static logical lside; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj, nounit; + + +/* + Purpose + ======= + + ZTRMM performs one of the matrix-matrix operations + + B := alpha*op( A )*B, or B := alpha*B*op( A ) + + where alpha is a scalar, B is an m by n matrix, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A' or op( A ) = conjg( A' ). + + Arguments + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) multiplies B from + the left or right as follows: + + SIDE = 'L' or 'l' B := alpha*op( A )*B. + + SIDE = 'R' or 'r' B := alpha*B*op( A ). + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = conjg( A' ). + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - COMPLEX*16 array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the matrix B, and on exit is overwritten by the + transformed matrix. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + noconj = lsame_(transa, "T"); + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("ZTRMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (alpha->r == 0. && alpha->i == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + b[i__3].r = 0., b[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*A*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + i__3 = k + j * b_dim1; + if (b[i__3].r != 0. || b[i__3].i != 0.) { + i__3 = k + j * b_dim1; + z__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3] + .i, z__1.i = alpha->r * b[i__3].i + + alpha->i * b[i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + i__3 = k - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = i__ + k * a_dim1; + z__2.r = temp.r * a[i__6].r - temp.i * a[i__6] + .i, z__2.i = temp.r * a[i__6].i + + temp.i * a[i__6].r; + z__1.r = b[i__5].r + z__2.r, z__1.i = b[i__5] + .i + z__2.i; + b[i__4].r = z__1.r, b[i__4].i = z__1.i; +/* L30: */ + } + if (nounit) { + i__3 = k + k * a_dim1; + z__1.r = temp.r * a[i__3].r - temp.i * a[i__3] + .i, z__1.i = temp.r * a[i__3].i + + temp.i * a[i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__3 = k + j * b_dim1; + b[i__3].r = temp.r, b[i__3].i = temp.i; + } +/* L40: */ + } +/* L50: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (k = *m; k >= 1; --k) { + i__2 = k + j * b_dim1; + if (b[i__2].r != 0. || b[i__2].i != 0.) { + i__2 = k + j * b_dim1; + z__1.r = alpha->r * b[i__2].r - alpha->i * b[i__2] + .i, z__1.i = alpha->r * b[i__2].i + + alpha->i * b[i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + i__2 = k + j * b_dim1; + b[i__2].r = temp.r, b[i__2].i = temp.i; + if (nounit) { + i__2 = k + j * b_dim1; + i__3 = k + j * b_dim1; + i__4 = k + k * a_dim1; + z__1.r = b[i__3].r * a[i__4].r - b[i__3].i * + a[i__4].i, z__1.i = b[i__3].r * a[ + i__4].i + b[i__3].i * a[i__4].r; + b[i__2].r = z__1.r, b[i__2].i = z__1.i; + } + i__2 = *m; + for (i__ = k + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = i__ + k * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5] + .i, z__2.i = temp.r * a[i__5].i + + temp.i * a[i__5].r; + z__1.r = b[i__4].r + z__2.r, z__1.i = b[i__4] + .i + z__2.i; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L60: */ + } + } +/* L70: */ + } +/* L80: */ + } + } + } else { + +/* Form B := alpha*A'*B or B := alpha*conjg( A' )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + i__2 = i__ + j * b_dim1; + temp.r = b[i__2].r, temp.i = b[i__2].i; + if (noconj) { + if (nounit) { + i__2 = i__ + i__ * a_dim1; + z__1.r = temp.r * a[i__2].r - temp.i * a[i__2] + .i, z__1.i = temp.r * a[i__2].i + + temp.i * a[i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = i__ - 1; + for (k = 1; k <= i__2; ++k) { + i__3 = k + i__ * a_dim1; + i__4 = k + j * b_dim1; + z__2.r = a[i__3].r * b[i__4].r - a[i__3].i * + b[i__4].i, z__2.i = a[i__3].r * b[ + i__4].i + a[i__3].i * b[i__4].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L90: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[i__ + i__ * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = i__ - 1; + for (k = 1; k <= i__2; ++k) { + d_cnjg(&z__3, &a[k + i__ * a_dim1]); + i__3 = k + j * b_dim1; + z__2.r = z__3.r * b[i__3].r - z__3.i * b[i__3] + .i, z__2.i = z__3.r * b[i__3].i + + z__3.i * b[i__3].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L100: */ + } + } + i__2 = i__ + j * b_dim1; + z__1.r = alpha->r * temp.r - alpha->i * temp.i, + z__1.i = alpha->r * temp.i + alpha->i * + temp.r; + b[i__2].r = z__1.r, b[i__2].i = z__1.i; +/* L110: */ + } +/* L120: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + temp.r = b[i__3].r, temp.i = b[i__3].i; + if (noconj) { + if (nounit) { + i__3 = i__ + i__ * a_dim1; + z__1.r = temp.r * a[i__3].r - temp.i * a[i__3] + .i, z__1.i = temp.r * a[i__3].i + + temp.i * a[i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__3 = *m; + for (k = i__ + 1; k <= i__3; ++k) { + i__4 = k + i__ * a_dim1; + i__5 = k + j * b_dim1; + z__2.r = a[i__4].r * b[i__5].r - a[i__4].i * + b[i__5].i, z__2.i = a[i__4].r * b[ + i__5].i + a[i__4].i * b[i__5].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L130: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[i__ + i__ * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__3 = *m; + for (k = i__ + 1; k <= i__3; ++k) { + d_cnjg(&z__3, &a[k + i__ * a_dim1]); + i__4 = k + j * b_dim1; + z__2.r = z__3.r * b[i__4].r - z__3.i * b[i__4] + .i, z__2.i = z__3.r * b[i__4].i + + z__3.i * b[i__4].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L140: */ + } + } + i__3 = i__ + j * b_dim1; + z__1.r = alpha->r * temp.r - alpha->i * temp.i, + z__1.i = alpha->r * temp.i + alpha->i * + temp.r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L150: */ + } +/* L160: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*A. */ + + if (upper) { + for (j = *n; j >= 1; --j) { + temp.r = alpha->r, temp.i = alpha->i; + if (nounit) { + i__1 = j + j * a_dim1; + z__1.r = temp.r * a[i__1].r - temp.i * a[i__1].i, + z__1.i = temp.r * a[i__1].i + temp.i * a[i__1] + .r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * b_dim1; + i__3 = i__ + j * b_dim1; + z__1.r = temp.r * b[i__3].r - temp.i * b[i__3].i, + z__1.i = temp.r * b[i__3].i + temp.i * b[i__3] + .r; + b[i__2].r = z__1.r, b[i__2].i = z__1.i; +/* L170: */ + } + i__1 = j - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = k + j * a_dim1; + if (a[i__2].r != 0. || a[i__2].i != 0.) { + i__2 = k + j * a_dim1; + z__1.r = alpha->r * a[i__2].r - alpha->i * a[i__2] + .i, z__1.i = alpha->r * a[i__2].i + + alpha->i * a[i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = i__ + k * b_dim1; + z__2.r = temp.r * b[i__5].r - temp.i * b[i__5] + .i, z__2.i = temp.r * b[i__5].i + + temp.i * b[i__5].r; + z__1.r = b[i__4].r + z__2.r, z__1.i = b[i__4] + .i + z__2.i; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L180: */ + } + } +/* L190: */ + } +/* L200: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp.r = alpha->r, temp.i = alpha->i; + if (nounit) { + i__2 = j + j * a_dim1; + z__1.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + z__1.i = temp.r * a[i__2].i + temp.i * a[i__2] + .r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + z__1.r = temp.r * b[i__4].r - temp.i * b[i__4].i, + z__1.i = temp.r * b[i__4].i + temp.i * b[i__4] + .r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L210: */ + } + i__2 = *n; + for (k = j + 1; k <= i__2; ++k) { + i__3 = k + j * a_dim1; + if (a[i__3].r != 0. || a[i__3].i != 0.) { + i__3 = k + j * a_dim1; + z__1.r = alpha->r * a[i__3].r - alpha->i * a[i__3] + .i, z__1.i = alpha->r * a[i__3].i + + alpha->i * a[i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = i__ + k * b_dim1; + z__2.r = temp.r * b[i__6].r - temp.i * b[i__6] + .i, z__2.i = temp.r * b[i__6].i + + temp.i * b[i__6].r; + z__1.r = b[i__5].r + z__2.r, z__1.i = b[i__5] + .i + z__2.i; + b[i__4].r = z__1.r, b[i__4].i = z__1.i; +/* L220: */ + } + } +/* L230: */ + } +/* L240: */ + } + } + } else { + +/* Form B := alpha*B*A' or B := alpha*B*conjg( A' ). */ + + if (upper) { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + i__2 = k - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = j + k * a_dim1; + if (a[i__3].r != 0. || a[i__3].i != 0.) { + if (noconj) { + i__3 = j + k * a_dim1; + z__1.r = alpha->r * a[i__3].r - alpha->i * a[ + i__3].i, z__1.i = alpha->r * a[i__3] + .i + alpha->i * a[i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + } else { + d_cnjg(&z__2, &a[j + k * a_dim1]); + z__1.r = alpha->r * z__2.r - alpha->i * + z__2.i, z__1.i = alpha->r * z__2.i + + alpha->i * z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = i__ + k * b_dim1; + z__2.r = temp.r * b[i__6].r - temp.i * b[i__6] + .i, z__2.i = temp.r * b[i__6].i + + temp.i * b[i__6].r; + z__1.r = b[i__5].r + z__2.r, z__1.i = b[i__5] + .i + z__2.i; + b[i__4].r = z__1.r, b[i__4].i = z__1.i; +/* L250: */ + } + } +/* L260: */ + } + temp.r = alpha->r, temp.i = alpha->i; + if (nounit) { + if (noconj) { + i__2 = k + k * a_dim1; + z__1.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + z__1.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + } else { + d_cnjg(&z__2, &a[k + k * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + } + if (temp.r != 1. || temp.i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + k * b_dim1; + i__4 = i__ + k * b_dim1; + z__1.r = temp.r * b[i__4].r - temp.i * b[i__4].i, + z__1.i = temp.r * b[i__4].i + temp.i * b[ + i__4].r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L270: */ + } + } +/* L280: */ + } + } else { + for (k = *n; k >= 1; --k) { + i__1 = *n; + for (j = k + 1; j <= i__1; ++j) { + i__2 = j + k * a_dim1; + if (a[i__2].r != 0. || a[i__2].i != 0.) { + if (noconj) { + i__2 = j + k * a_dim1; + z__1.r = alpha->r * a[i__2].r - alpha->i * a[ + i__2].i, z__1.i = alpha->r * a[i__2] + .i + alpha->i * a[i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + } else { + d_cnjg(&z__2, &a[j + k * a_dim1]); + z__1.r = alpha->r * z__2.r - alpha->i * + z__2.i, z__1.i = alpha->r * z__2.i + + alpha->i * z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = i__ + k * b_dim1; + z__2.r = temp.r * b[i__5].r - temp.i * b[i__5] + .i, z__2.i = temp.r * b[i__5].i + + temp.i * b[i__5].r; + z__1.r = b[i__4].r + z__2.r, z__1.i = b[i__4] + .i + z__2.i; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L290: */ + } + } +/* L300: */ + } + temp.r = alpha->r, temp.i = alpha->i; + if (nounit) { + if (noconj) { + i__1 = k + k * a_dim1; + z__1.r = temp.r * a[i__1].r - temp.i * a[i__1].i, + z__1.i = temp.r * a[i__1].i + temp.i * a[ + i__1].r; + temp.r = z__1.r, temp.i = z__1.i; + } else { + d_cnjg(&z__2, &a[k + k * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + } + if (temp.r != 1. || temp.i != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + k * b_dim1; + i__3 = i__ + k * b_dim1; + z__1.r = temp.r * b[i__3].r - temp.i * b[i__3].i, + z__1.i = temp.r * b[i__3].i + temp.i * b[ + i__3].r; + b[i__2].r = z__1.r, b[i__2].i = z__1.i; +/* L310: */ + } + } +/* L320: */ + } + } + } + } + + return 0; + +/* End of ZTRMM . */ + +} /* ztrmm_ */ + +/* Subroutine */ int ztrmv_(char *uplo, char *trans, char *diag, integer *n, + doublecomplex *a, integer *lda, doublecomplex *x, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, j, ix, jx, kx, info; + static doublecomplex temp; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj, nounit; + + +/* + Purpose + ======= + + ZTRMV performs one of the matrix-vector operations + + x := A*x, or x := A'*x, or x := conjg( A' )*x, + + where x is an n element vector and A is an n by n unit, or non-unit, + upper or lower triangular matrix. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' x := A*x. + + TRANS = 'T' or 't' x := A'*x. + + TRANS = 'C' or 'c' x := conjg( A' )*x. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit + triangular as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - COMPLEX*16 array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element vector x. On exit, X is overwritten with the + tranformed vector x. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < max(1,*n)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } + if (info != 0) { + xerbla_("ZTRMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + noconj = lsame_(trans, "T"); + nounit = lsame_(diag, "N"); + +/* + Set up the start point in X if the increment is not unity. This + will be ( N - 1 )*INCX too small for descending loops. +*/ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (lsame_(trans, "N")) { + +/* Form x := A*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + if (x[i__2].r != 0. || x[i__2].i != 0.) { + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + z__1.r = x[i__4].r + z__2.r, z__1.i = x[i__4].i + + z__2.i; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; +/* L10: */ + } + if (nounit) { + i__2 = j; + i__3 = j; + i__4 = j + j * a_dim1; + z__1.r = x[i__3].r * a[i__4].r - x[i__3].i * a[ + i__4].i, z__1.i = x[i__3].r * a[i__4].i + + x[i__3].i * a[i__4].r; + x[i__2].r = z__1.r, x[i__2].i = z__1.i; + } + } +/* L20: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + if (x[i__2].r != 0. || x[i__2].i != 0.) { + i__2 = jx; + temp.r = x[i__2].r, temp.i = x[i__2].i; + ix = kx; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = ix; + i__4 = ix; + i__5 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + z__1.r = x[i__4].r + z__2.r, z__1.i = x[i__4].i + + z__2.i; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + ix += *incx; +/* L30: */ + } + if (nounit) { + i__2 = jx; + i__3 = jx; + i__4 = j + j * a_dim1; + z__1.r = x[i__3].r * a[i__4].r - x[i__3].i * a[ + i__4].i, z__1.i = x[i__3].r * a[i__4].i + + x[i__3].i * a[i__4].r; + x[i__2].r = z__1.r, x[i__2].i = z__1.i; + } + } + jx += *incx; +/* L40: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + if (x[i__1].r != 0. || x[i__1].i != 0.) { + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + i__2 = i__; + i__3 = i__; + i__4 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__4].r - temp.i * a[i__4].i, + z__2.i = temp.r * a[i__4].i + temp.i * a[ + i__4].r; + z__1.r = x[i__3].r + z__2.r, z__1.i = x[i__3].i + + z__2.i; + x[i__2].r = z__1.r, x[i__2].i = z__1.i; +/* L50: */ + } + if (nounit) { + i__1 = j; + i__2 = j; + i__3 = j + j * a_dim1; + z__1.r = x[i__2].r * a[i__3].r - x[i__2].i * a[ + i__3].i, z__1.i = x[i__2].r * a[i__3].i + + x[i__2].i * a[i__3].r; + x[i__1].r = z__1.r, x[i__1].i = z__1.i; + } + } +/* L60: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + i__1 = jx; + if (x[i__1].r != 0. || x[i__1].i != 0.) { + i__1 = jx; + temp.r = x[i__1].r, temp.i = x[i__1].i; + ix = kx; + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + i__2 = ix; + i__3 = ix; + i__4 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__4].r - temp.i * a[i__4].i, + z__2.i = temp.r * a[i__4].i + temp.i * a[ + i__4].r; + z__1.r = x[i__3].r + z__2.r, z__1.i = x[i__3].i + + z__2.i; + x[i__2].r = z__1.r, x[i__2].i = z__1.i; + ix -= *incx; +/* L70: */ + } + if (nounit) { + i__1 = jx; + i__2 = jx; + i__3 = j + j * a_dim1; + z__1.r = x[i__2].r * a[i__3].r - x[i__2].i * a[ + i__3].i, z__1.i = x[i__2].r * a[i__3].i + + x[i__2].i * a[i__3].r; + x[i__1].r = z__1.r, x[i__1].i = z__1.i; + } + } + jx -= *incx; +/* L80: */ + } + } + } + } else { + +/* Form x := A'*x or x := conjg( A' )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + if (noconj) { + if (nounit) { + i__1 = j + j * a_dim1; + z__1.r = temp.r * a[i__1].r - temp.i * a[i__1].i, + z__1.i = temp.r * a[i__1].i + temp.i * a[ + i__1].r; + temp.r = z__1.r, temp.i = z__1.i; + } + for (i__ = j - 1; i__ >= 1; --i__) { + i__1 = i__ + j * a_dim1; + i__2 = i__; + z__2.r = a[i__1].r * x[i__2].r - a[i__1].i * x[ + i__2].i, z__2.i = a[i__1].r * x[i__2].i + + a[i__1].i * x[i__2].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L90: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + for (i__ = j - 1; i__ >= 1; --i__) { + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__1 = i__; + z__2.r = z__3.r * x[i__1].r - z__3.i * x[i__1].i, + z__2.i = z__3.r * x[i__1].i + z__3.i * x[ + i__1].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L100: */ + } + } + i__1 = j; + x[i__1].r = temp.r, x[i__1].i = temp.i; +/* L110: */ + } + } else { + jx = kx + (*n - 1) * *incx; + for (j = *n; j >= 1; --j) { + i__1 = jx; + temp.r = x[i__1].r, temp.i = x[i__1].i; + ix = jx; + if (noconj) { + if (nounit) { + i__1 = j + j * a_dim1; + z__1.r = temp.r * a[i__1].r - temp.i * a[i__1].i, + z__1.i = temp.r * a[i__1].i + temp.i * a[ + i__1].r; + temp.r = z__1.r, temp.i = z__1.i; + } + for (i__ = j - 1; i__ >= 1; --i__) { + ix -= *incx; + i__1 = i__ + j * a_dim1; + i__2 = ix; + z__2.r = a[i__1].r * x[i__2].r - a[i__1].i * x[ + i__2].i, z__2.i = a[i__1].r * x[i__2].i + + a[i__1].i * x[i__2].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L120: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + for (i__ = j - 1; i__ >= 1; --i__) { + ix -= *incx; + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__1 = ix; + z__2.r = z__3.r * x[i__1].r - z__3.i * x[i__1].i, + z__2.i = z__3.r * x[i__1].i + z__3.i * x[ + i__1].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L130: */ + } + } + i__1 = jx; + x[i__1].r = temp.r, x[i__1].i = temp.i; + jx -= *incx; +/* L140: */ + } + } + } else { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + if (noconj) { + if (nounit) { + i__2 = j + j * a_dim1; + z__1.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + z__1.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__; + z__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[ + i__4].i, z__2.i = a[i__3].r * x[i__4].i + + a[i__3].i * x[i__4].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L150: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = i__; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, + z__2.i = z__3.r * x[i__3].i + z__3.i * x[ + i__3].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L160: */ + } + } + i__2 = j; + x[i__2].r = temp.r, x[i__2].i = temp.i; +/* L170: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + temp.r = x[i__2].r, temp.i = x[i__2].i; + ix = jx; + if (noconj) { + if (nounit) { + i__2 = j + j * a_dim1; + z__1.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + z__1.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + i__3 = i__ + j * a_dim1; + i__4 = ix; + z__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[ + i__4].i, z__2.i = a[i__3].r * x[i__4].i + + a[i__3].i * x[i__4].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L180: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = ix; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, + z__2.i = z__3.r * x[i__3].i + z__3.i * x[ + i__3].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L190: */ + } + } + i__2 = jx; + x[i__2].r = temp.r, x[i__2].i = temp.i; + jx += *incx; +/* L200: */ + } + } + } + } + + return 0; + +/* End of ZTRMV . */ + +} /* ztrmv_ */ + +/* Subroutine */ int ztrsm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, doublecomplex *alpha, doublecomplex *a, + integer *lda, doublecomplex *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4, i__5, + i__6, i__7; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, j, k, info; + static doublecomplex temp; + static logical lside; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj, nounit; + + +/* + Purpose + ======= + + ZTRSM solves one of the matrix equations + + op( A )*X = alpha*B, or X*op( A ) = alpha*B, + + where alpha is a scalar, X and B are m by n matrices, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A' or op( A ) = conjg( A' ). + + The matrix X is overwritten on B. + + Arguments + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) appears on the left + or right of X as follows: + + SIDE = 'L' or 'l' op( A )*X = alpha*B. + + SIDE = 'R' or 'r' X*op( A ) = alpha*B. + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = conjg( A' ). + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - COMPLEX*16 . + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - COMPLEX*16 array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the right-hand side matrix B, and on exit is + overwritten by the solution matrix X. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + Further Details + =============== + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + noconj = lsame_(transa, "T"); + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("ZTRSM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (alpha->r == 0. && alpha->i == 0.) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + b[i__3].r = 0., b[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*inv( A )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (alpha->r != 1. || alpha->i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + z__1.r = alpha->r * b[i__4].r - alpha->i * b[i__4] + .i, z__1.i = alpha->r * b[i__4].i + + alpha->i * b[i__4].r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L30: */ + } + } + for (k = *m; k >= 1; --k) { + i__2 = k + j * b_dim1; + if (b[i__2].r != 0. || b[i__2].i != 0.) { + if (nounit) { + i__2 = k + j * b_dim1; + z_div(&z__1, &b[k + j * b_dim1], &a[k + k * + a_dim1]); + b[i__2].r = z__1.r, b[i__2].i = z__1.i; + } + i__2 = k - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = k + j * b_dim1; + i__6 = i__ + k * a_dim1; + z__2.r = b[i__5].r * a[i__6].r - b[i__5].i * + a[i__6].i, z__2.i = b[i__5].r * a[ + i__6].i + b[i__5].i * a[i__6].r; + z__1.r = b[i__4].r - z__2.r, z__1.i = b[i__4] + .i - z__2.i; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L40: */ + } + } +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (alpha->r != 1. || alpha->i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + z__1.r = alpha->r * b[i__4].r - alpha->i * b[i__4] + .i, z__1.i = alpha->r * b[i__4].i + + alpha->i * b[i__4].r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L70: */ + } + } + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + i__3 = k + j * b_dim1; + if (b[i__3].r != 0. || b[i__3].i != 0.) { + if (nounit) { + i__3 = k + j * b_dim1; + z_div(&z__1, &b[k + j * b_dim1], &a[k + k * + a_dim1]); + b[i__3].r = z__1.r, b[i__3].i = z__1.i; + } + i__3 = *m; + for (i__ = k + 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = k + j * b_dim1; + i__7 = i__ + k * a_dim1; + z__2.r = b[i__6].r * a[i__7].r - b[i__6].i * + a[i__7].i, z__2.i = b[i__6].r * a[ + i__7].i + b[i__6].i * a[i__7].r; + z__1.r = b[i__5].r - z__2.r, z__1.i = b[i__5] + .i - z__2.i; + b[i__4].r = z__1.r, b[i__4].i = z__1.i; +/* L80: */ + } + } +/* L90: */ + } +/* L100: */ + } + } + } else { + +/* + Form B := alpha*inv( A' )*B + or B := alpha*inv( conjg( A' ) )*B. +*/ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + z__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3].i, + z__1.i = alpha->r * b[i__3].i + alpha->i * b[ + i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + if (noconj) { + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + i__4 = k + i__ * a_dim1; + i__5 = k + j * b_dim1; + z__2.r = a[i__4].r * b[i__5].r - a[i__4].i * + b[i__5].i, z__2.i = a[i__4].r * b[ + i__5].i + a[i__4].i * b[i__5].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L110: */ + } + if (nounit) { + z_div(&z__1, &temp, &a[i__ + i__ * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } + } else { + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + d_cnjg(&z__3, &a[k + i__ * a_dim1]); + i__4 = k + j * b_dim1; + z__2.r = z__3.r * b[i__4].r - z__3.i * b[i__4] + .i, z__2.i = z__3.r * b[i__4].i + + z__3.i * b[i__4].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L120: */ + } + if (nounit) { + d_cnjg(&z__2, &a[i__ + i__ * a_dim1]); + z_div(&z__1, &temp, &z__2); + temp.r = z__1.r, temp.i = z__1.i; + } + } + i__3 = i__ + j * b_dim1; + b[i__3].r = temp.r, b[i__3].i = temp.i; +/* L130: */ + } +/* L140: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + i__2 = i__ + j * b_dim1; + z__1.r = alpha->r * b[i__2].r - alpha->i * b[i__2].i, + z__1.i = alpha->r * b[i__2].i + alpha->i * b[ + i__2].r; + temp.r = z__1.r, temp.i = z__1.i; + if (noconj) { + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + i__3 = k + i__ * a_dim1; + i__4 = k + j * b_dim1; + z__2.r = a[i__3].r * b[i__4].r - a[i__3].i * + b[i__4].i, z__2.i = a[i__3].r * b[ + i__4].i + a[i__3].i * b[i__4].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L150: */ + } + if (nounit) { + z_div(&z__1, &temp, &a[i__ + i__ * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } + } else { + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + d_cnjg(&z__3, &a[k + i__ * a_dim1]); + i__3 = k + j * b_dim1; + z__2.r = z__3.r * b[i__3].r - z__3.i * b[i__3] + .i, z__2.i = z__3.r * b[i__3].i + + z__3.i * b[i__3].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L160: */ + } + if (nounit) { + d_cnjg(&z__2, &a[i__ + i__ * a_dim1]); + z_div(&z__1, &temp, &z__2); + temp.r = z__1.r, temp.i = z__1.i; + } + } + i__2 = i__ + j * b_dim1; + b[i__2].r = temp.r, b[i__2].i = temp.i; +/* L170: */ + } +/* L180: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*inv( A ). */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (alpha->r != 1. || alpha->i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + z__1.r = alpha->r * b[i__4].r - alpha->i * b[i__4] + .i, z__1.i = alpha->r * b[i__4].i + + alpha->i * b[i__4].r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L190: */ + } + } + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + i__3 = k + j * a_dim1; + if (a[i__3].r != 0. || a[i__3].i != 0.) { + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = k + j * a_dim1; + i__7 = i__ + k * b_dim1; + z__2.r = a[i__6].r * b[i__7].r - a[i__6].i * + b[i__7].i, z__2.i = a[i__6].r * b[ + i__7].i + a[i__6].i * b[i__7].r; + z__1.r = b[i__5].r - z__2.r, z__1.i = b[i__5] + .i - z__2.i; + b[i__4].r = z__1.r, b[i__4].i = z__1.i; +/* L200: */ + } + } +/* L210: */ + } + if (nounit) { + z_div(&z__1, &c_b1078, &a[j + j * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + z__1.r = temp.r * b[i__4].r - temp.i * b[i__4].i, + z__1.i = temp.r * b[i__4].i + temp.i * b[ + i__4].r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L220: */ + } + } +/* L230: */ + } + } else { + for (j = *n; j >= 1; --j) { + if (alpha->r != 1. || alpha->i != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * b_dim1; + i__3 = i__ + j * b_dim1; + z__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3] + .i, z__1.i = alpha->r * b[i__3].i + + alpha->i * b[i__3].r; + b[i__2].r = z__1.r, b[i__2].i = z__1.i; +/* L240: */ + } + } + i__1 = *n; + for (k = j + 1; k <= i__1; ++k) { + i__2 = k + j * a_dim1; + if (a[i__2].r != 0. || a[i__2].i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = k + j * a_dim1; + i__6 = i__ + k * b_dim1; + z__2.r = a[i__5].r * b[i__6].r - a[i__5].i * + b[i__6].i, z__2.i = a[i__5].r * b[ + i__6].i + a[i__5].i * b[i__6].r; + z__1.r = b[i__4].r - z__2.r, z__1.i = b[i__4] + .i - z__2.i; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L250: */ + } + } +/* L260: */ + } + if (nounit) { + z_div(&z__1, &c_b1078, &a[j + j * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * b_dim1; + i__3 = i__ + j * b_dim1; + z__1.r = temp.r * b[i__3].r - temp.i * b[i__3].i, + z__1.i = temp.r * b[i__3].i + temp.i * b[ + i__3].r; + b[i__2].r = z__1.r, b[i__2].i = z__1.i; +/* L270: */ + } + } +/* L280: */ + } + } + } else { + +/* + Form B := alpha*B*inv( A' ) + or B := alpha*B*inv( conjg( A' ) ). +*/ + + if (upper) { + for (k = *n; k >= 1; --k) { + if (nounit) { + if (noconj) { + z_div(&z__1, &c_b1078, &a[k + k * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } else { + d_cnjg(&z__2, &a[k + k * a_dim1]); + z_div(&z__1, &c_b1078, &z__2); + temp.r = z__1.r, temp.i = z__1.i; + } + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + k * b_dim1; + i__3 = i__ + k * b_dim1; + z__1.r = temp.r * b[i__3].r - temp.i * b[i__3].i, + z__1.i = temp.r * b[i__3].i + temp.i * b[ + i__3].r; + b[i__2].r = z__1.r, b[i__2].i = z__1.i; +/* L290: */ + } + } + i__1 = k - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = j + k * a_dim1; + if (a[i__2].r != 0. || a[i__2].i != 0.) { + if (noconj) { + i__2 = j + k * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + } else { + d_cnjg(&z__1, &a[j + k * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * b_dim1; + i__5 = i__ + k * b_dim1; + z__2.r = temp.r * b[i__5].r - temp.i * b[i__5] + .i, z__2.i = temp.r * b[i__5].i + + temp.i * b[i__5].r; + z__1.r = b[i__4].r - z__2.r, z__1.i = b[i__4] + .i - z__2.i; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L300: */ + } + } +/* L310: */ + } + if (alpha->r != 1. || alpha->i != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + k * b_dim1; + i__3 = i__ + k * b_dim1; + z__1.r = alpha->r * b[i__3].r - alpha->i * b[i__3] + .i, z__1.i = alpha->r * b[i__3].i + + alpha->i * b[i__3].r; + b[i__2].r = z__1.r, b[i__2].i = z__1.i; +/* L320: */ + } + } +/* L330: */ + } + } else { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + if (nounit) { + if (noconj) { + z_div(&z__1, &c_b1078, &a[k + k * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } else { + d_cnjg(&z__2, &a[k + k * a_dim1]); + z_div(&z__1, &c_b1078, &z__2); + temp.r = z__1.r, temp.i = z__1.i; + } + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + k * b_dim1; + i__4 = i__ + k * b_dim1; + z__1.r = temp.r * b[i__4].r - temp.i * b[i__4].i, + z__1.i = temp.r * b[i__4].i + temp.i * b[ + i__4].r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L340: */ + } + } + i__2 = *n; + for (j = k + 1; j <= i__2; ++j) { + i__3 = j + k * a_dim1; + if (a[i__3].r != 0. || a[i__3].i != 0.) { + if (noconj) { + i__3 = j + k * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + } else { + d_cnjg(&z__1, &a[j + k * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * b_dim1; + i__5 = i__ + j * b_dim1; + i__6 = i__ + k * b_dim1; + z__2.r = temp.r * b[i__6].r - temp.i * b[i__6] + .i, z__2.i = temp.r * b[i__6].i + + temp.i * b[i__6].r; + z__1.r = b[i__5].r - z__2.r, z__1.i = b[i__5] + .i - z__2.i; + b[i__4].r = z__1.r, b[i__4].i = z__1.i; +/* L350: */ + } + } +/* L360: */ + } + if (alpha->r != 1. || alpha->i != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + k * b_dim1; + i__4 = i__ + k * b_dim1; + z__1.r = alpha->r * b[i__4].r - alpha->i * b[i__4] + .i, z__1.i = alpha->r * b[i__4].i + + alpha->i * b[i__4].r; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L370: */ + } + } +/* L380: */ + } + } + } + } + + return 0; + +/* End of ZTRSM . */ + +} /* ztrsm_ */ + +/* Subroutine */ int ztrsv_(char *uplo, char *trans, char *diag, integer *n, + doublecomplex *a, integer *lda, doublecomplex *x, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, j, ix, jx, kx, info; + static doublecomplex temp; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconj, nounit; + + +/* + Purpose + ======= + + ZTRSV solves one of the systems of equations + + A*x = b, or A'*x = b, or conjg( A' )*x = b, + + where b and x are n element vectors and A is an n by n unit, or + non-unit, upper or lower triangular matrix. + + No test for singularity or near-singularity is included in this + routine. Such tests must be performed before calling this routine. + + Arguments + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the equations to be solved as + follows: + + TRANS = 'N' or 'n' A*x = b. + + TRANS = 'T' or 't' A'*x = b. + + TRANS = 'C' or 'c' conjg( A' )*x = b. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit + triangular as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + A - COMPLEX*16 array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - COMPLEX*16 array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element right-hand side vector b. On exit, X is overwritten + with the solution vector x. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + Further Details + =============== + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < max(1,*n)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } + if (info != 0) { + xerbla_("ZTRSV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + noconj = lsame_(trans, "T"); + nounit = lsame_(diag, "N"); + +/* + Set up the start point in X if the increment is not unity. This + will be ( N - 1 )*INCX too small for descending loops. +*/ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. +*/ + + if (lsame_(trans, "N")) { + +/* Form x := inv( A )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + if (x[i__1].r != 0. || x[i__1].i != 0.) { + if (nounit) { + i__1 = j; + z_div(&z__1, &x[j], &a[j + j * a_dim1]); + x[i__1].r = z__1.r, x[i__1].i = z__1.i; + } + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + for (i__ = j - 1; i__ >= 1; --i__) { + i__1 = i__; + i__2 = i__; + i__3 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__3].r - temp.i * a[i__3].i, + z__2.i = temp.r * a[i__3].i + temp.i * a[ + i__3].r; + z__1.r = x[i__2].r - z__2.r, z__1.i = x[i__2].i - + z__2.i; + x[i__1].r = z__1.r, x[i__1].i = z__1.i; +/* L10: */ + } + } +/* L20: */ + } + } else { + jx = kx + (*n - 1) * *incx; + for (j = *n; j >= 1; --j) { + i__1 = jx; + if (x[i__1].r != 0. || x[i__1].i != 0.) { + if (nounit) { + i__1 = jx; + z_div(&z__1, &x[jx], &a[j + j * a_dim1]); + x[i__1].r = z__1.r, x[i__1].i = z__1.i; + } + i__1 = jx; + temp.r = x[i__1].r, temp.i = x[i__1].i; + ix = jx; + for (i__ = j - 1; i__ >= 1; --i__) { + ix -= *incx; + i__1 = ix; + i__2 = ix; + i__3 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__3].r - temp.i * a[i__3].i, + z__2.i = temp.r * a[i__3].i + temp.i * a[ + i__3].r; + z__1.r = x[i__2].r - z__2.r, z__1.i = x[i__2].i - + z__2.i; + x[i__1].r = z__1.r, x[i__1].i = z__1.i; +/* L30: */ + } + } + jx -= *incx; +/* L40: */ + } + } + } else { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + if (x[i__2].r != 0. || x[i__2].i != 0.) { + if (nounit) { + i__2 = j; + z_div(&z__1, &x[j], &a[j + j * a_dim1]); + x[i__2].r = z__1.r, x[i__2].i = z__1.i; + } + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + z__1.r = x[i__4].r - z__2.r, z__1.i = x[i__4].i - + z__2.i; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; +/* L50: */ + } + } +/* L60: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + if (x[i__2].r != 0. || x[i__2].i != 0.) { + if (nounit) { + i__2 = jx; + z_div(&z__1, &x[jx], &a[j + j * a_dim1]); + x[i__2].r = z__1.r, x[i__2].i = z__1.i; + } + i__2 = jx; + temp.r = x[i__2].r, temp.i = x[i__2].i; + ix = jx; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + ix += *incx; + i__3 = ix; + i__4 = ix; + i__5 = i__ + j * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + z__1.r = x[i__4].r - z__2.r, z__1.i = x[i__4].i - + z__2.i; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } + } else { + +/* Form x := inv( A' )*x or x := inv( conjg( A' ) )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + if (noconj) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__; + z__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[ + i__4].i, z__2.i = a[i__3].r * x[i__4].i + + a[i__3].i * x[i__4].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L90: */ + } + if (nounit) { + z_div(&z__1, &temp, &a[j + j * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } + } else { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = i__; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, + z__2.i = z__3.r * x[i__3].i + z__3.i * x[ + i__3].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L100: */ + } + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z_div(&z__1, &temp, &z__2); + temp.r = z__1.r, temp.i = z__1.i; + } + } + i__2 = j; + x[i__2].r = temp.r, x[i__2].i = temp.i; +/* L110: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + ix = kx; + i__2 = jx; + temp.r = x[i__2].r, temp.i = x[i__2].i; + if (noconj) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = ix; + z__2.r = a[i__3].r * x[i__4].r - a[i__3].i * x[ + i__4].i, z__2.i = a[i__3].r * x[i__4].i + + a[i__3].i * x[i__4].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix += *incx; +/* L120: */ + } + if (nounit) { + z_div(&z__1, &temp, &a[j + j * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } + } else { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__3 = ix; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, + z__2.i = z__3.r * x[i__3].i + z__3.i * x[ + i__3].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix += *incx; +/* L130: */ + } + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z_div(&z__1, &temp, &z__2); + temp.r = z__1.r, temp.i = z__1.i; + } + } + i__2 = jx; + x[i__2].r = temp.r, x[i__2].i = temp.i; + jx += *incx; +/* L140: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + if (noconj) { + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + i__2 = i__ + j * a_dim1; + i__3 = i__; + z__2.r = a[i__2].r * x[i__3].r - a[i__2].i * x[ + i__3].i, z__2.i = a[i__2].r * x[i__3].i + + a[i__2].i * x[i__3].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L150: */ + } + if (nounit) { + z_div(&z__1, &temp, &a[j + j * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } + } else { + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__2 = i__; + z__2.r = z__3.r * x[i__2].r - z__3.i * x[i__2].i, + z__2.i = z__3.r * x[i__2].i + z__3.i * x[ + i__2].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L160: */ + } + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z_div(&z__1, &temp, &z__2); + temp.r = z__1.r, temp.i = z__1.i; + } + } + i__1 = j; + x[i__1].r = temp.r, x[i__1].i = temp.i; +/* L170: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + ix = kx; + i__1 = jx; + temp.r = x[i__1].r, temp.i = x[i__1].i; + if (noconj) { + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + i__2 = i__ + j * a_dim1; + i__3 = ix; + z__2.r = a[i__2].r * x[i__3].r - a[i__2].i * x[ + i__3].i, z__2.i = a[i__2].r * x[i__3].i + + a[i__2].i * x[i__3].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix -= *incx; +/* L180: */ + } + if (nounit) { + z_div(&z__1, &temp, &a[j + j * a_dim1]); + temp.r = z__1.r, temp.i = z__1.i; + } + } else { + i__1 = j + 1; + for (i__ = *n; i__ >= i__1; --i__) { + d_cnjg(&z__3, &a[i__ + j * a_dim1]); + i__2 = ix; + z__2.r = z__3.r * x[i__2].r - z__3.i * x[i__2].i, + z__2.i = z__3.r * x[i__2].i + z__3.i * x[ + i__2].r; + z__1.r = temp.r - z__2.r, z__1.i = temp.i - + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix -= *incx; +/* L190: */ + } + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z_div(&z__1, &temp, &z__2); + temp.r = z__1.r, temp.i = z__1.i; + } + } + i__1 = jx; + x[i__1].r = temp.r, x[i__1].i = temp.i; + jx -= *incx; +/* L200: */ + } + } + } + } + + return 0; + +/* End of ZTRSV . */ + +} /* ztrsv_ */ + diff --git a/numpy/linalg/lapack_lite/f2c_c_lapack.c b/numpy/linalg/lapack_lite/f2c_c_lapack.c new file mode 100644 index 0000000..25221ba --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c_c_lapack.c @@ -0,0 +1,27203 @@ +/* +NOTE: This is generated code. Look in Misc/lapack_lite for information on + remaking this file. +*/ +#include "f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal dlamch_(char *); +#define EPSILON dlamch_("Epsilon") +#define SAFEMINIMUM dlamch_("Safe minimum") +#define PRECISION dlamch_("Precision") +#define BASE dlamch_("Base") +#endif + +extern doublereal dlapy2_(doublereal *x, doublereal *y); + +/* +f2c knows the exact rules for precedence, and so omits parentheses where not +strictly necessary. Since this is generated code, we don't really care if +it's readable, and we know what is written is correct. So don't warn about +them. +*/ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wparentheses" +#endif + + +/* Table of constant values */ + +static integer c__1 = 1; +static complex c_b56 = {0.f,0.f}; +static complex c_b57 = {1.f,0.f}; +static integer c_n1 = -1; +static integer c__3 = 3; +static integer c__2 = 2; +static integer c__0 = 0; +static integer c__65 = 65; +static real c_b894 = 1.f; +static integer c__12 = 12; +static integer c__49 = 49; +static real c_b1087 = 0.f; +static integer c__9 = 9; +static real c_b1136 = -1.f; +static integer c__13 = 13; +static integer c__15 = 15; +static integer c__14 = 14; +static integer c__16 = 16; +static logical c_false = FALSE_; +static logical c_true = TRUE_; +static real c_b2023 = .5f; + +/* Subroutine */ int cgebak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, real *scale, integer *m, complex *v, integer *ldv, + integer *info) +{ + /* System generated locals */ + integer v_dim1, v_offset, i__1; + + /* Local variables */ + static integer i__, k; + static real s; + static integer ii; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int cswap_(integer *, complex *, integer *, + complex *, integer *); + static logical leftv; + extern /* Subroutine */ int csscal_(integer *, real *, complex *, integer + *), xerbla_(char *, integer *); + static logical rightv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGEBAK forms the right or left eigenvectors of a complex general + matrix by backward transformation on the computed eigenvectors of the + balanced matrix output by CGEBAL. + + Arguments + ========= + + JOB (input) CHARACTER*1 + Specifies the type of backward transformation required: + = 'N', do nothing, return immediately; + = 'P', do backward transformation for permutation only; + = 'S', do backward transformation for scaling only; + = 'B', do backward transformations for both permutation and + scaling. + JOB must be the same as the argument JOB supplied to CGEBAL. + + SIDE (input) CHARACTER*1 + = 'R': V contains right eigenvectors; + = 'L': V contains left eigenvectors. + + N (input) INTEGER + The number of rows of the matrix V. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + The integers ILO and IHI determined by CGEBAL. + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + SCALE (input) REAL array, dimension (N) + Details of the permutation and scaling factors, as returned + by CGEBAL. + + M (input) INTEGER + The number of columns of the matrix V. M >= 0. + + V (input/output) COMPLEX array, dimension (LDV,M) + On entry, the matrix of right or left eigenvectors to be + transformed, as returned by CHSEIN or CTREVC. + On exit, V is overwritten by the transformed eigenvectors. + + LDV (input) INTEGER + The leading dimension of the array V. LDV >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Decode and Test the input parameters +*/ + + /* Parameter adjustments */ + --scale; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + + /* Function Body */ + rightv = lsame_(side, "R"); + leftv = lsame_(side, "L"); + + *info = 0; + if (! lsame_(job, "N") && ! lsame_(job, "P") && ! lsame_(job, "S") + && ! lsame_(job, "B")) { + *info = -1; + } else if (! rightv && ! leftv) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -4; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -5; + } else if (*m < 0) { + *info = -7; + } else if (*ldv < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGEBAK", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*m == 0) { + return 0; + } + if (lsame_(job, "N")) { + return 0; + } + + if (*ilo == *ihi) { + goto L30; + } + +/* Backward balance */ + + if (lsame_(job, "S") || lsame_(job, "B")) { + + if (rightv) { + i__1 = *ihi; + for (i__ = *ilo; i__ <= i__1; ++i__) { + s = scale[i__]; + csscal_(m, &s, &v[i__ + v_dim1], ldv); +/* L10: */ + } + } + + if (leftv) { + i__1 = *ihi; + for (i__ = *ilo; i__ <= i__1; ++i__) { + s = 1.f / scale[i__]; + csscal_(m, &s, &v[i__ + v_dim1], ldv); +/* L20: */ + } + } + + } + +/* + Backward permutation + + For I = ILO-1 step -1 until 1, + IHI+1 step 1 until N do -- +*/ + +L30: + if (lsame_(job, "P") || lsame_(job, "B")) { + if (rightv) { + i__1 = *n; + for (ii = 1; ii <= i__1; ++ii) { + i__ = ii; + if (i__ >= *ilo && i__ <= *ihi) { + goto L40; + } + if (i__ < *ilo) { + i__ = *ilo - ii; + } + k = scale[i__]; + if (k == i__) { + goto L40; + } + cswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv); +L40: + ; + } + } + + if (leftv) { + i__1 = *n; + for (ii = 1; ii <= i__1; ++ii) { + i__ = ii; + if (i__ >= *ilo && i__ <= *ihi) { + goto L50; + } + if (i__ < *ilo) { + i__ = *ilo - ii; + } + k = scale[i__]; + if (k == i__) { + goto L50; + } + cswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv); +L50: + ; + } + } + } + + return 0; + +/* End of CGEBAK */ + +} /* cgebak_ */ + +/* Subroutine */ int cgebal_(char *job, integer *n, complex *a, integer *lda, + integer *ilo, integer *ihi, real *scale, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + real r__1, r__2; + + /* Local variables */ + static real c__, f, g; + static integer i__, j, k, l, m; + static real r__, s, ca, ra; + static integer ica, ira, iexc; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int cswap_(integer *, complex *, integer *, + complex *, integer *); + static real sfmin1, sfmin2, sfmax1, sfmax2; + extern integer icamax_(integer *, complex *, integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int csscal_(integer *, real *, complex *, integer + *), xerbla_(char *, integer *); + extern logical sisnan_(real *); + static logical noconv; + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + CGEBAL balances a general complex matrix A. This involves, first, + permuting A by a similarity transformation to isolate eigenvalues + in the first 1 to ILO-1 and last IHI+1 to N elements on the + diagonal; and second, applying a diagonal similarity transformation + to rows and columns ILO to IHI to make the rows and columns as + close in norm as possible. Both steps are optional. + + Balancing may reduce the 1-norm of the matrix, and improve the + accuracy of the computed eigenvalues and/or eigenvectors. + + Arguments + ========= + + JOB (input) CHARACTER*1 + Specifies the operations to be performed on A: + = 'N': none: simply set ILO = 1, IHI = N, SCALE(I) = 1.0 + for i = 1,...,N; + = 'P': permute only; + = 'S': scale only; + = 'B': both permute and scale. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the input matrix A. + On exit, A is overwritten by the balanced matrix. + If JOB = 'N', A is not referenced. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + ILO (output) INTEGER + IHI (output) INTEGER + ILO and IHI are set to integers such that on exit + A(i,j) = 0 if i > j and j = 1,...,ILO-1 or I = IHI+1,...,N. + If JOB = 'N' or 'S', ILO = 1 and IHI = N. + + SCALE (output) REAL array, dimension (N) + Details of the permutations and scaling factors applied to + A. If P(j) is the index of the row and column interchanged + with row and column j and D(j) is the scaling factor + applied to row and column j, then + SCALE(j) = P(j) for j = 1,...,ILO-1 + = D(j) for j = ILO,...,IHI + = P(j) for j = IHI+1,...,N. + The order in which the interchanges are made is N to IHI+1, + then 1 to ILO-1. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The permutations consist of row and column interchanges which put + the matrix in the form + + ( T1 X Y ) + P A P = ( 0 B Z ) + ( 0 0 T2 ) + + where T1 and T2 are upper triangular matrices whose eigenvalues lie + along the diagonal. The column indices ILO and IHI mark the starting + and ending columns of the submatrix B. Balancing consists of applying + a diagonal similarity transformation inv(D) * B * D to make the + 1-norms of each row of B and its corresponding column nearly equal. + The output matrix is + + ( T1 X*D Y ) + ( 0 inv(D)*B*D inv(D)*Z ). + ( 0 0 T2 ) + + Information about the permutations P and the diagonal matrix D is + returned in the vector SCALE. + + This subroutine is based on the EISPACK routine CBAL. + + Modified by Tzu-Yi Chen, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --scale; + + /* Function Body */ + *info = 0; + if (! lsame_(job, "N") && ! lsame_(job, "P") && ! lsame_(job, "S") + && ! lsame_(job, "B")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGEBAL", &i__1); + return 0; + } + + k = 1; + l = *n; + + if (*n == 0) { + goto L210; + } + + if (lsame_(job, "N")) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + scale[i__] = 1.f; +/* L10: */ + } + goto L210; + } + + if (lsame_(job, "S")) { + goto L120; + } + +/* Permutation to isolate eigenvalues if possible */ + + goto L50; + +/* Row and column exchange. */ + +L20: + scale[m] = (real) j; + if (j == m) { + goto L30; + } + + cswap_(&l, &a[j * a_dim1 + 1], &c__1, &a[m * a_dim1 + 1], &c__1); + i__1 = *n - k + 1; + cswap_(&i__1, &a[j + k * a_dim1], lda, &a[m + k * a_dim1], lda); + +L30: + switch (iexc) { + case 1: goto L40; + case 2: goto L80; + } + +/* Search for rows isolating an eigenvalue and push them down. */ + +L40: + if (l == 1) { + goto L210; + } + --l; + +L50: + for (j = l; j >= 1; --j) { + + i__1 = l; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__ == j) { + goto L60; + } + i__2 = j + i__ * a_dim1; + if (a[i__2].r != 0.f || r_imag(&a[j + i__ * a_dim1]) != 0.f) { + goto L70; + } +L60: + ; + } + + m = l; + iexc = 1; + goto L20; +L70: + ; + } + + goto L90; + +/* Search for columns isolating an eigenvalue and push them left. */ + +L80: + ++k; + +L90: + i__1 = l; + for (j = k; j <= i__1; ++j) { + + i__2 = l; + for (i__ = k; i__ <= i__2; ++i__) { + if (i__ == j) { + goto L100; + } + i__3 = i__ + j * a_dim1; + if (a[i__3].r != 0.f || r_imag(&a[i__ + j * a_dim1]) != 0.f) { + goto L110; + } +L100: + ; + } + + m = k; + iexc = 2; + goto L20; +L110: + ; + } + +L120: + i__1 = l; + for (i__ = k; i__ <= i__1; ++i__) { + scale[i__] = 1.f; +/* L130: */ + } + + if (lsame_(job, "P")) { + goto L210; + } + +/* + Balance the submatrix in rows K to L. + + Iterative loop for norm reduction +*/ + + sfmin1 = slamch_("S") / slamch_("P"); + sfmax1 = 1.f / sfmin1; + sfmin2 = sfmin1 * 2.f; + sfmax2 = 1.f / sfmin2; +L140: + noconv = FALSE_; + + i__1 = l; + for (i__ = k; i__ <= i__1; ++i__) { + c__ = 0.f; + r__ = 0.f; + + i__2 = l; + for (j = k; j <= i__2; ++j) { + if (j == i__) { + goto L150; + } + i__3 = j + i__ * a_dim1; + c__ += (r__1 = a[i__3].r, dabs(r__1)) + (r__2 = r_imag(&a[j + i__ + * a_dim1]), dabs(r__2)); + i__3 = i__ + j * a_dim1; + r__ += (r__1 = a[i__3].r, dabs(r__1)) + (r__2 = r_imag(&a[i__ + j + * a_dim1]), dabs(r__2)); +L150: + ; + } + ica = icamax_(&l, &a[i__ * a_dim1 + 1], &c__1); + ca = c_abs(&a[ica + i__ * a_dim1]); + i__2 = *n - k + 1; + ira = icamax_(&i__2, &a[i__ + k * a_dim1], lda); + ra = c_abs(&a[i__ + (ira + k - 1) * a_dim1]); + +/* Guard against zero C or R due to underflow. */ + + if (c__ == 0.f || r__ == 0.f) { + goto L200; + } + g = r__ / 2.f; + f = 1.f; + s = c__ + r__; +L160: +/* Computing MAX */ + r__1 = max(f,c__); +/* Computing MIN */ + r__2 = min(r__,g); + if (c__ >= g || dmax(r__1,ca) >= sfmax2 || dmin(r__2,ra) <= sfmin2) { + goto L170; + } + r__1 = c__ + f + ca + r__ + g + ra; + if (sisnan_(&r__1)) { + +/* Exit if NaN to avoid infinite loop */ + + *info = -3; + i__2 = -(*info); + xerbla_("CGEBAL", &i__2); + return 0; + } + f *= 2.f; + c__ *= 2.f; + ca *= 2.f; + r__ /= 2.f; + g /= 2.f; + ra /= 2.f; + goto L160; + +L170: + g = c__ / 2.f; +L180: +/* Computing MIN */ + r__1 = min(f,c__), r__1 = min(r__1,g); + if (g < r__ || dmax(r__,ra) >= sfmax2 || dmin(r__1,ca) <= sfmin2) { + goto L190; + } + f /= 2.f; + c__ /= 2.f; + g /= 2.f; + ca /= 2.f; + r__ *= 2.f; + ra *= 2.f; + goto L180; + +/* Now balance. */ + +L190: + if (c__ + r__ >= s * .95f) { + goto L200; + } + if (f < 1.f && scale[i__] < 1.f) { + if (f * scale[i__] <= sfmin1) { + goto L200; + } + } + if (f > 1.f && scale[i__] > 1.f) { + if (scale[i__] >= sfmax1 / f) { + goto L200; + } + } + g = 1.f / f; + scale[i__] *= f; + noconv = TRUE_; + + i__2 = *n - k + 1; + csscal_(&i__2, &g, &a[i__ + k * a_dim1], lda); + csscal_(&l, &f, &a[i__ * a_dim1 + 1], &c__1); + +L200: + ; + } + + if (noconv) { + goto L140; + } + +L210: + *ilo = k; + *ihi = l; + + return 0; + +/* End of CGEBAL */ + +} /* cgebal_ */ + +/* Subroutine */ int cgebd2_(integer *m, integer *n, complex *a, integer *lda, + real *d__, real *e, complex *tauq, complex *taup, complex *work, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer i__; + static complex alpha; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *), + clarfg_(integer *, complex *, complex *, integer *, complex *), + clacgv_(integer *, complex *, integer *), xerbla_(char *, integer + *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGEBD2 reduces a complex general m by n matrix A to upper or lower + real bidiagonal form B by a unitary transformation: Q' * A * P = B. + + If m >= n, B is upper bidiagonal; if m < n, B is lower bidiagonal. + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. M >= 0. + + N (input) INTEGER + The number of columns in the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the m by n general matrix to be reduced. + On exit, + if m >= n, the diagonal and the first superdiagonal are + overwritten with the upper bidiagonal matrix B; the + elements below the diagonal, with the array TAUQ, represent + the unitary matrix Q as a product of elementary + reflectors, and the elements above the first superdiagonal, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors; + if m < n, the diagonal and the first subdiagonal are + overwritten with the lower bidiagonal matrix B; the + elements below the first subdiagonal, with the array TAUQ, + represent the unitary matrix Q as a product of + elementary reflectors, and the elements above the diagonal, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) REAL array, dimension (min(M,N)) + The diagonal elements of the bidiagonal matrix B: + D(i) = A(i,i). + + E (output) REAL array, dimension (min(M,N)-1) + The off-diagonal elements of the bidiagonal matrix B: + if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1; + if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1. + + TAUQ (output) COMPLEX array dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the unitary matrix Q. See Further Details. + + TAUP (output) COMPLEX array, dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the unitary matrix P. See Further Details. + + WORK (workspace) COMPLEX array, dimension (max(M,N)) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + If m >= n, + + Q = H(1) H(2) . . . H(n) and P = G(1) G(2) . . . G(n-1) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, and v and u are complex + vectors; v(1:i-1) = 0, v(i) = 1, and v(i+1:m) is stored on exit in + A(i+1:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+2:n) is stored on exit in + A(i,i+2:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, + + Q = H(1) H(2) . . . H(m-1) and P = G(1) G(2) . . . G(m) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, v and u are complex vectors; + v(1:i) = 0, v(i+1) = 1, and v(i+2:m) is stored on exit in A(i+2:m,i); + u(1:i-1) = 0, u(i) = 1, and u(i+1:n) is stored on exit in A(i,i+1:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + The contents of A on exit are illustrated by the following examples: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) + ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) + ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) + ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) + ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) + ( v1 v2 v3 v4 v5 ) + + where d and e denote diagonal and off-diagonal elements of B, vi + denotes an element of the vector defining H(i), and ui an element of + the vector defining G(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info < 0) { + i__1 = -(*info); + xerbla_("CGEBD2", &i__1); + return 0; + } + + if (*m >= *n) { + +/* Reduce to upper bidiagonal form */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ + + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + clarfg_(&i__2, &alpha, &a[min(i__3,*m) + i__ * a_dim1], &c__1, & + tauq[i__]); + i__2 = i__; + d__[i__2] = alpha.r; + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Apply H(i)' to A(i:m,i+1:n) from the left */ + + if (i__ < *n) { + i__2 = *m - i__ + 1; + i__3 = *n - i__; + r_cnjg(&q__1, &tauq[i__]); + clarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, & + q__1, &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + } + i__2 = i__ + i__ * a_dim1; + i__3 = i__; + a[i__2].r = d__[i__3], a[i__2].i = 0.f; + + if (i__ < *n) { + +/* + Generate elementary reflector G(i) to annihilate + A(i,i+2:n) +*/ + + i__2 = *n - i__; + clacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ + (i__ + 1) * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + clarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, & + taup[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + (i__ + 1) * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Apply G(i) to A(i+1:m,i+1:n) from the right */ + + i__2 = *m - i__; + i__3 = *n - i__; + clarf_("Right", &i__2, &i__3, &a[i__ + (i__ + 1) * a_dim1], + lda, &taup[i__], &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &work[1]); + i__2 = *n - i__; + clacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ + (i__ + 1) * a_dim1; + i__3 = i__; + a[i__2].r = e[i__3], a[i__2].i = 0.f; + } else { + i__2 = i__; + taup[i__2].r = 0.f, taup[i__2].i = 0.f; + } +/* L10: */ + } + } else { + +/* Reduce to lower bidiagonal form */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector G(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; + clacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + clarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, & + taup[i__]); + i__2 = i__; + d__[i__2] = alpha.r; + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Apply G(i) to A(i+1:m,i:n) from the right */ + + if (i__ < *m) { + i__2 = *m - i__; + i__3 = *n - i__ + 1; + clarf_("Right", &i__2, &i__3, &a[i__ + i__ * a_dim1], lda, & + taup[i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + i__2 = *n - i__ + 1; + clacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + i__3 = i__; + a[i__2].r = d__[i__3], a[i__2].i = 0.f; + + if (i__ < *m) { + +/* + Generate elementary reflector H(i) to annihilate + A(i+2:m,i) +*/ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *m - i__; +/* Computing MIN */ + i__3 = i__ + 2; + clarfg_(&i__2, &alpha, &a[min(i__3,*m) + i__ * a_dim1], &c__1, + &tauq[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Apply H(i)' to A(i+1:m,i+1:n) from the left */ + + i__2 = *m - i__; + i__3 = *n - i__; + r_cnjg(&q__1, &tauq[i__]); + clarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], & + c__1, &q__1, &a[i__ + 1 + (i__ + 1) * a_dim1], lda, & + work[1]); + i__2 = i__ + 1 + i__ * a_dim1; + i__3 = i__; + a[i__2].r = e[i__3], a[i__2].i = 0.f; + } else { + i__2 = i__; + tauq[i__2].r = 0.f, tauq[i__2].i = 0.f; + } +/* L20: */ + } + } + return 0; + +/* End of CGEBD2 */ + +} /* cgebd2_ */ + +/* Subroutine */ int cgebrd_(integer *m, integer *n, complex *a, integer *lda, + real *d__, real *e, complex *tauq, complex *taup, complex *work, + integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + real r__1; + complex q__1; + + /* Local variables */ + static integer i__, j, nb, nx; + static real ws; + extern /* Subroutine */ int cgemm_(char *, char *, integer *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *); + static integer nbmin, iinfo, minmn; + extern /* Subroutine */ int cgebd2_(integer *, integer *, complex *, + integer *, real *, real *, complex *, complex *, complex *, + integer *), clabrd_(integer *, integer *, integer *, complex *, + integer *, real *, real *, complex *, complex *, complex *, + integer *, complex *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwrkx, ldwrky, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGEBRD reduces a general complex M-by-N matrix A to upper or lower + bidiagonal form B by a unitary transformation: Q**H * A * P = B. + + If m >= n, B is upper bidiagonal; if m < n, B is lower bidiagonal. + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. M >= 0. + + N (input) INTEGER + The number of columns in the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the M-by-N general matrix to be reduced. + On exit, + if m >= n, the diagonal and the first superdiagonal are + overwritten with the upper bidiagonal matrix B; the + elements below the diagonal, with the array TAUQ, represent + the unitary matrix Q as a product of elementary + reflectors, and the elements above the first superdiagonal, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors; + if m < n, the diagonal and the first subdiagonal are + overwritten with the lower bidiagonal matrix B; the + elements below the first subdiagonal, with the array TAUQ, + represent the unitary matrix Q as a product of + elementary reflectors, and the elements above the diagonal, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) REAL array, dimension (min(M,N)) + The diagonal elements of the bidiagonal matrix B: + D(i) = A(i,i). + + E (output) REAL array, dimension (min(M,N)-1) + The off-diagonal elements of the bidiagonal matrix B: + if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1; + if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1. + + TAUQ (output) COMPLEX array dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the unitary matrix Q. See Further Details. + + TAUP (output) COMPLEX array, dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the unitary matrix P. See Further Details. + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. LWORK >= max(1,M,N). + For optimum performance LWORK >= (M+N)*NB, where NB + is the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + If m >= n, + + Q = H(1) H(2) . . . H(n) and P = G(1) G(2) . . . G(n-1) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, and v and u are complex + vectors; v(1:i-1) = 0, v(i) = 1, and v(i+1:m) is stored on exit in + A(i+1:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+2:n) is stored on exit in + A(i,i+2:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, + + Q = H(1) H(2) . . . H(m-1) and P = G(1) G(2) . . . G(m) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, and v and u are complex + vectors; v(1:i) = 0, v(i+1) = 1, and v(i+2:m) is stored on exit in + A(i+2:m,i); u(1:i-1) = 0, u(i) = 1, and u(i+1:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + The contents of A on exit are illustrated by the following examples: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) + ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) + ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) + ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) + ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) + ( v1 v2 v3 v4 v5 ) + + where d and e denote diagonal and off-diagonal elements of B, vi + denotes an element of the vector defining H(i), and ui an element of + the vector defining G(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + --work; + + /* Function Body */ + *info = 0; +/* Computing MAX */ + i__1 = 1, i__2 = ilaenv_(&c__1, "CGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = max(i__1,i__2); + lwkopt = (*m + *n) * nb; + r__1 = (real) lwkopt; + work[1].r = r__1, work[1].i = 0.f; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = max(1,*m); + if (*lwork < max(i__1,*n) && ! lquery) { + *info = -10; + } + } + if (*info < 0) { + i__1 = -(*info); + xerbla_("CGEBRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + minmn = min(*m,*n); + if (minmn == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + ws = (real) max(*m,*n); + ldwrkx = *m; + ldwrky = *n; + + if (nb > 1 && nb < minmn) { + +/* + Set the crossover point NX. + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "CGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + +/* Determine when to switch from blocked to unblocked code. */ + + if (nx < minmn) { + ws = (real) ((*m + *n) * nb); + if ((real) (*lwork) < ws) { + +/* + Not enough work space for the optimal NB, consider using + a smaller block size. +*/ + + nbmin = ilaenv_(&c__2, "CGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + if (*lwork >= (*m + *n) * nbmin) { + nb = *lwork / (*m + *n); + } else { + nb = 1; + nx = minmn; + } + } + } + } else { + nx = minmn; + } + + i__1 = minmn - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + +/* + Reduce rows and columns i:i+ib-1 to bidiagonal form and return + the matrices X and Y which are needed to update the unreduced + part of the matrix +*/ + + i__3 = *m - i__ + 1; + i__4 = *n - i__ + 1; + clabrd_(&i__3, &i__4, &nb, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[ + i__], &tauq[i__], &taup[i__], &work[1], &ldwrkx, &work[ldwrkx + * nb + 1], &ldwrky); + +/* + Update the trailing submatrix A(i+ib:m,i+ib:n), using + an update of the form A := A - V*Y' - X*U' +*/ + + i__3 = *m - i__ - nb + 1; + i__4 = *n - i__ - nb + 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "Conjugate transpose", &i__3, &i__4, &nb, & + q__1, &a[i__ + nb + i__ * a_dim1], lda, &work[ldwrkx * nb + + nb + 1], &ldwrky, &c_b57, &a[i__ + nb + (i__ + nb) * a_dim1], + lda); + i__3 = *m - i__ - nb + 1; + i__4 = *n - i__ - nb + 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "No transpose", &i__3, &i__4, &nb, &q__1, & + work[nb + 1], &ldwrkx, &a[i__ + (i__ + nb) * a_dim1], lda, & + c_b57, &a[i__ + nb + (i__ + nb) * a_dim1], lda); + +/* Copy diagonal and off-diagonal elements of B back into A */ + + if (*m >= *n) { + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + i__4 = j + j * a_dim1; + i__5 = j; + a[i__4].r = d__[i__5], a[i__4].i = 0.f; + i__4 = j + (j + 1) * a_dim1; + i__5 = j; + a[i__4].r = e[i__5], a[i__4].i = 0.f; +/* L10: */ + } + } else { + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + i__4 = j + j * a_dim1; + i__5 = j; + a[i__4].r = d__[i__5], a[i__4].i = 0.f; + i__4 = j + 1 + j * a_dim1; + i__5 = j; + a[i__4].r = e[i__5], a[i__4].i = 0.f; +/* L20: */ + } + } +/* L30: */ + } + +/* Use unblocked code to reduce the remainder of the matrix */ + + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + cgebd2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], & + tauq[i__], &taup[i__], &work[1], &iinfo); + work[1].r = ws, work[1].i = 0.f; + return 0; + +/* End of CGEBRD */ + +} /* cgebrd_ */ + +/* Subroutine */ int cgeev_(char *jobvl, char *jobvr, integer *n, complex *a, + integer *lda, complex *w, complex *vl, integer *ldvl, complex *vr, + integer *ldvr, complex *work, integer *lwork, real *rwork, integer * + info) +{ + /* System generated locals */ + integer a_dim1, a_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, + i__2, i__3; + real r__1, r__2; + complex q__1, q__2; + + /* Local variables */ + static integer i__, k, ihi; + static real scl; + static integer ilo; + static real dum[1], eps; + static complex tmp; + static integer ibal; + static char side[1]; + static real anrm; + static integer ierr, itau, iwrk, nout; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *); + extern logical lsame_(char *, char *); + extern doublereal scnrm2_(integer *, complex *, integer *); + extern /* Subroutine */ int cgebak_(char *, char *, integer *, integer *, + integer *, real *, integer *, complex *, integer *, integer *), cgebal_(char *, integer *, complex *, integer *, + integer *, integer *, real *, integer *), slabad_(real *, + real *); + static logical scalea; + extern doublereal clange_(char *, integer *, integer *, complex *, + integer *, real *); + static real cscale; + extern /* Subroutine */ int cgehrd_(integer *, integer *, integer *, + complex *, integer *, complex *, complex *, integer *, integer *), + clascl_(char *, integer *, integer *, real *, real *, integer *, + integer *, complex *, integer *, integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int csscal_(integer *, real *, complex *, integer + *), clacpy_(char *, integer *, integer *, complex *, integer *, + complex *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical select[1]; + static real bignum; + extern integer isamax_(integer *, real *, integer *); + extern /* Subroutine */ int chseqr_(char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *, integer *), ctrevc_(char *, + char *, logical *, integer *, complex *, integer *, complex *, + integer *, complex *, integer *, integer *, integer *, complex *, + real *, integer *), cunghr_(integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + integer *); + static integer minwrk, maxwrk; + static logical wantvl; + static real smlnum; + static integer hswork, irwork; + static logical lquery, wantvr; + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGEEV computes for an N-by-N complex nonsymmetric matrix A, the + eigenvalues and, optionally, the left and/or right eigenvectors. + + The right eigenvector v(j) of A satisfies + A * v(j) = lambda(j) * v(j) + where lambda(j) is its eigenvalue. + The left eigenvector u(j) of A satisfies + u(j)**H * A = lambda(j) * u(j)**H + where u(j)**H denotes the conjugate transpose of u(j). + + The computed eigenvectors are normalized to have Euclidean norm + equal to 1 and largest component real. + + Arguments + ========= + + JOBVL (input) CHARACTER*1 + = 'N': left eigenvectors of A are not computed; + = 'V': left eigenvectors of are computed. + + JOBVR (input) CHARACTER*1 + = 'N': right eigenvectors of A are not computed; + = 'V': right eigenvectors of A are computed. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the N-by-N matrix A. + On exit, A has been overwritten. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + W (output) COMPLEX array, dimension (N) + W contains the computed eigenvalues. + + VL (output) COMPLEX array, dimension (LDVL,N) + If JOBVL = 'V', the left eigenvectors u(j) are stored one + after another in the columns of VL, in the same order + as their eigenvalues. + If JOBVL = 'N', VL is not referenced. + u(j) = VL(:,j), the j-th column of VL. + + LDVL (input) INTEGER + The leading dimension of the array VL. LDVL >= 1; if + JOBVL = 'V', LDVL >= N. + + VR (output) COMPLEX array, dimension (LDVR,N) + If JOBVR = 'V', the right eigenvectors v(j) are stored one + after another in the columns of VR, in the same order + as their eigenvalues. + If JOBVR = 'N', VR is not referenced. + v(j) = VR(:,j), the j-th column of VR. + + LDVR (input) INTEGER + The leading dimension of the array VR. LDVR >= 1; if + JOBVR = 'V', LDVR >= N. + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,2*N). + For good performance, LWORK must generally be larger. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + RWORK (workspace) REAL array, dimension (2*N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = i, the QR algorithm failed to compute all the + eigenvalues, and no eigenvectors have been computed; + elements and i+1:N of W contain eigenvalues which have + converged. + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --w; + vl_dim1 = *ldvl; + vl_offset = 1 + vl_dim1; + vl -= vl_offset; + vr_dim1 = *ldvr; + vr_offset = 1 + vr_dim1; + vr -= vr_offset; + --work; + --rwork; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1; + wantvl = lsame_(jobvl, "V"); + wantvr = lsame_(jobvr, "V"); + if (! wantvl && ! lsame_(jobvl, "N")) { + *info = -1; + } else if (! wantvr && ! lsame_(jobvr, "N")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldvl < 1 || wantvl && *ldvl < *n) { + *info = -8; + } else if (*ldvr < 1 || wantvr && *ldvr < *n) { + *info = -10; + } + +/* + Compute workspace + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + CWorkspace refers to complex workspace, and RWorkspace to real + workspace. NB refers to the optimal block size for the + immediately following subroutine, as returned by ILAENV. + HSWORK refers to the workspace preferred by CHSEQR, as + calculated below. HSWORK is computed assuming ILO=1 and IHI=N, + the worst case.) +*/ + + if (*info == 0) { + if (*n == 0) { + minwrk = 1; + maxwrk = 1; + } else { + maxwrk = *n + *n * ilaenv_(&c__1, "CGEHRD", " ", n, &c__1, n, & + c__0, (ftnlen)6, (ftnlen)1); + minwrk = *n << 1; + if (wantvl) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + (*n - 1) * ilaenv_(&c__1, "CUNGHR", + " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); + chseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &w[1], &vl[ + vl_offset], ldvl, &work[1], &c_n1, info); + } else if (wantvr) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + (*n - 1) * ilaenv_(&c__1, "CUNGHR", + " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); + chseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &w[1], &vr[ + vr_offset], ldvr, &work[1], &c_n1, info); + } else { + chseqr_("E", "N", n, &c__1, n, &a[a_offset], lda, &w[1], &vr[ + vr_offset], ldvr, &work[1], &c_n1, info); + } + hswork = work[1].r; +/* Computing MAX */ + i__1 = max(maxwrk,hswork); + maxwrk = max(i__1,minwrk); + } + work[1].r = (real) maxwrk, work[1].i = 0.f; + + if (*lwork < minwrk && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGEEV ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Get machine constants */ + + eps = slamch_("P"); + smlnum = slamch_("S"); + bignum = 1.f / smlnum; + slabad_(&smlnum, &bignum); + smlnum = sqrt(smlnum) / eps; + bignum = 1.f / smlnum; + +/* Scale A if max element outside range [SMLNUM,BIGNUM] */ + + anrm = clange_("M", n, n, &a[a_offset], lda, dum); + scalea = FALSE_; + if (anrm > 0.f && anrm < smlnum) { + scalea = TRUE_; + cscale = smlnum; + } else if (anrm > bignum) { + scalea = TRUE_; + cscale = bignum; + } + if (scalea) { + clascl_("G", &c__0, &c__0, &anrm, &cscale, n, n, &a[a_offset], lda, & + ierr); + } + +/* + Balance the matrix + (CWorkspace: none) + (RWorkspace: need N) +*/ + + ibal = 1; + cgebal_("B", n, &a[a_offset], lda, &ilo, &ihi, &rwork[ibal], &ierr); + +/* + Reduce to upper Hessenberg form + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: none) +*/ + + itau = 1; + iwrk = itau + *n; + i__1 = *lwork - iwrk + 1; + cgehrd_(n, &ilo, &ihi, &a[a_offset], lda, &work[itau], &work[iwrk], &i__1, + &ierr); + + if (wantvl) { + +/* + Want left eigenvectors + Copy Householder vectors to VL +*/ + + *(unsigned char *)side = 'L'; + clacpy_("L", n, n, &a[a_offset], lda, &vl[vl_offset], ldvl) + ; + +/* + Generate unitary matrix in VL + (CWorkspace: need 2*N-1, prefer N+(N-1)*NB) + (RWorkspace: none) +*/ + + i__1 = *lwork - iwrk + 1; + cunghr_(n, &ilo, &ihi, &vl[vl_offset], ldvl, &work[itau], &work[iwrk], + &i__1, &ierr); + +/* + Perform QR iteration, accumulating Schur vectors in VL + (CWorkspace: need 1, prefer HSWORK (see comments) ) + (RWorkspace: none) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + chseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &w[1], &vl[ + vl_offset], ldvl, &work[iwrk], &i__1, info); + + if (wantvr) { + +/* + Want left and right eigenvectors + Copy Schur vectors to VR +*/ + + *(unsigned char *)side = 'B'; + clacpy_("F", n, n, &vl[vl_offset], ldvl, &vr[vr_offset], ldvr); + } + + } else if (wantvr) { + +/* + Want right eigenvectors + Copy Householder vectors to VR +*/ + + *(unsigned char *)side = 'R'; + clacpy_("L", n, n, &a[a_offset], lda, &vr[vr_offset], ldvr) + ; + +/* + Generate unitary matrix in VR + (CWorkspace: need 2*N-1, prefer N+(N-1)*NB) + (RWorkspace: none) +*/ + + i__1 = *lwork - iwrk + 1; + cunghr_(n, &ilo, &ihi, &vr[vr_offset], ldvr, &work[itau], &work[iwrk], + &i__1, &ierr); + +/* + Perform QR iteration, accumulating Schur vectors in VR + (CWorkspace: need 1, prefer HSWORK (see comments) ) + (RWorkspace: none) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + chseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &w[1], &vr[ + vr_offset], ldvr, &work[iwrk], &i__1, info); + + } else { + +/* + Compute eigenvalues only + (CWorkspace: need 1, prefer HSWORK (see comments) ) + (RWorkspace: none) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + chseqr_("E", "N", n, &ilo, &ihi, &a[a_offset], lda, &w[1], &vr[ + vr_offset], ldvr, &work[iwrk], &i__1, info); + } + +/* If INFO > 0 from CHSEQR, then quit */ + + if (*info > 0) { + goto L50; + } + + if (wantvl || wantvr) { + +/* + Compute left and/or right eigenvectors + (CWorkspace: need 2*N) + (RWorkspace: need 2*N) +*/ + + irwork = ibal + *n; + ctrevc_(side, "B", select, n, &a[a_offset], lda, &vl[vl_offset], ldvl, + &vr[vr_offset], ldvr, n, &nout, &work[iwrk], &rwork[irwork], + &ierr); + } + + if (wantvl) { + +/* + Undo balancing of left eigenvectors + (CWorkspace: none) + (RWorkspace: need N) +*/ + + cgebak_("B", "L", n, &ilo, &ihi, &rwork[ibal], n, &vl[vl_offset], + ldvl, &ierr); + +/* Normalize left eigenvectors and make largest component real */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + scl = 1.f / scnrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1); + csscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1); + i__2 = *n; + for (k = 1; k <= i__2; ++k) { + i__3 = k + i__ * vl_dim1; +/* Computing 2nd power */ + r__1 = vl[i__3].r; +/* Computing 2nd power */ + r__2 = r_imag(&vl[k + i__ * vl_dim1]); + rwork[irwork + k - 1] = r__1 * r__1 + r__2 * r__2; +/* L10: */ + } + k = isamax_(n, &rwork[irwork], &c__1); + r_cnjg(&q__2, &vl[k + i__ * vl_dim1]); + r__1 = sqrt(rwork[irwork + k - 1]); + q__1.r = q__2.r / r__1, q__1.i = q__2.i / r__1; + tmp.r = q__1.r, tmp.i = q__1.i; + cscal_(n, &tmp, &vl[i__ * vl_dim1 + 1], &c__1); + i__2 = k + i__ * vl_dim1; + i__3 = k + i__ * vl_dim1; + r__1 = vl[i__3].r; + q__1.r = r__1, q__1.i = 0.f; + vl[i__2].r = q__1.r, vl[i__2].i = q__1.i; +/* L20: */ + } + } + + if (wantvr) { + +/* + Undo balancing of right eigenvectors + (CWorkspace: none) + (RWorkspace: need N) +*/ + + cgebak_("B", "R", n, &ilo, &ihi, &rwork[ibal], n, &vr[vr_offset], + ldvr, &ierr); + +/* Normalize right eigenvectors and make largest component real */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + scl = 1.f / scnrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1); + csscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1); + i__2 = *n; + for (k = 1; k <= i__2; ++k) { + i__3 = k + i__ * vr_dim1; +/* Computing 2nd power */ + r__1 = vr[i__3].r; +/* Computing 2nd power */ + r__2 = r_imag(&vr[k + i__ * vr_dim1]); + rwork[irwork + k - 1] = r__1 * r__1 + r__2 * r__2; +/* L30: */ + } + k = isamax_(n, &rwork[irwork], &c__1); + r_cnjg(&q__2, &vr[k + i__ * vr_dim1]); + r__1 = sqrt(rwork[irwork + k - 1]); + q__1.r = q__2.r / r__1, q__1.i = q__2.i / r__1; + tmp.r = q__1.r, tmp.i = q__1.i; + cscal_(n, &tmp, &vr[i__ * vr_dim1 + 1], &c__1); + i__2 = k + i__ * vr_dim1; + i__3 = k + i__ * vr_dim1; + r__1 = vr[i__3].r; + q__1.r = r__1, q__1.i = 0.f; + vr[i__2].r = q__1.r, vr[i__2].i = q__1.i; +/* L40: */ + } + } + +/* Undo scaling if necessary */ + +L50: + if (scalea) { + i__1 = *n - *info; +/* Computing MAX */ + i__3 = *n - *info; + i__2 = max(i__3,1); + clascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &w[*info + 1] + , &i__2, &ierr); + if (*info > 0) { + i__1 = ilo - 1; + clascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &w[1], n, + &ierr); + } + } + + work[1].r = (real) maxwrk, work[1].i = 0.f; + return 0; + +/* End of CGEEV */ + +} /* cgeev_ */ + +/* Subroutine */ int cgehd2_(integer *n, integer *ilo, integer *ihi, complex * + a, integer *lda, complex *tau, complex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer i__; + static complex alpha; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *), + clarfg_(integer *, complex *, complex *, integer *, complex *), + xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGEHD2 reduces a complex general matrix A to upper Hessenberg form H + by a unitary similarity transformation: Q' * A * Q = H . + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that A is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to CGEBAL; otherwise they should be + set to 1 and N respectively. See Further Details. + 1 <= ILO <= IHI <= max(1,N). + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the n by n general matrix to be reduced. + On exit, the upper triangle and the first subdiagonal of A + are overwritten with the upper Hessenberg matrix H, and the + elements below the first subdiagonal, with the array TAU, + represent the unitary matrix Q as a product of elementary + reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) COMPLEX array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) COMPLEX array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrix Q is represented as a product of (ihi-ilo) elementary + reflectors + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on + exit in A(i+2:ihi,i), and tau in TAU(i). + + The contents of A are illustrated by the following example, with + n = 7, ilo = 2 and ihi = 6: + + on entry, on exit, + + ( a a a a a a a ) ( a a h h h h a ) + ( a a a a a a ) ( a h h h h a ) + ( a a a a a a ) ( h h h h h h ) + ( a a a a a a ) ( v2 h h h h h ) + ( a a a a a a ) ( v2 v3 h h h h ) + ( a a a a a a ) ( v2 v3 v4 h h h ) + ( a ) ( a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGEHD2", &i__1); + return 0; + } + + i__1 = *ihi - 1; + for (i__ = *ilo; i__ <= i__1; ++i__) { + +/* Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) */ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *ihi - i__; +/* Computing MIN */ + i__3 = i__ + 2; + clarfg_(&i__2, &alpha, &a[min(i__3,*n) + i__ * a_dim1], &c__1, &tau[ + i__]); + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Apply H(i) to A(1:ihi,i+1:ihi) from the right */ + + i__2 = *ihi - i__; + clarf_("Right", ihi, &i__2, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &a[(i__ + 1) * a_dim1 + 1], lda, &work[1]); + +/* Apply H(i)' to A(i+1:ihi,i+1:n) from the left */ + + i__2 = *ihi - i__; + i__3 = *n - i__; + r_cnjg(&q__1, &tau[i__]); + clarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], &c__1, &q__1, + &a[i__ + 1 + (i__ + 1) * a_dim1], lda, &work[1]); + + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = alpha.r, a[i__2].i = alpha.i; +/* L10: */ + } + + return 0; + +/* End of CGEHD2 */ + +} /* cgehd2_ */ + +/* Subroutine */ int cgehrd_(integer *n, integer *ilo, integer *ihi, complex * + a, integer *lda, complex *tau, complex *work, integer *lwork, integer + *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + complex q__1; + + /* Local variables */ + static integer i__, j; + static complex t[4160] /* was [65][64] */; + static integer ib; + static complex ei; + static integer nb, nh, nx, iws; + extern /* Subroutine */ int cgemm_(char *, char *, integer *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *); + static integer nbmin, iinfo; + extern /* Subroutine */ int ctrmm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *), caxpy_(integer *, + complex *, complex *, integer *, complex *, integer *), cgehd2_( + integer *, integer *, integer *, complex *, integer *, complex *, + complex *, integer *), clahr2_(integer *, integer *, integer *, + complex *, integer *, complex *, complex *, integer *, complex *, + integer *), clarfb_(char *, char *, char *, char *, integer *, + integer *, integer *, complex *, integer *, complex *, integer *, + complex *, integer *, complex *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + -- April 2009 -- + + + Purpose + ======= + + CGEHRD reduces a complex general matrix A to upper Hessenberg form H by + an unitary similarity transformation: Q' * A * Q = H . + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that A is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to CGEBAL; otherwise they should be + set to 1 and N respectively. See Further Details. + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the N-by-N general matrix to be reduced. + On exit, the upper triangle and the first subdiagonal of A + are overwritten with the upper Hessenberg matrix H, and the + elements below the first subdiagonal, with the array TAU, + represent the unitary matrix Q as a product of elementary + reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) COMPLEX array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). Elements 1:ILO-1 and IHI:N-1 of TAU are set to + zero. + + WORK (workspace/output) COMPLEX array, dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrix Q is represented as a product of (ihi-ilo) elementary + reflectors + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on + exit in A(i+2:ihi,i), and tau in TAU(i). + + The contents of A are illustrated by the following example, with + n = 7, ilo = 2 and ihi = 6: + + on entry, on exit, + + ( a a a a a a a ) ( a a h h h h a ) + ( a a a a a a ) ( a h h h h a ) + ( a a a a a a ) ( h h h h h h ) + ( a a a a a a ) ( v2 h h h h h ) + ( a a a a a a ) ( v2 v3 h h h h ) + ( a a a a a a ) ( v2 v3 v4 h h h ) + ( a ) ( a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + This file is a slight modification of LAPACK-3.0's DGEHRD + subroutine incorporating improvements proposed by Quintana-Orti and + Van de Geijn (2006). (See DLAHR2.) + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; +/* Computing MIN */ + i__1 = 64, i__2 = ilaenv_(&c__1, "CGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = min(i__1,i__2); + lwkopt = *n * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + lquery = *lwork == -1; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGEHRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Set elements 1:ILO-1 and IHI:N-1 of TAU to zero */ + + i__1 = *ilo - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + tau[i__2].r = 0.f, tau[i__2].i = 0.f; +/* L10: */ + } + i__1 = *n - 1; + for (i__ = max(1,*ihi); i__ <= i__1; ++i__) { + i__2 = i__; + tau[i__2].r = 0.f, tau[i__2].i = 0.f; +/* L20: */ + } + +/* Quick return if possible */ + + nh = *ihi - *ilo + 1; + if (nh <= 1) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + +/* + Determine the block size + + Computing MIN +*/ + i__1 = 64, i__2 = ilaenv_(&c__1, "CGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = min(i__1,i__2); + nbmin = 2; + iws = 1; + if (nb > 1 && nb < nh) { + +/* + Determine when to cross over from blocked to unblocked code + (last block is always handled by unblocked code) + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "CGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < nh) { + +/* Determine if workspace is large enough for blocked code */ + + iws = *n * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: determine the + minimum value of NB, and reduce NB or force use of + unblocked code + + Computing MAX +*/ + i__1 = 2, i__2 = ilaenv_(&c__2, "CGEHRD", " ", n, ilo, ihi, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + if (*lwork >= *n * nbmin) { + nb = *lwork / *n; + } else { + nb = 1; + } + } + } + } + ldwork = *n; + + if (nb < nbmin || nb >= nh) { + +/* Use unblocked code below */ + + i__ = *ilo; + + } else { + +/* Use blocked code */ + + i__1 = *ihi - 1 - nx; + i__2 = nb; + for (i__ = *ilo; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = nb, i__4 = *ihi - i__; + ib = min(i__3,i__4); + +/* + Reduce columns i:i+ib-1 to Hessenberg form, returning the + matrices V and T of the block reflector H = I - V*T*V' + which performs the reduction, and also the matrix Y = A*V*T +*/ + + clahr2_(ihi, &i__, &ib, &a[i__ * a_dim1 + 1], lda, &tau[i__], t, & + c__65, &work[1], &ldwork); + +/* + Apply the block reflector H to A(1:ihi,i+ib:ihi) from the + right, computing A := A - Y * V'. V(i+ib,ib-1) must be set + to 1 +*/ + + i__3 = i__ + ib + (i__ + ib - 1) * a_dim1; + ei.r = a[i__3].r, ei.i = a[i__3].i; + i__3 = i__ + ib + (i__ + ib - 1) * a_dim1; + a[i__3].r = 1.f, a[i__3].i = 0.f; + i__3 = *ihi - i__ - ib + 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "Conjugate transpose", ihi, &i__3, &ib, & + q__1, &work[1], &ldwork, &a[i__ + ib + i__ * a_dim1], lda, + &c_b57, &a[(i__ + ib) * a_dim1 + 1], lda); + i__3 = i__ + ib + (i__ + ib - 1) * a_dim1; + a[i__3].r = ei.r, a[i__3].i = ei.i; + +/* + Apply the block reflector H to A(1:i,i+1:i+ib-1) from the + right +*/ + + i__3 = ib - 1; + ctrmm_("Right", "Lower", "Conjugate transpose", "Unit", &i__, & + i__3, &c_b57, &a[i__ + 1 + i__ * a_dim1], lda, &work[1], & + ldwork); + i__3 = ib - 2; + for (j = 0; j <= i__3; ++j) { + q__1.r = -1.f, q__1.i = -0.f; + caxpy_(&i__, &q__1, &work[ldwork * j + 1], &c__1, &a[(i__ + j + + 1) * a_dim1 + 1], &c__1); +/* L30: */ + } + +/* + Apply the block reflector H to A(i+1:ihi,i+ib:n) from the + left +*/ + + i__3 = *ihi - i__; + i__4 = *n - i__ - ib + 1; + clarfb_("Left", "Conjugate transpose", "Forward", "Columnwise", & + i__3, &i__4, &ib, &a[i__ + 1 + i__ * a_dim1], lda, t, & + c__65, &a[i__ + 1 + (i__ + ib) * a_dim1], lda, &work[1], & + ldwork); +/* L40: */ + } + } + +/* Use unblocked code to reduce the rest of the matrix */ + + cgehd2_(n, &i__, ihi, &a[a_offset], lda, &tau[1], &work[1], &iinfo); + work[1].r = (real) iws, work[1].i = 0.f; + + return 0; + +/* End of CGEHRD */ + +} /* cgehrd_ */ + +/* Subroutine */ int cgelq2_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, k; + static complex alpha; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *), + clarfg_(integer *, complex *, complex *, integer *, complex *), + clacgv_(integer *, complex *, integer *), xerbla_(char *, integer + *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + CGELQ2 computes an LQ factorization of a complex m by n matrix A: + A = L * Q. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, the elements on and below the diagonal of the array + contain the m by min(m,n) lower trapezoidal matrix L (L is + lower triangular if m <= n); the elements above the diagonal, + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) COMPLEX array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) COMPLEX array, dimension (M) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(k)' . . . H(2)' H(1)', where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i-1) = 0 and v(i) = 1; conjg(v(i+1:n)) is stored on exit in + A(i,i+1:n), and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGELQ2", &i__1); + return 0; + } + + k = min(*m,*n); + + i__1 = k; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; + clacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + clarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, &tau[i__] + ); + if (i__ < *m) { + +/* Apply H(i) to A(i+1:m,i:n) from the right */ + + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + i__2 = *m - i__; + i__3 = *n - i__ + 1; + clarf_("Right", &i__2, &i__3, &a[i__ + i__ * a_dim1], lda, &tau[ + i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + i__2 = i__ + i__ * a_dim1; + a[i__2].r = alpha.r, a[i__2].i = alpha.i; + i__2 = *n - i__ + 1; + clacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); +/* L10: */ + } + return 0; + +/* End of CGELQ2 */ + +} /* cgelq2_ */ + +/* Subroutine */ int cgelqf_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, k, ib, nb, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int cgelq2_(integer *, integer *, complex *, + integer *, complex *, complex *, integer *), clarfb_(char *, char + *, char *, char *, integer *, integer *, integer *, complex *, + integer *, complex *, integer *, complex *, integer *, complex *, + integer *), clarft_(char *, char * + , integer *, integer *, complex *, integer *, complex *, complex * + , integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGELQF computes an LQ factorization of a complex M-by-N matrix A: + A = L * Q. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, the elements on and below the diagonal of the array + contain the m-by-min(m,n) lower trapezoidal matrix L (L is + lower triangular if m <= n); the elements above the diagonal, + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) COMPLEX array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,M). + For optimum performance LWORK >= M*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(k)' . . . H(2)' H(1)', where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i-1) = 0 and v(i) = 1; conjg(v(i+1:n)) is stored on exit in + A(i,i+1:n), and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "CGELQF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + lwkopt = *m * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else if (*lwork < max(1,*m) && ! lquery) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGELQF", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + k = min(*m,*n); + if (k == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *m; + if (nb > 1 && nb < k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "CGELQF", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *m; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "CGELQF", " ", m, n, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < k && nx < k) { + +/* Use blocked code initially */ + + i__1 = k - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = k - i__ + 1; + ib = min(i__3,nb); + +/* + Compute the LQ factorization of the current block + A(i:i+ib-1,i:n) +*/ + + i__3 = *n - i__ + 1; + cgelq2_(&ib, &i__3, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[ + 1], &iinfo); + if (i__ + ib <= *m) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__3 = *n - i__ + 1; + clarft_("Forward", "Rowwise", &i__3, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H to A(i+ib:m,i:n) from the right */ + + i__3 = *m - i__ - ib + 1; + i__4 = *n - i__ + 1; + clarfb_("Right", "No transpose", "Forward", "Rowwise", &i__3, + &i__4, &ib, &a[i__ + i__ * a_dim1], lda, &work[1], & + ldwork, &a[i__ + ib + i__ * a_dim1], lda, &work[ib + + 1], &ldwork); + } +/* L10: */ + } + } else { + i__ = 1; + } + +/* Use unblocked code to factor the last or only block. */ + + if (i__ <= k) { + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + cgelq2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[1] + , &iinfo); + } + + work[1].r = (real) iws, work[1].i = 0.f; + return 0; + +/* End of CGELQF */ + +} /* cgelqf_ */ + +/* Subroutine */ int cgeqr2_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer i__, k; + static complex alpha; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *), + clarfg_(integer *, complex *, complex *, integer *, complex *), + xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + CGEQR2 computes a QR factorization of a complex m by n matrix A: + A = Q * R. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, the elements on and above the diagonal of the array + contain the min(m,n) by n upper trapezoidal matrix R (R is + upper triangular if m >= n); the elements below the diagonal, + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) COMPLEX array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) COMPLEX array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(1) H(2) . . . H(k), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGEQR2", &i__1); + return 0; + } + + k = min(*m,*n); + + i__1 = k; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ + + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + clarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * a_dim1] + , &c__1, &tau[i__]); + if (i__ < *n) { + +/* Apply H(i)' to A(i:m,i+1:n) from the left */ + + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + i__2 = *m - i__ + 1; + i__3 = *n - i__; + r_cnjg(&q__1, &tau[i__]); + clarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, &q__1, + &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + i__2 = i__ + i__ * a_dim1; + a[i__2].r = alpha.r, a[i__2].i = alpha.i; + } +/* L10: */ + } + return 0; + +/* End of CGEQR2 */ + +} /* cgeqr2_ */ + +/* Subroutine */ int cgeqrf_(integer *m, integer *n, complex *a, integer *lda, + complex *tau, complex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, k, ib, nb, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int cgeqr2_(integer *, integer *, complex *, + integer *, complex *, complex *, integer *), clarfb_(char *, char + *, char *, char *, integer *, integer *, integer *, complex *, + integer *, complex *, integer *, complex *, integer *, complex *, + integer *), clarft_(char *, char * + , integer *, integer *, complex *, integer *, complex *, complex * + , integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGEQRF computes a QR factorization of a complex M-by-N matrix A: + A = Q * R. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, the elements on and above the diagonal of the array + contain the min(M,N)-by-N upper trapezoidal matrix R (R is + upper triangular if m >= n); the elements below the diagonal, + with the array TAU, represent the unitary matrix Q as a + product of min(m,n) elementary reflectors (see Further + Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) COMPLEX array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(1) H(2) . . . H(k), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "CGEQRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + lwkopt = *n * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGEQRF", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + k = min(*m,*n); + if (k == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *n; + if (nb > 1 && nb < k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "CGEQRF", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "CGEQRF", " ", m, n, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < k && nx < k) { + +/* Use blocked code initially */ + + i__1 = k - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = k - i__ + 1; + ib = min(i__3,nb); + +/* + Compute the QR factorization of the current block + A(i:m,i:i+ib-1) +*/ + + i__3 = *m - i__ + 1; + cgeqr2_(&i__3, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[ + 1], &iinfo); + if (i__ + ib <= *n) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__3 = *m - i__ + 1; + clarft_("Forward", "Columnwise", &i__3, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H' to A(i:m,i+ib:n) from the left */ + + i__3 = *m - i__ + 1; + i__4 = *n - i__ - ib + 1; + clarfb_("Left", "Conjugate transpose", "Forward", "Columnwise" + , &i__3, &i__4, &ib, &a[i__ + i__ * a_dim1], lda, & + work[1], &ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, + &work[ib + 1], &ldwork); + } +/* L10: */ + } + } else { + i__ = 1; + } + +/* Use unblocked code to factor the last or only block. */ + + if (i__ <= k) { + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + cgeqr2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[1] + , &iinfo); + } + + work[1].r = (real) iws, work[1].i = 0.f; + return 0; + +/* End of CGEQRF */ + +} /* cgeqrf_ */ + +/* Subroutine */ int cgesdd_(char *jobz, integer *m, integer *n, complex *a, + integer *lda, real *s, complex *u, integer *ldu, complex *vt, integer + *ldvt, complex *work, integer *lwork, real *rwork, integer *iwork, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, u_dim1, u_offset, vt_dim1, vt_offset, i__1, + i__2, i__3; + + /* Local variables */ + static integer i__, ie, il, ir, iu, blk; + static real dum[1], eps; + static integer iru, ivt, iscl; + static real anrm; + static integer idum[1], ierr, itau, irvt; + extern /* Subroutine */ int cgemm_(char *, char *, integer *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *); + extern logical lsame_(char *, char *); + static integer chunk, minmn, wrkbl, itaup, itauq; + static logical wntqa; + static integer nwork; + extern /* Subroutine */ int clacp2_(char *, integer *, integer *, real *, + integer *, complex *, integer *); + static logical wntqn, wntqo, wntqs; + static integer mnthr1, mnthr2; + extern /* Subroutine */ int cgebrd_(integer *, integer *, complex *, + integer *, real *, real *, complex *, complex *, complex *, + integer *, integer *); + extern doublereal clange_(char *, integer *, integer *, complex *, + integer *, real *); + extern /* Subroutine */ int cgelqf_(integer *, integer *, complex *, + integer *, complex *, complex *, integer *, integer *), clacrm_( + integer *, integer *, complex *, integer *, real *, integer *, + complex *, integer *, real *), clarcm_(integer *, integer *, real + *, integer *, complex *, integer *, complex *, integer *, real *), + clascl_(char *, integer *, integer *, real *, real *, integer *, + integer *, complex *, integer *, integer *), sbdsdc_(char + *, char *, integer *, real *, real *, real *, integer *, real *, + integer *, real *, integer *, real *, integer *, integer *), cgeqrf_(integer *, integer *, complex *, integer + *, complex *, complex *, integer *, integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int clacpy_(char *, integer *, integer *, complex + *, integer *, complex *, integer *), claset_(char *, + integer *, integer *, complex *, complex *, complex *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int cungbr_(char *, integer *, integer *, integer + *, complex *, integer *, complex *, complex *, integer *, integer + *); + static real bignum; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *), cunmbr_(char *, char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *, integer *), cunglq_( + integer *, integer *, integer *, complex *, integer *, complex *, + complex *, integer *, integer *); + static integer ldwrkl; + extern /* Subroutine */ int cungqr_(integer *, integer *, integer *, + complex *, integer *, complex *, complex *, integer *, integer *); + static integer ldwrkr, minwrk, ldwrku, maxwrk, ldwkvt; + static real smlnum; + static logical wntqas; + static integer nrwork; + + +/* + -- LAPACK driver routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + 8-15-00: Improve consistency of WS calculations (eca) + + + Purpose + ======= + + CGESDD computes the singular value decomposition (SVD) of a complex + M-by-N matrix A, optionally computing the left and/or right singular + vectors, by using divide-and-conquer method. The SVD is written + + A = U * SIGMA * conjugate-transpose(V) + + where SIGMA is an M-by-N matrix which is zero except for its + min(m,n) diagonal elements, U is an M-by-M unitary matrix, and + V is an N-by-N unitary matrix. The diagonal elements of SIGMA + are the singular values of A; they are real and non-negative, and + are returned in descending order. The first min(m,n) columns of + U and V are the left and right singular vectors of A. + + Note that the routine returns VT = V**H, not V. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + JOBZ (input) CHARACTER*1 + Specifies options for computing all or part of the matrix U: + = 'A': all M columns of U and all N rows of V**H are + returned in the arrays U and VT; + = 'S': the first min(M,N) columns of U and the first + min(M,N) rows of V**H are returned in the arrays U + and VT; + = 'O': If M >= N, the first N columns of U are overwritten + in the array A and all rows of V**H are returned in + the array VT; + otherwise, all columns of U are returned in the + array U and the first M rows of V**H are overwritten + in the array A; + = 'N': no columns of U or rows of V**H are computed. + + M (input) INTEGER + The number of rows of the input matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the input matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, + if JOBZ = 'O', A is overwritten with the first N columns + of U (the left singular vectors, stored + columnwise) if M >= N; + A is overwritten with the first M rows + of V**H (the right singular vectors, stored + rowwise) otherwise. + if JOBZ .ne. 'O', the contents of A are destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + S (output) REAL array, dimension (min(M,N)) + The singular values of A, sorted so that S(i) >= S(i+1). + + U (output) COMPLEX array, dimension (LDU,UCOL) + UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N; + UCOL = min(M,N) if JOBZ = 'S'. + If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M + unitary matrix U; + if JOBZ = 'S', U contains the first min(M,N) columns of U + (the left singular vectors, stored columnwise); + if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= 1; if + JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M. + + VT (output) COMPLEX array, dimension (LDVT,N) + If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the + N-by-N unitary matrix V**H; + if JOBZ = 'S', VT contains the first min(M,N) rows of + V**H (the right singular vectors, stored rowwise); + if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= 1; if + JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N; + if JOBZ = 'S', LDVT >= min(M,N). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= 1. + if JOBZ = 'N', LWORK >= 2*min(M,N)+max(M,N). + if JOBZ = 'O', + LWORK >= 2*min(M,N)*min(M,N)+2*min(M,N)+max(M,N). + if JOBZ = 'S' or 'A', + LWORK >= min(M,N)*min(M,N)+2*min(M,N)+max(M,N). + For good performance, LWORK should generally be larger. + + If LWORK = -1, a workspace query is assumed. The optimal + size for the WORK array is calculated and stored in WORK(1), + and no other work except argument checking is performed. + + RWORK (workspace) REAL array, dimension (MAX(1,LRWORK)) + If JOBZ = 'N', LRWORK >= 5*min(M,N). + Otherwise, + LRWORK >= min(M,N)*max(5*min(M,N)+7,2*max(M,N)+2*min(M,N)+1) + + IWORK (workspace) INTEGER array, dimension (8*min(M,N)) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The updating process of SBDSDC did not converge. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --s; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + minmn = min(*m,*n); + mnthr1 = (integer) (minmn * 17.f / 9.f); + mnthr2 = (integer) (minmn * 5.f / 3.f); + wntqa = lsame_(jobz, "A"); + wntqs = lsame_(jobz, "S"); + wntqas = wntqa || wntqs; + wntqo = lsame_(jobz, "O"); + wntqn = lsame_(jobz, "N"); + minwrk = 1; + maxwrk = 1; + + if (! (wntqa || wntqs || wntqo || wntqn)) { + *info = -1; + } else if (*m < 0) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*ldu < 1 || wntqas && *ldu < *m || wntqo && *m < *n && *ldu < * + m) { + *info = -8; + } else if (*ldvt < 1 || wntqa && *ldvt < *n || wntqs && *ldvt < minmn || + wntqo && *m >= *n && *ldvt < *n) { + *info = -10; + } + +/* + Compute workspace + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + CWorkspace refers to complex workspace, and RWorkspace to + real workspace. NB refers to the optimal block size for the + immediately following subroutine, as returned by ILAENV.) +*/ + + if (*info == 0 && *m > 0 && *n > 0) { + if (*m >= *n) { + +/* + There is no complex work space needed for bidiagonal SVD + The real work space needed for bidiagonal SVD is BDSPAC + for computing singular values and singular vectors; BDSPAN + for computing singular values only. + BDSPAC = 5*N*N + 7*N + BDSPAN = MAX(7*N+4, 3*N+2+SMLSIZ*(SMLSIZ+8)) +*/ + + if (*m >= mnthr1) { + if (wntqn) { + +/* Path 1 (M much larger than N, JOBZ='N') */ + + maxwrk = *n + *n * ilaenv_(&c__1, "CGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + (*n << 1) * ilaenv_(& + c__1, "CGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + maxwrk = max(i__1,i__2); + minwrk = *n * 3; + } else if (wntqo) { + +/* Path 2 (M much larger than N, JOBZ='O') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "CGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *n * ilaenv_(&c__1, "CUNGQR", + " ", m, n, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + (*n << 1) * ilaenv_(& + c__1, "CGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "QLN", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *m * *n + *n * *n + wrkbl; + minwrk = (*n << 1) * *n + *n * 3; + } else if (wntqs) { + +/* Path 3 (M much larger than N, JOBZ='S') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "CGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *n * ilaenv_(&c__1, "CUNGQR", + " ", m, n, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + (*n << 1) * ilaenv_(& + c__1, "CGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "QLN", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *n * *n + wrkbl; + minwrk = *n * *n + *n * 3; + } else if (wntqa) { + +/* Path 4 (M much larger than N, JOBZ='A') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "CGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *m * ilaenv_(&c__1, "CUNGQR", + " ", m, m, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + (*n << 1) * ilaenv_(& + c__1, "CGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "QLN", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *n * *n + wrkbl; + minwrk = *n * *n + (*n << 1) + *m; + } + } else if (*m >= mnthr2) { + +/* Path 5 (M much larger than N, but not as much as MNTHR1) */ + + maxwrk = (*n << 1) + (*m + *n) * ilaenv_(&c__1, "CGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + minwrk = (*n << 1) + *m; + if (wntqo) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNGBR", "P", n, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNGBR", "Q", m, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + maxwrk += *m * *n; + minwrk += *n * *n; + } else if (wntqs) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNGBR", "P", n, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNGBR", "Q", m, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + } else if (wntqa) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNGBR", "P", n, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "Q", m, m, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + } + } else { + +/* Path 6 (M at least N, but not much larger) */ + + maxwrk = (*n << 1) + (*m + *n) * ilaenv_(&c__1, "CGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + minwrk = (*n << 1) + *m; + if (wntqo) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "QLN", m, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + maxwrk += *m * *n; + minwrk += *n * *n; + } else if (wntqs) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNMBR", "QLN", m, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + } else if (wntqa) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "CUNGBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "QLN", m, m, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + } + } + } else { + +/* + There is no complex work space needed for bidiagonal SVD + The real work space needed for bidiagonal SVD is BDSPAC + for computing singular values and singular vectors; BDSPAN + for computing singular values only. + BDSPAC = 5*M*M + 7*M + BDSPAN = MAX(7*M+4, 3*M+2+SMLSIZ*(SMLSIZ+8)) +*/ + + if (*n >= mnthr1) { + if (wntqn) { + +/* Path 1t (N much larger than M, JOBZ='N') */ + + maxwrk = *m + *m * ilaenv_(&c__1, "CGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + (*m << 1) * ilaenv_(& + c__1, "CGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + maxwrk = max(i__1,i__2); + minwrk = *m * 3; + } else if (wntqo) { + +/* Path 2t (N much larger than M, JOBZ='O') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "CGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *m * ilaenv_(&c__1, "CUNGLQ", + " ", m, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + (*m << 1) * ilaenv_(& + c__1, "CGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNMBR", "PRC", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNMBR", "QLN", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *m * *n + *m * *m + wrkbl; + minwrk = (*m << 1) * *m + *m * 3; + } else if (wntqs) { + +/* Path 3t (N much larger than M, JOBZ='S') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "CGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *m * ilaenv_(&c__1, "CUNGLQ", + " ", m, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + (*m << 1) * ilaenv_(& + c__1, "CGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNMBR", "PRC", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNMBR", "QLN", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *m * *m + wrkbl; + minwrk = *m * *m + *m * 3; + } else if (wntqa) { + +/* Path 4t (N much larger than M, JOBZ='A') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "CGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *n * ilaenv_(&c__1, "CUNGLQ", + " ", n, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + (*m << 1) * ilaenv_(& + c__1, "CGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNMBR", "PRC", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNMBR", "QLN", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *m * *m + wrkbl; + minwrk = *m * *m + (*m << 1) + *n; + } + } else if (*n >= mnthr2) { + +/* Path 5t (N much larger than M, but not as much as MNTHR1) */ + + maxwrk = (*m << 1) + (*m + *n) * ilaenv_(&c__1, "CGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + minwrk = (*m << 1) + *n; + if (wntqo) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "P", m, n, m, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "Q", m, m, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + maxwrk += *m * *n; + minwrk += *m * *m; + } else if (wntqs) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "P", m, n, m, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "Q", m, m, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + } else if (wntqa) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *n * ilaenv_(&c__1, + "CUNGBR", "P", n, n, m, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "Q", m, m, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + } + } else { + +/* Path 6t (N greater than M, but not much larger) */ + + maxwrk = (*m << 1) + (*m + *n) * ilaenv_(&c__1, "CGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + minwrk = (*m << 1) + *n; + if (wntqo) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNMBR", "PRC", m, n, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNMBR", "QLN", m, m, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + maxwrk += *m * *n; + minwrk += *m * *m; + } else if (wntqs) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "PRC", m, n, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "QLN", m, m, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + } else if (wntqa) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *n * ilaenv_(&c__1, + "CUNGBR", "PRC", n, n, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "CUNGBR", "QLN", m, m, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + } + } + } + maxwrk = max(maxwrk,minwrk); + } + if (*info == 0) { + work[1].r = (real) maxwrk, work[1].i = 0.f; + if (*lwork < minwrk && *lwork != -1) { + *info = -13; + } + } + +/* Quick returns */ + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGESDD", &i__1); + return 0; + } + if (*lwork == -1) { + return 0; + } + if (*m == 0 || *n == 0) { + return 0; + } + +/* Get machine constants */ + + eps = slamch_("P"); + smlnum = sqrt(slamch_("S")) / eps; + bignum = 1.f / smlnum; + +/* Scale A if max element outside range [SMLNUM,BIGNUM] */ + + anrm = clange_("M", m, n, &a[a_offset], lda, dum); + iscl = 0; + if (anrm > 0.f && anrm < smlnum) { + iscl = 1; + clascl_("G", &c__0, &c__0, &anrm, &smlnum, m, n, &a[a_offset], lda, & + ierr); + } else if (anrm > bignum) { + iscl = 1; + clascl_("G", &c__0, &c__0, &anrm, &bignum, m, n, &a[a_offset], lda, & + ierr); + } + + if (*m >= *n) { + +/* + A has at least as many rows as columns. If A has sufficiently + more rows than columns, first reduce using the QR + decomposition (if sufficient workspace available) +*/ + + if (*m >= mnthr1) { + + if (wntqn) { + +/* + Path 1 (M much larger than N, JOBZ='N') + No singular vectors to be computed +*/ + + itau = 1; + nwork = itau + *n; + +/* + Compute A=Q*R + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: need 0) +*/ + + i__1 = *lwork - nwork + 1; + cgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Zero out below R */ + + i__1 = *n - 1; + i__2 = *n - 1; + claset_("L", &i__1, &i__2, &c_b56, &c_b56, &a[a_dim1 + 2], + lda); + ie = 1; + itauq = 1; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A + (CWorkspace: need 3*N, prefer 2*N+2*N*NB) + (RWorkspace: need N) +*/ + + i__1 = *lwork - nwork + 1; + cgebrd_(n, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + nrwork = ie + *n; + +/* + Perform bidiagonal SVD, compute singular values only + (CWorkspace: 0) + (RWorkspace: need BDSPAN) +*/ + + sbdsdc_("U", "N", n, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + + } else if (wntqo) { + +/* + Path 2 (M much larger than N, JOBZ='O') + N left singular vectors to be overwritten on A and + N right singular vectors to be computed in VT +*/ + + iu = 1; + +/* WORK(IU) is N by N */ + + ldwrku = *n; + ir = iu + ldwrku * *n; + if (*lwork >= *m * *n + *n * *n + *n * 3) { + +/* WORK(IR) is M by N */ + + ldwrkr = *m; + } else { + ldwrkr = (*lwork - *n * *n - *n * 3) / *n; + } + itau = ir + ldwrkr * *n; + nwork = itau + *n; + +/* + Compute A=Q*R + (CWorkspace: need N*N+2*N, prefer M*N+N+N*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + cgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Copy R to WORK( IR ), zeroing out below it */ + + clacpy_("U", n, n, &a[a_offset], lda, &work[ir], &ldwrkr); + i__1 = *n - 1; + i__2 = *n - 1; + claset_("L", &i__1, &i__2, &c_b56, &c_b56, &work[ir + 1], & + ldwrkr); + +/* + Generate Q in A + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + cungqr_(m, n, n, &a[a_offset], lda, &work[itau], &work[nwork], + &i__1, &ierr); + ie = 1; + itauq = itau; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in WORK(IR) + (CWorkspace: need N*N+3*N, prefer M*N+2*N+2*N*NB) + (RWorkspace: need N) +*/ + + i__1 = *lwork - nwork + 1; + cgebrd_(n, n, &work[ir], &ldwrkr, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of R in WORK(IRU) and computing right singular vectors + of R in WORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *n; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix WORK(IU) + Overwrite WORK(IU) by the left singular vectors of R + (CWorkspace: need 2*N*N+3*N, prefer M*N+N*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[iru], n, &work[iu], &ldwrku); + i__1 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", n, n, n, &work[ir], &ldwrkr, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__1, & + ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by the right singular vectors of R + (CWorkspace: need N*N+3*N, prefer M*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", n, n, n, &work[ir], &ldwrkr, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + +/* + Multiply Q in A by left singular vectors of R in + WORK(IU), storing result in WORK(IR) and copying to A + (CWorkspace: need 2*N*N, prefer N*N+M*N) + (RWorkspace: 0) +*/ + + i__1 = *m; + i__2 = ldwrkr; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrkr); + cgemm_("N", "N", &chunk, n, n, &c_b57, &a[i__ + a_dim1], + lda, &work[iu], &ldwrku, &c_b56, &work[ir], & + ldwrkr); + clacpy_("F", &chunk, n, &work[ir], &ldwrkr, &a[i__ + + a_dim1], lda); +/* L10: */ + } + + } else if (wntqs) { + +/* + Path 3 (M much larger than N, JOBZ='S') + N left singular vectors to be computed in U and + N right singular vectors to be computed in VT +*/ + + ir = 1; + +/* WORK(IR) is N by N */ + + ldwrkr = *n; + itau = ir + ldwrkr * *n; + nwork = itau + *n; + +/* + Compute A=Q*R + (CWorkspace: need N*N+2*N, prefer N*N+N+N*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + cgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Copy R to WORK(IR), zeroing out below it */ + + clacpy_("U", n, n, &a[a_offset], lda, &work[ir], &ldwrkr); + i__2 = *n - 1; + i__1 = *n - 1; + claset_("L", &i__2, &i__1, &c_b56, &c_b56, &work[ir + 1], & + ldwrkr); + +/* + Generate Q in A + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + cungqr_(m, n, n, &a[a_offset], lda, &work[itau], &work[nwork], + &i__2, &ierr); + ie = 1; + itauq = itau; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in WORK(IR) + (CWorkspace: need N*N+3*N, prefer N*N+2*N+2*N*NB) + (RWorkspace: need N) +*/ + + i__2 = *lwork - nwork + 1; + cgebrd_(n, n, &work[ir], &ldwrkr, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *n; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of R + (CWorkspace: need N*N+3*N, prefer N*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[iru], n, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", n, n, n, &work[ir], &ldwrkr, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of R + (CWorkspace: need N*N+3*N, prefer N*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", n, n, n, &work[ir], &ldwrkr, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply Q in A by left singular vectors of R in + WORK(IR), storing result in U + (CWorkspace: need N*N) + (RWorkspace: 0) +*/ + + clacpy_("F", n, n, &u[u_offset], ldu, &work[ir], &ldwrkr); + cgemm_("N", "N", m, n, n, &c_b57, &a[a_offset], lda, &work[ir] + , &ldwrkr, &c_b56, &u[u_offset], ldu); + + } else if (wntqa) { + +/* + Path 4 (M much larger than N, JOBZ='A') + M left singular vectors to be computed in U and + N right singular vectors to be computed in VT +*/ + + iu = 1; + +/* WORK(IU) is N by N */ + + ldwrku = *n; + itau = iu + ldwrku * *n; + nwork = itau + *n; + +/* + Compute A=Q*R, copying result to U + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + cgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + clacpy_("L", m, n, &a[a_offset], lda, &u[u_offset], ldu); + +/* + Generate Q in U + (CWorkspace: need N+M, prefer N+M*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + cungqr_(m, m, n, &u[u_offset], ldu, &work[itau], &work[nwork], + &i__2, &ierr); + +/* Produce R in A, zeroing out below it */ + + i__2 = *n - 1; + i__1 = *n - 1; + claset_("L", &i__2, &i__1, &c_b56, &c_b56, &a[a_dim1 + 2], + lda); + ie = 1; + itauq = itau; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A + (CWorkspace: need 3*N, prefer 2*N+2*N*NB) + (RWorkspace: need N) +*/ + + i__2 = *lwork - nwork + 1; + cgebrd_(n, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + iru = ie + *n; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix WORK(IU) + Overwrite WORK(IU) by left singular vectors of R + (CWorkspace: need N*N+3*N, prefer N*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[iru], n, &work[iu], &ldwrku); + i__2 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", n, n, n, &a[a_offset], lda, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__2, & + ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of R + (CWorkspace: need 3*N, prefer 2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply Q in U by left singular vectors of R in + WORK(IU), storing result in A + (CWorkspace: need N*N) + (RWorkspace: 0) +*/ + + cgemm_("N", "N", m, n, n, &c_b57, &u[u_offset], ldu, &work[iu] + , &ldwrku, &c_b56, &a[a_offset], lda); + +/* Copy left singular vectors of A from A to U */ + + clacpy_("F", m, n, &a[a_offset], lda, &u[u_offset], ldu); + + } + + } else if (*m >= mnthr2) { + +/* + MNTHR2 <= M < MNTHR1 + + Path 5 (M much larger than N, but not as much as MNTHR1) + Reduce to bidiagonal form without QR decomposition, use + CUNGBR and matrix multiplication to compute singular vectors +*/ + + ie = 1; + nrwork = ie + *n; + itauq = 1; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize A + (CWorkspace: need 2*N+M, prefer 2*N+(M+N)*NB) + (RWorkspace: need N) +*/ + + i__2 = *lwork - nwork + 1; + cgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__2, &ierr); + if (wntqn) { + +/* + Compute singular values only + (Cworkspace: 0) + (Rworkspace: need BDSPAN) +*/ + + sbdsdc_("U", "N", n, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + } else if (wntqo) { + iu = nwork; + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + clacpy_("U", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + cungbr_("P", n, n, n, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Generate Q in A + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + cungbr_("Q", m, n, n, &a[a_offset], lda, &work[itauq], &work[ + nwork], &i__2, &ierr); + + if (*lwork >= *m * *n + *n * 3) { + +/* WORK( IU ) is M by N */ + + ldwrku = *m; + } else { + +/* WORK(IU) is LDWRKU by N */ + + ldwrku = (*lwork - *n * 3) / *n; + } + nwork = iu + ldwrku * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in WORK(IU), copying to VT + (Cworkspace: need 0) + (Rworkspace: need 3*N*N) +*/ + + clarcm_(n, n, &rwork[irvt], n, &vt[vt_offset], ldvt, &work[iu] + , &ldwrku, &rwork[nrwork]); + clacpy_("F", n, n, &work[iu], &ldwrku, &vt[vt_offset], ldvt); + +/* + Multiply Q in A by real matrix RWORK(IRU), storing the + result in WORK(IU), copying to A + (CWorkspace: need N*N, prefer M*N) + (Rworkspace: need 3*N*N, prefer N*N+2*M*N) +*/ + + nrwork = irvt; + i__2 = *m; + i__1 = ldwrku; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrku); + clacrm_(&chunk, n, &a[i__ + a_dim1], lda, &rwork[iru], n, + &work[iu], &ldwrku, &rwork[nrwork]); + clacpy_("F", &chunk, n, &work[iu], &ldwrku, &a[i__ + + a_dim1], lda); +/* L20: */ + } + + } else if (wntqs) { + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + clacpy_("U", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + cungbr_("P", n, n, n, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__1, &ierr); + +/* + Copy A to U, generate Q + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + clacpy_("L", m, n, &a[a_offset], lda, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + cungbr_("Q", m, n, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in A, copying to VT + (Cworkspace: need 0) + (Rworkspace: need 3*N*N) +*/ + + clarcm_(n, n, &rwork[irvt], n, &vt[vt_offset], ldvt, &a[ + a_offset], lda, &rwork[nrwork]); + clacpy_("F", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + +/* + Multiply Q in U by real matrix RWORK(IRU), storing the + result in A, copying to U + (CWorkspace: need 0) + (Rworkspace: need N*N+2*M*N) +*/ + + nrwork = irvt; + clacrm_(m, n, &u[u_offset], ldu, &rwork[iru], n, &a[a_offset], + lda, &rwork[nrwork]); + clacpy_("F", m, n, &a[a_offset], lda, &u[u_offset], ldu); + } else { + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + clacpy_("U", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + cungbr_("P", n, n, n, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__1, &ierr); + +/* + Copy A to U, generate Q + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + clacpy_("L", m, n, &a[a_offset], lda, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + cungbr_("Q", m, m, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in A, copying to VT + (Cworkspace: need 0) + (Rworkspace: need 3*N*N) +*/ + + clarcm_(n, n, &rwork[irvt], n, &vt[vt_offset], ldvt, &a[ + a_offset], lda, &rwork[nrwork]); + clacpy_("F", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + +/* + Multiply Q in U by real matrix RWORK(IRU), storing the + result in A, copying to U + (CWorkspace: 0) + (Rworkspace: need 3*N*N) +*/ + + nrwork = irvt; + clacrm_(m, n, &u[u_offset], ldu, &rwork[iru], n, &a[a_offset], + lda, &rwork[nrwork]); + clacpy_("F", m, n, &a[a_offset], lda, &u[u_offset], ldu); + } + + } else { + +/* + M .LT. MNTHR2 + + Path 6 (M at least N, but not much larger) + Reduce to bidiagonal form without QR decomposition + Use CUNMBR to compute singular vectors +*/ + + ie = 1; + nrwork = ie + *n; + itauq = 1; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize A + (CWorkspace: need 2*N+M, prefer 2*N+(M+N)*NB) + (RWorkspace: need N) +*/ + + i__1 = *lwork - nwork + 1; + cgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__1, &ierr); + if (wntqn) { + +/* + Compute singular values only + (Cworkspace: 0) + (Rworkspace: need BDSPAN) +*/ + + sbdsdc_("U", "N", n, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + } else if (wntqo) { + iu = nwork; + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + if (*lwork >= *m * *n + *n * 3) { + +/* WORK( IU ) is M by N */ + + ldwrku = *m; + } else { + +/* WORK( IU ) is LDWRKU by N */ + + ldwrku = (*lwork - *n * 3) / *n; + } + nwork = iu + ldwrku * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: need 0) +*/ + + clacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + + if (*lwork >= *m * *n + *n * 3) { + +/* + Copy real matrix RWORK(IRU) to complex matrix WORK(IU) + Overwrite WORK(IU) by left singular vectors of A, copying + to A + (Cworkspace: need M*N+2*N, prefer M*N+N+N*NB) + (Rworkspace: need 0) +*/ + + claset_("F", m, n, &c_b56, &c_b56, &work[iu], &ldwrku); + clacp2_("F", n, n, &rwork[iru], n, &work[iu], &ldwrku); + i__1 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, n, n, &a[a_offset], lda, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__1, & + ierr); + clacpy_("F", m, n, &work[iu], &ldwrku, &a[a_offset], lda); + } else { + +/* + Generate Q in A + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: need 0) +*/ + + i__1 = *lwork - nwork + 1; + cungbr_("Q", m, n, n, &a[a_offset], lda, &work[itauq], & + work[nwork], &i__1, &ierr); + +/* + Multiply Q in A by real matrix RWORK(IRU), storing the + result in WORK(IU), copying to A + (CWorkspace: need N*N, prefer M*N) + (Rworkspace: need 3*N*N, prefer N*N+2*M*N) +*/ + + nrwork = irvt; + i__1 = *m; + i__2 = ldwrku; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrku); + clacrm_(&chunk, n, &a[i__ + a_dim1], lda, &rwork[iru], + n, &work[iu], &ldwrku, &rwork[nrwork]); + clacpy_("F", &chunk, n, &work[iu], &ldwrku, &a[i__ + + a_dim1], lda); +/* L30: */ + } + } + + } else if (wntqs) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (CWorkspace: need 3*N, prefer 2*N+N*NB) + (RWorkspace: 0) +*/ + + claset_("F", m, n, &c_b56, &c_b56, &u[u_offset], ldu); + clacp2_("F", n, n, &rwork[iru], n, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, n, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (CWorkspace: need 3*N, prefer 2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + } else { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + sbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* Set the right corner of U to identity matrix */ + + claset_("F", m, m, &c_b56, &c_b56, &u[u_offset], ldu); + if (*m > *n) { + i__2 = *m - *n; + i__1 = *m - *n; + claset_("F", &i__2, &i__1, &c_b56, &c_b57, &u[*n + 1 + (* + n + 1) * u_dim1], ldu); + } + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (CWorkspace: need 2*N+M, prefer 2*N+M*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[iru], n, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (CWorkspace: need 3*N, prefer 2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + } + + } + + } else { + +/* + A has more columns than rows. If A has sufficiently more + columns than rows, first reduce using the LQ decomposition (if + sufficient workspace available) +*/ + + if (*n >= mnthr1) { + + if (wntqn) { + +/* + Path 1t (N much larger than M, JOBZ='N') + No singular vectors to be computed +*/ + + itau = 1; + nwork = itau + *m; + +/* + Compute A=L*Q + (CWorkspace: need 2*M, prefer M+M*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + cgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Zero out above L */ + + i__2 = *m - 1; + i__1 = *m - 1; + claset_("U", &i__2, &i__1, &c_b56, &c_b56, &a[(a_dim1 << 1) + + 1], lda); + ie = 1; + itauq = 1; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in A + (CWorkspace: need 3*M, prefer 2*M+2*M*NB) + (RWorkspace: need M) +*/ + + i__2 = *lwork - nwork + 1; + cgebrd_(m, m, &a[a_offset], lda, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + nrwork = ie + *m; + +/* + Perform bidiagonal SVD, compute singular values only + (CWorkspace: 0) + (RWorkspace: need BDSPAN) +*/ + + sbdsdc_("U", "N", m, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + + } else if (wntqo) { + +/* + Path 2t (N much larger than M, JOBZ='O') + M right singular vectors to be overwritten on A and + M left singular vectors to be computed in U +*/ + + ivt = 1; + ldwkvt = *m; + +/* WORK(IVT) is M by M */ + + il = ivt + ldwkvt * *m; + if (*lwork >= *m * *n + *m * *m + *m * 3) { + +/* WORK(IL) M by N */ + + ldwrkl = *m; + chunk = *n; + } else { + +/* WORK(IL) is M by CHUNK */ + + ldwrkl = *m; + chunk = (*lwork - *m * *m - *m * 3) / *m; + } + itau = il + ldwrkl * chunk; + nwork = itau + *m; + +/* + Compute A=L*Q + (CWorkspace: need 2*M, prefer M+M*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + cgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Copy L to WORK(IL), zeroing about above it */ + + clacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwrkl); + i__2 = *m - 1; + i__1 = *m - 1; + claset_("U", &i__2, &i__1, &c_b56, &c_b56, &work[il + ldwrkl], + &ldwrkl); + +/* + Generate Q in A + (CWorkspace: need M*M+2*M, prefer M*M+M+M*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + cunglq_(m, n, m, &a[a_offset], lda, &work[itau], &work[nwork], + &i__2, &ierr); + ie = 1; + itauq = itau; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IL) + (CWorkspace: need M*M+3*M, prefer M*M+2*M+2*M*NB) + (RWorkspace: need M) +*/ + + i__2 = *lwork - nwork + 1; + cgebrd_(m, m, &work[il], &ldwrkl, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *m; + irvt = iru + *m * *m; + nrwork = irvt + *m * *m; + sbdsdc_("U", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix WORK(IU) + Overwrite WORK(IU) by the left singular vectors of L + (CWorkspace: need N*N+3*N, prefer M*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, m, m, &work[il], &ldwrkl, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix WORK(IVT) + Overwrite WORK(IVT) by the right singular vectors of L + (CWorkspace: need N*N+3*N, prefer M*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", m, m, &rwork[irvt], m, &work[ivt], &ldwkvt); + i__2 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", m, m, m, &work[il], &ldwrkl, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply right singular vectors of L in WORK(IL) by Q + in A, storing result in WORK(IL) and copying to A + (CWorkspace: need 2*M*M, prefer M*M+M*N)) + (RWorkspace: 0) +*/ + + i__2 = *n; + i__1 = chunk; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + cgemm_("N", "N", m, &blk, m, &c_b57, &work[ivt], m, &a[ + i__ * a_dim1 + 1], lda, &c_b56, &work[il], & + ldwrkl); + clacpy_("F", m, &blk, &work[il], &ldwrkl, &a[i__ * a_dim1 + + 1], lda); +/* L40: */ + } + + } else if (wntqs) { + +/* + Path 3t (N much larger than M, JOBZ='S') + M right singular vectors to be computed in VT and + M left singular vectors to be computed in U +*/ + + il = 1; + +/* WORK(IL) is M by M */ + + ldwrkl = *m; + itau = il + ldwrkl * *m; + nwork = itau + *m; + +/* + Compute A=L*Q + (CWorkspace: need 2*M, prefer M+M*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + cgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Copy L to WORK(IL), zeroing out above it */ + + clacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwrkl); + i__1 = *m - 1; + i__2 = *m - 1; + claset_("U", &i__1, &i__2, &c_b56, &c_b56, &work[il + ldwrkl], + &ldwrkl); + +/* + Generate Q in A + (CWorkspace: need M*M+2*M, prefer M*M+M+M*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + cunglq_(m, n, m, &a[a_offset], lda, &work[itau], &work[nwork], + &i__1, &ierr); + ie = 1; + itauq = itau; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IL) + (CWorkspace: need M*M+3*M, prefer M*M+2*M+2*M*NB) + (RWorkspace: need M) +*/ + + i__1 = *lwork - nwork + 1; + cgebrd_(m, m, &work[il], &ldwrkl, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *m; + irvt = iru + *m * *m; + nrwork = irvt + *m * *m; + sbdsdc_("U", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of L + (CWorkspace: need M*M+3*M, prefer M*M+2*M+M*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, m, m, &work[il], &ldwrkl, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by left singular vectors of L + (CWorkspace: need M*M+3*M, prefer M*M+2*M+M*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", m, m, &rwork[irvt], m, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", m, m, m, &work[il], &ldwrkl, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + +/* + Copy VT to WORK(IL), multiply right singular vectors of L + in WORK(IL) by Q in A, storing result in VT + (CWorkspace: need M*M) + (RWorkspace: 0) +*/ + + clacpy_("F", m, m, &vt[vt_offset], ldvt, &work[il], &ldwrkl); + cgemm_("N", "N", m, n, m, &c_b57, &work[il], &ldwrkl, &a[ + a_offset], lda, &c_b56, &vt[vt_offset], ldvt); + + } else if (wntqa) { + +/* + Path 9t (N much larger than M, JOBZ='A') + N right singular vectors to be computed in VT and + M left singular vectors to be computed in U +*/ + + ivt = 1; + +/* WORK(IVT) is M by M */ + + ldwkvt = *m; + itau = ivt + ldwkvt * *m; + nwork = itau + *m; + +/* + Compute A=L*Q, copying result to VT + (CWorkspace: need 2*M, prefer M+M*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + cgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + clacpy_("U", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + +/* + Generate Q in VT + (CWorkspace: need M+N, prefer M+N*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + cunglq_(n, n, m, &vt[vt_offset], ldvt, &work[itau], &work[ + nwork], &i__1, &ierr); + +/* Produce L in A, zeroing out above it */ + + i__1 = *m - 1; + i__2 = *m - 1; + claset_("U", &i__1, &i__2, &c_b56, &c_b56, &a[(a_dim1 << 1) + + 1], lda); + ie = 1; + itauq = itau; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in A + (CWorkspace: need M*M+3*M, prefer M*M+2*M+2*M*NB) + (RWorkspace: need M) +*/ + + i__1 = *lwork - nwork + 1; + cgebrd_(m, m, &a[a_offset], lda, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *m; + irvt = iru + *m * *m; + nrwork = irvt + *m * *m; + sbdsdc_("U", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of L + (CWorkspace: need 3*M, prefer 2*M+M*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, m, m, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix WORK(IVT) + Overwrite WORK(IVT) by right singular vectors of L + (CWorkspace: need M*M+3*M, prefer M*M+2*M+M*NB) + (RWorkspace: 0) +*/ + + clacp2_("F", m, m, &rwork[irvt], m, &work[ivt], &ldwkvt); + i__1 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", m, m, m, &a[a_offset], lda, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__1, & + ierr); + +/* + Multiply right singular vectors of L in WORK(IVT) by + Q in VT, storing result in A + (CWorkspace: need M*M) + (RWorkspace: 0) +*/ + + cgemm_("N", "N", m, n, m, &c_b57, &work[ivt], &ldwkvt, &vt[ + vt_offset], ldvt, &c_b56, &a[a_offset], lda); + +/* Copy right singular vectors of A from A to VT */ + + clacpy_("F", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + + } + + } else if (*n >= mnthr2) { + +/* + MNTHR2 <= N < MNTHR1 + + Path 5t (N much larger than M, but not as much as MNTHR1) + Reduce to bidiagonal form without QR decomposition, use + CUNGBR and matrix multiplication to compute singular vectors +*/ + + + ie = 1; + nrwork = ie + *m; + itauq = 1; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize A + (CWorkspace: need 2*M+N, prefer 2*M+(M+N)*NB) + (RWorkspace: M) +*/ + + i__1 = *lwork - nwork + 1; + cgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__1, &ierr); + + if (wntqn) { + +/* + Compute singular values only + (Cworkspace: 0) + (Rworkspace: need BDSPAN) +*/ + + sbdsdc_("L", "N", m, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + } else if (wntqo) { + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + ivt = nwork; + +/* + Copy A to U, generate Q + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + clacpy_("L", m, m, &a[a_offset], lda, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + cungbr_("Q", m, m, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__1, &ierr); + +/* + Generate P**H in A + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + cungbr_("P", m, n, m, &a[a_offset], lda, &work[itaup], &work[ + nwork], &i__1, &ierr); + + ldwkvt = *m; + if (*lwork >= *m * *n + *m * 3) { + +/* WORK( IVT ) is M by N */ + + nwork = ivt + ldwkvt * *n; + chunk = *n; + } else { + +/* WORK( IVT ) is M by CHUNK */ + + chunk = (*lwork - *m * 3) / *m; + nwork = ivt + ldwkvt * chunk; + } + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + sbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply Q in U by real matrix RWORK(IRVT) + storing the result in WORK(IVT), copying to U + (Cworkspace: need 0) + (Rworkspace: need 2*M*M) +*/ + + clacrm_(m, m, &u[u_offset], ldu, &rwork[iru], m, &work[ivt], & + ldwkvt, &rwork[nrwork]); + clacpy_("F", m, m, &work[ivt], &ldwkvt, &u[u_offset], ldu); + +/* + Multiply RWORK(IRVT) by P**H in A, storing the + result in WORK(IVT), copying to A + (CWorkspace: need M*M, prefer M*N) + (Rworkspace: need 2*M*M, prefer 2*M*N) +*/ + + nrwork = iru; + i__1 = *n; + i__2 = chunk; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + clarcm_(m, &blk, &rwork[irvt], m, &a[i__ * a_dim1 + 1], + lda, &work[ivt], &ldwkvt, &rwork[nrwork]); + clacpy_("F", m, &blk, &work[ivt], &ldwkvt, &a[i__ * + a_dim1 + 1], lda); +/* L50: */ + } + } else if (wntqs) { + +/* + Copy A to U, generate Q + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + clacpy_("L", m, m, &a[a_offset], lda, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + cungbr_("Q", m, m, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__2, &ierr); + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + clacpy_("U", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + cungbr_("P", m, n, m, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + sbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply Q in U by real matrix RWORK(IRU), storing the + result in A, copying to U + (CWorkspace: need 0) + (Rworkspace: need 3*M*M) +*/ + + clacrm_(m, m, &u[u_offset], ldu, &rwork[iru], m, &a[a_offset], + lda, &rwork[nrwork]); + clacpy_("F", m, m, &a[a_offset], lda, &u[u_offset], ldu); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in A, copying to VT + (Cworkspace: need 0) + (Rworkspace: need M*M+2*M*N) +*/ + + nrwork = iru; + clarcm_(m, n, &rwork[irvt], m, &vt[vt_offset], ldvt, &a[ + a_offset], lda, &rwork[nrwork]); + clacpy_("F", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + } else { + +/* + Copy A to U, generate Q + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + clacpy_("L", m, m, &a[a_offset], lda, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + cungbr_("Q", m, m, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__2, &ierr); + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + clacpy_("U", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + cungbr_("P", n, n, m, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + sbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply Q in U by real matrix RWORK(IRU), storing the + result in A, copying to U + (CWorkspace: need 0) + (Rworkspace: need 3*M*M) +*/ + + clacrm_(m, m, &u[u_offset], ldu, &rwork[iru], m, &a[a_offset], + lda, &rwork[nrwork]); + clacpy_("F", m, m, &a[a_offset], lda, &u[u_offset], ldu); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in A, copying to VT + (Cworkspace: need 0) + (Rworkspace: need M*M+2*M*N) +*/ + + clarcm_(m, n, &rwork[irvt], m, &vt[vt_offset], ldvt, &a[ + a_offset], lda, &rwork[nrwork]); + clacpy_("F", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + } + + } else { + +/* + N .LT. MNTHR2 + + Path 6t (N greater than M, but not much larger) + Reduce to bidiagonal form without LQ decomposition + Use CUNMBR to compute singular vectors +*/ + + ie = 1; + nrwork = ie + *m; + itauq = 1; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize A + (CWorkspace: need 2*M+N, prefer 2*M+(M+N)*NB) + (RWorkspace: M) +*/ + + i__2 = *lwork - nwork + 1; + cgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__2, &ierr); + if (wntqn) { + +/* + Compute singular values only + (Cworkspace: 0) + (Rworkspace: need BDSPAN) +*/ + + sbdsdc_("L", "N", m, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + } else if (wntqo) { + ldwkvt = *m; + ivt = nwork; + if (*lwork >= *m * *n + *m * 3) { + +/* WORK( IVT ) is M by N */ + + claset_("F", m, n, &c_b56, &c_b56, &work[ivt], &ldwkvt); + nwork = ivt + ldwkvt * *n; + } else { + +/* WORK( IVT ) is M by CHUNK */ + + chunk = (*lwork - *m * 3) / *m; + nwork = ivt + ldwkvt * chunk; + } + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + sbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: need 0) +*/ + + clacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + + if (*lwork >= *m * *n + *m * 3) { + +/* + Copy real matrix RWORK(IRVT) to complex matrix WORK(IVT) + Overwrite WORK(IVT) by right singular vectors of A, + copying to A + (Cworkspace: need M*N+2*M, prefer M*N+M+M*NB) + (Rworkspace: need 0) +*/ + + clacp2_("F", m, m, &rwork[irvt], m, &work[ivt], &ldwkvt); + i__2 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", m, n, m, &a[a_offset], lda, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__2, + &ierr); + clacpy_("F", m, n, &work[ivt], &ldwkvt, &a[a_offset], lda); + } else { + +/* + Generate P**H in A + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: need 0) +*/ + + i__2 = *lwork - nwork + 1; + cungbr_("P", m, n, m, &a[a_offset], lda, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Multiply Q in A by real matrix RWORK(IRU), storing the + result in WORK(IU), copying to A + (CWorkspace: need M*M, prefer M*N) + (Rworkspace: need 3*M*M, prefer M*M+2*M*N) +*/ + + nrwork = iru; + i__2 = *n; + i__1 = chunk; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + clarcm_(m, &blk, &rwork[irvt], m, &a[i__ * a_dim1 + 1] + , lda, &work[ivt], &ldwkvt, &rwork[nrwork]); + clacpy_("F", m, &blk, &work[ivt], &ldwkvt, &a[i__ * + a_dim1 + 1], lda); +/* L60: */ + } + } + } else if (wntqs) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + sbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (CWorkspace: need 3*M, prefer 2*M+M*NB) + (RWorkspace: M*M) +*/ + + clacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (CWorkspace: need 3*M, prefer 2*M+M*NB) + (RWorkspace: M*M) +*/ + + claset_("F", m, n, &c_b56, &c_b56, &vt[vt_offset], ldvt); + clacp2_("F", m, m, &rwork[irvt], m, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", m, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } else { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + + sbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (CWorkspace: need 3*M, prefer 2*M+M*NB) + (RWorkspace: M*M) +*/ + + clacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + cunmbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + +/* Set all of VT to identity matrix */ + + claset_("F", n, n, &c_b56, &c_b57, &vt[vt_offset], ldvt); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (CWorkspace: need 2*M+N, prefer 2*M+N*NB) + (RWorkspace: M*M) +*/ + + clacp2_("F", m, m, &rwork[irvt], m, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + cunmbr_("P", "R", "C", n, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } + + } + + } + +/* Undo scaling if necessary */ + + if (iscl == 1) { + if (anrm > bignum) { + slascl_("G", &c__0, &c__0, &bignum, &anrm, &minmn, &c__1, &s[1], & + minmn, &ierr); + } + if (*info != 0 && anrm > bignum) { + i__1 = minmn - 1; + slascl_("G", &c__0, &c__0, &bignum, &anrm, &i__1, &c__1, &rwork[ + ie], &minmn, &ierr); + } + if (anrm < smlnum) { + slascl_("G", &c__0, &c__0, &smlnum, &anrm, &minmn, &c__1, &s[1], & + minmn, &ierr); + } + if (*info != 0 && anrm < smlnum) { + i__1 = minmn - 1; + slascl_("G", &c__0, &c__0, &smlnum, &anrm, &i__1, &c__1, &rwork[ + ie], &minmn, &ierr); + } + } + +/* Return optimal workspace in WORK(1) */ + + work[1].r = (real) maxwrk, work[1].i = 0.f; + + return 0; + +/* End of CGESDD */ + +} /* cgesdd_ */ + +/* Subroutine */ int cgesv_(integer *n, integer *nrhs, complex *a, integer * + lda, integer *ipiv, complex *b, integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern /* Subroutine */ int cgetrf_(integer *, integer *, complex *, + integer *, integer *, integer *), xerbla_(char *, integer *), cgetrs_(char *, integer *, integer *, complex *, integer + *, integer *, complex *, integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGESV computes the solution to a complex system of linear equations + A * X = B, + where A is an N-by-N matrix and X and B are N-by-NRHS matrices. + + The LU decomposition with partial pivoting and row interchanges is + used to factor A as + A = P * L * U, + where P is a permutation matrix, L is unit lower triangular, and U is + upper triangular. The factored form of A is then used to solve the + system of equations A * X = B. + + Arguments + ========= + + N (input) INTEGER + The number of linear equations, i.e., the order of the + matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the N-by-N coefficient matrix A. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (output) INTEGER array, dimension (N) + The pivot indices that define the permutation matrix P; + row i of the matrix was interchanged with row IPIV(i). + + B (input/output) COMPLEX array, dimension (LDB,NRHS) + On entry, the N-by-NRHS matrix of right hand side matrix B. + On exit, if INFO = 0, the N-by-NRHS solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, so the solution could not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*nrhs < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGESV ", &i__1); + return 0; + } + +/* Compute the LU factorization of A. */ + + cgetrf_(n, n, &a[a_offset], lda, &ipiv[1], info); + if (*info == 0) { + +/* Solve the system A*X = B, overwriting B with X. */ + + cgetrs_("No transpose", n, nrhs, &a[a_offset], lda, &ipiv[1], &b[ + b_offset], ldb, info); + } + return 0; + +/* End of CGESV */ + +} /* cgesv_ */ + +/* Subroutine */ int cgetf2_(integer *m, integer *n, complex *a, integer *lda, + integer *ipiv, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer i__, j, jp; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *), cgeru_(integer *, integer *, complex *, complex *, + integer *, complex *, integer *, complex *, integer *); + static real sfmin; + extern /* Subroutine */ int cswap_(integer *, complex *, integer *, + complex *, integer *); + extern integer icamax_(integer *, complex *, integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGETF2 computes an LU factorization of a general m-by-n matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 2 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the m by n matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, U(k,k) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGETF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Compute machine safe minimum */ + + sfmin = slamch_("S"); + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + +/* Find pivot and test for singularity. */ + + i__2 = *m - j + 1; + jp = j - 1 + icamax_(&i__2, &a[j + j * a_dim1], &c__1); + ipiv[j] = jp; + i__2 = jp + j * a_dim1; + if (a[i__2].r != 0.f || a[i__2].i != 0.f) { + +/* Apply the interchange to columns 1:N. */ + + if (jp != j) { + cswap_(n, &a[j + a_dim1], lda, &a[jp + a_dim1], lda); + } + +/* Compute elements J+1:M of J-th column. */ + + if (j < *m) { + if (c_abs(&a[j + j * a_dim1]) >= sfmin) { + i__2 = *m - j; + c_div(&q__1, &c_b57, &a[j + j * a_dim1]); + cscal_(&i__2, &q__1, &a[j + 1 + j * a_dim1], &c__1); + } else { + i__2 = *m - j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ + j * a_dim1; + c_div(&q__1, &a[j + i__ + j * a_dim1], &a[j + j * + a_dim1]); + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L20: */ + } + } + } + + } else if (*info == 0) { + + *info = j; + } + + if (j < min(*m,*n)) { + +/* Update trailing submatrix. */ + + i__2 = *m - j; + i__3 = *n - j; + q__1.r = -1.f, q__1.i = -0.f; + cgeru_(&i__2, &i__3, &q__1, &a[j + 1 + j * a_dim1], &c__1, &a[j + + (j + 1) * a_dim1], lda, &a[j + 1 + (j + 1) * a_dim1], lda) + ; + } +/* L10: */ + } + return 0; + +/* End of CGETF2 */ + +} /* cgetf2_ */ + +/* Subroutine */ int cgetrf_(integer *m, integer *n, complex *a, integer *lda, + integer *ipiv, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1; + + /* Local variables */ + static integer i__, j, jb, nb; + extern /* Subroutine */ int cgemm_(char *, char *, integer *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *); + static integer iinfo; + extern /* Subroutine */ int ctrsm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *), cgetf2_(integer *, + integer *, complex *, integer *, integer *, integer *), xerbla_( + char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int claswp_(integer *, complex *, integer *, + integer *, integer *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGETRF computes an LU factorization of a general M-by-N matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 3 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the M-by-N matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGETRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "CGETRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + if (nb <= 1 || nb >= min(*m,*n)) { + +/* Use unblocked code. */ + + cgetf2_(m, n, &a[a_offset], lda, &ipiv[1], info); + } else { + +/* Use blocked code. */ + + i__1 = min(*m,*n); + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { +/* Computing MIN */ + i__3 = min(*m,*n) - j + 1; + jb = min(i__3,nb); + +/* + Factor diagonal and subdiagonal blocks and test for exact + singularity. +*/ + + i__3 = *m - j + 1; + cgetf2_(&i__3, &jb, &a[j + j * a_dim1], lda, &ipiv[j], &iinfo); + +/* Adjust INFO and the pivot indices. */ + + if (*info == 0 && iinfo > 0) { + *info = iinfo + j - 1; + } +/* Computing MIN */ + i__4 = *m, i__5 = j + jb - 1; + i__3 = min(i__4,i__5); + for (i__ = j; i__ <= i__3; ++i__) { + ipiv[i__] = j - 1 + ipiv[i__]; +/* L10: */ + } + +/* Apply interchanges to columns 1:J-1. */ + + i__3 = j - 1; + i__4 = j + jb - 1; + claswp_(&i__3, &a[a_offset], lda, &j, &i__4, &ipiv[1], &c__1); + + if (j + jb <= *n) { + +/* Apply interchanges to columns J+JB:N. */ + + i__3 = *n - j - jb + 1; + i__4 = j + jb - 1; + claswp_(&i__3, &a[(j + jb) * a_dim1 + 1], lda, &j, &i__4, & + ipiv[1], &c__1); + +/* Compute block row of U. */ + + i__3 = *n - j - jb + 1; + ctrsm_("Left", "Lower", "No transpose", "Unit", &jb, &i__3, & + c_b57, &a[j + j * a_dim1], lda, &a[j + (j + jb) * + a_dim1], lda); + if (j + jb <= *m) { + +/* Update trailing submatrix. */ + + i__3 = *m - j - jb + 1; + i__4 = *n - j - jb + 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "No transpose", &i__3, &i__4, &jb, + &q__1, &a[j + jb + j * a_dim1], lda, &a[j + (j + + jb) * a_dim1], lda, &c_b57, &a[j + jb + (j + jb) * + a_dim1], lda); + } + } +/* L20: */ + } + } + return 0; + +/* End of CGETRF */ + +} /* cgetrf_ */ + +/* Subroutine */ int cgetrs_(char *trans, integer *n, integer *nrhs, complex * + a, integer *lda, integer *ipiv, complex *b, integer *ldb, integer * + info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int ctrsm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *), xerbla_(char *, + integer *), claswp_(integer *, complex *, integer *, + integer *, integer *, integer *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CGETRS solves a system of linear equations + A * X = B, A**T * X = B, or A**H * X = B + with a general N-by-N matrix A using the LU factorization computed + by CGETRF. + + Arguments + ========= + + TRANS (input) CHARACTER*1 + Specifies the form of the system of equations: + = 'N': A * X = B (No transpose) + = 'T': A**T * X = B (Transpose) + = 'C': A**H * X = B (Conjugate transpose) + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) COMPLEX array, dimension (LDA,N) + The factors L and U from the factorization A = P*L*U + as computed by CGETRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (input) INTEGER array, dimension (N) + The pivot indices from CGETRF; for 1<=i<=N, row i of the + matrix was interchanged with row IPIV(i). + + B (input/output) COMPLEX array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + notran = lsame_(trans, "N"); + if (! notran && ! lsame_(trans, "T") && ! lsame_( + trans, "C")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CGETRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (notran) { + +/* + Solve A * X = B. + + Apply row interchanges to the right hand sides. +*/ + + claswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c__1); + +/* Solve L*X = B, overwriting B with X. */ + + ctrsm_("Left", "Lower", "No transpose", "Unit", n, nrhs, &c_b57, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + ctrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b57, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A**T * X = B or A**H * X = B. + + Solve U'*X = B, overwriting B with X. +*/ + + ctrsm_("Left", "Upper", trans, "Non-unit", n, nrhs, &c_b57, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + ctrsm_("Left", "Lower", trans, "Unit", n, nrhs, &c_b57, &a[a_offset], + lda, &b[b_offset], ldb); + +/* Apply row interchanges to the solution vectors. */ + + claswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c_n1); + } + + return 0; + +/* End of CGETRS */ + +} /* cgetrs_ */ + +/* Subroutine */ int cheevd_(char *jobz, char *uplo, integer *n, complex *a, + integer *lda, real *w, complex *work, integer *lwork, real *rwork, + integer *lrwork, integer *iwork, integer *liwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static real eps; + static integer inde; + static real anrm; + static integer imax; + static real rmin, rmax; + static integer lopt; + static real sigma; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + static integer lwmin, liopt; + static logical lower; + static integer llrwk, lropt; + static logical wantz; + static integer indwk2, llwrk2; + extern doublereal clanhe_(char *, char *, integer *, complex *, integer *, + real *); + static integer iscale; + extern /* Subroutine */ int clascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, complex *, integer *, integer *), cstedc_(char *, integer *, real *, real *, complex *, + integer *, complex *, integer *, real *, integer *, integer *, + integer *, integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int chetrd_(char *, integer *, complex *, integer + *, real *, real *, complex *, complex *, integer *, integer *), clacpy_(char *, integer *, integer *, complex *, integer + *, complex *, integer *); + static real safmin; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *); + static real bignum; + static integer indtau, indrwk, indwrk, liwmin; + extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *); + static integer lrwmin; + extern /* Subroutine */ int cunmtr_(char *, char *, char *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *, integer *); + static integer llwork; + static real smlnum; + static logical lquery; + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CHEEVD computes all eigenvalues and, optionally, eigenvectors of a + complex Hermitian matrix A. If eigenvectors are desired, it uses a + divide and conquer algorithm. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + JOBZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only; + = 'V': Compute eigenvalues and eigenvectors. + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA, N) + On entry, the Hermitian matrix A. If UPLO = 'U', the + leading N-by-N upper triangular part of A contains the + upper triangular part of the matrix A. If UPLO = 'L', + the leading N-by-N lower triangular part of A contains + the lower triangular part of the matrix A. + On exit, if JOBZ = 'V', then if INFO = 0, A contains the + orthonormal eigenvectors of the matrix A. + If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') + or the upper triangle (if UPLO='U') of A, including the + diagonal, is destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + W (output) REAL array, dimension (N) + If INFO = 0, the eigenvalues in ascending order. + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. + If N <= 1, LWORK must be at least 1. + If JOBZ = 'N' and N > 1, LWORK must be at least N + 1. + If JOBZ = 'V' and N > 1, LWORK must be at least 2*N + N**2. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal sizes of the WORK, RWORK and + IWORK arrays, returns these values as the first entries of + the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + RWORK (workspace/output) REAL array, + dimension (LRWORK) + On exit, if INFO = 0, RWORK(1) returns the optimal LRWORK. + + LRWORK (input) INTEGER + The dimension of the array RWORK. + If N <= 1, LRWORK must be at least 1. + If JOBZ = 'N' and N > 1, LRWORK must be at least N. + If JOBZ = 'V' and N > 1, LRWORK must be at least + 1 + 5*N + 2*N**2. + + If LRWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK, RWORK + and IWORK arrays, returns these values as the first entries + of the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) + On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. + + LIWORK (input) INTEGER + The dimension of the array IWORK. + If N <= 1, LIWORK must be at least 1. + If JOBZ = 'N' and N > 1, LIWORK must be at least 1. + If JOBZ = 'V' and N > 1, LIWORK must be at least 3 + 5*N. + + If LIWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK, RWORK + and IWORK arrays, returns these values as the first entries + of the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i and JOBZ = 'N', then the algorithm failed + to converge; i off-diagonal elements of an intermediate + tridiagonal form did not converge to zero; + if INFO = i and JOBZ = 'V', then the algorithm failed + to compute an eigenvalue while working on the submatrix + lying in rows and columns INFO/(N+1) through + mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + Modified description of INFO. Sven, 16 Feb 05. + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --w; + --work; + --rwork; + --iwork; + + /* Function Body */ + wantz = lsame_(jobz, "V"); + lower = lsame_(uplo, "L"); + lquery = *lwork == -1 || *lrwork == -1 || *liwork == -1; + + *info = 0; + if (! (wantz || lsame_(jobz, "N"))) { + *info = -1; + } else if (! (lower || lsame_(uplo, "U"))) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + + if (*info == 0) { + if (*n <= 1) { + lwmin = 1; + lrwmin = 1; + liwmin = 1; + lopt = lwmin; + lropt = lrwmin; + liopt = liwmin; + } else { + if (wantz) { + lwmin = (*n << 1) + *n * *n; +/* Computing 2nd power */ + i__1 = *n; + lrwmin = *n * 5 + 1 + (i__1 * i__1 << 1); + liwmin = *n * 5 + 3; + } else { + lwmin = *n + 1; + lrwmin = *n; + liwmin = 1; + } +/* Computing MAX */ + i__1 = lwmin, i__2 = *n + ilaenv_(&c__1, "CHETRD", uplo, n, &c_n1, + &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + lopt = max(i__1,i__2); + lropt = lrwmin; + liopt = liwmin; + } + work[1].r = (real) lopt, work[1].i = 0.f; + rwork[1] = (real) lropt; + iwork[1] = liopt; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*lrwork < lrwmin && ! lquery) { + *info = -10; + } else if (*liwork < liwmin && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CHEEVD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (*n == 1) { + i__1 = a_dim1 + 1; + w[1] = a[i__1].r; + if (wantz) { + i__1 = a_dim1 + 1; + a[i__1].r = 1.f, a[i__1].i = 0.f; + } + return 0; + } + +/* Get machine constants. */ + + safmin = slamch_("Safe minimum"); + eps = slamch_("Precision"); + smlnum = safmin / eps; + bignum = 1.f / smlnum; + rmin = sqrt(smlnum); + rmax = sqrt(bignum); + +/* Scale matrix to allowable range, if necessary. */ + + anrm = clanhe_("M", uplo, n, &a[a_offset], lda, &rwork[1]); + iscale = 0; + if (anrm > 0.f && anrm < rmin) { + iscale = 1; + sigma = rmin / anrm; + } else if (anrm > rmax) { + iscale = 1; + sigma = rmax / anrm; + } + if (iscale == 1) { + clascl_(uplo, &c__0, &c__0, &c_b894, &sigma, n, n, &a[a_offset], lda, + info); + } + +/* Call CHETRD to reduce Hermitian matrix to tridiagonal form. */ + + inde = 1; + indtau = 1; + indwrk = indtau + *n; + indrwk = inde + *n; + indwk2 = indwrk + *n * *n; + llwork = *lwork - indwrk + 1; + llwrk2 = *lwork - indwk2 + 1; + llrwk = *lrwork - indrwk + 1; + chetrd_(uplo, n, &a[a_offset], lda, &w[1], &rwork[inde], &work[indtau], & + work[indwrk], &llwork, &iinfo); + +/* + For eigenvalues only, call SSTERF. For eigenvectors, first call + CSTEDC to generate the eigenvector matrix, WORK(INDWRK), of the + tridiagonal matrix, then call CUNMTR to multiply it to the + Householder transformations represented as Householder vectors in + A. +*/ + + if (! wantz) { + ssterf_(n, &w[1], &rwork[inde], info); + } else { + cstedc_("I", n, &w[1], &rwork[inde], &work[indwrk], n, &work[indwk2], + &llwrk2, &rwork[indrwk], &llrwk, &iwork[1], liwork, info); + cunmtr_("L", uplo, "N", n, n, &a[a_offset], lda, &work[indtau], &work[ + indwrk], n, &work[indwk2], &llwrk2, &iinfo); + clacpy_("A", n, n, &work[indwrk], n, &a[a_offset], lda); + } + +/* If matrix was scaled, then rescale eigenvalues appropriately. */ + + if (iscale == 1) { + if (*info == 0) { + imax = *n; + } else { + imax = *info - 1; + } + r__1 = 1.f / sigma; + sscal_(&imax, &r__1, &w[1], &c__1); + } + + work[1].r = (real) lopt, work[1].i = 0.f; + rwork[1] = (real) lropt; + iwork[1] = liopt; + + return 0; + +/* End of CHEEVD */ + +} /* cheevd_ */ + +/* Subroutine */ int chetd2_(char *uplo, integer *n, complex *a, integer *lda, + real *d__, real *e, complex *tau, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + real r__1; + complex q__1, q__2, q__3, q__4; + + /* Local variables */ + static integer i__; + static complex taui; + extern /* Subroutine */ int cher2_(char *, integer *, complex *, complex * + , integer *, complex *, integer *, complex *, integer *); + static complex alpha; + extern /* Complex */ VOID cdotc_(complex *, integer *, complex *, integer + *, complex *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int chemv_(char *, integer *, complex *, complex * + , integer *, complex *, integer *, complex *, complex *, integer * + ), caxpy_(integer *, complex *, complex *, integer *, + complex *, integer *); + static logical upper; + extern /* Subroutine */ int clarfg_(integer *, complex *, complex *, + integer *, complex *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CHETD2 reduces a complex Hermitian matrix A to real symmetric + tridiagonal form T by a unitary similarity transformation: + Q' * A * Q = T. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + Hermitian matrix A is stored: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + n-by-n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n-by-n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit, if UPLO = 'U', the diagonal and first superdiagonal + of A are overwritten by the corresponding elements of the + tridiagonal matrix T, and the elements above the first + superdiagonal, with the array TAU, represent the unitary + matrix Q as a product of elementary reflectors; if UPLO + = 'L', the diagonal and first subdiagonal of A are over- + written by the corresponding elements of the tridiagonal + matrix T, and the elements below the first subdiagonal, with + the array TAU, represent the unitary matrix Q as a product + of elementary reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + D (output) REAL array, dimension (N) + The diagonal elements of the tridiagonal matrix T: + D(i) = A(i,i). + + E (output) REAL array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix T: + E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. + + TAU (output) COMPLEX array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-1) . . . H(2) H(1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in + A(1:i-1,i+1), and tau in TAU(i). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(n-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v2 v3 v4 ) ( d ) + ( d e v3 v4 ) ( e d ) + ( d e v4 ) ( v1 e d ) + ( d e ) ( v1 v2 e d ) + ( d ) ( v1 v2 v3 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tau; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CHETD2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + return 0; + } + + if (upper) { + +/* Reduce the upper triangle of A */ + + i__1 = *n + *n * a_dim1; + i__2 = *n + *n * a_dim1; + r__1 = a[i__2].r; + a[i__1].r = r__1, a[i__1].i = 0.f; + for (i__ = *n - 1; i__ >= 1; --i__) { + +/* + Generate elementary reflector H(i) = I - tau * v * v' + to annihilate A(1:i-1,i+1) +*/ + + i__1 = i__ + (i__ + 1) * a_dim1; + alpha.r = a[i__1].r, alpha.i = a[i__1].i; + clarfg_(&i__, &alpha, &a[(i__ + 1) * a_dim1 + 1], &c__1, &taui); + i__1 = i__; + e[i__1] = alpha.r; + + if (taui.r != 0.f || taui.i != 0.f) { + +/* Apply H(i) from both sides to A(1:i,1:i) */ + + i__1 = i__ + (i__ + 1) * a_dim1; + a[i__1].r = 1.f, a[i__1].i = 0.f; + +/* Compute x := tau * A * v storing x in TAU(1:i) */ + + chemv_(uplo, &i__, &taui, &a[a_offset], lda, &a[(i__ + 1) * + a_dim1 + 1], &c__1, &c_b56, &tau[1], &c__1) + ; + +/* Compute w := x - 1/2 * tau * (x'*v) * v */ + + q__3.r = -.5f, q__3.i = -0.f; + q__2.r = q__3.r * taui.r - q__3.i * taui.i, q__2.i = q__3.r * + taui.i + q__3.i * taui.r; + cdotc_(&q__4, &i__, &tau[1], &c__1, &a[(i__ + 1) * a_dim1 + 1] + , &c__1); + q__1.r = q__2.r * q__4.r - q__2.i * q__4.i, q__1.i = q__2.r * + q__4.i + q__2.i * q__4.r; + alpha.r = q__1.r, alpha.i = q__1.i; + caxpy_(&i__, &alpha, &a[(i__ + 1) * a_dim1 + 1], &c__1, &tau[ + 1], &c__1); + +/* + Apply the transformation as a rank-2 update: + A := A - v * w' - w * v' +*/ + + q__1.r = -1.f, q__1.i = -0.f; + cher2_(uplo, &i__, &q__1, &a[(i__ + 1) * a_dim1 + 1], &c__1, & + tau[1], &c__1, &a[a_offset], lda); + + } else { + i__1 = i__ + i__ * a_dim1; + i__2 = i__ + i__ * a_dim1; + r__1 = a[i__2].r; + a[i__1].r = r__1, a[i__1].i = 0.f; + } + i__1 = i__ + (i__ + 1) * a_dim1; + i__2 = i__; + a[i__1].r = e[i__2], a[i__1].i = 0.f; + i__1 = i__ + 1; + i__2 = i__ + 1 + (i__ + 1) * a_dim1; + d__[i__1] = a[i__2].r; + i__1 = i__; + tau[i__1].r = taui.r, tau[i__1].i = taui.i; +/* L10: */ + } + i__1 = a_dim1 + 1; + d__[1] = a[i__1].r; + } else { + +/* Reduce the lower triangle of A */ + + i__1 = a_dim1 + 1; + i__2 = a_dim1 + 1; + r__1 = a[i__2].r; + a[i__1].r = r__1, a[i__1].i = 0.f; + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* + Generate elementary reflector H(i) = I - tau * v * v' + to annihilate A(i+2:n,i) +*/ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + clarfg_(&i__2, &alpha, &a[min(i__3,*n) + i__ * a_dim1], &c__1, & + taui); + i__2 = i__; + e[i__2] = alpha.r; + + if (taui.r != 0.f || taui.i != 0.f) { + +/* Apply H(i) from both sides to A(i+1:n,i+1:n) */ + + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Compute x := tau * A * v storing y in TAU(i:n-1) */ + + i__2 = *n - i__; + chemv_(uplo, &i__2, &taui, &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b56, &tau[ + i__], &c__1); + +/* Compute w := x - 1/2 * tau * (x'*v) * v */ + + q__3.r = -.5f, q__3.i = -0.f; + q__2.r = q__3.r * taui.r - q__3.i * taui.i, q__2.i = q__3.r * + taui.i + q__3.i * taui.r; + i__2 = *n - i__; + cdotc_(&q__4, &i__2, &tau[i__], &c__1, &a[i__ + 1 + i__ * + a_dim1], &c__1); + q__1.r = q__2.r * q__4.r - q__2.i * q__4.i, q__1.i = q__2.r * + q__4.i + q__2.i * q__4.r; + alpha.r = q__1.r, alpha.i = q__1.i; + i__2 = *n - i__; + caxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &c__1); + +/* + Apply the transformation as a rank-2 update: + A := A - v * w' - w * v' +*/ + + i__2 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cher2_(uplo, &i__2, &q__1, &a[i__ + 1 + i__ * a_dim1], &c__1, + &tau[i__], &c__1, &a[i__ + 1 + (i__ + 1) * a_dim1], + lda); + + } else { + i__2 = i__ + 1 + (i__ + 1) * a_dim1; + i__3 = i__ + 1 + (i__ + 1) * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + } + i__2 = i__ + 1 + i__ * a_dim1; + i__3 = i__; + a[i__2].r = e[i__3], a[i__2].i = 0.f; + i__2 = i__; + i__3 = i__ + i__ * a_dim1; + d__[i__2] = a[i__3].r; + i__2 = i__; + tau[i__2].r = taui.r, tau[i__2].i = taui.i; +/* L20: */ + } + i__1 = *n; + i__2 = *n + *n * a_dim1; + d__[i__1] = a[i__2].r; + } + + return 0; + +/* End of CHETD2 */ + +} /* chetd2_ */ + +/* Subroutine */ int chetrd_(char *uplo, integer *n, complex *a, integer *lda, + real *d__, real *e, complex *tau, complex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1; + + /* Local variables */ + static integer i__, j, nb, kk, nx, iws; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + static logical upper; + extern /* Subroutine */ int chetd2_(char *, integer *, complex *, integer + *, real *, real *, complex *, integer *), cher2k_(char *, + char *, integer *, integer *, complex *, complex *, integer *, + complex *, integer *, real *, complex *, integer *), clatrd_(char *, integer *, integer *, complex *, integer + *, real *, complex *, complex *, integer *), xerbla_(char + *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CHETRD reduces a complex Hermitian matrix A to real symmetric + tridiagonal form T by a unitary similarity transformation: + Q**H * A * Q = T. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit, if UPLO = 'U', the diagonal and first superdiagonal + of A are overwritten by the corresponding elements of the + tridiagonal matrix T, and the elements above the first + superdiagonal, with the array TAU, represent the unitary + matrix Q as a product of elementary reflectors; if UPLO + = 'L', the diagonal and first subdiagonal of A are over- + written by the corresponding elements of the tridiagonal + matrix T, and the elements below the first subdiagonal, with + the array TAU, represent the unitary matrix Q as a product + of elementary reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + D (output) REAL array, dimension (N) + The diagonal elements of the tridiagonal matrix T: + D(i) = A(i,i). + + E (output) REAL array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix T: + E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. + + TAU (output) COMPLEX array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= 1. + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-1) . . . H(2) H(1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in + A(1:i-1,i+1), and tau in TAU(i). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(n-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v2 v3 v4 ) ( d ) + ( d e v3 v4 ) ( e d ) + ( d e v4 ) ( v1 e d ) + ( d e ) ( v1 v2 e d ) + ( d ) ( v1 v2 v3 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tau; + --work; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + lquery = *lwork == -1; + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*lwork < 1 && ! lquery) { + *info = -9; + } + + if (*info == 0) { + +/* Determine the block size. */ + + nb = ilaenv_(&c__1, "CHETRD", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, + (ftnlen)1); + lwkopt = *n * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CHETRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + nx = *n; + iws = 1; + if (nb > 1 && nb < *n) { + +/* + Determine when to cross over from blocked to unblocked code + (last block is always handled by unblocked code). + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "CHETRD", uplo, n, &c_n1, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *n) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: determine the + minimum value of NB, and reduce NB or force use of + unblocked code by setting NX = N. + + Computing MAX +*/ + i__1 = *lwork / ldwork; + nb = max(i__1,1); + nbmin = ilaenv_(&c__2, "CHETRD", uplo, n, &c_n1, &c_n1, &c_n1, + (ftnlen)6, (ftnlen)1); + if (nb < nbmin) { + nx = *n; + } + } + } else { + nx = *n; + } + } else { + nb = 1; + } + + if (upper) { + +/* + Reduce the upper triangle of A. + Columns 1:kk are handled by the unblocked method. +*/ + + kk = *n - (*n - nx + nb - 1) / nb * nb; + i__1 = kk + 1; + i__2 = -nb; + for (i__ = *n - nb + 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { + +/* + Reduce columns i:i+nb-1 to tridiagonal form and form the + matrix W which is needed to update the unreduced part of + the matrix +*/ + + i__3 = i__ + nb - 1; + clatrd_(uplo, &i__3, &nb, &a[a_offset], lda, &e[1], &tau[1], & + work[1], &ldwork); + +/* + Update the unreduced submatrix A(1:i-1,1:i-1), using an + update of the form: A := A - V*W' - W*V' +*/ + + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cher2k_(uplo, "No transpose", &i__3, &nb, &q__1, &a[i__ * a_dim1 + + 1], lda, &work[1], &ldwork, &c_b894, &a[a_offset], lda); + +/* + Copy superdiagonal elements back into A, and diagonal + elements into D +*/ + + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + i__4 = j - 1 + j * a_dim1; + i__5 = j - 1; + a[i__4].r = e[i__5], a[i__4].i = 0.f; + i__4 = j; + i__5 = j + j * a_dim1; + d__[i__4] = a[i__5].r; +/* L10: */ + } +/* L20: */ + } + +/* Use unblocked code to reduce the last or only block */ + + chetd2_(uplo, &kk, &a[a_offset], lda, &d__[1], &e[1], &tau[1], &iinfo); + } else { + +/* Reduce the lower triangle of A */ + + i__2 = *n - nx; + i__1 = nb; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { + +/* + Reduce columns i:i+nb-1 to tridiagonal form and form the + matrix W which is needed to update the unreduced part of + the matrix +*/ + + i__3 = *n - i__ + 1; + clatrd_(uplo, &i__3, &nb, &a[i__ + i__ * a_dim1], lda, &e[i__], & + tau[i__], &work[1], &ldwork); + +/* + Update the unreduced submatrix A(i+nb:n,i+nb:n), using + an update of the form: A := A - V*W' - W*V' +*/ + + i__3 = *n - i__ - nb + 1; + q__1.r = -1.f, q__1.i = -0.f; + cher2k_(uplo, "No transpose", &i__3, &nb, &q__1, &a[i__ + nb + + i__ * a_dim1], lda, &work[nb + 1], &ldwork, &c_b894, &a[ + i__ + nb + (i__ + nb) * a_dim1], lda); + +/* + Copy subdiagonal elements back into A, and diagonal + elements into D +*/ + + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + i__4 = j + 1 + j * a_dim1; + i__5 = j; + a[i__4].r = e[i__5], a[i__4].i = 0.f; + i__4 = j; + i__5 = j + j * a_dim1; + d__[i__4] = a[i__5].r; +/* L30: */ + } +/* L40: */ + } + +/* Use unblocked code to reduce the last or only block */ + + i__1 = *n - i__ + 1; + chetd2_(uplo, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], + &tau[i__], &iinfo); + } + + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CHETRD */ + +} /* chetrd_ */ + +/* Subroutine */ int chseqr_(char *job, char *compz, integer *n, integer *ilo, + integer *ihi, complex *h__, integer *ldh, complex *w, complex *z__, + integer *ldz, complex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3[2]; + real r__1, r__2, r__3; + complex q__1; + char ch__1[2]; + + /* Local variables */ + static complex hl[2401] /* was [49][49] */; + static integer kbot, nmin; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int ccopy_(integer *, complex *, integer *, + complex *, integer *); + static logical initz; + static complex workl[49]; + static logical wantt, wantz; + extern /* Subroutine */ int claqr0_(logical *, logical *, integer *, + integer *, integer *, complex *, integer *, complex *, integer *, + integer *, complex *, integer *, complex *, integer *, integer *), + clahqr_(logical *, logical *, integer *, integer *, integer *, + complex *, integer *, complex *, integer *, integer *, complex *, + integer *, integer *), clacpy_(char *, integer *, integer *, + complex *, integer *, complex *, integer *), claset_(char + *, integer *, integer *, complex *, complex *, complex *, integer + *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical lquery; + + +/* + -- LAPACK computational routine (version 3.2.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + June 2010 + + Purpose + ======= + + CHSEQR computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**H, where T is an upper triangular matrix (the + Schur form), and Z is the unitary matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input unitary + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the unitary matrix Q: A = Q*H*Q**H = (QZ)*H*(QZ)**H. + + Arguments + ========= + + JOB (input) CHARACTER*1 + = 'E': compute eigenvalues only; + = 'S': compute eigenvalues and the Schur form T. + + COMPZ (input) CHARACTER*1 + = 'N': no Schur vectors are computed; + = 'I': Z is initialized to the unit matrix and the matrix Z + of Schur vectors of H is returned; + = 'V': Z must contain an unitary matrix Q on entry, and + the product Q*Z is returned. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to CGEBAL, and then passed to CGEHRD + when the matrix output by CGEBAL is reduced to Hessenberg + form. Otherwise ILO and IHI should be set to 1 and N + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) COMPLEX array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and JOB = 'S', H contains the upper + triangular matrix T from the Schur decomposition (the + Schur form). If INFO = 0 and JOB = 'E', the contents of + H are unspecified on exit. (The output value of H when + INFO.GT.0 is given under the description of INFO below.) + + Unlike earlier versions of CHSEQR, this subroutine may + explicitly H(i,j) = 0 for i.GT.j and j = 1, 2, ... ILO-1 + or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + W (output) COMPLEX array, dimension (N) + The computed eigenvalues. If JOB = 'S', the eigenvalues are + stored in the same order as on the diagonal of the Schur + form returned in H, with W(i) = H(i,i). + + Z (input/output) COMPLEX array, dimension (LDZ,N) + If COMPZ = 'N', Z is not referenced. + If COMPZ = 'I', on entry Z need not be set and on exit, + if INFO = 0, Z contains the unitary matrix Z of the Schur + vectors of H. If COMPZ = 'V', on entry Z must contain an + N-by-N matrix Q, which is assumed to be equal to the unit + matrix except for the submatrix Z(ILO:IHI,ILO:IHI). On exit, + if INFO = 0, Z contains Q*Z. + Normally Q is the unitary matrix generated by CUNGHR + after the call to CGEHRD which formed the Hessenberg matrix + H. (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if COMPZ = 'I' or + COMPZ = 'V', then LDZ.GE.MAX(1,N). Otherwize, LDZ.GE.1. + + WORK (workspace/output) COMPLEX array, dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient and delivers very good and sometimes + optimal performance. However, LWORK as large as 11*N + may be required for optimal performance. A workspace + query is recommended to determine the optimal workspace + size. + + If LWORK = -1, then CHSEQR does a workspace query. + In this case, CHSEQR checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .LT. 0: if INFO = -i, the i-th argument had an illegal + value + .GT. 0: if INFO = i, CHSEQR failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and JOB = 'E', then on exit, the + remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and JOB = 'S', then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is a unitary matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and COMPZ = 'V', then on exit + + (final value of Z) = (initial value of Z)*U + + where U is the unitary matrix in (*) (regard- + less of the value of JOB.) + + If INFO .GT. 0 and COMPZ = 'I', then on exit + (final value of Z) = U + where U is the unitary matrix in (*) (regard- + less of the value of JOB.) + + If INFO .GT. 0 and COMPZ = 'N', then Z is not + accessed. + + ================================================================ + Default values supplied by + ILAENV(ISPEC,'CHSEQR',JOB(:1)//COMPZ(:1),N,ILO,IHI,LWORK). + It is suggested that these defaults be adjusted in order + to attain best performance in each particular + computational environment. + + ISPEC=12: The CLAHQR vs CLAQR0 crossover point. + Default: 75. (Must be at least 11.) + + ISPEC=13: Recommended deflation window size. + This depends on ILO, IHI and NS. NS is the + number of simultaneous shifts returned + by ILAENV(ISPEC=15). (See ISPEC=15 below.) + The default for (IHI-ILO+1).LE.500 is NS. + The default for (IHI-ILO+1).GT.500 is 3*NS/2. + + ISPEC=14: Nibble crossover point. (See IPARMQ for + details.) Default: 14% of deflation window + size. + + ISPEC=15: Number of simultaneous shifts in a multishift + QR iteration. + + If IHI-ILO+1 is ... + + greater than ...but less ... the + or equal to ... than default is + + 1 30 NS = 2(+) + 30 60 NS = 4(+) + 60 150 NS = 10(+) + 150 590 NS = ** + 590 3000 NS = 64 + 3000 6000 NS = 128 + 6000 infinity NS = 256 + + (+) By default some or all matrices of this order + are passed to the implicit double shift routine + CLAHQR and this parameter is ignored. See + ISPEC=12 above and comments in IPARMQ for + details. + + (**) The asterisks (**) indicate an ad-hoc + function of N increasing from 10 to 64. + + ISPEC=16: Select structured matrix multiply. + If the number of simultaneous shifts (specified + by ISPEC=15) is less than 14, then the default + for ISPEC=16 is 0. Otherwise the default for + ISPEC=16 is 2. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . CLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== NL allocates some local workspace to help small matrices + . through a rare CLAHQR failure. NL .GT. NTINY = 11 is + . required and NL .LE. NMIN = ILAENV(ISPEC=12,...) is recom- + . mended. (The default value of NMIN is 75.) Using NL = 49 + . allows up to six simultaneous shifts and a 16-by-16 + . deflation window. ==== + + ==== Decode and check the input parameters. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --w; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + wantt = lsame_(job, "S"); + initz = lsame_(compz, "I"); + wantz = initz || lsame_(compz, "V"); + r__1 = (real) max(1,*n); + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + lquery = *lwork == -1; + + *info = 0; + if (! lsame_(job, "E") && ! wantt) { + *info = -1; + } else if (! lsame_(compz, "N") && ! wantz) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -4; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -5; + } else if (*ldh < max(1,*n)) { + *info = -7; + } else if (*ldz < 1 || wantz && *ldz < max(1,*n)) { + *info = -10; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -12; + } + + if (*info != 0) { + +/* ==== Quick return in case of invalid argument. ==== */ + + i__1 = -(*info); + xerbla_("CHSEQR", &i__1); + return 0; + + } else if (*n == 0) { + +/* ==== Quick return in case N = 0; nothing to do. ==== */ + + return 0; + + } else if (lquery) { + +/* ==== Quick return in case of a workspace query ==== */ + + claqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], ilo, + ihi, &z__[z_offset], ldz, &work[1], lwork, info); +/* + ==== Ensure reported workspace size is backward-compatible with + . previous LAPACK versions. ==== + Computing MAX +*/ + r__2 = work[1].r, r__3 = (real) max(1,*n); + r__1 = dmax(r__2,r__3); + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + return 0; + + } else { + +/* ==== copy eigenvalues isolated by CGEBAL ==== */ + + if (*ilo > 1) { + i__1 = *ilo - 1; + i__2 = *ldh + 1; + ccopy_(&i__1, &h__[h_offset], &i__2, &w[1], &c__1); + } + if (*ihi < *n) { + i__1 = *n - *ihi; + i__2 = *ldh + 1; + ccopy_(&i__1, &h__[*ihi + 1 + (*ihi + 1) * h_dim1], &i__2, &w[* + ihi + 1], &c__1); + } + +/* ==== Initialize Z, if requested ==== */ + + if (initz) { + claset_("A", n, n, &c_b56, &c_b57, &z__[z_offset], ldz) + ; + } + +/* ==== Quick return if possible ==== */ + + if (*ilo == *ihi) { + i__1 = *ilo; + i__2 = *ilo + *ilo * h_dim1; + w[i__1].r = h__[i__2].r, w[i__1].i = h__[i__2].i; + return 0; + } + +/* + ==== CLAHQR/CLAQR0 crossover point ==== + + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = job; + i__3[1] = 1, a__1[1] = compz; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + nmin = ilaenv_(&c__12, "CHSEQR", ch__1, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nmin = max(11,nmin); + +/* ==== CLAQR0 for big matrices; CLAHQR for small ones ==== */ + + if (*n > nmin) { + claqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], + ilo, ihi, &z__[z_offset], ldz, &work[1], lwork, info); + } else { + +/* ==== Small matrix ==== */ + + clahqr_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], + ilo, ihi, &z__[z_offset], ldz, info); + + if (*info > 0) { + +/* + ==== A rare CLAHQR failure! CLAQR0 sometimes succeeds + . when CLAHQR fails. ==== +*/ + + kbot = *info; + + if (*n >= 49) { + +/* + ==== Larger matrices have enough subdiagonal scratch + . space to call CLAQR0 directly. ==== +*/ + + claqr0_(&wantt, &wantz, n, ilo, &kbot, &h__[h_offset], + ldh, &w[1], ilo, ihi, &z__[z_offset], ldz, &work[ + 1], lwork, info); + + } else { + +/* + ==== Tiny matrices don't have enough subdiagonal + . scratch space to benefit from CLAQR0. Hence, + . tiny matrices must be copied into a larger + . array before calling CLAQR0. ==== +*/ + + clacpy_("A", n, n, &h__[h_offset], ldh, hl, &c__49); + i__1 = *n + 1 + *n * 49 - 50; + hl[i__1].r = 0.f, hl[i__1].i = 0.f; + i__1 = 49 - *n; + claset_("A", &c__49, &i__1, &c_b56, &c_b56, &hl[(*n + 1) * + 49 - 49], &c__49); + claqr0_(&wantt, &wantz, &c__49, ilo, &kbot, hl, &c__49, & + w[1], ilo, ihi, &z__[z_offset], ldz, workl, & + c__49, info); + if (wantt || *info != 0) { + clacpy_("A", n, n, hl, &c__49, &h__[h_offset], ldh); + } + } + } + } + +/* ==== Clear out the trash, if necessary. ==== */ + + if ((wantt || *info != 0) && *n > 2) { + i__1 = *n - 2; + i__2 = *n - 2; + claset_("L", &i__1, &i__2, &c_b56, &c_b56, &h__[h_dim1 + 3], ldh); + } + +/* + ==== Ensure reported workspace size is backward-compatible with + . previous LAPACK versions. ==== + + Computing MAX +*/ + r__2 = (real) max(1,*n), r__3 = work[1].r; + r__1 = dmax(r__2,r__3); + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + } + +/* ==== End of CHSEQR ==== */ + + return 0; +} /* chseqr_ */ + +/* Subroutine */ int clabrd_(integer *m, integer *n, integer *nb, complex *a, + integer *lda, real *d__, real *e, complex *tauq, complex *taup, + complex *x, integer *ldx, complex *y, integer *ldy) +{ + /* System generated locals */ + integer a_dim1, a_offset, x_dim1, x_offset, y_dim1, y_offset, i__1, i__2, + i__3; + complex q__1; + + /* Local variables */ + static integer i__; + static complex alpha; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *), cgemv_(char *, integer *, integer *, complex *, + complex *, integer *, complex *, integer *, complex *, complex *, + integer *), clarfg_(integer *, complex *, complex *, + integer *, complex *), clacgv_(integer *, complex *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLABRD reduces the first NB rows and columns of a complex general + m by n matrix A to upper or lower real bidiagonal form by a unitary + transformation Q' * A * P, and returns the matrices X and Y which + are needed to apply the transformation to the unreduced part of A. + + If m >= n, A is reduced to upper bidiagonal form; if m < n, to lower + bidiagonal form. + + This is an auxiliary routine called by CGEBRD + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. + + N (input) INTEGER + The number of columns in the matrix A. + + NB (input) INTEGER + The number of leading rows and columns of A to be reduced. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the m by n general matrix to be reduced. + On exit, the first NB rows and columns of the matrix are + overwritten; the rest of the array is unchanged. + If m >= n, elements on and below the diagonal in the first NB + columns, with the array TAUQ, represent the unitary + matrix Q as a product of elementary reflectors; and + elements above the diagonal in the first NB rows, with the + array TAUP, represent the unitary matrix P as a product + of elementary reflectors. + If m < n, elements below the diagonal in the first NB + columns, with the array TAUQ, represent the unitary + matrix Q as a product of elementary reflectors, and + elements on and above the diagonal in the first NB rows, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) REAL array, dimension (NB) + The diagonal elements of the first NB rows and columns of + the reduced matrix. D(i) = A(i,i). + + E (output) REAL array, dimension (NB) + The off-diagonal elements of the first NB rows and columns of + the reduced matrix. + + TAUQ (output) COMPLEX array dimension (NB) + The scalar factors of the elementary reflectors which + represent the unitary matrix Q. See Further Details. + + TAUP (output) COMPLEX array, dimension (NB) + The scalar factors of the elementary reflectors which + represent the unitary matrix P. See Further Details. + + X (output) COMPLEX array, dimension (LDX,NB) + The m-by-nb matrix X required to update the unreduced part + of A. + + LDX (input) INTEGER + The leading dimension of the array X. LDX >= max(1,M). + + Y (output) COMPLEX array, dimension (LDY,NB) + The n-by-nb matrix Y required to update the unreduced part + of A. + + LDY (input) INTEGER + The leading dimension of the array Y. LDY >= max(1,N). + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + Q = H(1) H(2) . . . H(nb) and P = G(1) G(2) . . . G(nb) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, and v and u are complex + vectors. + + If m >= n, v(1:i-1) = 0, v(i) = 1, and v(i:m) is stored on exit in + A(i:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+1:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, v(1:i) = 0, v(i+1) = 1, and v(i+1:m) is stored on exit in + A(i+2:m,i); u(1:i-1) = 0, u(i) = 1, and u(i:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + The elements of the vectors v and u together form the m-by-nb matrix + V and the nb-by-n matrix U' which are needed, with X and Y, to apply + the transformation to the unreduced part of the matrix, using a block + update of the form: A := A - V*Y' - X*U'. + + The contents of A on exit are illustrated by the following examples + with nb = 2: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( 1 1 u1 u1 u1 ) ( 1 u1 u1 u1 u1 u1 ) + ( v1 1 1 u2 u2 ) ( 1 1 u2 u2 u2 u2 ) + ( v1 v2 a a a ) ( v1 1 a a a a ) + ( v1 v2 a a a ) ( v1 v2 a a a a ) + ( v1 v2 a a a ) ( v1 v2 a a a a ) + ( v1 v2 a a a ) + + where a denotes an element of the original matrix which is unchanged, + vi denotes an element of the vector defining H(i), and ui an element + of the vector defining G(i). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + y_dim1 = *ldy; + y_offset = 1 + y_dim1; + y -= y_offset; + + /* Function Body */ + if (*m <= 0 || *n <= 0) { + return 0; + } + + if (*m >= *n) { + +/* Reduce to upper bidiagonal form */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i:m,i) */ + + i__2 = i__ - 1; + clacgv_(&i__2, &y[i__ + y_dim1], ldy); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &a[i__ + a_dim1], lda, + &y[i__ + y_dim1], ldy, &c_b57, &a[i__ + i__ * a_dim1], & + c__1); + i__2 = i__ - 1; + clacgv_(&i__2, &y[i__ + y_dim1], ldy); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &x[i__ + x_dim1], ldx, + &a[i__ * a_dim1 + 1], &c__1, &c_b57, &a[i__ + i__ * + a_dim1], &c__1); + +/* Generate reflection Q(i) to annihilate A(i+1:m,i) */ + + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + clarfg_(&i__2, &alpha, &a[min(i__3,*m) + i__ * a_dim1], &c__1, & + tauq[i__]); + i__2 = i__; + d__[i__2] = alpha.r; + if (i__ < *n) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Compute Y(i+1:n,i) */ + + i__2 = *m - i__ + 1; + i__3 = *n - i__; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + ( + i__ + 1) * a_dim1], lda, &a[i__ + i__ * a_dim1], & + c__1, &c_b56, &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + a_dim1], lda, &a[i__ + i__ * a_dim1], &c__1, &c_b56, & + y[i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &y[i__ + 1 + + y_dim1], ldy, &y[i__ * y_dim1 + 1], &c__1, &c_b57, &y[ + i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &x[i__ + + x_dim1], ldx, &a[i__ + i__ * a_dim1], &c__1, &c_b56, & + y[i__ * y_dim1 + 1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("Conjugate transpose", &i__2, &i__3, &q__1, &a[(i__ + + 1) * a_dim1 + 1], lda, &y[i__ * y_dim1 + 1], &c__1, & + c_b57, &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *n - i__; + cscal_(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1); + +/* Update A(i,i+1:n) */ + + i__2 = *n - i__; + clacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + clacgv_(&i__, &a[i__ + a_dim1], lda); + i__2 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__, &q__1, &y[i__ + 1 + + y_dim1], ldy, &a[i__ + a_dim1], lda, &c_b57, &a[i__ + + (i__ + 1) * a_dim1], lda); + clacgv_(&i__, &a[i__ + a_dim1], lda); + i__2 = i__ - 1; + clacgv_(&i__2, &x[i__ + x_dim1], ldx); + i__2 = i__ - 1; + i__3 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("Conjugate transpose", &i__2, &i__3, &q__1, &a[(i__ + + 1) * a_dim1 + 1], lda, &x[i__ + x_dim1], ldx, &c_b57, + &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ - 1; + clacgv_(&i__2, &x[i__ + x_dim1], ldx); + +/* Generate reflection P(i) to annihilate A(i,i+2:n) */ + + i__2 = i__ + (i__ + 1) * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + clarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, & + taup[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + (i__ + 1) * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Compute X(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = *n - i__; + cgemv_("No transpose", &i__2, &i__3, &c_b57, &a[i__ + 1 + ( + i__ + 1) * a_dim1], lda, &a[i__ + (i__ + 1) * a_dim1], + lda, &c_b56, &x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__; + cgemv_("Conjugate transpose", &i__2, &i__, &c_b57, &y[i__ + 1 + + y_dim1], ldy, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b56, &x[i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__, &q__1, &a[i__ + 1 + + a_dim1], lda, &x[i__ * x_dim1 + 1], &c__1, &c_b57, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + cgemv_("No transpose", &i__2, &i__3, &c_b57, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b56, &x[i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &x[i__ + 1 + + x_dim1], ldx, &x[i__ * x_dim1 + 1], &c__1, &c_b57, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *m - i__; + cscal_(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__; + clacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Reduce to lower bidiagonal form */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i,i:n) */ + + i__2 = *n - i__ + 1; + clacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ - 1; + clacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &y[i__ + y_dim1], ldy, + &a[i__ + a_dim1], lda, &c_b57, &a[i__ + i__ * a_dim1], + lda); + i__2 = i__ - 1; + clacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = i__ - 1; + clacgv_(&i__2, &x[i__ + x_dim1], ldx); + i__2 = i__ - 1; + i__3 = *n - i__ + 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("Conjugate transpose", &i__2, &i__3, &q__1, &a[i__ * + a_dim1 + 1], lda, &x[i__ + x_dim1], ldx, &c_b57, &a[i__ + + i__ * a_dim1], lda); + i__2 = i__ - 1; + clacgv_(&i__2, &x[i__ + x_dim1], ldx); + +/* Generate reflection P(i) to annihilate A(i,i+1:n) */ + + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + clarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, & + taup[i__]); + i__2 = i__; + d__[i__2] = alpha.r; + if (i__ < *m) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Compute X(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = *n - i__ + 1; + cgemv_("No transpose", &i__2, &i__3, &c_b57, &a[i__ + 1 + i__ + * a_dim1], lda, &a[i__ + i__ * a_dim1], lda, &c_b56, & + x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &y[i__ + + y_dim1], ldy, &a[i__ + i__ * a_dim1], lda, &c_b56, &x[ + i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &a[i__ + 1 + + a_dim1], lda, &x[i__ * x_dim1 + 1], &c__1, &c_b57, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__ + 1; + cgemv_("No transpose", &i__2, &i__3, &c_b57, &a[i__ * a_dim1 + + 1], lda, &a[i__ + i__ * a_dim1], lda, &c_b56, &x[ + i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &x[i__ + 1 + + x_dim1], ldx, &x[i__ * x_dim1 + 1], &c__1, &c_b57, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *m - i__; + cscal_(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__ + 1; + clacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + +/* Update A(i+1:m,i) */ + + i__2 = i__ - 1; + clacgv_(&i__2, &y[i__ + y_dim1], ldy); + i__2 = *m - i__; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &a[i__ + 1 + + a_dim1], lda, &y[i__ + y_dim1], ldy, &c_b57, &a[i__ + + 1 + i__ * a_dim1], &c__1); + i__2 = i__ - 1; + clacgv_(&i__2, &y[i__ + y_dim1], ldy); + i__2 = *m - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__, &q__1, &x[i__ + 1 + + x_dim1], ldx, &a[i__ * a_dim1 + 1], &c__1, &c_b57, &a[ + i__ + 1 + i__ * a_dim1], &c__1); + +/* Generate reflection Q(i) to annihilate A(i+2:m,i) */ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *m - i__; +/* Computing MIN */ + i__3 = i__ + 2; + clarfg_(&i__2, &alpha, &a[min(i__3,*m) + i__ * a_dim1], &c__1, + &tauq[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Compute Y(i+1:n,i) */ + + i__2 = *m - i__; + i__3 = *n - i__; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + 1 + (i__ + 1) * a_dim1], lda, &a[i__ + 1 + i__ * + a_dim1], &c__1, &c_b56, &y[i__ + 1 + i__ * y_dim1], & + c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + 1 + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &y[i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &y[i__ + 1 + + y_dim1], ldy, &y[i__ * y_dim1 + 1], &c__1, &c_b57, &y[ + i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__; + cgemv_("Conjugate transpose", &i__2, &i__, &c_b57, &x[i__ + 1 + + x_dim1], ldx, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &y[i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("Conjugate transpose", &i__, &i__2, &q__1, &a[(i__ + 1) + * a_dim1 + 1], lda, &y[i__ * y_dim1 + 1], &c__1, & + c_b57, &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *n - i__; + cscal_(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1); + } else { + i__2 = *n - i__ + 1; + clacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + } +/* L20: */ + } + } + return 0; + +/* End of CLABRD */ + +} /* clabrd_ */ + +/* Subroutine */ int clacgv_(integer *n, complex *x, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2; + complex q__1; + + /* Local variables */ + static integer i__, ioff; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLACGV conjugates a complex vector of length N. + + Arguments + ========= + + N (input) INTEGER + The length of the vector X. N >= 0. + + X (input/output) COMPLEX array, dimension + (1+(N-1)*abs(INCX)) + On entry, the vector of length N to be conjugated. + On exit, X is overwritten with conjg(X). + + INCX (input) INTEGER + The spacing between successive elements of X. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*incx == 1) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + r_cnjg(&q__1, &x[i__]); + x[i__2].r = q__1.r, x[i__2].i = q__1.i; +/* L10: */ + } + } else { + ioff = 1; + if (*incx < 0) { + ioff = 1 - (*n - 1) * *incx; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ioff; + r_cnjg(&q__1, &x[ioff]); + x[i__2].r = q__1.r, x[i__2].i = q__1.i; + ioff += *incx; +/* L20: */ + } + } + return 0; + +/* End of CLACGV */ + +} /* clacgv_ */ + +/* Subroutine */ int clacp2_(char *uplo, integer *m, integer *n, real *a, + integer *lda, complex *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLACP2 copies all or part of a real two-dimensional matrix A to a + complex matrix B. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be copied to B. + = 'U': Upper triangular part + = 'L': Lower triangular part + Otherwise: All of the matrix A + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input) REAL array, dimension (LDA,N) + The m by n matrix A. If UPLO = 'U', only the upper trapezium + is accessed; if UPLO = 'L', only the lower trapezium is + accessed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + B (output) COMPLEX array, dimension (LDB,N) + On exit, B = A in the locations specified by UPLO. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4], b[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + + } else if (lsame_(uplo, "L")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4], b[i__3].i = 0.f; +/* L30: */ + } +/* L40: */ + } + + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4], b[i__3].i = 0.f; +/* L50: */ + } +/* L60: */ + } + } + + return 0; + +/* End of CLACP2 */ + +} /* clacp2_ */ + +/* Subroutine */ int clacpy_(char *uplo, integer *m, integer *n, complex *a, + integer *lda, complex *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLACPY copies all or part of a two-dimensional matrix A to another + matrix B. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be copied to B. + = 'U': Upper triangular part + = 'L': Lower triangular part + Otherwise: All of the matrix A + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input) COMPLEX array, dimension (LDA,N) + The m by n matrix A. If UPLO = 'U', only the upper trapezium + is accessed; if UPLO = 'L', only the lower trapezium is + accessed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + B (output) COMPLEX array, dimension (LDB,N) + On exit, B = A in the locations specified by UPLO. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4].r, b[i__3].i = a[i__4].i; +/* L10: */ + } +/* L20: */ + } + + } else if (lsame_(uplo, "L")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4].r, b[i__3].i = a[i__4].i; +/* L30: */ + } +/* L40: */ + } + + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4].r, b[i__3].i = a[i__4].i; +/* L50: */ + } +/* L60: */ + } + } + + return 0; + +/* End of CLACPY */ + +} /* clacpy_ */ + +/* Subroutine */ int clacrm_(integer *m, integer *n, complex *a, integer *lda, + real *b, integer *ldb, complex *c__, integer *ldc, real *rwork) +{ + /* System generated locals */ + integer b_dim1, b_offset, a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, + i__3, i__4, i__5; + real r__1; + complex q__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLACRM performs a very simple matrix-matrix multiplication: + C := A * B, + where A is M by N and complex; B is N by N and real; + C is M by N and complex. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A and of the matrix C. + M >= 0. + + N (input) INTEGER + The number of columns and rows of the matrix B and + the number of columns of the matrix C. + N >= 0. + + A (input) COMPLEX array, dimension (LDA, N) + A contains the M by N matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >=max(1,M). + + B (input) REAL array, dimension (LDB, N) + B contains the N by N matrix B. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >=max(1,N). + + C (input) COMPLEX array, dimension (LDC, N) + C contains the M by N matrix C. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >=max(1,N). + + RWORK (workspace) REAL array, dimension (2*M*N) + + ===================================================================== + + + Quick return if possible. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --rwork; + + /* Function Body */ + if (*m == 0 || *n == 0) { + return 0; + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + rwork[(j - 1) * *m + i__] = a[i__3].r; +/* L10: */ + } +/* L20: */ + } + + l = *m * *n + 1; + sgemm_("N", "N", m, n, n, &c_b894, &rwork[1], m, &b[b_offset], ldb, & + c_b1087, &rwork[l], m); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = l + (j - 1) * *m + i__ - 1; + c__[i__3].r = rwork[i__4], c__[i__3].i = 0.f; +/* L30: */ + } +/* L40: */ + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + rwork[(j - 1) * *m + i__] = r_imag(&a[i__ + j * a_dim1]); +/* L50: */ + } +/* L60: */ + } + sgemm_("N", "N", m, n, n, &c_b894, &rwork[1], m, &b[b_offset], ldb, & + c_b1087, &rwork[l], m); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + r__1 = c__[i__4].r; + i__5 = l + (j - 1) * *m + i__ - 1; + q__1.r = r__1, q__1.i = rwork[i__5]; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L70: */ + } +/* L80: */ + } + + return 0; + +/* End of CLACRM */ + +} /* clacrm_ */ + +/* Complex */ VOID cladiv_(complex * ret_val, complex *x, complex *y) +{ + /* System generated locals */ + real r__1, r__2, r__3, r__4; + complex q__1; + + /* Local variables */ + static real zi, zr; + extern /* Subroutine */ int sladiv_(real *, real *, real *, real *, real * + , real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLADIV := X / Y, where X and Y are complex. The computation of X / Y + will not overflow on an intermediary step unless the results + overflows. + + Arguments + ========= + + X (input) COMPLEX + Y (input) COMPLEX + The complex scalars X and Y. + + ===================================================================== +*/ + + + r__1 = x->r; + r__2 = r_imag(x); + r__3 = y->r; + r__4 = r_imag(y); + sladiv_(&r__1, &r__2, &r__3, &r__4, &zr, &zi); + q__1.r = zr, q__1.i = zi; + ret_val->r = q__1.r, ret_val->i = q__1.i; + + return ; + +/* End of CLADIV */ + +} /* cladiv_ */ + +/* Subroutine */ int claed0_(integer *qsiz, integer *n, real *d__, real *e, + complex *q, integer *ldq, complex *qstore, integer *ldqs, real *rwork, + integer *iwork, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, qstore_dim1, qstore_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static integer i__, j, k, ll, iq, lgn, msd2, smm1, spm1, spm2; + static real temp; + static integer curr, iperm; + extern /* Subroutine */ int ccopy_(integer *, complex *, integer *, + complex *, integer *); + static integer indxq, iwrem; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + static integer iqptr; + extern /* Subroutine */ int claed7_(integer *, integer *, integer *, + integer *, integer *, integer *, real *, complex *, integer *, + real *, integer *, real *, integer *, integer *, integer *, + integer *, integer *, real *, complex *, real *, integer *, + integer *); + static integer tlvls; + extern /* Subroutine */ int clacrm_(integer *, integer *, complex *, + integer *, real *, integer *, complex *, integer *, real *); + static integer igivcl; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer igivnm, submat, curprb, subpbs, igivpt, curlvl, matsiz, + iprmpt, smlsiz; + extern /* Subroutine */ int ssteqr_(char *, integer *, real *, real *, + real *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + Using the divide and conquer method, CLAED0 computes all eigenvalues + of a symmetric tridiagonal matrix which is one diagonal block of + those from reducing a dense or band Hermitian matrix and + corresponding eigenvectors of the dense or band matrix. + + Arguments + ========= + + QSIZ (input) INTEGER + The dimension of the unitary matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N if ICOMPQ = 1. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, the eigenvalues in ascending order. + + E (input/output) REAL array, dimension (N-1) + On entry, the off-diagonal elements of the tridiagonal matrix. + On exit, E has been destroyed. + + Q (input/output) COMPLEX array, dimension (LDQ,N) + On entry, Q must contain an QSIZ x N matrix whose columns + unitarily orthonormal. It is a part of the unitary matrix + that reduces the full dense Hermitian matrix to a + (reducible) symmetric tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + IWORK (workspace) INTEGER array, + the dimension of IWORK must be at least + 6 + 6*N + 5*N*lg N + ( lg( N ) = smallest integer k + such that 2^k >= N ) + + RWORK (workspace) REAL array, + dimension (1 + 3*N + 2*N*lg N + 3*N**2) + ( lg( N ) = smallest integer k + such that 2^k >= N ) + + QSTORE (workspace) COMPLEX array, dimension (LDQS, N) + Used to store parts of + the eigenvector matrix when the updating matrix multiplies + take place. + + LDQS (input) INTEGER + The leading dimension of the array QSTORE. + LDQS >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute an eigenvalue while + working on the submatrix lying in rows and columns + INFO/(N+1) through mod(INFO,N+1). + + ===================================================================== + + Warning: N could be as big as QSIZ! + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + qstore_dim1 = *ldqs; + qstore_offset = 1 + qstore_dim1; + qstore -= qstore_offset; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + +/* + IF( ICOMPQ .LT. 0 .OR. ICOMPQ .GT. 2 ) THEN + INFO = -1 + ELSE IF( ( ICOMPQ .EQ. 1 ) .AND. ( QSIZ .LT. MAX( 0, N ) ) ) + $ THEN +*/ + if (*qsiz < max(0,*n)) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldq < max(1,*n)) { + *info = -6; + } else if (*ldqs < max(1,*n)) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CLAED0", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + smlsiz = ilaenv_(&c__9, "CLAED0", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + +/* + Determine the size and placement of the submatrices, and save in + the leading elements of IWORK. +*/ + + iwork[1] = *n; + subpbs = 1; + tlvls = 0; +L10: + if (iwork[subpbs] > smlsiz) { + for (j = subpbs; j >= 1; --j) { + iwork[j * 2] = (iwork[j] + 1) / 2; + iwork[(j << 1) - 1] = iwork[j] / 2; +/* L20: */ + } + ++tlvls; + subpbs <<= 1; + goto L10; + } + i__1 = subpbs; + for (j = 2; j <= i__1; ++j) { + iwork[j] += iwork[j - 1]; +/* L30: */ + } + +/* + Divide the matrix into SUBPBS submatrices of size at most SMLSIZ+1 + using rank-1 modifications (cuts). +*/ + + spm1 = subpbs - 1; + i__1 = spm1; + for (i__ = 1; i__ <= i__1; ++i__) { + submat = iwork[i__] + 1; + smm1 = submat - 1; + d__[smm1] -= (r__1 = e[smm1], dabs(r__1)); + d__[submat] -= (r__1 = e[smm1], dabs(r__1)); +/* L40: */ + } + + indxq = (*n << 2) + 3; + +/* + Set up workspaces for eigenvalues only/accumulate new vectors + routine +*/ + + temp = log((real) (*n)) / log(2.f); + lgn = (integer) temp; + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + iprmpt = indxq + *n + 1; + iperm = iprmpt + *n * lgn; + iqptr = iperm + *n * lgn; + igivpt = iqptr + *n + 2; + igivcl = igivpt + *n * lgn; + + igivnm = 1; + iq = igivnm + (*n << 1) * lgn; +/* Computing 2nd power */ + i__1 = *n; + iwrem = iq + i__1 * i__1 + 1; +/* Initialize pointers */ + i__1 = subpbs; + for (i__ = 0; i__ <= i__1; ++i__) { + iwork[iprmpt + i__] = 1; + iwork[igivpt + i__] = 1; +/* L50: */ + } + iwork[iqptr] = 1; + +/* + Solve each submatrix eigenproblem at the bottom of the divide and + conquer tree. +*/ + + curr = 0; + i__1 = spm1; + for (i__ = 0; i__ <= i__1; ++i__) { + if (i__ == 0) { + submat = 1; + matsiz = iwork[1]; + } else { + submat = iwork[i__] + 1; + matsiz = iwork[i__ + 1] - iwork[i__]; + } + ll = iq - 1 + iwork[iqptr + curr]; + ssteqr_("I", &matsiz, &d__[submat], &e[submat], &rwork[ll], &matsiz, & + rwork[1], info); + clacrm_(qsiz, &matsiz, &q[submat * q_dim1 + 1], ldq, &rwork[ll], & + matsiz, &qstore[submat * qstore_dim1 + 1], ldqs, &rwork[iwrem] + ); +/* Computing 2nd power */ + i__2 = matsiz; + iwork[iqptr + curr + 1] = iwork[iqptr + curr] + i__2 * i__2; + ++curr; + if (*info > 0) { + *info = submat * (*n + 1) + submat + matsiz - 1; + return 0; + } + k = 1; + i__2 = iwork[i__ + 1]; + for (j = submat; j <= i__2; ++j) { + iwork[indxq + j] = k; + ++k; +/* L60: */ + } +/* L70: */ + } + +/* + Successively merge eigensystems of adjacent submatrices + into eigensystem for the corresponding larger matrix. + + while ( SUBPBS > 1 ) +*/ + + curlvl = 1; +L80: + if (subpbs > 1) { + spm2 = subpbs - 2; + i__1 = spm2; + for (i__ = 0; i__ <= i__1; i__ += 2) { + if (i__ == 0) { + submat = 1; + matsiz = iwork[2]; + msd2 = iwork[1]; + curprb = 0; + } else { + submat = iwork[i__] + 1; + matsiz = iwork[i__ + 2] - iwork[i__]; + msd2 = matsiz / 2; + ++curprb; + } + +/* + Merge lower order eigensystems (of size MSD2 and MATSIZ - MSD2) + into an eigensystem of size MATSIZ. CLAED7 handles the case + when the eigenvectors of a full or band Hermitian matrix (which + was reduced to tridiagonal form) are desired. + + I am free to use Q as a valuable working space until Loop 150. +*/ + + claed7_(&matsiz, &msd2, qsiz, &tlvls, &curlvl, &curprb, &d__[ + submat], &qstore[submat * qstore_dim1 + 1], ldqs, &e[ + submat + msd2 - 1], &iwork[indxq + submat], &rwork[iq], & + iwork[iqptr], &iwork[iprmpt], &iwork[iperm], &iwork[ + igivpt], &iwork[igivcl], &rwork[igivnm], &q[submat * + q_dim1 + 1], &rwork[iwrem], &iwork[subpbs + 1], info); + if (*info > 0) { + *info = submat * (*n + 1) + submat + matsiz - 1; + return 0; + } + iwork[i__ / 2 + 1] = iwork[i__ + 2]; +/* L90: */ + } + subpbs /= 2; + ++curlvl; + goto L80; + } + +/* + end while + + Re-merge the eigenvalues/vectors which were deflated at the final + merge step. +*/ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + j = iwork[indxq + i__]; + rwork[i__] = d__[j]; + ccopy_(qsiz, &qstore[j * qstore_dim1 + 1], &c__1, &q[i__ * q_dim1 + 1] + , &c__1); +/* L100: */ + } + scopy_(n, &rwork[1], &c__1, &d__[1], &c__1); + + return 0; + +/* End of CLAED0 */ + +} /* claed0_ */ + +/* Subroutine */ int claed7_(integer *n, integer *cutpnt, integer *qsiz, + integer *tlvls, integer *curlvl, integer *curpbm, real *d__, complex * + q, integer *ldq, real *rho, integer *indxq, real *qstore, integer * + qptr, integer *prmptr, integer *perm, integer *givptr, integer * + givcol, real *givnum, complex *work, real *rwork, integer *iwork, + integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + + /* Local variables */ + static integer i__, k, n1, n2, iq, iw, iz, ptr, indx, curr, indxc, indxp; + extern /* Subroutine */ int claed8_(integer *, integer *, integer *, + complex *, integer *, real *, real *, integer *, real *, real *, + complex *, integer *, real *, integer *, integer *, integer *, + integer *, integer *, integer *, real *, integer *), slaed9_( + integer *, integer *, integer *, integer *, real *, real *, + integer *, real *, real *, real *, real *, integer *, integer *), + slaeda_(integer *, integer *, integer *, integer *, integer *, + integer *, integer *, integer *, real *, real *, integer *, real * + , real *, integer *); + static integer idlmda; + extern /* Subroutine */ int clacrm_(integer *, integer *, complex *, + integer *, real *, integer *, complex *, integer *, real *), + xerbla_(char *, integer *), slamrg_(integer *, integer *, + real *, integer *, integer *, integer *); + static integer coltyp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLAED7 computes the updated eigensystem of a diagonal + matrix after modification by a rank-one symmetric matrix. This + routine is used only for the eigenproblem which requires all + eigenvalues and optionally eigenvectors of a dense or banded + Hermitian matrix that has been reduced to tridiagonal form. + + T = Q(in) ( D(in) + RHO * Z*Z' ) Q'(in) = Q(out) * D(out) * Q'(out) + + where Z = Q'u, u is a vector of length N with ones in the + CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. + + The eigenvectors of the original matrix are stored in Q, and the + eigenvalues are in D. The algorithm consists of three stages: + + The first stage consists of deflating the size of the problem + when there are multiple eigenvalues or if there is a zero in + the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine SLAED2. + + The second stage consists of calculating the updated + eigenvalues. This is done by finding the roots of the secular + equation via the routine SLAED4 (as called by SLAED3). + This routine also calculates the eigenvectors of the current + problem. + + The final stage consists of computing the updated eigenvectors + directly using the updated eigenvalues. The eigenvectors for + the current problem are multiplied with the eigenvectors from + the overall problem. + + Arguments + ========= + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + CUTPNT (input) INTEGER + Contains the location of the last eigenvalue in the leading + sub-matrix. min(1,N) <= CUTPNT <= N. + + QSIZ (input) INTEGER + The dimension of the unitary matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N. + + TLVLS (input) INTEGER + The total number of merging levels in the overall divide and + conquer tree. + + CURLVL (input) INTEGER + The current level in the overall merge routine, + 0 <= curlvl <= tlvls. + + CURPBM (input) INTEGER + The current problem in the current level in the overall + merge routine (counting from upper left to lower right). + + D (input/output) REAL array, dimension (N) + On entry, the eigenvalues of the rank-1-perturbed matrix. + On exit, the eigenvalues of the repaired matrix. + + Q (input/output) COMPLEX array, dimension (LDQ,N) + On entry, the eigenvectors of the rank-1-perturbed matrix. + On exit, the eigenvectors of the repaired tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + RHO (input) REAL + Contains the subdiagonal element used to create the rank-1 + modification. + + INDXQ (output) INTEGER array, dimension (N) + This contains the permutation which will reintegrate the + subproblem just solved back into sorted order, + ie. D( INDXQ( I = 1, N ) ) will be in ascending order. + + IWORK (workspace) INTEGER array, dimension (4*N) + + RWORK (workspace) REAL array, + dimension (3*N+2*QSIZ*N) + + WORK (workspace) COMPLEX array, dimension (QSIZ*N) + + QSTORE (input/output) REAL array, dimension (N**2+1) + Stores eigenvectors of submatrices encountered during + divide and conquer, packed together. QPTR points to + beginning of the submatrices. + + QPTR (input/output) INTEGER array, dimension (N+2) + List of indices pointing to beginning of submatrices stored + in QSTORE. The submatrices are numbered starting at the + bottom left of the divide and conquer tree, from left to + right and bottom to top. + + PRMPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in PERM a + level's permutation is stored. PRMPTR(i+1) - PRMPTR(i) + indicates the size of the permutation and also the size of + the full, non-deflated problem. + + PERM (input) INTEGER array, dimension (N lg N) + Contains the permutations (from deflation and sorting) to be + applied to each eigenblock. + + GIVPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in GIVCOL a + level's Givens rotations are stored. GIVPTR(i+1) - GIVPTR(i) + indicates the number of Givens rotations. + + GIVCOL (input) INTEGER array, dimension (2, N lg N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (input) REAL array, dimension (2, N lg N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --qstore; + --qptr; + --prmptr; + --perm; + --givptr; + givcol -= 3; + givnum -= 3; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + +/* + IF( ICOMPQ.LT.0 .OR. ICOMPQ.GT.1 ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN +*/ + if (*n < 0) { + *info = -1; + } else if (min(1,*n) > *cutpnt || *n < *cutpnt) { + *info = -2; + } else if (*qsiz < *n) { + *info = -3; + } else if (*ldq < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CLAED7", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* + The following values are for bookkeeping purposes only. They are + integer pointers which indicate the portion of the workspace + used by a particular array in SLAED2 and SLAED3. +*/ + + iz = 1; + idlmda = iz + *n; + iw = idlmda + *n; + iq = iw + *n; + + indx = 1; + indxc = indx + *n; + coltyp = indxc + *n; + indxp = coltyp + *n; + +/* + Form the z-vector which consists of the last row of Q_1 and the + first row of Q_2. +*/ + + ptr = pow_ii(&c__2, tlvls) + 1; + i__1 = *curlvl - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *tlvls - i__; + ptr += pow_ii(&c__2, &i__2); +/* L10: */ + } + curr = ptr + *curpbm; + slaeda_(n, tlvls, curlvl, curpbm, &prmptr[1], &perm[1], &givptr[1], & + givcol[3], &givnum[3], &qstore[1], &qptr[1], &rwork[iz], &rwork[ + iz + *n], info); + +/* + When solving the final problem, we no longer need the stored data, + so we will overwrite the data from this level onto the previously + used storage space. +*/ + + if (*curlvl == *tlvls) { + qptr[curr] = 1; + prmptr[curr] = 1; + givptr[curr] = 1; + } + +/* Sort and Deflate eigenvalues. */ + + claed8_(&k, n, qsiz, &q[q_offset], ldq, &d__[1], rho, cutpnt, &rwork[iz], + &rwork[idlmda], &work[1], qsiz, &rwork[iw], &iwork[indxp], &iwork[ + indx], &indxq[1], &perm[prmptr[curr]], &givptr[curr + 1], &givcol[ + (givptr[curr] << 1) + 1], &givnum[(givptr[curr] << 1) + 1], info); + prmptr[curr + 1] = prmptr[curr] + *n; + givptr[curr + 1] += givptr[curr]; + +/* Solve Secular Equation. */ + + if (k != 0) { + slaed9_(&k, &c__1, &k, n, &d__[1], &rwork[iq], &k, rho, &rwork[idlmda] + , &rwork[iw], &qstore[qptr[curr]], &k, info); + clacrm_(qsiz, &k, &work[1], qsiz, &qstore[qptr[curr]], &k, &q[ + q_offset], ldq, &rwork[iq]); +/* Computing 2nd power */ + i__1 = k; + qptr[curr + 1] = qptr[curr] + i__1 * i__1; + if (*info != 0) { + return 0; + } + +/* Prepare the INDXQ sorting premutation. */ + + n1 = k; + n2 = *n - k; + slamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &indxq[1]); + } else { + qptr[curr + 1] = qptr[curr]; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + indxq[i__] = i__; +/* L20: */ + } + } + + return 0; + +/* End of CLAED7 */ + +} /* claed7_ */ + +/* Subroutine */ int claed8_(integer *k, integer *n, integer *qsiz, complex * + q, integer *ldq, real *d__, real *rho, integer *cutpnt, real *z__, + real *dlamda, complex *q2, integer *ldq2, real *w, integer *indxp, + integer *indx, integer *indxq, integer *perm, integer *givptr, + integer *givcol, real *givnum, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, q2_dim1, q2_offset, i__1; + real r__1; + + /* Local variables */ + static real c__; + static integer i__, j; + static real s, t; + static integer k2, n1, n2, jp, n1p1; + static real eps, tau, tol; + static integer jlam, imax, jmax; + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + ccopy_(integer *, complex *, integer *, complex *, integer *), + csrot_(integer *, complex *, integer *, complex *, integer *, + real *, real *), scopy_(integer *, real *, integer *, real *, + integer *); + extern doublereal slapy2_(real *, real *), slamch_(char *); + extern /* Subroutine */ int clacpy_(char *, integer *, integer *, complex + *, integer *, complex *, integer *), xerbla_(char *, + integer *); + extern integer isamax_(integer *, real *, integer *); + extern /* Subroutine */ int slamrg_(integer *, integer *, real *, integer + *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + CLAED8 merges the two sets of eigenvalues together into a single + sorted set. Then it tries to deflate the size of the problem. + There are two ways in which deflation can occur: when two or more + eigenvalues are close together or if there is a tiny element in the + Z vector. For each such occurrence the order of the related secular + equation problem is reduced by one. + + Arguments + ========= + + K (output) INTEGER + Contains the number of non-deflated eigenvalues. + This is the order of the related secular equation. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + QSIZ (input) INTEGER + The dimension of the unitary matrix used to reduce + the dense or band matrix to tridiagonal form. + QSIZ >= N if ICOMPQ = 1. + + Q (input/output) COMPLEX array, dimension (LDQ,N) + On entry, Q contains the eigenvectors of the partially solved + system which has been previously updated in matrix + multiplies with other partially solved eigensystems. + On exit, Q contains the trailing (N-K) updated eigenvectors + (those which were deflated) in its last N-K columns. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max( 1, N ). + + D (input/output) REAL array, dimension (N) + On entry, D contains the eigenvalues of the two submatrices to + be combined. On exit, D contains the trailing (N-K) updated + eigenvalues (those which were deflated) sorted into increasing + order. + + RHO (input/output) REAL + Contains the off diagonal element associated with the rank-1 + cut which originally split the two submatrices which are now + being recombined. RHO is modified during the computation to + the value required by SLAED3. + + CUTPNT (input) INTEGER + Contains the location of the last eigenvalue in the leading + sub-matrix. MIN(1,N) <= CUTPNT <= N. + + Z (input) REAL array, dimension (N) + On input this vector contains the updating vector (the last + row of the first sub-eigenvector matrix and the first row of + the second sub-eigenvector matrix). The contents of Z are + destroyed during the updating process. + + DLAMDA (output) REAL array, dimension (N) + Contains a copy of the first K eigenvalues which will be used + by SLAED3 to form the secular equation. + + Q2 (output) COMPLEX array, dimension (LDQ2,N) + If ICOMPQ = 0, Q2 is not referenced. Otherwise, + Contains a copy of the first K eigenvectors which will be used + by SLAED7 in a matrix multiply (SGEMM) to update the new + eigenvectors. + + LDQ2 (input) INTEGER + The leading dimension of the array Q2. LDQ2 >= max( 1, N ). + + W (output) REAL array, dimension (N) + This will hold the first k values of the final + deflation-altered z-vector and will be passed to SLAED3. + + INDXP (workspace) INTEGER array, dimension (N) + This will contain the permutation used to place deflated + values of D at the end of the array. On output INDXP(1:K) + points to the nondeflated D-values and INDXP(K+1:N) + points to the deflated eigenvalues. + + INDX (workspace) INTEGER array, dimension (N) + This will contain the permutation used to sort the contents of + D into ascending order. + + INDXQ (input) INTEGER array, dimension (N) + This contains the permutation which separately sorts the two + sub-problems in D into ascending order. Note that elements in + the second half of this permutation must first have CUTPNT + added to their values in order to be accurate. + + PERM (output) INTEGER array, dimension (N) + Contains the permutations (from deflation and sorting) to be + applied to each eigenblock. + + GIVPTR (output) INTEGER + Contains the number of Givens rotations which took place in + this subproblem. + + GIVCOL (output) INTEGER array, dimension (2, N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (output) REAL array, dimension (2, N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --d__; + --z__; + --dlamda; + q2_dim1 = *ldq2; + q2_offset = 1 + q2_dim1; + q2 -= q2_offset; + --w; + --indxp; + --indx; + --indxq; + --perm; + givcol -= 3; + givnum -= 3; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -2; + } else if (*qsiz < *n) { + *info = -3; + } else if (*ldq < max(1,*n)) { + *info = -5; + } else if (*cutpnt < min(1,*n) || *cutpnt > *n) { + *info = -8; + } else if (*ldq2 < max(1,*n)) { + *info = -12; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CLAED8", &i__1); + return 0; + } + +/* + Need to initialize GIVPTR to O here in case of quick exit + to prevent an unspecified code behavior (usually sigfault) + when IWORK array on entry to *stedc is not zeroed + (or at least some IWORK entries which used in *laed7 for GIVPTR). +*/ + + *givptr = 0; + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + n1 = *cutpnt; + n2 = *n - n1; + n1p1 = n1 + 1; + + if (*rho < 0.f) { + sscal_(&n2, &c_b1136, &z__[n1p1], &c__1); + } + +/* Normalize z so that norm(z) = 1 */ + + t = 1.f / sqrt(2.f); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + indx[j] = j; +/* L10: */ + } + sscal_(n, &t, &z__[1], &c__1); + *rho = (r__1 = *rho * 2.f, dabs(r__1)); + +/* Sort the eigenvalues into increasing order */ + + i__1 = *n; + for (i__ = *cutpnt + 1; i__ <= i__1; ++i__) { + indxq[i__] += *cutpnt; +/* L20: */ + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = d__[indxq[i__]]; + w[i__] = z__[indxq[i__]]; +/* L30: */ + } + i__ = 1; + j = *cutpnt + 1; + slamrg_(&n1, &n2, &dlamda[1], &c__1, &c__1, &indx[1]); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d__[i__] = dlamda[indx[i__]]; + z__[i__] = w[indx[i__]]; +/* L40: */ + } + +/* Calculate the allowable deflation tolerance */ + + imax = isamax_(n, &z__[1], &c__1); + jmax = isamax_(n, &d__[1], &c__1); + eps = slamch_("Epsilon"); + tol = eps * 8.f * (r__1 = d__[jmax], dabs(r__1)); + +/* + If the rank-1 modifier is small enough, no more needs to be done + -- except to reorganize Q so that its columns correspond with the + elements in D. +*/ + + if (*rho * (r__1 = z__[imax], dabs(r__1)) <= tol) { + *k = 0; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + perm[j] = indxq[indx[j]]; + ccopy_(qsiz, &q[perm[j] * q_dim1 + 1], &c__1, &q2[j * q2_dim1 + 1] + , &c__1); +/* L50: */ + } + clacpy_("A", qsiz, n, &q2[q2_dim1 + 1], ldq2, &q[q_dim1 + 1], ldq); + return 0; + } + +/* + If there are multiple eigenvalues then the problem deflates. Here + the number of equal eigenvalues are found. As each equal + eigenvalue is found, an elementary reflector is computed to rotate + the corresponding eigensubspace so that the corresponding + components of Z are zero in this new basis. +*/ + + *k = 0; + k2 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*rho * (r__1 = z__[j], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + indxp[k2] = j; + if (j == *n) { + goto L100; + } + } else { + jlam = j; + goto L70; + } +/* L60: */ + } +L70: + ++j; + if (j > *n) { + goto L90; + } + if (*rho * (r__1 = z__[j], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + indxp[k2] = j; + } else { + +/* Check if eigenvalues are close enough to allow deflation. */ + + s = z__[jlam]; + c__ = z__[j]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = slapy2_(&c__, &s); + t = d__[j] - d__[jlam]; + c__ /= tau; + s = -s / tau; + if ((r__1 = t * c__ * s, dabs(r__1)) <= tol) { + +/* Deflation is possible. */ + + z__[j] = tau; + z__[jlam] = 0.f; + +/* Record the appropriate Givens rotation */ + + ++(*givptr); + givcol[(*givptr << 1) + 1] = indxq[indx[jlam]]; + givcol[(*givptr << 1) + 2] = indxq[indx[j]]; + givnum[(*givptr << 1) + 1] = c__; + givnum[(*givptr << 1) + 2] = s; + csrot_(qsiz, &q[indxq[indx[jlam]] * q_dim1 + 1], &c__1, &q[indxq[ + indx[j]] * q_dim1 + 1], &c__1, &c__, &s); + t = d__[jlam] * c__ * c__ + d__[j] * s * s; + d__[j] = d__[jlam] * s * s + d__[j] * c__ * c__; + d__[jlam] = t; + --k2; + i__ = 1; +L80: + if (k2 + i__ <= *n) { + if (d__[jlam] < d__[indxp[k2 + i__]]) { + indxp[k2 + i__ - 1] = indxp[k2 + i__]; + indxp[k2 + i__] = jlam; + ++i__; + goto L80; + } else { + indxp[k2 + i__ - 1] = jlam; + } + } else { + indxp[k2 + i__ - 1] = jlam; + } + jlam = j; + } else { + ++(*k); + w[*k] = z__[jlam]; + dlamda[*k] = d__[jlam]; + indxp[*k] = jlam; + jlam = j; + } + } + goto L70; +L90: + +/* Record the last eigenvalue. */ + + ++(*k); + w[*k] = z__[jlam]; + dlamda[*k] = d__[jlam]; + indxp[*k] = jlam; + +L100: + +/* + Sort the eigenvalues and corresponding eigenvectors into DLAMDA + and Q2 respectively. The eigenvalues/vectors which were not + deflated go into the first K slots of DLAMDA and Q2 respectively, + while those which were deflated go into the last N - K slots. +*/ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + jp = indxp[j]; + dlamda[j] = d__[jp]; + perm[j] = indxq[indx[jp]]; + ccopy_(qsiz, &q[perm[j] * q_dim1 + 1], &c__1, &q2[j * q2_dim1 + 1], & + c__1); +/* L110: */ + } + +/* + The deflated eigenvalues and their corresponding vectors go back + into the last N - K slots of D and Q respectively. +*/ + + if (*k < *n) { + i__1 = *n - *k; + scopy_(&i__1, &dlamda[*k + 1], &c__1, &d__[*k + 1], &c__1); + i__1 = *n - *k; + clacpy_("A", qsiz, &i__1, &q2[(*k + 1) * q2_dim1 + 1], ldq2, &q[(*k + + 1) * q_dim1 + 1], ldq); + } + + return 0; + +/* End of CLAED8 */ + +} /* claed8_ */ + +/* Subroutine */ int clahqr_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *w, + integer *iloz, integer *ihiz, complex *z__, integer *ldz, integer * + info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + real r__1, r__2, r__3, r__4, r__5, r__6; + complex q__1, q__2, q__3, q__4, q__5, q__6, q__7; + + /* Local variables */ + static integer i__, j, k, l, m; + static real s; + static complex t, u, v[2], x, y; + static integer i1, i2; + static complex t1; + static real t2; + static complex v2; + static real aa, ab, ba, bb, h10; + static complex h11; + static real h21; + static complex h22, sc; + static integer nh, nz; + static real sx; + static integer jhi; + static complex h11s; + static integer jlo, its; + static real ulp; + static complex sum; + static real tst; + static complex temp; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *), ccopy_(integer *, complex *, integer *, complex *, + integer *); + static real rtemp; + extern /* Subroutine */ int slabad_(real *, real *), clarfg_(integer *, + complex *, complex *, integer *, complex *); + extern /* Complex */ VOID cladiv_(complex *, complex *, complex *); + extern doublereal slamch_(char *); + static real safmin, safmax, smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Purpose + ======= + + CLAHQR is an auxiliary routine called by CHSEQR to update the + eigenvalues and Schur decomposition already computed by CHSEQR, by + dealing with the Hessenberg submatrix in rows and columns ILO to + IHI. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows and + columns IHI+1:N, and that H(ILO,ILO-1) = 0 (unless ILO = 1). + CLAHQR works primarily with the Hessenberg submatrix in rows + and columns ILO to IHI, but applies transformations to all of + H if WANTT is .TRUE.. + 1 <= ILO <= max(1,IHI); IHI <= N. + + H (input/output) COMPLEX array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO is zero and if WANTT is .TRUE., then H + is upper triangular in rows and columns ILO:IHI. If INFO + is zero and if WANTT is .FALSE., then the contents of H + are unspecified on exit. The output state of H in case + INF is positive is below under the description of INFO. + + LDH (input) INTEGER + The leading dimension of the array H. LDH >= max(1,N). + + W (output) COMPLEX array, dimension (N) + The computed eigenvalues ILO to IHI are stored in the + corresponding elements of W. If WANTT is .TRUE., the + eigenvalues are stored in the same order as on the diagonal + of the Schur form returned in H, with W(i) = H(i,i). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. + 1 <= ILOZ <= ILO; IHI <= IHIZ <= N. + + Z (input/output) COMPLEX array, dimension (LDZ,N) + If WANTZ is .TRUE., on entry Z must contain the current + matrix Z of transformations accumulated by CHSEQR, and on + exit Z has been updated; transformations are applied only to + the submatrix Z(ILOZ:IHIZ,ILO:IHI). + If WANTZ is .FALSE., Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, CLAHQR failed to compute all the + eigenvalues ILO to IHI in a total of 30 iterations + per eigenvalue; elements i+1:ihi of W contain + those eigenvalues which have been successfully + computed. + + If INFO .GT. 0 and WANTT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the + eigenvalues of the upper Hessenberg matrix + rows and columns ILO thorugh INFO of the final, + output value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + (*) (initial value of H)*U = U*(final value of H) + where U is an orthognal matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + (final value of Z) = (initial value of Z)*U + where U is the orthogonal matrix in (*) + (regardless of the value of WANTT.) + + Further Details + =============== + + 02-96 Based on modifications by + David Day, Sandia National Laboratory, USA + + 12-04 Further modifications by + Ralph Byers, University of Kansas, USA + This is a modified version of CLAHQR from LAPACK version 3.0. + It is (1) more robust against overflow and underflow and + (2) adopts the more conservative Ahues & Tisseur stopping + criterion (LAWN 122, 1997). + + ========================================================= +*/ + + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --w; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + + /* Function Body */ + *info = 0; + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*ilo == *ihi) { + i__1 = *ilo; + i__2 = *ilo + *ilo * h_dim1; + w[i__1].r = h__[i__2].r, w[i__1].i = h__[i__2].i; + return 0; + } + +/* ==== clear out the trash ==== */ + i__1 = *ihi - 3; + for (j = *ilo; j <= i__1; ++j) { + i__2 = j + 2 + j * h_dim1; + h__[i__2].r = 0.f, h__[i__2].i = 0.f; + i__2 = j + 3 + j * h_dim1; + h__[i__2].r = 0.f, h__[i__2].i = 0.f; +/* L10: */ + } + if (*ilo <= *ihi - 2) { + i__1 = *ihi + (*ihi - 2) * h_dim1; + h__[i__1].r = 0.f, h__[i__1].i = 0.f; + } +/* ==== ensure that subdiagonal entries are real ==== */ + if (*wantt) { + jlo = 1; + jhi = *n; + } else { + jlo = *ilo; + jhi = *ihi; + } + i__1 = *ihi; + for (i__ = *ilo + 1; i__ <= i__1; ++i__) { + if (r_imag(&h__[i__ + (i__ - 1) * h_dim1]) != 0.f) { +/* + ==== The following redundant normalization + . avoids problems with both gradual and + . sudden underflow in ABS(H(I,I-1)) ==== +*/ + i__2 = i__ + (i__ - 1) * h_dim1; + i__3 = i__ + (i__ - 1) * h_dim1; + r__3 = (r__1 = h__[i__3].r, dabs(r__1)) + (r__2 = r_imag(&h__[i__ + + (i__ - 1) * h_dim1]), dabs(r__2)); + q__1.r = h__[i__2].r / r__3, q__1.i = h__[i__2].i / r__3; + sc.r = q__1.r, sc.i = q__1.i; + r_cnjg(&q__2, &sc); + r__1 = c_abs(&sc); + q__1.r = q__2.r / r__1, q__1.i = q__2.i / r__1; + sc.r = q__1.r, sc.i = q__1.i; + i__2 = i__ + (i__ - 1) * h_dim1; + r__1 = c_abs(&h__[i__ + (i__ - 1) * h_dim1]); + h__[i__2].r = r__1, h__[i__2].i = 0.f; + i__2 = jhi - i__ + 1; + cscal_(&i__2, &sc, &h__[i__ + i__ * h_dim1], ldh); +/* Computing MIN */ + i__3 = jhi, i__4 = i__ + 1; + i__2 = min(i__3,i__4) - jlo + 1; + r_cnjg(&q__1, &sc); + cscal_(&i__2, &q__1, &h__[jlo + i__ * h_dim1], &c__1); + if (*wantz) { + i__2 = *ihiz - *iloz + 1; + r_cnjg(&q__1, &sc); + cscal_(&i__2, &q__1, &z__[*iloz + i__ * z_dim1], &c__1); + } + } +/* L20: */ + } + + nh = *ihi - *ilo + 1; + nz = *ihiz - *iloz + 1; + +/* Set machine-dependent constants for the stopping criterion. */ + + safmin = slamch_("SAFE MINIMUM"); + safmax = 1.f / safmin; + slabad_(&safmin, &safmax); + ulp = slamch_("PRECISION"); + smlnum = safmin * ((real) nh / ulp); + +/* + I1 and I2 are the indices of the first row and last column of H + to which transformations must be applied. If eigenvalues only are + being computed, I1 and I2 are set inside the main loop. +*/ + + if (*wantt) { + i1 = 1; + i2 = *n; + } + +/* + The main loop begins here. I is the loop index and decreases from + IHI to ILO in steps of 1. Each iteration of the loop works + with the active submatrix in rows and columns L to I. + Eigenvalues I+1 to IHI have already converged. Either L = ILO, or + H(L,L-1) is negligible so that the matrix splits. +*/ + + i__ = *ihi; +L30: + if (i__ < *ilo) { + goto L150; + } + +/* + Perform QR iterations on rows and columns ILO to I until a + submatrix of order 1 splits off at the bottom because a + subdiagonal element has become negligible. +*/ + + l = *ilo; + for (its = 0; its <= 30; ++its) { + +/* Look for a single small subdiagonal element. */ + + i__1 = l + 1; + for (k = i__; k >= i__1; --k) { + i__2 = k + (k - 1) * h_dim1; + if ((r__1 = h__[i__2].r, dabs(r__1)) + (r__2 = r_imag(&h__[k + (k + - 1) * h_dim1]), dabs(r__2)) <= smlnum) { + goto L50; + } + i__2 = k - 1 + (k - 1) * h_dim1; + i__3 = k + k * h_dim1; + tst = (r__1 = h__[i__2].r, dabs(r__1)) + (r__2 = r_imag(&h__[k - + 1 + (k - 1) * h_dim1]), dabs(r__2)) + ((r__3 = h__[i__3] + .r, dabs(r__3)) + (r__4 = r_imag(&h__[k + k * h_dim1]), + dabs(r__4))); + if (tst == 0.f) { + if (k - 2 >= *ilo) { + i__2 = k - 1 + (k - 2) * h_dim1; + tst += (r__1 = h__[i__2].r, dabs(r__1)); + } + if (k + 1 <= *ihi) { + i__2 = k + 1 + k * h_dim1; + tst += (r__1 = h__[i__2].r, dabs(r__1)); + } + } +/* + ==== The following is a conservative small subdiagonal + . deflation criterion due to Ahues & Tisseur (LAWN 122, + . 1997). It has better mathematical foundation and + . improves accuracy in some examples. ==== +*/ + i__2 = k + (k - 1) * h_dim1; + if ((r__1 = h__[i__2].r, dabs(r__1)) <= ulp * tst) { +/* Computing MAX */ + i__2 = k + (k - 1) * h_dim1; + i__3 = k - 1 + k * h_dim1; + r__5 = (r__1 = h__[i__2].r, dabs(r__1)) + (r__2 = r_imag(&h__[ + k + (k - 1) * h_dim1]), dabs(r__2)), r__6 = (r__3 = + h__[i__3].r, dabs(r__3)) + (r__4 = r_imag(&h__[k - 1 + + k * h_dim1]), dabs(r__4)); + ab = dmax(r__5,r__6); +/* Computing MIN */ + i__2 = k + (k - 1) * h_dim1; + i__3 = k - 1 + k * h_dim1; + r__5 = (r__1 = h__[i__2].r, dabs(r__1)) + (r__2 = r_imag(&h__[ + k + (k - 1) * h_dim1]), dabs(r__2)), r__6 = (r__3 = + h__[i__3].r, dabs(r__3)) + (r__4 = r_imag(&h__[k - 1 + + k * h_dim1]), dabs(r__4)); + ba = dmin(r__5,r__6); + i__2 = k - 1 + (k - 1) * h_dim1; + i__3 = k + k * h_dim1; + q__2.r = h__[i__2].r - h__[i__3].r, q__2.i = h__[i__2].i - + h__[i__3].i; + q__1.r = q__2.r, q__1.i = q__2.i; +/* Computing MAX */ + i__4 = k + k * h_dim1; + r__5 = (r__1 = h__[i__4].r, dabs(r__1)) + (r__2 = r_imag(&h__[ + k + k * h_dim1]), dabs(r__2)), r__6 = (r__3 = q__1.r, + dabs(r__3)) + (r__4 = r_imag(&q__1), dabs(r__4)); + aa = dmax(r__5,r__6); + i__2 = k - 1 + (k - 1) * h_dim1; + i__3 = k + k * h_dim1; + q__2.r = h__[i__2].r - h__[i__3].r, q__2.i = h__[i__2].i - + h__[i__3].i; + q__1.r = q__2.r, q__1.i = q__2.i; +/* Computing MIN */ + i__4 = k + k * h_dim1; + r__5 = (r__1 = h__[i__4].r, dabs(r__1)) + (r__2 = r_imag(&h__[ + k + k * h_dim1]), dabs(r__2)), r__6 = (r__3 = q__1.r, + dabs(r__3)) + (r__4 = r_imag(&q__1), dabs(r__4)); + bb = dmin(r__5,r__6); + s = aa + ab; +/* Computing MAX */ + r__1 = smlnum, r__2 = ulp * (bb * (aa / s)); + if (ba * (ab / s) <= dmax(r__1,r__2)) { + goto L50; + } + } +/* L40: */ + } +L50: + l = k; + if (l > *ilo) { + +/* H(L,L-1) is negligible */ + + i__1 = l + (l - 1) * h_dim1; + h__[i__1].r = 0.f, h__[i__1].i = 0.f; + } + +/* Exit from loop if a submatrix of order 1 has split off. */ + + if (l >= i__) { + goto L140; + } + +/* + Now the active submatrix is in rows and columns L to I. If + eigenvalues only are being computed, only the active submatrix + need be transformed. +*/ + + if (! (*wantt)) { + i1 = l; + i2 = i__; + } + + if (its == 10) { + +/* Exceptional shift. */ + + i__1 = l + 1 + l * h_dim1; + s = (r__1 = h__[i__1].r, dabs(r__1)) * .75f; + i__1 = l + l * h_dim1; + q__1.r = s + h__[i__1].r, q__1.i = h__[i__1].i; + t.r = q__1.r, t.i = q__1.i; + } else if (its == 20) { + +/* Exceptional shift. */ + + i__1 = i__ + (i__ - 1) * h_dim1; + s = (r__1 = h__[i__1].r, dabs(r__1)) * .75f; + i__1 = i__ + i__ * h_dim1; + q__1.r = s + h__[i__1].r, q__1.i = h__[i__1].i; + t.r = q__1.r, t.i = q__1.i; + } else { + +/* Wilkinson's shift. */ + + i__1 = i__ + i__ * h_dim1; + t.r = h__[i__1].r, t.i = h__[i__1].i; + c_sqrt(&q__2, &h__[i__ - 1 + i__ * h_dim1]); + c_sqrt(&q__3, &h__[i__ + (i__ - 1) * h_dim1]); + q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, q__1.i = q__2.r * + q__3.i + q__2.i * q__3.r; + u.r = q__1.r, u.i = q__1.i; + s = (r__1 = u.r, dabs(r__1)) + (r__2 = r_imag(&u), dabs(r__2)); + if (s != 0.f) { + i__1 = i__ - 1 + (i__ - 1) * h_dim1; + q__2.r = h__[i__1].r - t.r, q__2.i = h__[i__1].i - t.i; + q__1.r = q__2.r * .5f, q__1.i = q__2.i * .5f; + x.r = q__1.r, x.i = q__1.i; + sx = (r__1 = x.r, dabs(r__1)) + (r__2 = r_imag(&x), dabs(r__2) + ); +/* Computing MAX */ + r__3 = s, r__4 = (r__1 = x.r, dabs(r__1)) + (r__2 = r_imag(&x) + , dabs(r__2)); + s = dmax(r__3,r__4); + q__5.r = x.r / s, q__5.i = x.i / s; + pow_ci(&q__4, &q__5, &c__2); + q__7.r = u.r / s, q__7.i = u.i / s; + pow_ci(&q__6, &q__7, &c__2); + q__3.r = q__4.r + q__6.r, q__3.i = q__4.i + q__6.i; + c_sqrt(&q__2, &q__3); + q__1.r = s * q__2.r, q__1.i = s * q__2.i; + y.r = q__1.r, y.i = q__1.i; + if (sx > 0.f) { + q__1.r = x.r / sx, q__1.i = x.i / sx; + q__2.r = x.r / sx, q__2.i = x.i / sx; + if (q__1.r * y.r + r_imag(&q__2) * r_imag(&y) < 0.f) { + q__3.r = -y.r, q__3.i = -y.i; + y.r = q__3.r, y.i = q__3.i; + } + } + q__4.r = x.r + y.r, q__4.i = x.i + y.i; + cladiv_(&q__3, &u, &q__4); + q__2.r = u.r * q__3.r - u.i * q__3.i, q__2.i = u.r * q__3.i + + u.i * q__3.r; + q__1.r = t.r - q__2.r, q__1.i = t.i - q__2.i; + t.r = q__1.r, t.i = q__1.i; + } + } + +/* Look for two consecutive small subdiagonal elements. */ + + i__1 = l + 1; + for (m = i__ - 1; m >= i__1; --m) { + +/* + Determine the effect of starting the single-shift QR + iteration at row M, and see if this would make H(M,M-1) + negligible. +*/ + + i__2 = m + m * h_dim1; + h11.r = h__[i__2].r, h11.i = h__[i__2].i; + i__2 = m + 1 + (m + 1) * h_dim1; + h22.r = h__[i__2].r, h22.i = h__[i__2].i; + q__1.r = h11.r - t.r, q__1.i = h11.i - t.i; + h11s.r = q__1.r, h11s.i = q__1.i; + i__2 = m + 1 + m * h_dim1; + h21 = h__[i__2].r; + s = (r__1 = h11s.r, dabs(r__1)) + (r__2 = r_imag(&h11s), dabs( + r__2)) + dabs(h21); + q__1.r = h11s.r / s, q__1.i = h11s.i / s; + h11s.r = q__1.r, h11s.i = q__1.i; + h21 /= s; + v[0].r = h11s.r, v[0].i = h11s.i; + v[1].r = h21, v[1].i = 0.f; + i__2 = m + (m - 1) * h_dim1; + h10 = h__[i__2].r; + if (dabs(h10) * dabs(h21) <= ulp * (((r__1 = h11s.r, dabs(r__1)) + + (r__2 = r_imag(&h11s), dabs(r__2))) * ((r__3 = h11.r, + dabs(r__3)) + (r__4 = r_imag(&h11), dabs(r__4)) + ((r__5 = + h22.r, dabs(r__5)) + (r__6 = r_imag(&h22), dabs(r__6))))) + ) { + goto L70; + } +/* L60: */ + } + i__1 = l + l * h_dim1; + h11.r = h__[i__1].r, h11.i = h__[i__1].i; + i__1 = l + 1 + (l + 1) * h_dim1; + h22.r = h__[i__1].r, h22.i = h__[i__1].i; + q__1.r = h11.r - t.r, q__1.i = h11.i - t.i; + h11s.r = q__1.r, h11s.i = q__1.i; + i__1 = l + 1 + l * h_dim1; + h21 = h__[i__1].r; + s = (r__1 = h11s.r, dabs(r__1)) + (r__2 = r_imag(&h11s), dabs(r__2)) + + dabs(h21); + q__1.r = h11s.r / s, q__1.i = h11s.i / s; + h11s.r = q__1.r, h11s.i = q__1.i; + h21 /= s; + v[0].r = h11s.r, v[0].i = h11s.i; + v[1].r = h21, v[1].i = 0.f; +L70: + +/* Single-shift QR step */ + + i__1 = i__ - 1; + for (k = m; k <= i__1; ++k) { + +/* + The first iteration of this loop determines a reflection G + from the vector V and applies it from left and right to H, + thus creating a nonzero bulge below the subdiagonal. + + Each subsequent iteration determines a reflection G to + restore the Hessenberg form in the (K-1)th column, and thus + chases the bulge one step toward the bottom of the active + submatrix. + + V(2) is always real before the call to CLARFG, and hence + after the call T2 ( = T1*V(2) ) is also real. +*/ + + if (k > m) { + ccopy_(&c__2, &h__[k + (k - 1) * h_dim1], &c__1, v, &c__1); + } + clarfg_(&c__2, v, &v[1], &c__1, &t1); + if (k > m) { + i__2 = k + (k - 1) * h_dim1; + h__[i__2].r = v[0].r, h__[i__2].i = v[0].i; + i__2 = k + 1 + (k - 1) * h_dim1; + h__[i__2].r = 0.f, h__[i__2].i = 0.f; + } + v2.r = v[1].r, v2.i = v[1].i; + q__1.r = t1.r * v2.r - t1.i * v2.i, q__1.i = t1.r * v2.i + t1.i * + v2.r; + t2 = q__1.r; + +/* + Apply G from the left to transform the rows of the matrix + in columns K to I2. +*/ + + i__2 = i2; + for (j = k; j <= i__2; ++j) { + r_cnjg(&q__3, &t1); + i__3 = k + j * h_dim1; + q__2.r = q__3.r * h__[i__3].r - q__3.i * h__[i__3].i, q__2.i = + q__3.r * h__[i__3].i + q__3.i * h__[i__3].r; + i__4 = k + 1 + j * h_dim1; + q__4.r = t2 * h__[i__4].r, q__4.i = t2 * h__[i__4].i; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + sum.r = q__1.r, sum.i = q__1.i; + i__3 = k + j * h_dim1; + i__4 = k + j * h_dim1; + q__1.r = h__[i__4].r - sum.r, q__1.i = h__[i__4].i - sum.i; + h__[i__3].r = q__1.r, h__[i__3].i = q__1.i; + i__3 = k + 1 + j * h_dim1; + i__4 = k + 1 + j * h_dim1; + q__2.r = sum.r * v2.r - sum.i * v2.i, q__2.i = sum.r * v2.i + + sum.i * v2.r; + q__1.r = h__[i__4].r - q__2.r, q__1.i = h__[i__4].i - q__2.i; + h__[i__3].r = q__1.r, h__[i__3].i = q__1.i; +/* L80: */ + } + +/* + Apply G from the right to transform the columns of the + matrix in rows I1 to min(K+2,I). + + Computing MIN +*/ + i__3 = k + 2; + i__2 = min(i__3,i__); + for (j = i1; j <= i__2; ++j) { + i__3 = j + k * h_dim1; + q__2.r = t1.r * h__[i__3].r - t1.i * h__[i__3].i, q__2.i = + t1.r * h__[i__3].i + t1.i * h__[i__3].r; + i__4 = j + (k + 1) * h_dim1; + q__3.r = t2 * h__[i__4].r, q__3.i = t2 * h__[i__4].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + sum.r = q__1.r, sum.i = q__1.i; + i__3 = j + k * h_dim1; + i__4 = j + k * h_dim1; + q__1.r = h__[i__4].r - sum.r, q__1.i = h__[i__4].i - sum.i; + h__[i__3].r = q__1.r, h__[i__3].i = q__1.i; + i__3 = j + (k + 1) * h_dim1; + i__4 = j + (k + 1) * h_dim1; + r_cnjg(&q__3, &v2); + q__2.r = sum.r * q__3.r - sum.i * q__3.i, q__2.i = sum.r * + q__3.i + sum.i * q__3.r; + q__1.r = h__[i__4].r - q__2.r, q__1.i = h__[i__4].i - q__2.i; + h__[i__3].r = q__1.r, h__[i__3].i = q__1.i; +/* L90: */ + } + + if (*wantz) { + +/* Accumulate transformations in the matrix Z */ + + i__2 = *ihiz; + for (j = *iloz; j <= i__2; ++j) { + i__3 = j + k * z_dim1; + q__2.r = t1.r * z__[i__3].r - t1.i * z__[i__3].i, q__2.i = + t1.r * z__[i__3].i + t1.i * z__[i__3].r; + i__4 = j + (k + 1) * z_dim1; + q__3.r = t2 * z__[i__4].r, q__3.i = t2 * z__[i__4].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + sum.r = q__1.r, sum.i = q__1.i; + i__3 = j + k * z_dim1; + i__4 = j + k * z_dim1; + q__1.r = z__[i__4].r - sum.r, q__1.i = z__[i__4].i - + sum.i; + z__[i__3].r = q__1.r, z__[i__3].i = q__1.i; + i__3 = j + (k + 1) * z_dim1; + i__4 = j + (k + 1) * z_dim1; + r_cnjg(&q__3, &v2); + q__2.r = sum.r * q__3.r - sum.i * q__3.i, q__2.i = sum.r * + q__3.i + sum.i * q__3.r; + q__1.r = z__[i__4].r - q__2.r, q__1.i = z__[i__4].i - + q__2.i; + z__[i__3].r = q__1.r, z__[i__3].i = q__1.i; +/* L100: */ + } + } + + if (k == m && m > l) { + +/* + If the QR step was started at row M > L because two + consecutive small subdiagonals were found, then extra + scaling must be performed to ensure that H(M,M-1) remains + real. +*/ + + q__1.r = 1.f - t1.r, q__1.i = 0.f - t1.i; + temp.r = q__1.r, temp.i = q__1.i; + r__1 = c_abs(&temp); + q__1.r = temp.r / r__1, q__1.i = temp.i / r__1; + temp.r = q__1.r, temp.i = q__1.i; + i__2 = m + 1 + m * h_dim1; + i__3 = m + 1 + m * h_dim1; + r_cnjg(&q__2, &temp); + q__1.r = h__[i__3].r * q__2.r - h__[i__3].i * q__2.i, q__1.i = + h__[i__3].r * q__2.i + h__[i__3].i * q__2.r; + h__[i__2].r = q__1.r, h__[i__2].i = q__1.i; + if (m + 2 <= i__) { + i__2 = m + 2 + (m + 1) * h_dim1; + i__3 = m + 2 + (m + 1) * h_dim1; + q__1.r = h__[i__3].r * temp.r - h__[i__3].i * temp.i, + q__1.i = h__[i__3].r * temp.i + h__[i__3].i * + temp.r; + h__[i__2].r = q__1.r, h__[i__2].i = q__1.i; + } + i__2 = i__; + for (j = m; j <= i__2; ++j) { + if (j != m + 1) { + if (i2 > j) { + i__3 = i2 - j; + cscal_(&i__3, &temp, &h__[j + (j + 1) * h_dim1], + ldh); + } + i__3 = j - i1; + r_cnjg(&q__1, &temp); + cscal_(&i__3, &q__1, &h__[i1 + j * h_dim1], &c__1); + if (*wantz) { + r_cnjg(&q__1, &temp); + cscal_(&nz, &q__1, &z__[*iloz + j * z_dim1], & + c__1); + } + } +/* L110: */ + } + } +/* L120: */ + } + +/* Ensure that H(I,I-1) is real. */ + + i__1 = i__ + (i__ - 1) * h_dim1; + temp.r = h__[i__1].r, temp.i = h__[i__1].i; + if (r_imag(&temp) != 0.f) { + rtemp = c_abs(&temp); + i__1 = i__ + (i__ - 1) * h_dim1; + h__[i__1].r = rtemp, h__[i__1].i = 0.f; + q__1.r = temp.r / rtemp, q__1.i = temp.i / rtemp; + temp.r = q__1.r, temp.i = q__1.i; + if (i2 > i__) { + i__1 = i2 - i__; + r_cnjg(&q__1, &temp); + cscal_(&i__1, &q__1, &h__[i__ + (i__ + 1) * h_dim1], ldh); + } + i__1 = i__ - i1; + cscal_(&i__1, &temp, &h__[i1 + i__ * h_dim1], &c__1); + if (*wantz) { + cscal_(&nz, &temp, &z__[*iloz + i__ * z_dim1], &c__1); + } + } + +/* L130: */ + } + +/* Failure to converge in remaining number of iterations */ + + *info = i__; + return 0; + +L140: + +/* H(I,I-1) is negligible: one eigenvalue has converged. */ + + i__1 = i__; + i__2 = i__ + i__ * h_dim1; + w[i__1].r = h__[i__2].r, w[i__1].i = h__[i__2].i; + +/* return to start of the main loop with new value of I. */ + + i__ = l - 1; + goto L30; + +L150: + return 0; + +/* End of CLAHQR */ + +} /* clahqr_ */ + +/* Subroutine */ int clahr2_(integer *n, integer *k, integer *nb, complex *a, + integer *lda, complex *tau, complex *t, integer *ldt, complex *y, + integer *ldy) +{ + /* System generated locals */ + integer a_dim1, a_offset, t_dim1, t_offset, y_dim1, y_offset, i__1, i__2, + i__3; + complex q__1; + + /* Local variables */ + static integer i__; + static complex ei; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *), cgemm_(char *, char *, integer *, integer *, integer * + , complex *, complex *, integer *, complex *, integer *, complex * + , complex *, integer *), cgemv_(char *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *), ccopy_(integer *, + complex *, integer *, complex *, integer *), ctrmm_(char *, char * + , char *, char *, integer *, integer *, complex *, complex *, + integer *, complex *, integer *), + caxpy_(integer *, complex *, complex *, integer *, complex *, + integer *), ctrmv_(char *, char *, char *, integer *, complex *, + integer *, complex *, integer *), clarfg_( + integer *, complex *, complex *, integer *, complex *), clacgv_( + integer *, complex *, integer *), clacpy_(char *, integer *, + integer *, complex *, integer *, complex *, integer *); + + +/* -- LAPACK auxiliary routine (version 3.2.1) -- */ +/* -- LAPACK is a software package provided by Univ. of Tennessee, --* -- April 2009 + -- */ +/* + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + CLAHR2 reduces the first NB columns of A complex general n-BY-(n-k+1) + matrix A so that elements below the k-th subdiagonal are zero. The + reduction is performed by an unitary similarity transformation + Q' * A * Q. The routine returns the matrices V and T which determine + Q as a block reflector I - V*T*V', and also the matrix Y = A * V * T. + + This is an auxiliary routine called by CGEHRD. + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. + + K (input) INTEGER + The offset for the reduction. Elements below the k-th + subdiagonal in the first NB columns are reduced to zero. + K < N. + + NB (input) INTEGER + The number of columns to be reduced. + + A (input/output) COMPLEX array, dimension (LDA,N-K+1) + On entry, the n-by-(n-k+1) general matrix A. + On exit, the elements on and above the k-th subdiagonal in + the first NB columns are overwritten with the corresponding + elements of the reduced matrix; the elements below the k-th + subdiagonal, with the array TAU, represent the matrix Q as a + product of elementary reflectors. The other columns of A are + unchanged. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) COMPLEX array, dimension (NB) + The scalar factors of the elementary reflectors. See Further + Details. + + T (output) COMPLEX array, dimension (LDT,NB) + The upper triangular matrix T. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= NB. + + Y (output) COMPLEX array, dimension (LDY,NB) + The n-by-nb matrix Y. + + LDY (input) INTEGER + The leading dimension of the array Y. LDY >= N. + + Further Details + =============== + + The matrix Q is represented as a product of nb elementary reflectors + + Q = H(1) H(2) . . . H(nb). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i+k-1) = 0, v(i+k) = 1; v(i+k+1:n) is stored on exit in + A(i+k+1:n,i), and tau in TAU(i). + + The elements of the vectors v together form the (n-k+1)-by-nb matrix + V which is needed, with T and Y, to apply the transformation to the + unreduced part of the matrix, using an update of the form: + A := (I - V*T*V') * (A - Y*V'). + + The contents of A on exit are illustrated by the following example + with n = 7, k = 3 and nb = 2: + + ( a a a a a ) + ( a a a a a ) + ( a a a a a ) + ( h h a a a ) + ( v1 h a a a ) + ( v1 v2 a a a ) + ( v1 v2 a a a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + This subroutine is a slight modification of LAPACK-3.0's DLAHRD + incorporating improvements proposed by Quintana-Orti and Van de + Gejin. Note that the entries of A(1:K,2:NB) differ from those + returned by the original LAPACK-3.0's DLAHRD routine. (This + subroutine is not backward compatible with LAPACK-3.0's DLAHRD.) + + References + ========== + + Gregorio Quintana-Orti and Robert van de Geijn, "Improving the + performance of reduction to Hessenberg form," ACM Transactions on + Mathematical Software, 32(2):180-194, June 2006. + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + --tau; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + y_dim1 = *ldy; + y_offset = 1 + y_dim1; + y -= y_offset; + + /* Function Body */ + if (*n <= 1) { + return 0; + } + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__ > 1) { + +/* + Update A(K+1:N,I) + + Update I-th column of A - Y * V' +*/ + + i__2 = i__ - 1; + clacgv_(&i__2, &a[*k + i__ - 1 + a_dim1], lda); + i__2 = *n - *k; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("NO TRANSPOSE", &i__2, &i__3, &q__1, &y[*k + 1 + y_dim1], + ldy, &a[*k + i__ - 1 + a_dim1], lda, &c_b57, &a[*k + 1 + + i__ * a_dim1], &c__1); + i__2 = i__ - 1; + clacgv_(&i__2, &a[*k + i__ - 1 + a_dim1], lda); + +/* + Apply I - V * T' * V' to this column (call it b) from the + left, using the last column of T as workspace + + Let V = ( V1 ) and b = ( b1 ) (first I-1 rows) + ( V2 ) ( b2 ) + + where V1 is unit lower triangular + + w := V1' * b1 +*/ + + i__2 = i__ - 1; + ccopy_(&i__2, &a[*k + 1 + i__ * a_dim1], &c__1, &t[*nb * t_dim1 + + 1], &c__1); + i__2 = i__ - 1; + ctrmv_("Lower", "Conjugate transpose", "UNIT", &i__2, &a[*k + 1 + + a_dim1], lda, &t[*nb * t_dim1 + 1], &c__1); + +/* w := w + V2'*b2 */ + + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[*k + i__ + + a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b57, + &t[*nb * t_dim1 + 1], &c__1); + +/* w := T'*w */ + + i__2 = i__ - 1; + ctrmv_("Upper", "Conjugate transpose", "NON-UNIT", &i__2, &t[ + t_offset], ldt, &t[*nb * t_dim1 + 1], &c__1); + +/* b2 := b2 - V2*w */ + + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("NO TRANSPOSE", &i__2, &i__3, &q__1, &a[*k + i__ + a_dim1], + lda, &t[*nb * t_dim1 + 1], &c__1, &c_b57, &a[*k + i__ + + i__ * a_dim1], &c__1); + +/* b1 := b1 - V1*w */ + + i__2 = i__ - 1; + ctrmv_("Lower", "NO TRANSPOSE", "UNIT", &i__2, &a[*k + 1 + a_dim1] + , lda, &t[*nb * t_dim1 + 1], &c__1); + i__2 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + caxpy_(&i__2, &q__1, &t[*nb * t_dim1 + 1], &c__1, &a[*k + 1 + i__ + * a_dim1], &c__1); + + i__2 = *k + i__ - 1 + (i__ - 1) * a_dim1; + a[i__2].r = ei.r, a[i__2].i = ei.i; + } + +/* + Generate the elementary reflector H(I) to annihilate + A(K+I+1:N,I) +*/ + + i__2 = *n - *k - i__ + 1; +/* Computing MIN */ + i__3 = *k + i__ + 1; + clarfg_(&i__2, &a[*k + i__ + i__ * a_dim1], &a[min(i__3,*n) + i__ * + a_dim1], &c__1, &tau[i__]); + i__2 = *k + i__ + i__ * a_dim1; + ei.r = a[i__2].r, ei.i = a[i__2].i; + i__2 = *k + i__ + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Compute Y(K+1:N,I) */ + + i__2 = *n - *k; + i__3 = *n - *k - i__ + 1; + cgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b57, &a[*k + 1 + (i__ + 1) * + a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b56, &y[* + k + 1 + i__ * y_dim1], &c__1); + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[*k + i__ + + a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b56, &t[ + i__ * t_dim1 + 1], &c__1); + i__2 = *n - *k; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("NO TRANSPOSE", &i__2, &i__3, &q__1, &y[*k + 1 + y_dim1], ldy, + &t[i__ * t_dim1 + 1], &c__1, &c_b57, &y[*k + 1 + i__ * y_dim1] + , &c__1); + i__2 = *n - *k; + cscal_(&i__2, &tau[i__], &y[*k + 1 + i__ * y_dim1], &c__1); + +/* Compute T(1:I,I) */ + + i__2 = i__ - 1; + i__3 = i__; + q__1.r = -tau[i__3].r, q__1.i = -tau[i__3].i; + cscal_(&i__2, &q__1, &t[i__ * t_dim1 + 1], &c__1); + i__2 = i__ - 1; + ctrmv_("Upper", "No Transpose", "NON-UNIT", &i__2, &t[t_offset], ldt, + &t[i__ * t_dim1 + 1], &c__1) + ; + i__2 = i__ + i__ * t_dim1; + i__3 = i__; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + +/* L10: */ + } + i__1 = *k + *nb + *nb * a_dim1; + a[i__1].r = ei.r, a[i__1].i = ei.i; + +/* Compute Y(1:K,1:NB) */ + + clacpy_("ALL", k, nb, &a[(a_dim1 << 1) + 1], lda, &y[y_offset], ldy); + ctrmm_("RIGHT", "Lower", "NO TRANSPOSE", "UNIT", k, nb, &c_b57, &a[*k + 1 + + a_dim1], lda, &y[y_offset], ldy); + if (*n > *k + *nb) { + i__1 = *n - *k - *nb; + cgemm_("NO TRANSPOSE", "NO TRANSPOSE", k, nb, &i__1, &c_b57, &a[(*nb + + 2) * a_dim1 + 1], lda, &a[*k + 1 + *nb + a_dim1], lda, & + c_b57, &y[y_offset], ldy); + } + ctrmm_("RIGHT", "Upper", "NO TRANSPOSE", "NON-UNIT", k, nb, &c_b57, &t[ + t_offset], ldt, &y[y_offset], ldy); + + return 0; + +/* End of CLAHR2 */ + +} /* clahr2_ */ + +doublereal clange_(char *norm, integer *m, integer *n, complex *a, integer * + lda, real *work) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real ret_val, r__1, r__2; + + /* Local variables */ + static integer i__, j; + static real sum, scale; + extern logical lsame_(char *, char *); + static real value; + extern /* Subroutine */ int classq_(integer *, complex *, integer *, real + *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLANGE returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + complex matrix A. + + Description + =========== + + CLANGE returns the value + + CLANGE = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in CLANGE as described + above. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. When M = 0, + CLANGE is set to zero. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. When N = 0, + CLANGE is set to zero. + + A (input) COMPLEX array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(M,1). + + WORK (workspace) REAL array, dimension (MAX(1,LWORK)), + where LWORK >= M when NORM = 'I'; otherwise, WORK is not + referenced. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (min(*m,*n) == 0) { + value = 0.f; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + value = 0.f; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + r__1 = value, r__2 = c_abs(&a[i__ + j * a_dim1]); + value = dmax(r__1,r__2); +/* L10: */ + } +/* L20: */ + } + } else if (lsame_(norm, "O") || *(unsigned char *) + norm == '1') { + +/* Find norm1(A). */ + + value = 0.f; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = 0.f; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + sum += c_abs(&a[i__ + j * a_dim1]); +/* L30: */ + } + value = dmax(value,sum); +/* L40: */ + } + } else if (lsame_(norm, "I")) { + +/* Find normI(A). */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.f; +/* L50: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] += c_abs(&a[i__ + j * a_dim1]); +/* L60: */ + } +/* L70: */ + } + value = 0.f; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__1 = value, r__2 = work[i__]; + value = dmax(r__1,r__2); +/* L80: */ + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.f; + sum = 1.f; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + classq_(m, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L90: */ + } + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of CLANGE */ + +} /* clange_ */ + +doublereal clanhe_(char *norm, char *uplo, integer *n, complex *a, integer * + lda, real *work) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real ret_val, r__1, r__2, r__3; + + /* Local variables */ + static integer i__, j; + static real sum, absa, scale; + extern logical lsame_(char *, char *); + static real value; + extern /* Subroutine */ int classq_(integer *, complex *, integer *, real + *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLANHE returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + complex hermitian matrix A. + + Description + =========== + + CLANHE returns the value + + CLANHE = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in CLANHE as described + above. + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + hermitian matrix A is to be referenced. + = 'U': Upper triangular part of A is referenced + = 'L': Lower triangular part of A is referenced + + N (input) INTEGER + The order of the matrix A. N >= 0. When N = 0, CLANHE is + set to zero. + + A (input) COMPLEX array, dimension (LDA,N) + The hermitian matrix A. If UPLO = 'U', the leading n by n + upper triangular part of A contains the upper triangular part + of the matrix A, and the strictly lower triangular part of A + is not referenced. If UPLO = 'L', the leading n by n lower + triangular part of A contains the lower triangular part of + the matrix A, and the strictly upper triangular part of A is + not referenced. Note that the imaginary parts of the diagonal + elements need not be set and are assumed to be zero. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(N,1). + + WORK (workspace) REAL array, dimension (MAX(1,LWORK)), + where LWORK >= N when NORM = 'I' or '1' or 'O'; otherwise, + WORK is not referenced. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (*n == 0) { + value = 0.f; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + value = 0.f; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + r__1 = value, r__2 = c_abs(&a[i__ + j * a_dim1]); + value = dmax(r__1,r__2); +/* L10: */ + } +/* Computing MAX */ + i__2 = j + j * a_dim1; + r__2 = value, r__3 = (r__1 = a[i__2].r, dabs(r__1)); + value = dmax(r__2,r__3); +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = j + j * a_dim1; + r__2 = value, r__3 = (r__1 = a[i__2].r, dabs(r__1)); + value = dmax(r__2,r__3); + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + r__1 = value, r__2 = c_abs(&a[i__ + j * a_dim1]); + value = dmax(r__1,r__2); +/* L30: */ + } +/* L40: */ + } + } + } else if (lsame_(norm, "I") || lsame_(norm, "O") || *(unsigned char *)norm == '1') { + +/* Find normI(A) ( = norm1(A), since A is hermitian). */ + + value = 0.f; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = 0.f; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + absa = c_abs(&a[i__ + j * a_dim1]); + sum += absa; + work[i__] += absa; +/* L50: */ + } + i__2 = j + j * a_dim1; + work[j] = sum + (r__1 = a[i__2].r, dabs(r__1)); +/* L60: */ + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__1 = value, r__2 = work[i__]; + value = dmax(r__1,r__2); +/* L70: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.f; +/* L80: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j + j * a_dim1; + sum = work[j] + (r__1 = a[i__2].r, dabs(r__1)); + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + absa = c_abs(&a[i__ + j * a_dim1]); + sum += absa; + work[i__] += absa; +/* L90: */ + } + value = dmax(value,sum); +/* L100: */ + } + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.f; + sum = 1.f; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + i__2 = j - 1; + classq_(&i__2, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L110: */ + } + } else { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = *n - j; + classq_(&i__2, &a[j + 1 + j * a_dim1], &c__1, &scale, &sum); +/* L120: */ + } + } + sum *= 2; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + if (a[i__2].r != 0.f) { + i__2 = i__ + i__ * a_dim1; + absa = (r__1 = a[i__2].r, dabs(r__1)); + if (scale < absa) { +/* Computing 2nd power */ + r__1 = scale / absa; + sum = sum * (r__1 * r__1) + 1.f; + scale = absa; + } else { +/* Computing 2nd power */ + r__1 = absa / scale; + sum += r__1 * r__1; + } + } +/* L130: */ + } + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of CLANHE */ + +} /* clanhe_ */ + +/* Subroutine */ int claqr0_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *w, + integer *iloz, integer *ihiz, complex *z__, integer *ldz, complex * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5; + real r__1, r__2, r__3, r__4, r__5, r__6, r__7, r__8; + complex q__1, q__2, q__3, q__4, q__5; + + /* Local variables */ + static integer i__, k; + static real s; + static complex aa, bb, cc, dd; + static integer ld, nh, it, ks, kt, ku, kv, ls, ns, nw; + static complex tr2, det; + static integer inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, kbot, + nmin; + static complex swap; + static integer ktop; + static complex zdum[1] /* was [1][1] */; + static integer kacc22, itmax, nsmax, nwmax, kwtop; + extern /* Subroutine */ int claqr3_(logical *, logical *, integer *, + integer *, integer *, integer *, complex *, integer *, integer *, + integer *, complex *, integer *, integer *, integer *, complex *, + complex *, integer *, integer *, complex *, integer *, integer *, + complex *, integer *, complex *, integer *), claqr4_(logical *, + logical *, integer *, integer *, integer *, complex *, integer *, + complex *, integer *, integer *, complex *, integer *, complex *, + integer *, integer *), claqr5_(logical *, logical *, integer *, + integer *, integer *, integer *, integer *, complex *, complex *, + integer *, integer *, integer *, complex *, integer *, complex *, + integer *, complex *, integer *, integer *, complex *, integer *, + integer *, complex *, integer *); + static integer nibble; + extern /* Subroutine */ int clahqr_(logical *, logical *, integer *, + integer *, integer *, complex *, integer *, complex *, integer *, + integer *, complex *, integer *, integer *), clacpy_(char *, + integer *, integer *, complex *, integer *, complex *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static char jbcmpz[2]; + static complex rtdisc; + static integer nwupbd; + static logical sorted; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Purpose + ======= + + CLAQR0 computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**H, where T is an upper triangular matrix (the + Schur form), and Z is the unitary matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input unitary + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the unitary matrix Q: A = Q*H*Q**H = (QZ)*H*(QZ)**H. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1, + H(ILO,ILO-1) is zero. ILO and IHI are normally set by a + previous call to CGEBAL, and then passed to CGEHRD when the + matrix output by CGEBAL is reduced to Hessenberg form. + Otherwise, ILO and IHI should be set to 1 and N, + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) COMPLEX array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and WANTT is .TRUE., then H + contains the upper triangular matrix T from the Schur + decomposition (the Schur form). If INFO = 0 and WANT is + .FALSE., then the contents of H are unspecified on exit. + (The output value of H when INFO.GT.0 is given under the + description of INFO below.) + + This subroutine may explicitly set H(i,j) = 0 for i.GT.j and + j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + W (output) COMPLEX array, dimension (N) + The computed eigenvalues of H(ILO:IHI,ILO:IHI) are stored + in W(ILO:IHI). If WANTT is .TRUE., then the eigenvalues are + stored in the same order as on the diagonal of the Schur + form returned in H, with W(i) = H(i,i). + + Z (input/output) COMPLEX array, dimension (LDZ,IHI) + If WANTZ is .FALSE., then Z is not referenced. + If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is + replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the + orthogonal Schur factor of H(ILO:IHI,ILO:IHI). + (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if WANTZ is .TRUE. + then LDZ.GE.MAX(1,IHIZ). Otherwize, LDZ.GE.1. + + WORK (workspace/output) COMPLEX array, dimension LWORK + On exit, if LWORK = -1, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient, but LWORK typically as large as 6*N may + be required for optimal performance. A workspace query + to determine the optimal workspace size is recommended. + + If LWORK = -1, then CLAQR0 does a workspace query. + In this case, CLAQR0 checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, CLAQR0 failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and WANT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is a unitary matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + + (final value of Z(ILO:IHI,ILOZ:IHIZ) + = (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U + + where U is the unitary matrix in (*) (regard- + less of the value of WANTT.) + + If INFO .GT. 0 and WANTZ is .FALSE., then Z is not + accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . CLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== Exceptional deflation windows: try to cure rare + . slow convergence by varying the size of the + . deflation window after KEXNW iterations. ==== + + ==== Exceptional shifts: try to cure rare slow convergence + . with ad-hoc exceptional shifts every KEXSH iterations. + . ==== + + ==== The constant WILK1 is used to form the exceptional + . shifts. ==== +*/ + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --w; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + +/* ==== Quick return for N = 0: nothing to do. ==== */ + + if (*n == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + if (*n <= 11) { + +/* ==== Tiny matrices must use CLAHQR. ==== */ + + lwkopt = 1; + if (*lwork != -1) { + clahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], + iloz, ihiz, &z__[z_offset], ldz, info); + } + } else { + +/* + ==== Use small bulge multi-shift QR with aggressive early + . deflation on larger-than-tiny matrices. ==== + + ==== Hope for the best. ==== +*/ + + *info = 0; + +/* ==== Set up job flags for ILAENV. ==== */ + + if (*wantt) { + *(unsigned char *)jbcmpz = 'S'; + } else { + *(unsigned char *)jbcmpz = 'E'; + } + if (*wantz) { + *(unsigned char *)&jbcmpz[1] = 'V'; + } else { + *(unsigned char *)&jbcmpz[1] = 'N'; + } + +/* + ==== NWR = recommended deflation window size. At this + . point, N .GT. NTINY = 11, so there is enough + . subdiagonal workspace for NWR.GE.2 as required. + . (In fact, there is enough subdiagonal space for + . NWR.GE.3.) ==== +*/ + + nwr = ilaenv_(&c__13, "CLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nwr = max(2,nwr); +/* Computing MIN */ + i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2); + nwr = min(i__1,nwr); + +/* + ==== NSR = recommended number of simultaneous shifts. + . At this point N .GT. NTINY = 11, so there is at + . enough subdiagonal workspace for NSR to be even + . and greater than or equal to two as required. ==== +*/ + + nsr = ilaenv_(&c__15, "CLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); +/* Computing MIN */ + i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - + *ilo; + nsr = min(i__1,i__2); +/* Computing MAX */ + i__1 = 2, i__2 = nsr - nsr % 2; + nsr = max(i__1,i__2); + +/* + ==== Estimate optimal workspace ==== + + ==== Workspace query call to CLAQR3 ==== +*/ + + i__1 = nwr + 1; + claqr3_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, + ihiz, &z__[z_offset], ldz, &ls, &ld, &w[1], &h__[h_offset], + ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], ldh, &work[1], + &c_n1); + +/* + ==== Optimal workspace = MAX(CLAQR5, CLAQR3) ==== + + Computing MAX +*/ + i__1 = nsr * 3 / 2, i__2 = (integer) work[1].r; + lwkopt = max(i__1,i__2); + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + r__1 = (real) lwkopt; + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + return 0; + } + +/* ==== CLAHQR/CLAQR0 crossover point ==== */ + + nmin = ilaenv_(&c__12, "CLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen) + 6, (ftnlen)2); + nmin = max(11,nmin); + +/* ==== Nibble crossover point ==== */ + + nibble = ilaenv_(&c__14, "CLAQR0", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + nibble = max(0,nibble); + +/* + ==== Accumulate reflections during ttswp? Use block + . 2-by-2 structure during matrix-matrix multiply? ==== +*/ + + kacc22 = ilaenv_(&c__16, "CLAQR0", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + kacc22 = max(0,kacc22); + kacc22 = min(2,kacc22); + +/* + ==== NWMAX = the largest possible deflation window for + . which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n - 1) / 3, i__2 = *lwork / 2; + nwmax = min(i__1,i__2); + nw = nwmax; + +/* + ==== NSMAX = the Largest number of simultaneous shifts + . for which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3; + nsmax = min(i__1,i__2); + nsmax -= nsmax % 2; + +/* ==== NDFL: an iteration count restarted at deflation. ==== */ + + ndfl = 1; + +/* + ==== ITMAX = iteration limit ==== + + Computing MAX +*/ + i__1 = 10, i__2 = *ihi - *ilo + 1; + itmax = max(i__1,i__2) * 30; + +/* ==== Last row and column in the active block ==== */ + + kbot = *ihi; + +/* ==== Main Loop ==== */ + + i__1 = itmax; + for (it = 1; it <= i__1; ++it) { + +/* ==== Done when KBOT falls below ILO ==== */ + + if (kbot < *ilo) { + goto L80; + } + +/* ==== Locate active block ==== */ + + i__2 = *ilo + 1; + for (k = kbot; k >= i__2; --k) { + i__3 = k + (k - 1) * h_dim1; + if (h__[i__3].r == 0.f && h__[i__3].i == 0.f) { + goto L20; + } +/* L10: */ + } + k = *ilo; +L20: + ktop = k; + +/* + ==== Select deflation window size: + . Typical Case: + . If possible and advisable, nibble the entire + . active block. If not, use size MIN(NWR,NWMAX) + . or MIN(NWR+1,NWMAX) depending upon which has + . the smaller corresponding subdiagonal entry + . (a heuristic). + . + . Exceptional Case: + . If there have been no deflations in KEXNW or + . more iterations, then vary the deflation window + . size. At first, because, larger windows are, + . in general, more powerful than smaller ones, + . rapidly increase the window to the maximum possible. + . Then, gradually reduce the window size. ==== +*/ + + nh = kbot - ktop + 1; + nwupbd = min(nh,nwmax); + if (ndfl < 5) { + nw = min(nwupbd,nwr); + } else { +/* Computing MIN */ + i__2 = nwupbd, i__3 = nw << 1; + nw = min(i__2,i__3); + } + if (nw < nwmax) { + if (nw >= nh - 1) { + nw = nh; + } else { + kwtop = kbot - nw + 1; + i__2 = kwtop + (kwtop - 1) * h_dim1; + i__3 = kwtop - 1 + (kwtop - 2) * h_dim1; + if ((r__1 = h__[i__2].r, dabs(r__1)) + (r__2 = r_imag(& + h__[kwtop + (kwtop - 1) * h_dim1]), dabs(r__2)) > + (r__3 = h__[i__3].r, dabs(r__3)) + (r__4 = r_imag( + &h__[kwtop - 1 + (kwtop - 2) * h_dim1]), dabs( + r__4))) { + ++nw; + } + } + } + if (ndfl < 5) { + ndec = -1; + } else if (ndec >= 0 || nw >= nwupbd) { + ++ndec; + if (nw - ndec < 2) { + ndec = 0; + } + nw -= ndec; + } + +/* + ==== Aggressive early deflation: + . split workspace under the subdiagonal into + . - an nw-by-nw work array V in the lower + . left-hand-corner, + . - an NW-by-at-least-NW-but-more-is-better + . (NW-by-NHO) horizontal work array along + . the bottom edge, + . - an at-least-NW-but-more-is-better (NHV-by-NW) + . vertical work array along the left-hand-edge. + . ==== +*/ + + kv = *n - nw + 1; + kt = nw + 1; + nho = *n - nw - 1 - kt + 1; + kwv = nw + 2; + nve = *n - nw - kwv + 1; + +/* ==== Aggressive early deflation ==== */ + + claqr3_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, + iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &w[1], &h__[kv + + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], ldh, &nve, & + h__[kwv + h_dim1], ldh, &work[1], lwork); + +/* ==== Adjust KBOT accounting for new deflations. ==== */ + + kbot -= ld; + +/* ==== KS points to the shifts. ==== */ + + ks = kbot - ls + 1; + +/* + ==== Skip an expensive QR sweep if there is a (partly + . heuristic) reason to expect that many eigenvalues + . will deflate without it. Here, the QR sweep is + . skipped if many eigenvalues have just been deflated + . or if the remaining active block is small. +*/ + + if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min( + nmin,nwmax)) { + +/* + ==== NS = nominal number of simultaneous shifts. + . This may be lowered (slightly) if CLAQR3 + . did not provide that many shifts. ==== + + Computing MIN + Computing MAX +*/ + i__4 = 2, i__5 = kbot - ktop; + i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5); + ns = min(i__2,i__3); + ns -= ns % 2; + +/* + ==== If there have been no deflations + . in a multiple of KEXSH iterations, + . then try exceptional shifts. + . Otherwise use shifts provided by + . CLAQR3 above or from the eigenvalues + . of a trailing principal submatrix. ==== +*/ + + if (ndfl % 6 == 0) { + ks = kbot - ns + 1; + i__2 = ks + 1; + for (i__ = kbot; i__ >= i__2; i__ += -2) { + i__3 = i__; + i__4 = i__ + i__ * h_dim1; + i__5 = i__ + (i__ - 1) * h_dim1; + r__3 = ((r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[i__ + (i__ - 1) * h_dim1]), dabs( + r__2))) * .75f; + q__1.r = h__[i__4].r + r__3, q__1.i = h__[i__4].i; + w[i__3].r = q__1.r, w[i__3].i = q__1.i; + i__3 = i__ - 1; + i__4 = i__; + w[i__3].r = w[i__4].r, w[i__3].i = w[i__4].i; +/* L30: */ + } + } else { + +/* + ==== Got NS/2 or fewer shifts? Use CLAQR4 or + . CLAHQR on a trailing principal submatrix to + . get more. (Since NS.LE.NSMAX.LE.(N+6)/9, + . there is enough space below the subdiagonal + . to fit an NS-by-NS scratch array.) ==== +*/ + + if (kbot - ks + 1 <= ns / 2) { + ks = kbot - ns + 1; + kt = *n - ns + 1; + clacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, & + h__[kt + h_dim1], ldh); + if (ns > nmin) { + claqr4_(&c_false, &c_false, &ns, &c__1, &ns, &h__[ + kt + h_dim1], ldh, &w[ks], &c__1, &c__1, + zdum, &c__1, &work[1], lwork, &inf); + } else { + clahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[ + kt + h_dim1], ldh, &w[ks], &c__1, &c__1, + zdum, &c__1, &inf); + } + ks += inf; + +/* + ==== In case of a rare QR failure use + . eigenvalues of the trailing 2-by-2 + . principal submatrix. Scale to avoid + . overflows, underflows and subnormals. + . (The scale factor S can not be zero, + . because H(KBOT,KBOT-1) is nonzero.) ==== +*/ + + if (ks >= kbot) { + i__2 = kbot - 1 + (kbot - 1) * h_dim1; + i__3 = kbot + (kbot - 1) * h_dim1; + i__4 = kbot - 1 + kbot * h_dim1; + i__5 = kbot + kbot * h_dim1; + s = (r__1 = h__[i__2].r, dabs(r__1)) + (r__2 = + r_imag(&h__[kbot - 1 + (kbot - 1) * + h_dim1]), dabs(r__2)) + ((r__3 = h__[i__3] + .r, dabs(r__3)) + (r__4 = r_imag(&h__[ + kbot + (kbot - 1) * h_dim1]), dabs(r__4))) + + ((r__5 = h__[i__4].r, dabs(r__5)) + ( + r__6 = r_imag(&h__[kbot - 1 + kbot * + h_dim1]), dabs(r__6))) + ((r__7 = h__[ + i__5].r, dabs(r__7)) + (r__8 = r_imag(& + h__[kbot + kbot * h_dim1]), dabs(r__8))); + i__2 = kbot - 1 + (kbot - 1) * h_dim1; + q__1.r = h__[i__2].r / s, q__1.i = h__[i__2].i / + s; + aa.r = q__1.r, aa.i = q__1.i; + i__2 = kbot + (kbot - 1) * h_dim1; + q__1.r = h__[i__2].r / s, q__1.i = h__[i__2].i / + s; + cc.r = q__1.r, cc.i = q__1.i; + i__2 = kbot - 1 + kbot * h_dim1; + q__1.r = h__[i__2].r / s, q__1.i = h__[i__2].i / + s; + bb.r = q__1.r, bb.i = q__1.i; + i__2 = kbot + kbot * h_dim1; + q__1.r = h__[i__2].r / s, q__1.i = h__[i__2].i / + s; + dd.r = q__1.r, dd.i = q__1.i; + q__2.r = aa.r + dd.r, q__2.i = aa.i + dd.i; + q__1.r = q__2.r / 2.f, q__1.i = q__2.i / 2.f; + tr2.r = q__1.r, tr2.i = q__1.i; + q__3.r = aa.r - tr2.r, q__3.i = aa.i - tr2.i; + q__4.r = dd.r - tr2.r, q__4.i = dd.i - tr2.i; + q__2.r = q__3.r * q__4.r - q__3.i * q__4.i, + q__2.i = q__3.r * q__4.i + q__3.i * + q__4.r; + q__5.r = bb.r * cc.r - bb.i * cc.i, q__5.i = bb.r + * cc.i + bb.i * cc.r; + q__1.r = q__2.r - q__5.r, q__1.i = q__2.i - + q__5.i; + det.r = q__1.r, det.i = q__1.i; + q__2.r = -det.r, q__2.i = -det.i; + c_sqrt(&q__1, &q__2); + rtdisc.r = q__1.r, rtdisc.i = q__1.i; + i__2 = kbot - 1; + q__2.r = tr2.r + rtdisc.r, q__2.i = tr2.i + + rtdisc.i; + q__1.r = s * q__2.r, q__1.i = s * q__2.i; + w[i__2].r = q__1.r, w[i__2].i = q__1.i; + i__2 = kbot; + q__2.r = tr2.r - rtdisc.r, q__2.i = tr2.i - + rtdisc.i; + q__1.r = s * q__2.r, q__1.i = s * q__2.i; + w[i__2].r = q__1.r, w[i__2].i = q__1.i; + + ks = kbot - 1; + } + } + + if (kbot - ks + 1 > ns) { + +/* ==== Sort the shifts (Helps a little) ==== */ + + sorted = FALSE_; + i__2 = ks + 1; + for (k = kbot; k >= i__2; --k) { + if (sorted) { + goto L60; + } + sorted = TRUE_; + i__3 = k - 1; + for (i__ = ks; i__ <= i__3; ++i__) { + i__4 = i__; + i__5 = i__ + 1; + if ((r__1 = w[i__4].r, dabs(r__1)) + (r__2 = + r_imag(&w[i__]), dabs(r__2)) < (r__3 = + w[i__5].r, dabs(r__3)) + (r__4 = + r_imag(&w[i__ + 1]), dabs(r__4))) { + sorted = FALSE_; + i__4 = i__; + swap.r = w[i__4].r, swap.i = w[i__4].i; + i__4 = i__; + i__5 = i__ + 1; + w[i__4].r = w[i__5].r, w[i__4].i = w[i__5] + .i; + i__4 = i__ + 1; + w[i__4].r = swap.r, w[i__4].i = swap.i; + } +/* L40: */ + } +/* L50: */ + } +L60: + ; + } + } + +/* + ==== If there are only two shifts, then use + . only one. ==== +*/ + + if (kbot - ks + 1 == 2) { + i__2 = kbot; + i__3 = kbot + kbot * h_dim1; + q__2.r = w[i__2].r - h__[i__3].r, q__2.i = w[i__2].i - + h__[i__3].i; + q__1.r = q__2.r, q__1.i = q__2.i; + i__4 = kbot - 1; + i__5 = kbot + kbot * h_dim1; + q__4.r = w[i__4].r - h__[i__5].r, q__4.i = w[i__4].i - + h__[i__5].i; + q__3.r = q__4.r, q__3.i = q__4.i; + if ((r__1 = q__1.r, dabs(r__1)) + (r__2 = r_imag(&q__1), + dabs(r__2)) < (r__3 = q__3.r, dabs(r__3)) + (r__4 + = r_imag(&q__3), dabs(r__4))) { + i__2 = kbot - 1; + i__3 = kbot; + w[i__2].r = w[i__3].r, w[i__2].i = w[i__3].i; + } else { + i__2 = kbot; + i__3 = kbot - 1; + w[i__2].r = w[i__3].r, w[i__2].i = w[i__3].i; + } + } + +/* + ==== Use up to NS of the the smallest magnatiude + . shifts. If there aren't NS shifts available, + . then use them all, possibly dropping one to + . make the number of shifts even. ==== + + Computing MIN +*/ + i__2 = ns, i__3 = kbot - ks + 1; + ns = min(i__2,i__3); + ns -= ns % 2; + ks = kbot - ns + 1; + +/* + ==== Small-bulge multi-shift QR sweep: + . split workspace under the subdiagonal into + . - a KDU-by-KDU work array U in the lower + . left-hand-corner, + . - a KDU-by-at-least-KDU-but-more-is-better + . (KDU-by-NHo) horizontal work array WH along + . the bottom edge, + . - and an at-least-KDU-but-more-is-better-by-KDU + . (NVE-by-KDU) vertical work WV arrow along + . the left-hand-edge. ==== +*/ + + kdu = ns * 3 - 3; + ku = *n - kdu + 1; + kwh = kdu + 1; + nho = *n - kdu - 3 - (kdu + 1) + 1; + kwv = kdu + 4; + nve = *n - kdu - kwv + 1; + +/* ==== Small-bulge multi-shift QR sweep ==== */ + + claqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &w[ks], & + h__[h_offset], ldh, iloz, ihiz, &z__[z_offset], ldz, & + work[1], &c__3, &h__[ku + h_dim1], ldh, &nve, &h__[ + kwv + h_dim1], ldh, &nho, &h__[ku + kwh * h_dim1], + ldh); + } + +/* ==== Note progress (or the lack of it). ==== */ + + if (ld > 0) { + ndfl = 1; + } else { + ++ndfl; + } + +/* + ==== End of main loop ==== + L70: +*/ + } + +/* + ==== Iteration limit exceeded. Set INFO to show where + . the problem occurred and exit. ==== +*/ + + *info = kbot; +L80: + ; + } + +/* ==== Return the optimal value of LWORK. ==== */ + + r__1 = (real) lwkopt; + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + +/* ==== End of CLAQR0 ==== */ + + return 0; +} /* claqr0_ */ + +/* Subroutine */ int claqr1_(integer *n, complex *h__, integer *ldh, complex * + s1, complex *s2, complex *v) +{ + /* System generated locals */ + integer h_dim1, h_offset, i__1, i__2, i__3, i__4; + real r__1, r__2, r__3, r__4, r__5, r__6; + complex q__1, q__2, q__3, q__4, q__5, q__6, q__7, q__8; + + /* Local variables */ + static real s; + static complex h21s, h31s; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Given a 2-by-2 or 3-by-3 matrix H, CLAQR1 sets v to a + scalar multiple of the first column of the product + + (*) K = (H - s1*I)*(H - s2*I) + + scaling to avoid overflows and most underflows. + + This is useful for starting double implicit shift bulges + in the QR algorithm. + + + N (input) integer + Order of the matrix H. N must be either 2 or 3. + + H (input) COMPLEX array of dimension (LDH,N) + The 2-by-2 or 3-by-3 matrix H in (*). + + LDH (input) integer + The leading dimension of H as declared in + the calling procedure. LDH.GE.N + + S1 (input) COMPLEX + S2 S1 and S2 are the shifts defining K in (*) above. + + V (output) COMPLEX array of dimension N + A scalar multiple of the first column of the + matrix K in (*). + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --v; + + /* Function Body */ + if (*n == 2) { + i__1 = h_dim1 + 1; + q__2.r = h__[i__1].r - s2->r, q__2.i = h__[i__1].i - s2->i; + q__1.r = q__2.r, q__1.i = q__2.i; + i__2 = h_dim1 + 2; + s = (r__1 = q__1.r, dabs(r__1)) + (r__2 = r_imag(&q__1), dabs(r__2)) + + ((r__3 = h__[i__2].r, dabs(r__3)) + (r__4 = r_imag(&h__[ + h_dim1 + 2]), dabs(r__4))); + if (s == 0.f) { + v[1].r = 0.f, v[1].i = 0.f; + v[2].r = 0.f, v[2].i = 0.f; + } else { + i__1 = h_dim1 + 2; + q__1.r = h__[i__1].r / s, q__1.i = h__[i__1].i / s; + h21s.r = q__1.r, h21s.i = q__1.i; + i__1 = (h_dim1 << 1) + 1; + q__2.r = h21s.r * h__[i__1].r - h21s.i * h__[i__1].i, q__2.i = + h21s.r * h__[i__1].i + h21s.i * h__[i__1].r; + i__2 = h_dim1 + 1; + q__4.r = h__[i__2].r - s1->r, q__4.i = h__[i__2].i - s1->i; + i__3 = h_dim1 + 1; + q__6.r = h__[i__3].r - s2->r, q__6.i = h__[i__3].i - s2->i; + q__5.r = q__6.r / s, q__5.i = q__6.i / s; + q__3.r = q__4.r * q__5.r - q__4.i * q__5.i, q__3.i = q__4.r * + q__5.i + q__4.i * q__5.r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + v[1].r = q__1.r, v[1].i = q__1.i; + i__1 = h_dim1 + 1; + i__2 = (h_dim1 << 1) + 2; + q__4.r = h__[i__1].r + h__[i__2].r, q__4.i = h__[i__1].i + h__[ + i__2].i; + q__3.r = q__4.r - s1->r, q__3.i = q__4.i - s1->i; + q__2.r = q__3.r - s2->r, q__2.i = q__3.i - s2->i; + q__1.r = h21s.r * q__2.r - h21s.i * q__2.i, q__1.i = h21s.r * + q__2.i + h21s.i * q__2.r; + v[2].r = q__1.r, v[2].i = q__1.i; + } + } else { + i__1 = h_dim1 + 1; + q__2.r = h__[i__1].r - s2->r, q__2.i = h__[i__1].i - s2->i; + q__1.r = q__2.r, q__1.i = q__2.i; + i__2 = h_dim1 + 2; + i__3 = h_dim1 + 3; + s = (r__1 = q__1.r, dabs(r__1)) + (r__2 = r_imag(&q__1), dabs(r__2)) + + ((r__3 = h__[i__2].r, dabs(r__3)) + (r__4 = r_imag(&h__[ + h_dim1 + 2]), dabs(r__4))) + ((r__5 = h__[i__3].r, dabs(r__5)) + + (r__6 = r_imag(&h__[h_dim1 + 3]), dabs(r__6))); + if (s == 0.f) { + v[1].r = 0.f, v[1].i = 0.f; + v[2].r = 0.f, v[2].i = 0.f; + v[3].r = 0.f, v[3].i = 0.f; + } else { + i__1 = h_dim1 + 2; + q__1.r = h__[i__1].r / s, q__1.i = h__[i__1].i / s; + h21s.r = q__1.r, h21s.i = q__1.i; + i__1 = h_dim1 + 3; + q__1.r = h__[i__1].r / s, q__1.i = h__[i__1].i / s; + h31s.r = q__1.r, h31s.i = q__1.i; + i__1 = h_dim1 + 1; + q__4.r = h__[i__1].r - s1->r, q__4.i = h__[i__1].i - s1->i; + i__2 = h_dim1 + 1; + q__6.r = h__[i__2].r - s2->r, q__6.i = h__[i__2].i - s2->i; + q__5.r = q__6.r / s, q__5.i = q__6.i / s; + q__3.r = q__4.r * q__5.r - q__4.i * q__5.i, q__3.i = q__4.r * + q__5.i + q__4.i * q__5.r; + i__3 = (h_dim1 << 1) + 1; + q__7.r = h__[i__3].r * h21s.r - h__[i__3].i * h21s.i, q__7.i = + h__[i__3].r * h21s.i + h__[i__3].i * h21s.r; + q__2.r = q__3.r + q__7.r, q__2.i = q__3.i + q__7.i; + i__4 = h_dim1 * 3 + 1; + q__8.r = h__[i__4].r * h31s.r - h__[i__4].i * h31s.i, q__8.i = + h__[i__4].r * h31s.i + h__[i__4].i * h31s.r; + q__1.r = q__2.r + q__8.r, q__1.i = q__2.i + q__8.i; + v[1].r = q__1.r, v[1].i = q__1.i; + i__1 = h_dim1 + 1; + i__2 = (h_dim1 << 1) + 2; + q__5.r = h__[i__1].r + h__[i__2].r, q__5.i = h__[i__1].i + h__[ + i__2].i; + q__4.r = q__5.r - s1->r, q__4.i = q__5.i - s1->i; + q__3.r = q__4.r - s2->r, q__3.i = q__4.i - s2->i; + q__2.r = h21s.r * q__3.r - h21s.i * q__3.i, q__2.i = h21s.r * + q__3.i + h21s.i * q__3.r; + i__3 = h_dim1 * 3 + 2; + q__6.r = h__[i__3].r * h31s.r - h__[i__3].i * h31s.i, q__6.i = + h__[i__3].r * h31s.i + h__[i__3].i * h31s.r; + q__1.r = q__2.r + q__6.r, q__1.i = q__2.i + q__6.i; + v[2].r = q__1.r, v[2].i = q__1.i; + i__1 = h_dim1 + 1; + i__2 = h_dim1 * 3 + 3; + q__5.r = h__[i__1].r + h__[i__2].r, q__5.i = h__[i__1].i + h__[ + i__2].i; + q__4.r = q__5.r - s1->r, q__4.i = q__5.i - s1->i; + q__3.r = q__4.r - s2->r, q__3.i = q__4.i - s2->i; + q__2.r = h31s.r * q__3.r - h31s.i * q__3.i, q__2.i = h31s.r * + q__3.i + h31s.i * q__3.r; + i__3 = (h_dim1 << 1) + 3; + q__6.r = h21s.r * h__[i__3].r - h21s.i * h__[i__3].i, q__6.i = + h21s.r * h__[i__3].i + h21s.i * h__[i__3].r; + q__1.r = q__2.r + q__6.r, q__1.i = q__2.i + q__6.i; + v[3].r = q__1.r, v[3].i = q__1.i; + } + } + return 0; +} /* claqr1_ */ + +/* Subroutine */ int claqr2_(logical *wantt, logical *wantz, integer *n, + integer *ktop, integer *kbot, integer *nw, complex *h__, integer *ldh, + integer *iloz, integer *ihiz, complex *z__, integer *ldz, integer * + ns, integer *nd, complex *sh, complex *v, integer *ldv, integer *nh, + complex *t, integer *ldt, integer *nv, complex *wv, integer *ldwv, + complex *work, integer *lwork) +{ + /* System generated locals */ + integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, + wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + real r__1, r__2, r__3, r__4, r__5, r__6; + complex q__1, q__2; + + /* Local variables */ + static integer i__, j; + static complex s; + static integer jw; + static real foo; + static integer kln; + static complex tau; + static integer knt; + static real ulp; + static integer lwk1, lwk2; + static complex beta; + static integer kcol, info, ifst, ilst, ltop, krow; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *), + cgemm_(char *, char *, integer *, integer *, integer *, complex *, + complex *, integer *, complex *, integer *, complex *, complex *, + integer *), ccopy_(integer *, complex *, integer + *, complex *, integer *); + static integer infqr, kwtop; + extern /* Subroutine */ int slabad_(real *, real *), cgehrd_(integer *, + integer *, integer *, complex *, integer *, complex *, complex *, + integer *, integer *), clarfg_(integer *, complex *, complex *, + integer *, complex *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int clahqr_(logical *, logical *, integer *, + integer *, integer *, complex *, integer *, complex *, integer *, + integer *, complex *, integer *, integer *), clacpy_(char *, + integer *, integer *, complex *, integer *, complex *, integer *), claset_(char *, integer *, integer *, complex *, complex + *, complex *, integer *); + static real safmin, safmax; + extern /* Subroutine */ int ctrexc_(char *, integer *, complex *, integer + *, complex *, integer *, integer *, integer *, integer *), + cunmhr_(char *, char *, integer *, integer *, integer *, integer + *, complex *, integer *, complex *, complex *, integer *, complex + *, integer *, integer *); + static real smlnum; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + -- April 2009 -- + + + This subroutine is identical to CLAQR3 except that it avoids + recursion by calling CLAHQR instead of CLAQR4. + + + ****************************************************************** + Aggressive early deflation: + + This subroutine accepts as input an upper Hessenberg matrix + H and performs an unitary similarity transformation + designed to detect and deflate fully converged eigenvalues from + a trailing principal submatrix. On output H has been over- + written by a new Hessenberg matrix that is a perturbation of + an unitary similarity transformation of H. It is to be + hoped that the final version of H has many zero subdiagonal + entries. + + ****************************************************************** + WANTT (input) LOGICAL + If .TRUE., then the Hessenberg matrix H is fully updated + so that the triangular Schur factor may be + computed (in cooperation with the calling subroutine). + If .FALSE., then only enough of H is updated to preserve + the eigenvalues. + + WANTZ (input) LOGICAL + If .TRUE., then the unitary matrix Z is updated so + so that the unitary Schur factor may be computed + (in cooperation with the calling subroutine). + If .FALSE., then Z is not referenced. + + N (input) INTEGER + The order of the matrix H and (if WANTZ is .TRUE.) the + order of the unitary matrix Z. + + KTOP (input) INTEGER + It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0. + KBOT and KTOP together determine an isolated block + along the diagonal of the Hessenberg matrix. + + KBOT (input) INTEGER + It is assumed without a check that either + KBOT = N or H(KBOT+1,KBOT)=0. KBOT and KTOP together + determine an isolated block along the diagonal of the + Hessenberg matrix. + + NW (input) INTEGER + Deflation window size. 1 .LE. NW .LE. (KBOT-KTOP+1). + + H (input/output) COMPLEX array, dimension (LDH,N) + On input the initial N-by-N section of H stores the + Hessenberg matrix undergoing aggressive early deflation. + On output H has been transformed by a unitary + similarity transformation, perturbed, and the returned + to Hessenberg form that (it is to be hoped) has some + zero subdiagonal entries. + + LDH (input) integer + Leading dimension of H just as declared in the calling + subroutine. N .LE. LDH + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N. + + Z (input/output) COMPLEX array, dimension (LDZ,N) + IF WANTZ is .TRUE., then on output, the unitary + similarity transformation mentioned above has been + accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ is .FALSE., then Z is unreferenced. + + LDZ (input) integer + The leading dimension of Z just as declared in the + calling subroutine. 1 .LE. LDZ. + + NS (output) integer + The number of unconverged (ie approximate) eigenvalues + returned in SR and SI that may be used as shifts by the + calling subroutine. + + ND (output) integer + The number of converged eigenvalues uncovered by this + subroutine. + + SH (output) COMPLEX array, dimension KBOT + On output, approximate eigenvalues that may + be used for shifts are stored in SH(KBOT-ND-NS+1) + through SR(KBOT-ND). Converged eigenvalues are + stored in SH(KBOT-ND+1) through SH(KBOT). + + V (workspace) COMPLEX array, dimension (LDV,NW) + An NW-by-NW work array. + + LDV (input) integer scalar + The leading dimension of V just as declared in the + calling subroutine. NW .LE. LDV + + NH (input) integer scalar + The number of columns of T. NH.GE.NW. + + T (workspace) COMPLEX array, dimension (LDT,NW) + + LDT (input) integer + The leading dimension of T just as declared in the + calling subroutine. NW .LE. LDT + + NV (input) integer + The number of rows of work array WV available for + workspace. NV.GE.NW. + + WV (workspace) COMPLEX array, dimension (LDWV,NW) + + LDWV (input) integer + The leading dimension of W just as declared in the + calling subroutine. NW .LE. LDV + + WORK (workspace) COMPLEX array, dimension LWORK. + On exit, WORK(1) is set to an estimate of the optimal value + of LWORK for the given values of N, NW, KTOP and KBOT. + + LWORK (input) integer + The dimension of the work array WORK. LWORK = 2*NW + suffices, but greater efficiency may result from larger + values of LWORK. + + If LWORK = -1, then a workspace query is assumed; CLAQR2 + only estimates the optimal workspace size for the given + values of N, NW, KTOP and KBOT. The estimate is returned + in WORK(1). No error message related to LWORK is issued + by XERBLA. Neither H nor Z are accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + + ==== Estimate optimal workspace. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --sh; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + --work; + + /* Function Body */ +/* Computing MIN */ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + if (jw <= 2) { + lwkopt = 1; + } else { + +/* ==== Workspace query call to CGEHRD ==== */ + + i__1 = jw - 1; + cgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], & + c_n1, &info); + lwk1 = (integer) work[1].r; + +/* ==== Workspace query call to CUNMHR ==== */ + + i__1 = jw - 1; + cunmhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[1], &c_n1, &info); + lwk2 = (integer) work[1].r; + +/* ==== Optimal workspace ==== */ + + lwkopt = jw + max(lwk1,lwk2); + } + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + r__1 = (real) lwkopt; + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + return 0; + } + +/* + ==== Nothing to do ... + ... for an empty active block ... ==== +*/ + *ns = 0; + *nd = 0; + work[1].r = 1.f, work[1].i = 0.f; + if (*ktop > *kbot) { + return 0; + } +/* ... nor for an empty deflation window. ==== */ + if (*nw < 1) { + return 0; + } + +/* ==== Machine constants ==== */ + + safmin = slamch_("SAFE MINIMUM"); + safmax = 1.f / safmin; + slabad_(&safmin, &safmax); + ulp = slamch_("PRECISION"); + smlnum = safmin * ((real) (*n) / ulp); + +/* + ==== Setup deflation window ==== + + Computing MIN +*/ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + kwtop = *kbot - jw + 1; + if (kwtop == *ktop) { + s.r = 0.f, s.i = 0.f; + } else { + i__1 = kwtop + (kwtop - 1) * h_dim1; + s.r = h__[i__1].r, s.i = h__[i__1].i; + } + + if (*kbot == kwtop) { + +/* ==== 1-by-1 deflation window: not much to do ==== */ + + i__1 = kwtop; + i__2 = kwtop + kwtop * h_dim1; + sh[i__1].r = h__[i__2].r, sh[i__1].i = h__[i__2].i; + *ns = 1; + *nd = 0; +/* Computing MAX */ + i__1 = kwtop + kwtop * h_dim1; + r__5 = smlnum, r__6 = ulp * ((r__1 = h__[i__1].r, dabs(r__1)) + (r__2 + = r_imag(&h__[kwtop + kwtop * h_dim1]), dabs(r__2))); + if ((r__3 = s.r, dabs(r__3)) + (r__4 = r_imag(&s), dabs(r__4)) <= + dmax(r__5,r__6)) { + *ns = 0; + *nd = 1; + if (kwtop > *ktop) { + i__1 = kwtop + (kwtop - 1) * h_dim1; + h__[i__1].r = 0.f, h__[i__1].i = 0.f; + } + } + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + +/* + ==== Convert to spike-triangular form. (In case of a + . rare QR failure, this routine continues to do + . aggressive early deflation using that part of + . the deflation window that converged using INFQR + . here and there to keep track.) ==== +*/ + + clacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], + ldt); + i__1 = jw - 1; + i__2 = *ldh + 1; + i__3 = *ldt + 1; + ccopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], & + i__3); + + claset_("A", &jw, &jw, &c_b56, &c_b57, &v[v_offset], ldv); + clahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sh[kwtop], + &c__1, &jw, &v[v_offset], ldv, &infqr); + +/* ==== Deflation detection loop ==== */ + + *ns = jw; + ilst = infqr + 1; + i__1 = jw; + for (knt = infqr + 1; knt <= i__1; ++knt) { + +/* ==== Small spike tip deflation test ==== */ + + i__2 = *ns + *ns * t_dim1; + foo = (r__1 = t[i__2].r, dabs(r__1)) + (r__2 = r_imag(&t[*ns + *ns * + t_dim1]), dabs(r__2)); + if (foo == 0.f) { + foo = (r__1 = s.r, dabs(r__1)) + (r__2 = r_imag(&s), dabs(r__2)); + } + i__2 = *ns * v_dim1 + 1; +/* Computing MAX */ + r__5 = smlnum, r__6 = ulp * foo; + if (((r__1 = s.r, dabs(r__1)) + (r__2 = r_imag(&s), dabs(r__2))) * (( + r__3 = v[i__2].r, dabs(r__3)) + (r__4 = r_imag(&v[*ns * + v_dim1 + 1]), dabs(r__4))) <= dmax(r__5,r__6)) { + +/* ==== One more converged eigenvalue ==== */ + + --(*ns); + } else { + +/* + ==== One undeflatable eigenvalue. Move it up out of the + . way. (CTREXC can not fail in this case.) ==== +*/ + + ifst = *ns; + ctrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, & + ilst, &info); + ++ilst; + } +/* L10: */ + } + +/* ==== Return to Hessenberg form ==== */ + + if (*ns == 0) { + s.r = 0.f, s.i = 0.f; + } + + if (*ns < jw) { + +/* + ==== sorting the diagonal of T improves accuracy for + . graded matrices. ==== +*/ + + i__1 = *ns; + for (i__ = infqr + 1; i__ <= i__1; ++i__) { + ifst = i__; + i__2 = *ns; + for (j = i__ + 1; j <= i__2; ++j) { + i__3 = j + j * t_dim1; + i__4 = ifst + ifst * t_dim1; + if ((r__1 = t[i__3].r, dabs(r__1)) + (r__2 = r_imag(&t[j + j * + t_dim1]), dabs(r__2)) > (r__3 = t[i__4].r, dabs(r__3) + ) + (r__4 = r_imag(&t[ifst + ifst * t_dim1]), dabs( + r__4))) { + ifst = j; + } +/* L20: */ + } + ilst = i__; + if (ifst != ilst) { + ctrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &info); + } +/* L30: */ + } + } + +/* ==== Restore shift/eigenvalue array from T ==== */ + + i__1 = jw; + for (i__ = infqr + 1; i__ <= i__1; ++i__) { + i__2 = kwtop + i__ - 1; + i__3 = i__ + i__ * t_dim1; + sh[i__2].r = t[i__3].r, sh[i__2].i = t[i__3].i; +/* L40: */ + } + + + if (*ns < jw || s.r == 0.f && s.i == 0.f) { + if (*ns > 1 && (s.r != 0.f || s.i != 0.f)) { + +/* ==== Reflect spike back into lower triangle ==== */ + + ccopy_(ns, &v[v_offset], ldv, &work[1], &c__1); + i__1 = *ns; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + r_cnjg(&q__1, &work[i__]); + work[i__2].r = q__1.r, work[i__2].i = q__1.i; +/* L50: */ + } + beta.r = work[1].r, beta.i = work[1].i; + clarfg_(ns, &beta, &work[2], &c__1, &tau); + work[1].r = 1.f, work[1].i = 0.f; + + i__1 = jw - 2; + i__2 = jw - 2; + claset_("L", &i__1, &i__2, &c_b56, &c_b56, &t[t_dim1 + 3], ldt); + + r_cnjg(&q__1, &tau); + clarf_("L", ns, &jw, &work[1], &c__1, &q__1, &t[t_offset], ldt, & + work[jw + 1]); + clarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + clarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, & + work[jw + 1]); + + i__1 = *lwork - jw; + cgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1] + , &i__1, &info); + } + +/* ==== Copy updated reduced window into place ==== */ + + if (kwtop > 1) { + i__1 = kwtop + (kwtop - 1) * h_dim1; + r_cnjg(&q__2, &v[v_dim1 + 1]); + q__1.r = s.r * q__2.r - s.i * q__2.i, q__1.i = s.r * q__2.i + s.i + * q__2.r; + h__[i__1].r = q__1.r, h__[i__1].i = q__1.i; + } + clacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1] + , ldh); + i__1 = jw - 1; + i__2 = *ldt + 1; + i__3 = *ldh + 1; + ccopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1], + &i__3); + +/* + ==== Accumulate orthogonal matrix in order update + . H and Z, if requested. ==== +*/ + + if (*ns > 1 && (s.r != 0.f || s.i != 0.f)) { + i__1 = *lwork - jw; + cunmhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[jw + 1], &i__1, &info); + } + +/* ==== Update vertical slab in H ==== */ + + if (*wantt) { + ltop = 1; + } else { + ltop = *ktop; + } + i__1 = kwtop - 1; + i__2 = *nv; + for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = kwtop - krow; + kln = min(i__3,i__4); + cgemm_("N", "N", &kln, &jw, &jw, &c_b57, &h__[krow + kwtop * + h_dim1], ldh, &v[v_offset], ldv, &c_b56, &wv[wv_offset], + ldwv); + clacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * + h_dim1], ldh); +/* L60: */ + } + +/* ==== Update horizontal slab in H ==== */ + + if (*wantt) { + i__2 = *n; + i__1 = *nh; + for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; + kcol += i__1) { +/* Computing MIN */ + i__3 = *nh, i__4 = *n - kcol + 1; + kln = min(i__3,i__4); + cgemm_("C", "N", &jw, &kln, &jw, &c_b57, &v[v_offset], ldv, & + h__[kwtop + kcol * h_dim1], ldh, &c_b56, &t[t_offset], + ldt); + clacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol * + h_dim1], ldh); +/* L70: */ + } + } + +/* ==== Update vertical slab in Z ==== */ + + if (*wantz) { + i__1 = *ihiz; + i__2 = *nv; + for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = *ihiz - krow + 1; + kln = min(i__3,i__4); + cgemm_("N", "N", &kln, &jw, &jw, &c_b57, &z__[krow + kwtop * + z_dim1], ldz, &v[v_offset], ldv, &c_b56, &wv[ + wv_offset], ldwv); + clacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + + kwtop * z_dim1], ldz); +/* L80: */ + } + } + } + +/* ==== Return the number of deflations ... ==== */ + + *nd = jw - *ns; + +/* + ==== ... and the number of shifts. (Subtracting + . INFQR from the spike length takes care + . of the case of a rare QR failure while + . calculating eigenvalues of the deflation + . window.) ==== +*/ + + *ns -= infqr; + +/* ==== Return optimal workspace. ==== */ + + r__1 = (real) lwkopt; + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + +/* ==== End of CLAQR2 ==== */ + + return 0; +} /* claqr2_ */ + +/* Subroutine */ int claqr3_(logical *wantt, logical *wantz, integer *n, + integer *ktop, integer *kbot, integer *nw, complex *h__, integer *ldh, + integer *iloz, integer *ihiz, complex *z__, integer *ldz, integer * + ns, integer *nd, complex *sh, complex *v, integer *ldv, integer *nh, + complex *t, integer *ldt, integer *nv, complex *wv, integer *ldwv, + complex *work, integer *lwork) +{ + /* System generated locals */ + integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, + wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + real r__1, r__2, r__3, r__4, r__5, r__6; + complex q__1, q__2; + + /* Local variables */ + static integer i__, j; + static complex s; + static integer jw; + static real foo; + static integer kln; + static complex tau; + static integer knt; + static real ulp; + static integer lwk1, lwk2, lwk3; + static complex beta; + static integer kcol, info, nmin, ifst, ilst, ltop, krow; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *), + cgemm_(char *, char *, integer *, integer *, integer *, complex *, + complex *, integer *, complex *, integer *, complex *, complex *, + integer *), ccopy_(integer *, complex *, integer + *, complex *, integer *); + static integer infqr, kwtop; + extern /* Subroutine */ int claqr4_(logical *, logical *, integer *, + integer *, integer *, complex *, integer *, complex *, integer *, + integer *, complex *, integer *, complex *, integer *, integer *), + slabad_(real *, real *), cgehrd_(integer *, integer *, integer *, + complex *, integer *, complex *, complex *, integer *, integer *) + , clarfg_(integer *, complex *, complex *, integer *, complex *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int clahqr_(logical *, logical *, integer *, + integer *, integer *, complex *, integer *, complex *, integer *, + integer *, complex *, integer *, integer *), clacpy_(char *, + integer *, integer *, complex *, integer *, complex *, integer *), claset_(char *, integer *, integer *, complex *, complex + *, complex *, integer *); + static real safmin; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static real safmax; + extern /* Subroutine */ int ctrexc_(char *, integer *, complex *, integer + *, complex *, integer *, integer *, integer *, integer *), + cunmhr_(char *, char *, integer *, integer *, integer *, integer + *, complex *, integer *, complex *, complex *, integer *, complex + *, integer *, integer *); + static real smlnum; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + -- April 2009 -- + + + ****************************************************************** + Aggressive early deflation: + + This subroutine accepts as input an upper Hessenberg matrix + H and performs an unitary similarity transformation + designed to detect and deflate fully converged eigenvalues from + a trailing principal submatrix. On output H has been over- + written by a new Hessenberg matrix that is a perturbation of + an unitary similarity transformation of H. It is to be + hoped that the final version of H has many zero subdiagonal + entries. + + ****************************************************************** + WANTT (input) LOGICAL + If .TRUE., then the Hessenberg matrix H is fully updated + so that the triangular Schur factor may be + computed (in cooperation with the calling subroutine). + If .FALSE., then only enough of H is updated to preserve + the eigenvalues. + + WANTZ (input) LOGICAL + If .TRUE., then the unitary matrix Z is updated so + so that the unitary Schur factor may be computed + (in cooperation with the calling subroutine). + If .FALSE., then Z is not referenced. + + N (input) INTEGER + The order of the matrix H and (if WANTZ is .TRUE.) the + order of the unitary matrix Z. + + KTOP (input) INTEGER + It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0. + KBOT and KTOP together determine an isolated block + along the diagonal of the Hessenberg matrix. + + KBOT (input) INTEGER + It is assumed without a check that either + KBOT = N or H(KBOT+1,KBOT)=0. KBOT and KTOP together + determine an isolated block along the diagonal of the + Hessenberg matrix. + + NW (input) INTEGER + Deflation window size. 1 .LE. NW .LE. (KBOT-KTOP+1). + + H (input/output) COMPLEX array, dimension (LDH,N) + On input the initial N-by-N section of H stores the + Hessenberg matrix undergoing aggressive early deflation. + On output H has been transformed by a unitary + similarity transformation, perturbed, and the returned + to Hessenberg form that (it is to be hoped) has some + zero subdiagonal entries. + + LDH (input) integer + Leading dimension of H just as declared in the calling + subroutine. N .LE. LDH + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N. + + Z (input/output) COMPLEX array, dimension (LDZ,N) + IF WANTZ is .TRUE., then on output, the unitary + similarity transformation mentioned above has been + accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ is .FALSE., then Z is unreferenced. + + LDZ (input) integer + The leading dimension of Z just as declared in the + calling subroutine. 1 .LE. LDZ. + + NS (output) integer + The number of unconverged (ie approximate) eigenvalues + returned in SR and SI that may be used as shifts by the + calling subroutine. + + ND (output) integer + The number of converged eigenvalues uncovered by this + subroutine. + + SH (output) COMPLEX array, dimension KBOT + On output, approximate eigenvalues that may + be used for shifts are stored in SH(KBOT-ND-NS+1) + through SR(KBOT-ND). Converged eigenvalues are + stored in SH(KBOT-ND+1) through SH(KBOT). + + V (workspace) COMPLEX array, dimension (LDV,NW) + An NW-by-NW work array. + + LDV (input) integer scalar + The leading dimension of V just as declared in the + calling subroutine. NW .LE. LDV + + NH (input) integer scalar + The number of columns of T. NH.GE.NW. + + T (workspace) COMPLEX array, dimension (LDT,NW) + + LDT (input) integer + The leading dimension of T just as declared in the + calling subroutine. NW .LE. LDT + + NV (input) integer + The number of rows of work array WV available for + workspace. NV.GE.NW. + + WV (workspace) COMPLEX array, dimension (LDWV,NW) + + LDWV (input) integer + The leading dimension of W just as declared in the + calling subroutine. NW .LE. LDV + + WORK (workspace) COMPLEX array, dimension LWORK. + On exit, WORK(1) is set to an estimate of the optimal value + of LWORK for the given values of N, NW, KTOP and KBOT. + + LWORK (input) integer + The dimension of the work array WORK. LWORK = 2*NW + suffices, but greater efficiency may result from larger + values of LWORK. + + If LWORK = -1, then a workspace query is assumed; CLAQR3 + only estimates the optimal workspace size for the given + values of N, NW, KTOP and KBOT. The estimate is returned + in WORK(1). No error message related to LWORK is issued + by XERBLA. Neither H nor Z are accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + + ==== Estimate optimal workspace. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --sh; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + --work; + + /* Function Body */ +/* Computing MIN */ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + if (jw <= 2) { + lwkopt = 1; + } else { + +/* ==== Workspace query call to CGEHRD ==== */ + + i__1 = jw - 1; + cgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], & + c_n1, &info); + lwk1 = (integer) work[1].r; + +/* ==== Workspace query call to CUNMHR ==== */ + + i__1 = jw - 1; + cunmhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[1], &c_n1, &info); + lwk2 = (integer) work[1].r; + +/* ==== Workspace query call to CLAQR4 ==== */ + + claqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sh[1], + &c__1, &jw, &v[v_offset], ldv, &work[1], &c_n1, &infqr); + lwk3 = (integer) work[1].r; + +/* + ==== Optimal workspace ==== + + Computing MAX +*/ + i__1 = jw + max(lwk1,lwk2); + lwkopt = max(i__1,lwk3); + } + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + r__1 = (real) lwkopt; + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + return 0; + } + +/* + ==== Nothing to do ... + ... for an empty active block ... ==== +*/ + *ns = 0; + *nd = 0; + work[1].r = 1.f, work[1].i = 0.f; + if (*ktop > *kbot) { + return 0; + } +/* ... nor for an empty deflation window. ==== */ + if (*nw < 1) { + return 0; + } + +/* ==== Machine constants ==== */ + + safmin = slamch_("SAFE MINIMUM"); + safmax = 1.f / safmin; + slabad_(&safmin, &safmax); + ulp = slamch_("PRECISION"); + smlnum = safmin * ((real) (*n) / ulp); + +/* + ==== Setup deflation window ==== + + Computing MIN +*/ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + kwtop = *kbot - jw + 1; + if (kwtop == *ktop) { + s.r = 0.f, s.i = 0.f; + } else { + i__1 = kwtop + (kwtop - 1) * h_dim1; + s.r = h__[i__1].r, s.i = h__[i__1].i; + } + + if (*kbot == kwtop) { + +/* ==== 1-by-1 deflation window: not much to do ==== */ + + i__1 = kwtop; + i__2 = kwtop + kwtop * h_dim1; + sh[i__1].r = h__[i__2].r, sh[i__1].i = h__[i__2].i; + *ns = 1; + *nd = 0; +/* Computing MAX */ + i__1 = kwtop + kwtop * h_dim1; + r__5 = smlnum, r__6 = ulp * ((r__1 = h__[i__1].r, dabs(r__1)) + (r__2 + = r_imag(&h__[kwtop + kwtop * h_dim1]), dabs(r__2))); + if ((r__3 = s.r, dabs(r__3)) + (r__4 = r_imag(&s), dabs(r__4)) <= + dmax(r__5,r__6)) { + *ns = 0; + *nd = 1; + if (kwtop > *ktop) { + i__1 = kwtop + (kwtop - 1) * h_dim1; + h__[i__1].r = 0.f, h__[i__1].i = 0.f; + } + } + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + +/* + ==== Convert to spike-triangular form. (In case of a + . rare QR failure, this routine continues to do + . aggressive early deflation using that part of + . the deflation window that converged using INFQR + . here and there to keep track.) ==== +*/ + + clacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], + ldt); + i__1 = jw - 1; + i__2 = *ldh + 1; + i__3 = *ldt + 1; + ccopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], & + i__3); + + claset_("A", &jw, &jw, &c_b56, &c_b57, &v[v_offset], ldv); + nmin = ilaenv_(&c__12, "CLAQR3", "SV", &jw, &c__1, &jw, lwork, (ftnlen)6, + (ftnlen)2); + if (jw > nmin) { + claqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sh[ + kwtop], &c__1, &jw, &v[v_offset], ldv, &work[1], lwork, & + infqr); + } else { + clahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sh[ + kwtop], &c__1, &jw, &v[v_offset], ldv, &infqr); + } + +/* ==== Deflation detection loop ==== */ + + *ns = jw; + ilst = infqr + 1; + i__1 = jw; + for (knt = infqr + 1; knt <= i__1; ++knt) { + +/* ==== Small spike tip deflation test ==== */ + + i__2 = *ns + *ns * t_dim1; + foo = (r__1 = t[i__2].r, dabs(r__1)) + (r__2 = r_imag(&t[*ns + *ns * + t_dim1]), dabs(r__2)); + if (foo == 0.f) { + foo = (r__1 = s.r, dabs(r__1)) + (r__2 = r_imag(&s), dabs(r__2)); + } + i__2 = *ns * v_dim1 + 1; +/* Computing MAX */ + r__5 = smlnum, r__6 = ulp * foo; + if (((r__1 = s.r, dabs(r__1)) + (r__2 = r_imag(&s), dabs(r__2))) * (( + r__3 = v[i__2].r, dabs(r__3)) + (r__4 = r_imag(&v[*ns * + v_dim1 + 1]), dabs(r__4))) <= dmax(r__5,r__6)) { + +/* ==== One more converged eigenvalue ==== */ + + --(*ns); + } else { + +/* + ==== One undeflatable eigenvalue. Move it up out of the + . way. (CTREXC can not fail in this case.) ==== +*/ + + ifst = *ns; + ctrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, & + ilst, &info); + ++ilst; + } +/* L10: */ + } + +/* ==== Return to Hessenberg form ==== */ + + if (*ns == 0) { + s.r = 0.f, s.i = 0.f; + } + + if (*ns < jw) { + +/* + ==== sorting the diagonal of T improves accuracy for + . graded matrices. ==== +*/ + + i__1 = *ns; + for (i__ = infqr + 1; i__ <= i__1; ++i__) { + ifst = i__; + i__2 = *ns; + for (j = i__ + 1; j <= i__2; ++j) { + i__3 = j + j * t_dim1; + i__4 = ifst + ifst * t_dim1; + if ((r__1 = t[i__3].r, dabs(r__1)) + (r__2 = r_imag(&t[j + j * + t_dim1]), dabs(r__2)) > (r__3 = t[i__4].r, dabs(r__3) + ) + (r__4 = r_imag(&t[ifst + ifst * t_dim1]), dabs( + r__4))) { + ifst = j; + } +/* L20: */ + } + ilst = i__; + if (ifst != ilst) { + ctrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &info); + } +/* L30: */ + } + } + +/* ==== Restore shift/eigenvalue array from T ==== */ + + i__1 = jw; + for (i__ = infqr + 1; i__ <= i__1; ++i__) { + i__2 = kwtop + i__ - 1; + i__3 = i__ + i__ * t_dim1; + sh[i__2].r = t[i__3].r, sh[i__2].i = t[i__3].i; +/* L40: */ + } + + + if (*ns < jw || s.r == 0.f && s.i == 0.f) { + if (*ns > 1 && (s.r != 0.f || s.i != 0.f)) { + +/* ==== Reflect spike back into lower triangle ==== */ + + ccopy_(ns, &v[v_offset], ldv, &work[1], &c__1); + i__1 = *ns; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + r_cnjg(&q__1, &work[i__]); + work[i__2].r = q__1.r, work[i__2].i = q__1.i; +/* L50: */ + } + beta.r = work[1].r, beta.i = work[1].i; + clarfg_(ns, &beta, &work[2], &c__1, &tau); + work[1].r = 1.f, work[1].i = 0.f; + + i__1 = jw - 2; + i__2 = jw - 2; + claset_("L", &i__1, &i__2, &c_b56, &c_b56, &t[t_dim1 + 3], ldt); + + r_cnjg(&q__1, &tau); + clarf_("L", ns, &jw, &work[1], &c__1, &q__1, &t[t_offset], ldt, & + work[jw + 1]); + clarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + clarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, & + work[jw + 1]); + + i__1 = *lwork - jw; + cgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1] + , &i__1, &info); + } + +/* ==== Copy updated reduced window into place ==== */ + + if (kwtop > 1) { + i__1 = kwtop + (kwtop - 1) * h_dim1; + r_cnjg(&q__2, &v[v_dim1 + 1]); + q__1.r = s.r * q__2.r - s.i * q__2.i, q__1.i = s.r * q__2.i + s.i + * q__2.r; + h__[i__1].r = q__1.r, h__[i__1].i = q__1.i; + } + clacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1] + , ldh); + i__1 = jw - 1; + i__2 = *ldt + 1; + i__3 = *ldh + 1; + ccopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1], + &i__3); + +/* + ==== Accumulate orthogonal matrix in order update + . H and Z, if requested. ==== +*/ + + if (*ns > 1 && (s.r != 0.f || s.i != 0.f)) { + i__1 = *lwork - jw; + cunmhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[jw + 1], &i__1, &info); + } + +/* ==== Update vertical slab in H ==== */ + + if (*wantt) { + ltop = 1; + } else { + ltop = *ktop; + } + i__1 = kwtop - 1; + i__2 = *nv; + for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = kwtop - krow; + kln = min(i__3,i__4); + cgemm_("N", "N", &kln, &jw, &jw, &c_b57, &h__[krow + kwtop * + h_dim1], ldh, &v[v_offset], ldv, &c_b56, &wv[wv_offset], + ldwv); + clacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * + h_dim1], ldh); +/* L60: */ + } + +/* ==== Update horizontal slab in H ==== */ + + if (*wantt) { + i__2 = *n; + i__1 = *nh; + for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; + kcol += i__1) { +/* Computing MIN */ + i__3 = *nh, i__4 = *n - kcol + 1; + kln = min(i__3,i__4); + cgemm_("C", "N", &jw, &kln, &jw, &c_b57, &v[v_offset], ldv, & + h__[kwtop + kcol * h_dim1], ldh, &c_b56, &t[t_offset], + ldt); + clacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol * + h_dim1], ldh); +/* L70: */ + } + } + +/* ==== Update vertical slab in Z ==== */ + + if (*wantz) { + i__1 = *ihiz; + i__2 = *nv; + for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = *ihiz - krow + 1; + kln = min(i__3,i__4); + cgemm_("N", "N", &kln, &jw, &jw, &c_b57, &z__[krow + kwtop * + z_dim1], ldz, &v[v_offset], ldv, &c_b56, &wv[ + wv_offset], ldwv); + clacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + + kwtop * z_dim1], ldz); +/* L80: */ + } + } + } + +/* ==== Return the number of deflations ... ==== */ + + *nd = jw - *ns; + +/* + ==== ... and the number of shifts. (Subtracting + . INFQR from the spike length takes care + . of the case of a rare QR failure while + . calculating eigenvalues of the deflation + . window.) ==== +*/ + + *ns -= infqr; + +/* ==== Return optimal workspace. ==== */ + + r__1 = (real) lwkopt; + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + +/* ==== End of CLAQR3 ==== */ + + return 0; +} /* claqr3_ */ + +/* Subroutine */ int claqr4_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *w, + integer *iloz, integer *ihiz, complex *z__, integer *ldz, complex * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5; + real r__1, r__2, r__3, r__4, r__5, r__6, r__7, r__8; + complex q__1, q__2, q__3, q__4, q__5; + + /* Local variables */ + static integer i__, k; + static real s; + static complex aa, bb, cc, dd; + static integer ld, nh, it, ks, kt, ku, kv, ls, ns, nw; + static complex tr2, det; + static integer inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, kbot, + nmin; + static complex swap; + static integer ktop; + static complex zdum[1] /* was [1][1] */; + static integer kacc22, itmax, nsmax, nwmax, kwtop; + extern /* Subroutine */ int claqr2_(logical *, logical *, integer *, + integer *, integer *, integer *, complex *, integer *, integer *, + integer *, complex *, integer *, integer *, integer *, complex *, + complex *, integer *, integer *, complex *, integer *, integer *, + complex *, integer *, complex *, integer *), claqr5_(logical *, + logical *, integer *, integer *, integer *, integer *, integer *, + complex *, complex *, integer *, integer *, integer *, complex *, + integer *, complex *, integer *, complex *, integer *, integer *, + complex *, integer *, integer *, complex *, integer *); + static integer nibble; + extern /* Subroutine */ int clahqr_(logical *, logical *, integer *, + integer *, integer *, complex *, integer *, complex *, integer *, + integer *, complex *, integer *, integer *), clacpy_(char *, + integer *, integer *, complex *, integer *, complex *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static char jbcmpz[2]; + static complex rtdisc; + static integer nwupbd; + static logical sorted; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + This subroutine implements one level of recursion for CLAQR0. + It is a complete implementation of the small bulge multi-shift + QR algorithm. It may be called by CLAQR0 and, for large enough + deflation window size, it may be called by CLAQR3. This + subroutine is identical to CLAQR0 except that it calls CLAQR2 + instead of CLAQR3. + + Purpose + ======= + + CLAQR4 computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**H, where T is an upper triangular matrix (the + Schur form), and Z is the unitary matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input unitary + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the unitary matrix Q: A = Q*H*Q**H = (QZ)*H*(QZ)**H. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1, + H(ILO,ILO-1) is zero. ILO and IHI are normally set by a + previous call to CGEBAL, and then passed to CGEHRD when the + matrix output by CGEBAL is reduced to Hessenberg form. + Otherwise, ILO and IHI should be set to 1 and N, + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) COMPLEX array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and WANTT is .TRUE., then H + contains the upper triangular matrix T from the Schur + decomposition (the Schur form). If INFO = 0 and WANT is + .FALSE., then the contents of H are unspecified on exit. + (The output value of H when INFO.GT.0 is given under the + description of INFO below.) + + This subroutine may explicitly set H(i,j) = 0 for i.GT.j and + j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + W (output) COMPLEX array, dimension (N) + The computed eigenvalues of H(ILO:IHI,ILO:IHI) are stored + in W(ILO:IHI). If WANTT is .TRUE., then the eigenvalues are + stored in the same order as on the diagonal of the Schur + form returned in H, with W(i) = H(i,i). + + Z (input/output) COMPLEX array, dimension (LDZ,IHI) + If WANTZ is .FALSE., then Z is not referenced. + If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is + replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the + orthogonal Schur factor of H(ILO:IHI,ILO:IHI). + (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if WANTZ is .TRUE. + then LDZ.GE.MAX(1,IHIZ). Otherwize, LDZ.GE.1. + + WORK (workspace/output) COMPLEX array, dimension LWORK + On exit, if LWORK = -1, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient, but LWORK typically as large as 6*N may + be required for optimal performance. A workspace query + to determine the optimal workspace size is recommended. + + If LWORK = -1, then CLAQR4 does a workspace query. + In this case, CLAQR4 checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, CLAQR4 failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and WANT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is a unitary matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + + (final value of Z(ILO:IHI,ILOZ:IHIZ) + = (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U + + where U is the unitary matrix in (*) (regard- + less of the value of WANTT.) + + If INFO .GT. 0 and WANTZ is .FALSE., then Z is not + accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . CLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== Exceptional deflation windows: try to cure rare + . slow convergence by varying the size of the + . deflation window after KEXNW iterations. ==== + + ==== Exceptional shifts: try to cure rare slow convergence + . with ad-hoc exceptional shifts every KEXSH iterations. + . ==== + + ==== The constant WILK1 is used to form the exceptional + . shifts. ==== +*/ + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --w; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + +/* ==== Quick return for N = 0: nothing to do. ==== */ + + if (*n == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + if (*n <= 11) { + +/* ==== Tiny matrices must use CLAHQR. ==== */ + + lwkopt = 1; + if (*lwork != -1) { + clahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], + iloz, ihiz, &z__[z_offset], ldz, info); + } + } else { + +/* + ==== Use small bulge multi-shift QR with aggressive early + . deflation on larger-than-tiny matrices. ==== + + ==== Hope for the best. ==== +*/ + + *info = 0; + +/* ==== Set up job flags for ILAENV. ==== */ + + if (*wantt) { + *(unsigned char *)jbcmpz = 'S'; + } else { + *(unsigned char *)jbcmpz = 'E'; + } + if (*wantz) { + *(unsigned char *)&jbcmpz[1] = 'V'; + } else { + *(unsigned char *)&jbcmpz[1] = 'N'; + } + +/* + ==== NWR = recommended deflation window size. At this + . point, N .GT. NTINY = 11, so there is enough + . subdiagonal workspace for NWR.GE.2 as required. + . (In fact, there is enough subdiagonal space for + . NWR.GE.3.) ==== +*/ + + nwr = ilaenv_(&c__13, "CLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nwr = max(2,nwr); +/* Computing MIN */ + i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2); + nwr = min(i__1,nwr); + +/* + ==== NSR = recommended number of simultaneous shifts. + . At this point N .GT. NTINY = 11, so there is at + . enough subdiagonal workspace for NSR to be even + . and greater than or equal to two as required. ==== +*/ + + nsr = ilaenv_(&c__15, "CLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); +/* Computing MIN */ + i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - + *ilo; + nsr = min(i__1,i__2); +/* Computing MAX */ + i__1 = 2, i__2 = nsr - nsr % 2; + nsr = max(i__1,i__2); + +/* + ==== Estimate optimal workspace ==== + + ==== Workspace query call to CLAQR2 ==== +*/ + + i__1 = nwr + 1; + claqr2_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, + ihiz, &z__[z_offset], ldz, &ls, &ld, &w[1], &h__[h_offset], + ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], ldh, &work[1], + &c_n1); + +/* + ==== Optimal workspace = MAX(CLAQR5, CLAQR2) ==== + + Computing MAX +*/ + i__1 = nsr * 3 / 2, i__2 = (integer) work[1].r; + lwkopt = max(i__1,i__2); + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + r__1 = (real) lwkopt; + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + return 0; + } + +/* ==== CLAHQR/CLAQR0 crossover point ==== */ + + nmin = ilaenv_(&c__12, "CLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen) + 6, (ftnlen)2); + nmin = max(11,nmin); + +/* ==== Nibble crossover point ==== */ + + nibble = ilaenv_(&c__14, "CLAQR4", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + nibble = max(0,nibble); + +/* + ==== Accumulate reflections during ttswp? Use block + . 2-by-2 structure during matrix-matrix multiply? ==== +*/ + + kacc22 = ilaenv_(&c__16, "CLAQR4", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + kacc22 = max(0,kacc22); + kacc22 = min(2,kacc22); + +/* + ==== NWMAX = the largest possible deflation window for + . which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n - 1) / 3, i__2 = *lwork / 2; + nwmax = min(i__1,i__2); + nw = nwmax; + +/* + ==== NSMAX = the Largest number of simultaneous shifts + . for which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3; + nsmax = min(i__1,i__2); + nsmax -= nsmax % 2; + +/* ==== NDFL: an iteration count restarted at deflation. ==== */ + + ndfl = 1; + +/* + ==== ITMAX = iteration limit ==== + + Computing MAX +*/ + i__1 = 10, i__2 = *ihi - *ilo + 1; + itmax = max(i__1,i__2) * 30; + +/* ==== Last row and column in the active block ==== */ + + kbot = *ihi; + +/* ==== Main Loop ==== */ + + i__1 = itmax; + for (it = 1; it <= i__1; ++it) { + +/* ==== Done when KBOT falls below ILO ==== */ + + if (kbot < *ilo) { + goto L80; + } + +/* ==== Locate active block ==== */ + + i__2 = *ilo + 1; + for (k = kbot; k >= i__2; --k) { + i__3 = k + (k - 1) * h_dim1; + if (h__[i__3].r == 0.f && h__[i__3].i == 0.f) { + goto L20; + } +/* L10: */ + } + k = *ilo; +L20: + ktop = k; + +/* + ==== Select deflation window size: + . Typical Case: + . If possible and advisable, nibble the entire + . active block. If not, use size MIN(NWR,NWMAX) + . or MIN(NWR+1,NWMAX) depending upon which has + . the smaller corresponding subdiagonal entry + . (a heuristic). + . + . Exceptional Case: + . If there have been no deflations in KEXNW or + . more iterations, then vary the deflation window + . size. At first, because, larger windows are, + . in general, more powerful than smaller ones, + . rapidly increase the window to the maximum possible. + . Then, gradually reduce the window size. ==== +*/ + + nh = kbot - ktop + 1; + nwupbd = min(nh,nwmax); + if (ndfl < 5) { + nw = min(nwupbd,nwr); + } else { +/* Computing MIN */ + i__2 = nwupbd, i__3 = nw << 1; + nw = min(i__2,i__3); + } + if (nw < nwmax) { + if (nw >= nh - 1) { + nw = nh; + } else { + kwtop = kbot - nw + 1; + i__2 = kwtop + (kwtop - 1) * h_dim1; + i__3 = kwtop - 1 + (kwtop - 2) * h_dim1; + if ((r__1 = h__[i__2].r, dabs(r__1)) + (r__2 = r_imag(& + h__[kwtop + (kwtop - 1) * h_dim1]), dabs(r__2)) > + (r__3 = h__[i__3].r, dabs(r__3)) + (r__4 = r_imag( + &h__[kwtop - 1 + (kwtop - 2) * h_dim1]), dabs( + r__4))) { + ++nw; + } + } + } + if (ndfl < 5) { + ndec = -1; + } else if (ndec >= 0 || nw >= nwupbd) { + ++ndec; + if (nw - ndec < 2) { + ndec = 0; + } + nw -= ndec; + } + +/* + ==== Aggressive early deflation: + . split workspace under the subdiagonal into + . - an nw-by-nw work array V in the lower + . left-hand-corner, + . - an NW-by-at-least-NW-but-more-is-better + . (NW-by-NHO) horizontal work array along + . the bottom edge, + . - an at-least-NW-but-more-is-better (NHV-by-NW) + . vertical work array along the left-hand-edge. + . ==== +*/ + + kv = *n - nw + 1; + kt = nw + 1; + nho = *n - nw - 1 - kt + 1; + kwv = nw + 2; + nve = *n - nw - kwv + 1; + +/* ==== Aggressive early deflation ==== */ + + claqr2_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, + iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &w[1], &h__[kv + + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], ldh, &nve, & + h__[kwv + h_dim1], ldh, &work[1], lwork); + +/* ==== Adjust KBOT accounting for new deflations. ==== */ + + kbot -= ld; + +/* ==== KS points to the shifts. ==== */ + + ks = kbot - ls + 1; + +/* + ==== Skip an expensive QR sweep if there is a (partly + . heuristic) reason to expect that many eigenvalues + . will deflate without it. Here, the QR sweep is + . skipped if many eigenvalues have just been deflated + . or if the remaining active block is small. +*/ + + if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min( + nmin,nwmax)) { + +/* + ==== NS = nominal number of simultaneous shifts. + . This may be lowered (slightly) if CLAQR2 + . did not provide that many shifts. ==== + + Computing MIN + Computing MAX +*/ + i__4 = 2, i__5 = kbot - ktop; + i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5); + ns = min(i__2,i__3); + ns -= ns % 2; + +/* + ==== If there have been no deflations + . in a multiple of KEXSH iterations, + . then try exceptional shifts. + . Otherwise use shifts provided by + . CLAQR2 above or from the eigenvalues + . of a trailing principal submatrix. ==== +*/ + + if (ndfl % 6 == 0) { + ks = kbot - ns + 1; + i__2 = ks + 1; + for (i__ = kbot; i__ >= i__2; i__ += -2) { + i__3 = i__; + i__4 = i__ + i__ * h_dim1; + i__5 = i__ + (i__ - 1) * h_dim1; + r__3 = ((r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[i__ + (i__ - 1) * h_dim1]), dabs( + r__2))) * .75f; + q__1.r = h__[i__4].r + r__3, q__1.i = h__[i__4].i; + w[i__3].r = q__1.r, w[i__3].i = q__1.i; + i__3 = i__ - 1; + i__4 = i__; + w[i__3].r = w[i__4].r, w[i__3].i = w[i__4].i; +/* L30: */ + } + } else { + +/* + ==== Got NS/2 or fewer shifts? Use CLAHQR + . on a trailing principal submatrix to + . get more. (Since NS.LE.NSMAX.LE.(N+6)/9, + . there is enough space below the subdiagonal + . to fit an NS-by-NS scratch array.) ==== +*/ + + if (kbot - ks + 1 <= ns / 2) { + ks = kbot - ns + 1; + kt = *n - ns + 1; + clacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, & + h__[kt + h_dim1], ldh); + clahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[kt + + h_dim1], ldh, &w[ks], &c__1, &c__1, zdum, & + c__1, &inf); + ks += inf; + +/* + ==== In case of a rare QR failure use + . eigenvalues of the trailing 2-by-2 + . principal submatrix. Scale to avoid + . overflows, underflows and subnormals. + . (The scale factor S can not be zero, + . because H(KBOT,KBOT-1) is nonzero.) ==== +*/ + + if (ks >= kbot) { + i__2 = kbot - 1 + (kbot - 1) * h_dim1; + i__3 = kbot + (kbot - 1) * h_dim1; + i__4 = kbot - 1 + kbot * h_dim1; + i__5 = kbot + kbot * h_dim1; + s = (r__1 = h__[i__2].r, dabs(r__1)) + (r__2 = + r_imag(&h__[kbot - 1 + (kbot - 1) * + h_dim1]), dabs(r__2)) + ((r__3 = h__[i__3] + .r, dabs(r__3)) + (r__4 = r_imag(&h__[ + kbot + (kbot - 1) * h_dim1]), dabs(r__4))) + + ((r__5 = h__[i__4].r, dabs(r__5)) + ( + r__6 = r_imag(&h__[kbot - 1 + kbot * + h_dim1]), dabs(r__6))) + ((r__7 = h__[ + i__5].r, dabs(r__7)) + (r__8 = r_imag(& + h__[kbot + kbot * h_dim1]), dabs(r__8))); + i__2 = kbot - 1 + (kbot - 1) * h_dim1; + q__1.r = h__[i__2].r / s, q__1.i = h__[i__2].i / + s; + aa.r = q__1.r, aa.i = q__1.i; + i__2 = kbot + (kbot - 1) * h_dim1; + q__1.r = h__[i__2].r / s, q__1.i = h__[i__2].i / + s; + cc.r = q__1.r, cc.i = q__1.i; + i__2 = kbot - 1 + kbot * h_dim1; + q__1.r = h__[i__2].r / s, q__1.i = h__[i__2].i / + s; + bb.r = q__1.r, bb.i = q__1.i; + i__2 = kbot + kbot * h_dim1; + q__1.r = h__[i__2].r / s, q__1.i = h__[i__2].i / + s; + dd.r = q__1.r, dd.i = q__1.i; + q__2.r = aa.r + dd.r, q__2.i = aa.i + dd.i; + q__1.r = q__2.r / 2.f, q__1.i = q__2.i / 2.f; + tr2.r = q__1.r, tr2.i = q__1.i; + q__3.r = aa.r - tr2.r, q__3.i = aa.i - tr2.i; + q__4.r = dd.r - tr2.r, q__4.i = dd.i - tr2.i; + q__2.r = q__3.r * q__4.r - q__3.i * q__4.i, + q__2.i = q__3.r * q__4.i + q__3.i * + q__4.r; + q__5.r = bb.r * cc.r - bb.i * cc.i, q__5.i = bb.r + * cc.i + bb.i * cc.r; + q__1.r = q__2.r - q__5.r, q__1.i = q__2.i - + q__5.i; + det.r = q__1.r, det.i = q__1.i; + q__2.r = -det.r, q__2.i = -det.i; + c_sqrt(&q__1, &q__2); + rtdisc.r = q__1.r, rtdisc.i = q__1.i; + i__2 = kbot - 1; + q__2.r = tr2.r + rtdisc.r, q__2.i = tr2.i + + rtdisc.i; + q__1.r = s * q__2.r, q__1.i = s * q__2.i; + w[i__2].r = q__1.r, w[i__2].i = q__1.i; + i__2 = kbot; + q__2.r = tr2.r - rtdisc.r, q__2.i = tr2.i - + rtdisc.i; + q__1.r = s * q__2.r, q__1.i = s * q__2.i; + w[i__2].r = q__1.r, w[i__2].i = q__1.i; + + ks = kbot - 1; + } + } + + if (kbot - ks + 1 > ns) { + +/* ==== Sort the shifts (Helps a little) ==== */ + + sorted = FALSE_; + i__2 = ks + 1; + for (k = kbot; k >= i__2; --k) { + if (sorted) { + goto L60; + } + sorted = TRUE_; + i__3 = k - 1; + for (i__ = ks; i__ <= i__3; ++i__) { + i__4 = i__; + i__5 = i__ + 1; + if ((r__1 = w[i__4].r, dabs(r__1)) + (r__2 = + r_imag(&w[i__]), dabs(r__2)) < (r__3 = + w[i__5].r, dabs(r__3)) + (r__4 = + r_imag(&w[i__ + 1]), dabs(r__4))) { + sorted = FALSE_; + i__4 = i__; + swap.r = w[i__4].r, swap.i = w[i__4].i; + i__4 = i__; + i__5 = i__ + 1; + w[i__4].r = w[i__5].r, w[i__4].i = w[i__5] + .i; + i__4 = i__ + 1; + w[i__4].r = swap.r, w[i__4].i = swap.i; + } +/* L40: */ + } +/* L50: */ + } +L60: + ; + } + } + +/* + ==== If there are only two shifts, then use + . only one. ==== +*/ + + if (kbot - ks + 1 == 2) { + i__2 = kbot; + i__3 = kbot + kbot * h_dim1; + q__2.r = w[i__2].r - h__[i__3].r, q__2.i = w[i__2].i - + h__[i__3].i; + q__1.r = q__2.r, q__1.i = q__2.i; + i__4 = kbot - 1; + i__5 = kbot + kbot * h_dim1; + q__4.r = w[i__4].r - h__[i__5].r, q__4.i = w[i__4].i - + h__[i__5].i; + q__3.r = q__4.r, q__3.i = q__4.i; + if ((r__1 = q__1.r, dabs(r__1)) + (r__2 = r_imag(&q__1), + dabs(r__2)) < (r__3 = q__3.r, dabs(r__3)) + (r__4 + = r_imag(&q__3), dabs(r__4))) { + i__2 = kbot - 1; + i__3 = kbot; + w[i__2].r = w[i__3].r, w[i__2].i = w[i__3].i; + } else { + i__2 = kbot; + i__3 = kbot - 1; + w[i__2].r = w[i__3].r, w[i__2].i = w[i__3].i; + } + } + +/* + ==== Use up to NS of the the smallest magnatiude + . shifts. If there aren't NS shifts available, + . then use them all, possibly dropping one to + . make the number of shifts even. ==== + + Computing MIN +*/ + i__2 = ns, i__3 = kbot - ks + 1; + ns = min(i__2,i__3); + ns -= ns % 2; + ks = kbot - ns + 1; + +/* + ==== Small-bulge multi-shift QR sweep: + . split workspace under the subdiagonal into + . - a KDU-by-KDU work array U in the lower + . left-hand-corner, + . - a KDU-by-at-least-KDU-but-more-is-better + . (KDU-by-NHo) horizontal work array WH along + . the bottom edge, + . - and an at-least-KDU-but-more-is-better-by-KDU + . (NVE-by-KDU) vertical work WV arrow along + . the left-hand-edge. ==== +*/ + + kdu = ns * 3 - 3; + ku = *n - kdu + 1; + kwh = kdu + 1; + nho = *n - kdu - 3 - (kdu + 1) + 1; + kwv = kdu + 4; + nve = *n - kdu - kwv + 1; + +/* ==== Small-bulge multi-shift QR sweep ==== */ + + claqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &w[ks], & + h__[h_offset], ldh, iloz, ihiz, &z__[z_offset], ldz, & + work[1], &c__3, &h__[ku + h_dim1], ldh, &nve, &h__[ + kwv + h_dim1], ldh, &nho, &h__[ku + kwh * h_dim1], + ldh); + } + +/* ==== Note progress (or the lack of it). ==== */ + + if (ld > 0) { + ndfl = 1; + } else { + ++ndfl; + } + +/* + ==== End of main loop ==== + L70: +*/ + } + +/* + ==== Iteration limit exceeded. Set INFO to show where + . the problem occurred and exit. ==== +*/ + + *info = kbot; +L80: + ; + } + +/* ==== Return the optimal value of LWORK. ==== */ + + r__1 = (real) lwkopt; + q__1.r = r__1, q__1.i = 0.f; + work[1].r = q__1.r, work[1].i = q__1.i; + +/* ==== End of CLAQR4 ==== */ + + return 0; +} /* claqr4_ */ + +/* Subroutine */ int claqr5_(logical *wantt, logical *wantz, integer *kacc22, + integer *n, integer *ktop, integer *kbot, integer *nshfts, complex *s, + complex *h__, integer *ldh, integer *iloz, integer *ihiz, complex * + z__, integer *ldz, complex *v, integer *ldv, complex *u, integer *ldu, + integer *nv, complex *wv, integer *ldwv, integer *nh, complex *wh, + integer *ldwh) +{ + /* System generated locals */ + integer h_dim1, h_offset, u_dim1, u_offset, v_dim1, v_offset, wh_dim1, + wh_offset, wv_dim1, wv_offset, z_dim1, z_offset, i__1, i__2, i__3, + i__4, i__5, i__6, i__7, i__8, i__9, i__10, i__11; + real r__1, r__2, r__3, r__4, r__5, r__6, r__7, r__8, r__9, r__10; + complex q__1, q__2, q__3, q__4, q__5, q__6, q__7, q__8; + + /* Local variables */ + static integer j, k, m, i2, j2, i4, j4, k1; + static real h11, h12, h21, h22; + static integer m22, ns, nu; + static complex vt[3]; + static real scl; + static integer kdu, kms; + static real ulp; + static integer knz, kzs; + static real tst1, tst2; + static complex beta; + static logical blk22, bmp22; + static integer mend, jcol, jlen, jbot, mbot, jtop, jrow, mtop; + static complex alpha; + static logical accum; + extern /* Subroutine */ int cgemm_(char *, char *, integer *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *); + static integer ndcol, incol, krcol, nbmps; + extern /* Subroutine */ int ctrmm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *), claqr1_(integer *, + complex *, integer *, complex *, complex *, complex *), slabad_( + real *, real *), clarfg_(integer *, complex *, complex *, integer + *, complex *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int clacpy_(char *, integer *, integer *, complex + *, integer *, complex *, integer *), claset_(char *, + integer *, integer *, complex *, complex *, complex *, integer *); + static real safmin, safmax; + static complex refsum; + static integer mstart; + static real smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + This auxiliary subroutine called by CLAQR0 performs a + single small-bulge multi-shift QR sweep. + + WANTT (input) logical scalar + WANTT = .true. if the triangular Schur factor + is being computed. WANTT is set to .false. otherwise. + + WANTZ (input) logical scalar + WANTZ = .true. if the unitary Schur factor is being + computed. WANTZ is set to .false. otherwise. + + KACC22 (input) integer with value 0, 1, or 2. + Specifies the computation mode of far-from-diagonal + orthogonal updates. + = 0: CLAQR5 does not accumulate reflections and does not + use matrix-matrix multiply to update far-from-diagonal + matrix entries. + = 1: CLAQR5 accumulates reflections and uses matrix-matrix + multiply to update the far-from-diagonal matrix entries. + = 2: CLAQR5 accumulates reflections, uses matrix-matrix + multiply to update the far-from-diagonal matrix entries, + and takes advantage of 2-by-2 block structure during + matrix multiplies. + + N (input) integer scalar + N is the order of the Hessenberg matrix H upon which this + subroutine operates. + + KTOP (input) integer scalar + KBOT (input) integer scalar + These are the first and last rows and columns of an + isolated diagonal block upon which the QR sweep is to be + applied. It is assumed without a check that + either KTOP = 1 or H(KTOP,KTOP-1) = 0 + and + either KBOT = N or H(KBOT+1,KBOT) = 0. + + NSHFTS (input) integer scalar + NSHFTS gives the number of simultaneous shifts. NSHFTS + must be positive and even. + + S (input/output) COMPLEX array of size (NSHFTS) + S contains the shifts of origin that define the multi- + shift QR sweep. On output S may be reordered. + + H (input/output) COMPLEX array of size (LDH,N) + On input H contains a Hessenberg matrix. On output a + multi-shift QR sweep with shifts SR(J)+i*SI(J) is applied + to the isolated diagonal block in rows and columns KTOP + through KBOT. + + LDH (input) integer scalar + LDH is the leading dimension of H just as declared in the + calling procedure. LDH.GE.MAX(1,N). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N + + Z (input/output) COMPLEX array of size (LDZ,IHI) + If WANTZ = .TRUE., then the QR Sweep unitary + similarity transformation is accumulated into + Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ = .FALSE., then Z is unreferenced. + + LDZ (input) integer scalar + LDA is the leading dimension of Z just as declared in + the calling procedure. LDZ.GE.N. + + V (workspace) COMPLEX array of size (LDV,NSHFTS/2) + + LDV (input) integer scalar + LDV is the leading dimension of V as declared in the + calling procedure. LDV.GE.3. + + U (workspace) COMPLEX array of size + (LDU,3*NSHFTS-3) + + LDU (input) integer scalar + LDU is the leading dimension of U just as declared in the + in the calling subroutine. LDU.GE.3*NSHFTS-3. + + NH (input) integer scalar + NH is the number of columns in array WH available for + workspace. NH.GE.1. + + WH (workspace) COMPLEX array of size (LDWH,NH) + + LDWH (input) integer scalar + Leading dimension of WH just as declared in the + calling procedure. LDWH.GE.3*NSHFTS-3. + + NV (input) integer scalar + NV is the number of rows in WV agailable for workspace. + NV.GE.1. + + WV (workspace) COMPLEX array of size + (LDWV,3*NSHFTS-3) + + LDWV (input) integer scalar + LDWV is the leading dimension of WV as declared in the + in the calling subroutine. LDWV.GE.NV. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + Reference: + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and + Level 3 Performance, SIAM Journal of Matrix Analysis, + volume 23, pages 929--947, 2002. + + ================================================================ + + + ==== If there are no shifts, then there is nothing to do. ==== +*/ + + /* Parameter adjustments */ + --s; + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + wh_dim1 = *ldwh; + wh_offset = 1 + wh_dim1; + wh -= wh_offset; + + /* Function Body */ + if (*nshfts < 2) { + return 0; + } + +/* + ==== If the active block is empty or 1-by-1, then there + . is nothing to do. ==== +*/ + + if (*ktop >= *kbot) { + return 0; + } + +/* + ==== NSHFTS is supposed to be even, but if it is odd, + . then simply reduce it by one. ==== +*/ + + ns = *nshfts - *nshfts % 2; + +/* ==== Machine constants for deflation ==== */ + + safmin = slamch_("SAFE MINIMUM"); + safmax = 1.f / safmin; + slabad_(&safmin, &safmax); + ulp = slamch_("PRECISION"); + smlnum = safmin * ((real) (*n) / ulp); + +/* + ==== Use accumulated reflections to update far-from-diagonal + . entries ? ==== +*/ + + accum = *kacc22 == 1 || *kacc22 == 2; + +/* ==== If so, exploit the 2-by-2 block structure? ==== */ + + blk22 = ns > 2 && *kacc22 == 2; + +/* ==== clear trash ==== */ + + if (*ktop + 2 <= *kbot) { + i__1 = *ktop + 2 + *ktop * h_dim1; + h__[i__1].r = 0.f, h__[i__1].i = 0.f; + } + +/* ==== NBMPS = number of 2-shift bulges in the chain ==== */ + + nbmps = ns / 2; + +/* ==== KDU = width of slab ==== */ + + kdu = nbmps * 6 - 3; + +/* ==== Create and chase chains of NBMPS bulges ==== */ + + i__1 = *kbot - 2; + i__2 = nbmps * 3 - 2; + for (incol = (1 - nbmps) * 3 + *ktop - 1; i__2 < 0 ? incol >= i__1 : + incol <= i__1; incol += i__2) { + ndcol = incol + kdu; + if (accum) { + claset_("ALL", &kdu, &kdu, &c_b56, &c_b57, &u[u_offset], ldu); + } + +/* + ==== Near-the-diagonal bulge chase. The following loop + . performs the near-the-diagonal part of a small bulge + . multi-shift QR sweep. Each 6*NBMPS-2 column diagonal + . chunk extends from column INCOL to column NDCOL + . (including both column INCOL and column NDCOL). The + . following loop chases a 3*NBMPS column long chain of + . NBMPS bulges 3*NBMPS-2 columns to the right. (INCOL + . may be less than KTOP and and NDCOL may be greater than + . KBOT indicating phantom columns from which to chase + . bulges before they are actually introduced or to which + . to chase bulges beyond column KBOT.) ==== + + Computing MIN +*/ + i__4 = incol + nbmps * 3 - 3, i__5 = *kbot - 2; + i__3 = min(i__4,i__5); + for (krcol = incol; krcol <= i__3; ++krcol) { + +/* + ==== Bulges number MTOP to MBOT are active double implicit + . shift bulges. There may or may not also be small + . 2-by-2 bulge, if there is room. The inactive bulges + . (if any) must wait until the active bulges have moved + . down the diagonal to make room. The phantom matrix + . paradigm described above helps keep track. ==== + + Computing MAX +*/ + i__4 = 1, i__5 = (*ktop - 1 - krcol + 2) / 3 + 1; + mtop = max(i__4,i__5); +/* Computing MIN */ + i__4 = nbmps, i__5 = (*kbot - krcol) / 3; + mbot = min(i__4,i__5); + m22 = mbot + 1; + bmp22 = mbot < nbmps && krcol + (m22 - 1) * 3 == *kbot - 2; + +/* + ==== Generate reflections to chase the chain right + . one column. (The minimum value of K is KTOP-1.) ==== +*/ + + i__4 = mbot; + for (m = mtop; m <= i__4; ++m) { + k = krcol + (m - 1) * 3; + if (k == *ktop - 1) { + claqr1_(&c__3, &h__[*ktop + *ktop * h_dim1], ldh, &s[(m << + 1) - 1], &s[m * 2], &v[m * v_dim1 + 1]); + i__5 = m * v_dim1 + 1; + alpha.r = v[i__5].r, alpha.i = v[i__5].i; + clarfg_(&c__3, &alpha, &v[m * v_dim1 + 2], &c__1, &v[m * + v_dim1 + 1]); + } else { + i__5 = k + 1 + k * h_dim1; + beta.r = h__[i__5].r, beta.i = h__[i__5].i; + i__5 = m * v_dim1 + 2; + i__6 = k + 2 + k * h_dim1; + v[i__5].r = h__[i__6].r, v[i__5].i = h__[i__6].i; + i__5 = m * v_dim1 + 3; + i__6 = k + 3 + k * h_dim1; + v[i__5].r = h__[i__6].r, v[i__5].i = h__[i__6].i; + clarfg_(&c__3, &beta, &v[m * v_dim1 + 2], &c__1, &v[m * + v_dim1 + 1]); + +/* + ==== A Bulge may collapse because of vigilant + . deflation or destructive underflow. In the + . underflow case, try the two-small-subdiagonals + . trick to try to reinflate the bulge. ==== +*/ + + i__5 = k + 3 + k * h_dim1; + i__6 = k + 3 + (k + 1) * h_dim1; + i__7 = k + 3 + (k + 2) * h_dim1; + if (h__[i__5].r != 0.f || h__[i__5].i != 0.f || (h__[i__6] + .r != 0.f || h__[i__6].i != 0.f) || h__[i__7].r == + 0.f && h__[i__7].i == 0.f) { + +/* ==== Typical case: not collapsed (yet). ==== */ + + i__5 = k + 1 + k * h_dim1; + h__[i__5].r = beta.r, h__[i__5].i = beta.i; + i__5 = k + 2 + k * h_dim1; + h__[i__5].r = 0.f, h__[i__5].i = 0.f; + i__5 = k + 3 + k * h_dim1; + h__[i__5].r = 0.f, h__[i__5].i = 0.f; + } else { + +/* + ==== Atypical case: collapsed. Attempt to + . reintroduce ignoring H(K+1,K) and H(K+2,K). + . If the fill resulting from the new + . reflector is too large, then abandon it. + . Otherwise, use the new one. ==== +*/ + + claqr1_(&c__3, &h__[k + 1 + (k + 1) * h_dim1], ldh, & + s[(m << 1) - 1], &s[m * 2], vt); + alpha.r = vt[0].r, alpha.i = vt[0].i; + clarfg_(&c__3, &alpha, &vt[1], &c__1, vt); + r_cnjg(&q__2, vt); + i__5 = k + 1 + k * h_dim1; + r_cnjg(&q__5, &vt[1]); + i__6 = k + 2 + k * h_dim1; + q__4.r = q__5.r * h__[i__6].r - q__5.i * h__[i__6].i, + q__4.i = q__5.r * h__[i__6].i + q__5.i * h__[ + i__6].r; + q__3.r = h__[i__5].r + q__4.r, q__3.i = h__[i__5].i + + q__4.i; + q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, q__1.i = + q__2.r * q__3.i + q__2.i * q__3.r; + refsum.r = q__1.r, refsum.i = q__1.i; + + i__5 = k + 2 + k * h_dim1; + q__3.r = refsum.r * vt[1].r - refsum.i * vt[1].i, + q__3.i = refsum.r * vt[1].i + refsum.i * vt[1] + .r; + q__2.r = h__[i__5].r - q__3.r, q__2.i = h__[i__5].i - + q__3.i; + q__1.r = q__2.r, q__1.i = q__2.i; + q__5.r = refsum.r * vt[2].r - refsum.i * vt[2].i, + q__5.i = refsum.r * vt[2].i + refsum.i * vt[2] + .r; + q__4.r = q__5.r, q__4.i = q__5.i; + i__6 = k + k * h_dim1; + i__7 = k + 1 + (k + 1) * h_dim1; + i__8 = k + 2 + (k + 2) * h_dim1; + if ((r__1 = q__1.r, dabs(r__1)) + (r__2 = r_imag(& + q__1), dabs(r__2)) + ((r__3 = q__4.r, dabs( + r__3)) + (r__4 = r_imag(&q__4), dabs(r__4))) + > ulp * ((r__5 = h__[i__6].r, dabs(r__5)) + ( + r__6 = r_imag(&h__[k + k * h_dim1]), dabs( + r__6)) + ((r__7 = h__[i__7].r, dabs(r__7)) + ( + r__8 = r_imag(&h__[k + 1 + (k + 1) * h_dim1]), + dabs(r__8))) + ((r__9 = h__[i__8].r, dabs( + r__9)) + (r__10 = r_imag(&h__[k + 2 + (k + 2) + * h_dim1]), dabs(r__10))))) { + +/* + ==== Starting a new bulge here would + . create non-negligible fill. Use + . the old one with trepidation. ==== +*/ + + i__5 = k + 1 + k * h_dim1; + h__[i__5].r = beta.r, h__[i__5].i = beta.i; + i__5 = k + 2 + k * h_dim1; + h__[i__5].r = 0.f, h__[i__5].i = 0.f; + i__5 = k + 3 + k * h_dim1; + h__[i__5].r = 0.f, h__[i__5].i = 0.f; + } else { + +/* + ==== Stating a new bulge here would + . create only negligible fill. + . Replace the old reflector with + . the new one. ==== +*/ + + i__5 = k + 1 + k * h_dim1; + i__6 = k + 1 + k * h_dim1; + q__1.r = h__[i__6].r - refsum.r, q__1.i = h__[ + i__6].i - refsum.i; + h__[i__5].r = q__1.r, h__[i__5].i = q__1.i; + i__5 = k + 2 + k * h_dim1; + h__[i__5].r = 0.f, h__[i__5].i = 0.f; + i__5 = k + 3 + k * h_dim1; + h__[i__5].r = 0.f, h__[i__5].i = 0.f; + i__5 = m * v_dim1 + 1; + v[i__5].r = vt[0].r, v[i__5].i = vt[0].i; + i__5 = m * v_dim1 + 2; + v[i__5].r = vt[1].r, v[i__5].i = vt[1].i; + i__5 = m * v_dim1 + 3; + v[i__5].r = vt[2].r, v[i__5].i = vt[2].i; + } + } + } +/* L10: */ + } + +/* ==== Generate a 2-by-2 reflection, if needed. ==== */ + + k = krcol + (m22 - 1) * 3; + if (bmp22) { + if (k == *ktop - 1) { + claqr1_(&c__2, &h__[k + 1 + (k + 1) * h_dim1], ldh, &s[( + m22 << 1) - 1], &s[m22 * 2], &v[m22 * v_dim1 + 1]) + ; + i__4 = m22 * v_dim1 + 1; + beta.r = v[i__4].r, beta.i = v[i__4].i; + clarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 + * v_dim1 + 1]); + } else { + i__4 = k + 1 + k * h_dim1; + beta.r = h__[i__4].r, beta.i = h__[i__4].i; + i__4 = m22 * v_dim1 + 2; + i__5 = k + 2 + k * h_dim1; + v[i__4].r = h__[i__5].r, v[i__4].i = h__[i__5].i; + clarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 + * v_dim1 + 1]); + i__4 = k + 1 + k * h_dim1; + h__[i__4].r = beta.r, h__[i__4].i = beta.i; + i__4 = k + 2 + k * h_dim1; + h__[i__4].r = 0.f, h__[i__4].i = 0.f; + } + } + +/* ==== Multiply H by reflections from the left ==== */ + + if (accum) { + jbot = min(ndcol,*kbot); + } else if (*wantt) { + jbot = *n; + } else { + jbot = *kbot; + } + i__4 = jbot; + for (j = max(*ktop,krcol); j <= i__4; ++j) { +/* Computing MIN */ + i__5 = mbot, i__6 = (j - krcol + 2) / 3; + mend = min(i__5,i__6); + i__5 = mend; + for (m = mtop; m <= i__5; ++m) { + k = krcol + (m - 1) * 3; + r_cnjg(&q__2, &v[m * v_dim1 + 1]); + i__6 = k + 1 + j * h_dim1; + r_cnjg(&q__6, &v[m * v_dim1 + 2]); + i__7 = k + 2 + j * h_dim1; + q__5.r = q__6.r * h__[i__7].r - q__6.i * h__[i__7].i, + q__5.i = q__6.r * h__[i__7].i + q__6.i * h__[i__7] + .r; + q__4.r = h__[i__6].r + q__5.r, q__4.i = h__[i__6].i + + q__5.i; + r_cnjg(&q__8, &v[m * v_dim1 + 3]); + i__8 = k + 3 + j * h_dim1; + q__7.r = q__8.r * h__[i__8].r - q__8.i * h__[i__8].i, + q__7.i = q__8.r * h__[i__8].i + q__8.i * h__[i__8] + .r; + q__3.r = q__4.r + q__7.r, q__3.i = q__4.i + q__7.i; + q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, q__1.i = + q__2.r * q__3.i + q__2.i * q__3.r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__6 = k + 1 + j * h_dim1; + i__7 = k + 1 + j * h_dim1; + q__1.r = h__[i__7].r - refsum.r, q__1.i = h__[i__7].i - + refsum.i; + h__[i__6].r = q__1.r, h__[i__6].i = q__1.i; + i__6 = k + 2 + j * h_dim1; + i__7 = k + 2 + j * h_dim1; + i__8 = m * v_dim1 + 2; + q__2.r = refsum.r * v[i__8].r - refsum.i * v[i__8].i, + q__2.i = refsum.r * v[i__8].i + refsum.i * v[i__8] + .r; + q__1.r = h__[i__7].r - q__2.r, q__1.i = h__[i__7].i - + q__2.i; + h__[i__6].r = q__1.r, h__[i__6].i = q__1.i; + i__6 = k + 3 + j * h_dim1; + i__7 = k + 3 + j * h_dim1; + i__8 = m * v_dim1 + 3; + q__2.r = refsum.r * v[i__8].r - refsum.i * v[i__8].i, + q__2.i = refsum.r * v[i__8].i + refsum.i * v[i__8] + .r; + q__1.r = h__[i__7].r - q__2.r, q__1.i = h__[i__7].i - + q__2.i; + h__[i__6].r = q__1.r, h__[i__6].i = q__1.i; +/* L20: */ + } +/* L30: */ + } + if (bmp22) { + k = krcol + (m22 - 1) * 3; +/* Computing MAX */ + i__4 = k + 1; + i__5 = jbot; + for (j = max(i__4,*ktop); j <= i__5; ++j) { + r_cnjg(&q__2, &v[m22 * v_dim1 + 1]); + i__4 = k + 1 + j * h_dim1; + r_cnjg(&q__5, &v[m22 * v_dim1 + 2]); + i__6 = k + 2 + j * h_dim1; + q__4.r = q__5.r * h__[i__6].r - q__5.i * h__[i__6].i, + q__4.i = q__5.r * h__[i__6].i + q__5.i * h__[i__6] + .r; + q__3.r = h__[i__4].r + q__4.r, q__3.i = h__[i__4].i + + q__4.i; + q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, q__1.i = + q__2.r * q__3.i + q__2.i * q__3.r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__4 = k + 1 + j * h_dim1; + i__6 = k + 1 + j * h_dim1; + q__1.r = h__[i__6].r - refsum.r, q__1.i = h__[i__6].i - + refsum.i; + h__[i__4].r = q__1.r, h__[i__4].i = q__1.i; + i__4 = k + 2 + j * h_dim1; + i__6 = k + 2 + j * h_dim1; + i__7 = m22 * v_dim1 + 2; + q__2.r = refsum.r * v[i__7].r - refsum.i * v[i__7].i, + q__2.i = refsum.r * v[i__7].i + refsum.i * v[i__7] + .r; + q__1.r = h__[i__6].r - q__2.r, q__1.i = h__[i__6].i - + q__2.i; + h__[i__4].r = q__1.r, h__[i__4].i = q__1.i; +/* L40: */ + } + } + +/* + ==== Multiply H by reflections from the right. + . Delay filling in the last row until the + . vigilant deflation check is complete. ==== +*/ + + if (accum) { + jtop = max(*ktop,incol); + } else if (*wantt) { + jtop = 1; + } else { + jtop = *ktop; + } + i__5 = mbot; + for (m = mtop; m <= i__5; ++m) { + i__4 = m * v_dim1 + 1; + if (v[i__4].r != 0.f || v[i__4].i != 0.f) { + k = krcol + (m - 1) * 3; +/* Computing MIN */ + i__6 = *kbot, i__7 = k + 3; + i__4 = min(i__6,i__7); + for (j = jtop; j <= i__4; ++j) { + i__6 = m * v_dim1 + 1; + i__7 = j + (k + 1) * h_dim1; + i__8 = m * v_dim1 + 2; + i__9 = j + (k + 2) * h_dim1; + q__4.r = v[i__8].r * h__[i__9].r - v[i__8].i * h__[ + i__9].i, q__4.i = v[i__8].r * h__[i__9].i + v[ + i__8].i * h__[i__9].r; + q__3.r = h__[i__7].r + q__4.r, q__3.i = h__[i__7].i + + q__4.i; + i__10 = m * v_dim1 + 3; + i__11 = j + (k + 3) * h_dim1; + q__5.r = v[i__10].r * h__[i__11].r - v[i__10].i * h__[ + i__11].i, q__5.i = v[i__10].r * h__[i__11].i + + v[i__10].i * h__[i__11].r; + q__2.r = q__3.r + q__5.r, q__2.i = q__3.i + q__5.i; + q__1.r = v[i__6].r * q__2.r - v[i__6].i * q__2.i, + q__1.i = v[i__6].r * q__2.i + v[i__6].i * + q__2.r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__6 = j + (k + 1) * h_dim1; + i__7 = j + (k + 1) * h_dim1; + q__1.r = h__[i__7].r - refsum.r, q__1.i = h__[i__7].i + - refsum.i; + h__[i__6].r = q__1.r, h__[i__6].i = q__1.i; + i__6 = j + (k + 2) * h_dim1; + i__7 = j + (k + 2) * h_dim1; + r_cnjg(&q__3, &v[m * v_dim1 + 2]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, + q__2.i = refsum.r * q__3.i + refsum.i * + q__3.r; + q__1.r = h__[i__7].r - q__2.r, q__1.i = h__[i__7].i - + q__2.i; + h__[i__6].r = q__1.r, h__[i__6].i = q__1.i; + i__6 = j + (k + 3) * h_dim1; + i__7 = j + (k + 3) * h_dim1; + r_cnjg(&q__3, &v[m * v_dim1 + 3]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, + q__2.i = refsum.r * q__3.i + refsum.i * + q__3.r; + q__1.r = h__[i__7].r - q__2.r, q__1.i = h__[i__7].i - + q__2.i; + h__[i__6].r = q__1.r, h__[i__6].i = q__1.i; +/* L50: */ + } + + if (accum) { + +/* + ==== Accumulate U. (If necessary, update Z later + . with with an efficient matrix-matrix + . multiply.) ==== +*/ + + kms = k - incol; +/* Computing MAX */ + i__4 = 1, i__6 = *ktop - incol; + i__7 = kdu; + for (j = max(i__4,i__6); j <= i__7; ++j) { + i__4 = m * v_dim1 + 1; + i__6 = j + (kms + 1) * u_dim1; + i__8 = m * v_dim1 + 2; + i__9 = j + (kms + 2) * u_dim1; + q__4.r = v[i__8].r * u[i__9].r - v[i__8].i * u[ + i__9].i, q__4.i = v[i__8].r * u[i__9].i + + v[i__8].i * u[i__9].r; + q__3.r = u[i__6].r + q__4.r, q__3.i = u[i__6].i + + q__4.i; + i__10 = m * v_dim1 + 3; + i__11 = j + (kms + 3) * u_dim1; + q__5.r = v[i__10].r * u[i__11].r - v[i__10].i * u[ + i__11].i, q__5.i = v[i__10].r * u[i__11] + .i + v[i__10].i * u[i__11].r; + q__2.r = q__3.r + q__5.r, q__2.i = q__3.i + + q__5.i; + q__1.r = v[i__4].r * q__2.r - v[i__4].i * q__2.i, + q__1.i = v[i__4].r * q__2.i + v[i__4].i * + q__2.r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__4 = j + (kms + 1) * u_dim1; + i__6 = j + (kms + 1) * u_dim1; + q__1.r = u[i__6].r - refsum.r, q__1.i = u[i__6].i + - refsum.i; + u[i__4].r = q__1.r, u[i__4].i = q__1.i; + i__4 = j + (kms + 2) * u_dim1; + i__6 = j + (kms + 2) * u_dim1; + r_cnjg(&q__3, &v[m * v_dim1 + 2]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, + q__2.i = refsum.r * q__3.i + refsum.i * + q__3.r; + q__1.r = u[i__6].r - q__2.r, q__1.i = u[i__6].i - + q__2.i; + u[i__4].r = q__1.r, u[i__4].i = q__1.i; + i__4 = j + (kms + 3) * u_dim1; + i__6 = j + (kms + 3) * u_dim1; + r_cnjg(&q__3, &v[m * v_dim1 + 3]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, + q__2.i = refsum.r * q__3.i + refsum.i * + q__3.r; + q__1.r = u[i__6].r - q__2.r, q__1.i = u[i__6].i - + q__2.i; + u[i__4].r = q__1.r, u[i__4].i = q__1.i; +/* L60: */ + } + } else if (*wantz) { + +/* + ==== U is not accumulated, so update Z + . now by multiplying by reflections + . from the right. ==== +*/ + + i__7 = *ihiz; + for (j = *iloz; j <= i__7; ++j) { + i__4 = m * v_dim1 + 1; + i__6 = j + (k + 1) * z_dim1; + i__8 = m * v_dim1 + 2; + i__9 = j + (k + 2) * z_dim1; + q__4.r = v[i__8].r * z__[i__9].r - v[i__8].i * + z__[i__9].i, q__4.i = v[i__8].r * z__[ + i__9].i + v[i__8].i * z__[i__9].r; + q__3.r = z__[i__6].r + q__4.r, q__3.i = z__[i__6] + .i + q__4.i; + i__10 = m * v_dim1 + 3; + i__11 = j + (k + 3) * z_dim1; + q__5.r = v[i__10].r * z__[i__11].r - v[i__10].i * + z__[i__11].i, q__5.i = v[i__10].r * z__[ + i__11].i + v[i__10].i * z__[i__11].r; + q__2.r = q__3.r + q__5.r, q__2.i = q__3.i + + q__5.i; + q__1.r = v[i__4].r * q__2.r - v[i__4].i * q__2.i, + q__1.i = v[i__4].r * q__2.i + v[i__4].i * + q__2.r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__4 = j + (k + 1) * z_dim1; + i__6 = j + (k + 1) * z_dim1; + q__1.r = z__[i__6].r - refsum.r, q__1.i = z__[ + i__6].i - refsum.i; + z__[i__4].r = q__1.r, z__[i__4].i = q__1.i; + i__4 = j + (k + 2) * z_dim1; + i__6 = j + (k + 2) * z_dim1; + r_cnjg(&q__3, &v[m * v_dim1 + 2]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, + q__2.i = refsum.r * q__3.i + refsum.i * + q__3.r; + q__1.r = z__[i__6].r - q__2.r, q__1.i = z__[i__6] + .i - q__2.i; + z__[i__4].r = q__1.r, z__[i__4].i = q__1.i; + i__4 = j + (k + 3) * z_dim1; + i__6 = j + (k + 3) * z_dim1; + r_cnjg(&q__3, &v[m * v_dim1 + 3]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, + q__2.i = refsum.r * q__3.i + refsum.i * + q__3.r; + q__1.r = z__[i__6].r - q__2.r, q__1.i = z__[i__6] + .i - q__2.i; + z__[i__4].r = q__1.r, z__[i__4].i = q__1.i; +/* L70: */ + } + } + } +/* L80: */ + } + +/* ==== Special case: 2-by-2 reflection (if needed) ==== */ + + k = krcol + (m22 - 1) * 3; + i__5 = m22 * v_dim1 + 1; + if (bmp22 && (v[i__5].r != 0.f || v[i__5].i != 0.f)) { +/* Computing MIN */ + i__7 = *kbot, i__4 = k + 3; + i__5 = min(i__7,i__4); + for (j = jtop; j <= i__5; ++j) { + i__7 = m22 * v_dim1 + 1; + i__4 = j + (k + 1) * h_dim1; + i__6 = m22 * v_dim1 + 2; + i__8 = j + (k + 2) * h_dim1; + q__3.r = v[i__6].r * h__[i__8].r - v[i__6].i * h__[i__8] + .i, q__3.i = v[i__6].r * h__[i__8].i + v[i__6].i * + h__[i__8].r; + q__2.r = h__[i__4].r + q__3.r, q__2.i = h__[i__4].i + + q__3.i; + q__1.r = v[i__7].r * q__2.r - v[i__7].i * q__2.i, q__1.i = + v[i__7].r * q__2.i + v[i__7].i * q__2.r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__7 = j + (k + 1) * h_dim1; + i__4 = j + (k + 1) * h_dim1; + q__1.r = h__[i__4].r - refsum.r, q__1.i = h__[i__4].i - + refsum.i; + h__[i__7].r = q__1.r, h__[i__7].i = q__1.i; + i__7 = j + (k + 2) * h_dim1; + i__4 = j + (k + 2) * h_dim1; + r_cnjg(&q__3, &v[m22 * v_dim1 + 2]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, q__2.i = + refsum.r * q__3.i + refsum.i * q__3.r; + q__1.r = h__[i__4].r - q__2.r, q__1.i = h__[i__4].i - + q__2.i; + h__[i__7].r = q__1.r, h__[i__7].i = q__1.i; +/* L90: */ + } + + if (accum) { + kms = k - incol; +/* Computing MAX */ + i__5 = 1, i__7 = *ktop - incol; + i__4 = kdu; + for (j = max(i__5,i__7); j <= i__4; ++j) { + i__5 = m22 * v_dim1 + 1; + i__7 = j + (kms + 1) * u_dim1; + i__6 = m22 * v_dim1 + 2; + i__8 = j + (kms + 2) * u_dim1; + q__3.r = v[i__6].r * u[i__8].r - v[i__6].i * u[i__8] + .i, q__3.i = v[i__6].r * u[i__8].i + v[i__6] + .i * u[i__8].r; + q__2.r = u[i__7].r + q__3.r, q__2.i = u[i__7].i + + q__3.i; + q__1.r = v[i__5].r * q__2.r - v[i__5].i * q__2.i, + q__1.i = v[i__5].r * q__2.i + v[i__5].i * + q__2.r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__5 = j + (kms + 1) * u_dim1; + i__7 = j + (kms + 1) * u_dim1; + q__1.r = u[i__7].r - refsum.r, q__1.i = u[i__7].i - + refsum.i; + u[i__5].r = q__1.r, u[i__5].i = q__1.i; + i__5 = j + (kms + 2) * u_dim1; + i__7 = j + (kms + 2) * u_dim1; + r_cnjg(&q__3, &v[m22 * v_dim1 + 2]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, + q__2.i = refsum.r * q__3.i + refsum.i * + q__3.r; + q__1.r = u[i__7].r - q__2.r, q__1.i = u[i__7].i - + q__2.i; + u[i__5].r = q__1.r, u[i__5].i = q__1.i; +/* L100: */ + } + } else if (*wantz) { + i__4 = *ihiz; + for (j = *iloz; j <= i__4; ++j) { + i__5 = m22 * v_dim1 + 1; + i__7 = j + (k + 1) * z_dim1; + i__6 = m22 * v_dim1 + 2; + i__8 = j + (k + 2) * z_dim1; + q__3.r = v[i__6].r * z__[i__8].r - v[i__6].i * z__[ + i__8].i, q__3.i = v[i__6].r * z__[i__8].i + v[ + i__6].i * z__[i__8].r; + q__2.r = z__[i__7].r + q__3.r, q__2.i = z__[i__7].i + + q__3.i; + q__1.r = v[i__5].r * q__2.r - v[i__5].i * q__2.i, + q__1.i = v[i__5].r * q__2.i + v[i__5].i * + q__2.r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__5 = j + (k + 1) * z_dim1; + i__7 = j + (k + 1) * z_dim1; + q__1.r = z__[i__7].r - refsum.r, q__1.i = z__[i__7].i + - refsum.i; + z__[i__5].r = q__1.r, z__[i__5].i = q__1.i; + i__5 = j + (k + 2) * z_dim1; + i__7 = j + (k + 2) * z_dim1; + r_cnjg(&q__3, &v[m22 * v_dim1 + 2]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, + q__2.i = refsum.r * q__3.i + refsum.i * + q__3.r; + q__1.r = z__[i__7].r - q__2.r, q__1.i = z__[i__7].i - + q__2.i; + z__[i__5].r = q__1.r, z__[i__5].i = q__1.i; +/* L110: */ + } + } + } + +/* ==== Vigilant deflation check ==== */ + + mstart = mtop; + if (krcol + (mstart - 1) * 3 < *ktop) { + ++mstart; + } + mend = mbot; + if (bmp22) { + ++mend; + } + if (krcol == *kbot - 2) { + ++mend; + } + i__4 = mend; + for (m = mstart; m <= i__4; ++m) { +/* Computing MIN */ + i__5 = *kbot - 1, i__7 = krcol + (m - 1) * 3; + k = min(i__5,i__7); + +/* + ==== The following convergence test requires that + . the tradition small-compared-to-nearby-diagonals + . criterion and the Ahues & Tisseur (LAWN 122, 1997) + . criteria both be satisfied. The latter improves + . accuracy in some examples. Falling back on an + . alternate convergence criterion when TST1 or TST2 + . is zero (as done here) is traditional but probably + . unnecessary. ==== +*/ + + i__5 = k + 1 + k * h_dim1; + if (h__[i__5].r != 0.f || h__[i__5].i != 0.f) { + i__5 = k + k * h_dim1; + i__7 = k + 1 + (k + 1) * h_dim1; + tst1 = (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = r_imag(& + h__[k + k * h_dim1]), dabs(r__2)) + ((r__3 = h__[ + i__7].r, dabs(r__3)) + (r__4 = r_imag(&h__[k + 1 + + (k + 1) * h_dim1]), dabs(r__4))); + if (tst1 == 0.f) { + if (k >= *ktop + 1) { + i__5 = k + (k - 1) * h_dim1; + tst1 += (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + (k - 1) * h_dim1]), dabs( + r__2)); + } + if (k >= *ktop + 2) { + i__5 = k + (k - 2) * h_dim1; + tst1 += (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + (k - 2) * h_dim1]), dabs( + r__2)); + } + if (k >= *ktop + 3) { + i__5 = k + (k - 3) * h_dim1; + tst1 += (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + (k - 3) * h_dim1]), dabs( + r__2)); + } + if (k <= *kbot - 2) { + i__5 = k + 2 + (k + 1) * h_dim1; + tst1 += (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + 2 + (k + 1) * h_dim1]), + dabs(r__2)); + } + if (k <= *kbot - 3) { + i__5 = k + 3 + (k + 1) * h_dim1; + tst1 += (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + 3 + (k + 1) * h_dim1]), + dabs(r__2)); + } + if (k <= *kbot - 4) { + i__5 = k + 4 + (k + 1) * h_dim1; + tst1 += (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + 4 + (k + 1) * h_dim1]), + dabs(r__2)); + } + } + i__5 = k + 1 + k * h_dim1; +/* Computing MAX */ + r__3 = smlnum, r__4 = ulp * tst1; + if ((r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = r_imag(& + h__[k + 1 + k * h_dim1]), dabs(r__2)) <= dmax( + r__3,r__4)) { +/* Computing MAX */ + i__5 = k + 1 + k * h_dim1; + i__7 = k + (k + 1) * h_dim1; + r__5 = (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + 1 + k * h_dim1]), dabs(r__2)), + r__6 = (r__3 = h__[i__7].r, dabs(r__3)) + ( + r__4 = r_imag(&h__[k + (k + 1) * h_dim1]), + dabs(r__4)); + h12 = dmax(r__5,r__6); +/* Computing MIN */ + i__5 = k + 1 + k * h_dim1; + i__7 = k + (k + 1) * h_dim1; + r__5 = (r__1 = h__[i__5].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + 1 + k * h_dim1]), dabs(r__2)), + r__6 = (r__3 = h__[i__7].r, dabs(r__3)) + ( + r__4 = r_imag(&h__[k + (k + 1) * h_dim1]), + dabs(r__4)); + h21 = dmin(r__5,r__6); + i__5 = k + k * h_dim1; + i__7 = k + 1 + (k + 1) * h_dim1; + q__2.r = h__[i__5].r - h__[i__7].r, q__2.i = h__[i__5] + .i - h__[i__7].i; + q__1.r = q__2.r, q__1.i = q__2.i; +/* Computing MAX */ + i__6 = k + 1 + (k + 1) * h_dim1; + r__5 = (r__1 = h__[i__6].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + 1 + (k + 1) * h_dim1]), dabs( + r__2)), r__6 = (r__3 = q__1.r, dabs(r__3)) + ( + r__4 = r_imag(&q__1), dabs(r__4)); + h11 = dmax(r__5,r__6); + i__5 = k + k * h_dim1; + i__7 = k + 1 + (k + 1) * h_dim1; + q__2.r = h__[i__5].r - h__[i__7].r, q__2.i = h__[i__5] + .i - h__[i__7].i; + q__1.r = q__2.r, q__1.i = q__2.i; +/* Computing MIN */ + i__6 = k + 1 + (k + 1) * h_dim1; + r__5 = (r__1 = h__[i__6].r, dabs(r__1)) + (r__2 = + r_imag(&h__[k + 1 + (k + 1) * h_dim1]), dabs( + r__2)), r__6 = (r__3 = q__1.r, dabs(r__3)) + ( + r__4 = r_imag(&q__1), dabs(r__4)); + h22 = dmin(r__5,r__6); + scl = h11 + h12; + tst2 = h22 * (h11 / scl); + +/* Computing MAX */ + r__1 = smlnum, r__2 = ulp * tst2; + if (tst2 == 0.f || h21 * (h12 / scl) <= dmax(r__1, + r__2)) { + i__5 = k + 1 + k * h_dim1; + h__[i__5].r = 0.f, h__[i__5].i = 0.f; + } + } + } +/* L120: */ + } + +/* + ==== Fill in the last row of each bulge. ==== + + Computing MIN +*/ + i__4 = nbmps, i__5 = (*kbot - krcol - 1) / 3; + mend = min(i__4,i__5); + i__4 = mend; + for (m = mtop; m <= i__4; ++m) { + k = krcol + (m - 1) * 3; + i__5 = m * v_dim1 + 1; + i__7 = m * v_dim1 + 3; + q__2.r = v[i__5].r * v[i__7].r - v[i__5].i * v[i__7].i, + q__2.i = v[i__5].r * v[i__7].i + v[i__5].i * v[i__7] + .r; + i__6 = k + 4 + (k + 3) * h_dim1; + q__1.r = q__2.r * h__[i__6].r - q__2.i * h__[i__6].i, q__1.i = + q__2.r * h__[i__6].i + q__2.i * h__[i__6].r; + refsum.r = q__1.r, refsum.i = q__1.i; + i__5 = k + 4 + (k + 1) * h_dim1; + q__1.r = -refsum.r, q__1.i = -refsum.i; + h__[i__5].r = q__1.r, h__[i__5].i = q__1.i; + i__5 = k + 4 + (k + 2) * h_dim1; + q__2.r = -refsum.r, q__2.i = -refsum.i; + r_cnjg(&q__3, &v[m * v_dim1 + 2]); + q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, q__1.i = q__2.r * + q__3.i + q__2.i * q__3.r; + h__[i__5].r = q__1.r, h__[i__5].i = q__1.i; + i__5 = k + 4 + (k + 3) * h_dim1; + i__7 = k + 4 + (k + 3) * h_dim1; + r_cnjg(&q__3, &v[m * v_dim1 + 3]); + q__2.r = refsum.r * q__3.r - refsum.i * q__3.i, q__2.i = + refsum.r * q__3.i + refsum.i * q__3.r; + q__1.r = h__[i__7].r - q__2.r, q__1.i = h__[i__7].i - q__2.i; + h__[i__5].r = q__1.r, h__[i__5].i = q__1.i; +/* L130: */ + } + +/* + ==== End of near-the-diagonal bulge chase. ==== + + L140: +*/ + } + +/* + ==== Use U (if accumulated) to update far-from-diagonal + . entries in H. If required, use U to update Z as + . well. ==== +*/ + + if (accum) { + if (*wantt) { + jtop = 1; + jbot = *n; + } else { + jtop = *ktop; + jbot = *kbot; + } + if (! blk22 || incol < *ktop || ndcol > *kbot || ns <= 2) { + +/* + ==== Updates not exploiting the 2-by-2 block + . structure of U. K1 and NU keep track of + . the location and size of U in the special + . cases of introducing bulges and chasing + . bulges off the bottom. In these special + . cases and in case the number of shifts + . is NS = 2, there is no 2-by-2 block + . structure to exploit. ==== + + Computing MAX +*/ + i__3 = 1, i__4 = *ktop - incol; + k1 = max(i__3,i__4); +/* Computing MAX */ + i__3 = 0, i__4 = ndcol - *kbot; + nu = kdu - max(i__3,i__4) - k1 + 1; + +/* ==== Horizontal Multiply ==== */ + + i__3 = jbot; + i__4 = *nh; + for (jcol = min(ndcol,*kbot) + 1; i__4 < 0 ? jcol >= i__3 : + jcol <= i__3; jcol += i__4) { +/* Computing MIN */ + i__5 = *nh, i__7 = jbot - jcol + 1; + jlen = min(i__5,i__7); + cgemm_("C", "N", &nu, &jlen, &nu, &c_b57, &u[k1 + k1 * + u_dim1], ldu, &h__[incol + k1 + jcol * h_dim1], + ldh, &c_b56, &wh[wh_offset], ldwh); + clacpy_("ALL", &nu, &jlen, &wh[wh_offset], ldwh, &h__[ + incol + k1 + jcol * h_dim1], ldh); +/* L150: */ + } + +/* ==== Vertical multiply ==== */ + + i__4 = max(*ktop,incol) - 1; + i__3 = *nv; + for (jrow = jtop; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; + jrow += i__3) { +/* Computing MIN */ + i__5 = *nv, i__7 = max(*ktop,incol) - jrow; + jlen = min(i__5,i__7); + cgemm_("N", "N", &jlen, &nu, &nu, &c_b57, &h__[jrow + ( + incol + k1) * h_dim1], ldh, &u[k1 + k1 * u_dim1], + ldu, &c_b56, &wv[wv_offset], ldwv); + clacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &h__[ + jrow + (incol + k1) * h_dim1], ldh); +/* L160: */ + } + +/* ==== Z multiply (also vertical) ==== */ + + if (*wantz) { + i__3 = *ihiz; + i__4 = *nv; + for (jrow = *iloz; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; + jrow += i__4) { +/* Computing MIN */ + i__5 = *nv, i__7 = *ihiz - jrow + 1; + jlen = min(i__5,i__7); + cgemm_("N", "N", &jlen, &nu, &nu, &c_b57, &z__[jrow + + (incol + k1) * z_dim1], ldz, &u[k1 + k1 * + u_dim1], ldu, &c_b56, &wv[wv_offset], ldwv); + clacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &z__[ + jrow + (incol + k1) * z_dim1], ldz) + ; +/* L170: */ + } + } + } else { + +/* + ==== Updates exploiting U's 2-by-2 block structure. + . (I2, I4, J2, J4 are the last rows and columns + . of the blocks.) ==== +*/ + + i2 = (kdu + 1) / 2; + i4 = kdu; + j2 = i4 - i2; + j4 = kdu; + +/* + ==== KZS and KNZ deal with the band of zeros + . along the diagonal of one of the triangular + . blocks. ==== +*/ + + kzs = j4 - j2 - (ns + 1); + knz = ns + 1; + +/* ==== Horizontal multiply ==== */ + + i__4 = jbot; + i__3 = *nh; + for (jcol = min(ndcol,*kbot) + 1; i__3 < 0 ? jcol >= i__4 : + jcol <= i__4; jcol += i__3) { +/* Computing MIN */ + i__5 = *nh, i__7 = jbot - jcol + 1; + jlen = min(i__5,i__7); + +/* + ==== Copy bottom of H to top+KZS of scratch ==== + (The first KZS rows get multiplied by zero.) ==== +*/ + + clacpy_("ALL", &knz, &jlen, &h__[incol + 1 + j2 + jcol * + h_dim1], ldh, &wh[kzs + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U21' ==== */ + + claset_("ALL", &kzs, &jlen, &c_b56, &c_b56, &wh[wh_offset] + , ldwh); + ctrmm_("L", "U", "C", "N", &knz, &jlen, &c_b57, &u[j2 + 1 + + (kzs + 1) * u_dim1], ldu, &wh[kzs + 1 + wh_dim1] + , ldwh); + +/* ==== Multiply top of H by U11' ==== */ + + cgemm_("C", "N", &i2, &jlen, &j2, &c_b57, &u[u_offset], + ldu, &h__[incol + 1 + jcol * h_dim1], ldh, &c_b57, + &wh[wh_offset], ldwh); + +/* ==== Copy top of H to bottom of WH ==== */ + + clacpy_("ALL", &j2, &jlen, &h__[incol + 1 + jcol * h_dim1] + , ldh, &wh[i2 + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U21' ==== */ + + ctrmm_("L", "L", "C", "N", &j2, &jlen, &c_b57, &u[(i2 + 1) + * u_dim1 + 1], ldu, &wh[i2 + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + cgemm_("C", "N", &i__5, &jlen, &i__7, &c_b57, &u[j2 + 1 + + (i2 + 1) * u_dim1], ldu, &h__[incol + 1 + j2 + + jcol * h_dim1], ldh, &c_b57, &wh[i2 + 1 + wh_dim1] + , ldwh); + +/* ==== Copy it back ==== */ + + clacpy_("ALL", &kdu, &jlen, &wh[wh_offset], ldwh, &h__[ + incol + 1 + jcol * h_dim1], ldh); +/* L180: */ + } + +/* ==== Vertical multiply ==== */ + + i__3 = max(incol,*ktop) - 1; + i__4 = *nv; + for (jrow = jtop; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; + jrow += i__4) { +/* Computing MIN */ + i__5 = *nv, i__7 = max(incol,*ktop) - jrow; + jlen = min(i__5,i__7); + +/* + ==== Copy right of H to scratch (the first KZS + . columns get multiplied by zero) ==== +*/ + + clacpy_("ALL", &jlen, &knz, &h__[jrow + (incol + 1 + j2) * + h_dim1], ldh, &wv[(kzs + 1) * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U21 ==== */ + + claset_("ALL", &jlen, &kzs, &c_b56, &c_b56, &wv[wv_offset] + , ldwv); + ctrmm_("R", "U", "N", "N", &jlen, &knz, &c_b57, &u[j2 + 1 + + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Multiply by U11 ==== */ + + cgemm_("N", "N", &jlen, &i2, &j2, &c_b57, &h__[jrow + ( + incol + 1) * h_dim1], ldh, &u[u_offset], ldu, & + c_b57, &wv[wv_offset], ldwv) + ; + +/* ==== Copy left of H to right of scratch ==== */ + + clacpy_("ALL", &jlen, &j2, &h__[jrow + (incol + 1) * + h_dim1], ldh, &wv[(i2 + 1) * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U21 ==== */ + + i__5 = i4 - i2; + ctrmm_("R", "L", "N", "N", &jlen, &i__5, &c_b57, &u[(i2 + + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * wv_dim1 + 1] + , ldwv); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + cgemm_("N", "N", &jlen, &i__5, &i__7, &c_b57, &h__[jrow + + (incol + 1 + j2) * h_dim1], ldh, &u[j2 + 1 + (i2 + + 1) * u_dim1], ldu, &c_b57, &wv[(i2 + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Copy it back ==== */ + + clacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, &h__[ + jrow + (incol + 1) * h_dim1], ldh); +/* L190: */ + } + +/* ==== Multiply Z (also vertical) ==== */ + + if (*wantz) { + i__4 = *ihiz; + i__3 = *nv; + for (jrow = *iloz; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; + jrow += i__3) { +/* Computing MIN */ + i__5 = *nv, i__7 = *ihiz - jrow + 1; + jlen = min(i__5,i__7); + +/* + ==== Copy right of Z to left of scratch (first + . KZS columns get multiplied by zero) ==== +*/ + + clacpy_("ALL", &jlen, &knz, &z__[jrow + (incol + 1 + + j2) * z_dim1], ldz, &wv[(kzs + 1) * wv_dim1 + + 1], ldwv); + +/* ==== Multiply by U12 ==== */ + + claset_("ALL", &jlen, &kzs, &c_b56, &c_b56, &wv[ + wv_offset], ldwv); + ctrmm_("R", "U", "N", "N", &jlen, &knz, &c_b57, &u[j2 + + 1 + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) + * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U11 ==== */ + + cgemm_("N", "N", &jlen, &i2, &j2, &c_b57, &z__[jrow + + (incol + 1) * z_dim1], ldz, &u[u_offset], ldu, + &c_b57, &wv[wv_offset], ldwv); + +/* ==== Copy left of Z to right of scratch ==== */ + + clacpy_("ALL", &jlen, &j2, &z__[jrow + (incol + 1) * + z_dim1], ldz, &wv[(i2 + 1) * wv_dim1 + 1], + ldwv); + +/* ==== Multiply by U21 ==== */ + + i__5 = i4 - i2; + ctrmm_("R", "L", "N", "N", &jlen, &i__5, &c_b57, &u[( + i2 + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + cgemm_("N", "N", &jlen, &i__5, &i__7, &c_b57, &z__[ + jrow + (incol + 1 + j2) * z_dim1], ldz, &u[j2 + + 1 + (i2 + 1) * u_dim1], ldu, &c_b57, &wv[( + i2 + 1) * wv_dim1 + 1], ldwv); + +/* ==== Copy the result back to Z ==== */ + + clacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, & + z__[jrow + (incol + 1) * z_dim1], ldz); +/* L200: */ + } + } + } + } +/* L210: */ + } + +/* ==== End of CLAQR5 ==== */ + + return 0; +} /* claqr5_ */ + +/* Subroutine */ int clarcm_(integer *m, integer *n, real *a, integer *lda, + complex *b, integer *ldb, complex *c__, integer *ldc, real *rwork) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3, i__4, i__5; + real r__1; + complex q__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLARCM performs a very simple matrix-matrix multiplication: + C := A * B, + where A is M by M and real; B is M by N and complex; + C is M by N and complex. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A and of the matrix C. + M >= 0. + + N (input) INTEGER + The number of columns and rows of the matrix B and + the number of columns of the matrix C. + N >= 0. + + A (input) REAL array, dimension (LDA, M) + A contains the M by M matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >=max(1,M). + + B (input) REAL array, dimension (LDB, N) + B contains the M by N matrix B. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >=max(1,M). + + C (input) COMPLEX array, dimension (LDC, N) + C contains the M by N matrix C. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >=max(1,M). + + RWORK (workspace) REAL array, dimension (2*M*N) + + ===================================================================== + + + Quick return if possible. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --rwork; + + /* Function Body */ + if (*m == 0 || *n == 0) { + return 0; + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + rwork[(j - 1) * *m + i__] = b[i__3].r; +/* L10: */ + } +/* L20: */ + } + + l = *m * *n + 1; + sgemm_("N", "N", m, n, m, &c_b894, &a[a_offset], lda, &rwork[1], m, & + c_b1087, &rwork[l], m); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = l + (j - 1) * *m + i__ - 1; + c__[i__3].r = rwork[i__4], c__[i__3].i = 0.f; +/* L30: */ + } +/* L40: */ + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + rwork[(j - 1) * *m + i__] = r_imag(&b[i__ + j * b_dim1]); +/* L50: */ + } +/* L60: */ + } + sgemm_("N", "N", m, n, m, &c_b894, &a[a_offset], lda, &rwork[1], m, & + c_b1087, &rwork[l], m); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + r__1 = c__[i__4].r; + i__5 = l + (j - 1) * *m + i__ - 1; + q__1.r = r__1, q__1.i = rwork[i__5]; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L70: */ + } +/* L80: */ + } + + return 0; + +/* End of CLARCM */ + +} /* clarcm_ */ + +/* Subroutine */ int clarf_(char *side, integer *m, integer *n, complex *v, + integer *incv, complex *tau, complex *c__, integer *ldc, complex * + work) +{ + /* System generated locals */ + integer c_dim1, c_offset, i__1; + complex q__1; + + /* Local variables */ + static integer i__; + static logical applyleft; + extern /* Subroutine */ int cgerc_(integer *, integer *, complex *, + complex *, integer *, complex *, integer *, complex *, integer *), + cgemv_(char *, integer *, integer *, complex *, complex *, + integer *, complex *, integer *, complex *, complex *, integer *); + extern logical lsame_(char *, char *); + static integer lastc, lastv; + extern integer ilaclc_(integer *, integer *, complex *, integer *), + ilaclr_(integer *, integer *, complex *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLARF applies a complex elementary reflector H to a complex M-by-N + matrix C, from either the left or the right. H is represented in the + form + + H = I - tau * v * v' + + where tau is a complex scalar and v is a complex vector. + + If tau = 0, then H is taken to be the unit matrix. + + To apply H' (the conjugate transpose of H), supply conjg(tau) instead + tau. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': form H * C + = 'R': form C * H + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + V (input) COMPLEX array, dimension + (1 + (M-1)*abs(INCV)) if SIDE = 'L' + or (1 + (N-1)*abs(INCV)) if SIDE = 'R' + The vector v in the representation of H. V is not used if + TAU = 0. + + INCV (input) INTEGER + The increment between elements of v. INCV <> 0. + + TAU (input) COMPLEX + The value tau in the representation of H. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by the matrix H * C if SIDE = 'L', + or C * H if SIDE = 'R'. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX array, dimension + (N) if SIDE = 'L' + or (M) if SIDE = 'R' + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --v; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + applyleft = lsame_(side, "L"); + lastv = 0; + lastc = 0; + if (tau->r != 0.f || tau->i != 0.f) { +/* + Set up variables for scanning V. LASTV begins pointing to the end + of V. +*/ + if (applyleft) { + lastv = *m; + } else { + lastv = *n; + } + if (*incv > 0) { + i__ = (lastv - 1) * *incv + 1; + } else { + i__ = 1; + } +/* Look for the last non-zero row in V. */ + for(;;) { /* while(complicated condition) */ + i__1 = i__; + if (!(lastv > 0 && (v[i__1].r == 0.f && v[i__1].i == 0.f))) + break; + --lastv; + i__ -= *incv; + } + if (applyleft) { +/* Scan for the last non-zero column in C(1:lastv,:). */ + lastc = ilaclc_(&lastv, n, &c__[c_offset], ldc); + } else { +/* Scan for the last non-zero row in C(:,1:lastv). */ + lastc = ilaclr_(m, &lastv, &c__[c_offset], ldc); + } + } +/* + Note that lastc.eq.0 renders the BLAS operations null; no special + case is needed at this level. +*/ + if (applyleft) { + +/* Form H * C */ + + if (lastv > 0) { + +/* w(1:lastc,1) := C(1:lastv,1:lastc)' * v(1:lastv,1) */ + + cgemv_("Conjugate transpose", &lastv, &lastc, &c_b57, &c__[ + c_offset], ldc, &v[1], incv, &c_b56, &work[1], &c__1); + +/* C(1:lastv,1:lastc) := C(...) - v(1:lastv,1) * w(1:lastc,1)' */ + + q__1.r = -tau->r, q__1.i = -tau->i; + cgerc_(&lastv, &lastc, &q__1, &v[1], incv, &work[1], &c__1, &c__[ + c_offset], ldc); + } + } else { + +/* Form C * H */ + + if (lastv > 0) { + +/* w(1:lastc,1) := C(1:lastc,1:lastv) * v(1:lastv,1) */ + + cgemv_("No transpose", &lastc, &lastv, &c_b57, &c__[c_offset], + ldc, &v[1], incv, &c_b56, &work[1], &c__1); + +/* C(1:lastc,1:lastv) := C(...) - w(1:lastc,1) * v(1:lastv,1)' */ + + q__1.r = -tau->r, q__1.i = -tau->i; + cgerc_(&lastc, &lastv, &q__1, &work[1], &c__1, &v[1], incv, &c__[ + c_offset], ldc); + } + } + return 0; + +/* End of CLARF */ + +} /* clarf_ */ + +/* Subroutine */ int clarfb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, complex *v, integer *ldv, + complex *t, integer *ldt, complex *c__, integer *ldc, complex *work, + integer *ldwork) +{ + /* System generated locals */ + integer c_dim1, c_offset, t_dim1, t_offset, v_dim1, v_offset, work_dim1, + work_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1, q__2; + + /* Local variables */ + static integer i__, j; + extern /* Subroutine */ int cgemm_(char *, char *, integer *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *); + extern logical lsame_(char *, char *); + static integer lastc; + extern /* Subroutine */ int ccopy_(integer *, complex *, integer *, + complex *, integer *), ctrmm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *); + static integer lastv; + extern integer ilaclc_(integer *, integer *, complex *, integer *); + extern /* Subroutine */ int clacgv_(integer *, complex *, integer *); + extern integer ilaclr_(integer *, integer *, complex *, integer *); + static char transt[1]; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLARFB applies a complex block reflector H or its transpose H' to a + complex M-by-N matrix C, from either the left or the right. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply H or H' from the Left + = 'R': apply H or H' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply H (No transpose) + = 'C': apply H' (Conjugate transpose) + + DIRECT (input) CHARACTER*1 + Indicates how H is formed from a product of elementary + reflectors + = 'F': H = H(1) H(2) . . . H(k) (Forward) + = 'B': H = H(k) . . . H(2) H(1) (Backward) + + STOREV (input) CHARACTER*1 + Indicates how the vectors which define the elementary + reflectors are stored: + = 'C': Columnwise + = 'R': Rowwise + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + K (input) INTEGER + The order of the matrix T (= the number of elementary + reflectors whose product defines the block reflector). + + V (input) COMPLEX array, dimension + (LDV,K) if STOREV = 'C' + (LDV,M) if STOREV = 'R' and SIDE = 'L' + (LDV,N) if STOREV = 'R' and SIDE = 'R' + The matrix V. See further details. + + LDV (input) INTEGER + The leading dimension of the array V. + If STOREV = 'C' and SIDE = 'L', LDV >= max(1,M); + if STOREV = 'C' and SIDE = 'R', LDV >= max(1,N); + if STOREV = 'R', LDV >= K. + + T (input) COMPLEX array, dimension (LDT,K) + The triangular K-by-K matrix T in the representation of the + block reflector. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= K. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by H*C or H'*C or C*H or C*H'. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX array, dimension (LDWORK,K) + + LDWORK (input) INTEGER + The leading dimension of the array WORK. + If SIDE = 'L', LDWORK >= max(1,N); + if SIDE = 'R', LDWORK >= max(1,M). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + work_dim1 = *ldwork; + work_offset = 1 + work_dim1; + work -= work_offset; + + /* Function Body */ + if (*m <= 0 || *n <= 0) { + return 0; + } + + if (lsame_(trans, "N")) { + *(unsigned char *)transt = 'C'; + } else { + *(unsigned char *)transt = 'N'; + } + + if (lsame_(storev, "C")) { + + if (lsame_(direct, "F")) { + +/* + Let V = ( V1 ) (first K rows) + ( V2 ) + where V1 is unit lower triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaclr_(m, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaclc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK) + + W := C1' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + ccopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 + + 1], &c__1); + clacgv_(&lastc, &work[j * work_dim1 + 1], &c__1); +/* L10: */ + } + +/* W := W * V1 */ + + ctrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b57, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2'*V2 */ + + i__1 = lastv - *k; + cgemm_("Conjugate transpose", "No transpose", &lastc, k, & + i__1, &c_b57, &c__[*k + 1 + c_dim1], ldc, &v[*k + + 1 + v_dim1], ldv, &c_b57, &work[work_offset], + ldwork); + } + +/* W := W * T' or W * T */ + + ctrmm_("Right", "Upper", transt, "Non-unit", &lastc, k, & + c_b57, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V * W' */ + + if (*m > *k) { + +/* C2 := C2 - V2 * W' */ + + i__1 = lastv - *k; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "Conjugate transpose", &i__1, & + lastc, k, &q__1, &v[*k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork, &c_b57, &c__[*k + 1 + + c_dim1], ldc); + } + +/* W := W * V1' */ + + ctrmm_("Right", "Lower", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[v_offset], ldv, &work[ + work_offset], ldwork); + +/* C1 := C1 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ * c_dim1; + i__4 = j + i__ * c_dim1; + r_cnjg(&q__2, &work[i__ + j * work_dim1]); + q__1.r = c__[i__4].r - q__2.r, q__1.i = c__[i__4].i - + q__2.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L20: */ + } +/* L30: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaclr_(n, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaclr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V = (C1*V1 + C2*V2) (stored in WORK) + + W := C1 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + ccopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * + work_dim1 + 1], &c__1); +/* L40: */ + } + +/* W := W * V1 */ + + ctrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b57, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2 * V2 */ + + i__1 = lastv - *k; + cgemm_("No transpose", "No transpose", &lastc, k, &i__1, & + c_b57, &c__[(*k + 1) * c_dim1 + 1], ldc, &v[*k + + 1 + v_dim1], ldv, &c_b57, &work[work_offset], + ldwork); + } + +/* W := W * T or W * T' */ + + ctrmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b57, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V' */ + + if (lastv > *k) { + +/* C2 := C2 - W * V2' */ + + i__1 = lastv - *k; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "Conjugate transpose", &lastc, & + i__1, k, &q__1, &work[work_offset], ldwork, &v[*k + + 1 + v_dim1], ldv, &c_b57, &c__[(*k + 1) * + c_dim1 + 1], ldc); + } + +/* W := W * V1' */ + + ctrmm_("Right", "Lower", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[v_offset], ldv, &work[ + work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * work_dim1; + q__1.r = c__[i__4].r - work[i__5].r, q__1.i = c__[ + i__4].i - work[i__5].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L50: */ + } +/* L60: */ + } + } + + } else { + +/* + Let V = ( V1 ) + ( V2 ) (last K rows) + where V2 is unit upper triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaclr_(m, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaclc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK) + + W := C2' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + ccopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[ + j * work_dim1 + 1], &c__1); + clacgv_(&lastc, &work[j * work_dim1 + 1], &c__1); +/* L70: */ + } + +/* W := W * V2 */ + + ctrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b57, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1'*V1 */ + + i__1 = lastv - *k; + cgemm_("Conjugate transpose", "No transpose", &lastc, k, & + i__1, &c_b57, &c__[c_offset], ldc, &v[v_offset], + ldv, &c_b57, &work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + ctrmm_("Right", "Lower", transt, "Non-unit", &lastc, k, & + c_b57, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V * W' */ + + if (lastv > *k) { + +/* C1 := C1 - V1 * W' */ + + i__1 = lastv - *k; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "Conjugate transpose", &i__1, & + lastc, k, &q__1, &v[v_offset], ldv, &work[ + work_offset], ldwork, &c_b57, &c__[c_offset], ldc); + } + +/* W := W * V2' */ + + ctrmm_("Right", "Upper", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[lastv - *k + 1 + v_dim1], ldv, & + work[work_offset], ldwork); + +/* C2 := C2 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = lastv - *k + j + i__ * c_dim1; + i__4 = lastv - *k + j + i__ * c_dim1; + r_cnjg(&q__2, &work[i__ + j * work_dim1]); + q__1.r = c__[i__4].r - q__2.r, q__1.i = c__[i__4].i - + q__2.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L80: */ + } +/* L90: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaclr_(n, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaclr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V = (C1*V1 + C2*V2) (stored in WORK) + + W := C2 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + ccopy_(&lastc, &c__[(lastv - *k + j) * c_dim1 + 1], &c__1, + &work[j * work_dim1 + 1], &c__1); +/* L100: */ + } + +/* W := W * V2 */ + + ctrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b57, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1 * V1 */ + + i__1 = lastv - *k; + cgemm_("No transpose", "No transpose", &lastc, k, &i__1, & + c_b57, &c__[c_offset], ldc, &v[v_offset], ldv, & + c_b57, &work[work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + ctrmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b57, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V' */ + + if (lastv > *k) { + +/* C1 := C1 - W * V1' */ + + i__1 = lastv - *k; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "Conjugate transpose", &lastc, & + i__1, k, &q__1, &work[work_offset], ldwork, &v[ + v_offset], ldv, &c_b57, &c__[c_offset], ldc); + } + +/* W := W * V2' */ + + ctrmm_("Right", "Upper", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[lastv - *k + 1 + v_dim1], ldv, & + work[work_offset], ldwork); + +/* C2 := C2 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + (lastv - *k + j) * c_dim1; + i__4 = i__ + (lastv - *k + j) * c_dim1; + i__5 = i__ + j * work_dim1; + q__1.r = c__[i__4].r - work[i__5].r, q__1.i = c__[ + i__4].i - work[i__5].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L110: */ + } +/* L120: */ + } + } + } + + } else if (lsame_(storev, "R")) { + + if (lsame_(direct, "F")) { + +/* + Let V = ( V1 V2 ) (V1: first K columns) + where V1 is unit upper triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaclc_(k, m, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaclc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK) + + W := C1' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + ccopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 + + 1], &c__1); + clacgv_(&lastc, &work[j * work_dim1 + 1], &c__1); +/* L130: */ + } + +/* W := W * V1' */ + + ctrmm_("Right", "Upper", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[v_offset], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2'*V2' */ + + i__1 = lastv - *k; + cgemm_("Conjugate transpose", "Conjugate transpose", & + lastc, k, &i__1, &c_b57, &c__[*k + 1 + c_dim1], + ldc, &v[(*k + 1) * v_dim1 + 1], ldv, &c_b57, & + work[work_offset], ldwork) + ; + } + +/* W := W * T' or W * T */ + + ctrmm_("Right", "Upper", transt, "Non-unit", &lastc, k, & + c_b57, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V' * W' */ + + if (lastv > *k) { + +/* C2 := C2 - V2' * W' */ + + i__1 = lastv - *k; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("Conjugate transpose", "Conjugate transpose", & + i__1, &lastc, k, &q__1, &v[(*k + 1) * v_dim1 + 1], + ldv, &work[work_offset], ldwork, &c_b57, &c__[*k + + 1 + c_dim1], ldc); + } + +/* W := W * V1 */ + + ctrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b57, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ * c_dim1; + i__4 = j + i__ * c_dim1; + r_cnjg(&q__2, &work[i__ + j * work_dim1]); + q__1.r = c__[i__4].r - q__2.r, q__1.i = c__[i__4].i - + q__2.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L140: */ + } +/* L150: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaclc_(k, n, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaclr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V' = (C1*V1' + C2*V2') (stored in WORK) + + W := C1 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + ccopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * + work_dim1 + 1], &c__1); +/* L160: */ + } + +/* W := W * V1' */ + + ctrmm_("Right", "Upper", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[v_offset], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2 * V2' */ + + i__1 = lastv - *k; + cgemm_("No transpose", "Conjugate transpose", &lastc, k, & + i__1, &c_b57, &c__[(*k + 1) * c_dim1 + 1], ldc, & + v[(*k + 1) * v_dim1 + 1], ldv, &c_b57, &work[ + work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + ctrmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b57, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V */ + + if (lastv > *k) { + +/* C2 := C2 - W * V2 */ + + i__1 = lastv - *k; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "No transpose", &lastc, &i__1, k, & + q__1, &work[work_offset], ldwork, &v[(*k + 1) * + v_dim1 + 1], ldv, &c_b57, &c__[(*k + 1) * c_dim1 + + 1], ldc); + } + +/* W := W * V1 */ + + ctrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b57, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * work_dim1; + q__1.r = c__[i__4].r - work[i__5].r, q__1.i = c__[ + i__4].i - work[i__5].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L170: */ + } +/* L180: */ + } + + } + + } else { + +/* + Let V = ( V1 V2 ) (V2: last K columns) + where V2 is unit lower triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaclc_(k, m, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaclc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK) + + W := C2' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + ccopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[ + j * work_dim1 + 1], &c__1); + clacgv_(&lastc, &work[j * work_dim1 + 1], &c__1); +/* L190: */ + } + +/* W := W * V2' */ + + ctrmm_("Right", "Lower", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[(lastv - *k + 1) * v_dim1 + 1], + ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1'*V1' */ + + i__1 = lastv - *k; + cgemm_("Conjugate transpose", "Conjugate transpose", & + lastc, k, &i__1, &c_b57, &c__[c_offset], ldc, &v[ + v_offset], ldv, &c_b57, &work[work_offset], + ldwork); + } + +/* W := W * T' or W * T */ + + ctrmm_("Right", "Lower", transt, "Non-unit", &lastc, k, & + c_b57, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V' * W' */ + + if (lastv > *k) { + +/* C1 := C1 - V1' * W' */ + + i__1 = lastv - *k; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("Conjugate transpose", "Conjugate transpose", & + i__1, &lastc, k, &q__1, &v[v_offset], ldv, &work[ + work_offset], ldwork, &c_b57, &c__[c_offset], ldc); + } + +/* W := W * V2 */ + + ctrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b57, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + +/* C2 := C2 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = lastv - *k + j + i__ * c_dim1; + i__4 = lastv - *k + j + i__ * c_dim1; + r_cnjg(&q__2, &work[i__ + j * work_dim1]); + q__1.r = c__[i__4].r - q__2.r, q__1.i = c__[i__4].i - + q__2.i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L200: */ + } +/* L210: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaclc_(k, n, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaclr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V' = (C1*V1' + C2*V2') (stored in WORK) + + W := C2 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + ccopy_(&lastc, &c__[(lastv - *k + j) * c_dim1 + 1], &c__1, + &work[j * work_dim1 + 1], &c__1); +/* L220: */ + } + +/* W := W * V2' */ + + ctrmm_("Right", "Lower", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[(lastv - *k + 1) * v_dim1 + 1], + ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1 * V1' */ + + i__1 = lastv - *k; + cgemm_("No transpose", "Conjugate transpose", &lastc, k, & + i__1, &c_b57, &c__[c_offset], ldc, &v[v_offset], + ldv, &c_b57, &work[work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + ctrmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b57, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V */ + + if (lastv > *k) { + +/* C1 := C1 - W * V1 */ + + i__1 = lastv - *k; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "No transpose", &lastc, &i__1, k, & + q__1, &work[work_offset], ldwork, &v[v_offset], + ldv, &c_b57, &c__[c_offset], ldc); + } + +/* W := W * V2 */ + + ctrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b57, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + (lastv - *k + j) * c_dim1; + i__4 = i__ + (lastv - *k + j) * c_dim1; + i__5 = i__ + j * work_dim1; + q__1.r = c__[i__4].r - work[i__5].r, q__1.i = c__[ + i__4].i - work[i__5].i; + c__[i__3].r = q__1.r, c__[i__3].i = q__1.i; +/* L230: */ + } +/* L240: */ + } + + } + + } + } + + return 0; + +/* End of CLARFB */ + +} /* clarfb_ */ + +/* Subroutine */ int clarfg_(integer *n, complex *alpha, complex *x, integer * + incx, complex *tau) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2; + complex q__1, q__2; + + /* Local variables */ + static integer j, knt; + static real beta; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *); + static real alphi, alphr, xnorm; + extern doublereal scnrm2_(integer *, complex *, integer *), slapy3_(real * + , real *, real *); + extern /* Complex */ VOID cladiv_(complex *, complex *, complex *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int csscal_(integer *, real *, complex *, integer + *); + static real safmin, rsafmn; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLARFG generates a complex elementary reflector H of order n, such + that + + H' * ( alpha ) = ( beta ), H' * H = I. + ( x ) ( 0 ) + + where alpha and beta are scalars, with beta real, and x is an + (n-1)-element complex vector. H is represented in the form + + H = I - tau * ( 1 ) * ( 1 v' ) , + ( v ) + + where tau is a complex scalar and v is a complex (n-1)-element + vector. Note that H is not hermitian. + + If the elements of x are all zero and alpha is real, then tau = 0 + and H is taken to be the unit matrix. + + Otherwise 1 <= real(tau) <= 2 and abs(tau-1) <= 1 . + + Arguments + ========= + + N (input) INTEGER + The order of the elementary reflector. + + ALPHA (input/output) COMPLEX + On entry, the value alpha. + On exit, it is overwritten with the value beta. + + X (input/output) COMPLEX array, dimension + (1+(N-2)*abs(INCX)) + On entry, the vector x. + On exit, it is overwritten with the vector v. + + INCX (input) INTEGER + The increment between elements of X. INCX > 0. + + TAU (output) COMPLEX + The value tau. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n <= 0) { + tau->r = 0.f, tau->i = 0.f; + return 0; + } + + i__1 = *n - 1; + xnorm = scnrm2_(&i__1, &x[1], incx); + alphr = alpha->r; + alphi = r_imag(alpha); + + if (xnorm == 0.f && alphi == 0.f) { + +/* H = I */ + + tau->r = 0.f, tau->i = 0.f; + } else { + +/* general case */ + + r__1 = slapy3_(&alphr, &alphi, &xnorm); + beta = -r_sign(&r__1, &alphr); + safmin = slamch_("S") / slamch_("E"); + rsafmn = 1.f / safmin; + + knt = 0; + if (dabs(beta) < safmin) { + +/* XNORM, BETA may be inaccurate; scale X and recompute them */ + +L10: + ++knt; + i__1 = *n - 1; + csscal_(&i__1, &rsafmn, &x[1], incx); + beta *= rsafmn; + alphi *= rsafmn; + alphr *= rsafmn; + if (dabs(beta) < safmin) { + goto L10; + } + +/* New BETA is at most 1, at least SAFMIN */ + + i__1 = *n - 1; + xnorm = scnrm2_(&i__1, &x[1], incx); + q__1.r = alphr, q__1.i = alphi; + alpha->r = q__1.r, alpha->i = q__1.i; + r__1 = slapy3_(&alphr, &alphi, &xnorm); + beta = -r_sign(&r__1, &alphr); + } + r__1 = (beta - alphr) / beta; + r__2 = -alphi / beta; + q__1.r = r__1, q__1.i = r__2; + tau->r = q__1.r, tau->i = q__1.i; + q__2.r = alpha->r - beta, q__2.i = alpha->i; + cladiv_(&q__1, &c_b57, &q__2); + alpha->r = q__1.r, alpha->i = q__1.i; + i__1 = *n - 1; + cscal_(&i__1, alpha, &x[1], incx); + +/* If ALPHA is subnormal, it may lose relative accuracy */ + + i__1 = knt; + for (j = 1; j <= i__1; ++j) { + beta *= safmin; +/* L20: */ + } + alpha->r = beta, alpha->i = 0.f; + } + + return 0; + +/* End of CLARFG */ + +} /* clarfg_ */ + +/* Subroutine */ int clarft_(char *direct, char *storev, integer *n, integer * + k, complex *v, integer *ldv, complex *tau, complex *t, integer *ldt) +{ + /* System generated locals */ + integer t_dim1, t_offset, v_dim1, v_offset, i__1, i__2, i__3, i__4; + complex q__1; + + /* Local variables */ + static integer i__, j, prevlastv; + static complex vii; + extern /* Subroutine */ int cgemv_(char *, integer *, integer *, complex * + , complex *, integer *, complex *, integer *, complex *, complex * + , integer *); + extern logical lsame_(char *, char *); + static integer lastv; + extern /* Subroutine */ int ctrmv_(char *, char *, char *, integer *, + complex *, integer *, complex *, integer *), clacgv_(integer *, complex *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLARFT forms the triangular factor T of a complex block reflector H + of order n, which is defined as a product of k elementary reflectors. + + If DIRECT = 'F', H = H(1) H(2) . . . H(k) and T is upper triangular; + + If DIRECT = 'B', H = H(k) . . . H(2) H(1) and T is lower triangular. + + If STOREV = 'C', the vector which defines the elementary reflector + H(i) is stored in the i-th column of the array V, and + + H = I - V * T * V' + + If STOREV = 'R', the vector which defines the elementary reflector + H(i) is stored in the i-th row of the array V, and + + H = I - V' * T * V + + Arguments + ========= + + DIRECT (input) CHARACTER*1 + Specifies the order in which the elementary reflectors are + multiplied to form the block reflector: + = 'F': H = H(1) H(2) . . . H(k) (Forward) + = 'B': H = H(k) . . . H(2) H(1) (Backward) + + STOREV (input) CHARACTER*1 + Specifies how the vectors which define the elementary + reflectors are stored (see also Further Details): + = 'C': columnwise + = 'R': rowwise + + N (input) INTEGER + The order of the block reflector H. N >= 0. + + K (input) INTEGER + The order of the triangular factor T (= the number of + elementary reflectors). K >= 1. + + V (input/output) COMPLEX array, dimension + (LDV,K) if STOREV = 'C' + (LDV,N) if STOREV = 'R' + The matrix V. See further details. + + LDV (input) INTEGER + The leading dimension of the array V. + If STOREV = 'C', LDV >= max(1,N); if STOREV = 'R', LDV >= K. + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i). + + T (output) COMPLEX array, dimension (LDT,K) + The k by k triangular factor T of the block reflector. + If DIRECT = 'F', T is upper triangular; if DIRECT = 'B', T is + lower triangular. The rest of the array is not used. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= K. + + Further Details + =============== + + The shape of the matrix V and the storage of the vectors which define + the H(i) is best illustrated by the following example with n = 5 and + k = 3. The elements equal to 1 are not stored; the corresponding + array elements are modified but restored on exit. The rest of the + array is not used. + + DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': + + V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) + ( v1 1 ) ( 1 v2 v2 v2 ) + ( v1 v2 1 ) ( 1 v3 v3 ) + ( v1 v2 v3 ) + ( v1 v2 v3 ) + + DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': + + V = ( v1 v2 v3 ) V = ( v1 v1 1 ) + ( v1 v2 v3 ) ( v2 v2 v2 1 ) + ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) + ( 1 v3 ) + ( 1 ) + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + --tau; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + + /* Function Body */ + if (*n == 0) { + return 0; + } + + if (lsame_(direct, "F")) { + prevlastv = *n; + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + prevlastv = max(prevlastv,i__); + i__2 = i__; + if (tau[i__2].r == 0.f && tau[i__2].i == 0.f) { + +/* H(i) = I */ + + i__2 = i__; + for (j = 1; j <= i__2; ++j) { + i__3 = j + i__ * t_dim1; + t[i__3].r = 0.f, t[i__3].i = 0.f; +/* L10: */ + } + } else { + +/* general case */ + + i__2 = i__ + i__ * v_dim1; + vii.r = v[i__2].r, vii.i = v[i__2].i; + i__2 = i__ + i__ * v_dim1; + v[i__2].r = 1.f, v[i__2].i = 0.f; + if (lsame_(storev, "C")) { +/* Skip any trailing zeros. */ + i__2 = i__ + 1; + for (lastv = *n; lastv >= i__2; --lastv) { + i__3 = lastv + i__ * v_dim1; + if (v[i__3].r != 0.f || v[i__3].i != 0.f) { + goto L15; + } + } +L15: + j = min(lastv,prevlastv); + +/* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)' * V(i:j,i) */ + + i__2 = j - i__ + 1; + i__3 = i__ - 1; + i__4 = i__; + q__1.r = -tau[i__4].r, q__1.i = -tau[i__4].i; + cgemv_("Conjugate transpose", &i__2, &i__3, &q__1, &v[i__ + + v_dim1], ldv, &v[i__ + i__ * v_dim1], &c__1, & + c_b56, &t[i__ * t_dim1 + 1], &c__1); + } else { +/* Skip any trailing zeros. */ + i__2 = i__ + 1; + for (lastv = *n; lastv >= i__2; --lastv) { + i__3 = i__ + lastv * v_dim1; + if (v[i__3].r != 0.f || v[i__3].i != 0.f) { + goto L16; + } + } +L16: + j = min(lastv,prevlastv); + +/* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)' */ + + if (i__ < j) { + i__2 = j - i__; + clacgv_(&i__2, &v[i__ + (i__ + 1) * v_dim1], ldv); + } + i__2 = i__ - 1; + i__3 = j - i__ + 1; + i__4 = i__; + q__1.r = -tau[i__4].r, q__1.i = -tau[i__4].i; + cgemv_("No transpose", &i__2, &i__3, &q__1, &v[i__ * + v_dim1 + 1], ldv, &v[i__ + i__ * v_dim1], ldv, & + c_b56, &t[i__ * t_dim1 + 1], &c__1); + if (i__ < j) { + i__2 = j - i__; + clacgv_(&i__2, &v[i__ + (i__ + 1) * v_dim1], ldv); + } + } + i__2 = i__ + i__ * v_dim1; + v[i__2].r = vii.r, v[i__2].i = vii.i; + +/* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */ + + i__2 = i__ - 1; + ctrmv_("Upper", "No transpose", "Non-unit", &i__2, &t[ + t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1); + i__2 = i__ + i__ * t_dim1; + i__3 = i__; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + if (i__ > 1) { + prevlastv = max(prevlastv,lastv); + } else { + prevlastv = lastv; + } + } +/* L20: */ + } + } else { + prevlastv = 1; + for (i__ = *k; i__ >= 1; --i__) { + i__1 = i__; + if (tau[i__1].r == 0.f && tau[i__1].i == 0.f) { + +/* H(i) = I */ + + i__1 = *k; + for (j = i__; j <= i__1; ++j) { + i__2 = j + i__ * t_dim1; + t[i__2].r = 0.f, t[i__2].i = 0.f; +/* L30: */ + } + } else { + +/* general case */ + + if (i__ < *k) { + if (lsame_(storev, "C")) { + i__1 = *n - *k + i__ + i__ * v_dim1; + vii.r = v[i__1].r, vii.i = v[i__1].i; + i__1 = *n - *k + i__ + i__ * v_dim1; + v[i__1].r = 1.f, v[i__1].i = 0.f; +/* Skip any leading zeros. */ + i__1 = i__ - 1; + for (lastv = 1; lastv <= i__1; ++lastv) { + i__2 = lastv + i__ * v_dim1; + if (v[i__2].r != 0.f || v[i__2].i != 0.f) { + goto L35; + } + } +L35: + j = max(lastv,prevlastv); + +/* + T(i+1:k,i) := + - tau(i) * V(j:n-k+i,i+1:k)' * V(j:n-k+i,i) +*/ + + i__1 = *n - *k + i__ - j + 1; + i__2 = *k - i__; + i__3 = i__; + q__1.r = -tau[i__3].r, q__1.i = -tau[i__3].i; + cgemv_("Conjugate transpose", &i__1, &i__2, &q__1, &v[ + j + (i__ + 1) * v_dim1], ldv, &v[j + i__ * + v_dim1], &c__1, &c_b56, &t[i__ + 1 + i__ * + t_dim1], &c__1); + i__1 = *n - *k + i__ + i__ * v_dim1; + v[i__1].r = vii.r, v[i__1].i = vii.i; + } else { + i__1 = i__ + (*n - *k + i__) * v_dim1; + vii.r = v[i__1].r, vii.i = v[i__1].i; + i__1 = i__ + (*n - *k + i__) * v_dim1; + v[i__1].r = 1.f, v[i__1].i = 0.f; +/* Skip any leading zeros. */ + i__1 = i__ - 1; + for (lastv = 1; lastv <= i__1; ++lastv) { + i__2 = i__ + lastv * v_dim1; + if (v[i__2].r != 0.f || v[i__2].i != 0.f) { + goto L36; + } + } +L36: + j = max(lastv,prevlastv); + +/* + T(i+1:k,i) := + - tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)' +*/ + + i__1 = *n - *k + i__ - 1 - j + 1; + clacgv_(&i__1, &v[i__ + j * v_dim1], ldv); + i__1 = *k - i__; + i__2 = *n - *k + i__ - j + 1; + i__3 = i__; + q__1.r = -tau[i__3].r, q__1.i = -tau[i__3].i; + cgemv_("No transpose", &i__1, &i__2, &q__1, &v[i__ + + 1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], + ldv, &c_b56, &t[i__ + 1 + i__ * t_dim1], & + c__1); + i__1 = *n - *k + i__ - 1 - j + 1; + clacgv_(&i__1, &v[i__ + j * v_dim1], ldv); + i__1 = i__ + (*n - *k + i__) * v_dim1; + v[i__1].r = vii.r, v[i__1].i = vii.i; + } + +/* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */ + + i__1 = *k - i__; + ctrmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ + + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ * + t_dim1], &c__1) + ; + if (i__ > 1) { + prevlastv = min(prevlastv,lastv); + } else { + prevlastv = lastv; + } + } + i__1 = i__ + i__ * t_dim1; + i__2 = i__; + t[i__1].r = tau[i__2].r, t[i__1].i = tau[i__2].i; + } +/* L40: */ + } + } + return 0; + +/* End of CLARFT */ + +} /* clarft_ */ + +/* Subroutine */ int clartg_(complex *f, complex *g, real *cs, complex *sn, + complex *r__) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2, r__3, r__4, r__5, r__6, r__7, r__8, r__9, r__10; + complex q__1, q__2, q__3; + + /* Local variables */ + static real d__; + static integer i__; + static real f2, g2; + static complex ff; + static real di, dr; + static complex fs, gs; + static real f2s, g2s, eps, scale; + static integer count; + static real safmn2, safmx2; + extern doublereal slapy2_(real *, real *), slamch_(char *); + static real safmin; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLARTG generates a plane rotation so that + + [ CS SN ] [ F ] [ R ] + [ __ ] . [ ] = [ ] where CS**2 + |SN|**2 = 1. + [ -SN CS ] [ G ] [ 0 ] + + This is a faster version of the BLAS1 routine CROTG, except for + the following differences: + F and G are unchanged on return. + If G=0, then CS=1 and SN=0. + If F=0, then CS=0 and SN is chosen so that R is real. + + Arguments + ========= + + F (input) COMPLEX + The first component of vector to be rotated. + + G (input) COMPLEX + The second component of vector to be rotated. + + CS (output) REAL + The cosine of the rotation. + + SN (output) COMPLEX + The sine of the rotation. + + R (output) COMPLEX + The nonzero component of the rotated vector. + + Further Details + ======= ======= + + 3-5-96 - Modified with a new algorithm by W. Kahan and J. Demmel + + This version has a few statements commented out for thread safety + (machine parameters are computed on each entry). 10 feb 03, SJH. + + ===================================================================== + + LOGICAL FIRST + SAVE FIRST, SAFMX2, SAFMIN, SAFMN2 + DATA FIRST / .TRUE. / + + IF( FIRST ) THEN +*/ + safmin = slamch_("S"); + eps = slamch_("E"); + r__1 = slamch_("B"); + i__1 = (integer) (log(safmin / eps) / log(slamch_("B")) / 2.f); + safmn2 = pow_ri(&r__1, &i__1); + safmx2 = 1.f / safmn2; +/* + FIRST = .FALSE. + END IF + Computing MAX + Computing MAX +*/ + r__7 = (r__1 = f->r, dabs(r__1)), r__8 = (r__2 = r_imag(f), dabs(r__2)); +/* Computing MAX */ + r__9 = (r__3 = g->r, dabs(r__3)), r__10 = (r__4 = r_imag(g), dabs(r__4)); + r__5 = dmax(r__7,r__8), r__6 = dmax(r__9,r__10); + scale = dmax(r__5,r__6); + fs.r = f->r, fs.i = f->i; + gs.r = g->r, gs.i = g->i; + count = 0; + if (scale >= safmx2) { +L10: + ++count; + q__1.r = safmn2 * fs.r, q__1.i = safmn2 * fs.i; + fs.r = q__1.r, fs.i = q__1.i; + q__1.r = safmn2 * gs.r, q__1.i = safmn2 * gs.i; + gs.r = q__1.r, gs.i = q__1.i; + scale *= safmn2; + if (scale >= safmx2) { + goto L10; + } + } else if (scale <= safmn2) { + if (g->r == 0.f && g->i == 0.f) { + *cs = 1.f; + sn->r = 0.f, sn->i = 0.f; + r__->r = f->r, r__->i = f->i; + return 0; + } +L20: + --count; + q__1.r = safmx2 * fs.r, q__1.i = safmx2 * fs.i; + fs.r = q__1.r, fs.i = q__1.i; + q__1.r = safmx2 * gs.r, q__1.i = safmx2 * gs.i; + gs.r = q__1.r, gs.i = q__1.i; + scale *= safmx2; + if (scale <= safmn2) { + goto L20; + } + } +/* Computing 2nd power */ + r__1 = fs.r; +/* Computing 2nd power */ + r__2 = r_imag(&fs); + f2 = r__1 * r__1 + r__2 * r__2; +/* Computing 2nd power */ + r__1 = gs.r; +/* Computing 2nd power */ + r__2 = r_imag(&gs); + g2 = r__1 * r__1 + r__2 * r__2; + if (f2 <= dmax(g2,1.f) * safmin) { + +/* This is a rare case: F is very small. */ + + if (f->r == 0.f && f->i == 0.f) { + *cs = 0.f; + r__2 = g->r; + r__3 = r_imag(g); + r__1 = slapy2_(&r__2, &r__3); + r__->r = r__1, r__->i = 0.f; +/* Do complex/real division explicitly with two real divisions */ + r__1 = gs.r; + r__2 = r_imag(&gs); + d__ = slapy2_(&r__1, &r__2); + r__1 = gs.r / d__; + r__2 = -r_imag(&gs) / d__; + q__1.r = r__1, q__1.i = r__2; + sn->r = q__1.r, sn->i = q__1.i; + return 0; + } + r__1 = fs.r; + r__2 = r_imag(&fs); + f2s = slapy2_(&r__1, &r__2); +/* + G2 and G2S are accurate + G2 is at least SAFMIN, and G2S is at least SAFMN2 +*/ + g2s = sqrt(g2); +/* + Error in CS from underflow in F2S is at most + UNFL / SAFMN2 .lt. sqrt(UNFL*EPS) .lt. EPS + If MAX(G2,ONE)=G2, then F2 .lt. G2*SAFMIN, + and so CS .lt. sqrt(SAFMIN) + If MAX(G2,ONE)=ONE, then F2 .lt. SAFMIN + and so CS .lt. sqrt(SAFMIN)/SAFMN2 = sqrt(EPS) + Therefore, CS = F2S/G2S / sqrt( 1 + (F2S/G2S)**2 ) = F2S/G2S +*/ + *cs = f2s / g2s; +/* + Make sure abs(FF) = 1 + Do complex/real division explicitly with 2 real divisions + Computing MAX +*/ + r__3 = (r__1 = f->r, dabs(r__1)), r__4 = (r__2 = r_imag(f), dabs(r__2) + ); + if (dmax(r__3,r__4) > 1.f) { + r__1 = f->r; + r__2 = r_imag(f); + d__ = slapy2_(&r__1, &r__2); + r__1 = f->r / d__; + r__2 = r_imag(f) / d__; + q__1.r = r__1, q__1.i = r__2; + ff.r = q__1.r, ff.i = q__1.i; + } else { + dr = safmx2 * f->r; + di = safmx2 * r_imag(f); + d__ = slapy2_(&dr, &di); + r__1 = dr / d__; + r__2 = di / d__; + q__1.r = r__1, q__1.i = r__2; + ff.r = q__1.r, ff.i = q__1.i; + } + r__1 = gs.r / g2s; + r__2 = -r_imag(&gs) / g2s; + q__2.r = r__1, q__2.i = r__2; + q__1.r = ff.r * q__2.r - ff.i * q__2.i, q__1.i = ff.r * q__2.i + ff.i + * q__2.r; + sn->r = q__1.r, sn->i = q__1.i; + q__2.r = *cs * f->r, q__2.i = *cs * f->i; + q__3.r = sn->r * g->r - sn->i * g->i, q__3.i = sn->r * g->i + sn->i * + g->r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + r__->r = q__1.r, r__->i = q__1.i; + } else { + +/* + This is the most common case. + Neither F2 nor F2/G2 are less than SAFMIN + F2S cannot overflow, and it is accurate +*/ + + f2s = sqrt(g2 / f2 + 1.f); +/* Do the F2S(real)*FS(complex) multiply with two real multiplies */ + r__1 = f2s * fs.r; + r__2 = f2s * r_imag(&fs); + q__1.r = r__1, q__1.i = r__2; + r__->r = q__1.r, r__->i = q__1.i; + *cs = 1.f / f2s; + d__ = f2 + g2; +/* Do complex/real division explicitly with two real divisions */ + r__1 = r__->r / d__; + r__2 = r_imag(r__) / d__; + q__1.r = r__1, q__1.i = r__2; + sn->r = q__1.r, sn->i = q__1.i; + r_cnjg(&q__2, &gs); + q__1.r = sn->r * q__2.r - sn->i * q__2.i, q__1.i = sn->r * q__2.i + + sn->i * q__2.r; + sn->r = q__1.r, sn->i = q__1.i; + if (count != 0) { + if (count > 0) { + i__1 = count; + for (i__ = 1; i__ <= i__1; ++i__) { + q__1.r = safmx2 * r__->r, q__1.i = safmx2 * r__->i; + r__->r = q__1.r, r__->i = q__1.i; +/* L30: */ + } + } else { + i__1 = -count; + for (i__ = 1; i__ <= i__1; ++i__) { + q__1.r = safmn2 * r__->r, q__1.i = safmn2 * r__->i; + r__->r = q__1.r, r__->i = q__1.i; +/* L40: */ + } + } + } + } + return 0; + +/* End of CLARTG */ + +} /* clartg_ */ + +/* Subroutine */ int clascl_(char *type__, integer *kl, integer *ku, real * + cfrom, real *cto, integer *m, integer *n, complex *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1; + + /* Local variables */ + static integer i__, j, k1, k2, k3, k4; + static real mul, cto1; + static logical done; + static real ctoc; + extern logical lsame_(char *, char *); + static integer itype; + static real cfrom1; + extern doublereal slamch_(char *); + static real cfromc; + extern /* Subroutine */ int xerbla_(char *, integer *); + static real bignum; + extern logical sisnan_(real *); + static real smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLASCL multiplies the M by N complex matrix A by the real scalar + CTO/CFROM. This is done without over/underflow as long as the final + result CTO*A(I,J)/CFROM does not over/underflow. TYPE specifies that + A may be full, upper triangular, lower triangular, upper Hessenberg, + or banded. + + Arguments + ========= + + TYPE (input) CHARACTER*1 + TYPE indices the storage type of the input matrix. + = 'G': A is a full matrix. + = 'L': A is a lower triangular matrix. + = 'U': A is an upper triangular matrix. + = 'H': A is an upper Hessenberg matrix. + = 'B': A is a symmetric band matrix with lower bandwidth KL + and upper bandwidth KU and with the only the lower + half stored. + = 'Q': A is a symmetric band matrix with lower bandwidth KL + and upper bandwidth KU and with the only the upper + half stored. + = 'Z': A is a band matrix with lower bandwidth KL and upper + bandwidth KU. + + KL (input) INTEGER + The lower bandwidth of A. Referenced only if TYPE = 'B', + 'Q' or 'Z'. + + KU (input) INTEGER + The upper bandwidth of A. Referenced only if TYPE = 'B', + 'Q' or 'Z'. + + CFROM (input) REAL + CTO (input) REAL + The matrix A is multiplied by CTO/CFROM. A(I,J) is computed + without over/underflow if the final result CTO*A(I,J)/CFROM + can be represented without over/underflow. CFROM must be + nonzero. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + The matrix to be multiplied by CTO/CFROM. See TYPE for the + storage type. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + INFO (output) INTEGER + 0 - successful exit + <0 - if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + + if (lsame_(type__, "G")) { + itype = 0; + } else if (lsame_(type__, "L")) { + itype = 1; + } else if (lsame_(type__, "U")) { + itype = 2; + } else if (lsame_(type__, "H")) { + itype = 3; + } else if (lsame_(type__, "B")) { + itype = 4; + } else if (lsame_(type__, "Q")) { + itype = 5; + } else if (lsame_(type__, "Z")) { + itype = 6; + } else { + itype = -1; + } + + if (itype == -1) { + *info = -1; + } else if (*cfrom == 0.f || sisnan_(cfrom)) { + *info = -4; + } else if (sisnan_(cto)) { + *info = -5; + } else if (*m < 0) { + *info = -6; + } else if (*n < 0 || itype == 4 && *n != *m || itype == 5 && *n != *m) { + *info = -7; + } else if (itype <= 3 && *lda < max(1,*m)) { + *info = -9; + } else if (itype >= 4) { +/* Computing MAX */ + i__1 = *m - 1; + if (*kl < 0 || *kl > max(i__1,0)) { + *info = -2; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = *n - 1; + if (*ku < 0 || *ku > max(i__1,0) || (itype == 4 || itype == 5) && + *kl != *ku) { + *info = -3; + } else if (itype == 4 && *lda < *kl + 1 || itype == 5 && *lda < * + ku + 1 || itype == 6 && *lda < (*kl << 1) + *ku + 1) { + *info = -9; + } + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CLASCL", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *m == 0) { + return 0; + } + +/* Get machine parameters */ + + smlnum = slamch_("S"); + bignum = 1.f / smlnum; + + cfromc = *cfrom; + ctoc = *cto; + +L10: + cfrom1 = cfromc * smlnum; + if (cfrom1 == cfromc) { +/* + CFROMC is an inf. Multiply by a correctly signed zero for + finite CTOC, or a NaN if CTOC is infinite. +*/ + mul = ctoc / cfromc; + done = TRUE_; + cto1 = ctoc; + } else { + cto1 = ctoc / bignum; + if (cto1 == ctoc) { +/* + CTOC is either 0 or an inf. In both cases, CTOC itself + serves as the correct multiplication factor. +*/ + mul = ctoc; + done = TRUE_; + cfromc = 1.f; + } else if (dabs(cfrom1) > dabs(ctoc) && ctoc != 0.f) { + mul = smlnum; + done = FALSE_; + cfromc = cfrom1; + } else if (dabs(cto1) > dabs(cfromc)) { + mul = bignum; + done = FALSE_; + ctoc = cto1; + } else { + mul = ctoc / cfromc; + done = TRUE_; + } + } + + if (itype == 0) { + +/* Full matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + q__1.r = mul * a[i__4].r, q__1.i = mul * a[i__4].i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L20: */ + } +/* L30: */ + } + + } else if (itype == 1) { + +/* Lower triangular matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + q__1.r = mul * a[i__4].r, q__1.i = mul * a[i__4].i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L40: */ + } +/* L50: */ + } + + } else if (itype == 2) { + +/* Upper triangular matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + q__1.r = mul * a[i__4].r, q__1.i = mul * a[i__4].i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L60: */ + } +/* L70: */ + } + + } else if (itype == 3) { + +/* Upper Hessenberg matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = j + 1; + i__2 = min(i__3,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + q__1.r = mul * a[i__4].r, q__1.i = mul * a[i__4].i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L80: */ + } +/* L90: */ + } + + } else if (itype == 4) { + +/* Lower half of a symmetric band matrix */ + + k3 = *kl + 1; + k4 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = k3, i__4 = k4 - j; + i__2 = min(i__3,i__4); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + q__1.r = mul * a[i__4].r, q__1.i = mul * a[i__4].i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L100: */ + } +/* L110: */ + } + + } else if (itype == 5) { + +/* Upper half of a symmetric band matrix */ + + k1 = *ku + 2; + k3 = *ku + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = k1 - j; + i__3 = k3; + for (i__ = max(i__2,1); i__ <= i__3; ++i__) { + i__2 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + q__1.r = mul * a[i__4].r, q__1.i = mul * a[i__4].i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; +/* L120: */ + } +/* L130: */ + } + + } else if (itype == 6) { + +/* Band matrix */ + + k1 = *kl + *ku + 2; + k2 = *kl + 1; + k3 = (*kl << 1) + *ku + 1; + k4 = *kl + *ku + 1 + *m; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__3 = k1 - j; +/* Computing MIN */ + i__4 = k3, i__5 = k4 - j; + i__2 = min(i__4,i__5); + for (i__ = max(i__3,k2); i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + q__1.r = mul * a[i__4].r, q__1.i = mul * a[i__4].i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L140: */ + } +/* L150: */ + } + + } + + if (! done) { + goto L10; + } + + return 0; + +/* End of CLASCL */ + +} /* clascl_ */ + +/* Subroutine */ int claset_(char *uplo, integer *m, integer *n, complex * + alpha, complex *beta, complex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLASET initializes a 2-D array A to BETA on the diagonal and + ALPHA on the offdiagonals. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be set. + = 'U': Upper triangular part is set. The lower triangle + is unchanged. + = 'L': Lower triangular part is set. The upper triangle + is unchanged. + Otherwise: All of the matrix A is set. + + M (input) INTEGER + On entry, M specifies the number of rows of A. + + N (input) INTEGER + On entry, N specifies the number of columns of A. + + ALPHA (input) COMPLEX + All the offdiagonal array elements are set to ALPHA. + + BETA (input) COMPLEX + All the diagonal array elements are set to BETA. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, A(i,j) = ALPHA, 1 <= i <= m, 1 <= j <= n, i.ne.j; + A(i,i) = BETA , 1 <= i <= min(m,n) + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + +/* + Set the diagonal to BETA and the strictly upper triangular + part of the array to ALPHA. +*/ + + i__1 = *n; + for (j = 2; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = j - 1; + i__2 = min(i__3,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = alpha->r, a[i__3].i = alpha->i; +/* L10: */ + } +/* L20: */ + } + i__1 = min(*n,*m); + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = beta->r, a[i__2].i = beta->i; +/* L30: */ + } + + } else if (lsame_(uplo, "L")) { + +/* + Set the diagonal to BETA and the strictly lower triangular + part of the array to ALPHA. +*/ + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = alpha->r, a[i__3].i = alpha->i; +/* L40: */ + } +/* L50: */ + } + i__1 = min(*n,*m); + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = beta->r, a[i__2].i = beta->i; +/* L60: */ + } + + } else { + +/* + Set the array to BETA on the diagonal and ALPHA on the + offdiagonal. +*/ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = alpha->r, a[i__3].i = alpha->i; +/* L70: */ + } +/* L80: */ + } + i__1 = min(*m,*n); + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = beta->r, a[i__2].i = beta->i; +/* L90: */ + } + } + + return 0; + +/* End of CLASET */ + +} /* claset_ */ + +/* Subroutine */ int clasr_(char *side, char *pivot, char *direct, integer *m, + integer *n, real *c__, real *s, complex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + complex q__1, q__2, q__3; + + /* Local variables */ + static integer i__, j, info; + static complex temp; + extern logical lsame_(char *, char *); + static real ctemp, stemp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLASR applies a sequence of real plane rotations to a complex matrix + A, from either the left or the right. + + When SIDE = 'L', the transformation takes the form + + A := P*A + + and when SIDE = 'R', the transformation takes the form + + A := A*P**T + + where P is an orthogonal matrix consisting of a sequence of z plane + rotations, with z = M when SIDE = 'L' and z = N when SIDE = 'R', + and P**T is the transpose of P. + + When DIRECT = 'F' (Forward sequence), then + + P = P(z-1) * ... * P(2) * P(1) + + and when DIRECT = 'B' (Backward sequence), then + + P = P(1) * P(2) * ... * P(z-1) + + where P(k) is a plane rotation matrix defined by the 2-by-2 rotation + + R(k) = ( c(k) s(k) ) + = ( -s(k) c(k) ). + + When PIVOT = 'V' (Variable pivot), the rotation is performed + for the plane (k,k+1), i.e., P(k) has the form + + P(k) = ( 1 ) + ( ... ) + ( 1 ) + ( c(k) s(k) ) + ( -s(k) c(k) ) + ( 1 ) + ( ... ) + ( 1 ) + + where R(k) appears as a rank-2 modification to the identity matrix in + rows and columns k and k+1. + + When PIVOT = 'T' (Top pivot), the rotation is performed for the + plane (1,k+1), so P(k) has the form + + P(k) = ( c(k) s(k) ) + ( 1 ) + ( ... ) + ( 1 ) + ( -s(k) c(k) ) + ( 1 ) + ( ... ) + ( 1 ) + + where R(k) appears in rows and columns 1 and k+1. + + Similarly, when PIVOT = 'B' (Bottom pivot), the rotation is + performed for the plane (k,z), giving P(k) the form + + P(k) = ( 1 ) + ( ... ) + ( 1 ) + ( c(k) s(k) ) + ( 1 ) + ( ... ) + ( 1 ) + ( -s(k) c(k) ) + + where R(k) appears in rows and columns k and z. The rotations are + performed without ever forming P(k) explicitly. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + Specifies whether the plane rotation matrix P is applied to + A on the left or the right. + = 'L': Left, compute A := P*A + = 'R': Right, compute A:= A*P**T + + PIVOT (input) CHARACTER*1 + Specifies the plane for which P(k) is a plane rotation + matrix. + = 'V': Variable pivot, the plane (k,k+1) + = 'T': Top pivot, the plane (1,k+1) + = 'B': Bottom pivot, the plane (k,z) + + DIRECT (input) CHARACTER*1 + Specifies whether P is a forward or backward sequence of + plane rotations. + = 'F': Forward, P = P(z-1)*...*P(2)*P(1) + = 'B': Backward, P = P(1)*P(2)*...*P(z-1) + + M (input) INTEGER + The number of rows of the matrix A. If m <= 1, an immediate + return is effected. + + N (input) INTEGER + The number of columns of the matrix A. If n <= 1, an + immediate return is effected. + + C (input) REAL array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + The cosines c(k) of the plane rotations. + + S (input) REAL array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + The sines s(k) of the plane rotations. The 2-by-2 plane + rotation part of the matrix P(k), R(k), has the form + R(k) = ( c(k) s(k) ) + ( -s(k) c(k) ). + + A (input/output) COMPLEX array, dimension (LDA,N) + The M-by-N matrix A. On exit, A is overwritten by P*A if + SIDE = 'R' or by A*P**T if SIDE = 'L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + --c__; + --s; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (! (lsame_(side, "L") || lsame_(side, "R"))) { + info = 1; + } else if (! (lsame_(pivot, "V") || lsame_(pivot, + "T") || lsame_(pivot, "B"))) { + info = 2; + } else if (! (lsame_(direct, "F") || lsame_(direct, + "B"))) { + info = 3; + } else if (*m < 0) { + info = 4; + } else if (*n < 0) { + info = 5; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("CLASR ", &info); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + if (lsame_(side, "L")) { + +/* Form P * A */ + + if (lsame_(pivot, "V")) { + if (lsame_(direct, "F")) { + i__1 = *m - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + 1 + i__ * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = j + 1 + i__ * a_dim1; + q__2.r = ctemp * temp.r, q__2.i = ctemp * temp.i; + i__4 = j + i__ * a_dim1; + q__3.r = stemp * a[i__4].r, q__3.i = stemp * a[ + i__4].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + i__3 = j + i__ * a_dim1; + q__2.r = stemp * temp.r, q__2.i = stemp * temp.i; + i__4 = j + i__ * a_dim1; + q__3.r = ctemp * a[i__4].r, q__3.i = ctemp * a[ + i__4].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L10: */ + } + } +/* L20: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = j + 1 + i__ * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = j + 1 + i__ * a_dim1; + q__2.r = ctemp * temp.r, q__2.i = ctemp * temp.i; + i__3 = j + i__ * a_dim1; + q__3.r = stemp * a[i__3].r, q__3.i = stemp * a[ + i__3].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; + i__2 = j + i__ * a_dim1; + q__2.r = stemp * temp.r, q__2.i = stemp * temp.i; + i__3 = j + i__ * a_dim1; + q__3.r = ctemp * a[i__3].r, q__3.i = ctemp * a[ + i__3].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; +/* L30: */ + } + } +/* L40: */ + } + } + } else if (lsame_(pivot, "T")) { + if (lsame_(direct, "F")) { + i__1 = *m; + for (j = 2; j <= i__1; ++j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = j + i__ * a_dim1; + q__2.r = ctemp * temp.r, q__2.i = ctemp * temp.i; + i__4 = i__ * a_dim1 + 1; + q__3.r = stemp * a[i__4].r, q__3.i = stemp * a[ + i__4].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + i__3 = i__ * a_dim1 + 1; + q__2.r = stemp * temp.r, q__2.i = stemp * temp.i; + i__4 = i__ * a_dim1 + 1; + q__3.r = ctemp * a[i__4].r, q__3.i = ctemp * a[ + i__4].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L50: */ + } + } +/* L60: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m; j >= 2; --j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = j + i__ * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = j + i__ * a_dim1; + q__2.r = ctemp * temp.r, q__2.i = ctemp * temp.i; + i__3 = i__ * a_dim1 + 1; + q__3.r = stemp * a[i__3].r, q__3.i = stemp * a[ + i__3].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; + i__2 = i__ * a_dim1 + 1; + q__2.r = stemp * temp.r, q__2.i = stemp * temp.i; + i__3 = i__ * a_dim1 + 1; + q__3.r = ctemp * a[i__3].r, q__3.i = ctemp * a[ + i__3].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; +/* L70: */ + } + } +/* L80: */ + } + } + } else if (lsame_(pivot, "B")) { + if (lsame_(direct, "F")) { + i__1 = *m - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = j + i__ * a_dim1; + i__4 = *m + i__ * a_dim1; + q__2.r = stemp * a[i__4].r, q__2.i = stemp * a[ + i__4].i; + q__3.r = ctemp * temp.r, q__3.i = ctemp * temp.i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + i__3 = *m + i__ * a_dim1; + i__4 = *m + i__ * a_dim1; + q__2.r = ctemp * a[i__4].r, q__2.i = ctemp * a[ + i__4].i; + q__3.r = stemp * temp.r, q__3.i = stemp * temp.i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L90: */ + } + } +/* L100: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = j + i__ * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = j + i__ * a_dim1; + i__3 = *m + i__ * a_dim1; + q__2.r = stemp * a[i__3].r, q__2.i = stemp * a[ + i__3].i; + q__3.r = ctemp * temp.r, q__3.i = ctemp * temp.i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; + i__2 = *m + i__ * a_dim1; + i__3 = *m + i__ * a_dim1; + q__2.r = ctemp * a[i__3].r, q__2.i = ctemp * a[ + i__3].i; + q__3.r = stemp * temp.r, q__3.i = stemp * temp.i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; +/* L110: */ + } + } +/* L120: */ + } + } + } + } else if (lsame_(side, "R")) { + +/* Form A * P' */ + + if (lsame_(pivot, "V")) { + if (lsame_(direct, "F")) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + (j + 1) * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = i__ + (j + 1) * a_dim1; + q__2.r = ctemp * temp.r, q__2.i = ctemp * temp.i; + i__4 = i__ + j * a_dim1; + q__3.r = stemp * a[i__4].r, q__3.i = stemp * a[ + i__4].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + i__3 = i__ + j * a_dim1; + q__2.r = stemp * temp.r, q__2.i = stemp * temp.i; + i__4 = i__ + j * a_dim1; + q__3.r = ctemp * a[i__4].r, q__3.i = ctemp * a[ + i__4].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L130: */ + } + } +/* L140: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + (j + 1) * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = i__ + (j + 1) * a_dim1; + q__2.r = ctemp * temp.r, q__2.i = ctemp * temp.i; + i__3 = i__ + j * a_dim1; + q__3.r = stemp * a[i__3].r, q__3.i = stemp * a[ + i__3].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; + i__2 = i__ + j * a_dim1; + q__2.r = stemp * temp.r, q__2.i = stemp * temp.i; + i__3 = i__ + j * a_dim1; + q__3.r = ctemp * a[i__3].r, q__3.i = ctemp * a[ + i__3].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; +/* L150: */ + } + } +/* L160: */ + } + } + } else if (lsame_(pivot, "T")) { + if (lsame_(direct, "F")) { + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = i__ + j * a_dim1; + q__2.r = ctemp * temp.r, q__2.i = ctemp * temp.i; + i__4 = i__ + a_dim1; + q__3.r = stemp * a[i__4].r, q__3.i = stemp * a[ + i__4].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + i__3 = i__ + a_dim1; + q__2.r = stemp * temp.r, q__2.i = stemp * temp.i; + i__4 = i__ + a_dim1; + q__3.r = ctemp * a[i__4].r, q__3.i = ctemp * a[ + i__4].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L170: */ + } + } +/* L180: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n; j >= 2; --j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = i__ + j * a_dim1; + q__2.r = ctemp * temp.r, q__2.i = ctemp * temp.i; + i__3 = i__ + a_dim1; + q__3.r = stemp * a[i__3].r, q__3.i = stemp * a[ + i__3].i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; + i__2 = i__ + a_dim1; + q__2.r = stemp * temp.r, q__2.i = stemp * temp.i; + i__3 = i__ + a_dim1; + q__3.r = ctemp * a[i__3].r, q__3.i = ctemp * a[ + i__3].i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; +/* L190: */ + } + } +/* L200: */ + } + } + } else if (lsame_(pivot, "B")) { + if (lsame_(direct, "F")) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = i__ + j * a_dim1; + i__4 = i__ + *n * a_dim1; + q__2.r = stemp * a[i__4].r, q__2.i = stemp * a[ + i__4].i; + q__3.r = ctemp * temp.r, q__3.i = ctemp * temp.i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; + i__3 = i__ + *n * a_dim1; + i__4 = i__ + *n * a_dim1; + q__2.r = ctemp * a[i__4].r, q__2.i = ctemp * a[ + i__4].i; + q__3.r = stemp * temp.r, q__3.i = stemp * temp.i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__3].r = q__1.r, a[i__3].i = q__1.i; +/* L210: */ + } + } +/* L220: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = i__ + j * a_dim1; + i__3 = i__ + *n * a_dim1; + q__2.r = stemp * a[i__3].r, q__2.i = stemp * a[ + i__3].i; + q__3.r = ctemp * temp.r, q__3.i = ctemp * temp.i; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; + i__2 = i__ + *n * a_dim1; + i__3 = i__ + *n * a_dim1; + q__2.r = ctemp * a[i__3].r, q__2.i = ctemp * a[ + i__3].i; + q__3.r = stemp * temp.r, q__3.i = stemp * temp.i; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - + q__3.i; + a[i__2].r = q__1.r, a[i__2].i = q__1.i; +/* L230: */ + } + } +/* L240: */ + } + } + } + } + + return 0; + +/* End of CLASR */ + +} /* clasr_ */ + +/* Subroutine */ int classq_(integer *n, complex *x, integer *incx, real * + scale, real *sumsq) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + real r__1; + + /* Local variables */ + static integer ix; + static real temp1; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLASSQ returns the values scl and ssq such that + + ( scl**2 )*ssq = x( 1 )**2 +...+ x( n )**2 + ( scale**2 )*sumsq, + + where x( i ) = abs( X( 1 + ( i - 1 )*INCX ) ). The value of sumsq is + assumed to be at least unity and the value of ssq will then satisfy + + 1.0 .le. ssq .le. ( sumsq + 2*n ). + + scale is assumed to be non-negative and scl returns the value + + scl = max( scale, abs( real( x( i ) ) ), abs( aimag( x( i ) ) ) ), + i + + scale and sumsq must be supplied in SCALE and SUMSQ respectively. + SCALE and SUMSQ are overwritten by scl and ssq respectively. + + The routine makes only one pass through the vector X. + + Arguments + ========= + + N (input) INTEGER + The number of elements to be used from the vector X. + + X (input) COMPLEX array, dimension (N) + The vector x as described above. + x( i ) = X( 1 + ( i - 1 )*INCX ), 1 <= i <= n. + + INCX (input) INTEGER + The increment between successive values of the vector X. + INCX > 0. + + SCALE (input/output) REAL + On entry, the value scale in the equation above. + On exit, SCALE is overwritten with the value scl . + + SUMSQ (input/output) REAL + On entry, the value sumsq in the equation above. + On exit, SUMSQ is overwritten with the value ssq . + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n > 0) { + i__1 = (*n - 1) * *incx + 1; + i__2 = *incx; + for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) { + i__3 = ix; + if (x[i__3].r != 0.f) { + i__3 = ix; + temp1 = (r__1 = x[i__3].r, dabs(r__1)); + if (*scale < temp1) { +/* Computing 2nd power */ + r__1 = *scale / temp1; + *sumsq = *sumsq * (r__1 * r__1) + 1; + *scale = temp1; + } else { +/* Computing 2nd power */ + r__1 = temp1 / *scale; + *sumsq += r__1 * r__1; + } + } + if (r_imag(&x[ix]) != 0.f) { + temp1 = (r__1 = r_imag(&x[ix]), dabs(r__1)); + if (*scale < temp1) { +/* Computing 2nd power */ + r__1 = *scale / temp1; + *sumsq = *sumsq * (r__1 * r__1) + 1; + *scale = temp1; + } else { +/* Computing 2nd power */ + r__1 = temp1 / *scale; + *sumsq += r__1 * r__1; + } + } +/* L10: */ + } + } + + return 0; + +/* End of CLASSQ */ + +} /* classq_ */ + +/* Subroutine */ int claswp_(integer *n, complex *a, integer *lda, integer * + k1, integer *k2, integer *ipiv, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5, i__6; + + /* Local variables */ + static integer i__, j, k, i1, i2, n32, ip, ix, ix0, inc; + static complex temp; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLASWP performs a series of row interchanges on the matrix A. + One row interchange is initiated for each of rows K1 through K2 of A. + + Arguments + ========= + + N (input) INTEGER + The number of columns of the matrix A. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the matrix of column dimension N to which the row + interchanges will be applied. + On exit, the permuted matrix. + + LDA (input) INTEGER + The leading dimension of the array A. + + K1 (input) INTEGER + The first element of IPIV for which a row interchange will + be done. + + K2 (input) INTEGER + The last element of IPIV for which a row interchange will + be done. + + IPIV (input) INTEGER array, dimension (K2*abs(INCX)) + The vector of pivot indices. Only the elements in positions + K1 through K2 of IPIV are accessed. + IPIV(K) = L implies rows K and L are to be interchanged. + + INCX (input) INTEGER + The increment between successive values of IPIV. If IPIV + is negative, the pivots are applied in reverse order. + + Further Details + =============== + + Modified by + R. C. Whaley, Computer Science Dept., Univ. of Tenn., Knoxville, USA + + ===================================================================== + + + Interchange row I with row IPIV(I) for each of rows K1 through K2. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + if (*incx > 0) { + ix0 = *k1; + i1 = *k1; + i2 = *k2; + inc = 1; + } else if (*incx < 0) { + ix0 = (1 - *k2) * *incx + 1; + i1 = *k2; + i2 = *k1; + inc = -1; + } else { + return 0; + } + + n32 = *n / 32 << 5; + if (n32 != 0) { + i__1 = n32; + for (j = 1; j <= i__1; j += 32) { + ix = ix0; + i__2 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__3) + { + ip = ipiv[ix]; + if (ip != i__) { + i__4 = j + 31; + for (k = j; k <= i__4; ++k) { + i__5 = i__ + k * a_dim1; + temp.r = a[i__5].r, temp.i = a[i__5].i; + i__5 = i__ + k * a_dim1; + i__6 = ip + k * a_dim1; + a[i__5].r = a[i__6].r, a[i__5].i = a[i__6].i; + i__5 = ip + k * a_dim1; + a[i__5].r = temp.r, a[i__5].i = temp.i; +/* L10: */ + } + } + ix += *incx; +/* L20: */ + } +/* L30: */ + } + } + if (n32 != *n) { + ++n32; + ix = ix0; + i__1 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__3) { + ip = ipiv[ix]; + if (ip != i__) { + i__2 = *n; + for (k = n32; k <= i__2; ++k) { + i__4 = i__ + k * a_dim1; + temp.r = a[i__4].r, temp.i = a[i__4].i; + i__4 = i__ + k * a_dim1; + i__5 = ip + k * a_dim1; + a[i__4].r = a[i__5].r, a[i__4].i = a[i__5].i; + i__4 = ip + k * a_dim1; + a[i__4].r = temp.r, a[i__4].i = temp.i; +/* L40: */ + } + } + ix += *incx; +/* L50: */ + } + } + + return 0; + +/* End of CLASWP */ + +} /* claswp_ */ + +/* Subroutine */ int clatrd_(char *uplo, integer *n, integer *nb, complex *a, + integer *lda, real *e, complex *tau, complex *w, integer *ldw) +{ + /* System generated locals */ + integer a_dim1, a_offset, w_dim1, w_offset, i__1, i__2, i__3; + real r__1; + complex q__1, q__2, q__3, q__4; + + /* Local variables */ + static integer i__, iw; + static complex alpha; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *); + extern /* Complex */ VOID cdotc_(complex *, integer *, complex *, integer + *, complex *, integer *); + extern /* Subroutine */ int cgemv_(char *, integer *, integer *, complex * + , complex *, integer *, complex *, integer *, complex *, complex * + , integer *), chemv_(char *, integer *, complex *, + complex *, integer *, complex *, integer *, complex *, complex *, + integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int caxpy_(integer *, complex *, complex *, + integer *, complex *, integer *), clarfg_(integer *, complex *, + complex *, integer *, complex *), clacgv_(integer *, complex *, + integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLATRD reduces NB rows and columns of a complex Hermitian matrix A to + Hermitian tridiagonal form by a unitary similarity + transformation Q' * A * Q, and returns the matrices V and W which are + needed to apply the transformation to the unreduced part of A. + + If UPLO = 'U', CLATRD reduces the last NB rows and columns of a + matrix, of which the upper triangle is supplied; + if UPLO = 'L', CLATRD reduces the first NB rows and columns of a + matrix, of which the lower triangle is supplied. + + This is an auxiliary routine called by CHETRD. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + Hermitian matrix A is stored: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. + + NB (input) INTEGER + The number of rows and columns to be reduced. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + n-by-n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n-by-n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit: + if UPLO = 'U', the last NB columns have been reduced to + tridiagonal form, with the diagonal elements overwriting + the diagonal elements of A; the elements above the diagonal + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors; + if UPLO = 'L', the first NB columns have been reduced to + tridiagonal form, with the diagonal elements overwriting + the diagonal elements of A; the elements below the diagonal + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + E (output) REAL array, dimension (N-1) + If UPLO = 'U', E(n-nb:n-1) contains the superdiagonal + elements of the last NB columns of the reduced matrix; + if UPLO = 'L', E(1:nb) contains the subdiagonal elements of + the first NB columns of the reduced matrix. + + TAU (output) COMPLEX array, dimension (N-1) + The scalar factors of the elementary reflectors, stored in + TAU(n-nb:n-1) if UPLO = 'U', and in TAU(1:nb) if UPLO = 'L'. + See Further Details. + + W (output) COMPLEX array, dimension (LDW,NB) + The n-by-nb matrix W required to update the unreduced part + of A. + + LDW (input) INTEGER + The leading dimension of the array W. LDW >= max(1,N). + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n) H(n-1) . . . H(n-nb+1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i:n) = 0 and v(i-1) = 1; v(1:i-1) is stored on exit in A(1:i-1,i), + and tau in TAU(i-1). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(nb). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0 and v(i+1) = 1; v(i+1:n) is stored on exit in A(i+1:n,i), + and tau in TAU(i). + + The elements of the vectors v together form the n-by-nb matrix V + which is needed, with W, to apply the transformation to the unreduced + part of the matrix, using a Hermitian rank-2k update of the form: + A := A - V*W' - W*V'. + + The contents of A on exit are illustrated by the following examples + with n = 5 and nb = 2: + + if UPLO = 'U': if UPLO = 'L': + + ( a a a v4 v5 ) ( d ) + ( a a v4 v5 ) ( 1 d ) + ( a 1 v5 ) ( v1 1 a ) + ( d 1 ) ( v1 v2 a a ) + ( d ) ( v1 v2 a a a ) + + where d denotes a diagonal element of the reduced matrix, a denotes + an element of the original matrix that is unchanged, and vi denotes + an element of the vector defining H(i). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --e; + --tau; + w_dim1 = *ldw; + w_offset = 1 + w_dim1; + w -= w_offset; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + + if (lsame_(uplo, "U")) { + +/* Reduce last NB columns of upper triangle */ + + i__1 = *n - *nb + 1; + for (i__ = *n; i__ >= i__1; --i__) { + iw = i__ - *n + *nb; + if (i__ < *n) { + +/* Update A(1:i,i) */ + + i__2 = i__ + i__ * a_dim1; + i__3 = i__ + i__ * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + i__2 = *n - i__; + clacgv_(&i__2, &w[i__ + (iw + 1) * w_dim1], ldw); + i__2 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__, &i__2, &q__1, &a[(i__ + 1) * + a_dim1 + 1], lda, &w[i__ + (iw + 1) * w_dim1], ldw, & + c_b57, &a[i__ * a_dim1 + 1], &c__1); + i__2 = *n - i__; + clacgv_(&i__2, &w[i__ + (iw + 1) * w_dim1], ldw); + i__2 = *n - i__; + clacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__, &i__2, &q__1, &w[(iw + 1) * + w_dim1 + 1], ldw, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b57, &a[i__ * a_dim1 + 1], &c__1); + i__2 = *n - i__; + clacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + i__3 = i__ + i__ * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + } + if (i__ > 1) { + +/* + Generate elementary reflector H(i) to annihilate + A(1:i-2,i) +*/ + + i__2 = i__ - 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = i__ - 1; + clarfg_(&i__2, &alpha, &a[i__ * a_dim1 + 1], &c__1, &tau[i__ + - 1]); + i__2 = i__ - 1; + e[i__2] = alpha.r; + i__2 = i__ - 1 + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Compute W(1:i-1,i) */ + + i__2 = i__ - 1; + chemv_("Upper", &i__2, &c_b57, &a[a_offset], lda, &a[i__ * + a_dim1 + 1], &c__1, &c_b56, &w[iw * w_dim1 + 1], & + c__1); + if (i__ < *n) { + i__2 = i__ - 1; + i__3 = *n - i__; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &w[( + iw + 1) * w_dim1 + 1], ldw, &a[i__ * a_dim1 + 1], + &c__1, &c_b56, &w[i__ + 1 + iw * w_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &a[(i__ + 1) * + a_dim1 + 1], lda, &w[i__ + 1 + iw * w_dim1], & + c__1, &c_b57, &w[iw * w_dim1 + 1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[( + i__ + 1) * a_dim1 + 1], lda, &a[i__ * a_dim1 + 1], + &c__1, &c_b56, &w[i__ + 1 + iw * w_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &w[(iw + 1) * + w_dim1 + 1], ldw, &w[i__ + 1 + iw * w_dim1], & + c__1, &c_b57, &w[iw * w_dim1 + 1], &c__1); + } + i__2 = i__ - 1; + cscal_(&i__2, &tau[i__ - 1], &w[iw * w_dim1 + 1], &c__1); + q__3.r = -.5f, q__3.i = -0.f; + i__2 = i__ - 1; + q__2.r = q__3.r * tau[i__2].r - q__3.i * tau[i__2].i, q__2.i = + q__3.r * tau[i__2].i + q__3.i * tau[i__2].r; + i__3 = i__ - 1; + cdotc_(&q__4, &i__3, &w[iw * w_dim1 + 1], &c__1, &a[i__ * + a_dim1 + 1], &c__1); + q__1.r = q__2.r * q__4.r - q__2.i * q__4.i, q__1.i = q__2.r * + q__4.i + q__2.i * q__4.r; + alpha.r = q__1.r, alpha.i = q__1.i; + i__2 = i__ - 1; + caxpy_(&i__2, &alpha, &a[i__ * a_dim1 + 1], &c__1, &w[iw * + w_dim1 + 1], &c__1); + } + +/* L10: */ + } + } else { + +/* Reduce first NB columns of lower triangle */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i:n,i) */ + + i__2 = i__ + i__ * a_dim1; + i__3 = i__ + i__ * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + i__2 = i__ - 1; + clacgv_(&i__2, &w[i__ + w_dim1], ldw); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &a[i__ + a_dim1], lda, + &w[i__ + w_dim1], ldw, &c_b57, &a[i__ + i__ * a_dim1], & + c__1); + i__2 = i__ - 1; + clacgv_(&i__2, &w[i__ + w_dim1], ldw); + i__2 = i__ - 1; + clacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &w[i__ + w_dim1], ldw, + &a[i__ + a_dim1], lda, &c_b57, &a[i__ + i__ * a_dim1], & + c__1); + i__2 = i__ - 1; + clacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + i__3 = i__ + i__ * a_dim1; + r__1 = a[i__3].r; + a[i__2].r = r__1, a[i__2].i = 0.f; + if (i__ < *n) { + +/* + Generate elementary reflector H(i) to annihilate + A(i+2:n,i) +*/ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + clarfg_(&i__2, &alpha, &a[min(i__3,*n) + i__ * a_dim1], &c__1, + &tau[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + +/* Compute W(i+1:n,i) */ + + i__2 = *n - i__; + chemv_("Lower", &i__2, &c_b57, &a[i__ + 1 + (i__ + 1) * + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &w[i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &w[i__ + + 1 + w_dim1], ldw, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &w[i__ * w_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &a[i__ + 1 + + a_dim1], lda, &w[i__ * w_dim1 + 1], &c__1, &c_b57, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + 1 + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &w[i__ * w_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &w[i__ + 1 + + w_dim1], ldw, &w[i__ * w_dim1 + 1], &c__1, &c_b57, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + cscal_(&i__2, &tau[i__], &w[i__ + 1 + i__ * w_dim1], &c__1); + q__3.r = -.5f, q__3.i = -0.f; + i__2 = i__; + q__2.r = q__3.r * tau[i__2].r - q__3.i * tau[i__2].i, q__2.i = + q__3.r * tau[i__2].i + q__3.i * tau[i__2].r; + i__3 = *n - i__; + cdotc_(&q__4, &i__3, &w[i__ + 1 + i__ * w_dim1], &c__1, &a[ + i__ + 1 + i__ * a_dim1], &c__1); + q__1.r = q__2.r * q__4.r - q__2.i * q__4.i, q__1.i = q__2.r * + q__4.i + q__2.i * q__4.r; + alpha.r = q__1.r, alpha.i = q__1.i; + i__2 = *n - i__; + caxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + } + +/* L20: */ + } + } + + return 0; + +/* End of CLATRD */ + +} /* clatrd_ */ + +/* Subroutine */ int clatrs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, complex *a, integer *lda, complex *x, real *scale, + real *cnorm, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + real r__1, r__2, r__3, r__4; + complex q__1, q__2, q__3, q__4; + + /* Local variables */ + static integer i__, j; + static real xj, rec, tjj; + static integer jinc; + static real xbnd; + static integer imax; + static real tmax; + static complex tjjs; + static real xmax, grow; + extern /* Complex */ VOID cdotc_(complex *, integer *, complex *, integer + *, complex *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + static real tscal; + static complex uscal; + static integer jlast; + extern /* Complex */ VOID cdotu_(complex *, integer *, complex *, integer + *, complex *, integer *); + static complex csumj; + extern /* Subroutine */ int caxpy_(integer *, complex *, complex *, + integer *, complex *, integer *); + static logical upper; + extern /* Subroutine */ int ctrsv_(char *, char *, char *, integer *, + complex *, integer *, complex *, integer *), slabad_(real *, real *); + extern integer icamax_(integer *, complex *, integer *); + extern /* Complex */ VOID cladiv_(complex *, complex *, complex *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int csscal_(integer *, real *, complex *, integer + *), xerbla_(char *, integer *); + static real bignum; + extern integer isamax_(integer *, real *, integer *); + extern doublereal scasum_(integer *, complex *, integer *); + static logical notran; + static integer jfirst; + static real smlnum; + static logical nounit; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLATRS solves one of the triangular systems + + A * x = s*b, A**T * x = s*b, or A**H * x = s*b, + + with scaling to prevent overflow. Here A is an upper or lower + triangular matrix, A**T denotes the transpose of A, A**H denotes the + conjugate transpose of A, x and b are n-element vectors, and s is a + scaling factor, usually less than or equal to 1, chosen so that the + components of x will be less than the overflow threshold. If the + unscaled problem will not cause overflow, the Level 2 BLAS routine + CTRSV is called. If the matrix A is singular (A(j,j) = 0 for some j), + then s is set to 0 and a non-trivial solution to A*x = 0 is returned. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the matrix A is upper or lower triangular. + = 'U': Upper triangular + = 'L': Lower triangular + + TRANS (input) CHARACTER*1 + Specifies the operation applied to A. + = 'N': Solve A * x = s*b (No transpose) + = 'T': Solve A**T * x = s*b (Transpose) + = 'C': Solve A**H * x = s*b (Conjugate transpose) + + DIAG (input) CHARACTER*1 + Specifies whether or not the matrix A is unit triangular. + = 'N': Non-unit triangular + = 'U': Unit triangular + + NORMIN (input) CHARACTER*1 + Specifies whether CNORM has been set or not. + = 'Y': CNORM contains the column norms on entry + = 'N': CNORM is not set on entry. On exit, the norms will + be computed and stored in CNORM. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input) COMPLEX array, dimension (LDA,N) + The triangular matrix A. If UPLO = 'U', the leading n by n + upper triangular part of the array A contains the upper + triangular matrix, and the strictly lower triangular part of + A is not referenced. If UPLO = 'L', the leading n by n lower + triangular part of the array A contains the lower triangular + matrix, and the strictly upper triangular part of A is not + referenced. If DIAG = 'U', the diagonal elements of A are + also not referenced and are assumed to be 1. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max (1,N). + + X (input/output) COMPLEX array, dimension (N) + On entry, the right hand side b of the triangular system. + On exit, X is overwritten by the solution vector x. + + SCALE (output) REAL + The scaling factor s for the triangular system + A * x = s*b, A**T * x = s*b, or A**H * x = s*b. + If SCALE = 0, the matrix A is singular or badly scaled, and + the vector x is an exact or approximate solution to A*x = 0. + + CNORM (input or output) REAL array, dimension (N) + + If NORMIN = 'Y', CNORM is an input argument and CNORM(j) + contains the norm of the off-diagonal part of the j-th column + of A. If TRANS = 'N', CNORM(j) must be greater than or equal + to the infinity-norm, and if TRANS = 'T' or 'C', CNORM(j) + must be greater than or equal to the 1-norm. + + If NORMIN = 'N', CNORM is an output argument and CNORM(j) + returns the 1-norm of the offdiagonal part of the j-th column + of A. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + Further Details + ======= ======= + + A rough bound on x is computed; if that is less than overflow, CTRSV + is called, otherwise, specific code is used which checks for possible + overflow or divide-by-zero at every operation. + + A columnwise scheme is used for solving A*x = b. The basic algorithm + if A is lower triangular is + + x[1:n] := b[1:n] + for j = 1, ..., n + x(j) := x(j) / A(j,j) + x[j+1:n] := x[j+1:n] - x(j) * A[j+1:n,j] + end + + Define bounds on the components of x after j iterations of the loop: + M(j) = bound on x[1:j] + G(j) = bound on x[j+1:n] + Initially, let M(0) = 0 and G(0) = max{x(i), i=1,...,n}. + + Then for iteration j+1 we have + M(j+1) <= G(j) / | A(j+1,j+1) | + G(j+1) <= G(j) + M(j+1) * | A[j+2:n,j+1] | + <= G(j) ( 1 + CNORM(j+1) / | A(j+1,j+1) | ) + + where CNORM(j+1) is greater than or equal to the infinity-norm of + column j+1 of A, not counting the diagonal. Hence + + G(j) <= G(0) product ( 1 + CNORM(i) / | A(i,i) | ) + 1<=i<=j + and + + |x(j)| <= ( G(0) / |A(j,j)| ) product ( 1 + CNORM(i) / |A(i,i)| ) + 1<=i< j + + Since |x(j)| <= M(j), we use the Level 2 BLAS routine CTRSV if the + reciprocal of the largest M(j), j=1,..,n, is larger than + max(underflow, 1/overflow). + + The bound on x(j) is also used to determine when a step in the + columnwise method can be performed without fear of overflow. If + the computed bound is greater than a large constant, x is scaled to + prevent overflow, but if the bound overflows, x is set to 0, x(j) to + 1, and scale to 0, and a non-trivial solution to A*x = 0 is found. + + Similarly, a row-wise scheme is used to solve A**T *x = b or + A**H *x = b. The basic algorithm for A upper triangular is + + for j = 1, ..., n + x(j) := ( b(j) - A[1:j-1,j]' * x[1:j-1] ) / A(j,j) + end + + We simultaneously compute two bounds + G(j) = bound on ( b(i) - A[1:i-1,i]' * x[1:i-1] ), 1<=i<=j + M(j) = bound on x(i), 1<=i<=j + + The initial values are G(0) = 0, M(0) = max{b(i), i=1,..,n}, and we + add the constraint G(j) >= G(j-1) and M(j) >= M(j-1) for j >= 1. + Then the bound on x(j) is + + M(j) <= M(j-1) * ( 1 + CNORM(j) ) / | A(j,j) | + + <= M(0) * product ( ( 1 + CNORM(i) ) / |A(i,i)| ) + 1<=i<=j + + and we can safely call CTRSV if 1/M(n) and 1/G(n) are both greater + than max(underflow, 1/overflow). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --cnorm; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + notran = lsame_(trans, "N"); + nounit = lsame_(diag, "N"); + +/* Test the input parameters. */ + + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T") && ! + lsame_(trans, "C")) { + *info = -2; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -3; + } else if (! lsame_(normin, "Y") && ! lsame_(normin, + "N")) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*lda < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CLATRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine machine dependent parameters to control overflow. */ + + smlnum = slamch_("Safe minimum"); + bignum = 1.f / smlnum; + slabad_(&smlnum, &bignum); + smlnum /= slamch_("Precision"); + bignum = 1.f / smlnum; + *scale = 1.f; + + if (lsame_(normin, "N")) { + +/* Compute the 1-norm of each column, not including the diagonal. */ + + if (upper) { + +/* A is upper triangular. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + cnorm[j] = scasum_(&i__2, &a[j * a_dim1 + 1], &c__1); +/* L10: */ + } + } else { + +/* A is lower triangular. */ + + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = *n - j; + cnorm[j] = scasum_(&i__2, &a[j + 1 + j * a_dim1], &c__1); +/* L20: */ + } + cnorm[*n] = 0.f; + } + } + +/* + Scale the column norms by TSCAL if the maximum element in CNORM is + greater than BIGNUM/2. +*/ + + imax = isamax_(n, &cnorm[1], &c__1); + tmax = cnorm[imax]; + if (tmax <= bignum * .5f) { + tscal = 1.f; + } else { + tscal = .5f / (smlnum * tmax); + sscal_(n, &tscal, &cnorm[1], &c__1); + } + +/* + Compute a bound on the computed solution vector to see if the + Level 2 BLAS routine CTRSV can be used. +*/ + + xmax = 0.f; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = j; + r__3 = xmax, r__4 = (r__1 = x[i__2].r / 2.f, dabs(r__1)) + (r__2 = + r_imag(&x[j]) / 2.f, dabs(r__2)); + xmax = dmax(r__3,r__4); +/* L30: */ + } + xbnd = xmax; + + if (notran) { + +/* Compute the growth in A * x = b. */ + + if (upper) { + jfirst = *n; + jlast = 1; + jinc = -1; + } else { + jfirst = 1; + jlast = *n; + jinc = 1; + } + + if (tscal != 1.f) { + grow = 0.f; + goto L60; + } + + if (nounit) { + +/* + A is non-unit triangular. + + Compute GROW = 1/G(j) and XBND = 1/M(j). + Initially, G(0) = max{x(i), i=1,...,n}. +*/ + + grow = .5f / dmax(xbnd,smlnum); + xbnd = grow; + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L60; + } + + i__3 = j + j * a_dim1; + tjjs.r = a[i__3].r, tjjs.i = a[i__3].i; + tjj = (r__1 = tjjs.r, dabs(r__1)) + (r__2 = r_imag(&tjjs), + dabs(r__2)); + + if (tjj >= smlnum) { + +/* + M(j) = G(j-1) / abs(A(j,j)) + + Computing MIN +*/ + r__1 = xbnd, r__2 = dmin(1.f,tjj) * grow; + xbnd = dmin(r__1,r__2); + } else { + +/* M(j) could overflow, set XBND to 0. */ + + xbnd = 0.f; + } + + if (tjj + cnorm[j] >= smlnum) { + +/* G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) */ + + grow *= tjj / (tjj + cnorm[j]); + } else { + +/* G(j) could overflow, set GROW to 0. */ + + grow = 0.f; + } +/* L40: */ + } + grow = xbnd; + } else { + +/* + A is unit triangular. + + Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. + + Computing MIN +*/ + r__1 = 1.f, r__2 = .5f / dmax(xbnd,smlnum); + grow = dmin(r__1,r__2); + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L60; + } + +/* G(j) = G(j-1)*( 1 + CNORM(j) ) */ + + grow *= 1.f / (cnorm[j] + 1.f); +/* L50: */ + } + } +L60: + + ; + } else { + +/* Compute the growth in A**T * x = b or A**H * x = b. */ + + if (upper) { + jfirst = 1; + jlast = *n; + jinc = 1; + } else { + jfirst = *n; + jlast = 1; + jinc = -1; + } + + if (tscal != 1.f) { + grow = 0.f; + goto L90; + } + + if (nounit) { + +/* + A is non-unit triangular. + + Compute GROW = 1/G(j) and XBND = 1/M(j). + Initially, M(0) = max{x(i), i=1,...,n}. +*/ + + grow = .5f / dmax(xbnd,smlnum); + xbnd = grow; + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L90; + } + +/* G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) */ + + xj = cnorm[j] + 1.f; +/* Computing MIN */ + r__1 = grow, r__2 = xbnd / xj; + grow = dmin(r__1,r__2); + + i__3 = j + j * a_dim1; + tjjs.r = a[i__3].r, tjjs.i = a[i__3].i; + tjj = (r__1 = tjjs.r, dabs(r__1)) + (r__2 = r_imag(&tjjs), + dabs(r__2)); + + if (tjj >= smlnum) { + +/* M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) */ + + if (xj > tjj) { + xbnd *= tjj / xj; + } + } else { + +/* M(j) could overflow, set XBND to 0. */ + + xbnd = 0.f; + } +/* L70: */ + } + grow = dmin(grow,xbnd); + } else { + +/* + A is unit triangular. + + Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. + + Computing MIN +*/ + r__1 = 1.f, r__2 = .5f / dmax(xbnd,smlnum); + grow = dmin(r__1,r__2); + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L90; + } + +/* G(j) = ( 1 + CNORM(j) )*G(j-1) */ + + xj = cnorm[j] + 1.f; + grow /= xj; +/* L80: */ + } + } +L90: + ; + } + + if (grow * tscal > smlnum) { + +/* + Use the Level 2 BLAS solve if the reciprocal of the bound on + elements of X is not too small. +*/ + + ctrsv_(uplo, trans, diag, n, &a[a_offset], lda, &x[1], &c__1); + } else { + +/* Use a Level 1 BLAS solve, scaling intermediate results. */ + + if (xmax > bignum * .5f) { + +/* + Scale X so that its components are less than or equal to + BIGNUM in absolute value. +*/ + + *scale = bignum * .5f / xmax; + csscal_(n, scale, &x[1], &c__1); + xmax = bignum; + } else { + xmax *= 2.f; + } + + if (notran) { + +/* Solve A * x = b */ + + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Compute x(j) = b(j) / A(j,j), scaling x if necessary. */ + + i__3 = j; + xj = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = r_imag(&x[j]), + dabs(r__2)); + if (nounit) { + i__3 = j + j * a_dim1; + q__1.r = tscal * a[i__3].r, q__1.i = tscal * a[i__3].i; + tjjs.r = q__1.r, tjjs.i = q__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.f; + if (tscal == 1.f) { + goto L105; + } + } + tjj = (r__1 = tjjs.r, dabs(r__1)) + (r__2 = r_imag(&tjjs), + dabs(r__2)); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.f) { + if (xj > tjj * bignum) { + +/* Scale x by 1/b(j). */ + + rec = 1.f / xj; + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + i__3 = j; + cladiv_(&q__1, &x[j], &tjjs); + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + i__3 = j; + xj = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = r_imag(&x[j] + ), dabs(r__2)); + } else if (tjj > 0.f) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* + Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM + to avoid overflow when dividing by A(j,j). +*/ + + rec = tjj * bignum / xj; + if (cnorm[j] > 1.f) { + +/* + Scale by 1/CNORM(j) to avoid overflow when + multiplying x(j) times column j. +*/ + + rec /= cnorm[j]; + } + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + i__3 = j; + cladiv_(&q__1, &x[j], &tjjs); + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + i__3 = j; + xj = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = r_imag(&x[j] + ), dabs(r__2)); + } else { + +/* + A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and + scale = 0, and compute a solution to A*x = 0. +*/ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__; + x[i__4].r = 0.f, x[i__4].i = 0.f; +/* L100: */ + } + i__3 = j; + x[i__3].r = 1.f, x[i__3].i = 0.f; + xj = 1.f; + *scale = 0.f; + xmax = 0.f; + } +L105: + +/* + Scale x if necessary to avoid overflow when adding a + multiple of column j of A. +*/ + + if (xj > 1.f) { + rec = 1.f / xj; + if (cnorm[j] > (bignum - xmax) * rec) { + +/* Scale x by 1/(2*abs(x(j))). */ + + rec *= .5f; + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + } + } else if (xj * cnorm[j] > bignum - xmax) { + +/* Scale x by 1/2. */ + + csscal_(n, &c_b2023, &x[1], &c__1); + *scale *= .5f; + } + + if (upper) { + if (j > 1) { + +/* + Compute the update + x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j) +*/ + + i__3 = j - 1; + i__4 = j; + q__2.r = -x[i__4].r, q__2.i = -x[i__4].i; + q__1.r = tscal * q__2.r, q__1.i = tscal * q__2.i; + caxpy_(&i__3, &q__1, &a[j * a_dim1 + 1], &c__1, &x[1], + &c__1); + i__3 = j - 1; + i__ = icamax_(&i__3, &x[1], &c__1); + i__3 = i__; + xmax = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = + r_imag(&x[i__]), dabs(r__2)); + } + } else { + if (j < *n) { + +/* + Compute the update + x(j+1:n) := x(j+1:n) - x(j) * A(j+1:n,j) +*/ + + i__3 = *n - j; + i__4 = j; + q__2.r = -x[i__4].r, q__2.i = -x[i__4].i; + q__1.r = tscal * q__2.r, q__1.i = tscal * q__2.i; + caxpy_(&i__3, &q__1, &a[j + 1 + j * a_dim1], &c__1, & + x[j + 1], &c__1); + i__3 = *n - j; + i__ = j + icamax_(&i__3, &x[j + 1], &c__1); + i__3 = i__; + xmax = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = + r_imag(&x[i__]), dabs(r__2)); + } + } +/* L110: */ + } + + } else if (lsame_(trans, "T")) { + +/* Solve A**T * x = b */ + + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* + Compute x(j) = b(j) - sum A(k,j)*x(k). + k<>j +*/ + + i__3 = j; + xj = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = r_imag(&x[j]), + dabs(r__2)); + uscal.r = tscal, uscal.i = 0.f; + rec = 1.f / dmax(xmax,1.f); + if (cnorm[j] > (bignum - xj) * rec) { + +/* If x(j) could overflow, scale x by 1/(2*XMAX). */ + + rec *= .5f; + if (nounit) { + i__3 = j + j * a_dim1; + q__1.r = tscal * a[i__3].r, q__1.i = tscal * a[i__3] + .i; + tjjs.r = q__1.r, tjjs.i = q__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.f; + } + tjj = (r__1 = tjjs.r, dabs(r__1)) + (r__2 = r_imag(&tjjs), + dabs(r__2)); + if (tjj > 1.f) { + +/* + Divide by A(j,j) when scaling x if A(j,j) > 1. + + Computing MIN +*/ + r__1 = 1.f, r__2 = rec * tjj; + rec = dmin(r__1,r__2); + cladiv_(&q__1, &uscal, &tjjs); + uscal.r = q__1.r, uscal.i = q__1.i; + } + if (rec < 1.f) { + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + + csumj.r = 0.f, csumj.i = 0.f; + if (uscal.r == 1.f && uscal.i == 0.f) { + +/* + If the scaling needed for A in the dot product is 1, + call CDOTU to perform the dot product. +*/ + + if (upper) { + i__3 = j - 1; + cdotu_(&q__1, &i__3, &a[j * a_dim1 + 1], &c__1, &x[1], + &c__1); + csumj.r = q__1.r, csumj.i = q__1.i; + } else if (j < *n) { + i__3 = *n - j; + cdotu_(&q__1, &i__3, &a[j + 1 + j * a_dim1], &c__1, & + x[j + 1], &c__1); + csumj.r = q__1.r, csumj.i = q__1.i; + } + } else { + +/* Otherwise, use in-line code for the dot product. */ + + if (upper) { + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * a_dim1; + q__3.r = a[i__4].r * uscal.r - a[i__4].i * + uscal.i, q__3.i = a[i__4].r * uscal.i + a[ + i__4].i * uscal.r; + i__5 = i__; + q__2.r = q__3.r * x[i__5].r - q__3.i * x[i__5].i, + q__2.i = q__3.r * x[i__5].i + q__3.i * x[ + i__5].r; + q__1.r = csumj.r + q__2.r, q__1.i = csumj.i + + q__2.i; + csumj.r = q__1.r, csumj.i = q__1.i; +/* L120: */ + } + } else if (j < *n) { + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * a_dim1; + q__3.r = a[i__4].r * uscal.r - a[i__4].i * + uscal.i, q__3.i = a[i__4].r * uscal.i + a[ + i__4].i * uscal.r; + i__5 = i__; + q__2.r = q__3.r * x[i__5].r - q__3.i * x[i__5].i, + q__2.i = q__3.r * x[i__5].i + q__3.i * x[ + i__5].r; + q__1.r = csumj.r + q__2.r, q__1.i = csumj.i + + q__2.i; + csumj.r = q__1.r, csumj.i = q__1.i; +/* L130: */ + } + } + } + + q__1.r = tscal, q__1.i = 0.f; + if (uscal.r == q__1.r && uscal.i == q__1.i) { + +/* + Compute x(j) := ( x(j) - CSUMJ ) / A(j,j) if 1/A(j,j) + was not used to scale the dotproduct. +*/ + + i__3 = j; + i__4 = j; + q__1.r = x[i__4].r - csumj.r, q__1.i = x[i__4].i - + csumj.i; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + i__3 = j; + xj = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = r_imag(&x[j] + ), dabs(r__2)); + if (nounit) { + i__3 = j + j * a_dim1; + q__1.r = tscal * a[i__3].r, q__1.i = tscal * a[i__3] + .i; + tjjs.r = q__1.r, tjjs.i = q__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.f; + if (tscal == 1.f) { + goto L145; + } + } + +/* Compute x(j) = x(j) / A(j,j), scaling if necessary. */ + + tjj = (r__1 = tjjs.r, dabs(r__1)) + (r__2 = r_imag(&tjjs), + dabs(r__2)); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.f) { + if (xj > tjj * bignum) { + +/* Scale X by 1/abs(x(j)). */ + + rec = 1.f / xj; + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + i__3 = j; + cladiv_(&q__1, &x[j], &tjjs); + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + } else if (tjj > 0.f) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. */ + + rec = tjj * bignum / xj; + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + i__3 = j; + cladiv_(&q__1, &x[j], &tjjs); + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + } else { + +/* + A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and + scale = 0 and compute a solution to A**T *x = 0. +*/ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__; + x[i__4].r = 0.f, x[i__4].i = 0.f; +/* L140: */ + } + i__3 = j; + x[i__3].r = 1.f, x[i__3].i = 0.f; + *scale = 0.f; + xmax = 0.f; + } +L145: + ; + } else { + +/* + Compute x(j) := x(j) / A(j,j) - CSUMJ if the dot + product has already been divided by 1/A(j,j). +*/ + + i__3 = j; + cladiv_(&q__2, &x[j], &tjjs); + q__1.r = q__2.r - csumj.r, q__1.i = q__2.i - csumj.i; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + } +/* Computing MAX */ + i__3 = j; + r__3 = xmax, r__4 = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = + r_imag(&x[j]), dabs(r__2)); + xmax = dmax(r__3,r__4); +/* L150: */ + } + + } else { + +/* Solve A**H * x = b */ + + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* + Compute x(j) = b(j) - sum A(k,j)*x(k). + k<>j +*/ + + i__3 = j; + xj = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = r_imag(&x[j]), + dabs(r__2)); + uscal.r = tscal, uscal.i = 0.f; + rec = 1.f / dmax(xmax,1.f); + if (cnorm[j] > (bignum - xj) * rec) { + +/* If x(j) could overflow, scale x by 1/(2*XMAX). */ + + rec *= .5f; + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + q__1.r = tscal * q__2.r, q__1.i = tscal * q__2.i; + tjjs.r = q__1.r, tjjs.i = q__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.f; + } + tjj = (r__1 = tjjs.r, dabs(r__1)) + (r__2 = r_imag(&tjjs), + dabs(r__2)); + if (tjj > 1.f) { + +/* + Divide by A(j,j) when scaling x if A(j,j) > 1. + + Computing MIN +*/ + r__1 = 1.f, r__2 = rec * tjj; + rec = dmin(r__1,r__2); + cladiv_(&q__1, &uscal, &tjjs); + uscal.r = q__1.r, uscal.i = q__1.i; + } + if (rec < 1.f) { + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + + csumj.r = 0.f, csumj.i = 0.f; + if (uscal.r == 1.f && uscal.i == 0.f) { + +/* + If the scaling needed for A in the dot product is 1, + call CDOTC to perform the dot product. +*/ + + if (upper) { + i__3 = j - 1; + cdotc_(&q__1, &i__3, &a[j * a_dim1 + 1], &c__1, &x[1], + &c__1); + csumj.r = q__1.r, csumj.i = q__1.i; + } else if (j < *n) { + i__3 = *n - j; + cdotc_(&q__1, &i__3, &a[j + 1 + j * a_dim1], &c__1, & + x[j + 1], &c__1); + csumj.r = q__1.r, csumj.i = q__1.i; + } + } else { + +/* Otherwise, use in-line code for the dot product. */ + + if (upper) { + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + r_cnjg(&q__4, &a[i__ + j * a_dim1]); + q__3.r = q__4.r * uscal.r - q__4.i * uscal.i, + q__3.i = q__4.r * uscal.i + q__4.i * + uscal.r; + i__4 = i__; + q__2.r = q__3.r * x[i__4].r - q__3.i * x[i__4].i, + q__2.i = q__3.r * x[i__4].i + q__3.i * x[ + i__4].r; + q__1.r = csumj.r + q__2.r, q__1.i = csumj.i + + q__2.i; + csumj.r = q__1.r, csumj.i = q__1.i; +/* L160: */ + } + } else if (j < *n) { + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + r_cnjg(&q__4, &a[i__ + j * a_dim1]); + q__3.r = q__4.r * uscal.r - q__4.i * uscal.i, + q__3.i = q__4.r * uscal.i + q__4.i * + uscal.r; + i__4 = i__; + q__2.r = q__3.r * x[i__4].r - q__3.i * x[i__4].i, + q__2.i = q__3.r * x[i__4].i + q__3.i * x[ + i__4].r; + q__1.r = csumj.r + q__2.r, q__1.i = csumj.i + + q__2.i; + csumj.r = q__1.r, csumj.i = q__1.i; +/* L170: */ + } + } + } + + q__1.r = tscal, q__1.i = 0.f; + if (uscal.r == q__1.r && uscal.i == q__1.i) { + +/* + Compute x(j) := ( x(j) - CSUMJ ) / A(j,j) if 1/A(j,j) + was not used to scale the dotproduct. +*/ + + i__3 = j; + i__4 = j; + q__1.r = x[i__4].r - csumj.r, q__1.i = x[i__4].i - + csumj.i; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + i__3 = j; + xj = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = r_imag(&x[j] + ), dabs(r__2)); + if (nounit) { + r_cnjg(&q__2, &a[j + j * a_dim1]); + q__1.r = tscal * q__2.r, q__1.i = tscal * q__2.i; + tjjs.r = q__1.r, tjjs.i = q__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.f; + if (tscal == 1.f) { + goto L185; + } + } + +/* Compute x(j) = x(j) / A(j,j), scaling if necessary. */ + + tjj = (r__1 = tjjs.r, dabs(r__1)) + (r__2 = r_imag(&tjjs), + dabs(r__2)); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.f) { + if (xj > tjj * bignum) { + +/* Scale X by 1/abs(x(j)). */ + + rec = 1.f / xj; + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + i__3 = j; + cladiv_(&q__1, &x[j], &tjjs); + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + } else if (tjj > 0.f) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. */ + + rec = tjj * bignum / xj; + csscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + i__3 = j; + cladiv_(&q__1, &x[j], &tjjs); + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + } else { + +/* + A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and + scale = 0 and compute a solution to A**H *x = 0. +*/ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__; + x[i__4].r = 0.f, x[i__4].i = 0.f; +/* L180: */ + } + i__3 = j; + x[i__3].r = 1.f, x[i__3].i = 0.f; + *scale = 0.f; + xmax = 0.f; + } +L185: + ; + } else { + +/* + Compute x(j) := x(j) / A(j,j) - CSUMJ if the dot + product has already been divided by 1/A(j,j). +*/ + + i__3 = j; + cladiv_(&q__2, &x[j], &tjjs); + q__1.r = q__2.r - csumj.r, q__1.i = q__2.i - csumj.i; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + } +/* Computing MAX */ + i__3 = j; + r__3 = xmax, r__4 = (r__1 = x[i__3].r, dabs(r__1)) + (r__2 = + r_imag(&x[j]), dabs(r__2)); + xmax = dmax(r__3,r__4); +/* L190: */ + } + } + *scale /= tscal; + } + +/* Scale the column norms by 1/TSCAL for return. */ + + if (tscal != 1.f) { + r__1 = 1.f / tscal; + sscal_(n, &r__1, &cnorm[1], &c__1); + } + + return 0; + +/* End of CLATRS */ + +} /* clatrs_ */ + +/* Subroutine */ int clauu2_(char *uplo, integer *n, complex *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + real r__1; + complex q__1; + + /* Local variables */ + static integer i__; + static real aii; + extern /* Complex */ VOID cdotc_(complex *, integer *, complex *, integer + *, complex *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int cgemv_(char *, integer *, integer *, complex * + , complex *, integer *, complex *, integer *, complex *, complex * + , integer *); + static logical upper; + extern /* Subroutine */ int clacgv_(integer *, complex *, integer *), + csscal_(integer *, real *, complex *, integer *), xerbla_(char *, + integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLAUU2 computes the product U * U' or L' * L, where the triangular + factor U or L is stored in the upper or lower triangular part of + the array A. + + If UPLO = 'U' or 'u' then the upper triangle of the result is stored, + overwriting the factor U in A. + If UPLO = 'L' or 'l' then the lower triangle of the result is stored, + overwriting the factor L in A. + + This is the unblocked form of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the triangular factor stored in the array A + is upper or lower triangular: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the triangular factor U or L. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the triangular factor U or L. + On exit, if UPLO = 'U', the upper triangle of A is + overwritten with the upper triangle of the product U * U'; + if UPLO = 'L', the lower triangle of A is overwritten with + the lower triangle of the product L' * L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CLAUU2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the product U * U'. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + aii = a[i__2].r; + if (i__ < *n) { + i__2 = i__ + i__ * a_dim1; + i__3 = *n - i__; + cdotc_(&q__1, &i__3, &a[i__ + (i__ + 1) * a_dim1], lda, &a[ + i__ + (i__ + 1) * a_dim1], lda); + r__1 = aii * aii + q__1.r; + a[i__2].r = r__1, a[i__2].i = 0.f; + i__2 = *n - i__; + clacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ - 1; + i__3 = *n - i__; + q__1.r = aii, q__1.i = 0.f; + cgemv_("No transpose", &i__2, &i__3, &c_b57, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ + (i__ + 1) * a_dim1], lda, & + q__1, &a[i__ * a_dim1 + 1], &c__1); + i__2 = *n - i__; + clacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + } else { + csscal_(&i__, &aii, &a[i__ * a_dim1 + 1], &c__1); + } +/* L10: */ + } + + } else { + +/* Compute the product L' * L. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + aii = a[i__2].r; + if (i__ < *n) { + i__2 = i__ + i__ * a_dim1; + i__3 = *n - i__; + cdotc_(&q__1, &i__3, &a[i__ + 1 + i__ * a_dim1], &c__1, &a[ + i__ + 1 + i__ * a_dim1], &c__1); + r__1 = aii * aii + q__1.r; + a[i__2].r = r__1, a[i__2].i = 0.f; + i__2 = i__ - 1; + clacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = *n - i__; + i__3 = i__ - 1; + q__1.r = aii, q__1.i = 0.f; + cgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + 1 + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + q__1, &a[i__ + a_dim1], lda); + i__2 = i__ - 1; + clacgv_(&i__2, &a[i__ + a_dim1], lda); + } else { + csscal_(&i__, &aii, &a[i__ + a_dim1], lda); + } +/* L20: */ + } + } + + return 0; + +/* End of CLAUU2 */ + +} /* clauu2_ */ + +/* Subroutine */ int clauum_(char *uplo, integer *n, complex *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, ib, nb; + extern /* Subroutine */ int cgemm_(char *, char *, integer *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *), cherk_(char *, + char *, integer *, integer *, real *, complex *, integer *, real * + , complex *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int ctrmm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *); + static logical upper; + extern /* Subroutine */ int clauu2_(char *, integer *, complex *, integer + *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CLAUUM computes the product U * U' or L' * L, where the triangular + factor U or L is stored in the upper or lower triangular part of + the array A. + + If UPLO = 'U' or 'u' then the upper triangle of the result is stored, + overwriting the factor U in A. + If UPLO = 'L' or 'l' then the lower triangle of the result is stored, + overwriting the factor L in A. + + This is the blocked form of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the triangular factor stored in the array A + is upper or lower triangular: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the triangular factor U or L. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the triangular factor U or L. + On exit, if UPLO = 'U', the upper triangle of A is + overwritten with the upper triangle of the product U * U'; + if UPLO = 'L', the lower triangle of A is overwritten with + the lower triangle of the product L' * L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CLAUUM", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "CLAUUM", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code */ + + clauu2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code */ + + if (upper) { + +/* Compute the product U * U'. */ + + i__1 = *n; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = nb, i__4 = *n - i__ + 1; + ib = min(i__3,i__4); + i__3 = i__ - 1; + ctrmm_("Right", "Upper", "Conjugate transpose", "Non-unit", & + i__3, &ib, &c_b57, &a[i__ + i__ * a_dim1], lda, &a[ + i__ * a_dim1 + 1], lda); + clauu2_("Upper", &ib, &a[i__ + i__ * a_dim1], lda, info); + if (i__ + ib <= *n) { + i__3 = i__ - 1; + i__4 = *n - i__ - ib + 1; + cgemm_("No transpose", "Conjugate transpose", &i__3, &ib, + &i__4, &c_b57, &a[(i__ + ib) * a_dim1 + 1], lda, & + a[i__ + (i__ + ib) * a_dim1], lda, &c_b57, &a[i__ + * a_dim1 + 1], lda); + i__3 = *n - i__ - ib + 1; + cherk_("Upper", "No transpose", &ib, &i__3, &c_b894, &a[ + i__ + (i__ + ib) * a_dim1], lda, &c_b894, &a[i__ + + i__ * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the product L' * L. */ + + i__2 = *n; + i__1 = nb; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { +/* Computing MIN */ + i__3 = nb, i__4 = *n - i__ + 1; + ib = min(i__3,i__4); + i__3 = i__ - 1; + ctrmm_("Left", "Lower", "Conjugate transpose", "Non-unit", & + ib, &i__3, &c_b57, &a[i__ + i__ * a_dim1], lda, &a[ + i__ + a_dim1], lda); + clauu2_("Lower", &ib, &a[i__ + i__ * a_dim1], lda, info); + if (i__ + ib <= *n) { + i__3 = i__ - 1; + i__4 = *n - i__ - ib + 1; + cgemm_("Conjugate transpose", "No transpose", &ib, &i__3, + &i__4, &c_b57, &a[i__ + ib + i__ * a_dim1], lda, & + a[i__ + ib + a_dim1], lda, &c_b57, &a[i__ + + a_dim1], lda); + i__3 = *n - i__ - ib + 1; + cherk_("Lower", "Conjugate transpose", &ib, &i__3, & + c_b894, &a[i__ + ib + i__ * a_dim1], lda, &c_b894, + &a[i__ + i__ * a_dim1], lda); + } +/* L20: */ + } + } + } + + return 0; + +/* End of CLAUUM */ + +} /* clauum_ */ + +/* Subroutine */ int cpotf2_(char *uplo, integer *n, complex *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + real r__1; + complex q__1, q__2; + + /* Local variables */ + static integer j; + static real ajj; + extern /* Complex */ VOID cdotc_(complex *, integer *, complex *, integer + *, complex *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int cgemv_(char *, integer *, integer *, complex * + , complex *, integer *, complex *, integer *, complex *, complex * + , integer *); + static logical upper; + extern /* Subroutine */ int clacgv_(integer *, complex *, integer *), + csscal_(integer *, real *, complex *, integer *), xerbla_(char *, + integer *); + extern logical sisnan_(real *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CPOTF2 computes the Cholesky factorization of a complex Hermitian + positive definite matrix A. + + The factorization has the form + A = U' * U , if UPLO = 'U', or + A = L * L', if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the unblocked version of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + Hermitian matrix A is stored. + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + n by n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U'*U or A = L*L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, the leading minor of order k is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CPOTF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute U(J,J) and test for non-positive-definiteness. */ + + i__2 = j + j * a_dim1; + r__1 = a[i__2].r; + i__3 = j - 1; + cdotc_(&q__2, &i__3, &a[j * a_dim1 + 1], &c__1, &a[j * a_dim1 + 1] + , &c__1); + q__1.r = r__1 - q__2.r, q__1.i = -q__2.i; + ajj = q__1.r; + if (ajj <= 0.f || sisnan_(&ajj)) { + i__2 = j + j * a_dim1; + a[i__2].r = ajj, a[i__2].i = 0.f; + goto L30; + } + ajj = sqrt(ajj); + i__2 = j + j * a_dim1; + a[i__2].r = ajj, a[i__2].i = 0.f; + +/* Compute elements J+1:N of row J. */ + + if (j < *n) { + i__2 = j - 1; + clacgv_(&i__2, &a[j * a_dim1 + 1], &c__1); + i__2 = j - 1; + i__3 = *n - j; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("Transpose", &i__2, &i__3, &q__1, &a[(j + 1) * a_dim1 + + 1], lda, &a[j * a_dim1 + 1], &c__1, &c_b57, &a[j + ( + j + 1) * a_dim1], lda); + i__2 = j - 1; + clacgv_(&i__2, &a[j * a_dim1 + 1], &c__1); + i__2 = *n - j; + r__1 = 1.f / ajj; + csscal_(&i__2, &r__1, &a[j + (j + 1) * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute L(J,J) and test for non-positive-definiteness. */ + + i__2 = j + j * a_dim1; + r__1 = a[i__2].r; + i__3 = j - 1; + cdotc_(&q__2, &i__3, &a[j + a_dim1], lda, &a[j + a_dim1], lda); + q__1.r = r__1 - q__2.r, q__1.i = -q__2.i; + ajj = q__1.r; + if (ajj <= 0.f || sisnan_(&ajj)) { + i__2 = j + j * a_dim1; + a[i__2].r = ajj, a[i__2].i = 0.f; + goto L30; + } + ajj = sqrt(ajj); + i__2 = j + j * a_dim1; + a[i__2].r = ajj, a[i__2].i = 0.f; + +/* Compute elements J+1:N of column J. */ + + if (j < *n) { + i__2 = j - 1; + clacgv_(&i__2, &a[j + a_dim1], lda); + i__2 = *n - j; + i__3 = j - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemv_("No transpose", &i__2, &i__3, &q__1, &a[j + 1 + a_dim1] + , lda, &a[j + a_dim1], lda, &c_b57, &a[j + 1 + j * + a_dim1], &c__1); + i__2 = j - 1; + clacgv_(&i__2, &a[j + a_dim1], lda); + i__2 = *n - j; + r__1 = 1.f / ajj; + csscal_(&i__2, &r__1, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + goto L40; + +L30: + *info = j; + +L40: + return 0; + +/* End of CPOTF2 */ + +} /* cpotf2_ */ + +/* Subroutine */ int cpotrf_(char *uplo, integer *n, complex *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + complex q__1; + + /* Local variables */ + static integer j, jb, nb; + extern /* Subroutine */ int cgemm_(char *, char *, integer *, integer *, + integer *, complex *, complex *, integer *, complex *, integer *, + complex *, complex *, integer *), cherk_(char *, + char *, integer *, integer *, real *, complex *, integer *, real * + , complex *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int ctrsm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *); + static logical upper; + extern /* Subroutine */ int cpotf2_(char *, integer *, complex *, integer + *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CPOTRF computes the Cholesky factorization of a complex Hermitian + positive definite matrix A. + + The factorization has the form + A = U**H * U, if UPLO = 'U', or + A = L * L**H, if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the block version of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U**H*U or A = L*L**H. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the leading minor of order i is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CPOTRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "CPOTRF", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code. */ + + cpotf2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code. */ + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + cherk_("Upper", "Conjugate transpose", &jb, &i__3, &c_b1136, & + a[j * a_dim1 + 1], lda, &c_b894, &a[j + j * a_dim1], + lda); + cpotf2_("Upper", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block row. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("Conjugate transpose", "No transpose", &jb, &i__3, + &i__4, &q__1, &a[j * a_dim1 + 1], lda, &a[(j + jb) + * a_dim1 + 1], lda, &c_b57, &a[j + (j + jb) * + a_dim1], lda); + i__3 = *n - j - jb + 1; + ctrsm_("Left", "Upper", "Conjugate transpose", "Non-unit", + &jb, &i__3, &c_b57, &a[j + j * a_dim1], lda, &a[ + j + (j + jb) * a_dim1], lda); + } +/* L10: */ + } + + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__2 = *n; + i__1 = nb; + for (j = 1; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + cherk_("Lower", "No transpose", &jb, &i__3, &c_b1136, &a[j + + a_dim1], lda, &c_b894, &a[j + j * a_dim1], lda); + cpotf2_("Lower", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block column. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + q__1.r = -1.f, q__1.i = -0.f; + cgemm_("No transpose", "Conjugate transpose", &i__3, &jb, + &i__4, &q__1, &a[j + jb + a_dim1], lda, &a[j + + a_dim1], lda, &c_b57, &a[j + jb + j * a_dim1], + lda); + i__3 = *n - j - jb + 1; + ctrsm_("Right", "Lower", "Conjugate transpose", "Non-unit" + , &i__3, &jb, &c_b57, &a[j + j * a_dim1], lda, &a[ + j + jb + j * a_dim1], lda); + } +/* L20: */ + } + } + } + goto L40; + +L30: + *info = *info + j - 1; + +L40: + return 0; + +/* End of CPOTRF */ + +} /* cpotrf_ */ + +/* Subroutine */ int cpotri_(char *uplo, integer *n, complex *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *), clauum_( + char *, integer *, complex *, integer *, integer *), + ctrtri_(char *, char *, integer *, complex *, integer *, integer * + ); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CPOTRI computes the inverse of a complex Hermitian positive definite + matrix A using the Cholesky factorization A = U**H*U or A = L*L**H + computed by CPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the triangular factor U or L from the Cholesky + factorization A = U**H*U or A = L*L**H, as computed by + CPOTRF. + On exit, the upper or lower triangle of the (Hermitian) + inverse of A, overwriting the input factor U or L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the (i,i) element of the factor U or L is + zero, and the inverse could not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CPOTRI", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Invert the triangular Cholesky factor U or L. */ + + ctrtri_(uplo, "Non-unit", n, &a[a_offset], lda, info); + if (*info > 0) { + return 0; + } + +/* Form inv(U)*inv(U)' or inv(L)'*inv(L). */ + + clauum_(uplo, n, &a[a_offset], lda, info); + + return 0; + +/* End of CPOTRI */ + +} /* cpotri_ */ + +/* Subroutine */ int cpotrs_(char *uplo, integer *n, integer *nrhs, complex * + a, integer *lda, complex *b, integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int ctrsm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CPOTRS solves a system of linear equations A*X = B with a Hermitian + positive definite matrix A using the Cholesky factorization + A = U**H*U or A = L*L**H computed by CPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) COMPLEX array, dimension (LDA,N) + The triangular factor U or L from the Cholesky factorization + A = U**H*U or A = L*L**H, as computed by CPOTRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + B (input/output) COMPLEX array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CPOTRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (upper) { + +/* + Solve A*X = B where A = U'*U. + + Solve U'*X = B, overwriting B with X. +*/ + + ctrsm_("Left", "Upper", "Conjugate transpose", "Non-unit", n, nrhs, & + c_b57, &a[a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + ctrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b57, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A*X = B where A = L*L'. + + Solve L*X = B, overwriting B with X. +*/ + + ctrsm_("Left", "Lower", "No transpose", "Non-unit", n, nrhs, &c_b57, & + a[a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + ctrsm_("Left", "Lower", "Conjugate transpose", "Non-unit", n, nrhs, & + c_b57, &a[a_offset], lda, &b[b_offset], ldb); + } + + return 0; + +/* End of CPOTRS */ + +} /* cpotrs_ */ + +/* Subroutine */ int crot_(integer *n, complex *cx, integer *incx, complex * + cy, integer *incy, real *c__, complex *s) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + complex q__1, q__2, q__3, q__4; + + /* Local variables */ + static integer i__, ix, iy; + static complex stemp; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CROT applies a plane rotation, where the cos (C) is real and the + sin (S) is complex, and the vectors CX and CY are complex. + + Arguments + ========= + + N (input) INTEGER + The number of elements in the vectors CX and CY. + + CX (input/output) COMPLEX array, dimension (N) + On input, the vector X. + On output, CX is overwritten with C*X + S*Y. + + INCX (input) INTEGER + The increment between successive values of CY. INCX <> 0. + + CY (input/output) COMPLEX array, dimension (N) + On input, the vector Y. + On output, CY is overwritten with -CONJG(S)*X + C*Y. + + INCY (input) INTEGER + The increment between successive values of CY. INCX <> 0. + + C (input) REAL + S (input) COMPLEX + C and S define a rotation + [ C S ] + [ -conjg(S) C ] + where C*C + S*CONJG(S) = 1.0. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* Code for unequal increments or equal increments not equal to 1 */ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + q__2.r = *c__ * cx[i__2].r, q__2.i = *c__ * cx[i__2].i; + i__3 = iy; + q__3.r = s->r * cy[i__3].r - s->i * cy[i__3].i, q__3.i = s->r * cy[ + i__3].i + s->i * cy[i__3].r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + stemp.r = q__1.r, stemp.i = q__1.i; + i__2 = iy; + i__3 = iy; + q__2.r = *c__ * cy[i__3].r, q__2.i = *c__ * cy[i__3].i; + r_cnjg(&q__4, s); + i__4 = ix; + q__3.r = q__4.r * cx[i__4].r - q__4.i * cx[i__4].i, q__3.i = q__4.r * + cx[i__4].i + q__4.i * cx[i__4].r; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - q__3.i; + cy[i__2].r = q__1.r, cy[i__2].i = q__1.i; + i__2 = ix; + cx[i__2].r = stemp.r, cx[i__2].i = stemp.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* Code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + q__2.r = *c__ * cx[i__2].r, q__2.i = *c__ * cx[i__2].i; + i__3 = i__; + q__3.r = s->r * cy[i__3].r - s->i * cy[i__3].i, q__3.i = s->r * cy[ + i__3].i + s->i * cy[i__3].r; + q__1.r = q__2.r + q__3.r, q__1.i = q__2.i + q__3.i; + stemp.r = q__1.r, stemp.i = q__1.i; + i__2 = i__; + i__3 = i__; + q__2.r = *c__ * cy[i__3].r, q__2.i = *c__ * cy[i__3].i; + r_cnjg(&q__4, s); + i__4 = i__; + q__3.r = q__4.r * cx[i__4].r - q__4.i * cx[i__4].i, q__3.i = q__4.r * + cx[i__4].i + q__4.i * cx[i__4].r; + q__1.r = q__2.r - q__3.r, q__1.i = q__2.i - q__3.i; + cy[i__2].r = q__1.r, cy[i__2].i = q__1.i; + i__2 = i__; + cx[i__2].r = stemp.r, cx[i__2].i = stemp.i; +/* L30: */ + } + return 0; +} /* crot_ */ + +/* Subroutine */ int cstedc_(char *compz, integer *n, real *d__, real *e, + complex *z__, integer *ldz, complex *work, integer *lwork, real * + rwork, integer *lrwork, integer *iwork, integer *liwork, integer * + info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2, i__3, i__4; + real r__1, r__2; + + /* Local variables */ + static integer i__, j, k, m; + static real p; + static integer ii, ll, lgn; + static real eps, tiny; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int cswap_(integer *, complex *, integer *, + complex *, integer *); + static integer lwmin; + extern /* Subroutine */ int claed0_(integer *, integer *, real *, real *, + complex *, integer *, complex *, integer *, real *, integer *, + integer *); + static integer start; + extern /* Subroutine */ int clacrm_(integer *, integer *, complex *, + integer *, real *, integer *, complex *, integer *, real *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int clacpy_(char *, integer *, integer *, complex + *, integer *, complex *, integer *), xerbla_(char *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer finish; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *), sstedc_(char *, integer *, real *, real *, real *, + integer *, real *, integer *, integer *, integer *, integer *), slaset_(char *, integer *, integer *, real *, real *, + real *, integer *); + static integer liwmin, icompz; + extern /* Subroutine */ int csteqr_(char *, integer *, real *, real *, + complex *, integer *, real *, integer *); + static real orgnrm; + extern doublereal slanst_(char *, integer *, real *, real *); + extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *); + static integer lrwmin; + static logical lquery; + static integer smlsiz; + extern /* Subroutine */ int ssteqr_(char *, integer *, real *, real *, + real *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CSTEDC computes all eigenvalues and, optionally, eigenvectors of a + symmetric tridiagonal matrix using the divide and conquer method. + The eigenvectors of a full or band complex Hermitian matrix can also + be found if CHETRD or CHPTRD or CHBTRD has been used to reduce this + matrix to tridiagonal form. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. See SLAED3 for details. + + Arguments + ========= + + COMPZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only. + = 'I': Compute eigenvectors of tridiagonal matrix also. + = 'V': Compute eigenvectors of original Hermitian matrix + also. On entry, Z contains the unitary matrix used + to reduce the original matrix to tridiagonal form. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) REAL array, dimension (N-1) + On entry, the subdiagonal elements of the tridiagonal matrix. + On exit, E has been destroyed. + + Z (input/output) COMPLEX array, dimension (LDZ,N) + On entry, if COMPZ = 'V', then Z contains the unitary + matrix used in the reduction to tridiagonal form. + On exit, if INFO = 0, then if COMPZ = 'V', Z contains the + orthonormal eigenvectors of the original Hermitian matrix, + and if COMPZ = 'I', Z contains the orthonormal eigenvectors + of the symmetric tridiagonal matrix. + If COMPZ = 'N', then Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= 1. + If eigenvectors are desired, then LDZ >= max(1,N). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If COMPZ = 'N' or 'I', or N <= 1, LWORK must be at least 1. + If COMPZ = 'V' and N > 1, LWORK must be at least N*N. + Note that for COMPZ = 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LWORK need + only be 1. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal sizes of the WORK, RWORK and + IWORK arrays, returns these values as the first entries of + the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + RWORK (workspace/output) REAL array, dimension (MAX(1,LRWORK)) + On exit, if INFO = 0, RWORK(1) returns the optimal LRWORK. + + LRWORK (input) INTEGER + The dimension of the array RWORK. + If COMPZ = 'N' or N <= 1, LRWORK must be at least 1. + If COMPZ = 'V' and N > 1, LRWORK must be at least + 1 + 3*N + 2*N*lg N + 3*N**2 , + where lg( N ) = smallest integer k such + that 2**k >= N. + If COMPZ = 'I' and N > 1, LRWORK must be at least + 1 + 4*N + 2*N**2 . + Note that for COMPZ = 'I' or 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LRWORK + need only be max(1,2*(N-1)). + + If LRWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK, RWORK + and IWORK arrays, returns these values as the first entries + of the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) + On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. + + LIWORK (input) INTEGER + The dimension of the array IWORK. + If COMPZ = 'N' or N <= 1, LIWORK must be at least 1. + If COMPZ = 'V' or N > 1, LIWORK must be at least + 6 + 6*N + 5*N*lg N. + If COMPZ = 'I' or N > 1, LIWORK must be at least + 3 + 5*N . + Note that for COMPZ = 'I' or 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LIWORK + need only be 1. + + If LIWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK, RWORK + and IWORK arrays, returns these values as the first entries + of the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute an eigenvalue while + working on the submatrix lying in rows and columns + INFO/(N+1) through mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1 || *lrwork == -1 || *liwork == -1; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + + if (*info == 0) { + +/* Compute the workspace requirements */ + + smlsiz = ilaenv_(&c__9, "CSTEDC", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + if (*n <= 1 || icompz == 0) { + lwmin = 1; + liwmin = 1; + lrwmin = 1; + } else if (*n <= smlsiz) { + lwmin = 1; + liwmin = 1; + lrwmin = *n - 1 << 1; + } else if (icompz == 1) { + lgn = (integer) (log((real) (*n)) / log(2.f)); + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + lwmin = *n * *n; +/* Computing 2nd power */ + i__1 = *n; + lrwmin = *n * 3 + 1 + (*n << 1) * lgn + i__1 * i__1 * 3; + liwmin = *n * 6 + 6 + *n * 5 * lgn; + } else if (icompz == 2) { + lwmin = 1; +/* Computing 2nd power */ + i__1 = *n; + lrwmin = (*n << 2) + 1 + (i__1 * i__1 << 1); + liwmin = *n * 5 + 3; + } + work[1].r = (real) lwmin, work[1].i = 0.f; + rwork[1] = (real) lrwmin; + iwork[1] = liwmin; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*lrwork < lrwmin && ! lquery) { + *info = -10; + } else if (*liwork < liwmin && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CSTEDC", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*n == 1) { + if (icompz != 0) { + i__1 = z_dim1 + 1; + z__[i__1].r = 1.f, z__[i__1].i = 0.f; + } + return 0; + } + +/* + If the following conditional clause is removed, then the routine + will use the Divide and Conquer routine to compute only the + eigenvalues, which requires (3N + 3N**2) real workspace and + (2 + 5N + 2N lg(N)) integer workspace. + Since on many architectures SSTERF is much faster than any other + algorithm for finding eigenvalues only, it is used here + as the default. If the conditional clause is removed, then + information on the size of workspace needs to be changed. + + If COMPZ = 'N', use SSTERF to compute the eigenvalues. +*/ + + if (icompz == 0) { + ssterf_(n, &d__[1], &e[1], info); + goto L70; + } + +/* + If N is smaller than the minimum divide size (SMLSIZ+1), then + solve the problem with another solver. +*/ + + if (*n <= smlsiz) { + + csteqr_(compz, n, &d__[1], &e[1], &z__[z_offset], ldz, &rwork[1], + info); + + } else { + +/* If COMPZ = 'I', we simply call SSTEDC instead. */ + + if (icompz == 2) { + slaset_("Full", n, n, &c_b1087, &c_b894, &rwork[1], n); + ll = *n * *n + 1; + i__1 = *lrwork - ll + 1; + sstedc_("I", n, &d__[1], &e[1], &rwork[1], n, &rwork[ll], &i__1, & + iwork[1], liwork, info); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * z_dim1; + i__4 = (j - 1) * *n + i__; + z__[i__3].r = rwork[i__4], z__[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + goto L70; + } + +/* + From now on, only option left to be handled is COMPZ = 'V', + i.e. ICOMPZ = 1. + + Scale. +*/ + + orgnrm = slanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.f) { + goto L70; + } + + eps = slamch_("Epsilon"); + + start = 1; + +/* while ( START <= N ) */ + +L30: + if (start <= *n) { + +/* + Let FINISH be the position of the next subdiagonal entry + such that E( FINISH ) <= TINY or FINISH = N if no such + subdiagonal exists. The matrix identified by the elements + between START and FINISH constitutes an independent + sub-problem. +*/ + + finish = start; +L40: + if (finish < *n) { + tiny = eps * sqrt((r__1 = d__[finish], dabs(r__1))) * sqrt(( + r__2 = d__[finish + 1], dabs(r__2))); + if ((r__1 = e[finish], dabs(r__1)) > tiny) { + ++finish; + goto L40; + } + } + +/* (Sub) Problem determined. Compute its size and solve it. */ + + m = finish - start + 1; + if (m > smlsiz) { + +/* Scale. */ + + orgnrm = slanst_("M", &m, &d__[start], &e[start]); + slascl_("G", &c__0, &c__0, &orgnrm, &c_b894, &m, &c__1, &d__[ + start], &m, info); + i__1 = m - 1; + i__2 = m - 1; + slascl_("G", &c__0, &c__0, &orgnrm, &c_b894, &i__1, &c__1, &e[ + start], &i__2, info); + + claed0_(n, &m, &d__[start], &e[start], &z__[start * z_dim1 + + 1], ldz, &work[1], n, &rwork[1], &iwork[1], info); + if (*info > 0) { + *info = (*info / (m + 1) + start - 1) * (*n + 1) + *info % + (m + 1) + start - 1; + goto L70; + } + +/* Scale back. */ + + slascl_("G", &c__0, &c__0, &c_b894, &orgnrm, &m, &c__1, &d__[ + start], &m, info); + + } else { + ssteqr_("I", &m, &d__[start], &e[start], &rwork[1], &m, & + rwork[m * m + 1], info); + clacrm_(n, &m, &z__[start * z_dim1 + 1], ldz, &rwork[1], &m, & + work[1], n, &rwork[m * m + 1]); + clacpy_("A", n, &m, &work[1], n, &z__[start * z_dim1 + 1], + ldz); + if (*info > 0) { + *info = start * (*n + 1) + finish; + goto L70; + } + } + + start = finish + 1; + goto L30; + } + +/* + endwhile + + If the problem split any number of times, then the eigenvalues + will not be properly ordered. Here we permute the eigenvalues + (and the associated eigenvectors) into ascending order. +*/ + + if (m != *n) { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L50: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + cswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + + 1], &c__1); + } +/* L60: */ + } + } + } + +L70: + work[1].r = (real) lwmin, work[1].i = 0.f; + rwork[1] = (real) lrwmin; + iwork[1] = liwmin; + + return 0; + +/* End of CSTEDC */ + +} /* cstedc_ */ + +/* Subroutine */ int csteqr_(char *compz, integer *n, real *d__, real *e, + complex *z__, integer *ldz, real *work, integer *info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2; + real r__1, r__2; + + /* Local variables */ + static real b, c__, f, g; + static integer i__, j, k, l, m; + static real p, r__, s; + static integer l1, ii, mm, lm1, mm1, nm1; + static real rt1, rt2, eps; + static integer lsv; + static real tst, eps2; + static integer lend, jtot; + extern /* Subroutine */ int slae2_(real *, real *, real *, real *, real *) + ; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int clasr_(char *, char *, char *, integer *, + integer *, real *, real *, complex *, integer *); + static real anorm; + extern /* Subroutine */ int cswap_(integer *, complex *, integer *, + complex *, integer *); + static integer lendm1, lendp1; + extern /* Subroutine */ int slaev2_(real *, real *, real *, real *, real * + , real *, real *); + extern doublereal slapy2_(real *, real *); + static integer iscale; + extern doublereal slamch_(char *); + extern /* Subroutine */ int claset_(char *, integer *, integer *, complex + *, complex *, complex *, integer *); + static real safmin; + extern /* Subroutine */ int xerbla_(char *, integer *); + static real safmax; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *); + static integer lendsv; + extern /* Subroutine */ int slartg_(real *, real *, real *, real *, real * + ); + static real ssfmin; + static integer nmaxit, icompz; + static real ssfmax; + extern doublereal slanst_(char *, integer *, real *, real *); + extern /* Subroutine */ int slasrt_(char *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CSTEQR computes all eigenvalues and, optionally, eigenvectors of a + symmetric tridiagonal matrix using the implicit QL or QR method. + The eigenvectors of a full or band complex Hermitian matrix can also + be found if CHETRD or CHPTRD or CHBTRD has been used to reduce this + matrix to tridiagonal form. + + Arguments + ========= + + COMPZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only. + = 'V': Compute eigenvalues and eigenvectors of the original + Hermitian matrix. On entry, Z must contain the + unitary matrix used to reduce the original matrix + to tridiagonal form. + = 'I': Compute eigenvalues and eigenvectors of the + tridiagonal matrix. Z is initialized to the identity + matrix. + + N (input) INTEGER + The order of the matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) REAL array, dimension (N-1) + On entry, the (n-1) subdiagonal elements of the tridiagonal + matrix. + On exit, E has been destroyed. + + Z (input/output) COMPLEX array, dimension (LDZ, N) + On entry, if COMPZ = 'V', then Z contains the unitary + matrix used in the reduction to tridiagonal form. + On exit, if INFO = 0, then if COMPZ = 'V', Z contains the + orthonormal eigenvectors of the original Hermitian matrix, + and if COMPZ = 'I', Z contains the orthonormal eigenvectors + of the symmetric tridiagonal matrix. + If COMPZ = 'N', then Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= 1, and if + eigenvectors are desired, then LDZ >= max(1,N). + + WORK (workspace) REAL array, dimension (max(1,2*N-2)) + If COMPZ = 'N', then WORK is not referenced. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: the algorithm has failed to find all the eigenvalues in + a total of 30*N iterations; if INFO = i, then i + elements of E have not converged to zero; on exit, D + and E contain the elements of a symmetric tridiagonal + matrix which is unitarily similar to the original + matrix. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CSTEQR", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (*n == 1) { + if (icompz == 2) { + i__1 = z_dim1 + 1; + z__[i__1].r = 1.f, z__[i__1].i = 0.f; + } + return 0; + } + +/* Determine the unit roundoff and over/underflow thresholds. */ + + eps = slamch_("E"); +/* Computing 2nd power */ + r__1 = eps; + eps2 = r__1 * r__1; + safmin = slamch_("S"); + safmax = 1.f / safmin; + ssfmax = sqrt(safmax) / 3.f; + ssfmin = sqrt(safmin) / eps2; + +/* + Compute the eigenvalues and eigenvectors of the tridiagonal + matrix. +*/ + + if (icompz == 2) { + claset_("Full", n, n, &c_b56, &c_b57, &z__[z_offset], ldz); + } + + nmaxit = *n * 30; + jtot = 0; + +/* + Determine where the matrix splits and choose QL or QR iteration + for each block, according to whether top or bottom diagonal + element is smaller. +*/ + + l1 = 1; + nm1 = *n - 1; + +L10: + if (l1 > *n) { + goto L160; + } + if (l1 > 1) { + e[l1 - 1] = 0.f; + } + if (l1 <= nm1) { + i__1 = nm1; + for (m = l1; m <= i__1; ++m) { + tst = (r__1 = e[m], dabs(r__1)); + if (tst == 0.f) { + goto L30; + } + if (tst <= sqrt((r__1 = d__[m], dabs(r__1))) * sqrt((r__2 = d__[m + + 1], dabs(r__2))) * eps) { + e[m] = 0.f; + goto L30; + } +/* L20: */ + } + } + m = *n; + +L30: + l = l1; + lsv = l; + lend = m; + lendsv = lend; + l1 = m + 1; + if (lend == l) { + goto L10; + } + +/* Scale submatrix in rows and columns L to LEND */ + + i__1 = lend - l + 1; + anorm = slanst_("I", &i__1, &d__[l], &e[l]); + iscale = 0; + if (anorm == 0.f) { + goto L10; + } + if (anorm > ssfmax) { + iscale = 1; + i__1 = lend - l + 1; + slascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + slascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, + info); + } else if (anorm < ssfmin) { + iscale = 2; + i__1 = lend - l + 1; + slascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + slascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, + info); + } + +/* Choose between QL and QR iteration */ + + if ((r__1 = d__[lend], dabs(r__1)) < (r__2 = d__[l], dabs(r__2))) { + lend = lsv; + l = lendsv; + } + + if (lend > l) { + +/* + QL Iteration + + Look for small subdiagonal element. +*/ + +L40: + if (l != lend) { + lendm1 = lend - 1; + i__1 = lendm1; + for (m = l; m <= i__1; ++m) { +/* Computing 2nd power */ + r__2 = (r__1 = e[m], dabs(r__1)); + tst = r__2 * r__2; + if (tst <= eps2 * (r__1 = d__[m], dabs(r__1)) * (r__2 = d__[m + + 1], dabs(r__2)) + safmin) { + goto L60; + } +/* L50: */ + } + } + + m = lend; + +L60: + if (m < lend) { + e[m] = 0.f; + } + p = d__[l]; + if (m == l) { + goto L80; + } + +/* + If remaining matrix is 2-by-2, use SLAE2 or SLAEV2 + to compute its eigensystem. +*/ + + if (m == l + 1) { + if (icompz > 0) { + slaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); + work[l] = c__; + work[*n - 1 + l] = s; + clasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], & + z__[l * z_dim1 + 1], ldz); + } else { + slae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); + } + d__[l] = rt1; + d__[l + 1] = rt2; + e[l] = 0.f; + l += 2; + if (l <= lend) { + goto L40; + } + goto L140; + } + + if (jtot == nmaxit) { + goto L140; + } + ++jtot; + +/* Form shift. */ + + g = (d__[l + 1] - p) / (e[l] * 2.f); + r__ = slapy2_(&g, &c_b894); + g = d__[m] - p + e[l] / (g + r_sign(&r__, &g)); + + s = 1.f; + c__ = 1.f; + p = 0.f; + +/* Inner loop */ + + mm1 = m - 1; + i__1 = l; + for (i__ = mm1; i__ >= i__1; --i__) { + f = s * e[i__]; + b = c__ * e[i__]; + slartg_(&g, &f, &c__, &s, &r__); + if (i__ != m - 1) { + e[i__ + 1] = r__; + } + g = d__[i__ + 1] - p; + r__ = (d__[i__] - g) * s + c__ * 2.f * b; + p = s * r__; + d__[i__ + 1] = g + p; + g = c__ * r__ - b; + +/* If eigenvectors are desired, then save rotations. */ + + if (icompz > 0) { + work[i__] = c__; + work[*n - 1 + i__] = -s; + } + +/* L70: */ + } + +/* If eigenvectors are desired, then apply saved rotations. */ + + if (icompz > 0) { + mm = m - l + 1; + clasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l + * z_dim1 + 1], ldz); + } + + d__[l] -= p; + e[l] = g; + goto L40; + +/* Eigenvalue found. */ + +L80: + d__[l] = p; + + ++l; + if (l <= lend) { + goto L40; + } + goto L140; + + } else { + +/* + QR Iteration + + Look for small superdiagonal element. +*/ + +L90: + if (l != lend) { + lendp1 = lend + 1; + i__1 = lendp1; + for (m = l; m >= i__1; --m) { +/* Computing 2nd power */ + r__2 = (r__1 = e[m - 1], dabs(r__1)); + tst = r__2 * r__2; + if (tst <= eps2 * (r__1 = d__[m], dabs(r__1)) * (r__2 = d__[m + - 1], dabs(r__2)) + safmin) { + goto L110; + } +/* L100: */ + } + } + + m = lend; + +L110: + if (m > lend) { + e[m - 1] = 0.f; + } + p = d__[l]; + if (m == l) { + goto L130; + } + +/* + If remaining matrix is 2-by-2, use SLAE2 or SLAEV2 + to compute its eigensystem. +*/ + + if (m == l - 1) { + if (icompz > 0) { + slaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) + ; + work[m] = c__; + work[*n - 1 + m] = s; + clasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], & + z__[(l - 1) * z_dim1 + 1], ldz); + } else { + slae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); + } + d__[l - 1] = rt1; + d__[l] = rt2; + e[l - 1] = 0.f; + l += -2; + if (l >= lend) { + goto L90; + } + goto L140; + } + + if (jtot == nmaxit) { + goto L140; + } + ++jtot; + +/* Form shift. */ + + g = (d__[l - 1] - p) / (e[l - 1] * 2.f); + r__ = slapy2_(&g, &c_b894); + g = d__[m] - p + e[l - 1] / (g + r_sign(&r__, &g)); + + s = 1.f; + c__ = 1.f; + p = 0.f; + +/* Inner loop */ + + lm1 = l - 1; + i__1 = lm1; + for (i__ = m; i__ <= i__1; ++i__) { + f = s * e[i__]; + b = c__ * e[i__]; + slartg_(&g, &f, &c__, &s, &r__); + if (i__ != m) { + e[i__ - 1] = r__; + } + g = d__[i__] - p; + r__ = (d__[i__ + 1] - g) * s + c__ * 2.f * b; + p = s * r__; + d__[i__] = g + p; + g = c__ * r__ - b; + +/* If eigenvectors are desired, then save rotations. */ + + if (icompz > 0) { + work[i__] = c__; + work[*n - 1 + i__] = s; + } + +/* L120: */ + } + +/* If eigenvectors are desired, then apply saved rotations. */ + + if (icompz > 0) { + mm = l - m + 1; + clasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m + * z_dim1 + 1], ldz); + } + + d__[l] -= p; + e[lm1] = g; + goto L90; + +/* Eigenvalue found. */ + +L130: + d__[l] = p; + + --l; + if (l >= lend) { + goto L90; + } + goto L140; + + } + +/* Undo scaling if necessary */ + +L140: + if (iscale == 1) { + i__1 = lendsv - lsv + 1; + slascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + i__1 = lendsv - lsv; + slascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, + info); + } else if (iscale == 2) { + i__1 = lendsv - lsv + 1; + slascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + i__1 = lendsv - lsv; + slascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, + info); + } + +/* + Check for no convergence to an eigenvalue after a total + of N*MAXIT iterations. +*/ + + if (jtot == nmaxit) { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (e[i__] != 0.f) { + ++(*info); + } +/* L150: */ + } + return 0; + } + goto L10; + +/* Order eigenvalues and eigenvectors. */ + +L160: + if (icompz == 0) { + +/* Use Quick Sort */ + + slasrt_("I", n, &d__[1], info); + + } else { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L170: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + cswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], + &c__1); + } +/* L180: */ + } + } + return 0; + +/* End of CSTEQR */ + +} /* csteqr_ */ + +/* Subroutine */ int ctrevc_(char *side, char *howmny, logical *select, + integer *n, complex *t, integer *ldt, complex *vl, integer *ldvl, + complex *vr, integer *ldvr, integer *mm, integer *m, complex *work, + real *rwork, integer *info) +{ + /* System generated locals */ + integer t_dim1, t_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, + i__2, i__3, i__4, i__5; + real r__1, r__2, r__3; + complex q__1, q__2; + + /* Local variables */ + static integer i__, j, k, ii, ki, is; + static real ulp; + static logical allv; + static real unfl, ovfl, smin; + static logical over; + static real scale; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int cgemv_(char *, integer *, integer *, complex * + , complex *, integer *, complex *, integer *, complex *, complex * + , integer *); + static real remax; + extern /* Subroutine */ int ccopy_(integer *, complex *, integer *, + complex *, integer *); + static logical leftv, bothv, somev; + extern /* Subroutine */ int slabad_(real *, real *); + extern integer icamax_(integer *, complex *, integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int csscal_(integer *, real *, complex *, integer + *), xerbla_(char *, integer *), clatrs_(char *, char *, + char *, char *, integer *, complex *, integer *, complex *, real * + , real *, integer *); + extern doublereal scasum_(integer *, complex *, integer *); + static logical rightv; + static real smlnum; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CTREVC computes some or all of the right and/or left eigenvectors of + a complex upper triangular matrix T. + Matrices of this type are produced by the Schur factorization of + a complex general matrix: A = Q*T*Q**H, as computed by CHSEQR. + + The right eigenvector x and the left eigenvector y of T corresponding + to an eigenvalue w are defined by: + + T*x = w*x, (y**H)*T = w*(y**H) + + where y**H denotes the conjugate transpose of the vector y. + The eigenvalues are not input to this routine, but are read directly + from the diagonal of T. + + This routine returns the matrices X and/or Y of right and left + eigenvectors of T, or the products Q*X and/or Q*Y, where Q is an + input matrix. If Q is the unitary factor that reduces a matrix A to + Schur form T, then Q*X and Q*Y are the matrices of right and left + eigenvectors of A. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'R': compute right eigenvectors only; + = 'L': compute left eigenvectors only; + = 'B': compute both right and left eigenvectors. + + HOWMNY (input) CHARACTER*1 + = 'A': compute all right and/or left eigenvectors; + = 'B': compute all right and/or left eigenvectors, + backtransformed using the matrices supplied in + VR and/or VL; + = 'S': compute selected right and/or left eigenvectors, + as indicated by the logical array SELECT. + + SELECT (input) LOGICAL array, dimension (N) + If HOWMNY = 'S', SELECT specifies the eigenvectors to be + computed. + The eigenvector corresponding to the j-th eigenvalue is + computed if SELECT(j) = .TRUE.. + Not referenced if HOWMNY = 'A' or 'B'. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input/output) COMPLEX array, dimension (LDT,N) + The upper triangular matrix T. T is modified, but restored + on exit. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + VL (input/output) COMPLEX array, dimension (LDVL,MM) + On entry, if SIDE = 'L' or 'B' and HOWMNY = 'B', VL must + contain an N-by-N matrix Q (usually the unitary matrix Q of + Schur vectors returned by CHSEQR). + On exit, if SIDE = 'L' or 'B', VL contains: + if HOWMNY = 'A', the matrix Y of left eigenvectors of T; + if HOWMNY = 'B', the matrix Q*Y; + if HOWMNY = 'S', the left eigenvectors of T specified by + SELECT, stored consecutively in the columns + of VL, in the same order as their + eigenvalues. + Not referenced if SIDE = 'R'. + + LDVL (input) INTEGER + The leading dimension of the array VL. LDVL >= 1, and if + SIDE = 'L' or 'B', LDVL >= N. + + VR (input/output) COMPLEX array, dimension (LDVR,MM) + On entry, if SIDE = 'R' or 'B' and HOWMNY = 'B', VR must + contain an N-by-N matrix Q (usually the unitary matrix Q of + Schur vectors returned by CHSEQR). + On exit, if SIDE = 'R' or 'B', VR contains: + if HOWMNY = 'A', the matrix X of right eigenvectors of T; + if HOWMNY = 'B', the matrix Q*X; + if HOWMNY = 'S', the right eigenvectors of T specified by + SELECT, stored consecutively in the columns + of VR, in the same order as their + eigenvalues. + Not referenced if SIDE = 'L'. + + LDVR (input) INTEGER + The leading dimension of the array VR. LDVR >= 1, and if + SIDE = 'R' or 'B'; LDVR >= N. + + MM (input) INTEGER + The number of columns in the arrays VL and/or VR. MM >= M. + + M (output) INTEGER + The number of columns in the arrays VL and/or VR actually + used to store the eigenvectors. If HOWMNY = 'A' or 'B', M + is set to N. Each selected eigenvector occupies one + column. + + WORK (workspace) COMPLEX array, dimension (2*N) + + RWORK (workspace) REAL array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The algorithm used in this program is basically backward (forward) + substitution, with scaling to make the the code robust against + possible overflow. + + Each eigenvector is normalized so that the element of largest + magnitude has magnitude 1; here the magnitude of a complex number + (x,y) is taken to be |x| + |y|. + + ===================================================================== + + + Decode and test the input parameters +*/ + + /* Parameter adjustments */ + --select; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + vl_dim1 = *ldvl; + vl_offset = 1 + vl_dim1; + vl -= vl_offset; + vr_dim1 = *ldvr; + vr_offset = 1 + vr_dim1; + vr -= vr_offset; + --work; + --rwork; + + /* Function Body */ + bothv = lsame_(side, "B"); + rightv = lsame_(side, "R") || bothv; + leftv = lsame_(side, "L") || bothv; + + allv = lsame_(howmny, "A"); + over = lsame_(howmny, "B"); + somev = lsame_(howmny, "S"); + +/* + Set M to the number of columns required to store the selected + eigenvectors. +*/ + + if (somev) { + *m = 0; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (select[j]) { + ++(*m); + } +/* L10: */ + } + } else { + *m = *n; + } + + *info = 0; + if (! rightv && ! leftv) { + *info = -1; + } else if (! allv && ! over && ! somev) { + *info = -2; + } else if (*n < 0) { + *info = -4; + } else if (*ldt < max(1,*n)) { + *info = -6; + } else if (*ldvl < 1 || leftv && *ldvl < *n) { + *info = -8; + } else if (*ldvr < 1 || rightv && *ldvr < *n) { + *info = -10; + } else if (*mm < *m) { + *info = -11; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CTREVC", &i__1); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + +/* Set the constants to control overflow. */ + + unfl = slamch_("Safe minimum"); + ovfl = 1.f / unfl; + slabad_(&unfl, &ovfl); + ulp = slamch_("Precision"); + smlnum = unfl * (*n / ulp); + +/* Store the diagonal elements of T in working array WORK. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + *n; + i__3 = i__ + i__ * t_dim1; + work[i__2].r = t[i__3].r, work[i__2].i = t[i__3].i; +/* L20: */ + } + +/* + Compute 1-norm of each column of strictly upper triangular + part of T to control overflow in triangular solver. +*/ + + rwork[1] = 0.f; + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + i__2 = j - 1; + rwork[j] = scasum_(&i__2, &t[j * t_dim1 + 1], &c__1); +/* L30: */ + } + + if (rightv) { + +/* Compute right eigenvectors. */ + + is = *m; + for (ki = *n; ki >= 1; --ki) { + + if (somev) { + if (! select[ki]) { + goto L80; + } + } +/* Computing MAX */ + i__1 = ki + ki * t_dim1; + r__3 = ulp * ((r__1 = t[i__1].r, dabs(r__1)) + (r__2 = r_imag(&t[ + ki + ki * t_dim1]), dabs(r__2))); + smin = dmax(r__3,smlnum); + + work[1].r = 1.f, work[1].i = 0.f; + +/* Form right-hand side. */ + + i__1 = ki - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = k; + i__3 = k + ki * t_dim1; + q__1.r = -t[i__3].r, q__1.i = -t[i__3].i; + work[i__2].r = q__1.r, work[i__2].i = q__1.i; +/* L40: */ + } + +/* + Solve the triangular system: + (T(1:KI-1,1:KI-1) - T(KI,KI))*X = SCALE*WORK. +*/ + + i__1 = ki - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = k + k * t_dim1; + i__3 = k + k * t_dim1; + i__4 = ki + ki * t_dim1; + q__1.r = t[i__3].r - t[i__4].r, q__1.i = t[i__3].i - t[i__4] + .i; + t[i__2].r = q__1.r, t[i__2].i = q__1.i; + i__2 = k + k * t_dim1; + if ((r__1 = t[i__2].r, dabs(r__1)) + (r__2 = r_imag(&t[k + k * + t_dim1]), dabs(r__2)) < smin) { + i__3 = k + k * t_dim1; + t[i__3].r = smin, t[i__3].i = 0.f; + } +/* L50: */ + } + + if (ki > 1) { + i__1 = ki - 1; + clatrs_("Upper", "No transpose", "Non-unit", "Y", &i__1, &t[ + t_offset], ldt, &work[1], &scale, &rwork[1], info); + i__1 = ki; + work[i__1].r = scale, work[i__1].i = 0.f; + } + +/* Copy the vector x or Q*x to VR and normalize. */ + + if (! over) { + ccopy_(&ki, &work[1], &c__1, &vr[is * vr_dim1 + 1], &c__1); + + ii = icamax_(&ki, &vr[is * vr_dim1 + 1], &c__1); + i__1 = ii + is * vr_dim1; + remax = 1.f / ((r__1 = vr[i__1].r, dabs(r__1)) + (r__2 = + r_imag(&vr[ii + is * vr_dim1]), dabs(r__2))); + csscal_(&ki, &remax, &vr[is * vr_dim1 + 1], &c__1); + + i__1 = *n; + for (k = ki + 1; k <= i__1; ++k) { + i__2 = k + is * vr_dim1; + vr[i__2].r = 0.f, vr[i__2].i = 0.f; +/* L60: */ + } + } else { + if (ki > 1) { + i__1 = ki - 1; + q__1.r = scale, q__1.i = 0.f; + cgemv_("N", n, &i__1, &c_b57, &vr[vr_offset], ldvr, &work[ + 1], &c__1, &q__1, &vr[ki * vr_dim1 + 1], &c__1); + } + + ii = icamax_(n, &vr[ki * vr_dim1 + 1], &c__1); + i__1 = ii + ki * vr_dim1; + remax = 1.f / ((r__1 = vr[i__1].r, dabs(r__1)) + (r__2 = + r_imag(&vr[ii + ki * vr_dim1]), dabs(r__2))); + csscal_(n, &remax, &vr[ki * vr_dim1 + 1], &c__1); + } + +/* Set back the original diagonal elements of T. */ + + i__1 = ki - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = k + k * t_dim1; + i__3 = k + *n; + t[i__2].r = work[i__3].r, t[i__2].i = work[i__3].i; +/* L70: */ + } + + --is; +L80: + ; + } + } + + if (leftv) { + +/* Compute left eigenvectors. */ + + is = 1; + i__1 = *n; + for (ki = 1; ki <= i__1; ++ki) { + + if (somev) { + if (! select[ki]) { + goto L130; + } + } +/* Computing MAX */ + i__2 = ki + ki * t_dim1; + r__3 = ulp * ((r__1 = t[i__2].r, dabs(r__1)) + (r__2 = r_imag(&t[ + ki + ki * t_dim1]), dabs(r__2))); + smin = dmax(r__3,smlnum); + + i__2 = *n; + work[i__2].r = 1.f, work[i__2].i = 0.f; + +/* Form right-hand side. */ + + i__2 = *n; + for (k = ki + 1; k <= i__2; ++k) { + i__3 = k; + r_cnjg(&q__2, &t[ki + k * t_dim1]); + q__1.r = -q__2.r, q__1.i = -q__2.i; + work[i__3].r = q__1.r, work[i__3].i = q__1.i; +/* L90: */ + } + +/* + Solve the triangular system: + (T(KI+1:N,KI+1:N) - T(KI,KI))'*X = SCALE*WORK. +*/ + + i__2 = *n; + for (k = ki + 1; k <= i__2; ++k) { + i__3 = k + k * t_dim1; + i__4 = k + k * t_dim1; + i__5 = ki + ki * t_dim1; + q__1.r = t[i__4].r - t[i__5].r, q__1.i = t[i__4].i - t[i__5] + .i; + t[i__3].r = q__1.r, t[i__3].i = q__1.i; + i__3 = k + k * t_dim1; + if ((r__1 = t[i__3].r, dabs(r__1)) + (r__2 = r_imag(&t[k + k * + t_dim1]), dabs(r__2)) < smin) { + i__4 = k + k * t_dim1; + t[i__4].r = smin, t[i__4].i = 0.f; + } +/* L100: */ + } + + if (ki < *n) { + i__2 = *n - ki; + clatrs_("Upper", "Conjugate transpose", "Non-unit", "Y", & + i__2, &t[ki + 1 + (ki + 1) * t_dim1], ldt, &work[ki + + 1], &scale, &rwork[1], info); + i__2 = ki; + work[i__2].r = scale, work[i__2].i = 0.f; + } + +/* Copy the vector x or Q*x to VL and normalize. */ + + if (! over) { + i__2 = *n - ki + 1; + ccopy_(&i__2, &work[ki], &c__1, &vl[ki + is * vl_dim1], &c__1) + ; + + i__2 = *n - ki + 1; + ii = icamax_(&i__2, &vl[ki + is * vl_dim1], &c__1) + ki - 1; + i__2 = ii + is * vl_dim1; + remax = 1.f / ((r__1 = vl[i__2].r, dabs(r__1)) + (r__2 = + r_imag(&vl[ii + is * vl_dim1]), dabs(r__2))); + i__2 = *n - ki + 1; + csscal_(&i__2, &remax, &vl[ki + is * vl_dim1], &c__1); + + i__2 = ki - 1; + for (k = 1; k <= i__2; ++k) { + i__3 = k + is * vl_dim1; + vl[i__3].r = 0.f, vl[i__3].i = 0.f; +/* L110: */ + } + } else { + if (ki < *n) { + i__2 = *n - ki; + q__1.r = scale, q__1.i = 0.f; + cgemv_("N", n, &i__2, &c_b57, &vl[(ki + 1) * vl_dim1 + 1], + ldvl, &work[ki + 1], &c__1, &q__1, &vl[ki * + vl_dim1 + 1], &c__1); + } + + ii = icamax_(n, &vl[ki * vl_dim1 + 1], &c__1); + i__2 = ii + ki * vl_dim1; + remax = 1.f / ((r__1 = vl[i__2].r, dabs(r__1)) + (r__2 = + r_imag(&vl[ii + ki * vl_dim1]), dabs(r__2))); + csscal_(n, &remax, &vl[ki * vl_dim1 + 1], &c__1); + } + +/* Set back the original diagonal elements of T. */ + + i__2 = *n; + for (k = ki + 1; k <= i__2; ++k) { + i__3 = k + k * t_dim1; + i__4 = k + *n; + t[i__3].r = work[i__4].r, t[i__3].i = work[i__4].i; +/* L120: */ + } + + ++is; +L130: + ; + } + } + + return 0; + +/* End of CTREVC */ + +} /* ctrevc_ */ + +/* Subroutine */ int ctrexc_(char *compq, integer *n, complex *t, integer * + ldt, complex *q, integer *ldq, integer *ifst, integer *ilst, integer * + info) +{ + /* System generated locals */ + integer q_dim1, q_offset, t_dim1, t_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer k, m1, m2, m3; + static real cs; + static complex t11, t22, sn, temp; + extern /* Subroutine */ int crot_(integer *, complex *, integer *, + complex *, integer *, real *, complex *); + extern logical lsame_(char *, char *); + static logical wantq; + extern /* Subroutine */ int clartg_(complex *, complex *, real *, complex + *, complex *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CTREXC reorders the Schur factorization of a complex matrix + A = Q*T*Q**H, so that the diagonal element of T with row index IFST + is moved to row ILST. + + The Schur form T is reordered by a unitary similarity transformation + Z**H*T*Z, and optionally the matrix Q of Schur vectors is updated by + postmultplying it with Z. + + Arguments + ========= + + COMPQ (input) CHARACTER*1 + = 'V': update the matrix Q of Schur vectors; + = 'N': do not update Q. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input/output) COMPLEX array, dimension (LDT,N) + On entry, the upper triangular matrix T. + On exit, the reordered upper triangular matrix. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + Q (input/output) COMPLEX array, dimension (LDQ,N) + On entry, if COMPQ = 'V', the matrix Q of Schur vectors. + On exit, if COMPQ = 'V', Q has been postmultiplied by the + unitary transformation matrix Z which reorders T. + If COMPQ = 'N', Q is not referenced. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + IFST (input) INTEGER + ILST (input) INTEGER + Specify the reordering of the diagonal elements of T: + The element with row index IFST is moved to row ILST by a + sequence of transpositions between adjacent elements. + 1 <= IFST <= N; 1 <= ILST <= N. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Decode and test the input parameters. +*/ + + /* Parameter adjustments */ + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + + /* Function Body */ + *info = 0; + wantq = lsame_(compq, "V"); + if (! lsame_(compq, "N") && ! wantq) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldt < max(1,*n)) { + *info = -4; + } else if (*ldq < 1 || wantq && *ldq < max(1,*n)) { + *info = -6; + } else if (*ifst < 1 || *ifst > *n) { + *info = -7; + } else if (*ilst < 1 || *ilst > *n) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CTREXC", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 1 || *ifst == *ilst) { + return 0; + } + + if (*ifst < *ilst) { + +/* Move the IFST-th diagonal element forward down the diagonal. */ + + m1 = 0; + m2 = -1; + m3 = 1; + } else { + +/* Move the IFST-th diagonal element backward up the diagonal. */ + + m1 = -1; + m2 = 0; + m3 = -1; + } + + i__1 = *ilst + m2; + i__2 = m3; + for (k = *ifst + m1; i__2 < 0 ? k >= i__1 : k <= i__1; k += i__2) { + +/* Interchange the k-th and (k+1)-th diagonal elements. */ + + i__3 = k + k * t_dim1; + t11.r = t[i__3].r, t11.i = t[i__3].i; + i__3 = k + 1 + (k + 1) * t_dim1; + t22.r = t[i__3].r, t22.i = t[i__3].i; + +/* Determine the transformation to perform the interchange. */ + + q__1.r = t22.r - t11.r, q__1.i = t22.i - t11.i; + clartg_(&t[k + (k + 1) * t_dim1], &q__1, &cs, &sn, &temp); + +/* Apply transformation to the matrix T. */ + + if (k + 2 <= *n) { + i__3 = *n - k - 1; + crot_(&i__3, &t[k + (k + 2) * t_dim1], ldt, &t[k + 1 + (k + 2) * + t_dim1], ldt, &cs, &sn); + } + i__3 = k - 1; + r_cnjg(&q__1, &sn); + crot_(&i__3, &t[k * t_dim1 + 1], &c__1, &t[(k + 1) * t_dim1 + 1], & + c__1, &cs, &q__1); + + i__3 = k + k * t_dim1; + t[i__3].r = t22.r, t[i__3].i = t22.i; + i__3 = k + 1 + (k + 1) * t_dim1; + t[i__3].r = t11.r, t[i__3].i = t11.i; + + if (wantq) { + +/* Accumulate transformation in the matrix Q. */ + + r_cnjg(&q__1, &sn); + crot_(n, &q[k * q_dim1 + 1], &c__1, &q[(k + 1) * q_dim1 + 1], & + c__1, &cs, &q__1); + } + +/* L10: */ + } + + return 0; + +/* End of CTREXC */ + +} /* ctrexc_ */ + +/* Subroutine */ int ctrti2_(char *uplo, char *diag, integer *n, complex *a, + integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + complex q__1; + + /* Local variables */ + static integer j; + static complex ajj; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *); + extern logical lsame_(char *, char *); + static logical upper; + extern /* Subroutine */ int ctrmv_(char *, char *, char *, integer *, + complex *, integer *, complex *, integer *), xerbla_(char *, integer *); + static logical nounit; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CTRTI2 computes the inverse of a complex upper or lower triangular + matrix. + + This is the Level 2 BLAS version of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the matrix A is upper or lower triangular. + = 'U': Upper triangular + = 'L': Lower triangular + + DIAG (input) CHARACTER*1 + Specifies whether or not the matrix A is unit triangular. + = 'N': Non-unit triangular + = 'U': Unit triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the triangular matrix A. If UPLO = 'U', the + leading n by n upper triangular part of the array A contains + the upper triangular matrix, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of the array A contains + the lower triangular matrix, and the strictly upper + triangular part of A is not referenced. If DIAG = 'U', the + diagonal elements of A are also not referenced and are + assumed to be 1. + + On exit, the (triangular) inverse of the original matrix, in + the same storage format. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + nounit = lsame_(diag, "N"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CTRTI2", &i__1); + return 0; + } + + if (upper) { + +/* Compute inverse of upper triangular matrix. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (nounit) { + i__2 = j + j * a_dim1; + c_div(&q__1, &c_b57, &a[j + j * a_dim1]); + a[i__2].r = q__1.r, a[i__2].i = q__1.i; + i__2 = j + j * a_dim1; + q__1.r = -a[i__2].r, q__1.i = -a[i__2].i; + ajj.r = q__1.r, ajj.i = q__1.i; + } else { + q__1.r = -1.f, q__1.i = -0.f; + ajj.r = q__1.r, ajj.i = q__1.i; + } + +/* Compute elements 1:j-1 of j-th column. */ + + i__2 = j - 1; + ctrmv_("Upper", "No transpose", diag, &i__2, &a[a_offset], lda, & + a[j * a_dim1 + 1], &c__1); + i__2 = j - 1; + cscal_(&i__2, &ajj, &a[j * a_dim1 + 1], &c__1); +/* L10: */ + } + } else { + +/* Compute inverse of lower triangular matrix. */ + + for (j = *n; j >= 1; --j) { + if (nounit) { + i__1 = j + j * a_dim1; + c_div(&q__1, &c_b57, &a[j + j * a_dim1]); + a[i__1].r = q__1.r, a[i__1].i = q__1.i; + i__1 = j + j * a_dim1; + q__1.r = -a[i__1].r, q__1.i = -a[i__1].i; + ajj.r = q__1.r, ajj.i = q__1.i; + } else { + q__1.r = -1.f, q__1.i = -0.f; + ajj.r = q__1.r, ajj.i = q__1.i; + } + if (j < *n) { + +/* Compute elements j+1:n of j-th column. */ + + i__1 = *n - j; + ctrmv_("Lower", "No transpose", diag, &i__1, &a[j + 1 + (j + + 1) * a_dim1], lda, &a[j + 1 + j * a_dim1], &c__1); + i__1 = *n - j; + cscal_(&i__1, &ajj, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + + return 0; + +/* End of CTRTI2 */ + +} /* ctrti2_ */ + +/* Subroutine */ int ctrtri_(char *uplo, char *diag, integer *n, complex *a, + integer *lda, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, i__1, i__2, i__3[2], i__4, i__5; + complex q__1; + char ch__1[2]; + + /* Local variables */ + static integer j, jb, nb, nn; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int ctrmm_(char *, char *, char *, char *, + integer *, integer *, complex *, complex *, integer *, complex *, + integer *), ctrsm_(char *, char *, + char *, char *, integer *, integer *, complex *, complex *, + integer *, complex *, integer *); + static logical upper; + extern /* Subroutine */ int ctrti2_(char *, char *, integer *, complex *, + integer *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical nounit; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CTRTRI computes the inverse of a complex upper or lower triangular + matrix A. + + This is the Level 3 BLAS version of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': A is upper triangular; + = 'L': A is lower triangular. + + DIAG (input) CHARACTER*1 + = 'N': A is non-unit triangular; + = 'U': A is unit triangular. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the triangular matrix A. If UPLO = 'U', the + leading N-by-N upper triangular part of the array A contains + the upper triangular matrix, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of the array A contains + the lower triangular matrix, and the strictly upper + triangular part of A is not referenced. If DIAG = 'U', the + diagonal elements of A are also not referenced and are + assumed to be 1. + On exit, the (triangular) inverse of the original matrix, in + the same storage format. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, A(i,i) is exactly zero. The triangular + matrix is singular and its inverse can not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + nounit = lsame_(diag, "N"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CTRTRI", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Check for singularity if non-unit. */ + + if (nounit) { + i__1 = *n; + for (*info = 1; *info <= i__1; ++(*info)) { + i__2 = *info + *info * a_dim1; + if (a[i__2].r == 0.f && a[i__2].i == 0.f) { + return 0; + } +/* L10: */ + } + *info = 0; + } + +/* + Determine the block size for this environment. + + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = uplo; + i__3[1] = 1, a__1[1] = diag; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "CTRTRI", ch__1, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)2); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code */ + + ctrti2_(uplo, diag, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code */ + + if (upper) { + +/* Compute inverse of upper triangular matrix */ + + i__1 = *n; + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *n - j + 1; + jb = min(i__4,i__5); + +/* Compute rows 1:j-1 of current block column */ + + i__4 = j - 1; + ctrmm_("Left", "Upper", "No transpose", diag, &i__4, &jb, & + c_b57, &a[a_offset], lda, &a[j * a_dim1 + 1], lda); + i__4 = j - 1; + q__1.r = -1.f, q__1.i = -0.f; + ctrsm_("Right", "Upper", "No transpose", diag, &i__4, &jb, & + q__1, &a[j + j * a_dim1], lda, &a[j * a_dim1 + 1], + lda); + +/* Compute inverse of current diagonal block */ + + ctrti2_("Upper", diag, &jb, &a[j + j * a_dim1], lda, info); +/* L20: */ + } + } else { + +/* Compute inverse of lower triangular matrix */ + + nn = (*n - 1) / nb * nb + 1; + i__2 = -nb; + for (j = nn; i__2 < 0 ? j >= 1 : j <= 1; j += i__2) { +/* Computing MIN */ + i__1 = nb, i__4 = *n - j + 1; + jb = min(i__1,i__4); + if (j + jb <= *n) { + +/* Compute rows j+jb:n of current block column */ + + i__1 = *n - j - jb + 1; + ctrmm_("Left", "Lower", "No transpose", diag, &i__1, &jb, + &c_b57, &a[j + jb + (j + jb) * a_dim1], lda, &a[j + + jb + j * a_dim1], lda); + i__1 = *n - j - jb + 1; + q__1.r = -1.f, q__1.i = -0.f; + ctrsm_("Right", "Lower", "No transpose", diag, &i__1, &jb, + &q__1, &a[j + j * a_dim1], lda, &a[j + jb + j * + a_dim1], lda); + } + +/* Compute inverse of current diagonal block */ + + ctrti2_("Lower", diag, &jb, &a[j + j * a_dim1], lda, info); +/* L30: */ + } + } + } + + return 0; + +/* End of CTRTRI */ + +} /* ctrtri_ */ + +/* Subroutine */ int cung2r_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *), clarf_(char *, integer *, integer *, complex *, + integer *, complex *, complex *, integer *, complex *), + xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNG2R generates an m by n complex matrix Q with orthonormal columns, + which is defined as the first n columns of a product of k elementary + reflectors of order m + + Q = H(1) H(2) . . . H(k) + + as returned by CGEQRF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. M >= N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. N >= K >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the i-th column must contain the vector which + defines the elementary reflector H(i), for i = 1,2,...,k, as + returned by CGEQRF in the first k columns of its array + argument A. + On exit, the m by n matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGEQRF. + + WORK (workspace) COMPLEX array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0 || *n > *m) { + *info = -2; + } else if (*k < 0 || *k > *n) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNG2R", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + return 0; + } + +/* Initialise columns k+1:n to columns of the unit matrix */ + + i__1 = *n; + for (j = *k + 1; j <= i__1; ++j) { + i__2 = *m; + for (l = 1; l <= i__2; ++l) { + i__3 = l + j * a_dim1; + a[i__3].r = 0.f, a[i__3].i = 0.f; +/* L10: */ + } + i__2 = j + j * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; +/* L20: */ + } + + for (i__ = *k; i__ >= 1; --i__) { + +/* Apply H(i) to A(i:m,i:n) from the left */ + + if (i__ < *n) { + i__1 = i__ + i__ * a_dim1; + a[i__1].r = 1.f, a[i__1].i = 0.f; + i__1 = *m - i__ + 1; + i__2 = *n - i__; + clarf_("Left", &i__1, &i__2, &a[i__ + i__ * a_dim1], &c__1, &tau[ + i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + } + if (i__ < *m) { + i__1 = *m - i__; + i__2 = i__; + q__1.r = -tau[i__2].r, q__1.i = -tau[i__2].i; + cscal_(&i__1, &q__1, &a[i__ + 1 + i__ * a_dim1], &c__1); + } + i__1 = i__ + i__ * a_dim1; + i__2 = i__; + q__1.r = 1.f - tau[i__2].r, q__1.i = 0.f - tau[i__2].i; + a[i__1].r = q__1.r, a[i__1].i = q__1.i; + +/* Set A(1:i-1,i) to zero */ + + i__1 = i__ - 1; + for (l = 1; l <= i__1; ++l) { + i__2 = l + i__ * a_dim1; + a[i__2].r = 0.f, a[i__2].i = 0.f; +/* L30: */ + } +/* L40: */ + } + return 0; + +/* End of CUNG2R */ + +} /* cung2r_ */ + +/* Subroutine */ int cungbr_(char *vect, integer *m, integer *n, integer *k, + complex *a, integer *lda, complex *tau, complex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, nb, mn; + extern logical lsame_(char *, char *); + static integer iinfo; + static logical wantq; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int cunglq_(integer *, integer *, integer *, + complex *, integer *, complex *, complex *, integer *, integer *), + cungqr_(integer *, integer *, integer *, complex *, integer *, + complex *, complex *, integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNGBR generates one of the complex unitary matrices Q or P**H + determined by CGEBRD when reducing a complex matrix A to bidiagonal + form: A = Q * B * P**H. Q and P**H are defined as products of + elementary reflectors H(i) or G(i) respectively. + + If VECT = 'Q', A is assumed to have been an M-by-K matrix, and Q + is of order M: + if m >= k, Q = H(1) H(2) . . . H(k) and CUNGBR returns the first n + columns of Q, where m >= n >= k; + if m < k, Q = H(1) H(2) . . . H(m-1) and CUNGBR returns Q as an + M-by-M matrix. + + If VECT = 'P', A is assumed to have been a K-by-N matrix, and P**H + is of order N: + if k < n, P**H = G(k) . . . G(2) G(1) and CUNGBR returns the first m + rows of P**H, where n >= m >= k; + if k >= n, P**H = G(n-1) . . . G(2) G(1) and CUNGBR returns P**H as + an N-by-N matrix. + + Arguments + ========= + + VECT (input) CHARACTER*1 + Specifies whether the matrix Q or the matrix P**H is + required, as defined in the transformation applied by CGEBRD: + = 'Q': generate Q; + = 'P': generate P**H. + + M (input) INTEGER + The number of rows of the matrix Q or P**H to be returned. + M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q or P**H to be returned. + N >= 0. + If VECT = 'Q', M >= N >= min(M,K); + if VECT = 'P', N >= M >= min(N,K). + + K (input) INTEGER + If VECT = 'Q', the number of columns in the original M-by-K + matrix reduced by CGEBRD. + If VECT = 'P', the number of rows in the original K-by-N + matrix reduced by CGEBRD. + K >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the vectors which define the elementary reflectors, + as returned by CGEBRD. + On exit, the M-by-N matrix Q or P**H. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= M. + + TAU (input) COMPLEX array, dimension + (min(M,K)) if VECT = 'Q' + (min(N,K)) if VECT = 'P' + TAU(i) must contain the scalar factor of the elementary + reflector H(i) or G(i), which determines Q or P**H, as + returned by CGEBRD in its array argument TAUQ or TAUP. + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,min(M,N)). + For optimum performance LWORK >= min(M,N)*NB, where NB + is the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + wantq = lsame_(vect, "Q"); + mn = min(*m,*n); + lquery = *lwork == -1; + if (! wantq && ! lsame_(vect, "P")) { + *info = -1; + } else if (*m < 0) { + *info = -2; + } else if (*n < 0 || wantq && (*n > *m || *n < min(*m,*k)) || ! wantq && ( + *m > *n || *m < min(*n,*k))) { + *info = -3; + } else if (*k < 0) { + *info = -4; + } else if (*lda < max(1,*m)) { + *info = -6; + } else if (*lwork < max(1,mn) && ! lquery) { + *info = -9; + } + + if (*info == 0) { + if (wantq) { + nb = ilaenv_(&c__1, "CUNGQR", " ", m, n, k, &c_n1, (ftnlen)6, ( + ftnlen)1); + } else { + nb = ilaenv_(&c__1, "CUNGLQ", " ", m, n, k, &c_n1, (ftnlen)6, ( + ftnlen)1); + } + lwkopt = max(1,mn) * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNGBR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + if (wantq) { + +/* + Form Q, determined by a call to CGEBRD to reduce an m-by-k + matrix +*/ + + if (*m >= *k) { + +/* If m >= k, assume m >= n >= k */ + + cungqr_(m, n, k, &a[a_offset], lda, &tau[1], &work[1], lwork, & + iinfo); + + } else { + +/* + If m < k, assume m = n + + Shift the vectors which define the elementary reflectors one + column to the right, and set the first row and column of Q + to those of the unit matrix +*/ + + for (j = *m; j >= 2; --j) { + i__1 = j * a_dim1 + 1; + a[i__1].r = 0.f, a[i__1].i = 0.f; + i__1 = *m; + for (i__ = j + 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * a_dim1; + i__3 = i__ + (j - 1) * a_dim1; + a[i__2].r = a[i__3].r, a[i__2].i = a[i__3].i; +/* L10: */ + } +/* L20: */ + } + i__1 = a_dim1 + 1; + a[i__1].r = 1.f, a[i__1].i = 0.f; + i__1 = *m; + for (i__ = 2; i__ <= i__1; ++i__) { + i__2 = i__ + a_dim1; + a[i__2].r = 0.f, a[i__2].i = 0.f; +/* L30: */ + } + if (*m > 1) { + +/* Form Q(2:m,2:m) */ + + i__1 = *m - 1; + i__2 = *m - 1; + i__3 = *m - 1; + cungqr_(&i__1, &i__2, &i__3, &a[(a_dim1 << 1) + 2], lda, &tau[ + 1], &work[1], lwork, &iinfo); + } + } + } else { + +/* + Form P', determined by a call to CGEBRD to reduce a k-by-n + matrix +*/ + + if (*k < *n) { + +/* If k < n, assume k <= m <= n */ + + cunglq_(m, n, k, &a[a_offset], lda, &tau[1], &work[1], lwork, & + iinfo); + + } else { + +/* + If k >= n, assume m = n + + Shift the vectors which define the elementary reflectors one + row downward, and set the first row and column of P' to + those of the unit matrix +*/ + + i__1 = a_dim1 + 1; + a[i__1].r = 1.f, a[i__1].i = 0.f; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + i__2 = i__ + a_dim1; + a[i__2].r = 0.f, a[i__2].i = 0.f; +/* L40: */ + } + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + for (i__ = j - 1; i__ >= 2; --i__) { + i__2 = i__ + j * a_dim1; + i__3 = i__ - 1 + j * a_dim1; + a[i__2].r = a[i__3].r, a[i__2].i = a[i__3].i; +/* L50: */ + } + i__2 = j * a_dim1 + 1; + a[i__2].r = 0.f, a[i__2].i = 0.f; +/* L60: */ + } + if (*n > 1) { + +/* Form P'(2:n,2:n) */ + + i__1 = *n - 1; + i__2 = *n - 1; + i__3 = *n - 1; + cunglq_(&i__1, &i__2, &i__3, &a[(a_dim1 << 1) + 2], lda, &tau[ + 1], &work[1], lwork, &iinfo); + } + } + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CUNGBR */ + +} /* cungbr_ */ + +/* Subroutine */ int cunghr_(integer *n, integer *ilo, integer *ihi, complex * + a, integer *lda, complex *tau, complex *work, integer *lwork, integer + *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, nb, nh, iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int cungqr_(integer *, integer *, integer *, + complex *, integer *, complex *, complex *, integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNGHR generates a complex unitary matrix Q which is defined as the + product of IHI-ILO elementary reflectors of order N, as returned by + CGEHRD: + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Arguments + ========= + + N (input) INTEGER + The order of the matrix Q. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + ILO and IHI must have the same values as in the previous call + of CGEHRD. Q is equal to the unit matrix except in the + submatrix Q(ilo+1:ihi,ilo+1:ihi). + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the vectors which define the elementary reflectors, + as returned by CGEHRD. + On exit, the N-by-N unitary matrix Q. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (input) COMPLEX array, dimension (N-1) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGEHRD. + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= IHI-ILO. + For optimum performance LWORK >= (IHI-ILO)*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nh = *ihi - *ilo; + lquery = *lwork == -1; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*lwork < max(1,nh) && ! lquery) { + *info = -8; + } + + if (*info == 0) { + nb = ilaenv_(&c__1, "CUNGQR", " ", &nh, &nh, &nh, &c_n1, (ftnlen)6, ( + ftnlen)1); + lwkopt = max(1,nh) * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNGHR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + +/* + Shift the vectors which define the elementary reflectors one + column to the right, and set the first ilo and the last n-ihi + rows and columns to those of the unit matrix +*/ + + i__1 = *ilo + 1; + for (j = *ihi; j >= i__1; --j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0.f, a[i__3].i = 0.f; +/* L10: */ + } + i__2 = *ihi; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + (j - 1) * a_dim1; + a[i__3].r = a[i__4].r, a[i__3].i = a[i__4].i; +/* L20: */ + } + i__2 = *n; + for (i__ = *ihi + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0.f, a[i__3].i = 0.f; +/* L30: */ + } +/* L40: */ + } + i__1 = *ilo; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0.f, a[i__3].i = 0.f; +/* L50: */ + } + i__2 = j + j * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; +/* L60: */ + } + i__1 = *n; + for (j = *ihi + 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0.f, a[i__3].i = 0.f; +/* L70: */ + } + i__2 = j + j * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; +/* L80: */ + } + + if (nh > 0) { + +/* Generate Q(ilo+1:ihi,ilo+1:ihi) */ + + cungqr_(&nh, &nh, &nh, &a[*ilo + 1 + (*ilo + 1) * a_dim1], lda, &tau[* + ilo], &work[1], lwork, &iinfo); + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CUNGHR */ + +} /* cunghr_ */ + +/* Subroutine */ int cungl2_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + complex q__1, q__2; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int cscal_(integer *, complex *, complex *, + integer *), clarf_(char *, integer *, integer *, complex *, + integer *, complex *, complex *, integer *, complex *), + clacgv_(integer *, complex *, integer *), xerbla_(char *, integer + *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNGL2 generates an m-by-n complex matrix Q with orthonormal rows, + which is defined as the first m rows of a product of k elementary + reflectors of order n + + Q = H(k)' . . . H(2)' H(1)' + + as returned by CGELQF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. N >= M. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. M >= K >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the i-th row must contain the vector which defines + the elementary reflector H(i), for i = 1,2,...,k, as returned + by CGELQF in the first k rows of its array argument A. + On exit, the m by n matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGELQF. + + WORK (workspace) COMPLEX array, dimension (M) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < *m) { + *info = -2; + } else if (*k < 0 || *k > *m) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNGL2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m <= 0) { + return 0; + } + + if (*k < *m) { + +/* Initialise rows k+1:m to rows of the unit matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (l = *k + 1; l <= i__2; ++l) { + i__3 = l + j * a_dim1; + a[i__3].r = 0.f, a[i__3].i = 0.f; +/* L10: */ + } + if (j > *k && j <= *m) { + i__2 = j + j * a_dim1; + a[i__2].r = 1.f, a[i__2].i = 0.f; + } +/* L20: */ + } + } + + for (i__ = *k; i__ >= 1; --i__) { + +/* Apply H(i)' to A(i:m,i:n) from the right */ + + if (i__ < *n) { + i__1 = *n - i__; + clacgv_(&i__1, &a[i__ + (i__ + 1) * a_dim1], lda); + if (i__ < *m) { + i__1 = i__ + i__ * a_dim1; + a[i__1].r = 1.f, a[i__1].i = 0.f; + i__1 = *m - i__; + i__2 = *n - i__ + 1; + r_cnjg(&q__1, &tau[i__]); + clarf_("Right", &i__1, &i__2, &a[i__ + i__ * a_dim1], lda, & + q__1, &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + i__1 = *n - i__; + i__2 = i__; + q__1.r = -tau[i__2].r, q__1.i = -tau[i__2].i; + cscal_(&i__1, &q__1, &a[i__ + (i__ + 1) * a_dim1], lda); + i__1 = *n - i__; + clacgv_(&i__1, &a[i__ + (i__ + 1) * a_dim1], lda); + } + i__1 = i__ + i__ * a_dim1; + r_cnjg(&q__2, &tau[i__]); + q__1.r = 1.f - q__2.r, q__1.i = 0.f - q__2.i; + a[i__1].r = q__1.r, a[i__1].i = q__1.i; + +/* Set A(i,1:i-1,i) to zero */ + + i__1 = i__ - 1; + for (l = 1; l <= i__1; ++l) { + i__2 = i__ + l * a_dim1; + a[i__2].r = 0.f, a[i__2].i = 0.f; +/* L30: */ + } +/* L40: */ + } + return 0; + +/* End of CUNGL2 */ + +} /* cungl2_ */ + +/* Subroutine */ int cunglq_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *lwork, integer * + info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int cungl2_(integer *, integer *, integer *, + complex *, integer *, complex *, complex *, integer *), clarfb_( + char *, char *, char *, char *, integer *, integer *, integer *, + complex *, integer *, complex *, integer *, complex *, integer *, + complex *, integer *), clarft_( + char *, char *, integer *, integer *, complex *, integer *, + complex *, complex *, integer *), xerbla_(char *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNGLQ generates an M-by-N complex matrix Q with orthonormal rows, + which is defined as the first M rows of a product of K elementary + reflectors of order N + + Q = H(k)' . . . H(2)' H(1)' + + as returned by CGELQF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. N >= M. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. M >= K >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the i-th row must contain the vector which defines + the elementary reflector H(i), for i = 1,2,...,k, as returned + by CGELQF in the first k rows of its array argument A. + On exit, the M-by-N matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGELQF. + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,M). + For optimum performance LWORK >= M*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit; + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "CUNGLQ", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1); + lwkopt = max(1,*m) * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < *m) { + *info = -2; + } else if (*k < 0 || *k > *m) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*lwork < max(1,*m) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNGLQ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m <= 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *m; + if (nb > 1 && nb < *k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "CUNGLQ", " ", m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *m; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "CUNGLQ", " ", m, n, k, &c_n1, + (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < *k && nx < *k) { + +/* + Use blocked code after the last block. + The first kk rows are handled by the block method. +*/ + + ki = (*k - nx - 1) / nb * nb; +/* Computing MIN */ + i__1 = *k, i__2 = ki + nb; + kk = min(i__1,i__2); + +/* Set A(kk+1:m,1:kk) to zero. */ + + i__1 = kk; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = kk + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0.f, a[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + kk = 0; + } + +/* Use unblocked code for the last or only block. */ + + if (kk < *m) { + i__1 = *m - kk; + i__2 = *n - kk; + i__3 = *k - kk; + cungl2_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, & + tau[kk + 1], &work[1], &iinfo); + } + + if (kk > 0) { + +/* Use blocked code */ + + i__1 = -nb; + for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) { +/* Computing MIN */ + i__2 = nb, i__3 = *k - i__ + 1; + ib = min(i__2,i__3); + if (i__ + ib <= *m) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__2 = *n - i__ + 1; + clarft_("Forward", "Rowwise", &i__2, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H' to A(i+ib:m,i:n) from the right */ + + i__2 = *m - i__ - ib + 1; + i__3 = *n - i__ + 1; + clarfb_("Right", "Conjugate transpose", "Forward", "Rowwise", + &i__2, &i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[ + 1], &ldwork, &a[i__ + ib + i__ * a_dim1], lda, &work[ + ib + 1], &ldwork); + } + +/* Apply H' to columns i:n of current block */ + + i__2 = *n - i__ + 1; + cungl2_(&ib, &i__2, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], & + work[1], &iinfo); + +/* Set columns 1:i-1 of current block to zero */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = i__ + ib - 1; + for (l = i__; l <= i__3; ++l) { + i__4 = l + j * a_dim1; + a[i__4].r = 0.f, a[i__4].i = 0.f; +/* L30: */ + } +/* L40: */ + } +/* L50: */ + } + } + + work[1].r = (real) iws, work[1].i = 0.f; + return 0; + +/* End of CUNGLQ */ + +} /* cunglq_ */ + +/* Subroutine */ int cungqr_(integer *m, integer *n, integer *k, complex *a, + integer *lda, complex *tau, complex *work, integer *lwork, integer * + info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int cung2r_(integer *, integer *, integer *, + complex *, integer *, complex *, complex *, integer *), clarfb_( + char *, char *, char *, char *, integer *, integer *, integer *, + complex *, integer *, complex *, integer *, complex *, integer *, + complex *, integer *), clarft_( + char *, char *, integer *, integer *, complex *, integer *, + complex *, complex *, integer *), xerbla_(char *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNGQR generates an M-by-N complex matrix Q with orthonormal columns, + which is defined as the first N columns of a product of K elementary + reflectors of order M + + Q = H(1) H(2) . . . H(k) + + as returned by CGEQRF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. M >= N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. N >= K >= 0. + + A (input/output) COMPLEX array, dimension (LDA,N) + On entry, the i-th column must contain the vector which + defines the elementary reflector H(i), for i = 1,2,...,k, as + returned by CGEQRF in the first k columns of its array + argument A. + On exit, the M-by-N matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGEQRF. + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "CUNGQR", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1); + lwkopt = max(1,*n) * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0 || *n > *m) { + *info = -2; + } else if (*k < 0 || *k > *n) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNGQR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *n; + if (nb > 1 && nb < *k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "CUNGQR", " ", m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "CUNGQR", " ", m, n, k, &c_n1, + (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < *k && nx < *k) { + +/* + Use blocked code after the last block. + The first kk columns are handled by the block method. +*/ + + ki = (*k - nx - 1) / nb * nb; +/* Computing MIN */ + i__1 = *k, i__2 = ki + nb; + kk = min(i__1,i__2); + +/* Set A(1:kk,kk+1:n) to zero. */ + + i__1 = *n; + for (j = kk + 1; j <= i__1; ++j) { + i__2 = kk; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0.f, a[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + kk = 0; + } + +/* Use unblocked code for the last or only block. */ + + if (kk < *n) { + i__1 = *m - kk; + i__2 = *n - kk; + i__3 = *k - kk; + cung2r_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, & + tau[kk + 1], &work[1], &iinfo); + } + + if (kk > 0) { + +/* Use blocked code */ + + i__1 = -nb; + for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) { +/* Computing MIN */ + i__2 = nb, i__3 = *k - i__ + 1; + ib = min(i__2,i__3); + if (i__ + ib <= *n) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__2 = *m - i__ + 1; + clarft_("Forward", "Columnwise", &i__2, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H to A(i:m,i+ib:n) from the left */ + + i__2 = *m - i__ + 1; + i__3 = *n - i__ - ib + 1; + clarfb_("Left", "No transpose", "Forward", "Columnwise", & + i__2, &i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[ + 1], &ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, & + work[ib + 1], &ldwork); + } + +/* Apply H to rows i:m of current block */ + + i__2 = *m - i__ + 1; + cung2r_(&i__2, &ib, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], & + work[1], &iinfo); + +/* Set rows 1:i-1 of current block to zero */ + + i__2 = i__ + ib - 1; + for (j = i__; j <= i__2; ++j) { + i__3 = i__ - 1; + for (l = 1; l <= i__3; ++l) { + i__4 = l + j * a_dim1; + a[i__4].r = 0.f, a[i__4].i = 0.f; +/* L30: */ + } +/* L40: */ + } +/* L50: */ + } + } + + work[1].r = (real) iws, work[1].i = 0.f; + return 0; + +/* End of CUNGQR */ + +} /* cungqr_ */ + +/* Subroutine */ int cunm2l_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer i__, i1, i2, i3, mi, ni, nq; + static complex aii; + static logical left; + static complex taui; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNM2L overwrites the general complex m-by-n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'C', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'C', + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by CGEQLF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'C': apply Q' (Conjugate transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + CGEQLF in the last k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGEQLF. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the m-by-n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNM2L", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + } else { + mi = *m; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) or H(i)' is applied to C(1:m-k+i,1:n) */ + + mi = *m - *k + i__; + } else { + +/* H(i) or H(i)' is applied to C(1:m,1:n-k+i) */ + + ni = *n - *k + i__; + } + +/* Apply H(i) or H(i)' */ + + if (notran) { + i__3 = i__; + taui.r = tau[i__3].r, taui.i = tau[i__3].i; + } else { + r_cnjg(&q__1, &tau[i__]); + taui.r = q__1.r, taui.i = q__1.i; + } + i__3 = nq - *k + i__ + i__ * a_dim1; + aii.r = a[i__3].r, aii.i = a[i__3].i; + i__3 = nq - *k + i__ + i__ * a_dim1; + a[i__3].r = 1.f, a[i__3].i = 0.f; + clarf_(side, &mi, &ni, &a[i__ * a_dim1 + 1], &c__1, &taui, &c__[ + c_offset], ldc, &work[1]); + i__3 = nq - *k + i__ + i__ * a_dim1; + a[i__3].r = aii.r, a[i__3].i = aii.i; +/* L10: */ + } + return 0; + +/* End of CUNM2L */ + +} /* cunm2l_ */ + +/* Subroutine */ int cunm2r_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer i__, i1, i2, i3, ic, jc, mi, ni, nq; + static complex aii; + static logical left; + static complex taui; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNM2R overwrites the general complex m-by-n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'C', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'C', + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(1) H(2) . . . H(k) + + as returned by CGEQRF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'C': apply Q' (Conjugate transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + CGEQRF in the first k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGEQRF. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the m-by-n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNM2R", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && ! notran || ! left && notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) or H(i)' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H(i) or H(i)' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H(i) or H(i)' */ + + if (notran) { + i__3 = i__; + taui.r = tau[i__3].r, taui.i = tau[i__3].i; + } else { + r_cnjg(&q__1, &tau[i__]); + taui.r = q__1.r, taui.i = q__1.i; + } + i__3 = i__ + i__ * a_dim1; + aii.r = a[i__3].r, aii.i = a[i__3].i; + i__3 = i__ + i__ * a_dim1; + a[i__3].r = 1.f, a[i__3].i = 0.f; + clarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], &c__1, &taui, &c__[ic + + jc * c_dim1], ldc, &work[1]); + i__3 = i__ + i__ * a_dim1; + a[i__3].r = aii.r, a[i__3].i = aii.i; +/* L10: */ + } + return 0; + +/* End of CUNM2R */ + +} /* cunm2r_ */ + +/* Subroutine */ int cunmbr_(char *vect, char *side, char *trans, integer *m, + integer *n, integer *k, complex *a, integer *lda, complex *tau, + complex *c__, integer *ldc, complex *work, integer *lwork, integer * + info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2]; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int cunmlq_(char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *, integer *); + static logical notran; + extern /* Subroutine */ int cunmqr_(char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *, integer *); + static logical applyq; + static char transt[1]; + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + If VECT = 'Q', CUNMBR overwrites the general complex M-by-N matrix C + with + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + If VECT = 'P', CUNMBR overwrites the general complex M-by-N matrix C + with + SIDE = 'L' SIDE = 'R' + TRANS = 'N': P * C C * P + TRANS = 'C': P**H * C C * P**H + + Here Q and P**H are the unitary matrices determined by CGEBRD when + reducing a complex matrix A to bidiagonal form: A = Q * B * P**H. Q + and P**H are defined as products of elementary reflectors H(i) and + G(i) respectively. + + Let nq = m if SIDE = 'L' and nq = n if SIDE = 'R'. Thus nq is the + order of the unitary matrix Q or P**H that is applied. + + If VECT = 'Q', A is assumed to have been an NQ-by-K matrix: + if nq >= k, Q = H(1) H(2) . . . H(k); + if nq < k, Q = H(1) H(2) . . . H(nq-1). + + If VECT = 'P', A is assumed to have been a K-by-NQ matrix: + if k < nq, P = G(1) G(2) . . . G(k); + if k >= nq, P = G(1) G(2) . . . G(nq-1). + + Arguments + ========= + + VECT (input) CHARACTER*1 + = 'Q': apply Q or Q**H; + = 'P': apply P or P**H. + + SIDE (input) CHARACTER*1 + = 'L': apply Q, Q**H, P or P**H from the Left; + = 'R': apply Q, Q**H, P or P**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q or P; + = 'C': Conjugate transpose, apply Q**H or P**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + If VECT = 'Q', the number of columns in the original + matrix reduced by CGEBRD. + If VECT = 'P', the number of rows in the original + matrix reduced by CGEBRD. + K >= 0. + + A (input) COMPLEX array, dimension + (LDA,min(nq,K)) if VECT = 'Q' + (LDA,nq) if VECT = 'P' + The vectors which define the elementary reflectors H(i) and + G(i), whose products determine the matrices Q and P, as + returned by CGEBRD. + + LDA (input) INTEGER + The leading dimension of the array A. + If VECT = 'Q', LDA >= max(1,nq); + if VECT = 'P', LDA >= max(1,min(nq,K)). + + TAU (input) COMPLEX array, dimension (min(nq,K)) + TAU(i) must contain the scalar factor of the elementary + reflector H(i) or G(i) which determines Q or P, as returned + by CGEBRD in the array argument TAUQ or TAUP. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q + or P*C or P**H*C or C*P or C*P**H. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M); + if N = 0 or M = 0, LWORK >= 1. + For optimum performance LWORK >= max(1,N*NB) if SIDE = 'L', + and LWORK >= max(1,M*NB) if SIDE = 'R', where NB is the + optimal blocksize. (NB = 0 if M = 0 or N = 0.) + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + applyq = lsame_(vect, "Q"); + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q or P and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (*m == 0 || *n == 0) { + nw = 0; + } + if (! applyq && ! lsame_(vect, "P")) { + *info = -1; + } else if (! left && ! lsame_(side, "R")) { + *info = -2; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -3; + } else if (*m < 0) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*k < 0) { + *info = -6; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = 1, i__2 = min(nq,*k); + if (applyq && *lda < max(1,nq) || ! applyq && *lda < max(i__1,i__2)) { + *info = -8; + } else if (*ldc < max(1,*m)) { + *info = -11; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -13; + } + } + + if (*info == 0) { + if (nw > 0) { + if (applyq) { + if (left) { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *m - 1; + i__2 = *m - 1; + nb = ilaenv_(&c__1, "CUNMQR", ch__1, &i__1, n, &i__2, & + c_n1, (ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *n - 1; + i__2 = *n - 1; + nb = ilaenv_(&c__1, "CUNMQR", ch__1, m, &i__1, &i__2, & + c_n1, (ftnlen)6, (ftnlen)2); + } + } else { + if (left) { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *m - 1; + i__2 = *m - 1; + nb = ilaenv_(&c__1, "CUNMLQ", ch__1, &i__1, n, &i__2, & + c_n1, (ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *n - 1; + i__2 = *n - 1; + nb = ilaenv_(&c__1, "CUNMLQ", ch__1, m, &i__1, &i__2, & + c_n1, (ftnlen)6, (ftnlen)2); + } + } +/* Computing MAX */ + i__1 = 1, i__2 = nw * nb; + lwkopt = max(i__1,i__2); + } else { + lwkopt = 1; + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNMBR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + + if (applyq) { + +/* Apply Q */ + + if (nq >= *k) { + +/* Q was determined by a call to CGEBRD with nq >= k */ + + cunmqr_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], lwork, &iinfo); + } else if (nq > 1) { + +/* Q was determined by a call to CGEBRD with nq < k */ + + if (left) { + mi = *m - 1; + ni = *n; + i1 = 2; + i2 = 1; + } else { + mi = *m; + ni = *n - 1; + i1 = 1; + i2 = 2; + } + i__1 = nq - 1; + cunmqr_(side, trans, &mi, &ni, &i__1, &a[a_dim1 + 2], lda, &tau[1] + , &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + } + } else { + +/* Apply P */ + + if (notran) { + *(unsigned char *)transt = 'C'; + } else { + *(unsigned char *)transt = 'N'; + } + if (nq > *k) { + +/* P was determined by a call to CGEBRD with nq > k */ + + cunmlq_(side, transt, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], lwork, &iinfo); + } else if (nq > 1) { + +/* P was determined by a call to CGEBRD with nq <= k */ + + if (left) { + mi = *m - 1; + ni = *n; + i1 = 2; + i2 = 1; + } else { + mi = *m; + ni = *n - 1; + i1 = 1; + i2 = 2; + } + i__1 = nq - 1; + cunmlq_(side, transt, &mi, &ni, &i__1, &a[(a_dim1 << 1) + 1], lda, + &tau[1], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, & + iinfo); + } + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CUNMBR */ + +} /* cunmbr_ */ + +/* Subroutine */ int cunmhr_(char *side, char *trans, integer *m, integer *n, + integer *ilo, integer *ihi, complex *a, integer *lda, complex *tau, + complex *c__, integer *ldc, complex *work, integer *lwork, integer * + info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, nh, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int cunmqr_(char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNMHR overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix of order nq, with nq = m if + SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of + IHI-ILO elementary reflectors, as returned by CGEHRD: + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'C': apply Q**H (Conjugate transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + ILO and IHI must have the same values as in the previous call + of CGEHRD. Q is equal to the unit matrix except in the + submatrix Q(ilo+1:ihi,ilo+1:ihi). + If SIDE = 'L', then 1 <= ILO <= IHI <= M, if M > 0, and + ILO = 1 and IHI = 0, if M = 0; + if SIDE = 'R', then 1 <= ILO <= IHI <= N, if N > 0, and + ILO = 1 and IHI = 0, if N = 0. + + A (input) COMPLEX array, dimension + (LDA,M) if SIDE = 'L' + (LDA,N) if SIDE = 'R' + The vectors which define the elementary reflectors, as + returned by CGEHRD. + + LDA (input) INTEGER + The leading dimension of the array A. + LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. + + TAU (input) COMPLEX array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGEHRD. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + nh = *ihi - *ilo; + left = lsame_(side, "L"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*ilo < 1 || *ilo > max(1,nq)) { + *info = -5; + } else if (*ihi < min(*ilo,nq) || *ihi > nq) { + *info = -6; + } else if (*lda < max(1,nq)) { + *info = -8; + } else if (*ldc < max(1,*m)) { + *info = -11; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -13; + } + + if (*info == 0) { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "CUNMQR", ch__1, &nh, n, &nh, &c_n1, (ftnlen) + 6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "CUNMQR", ch__1, m, &nh, &nh, &c_n1, (ftnlen) + 6, (ftnlen)2); + } + lwkopt = max(1,nw) * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + } + + if (*info != 0) { + i__2 = -(*info); + xerbla_("CUNMHR", &i__2); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || nh == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + if (left) { + mi = nh; + ni = *n; + i1 = *ilo + 1; + i2 = 1; + } else { + mi = *m; + ni = nh; + i1 = 1; + i2 = *ilo + 1; + } + + cunmqr_(side, trans, &mi, &ni, &nh, &a[*ilo + 1 + *ilo * a_dim1], lda, & + tau[*ilo], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CUNMHR */ + +} /* cunmhr_ */ + +/* Subroutine */ int cunml2_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + complex q__1; + + /* Local variables */ + static integer i__, i1, i2, i3, ic, jc, mi, ni, nq; + static complex aii; + static logical left; + static complex taui; + extern /* Subroutine */ int clarf_(char *, integer *, integer *, complex * + , integer *, complex *, complex *, integer *, complex *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int clacgv_(integer *, complex *, integer *), + xerbla_(char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNML2 overwrites the general complex m-by-n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'C', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'C', + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(k)' . . . H(2)' H(1)' + + as returned by CGELQF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'C': apply Q' (Conjugate transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX array, dimension + (LDA,M) if SIDE = 'L', + (LDA,N) if SIDE = 'R' + The i-th row must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + CGELQF in the first k rows of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,K). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGELQF. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the m-by-n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,*k)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNML2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) or H(i)' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H(i) or H(i)' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H(i) or H(i)' */ + + if (notran) { + r_cnjg(&q__1, &tau[i__]); + taui.r = q__1.r, taui.i = q__1.i; + } else { + i__3 = i__; + taui.r = tau[i__3].r, taui.i = tau[i__3].i; + } + if (i__ < nq) { + i__3 = nq - i__; + clacgv_(&i__3, &a[i__ + (i__ + 1) * a_dim1], lda); + } + i__3 = i__ + i__ * a_dim1; + aii.r = a[i__3].r, aii.i = a[i__3].i; + i__3 = i__ + i__ * a_dim1; + a[i__3].r = 1.f, a[i__3].i = 0.f; + clarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], lda, &taui, &c__[ic + + jc * c_dim1], ldc, &work[1]); + i__3 = i__ + i__ * a_dim1; + a[i__3].r = aii.r, a[i__3].i = aii.i; + if (i__ < nq) { + i__3 = nq - i__; + clacgv_(&i__3, &a[i__ + (i__ + 1) * a_dim1], lda); + } +/* L10: */ + } + return 0; + +/* End of CUNML2 */ + +} /* cunml2_ */ + +/* Subroutine */ int cunmlq_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static complex t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int cunml2_(char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *), clarfb_(char *, char *, + char *, char *, integer *, integer *, integer *, complex *, + integer *, complex *, integer *, complex *, integer *, complex *, + integer *), clarft_(char *, char * + , integer *, integer *, complex *, integer *, complex *, complex * + , integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical notran; + static integer ldwork; + static char transt[1]; + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNMLQ overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(k)' . . . H(2)' H(1)' + + as returned by CGELQF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'C': Conjugate transpose, apply Q**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX array, dimension + (LDA,M) if SIDE = 'L', + (LDA,N) if SIDE = 'R' + The i-th row must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + CGELQF in the first k rows of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,K). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGELQF. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,*k)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + +/* + Determine the block size. NB may be at most NBMAX, where NBMAX + is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "CUNMLQ", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = max(1,nw) * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNMLQ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "CUNMLQ", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + cunml2_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + if (notran) { + *(unsigned char *)transt = 'C'; + } else { + *(unsigned char *)transt = 'N'; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__4 = nq - i__ + 1; + clarft_("Forward", "Rowwise", &i__4, &ib, &a[i__ + i__ * a_dim1], + lda, &tau[i__], t, &c__65); + if (left) { + +/* H or H' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H or H' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H or H' */ + + clarfb_(side, transt, "Forward", "Rowwise", &mi, &ni, &ib, &a[i__ + + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * c_dim1], + ldc, &work[1], &ldwork); +/* L10: */ + } + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CUNMLQ */ + +} /* cunmlq_ */ + +/* Subroutine */ int cunmql_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static complex t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int cunm2l_(char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *), clarfb_(char *, char *, + char *, char *, integer *, integer *, integer *, complex *, + integer *, complex *, integer *, complex *, integer *, complex *, + integer *), clarft_(char *, char * + , integer *, integer *, complex *, integer *, complex *, complex * + , integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical notran; + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNMQL overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by CGEQLF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'C': Transpose, apply Q**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + CGEQLF in the last k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGEQLF. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = max(1,*n); + } else { + nq = *n; + nw = max(1,*m); + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + + if (*info == 0) { + if (*m == 0 || *n == 0) { + lwkopt = 1; + } else { + +/* + Determine the block size. NB may be at most NBMAX, where + NBMAX is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "CUNMQL", ch__1, m, n, k, &c_n1, + (ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = nw * nb; + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + + if (*lwork < nw && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNMQL", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "CUNMQL", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + cunm2l_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + } else { + mi = *m; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i+ib-1) . . . H(i+1) H(i) +*/ + + i__4 = nq - *k + i__ + ib - 1; + clarft_("Backward", "Columnwise", &i__4, &ib, &a[i__ * a_dim1 + 1] + , lda, &tau[i__], t, &c__65); + if (left) { + +/* H or H' is applied to C(1:m-k+i+ib-1,1:n) */ + + mi = *m - *k + i__ + ib - 1; + } else { + +/* H or H' is applied to C(1:m,1:n-k+i+ib-1) */ + + ni = *n - *k + i__ + ib - 1; + } + +/* Apply H or H' */ + + clarfb_(side, trans, "Backward", "Columnwise", &mi, &ni, &ib, &a[ + i__ * a_dim1 + 1], lda, t, &c__65, &c__[c_offset], ldc, & + work[1], &ldwork); +/* L10: */ + } + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CUNMQL */ + +} /* cunmql_ */ + +/* Subroutine */ int cunmqr_(char *side, char *trans, integer *m, integer *n, + integer *k, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static complex t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int cunm2r_(char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *), clarfb_(char *, char *, + char *, char *, integer *, integer *, integer *, complex *, + integer *, complex *, integer *, complex *, integer *, complex *, + integer *), clarft_(char *, char * + , integer *, integer *, complex *, integer *, complex *, complex * + , integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical notran; + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNMQR overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(1) H(2) . . . H(k) + + as returned by CGEQRF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'C': Conjugate transpose, apply Q**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + CGEQRF in the first k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) COMPLEX array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CGEQRF. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + +/* + Determine the block size. NB may be at most NBMAX, where NBMAX + is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "CUNMQR", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = max(1,nw) * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CUNMQR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "CUNMQR", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + cunm2r_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && ! notran || ! left && notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__4 = nq - i__ + 1; + clarft_("Forward", "Columnwise", &i__4, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], t, &c__65) + ; + if (left) { + +/* H or H' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H or H' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H or H' */ + + clarfb_(side, trans, "Forward", "Columnwise", &mi, &ni, &ib, &a[ + i__ + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * + c_dim1], ldc, &work[1], &ldwork); +/* L10: */ + } + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CUNMQR */ + +} /* cunmqr_ */ + +/* Subroutine */ int cunmtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, complex *a, integer *lda, complex *tau, complex *c__, + integer *ldc, complex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2, i__3; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int cunmql_(char *, char *, integer *, integer *, + integer *, complex *, integer *, complex *, complex *, integer *, + complex *, integer *, integer *), cunmqr_(char *, + char *, integer *, integer *, integer *, complex *, integer *, + complex *, complex *, integer *, complex *, integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + CUNMTR overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix of order nq, with nq = m if + SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of + nq-1 elementary reflectors, as returned by CHETRD: + + if UPLO = 'U', Q = H(nq-1) . . . H(2) H(1); + + if UPLO = 'L', Q = H(1) H(2) . . . H(nq-1). + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A contains elementary reflectors + from CHETRD; + = 'L': Lower triangle of A contains elementary reflectors + from CHETRD. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'C': Conjugate transpose, apply Q**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + A (input) COMPLEX array, dimension + (LDA,M) if SIDE = 'L' + (LDA,N) if SIDE = 'R' + The vectors which define the elementary reflectors, as + returned by CHETRD. + + LDA (input) INTEGER + The leading dimension of the array A. + LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. + + TAU (input) COMPLEX array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by CHETRD. + + C (input/output) COMPLEX array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >=M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + upper = lsame_(uplo, "U"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! upper && ! lsame_(uplo, "L")) { + *info = -2; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "C")) { + *info = -3; + } else if (*m < 0) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + if (upper) { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *m - 1; + i__3 = *m - 1; + nb = ilaenv_(&c__1, "CUNMQL", ch__1, &i__2, n, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *n - 1; + i__3 = *n - 1; + nb = ilaenv_(&c__1, "CUNMQL", ch__1, m, &i__2, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } else { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *m - 1; + i__3 = *m - 1; + nb = ilaenv_(&c__1, "CUNMQR", ch__1, &i__2, n, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *n - 1; + i__3 = *n - 1; + nb = ilaenv_(&c__1, "CUNMQR", ch__1, m, &i__2, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } + lwkopt = max(1,nw) * nb; + work[1].r = (real) lwkopt, work[1].i = 0.f; + } + + if (*info != 0) { + i__2 = -(*info); + xerbla_("CUNMTR", &i__2); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || nq == 1) { + work[1].r = 1.f, work[1].i = 0.f; + return 0; + } + + if (left) { + mi = *m - 1; + ni = *n; + } else { + mi = *m; + ni = *n - 1; + } + + if (upper) { + +/* Q was determined by a call to CHETRD with UPLO = 'U' */ + + i__2 = nq - 1; + cunmql_(side, trans, &mi, &ni, &i__2, &a[(a_dim1 << 1) + 1], lda, & + tau[1], &c__[c_offset], ldc, &work[1], lwork, &iinfo); + } else { + +/* Q was determined by a call to CHETRD with UPLO = 'L' */ + + if (left) { + i1 = 2; + i2 = 1; + } else { + i1 = 1; + i2 = 2; + } + i__2 = nq - 1; + cunmqr_(side, trans, &mi, &ni, &i__2, &a[a_dim1 + 2], lda, &tau[1], & + c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + } + work[1].r = (real) lwkopt, work[1].i = 0.f; + return 0; + +/* End of CUNMTR */ + +} /* cunmtr_ */ + diff --git a/numpy/linalg/lapack_lite/f2c_config.c b/numpy/linalg/lapack_lite/f2c_config.c new file mode 100644 index 0000000..2fe6082 --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c_config.c @@ -0,0 +1,2068 @@ +/* +NOTE: This is generated code. Look in Misc/lapack_lite for information on + remaking this file. +*/ +#include "f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal dlamch_(char *); +#define EPSILON dlamch_("Epsilon") +#define SAFEMINIMUM dlamch_("Safe minimum") +#define PRECISION dlamch_("Precision") +#define BASE dlamch_("Base") +#endif + +extern doublereal dlapy2_(doublereal *x, doublereal *y); + +/* +f2c knows the exact rules for precedence, and so omits parentheses where not +strictly necessary. Since this is generated code, we don't really care if +it's readable, and we know what is written is correct. So don't warn about +them. +*/ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wparentheses" +#endif + + +/* Table of constant values */ + +static integer c__1 = 1; +static doublereal c_b32 = 0.; +static real c_b66 = 0.f; + +doublereal dlamch_(char *cmach) +{ + /* Initialized data */ + + static logical first = TRUE_; + + /* System generated locals */ + integer i__1; + doublereal ret_val; + + /* Local variables */ + static doublereal t; + static integer it; + static doublereal rnd, eps, base; + static integer beta; + static doublereal emin, prec, emax; + static integer imin, imax; + static logical lrnd; + static doublereal rmin, rmax, rmach; + extern logical lsame_(char *, char *); + static doublereal small, sfmin; + extern /* Subroutine */ int dlamc2_(integer *, integer *, logical *, + doublereal *, integer *, doublereal *, integer *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + DLAMCH determines double precision machine parameters. + + Arguments + ========= + + CMACH (input) CHARACTER*1 + Specifies the value to be returned by DLAMCH: + = 'E' or 'e', DLAMCH := eps + = 'S' or 's , DLAMCH := sfmin + = 'B' or 'b', DLAMCH := base + = 'P' or 'p', DLAMCH := eps*base + = 'N' or 'n', DLAMCH := t + = 'R' or 'r', DLAMCH := rnd + = 'M' or 'm', DLAMCH := emin + = 'U' or 'u', DLAMCH := rmin + = 'L' or 'l', DLAMCH := emax + = 'O' or 'o', DLAMCH := rmax + + where + + eps = relative machine precision + sfmin = safe minimum, such that 1/sfmin does not overflow + base = base of the machine + prec = eps*base + t = number of (base) digits in the mantissa + rnd = 1.0 when rounding occurs in addition, 0.0 otherwise + emin = minimum exponent before (gradual) underflow + rmin = underflow threshold - base**(emin-1) + emax = largest exponent before overflow + rmax = overflow threshold - (base**emax)*(1-eps) + + ===================================================================== +*/ + + + if (first) { + dlamc2_(&beta, &it, &lrnd, &eps, &imin, &rmin, &imax, &rmax); + base = (doublereal) beta; + t = (doublereal) it; + if (lrnd) { + rnd = 1.; + i__1 = 1 - it; + eps = pow_di(&base, &i__1) / 2; + } else { + rnd = 0.; + i__1 = 1 - it; + eps = pow_di(&base, &i__1); + } + prec = eps * base; + emin = (doublereal) imin; + emax = (doublereal) imax; + sfmin = rmin; + small = 1. / rmax; + if (small >= sfmin) { + +/* + Use SMALL plus a bit, to avoid the possibility of rounding + causing overflow when computing 1/sfmin. +*/ + + sfmin = small * (eps + 1.); + } + } + + if (lsame_(cmach, "E")) { + rmach = eps; + } else if (lsame_(cmach, "S")) { + rmach = sfmin; + } else if (lsame_(cmach, "B")) { + rmach = base; + } else if (lsame_(cmach, "P")) { + rmach = prec; + } else if (lsame_(cmach, "N")) { + rmach = t; + } else if (lsame_(cmach, "R")) { + rmach = rnd; + } else if (lsame_(cmach, "M")) { + rmach = emin; + } else if (lsame_(cmach, "U")) { + rmach = rmin; + } else if (lsame_(cmach, "L")) { + rmach = emax; + } else if (lsame_(cmach, "O")) { + rmach = rmax; + } + + ret_val = rmach; + first = FALSE_; + return ret_val; + +/* End of DLAMCH */ + +} /* dlamch_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int dlamc1_(integer *beta, integer *t, logical *rnd, logical + *ieee1) +{ + /* Initialized data */ + + static logical first = TRUE_; + + /* System generated locals */ + doublereal d__1, d__2; + + /* Local variables */ + static doublereal a, b, c__, f, t1, t2; + static integer lt; + static doublereal one, qtr; + static logical lrnd; + static integer lbeta; + static doublereal savec; + extern doublereal dlamc3_(doublereal *, doublereal *); + static logical lieee1; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + DLAMC1 determines the machine parameters given by BETA, T, RND, and + IEEE1. + + Arguments + ========= + + BETA (output) INTEGER + The base of the machine. + + T (output) INTEGER + The number of ( BETA ) digits in the mantissa. + + RND (output) LOGICAL + Specifies whether proper rounding ( RND = .TRUE. ) or + chopping ( RND = .FALSE. ) occurs in addition. This may not + be a reliable guide to the way in which the machine performs + its arithmetic. + + IEEE1 (output) LOGICAL + Specifies whether rounding appears to be done in the IEEE + 'round to nearest' style. + + Further Details + =============== + + The routine is based on the routine ENVRON by Malcolm and + incorporates suggestions by Gentleman and Marovich. See + + Malcolm M. A. (1972) Algorithms to reveal properties of + floating-point arithmetic. Comms. of the ACM, 15, 949-951. + + Gentleman W. M. and Marovich S. B. (1974) More on algorithms + that reveal properties of floating point arithmetic units. + Comms. of the ACM, 17, 276-277. + + ===================================================================== +*/ + + + if (first) { + one = 1.; + +/* + LBETA, LIEEE1, LT and LRND are the local values of BETA, + IEEE1, T and RND. + + Throughout this routine we use the function DLAMC3 to ensure + that relevant values are stored and not held in registers, or + are not affected by optimizers. + + Compute a = 2.0**m with the smallest positive integer m such + that + + fl( a + 1.0 ) = a. +*/ + + a = 1.; + c__ = 1.; + +/* + WHILE( C.EQ.ONE )LOOP */ +L10: + if (c__ == one) { + a *= 2; + c__ = dlamc3_(&a, &one); + d__1 = -a; + c__ = dlamc3_(&c__, &d__1); + goto L10; + } +/* + + END WHILE + + Now compute b = 2.0**m with the smallest positive integer m + such that + + fl( a + b ) .gt. a. +*/ + + b = 1.; + c__ = dlamc3_(&a, &b); + +/* + WHILE( C.EQ.A )LOOP */ +L20: + if (c__ == a) { + b *= 2; + c__ = dlamc3_(&a, &b); + goto L20; + } +/* + + END WHILE + + Now compute the base. a and c are neighbouring floating point + numbers in the interval ( beta**t, beta**( t + 1 ) ) and so + their difference is beta. Adding 0.25 to c is to ensure that it + is truncated to beta and not ( beta - 1 ). +*/ + + qtr = one / 4; + savec = c__; + d__1 = -a; + c__ = dlamc3_(&c__, &d__1); + lbeta = (integer) (c__ + qtr); + +/* + Now determine whether rounding or chopping occurs, by adding a + bit less than beta/2 and a bit more than beta/2 to a. +*/ + + b = (doublereal) lbeta; + d__1 = b / 2; + d__2 = -b / 100; + f = dlamc3_(&d__1, &d__2); + c__ = dlamc3_(&f, &a); + if (c__ == a) { + lrnd = TRUE_; + } else { + lrnd = FALSE_; + } + d__1 = b / 2; + d__2 = b / 100; + f = dlamc3_(&d__1, &d__2); + c__ = dlamc3_(&f, &a); + if (lrnd && c__ == a) { + lrnd = FALSE_; + } + +/* + Try and decide whether rounding is done in the IEEE 'round to + nearest' style. B/2 is half a unit in the last place of the two + numbers A and SAVEC. Furthermore, A is even, i.e. has last bit + zero, and SAVEC is odd. Thus adding B/2 to A should not change + A, but adding B/2 to SAVEC should change SAVEC. +*/ + + d__1 = b / 2; + t1 = dlamc3_(&d__1, &a); + d__1 = b / 2; + t2 = dlamc3_(&d__1, &savec); + lieee1 = t1 == a && t2 > savec && lrnd; + +/* + Now find the mantissa, t. It should be the integer part of + log to the base beta of a, however it is safer to determine t + by powering. So we find t as the smallest positive integer for + which + + fl( beta**t + 1.0 ) = 1.0. +*/ + + lt = 0; + a = 1.; + c__ = 1.; + +/* + WHILE( C.EQ.ONE )LOOP */ +L30: + if (c__ == one) { + ++lt; + a *= lbeta; + c__ = dlamc3_(&a, &one); + d__1 = -a; + c__ = dlamc3_(&c__, &d__1); + goto L30; + } +/* + END WHILE */ + + } + + *beta = lbeta; + *t = lt; + *rnd = lrnd; + *ieee1 = lieee1; + first = FALSE_; + return 0; + +/* End of DLAMC1 */ + +} /* dlamc1_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int dlamc2_(integer *beta, integer *t, logical *rnd, + doublereal *eps, integer *emin, doublereal *rmin, integer *emax, + doublereal *rmax) +{ + /* Initialized data */ + + static logical first = TRUE_; + static logical iwarn = FALSE_; + + /* Format strings */ + static char fmt_9999[] = "(//\002 WARNING. The value EMIN may be incorre" + "ct:-\002,\002 EMIN = \002,i8,/\002 If, after inspection, the va" + "lue EMIN looks\002,\002 acceptable please comment out \002,/\002" + " the IF block as marked within the code of routine\002,\002 DLAM" + "C2,\002,/\002 otherwise supply EMIN explicitly.\002,/)"; + + /* System generated locals */ + integer i__1; + doublereal d__1, d__2, d__3, d__4, d__5; + + /* Local variables */ + static doublereal a, b, c__; + static integer i__, lt; + static doublereal one, two; + static logical ieee; + static doublereal half; + static logical lrnd; + static doublereal leps, zero; + static integer lbeta; + static doublereal rbase; + static integer lemin, lemax, gnmin; + static doublereal small; + static integer gpmin; + static doublereal third, lrmin, lrmax, sixth; + extern /* Subroutine */ int dlamc1_(integer *, integer *, logical *, + logical *); + extern doublereal dlamc3_(doublereal *, doublereal *); + static logical lieee1; + extern /* Subroutine */ int dlamc4_(integer *, doublereal *, integer *), + dlamc5_(integer *, integer *, integer *, logical *, integer *, + doublereal *); + static integer ngnmin, ngpmin; + + /* Fortran I/O blocks */ + static cilist io___58 = { 0, 6, 0, fmt_9999, 0 }; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + DLAMC2 determines the machine parameters specified in its argument + list. + + Arguments + ========= + + BETA (output) INTEGER + The base of the machine. + + T (output) INTEGER + The number of ( BETA ) digits in the mantissa. + + RND (output) LOGICAL + Specifies whether proper rounding ( RND = .TRUE. ) or + chopping ( RND = .FALSE. ) occurs in addition. This may not + be a reliable guide to the way in which the machine performs + its arithmetic. + + EPS (output) DOUBLE PRECISION + The smallest positive number such that + + fl( 1.0 - EPS ) .LT. 1.0, + + where fl denotes the computed value. + + EMIN (output) INTEGER + The minimum exponent before (gradual) underflow occurs. + + RMIN (output) DOUBLE PRECISION + The smallest normalized number for the machine, given by + BASE**( EMIN - 1 ), where BASE is the floating point value + of BETA. + + EMAX (output) INTEGER + The maximum exponent before overflow occurs. + + RMAX (output) DOUBLE PRECISION + The largest positive number for the machine, given by + BASE**EMAX * ( 1 - EPS ), where BASE is the floating point + value of BETA. + + Further Details + =============== + + The computation of EPS is based on a routine PARANOIA by + W. Kahan of the University of California at Berkeley. + + ===================================================================== +*/ + + + if (first) { + zero = 0.; + one = 1.; + two = 2.; + +/* + LBETA, LT, LRND, LEPS, LEMIN and LRMIN are the local values of + BETA, T, RND, EPS, EMIN and RMIN. + + Throughout this routine we use the function DLAMC3 to ensure + that relevant values are stored and not held in registers, or + are not affected by optimizers. + + DLAMC1 returns the parameters LBETA, LT, LRND and LIEEE1. +*/ + + dlamc1_(&lbeta, <, &lrnd, &lieee1); + +/* Start to find EPS. */ + + b = (doublereal) lbeta; + i__1 = -lt; + a = pow_di(&b, &i__1); + leps = a; + +/* Try some tricks to see whether or not this is the correct EPS. */ + + b = two / 3; + half = one / 2; + d__1 = -half; + sixth = dlamc3_(&b, &d__1); + third = dlamc3_(&sixth, &sixth); + d__1 = -half; + b = dlamc3_(&third, &d__1); + b = dlamc3_(&b, &sixth); + b = abs(b); + if (b < leps) { + b = leps; + } + + leps = 1.; + +/* + WHILE( ( LEPS.GT.B ).AND.( B.GT.ZERO ) )LOOP */ +L10: + if (leps > b && b > zero) { + leps = b; + d__1 = half * leps; +/* Computing 5th power */ + d__3 = two, d__4 = d__3, d__3 *= d__3; +/* Computing 2nd power */ + d__5 = leps; + d__2 = d__4 * (d__3 * d__3) * (d__5 * d__5); + c__ = dlamc3_(&d__1, &d__2); + d__1 = -c__; + c__ = dlamc3_(&half, &d__1); + b = dlamc3_(&half, &c__); + d__1 = -b; + c__ = dlamc3_(&half, &d__1); + b = dlamc3_(&half, &c__); + goto L10; + } +/* + END WHILE */ + + if (a < leps) { + leps = a; + } + +/* + Computation of EPS complete. + + Now find EMIN. Let A = + or - 1, and + or - (1 + BASE**(-3)). + Keep dividing A by BETA until (gradual) underflow occurs. This + is detected when we cannot recover the previous A. +*/ + + rbase = one / lbeta; + small = one; + for (i__ = 1; i__ <= 3; ++i__) { + d__1 = small * rbase; + small = dlamc3_(&d__1, &zero); +/* L20: */ + } + a = dlamc3_(&one, &small); + dlamc4_(&ngpmin, &one, &lbeta); + d__1 = -one; + dlamc4_(&ngnmin, &d__1, &lbeta); + dlamc4_(&gpmin, &a, &lbeta); + d__1 = -a; + dlamc4_(&gnmin, &d__1, &lbeta); + ieee = FALSE_; + + if (ngpmin == ngnmin && gpmin == gnmin) { + if (ngpmin == gpmin) { + lemin = ngpmin; +/* + ( Non twos-complement machines, no gradual underflow; + e.g., VAX ) +*/ + } else if (gpmin - ngpmin == 3) { + lemin = ngpmin - 1 + lt; + ieee = TRUE_; +/* + ( Non twos-complement machines, with gradual underflow; + e.g., IEEE standard followers ) +*/ + } else { + lemin = min(ngpmin,gpmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } else if (ngpmin == gpmin && ngnmin == gnmin) { + if ((i__1 = ngpmin - ngnmin, abs(i__1)) == 1) { + lemin = max(ngpmin,ngnmin); +/* + ( Twos-complement machines, no gradual underflow; + e.g., CYBER 205 ) +*/ + } else { + lemin = min(ngpmin,ngnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } else if ((i__1 = ngpmin - ngnmin, abs(i__1)) == 1 && gpmin == gnmin) + { + if (gpmin - min(ngpmin,ngnmin) == 3) { + lemin = max(ngpmin,ngnmin) - 1 + lt; +/* + ( Twos-complement machines with gradual underflow; + no known machine ) +*/ + } else { + lemin = min(ngpmin,ngnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } else { +/* Computing MIN */ + i__1 = min(ngpmin,ngnmin), i__1 = min(i__1,gpmin); + lemin = min(i__1,gnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + first = FALSE_; +/* + ** + Comment out this if block if EMIN is ok +*/ + if (iwarn) { + first = TRUE_; + s_wsfe(&io___58); + do_fio(&c__1, (char *)&lemin, (ftnlen)sizeof(integer)); + e_wsfe(); + } +/* + ** + + Assume IEEE arithmetic if we found denormalised numbers above, + or if arithmetic seems to round in the IEEE style, determined + in routine DLAMC1. A true IEEE machine should have both things + true; however, faulty machines may have one or the other. +*/ + + ieee = ieee || lieee1; + +/* + Compute RMIN by successive division by BETA. We could compute + RMIN as BASE**( EMIN - 1 ), but some machines underflow during + this computation. +*/ + + lrmin = 1.; + i__1 = 1 - lemin; + for (i__ = 1; i__ <= i__1; ++i__) { + d__1 = lrmin * rbase; + lrmin = dlamc3_(&d__1, &zero); +/* L30: */ + } + +/* Finally, call DLAMC5 to compute EMAX and RMAX. */ + + dlamc5_(&lbeta, <, &lemin, &ieee, &lemax, &lrmax); + } + + *beta = lbeta; + *t = lt; + *rnd = lrnd; + *eps = leps; + *emin = lemin; + *rmin = lrmin; + *emax = lemax; + *rmax = lrmax; + + return 0; + + +/* End of DLAMC2 */ + +} /* dlamc2_ */ + + +/* *********************************************************************** */ + +doublereal dlamc3_(doublereal *a, doublereal *b) +{ + /* System generated locals */ + doublereal ret_val; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + DLAMC3 is intended to force A and B to be stored prior to doing + the addition of A and B , for use in situations where optimizers + might hold one of these in a register. + + Arguments + ========= + + A (input) DOUBLE PRECISION + B (input) DOUBLE PRECISION + The values A and B. + + ===================================================================== +*/ + + + ret_val = *a + *b; + + return ret_val; + +/* End of DLAMC3 */ + +} /* dlamc3_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int dlamc4_(integer *emin, doublereal *start, integer *base) +{ + /* System generated locals */ + integer i__1; + doublereal d__1; + + /* Local variables */ + static doublereal a; + static integer i__; + static doublereal b1, b2, c1, c2, d1, d2, one, zero, rbase; + extern doublereal dlamc3_(doublereal *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + DLAMC4 is a service routine for DLAMC2. + + Arguments + ========= + + EMIN (output) INTEGER + The minimum exponent before (gradual) underflow, computed by + setting A = START and dividing by BASE until the previous A + can not be recovered. + + START (input) DOUBLE PRECISION + The starting point for determining EMIN. + + BASE (input) INTEGER + The base of the machine. + + ===================================================================== +*/ + + + a = *start; + one = 1.; + rbase = one / *base; + zero = 0.; + *emin = 1; + d__1 = a * rbase; + b1 = dlamc3_(&d__1, &zero); + c1 = a; + c2 = a; + d1 = a; + d2 = a; +/* + + WHILE( ( C1.EQ.A ).AND.( C2.EQ.A ).AND. + $ ( D1.EQ.A ).AND.( D2.EQ.A ) )LOOP +*/ +L10: + if (c1 == a && c2 == a && d1 == a && d2 == a) { + --(*emin); + a = b1; + d__1 = a / *base; + b1 = dlamc3_(&d__1, &zero); + d__1 = b1 * *base; + c1 = dlamc3_(&d__1, &zero); + d1 = zero; + i__1 = *base; + for (i__ = 1; i__ <= i__1; ++i__) { + d1 += b1; +/* L20: */ + } + d__1 = a * rbase; + b2 = dlamc3_(&d__1, &zero); + d__1 = b2 / rbase; + c2 = dlamc3_(&d__1, &zero); + d2 = zero; + i__1 = *base; + for (i__ = 1; i__ <= i__1; ++i__) { + d2 += b2; +/* L30: */ + } + goto L10; + } +/* + END WHILE */ + + return 0; + +/* End of DLAMC4 */ + +} /* dlamc4_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int dlamc5_(integer *beta, integer *p, integer *emin, + logical *ieee, integer *emax, doublereal *rmax) +{ + /* System generated locals */ + integer i__1; + doublereal d__1; + + /* Local variables */ + static integer i__; + static doublereal y, z__; + static integer try__, lexp; + static doublereal oldy; + static integer uexp, nbits; + extern doublereal dlamc3_(doublereal *, doublereal *); + static doublereal recbas; + static integer exbits, expsum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + DLAMC5 attempts to compute RMAX, the largest machine floating-point + number, without overflow. It assumes that EMAX + abs(EMIN) sum + approximately to a power of 2. It will fail on machines where this + assumption does not hold, for example, the Cyber 205 (EMIN = -28625, + EMAX = 28718). It will also fail if the value supplied for EMIN is + too large (i.e. too close to zero), probably with overflow. + + Arguments + ========= + + BETA (input) INTEGER + The base of floating-point arithmetic. + + P (input) INTEGER + The number of base BETA digits in the mantissa of a + floating-point value. + + EMIN (input) INTEGER + The minimum exponent before (gradual) underflow. + + IEEE (input) LOGICAL + A logical flag specifying whether or not the arithmetic + system is thought to comply with the IEEE standard. + + EMAX (output) INTEGER + The largest exponent before overflow + + RMAX (output) DOUBLE PRECISION + The largest machine floating-point number. + + ===================================================================== + + + First compute LEXP and UEXP, two powers of 2 that bound + abs(EMIN). We then assume that EMAX + abs(EMIN) will sum + approximately to the bound that is closest to abs(EMIN). + (EMAX is the exponent of the required number RMAX). +*/ + + lexp = 1; + exbits = 1; +L10: + try__ = lexp << 1; + if (try__ <= -(*emin)) { + lexp = try__; + ++exbits; + goto L10; + } + if (lexp == -(*emin)) { + uexp = lexp; + } else { + uexp = try__; + ++exbits; + } + +/* + Now -LEXP is less than or equal to EMIN, and -UEXP is greater + than or equal to EMIN. EXBITS is the number of bits needed to + store the exponent. +*/ + + if (uexp + *emin > -lexp - *emin) { + expsum = lexp << 1; + } else { + expsum = uexp << 1; + } + +/* + EXPSUM is the exponent range, approximately equal to + EMAX - EMIN + 1 . +*/ + + *emax = expsum + *emin - 1; + nbits = exbits + 1 + *p; + +/* + NBITS is the total number of bits needed to store a + floating-point number. +*/ + + if (nbits % 2 == 1 && *beta == 2) { + +/* + Either there are an odd number of bits used to store a + floating-point number, which is unlikely, or some bits are + not used in the representation of numbers, which is possible, + (e.g. Cray machines) or the mantissa has an implicit bit, + (e.g. IEEE machines, Dec Vax machines), which is perhaps the + most likely. We have to assume the last alternative. + If this is true, then we need to reduce EMAX by one because + there must be some way of representing zero in an implicit-bit + system. On machines like Cray, we are reducing EMAX by one + unnecessarily. +*/ + + --(*emax); + } + + if (*ieee) { + +/* + Assume we are on an IEEE machine which reserves one exponent + for infinity and NaN. +*/ + + --(*emax); + } + +/* + Now create RMAX, the largest machine number, which should + be equal to (1.0 - BETA**(-P)) * BETA**EMAX . + + First compute 1.0 - BETA**(-P), being careful that the + result is less than 1.0 . +*/ + + recbas = 1. / *beta; + z__ = *beta - 1.; + y = 0.; + i__1 = *p; + for (i__ = 1; i__ <= i__1; ++i__) { + z__ *= recbas; + if (y < 1.) { + oldy = y; + } + y = dlamc3_(&y, &z__); +/* L20: */ + } + if (y >= 1.) { + y = oldy; + } + +/* Now multiply by BETA**EMAX to get RMAX. */ + + i__1 = *emax; + for (i__ = 1; i__ <= i__1; ++i__) { + d__1 = y * *beta; + y = dlamc3_(&d__1, &c_b32); +/* L30: */ + } + + *rmax = y; + return 0; + +/* End of DLAMC5 */ + +} /* dlamc5_ */ + +logical lsame_(char *ca, char *cb) +{ + /* System generated locals */ + logical ret_val; + + /* Local variables */ + static integer inta, intb, zcode; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + LSAME returns .TRUE. if CA is the same letter as CB regardless of + case. + + Arguments + ========= + + CA (input) CHARACTER*1 + CB (input) CHARACTER*1 + CA and CB specify the single characters to be compared. + + ===================================================================== + + + Test if the characters are equal +*/ + + ret_val = *(unsigned char *)ca == *(unsigned char *)cb; + if (ret_val) { + return ret_val; + } + +/* Now test for equivalence if both characters are alphabetic. */ + + zcode = 'Z'; + +/* + Use 'Z' rather than 'A' so that ASCII can be detected on Prime + machines, on which ICHAR returns a value with bit 8 set. + ICHAR('A') on Prime machines returns 193 which is the same as + ICHAR('A') on an EBCDIC machine. +*/ + + inta = *(unsigned char *)ca; + intb = *(unsigned char *)cb; + + if (zcode == 90 || zcode == 122) { + +/* + ASCII is assumed - ZCODE is the ASCII code of either lower or + upper case 'Z'. +*/ + + if (inta >= 97 && inta <= 122) { + inta += -32; + } + if (intb >= 97 && intb <= 122) { + intb += -32; + } + + } else if (zcode == 233 || zcode == 169) { + +/* + EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or + upper case 'Z'. +*/ + + if (inta >= 129 && inta <= 137 || inta >= 145 && inta <= 153 || inta + >= 162 && inta <= 169) { + inta += 64; + } + if (intb >= 129 && intb <= 137 || intb >= 145 && intb <= 153 || intb + >= 162 && intb <= 169) { + intb += 64; + } + + } else if (zcode == 218 || zcode == 250) { + +/* + ASCII is assumed, on Prime machines - ZCODE is the ASCII code + plus 128 of either lower or upper case 'Z'. +*/ + + if (inta >= 225 && inta <= 250) { + inta += -32; + } + if (intb >= 225 && intb <= 250) { + intb += -32; + } + } + ret_val = inta == intb; + +/* + RETURN + + End of LSAME +*/ + + return ret_val; +} /* lsame_ */ + +doublereal slamch_(char *cmach) +{ + /* Initialized data */ + + static logical first = TRUE_; + + /* System generated locals */ + integer i__1; + real ret_val; + + /* Local variables */ + static real t; + static integer it; + static real rnd, eps, base; + static integer beta; + static real emin, prec, emax; + static integer imin, imax; + static logical lrnd; + static real rmin, rmax, rmach; + extern logical lsame_(char *, char *); + static real small, sfmin; + extern /* Subroutine */ int slamc2_(integer *, integer *, logical *, real + *, integer *, real *, integer *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + SLAMCH determines single precision machine parameters. + + Arguments + ========= + + CMACH (input) CHARACTER*1 + Specifies the value to be returned by SLAMCH: + = 'E' or 'e', SLAMCH := eps + = 'S' or 's , SLAMCH := sfmin + = 'B' or 'b', SLAMCH := base + = 'P' or 'p', SLAMCH := eps*base + = 'N' or 'n', SLAMCH := t + = 'R' or 'r', SLAMCH := rnd + = 'M' or 'm', SLAMCH := emin + = 'U' or 'u', SLAMCH := rmin + = 'L' or 'l', SLAMCH := emax + = 'O' or 'o', SLAMCH := rmax + + where + + eps = relative machine precision + sfmin = safe minimum, such that 1/sfmin does not overflow + base = base of the machine + prec = eps*base + t = number of (base) digits in the mantissa + rnd = 1.0 when rounding occurs in addition, 0.0 otherwise + emin = minimum exponent before (gradual) underflow + rmin = underflow threshold - base**(emin-1) + emax = largest exponent before overflow + rmax = overflow threshold - (base**emax)*(1-eps) + + ===================================================================== +*/ + + + if (first) { + slamc2_(&beta, &it, &lrnd, &eps, &imin, &rmin, &imax, &rmax); + base = (real) beta; + t = (real) it; + if (lrnd) { + rnd = 1.f; + i__1 = 1 - it; + eps = pow_ri(&base, &i__1) / 2; + } else { + rnd = 0.f; + i__1 = 1 - it; + eps = pow_ri(&base, &i__1); + } + prec = eps * base; + emin = (real) imin; + emax = (real) imax; + sfmin = rmin; + small = 1.f / rmax; + if (small >= sfmin) { + +/* + Use SMALL plus a bit, to avoid the possibility of rounding + causing overflow when computing 1/sfmin. +*/ + + sfmin = small * (eps + 1.f); + } + } + + if (lsame_(cmach, "E")) { + rmach = eps; + } else if (lsame_(cmach, "S")) { + rmach = sfmin; + } else if (lsame_(cmach, "B")) { + rmach = base; + } else if (lsame_(cmach, "P")) { + rmach = prec; + } else if (lsame_(cmach, "N")) { + rmach = t; + } else if (lsame_(cmach, "R")) { + rmach = rnd; + } else if (lsame_(cmach, "M")) { + rmach = emin; + } else if (lsame_(cmach, "U")) { + rmach = rmin; + } else if (lsame_(cmach, "L")) { + rmach = emax; + } else if (lsame_(cmach, "O")) { + rmach = rmax; + } + + ret_val = rmach; + first = FALSE_; + return ret_val; + +/* End of SLAMCH */ + +} /* slamch_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int slamc1_(integer *beta, integer *t, logical *rnd, logical + *ieee1) +{ + /* Initialized data */ + + static logical first = TRUE_; + + /* System generated locals */ + real r__1, r__2; + + /* Local variables */ + static real a, b, c__, f, t1, t2; + static integer lt; + static real one, qtr; + static logical lrnd; + static integer lbeta; + static real savec; + static logical lieee1; + extern doublereal slamc3_(real *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + SLAMC1 determines the machine parameters given by BETA, T, RND, and + IEEE1. + + Arguments + ========= + + BETA (output) INTEGER + The base of the machine. + + T (output) INTEGER + The number of ( BETA ) digits in the mantissa. + + RND (output) LOGICAL + Specifies whether proper rounding ( RND = .TRUE. ) or + chopping ( RND = .FALSE. ) occurs in addition. This may not + be a reliable guide to the way in which the machine performs + its arithmetic. + + IEEE1 (output) LOGICAL + Specifies whether rounding appears to be done in the IEEE + 'round to nearest' style. + + Further Details + =============== + + The routine is based on the routine ENVRON by Malcolm and + incorporates suggestions by Gentleman and Marovich. See + + Malcolm M. A. (1972) Algorithms to reveal properties of + floating-point arithmetic. Comms. of the ACM, 15, 949-951. + + Gentleman W. M. and Marovich S. B. (1974) More on algorithms + that reveal properties of floating point arithmetic units. + Comms. of the ACM, 17, 276-277. + + ===================================================================== +*/ + + + if (first) { + one = 1.f; + +/* + LBETA, LIEEE1, LT and LRND are the local values of BETA, + IEEE1, T and RND. + + Throughout this routine we use the function SLAMC3 to ensure + that relevant values are stored and not held in registers, or + are not affected by optimizers. + + Compute a = 2.0**m with the smallest positive integer m such + that + + fl( a + 1.0 ) = a. +*/ + + a = 1.f; + c__ = 1.f; + +/* + WHILE( C.EQ.ONE )LOOP */ +L10: + if (c__ == one) { + a *= 2; + c__ = slamc3_(&a, &one); + r__1 = -a; + c__ = slamc3_(&c__, &r__1); + goto L10; + } +/* + + END WHILE + + Now compute b = 2.0**m with the smallest positive integer m + such that + + fl( a + b ) .gt. a. +*/ + + b = 1.f; + c__ = slamc3_(&a, &b); + +/* + WHILE( C.EQ.A )LOOP */ +L20: + if (c__ == a) { + b *= 2; + c__ = slamc3_(&a, &b); + goto L20; + } +/* + + END WHILE + + Now compute the base. a and c are neighbouring floating point + numbers in the interval ( beta**t, beta**( t + 1 ) ) and so + their difference is beta. Adding 0.25 to c is to ensure that it + is truncated to beta and not ( beta - 1 ). +*/ + + qtr = one / 4; + savec = c__; + r__1 = -a; + c__ = slamc3_(&c__, &r__1); + lbeta = c__ + qtr; + +/* + Now determine whether rounding or chopping occurs, by adding a + bit less than beta/2 and a bit more than beta/2 to a. +*/ + + b = (real) lbeta; + r__1 = b / 2; + r__2 = -b / 100; + f = slamc3_(&r__1, &r__2); + c__ = slamc3_(&f, &a); + if (c__ == a) { + lrnd = TRUE_; + } else { + lrnd = FALSE_; + } + r__1 = b / 2; + r__2 = b / 100; + f = slamc3_(&r__1, &r__2); + c__ = slamc3_(&f, &a); + if (lrnd && c__ == a) { + lrnd = FALSE_; + } + +/* + Try and decide whether rounding is done in the IEEE 'round to + nearest' style. B/2 is half a unit in the last place of the two + numbers A and SAVEC. Furthermore, A is even, i.e. has last bit + zero, and SAVEC is odd. Thus adding B/2 to A should not change + A, but adding B/2 to SAVEC should change SAVEC. +*/ + + r__1 = b / 2; + t1 = slamc3_(&r__1, &a); + r__1 = b / 2; + t2 = slamc3_(&r__1, &savec); + lieee1 = t1 == a && t2 > savec && lrnd; + +/* + Now find the mantissa, t. It should be the integer part of + log to the base beta of a, however it is safer to determine t + by powering. So we find t as the smallest positive integer for + which + + fl( beta**t + 1.0 ) = 1.0. +*/ + + lt = 0; + a = 1.f; + c__ = 1.f; + +/* + WHILE( C.EQ.ONE )LOOP */ +L30: + if (c__ == one) { + ++lt; + a *= lbeta; + c__ = slamc3_(&a, &one); + r__1 = -a; + c__ = slamc3_(&c__, &r__1); + goto L30; + } +/* + END WHILE */ + + } + + *beta = lbeta; + *t = lt; + *rnd = lrnd; + *ieee1 = lieee1; + first = FALSE_; + return 0; + +/* End of SLAMC1 */ + +} /* slamc1_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int slamc2_(integer *beta, integer *t, logical *rnd, real * + eps, integer *emin, real *rmin, integer *emax, real *rmax) +{ + /* Initialized data */ + + static logical first = TRUE_; + static logical iwarn = FALSE_; + + /* Format strings */ + static char fmt_9999[] = "(//\002 WARNING. The value EMIN may be incorre" + "ct:-\002,\002 EMIN = \002,i8,/\002 If, after inspection, the va" + "lue EMIN looks\002,\002 acceptable please comment out \002,/\002" + " the IF block as marked within the code of routine\002,\002 SLAM" + "C2,\002,/\002 otherwise supply EMIN explicitly.\002,/)"; + + /* System generated locals */ + integer i__1; + real r__1, r__2, r__3, r__4, r__5; + + /* Local variables */ + static real a, b, c__; + static integer i__, lt; + static real one, two; + static logical ieee; + static real half; + static logical lrnd; + static real leps, zero; + static integer lbeta; + static real rbase; + static integer lemin, lemax, gnmin; + static real small; + static integer gpmin; + static real third, lrmin, lrmax, sixth; + static logical lieee1; + extern /* Subroutine */ int slamc1_(integer *, integer *, logical *, + logical *); + extern doublereal slamc3_(real *, real *); + extern /* Subroutine */ int slamc4_(integer *, real *, integer *), + slamc5_(integer *, integer *, integer *, logical *, integer *, + real *); + static integer ngnmin, ngpmin; + + /* Fortran I/O blocks */ + static cilist io___144 = { 0, 6, 0, fmt_9999, 0 }; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + SLAMC2 determines the machine parameters specified in its argument + list. + + Arguments + ========= + + BETA (output) INTEGER + The base of the machine. + + T (output) INTEGER + The number of ( BETA ) digits in the mantissa. + + RND (output) LOGICAL + Specifies whether proper rounding ( RND = .TRUE. ) or + chopping ( RND = .FALSE. ) occurs in addition. This may not + be a reliable guide to the way in which the machine performs + its arithmetic. + + EPS (output) REAL + The smallest positive number such that + + fl( 1.0 - EPS ) .LT. 1.0, + + where fl denotes the computed value. + + EMIN (output) INTEGER + The minimum exponent before (gradual) underflow occurs. + + RMIN (output) REAL + The smallest normalized number for the machine, given by + BASE**( EMIN - 1 ), where BASE is the floating point value + of BETA. + + EMAX (output) INTEGER + The maximum exponent before overflow occurs. + + RMAX (output) REAL + The largest positive number for the machine, given by + BASE**EMAX * ( 1 - EPS ), where BASE is the floating point + value of BETA. + + Further Details + =============== + + The computation of EPS is based on a routine PARANOIA by + W. Kahan of the University of California at Berkeley. + + ===================================================================== +*/ + + + if (first) { + zero = 0.f; + one = 1.f; + two = 2.f; + +/* + LBETA, LT, LRND, LEPS, LEMIN and LRMIN are the local values of + BETA, T, RND, EPS, EMIN and RMIN. + + Throughout this routine we use the function SLAMC3 to ensure + that relevant values are stored and not held in registers, or + are not affected by optimizers. + + SLAMC1 returns the parameters LBETA, LT, LRND and LIEEE1. +*/ + + slamc1_(&lbeta, <, &lrnd, &lieee1); + +/* Start to find EPS. */ + + b = (real) lbeta; + i__1 = -lt; + a = pow_ri(&b, &i__1); + leps = a; + +/* Try some tricks to see whether or not this is the correct EPS. */ + + b = two / 3; + half = one / 2; + r__1 = -half; + sixth = slamc3_(&b, &r__1); + third = slamc3_(&sixth, &sixth); + r__1 = -half; + b = slamc3_(&third, &r__1); + b = slamc3_(&b, &sixth); + b = dabs(b); + if (b < leps) { + b = leps; + } + + leps = 1.f; + +/* + WHILE( ( LEPS.GT.B ).AND.( B.GT.ZERO ) )LOOP */ +L10: + if (leps > b && b > zero) { + leps = b; + r__1 = half * leps; +/* Computing 5th power */ + r__3 = two, r__4 = r__3, r__3 *= r__3; +/* Computing 2nd power */ + r__5 = leps; + r__2 = r__4 * (r__3 * r__3) * (r__5 * r__5); + c__ = slamc3_(&r__1, &r__2); + r__1 = -c__; + c__ = slamc3_(&half, &r__1); + b = slamc3_(&half, &c__); + r__1 = -b; + c__ = slamc3_(&half, &r__1); + b = slamc3_(&half, &c__); + goto L10; + } +/* + END WHILE */ + + if (a < leps) { + leps = a; + } + +/* + Computation of EPS complete. + + Now find EMIN. Let A = + or - 1, and + or - (1 + BASE**(-3)). + Keep dividing A by BETA until (gradual) underflow occurs. This + is detected when we cannot recover the previous A. +*/ + + rbase = one / lbeta; + small = one; + for (i__ = 1; i__ <= 3; ++i__) { + r__1 = small * rbase; + small = slamc3_(&r__1, &zero); +/* L20: */ + } + a = slamc3_(&one, &small); + slamc4_(&ngpmin, &one, &lbeta); + r__1 = -one; + slamc4_(&ngnmin, &r__1, &lbeta); + slamc4_(&gpmin, &a, &lbeta); + r__1 = -a; + slamc4_(&gnmin, &r__1, &lbeta); + ieee = FALSE_; + + if (ngpmin == ngnmin && gpmin == gnmin) { + if (ngpmin == gpmin) { + lemin = ngpmin; +/* + ( Non twos-complement machines, no gradual underflow; + e.g., VAX ) +*/ + } else if (gpmin - ngpmin == 3) { + lemin = ngpmin - 1 + lt; + ieee = TRUE_; +/* + ( Non twos-complement machines, with gradual underflow; + e.g., IEEE standard followers ) +*/ + } else { + lemin = min(ngpmin,gpmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } else if (ngpmin == gpmin && ngnmin == gnmin) { + if ((i__1 = ngpmin - ngnmin, abs(i__1)) == 1) { + lemin = max(ngpmin,ngnmin); +/* + ( Twos-complement machines, no gradual underflow; + e.g., CYBER 205 ) +*/ + } else { + lemin = min(ngpmin,ngnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } else if ((i__1 = ngpmin - ngnmin, abs(i__1)) == 1 && gpmin == gnmin) + { + if (gpmin - min(ngpmin,ngnmin) == 3) { + lemin = max(ngpmin,ngnmin) - 1 + lt; +/* + ( Twos-complement machines with gradual underflow; + no known machine ) +*/ + } else { + lemin = min(ngpmin,ngnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } else { +/* Computing MIN */ + i__1 = min(ngpmin,ngnmin), i__1 = min(i__1,gpmin); + lemin = min(i__1,gnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + first = FALSE_; +/* + ** + Comment out this if block if EMIN is ok +*/ + if (iwarn) { + first = TRUE_; + s_wsfe(&io___144); + do_fio(&c__1, (char *)&lemin, (ftnlen)sizeof(integer)); + e_wsfe(); + } +/* + ** + + Assume IEEE arithmetic if we found denormalised numbers above, + or if arithmetic seems to round in the IEEE style, determined + in routine SLAMC1. A true IEEE machine should have both things + true; however, faulty machines may have one or the other. +*/ + + ieee = ieee || lieee1; + +/* + Compute RMIN by successive division by BETA. We could compute + RMIN as BASE**( EMIN - 1 ), but some machines underflow during + this computation. +*/ + + lrmin = 1.f; + i__1 = 1 - lemin; + for (i__ = 1; i__ <= i__1; ++i__) { + r__1 = lrmin * rbase; + lrmin = slamc3_(&r__1, &zero); +/* L30: */ + } + +/* Finally, call SLAMC5 to compute EMAX and RMAX. */ + + slamc5_(&lbeta, <, &lemin, &ieee, &lemax, &lrmax); + } + + *beta = lbeta; + *t = lt; + *rnd = lrnd; + *eps = leps; + *emin = lemin; + *rmin = lrmin; + *emax = lemax; + *rmax = lrmax; + + return 0; + + +/* End of SLAMC2 */ + +} /* slamc2_ */ + + +/* *********************************************************************** */ + +doublereal slamc3_(real *a, real *b) +{ + /* System generated locals */ + real ret_val; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + SLAMC3 is intended to force A and B to be stored prior to doing + the addition of A and B , for use in situations where optimizers + might hold one of these in a register. + + Arguments + ========= + + A (input) REAL + B (input) REAL + The values A and B. + + ===================================================================== +*/ + + + ret_val = *a + *b; + + return ret_val; + +/* End of SLAMC3 */ + +} /* slamc3_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int slamc4_(integer *emin, real *start, integer *base) +{ + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + static real a; + static integer i__; + static real b1, b2, c1, c2, d1, d2, one, zero, rbase; + extern doublereal slamc3_(real *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + SLAMC4 is a service routine for SLAMC2. + + Arguments + ========= + + EMIN (output) INTEGER + The minimum exponent before (gradual) underflow, computed by + setting A = START and dividing by BASE until the previous A + can not be recovered. + + START (input) REAL + The starting point for determining EMIN. + + BASE (input) INTEGER + The base of the machine. + + ===================================================================== +*/ + + + a = *start; + one = 1.f; + rbase = one / *base; + zero = 0.f; + *emin = 1; + r__1 = a * rbase; + b1 = slamc3_(&r__1, &zero); + c1 = a; + c2 = a; + d1 = a; + d2 = a; +/* + + WHILE( ( C1.EQ.A ).AND.( C2.EQ.A ).AND. + $ ( D1.EQ.A ).AND.( D2.EQ.A ) )LOOP +*/ +L10: + if (c1 == a && c2 == a && d1 == a && d2 == a) { + --(*emin); + a = b1; + r__1 = a / *base; + b1 = slamc3_(&r__1, &zero); + r__1 = b1 * *base; + c1 = slamc3_(&r__1, &zero); + d1 = zero; + i__1 = *base; + for (i__ = 1; i__ <= i__1; ++i__) { + d1 += b1; +/* L20: */ + } + r__1 = a * rbase; + b2 = slamc3_(&r__1, &zero); + r__1 = b2 / rbase; + c2 = slamc3_(&r__1, &zero); + d2 = zero; + i__1 = *base; + for (i__ = 1; i__ <= i__1; ++i__) { + d2 += b2; +/* L30: */ + } + goto L10; + } +/* + END WHILE */ + + return 0; + +/* End of SLAMC4 */ + +} /* slamc4_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int slamc5_(integer *beta, integer *p, integer *emin, + logical *ieee, integer *emax, real *rmax) +{ + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + static integer i__; + static real y, z__; + static integer try__, lexp; + static real oldy; + static integer uexp, nbits; + extern doublereal slamc3_(real *, real *); + static real recbas; + static integer exbits, expsum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. + November 2006 + + + Purpose + ======= + + SLAMC5 attempts to compute RMAX, the largest machine floating-point + number, without overflow. It assumes that EMAX + abs(EMIN) sum + approximately to a power of 2. It will fail on machines where this + assumption does not hold, for example, the Cyber 205 (EMIN = -28625, + EMAX = 28718). It will also fail if the value supplied for EMIN is + too large (i.e. too close to zero), probably with overflow. + + Arguments + ========= + + BETA (input) INTEGER + The base of floating-point arithmetic. + + P (input) INTEGER + The number of base BETA digits in the mantissa of a + floating-point value. + + EMIN (input) INTEGER + The minimum exponent before (gradual) underflow. + + IEEE (input) LOGICAL + A logical flag specifying whether or not the arithmetic + system is thought to comply with the IEEE standard. + + EMAX (output) INTEGER + The largest exponent before overflow + + RMAX (output) REAL + The largest machine floating-point number. + + ===================================================================== + + + First compute LEXP and UEXP, two powers of 2 that bound + abs(EMIN). We then assume that EMAX + abs(EMIN) will sum + approximately to the bound that is closest to abs(EMIN). + (EMAX is the exponent of the required number RMAX). +*/ + + lexp = 1; + exbits = 1; +L10: + try__ = lexp << 1; + if (try__ <= -(*emin)) { + lexp = try__; + ++exbits; + goto L10; + } + if (lexp == -(*emin)) { + uexp = lexp; + } else { + uexp = try__; + ++exbits; + } + +/* + Now -LEXP is less than or equal to EMIN, and -UEXP is greater + than or equal to EMIN. EXBITS is the number of bits needed to + store the exponent. +*/ + + if (uexp + *emin > -lexp - *emin) { + expsum = lexp << 1; + } else { + expsum = uexp << 1; + } + +/* + EXPSUM is the exponent range, approximately equal to + EMAX - EMIN + 1 . +*/ + + *emax = expsum + *emin - 1; + nbits = exbits + 1 + *p; + +/* + NBITS is the total number of bits needed to store a + floating-point number. +*/ + + if (nbits % 2 == 1 && *beta == 2) { + +/* + Either there are an odd number of bits used to store a + floating-point number, which is unlikely, or some bits are + not used in the representation of numbers, which is possible, + (e.g. Cray machines) or the mantissa has an implicit bit, + (e.g. IEEE machines, Dec Vax machines), which is perhaps the + most likely. We have to assume the last alternative. + If this is true, then we need to reduce EMAX by one because + there must be some way of representing zero in an implicit-bit + system. On machines like Cray, we are reducing EMAX by one + unnecessarily. +*/ + + --(*emax); + } + + if (*ieee) { + +/* + Assume we are on an IEEE machine which reserves one exponent + for infinity and NaN. +*/ + + --(*emax); + } + +/* + Now create RMAX, the largest machine number, which should + be equal to (1.0 - BETA**(-P)) * BETA**EMAX . + + First compute 1.0 - BETA**(-P), being careful that the + result is less than 1.0 . +*/ + + recbas = 1.f / *beta; + z__ = *beta - 1.f; + y = 0.f; + i__1 = *p; + for (i__ = 1; i__ <= i__1; ++i__) { + z__ *= recbas; + if (y < 1.f) { + oldy = y; + } + y = slamc3_(&y, &z__); +/* L20: */ + } + if (y >= 1.f) { + y = oldy; + } + +/* Now multiply by BETA**EMAX to get RMAX. */ + + i__1 = *emax; + for (i__ = 1; i__ <= i__1; ++i__) { + r__1 = y * *beta; + y = slamc3_(&r__1, &c_b66); +/* L30: */ + } + + *rmax = y; + return 0; + +/* End of SLAMC5 */ + +} /* slamc5_ */ + diff --git a/numpy/linalg/lapack_lite/f2c_d_lapack.c b/numpy/linalg/lapack_lite/f2c_d_lapack.c new file mode 100644 index 0000000..1a6675e --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c_d_lapack.c @@ -0,0 +1,41864 @@ +/* +NOTE: This is generated code. Look in Misc/lapack_lite for information on + remaking this file. +*/ +#include "f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal dlamch_(char *); +#define EPSILON dlamch_("Epsilon") +#define SAFEMINIMUM dlamch_("Safe minimum") +#define PRECISION dlamch_("Precision") +#define BASE dlamch_("Base") +#endif + +extern doublereal dlapy2_(doublereal *x, doublereal *y); + +/* +f2c knows the exact rules for precedence, and so omits parentheses where not +strictly necessary. Since this is generated code, we don't really care if +it's readable, and we know what is written is correct. So don't warn about +them. +*/ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wparentheses" +#endif + + +/* Table of constant values */ + +static integer c__9 = 9; +static integer c__0 = 0; +static doublereal c_b15 = 1.; +static integer c__1 = 1; +static doublereal c_b29 = 0.; +static doublereal c_b94 = -.125; +static doublereal c_b151 = -1.; +static integer c_n1 = -1; +static integer c__3 = 3; +static integer c__2 = 2; +static integer c__65 = 65; +static integer c__6 = 6; +static integer c__12 = 12; +static integer c__49 = 49; +static integer c__4 = 4; +static logical c_false = FALSE_; +static integer c__13 = 13; +static integer c__15 = 15; +static integer c__14 = 14; +static integer c__16 = 16; +static logical c_true = TRUE_; +static integer c__10 = 10; +static integer c__11 = 11; +static doublereal c_b3192 = 2.; + +/* Subroutine */ int dbdsdc_(char *uplo, char *compq, integer *n, doublereal * + d__, doublereal *e, doublereal *u, integer *ldu, doublereal *vt, + integer *ldvt, doublereal *q, integer *iq, doublereal *work, integer * + iwork, integer *info) +{ + /* System generated locals */ + integer u_dim1, u_offset, vt_dim1, vt_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer i__, j, k; + static doublereal p, r__; + static integer z__, ic, ii, kk; + static doublereal cs; + static integer is, iu; + static doublereal sn; + static integer nm1; + static doublereal eps; + static integer ivt, difl, difr, ierr, perm, mlvl, sqre; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dlasr_(char *, char *, char *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *), dcopy_(integer *, doublereal *, integer * + , doublereal *, integer *), dswap_(integer *, doublereal *, + integer *, doublereal *, integer *); + static integer poles, iuplo, nsize, start; + extern /* Subroutine */ int dlasd0_(integer *, integer *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + integer *, integer *, doublereal *, integer *); + + extern /* Subroutine */ int dlasda_(integer *, integer *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *, integer *, integer *, integer *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *, + integer *), dlascl_(char *, integer *, integer *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + integer *), dlasdq_(char *, integer *, integer *, integer + *, integer *, integer *, doublereal *, doublereal *, doublereal *, + integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *), dlaset_(char *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *), dlartg_(doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *); + static integer givcol; + extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); + static integer icompq; + static doublereal orgnrm; + static integer givnum, givptr, qstart, smlsiz, wstart, smlszp; + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DBDSDC computes the singular value decomposition (SVD) of a real + N-by-N (upper or lower) bidiagonal matrix B: B = U * S * VT, + using a divide and conquer method, where S is a diagonal matrix + with non-negative diagonal elements (the singular values of B), and + U and VT are orthogonal matrices of left and right singular vectors, + respectively. DBDSDC can be used to compute all singular values, + and optionally, singular vectors or singular vectors in compact form. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. See DLASD3 for details. + + The code currently calls DLASDQ if singular values only are desired. + However, it can be slightly modified to compute singular values + using the divide and conquer method. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': B is upper bidiagonal. + = 'L': B is lower bidiagonal. + + COMPQ (input) CHARACTER*1 + Specifies whether singular vectors are to be computed + as follows: + = 'N': Compute singular values only; + = 'P': Compute singular values and compute singular + vectors in compact form; + = 'I': Compute singular values and singular vectors. + + N (input) INTEGER + The order of the matrix B. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the n diagonal elements of the bidiagonal matrix B. + On exit, if INFO=0, the singular values of B. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + On entry, the elements of E contain the offdiagonal + elements of the bidiagonal matrix whose SVD is desired. + On exit, E has been destroyed. + + U (output) DOUBLE PRECISION array, dimension (LDU,N) + If COMPQ = 'I', then: + On exit, if INFO = 0, U contains the left singular vectors + of the bidiagonal matrix. + For other values of COMPQ, U is not referenced. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= 1. + If singular vectors are desired, then LDU >= max( 1, N ). + + VT (output) DOUBLE PRECISION array, dimension (LDVT,N) + If COMPQ = 'I', then: + On exit, if INFO = 0, VT' contains the right singular + vectors of the bidiagonal matrix. + For other values of COMPQ, VT is not referenced. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= 1. + If singular vectors are desired, then LDVT >= max( 1, N ). + + Q (output) DOUBLE PRECISION array, dimension (LDQ) + If COMPQ = 'P', then: + On exit, if INFO = 0, Q and IQ contain the left + and right singular vectors in a compact form, + requiring O(N log N) space instead of 2*N**2. + In particular, Q contains all the DOUBLE PRECISION data in + LDQ >= N*(11 + 2*SMLSIZ + 8*INT(LOG_2(N/(SMLSIZ+1)))) + words of memory, where SMLSIZ is returned by ILAENV and + is equal to the maximum size of the subproblems at the + bottom of the computation tree (usually about 25). + For other values of COMPQ, Q is not referenced. + + IQ (output) INTEGER array, dimension (LDIQ) + If COMPQ = 'P', then: + On exit, if INFO = 0, Q and IQ contain the left + and right singular vectors in a compact form, + requiring O(N log N) space instead of 2*N**2. + In particular, IQ contains all INTEGER data in + LDIQ >= N*(3 + 3*INT(LOG_2(N/(SMLSIZ+1)))) + words of memory, where SMLSIZ is returned by ILAENV and + is equal to the maximum size of the subproblems at the + bottom of the computation tree (usually about 25). + For other values of COMPQ, IQ is not referenced. + + WORK (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + If COMPQ = 'N' then LWORK >= (4 * N). + If COMPQ = 'P' then LWORK >= (6 * N). + If COMPQ = 'I' then LWORK >= (3 * N**2 + 4 * N). + + IWORK (workspace) INTEGER array, dimension (8*N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute a singular value. + The update process of divide and conquer failed. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + Changed dimension statement in comment describing E from (N) to + (N-1). Sven, 17 Feb 05. + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --q; + --iq; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + iuplo = 0; + if (lsame_(uplo, "U")) { + iuplo = 1; + } + if (lsame_(uplo, "L")) { + iuplo = 2; + } + if (lsame_(compq, "N")) { + icompq = 0; + } else if (lsame_(compq, "P")) { + icompq = 1; + } else if (lsame_(compq, "I")) { + icompq = 2; + } else { + icompq = -1; + } + if (iuplo == 0) { + *info = -1; + } else if (icompq < 0) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ldu < 1 || icompq == 2 && *ldu < *n) { + *info = -7; + } else if (*ldvt < 1 || icompq == 2 && *ldvt < *n) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DBDSDC", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + smlsiz = ilaenv_(&c__9, "DBDSDC", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + if (*n == 1) { + if (icompq == 1) { + q[1] = d_sign(&c_b15, &d__[1]); + q[smlsiz * *n + 1] = 1.; + } else if (icompq == 2) { + u[u_dim1 + 1] = d_sign(&c_b15, &d__[1]); + vt[vt_dim1 + 1] = 1.; + } + d__[1] = abs(d__[1]); + return 0; + } + nm1 = *n - 1; + +/* + If matrix lower bidiagonal, rotate to be upper bidiagonal + by applying Givens rotations on the left +*/ + + wstart = 1; + qstart = 3; + if (icompq == 1) { + dcopy_(n, &d__[1], &c__1, &q[1], &c__1); + i__1 = *n - 1; + dcopy_(&i__1, &e[1], &c__1, &q[*n + 1], &c__1); + } + if (iuplo == 2) { + qstart = 5; + wstart = (*n << 1) - 1; + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + dlartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + if (icompq == 1) { + q[i__ + (*n << 1)] = cs; + q[i__ + *n * 3] = sn; + } else if (icompq == 2) { + work[i__] = cs; + work[nm1 + i__] = -sn; + } +/* L10: */ + } + } + +/* If ICOMPQ = 0, use DLASDQ to compute the singular values. */ + + if (icompq == 0) { + dlasdq_("U", &c__0, n, &c__0, &c__0, &c__0, &d__[1], &e[1], &vt[ + vt_offset], ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[ + wstart], info); + goto L40; + } + +/* + If N is smaller than the minimum divide size SMLSIZ, then solve + the problem with another solver. +*/ + + if (*n <= smlsiz) { + if (icompq == 2) { + dlaset_("A", n, n, &c_b29, &c_b15, &u[u_offset], ldu); + dlaset_("A", n, n, &c_b29, &c_b15, &vt[vt_offset], ldvt); + dlasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &vt[vt_offset] + , ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[ + wstart], info); + } else if (icompq == 1) { + iu = 1; + ivt = iu + *n; + dlaset_("A", n, n, &c_b29, &c_b15, &q[iu + (qstart - 1) * *n], n); + dlaset_("A", n, n, &c_b29, &c_b15, &q[ivt + (qstart - 1) * *n], n); + dlasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &q[ivt + ( + qstart - 1) * *n], n, &q[iu + (qstart - 1) * *n], n, &q[ + iu + (qstart - 1) * *n], n, &work[wstart], info); + } + goto L40; + } + + if (icompq == 2) { + dlaset_("A", n, n, &c_b29, &c_b15, &u[u_offset], ldu); + dlaset_("A", n, n, &c_b29, &c_b15, &vt[vt_offset], ldvt); + } + +/* Scale. */ + + orgnrm = dlanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.) { + return 0; + } + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, n, &c__1, &d__[1], n, &ierr); + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &nm1, &c__1, &e[1], &nm1, & + ierr); + + eps = EPSILON; + + mlvl = (integer) (log((doublereal) (*n) / (doublereal) (smlsiz + 1)) / + log(2.)) + 1; + smlszp = smlsiz + 1; + + if (icompq == 1) { + iu = 1; + ivt = smlsiz + 1; + difl = ivt + smlszp; + difr = difl + mlvl; + z__ = difr + (mlvl << 1); + ic = z__ + mlvl; + is = ic + 1; + poles = is + 1; + givnum = poles + (mlvl << 1); + + k = 1; + givptr = 2; + perm = 3; + givcol = perm + mlvl; + } + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((d__1 = d__[i__], abs(d__1)) < eps) { + d__[i__] = d_sign(&eps, &d__[i__]); + } +/* L20: */ + } + + start = 1; + sqre = 0; + + i__1 = nm1; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((d__1 = e[i__], abs(d__1)) < eps || i__ == nm1) { + +/* + Subproblem found. First determine its size and then + apply divide and conquer on it. +*/ + + if (i__ < nm1) { + +/* A subproblem with E(I) small for I < NM1. */ + + nsize = i__ - start + 1; + } else if ((d__1 = e[i__], abs(d__1)) >= eps) { + +/* A subproblem with E(NM1) not too small but I = NM1. */ + + nsize = *n - start + 1; + } else { + +/* + A subproblem with E(NM1) small. This implies an + 1-by-1 subproblem at D(N). Solve this 1-by-1 problem + first. +*/ + + nsize = i__ - start + 1; + if (icompq == 2) { + u[*n + *n * u_dim1] = d_sign(&c_b15, &d__[*n]); + vt[*n + *n * vt_dim1] = 1.; + } else if (icompq == 1) { + q[*n + (qstart - 1) * *n] = d_sign(&c_b15, &d__[*n]); + q[*n + (smlsiz + qstart - 1) * *n] = 1.; + } + d__[*n] = (d__1 = d__[*n], abs(d__1)); + } + if (icompq == 2) { + dlasd0_(&nsize, &sqre, &d__[start], &e[start], &u[start + + start * u_dim1], ldu, &vt[start + start * vt_dim1], + ldvt, &smlsiz, &iwork[1], &work[wstart], info); + } else { + dlasda_(&icompq, &smlsiz, &nsize, &sqre, &d__[start], &e[ + start], &q[start + (iu + qstart - 2) * *n], n, &q[ + start + (ivt + qstart - 2) * *n], &iq[start + k * *n], + &q[start + (difl + qstart - 2) * *n], &q[start + ( + difr + qstart - 2) * *n], &q[start + (z__ + qstart - + 2) * *n], &q[start + (poles + qstart - 2) * *n], &iq[ + start + givptr * *n], &iq[start + givcol * *n], n, & + iq[start + perm * *n], &q[start + (givnum + qstart - + 2) * *n], &q[start + (ic + qstart - 2) * *n], &q[ + start + (is + qstart - 2) * *n], &work[wstart], & + iwork[1], info); + } + if (*info != 0) { + return 0; + } + start = i__ + 1; + } +/* L30: */ + } + +/* Unscale */ + + dlascl_("G", &c__0, &c__0, &c_b15, &orgnrm, n, &c__1, &d__[1], n, &ierr); +L40: + +/* Use Selection Sort to minimize swaps of singular vectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + kk = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] > p) { + kk = j; + p = d__[j]; + } +/* L50: */ + } + if (kk != i__) { + d__[kk] = d__[i__]; + d__[i__] = p; + if (icompq == 1) { + iq[i__] = kk; + } else if (icompq == 2) { + dswap_(n, &u[i__ * u_dim1 + 1], &c__1, &u[kk * u_dim1 + 1], & + c__1); + dswap_(n, &vt[i__ + vt_dim1], ldvt, &vt[kk + vt_dim1], ldvt); + } + } else if (icompq == 1) { + iq[i__] = i__; + } +/* L60: */ + } + +/* If ICOMPQ = 1, use IQ(N,1) as the indicator for UPLO */ + + if (icompq == 1) { + if (iuplo == 1) { + iq[*n] = 1; + } else { + iq[*n] = 0; + } + } + +/* + If B is lower bidiagonal, update U by those Givens rotations + which rotated B to be upper bidiagonal +*/ + + if (iuplo == 2 && icompq == 2) { + dlasr_("L", "V", "B", n, n, &work[1], &work[*n], &u[u_offset], ldu); + } + + return 0; + +/* End of DBDSDC */ + +} /* dbdsdc_ */ + +/* Subroutine */ int dbdsqr_(char *uplo, integer *n, integer *ncvt, integer * + nru, integer *ncc, doublereal *d__, doublereal *e, doublereal *vt, + integer *ldvt, doublereal *u, integer *ldu, doublereal *c__, integer * + ldc, doublereal *work, integer *info) +{ + /* System generated locals */ + integer c_dim1, c_offset, u_dim1, u_offset, vt_dim1, vt_offset, i__1, + i__2; + doublereal d__1, d__2, d__3, d__4; + + /* Local variables */ + static doublereal f, g, h__; + static integer i__, j, m; + static doublereal r__, cs; + static integer ll; + static doublereal sn, mu; + static integer nm1, nm12, nm13, lll; + static doublereal eps, sll, tol, abse; + static integer idir; + static doublereal abss; + static integer oldm; + static doublereal cosl; + static integer isub, iter; + static doublereal unfl, sinl, cosr, smin, smax, sinr; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *), dlas2_( + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *), dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + static doublereal oldcs; + extern /* Subroutine */ int dlasr_(char *, char *, char *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *); + static integer oldll; + static doublereal shift, sigmn, oldsn; + extern /* Subroutine */ int dswap_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer maxit; + static doublereal sminl, sigmx; + static logical lower; + extern /* Subroutine */ int dlasq1_(integer *, doublereal *, doublereal *, + doublereal *, integer *), dlasv2_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *); + + extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *), xerbla_(char *, + integer *); + static doublereal sminoa, thresh; + static logical rotate; + static doublereal tolmul; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + January 2007 + + + Purpose + ======= + + DBDSQR computes the singular values and, optionally, the right and/or + left singular vectors from the singular value decomposition (SVD) of + a real N-by-N (upper or lower) bidiagonal matrix B using the implicit + zero-shift QR algorithm. The SVD of B has the form + + B = Q * S * P**T + + where S is the diagonal matrix of singular values, Q is an orthogonal + matrix of left singular vectors, and P is an orthogonal matrix of + right singular vectors. If left singular vectors are requested, this + subroutine actually returns U*Q instead of Q, and, if right singular + vectors are requested, this subroutine returns P**T*VT instead of + P**T, for given real input matrices U and VT. When U and VT are the + orthogonal matrices that reduce a general matrix A to bidiagonal + form: A = U*B*VT, as computed by DGEBRD, then + + A = (U*Q) * S * (P**T*VT) + + is the SVD of A. Optionally, the subroutine may also compute Q**T*C + for a given real input matrix C. + + See "Computing Small Singular Values of Bidiagonal Matrices With + Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, + LAPACK Working Note #3 (or SIAM J. Sci. Statist. Comput. vol. 11, + no. 5, pp. 873-912, Sept 1990) and + "Accurate singular values and differential qd algorithms," by + B. Parlett and V. Fernando, Technical Report CPAM-554, Mathematics + Department, University of California at Berkeley, July 1992 + for a detailed description of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': B is upper bidiagonal; + = 'L': B is lower bidiagonal. + + N (input) INTEGER + The order of the matrix B. N >= 0. + + NCVT (input) INTEGER + The number of columns of the matrix VT. NCVT >= 0. + + NRU (input) INTEGER + The number of rows of the matrix U. NRU >= 0. + + NCC (input) INTEGER + The number of columns of the matrix C. NCC >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the n diagonal elements of the bidiagonal matrix B. + On exit, if INFO=0, the singular values of B in decreasing + order. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + On entry, the N-1 offdiagonal elements of the bidiagonal + matrix B. + On exit, if INFO = 0, E is destroyed; if INFO > 0, D and E + will contain the diagonal and superdiagonal elements of a + bidiagonal matrix orthogonally equivalent to the one given + as input. + + VT (input/output) DOUBLE PRECISION array, dimension (LDVT, NCVT) + On entry, an N-by-NCVT matrix VT. + On exit, VT is overwritten by P**T * VT. + Not referenced if NCVT = 0. + + LDVT (input) INTEGER + The leading dimension of the array VT. + LDVT >= max(1,N) if NCVT > 0; LDVT >= 1 if NCVT = 0. + + U (input/output) DOUBLE PRECISION array, dimension (LDU, N) + On entry, an NRU-by-N matrix U. + On exit, U is overwritten by U * Q. + Not referenced if NRU = 0. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= max(1,NRU). + + C (input/output) DOUBLE PRECISION array, dimension (LDC, NCC) + On entry, an N-by-NCC matrix C. + On exit, C is overwritten by Q**T * C. + Not referenced if NCC = 0. + + LDC (input) INTEGER + The leading dimension of the array C. + LDC >= max(1,N) if NCC > 0; LDC >=1 if NCC = 0. + + WORK (workspace) DOUBLE PRECISION array, dimension (4*N) + + INFO (output) INTEGER + = 0: successful exit + < 0: If INFO = -i, the i-th argument had an illegal value + > 0: + if NCVT = NRU = NCC = 0, + = 1, a split was marked by a positive value in E + = 2, current block of Z not diagonalized after 30*N + iterations (in inner while loop) + = 3, termination criterion of outer while loop not met + (program created more than N unreduced blocks) + else NCVT = NRU = NCC = 0, + the algorithm did not converge; D and E contain the + elements of a bidiagonal matrix which is orthogonally + similar to the input matrix B; if INFO = i, i + elements of E have not converged to zero. + + Internal Parameters + =================== + + TOLMUL DOUBLE PRECISION, default = max(10,min(100,EPS**(-1/8))) + TOLMUL controls the convergence criterion of the QR loop. + If it is positive, TOLMUL*EPS is the desired relative + precision in the computed singular values. + If it is negative, abs(TOLMUL*EPS*sigma_max) is the + desired absolute accuracy in the computed singular + values (corresponds to relative accuracy + abs(TOLMUL*EPS) in the largest singular value. + abs(TOLMUL) should be between 1 and 1/EPS, and preferably + between 10 (for fast convergence) and .1/EPS + (for there to be some accuracy in the results). + Default is to lose at either one eighth or 2 of the + available decimal digits in each computed singular value + (whichever is smaller). + + MAXITR INTEGER, default = 6 + MAXITR controls the maximum number of passes of the + algorithm through its inner loop. The algorithms stops + (and so fails to converge) if the number of passes + through the inner loop exceeds MAXITR*N**2. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + lower = lsame_(uplo, "L"); + if (! lsame_(uplo, "U") && ! lower) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ncvt < 0) { + *info = -3; + } else if (*nru < 0) { + *info = -4; + } else if (*ncc < 0) { + *info = -5; + } else if (*ncvt == 0 && *ldvt < 1 || *ncvt > 0 && *ldvt < max(1,*n)) { + *info = -9; + } else if (*ldu < max(1,*nru)) { + *info = -11; + } else if (*ncc == 0 && *ldc < 1 || *ncc > 0 && *ldc < max(1,*n)) { + *info = -13; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DBDSQR", &i__1); + return 0; + } + if (*n == 0) { + return 0; + } + if (*n == 1) { + goto L160; + } + +/* ROTATE is true if any singular vectors desired, false otherwise */ + + rotate = *ncvt > 0 || *nru > 0 || *ncc > 0; + +/* If no singular vectors desired, use qd algorithm */ + + if (! rotate) { + dlasq1_(n, &d__[1], &e[1], &work[1], info); + return 0; + } + + nm1 = *n - 1; + nm12 = nm1 + nm1; + nm13 = nm12 + nm1; + idir = 0; + +/* Get machine constants */ + + eps = EPSILON; + unfl = SAFEMINIMUM; + +/* + If matrix lower bidiagonal, rotate to be upper bidiagonal + by applying Givens rotations on the left +*/ + + if (lower) { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + dlartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + work[i__] = cs; + work[nm1 + i__] = sn; +/* L10: */ + } + +/* Update singular vectors if desired */ + + if (*nru > 0) { + dlasr_("R", "V", "F", nru, n, &work[1], &work[*n], &u[u_offset], + ldu); + } + if (*ncc > 0) { + dlasr_("L", "V", "F", n, ncc, &work[1], &work[*n], &c__[c_offset], + ldc); + } + } + +/* + Compute singular values to relative accuracy TOL + (By setting TOL to be negative, algorithm will compute + singular values to absolute accuracy ABS(TOL)*norm(input matrix)) + + Computing MAX + Computing MIN +*/ + d__3 = 100., d__4 = pow_dd(&eps, &c_b94); + d__1 = 10., d__2 = min(d__3,d__4); + tolmul = max(d__1,d__2); + tol = tolmul * eps; + +/* Compute approximate maximum, minimum singular values */ + + smax = 0.; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__2 = smax, d__3 = (d__1 = d__[i__], abs(d__1)); + smax = max(d__2,d__3); +/* L20: */ + } + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__2 = smax, d__3 = (d__1 = e[i__], abs(d__1)); + smax = max(d__2,d__3); +/* L30: */ + } + sminl = 0.; + if (tol >= 0.) { + +/* Relative accuracy desired */ + + sminoa = abs(d__[1]); + if (sminoa == 0.) { + goto L50; + } + mu = sminoa; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + mu = (d__2 = d__[i__], abs(d__2)) * (mu / (mu + (d__1 = e[i__ - 1] + , abs(d__1)))); + sminoa = min(sminoa,mu); + if (sminoa == 0.) { + goto L50; + } +/* L40: */ + } +L50: + sminoa /= sqrt((doublereal) (*n)); +/* Computing MAX */ + d__1 = tol * sminoa, d__2 = *n * 6 * *n * unfl; + thresh = max(d__1,d__2); + } else { + +/* + Absolute accuracy desired + + Computing MAX +*/ + d__1 = abs(tol) * smax, d__2 = *n * 6 * *n * unfl; + thresh = max(d__1,d__2); + } + +/* + Prepare for main iteration loop for the singular values + (MAXIT is the maximum number of passes through the inner + loop permitted before nonconvergence signalled.) +*/ + + maxit = *n * 6 * *n; + iter = 0; + oldll = -1; + oldm = -1; + +/* M points to last element of unconverged part of matrix */ + + m = *n; + +/* Begin main iteration loop */ + +L60: + +/* Check for convergence or exceeding iteration count */ + + if (m <= 1) { + goto L160; + } + if (iter > maxit) { + goto L200; + } + +/* Find diagonal block of matrix to work on */ + + if (tol < 0. && (d__1 = d__[m], abs(d__1)) <= thresh) { + d__[m] = 0.; + } + smax = (d__1 = d__[m], abs(d__1)); + smin = smax; + i__1 = m - 1; + for (lll = 1; lll <= i__1; ++lll) { + ll = m - lll; + abss = (d__1 = d__[ll], abs(d__1)); + abse = (d__1 = e[ll], abs(d__1)); + if (tol < 0. && abss <= thresh) { + d__[ll] = 0.; + } + if (abse <= thresh) { + goto L80; + } + smin = min(smin,abss); +/* Computing MAX */ + d__1 = max(smax,abss); + smax = max(d__1,abse); +/* L70: */ + } + ll = 0; + goto L90; +L80: + e[ll] = 0.; + +/* Matrix splits since E(LL) = 0 */ + + if (ll == m - 1) { + +/* Convergence of bottom singular value, return to top of loop */ + + --m; + goto L60; + } +L90: + ++ll; + +/* E(LL) through E(M-1) are nonzero, E(LL-1) is zero */ + + if (ll == m - 1) { + +/* 2 by 2 block, handle separately */ + + dlasv2_(&d__[m - 1], &e[m - 1], &d__[m], &sigmn, &sigmx, &sinr, &cosr, + &sinl, &cosl); + d__[m - 1] = sigmx; + e[m - 1] = 0.; + d__[m] = sigmn; + +/* Compute singular vectors, if desired */ + + if (*ncvt > 0) { + drot_(ncvt, &vt[m - 1 + vt_dim1], ldvt, &vt[m + vt_dim1], ldvt, & + cosr, &sinr); + } + if (*nru > 0) { + drot_(nru, &u[(m - 1) * u_dim1 + 1], &c__1, &u[m * u_dim1 + 1], & + c__1, &cosl, &sinl); + } + if (*ncc > 0) { + drot_(ncc, &c__[m - 1 + c_dim1], ldc, &c__[m + c_dim1], ldc, & + cosl, &sinl); + } + m += -2; + goto L60; + } + +/* + If working on new submatrix, choose shift direction + (from larger end diagonal element towards smaller) +*/ + + if (ll > oldm || m < oldll) { + if ((d__1 = d__[ll], abs(d__1)) >= (d__2 = d__[m], abs(d__2))) { + +/* Chase bulge from top (big end) to bottom (small end) */ + + idir = 1; + } else { + +/* Chase bulge from bottom (big end) to top (small end) */ + + idir = 2; + } + } + +/* Apply convergence tests */ + + if (idir == 1) { + +/* + Run convergence test in forward direction + First apply standard test to bottom of matrix +*/ + + if ((d__2 = e[m - 1], abs(d__2)) <= abs(tol) * (d__1 = d__[m], abs( + d__1)) || tol < 0. && (d__3 = e[m - 1], abs(d__3)) <= thresh) + { + e[m - 1] = 0.; + goto L60; + } + + if (tol >= 0.) { + +/* + If relative accuracy desired, + apply convergence criterion forward +*/ + + mu = (d__1 = d__[ll], abs(d__1)); + sminl = mu; + i__1 = m - 1; + for (lll = ll; lll <= i__1; ++lll) { + if ((d__1 = e[lll], abs(d__1)) <= tol * mu) { + e[lll] = 0.; + goto L60; + } + mu = (d__2 = d__[lll + 1], abs(d__2)) * (mu / (mu + (d__1 = e[ + lll], abs(d__1)))); + sminl = min(sminl,mu); +/* L100: */ + } + } + + } else { + +/* + Run convergence test in backward direction + First apply standard test to top of matrix +*/ + + if ((d__2 = e[ll], abs(d__2)) <= abs(tol) * (d__1 = d__[ll], abs(d__1) + ) || tol < 0. && (d__3 = e[ll], abs(d__3)) <= thresh) { + e[ll] = 0.; + goto L60; + } + + if (tol >= 0.) { + +/* + If relative accuracy desired, + apply convergence criterion backward +*/ + + mu = (d__1 = d__[m], abs(d__1)); + sminl = mu; + i__1 = ll; + for (lll = m - 1; lll >= i__1; --lll) { + if ((d__1 = e[lll], abs(d__1)) <= tol * mu) { + e[lll] = 0.; + goto L60; + } + mu = (d__2 = d__[lll], abs(d__2)) * (mu / (mu + (d__1 = e[lll] + , abs(d__1)))); + sminl = min(sminl,mu); +/* L110: */ + } + } + } + oldll = ll; + oldm = m; + +/* + Compute shift. First, test if shifting would ruin relative + accuracy, and if so set the shift to zero. + + Computing MAX +*/ + d__1 = eps, d__2 = tol * .01; + if (tol >= 0. && *n * tol * (sminl / smax) <= max(d__1,d__2)) { + +/* Use a zero shift to avoid loss of relative accuracy */ + + shift = 0.; + } else { + +/* Compute the shift from 2-by-2 block at end of matrix */ + + if (idir == 1) { + sll = (d__1 = d__[ll], abs(d__1)); + dlas2_(&d__[m - 1], &e[m - 1], &d__[m], &shift, &r__); + } else { + sll = (d__1 = d__[m], abs(d__1)); + dlas2_(&d__[ll], &e[ll], &d__[ll + 1], &shift, &r__); + } + +/* Test if shift negligible, and if so set to zero */ + + if (sll > 0.) { +/* Computing 2nd power */ + d__1 = shift / sll; + if (d__1 * d__1 < eps) { + shift = 0.; + } + } + } + +/* Increment iteration count */ + + iter = iter + m - ll; + +/* If SHIFT = 0, do simplified QR iteration */ + + if (shift == 0.) { + if (idir == 1) { + +/* + Chase bulge from top to bottom + Save cosines and sines for later singular vector updates +*/ + + cs = 1.; + oldcs = 1.; + i__1 = m - 1; + for (i__ = ll; i__ <= i__1; ++i__) { + d__1 = d__[i__] * cs; + dlartg_(&d__1, &e[i__], &cs, &sn, &r__); + if (i__ > ll) { + e[i__ - 1] = oldsn * r__; + } + d__1 = oldcs * r__; + d__2 = d__[i__ + 1] * sn; + dlartg_(&d__1, &d__2, &oldcs, &oldsn, &d__[i__]); + work[i__ - ll + 1] = cs; + work[i__ - ll + 1 + nm1] = sn; + work[i__ - ll + 1 + nm12] = oldcs; + work[i__ - ll + 1 + nm13] = oldsn; +/* L120: */ + } + h__ = d__[m] * cs; + d__[m] = h__ * oldcs; + e[m - 1] = h__ * oldsn; + +/* Update singular vectors */ + + if (*ncvt > 0) { + i__1 = m - ll + 1; + dlasr_("L", "V", "F", &i__1, ncvt, &work[1], &work[*n], &vt[ + ll + vt_dim1], ldvt); + } + if (*nru > 0) { + i__1 = m - ll + 1; + dlasr_("R", "V", "F", nru, &i__1, &work[nm12 + 1], &work[nm13 + + 1], &u[ll * u_dim1 + 1], ldu); + } + if (*ncc > 0) { + i__1 = m - ll + 1; + dlasr_("L", "V", "F", &i__1, ncc, &work[nm12 + 1], &work[nm13 + + 1], &c__[ll + c_dim1], ldc); + } + +/* Test convergence */ + + if ((d__1 = e[m - 1], abs(d__1)) <= thresh) { + e[m - 1] = 0.; + } + + } else { + +/* + Chase bulge from bottom to top + Save cosines and sines for later singular vector updates +*/ + + cs = 1.; + oldcs = 1.; + i__1 = ll + 1; + for (i__ = m; i__ >= i__1; --i__) { + d__1 = d__[i__] * cs; + dlartg_(&d__1, &e[i__ - 1], &cs, &sn, &r__); + if (i__ < m) { + e[i__] = oldsn * r__; + } + d__1 = oldcs * r__; + d__2 = d__[i__ - 1] * sn; + dlartg_(&d__1, &d__2, &oldcs, &oldsn, &d__[i__]); + work[i__ - ll] = cs; + work[i__ - ll + nm1] = -sn; + work[i__ - ll + nm12] = oldcs; + work[i__ - ll + nm13] = -oldsn; +/* L130: */ + } + h__ = d__[ll] * cs; + d__[ll] = h__ * oldcs; + e[ll] = h__ * oldsn; + +/* Update singular vectors */ + + if (*ncvt > 0) { + i__1 = m - ll + 1; + dlasr_("L", "V", "B", &i__1, ncvt, &work[nm12 + 1], &work[ + nm13 + 1], &vt[ll + vt_dim1], ldvt); + } + if (*nru > 0) { + i__1 = m - ll + 1; + dlasr_("R", "V", "B", nru, &i__1, &work[1], &work[*n], &u[ll * + u_dim1 + 1], ldu); + } + if (*ncc > 0) { + i__1 = m - ll + 1; + dlasr_("L", "V", "B", &i__1, ncc, &work[1], &work[*n], &c__[ + ll + c_dim1], ldc); + } + +/* Test convergence */ + + if ((d__1 = e[ll], abs(d__1)) <= thresh) { + e[ll] = 0.; + } + } + } else { + +/* Use nonzero shift */ + + if (idir == 1) { + +/* + Chase bulge from top to bottom + Save cosines and sines for later singular vector updates +*/ + + f = ((d__1 = d__[ll], abs(d__1)) - shift) * (d_sign(&c_b15, &d__[ + ll]) + shift / d__[ll]); + g = e[ll]; + i__1 = m - 1; + for (i__ = ll; i__ <= i__1; ++i__) { + dlartg_(&f, &g, &cosr, &sinr, &r__); + if (i__ > ll) { + e[i__ - 1] = r__; + } + f = cosr * d__[i__] + sinr * e[i__]; + e[i__] = cosr * e[i__] - sinr * d__[i__]; + g = sinr * d__[i__ + 1]; + d__[i__ + 1] = cosr * d__[i__ + 1]; + dlartg_(&f, &g, &cosl, &sinl, &r__); + d__[i__] = r__; + f = cosl * e[i__] + sinl * d__[i__ + 1]; + d__[i__ + 1] = cosl * d__[i__ + 1] - sinl * e[i__]; + if (i__ < m - 1) { + g = sinl * e[i__ + 1]; + e[i__ + 1] = cosl * e[i__ + 1]; + } + work[i__ - ll + 1] = cosr; + work[i__ - ll + 1 + nm1] = sinr; + work[i__ - ll + 1 + nm12] = cosl; + work[i__ - ll + 1 + nm13] = sinl; +/* L140: */ + } + e[m - 1] = f; + +/* Update singular vectors */ + + if (*ncvt > 0) { + i__1 = m - ll + 1; + dlasr_("L", "V", "F", &i__1, ncvt, &work[1], &work[*n], &vt[ + ll + vt_dim1], ldvt); + } + if (*nru > 0) { + i__1 = m - ll + 1; + dlasr_("R", "V", "F", nru, &i__1, &work[nm12 + 1], &work[nm13 + + 1], &u[ll * u_dim1 + 1], ldu); + } + if (*ncc > 0) { + i__1 = m - ll + 1; + dlasr_("L", "V", "F", &i__1, ncc, &work[nm12 + 1], &work[nm13 + + 1], &c__[ll + c_dim1], ldc); + } + +/* Test convergence */ + + if ((d__1 = e[m - 1], abs(d__1)) <= thresh) { + e[m - 1] = 0.; + } + + } else { + +/* + Chase bulge from bottom to top + Save cosines and sines for later singular vector updates +*/ + + f = ((d__1 = d__[m], abs(d__1)) - shift) * (d_sign(&c_b15, &d__[m] + ) + shift / d__[m]); + g = e[m - 1]; + i__1 = ll + 1; + for (i__ = m; i__ >= i__1; --i__) { + dlartg_(&f, &g, &cosr, &sinr, &r__); + if (i__ < m) { + e[i__] = r__; + } + f = cosr * d__[i__] + sinr * e[i__ - 1]; + e[i__ - 1] = cosr * e[i__ - 1] - sinr * d__[i__]; + g = sinr * d__[i__ - 1]; + d__[i__ - 1] = cosr * d__[i__ - 1]; + dlartg_(&f, &g, &cosl, &sinl, &r__); + d__[i__] = r__; + f = cosl * e[i__ - 1] + sinl * d__[i__ - 1]; + d__[i__ - 1] = cosl * d__[i__ - 1] - sinl * e[i__ - 1]; + if (i__ > ll + 1) { + g = sinl * e[i__ - 2]; + e[i__ - 2] = cosl * e[i__ - 2]; + } + work[i__ - ll] = cosr; + work[i__ - ll + nm1] = -sinr; + work[i__ - ll + nm12] = cosl; + work[i__ - ll + nm13] = -sinl; +/* L150: */ + } + e[ll] = f; + +/* Test convergence */ + + if ((d__1 = e[ll], abs(d__1)) <= thresh) { + e[ll] = 0.; + } + +/* Update singular vectors if desired */ + + if (*ncvt > 0) { + i__1 = m - ll + 1; + dlasr_("L", "V", "B", &i__1, ncvt, &work[nm12 + 1], &work[ + nm13 + 1], &vt[ll + vt_dim1], ldvt); + } + if (*nru > 0) { + i__1 = m - ll + 1; + dlasr_("R", "V", "B", nru, &i__1, &work[1], &work[*n], &u[ll * + u_dim1 + 1], ldu); + } + if (*ncc > 0) { + i__1 = m - ll + 1; + dlasr_("L", "V", "B", &i__1, ncc, &work[1], &work[*n], &c__[ + ll + c_dim1], ldc); + } + } + } + +/* QR iteration finished, go back and check convergence */ + + goto L60; + +/* All singular values converged, so make them positive */ + +L160: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if (d__[i__] < 0.) { + d__[i__] = -d__[i__]; + +/* Change sign of singular vectors, if desired */ + + if (*ncvt > 0) { + dscal_(ncvt, &c_b151, &vt[i__ + vt_dim1], ldvt); + } + } +/* L170: */ + } + +/* + Sort the singular values into decreasing order (insertion sort on + singular values, but only one transposition per singular vector) +*/ + + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Scan for smallest D(I) */ + + isub = 1; + smin = d__[1]; + i__2 = *n + 1 - i__; + for (j = 2; j <= i__2; ++j) { + if (d__[j] <= smin) { + isub = j; + smin = d__[j]; + } +/* L180: */ + } + if (isub != *n + 1 - i__) { + +/* Swap singular values and vectors */ + + d__[isub] = d__[*n + 1 - i__]; + d__[*n + 1 - i__] = smin; + if (*ncvt > 0) { + dswap_(ncvt, &vt[isub + vt_dim1], ldvt, &vt[*n + 1 - i__ + + vt_dim1], ldvt); + } + if (*nru > 0) { + dswap_(nru, &u[isub * u_dim1 + 1], &c__1, &u[(*n + 1 - i__) * + u_dim1 + 1], &c__1); + } + if (*ncc > 0) { + dswap_(ncc, &c__[isub + c_dim1], ldc, &c__[*n + 1 - i__ + + c_dim1], ldc); + } + } +/* L190: */ + } + goto L220; + +/* Maximum number of iterations exceeded, failure to converge */ + +L200: + *info = 0; + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (e[i__] != 0.) { + ++(*info); + } +/* L210: */ + } +L220: + return 0; + +/* End of DBDSQR */ + +} /* dbdsqr_ */ + +/* Subroutine */ int dgebak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, doublereal *scale, integer *m, doublereal *v, integer * + ldv, integer *info) +{ + /* System generated locals */ + integer v_dim1, v_offset, i__1; + + /* Local variables */ + static integer i__, k; + static doublereal s; + static integer ii; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dswap_(integer *, doublereal *, integer *, + doublereal *, integer *); + static logical leftv; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical rightv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGEBAK forms the right or left eigenvectors of a real general matrix + by backward transformation on the computed eigenvectors of the + balanced matrix output by DGEBAL. + + Arguments + ========= + + JOB (input) CHARACTER*1 + Specifies the type of backward transformation required: + = 'N', do nothing, return immediately; + = 'P', do backward transformation for permutation only; + = 'S', do backward transformation for scaling only; + = 'B', do backward transformations for both permutation and + scaling. + JOB must be the same as the argument JOB supplied to DGEBAL. + + SIDE (input) CHARACTER*1 + = 'R': V contains right eigenvectors; + = 'L': V contains left eigenvectors. + + N (input) INTEGER + The number of rows of the matrix V. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + The integers ILO and IHI determined by DGEBAL. + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + SCALE (input) DOUBLE PRECISION array, dimension (N) + Details of the permutation and scaling factors, as returned + by DGEBAL. + + M (input) INTEGER + The number of columns of the matrix V. M >= 0. + + V (input/output) DOUBLE PRECISION array, dimension (LDV,M) + On entry, the matrix of right or left eigenvectors to be + transformed, as returned by DHSEIN or DTREVC. + On exit, V is overwritten by the transformed eigenvectors. + + LDV (input) INTEGER + The leading dimension of the array V. LDV >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Decode and Test the input parameters +*/ + + /* Parameter adjustments */ + --scale; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + + /* Function Body */ + rightv = lsame_(side, "R"); + leftv = lsame_(side, "L"); + + *info = 0; + if (! lsame_(job, "N") && ! lsame_(job, "P") && ! lsame_(job, "S") + && ! lsame_(job, "B")) { + *info = -1; + } else if (! rightv && ! leftv) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -4; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -5; + } else if (*m < 0) { + *info = -7; + } else if (*ldv < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGEBAK", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*m == 0) { + return 0; + } + if (lsame_(job, "N")) { + return 0; + } + + if (*ilo == *ihi) { + goto L30; + } + +/* Backward balance */ + + if (lsame_(job, "S") || lsame_(job, "B")) { + + if (rightv) { + i__1 = *ihi; + for (i__ = *ilo; i__ <= i__1; ++i__) { + s = scale[i__]; + dscal_(m, &s, &v[i__ + v_dim1], ldv); +/* L10: */ + } + } + + if (leftv) { + i__1 = *ihi; + for (i__ = *ilo; i__ <= i__1; ++i__) { + s = 1. / scale[i__]; + dscal_(m, &s, &v[i__ + v_dim1], ldv); +/* L20: */ + } + } + + } + +/* + Backward permutation + + For I = ILO-1 step -1 until 1, + IHI+1 step 1 until N do -- +*/ + +L30: + if (lsame_(job, "P") || lsame_(job, "B")) { + if (rightv) { + i__1 = *n; + for (ii = 1; ii <= i__1; ++ii) { + i__ = ii; + if (i__ >= *ilo && i__ <= *ihi) { + goto L40; + } + if (i__ < *ilo) { + i__ = *ilo - ii; + } + k = (integer) scale[i__]; + if (k == i__) { + goto L40; + } + dswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv); +L40: + ; + } + } + + if (leftv) { + i__1 = *n; + for (ii = 1; ii <= i__1; ++ii) { + i__ = ii; + if (i__ >= *ilo && i__ <= *ihi) { + goto L50; + } + if (i__ < *ilo) { + i__ = *ilo - ii; + } + k = (integer) scale[i__]; + if (k == i__) { + goto L50; + } + dswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv); +L50: + ; + } + } + } + + return 0; + +/* End of DGEBAK */ + +} /* dgebak_ */ + +/* Subroutine */ int dgebal_(char *job, integer *n, doublereal *a, integer * + lda, integer *ilo, integer *ihi, doublereal *scale, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal c__, f, g; + static integer i__, j, k, l, m; + static doublereal r__, s, ca, ra; + static integer ica, ira, iexc; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dswap_(integer *, doublereal *, integer *, + doublereal *, integer *); + static doublereal sfmin1, sfmin2, sfmax1, sfmax2; + + extern integer idamax_(integer *, doublereal *, integer *); + extern logical disnan_(doublereal *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical noconv; + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DGEBAL balances a general real matrix A. This involves, first, + permuting A by a similarity transformation to isolate eigenvalues + in the first 1 to ILO-1 and last IHI+1 to N elements on the + diagonal; and second, applying a diagonal similarity transformation + to rows and columns ILO to IHI to make the rows and columns as + close in norm as possible. Both steps are optional. + + Balancing may reduce the 1-norm of the matrix, and improve the + accuracy of the computed eigenvalues and/or eigenvectors. + + Arguments + ========= + + JOB (input) CHARACTER*1 + Specifies the operations to be performed on A: + = 'N': none: simply set ILO = 1, IHI = N, SCALE(I) = 1.0 + for i = 1,...,N; + = 'P': permute only; + = 'S': scale only; + = 'B': both permute and scale. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the input matrix A. + On exit, A is overwritten by the balanced matrix. + If JOB = 'N', A is not referenced. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + ILO (output) INTEGER + IHI (output) INTEGER + ILO and IHI are set to integers such that on exit + A(i,j) = 0 if i > j and j = 1,...,ILO-1 or I = IHI+1,...,N. + If JOB = 'N' or 'S', ILO = 1 and IHI = N. + + SCALE (output) DOUBLE PRECISION array, dimension (N) + Details of the permutations and scaling factors applied to + A. If P(j) is the index of the row and column interchanged + with row and column j and D(j) is the scaling factor + applied to row and column j, then + SCALE(j) = P(j) for j = 1,...,ILO-1 + = D(j) for j = ILO,...,IHI + = P(j) for j = IHI+1,...,N. + The order in which the interchanges are made is N to IHI+1, + then 1 to ILO-1. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The permutations consist of row and column interchanges which put + the matrix in the form + + ( T1 X Y ) + P A P = ( 0 B Z ) + ( 0 0 T2 ) + + where T1 and T2 are upper triangular matrices whose eigenvalues lie + along the diagonal. The column indices ILO and IHI mark the starting + and ending columns of the submatrix B. Balancing consists of applying + a diagonal similarity transformation inv(D) * B * D to make the + 1-norms of each row of B and its corresponding column nearly equal. + The output matrix is + + ( T1 X*D Y ) + ( 0 inv(D)*B*D inv(D)*Z ). + ( 0 0 T2 ) + + Information about the permutations P and the diagonal matrix D is + returned in the vector SCALE. + + This subroutine is based on the EISPACK routine BALANC. + + Modified by Tzu-Yi Chen, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --scale; + + /* Function Body */ + *info = 0; + if (! lsame_(job, "N") && ! lsame_(job, "P") && ! lsame_(job, "S") + && ! lsame_(job, "B")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGEBAL", &i__1); + return 0; + } + + k = 1; + l = *n; + + if (*n == 0) { + goto L210; + } + + if (lsame_(job, "N")) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + scale[i__] = 1.; +/* L10: */ + } + goto L210; + } + + if (lsame_(job, "S")) { + goto L120; + } + +/* Permutation to isolate eigenvalues if possible */ + + goto L50; + +/* Row and column exchange. */ + +L20: + scale[m] = (doublereal) j; + if (j == m) { + goto L30; + } + + dswap_(&l, &a[j * a_dim1 + 1], &c__1, &a[m * a_dim1 + 1], &c__1); + i__1 = *n - k + 1; + dswap_(&i__1, &a[j + k * a_dim1], lda, &a[m + k * a_dim1], lda); + +L30: + switch (iexc) { + case 1: goto L40; + case 2: goto L80; + } + +/* Search for rows isolating an eigenvalue and push them down. */ + +L40: + if (l == 1) { + goto L210; + } + --l; + +L50: + for (j = l; j >= 1; --j) { + + i__1 = l; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__ == j) { + goto L60; + } + if (a[j + i__ * a_dim1] != 0.) { + goto L70; + } +L60: + ; + } + + m = l; + iexc = 1; + goto L20; +L70: + ; + } + + goto L90; + +/* Search for columns isolating an eigenvalue and push them left. */ + +L80: + ++k; + +L90: + i__1 = l; + for (j = k; j <= i__1; ++j) { + + i__2 = l; + for (i__ = k; i__ <= i__2; ++i__) { + if (i__ == j) { + goto L100; + } + if (a[i__ + j * a_dim1] != 0.) { + goto L110; + } +L100: + ; + } + + m = k; + iexc = 2; + goto L20; +L110: + ; + } + +L120: + i__1 = l; + for (i__ = k; i__ <= i__1; ++i__) { + scale[i__] = 1.; +/* L130: */ + } + + if (lsame_(job, "P")) { + goto L210; + } + +/* + Balance the submatrix in rows K to L. + + Iterative loop for norm reduction +*/ + + sfmin1 = SAFEMINIMUM / PRECISION; + sfmax1 = 1. / sfmin1; + sfmin2 = sfmin1 * 2.; + sfmax2 = 1. / sfmin2; +L140: + noconv = FALSE_; + + i__1 = l; + for (i__ = k; i__ <= i__1; ++i__) { + c__ = 0.; + r__ = 0.; + + i__2 = l; + for (j = k; j <= i__2; ++j) { + if (j == i__) { + goto L150; + } + c__ += (d__1 = a[j + i__ * a_dim1], abs(d__1)); + r__ += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +L150: + ; + } + ica = idamax_(&l, &a[i__ * a_dim1 + 1], &c__1); + ca = (d__1 = a[ica + i__ * a_dim1], abs(d__1)); + i__2 = *n - k + 1; + ira = idamax_(&i__2, &a[i__ + k * a_dim1], lda); + ra = (d__1 = a[i__ + (ira + k - 1) * a_dim1], abs(d__1)); + +/* Guard against zero C or R due to underflow. */ + + if (c__ == 0. || r__ == 0.) { + goto L200; + } + g = r__ / 2.; + f = 1.; + s = c__ + r__; +L160: +/* Computing MAX */ + d__1 = max(f,c__); +/* Computing MIN */ + d__2 = min(r__,g); + if (c__ >= g || max(d__1,ca) >= sfmax2 || min(d__2,ra) <= sfmin2) { + goto L170; + } + d__1 = c__ + f + ca + r__ + g + ra; + if (disnan_(&d__1)) { + +/* Exit if NaN to avoid infinite loop */ + + *info = -3; + i__2 = -(*info); + xerbla_("DGEBAL", &i__2); + return 0; + } + f *= 2.; + c__ *= 2.; + ca *= 2.; + r__ /= 2.; + g /= 2.; + ra /= 2.; + goto L160; + +L170: + g = c__ / 2.; +L180: +/* Computing MIN */ + d__1 = min(f,c__), d__1 = min(d__1,g); + if (g < r__ || max(r__,ra) >= sfmax2 || min(d__1,ca) <= sfmin2) { + goto L190; + } + f /= 2.; + c__ /= 2.; + g /= 2.; + ca /= 2.; + r__ *= 2.; + ra *= 2.; + goto L180; + +/* Now balance. */ + +L190: + if (c__ + r__ >= s * .95) { + goto L200; + } + if (f < 1. && scale[i__] < 1.) { + if (f * scale[i__] <= sfmin1) { + goto L200; + } + } + if (f > 1. && scale[i__] > 1.) { + if (scale[i__] >= sfmax1 / f) { + goto L200; + } + } + g = 1. / f; + scale[i__] *= f; + noconv = TRUE_; + + i__2 = *n - k + 1; + dscal_(&i__2, &g, &a[i__ + k * a_dim1], lda); + dscal_(&l, &f, &a[i__ * a_dim1 + 1], &c__1); + +L200: + ; + } + + if (noconv) { + goto L140; + } + +L210: + *ilo = k; + *ihi = l; + + return 0; + +/* End of DGEBAL */ + +} /* dgebal_ */ + +/* Subroutine */ int dgebd2_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *d__, doublereal *e, doublereal *tauq, doublereal * + taup, doublereal *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *), dlarfg_(integer *, doublereal *, + doublereal *, integer *, doublereal *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGEBD2 reduces a real general m by n matrix A to upper or lower + bidiagonal form B by an orthogonal transformation: Q' * A * P = B. + + If m >= n, B is upper bidiagonal; if m < n, B is lower bidiagonal. + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. M >= 0. + + N (input) INTEGER + The number of columns in the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the m by n general matrix to be reduced. + On exit, + if m >= n, the diagonal and the first superdiagonal are + overwritten with the upper bidiagonal matrix B; the + elements below the diagonal, with the array TAUQ, represent + the orthogonal matrix Q as a product of elementary + reflectors, and the elements above the first superdiagonal, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors; + if m < n, the diagonal and the first subdiagonal are + overwritten with the lower bidiagonal matrix B; the + elements below the first subdiagonal, with the array TAUQ, + represent the orthogonal matrix Q as a product of + elementary reflectors, and the elements above the diagonal, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) DOUBLE PRECISION array, dimension (min(M,N)) + The diagonal elements of the bidiagonal matrix B: + D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (min(M,N)-1) + The off-diagonal elements of the bidiagonal matrix B: + if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1; + if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1. + + TAUQ (output) DOUBLE PRECISION array dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix Q. See Further Details. + + TAUP (output) DOUBLE PRECISION array, dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix P. See Further Details. + + WORK (workspace) DOUBLE PRECISION array, dimension (max(M,N)) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + If m >= n, + + Q = H(1) H(2) . . . H(n) and P = G(1) G(2) . . . G(n-1) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors; + v(1:i-1) = 0, v(i) = 1, and v(i+1:m) is stored on exit in A(i+1:m,i); + u(1:i) = 0, u(i+1) = 1, and u(i+2:n) is stored on exit in A(i,i+2:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, + + Q = H(1) H(2) . . . H(m-1) and P = G(1) G(2) . . . G(m) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors; + v(1:i) = 0, v(i+1) = 1, and v(i+2:m) is stored on exit in A(i+2:m,i); + u(1:i-1) = 0, u(i) = 1, and u(i+1:n) is stored on exit in A(i,i+1:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + The contents of A on exit are illustrated by the following examples: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) + ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) + ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) + ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) + ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) + ( v1 v2 v3 v4 v5 ) + + where d and e denote diagonal and off-diagonal elements of B, vi + denotes an element of the vector defining H(i), and ui an element of + the vector defining G(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info < 0) { + i__1 = -(*info); + xerbla_("DGEBD2", &i__1); + return 0; + } + + if (*m >= *n) { + +/* Reduce to upper bidiagonal form */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ + + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + dlarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * + a_dim1], &c__1, &tauq[i__]); + d__[i__] = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.; + +/* Apply H(i) to A(i:m,i+1:n) from the left */ + + if (i__ < *n) { + i__2 = *m - i__ + 1; + i__3 = *n - i__; + dlarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, & + tauq[i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1] + ); + } + a[i__ + i__ * a_dim1] = d__[i__]; + + if (i__ < *n) { + +/* + Generate elementary reflector G(i) to annihilate + A(i,i+2:n) +*/ + + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + dlarfg_(&i__2, &a[i__ + (i__ + 1) * a_dim1], &a[i__ + min( + i__3,*n) * a_dim1], lda, &taup[i__]); + e[i__] = a[i__ + (i__ + 1) * a_dim1]; + a[i__ + (i__ + 1) * a_dim1] = 1.; + +/* Apply G(i) to A(i+1:m,i+1:n) from the right */ + + i__2 = *m - i__; + i__3 = *n - i__; + dlarf_("Right", &i__2, &i__3, &a[i__ + (i__ + 1) * a_dim1], + lda, &taup[i__], &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &work[1]); + a[i__ + (i__ + 1) * a_dim1] = e[i__]; + } else { + taup[i__] = 0.; + } +/* L10: */ + } + } else { + +/* Reduce to lower bidiagonal form */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector G(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + dlarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[i__ + min(i__3,*n) * + a_dim1], lda, &taup[i__]); + d__[i__] = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.; + +/* Apply G(i) to A(i+1:m,i:n) from the right */ + + if (i__ < *m) { + i__2 = *m - i__; + i__3 = *n - i__ + 1; + dlarf_("Right", &i__2, &i__3, &a[i__ + i__ * a_dim1], lda, & + taup[i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + a[i__ + i__ * a_dim1] = d__[i__]; + + if (i__ < *m) { + +/* + Generate elementary reflector H(i) to annihilate + A(i+2:m,i) +*/ + + i__2 = *m - i__; +/* Computing MIN */ + i__3 = i__ + 2; + dlarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*m) + + i__ * a_dim1], &c__1, &tauq[i__]); + e[i__] = a[i__ + 1 + i__ * a_dim1]; + a[i__ + 1 + i__ * a_dim1] = 1.; + +/* Apply H(i) to A(i+1:m,i+1:n) from the left */ + + i__2 = *m - i__; + i__3 = *n - i__; + dlarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], & + c__1, &tauq[i__], &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &work[1]); + a[i__ + 1 + i__ * a_dim1] = e[i__]; + } else { + tauq[i__] = 0.; + } +/* L20: */ + } + } + return 0; + +/* End of DGEBD2 */ + +} /* dgebd2_ */ + +/* Subroutine */ int dgebrd_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *d__, doublereal *e, doublereal *tauq, doublereal * + taup, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, nb, nx; + static doublereal ws; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer nbmin, iinfo, minmn; + extern /* Subroutine */ int dgebd2_(integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *), dlabrd_(integer *, integer *, integer * + , doublereal *, integer *, doublereal *, doublereal *, doublereal + *, doublereal *, doublereal *, integer *, doublereal *, integer *) + , xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwrkx, ldwrky, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGEBRD reduces a general real M-by-N matrix A to upper or lower + bidiagonal form B by an orthogonal transformation: Q**T * A * P = B. + + If m >= n, B is upper bidiagonal; if m < n, B is lower bidiagonal. + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. M >= 0. + + N (input) INTEGER + The number of columns in the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the M-by-N general matrix to be reduced. + On exit, + if m >= n, the diagonal and the first superdiagonal are + overwritten with the upper bidiagonal matrix B; the + elements below the diagonal, with the array TAUQ, represent + the orthogonal matrix Q as a product of elementary + reflectors, and the elements above the first superdiagonal, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors; + if m < n, the diagonal and the first subdiagonal are + overwritten with the lower bidiagonal matrix B; the + elements below the first subdiagonal, with the array TAUQ, + represent the orthogonal matrix Q as a product of + elementary reflectors, and the elements above the diagonal, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) DOUBLE PRECISION array, dimension (min(M,N)) + The diagonal elements of the bidiagonal matrix B: + D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (min(M,N)-1) + The off-diagonal elements of the bidiagonal matrix B: + if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1; + if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1. + + TAUQ (output) DOUBLE PRECISION array dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix Q. See Further Details. + + TAUP (output) DOUBLE PRECISION array, dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix P. See Further Details. + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. LWORK >= max(1,M,N). + For optimum performance LWORK >= (M+N)*NB, where NB + is the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + If m >= n, + + Q = H(1) H(2) . . . H(n) and P = G(1) G(2) . . . G(n-1) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors; + v(1:i-1) = 0, v(i) = 1, and v(i+1:m) is stored on exit in A(i+1:m,i); + u(1:i) = 0, u(i+1) = 1, and u(i+2:n) is stored on exit in A(i,i+2:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, + + Q = H(1) H(2) . . . H(m-1) and P = G(1) G(2) . . . G(m) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors; + v(1:i) = 0, v(i+1) = 1, and v(i+2:m) is stored on exit in A(i+2:m,i); + u(1:i-1) = 0, u(i) = 1, and u(i+1:n) is stored on exit in A(i,i+1:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + The contents of A on exit are illustrated by the following examples: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) + ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) + ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) + ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) + ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) + ( v1 v2 v3 v4 v5 ) + + where d and e denote diagonal and off-diagonal elements of B, vi + denotes an element of the vector defining H(i), and ui an element of + the vector defining G(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + --work; + + /* Function Body */ + *info = 0; +/* Computing MAX */ + i__1 = 1, i__2 = ilaenv_(&c__1, "DGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = max(i__1,i__2); + lwkopt = (*m + *n) * nb; + work[1] = (doublereal) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = max(1,*m); + if (*lwork < max(i__1,*n) && ! lquery) { + *info = -10; + } + } + if (*info < 0) { + i__1 = -(*info); + xerbla_("DGEBRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + minmn = min(*m,*n); + if (minmn == 0) { + work[1] = 1.; + return 0; + } + + ws = (doublereal) max(*m,*n); + ldwrkx = *m; + ldwrky = *n; + + if (nb > 1 && nb < minmn) { + +/* + Set the crossover point NX. + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "DGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + +/* Determine when to switch from blocked to unblocked code. */ + + if (nx < minmn) { + ws = (doublereal) ((*m + *n) * nb); + if ((doublereal) (*lwork) < ws) { + +/* + Not enough work space for the optimal NB, consider using + a smaller block size. +*/ + + nbmin = ilaenv_(&c__2, "DGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + if (*lwork >= (*m + *n) * nbmin) { + nb = *lwork / (*m + *n); + } else { + nb = 1; + nx = minmn; + } + } + } + } else { + nx = minmn; + } + + i__1 = minmn - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + +/* + Reduce rows and columns i:i+nb-1 to bidiagonal form and return + the matrices X and Y which are needed to update the unreduced + part of the matrix +*/ + + i__3 = *m - i__ + 1; + i__4 = *n - i__ + 1; + dlabrd_(&i__3, &i__4, &nb, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[ + i__], &tauq[i__], &taup[i__], &work[1], &ldwrkx, &work[ldwrkx + * nb + 1], &ldwrky); + +/* + Update the trailing submatrix A(i+nb:m,i+nb:n), using an update + of the form A := A - V*Y' - X*U' +*/ + + i__3 = *m - i__ - nb + 1; + i__4 = *n - i__ - nb + 1; + dgemm_("No transpose", "Transpose", &i__3, &i__4, &nb, &c_b151, &a[ + i__ + nb + i__ * a_dim1], lda, &work[ldwrkx * nb + nb + 1], & + ldwrky, &c_b15, &a[i__ + nb + (i__ + nb) * a_dim1], lda); + i__3 = *m - i__ - nb + 1; + i__4 = *n - i__ - nb + 1; + dgemm_("No transpose", "No transpose", &i__3, &i__4, &nb, &c_b151, & + work[nb + 1], &ldwrkx, &a[i__ + (i__ + nb) * a_dim1], lda, & + c_b15, &a[i__ + nb + (i__ + nb) * a_dim1], lda); + +/* Copy diagonal and off-diagonal elements of B back into A */ + + if (*m >= *n) { + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + a[j + j * a_dim1] = d__[j]; + a[j + (j + 1) * a_dim1] = e[j]; +/* L10: */ + } + } else { + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + a[j + j * a_dim1] = d__[j]; + a[j + 1 + j * a_dim1] = e[j]; +/* L20: */ + } + } +/* L30: */ + } + +/* Use unblocked code to reduce the remainder of the matrix */ + + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + dgebd2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], & + tauq[i__], &taup[i__], &work[1], &iinfo); + work[1] = ws; + return 0; + +/* End of DGEBRD */ + +} /* dgebrd_ */ + +/* Subroutine */ int dgeev_(char *jobvl, char *jobvr, integer *n, doublereal * + a, integer *lda, doublereal *wr, doublereal *wi, doublereal *vl, + integer *ldvl, doublereal *vr, integer *ldvr, doublereal *work, + integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, + i__2, i__3; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__, k; + static doublereal r__, cs, sn; + static integer ihi; + static doublereal scl; + static integer ilo; + static doublereal dum[1], eps; + static integer ibal; + static char side[1]; + static doublereal anrm; + static integer ierr, itau; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *); + static integer iwrk, nout; + extern doublereal dnrm2_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + extern doublereal dlapy2_(doublereal *, doublereal *); + extern /* Subroutine */ int dlabad_(doublereal *, doublereal *), dgebak_( + char *, char *, integer *, integer *, integer *, doublereal *, + integer *, doublereal *, integer *, integer *), + dgebal_(char *, integer *, doublereal *, integer *, integer *, + integer *, doublereal *, integer *); + static logical scalea; + + static doublereal cscale; + extern doublereal dlange_(char *, integer *, integer *, doublereal *, + integer *, doublereal *); + extern /* Subroutine */ int dgehrd_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + integer *), dlascl_(char *, integer *, integer *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + integer *); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dlacpy_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *), + dlartg_(doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *), xerbla_(char *, integer *); + static logical select[1]; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static doublereal bignum; + extern /* Subroutine */ int dorghr_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + integer *), dhseqr_(char *, char *, integer *, integer *, integer + *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, integer *, doublereal *, integer *, integer *), dtrevc_(char *, char *, logical *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *, integer *, integer *, doublereal *, integer *); + static integer minwrk, maxwrk; + static logical wantvl; + static doublereal smlnum; + static integer hswork; + static logical lquery, wantvr; + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGEEV computes for an N-by-N real nonsymmetric matrix A, the + eigenvalues and, optionally, the left and/or right eigenvectors. + + The right eigenvector v(j) of A satisfies + A * v(j) = lambda(j) * v(j) + where lambda(j) is its eigenvalue. + The left eigenvector u(j) of A satisfies + u(j)**H * A = lambda(j) * u(j)**H + where u(j)**H denotes the conjugate transpose of u(j). + + The computed eigenvectors are normalized to have Euclidean norm + equal to 1 and largest component real. + + Arguments + ========= + + JOBVL (input) CHARACTER*1 + = 'N': left eigenvectors of A are not computed; + = 'V': left eigenvectors of A are computed. + + JOBVR (input) CHARACTER*1 + = 'N': right eigenvectors of A are not computed; + = 'V': right eigenvectors of A are computed. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the N-by-N matrix A. + On exit, A has been overwritten. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + WR (output) DOUBLE PRECISION array, dimension (N) + WI (output) DOUBLE PRECISION array, dimension (N) + WR and WI contain the real and imaginary parts, + respectively, of the computed eigenvalues. Complex + conjugate pairs of eigenvalues appear consecutively + with the eigenvalue having the positive imaginary part + first. + + VL (output) DOUBLE PRECISION array, dimension (LDVL,N) + If JOBVL = 'V', the left eigenvectors u(j) are stored one + after another in the columns of VL, in the same order + as their eigenvalues. + If JOBVL = 'N', VL is not referenced. + If the j-th eigenvalue is real, then u(j) = VL(:,j), + the j-th column of VL. + If the j-th and (j+1)-st eigenvalues form a complex + conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and + u(j+1) = VL(:,j) - i*VL(:,j+1). + + LDVL (input) INTEGER + The leading dimension of the array VL. LDVL >= 1; if + JOBVL = 'V', LDVL >= N. + + VR (output) DOUBLE PRECISION array, dimension (LDVR,N) + If JOBVR = 'V', the right eigenvectors v(j) are stored one + after another in the columns of VR, in the same order + as their eigenvalues. + If JOBVR = 'N', VR is not referenced. + If the j-th eigenvalue is real, then v(j) = VR(:,j), + the j-th column of VR. + If the j-th and (j+1)-st eigenvalues form a complex + conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and + v(j+1) = VR(:,j) - i*VR(:,j+1). + + LDVR (input) INTEGER + The leading dimension of the array VR. LDVR >= 1; if + JOBVR = 'V', LDVR >= N. + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,3*N), and + if JOBVL = 'V' or JOBVR = 'V', LWORK >= 4*N. For good + performance, LWORK must generally be larger. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = i, the QR algorithm failed to compute all the + eigenvalues, and no eigenvectors have been computed; + elements i+1:N of WR and WI contain eigenvalues which + have converged. + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --wr; + --wi; + vl_dim1 = *ldvl; + vl_offset = 1 + vl_dim1; + vl -= vl_offset; + vr_dim1 = *ldvr; + vr_offset = 1 + vr_dim1; + vr -= vr_offset; + --work; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1; + wantvl = lsame_(jobvl, "V"); + wantvr = lsame_(jobvr, "V"); + if (! wantvl && ! lsame_(jobvl, "N")) { + *info = -1; + } else if (! wantvr && ! lsame_(jobvr, "N")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldvl < 1 || wantvl && *ldvl < *n) { + *info = -9; + } else if (*ldvr < 1 || wantvr && *ldvr < *n) { + *info = -11; + } + +/* + Compute workspace + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + NB refers to the optimal block size for the immediately + following subroutine, as returned by ILAENV. + HSWORK refers to the workspace preferred by DHSEQR, as + calculated below. HSWORK is computed assuming ILO=1 and IHI=N, + the worst case.) +*/ + + if (*info == 0) { + if (*n == 0) { + minwrk = 1; + maxwrk = 1; + } else { + maxwrk = (*n << 1) + *n * ilaenv_(&c__1, "DGEHRD", " ", n, &c__1, + n, &c__0, (ftnlen)6, (ftnlen)1); + if (wantvl) { + minwrk = *n << 2; +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + (*n - 1) * ilaenv_(&c__1, + "DORGHR", " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + dhseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[ + 1], &vl[vl_offset], ldvl, &work[1], &c_n1, info); + hswork = (integer) work[1]; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = * + n + hswork; + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n << 2; + maxwrk = max(i__1,i__2); + } else if (wantvr) { + minwrk = *n << 2; +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + (*n - 1) * ilaenv_(&c__1, + "DORGHR", " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + dhseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[ + 1], &vr[vr_offset], ldvr, &work[1], &c_n1, info); + hswork = (integer) work[1]; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = * + n + hswork; + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n << 2; + maxwrk = max(i__1,i__2); + } else { + minwrk = *n * 3; + dhseqr_("E", "N", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[ + 1], &vr[vr_offset], ldvr, &work[1], &c_n1, info); + hswork = (integer) work[1]; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = * + n + hswork; + maxwrk = max(i__1,i__2); + } + maxwrk = max(maxwrk,minwrk); + } + work[1] = (doublereal) maxwrk; + + if (*lwork < minwrk && ! lquery) { + *info = -13; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGEEV ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Get machine constants */ + + eps = PRECISION; + smlnum = SAFEMINIMUM; + bignum = 1. / smlnum; + dlabad_(&smlnum, &bignum); + smlnum = sqrt(smlnum) / eps; + bignum = 1. / smlnum; + +/* Scale A if max element outside range [SMLNUM,BIGNUM] */ + + anrm = dlange_("M", n, n, &a[a_offset], lda, dum); + scalea = FALSE_; + if (anrm > 0. && anrm < smlnum) { + scalea = TRUE_; + cscale = smlnum; + } else if (anrm > bignum) { + scalea = TRUE_; + cscale = bignum; + } + if (scalea) { + dlascl_("G", &c__0, &c__0, &anrm, &cscale, n, n, &a[a_offset], lda, & + ierr); + } + +/* + Balance the matrix + (Workspace: need N) +*/ + + ibal = 1; + dgebal_("B", n, &a[a_offset], lda, &ilo, &ihi, &work[ibal], &ierr); + +/* + Reduce to upper Hessenberg form + (Workspace: need 3*N, prefer 2*N+N*NB) +*/ + + itau = ibal + *n; + iwrk = itau + *n; + i__1 = *lwork - iwrk + 1; + dgehrd_(n, &ilo, &ihi, &a[a_offset], lda, &work[itau], &work[iwrk], &i__1, + &ierr); + + if (wantvl) { + +/* + Want left eigenvectors + Copy Householder vectors to VL +*/ + + *(unsigned char *)side = 'L'; + dlacpy_("L", n, n, &a[a_offset], lda, &vl[vl_offset], ldvl) + ; + +/* + Generate orthogonal matrix in VL + (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB) +*/ + + i__1 = *lwork - iwrk + 1; + dorghr_(n, &ilo, &ihi, &vl[vl_offset], ldvl, &work[itau], &work[iwrk], + &i__1, &ierr); + +/* + Perform QR iteration, accumulating Schur vectors in VL + (Workspace: need N+1, prefer N+HSWORK (see comments) ) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + dhseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], & + vl[vl_offset], ldvl, &work[iwrk], &i__1, info); + + if (wantvr) { + +/* + Want left and right eigenvectors + Copy Schur vectors to VR +*/ + + *(unsigned char *)side = 'B'; + dlacpy_("F", n, n, &vl[vl_offset], ldvl, &vr[vr_offset], ldvr); + } + + } else if (wantvr) { + +/* + Want right eigenvectors + Copy Householder vectors to VR +*/ + + *(unsigned char *)side = 'R'; + dlacpy_("L", n, n, &a[a_offset], lda, &vr[vr_offset], ldvr) + ; + +/* + Generate orthogonal matrix in VR + (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB) +*/ + + i__1 = *lwork - iwrk + 1; + dorghr_(n, &ilo, &ihi, &vr[vr_offset], ldvr, &work[itau], &work[iwrk], + &i__1, &ierr); + +/* + Perform QR iteration, accumulating Schur vectors in VR + (Workspace: need N+1, prefer N+HSWORK (see comments) ) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + dhseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], & + vr[vr_offset], ldvr, &work[iwrk], &i__1, info); + + } else { + +/* + Compute eigenvalues only + (Workspace: need N+1, prefer N+HSWORK (see comments) ) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + dhseqr_("E", "N", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], & + vr[vr_offset], ldvr, &work[iwrk], &i__1, info); + } + +/* If INFO > 0 from DHSEQR, then quit */ + + if (*info > 0) { + goto L50; + } + + if (wantvl || wantvr) { + +/* + Compute left and/or right eigenvectors + (Workspace: need 4*N) +*/ + + dtrevc_(side, "B", select, n, &a[a_offset], lda, &vl[vl_offset], ldvl, + &vr[vr_offset], ldvr, n, &nout, &work[iwrk], &ierr); + } + + if (wantvl) { + +/* + Undo balancing of left eigenvectors + (Workspace: need N) +*/ + + dgebak_("B", "L", n, &ilo, &ihi, &work[ibal], n, &vl[vl_offset], ldvl, + &ierr); + +/* Normalize left eigenvectors and make largest component real */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if (wi[i__] == 0.) { + scl = 1. / dnrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1); + dscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1); + } else if (wi[i__] > 0.) { + d__1 = dnrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1); + d__2 = dnrm2_(n, &vl[(i__ + 1) * vl_dim1 + 1], &c__1); + scl = 1. / dlapy2_(&d__1, &d__2); + dscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1); + dscal_(n, &scl, &vl[(i__ + 1) * vl_dim1 + 1], &c__1); + i__2 = *n; + for (k = 1; k <= i__2; ++k) { +/* Computing 2nd power */ + d__1 = vl[k + i__ * vl_dim1]; +/* Computing 2nd power */ + d__2 = vl[k + (i__ + 1) * vl_dim1]; + work[iwrk + k - 1] = d__1 * d__1 + d__2 * d__2; +/* L10: */ + } + k = idamax_(n, &work[iwrk], &c__1); + dlartg_(&vl[k + i__ * vl_dim1], &vl[k + (i__ + 1) * vl_dim1], + &cs, &sn, &r__); + drot_(n, &vl[i__ * vl_dim1 + 1], &c__1, &vl[(i__ + 1) * + vl_dim1 + 1], &c__1, &cs, &sn); + vl[k + (i__ + 1) * vl_dim1] = 0.; + } +/* L20: */ + } + } + + if (wantvr) { + +/* + Undo balancing of right eigenvectors + (Workspace: need N) +*/ + + dgebak_("B", "R", n, &ilo, &ihi, &work[ibal], n, &vr[vr_offset], ldvr, + &ierr); + +/* Normalize right eigenvectors and make largest component real */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if (wi[i__] == 0.) { + scl = 1. / dnrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1); + dscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1); + } else if (wi[i__] > 0.) { + d__1 = dnrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1); + d__2 = dnrm2_(n, &vr[(i__ + 1) * vr_dim1 + 1], &c__1); + scl = 1. / dlapy2_(&d__1, &d__2); + dscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1); + dscal_(n, &scl, &vr[(i__ + 1) * vr_dim1 + 1], &c__1); + i__2 = *n; + for (k = 1; k <= i__2; ++k) { +/* Computing 2nd power */ + d__1 = vr[k + i__ * vr_dim1]; +/* Computing 2nd power */ + d__2 = vr[k + (i__ + 1) * vr_dim1]; + work[iwrk + k - 1] = d__1 * d__1 + d__2 * d__2; +/* L30: */ + } + k = idamax_(n, &work[iwrk], &c__1); + dlartg_(&vr[k + i__ * vr_dim1], &vr[k + (i__ + 1) * vr_dim1], + &cs, &sn, &r__); + drot_(n, &vr[i__ * vr_dim1 + 1], &c__1, &vr[(i__ + 1) * + vr_dim1 + 1], &c__1, &cs, &sn); + vr[k + (i__ + 1) * vr_dim1] = 0.; + } +/* L40: */ + } + } + +/* Undo scaling if necessary */ + +L50: + if (scalea) { + i__1 = *n - *info; +/* Computing MAX */ + i__3 = *n - *info; + i__2 = max(i__3,1); + dlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wr[*info + + 1], &i__2, &ierr); + i__1 = *n - *info; +/* Computing MAX */ + i__3 = *n - *info; + i__2 = max(i__3,1); + dlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wi[*info + + 1], &i__2, &ierr); + if (*info > 0) { + i__1 = ilo - 1; + dlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wr[1], + n, &ierr); + i__1 = ilo - 1; + dlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wi[1], + n, &ierr); + } + } + + work[1] = (doublereal) maxwrk; + return 0; + +/* End of DGEEV */ + +} /* dgeev_ */ + +/* Subroutine */ int dgehd2_(integer *n, integer *ilo, integer *ihi, + doublereal *a, integer *lda, doublereal *tau, doublereal *work, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__; + static doublereal aii; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *), dlarfg_(integer *, doublereal *, + doublereal *, integer *, doublereal *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGEHD2 reduces a real general matrix A to upper Hessenberg form H by + an orthogonal similarity transformation: Q' * A * Q = H . + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that A is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to DGEBAL; otherwise they should be + set to 1 and N respectively. See Further Details. + 1 <= ILO <= IHI <= max(1,N). + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the n by n general matrix to be reduced. + On exit, the upper triangle and the first subdiagonal of A + are overwritten with the upper Hessenberg matrix H, and the + elements below the first subdiagonal, with the array TAU, + represent the orthogonal matrix Q as a product of elementary + reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) DOUBLE PRECISION array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) DOUBLE PRECISION array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrix Q is represented as a product of (ihi-ilo) elementary + reflectors + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on + exit in A(i+2:ihi,i), and tau in TAU(i). + + The contents of A are illustrated by the following example, with + n = 7, ilo = 2 and ihi = 6: + + on entry, on exit, + + ( a a a a a a a ) ( a a h h h h a ) + ( a a a a a a ) ( a h h h h a ) + ( a a a a a a ) ( h h h h h h ) + ( a a a a a a ) ( v2 h h h h h ) + ( a a a a a a ) ( v2 v3 h h h h ) + ( a a a a a a ) ( v2 v3 v4 h h h ) + ( a ) ( a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGEHD2", &i__1); + return 0; + } + + i__1 = *ihi - 1; + for (i__ = *ilo; i__ <= i__1; ++i__) { + +/* Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) */ + + i__2 = *ihi - i__; +/* Computing MIN */ + i__3 = i__ + 2; + dlarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + i__ * + a_dim1], &c__1, &tau[i__]); + aii = a[i__ + 1 + i__ * a_dim1]; + a[i__ + 1 + i__ * a_dim1] = 1.; + +/* Apply H(i) to A(1:ihi,i+1:ihi) from the right */ + + i__2 = *ihi - i__; + dlarf_("Right", ihi, &i__2, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &a[(i__ + 1) * a_dim1 + 1], lda, &work[1]); + +/* Apply H(i) to A(i+1:ihi,i+1:n) from the left */ + + i__2 = *ihi - i__; + i__3 = *n - i__; + dlarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &a[i__ + 1 + (i__ + 1) * a_dim1], lda, &work[1]); + + a[i__ + 1 + i__ * a_dim1] = aii; +/* L10: */ + } + + return 0; + +/* End of DGEHD2 */ + +} /* dgehd2_ */ + +/* Subroutine */ int dgehrd_(integer *n, integer *ilo, integer *ihi, + doublereal *a, integer *lda, doublereal *tau, doublereal *work, + integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j; + static doublereal t[4160] /* was [65][64] */; + static integer ib; + static doublereal ei; + static integer nb, nh, nx, iws; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer nbmin, iinfo; + extern /* Subroutine */ int dtrmm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *), daxpy_( + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *), dgehd2_(integer *, integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *), dlahr2_( + integer *, integer *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *), + dlarfb_(char *, char *, char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + -- April 2009 -- + + + Purpose + ======= + + DGEHRD reduces a real general matrix A to upper Hessenberg form H by + an orthogonal similarity transformation: Q' * A * Q = H . + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that A is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to DGEBAL; otherwise they should be + set to 1 and N respectively. See Further Details. + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the N-by-N general matrix to be reduced. + On exit, the upper triangle and the first subdiagonal of A + are overwritten with the upper Hessenberg matrix H, and the + elements below the first subdiagonal, with the array TAU, + represent the orthogonal matrix Q as a product of elementary + reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) DOUBLE PRECISION array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). Elements 1:ILO-1 and IHI:N-1 of TAU are set to + zero. + + WORK (workspace/output) DOUBLE PRECISION array, dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrix Q is represented as a product of (ihi-ilo) elementary + reflectors + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on + exit in A(i+2:ihi,i), and tau in TAU(i). + + The contents of A are illustrated by the following example, with + n = 7, ilo = 2 and ihi = 6: + + on entry, on exit, + + ( a a a a a a a ) ( a a h h h h a ) + ( a a a a a a ) ( a h h h h a ) + ( a a a a a a ) ( h h h h h h ) + ( a a a a a a ) ( v2 h h h h h ) + ( a a a a a a ) ( v2 v3 h h h h ) + ( a a a a a a ) ( v2 v3 v4 h h h ) + ( a ) ( a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + This file is a slight modification of LAPACK-3.0's DGEHRD + subroutine incorporating improvements proposed by Quintana-Orti and + Van de Geijn (2006). (See DLAHR2.) + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; +/* Computing MIN */ + i__1 = 64, i__2 = ilaenv_(&c__1, "DGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = min(i__1,i__2); + lwkopt = *n * nb; + work[1] = (doublereal) lwkopt; + lquery = *lwork == -1; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGEHRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Set elements 1:ILO-1 and IHI:N-1 of TAU to zero */ + + i__1 = *ilo - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + tau[i__] = 0.; +/* L10: */ + } + i__1 = *n - 1; + for (i__ = max(1,*ihi); i__ <= i__1; ++i__) { + tau[i__] = 0.; +/* L20: */ + } + +/* Quick return if possible */ + + nh = *ihi - *ilo + 1; + if (nh <= 1) { + work[1] = 1.; + return 0; + } + +/* + Determine the block size + + Computing MIN +*/ + i__1 = 64, i__2 = ilaenv_(&c__1, "DGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = min(i__1,i__2); + nbmin = 2; + iws = 1; + if (nb > 1 && nb < nh) { + +/* + Determine when to cross over from blocked to unblocked code + (last block is always handled by unblocked code) + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "DGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < nh) { + +/* Determine if workspace is large enough for blocked code */ + + iws = *n * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: determine the + minimum value of NB, and reduce NB or force use of + unblocked code + + Computing MAX +*/ + i__1 = 2, i__2 = ilaenv_(&c__2, "DGEHRD", " ", n, ilo, ihi, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + if (*lwork >= *n * nbmin) { + nb = *lwork / *n; + } else { + nb = 1; + } + } + } + } + ldwork = *n; + + if (nb < nbmin || nb >= nh) { + +/* Use unblocked code below */ + + i__ = *ilo; + + } else { + +/* Use blocked code */ + + i__1 = *ihi - 1 - nx; + i__2 = nb; + for (i__ = *ilo; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = nb, i__4 = *ihi - i__; + ib = min(i__3,i__4); + +/* + Reduce columns i:i+ib-1 to Hessenberg form, returning the + matrices V and T of the block reflector H = I - V*T*V' + which performs the reduction, and also the matrix Y = A*V*T +*/ + + dlahr2_(ihi, &i__, &ib, &a[i__ * a_dim1 + 1], lda, &tau[i__], t, & + c__65, &work[1], &ldwork); + +/* + Apply the block reflector H to A(1:ihi,i+ib:ihi) from the + right, computing A := A - Y * V'. V(i+ib,ib-1) must be set + to 1 +*/ + + ei = a[i__ + ib + (i__ + ib - 1) * a_dim1]; + a[i__ + ib + (i__ + ib - 1) * a_dim1] = 1.; + i__3 = *ihi - i__ - ib + 1; + dgemm_("No transpose", "Transpose", ihi, &i__3, &ib, &c_b151, & + work[1], &ldwork, &a[i__ + ib + i__ * a_dim1], lda, & + c_b15, &a[(i__ + ib) * a_dim1 + 1], lda); + a[i__ + ib + (i__ + ib - 1) * a_dim1] = ei; + +/* + Apply the block reflector H to A(1:i,i+1:i+ib-1) from the + right +*/ + + i__3 = ib - 1; + dtrmm_("Right", "Lower", "Transpose", "Unit", &i__, &i__3, &c_b15, + &a[i__ + 1 + i__ * a_dim1], lda, &work[1], &ldwork); + i__3 = ib - 2; + for (j = 0; j <= i__3; ++j) { + daxpy_(&i__, &c_b151, &work[ldwork * j + 1], &c__1, &a[(i__ + + j + 1) * a_dim1 + 1], &c__1); +/* L30: */ + } + +/* + Apply the block reflector H to A(i+1:ihi,i+ib:n) from the + left +*/ + + i__3 = *ihi - i__; + i__4 = *n - i__ - ib + 1; + dlarfb_("Left", "Transpose", "Forward", "Columnwise", &i__3, & + i__4, &ib, &a[i__ + 1 + i__ * a_dim1], lda, t, &c__65, &a[ + i__ + 1 + (i__ + ib) * a_dim1], lda, &work[1], &ldwork); +/* L40: */ + } + } + +/* Use unblocked code to reduce the rest of the matrix */ + + dgehd2_(n, &i__, ihi, &a[a_offset], lda, &tau[1], &work[1], &iinfo); + work[1] = (doublereal) iws; + + return 0; + +/* End of DGEHRD */ + +} /* dgehrd_ */ + +/* Subroutine */ int dgelq2_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, k; + static doublereal aii; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *), dlarfg_(integer *, doublereal *, + doublereal *, integer *, doublereal *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DGELQ2 computes an LQ factorization of a real m by n matrix A: + A = L * Q. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, the elements on and below the diagonal of the array + contain the m by min(m,n) lower trapezoidal matrix L (L is + lower triangular if m <= n); the elements above the diagonal, + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) DOUBLE PRECISION array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) DOUBLE PRECISION array, dimension (M) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(k) . . . H(2) H(1), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:n) is stored on exit in A(i,i+1:n), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGELQ2", &i__1); + return 0; + } + + k = min(*m,*n); + + i__1 = k; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + dlarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[i__ + min(i__3,*n) * a_dim1] + , lda, &tau[i__]); + if (i__ < *m) { + +/* Apply H(i) to A(i+1:m,i:n) from the right */ + + aii = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.; + i__2 = *m - i__; + i__3 = *n - i__ + 1; + dlarf_("Right", &i__2, &i__3, &a[i__ + i__ * a_dim1], lda, &tau[ + i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + a[i__ + i__ * a_dim1] = aii; + } +/* L10: */ + } + return 0; + +/* End of DGELQ2 */ + +} /* dgelq2_ */ + +/* Subroutine */ int dgelqf_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, k, ib, nb, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int dgelq2_(integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *), dlarfb_(char *, + char *, char *, char *, integer *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *, doublereal *, integer *), dlarft_(char *, char *, integer *, integer *, doublereal + *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGELQF computes an LQ factorization of a real M-by-N matrix A: + A = L * Q. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, the elements on and below the diagonal of the array + contain the m-by-min(m,n) lower trapezoidal matrix L (L is + lower triangular if m <= n); the elements above the diagonal, + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) DOUBLE PRECISION array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,M). + For optimum performance LWORK >= M*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(k) . . . H(2) H(1), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:n) is stored on exit in A(i,i+1:n), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "DGELQF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + lwkopt = *m * nb; + work[1] = (doublereal) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else if (*lwork < max(1,*m) && ! lquery) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGELQF", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + k = min(*m,*n); + if (k == 0) { + work[1] = 1.; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *m; + if (nb > 1 && nb < k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "DGELQF", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *m; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "DGELQF", " ", m, n, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < k && nx < k) { + +/* Use blocked code initially */ + + i__1 = k - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = k - i__ + 1; + ib = min(i__3,nb); + +/* + Compute the LQ factorization of the current block + A(i:i+ib-1,i:n) +*/ + + i__3 = *n - i__ + 1; + dgelq2_(&ib, &i__3, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[ + 1], &iinfo); + if (i__ + ib <= *m) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__3 = *n - i__ + 1; + dlarft_("Forward", "Rowwise", &i__3, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H to A(i+ib:m,i:n) from the right */ + + i__3 = *m - i__ - ib + 1; + i__4 = *n - i__ + 1; + dlarfb_("Right", "No transpose", "Forward", "Rowwise", &i__3, + &i__4, &ib, &a[i__ + i__ * a_dim1], lda, &work[1], & + ldwork, &a[i__ + ib + i__ * a_dim1], lda, &work[ib + + 1], &ldwork); + } +/* L10: */ + } + } else { + i__ = 1; + } + +/* Use unblocked code to factor the last or only block. */ + + if (i__ <= k) { + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + dgelq2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[1] + , &iinfo); + } + + work[1] = (doublereal) iws; + return 0; + +/* End of DGELQF */ + +} /* dgelqf_ */ + +/* Subroutine */ int dgelsd_(integer *m, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * + s, doublereal *rcond, integer *rank, doublereal *work, integer *lwork, + integer *iwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer ie, il, mm; + static doublereal eps, anrm, bnrm; + static integer itau, nlvl, iascl, ibscl; + static doublereal sfmin; + static integer minmn, maxmn, itaup, itauq, mnthr, nwork; + extern /* Subroutine */ int dlabad_(doublereal *, doublereal *), dgebrd_( + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *, + integer *); + extern doublereal dlamch_(char *), dlange_(char *, integer *, + integer *, doublereal *, integer *, doublereal *); + extern /* Subroutine */ int dgelqf_(integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *, integer *), + dlalsd_(char *, integer *, integer *, integer *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *, integer *), dlascl_(char *, + integer *, integer *, doublereal *, doublereal *, integer *, + integer *, doublereal *, integer *, integer *), dgeqrf_( + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, integer *), dlacpy_(char *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *), dlaset_(char *, integer *, integer *, doublereal *, + doublereal *, doublereal *, integer *), xerbla_(char *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static doublereal bignum; + extern /* Subroutine */ int dormbr_(char *, char *, char *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, integer *); + static integer wlalsd; + extern /* Subroutine */ int dormlq_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *, integer *); + static integer ldwork; + extern /* Subroutine */ int dormqr_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *, integer *); + static integer liwork, minwrk, maxwrk; + static doublereal smlnum; + static logical lquery; + static integer smlsiz; + + +/* + -- LAPACK driver routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DGELSD computes the minimum-norm solution to a real linear least + squares problem: + minimize 2-norm(| b - A*x |) + using the singular value decomposition (SVD) of A. A is an M-by-N + matrix which may be rank-deficient. + + Several right hand side vectors b and solution vectors x can be + handled in a single call; they are stored as the columns of the + M-by-NRHS right hand side matrix B and the N-by-NRHS solution + matrix X. + + The problem is solved in three steps: + (1) Reduce the coefficient matrix A to bidiagonal form with + Householder transformations, reducing the original problem + into a "bidiagonal least squares problem" (BLS) + (2) Solve the BLS using a divide and conquer approach. + (3) Apply back all the Householder tranformations to solve + the original least squares problem. + + The effective rank of A is determined by treating as zero those + singular values which are less than RCOND times the largest singular + value. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + M (input) INTEGER + The number of rows of A. M >= 0. + + N (input) INTEGER + The number of columns of A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrices B and X. NRHS >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, A has been destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) + On entry, the M-by-NRHS right hand side matrix B. + On exit, B is overwritten by the N-by-NRHS solution + matrix X. If m >= n and RANK = n, the residual + sum-of-squares for the solution in the i-th column is given + by the sum of squares of elements n+1:m in that column. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,max(M,N)). + + S (output) DOUBLE PRECISION array, dimension (min(M,N)) + The singular values of A in decreasing order. + The condition number of A in the 2-norm = S(1)/S(min(m,n)). + + RCOND (input) DOUBLE PRECISION + RCOND is used to determine the effective rank of A. + Singular values S(i) <= RCOND*S(1) are treated as zero. + If RCOND < 0, machine precision is used instead. + + RANK (output) INTEGER + The effective rank of A, i.e., the number of singular values + which are greater than RCOND*S(1). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK must be at least 1. + The exact minimum amount of workspace needed depends on M, + N and NRHS. As long as LWORK is at least + 12*N + 2*N*SMLSIZ + 8*N*NLVL + N*NRHS + (SMLSIZ+1)**2, + if M is greater than or equal to N or + 12*M + 2*M*SMLSIZ + 8*M*NLVL + M*NRHS + (SMLSIZ+1)**2, + if M is less than N, the code will execute correctly. + SMLSIZ is returned by ILAENV and is equal to the maximum + size of the subproblems at the bottom of the computation + tree (usually about 25), and + NLVL = MAX( 0, INT( LOG_2( MIN( M,N )/(SMLSIZ+1) ) ) + 1 ) + For good performance, LWORK should generally be larger. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + IWORK (workspace) INTEGER array, dimension (MAX(1,LIWORK)) + LIWORK >= max(1, 3 * MINMN * NLVL + 11 * MINMN), + where MINMN = MIN( M,N ). + On exit, if INFO = 0, IWORK(1) returns the minimum LIWORK. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: the algorithm for computing the SVD failed to converge; + if INFO = i, i off-diagonal elements of an intermediate + bidiagonal form did not converge to zero. + + Further Details + =============== + + Based on contributions by + Ming Gu and Ren-Cang Li, Computer Science Division, University of + California at Berkeley, USA + Osni Marques, LBNL/NERSC, USA + + ===================================================================== + + + Test the input arguments. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + --s; + --work; + --iwork; + + /* Function Body */ + *info = 0; + minmn = min(*m,*n); + maxmn = max(*m,*n); + mnthr = ilaenv_(&c__6, "DGELSD", " ", m, n, nrhs, &c_n1, (ftnlen)6, ( + ftnlen)1); + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*ldb < max(1,maxmn)) { + *info = -7; + } + + smlsiz = ilaenv_(&c__9, "DGELSD", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + +/* + Compute workspace. + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + NB refers to the optimal block size for the immediately + following subroutine, as returned by ILAENV.) +*/ + + minwrk = 1; + liwork = 1; + minmn = max(1,minmn); +/* Computing MAX */ + i__1 = (integer) (log((doublereal) minmn / (doublereal) (smlsiz + 1)) / + log(2.)) + 1; + nlvl = max(i__1,0); + + if (*info == 0) { + maxwrk = 0; + liwork = minmn * 3 * nlvl + minmn * 11; + mm = *m; + if (*m >= *n && *m >= mnthr) { + +/* Path 1a - overdetermined, with many more rows than columns. */ + + mm = *n; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + *n * ilaenv_(&c__1, "DGEQRF", " ", m, + n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + *nrhs * ilaenv_(&c__1, "DORMQR", "LT", + m, nrhs, n, &c_n1, (ftnlen)6, (ftnlen)2); + maxwrk = max(i__1,i__2); + } + if (*m >= *n) { + +/* + Path 1 - overdetermined or exactly determined. + + Computing MAX +*/ + i__1 = maxwrk, i__2 = *n * 3 + (mm + *n) * ilaenv_(&c__1, "DGEBRD" + , " ", &mm, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n * 3 + *nrhs * ilaenv_(&c__1, "DORMBR", + "QLT", &mm, nrhs, n, &c_n1, (ftnlen)6, (ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n * 3 + (*n - 1) * ilaenv_(&c__1, "DORMBR", + "PLN", n, nrhs, n, &c_n1, (ftnlen)6, (ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing 2nd power */ + i__1 = smlsiz + 1; + wlalsd = *n * 9 + (*n << 1) * smlsiz + (*n << 3) * nlvl + *n * * + nrhs + i__1 * i__1; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n * 3 + wlalsd; + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = *n * 3 + mm, i__2 = *n * 3 + *nrhs, i__1 = max(i__1,i__2), + i__2 = *n * 3 + wlalsd; + minwrk = max(i__1,i__2); + } + if (*n > *m) { +/* Computing 2nd power */ + i__1 = smlsiz + 1; + wlalsd = *m * 9 + (*m << 1) * smlsiz + (*m << 3) * nlvl + *m * * + nrhs + i__1 * i__1; + if (*n >= mnthr) { + +/* + Path 2a - underdetermined, with many more columns + than rows. +*/ + + maxwrk = *m + *m * ilaenv_(&c__1, "DGELQF", " ", m, n, &c_n1, + &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 2) + (*m << 1) * + ilaenv_(&c__1, "DGEBRD", " ", m, m, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 2) + *nrhs * ilaenv_(& + c__1, "DORMBR", "QLT", m, nrhs, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 2) + (*m - 1) * + ilaenv_(&c__1, "DORMBR", "PLN", m, nrhs, m, &c_n1, ( + ftnlen)6, (ftnlen)3); + maxwrk = max(i__1,i__2); + if (*nrhs > 1) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + *m + *m * *nrhs; + maxwrk = max(i__1,i__2); + } else { +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 1); + maxwrk = max(i__1,i__2); + } +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m + *nrhs * ilaenv_(&c__1, "DORMLQ", + "LT", n, nrhs, m, &c_n1, (ftnlen)6, (ftnlen)2); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 2) + wlalsd; + maxwrk = max(i__1,i__2); +/* + XXX: Ensure the Path 2a case below is triggered. The workspace + calculation should use queries for all routines eventually. + Computing MAX + Computing MAX +*/ + i__3 = *m, i__4 = (*m << 1) - 4, i__3 = max(i__3,i__4), i__3 = + max(i__3,*nrhs), i__4 = *n - *m * 3; + i__1 = maxwrk, i__2 = (*m << 2) + *m * *m + max(i__3,i__4); + maxwrk = max(i__1,i__2); + } else { + +/* Path 2 - remaining underdetermined cases. */ + + maxwrk = *m * 3 + (*n + *m) * ilaenv_(&c__1, "DGEBRD", " ", m, + n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * 3 + *nrhs * ilaenv_(&c__1, "DORMBR" + , "QLT", m, nrhs, n, &c_n1, (ftnlen)6, (ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR", + "PLN", n, nrhs, m, &c_n1, (ftnlen)6, (ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * 3 + wlalsd; + maxwrk = max(i__1,i__2); + } +/* Computing MAX */ + i__1 = *m * 3 + *nrhs, i__2 = *m * 3 + *m, i__1 = max(i__1,i__2), + i__2 = *m * 3 + wlalsd; + minwrk = max(i__1,i__2); + } + minwrk = min(minwrk,maxwrk); + work[1] = (doublereal) maxwrk; + iwork[1] = liwork; + if (*lwork < minwrk && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGELSD", &i__1); + return 0; + } else if (lquery) { + goto L10; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + *rank = 0; + return 0; + } + +/* Get machine parameters. */ + + eps = PRECISION; + sfmin = SAFEMINIMUM; + smlnum = sfmin / eps; + bignum = 1. / smlnum; + dlabad_(&smlnum, &bignum); + +/* Scale A if max entry outside range [SMLNUM,BIGNUM]. */ + + anrm = dlange_("M", m, n, &a[a_offset], lda, &work[1]); + iascl = 0; + if (anrm > 0. && anrm < smlnum) { + +/* Scale matrix norm up to SMLNUM. */ + + dlascl_("G", &c__0, &c__0, &anrm, &smlnum, m, n, &a[a_offset], lda, + info); + iascl = 1; + } else if (anrm > bignum) { + +/* Scale matrix norm down to BIGNUM. */ + + dlascl_("G", &c__0, &c__0, &anrm, &bignum, m, n, &a[a_offset], lda, + info); + iascl = 2; + } else if (anrm == 0.) { + +/* Matrix all zero. Return zero solution. */ + + i__1 = max(*m,*n); + dlaset_("F", &i__1, nrhs, &c_b29, &c_b29, &b[b_offset], ldb); + dlaset_("F", &minmn, &c__1, &c_b29, &c_b29, &s[1], &c__1); + *rank = 0; + goto L10; + } + +/* Scale B if max entry outside range [SMLNUM,BIGNUM]. */ + + bnrm = dlange_("M", m, nrhs, &b[b_offset], ldb, &work[1]); + ibscl = 0; + if (bnrm > 0. && bnrm < smlnum) { + +/* Scale matrix norm up to SMLNUM. */ + + dlascl_("G", &c__0, &c__0, &bnrm, &smlnum, m, nrhs, &b[b_offset], ldb, + info); + ibscl = 1; + } else if (bnrm > bignum) { + +/* Scale matrix norm down to BIGNUM. */ + + dlascl_("G", &c__0, &c__0, &bnrm, &bignum, m, nrhs, &b[b_offset], ldb, + info); + ibscl = 2; + } + +/* If M < N make sure certain entries of B are zero. */ + + if (*m < *n) { + i__1 = *n - *m; + dlaset_("F", &i__1, nrhs, &c_b29, &c_b29, &b[*m + 1 + b_dim1], ldb); + } + +/* Overdetermined case. */ + + if (*m >= *n) { + +/* Path 1 - overdetermined or exactly determined. */ + + mm = *m; + if (*m >= mnthr) { + +/* Path 1a - overdetermined, with many more rows than columns. */ + + mm = *n; + itau = 1; + nwork = itau + *n; + +/* + Compute A=Q*R. + (Workspace: need 2*N, prefer N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], &i__1, + info); + +/* + Multiply B by transpose(Q). + (Workspace: need N+NRHS, prefer N+NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormqr_("L", "T", m, nrhs, n, &a[a_offset], lda, &work[itau], &b[ + b_offset], ldb, &work[nwork], &i__1, info); + +/* Zero out below R. */ + + if (*n > 1) { + i__1 = *n - 1; + i__2 = *n - 1; + dlaset_("L", &i__1, &i__2, &c_b29, &c_b29, &a[a_dim1 + 2], + lda); + } + } + + ie = 1; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A. + (Workspace: need 3*N+MM, prefer 3*N+(MM+N)*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgebrd_(&mm, n, &a[a_offset], lda, &s[1], &work[ie], &work[itauq], & + work[itaup], &work[nwork], &i__1, info); + +/* + Multiply B by transpose of left bidiagonalizing vectors of R. + (Workspace: need 3*N+NRHS, prefer 3*N+NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "T", &mm, nrhs, n, &a[a_offset], lda, &work[itauq], + &b[b_offset], ldb, &work[nwork], &i__1, info); + +/* Solve the bidiagonal least squares problem. */ + + dlalsd_("U", &smlsiz, n, nrhs, &s[1], &work[ie], &b[b_offset], ldb, + rcond, rank, &work[nwork], &iwork[1], info); + if (*info != 0) { + goto L10; + } + +/* Multiply B by right bidiagonalizing vectors of R. */ + + i__1 = *lwork - nwork + 1; + dormbr_("P", "L", "N", n, nrhs, n, &a[a_offset], lda, &work[itaup], & + b[b_offset], ldb, &work[nwork], &i__1, info); + + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = *m, i__2 = (*m << 1) - 4, i__1 = max(i__1,i__2), i__1 = max( + i__1,*nrhs), i__2 = *n - *m * 3, i__1 = max(i__1,i__2); + if (*n >= mnthr && *lwork >= (*m << 2) + *m * *m + max(i__1,wlalsd)) { + +/* + Path 2a - underdetermined, with many more columns than rows + and sufficient workspace for an efficient algorithm. +*/ + + ldwork = *m; +/* + Computing MAX + Computing MAX +*/ + i__3 = *m, i__4 = (*m << 1) - 4, i__3 = max(i__3,i__4), i__3 = + max(i__3,*nrhs), i__4 = *n - *m * 3; + i__1 = (*m << 2) + *m * *lda + max(i__3,i__4), i__2 = *m * *lda + + *m + *m * *nrhs, i__1 = max(i__1,i__2), i__2 = (*m << 2) + + *m * *lda + wlalsd; + if (*lwork >= max(i__1,i__2)) { + ldwork = *lda; + } + itau = 1; + nwork = *m + 1; + +/* + Compute A=L*Q. + (Workspace: need 2*M, prefer M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], &i__1, + info); + il = nwork; + +/* Copy L to WORK(IL), zeroing out above its diagonal. */ + + dlacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwork); + i__1 = *m - 1; + i__2 = *m - 1; + dlaset_("U", &i__1, &i__2, &c_b29, &c_b29, &work[il + ldwork], & + ldwork); + ie = il + ldwork * *m; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IL). + (Workspace: need M*M+5*M, prefer M*M+4*M+2*M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgebrd_(m, m, &work[il], &ldwork, &s[1], &work[ie], &work[itauq], + &work[itaup], &work[nwork], &i__1, info); + +/* + Multiply B by transpose of left bidiagonalizing vectors of L. + (Workspace: need M*M+4*M+NRHS, prefer M*M+4*M+NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "T", m, nrhs, m, &work[il], &ldwork, &work[ + itauq], &b[b_offset], ldb, &work[nwork], &i__1, info); + +/* Solve the bidiagonal least squares problem. */ + + dlalsd_("U", &smlsiz, m, nrhs, &s[1], &work[ie], &b[b_offset], + ldb, rcond, rank, &work[nwork], &iwork[1], info); + if (*info != 0) { + goto L10; + } + +/* Multiply B by right bidiagonalizing vectors of L. */ + + i__1 = *lwork - nwork + 1; + dormbr_("P", "L", "N", m, nrhs, m, &work[il], &ldwork, &work[ + itaup], &b[b_offset], ldb, &work[nwork], &i__1, info); + +/* Zero out below first M rows of B. */ + + i__1 = *n - *m; + dlaset_("F", &i__1, nrhs, &c_b29, &c_b29, &b[*m + 1 + b_dim1], + ldb); + nwork = itau + *m; + +/* + Multiply transpose(Q) by B. + (Workspace: need M+NRHS, prefer M+NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormlq_("L", "T", n, nrhs, m, &a[a_offset], lda, &work[itau], &b[ + b_offset], ldb, &work[nwork], &i__1, info); + + } else { + +/* Path 2 - remaining underdetermined cases. */ + + ie = 1; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize A. + (Workspace: need 3*M+N, prefer 3*M+(M+N)*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgebrd_(m, n, &a[a_offset], lda, &s[1], &work[ie], &work[itauq], & + work[itaup], &work[nwork], &i__1, info); + +/* + Multiply B by transpose of left bidiagonalizing vectors. + (Workspace: need 3*M+NRHS, prefer 3*M+NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "T", m, nrhs, n, &a[a_offset], lda, &work[itauq] + , &b[b_offset], ldb, &work[nwork], &i__1, info); + +/* Solve the bidiagonal least squares problem. */ + + dlalsd_("L", &smlsiz, m, nrhs, &s[1], &work[ie], &b[b_offset], + ldb, rcond, rank, &work[nwork], &iwork[1], info); + if (*info != 0) { + goto L10; + } + +/* Multiply B by right bidiagonalizing vectors of A. */ + + i__1 = *lwork - nwork + 1; + dormbr_("P", "L", "N", n, nrhs, m, &a[a_offset], lda, &work[itaup] + , &b[b_offset], ldb, &work[nwork], &i__1, info); + + } + } + +/* Undo scaling. */ + + if (iascl == 1) { + dlascl_("G", &c__0, &c__0, &anrm, &smlnum, n, nrhs, &b[b_offset], ldb, + info); + dlascl_("G", &c__0, &c__0, &smlnum, &anrm, &minmn, &c__1, &s[1], & + minmn, info); + } else if (iascl == 2) { + dlascl_("G", &c__0, &c__0, &anrm, &bignum, n, nrhs, &b[b_offset], ldb, + info); + dlascl_("G", &c__0, &c__0, &bignum, &anrm, &minmn, &c__1, &s[1], & + minmn, info); + } + if (ibscl == 1) { + dlascl_("G", &c__0, &c__0, &smlnum, &bnrm, n, nrhs, &b[b_offset], ldb, + info); + } else if (ibscl == 2) { + dlascl_("G", &c__0, &c__0, &bignum, &bnrm, n, nrhs, &b[b_offset], ldb, + info); + } + +L10: + work[1] = (doublereal) maxwrk; + iwork[1] = liwork; + return 0; + +/* End of DGELSD */ + +} /* dgelsd_ */ + +/* Subroutine */ int dgeqr2_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, k; + static doublereal aii; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *), dlarfg_(integer *, doublereal *, + doublereal *, integer *, doublereal *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DGEQR2 computes a QR factorization of a real m by n matrix A: + A = Q * R. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, the elements on and above the diagonal of the array + contain the min(m,n) by n upper trapezoidal matrix R (R is + upper triangular if m >= n); the elements below the diagonal, + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) DOUBLE PRECISION array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) DOUBLE PRECISION array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(1) H(2) . . . H(k), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGEQR2", &i__1); + return 0; + } + + k = min(*m,*n); + + i__1 = k; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ + + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + dlarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * a_dim1] + , &c__1, &tau[i__]); + if (i__ < *n) { + +/* Apply H(i) to A(i:m,i+1:n) from the left */ + + aii = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.; + i__2 = *m - i__ + 1; + i__3 = *n - i__; + dlarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, &tau[ + i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + a[i__ + i__ * a_dim1] = aii; + } +/* L10: */ + } + return 0; + +/* End of DGEQR2 */ + +} /* dgeqr2_ */ + +/* Subroutine */ int dgeqrf_(integer *m, integer *n, doublereal *a, integer * + lda, doublereal *tau, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, k, ib, nb, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int dgeqr2_(integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *), dlarfb_(char *, + char *, char *, char *, integer *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *, doublereal *, integer *), dlarft_(char *, char *, integer *, integer *, doublereal + *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGEQRF computes a QR factorization of a real M-by-N matrix A: + A = Q * R. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, the elements on and above the diagonal of the array + contain the min(M,N)-by-N upper trapezoidal matrix R (R is + upper triangular if m >= n); the elements below the diagonal, + with the array TAU, represent the orthogonal matrix Q as a + product of min(m,n) elementary reflectors (see Further + Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) DOUBLE PRECISION array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(1) H(2) . . . H(k), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "DGEQRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + lwkopt = *n * nb; + work[1] = (doublereal) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGEQRF", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + k = min(*m,*n); + if (k == 0) { + work[1] = 1.; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *n; + if (nb > 1 && nb < k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "DGEQRF", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "DGEQRF", " ", m, n, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < k && nx < k) { + +/* Use blocked code initially */ + + i__1 = k - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = k - i__ + 1; + ib = min(i__3,nb); + +/* + Compute the QR factorization of the current block + A(i:m,i:i+ib-1) +*/ + + i__3 = *m - i__ + 1; + dgeqr2_(&i__3, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[ + 1], &iinfo); + if (i__ + ib <= *n) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__3 = *m - i__ + 1; + dlarft_("Forward", "Columnwise", &i__3, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H' to A(i:m,i+ib:n) from the left */ + + i__3 = *m - i__ + 1; + i__4 = *n - i__ - ib + 1; + dlarfb_("Left", "Transpose", "Forward", "Columnwise", &i__3, & + i__4, &ib, &a[i__ + i__ * a_dim1], lda, &work[1], & + ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, &work[ib + + 1], &ldwork); + } +/* L10: */ + } + } else { + i__ = 1; + } + +/* Use unblocked code to factor the last or only block. */ + + if (i__ <= k) { + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + dgeqr2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[1] + , &iinfo); + } + + work[1] = (doublereal) iws; + return 0; + +/* End of DGEQRF */ + +} /* dgeqrf_ */ + +/* Subroutine */ int dgesdd_(char *jobz, integer *m, integer *n, doublereal * + a, integer *lda, doublereal *s, doublereal *u, integer *ldu, + doublereal *vt, integer *ldvt, doublereal *work, integer *lwork, + integer *iwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, u_dim1, u_offset, vt_dim1, vt_offset, i__1, + i__2, i__3; + + /* Local variables */ + static integer i__, ie, il, ir, iu, blk; + static doublereal dum[1], eps; + static integer ivt, iscl; + static doublereal anrm; + static integer idum[1], ierr, itau; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + extern logical lsame_(char *, char *); + static integer chunk, minmn, wrkbl, itaup, itauq, mnthr; + static logical wntqa; + static integer nwork; + static logical wntqn, wntqo, wntqs; + extern /* Subroutine */ int dbdsdc_(char *, char *, integer *, doublereal + *, doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, integer *, integer *), dgebrd_(integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *, integer *); + extern doublereal dlamch_(char *), dlange_(char *, integer *, + integer *, doublereal *, integer *, doublereal *); + static integer bdspac; + extern /* Subroutine */ int dgelqf_(integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *, integer *), + dlascl_(char *, integer *, integer *, doublereal *, doublereal *, + integer *, integer *, doublereal *, integer *, integer *), + dgeqrf_(integer *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *, integer *), dlacpy_(char *, + integer *, integer *, doublereal *, integer *, doublereal *, + integer *), dlaset_(char *, integer *, integer *, + doublereal *, doublereal *, doublereal *, integer *), + xerbla_(char *, integer *), dorgbr_(char *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static doublereal bignum; + extern /* Subroutine */ int dormbr_(char *, char *, char *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, integer *), dorglq_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + integer *), dorgqr_(integer *, integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *, integer *); + static integer ldwrkl, ldwrkr, minwrk, ldwrku, maxwrk, ldwkvt; + static doublereal smlnum; + static logical wntqas, lquery; + + +/* + -- LAPACK driver routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + March 2009 + + + Purpose + ======= + + DGESDD computes the singular value decomposition (SVD) of a real + M-by-N matrix A, optionally computing the left and right singular + vectors. If singular vectors are desired, it uses a + divide-and-conquer algorithm. + + The SVD is written + + A = U * SIGMA * transpose(V) + + where SIGMA is an M-by-N matrix which is zero except for its + min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and + V is an N-by-N orthogonal matrix. The diagonal elements of SIGMA + are the singular values of A; they are real and non-negative, and + are returned in descending order. The first min(m,n) columns of + U and V are the left and right singular vectors of A. + + Note that the routine returns VT = V**T, not V. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + JOBZ (input) CHARACTER*1 + Specifies options for computing all or part of the matrix U: + = 'A': all M columns of U and all N rows of V**T are + returned in the arrays U and VT; + = 'S': the first min(M,N) columns of U and the first + min(M,N) rows of V**T are returned in the arrays U + and VT; + = 'O': If M >= N, the first N columns of U are overwritten + on the array A and all rows of V**T are returned in + the array VT; + otherwise, all columns of U are returned in the + array U and the first M rows of V**T are overwritten + in the array A; + = 'N': no columns of U or rows of V**T are computed. + + M (input) INTEGER + The number of rows of the input matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the input matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, + if JOBZ = 'O', A is overwritten with the first N columns + of U (the left singular vectors, stored + columnwise) if M >= N; + A is overwritten with the first M rows + of V**T (the right singular vectors, stored + rowwise) otherwise. + if JOBZ .ne. 'O', the contents of A are destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + S (output) DOUBLE PRECISION array, dimension (min(M,N)) + The singular values of A, sorted so that S(i) >= S(i+1). + + U (output) DOUBLE PRECISION array, dimension (LDU,UCOL) + UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N; + UCOL = min(M,N) if JOBZ = 'S'. + If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M + orthogonal matrix U; + if JOBZ = 'S', U contains the first min(M,N) columns of U + (the left singular vectors, stored columnwise); + if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= 1; if + JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M. + + VT (output) DOUBLE PRECISION array, dimension (LDVT,N) + If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the + N-by-N orthogonal matrix V**T; + if JOBZ = 'S', VT contains the first min(M,N) rows of + V**T (the right singular vectors, stored rowwise); + if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= 1; if + JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N; + if JOBZ = 'S', LDVT >= min(M,N). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK; + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= 1. + If JOBZ = 'N', + LWORK >= 3*min(M,N) + max(max(M,N),7*min(M,N)). + If JOBZ = 'O', + LWORK >= 3*min(M,N) + + max(max(M,N),5*min(M,N)*min(M,N)+4*min(M,N)). + If JOBZ = 'S' or 'A' + LWORK >= 3*min(M,N) + + max(max(M,N),4*min(M,N)*min(M,N)+4*min(M,N)). + For good performance, LWORK should generally be larger. + If LWORK = -1 but other input arguments are legal, WORK(1) + returns the optimal LWORK. + + IWORK (workspace) INTEGER array, dimension (8*min(M,N)) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: DBDSDC did not converge, updating process failed. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --s; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + minmn = min(*m,*n); + wntqa = lsame_(jobz, "A"); + wntqs = lsame_(jobz, "S"); + wntqas = wntqa || wntqs; + wntqo = lsame_(jobz, "O"); + wntqn = lsame_(jobz, "N"); + lquery = *lwork == -1; + + if (! (wntqa || wntqs || wntqo || wntqn)) { + *info = -1; + } else if (*m < 0) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*ldu < 1 || wntqas && *ldu < *m || wntqo && *m < *n && *ldu < * + m) { + *info = -8; + } else if (*ldvt < 1 || wntqa && *ldvt < *n || wntqs && *ldvt < minmn || + wntqo && *m >= *n && *ldvt < *n) { + *info = -10; + } + +/* + Compute workspace + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + NB refers to the optimal block size for the immediately + following subroutine, as returned by ILAENV.) +*/ + + if (*info == 0) { + minwrk = 1; + maxwrk = 1; + if (*m >= *n && minmn > 0) { + +/* Compute space needed for DBDSDC */ + + mnthr = (integer) (minmn * 11. / 6.); + if (wntqn) { + bdspac = *n * 7; + } else { + bdspac = *n * 3 * *n + (*n << 2); + } + if (*m >= mnthr) { + if (wntqn) { + +/* Path 1 (M much larger than N, JOBZ='N') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "DGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + (*n << 1) * ilaenv_(&c__1, + "DGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n; + maxwrk = max(i__1,i__2); + minwrk = bdspac + *n; + } else if (wntqo) { + +/* Path 2 (M much larger than N, JOBZ='O') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "DGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *n * ilaenv_(&c__1, "DORGQR", + " ", m, n, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + (*n << 1) * ilaenv_(&c__1, + "DGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "QLN", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + (*n << 1) * *n; + minwrk = bdspac + (*n << 1) * *n + *n * 3; + } else if (wntqs) { + +/* Path 3 (M much larger than N, JOBZ='S') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "DGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *n * ilaenv_(&c__1, "DORGQR", + " ", m, n, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + (*n << 1) * ilaenv_(&c__1, + "DGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "QLN", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *n * *n; + minwrk = bdspac + *n * *n + *n * 3; + } else if (wntqa) { + +/* Path 4 (M much larger than N, JOBZ='A') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "DGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *m * ilaenv_(&c__1, "DORGQR", + " ", m, m, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + (*n << 1) * ilaenv_(&c__1, + "DGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "QLN", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *n * *n; + minwrk = bdspac + *n * *n + *n * 3; + } + } else { + +/* Path 5 (M at least N, but not much larger) */ + + wrkbl = *n * 3 + (*m + *n) * ilaenv_(&c__1, "DGEBRD", " ", m, + n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + if (wntqn) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + maxwrk = max(i__1,i__2); + minwrk = *n * 3 + max(*m,bdspac); + } else if (wntqo) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "QLN", m, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *m * *n; +/* Computing MAX */ + i__1 = *m, i__2 = *n * *n + bdspac; + minwrk = *n * 3 + max(i__1,i__2); + } else if (wntqs) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "QLN", m, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + maxwrk = max(i__1,i__2); + minwrk = *n * 3 + max(*m,bdspac); + } else if (wntqa) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "QLN", m, m, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "DORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = bdspac + *n * 3; + maxwrk = max(i__1,i__2); + minwrk = *n * 3 + max(*m,bdspac); + } + } + } else if (minmn > 0) { + +/* Compute space needed for DBDSDC */ + + mnthr = (integer) (minmn * 11. / 6.); + if (wntqn) { + bdspac = *m * 7; + } else { + bdspac = *m * 3 * *m + (*m << 2); + } + if (*n >= mnthr) { + if (wntqn) { + +/* Path 1t (N much larger than M, JOBZ='N') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "DGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + (*m << 1) * ilaenv_(&c__1, + "DGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m; + maxwrk = max(i__1,i__2); + minwrk = bdspac + *m; + } else if (wntqo) { + +/* Path 2t (N much larger than M, JOBZ='O') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "DGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *m * ilaenv_(&c__1, "DORGLQ", + " ", m, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + (*m << 1) * ilaenv_(&c__1, + "DGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "QLN", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "PRT", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + (*m << 1) * *m; + minwrk = bdspac + (*m << 1) * *m + *m * 3; + } else if (wntqs) { + +/* Path 3t (N much larger than M, JOBZ='S') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "DGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *m * ilaenv_(&c__1, "DORGLQ", + " ", m, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + (*m << 1) * ilaenv_(&c__1, + "DGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "QLN", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "PRT", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *m * *m; + minwrk = bdspac + *m * *m + *m * 3; + } else if (wntqa) { + +/* Path 4t (N much larger than M, JOBZ='A') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "DGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *n * ilaenv_(&c__1, "DORGLQ", + " ", n, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + (*m << 1) * ilaenv_(&c__1, + "DGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "QLN", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "PRT", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *m * *m; + minwrk = bdspac + *m * *m + *m * 3; + } + } else { + +/* Path 5t (N greater than M, but not much larger) */ + + wrkbl = *m * 3 + (*m + *n) * ilaenv_(&c__1, "DGEBRD", " ", m, + n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + if (wntqn) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + maxwrk = max(i__1,i__2); + minwrk = *m * 3 + max(*n,bdspac); + } else if (wntqo) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "QLN", m, m, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "PRT", m, n, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *m * *n; +/* Computing MAX */ + i__1 = *n, i__2 = *m * *m + bdspac; + minwrk = *m * 3 + max(i__1,i__2); + } else if (wntqs) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "QLN", m, m, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "PRT", m, n, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + maxwrk = max(i__1,i__2); + minwrk = *m * 3 + max(*n,bdspac); + } else if (wntqa) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "QLN", m, m, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "DORMBR" + , "PRT", n, n, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + maxwrk = max(i__1,i__2); + minwrk = *m * 3 + max(*n,bdspac); + } + } + } + maxwrk = max(maxwrk,minwrk); + work[1] = (doublereal) maxwrk; + + if (*lwork < minwrk && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGESDD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Get machine constants */ + + eps = PRECISION; + smlnum = sqrt(SAFEMINIMUM) / eps; + bignum = 1. / smlnum; + +/* Scale A if max element outside range [SMLNUM,BIGNUM] */ + + anrm = dlange_("M", m, n, &a[a_offset], lda, dum); + iscl = 0; + if (anrm > 0. && anrm < smlnum) { + iscl = 1; + dlascl_("G", &c__0, &c__0, &anrm, &smlnum, m, n, &a[a_offset], lda, & + ierr); + } else if (anrm > bignum) { + iscl = 1; + dlascl_("G", &c__0, &c__0, &anrm, &bignum, m, n, &a[a_offset], lda, & + ierr); + } + + if (*m >= *n) { + +/* + A has at least as many rows as columns. If A has sufficiently + more rows than columns, first reduce using the QR + decomposition (if sufficient workspace available) +*/ + + if (*m >= mnthr) { + + if (wntqn) { + +/* + Path 1 (M much larger than N, JOBZ='N') + No singular vectors to be computed +*/ + + itau = 1; + nwork = itau + *n; + +/* + Compute A=Q*R + (Workspace: need 2*N, prefer N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Zero out below R */ + + i__1 = *n - 1; + i__2 = *n - 1; + dlaset_("L", &i__1, &i__2, &c_b29, &c_b29, &a[a_dim1 + 2], + lda); + ie = 1; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A + (Workspace: need 4*N, prefer 3*N+2*N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgebrd_(n, n, &a[a_offset], lda, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + nwork = ie + *n; + +/* + Perform bidiagonal SVD, computing singular values only + (Workspace: need N+BDSPAC) +*/ + + dbdsdc_("U", "N", n, &s[1], &work[ie], dum, &c__1, dum, &c__1, + dum, idum, &work[nwork], &iwork[1], info); + + } else if (wntqo) { + +/* + Path 2 (M much larger than N, JOBZ = 'O') + N left singular vectors to be overwritten on A and + N right singular vectors to be computed in VT +*/ + + ir = 1; + +/* WORK(IR) is LDWRKR by N */ + + if (*lwork >= *lda * *n + *n * *n + *n * 3 + bdspac) { + ldwrkr = *lda; + } else { + ldwrkr = (*lwork - *n * *n - *n * 3 - bdspac) / *n; + } + itau = ir + ldwrkr * *n; + nwork = itau + *n; + +/* + Compute A=Q*R + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Copy R to WORK(IR), zeroing out below it */ + + dlacpy_("U", n, n, &a[a_offset], lda, &work[ir], &ldwrkr); + i__1 = *n - 1; + i__2 = *n - 1; + dlaset_("L", &i__1, &i__2, &c_b29, &c_b29, &work[ir + 1], & + ldwrkr); + +/* + Generate Q in A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dorgqr_(m, n, n, &a[a_offset], lda, &work[itau], &work[nwork], + &i__1, &ierr); + ie = itau; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in VT, copying result to WORK(IR) + (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgebrd_(n, n, &work[ir], &ldwrkr, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* WORK(IU) is N by N */ + + iu = nwork; + nwork = iu + *n * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in WORK(IU) and computing right + singular vectors of bidiagonal matrix in VT + (Workspace: need N+N*N+BDSPAC) +*/ + + dbdsdc_("U", "I", n, &s[1], &work[ie], &work[iu], n, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite WORK(IU) by left singular vectors of R + and VT by right singular vectors of R + (Workspace: need 2*N*N+3*N, prefer 2*N*N+2*N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", n, n, n, &work[ir], &ldwrkr, &work[ + itauq], &work[iu], n, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + dormbr_("P", "R", "T", n, n, n, &work[ir], &ldwrkr, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + +/* + Multiply Q in A by left singular vectors of R in + WORK(IU), storing result in WORK(IR) and copying to A + (Workspace: need 2*N*N, prefer N*N+M*N) +*/ + + i__1 = *m; + i__2 = ldwrkr; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrkr); + dgemm_("N", "N", &chunk, n, n, &c_b15, &a[i__ + a_dim1], + lda, &work[iu], n, &c_b29, &work[ir], &ldwrkr); + dlacpy_("F", &chunk, n, &work[ir], &ldwrkr, &a[i__ + + a_dim1], lda); +/* L10: */ + } + + } else if (wntqs) { + +/* + Path 3 (M much larger than N, JOBZ='S') + N left singular vectors to be computed in U and + N right singular vectors to be computed in VT +*/ + + ir = 1; + +/* WORK(IR) is N by N */ + + ldwrkr = *n; + itau = ir + ldwrkr * *n; + nwork = itau + *n; + +/* + Compute A=Q*R + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Copy R to WORK(IR), zeroing out below it */ + + dlacpy_("U", n, n, &a[a_offset], lda, &work[ir], &ldwrkr); + i__2 = *n - 1; + i__1 = *n - 1; + dlaset_("L", &i__2, &i__1, &c_b29, &c_b29, &work[ir + 1], & + ldwrkr); + +/* + Generate Q in A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dorgqr_(m, n, n, &a[a_offset], lda, &work[itau], &work[nwork], + &i__2, &ierr); + ie = itau; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in WORK(IR) + (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgebrd_(n, n, &work[ir], &ldwrkr, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagoal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need N+BDSPAC) +*/ + + dbdsdc_("U", "I", n, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of R and VT + by right singular vectors of R + (Workspace: need N*N+3*N, prefer N*N+2*N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", n, n, n, &work[ir], &ldwrkr, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + + i__2 = *lwork - nwork + 1; + dormbr_("P", "R", "T", n, n, n, &work[ir], &ldwrkr, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply Q in A by left singular vectors of R in + WORK(IR), storing result in U + (Workspace: need N*N) +*/ + + dlacpy_("F", n, n, &u[u_offset], ldu, &work[ir], &ldwrkr); + dgemm_("N", "N", m, n, n, &c_b15, &a[a_offset], lda, &work[ir] + , &ldwrkr, &c_b29, &u[u_offset], ldu); + + } else if (wntqa) { + +/* + Path 4 (M much larger than N, JOBZ='A') + M left singular vectors to be computed in U and + N right singular vectors to be computed in VT +*/ + + iu = 1; + +/* WORK(IU) is N by N */ + + ldwrku = *n; + itau = iu + ldwrku * *n; + nwork = itau + *n; + +/* + Compute A=Q*R, copying result to U + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + dlacpy_("L", m, n, &a[a_offset], lda, &u[u_offset], ldu); + +/* + Generate Q in U + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + i__2 = *lwork - nwork + 1; + dorgqr_(m, m, n, &u[u_offset], ldu, &work[itau], &work[nwork], + &i__2, &ierr); + +/* Produce R in A, zeroing out other entries */ + + i__2 = *n - 1; + i__1 = *n - 1; + dlaset_("L", &i__2, &i__1, &c_b29, &c_b29, &a[a_dim1 + 2], + lda); + ie = itau; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A + (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgebrd_(n, n, &a[a_offset], lda, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in WORK(IU) and computing right + singular vectors of bidiagonal matrix in VT + (Workspace: need N+N*N+BDSPAC) +*/ + + dbdsdc_("U", "I", n, &s[1], &work[ie], &work[iu], n, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite WORK(IU) by left singular vectors of R and VT + by right singular vectors of R + (Workspace: need N*N+3*N, prefer N*N+2*N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", n, n, n, &a[a_offset], lda, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__2, & + ierr); + i__2 = *lwork - nwork + 1; + dormbr_("P", "R", "T", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply Q in U by left singular vectors of R in + WORK(IU), storing result in A + (Workspace: need N*N) +*/ + + dgemm_("N", "N", m, n, n, &c_b15, &u[u_offset], ldu, &work[iu] + , &ldwrku, &c_b29, &a[a_offset], lda); + +/* Copy left singular vectors of A from A to U */ + + dlacpy_("F", m, n, &a[a_offset], lda, &u[u_offset], ldu); + + } + + } else { + +/* + M .LT. MNTHR + + Path 5 (M at least N, but not much larger) + Reduce to bidiagonal form without QR decomposition +*/ + + ie = 1; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize A + (Workspace: need 3*N+M, prefer 3*N+(M+N)*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgebrd_(m, n, &a[a_offset], lda, &s[1], &work[ie], &work[itauq], & + work[itaup], &work[nwork], &i__2, &ierr); + if (wntqn) { + +/* + Perform bidiagonal SVD, only computing singular values + (Workspace: need N+BDSPAC) +*/ + + dbdsdc_("U", "N", n, &s[1], &work[ie], dum, &c__1, dum, &c__1, + dum, idum, &work[nwork], &iwork[1], info); + } else if (wntqo) { + iu = nwork; + if (*lwork >= *m * *n + *n * 3 + bdspac) { + +/* WORK( IU ) is M by N */ + + ldwrku = *m; + nwork = iu + ldwrku * *n; + dlaset_("F", m, n, &c_b29, &c_b29, &work[iu], &ldwrku); + } else { + +/* WORK( IU ) is N by N */ + + ldwrku = *n; + nwork = iu + ldwrku * *n; + +/* WORK(IR) is LDWRKR by N */ + + ir = nwork; + ldwrkr = (*lwork - *n * *n - *n * 3) / *n; + } + nwork = iu + ldwrku * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in WORK(IU) and computing right + singular vectors of bidiagonal matrix in VT + (Workspace: need N+N*N+BDSPAC) +*/ + + dbdsdc_("U", "I", n, &s[1], &work[ie], &work[iu], &ldwrku, & + vt[vt_offset], ldvt, dum, idum, &work[nwork], &iwork[ + 1], info); + +/* + Overwrite VT by right singular vectors of A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dormbr_("P", "R", "T", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + + if (*lwork >= *m * *n + *n * 3 + bdspac) { + +/* + Overwrite WORK(IU) by left singular vectors of A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, n, n, &a[a_offset], lda, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__2, & + ierr); + +/* Copy left singular vectors of A from WORK(IU) to A */ + + dlacpy_("F", m, n, &work[iu], &ldwrku, &a[a_offset], lda); + } else { + +/* + Generate Q in A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + dorgbr_("Q", m, n, n, &a[a_offset], lda, &work[itauq], & + work[nwork], &i__2, &ierr); + +/* + Multiply Q in A by left singular vectors of + bidiagonal matrix in WORK(IU), storing result in + WORK(IR) and copying to A + (Workspace: need 2*N*N, prefer N*N+M*N) +*/ + + i__2 = *m; + i__1 = ldwrkr; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrkr); + dgemm_("N", "N", &chunk, n, n, &c_b15, &a[i__ + + a_dim1], lda, &work[iu], &ldwrku, &c_b29, & + work[ir], &ldwrkr); + dlacpy_("F", &chunk, n, &work[ir], &ldwrkr, &a[i__ + + a_dim1], lda); +/* L20: */ + } + } + + } else if (wntqs) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need N+BDSPAC) +*/ + + dlaset_("F", m, n, &c_b29, &c_b29, &u[u_offset], ldu); + dbdsdc_("U", "I", n, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of A and VT + by right singular vectors of A + (Workspace: need 3*N, prefer 2*N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, n, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + dormbr_("P", "R", "T", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } else if (wntqa) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need N+BDSPAC) +*/ + + dlaset_("F", m, m, &c_b29, &c_b29, &u[u_offset], ldu); + dbdsdc_("U", "I", n, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* Set the right corner of U to identity matrix */ + + if (*m > *n) { + i__1 = *m - *n; + i__2 = *m - *n; + dlaset_("F", &i__1, &i__2, &c_b29, &c_b15, &u[*n + 1 + (* + n + 1) * u_dim1], ldu); + } + +/* + Overwrite U by left singular vectors of A and VT + by right singular vectors of A + (Workspace: need N*N+2*N+M, prefer N*N+2*N+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + dormbr_("P", "R", "T", n, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } + + } + + } else { + +/* + A has more columns than rows. If A has sufficiently more + columns than rows, first reduce using the LQ decomposition (if + sufficient workspace available) +*/ + + if (*n >= mnthr) { + + if (wntqn) { + +/* + Path 1t (N much larger than M, JOBZ='N') + No singular vectors to be computed +*/ + + itau = 1; + nwork = itau + *m; + +/* + Compute A=L*Q + (Workspace: need 2*M, prefer M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Zero out above L */ + + i__1 = *m - 1; + i__2 = *m - 1; + dlaset_("U", &i__1, &i__2, &c_b29, &c_b29, &a[(a_dim1 << 1) + + 1], lda); + ie = 1; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in A + (Workspace: need 4*M, prefer 3*M+2*M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgebrd_(m, m, &a[a_offset], lda, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + nwork = ie + *m; + +/* + Perform bidiagonal SVD, computing singular values only + (Workspace: need M+BDSPAC) +*/ + + dbdsdc_("U", "N", m, &s[1], &work[ie], dum, &c__1, dum, &c__1, + dum, idum, &work[nwork], &iwork[1], info); + + } else if (wntqo) { + +/* + Path 2t (N much larger than M, JOBZ='O') + M right singular vectors to be overwritten on A and + M left singular vectors to be computed in U +*/ + + ivt = 1; + +/* IVT is M by M */ + + il = ivt + *m * *m; + if (*lwork >= *m * *n + *m * *m + *m * 3 + bdspac) { + +/* WORK(IL) is M by N */ + + ldwrkl = *m; + chunk = *n; + } else { + ldwrkl = *m; + chunk = (*lwork - *m * *m) / *m; + } + itau = il + ldwrkl * *m; + nwork = itau + *m; + +/* + Compute A=L*Q + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Copy L to WORK(IL), zeroing about above it */ + + dlacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwrkl); + i__1 = *m - 1; + i__2 = *m - 1; + dlaset_("U", &i__1, &i__2, &c_b29, &c_b29, &work[il + ldwrkl], + &ldwrkl); + +/* + Generate Q in A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dorglq_(m, n, m, &a[a_offset], lda, &work[itau], &work[nwork], + &i__1, &ierr); + ie = itau; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IL) + (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dgebrd_(m, m, &work[il], &ldwrkl, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U, and computing right singular + vectors of bidiagonal matrix in WORK(IVT) + (Workspace: need M+M*M+BDSPAC) +*/ + + dbdsdc_("U", "I", m, &s[1], &work[ie], &u[u_offset], ldu, & + work[ivt], m, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of L and WORK(IVT) + by right singular vectors of L + (Workspace: need 2*M*M+3*M, prefer 2*M*M+2*M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, m, m, &work[il], &ldwrkl, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + dormbr_("P", "R", "T", m, m, m, &work[il], &ldwrkl, &work[ + itaup], &work[ivt], m, &work[nwork], &i__1, &ierr); + +/* + Multiply right singular vectors of L in WORK(IVT) by Q + in A, storing result in WORK(IL) and copying to A + (Workspace: need 2*M*M, prefer M*M+M*N) +*/ + + i__1 = *n; + i__2 = chunk; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + dgemm_("N", "N", m, &blk, m, &c_b15, &work[ivt], m, &a[ + i__ * a_dim1 + 1], lda, &c_b29, &work[il], & + ldwrkl); + dlacpy_("F", m, &blk, &work[il], &ldwrkl, &a[i__ * a_dim1 + + 1], lda); +/* L30: */ + } + + } else if (wntqs) { + +/* + Path 3t (N much larger than M, JOBZ='S') + M right singular vectors to be computed in VT and + M left singular vectors to be computed in U +*/ + + il = 1; + +/* WORK(IL) is M by M */ + + ldwrkl = *m; + itau = il + ldwrkl * *m; + nwork = itau + *m; + +/* + Compute A=L*Q + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Copy L to WORK(IL), zeroing out above it */ + + dlacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwrkl); + i__2 = *m - 1; + i__1 = *m - 1; + dlaset_("U", &i__2, &i__1, &c_b29, &c_b29, &work[il + ldwrkl], + &ldwrkl); + +/* + Generate Q in A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dorglq_(m, n, m, &a[a_offset], lda, &work[itau], &work[nwork], + &i__2, &ierr); + ie = itau; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IU), copying result to U + (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgebrd_(m, m, &work[il], &ldwrkl, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need M+BDSPAC) +*/ + + dbdsdc_("U", "I", m, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of L and VT + by right singular vectors of L + (Workspace: need M*M+3*M, prefer M*M+2*M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, m, m, &work[il], &ldwrkl, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + i__2 = *lwork - nwork + 1; + dormbr_("P", "R", "T", m, m, m, &work[il], &ldwrkl, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply right singular vectors of L in WORK(IL) by + Q in A, storing result in VT + (Workspace: need M*M) +*/ + + dlacpy_("F", m, m, &vt[vt_offset], ldvt, &work[il], &ldwrkl); + dgemm_("N", "N", m, n, m, &c_b15, &work[il], &ldwrkl, &a[ + a_offset], lda, &c_b29, &vt[vt_offset], ldvt); + + } else if (wntqa) { + +/* + Path 4t (N much larger than M, JOBZ='A') + N right singular vectors to be computed in VT and + M left singular vectors to be computed in U +*/ + + ivt = 1; + +/* WORK(IVT) is M by M */ + + ldwkvt = *m; + itau = ivt + ldwkvt * *m; + nwork = itau + *m; + +/* + Compute A=L*Q, copying result to VT + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + dlacpy_("U", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + +/* + Generate Q in VT + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dorglq_(n, n, m, &vt[vt_offset], ldvt, &work[itau], &work[ + nwork], &i__2, &ierr); + +/* Produce L in A, zeroing out other entries */ + + i__2 = *m - 1; + i__1 = *m - 1; + dlaset_("U", &i__2, &i__1, &c_b29, &c_b29, &a[(a_dim1 << 1) + + 1], lda); + ie = itau; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in A + (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgebrd_(m, m, &a[a_offset], lda, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in WORK(IVT) + (Workspace: need M+M*M+BDSPAC) +*/ + + dbdsdc_("U", "I", m, &s[1], &work[ie], &u[u_offset], ldu, & + work[ivt], &ldwkvt, dum, idum, &work[nwork], &iwork[1] + , info); + +/* + Overwrite U by left singular vectors of L and WORK(IVT) + by right singular vectors of L + (Workspace: need M*M+3*M, prefer M*M+2*M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, m, m, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + i__2 = *lwork - nwork + 1; + dormbr_("P", "R", "T", m, m, m, &a[a_offset], lda, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply right singular vectors of L in WORK(IVT) by + Q in VT, storing result in A + (Workspace: need M*M) +*/ + + dgemm_("N", "N", m, n, m, &c_b15, &work[ivt], &ldwkvt, &vt[ + vt_offset], ldvt, &c_b29, &a[a_offset], lda); + +/* Copy right singular vectors of A from A to VT */ + + dlacpy_("F", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + + } + + } else { + +/* + N .LT. MNTHR + + Path 5t (N greater than M, but not much larger) + Reduce to bidiagonal form without LQ decomposition +*/ + + ie = 1; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize A + (Workspace: need 3*M+N, prefer 3*M+(M+N)*NB) +*/ + + i__2 = *lwork - nwork + 1; + dgebrd_(m, n, &a[a_offset], lda, &s[1], &work[ie], &work[itauq], & + work[itaup], &work[nwork], &i__2, &ierr); + if (wntqn) { + +/* + Perform bidiagonal SVD, only computing singular values + (Workspace: need M+BDSPAC) +*/ + + dbdsdc_("L", "N", m, &s[1], &work[ie], dum, &c__1, dum, &c__1, + dum, idum, &work[nwork], &iwork[1], info); + } else if (wntqo) { + ldwkvt = *m; + ivt = nwork; + if (*lwork >= *m * *n + *m * 3 + bdspac) { + +/* WORK( IVT ) is M by N */ + + dlaset_("F", m, n, &c_b29, &c_b29, &work[ivt], &ldwkvt); + nwork = ivt + ldwkvt * *n; + } else { + +/* WORK( IVT ) is M by M */ + + nwork = ivt + ldwkvt * *m; + il = nwork; + +/* WORK(IL) is M by CHUNK */ + + chunk = (*lwork - *m * *m - *m * 3) / *m; + } + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in WORK(IVT) + (Workspace: need M*M+BDSPAC) +*/ + + dbdsdc_("L", "I", m, &s[1], &work[ie], &u[u_offset], ldu, & + work[ivt], &ldwkvt, dum, idum, &work[nwork], &iwork[1] + , info); + +/* + Overwrite U by left singular vectors of A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + + if (*lwork >= *m * *n + *m * 3 + bdspac) { + +/* + Overwrite WORK(IVT) by left singular vectors of A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dormbr_("P", "R", "T", m, n, m, &a[a_offset], lda, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__2, + &ierr); + +/* Copy right singular vectors of A from WORK(IVT) to A */ + + dlacpy_("F", m, n, &work[ivt], &ldwkvt, &a[a_offset], lda); + } else { + +/* + Generate P**T in A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + dorgbr_("P", m, n, m, &a[a_offset], lda, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Multiply Q in A by right singular vectors of + bidiagonal matrix in WORK(IVT), storing result in + WORK(IL) and copying to A + (Workspace: need 2*M*M, prefer M*M+M*N) +*/ + + i__2 = *n; + i__1 = chunk; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + dgemm_("N", "N", m, &blk, m, &c_b15, &work[ivt], & + ldwkvt, &a[i__ * a_dim1 + 1], lda, &c_b29, & + work[il], m); + dlacpy_("F", m, &blk, &work[il], m, &a[i__ * a_dim1 + + 1], lda); +/* L40: */ + } + } + } else if (wntqs) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need M+BDSPAC) +*/ + + dlaset_("F", m, n, &c_b29, &c_b29, &vt[vt_offset], ldvt); + dbdsdc_("L", "I", m, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of A and VT + by right singular vectors of A + (Workspace: need 3*M, prefer 2*M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + dormbr_("P", "R", "T", m, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } else if (wntqa) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need M+BDSPAC) +*/ + + dlaset_("F", n, n, &c_b29, &c_b29, &vt[vt_offset], ldvt); + dbdsdc_("L", "I", m, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* Set the right corner of VT to identity matrix */ + + if (*n > *m) { + i__1 = *n - *m; + i__2 = *n - *m; + dlaset_("F", &i__1, &i__2, &c_b29, &c_b15, &vt[*m + 1 + (* + m + 1) * vt_dim1], ldvt); + } + +/* + Overwrite U by left singular vectors of A and VT + by right singular vectors of A + (Workspace: need 2*M+N, prefer 2*M+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + dormbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + dormbr_("P", "R", "T", n, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } + + } + + } + +/* Undo scaling if necessary */ + + if (iscl == 1) { + if (anrm > bignum) { + dlascl_("G", &c__0, &c__0, &bignum, &anrm, &minmn, &c__1, &s[1], & + minmn, &ierr); + } + if (anrm < smlnum) { + dlascl_("G", &c__0, &c__0, &smlnum, &anrm, &minmn, &c__1, &s[1], & + minmn, &ierr); + } + } + +/* Return optimal workspace in WORK(1) */ + + work[1] = (doublereal) maxwrk; + + return 0; + +/* End of DGESDD */ + +} /* dgesdd_ */ + +/* Subroutine */ int dgesv_(integer *n, integer *nrhs, doublereal *a, integer + *lda, integer *ipiv, doublereal *b, integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern /* Subroutine */ int dgetrf_(integer *, integer *, doublereal *, + integer *, integer *, integer *), xerbla_(char *, integer *), dgetrs_(char *, integer *, integer *, doublereal *, + integer *, integer *, doublereal *, integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGESV computes the solution to a real system of linear equations + A * X = B, + where A is an N-by-N matrix and X and B are N-by-NRHS matrices. + + The LU decomposition with partial pivoting and row interchanges is + used to factor A as + A = P * L * U, + where P is a permutation matrix, L is unit lower triangular, and U is + upper triangular. The factored form of A is then used to solve the + system of equations A * X = B. + + Arguments + ========= + + N (input) INTEGER + The number of linear equations, i.e., the order of the + matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the N-by-N coefficient matrix A. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (output) INTEGER array, dimension (N) + The pivot indices that define the permutation matrix P; + row i of the matrix was interchanged with row IPIV(i). + + B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) + On entry, the N-by-NRHS matrix of right hand side matrix B. + On exit, if INFO = 0, the N-by-NRHS solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, so the solution could not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*nrhs < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGESV ", &i__1); + return 0; + } + +/* Compute the LU factorization of A. */ + + dgetrf_(n, n, &a[a_offset], lda, &ipiv[1], info); + if (*info == 0) { + +/* Solve the system A*X = B, overwriting B with X. */ + + dgetrs_("No transpose", n, nrhs, &a[a_offset], lda, &ipiv[1], &b[ + b_offset], ldb, info); + } + return 0; + +/* End of DGESV */ + +} /* dgesv_ */ + +/* Subroutine */ int dgetf2_(integer *m, integer *n, doublereal *a, integer * + lda, integer *ipiv, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1; + + /* Local variables */ + static integer i__, j, jp; + extern /* Subroutine */ int dger_(integer *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *), dscal_(integer *, doublereal *, doublereal *, integer + *); + static doublereal sfmin; + extern /* Subroutine */ int dswap_(integer *, doublereal *, integer *, + doublereal *, integer *); + + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGETF2 computes an LU factorization of a general m-by-n matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 2 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the m by n matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, U(k,k) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGETF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Compute machine safe minimum */ + + sfmin = SAFEMINIMUM; + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + +/* Find pivot and test for singularity. */ + + i__2 = *m - j + 1; + jp = j - 1 + idamax_(&i__2, &a[j + j * a_dim1], &c__1); + ipiv[j] = jp; + if (a[jp + j * a_dim1] != 0.) { + +/* Apply the interchange to columns 1:N. */ + + if (jp != j) { + dswap_(n, &a[j + a_dim1], lda, &a[jp + a_dim1], lda); + } + +/* Compute elements J+1:M of J-th column. */ + + if (j < *m) { + if ((d__1 = a[j + j * a_dim1], abs(d__1)) >= sfmin) { + i__2 = *m - j; + d__1 = 1. / a[j + j * a_dim1]; + dscal_(&i__2, &d__1, &a[j + 1 + j * a_dim1], &c__1); + } else { + i__2 = *m - j; + for (i__ = 1; i__ <= i__2; ++i__) { + a[j + i__ + j * a_dim1] /= a[j + j * a_dim1]; +/* L20: */ + } + } + } + + } else if (*info == 0) { + + *info = j; + } + + if (j < min(*m,*n)) { + +/* Update trailing submatrix. */ + + i__2 = *m - j; + i__3 = *n - j; + dger_(&i__2, &i__3, &c_b151, &a[j + 1 + j * a_dim1], &c__1, &a[j + + (j + 1) * a_dim1], lda, &a[j + 1 + (j + 1) * a_dim1], + lda); + } +/* L10: */ + } + return 0; + +/* End of DGETF2 */ + +} /* dgetf2_ */ + +/* Subroutine */ int dgetrf_(integer *m, integer *n, doublereal *a, integer * + lda, integer *ipiv, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + + /* Local variables */ + static integer i__, j, jb, nb; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer iinfo; + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *), dgetf2_( + integer *, integer *, doublereal *, integer *, integer *, integer + *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int dlaswp_(integer *, doublereal *, integer *, + integer *, integer *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGETRF computes an LU factorization of a general M-by-N matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 3 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the M-by-N matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGETRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "DGETRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + if (nb <= 1 || nb >= min(*m,*n)) { + +/* Use unblocked code. */ + + dgetf2_(m, n, &a[a_offset], lda, &ipiv[1], info); + } else { + +/* Use blocked code. */ + + i__1 = min(*m,*n); + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { +/* Computing MIN */ + i__3 = min(*m,*n) - j + 1; + jb = min(i__3,nb); + +/* + Factor diagonal and subdiagonal blocks and test for exact + singularity. +*/ + + i__3 = *m - j + 1; + dgetf2_(&i__3, &jb, &a[j + j * a_dim1], lda, &ipiv[j], &iinfo); + +/* Adjust INFO and the pivot indices. */ + + if (*info == 0 && iinfo > 0) { + *info = iinfo + j - 1; + } +/* Computing MIN */ + i__4 = *m, i__5 = j + jb - 1; + i__3 = min(i__4,i__5); + for (i__ = j; i__ <= i__3; ++i__) { + ipiv[i__] = j - 1 + ipiv[i__]; +/* L10: */ + } + +/* Apply interchanges to columns 1:J-1. */ + + i__3 = j - 1; + i__4 = j + jb - 1; + dlaswp_(&i__3, &a[a_offset], lda, &j, &i__4, &ipiv[1], &c__1); + + if (j + jb <= *n) { + +/* Apply interchanges to columns J+JB:N. */ + + i__3 = *n - j - jb + 1; + i__4 = j + jb - 1; + dlaswp_(&i__3, &a[(j + jb) * a_dim1 + 1], lda, &j, &i__4, & + ipiv[1], &c__1); + +/* Compute block row of U. */ + + i__3 = *n - j - jb + 1; + dtrsm_("Left", "Lower", "No transpose", "Unit", &jb, &i__3, & + c_b15, &a[j + j * a_dim1], lda, &a[j + (j + jb) * + a_dim1], lda); + if (j + jb <= *m) { + +/* Update trailing submatrix. */ + + i__3 = *m - j - jb + 1; + i__4 = *n - j - jb + 1; + dgemm_("No transpose", "No transpose", &i__3, &i__4, &jb, + &c_b151, &a[j + jb + j * a_dim1], lda, &a[j + (j + + jb) * a_dim1], lda, &c_b15, &a[j + jb + (j + jb) + * a_dim1], lda); + } + } +/* L20: */ + } + } + return 0; + +/* End of DGETRF */ + +} /* dgetrf_ */ + +/* Subroutine */ int dgetrs_(char *trans, integer *n, integer *nrhs, + doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer * + ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *), xerbla_( + char *, integer *), dlaswp_(integer *, doublereal *, + integer *, integer *, integer *, integer *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DGETRS solves a system of linear equations + A * X = B or A' * X = B + with a general N-by-N matrix A using the LU factorization computed + by DGETRF. + + Arguments + ========= + + TRANS (input) CHARACTER*1 + Specifies the form of the system of equations: + = 'N': A * X = B (No transpose) + = 'T': A'* X = B (Transpose) + = 'C': A'* X = B (Conjugate transpose = Transpose) + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The factors L and U from the factorization A = P*L*U + as computed by DGETRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (input) INTEGER array, dimension (N) + The pivot indices from DGETRF; for 1<=i<=N, row i of the + matrix was interchanged with row IPIV(i). + + B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + notran = lsame_(trans, "N"); + if (! notran && ! lsame_(trans, "T") && ! lsame_( + trans, "C")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DGETRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (notran) { + +/* + Solve A * X = B. + + Apply row interchanges to the right hand sides. +*/ + + dlaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c__1); + +/* Solve L*X = B, overwriting B with X. */ + + dtrsm_("Left", "Lower", "No transpose", "Unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + dtrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b15, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A' * X = B. + + Solve U'*X = B, overwriting B with X. +*/ + + dtrsm_("Left", "Upper", "Transpose", "Non-unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + dtrsm_("Left", "Lower", "Transpose", "Unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Apply row interchanges to the solution vectors. */ + + dlaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c_n1); + } + + return 0; + +/* End of DGETRS */ + +} /* dgetrs_ */ + +/* Subroutine */ int dhseqr_(char *job, char *compz, integer *n, integer *ilo, + integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, + doublereal *wi, doublereal *z__, integer *ldz, doublereal *work, + integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2[2], i__3; + doublereal d__1; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static doublereal hl[2401] /* was [49][49] */; + static integer kbot, nmin; + extern logical lsame_(char *, char *); + static logical initz; + static doublereal workl[49]; + static logical wantt, wantz; + extern /* Subroutine */ int dlaqr0_(logical *, logical *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + doublereal *, integer *, integer *), dlahqr_(logical *, logical *, + integer *, integer *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dlacpy_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *), + dlaset_(char *, integer *, integer *, doublereal *, doublereal *, + doublereal *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical lquery; + + +/* + -- LAPACK computational routine (version 3.2.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + June 2010 + + Purpose + ======= + + DHSEQR computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**T, where T is an upper quasi-triangular matrix (the + Schur form), and Z is the orthogonal matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input orthogonal + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the orthogonal matrix Q: A = Q*H*Q**T = (QZ)*T*(QZ)**T. + + Arguments + ========= + + JOB (input) CHARACTER*1 + = 'E': compute eigenvalues only; + = 'S': compute eigenvalues and the Schur form T. + + COMPZ (input) CHARACTER*1 + = 'N': no Schur vectors are computed; + = 'I': Z is initialized to the unit matrix and the matrix Z + of Schur vectors of H is returned; + = 'V': Z must contain an orthogonal matrix Q on entry, and + the product Q*Z is returned. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to DGEBAL, and then passed to DGEHRD + when the matrix output by DGEBAL is reduced to Hessenberg + form. Otherwise ILO and IHI should be set to 1 and N + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) DOUBLE PRECISION array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and JOB = 'S', then H contains the + upper quasi-triangular matrix T from the Schur decomposition + (the Schur form); 2-by-2 diagonal blocks (corresponding to + complex conjugate pairs of eigenvalues) are returned in + standard form, with H(i,i) = H(i+1,i+1) and + H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and JOB = 'E', the + contents of H are unspecified on exit. (The output value of + H when INFO.GT.0 is given under the description of INFO + below.) + + Unlike earlier versions of DHSEQR, this subroutine may + explicitly H(i,j) = 0 for i.GT.j and j = 1, 2, ... ILO-1 + or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + WR (output) DOUBLE PRECISION array, dimension (N) + WI (output) DOUBLE PRECISION array, dimension (N) + The real and imaginary parts, respectively, of the computed + eigenvalues. If two eigenvalues are computed as a complex + conjugate pair, they are stored in consecutive elements of + WR and WI, say the i-th and (i+1)th, with WI(i) .GT. 0 and + WI(i+1) .LT. 0. If JOB = 'S', the eigenvalues are stored in + the same order as on the diagonal of the Schur form returned + in H, with WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 + diagonal block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and + WI(i+1) = -WI(i). + + Z (input/output) DOUBLE PRECISION array, dimension (LDZ,N) + If COMPZ = 'N', Z is not referenced. + If COMPZ = 'I', on entry Z need not be set and on exit, + if INFO = 0, Z contains the orthogonal matrix Z of the Schur + vectors of H. If COMPZ = 'V', on entry Z must contain an + N-by-N matrix Q, which is assumed to be equal to the unit + matrix except for the submatrix Z(ILO:IHI,ILO:IHI). On exit, + if INFO = 0, Z contains Q*Z. + Normally Q is the orthogonal matrix generated by DORGHR + after the call to DGEHRD which formed the Hessenberg matrix + H. (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if COMPZ = 'I' or + COMPZ = 'V', then LDZ.GE.MAX(1,N). Otherwize, LDZ.GE.1. + + WORK (workspace/output) DOUBLE PRECISION array, dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient and delivers very good and sometimes + optimal performance. However, LWORK as large as 11*N + may be required for optimal performance. A workspace + query is recommended to determine the optimal workspace + size. + + If LWORK = -1, then DHSEQR does a workspace query. + In this case, DHSEQR checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .LT. 0: if INFO = -i, the i-th argument had an illegal + value + .GT. 0: if INFO = i, DHSEQR failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and JOB = 'E', then on exit, the + remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and JOB = 'S', then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is an orthogonal matrix. The final + value of H is upper Hessenberg and quasi-triangular + in rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and COMPZ = 'V', then on exit + + (final value of Z) = (initial value of Z)*U + + where U is the orthogonal matrix in (*) (regard- + less of the value of JOB.) + + If INFO .GT. 0 and COMPZ = 'I', then on exit + (final value of Z) = U + where U is the orthogonal matrix in (*) (regard- + less of the value of JOB.) + + If INFO .GT. 0 and COMPZ = 'N', then Z is not + accessed. + + ================================================================ + Default values supplied by + ILAENV(ISPEC,'DHSEQR',JOB(:1)//COMPZ(:1),N,ILO,IHI,LWORK). + It is suggested that these defaults be adjusted in order + to attain best performance in each particular + computational environment. + + ISPEC=12: The DLAHQR vs DLAQR0 crossover point. + Default: 75. (Must be at least 11.) + + ISPEC=13: Recommended deflation window size. + This depends on ILO, IHI and NS. NS is the + number of simultaneous shifts returned + by ILAENV(ISPEC=15). (See ISPEC=15 below.) + The default for (IHI-ILO+1).LE.500 is NS. + The default for (IHI-ILO+1).GT.500 is 3*NS/2. + + ISPEC=14: Nibble crossover point. (See IPARMQ for + details.) Default: 14% of deflation window + size. + + ISPEC=15: Number of simultaneous shifts in a multishift + QR iteration. + + If IHI-ILO+1 is ... + + greater than ...but less ... the + or equal to ... than default is + + 1 30 NS = 2(+) + 30 60 NS = 4(+) + 60 150 NS = 10(+) + 150 590 NS = ** + 590 3000 NS = 64 + 3000 6000 NS = 128 + 6000 infinity NS = 256 + + (+) By default some or all matrices of this order + are passed to the implicit double shift routine + DLAHQR and this parameter is ignored. See + ISPEC=12 above and comments in IPARMQ for + details. + + (**) The asterisks (**) indicate an ad-hoc + function of N increasing from 10 to 64. + + ISPEC=16: Select structured matrix multiply. + If the number of simultaneous shifts (specified + by ISPEC=15) is less than 14, then the default + for ISPEC=16 is 0. Otherwise the default for + ISPEC=16 is 2. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . DLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== NL allocates some local workspace to help small matrices + . through a rare DLAHQR failure. NL .GT. NTINY = 11 is + . required and NL .LE. NMIN = ILAENV(ISPEC=12,...) is recom- + . mended. (The default value of NMIN is 75.) Using NL = 49 + . allows up to six simultaneous shifts and a 16-by-16 + . deflation window. ==== + + ==== Decode and check the input parameters. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --wr; + --wi; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + wantt = lsame_(job, "S"); + initz = lsame_(compz, "I"); + wantz = initz || lsame_(compz, "V"); + work[1] = (doublereal) max(1,*n); + lquery = *lwork == -1; + + *info = 0; + if (! lsame_(job, "E") && ! wantt) { + *info = -1; + } else if (! lsame_(compz, "N") && ! wantz) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -4; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -5; + } else if (*ldh < max(1,*n)) { + *info = -7; + } else if (*ldz < 1 || wantz && *ldz < max(1,*n)) { + *info = -11; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -13; + } + + if (*info != 0) { + +/* ==== Quick return in case of invalid argument. ==== */ + + i__1 = -(*info); + xerbla_("DHSEQR", &i__1); + return 0; + + } else if (*n == 0) { + +/* ==== Quick return in case N = 0; nothing to do. ==== */ + + return 0; + + } else if (lquery) { + +/* ==== Quick return in case of a workspace query ==== */ + + dlaqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], &wi[ + 1], ilo, ihi, &z__[z_offset], ldz, &work[1], lwork, info); +/* + ==== Ensure reported workspace size is backward-compatible with + . previous LAPACK versions. ==== + Computing MAX +*/ + d__1 = (doublereal) max(1,*n); + work[1] = max(d__1,work[1]); + return 0; + + } else { + +/* ==== copy eigenvalues isolated by DGEBAL ==== */ + + i__1 = *ilo - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + wr[i__] = h__[i__ + i__ * h_dim1]; + wi[i__] = 0.; +/* L10: */ + } + i__1 = *n; + for (i__ = *ihi + 1; i__ <= i__1; ++i__) { + wr[i__] = h__[i__ + i__ * h_dim1]; + wi[i__] = 0.; +/* L20: */ + } + +/* ==== Initialize Z, if requested ==== */ + + if (initz) { + dlaset_("A", n, n, &c_b29, &c_b15, &z__[z_offset], ldz) + ; + } + +/* ==== Quick return if possible ==== */ + + if (*ilo == *ihi) { + wr[*ilo] = h__[*ilo + *ilo * h_dim1]; + wi[*ilo] = 0.; + return 0; + } + +/* + ==== DLAHQR/DLAQR0 crossover point ==== + + Writing concatenation +*/ + i__2[0] = 1, a__1[0] = job; + i__2[1] = 1, a__1[1] = compz; + s_cat(ch__1, a__1, i__2, &c__2, (ftnlen)2); + nmin = ilaenv_(&c__12, "DHSEQR", ch__1, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nmin = max(11,nmin); + +/* ==== DLAQR0 for big matrices; DLAHQR for small ones ==== */ + + if (*n > nmin) { + dlaqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], + &wi[1], ilo, ihi, &z__[z_offset], ldz, &work[1], lwork, + info); + } else { + +/* ==== Small matrix ==== */ + + dlahqr_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], + &wi[1], ilo, ihi, &z__[z_offset], ldz, info); + + if (*info > 0) { + +/* + ==== A rare DLAHQR failure! DLAQR0 sometimes succeeds + . when DLAHQR fails. ==== +*/ + + kbot = *info; + + if (*n >= 49) { + +/* + ==== Larger matrices have enough subdiagonal scratch + . space to call DLAQR0 directly. ==== +*/ + + dlaqr0_(&wantt, &wantz, n, ilo, &kbot, &h__[h_offset], + ldh, &wr[1], &wi[1], ilo, ihi, &z__[z_offset], + ldz, &work[1], lwork, info); + + } else { + +/* + ==== Tiny matrices don't have enough subdiagonal + . scratch space to benefit from DLAQR0. Hence, + . tiny matrices must be copied into a larger + . array before calling DLAQR0. ==== +*/ + + dlacpy_("A", n, n, &h__[h_offset], ldh, hl, &c__49); + hl[*n + 1 + *n * 49 - 50] = 0.; + i__1 = 49 - *n; + dlaset_("A", &c__49, &i__1, &c_b29, &c_b29, &hl[(*n + 1) * + 49 - 49], &c__49); + dlaqr0_(&wantt, &wantz, &c__49, ilo, &kbot, hl, &c__49, & + wr[1], &wi[1], ilo, ihi, &z__[z_offset], ldz, + workl, &c__49, info); + if (wantt || *info != 0) { + dlacpy_("A", n, n, hl, &c__49, &h__[h_offset], ldh); + } + } + } + } + +/* ==== Clear out the trash, if necessary. ==== */ + + if ((wantt || *info != 0) && *n > 2) { + i__1 = *n - 2; + i__3 = *n - 2; + dlaset_("L", &i__1, &i__3, &c_b29, &c_b29, &h__[h_dim1 + 3], ldh); + } + +/* + ==== Ensure reported workspace size is backward-compatible with + . previous LAPACK versions. ==== + + Computing MAX +*/ + d__1 = (doublereal) max(1,*n); + work[1] = max(d__1,work[1]); + } + +/* ==== End of DHSEQR ==== */ + + return 0; +} /* dhseqr_ */ + +logical disnan_(doublereal *din) +{ + /* System generated locals */ + logical ret_val; + + /* Local variables */ + extern logical dlaisnan_(doublereal *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DISNAN returns .TRUE. if its argument is NaN, and .FALSE. + otherwise. To be replaced by the Fortran 2003 intrinsic in the + future. + + Arguments + ========= + + DIN (input) DOUBLE PRECISION + Input to test for NaN. + + ===================================================================== +*/ + + ret_val = dlaisnan_(din, din); + return ret_val; +} /* disnan_ */ + +/* Subroutine */ int dlabad_(doublereal *small, doublereal *large) +{ + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLABAD takes as input the values computed by DLAMCH for underflow and + overflow, and returns the square root of each of these values if the + log of LARGE is sufficiently large. This subroutine is intended to + identify machines with a large exponent range, such as the Crays, and + redefine the underflow and overflow limits to be the square roots of + the values computed by DLAMCH. This subroutine is needed because + DLAMCH does not compensate for poor arithmetic in the upper half of + the exponent range, as is found on a Cray. + + Arguments + ========= + + SMALL (input/output) DOUBLE PRECISION + On entry, the underflow threshold as computed by DLAMCH. + On exit, if LOG10(LARGE) is sufficiently large, the square + root of SMALL, otherwise unchanged. + + LARGE (input/output) DOUBLE PRECISION + On entry, the overflow threshold as computed by DLAMCH. + On exit, if LOG10(LARGE) is sufficiently large, the square + root of LARGE, otherwise unchanged. + + ===================================================================== + + + If it looks like we're on a Cray, take the square root of + SMALL and LARGE to avoid overflow and underflow problems. +*/ + + if (d_lg10(large) > 2e3) { + *small = sqrt(*small); + *large = sqrt(*large); + } + + return 0; + +/* End of DLABAD */ + +} /* dlabad_ */ + +/* Subroutine */ int dlabrd_(integer *m, integer *n, integer *nb, doublereal * + a, integer *lda, doublereal *d__, doublereal *e, doublereal *tauq, + doublereal *taup, doublereal *x, integer *ldx, doublereal *y, integer + *ldy) +{ + /* System generated locals */ + integer a_dim1, a_offset, x_dim1, x_offset, y_dim1, y_offset, i__1, i__2, + i__3; + + /* Local variables */ + static integer i__; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *), dgemv_(char *, integer *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *), dlarfg_(integer *, doublereal *, + doublereal *, integer *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLABRD reduces the first NB rows and columns of a real general + m by n matrix A to upper or lower bidiagonal form by an orthogonal + transformation Q' * A * P, and returns the matrices X and Y which + are needed to apply the transformation to the unreduced part of A. + + If m >= n, A is reduced to upper bidiagonal form; if m < n, to lower + bidiagonal form. + + This is an auxiliary routine called by DGEBRD + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. + + N (input) INTEGER + The number of columns in the matrix A. + + NB (input) INTEGER + The number of leading rows and columns of A to be reduced. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the m by n general matrix to be reduced. + On exit, the first NB rows and columns of the matrix are + overwritten; the rest of the array is unchanged. + If m >= n, elements on and below the diagonal in the first NB + columns, with the array TAUQ, represent the orthogonal + matrix Q as a product of elementary reflectors; and + elements above the diagonal in the first NB rows, with the + array TAUP, represent the orthogonal matrix P as a product + of elementary reflectors. + If m < n, elements below the diagonal in the first NB + columns, with the array TAUQ, represent the orthogonal + matrix Q as a product of elementary reflectors, and + elements on and above the diagonal in the first NB rows, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) DOUBLE PRECISION array, dimension (NB) + The diagonal elements of the first NB rows and columns of + the reduced matrix. D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (NB) + The off-diagonal elements of the first NB rows and columns of + the reduced matrix. + + TAUQ (output) DOUBLE PRECISION array dimension (NB) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix Q. See Further Details. + + TAUP (output) DOUBLE PRECISION array, dimension (NB) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix P. See Further Details. + + X (output) DOUBLE PRECISION array, dimension (LDX,NB) + The m-by-nb matrix X required to update the unreduced part + of A. + + LDX (input) INTEGER + The leading dimension of the array X. LDX >= M. + + Y (output) DOUBLE PRECISION array, dimension (LDY,NB) + The n-by-nb matrix Y required to update the unreduced part + of A. + + LDY (input) INTEGER + The leading dimension of the array Y. LDY >= N. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + Q = H(1) H(2) . . . H(nb) and P = G(1) G(2) . . . G(nb) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors. + + If m >= n, v(1:i-1) = 0, v(i) = 1, and v(i:m) is stored on exit in + A(i:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+1:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, v(1:i) = 0, v(i+1) = 1, and v(i+1:m) is stored on exit in + A(i+2:m,i); u(1:i-1) = 0, u(i) = 1, and u(i:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + The elements of the vectors v and u together form the m-by-nb matrix + V and the nb-by-n matrix U' which are needed, with X and Y, to apply + the transformation to the unreduced part of the matrix, using a block + update of the form: A := A - V*Y' - X*U'. + + The contents of A on exit are illustrated by the following examples + with nb = 2: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( 1 1 u1 u1 u1 ) ( 1 u1 u1 u1 u1 u1 ) + ( v1 1 1 u2 u2 ) ( 1 1 u2 u2 u2 u2 ) + ( v1 v2 a a a ) ( v1 1 a a a a ) + ( v1 v2 a a a ) ( v1 v2 a a a a ) + ( v1 v2 a a a ) ( v1 v2 a a a a ) + ( v1 v2 a a a ) + + where a denotes an element of the original matrix which is unchanged, + vi denotes an element of the vector defining H(i), and ui an element + of the vector defining G(i). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + y_dim1 = *ldy; + y_offset = 1 + y_dim1; + y -= y_offset; + + /* Function Body */ + if (*m <= 0 || *n <= 0) { + return 0; + } + + if (*m >= *n) { + +/* Reduce to upper bidiagonal form */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i:m,i) */ + + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + a_dim1], + lda, &y[i__ + y_dim1], ldy, &c_b15, &a[i__ + i__ * a_dim1] + , &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &x[i__ + x_dim1], + ldx, &a[i__ * a_dim1 + 1], &c__1, &c_b15, &a[i__ + i__ * + a_dim1], &c__1); + +/* Generate reflection Q(i) to annihilate A(i+1:m,i) */ + + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + dlarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * + a_dim1], &c__1, &tauq[i__]); + d__[i__] = a[i__ + i__ * a_dim1]; + if (i__ < *n) { + a[i__ + i__ * a_dim1] = 1.; + +/* Compute Y(i+1:n,i) */ + + i__2 = *m - i__ + 1; + i__3 = *n - i__; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + (i__ + 1) * + a_dim1], lda, &a[i__ + i__ * a_dim1], &c__1, &c_b29, + &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + a_dim1], + lda, &a[i__ + i__ * a_dim1], &c__1, &c_b29, &y[i__ * + y_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &y[i__ + 1 + + y_dim1], ldy, &y[i__ * y_dim1 + 1], &c__1, &c_b15, &y[ + i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &x[i__ + x_dim1], + ldx, &a[i__ + i__ * a_dim1], &c__1, &c_b29, &y[i__ * + y_dim1 + 1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + dgemv_("Transpose", &i__2, &i__3, &c_b151, &a[(i__ + 1) * + a_dim1 + 1], lda, &y[i__ * y_dim1 + 1], &c__1, &c_b15, + &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *n - i__; + dscal_(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1); + +/* Update A(i,i+1:n) */ + + i__2 = *n - i__; + dgemv_("No transpose", &i__2, &i__, &c_b151, &y[i__ + 1 + + y_dim1], ldy, &a[i__ + a_dim1], lda, &c_b15, &a[i__ + + (i__ + 1) * a_dim1], lda); + i__2 = i__ - 1; + i__3 = *n - i__; + dgemv_("Transpose", &i__2, &i__3, &c_b151, &a[(i__ + 1) * + a_dim1 + 1], lda, &x[i__ + x_dim1], ldx, &c_b15, &a[ + i__ + (i__ + 1) * a_dim1], lda); + +/* Generate reflection P(i) to annihilate A(i,i+2:n) */ + + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + dlarfg_(&i__2, &a[i__ + (i__ + 1) * a_dim1], &a[i__ + min( + i__3,*n) * a_dim1], lda, &taup[i__]); + e[i__] = a[i__ + (i__ + 1) * a_dim1]; + a[i__ + (i__ + 1) * a_dim1] = 1.; + +/* Compute X(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = *n - i__; + dgemv_("No transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + ( + i__ + 1) * a_dim1], lda, &a[i__ + (i__ + 1) * a_dim1], + lda, &c_b29, &x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__; + dgemv_("Transpose", &i__2, &i__, &c_b15, &y[i__ + 1 + y_dim1], + ldy, &a[i__ + (i__ + 1) * a_dim1], lda, &c_b29, &x[ + i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + dgemv_("No transpose", &i__2, &i__, &c_b151, &a[i__ + 1 + + a_dim1], lda, &x[i__ * x_dim1 + 1], &c__1, &c_b15, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + dgemv_("No transpose", &i__2, &i__3, &c_b15, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b29, &x[i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &x[i__ + 1 + + x_dim1], ldx, &x[i__ * x_dim1 + 1], &c__1, &c_b15, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *m - i__; + dscal_(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1); + } +/* L10: */ + } + } else { + +/* Reduce to lower bidiagonal form */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i,i:n) */ + + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &y[i__ + y_dim1], + ldy, &a[i__ + a_dim1], lda, &c_b15, &a[i__ + i__ * a_dim1] + , lda); + i__2 = i__ - 1; + i__3 = *n - i__ + 1; + dgemv_("Transpose", &i__2, &i__3, &c_b151, &a[i__ * a_dim1 + 1], + lda, &x[i__ + x_dim1], ldx, &c_b15, &a[i__ + i__ * a_dim1] + , lda); + +/* Generate reflection P(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + dlarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[i__ + min(i__3,*n) * + a_dim1], lda, &taup[i__]); + d__[i__] = a[i__ + i__ * a_dim1]; + if (i__ < *m) { + a[i__ + i__ * a_dim1] = 1.; + +/* Compute X(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = *n - i__ + 1; + dgemv_("No transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + i__ + * a_dim1], lda, &a[i__ + i__ * a_dim1], lda, &c_b29, & + x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &y[i__ + y_dim1], + ldy, &a[i__ + i__ * a_dim1], lda, &c_b29, &x[i__ * + x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + 1 + + a_dim1], lda, &x[i__ * x_dim1 + 1], &c__1, &c_b15, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__ + 1; + dgemv_("No transpose", &i__2, &i__3, &c_b15, &a[i__ * a_dim1 + + 1], lda, &a[i__ + i__ * a_dim1], lda, &c_b29, &x[ + i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &x[i__ + 1 + + x_dim1], ldx, &x[i__ * x_dim1 + 1], &c__1, &c_b15, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *m - i__; + dscal_(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1); + +/* Update A(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + 1 + + a_dim1], lda, &y[i__ + y_dim1], ldy, &c_b15, &a[i__ + + 1 + i__ * a_dim1], &c__1); + i__2 = *m - i__; + dgemv_("No transpose", &i__2, &i__, &c_b151, &x[i__ + 1 + + x_dim1], ldx, &a[i__ * a_dim1 + 1], &c__1, &c_b15, &a[ + i__ + 1 + i__ * a_dim1], &c__1); + +/* Generate reflection Q(i) to annihilate A(i+2:m,i) */ + + i__2 = *m - i__; +/* Computing MIN */ + i__3 = i__ + 2; + dlarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*m) + + i__ * a_dim1], &c__1, &tauq[i__]); + e[i__] = a[i__ + 1 + i__ * a_dim1]; + a[i__ + 1 + i__ * a_dim1] = 1.; + +/* Compute Y(i+1:n,i) */ + + i__2 = *m - i__; + i__3 = *n - i__; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + (i__ + + 1) * a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, + &c_b29, &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + a_dim1] + , lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &y[ + i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &y[i__ + 1 + + y_dim1], ldy, &y[i__ * y_dim1 + 1], &c__1, &c_b15, &y[ + i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__; + dgemv_("Transpose", &i__2, &i__, &c_b15, &x[i__ + 1 + x_dim1], + ldx, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &y[ + i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + dgemv_("Transpose", &i__, &i__2, &c_b151, &a[(i__ + 1) * + a_dim1 + 1], lda, &y[i__ * y_dim1 + 1], &c__1, &c_b15, + &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *n - i__; + dscal_(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1); + } +/* L20: */ + } + } + return 0; + +/* End of DLABRD */ + +} /* dlabrd_ */ + +/* Subroutine */ int dlacpy_(char *uplo, integer *m, integer *n, doublereal * + a, integer *lda, doublereal *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLACPY copies all or part of a two-dimensional matrix A to another + matrix B. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be copied to B. + = 'U': Upper triangular part + = 'L': Lower triangular part + Otherwise: All of the matrix A + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The m by n matrix A. If UPLO = 'U', only the upper triangle + or trapezoid is accessed; if UPLO = 'L', only the lower + triangle or trapezoid is accessed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + B (output) DOUBLE PRECISION array, dimension (LDB,N) + On exit, B = A in the locations specified by UPLO. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = a[i__ + j * a_dim1]; +/* L10: */ + } +/* L20: */ + } + } else if (lsame_(uplo, "L")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = a[i__ + j * a_dim1]; +/* L30: */ + } +/* L40: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = a[i__ + j * a_dim1]; +/* L50: */ + } +/* L60: */ + } + } + return 0; + +/* End of DLACPY */ + +} /* dlacpy_ */ + +/* Subroutine */ int dladiv_(doublereal *a, doublereal *b, doublereal *c__, + doublereal *d__, doublereal *p, doublereal *q) +{ + static doublereal e, f; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLADIV performs complex division in real arithmetic + + a + i*b + p + i*q = --------- + c + i*d + + The algorithm is due to Robert L. Smith and can be found + in D. Knuth, The art of Computer Programming, Vol.2, p.195 + + Arguments + ========= + + A (input) DOUBLE PRECISION + B (input) DOUBLE PRECISION + C (input) DOUBLE PRECISION + D (input) DOUBLE PRECISION + The scalars a, b, c, and d in the above expression. + + P (output) DOUBLE PRECISION + Q (output) DOUBLE PRECISION + The scalars p and q in the above expression. + + ===================================================================== +*/ + + + if (abs(*d__) < abs(*c__)) { + e = *d__ / *c__; + f = *c__ + *d__ * e; + *p = (*a + *b * e) / f; + *q = (*b - *a * e) / f; + } else { + e = *c__ / *d__; + f = *d__ + *c__ * e; + *p = (*b + *a * e) / f; + *q = (-(*a) + *b * e) / f; + } + + return 0; + +/* End of DLADIV */ + +} /* dladiv_ */ + +/* Subroutine */ int dlae2_(doublereal *a, doublereal *b, doublereal *c__, + doublereal *rt1, doublereal *rt2) +{ + /* System generated locals */ + doublereal d__1; + + /* Local variables */ + static doublereal ab, df, tb, sm, rt, adf, acmn, acmx; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAE2 computes the eigenvalues of a 2-by-2 symmetric matrix + [ A B ] + [ B C ]. + On return, RT1 is the eigenvalue of larger absolute value, and RT2 + is the eigenvalue of smaller absolute value. + + Arguments + ========= + + A (input) DOUBLE PRECISION + The (1,1) element of the 2-by-2 matrix. + + B (input) DOUBLE PRECISION + The (1,2) and (2,1) elements of the 2-by-2 matrix. + + C (input) DOUBLE PRECISION + The (2,2) element of the 2-by-2 matrix. + + RT1 (output) DOUBLE PRECISION + The eigenvalue of larger absolute value. + + RT2 (output) DOUBLE PRECISION + The eigenvalue of smaller absolute value. + + Further Details + =============== + + RT1 is accurate to a few ulps barring over/underflow. + + RT2 may be inaccurate if there is massive cancellation in the + determinant A*C-B*B; higher precision or correctly rounded or + correctly truncated arithmetic would be needed to compute RT2 + accurately in all cases. + + Overflow is possible only if RT1 is within a factor of 5 of overflow. + Underflow is harmless if the input data is 0 or exceeds + underflow_threshold / macheps. + + ===================================================================== + + + Compute the eigenvalues +*/ + + sm = *a + *c__; + df = *a - *c__; + adf = abs(df); + tb = *b + *b; + ab = abs(tb); + if (abs(*a) > abs(*c__)) { + acmx = *a; + acmn = *c__; + } else { + acmx = *c__; + acmn = *a; + } + if (adf > ab) { +/* Computing 2nd power */ + d__1 = ab / adf; + rt = adf * sqrt(d__1 * d__1 + 1.); + } else if (adf < ab) { +/* Computing 2nd power */ + d__1 = adf / ab; + rt = ab * sqrt(d__1 * d__1 + 1.); + } else { + +/* Includes case AB=ADF=0 */ + + rt = ab * sqrt(2.); + } + if (sm < 0.) { + *rt1 = (sm - rt) * .5; + +/* + Order of execution important. + To get fully accurate smaller eigenvalue, + next line needs to be executed in higher precision. +*/ + + *rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b; + } else if (sm > 0.) { + *rt1 = (sm + rt) * .5; + +/* + Order of execution important. + To get fully accurate smaller eigenvalue, + next line needs to be executed in higher precision. +*/ + + *rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b; + } else { + +/* Includes case RT1 = RT2 = 0 */ + + *rt1 = rt * .5; + *rt2 = rt * -.5; + } + return 0; + +/* End of DLAE2 */ + +} /* dlae2_ */ + +/* Subroutine */ int dlaed0_(integer *icompq, integer *qsiz, integer *n, + doublereal *d__, doublereal *e, doublereal *q, integer *ldq, + doublereal *qstore, integer *ldqs, doublereal *work, integer *iwork, + integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, qstore_dim1, qstore_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer i__, j, k, iq, lgn, msd2, smm1, spm1, spm2; + static doublereal temp; + static integer curr; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer iperm; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer indxq, iwrem; + extern /* Subroutine */ int dlaed1_(integer *, doublereal *, doublereal *, + integer *, integer *, doublereal *, integer *, doublereal *, + integer *, integer *); + static integer iqptr; + extern /* Subroutine */ int dlaed7_(integer *, integer *, integer *, + integer *, integer *, integer *, doublereal *, doublereal *, + integer *, integer *, doublereal *, integer *, doublereal *, + integer *, integer *, integer *, integer *, integer *, doublereal + *, doublereal *, integer *, integer *); + static integer tlvls; + extern /* Subroutine */ int dlacpy_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *); + static integer igivcl; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer igivnm, submat, curprb, subpbs, igivpt; + extern /* Subroutine */ int dsteqr_(char *, integer *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, integer *); + static integer curlvl, matsiz, iprmpt, smlsiz; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAED0 computes all eigenvalues and corresponding eigenvectors of a + symmetric tridiagonal matrix using the divide and conquer method. + + Arguments + ========= + + ICOMPQ (input) INTEGER + = 0: Compute eigenvalues only. + = 1: Compute eigenvectors of original dense symmetric matrix + also. On entry, Q contains the orthogonal matrix used + to reduce the original matrix to tridiagonal form. + = 2: Compute eigenvalues and eigenvectors of tridiagonal + matrix. + + QSIZ (input) INTEGER + The dimension of the orthogonal matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N if ICOMPQ = 1. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the main diagonal of the tridiagonal matrix. + On exit, its eigenvalues. + + E (input) DOUBLE PRECISION array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix. + On exit, E has been destroyed. + + Q (input/output) DOUBLE PRECISION array, dimension (LDQ, N) + On entry, Q must contain an N-by-N orthogonal matrix. + If ICOMPQ = 0 Q is not referenced. + If ICOMPQ = 1 On entry, Q is a subset of the columns of the + orthogonal matrix used to reduce the full + matrix to tridiagonal form corresponding to + the subset of the full matrix which is being + decomposed at this time. + If ICOMPQ = 2 On entry, Q will be the identity matrix. + On exit, Q contains the eigenvectors of the + tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. If eigenvectors are + desired, then LDQ >= max(1,N). In any case, LDQ >= 1. + + QSTORE (workspace) DOUBLE PRECISION array, dimension (LDQS, N) + Referenced only when ICOMPQ = 1. Used to store parts of + the eigenvector matrix when the updating matrix multiplies + take place. + + LDQS (input) INTEGER + The leading dimension of the array QSTORE. If ICOMPQ = 1, + then LDQS >= max(1,N). In any case, LDQS >= 1. + + WORK (workspace) DOUBLE PRECISION array, + If ICOMPQ = 0 or 1, the dimension of WORK must be at least + 1 + 3*N + 2*N*lg N + 2*N**2 + ( lg( N ) = smallest integer k + such that 2^k >= N ) + If ICOMPQ = 2, the dimension of WORK must be at least + 4*N + N**2. + + IWORK (workspace) INTEGER array, + If ICOMPQ = 0 or 1, the dimension of IWORK must be at least + 6 + 6*N + 5*N*lg N. + ( lg( N ) = smallest integer k + such that 2^k >= N ) + If ICOMPQ = 2, the dimension of IWORK must be at least + 3 + 5*N. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute an eigenvalue while + working on the submatrix lying in rows and columns + INFO/(N+1) through mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + qstore_dim1 = *ldqs; + qstore_offset = 1 + qstore_dim1; + qstore -= qstore_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 2) { + *info = -1; + } else if (*icompq == 1 && *qsiz < max(0,*n)) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ldq < max(1,*n)) { + *info = -7; + } else if (*ldqs < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAED0", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + smlsiz = ilaenv_(&c__9, "DLAED0", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + +/* + Determine the size and placement of the submatrices, and save in + the leading elements of IWORK. +*/ + + iwork[1] = *n; + subpbs = 1; + tlvls = 0; +L10: + if (iwork[subpbs] > smlsiz) { + for (j = subpbs; j >= 1; --j) { + iwork[j * 2] = (iwork[j] + 1) / 2; + iwork[(j << 1) - 1] = iwork[j] / 2; +/* L20: */ + } + ++tlvls; + subpbs <<= 1; + goto L10; + } + i__1 = subpbs; + for (j = 2; j <= i__1; ++j) { + iwork[j] += iwork[j - 1]; +/* L30: */ + } + +/* + Divide the matrix into SUBPBS submatrices of size at most SMLSIZ+1 + using rank-1 modifications (cuts). +*/ + + spm1 = subpbs - 1; + i__1 = spm1; + for (i__ = 1; i__ <= i__1; ++i__) { + submat = iwork[i__] + 1; + smm1 = submat - 1; + d__[smm1] -= (d__1 = e[smm1], abs(d__1)); + d__[submat] -= (d__1 = e[smm1], abs(d__1)); +/* L40: */ + } + + indxq = (*n << 2) + 3; + if (*icompq != 2) { + +/* + Set up workspaces for eigenvalues only/accumulate new vectors + routine +*/ + + temp = log((doublereal) (*n)) / log(2.); + lgn = (integer) temp; + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + iprmpt = indxq + *n + 1; + iperm = iprmpt + *n * lgn; + iqptr = iperm + *n * lgn; + igivpt = iqptr + *n + 2; + igivcl = igivpt + *n * lgn; + + igivnm = 1; + iq = igivnm + (*n << 1) * lgn; +/* Computing 2nd power */ + i__1 = *n; + iwrem = iq + i__1 * i__1 + 1; + +/* Initialize pointers */ + + i__1 = subpbs; + for (i__ = 0; i__ <= i__1; ++i__) { + iwork[iprmpt + i__] = 1; + iwork[igivpt + i__] = 1; +/* L50: */ + } + iwork[iqptr] = 1; + } + +/* + Solve each submatrix eigenproblem at the bottom of the divide and + conquer tree. +*/ + + curr = 0; + i__1 = spm1; + for (i__ = 0; i__ <= i__1; ++i__) { + if (i__ == 0) { + submat = 1; + matsiz = iwork[1]; + } else { + submat = iwork[i__] + 1; + matsiz = iwork[i__ + 1] - iwork[i__]; + } + if (*icompq == 2) { + dsteqr_("I", &matsiz, &d__[submat], &e[submat], &q[submat + + submat * q_dim1], ldq, &work[1], info); + if (*info != 0) { + goto L130; + } + } else { + dsteqr_("I", &matsiz, &d__[submat], &e[submat], &work[iq - 1 + + iwork[iqptr + curr]], &matsiz, &work[1], info); + if (*info != 0) { + goto L130; + } + if (*icompq == 1) { + dgemm_("N", "N", qsiz, &matsiz, &matsiz, &c_b15, &q[submat * + q_dim1 + 1], ldq, &work[iq - 1 + iwork[iqptr + curr]], + &matsiz, &c_b29, &qstore[submat * qstore_dim1 + 1], + ldqs); + } +/* Computing 2nd power */ + i__2 = matsiz; + iwork[iqptr + curr + 1] = iwork[iqptr + curr] + i__2 * i__2; + ++curr; + } + k = 1; + i__2 = iwork[i__ + 1]; + for (j = submat; j <= i__2; ++j) { + iwork[indxq + j] = k; + ++k; +/* L60: */ + } +/* L70: */ + } + +/* + Successively merge eigensystems of adjacent submatrices + into eigensystem for the corresponding larger matrix. + + while ( SUBPBS > 1 ) +*/ + + curlvl = 1; +L80: + if (subpbs > 1) { + spm2 = subpbs - 2; + i__1 = spm2; + for (i__ = 0; i__ <= i__1; i__ += 2) { + if (i__ == 0) { + submat = 1; + matsiz = iwork[2]; + msd2 = iwork[1]; + curprb = 0; + } else { + submat = iwork[i__] + 1; + matsiz = iwork[i__ + 2] - iwork[i__]; + msd2 = matsiz / 2; + ++curprb; + } + +/* + Merge lower order eigensystems (of size MSD2 and MATSIZ - MSD2) + into an eigensystem of size MATSIZ. + DLAED1 is used only for the full eigensystem of a tridiagonal + matrix. + DLAED7 handles the cases in which eigenvalues only or eigenvalues + and eigenvectors of a full symmetric matrix (which was reduced to + tridiagonal form) are desired. +*/ + + if (*icompq == 2) { + dlaed1_(&matsiz, &d__[submat], &q[submat + submat * q_dim1], + ldq, &iwork[indxq + submat], &e[submat + msd2 - 1], & + msd2, &work[1], &iwork[subpbs + 1], info); + } else { + dlaed7_(icompq, &matsiz, qsiz, &tlvls, &curlvl, &curprb, &d__[ + submat], &qstore[submat * qstore_dim1 + 1], ldqs, & + iwork[indxq + submat], &e[submat + msd2 - 1], &msd2, & + work[iq], &iwork[iqptr], &iwork[iprmpt], &iwork[iperm] + , &iwork[igivpt], &iwork[igivcl], &work[igivnm], & + work[iwrem], &iwork[subpbs + 1], info); + } + if (*info != 0) { + goto L130; + } + iwork[i__ / 2 + 1] = iwork[i__ + 2]; +/* L90: */ + } + subpbs /= 2; + ++curlvl; + goto L80; + } + +/* + end while + + Re-merge the eigenvalues/vectors which were deflated at the final + merge step. +*/ + + if (*icompq == 1) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + j = iwork[indxq + i__]; + work[i__] = d__[j]; + dcopy_(qsiz, &qstore[j * qstore_dim1 + 1], &c__1, &q[i__ * q_dim1 + + 1], &c__1); +/* L100: */ + } + dcopy_(n, &work[1], &c__1, &d__[1], &c__1); + } else if (*icompq == 2) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + j = iwork[indxq + i__]; + work[i__] = d__[j]; + dcopy_(n, &q[j * q_dim1 + 1], &c__1, &work[*n * i__ + 1], &c__1); +/* L110: */ + } + dcopy_(n, &work[1], &c__1, &d__[1], &c__1); + dlacpy_("A", n, n, &work[*n + 1], n, &q[q_offset], ldq); + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + j = iwork[indxq + i__]; + work[i__] = d__[j]; +/* L120: */ + } + dcopy_(n, &work[1], &c__1, &d__[1], &c__1); + } + goto L140; + +L130: + *info = submat * (*n + 1) + submat + matsiz - 1; + +L140: + return 0; + +/* End of DLAED0 */ + +} /* dlaed0_ */ + +/* Subroutine */ int dlaed1_(integer *n, doublereal *d__, doublereal *q, + integer *ldq, integer *indxq, doublereal *rho, integer *cutpnt, + doublereal *work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + + /* Local variables */ + static integer i__, k, n1, n2, is, iw, iz, iq2, zpp1, indx, indxc; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer indxp; + extern /* Subroutine */ int dlaed2_(integer *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *, + integer *, integer *, integer *, integer *), dlaed3_(integer *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, doublereal *, doublereal *, integer *, integer *, + doublereal *, doublereal *, integer *); + static integer idlmda; + extern /* Subroutine */ int dlamrg_(integer *, integer *, doublereal *, + integer *, integer *, integer *), xerbla_(char *, integer *); + static integer coltyp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAED1 computes the updated eigensystem of a diagonal + matrix after modification by a rank-one symmetric matrix. This + routine is used only for the eigenproblem which requires all + eigenvalues and eigenvectors of a tridiagonal matrix. DLAED7 handles + the case in which eigenvalues only or eigenvalues and eigenvectors + of a full symmetric matrix (which was reduced to tridiagonal form) + are desired. + + T = Q(in) ( D(in) + RHO * Z*Z' ) Q'(in) = Q(out) * D(out) * Q'(out) + + where Z = Q'u, u is a vector of length N with ones in the + CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. + + The eigenvectors of the original matrix are stored in Q, and the + eigenvalues are in D. The algorithm consists of three stages: + + The first stage consists of deflating the size of the problem + when there are multiple eigenvalues or if there is a zero in + the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine DLAED2. + + The second stage consists of calculating the updated + eigenvalues. This is done by finding the roots of the secular + equation via the routine DLAED4 (as called by DLAED3). + This routine also calculates the eigenvectors of the current + problem. + + The final stage consists of computing the updated eigenvectors + directly using the updated eigenvalues. The eigenvectors for + the current problem are multiplied with the eigenvectors from + the overall problem. + + Arguments + ========= + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the eigenvalues of the rank-1-perturbed matrix. + On exit, the eigenvalues of the repaired matrix. + + Q (input/output) DOUBLE PRECISION array, dimension (LDQ,N) + On entry, the eigenvectors of the rank-1-perturbed matrix. + On exit, the eigenvectors of the repaired tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + INDXQ (input/output) INTEGER array, dimension (N) + On entry, the permutation which separately sorts the two + subproblems in D into ascending order. + On exit, the permutation which will reintegrate the + subproblems back into sorted order, + i.e. D( INDXQ( I = 1, N ) ) will be in ascending order. + + RHO (input) DOUBLE PRECISION + The subdiagonal entry used to create the rank-1 modification. + + CUTPNT (input) INTEGER + The location of the last eigenvalue in the leading sub-matrix. + min(1,N) <= CUTPNT <= N/2. + + WORK (workspace) DOUBLE PRECISION array, dimension (4*N + N**2) + + IWORK (workspace) INTEGER array, dimension (4*N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -1; + } else if (*ldq < max(1,*n)) { + *info = -4; + } else /* if(complicated condition) */ { +/* Computing MIN */ + i__1 = 1, i__2 = *n / 2; + if (min(i__1,i__2) > *cutpnt || *n / 2 < *cutpnt) { + *info = -7; + } + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAED1", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* + The following values are integer pointers which indicate + the portion of the workspace + used by a particular array in DLAED2 and DLAED3. +*/ + + iz = 1; + idlmda = iz + *n; + iw = idlmda + *n; + iq2 = iw + *n; + + indx = 1; + indxc = indx + *n; + coltyp = indxc + *n; + indxp = coltyp + *n; + + +/* + Form the z-vector which consists of the last row of Q_1 and the + first row of Q_2. +*/ + + dcopy_(cutpnt, &q[*cutpnt + q_dim1], ldq, &work[iz], &c__1); + zpp1 = *cutpnt + 1; + i__1 = *n - *cutpnt; + dcopy_(&i__1, &q[zpp1 + zpp1 * q_dim1], ldq, &work[iz + *cutpnt], &c__1); + +/* Deflate eigenvalues. */ + + dlaed2_(&k, n, cutpnt, &d__[1], &q[q_offset], ldq, &indxq[1], rho, &work[ + iz], &work[idlmda], &work[iw], &work[iq2], &iwork[indx], &iwork[ + indxc], &iwork[indxp], &iwork[coltyp], info); + + if (*info != 0) { + goto L20; + } + +/* Solve Secular Equation. */ + + if (k != 0) { + is = (iwork[coltyp] + iwork[coltyp + 1]) * *cutpnt + (iwork[coltyp + + 1] + iwork[coltyp + 2]) * (*n - *cutpnt) + iq2; + dlaed3_(&k, n, cutpnt, &d__[1], &q[q_offset], ldq, rho, &work[idlmda], + &work[iq2], &iwork[indxc], &iwork[coltyp], &work[iw], &work[ + is], info); + if (*info != 0) { + goto L20; + } + +/* Prepare the INDXQ sorting permutation. */ + + n1 = k; + n2 = *n - k; + dlamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &indxq[1]); + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + indxq[i__] = i__; +/* L10: */ + } + } + +L20: + return 0; + +/* End of DLAED1 */ + +} /* dlaed1_ */ + +/* Subroutine */ int dlaed2_(integer *k, integer *n, integer *n1, doublereal * + d__, doublereal *q, integer *ldq, integer *indxq, doublereal *rho, + doublereal *z__, doublereal *dlamda, doublereal *w, doublereal *q2, + integer *indx, integer *indxc, integer *indxp, integer *coltyp, + integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + doublereal d__1, d__2, d__3, d__4; + + /* Local variables */ + static doublereal c__; + static integer i__, j; + static doublereal s, t; + static integer k2, n2, ct, nj, pj, js, iq1, iq2, n1p1; + static doublereal eps, tau, tol; + static integer psm[4], imax, jmax; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *); + static integer ctot[4]; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *), dcopy_(integer *, doublereal *, integer *, doublereal + *, integer *); + + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dlamrg_(integer *, integer *, doublereal *, + integer *, integer *, integer *), dlacpy_(char *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAED2 merges the two sets of eigenvalues together into a single + sorted set. Then it tries to deflate the size of the problem. + There are two ways in which deflation can occur: when two or more + eigenvalues are close together or if there is a tiny entry in the + Z vector. For each such occurrence the order of the related secular + equation problem is reduced by one. + + Arguments + ========= + + K (output) INTEGER + The number of non-deflated eigenvalues, and the order of the + related secular equation. 0 <= K <=N. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + N1 (input) INTEGER + The location of the last eigenvalue in the leading sub-matrix. + min(1,N) <= N1 <= N/2. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, D contains the eigenvalues of the two submatrices to + be combined. + On exit, D contains the trailing (N-K) updated eigenvalues + (those which were deflated) sorted into increasing order. + + Q (input/output) DOUBLE PRECISION array, dimension (LDQ, N) + On entry, Q contains the eigenvectors of two submatrices in + the two square blocks with corners at (1,1), (N1,N1) + and (N1+1, N1+1), (N,N). + On exit, Q contains the trailing (N-K) updated eigenvectors + (those which were deflated) in its last N-K columns. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + INDXQ (input/output) INTEGER array, dimension (N) + The permutation which separately sorts the two sub-problems + in D into ascending order. Note that elements in the second + half of this permutation must first have N1 added to their + values. Destroyed on exit. + + RHO (input/output) DOUBLE PRECISION + On entry, the off-diagonal element associated with the rank-1 + cut which originally split the two submatrices which are now + being recombined. + On exit, RHO has been modified to the value required by + DLAED3. + + Z (input) DOUBLE PRECISION array, dimension (N) + On entry, Z contains the updating vector (the last + row of the first sub-eigenvector matrix and the first row of + the second sub-eigenvector matrix). + On exit, the contents of Z have been destroyed by the updating + process. + + DLAMDA (output) DOUBLE PRECISION array, dimension (N) + A copy of the first K eigenvalues which will be used by + DLAED3 to form the secular equation. + + W (output) DOUBLE PRECISION array, dimension (N) + The first k values of the final deflation-altered z-vector + which will be passed to DLAED3. + + Q2 (output) DOUBLE PRECISION array, dimension (N1**2+(N-N1)**2) + A copy of the first K eigenvectors which will be used by + DLAED3 in a matrix multiply (DGEMM) to solve for the new + eigenvectors. + + INDX (workspace) INTEGER array, dimension (N) + The permutation used to sort the contents of DLAMDA into + ascending order. + + INDXC (output) INTEGER array, dimension (N) + The permutation used to arrange the columns of the deflated + Q matrix into three groups: the first group contains non-zero + elements only at and above N1, the second contains + non-zero elements only below N1, and the third is dense. + + INDXP (workspace) INTEGER array, dimension (N) + The permutation used to place deflated values of D at the end + of the array. INDXP(1:K) points to the nondeflated D-values + and INDXP(K+1:N) points to the deflated eigenvalues. + + COLTYP (workspace/output) INTEGER array, dimension (N) + During execution, a label which will indicate which of the + following types a column in the Q2 matrix is: + 1 : non-zero in the upper half only; + 2 : dense; + 3 : non-zero in the lower half only; + 4 : deflated. + On exit, COLTYP(i) is the number of columns of type i, + for i=1 to 4 only. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --z__; + --dlamda; + --w; + --q2; + --indx; + --indxc; + --indxp; + --coltyp; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -2; + } else if (*ldq < max(1,*n)) { + *info = -6; + } else /* if(complicated condition) */ { +/* Computing MIN */ + i__1 = 1, i__2 = *n / 2; + if (min(i__1,i__2) > *n1 || *n / 2 < *n1) { + *info = -3; + } + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAED2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + n2 = *n - *n1; + n1p1 = *n1 + 1; + + if (*rho < 0.) { + dscal_(&n2, &c_b151, &z__[n1p1], &c__1); + } + +/* + Normalize z so that norm(z) = 1. Since z is the concatenation of + two normalized vectors, norm2(z) = sqrt(2). +*/ + + t = 1. / sqrt(2.); + dscal_(n, &t, &z__[1], &c__1); + +/* RHO = ABS( norm(z)**2 * RHO ) */ + + *rho = (d__1 = *rho * 2., abs(d__1)); + +/* Sort the eigenvalues into increasing order */ + + i__1 = *n; + for (i__ = n1p1; i__ <= i__1; ++i__) { + indxq[i__] += *n1; +/* L10: */ + } + +/* re-integrate the deflated parts from the last pass */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = d__[indxq[i__]]; +/* L20: */ + } + dlamrg_(n1, &n2, &dlamda[1], &c__1, &c__1, &indxc[1]); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + indx[i__] = indxq[indxc[i__]]; +/* L30: */ + } + +/* Calculate the allowable deflation tolerance */ + + imax = idamax_(n, &z__[1], &c__1); + jmax = idamax_(n, &d__[1], &c__1); + eps = EPSILON; +/* Computing MAX */ + d__3 = (d__1 = d__[jmax], abs(d__1)), d__4 = (d__2 = z__[imax], abs(d__2)) + ; + tol = eps * 8. * max(d__3,d__4); + +/* + If the rank-1 modifier is small enough, no more needs to be done + except to reorganize Q so that its columns correspond with the + elements in D. +*/ + + if (*rho * (d__1 = z__[imax], abs(d__1)) <= tol) { + *k = 0; + iq2 = 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__ = indx[j]; + dcopy_(n, &q[i__ * q_dim1 + 1], &c__1, &q2[iq2], &c__1); + dlamda[j] = d__[i__]; + iq2 += *n; +/* L40: */ + } + dlacpy_("A", n, n, &q2[1], n, &q[q_offset], ldq); + dcopy_(n, &dlamda[1], &c__1, &d__[1], &c__1); + goto L190; + } + +/* + If there are multiple eigenvalues then the problem deflates. Here + the number of equal eigenvalues are found. As each equal + eigenvalue is found, an elementary reflector is computed to rotate + the corresponding eigensubspace so that the corresponding + components of Z are zero in this new basis. +*/ + + i__1 = *n1; + for (i__ = 1; i__ <= i__1; ++i__) { + coltyp[i__] = 1; +/* L50: */ + } + i__1 = *n; + for (i__ = n1p1; i__ <= i__1; ++i__) { + coltyp[i__] = 3; +/* L60: */ + } + + + *k = 0; + k2 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + nj = indx[j]; + if (*rho * (d__1 = z__[nj], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + coltyp[nj] = 4; + indxp[k2] = nj; + if (j == *n) { + goto L100; + } + } else { + pj = nj; + goto L80; + } +/* L70: */ + } +L80: + ++j; + nj = indx[j]; + if (j > *n) { + goto L100; + } + if (*rho * (d__1 = z__[nj], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + coltyp[nj] = 4; + indxp[k2] = nj; + } else { + +/* Check if eigenvalues are close enough to allow deflation. */ + + s = z__[pj]; + c__ = z__[nj]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = dlapy2_(&c__, &s); + t = d__[nj] - d__[pj]; + c__ /= tau; + s = -s / tau; + if ((d__1 = t * c__ * s, abs(d__1)) <= tol) { + +/* Deflation is possible. */ + + z__[nj] = tau; + z__[pj] = 0.; + if (coltyp[nj] != coltyp[pj]) { + coltyp[nj] = 2; + } + coltyp[pj] = 4; + drot_(n, &q[pj * q_dim1 + 1], &c__1, &q[nj * q_dim1 + 1], &c__1, & + c__, &s); +/* Computing 2nd power */ + d__1 = c__; +/* Computing 2nd power */ + d__2 = s; + t = d__[pj] * (d__1 * d__1) + d__[nj] * (d__2 * d__2); +/* Computing 2nd power */ + d__1 = s; +/* Computing 2nd power */ + d__2 = c__; + d__[nj] = d__[pj] * (d__1 * d__1) + d__[nj] * (d__2 * d__2); + d__[pj] = t; + --k2; + i__ = 1; +L90: + if (k2 + i__ <= *n) { + if (d__[pj] < d__[indxp[k2 + i__]]) { + indxp[k2 + i__ - 1] = indxp[k2 + i__]; + indxp[k2 + i__] = pj; + ++i__; + goto L90; + } else { + indxp[k2 + i__ - 1] = pj; + } + } else { + indxp[k2 + i__ - 1] = pj; + } + pj = nj; + } else { + ++(*k); + dlamda[*k] = d__[pj]; + w[*k] = z__[pj]; + indxp[*k] = pj; + pj = nj; + } + } + goto L80; +L100: + +/* Record the last eigenvalue. */ + + ++(*k); + dlamda[*k] = d__[pj]; + w[*k] = z__[pj]; + indxp[*k] = pj; + +/* + Count up the total number of the various types of columns, then + form a permutation which positions the four column types into + four uniform groups (although one or more of these groups may be + empty). +*/ + + for (j = 1; j <= 4; ++j) { + ctot[j - 1] = 0; +/* L110: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + ct = coltyp[j]; + ++ctot[ct - 1]; +/* L120: */ + } + +/* PSM(*) = Position in SubMatrix (of types 1 through 4) */ + + psm[0] = 1; + psm[1] = ctot[0] + 1; + psm[2] = psm[1] + ctot[1]; + psm[3] = psm[2] + ctot[2]; + *k = *n - ctot[3]; + +/* + Fill out the INDXC array so that the permutation which it induces + will place all type-1 columns first, all type-2 columns next, + then all type-3's, and finally all type-4's. +*/ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + js = indxp[j]; + ct = coltyp[js]; + indx[psm[ct - 1]] = js; + indxc[psm[ct - 1]] = j; + ++psm[ct - 1]; +/* L130: */ + } + +/* + Sort the eigenvalues and corresponding eigenvectors into DLAMDA + and Q2 respectively. The eigenvalues/vectors which were not + deflated go into the first K slots of DLAMDA and Q2 respectively, + while those which were deflated go into the last N - K slots. +*/ + + i__ = 1; + iq1 = 1; + iq2 = (ctot[0] + ctot[1]) * *n1 + 1; + i__1 = ctot[0]; + for (j = 1; j <= i__1; ++j) { + js = indx[i__]; + dcopy_(n1, &q[js * q_dim1 + 1], &c__1, &q2[iq1], &c__1); + z__[i__] = d__[js]; + ++i__; + iq1 += *n1; +/* L140: */ + } + + i__1 = ctot[1]; + for (j = 1; j <= i__1; ++j) { + js = indx[i__]; + dcopy_(n1, &q[js * q_dim1 + 1], &c__1, &q2[iq1], &c__1); + dcopy_(&n2, &q[*n1 + 1 + js * q_dim1], &c__1, &q2[iq2], &c__1); + z__[i__] = d__[js]; + ++i__; + iq1 += *n1; + iq2 += n2; +/* L150: */ + } + + i__1 = ctot[2]; + for (j = 1; j <= i__1; ++j) { + js = indx[i__]; + dcopy_(&n2, &q[*n1 + 1 + js * q_dim1], &c__1, &q2[iq2], &c__1); + z__[i__] = d__[js]; + ++i__; + iq2 += n2; +/* L160: */ + } + + iq1 = iq2; + i__1 = ctot[3]; + for (j = 1; j <= i__1; ++j) { + js = indx[i__]; + dcopy_(n, &q[js * q_dim1 + 1], &c__1, &q2[iq2], &c__1); + iq2 += *n; + z__[i__] = d__[js]; + ++i__; +/* L170: */ + } + +/* + The deflated eigenvalues and their corresponding vectors go back + into the last N - K slots of D and Q respectively. +*/ + + dlacpy_("A", n, &ctot[3], &q2[iq1], n, &q[(*k + 1) * q_dim1 + 1], ldq); + i__1 = *n - *k; + dcopy_(&i__1, &z__[*k + 1], &c__1, &d__[*k + 1], &c__1); + +/* Copy CTOT into COLTYP for referencing in DLAED3. */ + + for (j = 1; j <= 4; ++j) { + coltyp[j] = ctot[j - 1]; +/* L180: */ + } + +L190: + return 0; + +/* End of DLAED2 */ + +} /* dlaed2_ */ + +/* Subroutine */ int dlaed3_(integer *k, integer *n, integer *n1, doublereal * + d__, doublereal *q, integer *ldq, doublereal *rho, doublereal *dlamda, + doublereal *q2, integer *indx, integer *ctot, doublereal *w, + doublereal *s, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer i__, j, n2, n12, ii, n23, iq2; + static doublereal temp; + extern doublereal dnrm2_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *), + dcopy_(integer *, doublereal *, integer *, doublereal *, integer + *), dlaed4_(integer *, integer *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, integer *); + extern doublereal dlamc3_(doublereal *, doublereal *); + extern /* Subroutine */ int dlacpy_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *), + dlaset_(char *, integer *, integer *, doublereal *, doublereal *, + doublereal *, integer *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAED3 finds the roots of the secular equation, as defined by the + values in D, W, and RHO, between 1 and K. It makes the + appropriate calls to DLAED4 and then updates the eigenvectors by + multiplying the matrix of eigenvectors of the pair of eigensystems + being combined by the matrix of eigenvectors of the K-by-K system + which is solved here. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + K (input) INTEGER + The number of terms in the rational function to be solved by + DLAED4. K >= 0. + + N (input) INTEGER + The number of rows and columns in the Q matrix. + N >= K (deflation may result in N>K). + + N1 (input) INTEGER + The location of the last eigenvalue in the leading submatrix. + min(1,N) <= N1 <= N/2. + + D (output) DOUBLE PRECISION array, dimension (N) + D(I) contains the updated eigenvalues for + 1 <= I <= K. + + Q (output) DOUBLE PRECISION array, dimension (LDQ,N) + Initially the first K columns are used as workspace. + On output the columns 1 to K contain + the updated eigenvectors. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + RHO (input) DOUBLE PRECISION + The value of the parameter in the rank one update equation. + RHO >= 0 required. + + DLAMDA (input/output) DOUBLE PRECISION array, dimension (K) + The first K elements of this array contain the old roots + of the deflated updating problem. These are the poles + of the secular equation. May be changed on output by + having lowest order bit set to zero on Cray X-MP, Cray Y-MP, + Cray-2, or Cray C-90, as described above. + + Q2 (input) DOUBLE PRECISION array, dimension (LDQ2, N) + The first K columns of this matrix contain the non-deflated + eigenvectors for the split problem. + + INDX (input) INTEGER array, dimension (N) + The permutation used to arrange the columns of the deflated + Q matrix into three groups (see DLAED2). + The rows of the eigenvectors found by DLAED4 must be likewise + permuted before the matrix multiply can take place. + + CTOT (input) INTEGER array, dimension (4) + A count of the total number of the various types of columns + in Q, as described in INDX. The fourth column type is any + column which has been deflated. + + W (input/output) DOUBLE PRECISION array, dimension (K) + The first K elements of this array contain the components + of the deflation-adjusted updating vector. Destroyed on + output. + + S (workspace) DOUBLE PRECISION array, dimension (N1 + 1)*K + Will contain the eigenvectors of the repaired matrix which + will be multiplied by the previously accumulated eigenvectors + to update the system. + + LDS (input) INTEGER + The leading dimension of S. LDS >= max(1,K). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --dlamda; + --q2; + --indx; + --ctot; + --w; + --s; + + /* Function Body */ + *info = 0; + + if (*k < 0) { + *info = -1; + } else if (*n < *k) { + *info = -2; + } else if (*ldq < max(1,*n)) { + *info = -6; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAED3", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*k == 0) { + return 0; + } + +/* + Modify values DLAMDA(i) to make sure all DLAMDA(i)-DLAMDA(j) can + be computed with high relative accuracy (barring over/underflow). + This is a problem on machines without a guard digit in + add/subtract (Cray XMP, Cray YMP, Cray C 90 and Cray 2). + The following code replaces DLAMDA(I) by 2*DLAMDA(I)-DLAMDA(I), + which on any of these machines zeros out the bottommost + bit of DLAMDA(I) if it is 1; this makes the subsequent + subtractions DLAMDA(I)-DLAMDA(J) unproblematic when cancellation + occurs. On binary machines with a guard digit (almost all + machines) it does not change DLAMDA(I) at all. On hexadecimal + and decimal machines with a guard digit, it slightly + changes the bottommost bits of DLAMDA(I). It does not account + for hexadecimal or decimal machines without guard digits + (we know of none). We use a subroutine call to compute + 2*DLAMBDA(I) to prevent optimizing compilers from eliminating + this code. +*/ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = dlamc3_(&dlamda[i__], &dlamda[i__]) - dlamda[i__]; +/* L10: */ + } + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dlaed4_(k, &j, &dlamda[1], &w[1], &q[j * q_dim1 + 1], rho, &d__[j], + info); + +/* If the zero finder fails, the computation is terminated. */ + + if (*info != 0) { + goto L120; + } +/* L20: */ + } + + if (*k == 1) { + goto L110; + } + if (*k == 2) { + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + w[1] = q[j * q_dim1 + 1]; + w[2] = q[j * q_dim1 + 2]; + ii = indx[1]; + q[j * q_dim1 + 1] = w[ii]; + ii = indx[2]; + q[j * q_dim1 + 2] = w[ii]; +/* L30: */ + } + goto L110; + } + +/* Compute updated W. */ + + dcopy_(k, &w[1], &c__1, &s[1], &c__1); + +/* Initialize W(I) = Q(I,I) */ + + i__1 = *ldq + 1; + dcopy_(k, &q[q_offset], &i__1, &w[1], &c__1); + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + w[i__] *= q[i__ + j * q_dim1] / (dlamda[i__] - dlamda[j]); +/* L40: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + w[i__] *= q[i__ + j * q_dim1] / (dlamda[i__] - dlamda[j]); +/* L50: */ + } +/* L60: */ + } + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + d__1 = sqrt(-w[i__]); + w[i__] = d_sign(&d__1, &s[i__]); +/* L70: */ + } + +/* Compute eigenvectors of the modified rank-1 modification. */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = *k; + for (i__ = 1; i__ <= i__2; ++i__) { + s[i__] = w[i__] / q[i__ + j * q_dim1]; +/* L80: */ + } + temp = dnrm2_(k, &s[1], &c__1); + i__2 = *k; + for (i__ = 1; i__ <= i__2; ++i__) { + ii = indx[i__]; + q[i__ + j * q_dim1] = s[ii] / temp; +/* L90: */ + } +/* L100: */ + } + +/* Compute the updated eigenvectors. */ + +L110: + + n2 = *n - *n1; + n12 = ctot[1] + ctot[2]; + n23 = ctot[2] + ctot[3]; + + dlacpy_("A", &n23, k, &q[ctot[1] + 1 + q_dim1], ldq, &s[1], &n23); + iq2 = *n1 * n12 + 1; + if (n23 != 0) { + dgemm_("N", "N", &n2, k, &n23, &c_b15, &q2[iq2], &n2, &s[1], &n23, & + c_b29, &q[*n1 + 1 + q_dim1], ldq); + } else { + dlaset_("A", &n2, k, &c_b29, &c_b29, &q[*n1 + 1 + q_dim1], ldq); + } + + dlacpy_("A", &n12, k, &q[q_offset], ldq, &s[1], &n12); + if (n12 != 0) { + dgemm_("N", "N", n1, k, &n12, &c_b15, &q2[1], n1, &s[1], &n12, &c_b29, + &q[q_offset], ldq); + } else { + dlaset_("A", n1, k, &c_b29, &c_b29, &q[q_dim1 + 1], ldq); + } + + +L120: + return 0; + +/* End of DLAED3 */ + +} /* dlaed3_ */ + +/* Subroutine */ int dlaed4_(integer *n, integer *i__, doublereal *d__, + doublereal *z__, doublereal *delta, doublereal *rho, doublereal *dlam, + integer *info) +{ + /* System generated locals */ + integer i__1; + doublereal d__1; + + /* Local variables */ + static doublereal a, b, c__; + static integer j; + static doublereal w; + static integer ii; + static doublereal dw, zz[3]; + static integer ip1; + static doublereal del, eta, phi, eps, tau, psi; + static integer iim1, iip1; + static doublereal dphi, dpsi; + static integer iter; + static doublereal temp, prew, temp1, dltlb, dltub, midpt; + static integer niter; + static logical swtch; + extern /* Subroutine */ int dlaed5_(integer *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *), dlaed6_(integer *, + logical *, doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *); + static logical swtch3; + + static logical orgati; + static doublereal erretm, rhoinv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This subroutine computes the I-th updated eigenvalue of a symmetric + rank-one modification to a diagonal matrix whose elements are + given in the array d, and that + + D(i) < D(j) for i < j + + and that RHO > 0. This is arranged by the calling routine, and is + no loss in generality. The rank-one modified system is thus + + diag( D ) + RHO * Z * Z_transpose. + + where we assume the Euclidean norm of Z is 1. + + The method consists of approximating the rational functions in the + secular equation by simpler interpolating rational functions. + + Arguments + ========= + + N (input) INTEGER + The length of all arrays. + + I (input) INTEGER + The index of the eigenvalue to be computed. 1 <= I <= N. + + D (input) DOUBLE PRECISION array, dimension (N) + The original eigenvalues. It is assumed that they are in + order, D(I) < D(J) for I < J. + + Z (input) DOUBLE PRECISION array, dimension (N) + The components of the updating vector. + + DELTA (output) DOUBLE PRECISION array, dimension (N) + If N .GT. 2, DELTA contains (D(j) - lambda_I) in its j-th + component. If N = 1, then DELTA(1) = 1. If N = 2, see DLAED5 + for detail. The vector DELTA contains the information necessary + to construct the eigenvectors by DLAED3 and DLAED9. + + RHO (input) DOUBLE PRECISION + The scalar in the symmetric updating formula. + + DLAM (output) DOUBLE PRECISION + The computed lambda_I, the I-th updated eigenvalue. + + INFO (output) INTEGER + = 0: successful exit + > 0: if INFO = 1, the updating process failed. + + Internal Parameters + =================== + + Logical variable ORGATI (origin-at-i?) is used for distinguishing + whether D(i) or D(i+1) is treated as the origin. + + ORGATI = .true. origin at i + ORGATI = .false. origin at i+1 + + Logical variable SWTCH3 (switch-for-3-poles?) is for noting + if we are working with THREE poles! + + MAXIT is the maximum number of iterations allowed for each + eigenvalue. + + Further Details + =============== + + Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Since this routine is called in an inner loop, we do no argument + checking. + + Quick return for N=1 and 2. +*/ + + /* Parameter adjustments */ + --delta; + --z__; + --d__; + + /* Function Body */ + *info = 0; + if (*n == 1) { + +/* Presumably, I=1 upon entry */ + + *dlam = d__[1] + *rho * z__[1] * z__[1]; + delta[1] = 1.; + return 0; + } + if (*n == 2) { + dlaed5_(i__, &d__[1], &z__[1], &delta[1], rho, dlam); + return 0; + } + +/* Compute machine epsilon */ + + eps = EPSILON; + rhoinv = 1. / *rho; + +/* The case I = N */ + + if (*i__ == *n) { + +/* Initialize some basic variables */ + + ii = *n - 1; + niter = 1; + +/* Calculate initial guess */ + + midpt = *rho / 2.; + +/* + If ||Z||_2 is not one, then TEMP should be set to + RHO * ||Z||_2^2 / TWO +*/ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - midpt; +/* L10: */ + } + + psi = 0.; + i__1 = *n - 2; + for (j = 1; j <= i__1; ++j) { + psi += z__[j] * z__[j] / delta[j]; +/* L20: */ + } + + c__ = rhoinv + psi; + w = c__ + z__[ii] * z__[ii] / delta[ii] + z__[*n] * z__[*n] / delta[* + n]; + + if (w <= 0.) { + temp = z__[*n - 1] * z__[*n - 1] / (d__[*n] - d__[*n - 1] + *rho) + + z__[*n] * z__[*n] / *rho; + if (c__ <= temp) { + tau = *rho; + } else { + del = d__[*n] - d__[*n - 1]; + a = -c__ * del + z__[*n - 1] * z__[*n - 1] + z__[*n] * z__[*n] + ; + b = z__[*n] * z__[*n] * del; + if (a < 0.) { + tau = b * 2. / (sqrt(a * a + b * 4. * c__) - a); + } else { + tau = (a + sqrt(a * a + b * 4. * c__)) / (c__ * 2.); + } + } + +/* + It can be proved that + D(N)+RHO/2 <= LAMBDA(N) < D(N)+TAU <= D(N)+RHO +*/ + + dltlb = midpt; + dltub = *rho; + } else { + del = d__[*n] - d__[*n - 1]; + a = -c__ * del + z__[*n - 1] * z__[*n - 1] + z__[*n] * z__[*n]; + b = z__[*n] * z__[*n] * del; + if (a < 0.) { + tau = b * 2. / (sqrt(a * a + b * 4. * c__) - a); + } else { + tau = (a + sqrt(a * a + b * 4. * c__)) / (c__ * 2.); + } + +/* + It can be proved that + D(N) < D(N)+TAU < LAMBDA(N) < D(N)+RHO/2 +*/ + + dltlb = 0.; + dltub = midpt; + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - tau; +/* L30: */ + } + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L40: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / delta[*n]; + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8. + erretm - phi + rhoinv + abs(tau) * (dpsi + + dphi); + + w = rhoinv + phi + psi; + +/* Test for convergence */ + + if (abs(w) <= eps * erretm) { + *dlam = d__[*i__] + tau; + goto L250; + } + + if (w <= 0.) { + dltlb = max(dltlb,tau); + } else { + dltub = min(dltub,tau); + } + +/* Calculate the new step */ + + ++niter; + c__ = w - delta[*n - 1] * dpsi - delta[*n] * dphi; + a = (delta[*n - 1] + delta[*n]) * w - delta[*n - 1] * delta[*n] * ( + dpsi + dphi); + b = delta[*n - 1] * delta[*n] * w; + if (c__ < 0.) { + c__ = abs(c__); + } + if (c__ == 0.) { +/* + ETA = B/A + ETA = RHO - TAU +*/ + eta = dltub - tau; + } else if (a >= 0.) { + eta = (a + sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / (c__ + * 2.); + } else { + eta = b * 2. / (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1))) + ); + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta > 0.) { + eta = -w / (dpsi + dphi); + } + temp = tau + eta; + if (temp > dltub || temp < dltlb) { + if (w < 0.) { + eta = (dltub - tau) / 2.; + } else { + eta = (dltlb - tau) / 2.; + } + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; +/* L50: */ + } + + tau += eta; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L60: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / delta[*n]; + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8. + erretm - phi + rhoinv + abs(tau) * (dpsi + + dphi); + + w = rhoinv + phi + psi; + +/* Main loop to update the values of the array DELTA */ + + iter = niter + 1; + + for (niter = iter; niter <= 30; ++niter) { + +/* Test for convergence */ + + if (abs(w) <= eps * erretm) { + *dlam = d__[*i__] + tau; + goto L250; + } + + if (w <= 0.) { + dltlb = max(dltlb,tau); + } else { + dltub = min(dltub,tau); + } + +/* Calculate the new step */ + + c__ = w - delta[*n - 1] * dpsi - delta[*n] * dphi; + a = (delta[*n - 1] + delta[*n]) * w - delta[*n - 1] * delta[*n] * + (dpsi + dphi); + b = delta[*n - 1] * delta[*n] * w; + if (a >= 0.) { + eta = (a + sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / ( + c__ * 2.); + } else { + eta = b * 2. / (a - sqrt((d__1 = a * a - b * 4. * c__, abs( + d__1)))); + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta > 0.) { + eta = -w / (dpsi + dphi); + } + temp = tau + eta; + if (temp > dltub || temp < dltlb) { + if (w < 0.) { + eta = (dltub - tau) / 2.; + } else { + eta = (dltlb - tau) / 2.; + } + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; +/* L70: */ + } + + tau += eta; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L80: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / delta[*n]; + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8. + erretm - phi + rhoinv + abs(tau) * ( + dpsi + dphi); + + w = rhoinv + phi + psi; +/* L90: */ + } + +/* Return with INFO = 1, NITER = MAXIT and not converged */ + + *info = 1; + *dlam = d__[*i__] + tau; + goto L250; + +/* End for the case I = N */ + + } else { + +/* The case for I < N */ + + niter = 1; + ip1 = *i__ + 1; + +/* Calculate initial guess */ + + del = d__[ip1] - d__[*i__]; + midpt = del / 2.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - midpt; +/* L100: */ + } + + psi = 0.; + i__1 = *i__ - 1; + for (j = 1; j <= i__1; ++j) { + psi += z__[j] * z__[j] / delta[j]; +/* L110: */ + } + + phi = 0.; + i__1 = *i__ + 2; + for (j = *n; j >= i__1; --j) { + phi += z__[j] * z__[j] / delta[j]; +/* L120: */ + } + c__ = rhoinv + psi + phi; + w = c__ + z__[*i__] * z__[*i__] / delta[*i__] + z__[ip1] * z__[ip1] / + delta[ip1]; + + if (w > 0.) { + +/* + d(i)< the ith eigenvalue < (d(i)+d(i+1))/2 + + We choose d(i) as origin. +*/ + + orgati = TRUE_; + a = c__ * del + z__[*i__] * z__[*i__] + z__[ip1] * z__[ip1]; + b = z__[*i__] * z__[*i__] * del; + if (a > 0.) { + tau = b * 2. / (a + sqrt((d__1 = a * a - b * 4. * c__, abs( + d__1)))); + } else { + tau = (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / ( + c__ * 2.); + } + dltlb = 0.; + dltub = midpt; + } else { + +/* + (d(i)+d(i+1))/2 <= the ith eigenvalue < d(i+1) + + We choose d(i+1) as origin. +*/ + + orgati = FALSE_; + a = c__ * del - z__[*i__] * z__[*i__] - z__[ip1] * z__[ip1]; + b = z__[ip1] * z__[ip1] * del; + if (a < 0.) { + tau = b * 2. / (a - sqrt((d__1 = a * a + b * 4. * c__, abs( + d__1)))); + } else { + tau = -(a + sqrt((d__1 = a * a + b * 4. * c__, abs(d__1)))) / + (c__ * 2.); + } + dltlb = -midpt; + dltub = 0.; + } + + if (orgati) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - tau; +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[ip1] - tau; +/* L140: */ + } + } + if (orgati) { + ii = *i__; + } else { + ii = *i__ + 1; + } + iim1 = ii - 1; + iip1 = ii + 1; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L150: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.; + phi = 0.; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / delta[j]; + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L160: */ + } + + w = rhoinv + phi + psi; + +/* + W is the value of the secular function with + its ii-th element removed. +*/ + + swtch3 = FALSE_; + if (orgati) { + if (w < 0.) { + swtch3 = TRUE_; + } + } else { + if (w > 0.) { + swtch3 = TRUE_; + } + } + if (ii == 1 || ii == *n) { + swtch3 = FALSE_; + } + + temp = z__[ii] / delta[ii]; + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w += temp; + erretm = (phi - psi) * 8. + erretm + rhoinv * 2. + abs(temp) * 3. + + abs(tau) * dw; + +/* Test for convergence */ + + if (abs(w) <= eps * erretm) { + if (orgati) { + *dlam = d__[*i__] + tau; + } else { + *dlam = d__[ip1] + tau; + } + goto L250; + } + + if (w <= 0.) { + dltlb = max(dltlb,tau); + } else { + dltub = min(dltub,tau); + } + +/* Calculate the new step */ + + ++niter; + if (! swtch3) { + if (orgati) { +/* Computing 2nd power */ + d__1 = z__[*i__] / delta[*i__]; + c__ = w - delta[ip1] * dw - (d__[*i__] - d__[ip1]) * (d__1 * + d__1); + } else { +/* Computing 2nd power */ + d__1 = z__[ip1] / delta[ip1]; + c__ = w - delta[*i__] * dw - (d__[ip1] - d__[*i__]) * (d__1 * + d__1); + } + a = (delta[*i__] + delta[ip1]) * w - delta[*i__] * delta[ip1] * + dw; + b = delta[*i__] * delta[ip1] * w; + if (c__ == 0.) { + if (a == 0.) { + if (orgati) { + a = z__[*i__] * z__[*i__] + delta[ip1] * delta[ip1] * + (dpsi + dphi); + } else { + a = z__[ip1] * z__[ip1] + delta[*i__] * delta[*i__] * + (dpsi + dphi); + } + } + eta = b / a; + } else if (a <= 0.) { + eta = (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / ( + c__ * 2.); + } else { + eta = b * 2. / (a + sqrt((d__1 = a * a - b * 4. * c__, abs( + d__1)))); + } + } else { + +/* Interpolation using THREE most relevant poles */ + + temp = rhoinv + psi + phi; + if (orgati) { + temp1 = z__[iim1] / delta[iim1]; + temp1 *= temp1; + c__ = temp - delta[iip1] * (dpsi + dphi) - (d__[iim1] - d__[ + iip1]) * temp1; + zz[0] = z__[iim1] * z__[iim1]; + zz[2] = delta[iip1] * delta[iip1] * (dpsi - temp1 + dphi); + } else { + temp1 = z__[iip1] / delta[iip1]; + temp1 *= temp1; + c__ = temp - delta[iim1] * (dpsi + dphi) - (d__[iip1] - d__[ + iim1]) * temp1; + zz[0] = delta[iim1] * delta[iim1] * (dpsi + (dphi - temp1)); + zz[2] = z__[iip1] * z__[iip1]; + } + zz[1] = z__[ii] * z__[ii]; + dlaed6_(&niter, &orgati, &c__, &delta[iim1], zz, &w, &eta, info); + if (*info != 0) { + goto L250; + } + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta >= 0.) { + eta = -w / dw; + } + temp = tau + eta; + if (temp > dltub || temp < dltlb) { + if (w < 0.) { + eta = (dltub - tau) / 2.; + } else { + eta = (dltlb - tau) / 2.; + } + } + + prew = w; + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; +/* L180: */ + } + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L190: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.; + phi = 0.; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / delta[j]; + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L200: */ + } + + temp = z__[ii] / delta[ii]; + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w = rhoinv + phi + psi + temp; + erretm = (phi - psi) * 8. + erretm + rhoinv * 2. + abs(temp) * 3. + ( + d__1 = tau + eta, abs(d__1)) * dw; + + swtch = FALSE_; + if (orgati) { + if (-w > abs(prew) / 10.) { + swtch = TRUE_; + } + } else { + if (w > abs(prew) / 10.) { + swtch = TRUE_; + } + } + + tau += eta; + +/* Main loop to update the values of the array DELTA */ + + iter = niter + 1; + + for (niter = iter; niter <= 30; ++niter) { + +/* Test for convergence */ + + if (abs(w) <= eps * erretm) { + if (orgati) { + *dlam = d__[*i__] + tau; + } else { + *dlam = d__[ip1] + tau; + } + goto L250; + } + + if (w <= 0.) { + dltlb = max(dltlb,tau); + } else { + dltub = min(dltub,tau); + } + +/* Calculate the new step */ + + if (! swtch3) { + if (! swtch) { + if (orgati) { +/* Computing 2nd power */ + d__1 = z__[*i__] / delta[*i__]; + c__ = w - delta[ip1] * dw - (d__[*i__] - d__[ip1]) * ( + d__1 * d__1); + } else { +/* Computing 2nd power */ + d__1 = z__[ip1] / delta[ip1]; + c__ = w - delta[*i__] * dw - (d__[ip1] - d__[*i__]) * + (d__1 * d__1); + } + } else { + temp = z__[ii] / delta[ii]; + if (orgati) { + dpsi += temp * temp; + } else { + dphi += temp * temp; + } + c__ = w - delta[*i__] * dpsi - delta[ip1] * dphi; + } + a = (delta[*i__] + delta[ip1]) * w - delta[*i__] * delta[ip1] + * dw; + b = delta[*i__] * delta[ip1] * w; + if (c__ == 0.) { + if (a == 0.) { + if (! swtch) { + if (orgati) { + a = z__[*i__] * z__[*i__] + delta[ip1] * + delta[ip1] * (dpsi + dphi); + } else { + a = z__[ip1] * z__[ip1] + delta[*i__] * delta[ + *i__] * (dpsi + dphi); + } + } else { + a = delta[*i__] * delta[*i__] * dpsi + delta[ip1] + * delta[ip1] * dphi; + } + } + eta = b / a; + } else if (a <= 0.) { + eta = (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) + / (c__ * 2.); + } else { + eta = b * 2. / (a + sqrt((d__1 = a * a - b * 4. * c__, + abs(d__1)))); + } + } else { + +/* Interpolation using THREE most relevant poles */ + + temp = rhoinv + psi + phi; + if (swtch) { + c__ = temp - delta[iim1] * dpsi - delta[iip1] * dphi; + zz[0] = delta[iim1] * delta[iim1] * dpsi; + zz[2] = delta[iip1] * delta[iip1] * dphi; + } else { + if (orgati) { + temp1 = z__[iim1] / delta[iim1]; + temp1 *= temp1; + c__ = temp - delta[iip1] * (dpsi + dphi) - (d__[iim1] + - d__[iip1]) * temp1; + zz[0] = z__[iim1] * z__[iim1]; + zz[2] = delta[iip1] * delta[iip1] * (dpsi - temp1 + + dphi); + } else { + temp1 = z__[iip1] / delta[iip1]; + temp1 *= temp1; + c__ = temp - delta[iim1] * (dpsi + dphi) - (d__[iip1] + - d__[iim1]) * temp1; + zz[0] = delta[iim1] * delta[iim1] * (dpsi + (dphi - + temp1)); + zz[2] = z__[iip1] * z__[iip1]; + } + } + dlaed6_(&niter, &orgati, &c__, &delta[iim1], zz, &w, &eta, + info); + if (*info != 0) { + goto L250; + } + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta >= 0.) { + eta = -w / dw; + } + temp = tau + eta; + if (temp > dltub || temp < dltlb) { + if (w < 0.) { + eta = (dltub - tau) / 2.; + } else { + eta = (dltlb - tau) / 2.; + } + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; +/* L210: */ + } + + tau += eta; + prew = w; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L220: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.; + phi = 0.; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / delta[j]; + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L230: */ + } + + temp = z__[ii] / delta[ii]; + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w = rhoinv + phi + psi + temp; + erretm = (phi - psi) * 8. + erretm + rhoinv * 2. + abs(temp) * 3. + + abs(tau) * dw; + if (w * prew > 0. && abs(w) > abs(prew) / 10.) { + swtch = ! swtch; + } + +/* L240: */ + } + +/* Return with INFO = 1, NITER = MAXIT and not converged */ + + *info = 1; + if (orgati) { + *dlam = d__[*i__] + tau; + } else { + *dlam = d__[ip1] + tau; + } + + } + +L250: + + return 0; + +/* End of DLAED4 */ + +} /* dlaed4_ */ + +/* Subroutine */ int dlaed5_(integer *i__, doublereal *d__, doublereal *z__, + doublereal *delta, doublereal *rho, doublereal *dlam) +{ + /* System generated locals */ + doublereal d__1; + + /* Local variables */ + static doublereal b, c__, w, del, tau, temp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This subroutine computes the I-th eigenvalue of a symmetric rank-one + modification of a 2-by-2 diagonal matrix + + diag( D ) + RHO * Z * transpose(Z) . + + The diagonal elements in the array D are assumed to satisfy + + D(i) < D(j) for i < j . + + We also assume RHO > 0 and that the Euclidean norm of the vector + Z is one. + + Arguments + ========= + + I (input) INTEGER + The index of the eigenvalue to be computed. I = 1 or I = 2. + + D (input) DOUBLE PRECISION array, dimension (2) + The original eigenvalues. We assume D(1) < D(2). + + Z (input) DOUBLE PRECISION array, dimension (2) + The components of the updating vector. + + DELTA (output) DOUBLE PRECISION array, dimension (2) + The vector DELTA contains the information necessary + to construct the eigenvectors. + + RHO (input) DOUBLE PRECISION + The scalar in the symmetric updating formula. + + DLAM (output) DOUBLE PRECISION + The computed lambda_I, the I-th updated eigenvalue. + + Further Details + =============== + + Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --delta; + --z__; + --d__; + + /* Function Body */ + del = d__[2] - d__[1]; + if (*i__ == 1) { + w = *rho * 2. * (z__[2] * z__[2] - z__[1] * z__[1]) / del + 1.; + if (w > 0.) { + b = del + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[1] * z__[1] * del; + +/* B > ZERO, always */ + + tau = c__ * 2. / (b + sqrt((d__1 = b * b - c__ * 4., abs(d__1)))); + *dlam = d__[1] + tau; + delta[1] = -z__[1] / tau; + delta[2] = z__[2] / (del - tau); + } else { + b = -del + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[2] * z__[2] * del; + if (b > 0.) { + tau = c__ * -2. / (b + sqrt(b * b + c__ * 4.)); + } else { + tau = (b - sqrt(b * b + c__ * 4.)) / 2.; + } + *dlam = d__[2] + tau; + delta[1] = -z__[1] / (del + tau); + delta[2] = -z__[2] / tau; + } + temp = sqrt(delta[1] * delta[1] + delta[2] * delta[2]); + delta[1] /= temp; + delta[2] /= temp; + } else { + +/* Now I=2 */ + + b = -del + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[2] * z__[2] * del; + if (b > 0.) { + tau = (b + sqrt(b * b + c__ * 4.)) / 2.; + } else { + tau = c__ * 2. / (-b + sqrt(b * b + c__ * 4.)); + } + *dlam = d__[2] + tau; + delta[1] = -z__[1] / (del + tau); + delta[2] = -z__[2] / tau; + temp = sqrt(delta[1] * delta[1] + delta[2] * delta[2]); + delta[1] /= temp; + delta[2] /= temp; + } + return 0; + +/* End OF DLAED5 */ + +} /* dlaed5_ */ + +/* Subroutine */ int dlaed6_(integer *kniter, logical *orgati, doublereal * + rho, doublereal *d__, doublereal *z__, doublereal *finit, doublereal * + tau, integer *info) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2, d__3, d__4; + + /* Local variables */ + static doublereal a, b, c__, f; + static integer i__; + static doublereal fc, df, ddf, lbd, eta, ubd, eps, base; + static integer iter; + static doublereal temp, temp1, temp2, temp3, temp4; + static logical scale; + static integer niter; + static doublereal small1, small2, sminv1, sminv2; + + static doublereal dscale[3], sclfac, zscale[3], erretm, sclinv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + February 2007 + + + Purpose + ======= + + DLAED6 computes the positive or negative root (closest to the origin) + of + z(1) z(2) z(3) + f(x) = rho + --------- + ---------- + --------- + d(1)-x d(2)-x d(3)-x + + It is assumed that + + if ORGATI = .true. the root is between d(2) and d(3); + otherwise it is between d(1) and d(2) + + This routine will be called by DLAED4 when necessary. In most cases, + the root sought is the smallest in magnitude, though it might not be + in some extremely rare situations. + + Arguments + ========= + + KNITER (input) INTEGER + Refer to DLAED4 for its significance. + + ORGATI (input) LOGICAL + If ORGATI is true, the needed root is between d(2) and + d(3); otherwise it is between d(1) and d(2). See + DLAED4 for further details. + + RHO (input) DOUBLE PRECISION + Refer to the equation f(x) above. + + D (input) DOUBLE PRECISION array, dimension (3) + D satisfies d(1) < d(2) < d(3). + + Z (input) DOUBLE PRECISION array, dimension (3) + Each of the elements in z must be positive. + + FINIT (input) DOUBLE PRECISION + The value of f at 0. It is more accurate than the one + evaluated inside this routine (if someone wants to do + so). + + TAU (output) DOUBLE PRECISION + The root of the equation f(x). + + INFO (output) INTEGER + = 0: successful exit + > 0: if INFO = 1, failure to converge + + Further Details + =============== + + 30/06/99: Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + 10/02/03: This version has a few statements commented out for thread + safety (machine parameters are computed on each entry). SJH. + + 05/10/06: Modified from a new version of Ren-Cang Li, use + Gragg-Thornton-Warner cubic convergent scheme for better stability. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --z__; + --d__; + + /* Function Body */ + *info = 0; + + if (*orgati) { + lbd = d__[2]; + ubd = d__[3]; + } else { + lbd = d__[1]; + ubd = d__[2]; + } + if (*finit < 0.) { + lbd = 0.; + } else { + ubd = 0.; + } + + niter = 1; + *tau = 0.; + if (*kniter == 2) { + if (*orgati) { + temp = (d__[3] - d__[2]) / 2.; + c__ = *rho + z__[1] / (d__[1] - d__[2] - temp); + a = c__ * (d__[2] + d__[3]) + z__[2] + z__[3]; + b = c__ * d__[2] * d__[3] + z__[2] * d__[3] + z__[3] * d__[2]; + } else { + temp = (d__[1] - d__[2]) / 2.; + c__ = *rho + z__[3] / (d__[3] - d__[2] - temp); + a = c__ * (d__[1] + d__[2]) + z__[1] + z__[2]; + b = c__ * d__[1] * d__[2] + z__[1] * d__[2] + z__[2] * d__[1]; + } +/* Computing MAX */ + d__1 = abs(a), d__2 = abs(b), d__1 = max(d__1,d__2), d__2 = abs(c__); + temp = max(d__1,d__2); + a /= temp; + b /= temp; + c__ /= temp; + if (c__ == 0.) { + *tau = b / a; + } else if (a <= 0.) { + *tau = (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / ( + c__ * 2.); + } else { + *tau = b * 2. / (a + sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)) + )); + } + if (*tau < lbd || *tau > ubd) { + *tau = (lbd + ubd) / 2.; + } + if (d__[1] == *tau || d__[2] == *tau || d__[3] == *tau) { + *tau = 0.; + } else { + temp = *finit + *tau * z__[1] / (d__[1] * (d__[1] - *tau)) + *tau + * z__[2] / (d__[2] * (d__[2] - *tau)) + *tau * z__[3] / ( + d__[3] * (d__[3] - *tau)); + if (temp <= 0.) { + lbd = *tau; + } else { + ubd = *tau; + } + if (abs(*finit) <= abs(temp)) { + *tau = 0.; + } + } + } + +/* + get machine parameters for possible scaling to avoid overflow + + modified by Sven: parameters SMALL1, SMINV1, SMALL2, + SMINV2, EPS are not SAVEd anymore between one call to the + others but recomputed at each call +*/ + + eps = EPSILON; + base = BASE; + i__1 = (integer) (log(SAFEMINIMUM) / log(base) / 3.); + small1 = pow_di(&base, &i__1); + sminv1 = 1. / small1; + small2 = small1 * small1; + sminv2 = sminv1 * sminv1; + +/* + Determine if scaling of inputs necessary to avoid overflow + when computing 1/TEMP**3 +*/ + + if (*orgati) { +/* Computing MIN */ + d__3 = (d__1 = d__[2] - *tau, abs(d__1)), d__4 = (d__2 = d__[3] - * + tau, abs(d__2)); + temp = min(d__3,d__4); + } else { +/* Computing MIN */ + d__3 = (d__1 = d__[1] - *tau, abs(d__1)), d__4 = (d__2 = d__[2] - * + tau, abs(d__2)); + temp = min(d__3,d__4); + } + scale = FALSE_; + if (temp <= small1) { + scale = TRUE_; + if (temp <= small2) { + +/* Scale up by power of radix nearest 1/SAFMIN**(2/3) */ + + sclfac = sminv2; + sclinv = small2; + } else { + +/* Scale up by power of radix nearest 1/SAFMIN**(1/3) */ + + sclfac = sminv1; + sclinv = small1; + } + +/* Scaling up safe because D, Z, TAU scaled elsewhere to be O(1) */ + + for (i__ = 1; i__ <= 3; ++i__) { + dscale[i__ - 1] = d__[i__] * sclfac; + zscale[i__ - 1] = z__[i__] * sclfac; +/* L10: */ + } + *tau *= sclfac; + lbd *= sclfac; + ubd *= sclfac; + } else { + +/* Copy D and Z to DSCALE and ZSCALE */ + + for (i__ = 1; i__ <= 3; ++i__) { + dscale[i__ - 1] = d__[i__]; + zscale[i__ - 1] = z__[i__]; +/* L20: */ + } + } + + fc = 0.; + df = 0.; + ddf = 0.; + for (i__ = 1; i__ <= 3; ++i__) { + temp = 1. / (dscale[i__ - 1] - *tau); + temp1 = zscale[i__ - 1] * temp; + temp2 = temp1 * temp; + temp3 = temp2 * temp; + fc += temp1 / dscale[i__ - 1]; + df += temp2; + ddf += temp3; +/* L30: */ + } + f = *finit + *tau * fc; + + if (abs(f) <= 0.) { + goto L60; + } + if (f <= 0.) { + lbd = *tau; + } else { + ubd = *tau; + } + +/* + Iteration begins -- Use Gragg-Thornton-Warner cubic convergent + scheme + + It is not hard to see that + + 1) Iterations will go up monotonically + if FINIT < 0; + + 2) Iterations will go down monotonically + if FINIT > 0. +*/ + + iter = niter + 1; + + for (niter = iter; niter <= 40; ++niter) { + + if (*orgati) { + temp1 = dscale[1] - *tau; + temp2 = dscale[2] - *tau; + } else { + temp1 = dscale[0] - *tau; + temp2 = dscale[1] - *tau; + } + a = (temp1 + temp2) * f - temp1 * temp2 * df; + b = temp1 * temp2 * f; + c__ = f - (temp1 + temp2) * df + temp1 * temp2 * ddf; +/* Computing MAX */ + d__1 = abs(a), d__2 = abs(b), d__1 = max(d__1,d__2), d__2 = abs(c__); + temp = max(d__1,d__2); + a /= temp; + b /= temp; + c__ /= temp; + if (c__ == 0.) { + eta = b / a; + } else if (a <= 0.) { + eta = (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / (c__ + * 2.); + } else { + eta = b * 2. / (a + sqrt((d__1 = a * a - b * 4. * c__, abs(d__1))) + ); + } + if (f * eta >= 0.) { + eta = -f / df; + } + + *tau += eta; + if (*tau < lbd || *tau > ubd) { + *tau = (lbd + ubd) / 2.; + } + + fc = 0.; + erretm = 0.; + df = 0.; + ddf = 0.; + for (i__ = 1; i__ <= 3; ++i__) { + temp = 1. / (dscale[i__ - 1] - *tau); + temp1 = zscale[i__ - 1] * temp; + temp2 = temp1 * temp; + temp3 = temp2 * temp; + temp4 = temp1 / dscale[i__ - 1]; + fc += temp4; + erretm += abs(temp4); + df += temp2; + ddf += temp3; +/* L40: */ + } + f = *finit + *tau * fc; + erretm = (abs(*finit) + abs(*tau) * erretm) * 8. + abs(*tau) * df; + if (abs(f) <= eps * erretm) { + goto L60; + } + if (f <= 0.) { + lbd = *tau; + } else { + ubd = *tau; + } +/* L50: */ + } + *info = 1; +L60: + +/* Undo scaling */ + + if (scale) { + *tau *= sclinv; + } + return 0; + +/* End of DLAED6 */ + +} /* dlaed6_ */ + +/* Subroutine */ int dlaed7_(integer *icompq, integer *n, integer *qsiz, + integer *tlvls, integer *curlvl, integer *curpbm, doublereal *d__, + doublereal *q, integer *ldq, integer *indxq, doublereal *rho, integer + *cutpnt, doublereal *qstore, integer *qptr, integer *prmptr, integer * + perm, integer *givptr, integer *givcol, doublereal *givnum, + doublereal *work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + + /* Local variables */ + static integer i__, k, n1, n2, is, iw, iz, iq2, ptr, ldq2, indx, curr; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer indxc, indxp; + extern /* Subroutine */ int dlaed8_(integer *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, doublereal *, + integer *, doublereal *, integer *, integer *, integer *, + doublereal *, integer *, integer *, integer *), dlaed9_(integer *, + integer *, integer *, integer *, doublereal *, doublereal *, + integer *, doublereal *, doublereal *, doublereal *, doublereal *, + integer *, integer *), dlaeda_(integer *, integer *, integer *, + integer *, integer *, integer *, integer *, integer *, doublereal + *, doublereal *, integer *, doublereal *, doublereal *, integer *) + ; + static integer idlmda; + extern /* Subroutine */ int dlamrg_(integer *, integer *, doublereal *, + integer *, integer *, integer *), xerbla_(char *, integer *); + static integer coltyp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAED7 computes the updated eigensystem of a diagonal + matrix after modification by a rank-one symmetric matrix. This + routine is used only for the eigenproblem which requires all + eigenvalues and optionally eigenvectors of a dense symmetric matrix + that has been reduced to tridiagonal form. DLAED1 handles + the case in which all eigenvalues and eigenvectors of a symmetric + tridiagonal matrix are desired. + + T = Q(in) ( D(in) + RHO * Z*Z' ) Q'(in) = Q(out) * D(out) * Q'(out) + + where Z = Q'u, u is a vector of length N with ones in the + CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. + + The eigenvectors of the original matrix are stored in Q, and the + eigenvalues are in D. The algorithm consists of three stages: + + The first stage consists of deflating the size of the problem + when there are multiple eigenvalues or if there is a zero in + the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine DLAED8. + + The second stage consists of calculating the updated + eigenvalues. This is done by finding the roots of the secular + equation via the routine DLAED4 (as called by DLAED9). + This routine also calculates the eigenvectors of the current + problem. + + The final stage consists of computing the updated eigenvectors + directly using the updated eigenvalues. The eigenvectors for + the current problem are multiplied with the eigenvectors from + the overall problem. + + Arguments + ========= + + ICOMPQ (input) INTEGER + = 0: Compute eigenvalues only. + = 1: Compute eigenvectors of original dense symmetric matrix + also. On entry, Q contains the orthogonal matrix used + to reduce the original matrix to tridiagonal form. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + QSIZ (input) INTEGER + The dimension of the orthogonal matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N if ICOMPQ = 1. + + TLVLS (input) INTEGER + The total number of merging levels in the overall divide and + conquer tree. + + CURLVL (input) INTEGER + The current level in the overall merge routine, + 0 <= CURLVL <= TLVLS. + + CURPBM (input) INTEGER + The current problem in the current level in the overall + merge routine (counting from upper left to lower right). + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the eigenvalues of the rank-1-perturbed matrix. + On exit, the eigenvalues of the repaired matrix. + + Q (input/output) DOUBLE PRECISION array, dimension (LDQ, N) + On entry, the eigenvectors of the rank-1-perturbed matrix. + On exit, the eigenvectors of the repaired tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + INDXQ (output) INTEGER array, dimension (N) + The permutation which will reintegrate the subproblem just + solved back into sorted order, i.e., D( INDXQ( I = 1, N ) ) + will be in ascending order. + + RHO (input) DOUBLE PRECISION + The subdiagonal element used to create the rank-1 + modification. + + CUTPNT (input) INTEGER + Contains the location of the last eigenvalue in the leading + sub-matrix. min(1,N) <= CUTPNT <= N. + + QSTORE (input/output) DOUBLE PRECISION array, dimension (N**2+1) + Stores eigenvectors of submatrices encountered during + divide and conquer, packed together. QPTR points to + beginning of the submatrices. + + QPTR (input/output) INTEGER array, dimension (N+2) + List of indices pointing to beginning of submatrices stored + in QSTORE. The submatrices are numbered starting at the + bottom left of the divide and conquer tree, from left to + right and bottom to top. + + PRMPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in PERM a + level's permutation is stored. PRMPTR(i+1) - PRMPTR(i) + indicates the size of the permutation and also the size of + the full, non-deflated problem. + + PERM (input) INTEGER array, dimension (N lg N) + Contains the permutations (from deflation and sorting) to be + applied to each eigenblock. + + GIVPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in GIVCOL a + level's Givens rotations are stored. GIVPTR(i+1) - GIVPTR(i) + indicates the number of Givens rotations. + + GIVCOL (input) INTEGER array, dimension (2, N lg N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (input) DOUBLE PRECISION array, dimension (2, N lg N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + WORK (workspace) DOUBLE PRECISION array, dimension (3*N+QSIZ*N) + + IWORK (workspace) INTEGER array, dimension (4*N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --qstore; + --qptr; + --prmptr; + --perm; + --givptr; + givcol -= 3; + givnum -= 3; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*icompq == 1 && *qsiz < *n) { + *info = -4; + } else if (*ldq < max(1,*n)) { + *info = -9; + } else if (min(1,*n) > *cutpnt || *n < *cutpnt) { + *info = -12; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAED7", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* + The following values are for bookkeeping purposes only. They are + integer pointers which indicate the portion of the workspace + used by a particular array in DLAED8 and DLAED9. +*/ + + if (*icompq == 1) { + ldq2 = *qsiz; + } else { + ldq2 = *n; + } + + iz = 1; + idlmda = iz + *n; + iw = idlmda + *n; + iq2 = iw + *n; + is = iq2 + *n * ldq2; + + indx = 1; + indxc = indx + *n; + coltyp = indxc + *n; + indxp = coltyp + *n; + +/* + Form the z-vector which consists of the last row of Q_1 and the + first row of Q_2. +*/ + + ptr = pow_ii(&c__2, tlvls) + 1; + i__1 = *curlvl - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *tlvls - i__; + ptr += pow_ii(&c__2, &i__2); +/* L10: */ + } + curr = ptr + *curpbm; + dlaeda_(n, tlvls, curlvl, curpbm, &prmptr[1], &perm[1], &givptr[1], & + givcol[3], &givnum[3], &qstore[1], &qptr[1], &work[iz], &work[iz + + *n], info); + +/* + When solving the final problem, we no longer need the stored data, + so we will overwrite the data from this level onto the previously + used storage space. +*/ + + if (*curlvl == *tlvls) { + qptr[curr] = 1; + prmptr[curr] = 1; + givptr[curr] = 1; + } + +/* Sort and Deflate eigenvalues. */ + + dlaed8_(icompq, &k, n, qsiz, &d__[1], &q[q_offset], ldq, &indxq[1], rho, + cutpnt, &work[iz], &work[idlmda], &work[iq2], &ldq2, &work[iw], & + perm[prmptr[curr]], &givptr[curr + 1], &givcol[(givptr[curr] << 1) + + 1], &givnum[(givptr[curr] << 1) + 1], &iwork[indxp], &iwork[ + indx], info); + prmptr[curr + 1] = prmptr[curr] + *n; + givptr[curr + 1] += givptr[curr]; + +/* Solve Secular Equation. */ + + if (k != 0) { + dlaed9_(&k, &c__1, &k, n, &d__[1], &work[is], &k, rho, &work[idlmda], + &work[iw], &qstore[qptr[curr]], &k, info); + if (*info != 0) { + goto L30; + } + if (*icompq == 1) { + dgemm_("N", "N", qsiz, &k, &k, &c_b15, &work[iq2], &ldq2, &qstore[ + qptr[curr]], &k, &c_b29, &q[q_offset], ldq); + } +/* Computing 2nd power */ + i__1 = k; + qptr[curr + 1] = qptr[curr] + i__1 * i__1; + +/* Prepare the INDXQ sorting permutation. */ + + n1 = k; + n2 = *n - k; + dlamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &indxq[1]); + } else { + qptr[curr + 1] = qptr[curr]; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + indxq[i__] = i__; +/* L20: */ + } + } + +L30: + return 0; + +/* End of DLAED7 */ + +} /* dlaed7_ */ + +/* Subroutine */ int dlaed8_(integer *icompq, integer *k, integer *n, integer + *qsiz, doublereal *d__, doublereal *q, integer *ldq, integer *indxq, + doublereal *rho, integer *cutpnt, doublereal *z__, doublereal *dlamda, + doublereal *q2, integer *ldq2, doublereal *w, integer *perm, integer + *givptr, integer *givcol, doublereal *givnum, integer *indxp, integer + *indx, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, q2_dim1, q2_offset, i__1; + doublereal d__1; + + /* Local variables */ + static doublereal c__; + static integer i__, j; + static doublereal s, t; + static integer k2, n1, n2, jp, n1p1; + static doublereal eps, tau, tol; + static integer jlam, imax, jmax; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *), dscal_( + integer *, doublereal *, doublereal *, integer *), dcopy_(integer + *, doublereal *, integer *, doublereal *, integer *); + + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dlamrg_(integer *, integer *, doublereal *, + integer *, integer *, integer *), dlacpy_(char *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLAED8 merges the two sets of eigenvalues together into a single + sorted set. Then it tries to deflate the size of the problem. + There are two ways in which deflation can occur: when two or more + eigenvalues are close together or if there is a tiny element in the + Z vector. For each such occurrence the order of the related secular + equation problem is reduced by one. + + Arguments + ========= + + ICOMPQ (input) INTEGER + = 0: Compute eigenvalues only. + = 1: Compute eigenvectors of original dense symmetric matrix + also. On entry, Q contains the orthogonal matrix used + to reduce the original matrix to tridiagonal form. + + K (output) INTEGER + The number of non-deflated eigenvalues, and the order of the + related secular equation. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + QSIZ (input) INTEGER + The dimension of the orthogonal matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N if ICOMPQ = 1. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the eigenvalues of the two submatrices to be + combined. On exit, the trailing (N-K) updated eigenvalues + (those which were deflated) sorted into increasing order. + + Q (input/output) DOUBLE PRECISION array, dimension (LDQ,N) + If ICOMPQ = 0, Q is not referenced. Otherwise, + on entry, Q contains the eigenvectors of the partially solved + system which has been previously updated in matrix + multiplies with other partially solved eigensystems. + On exit, Q contains the trailing (N-K) updated eigenvectors + (those which were deflated) in its last N-K columns. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + INDXQ (input) INTEGER array, dimension (N) + The permutation which separately sorts the two sub-problems + in D into ascending order. Note that elements in the second + half of this permutation must first have CUTPNT added to + their values in order to be accurate. + + RHO (input/output) DOUBLE PRECISION + On entry, the off-diagonal element associated with the rank-1 + cut which originally split the two submatrices which are now + being recombined. + On exit, RHO has been modified to the value required by + DLAED3. + + CUTPNT (input) INTEGER + The location of the last eigenvalue in the leading + sub-matrix. min(1,N) <= CUTPNT <= N. + + Z (input) DOUBLE PRECISION array, dimension (N) + On entry, Z contains the updating vector (the last row of + the first sub-eigenvector matrix and the first row of the + second sub-eigenvector matrix). + On exit, the contents of Z are destroyed by the updating + process. + + DLAMDA (output) DOUBLE PRECISION array, dimension (N) + A copy of the first K eigenvalues which will be used by + DLAED3 to form the secular equation. + + Q2 (output) DOUBLE PRECISION array, dimension (LDQ2,N) + If ICOMPQ = 0, Q2 is not referenced. Otherwise, + a copy of the first K eigenvectors which will be used by + DLAED7 in a matrix multiply (DGEMM) to update the new + eigenvectors. + + LDQ2 (input) INTEGER + The leading dimension of the array Q2. LDQ2 >= max(1,N). + + W (output) DOUBLE PRECISION array, dimension (N) + The first k values of the final deflation-altered z-vector and + will be passed to DLAED3. + + PERM (output) INTEGER array, dimension (N) + The permutations (from deflation and sorting) to be applied + to each eigenblock. + + GIVPTR (output) INTEGER + The number of Givens rotations which took place in this + subproblem. + + GIVCOL (output) INTEGER array, dimension (2, N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (output) DOUBLE PRECISION array, dimension (2, N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + INDXP (workspace) INTEGER array, dimension (N) + The permutation used to place deflated values of D at the end + of the array. INDXP(1:K) points to the nondeflated D-values + and INDXP(K+1:N) points to the deflated eigenvalues. + + INDX (workspace) INTEGER array, dimension (N) + The permutation used to sort the contents of D into ascending + order. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --z__; + --dlamda; + q2_dim1 = *ldq2; + q2_offset = 1 + q2_dim1; + q2 -= q2_offset; + --w; + --perm; + givcol -= 3; + givnum -= 3; + --indxp; + --indx; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*n < 0) { + *info = -3; + } else if (*icompq == 1 && *qsiz < *n) { + *info = -4; + } else if (*ldq < max(1,*n)) { + *info = -7; + } else if (*cutpnt < min(1,*n) || *cutpnt > *n) { + *info = -10; + } else if (*ldq2 < max(1,*n)) { + *info = -14; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAED8", &i__1); + return 0; + } + +/* + Need to initialize GIVPTR to O here in case of quick exit + to prevent an unspecified code behavior (usually sigfault) + when IWORK array on entry to *stedc is not zeroed + (or at least some IWORK entries which used in *laed7 for GIVPTR). +*/ + + *givptr = 0; + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + n1 = *cutpnt; + n2 = *n - n1; + n1p1 = n1 + 1; + + if (*rho < 0.) { + dscal_(&n2, &c_b151, &z__[n1p1], &c__1); + } + +/* Normalize z so that norm(z) = 1 */ + + t = 1. / sqrt(2.); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + indx[j] = j; +/* L10: */ + } + dscal_(n, &t, &z__[1], &c__1); + *rho = (d__1 = *rho * 2., abs(d__1)); + +/* Sort the eigenvalues into increasing order */ + + i__1 = *n; + for (i__ = *cutpnt + 1; i__ <= i__1; ++i__) { + indxq[i__] += *cutpnt; +/* L20: */ + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = d__[indxq[i__]]; + w[i__] = z__[indxq[i__]]; +/* L30: */ + } + i__ = 1; + j = *cutpnt + 1; + dlamrg_(&n1, &n2, &dlamda[1], &c__1, &c__1, &indx[1]); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d__[i__] = dlamda[indx[i__]]; + z__[i__] = w[indx[i__]]; +/* L40: */ + } + +/* Calculate the allowable deflation tolerence */ + + imax = idamax_(n, &z__[1], &c__1); + jmax = idamax_(n, &d__[1], &c__1); + eps = EPSILON; + tol = eps * 8. * (d__1 = d__[jmax], abs(d__1)); + +/* + If the rank-1 modifier is small enough, no more needs to be done + except to reorganize Q so that its columns correspond with the + elements in D. +*/ + + if (*rho * (d__1 = z__[imax], abs(d__1)) <= tol) { + *k = 0; + if (*icompq == 0) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + perm[j] = indxq[indx[j]]; +/* L50: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + perm[j] = indxq[indx[j]]; + dcopy_(qsiz, &q[perm[j] * q_dim1 + 1], &c__1, &q2[j * q2_dim1 + + 1], &c__1); +/* L60: */ + } + dlacpy_("A", qsiz, n, &q2[q2_dim1 + 1], ldq2, &q[q_dim1 + 1], ldq); + } + return 0; + } + +/* + If there are multiple eigenvalues then the problem deflates. Here + the number of equal eigenvalues are found. As each equal + eigenvalue is found, an elementary reflector is computed to rotate + the corresponding eigensubspace so that the corresponding + components of Z are zero in this new basis. +*/ + + *k = 0; + k2 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*rho * (d__1 = z__[j], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + indxp[k2] = j; + if (j == *n) { + goto L110; + } + } else { + jlam = j; + goto L80; + } +/* L70: */ + } +L80: + ++j; + if (j > *n) { + goto L100; + } + if (*rho * (d__1 = z__[j], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + indxp[k2] = j; + } else { + +/* Check if eigenvalues are close enough to allow deflation. */ + + s = z__[jlam]; + c__ = z__[j]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = dlapy2_(&c__, &s); + t = d__[j] - d__[jlam]; + c__ /= tau; + s = -s / tau; + if ((d__1 = t * c__ * s, abs(d__1)) <= tol) { + +/* Deflation is possible. */ + + z__[j] = tau; + z__[jlam] = 0.; + +/* Record the appropriate Givens rotation */ + + ++(*givptr); + givcol[(*givptr << 1) + 1] = indxq[indx[jlam]]; + givcol[(*givptr << 1) + 2] = indxq[indx[j]]; + givnum[(*givptr << 1) + 1] = c__; + givnum[(*givptr << 1) + 2] = s; + if (*icompq == 1) { + drot_(qsiz, &q[indxq[indx[jlam]] * q_dim1 + 1], &c__1, &q[ + indxq[indx[j]] * q_dim1 + 1], &c__1, &c__, &s); + } + t = d__[jlam] * c__ * c__ + d__[j] * s * s; + d__[j] = d__[jlam] * s * s + d__[j] * c__ * c__; + d__[jlam] = t; + --k2; + i__ = 1; +L90: + if (k2 + i__ <= *n) { + if (d__[jlam] < d__[indxp[k2 + i__]]) { + indxp[k2 + i__ - 1] = indxp[k2 + i__]; + indxp[k2 + i__] = jlam; + ++i__; + goto L90; + } else { + indxp[k2 + i__ - 1] = jlam; + } + } else { + indxp[k2 + i__ - 1] = jlam; + } + jlam = j; + } else { + ++(*k); + w[*k] = z__[jlam]; + dlamda[*k] = d__[jlam]; + indxp[*k] = jlam; + jlam = j; + } + } + goto L80; +L100: + +/* Record the last eigenvalue. */ + + ++(*k); + w[*k] = z__[jlam]; + dlamda[*k] = d__[jlam]; + indxp[*k] = jlam; + +L110: + +/* + Sort the eigenvalues and corresponding eigenvectors into DLAMDA + and Q2 respectively. The eigenvalues/vectors which were not + deflated go into the first K slots of DLAMDA and Q2 respectively, + while those which were deflated go into the last N - K slots. +*/ + + if (*icompq == 0) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + jp = indxp[j]; + dlamda[j] = d__[jp]; + perm[j] = indxq[indx[jp]]; +/* L120: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + jp = indxp[j]; + dlamda[j] = d__[jp]; + perm[j] = indxq[indx[jp]]; + dcopy_(qsiz, &q[perm[j] * q_dim1 + 1], &c__1, &q2[j * q2_dim1 + 1] + , &c__1); +/* L130: */ + } + } + +/* + The deflated eigenvalues and their corresponding vectors go back + into the last N - K slots of D and Q respectively. +*/ + + if (*k < *n) { + if (*icompq == 0) { + i__1 = *n - *k; + dcopy_(&i__1, &dlamda[*k + 1], &c__1, &d__[*k + 1], &c__1); + } else { + i__1 = *n - *k; + dcopy_(&i__1, &dlamda[*k + 1], &c__1, &d__[*k + 1], &c__1); + i__1 = *n - *k; + dlacpy_("A", qsiz, &i__1, &q2[(*k + 1) * q2_dim1 + 1], ldq2, &q[(* + k + 1) * q_dim1 + 1], ldq); + } + } + + return 0; + +/* End of DLAED8 */ + +} /* dlaed8_ */ + +/* Subroutine */ int dlaed9_(integer *k, integer *kstart, integer *kstop, + integer *n, doublereal *d__, doublereal *q, integer *ldq, doublereal * + rho, doublereal *dlamda, doublereal *w, doublereal *s, integer *lds, + integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, s_dim1, s_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer i__, j; + static doublereal temp; + extern doublereal dnrm2_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *), dlaed4_(integer *, integer *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *); + extern doublereal dlamc3_(doublereal *, doublereal *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAED9 finds the roots of the secular equation, as defined by the + values in D, Z, and RHO, between KSTART and KSTOP. It makes the + appropriate calls to DLAED4 and then stores the new matrix of + eigenvectors for use in calculating the next level of Z vectors. + + Arguments + ========= + + K (input) INTEGER + The number of terms in the rational function to be solved by + DLAED4. K >= 0. + + KSTART (input) INTEGER + KSTOP (input) INTEGER + The updated eigenvalues Lambda(I), KSTART <= I <= KSTOP + are to be computed. 1 <= KSTART <= KSTOP <= K. + + N (input) INTEGER + The number of rows and columns in the Q matrix. + N >= K (delation may result in N > K). + + D (output) DOUBLE PRECISION array, dimension (N) + D(I) contains the updated eigenvalues + for KSTART <= I <= KSTOP. + + Q (workspace) DOUBLE PRECISION array, dimension (LDQ,N) + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max( 1, N ). + + RHO (input) DOUBLE PRECISION + The value of the parameter in the rank one update equation. + RHO >= 0 required. + + DLAMDA (input) DOUBLE PRECISION array, dimension (K) + The first K elements of this array contain the old roots + of the deflated updating problem. These are the poles + of the secular equation. + + W (input) DOUBLE PRECISION array, dimension (K) + The first K elements of this array contain the components + of the deflation-adjusted updating vector. + + S (output) DOUBLE PRECISION array, dimension (LDS, K) + Will contain the eigenvectors of the repaired matrix which + will be stored for subsequent Z vector calculation and + multiplied by the previously accumulated eigenvectors + to update the system. + + LDS (input) INTEGER + The leading dimension of S. LDS >= max( 1, K ). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --dlamda; + --w; + s_dim1 = *lds; + s_offset = 1 + s_dim1; + s -= s_offset; + + /* Function Body */ + *info = 0; + + if (*k < 0) { + *info = -1; + } else if (*kstart < 1 || *kstart > max(1,*k)) { + *info = -2; + } else if (max(1,*kstop) < *kstart || *kstop > max(1,*k)) { + *info = -3; + } else if (*n < *k) { + *info = -4; + } else if (*ldq < max(1,*k)) { + *info = -7; + } else if (*lds < max(1,*k)) { + *info = -12; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAED9", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*k == 0) { + return 0; + } + +/* + Modify values DLAMDA(i) to make sure all DLAMDA(i)-DLAMDA(j) can + be computed with high relative accuracy (barring over/underflow). + This is a problem on machines without a guard digit in + add/subtract (Cray XMP, Cray YMP, Cray C 90 and Cray 2). + The following code replaces DLAMDA(I) by 2*DLAMDA(I)-DLAMDA(I), + which on any of these machines zeros out the bottommost + bit of DLAMDA(I) if it is 1; this makes the subsequent + subtractions DLAMDA(I)-DLAMDA(J) unproblematic when cancellation + occurs. On binary machines with a guard digit (almost all + machines) it does not change DLAMDA(I) at all. On hexadecimal + and decimal machines with a guard digit, it slightly + changes the bottommost bits of DLAMDA(I). It does not account + for hexadecimal or decimal machines without guard digits + (we know of none). We use a subroutine call to compute + 2*DLAMBDA(I) to prevent optimizing compilers from eliminating + this code. +*/ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = dlamc3_(&dlamda[i__], &dlamda[i__]) - dlamda[i__]; +/* L10: */ + } + + i__1 = *kstop; + for (j = *kstart; j <= i__1; ++j) { + dlaed4_(k, &j, &dlamda[1], &w[1], &q[j * q_dim1 + 1], rho, &d__[j], + info); + +/* If the zero finder fails, the computation is terminated. */ + + if (*info != 0) { + goto L120; + } +/* L20: */ + } + + if (*k == 1 || *k == 2) { + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *k; + for (j = 1; j <= i__2; ++j) { + s[j + i__ * s_dim1] = q[j + i__ * q_dim1]; +/* L30: */ + } +/* L40: */ + } + goto L120; + } + +/* Compute updated W. */ + + dcopy_(k, &w[1], &c__1, &s[s_offset], &c__1); + +/* Initialize W(I) = Q(I,I) */ + + i__1 = *ldq + 1; + dcopy_(k, &q[q_offset], &i__1, &w[1], &c__1); + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + w[i__] *= q[i__ + j * q_dim1] / (dlamda[i__] - dlamda[j]); +/* L50: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + w[i__] *= q[i__ + j * q_dim1] / (dlamda[i__] - dlamda[j]); +/* L60: */ + } +/* L70: */ + } + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + d__1 = sqrt(-w[i__]); + w[i__] = d_sign(&d__1, &s[i__ + s_dim1]); +/* L80: */ + } + +/* Compute eigenvectors of the modified rank-1 modification. */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = *k; + for (i__ = 1; i__ <= i__2; ++i__) { + q[i__ + j * q_dim1] = w[i__] / q[i__ + j * q_dim1]; +/* L90: */ + } + temp = dnrm2_(k, &q[j * q_dim1 + 1], &c__1); + i__2 = *k; + for (i__ = 1; i__ <= i__2; ++i__) { + s[i__ + j * s_dim1] = q[i__ + j * q_dim1] / temp; +/* L100: */ + } +/* L110: */ + } + +L120: + return 0; + +/* End of DLAED9 */ + +} /* dlaed9_ */ + +/* Subroutine */ int dlaeda_(integer *n, integer *tlvls, integer *curlvl, + integer *curpbm, integer *prmptr, integer *perm, integer *givptr, + integer *givcol, doublereal *givnum, doublereal *q, integer *qptr, + doublereal *z__, doublereal *ztemp, integer *info) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + + /* Local variables */ + static integer i__, k, mid, ptr; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *); + static integer curr, bsiz1, bsiz2, psiz1, psiz2, zptr1; + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *), dcopy_(integer *, + doublereal *, integer *, doublereal *, integer *), xerbla_(char *, + integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLAEDA computes the Z vector corresponding to the merge step in the + CURLVLth step of the merge process with TLVLS steps for the CURPBMth + problem. + + Arguments + ========= + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + TLVLS (input) INTEGER + The total number of merging levels in the overall divide and + conquer tree. + + CURLVL (input) INTEGER + The current level in the overall merge routine, + 0 <= curlvl <= tlvls. + + CURPBM (input) INTEGER + The current problem in the current level in the overall + merge routine (counting from upper left to lower right). + + PRMPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in PERM a + level's permutation is stored. PRMPTR(i+1) - PRMPTR(i) + indicates the size of the permutation and incidentally the + size of the full, non-deflated problem. + + PERM (input) INTEGER array, dimension (N lg N) + Contains the permutations (from deflation and sorting) to be + applied to each eigenblock. + + GIVPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in GIVCOL a + level's Givens rotations are stored. GIVPTR(i+1) - GIVPTR(i) + indicates the number of Givens rotations. + + GIVCOL (input) INTEGER array, dimension (2, N lg N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (input) DOUBLE PRECISION array, dimension (2, N lg N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + Q (input) DOUBLE PRECISION array, dimension (N**2) + Contains the square eigenblocks from previous levels, the + starting positions for blocks are given by QPTR. + + QPTR (input) INTEGER array, dimension (N+2) + Contains a list of pointers which indicate where in Q an + eigenblock is stored. SQRT( QPTR(i+1) - QPTR(i) ) indicates + the size of the block. + + Z (output) DOUBLE PRECISION array, dimension (N) + On output this vector contains the updating vector (the last + row of the first sub-eigenvector matrix and the first row of + the second sub-eigenvector matrix). + + ZTEMP (workspace) DOUBLE PRECISION array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --ztemp; + --z__; + --qptr; + --q; + givnum -= 3; + givcol -= 3; + --givptr; + --perm; + --prmptr; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -1; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAEDA", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine location of first number in second half. */ + + mid = *n / 2 + 1; + +/* Gather last/first rows of appropriate eigenblocks into center of Z */ + + ptr = 1; + +/* + Determine location of lowest level subproblem in the full storage + scheme +*/ + + i__1 = *curlvl - 1; + curr = ptr + *curpbm * pow_ii(&c__2, curlvl) + pow_ii(&c__2, &i__1) - 1; + +/* + Determine size of these matrices. We add HALF to the value of + the SQRT in case the machine underestimates one of these square + roots. +*/ + + bsiz1 = (integer) (sqrt((doublereal) (qptr[curr + 1] - qptr[curr])) + .5); + bsiz2 = (integer) (sqrt((doublereal) (qptr[curr + 2] - qptr[curr + 1])) + + .5); + i__1 = mid - bsiz1 - 1; + for (k = 1; k <= i__1; ++k) { + z__[k] = 0.; +/* L10: */ + } + dcopy_(&bsiz1, &q[qptr[curr] + bsiz1 - 1], &bsiz1, &z__[mid - bsiz1], & + c__1); + dcopy_(&bsiz2, &q[qptr[curr + 1]], &bsiz2, &z__[mid], &c__1); + i__1 = *n; + for (k = mid + bsiz2; k <= i__1; ++k) { + z__[k] = 0.; +/* L20: */ + } + +/* + Loop through remaining levels 1 -> CURLVL applying the Givens + rotations and permutation and then multiplying the center matrices + against the current Z. +*/ + + ptr = pow_ii(&c__2, tlvls) + 1; + i__1 = *curlvl - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = *curlvl - k; + i__3 = *curlvl - k - 1; + curr = ptr + *curpbm * pow_ii(&c__2, &i__2) + pow_ii(&c__2, &i__3) - + 1; + psiz1 = prmptr[curr + 1] - prmptr[curr]; + psiz2 = prmptr[curr + 2] - prmptr[curr + 1]; + zptr1 = mid - psiz1; + +/* Apply Givens at CURR and CURR+1 */ + + i__2 = givptr[curr + 1] - 1; + for (i__ = givptr[curr]; i__ <= i__2; ++i__) { + drot_(&c__1, &z__[zptr1 + givcol[(i__ << 1) + 1] - 1], &c__1, & + z__[zptr1 + givcol[(i__ << 1) + 2] - 1], &c__1, &givnum[( + i__ << 1) + 1], &givnum[(i__ << 1) + 2]); +/* L30: */ + } + i__2 = givptr[curr + 2] - 1; + for (i__ = givptr[curr + 1]; i__ <= i__2; ++i__) { + drot_(&c__1, &z__[mid - 1 + givcol[(i__ << 1) + 1]], &c__1, &z__[ + mid - 1 + givcol[(i__ << 1) + 2]], &c__1, &givnum[(i__ << + 1) + 1], &givnum[(i__ << 1) + 2]); +/* L40: */ + } + psiz1 = prmptr[curr + 1] - prmptr[curr]; + psiz2 = prmptr[curr + 2] - prmptr[curr + 1]; + i__2 = psiz1 - 1; + for (i__ = 0; i__ <= i__2; ++i__) { + ztemp[i__ + 1] = z__[zptr1 + perm[prmptr[curr] + i__] - 1]; +/* L50: */ + } + i__2 = psiz2 - 1; + for (i__ = 0; i__ <= i__2; ++i__) { + ztemp[psiz1 + i__ + 1] = z__[mid + perm[prmptr[curr + 1] + i__] - + 1]; +/* L60: */ + } + +/* + Multiply Blocks at CURR and CURR+1 + + Determine size of these matrices. We add HALF to the value of + the SQRT in case the machine underestimates one of these + square roots. +*/ + + bsiz1 = (integer) (sqrt((doublereal) (qptr[curr + 1] - qptr[curr])) + + .5); + bsiz2 = (integer) (sqrt((doublereal) (qptr[curr + 2] - qptr[curr + 1]) + ) + .5); + if (bsiz1 > 0) { + dgemv_("T", &bsiz1, &bsiz1, &c_b15, &q[qptr[curr]], &bsiz1, & + ztemp[1], &c__1, &c_b29, &z__[zptr1], &c__1); + } + i__2 = psiz1 - bsiz1; + dcopy_(&i__2, &ztemp[bsiz1 + 1], &c__1, &z__[zptr1 + bsiz1], &c__1); + if (bsiz2 > 0) { + dgemv_("T", &bsiz2, &bsiz2, &c_b15, &q[qptr[curr + 1]], &bsiz2, & + ztemp[psiz1 + 1], &c__1, &c_b29, &z__[mid], &c__1); + } + i__2 = psiz2 - bsiz2; + dcopy_(&i__2, &ztemp[psiz1 + bsiz2 + 1], &c__1, &z__[mid + bsiz2], & + c__1); + + i__2 = *tlvls - k; + ptr += pow_ii(&c__2, &i__2); +/* L70: */ + } + + return 0; + +/* End of DLAEDA */ + +} /* dlaeda_ */ + +/* Subroutine */ int dlaev2_(doublereal *a, doublereal *b, doublereal *c__, + doublereal *rt1, doublereal *rt2, doublereal *cs1, doublereal *sn1) +{ + /* System generated locals */ + doublereal d__1; + + /* Local variables */ + static doublereal ab, df, cs, ct, tb, sm, tn, rt, adf, acs; + static integer sgn1, sgn2; + static doublereal acmn, acmx; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAEV2 computes the eigendecomposition of a 2-by-2 symmetric matrix + [ A B ] + [ B C ]. + On return, RT1 is the eigenvalue of larger absolute value, RT2 is the + eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right + eigenvector for RT1, giving the decomposition + + [ CS1 SN1 ] [ A B ] [ CS1 -SN1 ] = [ RT1 0 ] + [-SN1 CS1 ] [ B C ] [ SN1 CS1 ] [ 0 RT2 ]. + + Arguments + ========= + + A (input) DOUBLE PRECISION + The (1,1) element of the 2-by-2 matrix. + + B (input) DOUBLE PRECISION + The (1,2) element and the conjugate of the (2,1) element of + the 2-by-2 matrix. + + C (input) DOUBLE PRECISION + The (2,2) element of the 2-by-2 matrix. + + RT1 (output) DOUBLE PRECISION + The eigenvalue of larger absolute value. + + RT2 (output) DOUBLE PRECISION + The eigenvalue of smaller absolute value. + + CS1 (output) DOUBLE PRECISION + SN1 (output) DOUBLE PRECISION + The vector (CS1, SN1) is a unit right eigenvector for RT1. + + Further Details + =============== + + RT1 is accurate to a few ulps barring over/underflow. + + RT2 may be inaccurate if there is massive cancellation in the + determinant A*C-B*B; higher precision or correctly rounded or + correctly truncated arithmetic would be needed to compute RT2 + accurately in all cases. + + CS1 and SN1 are accurate to a few ulps barring over/underflow. + + Overflow is possible only if RT1 is within a factor of 5 of overflow. + Underflow is harmless if the input data is 0 or exceeds + underflow_threshold / macheps. + + ===================================================================== + + + Compute the eigenvalues +*/ + + sm = *a + *c__; + df = *a - *c__; + adf = abs(df); + tb = *b + *b; + ab = abs(tb); + if (abs(*a) > abs(*c__)) { + acmx = *a; + acmn = *c__; + } else { + acmx = *c__; + acmn = *a; + } + if (adf > ab) { +/* Computing 2nd power */ + d__1 = ab / adf; + rt = adf * sqrt(d__1 * d__1 + 1.); + } else if (adf < ab) { +/* Computing 2nd power */ + d__1 = adf / ab; + rt = ab * sqrt(d__1 * d__1 + 1.); + } else { + +/* Includes case AB=ADF=0 */ + + rt = ab * sqrt(2.); + } + if (sm < 0.) { + *rt1 = (sm - rt) * .5; + sgn1 = -1; + +/* + Order of execution important. + To get fully accurate smaller eigenvalue, + next line needs to be executed in higher precision. +*/ + + *rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b; + } else if (sm > 0.) { + *rt1 = (sm + rt) * .5; + sgn1 = 1; + +/* + Order of execution important. + To get fully accurate smaller eigenvalue, + next line needs to be executed in higher precision. +*/ + + *rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b; + } else { + +/* Includes case RT1 = RT2 = 0 */ + + *rt1 = rt * .5; + *rt2 = rt * -.5; + sgn1 = 1; + } + +/* Compute the eigenvector */ + + if (df >= 0.) { + cs = df + rt; + sgn2 = 1; + } else { + cs = df - rt; + sgn2 = -1; + } + acs = abs(cs); + if (acs > ab) { + ct = -tb / cs; + *sn1 = 1. / sqrt(ct * ct + 1.); + *cs1 = ct * *sn1; + } else { + if (ab == 0.) { + *cs1 = 1.; + *sn1 = 0.; + } else { + tn = -cs / tb; + *cs1 = 1. / sqrt(tn * tn + 1.); + *sn1 = tn * *cs1; + } + } + if (sgn1 == sgn2) { + tn = *cs1; + *cs1 = -(*sn1); + *sn1 = tn; + } + return 0; + +/* End of DLAEV2 */ + +} /* dlaev2_ */ + +/* Subroutine */ int dlaexc_(logical *wantq, integer *n, doublereal *t, + integer *ldt, doublereal *q, integer *ldq, integer *j1, integer *n1, + integer *n2, doublereal *work, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, t_dim1, t_offset, i__1; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static doublereal d__[16] /* was [4][4] */; + static integer k; + static doublereal u[3], x[4] /* was [2][2] */; + static integer j2, j3, j4; + static doublereal u1[3], u2[3]; + static integer nd; + static doublereal cs, t11, t22, t33, sn, wi1, wi2, wr1, wr2, eps, tau, + tau1, tau2; + static integer ierr; + static doublereal temp; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *); + static doublereal scale, dnorm, xnorm; + extern /* Subroutine */ int dlanv2_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *), dlasy2_( + logical *, logical *, integer *, integer *, integer *, doublereal + *, integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *); + extern doublereal dlamch_(char *), dlange_(char *, integer *, + integer *, doublereal *, integer *, doublereal *); + extern /* Subroutine */ int dlarfg_(integer *, doublereal *, doublereal *, + integer *, doublereal *), dlacpy_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *), + dlartg_(doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *), dlarfx_(char *, integer *, integer *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *); + static doublereal thresh, smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLAEXC swaps adjacent diagonal blocks T11 and T22 of order 1 or 2 in + an upper quasi-triangular matrix T by an orthogonal similarity + transformation. + + T must be in Schur canonical form, that is, block upper triangular + with 1-by-1 and 2-by-2 diagonal blocks; each 2-by-2 diagonal block + has its diagonal elemnts equal and its off-diagonal elements of + opposite sign. + + Arguments + ========= + + WANTQ (input) LOGICAL + = .TRUE. : accumulate the transformation in the matrix Q; + = .FALSE.: do not accumulate the transformation. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input/output) DOUBLE PRECISION array, dimension (LDT,N) + On entry, the upper quasi-triangular matrix T, in Schur + canonical form. + On exit, the updated matrix T, again in Schur canonical form. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + Q (input/output) DOUBLE PRECISION array, dimension (LDQ,N) + On entry, if WANTQ is .TRUE., the orthogonal matrix Q. + On exit, if WANTQ is .TRUE., the updated matrix Q. + If WANTQ is .FALSE., Q is not referenced. + + LDQ (input) INTEGER + The leading dimension of the array Q. + LDQ >= 1; and if WANTQ is .TRUE., LDQ >= N. + + J1 (input) INTEGER + The index of the first row of the first block T11. + + N1 (input) INTEGER + The order of the first block T11. N1 = 0, 1 or 2. + + N2 (input) INTEGER + The order of the second block T22. N2 = 0, 1 or 2. + + WORK (workspace) DOUBLE PRECISION array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + = 1: the transformed matrix T would be too far from Schur + form; the blocks are not swapped and T and Q are + unchanged. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --work; + + /* Function Body */ + *info = 0; + +/* Quick return if possible */ + + if (*n == 0 || *n1 == 0 || *n2 == 0) { + return 0; + } + if (*j1 + *n1 > *n) { + return 0; + } + + j2 = *j1 + 1; + j3 = *j1 + 2; + j4 = *j1 + 3; + + if (*n1 == 1 && *n2 == 1) { + +/* Swap two 1-by-1 blocks. */ + + t11 = t[*j1 + *j1 * t_dim1]; + t22 = t[j2 + j2 * t_dim1]; + +/* Determine the transformation to perform the interchange. */ + + d__1 = t22 - t11; + dlartg_(&t[*j1 + j2 * t_dim1], &d__1, &cs, &sn, &temp); + +/* Apply transformation to the matrix T. */ + + if (j3 <= *n) { + i__1 = *n - *j1 - 1; + drot_(&i__1, &t[*j1 + j3 * t_dim1], ldt, &t[j2 + j3 * t_dim1], + ldt, &cs, &sn); + } + i__1 = *j1 - 1; + drot_(&i__1, &t[*j1 * t_dim1 + 1], &c__1, &t[j2 * t_dim1 + 1], &c__1, + &cs, &sn); + + t[*j1 + *j1 * t_dim1] = t22; + t[j2 + j2 * t_dim1] = t11; + + if (*wantq) { + +/* Accumulate transformation in the matrix Q. */ + + drot_(n, &q[*j1 * q_dim1 + 1], &c__1, &q[j2 * q_dim1 + 1], &c__1, + &cs, &sn); + } + + } else { + +/* + Swapping involves at least one 2-by-2 block. + + Copy the diagonal block of order N1+N2 to the local array D + and compute its norm. +*/ + + nd = *n1 + *n2; + dlacpy_("Full", &nd, &nd, &t[*j1 + *j1 * t_dim1], ldt, d__, &c__4); + dnorm = dlange_("Max", &nd, &nd, d__, &c__4, &work[1]); + +/* + Compute machine-dependent threshold for test for accepting + swap. +*/ + + eps = PRECISION; + smlnum = SAFEMINIMUM / eps; +/* Computing MAX */ + d__1 = eps * 10. * dnorm; + thresh = max(d__1,smlnum); + +/* Solve T11*X - X*T22 = scale*T12 for X. */ + + dlasy2_(&c_false, &c_false, &c_n1, n1, n2, d__, &c__4, &d__[*n1 + 1 + + (*n1 + 1 << 2) - 5], &c__4, &d__[(*n1 + 1 << 2) - 4], &c__4, & + scale, x, &c__2, &xnorm, &ierr); + +/* Swap the adjacent diagonal blocks. */ + + k = *n1 + *n1 + *n2 - 3; + switch (k) { + case 1: goto L10; + case 2: goto L20; + case 3: goto L30; + } + +L10: + +/* + N1 = 1, N2 = 2: generate elementary reflector H so that: + + ( scale, X11, X12 ) H = ( 0, 0, * ) +*/ + + u[0] = scale; + u[1] = x[0]; + u[2] = x[2]; + dlarfg_(&c__3, &u[2], u, &c__1, &tau); + u[2] = 1.; + t11 = t[*j1 + *j1 * t_dim1]; + +/* Perform swap provisionally on diagonal block in D. */ + + dlarfx_("L", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]); + dlarfx_("R", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]); + +/* + Test whether to reject swap. + + Computing MAX +*/ + d__2 = abs(d__[2]), d__3 = abs(d__[6]), d__2 = max(d__2,d__3), d__3 = + (d__1 = d__[10] - t11, abs(d__1)); + if (max(d__2,d__3) > thresh) { + goto L50; + } + +/* Accept swap: apply transformation to the entire matrix T. */ + + i__1 = *n - *j1 + 1; + dlarfx_("L", &c__3, &i__1, u, &tau, &t[*j1 + *j1 * t_dim1], ldt, & + work[1]); + dlarfx_("R", &j2, &c__3, u, &tau, &t[*j1 * t_dim1 + 1], ldt, &work[1]); + + t[j3 + *j1 * t_dim1] = 0.; + t[j3 + j2 * t_dim1] = 0.; + t[j3 + j3 * t_dim1] = t11; + + if (*wantq) { + +/* Accumulate transformation in the matrix Q. */ + + dlarfx_("R", n, &c__3, u, &tau, &q[*j1 * q_dim1 + 1], ldq, &work[ + 1]); + } + goto L40; + +L20: + +/* + N1 = 2, N2 = 1: generate elementary reflector H so that: + + H ( -X11 ) = ( * ) + ( -X21 ) = ( 0 ) + ( scale ) = ( 0 ) +*/ + + u[0] = -x[0]; + u[1] = -x[1]; + u[2] = scale; + dlarfg_(&c__3, u, &u[1], &c__1, &tau); + u[0] = 1.; + t33 = t[j3 + j3 * t_dim1]; + +/* Perform swap provisionally on diagonal block in D. */ + + dlarfx_("L", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]); + dlarfx_("R", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]); + +/* + Test whether to reject swap. + + Computing MAX +*/ + d__2 = abs(d__[1]), d__3 = abs(d__[2]), d__2 = max(d__2,d__3), d__3 = + (d__1 = d__[0] - t33, abs(d__1)); + if (max(d__2,d__3) > thresh) { + goto L50; + } + +/* Accept swap: apply transformation to the entire matrix T. */ + + dlarfx_("R", &j3, &c__3, u, &tau, &t[*j1 * t_dim1 + 1], ldt, &work[1]); + i__1 = *n - *j1; + dlarfx_("L", &c__3, &i__1, u, &tau, &t[*j1 + j2 * t_dim1], ldt, &work[ + 1]); + + t[*j1 + *j1 * t_dim1] = t33; + t[j2 + *j1 * t_dim1] = 0.; + t[j3 + *j1 * t_dim1] = 0.; + + if (*wantq) { + +/* Accumulate transformation in the matrix Q. */ + + dlarfx_("R", n, &c__3, u, &tau, &q[*j1 * q_dim1 + 1], ldq, &work[ + 1]); + } + goto L40; + +L30: + +/* + N1 = 2, N2 = 2: generate elementary reflectors H(1) and H(2) so + that: + + H(2) H(1) ( -X11 -X12 ) = ( * * ) + ( -X21 -X22 ) ( 0 * ) + ( scale 0 ) ( 0 0 ) + ( 0 scale ) ( 0 0 ) +*/ + + u1[0] = -x[0]; + u1[1] = -x[1]; + u1[2] = scale; + dlarfg_(&c__3, u1, &u1[1], &c__1, &tau1); + u1[0] = 1.; + + temp = -tau1 * (x[2] + u1[1] * x[3]); + u2[0] = -temp * u1[1] - x[3]; + u2[1] = -temp * u1[2]; + u2[2] = scale; + dlarfg_(&c__3, u2, &u2[1], &c__1, &tau2); + u2[0] = 1.; + +/* Perform swap provisionally on diagonal block in D. */ + + dlarfx_("L", &c__3, &c__4, u1, &tau1, d__, &c__4, &work[1]) + ; + dlarfx_("R", &c__4, &c__3, u1, &tau1, d__, &c__4, &work[1]) + ; + dlarfx_("L", &c__3, &c__4, u2, &tau2, &d__[1], &c__4, &work[1]); + dlarfx_("R", &c__4, &c__3, u2, &tau2, &d__[4], &c__4, &work[1]); + +/* + Test whether to reject swap. + + Computing MAX +*/ + d__1 = abs(d__[2]), d__2 = abs(d__[6]), d__1 = max(d__1,d__2), d__2 = + abs(d__[3]), d__1 = max(d__1,d__2), d__2 = abs(d__[7]); + if (max(d__1,d__2) > thresh) { + goto L50; + } + +/* Accept swap: apply transformation to the entire matrix T. */ + + i__1 = *n - *j1 + 1; + dlarfx_("L", &c__3, &i__1, u1, &tau1, &t[*j1 + *j1 * t_dim1], ldt, & + work[1]); + dlarfx_("R", &j4, &c__3, u1, &tau1, &t[*j1 * t_dim1 + 1], ldt, &work[ + 1]); + i__1 = *n - *j1 + 1; + dlarfx_("L", &c__3, &i__1, u2, &tau2, &t[j2 + *j1 * t_dim1], ldt, & + work[1]); + dlarfx_("R", &j4, &c__3, u2, &tau2, &t[j2 * t_dim1 + 1], ldt, &work[1] + ); + + t[j3 + *j1 * t_dim1] = 0.; + t[j3 + j2 * t_dim1] = 0.; + t[j4 + *j1 * t_dim1] = 0.; + t[j4 + j2 * t_dim1] = 0.; + + if (*wantq) { + +/* Accumulate transformation in the matrix Q. */ + + dlarfx_("R", n, &c__3, u1, &tau1, &q[*j1 * q_dim1 + 1], ldq, & + work[1]); + dlarfx_("R", n, &c__3, u2, &tau2, &q[j2 * q_dim1 + 1], ldq, &work[ + 1]); + } + +L40: + + if (*n2 == 2) { + +/* Standardize new 2-by-2 block T11 */ + + dlanv2_(&t[*j1 + *j1 * t_dim1], &t[*j1 + j2 * t_dim1], &t[j2 + * + j1 * t_dim1], &t[j2 + j2 * t_dim1], &wr1, &wi1, &wr2, & + wi2, &cs, &sn); + i__1 = *n - *j1 - 1; + drot_(&i__1, &t[*j1 + (*j1 + 2) * t_dim1], ldt, &t[j2 + (*j1 + 2) + * t_dim1], ldt, &cs, &sn); + i__1 = *j1 - 1; + drot_(&i__1, &t[*j1 * t_dim1 + 1], &c__1, &t[j2 * t_dim1 + 1], & + c__1, &cs, &sn); + if (*wantq) { + drot_(n, &q[*j1 * q_dim1 + 1], &c__1, &q[j2 * q_dim1 + 1], & + c__1, &cs, &sn); + } + } + + if (*n1 == 2) { + +/* Standardize new 2-by-2 block T22 */ + + j3 = *j1 + *n2; + j4 = j3 + 1; + dlanv2_(&t[j3 + j3 * t_dim1], &t[j3 + j4 * t_dim1], &t[j4 + j3 * + t_dim1], &t[j4 + j4 * t_dim1], &wr1, &wi1, &wr2, &wi2, & + cs, &sn); + if (j3 + 2 <= *n) { + i__1 = *n - j3 - 1; + drot_(&i__1, &t[j3 + (j3 + 2) * t_dim1], ldt, &t[j4 + (j3 + 2) + * t_dim1], ldt, &cs, &sn); + } + i__1 = j3 - 1; + drot_(&i__1, &t[j3 * t_dim1 + 1], &c__1, &t[j4 * t_dim1 + 1], & + c__1, &cs, &sn); + if (*wantq) { + drot_(n, &q[j3 * q_dim1 + 1], &c__1, &q[j4 * q_dim1 + 1], & + c__1, &cs, &sn); + } + } + + } + return 0; + +/* Exit with INFO = 1 if swap was rejected. */ + +L50: + *info = 1; + return 0; + +/* End of DLAEXC */ + +} /* dlaexc_ */ + +/* Subroutine */ int dlahqr_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal + *wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, + integer *ldz, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3; + doublereal d__1, d__2, d__3, d__4; + + /* Local variables */ + static integer i__, j, k, l, m; + static doublereal s, v[3]; + static integer i1, i2; + static doublereal t1, t2, t3, v2, v3, aa, ab, ba, bb, h11, h12, h21, h22, + cs; + static integer nh; + static doublereal sn; + static integer nr; + static doublereal tr; + static integer nz; + static doublereal det, h21s; + static integer its; + static doublereal ulp, sum, tst, rt1i, rt2i, rt1r, rt2r; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *), dcopy_( + integer *, doublereal *, integer *, doublereal *, integer *), + dlanv2_(doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *), dlabad_(doublereal *, doublereal *); + + extern /* Subroutine */ int dlarfg_(integer *, doublereal *, doublereal *, + integer *, doublereal *); + static doublereal safmin, safmax, rtdisc, smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Purpose + ======= + + DLAHQR is an auxiliary routine called by DHSEQR to update the + eigenvalues and Schur decomposition already computed by DHSEQR, by + dealing with the Hessenberg submatrix in rows and columns ILO to + IHI. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper quasi-triangular in + rows and columns IHI+1:N, and that H(ILO,ILO-1) = 0 (unless + ILO = 1). DLAHQR works primarily with the Hessenberg + submatrix in rows and columns ILO to IHI, but applies + transformations to all of H if WANTT is .TRUE.. + 1 <= ILO <= max(1,IHI); IHI <= N. + + H (input/output) DOUBLE PRECISION array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO is zero and if WANTT is .TRUE., H is upper + quasi-triangular in rows and columns ILO:IHI, with any + 2-by-2 diagonal blocks in standard form. If INFO is zero + and WANTT is .FALSE., the contents of H are unspecified on + exit. The output state of H if INFO is nonzero is given + below under the description of INFO. + + LDH (input) INTEGER + The leading dimension of the array H. LDH >= max(1,N). + + WR (output) DOUBLE PRECISION array, dimension (N) + WI (output) DOUBLE PRECISION array, dimension (N) + The real and imaginary parts, respectively, of the computed + eigenvalues ILO to IHI are stored in the corresponding + elements of WR and WI. If two eigenvalues are computed as a + complex conjugate pair, they are stored in consecutive + elements of WR and WI, say the i-th and (i+1)th, with + WI(i) > 0 and WI(i+1) < 0. If WANTT is .TRUE., the + eigenvalues are stored in the same order as on the diagonal + of the Schur form returned in H, with WR(i) = H(i,i), and, if + H(i:i+1,i:i+1) is a 2-by-2 diagonal block, + WI(i) = sqrt(H(i+1,i)*H(i,i+1)) and WI(i+1) = -WI(i). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. + 1 <= ILOZ <= ILO; IHI <= IHIZ <= N. + + Z (input/output) DOUBLE PRECISION array, dimension (LDZ,N) + If WANTZ is .TRUE., on entry Z must contain the current + matrix Z of transformations accumulated by DHSEQR, and on + exit Z has been updated; transformations are applied only to + the submatrix Z(ILOZ:IHIZ,ILO:IHI). + If WANTZ is .FALSE., Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: If INFO = i, DLAHQR failed to compute all the + eigenvalues ILO to IHI in a total of 30 iterations + per eigenvalue; elements i+1:ihi of WR and WI + contain those eigenvalues which have been + successfully computed. + + If INFO .GT. 0 and WANTT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the + eigenvalues of the upper Hessenberg matrix rows + and columns ILO thorugh INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + (*) (initial value of H)*U = U*(final value of H) + where U is an orthognal matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + (final value of Z) = (initial value of Z)*U + where U is the orthogonal matrix in (*) + (regardless of the value of WANTT.) + + Further Details + =============== + + 02-96 Based on modifications by + David Day, Sandia National Laboratory, USA + + 12-04 Further modifications by + Ralph Byers, University of Kansas, USA + This is a modified version of DLAHQR from LAPACK version 3.0. + It is (1) more robust against overflow and underflow and + (2) adopts the more conservative Ahues & Tisseur stopping + criterion (LAWN 122, 1997). + + ========================================================= +*/ + + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --wr; + --wi; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + + /* Function Body */ + *info = 0; + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*ilo == *ihi) { + wr[*ilo] = h__[*ilo + *ilo * h_dim1]; + wi[*ilo] = 0.; + return 0; + } + +/* ==== clear out the trash ==== */ + i__1 = *ihi - 3; + for (j = *ilo; j <= i__1; ++j) { + h__[j + 2 + j * h_dim1] = 0.; + h__[j + 3 + j * h_dim1] = 0.; +/* L10: */ + } + if (*ilo <= *ihi - 2) { + h__[*ihi + (*ihi - 2) * h_dim1] = 0.; + } + + nh = *ihi - *ilo + 1; + nz = *ihiz - *iloz + 1; + +/* Set machine-dependent constants for the stopping criterion. */ + + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + dlabad_(&safmin, &safmax); + ulp = PRECISION; + smlnum = safmin * ((doublereal) nh / ulp); + +/* + I1 and I2 are the indices of the first row and last column of H + to which transformations must be applied. If eigenvalues only are + being computed, I1 and I2 are set inside the main loop. +*/ + + if (*wantt) { + i1 = 1; + i2 = *n; + } + +/* + The main loop begins here. I is the loop index and decreases from + IHI to ILO in steps of 1 or 2. Each iteration of the loop works + with the active submatrix in rows and columns L to I. + Eigenvalues I+1 to IHI have already converged. Either L = ILO or + H(L,L-1) is negligible so that the matrix splits. +*/ + + i__ = *ihi; +L20: + l = *ilo; + if (i__ < *ilo) { + goto L160; + } + +/* + Perform QR iterations on rows and columns ILO to I until a + submatrix of order 1 or 2 splits off at the bottom because a + subdiagonal element has become negligible. +*/ + + for (its = 0; its <= 30; ++its) { + +/* Look for a single small subdiagonal element. */ + + i__1 = l + 1; + for (k = i__; k >= i__1; --k) { + if ((d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)) <= smlnum) { + goto L40; + } + tst = (d__1 = h__[k - 1 + (k - 1) * h_dim1], abs(d__1)) + (d__2 = + h__[k + k * h_dim1], abs(d__2)); + if (tst == 0.) { + if (k - 2 >= *ilo) { + tst += (d__1 = h__[k - 1 + (k - 2) * h_dim1], abs(d__1)); + } + if (k + 1 <= *ihi) { + tst += (d__1 = h__[k + 1 + k * h_dim1], abs(d__1)); + } + } +/* + ==== The following is a conservative small subdiagonal + . deflation criterion due to Ahues & Tisseur (LAWN 122, + . 1997). It has better mathematical foundation and + . improves accuracy in some cases. ==== +*/ + if ((d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)) <= ulp * tst) { +/* Computing MAX */ + d__3 = (d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)), d__4 = ( + d__2 = h__[k - 1 + k * h_dim1], abs(d__2)); + ab = max(d__3,d__4); +/* Computing MIN */ + d__3 = (d__1 = h__[k + (k - 1) * h_dim1], abs(d__1)), d__4 = ( + d__2 = h__[k - 1 + k * h_dim1], abs(d__2)); + ba = min(d__3,d__4); +/* Computing MAX */ + d__3 = (d__1 = h__[k + k * h_dim1], abs(d__1)), d__4 = (d__2 = + h__[k - 1 + (k - 1) * h_dim1] - h__[k + k * h_dim1], + abs(d__2)); + aa = max(d__3,d__4); +/* Computing MIN */ + d__3 = (d__1 = h__[k + k * h_dim1], abs(d__1)), d__4 = (d__2 = + h__[k - 1 + (k - 1) * h_dim1] - h__[k + k * h_dim1], + abs(d__2)); + bb = min(d__3,d__4); + s = aa + ab; +/* Computing MAX */ + d__1 = smlnum, d__2 = ulp * (bb * (aa / s)); + if (ba * (ab / s) <= max(d__1,d__2)) { + goto L40; + } + } +/* L30: */ + } +L40: + l = k; + if (l > *ilo) { + +/* H(L,L-1) is negligible */ + + h__[l + (l - 1) * h_dim1] = 0.; + } + +/* Exit from loop if a submatrix of order 1 or 2 has split off. */ + + if (l >= i__ - 1) { + goto L150; + } + +/* + Now the active submatrix is in rows and columns L to I. If + eigenvalues only are being computed, only the active submatrix + need be transformed. +*/ + + if (! (*wantt)) { + i1 = l; + i2 = i__; + } + + if (its == 10) { + +/* Exceptional shift. */ + + s = (d__1 = h__[l + 1 + l * h_dim1], abs(d__1)) + (d__2 = h__[l + + 2 + (l + 1) * h_dim1], abs(d__2)); + h11 = s * .75 + h__[l + l * h_dim1]; + h12 = s * -.4375; + h21 = s; + h22 = h11; + } else if (its == 20) { + +/* Exceptional shift. */ + + s = (d__1 = h__[i__ + (i__ - 1) * h_dim1], abs(d__1)) + (d__2 = + h__[i__ - 1 + (i__ - 2) * h_dim1], abs(d__2)); + h11 = s * .75 + h__[i__ + i__ * h_dim1]; + h12 = s * -.4375; + h21 = s; + h22 = h11; + } else { + +/* + Prepare to use Francis' double shift + (i.e. 2nd degree generalized Rayleigh quotient) +*/ + + h11 = h__[i__ - 1 + (i__ - 1) * h_dim1]; + h21 = h__[i__ + (i__ - 1) * h_dim1]; + h12 = h__[i__ - 1 + i__ * h_dim1]; + h22 = h__[i__ + i__ * h_dim1]; + } + s = abs(h11) + abs(h12) + abs(h21) + abs(h22); + if (s == 0.) { + rt1r = 0.; + rt1i = 0.; + rt2r = 0.; + rt2i = 0.; + } else { + h11 /= s; + h21 /= s; + h12 /= s; + h22 /= s; + tr = (h11 + h22) / 2.; + det = (h11 - tr) * (h22 - tr) - h12 * h21; + rtdisc = sqrt((abs(det))); + if (det >= 0.) { + +/* ==== complex conjugate shifts ==== */ + + rt1r = tr * s; + rt2r = rt1r; + rt1i = rtdisc * s; + rt2i = -rt1i; + } else { + +/* ==== real shifts (use only one of them) ==== */ + + rt1r = tr + rtdisc; + rt2r = tr - rtdisc; + if ((d__1 = rt1r - h22, abs(d__1)) <= (d__2 = rt2r - h22, abs( + d__2))) { + rt1r *= s; + rt2r = rt1r; + } else { + rt2r *= s; + rt1r = rt2r; + } + rt1i = 0.; + rt2i = 0.; + } + } + +/* Look for two consecutive small subdiagonal elements. */ + + i__1 = l; + for (m = i__ - 2; m >= i__1; --m) { +/* + Determine the effect of starting the double-shift QR + iteration at row M, and see if this would make H(M,M-1) + negligible. (The following uses scaling to avoid + overflows and most underflows.) +*/ + + h21s = h__[m + 1 + m * h_dim1]; + s = (d__1 = h__[m + m * h_dim1] - rt2r, abs(d__1)) + abs(rt2i) + + abs(h21s); + h21s = h__[m + 1 + m * h_dim1] / s; + v[0] = h21s * h__[m + (m + 1) * h_dim1] + (h__[m + m * h_dim1] - + rt1r) * ((h__[m + m * h_dim1] - rt2r) / s) - rt1i * (rt2i + / s); + v[1] = h21s * (h__[m + m * h_dim1] + h__[m + 1 + (m + 1) * h_dim1] + - rt1r - rt2r); + v[2] = h21s * h__[m + 2 + (m + 1) * h_dim1]; + s = abs(v[0]) + abs(v[1]) + abs(v[2]); + v[0] /= s; + v[1] /= s; + v[2] /= s; + if (m == l) { + goto L60; + } + if ((d__1 = h__[m + (m - 1) * h_dim1], abs(d__1)) * (abs(v[1]) + + abs(v[2])) <= ulp * abs(v[0]) * ((d__2 = h__[m - 1 + (m - + 1) * h_dim1], abs(d__2)) + (d__3 = h__[m + m * h_dim1], + abs(d__3)) + (d__4 = h__[m + 1 + (m + 1) * h_dim1], abs( + d__4)))) { + goto L60; + } +/* L50: */ + } +L60: + +/* Double-shift QR step */ + + i__1 = i__ - 1; + for (k = m; k <= i__1; ++k) { + +/* + The first iteration of this loop determines a reflection G + from the vector V and applies it from left and right to H, + thus creating a nonzero bulge below the subdiagonal. + + Each subsequent iteration determines a reflection G to + restore the Hessenberg form in the (K-1)th column, and thus + chases the bulge one step toward the bottom of the active + submatrix. NR is the order of G. + + Computing MIN +*/ + i__2 = 3, i__3 = i__ - k + 1; + nr = min(i__2,i__3); + if (k > m) { + dcopy_(&nr, &h__[k + (k - 1) * h_dim1], &c__1, v, &c__1); + } + dlarfg_(&nr, v, &v[1], &c__1, &t1); + if (k > m) { + h__[k + (k - 1) * h_dim1] = v[0]; + h__[k + 1 + (k - 1) * h_dim1] = 0.; + if (k < i__ - 1) { + h__[k + 2 + (k - 1) * h_dim1] = 0.; + } + } else if (m > l) { +/* + ==== Use the following instead of + . H( K, K-1 ) = -H( K, K-1 ) to + . avoid a bug when v(2) and v(3) + . underflow. ==== +*/ + h__[k + (k - 1) * h_dim1] *= 1. - t1; + } + v2 = v[1]; + t2 = t1 * v2; + if (nr == 3) { + v3 = v[2]; + t3 = t1 * v3; + +/* + Apply G from the left to transform the rows of the matrix + in columns K to I2. +*/ + + i__2 = i2; + for (j = k; j <= i__2; ++j) { + sum = h__[k + j * h_dim1] + v2 * h__[k + 1 + j * h_dim1] + + v3 * h__[k + 2 + j * h_dim1]; + h__[k + j * h_dim1] -= sum * t1; + h__[k + 1 + j * h_dim1] -= sum * t2; + h__[k + 2 + j * h_dim1] -= sum * t3; +/* L70: */ + } + +/* + Apply G from the right to transform the columns of the + matrix in rows I1 to min(K+3,I). + + Computing MIN +*/ + i__3 = k + 3; + i__2 = min(i__3,i__); + for (j = i1; j <= i__2; ++j) { + sum = h__[j + k * h_dim1] + v2 * h__[j + (k + 1) * h_dim1] + + v3 * h__[j + (k + 2) * h_dim1]; + h__[j + k * h_dim1] -= sum * t1; + h__[j + (k + 1) * h_dim1] -= sum * t2; + h__[j + (k + 2) * h_dim1] -= sum * t3; +/* L80: */ + } + + if (*wantz) { + +/* Accumulate transformations in the matrix Z */ + + i__2 = *ihiz; + for (j = *iloz; j <= i__2; ++j) { + sum = z__[j + k * z_dim1] + v2 * z__[j + (k + 1) * + z_dim1] + v3 * z__[j + (k + 2) * z_dim1]; + z__[j + k * z_dim1] -= sum * t1; + z__[j + (k + 1) * z_dim1] -= sum * t2; + z__[j + (k + 2) * z_dim1] -= sum * t3; +/* L90: */ + } + } + } else if (nr == 2) { + +/* + Apply G from the left to transform the rows of the matrix + in columns K to I2. +*/ + + i__2 = i2; + for (j = k; j <= i__2; ++j) { + sum = h__[k + j * h_dim1] + v2 * h__[k + 1 + j * h_dim1]; + h__[k + j * h_dim1] -= sum * t1; + h__[k + 1 + j * h_dim1] -= sum * t2; +/* L100: */ + } + +/* + Apply G from the right to transform the columns of the + matrix in rows I1 to min(K+3,I). +*/ + + i__2 = i__; + for (j = i1; j <= i__2; ++j) { + sum = h__[j + k * h_dim1] + v2 * h__[j + (k + 1) * h_dim1] + ; + h__[j + k * h_dim1] -= sum * t1; + h__[j + (k + 1) * h_dim1] -= sum * t2; +/* L110: */ + } + + if (*wantz) { + +/* Accumulate transformations in the matrix Z */ + + i__2 = *ihiz; + for (j = *iloz; j <= i__2; ++j) { + sum = z__[j + k * z_dim1] + v2 * z__[j + (k + 1) * + z_dim1]; + z__[j + k * z_dim1] -= sum * t1; + z__[j + (k + 1) * z_dim1] -= sum * t2; +/* L120: */ + } + } + } +/* L130: */ + } + +/* L140: */ + } + +/* Failure to converge in remaining number of iterations */ + + *info = i__; + return 0; + +L150: + + if (l == i__) { + +/* H(I,I-1) is negligible: one eigenvalue has converged. */ + + wr[i__] = h__[i__ + i__ * h_dim1]; + wi[i__] = 0.; + } else if (l == i__ - 1) { + +/* + H(I-1,I-2) is negligible: a pair of eigenvalues have converged. + + Transform the 2-by-2 submatrix to standard Schur form, + and compute and store the eigenvalues. +*/ + + dlanv2_(&h__[i__ - 1 + (i__ - 1) * h_dim1], &h__[i__ - 1 + i__ * + h_dim1], &h__[i__ + (i__ - 1) * h_dim1], &h__[i__ + i__ * + h_dim1], &wr[i__ - 1], &wi[i__ - 1], &wr[i__], &wi[i__], &cs, + &sn); + + if (*wantt) { + +/* Apply the transformation to the rest of H. */ + + if (i2 > i__) { + i__1 = i2 - i__; + drot_(&i__1, &h__[i__ - 1 + (i__ + 1) * h_dim1], ldh, &h__[ + i__ + (i__ + 1) * h_dim1], ldh, &cs, &sn); + } + i__1 = i__ - i1 - 1; + drot_(&i__1, &h__[i1 + (i__ - 1) * h_dim1], &c__1, &h__[i1 + i__ * + h_dim1], &c__1, &cs, &sn); + } + if (*wantz) { + +/* Apply the transformation to Z. */ + + drot_(&nz, &z__[*iloz + (i__ - 1) * z_dim1], &c__1, &z__[*iloz + + i__ * z_dim1], &c__1, &cs, &sn); + } + } + +/* return to start of the main loop with new value of I. */ + + i__ = l - 1; + goto L20; + +L160: + return 0; + +/* End of DLAHQR */ + +} /* dlahqr_ */ + +/* Subroutine */ int dlahr2_(integer *n, integer *k, integer *nb, doublereal * + a, integer *lda, doublereal *tau, doublereal *t, integer *ldt, + doublereal *y, integer *ldy) +{ + /* System generated locals */ + integer a_dim1, a_offset, t_dim1, t_offset, y_dim1, y_offset, i__1, i__2, + i__3; + doublereal d__1; + + /* Local variables */ + static integer i__; + static doublereal ei; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *), dgemm_(char *, char *, integer *, integer *, integer * + , doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *), dgemv_( + char *, integer *, integer *, doublereal *, doublereal *, integer + *, doublereal *, integer *, doublereal *, doublereal *, integer *), dcopy_(integer *, doublereal *, integer *, doublereal *, + integer *), dtrmm_(char *, char *, char *, char *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *), daxpy_(integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *), + dtrmv_(char *, char *, char *, integer *, doublereal *, integer *, + doublereal *, integer *), dlarfg_( + integer *, doublereal *, doublereal *, integer *, doublereal *), + dlacpy_(char *, integer *, integer *, doublereal *, integer *, + doublereal *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + -- April 2009 -- + + + Purpose + ======= + + DLAHR2 reduces the first NB columns of A real general n-BY-(n-k+1) + matrix A so that elements below the k-th subdiagonal are zero. The + reduction is performed by an orthogonal similarity transformation + Q' * A * Q. The routine returns the matrices V and T which determine + Q as a block reflector I - V*T*V', and also the matrix Y = A * V * T. + + This is an auxiliary routine called by DGEHRD. + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. + + K (input) INTEGER + The offset for the reduction. Elements below the k-th + subdiagonal in the first NB columns are reduced to zero. + K < N. + + NB (input) INTEGER + The number of columns to be reduced. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N-K+1) + On entry, the n-by-(n-k+1) general matrix A. + On exit, the elements on and above the k-th subdiagonal in + the first NB columns are overwritten with the corresponding + elements of the reduced matrix; the elements below the k-th + subdiagonal, with the array TAU, represent the matrix Q as a + product of elementary reflectors. The other columns of A are + unchanged. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) DOUBLE PRECISION array, dimension (NB) + The scalar factors of the elementary reflectors. See Further + Details. + + T (output) DOUBLE PRECISION array, dimension (LDT,NB) + The upper triangular matrix T. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= NB. + + Y (output) DOUBLE PRECISION array, dimension (LDY,NB) + The n-by-nb matrix Y. + + LDY (input) INTEGER + The leading dimension of the array Y. LDY >= N. + + Further Details + =============== + + The matrix Q is represented as a product of nb elementary reflectors + + Q = H(1) H(2) . . . H(nb). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i+k-1) = 0, v(i+k) = 1; v(i+k+1:n) is stored on exit in + A(i+k+1:n,i), and tau in TAU(i). + + The elements of the vectors v together form the (n-k+1)-by-nb matrix + V which is needed, with T and Y, to apply the transformation to the + unreduced part of the matrix, using an update of the form: + A := (I - V*T*V') * (A - Y*V'). + + The contents of A on exit are illustrated by the following example + with n = 7, k = 3 and nb = 2: + + ( a a a a a ) + ( a a a a a ) + ( a a a a a ) + ( h h a a a ) + ( v1 h a a a ) + ( v1 v2 a a a ) + ( v1 v2 a a a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + This subroutine is a slight modification of LAPACK-3.0's DLAHRD + incorporating improvements proposed by Quintana-Orti and Van de + Gejin. Note that the entries of A(1:K,2:NB) differ from those + returned by the original LAPACK-3.0's DLAHRD routine. (This + subroutine is not backward compatible with LAPACK-3.0's DLAHRD.) + + References + ========== + + Gregorio Quintana-Orti and Robert van de Geijn, "Improving the + performance of reduction to Hessenberg form," ACM Transactions on + Mathematical Software, 32(2):180-194, June 2006. + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + --tau; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + y_dim1 = *ldy; + y_offset = 1 + y_dim1; + y -= y_offset; + + /* Function Body */ + if (*n <= 1) { + return 0; + } + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__ > 1) { + +/* + Update A(K+1:N,I) + + Update I-th column of A - Y * V' +*/ + + i__2 = *n - *k; + i__3 = i__ - 1; + dgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b151, &y[*k + 1 + y_dim1], + ldy, &a[*k + i__ - 1 + a_dim1], lda, &c_b15, &a[*k + 1 + + i__ * a_dim1], &c__1); + +/* + Apply I - V * T' * V' to this column (call it b) from the + left, using the last column of T as workspace + + Let V = ( V1 ) and b = ( b1 ) (first I-1 rows) + ( V2 ) ( b2 ) + + where V1 is unit lower triangular + + w := V1' * b1 +*/ + + i__2 = i__ - 1; + dcopy_(&i__2, &a[*k + 1 + i__ * a_dim1], &c__1, &t[*nb * t_dim1 + + 1], &c__1); + i__2 = i__ - 1; + dtrmv_("Lower", "Transpose", "UNIT", &i__2, &a[*k + 1 + a_dim1], + lda, &t[*nb * t_dim1 + 1], &c__1); + +/* w := w + V2'*b2 */ + + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[*k + i__ + a_dim1], + lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b15, &t[*nb * + t_dim1 + 1], &c__1); + +/* w := T'*w */ + + i__2 = i__ - 1; + dtrmv_("Upper", "Transpose", "NON-UNIT", &i__2, &t[t_offset], ldt, + &t[*nb * t_dim1 + 1], &c__1); + +/* b2 := b2 - V2*w */ + + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + dgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b151, &a[*k + i__ + + a_dim1], lda, &t[*nb * t_dim1 + 1], &c__1, &c_b15, &a[*k + + i__ + i__ * a_dim1], &c__1); + +/* b1 := b1 - V1*w */ + + i__2 = i__ - 1; + dtrmv_("Lower", "NO TRANSPOSE", "UNIT", &i__2, &a[*k + 1 + a_dim1] + , lda, &t[*nb * t_dim1 + 1], &c__1); + i__2 = i__ - 1; + daxpy_(&i__2, &c_b151, &t[*nb * t_dim1 + 1], &c__1, &a[*k + 1 + + i__ * a_dim1], &c__1); + + a[*k + i__ - 1 + (i__ - 1) * a_dim1] = ei; + } + +/* + Generate the elementary reflector H(I) to annihilate + A(K+I+1:N,I) +*/ + + i__2 = *n - *k - i__ + 1; +/* Computing MIN */ + i__3 = *k + i__ + 1; + dlarfg_(&i__2, &a[*k + i__ + i__ * a_dim1], &a[min(i__3,*n) + i__ * + a_dim1], &c__1, &tau[i__]); + ei = a[*k + i__ + i__ * a_dim1]; + a[*k + i__ + i__ * a_dim1] = 1.; + +/* Compute Y(K+1:N,I) */ + + i__2 = *n - *k; + i__3 = *n - *k - i__ + 1; + dgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b15, &a[*k + 1 + (i__ + 1) * + a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b29, &y[* + k + 1 + i__ * y_dim1], &c__1); + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[*k + i__ + a_dim1], lda, + &a[*k + i__ + i__ * a_dim1], &c__1, &c_b29, &t[i__ * t_dim1 + + 1], &c__1); + i__2 = *n - *k; + i__3 = i__ - 1; + dgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b151, &y[*k + 1 + y_dim1], + ldy, &t[i__ * t_dim1 + 1], &c__1, &c_b15, &y[*k + 1 + i__ * + y_dim1], &c__1); + i__2 = *n - *k; + dscal_(&i__2, &tau[i__], &y[*k + 1 + i__ * y_dim1], &c__1); + +/* Compute T(1:I,I) */ + + i__2 = i__ - 1; + d__1 = -tau[i__]; + dscal_(&i__2, &d__1, &t[i__ * t_dim1 + 1], &c__1); + i__2 = i__ - 1; + dtrmv_("Upper", "No Transpose", "NON-UNIT", &i__2, &t[t_offset], ldt, + &t[i__ * t_dim1 + 1], &c__1) + ; + t[i__ + i__ * t_dim1] = tau[i__]; + +/* L10: */ + } + a[*k + *nb + *nb * a_dim1] = ei; + +/* Compute Y(1:K,1:NB) */ + + dlacpy_("ALL", k, nb, &a[(a_dim1 << 1) + 1], lda, &y[y_offset], ldy); + dtrmm_("RIGHT", "Lower", "NO TRANSPOSE", "UNIT", k, nb, &c_b15, &a[*k + 1 + + a_dim1], lda, &y[y_offset], ldy); + if (*n > *k + *nb) { + i__1 = *n - *k - *nb; + dgemm_("NO TRANSPOSE", "NO TRANSPOSE", k, nb, &i__1, &c_b15, &a[(*nb + + 2) * a_dim1 + 1], lda, &a[*k + 1 + *nb + a_dim1], lda, & + c_b15, &y[y_offset], ldy); + } + dtrmm_("RIGHT", "Upper", "NO TRANSPOSE", "NON-UNIT", k, nb, &c_b15, &t[ + t_offset], ldt, &y[y_offset], ldy); + + return 0; + +/* End of DLAHR2 */ + +} /* dlahr2_ */ + +logical dlaisnan_(doublereal *din1, doublereal *din2) +{ + /* System generated locals */ + logical ret_val; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + This routine is not for general use. It exists solely to avoid + over-optimization in DISNAN. + + DLAISNAN checks for NaNs by comparing its two arguments for + inequality. NaN is the only floating-point value where NaN != NaN + returns .TRUE. To check for NaNs, pass the same variable as both + arguments. + + A compiler must assume that the two arguments are + not the same variable, and the test will not be optimized away. + Interprocedural or whole-program optimization may delete this + test. The ISNAN functions will be replaced by the correct + Fortran 03 intrinsic once the intrinsic is widely available. + + Arguments + ========= + + DIN1 (input) DOUBLE PRECISION + + DIN2 (input) DOUBLE PRECISION + Two numbers to compare for inequality. + + ===================================================================== +*/ + + ret_val = *din1 != *din2; + return ret_val; +} /* dlaisnan_ */ + +/* Subroutine */ int dlaln2_(logical *ltrans, integer *na, integer *nw, + doublereal *smin, doublereal *ca, doublereal *a, integer *lda, + doublereal *d1, doublereal *d2, doublereal *b, integer *ldb, + doublereal *wr, doublereal *wi, doublereal *x, integer *ldx, + doublereal *scale, doublereal *xnorm, integer *info) +{ + /* Initialized data */ + + static logical zswap[4] = { FALSE_,FALSE_,TRUE_,TRUE_ }; + static logical rswap[4] = { FALSE_,TRUE_,FALSE_,TRUE_ }; + static integer ipivot[16] /* was [4][4] */ = { 1,2,3,4,2,1,4,3,3,4,1,2, + 4,3,2,1 }; + + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, x_dim1, x_offset; + doublereal d__1, d__2, d__3, d__4, d__5, d__6; + static doublereal equiv_0[4], equiv_1[4]; + + /* Local variables */ + static integer j; +#define ci (equiv_0) +#define cr (equiv_1) + static doublereal bi1, bi2, br1, br2, xi1, xi2, xr1, xr2, ci21, ci22, + cr21, cr22, li21, csi, ui11, lr21, ui12, ui22; +#define civ (equiv_0) + static doublereal csr, ur11, ur12, ur22; +#define crv (equiv_1) + static doublereal bbnd, cmax, ui11r, ui12s, temp, ur11r, ur12s, u22abs; + static integer icmax; + static doublereal bnorm, cnorm, smini; + + extern /* Subroutine */ int dladiv_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *); + static doublereal bignum, smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLALN2 solves a system of the form (ca A - w D ) X = s B + or (ca A' - w D) X = s B with possible scaling ("s") and + perturbation of A. (A' means A-transpose.) + + A is an NA x NA real matrix, ca is a real scalar, D is an NA x NA + real diagonal matrix, w is a real or complex value, and X and B are + NA x 1 matrices -- real if w is real, complex if w is complex. NA + may be 1 or 2. + + If w is complex, X and B are represented as NA x 2 matrices, + the first column of each being the real part and the second + being the imaginary part. + + "s" is a scaling factor (.LE. 1), computed by DLALN2, which is + so chosen that X can be computed without overflow. X is further + scaled if necessary to assure that norm(ca A - w D)*norm(X) is less + than overflow. + + If both singular values of (ca A - w D) are less than SMIN, + SMIN*identity will be used instead of (ca A - w D). If only one + singular value is less than SMIN, one element of (ca A - w D) will be + perturbed enough to make the smallest singular value roughly SMIN. + If both singular values are at least SMIN, (ca A - w D) will not be + perturbed. In any case, the perturbation will be at most some small + multiple of max( SMIN, ulp*norm(ca A - w D) ). The singular values + are computed by infinity-norm approximations, and thus will only be + correct to a factor of 2 or so. + + Note: all input quantities are assumed to be smaller than overflow + by a reasonable factor. (See BIGNUM.) + + Arguments + ========== + + LTRANS (input) LOGICAL + =.TRUE.: A-transpose will be used. + =.FALSE.: A will be used (not transposed.) + + NA (input) INTEGER + The size of the matrix A. It may (only) be 1 or 2. + + NW (input) INTEGER + 1 if "w" is real, 2 if "w" is complex. It may only be 1 + or 2. + + SMIN (input) DOUBLE PRECISION + The desired lower bound on the singular values of A. This + should be a safe distance away from underflow or overflow, + say, between (underflow/machine precision) and (machine + precision * overflow ). (See BIGNUM and ULP.) + + CA (input) DOUBLE PRECISION + The coefficient c, which A is multiplied by. + + A (input) DOUBLE PRECISION array, dimension (LDA,NA) + The NA x NA matrix A. + + LDA (input) INTEGER + The leading dimension of A. It must be at least NA. + + D1 (input) DOUBLE PRECISION + The 1,1 element in the diagonal matrix D. + + D2 (input) DOUBLE PRECISION + The 2,2 element in the diagonal matrix D. Not used if NW=1. + + B (input) DOUBLE PRECISION array, dimension (LDB,NW) + The NA x NW matrix B (right-hand side). If NW=2 ("w" is + complex), column 1 contains the real part of B and column 2 + contains the imaginary part. + + LDB (input) INTEGER + The leading dimension of B. It must be at least NA. + + WR (input) DOUBLE PRECISION + The real part of the scalar "w". + + WI (input) DOUBLE PRECISION + The imaginary part of the scalar "w". Not used if NW=1. + + X (output) DOUBLE PRECISION array, dimension (LDX,NW) + The NA x NW matrix X (unknowns), as computed by DLALN2. + If NW=2 ("w" is complex), on exit, column 1 will contain + the real part of X and column 2 will contain the imaginary + part. + + LDX (input) INTEGER + The leading dimension of X. It must be at least NA. + + SCALE (output) DOUBLE PRECISION + The scale factor that B must be multiplied by to insure + that overflow does not occur when computing X. Thus, + (ca A - w D) X will be SCALE*B, not B (ignoring + perturbations of A.) It will be at most 1. + + XNORM (output) DOUBLE PRECISION + The infinity-norm of X, when X is regarded as an NA x NW + real matrix. + + INFO (output) INTEGER + An error flag. It will be set to zero if no error occurs, + a negative number if an argument is in error, or a positive + number if ca A - w D had to be perturbed. + The possible values are: + = 0: No error occurred, and (ca A - w D) did not have to be + perturbed. + = 1: (ca A - w D) had to be perturbed to make its smallest + (or only) singular value greater than SMIN. + NOTE: In the interests of speed, this routine does not + check the inputs for errors. + + ===================================================================== +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + + /* Function Body */ + +/* Compute BIGNUM */ + + smlnum = 2. * SAFEMINIMUM; + bignum = 1. / smlnum; + smini = max(*smin,smlnum); + +/* Don't check for input errors */ + + *info = 0; + +/* Standard Initializations */ + + *scale = 1.; + + if (*na == 1) { + +/* 1 x 1 (i.e., scalar) system C X = B */ + + if (*nw == 1) { + +/* + Real 1x1 system. + + C = ca A - w D +*/ + + csr = *ca * a[a_dim1 + 1] - *wr * *d1; + cnorm = abs(csr); + +/* If | C | < SMINI, use C = SMINI */ + + if (cnorm < smini) { + csr = smini; + cnorm = smini; + *info = 1; + } + +/* Check scaling for X = B / C */ + + bnorm = (d__1 = b[b_dim1 + 1], abs(d__1)); + if (cnorm < 1. && bnorm > 1.) { + if (bnorm > bignum * cnorm) { + *scale = 1. / bnorm; + } + } + +/* Compute X */ + + x[x_dim1 + 1] = b[b_dim1 + 1] * *scale / csr; + *xnorm = (d__1 = x[x_dim1 + 1], abs(d__1)); + } else { + +/* + Complex 1x1 system (w is complex) + + C = ca A - w D +*/ + + csr = *ca * a[a_dim1 + 1] - *wr * *d1; + csi = -(*wi) * *d1; + cnorm = abs(csr) + abs(csi); + +/* If | C | < SMINI, use C = SMINI */ + + if (cnorm < smini) { + csr = smini; + csi = 0.; + cnorm = smini; + *info = 1; + } + +/* Check scaling for X = B / C */ + + bnorm = (d__1 = b[b_dim1 + 1], abs(d__1)) + (d__2 = b[(b_dim1 << + 1) + 1], abs(d__2)); + if (cnorm < 1. && bnorm > 1.) { + if (bnorm > bignum * cnorm) { + *scale = 1. / bnorm; + } + } + +/* Compute X */ + + d__1 = *scale * b[b_dim1 + 1]; + d__2 = *scale * b[(b_dim1 << 1) + 1]; + dladiv_(&d__1, &d__2, &csr, &csi, &x[x_dim1 + 1], &x[(x_dim1 << 1) + + 1]); + *xnorm = (d__1 = x[x_dim1 + 1], abs(d__1)) + (d__2 = x[(x_dim1 << + 1) + 1], abs(d__2)); + } + + } else { + +/* + 2x2 System + + Compute the real part of C = ca A - w D (or ca A' - w D ) +*/ + + cr[0] = *ca * a[a_dim1 + 1] - *wr * *d1; + cr[3] = *ca * a[(a_dim1 << 1) + 2] - *wr * *d2; + if (*ltrans) { + cr[2] = *ca * a[a_dim1 + 2]; + cr[1] = *ca * a[(a_dim1 << 1) + 1]; + } else { + cr[1] = *ca * a[a_dim1 + 2]; + cr[2] = *ca * a[(a_dim1 << 1) + 1]; + } + + if (*nw == 1) { + +/* + Real 2x2 system (w is real) + + Find the largest element in C +*/ + + cmax = 0.; + icmax = 0; + + for (j = 1; j <= 4; ++j) { + if ((d__1 = crv[j - 1], abs(d__1)) > cmax) { + cmax = (d__1 = crv[j - 1], abs(d__1)); + icmax = j; + } +/* L10: */ + } + +/* If norm(C) < SMINI, use SMINI*identity. */ + + if (cmax < smini) { +/* Computing MAX */ + d__3 = (d__1 = b[b_dim1 + 1], abs(d__1)), d__4 = (d__2 = b[ + b_dim1 + 2], abs(d__2)); + bnorm = max(d__3,d__4); + if (smini < 1. && bnorm > 1.) { + if (bnorm > bignum * smini) { + *scale = 1. / bnorm; + } + } + temp = *scale / smini; + x[x_dim1 + 1] = temp * b[b_dim1 + 1]; + x[x_dim1 + 2] = temp * b[b_dim1 + 2]; + *xnorm = temp * bnorm; + *info = 1; + return 0; + } + +/* Gaussian elimination with complete pivoting. */ + + ur11 = crv[icmax - 1]; + cr21 = crv[ipivot[(icmax << 2) - 3] - 1]; + ur12 = crv[ipivot[(icmax << 2) - 2] - 1]; + cr22 = crv[ipivot[(icmax << 2) - 1] - 1]; + ur11r = 1. / ur11; + lr21 = ur11r * cr21; + ur22 = cr22 - ur12 * lr21; + +/* If smaller pivot < SMINI, use SMINI */ + + if (abs(ur22) < smini) { + ur22 = smini; + *info = 1; + } + if (rswap[icmax - 1]) { + br1 = b[b_dim1 + 2]; + br2 = b[b_dim1 + 1]; + } else { + br1 = b[b_dim1 + 1]; + br2 = b[b_dim1 + 2]; + } + br2 -= lr21 * br1; +/* Computing MAX */ + d__2 = (d__1 = br1 * (ur22 * ur11r), abs(d__1)), d__3 = abs(br2); + bbnd = max(d__2,d__3); + if (bbnd > 1. && abs(ur22) < 1.) { + if (bbnd >= bignum * abs(ur22)) { + *scale = 1. / bbnd; + } + } + + xr2 = br2 * *scale / ur22; + xr1 = *scale * br1 * ur11r - xr2 * (ur11r * ur12); + if (zswap[icmax - 1]) { + x[x_dim1 + 1] = xr2; + x[x_dim1 + 2] = xr1; + } else { + x[x_dim1 + 1] = xr1; + x[x_dim1 + 2] = xr2; + } +/* Computing MAX */ + d__1 = abs(xr1), d__2 = abs(xr2); + *xnorm = max(d__1,d__2); + +/* Further scaling if norm(A) norm(X) > overflow */ + + if (*xnorm > 1. && cmax > 1.) { + if (*xnorm > bignum / cmax) { + temp = cmax / bignum; + x[x_dim1 + 1] = temp * x[x_dim1 + 1]; + x[x_dim1 + 2] = temp * x[x_dim1 + 2]; + *xnorm = temp * *xnorm; + *scale = temp * *scale; + } + } + } else { + +/* + Complex 2x2 system (w is complex) + + Find the largest element in C +*/ + + ci[0] = -(*wi) * *d1; + ci[1] = 0.; + ci[2] = 0.; + ci[3] = -(*wi) * *d2; + cmax = 0.; + icmax = 0; + + for (j = 1; j <= 4; ++j) { + if ((d__1 = crv[j - 1], abs(d__1)) + (d__2 = civ[j - 1], abs( + d__2)) > cmax) { + cmax = (d__1 = crv[j - 1], abs(d__1)) + (d__2 = civ[j - 1] + , abs(d__2)); + icmax = j; + } +/* L20: */ + } + +/* If norm(C) < SMINI, use SMINI*identity. */ + + if (cmax < smini) { +/* Computing MAX */ + d__5 = (d__1 = b[b_dim1 + 1], abs(d__1)) + (d__2 = b[(b_dim1 + << 1) + 1], abs(d__2)), d__6 = (d__3 = b[b_dim1 + 2], + abs(d__3)) + (d__4 = b[(b_dim1 << 1) + 2], abs(d__4)); + bnorm = max(d__5,d__6); + if (smini < 1. && bnorm > 1.) { + if (bnorm > bignum * smini) { + *scale = 1. / bnorm; + } + } + temp = *scale / smini; + x[x_dim1 + 1] = temp * b[b_dim1 + 1]; + x[x_dim1 + 2] = temp * b[b_dim1 + 2]; + x[(x_dim1 << 1) + 1] = temp * b[(b_dim1 << 1) + 1]; + x[(x_dim1 << 1) + 2] = temp * b[(b_dim1 << 1) + 2]; + *xnorm = temp * bnorm; + *info = 1; + return 0; + } + +/* Gaussian elimination with complete pivoting. */ + + ur11 = crv[icmax - 1]; + ui11 = civ[icmax - 1]; + cr21 = crv[ipivot[(icmax << 2) - 3] - 1]; + ci21 = civ[ipivot[(icmax << 2) - 3] - 1]; + ur12 = crv[ipivot[(icmax << 2) - 2] - 1]; + ui12 = civ[ipivot[(icmax << 2) - 2] - 1]; + cr22 = crv[ipivot[(icmax << 2) - 1] - 1]; + ci22 = civ[ipivot[(icmax << 2) - 1] - 1]; + if (icmax == 1 || icmax == 4) { + +/* Code when off-diagonals of pivoted C are real */ + + if (abs(ur11) > abs(ui11)) { + temp = ui11 / ur11; +/* Computing 2nd power */ + d__1 = temp; + ur11r = 1. / (ur11 * (d__1 * d__1 + 1.)); + ui11r = -temp * ur11r; + } else { + temp = ur11 / ui11; +/* Computing 2nd power */ + d__1 = temp; + ui11r = -1. / (ui11 * (d__1 * d__1 + 1.)); + ur11r = -temp * ui11r; + } + lr21 = cr21 * ur11r; + li21 = cr21 * ui11r; + ur12s = ur12 * ur11r; + ui12s = ur12 * ui11r; + ur22 = cr22 - ur12 * lr21; + ui22 = ci22 - ur12 * li21; + } else { + +/* Code when diagonals of pivoted C are real */ + + ur11r = 1. / ur11; + ui11r = 0.; + lr21 = cr21 * ur11r; + li21 = ci21 * ur11r; + ur12s = ur12 * ur11r; + ui12s = ui12 * ur11r; + ur22 = cr22 - ur12 * lr21 + ui12 * li21; + ui22 = -ur12 * li21 - ui12 * lr21; + } + u22abs = abs(ur22) + abs(ui22); + +/* If smaller pivot < SMINI, use SMINI */ + + if (u22abs < smini) { + ur22 = smini; + ui22 = 0.; + *info = 1; + } + if (rswap[icmax - 1]) { + br2 = b[b_dim1 + 1]; + br1 = b[b_dim1 + 2]; + bi2 = b[(b_dim1 << 1) + 1]; + bi1 = b[(b_dim1 << 1) + 2]; + } else { + br1 = b[b_dim1 + 1]; + br2 = b[b_dim1 + 2]; + bi1 = b[(b_dim1 << 1) + 1]; + bi2 = b[(b_dim1 << 1) + 2]; + } + br2 = br2 - lr21 * br1 + li21 * bi1; + bi2 = bi2 - li21 * br1 - lr21 * bi1; +/* Computing MAX */ + d__1 = (abs(br1) + abs(bi1)) * (u22abs * (abs(ur11r) + abs(ui11r)) + ), d__2 = abs(br2) + abs(bi2); + bbnd = max(d__1,d__2); + if (bbnd > 1. && u22abs < 1.) { + if (bbnd >= bignum * u22abs) { + *scale = 1. / bbnd; + br1 = *scale * br1; + bi1 = *scale * bi1; + br2 = *scale * br2; + bi2 = *scale * bi2; + } + } + + dladiv_(&br2, &bi2, &ur22, &ui22, &xr2, &xi2); + xr1 = ur11r * br1 - ui11r * bi1 - ur12s * xr2 + ui12s * xi2; + xi1 = ui11r * br1 + ur11r * bi1 - ui12s * xr2 - ur12s * xi2; + if (zswap[icmax - 1]) { + x[x_dim1 + 1] = xr2; + x[x_dim1 + 2] = xr1; + x[(x_dim1 << 1) + 1] = xi2; + x[(x_dim1 << 1) + 2] = xi1; + } else { + x[x_dim1 + 1] = xr1; + x[x_dim1 + 2] = xr2; + x[(x_dim1 << 1) + 1] = xi1; + x[(x_dim1 << 1) + 2] = xi2; + } +/* Computing MAX */ + d__1 = abs(xr1) + abs(xi1), d__2 = abs(xr2) + abs(xi2); + *xnorm = max(d__1,d__2); + +/* Further scaling if norm(A) norm(X) > overflow */ + + if (*xnorm > 1. && cmax > 1.) { + if (*xnorm > bignum / cmax) { + temp = cmax / bignum; + x[x_dim1 + 1] = temp * x[x_dim1 + 1]; + x[x_dim1 + 2] = temp * x[x_dim1 + 2]; + x[(x_dim1 << 1) + 1] = temp * x[(x_dim1 << 1) + 1]; + x[(x_dim1 << 1) + 2] = temp * x[(x_dim1 << 1) + 2]; + *xnorm = temp * *xnorm; + *scale = temp * *scale; + } + } + } + } + + return 0; + +/* End of DLALN2 */ + +} /* dlaln2_ */ + +#undef crv +#undef civ +#undef cr +#undef ci + + +/* Subroutine */ int dlals0_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *nrhs, doublereal *b, integer *ldb, doublereal + *bx, integer *ldbx, integer *perm, integer *givptr, integer *givcol, + integer *ldgcol, doublereal *givnum, integer *ldgnum, doublereal * + poles, doublereal *difl, doublereal *difr, doublereal *z__, integer * + k, doublereal *c__, doublereal *s, doublereal *work, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, b_dim1, b_offset, bx_dim1, bx_offset, + difr_dim1, difr_offset, givnum_dim1, givnum_offset, poles_dim1, + poles_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer i__, j, m, n; + static doublereal dj; + static integer nlp1; + static doublereal temp; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *); + extern doublereal dnrm2_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + static doublereal diflj, difrj, dsigj; + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *), dcopy_(integer *, + doublereal *, integer *, doublereal *, integer *); + extern doublereal dlamc3_(doublereal *, doublereal *); + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dlacpy_(char *, integer *, integer + *, doublereal *, integer *, doublereal *, integer *), + xerbla_(char *, integer *); + static doublereal dsigjp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLALS0 applies back the multiplying factors of either the left or the + right singular vector matrix of a diagonal matrix appended by a row + to the right hand side matrix B in solving the least squares problem + using the divide-and-conquer SVD approach. + + For the left singular vector matrix, three types of orthogonal + matrices are involved: + + (1L) Givens rotations: the number of such rotations is GIVPTR; the + pairs of columns/rows they were applied to are stored in GIVCOL; + and the C- and S-values of these rotations are stored in GIVNUM. + + (2L) Permutation. The (NL+1)-st row of B is to be moved to the first + row, and for J=2:N, PERM(J)-th row of B is to be moved to the + J-th row. + + (3L) The left singular vector matrix of the remaining matrix. + + For the right singular vector matrix, four types of orthogonal + matrices are involved: + + (1R) The right singular vector matrix of the remaining matrix. + + (2R) If SQRE = 1, one extra Givens rotation to generate the right + null space. + + (3R) The inverse transformation of (2L). + + (4R) The inverse transformation of (1L). + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed in + factored form: + = 0: Left singular vector matrix. + = 1: Right singular vector matrix. + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has row dimension N = NL + NR + 1, + and column dimension M = N + SQRE. + + NRHS (input) INTEGER + The number of columns of B and BX. NRHS must be at least 1. + + B (input/output) DOUBLE PRECISION array, dimension ( LDB, NRHS ) + On input, B contains the right hand sides of the least + squares problem in rows 1 through M. On output, B contains + the solution X in rows 1 through N. + + LDB (input) INTEGER + The leading dimension of B. LDB must be at least + max(1,MAX( M, N ) ). + + BX (workspace) DOUBLE PRECISION array, dimension ( LDBX, NRHS ) + + LDBX (input) INTEGER + The leading dimension of BX. + + PERM (input) INTEGER array, dimension ( N ) + The permutations (from deflation and sorting) applied + to the two blocks. + + GIVPTR (input) INTEGER + The number of Givens rotations which took place in this + subproblem. + + GIVCOL (input) INTEGER array, dimension ( LDGCOL, 2 ) + Each pair of numbers indicates a pair of rows/columns + involved in a Givens rotation. + + LDGCOL (input) INTEGER + The leading dimension of GIVCOL, must be at least N. + + GIVNUM (input) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ) + Each number indicates the C or S value used in the + corresponding Givens rotation. + + LDGNUM (input) INTEGER + The leading dimension of arrays DIFR, POLES and + GIVNUM, must be at least K. + + POLES (input) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ) + On entry, POLES(1:K, 1) contains the new singular + values obtained from solving the secular equation, and + POLES(1:K, 2) is an array containing the poles in the secular + equation. + + DIFL (input) DOUBLE PRECISION array, dimension ( K ). + On entry, DIFL(I) is the distance between I-th updated + (undeflated) singular value and the I-th (undeflated) old + singular value. + + DIFR (input) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ). + On entry, DIFR(I, 1) contains the distances between I-th + updated (undeflated) singular value and the I+1-th + (undeflated) old singular value. And DIFR(I, 2) is the + normalizing factor for the I-th right singular vector. + + Z (input) DOUBLE PRECISION array, dimension ( K ) + Contain the components of the deflation-adjusted updating row + vector. + + K (input) INTEGER + Contains the dimension of the non-deflated matrix, + This is the order of the related secular equation. 1 <= K <=N. + + C (input) DOUBLE PRECISION + C contains garbage if SQRE =0 and the C-value of a Givens + rotation related to the right null space if SQRE = 1. + + S (input) DOUBLE PRECISION + S contains garbage if SQRE =0 and the S-value of a Givens + rotation related to the right null space if SQRE = 1. + + WORK (workspace) DOUBLE PRECISION array, dimension ( K ) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Ming Gu and Ren-Cang Li, Computer Science Division, University of + California at Berkeley, USA + Osni Marques, LBNL/NERSC, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + bx_dim1 = *ldbx; + bx_offset = 1 + bx_dim1; + bx -= bx_offset; + --perm; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + difr_dim1 = *ldgnum; + difr_offset = 1 + difr_dim1; + difr -= difr_offset; + poles_dim1 = *ldgnum; + poles_offset = 1 + poles_dim1; + poles -= poles_offset; + givnum_dim1 = *ldgnum; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + --difl; + --z__; + --work; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*nl < 1) { + *info = -2; + } else if (*nr < 1) { + *info = -3; + } else if (*sqre < 0 || *sqre > 1) { + *info = -4; + } + + n = *nl + *nr + 1; + + if (*nrhs < 1) { + *info = -5; + } else if (*ldb < n) { + *info = -7; + } else if (*ldbx < n) { + *info = -9; + } else if (*givptr < 0) { + *info = -11; + } else if (*ldgcol < n) { + *info = -13; + } else if (*ldgnum < n) { + *info = -15; + } else if (*k < 1) { + *info = -20; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLALS0", &i__1); + return 0; + } + + m = n + *sqre; + nlp1 = *nl + 1; + + if (*icompq == 0) { + +/* + Apply back orthogonal transformations from the left. + + Step (1L): apply back the Givens rotations performed. +*/ + + i__1 = *givptr; + for (i__ = 1; i__ <= i__1; ++i__) { + drot_(nrhs, &b[givcol[i__ + (givcol_dim1 << 1)] + b_dim1], ldb, & + b[givcol[i__ + givcol_dim1] + b_dim1], ldb, &givnum[i__ + + (givnum_dim1 << 1)], &givnum[i__ + givnum_dim1]); +/* L10: */ + } + +/* Step (2L): permute rows of B. */ + + dcopy_(nrhs, &b[nlp1 + b_dim1], ldb, &bx[bx_dim1 + 1], ldbx); + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + dcopy_(nrhs, &b[perm[i__] + b_dim1], ldb, &bx[i__ + bx_dim1], + ldbx); +/* L20: */ + } + +/* + Step (3L): apply the inverse of the left singular vector + matrix to BX. +*/ + + if (*k == 1) { + dcopy_(nrhs, &bx[bx_offset], ldbx, &b[b_offset], ldb); + if (z__[1] < 0.) { + dscal_(nrhs, &c_b151, &b[b_offset], ldb); + } + } else { + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + diflj = difl[j]; + dj = poles[j + poles_dim1]; + dsigj = -poles[j + (poles_dim1 << 1)]; + if (j < *k) { + difrj = -difr[j + difr_dim1]; + dsigjp = -poles[j + 1 + (poles_dim1 << 1)]; + } + if (z__[j] == 0. || poles[j + (poles_dim1 << 1)] == 0.) { + work[j] = 0.; + } else { + work[j] = -poles[j + (poles_dim1 << 1)] * z__[j] / diflj / + (poles[j + (poles_dim1 << 1)] + dj); + } + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + if (z__[i__] == 0. || poles[i__ + (poles_dim1 << 1)] == + 0.) { + work[i__] = 0.; + } else { + work[i__] = poles[i__ + (poles_dim1 << 1)] * z__[i__] + / (dlamc3_(&poles[i__ + (poles_dim1 << 1)], & + dsigj) - diflj) / (poles[i__ + (poles_dim1 << + 1)] + dj); + } +/* L30: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + if (z__[i__] == 0. || poles[i__ + (poles_dim1 << 1)] == + 0.) { + work[i__] = 0.; + } else { + work[i__] = poles[i__ + (poles_dim1 << 1)] * z__[i__] + / (dlamc3_(&poles[i__ + (poles_dim1 << 1)], & + dsigjp) + difrj) / (poles[i__ + (poles_dim1 << + 1)] + dj); + } +/* L40: */ + } + work[1] = -1.; + temp = dnrm2_(k, &work[1], &c__1); + dgemv_("T", k, nrhs, &c_b15, &bx[bx_offset], ldbx, &work[1], & + c__1, &c_b29, &b[j + b_dim1], ldb); + dlascl_("G", &c__0, &c__0, &temp, &c_b15, &c__1, nrhs, &b[j + + b_dim1], ldb, info); +/* L50: */ + } + } + +/* Move the deflated rows of BX to B also. */ + + if (*k < max(m,n)) { + i__1 = n - *k; + dlacpy_("A", &i__1, nrhs, &bx[*k + 1 + bx_dim1], ldbx, &b[*k + 1 + + b_dim1], ldb); + } + } else { + +/* + Apply back the right orthogonal transformations. + + Step (1R): apply back the new right singular vector matrix + to B. +*/ + + if (*k == 1) { + dcopy_(nrhs, &b[b_offset], ldb, &bx[bx_offset], ldbx); + } else { + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dsigj = poles[j + (poles_dim1 << 1)]; + if (z__[j] == 0.) { + work[j] = 0.; + } else { + work[j] = -z__[j] / difl[j] / (dsigj + poles[j + + poles_dim1]) / difr[j + (difr_dim1 << 1)]; + } + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + if (z__[j] == 0.) { + work[i__] = 0.; + } else { + d__1 = -poles[i__ + 1 + (poles_dim1 << 1)]; + work[i__] = z__[j] / (dlamc3_(&dsigj, &d__1) - difr[ + i__ + difr_dim1]) / (dsigj + poles[i__ + + poles_dim1]) / difr[i__ + (difr_dim1 << 1)]; + } +/* L60: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + if (z__[j] == 0.) { + work[i__] = 0.; + } else { + d__1 = -poles[i__ + (poles_dim1 << 1)]; + work[i__] = z__[j] / (dlamc3_(&dsigj, &d__1) - difl[ + i__]) / (dsigj + poles[i__ + poles_dim1]) / + difr[i__ + (difr_dim1 << 1)]; + } +/* L70: */ + } + dgemv_("T", k, nrhs, &c_b15, &b[b_offset], ldb, &work[1], & + c__1, &c_b29, &bx[j + bx_dim1], ldbx); +/* L80: */ + } + } + +/* + Step (2R): if SQRE = 1, apply back the rotation that is + related to the right null space of the subproblem. +*/ + + if (*sqre == 1) { + dcopy_(nrhs, &b[m + b_dim1], ldb, &bx[m + bx_dim1], ldbx); + drot_(nrhs, &bx[bx_dim1 + 1], ldbx, &bx[m + bx_dim1], ldbx, c__, + s); + } + if (*k < max(m,n)) { + i__1 = n - *k; + dlacpy_("A", &i__1, nrhs, &b[*k + 1 + b_dim1], ldb, &bx[*k + 1 + + bx_dim1], ldbx); + } + +/* Step (3R): permute rows of B. */ + + dcopy_(nrhs, &bx[bx_dim1 + 1], ldbx, &b[nlp1 + b_dim1], ldb); + if (*sqre == 1) { + dcopy_(nrhs, &bx[m + bx_dim1], ldbx, &b[m + b_dim1], ldb); + } + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + dcopy_(nrhs, &bx[i__ + bx_dim1], ldbx, &b[perm[i__] + b_dim1], + ldb); +/* L90: */ + } + +/* Step (4R): apply back the Givens rotations performed. */ + + for (i__ = *givptr; i__ >= 1; --i__) { + d__1 = -givnum[i__ + givnum_dim1]; + drot_(nrhs, &b[givcol[i__ + (givcol_dim1 << 1)] + b_dim1], ldb, & + b[givcol[i__ + givcol_dim1] + b_dim1], ldb, &givnum[i__ + + (givnum_dim1 << 1)], &d__1); +/* L100: */ + } + } + + return 0; + +/* End of DLALS0 */ + +} /* dlals0_ */ + +/* Subroutine */ int dlalsa_(integer *icompq, integer *smlsiz, integer *n, + integer *nrhs, doublereal *b, integer *ldb, doublereal *bx, integer * + ldbx, doublereal *u, integer *ldu, doublereal *vt, integer *k, + doublereal *difl, doublereal *difr, doublereal *z__, doublereal * + poles, integer *givptr, integer *givcol, integer *ldgcol, integer * + perm, doublereal *givnum, doublereal *c__, doublereal *s, doublereal * + work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, perm_dim1, perm_offset, b_dim1, + b_offset, bx_dim1, bx_offset, difl_dim1, difl_offset, difr_dim1, + difr_offset, givnum_dim1, givnum_offset, poles_dim1, poles_offset, + u_dim1, u_offset, vt_dim1, vt_offset, z_dim1, z_offset, i__1, + i__2; + + /* Local variables */ + static integer i__, j, i1, ic, lf, nd, ll, nl, nr, im1, nlf, nrf, lvl, + ndb1, nlp1, lvl2, nrp1, nlvl, sqre; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer inode, ndiml, ndimr; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *), dlals0_(integer *, integer *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + integer *, integer *, integer *, integer *, integer *, doublereal + *, integer *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *, doublereal *, doublereal *, doublereal *, + integer *), dlasdt_(integer *, integer *, integer *, integer *, + integer *, integer *, integer *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLALSA is an itermediate step in solving the least squares problem + by computing the SVD of the coefficient matrix in compact form (The + singular vectors are computed as products of simple orthorgonal + matrices.). + + If ICOMPQ = 0, DLALSA applies the inverse of the left singular vector + matrix of an upper bidiagonal matrix to the right hand side; and if + ICOMPQ = 1, DLALSA applies the right singular vector matrix to the + right hand side. The singular vector matrices were generated in + compact form by DLALSA. + + Arguments + ========= + + + ICOMPQ (input) INTEGER + Specifies whether the left or the right singular vector + matrix is involved. + = 0: Left singular vector matrix + = 1: Right singular vector matrix + + SMLSIZ (input) INTEGER + The maximum size of the subproblems at the bottom of the + computation tree. + + N (input) INTEGER + The row and column dimensions of the upper bidiagonal matrix. + + NRHS (input) INTEGER + The number of columns of B and BX. NRHS must be at least 1. + + B (input/output) DOUBLE PRECISION array, dimension ( LDB, NRHS ) + On input, B contains the right hand sides of the least + squares problem in rows 1 through M. + On output, B contains the solution X in rows 1 through N. + + LDB (input) INTEGER + The leading dimension of B in the calling subprogram. + LDB must be at least max(1,MAX( M, N ) ). + + BX (output) DOUBLE PRECISION array, dimension ( LDBX, NRHS ) + On exit, the result of applying the left or right singular + vector matrix to B. + + LDBX (input) INTEGER + The leading dimension of BX. + + U (input) DOUBLE PRECISION array, dimension ( LDU, SMLSIZ ). + On entry, U contains the left singular vector matrices of all + subproblems at the bottom level. + + LDU (input) INTEGER, LDU = > N. + The leading dimension of arrays U, VT, DIFL, DIFR, + POLES, GIVNUM, and Z. + + VT (input) DOUBLE PRECISION array, dimension ( LDU, SMLSIZ+1 ). + On entry, VT' contains the right singular vector matrices of + all subproblems at the bottom level. + + K (input) INTEGER array, dimension ( N ). + + DIFL (input) DOUBLE PRECISION array, dimension ( LDU, NLVL ). + where NLVL = INT(log_2 (N/(SMLSIZ+1))) + 1. + + DIFR (input) DOUBLE PRECISION array, dimension ( LDU, 2 * NLVL ). + On entry, DIFL(*, I) and DIFR(*, 2 * I -1) record + distances between singular values on the I-th level and + singular values on the (I -1)-th level, and DIFR(*, 2 * I) + record the normalizing factors of the right singular vectors + matrices of subproblems on I-th level. + + Z (input) DOUBLE PRECISION array, dimension ( LDU, NLVL ). + On entry, Z(1, I) contains the components of the deflation- + adjusted updating row vector for subproblems on the I-th + level. + + POLES (input) DOUBLE PRECISION array, dimension ( LDU, 2 * NLVL ). + On entry, POLES(*, 2 * I -1: 2 * I) contains the new and old + singular values involved in the secular equations on the I-th + level. + + GIVPTR (input) INTEGER array, dimension ( N ). + On entry, GIVPTR( I ) records the number of Givens + rotations performed on the I-th problem on the computation + tree. + + GIVCOL (input) INTEGER array, dimension ( LDGCOL, 2 * NLVL ). + On entry, for each I, GIVCOL(*, 2 * I - 1: 2 * I) records the + locations of Givens rotations performed on the I-th level on + the computation tree. + + LDGCOL (input) INTEGER, LDGCOL = > N. + The leading dimension of arrays GIVCOL and PERM. + + PERM (input) INTEGER array, dimension ( LDGCOL, NLVL ). + On entry, PERM(*, I) records permutations done on the I-th + level of the computation tree. + + GIVNUM (input) DOUBLE PRECISION array, dimension ( LDU, 2 * NLVL ). + On entry, GIVNUM(*, 2 *I -1 : 2 * I) records the C- and S- + values of Givens rotations performed on the I-th level on the + computation tree. + + C (input) DOUBLE PRECISION array, dimension ( N ). + On entry, if the I-th subproblem is not square, + C( I ) contains the C-value of a Givens rotation related to + the right null space of the I-th subproblem. + + S (input) DOUBLE PRECISION array, dimension ( N ). + On entry, if the I-th subproblem is not square, + S( I ) contains the S-value of a Givens rotation related to + the right null space of the I-th subproblem. + + WORK (workspace) DOUBLE PRECISION array. + The dimension must be at least N. + + IWORK (workspace) INTEGER array. + The dimension must be at least 3 * N + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Ming Gu and Ren-Cang Li, Computer Science Division, University of + California at Berkeley, USA + Osni Marques, LBNL/NERSC, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + bx_dim1 = *ldbx; + bx_offset = 1 + bx_dim1; + bx -= bx_offset; + givnum_dim1 = *ldu; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + poles_dim1 = *ldu; + poles_offset = 1 + poles_dim1; + poles -= poles_offset; + z_dim1 = *ldu; + z_offset = 1 + z_dim1; + z__ -= z_offset; + difr_dim1 = *ldu; + difr_offset = 1 + difr_dim1; + difr -= difr_offset; + difl_dim1 = *ldu; + difl_offset = 1 + difl_dim1; + difl -= difl_offset; + vt_dim1 = *ldu; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + --k; + --givptr; + perm_dim1 = *ldgcol; + perm_offset = 1 + perm_dim1; + perm -= perm_offset; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + --c__; + --s; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*smlsiz < 3) { + *info = -2; + } else if (*n < *smlsiz) { + *info = -3; + } else if (*nrhs < 1) { + *info = -4; + } else if (*ldb < *n) { + *info = -6; + } else if (*ldbx < *n) { + *info = -8; + } else if (*ldu < *n) { + *info = -10; + } else if (*ldgcol < *n) { + *info = -19; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLALSA", &i__1); + return 0; + } + +/* Book-keeping and setting up the computation tree. */ + + inode = 1; + ndiml = inode + *n; + ndimr = ndiml + *n; + + dlasdt_(n, &nlvl, &nd, &iwork[inode], &iwork[ndiml], &iwork[ndimr], + smlsiz); + +/* + The following code applies back the left singular vector factors. + For applying back the right singular vector factors, go to 50. +*/ + + if (*icompq == 1) { + goto L50; + } + +/* + The nodes on the bottom level of the tree were solved + by DLASDQ. The corresponding left and right singular vector + matrices are in explicit form. First apply back the left + singular vector matrices. +*/ + + ndb1 = (nd + 1) / 2; + i__1 = nd; + for (i__ = ndb1; i__ <= i__1; ++i__) { + +/* + IC : center row of each node + NL : number of rows of left subproblem + NR : number of rows of right subproblem + NLF: starting row of the left subproblem + NRF: starting row of the right subproblem +*/ + + i1 = i__ - 1; + ic = iwork[inode + i1]; + nl = iwork[ndiml + i1]; + nr = iwork[ndimr + i1]; + nlf = ic - nl; + nrf = ic + 1; + dgemm_("T", "N", &nl, nrhs, &nl, &c_b15, &u[nlf + u_dim1], ldu, &b[ + nlf + b_dim1], ldb, &c_b29, &bx[nlf + bx_dim1], ldbx); + dgemm_("T", "N", &nr, nrhs, &nr, &c_b15, &u[nrf + u_dim1], ldu, &b[ + nrf + b_dim1], ldb, &c_b29, &bx[nrf + bx_dim1], ldbx); +/* L10: */ + } + +/* + Next copy the rows of B that correspond to unchanged rows + in the bidiagonal matrix to BX. +*/ + + i__1 = nd; + for (i__ = 1; i__ <= i__1; ++i__) { + ic = iwork[inode + i__ - 1]; + dcopy_(nrhs, &b[ic + b_dim1], ldb, &bx[ic + bx_dim1], ldbx); +/* L20: */ + } + +/* + Finally go through the left singular vector matrices of all + the other subproblems bottom-up on the tree. +*/ + + j = pow_ii(&c__2, &nlvl); + sqre = 0; + + for (lvl = nlvl; lvl >= 1; --lvl) { + lvl2 = (lvl << 1) - 1; + +/* + find the first node LF and last node LL on + the current level LVL +*/ + + if (lvl == 1) { + lf = 1; + ll = 1; + } else { + i__1 = lvl - 1; + lf = pow_ii(&c__2, &i__1); + ll = (lf << 1) - 1; + } + i__1 = ll; + for (i__ = lf; i__ <= i__1; ++i__) { + im1 = i__ - 1; + ic = iwork[inode + im1]; + nl = iwork[ndiml + im1]; + nr = iwork[ndimr + im1]; + nlf = ic - nl; + nrf = ic + 1; + --j; + dlals0_(icompq, &nl, &nr, &sqre, nrhs, &bx[nlf + bx_dim1], ldbx, & + b[nlf + b_dim1], ldb, &perm[nlf + lvl * perm_dim1], & + givptr[j], &givcol[nlf + lvl2 * givcol_dim1], ldgcol, & + givnum[nlf + lvl2 * givnum_dim1], ldu, &poles[nlf + lvl2 * + poles_dim1], &difl[nlf + lvl * difl_dim1], &difr[nlf + + lvl2 * difr_dim1], &z__[nlf + lvl * z_dim1], &k[j], &c__[ + j], &s[j], &work[1], info); +/* L30: */ + } +/* L40: */ + } + goto L90; + +/* ICOMPQ = 1: applying back the right singular vector factors. */ + +L50: + +/* + First now go through the right singular vector matrices of all + the tree nodes top-down. +*/ + + j = 0; + i__1 = nlvl; + for (lvl = 1; lvl <= i__1; ++lvl) { + lvl2 = (lvl << 1) - 1; + +/* + Find the first node LF and last node LL on + the current level LVL. +*/ + + if (lvl == 1) { + lf = 1; + ll = 1; + } else { + i__2 = lvl - 1; + lf = pow_ii(&c__2, &i__2); + ll = (lf << 1) - 1; + } + i__2 = lf; + for (i__ = ll; i__ >= i__2; --i__) { + im1 = i__ - 1; + ic = iwork[inode + im1]; + nl = iwork[ndiml + im1]; + nr = iwork[ndimr + im1]; + nlf = ic - nl; + nrf = ic + 1; + if (i__ == ll) { + sqre = 0; + } else { + sqre = 1; + } + ++j; + dlals0_(icompq, &nl, &nr, &sqre, nrhs, &b[nlf + b_dim1], ldb, &bx[ + nlf + bx_dim1], ldbx, &perm[nlf + lvl * perm_dim1], & + givptr[j], &givcol[nlf + lvl2 * givcol_dim1], ldgcol, & + givnum[nlf + lvl2 * givnum_dim1], ldu, &poles[nlf + lvl2 * + poles_dim1], &difl[nlf + lvl * difl_dim1], &difr[nlf + + lvl2 * difr_dim1], &z__[nlf + lvl * z_dim1], &k[j], &c__[ + j], &s[j], &work[1], info); +/* L60: */ + } +/* L70: */ + } + +/* + The nodes on the bottom level of the tree were solved + by DLASDQ. The corresponding right singular vector + matrices are in explicit form. Apply them back. +*/ + + ndb1 = (nd + 1) / 2; + i__1 = nd; + for (i__ = ndb1; i__ <= i__1; ++i__) { + i1 = i__ - 1; + ic = iwork[inode + i1]; + nl = iwork[ndiml + i1]; + nr = iwork[ndimr + i1]; + nlp1 = nl + 1; + if (i__ == nd) { + nrp1 = nr; + } else { + nrp1 = nr + 1; + } + nlf = ic - nl; + nrf = ic + 1; + dgemm_("T", "N", &nlp1, nrhs, &nlp1, &c_b15, &vt[nlf + vt_dim1], ldu, + &b[nlf + b_dim1], ldb, &c_b29, &bx[nlf + bx_dim1], ldbx); + dgemm_("T", "N", &nrp1, nrhs, &nrp1, &c_b15, &vt[nrf + vt_dim1], ldu, + &b[nrf + b_dim1], ldb, &c_b29, &bx[nrf + bx_dim1], ldbx); +/* L80: */ + } + +L90: + + return 0; + +/* End of DLALSA */ + +} /* dlalsa_ */ + +/* Subroutine */ int dlalsd_(char *uplo, integer *smlsiz, integer *n, integer + *nrhs, doublereal *d__, doublereal *e, doublereal *b, integer *ldb, + doublereal *rcond, integer *rank, doublereal *work, integer *iwork, + integer *info) +{ + /* System generated locals */ + integer b_dim1, b_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer c__, i__, j, k; + static doublereal r__; + static integer s, u, z__; + static doublereal cs; + static integer bx; + static doublereal sn; + static integer st, vt, nm1, st1; + static doublereal eps; + static integer iwk; + static doublereal tol; + static integer difl, difr; + static doublereal rcnd; + static integer perm, nsub; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *); + static integer nlvl, sqre, bxst; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *), + dcopy_(integer *, doublereal *, integer *, doublereal *, integer + *); + static integer poles, sizei, nsize, nwork, icmpq1, icmpq2; + + extern /* Subroutine */ int dlasda_(integer *, integer *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *, integer *, integer *, integer *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *, + integer *), dlalsa_(integer *, integer *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, doublereal *, integer *, integer *, integer *, + integer *, doublereal *, doublereal *, doublereal *, doublereal *, + integer *, integer *), dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dlasdq_(char *, integer *, integer *, integer + *, integer *, integer *, doublereal *, doublereal *, doublereal *, + integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *), dlacpy_(char *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *), dlartg_(doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *), dlaset_(char *, integer *, integer *, + doublereal *, doublereal *, doublereal *, integer *), + xerbla_(char *, integer *); + static integer givcol; + extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); + extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, + integer *); + static doublereal orgnrm; + static integer givnum, givptr, smlszp; + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLALSD uses the singular value decomposition of A to solve the least + squares problem of finding X to minimize the Euclidean norm of each + column of A*X-B, where A is N-by-N upper bidiagonal, and X and B + are N-by-NRHS. The solution X overwrites B. + + The singular values of A smaller than RCOND times the largest + singular value are treated as zero in solving the least squares + problem; in this case a minimum norm solution is returned. + The actual singular values are returned in D in ascending order. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray XMP, Cray YMP, Cray C 90, or Cray 2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': D and E define an upper bidiagonal matrix. + = 'L': D and E define a lower bidiagonal matrix. + + SMLSIZ (input) INTEGER + The maximum size of the subproblems at the bottom of the + computation tree. + + N (input) INTEGER + The dimension of the bidiagonal matrix. N >= 0. + + NRHS (input) INTEGER + The number of columns of B. NRHS must be at least 1. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry D contains the main diagonal of the bidiagonal + matrix. On exit, if INFO = 0, D contains its singular values. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + Contains the super-diagonal entries of the bidiagonal matrix. + On exit, E has been destroyed. + + B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) + On input, B contains the right hand sides of the least + squares problem. On output, B contains the solution X. + + LDB (input) INTEGER + The leading dimension of B in the calling subprogram. + LDB must be at least max(1,N). + + RCOND (input) DOUBLE PRECISION + The singular values of A less than or equal to RCOND times + the largest singular value are treated as zero in solving + the least squares problem. If RCOND is negative, + machine precision is used instead. + For example, if diag(S)*X=B were the least squares problem, + where diag(S) is a diagonal matrix of singular values, the + solution would be X(i) = B(i) / S(i) if S(i) is greater than + RCOND*max(S), and X(i) = 0 if S(i) is less than or equal to + RCOND*max(S). + + RANK (output) INTEGER + The number of singular values of A greater than RCOND times + the largest singular value. + + WORK (workspace) DOUBLE PRECISION array, dimension at least + (9*N + 2*N*SMLSIZ + 8*N*NLVL + N*NRHS + (SMLSIZ+1)**2), + where NLVL = max(0, INT(log_2 (N/(SMLSIZ+1))) + 1). + + IWORK (workspace) INTEGER array, dimension at least + (3*N*NLVL + 11*N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute a singular value while + working on the submatrix lying in rows and columns + INFO/(N+1) through MOD(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Ming Gu and Ren-Cang Li, Computer Science Division, University of + California at Berkeley, USA + Osni Marques, LBNL/NERSC, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -3; + } else if (*nrhs < 1) { + *info = -4; + } else if (*ldb < 1 || *ldb < *n) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLALSD", &i__1); + return 0; + } + + eps = EPSILON; + +/* Set up the tolerance. */ + + if (*rcond <= 0. || *rcond >= 1.) { + rcnd = eps; + } else { + rcnd = *rcond; + } + + *rank = 0; + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } else if (*n == 1) { + if (d__[1] == 0.) { + dlaset_("A", &c__1, nrhs, &c_b29, &c_b29, &b[b_offset], ldb); + } else { + *rank = 1; + dlascl_("G", &c__0, &c__0, &d__[1], &c_b15, &c__1, nrhs, &b[ + b_offset], ldb, info); + d__[1] = abs(d__[1]); + } + return 0; + } + +/* Rotate the matrix if it is lower bidiagonal. */ + + if (*(unsigned char *)uplo == 'L') { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + dlartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + if (*nrhs == 1) { + drot_(&c__1, &b[i__ + b_dim1], &c__1, &b[i__ + 1 + b_dim1], & + c__1, &cs, &sn); + } else { + work[(i__ << 1) - 1] = cs; + work[i__ * 2] = sn; + } +/* L10: */ + } + if (*nrhs > 1) { + i__1 = *nrhs; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *n - 1; + for (j = 1; j <= i__2; ++j) { + cs = work[(j << 1) - 1]; + sn = work[j * 2]; + drot_(&c__1, &b[j + i__ * b_dim1], &c__1, &b[j + 1 + i__ * + b_dim1], &c__1, &cs, &sn); +/* L20: */ + } +/* L30: */ + } + } + } + +/* Scale. */ + + nm1 = *n - 1; + orgnrm = dlanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.) { + dlaset_("A", n, nrhs, &c_b29, &c_b29, &b[b_offset], ldb); + return 0; + } + + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, n, &c__1, &d__[1], n, info); + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &nm1, &c__1, &e[1], &nm1, + info); + +/* + If N is smaller than the minimum divide size SMLSIZ, then solve + the problem with another solver. +*/ + + if (*n <= *smlsiz) { + nwork = *n * *n + 1; + dlaset_("A", n, n, &c_b29, &c_b15, &work[1], n); + dlasdq_("U", &c__0, n, n, &c__0, nrhs, &d__[1], &e[1], &work[1], n, & + work[1], n, &b[b_offset], ldb, &work[nwork], info); + if (*info != 0) { + return 0; + } + tol = rcnd * (d__1 = d__[idamax_(n, &d__[1], &c__1)], abs(d__1)); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if (d__[i__] <= tol) { + dlaset_("A", &c__1, nrhs, &c_b29, &c_b29, &b[i__ + b_dim1], + ldb); + } else { + dlascl_("G", &c__0, &c__0, &d__[i__], &c_b15, &c__1, nrhs, &b[ + i__ + b_dim1], ldb, info); + ++(*rank); + } +/* L40: */ + } + dgemm_("T", "N", n, nrhs, n, &c_b15, &work[1], n, &b[b_offset], ldb, & + c_b29, &work[nwork], n); + dlacpy_("A", n, nrhs, &work[nwork], n, &b[b_offset], ldb); + +/* Unscale. */ + + dlascl_("G", &c__0, &c__0, &c_b15, &orgnrm, n, &c__1, &d__[1], n, + info); + dlasrt_("D", n, &d__[1], info); + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, n, nrhs, &b[b_offset], + ldb, info); + + return 0; + } + +/* Book-keeping and setting up some constants. */ + + nlvl = (integer) (log((doublereal) (*n) / (doublereal) (*smlsiz + 1)) / + log(2.)) + 1; + + smlszp = *smlsiz + 1; + + u = 1; + vt = *smlsiz * *n + 1; + difl = vt + smlszp * *n; + difr = difl + nlvl * *n; + z__ = difr + (nlvl * *n << 1); + c__ = z__ + nlvl * *n; + s = c__ + *n; + poles = s + *n; + givnum = poles + (nlvl << 1) * *n; + bx = givnum + (nlvl << 1) * *n; + nwork = bx + *n * *nrhs; + + sizei = *n + 1; + k = sizei + *n; + givptr = k + *n; + perm = givptr + *n; + givcol = perm + nlvl * *n; + iwk = givcol + (nlvl * *n << 1); + + st = 1; + sqre = 0; + icmpq1 = 1; + icmpq2 = 0; + nsub = 0; + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((d__1 = d__[i__], abs(d__1)) < eps) { + d__[i__] = d_sign(&eps, &d__[i__]); + } +/* L50: */ + } + + i__1 = nm1; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((d__1 = e[i__], abs(d__1)) < eps || i__ == nm1) { + ++nsub; + iwork[nsub] = st; + +/* + Subproblem found. First determine its size and then + apply divide and conquer on it. +*/ + + if (i__ < nm1) { + +/* A subproblem with E(I) small for I < NM1. */ + + nsize = i__ - st + 1; + iwork[sizei + nsub - 1] = nsize; + } else if ((d__1 = e[i__], abs(d__1)) >= eps) { + +/* A subproblem with E(NM1) not too small but I = NM1. */ + + nsize = *n - st + 1; + iwork[sizei + nsub - 1] = nsize; + } else { + +/* + A subproblem with E(NM1) small. This implies an + 1-by-1 subproblem at D(N), which is not solved + explicitly. +*/ + + nsize = i__ - st + 1; + iwork[sizei + nsub - 1] = nsize; + ++nsub; + iwork[nsub] = *n; + iwork[sizei + nsub - 1] = 1; + dcopy_(nrhs, &b[*n + b_dim1], ldb, &work[bx + nm1], n); + } + st1 = st - 1; + if (nsize == 1) { + +/* + This is a 1-by-1 subproblem and is not solved + explicitly. +*/ + + dcopy_(nrhs, &b[st + b_dim1], ldb, &work[bx + st1], n); + } else if (nsize <= *smlsiz) { + +/* This is a small subproblem and is solved by DLASDQ. */ + + dlaset_("A", &nsize, &nsize, &c_b29, &c_b15, &work[vt + st1], + n); + dlasdq_("U", &c__0, &nsize, &nsize, &c__0, nrhs, &d__[st], &e[ + st], &work[vt + st1], n, &work[nwork], n, &b[st + + b_dim1], ldb, &work[nwork], info); + if (*info != 0) { + return 0; + } + dlacpy_("A", &nsize, nrhs, &b[st + b_dim1], ldb, &work[bx + + st1], n); + } else { + +/* A large problem. Solve it using divide and conquer. */ + + dlasda_(&icmpq1, smlsiz, &nsize, &sqre, &d__[st], &e[st], & + work[u + st1], n, &work[vt + st1], &iwork[k + st1], & + work[difl + st1], &work[difr + st1], &work[z__ + st1], + &work[poles + st1], &iwork[givptr + st1], &iwork[ + givcol + st1], n, &iwork[perm + st1], &work[givnum + + st1], &work[c__ + st1], &work[s + st1], &work[nwork], + &iwork[iwk], info); + if (*info != 0) { + return 0; + } + bxst = bx + st1; + dlalsa_(&icmpq2, smlsiz, &nsize, nrhs, &b[st + b_dim1], ldb, & + work[bxst], n, &work[u + st1], n, &work[vt + st1], & + iwork[k + st1], &work[difl + st1], &work[difr + st1], + &work[z__ + st1], &work[poles + st1], &iwork[givptr + + st1], &iwork[givcol + st1], n, &iwork[perm + st1], & + work[givnum + st1], &work[c__ + st1], &work[s + st1], + &work[nwork], &iwork[iwk], info); + if (*info != 0) { + return 0; + } + } + st = i__ + 1; + } +/* L60: */ + } + +/* Apply the singular values and treat the tiny ones as zero. */ + + tol = rcnd * (d__1 = d__[idamax_(n, &d__[1], &c__1)], abs(d__1)); + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* + Some of the elements in D can be negative because 1-by-1 + subproblems were not solved explicitly. +*/ + + if ((d__1 = d__[i__], abs(d__1)) <= tol) { + dlaset_("A", &c__1, nrhs, &c_b29, &c_b29, &work[bx + i__ - 1], n); + } else { + ++(*rank); + dlascl_("G", &c__0, &c__0, &d__[i__], &c_b15, &c__1, nrhs, &work[ + bx + i__ - 1], n, info); + } + d__[i__] = (d__1 = d__[i__], abs(d__1)); +/* L70: */ + } + +/* Now apply back the right singular vectors. */ + + icmpq2 = 1; + i__1 = nsub; + for (i__ = 1; i__ <= i__1; ++i__) { + st = iwork[i__]; + st1 = st - 1; + nsize = iwork[sizei + i__ - 1]; + bxst = bx + st1; + if (nsize == 1) { + dcopy_(nrhs, &work[bxst], n, &b[st + b_dim1], ldb); + } else if (nsize <= *smlsiz) { + dgemm_("T", "N", &nsize, nrhs, &nsize, &c_b15, &work[vt + st1], n, + &work[bxst], n, &c_b29, &b[st + b_dim1], ldb); + } else { + dlalsa_(&icmpq2, smlsiz, &nsize, nrhs, &work[bxst], n, &b[st + + b_dim1], ldb, &work[u + st1], n, &work[vt + st1], &iwork[ + k + st1], &work[difl + st1], &work[difr + st1], &work[z__ + + st1], &work[poles + st1], &iwork[givptr + st1], &iwork[ + givcol + st1], n, &iwork[perm + st1], &work[givnum + st1], + &work[c__ + st1], &work[s + st1], &work[nwork], &iwork[ + iwk], info); + if (*info != 0) { + return 0; + } + } +/* L80: */ + } + +/* Unscale and sort the singular values. */ + + dlascl_("G", &c__0, &c__0, &c_b15, &orgnrm, n, &c__1, &d__[1], n, info); + dlasrt_("D", n, &d__[1], info); + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, n, nrhs, &b[b_offset], ldb, + info); + + return 0; + +/* End of DLALSD */ + +} /* dlalsd_ */ + +/* Subroutine */ int dlamrg_(integer *n1, integer *n2, doublereal *a, integer + *dtrd1, integer *dtrd2, integer *index) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, ind1, ind2, n1sv, n2sv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAMRG will create a permutation list which will merge the elements + of A (which is composed of two independently sorted sets) into a + single set which is sorted in ascending order. + + Arguments + ========= + + N1 (input) INTEGER + N2 (input) INTEGER + These arguements contain the respective lengths of the two + sorted lists to be merged. + + A (input) DOUBLE PRECISION array, dimension (N1+N2) + The first N1 elements of A contain a list of numbers which + are sorted in either ascending or descending order. Likewise + for the final N2 elements. + + DTRD1 (input) INTEGER + DTRD2 (input) INTEGER + These are the strides to be taken through the array A. + Allowable strides are 1 and -1. They indicate whether a + subset of A is sorted in ascending (DTRDx = 1) or descending + (DTRDx = -1) order. + + INDEX (output) INTEGER array, dimension (N1+N2) + On exit this array will contain a permutation such that + if B( I ) = A( INDEX( I ) ) for I=1,N1+N2, then B will be + sorted in ascending order. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --index; + --a; + + /* Function Body */ + n1sv = *n1; + n2sv = *n2; + if (*dtrd1 > 0) { + ind1 = 1; + } else { + ind1 = *n1; + } + if (*dtrd2 > 0) { + ind2 = *n1 + 1; + } else { + ind2 = *n1 + *n2; + } + i__ = 1; +/* while ( (N1SV > 0) & (N2SV > 0) ) */ +L10: + if (n1sv > 0 && n2sv > 0) { + if (a[ind1] <= a[ind2]) { + index[i__] = ind1; + ++i__; + ind1 += *dtrd1; + --n1sv; + } else { + index[i__] = ind2; + ++i__; + ind2 += *dtrd2; + --n2sv; + } + goto L10; + } +/* end while */ + if (n1sv == 0) { + i__1 = n2sv; + for (n1sv = 1; n1sv <= i__1; ++n1sv) { + index[i__] = ind2; + ++i__; + ind2 += *dtrd2; +/* L20: */ + } + } else { +/* N2SV .EQ. 0 */ + i__1 = n1sv; + for (n2sv = 1; n2sv <= i__1; ++n2sv) { + index[i__] = ind1; + ++i__; + ind1 += *dtrd1; +/* L30: */ + } + } + + return 0; + +/* End of DLAMRG */ + +} /* dlamrg_ */ + +doublereal dlange_(char *norm, integer *m, integer *n, doublereal *a, integer + *lda, doublereal *work) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal ret_val, d__1, d__2, d__3; + + /* Local variables */ + static integer i__, j; + static doublereal sum, scale; + extern logical lsame_(char *, char *); + static doublereal value; + extern /* Subroutine */ int dlassq_(integer *, doublereal *, integer *, + doublereal *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLANGE returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + real matrix A. + + Description + =========== + + DLANGE returns the value + + DLANGE = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in DLANGE as described + above. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. When M = 0, + DLANGE is set to zero. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. When N = 0, + DLANGE is set to zero. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(M,1). + + WORK (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)), + where LWORK >= M when NORM = 'I'; otherwise, WORK is not + referenced. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (min(*m,*n) == 0) { + value = 0.; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + value = 0.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs(d__1)); + value = max(d__2,d__3); +/* L10: */ + } +/* L20: */ + } + } else if (lsame_(norm, "O") || *(unsigned char *) + norm == '1') { + +/* Find norm1(A). */ + + value = 0.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = 0.; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + sum += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L30: */ + } + value = max(value,sum); +/* L40: */ + } + } else if (lsame_(norm, "I")) { + +/* Find normI(A). */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.; +/* L50: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] += (d__1 = a[i__ + j * a_dim1], abs(d__1)); +/* L60: */ + } +/* L70: */ + } + value = 0.; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__1 = value, d__2 = work[i__]; + value = max(d__1,d__2); +/* L80: */ + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.; + sum = 1.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + dlassq_(m, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L90: */ + } + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of DLANGE */ + +} /* dlange_ */ + +doublereal dlanst_(char *norm, integer *n, doublereal *d__, doublereal *e) +{ + /* System generated locals */ + integer i__1; + doublereal ret_val, d__1, d__2, d__3, d__4, d__5; + + /* Local variables */ + static integer i__; + static doublereal sum, scale; + extern logical lsame_(char *, char *); + static doublereal anorm; + extern /* Subroutine */ int dlassq_(integer *, doublereal *, integer *, + doublereal *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLANST returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + real symmetric tridiagonal matrix A. + + Description + =========== + + DLANST returns the value + + DLANST = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in DLANST as described + above. + + N (input) INTEGER + The order of the matrix A. N >= 0. When N = 0, DLANST is + set to zero. + + D (input) DOUBLE PRECISION array, dimension (N) + The diagonal elements of A. + + E (input) DOUBLE PRECISION array, dimension (N-1) + The (n-1) sub-diagonal or super-diagonal elements of A. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --e; + --d__; + + /* Function Body */ + if (*n <= 0) { + anorm = 0.; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + anorm = (d__1 = d__[*n], abs(d__1)); + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__2 = anorm, d__3 = (d__1 = d__[i__], abs(d__1)); + anorm = max(d__2,d__3); +/* Computing MAX */ + d__2 = anorm, d__3 = (d__1 = e[i__], abs(d__1)); + anorm = max(d__2,d__3); +/* L10: */ + } + } else if (lsame_(norm, "O") || *(unsigned char *) + norm == '1' || lsame_(norm, "I")) { + +/* Find norm1(A). */ + + if (*n == 1) { + anorm = abs(d__[1]); + } else { +/* Computing MAX */ + d__3 = abs(d__[1]) + abs(e[1]), d__4 = (d__1 = e[*n - 1], abs( + d__1)) + (d__2 = d__[*n], abs(d__2)); + anorm = max(d__3,d__4); + i__1 = *n - 1; + for (i__ = 2; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__4 = anorm, d__5 = (d__1 = d__[i__], abs(d__1)) + (d__2 = e[ + i__], abs(d__2)) + (d__3 = e[i__ - 1], abs(d__3)); + anorm = max(d__4,d__5); +/* L20: */ + } + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.; + sum = 1.; + if (*n > 1) { + i__1 = *n - 1; + dlassq_(&i__1, &e[1], &c__1, &scale, &sum); + sum *= 2; + } + dlassq_(n, &d__[1], &c__1, &scale, &sum); + anorm = scale * sqrt(sum); + } + + ret_val = anorm; + return ret_val; + +/* End of DLANST */ + +} /* dlanst_ */ + +doublereal dlansy_(char *norm, char *uplo, integer *n, doublereal *a, integer + *lda, doublereal *work) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal ret_val, d__1, d__2, d__3; + + /* Local variables */ + static integer i__, j; + static doublereal sum, absa, scale; + extern logical lsame_(char *, char *); + static doublereal value; + extern /* Subroutine */ int dlassq_(integer *, doublereal *, integer *, + doublereal *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLANSY returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + real symmetric matrix A. + + Description + =========== + + DLANSY returns the value + + DLANSY = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in DLANSY as described + above. + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is to be referenced. + = 'U': Upper triangular part of A is referenced + = 'L': Lower triangular part of A is referenced + + N (input) INTEGER + The order of the matrix A. N >= 0. When N = 0, DLANSY is + set to zero. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The symmetric matrix A. If UPLO = 'U', the leading n by n + upper triangular part of A contains the upper triangular part + of the matrix A, and the strictly lower triangular part of A + is not referenced. If UPLO = 'L', the leading n by n lower + triangular part of A contains the lower triangular part of + the matrix A, and the strictly upper triangular part of A is + not referenced. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(N,1). + + WORK (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)), + where LWORK >= N when NORM = 'I' or '1' or 'O'; otherwise, + WORK is not referenced. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (*n == 0) { + value = 0.; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + value = 0.; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs( + d__1)); + value = max(d__2,d__3); +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__2 = value, d__3 = (d__1 = a[i__ + j * a_dim1], abs( + d__1)); + value = max(d__2,d__3); +/* L30: */ + } +/* L40: */ + } + } + } else if (lsame_(norm, "I") || lsame_(norm, "O") || *(unsigned char *)norm == '1') { + +/* Find normI(A) ( = norm1(A), since A is symmetric). */ + + value = 0.; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = 0.; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + absa = (d__1 = a[i__ + j * a_dim1], abs(d__1)); + sum += absa; + work[i__] += absa; +/* L50: */ + } + work[j] = sum + (d__1 = a[j + j * a_dim1], abs(d__1)); +/* L60: */ + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__1 = value, d__2 = work[i__]; + value = max(d__1,d__2); +/* L70: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.; +/* L80: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = work[j] + (d__1 = a[j + j * a_dim1], abs(d__1)); + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + absa = (d__1 = a[i__ + j * a_dim1], abs(d__1)); + sum += absa; + work[i__] += absa; +/* L90: */ + } + value = max(value,sum); +/* L100: */ + } + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.; + sum = 1.; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + i__2 = j - 1; + dlassq_(&i__2, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L110: */ + } + } else { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = *n - j; + dlassq_(&i__2, &a[j + 1 + j * a_dim1], &c__1, &scale, &sum); +/* L120: */ + } + } + sum *= 2; + i__1 = *lda + 1; + dlassq_(n, &a[a_offset], &i__1, &scale, &sum); + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of DLANSY */ + +} /* dlansy_ */ + +/* Subroutine */ int dlanv2_(doublereal *a, doublereal *b, doublereal *c__, + doublereal *d__, doublereal *rt1r, doublereal *rt1i, doublereal *rt2r, + doublereal *rt2i, doublereal *cs, doublereal *sn) +{ + /* System generated locals */ + doublereal d__1, d__2; + + /* Local variables */ + static doublereal p, z__, aa, bb, cc, dd, cs1, sn1, sab, sac, eps, tau, + temp, scale, bcmax, bcmis, sigma; + + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLANV2 computes the Schur factorization of a real 2-by-2 nonsymmetric + matrix in standard form: + + [ A B ] = [ CS -SN ] [ AA BB ] [ CS SN ] + [ C D ] [ SN CS ] [ CC DD ] [-SN CS ] + + where either + 1) CC = 0 so that AA and DD are real eigenvalues of the matrix, or + 2) AA = DD and BB*CC < 0, so that AA + or - sqrt(BB*CC) are complex + conjugate eigenvalues. + + Arguments + ========= + + A (input/output) DOUBLE PRECISION + B (input/output) DOUBLE PRECISION + C (input/output) DOUBLE PRECISION + D (input/output) DOUBLE PRECISION + On entry, the elements of the input matrix. + On exit, they are overwritten by the elements of the + standardised Schur form. + + RT1R (output) DOUBLE PRECISION + RT1I (output) DOUBLE PRECISION + RT2R (output) DOUBLE PRECISION + RT2I (output) DOUBLE PRECISION + The real and imaginary parts of the eigenvalues. If the + eigenvalues are a complex conjugate pair, RT1I > 0. + + CS (output) DOUBLE PRECISION + SN (output) DOUBLE PRECISION + Parameters of the rotation matrix. + + Further Details + =============== + + Modified by V. Sima, Research Institute for Informatics, Bucharest, + Romania, to reduce the risk of cancellation errors, + when computing real eigenvalues, and to ensure, if possible, that + abs(RT1R) >= abs(RT2R). + + ===================================================================== +*/ + + + eps = PRECISION; + if (*c__ == 0.) { + *cs = 1.; + *sn = 0.; + goto L10; + + } else if (*b == 0.) { + +/* Swap rows and columns */ + + *cs = 0.; + *sn = 1.; + temp = *d__; + *d__ = *a; + *a = temp; + *b = -(*c__); + *c__ = 0.; + goto L10; + } else if (*a - *d__ == 0. && d_sign(&c_b15, b) != d_sign(&c_b15, c__)) { + *cs = 1.; + *sn = 0.; + goto L10; + } else { + + temp = *a - *d__; + p = temp * .5; +/* Computing MAX */ + d__1 = abs(*b), d__2 = abs(*c__); + bcmax = max(d__1,d__2); +/* Computing MIN */ + d__1 = abs(*b), d__2 = abs(*c__); + bcmis = min(d__1,d__2) * d_sign(&c_b15, b) * d_sign(&c_b15, c__); +/* Computing MAX */ + d__1 = abs(p); + scale = max(d__1,bcmax); + z__ = p / scale * p + bcmax / scale * bcmis; + +/* + If Z is of the order of the machine accuracy, postpone the + decision on the nature of eigenvalues +*/ + + if (z__ >= eps * 4.) { + +/* Real eigenvalues. Compute A and D. */ + + d__1 = sqrt(scale) * sqrt(z__); + z__ = p + d_sign(&d__1, &p); + *a = *d__ + z__; + *d__ -= bcmax / z__ * bcmis; + +/* Compute B and the rotation matrix */ + + tau = dlapy2_(c__, &z__); + *cs = z__ / tau; + *sn = *c__ / tau; + *b -= *c__; + *c__ = 0.; + } else { + +/* + Complex eigenvalues, or real (almost) equal eigenvalues. + Make diagonal elements equal. +*/ + + sigma = *b + *c__; + tau = dlapy2_(&sigma, &temp); + *cs = sqrt((abs(sigma) / tau + 1.) * .5); + *sn = -(p / (tau * *cs)) * d_sign(&c_b15, &sigma); + +/* + Compute [ AA BB ] = [ A B ] [ CS -SN ] + [ CC DD ] [ C D ] [ SN CS ] +*/ + + aa = *a * *cs + *b * *sn; + bb = -(*a) * *sn + *b * *cs; + cc = *c__ * *cs + *d__ * *sn; + dd = -(*c__) * *sn + *d__ * *cs; + +/* + Compute [ A B ] = [ CS SN ] [ AA BB ] + [ C D ] [-SN CS ] [ CC DD ] +*/ + + *a = aa * *cs + cc * *sn; + *b = bb * *cs + dd * *sn; + *c__ = -aa * *sn + cc * *cs; + *d__ = -bb * *sn + dd * *cs; + + temp = (*a + *d__) * .5; + *a = temp; + *d__ = temp; + + if (*c__ != 0.) { + if (*b != 0.) { + if (d_sign(&c_b15, b) == d_sign(&c_b15, c__)) { + +/* Real eigenvalues: reduce to upper triangular form */ + + sab = sqrt((abs(*b))); + sac = sqrt((abs(*c__))); + d__1 = sab * sac; + p = d_sign(&d__1, c__); + tau = 1. / sqrt((d__1 = *b + *c__, abs(d__1))); + *a = temp + p; + *d__ = temp - p; + *b -= *c__; + *c__ = 0.; + cs1 = sab * tau; + sn1 = sac * tau; + temp = *cs * cs1 - *sn * sn1; + *sn = *cs * sn1 + *sn * cs1; + *cs = temp; + } + } else { + *b = -(*c__); + *c__ = 0.; + temp = *cs; + *cs = -(*sn); + *sn = temp; + } + } + } + + } + +L10: + +/* Store eigenvalues in (RT1R,RT1I) and (RT2R,RT2I). */ + + *rt1r = *a; + *rt2r = *d__; + if (*c__ == 0.) { + *rt1i = 0.; + *rt2i = 0.; + } else { + *rt1i = sqrt((abs(*b))) * sqrt((abs(*c__))); + *rt2i = -(*rt1i); + } + return 0; + +/* End of DLANV2 */ + +} /* dlanv2_ */ + +doublereal dlapy2_(doublereal *x, doublereal *y) +{ + /* System generated locals */ + doublereal ret_val, d__1; + + /* Local variables */ + static doublereal w, z__, xabs, yabs; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAPY2 returns sqrt(x**2+y**2), taking care not to cause unnecessary + overflow. + + Arguments + ========= + + X (input) DOUBLE PRECISION + Y (input) DOUBLE PRECISION + X and Y specify the values x and y. + + ===================================================================== +*/ + + + xabs = abs(*x); + yabs = abs(*y); + w = max(xabs,yabs); + z__ = min(xabs,yabs); + if (z__ == 0.) { + ret_val = w; + } else { +/* Computing 2nd power */ + d__1 = z__ / w; + ret_val = w * sqrt(d__1 * d__1 + 1.); + } + return ret_val; + +/* End of DLAPY2 */ + +} /* dlapy2_ */ + +doublereal dlapy3_(doublereal *x, doublereal *y, doublereal *z__) +{ + /* System generated locals */ + doublereal ret_val, d__1, d__2, d__3; + + /* Local variables */ + static doublereal w, xabs, yabs, zabs; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAPY3 returns sqrt(x**2+y**2+z**2), taking care not to cause + unnecessary overflow. + + Arguments + ========= + + X (input) DOUBLE PRECISION + Y (input) DOUBLE PRECISION + Z (input) DOUBLE PRECISION + X, Y and Z specify the values x, y and z. + + ===================================================================== +*/ + + + xabs = abs(*x); + yabs = abs(*y); + zabs = abs(*z__); +/* Computing MAX */ + d__1 = max(xabs,yabs); + w = max(d__1,zabs); + if (w == 0.) { +/* + W can be zero for max(0,nan,0) + adding all three entries together will make sure + NaN will not disappear. +*/ + ret_val = xabs + yabs + zabs; + } else { +/* Computing 2nd power */ + d__1 = xabs / w; +/* Computing 2nd power */ + d__2 = yabs / w; +/* Computing 2nd power */ + d__3 = zabs / w; + ret_val = w * sqrt(d__1 * d__1 + d__2 * d__2 + d__3 * d__3); + } + return ret_val; + +/* End of DLAPY3 */ + +} /* dlapy3_ */ + +/* Subroutine */ int dlaqr0_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal + *wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, + integer *ldz, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1, d__2, d__3, d__4; + + /* Local variables */ + static integer i__, k; + static doublereal aa, bb, cc, dd; + static integer ld; + static doublereal cs; + static integer nh, it, ks, kt; + static doublereal sn; + static integer ku, kv, ls, ns; + static doublereal ss; + static integer nw, inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, + kbot, nmin; + static doublereal swap; + static integer ktop; + static doublereal zdum[1] /* was [1][1] */; + static integer kacc22, itmax, nsmax, nwmax, kwtop; + extern /* Subroutine */ int dlanv2_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *), dlaqr3_( + logical *, logical *, integer *, integer *, integer *, integer *, + doublereal *, integer *, integer *, integer *, doublereal *, + integer *, integer *, integer *, doublereal *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *), + dlaqr4_(logical *, logical *, integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *, + integer *), dlaqr5_(logical *, logical *, integer *, integer *, + integer *, integer *, integer *, doublereal *, doublereal *, + doublereal *, integer *, integer *, integer *, doublereal *, + integer *, doublereal *, integer *, doublereal *, integer *, + integer *, doublereal *, integer *, integer *, doublereal *, + integer *); + static integer nibble; + extern /* Subroutine */ int dlahqr_(logical *, logical *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + integer *), dlacpy_(char *, integer *, integer *, doublereal *, + integer *, doublereal *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static char jbcmpz[2]; + static integer nwupbd; + static logical sorted; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Purpose + ======= + + DLAQR0 computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**T, where T is an upper quasi-triangular matrix (the + Schur form), and Z is the orthogonal matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input orthogonal + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the orthogonal matrix Q: A = Q*H*Q**T = (QZ)*T*(QZ)**T. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1, + H(ILO,ILO-1) is zero. ILO and IHI are normally set by a + previous call to DGEBAL, and then passed to DGEHRD when the + matrix output by DGEBAL is reduced to Hessenberg form. + Otherwise, ILO and IHI should be set to 1 and N, + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) DOUBLE PRECISION array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and WANTT is .TRUE., then H contains + the upper quasi-triangular matrix T from the Schur + decomposition (the Schur form); 2-by-2 diagonal blocks + (corresponding to complex conjugate pairs of eigenvalues) + are returned in standard form, with H(i,i) = H(i+1,i+1) + and H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and WANTT is + .FALSE., then the contents of H are unspecified on exit. + (The output value of H when INFO.GT.0 is given under the + description of INFO below.) + + This subroutine may explicitly set H(i,j) = 0 for i.GT.j and + j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + WR (output) DOUBLE PRECISION array, dimension (IHI) + WI (output) DOUBLE PRECISION array, dimension (IHI) + The real and imaginary parts, respectively, of the computed + eigenvalues of H(ILO:IHI,ILO:IHI) are stored in WR(ILO:IHI) + and WI(ILO:IHI). If two eigenvalues are computed as a + complex conjugate pair, they are stored in consecutive + elements of WR and WI, say the i-th and (i+1)th, with + WI(i) .GT. 0 and WI(i+1) .LT. 0. If WANTT is .TRUE., then + the eigenvalues are stored in the same order as on the + diagonal of the Schur form returned in H, with + WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 diagonal + block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and + WI(i+1) = -WI(i). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. + 1 .LE. ILOZ .LE. ILO; IHI .LE. IHIZ .LE. N. + + Z (input/output) DOUBLE PRECISION array, dimension (LDZ,IHI) + If WANTZ is .FALSE., then Z is not referenced. + If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is + replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the + orthogonal Schur factor of H(ILO:IHI,ILO:IHI). + (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if WANTZ is .TRUE. + then LDZ.GE.MAX(1,IHIZ). Otherwize, LDZ.GE.1. + + WORK (workspace/output) DOUBLE PRECISION array, dimension LWORK + On exit, if LWORK = -1, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient, but LWORK typically as large as 6*N may + be required for optimal performance. A workspace query + to determine the optimal workspace size is recommended. + + If LWORK = -1, then DLAQR0 does a workspace query. + In this case, DLAQR0 checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, DLAQR0 failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and WANT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is an orthogonal matrix. The final + value of H is upper Hessenberg and quasi-triangular + in rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + + (final value of Z(ILO:IHI,ILOZ:IHIZ) + = (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U + + where U is the orthogonal matrix in (*) (regard- + less of the value of WANTT.) + + If INFO .GT. 0 and WANTZ is .FALSE., then Z is not + accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . DLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== Exceptional deflation windows: try to cure rare + . slow convergence by varying the size of the + . deflation window after KEXNW iterations. ==== + + ==== Exceptional shifts: try to cure rare slow convergence + . with ad-hoc exceptional shifts every KEXSH iterations. + . ==== + + ==== The constants WILK1 and WILK2 are used to form the + . exceptional shifts. ==== +*/ + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --wr; + --wi; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + +/* ==== Quick return for N = 0: nothing to do. ==== */ + + if (*n == 0) { + work[1] = 1.; + return 0; + } + + if (*n <= 11) { + +/* ==== Tiny matrices must use DLAHQR. ==== */ + + lwkopt = 1; + if (*lwork != -1) { + dlahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], & + wi[1], iloz, ihiz, &z__[z_offset], ldz, info); + } + } else { + +/* + ==== Use small bulge multi-shift QR with aggressive early + . deflation on larger-than-tiny matrices. ==== + + ==== Hope for the best. ==== +*/ + + *info = 0; + +/* ==== Set up job flags for ILAENV. ==== */ + + if (*wantt) { + *(unsigned char *)jbcmpz = 'S'; + } else { + *(unsigned char *)jbcmpz = 'E'; + } + if (*wantz) { + *(unsigned char *)&jbcmpz[1] = 'V'; + } else { + *(unsigned char *)&jbcmpz[1] = 'N'; + } + +/* + ==== NWR = recommended deflation window size. At this + . point, N .GT. NTINY = 11, so there is enough + . subdiagonal workspace for NWR.GE.2 as required. + . (In fact, there is enough subdiagonal space for + . NWR.GE.3.) ==== +*/ + + nwr = ilaenv_(&c__13, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nwr = max(2,nwr); +/* Computing MIN */ + i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2); + nwr = min(i__1,nwr); + +/* + ==== NSR = recommended number of simultaneous shifts. + . At this point N .GT. NTINY = 11, so there is at + . enough subdiagonal workspace for NSR to be even + . and greater than or equal to two as required. ==== +*/ + + nsr = ilaenv_(&c__15, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); +/* Computing MIN */ + i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - + *ilo; + nsr = min(i__1,i__2); +/* Computing MAX */ + i__1 = 2, i__2 = nsr - nsr % 2; + nsr = max(i__1,i__2); + +/* + ==== Estimate optimal workspace ==== + + ==== Workspace query call to DLAQR3 ==== +*/ + + i__1 = nwr + 1; + dlaqr3_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, + ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], &h__[ + h_offset], ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], + ldh, &work[1], &c_n1); + +/* + ==== Optimal workspace = MAX(DLAQR5, DLAQR3) ==== + + Computing MAX +*/ + i__1 = nsr * 3 / 2, i__2 = (integer) work[1]; + lwkopt = max(i__1,i__2); + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + work[1] = (doublereal) lwkopt; + return 0; + } + +/* ==== DLAHQR/DLAQR0 crossover point ==== */ + + nmin = ilaenv_(&c__12, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen) + 6, (ftnlen)2); + nmin = max(11,nmin); + +/* ==== Nibble crossover point ==== */ + + nibble = ilaenv_(&c__14, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + nibble = max(0,nibble); + +/* + ==== Accumulate reflections during ttswp? Use block + . 2-by-2 structure during matrix-matrix multiply? ==== +*/ + + kacc22 = ilaenv_(&c__16, "DLAQR0", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + kacc22 = max(0,kacc22); + kacc22 = min(2,kacc22); + +/* + ==== NWMAX = the largest possible deflation window for + . which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n - 1) / 3, i__2 = *lwork / 2; + nwmax = min(i__1,i__2); + nw = nwmax; + +/* + ==== NSMAX = the Largest number of simultaneous shifts + . for which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3; + nsmax = min(i__1,i__2); + nsmax -= nsmax % 2; + +/* ==== NDFL: an iteration count restarted at deflation. ==== */ + + ndfl = 1; + +/* + ==== ITMAX = iteration limit ==== + + Computing MAX +*/ + i__1 = 10, i__2 = *ihi - *ilo + 1; + itmax = max(i__1,i__2) * 30; + +/* ==== Last row and column in the active block ==== */ + + kbot = *ihi; + +/* ==== Main Loop ==== */ + + i__1 = itmax; + for (it = 1; it <= i__1; ++it) { + +/* ==== Done when KBOT falls below ILO ==== */ + + if (kbot < *ilo) { + goto L90; + } + +/* ==== Locate active block ==== */ + + i__2 = *ilo + 1; + for (k = kbot; k >= i__2; --k) { + if (h__[k + (k - 1) * h_dim1] == 0.) { + goto L20; + } +/* L10: */ + } + k = *ilo; +L20: + ktop = k; + +/* + ==== Select deflation window size: + . Typical Case: + . If possible and advisable, nibble the entire + . active block. If not, use size MIN(NWR,NWMAX) + . or MIN(NWR+1,NWMAX) depending upon which has + . the smaller corresponding subdiagonal entry + . (a heuristic). + . + . Exceptional Case: + . If there have been no deflations in KEXNW or + . more iterations, then vary the deflation window + . size. At first, because, larger windows are, + . in general, more powerful than smaller ones, + . rapidly increase the window to the maximum possible. + . Then, gradually reduce the window size. ==== +*/ + + nh = kbot - ktop + 1; + nwupbd = min(nh,nwmax); + if (ndfl < 5) { + nw = min(nwupbd,nwr); + } else { +/* Computing MIN */ + i__2 = nwupbd, i__3 = nw << 1; + nw = min(i__2,i__3); + } + if (nw < nwmax) { + if (nw >= nh - 1) { + nw = nh; + } else { + kwtop = kbot - nw + 1; + if ((d__1 = h__[kwtop + (kwtop - 1) * h_dim1], abs(d__1)) + > (d__2 = h__[kwtop - 1 + (kwtop - 2) * h_dim1], + abs(d__2))) { + ++nw; + } + } + } + if (ndfl < 5) { + ndec = -1; + } else if (ndec >= 0 || nw >= nwupbd) { + ++ndec; + if (nw - ndec < 2) { + ndec = 0; + } + nw -= ndec; + } + +/* + ==== Aggressive early deflation: + . split workspace under the subdiagonal into + . - an nw-by-nw work array V in the lower + . left-hand-corner, + . - an NW-by-at-least-NW-but-more-is-better + . (NW-by-NHO) horizontal work array along + . the bottom edge, + . - an at-least-NW-but-more-is-better (NHV-by-NW) + . vertical work array along the left-hand-edge. + . ==== +*/ + + kv = *n - nw + 1; + kt = nw + 1; + nho = *n - nw - 1 - kt + 1; + kwv = nw + 2; + nve = *n - nw - kwv + 1; + +/* ==== Aggressive early deflation ==== */ + + dlaqr3_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, + iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], + &h__[kv + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], + ldh, &nve, &h__[kwv + h_dim1], ldh, &work[1], lwork); + +/* ==== Adjust KBOT accounting for new deflations. ==== */ + + kbot -= ld; + +/* ==== KS points to the shifts. ==== */ + + ks = kbot - ls + 1; + +/* + ==== Skip an expensive QR sweep if there is a (partly + . heuristic) reason to expect that many eigenvalues + . will deflate without it. Here, the QR sweep is + . skipped if many eigenvalues have just been deflated + . or if the remaining active block is small. +*/ + + if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min( + nmin,nwmax)) { + +/* + ==== NS = nominal number of simultaneous shifts. + . This may be lowered (slightly) if DLAQR3 + . did not provide that many shifts. ==== + + Computing MIN + Computing MAX +*/ + i__4 = 2, i__5 = kbot - ktop; + i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5); + ns = min(i__2,i__3); + ns -= ns % 2; + +/* + ==== If there have been no deflations + . in a multiple of KEXSH iterations, + . then try exceptional shifts. + . Otherwise use shifts provided by + . DLAQR3 above or from the eigenvalues + . of a trailing principal submatrix. ==== +*/ + + if (ndfl % 6 == 0) { + ks = kbot - ns + 1; +/* Computing MAX */ + i__3 = ks + 1, i__4 = ktop + 2; + i__2 = max(i__3,i__4); + for (i__ = kbot; i__ >= i__2; i__ += -2) { + ss = (d__1 = h__[i__ + (i__ - 1) * h_dim1], abs(d__1)) + + (d__2 = h__[i__ - 1 + (i__ - 2) * h_dim1], + abs(d__2)); + aa = ss * .75 + h__[i__ + i__ * h_dim1]; + bb = ss; + cc = ss * -.4375; + dd = aa; + dlanv2_(&aa, &bb, &cc, &dd, &wr[i__ - 1], &wi[i__ - 1] + , &wr[i__], &wi[i__], &cs, &sn); +/* L30: */ + } + if (ks == ktop) { + wr[ks + 1] = h__[ks + 1 + (ks + 1) * h_dim1]; + wi[ks + 1] = 0.; + wr[ks] = wr[ks + 1]; + wi[ks] = wi[ks + 1]; + } + } else { + +/* + ==== Got NS/2 or fewer shifts? Use DLAQR4 or + . DLAHQR on a trailing principal submatrix to + . get more. (Since NS.LE.NSMAX.LE.(N+6)/9, + . there is enough space below the subdiagonal + . to fit an NS-by-NS scratch array.) ==== +*/ + + if (kbot - ks + 1 <= ns / 2) { + ks = kbot - ns + 1; + kt = *n - ns + 1; + dlacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, & + h__[kt + h_dim1], ldh); + if (ns > nmin) { + dlaqr4_(&c_false, &c_false, &ns, &c__1, &ns, &h__[ + kt + h_dim1], ldh, &wr[ks], &wi[ks], & + c__1, &c__1, zdum, &c__1, &work[1], lwork, + &inf); + } else { + dlahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[ + kt + h_dim1], ldh, &wr[ks], &wi[ks], & + c__1, &c__1, zdum, &c__1, &inf); + } + ks += inf; + +/* + ==== In case of a rare QR failure use + . eigenvalues of the trailing 2-by-2 + . principal submatrix. ==== +*/ + + if (ks >= kbot) { + aa = h__[kbot - 1 + (kbot - 1) * h_dim1]; + cc = h__[kbot + (kbot - 1) * h_dim1]; + bb = h__[kbot - 1 + kbot * h_dim1]; + dd = h__[kbot + kbot * h_dim1]; + dlanv2_(&aa, &bb, &cc, &dd, &wr[kbot - 1], &wi[ + kbot - 1], &wr[kbot], &wi[kbot], &cs, &sn) + ; + ks = kbot - 1; + } + } + + if (kbot - ks + 1 > ns) { + +/* + ==== Sort the shifts (Helps a little) + . Bubble sort keeps complex conjugate + . pairs together. ==== +*/ + + sorted = FALSE_; + i__2 = ks + 1; + for (k = kbot; k >= i__2; --k) { + if (sorted) { + goto L60; + } + sorted = TRUE_; + i__3 = k - 1; + for (i__ = ks; i__ <= i__3; ++i__) { + if ((d__1 = wr[i__], abs(d__1)) + (d__2 = wi[ + i__], abs(d__2)) < (d__3 = wr[i__ + 1] + , abs(d__3)) + (d__4 = wi[i__ + 1], + abs(d__4))) { + sorted = FALSE_; + + swap = wr[i__]; + wr[i__] = wr[i__ + 1]; + wr[i__ + 1] = swap; + + swap = wi[i__]; + wi[i__] = wi[i__ + 1]; + wi[i__ + 1] = swap; + } +/* L40: */ + } +/* L50: */ + } +L60: + ; + } + +/* + ==== Shuffle shifts into pairs of real shifts + . and pairs of complex conjugate shifts + . assuming complex conjugate shifts are + . already adjacent to one another. (Yes, + . they are.) ==== +*/ + + i__2 = ks + 2; + for (i__ = kbot; i__ >= i__2; i__ += -2) { + if (wi[i__] != -wi[i__ - 1]) { + + swap = wr[i__]; + wr[i__] = wr[i__ - 1]; + wr[i__ - 1] = wr[i__ - 2]; + wr[i__ - 2] = swap; + + swap = wi[i__]; + wi[i__] = wi[i__ - 1]; + wi[i__ - 1] = wi[i__ - 2]; + wi[i__ - 2] = swap; + } +/* L70: */ + } + } + +/* + ==== If there are only two shifts and both are + . real, then use only one. ==== +*/ + + if (kbot - ks + 1 == 2) { + if (wi[kbot] == 0.) { + if ((d__1 = wr[kbot] - h__[kbot + kbot * h_dim1], abs( + d__1)) < (d__2 = wr[kbot - 1] - h__[kbot + + kbot * h_dim1], abs(d__2))) { + wr[kbot - 1] = wr[kbot]; + } else { + wr[kbot] = wr[kbot - 1]; + } + } + } + +/* + ==== Use up to NS of the the smallest magnatiude + . shifts. If there aren't NS shifts available, + . then use them all, possibly dropping one to + . make the number of shifts even. ==== + + Computing MIN +*/ + i__2 = ns, i__3 = kbot - ks + 1; + ns = min(i__2,i__3); + ns -= ns % 2; + ks = kbot - ns + 1; + +/* + ==== Small-bulge multi-shift QR sweep: + . split workspace under the subdiagonal into + . - a KDU-by-KDU work array U in the lower + . left-hand-corner, + . - a KDU-by-at-least-KDU-but-more-is-better + . (KDU-by-NHo) horizontal work array WH along + . the bottom edge, + . - and an at-least-KDU-but-more-is-better-by-KDU + . (NVE-by-KDU) vertical work WV arrow along + . the left-hand-edge. ==== +*/ + + kdu = ns * 3 - 3; + ku = *n - kdu + 1; + kwh = kdu + 1; + nho = *n - kdu - 3 - (kdu + 1) + 1; + kwv = kdu + 4; + nve = *n - kdu - kwv + 1; + +/* ==== Small-bulge multi-shift QR sweep ==== */ + + dlaqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &wr[ks], + &wi[ks], &h__[h_offset], ldh, iloz, ihiz, &z__[ + z_offset], ldz, &work[1], &c__3, &h__[ku + h_dim1], + ldh, &nve, &h__[kwv + h_dim1], ldh, &nho, &h__[ku + + kwh * h_dim1], ldh); + } + +/* ==== Note progress (or the lack of it). ==== */ + + if (ld > 0) { + ndfl = 1; + } else { + ++ndfl; + } + +/* + ==== End of main loop ==== + L80: +*/ + } + +/* + ==== Iteration limit exceeded. Set INFO to show where + . the problem occurred and exit. ==== +*/ + + *info = kbot; +L90: + ; + } + +/* ==== Return the optimal value of LWORK. ==== */ + + work[1] = (doublereal) lwkopt; + +/* ==== End of DLAQR0 ==== */ + + return 0; +} /* dlaqr0_ */ + +/* Subroutine */ int dlaqr1_(integer *n, doublereal *h__, integer *ldh, + doublereal *sr1, doublereal *si1, doublereal *sr2, doublereal *si2, + doublereal *v) +{ + /* System generated locals */ + integer h_dim1, h_offset; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static doublereal s, h21s, h31s; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Given a 2-by-2 or 3-by-3 matrix H, DLAQR1 sets v to a + scalar multiple of the first column of the product + + (*) K = (H - (sr1 + i*si1)*I)*(H - (sr2 + i*si2)*I) + + scaling to avoid overflows and most underflows. It + is assumed that either + + 1) sr1 = sr2 and si1 = -si2 + or + 2) si1 = si2 = 0. + + This is useful for starting double implicit shift bulges + in the QR algorithm. + + + N (input) integer + Order of the matrix H. N must be either 2 or 3. + + H (input) DOUBLE PRECISION array of dimension (LDH,N) + The 2-by-2 or 3-by-3 matrix H in (*). + + LDH (input) integer + The leading dimension of H as declared in + the calling procedure. LDH.GE.N + + SR1 (input) DOUBLE PRECISION + SI1 The shifts in (*). + SR2 + SI2 + + V (output) DOUBLE PRECISION array of dimension N + A scalar multiple of the first column of the + matrix K in (*). + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --v; + + /* Function Body */ + if (*n == 2) { + s = (d__1 = h__[h_dim1 + 1] - *sr2, abs(d__1)) + abs(*si2) + (d__2 = + h__[h_dim1 + 2], abs(d__2)); + if (s == 0.) { + v[1] = 0.; + v[2] = 0.; + } else { + h21s = h__[h_dim1 + 2] / s; + v[1] = h21s * h__[(h_dim1 << 1) + 1] + (h__[h_dim1 + 1] - *sr1) * + ((h__[h_dim1 + 1] - *sr2) / s) - *si1 * (*si2 / s); + v[2] = h21s * (h__[h_dim1 + 1] + h__[(h_dim1 << 1) + 2] - *sr1 - * + sr2); + } + } else { + s = (d__1 = h__[h_dim1 + 1] - *sr2, abs(d__1)) + abs(*si2) + (d__2 = + h__[h_dim1 + 2], abs(d__2)) + (d__3 = h__[h_dim1 + 3], abs( + d__3)); + if (s == 0.) { + v[1] = 0.; + v[2] = 0.; + v[3] = 0.; + } else { + h21s = h__[h_dim1 + 2] / s; + h31s = h__[h_dim1 + 3] / s; + v[1] = (h__[h_dim1 + 1] - *sr1) * ((h__[h_dim1 + 1] - *sr2) / s) + - *si1 * (*si2 / s) + h__[(h_dim1 << 1) + 1] * h21s + h__[ + h_dim1 * 3 + 1] * h31s; + v[2] = h21s * (h__[h_dim1 + 1] + h__[(h_dim1 << 1) + 2] - *sr1 - * + sr2) + h__[h_dim1 * 3 + 2] * h31s; + v[3] = h31s * (h__[h_dim1 + 1] + h__[h_dim1 * 3 + 3] - *sr1 - * + sr2) + h21s * h__[(h_dim1 << 1) + 3]; + } + } + return 0; +} /* dlaqr1_ */ + +/* Subroutine */ int dlaqr2_(logical *wantt, logical *wantz, integer *n, + integer *ktop, integer *kbot, integer *nw, doublereal *h__, integer * + ldh, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, + integer *ns, integer *nd, doublereal *sr, doublereal *si, doublereal * + v, integer *ldv, integer *nh, doublereal *t, integer *ldt, integer * + nv, doublereal *wv, integer *ldwv, doublereal *work, integer *lwork) +{ + /* System generated locals */ + integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, + wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2, d__3, d__4, d__5, d__6; + + /* Local variables */ + static integer i__, j, k; + static doublereal s, aa, bb, cc, dd, cs, sn; + static integer jw; + static doublereal evi, evk, foo; + static integer kln; + static doublereal tau, ulp; + static integer lwk1, lwk2; + static doublereal beta; + static integer kend, kcol, info, ifst, ilst, ltop, krow; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *), dgemm_(char *, char *, integer *, integer * + , integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static logical bulge; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer infqr, kwtop; + extern /* Subroutine */ int dlanv2_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *), dlabad_( + doublereal *, doublereal *); + + extern /* Subroutine */ int dgehrd_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + integer *), dlarfg_(integer *, doublereal *, doublereal *, + integer *, doublereal *), dlahqr_(logical *, logical *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + integer *), dlacpy_(char *, integer *, integer *, doublereal *, + integer *, doublereal *, integer *); + static doublereal safmin; + extern /* Subroutine */ int dlaset_(char *, integer *, integer *, + doublereal *, doublereal *, doublereal *, integer *); + static doublereal safmax; + extern /* Subroutine */ int dtrexc_(char *, integer *, doublereal *, + integer *, doublereal *, integer *, integer *, integer *, + doublereal *, integer *), dormhr_(char *, char *, integer + *, integer *, integer *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + integer *); + static logical sorted; + static doublereal smlnum; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + -- June 2010 -- + + + This subroutine is identical to DLAQR3 except that it avoids + recursion by calling DLAHQR instead of DLAQR4. + + + ****************************************************************** + Aggressive early deflation: + + This subroutine accepts as input an upper Hessenberg matrix + H and performs an orthogonal similarity transformation + designed to detect and deflate fully converged eigenvalues from + a trailing principal submatrix. On output H has been over- + written by a new Hessenberg matrix that is a perturbation of + an orthogonal similarity transformation of H. It is to be + hoped that the final version of H has many zero subdiagonal + entries. + + ****************************************************************** + WANTT (input) LOGICAL + If .TRUE., then the Hessenberg matrix H is fully updated + so that the quasi-triangular Schur factor may be + computed (in cooperation with the calling subroutine). + If .FALSE., then only enough of H is updated to preserve + the eigenvalues. + + WANTZ (input) LOGICAL + If .TRUE., then the orthogonal matrix Z is updated so + so that the orthogonal Schur factor may be computed + (in cooperation with the calling subroutine). + If .FALSE., then Z is not referenced. + + N (input) INTEGER + The order of the matrix H and (if WANTZ is .TRUE.) the + order of the orthogonal matrix Z. + + KTOP (input) INTEGER + It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0. + KBOT and KTOP together determine an isolated block + along the diagonal of the Hessenberg matrix. + + KBOT (input) INTEGER + It is assumed without a check that either + KBOT = N or H(KBOT+1,KBOT)=0. KBOT and KTOP together + determine an isolated block along the diagonal of the + Hessenberg matrix. + + NW (input) INTEGER + Deflation window size. 1 .LE. NW .LE. (KBOT-KTOP+1). + + H (input/output) DOUBLE PRECISION array, dimension (LDH,N) + On input the initial N-by-N section of H stores the + Hessenberg matrix undergoing aggressive early deflation. + On output H has been transformed by an orthogonal + similarity transformation, perturbed, and the returned + to Hessenberg form that (it is to be hoped) has some + zero subdiagonal entries. + + LDH (input) integer + Leading dimension of H just as declared in the calling + subroutine. N .LE. LDH + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N. + + Z (input/output) DOUBLE PRECISION array, dimension (LDZ,N) + IF WANTZ is .TRUE., then on output, the orthogonal + similarity transformation mentioned above has been + accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ is .FALSE., then Z is unreferenced. + + LDZ (input) integer + The leading dimension of Z just as declared in the + calling subroutine. 1 .LE. LDZ. + + NS (output) integer + The number of unconverged (ie approximate) eigenvalues + returned in SR and SI that may be used as shifts by the + calling subroutine. + + ND (output) integer + The number of converged eigenvalues uncovered by this + subroutine. + + SR (output) DOUBLE PRECISION array, dimension (KBOT) + SI (output) DOUBLE PRECISION array, dimension (KBOT) + On output, the real and imaginary parts of approximate + eigenvalues that may be used for shifts are stored in + SR(KBOT-ND-NS+1) through SR(KBOT-ND) and + SI(KBOT-ND-NS+1) through SI(KBOT-ND), respectively. + The real and imaginary parts of converged eigenvalues + are stored in SR(KBOT-ND+1) through SR(KBOT) and + SI(KBOT-ND+1) through SI(KBOT), respectively. + + V (workspace) DOUBLE PRECISION array, dimension (LDV,NW) + An NW-by-NW work array. + + LDV (input) integer scalar + The leading dimension of V just as declared in the + calling subroutine. NW .LE. LDV + + NH (input) integer scalar + The number of columns of T. NH.GE.NW. + + T (workspace) DOUBLE PRECISION array, dimension (LDT,NW) + + LDT (input) integer + The leading dimension of T just as declared in the + calling subroutine. NW .LE. LDT + + NV (input) integer + The number of rows of work array WV available for + workspace. NV.GE.NW. + + WV (workspace) DOUBLE PRECISION array, dimension (LDWV,NW) + + LDWV (input) integer + The leading dimension of W just as declared in the + calling subroutine. NW .LE. LDV + + WORK (workspace) DOUBLE PRECISION array, dimension (LWORK) + On exit, WORK(1) is set to an estimate of the optimal value + of LWORK for the given values of N, NW, KTOP and KBOT. + + LWORK (input) integer + The dimension of the work array WORK. LWORK = 2*NW + suffices, but greater efficiency may result from larger + values of LWORK. + + If LWORK = -1, then a workspace query is assumed; DLAQR2 + only estimates the optimal workspace size for the given + values of N, NW, KTOP and KBOT. The estimate is returned + in WORK(1). No error message related to LWORK is issued + by XERBLA. Neither H nor Z are accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + + ==== Estimate optimal workspace. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --sr; + --si; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + --work; + + /* Function Body */ +/* Computing MIN */ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + if (jw <= 2) { + lwkopt = 1; + } else { + +/* ==== Workspace query call to DGEHRD ==== */ + + i__1 = jw - 1; + dgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], & + c_n1, &info); + lwk1 = (integer) work[1]; + +/* ==== Workspace query call to DORMHR ==== */ + + i__1 = jw - 1; + dormhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[1], &c_n1, &info); + lwk2 = (integer) work[1]; + +/* ==== Optimal workspace ==== */ + + lwkopt = jw + max(lwk1,lwk2); + } + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + work[1] = (doublereal) lwkopt; + return 0; + } + +/* + ==== Nothing to do ... + ... for an empty active block ... ==== +*/ + *ns = 0; + *nd = 0; + work[1] = 1.; + if (*ktop > *kbot) { + return 0; + } +/* ... nor for an empty deflation window. ==== */ + if (*nw < 1) { + return 0; + } + +/* ==== Machine constants ==== */ + + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + dlabad_(&safmin, &safmax); + ulp = PRECISION; + smlnum = safmin * ((doublereal) (*n) / ulp); + +/* + ==== Setup deflation window ==== + + Computing MIN +*/ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + kwtop = *kbot - jw + 1; + if (kwtop == *ktop) { + s = 0.; + } else { + s = h__[kwtop + (kwtop - 1) * h_dim1]; + } + + if (*kbot == kwtop) { + +/* ==== 1-by-1 deflation window: not much to do ==== */ + + sr[kwtop] = h__[kwtop + kwtop * h_dim1]; + si[kwtop] = 0.; + *ns = 1; + *nd = 0; +/* Computing MAX */ + d__2 = smlnum, d__3 = ulp * (d__1 = h__[kwtop + kwtop * h_dim1], abs( + d__1)); + if (abs(s) <= max(d__2,d__3)) { + *ns = 0; + *nd = 1; + if (kwtop > *ktop) { + h__[kwtop + (kwtop - 1) * h_dim1] = 0.; + } + } + work[1] = 1.; + return 0; + } + +/* + ==== Convert to spike-triangular form. (In case of a + . rare QR failure, this routine continues to do + . aggressive early deflation using that part of + . the deflation window that converged using INFQR + . here and there to keep track.) ==== +*/ + + dlacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], + ldt); + i__1 = jw - 1; + i__2 = *ldh + 1; + i__3 = *ldt + 1; + dcopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], & + i__3); + + dlaset_("A", &jw, &jw, &c_b29, &c_b15, &v[v_offset], ldv); + dlahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[kwtop], + &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &infqr); + +/* ==== DTREXC needs a clean margin near the diagonal ==== */ + + i__1 = jw - 3; + for (j = 1; j <= i__1; ++j) { + t[j + 2 + j * t_dim1] = 0.; + t[j + 3 + j * t_dim1] = 0.; +/* L10: */ + } + if (jw > 2) { + t[jw + (jw - 2) * t_dim1] = 0.; + } + +/* ==== Deflation detection loop ==== */ + + *ns = jw; + ilst = infqr + 1; +L20: + if (ilst <= *ns) { + if (*ns == 1) { + bulge = FALSE_; + } else { + bulge = t[*ns + (*ns - 1) * t_dim1] != 0.; + } + +/* ==== Small spike tip test for deflation ==== */ + + if (! bulge) { + +/* ==== Real eigenvalue ==== */ + + foo = (d__1 = t[*ns + *ns * t_dim1], abs(d__1)); + if (foo == 0.) { + foo = abs(s); + } +/* Computing MAX */ + d__2 = smlnum, d__3 = ulp * foo; + if ((d__1 = s * v[*ns * v_dim1 + 1], abs(d__1)) <= max(d__2,d__3)) + { + +/* ==== Deflatable ==== */ + + --(*ns); + } else { + +/* + ==== Undeflatable. Move it up out of the way. + . (DTREXC can not fail in this case.) ==== +*/ + + ifst = *ns; + dtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + ++ilst; + } + } else { + +/* ==== Complex conjugate pair ==== */ + + foo = (d__3 = t[*ns + *ns * t_dim1], abs(d__3)) + sqrt((d__1 = t[* + ns + (*ns - 1) * t_dim1], abs(d__1))) * sqrt((d__2 = t[* + ns - 1 + *ns * t_dim1], abs(d__2))); + if (foo == 0.) { + foo = abs(s); + } +/* Computing MAX */ + d__3 = (d__1 = s * v[*ns * v_dim1 + 1], abs(d__1)), d__4 = (d__2 = + s * v[(*ns - 1) * v_dim1 + 1], abs(d__2)); +/* Computing MAX */ + d__5 = smlnum, d__6 = ulp * foo; + if (max(d__3,d__4) <= max(d__5,d__6)) { + +/* ==== Deflatable ==== */ + + *ns += -2; + } else { + +/* + ==== Undeflatable. Move them up out of the way. + . Fortunately, DTREXC does the right thing with + . ILST in case of a rare exchange failure. ==== +*/ + + ifst = *ns; + dtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + ilst += 2; + } + } + +/* ==== End deflation detection loop ==== */ + + goto L20; + } + +/* ==== Return to Hessenberg form ==== */ + + if (*ns == 0) { + s = 0.; + } + + if (*ns < jw) { + +/* + ==== sorting diagonal blocks of T improves accuracy for + . graded matrices. Bubble sort deals well with + . exchange failures. ==== +*/ + + sorted = FALSE_; + i__ = *ns + 1; +L30: + if (sorted) { + goto L50; + } + sorted = TRUE_; + + kend = i__ - 1; + i__ = infqr + 1; + if (i__ == *ns) { + k = i__ + 1; + } else if (t[i__ + 1 + i__ * t_dim1] == 0.) { + k = i__ + 1; + } else { + k = i__ + 2; + } +L40: + if (k <= kend) { + if (k == i__ + 1) { + evi = (d__1 = t[i__ + i__ * t_dim1], abs(d__1)); + } else { + evi = (d__3 = t[i__ + i__ * t_dim1], abs(d__3)) + sqrt((d__1 = + t[i__ + 1 + i__ * t_dim1], abs(d__1))) * sqrt((d__2 = + t[i__ + (i__ + 1) * t_dim1], abs(d__2))); + } + + if (k == kend) { + evk = (d__1 = t[k + k * t_dim1], abs(d__1)); + } else if (t[k + 1 + k * t_dim1] == 0.) { + evk = (d__1 = t[k + k * t_dim1], abs(d__1)); + } else { + evk = (d__3 = t[k + k * t_dim1], abs(d__3)) + sqrt((d__1 = t[ + k + 1 + k * t_dim1], abs(d__1))) * sqrt((d__2 = t[k + + (k + 1) * t_dim1], abs(d__2))); + } + + if (evi >= evk) { + i__ = k; + } else { + sorted = FALSE_; + ifst = i__; + ilst = k; + dtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + if (info == 0) { + i__ = ilst; + } else { + i__ = k; + } + } + if (i__ == kend) { + k = i__ + 1; + } else if (t[i__ + 1 + i__ * t_dim1] == 0.) { + k = i__ + 1; + } else { + k = i__ + 2; + } + goto L40; + } + goto L30; +L50: + ; + } + +/* ==== Restore shift/eigenvalue array from T ==== */ + + i__ = jw; +L60: + if (i__ >= infqr + 1) { + if (i__ == infqr + 1) { + sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1]; + si[kwtop + i__ - 1] = 0.; + --i__; + } else if (t[i__ + (i__ - 1) * t_dim1] == 0.) { + sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1]; + si[kwtop + i__ - 1] = 0.; + --i__; + } else { + aa = t[i__ - 1 + (i__ - 1) * t_dim1]; + cc = t[i__ + (i__ - 1) * t_dim1]; + bb = t[i__ - 1 + i__ * t_dim1]; + dd = t[i__ + i__ * t_dim1]; + dlanv2_(&aa, &bb, &cc, &dd, &sr[kwtop + i__ - 2], &si[kwtop + i__ + - 2], &sr[kwtop + i__ - 1], &si[kwtop + i__ - 1], &cs, & + sn); + i__ += -2; + } + goto L60; + } + + if (*ns < jw || s == 0.) { + if (*ns > 1 && s != 0.) { + +/* ==== Reflect spike back into lower triangle ==== */ + + dcopy_(ns, &v[v_offset], ldv, &work[1], &c__1); + beta = work[1]; + dlarfg_(ns, &beta, &work[2], &c__1, &tau); + work[1] = 1.; + + i__1 = jw - 2; + i__2 = jw - 2; + dlaset_("L", &i__1, &i__2, &c_b29, &c_b29, &t[t_dim1 + 3], ldt); + + dlarf_("L", ns, &jw, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + dlarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + dlarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, & + work[jw + 1]); + + i__1 = *lwork - jw; + dgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1] + , &i__1, &info); + } + +/* ==== Copy updated reduced window into place ==== */ + + if (kwtop > 1) { + h__[kwtop + (kwtop - 1) * h_dim1] = s * v[v_dim1 + 1]; + } + dlacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1] + , ldh); + i__1 = jw - 1; + i__2 = *ldt + 1; + i__3 = *ldh + 1; + dcopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1], + &i__3); + +/* + ==== Accumulate orthogonal matrix in order update + . H and Z, if requested. ==== +*/ + + if (*ns > 1 && s != 0.) { + i__1 = *lwork - jw; + dormhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[jw + 1], &i__1, &info); + } + +/* ==== Update vertical slab in H ==== */ + + if (*wantt) { + ltop = 1; + } else { + ltop = *ktop; + } + i__1 = kwtop - 1; + i__2 = *nv; + for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = kwtop - krow; + kln = min(i__3,i__4); + dgemm_("N", "N", &kln, &jw, &jw, &c_b15, &h__[krow + kwtop * + h_dim1], ldh, &v[v_offset], ldv, &c_b29, &wv[wv_offset], + ldwv); + dlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * + h_dim1], ldh); +/* L70: */ + } + +/* ==== Update horizontal slab in H ==== */ + + if (*wantt) { + i__2 = *n; + i__1 = *nh; + for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; + kcol += i__1) { +/* Computing MIN */ + i__3 = *nh, i__4 = *n - kcol + 1; + kln = min(i__3,i__4); + dgemm_("C", "N", &jw, &kln, &jw, &c_b15, &v[v_offset], ldv, & + h__[kwtop + kcol * h_dim1], ldh, &c_b29, &t[t_offset], + ldt); + dlacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol * + h_dim1], ldh); +/* L80: */ + } + } + +/* ==== Update vertical slab in Z ==== */ + + if (*wantz) { + i__1 = *ihiz; + i__2 = *nv; + for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = *ihiz - krow + 1; + kln = min(i__3,i__4); + dgemm_("N", "N", &kln, &jw, &jw, &c_b15, &z__[krow + kwtop * + z_dim1], ldz, &v[v_offset], ldv, &c_b29, &wv[ + wv_offset], ldwv); + dlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + + kwtop * z_dim1], ldz); +/* L90: */ + } + } + } + +/* ==== Return the number of deflations ... ==== */ + + *nd = jw - *ns; + +/* + ==== ... and the number of shifts. (Subtracting + . INFQR from the spike length takes care + . of the case of a rare QR failure while + . calculating eigenvalues of the deflation + . window.) ==== +*/ + + *ns -= infqr; + +/* ==== Return optimal workspace. ==== */ + + work[1] = (doublereal) lwkopt; + +/* ==== End of DLAQR2 ==== */ + + return 0; +} /* dlaqr2_ */ + +/* Subroutine */ int dlaqr3_(logical *wantt, logical *wantz, integer *n, + integer *ktop, integer *kbot, integer *nw, doublereal *h__, integer * + ldh, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, + integer *ns, integer *nd, doublereal *sr, doublereal *si, doublereal * + v, integer *ldv, integer *nh, doublereal *t, integer *ldt, integer * + nv, doublereal *wv, integer *ldwv, doublereal *work, integer *lwork) +{ + /* System generated locals */ + integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, + wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2, d__3, d__4, d__5, d__6; + + /* Local variables */ + static integer i__, j, k; + static doublereal s, aa, bb, cc, dd, cs, sn; + static integer jw; + static doublereal evi, evk, foo; + static integer kln; + static doublereal tau, ulp; + static integer lwk1, lwk2, lwk3; + static doublereal beta; + static integer kend, kcol, info, nmin, ifst, ilst, ltop, krow; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *), dgemm_(char *, char *, integer *, integer * + , integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static logical bulge; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer infqr, kwtop; + extern /* Subroutine */ int dlanv2_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *), dlaqr4_( + logical *, logical *, integer *, integer *, integer *, doublereal + *, integer *, doublereal *, doublereal *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *, integer *), + dlabad_(doublereal *, doublereal *); + + extern /* Subroutine */ int dgehrd_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + integer *), dlarfg_(integer *, doublereal *, doublereal *, + integer *, doublereal *), dlahqr_(logical *, logical *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + integer *), dlacpy_(char *, integer *, integer *, doublereal *, + integer *, doublereal *, integer *); + static doublereal safmin; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static doublereal safmax; + extern /* Subroutine */ int dlaset_(char *, integer *, integer *, + doublereal *, doublereal *, doublereal *, integer *), + dtrexc_(char *, integer *, doublereal *, integer *, doublereal *, + integer *, integer *, integer *, doublereal *, integer *), + dormhr_(char *, char *, integer *, integer *, integer *, integer + *, doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *, integer *); + static logical sorted; + static doublereal smlnum; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + -- June 2010 -- + + + ****************************************************************** + Aggressive early deflation: + + This subroutine accepts as input an upper Hessenberg matrix + H and performs an orthogonal similarity transformation + designed to detect and deflate fully converged eigenvalues from + a trailing principal submatrix. On output H has been over- + written by a new Hessenberg matrix that is a perturbation of + an orthogonal similarity transformation of H. It is to be + hoped that the final version of H has many zero subdiagonal + entries. + + ****************************************************************** + WANTT (input) LOGICAL + If .TRUE., then the Hessenberg matrix H is fully updated + so that the quasi-triangular Schur factor may be + computed (in cooperation with the calling subroutine). + If .FALSE., then only enough of H is updated to preserve + the eigenvalues. + + WANTZ (input) LOGICAL + If .TRUE., then the orthogonal matrix Z is updated so + so that the orthogonal Schur factor may be computed + (in cooperation with the calling subroutine). + If .FALSE., then Z is not referenced. + + N (input) INTEGER + The order of the matrix H and (if WANTZ is .TRUE.) the + order of the orthogonal matrix Z. + + KTOP (input) INTEGER + It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0. + KBOT and KTOP together determine an isolated block + along the diagonal of the Hessenberg matrix. + + KBOT (input) INTEGER + It is assumed without a check that either + KBOT = N or H(KBOT+1,KBOT)=0. KBOT and KTOP together + determine an isolated block along the diagonal of the + Hessenberg matrix. + + NW (input) INTEGER + Deflation window size. 1 .LE. NW .LE. (KBOT-KTOP+1). + + H (input/output) DOUBLE PRECISION array, dimension (LDH,N) + On input the initial N-by-N section of H stores the + Hessenberg matrix undergoing aggressive early deflation. + On output H has been transformed by an orthogonal + similarity transformation, perturbed, and the returned + to Hessenberg form that (it is to be hoped) has some + zero subdiagonal entries. + + LDH (input) integer + Leading dimension of H just as declared in the calling + subroutine. N .LE. LDH + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N. + + Z (input/output) DOUBLE PRECISION array, dimension (LDZ,N) + IF WANTZ is .TRUE., then on output, the orthogonal + similarity transformation mentioned above has been + accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ is .FALSE., then Z is unreferenced. + + LDZ (input) integer + The leading dimension of Z just as declared in the + calling subroutine. 1 .LE. LDZ. + + NS (output) integer + The number of unconverged (ie approximate) eigenvalues + returned in SR and SI that may be used as shifts by the + calling subroutine. + + ND (output) integer + The number of converged eigenvalues uncovered by this + subroutine. + + SR (output) DOUBLE PRECISION array, dimension (KBOT) + SI (output) DOUBLE PRECISION array, dimension (KBOT) + On output, the real and imaginary parts of approximate + eigenvalues that may be used for shifts are stored in + SR(KBOT-ND-NS+1) through SR(KBOT-ND) and + SI(KBOT-ND-NS+1) through SI(KBOT-ND), respectively. + The real and imaginary parts of converged eigenvalues + are stored in SR(KBOT-ND+1) through SR(KBOT) and + SI(KBOT-ND+1) through SI(KBOT), respectively. + + V (workspace) DOUBLE PRECISION array, dimension (LDV,NW) + An NW-by-NW work array. + + LDV (input) integer scalar + The leading dimension of V just as declared in the + calling subroutine. NW .LE. LDV + + NH (input) integer scalar + The number of columns of T. NH.GE.NW. + + T (workspace) DOUBLE PRECISION array, dimension (LDT,NW) + + LDT (input) integer + The leading dimension of T just as declared in the + calling subroutine. NW .LE. LDT + + NV (input) integer + The number of rows of work array WV available for + workspace. NV.GE.NW. + + WV (workspace) DOUBLE PRECISION array, dimension (LDWV,NW) + + LDWV (input) integer + The leading dimension of W just as declared in the + calling subroutine. NW .LE. LDV + + WORK (workspace) DOUBLE PRECISION array, dimension (LWORK) + On exit, WORK(1) is set to an estimate of the optimal value + of LWORK for the given values of N, NW, KTOP and KBOT. + + LWORK (input) integer + The dimension of the work array WORK. LWORK = 2*NW + suffices, but greater efficiency may result from larger + values of LWORK. + + If LWORK = -1, then a workspace query is assumed; DLAQR3 + only estimates the optimal workspace size for the given + values of N, NW, KTOP and KBOT. The estimate is returned + in WORK(1). No error message related to LWORK is issued + by XERBLA. Neither H nor Z are accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + + ==== Estimate optimal workspace. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --sr; + --si; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + --work; + + /* Function Body */ +/* Computing MIN */ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + if (jw <= 2) { + lwkopt = 1; + } else { + +/* ==== Workspace query call to DGEHRD ==== */ + + i__1 = jw - 1; + dgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], & + c_n1, &info); + lwk1 = (integer) work[1]; + +/* ==== Workspace query call to DORMHR ==== */ + + i__1 = jw - 1; + dormhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[1], &c_n1, &info); + lwk2 = (integer) work[1]; + +/* ==== Workspace query call to DLAQR4 ==== */ + + dlaqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[1], + &si[1], &c__1, &jw, &v[v_offset], ldv, &work[1], &c_n1, & + infqr); + lwk3 = (integer) work[1]; + +/* + ==== Optimal workspace ==== + + Computing MAX +*/ + i__1 = jw + max(lwk1,lwk2); + lwkopt = max(i__1,lwk3); + } + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + work[1] = (doublereal) lwkopt; + return 0; + } + +/* + ==== Nothing to do ... + ... for an empty active block ... ==== +*/ + *ns = 0; + *nd = 0; + work[1] = 1.; + if (*ktop > *kbot) { + return 0; + } +/* ... nor for an empty deflation window. ==== */ + if (*nw < 1) { + return 0; + } + +/* ==== Machine constants ==== */ + + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + dlabad_(&safmin, &safmax); + ulp = PRECISION; + smlnum = safmin * ((doublereal) (*n) / ulp); + +/* + ==== Setup deflation window ==== + + Computing MIN +*/ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + kwtop = *kbot - jw + 1; + if (kwtop == *ktop) { + s = 0.; + } else { + s = h__[kwtop + (kwtop - 1) * h_dim1]; + } + + if (*kbot == kwtop) { + +/* ==== 1-by-1 deflation window: not much to do ==== */ + + sr[kwtop] = h__[kwtop + kwtop * h_dim1]; + si[kwtop] = 0.; + *ns = 1; + *nd = 0; +/* Computing MAX */ + d__2 = smlnum, d__3 = ulp * (d__1 = h__[kwtop + kwtop * h_dim1], abs( + d__1)); + if (abs(s) <= max(d__2,d__3)) { + *ns = 0; + *nd = 1; + if (kwtop > *ktop) { + h__[kwtop + (kwtop - 1) * h_dim1] = 0.; + } + } + work[1] = 1.; + return 0; + } + +/* + ==== Convert to spike-triangular form. (In case of a + . rare QR failure, this routine continues to do + . aggressive early deflation using that part of + . the deflation window that converged using INFQR + . here and there to keep track.) ==== +*/ + + dlacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], + ldt); + i__1 = jw - 1; + i__2 = *ldh + 1; + i__3 = *ldt + 1; + dcopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], & + i__3); + + dlaset_("A", &jw, &jw, &c_b29, &c_b15, &v[v_offset], ldv); + nmin = ilaenv_(&c__12, "DLAQR3", "SV", &jw, &c__1, &jw, lwork, (ftnlen)6, + (ftnlen)2); + if (jw > nmin) { + dlaqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[ + kwtop], &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &work[1], + lwork, &infqr); + } else { + dlahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[ + kwtop], &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &infqr); + } + +/* ==== DTREXC needs a clean margin near the diagonal ==== */ + + i__1 = jw - 3; + for (j = 1; j <= i__1; ++j) { + t[j + 2 + j * t_dim1] = 0.; + t[j + 3 + j * t_dim1] = 0.; +/* L10: */ + } + if (jw > 2) { + t[jw + (jw - 2) * t_dim1] = 0.; + } + +/* ==== Deflation detection loop ==== */ + + *ns = jw; + ilst = infqr + 1; +L20: + if (ilst <= *ns) { + if (*ns == 1) { + bulge = FALSE_; + } else { + bulge = t[*ns + (*ns - 1) * t_dim1] != 0.; + } + +/* ==== Small spike tip test for deflation ==== */ + + if (! bulge) { + +/* ==== Real eigenvalue ==== */ + + foo = (d__1 = t[*ns + *ns * t_dim1], abs(d__1)); + if (foo == 0.) { + foo = abs(s); + } +/* Computing MAX */ + d__2 = smlnum, d__3 = ulp * foo; + if ((d__1 = s * v[*ns * v_dim1 + 1], abs(d__1)) <= max(d__2,d__3)) + { + +/* ==== Deflatable ==== */ + + --(*ns); + } else { + +/* + ==== Undeflatable. Move it up out of the way. + . (DTREXC can not fail in this case.) ==== +*/ + + ifst = *ns; + dtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + ++ilst; + } + } else { + +/* ==== Complex conjugate pair ==== */ + + foo = (d__3 = t[*ns + *ns * t_dim1], abs(d__3)) + sqrt((d__1 = t[* + ns + (*ns - 1) * t_dim1], abs(d__1))) * sqrt((d__2 = t[* + ns - 1 + *ns * t_dim1], abs(d__2))); + if (foo == 0.) { + foo = abs(s); + } +/* Computing MAX */ + d__3 = (d__1 = s * v[*ns * v_dim1 + 1], abs(d__1)), d__4 = (d__2 = + s * v[(*ns - 1) * v_dim1 + 1], abs(d__2)); +/* Computing MAX */ + d__5 = smlnum, d__6 = ulp * foo; + if (max(d__3,d__4) <= max(d__5,d__6)) { + +/* ==== Deflatable ==== */ + + *ns += -2; + } else { + +/* + ==== Undeflatable. Move them up out of the way. + . Fortunately, DTREXC does the right thing with + . ILST in case of a rare exchange failure. ==== +*/ + + ifst = *ns; + dtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + ilst += 2; + } + } + +/* ==== End deflation detection loop ==== */ + + goto L20; + } + +/* ==== Return to Hessenberg form ==== */ + + if (*ns == 0) { + s = 0.; + } + + if (*ns < jw) { + +/* + ==== sorting diagonal blocks of T improves accuracy for + . graded matrices. Bubble sort deals well with + . exchange failures. ==== +*/ + + sorted = FALSE_; + i__ = *ns + 1; +L30: + if (sorted) { + goto L50; + } + sorted = TRUE_; + + kend = i__ - 1; + i__ = infqr + 1; + if (i__ == *ns) { + k = i__ + 1; + } else if (t[i__ + 1 + i__ * t_dim1] == 0.) { + k = i__ + 1; + } else { + k = i__ + 2; + } +L40: + if (k <= kend) { + if (k == i__ + 1) { + evi = (d__1 = t[i__ + i__ * t_dim1], abs(d__1)); + } else { + evi = (d__3 = t[i__ + i__ * t_dim1], abs(d__3)) + sqrt((d__1 = + t[i__ + 1 + i__ * t_dim1], abs(d__1))) * sqrt((d__2 = + t[i__ + (i__ + 1) * t_dim1], abs(d__2))); + } + + if (k == kend) { + evk = (d__1 = t[k + k * t_dim1], abs(d__1)); + } else if (t[k + 1 + k * t_dim1] == 0.) { + evk = (d__1 = t[k + k * t_dim1], abs(d__1)); + } else { + evk = (d__3 = t[k + k * t_dim1], abs(d__3)) + sqrt((d__1 = t[ + k + 1 + k * t_dim1], abs(d__1))) * sqrt((d__2 = t[k + + (k + 1) * t_dim1], abs(d__2))); + } + + if (evi >= evk) { + i__ = k; + } else { + sorted = FALSE_; + ifst = i__; + ilst = k; + dtrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + if (info == 0) { + i__ = ilst; + } else { + i__ = k; + } + } + if (i__ == kend) { + k = i__ + 1; + } else if (t[i__ + 1 + i__ * t_dim1] == 0.) { + k = i__ + 1; + } else { + k = i__ + 2; + } + goto L40; + } + goto L30; +L50: + ; + } + +/* ==== Restore shift/eigenvalue array from T ==== */ + + i__ = jw; +L60: + if (i__ >= infqr + 1) { + if (i__ == infqr + 1) { + sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1]; + si[kwtop + i__ - 1] = 0.; + --i__; + } else if (t[i__ + (i__ - 1) * t_dim1] == 0.) { + sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1]; + si[kwtop + i__ - 1] = 0.; + --i__; + } else { + aa = t[i__ - 1 + (i__ - 1) * t_dim1]; + cc = t[i__ + (i__ - 1) * t_dim1]; + bb = t[i__ - 1 + i__ * t_dim1]; + dd = t[i__ + i__ * t_dim1]; + dlanv2_(&aa, &bb, &cc, &dd, &sr[kwtop + i__ - 2], &si[kwtop + i__ + - 2], &sr[kwtop + i__ - 1], &si[kwtop + i__ - 1], &cs, & + sn); + i__ += -2; + } + goto L60; + } + + if (*ns < jw || s == 0.) { + if (*ns > 1 && s != 0.) { + +/* ==== Reflect spike back into lower triangle ==== */ + + dcopy_(ns, &v[v_offset], ldv, &work[1], &c__1); + beta = work[1]; + dlarfg_(ns, &beta, &work[2], &c__1, &tau); + work[1] = 1.; + + i__1 = jw - 2; + i__2 = jw - 2; + dlaset_("L", &i__1, &i__2, &c_b29, &c_b29, &t[t_dim1 + 3], ldt); + + dlarf_("L", ns, &jw, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + dlarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + dlarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, & + work[jw + 1]); + + i__1 = *lwork - jw; + dgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1] + , &i__1, &info); + } + +/* ==== Copy updated reduced window into place ==== */ + + if (kwtop > 1) { + h__[kwtop + (kwtop - 1) * h_dim1] = s * v[v_dim1 + 1]; + } + dlacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1] + , ldh); + i__1 = jw - 1; + i__2 = *ldt + 1; + i__3 = *ldh + 1; + dcopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1], + &i__3); + +/* + ==== Accumulate orthogonal matrix in order update + . H and Z, if requested. ==== +*/ + + if (*ns > 1 && s != 0.) { + i__1 = *lwork - jw; + dormhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[jw + 1], &i__1, &info); + } + +/* ==== Update vertical slab in H ==== */ + + if (*wantt) { + ltop = 1; + } else { + ltop = *ktop; + } + i__1 = kwtop - 1; + i__2 = *nv; + for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = kwtop - krow; + kln = min(i__3,i__4); + dgemm_("N", "N", &kln, &jw, &jw, &c_b15, &h__[krow + kwtop * + h_dim1], ldh, &v[v_offset], ldv, &c_b29, &wv[wv_offset], + ldwv); + dlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * + h_dim1], ldh); +/* L70: */ + } + +/* ==== Update horizontal slab in H ==== */ + + if (*wantt) { + i__2 = *n; + i__1 = *nh; + for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; + kcol += i__1) { +/* Computing MIN */ + i__3 = *nh, i__4 = *n - kcol + 1; + kln = min(i__3,i__4); + dgemm_("C", "N", &jw, &kln, &jw, &c_b15, &v[v_offset], ldv, & + h__[kwtop + kcol * h_dim1], ldh, &c_b29, &t[t_offset], + ldt); + dlacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol * + h_dim1], ldh); +/* L80: */ + } + } + +/* ==== Update vertical slab in Z ==== */ + + if (*wantz) { + i__1 = *ihiz; + i__2 = *nv; + for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = *ihiz - krow + 1; + kln = min(i__3,i__4); + dgemm_("N", "N", &kln, &jw, &jw, &c_b15, &z__[krow + kwtop * + z_dim1], ldz, &v[v_offset], ldv, &c_b29, &wv[ + wv_offset], ldwv); + dlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + + kwtop * z_dim1], ldz); +/* L90: */ + } + } + } + +/* ==== Return the number of deflations ... ==== */ + + *nd = jw - *ns; + +/* + ==== ... and the number of shifts. (Subtracting + . INFQR from the spike length takes care + . of the case of a rare QR failure while + . calculating eigenvalues of the deflation + . window.) ==== +*/ + + *ns -= infqr; + +/* ==== Return optimal workspace. ==== */ + + work[1] = (doublereal) lwkopt; + +/* ==== End of DLAQR3 ==== */ + + return 0; +} /* dlaqr3_ */ + +/* Subroutine */ int dlaqr4_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal + *wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, + integer *ldz, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1, d__2, d__3, d__4; + + /* Local variables */ + static integer i__, k; + static doublereal aa, bb, cc, dd; + static integer ld; + static doublereal cs; + static integer nh, it, ks, kt; + static doublereal sn; + static integer ku, kv, ls, ns; + static doublereal ss; + static integer nw, inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, + kbot, nmin; + static doublereal swap; + static integer ktop; + static doublereal zdum[1] /* was [1][1] */; + static integer kacc22, itmax, nsmax, nwmax, kwtop; + extern /* Subroutine */ int dlaqr2_(logical *, logical *, integer *, + integer *, integer *, integer *, doublereal *, integer *, integer + *, integer *, doublereal *, integer *, integer *, integer *, + doublereal *, doublereal *, doublereal *, integer *, integer *, + doublereal *, integer *, integer *, doublereal *, integer *, + doublereal *, integer *), dlanv2_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *), dlaqr5_( + logical *, logical *, integer *, integer *, integer *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + integer *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *, doublereal *, integer *); + static integer nibble; + extern /* Subroutine */ int dlahqr_(logical *, logical *, integer *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + integer *), dlacpy_(char *, integer *, integer *, doublereal *, + integer *, doublereal *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static char jbcmpz[2]; + static integer nwupbd; + static logical sorted; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + This subroutine implements one level of recursion for DLAQR0. + It is a complete implementation of the small bulge multi-shift + QR algorithm. It may be called by DLAQR0 and, for large enough + deflation window size, it may be called by DLAQR3. This + subroutine is identical to DLAQR0 except that it calls DLAQR2 + instead of DLAQR3. + + Purpose + ======= + + DLAQR4 computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**T, where T is an upper quasi-triangular matrix (the + Schur form), and Z is the orthogonal matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input orthogonal + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the orthogonal matrix Q: A = Q*H*Q**T = (QZ)*T*(QZ)**T. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1, + H(ILO,ILO-1) is zero. ILO and IHI are normally set by a + previous call to DGEBAL, and then passed to DGEHRD when the + matrix output by DGEBAL is reduced to Hessenberg form. + Otherwise, ILO and IHI should be set to 1 and N, + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) DOUBLE PRECISION array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and WANTT is .TRUE., then H contains + the upper quasi-triangular matrix T from the Schur + decomposition (the Schur form); 2-by-2 diagonal blocks + (corresponding to complex conjugate pairs of eigenvalues) + are returned in standard form, with H(i,i) = H(i+1,i+1) + and H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and WANTT is + .FALSE., then the contents of H are unspecified on exit. + (The output value of H when INFO.GT.0 is given under the + description of INFO below.) + + This subroutine may explicitly set H(i,j) = 0 for i.GT.j and + j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + WR (output) DOUBLE PRECISION array, dimension (IHI) + WI (output) DOUBLE PRECISION array, dimension (IHI) + The real and imaginary parts, respectively, of the computed + eigenvalues of H(ILO:IHI,ILO:IHI) are stored in WR(ILO:IHI) + and WI(ILO:IHI). If two eigenvalues are computed as a + complex conjugate pair, they are stored in consecutive + elements of WR and WI, say the i-th and (i+1)th, with + WI(i) .GT. 0 and WI(i+1) .LT. 0. If WANTT is .TRUE., then + the eigenvalues are stored in the same order as on the + diagonal of the Schur form returned in H, with + WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 diagonal + block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and + WI(i+1) = -WI(i). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. + 1 .LE. ILOZ .LE. ILO; IHI .LE. IHIZ .LE. N. + + Z (input/output) DOUBLE PRECISION array, dimension (LDZ,IHI) + If WANTZ is .FALSE., then Z is not referenced. + If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is + replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the + orthogonal Schur factor of H(ILO:IHI,ILO:IHI). + (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if WANTZ is .TRUE. + then LDZ.GE.MAX(1,IHIZ). Otherwize, LDZ.GE.1. + + WORK (workspace/output) DOUBLE PRECISION array, dimension LWORK + On exit, if LWORK = -1, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient, but LWORK typically as large as 6*N may + be required for optimal performance. A workspace query + to determine the optimal workspace size is recommended. + + If LWORK = -1, then DLAQR4 does a workspace query. + In this case, DLAQR4 checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, DLAQR4 failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and WANT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is an orthogonal matrix. The final + value of H is upper Hessenberg and quasi-triangular + in rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + + (final value of Z(ILO:IHI,ILOZ:IHIZ) + = (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U + + where U is the orthogonal matrix in (*) (regard- + less of the value of WANTT.) + + If INFO .GT. 0 and WANTZ is .FALSE., then Z is not + accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . DLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== Exceptional deflation windows: try to cure rare + . slow convergence by varying the size of the + . deflation window after KEXNW iterations. ==== + + ==== Exceptional shifts: try to cure rare slow convergence + . with ad-hoc exceptional shifts every KEXSH iterations. + . ==== + + ==== The constants WILK1 and WILK2 are used to form the + . exceptional shifts. ==== +*/ + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --wr; + --wi; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + +/* ==== Quick return for N = 0: nothing to do. ==== */ + + if (*n == 0) { + work[1] = 1.; + return 0; + } + + if (*n <= 11) { + +/* ==== Tiny matrices must use DLAHQR. ==== */ + + lwkopt = 1; + if (*lwork != -1) { + dlahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], & + wi[1], iloz, ihiz, &z__[z_offset], ldz, info); + } + } else { + +/* + ==== Use small bulge multi-shift QR with aggressive early + . deflation on larger-than-tiny matrices. ==== + + ==== Hope for the best. ==== +*/ + + *info = 0; + +/* ==== Set up job flags for ILAENV. ==== */ + + if (*wantt) { + *(unsigned char *)jbcmpz = 'S'; + } else { + *(unsigned char *)jbcmpz = 'E'; + } + if (*wantz) { + *(unsigned char *)&jbcmpz[1] = 'V'; + } else { + *(unsigned char *)&jbcmpz[1] = 'N'; + } + +/* + ==== NWR = recommended deflation window size. At this + . point, N .GT. NTINY = 11, so there is enough + . subdiagonal workspace for NWR.GE.2 as required. + . (In fact, there is enough subdiagonal space for + . NWR.GE.3.) ==== +*/ + + nwr = ilaenv_(&c__13, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nwr = max(2,nwr); +/* Computing MIN */ + i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2); + nwr = min(i__1,nwr); + +/* + ==== NSR = recommended number of simultaneous shifts. + . At this point N .GT. NTINY = 11, so there is at + . enough subdiagonal workspace for NSR to be even + . and greater than or equal to two as required. ==== +*/ + + nsr = ilaenv_(&c__15, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); +/* Computing MIN */ + i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - + *ilo; + nsr = min(i__1,i__2); +/* Computing MAX */ + i__1 = 2, i__2 = nsr - nsr % 2; + nsr = max(i__1,i__2); + +/* + ==== Estimate optimal workspace ==== + + ==== Workspace query call to DLAQR2 ==== +*/ + + i__1 = nwr + 1; + dlaqr2_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, + ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], &h__[ + h_offset], ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], + ldh, &work[1], &c_n1); + +/* + ==== Optimal workspace = MAX(DLAQR5, DLAQR2) ==== + + Computing MAX +*/ + i__1 = nsr * 3 / 2, i__2 = (integer) work[1]; + lwkopt = max(i__1,i__2); + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + work[1] = (doublereal) lwkopt; + return 0; + } + +/* ==== DLAHQR/DLAQR0 crossover point ==== */ + + nmin = ilaenv_(&c__12, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen) + 6, (ftnlen)2); + nmin = max(11,nmin); + +/* ==== Nibble crossover point ==== */ + + nibble = ilaenv_(&c__14, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + nibble = max(0,nibble); + +/* + ==== Accumulate reflections during ttswp? Use block + . 2-by-2 structure during matrix-matrix multiply? ==== +*/ + + kacc22 = ilaenv_(&c__16, "DLAQR4", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + kacc22 = max(0,kacc22); + kacc22 = min(2,kacc22); + +/* + ==== NWMAX = the largest possible deflation window for + . which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n - 1) / 3, i__2 = *lwork / 2; + nwmax = min(i__1,i__2); + nw = nwmax; + +/* + ==== NSMAX = the Largest number of simultaneous shifts + . for which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3; + nsmax = min(i__1,i__2); + nsmax -= nsmax % 2; + +/* ==== NDFL: an iteration count restarted at deflation. ==== */ + + ndfl = 1; + +/* + ==== ITMAX = iteration limit ==== + + Computing MAX +*/ + i__1 = 10, i__2 = *ihi - *ilo + 1; + itmax = max(i__1,i__2) * 30; + +/* ==== Last row and column in the active block ==== */ + + kbot = *ihi; + +/* ==== Main Loop ==== */ + + i__1 = itmax; + for (it = 1; it <= i__1; ++it) { + +/* ==== Done when KBOT falls below ILO ==== */ + + if (kbot < *ilo) { + goto L90; + } + +/* ==== Locate active block ==== */ + + i__2 = *ilo + 1; + for (k = kbot; k >= i__2; --k) { + if (h__[k + (k - 1) * h_dim1] == 0.) { + goto L20; + } +/* L10: */ + } + k = *ilo; +L20: + ktop = k; + +/* + ==== Select deflation window size: + . Typical Case: + . If possible and advisable, nibble the entire + . active block. If not, use size MIN(NWR,NWMAX) + . or MIN(NWR+1,NWMAX) depending upon which has + . the smaller corresponding subdiagonal entry + . (a heuristic). + . + . Exceptional Case: + . If there have been no deflations in KEXNW or + . more iterations, then vary the deflation window + . size. At first, because, larger windows are, + . in general, more powerful than smaller ones, + . rapidly increase the window to the maximum possible. + . Then, gradually reduce the window size. ==== +*/ + + nh = kbot - ktop + 1; + nwupbd = min(nh,nwmax); + if (ndfl < 5) { + nw = min(nwupbd,nwr); + } else { +/* Computing MIN */ + i__2 = nwupbd, i__3 = nw << 1; + nw = min(i__2,i__3); + } + if (nw < nwmax) { + if (nw >= nh - 1) { + nw = nh; + } else { + kwtop = kbot - nw + 1; + if ((d__1 = h__[kwtop + (kwtop - 1) * h_dim1], abs(d__1)) + > (d__2 = h__[kwtop - 1 + (kwtop - 2) * h_dim1], + abs(d__2))) { + ++nw; + } + } + } + if (ndfl < 5) { + ndec = -1; + } else if (ndec >= 0 || nw >= nwupbd) { + ++ndec; + if (nw - ndec < 2) { + ndec = 0; + } + nw -= ndec; + } + +/* + ==== Aggressive early deflation: + . split workspace under the subdiagonal into + . - an nw-by-nw work array V in the lower + . left-hand-corner, + . - an NW-by-at-least-NW-but-more-is-better + . (NW-by-NHO) horizontal work array along + . the bottom edge, + . - an at-least-NW-but-more-is-better (NHV-by-NW) + . vertical work array along the left-hand-edge. + . ==== +*/ + + kv = *n - nw + 1; + kt = nw + 1; + nho = *n - nw - 1 - kt + 1; + kwv = nw + 2; + nve = *n - nw - kwv + 1; + +/* ==== Aggressive early deflation ==== */ + + dlaqr2_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, + iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], + &h__[kv + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], + ldh, &nve, &h__[kwv + h_dim1], ldh, &work[1], lwork); + +/* ==== Adjust KBOT accounting for new deflations. ==== */ + + kbot -= ld; + +/* ==== KS points to the shifts. ==== */ + + ks = kbot - ls + 1; + +/* + ==== Skip an expensive QR sweep if there is a (partly + . heuristic) reason to expect that many eigenvalues + . will deflate without it. Here, the QR sweep is + . skipped if many eigenvalues have just been deflated + . or if the remaining active block is small. +*/ + + if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min( + nmin,nwmax)) { + +/* + ==== NS = nominal number of simultaneous shifts. + . This may be lowered (slightly) if DLAQR2 + . did not provide that many shifts. ==== + + Computing MIN + Computing MAX +*/ + i__4 = 2, i__5 = kbot - ktop; + i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5); + ns = min(i__2,i__3); + ns -= ns % 2; + +/* + ==== If there have been no deflations + . in a multiple of KEXSH iterations, + . then try exceptional shifts. + . Otherwise use shifts provided by + . DLAQR2 above or from the eigenvalues + . of a trailing principal submatrix. ==== +*/ + + if (ndfl % 6 == 0) { + ks = kbot - ns + 1; +/* Computing MAX */ + i__3 = ks + 1, i__4 = ktop + 2; + i__2 = max(i__3,i__4); + for (i__ = kbot; i__ >= i__2; i__ += -2) { + ss = (d__1 = h__[i__ + (i__ - 1) * h_dim1], abs(d__1)) + + (d__2 = h__[i__ - 1 + (i__ - 2) * h_dim1], + abs(d__2)); + aa = ss * .75 + h__[i__ + i__ * h_dim1]; + bb = ss; + cc = ss * -.4375; + dd = aa; + dlanv2_(&aa, &bb, &cc, &dd, &wr[i__ - 1], &wi[i__ - 1] + , &wr[i__], &wi[i__], &cs, &sn); +/* L30: */ + } + if (ks == ktop) { + wr[ks + 1] = h__[ks + 1 + (ks + 1) * h_dim1]; + wi[ks + 1] = 0.; + wr[ks] = wr[ks + 1]; + wi[ks] = wi[ks + 1]; + } + } else { + +/* + ==== Got NS/2 or fewer shifts? Use DLAHQR + . on a trailing principal submatrix to + . get more. (Since NS.LE.NSMAX.LE.(N+6)/9, + . there is enough space below the subdiagonal + . to fit an NS-by-NS scratch array.) ==== +*/ + + if (kbot - ks + 1 <= ns / 2) { + ks = kbot - ns + 1; + kt = *n - ns + 1; + dlacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, & + h__[kt + h_dim1], ldh); + dlahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[kt + + h_dim1], ldh, &wr[ks], &wi[ks], &c__1, & + c__1, zdum, &c__1, &inf); + ks += inf; + +/* + ==== In case of a rare QR failure use + . eigenvalues of the trailing 2-by-2 + . principal submatrix. ==== +*/ + + if (ks >= kbot) { + aa = h__[kbot - 1 + (kbot - 1) * h_dim1]; + cc = h__[kbot + (kbot - 1) * h_dim1]; + bb = h__[kbot - 1 + kbot * h_dim1]; + dd = h__[kbot + kbot * h_dim1]; + dlanv2_(&aa, &bb, &cc, &dd, &wr[kbot - 1], &wi[ + kbot - 1], &wr[kbot], &wi[kbot], &cs, &sn) + ; + ks = kbot - 1; + } + } + + if (kbot - ks + 1 > ns) { + +/* + ==== Sort the shifts (Helps a little) + . Bubble sort keeps complex conjugate + . pairs together. ==== +*/ + + sorted = FALSE_; + i__2 = ks + 1; + for (k = kbot; k >= i__2; --k) { + if (sorted) { + goto L60; + } + sorted = TRUE_; + i__3 = k - 1; + for (i__ = ks; i__ <= i__3; ++i__) { + if ((d__1 = wr[i__], abs(d__1)) + (d__2 = wi[ + i__], abs(d__2)) < (d__3 = wr[i__ + 1] + , abs(d__3)) + (d__4 = wi[i__ + 1], + abs(d__4))) { + sorted = FALSE_; + + swap = wr[i__]; + wr[i__] = wr[i__ + 1]; + wr[i__ + 1] = swap; + + swap = wi[i__]; + wi[i__] = wi[i__ + 1]; + wi[i__ + 1] = swap; + } +/* L40: */ + } +/* L50: */ + } +L60: + ; + } + +/* + ==== Shuffle shifts into pairs of real shifts + . and pairs of complex conjugate shifts + . assuming complex conjugate shifts are + . already adjacent to one another. (Yes, + . they are.) ==== +*/ + + i__2 = ks + 2; + for (i__ = kbot; i__ >= i__2; i__ += -2) { + if (wi[i__] != -wi[i__ - 1]) { + + swap = wr[i__]; + wr[i__] = wr[i__ - 1]; + wr[i__ - 1] = wr[i__ - 2]; + wr[i__ - 2] = swap; + + swap = wi[i__]; + wi[i__] = wi[i__ - 1]; + wi[i__ - 1] = wi[i__ - 2]; + wi[i__ - 2] = swap; + } +/* L70: */ + } + } + +/* + ==== If there are only two shifts and both are + . real, then use only one. ==== +*/ + + if (kbot - ks + 1 == 2) { + if (wi[kbot] == 0.) { + if ((d__1 = wr[kbot] - h__[kbot + kbot * h_dim1], abs( + d__1)) < (d__2 = wr[kbot - 1] - h__[kbot + + kbot * h_dim1], abs(d__2))) { + wr[kbot - 1] = wr[kbot]; + } else { + wr[kbot] = wr[kbot - 1]; + } + } + } + +/* + ==== Use up to NS of the the smallest magnatiude + . shifts. If there aren't NS shifts available, + . then use them all, possibly dropping one to + . make the number of shifts even. ==== + + Computing MIN +*/ + i__2 = ns, i__3 = kbot - ks + 1; + ns = min(i__2,i__3); + ns -= ns % 2; + ks = kbot - ns + 1; + +/* + ==== Small-bulge multi-shift QR sweep: + . split workspace under the subdiagonal into + . - a KDU-by-KDU work array U in the lower + . left-hand-corner, + . - a KDU-by-at-least-KDU-but-more-is-better + . (KDU-by-NHo) horizontal work array WH along + . the bottom edge, + . - and an at-least-KDU-but-more-is-better-by-KDU + . (NVE-by-KDU) vertical work WV arrow along + . the left-hand-edge. ==== +*/ + + kdu = ns * 3 - 3; + ku = *n - kdu + 1; + kwh = kdu + 1; + nho = *n - kdu - 3 - (kdu + 1) + 1; + kwv = kdu + 4; + nve = *n - kdu - kwv + 1; + +/* ==== Small-bulge multi-shift QR sweep ==== */ + + dlaqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &wr[ks], + &wi[ks], &h__[h_offset], ldh, iloz, ihiz, &z__[ + z_offset], ldz, &work[1], &c__3, &h__[ku + h_dim1], + ldh, &nve, &h__[kwv + h_dim1], ldh, &nho, &h__[ku + + kwh * h_dim1], ldh); + } + +/* ==== Note progress (or the lack of it). ==== */ + + if (ld > 0) { + ndfl = 1; + } else { + ++ndfl; + } + +/* + ==== End of main loop ==== + L80: +*/ + } + +/* + ==== Iteration limit exceeded. Set INFO to show where + . the problem occurred and exit. ==== +*/ + + *info = kbot; +L90: + ; + } + +/* ==== Return the optimal value of LWORK. ==== */ + + work[1] = (doublereal) lwkopt; + +/* ==== End of DLAQR4 ==== */ + + return 0; +} /* dlaqr4_ */ + +/* Subroutine */ int dlaqr5_(logical *wantt, logical *wantz, integer *kacc22, + integer *n, integer *ktop, integer *kbot, integer *nshfts, doublereal + *sr, doublereal *si, doublereal *h__, integer *ldh, integer *iloz, + integer *ihiz, doublereal *z__, integer *ldz, doublereal *v, integer * + ldv, doublereal *u, integer *ldu, integer *nv, doublereal *wv, + integer *ldwv, integer *nh, doublereal *wh, integer *ldwh) +{ + /* System generated locals */ + integer h_dim1, h_offset, u_dim1, u_offset, v_dim1, v_offset, wh_dim1, + wh_offset, wv_dim1, wv_offset, z_dim1, z_offset, i__1, i__2, i__3, + i__4, i__5, i__6, i__7; + doublereal d__1, d__2, d__3, d__4, d__5; + + /* Local variables */ + static integer i__, j, k, m, i2, j2, i4, j4, k1; + static doublereal h11, h12, h21, h22; + static integer m22, ns, nu; + static doublereal vt[3], scl; + static integer kdu, kms; + static doublereal ulp; + static integer knz, kzs; + static doublereal tst1, tst2, beta; + static logical blk22, bmp22; + static integer mend, jcol, jlen, jbot, mbot; + static doublereal swap; + static integer jtop, jrow, mtop; + static doublereal alpha; + static logical accum; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer ndcol, incol, krcol, nbmps; + extern /* Subroutine */ int dtrmm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *), dlaqr1_( + integer *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *), dlabad_(doublereal *, + doublereal *); + + extern /* Subroutine */ int dlarfg_(integer *, doublereal *, doublereal *, + integer *, doublereal *), dlacpy_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *); + static doublereal safmin; + extern /* Subroutine */ int dlaset_(char *, integer *, integer *, + doublereal *, doublereal *, doublereal *, integer *); + static doublereal safmax, refsum; + static integer mstart; + static doublereal smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + This auxiliary subroutine called by DLAQR0 performs a + single small-bulge multi-shift QR sweep. + + WANTT (input) logical scalar + WANTT = .true. if the quasi-triangular Schur factor + is being computed. WANTT is set to .false. otherwise. + + WANTZ (input) logical scalar + WANTZ = .true. if the orthogonal Schur factor is being + computed. WANTZ is set to .false. otherwise. + + KACC22 (input) integer with value 0, 1, or 2. + Specifies the computation mode of far-from-diagonal + orthogonal updates. + = 0: DLAQR5 does not accumulate reflections and does not + use matrix-matrix multiply to update far-from-diagonal + matrix entries. + = 1: DLAQR5 accumulates reflections and uses matrix-matrix + multiply to update the far-from-diagonal matrix entries. + = 2: DLAQR5 accumulates reflections, uses matrix-matrix + multiply to update the far-from-diagonal matrix entries, + and takes advantage of 2-by-2 block structure during + matrix multiplies. + + N (input) integer scalar + N is the order of the Hessenberg matrix H upon which this + subroutine operates. + + KTOP (input) integer scalar + KBOT (input) integer scalar + These are the first and last rows and columns of an + isolated diagonal block upon which the QR sweep is to be + applied. It is assumed without a check that + either KTOP = 1 or H(KTOP,KTOP-1) = 0 + and + either KBOT = N or H(KBOT+1,KBOT) = 0. + + NSHFTS (input) integer scalar + NSHFTS gives the number of simultaneous shifts. NSHFTS + must be positive and even. + + SR (input/output) DOUBLE PRECISION array of size (NSHFTS) + SI (input/output) DOUBLE PRECISION array of size (NSHFTS) + SR contains the real parts and SI contains the imaginary + parts of the NSHFTS shifts of origin that define the + multi-shift QR sweep. On output SR and SI may be + reordered. + + H (input/output) DOUBLE PRECISION array of size (LDH,N) + On input H contains a Hessenberg matrix. On output a + multi-shift QR sweep with shifts SR(J)+i*SI(J) is applied + to the isolated diagonal block in rows and columns KTOP + through KBOT. + + LDH (input) integer scalar + LDH is the leading dimension of H just as declared in the + calling procedure. LDH.GE.MAX(1,N). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N + + Z (input/output) DOUBLE PRECISION array of size (LDZ,IHI) + If WANTZ = .TRUE., then the QR Sweep orthogonal + similarity transformation is accumulated into + Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ = .FALSE., then Z is unreferenced. + + LDZ (input) integer scalar + LDA is the leading dimension of Z just as declared in + the calling procedure. LDZ.GE.N. + + V (workspace) DOUBLE PRECISION array of size (LDV,NSHFTS/2) + + LDV (input) integer scalar + LDV is the leading dimension of V as declared in the + calling procedure. LDV.GE.3. + + U (workspace) DOUBLE PRECISION array of size + (LDU,3*NSHFTS-3) + + LDU (input) integer scalar + LDU is the leading dimension of U just as declared in the + in the calling subroutine. LDU.GE.3*NSHFTS-3. + + NH (input) integer scalar + NH is the number of columns in array WH available for + workspace. NH.GE.1. + + WH (workspace) DOUBLE PRECISION array of size (LDWH,NH) + + LDWH (input) integer scalar + Leading dimension of WH just as declared in the + calling procedure. LDWH.GE.3*NSHFTS-3. + + NV (input) integer scalar + NV is the number of rows in WV agailable for workspace. + NV.GE.1. + + WV (workspace) DOUBLE PRECISION array of size + (LDWV,3*NSHFTS-3) + + LDWV (input) integer scalar + LDWV is the leading dimension of WV as declared in the + in the calling subroutine. LDWV.GE.NV. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + Reference: + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and + Level 3 Performance, SIAM Journal of Matrix Analysis, + volume 23, pages 929--947, 2002. + + ================================================================ + + + ==== If there are no shifts, then there is nothing to do. ==== +*/ + + /* Parameter adjustments */ + --sr; + --si; + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + wh_dim1 = *ldwh; + wh_offset = 1 + wh_dim1; + wh -= wh_offset; + + /* Function Body */ + if (*nshfts < 2) { + return 0; + } + +/* + ==== If the active block is empty or 1-by-1, then there + . is nothing to do. ==== +*/ + + if (*ktop >= *kbot) { + return 0; + } + +/* + ==== Shuffle shifts into pairs of real shifts and pairs + . of complex conjugate shifts assuming complex + . conjugate shifts are already adjacent to one + . another. ==== +*/ + + i__1 = *nshfts - 2; + for (i__ = 1; i__ <= i__1; i__ += 2) { + if (si[i__] != -si[i__ + 1]) { + + swap = sr[i__]; + sr[i__] = sr[i__ + 1]; + sr[i__ + 1] = sr[i__ + 2]; + sr[i__ + 2] = swap; + + swap = si[i__]; + si[i__] = si[i__ + 1]; + si[i__ + 1] = si[i__ + 2]; + si[i__ + 2] = swap; + } +/* L10: */ + } + +/* + ==== NSHFTS is supposed to be even, but if it is odd, + . then simply reduce it by one. The shuffle above + . ensures that the dropped shift is real and that + . the remaining shifts are paired. ==== +*/ + + ns = *nshfts - *nshfts % 2; + +/* ==== Machine constants for deflation ==== */ + + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + dlabad_(&safmin, &safmax); + ulp = PRECISION; + smlnum = safmin * ((doublereal) (*n) / ulp); + +/* + ==== Use accumulated reflections to update far-from-diagonal + . entries ? ==== +*/ + + accum = *kacc22 == 1 || *kacc22 == 2; + +/* ==== If so, exploit the 2-by-2 block structure? ==== */ + + blk22 = ns > 2 && *kacc22 == 2; + +/* ==== clear trash ==== */ + + if (*ktop + 2 <= *kbot) { + h__[*ktop + 2 + *ktop * h_dim1] = 0.; + } + +/* ==== NBMPS = number of 2-shift bulges in the chain ==== */ + + nbmps = ns / 2; + +/* ==== KDU = width of slab ==== */ + + kdu = nbmps * 6 - 3; + +/* ==== Create and chase chains of NBMPS bulges ==== */ + + i__1 = *kbot - 2; + i__2 = nbmps * 3 - 2; + for (incol = (1 - nbmps) * 3 + *ktop - 1; i__2 < 0 ? incol >= i__1 : + incol <= i__1; incol += i__2) { + ndcol = incol + kdu; + if (accum) { + dlaset_("ALL", &kdu, &kdu, &c_b29, &c_b15, &u[u_offset], ldu); + } + +/* + ==== Near-the-diagonal bulge chase. The following loop + . performs the near-the-diagonal part of a small bulge + . multi-shift QR sweep. Each 6*NBMPS-2 column diagonal + . chunk extends from column INCOL to column NDCOL + . (including both column INCOL and column NDCOL). The + . following loop chases a 3*NBMPS column long chain of + . NBMPS bulges 3*NBMPS-2 columns to the right. (INCOL + . may be less than KTOP and and NDCOL may be greater than + . KBOT indicating phantom columns from which to chase + . bulges before they are actually introduced or to which + . to chase bulges beyond column KBOT.) ==== + + Computing MIN +*/ + i__4 = incol + nbmps * 3 - 3, i__5 = *kbot - 2; + i__3 = min(i__4,i__5); + for (krcol = incol; krcol <= i__3; ++krcol) { + +/* + ==== Bulges number MTOP to MBOT are active double implicit + . shift bulges. There may or may not also be small + . 2-by-2 bulge, if there is room. The inactive bulges + . (if any) must wait until the active bulges have moved + . down the diagonal to make room. The phantom matrix + . paradigm described above helps keep track. ==== + + Computing MAX +*/ + i__4 = 1, i__5 = (*ktop - 1 - krcol + 2) / 3 + 1; + mtop = max(i__4,i__5); +/* Computing MIN */ + i__4 = nbmps, i__5 = (*kbot - krcol) / 3; + mbot = min(i__4,i__5); + m22 = mbot + 1; + bmp22 = mbot < nbmps && krcol + (m22 - 1) * 3 == *kbot - 2; + +/* + ==== Generate reflections to chase the chain right + . one column. (The minimum value of K is KTOP-1.) ==== +*/ + + i__4 = mbot; + for (m = mtop; m <= i__4; ++m) { + k = krcol + (m - 1) * 3; + if (k == *ktop - 1) { + dlaqr1_(&c__3, &h__[*ktop + *ktop * h_dim1], ldh, &sr[(m + << 1) - 1], &si[(m << 1) - 1], &sr[m * 2], &si[m * + 2], &v[m * v_dim1 + 1]); + alpha = v[m * v_dim1 + 1]; + dlarfg_(&c__3, &alpha, &v[m * v_dim1 + 2], &c__1, &v[m * + v_dim1 + 1]); + } else { + beta = h__[k + 1 + k * h_dim1]; + v[m * v_dim1 + 2] = h__[k + 2 + k * h_dim1]; + v[m * v_dim1 + 3] = h__[k + 3 + k * h_dim1]; + dlarfg_(&c__3, &beta, &v[m * v_dim1 + 2], &c__1, &v[m * + v_dim1 + 1]); + +/* + ==== A Bulge may collapse because of vigilant + . deflation or destructive underflow. In the + . underflow case, try the two-small-subdiagonals + . trick to try to reinflate the bulge. ==== +*/ + + if (h__[k + 3 + k * h_dim1] != 0. || h__[k + 3 + (k + 1) * + h_dim1] != 0. || h__[k + 3 + (k + 2) * h_dim1] == + 0.) { + +/* ==== Typical case: not collapsed (yet). ==== */ + + h__[k + 1 + k * h_dim1] = beta; + h__[k + 2 + k * h_dim1] = 0.; + h__[k + 3 + k * h_dim1] = 0.; + } else { + +/* + ==== Atypical case: collapsed. Attempt to + . reintroduce ignoring H(K+1,K) and H(K+2,K). + . If the fill resulting from the new + . reflector is too large, then abandon it. + . Otherwise, use the new one. ==== +*/ + + dlaqr1_(&c__3, &h__[k + 1 + (k + 1) * h_dim1], ldh, & + sr[(m << 1) - 1], &si[(m << 1) - 1], &sr[m * + 2], &si[m * 2], vt); + alpha = vt[0]; + dlarfg_(&c__3, &alpha, &vt[1], &c__1, vt); + refsum = vt[0] * (h__[k + 1 + k * h_dim1] + vt[1] * + h__[k + 2 + k * h_dim1]); + + if ((d__1 = h__[k + 2 + k * h_dim1] - refsum * vt[1], + abs(d__1)) + (d__2 = refsum * vt[2], abs(d__2) + ) > ulp * ((d__3 = h__[k + k * h_dim1], abs( + d__3)) + (d__4 = h__[k + 1 + (k + 1) * h_dim1] + , abs(d__4)) + (d__5 = h__[k + 2 + (k + 2) * + h_dim1], abs(d__5)))) { + +/* + ==== Starting a new bulge here would + . create non-negligible fill. Use + . the old one with trepidation. ==== +*/ + + h__[k + 1 + k * h_dim1] = beta; + h__[k + 2 + k * h_dim1] = 0.; + h__[k + 3 + k * h_dim1] = 0.; + } else { + +/* + ==== Stating a new bulge here would + . create only negligible fill. + . Replace the old reflector with + . the new one. ==== +*/ + + h__[k + 1 + k * h_dim1] -= refsum; + h__[k + 2 + k * h_dim1] = 0.; + h__[k + 3 + k * h_dim1] = 0.; + v[m * v_dim1 + 1] = vt[0]; + v[m * v_dim1 + 2] = vt[1]; + v[m * v_dim1 + 3] = vt[2]; + } + } + } +/* L20: */ + } + +/* ==== Generate a 2-by-2 reflection, if needed. ==== */ + + k = krcol + (m22 - 1) * 3; + if (bmp22) { + if (k == *ktop - 1) { + dlaqr1_(&c__2, &h__[k + 1 + (k + 1) * h_dim1], ldh, &sr[( + m22 << 1) - 1], &si[(m22 << 1) - 1], &sr[m22 * 2], + &si[m22 * 2], &v[m22 * v_dim1 + 1]); + beta = v[m22 * v_dim1 + 1]; + dlarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 + * v_dim1 + 1]); + } else { + beta = h__[k + 1 + k * h_dim1]; + v[m22 * v_dim1 + 2] = h__[k + 2 + k * h_dim1]; + dlarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 + * v_dim1 + 1]); + h__[k + 1 + k * h_dim1] = beta; + h__[k + 2 + k * h_dim1] = 0.; + } + } + +/* ==== Multiply H by reflections from the left ==== */ + + if (accum) { + jbot = min(ndcol,*kbot); + } else if (*wantt) { + jbot = *n; + } else { + jbot = *kbot; + } + i__4 = jbot; + for (j = max(*ktop,krcol); j <= i__4; ++j) { +/* Computing MIN */ + i__5 = mbot, i__6 = (j - krcol + 2) / 3; + mend = min(i__5,i__6); + i__5 = mend; + for (m = mtop; m <= i__5; ++m) { + k = krcol + (m - 1) * 3; + refsum = v[m * v_dim1 + 1] * (h__[k + 1 + j * h_dim1] + v[ + m * v_dim1 + 2] * h__[k + 2 + j * h_dim1] + v[m * + v_dim1 + 3] * h__[k + 3 + j * h_dim1]); + h__[k + 1 + j * h_dim1] -= refsum; + h__[k + 2 + j * h_dim1] -= refsum * v[m * v_dim1 + 2]; + h__[k + 3 + j * h_dim1] -= refsum * v[m * v_dim1 + 3]; +/* L30: */ + } +/* L40: */ + } + if (bmp22) { + k = krcol + (m22 - 1) * 3; +/* Computing MAX */ + i__4 = k + 1; + i__5 = jbot; + for (j = max(i__4,*ktop); j <= i__5; ++j) { + refsum = v[m22 * v_dim1 + 1] * (h__[k + 1 + j * h_dim1] + + v[m22 * v_dim1 + 2] * h__[k + 2 + j * h_dim1]); + h__[k + 1 + j * h_dim1] -= refsum; + h__[k + 2 + j * h_dim1] -= refsum * v[m22 * v_dim1 + 2]; +/* L50: */ + } + } + +/* + ==== Multiply H by reflections from the right. + . Delay filling in the last row until the + . vigilant deflation check is complete. ==== +*/ + + if (accum) { + jtop = max(*ktop,incol); + } else if (*wantt) { + jtop = 1; + } else { + jtop = *ktop; + } + i__5 = mbot; + for (m = mtop; m <= i__5; ++m) { + if (v[m * v_dim1 + 1] != 0.) { + k = krcol + (m - 1) * 3; +/* Computing MIN */ + i__6 = *kbot, i__7 = k + 3; + i__4 = min(i__6,i__7); + for (j = jtop; j <= i__4; ++j) { + refsum = v[m * v_dim1 + 1] * (h__[j + (k + 1) * + h_dim1] + v[m * v_dim1 + 2] * h__[j + (k + 2) + * h_dim1] + v[m * v_dim1 + 3] * h__[j + (k + + 3) * h_dim1]); + h__[j + (k + 1) * h_dim1] -= refsum; + h__[j + (k + 2) * h_dim1] -= refsum * v[m * v_dim1 + + 2]; + h__[j + (k + 3) * h_dim1] -= refsum * v[m * v_dim1 + + 3]; +/* L60: */ + } + + if (accum) { + +/* + ==== Accumulate U. (If necessary, update Z later + . with with an efficient matrix-matrix + . multiply.) ==== +*/ + + kms = k - incol; +/* Computing MAX */ + i__4 = 1, i__6 = *ktop - incol; + i__7 = kdu; + for (j = max(i__4,i__6); j <= i__7; ++j) { + refsum = v[m * v_dim1 + 1] * (u[j + (kms + 1) * + u_dim1] + v[m * v_dim1 + 2] * u[j + (kms + + 2) * u_dim1] + v[m * v_dim1 + 3] * u[j + + (kms + 3) * u_dim1]); + u[j + (kms + 1) * u_dim1] -= refsum; + u[j + (kms + 2) * u_dim1] -= refsum * v[m * + v_dim1 + 2]; + u[j + (kms + 3) * u_dim1] -= refsum * v[m * + v_dim1 + 3]; +/* L70: */ + } + } else if (*wantz) { + +/* + ==== U is not accumulated, so update Z + . now by multiplying by reflections + . from the right. ==== +*/ + + i__7 = *ihiz; + for (j = *iloz; j <= i__7; ++j) { + refsum = v[m * v_dim1 + 1] * (z__[j + (k + 1) * + z_dim1] + v[m * v_dim1 + 2] * z__[j + (k + + 2) * z_dim1] + v[m * v_dim1 + 3] * z__[ + j + (k + 3) * z_dim1]); + z__[j + (k + 1) * z_dim1] -= refsum; + z__[j + (k + 2) * z_dim1] -= refsum * v[m * + v_dim1 + 2]; + z__[j + (k + 3) * z_dim1] -= refsum * v[m * + v_dim1 + 3]; +/* L80: */ + } + } + } +/* L90: */ + } + +/* ==== Special case: 2-by-2 reflection (if needed) ==== */ + + k = krcol + (m22 - 1) * 3; + if (bmp22 && v[m22 * v_dim1 + 1] != 0.) { +/* Computing MIN */ + i__7 = *kbot, i__4 = k + 3; + i__5 = min(i__7,i__4); + for (j = jtop; j <= i__5; ++j) { + refsum = v[m22 * v_dim1 + 1] * (h__[j + (k + 1) * h_dim1] + + v[m22 * v_dim1 + 2] * h__[j + (k + 2) * h_dim1]) + ; + h__[j + (k + 1) * h_dim1] -= refsum; + h__[j + (k + 2) * h_dim1] -= refsum * v[m22 * v_dim1 + 2]; +/* L100: */ + } + + if (accum) { + kms = k - incol; +/* Computing MAX */ + i__5 = 1, i__7 = *ktop - incol; + i__4 = kdu; + for (j = max(i__5,i__7); j <= i__4; ++j) { + refsum = v[m22 * v_dim1 + 1] * (u[j + (kms + 1) * + u_dim1] + v[m22 * v_dim1 + 2] * u[j + (kms + + 2) * u_dim1]); + u[j + (kms + 1) * u_dim1] -= refsum; + u[j + (kms + 2) * u_dim1] -= refsum * v[m22 * v_dim1 + + 2]; +/* L110: */ + } + } else if (*wantz) { + i__4 = *ihiz; + for (j = *iloz; j <= i__4; ++j) { + refsum = v[m22 * v_dim1 + 1] * (z__[j + (k + 1) * + z_dim1] + v[m22 * v_dim1 + 2] * z__[j + (k + + 2) * z_dim1]); + z__[j + (k + 1) * z_dim1] -= refsum; + z__[j + (k + 2) * z_dim1] -= refsum * v[m22 * v_dim1 + + 2]; +/* L120: */ + } + } + } + +/* ==== Vigilant deflation check ==== */ + + mstart = mtop; + if (krcol + (mstart - 1) * 3 < *ktop) { + ++mstart; + } + mend = mbot; + if (bmp22) { + ++mend; + } + if (krcol == *kbot - 2) { + ++mend; + } + i__4 = mend; + for (m = mstart; m <= i__4; ++m) { +/* Computing MIN */ + i__5 = *kbot - 1, i__7 = krcol + (m - 1) * 3; + k = min(i__5,i__7); + +/* + ==== The following convergence test requires that + . the tradition small-compared-to-nearby-diagonals + . criterion and the Ahues & Tisseur (LAWN 122, 1997) + . criteria both be satisfied. The latter improves + . accuracy in some examples. Falling back on an + . alternate convergence criterion when TST1 or TST2 + . is zero (as done here) is traditional but probably + . unnecessary. ==== +*/ + + if (h__[k + 1 + k * h_dim1] != 0.) { + tst1 = (d__1 = h__[k + k * h_dim1], abs(d__1)) + (d__2 = + h__[k + 1 + (k + 1) * h_dim1], abs(d__2)); + if (tst1 == 0.) { + if (k >= *ktop + 1) { + tst1 += (d__1 = h__[k + (k - 1) * h_dim1], abs( + d__1)); + } + if (k >= *ktop + 2) { + tst1 += (d__1 = h__[k + (k - 2) * h_dim1], abs( + d__1)); + } + if (k >= *ktop + 3) { + tst1 += (d__1 = h__[k + (k - 3) * h_dim1], abs( + d__1)); + } + if (k <= *kbot - 2) { + tst1 += (d__1 = h__[k + 2 + (k + 1) * h_dim1], + abs(d__1)); + } + if (k <= *kbot - 3) { + tst1 += (d__1 = h__[k + 3 + (k + 1) * h_dim1], + abs(d__1)); + } + if (k <= *kbot - 4) { + tst1 += (d__1 = h__[k + 4 + (k + 1) * h_dim1], + abs(d__1)); + } + } +/* Computing MAX */ + d__2 = smlnum, d__3 = ulp * tst1; + if ((d__1 = h__[k + 1 + k * h_dim1], abs(d__1)) <= max( + d__2,d__3)) { +/* Computing MAX */ + d__3 = (d__1 = h__[k + 1 + k * h_dim1], abs(d__1)), + d__4 = (d__2 = h__[k + (k + 1) * h_dim1], abs( + d__2)); + h12 = max(d__3,d__4); +/* Computing MIN */ + d__3 = (d__1 = h__[k + 1 + k * h_dim1], abs(d__1)), + d__4 = (d__2 = h__[k + (k + 1) * h_dim1], abs( + d__2)); + h21 = min(d__3,d__4); +/* Computing MAX */ + d__3 = (d__1 = h__[k + 1 + (k + 1) * h_dim1], abs( + d__1)), d__4 = (d__2 = h__[k + k * h_dim1] - + h__[k + 1 + (k + 1) * h_dim1], abs(d__2)); + h11 = max(d__3,d__4); +/* Computing MIN */ + d__3 = (d__1 = h__[k + 1 + (k + 1) * h_dim1], abs( + d__1)), d__4 = (d__2 = h__[k + k * h_dim1] - + h__[k + 1 + (k + 1) * h_dim1], abs(d__2)); + h22 = min(d__3,d__4); + scl = h11 + h12; + tst2 = h22 * (h11 / scl); + +/* Computing MAX */ + d__1 = smlnum, d__2 = ulp * tst2; + if (tst2 == 0. || h21 * (h12 / scl) <= max(d__1,d__2)) + { + h__[k + 1 + k * h_dim1] = 0.; + } + } + } +/* L130: */ + } + +/* + ==== Fill in the last row of each bulge. ==== + + Computing MIN +*/ + i__4 = nbmps, i__5 = (*kbot - krcol - 1) / 3; + mend = min(i__4,i__5); + i__4 = mend; + for (m = mtop; m <= i__4; ++m) { + k = krcol + (m - 1) * 3; + refsum = v[m * v_dim1 + 1] * v[m * v_dim1 + 3] * h__[k + 4 + ( + k + 3) * h_dim1]; + h__[k + 4 + (k + 1) * h_dim1] = -refsum; + h__[k + 4 + (k + 2) * h_dim1] = -refsum * v[m * v_dim1 + 2]; + h__[k + 4 + (k + 3) * h_dim1] -= refsum * v[m * v_dim1 + 3]; +/* L140: */ + } + +/* + ==== End of near-the-diagonal bulge chase. ==== + + L150: +*/ + } + +/* + ==== Use U (if accumulated) to update far-from-diagonal + . entries in H. If required, use U to update Z as + . well. ==== +*/ + + if (accum) { + if (*wantt) { + jtop = 1; + jbot = *n; + } else { + jtop = *ktop; + jbot = *kbot; + } + if (! blk22 || incol < *ktop || ndcol > *kbot || ns <= 2) { + +/* + ==== Updates not exploiting the 2-by-2 block + . structure of U. K1 and NU keep track of + . the location and size of U in the special + . cases of introducing bulges and chasing + . bulges off the bottom. In these special + . cases and in case the number of shifts + . is NS = 2, there is no 2-by-2 block + . structure to exploit. ==== + + Computing MAX +*/ + i__3 = 1, i__4 = *ktop - incol; + k1 = max(i__3,i__4); +/* Computing MAX */ + i__3 = 0, i__4 = ndcol - *kbot; + nu = kdu - max(i__3,i__4) - k1 + 1; + +/* ==== Horizontal Multiply ==== */ + + i__3 = jbot; + i__4 = *nh; + for (jcol = min(ndcol,*kbot) + 1; i__4 < 0 ? jcol >= i__3 : + jcol <= i__3; jcol += i__4) { +/* Computing MIN */ + i__5 = *nh, i__7 = jbot - jcol + 1; + jlen = min(i__5,i__7); + dgemm_("C", "N", &nu, &jlen, &nu, &c_b15, &u[k1 + k1 * + u_dim1], ldu, &h__[incol + k1 + jcol * h_dim1], + ldh, &c_b29, &wh[wh_offset], ldwh); + dlacpy_("ALL", &nu, &jlen, &wh[wh_offset], ldwh, &h__[ + incol + k1 + jcol * h_dim1], ldh); +/* L160: */ + } + +/* ==== Vertical multiply ==== */ + + i__4 = max(*ktop,incol) - 1; + i__3 = *nv; + for (jrow = jtop; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; + jrow += i__3) { +/* Computing MIN */ + i__5 = *nv, i__7 = max(*ktop,incol) - jrow; + jlen = min(i__5,i__7); + dgemm_("N", "N", &jlen, &nu, &nu, &c_b15, &h__[jrow + ( + incol + k1) * h_dim1], ldh, &u[k1 + k1 * u_dim1], + ldu, &c_b29, &wv[wv_offset], ldwv); + dlacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &h__[ + jrow + (incol + k1) * h_dim1], ldh); +/* L170: */ + } + +/* ==== Z multiply (also vertical) ==== */ + + if (*wantz) { + i__3 = *ihiz; + i__4 = *nv; + for (jrow = *iloz; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; + jrow += i__4) { +/* Computing MIN */ + i__5 = *nv, i__7 = *ihiz - jrow + 1; + jlen = min(i__5,i__7); + dgemm_("N", "N", &jlen, &nu, &nu, &c_b15, &z__[jrow + + (incol + k1) * z_dim1], ldz, &u[k1 + k1 * + u_dim1], ldu, &c_b29, &wv[wv_offset], ldwv); + dlacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &z__[ + jrow + (incol + k1) * z_dim1], ldz) + ; +/* L180: */ + } + } + } else { + +/* + ==== Updates exploiting U's 2-by-2 block structure. + . (I2, I4, J2, J4 are the last rows and columns + . of the blocks.) ==== +*/ + + i2 = (kdu + 1) / 2; + i4 = kdu; + j2 = i4 - i2; + j4 = kdu; + +/* + ==== KZS and KNZ deal with the band of zeros + . along the diagonal of one of the triangular + . blocks. ==== +*/ + + kzs = j4 - j2 - (ns + 1); + knz = ns + 1; + +/* ==== Horizontal multiply ==== */ + + i__4 = jbot; + i__3 = *nh; + for (jcol = min(ndcol,*kbot) + 1; i__3 < 0 ? jcol >= i__4 : + jcol <= i__4; jcol += i__3) { +/* Computing MIN */ + i__5 = *nh, i__7 = jbot - jcol + 1; + jlen = min(i__5,i__7); + +/* + ==== Copy bottom of H to top+KZS of scratch ==== + (The first KZS rows get multiplied by zero.) ==== +*/ + + dlacpy_("ALL", &knz, &jlen, &h__[incol + 1 + j2 + jcol * + h_dim1], ldh, &wh[kzs + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U21' ==== */ + + dlaset_("ALL", &kzs, &jlen, &c_b29, &c_b29, &wh[wh_offset] + , ldwh); + dtrmm_("L", "U", "C", "N", &knz, &jlen, &c_b15, &u[j2 + 1 + + (kzs + 1) * u_dim1], ldu, &wh[kzs + 1 + wh_dim1] + , ldwh); + +/* ==== Multiply top of H by U11' ==== */ + + dgemm_("C", "N", &i2, &jlen, &j2, &c_b15, &u[u_offset], + ldu, &h__[incol + 1 + jcol * h_dim1], ldh, &c_b15, + &wh[wh_offset], ldwh); + +/* ==== Copy top of H to bottom of WH ==== */ + + dlacpy_("ALL", &j2, &jlen, &h__[incol + 1 + jcol * h_dim1] + , ldh, &wh[i2 + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U21' ==== */ + + dtrmm_("L", "L", "C", "N", &j2, &jlen, &c_b15, &u[(i2 + 1) + * u_dim1 + 1], ldu, &wh[i2 + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + dgemm_("C", "N", &i__5, &jlen, &i__7, &c_b15, &u[j2 + 1 + + (i2 + 1) * u_dim1], ldu, &h__[incol + 1 + j2 + + jcol * h_dim1], ldh, &c_b15, &wh[i2 + 1 + wh_dim1] + , ldwh); + +/* ==== Copy it back ==== */ + + dlacpy_("ALL", &kdu, &jlen, &wh[wh_offset], ldwh, &h__[ + incol + 1 + jcol * h_dim1], ldh); +/* L190: */ + } + +/* ==== Vertical multiply ==== */ + + i__3 = max(incol,*ktop) - 1; + i__4 = *nv; + for (jrow = jtop; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; + jrow += i__4) { +/* Computing MIN */ + i__5 = *nv, i__7 = max(incol,*ktop) - jrow; + jlen = min(i__5,i__7); + +/* + ==== Copy right of H to scratch (the first KZS + . columns get multiplied by zero) ==== +*/ + + dlacpy_("ALL", &jlen, &knz, &h__[jrow + (incol + 1 + j2) * + h_dim1], ldh, &wv[(kzs + 1) * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U21 ==== */ + + dlaset_("ALL", &jlen, &kzs, &c_b29, &c_b29, &wv[wv_offset] + , ldwv); + dtrmm_("R", "U", "N", "N", &jlen, &knz, &c_b15, &u[j2 + 1 + + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Multiply by U11 ==== */ + + dgemm_("N", "N", &jlen, &i2, &j2, &c_b15, &h__[jrow + ( + incol + 1) * h_dim1], ldh, &u[u_offset], ldu, & + c_b15, &wv[wv_offset], ldwv) + ; + +/* ==== Copy left of H to right of scratch ==== */ + + dlacpy_("ALL", &jlen, &j2, &h__[jrow + (incol + 1) * + h_dim1], ldh, &wv[(i2 + 1) * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U21 ==== */ + + i__5 = i4 - i2; + dtrmm_("R", "L", "N", "N", &jlen, &i__5, &c_b15, &u[(i2 + + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * wv_dim1 + 1] + , ldwv); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + dgemm_("N", "N", &jlen, &i__5, &i__7, &c_b15, &h__[jrow + + (incol + 1 + j2) * h_dim1], ldh, &u[j2 + 1 + (i2 + + 1) * u_dim1], ldu, &c_b15, &wv[(i2 + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Copy it back ==== */ + + dlacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, &h__[ + jrow + (incol + 1) * h_dim1], ldh); +/* L200: */ + } + +/* ==== Multiply Z (also vertical) ==== */ + + if (*wantz) { + i__4 = *ihiz; + i__3 = *nv; + for (jrow = *iloz; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; + jrow += i__3) { +/* Computing MIN */ + i__5 = *nv, i__7 = *ihiz - jrow + 1; + jlen = min(i__5,i__7); + +/* + ==== Copy right of Z to left of scratch (first + . KZS columns get multiplied by zero) ==== +*/ + + dlacpy_("ALL", &jlen, &knz, &z__[jrow + (incol + 1 + + j2) * z_dim1], ldz, &wv[(kzs + 1) * wv_dim1 + + 1], ldwv); + +/* ==== Multiply by U12 ==== */ + + dlaset_("ALL", &jlen, &kzs, &c_b29, &c_b29, &wv[ + wv_offset], ldwv); + dtrmm_("R", "U", "N", "N", &jlen, &knz, &c_b15, &u[j2 + + 1 + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) + * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U11 ==== */ + + dgemm_("N", "N", &jlen, &i2, &j2, &c_b15, &z__[jrow + + (incol + 1) * z_dim1], ldz, &u[u_offset], ldu, + &c_b15, &wv[wv_offset], ldwv); + +/* ==== Copy left of Z to right of scratch ==== */ + + dlacpy_("ALL", &jlen, &j2, &z__[jrow + (incol + 1) * + z_dim1], ldz, &wv[(i2 + 1) * wv_dim1 + 1], + ldwv); + +/* ==== Multiply by U21 ==== */ + + i__5 = i4 - i2; + dtrmm_("R", "L", "N", "N", &jlen, &i__5, &c_b15, &u[( + i2 + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + dgemm_("N", "N", &jlen, &i__5, &i__7, &c_b15, &z__[ + jrow + (incol + 1 + j2) * z_dim1], ldz, &u[j2 + + 1 + (i2 + 1) * u_dim1], ldu, &c_b15, &wv[( + i2 + 1) * wv_dim1 + 1], ldwv); + +/* ==== Copy the result back to Z ==== */ + + dlacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, & + z__[jrow + (incol + 1) * z_dim1], ldz); +/* L210: */ + } + } + } + } +/* L220: */ + } + +/* ==== End of DLAQR5 ==== */ + + return 0; +} /* dlaqr5_ */ + +/* Subroutine */ int dlarf_(char *side, integer *m, integer *n, doublereal *v, + integer *incv, doublereal *tau, doublereal *c__, integer *ldc, + doublereal *work) +{ + /* System generated locals */ + integer c_dim1, c_offset; + doublereal d__1; + + /* Local variables */ + static integer i__; + static logical applyleft; + extern /* Subroutine */ int dger_(integer *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *); + static integer lastc, lastv; + extern integer iladlc_(integer *, integer *, doublereal *, integer *), + iladlr_(integer *, integer *, doublereal *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLARF applies a real elementary reflector H to a real m by n matrix + C, from either the left or the right. H is represented in the form + + H = I - tau * v * v' + + where tau is a real scalar and v is a real vector. + + If tau = 0, then H is taken to be the unit matrix. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': form H * C + = 'R': form C * H + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + V (input) DOUBLE PRECISION array, dimension + (1 + (M-1)*abs(INCV)) if SIDE = 'L' + or (1 + (N-1)*abs(INCV)) if SIDE = 'R' + The vector v in the representation of H. V is not used if + TAU = 0. + + INCV (input) INTEGER + The increment between elements of v. INCV <> 0. + + TAU (input) DOUBLE PRECISION + The value tau in the representation of H. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by the matrix H * C if SIDE = 'L', + or C * H if SIDE = 'R'. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) DOUBLE PRECISION array, dimension + (N) if SIDE = 'L' + or (M) if SIDE = 'R' + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --v; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + applyleft = lsame_(side, "L"); + lastv = 0; + lastc = 0; + if (*tau != 0.) { +/* + Set up variables for scanning V. LASTV begins pointing to the end + of V. +*/ + if (applyleft) { + lastv = *m; + } else { + lastv = *n; + } + if (*incv > 0) { + i__ = (lastv - 1) * *incv + 1; + } else { + i__ = 1; + } +/* Look for the last non-zero row in V. */ + while(lastv > 0 && v[i__] == 0.) { + --lastv; + i__ -= *incv; + } + if (applyleft) { +/* Scan for the last non-zero column in C(1:lastv,:). */ + lastc = iladlc_(&lastv, n, &c__[c_offset], ldc); + } else { +/* Scan for the last non-zero row in C(:,1:lastv). */ + lastc = iladlr_(m, &lastv, &c__[c_offset], ldc); + } + } +/* + Note that lastc.eq.0 renders the BLAS operations null; no special + case is needed at this level. +*/ + if (applyleft) { + +/* Form H * C */ + + if (lastv > 0) { + +/* w(1:lastc,1) := C(1:lastv,1:lastc)' * v(1:lastv,1) */ + + dgemv_("Transpose", &lastv, &lastc, &c_b15, &c__[c_offset], ldc, & + v[1], incv, &c_b29, &work[1], &c__1); + +/* C(1:lastv,1:lastc) := C(...) - v(1:lastv,1) * w(1:lastc,1)' */ + + d__1 = -(*tau); + dger_(&lastv, &lastc, &d__1, &v[1], incv, &work[1], &c__1, &c__[ + c_offset], ldc); + } + } else { + +/* Form C * H */ + + if (lastv > 0) { + +/* w(1:lastc,1) := C(1:lastc,1:lastv) * v(1:lastv,1) */ + + dgemv_("No transpose", &lastc, &lastv, &c_b15, &c__[c_offset], + ldc, &v[1], incv, &c_b29, &work[1], &c__1); + +/* C(1:lastc,1:lastv) := C(...) - w(1:lastc,1) * v(1:lastv,1)' */ + + d__1 = -(*tau); + dger_(&lastc, &lastv, &d__1, &work[1], &c__1, &v[1], incv, &c__[ + c_offset], ldc); + } + } + return 0; + +/* End of DLARF */ + +} /* dlarf_ */ + +/* Subroutine */ int dlarfb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, doublereal *v, integer * + ldv, doublereal *t, integer *ldt, doublereal *c__, integer *ldc, + doublereal *work, integer *ldwork) +{ + /* System generated locals */ + integer c_dim1, c_offset, t_dim1, t_offset, v_dim1, v_offset, work_dim1, + work_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + extern logical lsame_(char *, char *); + static integer lastc; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *), dtrmm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *); + static integer lastv; + extern integer iladlc_(integer *, integer *, doublereal *, integer *), + iladlr_(integer *, integer *, doublereal *, integer *); + static char transt[1]; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLARFB applies a real block reflector H or its transpose H' to a + real m by n matrix C, from either the left or the right. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply H or H' from the Left + = 'R': apply H or H' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply H (No transpose) + = 'T': apply H' (Transpose) + + DIRECT (input) CHARACTER*1 + Indicates how H is formed from a product of elementary + reflectors + = 'F': H = H(1) H(2) . . . H(k) (Forward) + = 'B': H = H(k) . . . H(2) H(1) (Backward) + + STOREV (input) CHARACTER*1 + Indicates how the vectors which define the elementary + reflectors are stored: + = 'C': Columnwise + = 'R': Rowwise + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + K (input) INTEGER + The order of the matrix T (= the number of elementary + reflectors whose product defines the block reflector). + + V (input) DOUBLE PRECISION array, dimension + (LDV,K) if STOREV = 'C' + (LDV,M) if STOREV = 'R' and SIDE = 'L' + (LDV,N) if STOREV = 'R' and SIDE = 'R' + The matrix V. See further details. + + LDV (input) INTEGER + The leading dimension of the array V. + If STOREV = 'C' and SIDE = 'L', LDV >= max(1,M); + if STOREV = 'C' and SIDE = 'R', LDV >= max(1,N); + if STOREV = 'R', LDV >= K. + + T (input) DOUBLE PRECISION array, dimension (LDT,K) + The triangular k by k matrix T in the representation of the + block reflector. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= K. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by H*C or H'*C or C*H or C*H'. + + LDC (input) INTEGER + The leading dimension of the array C. LDA >= max(1,M). + + WORK (workspace) DOUBLE PRECISION array, dimension (LDWORK,K) + + LDWORK (input) INTEGER + The leading dimension of the array WORK. + If SIDE = 'L', LDWORK >= max(1,N); + if SIDE = 'R', LDWORK >= max(1,M). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + work_dim1 = *ldwork; + work_offset = 1 + work_dim1; + work -= work_offset; + + /* Function Body */ + if (*m <= 0 || *n <= 0) { + return 0; + } + + if (lsame_(trans, "N")) { + *(unsigned char *)transt = 'T'; + } else { + *(unsigned char *)transt = 'N'; + } + + if (lsame_(storev, "C")) { + + if (lsame_(direct, "F")) { + +/* + Let V = ( V1 ) (first K rows) + ( V2 ) + where V1 is unit lower triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = iladlr_(m, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = iladlc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK) + + W := C1' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dcopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 + + 1], &c__1); +/* L10: */ + } + +/* W := W * V1 */ + + dtrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2'*V2 */ + + i__1 = lastv - *k; + dgemm_("Transpose", "No transpose", &lastc, k, &i__1, & + c_b15, &c__[*k + 1 + c_dim1], ldc, &v[*k + 1 + + v_dim1], ldv, &c_b15, &work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + dtrmm_("Right", "Upper", transt, "Non-unit", &lastc, k, & + c_b15, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V * W' */ + + if (lastv > *k) { + +/* C2 := C2 - V2 * W' */ + + i__1 = lastv - *k; + dgemm_("No transpose", "Transpose", &i__1, &lastc, k, & + c_b151, &v[*k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork, &c_b15, &c__[*k + 1 + + c_dim1], ldc); + } + +/* W := W * V1' */ + + dtrmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[j + i__ * c_dim1] -= work[i__ + j * work_dim1]; +/* L20: */ + } +/* L30: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = iladlr_(n, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = iladlr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V = (C1*V1 + C2*V2) (stored in WORK) + + W := C1 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dcopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * + work_dim1 + 1], &c__1); +/* L40: */ + } + +/* W := W * V1 */ + + dtrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2 * V2 */ + + i__1 = lastv - *k; + dgemm_("No transpose", "No transpose", &lastc, k, &i__1, & + c_b15, &c__[(*k + 1) * c_dim1 + 1], ldc, &v[*k + + 1 + v_dim1], ldv, &c_b15, &work[work_offset], + ldwork); + } + +/* W := W * T or W * T' */ + + dtrmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b15, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V' */ + + if (lastv > *k) { + +/* C2 := C2 - W * V2' */ + + i__1 = lastv - *k; + dgemm_("No transpose", "Transpose", &lastc, &i__1, k, & + c_b151, &work[work_offset], ldwork, &v[*k + 1 + + v_dim1], ldv, &c_b15, &c__[(*k + 1) * c_dim1 + 1], + ldc); + } + +/* W := W * V1' */ + + dtrmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] -= work[i__ + j * work_dim1]; +/* L50: */ + } +/* L60: */ + } + } + + } else { + +/* + Let V = ( V1 ) + ( V2 ) (last K rows) + where V2 is unit upper triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = iladlr_(m, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = iladlc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK) + + W := C2' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dcopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[ + j * work_dim1 + 1], &c__1); +/* L70: */ + } + +/* W := W * V2 */ + + dtrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b15, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1'*V1 */ + + i__1 = lastv - *k; + dgemm_("Transpose", "No transpose", &lastc, k, &i__1, & + c_b15, &c__[c_offset], ldc, &v[v_offset], ldv, & + c_b15, &work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + dtrmm_("Right", "Lower", transt, "Non-unit", &lastc, k, & + c_b15, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V * W' */ + + if (lastv > *k) { + +/* C1 := C1 - V1 * W' */ + + i__1 = lastv - *k; + dgemm_("No transpose", "Transpose", &i__1, &lastc, k, & + c_b151, &v[v_offset], ldv, &work[work_offset], + ldwork, &c_b15, &c__[c_offset], ldc); + } + +/* W := W * V2' */ + + dtrmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, & + c_b15, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + +/* C2 := C2 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[lastv - *k + j + i__ * c_dim1] -= work[i__ + j * + work_dim1]; +/* L80: */ + } +/* L90: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = iladlr_(n, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = iladlr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V = (C1*V1 + C2*V2) (stored in WORK) + + W := C2 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dcopy_(&lastc, &c__[(*n - *k + j) * c_dim1 + 1], &c__1, & + work[j * work_dim1 + 1], &c__1); +/* L100: */ + } + +/* W := W * V2 */ + + dtrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b15, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1 * V1 */ + + i__1 = lastv - *k; + dgemm_("No transpose", "No transpose", &lastc, k, &i__1, & + c_b15, &c__[c_offset], ldc, &v[v_offset], ldv, & + c_b15, &work[work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + dtrmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b15, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V' */ + + if (lastv > *k) { + +/* C1 := C1 - W * V1' */ + + i__1 = lastv - *k; + dgemm_("No transpose", "Transpose", &lastc, &i__1, k, & + c_b151, &work[work_offset], ldwork, &v[v_offset], + ldv, &c_b15, &c__[c_offset], ldc); + } + +/* W := W * V2' */ + + dtrmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, & + c_b15, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + +/* C2 := C2 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + (lastv - *k + j) * c_dim1] -= work[i__ + j * + work_dim1]; +/* L110: */ + } +/* L120: */ + } + } + } + + } else if (lsame_(storev, "R")) { + + if (lsame_(direct, "F")) { + +/* + Let V = ( V1 V2 ) (V1: first K columns) + where V1 is unit upper triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = iladlc_(k, m, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = iladlc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK) + + W := C1' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dcopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 + + 1], &c__1); +/* L130: */ + } + +/* W := W * V1' */ + + dtrmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2'*V2' */ + + i__1 = lastv - *k; + dgemm_("Transpose", "Transpose", &lastc, k, &i__1, &c_b15, + &c__[*k + 1 + c_dim1], ldc, &v[(*k + 1) * v_dim1 + + 1], ldv, &c_b15, &work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + dtrmm_("Right", "Upper", transt, "Non-unit", &lastc, k, & + c_b15, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V' * W' */ + + if (lastv > *k) { + +/* C2 := C2 - V2' * W' */ + + i__1 = lastv - *k; + dgemm_("Transpose", "Transpose", &i__1, &lastc, k, & + c_b151, &v[(*k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork, &c_b15, &c__[*k + 1 + + c_dim1], ldc); + } + +/* W := W * V1 */ + + dtrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[j + i__ * c_dim1] -= work[i__ + j * work_dim1]; +/* L140: */ + } +/* L150: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = iladlc_(k, n, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = iladlr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V' = (C1*V1' + C2*V2') (stored in WORK) + + W := C1 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dcopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * + work_dim1 + 1], &c__1); +/* L160: */ + } + +/* W := W * V1' */ + + dtrmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2 * V2' */ + + i__1 = lastv - *k; + dgemm_("No transpose", "Transpose", &lastc, k, &i__1, & + c_b15, &c__[(*k + 1) * c_dim1 + 1], ldc, &v[(*k + + 1) * v_dim1 + 1], ldv, &c_b15, &work[work_offset], + ldwork); + } + +/* W := W * T or W * T' */ + + dtrmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b15, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V */ + + if (lastv > *k) { + +/* C2 := C2 - W * V2 */ + + i__1 = lastv - *k; + dgemm_("No transpose", "No transpose", &lastc, &i__1, k, & + c_b151, &work[work_offset], ldwork, &v[(*k + 1) * + v_dim1 + 1], ldv, &c_b15, &c__[(*k + 1) * c_dim1 + + 1], ldc); + } + +/* W := W * V1 */ + + dtrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] -= work[i__ + j * work_dim1]; +/* L170: */ + } +/* L180: */ + } + + } + + } else { + +/* + Let V = ( V1 V2 ) (V2: last K columns) + where V2 is unit lower triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = iladlc_(k, m, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = iladlc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK) + + W := C2' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dcopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[ + j * work_dim1 + 1], &c__1); +/* L190: */ + } + +/* W := W * V2' */ + + dtrmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, & + c_b15, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1'*V1' */ + + i__1 = lastv - *k; + dgemm_("Transpose", "Transpose", &lastc, k, &i__1, &c_b15, + &c__[c_offset], ldc, &v[v_offset], ldv, &c_b15, & + work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + dtrmm_("Right", "Lower", transt, "Non-unit", &lastc, k, & + c_b15, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V' * W' */ + + if (lastv > *k) { + +/* C1 := C1 - V1' * W' */ + + i__1 = lastv - *k; + dgemm_("Transpose", "Transpose", &i__1, &lastc, k, & + c_b151, &v[v_offset], ldv, &work[work_offset], + ldwork, &c_b15, &c__[c_offset], ldc); + } + +/* W := W * V2 */ + + dtrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b15, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + +/* C2 := C2 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[lastv - *k + j + i__ * c_dim1] -= work[i__ + j * + work_dim1]; +/* L200: */ + } +/* L210: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = iladlc_(k, n, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = iladlr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V' = (C1*V1' + C2*V2') (stored in WORK) + + W := C2 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dcopy_(&lastc, &c__[(lastv - *k + j) * c_dim1 + 1], &c__1, + &work[j * work_dim1 + 1], &c__1); +/* L220: */ + } + +/* W := W * V2' */ + + dtrmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, & + c_b15, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1 * V1' */ + + i__1 = lastv - *k; + dgemm_("No transpose", "Transpose", &lastc, k, &i__1, & + c_b15, &c__[c_offset], ldc, &v[v_offset], ldv, & + c_b15, &work[work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + dtrmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b15, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V */ + + if (lastv > *k) { + +/* C1 := C1 - W * V1 */ + + i__1 = lastv - *k; + dgemm_("No transpose", "No transpose", &lastc, &i__1, k, & + c_b151, &work[work_offset], ldwork, &v[v_offset], + ldv, &c_b15, &c__[c_offset], ldc); + } + +/* W := W * V2 */ + + dtrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b15, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + (lastv - *k + j) * c_dim1] -= work[i__ + j * + work_dim1]; +/* L230: */ + } +/* L240: */ + } + + } + + } + } + + return 0; + +/* End of DLARFB */ + +} /* dlarfb_ */ + +/* Subroutine */ int dlarfg_(integer *n, doublereal *alpha, doublereal *x, + integer *incx, doublereal *tau) +{ + /* System generated locals */ + integer i__1; + doublereal d__1; + + /* Local variables */ + static integer j, knt; + static doublereal beta; + extern doublereal dnrm2_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + static doublereal xnorm; + + static doublereal safmin, rsafmn; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLARFG generates a real elementary reflector H of order n, such + that + + H * ( alpha ) = ( beta ), H' * H = I. + ( x ) ( 0 ) + + where alpha and beta are scalars, and x is an (n-1)-element real + vector. H is represented in the form + + H = I - tau * ( 1 ) * ( 1 v' ) , + ( v ) + + where tau is a real scalar and v is a real (n-1)-element + vector. + + If the elements of x are all zero, then tau = 0 and H is taken to be + the unit matrix. + + Otherwise 1 <= tau <= 2. + + Arguments + ========= + + N (input) INTEGER + The order of the elementary reflector. + + ALPHA (input/output) DOUBLE PRECISION + On entry, the value alpha. + On exit, it is overwritten with the value beta. + + X (input/output) DOUBLE PRECISION array, dimension + (1+(N-2)*abs(INCX)) + On entry, the vector x. + On exit, it is overwritten with the vector v. + + INCX (input) INTEGER + The increment between elements of X. INCX > 0. + + TAU (output) DOUBLE PRECISION + The value tau. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n <= 1) { + *tau = 0.; + return 0; + } + + i__1 = *n - 1; + xnorm = dnrm2_(&i__1, &x[1], incx); + + if (xnorm == 0.) { + +/* H = I */ + + *tau = 0.; + } else { + +/* general case */ + + d__1 = dlapy2_(alpha, &xnorm); + beta = -d_sign(&d__1, alpha); + safmin = SAFEMINIMUM / EPSILON; + knt = 0; + if (abs(beta) < safmin) { + +/* XNORM, BETA may be inaccurate; scale X and recompute them */ + + rsafmn = 1. / safmin; +L10: + ++knt; + i__1 = *n - 1; + dscal_(&i__1, &rsafmn, &x[1], incx); + beta *= rsafmn; + *alpha *= rsafmn; + if (abs(beta) < safmin) { + goto L10; + } + +/* New BETA is at most 1, at least SAFMIN */ + + i__1 = *n - 1; + xnorm = dnrm2_(&i__1, &x[1], incx); + d__1 = dlapy2_(alpha, &xnorm); + beta = -d_sign(&d__1, alpha); + } + *tau = (beta - *alpha) / beta; + i__1 = *n - 1; + d__1 = 1. / (*alpha - beta); + dscal_(&i__1, &d__1, &x[1], incx); + +/* If ALPHA is subnormal, it may lose relative accuracy */ + + i__1 = knt; + for (j = 1; j <= i__1; ++j) { + beta *= safmin; +/* L20: */ + } + *alpha = beta; + } + + return 0; + +/* End of DLARFG */ + +} /* dlarfg_ */ + +/* Subroutine */ int dlarft_(char *direct, char *storev, integer *n, integer * + k, doublereal *v, integer *ldv, doublereal *tau, doublereal *t, + integer *ldt) +{ + /* System generated locals */ + integer t_dim1, t_offset, v_dim1, v_offset, i__1, i__2, i__3; + doublereal d__1; + + /* Local variables */ + static integer i__, j, prevlastv; + static doublereal vii; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *); + static integer lastv; + extern /* Subroutine */ int dtrmv_(char *, char *, char *, integer *, + doublereal *, integer *, doublereal *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLARFT forms the triangular factor T of a real block reflector H + of order n, which is defined as a product of k elementary reflectors. + + If DIRECT = 'F', H = H(1) H(2) . . . H(k) and T is upper triangular; + + If DIRECT = 'B', H = H(k) . . . H(2) H(1) and T is lower triangular. + + If STOREV = 'C', the vector which defines the elementary reflector + H(i) is stored in the i-th column of the array V, and + + H = I - V * T * V' + + If STOREV = 'R', the vector which defines the elementary reflector + H(i) is stored in the i-th row of the array V, and + + H = I - V' * T * V + + Arguments + ========= + + DIRECT (input) CHARACTER*1 + Specifies the order in which the elementary reflectors are + multiplied to form the block reflector: + = 'F': H = H(1) H(2) . . . H(k) (Forward) + = 'B': H = H(k) . . . H(2) H(1) (Backward) + + STOREV (input) CHARACTER*1 + Specifies how the vectors which define the elementary + reflectors are stored (see also Further Details): + = 'C': columnwise + = 'R': rowwise + + N (input) INTEGER + The order of the block reflector H. N >= 0. + + K (input) INTEGER + The order of the triangular factor T (= the number of + elementary reflectors). K >= 1. + + V (input/output) DOUBLE PRECISION array, dimension + (LDV,K) if STOREV = 'C' + (LDV,N) if STOREV = 'R' + The matrix V. See further details. + + LDV (input) INTEGER + The leading dimension of the array V. + If STOREV = 'C', LDV >= max(1,N); if STOREV = 'R', LDV >= K. + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i). + + T (output) DOUBLE PRECISION array, dimension (LDT,K) + The k by k triangular factor T of the block reflector. + If DIRECT = 'F', T is upper triangular; if DIRECT = 'B', T is + lower triangular. The rest of the array is not used. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= K. + + Further Details + =============== + + The shape of the matrix V and the storage of the vectors which define + the H(i) is best illustrated by the following example with n = 5 and + k = 3. The elements equal to 1 are not stored; the corresponding + array elements are modified but restored on exit. The rest of the + array is not used. + + DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': + + V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) + ( v1 1 ) ( 1 v2 v2 v2 ) + ( v1 v2 1 ) ( 1 v3 v3 ) + ( v1 v2 v3 ) + ( v1 v2 v3 ) + + DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': + + V = ( v1 v2 v3 ) V = ( v1 v1 1 ) + ( v1 v2 v3 ) ( v2 v2 v2 1 ) + ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) + ( 1 v3 ) + ( 1 ) + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + --tau; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + + /* Function Body */ + if (*n == 0) { + return 0; + } + + if (lsame_(direct, "F")) { + prevlastv = *n; + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + prevlastv = max(i__,prevlastv); + if (tau[i__] == 0.) { + +/* H(i) = I */ + + i__2 = i__; + for (j = 1; j <= i__2; ++j) { + t[j + i__ * t_dim1] = 0.; +/* L10: */ + } + } else { + +/* general case */ + + vii = v[i__ + i__ * v_dim1]; + v[i__ + i__ * v_dim1] = 1.; + if (lsame_(storev, "C")) { +/* Skip any trailing zeros. */ + i__2 = i__ + 1; + for (lastv = *n; lastv >= i__2; --lastv) { + if (v[lastv + i__ * v_dim1] != 0.) { + goto L15; + } + } +L15: + j = min(lastv,prevlastv); + +/* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)' * V(i:j,i) */ + + i__2 = j - i__ + 1; + i__3 = i__ - 1; + d__1 = -tau[i__]; + dgemv_("Transpose", &i__2, &i__3, &d__1, &v[i__ + v_dim1], + ldv, &v[i__ + i__ * v_dim1], &c__1, &c_b29, &t[ + i__ * t_dim1 + 1], &c__1); + } else { +/* Skip any trailing zeros. */ + i__2 = i__ + 1; + for (lastv = *n; lastv >= i__2; --lastv) { + if (v[i__ + lastv * v_dim1] != 0.) { + goto L16; + } + } +L16: + j = min(lastv,prevlastv); + +/* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)' */ + + i__2 = i__ - 1; + i__3 = j - i__ + 1; + d__1 = -tau[i__]; + dgemv_("No transpose", &i__2, &i__3, &d__1, &v[i__ * + v_dim1 + 1], ldv, &v[i__ + i__ * v_dim1], ldv, & + c_b29, &t[i__ * t_dim1 + 1], &c__1); + } + v[i__ + i__ * v_dim1] = vii; + +/* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */ + + i__2 = i__ - 1; + dtrmv_("Upper", "No transpose", "Non-unit", &i__2, &t[ + t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1); + t[i__ + i__ * t_dim1] = tau[i__]; + if (i__ > 1) { + prevlastv = max(prevlastv,lastv); + } else { + prevlastv = lastv; + } + } +/* L20: */ + } + } else { + prevlastv = 1; + for (i__ = *k; i__ >= 1; --i__) { + if (tau[i__] == 0.) { + +/* H(i) = I */ + + i__1 = *k; + for (j = i__; j <= i__1; ++j) { + t[j + i__ * t_dim1] = 0.; +/* L30: */ + } + } else { + +/* general case */ + + if (i__ < *k) { + if (lsame_(storev, "C")) { + vii = v[*n - *k + i__ + i__ * v_dim1]; + v[*n - *k + i__ + i__ * v_dim1] = 1.; +/* Skip any leading zeros. */ + i__1 = i__ - 1; + for (lastv = 1; lastv <= i__1; ++lastv) { + if (v[lastv + i__ * v_dim1] != 0.) { + goto L35; + } + } +L35: + j = max(lastv,prevlastv); + +/* + T(i+1:k,i) := + - tau(i) * V(j:n-k+i,i+1:k)' * V(j:n-k+i,i) +*/ + + i__1 = *n - *k + i__ - j + 1; + i__2 = *k - i__; + d__1 = -tau[i__]; + dgemv_("Transpose", &i__1, &i__2, &d__1, &v[j + (i__ + + 1) * v_dim1], ldv, &v[j + i__ * v_dim1], & + c__1, &c_b29, &t[i__ + 1 + i__ * t_dim1], & + c__1); + v[*n - *k + i__ + i__ * v_dim1] = vii; + } else { + vii = v[i__ + (*n - *k + i__) * v_dim1]; + v[i__ + (*n - *k + i__) * v_dim1] = 1.; +/* Skip any leading zeros. */ + i__1 = i__ - 1; + for (lastv = 1; lastv <= i__1; ++lastv) { + if (v[i__ + lastv * v_dim1] != 0.) { + goto L36; + } + } +L36: + j = max(lastv,prevlastv); + +/* + T(i+1:k,i) := + - tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)' +*/ + + i__1 = *k - i__; + i__2 = *n - *k + i__ - j + 1; + d__1 = -tau[i__]; + dgemv_("No transpose", &i__1, &i__2, &d__1, &v[i__ + + 1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], + ldv, &c_b29, &t[i__ + 1 + i__ * t_dim1], & + c__1); + v[i__ + (*n - *k + i__) * v_dim1] = vii; + } + +/* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */ + + i__1 = *k - i__; + dtrmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ + + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ * + t_dim1], &c__1) + ; + if (i__ > 1) { + prevlastv = min(prevlastv,lastv); + } else { + prevlastv = lastv; + } + } + t[i__ + i__ * t_dim1] = tau[i__]; + } +/* L40: */ + } + } + return 0; + +/* End of DLARFT */ + +} /* dlarft_ */ + +/* Subroutine */ int dlarfx_(char *side, integer *m, integer *n, doublereal * + v, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work) +{ + /* System generated locals */ + integer c_dim1, c_offset, i__1; + + /* Local variables */ + static integer j; + static doublereal t1, t2, t3, t4, t5, t6, t7, t8, t9, v1, v2, v3, v4, v5, + v6, v7, v8, v9, t10, v10, sum; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *); + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLARFX applies a real elementary reflector H to a real m by n + matrix C, from either the left or the right. H is represented in the + form + + H = I - tau * v * v' + + where tau is a real scalar and v is a real vector. + + If tau = 0, then H is taken to be the unit matrix + + This version uses inline code if H has order < 11. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': form H * C + = 'R': form C * H + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + V (input) DOUBLE PRECISION array, dimension (M) if SIDE = 'L' + or (N) if SIDE = 'R' + The vector v in the representation of H. + + TAU (input) DOUBLE PRECISION + The value tau in the representation of H. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by the matrix H * C if SIDE = 'L', + or C * H if SIDE = 'R'. + + LDC (input) INTEGER + The leading dimension of the array C. LDA >= (1,M). + + WORK (workspace) DOUBLE PRECISION array, dimension + (N) if SIDE = 'L' + or (M) if SIDE = 'R' + WORK is not referenced if H has order < 11. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --v; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + if (*tau == 0.) { + return 0; + } + if (lsame_(side, "L")) { + +/* Form H * C, where H has order m. */ + + switch (*m) { + case 1: goto L10; + case 2: goto L30; + case 3: goto L50; + case 4: goto L70; + case 5: goto L90; + case 6: goto L110; + case 7: goto L130; + case 8: goto L150; + case 9: goto L170; + case 10: goto L190; + } + +/* Code for general M */ + + dlarf_(side, m, n, &v[1], &c__1, tau, &c__[c_offset], ldc, &work[1]); + goto L410; +L10: + +/* Special code for 1 x 1 Householder */ + + t1 = 1. - *tau * v[1] * v[1]; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + c__[j * c_dim1 + 1] = t1 * c__[j * c_dim1 + 1]; +/* L20: */ + } + goto L410; +L30: + +/* Special code for 2 x 2 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; +/* L40: */ + } + goto L410; +L50: + +/* Special code for 3 x 3 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; +/* L60: */ + } + goto L410; +L70: + +/* Special code for 4 x 4 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; +/* L80: */ + } + goto L410; +L90: + +/* Special code for 5 x 5 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; +/* L100: */ + } + goto L410; +L110: + +/* Special code for 6 x 6 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; +/* L120: */ + } + goto L410; +L130: + +/* Special code for 7 x 7 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * + c_dim1 + 7]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; + c__[j * c_dim1 + 7] -= sum * t7; +/* L140: */ + } + goto L410; +L150: + +/* Special code for 8 x 8 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * + c_dim1 + 7] + v8 * c__[j * c_dim1 + 8]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; + c__[j * c_dim1 + 7] -= sum * t7; + c__[j * c_dim1 + 8] -= sum * t8; +/* L160: */ + } + goto L410; +L170: + +/* Special code for 9 x 9 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + v9 = v[9]; + t9 = *tau * v9; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * + c_dim1 + 7] + v8 * c__[j * c_dim1 + 8] + v9 * c__[j * + c_dim1 + 9]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; + c__[j * c_dim1 + 7] -= sum * t7; + c__[j * c_dim1 + 8] -= sum * t8; + c__[j * c_dim1 + 9] -= sum * t9; +/* L180: */ + } + goto L410; +L190: + +/* Special code for 10 x 10 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + v9 = v[9]; + t9 = *tau * v9; + v10 = v[10]; + t10 = *tau * v10; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * + c_dim1 + 7] + v8 * c__[j * c_dim1 + 8] + v9 * c__[j * + c_dim1 + 9] + v10 * c__[j * c_dim1 + 10]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; + c__[j * c_dim1 + 7] -= sum * t7; + c__[j * c_dim1 + 8] -= sum * t8; + c__[j * c_dim1 + 9] -= sum * t9; + c__[j * c_dim1 + 10] -= sum * t10; +/* L200: */ + } + goto L410; + } else { + +/* Form C * H, where H has order n. */ + + switch (*n) { + case 1: goto L210; + case 2: goto L230; + case 3: goto L250; + case 4: goto L270; + case 5: goto L290; + case 6: goto L310; + case 7: goto L330; + case 8: goto L350; + case 9: goto L370; + case 10: goto L390; + } + +/* Code for general N */ + + dlarf_(side, m, n, &v[1], &c__1, tau, &c__[c_offset], ldc, &work[1]); + goto L410; +L210: + +/* Special code for 1 x 1 Householder */ + + t1 = 1. - *tau * v[1] * v[1]; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + c__[j + c_dim1] = t1 * c__[j + c_dim1]; +/* L220: */ + } + goto L410; +L230: + +/* Special code for 2 x 2 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; +/* L240: */ + } + goto L410; +L250: + +/* Special code for 3 x 3 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; +/* L260: */ + } + goto L410; +L270: + +/* Special code for 4 x 4 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; +/* L280: */ + } + goto L410; +L290: + +/* Special code for 5 x 5 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; +/* L300: */ + } + goto L410; +L310: + +/* Special code for 6 x 6 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; +/* L320: */ + } + goto L410; +L330: + +/* Special code for 7 x 7 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[ + j + c_dim1 * 7]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; + c__[j + c_dim1 * 7] -= sum * t7; +/* L340: */ + } + goto L410; +L350: + +/* Special code for 8 x 8 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[ + j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; + c__[j + c_dim1 * 7] -= sum * t7; + c__[j + (c_dim1 << 3)] -= sum * t8; +/* L360: */ + } + goto L410; +L370: + +/* Special code for 9 x 9 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + v9 = v[9]; + t9 = *tau * v9; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[ + j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)] + v9 * c__[ + j + c_dim1 * 9]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; + c__[j + c_dim1 * 7] -= sum * t7; + c__[j + (c_dim1 << 3)] -= sum * t8; + c__[j + c_dim1 * 9] -= sum * t9; +/* L380: */ + } + goto L410; +L390: + +/* Special code for 10 x 10 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + v9 = v[9]; + t9 = *tau * v9; + v10 = v[10]; + t10 = *tau * v10; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[ + j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)] + v9 * c__[ + j + c_dim1 * 9] + v10 * c__[j + c_dim1 * 10]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; + c__[j + c_dim1 * 7] -= sum * t7; + c__[j + (c_dim1 << 3)] -= sum * t8; + c__[j + c_dim1 * 9] -= sum * t9; + c__[j + c_dim1 * 10] -= sum * t10; +/* L400: */ + } + goto L410; + } +L410: + return 0; + +/* End of DLARFX */ + +} /* dlarfx_ */ + +/* Subroutine */ int dlartg_(doublereal *f, doublereal *g, doublereal *cs, + doublereal *sn, doublereal *r__) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__; + static doublereal f1, g1, eps, scale; + static integer count; + static doublereal safmn2, safmx2; + + static doublereal safmin; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLARTG generate a plane rotation so that + + [ CS SN ] . [ F ] = [ R ] where CS**2 + SN**2 = 1. + [ -SN CS ] [ G ] [ 0 ] + + This is a slower, more accurate version of the BLAS1 routine DROTG, + with the following other differences: + F and G are unchanged on return. + If G=0, then CS=1 and SN=0. + If F=0 and (G .ne. 0), then CS=0 and SN=1 without doing any + floating point operations (saves work in DBDSQR when + there are zeros on the diagonal). + + If F exceeds G in magnitude, CS will be positive. + + Arguments + ========= + + F (input) DOUBLE PRECISION + The first component of vector to be rotated. + + G (input) DOUBLE PRECISION + The second component of vector to be rotated. + + CS (output) DOUBLE PRECISION + The cosine of the rotation. + + SN (output) DOUBLE PRECISION + The sine of the rotation. + + R (output) DOUBLE PRECISION + The nonzero component of the rotated vector. + + This version has a few statements commented out for thread safety + (machine parameters are computed on each entry). 10 feb 03, SJH. + + ===================================================================== + + LOGICAL FIRST + SAVE FIRST, SAFMX2, SAFMIN, SAFMN2 + DATA FIRST / .TRUE. / + + IF( FIRST ) THEN +*/ + safmin = SAFEMINIMUM; + eps = EPSILON; + d__1 = BASE; + i__1 = (integer) (log(safmin / eps) / log(BASE) / 2.); + safmn2 = pow_di(&d__1, &i__1); + safmx2 = 1. / safmn2; +/* + FIRST = .FALSE. + END IF +*/ + if (*g == 0.) { + *cs = 1.; + *sn = 0.; + *r__ = *f; + } else if (*f == 0.) { + *cs = 0.; + *sn = 1.; + *r__ = *g; + } else { + f1 = *f; + g1 = *g; +/* Computing MAX */ + d__1 = abs(f1), d__2 = abs(g1); + scale = max(d__1,d__2); + if (scale >= safmx2) { + count = 0; +L10: + ++count; + f1 *= safmn2; + g1 *= safmn2; +/* Computing MAX */ + d__1 = abs(f1), d__2 = abs(g1); + scale = max(d__1,d__2); + if (scale >= safmx2) { + goto L10; + } +/* Computing 2nd power */ + d__1 = f1; +/* Computing 2nd power */ + d__2 = g1; + *r__ = sqrt(d__1 * d__1 + d__2 * d__2); + *cs = f1 / *r__; + *sn = g1 / *r__; + i__1 = count; + for (i__ = 1; i__ <= i__1; ++i__) { + *r__ *= safmx2; +/* L20: */ + } + } else if (scale <= safmn2) { + count = 0; +L30: + ++count; + f1 *= safmx2; + g1 *= safmx2; +/* Computing MAX */ + d__1 = abs(f1), d__2 = abs(g1); + scale = max(d__1,d__2); + if (scale <= safmn2) { + goto L30; + } +/* Computing 2nd power */ + d__1 = f1; +/* Computing 2nd power */ + d__2 = g1; + *r__ = sqrt(d__1 * d__1 + d__2 * d__2); + *cs = f1 / *r__; + *sn = g1 / *r__; + i__1 = count; + for (i__ = 1; i__ <= i__1; ++i__) { + *r__ *= safmn2; +/* L40: */ + } + } else { +/* Computing 2nd power */ + d__1 = f1; +/* Computing 2nd power */ + d__2 = g1; + *r__ = sqrt(d__1 * d__1 + d__2 * d__2); + *cs = f1 / *r__; + *sn = g1 / *r__; + } + if (abs(*f) > abs(*g) && *cs < 0.) { + *cs = -(*cs); + *sn = -(*sn); + *r__ = -(*r__); + } + } + return 0; + +/* End of DLARTG */ + +} /* dlartg_ */ + +/* Subroutine */ int dlas2_(doublereal *f, doublereal *g, doublereal *h__, + doublereal *ssmin, doublereal *ssmax) +{ + /* System generated locals */ + doublereal d__1, d__2; + + /* Local variables */ + static doublereal c__, fa, ga, ha, as, at, au, fhmn, fhmx; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAS2 computes the singular values of the 2-by-2 matrix + [ F G ] + [ 0 H ]. + On return, SSMIN is the smaller singular value and SSMAX is the + larger singular value. + + Arguments + ========= + + F (input) DOUBLE PRECISION + The (1,1) element of the 2-by-2 matrix. + + G (input) DOUBLE PRECISION + The (1,2) element of the 2-by-2 matrix. + + H (input) DOUBLE PRECISION + The (2,2) element of the 2-by-2 matrix. + + SSMIN (output) DOUBLE PRECISION + The smaller singular value. + + SSMAX (output) DOUBLE PRECISION + The larger singular value. + + Further Details + =============== + + Barring over/underflow, all output quantities are correct to within + a few units in the last place (ulps), even in the absence of a guard + digit in addition/subtraction. + + In IEEE arithmetic, the code works correctly if one matrix element is + infinite. + + Overflow will not occur unless the largest singular value itself + overflows, or is within a few ulps of overflow. (On machines with + partial overflow, like the Cray, overflow may occur if the largest + singular value is within a factor of 2 of overflow.) + + Underflow is harmless if underflow is gradual. Otherwise, results + may correspond to a matrix modified by perturbations of size near + the underflow threshold. + + ==================================================================== +*/ + + + fa = abs(*f); + ga = abs(*g); + ha = abs(*h__); + fhmn = min(fa,ha); + fhmx = max(fa,ha); + if (fhmn == 0.) { + *ssmin = 0.; + if (fhmx == 0.) { + *ssmax = ga; + } else { +/* Computing 2nd power */ + d__1 = min(fhmx,ga) / max(fhmx,ga); + *ssmax = max(fhmx,ga) * sqrt(d__1 * d__1 + 1.); + } + } else { + if (ga < fhmx) { + as = fhmn / fhmx + 1.; + at = (fhmx - fhmn) / fhmx; +/* Computing 2nd power */ + d__1 = ga / fhmx; + au = d__1 * d__1; + c__ = 2. / (sqrt(as * as + au) + sqrt(at * at + au)); + *ssmin = fhmn * c__; + *ssmax = fhmx / c__; + } else { + au = fhmx / ga; + if (au == 0.) { + +/* + Avoid possible harmful underflow if exponent range + asymmetric (true SSMIN may not underflow even if + AU underflows) +*/ + + *ssmin = fhmn * fhmx / ga; + *ssmax = ga; + } else { + as = fhmn / fhmx + 1.; + at = (fhmx - fhmn) / fhmx; +/* Computing 2nd power */ + d__1 = as * au; +/* Computing 2nd power */ + d__2 = at * au; + c__ = 1. / (sqrt(d__1 * d__1 + 1.) + sqrt(d__2 * d__2 + 1.)); + *ssmin = fhmn * c__ * au; + *ssmin += *ssmin; + *ssmax = ga / (c__ + c__); + } + } + } + return 0; + +/* End of DLAS2 */ + +} /* dlas2_ */ + +/* Subroutine */ int dlascl_(char *type__, integer *kl, integer *ku, + doublereal *cfrom, doublereal *cto, integer *m, integer *n, + doublereal *a, integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + + /* Local variables */ + static integer i__, j, k1, k2, k3, k4; + static doublereal mul, cto1; + static logical done; + static doublereal ctoc; + extern logical lsame_(char *, char *); + static integer itype; + static doublereal cfrom1; + + static doublereal cfromc; + extern logical disnan_(doublereal *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static doublereal bignum, smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASCL multiplies the M by N real matrix A by the real scalar + CTO/CFROM. This is done without over/underflow as long as the final + result CTO*A(I,J)/CFROM does not over/underflow. TYPE specifies that + A may be full, upper triangular, lower triangular, upper Hessenberg, + or banded. + + Arguments + ========= + + TYPE (input) CHARACTER*1 + TYPE indices the storage type of the input matrix. + = 'G': A is a full matrix. + = 'L': A is a lower triangular matrix. + = 'U': A is an upper triangular matrix. + = 'H': A is an upper Hessenberg matrix. + = 'B': A is a symmetric band matrix with lower bandwidth KL + and upper bandwidth KU and with the only the lower + half stored. + = 'Q': A is a symmetric band matrix with lower bandwidth KL + and upper bandwidth KU and with the only the upper + half stored. + = 'Z': A is a band matrix with lower bandwidth KL and upper + bandwidth KU. + + KL (input) INTEGER + The lower bandwidth of A. Referenced only if TYPE = 'B', + 'Q' or 'Z'. + + KU (input) INTEGER + The upper bandwidth of A. Referenced only if TYPE = 'B', + 'Q' or 'Z'. + + CFROM (input) DOUBLE PRECISION + CTO (input) DOUBLE PRECISION + The matrix A is multiplied by CTO/CFROM. A(I,J) is computed + without over/underflow if the final result CTO*A(I,J)/CFROM + can be represented without over/underflow. CFROM must be + nonzero. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + The matrix to be multiplied by CTO/CFROM. See TYPE for the + storage type. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + INFO (output) INTEGER + 0 - successful exit + <0 - if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + + if (lsame_(type__, "G")) { + itype = 0; + } else if (lsame_(type__, "L")) { + itype = 1; + } else if (lsame_(type__, "U")) { + itype = 2; + } else if (lsame_(type__, "H")) { + itype = 3; + } else if (lsame_(type__, "B")) { + itype = 4; + } else if (lsame_(type__, "Q")) { + itype = 5; + } else if (lsame_(type__, "Z")) { + itype = 6; + } else { + itype = -1; + } + + if (itype == -1) { + *info = -1; + } else if (*cfrom == 0. || disnan_(cfrom)) { + *info = -4; + } else if (disnan_(cto)) { + *info = -5; + } else if (*m < 0) { + *info = -6; + } else if (*n < 0 || itype == 4 && *n != *m || itype == 5 && *n != *m) { + *info = -7; + } else if (itype <= 3 && *lda < max(1,*m)) { + *info = -9; + } else if (itype >= 4) { +/* Computing MAX */ + i__1 = *m - 1; + if (*kl < 0 || *kl > max(i__1,0)) { + *info = -2; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = *n - 1; + if (*ku < 0 || *ku > max(i__1,0) || (itype == 4 || itype == 5) && + *kl != *ku) { + *info = -3; + } else if (itype == 4 && *lda < *kl + 1 || itype == 5 && *lda < * + ku + 1 || itype == 6 && *lda < (*kl << 1) + *ku + 1) { + *info = -9; + } + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASCL", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *m == 0) { + return 0; + } + +/* Get machine parameters */ + + smlnum = SAFEMINIMUM; + bignum = 1. / smlnum; + + cfromc = *cfrom; + ctoc = *cto; + +L10: + cfrom1 = cfromc * smlnum; + if (cfrom1 == cfromc) { +/* + CFROMC is an inf. Multiply by a correctly signed zero for + finite CTOC, or a NaN if CTOC is infinite. +*/ + mul = ctoc / cfromc; + done = TRUE_; + cto1 = ctoc; + } else { + cto1 = ctoc / bignum; + if (cto1 == ctoc) { +/* + CTOC is either 0 or an inf. In both cases, CTOC itself + serves as the correct multiplication factor. +*/ + mul = ctoc; + done = TRUE_; + cfromc = 1.; + } else if (abs(cfrom1) > abs(ctoc) && ctoc != 0.) { + mul = smlnum; + done = FALSE_; + cfromc = cfrom1; + } else if (abs(cto1) > abs(cfromc)) { + mul = bignum; + done = FALSE_; + ctoc = cto1; + } else { + mul = ctoc / cfromc; + done = TRUE_; + } + } + + if (itype == 0) { + +/* Full matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L20: */ + } +/* L30: */ + } + + } else if (itype == 1) { + +/* Lower triangular matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L40: */ + } +/* L50: */ + } + + } else if (itype == 2) { + +/* Upper triangular matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L60: */ + } +/* L70: */ + } + + } else if (itype == 3) { + +/* Upper Hessenberg matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = j + 1; + i__2 = min(i__3,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L80: */ + } +/* L90: */ + } + + } else if (itype == 4) { + +/* Lower half of a symmetric band matrix */ + + k3 = *kl + 1; + k4 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = k3, i__4 = k4 - j; + i__2 = min(i__3,i__4); + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L100: */ + } +/* L110: */ + } + + } else if (itype == 5) { + +/* Upper half of a symmetric band matrix */ + + k1 = *ku + 2; + k3 = *ku + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = k1 - j; + i__3 = k3; + for (i__ = max(i__2,1); i__ <= i__3; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L120: */ + } +/* L130: */ + } + + } else if (itype == 6) { + +/* Band matrix */ + + k1 = *kl + *ku + 2; + k2 = *kl + 1; + k3 = (*kl << 1) + *ku + 1; + k4 = *kl + *ku + 1 + *m; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__3 = k1 - j; +/* Computing MIN */ + i__4 = k3, i__5 = k4 - j; + i__2 = min(i__4,i__5); + for (i__ = max(i__3,k2); i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L140: */ + } +/* L150: */ + } + + } + + if (! done) { + goto L10; + } + + return 0; + +/* End of DLASCL */ + +} /* dlascl_ */ + +/* Subroutine */ int dlasd0_(integer *n, integer *sqre, doublereal *d__, + doublereal *e, doublereal *u, integer *ldu, doublereal *vt, integer * + ldvt, integer *smlsiz, integer *iwork, doublereal *work, integer * + info) +{ + /* System generated locals */ + integer u_dim1, u_offset, vt_dim1, vt_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, m, i1, ic, lf, nd, ll, nl, nr, im1, ncc, nlf, nrf, + iwk, lvl, ndb1, nlp1, nrp1; + static doublereal beta; + static integer idxq, nlvl; + static doublereal alpha; + static integer inode, ndiml, idxqc, ndimr, itemp, sqrei; + extern /* Subroutine */ int dlasd1_(integer *, integer *, integer *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *, + doublereal *, integer *, integer *, integer *, doublereal *, + integer *), dlasdq_(char *, integer *, integer *, integer *, + integer *, integer *, doublereal *, doublereal *, doublereal *, + integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *), dlasdt_(integer *, integer *, + integer *, integer *, integer *, integer *, integer *), xerbla_( + char *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + Using a divide and conquer approach, DLASD0 computes the singular + value decomposition (SVD) of a real upper bidiagonal N-by-M + matrix B with diagonal D and offdiagonal E, where M = N + SQRE. + The algorithm computes orthogonal matrices U and VT such that + B = U * S * VT. The singular values S are overwritten on D. + + A related subroutine, DLASDA, computes only the singular values, + and optionally, the singular vectors in compact form. + + Arguments + ========= + + N (input) INTEGER + On entry, the row dimension of the upper bidiagonal matrix. + This is also the dimension of the main diagonal array D. + + SQRE (input) INTEGER + Specifies the column dimension of the bidiagonal matrix. + = 0: The bidiagonal matrix has column dimension M = N; + = 1: The bidiagonal matrix has column dimension M = N+1; + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry D contains the main diagonal of the bidiagonal + matrix. + On exit D, if INFO = 0, contains its singular values. + + E (input) DOUBLE PRECISION array, dimension (M-1) + Contains the subdiagonal entries of the bidiagonal matrix. + On exit, E has been destroyed. + + U (output) DOUBLE PRECISION array, dimension at least (LDQ, N) + On exit, U contains the left singular vectors. + + LDU (input) INTEGER + On entry, leading dimension of U. + + VT (output) DOUBLE PRECISION array, dimension at least (LDVT, M) + On exit, VT' contains the right singular vectors. + + LDVT (input) INTEGER + On entry, leading dimension of VT. + + SMLSIZ (input) INTEGER + On entry, maximum size of the subproblems at the + bottom of the computation tree. + + IWORK (workspace) INTEGER work array. + Dimension must be at least (8 * N) + + WORK (workspace) DOUBLE PRECISION work array. + Dimension must be at least (3 * M**2 + 2 * M) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --iwork; + --work; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -1; + } else if (*sqre < 0 || *sqre > 1) { + *info = -2; + } + + m = *n + *sqre; + + if (*ldu < *n) { + *info = -6; + } else if (*ldvt < m) { + *info = -8; + } else if (*smlsiz < 3) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASD0", &i__1); + return 0; + } + +/* If the input matrix is too small, call DLASDQ to find the SVD. */ + + if (*n <= *smlsiz) { + dlasdq_("U", sqre, n, &m, n, &c__0, &d__[1], &e[1], &vt[vt_offset], + ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[1], info); + return 0; + } + +/* Set up the computation tree. */ + + inode = 1; + ndiml = inode + *n; + ndimr = ndiml + *n; + idxq = ndimr + *n; + iwk = idxq + *n; + dlasdt_(n, &nlvl, &nd, &iwork[inode], &iwork[ndiml], &iwork[ndimr], + smlsiz); + +/* + For the nodes on bottom level of the tree, solve + their subproblems by DLASDQ. +*/ + + ndb1 = (nd + 1) / 2; + ncc = 0; + i__1 = nd; + for (i__ = ndb1; i__ <= i__1; ++i__) { + +/* + IC : center row of each node + NL : number of rows of left subproblem + NR : number of rows of right subproblem + NLF: starting row of the left subproblem + NRF: starting row of the right subproblem +*/ + + i1 = i__ - 1; + ic = iwork[inode + i1]; + nl = iwork[ndiml + i1]; + nlp1 = nl + 1; + nr = iwork[ndimr + i1]; + nrp1 = nr + 1; + nlf = ic - nl; + nrf = ic + 1; + sqrei = 1; + dlasdq_("U", &sqrei, &nl, &nlp1, &nl, &ncc, &d__[nlf], &e[nlf], &vt[ + nlf + nlf * vt_dim1], ldvt, &u[nlf + nlf * u_dim1], ldu, &u[ + nlf + nlf * u_dim1], ldu, &work[1], info); + if (*info != 0) { + return 0; + } + itemp = idxq + nlf - 2; + i__2 = nl; + for (j = 1; j <= i__2; ++j) { + iwork[itemp + j] = j; +/* L10: */ + } + if (i__ == nd) { + sqrei = *sqre; + } else { + sqrei = 1; + } + nrp1 = nr + sqrei; + dlasdq_("U", &sqrei, &nr, &nrp1, &nr, &ncc, &d__[nrf], &e[nrf], &vt[ + nrf + nrf * vt_dim1], ldvt, &u[nrf + nrf * u_dim1], ldu, &u[ + nrf + nrf * u_dim1], ldu, &work[1], info); + if (*info != 0) { + return 0; + } + itemp = idxq + ic; + i__2 = nr; + for (j = 1; j <= i__2; ++j) { + iwork[itemp + j - 1] = j; +/* L20: */ + } +/* L30: */ + } + +/* Now conquer each subproblem bottom-up. */ + + for (lvl = nlvl; lvl >= 1; --lvl) { + +/* + Find the first node LF and last node LL on the + current level LVL. +*/ + + if (lvl == 1) { + lf = 1; + ll = 1; + } else { + i__1 = lvl - 1; + lf = pow_ii(&c__2, &i__1); + ll = (lf << 1) - 1; + } + i__1 = ll; + for (i__ = lf; i__ <= i__1; ++i__) { + im1 = i__ - 1; + ic = iwork[inode + im1]; + nl = iwork[ndiml + im1]; + nr = iwork[ndimr + im1]; + nlf = ic - nl; + if (*sqre == 0 && i__ == ll) { + sqrei = *sqre; + } else { + sqrei = 1; + } + idxqc = idxq + nlf - 1; + alpha = d__[ic]; + beta = e[ic]; + dlasd1_(&nl, &nr, &sqrei, &d__[nlf], &alpha, &beta, &u[nlf + nlf * + u_dim1], ldu, &vt[nlf + nlf * vt_dim1], ldvt, &iwork[ + idxqc], &iwork[iwk], &work[1], info); + if (*info != 0) { + return 0; + } +/* L40: */ + } +/* L50: */ + } + + return 0; + +/* End of DLASD0 */ + +} /* dlasd0_ */ + +/* Subroutine */ int dlasd1_(integer *nl, integer *nr, integer *sqre, + doublereal *d__, doublereal *alpha, doublereal *beta, doublereal *u, + integer *ldu, doublereal *vt, integer *ldvt, integer *idxq, integer * + iwork, doublereal *work, integer *info) +{ + /* System generated locals */ + integer u_dim1, u_offset, vt_dim1, vt_offset, i__1; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__, k, m, n, n1, n2, iq, iz, iu2, ldq, idx, ldu2, ivt2, + idxc, idxp, ldvt2; + extern /* Subroutine */ int dlasd2_(integer *, integer *, integer *, + integer *, doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, integer *, + integer *, integer *, integer *, integer *, integer *), dlasd3_( + integer *, integer *, integer *, integer *, doublereal *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *, integer *, integer *, doublereal *, integer *), + dlascl_(char *, integer *, integer *, doublereal *, doublereal *, + integer *, integer *, doublereal *, integer *, integer *), + dlamrg_(integer *, integer *, doublereal *, integer *, integer *, + integer *); + static integer isigma; + extern /* Subroutine */ int xerbla_(char *, integer *); + static doublereal orgnrm; + static integer coltyp; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLASD1 computes the SVD of an upper bidiagonal N-by-M matrix B, + where N = NL + NR + 1 and M = N + SQRE. DLASD1 is called from DLASD0. + + A related subroutine DLASD7 handles the case in which the singular + values (and the singular vectors in factored form) are desired. + + DLASD1 computes the SVD as follows: + + ( D1(in) 0 0 0 ) + B = U(in) * ( Z1' a Z2' b ) * VT(in) + ( 0 0 D2(in) 0 ) + + = U(out) * ( D(out) 0) * VT(out) + + where Z' = (Z1' a Z2' b) = u' VT', and u is a vector of dimension M + with ALPHA and BETA in the NL+1 and NL+2 th entries and zeros + elsewhere; and the entry b is empty if SQRE = 0. + + The left singular vectors of the original matrix are stored in U, and + the transpose of the right singular vectors are stored in VT, and the + singular values are in D. The algorithm consists of three stages: + + The first stage consists of deflating the size of the problem + when there are multiple singular values or when there are zeros in + the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine DLASD2. + + The second stage consists of calculating the updated + singular values. This is done by finding the square roots of the + roots of the secular equation via the routine DLASD4 (as called + by DLASD3). This routine also calculates the singular vectors of + the current problem. + + The final stage consists of computing the updated singular vectors + directly using the updated singular values. The singular vectors + for the current problem are multiplied with the singular vectors + from the overall problem. + + Arguments + ========= + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has row dimension N = NL + NR + 1, + and column dimension M = N + SQRE. + + D (input/output) DOUBLE PRECISION array, + dimension (N = NL+NR+1). + On entry D(1:NL,1:NL) contains the singular values of the + upper block; and D(NL+2:N) contains the singular values of + the lower block. On exit D(1:N) contains the singular values + of the modified matrix. + + ALPHA (input/output) DOUBLE PRECISION + Contains the diagonal element associated with the added row. + + BETA (input/output) DOUBLE PRECISION + Contains the off-diagonal element associated with the added + row. + + U (input/output) DOUBLE PRECISION array, dimension(LDU,N) + On entry U(1:NL, 1:NL) contains the left singular vectors of + the upper block; U(NL+2:N, NL+2:N) contains the left singular + vectors of the lower block. On exit U contains the left + singular vectors of the bidiagonal matrix. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= max( 1, N ). + + VT (input/output) DOUBLE PRECISION array, dimension(LDVT,M) + where M = N + SQRE. + On entry VT(1:NL+1, 1:NL+1)' contains the right singular + vectors of the upper block; VT(NL+2:M, NL+2:M)' contains + the right singular vectors of the lower block. On exit + VT' contains the right singular vectors of the + bidiagonal matrix. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= max( 1, M ). + + IDXQ (output) INTEGER array, dimension(N) + This contains the permutation which will reintegrate the + subproblem just solved back into sorted order, i.e. + D( IDXQ( I = 1, N ) ) will be in ascending order. + + IWORK (workspace) INTEGER array, dimension( 4 * N ) + + WORK (workspace) DOUBLE PRECISION array, dimension( 3*M**2 + 2*M ) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --idxq; + --iwork; + --work; + + /* Function Body */ + *info = 0; + + if (*nl < 1) { + *info = -1; + } else if (*nr < 1) { + *info = -2; + } else if (*sqre < 0 || *sqre > 1) { + *info = -3; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASD1", &i__1); + return 0; + } + + n = *nl + *nr + 1; + m = n + *sqre; + +/* + The following values are for bookkeeping purposes only. They are + integer pointers which indicate the portion of the workspace + used by a particular array in DLASD2 and DLASD3. +*/ + + ldu2 = n; + ldvt2 = m; + + iz = 1; + isigma = iz + m; + iu2 = isigma + n; + ivt2 = iu2 + ldu2 * n; + iq = ivt2 + ldvt2 * m; + + idx = 1; + idxc = idx + n; + coltyp = idxc + n; + idxp = coltyp + n; + +/* + Scale. + + Computing MAX +*/ + d__1 = abs(*alpha), d__2 = abs(*beta); + orgnrm = max(d__1,d__2); + d__[*nl + 1] = 0.; + i__1 = n; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((d__1 = d__[i__], abs(d__1)) > orgnrm) { + orgnrm = (d__1 = d__[i__], abs(d__1)); + } +/* L10: */ + } + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &n, &c__1, &d__[1], &n, info); + *alpha /= orgnrm; + *beta /= orgnrm; + +/* Deflate singular values. */ + + dlasd2_(nl, nr, sqre, &k, &d__[1], &work[iz], alpha, beta, &u[u_offset], + ldu, &vt[vt_offset], ldvt, &work[isigma], &work[iu2], &ldu2, & + work[ivt2], &ldvt2, &iwork[idxp], &iwork[idx], &iwork[idxc], & + idxq[1], &iwork[coltyp], info); + +/* Solve Secular Equation and update singular vectors. */ + + ldq = k; + dlasd3_(nl, nr, sqre, &k, &d__[1], &work[iq], &ldq, &work[isigma], &u[ + u_offset], ldu, &work[iu2], &ldu2, &vt[vt_offset], ldvt, &work[ + ivt2], &ldvt2, &iwork[idxc], &iwork[coltyp], &work[iz], info); + if (*info != 0) { + return 0; + } + +/* Unscale. */ + + dlascl_("G", &c__0, &c__0, &c_b15, &orgnrm, &n, &c__1, &d__[1], &n, info); + +/* Prepare the IDXQ sorting permutation. */ + + n1 = k; + n2 = n - k; + dlamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &idxq[1]); + + return 0; + +/* End of DLASD1 */ + +} /* dlasd1_ */ + +/* Subroutine */ int dlasd2_(integer *nl, integer *nr, integer *sqre, integer + *k, doublereal *d__, doublereal *z__, doublereal *alpha, doublereal * + beta, doublereal *u, integer *ldu, doublereal *vt, integer *ldvt, + doublereal *dsigma, doublereal *u2, integer *ldu2, doublereal *vt2, + integer *ldvt2, integer *idxp, integer *idx, integer *idxc, integer * + idxq, integer *coltyp, integer *info) +{ + /* System generated locals */ + integer u_dim1, u_offset, u2_dim1, u2_offset, vt_dim1, vt_offset, + vt2_dim1, vt2_offset, i__1; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal c__; + static integer i__, j, m, n; + static doublereal s; + static integer k2; + static doublereal z1; + static integer ct, jp; + static doublereal eps, tau, tol; + static integer psm[4], nlp1, nlp2, idxi, idxj; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *); + static integer ctot[4], idxjp; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer jprev; + + extern /* Subroutine */ int dlamrg_(integer *, integer *, doublereal *, + integer *, integer *, integer *), dlacpy_(char *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *), dlaset_(char *, integer *, integer *, doublereal *, + doublereal *, doublereal *, integer *), xerbla_(char *, + integer *); + static doublereal hlftol; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASD2 merges the two sets of singular values together into a single + sorted set. Then it tries to deflate the size of the problem. + There are two ways in which deflation can occur: when two or more + singular values are close together or if there is a tiny entry in the + Z vector. For each such occurrence the order of the related secular + equation problem is reduced by one. + + DLASD2 is called from DLASD1. + + Arguments + ========= + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has N = NL + NR + 1 rows and + M = N + SQRE >= N columns. + + K (output) INTEGER + Contains the dimension of the non-deflated matrix, + This is the order of the related secular equation. 1 <= K <=N. + + D (input/output) DOUBLE PRECISION array, dimension(N) + On entry D contains the singular values of the two submatrices + to be combined. On exit D contains the trailing (N-K) updated + singular values (those which were deflated) sorted into + increasing order. + + Z (output) DOUBLE PRECISION array, dimension(N) + On exit Z contains the updating row vector in the secular + equation. + + ALPHA (input) DOUBLE PRECISION + Contains the diagonal element associated with the added row. + + BETA (input) DOUBLE PRECISION + Contains the off-diagonal element associated with the added + row. + + U (input/output) DOUBLE PRECISION array, dimension(LDU,N) + On entry U contains the left singular vectors of two + submatrices in the two square blocks with corners at (1,1), + (NL, NL), and (NL+2, NL+2), (N,N). + On exit U contains the trailing (N-K) updated left singular + vectors (those which were deflated) in its last N-K columns. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= N. + + VT (input/output) DOUBLE PRECISION array, dimension(LDVT,M) + On entry VT' contains the right singular vectors of two + submatrices in the two square blocks with corners at (1,1), + (NL+1, NL+1), and (NL+2, NL+2), (M,M). + On exit VT' contains the trailing (N-K) updated right singular + vectors (those which were deflated) in its last N-K columns. + In case SQRE =1, the last row of VT spans the right null + space. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= M. + + DSIGMA (output) DOUBLE PRECISION array, dimension (N) + Contains a copy of the diagonal elements (K-1 singular values + and one zero) in the secular equation. + + U2 (output) DOUBLE PRECISION array, dimension(LDU2,N) + Contains a copy of the first K-1 left singular vectors which + will be used by DLASD3 in a matrix multiply (DGEMM) to solve + for the new left singular vectors. U2 is arranged into four + blocks. The first block contains a column with 1 at NL+1 and + zero everywhere else; the second block contains non-zero + entries only at and above NL; the third contains non-zero + entries only below NL+1; and the fourth is dense. + + LDU2 (input) INTEGER + The leading dimension of the array U2. LDU2 >= N. + + VT2 (output) DOUBLE PRECISION array, dimension(LDVT2,N) + VT2' contains a copy of the first K right singular vectors + which will be used by DLASD3 in a matrix multiply (DGEMM) to + solve for the new right singular vectors. VT2 is arranged into + three blocks. The first block contains a row that corresponds + to the special 0 diagonal element in SIGMA; the second block + contains non-zeros only at and before NL +1; the third block + contains non-zeros only at and after NL +2. + + LDVT2 (input) INTEGER + The leading dimension of the array VT2. LDVT2 >= M. + + IDXP (workspace) INTEGER array dimension(N) + This will contain the permutation used to place deflated + values of D at the end of the array. On output IDXP(2:K) + points to the nondeflated D-values and IDXP(K+1:N) + points to the deflated singular values. + + IDX (workspace) INTEGER array dimension(N) + This will contain the permutation used to sort the contents of + D into ascending order. + + IDXC (output) INTEGER array dimension(N) + This will contain the permutation used to arrange the columns + of the deflated U matrix into three groups: the first group + contains non-zero entries only at and above NL, the second + contains non-zero entries only below NL+2, and the third is + dense. + + IDXQ (input/output) INTEGER array dimension(N) + This contains the permutation which separately sorts the two + sub-problems in D into ascending order. Note that entries in + the first hlaf of this permutation must first be moved one + position backward; and entries in the second half + must first have NL+1 added to their values. + + COLTYP (workspace/output) INTEGER array dimension(N) + As workspace, this will contain a label which will indicate + which of the following types a column in the U2 matrix or a + row in the VT2 matrix is: + 1 : non-zero in the upper half only + 2 : non-zero in the lower half only + 3 : dense + 4 : deflated + + On exit, it is an array of dimension 4, with COLTYP(I) being + the dimension of the I-th type columns. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --z__; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --dsigma; + u2_dim1 = *ldu2; + u2_offset = 1 + u2_dim1; + u2 -= u2_offset; + vt2_dim1 = *ldvt2; + vt2_offset = 1 + vt2_dim1; + vt2 -= vt2_offset; + --idxp; + --idx; + --idxc; + --idxq; + --coltyp; + + /* Function Body */ + *info = 0; + + if (*nl < 1) { + *info = -1; + } else if (*nr < 1) { + *info = -2; + } else if (*sqre != 1 && *sqre != 0) { + *info = -3; + } + + n = *nl + *nr + 1; + m = n + *sqre; + + if (*ldu < n) { + *info = -10; + } else if (*ldvt < m) { + *info = -12; + } else if (*ldu2 < n) { + *info = -15; + } else if (*ldvt2 < m) { + *info = -17; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASD2", &i__1); + return 0; + } + + nlp1 = *nl + 1; + nlp2 = *nl + 2; + +/* + Generate the first part of the vector Z; and move the singular + values in the first part of D one position backward. +*/ + + z1 = *alpha * vt[nlp1 + nlp1 * vt_dim1]; + z__[1] = z1; + for (i__ = *nl; i__ >= 1; --i__) { + z__[i__ + 1] = *alpha * vt[i__ + nlp1 * vt_dim1]; + d__[i__ + 1] = d__[i__]; + idxq[i__ + 1] = idxq[i__] + 1; +/* L10: */ + } + +/* Generate the second part of the vector Z. */ + + i__1 = m; + for (i__ = nlp2; i__ <= i__1; ++i__) { + z__[i__] = *beta * vt[i__ + nlp2 * vt_dim1]; +/* L20: */ + } + +/* Initialize some reference arrays. */ + + i__1 = nlp1; + for (i__ = 2; i__ <= i__1; ++i__) { + coltyp[i__] = 1; +/* L30: */ + } + i__1 = n; + for (i__ = nlp2; i__ <= i__1; ++i__) { + coltyp[i__] = 2; +/* L40: */ + } + +/* Sort the singular values into increasing order */ + + i__1 = n; + for (i__ = nlp2; i__ <= i__1; ++i__) { + idxq[i__] += nlp1; +/* L50: */ + } + +/* + DSIGMA, IDXC, IDXC, and the first column of U2 + are used as storage space. +*/ + + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + dsigma[i__] = d__[idxq[i__]]; + u2[i__ + u2_dim1] = z__[idxq[i__]]; + idxc[i__] = coltyp[idxq[i__]]; +/* L60: */ + } + + dlamrg_(nl, nr, &dsigma[2], &c__1, &c__1, &idx[2]); + + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + idxi = idx[i__] + 1; + d__[i__] = dsigma[idxi]; + z__[i__] = u2[idxi + u2_dim1]; + coltyp[i__] = idxc[idxi]; +/* L70: */ + } + +/* Calculate the allowable deflation tolerance */ + + eps = EPSILON; +/* Computing MAX */ + d__1 = abs(*alpha), d__2 = abs(*beta); + tol = max(d__1,d__2); +/* Computing MAX */ + d__2 = (d__1 = d__[n], abs(d__1)); + tol = eps * 8. * max(d__2,tol); + +/* + There are 2 kinds of deflation -- first a value in the z-vector + is small, second two (or more) singular values are very close + together (their difference is small). + + If the value in the z-vector is small, we simply permute the + array so that the corresponding singular value is moved to the + end. + + If two values in the D-vector are close, we perform a two-sided + rotation designed to make one of the corresponding z-vector + entries zero, and then permute the array so that the deflated + singular value is moved to the end. + + If there are multiple singular values then the problem deflates. + Here the number of equal singular values are found. As each equal + singular value is found, an elementary reflector is computed to + rotate the corresponding singular subspace so that the + corresponding components of Z are zero in this new basis. +*/ + + *k = 1; + k2 = n + 1; + i__1 = n; + for (j = 2; j <= i__1; ++j) { + if ((d__1 = z__[j], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + idxp[k2] = j; + coltyp[j] = 4; + if (j == n) { + goto L120; + } + } else { + jprev = j; + goto L90; + } +/* L80: */ + } +L90: + j = jprev; +L100: + ++j; + if (j > n) { + goto L110; + } + if ((d__1 = z__[j], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + idxp[k2] = j; + coltyp[j] = 4; + } else { + +/* Check if singular values are close enough to allow deflation. */ + + if ((d__1 = d__[j] - d__[jprev], abs(d__1)) <= tol) { + +/* Deflation is possible. */ + + s = z__[jprev]; + c__ = z__[j]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = dlapy2_(&c__, &s); + c__ /= tau; + s = -s / tau; + z__[j] = tau; + z__[jprev] = 0.; + +/* + Apply back the Givens rotation to the left and right + singular vector matrices. +*/ + + idxjp = idxq[idx[jprev] + 1]; + idxj = idxq[idx[j] + 1]; + if (idxjp <= nlp1) { + --idxjp; + } + if (idxj <= nlp1) { + --idxj; + } + drot_(&n, &u[idxjp * u_dim1 + 1], &c__1, &u[idxj * u_dim1 + 1], & + c__1, &c__, &s); + drot_(&m, &vt[idxjp + vt_dim1], ldvt, &vt[idxj + vt_dim1], ldvt, & + c__, &s); + if (coltyp[j] != coltyp[jprev]) { + coltyp[j] = 3; + } + coltyp[jprev] = 4; + --k2; + idxp[k2] = jprev; + jprev = j; + } else { + ++(*k); + u2[*k + u2_dim1] = z__[jprev]; + dsigma[*k] = d__[jprev]; + idxp[*k] = jprev; + jprev = j; + } + } + goto L100; +L110: + +/* Record the last singular value. */ + + ++(*k); + u2[*k + u2_dim1] = z__[jprev]; + dsigma[*k] = d__[jprev]; + idxp[*k] = jprev; + +L120: + +/* + Count up the total number of the various types of columns, then + form a permutation which positions the four column types into + four groups of uniform structure (although one or more of these + groups may be empty). +*/ + + for (j = 1; j <= 4; ++j) { + ctot[j - 1] = 0; +/* L130: */ + } + i__1 = n; + for (j = 2; j <= i__1; ++j) { + ct = coltyp[j]; + ++ctot[ct - 1]; +/* L140: */ + } + +/* PSM(*) = Position in SubMatrix (of types 1 through 4) */ + + psm[0] = 2; + psm[1] = ctot[0] + 2; + psm[2] = psm[1] + ctot[1]; + psm[3] = psm[2] + ctot[2]; + +/* + Fill out the IDXC array so that the permutation which it induces + will place all type-1 columns first, all type-2 columns next, + then all type-3's, and finally all type-4's, starting from the + second column. This applies similarly to the rows of VT. +*/ + + i__1 = n; + for (j = 2; j <= i__1; ++j) { + jp = idxp[j]; + ct = coltyp[jp]; + idxc[psm[ct - 1]] = j; + ++psm[ct - 1]; +/* L150: */ + } + +/* + Sort the singular values and corresponding singular vectors into + DSIGMA, U2, and VT2 respectively. The singular values/vectors + which were not deflated go into the first K slots of DSIGMA, U2, + and VT2 respectively, while those which were deflated go into the + last N - K slots, except that the first column/row will be treated + separately. +*/ + + i__1 = n; + for (j = 2; j <= i__1; ++j) { + jp = idxp[j]; + dsigma[j] = d__[jp]; + idxj = idxq[idx[idxp[idxc[j]]] + 1]; + if (idxj <= nlp1) { + --idxj; + } + dcopy_(&n, &u[idxj * u_dim1 + 1], &c__1, &u2[j * u2_dim1 + 1], &c__1); + dcopy_(&m, &vt[idxj + vt_dim1], ldvt, &vt2[j + vt2_dim1], ldvt2); +/* L160: */ + } + +/* Determine DSIGMA(1), DSIGMA(2) and Z(1) */ + + dsigma[1] = 0.; + hlftol = tol / 2.; + if (abs(dsigma[2]) <= hlftol) { + dsigma[2] = hlftol; + } + if (m > n) { + z__[1] = dlapy2_(&z1, &z__[m]); + if (z__[1] <= tol) { + c__ = 1.; + s = 0.; + z__[1] = tol; + } else { + c__ = z1 / z__[1]; + s = z__[m] / z__[1]; + } + } else { + if (abs(z1) <= tol) { + z__[1] = tol; + } else { + z__[1] = z1; + } + } + +/* Move the rest of the updating row to Z. */ + + i__1 = *k - 1; + dcopy_(&i__1, &u2[u2_dim1 + 2], &c__1, &z__[2], &c__1); + +/* + Determine the first column of U2, the first row of VT2 and the + last row of VT. +*/ + + dlaset_("A", &n, &c__1, &c_b29, &c_b29, &u2[u2_offset], ldu2); + u2[nlp1 + u2_dim1] = 1.; + if (m > n) { + i__1 = nlp1; + for (i__ = 1; i__ <= i__1; ++i__) { + vt[m + i__ * vt_dim1] = -s * vt[nlp1 + i__ * vt_dim1]; + vt2[i__ * vt2_dim1 + 1] = c__ * vt[nlp1 + i__ * vt_dim1]; +/* L170: */ + } + i__1 = m; + for (i__ = nlp2; i__ <= i__1; ++i__) { + vt2[i__ * vt2_dim1 + 1] = s * vt[m + i__ * vt_dim1]; + vt[m + i__ * vt_dim1] = c__ * vt[m + i__ * vt_dim1]; +/* L180: */ + } + } else { + dcopy_(&m, &vt[nlp1 + vt_dim1], ldvt, &vt2[vt2_dim1 + 1], ldvt2); + } + if (m > n) { + dcopy_(&m, &vt[m + vt_dim1], ldvt, &vt2[m + vt2_dim1], ldvt2); + } + +/* + The deflated singular values and their corresponding vectors go + into the back of D, U, and V respectively. +*/ + + if (n > *k) { + i__1 = n - *k; + dcopy_(&i__1, &dsigma[*k + 1], &c__1, &d__[*k + 1], &c__1); + i__1 = n - *k; + dlacpy_("A", &n, &i__1, &u2[(*k + 1) * u2_dim1 + 1], ldu2, &u[(*k + 1) + * u_dim1 + 1], ldu); + i__1 = n - *k; + dlacpy_("A", &i__1, &m, &vt2[*k + 1 + vt2_dim1], ldvt2, &vt[*k + 1 + + vt_dim1], ldvt); + } + +/* Copy CTOT into COLTYP for referencing in DLASD3. */ + + for (j = 1; j <= 4; ++j) { + coltyp[j] = ctot[j - 1]; +/* L190: */ + } + + return 0; + +/* End of DLASD2 */ + +} /* dlasd2_ */ + +/* Subroutine */ int dlasd3_(integer *nl, integer *nr, integer *sqre, integer + *k, doublereal *d__, doublereal *q, integer *ldq, doublereal *dsigma, + doublereal *u, integer *ldu, doublereal *u2, integer *ldu2, + doublereal *vt, integer *ldvt, doublereal *vt2, integer *ldvt2, + integer *idxc, integer *ctot, doublereal *z__, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, u_dim1, u_offset, u2_dim1, u2_offset, vt_dim1, + vt_offset, vt2_dim1, vt2_offset, i__1, i__2; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__, j, m, n, jc; + static doublereal rho; + static integer nlp1, nlp2, nrp1; + static doublereal temp; + extern doublereal dnrm2_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer ctemp; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer ktemp; + extern doublereal dlamc3_(doublereal *, doublereal *); + extern /* Subroutine */ int dlasd4_(integer *, integer *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *), dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dlacpy_(char *, integer *, integer + *, doublereal *, integer *, doublereal *, integer *), + xerbla_(char *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLASD3 finds all the square roots of the roots of the secular + equation, as defined by the values in D and Z. It makes the + appropriate calls to DLASD4 and then updates the singular + vectors by matrix multiplication. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray XMP, Cray YMP, Cray C 90, or Cray 2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + DLASD3 is called from DLASD1. + + Arguments + ========= + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has N = NL + NR + 1 rows and + M = N + SQRE >= N columns. + + K (input) INTEGER + The size of the secular equation, 1 =< K = < N. + + D (output) DOUBLE PRECISION array, dimension(K) + On exit the square roots of the roots of the secular equation, + in ascending order. + + Q (workspace) DOUBLE PRECISION array, + dimension at least (LDQ,K). + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= K. + + DSIGMA (input) DOUBLE PRECISION array, dimension(K) + The first K elements of this array contain the old roots + of the deflated updating problem. These are the poles + of the secular equation. + + U (output) DOUBLE PRECISION array, dimension (LDU, N) + The last N - K columns of this matrix contain the deflated + left singular vectors. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= N. + + U2 (input/output) DOUBLE PRECISION array, dimension (LDU2, N) + The first K columns of this matrix contain the non-deflated + left singular vectors for the split problem. + + LDU2 (input) INTEGER + The leading dimension of the array U2. LDU2 >= N. + + VT (output) DOUBLE PRECISION array, dimension (LDVT, M) + The last M - K columns of VT' contain the deflated + right singular vectors. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= N. + + VT2 (input/output) DOUBLE PRECISION array, dimension (LDVT2, N) + The first K columns of VT2' contain the non-deflated + right singular vectors for the split problem. + + LDVT2 (input) INTEGER + The leading dimension of the array VT2. LDVT2 >= N. + + IDXC (input) INTEGER array, dimension ( N ) + The permutation used to arrange the columns of U (and rows of + VT) into three groups: the first group contains non-zero + entries only at and above (or before) NL +1; the second + contains non-zero entries only at and below (or after) NL+2; + and the third is dense. The first column of U and the row of + VT are treated separately, however. + + The rows of the singular vectors found by DLASD4 + must be likewise permuted before the matrix multiplies can + take place. + + CTOT (input) INTEGER array, dimension ( 4 ) + A count of the total number of the various types of columns + in U (or rows in VT), as described in IDXC. The fourth column + type is any column which has been deflated. + + Z (input) DOUBLE PRECISION array, dimension (K) + The first K elements of this array contain the components + of the deflation-adjusted updating row vector. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --dsigma; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + u2_dim1 = *ldu2; + u2_offset = 1 + u2_dim1; + u2 -= u2_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + vt2_dim1 = *ldvt2; + vt2_offset = 1 + vt2_dim1; + vt2 -= vt2_offset; + --idxc; + --ctot; + --z__; + + /* Function Body */ + *info = 0; + + if (*nl < 1) { + *info = -1; + } else if (*nr < 1) { + *info = -2; + } else if (*sqre != 1 && *sqre != 0) { + *info = -3; + } + + n = *nl + *nr + 1; + m = n + *sqre; + nlp1 = *nl + 1; + nlp2 = *nl + 2; + + if (*k < 1 || *k > n) { + *info = -4; + } else if (*ldq < *k) { + *info = -7; + } else if (*ldu < n) { + *info = -10; + } else if (*ldu2 < n) { + *info = -12; + } else if (*ldvt < m) { + *info = -14; + } else if (*ldvt2 < m) { + *info = -16; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASD3", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*k == 1) { + d__[1] = abs(z__[1]); + dcopy_(&m, &vt2[vt2_dim1 + 1], ldvt2, &vt[vt_dim1 + 1], ldvt); + if (z__[1] > 0.) { + dcopy_(&n, &u2[u2_dim1 + 1], &c__1, &u[u_dim1 + 1], &c__1); + } else { + i__1 = n; + for (i__ = 1; i__ <= i__1; ++i__) { + u[i__ + u_dim1] = -u2[i__ + u2_dim1]; +/* L10: */ + } + } + return 0; + } + +/* + Modify values DSIGMA(i) to make sure all DSIGMA(i)-DSIGMA(j) can + be computed with high relative accuracy (barring over/underflow). + This is a problem on machines without a guard digit in + add/subtract (Cray XMP, Cray YMP, Cray C 90 and Cray 2). + The following code replaces DSIGMA(I) by 2*DSIGMA(I)-DSIGMA(I), + which on any of these machines zeros out the bottommost + bit of DSIGMA(I) if it is 1; this makes the subsequent + subtractions DSIGMA(I)-DSIGMA(J) unproblematic when cancellation + occurs. On binary machines with a guard digit (almost all + machines) it does not change DSIGMA(I) at all. On hexadecimal + and decimal machines with a guard digit, it slightly + changes the bottommost bits of DSIGMA(I). It does not account + for hexadecimal or decimal machines without guard digits + (we know of none). We use a subroutine call to compute + 2*DSIGMA(I) to prevent optimizing compilers from eliminating + this code. +*/ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + dsigma[i__] = dlamc3_(&dsigma[i__], &dsigma[i__]) - dsigma[i__]; +/* L20: */ + } + +/* Keep a copy of Z. */ + + dcopy_(k, &z__[1], &c__1, &q[q_offset], &c__1); + +/* Normalize Z. */ + + rho = dnrm2_(k, &z__[1], &c__1); + dlascl_("G", &c__0, &c__0, &rho, &c_b15, k, &c__1, &z__[1], k, info); + rho *= rho; + +/* Find the new singular values. */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dlasd4_(k, &j, &dsigma[1], &z__[1], &u[j * u_dim1 + 1], &rho, &d__[j], + &vt[j * vt_dim1 + 1], info); + +/* If the zero finder fails, the computation is terminated. */ + + if (*info != 0) { + return 0; + } +/* L30: */ + } + +/* Compute updated Z. */ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + z__[i__] = u[i__ + *k * u_dim1] * vt[i__ + *k * vt_dim1]; + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + z__[i__] *= u[i__ + j * u_dim1] * vt[i__ + j * vt_dim1] / (dsigma[ + i__] - dsigma[j]) / (dsigma[i__] + dsigma[j]); +/* L40: */ + } + i__2 = *k - 1; + for (j = i__; j <= i__2; ++j) { + z__[i__] *= u[i__ + j * u_dim1] * vt[i__ + j * vt_dim1] / (dsigma[ + i__] - dsigma[j + 1]) / (dsigma[i__] + dsigma[j + 1]); +/* L50: */ + } + d__2 = sqrt((d__1 = z__[i__], abs(d__1))); + z__[i__] = d_sign(&d__2, &q[i__ + q_dim1]); +/* L60: */ + } + +/* + Compute left singular vectors of the modified diagonal matrix, + and store related information for the right singular vectors. +*/ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + vt[i__ * vt_dim1 + 1] = z__[1] / u[i__ * u_dim1 + 1] / vt[i__ * + vt_dim1 + 1]; + u[i__ * u_dim1 + 1] = -1.; + i__2 = *k; + for (j = 2; j <= i__2; ++j) { + vt[j + i__ * vt_dim1] = z__[j] / u[j + i__ * u_dim1] / vt[j + i__ + * vt_dim1]; + u[j + i__ * u_dim1] = dsigma[j] * vt[j + i__ * vt_dim1]; +/* L70: */ + } + temp = dnrm2_(k, &u[i__ * u_dim1 + 1], &c__1); + q[i__ * q_dim1 + 1] = u[i__ * u_dim1 + 1] / temp; + i__2 = *k; + for (j = 2; j <= i__2; ++j) { + jc = idxc[j]; + q[j + i__ * q_dim1] = u[jc + i__ * u_dim1] / temp; +/* L80: */ + } +/* L90: */ + } + +/* Update the left singular vector matrix. */ + + if (*k == 2) { + dgemm_("N", "N", &n, k, k, &c_b15, &u2[u2_offset], ldu2, &q[q_offset], + ldq, &c_b29, &u[u_offset], ldu); + goto L100; + } + if (ctot[1] > 0) { + dgemm_("N", "N", nl, k, &ctot[1], &c_b15, &u2[(u2_dim1 << 1) + 1], + ldu2, &q[q_dim1 + 2], ldq, &c_b29, &u[u_dim1 + 1], ldu); + if (ctot[3] > 0) { + ktemp = ctot[1] + 2 + ctot[2]; + dgemm_("N", "N", nl, k, &ctot[3], &c_b15, &u2[ktemp * u2_dim1 + 1] + , ldu2, &q[ktemp + q_dim1], ldq, &c_b15, &u[u_dim1 + 1], + ldu); + } + } else if (ctot[3] > 0) { + ktemp = ctot[1] + 2 + ctot[2]; + dgemm_("N", "N", nl, k, &ctot[3], &c_b15, &u2[ktemp * u2_dim1 + 1], + ldu2, &q[ktemp + q_dim1], ldq, &c_b29, &u[u_dim1 + 1], ldu); + } else { + dlacpy_("F", nl, k, &u2[u2_offset], ldu2, &u[u_offset], ldu); + } + dcopy_(k, &q[q_dim1 + 1], ldq, &u[nlp1 + u_dim1], ldu); + ktemp = ctot[1] + 2; + ctemp = ctot[2] + ctot[3]; + dgemm_("N", "N", nr, k, &ctemp, &c_b15, &u2[nlp2 + ktemp * u2_dim1], ldu2, + &q[ktemp + q_dim1], ldq, &c_b29, &u[nlp2 + u_dim1], ldu); + +/* Generate the right singular vectors. */ + +L100: + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = dnrm2_(k, &vt[i__ * vt_dim1 + 1], &c__1); + q[i__ + q_dim1] = vt[i__ * vt_dim1 + 1] / temp; + i__2 = *k; + for (j = 2; j <= i__2; ++j) { + jc = idxc[j]; + q[i__ + j * q_dim1] = vt[jc + i__ * vt_dim1] / temp; +/* L110: */ + } +/* L120: */ + } + +/* Update the right singular vector matrix. */ + + if (*k == 2) { + dgemm_("N", "N", k, &m, k, &c_b15, &q[q_offset], ldq, &vt2[vt2_offset] + , ldvt2, &c_b29, &vt[vt_offset], ldvt); + return 0; + } + ktemp = ctot[1] + 1; + dgemm_("N", "N", k, &nlp1, &ktemp, &c_b15, &q[q_dim1 + 1], ldq, &vt2[ + vt2_dim1 + 1], ldvt2, &c_b29, &vt[vt_dim1 + 1], ldvt); + ktemp = ctot[1] + 2 + ctot[2]; + if (ktemp <= *ldvt2) { + dgemm_("N", "N", k, &nlp1, &ctot[3], &c_b15, &q[ktemp * q_dim1 + 1], + ldq, &vt2[ktemp + vt2_dim1], ldvt2, &c_b15, &vt[vt_dim1 + 1], + ldvt); + } + + ktemp = ctot[1] + 1; + nrp1 = *nr + *sqre; + if (ktemp > 1) { + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + q[i__ + ktemp * q_dim1] = q[i__ + q_dim1]; +/* L130: */ + } + i__1 = m; + for (i__ = nlp2; i__ <= i__1; ++i__) { + vt2[ktemp + i__ * vt2_dim1] = vt2[i__ * vt2_dim1 + 1]; +/* L140: */ + } + } + ctemp = ctot[2] + 1 + ctot[3]; + dgemm_("N", "N", k, &nrp1, &ctemp, &c_b15, &q[ktemp * q_dim1 + 1], ldq, & + vt2[ktemp + nlp2 * vt2_dim1], ldvt2, &c_b29, &vt[nlp2 * vt_dim1 + + 1], ldvt); + + return 0; + +/* End of DLASD3 */ + +} /* dlasd3_ */ + +/* Subroutine */ int dlasd4_(integer *n, integer *i__, doublereal *d__, + doublereal *z__, doublereal *delta, doublereal *rho, doublereal * + sigma, doublereal *work, integer *info) +{ + /* System generated locals */ + integer i__1; + doublereal d__1; + + /* Local variables */ + static doublereal a, b, c__; + static integer j; + static doublereal w, dd[3]; + static integer ii; + static doublereal dw, zz[3]; + static integer ip1; + static doublereal eta, phi, eps, tau, psi; + static integer iim1, iip1; + static doublereal dphi, dpsi; + static integer iter; + static doublereal temp, prew, sg2lb, sg2ub, temp1, temp2, dtiim, delsq, + dtiip; + static integer niter; + static doublereal dtisq; + static logical swtch; + static doublereal dtnsq; + extern /* Subroutine */ int dlaed6_(integer *, logical *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *) + , dlasd5_(integer *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *); + static doublereal delsq2, dtnsq1; + static logical swtch3; + + static logical orgati; + static doublereal erretm, dtipsq, rhoinv; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This subroutine computes the square root of the I-th updated + eigenvalue of a positive symmetric rank-one modification to + a positive diagonal matrix whose entries are given as the squares + of the corresponding entries in the array d, and that + + 0 <= D(i) < D(j) for i < j + + and that RHO > 0. This is arranged by the calling routine, and is + no loss in generality. The rank-one modified system is thus + + diag( D ) * diag( D ) + RHO * Z * Z_transpose. + + where we assume the Euclidean norm of Z is 1. + + The method consists of approximating the rational functions in the + secular equation by simpler interpolating rational functions. + + Arguments + ========= + + N (input) INTEGER + The length of all arrays. + + I (input) INTEGER + The index of the eigenvalue to be computed. 1 <= I <= N. + + D (input) DOUBLE PRECISION array, dimension ( N ) + The original eigenvalues. It is assumed that they are in + order, 0 <= D(I) < D(J) for I < J. + + Z (input) DOUBLE PRECISION array, dimension ( N ) + The components of the updating vector. + + DELTA (output) DOUBLE PRECISION array, dimension ( N ) + If N .ne. 1, DELTA contains (D(j) - sigma_I) in its j-th + component. If N = 1, then DELTA(1) = 1. The vector DELTA + contains the information necessary to construct the + (singular) eigenvectors. + + RHO (input) DOUBLE PRECISION + The scalar in the symmetric updating formula. + + SIGMA (output) DOUBLE PRECISION + The computed sigma_I, the I-th updated eigenvalue. + + WORK (workspace) DOUBLE PRECISION array, dimension ( N ) + If N .ne. 1, WORK contains (D(j) + sigma_I) in its j-th + component. If N = 1, then WORK( 1 ) = 1. + + INFO (output) INTEGER + = 0: successful exit + > 0: if INFO = 1, the updating process failed. + + Internal Parameters + =================== + + Logical variable ORGATI (origin-at-i?) is used for distinguishing + whether D(i) or D(i+1) is treated as the origin. + + ORGATI = .true. origin at i + ORGATI = .false. origin at i+1 + + Logical variable SWTCH3 (switch-for-3-poles?) is for noting + if we are working with THREE poles! + + MAXIT is the maximum number of iterations allowed for each + eigenvalue. + + Further Details + =============== + + Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Since this routine is called in an inner loop, we do no argument + checking. + + Quick return for N=1 and 2. +*/ + + /* Parameter adjustments */ + --work; + --delta; + --z__; + --d__; + + /* Function Body */ + *info = 0; + if (*n == 1) { + +/* Presumably, I=1 upon entry */ + + *sigma = sqrt(d__[1] * d__[1] + *rho * z__[1] * z__[1]); + delta[1] = 1.; + work[1] = 1.; + return 0; + } + if (*n == 2) { + dlasd5_(i__, &d__[1], &z__[1], &delta[1], rho, sigma, &work[1]); + return 0; + } + +/* Compute machine epsilon */ + + eps = EPSILON; + rhoinv = 1. / *rho; + +/* The case I = N */ + + if (*i__ == *n) { + +/* Initialize some basic variables */ + + ii = *n - 1; + niter = 1; + +/* Calculate initial guess */ + + temp = *rho / 2.; + +/* + If ||Z||_2 is not one, then TEMP should be set to + RHO * ||Z||_2^2 / TWO +*/ + + temp1 = temp / (d__[*n] + sqrt(d__[*n] * d__[*n] + temp)); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] = d__[j] + d__[*n] + temp1; + delta[j] = d__[j] - d__[*n] - temp1; +/* L10: */ + } + + psi = 0.; + i__1 = *n - 2; + for (j = 1; j <= i__1; ++j) { + psi += z__[j] * z__[j] / (delta[j] * work[j]); +/* L20: */ + } + + c__ = rhoinv + psi; + w = c__ + z__[ii] * z__[ii] / (delta[ii] * work[ii]) + z__[*n] * z__[* + n] / (delta[*n] * work[*n]); + + if (w <= 0.) { + temp1 = sqrt(d__[*n] * d__[*n] + *rho); + temp = z__[*n - 1] * z__[*n - 1] / ((d__[*n - 1] + temp1) * (d__[* + n] - d__[*n - 1] + *rho / (d__[*n] + temp1))) + z__[*n] * + z__[*n] / *rho; + +/* + The following TAU is to approximate + SIGMA_n^2 - D( N )*D( N ) +*/ + + if (c__ <= temp) { + tau = *rho; + } else { + delsq = (d__[*n] - d__[*n - 1]) * (d__[*n] + d__[*n - 1]); + a = -c__ * delsq + z__[*n - 1] * z__[*n - 1] + z__[*n] * z__[* + n]; + b = z__[*n] * z__[*n] * delsq; + if (a < 0.) { + tau = b * 2. / (sqrt(a * a + b * 4. * c__) - a); + } else { + tau = (a + sqrt(a * a + b * 4. * c__)) / (c__ * 2.); + } + } + +/* + It can be proved that + D(N)^2+RHO/2 <= SIGMA_n^2 < D(N)^2+TAU <= D(N)^2+RHO +*/ + + } else { + delsq = (d__[*n] - d__[*n - 1]) * (d__[*n] + d__[*n - 1]); + a = -c__ * delsq + z__[*n - 1] * z__[*n - 1] + z__[*n] * z__[*n]; + b = z__[*n] * z__[*n] * delsq; + +/* + The following TAU is to approximate + SIGMA_n^2 - D( N )*D( N ) +*/ + + if (a < 0.) { + tau = b * 2. / (sqrt(a * a + b * 4. * c__) - a); + } else { + tau = (a + sqrt(a * a + b * 4. * c__)) / (c__ * 2.); + } + +/* + It can be proved that + D(N)^2 < D(N)^2+TAU < SIGMA(N)^2 < D(N)^2+RHO/2 +*/ + + } + +/* The following ETA is to approximate SIGMA_n - D( N ) */ + + eta = tau / (d__[*n] + sqrt(d__[*n] * d__[*n] + tau)); + + *sigma = d__[*n] + eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - eta; + work[j] = d__[j] + d__[*i__] + eta; +/* L30: */ + } + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (delta[j] * work[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L40: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / (delta[*n] * work[*n]); + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8. + erretm - phi + rhoinv + abs(tau) * (dpsi + + dphi); + + w = rhoinv + phi + psi; + +/* Test for convergence */ + + if (abs(w) <= eps * erretm) { + goto L240; + } + +/* Calculate the new step */ + + ++niter; + dtnsq1 = work[*n - 1] * delta[*n - 1]; + dtnsq = work[*n] * delta[*n]; + c__ = w - dtnsq1 * dpsi - dtnsq * dphi; + a = (dtnsq + dtnsq1) * w - dtnsq * dtnsq1 * (dpsi + dphi); + b = dtnsq * dtnsq1 * w; + if (c__ < 0.) { + c__ = abs(c__); + } + if (c__ == 0.) { + eta = *rho - *sigma * *sigma; + } else if (a >= 0.) { + eta = (a + sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / (c__ + * 2.); + } else { + eta = b * 2. / (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1))) + ); + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta > 0.) { + eta = -w / (dpsi + dphi); + } + temp = eta - dtnsq; + if (temp > *rho) { + eta = *rho + dtnsq; + } + + tau += eta; + eta /= *sigma + sqrt(eta + *sigma * *sigma); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; + work[j] += eta; +/* L50: */ + } + + *sigma += eta; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L60: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / (work[*n] * delta[*n]); + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8. + erretm - phi + rhoinv + abs(tau) * (dpsi + + dphi); + + w = rhoinv + phi + psi; + +/* Main loop to update the values of the array DELTA */ + + iter = niter + 1; + + for (niter = iter; niter <= 20; ++niter) { + +/* Test for convergence */ + + if (abs(w) <= eps * erretm) { + goto L240; + } + +/* Calculate the new step */ + + dtnsq1 = work[*n - 1] * delta[*n - 1]; + dtnsq = work[*n] * delta[*n]; + c__ = w - dtnsq1 * dpsi - dtnsq * dphi; + a = (dtnsq + dtnsq1) * w - dtnsq1 * dtnsq * (dpsi + dphi); + b = dtnsq1 * dtnsq * w; + if (a >= 0.) { + eta = (a + sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / ( + c__ * 2.); + } else { + eta = b * 2. / (a - sqrt((d__1 = a * a - b * 4. * c__, abs( + d__1)))); + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta > 0.) { + eta = -w / (dpsi + dphi); + } + temp = eta - dtnsq; + if (temp <= 0.) { + eta /= 2.; + } + + tau += eta; + eta /= *sigma + sqrt(eta + *sigma * *sigma); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; + work[j] += eta; +/* L70: */ + } + + *sigma += eta; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L80: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / (work[*n] * delta[*n]); + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8. + erretm - phi + rhoinv + abs(tau) * ( + dpsi + dphi); + + w = rhoinv + phi + psi; +/* L90: */ + } + +/* Return with INFO = 1, NITER = MAXIT and not converged */ + + *info = 1; + goto L240; + +/* End for the case I = N */ + + } else { + +/* The case for I < N */ + + niter = 1; + ip1 = *i__ + 1; + +/* Calculate initial guess */ + + delsq = (d__[ip1] - d__[*i__]) * (d__[ip1] + d__[*i__]); + delsq2 = delsq / 2.; + temp = delsq2 / (d__[*i__] + sqrt(d__[*i__] * d__[*i__] + delsq2)); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] = d__[j] + d__[*i__] + temp; + delta[j] = d__[j] - d__[*i__] - temp; +/* L100: */ + } + + psi = 0.; + i__1 = *i__ - 1; + for (j = 1; j <= i__1; ++j) { + psi += z__[j] * z__[j] / (work[j] * delta[j]); +/* L110: */ + } + + phi = 0.; + i__1 = *i__ + 2; + for (j = *n; j >= i__1; --j) { + phi += z__[j] * z__[j] / (work[j] * delta[j]); +/* L120: */ + } + c__ = rhoinv + psi + phi; + w = c__ + z__[*i__] * z__[*i__] / (work[*i__] * delta[*i__]) + z__[ + ip1] * z__[ip1] / (work[ip1] * delta[ip1]); + + if (w > 0.) { + +/* + d(i)^2 < the ith sigma^2 < (d(i)^2+d(i+1)^2)/2 + + We choose d(i) as origin. +*/ + + orgati = TRUE_; + sg2lb = 0.; + sg2ub = delsq2; + a = c__ * delsq + z__[*i__] * z__[*i__] + z__[ip1] * z__[ip1]; + b = z__[*i__] * z__[*i__] * delsq; + if (a > 0.) { + tau = b * 2. / (a + sqrt((d__1 = a * a - b * 4. * c__, abs( + d__1)))); + } else { + tau = (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / ( + c__ * 2.); + } + +/* + TAU now is an estimation of SIGMA^2 - D( I )^2. The + following, however, is the corresponding estimation of + SIGMA - D( I ). +*/ + + eta = tau / (d__[*i__] + sqrt(d__[*i__] * d__[*i__] + tau)); + } else { + +/* + (d(i)^2+d(i+1)^2)/2 <= the ith sigma^2 < d(i+1)^2/2 + + We choose d(i+1) as origin. +*/ + + orgati = FALSE_; + sg2lb = -delsq2; + sg2ub = 0.; + a = c__ * delsq - z__[*i__] * z__[*i__] - z__[ip1] * z__[ip1]; + b = z__[ip1] * z__[ip1] * delsq; + if (a < 0.) { + tau = b * 2. / (a - sqrt((d__1 = a * a + b * 4. * c__, abs( + d__1)))); + } else { + tau = -(a + sqrt((d__1 = a * a + b * 4. * c__, abs(d__1)))) / + (c__ * 2.); + } + +/* + TAU now is an estimation of SIGMA^2 - D( IP1 )^2. The + following, however, is the corresponding estimation of + SIGMA - D( IP1 ). +*/ + + eta = tau / (d__[ip1] + sqrt((d__1 = d__[ip1] * d__[ip1] + tau, + abs(d__1)))); + } + + if (orgati) { + ii = *i__; + *sigma = d__[*i__] + eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] = d__[j] + d__[*i__] + eta; + delta[j] = d__[j] - d__[*i__] - eta; +/* L130: */ + } + } else { + ii = *i__ + 1; + *sigma = d__[ip1] + eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] = d__[j] + d__[ip1] + eta; + delta[j] = d__[j] - d__[ip1] - eta; +/* L140: */ + } + } + iim1 = ii - 1; + iip1 = ii + 1; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L150: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.; + phi = 0.; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / (work[j] * delta[j]); + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L160: */ + } + + w = rhoinv + phi + psi; + +/* + W is the value of the secular function with + its ii-th element removed. +*/ + + swtch3 = FALSE_; + if (orgati) { + if (w < 0.) { + swtch3 = TRUE_; + } + } else { + if (w > 0.) { + swtch3 = TRUE_; + } + } + if (ii == 1 || ii == *n) { + swtch3 = FALSE_; + } + + temp = z__[ii] / (work[ii] * delta[ii]); + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w += temp; + erretm = (phi - psi) * 8. + erretm + rhoinv * 2. + abs(temp) * 3. + + abs(tau) * dw; + +/* Test for convergence */ + + if (abs(w) <= eps * erretm) { + goto L240; + } + + if (w <= 0.) { + sg2lb = max(sg2lb,tau); + } else { + sg2ub = min(sg2ub,tau); + } + +/* Calculate the new step */ + + ++niter; + if (! swtch3) { + dtipsq = work[ip1] * delta[ip1]; + dtisq = work[*i__] * delta[*i__]; + if (orgati) { +/* Computing 2nd power */ + d__1 = z__[*i__] / dtisq; + c__ = w - dtipsq * dw + delsq * (d__1 * d__1); + } else { +/* Computing 2nd power */ + d__1 = z__[ip1] / dtipsq; + c__ = w - dtisq * dw - delsq * (d__1 * d__1); + } + a = (dtipsq + dtisq) * w - dtipsq * dtisq * dw; + b = dtipsq * dtisq * w; + if (c__ == 0.) { + if (a == 0.) { + if (orgati) { + a = z__[*i__] * z__[*i__] + dtipsq * dtipsq * (dpsi + + dphi); + } else { + a = z__[ip1] * z__[ip1] + dtisq * dtisq * (dpsi + + dphi); + } + } + eta = b / a; + } else if (a <= 0.) { + eta = (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) / ( + c__ * 2.); + } else { + eta = b * 2. / (a + sqrt((d__1 = a * a - b * 4. * c__, abs( + d__1)))); + } + } else { + +/* Interpolation using THREE most relevant poles */ + + dtiim = work[iim1] * delta[iim1]; + dtiip = work[iip1] * delta[iip1]; + temp = rhoinv + psi + phi; + if (orgati) { + temp1 = z__[iim1] / dtiim; + temp1 *= temp1; + c__ = temp - dtiip * (dpsi + dphi) - (d__[iim1] - d__[iip1]) * + (d__[iim1] + d__[iip1]) * temp1; + zz[0] = z__[iim1] * z__[iim1]; + if (dpsi < temp1) { + zz[2] = dtiip * dtiip * dphi; + } else { + zz[2] = dtiip * dtiip * (dpsi - temp1 + dphi); + } + } else { + temp1 = z__[iip1] / dtiip; + temp1 *= temp1; + c__ = temp - dtiim * (dpsi + dphi) - (d__[iip1] - d__[iim1]) * + (d__[iim1] + d__[iip1]) * temp1; + if (dphi < temp1) { + zz[0] = dtiim * dtiim * dpsi; + } else { + zz[0] = dtiim * dtiim * (dpsi + (dphi - temp1)); + } + zz[2] = z__[iip1] * z__[iip1]; + } + zz[1] = z__[ii] * z__[ii]; + dd[0] = dtiim; + dd[1] = delta[ii] * work[ii]; + dd[2] = dtiip; + dlaed6_(&niter, &orgati, &c__, dd, zz, &w, &eta, info); + if (*info != 0) { + goto L240; + } + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta >= 0.) { + eta = -w / dw; + } + if (orgati) { + temp1 = work[*i__] * delta[*i__]; + temp = eta - temp1; + } else { + temp1 = work[ip1] * delta[ip1]; + temp = eta - temp1; + } + if (temp > sg2ub || temp < sg2lb) { + if (w < 0.) { + eta = (sg2ub - tau) / 2.; + } else { + eta = (sg2lb - tau) / 2.; + } + } + + tau += eta; + eta /= *sigma + sqrt(*sigma * *sigma + eta); + + prew = w; + + *sigma += eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] += eta; + delta[j] -= eta; +/* L170: */ + } + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L180: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.; + phi = 0.; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / (work[j] * delta[j]); + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L190: */ + } + + temp = z__[ii] / (work[ii] * delta[ii]); + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w = rhoinv + phi + psi + temp; + erretm = (phi - psi) * 8. + erretm + rhoinv * 2. + abs(temp) * 3. + + abs(tau) * dw; + + if (w <= 0.) { + sg2lb = max(sg2lb,tau); + } else { + sg2ub = min(sg2ub,tau); + } + + swtch = FALSE_; + if (orgati) { + if (-w > abs(prew) / 10.) { + swtch = TRUE_; + } + } else { + if (w > abs(prew) / 10.) { + swtch = TRUE_; + } + } + +/* Main loop to update the values of the array DELTA and WORK */ + + iter = niter + 1; + + for (niter = iter; niter <= 20; ++niter) { + +/* Test for convergence */ + + if (abs(w) <= eps * erretm) { + goto L240; + } + +/* Calculate the new step */ + + if (! swtch3) { + dtipsq = work[ip1] * delta[ip1]; + dtisq = work[*i__] * delta[*i__]; + if (! swtch) { + if (orgati) { +/* Computing 2nd power */ + d__1 = z__[*i__] / dtisq; + c__ = w - dtipsq * dw + delsq * (d__1 * d__1); + } else { +/* Computing 2nd power */ + d__1 = z__[ip1] / dtipsq; + c__ = w - dtisq * dw - delsq * (d__1 * d__1); + } + } else { + temp = z__[ii] / (work[ii] * delta[ii]); + if (orgati) { + dpsi += temp * temp; + } else { + dphi += temp * temp; + } + c__ = w - dtisq * dpsi - dtipsq * dphi; + } + a = (dtipsq + dtisq) * w - dtipsq * dtisq * dw; + b = dtipsq * dtisq * w; + if (c__ == 0.) { + if (a == 0.) { + if (! swtch) { + if (orgati) { + a = z__[*i__] * z__[*i__] + dtipsq * dtipsq * + (dpsi + dphi); + } else { + a = z__[ip1] * z__[ip1] + dtisq * dtisq * ( + dpsi + dphi); + } + } else { + a = dtisq * dtisq * dpsi + dtipsq * dtipsq * dphi; + } + } + eta = b / a; + } else if (a <= 0.) { + eta = (a - sqrt((d__1 = a * a - b * 4. * c__, abs(d__1)))) + / (c__ * 2.); + } else { + eta = b * 2. / (a + sqrt((d__1 = a * a - b * 4. * c__, + abs(d__1)))); + } + } else { + +/* Interpolation using THREE most relevant poles */ + + dtiim = work[iim1] * delta[iim1]; + dtiip = work[iip1] * delta[iip1]; + temp = rhoinv + psi + phi; + if (swtch) { + c__ = temp - dtiim * dpsi - dtiip * dphi; + zz[0] = dtiim * dtiim * dpsi; + zz[2] = dtiip * dtiip * dphi; + } else { + if (orgati) { + temp1 = z__[iim1] / dtiim; + temp1 *= temp1; + temp2 = (d__[iim1] - d__[iip1]) * (d__[iim1] + d__[ + iip1]) * temp1; + c__ = temp - dtiip * (dpsi + dphi) - temp2; + zz[0] = z__[iim1] * z__[iim1]; + if (dpsi < temp1) { + zz[2] = dtiip * dtiip * dphi; + } else { + zz[2] = dtiip * dtiip * (dpsi - temp1 + dphi); + } + } else { + temp1 = z__[iip1] / dtiip; + temp1 *= temp1; + temp2 = (d__[iip1] - d__[iim1]) * (d__[iim1] + d__[ + iip1]) * temp1; + c__ = temp - dtiim * (dpsi + dphi) - temp2; + if (dphi < temp1) { + zz[0] = dtiim * dtiim * dpsi; + } else { + zz[0] = dtiim * dtiim * (dpsi + (dphi - temp1)); + } + zz[2] = z__[iip1] * z__[iip1]; + } + } + dd[0] = dtiim; + dd[1] = delta[ii] * work[ii]; + dd[2] = dtiip; + dlaed6_(&niter, &orgati, &c__, dd, zz, &w, &eta, info); + if (*info != 0) { + goto L240; + } + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta >= 0.) { + eta = -w / dw; + } + if (orgati) { + temp1 = work[*i__] * delta[*i__]; + temp = eta - temp1; + } else { + temp1 = work[ip1] * delta[ip1]; + temp = eta - temp1; + } + if (temp > sg2ub || temp < sg2lb) { + if (w < 0.) { + eta = (sg2ub - tau) / 2.; + } else { + eta = (sg2lb - tau) / 2.; + } + } + + tau += eta; + eta /= *sigma + sqrt(*sigma * *sigma + eta); + + *sigma += eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] += eta; + delta[j] -= eta; +/* L200: */ + } + + prew = w; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.; + psi = 0.; + erretm = 0.; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L210: */ + } + erretm = abs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.; + phi = 0.; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / (work[j] * delta[j]); + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L220: */ + } + + temp = z__[ii] / (work[ii] * delta[ii]); + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w = rhoinv + phi + psi + temp; + erretm = (phi - psi) * 8. + erretm + rhoinv * 2. + abs(temp) * 3. + + abs(tau) * dw; + if (w * prew > 0. && abs(w) > abs(prew) / 10.) { + swtch = ! swtch; + } + + if (w <= 0.) { + sg2lb = max(sg2lb,tau); + } else { + sg2ub = min(sg2ub,tau); + } + +/* L230: */ + } + +/* Return with INFO = 1, NITER = MAXIT and not converged */ + + *info = 1; + + } + +L240: + return 0; + +/* End of DLASD4 */ + +} /* dlasd4_ */ + +/* Subroutine */ int dlasd5_(integer *i__, doublereal *d__, doublereal *z__, + doublereal *delta, doublereal *rho, doublereal *dsigma, doublereal * + work) +{ + /* System generated locals */ + doublereal d__1; + + /* Local variables */ + static doublereal b, c__, w, del, tau, delsq; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This subroutine computes the square root of the I-th eigenvalue + of a positive symmetric rank-one modification of a 2-by-2 diagonal + matrix + + diag( D ) * diag( D ) + RHO * Z * transpose(Z) . + + The diagonal entries in the array D are assumed to satisfy + + 0 <= D(i) < D(j) for i < j . + + We also assume RHO > 0 and that the Euclidean norm of the vector + Z is one. + + Arguments + ========= + + I (input) INTEGER + The index of the eigenvalue to be computed. I = 1 or I = 2. + + D (input) DOUBLE PRECISION array, dimension ( 2 ) + The original eigenvalues. We assume 0 <= D(1) < D(2). + + Z (input) DOUBLE PRECISION array, dimension ( 2 ) + The components of the updating vector. + + DELTA (output) DOUBLE PRECISION array, dimension ( 2 ) + Contains (D(j) - sigma_I) in its j-th component. + The vector DELTA contains the information necessary + to construct the eigenvectors. + + RHO (input) DOUBLE PRECISION + The scalar in the symmetric updating formula. + + DSIGMA (output) DOUBLE PRECISION + The computed sigma_I, the I-th updated eigenvalue. + + WORK (workspace) DOUBLE PRECISION array, dimension ( 2 ) + WORK contains (D(j) + sigma_I) in its j-th component. + + Further Details + =============== + + Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --work; + --delta; + --z__; + --d__; + + /* Function Body */ + del = d__[2] - d__[1]; + delsq = del * (d__[2] + d__[1]); + if (*i__ == 1) { + w = *rho * 4. * (z__[2] * z__[2] / (d__[1] + d__[2] * 3.) - z__[1] * + z__[1] / (d__[1] * 3. + d__[2])) / del + 1.; + if (w > 0.) { + b = delsq + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[1] * z__[1] * delsq; + +/* + B > ZERO, always + + The following TAU is DSIGMA * DSIGMA - D( 1 ) * D( 1 ) +*/ + + tau = c__ * 2. / (b + sqrt((d__1 = b * b - c__ * 4., abs(d__1)))); + +/* The following TAU is DSIGMA - D( 1 ) */ + + tau /= d__[1] + sqrt(d__[1] * d__[1] + tau); + *dsigma = d__[1] + tau; + delta[1] = -tau; + delta[2] = del - tau; + work[1] = d__[1] * 2. + tau; + work[2] = d__[1] + tau + d__[2]; +/* + DELTA( 1 ) = -Z( 1 ) / TAU + DELTA( 2 ) = Z( 2 ) / ( DEL-TAU ) +*/ + } else { + b = -delsq + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[2] * z__[2] * delsq; + +/* The following TAU is DSIGMA * DSIGMA - D( 2 ) * D( 2 ) */ + + if (b > 0.) { + tau = c__ * -2. / (b + sqrt(b * b + c__ * 4.)); + } else { + tau = (b - sqrt(b * b + c__ * 4.)) / 2.; + } + +/* The following TAU is DSIGMA - D( 2 ) */ + + tau /= d__[2] + sqrt((d__1 = d__[2] * d__[2] + tau, abs(d__1))); + *dsigma = d__[2] + tau; + delta[1] = -(del + tau); + delta[2] = -tau; + work[1] = d__[1] + tau + d__[2]; + work[2] = d__[2] * 2. + tau; +/* + DELTA( 1 ) = -Z( 1 ) / ( DEL+TAU ) + DELTA( 2 ) = -Z( 2 ) / TAU +*/ + } +/* + TEMP = SQRT( DELTA( 1 )*DELTA( 1 )+DELTA( 2 )*DELTA( 2 ) ) + DELTA( 1 ) = DELTA( 1 ) / TEMP + DELTA( 2 ) = DELTA( 2 ) / TEMP +*/ + } else { + +/* Now I=2 */ + + b = -delsq + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[2] * z__[2] * delsq; + +/* The following TAU is DSIGMA * DSIGMA - D( 2 ) * D( 2 ) */ + + if (b > 0.) { + tau = (b + sqrt(b * b + c__ * 4.)) / 2.; + } else { + tau = c__ * 2. / (-b + sqrt(b * b + c__ * 4.)); + } + +/* The following TAU is DSIGMA - D( 2 ) */ + + tau /= d__[2] + sqrt(d__[2] * d__[2] + tau); + *dsigma = d__[2] + tau; + delta[1] = -(del + tau); + delta[2] = -tau; + work[1] = d__[1] + tau + d__[2]; + work[2] = d__[2] * 2. + tau; +/* + DELTA( 1 ) = -Z( 1 ) / ( DEL+TAU ) + DELTA( 2 ) = -Z( 2 ) / TAU + TEMP = SQRT( DELTA( 1 )*DELTA( 1 )+DELTA( 2 )*DELTA( 2 ) ) + DELTA( 1 ) = DELTA( 1 ) / TEMP + DELTA( 2 ) = DELTA( 2 ) / TEMP +*/ + } + return 0; + +/* End of DLASD5 */ + +} /* dlasd5_ */ + +/* Subroutine */ int dlasd6_(integer *icompq, integer *nl, integer *nr, + integer *sqre, doublereal *d__, doublereal *vf, doublereal *vl, + doublereal *alpha, doublereal *beta, integer *idxq, integer *perm, + integer *givptr, integer *givcol, integer *ldgcol, doublereal *givnum, + integer *ldgnum, doublereal *poles, doublereal *difl, doublereal * + difr, doublereal *z__, integer *k, doublereal *c__, doublereal *s, + doublereal *work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, givnum_dim1, givnum_offset, + poles_dim1, poles_offset, i__1; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__, m, n, n1, n2, iw, idx, idxc, idxp, ivfw, ivlw; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *), dlasd7_(integer *, integer *, integer *, + integer *, integer *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, integer *, integer *, + integer *, integer *, integer *, integer *, integer *, doublereal + *, integer *, doublereal *, doublereal *, integer *), dlasd8_( + integer *, integer *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, integer *, doublereal *, + doublereal *, integer *), dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dlamrg_(integer *, integer *, + doublereal *, integer *, integer *, integer *); + static integer isigma; + extern /* Subroutine */ int xerbla_(char *, integer *); + static doublereal orgnrm; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLASD6 computes the SVD of an updated upper bidiagonal matrix B + obtained by merging two smaller ones by appending a row. This + routine is used only for the problem which requires all singular + values and optionally singular vector matrices in factored form. + B is an N-by-M matrix with N = NL + NR + 1 and M = N + SQRE. + A related subroutine, DLASD1, handles the case in which all singular + values and singular vectors of the bidiagonal matrix are desired. + + DLASD6 computes the SVD as follows: + + ( D1(in) 0 0 0 ) + B = U(in) * ( Z1' a Z2' b ) * VT(in) + ( 0 0 D2(in) 0 ) + + = U(out) * ( D(out) 0) * VT(out) + + where Z' = (Z1' a Z2' b) = u' VT', and u is a vector of dimension M + with ALPHA and BETA in the NL+1 and NL+2 th entries and zeros + elsewhere; and the entry b is empty if SQRE = 0. + + The singular values of B can be computed using D1, D2, the first + components of all the right singular vectors of the lower block, and + the last components of all the right singular vectors of the upper + block. These components are stored and updated in VF and VL, + respectively, in DLASD6. Hence U and VT are not explicitly + referenced. + + The singular values are stored in D. The algorithm consists of two + stages: + + The first stage consists of deflating the size of the problem + when there are multiple singular values or if there is a zero + in the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine DLASD7. + + The second stage consists of calculating the updated + singular values. This is done by finding the roots of the + secular equation via the routine DLASD4 (as called by DLASD8). + This routine also updates VF and VL and computes the distances + between the updated singular values and the old singular + values. + + DLASD6 is called from DLASDA. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed in + factored form: + = 0: Compute singular values only. + = 1: Compute singular vectors in factored form as well. + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has row dimension N = NL + NR + 1, + and column dimension M = N + SQRE. + + D (input/output) DOUBLE PRECISION array, dimension ( NL+NR+1 ). + On entry D(1:NL,1:NL) contains the singular values of the + upper block, and D(NL+2:N) contains the singular values + of the lower block. On exit D(1:N) contains the singular + values of the modified matrix. + + VF (input/output) DOUBLE PRECISION array, dimension ( M ) + On entry, VF(1:NL+1) contains the first components of all + right singular vectors of the upper block; and VF(NL+2:M) + contains the first components of all right singular vectors + of the lower block. On exit, VF contains the first components + of all right singular vectors of the bidiagonal matrix. + + VL (input/output) DOUBLE PRECISION array, dimension ( M ) + On entry, VL(1:NL+1) contains the last components of all + right singular vectors of the upper block; and VL(NL+2:M) + contains the last components of all right singular vectors of + the lower block. On exit, VL contains the last components of + all right singular vectors of the bidiagonal matrix. + + ALPHA (input/output) DOUBLE PRECISION + Contains the diagonal element associated with the added row. + + BETA (input/output) DOUBLE PRECISION + Contains the off-diagonal element associated with the added + row. + + IDXQ (output) INTEGER array, dimension ( N ) + This contains the permutation which will reintegrate the + subproblem just solved back into sorted order, i.e. + D( IDXQ( I = 1, N ) ) will be in ascending order. + + PERM (output) INTEGER array, dimension ( N ) + The permutations (from deflation and sorting) to be applied + to each block. Not referenced if ICOMPQ = 0. + + GIVPTR (output) INTEGER + The number of Givens rotations which took place in this + subproblem. Not referenced if ICOMPQ = 0. + + GIVCOL (output) INTEGER array, dimension ( LDGCOL, 2 ) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. Not referenced if ICOMPQ = 0. + + LDGCOL (input) INTEGER + leading dimension of GIVCOL, must be at least N. + + GIVNUM (output) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ) + Each number indicates the C or S value to be used in the + corresponding Givens rotation. Not referenced if ICOMPQ = 0. + + LDGNUM (input) INTEGER + The leading dimension of GIVNUM and POLES, must be at least N. + + POLES (output) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ) + On exit, POLES(1,*) is an array containing the new singular + values obtained from solving the secular equation, and + POLES(2,*) is an array containing the poles in the secular + equation. Not referenced if ICOMPQ = 0. + + DIFL (output) DOUBLE PRECISION array, dimension ( N ) + On exit, DIFL(I) is the distance between I-th updated + (undeflated) singular value and the I-th (undeflated) old + singular value. + + DIFR (output) DOUBLE PRECISION array, + dimension ( LDGNUM, 2 ) if ICOMPQ = 1 and + dimension ( N ) if ICOMPQ = 0. + On exit, DIFR(I, 1) is the distance between I-th updated + (undeflated) singular value and the I+1-th (undeflated) old + singular value. + + If ICOMPQ = 1, DIFR(1:K,2) is an array containing the + normalizing factors for the right singular vector matrix. + + See DLASD8 for details on DIFL and DIFR. + + Z (output) DOUBLE PRECISION array, dimension ( M ) + The first elements of this array contain the components + of the deflation-adjusted updating row vector. + + K (output) INTEGER + Contains the dimension of the non-deflated matrix, + This is the order of the related secular equation. 1 <= K <=N. + + C (output) DOUBLE PRECISION + C contains garbage if SQRE =0 and the C-value of a Givens + rotation related to the right null space if SQRE = 1. + + S (output) DOUBLE PRECISION + S contains garbage if SQRE =0 and the S-value of a Givens + rotation related to the right null space if SQRE = 1. + + WORK (workspace) DOUBLE PRECISION array, dimension ( 4 * M ) + + IWORK (workspace) INTEGER array, dimension ( 3 * N ) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --vf; + --vl; + --idxq; + --perm; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + poles_dim1 = *ldgnum; + poles_offset = 1 + poles_dim1; + poles -= poles_offset; + givnum_dim1 = *ldgnum; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + --difl; + --difr; + --z__; + --work; + --iwork; + + /* Function Body */ + *info = 0; + n = *nl + *nr + 1; + m = n + *sqre; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*nl < 1) { + *info = -2; + } else if (*nr < 1) { + *info = -3; + } else if (*sqre < 0 || *sqre > 1) { + *info = -4; + } else if (*ldgcol < n) { + *info = -14; + } else if (*ldgnum < n) { + *info = -16; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASD6", &i__1); + return 0; + } + +/* + The following values are for bookkeeping purposes only. They are + integer pointers which indicate the portion of the workspace + used by a particular array in DLASD7 and DLASD8. +*/ + + isigma = 1; + iw = isigma + n; + ivfw = iw + m; + ivlw = ivfw + m; + + idx = 1; + idxc = idx + n; + idxp = idxc + n; + +/* + Scale. + + Computing MAX +*/ + d__1 = abs(*alpha), d__2 = abs(*beta); + orgnrm = max(d__1,d__2); + d__[*nl + 1] = 0.; + i__1 = n; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((d__1 = d__[i__], abs(d__1)) > orgnrm) { + orgnrm = (d__1 = d__[i__], abs(d__1)); + } +/* L10: */ + } + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &n, &c__1, &d__[1], &n, info); + *alpha /= orgnrm; + *beta /= orgnrm; + +/* Sort and Deflate singular values. */ + + dlasd7_(icompq, nl, nr, sqre, k, &d__[1], &z__[1], &work[iw], &vf[1], & + work[ivfw], &vl[1], &work[ivlw], alpha, beta, &work[isigma], & + iwork[idx], &iwork[idxp], &idxq[1], &perm[1], givptr, &givcol[ + givcol_offset], ldgcol, &givnum[givnum_offset], ldgnum, c__, s, + info); + +/* Solve Secular Equation, compute DIFL, DIFR, and update VF, VL. */ + + dlasd8_(icompq, k, &d__[1], &z__[1], &vf[1], &vl[1], &difl[1], &difr[1], + ldgnum, &work[isigma], &work[iw], info); + +/* Save the poles if ICOMPQ = 1. */ + + if (*icompq == 1) { + dcopy_(k, &d__[1], &c__1, &poles[poles_dim1 + 1], &c__1); + dcopy_(k, &work[isigma], &c__1, &poles[(poles_dim1 << 1) + 1], &c__1); + } + +/* Unscale. */ + + dlascl_("G", &c__0, &c__0, &c_b15, &orgnrm, &n, &c__1, &d__[1], &n, info); + +/* Prepare the IDXQ sorting permutation. */ + + n1 = *k; + n2 = n - *k; + dlamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &idxq[1]); + + return 0; + +/* End of DLASD6 */ + +} /* dlasd6_ */ + +/* Subroutine */ int dlasd7_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *k, doublereal *d__, doublereal *z__, + doublereal *zw, doublereal *vf, doublereal *vfw, doublereal *vl, + doublereal *vlw, doublereal *alpha, doublereal *beta, doublereal * + dsigma, integer *idx, integer *idxp, integer *idxq, integer *perm, + integer *givptr, integer *givcol, integer *ldgcol, doublereal *givnum, + integer *ldgnum, doublereal *c__, doublereal *s, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, givnum_dim1, givnum_offset, i__1; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__, j, m, n, k2; + static doublereal z1; + static integer jp; + static doublereal eps, tau, tol; + static integer nlp1, nlp2, idxi, idxj; + extern /* Subroutine */ int drot_(integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *); + static integer idxjp; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer jprev; + + extern /* Subroutine */ int dlamrg_(integer *, integer *, doublereal *, + integer *, integer *, integer *), xerbla_(char *, integer *); + static doublereal hlftol; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASD7 merges the two sets of singular values together into a single + sorted set. Then it tries to deflate the size of the problem. There + are two ways in which deflation can occur: when two or more singular + values are close together or if there is a tiny entry in the Z + vector. For each such occurrence the order of the related + secular equation problem is reduced by one. + + DLASD7 is called from DLASD6. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed + in compact form, as follows: + = 0: Compute singular values only. + = 1: Compute singular vectors of upper + bidiagonal matrix in compact form. + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has + N = NL + NR + 1 rows and + M = N + SQRE >= N columns. + + K (output) INTEGER + Contains the dimension of the non-deflated matrix, this is + the order of the related secular equation. 1 <= K <=N. + + D (input/output) DOUBLE PRECISION array, dimension ( N ) + On entry D contains the singular values of the two submatrices + to be combined. On exit D contains the trailing (N-K) updated + singular values (those which were deflated) sorted into + increasing order. + + Z (output) DOUBLE PRECISION array, dimension ( M ) + On exit Z contains the updating row vector in the secular + equation. + + ZW (workspace) DOUBLE PRECISION array, dimension ( M ) + Workspace for Z. + + VF (input/output) DOUBLE PRECISION array, dimension ( M ) + On entry, VF(1:NL+1) contains the first components of all + right singular vectors of the upper block; and VF(NL+2:M) + contains the first components of all right singular vectors + of the lower block. On exit, VF contains the first components + of all right singular vectors of the bidiagonal matrix. + + VFW (workspace) DOUBLE PRECISION array, dimension ( M ) + Workspace for VF. + + VL (input/output) DOUBLE PRECISION array, dimension ( M ) + On entry, VL(1:NL+1) contains the last components of all + right singular vectors of the upper block; and VL(NL+2:M) + contains the last components of all right singular vectors + of the lower block. On exit, VL contains the last components + of all right singular vectors of the bidiagonal matrix. + + VLW (workspace) DOUBLE PRECISION array, dimension ( M ) + Workspace for VL. + + ALPHA (input) DOUBLE PRECISION + Contains the diagonal element associated with the added row. + + BETA (input) DOUBLE PRECISION + Contains the off-diagonal element associated with the added + row. + + DSIGMA (output) DOUBLE PRECISION array, dimension ( N ) + Contains a copy of the diagonal elements (K-1 singular values + and one zero) in the secular equation. + + IDX (workspace) INTEGER array, dimension ( N ) + This will contain the permutation used to sort the contents of + D into ascending order. + + IDXP (workspace) INTEGER array, dimension ( N ) + This will contain the permutation used to place deflated + values of D at the end of the array. On output IDXP(2:K) + points to the nondeflated D-values and IDXP(K+1:N) + points to the deflated singular values. + + IDXQ (input) INTEGER array, dimension ( N ) + This contains the permutation which separately sorts the two + sub-problems in D into ascending order. Note that entries in + the first half of this permutation must first be moved one + position backward; and entries in the second half + must first have NL+1 added to their values. + + PERM (output) INTEGER array, dimension ( N ) + The permutations (from deflation and sorting) to be applied + to each singular block. Not referenced if ICOMPQ = 0. + + GIVPTR (output) INTEGER + The number of Givens rotations which took place in this + subproblem. Not referenced if ICOMPQ = 0. + + GIVCOL (output) INTEGER array, dimension ( LDGCOL, 2 ) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. Not referenced if ICOMPQ = 0. + + LDGCOL (input) INTEGER + The leading dimension of GIVCOL, must be at least N. + + GIVNUM (output) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ) + Each number indicates the C or S value to be used in the + corresponding Givens rotation. Not referenced if ICOMPQ = 0. + + LDGNUM (input) INTEGER + The leading dimension of GIVNUM, must be at least N. + + C (output) DOUBLE PRECISION + C contains garbage if SQRE =0 and the C-value of a Givens + rotation related to the right null space if SQRE = 1. + + S (output) DOUBLE PRECISION + S contains garbage if SQRE =0 and the S-value of a Givens + rotation related to the right null space if SQRE = 1. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --z__; + --zw; + --vf; + --vfw; + --vl; + --vlw; + --dsigma; + --idx; + --idxp; + --idxq; + --perm; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + givnum_dim1 = *ldgnum; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + + /* Function Body */ + *info = 0; + n = *nl + *nr + 1; + m = n + *sqre; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*nl < 1) { + *info = -2; + } else if (*nr < 1) { + *info = -3; + } else if (*sqre < 0 || *sqre > 1) { + *info = -4; + } else if (*ldgcol < n) { + *info = -22; + } else if (*ldgnum < n) { + *info = -24; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASD7", &i__1); + return 0; + } + + nlp1 = *nl + 1; + nlp2 = *nl + 2; + if (*icompq == 1) { + *givptr = 0; + } + +/* + Generate the first part of the vector Z and move the singular + values in the first part of D one position backward. +*/ + + z1 = *alpha * vl[nlp1]; + vl[nlp1] = 0.; + tau = vf[nlp1]; + for (i__ = *nl; i__ >= 1; --i__) { + z__[i__ + 1] = *alpha * vl[i__]; + vl[i__] = 0.; + vf[i__ + 1] = vf[i__]; + d__[i__ + 1] = d__[i__]; + idxq[i__ + 1] = idxq[i__] + 1; +/* L10: */ + } + vf[1] = tau; + +/* Generate the second part of the vector Z. */ + + i__1 = m; + for (i__ = nlp2; i__ <= i__1; ++i__) { + z__[i__] = *beta * vf[i__]; + vf[i__] = 0.; +/* L20: */ + } + +/* Sort the singular values into increasing order */ + + i__1 = n; + for (i__ = nlp2; i__ <= i__1; ++i__) { + idxq[i__] += nlp1; +/* L30: */ + } + +/* DSIGMA, IDXC, IDXC, and ZW are used as storage space. */ + + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + dsigma[i__] = d__[idxq[i__]]; + zw[i__] = z__[idxq[i__]]; + vfw[i__] = vf[idxq[i__]]; + vlw[i__] = vl[idxq[i__]]; +/* L40: */ + } + + dlamrg_(nl, nr, &dsigma[2], &c__1, &c__1, &idx[2]); + + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + idxi = idx[i__] + 1; + d__[i__] = dsigma[idxi]; + z__[i__] = zw[idxi]; + vf[i__] = vfw[idxi]; + vl[i__] = vlw[idxi]; +/* L50: */ + } + +/* Calculate the allowable deflation tolerence */ + + eps = EPSILON; +/* Computing MAX */ + d__1 = abs(*alpha), d__2 = abs(*beta); + tol = max(d__1,d__2); +/* Computing MAX */ + d__2 = (d__1 = d__[n], abs(d__1)); + tol = eps * 64. * max(d__2,tol); + +/* + There are 2 kinds of deflation -- first a value in the z-vector + is small, second two (or more) singular values are very close + together (their difference is small). + + If the value in the z-vector is small, we simply permute the + array so that the corresponding singular value is moved to the + end. + + If two values in the D-vector are close, we perform a two-sided + rotation designed to make one of the corresponding z-vector + entries zero, and then permute the array so that the deflated + singular value is moved to the end. + + If there are multiple singular values then the problem deflates. + Here the number of equal singular values are found. As each equal + singular value is found, an elementary reflector is computed to + rotate the corresponding singular subspace so that the + corresponding components of Z are zero in this new basis. +*/ + + *k = 1; + k2 = n + 1; + i__1 = n; + for (j = 2; j <= i__1; ++j) { + if ((d__1 = z__[j], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + idxp[k2] = j; + if (j == n) { + goto L100; + } + } else { + jprev = j; + goto L70; + } +/* L60: */ + } +L70: + j = jprev; +L80: + ++j; + if (j > n) { + goto L90; + } + if ((d__1 = z__[j], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + idxp[k2] = j; + } else { + +/* Check if singular values are close enough to allow deflation. */ + + if ((d__1 = d__[j] - d__[jprev], abs(d__1)) <= tol) { + +/* Deflation is possible. */ + + *s = z__[jprev]; + *c__ = z__[j]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = dlapy2_(c__, s); + z__[j] = tau; + z__[jprev] = 0.; + *c__ /= tau; + *s = -(*s) / tau; + +/* Record the appropriate Givens rotation */ + + if (*icompq == 1) { + ++(*givptr); + idxjp = idxq[idx[jprev] + 1]; + idxj = idxq[idx[j] + 1]; + if (idxjp <= nlp1) { + --idxjp; + } + if (idxj <= nlp1) { + --idxj; + } + givcol[*givptr + (givcol_dim1 << 1)] = idxjp; + givcol[*givptr + givcol_dim1] = idxj; + givnum[*givptr + (givnum_dim1 << 1)] = *c__; + givnum[*givptr + givnum_dim1] = *s; + } + drot_(&c__1, &vf[jprev], &c__1, &vf[j], &c__1, c__, s); + drot_(&c__1, &vl[jprev], &c__1, &vl[j], &c__1, c__, s); + --k2; + idxp[k2] = jprev; + jprev = j; + } else { + ++(*k); + zw[*k] = z__[jprev]; + dsigma[*k] = d__[jprev]; + idxp[*k] = jprev; + jprev = j; + } + } + goto L80; +L90: + +/* Record the last singular value. */ + + ++(*k); + zw[*k] = z__[jprev]; + dsigma[*k] = d__[jprev]; + idxp[*k] = jprev; + +L100: + +/* + Sort the singular values into DSIGMA. The singular values which + were not deflated go into the first K slots of DSIGMA, except + that DSIGMA(1) is treated separately. +*/ + + i__1 = n; + for (j = 2; j <= i__1; ++j) { + jp = idxp[j]; + dsigma[j] = d__[jp]; + vfw[j] = vf[jp]; + vlw[j] = vl[jp]; +/* L110: */ + } + if (*icompq == 1) { + i__1 = n; + for (j = 2; j <= i__1; ++j) { + jp = idxp[j]; + perm[j] = idxq[idx[jp] + 1]; + if (perm[j] <= nlp1) { + --perm[j]; + } +/* L120: */ + } + } + +/* + The deflated singular values go back into the last N - K slots of + D. +*/ + + i__1 = n - *k; + dcopy_(&i__1, &dsigma[*k + 1], &c__1, &d__[*k + 1], &c__1); + +/* + Determine DSIGMA(1), DSIGMA(2), Z(1), VF(1), VL(1), VF(M), and + VL(M). +*/ + + dsigma[1] = 0.; + hlftol = tol / 2.; + if (abs(dsigma[2]) <= hlftol) { + dsigma[2] = hlftol; + } + if (m > n) { + z__[1] = dlapy2_(&z1, &z__[m]); + if (z__[1] <= tol) { + *c__ = 1.; + *s = 0.; + z__[1] = tol; + } else { + *c__ = z1 / z__[1]; + *s = -z__[m] / z__[1]; + } + drot_(&c__1, &vf[m], &c__1, &vf[1], &c__1, c__, s); + drot_(&c__1, &vl[m], &c__1, &vl[1], &c__1, c__, s); + } else { + if (abs(z1) <= tol) { + z__[1] = tol; + } else { + z__[1] = z1; + } + } + +/* Restore Z, VF, and VL. */ + + i__1 = *k - 1; + dcopy_(&i__1, &zw[2], &c__1, &z__[2], &c__1); + i__1 = n - 1; + dcopy_(&i__1, &vfw[2], &c__1, &vf[2], &c__1); + i__1 = n - 1; + dcopy_(&i__1, &vlw[2], &c__1, &vl[2], &c__1); + + return 0; + +/* End of DLASD7 */ + +} /* dlasd7_ */ + +/* Subroutine */ int dlasd8_(integer *icompq, integer *k, doublereal *d__, + doublereal *z__, doublereal *vf, doublereal *vl, doublereal *difl, + doublereal *difr, integer *lddifr, doublereal *dsigma, doublereal * + work, integer *info) +{ + /* System generated locals */ + integer difr_dim1, difr_offset, i__1, i__2; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__, j; + static doublereal dj, rho; + static integer iwk1, iwk2, iwk3; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + static doublereal temp; + extern doublereal dnrm2_(integer *, doublereal *, integer *); + static integer iwk2i, iwk3i; + static doublereal diflj, difrj, dsigj; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + extern doublereal dlamc3_(doublereal *, doublereal *); + extern /* Subroutine */ int dlasd4_(integer *, integer *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *), dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dlaset_(char *, integer *, integer + *, doublereal *, doublereal *, doublereal *, integer *), + xerbla_(char *, integer *); + static doublereal dsigjp; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLASD8 finds the square roots of the roots of the secular equation, + as defined by the values in DSIGMA and Z. It makes the appropriate + calls to DLASD4, and stores, for each element in D, the distance + to its two nearest poles (elements in DSIGMA). It also updates + the arrays VF and VL, the first and last components of all the + right singular vectors of the original bidiagonal matrix. + + DLASD8 is called from DLASD6. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed in + factored form in the calling routine: + = 0: Compute singular values only. + = 1: Compute singular vectors in factored form as well. + + K (input) INTEGER + The number of terms in the rational function to be solved + by DLASD4. K >= 1. + + D (output) DOUBLE PRECISION array, dimension ( K ) + On output, D contains the updated singular values. + + Z (input/output) DOUBLE PRECISION array, dimension ( K ) + On entry, the first K elements of this array contain the + components of the deflation-adjusted updating row vector. + On exit, Z is updated. + + VF (input/output) DOUBLE PRECISION array, dimension ( K ) + On entry, VF contains information passed through DBEDE8. + On exit, VF contains the first K components of the first + components of all right singular vectors of the bidiagonal + matrix. + + VL (input/output) DOUBLE PRECISION array, dimension ( K ) + On entry, VL contains information passed through DBEDE8. + On exit, VL contains the first K components of the last + components of all right singular vectors of the bidiagonal + matrix. + + DIFL (output) DOUBLE PRECISION array, dimension ( K ) + On exit, DIFL(I) = D(I) - DSIGMA(I). + + DIFR (output) DOUBLE PRECISION array, + dimension ( LDDIFR, 2 ) if ICOMPQ = 1 and + dimension ( K ) if ICOMPQ = 0. + On exit, DIFR(I,1) = D(I) - DSIGMA(I+1), DIFR(K,1) is not + defined and will not be referenced. + + If ICOMPQ = 1, DIFR(1:K,2) is an array containing the + normalizing factors for the right singular vector matrix. + + LDDIFR (input) INTEGER + The leading dimension of DIFR, must be at least K. + + DSIGMA (input/output) DOUBLE PRECISION array, dimension ( K ) + On entry, the first K elements of this array contain the old + roots of the deflated updating problem. These are the poles + of the secular equation. + On exit, the elements of DSIGMA may be very slightly altered + in value. + + WORK (workspace) DOUBLE PRECISION array, dimension at least 3 * K + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --z__; + --vf; + --vl; + --difl; + difr_dim1 = *lddifr; + difr_offset = 1 + difr_dim1; + difr -= difr_offset; + --dsigma; + --work; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*k < 1) { + *info = -2; + } else if (*lddifr < *k) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASD8", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*k == 1) { + d__[1] = abs(z__[1]); + difl[1] = d__[1]; + if (*icompq == 1) { + difl[2] = 1.; + difr[(difr_dim1 << 1) + 1] = 1.; + } + return 0; + } + +/* + Modify values DSIGMA(i) to make sure all DSIGMA(i)-DSIGMA(j) can + be computed with high relative accuracy (barring over/underflow). + This is a problem on machines without a guard digit in + add/subtract (Cray XMP, Cray YMP, Cray C 90 and Cray 2). + The following code replaces DSIGMA(I) by 2*DSIGMA(I)-DSIGMA(I), + which on any of these machines zeros out the bottommost + bit of DSIGMA(I) if it is 1; this makes the subsequent + subtractions DSIGMA(I)-DSIGMA(J) unproblematic when cancellation + occurs. On binary machines with a guard digit (almost all + machines) it does not change DSIGMA(I) at all. On hexadecimal + and decimal machines with a guard digit, it slightly + changes the bottommost bits of DSIGMA(I). It does not account + for hexadecimal or decimal machines without guard digits + (we know of none). We use a subroutine call to compute + 2*DLAMBDA(I) to prevent optimizing compilers from eliminating + this code. +*/ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + dsigma[i__] = dlamc3_(&dsigma[i__], &dsigma[i__]) - dsigma[i__]; +/* L10: */ + } + +/* Book keeping. */ + + iwk1 = 1; + iwk2 = iwk1 + *k; + iwk3 = iwk2 + *k; + iwk2i = iwk2 - 1; + iwk3i = iwk3 - 1; + +/* Normalize Z. */ + + rho = dnrm2_(k, &z__[1], &c__1); + dlascl_("G", &c__0, &c__0, &rho, &c_b15, k, &c__1, &z__[1], k, info); + rho *= rho; + +/* Initialize WORK(IWK3). */ + + dlaset_("A", k, &c__1, &c_b15, &c_b15, &work[iwk3], k); + +/* + Compute the updated singular values, the arrays DIFL, DIFR, + and the updated Z. +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dlasd4_(k, &j, &dsigma[1], &z__[1], &work[iwk1], &rho, &d__[j], &work[ + iwk2], info); + +/* If the root finder fails, the computation is terminated. */ + + if (*info != 0) { + return 0; + } + work[iwk3i + j] = work[iwk3i + j] * work[j] * work[iwk2i + j]; + difl[j] = -work[j]; + difr[j + difr_dim1] = -work[j + 1]; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + work[iwk3i + i__] = work[iwk3i + i__] * work[i__] * work[iwk2i + + i__] / (dsigma[i__] - dsigma[j]) / (dsigma[i__] + dsigma[ + j]); +/* L20: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + work[iwk3i + i__] = work[iwk3i + i__] * work[i__] * work[iwk2i + + i__] / (dsigma[i__] - dsigma[j]) / (dsigma[i__] + dsigma[ + j]); +/* L30: */ + } +/* L40: */ + } + +/* Compute updated Z. */ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + d__2 = sqrt((d__1 = work[iwk3i + i__], abs(d__1))); + z__[i__] = d_sign(&d__2, &z__[i__]); +/* L50: */ + } + +/* Update VF and VL. */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + diflj = difl[j]; + dj = d__[j]; + dsigj = -dsigma[j]; + if (j < *k) { + difrj = -difr[j + difr_dim1]; + dsigjp = -dsigma[j + 1]; + } + work[j] = -z__[j] / diflj / (dsigma[j] + dj); + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] = z__[i__] / (dlamc3_(&dsigma[i__], &dsigj) - diflj) / ( + dsigma[i__] + dj); +/* L60: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + work[i__] = z__[i__] / (dlamc3_(&dsigma[i__], &dsigjp) + difrj) / + (dsigma[i__] + dj); +/* L70: */ + } + temp = dnrm2_(k, &work[1], &c__1); + work[iwk2i + j] = ddot_(k, &work[1], &c__1, &vf[1], &c__1) / temp; + work[iwk3i + j] = ddot_(k, &work[1], &c__1, &vl[1], &c__1) / temp; + if (*icompq == 1) { + difr[j + (difr_dim1 << 1)] = temp; + } +/* L80: */ + } + + dcopy_(k, &work[iwk2], &c__1, &vf[1], &c__1); + dcopy_(k, &work[iwk3], &c__1, &vl[1], &c__1); + + return 0; + +/* End of DLASD8 */ + +} /* dlasd8_ */ + +/* Subroutine */ int dlasda_(integer *icompq, integer *smlsiz, integer *n, + integer *sqre, doublereal *d__, doublereal *e, doublereal *u, integer + *ldu, doublereal *vt, integer *k, doublereal *difl, doublereal *difr, + doublereal *z__, doublereal *poles, integer *givptr, integer *givcol, + integer *ldgcol, integer *perm, doublereal *givnum, doublereal *c__, + doublereal *s, doublereal *work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, perm_dim1, perm_offset, difl_dim1, + difl_offset, difr_dim1, difr_offset, givnum_dim1, givnum_offset, + poles_dim1, poles_offset, u_dim1, u_offset, vt_dim1, vt_offset, + z_dim1, z_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, m, i1, ic, lf, nd, ll, nl, vf, nr, vl, im1, ncc, + nlf, nrf, vfi, iwk, vli, lvl, nru, ndb1, nlp1, lvl2, nrp1; + static doublereal beta; + static integer idxq, nlvl; + static doublereal alpha; + static integer inode, ndiml, ndimr, idxqi, itemp; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer sqrei; + extern /* Subroutine */ int dlasd6_(integer *, integer *, integer *, + integer *, doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *, integer *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, integer *, integer *); + static integer nwork1, nwork2; + extern /* Subroutine */ int dlasdq_(char *, integer *, integer *, integer + *, integer *, integer *, doublereal *, doublereal *, doublereal *, + integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *), dlasdt_(integer *, integer *, + integer *, integer *, integer *, integer *, integer *), dlaset_( + char *, integer *, integer *, doublereal *, doublereal *, + doublereal *, integer *), xerbla_(char *, integer *); + static integer smlszp; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + Using a divide and conquer approach, DLASDA computes the singular + value decomposition (SVD) of a real upper bidiagonal N-by-M matrix + B with diagonal D and offdiagonal E, where M = N + SQRE. The + algorithm computes the singular values in the SVD B = U * S * VT. + The orthogonal matrices U and VT are optionally computed in + compact form. + + A related subroutine, DLASD0, computes the singular values and + the singular vectors in explicit form. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed + in compact form, as follows + = 0: Compute singular values only. + = 1: Compute singular vectors of upper bidiagonal + matrix in compact form. + + SMLSIZ (input) INTEGER + The maximum size of the subproblems at the bottom of the + computation tree. + + N (input) INTEGER + The row dimension of the upper bidiagonal matrix. This is + also the dimension of the main diagonal array D. + + SQRE (input) INTEGER + Specifies the column dimension of the bidiagonal matrix. + = 0: The bidiagonal matrix has column dimension M = N; + = 1: The bidiagonal matrix has column dimension M = N + 1. + + D (input/output) DOUBLE PRECISION array, dimension ( N ) + On entry D contains the main diagonal of the bidiagonal + matrix. On exit D, if INFO = 0, contains its singular values. + + E (input) DOUBLE PRECISION array, dimension ( M-1 ) + Contains the subdiagonal entries of the bidiagonal matrix. + On exit, E has been destroyed. + + U (output) DOUBLE PRECISION array, + dimension ( LDU, SMLSIZ ) if ICOMPQ = 1, and not referenced + if ICOMPQ = 0. If ICOMPQ = 1, on exit, U contains the left + singular vector matrices of all subproblems at the bottom + level. + + LDU (input) INTEGER, LDU = > N. + The leading dimension of arrays U, VT, DIFL, DIFR, POLES, + GIVNUM, and Z. + + VT (output) DOUBLE PRECISION array, + dimension ( LDU, SMLSIZ+1 ) if ICOMPQ = 1, and not referenced + if ICOMPQ = 0. If ICOMPQ = 1, on exit, VT' contains the right + singular vector matrices of all subproblems at the bottom + level. + + K (output) INTEGER array, + dimension ( N ) if ICOMPQ = 1 and dimension 1 if ICOMPQ = 0. + If ICOMPQ = 1, on exit, K(I) is the dimension of the I-th + secular equation on the computation tree. + + DIFL (output) DOUBLE PRECISION array, dimension ( LDU, NLVL ), + where NLVL = floor(log_2 (N/SMLSIZ))). + + DIFR (output) DOUBLE PRECISION array, + dimension ( LDU, 2 * NLVL ) if ICOMPQ = 1 and + dimension ( N ) if ICOMPQ = 0. + If ICOMPQ = 1, on exit, DIFL(1:N, I) and DIFR(1:N, 2 * I - 1) + record distances between singular values on the I-th + level and singular values on the (I -1)-th level, and + DIFR(1:N, 2 * I ) contains the normalizing factors for + the right singular vector matrix. See DLASD8 for details. + + Z (output) DOUBLE PRECISION array, + dimension ( LDU, NLVL ) if ICOMPQ = 1 and + dimension ( N ) if ICOMPQ = 0. + The first K elements of Z(1, I) contain the components of + the deflation-adjusted updating row vector for subproblems + on the I-th level. + + POLES (output) DOUBLE PRECISION array, + dimension ( LDU, 2 * NLVL ) if ICOMPQ = 1, and not referenced + if ICOMPQ = 0. If ICOMPQ = 1, on exit, POLES(1, 2*I - 1) and + POLES(1, 2*I) contain the new and old singular values + involved in the secular equations on the I-th level. + + GIVPTR (output) INTEGER array, + dimension ( N ) if ICOMPQ = 1, and not referenced if + ICOMPQ = 0. If ICOMPQ = 1, on exit, GIVPTR( I ) records + the number of Givens rotations performed on the I-th + problem on the computation tree. + + GIVCOL (output) INTEGER array, + dimension ( LDGCOL, 2 * NLVL ) if ICOMPQ = 1, and not + referenced if ICOMPQ = 0. If ICOMPQ = 1, on exit, for each I, + GIVCOL(1, 2 *I - 1) and GIVCOL(1, 2 *I) record the locations + of Givens rotations performed on the I-th level on the + computation tree. + + LDGCOL (input) INTEGER, LDGCOL = > N. + The leading dimension of arrays GIVCOL and PERM. + + PERM (output) INTEGER array, + dimension ( LDGCOL, NLVL ) if ICOMPQ = 1, and not referenced + if ICOMPQ = 0. If ICOMPQ = 1, on exit, PERM(1, I) records + permutations done on the I-th level of the computation tree. + + GIVNUM (output) DOUBLE PRECISION array, + dimension ( LDU, 2 * NLVL ) if ICOMPQ = 1, and not + referenced if ICOMPQ = 0. If ICOMPQ = 1, on exit, for each I, + GIVNUM(1, 2 *I - 1) and GIVNUM(1, 2 *I) record the C- and S- + values of Givens rotations performed on the I-th level on + the computation tree. + + C (output) DOUBLE PRECISION array, + dimension ( N ) if ICOMPQ = 1, and dimension 1 if ICOMPQ = 0. + If ICOMPQ = 1 and the I-th subproblem is not square, on exit, + C( I ) contains the C-value of a Givens rotation related to + the right null space of the I-th subproblem. + + S (output) DOUBLE PRECISION array, dimension ( N ) if + ICOMPQ = 1, and dimension 1 if ICOMPQ = 0. If ICOMPQ = 1 + and the I-th subproblem is not square, on exit, S( I ) + contains the S-value of a Givens rotation related to + the right null space of the I-th subproblem. + + WORK (workspace) DOUBLE PRECISION array, dimension + (6 * N + (SMLSIZ + 1)*(SMLSIZ + 1)). + + IWORK (workspace) INTEGER array. + Dimension must be at least (7 * N). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + givnum_dim1 = *ldu; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + poles_dim1 = *ldu; + poles_offset = 1 + poles_dim1; + poles -= poles_offset; + z_dim1 = *ldu; + z_offset = 1 + z_dim1; + z__ -= z_offset; + difr_dim1 = *ldu; + difr_offset = 1 + difr_dim1; + difr -= difr_offset; + difl_dim1 = *ldu; + difl_offset = 1 + difl_dim1; + difl -= difl_offset; + vt_dim1 = *ldu; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + --k; + --givptr; + perm_dim1 = *ldgcol; + perm_offset = 1 + perm_dim1; + perm -= perm_offset; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + --c__; + --s; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*smlsiz < 3) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*sqre < 0 || *sqre > 1) { + *info = -4; + } else if (*ldu < *n + *sqre) { + *info = -8; + } else if (*ldgcol < *n) { + *info = -17; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASDA", &i__1); + return 0; + } + + m = *n + *sqre; + +/* If the input matrix is too small, call DLASDQ to find the SVD. */ + + if (*n <= *smlsiz) { + if (*icompq == 0) { + dlasdq_("U", sqre, n, &c__0, &c__0, &c__0, &d__[1], &e[1], &vt[ + vt_offset], ldu, &u[u_offset], ldu, &u[u_offset], ldu, & + work[1], info); + } else { + dlasdq_("U", sqre, n, &m, n, &c__0, &d__[1], &e[1], &vt[vt_offset] + , ldu, &u[u_offset], ldu, &u[u_offset], ldu, &work[1], + info); + } + return 0; + } + +/* Book-keeping and set up the computation tree. */ + + inode = 1; + ndiml = inode + *n; + ndimr = ndiml + *n; + idxq = ndimr + *n; + iwk = idxq + *n; + + ncc = 0; + nru = 0; + + smlszp = *smlsiz + 1; + vf = 1; + vl = vf + m; + nwork1 = vl + m; + nwork2 = nwork1 + smlszp * smlszp; + + dlasdt_(n, &nlvl, &nd, &iwork[inode], &iwork[ndiml], &iwork[ndimr], + smlsiz); + +/* + for the nodes on bottom level of the tree, solve + their subproblems by DLASDQ. +*/ + + ndb1 = (nd + 1) / 2; + i__1 = nd; + for (i__ = ndb1; i__ <= i__1; ++i__) { + +/* + IC : center row of each node + NL : number of rows of left subproblem + NR : number of rows of right subproblem + NLF: starting row of the left subproblem + NRF: starting row of the right subproblem +*/ + + i1 = i__ - 1; + ic = iwork[inode + i1]; + nl = iwork[ndiml + i1]; + nlp1 = nl + 1; + nr = iwork[ndimr + i1]; + nlf = ic - nl; + nrf = ic + 1; + idxqi = idxq + nlf - 2; + vfi = vf + nlf - 1; + vli = vl + nlf - 1; + sqrei = 1; + if (*icompq == 0) { + dlaset_("A", &nlp1, &nlp1, &c_b29, &c_b15, &work[nwork1], &smlszp); + dlasdq_("U", &sqrei, &nl, &nlp1, &nru, &ncc, &d__[nlf], &e[nlf], & + work[nwork1], &smlszp, &work[nwork2], &nl, &work[nwork2], + &nl, &work[nwork2], info); + itemp = nwork1 + nl * smlszp; + dcopy_(&nlp1, &work[nwork1], &c__1, &work[vfi], &c__1); + dcopy_(&nlp1, &work[itemp], &c__1, &work[vli], &c__1); + } else { + dlaset_("A", &nl, &nl, &c_b29, &c_b15, &u[nlf + u_dim1], ldu); + dlaset_("A", &nlp1, &nlp1, &c_b29, &c_b15, &vt[nlf + vt_dim1], + ldu); + dlasdq_("U", &sqrei, &nl, &nlp1, &nl, &ncc, &d__[nlf], &e[nlf], & + vt[nlf + vt_dim1], ldu, &u[nlf + u_dim1], ldu, &u[nlf + + u_dim1], ldu, &work[nwork1], info); + dcopy_(&nlp1, &vt[nlf + vt_dim1], &c__1, &work[vfi], &c__1); + dcopy_(&nlp1, &vt[nlf + nlp1 * vt_dim1], &c__1, &work[vli], &c__1) + ; + } + if (*info != 0) { + return 0; + } + i__2 = nl; + for (j = 1; j <= i__2; ++j) { + iwork[idxqi + j] = j; +/* L10: */ + } + if (i__ == nd && *sqre == 0) { + sqrei = 0; + } else { + sqrei = 1; + } + idxqi += nlp1; + vfi += nlp1; + vli += nlp1; + nrp1 = nr + sqrei; + if (*icompq == 0) { + dlaset_("A", &nrp1, &nrp1, &c_b29, &c_b15, &work[nwork1], &smlszp); + dlasdq_("U", &sqrei, &nr, &nrp1, &nru, &ncc, &d__[nrf], &e[nrf], & + work[nwork1], &smlszp, &work[nwork2], &nr, &work[nwork2], + &nr, &work[nwork2], info); + itemp = nwork1 + (nrp1 - 1) * smlszp; + dcopy_(&nrp1, &work[nwork1], &c__1, &work[vfi], &c__1); + dcopy_(&nrp1, &work[itemp], &c__1, &work[vli], &c__1); + } else { + dlaset_("A", &nr, &nr, &c_b29, &c_b15, &u[nrf + u_dim1], ldu); + dlaset_("A", &nrp1, &nrp1, &c_b29, &c_b15, &vt[nrf + vt_dim1], + ldu); + dlasdq_("U", &sqrei, &nr, &nrp1, &nr, &ncc, &d__[nrf], &e[nrf], & + vt[nrf + vt_dim1], ldu, &u[nrf + u_dim1], ldu, &u[nrf + + u_dim1], ldu, &work[nwork1], info); + dcopy_(&nrp1, &vt[nrf + vt_dim1], &c__1, &work[vfi], &c__1); + dcopy_(&nrp1, &vt[nrf + nrp1 * vt_dim1], &c__1, &work[vli], &c__1) + ; + } + if (*info != 0) { + return 0; + } + i__2 = nr; + for (j = 1; j <= i__2; ++j) { + iwork[idxqi + j] = j; +/* L20: */ + } +/* L30: */ + } + +/* Now conquer each subproblem bottom-up. */ + + j = pow_ii(&c__2, &nlvl); + for (lvl = nlvl; lvl >= 1; --lvl) { + lvl2 = (lvl << 1) - 1; + +/* + Find the first node LF and last node LL on + the current level LVL. +*/ + + if (lvl == 1) { + lf = 1; + ll = 1; + } else { + i__1 = lvl - 1; + lf = pow_ii(&c__2, &i__1); + ll = (lf << 1) - 1; + } + i__1 = ll; + for (i__ = lf; i__ <= i__1; ++i__) { + im1 = i__ - 1; + ic = iwork[inode + im1]; + nl = iwork[ndiml + im1]; + nr = iwork[ndimr + im1]; + nlf = ic - nl; + nrf = ic + 1; + if (i__ == ll) { + sqrei = *sqre; + } else { + sqrei = 1; + } + vfi = vf + nlf - 1; + vli = vl + nlf - 1; + idxqi = idxq + nlf - 1; + alpha = d__[ic]; + beta = e[ic]; + if (*icompq == 0) { + dlasd6_(icompq, &nl, &nr, &sqrei, &d__[nlf], &work[vfi], & + work[vli], &alpha, &beta, &iwork[idxqi], &perm[ + perm_offset], &givptr[1], &givcol[givcol_offset], + ldgcol, &givnum[givnum_offset], ldu, &poles[ + poles_offset], &difl[difl_offset], &difr[difr_offset], + &z__[z_offset], &k[1], &c__[1], &s[1], &work[nwork1], + &iwork[iwk], info); + } else { + --j; + dlasd6_(icompq, &nl, &nr, &sqrei, &d__[nlf], &work[vfi], & + work[vli], &alpha, &beta, &iwork[idxqi], &perm[nlf + + lvl * perm_dim1], &givptr[j], &givcol[nlf + lvl2 * + givcol_dim1], ldgcol, &givnum[nlf + lvl2 * + givnum_dim1], ldu, &poles[nlf + lvl2 * poles_dim1], & + difl[nlf + lvl * difl_dim1], &difr[nlf + lvl2 * + difr_dim1], &z__[nlf + lvl * z_dim1], &k[j], &c__[j], + &s[j], &work[nwork1], &iwork[iwk], info); + } + if (*info != 0) { + return 0; + } +/* L40: */ + } +/* L50: */ + } + + return 0; + +/* End of DLASDA */ + +} /* dlasda_ */ + +/* Subroutine */ int dlasdq_(char *uplo, integer *sqre, integer *n, integer * + ncvt, integer *nru, integer *ncc, doublereal *d__, doublereal *e, + doublereal *vt, integer *ldvt, doublereal *u, integer *ldu, + doublereal *c__, integer *ldc, doublereal *work, integer *info) +{ + /* System generated locals */ + integer c_dim1, c_offset, u_dim1, u_offset, vt_dim1, vt_offset, i__1, + i__2; + + /* Local variables */ + static integer i__, j; + static doublereal r__, cs, sn; + static integer np1, isub; + static doublereal smin; + static integer sqre1; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dlasr_(char *, char *, char *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *), dswap_(integer *, doublereal *, integer * + , doublereal *, integer *); + static integer iuplo; + extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *), xerbla_(char *, + integer *), dbdsqr_(char *, integer *, integer *, integer + *, integer *, doublereal *, doublereal *, doublereal *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *); + static logical rotate; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASDQ computes the singular value decomposition (SVD) of a real + (upper or lower) bidiagonal matrix with diagonal D and offdiagonal + E, accumulating the transformations if desired. Letting B denote + the input bidiagonal matrix, the algorithm computes orthogonal + matrices Q and P such that B = Q * S * P' (P' denotes the transpose + of P). The singular values S are overwritten on D. + + The input matrix U is changed to U * Q if desired. + The input matrix VT is changed to P' * VT if desired. + The input matrix C is changed to Q' * C if desired. + + See "Computing Small Singular Values of Bidiagonal Matrices With + Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, + LAPACK Working Note #3, for a detailed description of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + On entry, UPLO specifies whether the input bidiagonal matrix + is upper or lower bidiagonal, and wether it is square are + not. + UPLO = 'U' or 'u' B is upper bidiagonal. + UPLO = 'L' or 'l' B is lower bidiagonal. + + SQRE (input) INTEGER + = 0: then the input matrix is N-by-N. + = 1: then the input matrix is N-by-(N+1) if UPLU = 'U' and + (N+1)-by-N if UPLU = 'L'. + + The bidiagonal matrix has + N = NL + NR + 1 rows and + M = N + SQRE >= N columns. + + N (input) INTEGER + On entry, N specifies the number of rows and columns + in the matrix. N must be at least 0. + + NCVT (input) INTEGER + On entry, NCVT specifies the number of columns of + the matrix VT. NCVT must be at least 0. + + NRU (input) INTEGER + On entry, NRU specifies the number of rows of + the matrix U. NRU must be at least 0. + + NCC (input) INTEGER + On entry, NCC specifies the number of columns of + the matrix C. NCC must be at least 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, D contains the diagonal entries of the + bidiagonal matrix whose SVD is desired. On normal exit, + D contains the singular values in ascending order. + + E (input/output) DOUBLE PRECISION array. + dimension is (N-1) if SQRE = 0 and N if SQRE = 1. + On entry, the entries of E contain the offdiagonal entries + of the bidiagonal matrix whose SVD is desired. On normal + exit, E will contain 0. If the algorithm does not converge, + D and E will contain the diagonal and superdiagonal entries + of a bidiagonal matrix orthogonally equivalent to the one + given as input. + + VT (input/output) DOUBLE PRECISION array, dimension (LDVT, NCVT) + On entry, contains a matrix which on exit has been + premultiplied by P', dimension N-by-NCVT if SQRE = 0 + and (N+1)-by-NCVT if SQRE = 1 (not referenced if NCVT=0). + + LDVT (input) INTEGER + On entry, LDVT specifies the leading dimension of VT as + declared in the calling (sub) program. LDVT must be at + least 1. If NCVT is nonzero LDVT must also be at least N. + + U (input/output) DOUBLE PRECISION array, dimension (LDU, N) + On entry, contains a matrix which on exit has been + postmultiplied by Q, dimension NRU-by-N if SQRE = 0 + and NRU-by-(N+1) if SQRE = 1 (not referenced if NRU=0). + + LDU (input) INTEGER + On entry, LDU specifies the leading dimension of U as + declared in the calling (sub) program. LDU must be at + least max( 1, NRU ) . + + C (input/output) DOUBLE PRECISION array, dimension (LDC, NCC) + On entry, contains an N-by-NCC matrix which on exit + has been premultiplied by Q' dimension N-by-NCC if SQRE = 0 + and (N+1)-by-NCC if SQRE = 1 (not referenced if NCC=0). + + LDC (input) INTEGER + On entry, LDC specifies the leading dimension of C as + declared in the calling (sub) program. LDC must be at + least 1. If NCC is nonzero, LDC must also be at least N. + + WORK (workspace) DOUBLE PRECISION array, dimension (4*N) + Workspace. Only referenced if one of NCVT, NRU, or NCC is + nonzero, and if N is at least 2. + + INFO (output) INTEGER + On exit, a value of 0 indicates a successful exit. + If INFO < 0, argument number -INFO is illegal. + If INFO > 0, the algorithm did not converge, and INFO + specifies how many superdiagonals did not converge. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + iuplo = 0; + if (lsame_(uplo, "U")) { + iuplo = 1; + } + if (lsame_(uplo, "L")) { + iuplo = 2; + } + if (iuplo == 0) { + *info = -1; + } else if (*sqre < 0 || *sqre > 1) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ncvt < 0) { + *info = -4; + } else if (*nru < 0) { + *info = -5; + } else if (*ncc < 0) { + *info = -6; + } else if (*ncvt == 0 && *ldvt < 1 || *ncvt > 0 && *ldvt < max(1,*n)) { + *info = -10; + } else if (*ldu < max(1,*nru)) { + *info = -12; + } else if (*ncc == 0 && *ldc < 1 || *ncc > 0 && *ldc < max(1,*n)) { + *info = -14; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASDQ", &i__1); + return 0; + } + if (*n == 0) { + return 0; + } + +/* ROTATE is true if any singular vectors desired, false otherwise */ + + rotate = *ncvt > 0 || *nru > 0 || *ncc > 0; + np1 = *n + 1; + sqre1 = *sqre; + +/* + If matrix non-square upper bidiagonal, rotate to be lower + bidiagonal. The rotations are on the right. +*/ + + if (iuplo == 1 && sqre1 == 1) { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + dlartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + if (rotate) { + work[i__] = cs; + work[*n + i__] = sn; + } +/* L10: */ + } + dlartg_(&d__[*n], &e[*n], &cs, &sn, &r__); + d__[*n] = r__; + e[*n] = 0.; + if (rotate) { + work[*n] = cs; + work[*n + *n] = sn; + } + iuplo = 2; + sqre1 = 0; + +/* Update singular vectors if desired. */ + + if (*ncvt > 0) { + dlasr_("L", "V", "F", &np1, ncvt, &work[1], &work[np1], &vt[ + vt_offset], ldvt); + } + } + +/* + If matrix lower bidiagonal, rotate to be upper bidiagonal + by applying Givens rotations on the left. +*/ + + if (iuplo == 2) { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + dlartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + if (rotate) { + work[i__] = cs; + work[*n + i__] = sn; + } +/* L20: */ + } + +/* + If matrix (N+1)-by-N lower bidiagonal, one additional + rotation is needed. +*/ + + if (sqre1 == 1) { + dlartg_(&d__[*n], &e[*n], &cs, &sn, &r__); + d__[*n] = r__; + if (rotate) { + work[*n] = cs; + work[*n + *n] = sn; + } + } + +/* Update singular vectors if desired. */ + + if (*nru > 0) { + if (sqre1 == 0) { + dlasr_("R", "V", "F", nru, n, &work[1], &work[np1], &u[ + u_offset], ldu); + } else { + dlasr_("R", "V", "F", nru, &np1, &work[1], &work[np1], &u[ + u_offset], ldu); + } + } + if (*ncc > 0) { + if (sqre1 == 0) { + dlasr_("L", "V", "F", n, ncc, &work[1], &work[np1], &c__[ + c_offset], ldc); + } else { + dlasr_("L", "V", "F", &np1, ncc, &work[1], &work[np1], &c__[ + c_offset], ldc); + } + } + } + +/* + Call DBDSQR to compute the SVD of the reduced real + N-by-N upper bidiagonal matrix. +*/ + + dbdsqr_("U", n, ncvt, nru, ncc, &d__[1], &e[1], &vt[vt_offset], ldvt, &u[ + u_offset], ldu, &c__[c_offset], ldc, &work[1], info); + +/* + Sort the singular values into ascending order (insertion sort on + singular values, but only one transposition per singular vector) +*/ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Scan for smallest D(I). */ + + isub = i__; + smin = d__[i__]; + i__2 = *n; + for (j = i__ + 1; j <= i__2; ++j) { + if (d__[j] < smin) { + isub = j; + smin = d__[j]; + } +/* L30: */ + } + if (isub != i__) { + +/* Swap singular values and vectors. */ + + d__[isub] = d__[i__]; + d__[i__] = smin; + if (*ncvt > 0) { + dswap_(ncvt, &vt[isub + vt_dim1], ldvt, &vt[i__ + vt_dim1], + ldvt); + } + if (*nru > 0) { + dswap_(nru, &u[isub * u_dim1 + 1], &c__1, &u[i__ * u_dim1 + 1] + , &c__1); + } + if (*ncc > 0) { + dswap_(ncc, &c__[isub + c_dim1], ldc, &c__[i__ + c_dim1], ldc) + ; + } + } +/* L40: */ + } + + return 0; + +/* End of DLASDQ */ + +} /* dlasdq_ */ + +/* Subroutine */ int dlasdt_(integer *n, integer *lvl, integer *nd, integer * + inode, integer *ndiml, integer *ndimr, integer *msub) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + static integer i__, il, ir, maxn; + static doublereal temp; + static integer nlvl, llst, ncrnt; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + DLASDT creates a tree of subproblems for bidiagonal divide and + conquer. + + Arguments + ========= + + N (input) INTEGER + On entry, the number of diagonal elements of the + bidiagonal matrix. + + LVL (output) INTEGER + On exit, the number of levels on the computation tree. + + ND (output) INTEGER + On exit, the number of nodes on the tree. + + INODE (output) INTEGER array, dimension ( N ) + On exit, centers of subproblems. + + NDIML (output) INTEGER array, dimension ( N ) + On exit, row dimensions of left children. + + NDIMR (output) INTEGER array, dimension ( N ) + On exit, row dimensions of right children. + + MSUB (input) INTEGER + On entry, the maximum row dimension each subproblem at the + bottom of the tree can be of. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Find the number of levels on the tree. +*/ + + /* Parameter adjustments */ + --ndimr; + --ndiml; + --inode; + + /* Function Body */ + maxn = max(1,*n); + temp = log((doublereal) maxn / (doublereal) (*msub + 1)) / log(2.); + *lvl = (integer) temp + 1; + + i__ = *n / 2; + inode[1] = i__ + 1; + ndiml[1] = i__; + ndimr[1] = *n - i__ - 1; + il = 0; + ir = 1; + llst = 1; + i__1 = *lvl - 1; + for (nlvl = 1; nlvl <= i__1; ++nlvl) { + +/* + Constructing the tree at (NLVL+1)-st level. The number of + nodes created on this level is LLST * 2. +*/ + + i__2 = llst - 1; + for (i__ = 0; i__ <= i__2; ++i__) { + il += 2; + ir += 2; + ncrnt = llst + i__; + ndiml[il] = ndiml[ncrnt] / 2; + ndimr[il] = ndiml[ncrnt] - ndiml[il] - 1; + inode[il] = inode[ncrnt] - ndimr[il] - 1; + ndiml[ir] = ndimr[ncrnt] / 2; + ndimr[ir] = ndimr[ncrnt] - ndiml[ir] - 1; + inode[ir] = inode[ncrnt] + ndiml[ir] + 1; +/* L10: */ + } + llst <<= 1; +/* L20: */ + } + *nd = (llst << 1) - 1; + + return 0; + +/* End of DLASDT */ + +} /* dlasdt_ */ + +/* Subroutine */ int dlaset_(char *uplo, integer *m, integer *n, doublereal * + alpha, doublereal *beta, doublereal *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASET initializes an m-by-n matrix A to BETA on the diagonal and + ALPHA on the offdiagonals. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be set. + = 'U': Upper triangular part is set; the strictly lower + triangular part of A is not changed. + = 'L': Lower triangular part is set; the strictly upper + triangular part of A is not changed. + Otherwise: All of the matrix A is set. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + ALPHA (input) DOUBLE PRECISION + The constant to which the offdiagonal elements are to be set. + + BETA (input) DOUBLE PRECISION + The constant to which the diagonal elements are to be set. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On exit, the leading m-by-n submatrix of A is set as follows: + + if UPLO = 'U', A(i,j) = ALPHA, 1<=i<=j-1, 1<=j<=n, + if UPLO = 'L', A(i,j) = ALPHA, j+1<=i<=m, 1<=j<=n, + otherwise, A(i,j) = ALPHA, 1<=i<=m, 1<=j<=n, i.ne.j, + + and, for all UPLO, A(i,i) = BETA, 1<=i<=min(m,n). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + +/* + Set the strictly upper triangular or trapezoidal part of the + array to ALPHA. +*/ + + i__1 = *n; + for (j = 2; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = j - 1; + i__2 = min(i__3,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = *alpha; +/* L10: */ + } +/* L20: */ + } + + } else if (lsame_(uplo, "L")) { + +/* + Set the strictly lower triangular or trapezoidal part of the + array to ALPHA. +*/ + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j + 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = *alpha; +/* L30: */ + } +/* L40: */ + } + + } else { + +/* Set the leading m-by-n submatrix to ALPHA. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = *alpha; +/* L50: */ + } +/* L60: */ + } + } + +/* Set the first min(M,N) diagonal elements to BETA. */ + + i__1 = min(*m,*n); + for (i__ = 1; i__ <= i__1; ++i__) { + a[i__ + i__ * a_dim1] = *beta; +/* L70: */ + } + + return 0; + +/* End of DLASET */ + +} /* dlaset_ */ + +/* Subroutine */ int dlasq1_(integer *n, doublereal *d__, doublereal *e, + doublereal *work, integer *info) +{ + /* System generated locals */ + integer i__1, i__2; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static integer i__; + static doublereal eps; + extern /* Subroutine */ int dlas2_(doublereal *, doublereal *, doublereal + *, doublereal *, doublereal *); + static doublereal scale; + static integer iinfo; + static doublereal sigmn; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static doublereal sigmx; + extern /* Subroutine */ int dlasq2_(integer *, doublereal *, integer *); + + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *); + static doublereal safmin; + extern /* Subroutine */ int xerbla_(char *, integer *), dlasrt_( + char *, integer *, doublereal *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + DLASQ1 computes the singular values of a real N-by-N bidiagonal + matrix with diagonal D and off-diagonal E. The singular values + are computed to high relative accuracy, in the absence of + denormalization, underflow and overflow. The algorithm was first + presented in + + "Accurate singular values and differential qd algorithms" by K. V. + Fernando and B. N. Parlett, Numer. Math., Vol-67, No. 2, pp. 191-230, + 1994, + + and the present implementation is described in "An implementation of + the dqds Algorithm (Positive Case)", LAPACK Working Note. + + Arguments + ========= + + N (input) INTEGER + The number of rows and columns in the matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, D contains the diagonal elements of the + bidiagonal matrix whose SVD is desired. On normal exit, + D contains the singular values in decreasing order. + + E (input/output) DOUBLE PRECISION array, dimension (N) + On entry, elements E(1:N-1) contain the off-diagonal elements + of the bidiagonal matrix whose SVD is desired. + On exit, E is overwritten. + + WORK (workspace) DOUBLE PRECISION array, dimension (4*N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: the algorithm failed + = 1, a split was marked by a positive value in E + = 2, current block of Z not diagonalized after 30*N + iterations (in inner while loop) + = 3, termination criterion of outer while loop not met + (program created more than N unreduced blocks) + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --work; + --e; + --d__; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -2; + i__1 = -(*info); + xerbla_("DLASQ1", &i__1); + return 0; + } else if (*n == 0) { + return 0; + } else if (*n == 1) { + d__[1] = abs(d__[1]); + return 0; + } else if (*n == 2) { + dlas2_(&d__[1], &e[1], &d__[2], &sigmn, &sigmx); + d__[1] = sigmx; + d__[2] = sigmn; + return 0; + } + +/* Estimate the largest singular value. */ + + sigmx = 0.; + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + d__[i__] = (d__1 = d__[i__], abs(d__1)); +/* Computing MAX */ + d__2 = sigmx, d__3 = (d__1 = e[i__], abs(d__1)); + sigmx = max(d__2,d__3); +/* L10: */ + } + d__[*n] = (d__1 = d__[*n], abs(d__1)); + +/* Early return if SIGMX is zero (matrix is already diagonal). */ + + if (sigmx == 0.) { + dlasrt_("D", n, &d__[1], &iinfo); + return 0; + } + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__1 = sigmx, d__2 = d__[i__]; + sigmx = max(d__1,d__2); +/* L20: */ + } + +/* + Copy D and E into WORK (in the Z format) and scale (squaring the + input data makes scaling by a power of the radix pointless). +*/ + + eps = PRECISION; + safmin = SAFEMINIMUM; + scale = sqrt(eps / safmin); + dcopy_(n, &d__[1], &c__1, &work[1], &c__2); + i__1 = *n - 1; + dcopy_(&i__1, &e[1], &c__1, &work[2], &c__2); + i__1 = (*n << 1) - 1; + i__2 = (*n << 1) - 1; + dlascl_("G", &c__0, &c__0, &sigmx, &scale, &i__1, &c__1, &work[1], &i__2, + &iinfo); + +/* Compute the q's and e's. */ + + i__1 = (*n << 1) - 1; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing 2nd power */ + d__1 = work[i__]; + work[i__] = d__1 * d__1; +/* L30: */ + } + work[*n * 2] = 0.; + + dlasq2_(n, &work[1], info); + + if (*info == 0) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d__[i__] = sqrt(work[i__]); +/* L40: */ + } + dlascl_("G", &c__0, &c__0, &scale, &sigmx, n, &c__1, &d__[1], n, & + iinfo); + } + + return 0; + +/* End of DLASQ1 */ + +} /* dlasq1_ */ + +/* Subroutine */ int dlasq2_(integer *n, doublereal *z__, integer *info) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal d__, e, g; + static integer k; + static doublereal s, t; + static integer i0, i4, n0; + static doublereal dn; + static integer pp; + static doublereal dn1, dn2, dee, eps, tau, tol; + static integer ipn4; + static doublereal tol2; + static logical ieee; + static integer nbig; + static doublereal dmin__, emin, emax; + static integer kmin, ndiv, iter; + static doublereal qmin, temp, qmax, zmax; + static integer splt; + static doublereal dmin1, dmin2; + static integer nfail; + static doublereal desig, trace, sigma; + static integer iinfo, ttype; + extern /* Subroutine */ int dlasq3_(integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, doublereal *, doublereal *, + integer *, integer *, integer *, logical *, integer *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *); + + static doublereal deemin; + static integer iwhila, iwhilb; + static doublereal oldemn, safmin; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, + integer *); + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + DLASQ2 computes all the eigenvalues of the symmetric positive + definite tridiagonal matrix associated with the qd array Z to high + relative accuracy are computed to high relative accuracy, in the + absence of denormalization, underflow and overflow. + + To see the relation of Z to the tridiagonal matrix, let L be a + unit lower bidiagonal matrix with subdiagonals Z(2,4,6,,..) and + let U be an upper bidiagonal matrix with 1's above and diagonal + Z(1,3,5,,..). The tridiagonal is L*U or, if you prefer, the + symmetric tridiagonal to which it is similar. + + Note : DLASQ2 defines a logical variable, IEEE, which is true + on machines which follow ieee-754 floating-point standard in their + handling of infinities and NaNs, and false otherwise. This variable + is passed to DLASQ3. + + Arguments + ========= + + N (input) INTEGER + The number of rows and columns in the matrix. N >= 0. + + Z (input/output) DOUBLE PRECISION array, dimension ( 4*N ) + On entry Z holds the qd array. On exit, entries 1 to N hold + the eigenvalues in decreasing order, Z( 2*N+1 ) holds the + trace, and Z( 2*N+2 ) holds the sum of the eigenvalues. If + N > 2, then Z( 2*N+3 ) holds the iteration count, Z( 2*N+4 ) + holds NDIVS/NIN^2, and Z( 2*N+5 ) holds the percentage of + shifts that failed. + + INFO (output) INTEGER + = 0: successful exit + < 0: if the i-th argument is a scalar and had an illegal + value, then INFO = -i, if the i-th argument is an + array and the j-entry had an illegal value, then + INFO = -(i*100+j) + > 0: the algorithm failed + = 1, a split was marked by a positive value in E + = 2, current block of Z not diagonalized after 30*N + iterations (in inner while loop) + = 3, termination criterion of outer while loop not met + (program created more than N unreduced blocks) + + Further Details + =============== + Local Variables: I0:N0 defines a current unreduced segment of Z. + The shifts are accumulated in SIGMA. Iteration count is in ITER. + Ping-pong is controlled by PP (alternates between 0 and 1). + + ===================================================================== + + + Test the input arguments. + (in case DLASQ2 is not called by DLASQ1) +*/ + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + *info = 0; + eps = PRECISION; + safmin = SAFEMINIMUM; + tol = eps * 100.; +/* Computing 2nd power */ + d__1 = tol; + tol2 = d__1 * d__1; + + if (*n < 0) { + *info = -1; + xerbla_("DLASQ2", &c__1); + return 0; + } else if (*n == 0) { + return 0; + } else if (*n == 1) { + +/* 1-by-1 case. */ + + if (z__[1] < 0.) { + *info = -201; + xerbla_("DLASQ2", &c__2); + } + return 0; + } else if (*n == 2) { + +/* 2-by-2 case. */ + + if (z__[2] < 0. || z__[3] < 0.) { + *info = -2; + xerbla_("DLASQ2", &c__2); + return 0; + } else if (z__[3] > z__[1]) { + d__ = z__[3]; + z__[3] = z__[1]; + z__[1] = d__; + } + z__[5] = z__[1] + z__[2] + z__[3]; + if (z__[2] > z__[3] * tol2) { + t = (z__[1] - z__[3] + z__[2]) * .5; + s = z__[3] * (z__[2] / t); + if (s <= t) { + s = z__[3] * (z__[2] / (t * (sqrt(s / t + 1.) + 1.))); + } else { + s = z__[3] * (z__[2] / (t + sqrt(t) * sqrt(t + s))); + } + t = z__[1] + (s + z__[2]); + z__[3] *= z__[1] / t; + z__[1] = t; + } + z__[2] = z__[3]; + z__[6] = z__[2] + z__[1]; + return 0; + } + +/* Check for negative data and compute sums of q's and e's. */ + + z__[*n * 2] = 0.; + emin = z__[2]; + qmax = 0.; + zmax = 0.; + d__ = 0.; + e = 0.; + + i__1 = *n - 1 << 1; + for (k = 1; k <= i__1; k += 2) { + if (z__[k] < 0.) { + *info = -(k + 200); + xerbla_("DLASQ2", &c__2); + return 0; + } else if (z__[k + 1] < 0.) { + *info = -(k + 201); + xerbla_("DLASQ2", &c__2); + return 0; + } + d__ += z__[k]; + e += z__[k + 1]; +/* Computing MAX */ + d__1 = qmax, d__2 = z__[k]; + qmax = max(d__1,d__2); +/* Computing MIN */ + d__1 = emin, d__2 = z__[k + 1]; + emin = min(d__1,d__2); +/* Computing MAX */ + d__1 = max(qmax,zmax), d__2 = z__[k + 1]; + zmax = max(d__1,d__2); +/* L10: */ + } + if (z__[(*n << 1) - 1] < 0.) { + *info = -((*n << 1) + 199); + xerbla_("DLASQ2", &c__2); + return 0; + } + d__ += z__[(*n << 1) - 1]; +/* Computing MAX */ + d__1 = qmax, d__2 = z__[(*n << 1) - 1]; + qmax = max(d__1,d__2); + zmax = max(qmax,zmax); + +/* Check for diagonality. */ + + if (e == 0.) { + i__1 = *n; + for (k = 2; k <= i__1; ++k) { + z__[k] = z__[(k << 1) - 1]; +/* L20: */ + } + dlasrt_("D", n, &z__[1], &iinfo); + z__[(*n << 1) - 1] = d__; + return 0; + } + + trace = d__ + e; + +/* Check for zero data. */ + + if (trace == 0.) { + z__[(*n << 1) - 1] = 0.; + return 0; + } + +/* Check whether the machine is IEEE conformable. */ + + ieee = ilaenv_(&c__10, "DLASQ2", "N", &c__1, &c__2, &c__3, &c__4, (ftnlen) + 6, (ftnlen)1) == 1 && ilaenv_(&c__11, "DLASQ2", "N", &c__1, &c__2, + &c__3, &c__4, (ftnlen)6, (ftnlen)1) == 1; + +/* Rearrange data for locality: Z=(q1,qq1,e1,ee1,q2,qq2,e2,ee2,...). */ + + for (k = *n << 1; k >= 2; k += -2) { + z__[k * 2] = 0.; + z__[(k << 1) - 1] = z__[k]; + z__[(k << 1) - 2] = 0.; + z__[(k << 1) - 3] = z__[k - 1]; +/* L30: */ + } + + i0 = 1; + n0 = *n; + +/* Reverse the qd-array, if warranted. */ + + if (z__[(i0 << 2) - 3] * 1.5 < z__[(n0 << 2) - 3]) { + ipn4 = i0 + n0 << 2; + i__1 = i0 + n0 - 1 << 1; + for (i4 = i0 << 2; i4 <= i__1; i4 += 4) { + temp = z__[i4 - 3]; + z__[i4 - 3] = z__[ipn4 - i4 - 3]; + z__[ipn4 - i4 - 3] = temp; + temp = z__[i4 - 1]; + z__[i4 - 1] = z__[ipn4 - i4 - 5]; + z__[ipn4 - i4 - 5] = temp; +/* L40: */ + } + } + +/* Initial split checking via dqd and Li's test. */ + + pp = 0; + + for (k = 1; k <= 2; ++k) { + + d__ = z__[(n0 << 2) + pp - 3]; + i__1 = (i0 << 2) + pp; + for (i4 = (n0 - 1 << 2) + pp; i4 >= i__1; i4 += -4) { + if (z__[i4 - 1] <= tol2 * d__) { + z__[i4 - 1] = -0.; + d__ = z__[i4 - 3]; + } else { + d__ = z__[i4 - 3] * (d__ / (d__ + z__[i4 - 1])); + } +/* L50: */ + } + +/* dqd maps Z to ZZ plus Li's test. */ + + emin = z__[(i0 << 2) + pp + 1]; + d__ = z__[(i0 << 2) + pp - 3]; + i__1 = (n0 - 1 << 2) + pp; + for (i4 = (i0 << 2) + pp; i4 <= i__1; i4 += 4) { + z__[i4 - (pp << 1) - 2] = d__ + z__[i4 - 1]; + if (z__[i4 - 1] <= tol2 * d__) { + z__[i4 - 1] = -0.; + z__[i4 - (pp << 1) - 2] = d__; + z__[i4 - (pp << 1)] = 0.; + d__ = z__[i4 + 1]; + } else if (safmin * z__[i4 + 1] < z__[i4 - (pp << 1) - 2] && + safmin * z__[i4 - (pp << 1) - 2] < z__[i4 + 1]) { + temp = z__[i4 + 1] / z__[i4 - (pp << 1) - 2]; + z__[i4 - (pp << 1)] = z__[i4 - 1] * temp; + d__ *= temp; + } else { + z__[i4 - (pp << 1)] = z__[i4 + 1] * (z__[i4 - 1] / z__[i4 - ( + pp << 1) - 2]); + d__ = z__[i4 + 1] * (d__ / z__[i4 - (pp << 1) - 2]); + } +/* Computing MIN */ + d__1 = emin, d__2 = z__[i4 - (pp << 1)]; + emin = min(d__1,d__2); +/* L60: */ + } + z__[(n0 << 2) - pp - 2] = d__; + +/* Now find qmax. */ + + qmax = z__[(i0 << 2) - pp - 2]; + i__1 = (n0 << 2) - pp - 2; + for (i4 = (i0 << 2) - pp + 2; i4 <= i__1; i4 += 4) { +/* Computing MAX */ + d__1 = qmax, d__2 = z__[i4]; + qmax = max(d__1,d__2); +/* L70: */ + } + +/* Prepare for the next iteration on K. */ + + pp = 1 - pp; +/* L80: */ + } + +/* Initialise variables to pass to DLASQ3. */ + + ttype = 0; + dmin1 = 0.; + dmin2 = 0.; + dn = 0.; + dn1 = 0.; + dn2 = 0.; + g = 0.; + tau = 0.; + + iter = 2; + nfail = 0; + ndiv = n0 - i0 << 1; + + i__1 = *n + 1; + for (iwhila = 1; iwhila <= i__1; ++iwhila) { + if (n0 < 1) { + goto L170; + } + +/* + While array unfinished do + + E(N0) holds the value of SIGMA when submatrix in I0:N0 + splits from the rest of the array, but is negated. +*/ + + desig = 0.; + if (n0 == *n) { + sigma = 0.; + } else { + sigma = -z__[(n0 << 2) - 1]; + } + if (sigma < 0.) { + *info = 1; + return 0; + } + +/* + Find last unreduced submatrix's top index I0, find QMAX and + EMIN. Find Gershgorin-type bound if Q's much greater than E's. +*/ + + emax = 0.; + if (n0 > i0) { + emin = (d__1 = z__[(n0 << 2) - 5], abs(d__1)); + } else { + emin = 0.; + } + qmin = z__[(n0 << 2) - 3]; + qmax = qmin; + for (i4 = n0 << 2; i4 >= 8; i4 += -4) { + if (z__[i4 - 5] <= 0.) { + goto L100; + } + if (qmin >= emax * 4.) { +/* Computing MIN */ + d__1 = qmin, d__2 = z__[i4 - 3]; + qmin = min(d__1,d__2); +/* Computing MAX */ + d__1 = emax, d__2 = z__[i4 - 5]; + emax = max(d__1,d__2); + } +/* Computing MAX */ + d__1 = qmax, d__2 = z__[i4 - 7] + z__[i4 - 5]; + qmax = max(d__1,d__2); +/* Computing MIN */ + d__1 = emin, d__2 = z__[i4 - 5]; + emin = min(d__1,d__2); +/* L90: */ + } + i4 = 4; + +L100: + i0 = i4 / 4; + pp = 0; + + if (n0 - i0 > 1) { + dee = z__[(i0 << 2) - 3]; + deemin = dee; + kmin = i0; + i__2 = (n0 << 2) - 3; + for (i4 = (i0 << 2) + 1; i4 <= i__2; i4 += 4) { + dee = z__[i4] * (dee / (dee + z__[i4 - 2])); + if (dee <= deemin) { + deemin = dee; + kmin = (i4 + 3) / 4; + } +/* L110: */ + } + if (kmin - i0 << 1 < n0 - kmin && deemin <= z__[(n0 << 2) - 3] * + .5) { + ipn4 = i0 + n0 << 2; + pp = 2; + i__2 = i0 + n0 - 1 << 1; + for (i4 = i0 << 2; i4 <= i__2; i4 += 4) { + temp = z__[i4 - 3]; + z__[i4 - 3] = z__[ipn4 - i4 - 3]; + z__[ipn4 - i4 - 3] = temp; + temp = z__[i4 - 2]; + z__[i4 - 2] = z__[ipn4 - i4 - 2]; + z__[ipn4 - i4 - 2] = temp; + temp = z__[i4 - 1]; + z__[i4 - 1] = z__[ipn4 - i4 - 5]; + z__[ipn4 - i4 - 5] = temp; + temp = z__[i4]; + z__[i4] = z__[ipn4 - i4 - 4]; + z__[ipn4 - i4 - 4] = temp; +/* L120: */ + } + } + } + +/* + Put -(initial shift) into DMIN. + + Computing MAX +*/ + d__1 = 0., d__2 = qmin - sqrt(qmin) * 2. * sqrt(emax); + dmin__ = -max(d__1,d__2); + +/* + Now I0:N0 is unreduced. + PP = 0 for ping, PP = 1 for pong. + PP = 2 indicates that flipping was applied to the Z array and + and that the tests for deflation upon entry in DLASQ3 + should not be performed. +*/ + + nbig = (n0 - i0 + 1) * 30; + i__2 = nbig; + for (iwhilb = 1; iwhilb <= i__2; ++iwhilb) { + if (i0 > n0) { + goto L150; + } + +/* While submatrix unfinished take a good dqds step. */ + + dlasq3_(&i0, &n0, &z__[1], &pp, &dmin__, &sigma, &desig, &qmax, & + nfail, &iter, &ndiv, &ieee, &ttype, &dmin1, &dmin2, &dn, & + dn1, &dn2, &g, &tau); + + pp = 1 - pp; + +/* When EMIN is very small check for splits. */ + + if (pp == 0 && n0 - i0 >= 3) { + if (z__[n0 * 4] <= tol2 * qmax || z__[(n0 << 2) - 1] <= tol2 * + sigma) { + splt = i0 - 1; + qmax = z__[(i0 << 2) - 3]; + emin = z__[(i0 << 2) - 1]; + oldemn = z__[i0 * 4]; + i__3 = n0 - 3 << 2; + for (i4 = i0 << 2; i4 <= i__3; i4 += 4) { + if (z__[i4] <= tol2 * z__[i4 - 3] || z__[i4 - 1] <= + tol2 * sigma) { + z__[i4 - 1] = -sigma; + splt = i4 / 4; + qmax = 0.; + emin = z__[i4 + 3]; + oldemn = z__[i4 + 4]; + } else { +/* Computing MAX */ + d__1 = qmax, d__2 = z__[i4 + 1]; + qmax = max(d__1,d__2); +/* Computing MIN */ + d__1 = emin, d__2 = z__[i4 - 1]; + emin = min(d__1,d__2); +/* Computing MIN */ + d__1 = oldemn, d__2 = z__[i4]; + oldemn = min(d__1,d__2); + } +/* L130: */ + } + z__[(n0 << 2) - 1] = emin; + z__[n0 * 4] = oldemn; + i0 = splt + 1; + } + } + +/* L140: */ + } + + *info = 2; + return 0; + +/* end IWHILB */ + +L150: + +/* L160: */ + ; + } + + *info = 3; + return 0; + +/* end IWHILA */ + +L170: + +/* Move q's to the front. */ + + i__1 = *n; + for (k = 2; k <= i__1; ++k) { + z__[k] = z__[(k << 2) - 3]; +/* L180: */ + } + +/* Sort and compute sum of eigenvalues. */ + + dlasrt_("D", n, &z__[1], &iinfo); + + e = 0.; + for (k = *n; k >= 1; --k) { + e += z__[k]; +/* L190: */ + } + +/* Store trace, sum(eigenvalues) and information on performance. */ + + z__[(*n << 1) + 1] = trace; + z__[(*n << 1) + 2] = e; + z__[(*n << 1) + 3] = (doublereal) iter; +/* Computing 2nd power */ + i__1 = *n; + z__[(*n << 1) + 4] = (doublereal) ndiv / (doublereal) (i__1 * i__1); + z__[(*n << 1) + 5] = nfail * 100. / (doublereal) iter; + return 0; + +/* End of DLASQ2 */ + +} /* dlasq2_ */ + +/* Subroutine */ int dlasq3_(integer *i0, integer *n0, doublereal *z__, + integer *pp, doublereal *dmin__, doublereal *sigma, doublereal *desig, + doublereal *qmax, integer *nfail, integer *iter, integer *ndiv, + logical *ieee, integer *ttype, doublereal *dmin1, doublereal *dmin2, + doublereal *dn, doublereal *dn1, doublereal *dn2, doublereal *g, + doublereal *tau) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal s, t; + static integer j4, nn; + static doublereal eps, tol; + static integer n0in, ipn4; + static doublereal tol2, temp; + extern /* Subroutine */ int dlasq4_(integer *, integer *, doublereal *, + integer *, integer *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *, + doublereal *), dlasq5_(integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, logical *), dlasq6_( + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *); + + extern logical disnan_(doublereal *); + + +/* + -- LAPACK routine (version 3.2.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + DLASQ3 checks for deflation, computes a shift (TAU) and calls dqds. + In case of failure it changes shifts, and tries again until output + is positive. + + Arguments + ========= + + I0 (input) INTEGER + First index. + + N0 (input/output) INTEGER + Last index. + + Z (input) DOUBLE PRECISION array, dimension ( 4*N ) + Z holds the qd array. + + PP (input/output) INTEGER + PP=0 for ping, PP=1 for pong. + PP=2 indicates that flipping was applied to the Z array + and that the initial tests for deflation should not be + performed. + + DMIN (output) DOUBLE PRECISION + Minimum value of d. + + SIGMA (output) DOUBLE PRECISION + Sum of shifts used in current segment. + + DESIG (input/output) DOUBLE PRECISION + Lower order part of SIGMA + + QMAX (input) DOUBLE PRECISION + Maximum value of q. + + NFAIL (output) INTEGER + Number of times shift was too big. + + ITER (output) INTEGER + Number of iterations. + + NDIV (output) INTEGER + Number of divisions. + + IEEE (input) LOGICAL + Flag for IEEE or non IEEE arithmetic (passed to DLASQ5). + + TTYPE (input/output) INTEGER + Shift type. + + DMIN1 (input/output) DOUBLE PRECISION + + DMIN2 (input/output) DOUBLE PRECISION + + DN (input/output) DOUBLE PRECISION + + DN1 (input/output) DOUBLE PRECISION + + DN2 (input/output) DOUBLE PRECISION + + G (input/output) DOUBLE PRECISION + + TAU (input/output) DOUBLE PRECISION + + These are passed as arguments in order to save their values + between calls to DLASQ3. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + n0in = *n0; + eps = PRECISION; + tol = eps * 100.; +/* Computing 2nd power */ + d__1 = tol; + tol2 = d__1 * d__1; + +/* Check for deflation. */ + +L10: + + if (*n0 < *i0) { + return 0; + } + if (*n0 == *i0) { + goto L20; + } + nn = (*n0 << 2) + *pp; + if (*n0 == *i0 + 1) { + goto L40; + } + +/* Check whether E(N0-1) is negligible, 1 eigenvalue. */ + + if (z__[nn - 5] > tol2 * (*sigma + z__[nn - 3]) && z__[nn - (*pp << 1) - + 4] > tol2 * z__[nn - 7]) { + goto L30; + } + +L20: + + z__[(*n0 << 2) - 3] = z__[(*n0 << 2) + *pp - 3] + *sigma; + --(*n0); + goto L10; + +/* Check whether E(N0-2) is negligible, 2 eigenvalues. */ + +L30: + + if (z__[nn - 9] > tol2 * *sigma && z__[nn - (*pp << 1) - 8] > tol2 * z__[ + nn - 11]) { + goto L50; + } + +L40: + + if (z__[nn - 3] > z__[nn - 7]) { + s = z__[nn - 3]; + z__[nn - 3] = z__[nn - 7]; + z__[nn - 7] = s; + } + if (z__[nn - 5] > z__[nn - 3] * tol2) { + t = (z__[nn - 7] - z__[nn - 3] + z__[nn - 5]) * .5; + s = z__[nn - 3] * (z__[nn - 5] / t); + if (s <= t) { + s = z__[nn - 3] * (z__[nn - 5] / (t * (sqrt(s / t + 1.) + 1.))); + } else { + s = z__[nn - 3] * (z__[nn - 5] / (t + sqrt(t) * sqrt(t + s))); + } + t = z__[nn - 7] + (s + z__[nn - 5]); + z__[nn - 3] *= z__[nn - 7] / t; + z__[nn - 7] = t; + } + z__[(*n0 << 2) - 7] = z__[nn - 7] + *sigma; + z__[(*n0 << 2) - 3] = z__[nn - 3] + *sigma; + *n0 += -2; + goto L10; + +L50: + if (*pp == 2) { + *pp = 0; + } + +/* Reverse the qd-array, if warranted. */ + + if (*dmin__ <= 0. || *n0 < n0in) { + if (z__[(*i0 << 2) + *pp - 3] * 1.5 < z__[(*n0 << 2) + *pp - 3]) { + ipn4 = *i0 + *n0 << 2; + i__1 = *i0 + *n0 - 1 << 1; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + temp = z__[j4 - 3]; + z__[j4 - 3] = z__[ipn4 - j4 - 3]; + z__[ipn4 - j4 - 3] = temp; + temp = z__[j4 - 2]; + z__[j4 - 2] = z__[ipn4 - j4 - 2]; + z__[ipn4 - j4 - 2] = temp; + temp = z__[j4 - 1]; + z__[j4 - 1] = z__[ipn4 - j4 - 5]; + z__[ipn4 - j4 - 5] = temp; + temp = z__[j4]; + z__[j4] = z__[ipn4 - j4 - 4]; + z__[ipn4 - j4 - 4] = temp; +/* L60: */ + } + if (*n0 - *i0 <= 4) { + z__[(*n0 << 2) + *pp - 1] = z__[(*i0 << 2) + *pp - 1]; + z__[(*n0 << 2) - *pp] = z__[(*i0 << 2) - *pp]; + } +/* Computing MIN */ + d__1 = *dmin2, d__2 = z__[(*n0 << 2) + *pp - 1]; + *dmin2 = min(d__1,d__2); +/* Computing MIN */ + d__1 = z__[(*n0 << 2) + *pp - 1], d__2 = z__[(*i0 << 2) + *pp - 1] + , d__1 = min(d__1,d__2), d__2 = z__[(*i0 << 2) + *pp + 3]; + z__[(*n0 << 2) + *pp - 1] = min(d__1,d__2); +/* Computing MIN */ + d__1 = z__[(*n0 << 2) - *pp], d__2 = z__[(*i0 << 2) - *pp], d__1 = + min(d__1,d__2), d__2 = z__[(*i0 << 2) - *pp + 4]; + z__[(*n0 << 2) - *pp] = min(d__1,d__2); +/* Computing MAX */ + d__1 = *qmax, d__2 = z__[(*i0 << 2) + *pp - 3], d__1 = max(d__1, + d__2), d__2 = z__[(*i0 << 2) + *pp + 1]; + *qmax = max(d__1,d__2); + *dmin__ = -0.; + } + } + +/* Choose a shift. */ + + dlasq4_(i0, n0, &z__[1], pp, &n0in, dmin__, dmin1, dmin2, dn, dn1, dn2, + tau, ttype, g); + +/* Call dqds until DMIN > 0. */ + +L70: + + dlasq5_(i0, n0, &z__[1], pp, tau, dmin__, dmin1, dmin2, dn, dn1, dn2, + ieee); + + *ndiv += *n0 - *i0 + 2; + ++(*iter); + +/* Check status. */ + + if (*dmin__ >= 0. && *dmin1 > 0.) { + +/* Success. */ + + goto L90; + + } else if (*dmin__ < 0. && *dmin1 > 0. && z__[(*n0 - 1 << 2) - *pp] < tol + * (*sigma + *dn1) && abs(*dn) < tol * *sigma) { + +/* Convergence hidden by negative DN. */ + + z__[(*n0 - 1 << 2) - *pp + 2] = 0.; + *dmin__ = 0.; + goto L90; + } else if (*dmin__ < 0.) { + +/* TAU too big. Select new TAU and try again. */ + + ++(*nfail); + if (*ttype < -22) { + +/* Failed twice. Play it safe. */ + + *tau = 0.; + } else if (*dmin1 > 0.) { + +/* Late failure. Gives excellent shift. */ + + *tau = (*tau + *dmin__) * (1. - eps * 2.); + *ttype += -11; + } else { + +/* Early failure. Divide by 4. */ + + *tau *= .25; + *ttype += -12; + } + goto L70; + } else if (disnan_(dmin__)) { + +/* NaN. */ + + if (*tau == 0.) { + goto L80; + } else { + *tau = 0.; + goto L70; + } + } else { + +/* Possible underflow. Play it safe. */ + + goto L80; + } + +/* Risk of underflow. */ + +L80: + dlasq6_(i0, n0, &z__[1], pp, dmin__, dmin1, dmin2, dn, dn1, dn2); + *ndiv += *n0 - *i0 + 2; + ++(*iter); + *tau = 0.; + +L90: + if (*tau < *sigma) { + *desig += *tau; + t = *sigma + *desig; + *desig -= t - *sigma; + } else { + t = *sigma + *tau; + *desig = *sigma - (t - *tau) + *desig; + } + *sigma = t; + + return 0; + +/* End of DLASQ3 */ + +} /* dlasq3_ */ + +/* Subroutine */ int dlasq4_(integer *i0, integer *n0, doublereal *z__, + integer *pp, integer *n0in, doublereal *dmin__, doublereal *dmin1, + doublereal *dmin2, doublereal *dn, doublereal *dn1, doublereal *dn2, + doublereal *tau, integer *ttype, doublereal *g) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal s, a2, b1, b2; + static integer i4, nn, np; + static doublereal gam, gap1, gap2; + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + DLASQ4 computes an approximation TAU to the smallest eigenvalue + using values of d from the previous transform. + + I0 (input) INTEGER + First index. + + N0 (input) INTEGER + Last index. + + Z (input) DOUBLE PRECISION array, dimension ( 4*N ) + Z holds the qd array. + + PP (input) INTEGER + PP=0 for ping, PP=1 for pong. + + NOIN (input) INTEGER + The value of N0 at start of EIGTEST. + + DMIN (input) DOUBLE PRECISION + Minimum value of d. + + DMIN1 (input) DOUBLE PRECISION + Minimum value of d, excluding D( N0 ). + + DMIN2 (input) DOUBLE PRECISION + Minimum value of d, excluding D( N0 ) and D( N0-1 ). + + DN (input) DOUBLE PRECISION + d(N) + + DN1 (input) DOUBLE PRECISION + d(N-1) + + DN2 (input) DOUBLE PRECISION + d(N-2) + + TAU (output) DOUBLE PRECISION + This is the shift. + + TTYPE (output) INTEGER + Shift type. + + G (input/output) REAL + G is passed as an argument in order to save its value between + calls to DLASQ4. + + Further Details + =============== + CNST1 = 9/16 + + ===================================================================== + + + A negative DMIN forces the shift to take that absolute value + TTYPE records the type of shift. +*/ + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + if (*dmin__ <= 0.) { + *tau = -(*dmin__); + *ttype = -1; + return 0; + } + + nn = (*n0 << 2) + *pp; + if (*n0in == *n0) { + +/* No eigenvalues deflated. */ + + if (*dmin__ == *dn || *dmin__ == *dn1) { + + b1 = sqrt(z__[nn - 3]) * sqrt(z__[nn - 5]); + b2 = sqrt(z__[nn - 7]) * sqrt(z__[nn - 9]); + a2 = z__[nn - 7] + z__[nn - 5]; + +/* Cases 2 and 3. */ + + if (*dmin__ == *dn && *dmin1 == *dn1) { + gap2 = *dmin2 - a2 - *dmin2 * .25; + if (gap2 > 0. && gap2 > b2) { + gap1 = a2 - *dn - b2 / gap2 * b2; + } else { + gap1 = a2 - *dn - (b1 + b2); + } + if (gap1 > 0. && gap1 > b1) { +/* Computing MAX */ + d__1 = *dn - b1 / gap1 * b1, d__2 = *dmin__ * .5; + s = max(d__1,d__2); + *ttype = -2; + } else { + s = 0.; + if (*dn > b1) { + s = *dn - b1; + } + if (a2 > b1 + b2) { +/* Computing MIN */ + d__1 = s, d__2 = a2 - (b1 + b2); + s = min(d__1,d__2); + } +/* Computing MAX */ + d__1 = s, d__2 = *dmin__ * .333; + s = max(d__1,d__2); + *ttype = -3; + } + } else { + +/* Case 4. */ + + *ttype = -4; + s = *dmin__ * .25; + if (*dmin__ == *dn) { + gam = *dn; + a2 = 0.; + if (z__[nn - 5] > z__[nn - 7]) { + return 0; + } + b2 = z__[nn - 5] / z__[nn - 7]; + np = nn - 9; + } else { + np = nn - (*pp << 1); + b2 = z__[np - 2]; + gam = *dn1; + if (z__[np - 4] > z__[np - 2]) { + return 0; + } + a2 = z__[np - 4] / z__[np - 2]; + if (z__[nn - 9] > z__[nn - 11]) { + return 0; + } + b2 = z__[nn - 9] / z__[nn - 11]; + np = nn - 13; + } + +/* Approximate contribution to norm squared from I < NN-1. */ + + a2 += b2; + i__1 = (*i0 << 2) - 1 + *pp; + for (i4 = np; i4 >= i__1; i4 += -4) { + if (b2 == 0.) { + goto L20; + } + b1 = b2; + if (z__[i4] > z__[i4 - 2]) { + return 0; + } + b2 *= z__[i4] / z__[i4 - 2]; + a2 += b2; + if (max(b2,b1) * 100. < a2 || .563 < a2) { + goto L20; + } +/* L10: */ + } +L20: + a2 *= 1.05; + +/* Rayleigh quotient residual bound. */ + + if (a2 < .563) { + s = gam * (1. - sqrt(a2)) / (a2 + 1.); + } + } + } else if (*dmin__ == *dn2) { + +/* Case 5. */ + + *ttype = -5; + s = *dmin__ * .25; + +/* Compute contribution to norm squared from I > NN-2. */ + + np = nn - (*pp << 1); + b1 = z__[np - 2]; + b2 = z__[np - 6]; + gam = *dn2; + if (z__[np - 8] > b2 || z__[np - 4] > b1) { + return 0; + } + a2 = z__[np - 8] / b2 * (z__[np - 4] / b1 + 1.); + +/* Approximate contribution to norm squared from I < NN-2. */ + + if (*n0 - *i0 > 2) { + b2 = z__[nn - 13] / z__[nn - 15]; + a2 += b2; + i__1 = (*i0 << 2) - 1 + *pp; + for (i4 = nn - 17; i4 >= i__1; i4 += -4) { + if (b2 == 0.) { + goto L40; + } + b1 = b2; + if (z__[i4] > z__[i4 - 2]) { + return 0; + } + b2 *= z__[i4] / z__[i4 - 2]; + a2 += b2; + if (max(b2,b1) * 100. < a2 || .563 < a2) { + goto L40; + } +/* L30: */ + } +L40: + a2 *= 1.05; + } + + if (a2 < .563) { + s = gam * (1. - sqrt(a2)) / (a2 + 1.); + } + } else { + +/* Case 6, no information to guide us. */ + + if (*ttype == -6) { + *g += (1. - *g) * .333; + } else if (*ttype == -18) { + *g = .083250000000000005; + } else { + *g = .25; + } + s = *g * *dmin__; + *ttype = -6; + } + + } else if (*n0in == *n0 + 1) { + +/* One eigenvalue just deflated. Use DMIN1, DN1 for DMIN and DN. */ + + if (*dmin1 == *dn1 && *dmin2 == *dn2) { + +/* Cases 7 and 8. */ + + *ttype = -7; + s = *dmin1 * .333; + if (z__[nn - 5] > z__[nn - 7]) { + return 0; + } + b1 = z__[nn - 5] / z__[nn - 7]; + b2 = b1; + if (b2 == 0.) { + goto L60; + } + i__1 = (*i0 << 2) - 1 + *pp; + for (i4 = (*n0 << 2) - 9 + *pp; i4 >= i__1; i4 += -4) { + a2 = b1; + if (z__[i4] > z__[i4 - 2]) { + return 0; + } + b1 *= z__[i4] / z__[i4 - 2]; + b2 += b1; + if (max(b1,a2) * 100. < b2) { + goto L60; + } +/* L50: */ + } +L60: + b2 = sqrt(b2 * 1.05); +/* Computing 2nd power */ + d__1 = b2; + a2 = *dmin1 / (d__1 * d__1 + 1.); + gap2 = *dmin2 * .5 - a2; + if (gap2 > 0. && gap2 > b2 * a2) { +/* Computing MAX */ + d__1 = s, d__2 = a2 * (1. - a2 * 1.01 * (b2 / gap2) * b2); + s = max(d__1,d__2); + } else { +/* Computing MAX */ + d__1 = s, d__2 = a2 * (1. - b2 * 1.01); + s = max(d__1,d__2); + *ttype = -8; + } + } else { + +/* Case 9. */ + + s = *dmin1 * .25; + if (*dmin1 == *dn1) { + s = *dmin1 * .5; + } + *ttype = -9; + } + + } else if (*n0in == *n0 + 2) { + +/* + Two eigenvalues deflated. Use DMIN2, DN2 for DMIN and DN. + + Cases 10 and 11. +*/ + + if (*dmin2 == *dn2 && z__[nn - 5] * 2. < z__[nn - 7]) { + *ttype = -10; + s = *dmin2 * .333; + if (z__[nn - 5] > z__[nn - 7]) { + return 0; + } + b1 = z__[nn - 5] / z__[nn - 7]; + b2 = b1; + if (b2 == 0.) { + goto L80; + } + i__1 = (*i0 << 2) - 1 + *pp; + for (i4 = (*n0 << 2) - 9 + *pp; i4 >= i__1; i4 += -4) { + if (z__[i4] > z__[i4 - 2]) { + return 0; + } + b1 *= z__[i4] / z__[i4 - 2]; + b2 += b1; + if (b1 * 100. < b2) { + goto L80; + } +/* L70: */ + } +L80: + b2 = sqrt(b2 * 1.05); +/* Computing 2nd power */ + d__1 = b2; + a2 = *dmin2 / (d__1 * d__1 + 1.); + gap2 = z__[nn - 7] + z__[nn - 9] - sqrt(z__[nn - 11]) * sqrt(z__[ + nn - 9]) - a2; + if (gap2 > 0. && gap2 > b2 * a2) { +/* Computing MAX */ + d__1 = s, d__2 = a2 * (1. - a2 * 1.01 * (b2 / gap2) * b2); + s = max(d__1,d__2); + } else { +/* Computing MAX */ + d__1 = s, d__2 = a2 * (1. - b2 * 1.01); + s = max(d__1,d__2); + } + } else { + s = *dmin2 * .25; + *ttype = -11; + } + } else if (*n0in > *n0 + 2) { + +/* Case 12, more than two eigenvalues deflated. No information. */ + + s = 0.; + *ttype = -12; + } + + *tau = s; + return 0; + +/* End of DLASQ4 */ + +} /* dlasq4_ */ + +/* Subroutine */ int dlasq5_(integer *i0, integer *n0, doublereal *z__, + integer *pp, doublereal *tau, doublereal *dmin__, doublereal *dmin1, + doublereal *dmin2, doublereal *dn, doublereal *dnm1, doublereal *dnm2, + logical *ieee) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal d__; + static integer j4, j4p2; + static doublereal emin, temp; + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + DLASQ5 computes one dqds transform in ping-pong form, one + version for IEEE machines another for non IEEE machines. + + Arguments + ========= + + I0 (input) INTEGER + First index. + + N0 (input) INTEGER + Last index. + + Z (input) DOUBLE PRECISION array, dimension ( 4*N ) + Z holds the qd array. EMIN is stored in Z(4*N0) to avoid + an extra argument. + + PP (input) INTEGER + PP=0 for ping, PP=1 for pong. + + TAU (input) DOUBLE PRECISION + This is the shift. + + DMIN (output) DOUBLE PRECISION + Minimum value of d. + + DMIN1 (output) DOUBLE PRECISION + Minimum value of d, excluding D( N0 ). + + DMIN2 (output) DOUBLE PRECISION + Minimum value of d, excluding D( N0 ) and D( N0-1 ). + + DN (output) DOUBLE PRECISION + d(N0), the last value of d. + + DNM1 (output) DOUBLE PRECISION + d(N0-1). + + DNM2 (output) DOUBLE PRECISION + d(N0-2). + + IEEE (input) LOGICAL + Flag for IEEE or non IEEE arithmetic. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + if (*n0 - *i0 - 1 <= 0) { + return 0; + } + + j4 = (*i0 << 2) + *pp - 3; + emin = z__[j4 + 4]; + d__ = z__[j4] - *tau; + *dmin__ = d__; + *dmin1 = -z__[j4]; + + if (*ieee) { + +/* Code for IEEE arithmetic. */ + + if (*pp == 0) { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 2] = d__ + z__[j4 - 1]; + temp = z__[j4 + 1] / z__[j4 - 2]; + d__ = d__ * temp - *tau; + *dmin__ = min(*dmin__,d__); + z__[j4] = z__[j4 - 1] * temp; +/* Computing MIN */ + d__1 = z__[j4]; + emin = min(d__1,emin); +/* L10: */ + } + } else { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 3] = d__ + z__[j4]; + temp = z__[j4 + 2] / z__[j4 - 3]; + d__ = d__ * temp - *tau; + *dmin__ = min(*dmin__,d__); + z__[j4 - 1] = z__[j4] * temp; +/* Computing MIN */ + d__1 = z__[j4 - 1]; + emin = min(d__1,emin); +/* L20: */ + } + } + +/* Unroll last two steps. */ + + *dnm2 = d__; + *dmin2 = *dmin__; + j4 = (*n0 - 2 << 2) - *pp; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm2 + z__[j4p2]; + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]) - *tau; + *dmin__ = min(*dmin__,*dnm1); + + *dmin1 = *dmin__; + j4 += 4; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm1 + z__[j4p2]; + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]) - *tau; + *dmin__ = min(*dmin__,*dn); + + } else { + +/* Code for non IEEE arithmetic. */ + + if (*pp == 0) { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 2] = d__ + z__[j4 - 1]; + if (d__ < 0.) { + return 0; + } else { + z__[j4] = z__[j4 + 1] * (z__[j4 - 1] / z__[j4 - 2]); + d__ = z__[j4 + 1] * (d__ / z__[j4 - 2]) - *tau; + } + *dmin__ = min(*dmin__,d__); +/* Computing MIN */ + d__1 = emin, d__2 = z__[j4]; + emin = min(d__1,d__2); +/* L30: */ + } + } else { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 3] = d__ + z__[j4]; + if (d__ < 0.) { + return 0; + } else { + z__[j4 - 1] = z__[j4 + 2] * (z__[j4] / z__[j4 - 3]); + d__ = z__[j4 + 2] * (d__ / z__[j4 - 3]) - *tau; + } + *dmin__ = min(*dmin__,d__); +/* Computing MIN */ + d__1 = emin, d__2 = z__[j4 - 1]; + emin = min(d__1,d__2); +/* L40: */ + } + } + +/* Unroll last two steps. */ + + *dnm2 = d__; + *dmin2 = *dmin__; + j4 = (*n0 - 2 << 2) - *pp; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm2 + z__[j4p2]; + if (*dnm2 < 0.) { + return 0; + } else { + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]) - *tau; + } + *dmin__ = min(*dmin__,*dnm1); + + *dmin1 = *dmin__; + j4 += 4; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm1 + z__[j4p2]; + if (*dnm1 < 0.) { + return 0; + } else { + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]) - *tau; + } + *dmin__ = min(*dmin__,*dn); + + } + + z__[j4 + 2] = *dn; + z__[(*n0 << 2) - *pp] = emin; + return 0; + +/* End of DLASQ5 */ + +} /* dlasq5_ */ + +/* Subroutine */ int dlasq6_(integer *i0, integer *n0, doublereal *z__, + integer *pp, doublereal *dmin__, doublereal *dmin1, doublereal *dmin2, + doublereal *dn, doublereal *dnm1, doublereal *dnm2) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal d__; + static integer j4, j4p2; + static doublereal emin, temp; + + static doublereal safmin; + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + DLASQ6 computes one dqd (shift equal to zero) transform in + ping-pong form, with protection against underflow and overflow. + + Arguments + ========= + + I0 (input) INTEGER + First index. + + N0 (input) INTEGER + Last index. + + Z (input) DOUBLE PRECISION array, dimension ( 4*N ) + Z holds the qd array. EMIN is stored in Z(4*N0) to avoid + an extra argument. + + PP (input) INTEGER + PP=0 for ping, PP=1 for pong. + + DMIN (output) DOUBLE PRECISION + Minimum value of d. + + DMIN1 (output) DOUBLE PRECISION + Minimum value of d, excluding D( N0 ). + + DMIN2 (output) DOUBLE PRECISION + Minimum value of d, excluding D( N0 ) and D( N0-1 ). + + DN (output) DOUBLE PRECISION + d(N0), the last value of d. + + DNM1 (output) DOUBLE PRECISION + d(N0-1). + + DNM2 (output) DOUBLE PRECISION + d(N0-2). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + if (*n0 - *i0 - 1 <= 0) { + return 0; + } + + safmin = SAFEMINIMUM; + j4 = (*i0 << 2) + *pp - 3; + emin = z__[j4 + 4]; + d__ = z__[j4]; + *dmin__ = d__; + + if (*pp == 0) { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 2] = d__ + z__[j4 - 1]; + if (z__[j4 - 2] == 0.) { + z__[j4] = 0.; + d__ = z__[j4 + 1]; + *dmin__ = d__; + emin = 0.; + } else if (safmin * z__[j4 + 1] < z__[j4 - 2] && safmin * z__[j4 + - 2] < z__[j4 + 1]) { + temp = z__[j4 + 1] / z__[j4 - 2]; + z__[j4] = z__[j4 - 1] * temp; + d__ *= temp; + } else { + z__[j4] = z__[j4 + 1] * (z__[j4 - 1] / z__[j4 - 2]); + d__ = z__[j4 + 1] * (d__ / z__[j4 - 2]); + } + *dmin__ = min(*dmin__,d__); +/* Computing MIN */ + d__1 = emin, d__2 = z__[j4]; + emin = min(d__1,d__2); +/* L10: */ + } + } else { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 3] = d__ + z__[j4]; + if (z__[j4 - 3] == 0.) { + z__[j4 - 1] = 0.; + d__ = z__[j4 + 2]; + *dmin__ = d__; + emin = 0.; + } else if (safmin * z__[j4 + 2] < z__[j4 - 3] && safmin * z__[j4 + - 3] < z__[j4 + 2]) { + temp = z__[j4 + 2] / z__[j4 - 3]; + z__[j4 - 1] = z__[j4] * temp; + d__ *= temp; + } else { + z__[j4 - 1] = z__[j4 + 2] * (z__[j4] / z__[j4 - 3]); + d__ = z__[j4 + 2] * (d__ / z__[j4 - 3]); + } + *dmin__ = min(*dmin__,d__); +/* Computing MIN */ + d__1 = emin, d__2 = z__[j4 - 1]; + emin = min(d__1,d__2); +/* L20: */ + } + } + +/* Unroll last two steps. */ + + *dnm2 = d__; + *dmin2 = *dmin__; + j4 = (*n0 - 2 << 2) - *pp; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm2 + z__[j4p2]; + if (z__[j4 - 2] == 0.) { + z__[j4] = 0.; + *dnm1 = z__[j4p2 + 2]; + *dmin__ = *dnm1; + emin = 0.; + } else if (safmin * z__[j4p2 + 2] < z__[j4 - 2] && safmin * z__[j4 - 2] < + z__[j4p2 + 2]) { + temp = z__[j4p2 + 2] / z__[j4 - 2]; + z__[j4] = z__[j4p2] * temp; + *dnm1 = *dnm2 * temp; + } else { + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]); + } + *dmin__ = min(*dmin__,*dnm1); + + *dmin1 = *dmin__; + j4 += 4; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm1 + z__[j4p2]; + if (z__[j4 - 2] == 0.) { + z__[j4] = 0.; + *dn = z__[j4p2 + 2]; + *dmin__ = *dn; + emin = 0.; + } else if (safmin * z__[j4p2 + 2] < z__[j4 - 2] && safmin * z__[j4 - 2] < + z__[j4p2 + 2]) { + temp = z__[j4p2 + 2] / z__[j4 - 2]; + z__[j4] = z__[j4p2] * temp; + *dn = *dnm1 * temp; + } else { + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]); + } + *dmin__ = min(*dmin__,*dn); + + z__[j4 + 2] = *dn; + z__[(*n0 << 2) - *pp] = emin; + return 0; + +/* End of DLASQ6 */ + +} /* dlasq6_ */ + +/* Subroutine */ int dlasr_(char *side, char *pivot, char *direct, integer *m, + integer *n, doublereal *c__, doublereal *s, doublereal *a, integer * + lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, info; + static doublereal temp; + extern logical lsame_(char *, char *); + static doublereal ctemp, stemp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASR applies a sequence of plane rotations to a real matrix A, + from either the left or the right. + + When SIDE = 'L', the transformation takes the form + + A := P*A + + and when SIDE = 'R', the transformation takes the form + + A := A*P**T + + where P is an orthogonal matrix consisting of a sequence of z plane + rotations, with z = M when SIDE = 'L' and z = N when SIDE = 'R', + and P**T is the transpose of P. + + When DIRECT = 'F' (Forward sequence), then + + P = P(z-1) * ... * P(2) * P(1) + + and when DIRECT = 'B' (Backward sequence), then + + P = P(1) * P(2) * ... * P(z-1) + + where P(k) is a plane rotation matrix defined by the 2-by-2 rotation + + R(k) = ( c(k) s(k) ) + = ( -s(k) c(k) ). + + When PIVOT = 'V' (Variable pivot), the rotation is performed + for the plane (k,k+1), i.e., P(k) has the form + + P(k) = ( 1 ) + ( ... ) + ( 1 ) + ( c(k) s(k) ) + ( -s(k) c(k) ) + ( 1 ) + ( ... ) + ( 1 ) + + where R(k) appears as a rank-2 modification to the identity matrix in + rows and columns k and k+1. + + When PIVOT = 'T' (Top pivot), the rotation is performed for the + plane (1,k+1), so P(k) has the form + + P(k) = ( c(k) s(k) ) + ( 1 ) + ( ... ) + ( 1 ) + ( -s(k) c(k) ) + ( 1 ) + ( ... ) + ( 1 ) + + where R(k) appears in rows and columns 1 and k+1. + + Similarly, when PIVOT = 'B' (Bottom pivot), the rotation is + performed for the plane (k,z), giving P(k) the form + + P(k) = ( 1 ) + ( ... ) + ( 1 ) + ( c(k) s(k) ) + ( 1 ) + ( ... ) + ( 1 ) + ( -s(k) c(k) ) + + where R(k) appears in rows and columns k and z. The rotations are + performed without ever forming P(k) explicitly. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + Specifies whether the plane rotation matrix P is applied to + A on the left or the right. + = 'L': Left, compute A := P*A + = 'R': Right, compute A:= A*P**T + + PIVOT (input) CHARACTER*1 + Specifies the plane for which P(k) is a plane rotation + matrix. + = 'V': Variable pivot, the plane (k,k+1) + = 'T': Top pivot, the plane (1,k+1) + = 'B': Bottom pivot, the plane (k,z) + + DIRECT (input) CHARACTER*1 + Specifies whether P is a forward or backward sequence of + plane rotations. + = 'F': Forward, P = P(z-1)*...*P(2)*P(1) + = 'B': Backward, P = P(1)*P(2)*...*P(z-1) + + M (input) INTEGER + The number of rows of the matrix A. If m <= 1, an immediate + return is effected. + + N (input) INTEGER + The number of columns of the matrix A. If n <= 1, an + immediate return is effected. + + C (input) DOUBLE PRECISION array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + The cosines c(k) of the plane rotations. + + S (input) DOUBLE PRECISION array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + The sines s(k) of the plane rotations. The 2-by-2 plane + rotation part of the matrix P(k), R(k), has the form + R(k) = ( c(k) s(k) ) + ( -s(k) c(k) ). + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + The M-by-N matrix A. On exit, A is overwritten by P*A if + SIDE = 'R' or by A*P**T if SIDE = 'L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + --c__; + --s; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (! (lsame_(side, "L") || lsame_(side, "R"))) { + info = 1; + } else if (! (lsame_(pivot, "V") || lsame_(pivot, + "T") || lsame_(pivot, "B"))) { + info = 2; + } else if (! (lsame_(direct, "F") || lsame_(direct, + "B"))) { + info = 3; + } else if (*m < 0) { + info = 4; + } else if (*n < 0) { + info = 5; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("DLASR ", &info); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + if (lsame_(side, "L")) { + +/* Form P * A */ + + if (lsame_(pivot, "V")) { + if (lsame_(direct, "F")) { + i__1 = *m - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[j + 1 + i__ * a_dim1]; + a[j + 1 + i__ * a_dim1] = ctemp * temp - stemp * + a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = stemp * temp + ctemp * a[j + + i__ * a_dim1]; +/* L10: */ + } + } +/* L20: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[j + 1 + i__ * a_dim1]; + a[j + 1 + i__ * a_dim1] = ctemp * temp - stemp * + a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = stemp * temp + ctemp * a[j + + i__ * a_dim1]; +/* L30: */ + } + } +/* L40: */ + } + } + } else if (lsame_(pivot, "T")) { + if (lsame_(direct, "F")) { + i__1 = *m; + for (j = 2; j <= i__1; ++j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = ctemp * temp - stemp * a[ + i__ * a_dim1 + 1]; + a[i__ * a_dim1 + 1] = stemp * temp + ctemp * a[ + i__ * a_dim1 + 1]; +/* L50: */ + } + } +/* L60: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m; j >= 2; --j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = ctemp * temp - stemp * a[ + i__ * a_dim1 + 1]; + a[i__ * a_dim1 + 1] = stemp * temp + ctemp * a[ + i__ * a_dim1 + 1]; +/* L70: */ + } + } +/* L80: */ + } + } + } else if (lsame_(pivot, "B")) { + if (lsame_(direct, "F")) { + i__1 = *m - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = stemp * a[*m + i__ * a_dim1] + + ctemp * temp; + a[*m + i__ * a_dim1] = ctemp * a[*m + i__ * + a_dim1] - stemp * temp; +/* L90: */ + } + } +/* L100: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = stemp * a[*m + i__ * a_dim1] + + ctemp * temp; + a[*m + i__ * a_dim1] = ctemp * a[*m + i__ * + a_dim1] - stemp * temp; +/* L110: */ + } + } +/* L120: */ + } + } + } + } else if (lsame_(side, "R")) { + +/* Form A * P' */ + + if (lsame_(pivot, "V")) { + if (lsame_(direct, "F")) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[i__ + (j + 1) * a_dim1]; + a[i__ + (j + 1) * a_dim1] = ctemp * temp - stemp * + a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = stemp * temp + ctemp * a[ + i__ + j * a_dim1]; +/* L130: */ + } + } +/* L140: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[i__ + (j + 1) * a_dim1]; + a[i__ + (j + 1) * a_dim1] = ctemp * temp - stemp * + a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = stemp * temp + ctemp * a[ + i__ + j * a_dim1]; +/* L150: */ + } + } +/* L160: */ + } + } + } else if (lsame_(pivot, "T")) { + if (lsame_(direct, "F")) { + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = ctemp * temp - stemp * a[ + i__ + a_dim1]; + a[i__ + a_dim1] = stemp * temp + ctemp * a[i__ + + a_dim1]; +/* L170: */ + } + } +/* L180: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n; j >= 2; --j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = ctemp * temp - stemp * a[ + i__ + a_dim1]; + a[i__ + a_dim1] = stemp * temp + ctemp * a[i__ + + a_dim1]; +/* L190: */ + } + } +/* L200: */ + } + } + } else if (lsame_(pivot, "B")) { + if (lsame_(direct, "F")) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = stemp * a[i__ + *n * a_dim1] + + ctemp * temp; + a[i__ + *n * a_dim1] = ctemp * a[i__ + *n * + a_dim1] - stemp * temp; +/* L210: */ + } + } +/* L220: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = stemp * a[i__ + *n * a_dim1] + + ctemp * temp; + a[i__ + *n * a_dim1] = ctemp * a[i__ + *n * + a_dim1] - stemp * temp; +/* L230: */ + } + } +/* L240: */ + } + } + } + } + + return 0; + +/* End of DLASR */ + +} /* dlasr_ */ + +/* Subroutine */ int dlasrt_(char *id, integer *n, doublereal *d__, integer * + info) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + static integer i__, j; + static doublereal d1, d2, d3; + static integer dir; + static doublereal tmp; + static integer endd; + extern logical lsame_(char *, char *); + static integer stack[64] /* was [2][32] */; + static doublereal dmnmx; + static integer start; + extern /* Subroutine */ int xerbla_(char *, integer *); + static integer stkpnt; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + Sort the numbers in D in increasing order (if ID = 'I') or + in decreasing order (if ID = 'D' ). + + Use Quick Sort, reverting to Insertion sort on arrays of + size <= 20. Dimension of STACK limits N to about 2**32. + + Arguments + ========= + + ID (input) CHARACTER*1 + = 'I': sort D in increasing order; + = 'D': sort D in decreasing order. + + N (input) INTEGER + The length of the array D. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the array to be sorted. + On exit, D has been sorted into increasing order + (D(1) <= ... <= D(N) ) or into decreasing order + (D(1) >= ... >= D(N) ), depending on ID. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input paramters. +*/ + + /* Parameter adjustments */ + --d__; + + /* Function Body */ + *info = 0; + dir = -1; + if (lsame_(id, "D")) { + dir = 0; + } else if (lsame_(id, "I")) { + dir = 1; + } + if (dir == -1) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLASRT", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 1) { + return 0; + } + + stkpnt = 1; + stack[0] = 1; + stack[1] = *n; +L10: + start = stack[(stkpnt << 1) - 2]; + endd = stack[(stkpnt << 1) - 1]; + --stkpnt; + if (endd - start <= 20 && endd - start > 0) { + +/* Do Insertion sort on D( START:ENDD ) */ + + if (dir == 0) { + +/* Sort into decreasing order */ + + i__1 = endd; + for (i__ = start + 1; i__ <= i__1; ++i__) { + i__2 = start + 1; + for (j = i__; j >= i__2; --j) { + if (d__[j] > d__[j - 1]) { + dmnmx = d__[j]; + d__[j] = d__[j - 1]; + d__[j - 1] = dmnmx; + } else { + goto L30; + } +/* L20: */ + } +L30: + ; + } + + } else { + +/* Sort into increasing order */ + + i__1 = endd; + for (i__ = start + 1; i__ <= i__1; ++i__) { + i__2 = start + 1; + for (j = i__; j >= i__2; --j) { + if (d__[j] < d__[j - 1]) { + dmnmx = d__[j]; + d__[j] = d__[j - 1]; + d__[j - 1] = dmnmx; + } else { + goto L50; + } +/* L40: */ + } +L50: + ; + } + + } + + } else if (endd - start > 20) { + +/* + Partition D( START:ENDD ) and stack parts, largest one first + + Choose partition entry as median of 3 +*/ + + d1 = d__[start]; + d2 = d__[endd]; + i__ = (start + endd) / 2; + d3 = d__[i__]; + if (d1 < d2) { + if (d3 < d1) { + dmnmx = d1; + } else if (d3 < d2) { + dmnmx = d3; + } else { + dmnmx = d2; + } + } else { + if (d3 < d2) { + dmnmx = d2; + } else if (d3 < d1) { + dmnmx = d3; + } else { + dmnmx = d1; + } + } + + if (dir == 0) { + +/* Sort into decreasing order */ + + i__ = start - 1; + j = endd + 1; +L60: +L70: + --j; + if (d__[j] < dmnmx) { + goto L70; + } +L80: + ++i__; + if (d__[i__] > dmnmx) { + goto L80; + } + if (i__ < j) { + tmp = d__[i__]; + d__[i__] = d__[j]; + d__[j] = tmp; + goto L60; + } + if (j - start > endd - j - 1) { + ++stkpnt; + stack[(stkpnt << 1) - 2] = start; + stack[(stkpnt << 1) - 1] = j; + ++stkpnt; + stack[(stkpnt << 1) - 2] = j + 1; + stack[(stkpnt << 1) - 1] = endd; + } else { + ++stkpnt; + stack[(stkpnt << 1) - 2] = j + 1; + stack[(stkpnt << 1) - 1] = endd; + ++stkpnt; + stack[(stkpnt << 1) - 2] = start; + stack[(stkpnt << 1) - 1] = j; + } + } else { + +/* Sort into increasing order */ + + i__ = start - 1; + j = endd + 1; +L90: +L100: + --j; + if (d__[j] > dmnmx) { + goto L100; + } +L110: + ++i__; + if (d__[i__] < dmnmx) { + goto L110; + } + if (i__ < j) { + tmp = d__[i__]; + d__[i__] = d__[j]; + d__[j] = tmp; + goto L90; + } + if (j - start > endd - j - 1) { + ++stkpnt; + stack[(stkpnt << 1) - 2] = start; + stack[(stkpnt << 1) - 1] = j; + ++stkpnt; + stack[(stkpnt << 1) - 2] = j + 1; + stack[(stkpnt << 1) - 1] = endd; + } else { + ++stkpnt; + stack[(stkpnt << 1) - 2] = j + 1; + stack[(stkpnt << 1) - 1] = endd; + ++stkpnt; + stack[(stkpnt << 1) - 2] = start; + stack[(stkpnt << 1) - 1] = j; + } + } + } + if (stkpnt > 0) { + goto L10; + } + return 0; + +/* End of DLASRT */ + +} /* dlasrt_ */ + +/* Subroutine */ int dlassq_(integer *n, doublereal *x, integer *incx, + doublereal *scale, doublereal *sumsq) +{ + /* System generated locals */ + integer i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer ix; + static doublereal absxi; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASSQ returns the values scl and smsq such that + + ( scl**2 )*smsq = x( 1 )**2 +...+ x( n )**2 + ( scale**2 )*sumsq, + + where x( i ) = X( 1 + ( i - 1 )*INCX ). The value of sumsq is + assumed to be non-negative and scl returns the value + + scl = max( scale, abs( x( i ) ) ). + + scale and sumsq must be supplied in SCALE and SUMSQ and + scl and smsq are overwritten on SCALE and SUMSQ respectively. + + The routine makes only one pass through the vector x. + + Arguments + ========= + + N (input) INTEGER + The number of elements to be used from the vector X. + + X (input) DOUBLE PRECISION array, dimension (N) + The vector for which a scaled sum of squares is computed. + x( i ) = X( 1 + ( i - 1 )*INCX ), 1 <= i <= n. + + INCX (input) INTEGER + The increment between successive values of the vector X. + INCX > 0. + + SCALE (input/output) DOUBLE PRECISION + On entry, the value scale in the equation above. + On exit, SCALE is overwritten with scl , the scaling factor + for the sum of squares. + + SUMSQ (input/output) DOUBLE PRECISION + On entry, the value sumsq in the equation above. + On exit, SUMSQ is overwritten with smsq , the basic sum of + squares from which scl has been factored out. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n > 0) { + i__1 = (*n - 1) * *incx + 1; + i__2 = *incx; + for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) { + if (x[ix] != 0.) { + absxi = (d__1 = x[ix], abs(d__1)); + if (*scale < absxi) { +/* Computing 2nd power */ + d__1 = *scale / absxi; + *sumsq = *sumsq * (d__1 * d__1) + 1; + *scale = absxi; + } else { +/* Computing 2nd power */ + d__1 = absxi / *scale; + *sumsq += d__1 * d__1; + } + } +/* L10: */ + } + } + return 0; + +/* End of DLASSQ */ + +} /* dlassq_ */ + +/* Subroutine */ int dlasv2_(doublereal *f, doublereal *g, doublereal *h__, + doublereal *ssmin, doublereal *ssmax, doublereal *snr, doublereal * + csr, doublereal *snl, doublereal *csl) +{ + /* System generated locals */ + doublereal d__1; + + /* Local variables */ + static doublereal a, d__, l, m, r__, s, t, fa, ga, ha, ft, gt, ht, mm, tt, + clt, crt, slt, srt; + static integer pmax; + static doublereal temp; + static logical swap; + static doublereal tsign; + + static logical gasmal; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASV2 computes the singular value decomposition of a 2-by-2 + triangular matrix + [ F G ] + [ 0 H ]. + On return, abs(SSMAX) is the larger singular value, abs(SSMIN) is the + smaller singular value, and (CSL,SNL) and (CSR,SNR) are the left and + right singular vectors for abs(SSMAX), giving the decomposition + + [ CSL SNL ] [ F G ] [ CSR -SNR ] = [ SSMAX 0 ] + [-SNL CSL ] [ 0 H ] [ SNR CSR ] [ 0 SSMIN ]. + + Arguments + ========= + + F (input) DOUBLE PRECISION + The (1,1) element of the 2-by-2 matrix. + + G (input) DOUBLE PRECISION + The (1,2) element of the 2-by-2 matrix. + + H (input) DOUBLE PRECISION + The (2,2) element of the 2-by-2 matrix. + + SSMIN (output) DOUBLE PRECISION + abs(SSMIN) is the smaller singular value. + + SSMAX (output) DOUBLE PRECISION + abs(SSMAX) is the larger singular value. + + SNL (output) DOUBLE PRECISION + CSL (output) DOUBLE PRECISION + The vector (CSL, SNL) is a unit left singular vector for the + singular value abs(SSMAX). + + SNR (output) DOUBLE PRECISION + CSR (output) DOUBLE PRECISION + The vector (CSR, SNR) is a unit right singular vector for the + singular value abs(SSMAX). + + Further Details + =============== + + Any input parameter may be aliased with any output parameter. + + Barring over/underflow and assuming a guard digit in subtraction, all + output quantities are correct to within a few units in the last + place (ulps). + + In IEEE arithmetic, the code works correctly if one matrix element is + infinite. + + Overflow will not occur unless the largest singular value itself + overflows or is within a few ulps of overflow. (On machines with + partial overflow, like the Cray, overflow may occur if the largest + singular value is within a factor of 2 of overflow.) + + Underflow is harmless if underflow is gradual. Otherwise, results + may correspond to a matrix modified by perturbations of size near + the underflow threshold. + + ===================================================================== +*/ + + + ft = *f; + fa = abs(ft); + ht = *h__; + ha = abs(*h__); + +/* + PMAX points to the maximum absolute element of matrix + PMAX = 1 if F largest in absolute values + PMAX = 2 if G largest in absolute values + PMAX = 3 if H largest in absolute values +*/ + + pmax = 1; + swap = ha > fa; + if (swap) { + pmax = 3; + temp = ft; + ft = ht; + ht = temp; + temp = fa; + fa = ha; + ha = temp; + +/* Now FA .ge. HA */ + + } + gt = *g; + ga = abs(gt); + if (ga == 0.) { + +/* Diagonal matrix */ + + *ssmin = ha; + *ssmax = fa; + clt = 1.; + crt = 1.; + slt = 0.; + srt = 0.; + } else { + gasmal = TRUE_; + if (ga > fa) { + pmax = 2; + if (fa / ga < EPSILON) { + +/* Case of very large GA */ + + gasmal = FALSE_; + *ssmax = ga; + if (ha > 1.) { + *ssmin = fa / (ga / ha); + } else { + *ssmin = fa / ga * ha; + } + clt = 1.; + slt = ht / gt; + srt = 1.; + crt = ft / gt; + } + } + if (gasmal) { + +/* Normal case */ + + d__ = fa - ha; + if (d__ == fa) { + +/* Copes with infinite F or H */ + + l = 1.; + } else { + l = d__ / fa; + } + +/* Note that 0 .le. L .le. 1 */ + + m = gt / ft; + +/* Note that abs(M) .le. 1/macheps */ + + t = 2. - l; + +/* Note that T .ge. 1 */ + + mm = m * m; + tt = t * t; + s = sqrt(tt + mm); + +/* Note that 1 .le. S .le. 1 + 1/macheps */ + + if (l == 0.) { + r__ = abs(m); + } else { + r__ = sqrt(l * l + mm); + } + +/* Note that 0 .le. R .le. 1 + 1/macheps */ + + a = (s + r__) * .5; + +/* Note that 1 .le. A .le. 1 + abs(M) */ + + *ssmin = ha / a; + *ssmax = fa * a; + if (mm == 0.) { + +/* Note that M is very tiny */ + + if (l == 0.) { + t = d_sign(&c_b3192, &ft) * d_sign(&c_b15, >); + } else { + t = gt / d_sign(&d__, &ft) + m / t; + } + } else { + t = (m / (s + t) + m / (r__ + l)) * (a + 1.); + } + l = sqrt(t * t + 4.); + crt = 2. / l; + srt = t / l; + clt = (crt + srt * m) / a; + slt = ht / ft * srt / a; + } + } + if (swap) { + *csl = srt; + *snl = crt; + *csr = slt; + *snr = clt; + } else { + *csl = clt; + *snl = slt; + *csr = crt; + *snr = srt; + } + +/* Correct signs of SSMAX and SSMIN */ + + if (pmax == 1) { + tsign = d_sign(&c_b15, csr) * d_sign(&c_b15, csl) * d_sign(&c_b15, f); + } + if (pmax == 2) { + tsign = d_sign(&c_b15, snr) * d_sign(&c_b15, csl) * d_sign(&c_b15, g); + } + if (pmax == 3) { + tsign = d_sign(&c_b15, snr) * d_sign(&c_b15, snl) * d_sign(&c_b15, + h__); + } + *ssmax = d_sign(ssmax, &tsign); + d__1 = tsign * d_sign(&c_b15, f) * d_sign(&c_b15, h__); + *ssmin = d_sign(ssmin, &d__1); + return 0; + +/* End of DLASV2 */ + +} /* dlasv2_ */ + +/* Subroutine */ int dlaswp_(integer *n, doublereal *a, integer *lda, integer + *k1, integer *k2, integer *ipiv, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, k, i1, i2, n32, ip, ix, ix0, inc; + static doublereal temp; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASWP performs a series of row interchanges on the matrix A. + One row interchange is initiated for each of rows K1 through K2 of A. + + Arguments + ========= + + N (input) INTEGER + The number of columns of the matrix A. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the matrix of column dimension N to which the row + interchanges will be applied. + On exit, the permuted matrix. + + LDA (input) INTEGER + The leading dimension of the array A. + + K1 (input) INTEGER + The first element of IPIV for which a row interchange will + be done. + + K2 (input) INTEGER + The last element of IPIV for which a row interchange will + be done. + + IPIV (input) INTEGER array, dimension (K2*abs(INCX)) + The vector of pivot indices. Only the elements in positions + K1 through K2 of IPIV are accessed. + IPIV(K) = L implies rows K and L are to be interchanged. + + INCX (input) INTEGER + The increment between successive values of IPIV. If IPIV + is negative, the pivots are applied in reverse order. + + Further Details + =============== + + Modified by + R. C. Whaley, Computer Science Dept., Univ. of Tenn., Knoxville, USA + + ===================================================================== + + + Interchange row I with row IPIV(I) for each of rows K1 through K2. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + if (*incx > 0) { + ix0 = *k1; + i1 = *k1; + i2 = *k2; + inc = 1; + } else if (*incx < 0) { + ix0 = (1 - *k2) * *incx + 1; + i1 = *k2; + i2 = *k1; + inc = -1; + } else { + return 0; + } + + n32 = *n / 32 << 5; + if (n32 != 0) { + i__1 = n32; + for (j = 1; j <= i__1; j += 32) { + ix = ix0; + i__2 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__3) + { + ip = ipiv[ix]; + if (ip != i__) { + i__4 = j + 31; + for (k = j; k <= i__4; ++k) { + temp = a[i__ + k * a_dim1]; + a[i__ + k * a_dim1] = a[ip + k * a_dim1]; + a[ip + k * a_dim1] = temp; +/* L10: */ + } + } + ix += *incx; +/* L20: */ + } +/* L30: */ + } + } + if (n32 != *n) { + ++n32; + ix = ix0; + i__1 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__3) { + ip = ipiv[ix]; + if (ip != i__) { + i__2 = *n; + for (k = n32; k <= i__2; ++k) { + temp = a[i__ + k * a_dim1]; + a[i__ + k * a_dim1] = a[ip + k * a_dim1]; + a[ip + k * a_dim1] = temp; +/* L40: */ + } + } + ix += *incx; +/* L50: */ + } + } + + return 0; + +/* End of DLASWP */ + +} /* dlaswp_ */ + +/* Subroutine */ int dlasy2_(logical *ltranl, logical *ltranr, integer *isgn, + integer *n1, integer *n2, doublereal *tl, integer *ldtl, doublereal * + tr, integer *ldtr, doublereal *b, integer *ldb, doublereal *scale, + doublereal *x, integer *ldx, doublereal *xnorm, integer *info) +{ + /* Initialized data */ + + static integer locu12[4] = { 3,4,1,2 }; + static integer locl21[4] = { 2,1,4,3 }; + static integer locu22[4] = { 4,3,2,1 }; + static logical xswpiv[4] = { FALSE_,FALSE_,TRUE_,TRUE_ }; + static logical bswpiv[4] = { FALSE_,TRUE_,FALSE_,TRUE_ }; + + /* System generated locals */ + integer b_dim1, b_offset, tl_dim1, tl_offset, tr_dim1, tr_offset, x_dim1, + x_offset; + doublereal d__1, d__2, d__3, d__4, d__5, d__6, d__7, d__8; + + /* Local variables */ + static integer i__, j, k; + static doublereal x2[2], l21, u11, u12; + static integer ip, jp; + static doublereal u22, t16[16] /* was [4][4] */, gam, bet, eps, sgn, + tmp[4], tau1, btmp[4], smin; + static integer ipiv; + static doublereal temp; + static integer jpiv[4]; + static doublereal xmax; + static integer ipsv, jpsv; + static logical bswap; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *), dswap_(integer *, doublereal *, integer + *, doublereal *, integer *); + static logical xswap; + + extern integer idamax_(integer *, doublereal *, integer *); + static doublereal smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLASY2 solves for the N1 by N2 matrix X, 1 <= N1,N2 <= 2, in + + op(TL)*X + ISGN*X*op(TR) = SCALE*B, + + where TL is N1 by N1, TR is N2 by N2, B is N1 by N2, and ISGN = 1 or + -1. op(T) = T or T', where T' denotes the transpose of T. + + Arguments + ========= + + LTRANL (input) LOGICAL + On entry, LTRANL specifies the op(TL): + = .FALSE., op(TL) = TL, + = .TRUE., op(TL) = TL'. + + LTRANR (input) LOGICAL + On entry, LTRANR specifies the op(TR): + = .FALSE., op(TR) = TR, + = .TRUE., op(TR) = TR'. + + ISGN (input) INTEGER + On entry, ISGN specifies the sign of the equation + as described before. ISGN may only be 1 or -1. + + N1 (input) INTEGER + On entry, N1 specifies the order of matrix TL. + N1 may only be 0, 1 or 2. + + N2 (input) INTEGER + On entry, N2 specifies the order of matrix TR. + N2 may only be 0, 1 or 2. + + TL (input) DOUBLE PRECISION array, dimension (LDTL,2) + On entry, TL contains an N1 by N1 matrix. + + LDTL (input) INTEGER + The leading dimension of the matrix TL. LDTL >= max(1,N1). + + TR (input) DOUBLE PRECISION array, dimension (LDTR,2) + On entry, TR contains an N2 by N2 matrix. + + LDTR (input) INTEGER + The leading dimension of the matrix TR. LDTR >= max(1,N2). + + B (input) DOUBLE PRECISION array, dimension (LDB,2) + On entry, the N1 by N2 matrix B contains the right-hand + side of the equation. + + LDB (input) INTEGER + The leading dimension of the matrix B. LDB >= max(1,N1). + + SCALE (output) DOUBLE PRECISION + On exit, SCALE contains the scale factor. SCALE is chosen + less than or equal to 1 to prevent the solution overflowing. + + X (output) DOUBLE PRECISION array, dimension (LDX,2) + On exit, X contains the N1 by N2 solution. + + LDX (input) INTEGER + The leading dimension of the matrix X. LDX >= max(1,N1). + + XNORM (output) DOUBLE PRECISION + On exit, XNORM is the infinity-norm of the solution. + + INFO (output) INTEGER + On exit, INFO is set to + 0: successful exit. + 1: TL and TR have too close eigenvalues, so TL or + TR is perturbed to get a nonsingular equation. + NOTE: In the interests of speed, this routine does not + check the inputs for errors. + + ===================================================================== +*/ + + /* Parameter adjustments */ + tl_dim1 = *ldtl; + tl_offset = 1 + tl_dim1; + tl -= tl_offset; + tr_dim1 = *ldtr; + tr_offset = 1 + tr_dim1; + tr -= tr_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + + /* Function Body */ + +/* Do not check the input parameters for errors */ + + *info = 0; + +/* Quick return if possible */ + + if (*n1 == 0 || *n2 == 0) { + return 0; + } + +/* Set constants to control overflow */ + + eps = PRECISION; + smlnum = SAFEMINIMUM / eps; + sgn = (doublereal) (*isgn); + + k = *n1 + *n1 + *n2 - 2; + switch (k) { + case 1: goto L10; + case 2: goto L20; + case 3: goto L30; + case 4: goto L50; + } + +/* 1 by 1: TL11*X + SGN*X*TR11 = B11 */ + +L10: + tau1 = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1]; + bet = abs(tau1); + if (bet <= smlnum) { + tau1 = smlnum; + bet = smlnum; + *info = 1; + } + + *scale = 1.; + gam = (d__1 = b[b_dim1 + 1], abs(d__1)); + if (smlnum * gam > bet) { + *scale = 1. / gam; + } + + x[x_dim1 + 1] = b[b_dim1 + 1] * *scale / tau1; + *xnorm = (d__1 = x[x_dim1 + 1], abs(d__1)); + return 0; + +/* + 1 by 2: + TL11*[X11 X12] + ISGN*[X11 X12]*op[TR11 TR12] = [B11 B12] + [TR21 TR22] +*/ + +L20: + +/* + Computing MAX + Computing MAX +*/ + d__7 = (d__1 = tl[tl_dim1 + 1], abs(d__1)), d__8 = (d__2 = tr[tr_dim1 + 1] + , abs(d__2)), d__7 = max(d__7,d__8), d__8 = (d__3 = tr[(tr_dim1 << + 1) + 1], abs(d__3)), d__7 = max(d__7,d__8), d__8 = (d__4 = tr[ + tr_dim1 + 2], abs(d__4)), d__7 = max(d__7,d__8), d__8 = (d__5 = + tr[(tr_dim1 << 1) + 2], abs(d__5)); + d__6 = eps * max(d__7,d__8); + smin = max(d__6,smlnum); + tmp[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1]; + tmp[3] = tl[tl_dim1 + 1] + sgn * tr[(tr_dim1 << 1) + 2]; + if (*ltranr) { + tmp[1] = sgn * tr[tr_dim1 + 2]; + tmp[2] = sgn * tr[(tr_dim1 << 1) + 1]; + } else { + tmp[1] = sgn * tr[(tr_dim1 << 1) + 1]; + tmp[2] = sgn * tr[tr_dim1 + 2]; + } + btmp[0] = b[b_dim1 + 1]; + btmp[1] = b[(b_dim1 << 1) + 1]; + goto L40; + +/* + 2 by 1: + op[TL11 TL12]*[X11] + ISGN* [X11]*TR11 = [B11] + [TL21 TL22] [X21] [X21] [B21] +*/ + +L30: +/* + Computing MAX + Computing MAX +*/ + d__7 = (d__1 = tr[tr_dim1 + 1], abs(d__1)), d__8 = (d__2 = tl[tl_dim1 + 1] + , abs(d__2)), d__7 = max(d__7,d__8), d__8 = (d__3 = tl[(tl_dim1 << + 1) + 1], abs(d__3)), d__7 = max(d__7,d__8), d__8 = (d__4 = tl[ + tl_dim1 + 2], abs(d__4)), d__7 = max(d__7,d__8), d__8 = (d__5 = + tl[(tl_dim1 << 1) + 2], abs(d__5)); + d__6 = eps * max(d__7,d__8); + smin = max(d__6,smlnum); + tmp[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1]; + tmp[3] = tl[(tl_dim1 << 1) + 2] + sgn * tr[tr_dim1 + 1]; + if (*ltranl) { + tmp[1] = tl[(tl_dim1 << 1) + 1]; + tmp[2] = tl[tl_dim1 + 2]; + } else { + tmp[1] = tl[tl_dim1 + 2]; + tmp[2] = tl[(tl_dim1 << 1) + 1]; + } + btmp[0] = b[b_dim1 + 1]; + btmp[1] = b[b_dim1 + 2]; +L40: + +/* + Solve 2 by 2 system using complete pivoting. + Set pivots less than SMIN to SMIN. +*/ + + ipiv = idamax_(&c__4, tmp, &c__1); + u11 = tmp[ipiv - 1]; + if (abs(u11) <= smin) { + *info = 1; + u11 = smin; + } + u12 = tmp[locu12[ipiv - 1] - 1]; + l21 = tmp[locl21[ipiv - 1] - 1] / u11; + u22 = tmp[locu22[ipiv - 1] - 1] - u12 * l21; + xswap = xswpiv[ipiv - 1]; + bswap = bswpiv[ipiv - 1]; + if (abs(u22) <= smin) { + *info = 1; + u22 = smin; + } + if (bswap) { + temp = btmp[1]; + btmp[1] = btmp[0] - l21 * temp; + btmp[0] = temp; + } else { + btmp[1] -= l21 * btmp[0]; + } + *scale = 1.; + if (smlnum * 2. * abs(btmp[1]) > abs(u22) || smlnum * 2. * abs(btmp[0]) > + abs(u11)) { +/* Computing MAX */ + d__1 = abs(btmp[0]), d__2 = abs(btmp[1]); + *scale = .5 / max(d__1,d__2); + btmp[0] *= *scale; + btmp[1] *= *scale; + } + x2[1] = btmp[1] / u22; + x2[0] = btmp[0] / u11 - u12 / u11 * x2[1]; + if (xswap) { + temp = x2[1]; + x2[1] = x2[0]; + x2[0] = temp; + } + x[x_dim1 + 1] = x2[0]; + if (*n1 == 1) { + x[(x_dim1 << 1) + 1] = x2[1]; + *xnorm = (d__1 = x[x_dim1 + 1], abs(d__1)) + (d__2 = x[(x_dim1 << 1) + + 1], abs(d__2)); + } else { + x[x_dim1 + 2] = x2[1]; +/* Computing MAX */ + d__3 = (d__1 = x[x_dim1 + 1], abs(d__1)), d__4 = (d__2 = x[x_dim1 + 2] + , abs(d__2)); + *xnorm = max(d__3,d__4); + } + return 0; + +/* + 2 by 2: + op[TL11 TL12]*[X11 X12] +ISGN* [X11 X12]*op[TR11 TR12] = [B11 B12] + [TL21 TL22] [X21 X22] [X21 X22] [TR21 TR22] [B21 B22] + + Solve equivalent 4 by 4 system using complete pivoting. + Set pivots less than SMIN to SMIN. +*/ + +L50: +/* Computing MAX */ + d__5 = (d__1 = tr[tr_dim1 + 1], abs(d__1)), d__6 = (d__2 = tr[(tr_dim1 << + 1) + 1], abs(d__2)), d__5 = max(d__5,d__6), d__6 = (d__3 = tr[ + tr_dim1 + 2], abs(d__3)), d__5 = max(d__5,d__6), d__6 = (d__4 = + tr[(tr_dim1 << 1) + 2], abs(d__4)); + smin = max(d__5,d__6); +/* Computing MAX */ + d__5 = smin, d__6 = (d__1 = tl[tl_dim1 + 1], abs(d__1)), d__5 = max(d__5, + d__6), d__6 = (d__2 = tl[(tl_dim1 << 1) + 1], abs(d__2)), d__5 = + max(d__5,d__6), d__6 = (d__3 = tl[tl_dim1 + 2], abs(d__3)), d__5 = + max(d__5,d__6), d__6 = (d__4 = tl[(tl_dim1 << 1) + 2], abs(d__4)) + ; + smin = max(d__5,d__6); +/* Computing MAX */ + d__1 = eps * smin; + smin = max(d__1,smlnum); + btmp[0] = 0.; + dcopy_(&c__16, btmp, &c__0, t16, &c__1); + t16[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1]; + t16[5] = tl[(tl_dim1 << 1) + 2] + sgn * tr[tr_dim1 + 1]; + t16[10] = tl[tl_dim1 + 1] + sgn * tr[(tr_dim1 << 1) + 2]; + t16[15] = tl[(tl_dim1 << 1) + 2] + sgn * tr[(tr_dim1 << 1) + 2]; + if (*ltranl) { + t16[4] = tl[tl_dim1 + 2]; + t16[1] = tl[(tl_dim1 << 1) + 1]; + t16[14] = tl[tl_dim1 + 2]; + t16[11] = tl[(tl_dim1 << 1) + 1]; + } else { + t16[4] = tl[(tl_dim1 << 1) + 1]; + t16[1] = tl[tl_dim1 + 2]; + t16[14] = tl[(tl_dim1 << 1) + 1]; + t16[11] = tl[tl_dim1 + 2]; + } + if (*ltranr) { + t16[8] = sgn * tr[(tr_dim1 << 1) + 1]; + t16[13] = sgn * tr[(tr_dim1 << 1) + 1]; + t16[2] = sgn * tr[tr_dim1 + 2]; + t16[7] = sgn * tr[tr_dim1 + 2]; + } else { + t16[8] = sgn * tr[tr_dim1 + 2]; + t16[13] = sgn * tr[tr_dim1 + 2]; + t16[2] = sgn * tr[(tr_dim1 << 1) + 1]; + t16[7] = sgn * tr[(tr_dim1 << 1) + 1]; + } + btmp[0] = b[b_dim1 + 1]; + btmp[1] = b[b_dim1 + 2]; + btmp[2] = b[(b_dim1 << 1) + 1]; + btmp[3] = b[(b_dim1 << 1) + 2]; + +/* Perform elimination */ + + for (i__ = 1; i__ <= 3; ++i__) { + xmax = 0.; + for (ip = i__; ip <= 4; ++ip) { + for (jp = i__; jp <= 4; ++jp) { + if ((d__1 = t16[ip + (jp << 2) - 5], abs(d__1)) >= xmax) { + xmax = (d__1 = t16[ip + (jp << 2) - 5], abs(d__1)); + ipsv = ip; + jpsv = jp; + } +/* L60: */ + } +/* L70: */ + } + if (ipsv != i__) { + dswap_(&c__4, &t16[ipsv - 1], &c__4, &t16[i__ - 1], &c__4); + temp = btmp[i__ - 1]; + btmp[i__ - 1] = btmp[ipsv - 1]; + btmp[ipsv - 1] = temp; + } + if (jpsv != i__) { + dswap_(&c__4, &t16[(jpsv << 2) - 4], &c__1, &t16[(i__ << 2) - 4], + &c__1); + } + jpiv[i__ - 1] = jpsv; + if ((d__1 = t16[i__ + (i__ << 2) - 5], abs(d__1)) < smin) { + *info = 1; + t16[i__ + (i__ << 2) - 5] = smin; + } + for (j = i__ + 1; j <= 4; ++j) { + t16[j + (i__ << 2) - 5] /= t16[i__ + (i__ << 2) - 5]; + btmp[j - 1] -= t16[j + (i__ << 2) - 5] * btmp[i__ - 1]; + for (k = i__ + 1; k <= 4; ++k) { + t16[j + (k << 2) - 5] -= t16[j + (i__ << 2) - 5] * t16[i__ + ( + k << 2) - 5]; +/* L80: */ + } +/* L90: */ + } +/* L100: */ + } + if (abs(t16[15]) < smin) { + t16[15] = smin; + } + *scale = 1.; + if (smlnum * 8. * abs(btmp[0]) > abs(t16[0]) || smlnum * 8. * abs(btmp[1]) + > abs(t16[5]) || smlnum * 8. * abs(btmp[2]) > abs(t16[10]) || + smlnum * 8. * abs(btmp[3]) > abs(t16[15])) { +/* Computing MAX */ + d__1 = abs(btmp[0]), d__2 = abs(btmp[1]), d__1 = max(d__1,d__2), d__2 + = abs(btmp[2]), d__1 = max(d__1,d__2), d__2 = abs(btmp[3]); + *scale = .125 / max(d__1,d__2); + btmp[0] *= *scale; + btmp[1] *= *scale; + btmp[2] *= *scale; + btmp[3] *= *scale; + } + for (i__ = 1; i__ <= 4; ++i__) { + k = 5 - i__; + temp = 1. / t16[k + (k << 2) - 5]; + tmp[k - 1] = btmp[k - 1] * temp; + for (j = k + 1; j <= 4; ++j) { + tmp[k - 1] -= temp * t16[k + (j << 2) - 5] * tmp[j - 1]; +/* L110: */ + } +/* L120: */ + } + for (i__ = 1; i__ <= 3; ++i__) { + if (jpiv[4 - i__ - 1] != 4 - i__) { + temp = tmp[4 - i__ - 1]; + tmp[4 - i__ - 1] = tmp[jpiv[4 - i__ - 1] - 1]; + tmp[jpiv[4 - i__ - 1] - 1] = temp; + } +/* L130: */ + } + x[x_dim1 + 1] = tmp[0]; + x[x_dim1 + 2] = tmp[1]; + x[(x_dim1 << 1) + 1] = tmp[2]; + x[(x_dim1 << 1) + 2] = tmp[3]; +/* Computing MAX */ + d__1 = abs(tmp[0]) + abs(tmp[2]), d__2 = abs(tmp[1]) + abs(tmp[3]); + *xnorm = max(d__1,d__2); + return 0; + +/* End of DLASY2 */ + +} /* dlasy2_ */ + +/* Subroutine */ int dlatrd_(char *uplo, integer *n, integer *nb, doublereal * + a, integer *lda, doublereal *e, doublereal *tau, doublereal *w, + integer *ldw) +{ + /* System generated locals */ + integer a_dim1, a_offset, w_dim1, w_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, iw; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + static doublereal alpha; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *), daxpy_(integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *), + dsymv_(char *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *), dlarfg_(integer *, doublereal *, doublereal *, integer *, + doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLATRD reduces NB rows and columns of a real symmetric matrix A to + symmetric tridiagonal form by an orthogonal similarity + transformation Q' * A * Q, and returns the matrices V and W which are + needed to apply the transformation to the unreduced part of A. + + If UPLO = 'U', DLATRD reduces the last NB rows and columns of a + matrix, of which the upper triangle is supplied; + if UPLO = 'L', DLATRD reduces the first NB rows and columns of a + matrix, of which the lower triangle is supplied. + + This is an auxiliary routine called by DSYTRD. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is stored: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. + + NB (input) INTEGER + The number of rows and columns to be reduced. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + n-by-n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n-by-n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit: + if UPLO = 'U', the last NB columns have been reduced to + tridiagonal form, with the diagonal elements overwriting + the diagonal elements of A; the elements above the diagonal + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors; + if UPLO = 'L', the first NB columns have been reduced to + tridiagonal form, with the diagonal elements overwriting + the diagonal elements of A; the elements below the diagonal + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= (1,N). + + E (output) DOUBLE PRECISION array, dimension (N-1) + If UPLO = 'U', E(n-nb:n-1) contains the superdiagonal + elements of the last NB columns of the reduced matrix; + if UPLO = 'L', E(1:nb) contains the subdiagonal elements of + the first NB columns of the reduced matrix. + + TAU (output) DOUBLE PRECISION array, dimension (N-1) + The scalar factors of the elementary reflectors, stored in + TAU(n-nb:n-1) if UPLO = 'U', and in TAU(1:nb) if UPLO = 'L'. + See Further Details. + + W (output) DOUBLE PRECISION array, dimension (LDW,NB) + The n-by-nb matrix W required to update the unreduced part + of A. + + LDW (input) INTEGER + The leading dimension of the array W. LDW >= max(1,N). + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n) H(n-1) . . . H(n-nb+1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i:n) = 0 and v(i-1) = 1; v(1:i-1) is stored on exit in A(1:i-1,i), + and tau in TAU(i-1). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(nb). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0 and v(i+1) = 1; v(i+1:n) is stored on exit in A(i+1:n,i), + and tau in TAU(i). + + The elements of the vectors v together form the n-by-nb matrix V + which is needed, with W, to apply the transformation to the unreduced + part of the matrix, using a symmetric rank-2k update of the form: + A := A - V*W' - W*V'. + + The contents of A on exit are illustrated by the following examples + with n = 5 and nb = 2: + + if UPLO = 'U': if UPLO = 'L': + + ( a a a v4 v5 ) ( d ) + ( a a v4 v5 ) ( 1 d ) + ( a 1 v5 ) ( v1 1 a ) + ( d 1 ) ( v1 v2 a a ) + ( d ) ( v1 v2 a a a ) + + where d denotes a diagonal element of the reduced matrix, a denotes + an element of the original matrix that is unchanged, and vi denotes + an element of the vector defining H(i). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --e; + --tau; + w_dim1 = *ldw; + w_offset = 1 + w_dim1; + w -= w_offset; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + + if (lsame_(uplo, "U")) { + +/* Reduce last NB columns of upper triangle */ + + i__1 = *n - *nb + 1; + for (i__ = *n; i__ >= i__1; --i__) { + iw = i__ - *n + *nb; + if (i__ < *n) { + +/* Update A(1:i,i) */ + + i__2 = *n - i__; + dgemv_("No transpose", &i__, &i__2, &c_b151, &a[(i__ + 1) * + a_dim1 + 1], lda, &w[i__ + (iw + 1) * w_dim1], ldw, & + c_b15, &a[i__ * a_dim1 + 1], &c__1); + i__2 = *n - i__; + dgemv_("No transpose", &i__, &i__2, &c_b151, &w[(iw + 1) * + w_dim1 + 1], ldw, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b15, &a[i__ * a_dim1 + 1], &c__1); + } + if (i__ > 1) { + +/* + Generate elementary reflector H(i) to annihilate + A(1:i-2,i) +*/ + + i__2 = i__ - 1; + dlarfg_(&i__2, &a[i__ - 1 + i__ * a_dim1], &a[i__ * a_dim1 + + 1], &c__1, &tau[i__ - 1]); + e[i__ - 1] = a[i__ - 1 + i__ * a_dim1]; + a[i__ - 1 + i__ * a_dim1] = 1.; + +/* Compute W(1:i-1,i) */ + + i__2 = i__ - 1; + dsymv_("Upper", &i__2, &c_b15, &a[a_offset], lda, &a[i__ * + a_dim1 + 1], &c__1, &c_b29, &w[iw * w_dim1 + 1], & + c__1); + if (i__ < *n) { + i__2 = i__ - 1; + i__3 = *n - i__; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &w[(iw + 1) * + w_dim1 + 1], ldw, &a[i__ * a_dim1 + 1], &c__1, & + c_b29, &w[i__ + 1 + iw * w_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &a[(i__ + 1) + * a_dim1 + 1], lda, &w[i__ + 1 + iw * w_dim1], & + c__1, &c_b15, &w[iw * w_dim1 + 1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ * a_dim1 + 1], &c__1, & + c_b29, &w[i__ + 1 + iw * w_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &w[(iw + 1) + * w_dim1 + 1], ldw, &w[i__ + 1 + iw * w_dim1], & + c__1, &c_b15, &w[iw * w_dim1 + 1], &c__1); + } + i__2 = i__ - 1; + dscal_(&i__2, &tau[i__ - 1], &w[iw * w_dim1 + 1], &c__1); + i__2 = i__ - 1; + alpha = tau[i__ - 1] * -.5 * ddot_(&i__2, &w[iw * w_dim1 + 1], + &c__1, &a[i__ * a_dim1 + 1], &c__1); + i__2 = i__ - 1; + daxpy_(&i__2, &alpha, &a[i__ * a_dim1 + 1], &c__1, &w[iw * + w_dim1 + 1], &c__1); + } + +/* L10: */ + } + } else { + +/* Reduce first NB columns of lower triangle */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i:n,i) */ + + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + a_dim1], + lda, &w[i__ + w_dim1], ldw, &c_b15, &a[i__ + i__ * a_dim1] + , &c__1); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &w[i__ + w_dim1], + ldw, &a[i__ + a_dim1], lda, &c_b15, &a[i__ + i__ * a_dim1] + , &c__1); + if (i__ < *n) { + +/* + Generate elementary reflector H(i) to annihilate + A(i+2:n,i) +*/ + + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + dlarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + + i__ * a_dim1], &c__1, &tau[i__]); + e[i__] = a[i__ + 1 + i__ * a_dim1]; + a[i__ + 1 + i__ * a_dim1] = 1.; + +/* Compute W(i+1:n,i) */ + + i__2 = *n - i__; + dsymv_("Lower", &i__2, &c_b15, &a[i__ + 1 + (i__ + 1) * + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b29, &w[i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &w[i__ + 1 + w_dim1] + , ldw, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &w[ + i__ * w_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + 1 + + a_dim1], lda, &w[i__ * w_dim1 + 1], &c__1, &c_b15, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + a_dim1] + , lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &w[ + i__ * w_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &w[i__ + 1 + + w_dim1], ldw, &w[i__ * w_dim1 + 1], &c__1, &c_b15, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + dscal_(&i__2, &tau[i__], &w[i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + alpha = tau[i__] * -.5 * ddot_(&i__2, &w[i__ + 1 + i__ * + w_dim1], &c__1, &a[i__ + 1 + i__ * a_dim1], &c__1); + i__2 = *n - i__; + daxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + } + +/* L20: */ + } + } + + return 0; + +/* End of DLATRD */ + +} /* dlatrd_ */ + +/* Subroutine */ int dlauu2_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__; + static doublereal aii; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAUU2 computes the product U * U' or L' * L, where the triangular + factor U or L is stored in the upper or lower triangular part of + the array A. + + If UPLO = 'U' or 'u' then the upper triangle of the result is stored, + overwriting the factor U in A. + If UPLO = 'L' or 'l' then the lower triangle of the result is stored, + overwriting the factor L in A. + + This is the unblocked form of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the triangular factor stored in the array A + is upper or lower triangular: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the triangular factor U or L. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the triangular factor U or L. + On exit, if UPLO = 'U', the upper triangle of A is + overwritten with the upper triangle of the product U * U'; + if UPLO = 'L', the lower triangle of A is overwritten with + the lower triangle of the product L' * L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAUU2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the product U * U'. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + aii = a[i__ + i__ * a_dim1]; + if (i__ < *n) { + i__2 = *n - i__ + 1; + a[i__ + i__ * a_dim1] = ddot_(&i__2, &a[i__ + i__ * a_dim1], + lda, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ - 1; + i__3 = *n - i__; + dgemv_("No transpose", &i__2, &i__3, &c_b15, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ + (i__ + 1) * a_dim1], lda, & + aii, &a[i__ * a_dim1 + 1], &c__1); + } else { + dscal_(&i__, &aii, &a[i__ * a_dim1 + 1], &c__1); + } +/* L10: */ + } + + } else { + +/* Compute the product L' * L. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + aii = a[i__ + i__ * a_dim1]; + if (i__ < *n) { + i__2 = *n - i__ + 1; + a[i__ + i__ * a_dim1] = ddot_(&i__2, &a[i__ + i__ * a_dim1], & + c__1, &a[i__ + i__ * a_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + dgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + a_dim1] + , lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &aii, &a[ + i__ + a_dim1], lda); + } else { + dscal_(&i__, &aii, &a[i__ + a_dim1], lda); + } +/* L20: */ + } + } + + return 0; + +/* End of DLAUU2 */ + +} /* dlauu2_ */ + +/* Subroutine */ int dlauum_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, ib, nb; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dtrmm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *); + static logical upper; + extern /* Subroutine */ int dsyrk_(char *, char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, doublereal *, + integer *), dlauu2_(char *, integer *, + doublereal *, integer *, integer *), xerbla_(char *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DLAUUM computes the product U * U' or L' * L, where the triangular + factor U or L is stored in the upper or lower triangular part of + the array A. + + If UPLO = 'U' or 'u' then the upper triangle of the result is stored, + overwriting the factor U in A. + If UPLO = 'L' or 'l' then the lower triangle of the result is stored, + overwriting the factor L in A. + + This is the blocked form of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the triangular factor stored in the array A + is upper or lower triangular: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the triangular factor U or L. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the triangular factor U or L. + On exit, if UPLO = 'U', the upper triangle of A is + overwritten with the upper triangle of the product U * U'; + if UPLO = 'L', the lower triangle of A is overwritten with + the lower triangle of the product L' * L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DLAUUM", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "DLAUUM", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code */ + + dlauu2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code */ + + if (upper) { + +/* Compute the product U * U'. */ + + i__1 = *n; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = nb, i__4 = *n - i__ + 1; + ib = min(i__3,i__4); + i__3 = i__ - 1; + dtrmm_("Right", "Upper", "Transpose", "Non-unit", &i__3, &ib, + &c_b15, &a[i__ + i__ * a_dim1], lda, &a[i__ * a_dim1 + + 1], lda) + ; + dlauu2_("Upper", &ib, &a[i__ + i__ * a_dim1], lda, info); + if (i__ + ib <= *n) { + i__3 = i__ - 1; + i__4 = *n - i__ - ib + 1; + dgemm_("No transpose", "Transpose", &i__3, &ib, &i__4, & + c_b15, &a[(i__ + ib) * a_dim1 + 1], lda, &a[i__ + + (i__ + ib) * a_dim1], lda, &c_b15, &a[i__ * + a_dim1 + 1], lda); + i__3 = *n - i__ - ib + 1; + dsyrk_("Upper", "No transpose", &ib, &i__3, &c_b15, &a[ + i__ + (i__ + ib) * a_dim1], lda, &c_b15, &a[i__ + + i__ * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the product L' * L. */ + + i__2 = *n; + i__1 = nb; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { +/* Computing MIN */ + i__3 = nb, i__4 = *n - i__ + 1; + ib = min(i__3,i__4); + i__3 = i__ - 1; + dtrmm_("Left", "Lower", "Transpose", "Non-unit", &ib, &i__3, & + c_b15, &a[i__ + i__ * a_dim1], lda, &a[i__ + a_dim1], + lda); + dlauu2_("Lower", &ib, &a[i__ + i__ * a_dim1], lda, info); + if (i__ + ib <= *n) { + i__3 = i__ - 1; + i__4 = *n - i__ - ib + 1; + dgemm_("Transpose", "No transpose", &ib, &i__3, &i__4, & + c_b15, &a[i__ + ib + i__ * a_dim1], lda, &a[i__ + + ib + a_dim1], lda, &c_b15, &a[i__ + a_dim1], lda); + i__3 = *n - i__ - ib + 1; + dsyrk_("Lower", "Transpose", &ib, &i__3, &c_b15, &a[i__ + + ib + i__ * a_dim1], lda, &c_b15, &a[i__ + i__ * + a_dim1], lda); + } +/* L20: */ + } + } + } + + return 0; + +/* End of DLAUUM */ + +} /* dlauum_ */ + +/* Subroutine */ int dorg2r_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *), dlarf_(char *, integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *, doublereal *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORG2R generates an m by n real matrix Q with orthonormal columns, + which is defined as the first n columns of a product of k elementary + reflectors of order m + + Q = H(1) H(2) . . . H(k) + + as returned by DGEQRF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. M >= N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. N >= K >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the i-th column must contain the vector which + defines the elementary reflector H(i), for i = 1,2,...,k, as + returned by DGEQRF in the first k columns of its array + argument A. + On exit, the m-by-n matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGEQRF. + + WORK (workspace) DOUBLE PRECISION array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0 || *n > *m) { + *info = -2; + } else if (*k < 0 || *k > *n) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORG2R", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + return 0; + } + +/* Initialise columns k+1:n to columns of the unit matrix */ + + i__1 = *n; + for (j = *k + 1; j <= i__1; ++j) { + i__2 = *m; + for (l = 1; l <= i__2; ++l) { + a[l + j * a_dim1] = 0.; +/* L10: */ + } + a[j + j * a_dim1] = 1.; +/* L20: */ + } + + for (i__ = *k; i__ >= 1; --i__) { + +/* Apply H(i) to A(i:m,i:n) from the left */ + + if (i__ < *n) { + a[i__ + i__ * a_dim1] = 1.; + i__1 = *m - i__ + 1; + i__2 = *n - i__; + dlarf_("Left", &i__1, &i__2, &a[i__ + i__ * a_dim1], &c__1, &tau[ + i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + } + if (i__ < *m) { + i__1 = *m - i__; + d__1 = -tau[i__]; + dscal_(&i__1, &d__1, &a[i__ + 1 + i__ * a_dim1], &c__1); + } + a[i__ + i__ * a_dim1] = 1. - tau[i__]; + +/* Set A(1:i-1,i) to zero */ + + i__1 = i__ - 1; + for (l = 1; l <= i__1; ++l) { + a[l + i__ * a_dim1] = 0.; +/* L30: */ + } +/* L40: */ + } + return 0; + +/* End of DORG2R */ + +} /* dorg2r_ */ + +/* Subroutine */ int dorgbr_(char *vect, integer *m, integer *n, integer *k, + doublereal *a, integer *lda, doublereal *tau, doublereal *work, + integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, nb, mn; + extern logical lsame_(char *, char *); + static integer iinfo; + static logical wantq; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int dorglq_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + integer *), dorgqr_(integer *, integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORGBR generates one of the real orthogonal matrices Q or P**T + determined by DGEBRD when reducing a real matrix A to bidiagonal + form: A = Q * B * P**T. Q and P**T are defined as products of + elementary reflectors H(i) or G(i) respectively. + + If VECT = 'Q', A is assumed to have been an M-by-K matrix, and Q + is of order M: + if m >= k, Q = H(1) H(2) . . . H(k) and DORGBR returns the first n + columns of Q, where m >= n >= k; + if m < k, Q = H(1) H(2) . . . H(m-1) and DORGBR returns Q as an + M-by-M matrix. + + If VECT = 'P', A is assumed to have been a K-by-N matrix, and P**T + is of order N: + if k < n, P**T = G(k) . . . G(2) G(1) and DORGBR returns the first m + rows of P**T, where n >= m >= k; + if k >= n, P**T = G(n-1) . . . G(2) G(1) and DORGBR returns P**T as + an N-by-N matrix. + + Arguments + ========= + + VECT (input) CHARACTER*1 + Specifies whether the matrix Q or the matrix P**T is + required, as defined in the transformation applied by DGEBRD: + = 'Q': generate Q; + = 'P': generate P**T. + + M (input) INTEGER + The number of rows of the matrix Q or P**T to be returned. + M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q or P**T to be returned. + N >= 0. + If VECT = 'Q', M >= N >= min(M,K); + if VECT = 'P', N >= M >= min(N,K). + + K (input) INTEGER + If VECT = 'Q', the number of columns in the original M-by-K + matrix reduced by DGEBRD. + If VECT = 'P', the number of rows in the original K-by-N + matrix reduced by DGEBRD. + K >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the vectors which define the elementary reflectors, + as returned by DGEBRD. + On exit, the M-by-N matrix Q or P**T. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (input) DOUBLE PRECISION array, dimension + (min(M,K)) if VECT = 'Q' + (min(N,K)) if VECT = 'P' + TAU(i) must contain the scalar factor of the elementary + reflector H(i) or G(i), which determines Q or P**T, as + returned by DGEBRD in its array argument TAUQ or TAUP. + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,min(M,N)). + For optimum performance LWORK >= min(M,N)*NB, where NB + is the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + wantq = lsame_(vect, "Q"); + mn = min(*m,*n); + lquery = *lwork == -1; + if (! wantq && ! lsame_(vect, "P")) { + *info = -1; + } else if (*m < 0) { + *info = -2; + } else if (*n < 0 || wantq && (*n > *m || *n < min(*m,*k)) || ! wantq && ( + *m > *n || *m < min(*n,*k))) { + *info = -3; + } else if (*k < 0) { + *info = -4; + } else if (*lda < max(1,*m)) { + *info = -6; + } else if (*lwork < max(1,mn) && ! lquery) { + *info = -9; + } + + if (*info == 0) { + if (wantq) { + nb = ilaenv_(&c__1, "DORGQR", " ", m, n, k, &c_n1, (ftnlen)6, ( + ftnlen)1); + } else { + nb = ilaenv_(&c__1, "DORGLQ", " ", m, n, k, &c_n1, (ftnlen)6, ( + ftnlen)1); + } + lwkopt = max(1,mn) * nb; + work[1] = (doublereal) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORGBR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + work[1] = 1.; + return 0; + } + + if (wantq) { + +/* + Form Q, determined by a call to DGEBRD to reduce an m-by-k + matrix +*/ + + if (*m >= *k) { + +/* If m >= k, assume m >= n >= k */ + + dorgqr_(m, n, k, &a[a_offset], lda, &tau[1], &work[1], lwork, & + iinfo); + + } else { + +/* + If m < k, assume m = n + + Shift the vectors which define the elementary reflectors one + column to the right, and set the first row and column of Q + to those of the unit matrix +*/ + + for (j = *m; j >= 2; --j) { + a[j * a_dim1 + 1] = 0.; + i__1 = *m; + for (i__ = j + 1; i__ <= i__1; ++i__) { + a[i__ + j * a_dim1] = a[i__ + (j - 1) * a_dim1]; +/* L10: */ + } +/* L20: */ + } + a[a_dim1 + 1] = 1.; + i__1 = *m; + for (i__ = 2; i__ <= i__1; ++i__) { + a[i__ + a_dim1] = 0.; +/* L30: */ + } + if (*m > 1) { + +/* Form Q(2:m,2:m) */ + + i__1 = *m - 1; + i__2 = *m - 1; + i__3 = *m - 1; + dorgqr_(&i__1, &i__2, &i__3, &a[(a_dim1 << 1) + 2], lda, &tau[ + 1], &work[1], lwork, &iinfo); + } + } + } else { + +/* + Form P', determined by a call to DGEBRD to reduce a k-by-n + matrix +*/ + + if (*k < *n) { + +/* If k < n, assume k <= m <= n */ + + dorglq_(m, n, k, &a[a_offset], lda, &tau[1], &work[1], lwork, & + iinfo); + + } else { + +/* + If k >= n, assume m = n + + Shift the vectors which define the elementary reflectors one + row downward, and set the first row and column of P' to + those of the unit matrix +*/ + + a[a_dim1 + 1] = 1.; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + a[i__ + a_dim1] = 0.; +/* L40: */ + } + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + for (i__ = j - 1; i__ >= 2; --i__) { + a[i__ + j * a_dim1] = a[i__ - 1 + j * a_dim1]; +/* L50: */ + } + a[j * a_dim1 + 1] = 0.; +/* L60: */ + } + if (*n > 1) { + +/* Form P'(2:n,2:n) */ + + i__1 = *n - 1; + i__2 = *n - 1; + i__3 = *n - 1; + dorglq_(&i__1, &i__2, &i__3, &a[(a_dim1 << 1) + 2], lda, &tau[ + 1], &work[1], lwork, &iinfo); + } + } + } + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DORGBR */ + +} /* dorgbr_ */ + +/* Subroutine */ int dorghr_(integer *n, integer *ilo, integer *ihi, + doublereal *a, integer *lda, doublereal *tau, doublereal *work, + integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, nb, nh, iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int dorgqr_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORGHR generates a real orthogonal matrix Q which is defined as the + product of IHI-ILO elementary reflectors of order N, as returned by + DGEHRD: + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Arguments + ========= + + N (input) INTEGER + The order of the matrix Q. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + ILO and IHI must have the same values as in the previous call + of DGEHRD. Q is equal to the unit matrix except in the + submatrix Q(ilo+1:ihi,ilo+1:ihi). + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the vectors which define the elementary reflectors, + as returned by DGEHRD. + On exit, the N-by-N orthogonal matrix Q. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (input) DOUBLE PRECISION array, dimension (N-1) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGEHRD. + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= IHI-ILO. + For optimum performance LWORK >= (IHI-ILO)*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nh = *ihi - *ilo; + lquery = *lwork == -1; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*lwork < max(1,nh) && ! lquery) { + *info = -8; + } + + if (*info == 0) { + nb = ilaenv_(&c__1, "DORGQR", " ", &nh, &nh, &nh, &c_n1, (ftnlen)6, ( + ftnlen)1); + lwkopt = max(1,nh) * nb; + work[1] = (doublereal) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORGHR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + work[1] = 1.; + return 0; + } + +/* + Shift the vectors which define the elementary reflectors one + column to the right, and set the first ilo and the last n-ihi + rows and columns to those of the unit matrix +*/ + + i__1 = *ilo + 1; + for (j = *ihi; j >= i__1; --j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.; +/* L10: */ + } + i__2 = *ihi; + for (i__ = j + 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + (j - 1) * a_dim1]; +/* L20: */ + } + i__2 = *n; + for (i__ = *ihi + 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.; +/* L30: */ + } +/* L40: */ + } + i__1 = *ilo; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.; +/* L50: */ + } + a[j + j * a_dim1] = 1.; +/* L60: */ + } + i__1 = *n; + for (j = *ihi + 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.; +/* L70: */ + } + a[j + j * a_dim1] = 1.; +/* L80: */ + } + + if (nh > 0) { + +/* Generate Q(ilo+1:ihi,ilo+1:ihi) */ + + dorgqr_(&nh, &nh, &nh, &a[*ilo + 1 + (*ilo + 1) * a_dim1], lda, &tau[* + ilo], &work[1], lwork, &iinfo); + } + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DORGHR */ + +} /* dorghr_ */ + +/* Subroutine */ int dorgl2_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *), dlarf_(char *, integer *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *, doublereal *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORGL2 generates an m by n real matrix Q with orthonormal rows, + which is defined as the first m rows of a product of k elementary + reflectors of order n + + Q = H(k) . . . H(2) H(1) + + as returned by DGELQF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. N >= M. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. M >= K >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the i-th row must contain the vector which defines + the elementary reflector H(i), for i = 1,2,...,k, as returned + by DGELQF in the first k rows of its array argument A. + On exit, the m-by-n matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGELQF. + + WORK (workspace) DOUBLE PRECISION array, dimension (M) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < *m) { + *info = -2; + } else if (*k < 0 || *k > *m) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORGL2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m <= 0) { + return 0; + } + + if (*k < *m) { + +/* Initialise rows k+1:m to rows of the unit matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (l = *k + 1; l <= i__2; ++l) { + a[l + j * a_dim1] = 0.; +/* L10: */ + } + if (j > *k && j <= *m) { + a[j + j * a_dim1] = 1.; + } +/* L20: */ + } + } + + for (i__ = *k; i__ >= 1; --i__) { + +/* Apply H(i) to A(i:m,i:n) from the right */ + + if (i__ < *n) { + if (i__ < *m) { + a[i__ + i__ * a_dim1] = 1.; + i__1 = *m - i__; + i__2 = *n - i__ + 1; + dlarf_("Right", &i__1, &i__2, &a[i__ + i__ * a_dim1], lda, & + tau[i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + i__1 = *n - i__; + d__1 = -tau[i__]; + dscal_(&i__1, &d__1, &a[i__ + (i__ + 1) * a_dim1], lda); + } + a[i__ + i__ * a_dim1] = 1. - tau[i__]; + +/* Set A(i,1:i-1) to zero */ + + i__1 = i__ - 1; + for (l = 1; l <= i__1; ++l) { + a[i__ + l * a_dim1] = 0.; +/* L30: */ + } +/* L40: */ + } + return 0; + +/* End of DORGL2 */ + +} /* dorgl2_ */ + +/* Subroutine */ int dorglq_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int dorgl2_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *), + dlarfb_(char *, char *, char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, integer *), dlarft_(char *, char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORGLQ generates an M-by-N real matrix Q with orthonormal rows, + which is defined as the first M rows of a product of K elementary + reflectors of order N + + Q = H(k) . . . H(2) H(1) + + as returned by DGELQF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. N >= M. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. M >= K >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the i-th row must contain the vector which defines + the elementary reflector H(i), for i = 1,2,...,k, as returned + by DGELQF in the first k rows of its array argument A. + On exit, the M-by-N matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGELQF. + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,M). + For optimum performance LWORK >= M*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "DORGLQ", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1); + lwkopt = max(1,*m) * nb; + work[1] = (doublereal) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < *m) { + *info = -2; + } else if (*k < 0 || *k > *m) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*lwork < max(1,*m) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORGLQ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m <= 0) { + work[1] = 1.; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *m; + if (nb > 1 && nb < *k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "DORGLQ", " ", m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *m; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "DORGLQ", " ", m, n, k, &c_n1, + (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < *k && nx < *k) { + +/* + Use blocked code after the last block. + The first kk rows are handled by the block method. +*/ + + ki = (*k - nx - 1) / nb * nb; +/* Computing MIN */ + i__1 = *k, i__2 = ki + nb; + kk = min(i__1,i__2); + +/* Set A(kk+1:m,1:kk) to zero. */ + + i__1 = kk; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = kk + 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + kk = 0; + } + +/* Use unblocked code for the last or only block. */ + + if (kk < *m) { + i__1 = *m - kk; + i__2 = *n - kk; + i__3 = *k - kk; + dorgl2_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, & + tau[kk + 1], &work[1], &iinfo); + } + + if (kk > 0) { + +/* Use blocked code */ + + i__1 = -nb; + for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) { +/* Computing MIN */ + i__2 = nb, i__3 = *k - i__ + 1; + ib = min(i__2,i__3); + if (i__ + ib <= *m) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__2 = *n - i__ + 1; + dlarft_("Forward", "Rowwise", &i__2, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H' to A(i+ib:m,i:n) from the right */ + + i__2 = *m - i__ - ib + 1; + i__3 = *n - i__ + 1; + dlarfb_("Right", "Transpose", "Forward", "Rowwise", &i__2, & + i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[1], & + ldwork, &a[i__ + ib + i__ * a_dim1], lda, &work[ib + + 1], &ldwork); + } + +/* Apply H' to columns i:n of current block */ + + i__2 = *n - i__ + 1; + dorgl2_(&ib, &i__2, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], & + work[1], &iinfo); + +/* Set columns 1:i-1 of current block to zero */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = i__ + ib - 1; + for (l = i__; l <= i__3; ++l) { + a[l + j * a_dim1] = 0.; +/* L30: */ + } +/* L40: */ + } +/* L50: */ + } + } + + work[1] = (doublereal) iws; + return 0; + +/* End of DORGLQ */ + +} /* dorglq_ */ + +/* Subroutine */ int dorgqr_(integer *m, integer *n, integer *k, doublereal * + a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int dorg2r_(integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *), + dlarfb_(char *, char *, char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, integer *), dlarft_(char *, char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORGQR generates an M-by-N real matrix Q with orthonormal columns, + which is defined as the first N columns of a product of K elementary + reflectors of order M + + Q = H(1) H(2) . . . H(k) + + as returned by DGEQRF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. M >= N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. N >= K >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the i-th column must contain the vector which + defines the elementary reflector H(i), for i = 1,2,...,k, as + returned by DGEQRF in the first k columns of its array + argument A. + On exit, the M-by-N matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGEQRF. + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "DORGQR", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1); + lwkopt = max(1,*n) * nb; + work[1] = (doublereal) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0 || *n > *m) { + *info = -2; + } else if (*k < 0 || *k > *n) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORGQR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + work[1] = 1.; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *n; + if (nb > 1 && nb < *k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "DORGQR", " ", m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "DORGQR", " ", m, n, k, &c_n1, + (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < *k && nx < *k) { + +/* + Use blocked code after the last block. + The first kk columns are handled by the block method. +*/ + + ki = (*k - nx - 1) / nb * nb; +/* Computing MIN */ + i__1 = *k, i__2 = ki + nb; + kk = min(i__1,i__2); + +/* Set A(1:kk,kk+1:n) to zero. */ + + i__1 = *n; + for (j = kk + 1; j <= i__1; ++j) { + i__2 = kk; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + kk = 0; + } + +/* Use unblocked code for the last or only block. */ + + if (kk < *n) { + i__1 = *m - kk; + i__2 = *n - kk; + i__3 = *k - kk; + dorg2r_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, & + tau[kk + 1], &work[1], &iinfo); + } + + if (kk > 0) { + +/* Use blocked code */ + + i__1 = -nb; + for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) { +/* Computing MIN */ + i__2 = nb, i__3 = *k - i__ + 1; + ib = min(i__2,i__3); + if (i__ + ib <= *n) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__2 = *m - i__ + 1; + dlarft_("Forward", "Columnwise", &i__2, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H to A(i:m,i+ib:n) from the left */ + + i__2 = *m - i__ + 1; + i__3 = *n - i__ - ib + 1; + dlarfb_("Left", "No transpose", "Forward", "Columnwise", & + i__2, &i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[ + 1], &ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, & + work[ib + 1], &ldwork); + } + +/* Apply H to rows i:m of current block */ + + i__2 = *m - i__ + 1; + dorg2r_(&i__2, &ib, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], & + work[1], &iinfo); + +/* Set rows 1:i-1 of current block to zero */ + + i__2 = i__ + ib - 1; + for (j = i__; j <= i__2; ++j) { + i__3 = i__ - 1; + for (l = 1; l <= i__3; ++l) { + a[l + j * a_dim1] = 0.; +/* L30: */ + } +/* L40: */ + } +/* L50: */ + } + } + + work[1] = (doublereal) iws; + return 0; + +/* End of DORGQR */ + +} /* dorgqr_ */ + +/* Subroutine */ int dorm2l_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2; + + /* Local variables */ + static integer i__, i1, i2, i3, mi, ni, nq; + static doublereal aii; + static logical left; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORM2L overwrites the general real m by n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'T', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'T', + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by DGEQLF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'T': apply Q' (Transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + DGEQLF in the last k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGEQLF. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) DOUBLE PRECISION array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORM2L", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + } else { + mi = *m; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) is applied to C(1:m-k+i,1:n) */ + + mi = *m - *k + i__; + } else { + +/* H(i) is applied to C(1:m,1:n-k+i) */ + + ni = *n - *k + i__; + } + +/* Apply H(i) */ + + aii = a[nq - *k + i__ + i__ * a_dim1]; + a[nq - *k + i__ + i__ * a_dim1] = 1.; + dlarf_(side, &mi, &ni, &a[i__ * a_dim1 + 1], &c__1, &tau[i__], &c__[ + c_offset], ldc, &work[1]); + a[nq - *k + i__ + i__ * a_dim1] = aii; +/* L10: */ + } + return 0; + +/* End of DORM2L */ + +} /* dorm2l_ */ + +/* Subroutine */ int dorm2r_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2; + + /* Local variables */ + static integer i__, i1, i2, i3, ic, jc, mi, ni, nq; + static doublereal aii; + static logical left; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORM2R overwrites the general real m by n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'T', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'T', + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(1) H(2) . . . H(k) + + as returned by DGEQRF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'T': apply Q' (Transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + DGEQRF in the first k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGEQRF. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) DOUBLE PRECISION array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORM2R", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && ! notran || ! left && notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H(i) is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H(i) */ + + aii = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.; + dlarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], &c__1, &tau[i__], &c__[ + ic + jc * c_dim1], ldc, &work[1]); + a[i__ + i__ * a_dim1] = aii; +/* L10: */ + } + return 0; + +/* End of DORM2R */ + +} /* dorm2r_ */ + +/* Subroutine */ int dormbr_(char *vect, char *side, char *trans, integer *m, + integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, + doublereal *c__, integer *ldc, doublereal *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2]; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int dormlq_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *, integer *); + static logical notran; + extern /* Subroutine */ int dormqr_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *, integer *); + static logical applyq; + static char transt[1]; + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + If VECT = 'Q', DORMBR overwrites the general real M-by-N matrix C + with + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + If VECT = 'P', DORMBR overwrites the general real M-by-N matrix C + with + SIDE = 'L' SIDE = 'R' + TRANS = 'N': P * C C * P + TRANS = 'T': P**T * C C * P**T + + Here Q and P**T are the orthogonal matrices determined by DGEBRD when + reducing a real matrix A to bidiagonal form: A = Q * B * P**T. Q and + P**T are defined as products of elementary reflectors H(i) and G(i) + respectively. + + Let nq = m if SIDE = 'L' and nq = n if SIDE = 'R'. Thus nq is the + order of the orthogonal matrix Q or P**T that is applied. + + If VECT = 'Q', A is assumed to have been an NQ-by-K matrix: + if nq >= k, Q = H(1) H(2) . . . H(k); + if nq < k, Q = H(1) H(2) . . . H(nq-1). + + If VECT = 'P', A is assumed to have been a K-by-NQ matrix: + if k < nq, P = G(1) G(2) . . . G(k); + if k >= nq, P = G(1) G(2) . . . G(nq-1). + + Arguments + ========= + + VECT (input) CHARACTER*1 + = 'Q': apply Q or Q**T; + = 'P': apply P or P**T. + + SIDE (input) CHARACTER*1 + = 'L': apply Q, Q**T, P or P**T from the Left; + = 'R': apply Q, Q**T, P or P**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q or P; + = 'T': Transpose, apply Q**T or P**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + If VECT = 'Q', the number of columns in the original + matrix reduced by DGEBRD. + If VECT = 'P', the number of rows in the original + matrix reduced by DGEBRD. + K >= 0. + + A (input) DOUBLE PRECISION array, dimension + (LDA,min(nq,K)) if VECT = 'Q' + (LDA,nq) if VECT = 'P' + The vectors which define the elementary reflectors H(i) and + G(i), whose products determine the matrices Q and P, as + returned by DGEBRD. + + LDA (input) INTEGER + The leading dimension of the array A. + If VECT = 'Q', LDA >= max(1,nq); + if VECT = 'P', LDA >= max(1,min(nq,K)). + + TAU (input) DOUBLE PRECISION array, dimension (min(nq,K)) + TAU(i) must contain the scalar factor of the elementary + reflector H(i) or G(i) which determines Q or P, as returned + by DGEBRD in the array argument TAUQ or TAUP. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q + or P*C or P**T*C or C*P or C*P**T. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + applyq = lsame_(vect, "Q"); + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q or P and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! applyq && ! lsame_(vect, "P")) { + *info = -1; + } else if (! left && ! lsame_(side, "R")) { + *info = -2; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -3; + } else if (*m < 0) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*k < 0) { + *info = -6; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = 1, i__2 = min(nq,*k); + if (applyq && *lda < max(1,nq) || ! applyq && *lda < max(i__1,i__2)) { + *info = -8; + } else if (*ldc < max(1,*m)) { + *info = -11; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -13; + } + } + + if (*info == 0) { + if (applyq) { + if (left) { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *m - 1; + i__2 = *m - 1; + nb = ilaenv_(&c__1, "DORMQR", ch__1, &i__1, n, &i__2, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *n - 1; + i__2 = *n - 1; + nb = ilaenv_(&c__1, "DORMQR", ch__1, m, &i__1, &i__2, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } else { + if (left) { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *m - 1; + i__2 = *m - 1; + nb = ilaenv_(&c__1, "DORMLQ", ch__1, &i__1, n, &i__2, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *n - 1; + i__2 = *n - 1; + nb = ilaenv_(&c__1, "DORMLQ", ch__1, m, &i__1, &i__2, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } + lwkopt = max(1,nw) * nb; + work[1] = (doublereal) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORMBR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + work[1] = 1.; + if (*m == 0 || *n == 0) { + return 0; + } + + if (applyq) { + +/* Apply Q */ + + if (nq >= *k) { + +/* Q was determined by a call to DGEBRD with nq >= k */ + + dormqr_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], lwork, &iinfo); + } else if (nq > 1) { + +/* Q was determined by a call to DGEBRD with nq < k */ + + if (left) { + mi = *m - 1; + ni = *n; + i1 = 2; + i2 = 1; + } else { + mi = *m; + ni = *n - 1; + i1 = 1; + i2 = 2; + } + i__1 = nq - 1; + dormqr_(side, trans, &mi, &ni, &i__1, &a[a_dim1 + 2], lda, &tau[1] + , &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + } + } else { + +/* Apply P */ + + if (notran) { + *(unsigned char *)transt = 'T'; + } else { + *(unsigned char *)transt = 'N'; + } + if (nq > *k) { + +/* P was determined by a call to DGEBRD with nq > k */ + + dormlq_(side, transt, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], lwork, &iinfo); + } else if (nq > 1) { + +/* P was determined by a call to DGEBRD with nq <= k */ + + if (left) { + mi = *m - 1; + ni = *n; + i1 = 2; + i2 = 1; + } else { + mi = *m; + ni = *n - 1; + i1 = 1; + i2 = 2; + } + i__1 = nq - 1; + dormlq_(side, transt, &mi, &ni, &i__1, &a[(a_dim1 << 1) + 1], lda, + &tau[1], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, & + iinfo); + } + } + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DORMBR */ + +} /* dormbr_ */ + +/* Subroutine */ int dormhr_(char *side, char *trans, integer *m, integer *n, + integer *ilo, integer *ihi, doublereal *a, integer *lda, doublereal * + tau, doublereal *c__, integer *ldc, doublereal *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, nh, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int dormqr_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORMHR overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix of order nq, with nq = m if + SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of + IHI-ILO elementary reflectors, as returned by DGEHRD: + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + ILO and IHI must have the same values as in the previous call + of DGEHRD. Q is equal to the unit matrix except in the + submatrix Q(ilo+1:ihi,ilo+1:ihi). + If SIDE = 'L', then 1 <= ILO <= IHI <= M, if M > 0, and + ILO = 1 and IHI = 0, if M = 0; + if SIDE = 'R', then 1 <= ILO <= IHI <= N, if N > 0, and + ILO = 1 and IHI = 0, if N = 0. + + A (input) DOUBLE PRECISION array, dimension + (LDA,M) if SIDE = 'L' + (LDA,N) if SIDE = 'R' + The vectors which define the elementary reflectors, as + returned by DGEHRD. + + LDA (input) INTEGER + The leading dimension of the array A. + LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. + + TAU (input) DOUBLE PRECISION array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGEHRD. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + nh = *ihi - *ilo; + left = lsame_(side, "L"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*ilo < 1 || *ilo > max(1,nq)) { + *info = -5; + } else if (*ihi < min(*ilo,nq) || *ihi > nq) { + *info = -6; + } else if (*lda < max(1,nq)) { + *info = -8; + } else if (*ldc < max(1,*m)) { + *info = -11; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -13; + } + + if (*info == 0) { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "DORMQR", ch__1, &nh, n, &nh, &c_n1, (ftnlen) + 6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "DORMQR", ch__1, m, &nh, &nh, &c_n1, (ftnlen) + 6, (ftnlen)2); + } + lwkopt = max(1,nw) * nb; + work[1] = (doublereal) lwkopt; + } + + if (*info != 0) { + i__2 = -(*info); + xerbla_("DORMHR", &i__2); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || nh == 0) { + work[1] = 1.; + return 0; + } + + if (left) { + mi = nh; + ni = *n; + i1 = *ilo + 1; + i2 = 1; + } else { + mi = *m; + ni = nh; + i1 = 1; + i2 = *ilo + 1; + } + + dormqr_(side, trans, &mi, &ni, &nh, &a[*ilo + 1 + *ilo * a_dim1], lda, & + tau[*ilo], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DORMHR */ + +} /* dormhr_ */ + +/* Subroutine */ int dorml2_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2; + + /* Local variables */ + static integer i__, i1, i2, i3, ic, jc, mi, ni, nq; + static doublereal aii; + static logical left; + extern /* Subroutine */ int dlarf_(char *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORML2 overwrites the general real m by n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'T', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'T', + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by DGELQF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'T': apply Q' (Transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) DOUBLE PRECISION array, dimension + (LDA,M) if SIDE = 'L', + (LDA,N) if SIDE = 'R' + The i-th row must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + DGELQF in the first k rows of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,K). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGELQF. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) DOUBLE PRECISION array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,*k)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORML2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H(i) is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H(i) */ + + aii = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.; + dlarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], lda, &tau[i__], &c__[ + ic + jc * c_dim1], ldc, &work[1]); + a[i__ + i__ * a_dim1] = aii; +/* L10: */ + } + return 0; + +/* End of DORML2 */ + +} /* dorml2_ */ + +/* Subroutine */ int dormlq_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static doublereal t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int dorml2_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *), dlarfb_(char + *, char *, char *, char *, integer *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *, doublereal *, integer *), dlarft_(char *, char *, integer *, integer *, doublereal + *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical notran; + static integer ldwork; + static char transt[1]; + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORMLQ overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by DGELQF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) DOUBLE PRECISION array, dimension + (LDA,M) if SIDE = 'L', + (LDA,N) if SIDE = 'R' + The i-th row must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + DGELQF in the first k rows of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,K). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGELQF. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,*k)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + +/* + Determine the block size. NB may be at most NBMAX, where NBMAX + is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "DORMLQ", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = max(1,nw) * nb; + work[1] = (doublereal) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORMLQ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + work[1] = 1.; + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "DORMLQ", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + dorml2_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + if (notran) { + *(unsigned char *)transt = 'T'; + } else { + *(unsigned char *)transt = 'N'; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__4 = nq - i__ + 1; + dlarft_("Forward", "Rowwise", &i__4, &ib, &a[i__ + i__ * a_dim1], + lda, &tau[i__], t, &c__65); + if (left) { + +/* H or H' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H or H' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H or H' */ + + dlarfb_(side, transt, "Forward", "Rowwise", &mi, &ni, &ib, &a[i__ + + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * c_dim1], + ldc, &work[1], &ldwork); +/* L10: */ + } + } + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DORMLQ */ + +} /* dormlq_ */ + +/* Subroutine */ int dormql_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static doublereal t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int dorm2l_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *), dlarfb_(char + *, char *, char *, char *, integer *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *, doublereal *, integer *), dlarft_(char *, char *, integer *, integer *, doublereal + *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical notran; + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORMQL overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by DGEQLF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + DGEQLF in the last k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGEQLF. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = max(1,*n); + } else { + nq = *n; + nw = max(1,*m); + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + + if (*info == 0) { + if (*m == 0 || *n == 0) { + lwkopt = 1; + } else { + +/* + Determine the block size. NB may be at most NBMAX, where + NBMAX is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "DORMQL", ch__1, m, n, k, &c_n1, + (ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = nw * nb; + } + work[1] = (doublereal) lwkopt; + + if (*lwork < nw && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORMQL", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "DORMQL", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + dorm2l_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + } else { + mi = *m; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i+ib-1) . . . H(i+1) H(i) +*/ + + i__4 = nq - *k + i__ + ib - 1; + dlarft_("Backward", "Columnwise", &i__4, &ib, &a[i__ * a_dim1 + 1] + , lda, &tau[i__], t, &c__65); + if (left) { + +/* H or H' is applied to C(1:m-k+i+ib-1,1:n) */ + + mi = *m - *k + i__ + ib - 1; + } else { + +/* H or H' is applied to C(1:m,1:n-k+i+ib-1) */ + + ni = *n - *k + i__ + ib - 1; + } + +/* Apply H or H' */ + + dlarfb_(side, trans, "Backward", "Columnwise", &mi, &ni, &ib, &a[ + i__ * a_dim1 + 1], lda, t, &c__65, &c__[c_offset], ldc, & + work[1], &ldwork); +/* L10: */ + } + } + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DORMQL */ + +} /* dormql_ */ + +/* Subroutine */ int dormqr_(char *side, char *trans, integer *m, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static doublereal t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int dorm2r_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *), dlarfb_(char + *, char *, char *, char *, integer *, integer *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *, doublereal *, integer *), dlarft_(char *, char *, integer *, integer *, doublereal + *, integer *, doublereal *, doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical notran; + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORMQR overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(1) H(2) . . . H(k) + + as returned by DGEQRF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + DGEQRF in the first k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) DOUBLE PRECISION array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DGEQRF. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + +/* + Determine the block size. NB may be at most NBMAX, where NBMAX + is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "DORMQR", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = max(1,nw) * nb; + work[1] = (doublereal) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DORMQR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + work[1] = 1.; + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "DORMQR", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + dorm2r_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && ! notran || ! left && notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__4 = nq - i__ + 1; + dlarft_("Forward", "Columnwise", &i__4, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], t, &c__65) + ; + if (left) { + +/* H or H' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H or H' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H or H' */ + + dlarfb_(side, trans, "Forward", "Columnwise", &mi, &ni, &ib, &a[ + i__ + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * + c_dim1], ldc, &work[1], &ldwork); +/* L10: */ + } + } + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DORMQR */ + +} /* dormqr_ */ + +/* Subroutine */ int dormtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, doublereal *a, integer *lda, doublereal *tau, doublereal * + c__, integer *ldc, doublereal *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2, i__3; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int dormql_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *, integer *), + dormqr_(char *, char *, integer *, integer *, integer *, + doublereal *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DORMTR overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix of order nq, with nq = m if + SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of + nq-1 elementary reflectors, as returned by DSYTRD: + + if UPLO = 'U', Q = H(nq-1) . . . H(2) H(1); + + if UPLO = 'L', Q = H(1) H(2) . . . H(nq-1). + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A contains elementary reflectors + from DSYTRD; + = 'L': Lower triangle of A contains elementary reflectors + from DSYTRD. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + A (input) DOUBLE PRECISION array, dimension + (LDA,M) if SIDE = 'L' + (LDA,N) if SIDE = 'R' + The vectors which define the elementary reflectors, as + returned by DSYTRD. + + LDA (input) INTEGER + The leading dimension of the array A. + LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. + + TAU (input) DOUBLE PRECISION array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by DSYTRD. + + C (input/output) DOUBLE PRECISION array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + upper = lsame_(uplo, "U"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! upper && ! lsame_(uplo, "L")) { + *info = -2; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T")) { + *info = -3; + } else if (*m < 0) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + if (upper) { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *m - 1; + i__3 = *m - 1; + nb = ilaenv_(&c__1, "DORMQL", ch__1, &i__2, n, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *n - 1; + i__3 = *n - 1; + nb = ilaenv_(&c__1, "DORMQL", ch__1, m, &i__2, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } else { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *m - 1; + i__3 = *m - 1; + nb = ilaenv_(&c__1, "DORMQR", ch__1, &i__2, n, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *n - 1; + i__3 = *n - 1; + nb = ilaenv_(&c__1, "DORMQR", ch__1, m, &i__2, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } + lwkopt = max(1,nw) * nb; + work[1] = (doublereal) lwkopt; + } + + if (*info != 0) { + i__2 = -(*info); + xerbla_("DORMTR", &i__2); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || nq == 1) { + work[1] = 1.; + return 0; + } + + if (left) { + mi = *m - 1; + ni = *n; + } else { + mi = *m; + ni = *n - 1; + } + + if (upper) { + +/* Q was determined by a call to DSYTRD with UPLO = 'U' */ + + i__2 = nq - 1; + dormql_(side, trans, &mi, &ni, &i__2, &a[(a_dim1 << 1) + 1], lda, & + tau[1], &c__[c_offset], ldc, &work[1], lwork, &iinfo); + } else { + +/* Q was determined by a call to DSYTRD with UPLO = 'L' */ + + if (left) { + i1 = 2; + i2 = 1; + } else { + i1 = 1; + i2 = 2; + } + i__2 = nq - 1; + dormqr_(side, trans, &mi, &ni, &i__2, &a[a_dim1 + 2], lda, &tau[1], & + c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + } + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DORMTR */ + +} /* dormtr_ */ + +/* Subroutine */ int dpotf2_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1; + + /* Local variables */ + static integer j; + static doublereal ajj; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *); + static logical upper; + extern logical disnan_(doublereal *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DPOTF2 computes the Cholesky factorization of a real symmetric + positive definite matrix A. + + The factorization has the form + A = U' * U , if UPLO = 'U', or + A = L * L', if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the unblocked version of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is stored. + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + n by n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U'*U or A = L*L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, the leading minor of order k is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DPOTF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute U(J,J) and test for non-positive-definiteness. */ + + i__2 = j - 1; + ajj = a[j + j * a_dim1] - ddot_(&i__2, &a[j * a_dim1 + 1], &c__1, + &a[j * a_dim1 + 1], &c__1); + if (ajj <= 0. || disnan_(&ajj)) { + a[j + j * a_dim1] = ajj; + goto L30; + } + ajj = sqrt(ajj); + a[j + j * a_dim1] = ajj; + +/* Compute elements J+1:N of row J. */ + + if (j < *n) { + i__2 = j - 1; + i__3 = *n - j; + dgemv_("Transpose", &i__2, &i__3, &c_b151, &a[(j + 1) * + a_dim1 + 1], lda, &a[j * a_dim1 + 1], &c__1, &c_b15, & + a[j + (j + 1) * a_dim1], lda); + i__2 = *n - j; + d__1 = 1. / ajj; + dscal_(&i__2, &d__1, &a[j + (j + 1) * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute L(J,J) and test for non-positive-definiteness. */ + + i__2 = j - 1; + ajj = a[j + j * a_dim1] - ddot_(&i__2, &a[j + a_dim1], lda, &a[j + + a_dim1], lda); + if (ajj <= 0. || disnan_(&ajj)) { + a[j + j * a_dim1] = ajj; + goto L30; + } + ajj = sqrt(ajj); + a[j + j * a_dim1] = ajj; + +/* Compute elements J+1:N of column J. */ + + if (j < *n) { + i__2 = *n - j; + i__3 = j - 1; + dgemv_("No transpose", &i__2, &i__3, &c_b151, &a[j + 1 + + a_dim1], lda, &a[j + a_dim1], lda, &c_b15, &a[j + 1 + + j * a_dim1], &c__1); + i__2 = *n - j; + d__1 = 1. / ajj; + dscal_(&i__2, &d__1, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + goto L40; + +L30: + *info = j; + +L40: + return 0; + +/* End of DPOTF2 */ + +} /* dpotf2_ */ + +/* Subroutine */ int dpotrf_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer j, jb, nb; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *); + static logical upper; + extern /* Subroutine */ int dsyrk_(char *, char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, doublereal *, + integer *), dpotf2_(char *, integer *, + doublereal *, integer *, integer *), xerbla_(char *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DPOTRF computes the Cholesky factorization of a real symmetric + positive definite matrix A. + + The factorization has the form + A = U**T * U, if UPLO = 'U', or + A = L * L**T, if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the block version of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U**T*U or A = L*L**T. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the leading minor of order i is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DPOTRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "DPOTRF", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code. */ + + dpotf2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code. */ + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + dsyrk_("Upper", "Transpose", &jb, &i__3, &c_b151, &a[j * + a_dim1 + 1], lda, &c_b15, &a[j + j * a_dim1], lda); + dpotf2_("Upper", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block row. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + dgemm_("Transpose", "No transpose", &jb, &i__3, &i__4, & + c_b151, &a[j * a_dim1 + 1], lda, &a[(j + jb) * + a_dim1 + 1], lda, &c_b15, &a[j + (j + jb) * + a_dim1], lda); + i__3 = *n - j - jb + 1; + dtrsm_("Left", "Upper", "Transpose", "Non-unit", &jb, & + i__3, &c_b15, &a[j + j * a_dim1], lda, &a[j + (j + + jb) * a_dim1], lda); + } +/* L10: */ + } + + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__2 = *n; + i__1 = nb; + for (j = 1; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + dsyrk_("Lower", "No transpose", &jb, &i__3, &c_b151, &a[j + + a_dim1], lda, &c_b15, &a[j + j * a_dim1], lda); + dpotf2_("Lower", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block column. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + dgemm_("No transpose", "Transpose", &i__3, &jb, &i__4, & + c_b151, &a[j + jb + a_dim1], lda, &a[j + a_dim1], + lda, &c_b15, &a[j + jb + j * a_dim1], lda); + i__3 = *n - j - jb + 1; + dtrsm_("Right", "Lower", "Transpose", "Non-unit", &i__3, & + jb, &c_b15, &a[j + j * a_dim1], lda, &a[j + jb + + j * a_dim1], lda); + } +/* L20: */ + } + } + } + goto L40; + +L30: + *info = *info + j - 1; + +L40: + return 0; + +/* End of DPOTRF */ + +} /* dpotrf_ */ + +/* Subroutine */ int dpotri_(char *uplo, integer *n, doublereal *a, integer * + lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *), dlauum_( + char *, integer *, doublereal *, integer *, integer *), + dtrtri_(char *, char *, integer *, doublereal *, integer *, + integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DPOTRI computes the inverse of a real symmetric positive definite + matrix A using the Cholesky factorization A = U**T*U or A = L*L**T + computed by DPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the triangular factor U or L from the Cholesky + factorization A = U**T*U or A = L*L**T, as computed by + DPOTRF. + On exit, the upper or lower triangle of the (symmetric) + inverse of A, overwriting the input factor U or L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the (i,i) element of the factor U or L is + zero, and the inverse could not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DPOTRI", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Invert the triangular Cholesky factor U or L. */ + + dtrtri_(uplo, "Non-unit", n, &a[a_offset], lda, info); + if (*info > 0) { + return 0; + } + +/* Form inv(U)*inv(U)' or inv(L)'*inv(L). */ + + dlauum_(uplo, n, &a[a_offset], lda, info); + + return 0; + +/* End of DPOTRI */ + +} /* dpotri_ */ + +/* Subroutine */ int dpotrs_(char *uplo, integer *n, integer *nrhs, + doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * + info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dtrsm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DPOTRS solves a system of linear equations A*X = B with a symmetric + positive definite matrix A using the Cholesky factorization + A = U**T*U or A = L*L**T computed by DPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The triangular factor U or L from the Cholesky factorization + A = U**T*U or A = L*L**T, as computed by DPOTRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DPOTRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (upper) { + +/* + Solve A*X = B where A = U'*U. + + Solve U'*X = B, overwriting B with X. +*/ + + dtrsm_("Left", "Upper", "Transpose", "Non-unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + dtrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b15, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A*X = B where A = L*L'. + + Solve L*X = B, overwriting B with X. +*/ + + dtrsm_("Left", "Lower", "No transpose", "Non-unit", n, nrhs, &c_b15, & + a[a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + dtrsm_("Left", "Lower", "Transpose", "Non-unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + } + + return 0; + +/* End of DPOTRS */ + +} /* dpotrs_ */ + +/* Subroutine */ int dstedc_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublereal *z__, integer *ldz, doublereal *work, + integer *lwork, integer *iwork, integer *liwork, integer *info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__, j, k, m; + static doublereal p; + static integer ii, lgn; + static doublereal eps, tiny; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dswap_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer lwmin; + extern /* Subroutine */ int dlaed0_(integer *, integer *, integer *, + doublereal *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, integer *, integer *); + static integer start; + + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dlacpy_(char *, integer *, integer + *, doublereal *, integer *, doublereal *, integer *), + dlaset_(char *, integer *, integer *, doublereal *, doublereal *, + doublereal *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *); + static integer finish; + extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); + extern /* Subroutine */ int dsterf_(integer *, doublereal *, doublereal *, + integer *), dlasrt_(char *, integer *, doublereal *, integer *); + static integer liwmin, icompz; + extern /* Subroutine */ int dsteqr_(char *, integer *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, integer *); + static doublereal orgnrm; + static logical lquery; + static integer smlsiz, storez, strtrw; + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DSTEDC computes all eigenvalues and, optionally, eigenvectors of a + symmetric tridiagonal matrix using the divide and conquer method. + The eigenvectors of a full or band real symmetric matrix can also be + found if DSYTRD or DSPTRD or DSBTRD has been used to reduce this + matrix to tridiagonal form. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. See DLAED3 for details. + + Arguments + ========= + + COMPZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only. + = 'I': Compute eigenvectors of tridiagonal matrix also. + = 'V': Compute eigenvectors of original dense symmetric + matrix also. On entry, Z contains the orthogonal + matrix used to reduce the original matrix to + tridiagonal form. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + On entry, the subdiagonal elements of the tridiagonal matrix. + On exit, E has been destroyed. + + Z (input/output) DOUBLE PRECISION array, dimension (LDZ,N) + On entry, if COMPZ = 'V', then Z contains the orthogonal + matrix used in the reduction to tridiagonal form. + On exit, if INFO = 0, then if COMPZ = 'V', Z contains the + orthonormal eigenvectors of the original symmetric matrix, + and if COMPZ = 'I', Z contains the orthonormal eigenvectors + of the symmetric tridiagonal matrix. + If COMPZ = 'N', then Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= 1. + If eigenvectors are desired, then LDZ >= max(1,N). + + WORK (workspace/output) DOUBLE PRECISION array, + dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If COMPZ = 'N' or N <= 1 then LWORK must be at least 1. + If COMPZ = 'V' and N > 1 then LWORK must be at least + ( 1 + 3*N + 2*N*lg N + 3*N**2 ), + where lg( N ) = smallest integer k such + that 2**k >= N. + If COMPZ = 'I' and N > 1 then LWORK must be at least + ( 1 + 4*N + N**2 ). + Note that for COMPZ = 'I' or 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LWORK need + only be max(1,2*(N-1)). + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) + On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. + + LIWORK (input) INTEGER + The dimension of the array IWORK. + If COMPZ = 'N' or N <= 1 then LIWORK must be at least 1. + If COMPZ = 'V' and N > 1 then LIWORK must be at least + ( 6 + 6*N + 5*N*lg N ). + If COMPZ = 'I' and N > 1 then LIWORK must be at least + ( 3 + 5*N ). + Note that for COMPZ = 'I' or 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LIWORK + need only be 1. + + If LIWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal size of the IWORK array, + returns this value as the first entry of the IWORK array, and + no error message related to LIWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute an eigenvalue while + working on the submatrix lying in rows and columns + INFO/(N+1) through mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1 || *liwork == -1; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + + if (*info == 0) { + +/* Compute the workspace requirements */ + + smlsiz = ilaenv_(&c__9, "DSTEDC", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + if (*n <= 1 || icompz == 0) { + liwmin = 1; + lwmin = 1; + } else if (*n <= smlsiz) { + liwmin = 1; + lwmin = *n - 1 << 1; + } else { + lgn = (integer) (log((doublereal) (*n)) / log(2.)); + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (icompz == 1) { +/* Computing 2nd power */ + i__1 = *n; + lwmin = *n * 3 + 1 + (*n << 1) * lgn + i__1 * i__1 * 3; + liwmin = *n * 6 + 6 + *n * 5 * lgn; + } else if (icompz == 2) { +/* Computing 2nd power */ + i__1 = *n; + lwmin = (*n << 2) + 1 + i__1 * i__1; + liwmin = *n * 5 + 3; + } + } + work[1] = (doublereal) lwmin; + iwork[1] = liwmin; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*liwork < liwmin && ! lquery) { + *info = -10; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DSTEDC", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*n == 1) { + if (icompz != 0) { + z__[z_dim1 + 1] = 1.; + } + return 0; + } + +/* + If the following conditional clause is removed, then the routine + will use the Divide and Conquer routine to compute only the + eigenvalues, which requires (3N + 3N**2) real workspace and + (2 + 5N + 2N lg(N)) integer workspace. + Since on many architectures DSTERF is much faster than any other + algorithm for finding eigenvalues only, it is used here + as the default. If the conditional clause is removed, then + information on the size of workspace needs to be changed. + + If COMPZ = 'N', use DSTERF to compute the eigenvalues. +*/ + + if (icompz == 0) { + dsterf_(n, &d__[1], &e[1], info); + goto L50; + } + +/* + If N is smaller than the minimum divide size (SMLSIZ+1), then + solve the problem with another solver. +*/ + + if (*n <= smlsiz) { + + dsteqr_(compz, n, &d__[1], &e[1], &z__[z_offset], ldz, &work[1], info); + + } else { + +/* + If COMPZ = 'V', the Z matrix must be stored elsewhere for later + use. +*/ + + if (icompz == 1) { + storez = *n * *n + 1; + } else { + storez = 1; + } + + if (icompz == 2) { + dlaset_("Full", n, n, &c_b29, &c_b15, &z__[z_offset], ldz); + } + +/* Scale. */ + + orgnrm = dlanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.) { + goto L50; + } + + eps = EPSILON; + + start = 1; + +/* while ( START <= N ) */ + +L10: + if (start <= *n) { + +/* + Let FINISH be the position of the next subdiagonal entry + such that E( FINISH ) <= TINY or FINISH = N if no such + subdiagonal exists. The matrix identified by the elements + between START and FINISH constitutes an independent + sub-problem. +*/ + + finish = start; +L20: + if (finish < *n) { + tiny = eps * sqrt((d__1 = d__[finish], abs(d__1))) * sqrt(( + d__2 = d__[finish + 1], abs(d__2))); + if ((d__1 = e[finish], abs(d__1)) > tiny) { + ++finish; + goto L20; + } + } + +/* (Sub) Problem determined. Compute its size and solve it. */ + + m = finish - start + 1; + if (m == 1) { + start = finish + 1; + goto L10; + } + if (m > smlsiz) { + +/* Scale. */ + + orgnrm = dlanst_("M", &m, &d__[start], &e[start]); + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &m, &c__1, &d__[ + start], &m, info); + i__1 = m - 1; + i__2 = m - 1; + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &i__1, &c__1, &e[ + start], &i__2, info); + + if (icompz == 1) { + strtrw = 1; + } else { + strtrw = start; + } + dlaed0_(&icompz, n, &m, &d__[start], &e[start], &z__[strtrw + + start * z_dim1], ldz, &work[1], n, &work[storez], & + iwork[1], info); + if (*info != 0) { + *info = (*info / (m + 1) + start - 1) * (*n + 1) + *info % + (m + 1) + start - 1; + goto L50; + } + +/* Scale back. */ + + dlascl_("G", &c__0, &c__0, &c_b15, &orgnrm, &m, &c__1, &d__[ + start], &m, info); + + } else { + if (icompz == 1) { + +/* + Since QR won't update a Z matrix which is larger than + the length of D, we must solve the sub-problem in a + workspace and then multiply back into Z. +*/ + + dsteqr_("I", &m, &d__[start], &e[start], &work[1], &m, & + work[m * m + 1], info); + dlacpy_("A", n, &m, &z__[start * z_dim1 + 1], ldz, &work[ + storez], n); + dgemm_("N", "N", n, &m, &m, &c_b15, &work[storez], n, & + work[1], &m, &c_b29, &z__[start * z_dim1 + 1], + ldz); + } else if (icompz == 2) { + dsteqr_("I", &m, &d__[start], &e[start], &z__[start + + start * z_dim1], ldz, &work[1], info); + } else { + dsterf_(&m, &d__[start], &e[start], info); + } + if (*info != 0) { + *info = start * (*n + 1) + finish; + goto L50; + } + } + + start = finish + 1; + goto L10; + } + +/* + endwhile + + If the problem split any number of times, then the eigenvalues + will not be properly ordered. Here we permute the eigenvalues + (and the associated eigenvectors) into ascending order. +*/ + + if (m != *n) { + if (icompz == 0) { + +/* Use Quick Sort */ + + dlasrt_("I", n, &d__[1], info); + + } else { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L30: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + dswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * + z_dim1 + 1], &c__1); + } +/* L40: */ + } + } + } + } + +L50: + work[1] = (doublereal) lwmin; + iwork[1] = liwmin; + + return 0; + +/* End of DSTEDC */ + +} /* dstedc_ */ + +/* Subroutine */ int dsteqr_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublereal *z__, integer *ldz, doublereal *work, + integer *info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal b, c__, f, g; + static integer i__, j, k, l, m; + static doublereal p, r__, s; + static integer l1, ii, mm, lm1, mm1, nm1; + static doublereal rt1, rt2, eps; + static integer lsv; + static doublereal tst, eps2; + static integer lend, jtot; + extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal + *, doublereal *, doublereal *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dlasr_(char *, char *, char *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *); + static doublereal anorm; + extern /* Subroutine */ int dswap_(integer *, doublereal *, integer *, + doublereal *, integer *), dlaev2_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *); + static integer lendm1, lendp1; + + static integer iscale; + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dlaset_(char *, integer *, integer + *, doublereal *, doublereal *, doublereal *, integer *); + static doublereal safmin; + extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *); + static doublereal safmax; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); + extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, + integer *); + static integer lendsv; + static doublereal ssfmin; + static integer nmaxit, icompz; + static doublereal ssfmax; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DSTEQR computes all eigenvalues and, optionally, eigenvectors of a + symmetric tridiagonal matrix using the implicit QL or QR method. + The eigenvectors of a full or band symmetric matrix can also be found + if DSYTRD or DSPTRD or DSBTRD has been used to reduce this matrix to + tridiagonal form. + + Arguments + ========= + + COMPZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only. + = 'V': Compute eigenvalues and eigenvectors of the original + symmetric matrix. On entry, Z must contain the + orthogonal matrix used to reduce the original matrix + to tridiagonal form. + = 'I': Compute eigenvalues and eigenvectors of the + tridiagonal matrix. Z is initialized to the identity + matrix. + + N (input) INTEGER + The order of the matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + On entry, the (n-1) subdiagonal elements of the tridiagonal + matrix. + On exit, E has been destroyed. + + Z (input/output) DOUBLE PRECISION array, dimension (LDZ, N) + On entry, if COMPZ = 'V', then Z contains the orthogonal + matrix used in the reduction to tridiagonal form. + On exit, if INFO = 0, then if COMPZ = 'V', Z contains the + orthonormal eigenvectors of the original symmetric matrix, + and if COMPZ = 'I', Z contains the orthonormal eigenvectors + of the symmetric tridiagonal matrix. + If COMPZ = 'N', then Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= 1, and if + eigenvectors are desired, then LDZ >= max(1,N). + + WORK (workspace) DOUBLE PRECISION array, dimension (max(1,2*N-2)) + If COMPZ = 'N', then WORK is not referenced. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: the algorithm has failed to find all the eigenvalues in + a total of 30*N iterations; if INFO = i, then i + elements of E have not converged to zero; on exit, D + and E contain the elements of a symmetric tridiagonal + matrix which is orthogonally similar to the original + matrix. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DSTEQR", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (*n == 1) { + if (icompz == 2) { + z__[z_dim1 + 1] = 1.; + } + return 0; + } + +/* Determine the unit roundoff and over/underflow thresholds. */ + + eps = EPSILON; +/* Computing 2nd power */ + d__1 = eps; + eps2 = d__1 * d__1; + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + ssfmax = sqrt(safmax) / 3.; + ssfmin = sqrt(safmin) / eps2; + +/* + Compute the eigenvalues and eigenvectors of the tridiagonal + matrix. +*/ + + if (icompz == 2) { + dlaset_("Full", n, n, &c_b29, &c_b15, &z__[z_offset], ldz); + } + + nmaxit = *n * 30; + jtot = 0; + +/* + Determine where the matrix splits and choose QL or QR iteration + for each block, according to whether top or bottom diagonal + element is smaller. +*/ + + l1 = 1; + nm1 = *n - 1; + +L10: + if (l1 > *n) { + goto L160; + } + if (l1 > 1) { + e[l1 - 1] = 0.; + } + if (l1 <= nm1) { + i__1 = nm1; + for (m = l1; m <= i__1; ++m) { + tst = (d__1 = e[m], abs(d__1)); + if (tst == 0.) { + goto L30; + } + if (tst <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m + + 1], abs(d__2))) * eps) { + e[m] = 0.; + goto L30; + } +/* L20: */ + } + } + m = *n; + +L30: + l = l1; + lsv = l; + lend = m; + lendsv = lend; + l1 = m + 1; + if (lend == l) { + goto L10; + } + +/* Scale submatrix in rows and columns L to LEND */ + + i__1 = lend - l + 1; + anorm = dlanst_("I", &i__1, &d__[l], &e[l]); + iscale = 0; + if (anorm == 0.) { + goto L10; + } + if (anorm > ssfmax) { + iscale = 1; + i__1 = lend - l + 1; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, + info); + } else if (anorm < ssfmin) { + iscale = 2; + i__1 = lend - l + 1; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, + info); + } + +/* Choose between QL and QR iteration */ + + if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) { + lend = lsv; + l = lendsv; + } + + if (lend > l) { + +/* + QL Iteration + + Look for small subdiagonal element. +*/ + +L40: + if (l != lend) { + lendm1 = lend - 1; + i__1 = lendm1; + for (m = l; m <= i__1; ++m) { +/* Computing 2nd power */ + d__2 = (d__1 = e[m], abs(d__1)); + tst = d__2 * d__2; + if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m + + 1], abs(d__2)) + safmin) { + goto L60; + } +/* L50: */ + } + } + + m = lend; + +L60: + if (m < lend) { + e[m] = 0.; + } + p = d__[l]; + if (m == l) { + goto L80; + } + +/* + If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 + to compute its eigensystem. +*/ + + if (m == l + 1) { + if (icompz > 0) { + dlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); + work[l] = c__; + work[*n - 1 + l] = s; + dlasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], & + z__[l * z_dim1 + 1], ldz); + } else { + dlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); + } + d__[l] = rt1; + d__[l + 1] = rt2; + e[l] = 0.; + l += 2; + if (l <= lend) { + goto L40; + } + goto L140; + } + + if (jtot == nmaxit) { + goto L140; + } + ++jtot; + +/* Form shift. */ + + g = (d__[l + 1] - p) / (e[l] * 2.); + r__ = dlapy2_(&g, &c_b15); + g = d__[m] - p + e[l] / (g + d_sign(&r__, &g)); + + s = 1.; + c__ = 1.; + p = 0.; + +/* Inner loop */ + + mm1 = m - 1; + i__1 = l; + for (i__ = mm1; i__ >= i__1; --i__) { + f = s * e[i__]; + b = c__ * e[i__]; + dlartg_(&g, &f, &c__, &s, &r__); + if (i__ != m - 1) { + e[i__ + 1] = r__; + } + g = d__[i__ + 1] - p; + r__ = (d__[i__] - g) * s + c__ * 2. * b; + p = s * r__; + d__[i__ + 1] = g + p; + g = c__ * r__ - b; + +/* If eigenvectors are desired, then save rotations. */ + + if (icompz > 0) { + work[i__] = c__; + work[*n - 1 + i__] = -s; + } + +/* L70: */ + } + +/* If eigenvectors are desired, then apply saved rotations. */ + + if (icompz > 0) { + mm = m - l + 1; + dlasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l + * z_dim1 + 1], ldz); + } + + d__[l] -= p; + e[l] = g; + goto L40; + +/* Eigenvalue found. */ + +L80: + d__[l] = p; + + ++l; + if (l <= lend) { + goto L40; + } + goto L140; + + } else { + +/* + QR Iteration + + Look for small superdiagonal element. +*/ + +L90: + if (l != lend) { + lendp1 = lend + 1; + i__1 = lendp1; + for (m = l; m >= i__1; --m) { +/* Computing 2nd power */ + d__2 = (d__1 = e[m - 1], abs(d__1)); + tst = d__2 * d__2; + if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m + - 1], abs(d__2)) + safmin) { + goto L110; + } +/* L100: */ + } + } + + m = lend; + +L110: + if (m > lend) { + e[m - 1] = 0.; + } + p = d__[l]; + if (m == l) { + goto L130; + } + +/* + If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 + to compute its eigensystem. +*/ + + if (m == l - 1) { + if (icompz > 0) { + dlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) + ; + work[m] = c__; + work[*n - 1 + m] = s; + dlasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], & + z__[(l - 1) * z_dim1 + 1], ldz); + } else { + dlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); + } + d__[l - 1] = rt1; + d__[l] = rt2; + e[l - 1] = 0.; + l += -2; + if (l >= lend) { + goto L90; + } + goto L140; + } + + if (jtot == nmaxit) { + goto L140; + } + ++jtot; + +/* Form shift. */ + + g = (d__[l - 1] - p) / (e[l - 1] * 2.); + r__ = dlapy2_(&g, &c_b15); + g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g)); + + s = 1.; + c__ = 1.; + p = 0.; + +/* Inner loop */ + + lm1 = l - 1; + i__1 = lm1; + for (i__ = m; i__ <= i__1; ++i__) { + f = s * e[i__]; + b = c__ * e[i__]; + dlartg_(&g, &f, &c__, &s, &r__); + if (i__ != m) { + e[i__ - 1] = r__; + } + g = d__[i__] - p; + r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b; + p = s * r__; + d__[i__] = g + p; + g = c__ * r__ - b; + +/* If eigenvectors are desired, then save rotations. */ + + if (icompz > 0) { + work[i__] = c__; + work[*n - 1 + i__] = s; + } + +/* L120: */ + } + +/* If eigenvectors are desired, then apply saved rotations. */ + + if (icompz > 0) { + mm = l - m + 1; + dlasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m + * z_dim1 + 1], ldz); + } + + d__[l] -= p; + e[lm1] = g; + goto L90; + +/* Eigenvalue found. */ + +L130: + d__[l] = p; + + --l; + if (l >= lend) { + goto L90; + } + goto L140; + + } + +/* Undo scaling if necessary */ + +L140: + if (iscale == 1) { + i__1 = lendsv - lsv + 1; + dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + i__1 = lendsv - lsv; + dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, + info); + } else if (iscale == 2) { + i__1 = lendsv - lsv + 1; + dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + i__1 = lendsv - lsv; + dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, + info); + } + +/* + Check for no convergence to an eigenvalue after a total + of N*MAXIT iterations. +*/ + + if (jtot < nmaxit) { + goto L10; + } + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (e[i__] != 0.) { + ++(*info); + } +/* L150: */ + } + goto L190; + +/* Order eigenvalues and eigenvectors. */ + +L160: + if (icompz == 0) { + +/* Use Quick Sort */ + + dlasrt_("I", n, &d__[1], info); + + } else { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L170: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + dswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], + &c__1); + } +/* L180: */ + } + } + +L190: + return 0; + +/* End of DSTEQR */ + +} /* dsteqr_ */ + +/* Subroutine */ int dsterf_(integer *n, doublereal *d__, doublereal *e, + integer *info) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2, d__3; + + /* Local variables */ + static doublereal c__; + static integer i__, l, m; + static doublereal p, r__, s; + static integer l1; + static doublereal bb, rt1, rt2, eps, rte; + static integer lsv; + static doublereal eps2, oldc; + static integer lend, jtot; + extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal + *, doublereal *, doublereal *); + static doublereal gamma, alpha, sigma, anorm; + + static integer iscale; + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *); + static doublereal oldgam, safmin; + extern /* Subroutine */ int xerbla_(char *, integer *); + static doublereal safmax; + extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); + extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, + integer *); + static integer lendsv; + static doublereal ssfmin; + static integer nmaxit; + static doublereal ssfmax; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DSTERF computes all eigenvalues of a symmetric tridiagonal matrix + using the Pal-Walker-Kahan variant of the QL or QR algorithm. + + Arguments + ========= + + N (input) INTEGER + The order of the matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the n diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + On entry, the (n-1) subdiagonal elements of the tridiagonal + matrix. + On exit, E has been destroyed. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: the algorithm failed to find all of the eigenvalues in + a total of 30*N iterations; if INFO = i, then i + elements of E have not converged to zero. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --e; + --d__; + + /* Function Body */ + *info = 0; + +/* Quick return if possible */ + + if (*n < 0) { + *info = -1; + i__1 = -(*info); + xerbla_("DSTERF", &i__1); + return 0; + } + if (*n <= 1) { + return 0; + } + +/* Determine the unit roundoff for this environment. */ + + eps = EPSILON; +/* Computing 2nd power */ + d__1 = eps; + eps2 = d__1 * d__1; + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + ssfmax = sqrt(safmax) / 3.; + ssfmin = sqrt(safmin) / eps2; + +/* Compute the eigenvalues of the tridiagonal matrix. */ + + nmaxit = *n * 30; + sigma = 0.; + jtot = 0; + +/* + Determine where the matrix splits and choose QL or QR iteration + for each block, according to whether top or bottom diagonal + element is smaller. +*/ + + l1 = 1; + +L10: + if (l1 > *n) { + goto L170; + } + if (l1 > 1) { + e[l1 - 1] = 0.; + } + i__1 = *n - 1; + for (m = l1; m <= i__1; ++m) { + if ((d__3 = e[m], abs(d__3)) <= sqrt((d__1 = d__[m], abs(d__1))) * + sqrt((d__2 = d__[m + 1], abs(d__2))) * eps) { + e[m] = 0.; + goto L30; + } +/* L20: */ + } + m = *n; + +L30: + l = l1; + lsv = l; + lend = m; + lendsv = lend; + l1 = m + 1; + if (lend == l) { + goto L10; + } + +/* Scale submatrix in rows and columns L to LEND */ + + i__1 = lend - l + 1; + anorm = dlanst_("I", &i__1, &d__[l], &e[l]); + iscale = 0; + if (anorm > ssfmax) { + iscale = 1; + i__1 = lend - l + 1; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, + info); + } else if (anorm < ssfmin) { + iscale = 2; + i__1 = lend - l + 1; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, + info); + } + + i__1 = lend - 1; + for (i__ = l; i__ <= i__1; ++i__) { +/* Computing 2nd power */ + d__1 = e[i__]; + e[i__] = d__1 * d__1; +/* L40: */ + } + +/* Choose between QL and QR iteration */ + + if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) { + lend = lsv; + l = lendsv; + } + + if (lend >= l) { + +/* + QL Iteration + + Look for small subdiagonal element. +*/ + +L50: + if (l != lend) { + i__1 = lend - 1; + for (m = l; m <= i__1; ++m) { + if ((d__2 = e[m], abs(d__2)) <= eps2 * (d__1 = d__[m] * d__[m + + 1], abs(d__1))) { + goto L70; + } +/* L60: */ + } + } + m = lend; + +L70: + if (m < lend) { + e[m] = 0.; + } + p = d__[l]; + if (m == l) { + goto L90; + } + +/* + If remaining matrix is 2 by 2, use DLAE2 to compute its + eigenvalues. +*/ + + if (m == l + 1) { + rte = sqrt(e[l]); + dlae2_(&d__[l], &rte, &d__[l + 1], &rt1, &rt2); + d__[l] = rt1; + d__[l + 1] = rt2; + e[l] = 0.; + l += 2; + if (l <= lend) { + goto L50; + } + goto L150; + } + + if (jtot == nmaxit) { + goto L150; + } + ++jtot; + +/* Form shift. */ + + rte = sqrt(e[l]); + sigma = (d__[l + 1] - p) / (rte * 2.); + r__ = dlapy2_(&sigma, &c_b15); + sigma = p - rte / (sigma + d_sign(&r__, &sigma)); + + c__ = 1.; + s = 0.; + gamma = d__[m] - sigma; + p = gamma * gamma; + +/* Inner loop */ + + i__1 = l; + for (i__ = m - 1; i__ >= i__1; --i__) { + bb = e[i__]; + r__ = p + bb; + if (i__ != m - 1) { + e[i__ + 1] = s * r__; + } + oldc = c__; + c__ = p / r__; + s = bb / r__; + oldgam = gamma; + alpha = d__[i__]; + gamma = c__ * (alpha - sigma) - s * oldgam; + d__[i__ + 1] = oldgam + (alpha - gamma); + if (c__ != 0.) { + p = gamma * gamma / c__; + } else { + p = oldc * bb; + } +/* L80: */ + } + + e[l] = s * p; + d__[l] = sigma + gamma; + goto L50; + +/* Eigenvalue found. */ + +L90: + d__[l] = p; + + ++l; + if (l <= lend) { + goto L50; + } + goto L150; + + } else { + +/* + QR Iteration + + Look for small superdiagonal element. +*/ + +L100: + i__1 = lend + 1; + for (m = l; m >= i__1; --m) { + if ((d__2 = e[m - 1], abs(d__2)) <= eps2 * (d__1 = d__[m] * d__[m + - 1], abs(d__1))) { + goto L120; + } +/* L110: */ + } + m = lend; + +L120: + if (m > lend) { + e[m - 1] = 0.; + } + p = d__[l]; + if (m == l) { + goto L140; + } + +/* + If remaining matrix is 2 by 2, use DLAE2 to compute its + eigenvalues. +*/ + + if (m == l - 1) { + rte = sqrt(e[l - 1]); + dlae2_(&d__[l], &rte, &d__[l - 1], &rt1, &rt2); + d__[l] = rt1; + d__[l - 1] = rt2; + e[l - 1] = 0.; + l += -2; + if (l >= lend) { + goto L100; + } + goto L150; + } + + if (jtot == nmaxit) { + goto L150; + } + ++jtot; + +/* Form shift. */ + + rte = sqrt(e[l - 1]); + sigma = (d__[l - 1] - p) / (rte * 2.); + r__ = dlapy2_(&sigma, &c_b15); + sigma = p - rte / (sigma + d_sign(&r__, &sigma)); + + c__ = 1.; + s = 0.; + gamma = d__[m] - sigma; + p = gamma * gamma; + +/* Inner loop */ + + i__1 = l - 1; + for (i__ = m; i__ <= i__1; ++i__) { + bb = e[i__]; + r__ = p + bb; + if (i__ != m) { + e[i__ - 1] = s * r__; + } + oldc = c__; + c__ = p / r__; + s = bb / r__; + oldgam = gamma; + alpha = d__[i__ + 1]; + gamma = c__ * (alpha - sigma) - s * oldgam; + d__[i__] = oldgam + (alpha - gamma); + if (c__ != 0.) { + p = gamma * gamma / c__; + } else { + p = oldc * bb; + } +/* L130: */ + } + + e[l - 1] = s * p; + d__[l] = sigma + gamma; + goto L100; + +/* Eigenvalue found. */ + +L140: + d__[l] = p; + + --l; + if (l >= lend) { + goto L100; + } + goto L150; + + } + +/* Undo scaling if necessary */ + +L150: + if (iscale == 1) { + i__1 = lendsv - lsv + 1; + dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + } + if (iscale == 2) { + i__1 = lendsv - lsv + 1; + dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + } + +/* + Check for no convergence to an eigenvalue after a total + of N*MAXIT iterations. +*/ + + if (jtot < nmaxit) { + goto L10; + } + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (e[i__] != 0.) { + ++(*info); + } +/* L160: */ + } + goto L180; + +/* Sort eigenvalues in increasing order. */ + +L170: + dlasrt_("I", n, &d__[1], info); + +L180: + return 0; + +/* End of DSTERF */ + +} /* dsterf_ */ + +/* Subroutine */ int dsyevd_(char *jobz, char *uplo, integer *n, doublereal * + a, integer *lda, doublereal *w, doublereal *work, integer *lwork, + integer *iwork, integer *liwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1; + + /* Local variables */ + static doublereal eps; + static integer inde; + static doublereal anrm, rmin, rmax; + static integer lopt; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + static doublereal sigma; + extern logical lsame_(char *, char *); + static integer iinfo, lwmin, liopt; + static logical lower, wantz; + static integer indwk2, llwrk2; + + static integer iscale; + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dstedc_(char *, integer *, + doublereal *, doublereal *, doublereal *, integer *, doublereal *, + integer *, integer *, integer *, integer *), dlacpy_( + char *, integer *, integer *, doublereal *, integer *, doublereal + *, integer *); + static doublereal safmin; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *); + static doublereal bignum; + static integer indtau; + extern /* Subroutine */ int dsterf_(integer *, doublereal *, doublereal *, + integer *); + extern doublereal dlansy_(char *, char *, integer *, doublereal *, + integer *, doublereal *); + static integer indwrk, liwmin; + extern /* Subroutine */ int dormtr_(char *, char *, char *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *, integer *), dsytrd_(char *, integer *, doublereal *, integer *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *, + integer *); + static integer llwork; + static doublereal smlnum; + static logical lquery; + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DSYEVD computes all eigenvalues and, optionally, eigenvectors of a + real symmetric matrix A. If eigenvectors are desired, it uses a + divide and conquer algorithm. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Because of large use of BLAS of level 3, DSYEVD needs N**2 more + workspace than DSYEVX. + + Arguments + ========= + + JOBZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only; + = 'V': Compute eigenvalues and eigenvectors. + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA, N) + On entry, the symmetric matrix A. If UPLO = 'U', the + leading N-by-N upper triangular part of A contains the + upper triangular part of the matrix A. If UPLO = 'L', + the leading N-by-N lower triangular part of A contains + the lower triangular part of the matrix A. + On exit, if JOBZ = 'V', then if INFO = 0, A contains the + orthonormal eigenvectors of the matrix A. + If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') + or the upper triangle (if UPLO='U') of A, including the + diagonal, is destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + W (output) DOUBLE PRECISION array, dimension (N) + If INFO = 0, the eigenvalues in ascending order. + + WORK (workspace/output) DOUBLE PRECISION array, + dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If N <= 1, LWORK must be at least 1. + If JOBZ = 'N' and N > 1, LWORK must be at least 2*N+1. + If JOBZ = 'V' and N > 1, LWORK must be at least + 1 + 6*N + 2*N**2. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal sizes of the WORK and IWORK + arrays, returns these values as the first entries of the WORK + and IWORK arrays, and no error message related to LWORK or + LIWORK is issued by XERBLA. + + IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) + On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. + + LIWORK (input) INTEGER + The dimension of the array IWORK. + If N <= 1, LIWORK must be at least 1. + If JOBZ = 'N' and N > 1, LIWORK must be at least 1. + If JOBZ = 'V' and N > 1, LIWORK must be at least 3 + 5*N. + + If LIWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK and + IWORK arrays, returns these values as the first entries of + the WORK and IWORK arrays, and no error message related to + LWORK or LIWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i and JOBZ = 'N', then the algorithm failed + to converge; i off-diagonal elements of an intermediate + tridiagonal form did not converge to zero; + if INFO = i and JOBZ = 'V', then the algorithm failed + to compute an eigenvalue while working on the submatrix + lying in rows and columns INFO/(N+1) through + mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + Modified description of INFO. Sven, 16 Feb 05. + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --w; + --work; + --iwork; + + /* Function Body */ + wantz = lsame_(jobz, "V"); + lower = lsame_(uplo, "L"); + lquery = *lwork == -1 || *liwork == -1; + + *info = 0; + if (! (wantz || lsame_(jobz, "N"))) { + *info = -1; + } else if (! (lower || lsame_(uplo, "U"))) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + + if (*info == 0) { + if (*n <= 1) { + liwmin = 1; + lwmin = 1; + lopt = lwmin; + liopt = liwmin; + } else { + if (wantz) { + liwmin = *n * 5 + 3; +/* Computing 2nd power */ + i__1 = *n; + lwmin = *n * 6 + 1 + (i__1 * i__1 << 1); + } else { + liwmin = 1; + lwmin = (*n << 1) + 1; + } +/* Computing MAX */ + i__1 = lwmin, i__2 = (*n << 1) + ilaenv_(&c__1, "DSYTRD", uplo, n, + &c_n1, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + lopt = max(i__1,i__2); + liopt = liwmin; + } + work[1] = (doublereal) lopt; + iwork[1] = liopt; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*liwork < liwmin && ! lquery) { + *info = -10; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DSYEVD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (*n == 1) { + w[1] = a[a_dim1 + 1]; + if (wantz) { + a[a_dim1 + 1] = 1.; + } + return 0; + } + +/* Get machine constants. */ + + safmin = SAFEMINIMUM; + eps = PRECISION; + smlnum = safmin / eps; + bignum = 1. / smlnum; + rmin = sqrt(smlnum); + rmax = sqrt(bignum); + +/* Scale matrix to allowable range, if necessary. */ + + anrm = dlansy_("M", uplo, n, &a[a_offset], lda, &work[1]); + iscale = 0; + if (anrm > 0. && anrm < rmin) { + iscale = 1; + sigma = rmin / anrm; + } else if (anrm > rmax) { + iscale = 1; + sigma = rmax / anrm; + } + if (iscale == 1) { + dlascl_(uplo, &c__0, &c__0, &c_b15, &sigma, n, n, &a[a_offset], lda, + info); + } + +/* Call DSYTRD to reduce symmetric matrix to tridiagonal form. */ + + inde = 1; + indtau = inde + *n; + indwrk = indtau + *n; + llwork = *lwork - indwrk + 1; + indwk2 = indwrk + *n * *n; + llwrk2 = *lwork - indwk2 + 1; + + dsytrd_(uplo, n, &a[a_offset], lda, &w[1], &work[inde], &work[indtau], & + work[indwrk], &llwork, &iinfo); + lopt = (integer) ((*n << 1) + work[indwrk]); + +/* + For eigenvalues only, call DSTERF. For eigenvectors, first call + DSTEDC to generate the eigenvector matrix, WORK(INDWRK), of the + tridiagonal matrix, then call DORMTR to multiply it by the + Householder transformations stored in A. +*/ + + if (! wantz) { + dsterf_(n, &w[1], &work[inde], info); + } else { + dstedc_("I", n, &w[1], &work[inde], &work[indwrk], n, &work[indwk2], & + llwrk2, &iwork[1], liwork, info); + dormtr_("L", uplo, "N", n, n, &a[a_offset], lda, &work[indtau], &work[ + indwrk], n, &work[indwk2], &llwrk2, &iinfo); + dlacpy_("A", n, n, &work[indwrk], n, &a[a_offset], lda); +/* + Computing MAX + Computing 2nd power +*/ + i__3 = *n; + i__1 = lopt, i__2 = *n * 6 + 1 + (i__3 * i__3 << 1); + lopt = max(i__1,i__2); + } + +/* If matrix was scaled, then rescale eigenvalues appropriately. */ + + if (iscale == 1) { + d__1 = 1. / sigma; + dscal_(n, &d__1, &w[1], &c__1); + } + + work[1] = (doublereal) lopt; + iwork[1] = liopt; + + return 0; + +/* End of DSYEVD */ + +} /* dsyevd_ */ + +/* Subroutine */ int dsytd2_(char *uplo, integer *n, doublereal *a, integer * + lda, doublereal *d__, doublereal *e, doublereal *tau, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + static doublereal taui; + extern /* Subroutine */ int dsyr2_(char *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + integer *); + static doublereal alpha; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int daxpy_(integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *); + static logical upper; + extern /* Subroutine */ int dsymv_(char *, integer *, doublereal *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *), dlarfg_(integer *, doublereal *, + doublereal *, integer *, doublereal *), xerbla_(char *, integer * + ); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DSYTD2 reduces a real symmetric matrix A to symmetric tridiagonal + form T by an orthogonal similarity transformation: Q' * A * Q = T. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is stored: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + n-by-n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n-by-n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit, if UPLO = 'U', the diagonal and first superdiagonal + of A are overwritten by the corresponding elements of the + tridiagonal matrix T, and the elements above the first + superdiagonal, with the array TAU, represent the orthogonal + matrix Q as a product of elementary reflectors; if UPLO + = 'L', the diagonal and first subdiagonal of A are over- + written by the corresponding elements of the tridiagonal + matrix T, and the elements below the first subdiagonal, with + the array TAU, represent the orthogonal matrix Q as a product + of elementary reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + D (output) DOUBLE PRECISION array, dimension (N) + The diagonal elements of the tridiagonal matrix T: + D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix T: + E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. + + TAU (output) DOUBLE PRECISION array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-1) . . . H(2) H(1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in + A(1:i-1,i+1), and tau in TAU(i). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(n-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v2 v3 v4 ) ( d ) + ( d e v3 v4 ) ( e d ) + ( d e v4 ) ( v1 e d ) + ( d e ) ( v1 v2 e d ) + ( d ) ( v1 v2 v3 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tau; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DSYTD2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + return 0; + } + + if (upper) { + +/* Reduce the upper triangle of A */ + + for (i__ = *n - 1; i__ >= 1; --i__) { + +/* + Generate elementary reflector H(i) = I - tau * v * v' + to annihilate A(1:i-1,i+1) +*/ + + dlarfg_(&i__, &a[i__ + (i__ + 1) * a_dim1], &a[(i__ + 1) * a_dim1 + + 1], &c__1, &taui); + e[i__] = a[i__ + (i__ + 1) * a_dim1]; + + if (taui != 0.) { + +/* Apply H(i) from both sides to A(1:i,1:i) */ + + a[i__ + (i__ + 1) * a_dim1] = 1.; + +/* Compute x := tau * A * v storing x in TAU(1:i) */ + + dsymv_(uplo, &i__, &taui, &a[a_offset], lda, &a[(i__ + 1) * + a_dim1 + 1], &c__1, &c_b29, &tau[1], &c__1) + ; + +/* Compute w := x - 1/2 * tau * (x'*v) * v */ + + alpha = taui * -.5 * ddot_(&i__, &tau[1], &c__1, &a[(i__ + 1) + * a_dim1 + 1], &c__1); + daxpy_(&i__, &alpha, &a[(i__ + 1) * a_dim1 + 1], &c__1, &tau[ + 1], &c__1); + +/* + Apply the transformation as a rank-2 update: + A := A - v * w' - w * v' +*/ + + dsyr2_(uplo, &i__, &c_b151, &a[(i__ + 1) * a_dim1 + 1], &c__1, + &tau[1], &c__1, &a[a_offset], lda); + + a[i__ + (i__ + 1) * a_dim1] = e[i__]; + } + d__[i__ + 1] = a[i__ + 1 + (i__ + 1) * a_dim1]; + tau[i__] = taui; +/* L10: */ + } + d__[1] = a[a_dim1 + 1]; + } else { + +/* Reduce the lower triangle of A */ + + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* + Generate elementary reflector H(i) = I - tau * v * v' + to annihilate A(i+2:n,i) +*/ + + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + dlarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + i__ * + a_dim1], &c__1, &taui); + e[i__] = a[i__ + 1 + i__ * a_dim1]; + + if (taui != 0.) { + +/* Apply H(i) from both sides to A(i+1:n,i+1:n) */ + + a[i__ + 1 + i__ * a_dim1] = 1.; + +/* Compute x := tau * A * v storing y in TAU(i:n-1) */ + + i__2 = *n - i__; + dsymv_(uplo, &i__2, &taui, &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &tau[ + i__], &c__1); + +/* Compute w := x - 1/2 * tau * (x'*v) * v */ + + i__2 = *n - i__; + alpha = taui * -.5 * ddot_(&i__2, &tau[i__], &c__1, &a[i__ + + 1 + i__ * a_dim1], &c__1); + i__2 = *n - i__; + daxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &c__1); + +/* + Apply the transformation as a rank-2 update: + A := A - v * w' - w * v' +*/ + + i__2 = *n - i__; + dsyr2_(uplo, &i__2, &c_b151, &a[i__ + 1 + i__ * a_dim1], & + c__1, &tau[i__], &c__1, &a[i__ + 1 + (i__ + 1) * + a_dim1], lda); + + a[i__ + 1 + i__ * a_dim1] = e[i__]; + } + d__[i__] = a[i__ + i__ * a_dim1]; + tau[i__] = taui; +/* L20: */ + } + d__[*n] = a[*n + *n * a_dim1]; + } + + return 0; + +/* End of DSYTD2 */ + +} /* dsytd2_ */ + +/* Subroutine */ int dsytrd_(char *uplo, integer *n, doublereal *a, integer * + lda, doublereal *d__, doublereal *e, doublereal *tau, doublereal * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, nb, kk, nx, iws; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + static logical upper; + extern /* Subroutine */ int dsytd2_(char *, integer *, doublereal *, + integer *, doublereal *, doublereal *, doublereal *, integer *), dsyr2k_(char *, char *, integer *, integer *, doublereal + *, doublereal *, integer *, doublereal *, integer *, doublereal *, + doublereal *, integer *), dlatrd_(char *, + integer *, integer *, doublereal *, integer *, doublereal *, + doublereal *, doublereal *, integer *), xerbla_(char *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DSYTRD reduces a real symmetric matrix A to real symmetric + tridiagonal form T by an orthogonal similarity transformation: + Q**T * A * Q = T. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit, if UPLO = 'U', the diagonal and first superdiagonal + of A are overwritten by the corresponding elements of the + tridiagonal matrix T, and the elements above the first + superdiagonal, with the array TAU, represent the orthogonal + matrix Q as a product of elementary reflectors; if UPLO + = 'L', the diagonal and first subdiagonal of A are over- + written by the corresponding elements of the tridiagonal + matrix T, and the elements below the first subdiagonal, with + the array TAU, represent the orthogonal matrix Q as a product + of elementary reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + D (output) DOUBLE PRECISION array, dimension (N) + The diagonal elements of the tridiagonal matrix T: + D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix T: + E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. + + TAU (output) DOUBLE PRECISION array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= 1. + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-1) . . . H(2) H(1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in + A(1:i-1,i+1), and tau in TAU(i). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(n-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v2 v3 v4 ) ( d ) + ( d e v3 v4 ) ( e d ) + ( d e v4 ) ( v1 e d ) + ( d e ) ( v1 v2 e d ) + ( d ) ( v1 v2 v3 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tau; + --work; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + lquery = *lwork == -1; + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*lwork < 1 && ! lquery) { + *info = -9; + } + + if (*info == 0) { + +/* Determine the block size. */ + + nb = ilaenv_(&c__1, "DSYTRD", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, + (ftnlen)1); + lwkopt = *n * nb; + work[1] = (doublereal) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("DSYTRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + work[1] = 1.; + return 0; + } + + nx = *n; + iws = 1; + if (nb > 1 && nb < *n) { + +/* + Determine when to cross over from blocked to unblocked code + (last block is always handled by unblocked code). + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "DSYTRD", uplo, n, &c_n1, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *n) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: determine the + minimum value of NB, and reduce NB or force use of + unblocked code by setting NX = N. + + Computing MAX +*/ + i__1 = *lwork / ldwork; + nb = max(i__1,1); + nbmin = ilaenv_(&c__2, "DSYTRD", uplo, n, &c_n1, &c_n1, &c_n1, + (ftnlen)6, (ftnlen)1); + if (nb < nbmin) { + nx = *n; + } + } + } else { + nx = *n; + } + } else { + nb = 1; + } + + if (upper) { + +/* + Reduce the upper triangle of A. + Columns 1:kk are handled by the unblocked method. +*/ + + kk = *n - (*n - nx + nb - 1) / nb * nb; + i__1 = kk + 1; + i__2 = -nb; + for (i__ = *n - nb + 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { + +/* + Reduce columns i:i+nb-1 to tridiagonal form and form the + matrix W which is needed to update the unreduced part of + the matrix +*/ + + i__3 = i__ + nb - 1; + dlatrd_(uplo, &i__3, &nb, &a[a_offset], lda, &e[1], &tau[1], & + work[1], &ldwork); + +/* + Update the unreduced submatrix A(1:i-1,1:i-1), using an + update of the form: A := A - V*W' - W*V' +*/ + + i__3 = i__ - 1; + dsyr2k_(uplo, "No transpose", &i__3, &nb, &c_b151, &a[i__ * + a_dim1 + 1], lda, &work[1], &ldwork, &c_b15, &a[a_offset], + lda); + +/* + Copy superdiagonal elements back into A, and diagonal + elements into D +*/ + + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + a[j - 1 + j * a_dim1] = e[j - 1]; + d__[j] = a[j + j * a_dim1]; +/* L10: */ + } +/* L20: */ + } + +/* Use unblocked code to reduce the last or only block */ + + dsytd2_(uplo, &kk, &a[a_offset], lda, &d__[1], &e[1], &tau[1], &iinfo); + } else { + +/* Reduce the lower triangle of A */ + + i__2 = *n - nx; + i__1 = nb; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { + +/* + Reduce columns i:i+nb-1 to tridiagonal form and form the + matrix W which is needed to update the unreduced part of + the matrix +*/ + + i__3 = *n - i__ + 1; + dlatrd_(uplo, &i__3, &nb, &a[i__ + i__ * a_dim1], lda, &e[i__], & + tau[i__], &work[1], &ldwork); + +/* + Update the unreduced submatrix A(i+ib:n,i+ib:n), using + an update of the form: A := A - V*W' - W*V' +*/ + + i__3 = *n - i__ - nb + 1; + dsyr2k_(uplo, "No transpose", &i__3, &nb, &c_b151, &a[i__ + nb + + i__ * a_dim1], lda, &work[nb + 1], &ldwork, &c_b15, &a[ + i__ + nb + (i__ + nb) * a_dim1], lda); + +/* + Copy subdiagonal elements back into A, and diagonal + elements into D +*/ + + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + a[j + 1 + j * a_dim1] = e[j]; + d__[j] = a[j + j * a_dim1]; +/* L30: */ + } +/* L40: */ + } + +/* Use unblocked code to reduce the last or only block */ + + i__1 = *n - i__ + 1; + dsytd2_(uplo, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], + &tau[i__], &iinfo); + } + + work[1] = (doublereal) lwkopt; + return 0; + +/* End of DSYTRD */ + +} /* dsytrd_ */ + +/* Subroutine */ int dtrevc_(char *side, char *howmny, logical *select, + integer *n, doublereal *t, integer *ldt, doublereal *vl, integer * + ldvl, doublereal *vr, integer *ldvr, integer *mm, integer *m, + doublereal *work, integer *info) +{ + /* System generated locals */ + integer t_dim1, t_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, + i__2, i__3; + doublereal d__1, d__2, d__3, d__4; + + /* Local variables */ + static integer i__, j, k; + static doublereal x[4] /* was [2][2] */; + static integer j1, j2, n2, ii, ki, ip, is; + static doublereal wi, wr, rec, ulp, beta, emax; + static logical pair; + extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *, + integer *); + static logical allv; + static integer ierr; + static doublereal unfl, ovfl, smin; + static logical over; + static doublereal vmax; + static integer jnxt; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + static doublereal scale; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *); + static doublereal remax; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static logical leftv, bothv; + extern /* Subroutine */ int daxpy_(integer *, doublereal *, doublereal *, + integer *, doublereal *, integer *); + static doublereal vcrit; + static logical somev; + static doublereal xnorm; + extern /* Subroutine */ int dlaln2_(logical *, integer *, integer *, + doublereal *, doublereal *, doublereal *, integer *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, doublereal * + , doublereal *, integer *, doublereal *, doublereal *, integer *), + dlabad_(doublereal *, doublereal *); + + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static doublereal bignum; + static logical rightv; + static doublereal smlnum; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DTREVC computes some or all of the right and/or left eigenvectors of + a real upper quasi-triangular matrix T. + Matrices of this type are produced by the Schur factorization of + a real general matrix: A = Q*T*Q**T, as computed by DHSEQR. + + The right eigenvector x and the left eigenvector y of T corresponding + to an eigenvalue w are defined by: + + T*x = w*x, (y**H)*T = w*(y**H) + + where y**H denotes the conjugate transpose of y. + The eigenvalues are not input to this routine, but are read directly + from the diagonal blocks of T. + + This routine returns the matrices X and/or Y of right and left + eigenvectors of T, or the products Q*X and/or Q*Y, where Q is an + input matrix. If Q is the orthogonal factor that reduces a matrix + A to Schur form T, then Q*X and Q*Y are the matrices of right and + left eigenvectors of A. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'R': compute right eigenvectors only; + = 'L': compute left eigenvectors only; + = 'B': compute both right and left eigenvectors. + + HOWMNY (input) CHARACTER*1 + = 'A': compute all right and/or left eigenvectors; + = 'B': compute all right and/or left eigenvectors, + backtransformed by the matrices in VR and/or VL; + = 'S': compute selected right and/or left eigenvectors, + as indicated by the logical array SELECT. + + SELECT (input/output) LOGICAL array, dimension (N) + If HOWMNY = 'S', SELECT specifies the eigenvectors to be + computed. + If w(j) is a real eigenvalue, the corresponding real + eigenvector is computed if SELECT(j) is .TRUE.. + If w(j) and w(j+1) are the real and imaginary parts of a + complex eigenvalue, the corresponding complex eigenvector is + computed if either SELECT(j) or SELECT(j+1) is .TRUE., and + on exit SELECT(j) is set to .TRUE. and SELECT(j+1) is set to + .FALSE.. + Not referenced if HOWMNY = 'A' or 'B'. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input) DOUBLE PRECISION array, dimension (LDT,N) + The upper quasi-triangular matrix T in Schur canonical form. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + VL (input/output) DOUBLE PRECISION array, dimension (LDVL,MM) + On entry, if SIDE = 'L' or 'B' and HOWMNY = 'B', VL must + contain an N-by-N matrix Q (usually the orthogonal matrix Q + of Schur vectors returned by DHSEQR). + On exit, if SIDE = 'L' or 'B', VL contains: + if HOWMNY = 'A', the matrix Y of left eigenvectors of T; + if HOWMNY = 'B', the matrix Q*Y; + if HOWMNY = 'S', the left eigenvectors of T specified by + SELECT, stored consecutively in the columns + of VL, in the same order as their + eigenvalues. + A complex eigenvector corresponding to a complex eigenvalue + is stored in two consecutive columns, the first holding the + real part, and the second the imaginary part. + Not referenced if SIDE = 'R'. + + LDVL (input) INTEGER + The leading dimension of the array VL. LDVL >= 1, and if + SIDE = 'L' or 'B', LDVL >= N. + + VR (input/output) DOUBLE PRECISION array, dimension (LDVR,MM) + On entry, if SIDE = 'R' or 'B' and HOWMNY = 'B', VR must + contain an N-by-N matrix Q (usually the orthogonal matrix Q + of Schur vectors returned by DHSEQR). + On exit, if SIDE = 'R' or 'B', VR contains: + if HOWMNY = 'A', the matrix X of right eigenvectors of T; + if HOWMNY = 'B', the matrix Q*X; + if HOWMNY = 'S', the right eigenvectors of T specified by + SELECT, stored consecutively in the columns + of VR, in the same order as their + eigenvalues. + A complex eigenvector corresponding to a complex eigenvalue + is stored in two consecutive columns, the first holding the + real part and the second the imaginary part. + Not referenced if SIDE = 'L'. + + LDVR (input) INTEGER + The leading dimension of the array VR. LDVR >= 1, and if + SIDE = 'R' or 'B', LDVR >= N. + + MM (input) INTEGER + The number of columns in the arrays VL and/or VR. MM >= M. + + M (output) INTEGER + The number of columns in the arrays VL and/or VR actually + used to store the eigenvectors. + If HOWMNY = 'A' or 'B', M is set to N. + Each selected real eigenvector occupies one column and each + selected complex eigenvector occupies two columns. + + WORK (workspace) DOUBLE PRECISION array, dimension (3*N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The algorithm used in this program is basically backward (forward) + substitution, with scaling to make the the code robust against + possible overflow. + + Each eigenvector is normalized so that the element of largest + magnitude has magnitude 1; here the magnitude of a complex number + (x,y) is taken to be |x| + |y|. + + ===================================================================== + + + Decode and test the input parameters +*/ + + /* Parameter adjustments */ + --select; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + vl_dim1 = *ldvl; + vl_offset = 1 + vl_dim1; + vl -= vl_offset; + vr_dim1 = *ldvr; + vr_offset = 1 + vr_dim1; + vr -= vr_offset; + --work; + + /* Function Body */ + bothv = lsame_(side, "B"); + rightv = lsame_(side, "R") || bothv; + leftv = lsame_(side, "L") || bothv; + + allv = lsame_(howmny, "A"); + over = lsame_(howmny, "B"); + somev = lsame_(howmny, "S"); + + *info = 0; + if (! rightv && ! leftv) { + *info = -1; + } else if (! allv && ! over && ! somev) { + *info = -2; + } else if (*n < 0) { + *info = -4; + } else if (*ldt < max(1,*n)) { + *info = -6; + } else if (*ldvl < 1 || leftv && *ldvl < *n) { + *info = -8; + } else if (*ldvr < 1 || rightv && *ldvr < *n) { + *info = -10; + } else { + +/* + Set M to the number of columns required to store the selected + eigenvectors, standardize the array SELECT if necessary, and + test MM. +*/ + + if (somev) { + *m = 0; + pair = FALSE_; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (pair) { + pair = FALSE_; + select[j] = FALSE_; + } else { + if (j < *n) { + if (t[j + 1 + j * t_dim1] == 0.) { + if (select[j]) { + ++(*m); + } + } else { + pair = TRUE_; + if (select[j] || select[j + 1]) { + select[j] = TRUE_; + *m += 2; + } + } + } else { + if (select[*n]) { + ++(*m); + } + } + } +/* L10: */ + } + } else { + *m = *n; + } + + if (*mm < *m) { + *info = -11; + } + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DTREVC", &i__1); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + +/* Set the constants to control overflow. */ + + unfl = SAFEMINIMUM; + ovfl = 1. / unfl; + dlabad_(&unfl, &ovfl); + ulp = PRECISION; + smlnum = unfl * (*n / ulp); + bignum = (1. - ulp) / smlnum; + +/* + Compute 1-norm of each column of strictly upper triangular + part of T to control overflow in triangular solver. +*/ + + work[1] = 0.; + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + work[j] = 0.; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + work[j] += (d__1 = t[i__ + j * t_dim1], abs(d__1)); +/* L20: */ + } +/* L30: */ + } + +/* + Index IP is used to specify the real or complex eigenvalue: + IP = 0, real eigenvalue, + 1, first of conjugate complex pair: (wr,wi) + -1, second of conjugate complex pair: (wr,wi) +*/ + + n2 = *n << 1; + + if (rightv) { + +/* Compute right eigenvectors. */ + + ip = 0; + is = *m; + for (ki = *n; ki >= 1; --ki) { + + if (ip == 1) { + goto L130; + } + if (ki == 1) { + goto L40; + } + if (t[ki + (ki - 1) * t_dim1] == 0.) { + goto L40; + } + ip = -1; + +L40: + if (somev) { + if (ip == 0) { + if (! select[ki]) { + goto L130; + } + } else { + if (! select[ki - 1]) { + goto L130; + } + } + } + +/* Compute the KI-th eigenvalue (WR,WI). */ + + wr = t[ki + ki * t_dim1]; + wi = 0.; + if (ip != 0) { + wi = sqrt((d__1 = t[ki + (ki - 1) * t_dim1], abs(d__1))) * + sqrt((d__2 = t[ki - 1 + ki * t_dim1], abs(d__2))); + } +/* Computing MAX */ + d__1 = ulp * (abs(wr) + abs(wi)); + smin = max(d__1,smlnum); + + if (ip == 0) { + +/* Real right eigenvector */ + + work[ki + *n] = 1.; + +/* Form right-hand side */ + + i__1 = ki - 1; + for (k = 1; k <= i__1; ++k) { + work[k + *n] = -t[k + ki * t_dim1]; +/* L50: */ + } + +/* + Solve the upper quasi-triangular system: + (T(1:KI-1,1:KI-1) - WR)*X = SCALE*WORK. +*/ + + jnxt = ki - 1; + for (j = ki - 1; j >= 1; --j) { + if (j > jnxt) { + goto L60; + } + j1 = j; + j2 = j; + jnxt = j - 1; + if (j > 1) { + if (t[j + (j - 1) * t_dim1] != 0.) { + j1 = j - 1; + jnxt = j - 2; + } + } + + if (j1 == j2) { + +/* 1-by-1 diagonal block */ + + dlaln2_(&c_false, &c__1, &c__1, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &c_b29, x, &c__2, &scale, &xnorm, + &ierr); + +/* + Scale X(1,1) to avoid overflow when updating + the right-hand side. +*/ + + if (xnorm > 1.) { + if (work[j] > bignum / xnorm) { + x[0] /= xnorm; + scale /= xnorm; + } + } + +/* Scale if necessary */ + + if (scale != 1.) { + dscal_(&ki, &scale, &work[*n + 1], &c__1); + } + work[j + *n] = x[0]; + +/* Update right-hand side */ + + i__1 = j - 1; + d__1 = -x[0]; + daxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[ + *n + 1], &c__1); + + } else { + +/* 2-by-2 diagonal block */ + + dlaln2_(&c_false, &c__2, &c__1, &smin, &c_b15, &t[j - + 1 + (j - 1) * t_dim1], ldt, &c_b15, &c_b15, & + work[j - 1 + *n], n, &wr, &c_b29, x, &c__2, & + scale, &xnorm, &ierr); + +/* + Scale X(1,1) and X(2,1) to avoid overflow when + updating the right-hand side. +*/ + + if (xnorm > 1.) { +/* Computing MAX */ + d__1 = work[j - 1], d__2 = work[j]; + beta = max(d__1,d__2); + if (beta > bignum / xnorm) { + x[0] /= xnorm; + x[1] /= xnorm; + scale /= xnorm; + } + } + +/* Scale if necessary */ + + if (scale != 1.) { + dscal_(&ki, &scale, &work[*n + 1], &c__1); + } + work[j - 1 + *n] = x[0]; + work[j + *n] = x[1]; + +/* Update right-hand side */ + + i__1 = j - 2; + d__1 = -x[0]; + daxpy_(&i__1, &d__1, &t[(j - 1) * t_dim1 + 1], &c__1, + &work[*n + 1], &c__1); + i__1 = j - 2; + d__1 = -x[1]; + daxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[ + *n + 1], &c__1); + } +L60: + ; + } + +/* Copy the vector x or Q*x to VR and normalize. */ + + if (! over) { + dcopy_(&ki, &work[*n + 1], &c__1, &vr[is * vr_dim1 + 1], & + c__1); + + ii = idamax_(&ki, &vr[is * vr_dim1 + 1], &c__1); + remax = 1. / (d__1 = vr[ii + is * vr_dim1], abs(d__1)); + dscal_(&ki, &remax, &vr[is * vr_dim1 + 1], &c__1); + + i__1 = *n; + for (k = ki + 1; k <= i__1; ++k) { + vr[k + is * vr_dim1] = 0.; +/* L70: */ + } + } else { + if (ki > 1) { + i__1 = ki - 1; + dgemv_("N", n, &i__1, &c_b15, &vr[vr_offset], ldvr, & + work[*n + 1], &c__1, &work[ki + *n], &vr[ki * + vr_dim1 + 1], &c__1); + } + + ii = idamax_(n, &vr[ki * vr_dim1 + 1], &c__1); + remax = 1. / (d__1 = vr[ii + ki * vr_dim1], abs(d__1)); + dscal_(n, &remax, &vr[ki * vr_dim1 + 1], &c__1); + } + + } else { + +/* + Complex right eigenvector. + + Initial solve + [ (T(KI-1,KI-1) T(KI-1,KI) ) - (WR + I* WI)]*X = 0. + [ (T(KI,KI-1) T(KI,KI) ) ] +*/ + + if ((d__1 = t[ki - 1 + ki * t_dim1], abs(d__1)) >= (d__2 = t[ + ki + (ki - 1) * t_dim1], abs(d__2))) { + work[ki - 1 + *n] = 1.; + work[ki + n2] = wi / t[ki - 1 + ki * t_dim1]; + } else { + work[ki - 1 + *n] = -wi / t[ki + (ki - 1) * t_dim1]; + work[ki + n2] = 1.; + } + work[ki + *n] = 0.; + work[ki - 1 + n2] = 0.; + +/* Form right-hand side */ + + i__1 = ki - 2; + for (k = 1; k <= i__1; ++k) { + work[k + *n] = -work[ki - 1 + *n] * t[k + (ki - 1) * + t_dim1]; + work[k + n2] = -work[ki + n2] * t[k + ki * t_dim1]; +/* L80: */ + } + +/* + Solve upper quasi-triangular system: + (T(1:KI-2,1:KI-2) - (WR+i*WI))*X = SCALE*(WORK+i*WORK2) +*/ + + jnxt = ki - 2; + for (j = ki - 2; j >= 1; --j) { + if (j > jnxt) { + goto L90; + } + j1 = j; + j2 = j; + jnxt = j - 1; + if (j > 1) { + if (t[j + (j - 1) * t_dim1] != 0.) { + j1 = j - 1; + jnxt = j - 2; + } + } + + if (j1 == j2) { + +/* 1-by-1 diagonal block */ + + dlaln2_(&c_false, &c__1, &c__2, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &wi, x, &c__2, &scale, &xnorm, & + ierr); + +/* + Scale X(1,1) and X(1,2) to avoid overflow when + updating the right-hand side. +*/ + + if (xnorm > 1.) { + if (work[j] > bignum / xnorm) { + x[0] /= xnorm; + x[2] /= xnorm; + scale /= xnorm; + } + } + +/* Scale if necessary */ + + if (scale != 1.) { + dscal_(&ki, &scale, &work[*n + 1], &c__1); + dscal_(&ki, &scale, &work[n2 + 1], &c__1); + } + work[j + *n] = x[0]; + work[j + n2] = x[2]; + +/* Update the right-hand side */ + + i__1 = j - 1; + d__1 = -x[0]; + daxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[ + *n + 1], &c__1); + i__1 = j - 1; + d__1 = -x[2]; + daxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[ + n2 + 1], &c__1); + + } else { + +/* 2-by-2 diagonal block */ + + dlaln2_(&c_false, &c__2, &c__2, &smin, &c_b15, &t[j - + 1 + (j - 1) * t_dim1], ldt, &c_b15, &c_b15, & + work[j - 1 + *n], n, &wr, &wi, x, &c__2, & + scale, &xnorm, &ierr); + +/* + Scale X to avoid overflow when updating + the right-hand side. +*/ + + if (xnorm > 1.) { +/* Computing MAX */ + d__1 = work[j - 1], d__2 = work[j]; + beta = max(d__1,d__2); + if (beta > bignum / xnorm) { + rec = 1. / xnorm; + x[0] *= rec; + x[2] *= rec; + x[1] *= rec; + x[3] *= rec; + scale *= rec; + } + } + +/* Scale if necessary */ + + if (scale != 1.) { + dscal_(&ki, &scale, &work[*n + 1], &c__1); + dscal_(&ki, &scale, &work[n2 + 1], &c__1); + } + work[j - 1 + *n] = x[0]; + work[j + *n] = x[1]; + work[j - 1 + n2] = x[2]; + work[j + n2] = x[3]; + +/* Update the right-hand side */ + + i__1 = j - 2; + d__1 = -x[0]; + daxpy_(&i__1, &d__1, &t[(j - 1) * t_dim1 + 1], &c__1, + &work[*n + 1], &c__1); + i__1 = j - 2; + d__1 = -x[1]; + daxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[ + *n + 1], &c__1); + i__1 = j - 2; + d__1 = -x[2]; + daxpy_(&i__1, &d__1, &t[(j - 1) * t_dim1 + 1], &c__1, + &work[n2 + 1], &c__1); + i__1 = j - 2; + d__1 = -x[3]; + daxpy_(&i__1, &d__1, &t[j * t_dim1 + 1], &c__1, &work[ + n2 + 1], &c__1); + } +L90: + ; + } + +/* Copy the vector x or Q*x to VR and normalize. */ + + if (! over) { + dcopy_(&ki, &work[*n + 1], &c__1, &vr[(is - 1) * vr_dim1 + + 1], &c__1); + dcopy_(&ki, &work[n2 + 1], &c__1, &vr[is * vr_dim1 + 1], & + c__1); + + emax = 0.; + i__1 = ki; + for (k = 1; k <= i__1; ++k) { +/* Computing MAX */ + d__3 = emax, d__4 = (d__1 = vr[k + (is - 1) * vr_dim1] + , abs(d__1)) + (d__2 = vr[k + is * vr_dim1], + abs(d__2)); + emax = max(d__3,d__4); +/* L100: */ + } + + remax = 1. / emax; + dscal_(&ki, &remax, &vr[(is - 1) * vr_dim1 + 1], &c__1); + dscal_(&ki, &remax, &vr[is * vr_dim1 + 1], &c__1); + + i__1 = *n; + for (k = ki + 1; k <= i__1; ++k) { + vr[k + (is - 1) * vr_dim1] = 0.; + vr[k + is * vr_dim1] = 0.; +/* L110: */ + } + + } else { + + if (ki > 2) { + i__1 = ki - 2; + dgemv_("N", n, &i__1, &c_b15, &vr[vr_offset], ldvr, & + work[*n + 1], &c__1, &work[ki - 1 + *n], &vr[( + ki - 1) * vr_dim1 + 1], &c__1); + i__1 = ki - 2; + dgemv_("N", n, &i__1, &c_b15, &vr[vr_offset], ldvr, & + work[n2 + 1], &c__1, &work[ki + n2], &vr[ki * + vr_dim1 + 1], &c__1); + } else { + dscal_(n, &work[ki - 1 + *n], &vr[(ki - 1) * vr_dim1 + + 1], &c__1); + dscal_(n, &work[ki + n2], &vr[ki * vr_dim1 + 1], & + c__1); + } + + emax = 0.; + i__1 = *n; + for (k = 1; k <= i__1; ++k) { +/* Computing MAX */ + d__3 = emax, d__4 = (d__1 = vr[k + (ki - 1) * vr_dim1] + , abs(d__1)) + (d__2 = vr[k + ki * vr_dim1], + abs(d__2)); + emax = max(d__3,d__4); +/* L120: */ + } + remax = 1. / emax; + dscal_(n, &remax, &vr[(ki - 1) * vr_dim1 + 1], &c__1); + dscal_(n, &remax, &vr[ki * vr_dim1 + 1], &c__1); + } + } + + --is; + if (ip != 0) { + --is; + } +L130: + if (ip == 1) { + ip = 0; + } + if (ip == -1) { + ip = 1; + } +/* L140: */ + } + } + + if (leftv) { + +/* Compute left eigenvectors. */ + + ip = 0; + is = 1; + i__1 = *n; + for (ki = 1; ki <= i__1; ++ki) { + + if (ip == -1) { + goto L250; + } + if (ki == *n) { + goto L150; + } + if (t[ki + 1 + ki * t_dim1] == 0.) { + goto L150; + } + ip = 1; + +L150: + if (somev) { + if (! select[ki]) { + goto L250; + } + } + +/* Compute the KI-th eigenvalue (WR,WI). */ + + wr = t[ki + ki * t_dim1]; + wi = 0.; + if (ip != 0) { + wi = sqrt((d__1 = t[ki + (ki + 1) * t_dim1], abs(d__1))) * + sqrt((d__2 = t[ki + 1 + ki * t_dim1], abs(d__2))); + } +/* Computing MAX */ + d__1 = ulp * (abs(wr) + abs(wi)); + smin = max(d__1,smlnum); + + if (ip == 0) { + +/* Real left eigenvector. */ + + work[ki + *n] = 1.; + +/* Form right-hand side */ + + i__2 = *n; + for (k = ki + 1; k <= i__2; ++k) { + work[k + *n] = -t[ki + k * t_dim1]; +/* L160: */ + } + +/* + Solve the quasi-triangular system: + (T(KI+1:N,KI+1:N) - WR)'*X = SCALE*WORK +*/ + + vmax = 1.; + vcrit = bignum; + + jnxt = ki + 1; + i__2 = *n; + for (j = ki + 1; j <= i__2; ++j) { + if (j < jnxt) { + goto L170; + } + j1 = j; + j2 = j; + jnxt = j + 1; + if (j < *n) { + if (t[j + 1 + j * t_dim1] != 0.) { + j2 = j + 1; + jnxt = j + 2; + } + } + + if (j1 == j2) { + +/* + 1-by-1 diagonal block + + Scale if necessary to avoid overflow when forming + the right-hand side. +*/ + + if (work[j] > vcrit) { + rec = 1. / vmax; + i__3 = *n - ki + 1; + dscal_(&i__3, &rec, &work[ki + *n], &c__1); + vmax = 1.; + vcrit = bignum; + } + + i__3 = j - ki - 1; + work[j + *n] -= ddot_(&i__3, &t[ki + 1 + j * t_dim1], + &c__1, &work[ki + 1 + *n], &c__1); + +/* Solve (T(J,J)-WR)'*X = WORK */ + + dlaln2_(&c_false, &c__1, &c__1, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &c_b29, x, &c__2, &scale, &xnorm, + &ierr); + +/* Scale if necessary */ + + if (scale != 1.) { + i__3 = *n - ki + 1; + dscal_(&i__3, &scale, &work[ki + *n], &c__1); + } + work[j + *n] = x[0]; +/* Computing MAX */ + d__2 = (d__1 = work[j + *n], abs(d__1)); + vmax = max(d__2,vmax); + vcrit = bignum / vmax; + + } else { + +/* + 2-by-2 diagonal block + + Scale if necessary to avoid overflow when forming + the right-hand side. + + Computing MAX +*/ + d__1 = work[j], d__2 = work[j + 1]; + beta = max(d__1,d__2); + if (beta > vcrit) { + rec = 1. / vmax; + i__3 = *n - ki + 1; + dscal_(&i__3, &rec, &work[ki + *n], &c__1); + vmax = 1.; + vcrit = bignum; + } + + i__3 = j - ki - 1; + work[j + *n] -= ddot_(&i__3, &t[ki + 1 + j * t_dim1], + &c__1, &work[ki + 1 + *n], &c__1); + + i__3 = j - ki - 1; + work[j + 1 + *n] -= ddot_(&i__3, &t[ki + 1 + (j + 1) * + t_dim1], &c__1, &work[ki + 1 + *n], &c__1); + +/* + Solve + [T(J,J)-WR T(J,J+1) ]'* X = SCALE*( WORK1 ) + [T(J+1,J) T(J+1,J+1)-WR] ( WORK2 ) +*/ + + dlaln2_(&c_true, &c__2, &c__1, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &c_b29, x, &c__2, &scale, &xnorm, + &ierr); + +/* Scale if necessary */ + + if (scale != 1.) { + i__3 = *n - ki + 1; + dscal_(&i__3, &scale, &work[ki + *n], &c__1); + } + work[j + *n] = x[0]; + work[j + 1 + *n] = x[1]; + +/* Computing MAX */ + d__3 = (d__1 = work[j + *n], abs(d__1)), d__4 = (d__2 + = work[j + 1 + *n], abs(d__2)), d__3 = max( + d__3,d__4); + vmax = max(d__3,vmax); + vcrit = bignum / vmax; + + } +L170: + ; + } + +/* Copy the vector x or Q*x to VL and normalize. */ + + if (! over) { + i__2 = *n - ki + 1; + dcopy_(&i__2, &work[ki + *n], &c__1, &vl[ki + is * + vl_dim1], &c__1); + + i__2 = *n - ki + 1; + ii = idamax_(&i__2, &vl[ki + is * vl_dim1], &c__1) + ki - + 1; + remax = 1. / (d__1 = vl[ii + is * vl_dim1], abs(d__1)); + i__2 = *n - ki + 1; + dscal_(&i__2, &remax, &vl[ki + is * vl_dim1], &c__1); + + i__2 = ki - 1; + for (k = 1; k <= i__2; ++k) { + vl[k + is * vl_dim1] = 0.; +/* L180: */ + } + + } else { + + if (ki < *n) { + i__2 = *n - ki; + dgemv_("N", n, &i__2, &c_b15, &vl[(ki + 1) * vl_dim1 + + 1], ldvl, &work[ki + 1 + *n], &c__1, &work[ + ki + *n], &vl[ki * vl_dim1 + 1], &c__1); + } + + ii = idamax_(n, &vl[ki * vl_dim1 + 1], &c__1); + remax = 1. / (d__1 = vl[ii + ki * vl_dim1], abs(d__1)); + dscal_(n, &remax, &vl[ki * vl_dim1 + 1], &c__1); + + } + + } else { + +/* + Complex left eigenvector. + + Initial solve: + ((T(KI,KI) T(KI,KI+1) )' - (WR - I* WI))*X = 0. + ((T(KI+1,KI) T(KI+1,KI+1)) ) +*/ + + if ((d__1 = t[ki + (ki + 1) * t_dim1], abs(d__1)) >= (d__2 = + t[ki + 1 + ki * t_dim1], abs(d__2))) { + work[ki + *n] = wi / t[ki + (ki + 1) * t_dim1]; + work[ki + 1 + n2] = 1.; + } else { + work[ki + *n] = 1.; + work[ki + 1 + n2] = -wi / t[ki + 1 + ki * t_dim1]; + } + work[ki + 1 + *n] = 0.; + work[ki + n2] = 0.; + +/* Form right-hand side */ + + i__2 = *n; + for (k = ki + 2; k <= i__2; ++k) { + work[k + *n] = -work[ki + *n] * t[ki + k * t_dim1]; + work[k + n2] = -work[ki + 1 + n2] * t[ki + 1 + k * t_dim1] + ; +/* L190: */ + } + +/* + Solve complex quasi-triangular system: + ( T(KI+2,N:KI+2,N) - (WR-i*WI) )*X = WORK1+i*WORK2 +*/ + + vmax = 1.; + vcrit = bignum; + + jnxt = ki + 2; + i__2 = *n; + for (j = ki + 2; j <= i__2; ++j) { + if (j < jnxt) { + goto L200; + } + j1 = j; + j2 = j; + jnxt = j + 1; + if (j < *n) { + if (t[j + 1 + j * t_dim1] != 0.) { + j2 = j + 1; + jnxt = j + 2; + } + } + + if (j1 == j2) { + +/* + 1-by-1 diagonal block + + Scale if necessary to avoid overflow when + forming the right-hand side elements. +*/ + + if (work[j] > vcrit) { + rec = 1. / vmax; + i__3 = *n - ki + 1; + dscal_(&i__3, &rec, &work[ki + *n], &c__1); + i__3 = *n - ki + 1; + dscal_(&i__3, &rec, &work[ki + n2], &c__1); + vmax = 1.; + vcrit = bignum; + } + + i__3 = j - ki - 2; + work[j + *n] -= ddot_(&i__3, &t[ki + 2 + j * t_dim1], + &c__1, &work[ki + 2 + *n], &c__1); + i__3 = j - ki - 2; + work[j + n2] -= ddot_(&i__3, &t[ki + 2 + j * t_dim1], + &c__1, &work[ki + 2 + n2], &c__1); + +/* Solve (T(J,J)-(WR-i*WI))*(X11+i*X12)= WK+I*WK2 */ + + d__1 = -wi; + dlaln2_(&c_false, &c__1, &c__2, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &d__1, x, &c__2, &scale, &xnorm, & + ierr); + +/* Scale if necessary */ + + if (scale != 1.) { + i__3 = *n - ki + 1; + dscal_(&i__3, &scale, &work[ki + *n], &c__1); + i__3 = *n - ki + 1; + dscal_(&i__3, &scale, &work[ki + n2], &c__1); + } + work[j + *n] = x[0]; + work[j + n2] = x[2]; +/* Computing MAX */ + d__3 = (d__1 = work[j + *n], abs(d__1)), d__4 = (d__2 + = work[j + n2], abs(d__2)), d__3 = max(d__3, + d__4); + vmax = max(d__3,vmax); + vcrit = bignum / vmax; + + } else { + +/* + 2-by-2 diagonal block + + Scale if necessary to avoid overflow when forming + the right-hand side elements. + + Computing MAX +*/ + d__1 = work[j], d__2 = work[j + 1]; + beta = max(d__1,d__2); + if (beta > vcrit) { + rec = 1. / vmax; + i__3 = *n - ki + 1; + dscal_(&i__3, &rec, &work[ki + *n], &c__1); + i__3 = *n - ki + 1; + dscal_(&i__3, &rec, &work[ki + n2], &c__1); + vmax = 1.; + vcrit = bignum; + } + + i__3 = j - ki - 2; + work[j + *n] -= ddot_(&i__3, &t[ki + 2 + j * t_dim1], + &c__1, &work[ki + 2 + *n], &c__1); + + i__3 = j - ki - 2; + work[j + n2] -= ddot_(&i__3, &t[ki + 2 + j * t_dim1], + &c__1, &work[ki + 2 + n2], &c__1); + + i__3 = j - ki - 2; + work[j + 1 + *n] -= ddot_(&i__3, &t[ki + 2 + (j + 1) * + t_dim1], &c__1, &work[ki + 2 + *n], &c__1); + + i__3 = j - ki - 2; + work[j + 1 + n2] -= ddot_(&i__3, &t[ki + 2 + (j + 1) * + t_dim1], &c__1, &work[ki + 2 + n2], &c__1); + +/* + Solve 2-by-2 complex linear equation + ([T(j,j) T(j,j+1) ]'-(wr-i*wi)*I)*X = SCALE*B + ([T(j+1,j) T(j+1,j+1)] ) +*/ + + d__1 = -wi; + dlaln2_(&c_true, &c__2, &c__2, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &d__1, x, &c__2, &scale, &xnorm, & + ierr); + +/* Scale if necessary */ + + if (scale != 1.) { + i__3 = *n - ki + 1; + dscal_(&i__3, &scale, &work[ki + *n], &c__1); + i__3 = *n - ki + 1; + dscal_(&i__3, &scale, &work[ki + n2], &c__1); + } + work[j + *n] = x[0]; + work[j + n2] = x[2]; + work[j + 1 + *n] = x[1]; + work[j + 1 + n2] = x[3]; +/* Computing MAX */ + d__1 = abs(x[0]), d__2 = abs(x[2]), d__1 = max(d__1, + d__2), d__2 = abs(x[1]), d__1 = max(d__1,d__2) + , d__2 = abs(x[3]), d__1 = max(d__1,d__2); + vmax = max(d__1,vmax); + vcrit = bignum / vmax; + + } +L200: + ; + } + +/* Copy the vector x or Q*x to VL and normalize. */ + + if (! over) { + i__2 = *n - ki + 1; + dcopy_(&i__2, &work[ki + *n], &c__1, &vl[ki + is * + vl_dim1], &c__1); + i__2 = *n - ki + 1; + dcopy_(&i__2, &work[ki + n2], &c__1, &vl[ki + (is + 1) * + vl_dim1], &c__1); + + emax = 0.; + i__2 = *n; + for (k = ki; k <= i__2; ++k) { +/* Computing MAX */ + d__3 = emax, d__4 = (d__1 = vl[k + is * vl_dim1], abs( + d__1)) + (d__2 = vl[k + (is + 1) * vl_dim1], + abs(d__2)); + emax = max(d__3,d__4); +/* L220: */ + } + remax = 1. / emax; + i__2 = *n - ki + 1; + dscal_(&i__2, &remax, &vl[ki + is * vl_dim1], &c__1); + i__2 = *n - ki + 1; + dscal_(&i__2, &remax, &vl[ki + (is + 1) * vl_dim1], &c__1) + ; + + i__2 = ki - 1; + for (k = 1; k <= i__2; ++k) { + vl[k + is * vl_dim1] = 0.; + vl[k + (is + 1) * vl_dim1] = 0.; +/* L230: */ + } + } else { + if (ki < *n - 1) { + i__2 = *n - ki - 1; + dgemv_("N", n, &i__2, &c_b15, &vl[(ki + 2) * vl_dim1 + + 1], ldvl, &work[ki + 2 + *n], &c__1, &work[ + ki + *n], &vl[ki * vl_dim1 + 1], &c__1); + i__2 = *n - ki - 1; + dgemv_("N", n, &i__2, &c_b15, &vl[(ki + 2) * vl_dim1 + + 1], ldvl, &work[ki + 2 + n2], &c__1, &work[ + ki + 1 + n2], &vl[(ki + 1) * vl_dim1 + 1], & + c__1); + } else { + dscal_(n, &work[ki + *n], &vl[ki * vl_dim1 + 1], & + c__1); + dscal_(n, &work[ki + 1 + n2], &vl[(ki + 1) * vl_dim1 + + 1], &c__1); + } + + emax = 0.; + i__2 = *n; + for (k = 1; k <= i__2; ++k) { +/* Computing MAX */ + d__3 = emax, d__4 = (d__1 = vl[k + ki * vl_dim1], abs( + d__1)) + (d__2 = vl[k + (ki + 1) * vl_dim1], + abs(d__2)); + emax = max(d__3,d__4); +/* L240: */ + } + remax = 1. / emax; + dscal_(n, &remax, &vl[ki * vl_dim1 + 1], &c__1); + dscal_(n, &remax, &vl[(ki + 1) * vl_dim1 + 1], &c__1); + + } + + } + + ++is; + if (ip != 0) { + ++is; + } +L250: + if (ip == -1) { + ip = 0; + } + if (ip == 1) { + ip = -1; + } + +/* L260: */ + } + + } + + return 0; + +/* End of DTREVC */ + +} /* dtrevc_ */ + +/* Subroutine */ int dtrexc_(char *compq, integer *n, doublereal *t, integer * + ldt, doublereal *q, integer *ldq, integer *ifst, integer *ilst, + doublereal *work, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, t_dim1, t_offset, i__1; + + /* Local variables */ + static integer nbf, nbl, here; + extern logical lsame_(char *, char *); + static logical wantq; + extern /* Subroutine */ int dlaexc_(logical *, integer *, doublereal *, + integer *, doublereal *, integer *, integer *, integer *, integer + *, doublereal *, integer *), xerbla_(char *, integer *); + static integer nbnext; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DTREXC reorders the real Schur factorization of a real matrix + A = Q*T*Q**T, so that the diagonal block of T with row index IFST is + moved to row ILST. + + The real Schur form T is reordered by an orthogonal similarity + transformation Z**T*T*Z, and optionally the matrix Q of Schur vectors + is updated by postmultiplying it with Z. + + T must be in Schur canonical form (as returned by DHSEQR), that is, + block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each + 2-by-2 diagonal block has its diagonal elements equal and its + off-diagonal elements of opposite sign. + + Arguments + ========= + + COMPQ (input) CHARACTER*1 + = 'V': update the matrix Q of Schur vectors; + = 'N': do not update Q. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input/output) DOUBLE PRECISION array, dimension (LDT,N) + On entry, the upper quasi-triangular matrix T, in Schur + Schur canonical form. + On exit, the reordered upper quasi-triangular matrix, again + in Schur canonical form. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + Q (input/output) DOUBLE PRECISION array, dimension (LDQ,N) + On entry, if COMPQ = 'V', the matrix Q of Schur vectors. + On exit, if COMPQ = 'V', Q has been postmultiplied by the + orthogonal transformation matrix Z which reorders T. + If COMPQ = 'N', Q is not referenced. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + IFST (input/output) INTEGER + ILST (input/output) INTEGER + Specify the reordering of the diagonal blocks of T. + The block with row index IFST is moved to row ILST, by a + sequence of transpositions between adjacent blocks. + On exit, if IFST pointed on entry to the second row of a + 2-by-2 block, it is changed to point to the first row; ILST + always points to the first row of the block in its final + position (which may differ from its input value by +1 or -1). + 1 <= IFST <= N; 1 <= ILST <= N. + + WORK (workspace) DOUBLE PRECISION array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + = 1: two adjacent blocks were too close to swap (the problem + is very ill-conditioned); T may have been partially + reordered, and ILST points to the first row of the + current position of the block being moved. + + ===================================================================== + + + Decode and test the input arguments. +*/ + + /* Parameter adjustments */ + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --work; + + /* Function Body */ + *info = 0; + wantq = lsame_(compq, "V"); + if (! wantq && ! lsame_(compq, "N")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldt < max(1,*n)) { + *info = -4; + } else if (*ldq < 1 || wantq && *ldq < max(1,*n)) { + *info = -6; + } else if (*ifst < 1 || *ifst > *n) { + *info = -7; + } else if (*ilst < 1 || *ilst > *n) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DTREXC", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 1) { + return 0; + } + +/* + Determine the first row of specified block + and find out it is 1 by 1 or 2 by 2. +*/ + + if (*ifst > 1) { + if (t[*ifst + (*ifst - 1) * t_dim1] != 0.) { + --(*ifst); + } + } + nbf = 1; + if (*ifst < *n) { + if (t[*ifst + 1 + *ifst * t_dim1] != 0.) { + nbf = 2; + } + } + +/* + Determine the first row of the final block + and find out it is 1 by 1 or 2 by 2. +*/ + + if (*ilst > 1) { + if (t[*ilst + (*ilst - 1) * t_dim1] != 0.) { + --(*ilst); + } + } + nbl = 1; + if (*ilst < *n) { + if (t[*ilst + 1 + *ilst * t_dim1] != 0.) { + nbl = 2; + } + } + + if (*ifst == *ilst) { + return 0; + } + + if (*ifst < *ilst) { + +/* Update ILST */ + + if (nbf == 2 && nbl == 1) { + --(*ilst); + } + if (nbf == 1 && nbl == 2) { + ++(*ilst); + } + + here = *ifst; + +L10: + +/* Swap block with next one below */ + + if (nbf == 1 || nbf == 2) { + +/* Current block either 1 by 1 or 2 by 2 */ + + nbnext = 1; + if (here + nbf + 1 <= *n) { + if (t[here + nbf + 1 + (here + nbf) * t_dim1] != 0.) { + nbnext = 2; + } + } + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &here, & + nbf, &nbnext, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + here += nbnext; + +/* Test if 2 by 2 block breaks into two 1 by 1 blocks */ + + if (nbf == 2) { + if (t[here + 1 + here * t_dim1] == 0.) { + nbf = 3; + } + } + + } else { + +/* + Current block consists of two 1 by 1 blocks each of which + must be swapped individually +*/ + + nbnext = 1; + if (here + 3 <= *n) { + if (t[here + 3 + (here + 2) * t_dim1] != 0.) { + nbnext = 2; + } + } + i__1 = here + 1; + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, & + c__1, &nbnext, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + if (nbnext == 1) { + +/* Swap two 1 by 1 blocks, no problems possible */ + + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &c__1, &nbnext, &work[1], info); + ++here; + } else { + +/* Recompute NBNEXT in case 2 by 2 split */ + + if (t[here + 2 + (here + 1) * t_dim1] == 0.) { + nbnext = 1; + } + if (nbnext == 2) { + +/* 2 by 2 Block did not split */ + + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &c__1, &nbnext, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + here += 2; + } else { + +/* 2 by 2 Block did split */ + + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &c__1, &c__1, &work[1], info); + i__1 = here + 1; + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + i__1, &c__1, &c__1, &work[1], info); + here += 2; + } + } + } + if (here < *ilst) { + goto L10; + } + + } else { + + here = *ifst; +L20: + +/* Swap block with next one above */ + + if (nbf == 1 || nbf == 2) { + +/* Current block either 1 by 1 or 2 by 2 */ + + nbnext = 1; + if (here >= 3) { + if (t[here - 1 + (here - 2) * t_dim1] != 0.) { + nbnext = 2; + } + } + i__1 = here - nbnext; + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, & + nbnext, &nbf, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + here -= nbnext; + +/* Test if 2 by 2 block breaks into two 1 by 1 blocks */ + + if (nbf == 2) { + if (t[here + 1 + here * t_dim1] == 0.) { + nbf = 3; + } + } + + } else { + +/* + Current block consists of two 1 by 1 blocks each of which + must be swapped individually +*/ + + nbnext = 1; + if (here >= 3) { + if (t[here - 1 + (here - 2) * t_dim1] != 0.) { + nbnext = 2; + } + } + i__1 = here - nbnext; + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, & + nbnext, &c__1, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + if (nbnext == 1) { + +/* Swap two 1 by 1 blocks, no problems possible */ + + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &nbnext, &c__1, &work[1], info); + --here; + } else { + +/* Recompute NBNEXT in case 2 by 2 split */ + + if (t[here + (here - 1) * t_dim1] == 0.) { + nbnext = 1; + } + if (nbnext == 2) { + +/* 2 by 2 Block did not split */ + + i__1 = here - 1; + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + i__1, &c__2, &c__1, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + here += -2; + } else { + +/* 2 by 2 Block did split */ + + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &c__1, &c__1, &work[1], info); + i__1 = here - 1; + dlaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + i__1, &c__1, &c__1, &work[1], info); + here += -2; + } + } + } + if (here > *ilst) { + goto L20; + } + } + *ilst = here; + + return 0; + +/* End of DTREXC */ + +} /* dtrexc_ */ + +/* Subroutine */ int dtrti2_(char *uplo, char *diag, integer *n, doublereal * + a, integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer j; + static doublereal ajj; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + static logical upper; + extern /* Subroutine */ int dtrmv_(char *, char *, char *, integer *, + doublereal *, integer *, doublereal *, integer *), xerbla_(char *, integer *); + static logical nounit; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DTRTI2 computes the inverse of a real upper or lower triangular + matrix. + + This is the Level 2 BLAS version of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the matrix A is upper or lower triangular. + = 'U': Upper triangular + = 'L': Lower triangular + + DIAG (input) CHARACTER*1 + Specifies whether or not the matrix A is unit triangular. + = 'N': Non-unit triangular + = 'U': Unit triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the triangular matrix A. If UPLO = 'U', the + leading n by n upper triangular part of the array A contains + the upper triangular matrix, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of the array A contains + the lower triangular matrix, and the strictly upper + triangular part of A is not referenced. If DIAG = 'U', the + diagonal elements of A are also not referenced and are + assumed to be 1. + + On exit, the (triangular) inverse of the original matrix, in + the same storage format. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + nounit = lsame_(diag, "N"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DTRTI2", &i__1); + return 0; + } + + if (upper) { + +/* Compute inverse of upper triangular matrix. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (nounit) { + a[j + j * a_dim1] = 1. / a[j + j * a_dim1]; + ajj = -a[j + j * a_dim1]; + } else { + ajj = -1.; + } + +/* Compute elements 1:j-1 of j-th column. */ + + i__2 = j - 1; + dtrmv_("Upper", "No transpose", diag, &i__2, &a[a_offset], lda, & + a[j * a_dim1 + 1], &c__1); + i__2 = j - 1; + dscal_(&i__2, &ajj, &a[j * a_dim1 + 1], &c__1); +/* L10: */ + } + } else { + +/* Compute inverse of lower triangular matrix. */ + + for (j = *n; j >= 1; --j) { + if (nounit) { + a[j + j * a_dim1] = 1. / a[j + j * a_dim1]; + ajj = -a[j + j * a_dim1]; + } else { + ajj = -1.; + } + if (j < *n) { + +/* Compute elements j+1:n of j-th column. */ + + i__1 = *n - j; + dtrmv_("Lower", "No transpose", diag, &i__1, &a[j + 1 + (j + + 1) * a_dim1], lda, &a[j + 1 + j * a_dim1], &c__1); + i__1 = *n - j; + dscal_(&i__1, &ajj, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + + return 0; + +/* End of DTRTI2 */ + +} /* dtrti2_ */ + +/* Subroutine */ int dtrtri_(char *uplo, char *diag, integer *n, doublereal * + a, integer *lda, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, i__1, i__2[2], i__3, i__4, i__5; + char ch__1[2]; + + /* Local variables */ + static integer j, jb, nb, nn; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int dtrmm_(char *, char *, char *, char *, + integer *, integer *, doublereal *, doublereal *, integer *, + doublereal *, integer *), dtrsm_( + char *, char *, char *, char *, integer *, integer *, doublereal * + , doublereal *, integer *, doublereal *, integer *); + static logical upper; + extern /* Subroutine */ int dtrti2_(char *, char *, integer *, doublereal + *, integer *, integer *), xerbla_(char *, integer + *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical nounit; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + DTRTRI computes the inverse of a real upper or lower triangular + matrix A. + + This is the Level 3 BLAS version of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': A is upper triangular; + = 'L': A is lower triangular. + + DIAG (input) CHARACTER*1 + = 'N': A is non-unit triangular; + = 'U': A is unit triangular. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) DOUBLE PRECISION array, dimension (LDA,N) + On entry, the triangular matrix A. If UPLO = 'U', the + leading N-by-N upper triangular part of the array A contains + the upper triangular matrix, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of the array A contains + the lower triangular matrix, and the strictly upper + triangular part of A is not referenced. If DIAG = 'U', the + diagonal elements of A are also not referenced and are + assumed to be 1. + On exit, the (triangular) inverse of the original matrix, in + the same storage format. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, A(i,i) is exactly zero. The triangular + matrix is singular and its inverse can not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + nounit = lsame_(diag, "N"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("DTRTRI", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Check for singularity if non-unit. */ + + if (nounit) { + i__1 = *n; + for (*info = 1; *info <= i__1; ++(*info)) { + if (a[*info + *info * a_dim1] == 0.) { + return 0; + } +/* L10: */ + } + *info = 0; + } + +/* + Determine the block size for this environment. + + Writing concatenation +*/ + i__2[0] = 1, a__1[0] = uplo; + i__2[1] = 1, a__1[1] = diag; + s_cat(ch__1, a__1, i__2, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "DTRTRI", ch__1, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)2); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code */ + + dtrti2_(uplo, diag, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code */ + + if (upper) { + +/* Compute inverse of upper triangular matrix */ + + i__1 = *n; + i__3 = nb; + for (j = 1; i__3 < 0 ? j >= i__1 : j <= i__1; j += i__3) { +/* Computing MIN */ + i__4 = nb, i__5 = *n - j + 1; + jb = min(i__4,i__5); + +/* Compute rows 1:j-1 of current block column */ + + i__4 = j - 1; + dtrmm_("Left", "Upper", "No transpose", diag, &i__4, &jb, & + c_b15, &a[a_offset], lda, &a[j * a_dim1 + 1], lda); + i__4 = j - 1; + dtrsm_("Right", "Upper", "No transpose", diag, &i__4, &jb, & + c_b151, &a[j + j * a_dim1], lda, &a[j * a_dim1 + 1], + lda); + +/* Compute inverse of current diagonal block */ + + dtrti2_("Upper", diag, &jb, &a[j + j * a_dim1], lda, info); +/* L20: */ + } + } else { + +/* Compute inverse of lower triangular matrix */ + + nn = (*n - 1) / nb * nb + 1; + i__3 = -nb; + for (j = nn; i__3 < 0 ? j >= 1 : j <= 1; j += i__3) { +/* Computing MIN */ + i__1 = nb, i__4 = *n - j + 1; + jb = min(i__1,i__4); + if (j + jb <= *n) { + +/* Compute rows j+jb:n of current block column */ + + i__1 = *n - j - jb + 1; + dtrmm_("Left", "Lower", "No transpose", diag, &i__1, &jb, + &c_b15, &a[j + jb + (j + jb) * a_dim1], lda, &a[j + + jb + j * a_dim1], lda); + i__1 = *n - j - jb + 1; + dtrsm_("Right", "Lower", "No transpose", diag, &i__1, &jb, + &c_b151, &a[j + j * a_dim1], lda, &a[j + jb + j * + a_dim1], lda); + } + +/* Compute inverse of current diagonal block */ + + dtrti2_("Lower", diag, &jb, &a[j + j * a_dim1], lda, info); +/* L30: */ + } + } + } + + return 0; + +/* End of DTRTRI */ + +} /* dtrtri_ */ + diff --git a/numpy/linalg/lapack_lite/f2c_lapack.c b/numpy/linalg/lapack_lite/f2c_lapack.c new file mode 100644 index 0000000..d956ddb --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c_lapack.c @@ -0,0 +1,1651 @@ +/* +NOTE: This is generated code. Look in Misc/lapack_lite for information on + remaking this file. +*/ +#include "f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal dlamch_(char *); +#define EPSILON dlamch_("Epsilon") +#define SAFEMINIMUM dlamch_("Safe minimum") +#define PRECISION dlamch_("Precision") +#define BASE dlamch_("Base") +#endif + +extern doublereal dlapy2_(doublereal *x, doublereal *y); + +/* +f2c knows the exact rules for precedence, and so omits parentheses where not +strictly necessary. Since this is generated code, we don't really care if +it's readable, and we know what is written is correct. So don't warn about +them. +*/ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wparentheses" +#endif + + +/* Table of constant values */ + +static integer c__1 = 1; +static real c_b172 = 0.f; +static real c_b173 = 1.f; +static integer c__0 = 0; + +integer ieeeck_(integer *ispec, real *zero, real *one) +{ + /* System generated locals */ + integer ret_val; + + /* Local variables */ + static real nan1, nan2, nan3, nan4, nan5, nan6, neginf, posinf, negzro, + newzro; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + IEEECK is called from the ILAENV to verify that Infinity and + possibly NaN arithmetic is safe (i.e. will not trap). + + Arguments + ========= + + ISPEC (input) INTEGER + Specifies whether to test just for inifinity arithmetic + or whether to test for infinity and NaN arithmetic. + = 0: Verify infinity arithmetic only. + = 1: Verify infinity and NaN arithmetic. + + ZERO (input) REAL + Must contain the value 0.0 + This is passed to prevent the compiler from optimizing + away this code. + + ONE (input) REAL + Must contain the value 1.0 + This is passed to prevent the compiler from optimizing + away this code. + + RETURN VALUE: INTEGER + = 0: Arithmetic failed to produce the correct answers + = 1: Arithmetic produced the correct answers +*/ + + ret_val = 1; + + posinf = *one / *zero; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + neginf = -(*one) / *zero; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + negzro = *one / (neginf + *one); + if (negzro != *zero) { + ret_val = 0; + return ret_val; + } + + neginf = *one / negzro; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + newzro = negzro + *zero; + if (newzro != *zero) { + ret_val = 0; + return ret_val; + } + + posinf = *one / newzro; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + neginf *= posinf; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + posinf *= posinf; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + +/* Return if we were only asked to check infinity arithmetic */ + + if (*ispec == 0) { + return ret_val; + } + + nan1 = posinf + neginf; + + nan2 = posinf / neginf; + + nan3 = posinf / posinf; + + nan4 = posinf * *zero; + + nan5 = neginf * negzro; + + nan6 = nan5 * *zero; + + if (nan1 == nan1) { + ret_val = 0; + return ret_val; + } + + if (nan2 == nan2) { + ret_val = 0; + return ret_val; + } + + if (nan3 == nan3) { + ret_val = 0; + return ret_val; + } + + if (nan4 == nan4) { + ret_val = 0; + return ret_val; + } + + if (nan5 == nan5) { + ret_val = 0; + return ret_val; + } + + if (nan6 == nan6) { + ret_val = 0; + return ret_val; + } + + return ret_val; +} /* ieeeck_ */ + +integer ilaclc_(integer *m, integer *n, complex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, ret_val, i__1, i__2; + + /* Local variables */ + static integer i__; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILACLC scans A for its last non-zero column. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. + + N (input) INTEGER + The number of columns of the matrix A. + + A (input) COMPLEX array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Quick test for the common case where one corner is non-zero. +*/ + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (*n == 0) { + ret_val = *n; + } else /* if(complicated condition) */ { + i__1 = *n * a_dim1 + 1; + i__2 = *m + *n * a_dim1; + if (a[i__1].r != 0.f || a[i__1].i != 0.f || (a[i__2].r != 0.f || a[ + i__2].i != 0.f)) { + ret_val = *n; + } else { +/* Now scan each column from the end, returning with the first non-zero. */ + for (ret_val = *n; ret_val >= 1; --ret_val) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + ret_val * a_dim1; + if (a[i__2].r != 0.f || a[i__2].i != 0.f) { + return ret_val; + } + } + } + } + } + return ret_val; +} /* ilaclc_ */ + +integer ilaclr_(integer *m, integer *n, complex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, ret_val, i__1, i__2; + + /* Local variables */ + static integer i__, j; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILACLR scans A for its last non-zero row. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. + + N (input) INTEGER + The number of columns of the matrix A. + + A (input) COMPLEX array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Quick test for the common case where one corner is non-zero. +*/ + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (*m == 0) { + ret_val = *m; + } else /* if(complicated condition) */ { + i__1 = *m + a_dim1; + i__2 = *m + *n * a_dim1; + if (a[i__1].r != 0.f || a[i__1].i != 0.f || (a[i__2].r != 0.f || a[ + i__2].i != 0.f)) { + ret_val = *m; + } else { +/* Scan up each column tracking the last zero row seen. */ + ret_val = 0; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + i__2 = i__ + j * a_dim1; + if (a[i__2].r != 0.f || a[i__2].i != 0.f) { + goto L10; + } + } +L10: + ret_val = max(ret_val,i__); + } + } + } + return ret_val; +} /* ilaclr_ */ + +integer iladlc_(integer *m, integer *n, doublereal *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, ret_val, i__1; + + /* Local variables */ + static integer i__; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILADLC scans A for its last non-zero column. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. + + N (input) INTEGER + The number of columns of the matrix A. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Quick test for the common case where one corner is non-zero. +*/ + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (*n == 0) { + ret_val = *n; + } else if (a[*n * a_dim1 + 1] != 0. || a[*m + *n * a_dim1] != 0.) { + ret_val = *n; + } else { +/* Now scan each column from the end, returning with the first non-zero. */ + for (ret_val = *n; ret_val >= 1; --ret_val) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + if (a[i__ + ret_val * a_dim1] != 0.) { + return ret_val; + } + } + } + } + return ret_val; +} /* iladlc_ */ + +integer iladlr_(integer *m, integer *n, doublereal *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, ret_val, i__1; + + /* Local variables */ + static integer i__, j; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILADLR scans A for its last non-zero row. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. + + N (input) INTEGER + The number of columns of the matrix A. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Quick test for the common case where one corner is non-zero. +*/ + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (*m == 0) { + ret_val = *m; + } else if (a[*m + a_dim1] != 0. || a[*m + *n * a_dim1] != 0.) { + ret_val = *m; + } else { +/* Scan up each column tracking the last zero row seen. */ + ret_val = 0; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + if (a[i__ + j * a_dim1] != 0.) { + goto L10; + } + } +L10: + ret_val = max(ret_val,i__); + } + } + return ret_val; +} /* iladlr_ */ + +integer ilaenv_(integer *ispec, char *name__, char *opts, integer *n1, + integer *n2, integer *n3, integer *n4, ftnlen name_len, ftnlen + opts_len) +{ + /* System generated locals */ + integer ret_val; + + /* Local variables */ + static integer i__; + static char c1[1], c2[2], c3[3], c4[2]; + static integer ic, nb, iz, nx; + static logical cname; + static integer nbmin; + static logical sname; + extern integer ieeeck_(integer *, real *, real *); + static char subnam[6]; + extern integer iparmq_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + + -- April 2009 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILAENV is called from the LAPACK routines to choose problem-dependent + parameters for the local environment. See ISPEC for a description of + the parameters. + + ILAENV returns an INTEGER + if ILAENV >= 0: ILAENV returns the value of the parameter specified by ISPEC + if ILAENV < 0: if ILAENV = -k, the k-th argument had an illegal value. + + This version provides a set of parameters which should give good, + but not optimal, performance on many of the currently available + computers. Users are encouraged to modify this subroutine to set + the tuning parameters for their particular machine using the option + and problem size information in the arguments. + + This routine will not function correctly if it is converted to all + lower case. Converting it to all upper case is allowed. + + Arguments + ========= + + ISPEC (input) INTEGER + Specifies the parameter to be returned as the value of + ILAENV. + = 1: the optimal blocksize; if this value is 1, an unblocked + algorithm will give the best performance. + = 2: the minimum block size for which the block routine + should be used; if the usable block size is less than + this value, an unblocked routine should be used. + = 3: the crossover point (in a block routine, for N less + than this value, an unblocked routine should be used) + = 4: the number of shifts, used in the nonsymmetric + eigenvalue routines (DEPRECATED) + = 5: the minimum column dimension for blocking to be used; + rectangular blocks must have dimension at least k by m, + where k is given by ILAENV(2,...) and m by ILAENV(5,...) + = 6: the crossover point for the SVD (when reducing an m by n + matrix to bidiagonal form, if max(m,n)/min(m,n) exceeds + this value, a QR factorization is used first to reduce + the matrix to a triangular form.) + = 7: the number of processors + = 8: the crossover point for the multishift QR method + for nonsymmetric eigenvalue problems (DEPRECATED) + = 9: maximum size of the subproblems at the bottom of the + computation tree in the divide-and-conquer algorithm + (used by xGELSD and xGESDD) + =10: ieee NaN arithmetic can be trusted not to trap + =11: infinity arithmetic can be trusted not to trap + 12 <= ISPEC <= 16: + xHSEQR or one of its subroutines, + see IPARMQ for detailed explanation + + NAME (input) CHARACTER*(*) + The name of the calling subroutine, in either upper case or + lower case. + + OPTS (input) CHARACTER*(*) + The character options to the subroutine NAME, concatenated + into a single character string. For example, UPLO = 'U', + TRANS = 'T', and DIAG = 'N' for a triangular routine would + be specified as OPTS = 'UTN'. + + N1 (input) INTEGER + N2 (input) INTEGER + N3 (input) INTEGER + N4 (input) INTEGER + Problem dimensions for the subroutine NAME; these may not all + be required. + + Further Details + =============== + + The following conventions have been used when calling ILAENV from the + LAPACK routines: + 1) OPTS is a concatenation of all of the character options to + subroutine NAME, in the same order that they appear in the + argument list for NAME, even if they are not used in determining + the value of the parameter specified by ISPEC. + 2) The problem dimensions N1, N2, N3, N4 are specified in the order + that they appear in the argument list for NAME. N1 is used + first, N2 second, and so on, and unused problem dimensions are + passed a value of -1. + 3) The parameter value returned by ILAENV is checked for validity in + the calling subroutine. For example, ILAENV is used to retrieve + the optimal blocksize for STRTRI as follows: + + NB = ILAENV( 1, 'STRTRI', UPLO // DIAG, N, -1, -1, -1 ) + IF( NB.LE.1 ) NB = MAX( 1, N ) + + ===================================================================== +*/ + + + switch (*ispec) { + case 1: goto L10; + case 2: goto L10; + case 3: goto L10; + case 4: goto L80; + case 5: goto L90; + case 6: goto L100; + case 7: goto L110; + case 8: goto L120; + case 9: goto L130; + case 10: goto L140; + case 11: goto L150; + case 12: goto L160; + case 13: goto L160; + case 14: goto L160; + case 15: goto L160; + case 16: goto L160; + } + +/* Invalid value for ISPEC */ + + ret_val = -1; + return ret_val; + +L10: + +/* Convert NAME to upper case if the first character is lower case. */ + + ret_val = 1; + s_copy(subnam, name__, (ftnlen)6, name_len); + ic = *(unsigned char *)subnam; + iz = 'Z'; + if (iz == 90 || iz == 122) { + +/* ASCII character set */ + + if (ic >= 97 && ic <= 122) { + *(unsigned char *)subnam = (char) (ic - 32); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 97 && ic <= 122) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic - 32); + } +/* L20: */ + } + } + + } else if (iz == 233 || iz == 169) { + +/* EBCDIC character set */ + + if (ic >= 129 && ic <= 137 || ic >= 145 && ic <= 153 || ic >= 162 && + ic <= 169) { + *(unsigned char *)subnam = (char) (ic + 64); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 129 && ic <= 137 || ic >= 145 && ic <= 153 || ic >= + 162 && ic <= 169) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic + 64); + } +/* L30: */ + } + } + + } else if (iz == 218 || iz == 250) { + +/* Prime machines: ASCII+128 */ + + if (ic >= 225 && ic <= 250) { + *(unsigned char *)subnam = (char) (ic - 32); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 225 && ic <= 250) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic - 32); + } +/* L40: */ + } + } + } + + *(unsigned char *)c1 = *(unsigned char *)subnam; + sname = *(unsigned char *)c1 == 'S' || *(unsigned char *)c1 == 'D'; + cname = *(unsigned char *)c1 == 'C' || *(unsigned char *)c1 == 'Z'; + if (! (cname || sname)) { + return ret_val; + } + s_copy(c2, subnam + 1, (ftnlen)2, (ftnlen)2); + s_copy(c3, subnam + 3, (ftnlen)3, (ftnlen)3); + s_copy(c4, c3 + 1, (ftnlen)2, (ftnlen)2); + + switch (*ispec) { + case 1: goto L50; + case 2: goto L60; + case 3: goto L70; + } + +L50: + +/* + ISPEC = 1: block size + + In these examples, separate code is provided for setting NB for + real and complex. We assume that NB will take the same value in + single or double precision. +*/ + + nb = 1; + + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } else if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, + "RQF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen) + 3, (ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) + == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "PO", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } else if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nb = 32; + } else if (sname && s_cmp(c3, "GST", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } else if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nb = 32; + } else if (s_cmp(c3, "GST", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } + } else if (s_cmp(c2, "GB", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + if (*n4 <= 64) { + nb = 1; + } else { + nb = 32; + } + } else { + if (*n4 <= 64) { + nb = 1; + } else { + nb = 32; + } + } + } + } else if (s_cmp(c2, "PB", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + if (*n2 <= 64) { + nb = 1; + } else { + nb = 32; + } + } else { + if (*n2 <= 64) { + nb = 1; + } else { + nb = 32; + } + } + } + } else if (s_cmp(c2, "TR", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "LA", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "UUM", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (sname && s_cmp(c2, "ST", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "EBZ", (ftnlen)3, (ftnlen)3) == 0) { + nb = 1; + } + } + ret_val = nb; + return ret_val; + +L60: + +/* ISPEC = 2: minimum block size */ + + nbmin = 2; + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "RQF", ( + ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)3, ( + ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) == 0) + { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 8; + } else { + nbmin = 8; + } + } else if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nbmin = 2; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nbmin = 2; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } + } + ret_val = nbmin; + return ret_val; + +L70: + +/* ISPEC = 3: crossover point */ + + nx = 0; + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "RQF", ( + ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)3, ( + ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) == 0) + { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nx = 32; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nx = 32; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nx = 128; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nx = 128; + } + } + } + ret_val = nx; + return ret_val; + +L80: + +/* ISPEC = 4: number of shifts (used by xHSEQR) */ + + ret_val = 6; + return ret_val; + +L90: + +/* ISPEC = 5: minimum column dimension (not used) */ + + ret_val = 2; + return ret_val; + +L100: + +/* ISPEC = 6: crossover point for SVD (used by xGELSS and xGESVD) */ + + ret_val = (integer) ((real) min(*n1,*n2) * 1.6f); + return ret_val; + +L110: + +/* ISPEC = 7: number of processors (not used) */ + + ret_val = 1; + return ret_val; + +L120: + +/* ISPEC = 8: crossover point for multishift (used by xHSEQR) */ + + ret_val = 50; + return ret_val; + +L130: + +/* + ISPEC = 9: maximum size of the subproblems at the bottom of the + computation tree in the divide-and-conquer algorithm + (used by xGELSD and xGESDD) +*/ + + ret_val = 25; + return ret_val; + +L140: + +/* + ISPEC = 10: ieee NaN arithmetic can be trusted not to trap + + ILAENV = 0 +*/ + ret_val = 1; + if (ret_val == 1) { + ret_val = ieeeck_(&c__1, &c_b172, &c_b173); + } + return ret_val; + +L150: + +/* + ISPEC = 11: infinity arithmetic can be trusted not to trap + + ILAENV = 0 +*/ + ret_val = 1; + if (ret_val == 1) { + ret_val = ieeeck_(&c__0, &c_b172, &c_b173); + } + return ret_val; + +L160: + +/* 12 <= ISPEC <= 16: xHSEQR or one of its subroutines. */ + + ret_val = iparmq_(ispec, name__, opts, n1, n2, n3, n4, name_len, opts_len) + ; + return ret_val; + +/* End of ILAENV */ + +} /* ilaenv_ */ + +integer ilaslc_(integer *m, integer *n, real *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, ret_val, i__1; + + /* Local variables */ + static integer i__; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILASLC scans A for its last non-zero column. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. + + N (input) INTEGER + The number of columns of the matrix A. + + A (input) REAL array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Quick test for the common case where one corner is non-zero. +*/ + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (*n == 0) { + ret_val = *n; + } else if (a[*n * a_dim1 + 1] != 0.f || a[*m + *n * a_dim1] != 0.f) { + ret_val = *n; + } else { +/* Now scan each column from the end, returning with the first non-zero. */ + for (ret_val = *n; ret_val >= 1; --ret_val) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + if (a[i__ + ret_val * a_dim1] != 0.f) { + return ret_val; + } + } + } + } + return ret_val; +} /* ilaslc_ */ + +integer ilaslr_(integer *m, integer *n, real *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, ret_val, i__1; + + /* Local variables */ + static integer i__, j; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILASLR scans A for its last non-zero row. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. + + N (input) INTEGER + The number of columns of the matrix A. + + A (input) REAL array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Quick test for the common case where one corner is non-zero. +*/ + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (*m == 0) { + ret_val = *m; + } else if (a[*m + a_dim1] != 0.f || a[*m + *n * a_dim1] != 0.f) { + ret_val = *m; + } else { +/* Scan up each column tracking the last zero row seen. */ + ret_val = 0; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + if (a[i__ + j * a_dim1] != 0.f) { + goto L10; + } + } +L10: + ret_val = max(ret_val,i__); + } + } + return ret_val; +} /* ilaslr_ */ + +integer ilazlc_(integer *m, integer *n, doublecomplex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, ret_val, i__1, i__2; + + /* Local variables */ + static integer i__; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILAZLC scans A for its last non-zero column. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. + + N (input) INTEGER + The number of columns of the matrix A. + + A (input) COMPLEX*16 array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Quick test for the common case where one corner is non-zero. +*/ + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (*n == 0) { + ret_val = *n; + } else /* if(complicated condition) */ { + i__1 = *n * a_dim1 + 1; + i__2 = *m + *n * a_dim1; + if (a[i__1].r != 0. || a[i__1].i != 0. || (a[i__2].r != 0. || a[i__2] + .i != 0.)) { + ret_val = *n; + } else { +/* Now scan each column from the end, returning with the first non-zero. */ + for (ret_val = *n; ret_val >= 1; --ret_val) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + ret_val * a_dim1; + if (a[i__2].r != 0. || a[i__2].i != 0.) { + return ret_val; + } + } + } + } + } + return ret_val; +} /* ilazlc_ */ + +integer ilazlr_(integer *m, integer *n, doublecomplex *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, ret_val, i__1, i__2; + + /* Local variables */ + static integer i__, j; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + ILAZLR scans A for its last non-zero row. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. + + N (input) INTEGER + The number of columns of the matrix A. + + A (input) COMPLEX*16 array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Quick test for the common case where one corner is non-zero. +*/ + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (*m == 0) { + ret_val = *m; + } else /* if(complicated condition) */ { + i__1 = *m + a_dim1; + i__2 = *m + *n * a_dim1; + if (a[i__1].r != 0. || a[i__1].i != 0. || (a[i__2].r != 0. || a[i__2] + .i != 0.)) { + ret_val = *m; + } else { +/* Scan up each column tracking the last zero row seen. */ + ret_val = 0; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + i__2 = i__ + j * a_dim1; + if (a[i__2].r != 0. || a[i__2].i != 0.) { + goto L10; + } + } +L10: + ret_val = max(ret_val,i__); + } + } + } + return ret_val; +} /* ilazlr_ */ + +integer iparmq_(integer *ispec, char *name__, char *opts, integer *n, integer + *ilo, integer *ihi, integer *lwork, ftnlen name_len, ftnlen opts_len) +{ + /* System generated locals */ + integer ret_val, i__1, i__2; + real r__1; + + /* Local variables */ + static integer nh, ns; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This program sets problem and machine dependent parameters + useful for xHSEQR and its subroutines. It is called whenever + ILAENV is called with 12 <= ISPEC <= 16 + + Arguments + ========= + + ISPEC (input) integer scalar + ISPEC specifies which tunable parameter IPARMQ should + return. + + ISPEC=12: (INMIN) Matrices of order nmin or less + are sent directly to xLAHQR, the implicit + double shift QR algorithm. NMIN must be + at least 11. + + ISPEC=13: (INWIN) Size of the deflation window. + This is best set greater than or equal to + the number of simultaneous shifts NS. + Larger matrices benefit from larger deflation + windows. + + ISPEC=14: (INIBL) Determines when to stop nibbling and + invest in an (expensive) multi-shift QR sweep. + If the aggressive early deflation subroutine + finds LD converged eigenvalues from an order + NW deflation window and LD.GT.(NW*NIBBLE)/100, + then the next QR sweep is skipped and early + deflation is applied immediately to the + remaining active diagonal block. Setting + IPARMQ(ISPEC=14) = 0 causes TTQRE to skip a + multi-shift QR sweep whenever early deflation + finds a converged eigenvalue. Setting + IPARMQ(ISPEC=14) greater than or equal to 100 + prevents TTQRE from skipping a multi-shift + QR sweep. + + ISPEC=15: (NSHFTS) The number of simultaneous shifts in + a multi-shift QR iteration. + + ISPEC=16: (IACC22) IPARMQ is set to 0, 1 or 2 with the + following meanings. + 0: During the multi-shift QR sweep, + xLAQR5 does not accumulate reflections and + does not use matrix-matrix multiply to + update the far-from-diagonal matrix + entries. + 1: During the multi-shift QR sweep, + xLAQR5 and/or xLAQRaccumulates reflections and uses + matrix-matrix multiply to update the + far-from-diagonal matrix entries. + 2: During the multi-shift QR sweep. + xLAQR5 accumulates reflections and takes + advantage of 2-by-2 block structure during + matrix-matrix multiplies. + (If xTRMM is slower than xGEMM, then + IPARMQ(ISPEC=16)=1 may be more efficient than + IPARMQ(ISPEC=16)=2 despite the greater level of + arithmetic work implied by the latter choice.) + + NAME (input) character string + Name of the calling subroutine + + OPTS (input) character string + This is a concatenation of the string arguments to + TTQRE. + + N (input) integer scalar + N is the order of the Hessenberg matrix H. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular + in rows and columns 1:ILO-1 and IHI+1:N. + + LWORK (input) integer scalar + The amount of workspace available. + + Further Details + =============== + + Little is known about how best to choose these parameters. + It is possible to use different values of the parameters + for each of CHSEQR, DHSEQR, SHSEQR and ZHSEQR. + + It is probably best to choose different parameters for + different matrices and different parameters at different + times during the iteration, but this has not been + implemented --- yet. + + + The best choices of most of the parameters depend + in an ill-understood way on the relative execution + rate of xLAQR3 and xLAQR5 and on the nature of each + particular eigenvalue problem. Experiment may be the + only practical way to determine which choices are most + effective. + + Following is a list of default values supplied by IPARMQ. + These defaults may be adjusted in order to attain better + performance in any particular computational environment. + + IPARMQ(ISPEC=12) The xLAHQR vs xLAQR0 crossover point. + Default: 75. (Must be at least 11.) + + IPARMQ(ISPEC=13) Recommended deflation window size. + This depends on ILO, IHI and NS, the + number of simultaneous shifts returned + by IPARMQ(ISPEC=15). The default for + (IHI-ILO+1).LE.500 is NS. The default + for (IHI-ILO+1).GT.500 is 3*NS/2. + + IPARMQ(ISPEC=14) Nibble crossover point. Default: 14. + + IPARMQ(ISPEC=15) Number of simultaneous shifts, NS. + a multi-shift QR iteration. + + If IHI-ILO+1 is ... + + greater than ...but less ... the + or equal to ... than default is + + 0 30 NS = 2+ + 30 60 NS = 4+ + 60 150 NS = 10 + 150 590 NS = ** + 590 3000 NS = 64 + 3000 6000 NS = 128 + 6000 infinity NS = 256 + + (+) By default matrices of this order are + passed to the implicit double shift routine + xLAHQR. See IPARMQ(ISPEC=12) above. These + values of NS are used only in case of a rare + xLAHQR failure. + + (**) The asterisks (**) indicate an ad-hoc + function increasing from 10 to 64. + + IPARMQ(ISPEC=16) Select structured matrix multiply. + (See ISPEC=16 above for details.) + Default: 3. + + ================================================================ +*/ + if (*ispec == 15 || *ispec == 13 || *ispec == 16) { + +/* ==== Set the number simultaneous shifts ==== */ + + nh = *ihi - *ilo + 1; + ns = 2; + if (nh >= 30) { + ns = 4; + } + if (nh >= 60) { + ns = 10; + } + if (nh >= 150) { +/* Computing MAX */ + r__1 = log((real) nh) / log(2.f); + i__1 = 10, i__2 = nh / i_nint(&r__1); + ns = max(i__1,i__2); + } + if (nh >= 590) { + ns = 64; + } + if (nh >= 3000) { + ns = 128; + } + if (nh >= 6000) { + ns = 256; + } +/* Computing MAX */ + i__1 = 2, i__2 = ns - ns % 2; + ns = max(i__1,i__2); + } + + if (*ispec == 12) { + + +/* + ===== Matrices of order smaller than NMIN get sent + . to xLAHQR, the classic double shift algorithm. + . This must be at least 11. ==== +*/ + + ret_val = 75; + + } else if (*ispec == 14) { + +/* + ==== INIBL: skip a multi-shift qr iteration and + . whenever aggressive early deflation finds + . at least (NIBBLE*(window size)/100) deflations. ==== +*/ + + ret_val = 14; + + } else if (*ispec == 15) { + +/* ==== NSHFTS: The number of simultaneous shifts ===== */ + + ret_val = ns; + + } else if (*ispec == 13) { + +/* ==== NW: deflation window size. ==== */ + + if (nh <= 500) { + ret_val = ns; + } else { + ret_val = ns * 3 / 2; + } + + } else if (*ispec == 16) { + +/* + ==== IACC22: Whether to accumulate reflections + . before updating the far-from-diagonal elements + . and whether to use 2-by-2 block structure while + . doing it. A small amount of work could be saved + . by making this choice dependent also upon the + . NH=IHI-ILO+1. +*/ + + ret_val = 0; + if (ns >= 14) { + ret_val = 1; + } + if (ns >= 14) { + ret_val = 2; + } + + } else { +/* ===== invalid value of ispec ===== */ + ret_val = -1; + + } + +/* ==== End of IPARMQ ==== */ + + return ret_val; +} /* iparmq_ */ + diff --git a/numpy/linalg/lapack_lite/f2c_s_lapack.c b/numpy/linalg/lapack_lite/f2c_s_lapack.c new file mode 100644 index 0000000..04080f8 --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c_s_lapack.c @@ -0,0 +1,39603 @@ +/* +NOTE: This is generated code. Look in Misc/lapack_lite for information on + remaking this file. +*/ +#include "f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal dlamch_(char *); +#define EPSILON dlamch_("Epsilon") +#define SAFEMINIMUM dlamch_("Safe minimum") +#define PRECISION dlamch_("Precision") +#define BASE dlamch_("Base") +#endif + +extern doublereal dlapy2_(doublereal *x, doublereal *y); + +/* +f2c knows the exact rules for precedence, and so omits parentheses where not +strictly necessary. Since this is generated code, we don't really care if +it's readable, and we know what is written is correct. So don't warn about +them. +*/ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wparentheses" +#endif + + +/* Table of constant values */ + +static integer c__9 = 9; +static integer c__0 = 0; +static real c_b15 = 1.f; +static integer c__1 = 1; +static real c_b29 = 0.f; +static doublereal c_b94 = -.125; +static real c_b151 = -1.f; +static integer c_n1 = -1; +static integer c__3 = 3; +static integer c__2 = 2; +static integer c__65 = 65; +static integer c__12 = 12; +static integer c__49 = 49; +static integer c__4 = 4; +static logical c_false = FALSE_; +static integer c__13 = 13; +static integer c__15 = 15; +static integer c__14 = 14; +static integer c__16 = 16; +static logical c_true = TRUE_; +static real c_b2863 = 2.f; + +/* Subroutine */ int sbdsdc_(char *uplo, char *compq, integer *n, real *d__, + real *e, real *u, integer *ldu, real *vt, integer *ldvt, real *q, + integer *iq, real *work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer u_dim1, u_offset, vt_dim1, vt_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static integer i__, j, k; + static real p, r__; + static integer z__, ic, ii, kk; + static real cs; + static integer is, iu; + static real sn; + static integer nm1; + static real eps; + static integer ivt, difl, difr, ierr, perm, mlvl, sqre; + extern logical lsame_(char *, char *); + static integer poles; + extern /* Subroutine */ int slasr_(char *, char *, char *, integer *, + integer *, real *, real *, real *, integer *); + static integer iuplo, nsize, start; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *), sswap_(integer *, real *, integer *, real *, integer * + ), slasd0_(integer *, integer *, real *, real *, real *, integer * + , real *, integer *, integer *, integer *, real *, integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int slasda_(integer *, integer *, integer *, + integer *, real *, real *, real *, integer *, real *, integer *, + real *, real *, real *, real *, integer *, integer *, integer *, + integer *, real *, real *, real *, real *, integer *, integer *), + xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *); + static integer givcol; + extern /* Subroutine */ int slasdq_(char *, integer *, integer *, integer + *, integer *, integer *, real *, real *, real *, integer *, real * + , integer *, real *, integer *, real *, integer *); + static integer icompq; + extern /* Subroutine */ int slaset_(char *, integer *, integer *, real *, + real *, real *, integer *), slartg_(real *, real *, real * + , real *, real *); + static real orgnrm; + static integer givnum; + extern doublereal slanst_(char *, integer *, real *, real *); + static integer givptr, qstart, smlsiz, wstart, smlszp; + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SBDSDC computes the singular value decomposition (SVD) of a real + N-by-N (upper or lower) bidiagonal matrix B: B = U * S * VT, + using a divide and conquer method, where S is a diagonal matrix + with non-negative diagonal elements (the singular values of B), and + U and VT are orthogonal matrices of left and right singular vectors, + respectively. SBDSDC can be used to compute all singular values, + and optionally, singular vectors or singular vectors in compact form. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. See SLASD3 for details. + + The code currently calls SLASDQ if singular values only are desired. + However, it can be slightly modified to compute singular values + using the divide and conquer method. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': B is upper bidiagonal. + = 'L': B is lower bidiagonal. + + COMPQ (input) CHARACTER*1 + Specifies whether singular vectors are to be computed + as follows: + = 'N': Compute singular values only; + = 'P': Compute singular values and compute singular + vectors in compact form; + = 'I': Compute singular values and singular vectors. + + N (input) INTEGER + The order of the matrix B. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the n diagonal elements of the bidiagonal matrix B. + On exit, if INFO=0, the singular values of B. + + E (input/output) REAL array, dimension (N-1) + On entry, the elements of E contain the offdiagonal + elements of the bidiagonal matrix whose SVD is desired. + On exit, E has been destroyed. + + U (output) REAL array, dimension (LDU,N) + If COMPQ = 'I', then: + On exit, if INFO = 0, U contains the left singular vectors + of the bidiagonal matrix. + For other values of COMPQ, U is not referenced. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= 1. + If singular vectors are desired, then LDU >= max( 1, N ). + + VT (output) REAL array, dimension (LDVT,N) + If COMPQ = 'I', then: + On exit, if INFO = 0, VT' contains the right singular + vectors of the bidiagonal matrix. + For other values of COMPQ, VT is not referenced. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= 1. + If singular vectors are desired, then LDVT >= max( 1, N ). + + Q (output) REAL array, dimension (LDQ) + If COMPQ = 'P', then: + On exit, if INFO = 0, Q and IQ contain the left + and right singular vectors in a compact form, + requiring O(N log N) space instead of 2*N**2. + In particular, Q contains all the REAL data in + LDQ >= N*(11 + 2*SMLSIZ + 8*INT(LOG_2(N/(SMLSIZ+1)))) + words of memory, where SMLSIZ is returned by ILAENV and + is equal to the maximum size of the subproblems at the + bottom of the computation tree (usually about 25). + For other values of COMPQ, Q is not referenced. + + IQ (output) INTEGER array, dimension (LDIQ) + If COMPQ = 'P', then: + On exit, if INFO = 0, Q and IQ contain the left + and right singular vectors in a compact form, + requiring O(N log N) space instead of 2*N**2. + In particular, IQ contains all INTEGER data in + LDIQ >= N*(3 + 3*INT(LOG_2(N/(SMLSIZ+1)))) + words of memory, where SMLSIZ is returned by ILAENV and + is equal to the maximum size of the subproblems at the + bottom of the computation tree (usually about 25). + For other values of COMPQ, IQ is not referenced. + + WORK (workspace) REAL array, dimension (MAX(1,LWORK)) + If COMPQ = 'N' then LWORK >= (4 * N). + If COMPQ = 'P' then LWORK >= (6 * N). + If COMPQ = 'I' then LWORK >= (3 * N**2 + 4 * N). + + IWORK (workspace) INTEGER array, dimension (8*N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute a singular value. + The update process of divide and conquer failed. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + ===================================================================== + Changed dimension statement in comment describing E from (N) to + (N-1). Sven, 17 Feb 05. + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --q; + --iq; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + iuplo = 0; + if (lsame_(uplo, "U")) { + iuplo = 1; + } + if (lsame_(uplo, "L")) { + iuplo = 2; + } + if (lsame_(compq, "N")) { + icompq = 0; + } else if (lsame_(compq, "P")) { + icompq = 1; + } else if (lsame_(compq, "I")) { + icompq = 2; + } else { + icompq = -1; + } + if (iuplo == 0) { + *info = -1; + } else if (icompq < 0) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ldu < 1 || icompq == 2 && *ldu < *n) { + *info = -7; + } else if (*ldvt < 1 || icompq == 2 && *ldvt < *n) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SBDSDC", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + smlsiz = ilaenv_(&c__9, "SBDSDC", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + if (*n == 1) { + if (icompq == 1) { + q[1] = r_sign(&c_b15, &d__[1]); + q[smlsiz * *n + 1] = 1.f; + } else if (icompq == 2) { + u[u_dim1 + 1] = r_sign(&c_b15, &d__[1]); + vt[vt_dim1 + 1] = 1.f; + } + d__[1] = dabs(d__[1]); + return 0; + } + nm1 = *n - 1; + +/* + If matrix lower bidiagonal, rotate to be upper bidiagonal + by applying Givens rotations on the left +*/ + + wstart = 1; + qstart = 3; + if (icompq == 1) { + scopy_(n, &d__[1], &c__1, &q[1], &c__1); + i__1 = *n - 1; + scopy_(&i__1, &e[1], &c__1, &q[*n + 1], &c__1); + } + if (iuplo == 2) { + qstart = 5; + wstart = (*n << 1) - 1; + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + slartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + if (icompq == 1) { + q[i__ + (*n << 1)] = cs; + q[i__ + *n * 3] = sn; + } else if (icompq == 2) { + work[i__] = cs; + work[nm1 + i__] = -sn; + } +/* L10: */ + } + } + +/* If ICOMPQ = 0, use SLASDQ to compute the singular values. */ + + if (icompq == 0) { + slasdq_("U", &c__0, n, &c__0, &c__0, &c__0, &d__[1], &e[1], &vt[ + vt_offset], ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[ + wstart], info); + goto L40; + } + +/* + If N is smaller than the minimum divide size SMLSIZ, then solve + the problem with another solver. +*/ + + if (*n <= smlsiz) { + if (icompq == 2) { + slaset_("A", n, n, &c_b29, &c_b15, &u[u_offset], ldu); + slaset_("A", n, n, &c_b29, &c_b15, &vt[vt_offset], ldvt); + slasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &vt[vt_offset] + , ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[ + wstart], info); + } else if (icompq == 1) { + iu = 1; + ivt = iu + *n; + slaset_("A", n, n, &c_b29, &c_b15, &q[iu + (qstart - 1) * *n], n); + slaset_("A", n, n, &c_b29, &c_b15, &q[ivt + (qstart - 1) * *n], n); + slasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &q[ivt + ( + qstart - 1) * *n], n, &q[iu + (qstart - 1) * *n], n, &q[ + iu + (qstart - 1) * *n], n, &work[wstart], info); + } + goto L40; + } + + if (icompq == 2) { + slaset_("A", n, n, &c_b29, &c_b15, &u[u_offset], ldu); + slaset_("A", n, n, &c_b29, &c_b15, &vt[vt_offset], ldvt); + } + +/* Scale. */ + + orgnrm = slanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.f) { + return 0; + } + slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, n, &c__1, &d__[1], n, &ierr); + slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &nm1, &c__1, &e[1], &nm1, & + ierr); + + eps = slamch_("Epsilon"); + + mlvl = (integer) (log((real) (*n) / (real) (smlsiz + 1)) / log(2.f)) + 1; + smlszp = smlsiz + 1; + + if (icompq == 1) { + iu = 1; + ivt = smlsiz + 1; + difl = ivt + smlszp; + difr = difl + mlvl; + z__ = difr + (mlvl << 1); + ic = z__ + mlvl; + is = ic + 1; + poles = is + 1; + givnum = poles + (mlvl << 1); + + k = 1; + givptr = 2; + perm = 3; + givcol = perm + mlvl; + } + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((r__1 = d__[i__], dabs(r__1)) < eps) { + d__[i__] = r_sign(&eps, &d__[i__]); + } +/* L20: */ + } + + start = 1; + sqre = 0; + + i__1 = nm1; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((r__1 = e[i__], dabs(r__1)) < eps || i__ == nm1) { + +/* + Subproblem found. First determine its size and then + apply divide and conquer on it. +*/ + + if (i__ < nm1) { + +/* A subproblem with E(I) small for I < NM1. */ + + nsize = i__ - start + 1; + } else if ((r__1 = e[i__], dabs(r__1)) >= eps) { + +/* A subproblem with E(NM1) not too small but I = NM1. */ + + nsize = *n - start + 1; + } else { + +/* + A subproblem with E(NM1) small. This implies an + 1-by-1 subproblem at D(N). Solve this 1-by-1 problem + first. +*/ + + nsize = i__ - start + 1; + if (icompq == 2) { + u[*n + *n * u_dim1] = r_sign(&c_b15, &d__[*n]); + vt[*n + *n * vt_dim1] = 1.f; + } else if (icompq == 1) { + q[*n + (qstart - 1) * *n] = r_sign(&c_b15, &d__[*n]); + q[*n + (smlsiz + qstart - 1) * *n] = 1.f; + } + d__[*n] = (r__1 = d__[*n], dabs(r__1)); + } + if (icompq == 2) { + slasd0_(&nsize, &sqre, &d__[start], &e[start], &u[start + + start * u_dim1], ldu, &vt[start + start * vt_dim1], + ldvt, &smlsiz, &iwork[1], &work[wstart], info); + } else { + slasda_(&icompq, &smlsiz, &nsize, &sqre, &d__[start], &e[ + start], &q[start + (iu + qstart - 2) * *n], n, &q[ + start + (ivt + qstart - 2) * *n], &iq[start + k * *n], + &q[start + (difl + qstart - 2) * *n], &q[start + ( + difr + qstart - 2) * *n], &q[start + (z__ + qstart - + 2) * *n], &q[start + (poles + qstart - 2) * *n], &iq[ + start + givptr * *n], &iq[start + givcol * *n], n, & + iq[start + perm * *n], &q[start + (givnum + qstart - + 2) * *n], &q[start + (ic + qstart - 2) * *n], &q[ + start + (is + qstart - 2) * *n], &work[wstart], & + iwork[1], info); + } + if (*info != 0) { + return 0; + } + start = i__ + 1; + } +/* L30: */ + } + +/* Unscale */ + + slascl_("G", &c__0, &c__0, &c_b15, &orgnrm, n, &c__1, &d__[1], n, &ierr); +L40: + +/* Use Selection Sort to minimize swaps of singular vectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + kk = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] > p) { + kk = j; + p = d__[j]; + } +/* L50: */ + } + if (kk != i__) { + d__[kk] = d__[i__]; + d__[i__] = p; + if (icompq == 1) { + iq[i__] = kk; + } else if (icompq == 2) { + sswap_(n, &u[i__ * u_dim1 + 1], &c__1, &u[kk * u_dim1 + 1], & + c__1); + sswap_(n, &vt[i__ + vt_dim1], ldvt, &vt[kk + vt_dim1], ldvt); + } + } else if (icompq == 1) { + iq[i__] = i__; + } +/* L60: */ + } + +/* If ICOMPQ = 1, use IQ(N,1) as the indicator for UPLO */ + + if (icompq == 1) { + if (iuplo == 1) { + iq[*n] = 1; + } else { + iq[*n] = 0; + } + } + +/* + If B is lower bidiagonal, update U by those Givens rotations + which rotated B to be upper bidiagonal +*/ + + if (iuplo == 2 && icompq == 2) { + slasr_("L", "V", "B", n, n, &work[1], &work[*n], &u[u_offset], ldu); + } + + return 0; + +/* End of SBDSDC */ + +} /* sbdsdc_ */ + +/* Subroutine */ int sbdsqr_(char *uplo, integer *n, integer *ncvt, integer * + nru, integer *ncc, real *d__, real *e, real *vt, integer *ldvt, real * + u, integer *ldu, real *c__, integer *ldc, real *work, integer *info) +{ + /* System generated locals */ + integer c_dim1, c_offset, u_dim1, u_offset, vt_dim1, vt_offset, i__1, + i__2; + real r__1, r__2, r__3, r__4; + doublereal d__1; + + /* Local variables */ + static real f, g, h__; + static integer i__, j, m; + static real r__, cs; + static integer ll; + static real sn, mu; + static integer nm1, nm12, nm13, lll; + static real eps, sll, tol, abse; + static integer idir; + static real abss; + static integer oldm; + static real cosl; + static integer isub, iter; + static real unfl, sinl, cosr, smin, smax, sinr; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *), slas2_(real *, real *, real *, real *, + real *); + extern logical lsame_(char *, char *); + static real oldcs; + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + static integer oldll; + static real shift, sigmn, oldsn; + static integer maxit; + static real sminl; + extern /* Subroutine */ int slasr_(char *, char *, char *, integer *, + integer *, real *, real *, real *, integer *); + static real sigmx; + static logical lower; + extern /* Subroutine */ int sswap_(integer *, real *, integer *, real *, + integer *), slasq1_(integer *, real *, real *, real *, integer *), + slasv2_(real *, real *, real *, real *, real *, real *, real *, + real *, real *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static real sminoa; + extern /* Subroutine */ int slartg_(real *, real *, real *, real *, real * + ); + static real thresh; + static logical rotate; + static real tolmul; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + January 2007 + + + Purpose + ======= + + SBDSQR computes the singular values and, optionally, the right and/or + left singular vectors from the singular value decomposition (SVD) of + a real N-by-N (upper or lower) bidiagonal matrix B using the implicit + zero-shift QR algorithm. The SVD of B has the form + + B = Q * S * P**T + + where S is the diagonal matrix of singular values, Q is an orthogonal + matrix of left singular vectors, and P is an orthogonal matrix of + right singular vectors. If left singular vectors are requested, this + subroutine actually returns U*Q instead of Q, and, if right singular + vectors are requested, this subroutine returns P**T*VT instead of + P**T, for given real input matrices U and VT. When U and VT are the + orthogonal matrices that reduce a general matrix A to bidiagonal + form: A = U*B*VT, as computed by SGEBRD, then + + A = (U*Q) * S * (P**T*VT) + + is the SVD of A. Optionally, the subroutine may also compute Q**T*C + for a given real input matrix C. + + See "Computing Small Singular Values of Bidiagonal Matrices With + Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, + LAPACK Working Note #3 (or SIAM J. Sci. Statist. Comput. vol. 11, + no. 5, pp. 873-912, Sept 1990) and + "Accurate singular values and differential qd algorithms," by + B. Parlett and V. Fernando, Technical Report CPAM-554, Mathematics + Department, University of California at Berkeley, July 1992 + for a detailed description of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': B is upper bidiagonal; + = 'L': B is lower bidiagonal. + + N (input) INTEGER + The order of the matrix B. N >= 0. + + NCVT (input) INTEGER + The number of columns of the matrix VT. NCVT >= 0. + + NRU (input) INTEGER + The number of rows of the matrix U. NRU >= 0. + + NCC (input) INTEGER + The number of columns of the matrix C. NCC >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the n diagonal elements of the bidiagonal matrix B. + On exit, if INFO=0, the singular values of B in decreasing + order. + + E (input/output) REAL array, dimension (N-1) + On entry, the N-1 offdiagonal elements of the bidiagonal + matrix B. + On exit, if INFO = 0, E is destroyed; if INFO > 0, D and E + will contain the diagonal and superdiagonal elements of a + bidiagonal matrix orthogonally equivalent to the one given + as input. + + VT (input/output) REAL array, dimension (LDVT, NCVT) + On entry, an N-by-NCVT matrix VT. + On exit, VT is overwritten by P**T * VT. + Not referenced if NCVT = 0. + + LDVT (input) INTEGER + The leading dimension of the array VT. + LDVT >= max(1,N) if NCVT > 0; LDVT >= 1 if NCVT = 0. + + U (input/output) REAL array, dimension (LDU, N) + On entry, an NRU-by-N matrix U. + On exit, U is overwritten by U * Q. + Not referenced if NRU = 0. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= max(1,NRU). + + C (input/output) REAL array, dimension (LDC, NCC) + On entry, an N-by-NCC matrix C. + On exit, C is overwritten by Q**T * C. + Not referenced if NCC = 0. + + LDC (input) INTEGER + The leading dimension of the array C. + LDC >= max(1,N) if NCC > 0; LDC >=1 if NCC = 0. + + WORK (workspace) REAL array, dimension (4*N) + + INFO (output) INTEGER + = 0: successful exit + < 0: If INFO = -i, the i-th argument had an illegal value + > 0: + if NCVT = NRU = NCC = 0, + = 1, a split was marked by a positive value in E + = 2, current block of Z not diagonalized after 30*N + iterations (in inner while loop) + = 3, termination criterion of outer while loop not met + (program created more than N unreduced blocks) + else NCVT = NRU = NCC = 0, + the algorithm did not converge; D and E contain the + elements of a bidiagonal matrix which is orthogonally + similar to the input matrix B; if INFO = i, i + elements of E have not converged to zero. + + Internal Parameters + =================== + + TOLMUL REAL, default = max(10,min(100,EPS**(-1/8))) + TOLMUL controls the convergence criterion of the QR loop. + If it is positive, TOLMUL*EPS is the desired relative + precision in the computed singular values. + If it is negative, abs(TOLMUL*EPS*sigma_max) is the + desired absolute accuracy in the computed singular + values (corresponds to relative accuracy + abs(TOLMUL*EPS) in the largest singular value. + abs(TOLMUL) should be between 1 and 1/EPS, and preferably + between 10 (for fast convergence) and .1/EPS + (for there to be some accuracy in the results). + Default is to lose at either one eighth or 2 of the + available decimal digits in each computed singular value + (whichever is smaller). + + MAXITR INTEGER, default = 6 + MAXITR controls the maximum number of passes of the + algorithm through its inner loop. The algorithms stops + (and so fails to converge) if the number of passes + through the inner loop exceeds MAXITR*N**2. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + lower = lsame_(uplo, "L"); + if (! lsame_(uplo, "U") && ! lower) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ncvt < 0) { + *info = -3; + } else if (*nru < 0) { + *info = -4; + } else if (*ncc < 0) { + *info = -5; + } else if (*ncvt == 0 && *ldvt < 1 || *ncvt > 0 && *ldvt < max(1,*n)) { + *info = -9; + } else if (*ldu < max(1,*nru)) { + *info = -11; + } else if (*ncc == 0 && *ldc < 1 || *ncc > 0 && *ldc < max(1,*n)) { + *info = -13; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SBDSQR", &i__1); + return 0; + } + if (*n == 0) { + return 0; + } + if (*n == 1) { + goto L160; + } + +/* ROTATE is true if any singular vectors desired, false otherwise */ + + rotate = *ncvt > 0 || *nru > 0 || *ncc > 0; + +/* If no singular vectors desired, use qd algorithm */ + + if (! rotate) { + slasq1_(n, &d__[1], &e[1], &work[1], info); + return 0; + } + + nm1 = *n - 1; + nm12 = nm1 + nm1; + nm13 = nm12 + nm1; + idir = 0; + +/* Get machine constants */ + + eps = slamch_("Epsilon"); + unfl = slamch_("Safe minimum"); + +/* + If matrix lower bidiagonal, rotate to be upper bidiagonal + by applying Givens rotations on the left +*/ + + if (lower) { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + slartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + work[i__] = cs; + work[nm1 + i__] = sn; +/* L10: */ + } + +/* Update singular vectors if desired */ + + if (*nru > 0) { + slasr_("R", "V", "F", nru, n, &work[1], &work[*n], &u[u_offset], + ldu); + } + if (*ncc > 0) { + slasr_("L", "V", "F", n, ncc, &work[1], &work[*n], &c__[c_offset], + ldc); + } + } + +/* + Compute singular values to relative accuracy TOL + (By setting TOL to be negative, algorithm will compute + singular values to absolute accuracy ABS(TOL)*norm(input matrix)) + + Computing MAX + Computing MIN +*/ + d__1 = (doublereal) eps; + r__3 = 100.f, r__4 = pow_dd(&d__1, &c_b94); + r__1 = 10.f, r__2 = dmin(r__3,r__4); + tolmul = dmax(r__1,r__2); + tol = tolmul * eps; + +/* Compute approximate maximum, minimum singular values */ + + smax = 0.f; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__2 = smax, r__3 = (r__1 = d__[i__], dabs(r__1)); + smax = dmax(r__2,r__3); +/* L20: */ + } + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__2 = smax, r__3 = (r__1 = e[i__], dabs(r__1)); + smax = dmax(r__2,r__3); +/* L30: */ + } + sminl = 0.f; + if (tol >= 0.f) { + +/* Relative accuracy desired */ + + sminoa = dabs(d__[1]); + if (sminoa == 0.f) { + goto L50; + } + mu = sminoa; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + mu = (r__2 = d__[i__], dabs(r__2)) * (mu / (mu + (r__1 = e[i__ - + 1], dabs(r__1)))); + sminoa = dmin(sminoa,mu); + if (sminoa == 0.f) { + goto L50; + } +/* L40: */ + } +L50: + sminoa /= sqrt((real) (*n)); +/* Computing MAX */ + r__1 = tol * sminoa, r__2 = *n * 6 * *n * unfl; + thresh = dmax(r__1,r__2); + } else { + +/* + Absolute accuracy desired + + Computing MAX +*/ + r__1 = dabs(tol) * smax, r__2 = *n * 6 * *n * unfl; + thresh = dmax(r__1,r__2); + } + +/* + Prepare for main iteration loop for the singular values + (MAXIT is the maximum number of passes through the inner + loop permitted before nonconvergence signalled.) +*/ + + maxit = *n * 6 * *n; + iter = 0; + oldll = -1; + oldm = -1; + +/* M points to last element of unconverged part of matrix */ + + m = *n; + +/* Begin main iteration loop */ + +L60: + +/* Check for convergence or exceeding iteration count */ + + if (m <= 1) { + goto L160; + } + if (iter > maxit) { + goto L200; + } + +/* Find diagonal block of matrix to work on */ + + if (tol < 0.f && (r__1 = d__[m], dabs(r__1)) <= thresh) { + d__[m] = 0.f; + } + smax = (r__1 = d__[m], dabs(r__1)); + smin = smax; + i__1 = m - 1; + for (lll = 1; lll <= i__1; ++lll) { + ll = m - lll; + abss = (r__1 = d__[ll], dabs(r__1)); + abse = (r__1 = e[ll], dabs(r__1)); + if (tol < 0.f && abss <= thresh) { + d__[ll] = 0.f; + } + if (abse <= thresh) { + goto L80; + } + smin = dmin(smin,abss); +/* Computing MAX */ + r__1 = max(smax,abss); + smax = dmax(r__1,abse); +/* L70: */ + } + ll = 0; + goto L90; +L80: + e[ll] = 0.f; + +/* Matrix splits since E(LL) = 0 */ + + if (ll == m - 1) { + +/* Convergence of bottom singular value, return to top of loop */ + + --m; + goto L60; + } +L90: + ++ll; + +/* E(LL) through E(M-1) are nonzero, E(LL-1) is zero */ + + if (ll == m - 1) { + +/* 2 by 2 block, handle separately */ + + slasv2_(&d__[m - 1], &e[m - 1], &d__[m], &sigmn, &sigmx, &sinr, &cosr, + &sinl, &cosl); + d__[m - 1] = sigmx; + e[m - 1] = 0.f; + d__[m] = sigmn; + +/* Compute singular vectors, if desired */ + + if (*ncvt > 0) { + srot_(ncvt, &vt[m - 1 + vt_dim1], ldvt, &vt[m + vt_dim1], ldvt, & + cosr, &sinr); + } + if (*nru > 0) { + srot_(nru, &u[(m - 1) * u_dim1 + 1], &c__1, &u[m * u_dim1 + 1], & + c__1, &cosl, &sinl); + } + if (*ncc > 0) { + srot_(ncc, &c__[m - 1 + c_dim1], ldc, &c__[m + c_dim1], ldc, & + cosl, &sinl); + } + m += -2; + goto L60; + } + +/* + If working on new submatrix, choose shift direction + (from larger end diagonal element towards smaller) +*/ + + if (ll > oldm || m < oldll) { + if ((r__1 = d__[ll], dabs(r__1)) >= (r__2 = d__[m], dabs(r__2))) { + +/* Chase bulge from top (big end) to bottom (small end) */ + + idir = 1; + } else { + +/* Chase bulge from bottom (big end) to top (small end) */ + + idir = 2; + } + } + +/* Apply convergence tests */ + + if (idir == 1) { + +/* + Run convergence test in forward direction + First apply standard test to bottom of matrix +*/ + + if ((r__2 = e[m - 1], dabs(r__2)) <= dabs(tol) * (r__1 = d__[m], dabs( + r__1)) || tol < 0.f && (r__3 = e[m - 1], dabs(r__3)) <= + thresh) { + e[m - 1] = 0.f; + goto L60; + } + + if (tol >= 0.f) { + +/* + If relative accuracy desired, + apply convergence criterion forward +*/ + + mu = (r__1 = d__[ll], dabs(r__1)); + sminl = mu; + i__1 = m - 1; + for (lll = ll; lll <= i__1; ++lll) { + if ((r__1 = e[lll], dabs(r__1)) <= tol * mu) { + e[lll] = 0.f; + goto L60; + } + mu = (r__2 = d__[lll + 1], dabs(r__2)) * (mu / (mu + (r__1 = + e[lll], dabs(r__1)))); + sminl = dmin(sminl,mu); +/* L100: */ + } + } + + } else { + +/* + Run convergence test in backward direction + First apply standard test to top of matrix +*/ + + if ((r__2 = e[ll], dabs(r__2)) <= dabs(tol) * (r__1 = d__[ll], dabs( + r__1)) || tol < 0.f && (r__3 = e[ll], dabs(r__3)) <= thresh) { + e[ll] = 0.f; + goto L60; + } + + if (tol >= 0.f) { + +/* + If relative accuracy desired, + apply convergence criterion backward +*/ + + mu = (r__1 = d__[m], dabs(r__1)); + sminl = mu; + i__1 = ll; + for (lll = m - 1; lll >= i__1; --lll) { + if ((r__1 = e[lll], dabs(r__1)) <= tol * mu) { + e[lll] = 0.f; + goto L60; + } + mu = (r__2 = d__[lll], dabs(r__2)) * (mu / (mu + (r__1 = e[ + lll], dabs(r__1)))); + sminl = dmin(sminl,mu); +/* L110: */ + } + } + } + oldll = ll; + oldm = m; + +/* + Compute shift. First, test if shifting would ruin relative + accuracy, and if so set the shift to zero. + + Computing MAX +*/ + r__1 = eps, r__2 = tol * .01f; + if (tol >= 0.f && *n * tol * (sminl / smax) <= dmax(r__1,r__2)) { + +/* Use a zero shift to avoid loss of relative accuracy */ + + shift = 0.f; + } else { + +/* Compute the shift from 2-by-2 block at end of matrix */ + + if (idir == 1) { + sll = (r__1 = d__[ll], dabs(r__1)); + slas2_(&d__[m - 1], &e[m - 1], &d__[m], &shift, &r__); + } else { + sll = (r__1 = d__[m], dabs(r__1)); + slas2_(&d__[ll], &e[ll], &d__[ll + 1], &shift, &r__); + } + +/* Test if shift negligible, and if so set to zero */ + + if (sll > 0.f) { +/* Computing 2nd power */ + r__1 = shift / sll; + if (r__1 * r__1 < eps) { + shift = 0.f; + } + } + } + +/* Increment iteration count */ + + iter = iter + m - ll; + +/* If SHIFT = 0, do simplified QR iteration */ + + if (shift == 0.f) { + if (idir == 1) { + +/* + Chase bulge from top to bottom + Save cosines and sines for later singular vector updates +*/ + + cs = 1.f; + oldcs = 1.f; + i__1 = m - 1; + for (i__ = ll; i__ <= i__1; ++i__) { + r__1 = d__[i__] * cs; + slartg_(&r__1, &e[i__], &cs, &sn, &r__); + if (i__ > ll) { + e[i__ - 1] = oldsn * r__; + } + r__1 = oldcs * r__; + r__2 = d__[i__ + 1] * sn; + slartg_(&r__1, &r__2, &oldcs, &oldsn, &d__[i__]); + work[i__ - ll + 1] = cs; + work[i__ - ll + 1 + nm1] = sn; + work[i__ - ll + 1 + nm12] = oldcs; + work[i__ - ll + 1 + nm13] = oldsn; +/* L120: */ + } + h__ = d__[m] * cs; + d__[m] = h__ * oldcs; + e[m - 1] = h__ * oldsn; + +/* Update singular vectors */ + + if (*ncvt > 0) { + i__1 = m - ll + 1; + slasr_("L", "V", "F", &i__1, ncvt, &work[1], &work[*n], &vt[ + ll + vt_dim1], ldvt); + } + if (*nru > 0) { + i__1 = m - ll + 1; + slasr_("R", "V", "F", nru, &i__1, &work[nm12 + 1], &work[nm13 + + 1], &u[ll * u_dim1 + 1], ldu); + } + if (*ncc > 0) { + i__1 = m - ll + 1; + slasr_("L", "V", "F", &i__1, ncc, &work[nm12 + 1], &work[nm13 + + 1], &c__[ll + c_dim1], ldc); + } + +/* Test convergence */ + + if ((r__1 = e[m - 1], dabs(r__1)) <= thresh) { + e[m - 1] = 0.f; + } + + } else { + +/* + Chase bulge from bottom to top + Save cosines and sines for later singular vector updates +*/ + + cs = 1.f; + oldcs = 1.f; + i__1 = ll + 1; + for (i__ = m; i__ >= i__1; --i__) { + r__1 = d__[i__] * cs; + slartg_(&r__1, &e[i__ - 1], &cs, &sn, &r__); + if (i__ < m) { + e[i__] = oldsn * r__; + } + r__1 = oldcs * r__; + r__2 = d__[i__ - 1] * sn; + slartg_(&r__1, &r__2, &oldcs, &oldsn, &d__[i__]); + work[i__ - ll] = cs; + work[i__ - ll + nm1] = -sn; + work[i__ - ll + nm12] = oldcs; + work[i__ - ll + nm13] = -oldsn; +/* L130: */ + } + h__ = d__[ll] * cs; + d__[ll] = h__ * oldcs; + e[ll] = h__ * oldsn; + +/* Update singular vectors */ + + if (*ncvt > 0) { + i__1 = m - ll + 1; + slasr_("L", "V", "B", &i__1, ncvt, &work[nm12 + 1], &work[ + nm13 + 1], &vt[ll + vt_dim1], ldvt); + } + if (*nru > 0) { + i__1 = m - ll + 1; + slasr_("R", "V", "B", nru, &i__1, &work[1], &work[*n], &u[ll * + u_dim1 + 1], ldu); + } + if (*ncc > 0) { + i__1 = m - ll + 1; + slasr_("L", "V", "B", &i__1, ncc, &work[1], &work[*n], &c__[ + ll + c_dim1], ldc); + } + +/* Test convergence */ + + if ((r__1 = e[ll], dabs(r__1)) <= thresh) { + e[ll] = 0.f; + } + } + } else { + +/* Use nonzero shift */ + + if (idir == 1) { + +/* + Chase bulge from top to bottom + Save cosines and sines for later singular vector updates +*/ + + f = ((r__1 = d__[ll], dabs(r__1)) - shift) * (r_sign(&c_b15, &d__[ + ll]) + shift / d__[ll]); + g = e[ll]; + i__1 = m - 1; + for (i__ = ll; i__ <= i__1; ++i__) { + slartg_(&f, &g, &cosr, &sinr, &r__); + if (i__ > ll) { + e[i__ - 1] = r__; + } + f = cosr * d__[i__] + sinr * e[i__]; + e[i__] = cosr * e[i__] - sinr * d__[i__]; + g = sinr * d__[i__ + 1]; + d__[i__ + 1] = cosr * d__[i__ + 1]; + slartg_(&f, &g, &cosl, &sinl, &r__); + d__[i__] = r__; + f = cosl * e[i__] + sinl * d__[i__ + 1]; + d__[i__ + 1] = cosl * d__[i__ + 1] - sinl * e[i__]; + if (i__ < m - 1) { + g = sinl * e[i__ + 1]; + e[i__ + 1] = cosl * e[i__ + 1]; + } + work[i__ - ll + 1] = cosr; + work[i__ - ll + 1 + nm1] = sinr; + work[i__ - ll + 1 + nm12] = cosl; + work[i__ - ll + 1 + nm13] = sinl; +/* L140: */ + } + e[m - 1] = f; + +/* Update singular vectors */ + + if (*ncvt > 0) { + i__1 = m - ll + 1; + slasr_("L", "V", "F", &i__1, ncvt, &work[1], &work[*n], &vt[ + ll + vt_dim1], ldvt); + } + if (*nru > 0) { + i__1 = m - ll + 1; + slasr_("R", "V", "F", nru, &i__1, &work[nm12 + 1], &work[nm13 + + 1], &u[ll * u_dim1 + 1], ldu); + } + if (*ncc > 0) { + i__1 = m - ll + 1; + slasr_("L", "V", "F", &i__1, ncc, &work[nm12 + 1], &work[nm13 + + 1], &c__[ll + c_dim1], ldc); + } + +/* Test convergence */ + + if ((r__1 = e[m - 1], dabs(r__1)) <= thresh) { + e[m - 1] = 0.f; + } + + } else { + +/* + Chase bulge from bottom to top + Save cosines and sines for later singular vector updates +*/ + + f = ((r__1 = d__[m], dabs(r__1)) - shift) * (r_sign(&c_b15, &d__[ + m]) + shift / d__[m]); + g = e[m - 1]; + i__1 = ll + 1; + for (i__ = m; i__ >= i__1; --i__) { + slartg_(&f, &g, &cosr, &sinr, &r__); + if (i__ < m) { + e[i__] = r__; + } + f = cosr * d__[i__] + sinr * e[i__ - 1]; + e[i__ - 1] = cosr * e[i__ - 1] - sinr * d__[i__]; + g = sinr * d__[i__ - 1]; + d__[i__ - 1] = cosr * d__[i__ - 1]; + slartg_(&f, &g, &cosl, &sinl, &r__); + d__[i__] = r__; + f = cosl * e[i__ - 1] + sinl * d__[i__ - 1]; + d__[i__ - 1] = cosl * d__[i__ - 1] - sinl * e[i__ - 1]; + if (i__ > ll + 1) { + g = sinl * e[i__ - 2]; + e[i__ - 2] = cosl * e[i__ - 2]; + } + work[i__ - ll] = cosr; + work[i__ - ll + nm1] = -sinr; + work[i__ - ll + nm12] = cosl; + work[i__ - ll + nm13] = -sinl; +/* L150: */ + } + e[ll] = f; + +/* Test convergence */ + + if ((r__1 = e[ll], dabs(r__1)) <= thresh) { + e[ll] = 0.f; + } + +/* Update singular vectors if desired */ + + if (*ncvt > 0) { + i__1 = m - ll + 1; + slasr_("L", "V", "B", &i__1, ncvt, &work[nm12 + 1], &work[ + nm13 + 1], &vt[ll + vt_dim1], ldvt); + } + if (*nru > 0) { + i__1 = m - ll + 1; + slasr_("R", "V", "B", nru, &i__1, &work[1], &work[*n], &u[ll * + u_dim1 + 1], ldu); + } + if (*ncc > 0) { + i__1 = m - ll + 1; + slasr_("L", "V", "B", &i__1, ncc, &work[1], &work[*n], &c__[ + ll + c_dim1], ldc); + } + } + } + +/* QR iteration finished, go back and check convergence */ + + goto L60; + +/* All singular values converged, so make them positive */ + +L160: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if (d__[i__] < 0.f) { + d__[i__] = -d__[i__]; + +/* Change sign of singular vectors, if desired */ + + if (*ncvt > 0) { + sscal_(ncvt, &c_b151, &vt[i__ + vt_dim1], ldvt); + } + } +/* L170: */ + } + +/* + Sort the singular values into decreasing order (insertion sort on + singular values, but only one transposition per singular vector) +*/ + + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Scan for smallest D(I) */ + + isub = 1; + smin = d__[1]; + i__2 = *n + 1 - i__; + for (j = 2; j <= i__2; ++j) { + if (d__[j] <= smin) { + isub = j; + smin = d__[j]; + } +/* L180: */ + } + if (isub != *n + 1 - i__) { + +/* Swap singular values and vectors */ + + d__[isub] = d__[*n + 1 - i__]; + d__[*n + 1 - i__] = smin; + if (*ncvt > 0) { + sswap_(ncvt, &vt[isub + vt_dim1], ldvt, &vt[*n + 1 - i__ + + vt_dim1], ldvt); + } + if (*nru > 0) { + sswap_(nru, &u[isub * u_dim1 + 1], &c__1, &u[(*n + 1 - i__) * + u_dim1 + 1], &c__1); + } + if (*ncc > 0) { + sswap_(ncc, &c__[isub + c_dim1], ldc, &c__[*n + 1 - i__ + + c_dim1], ldc); + } + } +/* L190: */ + } + goto L220; + +/* Maximum number of iterations exceeded, failure to converge */ + +L200: + *info = 0; + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (e[i__] != 0.f) { + ++(*info); + } +/* L210: */ + } +L220: + return 0; + +/* End of SBDSQR */ + +} /* sbdsqr_ */ + +/* Subroutine */ int sgebak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, real *scale, integer *m, real *v, integer *ldv, integer + *info) +{ + /* System generated locals */ + integer v_dim1, v_offset, i__1; + + /* Local variables */ + static integer i__, k; + static real s; + static integer ii; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + static logical leftv; + extern /* Subroutine */ int sswap_(integer *, real *, integer *, real *, + integer *), xerbla_(char *, integer *); + static logical rightv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGEBAK forms the right or left eigenvectors of a real general matrix + by backward transformation on the computed eigenvectors of the + balanced matrix output by SGEBAL. + + Arguments + ========= + + JOB (input) CHARACTER*1 + Specifies the type of backward transformation required: + = 'N', do nothing, return immediately; + = 'P', do backward transformation for permutation only; + = 'S', do backward transformation for scaling only; + = 'B', do backward transformations for both permutation and + scaling. + JOB must be the same as the argument JOB supplied to SGEBAL. + + SIDE (input) CHARACTER*1 + = 'R': V contains right eigenvectors; + = 'L': V contains left eigenvectors. + + N (input) INTEGER + The number of rows of the matrix V. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + The integers ILO and IHI determined by SGEBAL. + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + SCALE (input) REAL array, dimension (N) + Details of the permutation and scaling factors, as returned + by SGEBAL. + + M (input) INTEGER + The number of columns of the matrix V. M >= 0. + + V (input/output) REAL array, dimension (LDV,M) + On entry, the matrix of right or left eigenvectors to be + transformed, as returned by SHSEIN or STREVC. + On exit, V is overwritten by the transformed eigenvectors. + + LDV (input) INTEGER + The leading dimension of the array V. LDV >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Decode and Test the input parameters +*/ + + /* Parameter adjustments */ + --scale; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + + /* Function Body */ + rightv = lsame_(side, "R"); + leftv = lsame_(side, "L"); + + *info = 0; + if (! lsame_(job, "N") && ! lsame_(job, "P") && ! lsame_(job, "S") + && ! lsame_(job, "B")) { + *info = -1; + } else if (! rightv && ! leftv) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -4; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -5; + } else if (*m < 0) { + *info = -7; + } else if (*ldv < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGEBAK", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*m == 0) { + return 0; + } + if (lsame_(job, "N")) { + return 0; + } + + if (*ilo == *ihi) { + goto L30; + } + +/* Backward balance */ + + if (lsame_(job, "S") || lsame_(job, "B")) { + + if (rightv) { + i__1 = *ihi; + for (i__ = *ilo; i__ <= i__1; ++i__) { + s = scale[i__]; + sscal_(m, &s, &v[i__ + v_dim1], ldv); +/* L10: */ + } + } + + if (leftv) { + i__1 = *ihi; + for (i__ = *ilo; i__ <= i__1; ++i__) { + s = 1.f / scale[i__]; + sscal_(m, &s, &v[i__ + v_dim1], ldv); +/* L20: */ + } + } + + } + +/* + Backward permutation + + For I = ILO-1 step -1 until 1, + IHI+1 step 1 until N do -- +*/ + +L30: + if (lsame_(job, "P") || lsame_(job, "B")) { + if (rightv) { + i__1 = *n; + for (ii = 1; ii <= i__1; ++ii) { + i__ = ii; + if (i__ >= *ilo && i__ <= *ihi) { + goto L40; + } + if (i__ < *ilo) { + i__ = *ilo - ii; + } + k = scale[i__]; + if (k == i__) { + goto L40; + } + sswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv); +L40: + ; + } + } + + if (leftv) { + i__1 = *n; + for (ii = 1; ii <= i__1; ++ii) { + i__ = ii; + if (i__ >= *ilo && i__ <= *ihi) { + goto L50; + } + if (i__ < *ilo) { + i__ = *ilo - ii; + } + k = scale[i__]; + if (k == i__) { + goto L50; + } + sswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv); +L50: + ; + } + } + } + + return 0; + +/* End of SGEBAK */ + +} /* sgebak_ */ + +/* Subroutine */ int sgebal_(char *job, integer *n, real *a, integer *lda, + integer *ilo, integer *ihi, real *scale, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real r__1, r__2; + + /* Local variables */ + static real c__, f, g; + static integer i__, j, k, l, m; + static real r__, s, ca, ra; + static integer ica, ira, iexc; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + sswap_(integer *, real *, integer *, real *, integer *); + static real sfmin1, sfmin2, sfmax1, sfmax2; + extern doublereal slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer isamax_(integer *, real *, integer *); + extern logical sisnan_(real *); + static logical noconv; + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SGEBAL balances a general real matrix A. This involves, first, + permuting A by a similarity transformation to isolate eigenvalues + in the first 1 to ILO-1 and last IHI+1 to N elements on the + diagonal; and second, applying a diagonal similarity transformation + to rows and columns ILO to IHI to make the rows and columns as + close in norm as possible. Both steps are optional. + + Balancing may reduce the 1-norm of the matrix, and improve the + accuracy of the computed eigenvalues and/or eigenvectors. + + Arguments + ========= + + JOB (input) CHARACTER*1 + Specifies the operations to be performed on A: + = 'N': none: simply set ILO = 1, IHI = N, SCALE(I) = 1.0 + for i = 1,...,N; + = 'P': permute only; + = 'S': scale only; + = 'B': both permute and scale. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the input matrix A. + On exit, A is overwritten by the balanced matrix. + If JOB = 'N', A is not referenced. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + ILO (output) INTEGER + IHI (output) INTEGER + ILO and IHI are set to integers such that on exit + A(i,j) = 0 if i > j and j = 1,...,ILO-1 or I = IHI+1,...,N. + If JOB = 'N' or 'S', ILO = 1 and IHI = N. + + SCALE (output) REAL array, dimension (N) + Details of the permutations and scaling factors applied to + A. If P(j) is the index of the row and column interchanged + with row and column j and D(j) is the scaling factor + applied to row and column j, then + SCALE(j) = P(j) for j = 1,...,ILO-1 + = D(j) for j = ILO,...,IHI + = P(j) for j = IHI+1,...,N. + The order in which the interchanges are made is N to IHI+1, + then 1 to ILO-1. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The permutations consist of row and column interchanges which put + the matrix in the form + + ( T1 X Y ) + P A P = ( 0 B Z ) + ( 0 0 T2 ) + + where T1 and T2 are upper triangular matrices whose eigenvalues lie + along the diagonal. The column indices ILO and IHI mark the starting + and ending columns of the submatrix B. Balancing consists of applying + a diagonal similarity transformation inv(D) * B * D to make the + 1-norms of each row of B and its corresponding column nearly equal. + The output matrix is + + ( T1 X*D Y ) + ( 0 inv(D)*B*D inv(D)*Z ). + ( 0 0 T2 ) + + Information about the permutations P and the diagonal matrix D is + returned in the vector SCALE. + + This subroutine is based on the EISPACK routine BALANC. + + Modified by Tzu-Yi Chen, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --scale; + + /* Function Body */ + *info = 0; + if (! lsame_(job, "N") && ! lsame_(job, "P") && ! lsame_(job, "S") + && ! lsame_(job, "B")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGEBAL", &i__1); + return 0; + } + + k = 1; + l = *n; + + if (*n == 0) { + goto L210; + } + + if (lsame_(job, "N")) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + scale[i__] = 1.f; +/* L10: */ + } + goto L210; + } + + if (lsame_(job, "S")) { + goto L120; + } + +/* Permutation to isolate eigenvalues if possible */ + + goto L50; + +/* Row and column exchange. */ + +L20: + scale[m] = (real) j; + if (j == m) { + goto L30; + } + + sswap_(&l, &a[j * a_dim1 + 1], &c__1, &a[m * a_dim1 + 1], &c__1); + i__1 = *n - k + 1; + sswap_(&i__1, &a[j + k * a_dim1], lda, &a[m + k * a_dim1], lda); + +L30: + switch (iexc) { + case 1: goto L40; + case 2: goto L80; + } + +/* Search for rows isolating an eigenvalue and push them down. */ + +L40: + if (l == 1) { + goto L210; + } + --l; + +L50: + for (j = l; j >= 1; --j) { + + i__1 = l; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__ == j) { + goto L60; + } + if (a[j + i__ * a_dim1] != 0.f) { + goto L70; + } +L60: + ; + } + + m = l; + iexc = 1; + goto L20; +L70: + ; + } + + goto L90; + +/* Search for columns isolating an eigenvalue and push them left. */ + +L80: + ++k; + +L90: + i__1 = l; + for (j = k; j <= i__1; ++j) { + + i__2 = l; + for (i__ = k; i__ <= i__2; ++i__) { + if (i__ == j) { + goto L100; + } + if (a[i__ + j * a_dim1] != 0.f) { + goto L110; + } +L100: + ; + } + + m = k; + iexc = 2; + goto L20; +L110: + ; + } + +L120: + i__1 = l; + for (i__ = k; i__ <= i__1; ++i__) { + scale[i__] = 1.f; +/* L130: */ + } + + if (lsame_(job, "P")) { + goto L210; + } + +/* + Balance the submatrix in rows K to L. + + Iterative loop for norm reduction +*/ + + sfmin1 = slamch_("S") / slamch_("P"); + sfmax1 = 1.f / sfmin1; + sfmin2 = sfmin1 * 2.f; + sfmax2 = 1.f / sfmin2; +L140: + noconv = FALSE_; + + i__1 = l; + for (i__ = k; i__ <= i__1; ++i__) { + c__ = 0.f; + r__ = 0.f; + + i__2 = l; + for (j = k; j <= i__2; ++j) { + if (j == i__) { + goto L150; + } + c__ += (r__1 = a[j + i__ * a_dim1], dabs(r__1)); + r__ += (r__1 = a[i__ + j * a_dim1], dabs(r__1)); +L150: + ; + } + ica = isamax_(&l, &a[i__ * a_dim1 + 1], &c__1); + ca = (r__1 = a[ica + i__ * a_dim1], dabs(r__1)); + i__2 = *n - k + 1; + ira = isamax_(&i__2, &a[i__ + k * a_dim1], lda); + ra = (r__1 = a[i__ + (ira + k - 1) * a_dim1], dabs(r__1)); + +/* Guard against zero C or R due to underflow. */ + + if (c__ == 0.f || r__ == 0.f) { + goto L200; + } + g = r__ / 2.f; + f = 1.f; + s = c__ + r__; +L160: +/* Computing MAX */ + r__1 = max(f,c__); +/* Computing MIN */ + r__2 = min(r__,g); + if (c__ >= g || dmax(r__1,ca) >= sfmax2 || dmin(r__2,ra) <= sfmin2) { + goto L170; + } + f *= 2.f; + c__ *= 2.f; + ca *= 2.f; + r__ /= 2.f; + g /= 2.f; + ra /= 2.f; + goto L160; + +L170: + g = c__ / 2.f; +L180: +/* Computing MIN */ + r__1 = min(f,c__), r__1 = min(r__1,g); + if (g < r__ || dmax(r__,ra) >= sfmax2 || dmin(r__1,ca) <= sfmin2) { + goto L190; + } + r__1 = c__ + f + ca + r__ + g + ra; + if (sisnan_(&r__1)) { + +/* Exit if NaN to avoid infinite loop */ + + *info = -3; + i__2 = -(*info); + xerbla_("SGEBAL", &i__2); + return 0; + } + f /= 2.f; + c__ /= 2.f; + g /= 2.f; + ca /= 2.f; + r__ *= 2.f; + ra *= 2.f; + goto L180; + +/* Now balance. */ + +L190: + if (c__ + r__ >= s * .95f) { + goto L200; + } + if (f < 1.f && scale[i__] < 1.f) { + if (f * scale[i__] <= sfmin1) { + goto L200; + } + } + if (f > 1.f && scale[i__] > 1.f) { + if (scale[i__] >= sfmax1 / f) { + goto L200; + } + } + g = 1.f / f; + scale[i__] *= f; + noconv = TRUE_; + + i__2 = *n - k + 1; + sscal_(&i__2, &g, &a[i__ + k * a_dim1], lda); + sscal_(&l, &f, &a[i__ * a_dim1 + 1], &c__1); + +L200: + ; + } + + if (noconv) { + goto L140; + } + +L210: + *ilo = k; + *ihi = l; + + return 0; + +/* End of SGEBAL */ + +} /* sgebal_ */ + +/* Subroutine */ int sgebd2_(integer *m, integer *n, real *a, integer *lda, + real *d__, real *e, real *tauq, real *taup, real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__; + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), xerbla_( + char *, integer *), slarfg_(integer *, real *, real *, + integer *, real *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGEBD2 reduces a real general m by n matrix A to upper or lower + bidiagonal form B by an orthogonal transformation: Q' * A * P = B. + + If m >= n, B is upper bidiagonal; if m < n, B is lower bidiagonal. + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. M >= 0. + + N (input) INTEGER + The number of columns in the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the m by n general matrix to be reduced. + On exit, + if m >= n, the diagonal and the first superdiagonal are + overwritten with the upper bidiagonal matrix B; the + elements below the diagonal, with the array TAUQ, represent + the orthogonal matrix Q as a product of elementary + reflectors, and the elements above the first superdiagonal, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors; + if m < n, the diagonal and the first subdiagonal are + overwritten with the lower bidiagonal matrix B; the + elements below the first subdiagonal, with the array TAUQ, + represent the orthogonal matrix Q as a product of + elementary reflectors, and the elements above the diagonal, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) REAL array, dimension (min(M,N)) + The diagonal elements of the bidiagonal matrix B: + D(i) = A(i,i). + + E (output) REAL array, dimension (min(M,N)-1) + The off-diagonal elements of the bidiagonal matrix B: + if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1; + if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1. + + TAUQ (output) REAL array dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix Q. See Further Details. + + TAUP (output) REAL array, dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix P. See Further Details. + + WORK (workspace) REAL array, dimension (max(M,N)) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + If m >= n, + + Q = H(1) H(2) . . . H(n) and P = G(1) G(2) . . . G(n-1) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors; + v(1:i-1) = 0, v(i) = 1, and v(i+1:m) is stored on exit in A(i+1:m,i); + u(1:i) = 0, u(i+1) = 1, and u(i+2:n) is stored on exit in A(i,i+2:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, + + Q = H(1) H(2) . . . H(m-1) and P = G(1) G(2) . . . G(m) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors; + v(1:i) = 0, v(i+1) = 1, and v(i+2:m) is stored on exit in A(i+2:m,i); + u(1:i-1) = 0, u(i) = 1, and u(i+1:n) is stored on exit in A(i,i+1:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + The contents of A on exit are illustrated by the following examples: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) + ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) + ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) + ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) + ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) + ( v1 v2 v3 v4 v5 ) + + where d and e denote diagonal and off-diagonal elements of B, vi + denotes an element of the vector defining H(i), and ui an element of + the vector defining G(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info < 0) { + i__1 = -(*info); + xerbla_("SGEBD2", &i__1); + return 0; + } + + if (*m >= *n) { + +/* Reduce to upper bidiagonal form */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ + + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + slarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * + a_dim1], &c__1, &tauq[i__]); + d__[i__] = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.f; + +/* Apply H(i) to A(i:m,i+1:n) from the left */ + + if (i__ < *n) { + i__2 = *m - i__ + 1; + i__3 = *n - i__; + slarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, & + tauq[i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1] + ); + } + a[i__ + i__ * a_dim1] = d__[i__]; + + if (i__ < *n) { + +/* + Generate elementary reflector G(i) to annihilate + A(i,i+2:n) +*/ + + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + slarfg_(&i__2, &a[i__ + (i__ + 1) * a_dim1], &a[i__ + min( + i__3,*n) * a_dim1], lda, &taup[i__]); + e[i__] = a[i__ + (i__ + 1) * a_dim1]; + a[i__ + (i__ + 1) * a_dim1] = 1.f; + +/* Apply G(i) to A(i+1:m,i+1:n) from the right */ + + i__2 = *m - i__; + i__3 = *n - i__; + slarf_("Right", &i__2, &i__3, &a[i__ + (i__ + 1) * a_dim1], + lda, &taup[i__], &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &work[1]); + a[i__ + (i__ + 1) * a_dim1] = e[i__]; + } else { + taup[i__] = 0.f; + } +/* L10: */ + } + } else { + +/* Reduce to lower bidiagonal form */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector G(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + slarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[i__ + min(i__3,*n) * + a_dim1], lda, &taup[i__]); + d__[i__] = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.f; + +/* Apply G(i) to A(i+1:m,i:n) from the right */ + + if (i__ < *m) { + i__2 = *m - i__; + i__3 = *n - i__ + 1; + slarf_("Right", &i__2, &i__3, &a[i__ + i__ * a_dim1], lda, & + taup[i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + a[i__ + i__ * a_dim1] = d__[i__]; + + if (i__ < *m) { + +/* + Generate elementary reflector H(i) to annihilate + A(i+2:m,i) +*/ + + i__2 = *m - i__; +/* Computing MIN */ + i__3 = i__ + 2; + slarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*m) + + i__ * a_dim1], &c__1, &tauq[i__]); + e[i__] = a[i__ + 1 + i__ * a_dim1]; + a[i__ + 1 + i__ * a_dim1] = 1.f; + +/* Apply H(i) to A(i+1:m,i+1:n) from the left */ + + i__2 = *m - i__; + i__3 = *n - i__; + slarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], & + c__1, &tauq[i__], &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &work[1]); + a[i__ + 1 + i__ * a_dim1] = e[i__]; + } else { + tauq[i__] = 0.f; + } +/* L20: */ + } + } + return 0; + +/* End of SGEBD2 */ + +} /* sgebd2_ */ + +/* Subroutine */ int sgebrd_(integer *m, integer *n, real *a, integer *lda, + real *d__, real *e, real *tauq, real *taup, real *work, integer * + lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, nb, nx; + static real ws; + static integer nbmin, iinfo; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static integer minmn; + extern /* Subroutine */ int sgebd2_(integer *, integer *, real *, integer + *, real *, real *, real *, real *, real *, integer *), slabrd_( + integer *, integer *, integer *, real *, integer *, real *, real * + , real *, real *, real *, integer *, real *, integer *), xerbla_( + char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwrkx, ldwrky, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGEBRD reduces a general real M-by-N matrix A to upper or lower + bidiagonal form B by an orthogonal transformation: Q**T * A * P = B. + + If m >= n, B is upper bidiagonal; if m < n, B is lower bidiagonal. + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. M >= 0. + + N (input) INTEGER + The number of columns in the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the M-by-N general matrix to be reduced. + On exit, + if m >= n, the diagonal and the first superdiagonal are + overwritten with the upper bidiagonal matrix B; the + elements below the diagonal, with the array TAUQ, represent + the orthogonal matrix Q as a product of elementary + reflectors, and the elements above the first superdiagonal, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors; + if m < n, the diagonal and the first subdiagonal are + overwritten with the lower bidiagonal matrix B; the + elements below the first subdiagonal, with the array TAUQ, + represent the orthogonal matrix Q as a product of + elementary reflectors, and the elements above the diagonal, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) REAL array, dimension (min(M,N)) + The diagonal elements of the bidiagonal matrix B: + D(i) = A(i,i). + + E (output) REAL array, dimension (min(M,N)-1) + The off-diagonal elements of the bidiagonal matrix B: + if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1; + if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1. + + TAUQ (output) REAL array dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix Q. See Further Details. + + TAUP (output) REAL array, dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix P. See Further Details. + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. LWORK >= max(1,M,N). + For optimum performance LWORK >= (M+N)*NB, where NB + is the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + If m >= n, + + Q = H(1) H(2) . . . H(n) and P = G(1) G(2) . . . G(n-1) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors; + v(1:i-1) = 0, v(i) = 1, and v(i+1:m) is stored on exit in A(i+1:m,i); + u(1:i) = 0, u(i+1) = 1, and u(i+2:n) is stored on exit in A(i,i+2:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, + + Q = H(1) H(2) . . . H(m-1) and P = G(1) G(2) . . . G(m) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors; + v(1:i) = 0, v(i+1) = 1, and v(i+2:m) is stored on exit in A(i+2:m,i); + u(1:i-1) = 0, u(i) = 1, and u(i+1:n) is stored on exit in A(i,i+1:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + The contents of A on exit are illustrated by the following examples: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) + ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) + ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) + ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) + ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) + ( v1 v2 v3 v4 v5 ) + + where d and e denote diagonal and off-diagonal elements of B, vi + denotes an element of the vector defining H(i), and ui an element of + the vector defining G(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + --work; + + /* Function Body */ + *info = 0; +/* Computing MAX */ + i__1 = 1, i__2 = ilaenv_(&c__1, "SGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = max(i__1,i__2); + lwkopt = (*m + *n) * nb; + work[1] = (real) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = max(1,*m); + if (*lwork < max(i__1,*n) && ! lquery) { + *info = -10; + } + } + if (*info < 0) { + i__1 = -(*info); + xerbla_("SGEBRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + minmn = min(*m,*n); + if (minmn == 0) { + work[1] = 1.f; + return 0; + } + + ws = (real) max(*m,*n); + ldwrkx = *m; + ldwrky = *n; + + if (nb > 1 && nb < minmn) { + +/* + Set the crossover point NX. + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "SGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + +/* Determine when to switch from blocked to unblocked code. */ + + if (nx < minmn) { + ws = (real) ((*m + *n) * nb); + if ((real) (*lwork) < ws) { + +/* + Not enough work space for the optimal NB, consider using + a smaller block size. +*/ + + nbmin = ilaenv_(&c__2, "SGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + if (*lwork >= (*m + *n) * nbmin) { + nb = *lwork / (*m + *n); + } else { + nb = 1; + nx = minmn; + } + } + } + } else { + nx = minmn; + } + + i__1 = minmn - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + +/* + Reduce rows and columns i:i+nb-1 to bidiagonal form and return + the matrices X and Y which are needed to update the unreduced + part of the matrix +*/ + + i__3 = *m - i__ + 1; + i__4 = *n - i__ + 1; + slabrd_(&i__3, &i__4, &nb, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[ + i__], &tauq[i__], &taup[i__], &work[1], &ldwrkx, &work[ldwrkx + * nb + 1], &ldwrky); + +/* + Update the trailing submatrix A(i+nb:m,i+nb:n), using an update + of the form A := A - V*Y' - X*U' +*/ + + i__3 = *m - i__ - nb + 1; + i__4 = *n - i__ - nb + 1; + sgemm_("No transpose", "Transpose", &i__3, &i__4, &nb, &c_b151, &a[ + i__ + nb + i__ * a_dim1], lda, &work[ldwrkx * nb + nb + 1], & + ldwrky, &c_b15, &a[i__ + nb + (i__ + nb) * a_dim1], lda); + i__3 = *m - i__ - nb + 1; + i__4 = *n - i__ - nb + 1; + sgemm_("No transpose", "No transpose", &i__3, &i__4, &nb, &c_b151, & + work[nb + 1], &ldwrkx, &a[i__ + (i__ + nb) * a_dim1], lda, & + c_b15, &a[i__ + nb + (i__ + nb) * a_dim1], lda); + +/* Copy diagonal and off-diagonal elements of B back into A */ + + if (*m >= *n) { + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + a[j + j * a_dim1] = d__[j]; + a[j + (j + 1) * a_dim1] = e[j]; +/* L10: */ + } + } else { + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + a[j + j * a_dim1] = d__[j]; + a[j + 1 + j * a_dim1] = e[j]; +/* L20: */ + } + } +/* L30: */ + } + +/* Use unblocked code to reduce the remainder of the matrix */ + + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + sgebd2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], & + tauq[i__], &taup[i__], &work[1], &iinfo); + work[1] = ws; + return 0; + +/* End of SGEBRD */ + +} /* sgebrd_ */ + +/* Subroutine */ int sgeev_(char *jobvl, char *jobvr, integer *n, real *a, + integer *lda, real *wr, real *wi, real *vl, integer *ldvl, real *vr, + integer *ldvr, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, + i__2, i__3; + real r__1, r__2; + + /* Local variables */ + static integer i__, k; + static real r__, cs, sn; + static integer ihi; + static real scl; + static integer ilo; + static real dum[1], eps; + static integer ibal; + static char side[1]; + static real anrm; + static integer ierr, itau, iwrk, nout; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *); + extern doublereal snrm2_(integer *, real *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + extern doublereal slapy2_(real *, real *); + extern /* Subroutine */ int slabad_(real *, real *); + static logical scalea; + static real cscale; + extern /* Subroutine */ int sgebak_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, integer *, integer *), sgebal_(char *, integer *, real *, integer *, + integer *, integer *, real *, integer *); + extern doublereal slamch_(char *), slange_(char *, integer *, + integer *, real *, integer *, real *); + extern /* Subroutine */ int sgehrd_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *, integer *), xerbla_(char + *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical select[1]; + static real bignum; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *); + extern integer isamax_(integer *, real *, integer *); + extern /* Subroutine */ int slacpy_(char *, integer *, integer *, real *, + integer *, real *, integer *), slartg_(real *, real *, + real *, real *, real *), sorghr_(integer *, integer *, integer *, + real *, integer *, real *, real *, integer *, integer *), shseqr_( + char *, char *, integer *, integer *, integer *, real *, integer * + , real *, real *, real *, integer *, real *, integer *, integer *), strevc_(char *, char *, logical *, integer *, + real *, integer *, real *, integer *, real *, integer *, integer * + , integer *, real *, integer *); + static integer minwrk, maxwrk; + static logical wantvl; + static real smlnum; + static integer hswork; + static logical lquery, wantvr; + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGEEV computes for an N-by-N real nonsymmetric matrix A, the + eigenvalues and, optionally, the left and/or right eigenvectors. + + The right eigenvector v(j) of A satisfies + A * v(j) = lambda(j) * v(j) + where lambda(j) is its eigenvalue. + The left eigenvector u(j) of A satisfies + u(j)**H * A = lambda(j) * u(j)**H + where u(j)**H denotes the conjugate transpose of u(j). + + The computed eigenvectors are normalized to have Euclidean norm + equal to 1 and largest component real. + + Arguments + ========= + + JOBVL (input) CHARACTER*1 + = 'N': left eigenvectors of A are not computed; + = 'V': left eigenvectors of A are computed. + + JOBVR (input) CHARACTER*1 + = 'N': right eigenvectors of A are not computed; + = 'V': right eigenvectors of A are computed. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the N-by-N matrix A. + On exit, A has been overwritten. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + WR (output) REAL array, dimension (N) + WI (output) REAL array, dimension (N) + WR and WI contain the real and imaginary parts, + respectively, of the computed eigenvalues. Complex + conjugate pairs of eigenvalues appear consecutively + with the eigenvalue having the positive imaginary part + first. + + VL (output) REAL array, dimension (LDVL,N) + If JOBVL = 'V', the left eigenvectors u(j) are stored one + after another in the columns of VL, in the same order + as their eigenvalues. + If JOBVL = 'N', VL is not referenced. + If the j-th eigenvalue is real, then u(j) = VL(:,j), + the j-th column of VL. + If the j-th and (j+1)-st eigenvalues form a complex + conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and + u(j+1) = VL(:,j) - i*VL(:,j+1). + + LDVL (input) INTEGER + The leading dimension of the array VL. LDVL >= 1; if + JOBVL = 'V', LDVL >= N. + + VR (output) REAL array, dimension (LDVR,N) + If JOBVR = 'V', the right eigenvectors v(j) are stored one + after another in the columns of VR, in the same order + as their eigenvalues. + If JOBVR = 'N', VR is not referenced. + If the j-th eigenvalue is real, then v(j) = VR(:,j), + the j-th column of VR. + If the j-th and (j+1)-st eigenvalues form a complex + conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and + v(j+1) = VR(:,j) - i*VR(:,j+1). + + LDVR (input) INTEGER + The leading dimension of the array VR. LDVR >= 1; if + JOBVR = 'V', LDVR >= N. + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,3*N), and + if JOBVL = 'V' or JOBVR = 'V', LWORK >= 4*N. For good + performance, LWORK must generally be larger. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = i, the QR algorithm failed to compute all the + eigenvalues, and no eigenvectors have been computed; + elements i+1:N of WR and WI contain eigenvalues which + have converged. + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --wr; + --wi; + vl_dim1 = *ldvl; + vl_offset = 1 + vl_dim1; + vl -= vl_offset; + vr_dim1 = *ldvr; + vr_offset = 1 + vr_dim1; + vr -= vr_offset; + --work; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1; + wantvl = lsame_(jobvl, "V"); + wantvr = lsame_(jobvr, "V"); + if (! wantvl && ! lsame_(jobvl, "N")) { + *info = -1; + } else if (! wantvr && ! lsame_(jobvr, "N")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldvl < 1 || wantvl && *ldvl < *n) { + *info = -9; + } else if (*ldvr < 1 || wantvr && *ldvr < *n) { + *info = -11; + } + +/* + Compute workspace + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + NB refers to the optimal block size for the immediately + following subroutine, as returned by ILAENV. + HSWORK refers to the workspace preferred by SHSEQR, as + calculated below. HSWORK is computed assuming ILO=1 and IHI=N, + the worst case.) +*/ + + if (*info == 0) { + if (*n == 0) { + minwrk = 1; + maxwrk = 1; + } else { + maxwrk = (*n << 1) + *n * ilaenv_(&c__1, "SGEHRD", " ", n, &c__1, + n, &c__0, (ftnlen)6, (ftnlen)1); + if (wantvl) { + minwrk = *n << 2; +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + (*n - 1) * ilaenv_(&c__1, + "SORGHR", " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + shseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[ + 1], &vl[vl_offset], ldvl, &work[1], &c_n1, info); + hswork = work[1]; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = * + n + hswork; + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n << 2; + maxwrk = max(i__1,i__2); + } else if (wantvr) { + minwrk = *n << 2; +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + (*n - 1) * ilaenv_(&c__1, + "SORGHR", " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + shseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[ + 1], &vr[vr_offset], ldvr, &work[1], &c_n1, info); + hswork = work[1]; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = * + n + hswork; + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n << 2; + maxwrk = max(i__1,i__2); + } else { + minwrk = *n * 3; + shseqr_("E", "N", n, &c__1, n, &a[a_offset], lda, &wr[1], &wi[ + 1], &vr[vr_offset], ldvr, &work[1], &c_n1, info); + hswork = work[1]; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + 1, i__1 = max(i__1,i__2), i__2 = * + n + hswork; + maxwrk = max(i__1,i__2); + } + maxwrk = max(maxwrk,minwrk); + } + work[1] = (real) maxwrk; + + if (*lwork < minwrk && ! lquery) { + *info = -13; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGEEV ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Get machine constants */ + + eps = slamch_("P"); + smlnum = slamch_("S"); + bignum = 1.f / smlnum; + slabad_(&smlnum, &bignum); + smlnum = sqrt(smlnum) / eps; + bignum = 1.f / smlnum; + +/* Scale A if max element outside range [SMLNUM,BIGNUM] */ + + anrm = slange_("M", n, n, &a[a_offset], lda, dum); + scalea = FALSE_; + if (anrm > 0.f && anrm < smlnum) { + scalea = TRUE_; + cscale = smlnum; + } else if (anrm > bignum) { + scalea = TRUE_; + cscale = bignum; + } + if (scalea) { + slascl_("G", &c__0, &c__0, &anrm, &cscale, n, n, &a[a_offset], lda, & + ierr); + } + +/* + Balance the matrix + (Workspace: need N) +*/ + + ibal = 1; + sgebal_("B", n, &a[a_offset], lda, &ilo, &ihi, &work[ibal], &ierr); + +/* + Reduce to upper Hessenberg form + (Workspace: need 3*N, prefer 2*N+N*NB) +*/ + + itau = ibal + *n; + iwrk = itau + *n; + i__1 = *lwork - iwrk + 1; + sgehrd_(n, &ilo, &ihi, &a[a_offset], lda, &work[itau], &work[iwrk], &i__1, + &ierr); + + if (wantvl) { + +/* + Want left eigenvectors + Copy Householder vectors to VL +*/ + + *(unsigned char *)side = 'L'; + slacpy_("L", n, n, &a[a_offset], lda, &vl[vl_offset], ldvl) + ; + +/* + Generate orthogonal matrix in VL + (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB) +*/ + + i__1 = *lwork - iwrk + 1; + sorghr_(n, &ilo, &ihi, &vl[vl_offset], ldvl, &work[itau], &work[iwrk], + &i__1, &ierr); + +/* + Perform QR iteration, accumulating Schur vectors in VL + (Workspace: need N+1, prefer N+HSWORK (see comments) ) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + shseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], & + vl[vl_offset], ldvl, &work[iwrk], &i__1, info); + + if (wantvr) { + +/* + Want left and right eigenvectors + Copy Schur vectors to VR +*/ + + *(unsigned char *)side = 'B'; + slacpy_("F", n, n, &vl[vl_offset], ldvl, &vr[vr_offset], ldvr); + } + + } else if (wantvr) { + +/* + Want right eigenvectors + Copy Householder vectors to VR +*/ + + *(unsigned char *)side = 'R'; + slacpy_("L", n, n, &a[a_offset], lda, &vr[vr_offset], ldvr) + ; + +/* + Generate orthogonal matrix in VR + (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB) +*/ + + i__1 = *lwork - iwrk + 1; + sorghr_(n, &ilo, &ihi, &vr[vr_offset], ldvr, &work[itau], &work[iwrk], + &i__1, &ierr); + +/* + Perform QR iteration, accumulating Schur vectors in VR + (Workspace: need N+1, prefer N+HSWORK (see comments) ) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + shseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], & + vr[vr_offset], ldvr, &work[iwrk], &i__1, info); + + } else { + +/* + Compute eigenvalues only + (Workspace: need N+1, prefer N+HSWORK (see comments) ) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + shseqr_("E", "N", n, &ilo, &ihi, &a[a_offset], lda, &wr[1], &wi[1], & + vr[vr_offset], ldvr, &work[iwrk], &i__1, info); + } + +/* If INFO > 0 from SHSEQR, then quit */ + + if (*info > 0) { + goto L50; + } + + if (wantvl || wantvr) { + +/* + Compute left and/or right eigenvectors + (Workspace: need 4*N) +*/ + + strevc_(side, "B", select, n, &a[a_offset], lda, &vl[vl_offset], ldvl, + &vr[vr_offset], ldvr, n, &nout, &work[iwrk], &ierr); + } + + if (wantvl) { + +/* + Undo balancing of left eigenvectors + (Workspace: need N) +*/ + + sgebak_("B", "L", n, &ilo, &ihi, &work[ibal], n, &vl[vl_offset], ldvl, + &ierr); + +/* Normalize left eigenvectors and make largest component real */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if (wi[i__] == 0.f) { + scl = 1.f / snrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1); + sscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1); + } else if (wi[i__] > 0.f) { + r__1 = snrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1); + r__2 = snrm2_(n, &vl[(i__ + 1) * vl_dim1 + 1], &c__1); + scl = 1.f / slapy2_(&r__1, &r__2); + sscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1); + sscal_(n, &scl, &vl[(i__ + 1) * vl_dim1 + 1], &c__1); + i__2 = *n; + for (k = 1; k <= i__2; ++k) { +/* Computing 2nd power */ + r__1 = vl[k + i__ * vl_dim1]; +/* Computing 2nd power */ + r__2 = vl[k + (i__ + 1) * vl_dim1]; + work[iwrk + k - 1] = r__1 * r__1 + r__2 * r__2; +/* L10: */ + } + k = isamax_(n, &work[iwrk], &c__1); + slartg_(&vl[k + i__ * vl_dim1], &vl[k + (i__ + 1) * vl_dim1], + &cs, &sn, &r__); + srot_(n, &vl[i__ * vl_dim1 + 1], &c__1, &vl[(i__ + 1) * + vl_dim1 + 1], &c__1, &cs, &sn); + vl[k + (i__ + 1) * vl_dim1] = 0.f; + } +/* L20: */ + } + } + + if (wantvr) { + +/* + Undo balancing of right eigenvectors + (Workspace: need N) +*/ + + sgebak_("B", "R", n, &ilo, &ihi, &work[ibal], n, &vr[vr_offset], ldvr, + &ierr); + +/* Normalize right eigenvectors and make largest component real */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if (wi[i__] == 0.f) { + scl = 1.f / snrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1); + sscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1); + } else if (wi[i__] > 0.f) { + r__1 = snrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1); + r__2 = snrm2_(n, &vr[(i__ + 1) * vr_dim1 + 1], &c__1); + scl = 1.f / slapy2_(&r__1, &r__2); + sscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1); + sscal_(n, &scl, &vr[(i__ + 1) * vr_dim1 + 1], &c__1); + i__2 = *n; + for (k = 1; k <= i__2; ++k) { +/* Computing 2nd power */ + r__1 = vr[k + i__ * vr_dim1]; +/* Computing 2nd power */ + r__2 = vr[k + (i__ + 1) * vr_dim1]; + work[iwrk + k - 1] = r__1 * r__1 + r__2 * r__2; +/* L30: */ + } + k = isamax_(n, &work[iwrk], &c__1); + slartg_(&vr[k + i__ * vr_dim1], &vr[k + (i__ + 1) * vr_dim1], + &cs, &sn, &r__); + srot_(n, &vr[i__ * vr_dim1 + 1], &c__1, &vr[(i__ + 1) * + vr_dim1 + 1], &c__1, &cs, &sn); + vr[k + (i__ + 1) * vr_dim1] = 0.f; + } +/* L40: */ + } + } + +/* Undo scaling if necessary */ + +L50: + if (scalea) { + i__1 = *n - *info; +/* Computing MAX */ + i__3 = *n - *info; + i__2 = max(i__3,1); + slascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wr[*info + + 1], &i__2, &ierr); + i__1 = *n - *info; +/* Computing MAX */ + i__3 = *n - *info; + i__2 = max(i__3,1); + slascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wi[*info + + 1], &i__2, &ierr); + if (*info > 0) { + i__1 = ilo - 1; + slascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wr[1], + n, &ierr); + i__1 = ilo - 1; + slascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &wi[1], + n, &ierr); + } + } + + work[1] = (real) maxwrk; + return 0; + +/* End of SGEEV */ + +} /* sgeev_ */ + +/* Subroutine */ int sgehd2_(integer *n, integer *ilo, integer *ihi, real *a, + integer *lda, real *tau, real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__; + static real aii; + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), xerbla_( + char *, integer *), slarfg_(integer *, real *, real *, + integer *, real *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGEHD2 reduces a real general matrix A to upper Hessenberg form H by + an orthogonal similarity transformation: Q' * A * Q = H . + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that A is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to SGEBAL; otherwise they should be + set to 1 and N respectively. See Further Details. + 1 <= ILO <= IHI <= max(1,N). + + A (input/output) REAL array, dimension (LDA,N) + On entry, the n by n general matrix to be reduced. + On exit, the upper triangle and the first subdiagonal of A + are overwritten with the upper Hessenberg matrix H, and the + elements below the first subdiagonal, with the array TAU, + represent the orthogonal matrix Q as a product of elementary + reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) REAL array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) REAL array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrix Q is represented as a product of (ihi-ilo) elementary + reflectors + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on + exit in A(i+2:ihi,i), and tau in TAU(i). + + The contents of A are illustrated by the following example, with + n = 7, ilo = 2 and ihi = 6: + + on entry, on exit, + + ( a a a a a a a ) ( a a h h h h a ) + ( a a a a a a ) ( a h h h h a ) + ( a a a a a a ) ( h h h h h h ) + ( a a a a a a ) ( v2 h h h h h ) + ( a a a a a a ) ( v2 v3 h h h h ) + ( a a a a a a ) ( v2 v3 v4 h h h ) + ( a ) ( a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGEHD2", &i__1); + return 0; + } + + i__1 = *ihi - 1; + for (i__ = *ilo; i__ <= i__1; ++i__) { + +/* Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) */ + + i__2 = *ihi - i__; +/* Computing MIN */ + i__3 = i__ + 2; + slarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + i__ * + a_dim1], &c__1, &tau[i__]); + aii = a[i__ + 1 + i__ * a_dim1]; + a[i__ + 1 + i__ * a_dim1] = 1.f; + +/* Apply H(i) to A(1:ihi,i+1:ihi) from the right */ + + i__2 = *ihi - i__; + slarf_("Right", ihi, &i__2, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &a[(i__ + 1) * a_dim1 + 1], lda, &work[1]); + +/* Apply H(i) to A(i+1:ihi,i+1:n) from the left */ + + i__2 = *ihi - i__; + i__3 = *n - i__; + slarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &a[i__ + 1 + (i__ + 1) * a_dim1], lda, &work[1]); + + a[i__ + 1 + i__ * a_dim1] = aii; +/* L10: */ + } + + return 0; + +/* End of SGEHD2 */ + +} /* sgehd2_ */ + +/* Subroutine */ int sgehrd_(integer *n, integer *ilo, integer *ihi, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j; + static real t[4160] /* was [65][64] */; + static integer ib; + static real ei; + static integer nb, nh, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *), strmm_(char *, char *, char *, + char *, integer *, integer *, real *, real *, integer *, real *, + integer *), saxpy_(integer *, + real *, real *, integer *, real *, integer *), sgehd2_(integer *, + integer *, integer *, real *, integer *, real *, real *, integer * + ), slahr2_(integer *, integer *, integer *, real *, integer *, + real *, real *, integer *, real *, integer *), slarfb_(char *, + char *, char *, char *, integer *, integer *, integer *, real *, + integer *, real *, integer *, real *, integer *, real *, integer * + ), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + -- April 2009 -- + + + Purpose + ======= + + SGEHRD reduces a real general matrix A to upper Hessenberg form H by + an orthogonal similarity transformation: Q' * A * Q = H . + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that A is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to SGEBAL; otherwise they should be + set to 1 and N respectively. See Further Details. + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the N-by-N general matrix to be reduced. + On exit, the upper triangle and the first subdiagonal of A + are overwritten with the upper Hessenberg matrix H, and the + elements below the first subdiagonal, with the array TAU, + represent the orthogonal matrix Q as a product of elementary + reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) REAL array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). Elements 1:ILO-1 and IHI:N-1 of TAU are set to + zero. + + WORK (workspace/output) REAL array, dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrix Q is represented as a product of (ihi-ilo) elementary + reflectors + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on + exit in A(i+2:ihi,i), and tau in TAU(i). + + The contents of A are illustrated by the following example, with + n = 7, ilo = 2 and ihi = 6: + + on entry, on exit, + + ( a a a a a a a ) ( a a h h h h a ) + ( a a a a a a ) ( a h h h h a ) + ( a a a a a a ) ( h h h h h h ) + ( a a a a a a ) ( v2 h h h h h ) + ( a a a a a a ) ( v2 v3 h h h h ) + ( a a a a a a ) ( v2 v3 v4 h h h ) + ( a ) ( a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + This file is a slight modification of LAPACK-3.0's DGEHRD + subroutine incorporating improvements proposed by Quintana-Orti and + Van de Geijn (2006). (See DLAHR2.) + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; +/* Computing MIN */ + i__1 = 64, i__2 = ilaenv_(&c__1, "SGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = min(i__1,i__2); + lwkopt = *n * nb; + work[1] = (real) lwkopt; + lquery = *lwork == -1; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGEHRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Set elements 1:ILO-1 and IHI:N-1 of TAU to zero */ + + i__1 = *ilo - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + tau[i__] = 0.f; +/* L10: */ + } + i__1 = *n - 1; + for (i__ = max(1,*ihi); i__ <= i__1; ++i__) { + tau[i__] = 0.f; +/* L20: */ + } + +/* Quick return if possible */ + + nh = *ihi - *ilo + 1; + if (nh <= 1) { + work[1] = 1.f; + return 0; + } + +/* + Determine the block size + + Computing MIN +*/ + i__1 = 64, i__2 = ilaenv_(&c__1, "SGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = min(i__1,i__2); + nbmin = 2; + iws = 1; + if (nb > 1 && nb < nh) { + +/* + Determine when to cross over from blocked to unblocked code + (last block is always handled by unblocked code) + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "SGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < nh) { + +/* Determine if workspace is large enough for blocked code */ + + iws = *n * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: determine the + minimum value of NB, and reduce NB or force use of + unblocked code + + Computing MAX +*/ + i__1 = 2, i__2 = ilaenv_(&c__2, "SGEHRD", " ", n, ilo, ihi, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + if (*lwork >= *n * nbmin) { + nb = *lwork / *n; + } else { + nb = 1; + } + } + } + } + ldwork = *n; + + if (nb < nbmin || nb >= nh) { + +/* Use unblocked code below */ + + i__ = *ilo; + + } else { + +/* Use blocked code */ + + i__1 = *ihi - 1 - nx; + i__2 = nb; + for (i__ = *ilo; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = nb, i__4 = *ihi - i__; + ib = min(i__3,i__4); + +/* + Reduce columns i:i+ib-1 to Hessenberg form, returning the + matrices V and T of the block reflector H = I - V*T*V' + which performs the reduction, and also the matrix Y = A*V*T +*/ + + slahr2_(ihi, &i__, &ib, &a[i__ * a_dim1 + 1], lda, &tau[i__], t, & + c__65, &work[1], &ldwork); + +/* + Apply the block reflector H to A(1:ihi,i+ib:ihi) from the + right, computing A := A - Y * V'. V(i+ib,ib-1) must be set + to 1 +*/ + + ei = a[i__ + ib + (i__ + ib - 1) * a_dim1]; + a[i__ + ib + (i__ + ib - 1) * a_dim1] = 1.f; + i__3 = *ihi - i__ - ib + 1; + sgemm_("No transpose", "Transpose", ihi, &i__3, &ib, &c_b151, & + work[1], &ldwork, &a[i__ + ib + i__ * a_dim1], lda, & + c_b15, &a[(i__ + ib) * a_dim1 + 1], lda); + a[i__ + ib + (i__ + ib - 1) * a_dim1] = ei; + +/* + Apply the block reflector H to A(1:i,i+1:i+ib-1) from the + right +*/ + + i__3 = ib - 1; + strmm_("Right", "Lower", "Transpose", "Unit", &i__, &i__3, &c_b15, + &a[i__ + 1 + i__ * a_dim1], lda, &work[1], &ldwork); + i__3 = ib - 2; + for (j = 0; j <= i__3; ++j) { + saxpy_(&i__, &c_b151, &work[ldwork * j + 1], &c__1, &a[(i__ + + j + 1) * a_dim1 + 1], &c__1); +/* L30: */ + } + +/* + Apply the block reflector H to A(i+1:ihi,i+ib:n) from the + left +*/ + + i__3 = *ihi - i__; + i__4 = *n - i__ - ib + 1; + slarfb_("Left", "Transpose", "Forward", "Columnwise", &i__3, & + i__4, &ib, &a[i__ + 1 + i__ * a_dim1], lda, t, &c__65, &a[ + i__ + 1 + (i__ + ib) * a_dim1], lda, &work[1], &ldwork); +/* L40: */ + } + } + +/* Use unblocked code to reduce the rest of the matrix */ + + sgehd2_(n, &i__, ihi, &a[a_offset], lda, &tau[1], &work[1], &iinfo); + work[1] = (real) iws; + + return 0; + +/* End of SGEHRD */ + +} /* sgehrd_ */ + +/* Subroutine */ int sgelq2_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, k; + static real aii; + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), xerbla_( + char *, integer *), slarfg_(integer *, real *, real *, + integer *, real *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SGELQ2 computes an LQ factorization of a real m by n matrix A: + A = L * Q. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, the elements on and below the diagonal of the array + contain the m by min(m,n) lower trapezoidal matrix L (L is + lower triangular if m <= n); the elements above the diagonal, + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) REAL array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) REAL array, dimension (M) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(k) . . . H(2) H(1), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:n) is stored on exit in A(i,i+1:n), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGELQ2", &i__1); + return 0; + } + + k = min(*m,*n); + + i__1 = k; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + slarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[i__ + min(i__3,*n) * a_dim1] + , lda, &tau[i__]); + if (i__ < *m) { + +/* Apply H(i) to A(i+1:m,i:n) from the right */ + + aii = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.f; + i__2 = *m - i__; + i__3 = *n - i__ + 1; + slarf_("Right", &i__2, &i__3, &a[i__ + i__ * a_dim1], lda, &tau[ + i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + a[i__ + i__ * a_dim1] = aii; + } +/* L10: */ + } + return 0; + +/* End of SGELQ2 */ + +} /* sgelq2_ */ + +/* Subroutine */ int sgelqf_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, k, ib, nb, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int sgelq2_(integer *, integer *, real *, integer + *, real *, real *, integer *), slarfb_(char *, char *, char *, + char *, integer *, integer *, integer *, real *, integer *, real * + , integer *, real *, integer *, real *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slarft_(char *, char *, integer *, integer *, + real *, integer *, real *, real *, integer *); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGELQF computes an LQ factorization of a real M-by-N matrix A: + A = L * Q. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, the elements on and below the diagonal of the array + contain the m-by-min(m,n) lower trapezoidal matrix L (L is + lower triangular if m <= n); the elements above the diagonal, + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) REAL array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,M). + For optimum performance LWORK >= M*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(k) . . . H(2) H(1), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:n) is stored on exit in A(i,i+1:n), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "SGELQF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + lwkopt = *m * nb; + work[1] = (real) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else if (*lwork < max(1,*m) && ! lquery) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGELQF", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + k = min(*m,*n); + if (k == 0) { + work[1] = 1.f; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *m; + if (nb > 1 && nb < k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "SGELQF", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *m; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "SGELQF", " ", m, n, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < k && nx < k) { + +/* Use blocked code initially */ + + i__1 = k - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = k - i__ + 1; + ib = min(i__3,nb); + +/* + Compute the LQ factorization of the current block + A(i:i+ib-1,i:n) +*/ + + i__3 = *n - i__ + 1; + sgelq2_(&ib, &i__3, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[ + 1], &iinfo); + if (i__ + ib <= *m) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__3 = *n - i__ + 1; + slarft_("Forward", "Rowwise", &i__3, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H to A(i+ib:m,i:n) from the right */ + + i__3 = *m - i__ - ib + 1; + i__4 = *n - i__ + 1; + slarfb_("Right", "No transpose", "Forward", "Rowwise", &i__3, + &i__4, &ib, &a[i__ + i__ * a_dim1], lda, &work[1], & + ldwork, &a[i__ + ib + i__ * a_dim1], lda, &work[ib + + 1], &ldwork); + } +/* L10: */ + } + } else { + i__ = 1; + } + +/* Use unblocked code to factor the last or only block. */ + + if (i__ <= k) { + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + sgelq2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[1] + , &iinfo); + } + + work[1] = (real) iws; + return 0; + +/* End of SGELQF */ + +} /* sgelqf_ */ + +/* Subroutine */ int sgeqr2_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, k; + static real aii; + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), xerbla_( + char *, integer *), slarfg_(integer *, real *, real *, + integer *, real *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SGEQR2 computes a QR factorization of a real m by n matrix A: + A = Q * R. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, the elements on and above the diagonal of the array + contain the min(m,n) by n upper trapezoidal matrix R (R is + upper triangular if m >= n); the elements below the diagonal, + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) REAL array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) REAL array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(1) H(2) . . . H(k), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGEQR2", &i__1); + return 0; + } + + k = min(*m,*n); + + i__1 = k; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ + + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + slarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * a_dim1] + , &c__1, &tau[i__]); + if (i__ < *n) { + +/* Apply H(i) to A(i:m,i+1:n) from the left */ + + aii = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.f; + i__2 = *m - i__ + 1; + i__3 = *n - i__; + slarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, &tau[ + i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + a[i__ + i__ * a_dim1] = aii; + } +/* L10: */ + } + return 0; + +/* End of SGEQR2 */ + +} /* sgeqr2_ */ + +/* Subroutine */ int sgeqrf_(integer *m, integer *n, real *a, integer *lda, + real *tau, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, k, ib, nb, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int sgeqr2_(integer *, integer *, real *, integer + *, real *, real *, integer *), slarfb_(char *, char *, char *, + char *, integer *, integer *, integer *, real *, integer *, real * + , integer *, real *, integer *, real *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slarft_(char *, char *, integer *, integer *, + real *, integer *, real *, real *, integer *); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGEQRF computes a QR factorization of a real M-by-N matrix A: + A = Q * R. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, the elements on and above the diagonal of the array + contain the min(M,N)-by-N upper trapezoidal matrix R (R is + upper triangular if m >= n); the elements below the diagonal, + with the array TAU, represent the orthogonal matrix Q as a + product of min(m,n) elementary reflectors (see Further + Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) REAL array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(1) H(2) . . . H(k), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "SGEQRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + lwkopt = *n * nb; + work[1] = (real) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGEQRF", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + k = min(*m,*n); + if (k == 0) { + work[1] = 1.f; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *n; + if (nb > 1 && nb < k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "SGEQRF", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "SGEQRF", " ", m, n, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < k && nx < k) { + +/* Use blocked code initially */ + + i__1 = k - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = k - i__ + 1; + ib = min(i__3,nb); + +/* + Compute the QR factorization of the current block + A(i:m,i:i+ib-1) +*/ + + i__3 = *m - i__ + 1; + sgeqr2_(&i__3, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[ + 1], &iinfo); + if (i__ + ib <= *n) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__3 = *m - i__ + 1; + slarft_("Forward", "Columnwise", &i__3, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H' to A(i:m,i+ib:n) from the left */ + + i__3 = *m - i__ + 1; + i__4 = *n - i__ - ib + 1; + slarfb_("Left", "Transpose", "Forward", "Columnwise", &i__3, & + i__4, &ib, &a[i__ + i__ * a_dim1], lda, &work[1], & + ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, &work[ib + + 1], &ldwork); + } +/* L10: */ + } + } else { + i__ = 1; + } + +/* Use unblocked code to factor the last or only block. */ + + if (i__ <= k) { + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + sgeqr2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[1] + , &iinfo); + } + + work[1] = (real) iws; + return 0; + +/* End of SGEQRF */ + +} /* sgeqrf_ */ + +/* Subroutine */ int sgesdd_(char *jobz, integer *m, integer *n, real *a, + integer *lda, real *s, real *u, integer *ldu, real *vt, integer *ldvt, + real *work, integer *lwork, integer *iwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, u_dim1, u_offset, vt_dim1, vt_offset, i__1, + i__2, i__3; + + /* Local variables */ + static integer i__, ie, il, ir, iu, blk; + static real dum[1], eps; + static integer ivt, iscl; + static real anrm; + static integer idum[1], ierr, itau; + extern logical lsame_(char *, char *); + static integer chunk; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static integer minmn, wrkbl, itaup, itauq, mnthr; + static logical wntqa; + static integer nwork; + static logical wntqn, wntqo, wntqs; + static integer bdspac; + extern /* Subroutine */ int sbdsdc_(char *, char *, integer *, real *, + real *, real *, integer *, real *, integer *, real *, integer *, + real *, integer *, integer *), sgebrd_(integer *, + integer *, real *, integer *, real *, real *, real *, real *, + real *, integer *, integer *); + extern doublereal slamch_(char *), slange_(char *, integer *, + integer *, real *, integer *, real *); + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static real bignum; + extern /* Subroutine */ int sgelqf_(integer *, integer *, real *, integer + *, real *, real *, integer *, integer *), slascl_(char *, integer + *, integer *, real *, real *, integer *, integer *, real *, + integer *, integer *), sgeqrf_(integer *, integer *, real + *, integer *, real *, real *, integer *, integer *), slacpy_(char + *, integer *, integer *, real *, integer *, real *, integer *), slaset_(char *, integer *, integer *, real *, real *, + real *, integer *), sorgbr_(char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, integer * + ); + static integer ldwrkl; + extern /* Subroutine */ int sormbr_(char *, char *, char *, integer *, + integer *, integer *, real *, integer *, real *, real *, integer * + , real *, integer *, integer *); + static integer ldwrkr, minwrk, ldwrku, maxwrk; + extern /* Subroutine */ int sorglq_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *, integer *); + static integer ldwkvt; + static real smlnum; + static logical wntqas; + extern /* Subroutine */ int sorgqr_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *, integer *); + static logical lquery; + + +/* + -- LAPACK driver routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + March 2009 + + + Purpose + ======= + + SGESDD computes the singular value decomposition (SVD) of a real + M-by-N matrix A, optionally computing the left and right singular + vectors. If singular vectors are desired, it uses a + divide-and-conquer algorithm. + + The SVD is written + + A = U * SIGMA * transpose(V) + + where SIGMA is an M-by-N matrix which is zero except for its + min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and + V is an N-by-N orthogonal matrix. The diagonal elements of SIGMA + are the singular values of A; they are real and non-negative, and + are returned in descending order. The first min(m,n) columns of + U and V are the left and right singular vectors of A. + + Note that the routine returns VT = V**T, not V. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + JOBZ (input) CHARACTER*1 + Specifies options for computing all or part of the matrix U: + = 'A': all M columns of U and all N rows of V**T are + returned in the arrays U and VT; + = 'S': the first min(M,N) columns of U and the first + min(M,N) rows of V**T are returned in the arrays U + and VT; + = 'O': If M >= N, the first N columns of U are overwritten + on the array A and all rows of V**T are returned in + the array VT; + otherwise, all columns of U are returned in the + array U and the first M rows of V**T are overwritten + in the array A; + = 'N': no columns of U or rows of V**T are computed. + + M (input) INTEGER + The number of rows of the input matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the input matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, + if JOBZ = 'O', A is overwritten with the first N columns + of U (the left singular vectors, stored + columnwise) if M >= N; + A is overwritten with the first M rows + of V**T (the right singular vectors, stored + rowwise) otherwise. + if JOBZ .ne. 'O', the contents of A are destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + S (output) REAL array, dimension (min(M,N)) + The singular values of A, sorted so that S(i) >= S(i+1). + + U (output) REAL array, dimension (LDU,UCOL) + UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N; + UCOL = min(M,N) if JOBZ = 'S'. + If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M + orthogonal matrix U; + if JOBZ = 'S', U contains the first min(M,N) columns of U + (the left singular vectors, stored columnwise); + if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= 1; if + JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M. + + VT (output) REAL array, dimension (LDVT,N) + If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the + N-by-N orthogonal matrix V**T; + if JOBZ = 'S', VT contains the first min(M,N) rows of + V**T (the right singular vectors, stored rowwise); + if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= 1; if + JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N; + if JOBZ = 'S', LDVT >= min(M,N). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK; + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= 1. + If JOBZ = 'N', + LWORK >= 3*min(M,N) + max(max(M,N),6*min(M,N)). + If JOBZ = 'O', + LWORK >= 3*min(M,N) + + max(max(M,N),5*min(M,N)*min(M,N)+4*min(M,N)). + If JOBZ = 'S' or 'A' + LWORK >= 3*min(M,N) + + max(max(M,N),4*min(M,N)*min(M,N)+4*min(M,N)). + For good performance, LWORK should generally be larger. + If LWORK = -1 but other input arguments are legal, WORK(1) + returns the optimal LWORK. + + IWORK (workspace) INTEGER array, dimension (8*min(M,N)) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: SBDSDC did not converge, updating process failed. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --s; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + minmn = min(*m,*n); + wntqa = lsame_(jobz, "A"); + wntqs = lsame_(jobz, "S"); + wntqas = wntqa || wntqs; + wntqo = lsame_(jobz, "O"); + wntqn = lsame_(jobz, "N"); + lquery = *lwork == -1; + + if (! (wntqa || wntqs || wntqo || wntqn)) { + *info = -1; + } else if (*m < 0) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*ldu < 1 || wntqas && *ldu < *m || wntqo && *m < *n && *ldu < * + m) { + *info = -8; + } else if (*ldvt < 1 || wntqa && *ldvt < *n || wntqs && *ldvt < minmn || + wntqo && *m >= *n && *ldvt < *n) { + *info = -10; + } + +/* + Compute workspace + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + NB refers to the optimal block size for the immediately + following subroutine, as returned by ILAENV.) +*/ + + if (*info == 0) { + minwrk = 1; + maxwrk = 1; + if (*m >= *n && minmn > 0) { + +/* Compute space needed for SBDSDC */ + + mnthr = (integer) (minmn * 11.f / 6.f); + if (wntqn) { + bdspac = *n * 7; + } else { + bdspac = *n * 3 * *n + (*n << 2); + } + if (*m >= mnthr) { + if (wntqn) { + +/* Path 1 (M much larger than N, JOBZ='N') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "SGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + (*n << 1) * ilaenv_(&c__1, + "SGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n; + maxwrk = max(i__1,i__2); + minwrk = bdspac + *n; + } else if (wntqo) { + +/* Path 2 (M much larger than N, JOBZ='O') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "SGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *n * ilaenv_(&c__1, "SORGQR", + " ", m, n, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + (*n << 1) * ilaenv_(&c__1, + "SGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "QLN", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + (*n << 1) * *n; + minwrk = bdspac + (*n << 1) * *n + *n * 3; + } else if (wntqs) { + +/* Path 3 (M much larger than N, JOBZ='S') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "SGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *n * ilaenv_(&c__1, "SORGQR", + " ", m, n, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + (*n << 1) * ilaenv_(&c__1, + "SGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "QLN", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *n * *n; + minwrk = bdspac + *n * *n + *n * 3; + } else if (wntqa) { + +/* Path 4 (M much larger than N, JOBZ='A') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "SGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *m * ilaenv_(&c__1, "SORGQR", + " ", m, m, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + (*n << 1) * ilaenv_(&c__1, + "SGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "QLN", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *n * *n; + minwrk = bdspac + *n * *n + *n * 3; + } + } else { + +/* Path 5 (M at least N, but not much larger) */ + + wrkbl = *n * 3 + (*m + *n) * ilaenv_(&c__1, "SGEBRD", " ", m, + n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + if (wntqn) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + maxwrk = max(i__1,i__2); + minwrk = *n * 3 + max(*m,bdspac); + } else if (wntqo) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "QLN", m, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *m * *n; +/* Computing MAX */ + i__1 = *m, i__2 = *n * *n + bdspac; + minwrk = *n * 3 + max(i__1,i__2); + } else if (wntqs) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "QLN", m, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *n * 3; + maxwrk = max(i__1,i__2); + minwrk = *n * 3 + max(*m,bdspac); + } else if (wntqa) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "QLN", m, m, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n * 3 + *n * ilaenv_(&c__1, "SORMBR" + , "PRT", n, n, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = bdspac + *n * 3; + maxwrk = max(i__1,i__2); + minwrk = *n * 3 + max(*m,bdspac); + } + } + } else if (minmn > 0) { + +/* Compute space needed for SBDSDC */ + + mnthr = (integer) (minmn * 11.f / 6.f); + if (wntqn) { + bdspac = *m * 7; + } else { + bdspac = *m * 3 * *m + (*m << 2); + } + if (*n >= mnthr) { + if (wntqn) { + +/* Path 1t (N much larger than M, JOBZ='N') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "SGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + (*m << 1) * ilaenv_(&c__1, + "SGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m; + maxwrk = max(i__1,i__2); + minwrk = bdspac + *m; + } else if (wntqo) { + +/* Path 2t (N much larger than M, JOBZ='O') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "SGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *m * ilaenv_(&c__1, "SORGLQ", + " ", m, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + (*m << 1) * ilaenv_(&c__1, + "SGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "QLN", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "PRT", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + (*m << 1) * *m; + minwrk = bdspac + (*m << 1) * *m + *m * 3; + } else if (wntqs) { + +/* Path 3t (N much larger than M, JOBZ='S') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "SGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *m * ilaenv_(&c__1, "SORGLQ", + " ", m, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + (*m << 1) * ilaenv_(&c__1, + "SGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "QLN", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "PRT", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *m * *m; + minwrk = bdspac + *m * *m + *m * 3; + } else if (wntqa) { + +/* Path 4t (N much larger than M, JOBZ='A') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "SGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *n * ilaenv_(&c__1, "SORGLQ", + " ", n, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + (*m << 1) * ilaenv_(&c__1, + "SGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "QLN", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "PRT", m, m, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *m * *m; + minwrk = bdspac + *m * *m + *m * 3; + } + } else { + +/* Path 5t (N greater than M, but not much larger) */ + + wrkbl = *m * 3 + (*m + *n) * ilaenv_(&c__1, "SGEBRD", " ", m, + n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + if (wntqn) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + maxwrk = max(i__1,i__2); + minwrk = *m * 3 + max(*n,bdspac); + } else if (wntqo) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "QLN", m, m, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "PRT", m, n, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + wrkbl = max(i__1,i__2); + maxwrk = wrkbl + *m * *n; +/* Computing MAX */ + i__1 = *n, i__2 = *m * *m + bdspac; + minwrk = *m * 3 + max(i__1,i__2); + } else if (wntqs) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "QLN", m, m, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "PRT", m, n, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + maxwrk = max(i__1,i__2); + minwrk = *m * 3 + max(*n,bdspac); + } else if (wntqa) { +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "QLN", m, m, n, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m * 3 + *m * ilaenv_(&c__1, "SORMBR" + , "PRT", n, n, m, &c_n1, (ftnlen)6, (ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = bdspac + *m * 3; + maxwrk = max(i__1,i__2); + minwrk = *m * 3 + max(*n,bdspac); + } + } + } + maxwrk = max(maxwrk,minwrk); + work[1] = (real) maxwrk; + + if (*lwork < minwrk && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGESDD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Get machine constants */ + + eps = slamch_("P"); + smlnum = sqrt(slamch_("S")) / eps; + bignum = 1.f / smlnum; + +/* Scale A if max element outside range [SMLNUM,BIGNUM] */ + + anrm = slange_("M", m, n, &a[a_offset], lda, dum); + iscl = 0; + if (anrm > 0.f && anrm < smlnum) { + iscl = 1; + slascl_("G", &c__0, &c__0, &anrm, &smlnum, m, n, &a[a_offset], lda, & + ierr); + } else if (anrm > bignum) { + iscl = 1; + slascl_("G", &c__0, &c__0, &anrm, &bignum, m, n, &a[a_offset], lda, & + ierr); + } + + if (*m >= *n) { + +/* + A has at least as many rows as columns. If A has sufficiently + more rows than columns, first reduce using the QR + decomposition (if sufficient workspace available) +*/ + + if (*m >= mnthr) { + + if (wntqn) { + +/* + Path 1 (M much larger than N, JOBZ='N') + No singular vectors to be computed +*/ + + itau = 1; + nwork = itau + *n; + +/* + Compute A=Q*R + (Workspace: need 2*N, prefer N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + sgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Zero out below R */ + + i__1 = *n - 1; + i__2 = *n - 1; + slaset_("L", &i__1, &i__2, &c_b29, &c_b29, &a[a_dim1 + 2], + lda); + ie = 1; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A + (Workspace: need 4*N, prefer 3*N+2*N*NB) +*/ + + i__1 = *lwork - nwork + 1; + sgebrd_(n, n, &a[a_offset], lda, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + nwork = ie + *n; + +/* + Perform bidiagonal SVD, computing singular values only + (Workspace: need N+BDSPAC) +*/ + + sbdsdc_("U", "N", n, &s[1], &work[ie], dum, &c__1, dum, &c__1, + dum, idum, &work[nwork], &iwork[1], info); + + } else if (wntqo) { + +/* + Path 2 (M much larger than N, JOBZ = 'O') + N left singular vectors to be overwritten on A and + N right singular vectors to be computed in VT +*/ + + ir = 1; + +/* WORK(IR) is LDWRKR by N */ + + if (*lwork >= *lda * *n + *n * *n + *n * 3 + bdspac) { + ldwrkr = *lda; + } else { + ldwrkr = (*lwork - *n * *n - *n * 3 - bdspac) / *n; + } + itau = ir + ldwrkr * *n; + nwork = itau + *n; + +/* + Compute A=Q*R + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + sgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Copy R to WORK(IR), zeroing out below it */ + + slacpy_("U", n, n, &a[a_offset], lda, &work[ir], &ldwrkr); + i__1 = *n - 1; + i__2 = *n - 1; + slaset_("L", &i__1, &i__2, &c_b29, &c_b29, &work[ir + 1], & + ldwrkr); + +/* + Generate Q in A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + sorgqr_(m, n, n, &a[a_offset], lda, &work[itau], &work[nwork], + &i__1, &ierr); + ie = itau; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in VT, copying result to WORK(IR) + (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB) +*/ + + i__1 = *lwork - nwork + 1; + sgebrd_(n, n, &work[ir], &ldwrkr, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* WORK(IU) is N by N */ + + iu = nwork; + nwork = iu + *n * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in WORK(IU) and computing right + singular vectors of bidiagonal matrix in VT + (Workspace: need N+N*N+BDSPAC) +*/ + + sbdsdc_("U", "I", n, &s[1], &work[ie], &work[iu], n, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite WORK(IU) by left singular vectors of R + and VT by right singular vectors of R + (Workspace: need 2*N*N+3*N, prefer 2*N*N+2*N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", n, n, n, &work[ir], &ldwrkr, &work[ + itauq], &work[iu], n, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + sormbr_("P", "R", "T", n, n, n, &work[ir], &ldwrkr, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + +/* + Multiply Q in A by left singular vectors of R in + WORK(IU), storing result in WORK(IR) and copying to A + (Workspace: need 2*N*N, prefer N*N+M*N) +*/ + + i__1 = *m; + i__2 = ldwrkr; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrkr); + sgemm_("N", "N", &chunk, n, n, &c_b15, &a[i__ + a_dim1], + lda, &work[iu], n, &c_b29, &work[ir], &ldwrkr); + slacpy_("F", &chunk, n, &work[ir], &ldwrkr, &a[i__ + + a_dim1], lda); +/* L10: */ + } + + } else if (wntqs) { + +/* + Path 3 (M much larger than N, JOBZ='S') + N left singular vectors to be computed in U and + N right singular vectors to be computed in VT +*/ + + ir = 1; + +/* WORK(IR) is N by N */ + + ldwrkr = *n; + itau = ir + ldwrkr * *n; + nwork = itau + *n; + +/* + Compute A=Q*R + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Copy R to WORK(IR), zeroing out below it */ + + slacpy_("U", n, n, &a[a_offset], lda, &work[ir], &ldwrkr); + i__2 = *n - 1; + i__1 = *n - 1; + slaset_("L", &i__2, &i__1, &c_b29, &c_b29, &work[ir + 1], & + ldwrkr); + +/* + Generate Q in A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sorgqr_(m, n, n, &a[a_offset], lda, &work[itau], &work[nwork], + &i__2, &ierr); + ie = itau; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in WORK(IR) + (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgebrd_(n, n, &work[ir], &ldwrkr, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagoal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need N+BDSPAC) +*/ + + sbdsdc_("U", "I", n, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of R and VT + by right singular vectors of R + (Workspace: need N*N+3*N, prefer N*N+2*N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", n, n, n, &work[ir], &ldwrkr, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + + i__2 = *lwork - nwork + 1; + sormbr_("P", "R", "T", n, n, n, &work[ir], &ldwrkr, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply Q in A by left singular vectors of R in + WORK(IR), storing result in U + (Workspace: need N*N) +*/ + + slacpy_("F", n, n, &u[u_offset], ldu, &work[ir], &ldwrkr); + sgemm_("N", "N", m, n, n, &c_b15, &a[a_offset], lda, &work[ir] + , &ldwrkr, &c_b29, &u[u_offset], ldu); + + } else if (wntqa) { + +/* + Path 4 (M much larger than N, JOBZ='A') + M left singular vectors to be computed in U and + N right singular vectors to be computed in VT +*/ + + iu = 1; + +/* WORK(IU) is N by N */ + + ldwrku = *n; + itau = iu + ldwrku * *n; + nwork = itau + *n; + +/* + Compute A=Q*R, copying result to U + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + slacpy_("L", m, n, &a[a_offset], lda, &u[u_offset], ldu); + +/* + Generate Q in U + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + i__2 = *lwork - nwork + 1; + sorgqr_(m, m, n, &u[u_offset], ldu, &work[itau], &work[nwork], + &i__2, &ierr); + +/* Produce R in A, zeroing out other entries */ + + i__2 = *n - 1; + i__1 = *n - 1; + slaset_("L", &i__2, &i__1, &c_b29, &c_b29, &a[a_dim1 + 2], + lda); + ie = itau; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A + (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgebrd_(n, n, &a[a_offset], lda, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in WORK(IU) and computing right + singular vectors of bidiagonal matrix in VT + (Workspace: need N+N*N+BDSPAC) +*/ + + sbdsdc_("U", "I", n, &s[1], &work[ie], &work[iu], n, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite WORK(IU) by left singular vectors of R and VT + by right singular vectors of R + (Workspace: need N*N+3*N, prefer N*N+2*N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", n, n, n, &a[a_offset], lda, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__2, & + ierr); + i__2 = *lwork - nwork + 1; + sormbr_("P", "R", "T", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply Q in U by left singular vectors of R in + WORK(IU), storing result in A + (Workspace: need N*N) +*/ + + sgemm_("N", "N", m, n, n, &c_b15, &u[u_offset], ldu, &work[iu] + , &ldwrku, &c_b29, &a[a_offset], lda); + +/* Copy left singular vectors of A from A to U */ + + slacpy_("F", m, n, &a[a_offset], lda, &u[u_offset], ldu); + + } + + } else { + +/* + M .LT. MNTHR + + Path 5 (M at least N, but not much larger) + Reduce to bidiagonal form without QR decomposition +*/ + + ie = 1; + itauq = ie + *n; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize A + (Workspace: need 3*N+M, prefer 3*N+(M+N)*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgebrd_(m, n, &a[a_offset], lda, &s[1], &work[ie], &work[itauq], & + work[itaup], &work[nwork], &i__2, &ierr); + if (wntqn) { + +/* + Perform bidiagonal SVD, only computing singular values + (Workspace: need N+BDSPAC) +*/ + + sbdsdc_("U", "N", n, &s[1], &work[ie], dum, &c__1, dum, &c__1, + dum, idum, &work[nwork], &iwork[1], info); + } else if (wntqo) { + iu = nwork; + if (*lwork >= *m * *n + *n * 3 + bdspac) { + +/* WORK( IU ) is M by N */ + + ldwrku = *m; + nwork = iu + ldwrku * *n; + slaset_("F", m, n, &c_b29, &c_b29, &work[iu], &ldwrku); + } else { + +/* WORK( IU ) is N by N */ + + ldwrku = *n; + nwork = iu + ldwrku * *n; + +/* WORK(IR) is LDWRKR by N */ + + ir = nwork; + ldwrkr = (*lwork - *n * *n - *n * 3) / *n; + } + nwork = iu + ldwrku * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in WORK(IU) and computing right + singular vectors of bidiagonal matrix in VT + (Workspace: need N+N*N+BDSPAC) +*/ + + sbdsdc_("U", "I", n, &s[1], &work[ie], &work[iu], &ldwrku, & + vt[vt_offset], ldvt, dum, idum, &work[nwork], &iwork[ + 1], info); + +/* + Overwrite VT by right singular vectors of A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sormbr_("P", "R", "T", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + + if (*lwork >= *m * *n + *n * 3 + bdspac) { + +/* + Overwrite WORK(IU) by left singular vectors of A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, n, n, &a[a_offset], lda, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__2, & + ierr); + +/* Copy left singular vectors of A from WORK(IU) to A */ + + slacpy_("F", m, n, &work[iu], &ldwrku, &a[a_offset], lda); + } else { + +/* + Generate Q in A + (Workspace: need N*N+2*N, prefer N*N+N+N*NB) +*/ + + i__2 = *lwork - nwork + 1; + sorgbr_("Q", m, n, n, &a[a_offset], lda, &work[itauq], & + work[nwork], &i__2, &ierr); + +/* + Multiply Q in A by left singular vectors of + bidiagonal matrix in WORK(IU), storing result in + WORK(IR) and copying to A + (Workspace: need 2*N*N, prefer N*N+M*N) +*/ + + i__2 = *m; + i__1 = ldwrkr; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrkr); + sgemm_("N", "N", &chunk, n, n, &c_b15, &a[i__ + + a_dim1], lda, &work[iu], &ldwrku, &c_b29, & + work[ir], &ldwrkr); + slacpy_("F", &chunk, n, &work[ir], &ldwrkr, &a[i__ + + a_dim1], lda); +/* L20: */ + } + } + + } else if (wntqs) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need N+BDSPAC) +*/ + + slaset_("F", m, n, &c_b29, &c_b29, &u[u_offset], ldu); + sbdsdc_("U", "I", n, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of A and VT + by right singular vectors of A + (Workspace: need 3*N, prefer 2*N+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, n, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + sormbr_("P", "R", "T", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } else if (wntqa) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need N+BDSPAC) +*/ + + slaset_("F", m, m, &c_b29, &c_b29, &u[u_offset], ldu); + sbdsdc_("U", "I", n, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* Set the right corner of U to identity matrix */ + + if (*m > *n) { + i__1 = *m - *n; + i__2 = *m - *n; + slaset_("F", &i__1, &i__2, &c_b29, &c_b15, &u[*n + 1 + (* + n + 1) * u_dim1], ldu); + } + +/* + Overwrite U by left singular vectors of A and VT + by right singular vectors of A + (Workspace: need N*N+2*N+M, prefer N*N+2*N+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + sormbr_("P", "R", "T", n, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } + + } + + } else { + +/* + A has more columns than rows. If A has sufficiently more + columns than rows, first reduce using the LQ decomposition (if + sufficient workspace available) +*/ + + if (*n >= mnthr) { + + if (wntqn) { + +/* + Path 1t (N much larger than M, JOBZ='N') + No singular vectors to be computed +*/ + + itau = 1; + nwork = itau + *m; + +/* + Compute A=L*Q + (Workspace: need 2*M, prefer M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + sgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Zero out above L */ + + i__1 = *m - 1; + i__2 = *m - 1; + slaset_("U", &i__1, &i__2, &c_b29, &c_b29, &a[(a_dim1 << 1) + + 1], lda); + ie = 1; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in A + (Workspace: need 4*M, prefer 3*M+2*M*NB) +*/ + + i__1 = *lwork - nwork + 1; + sgebrd_(m, m, &a[a_offset], lda, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + nwork = ie + *m; + +/* + Perform bidiagonal SVD, computing singular values only + (Workspace: need M+BDSPAC) +*/ + + sbdsdc_("U", "N", m, &s[1], &work[ie], dum, &c__1, dum, &c__1, + dum, idum, &work[nwork], &iwork[1], info); + + } else if (wntqo) { + +/* + Path 2t (N much larger than M, JOBZ='O') + M right singular vectors to be overwritten on A and + M left singular vectors to be computed in U +*/ + + ivt = 1; + +/* IVT is M by M */ + + il = ivt + *m * *m; + if (*lwork >= *m * *n + *m * *m + *m * 3 + bdspac) { + +/* WORK(IL) is M by N */ + + ldwrkl = *m; + chunk = *n; + } else { + ldwrkl = *m; + chunk = (*lwork - *m * *m) / *m; + } + itau = il + ldwrkl * *m; + nwork = itau + *m; + +/* + Compute A=L*Q + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + sgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Copy L to WORK(IL), zeroing about above it */ + + slacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwrkl); + i__1 = *m - 1; + i__2 = *m - 1; + slaset_("U", &i__1, &i__2, &c_b29, &c_b29, &work[il + ldwrkl], + &ldwrkl); + +/* + Generate Q in A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + sorglq_(m, n, m, &a[a_offset], lda, &work[itau], &work[nwork], + &i__1, &ierr); + ie = itau; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IL) + (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB) +*/ + + i__1 = *lwork - nwork + 1; + sgebrd_(m, m, &work[il], &ldwrkl, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U, and computing right singular + vectors of bidiagonal matrix in WORK(IVT) + (Workspace: need M+M*M+BDSPAC) +*/ + + sbdsdc_("U", "I", m, &s[1], &work[ie], &u[u_offset], ldu, & + work[ivt], m, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of L and WORK(IVT) + by right singular vectors of L + (Workspace: need 2*M*M+3*M, prefer 2*M*M+2*M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, m, m, &work[il], &ldwrkl, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + sormbr_("P", "R", "T", m, m, m, &work[il], &ldwrkl, &work[ + itaup], &work[ivt], m, &work[nwork], &i__1, &ierr); + +/* + Multiply right singular vectors of L in WORK(IVT) by Q + in A, storing result in WORK(IL) and copying to A + (Workspace: need 2*M*M, prefer M*M+M*N) +*/ + + i__1 = *n; + i__2 = chunk; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + sgemm_("N", "N", m, &blk, m, &c_b15, &work[ivt], m, &a[ + i__ * a_dim1 + 1], lda, &c_b29, &work[il], & + ldwrkl); + slacpy_("F", m, &blk, &work[il], &ldwrkl, &a[i__ * a_dim1 + + 1], lda); +/* L30: */ + } + + } else if (wntqs) { + +/* + Path 3t (N much larger than M, JOBZ='S') + M right singular vectors to be computed in VT and + M left singular vectors to be computed in U +*/ + + il = 1; + +/* WORK(IL) is M by M */ + + ldwrkl = *m; + itau = il + ldwrkl * *m; + nwork = itau + *m; + +/* + Compute A=L*Q + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Copy L to WORK(IL), zeroing out above it */ + + slacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwrkl); + i__2 = *m - 1; + i__1 = *m - 1; + slaset_("U", &i__2, &i__1, &c_b29, &c_b29, &work[il + ldwrkl], + &ldwrkl); + +/* + Generate Q in A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sorglq_(m, n, m, &a[a_offset], lda, &work[itau], &work[nwork], + &i__2, &ierr); + ie = itau; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IU), copying result to U + (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgebrd_(m, m, &work[il], &ldwrkl, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need M+BDSPAC) +*/ + + sbdsdc_("U", "I", m, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of L and VT + by right singular vectors of L + (Workspace: need M*M+3*M, prefer M*M+2*M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, m, m, &work[il], &ldwrkl, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + i__2 = *lwork - nwork + 1; + sormbr_("P", "R", "T", m, m, m, &work[il], &ldwrkl, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply right singular vectors of L in WORK(IL) by + Q in A, storing result in VT + (Workspace: need M*M) +*/ + + slacpy_("F", m, m, &vt[vt_offset], ldvt, &work[il], &ldwrkl); + sgemm_("N", "N", m, n, m, &c_b15, &work[il], &ldwrkl, &a[ + a_offset], lda, &c_b29, &vt[vt_offset], ldvt); + + } else if (wntqa) { + +/* + Path 4t (N much larger than M, JOBZ='A') + N right singular vectors to be computed in VT and + M left singular vectors to be computed in U +*/ + + ivt = 1; + +/* WORK(IVT) is M by M */ + + ldwkvt = *m; + itau = ivt + ldwkvt * *m; + nwork = itau + *m; + +/* + Compute A=L*Q, copying result to VT + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + slacpy_("U", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + +/* + Generate Q in VT + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sorglq_(n, n, m, &vt[vt_offset], ldvt, &work[itau], &work[ + nwork], &i__2, &ierr); + +/* Produce L in A, zeroing out other entries */ + + i__2 = *m - 1; + i__1 = *m - 1; + slaset_("U", &i__2, &i__1, &c_b29, &c_b29, &a[(a_dim1 << 1) + + 1], lda); + ie = itau; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in A + (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgebrd_(m, m, &a[a_offset], lda, &s[1], &work[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in WORK(IVT) + (Workspace: need M+M*M+BDSPAC) +*/ + + sbdsdc_("U", "I", m, &s[1], &work[ie], &u[u_offset], ldu, & + work[ivt], &ldwkvt, dum, idum, &work[nwork], &iwork[1] + , info); + +/* + Overwrite U by left singular vectors of L and WORK(IVT) + by right singular vectors of L + (Workspace: need M*M+3*M, prefer M*M+2*M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, m, m, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + i__2 = *lwork - nwork + 1; + sormbr_("P", "R", "T", m, m, m, &a[a_offset], lda, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply right singular vectors of L in WORK(IVT) by + Q in VT, storing result in A + (Workspace: need M*M) +*/ + + sgemm_("N", "N", m, n, m, &c_b15, &work[ivt], &ldwkvt, &vt[ + vt_offset], ldvt, &c_b29, &a[a_offset], lda); + +/* Copy right singular vectors of A from A to VT */ + + slacpy_("F", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + + } + + } else { + +/* + N .LT. MNTHR + + Path 5t (N greater than M, but not much larger) + Reduce to bidiagonal form without LQ decomposition +*/ + + ie = 1; + itauq = ie + *m; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize A + (Workspace: need 3*M+N, prefer 3*M+(M+N)*NB) +*/ + + i__2 = *lwork - nwork + 1; + sgebrd_(m, n, &a[a_offset], lda, &s[1], &work[ie], &work[itauq], & + work[itaup], &work[nwork], &i__2, &ierr); + if (wntqn) { + +/* + Perform bidiagonal SVD, only computing singular values + (Workspace: need M+BDSPAC) +*/ + + sbdsdc_("L", "N", m, &s[1], &work[ie], dum, &c__1, dum, &c__1, + dum, idum, &work[nwork], &iwork[1], info); + } else if (wntqo) { + ldwkvt = *m; + ivt = nwork; + if (*lwork >= *m * *n + *m * 3 + bdspac) { + +/* WORK( IVT ) is M by N */ + + slaset_("F", m, n, &c_b29, &c_b29, &work[ivt], &ldwkvt); + nwork = ivt + ldwkvt * *n; + } else { + +/* WORK( IVT ) is M by M */ + + nwork = ivt + ldwkvt * *m; + il = nwork; + +/* WORK(IL) is M by CHUNK */ + + chunk = (*lwork - *m * *m - *m * 3) / *m; + } + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in WORK(IVT) + (Workspace: need M*M+BDSPAC) +*/ + + sbdsdc_("L", "I", m, &s[1], &work[ie], &u[u_offset], ldu, & + work[ivt], &ldwkvt, dum, idum, &work[nwork], &iwork[1] + , info); + +/* + Overwrite U by left singular vectors of A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + + if (*lwork >= *m * *n + *m * 3 + bdspac) { + +/* + Overwrite WORK(IVT) by left singular vectors of A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sormbr_("P", "R", "T", m, n, m, &a[a_offset], lda, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__2, + &ierr); + +/* Copy right singular vectors of A from WORK(IVT) to A */ + + slacpy_("F", m, n, &work[ivt], &ldwkvt, &a[a_offset], lda); + } else { + +/* + Generate P**T in A + (Workspace: need M*M+2*M, prefer M*M+M+M*NB) +*/ + + i__2 = *lwork - nwork + 1; + sorgbr_("P", m, n, m, &a[a_offset], lda, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Multiply Q in A by right singular vectors of + bidiagonal matrix in WORK(IVT), storing result in + WORK(IL) and copying to A + (Workspace: need 2*M*M, prefer M*M+M*N) +*/ + + i__2 = *n; + i__1 = chunk; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + sgemm_("N", "N", m, &blk, m, &c_b15, &work[ivt], & + ldwkvt, &a[i__ * a_dim1 + 1], lda, &c_b29, & + work[il], m); + slacpy_("F", m, &blk, &work[il], m, &a[i__ * a_dim1 + + 1], lda); +/* L40: */ + } + } + } else if (wntqs) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need M+BDSPAC) +*/ + + slaset_("F", m, n, &c_b29, &c_b29, &vt[vt_offset], ldvt); + sbdsdc_("L", "I", m, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* + Overwrite U by left singular vectors of A and VT + by right singular vectors of A + (Workspace: need 3*M, prefer 2*M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + sormbr_("P", "R", "T", m, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } else if (wntqa) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in U and computing right singular + vectors of bidiagonal matrix in VT + (Workspace: need M+BDSPAC) +*/ + + slaset_("F", n, n, &c_b29, &c_b29, &vt[vt_offset], ldvt); + sbdsdc_("L", "I", m, &s[1], &work[ie], &u[u_offset], ldu, &vt[ + vt_offset], ldvt, dum, idum, &work[nwork], &iwork[1], + info); + +/* Set the right corner of VT to identity matrix */ + + if (*n > *m) { + i__1 = *n - *m; + i__2 = *n - *m; + slaset_("F", &i__1, &i__2, &c_b29, &c_b15, &vt[*m + 1 + (* + m + 1) * vt_dim1], ldvt); + } + +/* + Overwrite U by left singular vectors of A and VT + by right singular vectors of A + (Workspace: need 2*M+N, prefer 2*M+N*NB) +*/ + + i__1 = *lwork - nwork + 1; + sormbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + i__1 = *lwork - nwork + 1; + sormbr_("P", "R", "T", n, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } + + } + + } + +/* Undo scaling if necessary */ + + if (iscl == 1) { + if (anrm > bignum) { + slascl_("G", &c__0, &c__0, &bignum, &anrm, &minmn, &c__1, &s[1], & + minmn, &ierr); + } + if (anrm < smlnum) { + slascl_("G", &c__0, &c__0, &smlnum, &anrm, &minmn, &c__1, &s[1], & + minmn, &ierr); + } + } + +/* Return optimal workspace in WORK(1) */ + + work[1] = (real) maxwrk; + + return 0; + +/* End of SGESDD */ + +} /* sgesdd_ */ + +/* Subroutine */ int sgesv_(integer *n, integer *nrhs, real *a, integer *lda, + integer *ipiv, real *b, integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern /* Subroutine */ int xerbla_(char *, integer *), sgetrf_( + integer *, integer *, real *, integer *, integer *, integer *), + sgetrs_(char *, integer *, integer *, real *, integer *, integer * + , real *, integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGESV computes the solution to a real system of linear equations + A * X = B, + where A is an N-by-N matrix and X and B are N-by-NRHS matrices. + + The LU decomposition with partial pivoting and row interchanges is + used to factor A as + A = P * L * U, + where P is a permutation matrix, L is unit lower triangular, and U is + upper triangular. The factored form of A is then used to solve the + system of equations A * X = B. + + Arguments + ========= + + N (input) INTEGER + The number of linear equations, i.e., the order of the + matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the N-by-N coefficient matrix A. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (output) INTEGER array, dimension (N) + The pivot indices that define the permutation matrix P; + row i of the matrix was interchanged with row IPIV(i). + + B (input/output) REAL array, dimension (LDB,NRHS) + On entry, the N-by-NRHS matrix of right hand side matrix B. + On exit, if INFO = 0, the N-by-NRHS solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, so the solution could not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*nrhs < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGESV ", &i__1); + return 0; + } + +/* Compute the LU factorization of A. */ + + sgetrf_(n, n, &a[a_offset], lda, &ipiv[1], info); + if (*info == 0) { + +/* Solve the system A*X = B, overwriting B with X. */ + + sgetrs_("No transpose", n, nrhs, &a[a_offset], lda, &ipiv[1], &b[ + b_offset], ldb, info); + } + return 0; + +/* End of SGESV */ + +} /* sgesv_ */ + +/* Subroutine */ int sgetf2_(integer *m, integer *n, real *a, integer *lda, + integer *ipiv, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + real r__1; + + /* Local variables */ + static integer i__, j, jp; + extern /* Subroutine */ int sger_(integer *, integer *, real *, real *, + integer *, real *, integer *, real *, integer *), sscal_(integer * + , real *, real *, integer *); + static real sfmin; + extern /* Subroutine */ int sswap_(integer *, real *, integer *, real *, + integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer isamax_(integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGETF2 computes an LU factorization of a general m-by-n matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 2 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the m by n matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, U(k,k) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGETF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Compute machine safe minimum */ + + sfmin = slamch_("S"); + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + +/* Find pivot and test for singularity. */ + + i__2 = *m - j + 1; + jp = j - 1 + isamax_(&i__2, &a[j + j * a_dim1], &c__1); + ipiv[j] = jp; + if (a[jp + j * a_dim1] != 0.f) { + +/* Apply the interchange to columns 1:N. */ + + if (jp != j) { + sswap_(n, &a[j + a_dim1], lda, &a[jp + a_dim1], lda); + } + +/* Compute elements J+1:M of J-th column. */ + + if (j < *m) { + if ((r__1 = a[j + j * a_dim1], dabs(r__1)) >= sfmin) { + i__2 = *m - j; + r__1 = 1.f / a[j + j * a_dim1]; + sscal_(&i__2, &r__1, &a[j + 1 + j * a_dim1], &c__1); + } else { + i__2 = *m - j; + for (i__ = 1; i__ <= i__2; ++i__) { + a[j + i__ + j * a_dim1] /= a[j + j * a_dim1]; +/* L20: */ + } + } + } + + } else if (*info == 0) { + + *info = j; + } + + if (j < min(*m,*n)) { + +/* Update trailing submatrix. */ + + i__2 = *m - j; + i__3 = *n - j; + sger_(&i__2, &i__3, &c_b151, &a[j + 1 + j * a_dim1], &c__1, &a[j + + (j + 1) * a_dim1], lda, &a[j + 1 + (j + 1) * a_dim1], + lda); + } +/* L10: */ + } + return 0; + +/* End of SGETF2 */ + +} /* sgetf2_ */ + +/* Subroutine */ int sgetrf_(integer *m, integer *n, real *a, integer *lda, + integer *ipiv, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + + /* Local variables */ + static integer i__, j, jb, nb, iinfo; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *), strsm_(char *, char *, char *, + char *, integer *, integer *, real *, real *, integer *, real *, + integer *), sgetf2_(integer *, + integer *, real *, integer *, integer *, integer *), xerbla_(char + *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slaswp_(integer *, real *, integer *, integer + *, integer *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGETRF computes an LU factorization of a general M-by-N matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 3 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the M-by-N matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGETRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "SGETRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + if (nb <= 1 || nb >= min(*m,*n)) { + +/* Use unblocked code. */ + + sgetf2_(m, n, &a[a_offset], lda, &ipiv[1], info); + } else { + +/* Use blocked code. */ + + i__1 = min(*m,*n); + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { +/* Computing MIN */ + i__3 = min(*m,*n) - j + 1; + jb = min(i__3,nb); + +/* + Factor diagonal and subdiagonal blocks and test for exact + singularity. +*/ + + i__3 = *m - j + 1; + sgetf2_(&i__3, &jb, &a[j + j * a_dim1], lda, &ipiv[j], &iinfo); + +/* Adjust INFO and the pivot indices. */ + + if (*info == 0 && iinfo > 0) { + *info = iinfo + j - 1; + } +/* Computing MIN */ + i__4 = *m, i__5 = j + jb - 1; + i__3 = min(i__4,i__5); + for (i__ = j; i__ <= i__3; ++i__) { + ipiv[i__] = j - 1 + ipiv[i__]; +/* L10: */ + } + +/* Apply interchanges to columns 1:J-1. */ + + i__3 = j - 1; + i__4 = j + jb - 1; + slaswp_(&i__3, &a[a_offset], lda, &j, &i__4, &ipiv[1], &c__1); + + if (j + jb <= *n) { + +/* Apply interchanges to columns J+JB:N. */ + + i__3 = *n - j - jb + 1; + i__4 = j + jb - 1; + slaswp_(&i__3, &a[(j + jb) * a_dim1 + 1], lda, &j, &i__4, & + ipiv[1], &c__1); + +/* Compute block row of U. */ + + i__3 = *n - j - jb + 1; + strsm_("Left", "Lower", "No transpose", "Unit", &jb, &i__3, & + c_b15, &a[j + j * a_dim1], lda, &a[j + (j + jb) * + a_dim1], lda); + if (j + jb <= *m) { + +/* Update trailing submatrix. */ + + i__3 = *m - j - jb + 1; + i__4 = *n - j - jb + 1; + sgemm_("No transpose", "No transpose", &i__3, &i__4, &jb, + &c_b151, &a[j + jb + j * a_dim1], lda, &a[j + (j + + jb) * a_dim1], lda, &c_b15, &a[j + jb + (j + jb) + * a_dim1], lda); + } + } +/* L20: */ + } + } + return 0; + +/* End of SGETRF */ + +} /* sgetrf_ */ + +/* Subroutine */ int sgetrs_(char *trans, integer *n, integer *nrhs, real *a, + integer *lda, integer *ipiv, real *b, integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int strsm_(char *, char *, char *, char *, + integer *, integer *, real *, real *, integer *, real *, integer * + ), xerbla_(char *, integer *); + static logical notran; + extern /* Subroutine */ int slaswp_(integer *, real *, integer *, integer + *, integer *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SGETRS solves a system of linear equations + A * X = B or A' * X = B + with a general N-by-N matrix A using the LU factorization computed + by SGETRF. + + Arguments + ========= + + TRANS (input) CHARACTER*1 + Specifies the form of the system of equations: + = 'N': A * X = B (No transpose) + = 'T': A'* X = B (Transpose) + = 'C': A'* X = B (Conjugate transpose = Transpose) + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) REAL array, dimension (LDA,N) + The factors L and U from the factorization A = P*L*U + as computed by SGETRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (input) INTEGER array, dimension (N) + The pivot indices from SGETRF; for 1<=i<=N, row i of the + matrix was interchanged with row IPIV(i). + + B (input/output) REAL array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + notran = lsame_(trans, "N"); + if (! notran && ! lsame_(trans, "T") && ! lsame_( + trans, "C")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SGETRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (notran) { + +/* + Solve A * X = B. + + Apply row interchanges to the right hand sides. +*/ + + slaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c__1); + +/* Solve L*X = B, overwriting B with X. */ + + strsm_("Left", "Lower", "No transpose", "Unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + strsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b15, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A' * X = B. + + Solve U'*X = B, overwriting B with X. +*/ + + strsm_("Left", "Upper", "Transpose", "Non-unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + strsm_("Left", "Lower", "Transpose", "Unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Apply row interchanges to the solution vectors. */ + + slaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c_n1); + } + + return 0; + +/* End of SGETRS */ + +} /* sgetrs_ */ + +/* Subroutine */ int shseqr_(char *job, char *compz, integer *n, integer *ilo, + integer *ihi, real *h__, integer *ldh, real *wr, real *wi, real *z__, + integer *ldz, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2[2], i__3; + real r__1; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static real hl[2401] /* was [49][49] */; + static integer kbot, nmin; + extern logical lsame_(char *, char *); + static logical initz; + static real workl[49]; + static logical wantt, wantz; + extern /* Subroutine */ int slaqr0_(logical *, logical *, integer *, + integer *, integer *, real *, integer *, real *, real *, integer * + , integer *, real *, integer *, real *, integer *, integer *), + xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slahqr_(logical *, logical *, integer *, + integer *, integer *, real *, integer *, real *, real *, integer * + , integer *, real *, integer *, integer *), slacpy_(char *, + integer *, integer *, real *, integer *, real *, integer *), slaset_(char *, integer *, integer *, real *, real *, + real *, integer *); + static logical lquery; + + +/* + -- LAPACK computational routine (version 3.2.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + June 2010 + + Purpose + ======= + + SHSEQR computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**T, where T is an upper quasi-triangular matrix (the + Schur form), and Z is the orthogonal matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input orthogonal + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the orthogonal matrix Q: A = Q*H*Q**T = (QZ)*T*(QZ)**T. + + Arguments + ========= + + JOB (input) CHARACTER*1 + = 'E': compute eigenvalues only; + = 'S': compute eigenvalues and the Schur form T. + + COMPZ (input) CHARACTER*1 + = 'N': no Schur vectors are computed; + = 'I': Z is initialized to the unit matrix and the matrix Z + of Schur vectors of H is returned; + = 'V': Z must contain an orthogonal matrix Q on entry, and + the product Q*Z is returned. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to SGEBAL, and then passed to SGEHRD + when the matrix output by SGEBAL is reduced to Hessenberg + form. Otherwise ILO and IHI should be set to 1 and N + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) REAL array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and JOB = 'S', then H contains the + upper quasi-triangular matrix T from the Schur decomposition + (the Schur form); 2-by-2 diagonal blocks (corresponding to + complex conjugate pairs of eigenvalues) are returned in + standard form, with H(i,i) = H(i+1,i+1) and + H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and JOB = 'E', the + contents of H are unspecified on exit. (The output value of + H when INFO.GT.0 is given under the description of INFO + below.) + + Unlike earlier versions of SHSEQR, this subroutine may + explicitly H(i,j) = 0 for i.GT.j and j = 1, 2, ... ILO-1 + or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + WR (output) REAL array, dimension (N) + WI (output) REAL array, dimension (N) + The real and imaginary parts, respectively, of the computed + eigenvalues. If two eigenvalues are computed as a complex + conjugate pair, they are stored in consecutive elements of + WR and WI, say the i-th and (i+1)th, with WI(i) .GT. 0 and + WI(i+1) .LT. 0. If JOB = 'S', the eigenvalues are stored in + the same order as on the diagonal of the Schur form returned + in H, with WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 + diagonal block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and + WI(i+1) = -WI(i). + + Z (input/output) REAL array, dimension (LDZ,N) + If COMPZ = 'N', Z is not referenced. + If COMPZ = 'I', on entry Z need not be set and on exit, + if INFO = 0, Z contains the orthogonal matrix Z of the Schur + vectors of H. If COMPZ = 'V', on entry Z must contain an + N-by-N matrix Q, which is assumed to be equal to the unit + matrix except for the submatrix Z(ILO:IHI,ILO:IHI). On exit, + if INFO = 0, Z contains Q*Z. + Normally Q is the orthogonal matrix generated by SORGHR + after the call to SGEHRD which formed the Hessenberg matrix + H. (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if COMPZ = 'I' or + COMPZ = 'V', then LDZ.GE.MAX(1,N). Otherwize, LDZ.GE.1. + + WORK (workspace/output) REAL array, dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient and delivers very good and sometimes + optimal performance. However, LWORK as large as 11*N + may be required for optimal performance. A workspace + query is recommended to determine the optimal workspace + size. + + If LWORK = -1, then SHSEQR does a workspace query. + In this case, SHSEQR checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .LT. 0: if INFO = -i, the i-th argument had an illegal + value + .GT. 0: if INFO = i, SHSEQR failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and JOB = 'E', then on exit, the + remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and JOB = 'S', then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is an orthogonal matrix. The final + value of H is upper Hessenberg and quasi-triangular + in rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and COMPZ = 'V', then on exit + + (final value of Z) = (initial value of Z)*U + + where U is the orthogonal matrix in (*) (regard- + less of the value of JOB.) + + If INFO .GT. 0 and COMPZ = 'I', then on exit + (final value of Z) = U + where U is the orthogonal matrix in (*) (regard- + less of the value of JOB.) + + If INFO .GT. 0 and COMPZ = 'N', then Z is not + accessed. + + ================================================================ + Default values supplied by + ILAENV(ISPEC,'SHSEQR',JOB(:1)//COMPZ(:1),N,ILO,IHI,LWORK). + It is suggested that these defaults be adjusted in order + to attain best performance in each particular + computational environment. + + ISPEC=12: The SLAHQR vs SLAQR0 crossover point. + Default: 75. (Must be at least 11.) + + ISPEC=13: Recommended deflation window size. + This depends on ILO, IHI and NS. NS is the + number of simultaneous shifts returned + by ILAENV(ISPEC=15). (See ISPEC=15 below.) + The default for (IHI-ILO+1).LE.500 is NS. + The default for (IHI-ILO+1).GT.500 is 3*NS/2. + + ISPEC=14: Nibble crossover point. (See IPARMQ for + details.) Default: 14% of deflation window + size. + + ISPEC=15: Number of simultaneous shifts in a multishift + QR iteration. + + If IHI-ILO+1 is ... + + greater than ...but less ... the + or equal to ... than default is + + 1 30 NS = 2(+) + 30 60 NS = 4(+) + 60 150 NS = 10(+) + 150 590 NS = ** + 590 3000 NS = 64 + 3000 6000 NS = 128 + 6000 infinity NS = 256 + + (+) By default some or all matrices of this order + are passed to the implicit double shift routine + SLAHQR and this parameter is ignored. See + ISPEC=12 above and comments in IPARMQ for + details. + + (**) The asterisks (**) indicate an ad-hoc + function of N increasing from 10 to 64. + + ISPEC=16: Select structured matrix multiply. + If the number of simultaneous shifts (specified + by ISPEC=15) is less than 14, then the default + for ISPEC=16 is 0. Otherwise the default for + ISPEC=16 is 2. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . SLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== NL allocates some local workspace to help small matrices + . through a rare SLAHQR failure. NL .GT. NTINY = 11 is + . required and NL .LE. NMIN = ILAENV(ISPEC=12,...) is recom- + . mended. (The default value of NMIN is 75.) Using NL = 49 + . allows up to six simultaneous shifts and a 16-by-16 + . deflation window. ==== + + ==== Decode and check the input parameters. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --wr; + --wi; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + wantt = lsame_(job, "S"); + initz = lsame_(compz, "I"); + wantz = initz || lsame_(compz, "V"); + work[1] = (real) max(1,*n); + lquery = *lwork == -1; + + *info = 0; + if (! lsame_(job, "E") && ! wantt) { + *info = -1; + } else if (! lsame_(compz, "N") && ! wantz) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -4; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -5; + } else if (*ldh < max(1,*n)) { + *info = -7; + } else if (*ldz < 1 || wantz && *ldz < max(1,*n)) { + *info = -11; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -13; + } + + if (*info != 0) { + +/* ==== Quick return in case of invalid argument. ==== */ + + i__1 = -(*info); + xerbla_("SHSEQR", &i__1); + return 0; + + } else if (*n == 0) { + +/* ==== Quick return in case N = 0; nothing to do. ==== */ + + return 0; + + } else if (lquery) { + +/* ==== Quick return in case of a workspace query ==== */ + + slaqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], &wi[ + 1], ilo, ihi, &z__[z_offset], ldz, &work[1], lwork, info); +/* + ==== Ensure reported workspace size is backward-compatible with + . previous LAPACK versions. ==== + Computing MAX +*/ + r__1 = (real) max(1,*n); + work[1] = dmax(r__1,work[1]); + return 0; + + } else { + +/* ==== copy eigenvalues isolated by SGEBAL ==== */ + + i__1 = *ilo - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + wr[i__] = h__[i__ + i__ * h_dim1]; + wi[i__] = 0.f; +/* L10: */ + } + i__1 = *n; + for (i__ = *ihi + 1; i__ <= i__1; ++i__) { + wr[i__] = h__[i__ + i__ * h_dim1]; + wi[i__] = 0.f; +/* L20: */ + } + +/* ==== Initialize Z, if requested ==== */ + + if (initz) { + slaset_("A", n, n, &c_b29, &c_b15, &z__[z_offset], ldz) + ; + } + +/* ==== Quick return if possible ==== */ + + if (*ilo == *ihi) { + wr[*ilo] = h__[*ilo + *ilo * h_dim1]; + wi[*ilo] = 0.f; + return 0; + } + +/* + ==== SLAHQR/SLAQR0 crossover point ==== + + Writing concatenation +*/ + i__2[0] = 1, a__1[0] = job; + i__2[1] = 1, a__1[1] = compz; + s_cat(ch__1, a__1, i__2, &c__2, (ftnlen)2); + nmin = ilaenv_(&c__12, "SHSEQR", ch__1, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nmin = max(11,nmin); + +/* ==== SLAQR0 for big matrices; SLAHQR for small ones ==== */ + + if (*n > nmin) { + slaqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], + &wi[1], ilo, ihi, &z__[z_offset], ldz, &work[1], lwork, + info); + } else { + +/* ==== Small matrix ==== */ + + slahqr_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], + &wi[1], ilo, ihi, &z__[z_offset], ldz, info); + + if (*info > 0) { + +/* + ==== A rare SLAHQR failure! SLAQR0 sometimes succeeds + . when SLAHQR fails. ==== +*/ + + kbot = *info; + + if (*n >= 49) { + +/* + ==== Larger matrices have enough subdiagonal scratch + . space to call SLAQR0 directly. ==== +*/ + + slaqr0_(&wantt, &wantz, n, ilo, &kbot, &h__[h_offset], + ldh, &wr[1], &wi[1], ilo, ihi, &z__[z_offset], + ldz, &work[1], lwork, info); + + } else { + +/* + ==== Tiny matrices don't have enough subdiagonal + . scratch space to benefit from SLAQR0. Hence, + . tiny matrices must be copied into a larger + . array before calling SLAQR0. ==== +*/ + + slacpy_("A", n, n, &h__[h_offset], ldh, hl, &c__49); + hl[*n + 1 + *n * 49 - 50] = 0.f; + i__1 = 49 - *n; + slaset_("A", &c__49, &i__1, &c_b29, &c_b29, &hl[(*n + 1) * + 49 - 49], &c__49); + slaqr0_(&wantt, &wantz, &c__49, ilo, &kbot, hl, &c__49, & + wr[1], &wi[1], ilo, ihi, &z__[z_offset], ldz, + workl, &c__49, info); + if (wantt || *info != 0) { + slacpy_("A", n, n, hl, &c__49, &h__[h_offset], ldh); + } + } + } + } + +/* ==== Clear out the trash, if necessary. ==== */ + + if ((wantt || *info != 0) && *n > 2) { + i__1 = *n - 2; + i__3 = *n - 2; + slaset_("L", &i__1, &i__3, &c_b29, &c_b29, &h__[h_dim1 + 3], ldh); + } + +/* + ==== Ensure reported workspace size is backward-compatible with + . previous LAPACK versions. ==== + + Computing MAX +*/ + r__1 = (real) max(1,*n); + work[1] = dmax(r__1,work[1]); + } + +/* ==== End of SHSEQR ==== */ + + return 0; +} /* shseqr_ */ + +logical sisnan_(real *sin__) +{ + /* System generated locals */ + logical ret_val; + + /* Local variables */ + extern logical slaisnan_(real *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SISNAN returns .TRUE. if its argument is NaN, and .FALSE. + otherwise. To be replaced by the Fortran 2003 intrinsic in the + future. + + Arguments + ========= + + SIN (input) REAL + Input to test for NaN. + + ===================================================================== +*/ + + ret_val = slaisnan_(sin__, sin__); + return ret_val; +} /* sisnan_ */ + +/* Subroutine */ int slabad_(real *small, real *large) +{ + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLABAD takes as input the values computed by SLAMCH for underflow and + overflow, and returns the square root of each of these values if the + log of LARGE is sufficiently large. This subroutine is intended to + identify machines with a large exponent range, such as the Crays, and + redefine the underflow and overflow limits to be the square roots of + the values computed by SLAMCH. This subroutine is needed because + SLAMCH does not compensate for poor arithmetic in the upper half of + the exponent range, as is found on a Cray. + + Arguments + ========= + + SMALL (input/output) REAL + On entry, the underflow threshold as computed by SLAMCH. + On exit, if LOG10(LARGE) is sufficiently large, the square + root of SMALL, otherwise unchanged. + + LARGE (input/output) REAL + On entry, the overflow threshold as computed by SLAMCH. + On exit, if LOG10(LARGE) is sufficiently large, the square + root of LARGE, otherwise unchanged. + + ===================================================================== + + + If it looks like we're on a Cray, take the square root of + SMALL and LARGE to avoid overflow and underflow problems. +*/ + + if (r_lg10(large) > 2e3f) { + *small = sqrt(*small); + *large = sqrt(*large); + } + + return 0; + +/* End of SLABAD */ + +} /* slabad_ */ + +/* Subroutine */ int slabrd_(integer *m, integer *n, integer *nb, real *a, + integer *lda, real *d__, real *e, real *tauq, real *taup, real *x, + integer *ldx, real *y, integer *ldy) +{ + /* System generated locals */ + integer a_dim1, a_offset, x_dim1, x_offset, y_dim1, y_offset, i__1, i__2, + i__3; + + /* Local variables */ + static integer i__; + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + sgemv_(char *, integer *, integer *, real *, real *, integer *, + real *, integer *, real *, real *, integer *), slarfg_( + integer *, real *, real *, integer *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLABRD reduces the first NB rows and columns of a real general + m by n matrix A to upper or lower bidiagonal form by an orthogonal + transformation Q' * A * P, and returns the matrices X and Y which + are needed to apply the transformation to the unreduced part of A. + + If m >= n, A is reduced to upper bidiagonal form; if m < n, to lower + bidiagonal form. + + This is an auxiliary routine called by SGEBRD + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. + + N (input) INTEGER + The number of columns in the matrix A. + + NB (input) INTEGER + The number of leading rows and columns of A to be reduced. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the m by n general matrix to be reduced. + On exit, the first NB rows and columns of the matrix are + overwritten; the rest of the array is unchanged. + If m >= n, elements on and below the diagonal in the first NB + columns, with the array TAUQ, represent the orthogonal + matrix Q as a product of elementary reflectors; and + elements above the diagonal in the first NB rows, with the + array TAUP, represent the orthogonal matrix P as a product + of elementary reflectors. + If m < n, elements below the diagonal in the first NB + columns, with the array TAUQ, represent the orthogonal + matrix Q as a product of elementary reflectors, and + elements on and above the diagonal in the first NB rows, + with the array TAUP, represent the orthogonal matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) REAL array, dimension (NB) + The diagonal elements of the first NB rows and columns of + the reduced matrix. D(i) = A(i,i). + + E (output) REAL array, dimension (NB) + The off-diagonal elements of the first NB rows and columns of + the reduced matrix. + + TAUQ (output) REAL array dimension (NB) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix Q. See Further Details. + + TAUP (output) REAL array, dimension (NB) + The scalar factors of the elementary reflectors which + represent the orthogonal matrix P. See Further Details. + + X (output) REAL array, dimension (LDX,NB) + The m-by-nb matrix X required to update the unreduced part + of A. + + LDX (input) INTEGER + The leading dimension of the array X. LDX >= M. + + Y (output) REAL array, dimension (LDY,NB) + The n-by-nb matrix Y required to update the unreduced part + of A. + + LDY (input) INTEGER + The leading dimension of the array Y. LDY >= N. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + Q = H(1) H(2) . . . H(nb) and P = G(1) G(2) . . . G(nb) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are real scalars, and v and u are real vectors. + + If m >= n, v(1:i-1) = 0, v(i) = 1, and v(i:m) is stored on exit in + A(i:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+1:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, v(1:i) = 0, v(i+1) = 1, and v(i+1:m) is stored on exit in + A(i+2:m,i); u(1:i-1) = 0, u(i) = 1, and u(i:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + The elements of the vectors v and u together form the m-by-nb matrix + V and the nb-by-n matrix U' which are needed, with X and Y, to apply + the transformation to the unreduced part of the matrix, using a block + update of the form: A := A - V*Y' - X*U'. + + The contents of A on exit are illustrated by the following examples + with nb = 2: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( 1 1 u1 u1 u1 ) ( 1 u1 u1 u1 u1 u1 ) + ( v1 1 1 u2 u2 ) ( 1 1 u2 u2 u2 u2 ) + ( v1 v2 a a a ) ( v1 1 a a a a ) + ( v1 v2 a a a ) ( v1 v2 a a a a ) + ( v1 v2 a a a ) ( v1 v2 a a a a ) + ( v1 v2 a a a ) + + where a denotes an element of the original matrix which is unchanged, + vi denotes an element of the vector defining H(i), and ui an element + of the vector defining G(i). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + y_dim1 = *ldy; + y_offset = 1 + y_dim1; + y -= y_offset; + + /* Function Body */ + if (*m <= 0 || *n <= 0) { + return 0; + } + + if (*m >= *n) { + +/* Reduce to upper bidiagonal form */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i:m,i) */ + + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + a_dim1], + lda, &y[i__ + y_dim1], ldy, &c_b15, &a[i__ + i__ * a_dim1] + , &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &x[i__ + x_dim1], + ldx, &a[i__ * a_dim1 + 1], &c__1, &c_b15, &a[i__ + i__ * + a_dim1], &c__1); + +/* Generate reflection Q(i) to annihilate A(i+1:m,i) */ + + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + slarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * + a_dim1], &c__1, &tauq[i__]); + d__[i__] = a[i__ + i__ * a_dim1]; + if (i__ < *n) { + a[i__ + i__ * a_dim1] = 1.f; + +/* Compute Y(i+1:n,i) */ + + i__2 = *m - i__ + 1; + i__3 = *n - i__; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + (i__ + 1) * + a_dim1], lda, &a[i__ + i__ * a_dim1], &c__1, &c_b29, + &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + a_dim1], + lda, &a[i__ + i__ * a_dim1], &c__1, &c_b29, &y[i__ * + y_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &y[i__ + 1 + + y_dim1], ldy, &y[i__ * y_dim1 + 1], &c__1, &c_b15, &y[ + i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &x[i__ + x_dim1], + ldx, &a[i__ + i__ * a_dim1], &c__1, &c_b29, &y[i__ * + y_dim1 + 1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + sgemv_("Transpose", &i__2, &i__3, &c_b151, &a[(i__ + 1) * + a_dim1 + 1], lda, &y[i__ * y_dim1 + 1], &c__1, &c_b15, + &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *n - i__; + sscal_(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1); + +/* Update A(i,i+1:n) */ + + i__2 = *n - i__; + sgemv_("No transpose", &i__2, &i__, &c_b151, &y[i__ + 1 + + y_dim1], ldy, &a[i__ + a_dim1], lda, &c_b15, &a[i__ + + (i__ + 1) * a_dim1], lda); + i__2 = i__ - 1; + i__3 = *n - i__; + sgemv_("Transpose", &i__2, &i__3, &c_b151, &a[(i__ + 1) * + a_dim1 + 1], lda, &x[i__ + x_dim1], ldx, &c_b15, &a[ + i__ + (i__ + 1) * a_dim1], lda); + +/* Generate reflection P(i) to annihilate A(i,i+2:n) */ + + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + slarfg_(&i__2, &a[i__ + (i__ + 1) * a_dim1], &a[i__ + min( + i__3,*n) * a_dim1], lda, &taup[i__]); + e[i__] = a[i__ + (i__ + 1) * a_dim1]; + a[i__ + (i__ + 1) * a_dim1] = 1.f; + +/* Compute X(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = *n - i__; + sgemv_("No transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + ( + i__ + 1) * a_dim1], lda, &a[i__ + (i__ + 1) * a_dim1], + lda, &c_b29, &x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__; + sgemv_("Transpose", &i__2, &i__, &c_b15, &y[i__ + 1 + y_dim1], + ldy, &a[i__ + (i__ + 1) * a_dim1], lda, &c_b29, &x[ + i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + sgemv_("No transpose", &i__2, &i__, &c_b151, &a[i__ + 1 + + a_dim1], lda, &x[i__ * x_dim1 + 1], &c__1, &c_b15, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + sgemv_("No transpose", &i__2, &i__3, &c_b15, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b29, &x[i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &x[i__ + 1 + + x_dim1], ldx, &x[i__ * x_dim1 + 1], &c__1, &c_b15, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *m - i__; + sscal_(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1); + } +/* L10: */ + } + } else { + +/* Reduce to lower bidiagonal form */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i,i:n) */ + + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &y[i__ + y_dim1], + ldy, &a[i__ + a_dim1], lda, &c_b15, &a[i__ + i__ * a_dim1] + , lda); + i__2 = i__ - 1; + i__3 = *n - i__ + 1; + sgemv_("Transpose", &i__2, &i__3, &c_b151, &a[i__ * a_dim1 + 1], + lda, &x[i__ + x_dim1], ldx, &c_b15, &a[i__ + i__ * a_dim1] + , lda); + +/* Generate reflection P(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + slarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[i__ + min(i__3,*n) * + a_dim1], lda, &taup[i__]); + d__[i__] = a[i__ + i__ * a_dim1]; + if (i__ < *m) { + a[i__ + i__ * a_dim1] = 1.f; + +/* Compute X(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = *n - i__ + 1; + sgemv_("No transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + i__ + * a_dim1], lda, &a[i__ + i__ * a_dim1], lda, &c_b29, & + x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &y[i__ + y_dim1], + ldy, &a[i__ + i__ * a_dim1], lda, &c_b29, &x[i__ * + x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + 1 + + a_dim1], lda, &x[i__ * x_dim1 + 1], &c__1, &c_b15, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__ + 1; + sgemv_("No transpose", &i__2, &i__3, &c_b15, &a[i__ * a_dim1 + + 1], lda, &a[i__ + i__ * a_dim1], lda, &c_b29, &x[ + i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &x[i__ + 1 + + x_dim1], ldx, &x[i__ * x_dim1 + 1], &c__1, &c_b15, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *m - i__; + sscal_(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1); + +/* Update A(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + 1 + + a_dim1], lda, &y[i__ + y_dim1], ldy, &c_b15, &a[i__ + + 1 + i__ * a_dim1], &c__1); + i__2 = *m - i__; + sgemv_("No transpose", &i__2, &i__, &c_b151, &x[i__ + 1 + + x_dim1], ldx, &a[i__ * a_dim1 + 1], &c__1, &c_b15, &a[ + i__ + 1 + i__ * a_dim1], &c__1); + +/* Generate reflection Q(i) to annihilate A(i+2:m,i) */ + + i__2 = *m - i__; +/* Computing MIN */ + i__3 = i__ + 2; + slarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*m) + + i__ * a_dim1], &c__1, &tauq[i__]); + e[i__] = a[i__ + 1 + i__ * a_dim1]; + a[i__ + 1 + i__ * a_dim1] = 1.f; + +/* Compute Y(i+1:n,i) */ + + i__2 = *m - i__; + i__3 = *n - i__; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + (i__ + + 1) * a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, + &c_b29, &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + a_dim1] + , lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &y[ + i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &y[i__ + 1 + + y_dim1], ldy, &y[i__ * y_dim1 + 1], &c__1, &c_b15, &y[ + i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__; + sgemv_("Transpose", &i__2, &i__, &c_b15, &x[i__ + 1 + x_dim1], + ldx, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &y[ + i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + sgemv_("Transpose", &i__, &i__2, &c_b151, &a[(i__ + 1) * + a_dim1 + 1], lda, &y[i__ * y_dim1 + 1], &c__1, &c_b15, + &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *n - i__; + sscal_(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1); + } +/* L20: */ + } + } + return 0; + +/* End of SLABRD */ + +} /* slabrd_ */ + +/* Subroutine */ int slacpy_(char *uplo, integer *m, integer *n, real *a, + integer *lda, real *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLACPY copies all or part of a two-dimensional matrix A to another + matrix B. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be copied to B. + = 'U': Upper triangular part + = 'L': Lower triangular part + Otherwise: All of the matrix A + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input) REAL array, dimension (LDA,N) + The m by n matrix A. If UPLO = 'U', only the upper triangle + or trapezoid is accessed; if UPLO = 'L', only the lower + triangle or trapezoid is accessed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + B (output) REAL array, dimension (LDB,N) + On exit, B = A in the locations specified by UPLO. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = a[i__ + j * a_dim1]; +/* L10: */ + } +/* L20: */ + } + } else if (lsame_(uplo, "L")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = a[i__ + j * a_dim1]; +/* L30: */ + } +/* L40: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = a[i__ + j * a_dim1]; +/* L50: */ + } +/* L60: */ + } + } + return 0; + +/* End of SLACPY */ + +} /* slacpy_ */ + +/* Subroutine */ int sladiv_(real *a, real *b, real *c__, real *d__, real *p, + real *q) +{ + static real e, f; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLADIV performs complex division in real arithmetic + + a + i*b + p + i*q = --------- + c + i*d + + The algorithm is due to Robert L. Smith and can be found + in D. Knuth, The art of Computer Programming, Vol.2, p.195 + + Arguments + ========= + + A (input) REAL + B (input) REAL + C (input) REAL + D (input) REAL + The scalars a, b, c, and d in the above expression. + + P (output) REAL + Q (output) REAL + The scalars p and q in the above expression. + + ===================================================================== +*/ + + + if (dabs(*d__) < dabs(*c__)) { + e = *d__ / *c__; + f = *c__ + *d__ * e; + *p = (*a + *b * e) / f; + *q = (*b - *a * e) / f; + } else { + e = *c__ / *d__; + f = *d__ + *c__ * e; + *p = (*b + *a * e) / f; + *q = (-(*a) + *b * e) / f; + } + + return 0; + +/* End of SLADIV */ + +} /* sladiv_ */ + +/* Subroutine */ int slae2_(real *a, real *b, real *c__, real *rt1, real *rt2) +{ + /* System generated locals */ + real r__1; + + /* Local variables */ + static real ab, df, tb, sm, rt, adf, acmn, acmx; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAE2 computes the eigenvalues of a 2-by-2 symmetric matrix + [ A B ] + [ B C ]. + On return, RT1 is the eigenvalue of larger absolute value, and RT2 + is the eigenvalue of smaller absolute value. + + Arguments + ========= + + A (input) REAL + The (1,1) element of the 2-by-2 matrix. + + B (input) REAL + The (1,2) and (2,1) elements of the 2-by-2 matrix. + + C (input) REAL + The (2,2) element of the 2-by-2 matrix. + + RT1 (output) REAL + The eigenvalue of larger absolute value. + + RT2 (output) REAL + The eigenvalue of smaller absolute value. + + Further Details + =============== + + RT1 is accurate to a few ulps barring over/underflow. + + RT2 may be inaccurate if there is massive cancellation in the + determinant A*C-B*B; higher precision or correctly rounded or + correctly truncated arithmetic would be needed to compute RT2 + accurately in all cases. + + Overflow is possible only if RT1 is within a factor of 5 of overflow. + Underflow is harmless if the input data is 0 or exceeds + underflow_threshold / macheps. + + ===================================================================== + + + Compute the eigenvalues +*/ + + sm = *a + *c__; + df = *a - *c__; + adf = dabs(df); + tb = *b + *b; + ab = dabs(tb); + if (dabs(*a) > dabs(*c__)) { + acmx = *a; + acmn = *c__; + } else { + acmx = *c__; + acmn = *a; + } + if (adf > ab) { +/* Computing 2nd power */ + r__1 = ab / adf; + rt = adf * sqrt(r__1 * r__1 + 1.f); + } else if (adf < ab) { +/* Computing 2nd power */ + r__1 = adf / ab; + rt = ab * sqrt(r__1 * r__1 + 1.f); + } else { + +/* Includes case AB=ADF=0 */ + + rt = ab * sqrt(2.f); + } + if (sm < 0.f) { + *rt1 = (sm - rt) * .5f; + +/* + Order of execution important. + To get fully accurate smaller eigenvalue, + next line needs to be executed in higher precision. +*/ + + *rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b; + } else if (sm > 0.f) { + *rt1 = (sm + rt) * .5f; + +/* + Order of execution important. + To get fully accurate smaller eigenvalue, + next line needs to be executed in higher precision. +*/ + + *rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b; + } else { + +/* Includes case RT1 = RT2 = 0 */ + + *rt1 = rt * .5f; + *rt2 = rt * -.5f; + } + return 0; + +/* End of SLAE2 */ + +} /* slae2_ */ + +/* Subroutine */ int slaed0_(integer *icompq, integer *qsiz, integer *n, real + *d__, real *e, real *q, integer *ldq, real *qstore, integer *ldqs, + real *work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, qstore_dim1, qstore_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static integer i__, j, k, iq, lgn, msd2, smm1, spm1, spm2; + static real temp; + static integer curr; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static integer iperm, indxq, iwrem; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + static integer iqptr, tlvls; + extern /* Subroutine */ int slaed1_(integer *, real *, real *, integer *, + integer *, real *, integer *, real *, integer *, integer *), + slaed7_(integer *, integer *, integer *, integer *, integer *, + integer *, real *, real *, integer *, integer *, real *, integer * + , real *, integer *, integer *, integer *, integer *, integer *, + real *, real *, integer *, integer *); + static integer igivcl; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer igivnm, submat; + extern /* Subroutine */ int slacpy_(char *, integer *, integer *, real *, + integer *, real *, integer *); + static integer curprb, subpbs, igivpt, curlvl, matsiz, iprmpt, smlsiz; + extern /* Subroutine */ int ssteqr_(char *, integer *, real *, real *, + real *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAED0 computes all eigenvalues and corresponding eigenvectors of a + symmetric tridiagonal matrix using the divide and conquer method. + + Arguments + ========= + + ICOMPQ (input) INTEGER + = 0: Compute eigenvalues only. + = 1: Compute eigenvectors of original dense symmetric matrix + also. On entry, Q contains the orthogonal matrix used + to reduce the original matrix to tridiagonal form. + = 2: Compute eigenvalues and eigenvectors of tridiagonal + matrix. + + QSIZ (input) INTEGER + The dimension of the orthogonal matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N if ICOMPQ = 1. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the main diagonal of the tridiagonal matrix. + On exit, its eigenvalues. + + E (input) REAL array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix. + On exit, E has been destroyed. + + Q (input/output) REAL array, dimension (LDQ, N) + On entry, Q must contain an N-by-N orthogonal matrix. + If ICOMPQ = 0 Q is not referenced. + If ICOMPQ = 1 On entry, Q is a subset of the columns of the + orthogonal matrix used to reduce the full + matrix to tridiagonal form corresponding to + the subset of the full matrix which is being + decomposed at this time. + If ICOMPQ = 2 On entry, Q will be the identity matrix. + On exit, Q contains the eigenvectors of the + tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. If eigenvectors are + desired, then LDQ >= max(1,N). In any case, LDQ >= 1. + + QSTORE (workspace) REAL array, dimension (LDQS, N) + Referenced only when ICOMPQ = 1. Used to store parts of + the eigenvector matrix when the updating matrix multiplies + take place. + + LDQS (input) INTEGER + The leading dimension of the array QSTORE. If ICOMPQ = 1, + then LDQS >= max(1,N). In any case, LDQS >= 1. + + WORK (workspace) REAL array, + If ICOMPQ = 0 or 1, the dimension of WORK must be at least + 1 + 3*N + 2*N*lg N + 2*N**2 + ( lg( N ) = smallest integer k + such that 2^k >= N ) + If ICOMPQ = 2, the dimension of WORK must be at least + 4*N + N**2. + + IWORK (workspace) INTEGER array, + If ICOMPQ = 0 or 1, the dimension of IWORK must be at least + 6 + 6*N + 5*N*lg N. + ( lg( N ) = smallest integer k + such that 2^k >= N ) + If ICOMPQ = 2, the dimension of IWORK must be at least + 3 + 5*N. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute an eigenvalue while + working on the submatrix lying in rows and columns + INFO/(N+1) through mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + qstore_dim1 = *ldqs; + qstore_offset = 1 + qstore_dim1; + qstore -= qstore_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 2) { + *info = -1; + } else if (*icompq == 1 && *qsiz < max(0,*n)) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ldq < max(1,*n)) { + *info = -7; + } else if (*ldqs < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAED0", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + smlsiz = ilaenv_(&c__9, "SLAED0", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + +/* + Determine the size and placement of the submatrices, and save in + the leading elements of IWORK. +*/ + + iwork[1] = *n; + subpbs = 1; + tlvls = 0; +L10: + if (iwork[subpbs] > smlsiz) { + for (j = subpbs; j >= 1; --j) { + iwork[j * 2] = (iwork[j] + 1) / 2; + iwork[(j << 1) - 1] = iwork[j] / 2; +/* L20: */ + } + ++tlvls; + subpbs <<= 1; + goto L10; + } + i__1 = subpbs; + for (j = 2; j <= i__1; ++j) { + iwork[j] += iwork[j - 1]; +/* L30: */ + } + +/* + Divide the matrix into SUBPBS submatrices of size at most SMLSIZ+1 + using rank-1 modifications (cuts). +*/ + + spm1 = subpbs - 1; + i__1 = spm1; + for (i__ = 1; i__ <= i__1; ++i__) { + submat = iwork[i__] + 1; + smm1 = submat - 1; + d__[smm1] -= (r__1 = e[smm1], dabs(r__1)); + d__[submat] -= (r__1 = e[smm1], dabs(r__1)); +/* L40: */ + } + + indxq = (*n << 2) + 3; + if (*icompq != 2) { + +/* + Set up workspaces for eigenvalues only/accumulate new vectors + routine +*/ + + temp = log((real) (*n)) / log(2.f); + lgn = (integer) temp; + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + iprmpt = indxq + *n + 1; + iperm = iprmpt + *n * lgn; + iqptr = iperm + *n * lgn; + igivpt = iqptr + *n + 2; + igivcl = igivpt + *n * lgn; + + igivnm = 1; + iq = igivnm + (*n << 1) * lgn; +/* Computing 2nd power */ + i__1 = *n; + iwrem = iq + i__1 * i__1 + 1; + +/* Initialize pointers */ + + i__1 = subpbs; + for (i__ = 0; i__ <= i__1; ++i__) { + iwork[iprmpt + i__] = 1; + iwork[igivpt + i__] = 1; +/* L50: */ + } + iwork[iqptr] = 1; + } + +/* + Solve each submatrix eigenproblem at the bottom of the divide and + conquer tree. +*/ + + curr = 0; + i__1 = spm1; + for (i__ = 0; i__ <= i__1; ++i__) { + if (i__ == 0) { + submat = 1; + matsiz = iwork[1]; + } else { + submat = iwork[i__] + 1; + matsiz = iwork[i__ + 1] - iwork[i__]; + } + if (*icompq == 2) { + ssteqr_("I", &matsiz, &d__[submat], &e[submat], &q[submat + + submat * q_dim1], ldq, &work[1], info); + if (*info != 0) { + goto L130; + } + } else { + ssteqr_("I", &matsiz, &d__[submat], &e[submat], &work[iq - 1 + + iwork[iqptr + curr]], &matsiz, &work[1], info); + if (*info != 0) { + goto L130; + } + if (*icompq == 1) { + sgemm_("N", "N", qsiz, &matsiz, &matsiz, &c_b15, &q[submat * + q_dim1 + 1], ldq, &work[iq - 1 + iwork[iqptr + curr]], + &matsiz, &c_b29, &qstore[submat * qstore_dim1 + 1], + ldqs); + } +/* Computing 2nd power */ + i__2 = matsiz; + iwork[iqptr + curr + 1] = iwork[iqptr + curr] + i__2 * i__2; + ++curr; + } + k = 1; + i__2 = iwork[i__ + 1]; + for (j = submat; j <= i__2; ++j) { + iwork[indxq + j] = k; + ++k; +/* L60: */ + } +/* L70: */ + } + +/* + Successively merge eigensystems of adjacent submatrices + into eigensystem for the corresponding larger matrix. + + while ( SUBPBS > 1 ) +*/ + + curlvl = 1; +L80: + if (subpbs > 1) { + spm2 = subpbs - 2; + i__1 = spm2; + for (i__ = 0; i__ <= i__1; i__ += 2) { + if (i__ == 0) { + submat = 1; + matsiz = iwork[2]; + msd2 = iwork[1]; + curprb = 0; + } else { + submat = iwork[i__] + 1; + matsiz = iwork[i__ + 2] - iwork[i__]; + msd2 = matsiz / 2; + ++curprb; + } + +/* + Merge lower order eigensystems (of size MSD2 and MATSIZ - MSD2) + into an eigensystem of size MATSIZ. + SLAED1 is used only for the full eigensystem of a tridiagonal + matrix. + SLAED7 handles the cases in which eigenvalues only or eigenvalues + and eigenvectors of a full symmetric matrix (which was reduced to + tridiagonal form) are desired. +*/ + + if (*icompq == 2) { + slaed1_(&matsiz, &d__[submat], &q[submat + submat * q_dim1], + ldq, &iwork[indxq + submat], &e[submat + msd2 - 1], & + msd2, &work[1], &iwork[subpbs + 1], info); + } else { + slaed7_(icompq, &matsiz, qsiz, &tlvls, &curlvl, &curprb, &d__[ + submat], &qstore[submat * qstore_dim1 + 1], ldqs, & + iwork[indxq + submat], &e[submat + msd2 - 1], &msd2, & + work[iq], &iwork[iqptr], &iwork[iprmpt], &iwork[iperm] + , &iwork[igivpt], &iwork[igivcl], &work[igivnm], & + work[iwrem], &iwork[subpbs + 1], info); + } + if (*info != 0) { + goto L130; + } + iwork[i__ / 2 + 1] = iwork[i__ + 2]; +/* L90: */ + } + subpbs /= 2; + ++curlvl; + goto L80; + } + +/* + end while + + Re-merge the eigenvalues/vectors which were deflated at the final + merge step. +*/ + + if (*icompq == 1) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + j = iwork[indxq + i__]; + work[i__] = d__[j]; + scopy_(qsiz, &qstore[j * qstore_dim1 + 1], &c__1, &q[i__ * q_dim1 + + 1], &c__1); +/* L100: */ + } + scopy_(n, &work[1], &c__1, &d__[1], &c__1); + } else if (*icompq == 2) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + j = iwork[indxq + i__]; + work[i__] = d__[j]; + scopy_(n, &q[j * q_dim1 + 1], &c__1, &work[*n * i__ + 1], &c__1); +/* L110: */ + } + scopy_(n, &work[1], &c__1, &d__[1], &c__1); + slacpy_("A", n, n, &work[*n + 1], n, &q[q_offset], ldq); + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + j = iwork[indxq + i__]; + work[i__] = d__[j]; +/* L120: */ + } + scopy_(n, &work[1], &c__1, &d__[1], &c__1); + } + goto L140; + +L130: + *info = submat * (*n + 1) + submat + matsiz - 1; + +L140: + return 0; + +/* End of SLAED0 */ + +} /* slaed0_ */ + +/* Subroutine */ int slaed1_(integer *n, real *d__, real *q, integer *ldq, + integer *indxq, real *rho, integer *cutpnt, real *work, integer * + iwork, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + + /* Local variables */ + static integer i__, k, n1, n2, is, iw, iz, iq2, cpp1, indx, indxc, indxp; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *), slaed2_(integer *, integer *, integer *, real *, real + *, integer *, integer *, real *, real *, real *, real *, real *, + integer *, integer *, integer *, integer *, integer *), slaed3_( + integer *, integer *, integer *, real *, real *, integer *, real * + , real *, real *, integer *, integer *, real *, real *, integer *) + ; + static integer idlmda; + extern /* Subroutine */ int xerbla_(char *, integer *), slamrg_( + integer *, integer *, real *, integer *, integer *, integer *); + static integer coltyp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAED1 computes the updated eigensystem of a diagonal + matrix after modification by a rank-one symmetric matrix. This + routine is used only for the eigenproblem which requires all + eigenvalues and eigenvectors of a tridiagonal matrix. SLAED7 handles + the case in which eigenvalues only or eigenvalues and eigenvectors + of a full symmetric matrix (which was reduced to tridiagonal form) + are desired. + + T = Q(in) ( D(in) + RHO * Z*Z' ) Q'(in) = Q(out) * D(out) * Q'(out) + + where Z = Q'u, u is a vector of length N with ones in the + CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. + + The eigenvectors of the original matrix are stored in Q, and the + eigenvalues are in D. The algorithm consists of three stages: + + The first stage consists of deflating the size of the problem + when there are multiple eigenvalues or if there is a zero in + the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine SLAED2. + + The second stage consists of calculating the updated + eigenvalues. This is done by finding the roots of the secular + equation via the routine SLAED4 (as called by SLAED3). + This routine also calculates the eigenvectors of the current + problem. + + The final stage consists of computing the updated eigenvectors + directly using the updated eigenvalues. The eigenvectors for + the current problem are multiplied with the eigenvectors from + the overall problem. + + Arguments + ========= + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the eigenvalues of the rank-1-perturbed matrix. + On exit, the eigenvalues of the repaired matrix. + + Q (input/output) REAL array, dimension (LDQ,N) + On entry, the eigenvectors of the rank-1-perturbed matrix. + On exit, the eigenvectors of the repaired tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + INDXQ (input/output) INTEGER array, dimension (N) + On entry, the permutation which separately sorts the two + subproblems in D into ascending order. + On exit, the permutation which will reintegrate the + subproblems back into sorted order, + i.e. D( INDXQ( I = 1, N ) ) will be in ascending order. + + RHO (input) REAL + The subdiagonal entry used to create the rank-1 modification. + + CUTPNT (input) INTEGER + The location of the last eigenvalue in the leading sub-matrix. + min(1,N) <= CUTPNT <= N/2. + + WORK (workspace) REAL array, dimension (4*N + N**2) + + IWORK (workspace) INTEGER array, dimension (4*N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -1; + } else if (*ldq < max(1,*n)) { + *info = -4; + } else /* if(complicated condition) */ { +/* Computing MIN */ + i__1 = 1, i__2 = *n / 2; + if (min(i__1,i__2) > *cutpnt || *n / 2 < *cutpnt) { + *info = -7; + } + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAED1", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* + The following values are integer pointers which indicate + the portion of the workspace + used by a particular array in SLAED2 and SLAED3. +*/ + + iz = 1; + idlmda = iz + *n; + iw = idlmda + *n; + iq2 = iw + *n; + + indx = 1; + indxc = indx + *n; + coltyp = indxc + *n; + indxp = coltyp + *n; + + +/* + Form the z-vector which consists of the last row of Q_1 and the + first row of Q_2. +*/ + + scopy_(cutpnt, &q[*cutpnt + q_dim1], ldq, &work[iz], &c__1); + cpp1 = *cutpnt + 1; + i__1 = *n - *cutpnt; + scopy_(&i__1, &q[cpp1 + cpp1 * q_dim1], ldq, &work[iz + *cutpnt], &c__1); + +/* Deflate eigenvalues. */ + + slaed2_(&k, n, cutpnt, &d__[1], &q[q_offset], ldq, &indxq[1], rho, &work[ + iz], &work[idlmda], &work[iw], &work[iq2], &iwork[indx], &iwork[ + indxc], &iwork[indxp], &iwork[coltyp], info); + + if (*info != 0) { + goto L20; + } + +/* Solve Secular Equation. */ + + if (k != 0) { + is = (iwork[coltyp] + iwork[coltyp + 1]) * *cutpnt + (iwork[coltyp + + 1] + iwork[coltyp + 2]) * (*n - *cutpnt) + iq2; + slaed3_(&k, n, cutpnt, &d__[1], &q[q_offset], ldq, rho, &work[idlmda], + &work[iq2], &iwork[indxc], &iwork[coltyp], &work[iw], &work[ + is], info); + if (*info != 0) { + goto L20; + } + +/* Prepare the INDXQ sorting permutation. */ + + n1 = k; + n2 = *n - k; + slamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &indxq[1]); + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + indxq[i__] = i__; +/* L10: */ + } + } + +L20: + return 0; + +/* End of SLAED1 */ + +} /* slaed1_ */ + +/* Subroutine */ int slaed2_(integer *k, integer *n, integer *n1, real *d__, + real *q, integer *ldq, integer *indxq, real *rho, real *z__, real * + dlamda, real *w, real *q2, integer *indx, integer *indxc, integer * + indxp, integer *coltyp, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + real r__1, r__2, r__3, r__4; + + /* Local variables */ + static real c__; + static integer i__, j; + static real s, t; + static integer k2, n2, ct, nj, pj, js, iq1, iq2, n1p1; + static real eps, tau, tol; + static integer psm[4], imax, jmax, ctot[4]; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *), sscal_(integer *, real *, real *, + integer *), scopy_(integer *, real *, integer *, real *, integer * + ); + extern doublereal slapy2_(real *, real *), slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer isamax_(integer *, real *, integer *); + extern /* Subroutine */ int slamrg_(integer *, integer *, real *, integer + *, integer *, integer *), slacpy_(char *, integer *, integer *, + real *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAED2 merges the two sets of eigenvalues together into a single + sorted set. Then it tries to deflate the size of the problem. + There are two ways in which deflation can occur: when two or more + eigenvalues are close together or if there is a tiny entry in the + Z vector. For each such occurrence the order of the related secular + equation problem is reduced by one. + + Arguments + ========= + + K (output) INTEGER + The number of non-deflated eigenvalues, and the order of the + related secular equation. 0 <= K <=N. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + N1 (input) INTEGER + The location of the last eigenvalue in the leading sub-matrix. + min(1,N) <= N1 <= N/2. + + D (input/output) REAL array, dimension (N) + On entry, D contains the eigenvalues of the two submatrices to + be combined. + On exit, D contains the trailing (N-K) updated eigenvalues + (those which were deflated) sorted into increasing order. + + Q (input/output) REAL array, dimension (LDQ, N) + On entry, Q contains the eigenvectors of two submatrices in + the two square blocks with corners at (1,1), (N1,N1) + and (N1+1, N1+1), (N,N). + On exit, Q contains the trailing (N-K) updated eigenvectors + (those which were deflated) in its last N-K columns. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + INDXQ (input/output) INTEGER array, dimension (N) + The permutation which separately sorts the two sub-problems + in D into ascending order. Note that elements in the second + half of this permutation must first have N1 added to their + values. Destroyed on exit. + + RHO (input/output) REAL + On entry, the off-diagonal element associated with the rank-1 + cut which originally split the two submatrices which are now + being recombined. + On exit, RHO has been modified to the value required by + SLAED3. + + Z (input) REAL array, dimension (N) + On entry, Z contains the updating vector (the last + row of the first sub-eigenvector matrix and the first row of + the second sub-eigenvector matrix). + On exit, the contents of Z have been destroyed by the updating + process. + + DLAMDA (output) REAL array, dimension (N) + A copy of the first K eigenvalues which will be used by + SLAED3 to form the secular equation. + + W (output) REAL array, dimension (N) + The first k values of the final deflation-altered z-vector + which will be passed to SLAED3. + + Q2 (output) REAL array, dimension (N1**2+(N-N1)**2) + A copy of the first K eigenvectors which will be used by + SLAED3 in a matrix multiply (SGEMM) to solve for the new + eigenvectors. + + INDX (workspace) INTEGER array, dimension (N) + The permutation used to sort the contents of DLAMDA into + ascending order. + + INDXC (output) INTEGER array, dimension (N) + The permutation used to arrange the columns of the deflated + Q matrix into three groups: the first group contains non-zero + elements only at and above N1, the second contains + non-zero elements only below N1, and the third is dense. + + INDXP (workspace) INTEGER array, dimension (N) + The permutation used to place deflated values of D at the end + of the array. INDXP(1:K) points to the nondeflated D-values + and INDXP(K+1:N) points to the deflated eigenvalues. + + COLTYP (workspace/output) INTEGER array, dimension (N) + During execution, a label which will indicate which of the + following types a column in the Q2 matrix is: + 1 : non-zero in the upper half only; + 2 : dense; + 3 : non-zero in the lower half only; + 4 : deflated. + On exit, COLTYP(i) is the number of columns of type i, + for i=1 to 4 only. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --z__; + --dlamda; + --w; + --q2; + --indx; + --indxc; + --indxp; + --coltyp; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -2; + } else if (*ldq < max(1,*n)) { + *info = -6; + } else /* if(complicated condition) */ { +/* Computing MIN */ + i__1 = 1, i__2 = *n / 2; + if (min(i__1,i__2) > *n1 || *n / 2 < *n1) { + *info = -3; + } + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAED2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + n2 = *n - *n1; + n1p1 = *n1 + 1; + + if (*rho < 0.f) { + sscal_(&n2, &c_b151, &z__[n1p1], &c__1); + } + +/* + Normalize z so that norm(z) = 1. Since z is the concatenation of + two normalized vectors, norm2(z) = sqrt(2). +*/ + + t = 1.f / sqrt(2.f); + sscal_(n, &t, &z__[1], &c__1); + +/* RHO = ABS( norm(z)**2 * RHO ) */ + + *rho = (r__1 = *rho * 2.f, dabs(r__1)); + +/* Sort the eigenvalues into increasing order */ + + i__1 = *n; + for (i__ = n1p1; i__ <= i__1; ++i__) { + indxq[i__] += *n1; +/* L10: */ + } + +/* re-integrate the deflated parts from the last pass */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = d__[indxq[i__]]; +/* L20: */ + } + slamrg_(n1, &n2, &dlamda[1], &c__1, &c__1, &indxc[1]); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + indx[i__] = indxq[indxc[i__]]; +/* L30: */ + } + +/* Calculate the allowable deflation tolerance */ + + imax = isamax_(n, &z__[1], &c__1); + jmax = isamax_(n, &d__[1], &c__1); + eps = slamch_("Epsilon"); +/* Computing MAX */ + r__3 = (r__1 = d__[jmax], dabs(r__1)), r__4 = (r__2 = z__[imax], dabs( + r__2)); + tol = eps * 8.f * dmax(r__3,r__4); + +/* + If the rank-1 modifier is small enough, no more needs to be done + except to reorganize Q so that its columns correspond with the + elements in D. +*/ + + if (*rho * (r__1 = z__[imax], dabs(r__1)) <= tol) { + *k = 0; + iq2 = 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__ = indx[j]; + scopy_(n, &q[i__ * q_dim1 + 1], &c__1, &q2[iq2], &c__1); + dlamda[j] = d__[i__]; + iq2 += *n; +/* L40: */ + } + slacpy_("A", n, n, &q2[1], n, &q[q_offset], ldq); + scopy_(n, &dlamda[1], &c__1, &d__[1], &c__1); + goto L190; + } + +/* + If there are multiple eigenvalues then the problem deflates. Here + the number of equal eigenvalues are found. As each equal + eigenvalue is found, an elementary reflector is computed to rotate + the corresponding eigensubspace so that the corresponding + components of Z are zero in this new basis. +*/ + + i__1 = *n1; + for (i__ = 1; i__ <= i__1; ++i__) { + coltyp[i__] = 1; +/* L50: */ + } + i__1 = *n; + for (i__ = n1p1; i__ <= i__1; ++i__) { + coltyp[i__] = 3; +/* L60: */ + } + + + *k = 0; + k2 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + nj = indx[j]; + if (*rho * (r__1 = z__[nj], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + coltyp[nj] = 4; + indxp[k2] = nj; + if (j == *n) { + goto L100; + } + } else { + pj = nj; + goto L80; + } +/* L70: */ + } +L80: + ++j; + nj = indx[j]; + if (j > *n) { + goto L100; + } + if (*rho * (r__1 = z__[nj], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + coltyp[nj] = 4; + indxp[k2] = nj; + } else { + +/* Check if eigenvalues are close enough to allow deflation. */ + + s = z__[pj]; + c__ = z__[nj]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = slapy2_(&c__, &s); + t = d__[nj] - d__[pj]; + c__ /= tau; + s = -s / tau; + if ((r__1 = t * c__ * s, dabs(r__1)) <= tol) { + +/* Deflation is possible. */ + + z__[nj] = tau; + z__[pj] = 0.f; + if (coltyp[nj] != coltyp[pj]) { + coltyp[nj] = 2; + } + coltyp[pj] = 4; + srot_(n, &q[pj * q_dim1 + 1], &c__1, &q[nj * q_dim1 + 1], &c__1, & + c__, &s); +/* Computing 2nd power */ + r__1 = c__; +/* Computing 2nd power */ + r__2 = s; + t = d__[pj] * (r__1 * r__1) + d__[nj] * (r__2 * r__2); +/* Computing 2nd power */ + r__1 = s; +/* Computing 2nd power */ + r__2 = c__; + d__[nj] = d__[pj] * (r__1 * r__1) + d__[nj] * (r__2 * r__2); + d__[pj] = t; + --k2; + i__ = 1; +L90: + if (k2 + i__ <= *n) { + if (d__[pj] < d__[indxp[k2 + i__]]) { + indxp[k2 + i__ - 1] = indxp[k2 + i__]; + indxp[k2 + i__] = pj; + ++i__; + goto L90; + } else { + indxp[k2 + i__ - 1] = pj; + } + } else { + indxp[k2 + i__ - 1] = pj; + } + pj = nj; + } else { + ++(*k); + dlamda[*k] = d__[pj]; + w[*k] = z__[pj]; + indxp[*k] = pj; + pj = nj; + } + } + goto L80; +L100: + +/* Record the last eigenvalue. */ + + ++(*k); + dlamda[*k] = d__[pj]; + w[*k] = z__[pj]; + indxp[*k] = pj; + +/* + Count up the total number of the various types of columns, then + form a permutation which positions the four column types into + four uniform groups (although one or more of these groups may be + empty). +*/ + + for (j = 1; j <= 4; ++j) { + ctot[j - 1] = 0; +/* L110: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + ct = coltyp[j]; + ++ctot[ct - 1]; +/* L120: */ + } + +/* PSM(*) = Position in SubMatrix (of types 1 through 4) */ + + psm[0] = 1; + psm[1] = ctot[0] + 1; + psm[2] = psm[1] + ctot[1]; + psm[3] = psm[2] + ctot[2]; + *k = *n - ctot[3]; + +/* + Fill out the INDXC array so that the permutation which it induces + will place all type-1 columns first, all type-2 columns next, + then all type-3's, and finally all type-4's. +*/ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + js = indxp[j]; + ct = coltyp[js]; + indx[psm[ct - 1]] = js; + indxc[psm[ct - 1]] = j; + ++psm[ct - 1]; +/* L130: */ + } + +/* + Sort the eigenvalues and corresponding eigenvectors into DLAMDA + and Q2 respectively. The eigenvalues/vectors which were not + deflated go into the first K slots of DLAMDA and Q2 respectively, + while those which were deflated go into the last N - K slots. +*/ + + i__ = 1; + iq1 = 1; + iq2 = (ctot[0] + ctot[1]) * *n1 + 1; + i__1 = ctot[0]; + for (j = 1; j <= i__1; ++j) { + js = indx[i__]; + scopy_(n1, &q[js * q_dim1 + 1], &c__1, &q2[iq1], &c__1); + z__[i__] = d__[js]; + ++i__; + iq1 += *n1; +/* L140: */ + } + + i__1 = ctot[1]; + for (j = 1; j <= i__1; ++j) { + js = indx[i__]; + scopy_(n1, &q[js * q_dim1 + 1], &c__1, &q2[iq1], &c__1); + scopy_(&n2, &q[*n1 + 1 + js * q_dim1], &c__1, &q2[iq2], &c__1); + z__[i__] = d__[js]; + ++i__; + iq1 += *n1; + iq2 += n2; +/* L150: */ + } + + i__1 = ctot[2]; + for (j = 1; j <= i__1; ++j) { + js = indx[i__]; + scopy_(&n2, &q[*n1 + 1 + js * q_dim1], &c__1, &q2[iq2], &c__1); + z__[i__] = d__[js]; + ++i__; + iq2 += n2; +/* L160: */ + } + + iq1 = iq2; + i__1 = ctot[3]; + for (j = 1; j <= i__1; ++j) { + js = indx[i__]; + scopy_(n, &q[js * q_dim1 + 1], &c__1, &q2[iq2], &c__1); + iq2 += *n; + z__[i__] = d__[js]; + ++i__; +/* L170: */ + } + +/* + The deflated eigenvalues and their corresponding vectors go back + into the last N - K slots of D and Q respectively. +*/ + + slacpy_("A", n, &ctot[3], &q2[iq1], n, &q[(*k + 1) * q_dim1 + 1], ldq); + i__1 = *n - *k; + scopy_(&i__1, &z__[*k + 1], &c__1, &d__[*k + 1], &c__1); + +/* Copy CTOT into COLTYP for referencing in SLAED3. */ + + for (j = 1; j <= 4; ++j) { + coltyp[j] = ctot[j - 1]; +/* L180: */ + } + +L190: + return 0; + +/* End of SLAED2 */ + +} /* slaed2_ */ + +/* Subroutine */ int slaed3_(integer *k, integer *n, integer *n1, real *d__, + real *q, integer *ldq, real *rho, real *dlamda, real *q2, integer * + indx, integer *ctot, real *w, real *s, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static integer i__, j, n2, n12, ii, n23, iq2; + static real temp; + extern doublereal snrm2_(integer *, real *, integer *); + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *), scopy_(integer *, real *, + integer *, real *, integer *), slaed4_(integer *, integer *, real + *, real *, real *, real *, real *, integer *); + extern doublereal slamc3_(real *, real *); + extern /* Subroutine */ int xerbla_(char *, integer *), slacpy_( + char *, integer *, integer *, real *, integer *, real *, integer * + ), slaset_(char *, integer *, integer *, real *, real *, + real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAED3 finds the roots of the secular equation, as defined by the + values in D, W, and RHO, between 1 and K. It makes the + appropriate calls to SLAED4 and then updates the eigenvectors by + multiplying the matrix of eigenvectors of the pair of eigensystems + being combined by the matrix of eigenvectors of the K-by-K system + which is solved here. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + K (input) INTEGER + The number of terms in the rational function to be solved by + SLAED4. K >= 0. + + N (input) INTEGER + The number of rows and columns in the Q matrix. + N >= K (deflation may result in N>K). + + N1 (input) INTEGER + The location of the last eigenvalue in the leading submatrix. + min(1,N) <= N1 <= N/2. + + D (output) REAL array, dimension (N) + D(I) contains the updated eigenvalues for + 1 <= I <= K. + + Q (output) REAL array, dimension (LDQ,N) + Initially the first K columns are used as workspace. + On output the columns 1 to K contain + the updated eigenvectors. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + RHO (input) REAL + The value of the parameter in the rank one update equation. + RHO >= 0 required. + + DLAMDA (input/output) REAL array, dimension (K) + The first K elements of this array contain the old roots + of the deflated updating problem. These are the poles + of the secular equation. May be changed on output by + having lowest order bit set to zero on Cray X-MP, Cray Y-MP, + Cray-2, or Cray C-90, as described above. + + Q2 (input) REAL array, dimension (LDQ2, N) + The first K columns of this matrix contain the non-deflated + eigenvectors for the split problem. + + INDX (input) INTEGER array, dimension (N) + The permutation used to arrange the columns of the deflated + Q matrix into three groups (see SLAED2). + The rows of the eigenvectors found by SLAED4 must be likewise + permuted before the matrix multiply can take place. + + CTOT (input) INTEGER array, dimension (4) + A count of the total number of the various types of columns + in Q, as described in INDX. The fourth column type is any + column which has been deflated. + + W (input/output) REAL array, dimension (K) + The first K elements of this array contain the components + of the deflation-adjusted updating vector. Destroyed on + output. + + S (workspace) REAL array, dimension (N1 + 1)*K + Will contain the eigenvectors of the repaired matrix which + will be multiplied by the previously accumulated eigenvectors + to update the system. + + LDS (input) INTEGER + The leading dimension of S. LDS >= max(1,K). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --dlamda; + --q2; + --indx; + --ctot; + --w; + --s; + + /* Function Body */ + *info = 0; + + if (*k < 0) { + *info = -1; + } else if (*n < *k) { + *info = -2; + } else if (*ldq < max(1,*n)) { + *info = -6; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAED3", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*k == 0) { + return 0; + } + +/* + Modify values DLAMDA(i) to make sure all DLAMDA(i)-DLAMDA(j) can + be computed with high relative accuracy (barring over/underflow). + This is a problem on machines without a guard digit in + add/subtract (Cray XMP, Cray YMP, Cray C 90 and Cray 2). + The following code replaces DLAMDA(I) by 2*DLAMDA(I)-DLAMDA(I), + which on any of these machines zeros out the bottommost + bit of DLAMDA(I) if it is 1; this makes the subsequent + subtractions DLAMDA(I)-DLAMDA(J) unproblematic when cancellation + occurs. On binary machines with a guard digit (almost all + machines) it does not change DLAMDA(I) at all. On hexadecimal + and decimal machines with a guard digit, it slightly + changes the bottommost bits of DLAMDA(I). It does not account + for hexadecimal or decimal machines without guard digits + (we know of none). We use a subroutine call to compute + 2*DLAMBDA(I) to prevent optimizing compilers from eliminating + this code. +*/ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = slamc3_(&dlamda[i__], &dlamda[i__]) - dlamda[i__]; +/* L10: */ + } + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + slaed4_(k, &j, &dlamda[1], &w[1], &q[j * q_dim1 + 1], rho, &d__[j], + info); + +/* If the zero finder fails, the computation is terminated. */ + + if (*info != 0) { + goto L120; + } +/* L20: */ + } + + if (*k == 1) { + goto L110; + } + if (*k == 2) { + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + w[1] = q[j * q_dim1 + 1]; + w[2] = q[j * q_dim1 + 2]; + ii = indx[1]; + q[j * q_dim1 + 1] = w[ii]; + ii = indx[2]; + q[j * q_dim1 + 2] = w[ii]; +/* L30: */ + } + goto L110; + } + +/* Compute updated W. */ + + scopy_(k, &w[1], &c__1, &s[1], &c__1); + +/* Initialize W(I) = Q(I,I) */ + + i__1 = *ldq + 1; + scopy_(k, &q[q_offset], &i__1, &w[1], &c__1); + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + w[i__] *= q[i__ + j * q_dim1] / (dlamda[i__] - dlamda[j]); +/* L40: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + w[i__] *= q[i__ + j * q_dim1] / (dlamda[i__] - dlamda[j]); +/* L50: */ + } +/* L60: */ + } + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + r__1 = sqrt(-w[i__]); + w[i__] = r_sign(&r__1, &s[i__]); +/* L70: */ + } + +/* Compute eigenvectors of the modified rank-1 modification. */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = *k; + for (i__ = 1; i__ <= i__2; ++i__) { + s[i__] = w[i__] / q[i__ + j * q_dim1]; +/* L80: */ + } + temp = snrm2_(k, &s[1], &c__1); + i__2 = *k; + for (i__ = 1; i__ <= i__2; ++i__) { + ii = indx[i__]; + q[i__ + j * q_dim1] = s[ii] / temp; +/* L90: */ + } +/* L100: */ + } + +/* Compute the updated eigenvectors. */ + +L110: + + n2 = *n - *n1; + n12 = ctot[1] + ctot[2]; + n23 = ctot[2] + ctot[3]; + + slacpy_("A", &n23, k, &q[ctot[1] + 1 + q_dim1], ldq, &s[1], &n23); + iq2 = *n1 * n12 + 1; + if (n23 != 0) { + sgemm_("N", "N", &n2, k, &n23, &c_b15, &q2[iq2], &n2, &s[1], &n23, & + c_b29, &q[*n1 + 1 + q_dim1], ldq); + } else { + slaset_("A", &n2, k, &c_b29, &c_b29, &q[*n1 + 1 + q_dim1], ldq); + } + + slacpy_("A", &n12, k, &q[q_offset], ldq, &s[1], &n12); + if (n12 != 0) { + sgemm_("N", "N", n1, k, &n12, &c_b15, &q2[1], n1, &s[1], &n12, &c_b29, + &q[q_offset], ldq); + } else { + slaset_("A", n1, k, &c_b29, &c_b29, &q[q_dim1 + 1], ldq); + } + + +L120: + return 0; + +/* End of SLAED3 */ + +} /* slaed3_ */ + +/* Subroutine */ int slaed4_(integer *n, integer *i__, real *d__, real *z__, + real *delta, real *rho, real *dlam, integer *info) +{ + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + static real a, b, c__; + static integer j; + static real w; + static integer ii; + static real dw, zz[3]; + static integer ip1; + static real del, eta, phi, eps, tau, psi; + static integer iim1, iip1; + static real dphi, dpsi; + static integer iter; + static real temp, prew, temp1, dltlb, dltub, midpt; + static integer niter; + static logical swtch; + extern /* Subroutine */ int slaed5_(integer *, real *, real *, real *, + real *, real *), slaed6_(integer *, logical *, real *, real *, + real *, real *, real *, integer *); + static logical swtch3; + extern doublereal slamch_(char *); + static logical orgati; + static real erretm, rhoinv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This subroutine computes the I-th updated eigenvalue of a symmetric + rank-one modification to a diagonal matrix whose elements are + given in the array d, and that + + D(i) < D(j) for i < j + + and that RHO > 0. This is arranged by the calling routine, and is + no loss in generality. The rank-one modified system is thus + + diag( D ) + RHO * Z * Z_transpose. + + where we assume the Euclidean norm of Z is 1. + + The method consists of approximating the rational functions in the + secular equation by simpler interpolating rational functions. + + Arguments + ========= + + N (input) INTEGER + The length of all arrays. + + I (input) INTEGER + The index of the eigenvalue to be computed. 1 <= I <= N. + + D (input) REAL array, dimension (N) + The original eigenvalues. It is assumed that they are in + order, D(I) < D(J) for I < J. + + Z (input) REAL array, dimension (N) + The components of the updating vector. + + DELTA (output) REAL array, dimension (N) + If N .GT. 2, DELTA contains (D(j) - lambda_I) in its j-th + component. If N = 1, then DELTA(1) = 1. If N = 2, see SLAED5 + for detail. The vector DELTA contains the information necessary + to construct the eigenvectors by SLAED3 and SLAED9. + + RHO (input) REAL + The scalar in the symmetric updating formula. + + DLAM (output) REAL + The computed lambda_I, the I-th updated eigenvalue. + + INFO (output) INTEGER + = 0: successful exit + > 0: if INFO = 1, the updating process failed. + + Internal Parameters + =================== + + Logical variable ORGATI (origin-at-i?) is used for distinguishing + whether D(i) or D(i+1) is treated as the origin. + + ORGATI = .true. origin at i + ORGATI = .false. origin at i+1 + + Logical variable SWTCH3 (switch-for-3-poles?) is for noting + if we are working with THREE poles! + + MAXIT is the maximum number of iterations allowed for each + eigenvalue. + + Further Details + =============== + + Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Since this routine is called in an inner loop, we do no argument + checking. + + Quick return for N=1 and 2. +*/ + + /* Parameter adjustments */ + --delta; + --z__; + --d__; + + /* Function Body */ + *info = 0; + if (*n == 1) { + +/* Presumably, I=1 upon entry */ + + *dlam = d__[1] + *rho * z__[1] * z__[1]; + delta[1] = 1.f; + return 0; + } + if (*n == 2) { + slaed5_(i__, &d__[1], &z__[1], &delta[1], rho, dlam); + return 0; + } + +/* Compute machine epsilon */ + + eps = slamch_("Epsilon"); + rhoinv = 1.f / *rho; + +/* The case I = N */ + + if (*i__ == *n) { + +/* Initialize some basic variables */ + + ii = *n - 1; + niter = 1; + +/* Calculate initial guess */ + + midpt = *rho / 2.f; + +/* + If ||Z||_2 is not one, then TEMP should be set to + RHO * ||Z||_2^2 / TWO +*/ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - midpt; +/* L10: */ + } + + psi = 0.f; + i__1 = *n - 2; + for (j = 1; j <= i__1; ++j) { + psi += z__[j] * z__[j] / delta[j]; +/* L20: */ + } + + c__ = rhoinv + psi; + w = c__ + z__[ii] * z__[ii] / delta[ii] + z__[*n] * z__[*n] / delta[* + n]; + + if (w <= 0.f) { + temp = z__[*n - 1] * z__[*n - 1] / (d__[*n] - d__[*n - 1] + *rho) + + z__[*n] * z__[*n] / *rho; + if (c__ <= temp) { + tau = *rho; + } else { + del = d__[*n] - d__[*n - 1]; + a = -c__ * del + z__[*n - 1] * z__[*n - 1] + z__[*n] * z__[*n] + ; + b = z__[*n] * z__[*n] * del; + if (a < 0.f) { + tau = b * 2.f / (sqrt(a * a + b * 4.f * c__) - a); + } else { + tau = (a + sqrt(a * a + b * 4.f * c__)) / (c__ * 2.f); + } + } + +/* + It can be proved that + D(N)+RHO/2 <= LAMBDA(N) < D(N)+TAU <= D(N)+RHO +*/ + + dltlb = midpt; + dltub = *rho; + } else { + del = d__[*n] - d__[*n - 1]; + a = -c__ * del + z__[*n - 1] * z__[*n - 1] + z__[*n] * z__[*n]; + b = z__[*n] * z__[*n] * del; + if (a < 0.f) { + tau = b * 2.f / (sqrt(a * a + b * 4.f * c__) - a); + } else { + tau = (a + sqrt(a * a + b * 4.f * c__)) / (c__ * 2.f); + } + +/* + It can be proved that + D(N) < D(N)+TAU < LAMBDA(N) < D(N)+RHO/2 +*/ + + dltlb = 0.f; + dltub = midpt; + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - tau; +/* L30: */ + } + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L40: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / delta[*n]; + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8.f + erretm - phi + rhoinv + dabs(tau) * ( + dpsi + dphi); + + w = rhoinv + phi + psi; + +/* Test for convergence */ + + if (dabs(w) <= eps * erretm) { + *dlam = d__[*i__] + tau; + goto L250; + } + + if (w <= 0.f) { + dltlb = dmax(dltlb,tau); + } else { + dltub = dmin(dltub,tau); + } + +/* Calculate the new step */ + + ++niter; + c__ = w - delta[*n - 1] * dpsi - delta[*n] * dphi; + a = (delta[*n - 1] + delta[*n]) * w - delta[*n - 1] * delta[*n] * ( + dpsi + dphi); + b = delta[*n - 1] * delta[*n] * w; + if (c__ < 0.f) { + c__ = dabs(c__); + } + if (c__ == 0.f) { +/* + ETA = B/A + ETA = RHO - TAU +*/ + eta = dltub - tau; + } else if (a >= 0.f) { + eta = (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / ( + c__ * 2.f); + } else { + eta = b * 2.f / (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta > 0.f) { + eta = -w / (dpsi + dphi); + } + temp = tau + eta; + if (temp > dltub || temp < dltlb) { + if (w < 0.f) { + eta = (dltub - tau) / 2.f; + } else { + eta = (dltlb - tau) / 2.f; + } + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; +/* L50: */ + } + + tau += eta; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L60: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / delta[*n]; + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8.f + erretm - phi + rhoinv + dabs(tau) * ( + dpsi + dphi); + + w = rhoinv + phi + psi; + +/* Main loop to update the values of the array DELTA */ + + iter = niter + 1; + + for (niter = iter; niter <= 30; ++niter) { + +/* Test for convergence */ + + if (dabs(w) <= eps * erretm) { + *dlam = d__[*i__] + tau; + goto L250; + } + + if (w <= 0.f) { + dltlb = dmax(dltlb,tau); + } else { + dltub = dmin(dltub,tau); + } + +/* Calculate the new step */ + + c__ = w - delta[*n - 1] * dpsi - delta[*n] * dphi; + a = (delta[*n - 1] + delta[*n]) * w - delta[*n - 1] * delta[*n] * + (dpsi + dphi); + b = delta[*n - 1] * delta[*n] * w; + if (a >= 0.f) { + eta = (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / + (c__ * 2.f); + } else { + eta = b * 2.f / (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta > 0.f) { + eta = -w / (dpsi + dphi); + } + temp = tau + eta; + if (temp > dltub || temp < dltlb) { + if (w < 0.f) { + eta = (dltub - tau) / 2.f; + } else { + eta = (dltlb - tau) / 2.f; + } + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; +/* L70: */ + } + + tau += eta; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L80: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / delta[*n]; + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8.f + erretm - phi + rhoinv + dabs(tau) * + (dpsi + dphi); + + w = rhoinv + phi + psi; +/* L90: */ + } + +/* Return with INFO = 1, NITER = MAXIT and not converged */ + + *info = 1; + *dlam = d__[*i__] + tau; + goto L250; + +/* End for the case I = N */ + + } else { + +/* The case for I < N */ + + niter = 1; + ip1 = *i__ + 1; + +/* Calculate initial guess */ + + del = d__[ip1] - d__[*i__]; + midpt = del / 2.f; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - midpt; +/* L100: */ + } + + psi = 0.f; + i__1 = *i__ - 1; + for (j = 1; j <= i__1; ++j) { + psi += z__[j] * z__[j] / delta[j]; +/* L110: */ + } + + phi = 0.f; + i__1 = *i__ + 2; + for (j = *n; j >= i__1; --j) { + phi += z__[j] * z__[j] / delta[j]; +/* L120: */ + } + c__ = rhoinv + psi + phi; + w = c__ + z__[*i__] * z__[*i__] / delta[*i__] + z__[ip1] * z__[ip1] / + delta[ip1]; + + if (w > 0.f) { + +/* + d(i)< the ith eigenvalue < (d(i)+d(i+1))/2 + + We choose d(i) as origin. +*/ + + orgati = TRUE_; + a = c__ * del + z__[*i__] * z__[*i__] + z__[ip1] * z__[ip1]; + b = z__[*i__] * z__[*i__] * del; + if (a > 0.f) { + tau = b * 2.f / (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } else { + tau = (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / + (c__ * 2.f); + } + dltlb = 0.f; + dltub = midpt; + } else { + +/* + (d(i)+d(i+1))/2 <= the ith eigenvalue < d(i+1) + + We choose d(i+1) as origin. +*/ + + orgati = FALSE_; + a = c__ * del - z__[*i__] * z__[*i__] - z__[ip1] * z__[ip1]; + b = z__[ip1] * z__[ip1] * del; + if (a < 0.f) { + tau = b * 2.f / (a - sqrt((r__1 = a * a + b * 4.f * c__, dabs( + r__1)))); + } else { + tau = -(a + sqrt((r__1 = a * a + b * 4.f * c__, dabs(r__1)))) + / (c__ * 2.f); + } + dltlb = -midpt; + dltub = 0.f; + } + + if (orgati) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - tau; +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[ip1] - tau; +/* L140: */ + } + } + if (orgati) { + ii = *i__; + } else { + ii = *i__ + 1; + } + iim1 = ii - 1; + iip1 = ii + 1; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L150: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.f; + phi = 0.f; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / delta[j]; + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L160: */ + } + + w = rhoinv + phi + psi; + +/* + W is the value of the secular function with + its ii-th element removed. +*/ + + swtch3 = FALSE_; + if (orgati) { + if (w < 0.f) { + swtch3 = TRUE_; + } + } else { + if (w > 0.f) { + swtch3 = TRUE_; + } + } + if (ii == 1 || ii == *n) { + swtch3 = FALSE_; + } + + temp = z__[ii] / delta[ii]; + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w += temp; + erretm = (phi - psi) * 8.f + erretm + rhoinv * 2.f + dabs(temp) * 3.f + + dabs(tau) * dw; + +/* Test for convergence */ + + if (dabs(w) <= eps * erretm) { + if (orgati) { + *dlam = d__[*i__] + tau; + } else { + *dlam = d__[ip1] + tau; + } + goto L250; + } + + if (w <= 0.f) { + dltlb = dmax(dltlb,tau); + } else { + dltub = dmin(dltub,tau); + } + +/* Calculate the new step */ + + ++niter; + if (! swtch3) { + if (orgati) { +/* Computing 2nd power */ + r__1 = z__[*i__] / delta[*i__]; + c__ = w - delta[ip1] * dw - (d__[*i__] - d__[ip1]) * (r__1 * + r__1); + } else { +/* Computing 2nd power */ + r__1 = z__[ip1] / delta[ip1]; + c__ = w - delta[*i__] * dw - (d__[ip1] - d__[*i__]) * (r__1 * + r__1); + } + a = (delta[*i__] + delta[ip1]) * w - delta[*i__] * delta[ip1] * + dw; + b = delta[*i__] * delta[ip1] * w; + if (c__ == 0.f) { + if (a == 0.f) { + if (orgati) { + a = z__[*i__] * z__[*i__] + delta[ip1] * delta[ip1] * + (dpsi + dphi); + } else { + a = z__[ip1] * z__[ip1] + delta[*i__] * delta[*i__] * + (dpsi + dphi); + } + } + eta = b / a; + } else if (a <= 0.f) { + eta = (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / + (c__ * 2.f); + } else { + eta = b * 2.f / (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } + } else { + +/* Interpolation using THREE most relevant poles */ + + temp = rhoinv + psi + phi; + if (orgati) { + temp1 = z__[iim1] / delta[iim1]; + temp1 *= temp1; + c__ = temp - delta[iip1] * (dpsi + dphi) - (d__[iim1] - d__[ + iip1]) * temp1; + zz[0] = z__[iim1] * z__[iim1]; + zz[2] = delta[iip1] * delta[iip1] * (dpsi - temp1 + dphi); + } else { + temp1 = z__[iip1] / delta[iip1]; + temp1 *= temp1; + c__ = temp - delta[iim1] * (dpsi + dphi) - (d__[iip1] - d__[ + iim1]) * temp1; + zz[0] = delta[iim1] * delta[iim1] * (dpsi + (dphi - temp1)); + zz[2] = z__[iip1] * z__[iip1]; + } + zz[1] = z__[ii] * z__[ii]; + slaed6_(&niter, &orgati, &c__, &delta[iim1], zz, &w, &eta, info); + if (*info != 0) { + goto L250; + } + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta >= 0.f) { + eta = -w / dw; + } + temp = tau + eta; + if (temp > dltub || temp < dltlb) { + if (w < 0.f) { + eta = (dltub - tau) / 2.f; + } else { + eta = (dltlb - tau) / 2.f; + } + } + + prew = w; + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; +/* L180: */ + } + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L190: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.f; + phi = 0.f; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / delta[j]; + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L200: */ + } + + temp = z__[ii] / delta[ii]; + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w = rhoinv + phi + psi + temp; + erretm = (phi - psi) * 8.f + erretm + rhoinv * 2.f + dabs(temp) * 3.f + + (r__1 = tau + eta, dabs(r__1)) * dw; + + swtch = FALSE_; + if (orgati) { + if (-w > dabs(prew) / 10.f) { + swtch = TRUE_; + } + } else { + if (w > dabs(prew) / 10.f) { + swtch = TRUE_; + } + } + + tau += eta; + +/* Main loop to update the values of the array DELTA */ + + iter = niter + 1; + + for (niter = iter; niter <= 30; ++niter) { + +/* Test for convergence */ + + if (dabs(w) <= eps * erretm) { + if (orgati) { + *dlam = d__[*i__] + tau; + } else { + *dlam = d__[ip1] + tau; + } + goto L250; + } + + if (w <= 0.f) { + dltlb = dmax(dltlb,tau); + } else { + dltub = dmin(dltub,tau); + } + +/* Calculate the new step */ + + if (! swtch3) { + if (! swtch) { + if (orgati) { +/* Computing 2nd power */ + r__1 = z__[*i__] / delta[*i__]; + c__ = w - delta[ip1] * dw - (d__[*i__] - d__[ip1]) * ( + r__1 * r__1); + } else { +/* Computing 2nd power */ + r__1 = z__[ip1] / delta[ip1]; + c__ = w - delta[*i__] * dw - (d__[ip1] - d__[*i__]) * + (r__1 * r__1); + } + } else { + temp = z__[ii] / delta[ii]; + if (orgati) { + dpsi += temp * temp; + } else { + dphi += temp * temp; + } + c__ = w - delta[*i__] * dpsi - delta[ip1] * dphi; + } + a = (delta[*i__] + delta[ip1]) * w - delta[*i__] * delta[ip1] + * dw; + b = delta[*i__] * delta[ip1] * w; + if (c__ == 0.f) { + if (a == 0.f) { + if (! swtch) { + if (orgati) { + a = z__[*i__] * z__[*i__] + delta[ip1] * + delta[ip1] * (dpsi + dphi); + } else { + a = z__[ip1] * z__[ip1] + delta[*i__] * delta[ + *i__] * (dpsi + dphi); + } + } else { + a = delta[*i__] * delta[*i__] * dpsi + delta[ip1] + * delta[ip1] * dphi; + } + } + eta = b / a; + } else if (a <= 0.f) { + eta = (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)) + )) / (c__ * 2.f); + } else { + eta = b * 2.f / (a + sqrt((r__1 = a * a - b * 4.f * c__, + dabs(r__1)))); + } + } else { + +/* Interpolation using THREE most relevant poles */ + + temp = rhoinv + psi + phi; + if (swtch) { + c__ = temp - delta[iim1] * dpsi - delta[iip1] * dphi; + zz[0] = delta[iim1] * delta[iim1] * dpsi; + zz[2] = delta[iip1] * delta[iip1] * dphi; + } else { + if (orgati) { + temp1 = z__[iim1] / delta[iim1]; + temp1 *= temp1; + c__ = temp - delta[iip1] * (dpsi + dphi) - (d__[iim1] + - d__[iip1]) * temp1; + zz[0] = z__[iim1] * z__[iim1]; + zz[2] = delta[iip1] * delta[iip1] * (dpsi - temp1 + + dphi); + } else { + temp1 = z__[iip1] / delta[iip1]; + temp1 *= temp1; + c__ = temp - delta[iim1] * (dpsi + dphi) - (d__[iip1] + - d__[iim1]) * temp1; + zz[0] = delta[iim1] * delta[iim1] * (dpsi + (dphi - + temp1)); + zz[2] = z__[iip1] * z__[iip1]; + } + } + slaed6_(&niter, &orgati, &c__, &delta[iim1], zz, &w, &eta, + info); + if (*info != 0) { + goto L250; + } + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta >= 0.f) { + eta = -w / dw; + } + temp = tau + eta; + if (temp > dltub || temp < dltlb) { + if (w < 0.f) { + eta = (dltub - tau) / 2.f; + } else { + eta = (dltlb - tau) / 2.f; + } + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; +/* L210: */ + } + + tau += eta; + prew = w; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / delta[j]; + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L220: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.f; + phi = 0.f; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / delta[j]; + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L230: */ + } + + temp = z__[ii] / delta[ii]; + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w = rhoinv + phi + psi + temp; + erretm = (phi - psi) * 8.f + erretm + rhoinv * 2.f + dabs(temp) * + 3.f + dabs(tau) * dw; + if (w * prew > 0.f && dabs(w) > dabs(prew) / 10.f) { + swtch = ! swtch; + } + +/* L240: */ + } + +/* Return with INFO = 1, NITER = MAXIT and not converged */ + + *info = 1; + if (orgati) { + *dlam = d__[*i__] + tau; + } else { + *dlam = d__[ip1] + tau; + } + + } + +L250: + + return 0; + +/* End of SLAED4 */ + +} /* slaed4_ */ + +/* Subroutine */ int slaed5_(integer *i__, real *d__, real *z__, real *delta, + real *rho, real *dlam) +{ + /* System generated locals */ + real r__1; + + /* Local variables */ + static real b, c__, w, del, tau, temp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This subroutine computes the I-th eigenvalue of a symmetric rank-one + modification of a 2-by-2 diagonal matrix + + diag( D ) + RHO * Z * transpose(Z) . + + The diagonal elements in the array D are assumed to satisfy + + D(i) < D(j) for i < j . + + We also assume RHO > 0 and that the Euclidean norm of the vector + Z is one. + + Arguments + ========= + + I (input) INTEGER + The index of the eigenvalue to be computed. I = 1 or I = 2. + + D (input) REAL array, dimension (2) + The original eigenvalues. We assume D(1) < D(2). + + Z (input) REAL array, dimension (2) + The components of the updating vector. + + DELTA (output) REAL array, dimension (2) + The vector DELTA contains the information necessary + to construct the eigenvectors. + + RHO (input) REAL + The scalar in the symmetric updating formula. + + DLAM (output) REAL + The computed lambda_I, the I-th updated eigenvalue. + + Further Details + =============== + + Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --delta; + --z__; + --d__; + + /* Function Body */ + del = d__[2] - d__[1]; + if (*i__ == 1) { + w = *rho * 2.f * (z__[2] * z__[2] - z__[1] * z__[1]) / del + 1.f; + if (w > 0.f) { + b = del + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[1] * z__[1] * del; + +/* B > ZERO, always */ + + tau = c__ * 2.f / (b + sqrt((r__1 = b * b - c__ * 4.f, dabs(r__1)) + )); + *dlam = d__[1] + tau; + delta[1] = -z__[1] / tau; + delta[2] = z__[2] / (del - tau); + } else { + b = -del + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[2] * z__[2] * del; + if (b > 0.f) { + tau = c__ * -2.f / (b + sqrt(b * b + c__ * 4.f)); + } else { + tau = (b - sqrt(b * b + c__ * 4.f)) / 2.f; + } + *dlam = d__[2] + tau; + delta[1] = -z__[1] / (del + tau); + delta[2] = -z__[2] / tau; + } + temp = sqrt(delta[1] * delta[1] + delta[2] * delta[2]); + delta[1] /= temp; + delta[2] /= temp; + } else { + +/* Now I=2 */ + + b = -del + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[2] * z__[2] * del; + if (b > 0.f) { + tau = (b + sqrt(b * b + c__ * 4.f)) / 2.f; + } else { + tau = c__ * 2.f / (-b + sqrt(b * b + c__ * 4.f)); + } + *dlam = d__[2] + tau; + delta[1] = -z__[1] / (del + tau); + delta[2] = -z__[2] / tau; + temp = sqrt(delta[1] * delta[1] + delta[2] * delta[2]); + delta[1] /= temp; + delta[2] /= temp; + } + return 0; + +/* End OF SLAED5 */ + +} /* slaed5_ */ + +/* Subroutine */ int slaed6_(integer *kniter, logical *orgati, real *rho, + real *d__, real *z__, real *finit, real *tau, integer *info) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2, r__3, r__4; + + /* Local variables */ + static real a, b, c__, f; + static integer i__; + static real fc, df, ddf, lbd, eta, ubd, eps, base; + static integer iter; + static real temp, temp1, temp2, temp3, temp4; + static logical scale; + static integer niter; + static real small1, small2, sminv1, sminv2, dscale[3], sclfac; + extern doublereal slamch_(char *); + static real zscale[3], erretm, sclinv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + February 2007 + + + Purpose + ======= + + SLAED6 computes the positive or negative root (closest to the origin) + of + z(1) z(2) z(3) + f(x) = rho + --------- + ---------- + --------- + d(1)-x d(2)-x d(3)-x + + It is assumed that + + if ORGATI = .true. the root is between d(2) and d(3); + otherwise it is between d(1) and d(2) + + This routine will be called by SLAED4 when necessary. In most cases, + the root sought is the smallest in magnitude, though it might not be + in some extremely rare situations. + + Arguments + ========= + + KNITER (input) INTEGER + Refer to SLAED4 for its significance. + + ORGATI (input) LOGICAL + If ORGATI is true, the needed root is between d(2) and + d(3); otherwise it is between d(1) and d(2). See + SLAED4 for further details. + + RHO (input) REAL + Refer to the equation f(x) above. + + D (input) REAL array, dimension (3) + D satisfies d(1) < d(2) < d(3). + + Z (input) REAL array, dimension (3) + Each of the elements in z must be positive. + + FINIT (input) REAL + The value of f at 0. It is more accurate than the one + evaluated inside this routine (if someone wants to do + so). + + TAU (output) REAL + The root of the equation f(x). + + INFO (output) INTEGER + = 0: successful exit + > 0: if INFO = 1, failure to converge + + Further Details + =============== + + 30/06/99: Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + 10/02/03: This version has a few statements commented out for thread safety + (machine parameters are computed on each entry). SJH. + + 05/10/06: Modified from a new version of Ren-Cang Li, use + Gragg-Thornton-Warner cubic convergent scheme for better stability. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --z__; + --d__; + + /* Function Body */ + *info = 0; + + if (*orgati) { + lbd = d__[2]; + ubd = d__[3]; + } else { + lbd = d__[1]; + ubd = d__[2]; + } + if (*finit < 0.f) { + lbd = 0.f; + } else { + ubd = 0.f; + } + + niter = 1; + *tau = 0.f; + if (*kniter == 2) { + if (*orgati) { + temp = (d__[3] - d__[2]) / 2.f; + c__ = *rho + z__[1] / (d__[1] - d__[2] - temp); + a = c__ * (d__[2] + d__[3]) + z__[2] + z__[3]; + b = c__ * d__[2] * d__[3] + z__[2] * d__[3] + z__[3] * d__[2]; + } else { + temp = (d__[1] - d__[2]) / 2.f; + c__ = *rho + z__[3] / (d__[3] - d__[2] - temp); + a = c__ * (d__[1] + d__[2]) + z__[1] + z__[2]; + b = c__ * d__[1] * d__[2] + z__[1] * d__[2] + z__[2] * d__[1]; + } +/* Computing MAX */ + r__1 = dabs(a), r__2 = dabs(b), r__1 = max(r__1,r__2), r__2 = dabs( + c__); + temp = dmax(r__1,r__2); + a /= temp; + b /= temp; + c__ /= temp; + if (c__ == 0.f) { + *tau = b / a; + } else if (a <= 0.f) { + *tau = (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / ( + c__ * 2.f); + } else { + *tau = b * 2.f / (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } + if (*tau < lbd || *tau > ubd) { + *tau = (lbd + ubd) / 2.f; + } + if (d__[1] == *tau || d__[2] == *tau || d__[3] == *tau) { + *tau = 0.f; + } else { + temp = *finit + *tau * z__[1] / (d__[1] * (d__[1] - *tau)) + *tau + * z__[2] / (d__[2] * (d__[2] - *tau)) + *tau * z__[3] / ( + d__[3] * (d__[3] - *tau)); + if (temp <= 0.f) { + lbd = *tau; + } else { + ubd = *tau; + } + if (dabs(*finit) <= dabs(temp)) { + *tau = 0.f; + } + } + } + +/* + get machine parameters for possible scaling to avoid overflow + + modified by Sven: parameters SMALL1, SMINV1, SMALL2, + SMINV2, EPS are not SAVEd anymore between one call to the + others but recomputed at each call +*/ + + eps = slamch_("Epsilon"); + base = slamch_("Base"); + i__1 = (integer) (log(slamch_("SafMin")) / log(base) / 3.f); + small1 = pow_ri(&base, &i__1); + sminv1 = 1.f / small1; + small2 = small1 * small1; + sminv2 = sminv1 * sminv1; + +/* + Determine if scaling of inputs necessary to avoid overflow + when computing 1/TEMP**3 +*/ + + if (*orgati) { +/* Computing MIN */ + r__3 = (r__1 = d__[2] - *tau, dabs(r__1)), r__4 = (r__2 = d__[3] - * + tau, dabs(r__2)); + temp = dmin(r__3,r__4); + } else { +/* Computing MIN */ + r__3 = (r__1 = d__[1] - *tau, dabs(r__1)), r__4 = (r__2 = d__[2] - * + tau, dabs(r__2)); + temp = dmin(r__3,r__4); + } + scale = FALSE_; + if (temp <= small1) { + scale = TRUE_; + if (temp <= small2) { + +/* Scale up by power of radix nearest 1/SAFMIN**(2/3) */ + + sclfac = sminv2; + sclinv = small2; + } else { + +/* Scale up by power of radix nearest 1/SAFMIN**(1/3) */ + + sclfac = sminv1; + sclinv = small1; + } + +/* Scaling up safe because D, Z, TAU scaled elsewhere to be O(1) */ + + for (i__ = 1; i__ <= 3; ++i__) { + dscale[i__ - 1] = d__[i__] * sclfac; + zscale[i__ - 1] = z__[i__] * sclfac; +/* L10: */ + } + *tau *= sclfac; + lbd *= sclfac; + ubd *= sclfac; + } else { + +/* Copy D and Z to DSCALE and ZSCALE */ + + for (i__ = 1; i__ <= 3; ++i__) { + dscale[i__ - 1] = d__[i__]; + zscale[i__ - 1] = z__[i__]; +/* L20: */ + } + } + + fc = 0.f; + df = 0.f; + ddf = 0.f; + for (i__ = 1; i__ <= 3; ++i__) { + temp = 1.f / (dscale[i__ - 1] - *tau); + temp1 = zscale[i__ - 1] * temp; + temp2 = temp1 * temp; + temp3 = temp2 * temp; + fc += temp1 / dscale[i__ - 1]; + df += temp2; + ddf += temp3; +/* L30: */ + } + f = *finit + *tau * fc; + + if (dabs(f) <= 0.f) { + goto L60; + } + if (f <= 0.f) { + lbd = *tau; + } else { + ubd = *tau; + } + +/* + Iteration begins -- Use Gragg-Thornton-Warner cubic convergent + scheme + + It is not hard to see that + + 1) Iterations will go up monotonically + if FINIT < 0; + + 2) Iterations will go down monotonically + if FINIT > 0. +*/ + + iter = niter + 1; + + for (niter = iter; niter <= 40; ++niter) { + + if (*orgati) { + temp1 = dscale[1] - *tau; + temp2 = dscale[2] - *tau; + } else { + temp1 = dscale[0] - *tau; + temp2 = dscale[1] - *tau; + } + a = (temp1 + temp2) * f - temp1 * temp2 * df; + b = temp1 * temp2 * f; + c__ = f - (temp1 + temp2) * df + temp1 * temp2 * ddf; +/* Computing MAX */ + r__1 = dabs(a), r__2 = dabs(b), r__1 = max(r__1,r__2), r__2 = dabs( + c__); + temp = dmax(r__1,r__2); + a /= temp; + b /= temp; + c__ /= temp; + if (c__ == 0.f) { + eta = b / a; + } else if (a <= 0.f) { + eta = (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / ( + c__ * 2.f); + } else { + eta = b * 2.f / (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } + if (f * eta >= 0.f) { + eta = -f / df; + } + + *tau += eta; + if (*tau < lbd || *tau > ubd) { + *tau = (lbd + ubd) / 2.f; + } + + fc = 0.f; + erretm = 0.f; + df = 0.f; + ddf = 0.f; + for (i__ = 1; i__ <= 3; ++i__) { + temp = 1.f / (dscale[i__ - 1] - *tau); + temp1 = zscale[i__ - 1] * temp; + temp2 = temp1 * temp; + temp3 = temp2 * temp; + temp4 = temp1 / dscale[i__ - 1]; + fc += temp4; + erretm += dabs(temp4); + df += temp2; + ddf += temp3; +/* L40: */ + } + f = *finit + *tau * fc; + erretm = (dabs(*finit) + dabs(*tau) * erretm) * 8.f + dabs(*tau) * df; + if (dabs(f) <= eps * erretm) { + goto L60; + } + if (f <= 0.f) { + lbd = *tau; + } else { + ubd = *tau; + } +/* L50: */ + } + *info = 1; +L60: + +/* Undo scaling */ + + if (scale) { + *tau *= sclinv; + } + return 0; + +/* End of SLAED6 */ + +} /* slaed6_ */ + +/* Subroutine */ int slaed7_(integer *icompq, integer *n, integer *qsiz, + integer *tlvls, integer *curlvl, integer *curpbm, real *d__, real *q, + integer *ldq, integer *indxq, real *rho, integer *cutpnt, real * + qstore, integer *qptr, integer *prmptr, integer *perm, integer * + givptr, integer *givcol, real *givnum, real *work, integer *iwork, + integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + + /* Local variables */ + static integer i__, k, n1, n2, is, iw, iz, iq2, ptr, ldq2, indx, curr, + indxc; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static integer indxp; + extern /* Subroutine */ int slaed8_(integer *, integer *, integer *, + integer *, real *, real *, integer *, integer *, real *, integer * + , real *, real *, real *, integer *, real *, integer *, integer *, + integer *, real *, integer *, integer *, integer *), slaed9_( + integer *, integer *, integer *, integer *, real *, real *, + integer *, real *, real *, real *, real *, integer *, integer *), + slaeda_(integer *, integer *, integer *, integer *, integer *, + integer *, integer *, integer *, real *, real *, integer *, real * + , real *, integer *); + static integer idlmda; + extern /* Subroutine */ int xerbla_(char *, integer *), slamrg_( + integer *, integer *, real *, integer *, integer *, integer *); + static integer coltyp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAED7 computes the updated eigensystem of a diagonal + matrix after modification by a rank-one symmetric matrix. This + routine is used only for the eigenproblem which requires all + eigenvalues and optionally eigenvectors of a dense symmetric matrix + that has been reduced to tridiagonal form. SLAED1 handles + the case in which all eigenvalues and eigenvectors of a symmetric + tridiagonal matrix are desired. + + T = Q(in) ( D(in) + RHO * Z*Z' ) Q'(in) = Q(out) * D(out) * Q'(out) + + where Z = Q'u, u is a vector of length N with ones in the + CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. + + The eigenvectors of the original matrix are stored in Q, and the + eigenvalues are in D. The algorithm consists of three stages: + + The first stage consists of deflating the size of the problem + when there are multiple eigenvalues or if there is a zero in + the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine SLAED8. + + The second stage consists of calculating the updated + eigenvalues. This is done by finding the roots of the secular + equation via the routine SLAED4 (as called by SLAED9). + This routine also calculates the eigenvectors of the current + problem. + + The final stage consists of computing the updated eigenvectors + directly using the updated eigenvalues. The eigenvectors for + the current problem are multiplied with the eigenvectors from + the overall problem. + + Arguments + ========= + + ICOMPQ (input) INTEGER + = 0: Compute eigenvalues only. + = 1: Compute eigenvectors of original dense symmetric matrix + also. On entry, Q contains the orthogonal matrix used + to reduce the original matrix to tridiagonal form. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + QSIZ (input) INTEGER + The dimension of the orthogonal matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N if ICOMPQ = 1. + + TLVLS (input) INTEGER + The total number of merging levels in the overall divide and + conquer tree. + + CURLVL (input) INTEGER + The current level in the overall merge routine, + 0 <= CURLVL <= TLVLS. + + CURPBM (input) INTEGER + The current problem in the current level in the overall + merge routine (counting from upper left to lower right). + + D (input/output) REAL array, dimension (N) + On entry, the eigenvalues of the rank-1-perturbed matrix. + On exit, the eigenvalues of the repaired matrix. + + Q (input/output) REAL array, dimension (LDQ, N) + On entry, the eigenvectors of the rank-1-perturbed matrix. + On exit, the eigenvectors of the repaired tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + INDXQ (output) INTEGER array, dimension (N) + The permutation which will reintegrate the subproblem just + solved back into sorted order, i.e., D( INDXQ( I = 1, N ) ) + will be in ascending order. + + RHO (input) REAL + The subdiagonal element used to create the rank-1 + modification. + + CUTPNT (input) INTEGER + Contains the location of the last eigenvalue in the leading + sub-matrix. min(1,N) <= CUTPNT <= N. + + QSTORE (input/output) REAL array, dimension (N**2+1) + Stores eigenvectors of submatrices encountered during + divide and conquer, packed together. QPTR points to + beginning of the submatrices. + + QPTR (input/output) INTEGER array, dimension (N+2) + List of indices pointing to beginning of submatrices stored + in QSTORE. The submatrices are numbered starting at the + bottom left of the divide and conquer tree, from left to + right and bottom to top. + + PRMPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in PERM a + level's permutation is stored. PRMPTR(i+1) - PRMPTR(i) + indicates the size of the permutation and also the size of + the full, non-deflated problem. + + PERM (input) INTEGER array, dimension (N lg N) + Contains the permutations (from deflation and sorting) to be + applied to each eigenblock. + + GIVPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in GIVCOL a + level's Givens rotations are stored. GIVPTR(i+1) - GIVPTR(i) + indicates the number of Givens rotations. + + GIVCOL (input) INTEGER array, dimension (2, N lg N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (input) REAL array, dimension (2, N lg N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + WORK (workspace) REAL array, dimension (3*N+QSIZ*N) + + IWORK (workspace) INTEGER array, dimension (4*N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --qstore; + --qptr; + --prmptr; + --perm; + --givptr; + givcol -= 3; + givnum -= 3; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*icompq == 1 && *qsiz < *n) { + *info = -4; + } else if (*ldq < max(1,*n)) { + *info = -9; + } else if (min(1,*n) > *cutpnt || *n < *cutpnt) { + *info = -12; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAED7", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* + The following values are for bookkeeping purposes only. They are + integer pointers which indicate the portion of the workspace + used by a particular array in SLAED8 and SLAED9. +*/ + + if (*icompq == 1) { + ldq2 = *qsiz; + } else { + ldq2 = *n; + } + + iz = 1; + idlmda = iz + *n; + iw = idlmda + *n; + iq2 = iw + *n; + is = iq2 + *n * ldq2; + + indx = 1; + indxc = indx + *n; + coltyp = indxc + *n; + indxp = coltyp + *n; + +/* + Form the z-vector which consists of the last row of Q_1 and the + first row of Q_2. +*/ + + ptr = pow_ii(&c__2, tlvls) + 1; + i__1 = *curlvl - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *tlvls - i__; + ptr += pow_ii(&c__2, &i__2); +/* L10: */ + } + curr = ptr + *curpbm; + slaeda_(n, tlvls, curlvl, curpbm, &prmptr[1], &perm[1], &givptr[1], & + givcol[3], &givnum[3], &qstore[1], &qptr[1], &work[iz], &work[iz + + *n], info); + +/* + When solving the final problem, we no longer need the stored data, + so we will overwrite the data from this level onto the previously + used storage space. +*/ + + if (*curlvl == *tlvls) { + qptr[curr] = 1; + prmptr[curr] = 1; + givptr[curr] = 1; + } + +/* Sort and Deflate eigenvalues. */ + + slaed8_(icompq, &k, n, qsiz, &d__[1], &q[q_offset], ldq, &indxq[1], rho, + cutpnt, &work[iz], &work[idlmda], &work[iq2], &ldq2, &work[iw], & + perm[prmptr[curr]], &givptr[curr + 1], &givcol[(givptr[curr] << 1) + + 1], &givnum[(givptr[curr] << 1) + 1], &iwork[indxp], &iwork[ + indx], info); + prmptr[curr + 1] = prmptr[curr] + *n; + givptr[curr + 1] += givptr[curr]; + +/* Solve Secular Equation. */ + + if (k != 0) { + slaed9_(&k, &c__1, &k, n, &d__[1], &work[is], &k, rho, &work[idlmda], + &work[iw], &qstore[qptr[curr]], &k, info); + if (*info != 0) { + goto L30; + } + if (*icompq == 1) { + sgemm_("N", "N", qsiz, &k, &k, &c_b15, &work[iq2], &ldq2, &qstore[ + qptr[curr]], &k, &c_b29, &q[q_offset], ldq); + } +/* Computing 2nd power */ + i__1 = k; + qptr[curr + 1] = qptr[curr] + i__1 * i__1; + +/* Prepare the INDXQ sorting permutation. */ + + n1 = k; + n2 = *n - k; + slamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &indxq[1]); + } else { + qptr[curr + 1] = qptr[curr]; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + indxq[i__] = i__; +/* L20: */ + } + } + +L30: + return 0; + +/* End of SLAED7 */ + +} /* slaed7_ */ + +/* Subroutine */ int slaed8_(integer *icompq, integer *k, integer *n, integer + *qsiz, real *d__, real *q, integer *ldq, integer *indxq, real *rho, + integer *cutpnt, real *z__, real *dlamda, real *q2, integer *ldq2, + real *w, integer *perm, integer *givptr, integer *givcol, real * + givnum, integer *indxp, integer *indx, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, q2_dim1, q2_offset, i__1; + real r__1; + + /* Local variables */ + static real c__; + static integer i__, j; + static real s, t; + static integer k2, n1, n2, jp, n1p1; + static real eps, tau, tol; + static integer jlam, imax, jmax; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *), sscal_(integer *, real *, real *, + integer *), scopy_(integer *, real *, integer *, real *, integer * + ); + extern doublereal slapy2_(real *, real *), slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer isamax_(integer *, real *, integer *); + extern /* Subroutine */ int slamrg_(integer *, integer *, real *, integer + *, integer *, integer *), slacpy_(char *, integer *, integer *, + real *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SLAED8 merges the two sets of eigenvalues together into a single + sorted set. Then it tries to deflate the size of the problem. + There are two ways in which deflation can occur: when two or more + eigenvalues are close together or if there is a tiny element in the + Z vector. For each such occurrence the order of the related secular + equation problem is reduced by one. + + Arguments + ========= + + ICOMPQ (input) INTEGER + = 0: Compute eigenvalues only. + = 1: Compute eigenvectors of original dense symmetric matrix + also. On entry, Q contains the orthogonal matrix used + to reduce the original matrix to tridiagonal form. + + K (output) INTEGER + The number of non-deflated eigenvalues, and the order of the + related secular equation. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + QSIZ (input) INTEGER + The dimension of the orthogonal matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N if ICOMPQ = 1. + + D (input/output) REAL array, dimension (N) + On entry, the eigenvalues of the two submatrices to be + combined. On exit, the trailing (N-K) updated eigenvalues + (those which were deflated) sorted into increasing order. + + Q (input/output) REAL array, dimension (LDQ,N) + If ICOMPQ = 0, Q is not referenced. Otherwise, + on entry, Q contains the eigenvectors of the partially solved + system which has been previously updated in matrix + multiplies with other partially solved eigensystems. + On exit, Q contains the trailing (N-K) updated eigenvectors + (those which were deflated) in its last N-K columns. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + INDXQ (input) INTEGER array, dimension (N) + The permutation which separately sorts the two sub-problems + in D into ascending order. Note that elements in the second + half of this permutation must first have CUTPNT added to + their values in order to be accurate. + + RHO (input/output) REAL + On entry, the off-diagonal element associated with the rank-1 + cut which originally split the two submatrices which are now + being recombined. + On exit, RHO has been modified to the value required by + SLAED3. + + CUTPNT (input) INTEGER + The location of the last eigenvalue in the leading + sub-matrix. min(1,N) <= CUTPNT <= N. + + Z (input) REAL array, dimension (N) + On entry, Z contains the updating vector (the last row of + the first sub-eigenvector matrix and the first row of the + second sub-eigenvector matrix). + On exit, the contents of Z are destroyed by the updating + process. + + DLAMDA (output) REAL array, dimension (N) + A copy of the first K eigenvalues which will be used by + SLAED3 to form the secular equation. + + Q2 (output) REAL array, dimension (LDQ2,N) + If ICOMPQ = 0, Q2 is not referenced. Otherwise, + a copy of the first K eigenvectors which will be used by + SLAED7 in a matrix multiply (SGEMM) to update the new + eigenvectors. + + LDQ2 (input) INTEGER + The leading dimension of the array Q2. LDQ2 >= max(1,N). + + W (output) REAL array, dimension (N) + The first k values of the final deflation-altered z-vector and + will be passed to SLAED3. + + PERM (output) INTEGER array, dimension (N) + The permutations (from deflation and sorting) to be applied + to each eigenblock. + + GIVPTR (output) INTEGER + The number of Givens rotations which took place in this + subproblem. + + GIVCOL (output) INTEGER array, dimension (2, N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (output) REAL array, dimension (2, N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + INDXP (workspace) INTEGER array, dimension (N) + The permutation used to place deflated values of D at the end + of the array. INDXP(1:K) points to the nondeflated D-values + and INDXP(K+1:N) points to the deflated eigenvalues. + + INDX (workspace) INTEGER array, dimension (N) + The permutation used to sort the contents of D into ascending + order. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --z__; + --dlamda; + q2_dim1 = *ldq2; + q2_offset = 1 + q2_dim1; + q2 -= q2_offset; + --w; + --perm; + givcol -= 3; + givnum -= 3; + --indxp; + --indx; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*n < 0) { + *info = -3; + } else if (*icompq == 1 && *qsiz < *n) { + *info = -4; + } else if (*ldq < max(1,*n)) { + *info = -7; + } else if (*cutpnt < min(1,*n) || *cutpnt > *n) { + *info = -10; + } else if (*ldq2 < max(1,*n)) { + *info = -14; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAED8", &i__1); + return 0; + } + +/* + Need to initialize GIVPTR to O here in case of quick exit + to prevent an unspecified code behavior (usually sigfault) + when IWORK array on entry to *stedc is not zeroed + (or at least some IWORK entries which used in *laed7 for GIVPTR). +*/ + + *givptr = 0; + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + n1 = *cutpnt; + n2 = *n - n1; + n1p1 = n1 + 1; + + if (*rho < 0.f) { + sscal_(&n2, &c_b151, &z__[n1p1], &c__1); + } + +/* Normalize z so that norm(z) = 1 */ + + t = 1.f / sqrt(2.f); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + indx[j] = j; +/* L10: */ + } + sscal_(n, &t, &z__[1], &c__1); + *rho = (r__1 = *rho * 2.f, dabs(r__1)); + +/* Sort the eigenvalues into increasing order */ + + i__1 = *n; + for (i__ = *cutpnt + 1; i__ <= i__1; ++i__) { + indxq[i__] += *cutpnt; +/* L20: */ + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = d__[indxq[i__]]; + w[i__] = z__[indxq[i__]]; +/* L30: */ + } + i__ = 1; + j = *cutpnt + 1; + slamrg_(&n1, &n2, &dlamda[1], &c__1, &c__1, &indx[1]); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d__[i__] = dlamda[indx[i__]]; + z__[i__] = w[indx[i__]]; +/* L40: */ + } + +/* Calculate the allowable deflation tolerence */ + + imax = isamax_(n, &z__[1], &c__1); + jmax = isamax_(n, &d__[1], &c__1); + eps = slamch_("Epsilon"); + tol = eps * 8.f * (r__1 = d__[jmax], dabs(r__1)); + +/* + If the rank-1 modifier is small enough, no more needs to be done + except to reorganize Q so that its columns correspond with the + elements in D. +*/ + + if (*rho * (r__1 = z__[imax], dabs(r__1)) <= tol) { + *k = 0; + if (*icompq == 0) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + perm[j] = indxq[indx[j]]; +/* L50: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + perm[j] = indxq[indx[j]]; + scopy_(qsiz, &q[perm[j] * q_dim1 + 1], &c__1, &q2[j * q2_dim1 + + 1], &c__1); +/* L60: */ + } + slacpy_("A", qsiz, n, &q2[q2_dim1 + 1], ldq2, &q[q_dim1 + 1], ldq); + } + return 0; + } + +/* + If there are multiple eigenvalues then the problem deflates. Here + the number of equal eigenvalues are found. As each equal + eigenvalue is found, an elementary reflector is computed to rotate + the corresponding eigensubspace so that the corresponding + components of Z are zero in this new basis. +*/ + + *k = 0; + k2 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*rho * (r__1 = z__[j], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + indxp[k2] = j; + if (j == *n) { + goto L110; + } + } else { + jlam = j; + goto L80; + } +/* L70: */ + } +L80: + ++j; + if (j > *n) { + goto L100; + } + if (*rho * (r__1 = z__[j], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + indxp[k2] = j; + } else { + +/* Check if eigenvalues are close enough to allow deflation. */ + + s = z__[jlam]; + c__ = z__[j]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = slapy2_(&c__, &s); + t = d__[j] - d__[jlam]; + c__ /= tau; + s = -s / tau; + if ((r__1 = t * c__ * s, dabs(r__1)) <= tol) { + +/* Deflation is possible. */ + + z__[j] = tau; + z__[jlam] = 0.f; + +/* Record the appropriate Givens rotation */ + + ++(*givptr); + givcol[(*givptr << 1) + 1] = indxq[indx[jlam]]; + givcol[(*givptr << 1) + 2] = indxq[indx[j]]; + givnum[(*givptr << 1) + 1] = c__; + givnum[(*givptr << 1) + 2] = s; + if (*icompq == 1) { + srot_(qsiz, &q[indxq[indx[jlam]] * q_dim1 + 1], &c__1, &q[ + indxq[indx[j]] * q_dim1 + 1], &c__1, &c__, &s); + } + t = d__[jlam] * c__ * c__ + d__[j] * s * s; + d__[j] = d__[jlam] * s * s + d__[j] * c__ * c__; + d__[jlam] = t; + --k2; + i__ = 1; +L90: + if (k2 + i__ <= *n) { + if (d__[jlam] < d__[indxp[k2 + i__]]) { + indxp[k2 + i__ - 1] = indxp[k2 + i__]; + indxp[k2 + i__] = jlam; + ++i__; + goto L90; + } else { + indxp[k2 + i__ - 1] = jlam; + } + } else { + indxp[k2 + i__ - 1] = jlam; + } + jlam = j; + } else { + ++(*k); + w[*k] = z__[jlam]; + dlamda[*k] = d__[jlam]; + indxp[*k] = jlam; + jlam = j; + } + } + goto L80; +L100: + +/* Record the last eigenvalue. */ + + ++(*k); + w[*k] = z__[jlam]; + dlamda[*k] = d__[jlam]; + indxp[*k] = jlam; + +L110: + +/* + Sort the eigenvalues and corresponding eigenvectors into DLAMDA + and Q2 respectively. The eigenvalues/vectors which were not + deflated go into the first K slots of DLAMDA and Q2 respectively, + while those which were deflated go into the last N - K slots. +*/ + + if (*icompq == 0) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + jp = indxp[j]; + dlamda[j] = d__[jp]; + perm[j] = indxq[indx[jp]]; +/* L120: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + jp = indxp[j]; + dlamda[j] = d__[jp]; + perm[j] = indxq[indx[jp]]; + scopy_(qsiz, &q[perm[j] * q_dim1 + 1], &c__1, &q2[j * q2_dim1 + 1] + , &c__1); +/* L130: */ + } + } + +/* + The deflated eigenvalues and their corresponding vectors go back + into the last N - K slots of D and Q respectively. +*/ + + if (*k < *n) { + if (*icompq == 0) { + i__1 = *n - *k; + scopy_(&i__1, &dlamda[*k + 1], &c__1, &d__[*k + 1], &c__1); + } else { + i__1 = *n - *k; + scopy_(&i__1, &dlamda[*k + 1], &c__1, &d__[*k + 1], &c__1); + i__1 = *n - *k; + slacpy_("A", qsiz, &i__1, &q2[(*k + 1) * q2_dim1 + 1], ldq2, &q[(* + k + 1) * q_dim1 + 1], ldq); + } + } + + return 0; + +/* End of SLAED8 */ + +} /* slaed8_ */ + +/* Subroutine */ int slaed9_(integer *k, integer *kstart, integer *kstop, + integer *n, real *d__, real *q, integer *ldq, real *rho, real *dlamda, + real *w, real *s, integer *lds, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, s_dim1, s_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static integer i__, j; + static real temp; + extern doublereal snrm2_(integer *, real *, integer *); + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *), slaed4_(integer *, integer *, real *, real *, real *, + real *, real *, integer *); + extern doublereal slamc3_(real *, real *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAED9 finds the roots of the secular equation, as defined by the + values in D, Z, and RHO, between KSTART and KSTOP. It makes the + appropriate calls to SLAED4 and then stores the new matrix of + eigenvectors for use in calculating the next level of Z vectors. + + Arguments + ========= + + K (input) INTEGER + The number of terms in the rational function to be solved by + SLAED4. K >= 0. + + KSTART (input) INTEGER + KSTOP (input) INTEGER + The updated eigenvalues Lambda(I), KSTART <= I <= KSTOP + are to be computed. 1 <= KSTART <= KSTOP <= K. + + N (input) INTEGER + The number of rows and columns in the Q matrix. + N >= K (delation may result in N > K). + + D (output) REAL array, dimension (N) + D(I) contains the updated eigenvalues + for KSTART <= I <= KSTOP. + + Q (workspace) REAL array, dimension (LDQ,N) + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max( 1, N ). + + RHO (input) REAL + The value of the parameter in the rank one update equation. + RHO >= 0 required. + + DLAMDA (input) REAL array, dimension (K) + The first K elements of this array contain the old roots + of the deflated updating problem. These are the poles + of the secular equation. + + W (input) REAL array, dimension (K) + The first K elements of this array contain the components + of the deflation-adjusted updating vector. + + S (output) REAL array, dimension (LDS, K) + Will contain the eigenvectors of the repaired matrix which + will be stored for subsequent Z vector calculation and + multiplied by the previously accumulated eigenvectors + to update the system. + + LDS (input) INTEGER + The leading dimension of S. LDS >= max( 1, K ). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --dlamda; + --w; + s_dim1 = *lds; + s_offset = 1 + s_dim1; + s -= s_offset; + + /* Function Body */ + *info = 0; + + if (*k < 0) { + *info = -1; + } else if (*kstart < 1 || *kstart > max(1,*k)) { + *info = -2; + } else if (max(1,*kstop) < *kstart || *kstop > max(1,*k)) { + *info = -3; + } else if (*n < *k) { + *info = -4; + } else if (*ldq < max(1,*k)) { + *info = -7; + } else if (*lds < max(1,*k)) { + *info = -12; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAED9", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*k == 0) { + return 0; + } + +/* + Modify values DLAMDA(i) to make sure all DLAMDA(i)-DLAMDA(j) can + be computed with high relative accuracy (barring over/underflow). + This is a problem on machines without a guard digit in + add/subtract (Cray XMP, Cray YMP, Cray C 90 and Cray 2). + The following code replaces DLAMDA(I) by 2*DLAMDA(I)-DLAMDA(I), + which on any of these machines zeros out the bottommost + bit of DLAMDA(I) if it is 1; this makes the subsequent + subtractions DLAMDA(I)-DLAMDA(J) unproblematic when cancellation + occurs. On binary machines with a guard digit (almost all + machines) it does not change DLAMDA(I) at all. On hexadecimal + and decimal machines with a guard digit, it slightly + changes the bottommost bits of DLAMDA(I). It does not account + for hexadecimal or decimal machines without guard digits + (we know of none). We use a subroutine call to compute + 2*DLAMBDA(I) to prevent optimizing compilers from eliminating + this code. +*/ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = slamc3_(&dlamda[i__], &dlamda[i__]) - dlamda[i__]; +/* L10: */ + } + + i__1 = *kstop; + for (j = *kstart; j <= i__1; ++j) { + slaed4_(k, &j, &dlamda[1], &w[1], &q[j * q_dim1 + 1], rho, &d__[j], + info); + +/* If the zero finder fails, the computation is terminated. */ + + if (*info != 0) { + goto L120; + } +/* L20: */ + } + + if (*k == 1 || *k == 2) { + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *k; + for (j = 1; j <= i__2; ++j) { + s[j + i__ * s_dim1] = q[j + i__ * q_dim1]; +/* L30: */ + } +/* L40: */ + } + goto L120; + } + +/* Compute updated W. */ + + scopy_(k, &w[1], &c__1, &s[s_offset], &c__1); + +/* Initialize W(I) = Q(I,I) */ + + i__1 = *ldq + 1; + scopy_(k, &q[q_offset], &i__1, &w[1], &c__1); + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + w[i__] *= q[i__ + j * q_dim1] / (dlamda[i__] - dlamda[j]); +/* L50: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + w[i__] *= q[i__ + j * q_dim1] / (dlamda[i__] - dlamda[j]); +/* L60: */ + } +/* L70: */ + } + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + r__1 = sqrt(-w[i__]); + w[i__] = r_sign(&r__1, &s[i__ + s_dim1]); +/* L80: */ + } + +/* Compute eigenvectors of the modified rank-1 modification. */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = *k; + for (i__ = 1; i__ <= i__2; ++i__) { + q[i__ + j * q_dim1] = w[i__] / q[i__ + j * q_dim1]; +/* L90: */ + } + temp = snrm2_(k, &q[j * q_dim1 + 1], &c__1); + i__2 = *k; + for (i__ = 1; i__ <= i__2; ++i__) { + s[i__ + j * s_dim1] = q[i__ + j * q_dim1] / temp; +/* L100: */ + } +/* L110: */ + } + +L120: + return 0; + +/* End of SLAED9 */ + +} /* slaed9_ */ + +/* Subroutine */ int slaeda_(integer *n, integer *tlvls, integer *curlvl, + integer *curpbm, integer *prmptr, integer *perm, integer *givptr, + integer *givcol, real *givnum, real *q, integer *qptr, real *z__, + real *ztemp, integer *info) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + + /* Local variables */ + static integer i__, k, mid, ptr, curr; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *); + static integer bsiz1, bsiz2, psiz1, psiz2, zptr1; + extern /* Subroutine */ int sgemv_(char *, integer *, integer *, real *, + real *, integer *, real *, integer *, real *, real *, integer *), scopy_(integer *, real *, integer *, real *, integer *), + xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SLAEDA computes the Z vector corresponding to the merge step in the + CURLVLth step of the merge process with TLVLS steps for the CURPBMth + problem. + + Arguments + ========= + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + TLVLS (input) INTEGER + The total number of merging levels in the overall divide and + conquer tree. + + CURLVL (input) INTEGER + The current level in the overall merge routine, + 0 <= curlvl <= tlvls. + + CURPBM (input) INTEGER + The current problem in the current level in the overall + merge routine (counting from upper left to lower right). + + PRMPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in PERM a + level's permutation is stored. PRMPTR(i+1) - PRMPTR(i) + indicates the size of the permutation and incidentally the + size of the full, non-deflated problem. + + PERM (input) INTEGER array, dimension (N lg N) + Contains the permutations (from deflation and sorting) to be + applied to each eigenblock. + + GIVPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in GIVCOL a + level's Givens rotations are stored. GIVPTR(i+1) - GIVPTR(i) + indicates the number of Givens rotations. + + GIVCOL (input) INTEGER array, dimension (2, N lg N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (input) REAL array, dimension (2, N lg N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + Q (input) REAL array, dimension (N**2) + Contains the square eigenblocks from previous levels, the + starting positions for blocks are given by QPTR. + + QPTR (input) INTEGER array, dimension (N+2) + Contains a list of pointers which indicate where in Q an + eigenblock is stored. SQRT( QPTR(i+1) - QPTR(i) ) indicates + the size of the block. + + Z (output) REAL array, dimension (N) + On output this vector contains the updating vector (the last + row of the first sub-eigenvector matrix and the first row of + the second sub-eigenvector matrix). + + ZTEMP (workspace) REAL array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --ztemp; + --z__; + --qptr; + --q; + givnum -= 3; + givcol -= 3; + --givptr; + --perm; + --prmptr; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -1; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAEDA", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine location of first number in second half. */ + + mid = *n / 2 + 1; + +/* Gather last/first rows of appropriate eigenblocks into center of Z */ + + ptr = 1; + +/* + Determine location of lowest level subproblem in the full storage + scheme +*/ + + i__1 = *curlvl - 1; + curr = ptr + *curpbm * pow_ii(&c__2, curlvl) + pow_ii(&c__2, &i__1) - 1; + +/* + Determine size of these matrices. We add HALF to the value of + the SQRT in case the machine underestimates one of these square + roots. +*/ + + bsiz1 = (integer) (sqrt((real) (qptr[curr + 1] - qptr[curr])) + .5f); + bsiz2 = (integer) (sqrt((real) (qptr[curr + 2] - qptr[curr + 1])) + .5f); + i__1 = mid - bsiz1 - 1; + for (k = 1; k <= i__1; ++k) { + z__[k] = 0.f; +/* L10: */ + } + scopy_(&bsiz1, &q[qptr[curr] + bsiz1 - 1], &bsiz1, &z__[mid - bsiz1], & + c__1); + scopy_(&bsiz2, &q[qptr[curr + 1]], &bsiz2, &z__[mid], &c__1); + i__1 = *n; + for (k = mid + bsiz2; k <= i__1; ++k) { + z__[k] = 0.f; +/* L20: */ + } + +/* + Loop through remaining levels 1 -> CURLVL applying the Givens + rotations and permutation and then multiplying the center matrices + against the current Z. +*/ + + ptr = pow_ii(&c__2, tlvls) + 1; + i__1 = *curlvl - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = *curlvl - k; + i__3 = *curlvl - k - 1; + curr = ptr + *curpbm * pow_ii(&c__2, &i__2) + pow_ii(&c__2, &i__3) - + 1; + psiz1 = prmptr[curr + 1] - prmptr[curr]; + psiz2 = prmptr[curr + 2] - prmptr[curr + 1]; + zptr1 = mid - psiz1; + +/* Apply Givens at CURR and CURR+1 */ + + i__2 = givptr[curr + 1] - 1; + for (i__ = givptr[curr]; i__ <= i__2; ++i__) { + srot_(&c__1, &z__[zptr1 + givcol[(i__ << 1) + 1] - 1], &c__1, & + z__[zptr1 + givcol[(i__ << 1) + 2] - 1], &c__1, &givnum[( + i__ << 1) + 1], &givnum[(i__ << 1) + 2]); +/* L30: */ + } + i__2 = givptr[curr + 2] - 1; + for (i__ = givptr[curr + 1]; i__ <= i__2; ++i__) { + srot_(&c__1, &z__[mid - 1 + givcol[(i__ << 1) + 1]], &c__1, &z__[ + mid - 1 + givcol[(i__ << 1) + 2]], &c__1, &givnum[(i__ << + 1) + 1], &givnum[(i__ << 1) + 2]); +/* L40: */ + } + psiz1 = prmptr[curr + 1] - prmptr[curr]; + psiz2 = prmptr[curr + 2] - prmptr[curr + 1]; + i__2 = psiz1 - 1; + for (i__ = 0; i__ <= i__2; ++i__) { + ztemp[i__ + 1] = z__[zptr1 + perm[prmptr[curr] + i__] - 1]; +/* L50: */ + } + i__2 = psiz2 - 1; + for (i__ = 0; i__ <= i__2; ++i__) { + ztemp[psiz1 + i__ + 1] = z__[mid + perm[prmptr[curr + 1] + i__] - + 1]; +/* L60: */ + } + +/* + Multiply Blocks at CURR and CURR+1 + + Determine size of these matrices. We add HALF to the value of + the SQRT in case the machine underestimates one of these + square roots. +*/ + + bsiz1 = (integer) (sqrt((real) (qptr[curr + 1] - qptr[curr])) + .5f); + bsiz2 = (integer) (sqrt((real) (qptr[curr + 2] - qptr[curr + 1])) + + .5f); + if (bsiz1 > 0) { + sgemv_("T", &bsiz1, &bsiz1, &c_b15, &q[qptr[curr]], &bsiz1, & + ztemp[1], &c__1, &c_b29, &z__[zptr1], &c__1); + } + i__2 = psiz1 - bsiz1; + scopy_(&i__2, &ztemp[bsiz1 + 1], &c__1, &z__[zptr1 + bsiz1], &c__1); + if (bsiz2 > 0) { + sgemv_("T", &bsiz2, &bsiz2, &c_b15, &q[qptr[curr + 1]], &bsiz2, & + ztemp[psiz1 + 1], &c__1, &c_b29, &z__[mid], &c__1); + } + i__2 = psiz2 - bsiz2; + scopy_(&i__2, &ztemp[psiz1 + bsiz2 + 1], &c__1, &z__[mid + bsiz2], & + c__1); + + i__2 = *tlvls - k; + ptr += pow_ii(&c__2, &i__2); +/* L70: */ + } + + return 0; + +/* End of SLAEDA */ + +} /* slaeda_ */ + +/* Subroutine */ int slaev2_(real *a, real *b, real *c__, real *rt1, real * + rt2, real *cs1, real *sn1) +{ + /* System generated locals */ + real r__1; + + /* Local variables */ + static real ab, df, cs, ct, tb, sm, tn, rt, adf, acs; + static integer sgn1, sgn2; + static real acmn, acmx; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAEV2 computes the eigendecomposition of a 2-by-2 symmetric matrix + [ A B ] + [ B C ]. + On return, RT1 is the eigenvalue of larger absolute value, RT2 is the + eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right + eigenvector for RT1, giving the decomposition + + [ CS1 SN1 ] [ A B ] [ CS1 -SN1 ] = [ RT1 0 ] + [-SN1 CS1 ] [ B C ] [ SN1 CS1 ] [ 0 RT2 ]. + + Arguments + ========= + + A (input) REAL + The (1,1) element of the 2-by-2 matrix. + + B (input) REAL + The (1,2) element and the conjugate of the (2,1) element of + the 2-by-2 matrix. + + C (input) REAL + The (2,2) element of the 2-by-2 matrix. + + RT1 (output) REAL + The eigenvalue of larger absolute value. + + RT2 (output) REAL + The eigenvalue of smaller absolute value. + + CS1 (output) REAL + SN1 (output) REAL + The vector (CS1, SN1) is a unit right eigenvector for RT1. + + Further Details + =============== + + RT1 is accurate to a few ulps barring over/underflow. + + RT2 may be inaccurate if there is massive cancellation in the + determinant A*C-B*B; higher precision or correctly rounded or + correctly truncated arithmetic would be needed to compute RT2 + accurately in all cases. + + CS1 and SN1 are accurate to a few ulps barring over/underflow. + + Overflow is possible only if RT1 is within a factor of 5 of overflow. + Underflow is harmless if the input data is 0 or exceeds + underflow_threshold / macheps. + + ===================================================================== + + + Compute the eigenvalues +*/ + + sm = *a + *c__; + df = *a - *c__; + adf = dabs(df); + tb = *b + *b; + ab = dabs(tb); + if (dabs(*a) > dabs(*c__)) { + acmx = *a; + acmn = *c__; + } else { + acmx = *c__; + acmn = *a; + } + if (adf > ab) { +/* Computing 2nd power */ + r__1 = ab / adf; + rt = adf * sqrt(r__1 * r__1 + 1.f); + } else if (adf < ab) { +/* Computing 2nd power */ + r__1 = adf / ab; + rt = ab * sqrt(r__1 * r__1 + 1.f); + } else { + +/* Includes case AB=ADF=0 */ + + rt = ab * sqrt(2.f); + } + if (sm < 0.f) { + *rt1 = (sm - rt) * .5f; + sgn1 = -1; + +/* + Order of execution important. + To get fully accurate smaller eigenvalue, + next line needs to be executed in higher precision. +*/ + + *rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b; + } else if (sm > 0.f) { + *rt1 = (sm + rt) * .5f; + sgn1 = 1; + +/* + Order of execution important. + To get fully accurate smaller eigenvalue, + next line needs to be executed in higher precision. +*/ + + *rt2 = acmx / *rt1 * acmn - *b / *rt1 * *b; + } else { + +/* Includes case RT1 = RT2 = 0 */ + + *rt1 = rt * .5f; + *rt2 = rt * -.5f; + sgn1 = 1; + } + +/* Compute the eigenvector */ + + if (df >= 0.f) { + cs = df + rt; + sgn2 = 1; + } else { + cs = df - rt; + sgn2 = -1; + } + acs = dabs(cs); + if (acs > ab) { + ct = -tb / cs; + *sn1 = 1.f / sqrt(ct * ct + 1.f); + *cs1 = ct * *sn1; + } else { + if (ab == 0.f) { + *cs1 = 1.f; + *sn1 = 0.f; + } else { + tn = -cs / tb; + *cs1 = 1.f / sqrt(tn * tn + 1.f); + *sn1 = tn * *cs1; + } + } + if (sgn1 == sgn2) { + tn = *cs1; + *cs1 = -(*sn1); + *sn1 = tn; + } + return 0; + +/* End of SLAEV2 */ + +} /* slaev2_ */ + +/* Subroutine */ int slaexc_(logical *wantq, integer *n, real *t, integer * + ldt, real *q, integer *ldq, integer *j1, integer *n1, integer *n2, + real *work, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, t_dim1, t_offset, i__1; + real r__1, r__2, r__3; + + /* Local variables */ + static real d__[16] /* was [4][4] */; + static integer k; + static real u[3], x[4] /* was [2][2] */; + static integer j2, j3, j4; + static real u1[3], u2[3]; + static integer nd; + static real cs, t11, t22, t33, sn, wi1, wi2, wr1, wr2, eps, tau, tau1, + tau2; + static integer ierr; + static real temp; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *); + static real scale, dnorm, xnorm; + extern /* Subroutine */ int slanv2_(real *, real *, real *, real *, real * + , real *, real *, real *, real *, real *), slasy2_(logical *, + logical *, integer *, integer *, integer *, real *, integer *, + real *, integer *, real *, integer *, real *, real *, integer *, + real *, integer *); + extern doublereal slamch_(char *), slange_(char *, integer *, + integer *, real *, integer *, real *); + extern /* Subroutine */ int slarfg_(integer *, real *, real *, integer *, + real *), slacpy_(char *, integer *, integer *, real *, integer *, + real *, integer *), slartg_(real *, real *, real *, real * + , real *); + static real thresh; + extern /* Subroutine */ int slarfx_(char *, integer *, integer *, real *, + real *, real *, integer *, real *); + static real smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAEXC swaps adjacent diagonal blocks T11 and T22 of order 1 or 2 in + an upper quasi-triangular matrix T by an orthogonal similarity + transformation. + + T must be in Schur canonical form, that is, block upper triangular + with 1-by-1 and 2-by-2 diagonal blocks; each 2-by-2 diagonal block + has its diagonal elemnts equal and its off-diagonal elements of + opposite sign. + + Arguments + ========= + + WANTQ (input) LOGICAL + = .TRUE. : accumulate the transformation in the matrix Q; + = .FALSE.: do not accumulate the transformation. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input/output) REAL array, dimension (LDT,N) + On entry, the upper quasi-triangular matrix T, in Schur + canonical form. + On exit, the updated matrix T, again in Schur canonical form. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + Q (input/output) REAL array, dimension (LDQ,N) + On entry, if WANTQ is .TRUE., the orthogonal matrix Q. + On exit, if WANTQ is .TRUE., the updated matrix Q. + If WANTQ is .FALSE., Q is not referenced. + + LDQ (input) INTEGER + The leading dimension of the array Q. + LDQ >= 1; and if WANTQ is .TRUE., LDQ >= N. + + J1 (input) INTEGER + The index of the first row of the first block T11. + + N1 (input) INTEGER + The order of the first block T11. N1 = 0, 1 or 2. + + N2 (input) INTEGER + The order of the second block T22. N2 = 0, 1 or 2. + + WORK (workspace) REAL array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + = 1: the transformed matrix T would be too far from Schur + form; the blocks are not swapped and T and Q are + unchanged. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --work; + + /* Function Body */ + *info = 0; + +/* Quick return if possible */ + + if (*n == 0 || *n1 == 0 || *n2 == 0) { + return 0; + } + if (*j1 + *n1 > *n) { + return 0; + } + + j2 = *j1 + 1; + j3 = *j1 + 2; + j4 = *j1 + 3; + + if (*n1 == 1 && *n2 == 1) { + +/* Swap two 1-by-1 blocks. */ + + t11 = t[*j1 + *j1 * t_dim1]; + t22 = t[j2 + j2 * t_dim1]; + +/* Determine the transformation to perform the interchange. */ + + r__1 = t22 - t11; + slartg_(&t[*j1 + j2 * t_dim1], &r__1, &cs, &sn, &temp); + +/* Apply transformation to the matrix T. */ + + if (j3 <= *n) { + i__1 = *n - *j1 - 1; + srot_(&i__1, &t[*j1 + j3 * t_dim1], ldt, &t[j2 + j3 * t_dim1], + ldt, &cs, &sn); + } + i__1 = *j1 - 1; + srot_(&i__1, &t[*j1 * t_dim1 + 1], &c__1, &t[j2 * t_dim1 + 1], &c__1, + &cs, &sn); + + t[*j1 + *j1 * t_dim1] = t22; + t[j2 + j2 * t_dim1] = t11; + + if (*wantq) { + +/* Accumulate transformation in the matrix Q. */ + + srot_(n, &q[*j1 * q_dim1 + 1], &c__1, &q[j2 * q_dim1 + 1], &c__1, + &cs, &sn); + } + + } else { + +/* + Swapping involves at least one 2-by-2 block. + + Copy the diagonal block of order N1+N2 to the local array D + and compute its norm. +*/ + + nd = *n1 + *n2; + slacpy_("Full", &nd, &nd, &t[*j1 + *j1 * t_dim1], ldt, d__, &c__4); + dnorm = slange_("Max", &nd, &nd, d__, &c__4, &work[1]); + +/* + Compute machine-dependent threshold for test for accepting + swap. +*/ + + eps = slamch_("P"); + smlnum = slamch_("S") / eps; +/* Computing MAX */ + r__1 = eps * 10.f * dnorm; + thresh = dmax(r__1,smlnum); + +/* Solve T11*X - X*T22 = scale*T12 for X. */ + + slasy2_(&c_false, &c_false, &c_n1, n1, n2, d__, &c__4, &d__[*n1 + 1 + + (*n1 + 1 << 2) - 5], &c__4, &d__[(*n1 + 1 << 2) - 4], &c__4, & + scale, x, &c__2, &xnorm, &ierr); + +/* Swap the adjacent diagonal blocks. */ + + k = *n1 + *n1 + *n2 - 3; + switch (k) { + case 1: goto L10; + case 2: goto L20; + case 3: goto L30; + } + +L10: + +/* + N1 = 1, N2 = 2: generate elementary reflector H so that: + + ( scale, X11, X12 ) H = ( 0, 0, * ) +*/ + + u[0] = scale; + u[1] = x[0]; + u[2] = x[2]; + slarfg_(&c__3, &u[2], u, &c__1, &tau); + u[2] = 1.f; + t11 = t[*j1 + *j1 * t_dim1]; + +/* Perform swap provisionally on diagonal block in D. */ + + slarfx_("L", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]); + slarfx_("R", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]); + +/* + Test whether to reject swap. + + Computing MAX +*/ + r__2 = dabs(d__[2]), r__3 = dabs(d__[6]), r__2 = max(r__2,r__3), r__3 + = (r__1 = d__[10] - t11, dabs(r__1)); + if (dmax(r__2,r__3) > thresh) { + goto L50; + } + +/* Accept swap: apply transformation to the entire matrix T. */ + + i__1 = *n - *j1 + 1; + slarfx_("L", &c__3, &i__1, u, &tau, &t[*j1 + *j1 * t_dim1], ldt, & + work[1]); + slarfx_("R", &j2, &c__3, u, &tau, &t[*j1 * t_dim1 + 1], ldt, &work[1]); + + t[j3 + *j1 * t_dim1] = 0.f; + t[j3 + j2 * t_dim1] = 0.f; + t[j3 + j3 * t_dim1] = t11; + + if (*wantq) { + +/* Accumulate transformation in the matrix Q. */ + + slarfx_("R", n, &c__3, u, &tau, &q[*j1 * q_dim1 + 1], ldq, &work[ + 1]); + } + goto L40; + +L20: + +/* + N1 = 2, N2 = 1: generate elementary reflector H so that: + + H ( -X11 ) = ( * ) + ( -X21 ) = ( 0 ) + ( scale ) = ( 0 ) +*/ + + u[0] = -x[0]; + u[1] = -x[1]; + u[2] = scale; + slarfg_(&c__3, u, &u[1], &c__1, &tau); + u[0] = 1.f; + t33 = t[j3 + j3 * t_dim1]; + +/* Perform swap provisionally on diagonal block in D. */ + + slarfx_("L", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]); + slarfx_("R", &c__3, &c__3, u, &tau, d__, &c__4, &work[1]); + +/* + Test whether to reject swap. + + Computing MAX +*/ + r__2 = dabs(d__[1]), r__3 = dabs(d__[2]), r__2 = max(r__2,r__3), r__3 + = (r__1 = d__[0] - t33, dabs(r__1)); + if (dmax(r__2,r__3) > thresh) { + goto L50; + } + +/* Accept swap: apply transformation to the entire matrix T. */ + + slarfx_("R", &j3, &c__3, u, &tau, &t[*j1 * t_dim1 + 1], ldt, &work[1]); + i__1 = *n - *j1; + slarfx_("L", &c__3, &i__1, u, &tau, &t[*j1 + j2 * t_dim1], ldt, &work[ + 1]); + + t[*j1 + *j1 * t_dim1] = t33; + t[j2 + *j1 * t_dim1] = 0.f; + t[j3 + *j1 * t_dim1] = 0.f; + + if (*wantq) { + +/* Accumulate transformation in the matrix Q. */ + + slarfx_("R", n, &c__3, u, &tau, &q[*j1 * q_dim1 + 1], ldq, &work[ + 1]); + } + goto L40; + +L30: + +/* + N1 = 2, N2 = 2: generate elementary reflectors H(1) and H(2) so + that: + + H(2) H(1) ( -X11 -X12 ) = ( * * ) + ( -X21 -X22 ) ( 0 * ) + ( scale 0 ) ( 0 0 ) + ( 0 scale ) ( 0 0 ) +*/ + + u1[0] = -x[0]; + u1[1] = -x[1]; + u1[2] = scale; + slarfg_(&c__3, u1, &u1[1], &c__1, &tau1); + u1[0] = 1.f; + + temp = -tau1 * (x[2] + u1[1] * x[3]); + u2[0] = -temp * u1[1] - x[3]; + u2[1] = -temp * u1[2]; + u2[2] = scale; + slarfg_(&c__3, u2, &u2[1], &c__1, &tau2); + u2[0] = 1.f; + +/* Perform swap provisionally on diagonal block in D. */ + + slarfx_("L", &c__3, &c__4, u1, &tau1, d__, &c__4, &work[1]) + ; + slarfx_("R", &c__4, &c__3, u1, &tau1, d__, &c__4, &work[1]) + ; + slarfx_("L", &c__3, &c__4, u2, &tau2, &d__[1], &c__4, &work[1]); + slarfx_("R", &c__4, &c__3, u2, &tau2, &d__[4], &c__4, &work[1]); + +/* + Test whether to reject swap. + + Computing MAX +*/ + r__1 = dabs(d__[2]), r__2 = dabs(d__[6]), r__1 = max(r__1,r__2), r__2 + = dabs(d__[3]), r__1 = max(r__1,r__2), r__2 = dabs(d__[7]); + if (dmax(r__1,r__2) > thresh) { + goto L50; + } + +/* Accept swap: apply transformation to the entire matrix T. */ + + i__1 = *n - *j1 + 1; + slarfx_("L", &c__3, &i__1, u1, &tau1, &t[*j1 + *j1 * t_dim1], ldt, & + work[1]); + slarfx_("R", &j4, &c__3, u1, &tau1, &t[*j1 * t_dim1 + 1], ldt, &work[ + 1]); + i__1 = *n - *j1 + 1; + slarfx_("L", &c__3, &i__1, u2, &tau2, &t[j2 + *j1 * t_dim1], ldt, & + work[1]); + slarfx_("R", &j4, &c__3, u2, &tau2, &t[j2 * t_dim1 + 1], ldt, &work[1] + ); + + t[j3 + *j1 * t_dim1] = 0.f; + t[j3 + j2 * t_dim1] = 0.f; + t[j4 + *j1 * t_dim1] = 0.f; + t[j4 + j2 * t_dim1] = 0.f; + + if (*wantq) { + +/* Accumulate transformation in the matrix Q. */ + + slarfx_("R", n, &c__3, u1, &tau1, &q[*j1 * q_dim1 + 1], ldq, & + work[1]); + slarfx_("R", n, &c__3, u2, &tau2, &q[j2 * q_dim1 + 1], ldq, &work[ + 1]); + } + +L40: + + if (*n2 == 2) { + +/* Standardize new 2-by-2 block T11 */ + + slanv2_(&t[*j1 + *j1 * t_dim1], &t[*j1 + j2 * t_dim1], &t[j2 + * + j1 * t_dim1], &t[j2 + j2 * t_dim1], &wr1, &wi1, &wr2, & + wi2, &cs, &sn); + i__1 = *n - *j1 - 1; + srot_(&i__1, &t[*j1 + (*j1 + 2) * t_dim1], ldt, &t[j2 + (*j1 + 2) + * t_dim1], ldt, &cs, &sn); + i__1 = *j1 - 1; + srot_(&i__1, &t[*j1 * t_dim1 + 1], &c__1, &t[j2 * t_dim1 + 1], & + c__1, &cs, &sn); + if (*wantq) { + srot_(n, &q[*j1 * q_dim1 + 1], &c__1, &q[j2 * q_dim1 + 1], & + c__1, &cs, &sn); + } + } + + if (*n1 == 2) { + +/* Standardize new 2-by-2 block T22 */ + + j3 = *j1 + *n2; + j4 = j3 + 1; + slanv2_(&t[j3 + j3 * t_dim1], &t[j3 + j4 * t_dim1], &t[j4 + j3 * + t_dim1], &t[j4 + j4 * t_dim1], &wr1, &wi1, &wr2, &wi2, & + cs, &sn); + if (j3 + 2 <= *n) { + i__1 = *n - j3 - 1; + srot_(&i__1, &t[j3 + (j3 + 2) * t_dim1], ldt, &t[j4 + (j3 + 2) + * t_dim1], ldt, &cs, &sn); + } + i__1 = j3 - 1; + srot_(&i__1, &t[j3 * t_dim1 + 1], &c__1, &t[j4 * t_dim1 + 1], & + c__1, &cs, &sn); + if (*wantq) { + srot_(n, &q[j3 * q_dim1 + 1], &c__1, &q[j4 * q_dim1 + 1], & + c__1, &cs, &sn); + } + } + + } + return 0; + +/* Exit with INFO = 1 if swap was rejected. */ + +L50: + *info = 1; + return 0; + +/* End of SLAEXC */ + +} /* slaexc_ */ + +/* Subroutine */ int slahqr_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, real *h__, integer *ldh, real *wr, real * + wi, integer *iloz, integer *ihiz, real *z__, integer *ldz, integer * + info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3; + real r__1, r__2, r__3, r__4; + + /* Local variables */ + static integer i__, j, k, l, m; + static real s, v[3]; + static integer i1, i2; + static real t1, t2, t3, v2, v3, aa, ab, ba, bb, h11, h12, h21, h22, cs; + static integer nh; + static real sn; + static integer nr; + static real tr; + static integer nz; + static real det, h21s; + static integer its; + static real ulp, sum, tst, rt1i, rt2i, rt1r, rt2r; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *), scopy_(integer *, real *, integer *, + real *, integer *), slanv2_(real *, real *, real *, real *, real * + , real *, real *, real *, real *, real *), slabad_(real *, real *) + ; + extern doublereal slamch_(char *); + static real safmin; + extern /* Subroutine */ int slarfg_(integer *, real *, real *, integer *, + real *); + static real safmax, rtdisc, smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Purpose + ======= + + SLAHQR is an auxiliary routine called by SHSEQR to update the + eigenvalues and Schur decomposition already computed by SHSEQR, by + dealing with the Hessenberg submatrix in rows and columns ILO to + IHI. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper quasi-triangular in + rows and columns IHI+1:N, and that H(ILO,ILO-1) = 0 (unless + ILO = 1). SLAHQR works primarily with the Hessenberg + submatrix in rows and columns ILO to IHI, but applies + transformations to all of H if WANTT is .TRUE.. + 1 <= ILO <= max(1,IHI); IHI <= N. + + H (input/output) REAL array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO is zero and if WANTT is .TRUE., H is upper + quasi-triangular in rows and columns ILO:IHI, with any + 2-by-2 diagonal blocks in standard form. If INFO is zero + and WANTT is .FALSE., the contents of H are unspecified on + exit. The output state of H if INFO is nonzero is given + below under the description of INFO. + + LDH (input) INTEGER + The leading dimension of the array H. LDH >= max(1,N). + + WR (output) REAL array, dimension (N) + WI (output) REAL array, dimension (N) + The real and imaginary parts, respectively, of the computed + eigenvalues ILO to IHI are stored in the corresponding + elements of WR and WI. If two eigenvalues are computed as a + complex conjugate pair, they are stored in consecutive + elements of WR and WI, say the i-th and (i+1)th, with + WI(i) > 0 and WI(i+1) < 0. If WANTT is .TRUE., the + eigenvalues are stored in the same order as on the diagonal + of the Schur form returned in H, with WR(i) = H(i,i), and, if + H(i:i+1,i:i+1) is a 2-by-2 diagonal block, + WI(i) = sqrt(H(i+1,i)*H(i,i+1)) and WI(i+1) = -WI(i). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. + 1 <= ILOZ <= ILO; IHI <= IHIZ <= N. + + Z (input/output) REAL array, dimension (LDZ,N) + If WANTZ is .TRUE., on entry Z must contain the current + matrix Z of transformations accumulated by SHSEQR, and on + exit Z has been updated; transformations are applied only to + the submatrix Z(ILOZ:IHIZ,ILO:IHI). + If WANTZ is .FALSE., Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: If INFO = i, SLAHQR failed to compute all the + eigenvalues ILO to IHI in a total of 30 iterations + per eigenvalue; elements i+1:ihi of WR and WI + contain those eigenvalues which have been + successfully computed. + + If INFO .GT. 0 and WANTT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the + eigenvalues of the upper Hessenberg matrix rows + and columns ILO thorugh INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + (*) (initial value of H)*U = U*(final value of H) + where U is an orthognal matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + (final value of Z) = (initial value of Z)*U + where U is the orthogonal matrix in (*) + (regardless of the value of WANTT.) + + Further Details + =============== + + 02-96 Based on modifications by + David Day, Sandia National Laboratory, USA + + 12-04 Further modifications by + Ralph Byers, University of Kansas, USA + This is a modified version of SLAHQR from LAPACK version 3.0. + It is (1) more robust against overflow and underflow and + (2) adopts the more conservative Ahues & Tisseur stopping + criterion (LAWN 122, 1997). + + ========================================================= +*/ + + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --wr; + --wi; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + + /* Function Body */ + *info = 0; + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*ilo == *ihi) { + wr[*ilo] = h__[*ilo + *ilo * h_dim1]; + wi[*ilo] = 0.f; + return 0; + } + +/* ==== clear out the trash ==== */ + i__1 = *ihi - 3; + for (j = *ilo; j <= i__1; ++j) { + h__[j + 2 + j * h_dim1] = 0.f; + h__[j + 3 + j * h_dim1] = 0.f; +/* L10: */ + } + if (*ilo <= *ihi - 2) { + h__[*ihi + (*ihi - 2) * h_dim1] = 0.f; + } + + nh = *ihi - *ilo + 1; + nz = *ihiz - *iloz + 1; + +/* Set machine-dependent constants for the stopping criterion. */ + + safmin = slamch_("SAFE MINIMUM"); + safmax = 1.f / safmin; + slabad_(&safmin, &safmax); + ulp = slamch_("PRECISION"); + smlnum = safmin * ((real) nh / ulp); + +/* + I1 and I2 are the indices of the first row and last column of H + to which transformations must be applied. If eigenvalues only are + being computed, I1 and I2 are set inside the main loop. +*/ + + if (*wantt) { + i1 = 1; + i2 = *n; + } + +/* + The main loop begins here. I is the loop index and decreases from + IHI to ILO in steps of 1 or 2. Each iteration of the loop works + with the active submatrix in rows and columns L to I. + Eigenvalues I+1 to IHI have already converged. Either L = ILO or + H(L,L-1) is negligible so that the matrix splits. +*/ + + i__ = *ihi; +L20: + l = *ilo; + if (i__ < *ilo) { + goto L160; + } + +/* + Perform QR iterations on rows and columns ILO to I until a + submatrix of order 1 or 2 splits off at the bottom because a + subdiagonal element has become negligible. +*/ + + for (its = 0; its <= 30; ++its) { + +/* Look for a single small subdiagonal element. */ + + i__1 = l + 1; + for (k = i__; k >= i__1; --k) { + if ((r__1 = h__[k + (k - 1) * h_dim1], dabs(r__1)) <= smlnum) { + goto L40; + } + tst = (r__1 = h__[k - 1 + (k - 1) * h_dim1], dabs(r__1)) + (r__2 = + h__[k + k * h_dim1], dabs(r__2)); + if (tst == 0.f) { + if (k - 2 >= *ilo) { + tst += (r__1 = h__[k - 1 + (k - 2) * h_dim1], dabs(r__1)); + } + if (k + 1 <= *ihi) { + tst += (r__1 = h__[k + 1 + k * h_dim1], dabs(r__1)); + } + } +/* + ==== The following is a conservative small subdiagonal + . deflation criterion due to Ahues & Tisseur (LAWN 122, + . 1997). It has better mathematical foundation and + . improves accuracy in some cases. ==== +*/ + if ((r__1 = h__[k + (k - 1) * h_dim1], dabs(r__1)) <= ulp * tst) { +/* Computing MAX */ + r__3 = (r__1 = h__[k + (k - 1) * h_dim1], dabs(r__1)), r__4 = + (r__2 = h__[k - 1 + k * h_dim1], dabs(r__2)); + ab = dmax(r__3,r__4); +/* Computing MIN */ + r__3 = (r__1 = h__[k + (k - 1) * h_dim1], dabs(r__1)), r__4 = + (r__2 = h__[k - 1 + k * h_dim1], dabs(r__2)); + ba = dmin(r__3,r__4); +/* Computing MAX */ + r__3 = (r__1 = h__[k + k * h_dim1], dabs(r__1)), r__4 = (r__2 + = h__[k - 1 + (k - 1) * h_dim1] - h__[k + k * h_dim1], + dabs(r__2)); + aa = dmax(r__3,r__4); +/* Computing MIN */ + r__3 = (r__1 = h__[k + k * h_dim1], dabs(r__1)), r__4 = (r__2 + = h__[k - 1 + (k - 1) * h_dim1] - h__[k + k * h_dim1], + dabs(r__2)); + bb = dmin(r__3,r__4); + s = aa + ab; +/* Computing MAX */ + r__1 = smlnum, r__2 = ulp * (bb * (aa / s)); + if (ba * (ab / s) <= dmax(r__1,r__2)) { + goto L40; + } + } +/* L30: */ + } +L40: + l = k; + if (l > *ilo) { + +/* H(L,L-1) is negligible */ + + h__[l + (l - 1) * h_dim1] = 0.f; + } + +/* Exit from loop if a submatrix of order 1 or 2 has split off. */ + + if (l >= i__ - 1) { + goto L150; + } + +/* + Now the active submatrix is in rows and columns L to I. If + eigenvalues only are being computed, only the active submatrix + need be transformed. +*/ + + if (! (*wantt)) { + i1 = l; + i2 = i__; + } + + if (its == 10) { + +/* Exceptional shift. */ + + s = (r__1 = h__[l + 1 + l * h_dim1], dabs(r__1)) + (r__2 = h__[l + + 2 + (l + 1) * h_dim1], dabs(r__2)); + h11 = s * .75f + h__[l + l * h_dim1]; + h12 = s * -.4375f; + h21 = s; + h22 = h11; + } else if (its == 20) { + +/* Exceptional shift. */ + + s = (r__1 = h__[i__ + (i__ - 1) * h_dim1], dabs(r__1)) + (r__2 = + h__[i__ - 1 + (i__ - 2) * h_dim1], dabs(r__2)); + h11 = s * .75f + h__[i__ + i__ * h_dim1]; + h12 = s * -.4375f; + h21 = s; + h22 = h11; + } else { + +/* + Prepare to use Francis' double shift + (i.e. 2nd degree generalized Rayleigh quotient) +*/ + + h11 = h__[i__ - 1 + (i__ - 1) * h_dim1]; + h21 = h__[i__ + (i__ - 1) * h_dim1]; + h12 = h__[i__ - 1 + i__ * h_dim1]; + h22 = h__[i__ + i__ * h_dim1]; + } + s = dabs(h11) + dabs(h12) + dabs(h21) + dabs(h22); + if (s == 0.f) { + rt1r = 0.f; + rt1i = 0.f; + rt2r = 0.f; + rt2i = 0.f; + } else { + h11 /= s; + h21 /= s; + h12 /= s; + h22 /= s; + tr = (h11 + h22) / 2.f; + det = (h11 - tr) * (h22 - tr) - h12 * h21; + rtdisc = sqrt((dabs(det))); + if (det >= 0.f) { + +/* ==== complex conjugate shifts ==== */ + + rt1r = tr * s; + rt2r = rt1r; + rt1i = rtdisc * s; + rt2i = -rt1i; + } else { + +/* ==== real shifts (use only one of them) ==== */ + + rt1r = tr + rtdisc; + rt2r = tr - rtdisc; + if ((r__1 = rt1r - h22, dabs(r__1)) <= (r__2 = rt2r - h22, + dabs(r__2))) { + rt1r *= s; + rt2r = rt1r; + } else { + rt2r *= s; + rt1r = rt2r; + } + rt1i = 0.f; + rt2i = 0.f; + } + } + +/* Look for two consecutive small subdiagonal elements. */ + + i__1 = l; + for (m = i__ - 2; m >= i__1; --m) { +/* + Determine the effect of starting the double-shift QR + iteration at row M, and see if this would make H(M,M-1) + negligible. (The following uses scaling to avoid + overflows and most underflows.) +*/ + + h21s = h__[m + 1 + m * h_dim1]; + s = (r__1 = h__[m + m * h_dim1] - rt2r, dabs(r__1)) + dabs(rt2i) + + dabs(h21s); + h21s = h__[m + 1 + m * h_dim1] / s; + v[0] = h21s * h__[m + (m + 1) * h_dim1] + (h__[m + m * h_dim1] - + rt1r) * ((h__[m + m * h_dim1] - rt2r) / s) - rt1i * (rt2i + / s); + v[1] = h21s * (h__[m + m * h_dim1] + h__[m + 1 + (m + 1) * h_dim1] + - rt1r - rt2r); + v[2] = h21s * h__[m + 2 + (m + 1) * h_dim1]; + s = dabs(v[0]) + dabs(v[1]) + dabs(v[2]); + v[0] /= s; + v[1] /= s; + v[2] /= s; + if (m == l) { + goto L60; + } + if ((r__1 = h__[m + (m - 1) * h_dim1], dabs(r__1)) * (dabs(v[1]) + + dabs(v[2])) <= ulp * dabs(v[0]) * ((r__2 = h__[m - 1 + ( + m - 1) * h_dim1], dabs(r__2)) + (r__3 = h__[m + m * + h_dim1], dabs(r__3)) + (r__4 = h__[m + 1 + (m + 1) * + h_dim1], dabs(r__4)))) { + goto L60; + } +/* L50: */ + } +L60: + +/* Double-shift QR step */ + + i__1 = i__ - 1; + for (k = m; k <= i__1; ++k) { + +/* + The first iteration of this loop determines a reflection G + from the vector V and applies it from left and right to H, + thus creating a nonzero bulge below the subdiagonal. + + Each subsequent iteration determines a reflection G to + restore the Hessenberg form in the (K-1)th column, and thus + chases the bulge one step toward the bottom of the active + submatrix. NR is the order of G. + + Computing MIN +*/ + i__2 = 3, i__3 = i__ - k + 1; + nr = min(i__2,i__3); + if (k > m) { + scopy_(&nr, &h__[k + (k - 1) * h_dim1], &c__1, v, &c__1); + } + slarfg_(&nr, v, &v[1], &c__1, &t1); + if (k > m) { + h__[k + (k - 1) * h_dim1] = v[0]; + h__[k + 1 + (k - 1) * h_dim1] = 0.f; + if (k < i__ - 1) { + h__[k + 2 + (k - 1) * h_dim1] = 0.f; + } + } else if (m > l) { +/* + ==== Use the following instead of + . H( K, K-1 ) = -H( K, K-1 ) to + . avoid a bug when v(2) and v(3) + . underflow. ==== +*/ + h__[k + (k - 1) * h_dim1] *= 1.f - t1; + } + v2 = v[1]; + t2 = t1 * v2; + if (nr == 3) { + v3 = v[2]; + t3 = t1 * v3; + +/* + Apply G from the left to transform the rows of the matrix + in columns K to I2. +*/ + + i__2 = i2; + for (j = k; j <= i__2; ++j) { + sum = h__[k + j * h_dim1] + v2 * h__[k + 1 + j * h_dim1] + + v3 * h__[k + 2 + j * h_dim1]; + h__[k + j * h_dim1] -= sum * t1; + h__[k + 1 + j * h_dim1] -= sum * t2; + h__[k + 2 + j * h_dim1] -= sum * t3; +/* L70: */ + } + +/* + Apply G from the right to transform the columns of the + matrix in rows I1 to min(K+3,I). + + Computing MIN +*/ + i__3 = k + 3; + i__2 = min(i__3,i__); + for (j = i1; j <= i__2; ++j) { + sum = h__[j + k * h_dim1] + v2 * h__[j + (k + 1) * h_dim1] + + v3 * h__[j + (k + 2) * h_dim1]; + h__[j + k * h_dim1] -= sum * t1; + h__[j + (k + 1) * h_dim1] -= sum * t2; + h__[j + (k + 2) * h_dim1] -= sum * t3; +/* L80: */ + } + + if (*wantz) { + +/* Accumulate transformations in the matrix Z */ + + i__2 = *ihiz; + for (j = *iloz; j <= i__2; ++j) { + sum = z__[j + k * z_dim1] + v2 * z__[j + (k + 1) * + z_dim1] + v3 * z__[j + (k + 2) * z_dim1]; + z__[j + k * z_dim1] -= sum * t1; + z__[j + (k + 1) * z_dim1] -= sum * t2; + z__[j + (k + 2) * z_dim1] -= sum * t3; +/* L90: */ + } + } + } else if (nr == 2) { + +/* + Apply G from the left to transform the rows of the matrix + in columns K to I2. +*/ + + i__2 = i2; + for (j = k; j <= i__2; ++j) { + sum = h__[k + j * h_dim1] + v2 * h__[k + 1 + j * h_dim1]; + h__[k + j * h_dim1] -= sum * t1; + h__[k + 1 + j * h_dim1] -= sum * t2; +/* L100: */ + } + +/* + Apply G from the right to transform the columns of the + matrix in rows I1 to min(K+3,I). +*/ + + i__2 = i__; + for (j = i1; j <= i__2; ++j) { + sum = h__[j + k * h_dim1] + v2 * h__[j + (k + 1) * h_dim1] + ; + h__[j + k * h_dim1] -= sum * t1; + h__[j + (k + 1) * h_dim1] -= sum * t2; +/* L110: */ + } + + if (*wantz) { + +/* Accumulate transformations in the matrix Z */ + + i__2 = *ihiz; + for (j = *iloz; j <= i__2; ++j) { + sum = z__[j + k * z_dim1] + v2 * z__[j + (k + 1) * + z_dim1]; + z__[j + k * z_dim1] -= sum * t1; + z__[j + (k + 1) * z_dim1] -= sum * t2; +/* L120: */ + } + } + } +/* L130: */ + } + +/* L140: */ + } + +/* Failure to converge in remaining number of iterations */ + + *info = i__; + return 0; + +L150: + + if (l == i__) { + +/* H(I,I-1) is negligible: one eigenvalue has converged. */ + + wr[i__] = h__[i__ + i__ * h_dim1]; + wi[i__] = 0.f; + } else if (l == i__ - 1) { + +/* + H(I-1,I-2) is negligible: a pair of eigenvalues have converged. + + Transform the 2-by-2 submatrix to standard Schur form, + and compute and store the eigenvalues. +*/ + + slanv2_(&h__[i__ - 1 + (i__ - 1) * h_dim1], &h__[i__ - 1 + i__ * + h_dim1], &h__[i__ + (i__ - 1) * h_dim1], &h__[i__ + i__ * + h_dim1], &wr[i__ - 1], &wi[i__ - 1], &wr[i__], &wi[i__], &cs, + &sn); + + if (*wantt) { + +/* Apply the transformation to the rest of H. */ + + if (i2 > i__) { + i__1 = i2 - i__; + srot_(&i__1, &h__[i__ - 1 + (i__ + 1) * h_dim1], ldh, &h__[ + i__ + (i__ + 1) * h_dim1], ldh, &cs, &sn); + } + i__1 = i__ - i1 - 1; + srot_(&i__1, &h__[i1 + (i__ - 1) * h_dim1], &c__1, &h__[i1 + i__ * + h_dim1], &c__1, &cs, &sn); + } + if (*wantz) { + +/* Apply the transformation to Z. */ + + srot_(&nz, &z__[*iloz + (i__ - 1) * z_dim1], &c__1, &z__[*iloz + + i__ * z_dim1], &c__1, &cs, &sn); + } + } + +/* return to start of the main loop with new value of I. */ + + i__ = l - 1; + goto L20; + +L160: + return 0; + +/* End of SLAHQR */ + +} /* slahqr_ */ + +/* Subroutine */ int slahr2_(integer *n, integer *k, integer *nb, real *a, + integer *lda, real *tau, real *t, integer *ldt, real *y, integer *ldy) +{ + /* System generated locals */ + integer a_dim1, a_offset, t_dim1, t_offset, y_dim1, y_offset, i__1, i__2, + i__3; + real r__1; + + /* Local variables */ + static integer i__; + static real ei; + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + sgemm_(char *, char *, integer *, integer *, integer *, real *, + real *, integer *, real *, integer *, real *, real *, integer *), sgemv_(char *, integer *, integer *, real *, + real *, integer *, real *, integer *, real *, real *, integer *), scopy_(integer *, real *, integer *, real *, integer *), + strmm_(char *, char *, char *, char *, integer *, integer *, real + *, real *, integer *, real *, integer *), saxpy_(integer *, real *, real *, integer *, real *, + integer *), strmv_(char *, char *, char *, integer *, real *, + integer *, real *, integer *), slarfg_( + integer *, real *, real *, integer *, real *), slacpy_(char *, + integer *, integer *, real *, integer *, real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + -- April 2009 -- + + + Purpose + ======= + + SLAHR2 reduces the first NB columns of A real general n-BY-(n-k+1) + matrix A so that elements below the k-th subdiagonal are zero. The + reduction is performed by an orthogonal similarity transformation + Q' * A * Q. The routine returns the matrices V and T which determine + Q as a block reflector I - V*T*V', and also the matrix Y = A * V * T. + + This is an auxiliary routine called by SGEHRD. + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. + + K (input) INTEGER + The offset for the reduction. Elements below the k-th + subdiagonal in the first NB columns are reduced to zero. + K < N. + + NB (input) INTEGER + The number of columns to be reduced. + + A (input/output) REAL array, dimension (LDA,N-K+1) + On entry, the n-by-(n-k+1) general matrix A. + On exit, the elements on and above the k-th subdiagonal in + the first NB columns are overwritten with the corresponding + elements of the reduced matrix; the elements below the k-th + subdiagonal, with the array TAU, represent the matrix Q as a + product of elementary reflectors. The other columns of A are + unchanged. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) REAL array, dimension (NB) + The scalar factors of the elementary reflectors. See Further + Details. + + T (output) REAL array, dimension (LDT,NB) + The upper triangular matrix T. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= NB. + + Y (output) REAL array, dimension (LDY,NB) + The n-by-nb matrix Y. + + LDY (input) INTEGER + The leading dimension of the array Y. LDY >= N. + + Further Details + =============== + + The matrix Q is represented as a product of nb elementary reflectors + + Q = H(1) H(2) . . . H(nb). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i+k-1) = 0, v(i+k) = 1; v(i+k+1:n) is stored on exit in + A(i+k+1:n,i), and tau in TAU(i). + + The elements of the vectors v together form the (n-k+1)-by-nb matrix + V which is needed, with T and Y, to apply the transformation to the + unreduced part of the matrix, using an update of the form: + A := (I - V*T*V') * (A - Y*V'). + + The contents of A on exit are illustrated by the following example + with n = 7, k = 3 and nb = 2: + + ( a a a a a ) + ( a a a a a ) + ( a a a a a ) + ( h h a a a ) + ( v1 h a a a ) + ( v1 v2 a a a ) + ( v1 v2 a a a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + This subroutine is a slight modification of LAPACK-3.0's DLAHRD + incorporating improvements proposed by Quintana-Orti and Van de + Gejin. Note that the entries of A(1:K,2:NB) differ from those + returned by the original LAPACK-3.0's DLAHRD routine. (This + subroutine is not backward compatible with LAPACK-3.0's DLAHRD.) + + References + ========== + + Gregorio Quintana-Orti and Robert van de Geijn, "Improving the + performance of reduction to Hessenberg form," ACM Transactions on + Mathematical Software, 32(2):180-194, June 2006. + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + --tau; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + y_dim1 = *ldy; + y_offset = 1 + y_dim1; + y -= y_offset; + + /* Function Body */ + if (*n <= 1) { + return 0; + } + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__ > 1) { + +/* + Update A(K+1:N,I) + + Update I-th column of A - Y * V' +*/ + + i__2 = *n - *k; + i__3 = i__ - 1; + sgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b151, &y[*k + 1 + y_dim1], + ldy, &a[*k + i__ - 1 + a_dim1], lda, &c_b15, &a[*k + 1 + + i__ * a_dim1], &c__1); + +/* + Apply I - V * T' * V' to this column (call it b) from the + left, using the last column of T as workspace + + Let V = ( V1 ) and b = ( b1 ) (first I-1 rows) + ( V2 ) ( b2 ) + + where V1 is unit lower triangular + + w := V1' * b1 +*/ + + i__2 = i__ - 1; + scopy_(&i__2, &a[*k + 1 + i__ * a_dim1], &c__1, &t[*nb * t_dim1 + + 1], &c__1); + i__2 = i__ - 1; + strmv_("Lower", "Transpose", "UNIT", &i__2, &a[*k + 1 + a_dim1], + lda, &t[*nb * t_dim1 + 1], &c__1); + +/* w := w + V2'*b2 */ + + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[*k + i__ + a_dim1], + lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b15, &t[*nb * + t_dim1 + 1], &c__1); + +/* w := T'*w */ + + i__2 = i__ - 1; + strmv_("Upper", "Transpose", "NON-UNIT", &i__2, &t[t_offset], ldt, + &t[*nb * t_dim1 + 1], &c__1); + +/* b2 := b2 - V2*w */ + + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + sgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b151, &a[*k + i__ + + a_dim1], lda, &t[*nb * t_dim1 + 1], &c__1, &c_b15, &a[*k + + i__ + i__ * a_dim1], &c__1); + +/* b1 := b1 - V1*w */ + + i__2 = i__ - 1; + strmv_("Lower", "NO TRANSPOSE", "UNIT", &i__2, &a[*k + 1 + a_dim1] + , lda, &t[*nb * t_dim1 + 1], &c__1); + i__2 = i__ - 1; + saxpy_(&i__2, &c_b151, &t[*nb * t_dim1 + 1], &c__1, &a[*k + 1 + + i__ * a_dim1], &c__1); + + a[*k + i__ - 1 + (i__ - 1) * a_dim1] = ei; + } + +/* + Generate the elementary reflector H(I) to annihilate + A(K+I+1:N,I) +*/ + + i__2 = *n - *k - i__ + 1; +/* Computing MIN */ + i__3 = *k + i__ + 1; + slarfg_(&i__2, &a[*k + i__ + i__ * a_dim1], &a[min(i__3,*n) + i__ * + a_dim1], &c__1, &tau[i__]); + ei = a[*k + i__ + i__ * a_dim1]; + a[*k + i__ + i__ * a_dim1] = 1.f; + +/* Compute Y(K+1:N,I) */ + + i__2 = *n - *k; + i__3 = *n - *k - i__ + 1; + sgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b15, &a[*k + 1 + (i__ + 1) * + a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b29, &y[* + k + 1 + i__ * y_dim1], &c__1); + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[*k + i__ + a_dim1], lda, + &a[*k + i__ + i__ * a_dim1], &c__1, &c_b29, &t[i__ * t_dim1 + + 1], &c__1); + i__2 = *n - *k; + i__3 = i__ - 1; + sgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b151, &y[*k + 1 + y_dim1], + ldy, &t[i__ * t_dim1 + 1], &c__1, &c_b15, &y[*k + 1 + i__ * + y_dim1], &c__1); + i__2 = *n - *k; + sscal_(&i__2, &tau[i__], &y[*k + 1 + i__ * y_dim1], &c__1); + +/* Compute T(1:I,I) */ + + i__2 = i__ - 1; + r__1 = -tau[i__]; + sscal_(&i__2, &r__1, &t[i__ * t_dim1 + 1], &c__1); + i__2 = i__ - 1; + strmv_("Upper", "No Transpose", "NON-UNIT", &i__2, &t[t_offset], ldt, + &t[i__ * t_dim1 + 1], &c__1) + ; + t[i__ + i__ * t_dim1] = tau[i__]; + +/* L10: */ + } + a[*k + *nb + *nb * a_dim1] = ei; + +/* Compute Y(1:K,1:NB) */ + + slacpy_("ALL", k, nb, &a[(a_dim1 << 1) + 1], lda, &y[y_offset], ldy); + strmm_("RIGHT", "Lower", "NO TRANSPOSE", "UNIT", k, nb, &c_b15, &a[*k + 1 + + a_dim1], lda, &y[y_offset], ldy); + if (*n > *k + *nb) { + i__1 = *n - *k - *nb; + sgemm_("NO TRANSPOSE", "NO TRANSPOSE", k, nb, &i__1, &c_b15, &a[(*nb + + 2) * a_dim1 + 1], lda, &a[*k + 1 + *nb + a_dim1], lda, & + c_b15, &y[y_offset], ldy); + } + strmm_("RIGHT", "Upper", "NO TRANSPOSE", "NON-UNIT", k, nb, &c_b15, &t[ + t_offset], ldt, &y[y_offset], ldy); + + return 0; + +/* End of SLAHR2 */ + +} /* slahr2_ */ + +logical slaisnan_(real *sin1, real *sin2) +{ + /* System generated locals */ + logical ret_val; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + This routine is not for general use. It exists solely to avoid + over-optimization in SISNAN. + + SLAISNAN checks for NaNs by comparing its two arguments for + inequality. NaN is the only floating-point value where NaN != NaN + returns .TRUE. To check for NaNs, pass the same variable as both + arguments. + + A compiler must assume that the two arguments are + not the same variable, and the test will not be optimized away. + Interprocedural or whole-program optimization may delete this + test. The ISNAN functions will be replaced by the correct + Fortran 03 intrinsic once the intrinsic is widely available. + + Arguments + ========= + + SIN1 (input) REAL + + SIN2 (input) REAL + Two numbers to compare for inequality. + + ===================================================================== +*/ + + ret_val = *sin1 != *sin2; + return ret_val; +} /* slaisnan_ */ + +/* Subroutine */ int slaln2_(logical *ltrans, integer *na, integer *nw, real * + smin, real *ca, real *a, integer *lda, real *d1, real *d2, real *b, + integer *ldb, real *wr, real *wi, real *x, integer *ldx, real *scale, + real *xnorm, integer *info) +{ + /* Initialized data */ + + static logical cswap[4] = { FALSE_,FALSE_,TRUE_,TRUE_ }; + static logical rswap[4] = { FALSE_,TRUE_,FALSE_,TRUE_ }; + static integer ipivot[16] /* was [4][4] */ = { 1,2,3,4,2,1,4,3,3,4,1,2, + 4,3,2,1 }; + + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, x_dim1, x_offset; + real r__1, r__2, r__3, r__4, r__5, r__6; + static real equiv_0[4], equiv_1[4]; + + /* Local variables */ + static integer j; +#define ci (equiv_0) +#define cr (equiv_1) + static real bi1, bi2, br1, br2, xi1, xi2, xr1, xr2, ci21, ci22, cr21, + cr22, li21, csi, ui11, lr21, ui12, ui22; +#define civ (equiv_0) + static real csr, ur11, ur12, ur22; +#define crv (equiv_1) + static real bbnd, cmax, ui11r, ui12s, temp, ur11r, ur12s, u22abs; + static integer icmax; + static real bnorm, cnorm, smini; + extern doublereal slamch_(char *); + static real bignum; + extern /* Subroutine */ int sladiv_(real *, real *, real *, real *, real * + , real *); + static real smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLALN2 solves a system of the form (ca A - w D ) X = s B + or (ca A' - w D) X = s B with possible scaling ("s") and + perturbation of A. (A' means A-transpose.) + + A is an NA x NA real matrix, ca is a real scalar, D is an NA x NA + real diagonal matrix, w is a real or complex value, and X and B are + NA x 1 matrices -- real if w is real, complex if w is complex. NA + may be 1 or 2. + + If w is complex, X and B are represented as NA x 2 matrices, + the first column of each being the real part and the second + being the imaginary part. + + "s" is a scaling factor (.LE. 1), computed by SLALN2, which is + so chosen that X can be computed without overflow. X is further + scaled if necessary to assure that norm(ca A - w D)*norm(X) is less + than overflow. + + If both singular values of (ca A - w D) are less than SMIN, + SMIN*identity will be used instead of (ca A - w D). If only one + singular value is less than SMIN, one element of (ca A - w D) will be + perturbed enough to make the smallest singular value roughly SMIN. + If both singular values are at least SMIN, (ca A - w D) will not be + perturbed. In any case, the perturbation will be at most some small + multiple of max( SMIN, ulp*norm(ca A - w D) ). The singular values + are computed by infinity-norm approximations, and thus will only be + correct to a factor of 2 or so. + + Note: all input quantities are assumed to be smaller than overflow + by a reasonable factor. (See BIGNUM.) + + Arguments + ========== + + LTRANS (input) LOGICAL + =.TRUE.: A-transpose will be used. + =.FALSE.: A will be used (not transposed.) + + NA (input) INTEGER + The size of the matrix A. It may (only) be 1 or 2. + + NW (input) INTEGER + 1 if "w" is real, 2 if "w" is complex. It may only be 1 + or 2. + + SMIN (input) REAL + The desired lower bound on the singular values of A. This + should be a safe distance away from underflow or overflow, + say, between (underflow/machine precision) and (machine + precision * overflow ). (See BIGNUM and ULP.) + + CA (input) REAL + The coefficient c, which A is multiplied by. + + A (input) REAL array, dimension (LDA,NA) + The NA x NA matrix A. + + LDA (input) INTEGER + The leading dimension of A. It must be at least NA. + + D1 (input) REAL + The 1,1 element in the diagonal matrix D. + + D2 (input) REAL + The 2,2 element in the diagonal matrix D. Not used if NW=1. + + B (input) REAL array, dimension (LDB,NW) + The NA x NW matrix B (right-hand side). If NW=2 ("w" is + complex), column 1 contains the real part of B and column 2 + contains the imaginary part. + + LDB (input) INTEGER + The leading dimension of B. It must be at least NA. + + WR (input) REAL + The real part of the scalar "w". + + WI (input) REAL + The imaginary part of the scalar "w". Not used if NW=1. + + X (output) REAL array, dimension (LDX,NW) + The NA x NW matrix X (unknowns), as computed by SLALN2. + If NW=2 ("w" is complex), on exit, column 1 will contain + the real part of X and column 2 will contain the imaginary + part. + + LDX (input) INTEGER + The leading dimension of X. It must be at least NA. + + SCALE (output) REAL + The scale factor that B must be multiplied by to insure + that overflow does not occur when computing X. Thus, + (ca A - w D) X will be SCALE*B, not B (ignoring + perturbations of A.) It will be at most 1. + + XNORM (output) REAL + The infinity-norm of X, when X is regarded as an NA x NW + real matrix. + + INFO (output) INTEGER + An error flag. It will be set to zero if no error occurs, + a negative number if an argument is in error, or a positive + number if ca A - w D had to be perturbed. + The possible values are: + = 0: No error occurred, and (ca A - w D) did not have to be + perturbed. + = 1: (ca A - w D) had to be perturbed to make its smallest + (or only) singular value greater than SMIN. + NOTE: In the interests of speed, this routine does not + check the inputs for errors. + + ===================================================================== +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + + /* Function Body */ + +/* Compute BIGNUM */ + + smlnum = 2.f * slamch_("Safe minimum"); + bignum = 1.f / smlnum; + smini = dmax(*smin,smlnum); + +/* Don't check for input errors */ + + *info = 0; + +/* Standard Initializations */ + + *scale = 1.f; + + if (*na == 1) { + +/* 1 x 1 (i.e., scalar) system C X = B */ + + if (*nw == 1) { + +/* + Real 1x1 system. + + C = ca A - w D +*/ + + csr = *ca * a[a_dim1 + 1] - *wr * *d1; + cnorm = dabs(csr); + +/* If | C | < SMINI, use C = SMINI */ + + if (cnorm < smini) { + csr = smini; + cnorm = smini; + *info = 1; + } + +/* Check scaling for X = B / C */ + + bnorm = (r__1 = b[b_dim1 + 1], dabs(r__1)); + if (cnorm < 1.f && bnorm > 1.f) { + if (bnorm > bignum * cnorm) { + *scale = 1.f / bnorm; + } + } + +/* Compute X */ + + x[x_dim1 + 1] = b[b_dim1 + 1] * *scale / csr; + *xnorm = (r__1 = x[x_dim1 + 1], dabs(r__1)); + } else { + +/* + Complex 1x1 system (w is complex) + + C = ca A - w D +*/ + + csr = *ca * a[a_dim1 + 1] - *wr * *d1; + csi = -(*wi) * *d1; + cnorm = dabs(csr) + dabs(csi); + +/* If | C | < SMINI, use C = SMINI */ + + if (cnorm < smini) { + csr = smini; + csi = 0.f; + cnorm = smini; + *info = 1; + } + +/* Check scaling for X = B / C */ + + bnorm = (r__1 = b[b_dim1 + 1], dabs(r__1)) + (r__2 = b[(b_dim1 << + 1) + 1], dabs(r__2)); + if (cnorm < 1.f && bnorm > 1.f) { + if (bnorm > bignum * cnorm) { + *scale = 1.f / bnorm; + } + } + +/* Compute X */ + + r__1 = *scale * b[b_dim1 + 1]; + r__2 = *scale * b[(b_dim1 << 1) + 1]; + sladiv_(&r__1, &r__2, &csr, &csi, &x[x_dim1 + 1], &x[(x_dim1 << 1) + + 1]); + *xnorm = (r__1 = x[x_dim1 + 1], dabs(r__1)) + (r__2 = x[(x_dim1 << + 1) + 1], dabs(r__2)); + } + + } else { + +/* + 2x2 System + + Compute the real part of C = ca A - w D (or ca A' - w D ) +*/ + + cr[0] = *ca * a[a_dim1 + 1] - *wr * *d1; + cr[3] = *ca * a[(a_dim1 << 1) + 2] - *wr * *d2; + if (*ltrans) { + cr[2] = *ca * a[a_dim1 + 2]; + cr[1] = *ca * a[(a_dim1 << 1) + 1]; + } else { + cr[1] = *ca * a[a_dim1 + 2]; + cr[2] = *ca * a[(a_dim1 << 1) + 1]; + } + + if (*nw == 1) { + +/* + Real 2x2 system (w is real) + + Find the largest element in C +*/ + + cmax = 0.f; + icmax = 0; + + for (j = 1; j <= 4; ++j) { + if ((r__1 = crv[j - 1], dabs(r__1)) > cmax) { + cmax = (r__1 = crv[j - 1], dabs(r__1)); + icmax = j; + } +/* L10: */ + } + +/* If norm(C) < SMINI, use SMINI*identity. */ + + if (cmax < smini) { +/* Computing MAX */ + r__3 = (r__1 = b[b_dim1 + 1], dabs(r__1)), r__4 = (r__2 = b[ + b_dim1 + 2], dabs(r__2)); + bnorm = dmax(r__3,r__4); + if (smini < 1.f && bnorm > 1.f) { + if (bnorm > bignum * smini) { + *scale = 1.f / bnorm; + } + } + temp = *scale / smini; + x[x_dim1 + 1] = temp * b[b_dim1 + 1]; + x[x_dim1 + 2] = temp * b[b_dim1 + 2]; + *xnorm = temp * bnorm; + *info = 1; + return 0; + } + +/* Gaussian elimination with complete pivoting. */ + + ur11 = crv[icmax - 1]; + cr21 = crv[ipivot[(icmax << 2) - 3] - 1]; + ur12 = crv[ipivot[(icmax << 2) - 2] - 1]; + cr22 = crv[ipivot[(icmax << 2) - 1] - 1]; + ur11r = 1.f / ur11; + lr21 = ur11r * cr21; + ur22 = cr22 - ur12 * lr21; + +/* If smaller pivot < SMINI, use SMINI */ + + if (dabs(ur22) < smini) { + ur22 = smini; + *info = 1; + } + if (rswap[icmax - 1]) { + br1 = b[b_dim1 + 2]; + br2 = b[b_dim1 + 1]; + } else { + br1 = b[b_dim1 + 1]; + br2 = b[b_dim1 + 2]; + } + br2 -= lr21 * br1; +/* Computing MAX */ + r__2 = (r__1 = br1 * (ur22 * ur11r), dabs(r__1)), r__3 = dabs(br2) + ; + bbnd = dmax(r__2,r__3); + if (bbnd > 1.f && dabs(ur22) < 1.f) { + if (bbnd >= bignum * dabs(ur22)) { + *scale = 1.f / bbnd; + } + } + + xr2 = br2 * *scale / ur22; + xr1 = *scale * br1 * ur11r - xr2 * (ur11r * ur12); + if (cswap[icmax - 1]) { + x[x_dim1 + 1] = xr2; + x[x_dim1 + 2] = xr1; + } else { + x[x_dim1 + 1] = xr1; + x[x_dim1 + 2] = xr2; + } +/* Computing MAX */ + r__1 = dabs(xr1), r__2 = dabs(xr2); + *xnorm = dmax(r__1,r__2); + +/* Further scaling if norm(A) norm(X) > overflow */ + + if (*xnorm > 1.f && cmax > 1.f) { + if (*xnorm > bignum / cmax) { + temp = cmax / bignum; + x[x_dim1 + 1] = temp * x[x_dim1 + 1]; + x[x_dim1 + 2] = temp * x[x_dim1 + 2]; + *xnorm = temp * *xnorm; + *scale = temp * *scale; + } + } + } else { + +/* + Complex 2x2 system (w is complex) + + Find the largest element in C +*/ + + ci[0] = -(*wi) * *d1; + ci[1] = 0.f; + ci[2] = 0.f; + ci[3] = -(*wi) * *d2; + cmax = 0.f; + icmax = 0; + + for (j = 1; j <= 4; ++j) { + if ((r__1 = crv[j - 1], dabs(r__1)) + (r__2 = civ[j - 1], + dabs(r__2)) > cmax) { + cmax = (r__1 = crv[j - 1], dabs(r__1)) + (r__2 = civ[j - + 1], dabs(r__2)); + icmax = j; + } +/* L20: */ + } + +/* If norm(C) < SMINI, use SMINI*identity. */ + + if (cmax < smini) { +/* Computing MAX */ + r__5 = (r__1 = b[b_dim1 + 1], dabs(r__1)) + (r__2 = b[(b_dim1 + << 1) + 1], dabs(r__2)), r__6 = (r__3 = b[b_dim1 + 2], + dabs(r__3)) + (r__4 = b[(b_dim1 << 1) + 2], dabs( + r__4)); + bnorm = dmax(r__5,r__6); + if (smini < 1.f && bnorm > 1.f) { + if (bnorm > bignum * smini) { + *scale = 1.f / bnorm; + } + } + temp = *scale / smini; + x[x_dim1 + 1] = temp * b[b_dim1 + 1]; + x[x_dim1 + 2] = temp * b[b_dim1 + 2]; + x[(x_dim1 << 1) + 1] = temp * b[(b_dim1 << 1) + 1]; + x[(x_dim1 << 1) + 2] = temp * b[(b_dim1 << 1) + 2]; + *xnorm = temp * bnorm; + *info = 1; + return 0; + } + +/* Gaussian elimination with complete pivoting. */ + + ur11 = crv[icmax - 1]; + ui11 = civ[icmax - 1]; + cr21 = crv[ipivot[(icmax << 2) - 3] - 1]; + ci21 = civ[ipivot[(icmax << 2) - 3] - 1]; + ur12 = crv[ipivot[(icmax << 2) - 2] - 1]; + ui12 = civ[ipivot[(icmax << 2) - 2] - 1]; + cr22 = crv[ipivot[(icmax << 2) - 1] - 1]; + ci22 = civ[ipivot[(icmax << 2) - 1] - 1]; + if (icmax == 1 || icmax == 4) { + +/* Code when off-diagonals of pivoted C are real */ + + if (dabs(ur11) > dabs(ui11)) { + temp = ui11 / ur11; +/* Computing 2nd power */ + r__1 = temp; + ur11r = 1.f / (ur11 * (r__1 * r__1 + 1.f)); + ui11r = -temp * ur11r; + } else { + temp = ur11 / ui11; +/* Computing 2nd power */ + r__1 = temp; + ui11r = -1.f / (ui11 * (r__1 * r__1 + 1.f)); + ur11r = -temp * ui11r; + } + lr21 = cr21 * ur11r; + li21 = cr21 * ui11r; + ur12s = ur12 * ur11r; + ui12s = ur12 * ui11r; + ur22 = cr22 - ur12 * lr21; + ui22 = ci22 - ur12 * li21; + } else { + +/* Code when diagonals of pivoted C are real */ + + ur11r = 1.f / ur11; + ui11r = 0.f; + lr21 = cr21 * ur11r; + li21 = ci21 * ur11r; + ur12s = ur12 * ur11r; + ui12s = ui12 * ur11r; + ur22 = cr22 - ur12 * lr21 + ui12 * li21; + ui22 = -ur12 * li21 - ui12 * lr21; + } + u22abs = dabs(ur22) + dabs(ui22); + +/* If smaller pivot < SMINI, use SMINI */ + + if (u22abs < smini) { + ur22 = smini; + ui22 = 0.f; + *info = 1; + } + if (rswap[icmax - 1]) { + br2 = b[b_dim1 + 1]; + br1 = b[b_dim1 + 2]; + bi2 = b[(b_dim1 << 1) + 1]; + bi1 = b[(b_dim1 << 1) + 2]; + } else { + br1 = b[b_dim1 + 1]; + br2 = b[b_dim1 + 2]; + bi1 = b[(b_dim1 << 1) + 1]; + bi2 = b[(b_dim1 << 1) + 2]; + } + br2 = br2 - lr21 * br1 + li21 * bi1; + bi2 = bi2 - li21 * br1 - lr21 * bi1; +/* Computing MAX */ + r__1 = (dabs(br1) + dabs(bi1)) * (u22abs * (dabs(ur11r) + dabs( + ui11r))), r__2 = dabs(br2) + dabs(bi2); + bbnd = dmax(r__1,r__2); + if (bbnd > 1.f && u22abs < 1.f) { + if (bbnd >= bignum * u22abs) { + *scale = 1.f / bbnd; + br1 = *scale * br1; + bi1 = *scale * bi1; + br2 = *scale * br2; + bi2 = *scale * bi2; + } + } + + sladiv_(&br2, &bi2, &ur22, &ui22, &xr2, &xi2); + xr1 = ur11r * br1 - ui11r * bi1 - ur12s * xr2 + ui12s * xi2; + xi1 = ui11r * br1 + ur11r * bi1 - ui12s * xr2 - ur12s * xi2; + if (cswap[icmax - 1]) { + x[x_dim1 + 1] = xr2; + x[x_dim1 + 2] = xr1; + x[(x_dim1 << 1) + 1] = xi2; + x[(x_dim1 << 1) + 2] = xi1; + } else { + x[x_dim1 + 1] = xr1; + x[x_dim1 + 2] = xr2; + x[(x_dim1 << 1) + 1] = xi1; + x[(x_dim1 << 1) + 2] = xi2; + } +/* Computing MAX */ + r__1 = dabs(xr1) + dabs(xi1), r__2 = dabs(xr2) + dabs(xi2); + *xnorm = dmax(r__1,r__2); + +/* Further scaling if norm(A) norm(X) > overflow */ + + if (*xnorm > 1.f && cmax > 1.f) { + if (*xnorm > bignum / cmax) { + temp = cmax / bignum; + x[x_dim1 + 1] = temp * x[x_dim1 + 1]; + x[x_dim1 + 2] = temp * x[x_dim1 + 2]; + x[(x_dim1 << 1) + 1] = temp * x[(x_dim1 << 1) + 1]; + x[(x_dim1 << 1) + 2] = temp * x[(x_dim1 << 1) + 2]; + *xnorm = temp * *xnorm; + *scale = temp * *scale; + } + } + } + } + + return 0; + +/* End of SLALN2 */ + +} /* slaln2_ */ + +#undef crv +#undef civ +#undef cr +#undef ci + + +/* Subroutine */ int slamrg_(integer *n1, integer *n2, real *a, integer * + strd1, integer *strd2, integer *index) +{ + /* System generated locals */ + integer i__1; + + /* Local variables */ + static integer i__, ind1, ind2, n1sv, n2sv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAMRG will create a permutation list which will merge the elements + of A (which is composed of two independently sorted sets) into a + single set which is sorted in ascending order. + + Arguments + ========= + + N1 (input) INTEGER + N2 (input) INTEGER + These arguements contain the respective lengths of the two + sorted lists to be merged. + + A (input) REAL array, dimension (N1+N2) + The first N1 elements of A contain a list of numbers which + are sorted in either ascending or descending order. Likewise + for the final N2 elements. + + STRD1 (input) INTEGER + STRD2 (input) INTEGER + These are the strides to be taken through the array A. + Allowable strides are 1 and -1. They indicate whether a + subset of A is sorted in ascending (STRDx = 1) or descending + (STRDx = -1) order. + + INDEX (output) INTEGER array, dimension (N1+N2) + On exit this array will contain a permutation such that + if B( I ) = A( INDEX( I ) ) for I=1,N1+N2, then B will be + sorted in ascending order. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --index; + --a; + + /* Function Body */ + n1sv = *n1; + n2sv = *n2; + if (*strd1 > 0) { + ind1 = 1; + } else { + ind1 = *n1; + } + if (*strd2 > 0) { + ind2 = *n1 + 1; + } else { + ind2 = *n1 + *n2; + } + i__ = 1; +/* while ( (N1SV > 0) & (N2SV > 0) ) */ +L10: + if (n1sv > 0 && n2sv > 0) { + if (a[ind1] <= a[ind2]) { + index[i__] = ind1; + ++i__; + ind1 += *strd1; + --n1sv; + } else { + index[i__] = ind2; + ++i__; + ind2 += *strd2; + --n2sv; + } + goto L10; + } +/* end while */ + if (n1sv == 0) { + i__1 = n2sv; + for (n1sv = 1; n1sv <= i__1; ++n1sv) { + index[i__] = ind2; + ++i__; + ind2 += *strd2; +/* L20: */ + } + } else { +/* N2SV .EQ. 0 */ + i__1 = n1sv; + for (n2sv = 1; n2sv <= i__1; ++n2sv) { + index[i__] = ind1; + ++i__; + ind1 += *strd1; +/* L30: */ + } + } + + return 0; + +/* End of SLAMRG */ + +} /* slamrg_ */ + +doublereal slange_(char *norm, integer *m, integer *n, real *a, integer *lda, + real *work) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real ret_val, r__1, r__2, r__3; + + /* Local variables */ + static integer i__, j; + static real sum, scale; + extern logical lsame_(char *, char *); + static real value; + extern /* Subroutine */ int slassq_(integer *, real *, integer *, real *, + real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLANGE returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + real matrix A. + + Description + =========== + + SLANGE returns the value + + SLANGE = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in SLANGE as described + above. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. When M = 0, + SLANGE is set to zero. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. When N = 0, + SLANGE is set to zero. + + A (input) REAL array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(M,1). + + WORK (workspace) REAL array, dimension (MAX(1,LWORK)), + where LWORK >= M when NORM = 'I'; otherwise, WORK is not + referenced. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (min(*m,*n) == 0) { + value = 0.f; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + value = 0.f; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + r__2 = value, r__3 = (r__1 = a[i__ + j * a_dim1], dabs(r__1)); + value = dmax(r__2,r__3); +/* L10: */ + } +/* L20: */ + } + } else if (lsame_(norm, "O") || *(unsigned char *) + norm == '1') { + +/* Find norm1(A). */ + + value = 0.f; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = 0.f; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + sum += (r__1 = a[i__ + j * a_dim1], dabs(r__1)); +/* L30: */ + } + value = dmax(value,sum); +/* L40: */ + } + } else if (lsame_(norm, "I")) { + +/* Find normI(A). */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.f; +/* L50: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] += (r__1 = a[i__ + j * a_dim1], dabs(r__1)); +/* L60: */ + } +/* L70: */ + } + value = 0.f; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__1 = value, r__2 = work[i__]; + value = dmax(r__1,r__2); +/* L80: */ + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.f; + sum = 1.f; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + slassq_(m, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L90: */ + } + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of SLANGE */ + +} /* slange_ */ + +doublereal slanst_(char *norm, integer *n, real *d__, real *e) +{ + /* System generated locals */ + integer i__1; + real ret_val, r__1, r__2, r__3, r__4, r__5; + + /* Local variables */ + static integer i__; + static real sum, scale; + extern logical lsame_(char *, char *); + static real anorm; + extern /* Subroutine */ int slassq_(integer *, real *, integer *, real *, + real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLANST returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + real symmetric tridiagonal matrix A. + + Description + =========== + + SLANST returns the value + + SLANST = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in SLANST as described + above. + + N (input) INTEGER + The order of the matrix A. N >= 0. When N = 0, SLANST is + set to zero. + + D (input) REAL array, dimension (N) + The diagonal elements of A. + + E (input) REAL array, dimension (N-1) + The (n-1) sub-diagonal or super-diagonal elements of A. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --e; + --d__; + + /* Function Body */ + if (*n <= 0) { + anorm = 0.f; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + anorm = (r__1 = d__[*n], dabs(r__1)); + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__2 = anorm, r__3 = (r__1 = d__[i__], dabs(r__1)); + anorm = dmax(r__2,r__3); +/* Computing MAX */ + r__2 = anorm, r__3 = (r__1 = e[i__], dabs(r__1)); + anorm = dmax(r__2,r__3); +/* L10: */ + } + } else if (lsame_(norm, "O") || *(unsigned char *) + norm == '1' || lsame_(norm, "I")) { + +/* Find norm1(A). */ + + if (*n == 1) { + anorm = dabs(d__[1]); + } else { +/* Computing MAX */ + r__3 = dabs(d__[1]) + dabs(e[1]), r__4 = (r__1 = e[*n - 1], dabs( + r__1)) + (r__2 = d__[*n], dabs(r__2)); + anorm = dmax(r__3,r__4); + i__1 = *n - 1; + for (i__ = 2; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__4 = anorm, r__5 = (r__1 = d__[i__], dabs(r__1)) + (r__2 = + e[i__], dabs(r__2)) + (r__3 = e[i__ - 1], dabs(r__3)); + anorm = dmax(r__4,r__5); +/* L20: */ + } + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.f; + sum = 1.f; + if (*n > 1) { + i__1 = *n - 1; + slassq_(&i__1, &e[1], &c__1, &scale, &sum); + sum *= 2; + } + slassq_(n, &d__[1], &c__1, &scale, &sum); + anorm = scale * sqrt(sum); + } + + ret_val = anorm; + return ret_val; + +/* End of SLANST */ + +} /* slanst_ */ + +doublereal slansy_(char *norm, char *uplo, integer *n, real *a, integer *lda, + real *work) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real ret_val, r__1, r__2, r__3; + + /* Local variables */ + static integer i__, j; + static real sum, absa, scale; + extern logical lsame_(char *, char *); + static real value; + extern /* Subroutine */ int slassq_(integer *, real *, integer *, real *, + real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLANSY returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + real symmetric matrix A. + + Description + =========== + + SLANSY returns the value + + SLANSY = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in SLANSY as described + above. + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is to be referenced. + = 'U': Upper triangular part of A is referenced + = 'L': Lower triangular part of A is referenced + + N (input) INTEGER + The order of the matrix A. N >= 0. When N = 0, SLANSY is + set to zero. + + A (input) REAL array, dimension (LDA,N) + The symmetric matrix A. If UPLO = 'U', the leading n by n + upper triangular part of A contains the upper triangular part + of the matrix A, and the strictly lower triangular part of A + is not referenced. If UPLO = 'L', the leading n by n lower + triangular part of A contains the lower triangular part of + the matrix A, and the strictly upper triangular part of A is + not referenced. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(N,1). + + WORK (workspace) REAL array, dimension (MAX(1,LWORK)), + where LWORK >= N when NORM = 'I' or '1' or 'O'; otherwise, + WORK is not referenced. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (*n == 0) { + value = 0.f; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + value = 0.f; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + r__2 = value, r__3 = (r__1 = a[i__ + j * a_dim1], dabs( + r__1)); + value = dmax(r__2,r__3); +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { +/* Computing MAX */ + r__2 = value, r__3 = (r__1 = a[i__ + j * a_dim1], dabs( + r__1)); + value = dmax(r__2,r__3); +/* L30: */ + } +/* L40: */ + } + } + } else if (lsame_(norm, "I") || lsame_(norm, "O") || *(unsigned char *)norm == '1') { + +/* Find normI(A) ( = norm1(A), since A is symmetric). */ + + value = 0.f; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = 0.f; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + absa = (r__1 = a[i__ + j * a_dim1], dabs(r__1)); + sum += absa; + work[i__] += absa; +/* L50: */ + } + work[j] = sum + (r__1 = a[j + j * a_dim1], dabs(r__1)); +/* L60: */ + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__1 = value, r__2 = work[i__]; + value = dmax(r__1,r__2); +/* L70: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.f; +/* L80: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = work[j] + (r__1 = a[j + j * a_dim1], dabs(r__1)); + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + absa = (r__1 = a[i__ + j * a_dim1], dabs(r__1)); + sum += absa; + work[i__] += absa; +/* L90: */ + } + value = dmax(value,sum); +/* L100: */ + } + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.f; + sum = 1.f; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + i__2 = j - 1; + slassq_(&i__2, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L110: */ + } + } else { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = *n - j; + slassq_(&i__2, &a[j + 1 + j * a_dim1], &c__1, &scale, &sum); +/* L120: */ + } + } + sum *= 2; + i__1 = *lda + 1; + slassq_(n, &a[a_offset], &i__1, &scale, &sum); + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of SLANSY */ + +} /* slansy_ */ + +/* Subroutine */ int slanv2_(real *a, real *b, real *c__, real *d__, real * + rt1r, real *rt1i, real *rt2r, real *rt2i, real *cs, real *sn) +{ + /* System generated locals */ + real r__1, r__2; + + /* Local variables */ + static real p, z__, aa, bb, cc, dd, cs1, sn1, sab, sac, eps, tau, temp, + scale, bcmax, bcmis, sigma; + extern doublereal slapy2_(real *, real *), slamch_(char *); + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SLANV2 computes the Schur factorization of a real 2-by-2 nonsymmetric + matrix in standard form: + + [ A B ] = [ CS -SN ] [ AA BB ] [ CS SN ] + [ C D ] [ SN CS ] [ CC DD ] [-SN CS ] + + where either + 1) CC = 0 so that AA and DD are real eigenvalues of the matrix, or + 2) AA = DD and BB*CC < 0, so that AA + or - sqrt(BB*CC) are complex + conjugate eigenvalues. + + Arguments + ========= + + A (input/output) REAL + B (input/output) REAL + C (input/output) REAL + D (input/output) REAL + On entry, the elements of the input matrix. + On exit, they are overwritten by the elements of the + standardised Schur form. + + RT1R (output) REAL + RT1I (output) REAL + RT2R (output) REAL + RT2I (output) REAL + The real and imaginary parts of the eigenvalues. If the + eigenvalues are a complex conjugate pair, RT1I > 0. + + CS (output) REAL + SN (output) REAL + Parameters of the rotation matrix. + + Further Details + =============== + + Modified by V. Sima, Research Institute for Informatics, Bucharest, + Romania, to reduce the risk of cancellation errors, + when computing real eigenvalues, and to ensure, if possible, that + abs(RT1R) >= abs(RT2R). + + ===================================================================== +*/ + + + eps = slamch_("P"); + if (*c__ == 0.f) { + *cs = 1.f; + *sn = 0.f; + goto L10; + + } else if (*b == 0.f) { + +/* Swap rows and columns */ + + *cs = 0.f; + *sn = 1.f; + temp = *d__; + *d__ = *a; + *a = temp; + *b = -(*c__); + *c__ = 0.f; + goto L10; + } else if (*a - *d__ == 0.f && r_sign(&c_b15, b) != r_sign(&c_b15, c__)) { + *cs = 1.f; + *sn = 0.f; + goto L10; + } else { + + temp = *a - *d__; + p = temp * .5f; +/* Computing MAX */ + r__1 = dabs(*b), r__2 = dabs(*c__); + bcmax = dmax(r__1,r__2); +/* Computing MIN */ + r__1 = dabs(*b), r__2 = dabs(*c__); + bcmis = dmin(r__1,r__2) * r_sign(&c_b15, b) * r_sign(&c_b15, c__); +/* Computing MAX */ + r__1 = dabs(p); + scale = dmax(r__1,bcmax); + z__ = p / scale * p + bcmax / scale * bcmis; + +/* + If Z is of the order of the machine accuracy, postpone the + decision on the nature of eigenvalues +*/ + + if (z__ >= eps * 4.f) { + +/* Real eigenvalues. Compute A and D. */ + + r__1 = sqrt(scale) * sqrt(z__); + z__ = p + r_sign(&r__1, &p); + *a = *d__ + z__; + *d__ -= bcmax / z__ * bcmis; + +/* Compute B and the rotation matrix */ + + tau = slapy2_(c__, &z__); + *cs = z__ / tau; + *sn = *c__ / tau; + *b -= *c__; + *c__ = 0.f; + } else { + +/* + Complex eigenvalues, or real (almost) equal eigenvalues. + Make diagonal elements equal. +*/ + + sigma = *b + *c__; + tau = slapy2_(&sigma, &temp); + *cs = sqrt((dabs(sigma) / tau + 1.f) * .5f); + *sn = -(p / (tau * *cs)) * r_sign(&c_b15, &sigma); + +/* + Compute [ AA BB ] = [ A B ] [ CS -SN ] + [ CC DD ] [ C D ] [ SN CS ] +*/ + + aa = *a * *cs + *b * *sn; + bb = -(*a) * *sn + *b * *cs; + cc = *c__ * *cs + *d__ * *sn; + dd = -(*c__) * *sn + *d__ * *cs; + +/* + Compute [ A B ] = [ CS SN ] [ AA BB ] + [ C D ] [-SN CS ] [ CC DD ] +*/ + + *a = aa * *cs + cc * *sn; + *b = bb * *cs + dd * *sn; + *c__ = -aa * *sn + cc * *cs; + *d__ = -bb * *sn + dd * *cs; + + temp = (*a + *d__) * .5f; + *a = temp; + *d__ = temp; + + if (*c__ != 0.f) { + if (*b != 0.f) { + if (r_sign(&c_b15, b) == r_sign(&c_b15, c__)) { + +/* Real eigenvalues: reduce to upper triangular form */ + + sab = sqrt((dabs(*b))); + sac = sqrt((dabs(*c__))); + r__1 = sab * sac; + p = r_sign(&r__1, c__); + tau = 1.f / sqrt((r__1 = *b + *c__, dabs(r__1))); + *a = temp + p; + *d__ = temp - p; + *b -= *c__; + *c__ = 0.f; + cs1 = sab * tau; + sn1 = sac * tau; + temp = *cs * cs1 - *sn * sn1; + *sn = *cs * sn1 + *sn * cs1; + *cs = temp; + } + } else { + *b = -(*c__); + *c__ = 0.f; + temp = *cs; + *cs = -(*sn); + *sn = temp; + } + } + } + + } + +L10: + +/* Store eigenvalues in (RT1R,RT1I) and (RT2R,RT2I). */ + + *rt1r = *a; + *rt2r = *d__; + if (*c__ == 0.f) { + *rt1i = 0.f; + *rt2i = 0.f; + } else { + *rt1i = sqrt((dabs(*b))) * sqrt((dabs(*c__))); + *rt2i = -(*rt1i); + } + return 0; + +/* End of SLANV2 */ + +} /* slanv2_ */ + +doublereal slapy2_(real *x, real *y) +{ + /* System generated locals */ + real ret_val, r__1; + + /* Local variables */ + static real w, z__, xabs, yabs; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAPY2 returns sqrt(x**2+y**2), taking care not to cause unnecessary + overflow. + + Arguments + ========= + + X (input) REAL + Y (input) REAL + X and Y specify the values x and y. + + ===================================================================== +*/ + + + xabs = dabs(*x); + yabs = dabs(*y); + w = dmax(xabs,yabs); + z__ = dmin(xabs,yabs); + if (z__ == 0.f) { + ret_val = w; + } else { +/* Computing 2nd power */ + r__1 = z__ / w; + ret_val = w * sqrt(r__1 * r__1 + 1.f); + } + return ret_val; + +/* End of SLAPY2 */ + +} /* slapy2_ */ + +doublereal slapy3_(real *x, real *y, real *z__) +{ + /* System generated locals */ + real ret_val, r__1, r__2, r__3; + + /* Local variables */ + static real w, xabs, yabs, zabs; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAPY3 returns sqrt(x**2+y**2+z**2), taking care not to cause + unnecessary overflow. + + Arguments + ========= + + X (input) REAL + Y (input) REAL + Z (input) REAL + X, Y and Z specify the values x, y and z. + + ===================================================================== +*/ + + + xabs = dabs(*x); + yabs = dabs(*y); + zabs = dabs(*z__); +/* Computing MAX */ + r__1 = max(xabs,yabs); + w = dmax(r__1,zabs); + if (w == 0.f) { +/* + W can be zero for max(0,nan,0) + adding all three entries together will make sure + NaN will not disappear. +*/ + ret_val = xabs + yabs + zabs; + } else { +/* Computing 2nd power */ + r__1 = xabs / w; +/* Computing 2nd power */ + r__2 = yabs / w; +/* Computing 2nd power */ + r__3 = zabs / w; + ret_val = w * sqrt(r__1 * r__1 + r__2 * r__2 + r__3 * r__3); + } + return ret_val; + +/* End of SLAPY3 */ + +} /* slapy3_ */ + +/* Subroutine */ int slaqr0_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, real *h__, integer *ldh, real *wr, real * + wi, integer *iloz, integer *ihiz, real *z__, integer *ldz, real *work, + integer *lwork, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5; + real r__1, r__2, r__3, r__4; + + /* Local variables */ + static integer i__, k; + static real aa, bb, cc, dd; + static integer ld; + static real cs; + static integer nh, it, ks, kt; + static real sn; + static integer ku, kv, ls, ns; + static real ss; + static integer nw, inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, + kbot, nmin; + static real swap; + static integer ktop; + static real zdum[1] /* was [1][1] */; + static integer kacc22, itmax, nsmax, nwmax, kwtop; + extern /* Subroutine */ int slanv2_(real *, real *, real *, real *, real * + , real *, real *, real *, real *, real *), slaqr3_(logical *, + logical *, integer *, integer *, integer *, integer *, real *, + integer *, integer *, integer *, real *, integer *, integer *, + integer *, real *, real *, real *, integer *, integer *, real *, + integer *, integer *, real *, integer *, real *, integer *), + slaqr4_(logical *, logical *, integer *, integer *, integer *, + real *, integer *, real *, real *, integer *, integer *, real *, + integer *, real *, integer *, integer *), slaqr5_(logical *, + logical *, integer *, integer *, integer *, integer *, integer *, + real *, real *, real *, integer *, integer *, integer *, real *, + integer *, real *, integer *, real *, integer *, integer *, real * + , integer *, integer *, real *, integer *); + static integer nibble; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static char jbcmpz[2]; + extern /* Subroutine */ int slahqr_(logical *, logical *, integer *, + integer *, integer *, real *, integer *, real *, real *, integer * + , integer *, real *, integer *, integer *), slacpy_(char *, + integer *, integer *, real *, integer *, real *, integer *); + static integer nwupbd; + static logical sorted; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Purpose + ======= + + SLAQR0 computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**T, where T is an upper quasi-triangular matrix (the + Schur form), and Z is the orthogonal matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input orthogonal + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the orthogonal matrix Q: A = Q*H*Q**T = (QZ)*T*(QZ)**T. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1, + H(ILO,ILO-1) is zero. ILO and IHI are normally set by a + previous call to SGEBAL, and then passed to SGEHRD when the + matrix output by SGEBAL is reduced to Hessenberg form. + Otherwise, ILO and IHI should be set to 1 and N, + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) REAL array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and WANTT is .TRUE., then H contains + the upper quasi-triangular matrix T from the Schur + decomposition (the Schur form); 2-by-2 diagonal blocks + (corresponding to complex conjugate pairs of eigenvalues) + are returned in standard form, with H(i,i) = H(i+1,i+1) + and H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and WANTT is + .FALSE., then the contents of H are unspecified on exit. + (The output value of H when INFO.GT.0 is given under the + description of INFO below.) + + This subroutine may explicitly set H(i,j) = 0 for i.GT.j and + j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + WR (output) REAL array, dimension (IHI) + WI (output) REAL array, dimension (IHI) + The real and imaginary parts, respectively, of the computed + eigenvalues of H(ILO:IHI,ILO:IHI) are stored in WR(ILO:IHI) + and WI(ILO:IHI). If two eigenvalues are computed as a + complex conjugate pair, they are stored in consecutive + elements of WR and WI, say the i-th and (i+1)th, with + WI(i) .GT. 0 and WI(i+1) .LT. 0. If WANTT is .TRUE., then + the eigenvalues are stored in the same order as on the + diagonal of the Schur form returned in H, with + WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 diagonal + block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and + WI(i+1) = -WI(i). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. + 1 .LE. ILOZ .LE. ILO; IHI .LE. IHIZ .LE. N. + + Z (input/output) REAL array, dimension (LDZ,IHI) + If WANTZ is .FALSE., then Z is not referenced. + If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is + replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the + orthogonal Schur factor of H(ILO:IHI,ILO:IHI). + (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if WANTZ is .TRUE. + then LDZ.GE.MAX(1,IHIZ). Otherwize, LDZ.GE.1. + + WORK (workspace/output) REAL array, dimension LWORK + On exit, if LWORK = -1, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient, but LWORK typically as large as 6*N may + be required for optimal performance. A workspace query + to determine the optimal workspace size is recommended. + + If LWORK = -1, then SLAQR0 does a workspace query. + In this case, SLAQR0 checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, SLAQR0 failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and WANT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is an orthogonal matrix. The final + value of H is upper Hessenberg and quasi-triangular + in rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + + (final value of Z(ILO:IHI,ILOZ:IHIZ) + = (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U + + where U is the orthogonal matrix in (*) (regard- + less of the value of WANTT.) + + If INFO .GT. 0 and WANTZ is .FALSE., then Z is not + accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . SLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== Exceptional deflation windows: try to cure rare + . slow convergence by varying the size of the + . deflation window after KEXNW iterations. ==== + + ==== Exceptional shifts: try to cure rare slow convergence + . with ad-hoc exceptional shifts every KEXSH iterations. + . ==== + + ==== The constants WILK1 and WILK2 are used to form the + . exceptional shifts. ==== +*/ + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --wr; + --wi; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + +/* ==== Quick return for N = 0: nothing to do. ==== */ + + if (*n == 0) { + work[1] = 1.f; + return 0; + } + + if (*n <= 11) { + +/* ==== Tiny matrices must use SLAHQR. ==== */ + + lwkopt = 1; + if (*lwork != -1) { + slahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], & + wi[1], iloz, ihiz, &z__[z_offset], ldz, info); + } + } else { + +/* + ==== Use small bulge multi-shift QR with aggressive early + . deflation on larger-than-tiny matrices. ==== + + ==== Hope for the best. ==== +*/ + + *info = 0; + +/* ==== Set up job flags for ILAENV. ==== */ + + if (*wantt) { + *(unsigned char *)jbcmpz = 'S'; + } else { + *(unsigned char *)jbcmpz = 'E'; + } + if (*wantz) { + *(unsigned char *)&jbcmpz[1] = 'V'; + } else { + *(unsigned char *)&jbcmpz[1] = 'N'; + } + +/* + ==== NWR = recommended deflation window size. At this + . point, N .GT. NTINY = 11, so there is enough + . subdiagonal workspace for NWR.GE.2 as required. + . (In fact, there is enough subdiagonal space for + . NWR.GE.3.) ==== +*/ + + nwr = ilaenv_(&c__13, "SLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nwr = max(2,nwr); +/* Computing MIN */ + i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2); + nwr = min(i__1,nwr); + +/* + ==== NSR = recommended number of simultaneous shifts. + . At this point N .GT. NTINY = 11, so there is at + . enough subdiagonal workspace for NSR to be even + . and greater than or equal to two as required. ==== +*/ + + nsr = ilaenv_(&c__15, "SLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); +/* Computing MIN */ + i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - + *ilo; + nsr = min(i__1,i__2); +/* Computing MAX */ + i__1 = 2, i__2 = nsr - nsr % 2; + nsr = max(i__1,i__2); + +/* + ==== Estimate optimal workspace ==== + + ==== Workspace query call to SLAQR3 ==== +*/ + + i__1 = nwr + 1; + slaqr3_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, + ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], &h__[ + h_offset], ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], + ldh, &work[1], &c_n1); + +/* + ==== Optimal workspace = MAX(SLAQR5, SLAQR3) ==== + + Computing MAX +*/ + i__1 = nsr * 3 / 2, i__2 = (integer) work[1]; + lwkopt = max(i__1,i__2); + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + work[1] = (real) lwkopt; + return 0; + } + +/* ==== SLAHQR/SLAQR0 crossover point ==== */ + + nmin = ilaenv_(&c__12, "SLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen) + 6, (ftnlen)2); + nmin = max(11,nmin); + +/* ==== Nibble crossover point ==== */ + + nibble = ilaenv_(&c__14, "SLAQR0", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + nibble = max(0,nibble); + +/* + ==== Accumulate reflections during ttswp? Use block + . 2-by-2 structure during matrix-matrix multiply? ==== +*/ + + kacc22 = ilaenv_(&c__16, "SLAQR0", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + kacc22 = max(0,kacc22); + kacc22 = min(2,kacc22); + +/* + ==== NWMAX = the largest possible deflation window for + . which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n - 1) / 3, i__2 = *lwork / 2; + nwmax = min(i__1,i__2); + nw = nwmax; + +/* + ==== NSMAX = the Largest number of simultaneous shifts + . for which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3; + nsmax = min(i__1,i__2); + nsmax -= nsmax % 2; + +/* ==== NDFL: an iteration count restarted at deflation. ==== */ + + ndfl = 1; + +/* + ==== ITMAX = iteration limit ==== + + Computing MAX +*/ + i__1 = 10, i__2 = *ihi - *ilo + 1; + itmax = max(i__1,i__2) * 30; + +/* ==== Last row and column in the active block ==== */ + + kbot = *ihi; + +/* ==== Main Loop ==== */ + + i__1 = itmax; + for (it = 1; it <= i__1; ++it) { + +/* ==== Done when KBOT falls below ILO ==== */ + + if (kbot < *ilo) { + goto L90; + } + +/* ==== Locate active block ==== */ + + i__2 = *ilo + 1; + for (k = kbot; k >= i__2; --k) { + if (h__[k + (k - 1) * h_dim1] == 0.f) { + goto L20; + } +/* L10: */ + } + k = *ilo; +L20: + ktop = k; + +/* + ==== Select deflation window size: + . Typical Case: + . If possible and advisable, nibble the entire + . active block. If not, use size MIN(NWR,NWMAX) + . or MIN(NWR+1,NWMAX) depending upon which has + . the smaller corresponding subdiagonal entry + . (a heuristic). + . + . Exceptional Case: + . If there have been no deflations in KEXNW or + . more iterations, then vary the deflation window + . size. At first, because, larger windows are, + . in general, more powerful than smaller ones, + . rapidly increase the window to the maximum possible. + . Then, gradually reduce the window size. ==== +*/ + + nh = kbot - ktop + 1; + nwupbd = min(nh,nwmax); + if (ndfl < 5) { + nw = min(nwupbd,nwr); + } else { +/* Computing MIN */ + i__2 = nwupbd, i__3 = nw << 1; + nw = min(i__2,i__3); + } + if (nw < nwmax) { + if (nw >= nh - 1) { + nw = nh; + } else { + kwtop = kbot - nw + 1; + if ((r__1 = h__[kwtop + (kwtop - 1) * h_dim1], dabs(r__1)) + > (r__2 = h__[kwtop - 1 + (kwtop - 2) * h_dim1], + dabs(r__2))) { + ++nw; + } + } + } + if (ndfl < 5) { + ndec = -1; + } else if (ndec >= 0 || nw >= nwupbd) { + ++ndec; + if (nw - ndec < 2) { + ndec = 0; + } + nw -= ndec; + } + +/* + ==== Aggressive early deflation: + . split workspace under the subdiagonal into + . - an nw-by-nw work array V in the lower + . left-hand-corner, + . - an NW-by-at-least-NW-but-more-is-better + . (NW-by-NHO) horizontal work array along + . the bottom edge, + . - an at-least-NW-but-more-is-better (NHV-by-NW) + . vertical work array along the left-hand-edge. + . ==== +*/ + + kv = *n - nw + 1; + kt = nw + 1; + nho = *n - nw - 1 - kt + 1; + kwv = nw + 2; + nve = *n - nw - kwv + 1; + +/* ==== Aggressive early deflation ==== */ + + slaqr3_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, + iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], + &h__[kv + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], + ldh, &nve, &h__[kwv + h_dim1], ldh, &work[1], lwork); + +/* ==== Adjust KBOT accounting for new deflations. ==== */ + + kbot -= ld; + +/* ==== KS points to the shifts. ==== */ + + ks = kbot - ls + 1; + +/* + ==== Skip an expensive QR sweep if there is a (partly + . heuristic) reason to expect that many eigenvalues + . will deflate without it. Here, the QR sweep is + . skipped if many eigenvalues have just been deflated + . or if the remaining active block is small. +*/ + + if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min( + nmin,nwmax)) { + +/* + ==== NS = nominal number of simultaneous shifts. + . This may be lowered (slightly) if SLAQR3 + . did not provide that many shifts. ==== + + Computing MIN + Computing MAX +*/ + i__4 = 2, i__5 = kbot - ktop; + i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5); + ns = min(i__2,i__3); + ns -= ns % 2; + +/* + ==== If there have been no deflations + . in a multiple of KEXSH iterations, + . then try exceptional shifts. + . Otherwise use shifts provided by + . SLAQR3 above or from the eigenvalues + . of a trailing principal submatrix. ==== +*/ + + if (ndfl % 6 == 0) { + ks = kbot - ns + 1; +/* Computing MAX */ + i__3 = ks + 1, i__4 = ktop + 2; + i__2 = max(i__3,i__4); + for (i__ = kbot; i__ >= i__2; i__ += -2) { + ss = (r__1 = h__[i__ + (i__ - 1) * h_dim1], dabs(r__1) + ) + (r__2 = h__[i__ - 1 + (i__ - 2) * h_dim1], + dabs(r__2)); + aa = ss * .75f + h__[i__ + i__ * h_dim1]; + bb = ss; + cc = ss * -.4375f; + dd = aa; + slanv2_(&aa, &bb, &cc, &dd, &wr[i__ - 1], &wi[i__ - 1] + , &wr[i__], &wi[i__], &cs, &sn); +/* L30: */ + } + if (ks == ktop) { + wr[ks + 1] = h__[ks + 1 + (ks + 1) * h_dim1]; + wi[ks + 1] = 0.f; + wr[ks] = wr[ks + 1]; + wi[ks] = wi[ks + 1]; + } + } else { + +/* + ==== Got NS/2 or fewer shifts? Use SLAQR4 or + . SLAHQR on a trailing principal submatrix to + . get more. (Since NS.LE.NSMAX.LE.(N+6)/9, + . there is enough space below the subdiagonal + . to fit an NS-by-NS scratch array.) ==== +*/ + + if (kbot - ks + 1 <= ns / 2) { + ks = kbot - ns + 1; + kt = *n - ns + 1; + slacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, & + h__[kt + h_dim1], ldh); + if (ns > nmin) { + slaqr4_(&c_false, &c_false, &ns, &c__1, &ns, &h__[ + kt + h_dim1], ldh, &wr[ks], &wi[ks], & + c__1, &c__1, zdum, &c__1, &work[1], lwork, + &inf); + } else { + slahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[ + kt + h_dim1], ldh, &wr[ks], &wi[ks], & + c__1, &c__1, zdum, &c__1, &inf); + } + ks += inf; + +/* + ==== In case of a rare QR failure use + . eigenvalues of the trailing 2-by-2 + . principal submatrix. ==== +*/ + + if (ks >= kbot) { + aa = h__[kbot - 1 + (kbot - 1) * h_dim1]; + cc = h__[kbot + (kbot - 1) * h_dim1]; + bb = h__[kbot - 1 + kbot * h_dim1]; + dd = h__[kbot + kbot * h_dim1]; + slanv2_(&aa, &bb, &cc, &dd, &wr[kbot - 1], &wi[ + kbot - 1], &wr[kbot], &wi[kbot], &cs, &sn) + ; + ks = kbot - 1; + } + } + + if (kbot - ks + 1 > ns) { + +/* + ==== Sort the shifts (Helps a little) + . Bubble sort keeps complex conjugate + . pairs together. ==== +*/ + + sorted = FALSE_; + i__2 = ks + 1; + for (k = kbot; k >= i__2; --k) { + if (sorted) { + goto L60; + } + sorted = TRUE_; + i__3 = k - 1; + for (i__ = ks; i__ <= i__3; ++i__) { + if ((r__1 = wr[i__], dabs(r__1)) + (r__2 = wi[ + i__], dabs(r__2)) < (r__3 = wr[i__ + + 1], dabs(r__3)) + (r__4 = wi[i__ + 1], + dabs(r__4))) { + sorted = FALSE_; + + swap = wr[i__]; + wr[i__] = wr[i__ + 1]; + wr[i__ + 1] = swap; + + swap = wi[i__]; + wi[i__] = wi[i__ + 1]; + wi[i__ + 1] = swap; + } +/* L40: */ + } +/* L50: */ + } +L60: + ; + } + +/* + ==== Shuffle shifts into pairs of real shifts + . and pairs of complex conjugate shifts + . assuming complex conjugate shifts are + . already adjacent to one another. (Yes, + . they are.) ==== +*/ + + i__2 = ks + 2; + for (i__ = kbot; i__ >= i__2; i__ += -2) { + if (wi[i__] != -wi[i__ - 1]) { + + swap = wr[i__]; + wr[i__] = wr[i__ - 1]; + wr[i__ - 1] = wr[i__ - 2]; + wr[i__ - 2] = swap; + + swap = wi[i__]; + wi[i__] = wi[i__ - 1]; + wi[i__ - 1] = wi[i__ - 2]; + wi[i__ - 2] = swap; + } +/* L70: */ + } + } + +/* + ==== If there are only two shifts and both are + . real, then use only one. ==== +*/ + + if (kbot - ks + 1 == 2) { + if (wi[kbot] == 0.f) { + if ((r__1 = wr[kbot] - h__[kbot + kbot * h_dim1], + dabs(r__1)) < (r__2 = wr[kbot - 1] - h__[kbot + + kbot * h_dim1], dabs(r__2))) { + wr[kbot - 1] = wr[kbot]; + } else { + wr[kbot] = wr[kbot - 1]; + } + } + } + +/* + ==== Use up to NS of the the smallest magnatiude + . shifts. If there aren't NS shifts available, + . then use them all, possibly dropping one to + . make the number of shifts even. ==== + + Computing MIN +*/ + i__2 = ns, i__3 = kbot - ks + 1; + ns = min(i__2,i__3); + ns -= ns % 2; + ks = kbot - ns + 1; + +/* + ==== Small-bulge multi-shift QR sweep: + . split workspace under the subdiagonal into + . - a KDU-by-KDU work array U in the lower + . left-hand-corner, + . - a KDU-by-at-least-KDU-but-more-is-better + . (KDU-by-NHo) horizontal work array WH along + . the bottom edge, + . - and an at-least-KDU-but-more-is-better-by-KDU + . (NVE-by-KDU) vertical work WV arrow along + . the left-hand-edge. ==== +*/ + + kdu = ns * 3 - 3; + ku = *n - kdu + 1; + kwh = kdu + 1; + nho = *n - kdu - 3 - (kdu + 1) + 1; + kwv = kdu + 4; + nve = *n - kdu - kwv + 1; + +/* ==== Small-bulge multi-shift QR sweep ==== */ + + slaqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &wr[ks], + &wi[ks], &h__[h_offset], ldh, iloz, ihiz, &z__[ + z_offset], ldz, &work[1], &c__3, &h__[ku + h_dim1], + ldh, &nve, &h__[kwv + h_dim1], ldh, &nho, &h__[ku + + kwh * h_dim1], ldh); + } + +/* ==== Note progress (or the lack of it). ==== */ + + if (ld > 0) { + ndfl = 1; + } else { + ++ndfl; + } + +/* + ==== End of main loop ==== + L80: +*/ + } + +/* + ==== Iteration limit exceeded. Set INFO to show where + . the problem occurred and exit. ==== +*/ + + *info = kbot; +L90: + ; + } + +/* ==== Return the optimal value of LWORK. ==== */ + + work[1] = (real) lwkopt; + +/* ==== End of SLAQR0 ==== */ + + return 0; +} /* slaqr0_ */ + +/* Subroutine */ int slaqr1_(integer *n, real *h__, integer *ldh, real *sr1, + real *si1, real *sr2, real *si2, real *v) +{ + /* System generated locals */ + integer h_dim1, h_offset; + real r__1, r__2, r__3; + + /* Local variables */ + static real s, h21s, h31s; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Given a 2-by-2 or 3-by-3 matrix H, SLAQR1 sets v to a + scalar multiple of the first column of the product + + (*) K = (H - (sr1 + i*si1)*I)*(H - (sr2 + i*si2)*I) + + scaling to avoid overflows and most underflows. It + is assumed that either + + 1) sr1 = sr2 and si1 = -si2 + or + 2) si1 = si2 = 0. + + This is useful for starting double implicit shift bulges + in the QR algorithm. + + + N (input) integer + Order of the matrix H. N must be either 2 or 3. + + H (input) REAL array of dimension (LDH,N) + The 2-by-2 or 3-by-3 matrix H in (*). + + LDH (input) integer + The leading dimension of H as declared in + the calling procedure. LDH.GE.N + + SR1 (input) REAL + SI1 The shifts in (*). + SR2 + SI2 + + V (output) REAL array of dimension N + A scalar multiple of the first column of the + matrix K in (*). + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --v; + + /* Function Body */ + if (*n == 2) { + s = (r__1 = h__[h_dim1 + 1] - *sr2, dabs(r__1)) + dabs(*si2) + (r__2 = + h__[h_dim1 + 2], dabs(r__2)); + if (s == 0.f) { + v[1] = 0.f; + v[2] = 0.f; + } else { + h21s = h__[h_dim1 + 2] / s; + v[1] = h21s * h__[(h_dim1 << 1) + 1] + (h__[h_dim1 + 1] - *sr1) * + ((h__[h_dim1 + 1] - *sr2) / s) - *si1 * (*si2 / s); + v[2] = h21s * (h__[h_dim1 + 1] + h__[(h_dim1 << 1) + 2] - *sr1 - * + sr2); + } + } else { + s = (r__1 = h__[h_dim1 + 1] - *sr2, dabs(r__1)) + dabs(*si2) + (r__2 = + h__[h_dim1 + 2], dabs(r__2)) + (r__3 = h__[h_dim1 + 3], dabs( + r__3)); + if (s == 0.f) { + v[1] = 0.f; + v[2] = 0.f; + v[3] = 0.f; + } else { + h21s = h__[h_dim1 + 2] / s; + h31s = h__[h_dim1 + 3] / s; + v[1] = (h__[h_dim1 + 1] - *sr1) * ((h__[h_dim1 + 1] - *sr2) / s) + - *si1 * (*si2 / s) + h__[(h_dim1 << 1) + 1] * h21s + h__[ + h_dim1 * 3 + 1] * h31s; + v[2] = h21s * (h__[h_dim1 + 1] + h__[(h_dim1 << 1) + 2] - *sr1 - * + sr2) + h__[h_dim1 * 3 + 2] * h31s; + v[3] = h31s * (h__[h_dim1 + 1] + h__[h_dim1 * 3 + 3] - *sr1 - * + sr2) + h21s * h__[(h_dim1 << 1) + 3]; + } + } + return 0; +} /* slaqr1_ */ + +/* Subroutine */ int slaqr2_(logical *wantt, logical *wantz, integer *n, + integer *ktop, integer *kbot, integer *nw, real *h__, integer *ldh, + integer *iloz, integer *ihiz, real *z__, integer *ldz, integer *ns, + integer *nd, real *sr, real *si, real *v, integer *ldv, integer *nh, + real *t, integer *ldt, integer *nv, real *wv, integer *ldwv, real * + work, integer *lwork) +{ + /* System generated locals */ + integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, + wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + real r__1, r__2, r__3, r__4, r__5, r__6; + + /* Local variables */ + static integer i__, j, k; + static real s, aa, bb, cc, dd, cs, sn; + static integer jw; + static real evi, evk, foo; + static integer kln; + static real tau, ulp; + static integer lwk1, lwk2; + static real beta; + static integer kend, kcol, info, ifst, ilst, ltop, krow; + static logical bulge; + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), sgemm_( + char *, char *, integer *, integer *, integer *, real *, real *, + integer *, real *, integer *, real *, real *, integer *); + static integer infqr; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + static integer kwtop; + extern /* Subroutine */ int slanv2_(real *, real *, real *, real *, real * + , real *, real *, real *, real *, real *), slabad_(real *, real *) + ; + extern doublereal slamch_(char *); + extern /* Subroutine */ int sgehrd_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *, integer *); + static real safmin; + extern /* Subroutine */ int slarfg_(integer *, real *, real *, integer *, + real *); + static real safmax; + extern /* Subroutine */ int slahqr_(logical *, logical *, integer *, + integer *, integer *, real *, integer *, real *, real *, integer * + , integer *, real *, integer *, integer *), slacpy_(char *, + integer *, integer *, real *, integer *, real *, integer *), slaset_(char *, integer *, integer *, real *, real *, + real *, integer *); + static logical sorted; + extern /* Subroutine */ int strexc_(char *, integer *, real *, integer *, + real *, integer *, integer *, integer *, real *, integer *), sormhr_(char *, char *, integer *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *, integer *); + static real smlnum; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + -- April 2009 -- + + + This subroutine is identical to SLAQR3 except that it avoids + recursion by calling SLAHQR instead of SLAQR4. + + + ****************************************************************** + Aggressive early deflation: + + This subroutine accepts as input an upper Hessenberg matrix + H and performs an orthogonal similarity transformation + designed to detect and deflate fully converged eigenvalues from + a trailing principal submatrix. On output H has been over- + written by a new Hessenberg matrix that is a perturbation of + an orthogonal similarity transformation of H. It is to be + hoped that the final version of H has many zero subdiagonal + entries. + + ****************************************************************** + WANTT (input) LOGICAL + If .TRUE., then the Hessenberg matrix H is fully updated + so that the quasi-triangular Schur factor may be + computed (in cooperation with the calling subroutine). + If .FALSE., then only enough of H is updated to preserve + the eigenvalues. + + WANTZ (input) LOGICAL + If .TRUE., then the orthogonal matrix Z is updated so + so that the orthogonal Schur factor may be computed + (in cooperation with the calling subroutine). + If .FALSE., then Z is not referenced. + + N (input) INTEGER + The order of the matrix H and (if WANTZ is .TRUE.) the + order of the orthogonal matrix Z. + + KTOP (input) INTEGER + It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0. + KBOT and KTOP together determine an isolated block + along the diagonal of the Hessenberg matrix. + + KBOT (input) INTEGER + It is assumed without a check that either + KBOT = N or H(KBOT+1,KBOT)=0. KBOT and KTOP together + determine an isolated block along the diagonal of the + Hessenberg matrix. + + NW (input) INTEGER + Deflation window size. 1 .LE. NW .LE. (KBOT-KTOP+1). + + H (input/output) REAL array, dimension (LDH,N) + On input the initial N-by-N section of H stores the + Hessenberg matrix undergoing aggressive early deflation. + On output H has been transformed by an orthogonal + similarity transformation, perturbed, and the returned + to Hessenberg form that (it is to be hoped) has some + zero subdiagonal entries. + + LDH (input) integer + Leading dimension of H just as declared in the calling + subroutine. N .LE. LDH + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N. + + Z (input/output) REAL array, dimension (LDZ,N) + IF WANTZ is .TRUE., then on output, the orthogonal + similarity transformation mentioned above has been + accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ is .FALSE., then Z is unreferenced. + + LDZ (input) integer + The leading dimension of Z just as declared in the + calling subroutine. 1 .LE. LDZ. + + NS (output) integer + The number of unconverged (ie approximate) eigenvalues + returned in SR and SI that may be used as shifts by the + calling subroutine. + + ND (output) integer + The number of converged eigenvalues uncovered by this + subroutine. + + SR (output) REAL array, dimension KBOT + SI (output) REAL array, dimension KBOT + On output, the real and imaginary parts of approximate + eigenvalues that may be used for shifts are stored in + SR(KBOT-ND-NS+1) through SR(KBOT-ND) and + SI(KBOT-ND-NS+1) through SI(KBOT-ND), respectively. + The real and imaginary parts of converged eigenvalues + are stored in SR(KBOT-ND+1) through SR(KBOT) and + SI(KBOT-ND+1) through SI(KBOT), respectively. + + V (workspace) REAL array, dimension (LDV,NW) + An NW-by-NW work array. + + LDV (input) integer scalar + The leading dimension of V just as declared in the + calling subroutine. NW .LE. LDV + + NH (input) integer scalar + The number of columns of T. NH.GE.NW. + + T (workspace) REAL array, dimension (LDT,NW) + + LDT (input) integer + The leading dimension of T just as declared in the + calling subroutine. NW .LE. LDT + + NV (input) integer + The number of rows of work array WV available for + workspace. NV.GE.NW. + + WV (workspace) REAL array, dimension (LDWV,NW) + + LDWV (input) integer + The leading dimension of W just as declared in the + calling subroutine. NW .LE. LDV + + WORK (workspace) REAL array, dimension LWORK. + On exit, WORK(1) is set to an estimate of the optimal value + of LWORK for the given values of N, NW, KTOP and KBOT. + + LWORK (input) integer + The dimension of the work array WORK. LWORK = 2*NW + suffices, but greater efficiency may result from larger + values of LWORK. + + If LWORK = -1, then a workspace query is assumed; SLAQR2 + only estimates the optimal workspace size for the given + values of N, NW, KTOP and KBOT. The estimate is returned + in WORK(1). No error message related to LWORK is issued + by XERBLA. Neither H nor Z are accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + + ==== Estimate optimal workspace. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --sr; + --si; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + --work; + + /* Function Body */ +/* Computing MIN */ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + if (jw <= 2) { + lwkopt = 1; + } else { + +/* ==== Workspace query call to SGEHRD ==== */ + + i__1 = jw - 1; + sgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], & + c_n1, &info); + lwk1 = (integer) work[1]; + +/* ==== Workspace query call to SORMHR ==== */ + + i__1 = jw - 1; + sormhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[1], &c_n1, &info); + lwk2 = (integer) work[1]; + +/* ==== Optimal workspace ==== */ + + lwkopt = jw + max(lwk1,lwk2); + } + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + work[1] = (real) lwkopt; + return 0; + } + +/* + ==== Nothing to do ... + ... for an empty active block ... ==== +*/ + *ns = 0; + *nd = 0; + work[1] = 1.f; + if (*ktop > *kbot) { + return 0; + } +/* ... nor for an empty deflation window. ==== */ + if (*nw < 1) { + return 0; + } + +/* ==== Machine constants ==== */ + + safmin = slamch_("SAFE MINIMUM"); + safmax = 1.f / safmin; + slabad_(&safmin, &safmax); + ulp = slamch_("PRECISION"); + smlnum = safmin * ((real) (*n) / ulp); + +/* + ==== Setup deflation window ==== + + Computing MIN +*/ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + kwtop = *kbot - jw + 1; + if (kwtop == *ktop) { + s = 0.f; + } else { + s = h__[kwtop + (kwtop - 1) * h_dim1]; + } + + if (*kbot == kwtop) { + +/* ==== 1-by-1 deflation window: not much to do ==== */ + + sr[kwtop] = h__[kwtop + kwtop * h_dim1]; + si[kwtop] = 0.f; + *ns = 1; + *nd = 0; +/* Computing MAX */ + r__2 = smlnum, r__3 = ulp * (r__1 = h__[kwtop + kwtop * h_dim1], dabs( + r__1)); + if (dabs(s) <= dmax(r__2,r__3)) { + *ns = 0; + *nd = 1; + if (kwtop > *ktop) { + h__[kwtop + (kwtop - 1) * h_dim1] = 0.f; + } + } + work[1] = 1.f; + return 0; + } + +/* + ==== Convert to spike-triangular form. (In case of a + . rare QR failure, this routine continues to do + . aggressive early deflation using that part of + . the deflation window that converged using INFQR + . here and there to keep track.) ==== +*/ + + slacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], + ldt); + i__1 = jw - 1; + i__2 = *ldh + 1; + i__3 = *ldt + 1; + scopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], & + i__3); + + slaset_("A", &jw, &jw, &c_b29, &c_b15, &v[v_offset], ldv); + slahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[kwtop], + &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &infqr); + +/* ==== STREXC needs a clean margin near the diagonal ==== */ + + i__1 = jw - 3; + for (j = 1; j <= i__1; ++j) { + t[j + 2 + j * t_dim1] = 0.f; + t[j + 3 + j * t_dim1] = 0.f; +/* L10: */ + } + if (jw > 2) { + t[jw + (jw - 2) * t_dim1] = 0.f; + } + +/* ==== Deflation detection loop ==== */ + + *ns = jw; + ilst = infqr + 1; +L20: + if (ilst <= *ns) { + if (*ns == 1) { + bulge = FALSE_; + } else { + bulge = t[*ns + (*ns - 1) * t_dim1] != 0.f; + } + +/* ==== Small spike tip test for deflation ==== */ + + if (! bulge) { + +/* ==== Real eigenvalue ==== */ + + foo = (r__1 = t[*ns + *ns * t_dim1], dabs(r__1)); + if (foo == 0.f) { + foo = dabs(s); + } +/* Computing MAX */ + r__2 = smlnum, r__3 = ulp * foo; + if ((r__1 = s * v[*ns * v_dim1 + 1], dabs(r__1)) <= dmax(r__2, + r__3)) { + +/* ==== Deflatable ==== */ + + --(*ns); + } else { + +/* + ==== Undeflatable. Move it up out of the way. + . (STREXC can not fail in this case.) ==== +*/ + + ifst = *ns; + strexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + ++ilst; + } + } else { + +/* ==== Complex conjugate pair ==== */ + + foo = (r__3 = t[*ns + *ns * t_dim1], dabs(r__3)) + sqrt((r__1 = t[ + *ns + (*ns - 1) * t_dim1], dabs(r__1))) * sqrt((r__2 = t[* + ns - 1 + *ns * t_dim1], dabs(r__2))); + if (foo == 0.f) { + foo = dabs(s); + } +/* Computing MAX */ + r__3 = (r__1 = s * v[*ns * v_dim1 + 1], dabs(r__1)), r__4 = (r__2 + = s * v[(*ns - 1) * v_dim1 + 1], dabs(r__2)); +/* Computing MAX */ + r__5 = smlnum, r__6 = ulp * foo; + if (dmax(r__3,r__4) <= dmax(r__5,r__6)) { + +/* ==== Deflatable ==== */ + + *ns += -2; + } else { + +/* + ==== Undeflatable. Move them up out of the way. + . Fortunately, STREXC does the right thing with + . ILST in case of a rare exchange failure. ==== +*/ + + ifst = *ns; + strexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + ilst += 2; + } + } + +/* ==== End deflation detection loop ==== */ + + goto L20; + } + +/* ==== Return to Hessenberg form ==== */ + + if (*ns == 0) { + s = 0.f; + } + + if (*ns < jw) { + +/* + ==== sorting diagonal blocks of T improves accuracy for + . graded matrices. Bubble sort deals well with + . exchange failures. ==== +*/ + + sorted = FALSE_; + i__ = *ns + 1; +L30: + if (sorted) { + goto L50; + } + sorted = TRUE_; + + kend = i__ - 1; + i__ = infqr + 1; + if (i__ == *ns) { + k = i__ + 1; + } else if (t[i__ + 1 + i__ * t_dim1] == 0.f) { + k = i__ + 1; + } else { + k = i__ + 2; + } +L40: + if (k <= kend) { + if (k == i__ + 1) { + evi = (r__1 = t[i__ + i__ * t_dim1], dabs(r__1)); + } else { + evi = (r__3 = t[i__ + i__ * t_dim1], dabs(r__3)) + sqrt((r__1 + = t[i__ + 1 + i__ * t_dim1], dabs(r__1))) * sqrt(( + r__2 = t[i__ + (i__ + 1) * t_dim1], dabs(r__2))); + } + + if (k == kend) { + evk = (r__1 = t[k + k * t_dim1], dabs(r__1)); + } else if (t[k + 1 + k * t_dim1] == 0.f) { + evk = (r__1 = t[k + k * t_dim1], dabs(r__1)); + } else { + evk = (r__3 = t[k + k * t_dim1], dabs(r__3)) + sqrt((r__1 = t[ + k + 1 + k * t_dim1], dabs(r__1))) * sqrt((r__2 = t[k + + (k + 1) * t_dim1], dabs(r__2))); + } + + if (evi >= evk) { + i__ = k; + } else { + sorted = FALSE_; + ifst = i__; + ilst = k; + strexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + if (info == 0) { + i__ = ilst; + } else { + i__ = k; + } + } + if (i__ == kend) { + k = i__ + 1; + } else if (t[i__ + 1 + i__ * t_dim1] == 0.f) { + k = i__ + 1; + } else { + k = i__ + 2; + } + goto L40; + } + goto L30; +L50: + ; + } + +/* ==== Restore shift/eigenvalue array from T ==== */ + + i__ = jw; +L60: + if (i__ >= infqr + 1) { + if (i__ == infqr + 1) { + sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1]; + si[kwtop + i__ - 1] = 0.f; + --i__; + } else if (t[i__ + (i__ - 1) * t_dim1] == 0.f) { + sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1]; + si[kwtop + i__ - 1] = 0.f; + --i__; + } else { + aa = t[i__ - 1 + (i__ - 1) * t_dim1]; + cc = t[i__ + (i__ - 1) * t_dim1]; + bb = t[i__ - 1 + i__ * t_dim1]; + dd = t[i__ + i__ * t_dim1]; + slanv2_(&aa, &bb, &cc, &dd, &sr[kwtop + i__ - 2], &si[kwtop + i__ + - 2], &sr[kwtop + i__ - 1], &si[kwtop + i__ - 1], &cs, & + sn); + i__ += -2; + } + goto L60; + } + + if (*ns < jw || s == 0.f) { + if (*ns > 1 && s != 0.f) { + +/* ==== Reflect spike back into lower triangle ==== */ + + scopy_(ns, &v[v_offset], ldv, &work[1], &c__1); + beta = work[1]; + slarfg_(ns, &beta, &work[2], &c__1, &tau); + work[1] = 1.f; + + i__1 = jw - 2; + i__2 = jw - 2; + slaset_("L", &i__1, &i__2, &c_b29, &c_b29, &t[t_dim1 + 3], ldt); + + slarf_("L", ns, &jw, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + slarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + slarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, & + work[jw + 1]); + + i__1 = *lwork - jw; + sgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1] + , &i__1, &info); + } + +/* ==== Copy updated reduced window into place ==== */ + + if (kwtop > 1) { + h__[kwtop + (kwtop - 1) * h_dim1] = s * v[v_dim1 + 1]; + } + slacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1] + , ldh); + i__1 = jw - 1; + i__2 = *ldt + 1; + i__3 = *ldh + 1; + scopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1], + &i__3); + +/* + ==== Accumulate orthogonal matrix in order update + . H and Z, if requested. ==== +*/ + + if (*ns > 1 && s != 0.f) { + i__1 = *lwork - jw; + sormhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[jw + 1], &i__1, &info); + } + +/* ==== Update vertical slab in H ==== */ + + if (*wantt) { + ltop = 1; + } else { + ltop = *ktop; + } + i__1 = kwtop - 1; + i__2 = *nv; + for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = kwtop - krow; + kln = min(i__3,i__4); + sgemm_("N", "N", &kln, &jw, &jw, &c_b15, &h__[krow + kwtop * + h_dim1], ldh, &v[v_offset], ldv, &c_b29, &wv[wv_offset], + ldwv); + slacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * + h_dim1], ldh); +/* L70: */ + } + +/* ==== Update horizontal slab in H ==== */ + + if (*wantt) { + i__2 = *n; + i__1 = *nh; + for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; + kcol += i__1) { +/* Computing MIN */ + i__3 = *nh, i__4 = *n - kcol + 1; + kln = min(i__3,i__4); + sgemm_("C", "N", &jw, &kln, &jw, &c_b15, &v[v_offset], ldv, & + h__[kwtop + kcol * h_dim1], ldh, &c_b29, &t[t_offset], + ldt); + slacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol * + h_dim1], ldh); +/* L80: */ + } + } + +/* ==== Update vertical slab in Z ==== */ + + if (*wantz) { + i__1 = *ihiz; + i__2 = *nv; + for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = *ihiz - krow + 1; + kln = min(i__3,i__4); + sgemm_("N", "N", &kln, &jw, &jw, &c_b15, &z__[krow + kwtop * + z_dim1], ldz, &v[v_offset], ldv, &c_b29, &wv[ + wv_offset], ldwv); + slacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + + kwtop * z_dim1], ldz); +/* L90: */ + } + } + } + +/* ==== Return the number of deflations ... ==== */ + + *nd = jw - *ns; + +/* + ==== ... and the number of shifts. (Subtracting + . INFQR from the spike length takes care + . of the case of a rare QR failure while + . calculating eigenvalues of the deflation + . window.) ==== +*/ + + *ns -= infqr; + +/* ==== Return optimal workspace. ==== */ + + work[1] = (real) lwkopt; + +/* ==== End of SLAQR2 ==== */ + + return 0; +} /* slaqr2_ */ + +/* Subroutine */ int slaqr3_(logical *wantt, logical *wantz, integer *n, + integer *ktop, integer *kbot, integer *nw, real *h__, integer *ldh, + integer *iloz, integer *ihiz, real *z__, integer *ldz, integer *ns, + integer *nd, real *sr, real *si, real *v, integer *ldv, integer *nh, + real *t, integer *ldt, integer *nv, real *wv, integer *ldwv, real * + work, integer *lwork) +{ + /* System generated locals */ + integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, + wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + real r__1, r__2, r__3, r__4, r__5, r__6; + + /* Local variables */ + static integer i__, j, k; + static real s, aa, bb, cc, dd, cs, sn; + static integer jw; + static real evi, evk, foo; + static integer kln; + static real tau, ulp; + static integer lwk1, lwk2, lwk3; + static real beta; + static integer kend, kcol, info, nmin, ifst, ilst, ltop, krow; + static logical bulge; + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), sgemm_( + char *, char *, integer *, integer *, integer *, real *, real *, + integer *, real *, integer *, real *, real *, integer *); + static integer infqr; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + static integer kwtop; + extern /* Subroutine */ int slanv2_(real *, real *, real *, real *, real * + , real *, real *, real *, real *, real *), slaqr4_(logical *, + logical *, integer *, integer *, integer *, real *, integer *, + real *, real *, integer *, integer *, real *, integer *, real *, + integer *, integer *), slabad_(real *, real *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int sgehrd_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *, integer *); + static real safmin; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static real safmax; + extern /* Subroutine */ int slarfg_(integer *, real *, real *, integer *, + real *), slahqr_(logical *, logical *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, integer * + , real *, integer *, integer *), slacpy_(char *, integer *, + integer *, real *, integer *, real *, integer *), slaset_( + char *, integer *, integer *, real *, real *, real *, integer *); + static logical sorted; + extern /* Subroutine */ int strexc_(char *, integer *, real *, integer *, + real *, integer *, integer *, integer *, real *, integer *), sormhr_(char *, char *, integer *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *, integer *); + static real smlnum; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + -- April 2009 -- + + + ****************************************************************** + Aggressive early deflation: + + This subroutine accepts as input an upper Hessenberg matrix + H and performs an orthogonal similarity transformation + designed to detect and deflate fully converged eigenvalues from + a trailing principal submatrix. On output H has been over- + written by a new Hessenberg matrix that is a perturbation of + an orthogonal similarity transformation of H. It is to be + hoped that the final version of H has many zero subdiagonal + entries. + + ****************************************************************** + WANTT (input) LOGICAL + If .TRUE., then the Hessenberg matrix H is fully updated + so that the quasi-triangular Schur factor may be + computed (in cooperation with the calling subroutine). + If .FALSE., then only enough of H is updated to preserve + the eigenvalues. + + WANTZ (input) LOGICAL + If .TRUE., then the orthogonal matrix Z is updated so + so that the orthogonal Schur factor may be computed + (in cooperation with the calling subroutine). + If .FALSE., then Z is not referenced. + + N (input) INTEGER + The order of the matrix H and (if WANTZ is .TRUE.) the + order of the orthogonal matrix Z. + + KTOP (input) INTEGER + It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0. + KBOT and KTOP together determine an isolated block + along the diagonal of the Hessenberg matrix. + + KBOT (input) INTEGER + It is assumed without a check that either + KBOT = N or H(KBOT+1,KBOT)=0. KBOT and KTOP together + determine an isolated block along the diagonal of the + Hessenberg matrix. + + NW (input) INTEGER + Deflation window size. 1 .LE. NW .LE. (KBOT-KTOP+1). + + H (input/output) REAL array, dimension (LDH,N) + On input the initial N-by-N section of H stores the + Hessenberg matrix undergoing aggressive early deflation. + On output H has been transformed by an orthogonal + similarity transformation, perturbed, and the returned + to Hessenberg form that (it is to be hoped) has some + zero subdiagonal entries. + + LDH (input) integer + Leading dimension of H just as declared in the calling + subroutine. N .LE. LDH + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N. + + Z (input/output) REAL array, dimension (LDZ,N) + IF WANTZ is .TRUE., then on output, the orthogonal + similarity transformation mentioned above has been + accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ is .FALSE., then Z is unreferenced. + + LDZ (input) integer + The leading dimension of Z just as declared in the + calling subroutine. 1 .LE. LDZ. + + NS (output) integer + The number of unconverged (ie approximate) eigenvalues + returned in SR and SI that may be used as shifts by the + calling subroutine. + + ND (output) integer + The number of converged eigenvalues uncovered by this + subroutine. + + SR (output) REAL array, dimension KBOT + SI (output) REAL array, dimension KBOT + On output, the real and imaginary parts of approximate + eigenvalues that may be used for shifts are stored in + SR(KBOT-ND-NS+1) through SR(KBOT-ND) and + SI(KBOT-ND-NS+1) through SI(KBOT-ND), respectively. + The real and imaginary parts of converged eigenvalues + are stored in SR(KBOT-ND+1) through SR(KBOT) and + SI(KBOT-ND+1) through SI(KBOT), respectively. + + V (workspace) REAL array, dimension (LDV,NW) + An NW-by-NW work array. + + LDV (input) integer scalar + The leading dimension of V just as declared in the + calling subroutine. NW .LE. LDV + + NH (input) integer scalar + The number of columns of T. NH.GE.NW. + + T (workspace) REAL array, dimension (LDT,NW) + + LDT (input) integer + The leading dimension of T just as declared in the + calling subroutine. NW .LE. LDT + + NV (input) integer + The number of rows of work array WV available for + workspace. NV.GE.NW. + + WV (workspace) REAL array, dimension (LDWV,NW) + + LDWV (input) integer + The leading dimension of W just as declared in the + calling subroutine. NW .LE. LDV + + WORK (workspace) REAL array, dimension LWORK. + On exit, WORK(1) is set to an estimate of the optimal value + of LWORK for the given values of N, NW, KTOP and KBOT. + + LWORK (input) integer + The dimension of the work array WORK. LWORK = 2*NW + suffices, but greater efficiency may result from larger + values of LWORK. + + If LWORK = -1, then a workspace query is assumed; SLAQR3 + only estimates the optimal workspace size for the given + values of N, NW, KTOP and KBOT. The estimate is returned + in WORK(1). No error message related to LWORK is issued + by XERBLA. Neither H nor Z are accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + + ==== Estimate optimal workspace. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --sr; + --si; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + --work; + + /* Function Body */ +/* Computing MIN */ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + if (jw <= 2) { + lwkopt = 1; + } else { + +/* ==== Workspace query call to SGEHRD ==== */ + + i__1 = jw - 1; + sgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], & + c_n1, &info); + lwk1 = (integer) work[1]; + +/* ==== Workspace query call to SORMHR ==== */ + + i__1 = jw - 1; + sormhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[1], &c_n1, &info); + lwk2 = (integer) work[1]; + +/* ==== Workspace query call to SLAQR4 ==== */ + + slaqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[1], + &si[1], &c__1, &jw, &v[v_offset], ldv, &work[1], &c_n1, & + infqr); + lwk3 = (integer) work[1]; + +/* + ==== Optimal workspace ==== + + Computing MAX +*/ + i__1 = jw + max(lwk1,lwk2); + lwkopt = max(i__1,lwk3); + } + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + work[1] = (real) lwkopt; + return 0; + } + +/* + ==== Nothing to do ... + ... for an empty active block ... ==== +*/ + *ns = 0; + *nd = 0; + work[1] = 1.f; + if (*ktop > *kbot) { + return 0; + } +/* ... nor for an empty deflation window. ==== */ + if (*nw < 1) { + return 0; + } + +/* ==== Machine constants ==== */ + + safmin = slamch_("SAFE MINIMUM"); + safmax = 1.f / safmin; + slabad_(&safmin, &safmax); + ulp = slamch_("PRECISION"); + smlnum = safmin * ((real) (*n) / ulp); + +/* + ==== Setup deflation window ==== + + Computing MIN +*/ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + kwtop = *kbot - jw + 1; + if (kwtop == *ktop) { + s = 0.f; + } else { + s = h__[kwtop + (kwtop - 1) * h_dim1]; + } + + if (*kbot == kwtop) { + +/* ==== 1-by-1 deflation window: not much to do ==== */ + + sr[kwtop] = h__[kwtop + kwtop * h_dim1]; + si[kwtop] = 0.f; + *ns = 1; + *nd = 0; +/* Computing MAX */ + r__2 = smlnum, r__3 = ulp * (r__1 = h__[kwtop + kwtop * h_dim1], dabs( + r__1)); + if (dabs(s) <= dmax(r__2,r__3)) { + *ns = 0; + *nd = 1; + if (kwtop > *ktop) { + h__[kwtop + (kwtop - 1) * h_dim1] = 0.f; + } + } + work[1] = 1.f; + return 0; + } + +/* + ==== Convert to spike-triangular form. (In case of a + . rare QR failure, this routine continues to do + . aggressive early deflation using that part of + . the deflation window that converged using INFQR + . here and there to keep track.) ==== +*/ + + slacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], + ldt); + i__1 = jw - 1; + i__2 = *ldh + 1; + i__3 = *ldt + 1; + scopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], & + i__3); + + slaset_("A", &jw, &jw, &c_b29, &c_b15, &v[v_offset], ldv); + nmin = ilaenv_(&c__12, "SLAQR3", "SV", &jw, &c__1, &jw, lwork, (ftnlen)6, + (ftnlen)2); + if (jw > nmin) { + slaqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[ + kwtop], &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &work[1], + lwork, &infqr); + } else { + slahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sr[ + kwtop], &si[kwtop], &c__1, &jw, &v[v_offset], ldv, &infqr); + } + +/* ==== STREXC needs a clean margin near the diagonal ==== */ + + i__1 = jw - 3; + for (j = 1; j <= i__1; ++j) { + t[j + 2 + j * t_dim1] = 0.f; + t[j + 3 + j * t_dim1] = 0.f; +/* L10: */ + } + if (jw > 2) { + t[jw + (jw - 2) * t_dim1] = 0.f; + } + +/* ==== Deflation detection loop ==== */ + + *ns = jw; + ilst = infqr + 1; +L20: + if (ilst <= *ns) { + if (*ns == 1) { + bulge = FALSE_; + } else { + bulge = t[*ns + (*ns - 1) * t_dim1] != 0.f; + } + +/* ==== Small spike tip test for deflation ==== */ + + if (! bulge) { + +/* ==== Real eigenvalue ==== */ + + foo = (r__1 = t[*ns + *ns * t_dim1], dabs(r__1)); + if (foo == 0.f) { + foo = dabs(s); + } +/* Computing MAX */ + r__2 = smlnum, r__3 = ulp * foo; + if ((r__1 = s * v[*ns * v_dim1 + 1], dabs(r__1)) <= dmax(r__2, + r__3)) { + +/* ==== Deflatable ==== */ + + --(*ns); + } else { + +/* + ==== Undeflatable. Move it up out of the way. + . (STREXC can not fail in this case.) ==== +*/ + + ifst = *ns; + strexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + ++ilst; + } + } else { + +/* ==== Complex conjugate pair ==== */ + + foo = (r__3 = t[*ns + *ns * t_dim1], dabs(r__3)) + sqrt((r__1 = t[ + *ns + (*ns - 1) * t_dim1], dabs(r__1))) * sqrt((r__2 = t[* + ns - 1 + *ns * t_dim1], dabs(r__2))); + if (foo == 0.f) { + foo = dabs(s); + } +/* Computing MAX */ + r__3 = (r__1 = s * v[*ns * v_dim1 + 1], dabs(r__1)), r__4 = (r__2 + = s * v[(*ns - 1) * v_dim1 + 1], dabs(r__2)); +/* Computing MAX */ + r__5 = smlnum, r__6 = ulp * foo; + if (dmax(r__3,r__4) <= dmax(r__5,r__6)) { + +/* ==== Deflatable ==== */ + + *ns += -2; + } else { + +/* + ==== Undeflatable. Move them up out of the way. + . Fortunately, STREXC does the right thing with + . ILST in case of a rare exchange failure. ==== +*/ + + ifst = *ns; + strexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + ilst += 2; + } + } + +/* ==== End deflation detection loop ==== */ + + goto L20; + } + +/* ==== Return to Hessenberg form ==== */ + + if (*ns == 0) { + s = 0.f; + } + + if (*ns < jw) { + +/* + ==== sorting diagonal blocks of T improves accuracy for + . graded matrices. Bubble sort deals well with + . exchange failures. ==== +*/ + + sorted = FALSE_; + i__ = *ns + 1; +L30: + if (sorted) { + goto L50; + } + sorted = TRUE_; + + kend = i__ - 1; + i__ = infqr + 1; + if (i__ == *ns) { + k = i__ + 1; + } else if (t[i__ + 1 + i__ * t_dim1] == 0.f) { + k = i__ + 1; + } else { + k = i__ + 2; + } +L40: + if (k <= kend) { + if (k == i__ + 1) { + evi = (r__1 = t[i__ + i__ * t_dim1], dabs(r__1)); + } else { + evi = (r__3 = t[i__ + i__ * t_dim1], dabs(r__3)) + sqrt((r__1 + = t[i__ + 1 + i__ * t_dim1], dabs(r__1))) * sqrt(( + r__2 = t[i__ + (i__ + 1) * t_dim1], dabs(r__2))); + } + + if (k == kend) { + evk = (r__1 = t[k + k * t_dim1], dabs(r__1)); + } else if (t[k + 1 + k * t_dim1] == 0.f) { + evk = (r__1 = t[k + k * t_dim1], dabs(r__1)); + } else { + evk = (r__3 = t[k + k * t_dim1], dabs(r__3)) + sqrt((r__1 = t[ + k + 1 + k * t_dim1], dabs(r__1))) * sqrt((r__2 = t[k + + (k + 1) * t_dim1], dabs(r__2))); + } + + if (evi >= evk) { + i__ = k; + } else { + sorted = FALSE_; + ifst = i__; + ilst = k; + strexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &work[1], &info); + if (info == 0) { + i__ = ilst; + } else { + i__ = k; + } + } + if (i__ == kend) { + k = i__ + 1; + } else if (t[i__ + 1 + i__ * t_dim1] == 0.f) { + k = i__ + 1; + } else { + k = i__ + 2; + } + goto L40; + } + goto L30; +L50: + ; + } + +/* ==== Restore shift/eigenvalue array from T ==== */ + + i__ = jw; +L60: + if (i__ >= infqr + 1) { + if (i__ == infqr + 1) { + sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1]; + si[kwtop + i__ - 1] = 0.f; + --i__; + } else if (t[i__ + (i__ - 1) * t_dim1] == 0.f) { + sr[kwtop + i__ - 1] = t[i__ + i__ * t_dim1]; + si[kwtop + i__ - 1] = 0.f; + --i__; + } else { + aa = t[i__ - 1 + (i__ - 1) * t_dim1]; + cc = t[i__ + (i__ - 1) * t_dim1]; + bb = t[i__ - 1 + i__ * t_dim1]; + dd = t[i__ + i__ * t_dim1]; + slanv2_(&aa, &bb, &cc, &dd, &sr[kwtop + i__ - 2], &si[kwtop + i__ + - 2], &sr[kwtop + i__ - 1], &si[kwtop + i__ - 1], &cs, & + sn); + i__ += -2; + } + goto L60; + } + + if (*ns < jw || s == 0.f) { + if (*ns > 1 && s != 0.f) { + +/* ==== Reflect spike back into lower triangle ==== */ + + scopy_(ns, &v[v_offset], ldv, &work[1], &c__1); + beta = work[1]; + slarfg_(ns, &beta, &work[2], &c__1, &tau); + work[1] = 1.f; + + i__1 = jw - 2; + i__2 = jw - 2; + slaset_("L", &i__1, &i__2, &c_b29, &c_b29, &t[t_dim1 + 3], ldt); + + slarf_("L", ns, &jw, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + slarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + slarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, & + work[jw + 1]); + + i__1 = *lwork - jw; + sgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1] + , &i__1, &info); + } + +/* ==== Copy updated reduced window into place ==== */ + + if (kwtop > 1) { + h__[kwtop + (kwtop - 1) * h_dim1] = s * v[v_dim1 + 1]; + } + slacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1] + , ldh); + i__1 = jw - 1; + i__2 = *ldt + 1; + i__3 = *ldh + 1; + scopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1], + &i__3); + +/* + ==== Accumulate orthogonal matrix in order update + . H and Z, if requested. ==== +*/ + + if (*ns > 1 && s != 0.f) { + i__1 = *lwork - jw; + sormhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[jw + 1], &i__1, &info); + } + +/* ==== Update vertical slab in H ==== */ + + if (*wantt) { + ltop = 1; + } else { + ltop = *ktop; + } + i__1 = kwtop - 1; + i__2 = *nv; + for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = kwtop - krow; + kln = min(i__3,i__4); + sgemm_("N", "N", &kln, &jw, &jw, &c_b15, &h__[krow + kwtop * + h_dim1], ldh, &v[v_offset], ldv, &c_b29, &wv[wv_offset], + ldwv); + slacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * + h_dim1], ldh); +/* L70: */ + } + +/* ==== Update horizontal slab in H ==== */ + + if (*wantt) { + i__2 = *n; + i__1 = *nh; + for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; + kcol += i__1) { +/* Computing MIN */ + i__3 = *nh, i__4 = *n - kcol + 1; + kln = min(i__3,i__4); + sgemm_("C", "N", &jw, &kln, &jw, &c_b15, &v[v_offset], ldv, & + h__[kwtop + kcol * h_dim1], ldh, &c_b29, &t[t_offset], + ldt); + slacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol * + h_dim1], ldh); +/* L80: */ + } + } + +/* ==== Update vertical slab in Z ==== */ + + if (*wantz) { + i__1 = *ihiz; + i__2 = *nv; + for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = *ihiz - krow + 1; + kln = min(i__3,i__4); + sgemm_("N", "N", &kln, &jw, &jw, &c_b15, &z__[krow + kwtop * + z_dim1], ldz, &v[v_offset], ldv, &c_b29, &wv[ + wv_offset], ldwv); + slacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + + kwtop * z_dim1], ldz); +/* L90: */ + } + } + } + +/* ==== Return the number of deflations ... ==== */ + + *nd = jw - *ns; + +/* + ==== ... and the number of shifts. (Subtracting + . INFQR from the spike length takes care + . of the case of a rare QR failure while + . calculating eigenvalues of the deflation + . window.) ==== +*/ + + *ns -= infqr; + +/* ==== Return optimal workspace. ==== */ + + work[1] = (real) lwkopt; + +/* ==== End of SLAQR3 ==== */ + + return 0; +} /* slaqr3_ */ + +/* Subroutine */ int slaqr4_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, real *h__, integer *ldh, real *wr, real * + wi, integer *iloz, integer *ihiz, real *z__, integer *ldz, real *work, + integer *lwork, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5; + real r__1, r__2, r__3, r__4; + + /* Local variables */ + static integer i__, k; + static real aa, bb, cc, dd; + static integer ld; + static real cs; + static integer nh, it, ks, kt; + static real sn; + static integer ku, kv, ls, ns; + static real ss; + static integer nw, inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, + kbot, nmin; + static real swap; + static integer ktop; + static real zdum[1] /* was [1][1] */; + static integer kacc22, itmax, nsmax, nwmax, kwtop; + extern /* Subroutine */ int slaqr2_(logical *, logical *, integer *, + integer *, integer *, integer *, real *, integer *, integer *, + integer *, real *, integer *, integer *, integer *, real *, real * + , real *, integer *, integer *, real *, integer *, integer *, + real *, integer *, real *, integer *), slanv2_(real *, real *, + real *, real *, real *, real *, real *, real *, real *, real *), + slaqr5_(logical *, logical *, integer *, integer *, integer *, + integer *, integer *, real *, real *, real *, integer *, integer * + , integer *, real *, integer *, real *, integer *, real *, + integer *, integer *, real *, integer *, integer *, real *, + integer *); + static integer nibble; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static char jbcmpz[2]; + extern /* Subroutine */ int slahqr_(logical *, logical *, integer *, + integer *, integer *, real *, integer *, real *, real *, integer * + , integer *, real *, integer *, integer *), slacpy_(char *, + integer *, integer *, real *, integer *, real *, integer *); + static integer nwupbd; + static logical sorted; + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + This subroutine implements one level of recursion for SLAQR0. + It is a complete implementation of the small bulge multi-shift + QR algorithm. It may be called by SLAQR0 and, for large enough + deflation window size, it may be called by SLAQR3. This + subroutine is identical to SLAQR0 except that it calls SLAQR2 + instead of SLAQR3. + + Purpose + ======= + + SLAQR4 computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**T, where T is an upper quasi-triangular matrix (the + Schur form), and Z is the orthogonal matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input orthogonal + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the orthogonal matrix Q: A = Q*H*Q**T = (QZ)*T*(QZ)**T. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1, + H(ILO,ILO-1) is zero. ILO and IHI are normally set by a + previous call to SGEBAL, and then passed to SGEHRD when the + matrix output by SGEBAL is reduced to Hessenberg form. + Otherwise, ILO and IHI should be set to 1 and N, + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) REAL array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and WANTT is .TRUE., then H contains + the upper quasi-triangular matrix T from the Schur + decomposition (the Schur form); 2-by-2 diagonal blocks + (corresponding to complex conjugate pairs of eigenvalues) + are returned in standard form, with H(i,i) = H(i+1,i+1) + and H(i+1,i)*H(i,i+1).LT.0. If INFO = 0 and WANTT is + .FALSE., then the contents of H are unspecified on exit. + (The output value of H when INFO.GT.0 is given under the + description of INFO below.) + + This subroutine may explicitly set H(i,j) = 0 for i.GT.j and + j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + WR (output) REAL array, dimension (IHI) + WI (output) REAL array, dimension (IHI) + The real and imaginary parts, respectively, of the computed + eigenvalues of H(ILO:IHI,ILO:IHI) are stored in WR(ILO:IHI) + and WI(ILO:IHI). If two eigenvalues are computed as a + complex conjugate pair, they are stored in consecutive + elements of WR and WI, say the i-th and (i+1)th, with + WI(i) .GT. 0 and WI(i+1) .LT. 0. If WANTT is .TRUE., then + the eigenvalues are stored in the same order as on the + diagonal of the Schur form returned in H, with + WR(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 diagonal + block, WI(i) = sqrt(-H(i+1,i)*H(i,i+1)) and + WI(i+1) = -WI(i). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. + 1 .LE. ILOZ .LE. ILO; IHI .LE. IHIZ .LE. N. + + Z (input/output) REAL array, dimension (LDZ,IHI) + If WANTZ is .FALSE., then Z is not referenced. + If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is + replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the + orthogonal Schur factor of H(ILO:IHI,ILO:IHI). + (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if WANTZ is .TRUE. + then LDZ.GE.MAX(1,IHIZ). Otherwize, LDZ.GE.1. + + WORK (workspace/output) REAL array, dimension LWORK + On exit, if LWORK = -1, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient, but LWORK typically as large as 6*N may + be required for optimal performance. A workspace query + to determine the optimal workspace size is recommended. + + If LWORK = -1, then SLAQR4 does a workspace query. + In this case, SLAQR4 checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, SLAQR4 failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and WANT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is an orthogonal matrix. The final + value of H is upper Hessenberg and quasi-triangular + in rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + + (final value of Z(ILO:IHI,ILOZ:IHIZ) + = (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U + + where U is the orthogonal matrix in (*) (regard- + less of the value of WANTT.) + + If INFO .GT. 0 and WANTZ is .FALSE., then Z is not + accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . SLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== Exceptional deflation windows: try to cure rare + . slow convergence by varying the size of the + . deflation window after KEXNW iterations. ==== + + ==== Exceptional shifts: try to cure rare slow convergence + . with ad-hoc exceptional shifts every KEXSH iterations. + . ==== + + ==== The constants WILK1 and WILK2 are used to form the + . exceptional shifts. ==== +*/ + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --wr; + --wi; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + +/* ==== Quick return for N = 0: nothing to do. ==== */ + + if (*n == 0) { + work[1] = 1.f; + return 0; + } + + if (*n <= 11) { + +/* ==== Tiny matrices must use SLAHQR. ==== */ + + lwkopt = 1; + if (*lwork != -1) { + slahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &wr[1], & + wi[1], iloz, ihiz, &z__[z_offset], ldz, info); + } + } else { + +/* + ==== Use small bulge multi-shift QR with aggressive early + . deflation on larger-than-tiny matrices. ==== + + ==== Hope for the best. ==== +*/ + + *info = 0; + +/* ==== Set up job flags for ILAENV. ==== */ + + if (*wantt) { + *(unsigned char *)jbcmpz = 'S'; + } else { + *(unsigned char *)jbcmpz = 'E'; + } + if (*wantz) { + *(unsigned char *)&jbcmpz[1] = 'V'; + } else { + *(unsigned char *)&jbcmpz[1] = 'N'; + } + +/* + ==== NWR = recommended deflation window size. At this + . point, N .GT. NTINY = 11, so there is enough + . subdiagonal workspace for NWR.GE.2 as required. + . (In fact, there is enough subdiagonal space for + . NWR.GE.3.) ==== +*/ + + nwr = ilaenv_(&c__13, "SLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nwr = max(2,nwr); +/* Computing MIN */ + i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2); + nwr = min(i__1,nwr); + +/* + ==== NSR = recommended number of simultaneous shifts. + . At this point N .GT. NTINY = 11, so there is at + . enough subdiagonal workspace for NSR to be even + . and greater than or equal to two as required. ==== +*/ + + nsr = ilaenv_(&c__15, "SLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); +/* Computing MIN */ + i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - + *ilo; + nsr = min(i__1,i__2); +/* Computing MAX */ + i__1 = 2, i__2 = nsr - nsr % 2; + nsr = max(i__1,i__2); + +/* + ==== Estimate optimal workspace ==== + + ==== Workspace query call to SLAQR2 ==== +*/ + + i__1 = nwr + 1; + slaqr2_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, + ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], &h__[ + h_offset], ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], + ldh, &work[1], &c_n1); + +/* + ==== Optimal workspace = MAX(SLAQR5, SLAQR2) ==== + + Computing MAX +*/ + i__1 = nsr * 3 / 2, i__2 = (integer) work[1]; + lwkopt = max(i__1,i__2); + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + work[1] = (real) lwkopt; + return 0; + } + +/* ==== SLAHQR/SLAQR0 crossover point ==== */ + + nmin = ilaenv_(&c__12, "SLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen) + 6, (ftnlen)2); + nmin = max(11,nmin); + +/* ==== Nibble crossover point ==== */ + + nibble = ilaenv_(&c__14, "SLAQR4", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + nibble = max(0,nibble); + +/* + ==== Accumulate reflections during ttswp? Use block + . 2-by-2 structure during matrix-matrix multiply? ==== +*/ + + kacc22 = ilaenv_(&c__16, "SLAQR4", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + kacc22 = max(0,kacc22); + kacc22 = min(2,kacc22); + +/* + ==== NWMAX = the largest possible deflation window for + . which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n - 1) / 3, i__2 = *lwork / 2; + nwmax = min(i__1,i__2); + nw = nwmax; + +/* + ==== NSMAX = the Largest number of simultaneous shifts + . for which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3; + nsmax = min(i__1,i__2); + nsmax -= nsmax % 2; + +/* ==== NDFL: an iteration count restarted at deflation. ==== */ + + ndfl = 1; + +/* + ==== ITMAX = iteration limit ==== + + Computing MAX +*/ + i__1 = 10, i__2 = *ihi - *ilo + 1; + itmax = max(i__1,i__2) * 30; + +/* ==== Last row and column in the active block ==== */ + + kbot = *ihi; + +/* ==== Main Loop ==== */ + + i__1 = itmax; + for (it = 1; it <= i__1; ++it) { + +/* ==== Done when KBOT falls below ILO ==== */ + + if (kbot < *ilo) { + goto L90; + } + +/* ==== Locate active block ==== */ + + i__2 = *ilo + 1; + for (k = kbot; k >= i__2; --k) { + if (h__[k + (k - 1) * h_dim1] == 0.f) { + goto L20; + } +/* L10: */ + } + k = *ilo; +L20: + ktop = k; + +/* + ==== Select deflation window size: + . Typical Case: + . If possible and advisable, nibble the entire + . active block. If not, use size MIN(NWR,NWMAX) + . or MIN(NWR+1,NWMAX) depending upon which has + . the smaller corresponding subdiagonal entry + . (a heuristic). + . + . Exceptional Case: + . If there have been no deflations in KEXNW or + . more iterations, then vary the deflation window + . size. At first, because, larger windows are, + . in general, more powerful than smaller ones, + . rapidly increase the window to the maximum possible. + . Then, gradually reduce the window size. ==== +*/ + + nh = kbot - ktop + 1; + nwupbd = min(nh,nwmax); + if (ndfl < 5) { + nw = min(nwupbd,nwr); + } else { +/* Computing MIN */ + i__2 = nwupbd, i__3 = nw << 1; + nw = min(i__2,i__3); + } + if (nw < nwmax) { + if (nw >= nh - 1) { + nw = nh; + } else { + kwtop = kbot - nw + 1; + if ((r__1 = h__[kwtop + (kwtop - 1) * h_dim1], dabs(r__1)) + > (r__2 = h__[kwtop - 1 + (kwtop - 2) * h_dim1], + dabs(r__2))) { + ++nw; + } + } + } + if (ndfl < 5) { + ndec = -1; + } else if (ndec >= 0 || nw >= nwupbd) { + ++ndec; + if (nw - ndec < 2) { + ndec = 0; + } + nw -= ndec; + } + +/* + ==== Aggressive early deflation: + . split workspace under the subdiagonal into + . - an nw-by-nw work array V in the lower + . left-hand-corner, + . - an NW-by-at-least-NW-but-more-is-better + . (NW-by-NHO) horizontal work array along + . the bottom edge, + . - an at-least-NW-but-more-is-better (NHV-by-NW) + . vertical work array along the left-hand-edge. + . ==== +*/ + + kv = *n - nw + 1; + kt = nw + 1; + nho = *n - nw - 1 - kt + 1; + kwv = nw + 2; + nve = *n - nw - kwv + 1; + +/* ==== Aggressive early deflation ==== */ + + slaqr2_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, + iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &wr[1], &wi[1], + &h__[kv + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], + ldh, &nve, &h__[kwv + h_dim1], ldh, &work[1], lwork); + +/* ==== Adjust KBOT accounting for new deflations. ==== */ + + kbot -= ld; + +/* ==== KS points to the shifts. ==== */ + + ks = kbot - ls + 1; + +/* + ==== Skip an expensive QR sweep if there is a (partly + . heuristic) reason to expect that many eigenvalues + . will deflate without it. Here, the QR sweep is + . skipped if many eigenvalues have just been deflated + . or if the remaining active block is small. +*/ + + if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min( + nmin,nwmax)) { + +/* + ==== NS = nominal number of simultaneous shifts. + . This may be lowered (slightly) if SLAQR2 + . did not provide that many shifts. ==== + + Computing MIN + Computing MAX +*/ + i__4 = 2, i__5 = kbot - ktop; + i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5); + ns = min(i__2,i__3); + ns -= ns % 2; + +/* + ==== If there have been no deflations + . in a multiple of KEXSH iterations, + . then try exceptional shifts. + . Otherwise use shifts provided by + . SLAQR2 above or from the eigenvalues + . of a trailing principal submatrix. ==== +*/ + + if (ndfl % 6 == 0) { + ks = kbot - ns + 1; +/* Computing MAX */ + i__3 = ks + 1, i__4 = ktop + 2; + i__2 = max(i__3,i__4); + for (i__ = kbot; i__ >= i__2; i__ += -2) { + ss = (r__1 = h__[i__ + (i__ - 1) * h_dim1], dabs(r__1) + ) + (r__2 = h__[i__ - 1 + (i__ - 2) * h_dim1], + dabs(r__2)); + aa = ss * .75f + h__[i__ + i__ * h_dim1]; + bb = ss; + cc = ss * -.4375f; + dd = aa; + slanv2_(&aa, &bb, &cc, &dd, &wr[i__ - 1], &wi[i__ - 1] + , &wr[i__], &wi[i__], &cs, &sn); +/* L30: */ + } + if (ks == ktop) { + wr[ks + 1] = h__[ks + 1 + (ks + 1) * h_dim1]; + wi[ks + 1] = 0.f; + wr[ks] = wr[ks + 1]; + wi[ks] = wi[ks + 1]; + } + } else { + +/* + ==== Got NS/2 or fewer shifts? Use SLAHQR + . on a trailing principal submatrix to + . get more. (Since NS.LE.NSMAX.LE.(N+6)/9, + . there is enough space below the subdiagonal + . to fit an NS-by-NS scratch array.) ==== +*/ + + if (kbot - ks + 1 <= ns / 2) { + ks = kbot - ns + 1; + kt = *n - ns + 1; + slacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, & + h__[kt + h_dim1], ldh); + slahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[kt + + h_dim1], ldh, &wr[ks], &wi[ks], &c__1, & + c__1, zdum, &c__1, &inf); + ks += inf; + +/* + ==== In case of a rare QR failure use + . eigenvalues of the trailing 2-by-2 + . principal submatrix. ==== +*/ + + if (ks >= kbot) { + aa = h__[kbot - 1 + (kbot - 1) * h_dim1]; + cc = h__[kbot + (kbot - 1) * h_dim1]; + bb = h__[kbot - 1 + kbot * h_dim1]; + dd = h__[kbot + kbot * h_dim1]; + slanv2_(&aa, &bb, &cc, &dd, &wr[kbot - 1], &wi[ + kbot - 1], &wr[kbot], &wi[kbot], &cs, &sn) + ; + ks = kbot - 1; + } + } + + if (kbot - ks + 1 > ns) { + +/* + ==== Sort the shifts (Helps a little) + . Bubble sort keeps complex conjugate + . pairs together. ==== +*/ + + sorted = FALSE_; + i__2 = ks + 1; + for (k = kbot; k >= i__2; --k) { + if (sorted) { + goto L60; + } + sorted = TRUE_; + i__3 = k - 1; + for (i__ = ks; i__ <= i__3; ++i__) { + if ((r__1 = wr[i__], dabs(r__1)) + (r__2 = wi[ + i__], dabs(r__2)) < (r__3 = wr[i__ + + 1], dabs(r__3)) + (r__4 = wi[i__ + 1], + dabs(r__4))) { + sorted = FALSE_; + + swap = wr[i__]; + wr[i__] = wr[i__ + 1]; + wr[i__ + 1] = swap; + + swap = wi[i__]; + wi[i__] = wi[i__ + 1]; + wi[i__ + 1] = swap; + } +/* L40: */ + } +/* L50: */ + } +L60: + ; + } + +/* + ==== Shuffle shifts into pairs of real shifts + . and pairs of complex conjugate shifts + . assuming complex conjugate shifts are + . already adjacent to one another. (Yes, + . they are.) ==== +*/ + + i__2 = ks + 2; + for (i__ = kbot; i__ >= i__2; i__ += -2) { + if (wi[i__] != -wi[i__ - 1]) { + + swap = wr[i__]; + wr[i__] = wr[i__ - 1]; + wr[i__ - 1] = wr[i__ - 2]; + wr[i__ - 2] = swap; + + swap = wi[i__]; + wi[i__] = wi[i__ - 1]; + wi[i__ - 1] = wi[i__ - 2]; + wi[i__ - 2] = swap; + } +/* L70: */ + } + } + +/* + ==== If there are only two shifts and both are + . real, then use only one. ==== +*/ + + if (kbot - ks + 1 == 2) { + if (wi[kbot] == 0.f) { + if ((r__1 = wr[kbot] - h__[kbot + kbot * h_dim1], + dabs(r__1)) < (r__2 = wr[kbot - 1] - h__[kbot + + kbot * h_dim1], dabs(r__2))) { + wr[kbot - 1] = wr[kbot]; + } else { + wr[kbot] = wr[kbot - 1]; + } + } + } + +/* + ==== Use up to NS of the the smallest magnatiude + . shifts. If there aren't NS shifts available, + . then use them all, possibly dropping one to + . make the number of shifts even. ==== + + Computing MIN +*/ + i__2 = ns, i__3 = kbot - ks + 1; + ns = min(i__2,i__3); + ns -= ns % 2; + ks = kbot - ns + 1; + +/* + ==== Small-bulge multi-shift QR sweep: + . split workspace under the subdiagonal into + . - a KDU-by-KDU work array U in the lower + . left-hand-corner, + . - a KDU-by-at-least-KDU-but-more-is-better + . (KDU-by-NHo) horizontal work array WH along + . the bottom edge, + . - and an at-least-KDU-but-more-is-better-by-KDU + . (NVE-by-KDU) vertical work WV arrow along + . the left-hand-edge. ==== +*/ + + kdu = ns * 3 - 3; + ku = *n - kdu + 1; + kwh = kdu + 1; + nho = *n - kdu - 3 - (kdu + 1) + 1; + kwv = kdu + 4; + nve = *n - kdu - kwv + 1; + +/* ==== Small-bulge multi-shift QR sweep ==== */ + + slaqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &wr[ks], + &wi[ks], &h__[h_offset], ldh, iloz, ihiz, &z__[ + z_offset], ldz, &work[1], &c__3, &h__[ku + h_dim1], + ldh, &nve, &h__[kwv + h_dim1], ldh, &nho, &h__[ku + + kwh * h_dim1], ldh); + } + +/* ==== Note progress (or the lack of it). ==== */ + + if (ld > 0) { + ndfl = 1; + } else { + ++ndfl; + } + +/* + ==== End of main loop ==== + L80: +*/ + } + +/* + ==== Iteration limit exceeded. Set INFO to show where + . the problem occurred and exit. ==== +*/ + + *info = kbot; +L90: + ; + } + +/* ==== Return the optimal value of LWORK. ==== */ + + work[1] = (real) lwkopt; + +/* ==== End of SLAQR4 ==== */ + + return 0; +} /* slaqr4_ */ + +/* Subroutine */ int slaqr5_(logical *wantt, logical *wantz, integer *kacc22, + integer *n, integer *ktop, integer *kbot, integer *nshfts, real *sr, + real *si, real *h__, integer *ldh, integer *iloz, integer *ihiz, real + *z__, integer *ldz, real *v, integer *ldv, real *u, integer *ldu, + integer *nv, real *wv, integer *ldwv, integer *nh, real *wh, integer * + ldwh) +{ + /* System generated locals */ + integer h_dim1, h_offset, u_dim1, u_offset, v_dim1, v_offset, wh_dim1, + wh_offset, wv_dim1, wv_offset, z_dim1, z_offset, i__1, i__2, i__3, + i__4, i__5, i__6, i__7; + real r__1, r__2, r__3, r__4, r__5; + + /* Local variables */ + static integer i__, j, k, m, i2, j2, i4, j4, k1; + static real h11, h12, h21, h22; + static integer m22, ns, nu; + static real vt[3], scl; + static integer kdu, kms; + static real ulp; + static integer knz, kzs; + static real tst1, tst2, beta; + static logical blk22, bmp22; + static integer mend, jcol, jlen, jbot, mbot; + static real swap; + static integer jtop, jrow, mtop; + static real alpha; + static logical accum; + static integer ndcol, incol; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static integer krcol, nbmps; + extern /* Subroutine */ int strmm_(char *, char *, char *, char *, + integer *, integer *, real *, real *, integer *, real *, integer * + ), slaqr1_(integer *, real *, + integer *, real *, real *, real *, real *, real *), slabad_(real * + , real *); + extern doublereal slamch_(char *); + static real safmin; + extern /* Subroutine */ int slarfg_(integer *, real *, real *, integer *, + real *); + static real safmax; + extern /* Subroutine */ int slacpy_(char *, integer *, integer *, real *, + integer *, real *, integer *), slaset_(char *, integer *, + integer *, real *, real *, real *, integer *); + static real refsum; + static integer mstart; + static real smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + This auxiliary subroutine called by SLAQR0 performs a + single small-bulge multi-shift QR sweep. + + WANTT (input) logical scalar + WANTT = .true. if the quasi-triangular Schur factor + is being computed. WANTT is set to .false. otherwise. + + WANTZ (input) logical scalar + WANTZ = .true. if the orthogonal Schur factor is being + computed. WANTZ is set to .false. otherwise. + + KACC22 (input) integer with value 0, 1, or 2. + Specifies the computation mode of far-from-diagonal + orthogonal updates. + = 0: SLAQR5 does not accumulate reflections and does not + use matrix-matrix multiply to update far-from-diagonal + matrix entries. + = 1: SLAQR5 accumulates reflections and uses matrix-matrix + multiply to update the far-from-diagonal matrix entries. + = 2: SLAQR5 accumulates reflections, uses matrix-matrix + multiply to update the far-from-diagonal matrix entries, + and takes advantage of 2-by-2 block structure during + matrix multiplies. + + N (input) integer scalar + N is the order of the Hessenberg matrix H upon which this + subroutine operates. + + KTOP (input) integer scalar + KBOT (input) integer scalar + These are the first and last rows and columns of an + isolated diagonal block upon which the QR sweep is to be + applied. It is assumed without a check that + either KTOP = 1 or H(KTOP,KTOP-1) = 0 + and + either KBOT = N or H(KBOT+1,KBOT) = 0. + + NSHFTS (input) integer scalar + NSHFTS gives the number of simultaneous shifts. NSHFTS + must be positive and even. + + SR (input/output) REAL array of size (NSHFTS) + SI (input/output) REAL array of size (NSHFTS) + SR contains the real parts and SI contains the imaginary + parts of the NSHFTS shifts of origin that define the + multi-shift QR sweep. On output SR and SI may be + reordered. + + H (input/output) REAL array of size (LDH,N) + On input H contains a Hessenberg matrix. On output a + multi-shift QR sweep with shifts SR(J)+i*SI(J) is applied + to the isolated diagonal block in rows and columns KTOP + through KBOT. + + LDH (input) integer scalar + LDH is the leading dimension of H just as declared in the + calling procedure. LDH.GE.MAX(1,N). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N + + Z (input/output) REAL array of size (LDZ,IHI) + If WANTZ = .TRUE., then the QR Sweep orthogonal + similarity transformation is accumulated into + Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ = .FALSE., then Z is unreferenced. + + LDZ (input) integer scalar + LDA is the leading dimension of Z just as declared in + the calling procedure. LDZ.GE.N. + + V (workspace) REAL array of size (LDV,NSHFTS/2) + + LDV (input) integer scalar + LDV is the leading dimension of V as declared in the + calling procedure. LDV.GE.3. + + U (workspace) REAL array of size + (LDU,3*NSHFTS-3) + + LDU (input) integer scalar + LDU is the leading dimension of U just as declared in the + in the calling subroutine. LDU.GE.3*NSHFTS-3. + + NH (input) integer scalar + NH is the number of columns in array WH available for + workspace. NH.GE.1. + + WH (workspace) REAL array of size (LDWH,NH) + + LDWH (input) integer scalar + Leading dimension of WH just as declared in the + calling procedure. LDWH.GE.3*NSHFTS-3. + + NV (input) integer scalar + NV is the number of rows in WV agailable for workspace. + NV.GE.1. + + WV (workspace) REAL array of size + (LDWV,3*NSHFTS-3) + + LDWV (input) integer scalar + LDWV is the leading dimension of WV as declared in the + in the calling subroutine. LDWV.GE.NV. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + Reference: + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and + Level 3 Performance, SIAM Journal of Matrix Analysis, + volume 23, pages 929--947, 2002. + + ================================================================ + + + ==== If there are no shifts, then there is nothing to do. ==== +*/ + + /* Parameter adjustments */ + --sr; + --si; + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + wh_dim1 = *ldwh; + wh_offset = 1 + wh_dim1; + wh -= wh_offset; + + /* Function Body */ + if (*nshfts < 2) { + return 0; + } + +/* + ==== If the active block is empty or 1-by-1, then there + . is nothing to do. ==== +*/ + + if (*ktop >= *kbot) { + return 0; + } + +/* + ==== Shuffle shifts into pairs of real shifts and pairs + . of complex conjugate shifts assuming complex + . conjugate shifts are already adjacent to one + . another. ==== +*/ + + i__1 = *nshfts - 2; + for (i__ = 1; i__ <= i__1; i__ += 2) { + if (si[i__] != -si[i__ + 1]) { + + swap = sr[i__]; + sr[i__] = sr[i__ + 1]; + sr[i__ + 1] = sr[i__ + 2]; + sr[i__ + 2] = swap; + + swap = si[i__]; + si[i__] = si[i__ + 1]; + si[i__ + 1] = si[i__ + 2]; + si[i__ + 2] = swap; + } +/* L10: */ + } + +/* + ==== NSHFTS is supposed to be even, but if it is odd, + . then simply reduce it by one. The shuffle above + . ensures that the dropped shift is real and that + . the remaining shifts are paired. ==== +*/ + + ns = *nshfts - *nshfts % 2; + +/* ==== Machine constants for deflation ==== */ + + safmin = slamch_("SAFE MINIMUM"); + safmax = 1.f / safmin; + slabad_(&safmin, &safmax); + ulp = slamch_("PRECISION"); + smlnum = safmin * ((real) (*n) / ulp); + +/* + ==== Use accumulated reflections to update far-from-diagonal + . entries ? ==== +*/ + + accum = *kacc22 == 1 || *kacc22 == 2; + +/* ==== If so, exploit the 2-by-2 block structure? ==== */ + + blk22 = ns > 2 && *kacc22 == 2; + +/* ==== clear trash ==== */ + + if (*ktop + 2 <= *kbot) { + h__[*ktop + 2 + *ktop * h_dim1] = 0.f; + } + +/* ==== NBMPS = number of 2-shift bulges in the chain ==== */ + + nbmps = ns / 2; + +/* ==== KDU = width of slab ==== */ + + kdu = nbmps * 6 - 3; + +/* ==== Create and chase chains of NBMPS bulges ==== */ + + i__1 = *kbot - 2; + i__2 = nbmps * 3 - 2; + for (incol = (1 - nbmps) * 3 + *ktop - 1; i__2 < 0 ? incol >= i__1 : + incol <= i__1; incol += i__2) { + ndcol = incol + kdu; + if (accum) { + slaset_("ALL", &kdu, &kdu, &c_b29, &c_b15, &u[u_offset], ldu); + } + +/* + ==== Near-the-diagonal bulge chase. The following loop + . performs the near-the-diagonal part of a small bulge + . multi-shift QR sweep. Each 6*NBMPS-2 column diagonal + . chunk extends from column INCOL to column NDCOL + . (including both column INCOL and column NDCOL). The + . following loop chases a 3*NBMPS column long chain of + . NBMPS bulges 3*NBMPS-2 columns to the right. (INCOL + . may be less than KTOP and and NDCOL may be greater than + . KBOT indicating phantom columns from which to chase + . bulges before they are actually introduced or to which + . to chase bulges beyond column KBOT.) ==== + + Computing MIN +*/ + i__4 = incol + nbmps * 3 - 3, i__5 = *kbot - 2; + i__3 = min(i__4,i__5); + for (krcol = incol; krcol <= i__3; ++krcol) { + +/* + ==== Bulges number MTOP to MBOT are active double implicit + . shift bulges. There may or may not also be small + . 2-by-2 bulge, if there is room. The inactive bulges + . (if any) must wait until the active bulges have moved + . down the diagonal to make room. The phantom matrix + . paradigm described above helps keep track. ==== + + Computing MAX +*/ + i__4 = 1, i__5 = (*ktop - 1 - krcol + 2) / 3 + 1; + mtop = max(i__4,i__5); +/* Computing MIN */ + i__4 = nbmps, i__5 = (*kbot - krcol) / 3; + mbot = min(i__4,i__5); + m22 = mbot + 1; + bmp22 = mbot < nbmps && krcol + (m22 - 1) * 3 == *kbot - 2; + +/* + ==== Generate reflections to chase the chain right + . one column. (The minimum value of K is KTOP-1.) ==== +*/ + + i__4 = mbot; + for (m = mtop; m <= i__4; ++m) { + k = krcol + (m - 1) * 3; + if (k == *ktop - 1) { + slaqr1_(&c__3, &h__[*ktop + *ktop * h_dim1], ldh, &sr[(m + << 1) - 1], &si[(m << 1) - 1], &sr[m * 2], &si[m * + 2], &v[m * v_dim1 + 1]); + alpha = v[m * v_dim1 + 1]; + slarfg_(&c__3, &alpha, &v[m * v_dim1 + 2], &c__1, &v[m * + v_dim1 + 1]); + } else { + beta = h__[k + 1 + k * h_dim1]; + v[m * v_dim1 + 2] = h__[k + 2 + k * h_dim1]; + v[m * v_dim1 + 3] = h__[k + 3 + k * h_dim1]; + slarfg_(&c__3, &beta, &v[m * v_dim1 + 2], &c__1, &v[m * + v_dim1 + 1]); + +/* + ==== A Bulge may collapse because of vigilant + . deflation or destructive underflow. In the + . underflow case, try the two-small-subdiagonals + . trick to try to reinflate the bulge. ==== +*/ + + if (h__[k + 3 + k * h_dim1] != 0.f || h__[k + 3 + (k + 1) + * h_dim1] != 0.f || h__[k + 3 + (k + 2) * h_dim1] + == 0.f) { + +/* ==== Typical case: not collapsed (yet). ==== */ + + h__[k + 1 + k * h_dim1] = beta; + h__[k + 2 + k * h_dim1] = 0.f; + h__[k + 3 + k * h_dim1] = 0.f; + } else { + +/* + ==== Atypical case: collapsed. Attempt to + . reintroduce ignoring H(K+1,K) and H(K+2,K). + . If the fill resulting from the new + . reflector is too large, then abandon it. + . Otherwise, use the new one. ==== +*/ + + slaqr1_(&c__3, &h__[k + 1 + (k + 1) * h_dim1], ldh, & + sr[(m << 1) - 1], &si[(m << 1) - 1], &sr[m * + 2], &si[m * 2], vt); + alpha = vt[0]; + slarfg_(&c__3, &alpha, &vt[1], &c__1, vt); + refsum = vt[0] * (h__[k + 1 + k * h_dim1] + vt[1] * + h__[k + 2 + k * h_dim1]); + + if ((r__1 = h__[k + 2 + k * h_dim1] - refsum * vt[1], + dabs(r__1)) + (r__2 = refsum * vt[2], dabs( + r__2)) > ulp * ((r__3 = h__[k + k * h_dim1], + dabs(r__3)) + (r__4 = h__[k + 1 + (k + 1) * + h_dim1], dabs(r__4)) + (r__5 = h__[k + 2 + (k + + 2) * h_dim1], dabs(r__5)))) { + +/* + ==== Starting a new bulge here would + . create non-negligible fill. Use + . the old one with trepidation. ==== +*/ + + h__[k + 1 + k * h_dim1] = beta; + h__[k + 2 + k * h_dim1] = 0.f; + h__[k + 3 + k * h_dim1] = 0.f; + } else { + +/* + ==== Stating a new bulge here would + . create only negligible fill. + . Replace the old reflector with + . the new one. ==== +*/ + + h__[k + 1 + k * h_dim1] -= refsum; + h__[k + 2 + k * h_dim1] = 0.f; + h__[k + 3 + k * h_dim1] = 0.f; + v[m * v_dim1 + 1] = vt[0]; + v[m * v_dim1 + 2] = vt[1]; + v[m * v_dim1 + 3] = vt[2]; + } + } + } +/* L20: */ + } + +/* ==== Generate a 2-by-2 reflection, if needed. ==== */ + + k = krcol + (m22 - 1) * 3; + if (bmp22) { + if (k == *ktop - 1) { + slaqr1_(&c__2, &h__[k + 1 + (k + 1) * h_dim1], ldh, &sr[( + m22 << 1) - 1], &si[(m22 << 1) - 1], &sr[m22 * 2], + &si[m22 * 2], &v[m22 * v_dim1 + 1]); + beta = v[m22 * v_dim1 + 1]; + slarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 + * v_dim1 + 1]); + } else { + beta = h__[k + 1 + k * h_dim1]; + v[m22 * v_dim1 + 2] = h__[k + 2 + k * h_dim1]; + slarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 + * v_dim1 + 1]); + h__[k + 1 + k * h_dim1] = beta; + h__[k + 2 + k * h_dim1] = 0.f; + } + } + +/* ==== Multiply H by reflections from the left ==== */ + + if (accum) { + jbot = min(ndcol,*kbot); + } else if (*wantt) { + jbot = *n; + } else { + jbot = *kbot; + } + i__4 = jbot; + for (j = max(*ktop,krcol); j <= i__4; ++j) { +/* Computing MIN */ + i__5 = mbot, i__6 = (j - krcol + 2) / 3; + mend = min(i__5,i__6); + i__5 = mend; + for (m = mtop; m <= i__5; ++m) { + k = krcol + (m - 1) * 3; + refsum = v[m * v_dim1 + 1] * (h__[k + 1 + j * h_dim1] + v[ + m * v_dim1 + 2] * h__[k + 2 + j * h_dim1] + v[m * + v_dim1 + 3] * h__[k + 3 + j * h_dim1]); + h__[k + 1 + j * h_dim1] -= refsum; + h__[k + 2 + j * h_dim1] -= refsum * v[m * v_dim1 + 2]; + h__[k + 3 + j * h_dim1] -= refsum * v[m * v_dim1 + 3]; +/* L30: */ + } +/* L40: */ + } + if (bmp22) { + k = krcol + (m22 - 1) * 3; +/* Computing MAX */ + i__4 = k + 1; + i__5 = jbot; + for (j = max(i__4,*ktop); j <= i__5; ++j) { + refsum = v[m22 * v_dim1 + 1] * (h__[k + 1 + j * h_dim1] + + v[m22 * v_dim1 + 2] * h__[k + 2 + j * h_dim1]); + h__[k + 1 + j * h_dim1] -= refsum; + h__[k + 2 + j * h_dim1] -= refsum * v[m22 * v_dim1 + 2]; +/* L50: */ + } + } + +/* + ==== Multiply H by reflections from the right. + . Delay filling in the last row until the + . vigilant deflation check is complete. ==== +*/ + + if (accum) { + jtop = max(*ktop,incol); + } else if (*wantt) { + jtop = 1; + } else { + jtop = *ktop; + } + i__5 = mbot; + for (m = mtop; m <= i__5; ++m) { + if (v[m * v_dim1 + 1] != 0.f) { + k = krcol + (m - 1) * 3; +/* Computing MIN */ + i__6 = *kbot, i__7 = k + 3; + i__4 = min(i__6,i__7); + for (j = jtop; j <= i__4; ++j) { + refsum = v[m * v_dim1 + 1] * (h__[j + (k + 1) * + h_dim1] + v[m * v_dim1 + 2] * h__[j + (k + 2) + * h_dim1] + v[m * v_dim1 + 3] * h__[j + (k + + 3) * h_dim1]); + h__[j + (k + 1) * h_dim1] -= refsum; + h__[j + (k + 2) * h_dim1] -= refsum * v[m * v_dim1 + + 2]; + h__[j + (k + 3) * h_dim1] -= refsum * v[m * v_dim1 + + 3]; +/* L60: */ + } + + if (accum) { + +/* + ==== Accumulate U. (If necessary, update Z later + . with with an efficient matrix-matrix + . multiply.) ==== +*/ + + kms = k - incol; +/* Computing MAX */ + i__4 = 1, i__6 = *ktop - incol; + i__7 = kdu; + for (j = max(i__4,i__6); j <= i__7; ++j) { + refsum = v[m * v_dim1 + 1] * (u[j + (kms + 1) * + u_dim1] + v[m * v_dim1 + 2] * u[j + (kms + + 2) * u_dim1] + v[m * v_dim1 + 3] * u[j + + (kms + 3) * u_dim1]); + u[j + (kms + 1) * u_dim1] -= refsum; + u[j + (kms + 2) * u_dim1] -= refsum * v[m * + v_dim1 + 2]; + u[j + (kms + 3) * u_dim1] -= refsum * v[m * + v_dim1 + 3]; +/* L70: */ + } + } else if (*wantz) { + +/* + ==== U is not accumulated, so update Z + . now by multiplying by reflections + . from the right. ==== +*/ + + i__7 = *ihiz; + for (j = *iloz; j <= i__7; ++j) { + refsum = v[m * v_dim1 + 1] * (z__[j + (k + 1) * + z_dim1] + v[m * v_dim1 + 2] * z__[j + (k + + 2) * z_dim1] + v[m * v_dim1 + 3] * z__[ + j + (k + 3) * z_dim1]); + z__[j + (k + 1) * z_dim1] -= refsum; + z__[j + (k + 2) * z_dim1] -= refsum * v[m * + v_dim1 + 2]; + z__[j + (k + 3) * z_dim1] -= refsum * v[m * + v_dim1 + 3]; +/* L80: */ + } + } + } +/* L90: */ + } + +/* ==== Special case: 2-by-2 reflection (if needed) ==== */ + + k = krcol + (m22 - 1) * 3; + if (bmp22 && v[m22 * v_dim1 + 1] != 0.f) { +/* Computing MIN */ + i__7 = *kbot, i__4 = k + 3; + i__5 = min(i__7,i__4); + for (j = jtop; j <= i__5; ++j) { + refsum = v[m22 * v_dim1 + 1] * (h__[j + (k + 1) * h_dim1] + + v[m22 * v_dim1 + 2] * h__[j + (k + 2) * h_dim1]) + ; + h__[j + (k + 1) * h_dim1] -= refsum; + h__[j + (k + 2) * h_dim1] -= refsum * v[m22 * v_dim1 + 2]; +/* L100: */ + } + + if (accum) { + kms = k - incol; +/* Computing MAX */ + i__5 = 1, i__7 = *ktop - incol; + i__4 = kdu; + for (j = max(i__5,i__7); j <= i__4; ++j) { + refsum = v[m22 * v_dim1 + 1] * (u[j + (kms + 1) * + u_dim1] + v[m22 * v_dim1 + 2] * u[j + (kms + + 2) * u_dim1]); + u[j + (kms + 1) * u_dim1] -= refsum; + u[j + (kms + 2) * u_dim1] -= refsum * v[m22 * v_dim1 + + 2]; +/* L110: */ + } + } else if (*wantz) { + i__4 = *ihiz; + for (j = *iloz; j <= i__4; ++j) { + refsum = v[m22 * v_dim1 + 1] * (z__[j + (k + 1) * + z_dim1] + v[m22 * v_dim1 + 2] * z__[j + (k + + 2) * z_dim1]); + z__[j + (k + 1) * z_dim1] -= refsum; + z__[j + (k + 2) * z_dim1] -= refsum * v[m22 * v_dim1 + + 2]; +/* L120: */ + } + } + } + +/* ==== Vigilant deflation check ==== */ + + mstart = mtop; + if (krcol + (mstart - 1) * 3 < *ktop) { + ++mstart; + } + mend = mbot; + if (bmp22) { + ++mend; + } + if (krcol == *kbot - 2) { + ++mend; + } + i__4 = mend; + for (m = mstart; m <= i__4; ++m) { +/* Computing MIN */ + i__5 = *kbot - 1, i__7 = krcol + (m - 1) * 3; + k = min(i__5,i__7); + +/* + ==== The following convergence test requires that + . the tradition small-compared-to-nearby-diagonals + . criterion and the Ahues & Tisseur (LAWN 122, 1997) + . criteria both be satisfied. The latter improves + . accuracy in some examples. Falling back on an + . alternate convergence criterion when TST1 or TST2 + . is zero (as done here) is traditional but probably + . unnecessary. ==== +*/ + + if (h__[k + 1 + k * h_dim1] != 0.f) { + tst1 = (r__1 = h__[k + k * h_dim1], dabs(r__1)) + (r__2 = + h__[k + 1 + (k + 1) * h_dim1], dabs(r__2)); + if (tst1 == 0.f) { + if (k >= *ktop + 1) { + tst1 += (r__1 = h__[k + (k - 1) * h_dim1], dabs( + r__1)); + } + if (k >= *ktop + 2) { + tst1 += (r__1 = h__[k + (k - 2) * h_dim1], dabs( + r__1)); + } + if (k >= *ktop + 3) { + tst1 += (r__1 = h__[k + (k - 3) * h_dim1], dabs( + r__1)); + } + if (k <= *kbot - 2) { + tst1 += (r__1 = h__[k + 2 + (k + 1) * h_dim1], + dabs(r__1)); + } + if (k <= *kbot - 3) { + tst1 += (r__1 = h__[k + 3 + (k + 1) * h_dim1], + dabs(r__1)); + } + if (k <= *kbot - 4) { + tst1 += (r__1 = h__[k + 4 + (k + 1) * h_dim1], + dabs(r__1)); + } + } +/* Computing MAX */ + r__2 = smlnum, r__3 = ulp * tst1; + if ((r__1 = h__[k + 1 + k * h_dim1], dabs(r__1)) <= dmax( + r__2,r__3)) { +/* Computing MAX */ + r__3 = (r__1 = h__[k + 1 + k * h_dim1], dabs(r__1)), + r__4 = (r__2 = h__[k + (k + 1) * h_dim1], + dabs(r__2)); + h12 = dmax(r__3,r__4); +/* Computing MIN */ + r__3 = (r__1 = h__[k + 1 + k * h_dim1], dabs(r__1)), + r__4 = (r__2 = h__[k + (k + 1) * h_dim1], + dabs(r__2)); + h21 = dmin(r__3,r__4); +/* Computing MAX */ + r__3 = (r__1 = h__[k + 1 + (k + 1) * h_dim1], dabs( + r__1)), r__4 = (r__2 = h__[k + k * h_dim1] - + h__[k + 1 + (k + 1) * h_dim1], dabs(r__2)); + h11 = dmax(r__3,r__4); +/* Computing MIN */ + r__3 = (r__1 = h__[k + 1 + (k + 1) * h_dim1], dabs( + r__1)), r__4 = (r__2 = h__[k + k * h_dim1] - + h__[k + 1 + (k + 1) * h_dim1], dabs(r__2)); + h22 = dmin(r__3,r__4); + scl = h11 + h12; + tst2 = h22 * (h11 / scl); + +/* Computing MAX */ + r__1 = smlnum, r__2 = ulp * tst2; + if (tst2 == 0.f || h21 * (h12 / scl) <= dmax(r__1, + r__2)) { + h__[k + 1 + k * h_dim1] = 0.f; + } + } + } +/* L130: */ + } + +/* + ==== Fill in the last row of each bulge. ==== + + Computing MIN +*/ + i__4 = nbmps, i__5 = (*kbot - krcol - 1) / 3; + mend = min(i__4,i__5); + i__4 = mend; + for (m = mtop; m <= i__4; ++m) { + k = krcol + (m - 1) * 3; + refsum = v[m * v_dim1 + 1] * v[m * v_dim1 + 3] * h__[k + 4 + ( + k + 3) * h_dim1]; + h__[k + 4 + (k + 1) * h_dim1] = -refsum; + h__[k + 4 + (k + 2) * h_dim1] = -refsum * v[m * v_dim1 + 2]; + h__[k + 4 + (k + 3) * h_dim1] -= refsum * v[m * v_dim1 + 3]; +/* L140: */ + } + +/* + ==== End of near-the-diagonal bulge chase. ==== + + L150: +*/ + } + +/* + ==== Use U (if accumulated) to update far-from-diagonal + . entries in H. If required, use U to update Z as + . well. ==== +*/ + + if (accum) { + if (*wantt) { + jtop = 1; + jbot = *n; + } else { + jtop = *ktop; + jbot = *kbot; + } + if (! blk22 || incol < *ktop || ndcol > *kbot || ns <= 2) { + +/* + ==== Updates not exploiting the 2-by-2 block + . structure of U. K1 and NU keep track of + . the location and size of U in the special + . cases of introducing bulges and chasing + . bulges off the bottom. In these special + . cases and in case the number of shifts + . is NS = 2, there is no 2-by-2 block + . structure to exploit. ==== + + Computing MAX +*/ + i__3 = 1, i__4 = *ktop - incol; + k1 = max(i__3,i__4); +/* Computing MAX */ + i__3 = 0, i__4 = ndcol - *kbot; + nu = kdu - max(i__3,i__4) - k1 + 1; + +/* ==== Horizontal Multiply ==== */ + + i__3 = jbot; + i__4 = *nh; + for (jcol = min(ndcol,*kbot) + 1; i__4 < 0 ? jcol >= i__3 : + jcol <= i__3; jcol += i__4) { +/* Computing MIN */ + i__5 = *nh, i__7 = jbot - jcol + 1; + jlen = min(i__5,i__7); + sgemm_("C", "N", &nu, &jlen, &nu, &c_b15, &u[k1 + k1 * + u_dim1], ldu, &h__[incol + k1 + jcol * h_dim1], + ldh, &c_b29, &wh[wh_offset], ldwh); + slacpy_("ALL", &nu, &jlen, &wh[wh_offset], ldwh, &h__[ + incol + k1 + jcol * h_dim1], ldh); +/* L160: */ + } + +/* ==== Vertical multiply ==== */ + + i__4 = max(*ktop,incol) - 1; + i__3 = *nv; + for (jrow = jtop; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; + jrow += i__3) { +/* Computing MIN */ + i__5 = *nv, i__7 = max(*ktop,incol) - jrow; + jlen = min(i__5,i__7); + sgemm_("N", "N", &jlen, &nu, &nu, &c_b15, &h__[jrow + ( + incol + k1) * h_dim1], ldh, &u[k1 + k1 * u_dim1], + ldu, &c_b29, &wv[wv_offset], ldwv); + slacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &h__[ + jrow + (incol + k1) * h_dim1], ldh); +/* L170: */ + } + +/* ==== Z multiply (also vertical) ==== */ + + if (*wantz) { + i__3 = *ihiz; + i__4 = *nv; + for (jrow = *iloz; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; + jrow += i__4) { +/* Computing MIN */ + i__5 = *nv, i__7 = *ihiz - jrow + 1; + jlen = min(i__5,i__7); + sgemm_("N", "N", &jlen, &nu, &nu, &c_b15, &z__[jrow + + (incol + k1) * z_dim1], ldz, &u[k1 + k1 * + u_dim1], ldu, &c_b29, &wv[wv_offset], ldwv); + slacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &z__[ + jrow + (incol + k1) * z_dim1], ldz) + ; +/* L180: */ + } + } + } else { + +/* + ==== Updates exploiting U's 2-by-2 block structure. + . (I2, I4, J2, J4 are the last rows and columns + . of the blocks.) ==== +*/ + + i2 = (kdu + 1) / 2; + i4 = kdu; + j2 = i4 - i2; + j4 = kdu; + +/* + ==== KZS and KNZ deal with the band of zeros + . along the diagonal of one of the triangular + . blocks. ==== +*/ + + kzs = j4 - j2 - (ns + 1); + knz = ns + 1; + +/* ==== Horizontal multiply ==== */ + + i__4 = jbot; + i__3 = *nh; + for (jcol = min(ndcol,*kbot) + 1; i__3 < 0 ? jcol >= i__4 : + jcol <= i__4; jcol += i__3) { +/* Computing MIN */ + i__5 = *nh, i__7 = jbot - jcol + 1; + jlen = min(i__5,i__7); + +/* + ==== Copy bottom of H to top+KZS of scratch ==== + (The first KZS rows get multiplied by zero.) ==== +*/ + + slacpy_("ALL", &knz, &jlen, &h__[incol + 1 + j2 + jcol * + h_dim1], ldh, &wh[kzs + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U21' ==== */ + + slaset_("ALL", &kzs, &jlen, &c_b29, &c_b29, &wh[wh_offset] + , ldwh); + strmm_("L", "U", "C", "N", &knz, &jlen, &c_b15, &u[j2 + 1 + + (kzs + 1) * u_dim1], ldu, &wh[kzs + 1 + wh_dim1] + , ldwh); + +/* ==== Multiply top of H by U11' ==== */ + + sgemm_("C", "N", &i2, &jlen, &j2, &c_b15, &u[u_offset], + ldu, &h__[incol + 1 + jcol * h_dim1], ldh, &c_b15, + &wh[wh_offset], ldwh); + +/* ==== Copy top of H to bottom of WH ==== */ + + slacpy_("ALL", &j2, &jlen, &h__[incol + 1 + jcol * h_dim1] + , ldh, &wh[i2 + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U21' ==== */ + + strmm_("L", "L", "C", "N", &j2, &jlen, &c_b15, &u[(i2 + 1) + * u_dim1 + 1], ldu, &wh[i2 + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + sgemm_("C", "N", &i__5, &jlen, &i__7, &c_b15, &u[j2 + 1 + + (i2 + 1) * u_dim1], ldu, &h__[incol + 1 + j2 + + jcol * h_dim1], ldh, &c_b15, &wh[i2 + 1 + wh_dim1] + , ldwh); + +/* ==== Copy it back ==== */ + + slacpy_("ALL", &kdu, &jlen, &wh[wh_offset], ldwh, &h__[ + incol + 1 + jcol * h_dim1], ldh); +/* L190: */ + } + +/* ==== Vertical multiply ==== */ + + i__3 = max(incol,*ktop) - 1; + i__4 = *nv; + for (jrow = jtop; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; + jrow += i__4) { +/* Computing MIN */ + i__5 = *nv, i__7 = max(incol,*ktop) - jrow; + jlen = min(i__5,i__7); + +/* + ==== Copy right of H to scratch (the first KZS + . columns get multiplied by zero) ==== +*/ + + slacpy_("ALL", &jlen, &knz, &h__[jrow + (incol + 1 + j2) * + h_dim1], ldh, &wv[(kzs + 1) * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U21 ==== */ + + slaset_("ALL", &jlen, &kzs, &c_b29, &c_b29, &wv[wv_offset] + , ldwv); + strmm_("R", "U", "N", "N", &jlen, &knz, &c_b15, &u[j2 + 1 + + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Multiply by U11 ==== */ + + sgemm_("N", "N", &jlen, &i2, &j2, &c_b15, &h__[jrow + ( + incol + 1) * h_dim1], ldh, &u[u_offset], ldu, & + c_b15, &wv[wv_offset], ldwv) + ; + +/* ==== Copy left of H to right of scratch ==== */ + + slacpy_("ALL", &jlen, &j2, &h__[jrow + (incol + 1) * + h_dim1], ldh, &wv[(i2 + 1) * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U21 ==== */ + + i__5 = i4 - i2; + strmm_("R", "L", "N", "N", &jlen, &i__5, &c_b15, &u[(i2 + + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * wv_dim1 + 1] + , ldwv); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + sgemm_("N", "N", &jlen, &i__5, &i__7, &c_b15, &h__[jrow + + (incol + 1 + j2) * h_dim1], ldh, &u[j2 + 1 + (i2 + + 1) * u_dim1], ldu, &c_b15, &wv[(i2 + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Copy it back ==== */ + + slacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, &h__[ + jrow + (incol + 1) * h_dim1], ldh); +/* L200: */ + } + +/* ==== Multiply Z (also vertical) ==== */ + + if (*wantz) { + i__4 = *ihiz; + i__3 = *nv; + for (jrow = *iloz; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; + jrow += i__3) { +/* Computing MIN */ + i__5 = *nv, i__7 = *ihiz - jrow + 1; + jlen = min(i__5,i__7); + +/* + ==== Copy right of Z to left of scratch (first + . KZS columns get multiplied by zero) ==== +*/ + + slacpy_("ALL", &jlen, &knz, &z__[jrow + (incol + 1 + + j2) * z_dim1], ldz, &wv[(kzs + 1) * wv_dim1 + + 1], ldwv); + +/* ==== Multiply by U12 ==== */ + + slaset_("ALL", &jlen, &kzs, &c_b29, &c_b29, &wv[ + wv_offset], ldwv); + strmm_("R", "U", "N", "N", &jlen, &knz, &c_b15, &u[j2 + + 1 + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) + * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U11 ==== */ + + sgemm_("N", "N", &jlen, &i2, &j2, &c_b15, &z__[jrow + + (incol + 1) * z_dim1], ldz, &u[u_offset], ldu, + &c_b15, &wv[wv_offset], ldwv); + +/* ==== Copy left of Z to right of scratch ==== */ + + slacpy_("ALL", &jlen, &j2, &z__[jrow + (incol + 1) * + z_dim1], ldz, &wv[(i2 + 1) * wv_dim1 + 1], + ldwv); + +/* ==== Multiply by U21 ==== */ + + i__5 = i4 - i2; + strmm_("R", "L", "N", "N", &jlen, &i__5, &c_b15, &u[( + i2 + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + sgemm_("N", "N", &jlen, &i__5, &i__7, &c_b15, &z__[ + jrow + (incol + 1 + j2) * z_dim1], ldz, &u[j2 + + 1 + (i2 + 1) * u_dim1], ldu, &c_b15, &wv[( + i2 + 1) * wv_dim1 + 1], ldwv); + +/* ==== Copy the result back to Z ==== */ + + slacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, & + z__[jrow + (incol + 1) * z_dim1], ldz); +/* L210: */ + } + } + } + } +/* L220: */ + } + +/* ==== End of SLAQR5 ==== */ + + return 0; +} /* slaqr5_ */ + +/* Subroutine */ int slarf_(char *side, integer *m, integer *n, real *v, + integer *incv, real *tau, real *c__, integer *ldc, real *work) +{ + /* System generated locals */ + integer c_dim1, c_offset; + real r__1; + + /* Local variables */ + static integer i__; + static logical applyleft; + extern /* Subroutine */ int sger_(integer *, integer *, real *, real *, + integer *, real *, integer *, real *, integer *); + extern logical lsame_(char *, char *); + static integer lastc; + extern /* Subroutine */ int sgemv_(char *, integer *, integer *, real *, + real *, integer *, real *, integer *, real *, real *, integer *); + static integer lastv; + extern integer ilaslc_(integer *, integer *, real *, integer *), ilaslr_( + integer *, integer *, real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLARF applies a real elementary reflector H to a real m by n matrix + C, from either the left or the right. H is represented in the form + + H = I - tau * v * v' + + where tau is a real scalar and v is a real vector. + + If tau = 0, then H is taken to be the unit matrix. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': form H * C + = 'R': form C * H + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + V (input) REAL array, dimension + (1 + (M-1)*abs(INCV)) if SIDE = 'L' + or (1 + (N-1)*abs(INCV)) if SIDE = 'R' + The vector v in the representation of H. V is not used if + TAU = 0. + + INCV (input) INTEGER + The increment between elements of v. INCV <> 0. + + TAU (input) REAL + The value tau in the representation of H. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by the matrix H * C if SIDE = 'L', + or C * H if SIDE = 'R'. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) REAL array, dimension + (N) if SIDE = 'L' + or (M) if SIDE = 'R' + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --v; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + applyleft = lsame_(side, "L"); + lastv = 0; + lastc = 0; + if (*tau != 0.f) { +/* + Set up variables for scanning V. LASTV begins pointing to the end + of V. +*/ + if (applyleft) { + lastv = *m; + } else { + lastv = *n; + } + if (*incv > 0) { + i__ = (lastv - 1) * *incv + 1; + } else { + i__ = 1; + } +/* Look for the last non-zero row in V. */ + while(lastv > 0 && v[i__] == 0.f) { + --lastv; + i__ -= *incv; + } + if (applyleft) { +/* Scan for the last non-zero column in C(1:lastv,:). */ + lastc = ilaslc_(&lastv, n, &c__[c_offset], ldc); + } else { +/* Scan for the last non-zero row in C(:,1:lastv). */ + lastc = ilaslr_(m, &lastv, &c__[c_offset], ldc); + } + } +/* + Note that lastc.eq.0 renders the BLAS operations null; no special + case is needed at this level. +*/ + if (applyleft) { + +/* Form H * C */ + + if (lastv > 0) { + +/* w(1:lastc,1) := C(1:lastv,1:lastc)' * v(1:lastv,1) */ + + sgemv_("Transpose", &lastv, &lastc, &c_b15, &c__[c_offset], ldc, & + v[1], incv, &c_b29, &work[1], &c__1); + +/* C(1:lastv,1:lastc) := C(...) - v(1:lastv,1) * w(1:lastc,1)' */ + + r__1 = -(*tau); + sger_(&lastv, &lastc, &r__1, &v[1], incv, &work[1], &c__1, &c__[ + c_offset], ldc); + } + } else { + +/* Form C * H */ + + if (lastv > 0) { + +/* w(1:lastc,1) := C(1:lastc,1:lastv) * v(1:lastv,1) */ + + sgemv_("No transpose", &lastc, &lastv, &c_b15, &c__[c_offset], + ldc, &v[1], incv, &c_b29, &work[1], &c__1); + +/* C(1:lastc,1:lastv) := C(...) - w(1:lastc,1) * v(1:lastv,1)' */ + + r__1 = -(*tau); + sger_(&lastc, &lastv, &r__1, &work[1], &c__1, &v[1], incv, &c__[ + c_offset], ldc); + } + } + return 0; + +/* End of SLARF */ + +} /* slarf_ */ + +/* Subroutine */ int slarfb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, real *v, integer *ldv, + real *t, integer *ldt, real *c__, integer *ldc, real *work, integer * + ldwork) +{ + /* System generated locals */ + integer c_dim1, c_offset, t_dim1, t_offset, v_dim1, v_offset, work_dim1, + work_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + static integer lastc; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static integer lastv; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *), strmm_(char *, char *, char *, char *, integer *, + integer *, real *, real *, integer *, real *, integer *); + extern integer ilaslc_(integer *, integer *, real *, integer *), ilaslr_( + integer *, integer *, real *, integer *); + static char transt[1]; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLARFB applies a real block reflector H or its transpose H' to a + real m by n matrix C, from either the left or the right. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply H or H' from the Left + = 'R': apply H or H' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply H (No transpose) + = 'T': apply H' (Transpose) + + DIRECT (input) CHARACTER*1 + Indicates how H is formed from a product of elementary + reflectors + = 'F': H = H(1) H(2) . . . H(k) (Forward) + = 'B': H = H(k) . . . H(2) H(1) (Backward) + + STOREV (input) CHARACTER*1 + Indicates how the vectors which define the elementary + reflectors are stored: + = 'C': Columnwise + = 'R': Rowwise + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + K (input) INTEGER + The order of the matrix T (= the number of elementary + reflectors whose product defines the block reflector). + + V (input) REAL array, dimension + (LDV,K) if STOREV = 'C' + (LDV,M) if STOREV = 'R' and SIDE = 'L' + (LDV,N) if STOREV = 'R' and SIDE = 'R' + The matrix V. See further details. + + LDV (input) INTEGER + The leading dimension of the array V. + If STOREV = 'C' and SIDE = 'L', LDV >= max(1,M); + if STOREV = 'C' and SIDE = 'R', LDV >= max(1,N); + if STOREV = 'R', LDV >= K. + + T (input) REAL array, dimension (LDT,K) + The triangular k by k matrix T in the representation of the + block reflector. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= K. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by H*C or H'*C or C*H or C*H'. + + LDC (input) INTEGER + The leading dimension of the array C. LDA >= max(1,M). + + WORK (workspace) REAL array, dimension (LDWORK,K) + + LDWORK (input) INTEGER + The leading dimension of the array WORK. + If SIDE = 'L', LDWORK >= max(1,N); + if SIDE = 'R', LDWORK >= max(1,M). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + work_dim1 = *ldwork; + work_offset = 1 + work_dim1; + work -= work_offset; + + /* Function Body */ + if (*m <= 0 || *n <= 0) { + return 0; + } + + if (lsame_(trans, "N")) { + *(unsigned char *)transt = 'T'; + } else { + *(unsigned char *)transt = 'N'; + } + + if (lsame_(storev, "C")) { + + if (lsame_(direct, "F")) { + +/* + Let V = ( V1 ) (first K rows) + ( V2 ) + where V1 is unit lower triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaslr_(m, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaslc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK) + + W := C1' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + scopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 + + 1], &c__1); +/* L10: */ + } + +/* W := W * V1 */ + + strmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2'*V2 */ + + i__1 = lastv - *k; + sgemm_("Transpose", "No transpose", &lastc, k, &i__1, & + c_b15, &c__[*k + 1 + c_dim1], ldc, &v[*k + 1 + + v_dim1], ldv, &c_b15, &work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + strmm_("Right", "Upper", transt, "Non-unit", &lastc, k, & + c_b15, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V * W' */ + + if (lastv > *k) { + +/* C2 := C2 - V2 * W' */ + + i__1 = lastv - *k; + sgemm_("No transpose", "Transpose", &i__1, &lastc, k, & + c_b151, &v[*k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork, &c_b15, &c__[*k + 1 + + c_dim1], ldc); + } + +/* W := W * V1' */ + + strmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[j + i__ * c_dim1] -= work[i__ + j * work_dim1]; +/* L20: */ + } +/* L30: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaslr_(n, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaslr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V = (C1*V1 + C2*V2) (stored in WORK) + + W := C1 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + scopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * + work_dim1 + 1], &c__1); +/* L40: */ + } + +/* W := W * V1 */ + + strmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2 * V2 */ + + i__1 = lastv - *k; + sgemm_("No transpose", "No transpose", &lastc, k, &i__1, & + c_b15, &c__[(*k + 1) * c_dim1 + 1], ldc, &v[*k + + 1 + v_dim1], ldv, &c_b15, &work[work_offset], + ldwork); + } + +/* W := W * T or W * T' */ + + strmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b15, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V' */ + + if (lastv > *k) { + +/* C2 := C2 - W * V2' */ + + i__1 = lastv - *k; + sgemm_("No transpose", "Transpose", &lastc, &i__1, k, & + c_b151, &work[work_offset], ldwork, &v[*k + 1 + + v_dim1], ldv, &c_b15, &c__[(*k + 1) * c_dim1 + 1], + ldc); + } + +/* W := W * V1' */ + + strmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] -= work[i__ + j * work_dim1]; +/* L50: */ + } +/* L60: */ + } + } + + } else { + +/* + Let V = ( V1 ) + ( V2 ) (last K rows) + where V2 is unit upper triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaslr_(m, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaslc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK) + + W := C2' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + scopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[ + j * work_dim1 + 1], &c__1); +/* L70: */ + } + +/* W := W * V2 */ + + strmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b15, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1'*V1 */ + + i__1 = lastv - *k; + sgemm_("Transpose", "No transpose", &lastc, k, &i__1, & + c_b15, &c__[c_offset], ldc, &v[v_offset], ldv, & + c_b15, &work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + strmm_("Right", "Lower", transt, "Non-unit", &lastc, k, & + c_b15, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V * W' */ + + if (lastv > *k) { + +/* C1 := C1 - V1 * W' */ + + i__1 = lastv - *k; + sgemm_("No transpose", "Transpose", &i__1, &lastc, k, & + c_b151, &v[v_offset], ldv, &work[work_offset], + ldwork, &c_b15, &c__[c_offset], ldc); + } + +/* W := W * V2' */ + + strmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, & + c_b15, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + +/* C2 := C2 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[lastv - *k + j + i__ * c_dim1] -= work[i__ + j * + work_dim1]; +/* L80: */ + } +/* L90: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaslr_(n, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaslr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V = (C1*V1 + C2*V2) (stored in WORK) + + W := C2 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + scopy_(&lastc, &c__[(*n - *k + j) * c_dim1 + 1], &c__1, & + work[j * work_dim1 + 1], &c__1); +/* L100: */ + } + +/* W := W * V2 */ + + strmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b15, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1 * V1 */ + + i__1 = lastv - *k; + sgemm_("No transpose", "No transpose", &lastc, k, &i__1, & + c_b15, &c__[c_offset], ldc, &v[v_offset], ldv, & + c_b15, &work[work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + strmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b15, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V' */ + + if (lastv > *k) { + +/* C1 := C1 - W * V1' */ + + i__1 = lastv - *k; + sgemm_("No transpose", "Transpose", &lastc, &i__1, k, & + c_b151, &work[work_offset], ldwork, &v[v_offset], + ldv, &c_b15, &c__[c_offset], ldc); + } + +/* W := W * V2' */ + + strmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, & + c_b15, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + +/* C2 := C2 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + (lastv - *k + j) * c_dim1] -= work[i__ + j * + work_dim1]; +/* L110: */ + } +/* L120: */ + } + } + } + + } else if (lsame_(storev, "R")) { + + if (lsame_(direct, "F")) { + +/* + Let V = ( V1 V2 ) (V1: first K columns) + where V1 is unit upper triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaslc_(k, m, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaslc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK) + + W := C1' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + scopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 + + 1], &c__1); +/* L130: */ + } + +/* W := W * V1' */ + + strmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2'*V2' */ + + i__1 = lastv - *k; + sgemm_("Transpose", "Transpose", &lastc, k, &i__1, &c_b15, + &c__[*k + 1 + c_dim1], ldc, &v[(*k + 1) * v_dim1 + + 1], ldv, &c_b15, &work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + strmm_("Right", "Upper", transt, "Non-unit", &lastc, k, & + c_b15, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V' * W' */ + + if (lastv > *k) { + +/* C2 := C2 - V2' * W' */ + + i__1 = lastv - *k; + sgemm_("Transpose", "Transpose", &i__1, &lastc, k, & + c_b151, &v[(*k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork, &c_b15, &c__[*k + 1 + + c_dim1], ldc); + } + +/* W := W * V1 */ + + strmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[j + i__ * c_dim1] -= work[i__ + j * work_dim1]; +/* L140: */ + } +/* L150: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaslc_(k, n, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaslr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V' = (C1*V1' + C2*V2') (stored in WORK) + + W := C1 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + scopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * + work_dim1 + 1], &c__1); +/* L160: */ + } + +/* W := W * V1' */ + + strmm_("Right", "Upper", "Transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2 * V2' */ + + i__1 = lastv - *k; + sgemm_("No transpose", "Transpose", &lastc, k, &i__1, & + c_b15, &c__[(*k + 1) * c_dim1 + 1], ldc, &v[(*k + + 1) * v_dim1 + 1], ldv, &c_b15, &work[work_offset], + ldwork); + } + +/* W := W * T or W * T' */ + + strmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b15, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V */ + + if (lastv > *k) { + +/* C2 := C2 - W * V2 */ + + i__1 = lastv - *k; + sgemm_("No transpose", "No transpose", &lastc, &i__1, k, & + c_b151, &work[work_offset], ldwork, &v[(*k + 1) * + v_dim1 + 1], ldv, &c_b15, &c__[(*k + 1) * c_dim1 + + 1], ldc); + } + +/* W := W * V1 */ + + strmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b15, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] -= work[i__ + j * work_dim1]; +/* L170: */ + } +/* L180: */ + } + + } + + } else { + +/* + Let V = ( V1 V2 ) (V2: last K columns) + where V2 is unit lower triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaslc_(k, m, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaslc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK) + + W := C2' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + scopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[ + j * work_dim1 + 1], &c__1); +/* L190: */ + } + +/* W := W * V2' */ + + strmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, & + c_b15, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1'*V1' */ + + i__1 = lastv - *k; + sgemm_("Transpose", "Transpose", &lastc, k, &i__1, &c_b15, + &c__[c_offset], ldc, &v[v_offset], ldv, &c_b15, & + work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + strmm_("Right", "Lower", transt, "Non-unit", &lastc, k, & + c_b15, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V' * W' */ + + if (lastv > *k) { + +/* C1 := C1 - V1' * W' */ + + i__1 = lastv - *k; + sgemm_("Transpose", "Transpose", &i__1, &lastc, k, & + c_b151, &v[v_offset], ldv, &work[work_offset], + ldwork, &c_b15, &c__[c_offset], ldc); + } + +/* W := W * V2 */ + + strmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b15, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + +/* C2 := C2 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[lastv - *k + j + i__ * c_dim1] -= work[i__ + j * + work_dim1]; +/* L200: */ + } +/* L210: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilaslc_(k, n, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilaslr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V' = (C1*V1' + C2*V2') (stored in WORK) + + W := C2 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + scopy_(&lastc, &c__[(lastv - *k + j) * c_dim1 + 1], &c__1, + &work[j * work_dim1 + 1], &c__1); +/* L220: */ + } + +/* W := W * V2' */ + + strmm_("Right", "Lower", "Transpose", "Unit", &lastc, k, & + c_b15, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1 * V1' */ + + i__1 = lastv - *k; + sgemm_("No transpose", "Transpose", &lastc, k, &i__1, & + c_b15, &c__[c_offset], ldc, &v[v_offset], ldv, & + c_b15, &work[work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + strmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b15, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V */ + + if (lastv > *k) { + +/* C1 := C1 - W * V1 */ + + i__1 = lastv - *k; + sgemm_("No transpose", "No transpose", &lastc, &i__1, k, & + c_b151, &work[work_offset], ldwork, &v[v_offset], + ldv, &c_b15, &c__[c_offset], ldc); + } + +/* W := W * V2 */ + + strmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b15, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + (lastv - *k + j) * c_dim1] -= work[i__ + j * + work_dim1]; +/* L230: */ + } +/* L240: */ + } + + } + + } + } + + return 0; + +/* End of SLARFB */ + +} /* slarfb_ */ + +/* Subroutine */ int slarfg_(integer *n, real *alpha, real *x, integer *incx, + real *tau) +{ + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + static integer j, knt; + static real beta; + extern doublereal snrm2_(integer *, real *, integer *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + static real xnorm; + extern doublereal slapy2_(real *, real *), slamch_(char *); + static real safmin, rsafmn; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLARFG generates a real elementary reflector H of order n, such + that + + H * ( alpha ) = ( beta ), H' * H = I. + ( x ) ( 0 ) + + where alpha and beta are scalars, and x is an (n-1)-element real + vector. H is represented in the form + + H = I - tau * ( 1 ) * ( 1 v' ) , + ( v ) + + where tau is a real scalar and v is a real (n-1)-element + vector. + + If the elements of x are all zero, then tau = 0 and H is taken to be + the unit matrix. + + Otherwise 1 <= tau <= 2. + + Arguments + ========= + + N (input) INTEGER + The order of the elementary reflector. + + ALPHA (input/output) REAL + On entry, the value alpha. + On exit, it is overwritten with the value beta. + + X (input/output) REAL array, dimension + (1+(N-2)*abs(INCX)) + On entry, the vector x. + On exit, it is overwritten with the vector v. + + INCX (input) INTEGER + The increment between elements of X. INCX > 0. + + TAU (output) REAL + The value tau. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n <= 1) { + *tau = 0.f; + return 0; + } + + i__1 = *n - 1; + xnorm = snrm2_(&i__1, &x[1], incx); + + if (xnorm == 0.f) { + +/* H = I */ + + *tau = 0.f; + } else { + +/* general case */ + + r__1 = slapy2_(alpha, &xnorm); + beta = -r_sign(&r__1, alpha); + safmin = slamch_("S") / slamch_("E"); + knt = 0; + if (dabs(beta) < safmin) { + +/* XNORM, BETA may be inaccurate; scale X and recompute them */ + + rsafmn = 1.f / safmin; +L10: + ++knt; + i__1 = *n - 1; + sscal_(&i__1, &rsafmn, &x[1], incx); + beta *= rsafmn; + *alpha *= rsafmn; + if (dabs(beta) < safmin) { + goto L10; + } + +/* New BETA is at most 1, at least SAFMIN */ + + i__1 = *n - 1; + xnorm = snrm2_(&i__1, &x[1], incx); + r__1 = slapy2_(alpha, &xnorm); + beta = -r_sign(&r__1, alpha); + } + *tau = (beta - *alpha) / beta; + i__1 = *n - 1; + r__1 = 1.f / (*alpha - beta); + sscal_(&i__1, &r__1, &x[1], incx); + +/* If ALPHA is subnormal, it may lose relative accuracy */ + + i__1 = knt; + for (j = 1; j <= i__1; ++j) { + beta *= safmin; +/* L20: */ + } + *alpha = beta; + } + + return 0; + +/* End of SLARFG */ + +} /* slarfg_ */ + +/* Subroutine */ int slarft_(char *direct, char *storev, integer *n, integer * + k, real *v, integer *ldv, real *tau, real *t, integer *ldt) +{ + /* System generated locals */ + integer t_dim1, t_offset, v_dim1, v_offset, i__1, i__2, i__3; + real r__1; + + /* Local variables */ + static integer i__, j, prevlastv; + static real vii; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sgemv_(char *, integer *, integer *, real *, + real *, integer *, real *, integer *, real *, real *, integer *); + static integer lastv; + extern /* Subroutine */ int strmv_(char *, char *, char *, integer *, + real *, integer *, real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLARFT forms the triangular factor T of a real block reflector H + of order n, which is defined as a product of k elementary reflectors. + + If DIRECT = 'F', H = H(1) H(2) . . . H(k) and T is upper triangular; + + If DIRECT = 'B', H = H(k) . . . H(2) H(1) and T is lower triangular. + + If STOREV = 'C', the vector which defines the elementary reflector + H(i) is stored in the i-th column of the array V, and + + H = I - V * T * V' + + If STOREV = 'R', the vector which defines the elementary reflector + H(i) is stored in the i-th row of the array V, and + + H = I - V' * T * V + + Arguments + ========= + + DIRECT (input) CHARACTER*1 + Specifies the order in which the elementary reflectors are + multiplied to form the block reflector: + = 'F': H = H(1) H(2) . . . H(k) (Forward) + = 'B': H = H(k) . . . H(2) H(1) (Backward) + + STOREV (input) CHARACTER*1 + Specifies how the vectors which define the elementary + reflectors are stored (see also Further Details): + = 'C': columnwise + = 'R': rowwise + + N (input) INTEGER + The order of the block reflector H. N >= 0. + + K (input) INTEGER + The order of the triangular factor T (= the number of + elementary reflectors). K >= 1. + + V (input/output) REAL array, dimension + (LDV,K) if STOREV = 'C' + (LDV,N) if STOREV = 'R' + The matrix V. See further details. + + LDV (input) INTEGER + The leading dimension of the array V. + If STOREV = 'C', LDV >= max(1,N); if STOREV = 'R', LDV >= K. + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i). + + T (output) REAL array, dimension (LDT,K) + The k by k triangular factor T of the block reflector. + If DIRECT = 'F', T is upper triangular; if DIRECT = 'B', T is + lower triangular. The rest of the array is not used. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= K. + + Further Details + =============== + + The shape of the matrix V and the storage of the vectors which define + the H(i) is best illustrated by the following example with n = 5 and + k = 3. The elements equal to 1 are not stored; the corresponding + array elements are modified but restored on exit. The rest of the + array is not used. + + DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': + + V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) + ( v1 1 ) ( 1 v2 v2 v2 ) + ( v1 v2 1 ) ( 1 v3 v3 ) + ( v1 v2 v3 ) + ( v1 v2 v3 ) + + DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': + + V = ( v1 v2 v3 ) V = ( v1 v1 1 ) + ( v1 v2 v3 ) ( v2 v2 v2 1 ) + ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) + ( 1 v3 ) + ( 1 ) + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + --tau; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + + /* Function Body */ + if (*n == 0) { + return 0; + } + + if (lsame_(direct, "F")) { + prevlastv = *n; + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + prevlastv = max(i__,prevlastv); + if (tau[i__] == 0.f) { + +/* H(i) = I */ + + i__2 = i__; + for (j = 1; j <= i__2; ++j) { + t[j + i__ * t_dim1] = 0.f; +/* L10: */ + } + } else { + +/* general case */ + + vii = v[i__ + i__ * v_dim1]; + v[i__ + i__ * v_dim1] = 1.f; + if (lsame_(storev, "C")) { +/* Skip any trailing zeros. */ + i__2 = i__ + 1; + for (lastv = *n; lastv >= i__2; --lastv) { + if (v[lastv + i__ * v_dim1] != 0.f) { + goto L15; + } + } +L15: + j = min(lastv,prevlastv); + +/* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)' * V(i:j,i) */ + + i__2 = j - i__ + 1; + i__3 = i__ - 1; + r__1 = -tau[i__]; + sgemv_("Transpose", &i__2, &i__3, &r__1, &v[i__ + v_dim1], + ldv, &v[i__ + i__ * v_dim1], &c__1, &c_b29, &t[ + i__ * t_dim1 + 1], &c__1); + } else { +/* Skip any trailing zeros. */ + i__2 = i__ + 1; + for (lastv = *n; lastv >= i__2; --lastv) { + if (v[i__ + lastv * v_dim1] != 0.f) { + goto L16; + } + } +L16: + j = min(lastv,prevlastv); + +/* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)' */ + + i__2 = i__ - 1; + i__3 = j - i__ + 1; + r__1 = -tau[i__]; + sgemv_("No transpose", &i__2, &i__3, &r__1, &v[i__ * + v_dim1 + 1], ldv, &v[i__ + i__ * v_dim1], ldv, & + c_b29, &t[i__ * t_dim1 + 1], &c__1); + } + v[i__ + i__ * v_dim1] = vii; + +/* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */ + + i__2 = i__ - 1; + strmv_("Upper", "No transpose", "Non-unit", &i__2, &t[ + t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1); + t[i__ + i__ * t_dim1] = tau[i__]; + if (i__ > 1) { + prevlastv = max(prevlastv,lastv); + } else { + prevlastv = lastv; + } + } +/* L20: */ + } + } else { + prevlastv = 1; + for (i__ = *k; i__ >= 1; --i__) { + if (tau[i__] == 0.f) { + +/* H(i) = I */ + + i__1 = *k; + for (j = i__; j <= i__1; ++j) { + t[j + i__ * t_dim1] = 0.f; +/* L30: */ + } + } else { + +/* general case */ + + if (i__ < *k) { + if (lsame_(storev, "C")) { + vii = v[*n - *k + i__ + i__ * v_dim1]; + v[*n - *k + i__ + i__ * v_dim1] = 1.f; +/* Skip any leading zeros. */ + i__1 = i__ - 1; + for (lastv = 1; lastv <= i__1; ++lastv) { + if (v[lastv + i__ * v_dim1] != 0.f) { + goto L35; + } + } +L35: + j = max(lastv,prevlastv); + +/* + T(i+1:k,i) := + - tau(i) * V(j:n-k+i,i+1:k)' * V(j:n-k+i,i) +*/ + + i__1 = *n - *k + i__ - j + 1; + i__2 = *k - i__; + r__1 = -tau[i__]; + sgemv_("Transpose", &i__1, &i__2, &r__1, &v[j + (i__ + + 1) * v_dim1], ldv, &v[j + i__ * v_dim1], & + c__1, &c_b29, &t[i__ + 1 + i__ * t_dim1], & + c__1); + v[*n - *k + i__ + i__ * v_dim1] = vii; + } else { + vii = v[i__ + (*n - *k + i__) * v_dim1]; + v[i__ + (*n - *k + i__) * v_dim1] = 1.f; +/* Skip any leading zeros. */ + i__1 = i__ - 1; + for (lastv = 1; lastv <= i__1; ++lastv) { + if (v[i__ + lastv * v_dim1] != 0.f) { + goto L36; + } + } +L36: + j = max(lastv,prevlastv); + +/* + T(i+1:k,i) := + - tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)' +*/ + + i__1 = *k - i__; + i__2 = *n - *k + i__ - j + 1; + r__1 = -tau[i__]; + sgemv_("No transpose", &i__1, &i__2, &r__1, &v[i__ + + 1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], + ldv, &c_b29, &t[i__ + 1 + i__ * t_dim1], & + c__1); + v[i__ + (*n - *k + i__) * v_dim1] = vii; + } + +/* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */ + + i__1 = *k - i__; + strmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ + + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ * + t_dim1], &c__1) + ; + if (i__ > 1) { + prevlastv = min(prevlastv,lastv); + } else { + prevlastv = lastv; + } + } + t[i__ + i__ * t_dim1] = tau[i__]; + } +/* L40: */ + } + } + return 0; + +/* End of SLARFT */ + +} /* slarft_ */ + +/* Subroutine */ int slarfx_(char *side, integer *m, integer *n, real *v, + real *tau, real *c__, integer *ldc, real *work) +{ + /* System generated locals */ + integer c_dim1, c_offset, i__1; + + /* Local variables */ + static integer j; + static real t1, t2, t3, t4, t5, t6, t7, t8, t9, v1, v2, v3, v4, v5, v6, + v7, v8, v9, t10, v10, sum; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLARFX applies a real elementary reflector H to a real m by n + matrix C, from either the left or the right. H is represented in the + form + + H = I - tau * v * v' + + where tau is a real scalar and v is a real vector. + + If tau = 0, then H is taken to be the unit matrix + + This version uses inline code if H has order < 11. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': form H * C + = 'R': form C * H + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + V (input) REAL array, dimension (M) if SIDE = 'L' + or (N) if SIDE = 'R' + The vector v in the representation of H. + + TAU (input) REAL + The value tau in the representation of H. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by the matrix H * C if SIDE = 'L', + or C * H if SIDE = 'R'. + + LDC (input) INTEGER + The leading dimension of the array C. LDA >= (1,M). + + WORK (workspace) REAL array, dimension + (N) if SIDE = 'L' + or (M) if SIDE = 'R' + WORK is not referenced if H has order < 11. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --v; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + if (*tau == 0.f) { + return 0; + } + if (lsame_(side, "L")) { + +/* Form H * C, where H has order m. */ + + switch (*m) { + case 1: goto L10; + case 2: goto L30; + case 3: goto L50; + case 4: goto L70; + case 5: goto L90; + case 6: goto L110; + case 7: goto L130; + case 8: goto L150; + case 9: goto L170; + case 10: goto L190; + } + +/* Code for general M */ + + slarf_(side, m, n, &v[1], &c__1, tau, &c__[c_offset], ldc, &work[1]); + goto L410; +L10: + +/* Special code for 1 x 1 Householder */ + + t1 = 1.f - *tau * v[1] * v[1]; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + c__[j * c_dim1 + 1] = t1 * c__[j * c_dim1 + 1]; +/* L20: */ + } + goto L410; +L30: + +/* Special code for 2 x 2 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; +/* L40: */ + } + goto L410; +L50: + +/* Special code for 3 x 3 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; +/* L60: */ + } + goto L410; +L70: + +/* Special code for 4 x 4 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; +/* L80: */ + } + goto L410; +L90: + +/* Special code for 5 x 5 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; +/* L100: */ + } + goto L410; +L110: + +/* Special code for 6 x 6 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; +/* L120: */ + } + goto L410; +L130: + +/* Special code for 7 x 7 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * + c_dim1 + 7]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; + c__[j * c_dim1 + 7] -= sum * t7; +/* L140: */ + } + goto L410; +L150: + +/* Special code for 8 x 8 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * + c_dim1 + 7] + v8 * c__[j * c_dim1 + 8]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; + c__[j * c_dim1 + 7] -= sum * t7; + c__[j * c_dim1 + 8] -= sum * t8; +/* L160: */ + } + goto L410; +L170: + +/* Special code for 9 x 9 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + v9 = v[9]; + t9 = *tau * v9; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * + c_dim1 + 7] + v8 * c__[j * c_dim1 + 8] + v9 * c__[j * + c_dim1 + 9]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; + c__[j * c_dim1 + 7] -= sum * t7; + c__[j * c_dim1 + 8] -= sum * t8; + c__[j * c_dim1 + 9] -= sum * t9; +/* L180: */ + } + goto L410; +L190: + +/* Special code for 10 x 10 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + v9 = v[9]; + t9 = *tau * v9; + v10 = v[10]; + t10 = *tau * v10; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j * c_dim1 + 1] + v2 * c__[j * c_dim1 + 2] + v3 * + c__[j * c_dim1 + 3] + v4 * c__[j * c_dim1 + 4] + v5 * c__[ + j * c_dim1 + 5] + v6 * c__[j * c_dim1 + 6] + v7 * c__[j * + c_dim1 + 7] + v8 * c__[j * c_dim1 + 8] + v9 * c__[j * + c_dim1 + 9] + v10 * c__[j * c_dim1 + 10]; + c__[j * c_dim1 + 1] -= sum * t1; + c__[j * c_dim1 + 2] -= sum * t2; + c__[j * c_dim1 + 3] -= sum * t3; + c__[j * c_dim1 + 4] -= sum * t4; + c__[j * c_dim1 + 5] -= sum * t5; + c__[j * c_dim1 + 6] -= sum * t6; + c__[j * c_dim1 + 7] -= sum * t7; + c__[j * c_dim1 + 8] -= sum * t8; + c__[j * c_dim1 + 9] -= sum * t9; + c__[j * c_dim1 + 10] -= sum * t10; +/* L200: */ + } + goto L410; + } else { + +/* Form C * H, where H has order n. */ + + switch (*n) { + case 1: goto L210; + case 2: goto L230; + case 3: goto L250; + case 4: goto L270; + case 5: goto L290; + case 6: goto L310; + case 7: goto L330; + case 8: goto L350; + case 9: goto L370; + case 10: goto L390; + } + +/* Code for general N */ + + slarf_(side, m, n, &v[1], &c__1, tau, &c__[c_offset], ldc, &work[1]); + goto L410; +L210: + +/* Special code for 1 x 1 Householder */ + + t1 = 1.f - *tau * v[1] * v[1]; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + c__[j + c_dim1] = t1 * c__[j + c_dim1]; +/* L220: */ + } + goto L410; +L230: + +/* Special code for 2 x 2 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; +/* L240: */ + } + goto L410; +L250: + +/* Special code for 3 x 3 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; +/* L260: */ + } + goto L410; +L270: + +/* Special code for 4 x 4 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; +/* L280: */ + } + goto L410; +L290: + +/* Special code for 5 x 5 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; +/* L300: */ + } + goto L410; +L310: + +/* Special code for 6 x 6 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; +/* L320: */ + } + goto L410; +L330: + +/* Special code for 7 x 7 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[ + j + c_dim1 * 7]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; + c__[j + c_dim1 * 7] -= sum * t7; +/* L340: */ + } + goto L410; +L350: + +/* Special code for 8 x 8 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[ + j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; + c__[j + c_dim1 * 7] -= sum * t7; + c__[j + (c_dim1 << 3)] -= sum * t8; +/* L360: */ + } + goto L410; +L370: + +/* Special code for 9 x 9 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + v9 = v[9]; + t9 = *tau * v9; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[ + j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)] + v9 * c__[ + j + c_dim1 * 9]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; + c__[j + c_dim1 * 7] -= sum * t7; + c__[j + (c_dim1 << 3)] -= sum * t8; + c__[j + c_dim1 * 9] -= sum * t9; +/* L380: */ + } + goto L410; +L390: + +/* Special code for 10 x 10 Householder */ + + v1 = v[1]; + t1 = *tau * v1; + v2 = v[2]; + t2 = *tau * v2; + v3 = v[3]; + t3 = *tau * v3; + v4 = v[4]; + t4 = *tau * v4; + v5 = v[5]; + t5 = *tau * v5; + v6 = v[6]; + t6 = *tau * v6; + v7 = v[7]; + t7 = *tau * v7; + v8 = v[8]; + t8 = *tau * v8; + v9 = v[9]; + t9 = *tau * v9; + v10 = v[10]; + t10 = *tau * v10; + i__1 = *m; + for (j = 1; j <= i__1; ++j) { + sum = v1 * c__[j + c_dim1] + v2 * c__[j + (c_dim1 << 1)] + v3 * + c__[j + c_dim1 * 3] + v4 * c__[j + (c_dim1 << 2)] + v5 * + c__[j + c_dim1 * 5] + v6 * c__[j + c_dim1 * 6] + v7 * c__[ + j + c_dim1 * 7] + v8 * c__[j + (c_dim1 << 3)] + v9 * c__[ + j + c_dim1 * 9] + v10 * c__[j + c_dim1 * 10]; + c__[j + c_dim1] -= sum * t1; + c__[j + (c_dim1 << 1)] -= sum * t2; + c__[j + c_dim1 * 3] -= sum * t3; + c__[j + (c_dim1 << 2)] -= sum * t4; + c__[j + c_dim1 * 5] -= sum * t5; + c__[j + c_dim1 * 6] -= sum * t6; + c__[j + c_dim1 * 7] -= sum * t7; + c__[j + (c_dim1 << 3)] -= sum * t8; + c__[j + c_dim1 * 9] -= sum * t9; + c__[j + c_dim1 * 10] -= sum * t10; +/* L400: */ + } + goto L410; + } +L410: + return 0; + +/* End of SLARFX */ + +} /* slarfx_ */ + +/* Subroutine */ int slartg_(real *f, real *g, real *cs, real *sn, real *r__) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2; + + /* Local variables */ + static integer i__; + static real f1, g1, eps, scale; + static integer count; + static real safmn2, safmx2; + extern doublereal slamch_(char *); + static real safmin; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLARTG generate a plane rotation so that + + [ CS SN ] . [ F ] = [ R ] where CS**2 + SN**2 = 1. + [ -SN CS ] [ G ] [ 0 ] + + This is a slower, more accurate version of the BLAS1 routine SROTG, + with the following other differences: + F and G are unchanged on return. + If G=0, then CS=1 and SN=0. + If F=0 and (G .ne. 0), then CS=0 and SN=1 without doing any + floating point operations (saves work in SBDSQR when + there are zeros on the diagonal). + + If F exceeds G in magnitude, CS will be positive. + + Arguments + ========= + + F (input) REAL + The first component of vector to be rotated. + + G (input) REAL + The second component of vector to be rotated. + + CS (output) REAL + The cosine of the rotation. + + SN (output) REAL + The sine of the rotation. + + R (output) REAL + The nonzero component of the rotated vector. + + This version has a few statements commented out for thread safety + (machine parameters are computed on each entry). 10 feb 03, SJH. + + ===================================================================== + + LOGICAL FIRST + SAVE FIRST, SAFMX2, SAFMIN, SAFMN2 + DATA FIRST / .TRUE. / + + IF( FIRST ) THEN +*/ + safmin = slamch_("S"); + eps = slamch_("E"); + r__1 = slamch_("B"); + i__1 = (integer) (log(safmin / eps) / log(slamch_("B")) / 2.f); + safmn2 = pow_ri(&r__1, &i__1); + safmx2 = 1.f / safmn2; +/* + FIRST = .FALSE. + END IF +*/ + if (*g == 0.f) { + *cs = 1.f; + *sn = 0.f; + *r__ = *f; + } else if (*f == 0.f) { + *cs = 0.f; + *sn = 1.f; + *r__ = *g; + } else { + f1 = *f; + g1 = *g; +/* Computing MAX */ + r__1 = dabs(f1), r__2 = dabs(g1); + scale = dmax(r__1,r__2); + if (scale >= safmx2) { + count = 0; +L10: + ++count; + f1 *= safmn2; + g1 *= safmn2; +/* Computing MAX */ + r__1 = dabs(f1), r__2 = dabs(g1); + scale = dmax(r__1,r__2); + if (scale >= safmx2) { + goto L10; + } +/* Computing 2nd power */ + r__1 = f1; +/* Computing 2nd power */ + r__2 = g1; + *r__ = sqrt(r__1 * r__1 + r__2 * r__2); + *cs = f1 / *r__; + *sn = g1 / *r__; + i__1 = count; + for (i__ = 1; i__ <= i__1; ++i__) { + *r__ *= safmx2; +/* L20: */ + } + } else if (scale <= safmn2) { + count = 0; +L30: + ++count; + f1 *= safmx2; + g1 *= safmx2; +/* Computing MAX */ + r__1 = dabs(f1), r__2 = dabs(g1); + scale = dmax(r__1,r__2); + if (scale <= safmn2) { + goto L30; + } +/* Computing 2nd power */ + r__1 = f1; +/* Computing 2nd power */ + r__2 = g1; + *r__ = sqrt(r__1 * r__1 + r__2 * r__2); + *cs = f1 / *r__; + *sn = g1 / *r__; + i__1 = count; + for (i__ = 1; i__ <= i__1; ++i__) { + *r__ *= safmn2; +/* L40: */ + } + } else { +/* Computing 2nd power */ + r__1 = f1; +/* Computing 2nd power */ + r__2 = g1; + *r__ = sqrt(r__1 * r__1 + r__2 * r__2); + *cs = f1 / *r__; + *sn = g1 / *r__; + } + if (dabs(*f) > dabs(*g) && *cs < 0.f) { + *cs = -(*cs); + *sn = -(*sn); + *r__ = -(*r__); + } + } + return 0; + +/* End of SLARTG */ + +} /* slartg_ */ + +/* Subroutine */ int slas2_(real *f, real *g, real *h__, real *ssmin, real * + ssmax) +{ + /* System generated locals */ + real r__1, r__2; + + /* Local variables */ + static real c__, fa, ga, ha, as, at, au, fhmn, fhmx; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAS2 computes the singular values of the 2-by-2 matrix + [ F G ] + [ 0 H ]. + On return, SSMIN is the smaller singular value and SSMAX is the + larger singular value. + + Arguments + ========= + + F (input) REAL + The (1,1) element of the 2-by-2 matrix. + + G (input) REAL + The (1,2) element of the 2-by-2 matrix. + + H (input) REAL + The (2,2) element of the 2-by-2 matrix. + + SSMIN (output) REAL + The smaller singular value. + + SSMAX (output) REAL + The larger singular value. + + Further Details + =============== + + Barring over/underflow, all output quantities are correct to within + a few units in the last place (ulps), even in the absence of a guard + digit in addition/subtraction. + + In IEEE arithmetic, the code works correctly if one matrix element is + infinite. + + Overflow will not occur unless the largest singular value itself + overflows, or is within a few ulps of overflow. (On machines with + partial overflow, like the Cray, overflow may occur if the largest + singular value is within a factor of 2 of overflow.) + + Underflow is harmless if underflow is gradual. Otherwise, results + may correspond to a matrix modified by perturbations of size near + the underflow threshold. + + ==================================================================== +*/ + + + fa = dabs(*f); + ga = dabs(*g); + ha = dabs(*h__); + fhmn = dmin(fa,ha); + fhmx = dmax(fa,ha); + if (fhmn == 0.f) { + *ssmin = 0.f; + if (fhmx == 0.f) { + *ssmax = ga; + } else { +/* Computing 2nd power */ + r__1 = dmin(fhmx,ga) / dmax(fhmx,ga); + *ssmax = dmax(fhmx,ga) * sqrt(r__1 * r__1 + 1.f); + } + } else { + if (ga < fhmx) { + as = fhmn / fhmx + 1.f; + at = (fhmx - fhmn) / fhmx; +/* Computing 2nd power */ + r__1 = ga / fhmx; + au = r__1 * r__1; + c__ = 2.f / (sqrt(as * as + au) + sqrt(at * at + au)); + *ssmin = fhmn * c__; + *ssmax = fhmx / c__; + } else { + au = fhmx / ga; + if (au == 0.f) { + +/* + Avoid possible harmful underflow if exponent range + asymmetric (true SSMIN may not underflow even if + AU underflows) +*/ + + *ssmin = fhmn * fhmx / ga; + *ssmax = ga; + } else { + as = fhmn / fhmx + 1.f; + at = (fhmx - fhmn) / fhmx; +/* Computing 2nd power */ + r__1 = as * au; +/* Computing 2nd power */ + r__2 = at * au; + c__ = 1.f / (sqrt(r__1 * r__1 + 1.f) + sqrt(r__2 * r__2 + 1.f) + ); + *ssmin = fhmn * c__ * au; + *ssmin += *ssmin; + *ssmax = ga / (c__ + c__); + } + } + } + return 0; + +/* End of SLAS2 */ + +} /* slas2_ */ + +/* Subroutine */ int slascl_(char *type__, integer *kl, integer *ku, real * + cfrom, real *cto, integer *m, integer *n, real *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + + /* Local variables */ + static integer i__, j, k1, k2, k3, k4; + static real mul, cto1; + static logical done; + static real ctoc; + extern logical lsame_(char *, char *); + static integer itype; + static real cfrom1; + extern doublereal slamch_(char *); + static real cfromc; + extern /* Subroutine */ int xerbla_(char *, integer *); + static real bignum; + extern logical sisnan_(real *); + static real smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASCL multiplies the M by N real matrix A by the real scalar + CTO/CFROM. This is done without over/underflow as long as the final + result CTO*A(I,J)/CFROM does not over/underflow. TYPE specifies that + A may be full, upper triangular, lower triangular, upper Hessenberg, + or banded. + + Arguments + ========= + + TYPE (input) CHARACTER*1 + TYPE indices the storage type of the input matrix. + = 'G': A is a full matrix. + = 'L': A is a lower triangular matrix. + = 'U': A is an upper triangular matrix. + = 'H': A is an upper Hessenberg matrix. + = 'B': A is a symmetric band matrix with lower bandwidth KL + and upper bandwidth KU and with the only the lower + half stored. + = 'Q': A is a symmetric band matrix with lower bandwidth KL + and upper bandwidth KU and with the only the upper + half stored. + = 'Z': A is a band matrix with lower bandwidth KL and upper + bandwidth KU. + + KL (input) INTEGER + The lower bandwidth of A. Referenced only if TYPE = 'B', + 'Q' or 'Z'. + + KU (input) INTEGER + The upper bandwidth of A. Referenced only if TYPE = 'B', + 'Q' or 'Z'. + + CFROM (input) REAL + CTO (input) REAL + The matrix A is multiplied by CTO/CFROM. A(I,J) is computed + without over/underflow if the final result CTO*A(I,J)/CFROM + can be represented without over/underflow. CFROM must be + nonzero. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + The matrix to be multiplied by CTO/CFROM. See TYPE for the + storage type. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + INFO (output) INTEGER + 0 - successful exit + <0 - if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + + if (lsame_(type__, "G")) { + itype = 0; + } else if (lsame_(type__, "L")) { + itype = 1; + } else if (lsame_(type__, "U")) { + itype = 2; + } else if (lsame_(type__, "H")) { + itype = 3; + } else if (lsame_(type__, "B")) { + itype = 4; + } else if (lsame_(type__, "Q")) { + itype = 5; + } else if (lsame_(type__, "Z")) { + itype = 6; + } else { + itype = -1; + } + + if (itype == -1) { + *info = -1; + } else if (*cfrom == 0.f || sisnan_(cfrom)) { + *info = -4; + } else if (sisnan_(cto)) { + *info = -5; + } else if (*m < 0) { + *info = -6; + } else if (*n < 0 || itype == 4 && *n != *m || itype == 5 && *n != *m) { + *info = -7; + } else if (itype <= 3 && *lda < max(1,*m)) { + *info = -9; + } else if (itype >= 4) { +/* Computing MAX */ + i__1 = *m - 1; + if (*kl < 0 || *kl > max(i__1,0)) { + *info = -2; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = *n - 1; + if (*ku < 0 || *ku > max(i__1,0) || (itype == 4 || itype == 5) && + *kl != *ku) { + *info = -3; + } else if (itype == 4 && *lda < *kl + 1 || itype == 5 && *lda < * + ku + 1 || itype == 6 && *lda < (*kl << 1) + *ku + 1) { + *info = -9; + } + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASCL", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *m == 0) { + return 0; + } + +/* Get machine parameters */ + + smlnum = slamch_("S"); + bignum = 1.f / smlnum; + + cfromc = *cfrom; + ctoc = *cto; + +L10: + cfrom1 = cfromc * smlnum; + if (cfrom1 == cfromc) { +/* + CFROMC is an inf. Multiply by a correctly signed zero for + finite CTOC, or a NaN if CTOC is infinite. +*/ + mul = ctoc / cfromc; + done = TRUE_; + cto1 = ctoc; + } else { + cto1 = ctoc / bignum; + if (cto1 == ctoc) { +/* + CTOC is either 0 or an inf. In both cases, CTOC itself + serves as the correct multiplication factor. +*/ + mul = ctoc; + done = TRUE_; + cfromc = 1.f; + } else if (dabs(cfrom1) > dabs(ctoc) && ctoc != 0.f) { + mul = smlnum; + done = FALSE_; + cfromc = cfrom1; + } else if (dabs(cto1) > dabs(cfromc)) { + mul = bignum; + done = FALSE_; + ctoc = cto1; + } else { + mul = ctoc / cfromc; + done = TRUE_; + } + } + + if (itype == 0) { + +/* Full matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L20: */ + } +/* L30: */ + } + + } else if (itype == 1) { + +/* Lower triangular matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L40: */ + } +/* L50: */ + } + + } else if (itype == 2) { + +/* Upper triangular matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L60: */ + } +/* L70: */ + } + + } else if (itype == 3) { + +/* Upper Hessenberg matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = j + 1; + i__2 = min(i__3,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L80: */ + } +/* L90: */ + } + + } else if (itype == 4) { + +/* Lower half of a symmetric band matrix */ + + k3 = *kl + 1; + k4 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = k3, i__4 = k4 - j; + i__2 = min(i__3,i__4); + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L100: */ + } +/* L110: */ + } + + } else if (itype == 5) { + +/* Upper half of a symmetric band matrix */ + + k1 = *ku + 2; + k3 = *ku + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = k1 - j; + i__3 = k3; + for (i__ = max(i__2,1); i__ <= i__3; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L120: */ + } +/* L130: */ + } + + } else if (itype == 6) { + +/* Band matrix */ + + k1 = *kl + *ku + 2; + k2 = *kl + 1; + k3 = (*kl << 1) + *ku + 1; + k4 = *kl + *ku + 1 + *m; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__3 = k1 - j; +/* Computing MIN */ + i__4 = k3, i__5 = k4 - j; + i__2 = min(i__4,i__5); + for (i__ = max(i__3,k2); i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] *= mul; +/* L140: */ + } +/* L150: */ + } + + } + + if (! done) { + goto L10; + } + + return 0; + +/* End of SLASCL */ + +} /* slascl_ */ + +/* Subroutine */ int slasd0_(integer *n, integer *sqre, real *d__, real *e, + real *u, integer *ldu, real *vt, integer *ldvt, integer *smlsiz, + integer *iwork, real *work, integer *info) +{ + /* System generated locals */ + integer u_dim1, u_offset, vt_dim1, vt_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, m, i1, ic, lf, nd, ll, nl, nr, im1, ncc, nlf, nrf, + iwk, lvl, ndb1, nlp1, nrp1; + static real beta; + static integer idxq, nlvl; + static real alpha; + static integer inode, ndiml, idxqc, ndimr, itemp, sqrei; + extern /* Subroutine */ int slasd1_(integer *, integer *, integer *, real + *, real *, real *, real *, integer *, real *, integer *, integer * + , integer *, real *, integer *), xerbla_(char *, integer *), slasdq_(char *, integer *, integer *, integer *, integer + *, integer *, real *, real *, real *, integer *, real *, integer * + , real *, integer *, real *, integer *), slasdt_(integer * + , integer *, integer *, integer *, integer *, integer *, integer * + ); + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + Using a divide and conquer approach, SLASD0 computes the singular + value decomposition (SVD) of a real upper bidiagonal N-by-M + matrix B with diagonal D and offdiagonal E, where M = N + SQRE. + The algorithm computes orthogonal matrices U and VT such that + B = U * S * VT. The singular values S are overwritten on D. + + A related subroutine, SLASDA, computes only the singular values, + and optionally, the singular vectors in compact form. + + Arguments + ========= + + N (input) INTEGER + On entry, the row dimension of the upper bidiagonal matrix. + This is also the dimension of the main diagonal array D. + + SQRE (input) INTEGER + Specifies the column dimension of the bidiagonal matrix. + = 0: The bidiagonal matrix has column dimension M = N; + = 1: The bidiagonal matrix has column dimension M = N+1; + + D (input/output) REAL array, dimension (N) + On entry D contains the main diagonal of the bidiagonal + matrix. + On exit D, if INFO = 0, contains its singular values. + + E (input) REAL array, dimension (M-1) + Contains the subdiagonal entries of the bidiagonal matrix. + On exit, E has been destroyed. + + U (output) REAL array, dimension at least (LDQ, N) + On exit, U contains the left singular vectors. + + LDU (input) INTEGER + On entry, leading dimension of U. + + VT (output) REAL array, dimension at least (LDVT, M) + On exit, VT' contains the right singular vectors. + + LDVT (input) INTEGER + On entry, leading dimension of VT. + + SMLSIZ (input) INTEGER + On entry, maximum size of the subproblems at the + bottom of the computation tree. + + IWORK (workspace) INTEGER array, dimension (8*N) + + WORK (workspace) REAL array, dimension (3*M**2+2*M) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --iwork; + --work; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -1; + } else if (*sqre < 0 || *sqre > 1) { + *info = -2; + } + + m = *n + *sqre; + + if (*ldu < *n) { + *info = -6; + } else if (*ldvt < m) { + *info = -8; + } else if (*smlsiz < 3) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASD0", &i__1); + return 0; + } + +/* If the input matrix is too small, call SLASDQ to find the SVD. */ + + if (*n <= *smlsiz) { + slasdq_("U", sqre, n, &m, n, &c__0, &d__[1], &e[1], &vt[vt_offset], + ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[1], info); + return 0; + } + +/* Set up the computation tree. */ + + inode = 1; + ndiml = inode + *n; + ndimr = ndiml + *n; + idxq = ndimr + *n; + iwk = idxq + *n; + slasdt_(n, &nlvl, &nd, &iwork[inode], &iwork[ndiml], &iwork[ndimr], + smlsiz); + +/* + For the nodes on bottom level of the tree, solve + their subproblems by SLASDQ. +*/ + + ndb1 = (nd + 1) / 2; + ncc = 0; + i__1 = nd; + for (i__ = ndb1; i__ <= i__1; ++i__) { + +/* + IC : center row of each node + NL : number of rows of left subproblem + NR : number of rows of right subproblem + NLF: starting row of the left subproblem + NRF: starting row of the right subproblem +*/ + + i1 = i__ - 1; + ic = iwork[inode + i1]; + nl = iwork[ndiml + i1]; + nlp1 = nl + 1; + nr = iwork[ndimr + i1]; + nrp1 = nr + 1; + nlf = ic - nl; + nrf = ic + 1; + sqrei = 1; + slasdq_("U", &sqrei, &nl, &nlp1, &nl, &ncc, &d__[nlf], &e[nlf], &vt[ + nlf + nlf * vt_dim1], ldvt, &u[nlf + nlf * u_dim1], ldu, &u[ + nlf + nlf * u_dim1], ldu, &work[1], info); + if (*info != 0) { + return 0; + } + itemp = idxq + nlf - 2; + i__2 = nl; + for (j = 1; j <= i__2; ++j) { + iwork[itemp + j] = j; +/* L10: */ + } + if (i__ == nd) { + sqrei = *sqre; + } else { + sqrei = 1; + } + nrp1 = nr + sqrei; + slasdq_("U", &sqrei, &nr, &nrp1, &nr, &ncc, &d__[nrf], &e[nrf], &vt[ + nrf + nrf * vt_dim1], ldvt, &u[nrf + nrf * u_dim1], ldu, &u[ + nrf + nrf * u_dim1], ldu, &work[1], info); + if (*info != 0) { + return 0; + } + itemp = idxq + ic; + i__2 = nr; + for (j = 1; j <= i__2; ++j) { + iwork[itemp + j - 1] = j; +/* L20: */ + } +/* L30: */ + } + +/* Now conquer each subproblem bottom-up. */ + + for (lvl = nlvl; lvl >= 1; --lvl) { + +/* + Find the first node LF and last node LL on the + current level LVL. +*/ + + if (lvl == 1) { + lf = 1; + ll = 1; + } else { + i__1 = lvl - 1; + lf = pow_ii(&c__2, &i__1); + ll = (lf << 1) - 1; + } + i__1 = ll; + for (i__ = lf; i__ <= i__1; ++i__) { + im1 = i__ - 1; + ic = iwork[inode + im1]; + nl = iwork[ndiml + im1]; + nr = iwork[ndimr + im1]; + nlf = ic - nl; + if (*sqre == 0 && i__ == ll) { + sqrei = *sqre; + } else { + sqrei = 1; + } + idxqc = idxq + nlf - 1; + alpha = d__[ic]; + beta = e[ic]; + slasd1_(&nl, &nr, &sqrei, &d__[nlf], &alpha, &beta, &u[nlf + nlf * + u_dim1], ldu, &vt[nlf + nlf * vt_dim1], ldvt, &iwork[ + idxqc], &iwork[iwk], &work[1], info); + if (*info != 0) { + return 0; + } +/* L40: */ + } +/* L50: */ + } + + return 0; + +/* End of SLASD0 */ + +} /* slasd0_ */ + +/* Subroutine */ int slasd1_(integer *nl, integer *nr, integer *sqre, real * + d__, real *alpha, real *beta, real *u, integer *ldu, real *vt, + integer *ldvt, integer *idxq, integer *iwork, real *work, integer * + info) +{ + /* System generated locals */ + integer u_dim1, u_offset, vt_dim1, vt_offset, i__1; + real r__1, r__2; + + /* Local variables */ + static integer i__, k, m, n, n1, n2, iq, iz, iu2, ldq, idx, ldu2, ivt2, + idxc, idxp, ldvt2; + extern /* Subroutine */ int slasd2_(integer *, integer *, integer *, + integer *, real *, real *, real *, real *, real *, integer *, + real *, integer *, real *, real *, integer *, real *, integer *, + integer *, integer *, integer *, integer *, integer *, integer *), + slasd3_(integer *, integer *, integer *, integer *, real *, real + *, integer *, real *, real *, integer *, real *, integer *, real * + , integer *, real *, integer *, integer *, integer *, real *, + integer *); + static integer isigma; + extern /* Subroutine */ int xerbla_(char *, integer *), slascl_( + char *, integer *, integer *, real *, real *, integer *, integer * + , real *, integer *, integer *), slamrg_(integer *, + integer *, real *, integer *, integer *, integer *); + static real orgnrm; + static integer coltyp; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SLASD1 computes the SVD of an upper bidiagonal N-by-M matrix B, + where N = NL + NR + 1 and M = N + SQRE. SLASD1 is called from SLASD0. + + A related subroutine SLASD7 handles the case in which the singular + values (and the singular vectors in factored form) are desired. + + SLASD1 computes the SVD as follows: + + ( D1(in) 0 0 0 ) + B = U(in) * ( Z1' a Z2' b ) * VT(in) + ( 0 0 D2(in) 0 ) + + = U(out) * ( D(out) 0) * VT(out) + + where Z' = (Z1' a Z2' b) = u' VT', and u is a vector of dimension M + with ALPHA and BETA in the NL+1 and NL+2 th entries and zeros + elsewhere; and the entry b is empty if SQRE = 0. + + The left singular vectors of the original matrix are stored in U, and + the transpose of the right singular vectors are stored in VT, and the + singular values are in D. The algorithm consists of three stages: + + The first stage consists of deflating the size of the problem + when there are multiple singular values or when there are zeros in + the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine SLASD2. + + The second stage consists of calculating the updated + singular values. This is done by finding the square roots of the + roots of the secular equation via the routine SLASD4 (as called + by SLASD3). This routine also calculates the singular vectors of + the current problem. + + The final stage consists of computing the updated singular vectors + directly using the updated singular values. The singular vectors + for the current problem are multiplied with the singular vectors + from the overall problem. + + Arguments + ========= + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has row dimension N = NL + NR + 1, + and column dimension M = N + SQRE. + + D (input/output) REAL array, dimension (NL+NR+1). + N = NL+NR+1 + On entry D(1:NL,1:NL) contains the singular values of the + upper block; and D(NL+2:N) contains the singular values of + the lower block. On exit D(1:N) contains the singular values + of the modified matrix. + + ALPHA (input/output) REAL + Contains the diagonal element associated with the added row. + + BETA (input/output) REAL + Contains the off-diagonal element associated with the added + row. + + U (input/output) REAL array, dimension (LDU,N) + On entry U(1:NL, 1:NL) contains the left singular vectors of + the upper block; U(NL+2:N, NL+2:N) contains the left singular + vectors of the lower block. On exit U contains the left + singular vectors of the bidiagonal matrix. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= max( 1, N ). + + VT (input/output) REAL array, dimension (LDVT,M) + where M = N + SQRE. + On entry VT(1:NL+1, 1:NL+1)' contains the right singular + vectors of the upper block; VT(NL+2:M, NL+2:M)' contains + the right singular vectors of the lower block. On exit + VT' contains the right singular vectors of the + bidiagonal matrix. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= max( 1, M ). + + IDXQ (output) INTEGER array, dimension (N) + This contains the permutation which will reintegrate the + subproblem just solved back into sorted order, i.e. + D( IDXQ( I = 1, N ) ) will be in ascending order. + + IWORK (workspace) INTEGER array, dimension (4*N) + + WORK (workspace) REAL array, dimension (3*M**2+2*M) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --idxq; + --iwork; + --work; + + /* Function Body */ + *info = 0; + + if (*nl < 1) { + *info = -1; + } else if (*nr < 1) { + *info = -2; + } else if (*sqre < 0 || *sqre > 1) { + *info = -3; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASD1", &i__1); + return 0; + } + + n = *nl + *nr + 1; + m = n + *sqre; + +/* + The following values are for bookkeeping purposes only. They are + integer pointers which indicate the portion of the workspace + used by a particular array in SLASD2 and SLASD3. +*/ + + ldu2 = n; + ldvt2 = m; + + iz = 1; + isigma = iz + m; + iu2 = isigma + n; + ivt2 = iu2 + ldu2 * n; + iq = ivt2 + ldvt2 * m; + + idx = 1; + idxc = idx + n; + coltyp = idxc + n; + idxp = coltyp + n; + +/* + Scale. + + Computing MAX +*/ + r__1 = dabs(*alpha), r__2 = dabs(*beta); + orgnrm = dmax(r__1,r__2); + d__[*nl + 1] = 0.f; + i__1 = n; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((r__1 = d__[i__], dabs(r__1)) > orgnrm) { + orgnrm = (r__1 = d__[i__], dabs(r__1)); + } +/* L10: */ + } + slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &n, &c__1, &d__[1], &n, info); + *alpha /= orgnrm; + *beta /= orgnrm; + +/* Deflate singular values. */ + + slasd2_(nl, nr, sqre, &k, &d__[1], &work[iz], alpha, beta, &u[u_offset], + ldu, &vt[vt_offset], ldvt, &work[isigma], &work[iu2], &ldu2, & + work[ivt2], &ldvt2, &iwork[idxp], &iwork[idx], &iwork[idxc], & + idxq[1], &iwork[coltyp], info); + +/* Solve Secular Equation and update singular vectors. */ + + ldq = k; + slasd3_(nl, nr, sqre, &k, &d__[1], &work[iq], &ldq, &work[isigma], &u[ + u_offset], ldu, &work[iu2], &ldu2, &vt[vt_offset], ldvt, &work[ + ivt2], &ldvt2, &iwork[idxc], &iwork[coltyp], &work[iz], info); + if (*info != 0) { + return 0; + } + +/* Unscale. */ + + slascl_("G", &c__0, &c__0, &c_b15, &orgnrm, &n, &c__1, &d__[1], &n, info); + +/* Prepare the IDXQ sorting permutation. */ + + n1 = k; + n2 = n - k; + slamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &idxq[1]); + + return 0; + +/* End of SLASD1 */ + +} /* slasd1_ */ + +/* Subroutine */ int slasd2_(integer *nl, integer *nr, integer *sqre, integer + *k, real *d__, real *z__, real *alpha, real *beta, real *u, integer * + ldu, real *vt, integer *ldvt, real *dsigma, real *u2, integer *ldu2, + real *vt2, integer *ldvt2, integer *idxp, integer *idx, integer *idxc, + integer *idxq, integer *coltyp, integer *info) +{ + /* System generated locals */ + integer u_dim1, u_offset, u2_dim1, u2_offset, vt_dim1, vt_offset, + vt2_dim1, vt2_offset, i__1; + real r__1, r__2; + + /* Local variables */ + static real c__; + static integer i__, j, m, n; + static real s; + static integer k2; + static real z1; + static integer ct, jp; + static real eps, tau, tol; + static integer psm[4], nlp1, nlp2, idxi, idxj, ctot[4]; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *); + static integer idxjp, jprev; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + extern doublereal slapy2_(real *, real *), slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *), slamrg_( + integer *, integer *, real *, integer *, integer *, integer *); + static real hlftol; + extern /* Subroutine */ int slacpy_(char *, integer *, integer *, real *, + integer *, real *, integer *), slaset_(char *, integer *, + integer *, real *, real *, real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASD2 merges the two sets of singular values together into a single + sorted set. Then it tries to deflate the size of the problem. + There are two ways in which deflation can occur: when two or more + singular values are close together or if there is a tiny entry in the + Z vector. For each such occurrence the order of the related secular + equation problem is reduced by one. + + SLASD2 is called from SLASD1. + + Arguments + ========= + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has N = NL + NR + 1 rows and + M = N + SQRE >= N columns. + + K (output) INTEGER + Contains the dimension of the non-deflated matrix, + This is the order of the related secular equation. 1 <= K <=N. + + D (input/output) REAL array, dimension (N) + On entry D contains the singular values of the two submatrices + to be combined. On exit D contains the trailing (N-K) updated + singular values (those which were deflated) sorted into + increasing order. + + Z (output) REAL array, dimension (N) + On exit Z contains the updating row vector in the secular + equation. + + ALPHA (input) REAL + Contains the diagonal element associated with the added row. + + BETA (input) REAL + Contains the off-diagonal element associated with the added + row. + + U (input/output) REAL array, dimension (LDU,N) + On entry U contains the left singular vectors of two + submatrices in the two square blocks with corners at (1,1), + (NL, NL), and (NL+2, NL+2), (N,N). + On exit U contains the trailing (N-K) updated left singular + vectors (those which were deflated) in its last N-K columns. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= N. + + VT (input/output) REAL array, dimension (LDVT,M) + On entry VT' contains the right singular vectors of two + submatrices in the two square blocks with corners at (1,1), + (NL+1, NL+1), and (NL+2, NL+2), (M,M). + On exit VT' contains the trailing (N-K) updated right singular + vectors (those which were deflated) in its last N-K columns. + In case SQRE =1, the last row of VT spans the right null + space. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= M. + + DSIGMA (output) REAL array, dimension (N) + Contains a copy of the diagonal elements (K-1 singular values + and one zero) in the secular equation. + + U2 (output) REAL array, dimension (LDU2,N) + Contains a copy of the first K-1 left singular vectors which + will be used by SLASD3 in a matrix multiply (SGEMM) to solve + for the new left singular vectors. U2 is arranged into four + blocks. The first block contains a column with 1 at NL+1 and + zero everywhere else; the second block contains non-zero + entries only at and above NL; the third contains non-zero + entries only below NL+1; and the fourth is dense. + + LDU2 (input) INTEGER + The leading dimension of the array U2. LDU2 >= N. + + VT2 (output) REAL array, dimension (LDVT2,N) + VT2' contains a copy of the first K right singular vectors + which will be used by SLASD3 in a matrix multiply (SGEMM) to + solve for the new right singular vectors. VT2 is arranged into + three blocks. The first block contains a row that corresponds + to the special 0 diagonal element in SIGMA; the second block + contains non-zeros only at and before NL +1; the third block + contains non-zeros only at and after NL +2. + + LDVT2 (input) INTEGER + The leading dimension of the array VT2. LDVT2 >= M. + + IDXP (workspace) INTEGER array, dimension (N) + This will contain the permutation used to place deflated + values of D at the end of the array. On output IDXP(2:K) + points to the nondeflated D-values and IDXP(K+1:N) + points to the deflated singular values. + + IDX (workspace) INTEGER array, dimension (N) + This will contain the permutation used to sort the contents of + D into ascending order. + + IDXC (output) INTEGER array, dimension (N) + This will contain the permutation used to arrange the columns + of the deflated U matrix into three groups: the first group + contains non-zero entries only at and above NL, the second + contains non-zero entries only below NL+2, and the third is + dense. + + IDXQ (input/output) INTEGER array, dimension (N) + This contains the permutation which separately sorts the two + sub-problems in D into ascending order. Note that entries in + the first hlaf of this permutation must first be moved one + position backward; and entries in the second half + must first have NL+1 added to their values. + + COLTYP (workspace/output) INTEGER array, dimension (N) + As workspace, this will contain a label which will indicate + which of the following types a column in the U2 matrix or a + row in the VT2 matrix is: + 1 : non-zero in the upper half only + 2 : non-zero in the lower half only + 3 : dense + 4 : deflated + + On exit, it is an array of dimension 4, with COLTYP(I) being + the dimension of the I-th type columns. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --z__; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --dsigma; + u2_dim1 = *ldu2; + u2_offset = 1 + u2_dim1; + u2 -= u2_offset; + vt2_dim1 = *ldvt2; + vt2_offset = 1 + vt2_dim1; + vt2 -= vt2_offset; + --idxp; + --idx; + --idxc; + --idxq; + --coltyp; + + /* Function Body */ + *info = 0; + + if (*nl < 1) { + *info = -1; + } else if (*nr < 1) { + *info = -2; + } else if (*sqre != 1 && *sqre != 0) { + *info = -3; + } + + n = *nl + *nr + 1; + m = n + *sqre; + + if (*ldu < n) { + *info = -10; + } else if (*ldvt < m) { + *info = -12; + } else if (*ldu2 < n) { + *info = -15; + } else if (*ldvt2 < m) { + *info = -17; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASD2", &i__1); + return 0; + } + + nlp1 = *nl + 1; + nlp2 = *nl + 2; + +/* + Generate the first part of the vector Z; and move the singular + values in the first part of D one position backward. +*/ + + z1 = *alpha * vt[nlp1 + nlp1 * vt_dim1]; + z__[1] = z1; + for (i__ = *nl; i__ >= 1; --i__) { + z__[i__ + 1] = *alpha * vt[i__ + nlp1 * vt_dim1]; + d__[i__ + 1] = d__[i__]; + idxq[i__ + 1] = idxq[i__] + 1; +/* L10: */ + } + +/* Generate the second part of the vector Z. */ + + i__1 = m; + for (i__ = nlp2; i__ <= i__1; ++i__) { + z__[i__] = *beta * vt[i__ + nlp2 * vt_dim1]; +/* L20: */ + } + +/* Initialize some reference arrays. */ + + i__1 = nlp1; + for (i__ = 2; i__ <= i__1; ++i__) { + coltyp[i__] = 1; +/* L30: */ + } + i__1 = n; + for (i__ = nlp2; i__ <= i__1; ++i__) { + coltyp[i__] = 2; +/* L40: */ + } + +/* Sort the singular values into increasing order */ + + i__1 = n; + for (i__ = nlp2; i__ <= i__1; ++i__) { + idxq[i__] += nlp1; +/* L50: */ + } + +/* + DSIGMA, IDXC, IDXC, and the first column of U2 + are used as storage space. +*/ + + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + dsigma[i__] = d__[idxq[i__]]; + u2[i__ + u2_dim1] = z__[idxq[i__]]; + idxc[i__] = coltyp[idxq[i__]]; +/* L60: */ + } + + slamrg_(nl, nr, &dsigma[2], &c__1, &c__1, &idx[2]); + + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + idxi = idx[i__] + 1; + d__[i__] = dsigma[idxi]; + z__[i__] = u2[idxi + u2_dim1]; + coltyp[i__] = idxc[idxi]; +/* L70: */ + } + +/* Calculate the allowable deflation tolerance */ + + eps = slamch_("Epsilon"); +/* Computing MAX */ + r__1 = dabs(*alpha), r__2 = dabs(*beta); + tol = dmax(r__1,r__2); +/* Computing MAX */ + r__2 = (r__1 = d__[n], dabs(r__1)); + tol = eps * 8.f * dmax(r__2,tol); + +/* + There are 2 kinds of deflation -- first a value in the z-vector + is small, second two (or more) singular values are very close + together (their difference is small). + + If the value in the z-vector is small, we simply permute the + array so that the corresponding singular value is moved to the + end. + + If two values in the D-vector are close, we perform a two-sided + rotation designed to make one of the corresponding z-vector + entries zero, and then permute the array so that the deflated + singular value is moved to the end. + + If there are multiple singular values then the problem deflates. + Here the number of equal singular values are found. As each equal + singular value is found, an elementary reflector is computed to + rotate the corresponding singular subspace so that the + corresponding components of Z are zero in this new basis. +*/ + + *k = 1; + k2 = n + 1; + i__1 = n; + for (j = 2; j <= i__1; ++j) { + if ((r__1 = z__[j], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + idxp[k2] = j; + coltyp[j] = 4; + if (j == n) { + goto L120; + } + } else { + jprev = j; + goto L90; + } +/* L80: */ + } +L90: + j = jprev; +L100: + ++j; + if (j > n) { + goto L110; + } + if ((r__1 = z__[j], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + idxp[k2] = j; + coltyp[j] = 4; + } else { + +/* Check if singular values are close enough to allow deflation. */ + + if ((r__1 = d__[j] - d__[jprev], dabs(r__1)) <= tol) { + +/* Deflation is possible. */ + + s = z__[jprev]; + c__ = z__[j]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = slapy2_(&c__, &s); + c__ /= tau; + s = -s / tau; + z__[j] = tau; + z__[jprev] = 0.f; + +/* + Apply back the Givens rotation to the left and right + singular vector matrices. +*/ + + idxjp = idxq[idx[jprev] + 1]; + idxj = idxq[idx[j] + 1]; + if (idxjp <= nlp1) { + --idxjp; + } + if (idxj <= nlp1) { + --idxj; + } + srot_(&n, &u[idxjp * u_dim1 + 1], &c__1, &u[idxj * u_dim1 + 1], & + c__1, &c__, &s); + srot_(&m, &vt[idxjp + vt_dim1], ldvt, &vt[idxj + vt_dim1], ldvt, & + c__, &s); + if (coltyp[j] != coltyp[jprev]) { + coltyp[j] = 3; + } + coltyp[jprev] = 4; + --k2; + idxp[k2] = jprev; + jprev = j; + } else { + ++(*k); + u2[*k + u2_dim1] = z__[jprev]; + dsigma[*k] = d__[jprev]; + idxp[*k] = jprev; + jprev = j; + } + } + goto L100; +L110: + +/* Record the last singular value. */ + + ++(*k); + u2[*k + u2_dim1] = z__[jprev]; + dsigma[*k] = d__[jprev]; + idxp[*k] = jprev; + +L120: + +/* + Count up the total number of the various types of columns, then + form a permutation which positions the four column types into + four groups of uniform structure (although one or more of these + groups may be empty). +*/ + + for (j = 1; j <= 4; ++j) { + ctot[j - 1] = 0; +/* L130: */ + } + i__1 = n; + for (j = 2; j <= i__1; ++j) { + ct = coltyp[j]; + ++ctot[ct - 1]; +/* L140: */ + } + +/* PSM(*) = Position in SubMatrix (of types 1 through 4) */ + + psm[0] = 2; + psm[1] = ctot[0] + 2; + psm[2] = psm[1] + ctot[1]; + psm[3] = psm[2] + ctot[2]; + +/* + Fill out the IDXC array so that the permutation which it induces + will place all type-1 columns first, all type-2 columns next, + then all type-3's, and finally all type-4's, starting from the + second column. This applies similarly to the rows of VT. +*/ + + i__1 = n; + for (j = 2; j <= i__1; ++j) { + jp = idxp[j]; + ct = coltyp[jp]; + idxc[psm[ct - 1]] = j; + ++psm[ct - 1]; +/* L150: */ + } + +/* + Sort the singular values and corresponding singular vectors into + DSIGMA, U2, and VT2 respectively. The singular values/vectors + which were not deflated go into the first K slots of DSIGMA, U2, + and VT2 respectively, while those which were deflated go into the + last N - K slots, except that the first column/row will be treated + separately. +*/ + + i__1 = n; + for (j = 2; j <= i__1; ++j) { + jp = idxp[j]; + dsigma[j] = d__[jp]; + idxj = idxq[idx[idxp[idxc[j]]] + 1]; + if (idxj <= nlp1) { + --idxj; + } + scopy_(&n, &u[idxj * u_dim1 + 1], &c__1, &u2[j * u2_dim1 + 1], &c__1); + scopy_(&m, &vt[idxj + vt_dim1], ldvt, &vt2[j + vt2_dim1], ldvt2); +/* L160: */ + } + +/* Determine DSIGMA(1), DSIGMA(2) and Z(1) */ + + dsigma[1] = 0.f; + hlftol = tol / 2.f; + if (dabs(dsigma[2]) <= hlftol) { + dsigma[2] = hlftol; + } + if (m > n) { + z__[1] = slapy2_(&z1, &z__[m]); + if (z__[1] <= tol) { + c__ = 1.f; + s = 0.f; + z__[1] = tol; + } else { + c__ = z1 / z__[1]; + s = z__[m] / z__[1]; + } + } else { + if (dabs(z1) <= tol) { + z__[1] = tol; + } else { + z__[1] = z1; + } + } + +/* Move the rest of the updating row to Z. */ + + i__1 = *k - 1; + scopy_(&i__1, &u2[u2_dim1 + 2], &c__1, &z__[2], &c__1); + +/* + Determine the first column of U2, the first row of VT2 and the + last row of VT. +*/ + + slaset_("A", &n, &c__1, &c_b29, &c_b29, &u2[u2_offset], ldu2); + u2[nlp1 + u2_dim1] = 1.f; + if (m > n) { + i__1 = nlp1; + for (i__ = 1; i__ <= i__1; ++i__) { + vt[m + i__ * vt_dim1] = -s * vt[nlp1 + i__ * vt_dim1]; + vt2[i__ * vt2_dim1 + 1] = c__ * vt[nlp1 + i__ * vt_dim1]; +/* L170: */ + } + i__1 = m; + for (i__ = nlp2; i__ <= i__1; ++i__) { + vt2[i__ * vt2_dim1 + 1] = s * vt[m + i__ * vt_dim1]; + vt[m + i__ * vt_dim1] = c__ * vt[m + i__ * vt_dim1]; +/* L180: */ + } + } else { + scopy_(&m, &vt[nlp1 + vt_dim1], ldvt, &vt2[vt2_dim1 + 1], ldvt2); + } + if (m > n) { + scopy_(&m, &vt[m + vt_dim1], ldvt, &vt2[m + vt2_dim1], ldvt2); + } + +/* + The deflated singular values and their corresponding vectors go + into the back of D, U, and V respectively. +*/ + + if (n > *k) { + i__1 = n - *k; + scopy_(&i__1, &dsigma[*k + 1], &c__1, &d__[*k + 1], &c__1); + i__1 = n - *k; + slacpy_("A", &n, &i__1, &u2[(*k + 1) * u2_dim1 + 1], ldu2, &u[(*k + 1) + * u_dim1 + 1], ldu); + i__1 = n - *k; + slacpy_("A", &i__1, &m, &vt2[*k + 1 + vt2_dim1], ldvt2, &vt[*k + 1 + + vt_dim1], ldvt); + } + +/* Copy CTOT into COLTYP for referencing in SLASD3. */ + + for (j = 1; j <= 4; ++j) { + coltyp[j] = ctot[j - 1]; +/* L190: */ + } + + return 0; + +/* End of SLASD2 */ + +} /* slasd2_ */ + +/* Subroutine */ int slasd3_(integer *nl, integer *nr, integer *sqre, integer + *k, real *d__, real *q, integer *ldq, real *dsigma, real *u, integer * + ldu, real *u2, integer *ldu2, real *vt, integer *ldvt, real *vt2, + integer *ldvt2, integer *idxc, integer *ctot, real *z__, integer * + info) +{ + /* System generated locals */ + integer q_dim1, q_offset, u_dim1, u_offset, u2_dim1, u2_offset, vt_dim1, + vt_offset, vt2_dim1, vt2_offset, i__1, i__2; + real r__1, r__2; + + /* Local variables */ + static integer i__, j, m, n, jc; + static real rho; + static integer nlp1, nlp2, nrp1; + static real temp; + extern doublereal snrm2_(integer *, real *, integer *); + static integer ctemp; + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static integer ktemp; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + extern doublereal slamc3_(real *, real *); + extern /* Subroutine */ int slasd4_(integer *, integer *, real *, real *, + real *, real *, real *, real *, integer *), xerbla_(char *, + integer *), slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *), slacpy_(char *, integer *, integer *, real *, integer *, + real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SLASD3 finds all the square roots of the roots of the secular + equation, as defined by the values in D and Z. It makes the + appropriate calls to SLASD4 and then updates the singular + vectors by matrix multiplication. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray XMP, Cray YMP, Cray C 90, or Cray 2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + SLASD3 is called from SLASD1. + + Arguments + ========= + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has N = NL + NR + 1 rows and + M = N + SQRE >= N columns. + + K (input) INTEGER + The size of the secular equation, 1 =< K = < N. + + D (output) REAL array, dimension(K) + On exit the square roots of the roots of the secular equation, + in ascending order. + + Q (workspace) REAL array, + dimension at least (LDQ,K). + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= K. + + DSIGMA (input/output) REAL array, dimension(K) + The first K elements of this array contain the old roots + of the deflated updating problem. These are the poles + of the secular equation. + + U (output) REAL array, dimension (LDU, N) + The last N - K columns of this matrix contain the deflated + left singular vectors. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= N. + + U2 (input) REAL array, dimension (LDU2, N) + The first K columns of this matrix contain the non-deflated + left singular vectors for the split problem. + + LDU2 (input) INTEGER + The leading dimension of the array U2. LDU2 >= N. + + VT (output) REAL array, dimension (LDVT, M) + The last M - K columns of VT' contain the deflated + right singular vectors. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= N. + + VT2 (input/output) REAL array, dimension (LDVT2, N) + The first K columns of VT2' contain the non-deflated + right singular vectors for the split problem. + + LDVT2 (input) INTEGER + The leading dimension of the array VT2. LDVT2 >= N. + + IDXC (input) INTEGER array, dimension (N) + The permutation used to arrange the columns of U (and rows of + VT) into three groups: the first group contains non-zero + entries only at and above (or before) NL +1; the second + contains non-zero entries only at and below (or after) NL+2; + and the third is dense. The first column of U and the row of + VT are treated separately, however. + + The rows of the singular vectors found by SLASD4 + must be likewise permuted before the matrix multiplies can + take place. + + CTOT (input) INTEGER array, dimension (4) + A count of the total number of the various types of columns + in U (or rows in VT), as described in IDXC. The fourth column + type is any column which has been deflated. + + Z (input/output) REAL array, dimension (K) + The first K elements of this array contain the components + of the deflation-adjusted updating row vector. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --dsigma; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + u2_dim1 = *ldu2; + u2_offset = 1 + u2_dim1; + u2 -= u2_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + vt2_dim1 = *ldvt2; + vt2_offset = 1 + vt2_dim1; + vt2 -= vt2_offset; + --idxc; + --ctot; + --z__; + + /* Function Body */ + *info = 0; + + if (*nl < 1) { + *info = -1; + } else if (*nr < 1) { + *info = -2; + } else if (*sqre != 1 && *sqre != 0) { + *info = -3; + } + + n = *nl + *nr + 1; + m = n + *sqre; + nlp1 = *nl + 1; + nlp2 = *nl + 2; + + if (*k < 1 || *k > n) { + *info = -4; + } else if (*ldq < *k) { + *info = -7; + } else if (*ldu < n) { + *info = -10; + } else if (*ldu2 < n) { + *info = -12; + } else if (*ldvt < m) { + *info = -14; + } else if (*ldvt2 < m) { + *info = -16; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASD3", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*k == 1) { + d__[1] = dabs(z__[1]); + scopy_(&m, &vt2[vt2_dim1 + 1], ldvt2, &vt[vt_dim1 + 1], ldvt); + if (z__[1] > 0.f) { + scopy_(&n, &u2[u2_dim1 + 1], &c__1, &u[u_dim1 + 1], &c__1); + } else { + i__1 = n; + for (i__ = 1; i__ <= i__1; ++i__) { + u[i__ + u_dim1] = -u2[i__ + u2_dim1]; +/* L10: */ + } + } + return 0; + } + +/* + Modify values DSIGMA(i) to make sure all DSIGMA(i)-DSIGMA(j) can + be computed with high relative accuracy (barring over/underflow). + This is a problem on machines without a guard digit in + add/subtract (Cray XMP, Cray YMP, Cray C 90 and Cray 2). + The following code replaces DSIGMA(I) by 2*DSIGMA(I)-DSIGMA(I), + which on any of these machines zeros out the bottommost + bit of DSIGMA(I) if it is 1; this makes the subsequent + subtractions DSIGMA(I)-DSIGMA(J) unproblematic when cancellation + occurs. On binary machines with a guard digit (almost all + machines) it does not change DSIGMA(I) at all. On hexadecimal + and decimal machines with a guard digit, it slightly + changes the bottommost bits of DSIGMA(I). It does not account + for hexadecimal or decimal machines without guard digits + (we know of none). We use a subroutine call to compute + 2*DSIGMA(I) to prevent optimizing compilers from eliminating + this code. +*/ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + dsigma[i__] = slamc3_(&dsigma[i__], &dsigma[i__]) - dsigma[i__]; +/* L20: */ + } + +/* Keep a copy of Z. */ + + scopy_(k, &z__[1], &c__1, &q[q_offset], &c__1); + +/* Normalize Z. */ + + rho = snrm2_(k, &z__[1], &c__1); + slascl_("G", &c__0, &c__0, &rho, &c_b15, k, &c__1, &z__[1], k, info); + rho *= rho; + +/* Find the new singular values. */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + slasd4_(k, &j, &dsigma[1], &z__[1], &u[j * u_dim1 + 1], &rho, &d__[j], + &vt[j * vt_dim1 + 1], info); + +/* If the zero finder fails, the computation is terminated. */ + + if (*info != 0) { + return 0; + } +/* L30: */ + } + +/* Compute updated Z. */ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + z__[i__] = u[i__ + *k * u_dim1] * vt[i__ + *k * vt_dim1]; + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + z__[i__] *= u[i__ + j * u_dim1] * vt[i__ + j * vt_dim1] / (dsigma[ + i__] - dsigma[j]) / (dsigma[i__] + dsigma[j]); +/* L40: */ + } + i__2 = *k - 1; + for (j = i__; j <= i__2; ++j) { + z__[i__] *= u[i__ + j * u_dim1] * vt[i__ + j * vt_dim1] / (dsigma[ + i__] - dsigma[j + 1]) / (dsigma[i__] + dsigma[j + 1]); +/* L50: */ + } + r__2 = sqrt((r__1 = z__[i__], dabs(r__1))); + z__[i__] = r_sign(&r__2, &q[i__ + q_dim1]); +/* L60: */ + } + +/* + Compute left singular vectors of the modified diagonal matrix, + and store related information for the right singular vectors. +*/ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + vt[i__ * vt_dim1 + 1] = z__[1] / u[i__ * u_dim1 + 1] / vt[i__ * + vt_dim1 + 1]; + u[i__ * u_dim1 + 1] = -1.f; + i__2 = *k; + for (j = 2; j <= i__2; ++j) { + vt[j + i__ * vt_dim1] = z__[j] / u[j + i__ * u_dim1] / vt[j + i__ + * vt_dim1]; + u[j + i__ * u_dim1] = dsigma[j] * vt[j + i__ * vt_dim1]; +/* L70: */ + } + temp = snrm2_(k, &u[i__ * u_dim1 + 1], &c__1); + q[i__ * q_dim1 + 1] = u[i__ * u_dim1 + 1] / temp; + i__2 = *k; + for (j = 2; j <= i__2; ++j) { + jc = idxc[j]; + q[j + i__ * q_dim1] = u[jc + i__ * u_dim1] / temp; +/* L80: */ + } +/* L90: */ + } + +/* Update the left singular vector matrix. */ + + if (*k == 2) { + sgemm_("N", "N", &n, k, k, &c_b15, &u2[u2_offset], ldu2, &q[q_offset], + ldq, &c_b29, &u[u_offset], ldu); + goto L100; + } + if (ctot[1] > 0) { + sgemm_("N", "N", nl, k, &ctot[1], &c_b15, &u2[(u2_dim1 << 1) + 1], + ldu2, &q[q_dim1 + 2], ldq, &c_b29, &u[u_dim1 + 1], ldu); + if (ctot[3] > 0) { + ktemp = ctot[1] + 2 + ctot[2]; + sgemm_("N", "N", nl, k, &ctot[3], &c_b15, &u2[ktemp * u2_dim1 + 1] + , ldu2, &q[ktemp + q_dim1], ldq, &c_b15, &u[u_dim1 + 1], + ldu); + } + } else if (ctot[3] > 0) { + ktemp = ctot[1] + 2 + ctot[2]; + sgemm_("N", "N", nl, k, &ctot[3], &c_b15, &u2[ktemp * u2_dim1 + 1], + ldu2, &q[ktemp + q_dim1], ldq, &c_b29, &u[u_dim1 + 1], ldu); + } else { + slacpy_("F", nl, k, &u2[u2_offset], ldu2, &u[u_offset], ldu); + } + scopy_(k, &q[q_dim1 + 1], ldq, &u[nlp1 + u_dim1], ldu); + ktemp = ctot[1] + 2; + ctemp = ctot[2] + ctot[3]; + sgemm_("N", "N", nr, k, &ctemp, &c_b15, &u2[nlp2 + ktemp * u2_dim1], ldu2, + &q[ktemp + q_dim1], ldq, &c_b29, &u[nlp2 + u_dim1], ldu); + +/* Generate the right singular vectors. */ + +L100: + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = snrm2_(k, &vt[i__ * vt_dim1 + 1], &c__1); + q[i__ + q_dim1] = vt[i__ * vt_dim1 + 1] / temp; + i__2 = *k; + for (j = 2; j <= i__2; ++j) { + jc = idxc[j]; + q[i__ + j * q_dim1] = vt[jc + i__ * vt_dim1] / temp; +/* L110: */ + } +/* L120: */ + } + +/* Update the right singular vector matrix. */ + + if (*k == 2) { + sgemm_("N", "N", k, &m, k, &c_b15, &q[q_offset], ldq, &vt2[vt2_offset] + , ldvt2, &c_b29, &vt[vt_offset], ldvt); + return 0; + } + ktemp = ctot[1] + 1; + sgemm_("N", "N", k, &nlp1, &ktemp, &c_b15, &q[q_dim1 + 1], ldq, &vt2[ + vt2_dim1 + 1], ldvt2, &c_b29, &vt[vt_dim1 + 1], ldvt); + ktemp = ctot[1] + 2 + ctot[2]; + if (ktemp <= *ldvt2) { + sgemm_("N", "N", k, &nlp1, &ctot[3], &c_b15, &q[ktemp * q_dim1 + 1], + ldq, &vt2[ktemp + vt2_dim1], ldvt2, &c_b15, &vt[vt_dim1 + 1], + ldvt); + } + + ktemp = ctot[1] + 1; + nrp1 = *nr + *sqre; + if (ktemp > 1) { + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + q[i__ + ktemp * q_dim1] = q[i__ + q_dim1]; +/* L130: */ + } + i__1 = m; + for (i__ = nlp2; i__ <= i__1; ++i__) { + vt2[ktemp + i__ * vt2_dim1] = vt2[i__ * vt2_dim1 + 1]; +/* L140: */ + } + } + ctemp = ctot[2] + 1 + ctot[3]; + sgemm_("N", "N", k, &nrp1, &ctemp, &c_b15, &q[ktemp * q_dim1 + 1], ldq, & + vt2[ktemp + nlp2 * vt2_dim1], ldvt2, &c_b29, &vt[nlp2 * vt_dim1 + + 1], ldvt); + + return 0; + +/* End of SLASD3 */ + +} /* slasd3_ */ + +/* Subroutine */ int slasd4_(integer *n, integer *i__, real *d__, real *z__, + real *delta, real *rho, real *sigma, real *work, integer *info) +{ + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + static real a, b, c__; + static integer j; + static real w, dd[3]; + static integer ii; + static real dw, zz[3]; + static integer ip1; + static real eta, phi, eps, tau, psi; + static integer iim1, iip1; + static real dphi, dpsi; + static integer iter; + static real temp, prew, sg2lb, sg2ub, temp1, temp2, dtiim, delsq, dtiip; + static integer niter; + static real dtisq; + static logical swtch; + static real dtnsq; + extern /* Subroutine */ int slaed6_(integer *, logical *, real *, real *, + real *, real *, real *, integer *); + static real delsq2; + extern /* Subroutine */ int slasd5_(integer *, real *, real *, real *, + real *, real *, real *); + static real dtnsq1; + static logical swtch3; + extern doublereal slamch_(char *); + static logical orgati; + static real erretm, dtipsq, rhoinv; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This subroutine computes the square root of the I-th updated + eigenvalue of a positive symmetric rank-one modification to + a positive diagonal matrix whose entries are given as the squares + of the corresponding entries in the array d, and that + + 0 <= D(i) < D(j) for i < j + + and that RHO > 0. This is arranged by the calling routine, and is + no loss in generality. The rank-one modified system is thus + + diag( D ) * diag( D ) + RHO * Z * Z_transpose. + + where we assume the Euclidean norm of Z is 1. + + The method consists of approximating the rational functions in the + secular equation by simpler interpolating rational functions. + + Arguments + ========= + + N (input) INTEGER + The length of all arrays. + + I (input) INTEGER + The index of the eigenvalue to be computed. 1 <= I <= N. + + D (input) REAL array, dimension ( N ) + The original eigenvalues. It is assumed that they are in + order, 0 <= D(I) < D(J) for I < J. + + Z (input) REAL array, dimension (N) + The components of the updating vector. + + DELTA (output) REAL array, dimension (N) + If N .ne. 1, DELTA contains (D(j) - sigma_I) in its j-th + component. If N = 1, then DELTA(1) = 1. The vector DELTA + contains the information necessary to construct the + (singular) eigenvectors. + + RHO (input) REAL + The scalar in the symmetric updating formula. + + SIGMA (output) REAL + The computed sigma_I, the I-th updated eigenvalue. + + WORK (workspace) REAL array, dimension (N) + If N .ne. 1, WORK contains (D(j) + sigma_I) in its j-th + component. If N = 1, then WORK( 1 ) = 1. + + INFO (output) INTEGER + = 0: successful exit + > 0: if INFO = 1, the updating process failed. + + Internal Parameters + =================== + + Logical variable ORGATI (origin-at-i?) is used for distinguishing + whether D(i) or D(i+1) is treated as the origin. + + ORGATI = .true. origin at i + ORGATI = .false. origin at i+1 + + Logical variable SWTCH3 (switch-for-3-poles?) is for noting + if we are working with THREE poles! + + MAXIT is the maximum number of iterations allowed for each + eigenvalue. + + Further Details + =============== + + Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Since this routine is called in an inner loop, we do no argument + checking. + + Quick return for N=1 and 2. +*/ + + /* Parameter adjustments */ + --work; + --delta; + --z__; + --d__; + + /* Function Body */ + *info = 0; + if (*n == 1) { + +/* Presumably, I=1 upon entry */ + + *sigma = sqrt(d__[1] * d__[1] + *rho * z__[1] * z__[1]); + delta[1] = 1.f; + work[1] = 1.f; + return 0; + } + if (*n == 2) { + slasd5_(i__, &d__[1], &z__[1], &delta[1], rho, sigma, &work[1]); + return 0; + } + +/* Compute machine epsilon */ + + eps = slamch_("Epsilon"); + rhoinv = 1.f / *rho; + +/* The case I = N */ + + if (*i__ == *n) { + +/* Initialize some basic variables */ + + ii = *n - 1; + niter = 1; + +/* Calculate initial guess */ + + temp = *rho / 2.f; + +/* + If ||Z||_2 is not one, then TEMP should be set to + RHO * ||Z||_2^2 / TWO +*/ + + temp1 = temp / (d__[*n] + sqrt(d__[*n] * d__[*n] + temp)); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] = d__[j] + d__[*n] + temp1; + delta[j] = d__[j] - d__[*n] - temp1; +/* L10: */ + } + + psi = 0.f; + i__1 = *n - 2; + for (j = 1; j <= i__1; ++j) { + psi += z__[j] * z__[j] / (delta[j] * work[j]); +/* L20: */ + } + + c__ = rhoinv + psi; + w = c__ + z__[ii] * z__[ii] / (delta[ii] * work[ii]) + z__[*n] * z__[* + n] / (delta[*n] * work[*n]); + + if (w <= 0.f) { + temp1 = sqrt(d__[*n] * d__[*n] + *rho); + temp = z__[*n - 1] * z__[*n - 1] / ((d__[*n - 1] + temp1) * (d__[* + n] - d__[*n - 1] + *rho / (d__[*n] + temp1))) + z__[*n] * + z__[*n] / *rho; + +/* + The following TAU is to approximate + SIGMA_n^2 - D( N )*D( N ) +*/ + + if (c__ <= temp) { + tau = *rho; + } else { + delsq = (d__[*n] - d__[*n - 1]) * (d__[*n] + d__[*n - 1]); + a = -c__ * delsq + z__[*n - 1] * z__[*n - 1] + z__[*n] * z__[* + n]; + b = z__[*n] * z__[*n] * delsq; + if (a < 0.f) { + tau = b * 2.f / (sqrt(a * a + b * 4.f * c__) - a); + } else { + tau = (a + sqrt(a * a + b * 4.f * c__)) / (c__ * 2.f); + } + } + +/* + It can be proved that + D(N)^2+RHO/2 <= SIGMA_n^2 < D(N)^2+TAU <= D(N)^2+RHO +*/ + + } else { + delsq = (d__[*n] - d__[*n - 1]) * (d__[*n] + d__[*n - 1]); + a = -c__ * delsq + z__[*n - 1] * z__[*n - 1] + z__[*n] * z__[*n]; + b = z__[*n] * z__[*n] * delsq; + +/* + The following TAU is to approximate + SIGMA_n^2 - D( N )*D( N ) +*/ + + if (a < 0.f) { + tau = b * 2.f / (sqrt(a * a + b * 4.f * c__) - a); + } else { + tau = (a + sqrt(a * a + b * 4.f * c__)) / (c__ * 2.f); + } + +/* + It can be proved that + D(N)^2 < D(N)^2+TAU < SIGMA(N)^2 < D(N)^2+RHO/2 +*/ + + } + +/* The following ETA is to approximate SIGMA_n - D( N ) */ + + eta = tau / (d__[*n] + sqrt(d__[*n] * d__[*n] + tau)); + + *sigma = d__[*n] + eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] = d__[j] - d__[*i__] - eta; + work[j] = d__[j] + d__[*i__] + eta; +/* L30: */ + } + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (delta[j] * work[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L40: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / (delta[*n] * work[*n]); + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8.f + erretm - phi + rhoinv + dabs(tau) * ( + dpsi + dphi); + + w = rhoinv + phi + psi; + +/* Test for convergence */ + + if (dabs(w) <= eps * erretm) { + goto L240; + } + +/* Calculate the new step */ + + ++niter; + dtnsq1 = work[*n - 1] * delta[*n - 1]; + dtnsq = work[*n] * delta[*n]; + c__ = w - dtnsq1 * dpsi - dtnsq * dphi; + a = (dtnsq + dtnsq1) * w - dtnsq * dtnsq1 * (dpsi + dphi); + b = dtnsq * dtnsq1 * w; + if (c__ < 0.f) { + c__ = dabs(c__); + } + if (c__ == 0.f) { + eta = *rho - *sigma * *sigma; + } else if (a >= 0.f) { + eta = (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / ( + c__ * 2.f); + } else { + eta = b * 2.f / (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta > 0.f) { + eta = -w / (dpsi + dphi); + } + temp = eta - dtnsq; + if (temp > *rho) { + eta = *rho + dtnsq; + } + + tau += eta; + eta /= *sigma + sqrt(eta + *sigma * *sigma); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; + work[j] += eta; +/* L50: */ + } + + *sigma += eta; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L60: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / (work[*n] * delta[*n]); + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8.f + erretm - phi + rhoinv + dabs(tau) * ( + dpsi + dphi); + + w = rhoinv + phi + psi; + +/* Main loop to update the values of the array DELTA */ + + iter = niter + 1; + + for (niter = iter; niter <= 20; ++niter) { + +/* Test for convergence */ + + if (dabs(w) <= eps * erretm) { + goto L240; + } + +/* Calculate the new step */ + + dtnsq1 = work[*n - 1] * delta[*n - 1]; + dtnsq = work[*n] * delta[*n]; + c__ = w - dtnsq1 * dpsi - dtnsq * dphi; + a = (dtnsq + dtnsq1) * w - dtnsq1 * dtnsq * (dpsi + dphi); + b = dtnsq1 * dtnsq * w; + if (a >= 0.f) { + eta = (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / + (c__ * 2.f); + } else { + eta = b * 2.f / (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta > 0.f) { + eta = -w / (dpsi + dphi); + } + temp = eta - dtnsq; + if (temp <= 0.f) { + eta /= 2.f; + } + + tau += eta; + eta /= *sigma + sqrt(eta + *sigma * *sigma); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + delta[j] -= eta; + work[j] += eta; +/* L70: */ + } + + *sigma += eta; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = ii; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L80: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + temp = z__[*n] / (work[*n] * delta[*n]); + phi = z__[*n] * temp; + dphi = temp * temp; + erretm = (-phi - psi) * 8.f + erretm - phi + rhoinv + dabs(tau) * + (dpsi + dphi); + + w = rhoinv + phi + psi; +/* L90: */ + } + +/* Return with INFO = 1, NITER = MAXIT and not converged */ + + *info = 1; + goto L240; + +/* End for the case I = N */ + + } else { + +/* The case for I < N */ + + niter = 1; + ip1 = *i__ + 1; + +/* Calculate initial guess */ + + delsq = (d__[ip1] - d__[*i__]) * (d__[ip1] + d__[*i__]); + delsq2 = delsq / 2.f; + temp = delsq2 / (d__[*i__] + sqrt(d__[*i__] * d__[*i__] + delsq2)); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] = d__[j] + d__[*i__] + temp; + delta[j] = d__[j] - d__[*i__] - temp; +/* L100: */ + } + + psi = 0.f; + i__1 = *i__ - 1; + for (j = 1; j <= i__1; ++j) { + psi += z__[j] * z__[j] / (work[j] * delta[j]); +/* L110: */ + } + + phi = 0.f; + i__1 = *i__ + 2; + for (j = *n; j >= i__1; --j) { + phi += z__[j] * z__[j] / (work[j] * delta[j]); +/* L120: */ + } + c__ = rhoinv + psi + phi; + w = c__ + z__[*i__] * z__[*i__] / (work[*i__] * delta[*i__]) + z__[ + ip1] * z__[ip1] / (work[ip1] * delta[ip1]); + + if (w > 0.f) { + +/* + d(i)^2 < the ith sigma^2 < (d(i)^2+d(i+1)^2)/2 + + We choose d(i) as origin. +*/ + + orgati = TRUE_; + sg2lb = 0.f; + sg2ub = delsq2; + a = c__ * delsq + z__[*i__] * z__[*i__] + z__[ip1] * z__[ip1]; + b = z__[*i__] * z__[*i__] * delsq; + if (a > 0.f) { + tau = b * 2.f / (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } else { + tau = (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / + (c__ * 2.f); + } + +/* + TAU now is an estimation of SIGMA^2 - D( I )^2. The + following, however, is the corresponding estimation of + SIGMA - D( I ). +*/ + + eta = tau / (d__[*i__] + sqrt(d__[*i__] * d__[*i__] + tau)); + } else { + +/* + (d(i)^2+d(i+1)^2)/2 <= the ith sigma^2 < d(i+1)^2/2 + + We choose d(i+1) as origin. +*/ + + orgati = FALSE_; + sg2lb = -delsq2; + sg2ub = 0.f; + a = c__ * delsq - z__[*i__] * z__[*i__] - z__[ip1] * z__[ip1]; + b = z__[ip1] * z__[ip1] * delsq; + if (a < 0.f) { + tau = b * 2.f / (a - sqrt((r__1 = a * a + b * 4.f * c__, dabs( + r__1)))); + } else { + tau = -(a + sqrt((r__1 = a * a + b * 4.f * c__, dabs(r__1)))) + / (c__ * 2.f); + } + +/* + TAU now is an estimation of SIGMA^2 - D( IP1 )^2. The + following, however, is the corresponding estimation of + SIGMA - D( IP1 ). +*/ + + eta = tau / (d__[ip1] + sqrt((r__1 = d__[ip1] * d__[ip1] + tau, + dabs(r__1)))); + } + + if (orgati) { + ii = *i__; + *sigma = d__[*i__] + eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] = d__[j] + d__[*i__] + eta; + delta[j] = d__[j] - d__[*i__] - eta; +/* L130: */ + } + } else { + ii = *i__ + 1; + *sigma = d__[ip1] + eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] = d__[j] + d__[ip1] + eta; + delta[j] = d__[j] - d__[ip1] - eta; +/* L140: */ + } + } + iim1 = ii - 1; + iip1 = ii + 1; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L150: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.f; + phi = 0.f; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / (work[j] * delta[j]); + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L160: */ + } + + w = rhoinv + phi + psi; + +/* + W is the value of the secular function with + its ii-th element removed. +*/ + + swtch3 = FALSE_; + if (orgati) { + if (w < 0.f) { + swtch3 = TRUE_; + } + } else { + if (w > 0.f) { + swtch3 = TRUE_; + } + } + if (ii == 1 || ii == *n) { + swtch3 = FALSE_; + } + + temp = z__[ii] / (work[ii] * delta[ii]); + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w += temp; + erretm = (phi - psi) * 8.f + erretm + rhoinv * 2.f + dabs(temp) * 3.f + + dabs(tau) * dw; + +/* Test for convergence */ + + if (dabs(w) <= eps * erretm) { + goto L240; + } + + if (w <= 0.f) { + sg2lb = dmax(sg2lb,tau); + } else { + sg2ub = dmin(sg2ub,tau); + } + +/* Calculate the new step */ + + ++niter; + if (! swtch3) { + dtipsq = work[ip1] * delta[ip1]; + dtisq = work[*i__] * delta[*i__]; + if (orgati) { +/* Computing 2nd power */ + r__1 = z__[*i__] / dtisq; + c__ = w - dtipsq * dw + delsq * (r__1 * r__1); + } else { +/* Computing 2nd power */ + r__1 = z__[ip1] / dtipsq; + c__ = w - dtisq * dw - delsq * (r__1 * r__1); + } + a = (dtipsq + dtisq) * w - dtipsq * dtisq * dw; + b = dtipsq * dtisq * w; + if (c__ == 0.f) { + if (a == 0.f) { + if (orgati) { + a = z__[*i__] * z__[*i__] + dtipsq * dtipsq * (dpsi + + dphi); + } else { + a = z__[ip1] * z__[ip1] + dtisq * dtisq * (dpsi + + dphi); + } + } + eta = b / a; + } else if (a <= 0.f) { + eta = (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)))) / + (c__ * 2.f); + } else { + eta = b * 2.f / (a + sqrt((r__1 = a * a - b * 4.f * c__, dabs( + r__1)))); + } + } else { + +/* Interpolation using THREE most relevant poles */ + + dtiim = work[iim1] * delta[iim1]; + dtiip = work[iip1] * delta[iip1]; + temp = rhoinv + psi + phi; + if (orgati) { + temp1 = z__[iim1] / dtiim; + temp1 *= temp1; + c__ = temp - dtiip * (dpsi + dphi) - (d__[iim1] - d__[iip1]) * + (d__[iim1] + d__[iip1]) * temp1; + zz[0] = z__[iim1] * z__[iim1]; + if (dpsi < temp1) { + zz[2] = dtiip * dtiip * dphi; + } else { + zz[2] = dtiip * dtiip * (dpsi - temp1 + dphi); + } + } else { + temp1 = z__[iip1] / dtiip; + temp1 *= temp1; + c__ = temp - dtiim * (dpsi + dphi) - (d__[iip1] - d__[iim1]) * + (d__[iim1] + d__[iip1]) * temp1; + if (dphi < temp1) { + zz[0] = dtiim * dtiim * dpsi; + } else { + zz[0] = dtiim * dtiim * (dpsi + (dphi - temp1)); + } + zz[2] = z__[iip1] * z__[iip1]; + } + zz[1] = z__[ii] * z__[ii]; + dd[0] = dtiim; + dd[1] = delta[ii] * work[ii]; + dd[2] = dtiip; + slaed6_(&niter, &orgati, &c__, dd, zz, &w, &eta, info); + if (*info != 0) { + goto L240; + } + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta >= 0.f) { + eta = -w / dw; + } + if (orgati) { + temp1 = work[*i__] * delta[*i__]; + temp = eta - temp1; + } else { + temp1 = work[ip1] * delta[ip1]; + temp = eta - temp1; + } + if (temp > sg2ub || temp < sg2lb) { + if (w < 0.f) { + eta = (sg2ub - tau) / 2.f; + } else { + eta = (sg2lb - tau) / 2.f; + } + } + + tau += eta; + eta /= *sigma + sqrt(*sigma * *sigma + eta); + + prew = w; + + *sigma += eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] += eta; + delta[j] -= eta; +/* L170: */ + } + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L180: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.f; + phi = 0.f; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / (work[j] * delta[j]); + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L190: */ + } + + temp = z__[ii] / (work[ii] * delta[ii]); + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w = rhoinv + phi + psi + temp; + erretm = (phi - psi) * 8.f + erretm + rhoinv * 2.f + dabs(temp) * 3.f + + dabs(tau) * dw; + + if (w <= 0.f) { + sg2lb = dmax(sg2lb,tau); + } else { + sg2ub = dmin(sg2ub,tau); + } + + swtch = FALSE_; + if (orgati) { + if (-w > dabs(prew) / 10.f) { + swtch = TRUE_; + } + } else { + if (w > dabs(prew) / 10.f) { + swtch = TRUE_; + } + } + +/* Main loop to update the values of the array DELTA and WORK */ + + iter = niter + 1; + + for (niter = iter; niter <= 20; ++niter) { + +/* Test for convergence */ + + if (dabs(w) <= eps * erretm) { + goto L240; + } + +/* Calculate the new step */ + + if (! swtch3) { + dtipsq = work[ip1] * delta[ip1]; + dtisq = work[*i__] * delta[*i__]; + if (! swtch) { + if (orgati) { +/* Computing 2nd power */ + r__1 = z__[*i__] / dtisq; + c__ = w - dtipsq * dw + delsq * (r__1 * r__1); + } else { +/* Computing 2nd power */ + r__1 = z__[ip1] / dtipsq; + c__ = w - dtisq * dw - delsq * (r__1 * r__1); + } + } else { + temp = z__[ii] / (work[ii] * delta[ii]); + if (orgati) { + dpsi += temp * temp; + } else { + dphi += temp * temp; + } + c__ = w - dtisq * dpsi - dtipsq * dphi; + } + a = (dtipsq + dtisq) * w - dtipsq * dtisq * dw; + b = dtipsq * dtisq * w; + if (c__ == 0.f) { + if (a == 0.f) { + if (! swtch) { + if (orgati) { + a = z__[*i__] * z__[*i__] + dtipsq * dtipsq * + (dpsi + dphi); + } else { + a = z__[ip1] * z__[ip1] + dtisq * dtisq * ( + dpsi + dphi); + } + } else { + a = dtisq * dtisq * dpsi + dtipsq * dtipsq * dphi; + } + } + eta = b / a; + } else if (a <= 0.f) { + eta = (a - sqrt((r__1 = a * a - b * 4.f * c__, dabs(r__1)) + )) / (c__ * 2.f); + } else { + eta = b * 2.f / (a + sqrt((r__1 = a * a - b * 4.f * c__, + dabs(r__1)))); + } + } else { + +/* Interpolation using THREE most relevant poles */ + + dtiim = work[iim1] * delta[iim1]; + dtiip = work[iip1] * delta[iip1]; + temp = rhoinv + psi + phi; + if (swtch) { + c__ = temp - dtiim * dpsi - dtiip * dphi; + zz[0] = dtiim * dtiim * dpsi; + zz[2] = dtiip * dtiip * dphi; + } else { + if (orgati) { + temp1 = z__[iim1] / dtiim; + temp1 *= temp1; + temp2 = (d__[iim1] - d__[iip1]) * (d__[iim1] + d__[ + iip1]) * temp1; + c__ = temp - dtiip * (dpsi + dphi) - temp2; + zz[0] = z__[iim1] * z__[iim1]; + if (dpsi < temp1) { + zz[2] = dtiip * dtiip * dphi; + } else { + zz[2] = dtiip * dtiip * (dpsi - temp1 + dphi); + } + } else { + temp1 = z__[iip1] / dtiip; + temp1 *= temp1; + temp2 = (d__[iip1] - d__[iim1]) * (d__[iim1] + d__[ + iip1]) * temp1; + c__ = temp - dtiim * (dpsi + dphi) - temp2; + if (dphi < temp1) { + zz[0] = dtiim * dtiim * dpsi; + } else { + zz[0] = dtiim * dtiim * (dpsi + (dphi - temp1)); + } + zz[2] = z__[iip1] * z__[iip1]; + } + } + dd[0] = dtiim; + dd[1] = delta[ii] * work[ii]; + dd[2] = dtiip; + slaed6_(&niter, &orgati, &c__, dd, zz, &w, &eta, info); + if (*info != 0) { + goto L240; + } + } + +/* + Note, eta should be positive if w is negative, and + eta should be negative otherwise. However, + if for some reason caused by roundoff, eta*w > 0, + we simply use one Newton step instead. This way + will guarantee eta*w < 0. +*/ + + if (w * eta >= 0.f) { + eta = -w / dw; + } + if (orgati) { + temp1 = work[*i__] * delta[*i__]; + temp = eta - temp1; + } else { + temp1 = work[ip1] * delta[ip1]; + temp = eta - temp1; + } + if (temp > sg2ub || temp < sg2lb) { + if (w < 0.f) { + eta = (sg2ub - tau) / 2.f; + } else { + eta = (sg2lb - tau) / 2.f; + } + } + + tau += eta; + eta /= *sigma + sqrt(*sigma * *sigma + eta); + + *sigma += eta; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + work[j] += eta; + delta[j] -= eta; +/* L200: */ + } + + prew = w; + +/* Evaluate PSI and the derivative DPSI */ + + dpsi = 0.f; + psi = 0.f; + erretm = 0.f; + i__1 = iim1; + for (j = 1; j <= i__1; ++j) { + temp = z__[j] / (work[j] * delta[j]); + psi += z__[j] * temp; + dpsi += temp * temp; + erretm += psi; +/* L210: */ + } + erretm = dabs(erretm); + +/* Evaluate PHI and the derivative DPHI */ + + dphi = 0.f; + phi = 0.f; + i__1 = iip1; + for (j = *n; j >= i__1; --j) { + temp = z__[j] / (work[j] * delta[j]); + phi += z__[j] * temp; + dphi += temp * temp; + erretm += phi; +/* L220: */ + } + + temp = z__[ii] / (work[ii] * delta[ii]); + dw = dpsi + dphi + temp * temp; + temp = z__[ii] * temp; + w = rhoinv + phi + psi + temp; + erretm = (phi - psi) * 8.f + erretm + rhoinv * 2.f + dabs(temp) * + 3.f + dabs(tau) * dw; + if (w * prew > 0.f && dabs(w) > dabs(prew) / 10.f) { + swtch = ! swtch; + } + + if (w <= 0.f) { + sg2lb = dmax(sg2lb,tau); + } else { + sg2ub = dmin(sg2ub,tau); + } + +/* L230: */ + } + +/* Return with INFO = 1, NITER = MAXIT and not converged */ + + *info = 1; + + } + +L240: + return 0; + +/* End of SLASD4 */ + +} /* slasd4_ */ + +/* Subroutine */ int slasd5_(integer *i__, real *d__, real *z__, real *delta, + real *rho, real *dsigma, real *work) +{ + /* System generated locals */ + real r__1; + + /* Local variables */ + static real b, c__, w, del, tau, delsq; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + This subroutine computes the square root of the I-th eigenvalue + of a positive symmetric rank-one modification of a 2-by-2 diagonal + matrix + + diag( D ) * diag( D ) + RHO * Z * transpose(Z) . + + The diagonal entries in the array D are assumed to satisfy + + 0 <= D(i) < D(j) for i < j . + + We also assume RHO > 0 and that the Euclidean norm of the vector + Z is one. + + Arguments + ========= + + I (input) INTEGER + The index of the eigenvalue to be computed. I = 1 or I = 2. + + D (input) REAL array, dimension (2) + The original eigenvalues. We assume 0 <= D(1) < D(2). + + Z (input) REAL array, dimension (2) + The components of the updating vector. + + DELTA (output) REAL array, dimension (2) + Contains (D(j) - sigma_I) in its j-th component. + The vector DELTA contains the information necessary + to construct the eigenvectors. + + RHO (input) REAL + The scalar in the symmetric updating formula. + + DSIGMA (output) REAL + The computed sigma_I, the I-th updated eigenvalue. + + WORK (workspace) REAL array, dimension (2) + WORK contains (D(j) + sigma_I) in its j-th component. + + Further Details + =============== + + Based on contributions by + Ren-Cang Li, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --work; + --delta; + --z__; + --d__; + + /* Function Body */ + del = d__[2] - d__[1]; + delsq = del * (d__[2] + d__[1]); + if (*i__ == 1) { + w = *rho * 4.f * (z__[2] * z__[2] / (d__[1] + d__[2] * 3.f) - z__[1] * + z__[1] / (d__[1] * 3.f + d__[2])) / del + 1.f; + if (w > 0.f) { + b = delsq + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[1] * z__[1] * delsq; + +/* + B > ZERO, always + + The following TAU is DSIGMA * DSIGMA - D( 1 ) * D( 1 ) +*/ + + tau = c__ * 2.f / (b + sqrt((r__1 = b * b - c__ * 4.f, dabs(r__1)) + )); + +/* The following TAU is DSIGMA - D( 1 ) */ + + tau /= d__[1] + sqrt(d__[1] * d__[1] + tau); + *dsigma = d__[1] + tau; + delta[1] = -tau; + delta[2] = del - tau; + work[1] = d__[1] * 2.f + tau; + work[2] = d__[1] + tau + d__[2]; +/* + DELTA( 1 ) = -Z( 1 ) / TAU + DELTA( 2 ) = Z( 2 ) / ( DEL-TAU ) +*/ + } else { + b = -delsq + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[2] * z__[2] * delsq; + +/* The following TAU is DSIGMA * DSIGMA - D( 2 ) * D( 2 ) */ + + if (b > 0.f) { + tau = c__ * -2.f / (b + sqrt(b * b + c__ * 4.f)); + } else { + tau = (b - sqrt(b * b + c__ * 4.f)) / 2.f; + } + +/* The following TAU is DSIGMA - D( 2 ) */ + + tau /= d__[2] + sqrt((r__1 = d__[2] * d__[2] + tau, dabs(r__1))); + *dsigma = d__[2] + tau; + delta[1] = -(del + tau); + delta[2] = -tau; + work[1] = d__[1] + tau + d__[2]; + work[2] = d__[2] * 2.f + tau; +/* + DELTA( 1 ) = -Z( 1 ) / ( DEL+TAU ) + DELTA( 2 ) = -Z( 2 ) / TAU +*/ + } +/* + TEMP = SQRT( DELTA( 1 )*DELTA( 1 )+DELTA( 2 )*DELTA( 2 ) ) + DELTA( 1 ) = DELTA( 1 ) / TEMP + DELTA( 2 ) = DELTA( 2 ) / TEMP +*/ + } else { + +/* Now I=2 */ + + b = -delsq + *rho * (z__[1] * z__[1] + z__[2] * z__[2]); + c__ = *rho * z__[2] * z__[2] * delsq; + +/* The following TAU is DSIGMA * DSIGMA - D( 2 ) * D( 2 ) */ + + if (b > 0.f) { + tau = (b + sqrt(b * b + c__ * 4.f)) / 2.f; + } else { + tau = c__ * 2.f / (-b + sqrt(b * b + c__ * 4.f)); + } + +/* The following TAU is DSIGMA - D( 2 ) */ + + tau /= d__[2] + sqrt(d__[2] * d__[2] + tau); + *dsigma = d__[2] + tau; + delta[1] = -(del + tau); + delta[2] = -tau; + work[1] = d__[1] + tau + d__[2]; + work[2] = d__[2] * 2.f + tau; +/* + DELTA( 1 ) = -Z( 1 ) / ( DEL+TAU ) + DELTA( 2 ) = -Z( 2 ) / TAU + TEMP = SQRT( DELTA( 1 )*DELTA( 1 )+DELTA( 2 )*DELTA( 2 ) ) + DELTA( 1 ) = DELTA( 1 ) / TEMP + DELTA( 2 ) = DELTA( 2 ) / TEMP +*/ + } + return 0; + +/* End of SLASD5 */ + +} /* slasd5_ */ + +/* Subroutine */ int slasd6_(integer *icompq, integer *nl, integer *nr, + integer *sqre, real *d__, real *vf, real *vl, real *alpha, real *beta, + integer *idxq, integer *perm, integer *givptr, integer *givcol, + integer *ldgcol, real *givnum, integer *ldgnum, real *poles, real * + difl, real *difr, real *z__, integer *k, real *c__, real *s, real * + work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, givnum_dim1, givnum_offset, + poles_dim1, poles_offset, i__1; + real r__1, r__2; + + /* Local variables */ + static integer i__, m, n, n1, n2, iw, idx, idxc, idxp, ivfw, ivlw; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *), slasd7_(integer *, integer *, integer *, integer *, + integer *, real *, real *, real *, real *, real *, real *, real *, + real *, real *, real *, integer *, integer *, integer *, integer + *, integer *, integer *, integer *, real *, integer *, real *, + real *, integer *), slasd8_(integer *, integer *, real *, real *, + real *, real *, real *, real *, integer *, real *, real *, + integer *); + static integer isigma; + extern /* Subroutine */ int xerbla_(char *, integer *), slascl_( + char *, integer *, integer *, real *, real *, integer *, integer * + , real *, integer *, integer *), slamrg_(integer *, + integer *, real *, integer *, integer *, integer *); + static real orgnrm; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SLASD6 computes the SVD of an updated upper bidiagonal matrix B + obtained by merging two smaller ones by appending a row. This + routine is used only for the problem which requires all singular + values and optionally singular vector matrices in factored form. + B is an N-by-M matrix with N = NL + NR + 1 and M = N + SQRE. + A related subroutine, SLASD1, handles the case in which all singular + values and singular vectors of the bidiagonal matrix are desired. + + SLASD6 computes the SVD as follows: + + ( D1(in) 0 0 0 ) + B = U(in) * ( Z1' a Z2' b ) * VT(in) + ( 0 0 D2(in) 0 ) + + = U(out) * ( D(out) 0) * VT(out) + + where Z' = (Z1' a Z2' b) = u' VT', and u is a vector of dimension M + with ALPHA and BETA in the NL+1 and NL+2 th entries and zeros + elsewhere; and the entry b is empty if SQRE = 0. + + The singular values of B can be computed using D1, D2, the first + components of all the right singular vectors of the lower block, and + the last components of all the right singular vectors of the upper + block. These components are stored and updated in VF and VL, + respectively, in SLASD6. Hence U and VT are not explicitly + referenced. + + The singular values are stored in D. The algorithm consists of two + stages: + + The first stage consists of deflating the size of the problem + when there are multiple singular values or if there is a zero + in the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine SLASD7. + + The second stage consists of calculating the updated + singular values. This is done by finding the roots of the + secular equation via the routine SLASD4 (as called by SLASD8). + This routine also updates VF and VL and computes the distances + between the updated singular values and the old singular + values. + + SLASD6 is called from SLASDA. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed in + factored form: + = 0: Compute singular values only. + = 1: Compute singular vectors in factored form as well. + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has row dimension N = NL + NR + 1, + and column dimension M = N + SQRE. + + D (input/output) REAL array, dimension (NL+NR+1). + On entry D(1:NL,1:NL) contains the singular values of the + upper block, and D(NL+2:N) contains the singular values + of the lower block. On exit D(1:N) contains the singular + values of the modified matrix. + + VF (input/output) REAL array, dimension (M) + On entry, VF(1:NL+1) contains the first components of all + right singular vectors of the upper block; and VF(NL+2:M) + contains the first components of all right singular vectors + of the lower block. On exit, VF contains the first components + of all right singular vectors of the bidiagonal matrix. + + VL (input/output) REAL array, dimension (M) + On entry, VL(1:NL+1) contains the last components of all + right singular vectors of the upper block; and VL(NL+2:M) + contains the last components of all right singular vectors of + the lower block. On exit, VL contains the last components of + all right singular vectors of the bidiagonal matrix. + + ALPHA (input/output) REAL + Contains the diagonal element associated with the added row. + + BETA (input/output) REAL + Contains the off-diagonal element associated with the added + row. + + IDXQ (output) INTEGER array, dimension (N) + This contains the permutation which will reintegrate the + subproblem just solved back into sorted order, i.e. + D( IDXQ( I = 1, N ) ) will be in ascending order. + + PERM (output) INTEGER array, dimension ( N ) + The permutations (from deflation and sorting) to be applied + to each block. Not referenced if ICOMPQ = 0. + + GIVPTR (output) INTEGER + The number of Givens rotations which took place in this + subproblem. Not referenced if ICOMPQ = 0. + + GIVCOL (output) INTEGER array, dimension ( LDGCOL, 2 ) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. Not referenced if ICOMPQ = 0. + + LDGCOL (input) INTEGER + leading dimension of GIVCOL, must be at least N. + + GIVNUM (output) REAL array, dimension ( LDGNUM, 2 ) + Each number indicates the C or S value to be used in the + corresponding Givens rotation. Not referenced if ICOMPQ = 0. + + LDGNUM (input) INTEGER + The leading dimension of GIVNUM and POLES, must be at least N. + + POLES (output) REAL array, dimension ( LDGNUM, 2 ) + On exit, POLES(1,*) is an array containing the new singular + values obtained from solving the secular equation, and + POLES(2,*) is an array containing the poles in the secular + equation. Not referenced if ICOMPQ = 0. + + DIFL (output) REAL array, dimension ( N ) + On exit, DIFL(I) is the distance between I-th updated + (undeflated) singular value and the I-th (undeflated) old + singular value. + + DIFR (output) REAL array, + dimension ( LDGNUM, 2 ) if ICOMPQ = 1 and + dimension ( N ) if ICOMPQ = 0. + On exit, DIFR(I, 1) is the distance between I-th updated + (undeflated) singular value and the I+1-th (undeflated) old + singular value. + + If ICOMPQ = 1, DIFR(1:K,2) is an array containing the + normalizing factors for the right singular vector matrix. + + See SLASD8 for details on DIFL and DIFR. + + Z (output) REAL array, dimension ( M ) + The first elements of this array contain the components + of the deflation-adjusted updating row vector. + + K (output) INTEGER + Contains the dimension of the non-deflated matrix, + This is the order of the related secular equation. 1 <= K <=N. + + C (output) REAL + C contains garbage if SQRE =0 and the C-value of a Givens + rotation related to the right null space if SQRE = 1. + + S (output) REAL + S contains garbage if SQRE =0 and the S-value of a Givens + rotation related to the right null space if SQRE = 1. + + WORK (workspace) REAL array, dimension ( 4 * M ) + + IWORK (workspace) INTEGER array, dimension ( 3 * N ) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --vf; + --vl; + --idxq; + --perm; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + poles_dim1 = *ldgnum; + poles_offset = 1 + poles_dim1; + poles -= poles_offset; + givnum_dim1 = *ldgnum; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + --difl; + --difr; + --z__; + --work; + --iwork; + + /* Function Body */ + *info = 0; + n = *nl + *nr + 1; + m = n + *sqre; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*nl < 1) { + *info = -2; + } else if (*nr < 1) { + *info = -3; + } else if (*sqre < 0 || *sqre > 1) { + *info = -4; + } else if (*ldgcol < n) { + *info = -14; + } else if (*ldgnum < n) { + *info = -16; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASD6", &i__1); + return 0; + } + +/* + The following values are for bookkeeping purposes only. They are + integer pointers which indicate the portion of the workspace + used by a particular array in SLASD7 and SLASD8. +*/ + + isigma = 1; + iw = isigma + n; + ivfw = iw + m; + ivlw = ivfw + m; + + idx = 1; + idxc = idx + n; + idxp = idxc + n; + +/* + Scale. + + Computing MAX +*/ + r__1 = dabs(*alpha), r__2 = dabs(*beta); + orgnrm = dmax(r__1,r__2); + d__[*nl + 1] = 0.f; + i__1 = n; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((r__1 = d__[i__], dabs(r__1)) > orgnrm) { + orgnrm = (r__1 = d__[i__], dabs(r__1)); + } +/* L10: */ + } + slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &n, &c__1, &d__[1], &n, info); + *alpha /= orgnrm; + *beta /= orgnrm; + +/* Sort and Deflate singular values. */ + + slasd7_(icompq, nl, nr, sqre, k, &d__[1], &z__[1], &work[iw], &vf[1], & + work[ivfw], &vl[1], &work[ivlw], alpha, beta, &work[isigma], & + iwork[idx], &iwork[idxp], &idxq[1], &perm[1], givptr, &givcol[ + givcol_offset], ldgcol, &givnum[givnum_offset], ldgnum, c__, s, + info); + +/* Solve Secular Equation, compute DIFL, DIFR, and update VF, VL. */ + + slasd8_(icompq, k, &d__[1], &z__[1], &vf[1], &vl[1], &difl[1], &difr[1], + ldgnum, &work[isigma], &work[iw], info); + +/* Save the poles if ICOMPQ = 1. */ + + if (*icompq == 1) { + scopy_(k, &d__[1], &c__1, &poles[poles_dim1 + 1], &c__1); + scopy_(k, &work[isigma], &c__1, &poles[(poles_dim1 << 1) + 1], &c__1); + } + +/* Unscale. */ + + slascl_("G", &c__0, &c__0, &c_b15, &orgnrm, &n, &c__1, &d__[1], &n, info); + +/* Prepare the IDXQ sorting permutation. */ + + n1 = *k; + n2 = n - *k; + slamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &idxq[1]); + + return 0; + +/* End of SLASD6 */ + +} /* slasd6_ */ + +/* Subroutine */ int slasd7_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *k, real *d__, real *z__, real *zw, real *vf, + real *vfw, real *vl, real *vlw, real *alpha, real *beta, real *dsigma, + integer *idx, integer *idxp, integer *idxq, integer *perm, integer * + givptr, integer *givcol, integer *ldgcol, real *givnum, integer * + ldgnum, real *c__, real *s, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, givnum_dim1, givnum_offset, i__1; + real r__1, r__2; + + /* Local variables */ + static integer i__, j, m, n, k2; + static real z1; + static integer jp; + static real eps, tau, tol; + static integer nlp1, nlp2, idxi, idxj; + extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, + integer *, real *, real *); + static integer idxjp, jprev; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + extern doublereal slapy2_(real *, real *), slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *), slamrg_( + integer *, integer *, real *, integer *, integer *, integer *); + static real hlftol; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASD7 merges the two sets of singular values together into a single + sorted set. Then it tries to deflate the size of the problem. There + are two ways in which deflation can occur: when two or more singular + values are close together or if there is a tiny entry in the Z + vector. For each such occurrence the order of the related + secular equation problem is reduced by one. + + SLASD7 is called from SLASD6. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed + in compact form, as follows: + = 0: Compute singular values only. + = 1: Compute singular vectors of upper + bidiagonal matrix in compact form. + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has + N = NL + NR + 1 rows and + M = N + SQRE >= N columns. + + K (output) INTEGER + Contains the dimension of the non-deflated matrix, this is + the order of the related secular equation. 1 <= K <=N. + + D (input/output) REAL array, dimension ( N ) + On entry D contains the singular values of the two submatrices + to be combined. On exit D contains the trailing (N-K) updated + singular values (those which were deflated) sorted into + increasing order. + + Z (output) REAL array, dimension ( M ) + On exit Z contains the updating row vector in the secular + equation. + + ZW (workspace) REAL array, dimension ( M ) + Workspace for Z. + + VF (input/output) REAL array, dimension ( M ) + On entry, VF(1:NL+1) contains the first components of all + right singular vectors of the upper block; and VF(NL+2:M) + contains the first components of all right singular vectors + of the lower block. On exit, VF contains the first components + of all right singular vectors of the bidiagonal matrix. + + VFW (workspace) REAL array, dimension ( M ) + Workspace for VF. + + VL (input/output) REAL array, dimension ( M ) + On entry, VL(1:NL+1) contains the last components of all + right singular vectors of the upper block; and VL(NL+2:M) + contains the last components of all right singular vectors + of the lower block. On exit, VL contains the last components + of all right singular vectors of the bidiagonal matrix. + + VLW (workspace) REAL array, dimension ( M ) + Workspace for VL. + + ALPHA (input) REAL + Contains the diagonal element associated with the added row. + + BETA (input) REAL + Contains the off-diagonal element associated with the added + row. + + DSIGMA (output) REAL array, dimension ( N ) + Contains a copy of the diagonal elements (K-1 singular values + and one zero) in the secular equation. + + IDX (workspace) INTEGER array, dimension ( N ) + This will contain the permutation used to sort the contents of + D into ascending order. + + IDXP (workspace) INTEGER array, dimension ( N ) + This will contain the permutation used to place deflated + values of D at the end of the array. On output IDXP(2:K) + points to the nondeflated D-values and IDXP(K+1:N) + points to the deflated singular values. + + IDXQ (input) INTEGER array, dimension ( N ) + This contains the permutation which separately sorts the two + sub-problems in D into ascending order. Note that entries in + the first half of this permutation must first be moved one + position backward; and entries in the second half + must first have NL+1 added to their values. + + PERM (output) INTEGER array, dimension ( N ) + The permutations (from deflation and sorting) to be applied + to each singular block. Not referenced if ICOMPQ = 0. + + GIVPTR (output) INTEGER + The number of Givens rotations which took place in this + subproblem. Not referenced if ICOMPQ = 0. + + GIVCOL (output) INTEGER array, dimension ( LDGCOL, 2 ) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. Not referenced if ICOMPQ = 0. + + LDGCOL (input) INTEGER + The leading dimension of GIVCOL, must be at least N. + + GIVNUM (output) REAL array, dimension ( LDGNUM, 2 ) + Each number indicates the C or S value to be used in the + corresponding Givens rotation. Not referenced if ICOMPQ = 0. + + LDGNUM (input) INTEGER + The leading dimension of GIVNUM, must be at least N. + + C (output) REAL + C contains garbage if SQRE =0 and the C-value of a Givens + rotation related to the right null space if SQRE = 1. + + S (output) REAL + S contains garbage if SQRE =0 and the S-value of a Givens + rotation related to the right null space if SQRE = 1. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --z__; + --zw; + --vf; + --vfw; + --vl; + --vlw; + --dsigma; + --idx; + --idxp; + --idxq; + --perm; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + givnum_dim1 = *ldgnum; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + + /* Function Body */ + *info = 0; + n = *nl + *nr + 1; + m = n + *sqre; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*nl < 1) { + *info = -2; + } else if (*nr < 1) { + *info = -3; + } else if (*sqre < 0 || *sqre > 1) { + *info = -4; + } else if (*ldgcol < n) { + *info = -22; + } else if (*ldgnum < n) { + *info = -24; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASD7", &i__1); + return 0; + } + + nlp1 = *nl + 1; + nlp2 = *nl + 2; + if (*icompq == 1) { + *givptr = 0; + } + +/* + Generate the first part of the vector Z and move the singular + values in the first part of D one position backward. +*/ + + z1 = *alpha * vl[nlp1]; + vl[nlp1] = 0.f; + tau = vf[nlp1]; + for (i__ = *nl; i__ >= 1; --i__) { + z__[i__ + 1] = *alpha * vl[i__]; + vl[i__] = 0.f; + vf[i__ + 1] = vf[i__]; + d__[i__ + 1] = d__[i__]; + idxq[i__ + 1] = idxq[i__] + 1; +/* L10: */ + } + vf[1] = tau; + +/* Generate the second part of the vector Z. */ + + i__1 = m; + for (i__ = nlp2; i__ <= i__1; ++i__) { + z__[i__] = *beta * vf[i__]; + vf[i__] = 0.f; +/* L20: */ + } + +/* Sort the singular values into increasing order */ + + i__1 = n; + for (i__ = nlp2; i__ <= i__1; ++i__) { + idxq[i__] += nlp1; +/* L30: */ + } + +/* DSIGMA, IDXC, IDXC, and ZW are used as storage space. */ + + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + dsigma[i__] = d__[idxq[i__]]; + zw[i__] = z__[idxq[i__]]; + vfw[i__] = vf[idxq[i__]]; + vlw[i__] = vl[idxq[i__]]; +/* L40: */ + } + + slamrg_(nl, nr, &dsigma[2], &c__1, &c__1, &idx[2]); + + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + idxi = idx[i__] + 1; + d__[i__] = dsigma[idxi]; + z__[i__] = zw[idxi]; + vf[i__] = vfw[idxi]; + vl[i__] = vlw[idxi]; +/* L50: */ + } + +/* Calculate the allowable deflation tolerence */ + + eps = slamch_("Epsilon"); +/* Computing MAX */ + r__1 = dabs(*alpha), r__2 = dabs(*beta); + tol = dmax(r__1,r__2); +/* Computing MAX */ + r__2 = (r__1 = d__[n], dabs(r__1)); + tol = eps * 64.f * dmax(r__2,tol); + +/* + There are 2 kinds of deflation -- first a value in the z-vector + is small, second two (or more) singular values are very close + together (their difference is small). + + If the value in the z-vector is small, we simply permute the + array so that the corresponding singular value is moved to the + end. + + If two values in the D-vector are close, we perform a two-sided + rotation designed to make one of the corresponding z-vector + entries zero, and then permute the array so that the deflated + singular value is moved to the end. + + If there are multiple singular values then the problem deflates. + Here the number of equal singular values are found. As each equal + singular value is found, an elementary reflector is computed to + rotate the corresponding singular subspace so that the + corresponding components of Z are zero in this new basis. +*/ + + *k = 1; + k2 = n + 1; + i__1 = n; + for (j = 2; j <= i__1; ++j) { + if ((r__1 = z__[j], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + idxp[k2] = j; + if (j == n) { + goto L100; + } + } else { + jprev = j; + goto L70; + } +/* L60: */ + } +L70: + j = jprev; +L80: + ++j; + if (j > n) { + goto L90; + } + if ((r__1 = z__[j], dabs(r__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + idxp[k2] = j; + } else { + +/* Check if singular values are close enough to allow deflation. */ + + if ((r__1 = d__[j] - d__[jprev], dabs(r__1)) <= tol) { + +/* Deflation is possible. */ + + *s = z__[jprev]; + *c__ = z__[j]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = slapy2_(c__, s); + z__[j] = tau; + z__[jprev] = 0.f; + *c__ /= tau; + *s = -(*s) / tau; + +/* Record the appropriate Givens rotation */ + + if (*icompq == 1) { + ++(*givptr); + idxjp = idxq[idx[jprev] + 1]; + idxj = idxq[idx[j] + 1]; + if (idxjp <= nlp1) { + --idxjp; + } + if (idxj <= nlp1) { + --idxj; + } + givcol[*givptr + (givcol_dim1 << 1)] = idxjp; + givcol[*givptr + givcol_dim1] = idxj; + givnum[*givptr + (givnum_dim1 << 1)] = *c__; + givnum[*givptr + givnum_dim1] = *s; + } + srot_(&c__1, &vf[jprev], &c__1, &vf[j], &c__1, c__, s); + srot_(&c__1, &vl[jprev], &c__1, &vl[j], &c__1, c__, s); + --k2; + idxp[k2] = jprev; + jprev = j; + } else { + ++(*k); + zw[*k] = z__[jprev]; + dsigma[*k] = d__[jprev]; + idxp[*k] = jprev; + jprev = j; + } + } + goto L80; +L90: + +/* Record the last singular value. */ + + ++(*k); + zw[*k] = z__[jprev]; + dsigma[*k] = d__[jprev]; + idxp[*k] = jprev; + +L100: + +/* + Sort the singular values into DSIGMA. The singular values which + were not deflated go into the first K slots of DSIGMA, except + that DSIGMA(1) is treated separately. +*/ + + i__1 = n; + for (j = 2; j <= i__1; ++j) { + jp = idxp[j]; + dsigma[j] = d__[jp]; + vfw[j] = vf[jp]; + vlw[j] = vl[jp]; +/* L110: */ + } + if (*icompq == 1) { + i__1 = n; + for (j = 2; j <= i__1; ++j) { + jp = idxp[j]; + perm[j] = idxq[idx[jp] + 1]; + if (perm[j] <= nlp1) { + --perm[j]; + } +/* L120: */ + } + } + +/* + The deflated singular values go back into the last N - K slots of + D. +*/ + + i__1 = n - *k; + scopy_(&i__1, &dsigma[*k + 1], &c__1, &d__[*k + 1], &c__1); + +/* + Determine DSIGMA(1), DSIGMA(2), Z(1), VF(1), VL(1), VF(M), and + VL(M). +*/ + + dsigma[1] = 0.f; + hlftol = tol / 2.f; + if (dabs(dsigma[2]) <= hlftol) { + dsigma[2] = hlftol; + } + if (m > n) { + z__[1] = slapy2_(&z1, &z__[m]); + if (z__[1] <= tol) { + *c__ = 1.f; + *s = 0.f; + z__[1] = tol; + } else { + *c__ = z1 / z__[1]; + *s = -z__[m] / z__[1]; + } + srot_(&c__1, &vf[m], &c__1, &vf[1], &c__1, c__, s); + srot_(&c__1, &vl[m], &c__1, &vl[1], &c__1, c__, s); + } else { + if (dabs(z1) <= tol) { + z__[1] = tol; + } else { + z__[1] = z1; + } + } + +/* Restore Z, VF, and VL. */ + + i__1 = *k - 1; + scopy_(&i__1, &zw[2], &c__1, &z__[2], &c__1); + i__1 = n - 1; + scopy_(&i__1, &vfw[2], &c__1, &vf[2], &c__1); + i__1 = n - 1; + scopy_(&i__1, &vlw[2], &c__1, &vl[2], &c__1); + + return 0; + +/* End of SLASD7 */ + +} /* slasd7_ */ + +/* Subroutine */ int slasd8_(integer *icompq, integer *k, real *d__, real * + z__, real *vf, real *vl, real *difl, real *difr, integer *lddifr, + real *dsigma, real *work, integer *info) +{ + /* System generated locals */ + integer difr_dim1, difr_offset, i__1, i__2; + real r__1, r__2; + + /* Local variables */ + static integer i__, j; + static real dj, rho; + static integer iwk1, iwk2, iwk3; + static real temp; + extern doublereal sdot_(integer *, real *, integer *, real *, integer *); + static integer iwk2i, iwk3i; + extern doublereal snrm2_(integer *, real *, integer *); + static real diflj, difrj, dsigj; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + extern doublereal slamc3_(real *, real *); + extern /* Subroutine */ int slasd4_(integer *, integer *, real *, real *, + real *, real *, real *, real *, integer *), xerbla_(char *, + integer *); + static real dsigjp; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *), slaset_(char *, integer *, integer *, real *, real *, + real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SLASD8 finds the square roots of the roots of the secular equation, + as defined by the values in DSIGMA and Z. It makes the appropriate + calls to SLASD4, and stores, for each element in D, the distance + to its two nearest poles (elements in DSIGMA). It also updates + the arrays VF and VL, the first and last components of all the + right singular vectors of the original bidiagonal matrix. + + SLASD8 is called from SLASD6. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed in + factored form in the calling routine: + = 0: Compute singular values only. + = 1: Compute singular vectors in factored form as well. + + K (input) INTEGER + The number of terms in the rational function to be solved + by SLASD4. K >= 1. + + D (output) REAL array, dimension ( K ) + On output, D contains the updated singular values. + + Z (input/output) REAL array, dimension ( K ) + On entry, the first K elements of this array contain the + components of the deflation-adjusted updating row vector. + On exit, Z is updated. + + VF (input/output) REAL array, dimension ( K ) + On entry, VF contains information passed through DBEDE8. + On exit, VF contains the first K components of the first + components of all right singular vectors of the bidiagonal + matrix. + + VL (input/output) REAL array, dimension ( K ) + On entry, VL contains information passed through DBEDE8. + On exit, VL contains the first K components of the last + components of all right singular vectors of the bidiagonal + matrix. + + DIFL (output) REAL array, dimension ( K ) + On exit, DIFL(I) = D(I) - DSIGMA(I). + + DIFR (output) REAL array, + dimension ( LDDIFR, 2 ) if ICOMPQ = 1 and + dimension ( K ) if ICOMPQ = 0. + On exit, DIFR(I,1) = D(I) - DSIGMA(I+1), DIFR(K,1) is not + defined and will not be referenced. + + If ICOMPQ = 1, DIFR(1:K,2) is an array containing the + normalizing factors for the right singular vector matrix. + + LDDIFR (input) INTEGER + The leading dimension of DIFR, must be at least K. + + DSIGMA (input/output) REAL array, dimension ( K ) + On entry, the first K elements of this array contain the old + roots of the deflated updating problem. These are the poles + of the secular equation. + On exit, the elements of DSIGMA may be very slightly altered + in value. + + WORK (workspace) REAL array, dimension at least 3 * K + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --z__; + --vf; + --vl; + --difl; + difr_dim1 = *lddifr; + difr_offset = 1 + difr_dim1; + difr -= difr_offset; + --dsigma; + --work; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*k < 1) { + *info = -2; + } else if (*lddifr < *k) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASD8", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*k == 1) { + d__[1] = dabs(z__[1]); + difl[1] = d__[1]; + if (*icompq == 1) { + difl[2] = 1.f; + difr[(difr_dim1 << 1) + 1] = 1.f; + } + return 0; + } + +/* + Modify values DSIGMA(i) to make sure all DSIGMA(i)-DSIGMA(j) can + be computed with high relative accuracy (barring over/underflow). + This is a problem on machines without a guard digit in + add/subtract (Cray XMP, Cray YMP, Cray C 90 and Cray 2). + The following code replaces DSIGMA(I) by 2*DSIGMA(I)-DSIGMA(I), + which on any of these machines zeros out the bottommost + bit of DSIGMA(I) if it is 1; this makes the subsequent + subtractions DSIGMA(I)-DSIGMA(J) unproblematic when cancellation + occurs. On binary machines with a guard digit (almost all + machines) it does not change DSIGMA(I) at all. On hexadecimal + and decimal machines with a guard digit, it slightly + changes the bottommost bits of DSIGMA(I). It does not account + for hexadecimal or decimal machines without guard digits + (we know of none). We use a subroutine call to compute + 2*DLAMBDA(I) to prevent optimizing compilers from eliminating + this code. +*/ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + dsigma[i__] = slamc3_(&dsigma[i__], &dsigma[i__]) - dsigma[i__]; +/* L10: */ + } + +/* Book keeping. */ + + iwk1 = 1; + iwk2 = iwk1 + *k; + iwk3 = iwk2 + *k; + iwk2i = iwk2 - 1; + iwk3i = iwk3 - 1; + +/* Normalize Z. */ + + rho = snrm2_(k, &z__[1], &c__1); + slascl_("G", &c__0, &c__0, &rho, &c_b15, k, &c__1, &z__[1], k, info); + rho *= rho; + +/* Initialize WORK(IWK3). */ + + slaset_("A", k, &c__1, &c_b15, &c_b15, &work[iwk3], k); + +/* + Compute the updated singular values, the arrays DIFL, DIFR, + and the updated Z. +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + slasd4_(k, &j, &dsigma[1], &z__[1], &work[iwk1], &rho, &d__[j], &work[ + iwk2], info); + +/* If the root finder fails, the computation is terminated. */ + + if (*info != 0) { + return 0; + } + work[iwk3i + j] = work[iwk3i + j] * work[j] * work[iwk2i + j]; + difl[j] = -work[j]; + difr[j + difr_dim1] = -work[j + 1]; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + work[iwk3i + i__] = work[iwk3i + i__] * work[i__] * work[iwk2i + + i__] / (dsigma[i__] - dsigma[j]) / (dsigma[i__] + dsigma[ + j]); +/* L20: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + work[iwk3i + i__] = work[iwk3i + i__] * work[i__] * work[iwk2i + + i__] / (dsigma[i__] - dsigma[j]) / (dsigma[i__] + dsigma[ + j]); +/* L30: */ + } +/* L40: */ + } + +/* Compute updated Z. */ + + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + r__2 = sqrt((r__1 = work[iwk3i + i__], dabs(r__1))); + z__[i__] = r_sign(&r__2, &z__[i__]); +/* L50: */ + } + +/* Update VF and VL. */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + diflj = difl[j]; + dj = d__[j]; + dsigj = -dsigma[j]; + if (j < *k) { + difrj = -difr[j + difr_dim1]; + dsigjp = -dsigma[j + 1]; + } + work[j] = -z__[j] / diflj / (dsigma[j] + dj); + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] = z__[i__] / (slamc3_(&dsigma[i__], &dsigj) - diflj) / ( + dsigma[i__] + dj); +/* L60: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + work[i__] = z__[i__] / (slamc3_(&dsigma[i__], &dsigjp) + difrj) / + (dsigma[i__] + dj); +/* L70: */ + } + temp = snrm2_(k, &work[1], &c__1); + work[iwk2i + j] = sdot_(k, &work[1], &c__1, &vf[1], &c__1) / temp; + work[iwk3i + j] = sdot_(k, &work[1], &c__1, &vl[1], &c__1) / temp; + if (*icompq == 1) { + difr[j + (difr_dim1 << 1)] = temp; + } +/* L80: */ + } + + scopy_(k, &work[iwk2], &c__1, &vf[1], &c__1); + scopy_(k, &work[iwk3], &c__1, &vl[1], &c__1); + + return 0; + +/* End of SLASD8 */ + +} /* slasd8_ */ + +/* Subroutine */ int slasda_(integer *icompq, integer *smlsiz, integer *n, + integer *sqre, real *d__, real *e, real *u, integer *ldu, real *vt, + integer *k, real *difl, real *difr, real *z__, real *poles, integer * + givptr, integer *givcol, integer *ldgcol, integer *perm, real *givnum, + real *c__, real *s, real *work, integer *iwork, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, perm_dim1, perm_offset, difl_dim1, + difl_offset, difr_dim1, difr_offset, givnum_dim1, givnum_offset, + poles_dim1, poles_offset, u_dim1, u_offset, vt_dim1, vt_offset, + z_dim1, z_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, m, i1, ic, lf, nd, ll, nl, vf, nr, vl, im1, ncc, + nlf, nrf, vfi, iwk, vli, lvl, nru, ndb1, nlp1, lvl2, nrp1; + static real beta; + static integer idxq, nlvl; + static real alpha; + static integer inode, ndiml, ndimr, idxqi, itemp, sqrei; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *), slasd6_(integer *, integer *, integer *, integer *, + real *, real *, real *, real *, real *, integer *, integer *, + integer *, integer *, integer *, real *, integer *, real *, real * + , real *, real *, integer *, real *, real *, real *, integer *, + integer *); + static integer nwork1, nwork2; + extern /* Subroutine */ int xerbla_(char *, integer *), slasdq_( + char *, integer *, integer *, integer *, integer *, integer *, + real *, real *, real *, integer *, real *, integer *, real *, + integer *, real *, integer *), slasdt_(integer *, integer + *, integer *, integer *, integer *, integer *, integer *), + slaset_(char *, integer *, integer *, real *, real *, real *, + integer *); + static integer smlszp; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + Using a divide and conquer approach, SLASDA computes the singular + value decomposition (SVD) of a real upper bidiagonal N-by-M matrix + B with diagonal D and offdiagonal E, where M = N + SQRE. The + algorithm computes the singular values in the SVD B = U * S * VT. + The orthogonal matrices U and VT are optionally computed in + compact form. + + A related subroutine, SLASD0, computes the singular values and + the singular vectors in explicit form. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed + in compact form, as follows + = 0: Compute singular values only. + = 1: Compute singular vectors of upper bidiagonal + matrix in compact form. + + SMLSIZ (input) INTEGER + The maximum size of the subproblems at the bottom of the + computation tree. + + N (input) INTEGER + The row dimension of the upper bidiagonal matrix. This is + also the dimension of the main diagonal array D. + + SQRE (input) INTEGER + Specifies the column dimension of the bidiagonal matrix. + = 0: The bidiagonal matrix has column dimension M = N; + = 1: The bidiagonal matrix has column dimension M = N + 1. + + D (input/output) REAL array, dimension ( N ) + On entry D contains the main diagonal of the bidiagonal + matrix. On exit D, if INFO = 0, contains its singular values. + + E (input) REAL array, dimension ( M-1 ) + Contains the subdiagonal entries of the bidiagonal matrix. + On exit, E has been destroyed. + + U (output) REAL array, + dimension ( LDU, SMLSIZ ) if ICOMPQ = 1, and not referenced + if ICOMPQ = 0. If ICOMPQ = 1, on exit, U contains the left + singular vector matrices of all subproblems at the bottom + level. + + LDU (input) INTEGER, LDU = > N. + The leading dimension of arrays U, VT, DIFL, DIFR, POLES, + GIVNUM, and Z. + + VT (output) REAL array, + dimension ( LDU, SMLSIZ+1 ) if ICOMPQ = 1, and not referenced + if ICOMPQ = 0. If ICOMPQ = 1, on exit, VT' contains the right + singular vector matrices of all subproblems at the bottom + level. + + K (output) INTEGER array, dimension ( N ) + if ICOMPQ = 1 and dimension 1 if ICOMPQ = 0. + If ICOMPQ = 1, on exit, K(I) is the dimension of the I-th + secular equation on the computation tree. + + DIFL (output) REAL array, dimension ( LDU, NLVL ), + where NLVL = floor(log_2 (N/SMLSIZ))). + + DIFR (output) REAL array, + dimension ( LDU, 2 * NLVL ) if ICOMPQ = 1 and + dimension ( N ) if ICOMPQ = 0. + If ICOMPQ = 1, on exit, DIFL(1:N, I) and DIFR(1:N, 2 * I - 1) + record distances between singular values on the I-th + level and singular values on the (I -1)-th level, and + DIFR(1:N, 2 * I ) contains the normalizing factors for + the right singular vector matrix. See SLASD8 for details. + + Z (output) REAL array, + dimension ( LDU, NLVL ) if ICOMPQ = 1 and + dimension ( N ) if ICOMPQ = 0. + The first K elements of Z(1, I) contain the components of + the deflation-adjusted updating row vector for subproblems + on the I-th level. + + POLES (output) REAL array, + dimension ( LDU, 2 * NLVL ) if ICOMPQ = 1, and not referenced + if ICOMPQ = 0. If ICOMPQ = 1, on exit, POLES(1, 2*I - 1) and + POLES(1, 2*I) contain the new and old singular values + involved in the secular equations on the I-th level. + + GIVPTR (output) INTEGER array, + dimension ( N ) if ICOMPQ = 1, and not referenced if + ICOMPQ = 0. If ICOMPQ = 1, on exit, GIVPTR( I ) records + the number of Givens rotations performed on the I-th + problem on the computation tree. + + GIVCOL (output) INTEGER array, + dimension ( LDGCOL, 2 * NLVL ) if ICOMPQ = 1, and not + referenced if ICOMPQ = 0. If ICOMPQ = 1, on exit, for each I, + GIVCOL(1, 2 *I - 1) and GIVCOL(1, 2 *I) record the locations + of Givens rotations performed on the I-th level on the + computation tree. + + LDGCOL (input) INTEGER, LDGCOL = > N. + The leading dimension of arrays GIVCOL and PERM. + + PERM (output) INTEGER array, dimension ( LDGCOL, NLVL ) + if ICOMPQ = 1, and not referenced + if ICOMPQ = 0. If ICOMPQ = 1, on exit, PERM(1, I) records + permutations done on the I-th level of the computation tree. + + GIVNUM (output) REAL array, + dimension ( LDU, 2 * NLVL ) if ICOMPQ = 1, and not + referenced if ICOMPQ = 0. If ICOMPQ = 1, on exit, for each I, + GIVNUM(1, 2 *I - 1) and GIVNUM(1, 2 *I) record the C- and S- + values of Givens rotations performed on the I-th level on + the computation tree. + + C (output) REAL array, + dimension ( N ) if ICOMPQ = 1, and dimension 1 if ICOMPQ = 0. + If ICOMPQ = 1 and the I-th subproblem is not square, on exit, + C( I ) contains the C-value of a Givens rotation related to + the right null space of the I-th subproblem. + + S (output) REAL array, dimension ( N ) if + ICOMPQ = 1, and dimension 1 if ICOMPQ = 0. If ICOMPQ = 1 + and the I-th subproblem is not square, on exit, S( I ) + contains the S-value of a Givens rotation related to + the right null space of the I-th subproblem. + + WORK (workspace) REAL array, dimension + (6 * N + (SMLSIZ + 1)*(SMLSIZ + 1)). + + IWORK (workspace) INTEGER array, dimension (7*N). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, a singular value did not converge + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + givnum_dim1 = *ldu; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + poles_dim1 = *ldu; + poles_offset = 1 + poles_dim1; + poles -= poles_offset; + z_dim1 = *ldu; + z_offset = 1 + z_dim1; + z__ -= z_offset; + difr_dim1 = *ldu; + difr_offset = 1 + difr_dim1; + difr -= difr_offset; + difl_dim1 = *ldu; + difl_offset = 1 + difl_dim1; + difl -= difl_offset; + vt_dim1 = *ldu; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + --k; + --givptr; + perm_dim1 = *ldgcol; + perm_offset = 1 + perm_dim1; + perm -= perm_offset; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + --c__; + --s; + --work; + --iwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*smlsiz < 3) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*sqre < 0 || *sqre > 1) { + *info = -4; + } else if (*ldu < *n + *sqre) { + *info = -8; + } else if (*ldgcol < *n) { + *info = -17; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASDA", &i__1); + return 0; + } + + m = *n + *sqre; + +/* If the input matrix is too small, call SLASDQ to find the SVD. */ + + if (*n <= *smlsiz) { + if (*icompq == 0) { + slasdq_("U", sqre, n, &c__0, &c__0, &c__0, &d__[1], &e[1], &vt[ + vt_offset], ldu, &u[u_offset], ldu, &u[u_offset], ldu, & + work[1], info); + } else { + slasdq_("U", sqre, n, &m, n, &c__0, &d__[1], &e[1], &vt[vt_offset] + , ldu, &u[u_offset], ldu, &u[u_offset], ldu, &work[1], + info); + } + return 0; + } + +/* Book-keeping and set up the computation tree. */ + + inode = 1; + ndiml = inode + *n; + ndimr = ndiml + *n; + idxq = ndimr + *n; + iwk = idxq + *n; + + ncc = 0; + nru = 0; + + smlszp = *smlsiz + 1; + vf = 1; + vl = vf + m; + nwork1 = vl + m; + nwork2 = nwork1 + smlszp * smlszp; + + slasdt_(n, &nlvl, &nd, &iwork[inode], &iwork[ndiml], &iwork[ndimr], + smlsiz); + +/* + for the nodes on bottom level of the tree, solve + their subproblems by SLASDQ. +*/ + + ndb1 = (nd + 1) / 2; + i__1 = nd; + for (i__ = ndb1; i__ <= i__1; ++i__) { + +/* + IC : center row of each node + NL : number of rows of left subproblem + NR : number of rows of right subproblem + NLF: starting row of the left subproblem + NRF: starting row of the right subproblem +*/ + + i1 = i__ - 1; + ic = iwork[inode + i1]; + nl = iwork[ndiml + i1]; + nlp1 = nl + 1; + nr = iwork[ndimr + i1]; + nlf = ic - nl; + nrf = ic + 1; + idxqi = idxq + nlf - 2; + vfi = vf + nlf - 1; + vli = vl + nlf - 1; + sqrei = 1; + if (*icompq == 0) { + slaset_("A", &nlp1, &nlp1, &c_b29, &c_b15, &work[nwork1], &smlszp); + slasdq_("U", &sqrei, &nl, &nlp1, &nru, &ncc, &d__[nlf], &e[nlf], & + work[nwork1], &smlszp, &work[nwork2], &nl, &work[nwork2], + &nl, &work[nwork2], info); + itemp = nwork1 + nl * smlszp; + scopy_(&nlp1, &work[nwork1], &c__1, &work[vfi], &c__1); + scopy_(&nlp1, &work[itemp], &c__1, &work[vli], &c__1); + } else { + slaset_("A", &nl, &nl, &c_b29, &c_b15, &u[nlf + u_dim1], ldu); + slaset_("A", &nlp1, &nlp1, &c_b29, &c_b15, &vt[nlf + vt_dim1], + ldu); + slasdq_("U", &sqrei, &nl, &nlp1, &nl, &ncc, &d__[nlf], &e[nlf], & + vt[nlf + vt_dim1], ldu, &u[nlf + u_dim1], ldu, &u[nlf + + u_dim1], ldu, &work[nwork1], info); + scopy_(&nlp1, &vt[nlf + vt_dim1], &c__1, &work[vfi], &c__1); + scopy_(&nlp1, &vt[nlf + nlp1 * vt_dim1], &c__1, &work[vli], &c__1) + ; + } + if (*info != 0) { + return 0; + } + i__2 = nl; + for (j = 1; j <= i__2; ++j) { + iwork[idxqi + j] = j; +/* L10: */ + } + if (i__ == nd && *sqre == 0) { + sqrei = 0; + } else { + sqrei = 1; + } + idxqi += nlp1; + vfi += nlp1; + vli += nlp1; + nrp1 = nr + sqrei; + if (*icompq == 0) { + slaset_("A", &nrp1, &nrp1, &c_b29, &c_b15, &work[nwork1], &smlszp); + slasdq_("U", &sqrei, &nr, &nrp1, &nru, &ncc, &d__[nrf], &e[nrf], & + work[nwork1], &smlszp, &work[nwork2], &nr, &work[nwork2], + &nr, &work[nwork2], info); + itemp = nwork1 + (nrp1 - 1) * smlszp; + scopy_(&nrp1, &work[nwork1], &c__1, &work[vfi], &c__1); + scopy_(&nrp1, &work[itemp], &c__1, &work[vli], &c__1); + } else { + slaset_("A", &nr, &nr, &c_b29, &c_b15, &u[nrf + u_dim1], ldu); + slaset_("A", &nrp1, &nrp1, &c_b29, &c_b15, &vt[nrf + vt_dim1], + ldu); + slasdq_("U", &sqrei, &nr, &nrp1, &nr, &ncc, &d__[nrf], &e[nrf], & + vt[nrf + vt_dim1], ldu, &u[nrf + u_dim1], ldu, &u[nrf + + u_dim1], ldu, &work[nwork1], info); + scopy_(&nrp1, &vt[nrf + vt_dim1], &c__1, &work[vfi], &c__1); + scopy_(&nrp1, &vt[nrf + nrp1 * vt_dim1], &c__1, &work[vli], &c__1) + ; + } + if (*info != 0) { + return 0; + } + i__2 = nr; + for (j = 1; j <= i__2; ++j) { + iwork[idxqi + j] = j; +/* L20: */ + } +/* L30: */ + } + +/* Now conquer each subproblem bottom-up. */ + + j = pow_ii(&c__2, &nlvl); + for (lvl = nlvl; lvl >= 1; --lvl) { + lvl2 = (lvl << 1) - 1; + +/* + Find the first node LF and last node LL on + the current level LVL. +*/ + + if (lvl == 1) { + lf = 1; + ll = 1; + } else { + i__1 = lvl - 1; + lf = pow_ii(&c__2, &i__1); + ll = (lf << 1) - 1; + } + i__1 = ll; + for (i__ = lf; i__ <= i__1; ++i__) { + im1 = i__ - 1; + ic = iwork[inode + im1]; + nl = iwork[ndiml + im1]; + nr = iwork[ndimr + im1]; + nlf = ic - nl; + nrf = ic + 1; + if (i__ == ll) { + sqrei = *sqre; + } else { + sqrei = 1; + } + vfi = vf + nlf - 1; + vli = vl + nlf - 1; + idxqi = idxq + nlf - 1; + alpha = d__[ic]; + beta = e[ic]; + if (*icompq == 0) { + slasd6_(icompq, &nl, &nr, &sqrei, &d__[nlf], &work[vfi], & + work[vli], &alpha, &beta, &iwork[idxqi], &perm[ + perm_offset], &givptr[1], &givcol[givcol_offset], + ldgcol, &givnum[givnum_offset], ldu, &poles[ + poles_offset], &difl[difl_offset], &difr[difr_offset], + &z__[z_offset], &k[1], &c__[1], &s[1], &work[nwork1], + &iwork[iwk], info); + } else { + --j; + slasd6_(icompq, &nl, &nr, &sqrei, &d__[nlf], &work[vfi], & + work[vli], &alpha, &beta, &iwork[idxqi], &perm[nlf + + lvl * perm_dim1], &givptr[j], &givcol[nlf + lvl2 * + givcol_dim1], ldgcol, &givnum[nlf + lvl2 * + givnum_dim1], ldu, &poles[nlf + lvl2 * poles_dim1], & + difl[nlf + lvl * difl_dim1], &difr[nlf + lvl2 * + difr_dim1], &z__[nlf + lvl * z_dim1], &k[j], &c__[j], + &s[j], &work[nwork1], &iwork[iwk], info); + } + if (*info != 0) { + return 0; + } +/* L40: */ + } +/* L50: */ + } + + return 0; + +/* End of SLASDA */ + +} /* slasda_ */ + +/* Subroutine */ int slasdq_(char *uplo, integer *sqre, integer *n, integer * + ncvt, integer *nru, integer *ncc, real *d__, real *e, real *vt, + integer *ldvt, real *u, integer *ldu, real *c__, integer *ldc, real * + work, integer *info) +{ + /* System generated locals */ + integer c_dim1, c_offset, u_dim1, u_offset, vt_dim1, vt_offset, i__1, + i__2; + + /* Local variables */ + static integer i__, j; + static real r__, cs, sn; + static integer np1, isub; + static real smin; + static integer sqre1; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int slasr_(char *, char *, char *, integer *, + integer *, real *, real *, real *, integer *); + static integer iuplo; + extern /* Subroutine */ int sswap_(integer *, real *, integer *, real *, + integer *), xerbla_(char *, integer *), slartg_(real *, + real *, real *, real *, real *); + static logical rotate; + extern /* Subroutine */ int sbdsqr_(char *, integer *, integer *, integer + *, integer *, real *, real *, real *, integer *, real *, integer * + , real *, integer *, real *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASDQ computes the singular value decomposition (SVD) of a real + (upper or lower) bidiagonal matrix with diagonal D and offdiagonal + E, accumulating the transformations if desired. Letting B denote + the input bidiagonal matrix, the algorithm computes orthogonal + matrices Q and P such that B = Q * S * P' (P' denotes the transpose + of P). The singular values S are overwritten on D. + + The input matrix U is changed to U * Q if desired. + The input matrix VT is changed to P' * VT if desired. + The input matrix C is changed to Q' * C if desired. + + See "Computing Small Singular Values of Bidiagonal Matrices With + Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, + LAPACK Working Note #3, for a detailed description of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + On entry, UPLO specifies whether the input bidiagonal matrix + is upper or lower bidiagonal, and wether it is square are + not. + UPLO = 'U' or 'u' B is upper bidiagonal. + UPLO = 'L' or 'l' B is lower bidiagonal. + + SQRE (input) INTEGER + = 0: then the input matrix is N-by-N. + = 1: then the input matrix is N-by-(N+1) if UPLU = 'U' and + (N+1)-by-N if UPLU = 'L'. + + The bidiagonal matrix has + N = NL + NR + 1 rows and + M = N + SQRE >= N columns. + + N (input) INTEGER + On entry, N specifies the number of rows and columns + in the matrix. N must be at least 0. + + NCVT (input) INTEGER + On entry, NCVT specifies the number of columns of + the matrix VT. NCVT must be at least 0. + + NRU (input) INTEGER + On entry, NRU specifies the number of rows of + the matrix U. NRU must be at least 0. + + NCC (input) INTEGER + On entry, NCC specifies the number of columns of + the matrix C. NCC must be at least 0. + + D (input/output) REAL array, dimension (N) + On entry, D contains the diagonal entries of the + bidiagonal matrix whose SVD is desired. On normal exit, + D contains the singular values in ascending order. + + E (input/output) REAL array. + dimension is (N-1) if SQRE = 0 and N if SQRE = 1. + On entry, the entries of E contain the offdiagonal entries + of the bidiagonal matrix whose SVD is desired. On normal + exit, E will contain 0. If the algorithm does not converge, + D and E will contain the diagonal and superdiagonal entries + of a bidiagonal matrix orthogonally equivalent to the one + given as input. + + VT (input/output) REAL array, dimension (LDVT, NCVT) + On entry, contains a matrix which on exit has been + premultiplied by P', dimension N-by-NCVT if SQRE = 0 + and (N+1)-by-NCVT if SQRE = 1 (not referenced if NCVT=0). + + LDVT (input) INTEGER + On entry, LDVT specifies the leading dimension of VT as + declared in the calling (sub) program. LDVT must be at + least 1. If NCVT is nonzero LDVT must also be at least N. + + U (input/output) REAL array, dimension (LDU, N) + On entry, contains a matrix which on exit has been + postmultiplied by Q, dimension NRU-by-N if SQRE = 0 + and NRU-by-(N+1) if SQRE = 1 (not referenced if NRU=0). + + LDU (input) INTEGER + On entry, LDU specifies the leading dimension of U as + declared in the calling (sub) program. LDU must be at + least max( 1, NRU ) . + + C (input/output) REAL array, dimension (LDC, NCC) + On entry, contains an N-by-NCC matrix which on exit + has been premultiplied by Q' dimension N-by-NCC if SQRE = 0 + and (N+1)-by-NCC if SQRE = 1 (not referenced if NCC=0). + + LDC (input) INTEGER + On entry, LDC specifies the leading dimension of C as + declared in the calling (sub) program. LDC must be at + least 1. If NCC is nonzero, LDC must also be at least N. + + WORK (workspace) REAL array, dimension (4*N) + Workspace. Only referenced if one of NCVT, NRU, or NCC is + nonzero, and if N is at least 2. + + INFO (output) INTEGER + On exit, a value of 0 indicates a successful exit. + If INFO < 0, argument number -INFO is illegal. + If INFO > 0, the algorithm did not converge, and INFO + specifies how many superdiagonals did not converge. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + iuplo = 0; + if (lsame_(uplo, "U")) { + iuplo = 1; + } + if (lsame_(uplo, "L")) { + iuplo = 2; + } + if (iuplo == 0) { + *info = -1; + } else if (*sqre < 0 || *sqre > 1) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ncvt < 0) { + *info = -4; + } else if (*nru < 0) { + *info = -5; + } else if (*ncc < 0) { + *info = -6; + } else if (*ncvt == 0 && *ldvt < 1 || *ncvt > 0 && *ldvt < max(1,*n)) { + *info = -10; + } else if (*ldu < max(1,*nru)) { + *info = -12; + } else if (*ncc == 0 && *ldc < 1 || *ncc > 0 && *ldc < max(1,*n)) { + *info = -14; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASDQ", &i__1); + return 0; + } + if (*n == 0) { + return 0; + } + +/* ROTATE is true if any singular vectors desired, false otherwise */ + + rotate = *ncvt > 0 || *nru > 0 || *ncc > 0; + np1 = *n + 1; + sqre1 = *sqre; + +/* + If matrix non-square upper bidiagonal, rotate to be lower + bidiagonal. The rotations are on the right. +*/ + + if (iuplo == 1 && sqre1 == 1) { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + slartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + if (rotate) { + work[i__] = cs; + work[*n + i__] = sn; + } +/* L10: */ + } + slartg_(&d__[*n], &e[*n], &cs, &sn, &r__); + d__[*n] = r__; + e[*n] = 0.f; + if (rotate) { + work[*n] = cs; + work[*n + *n] = sn; + } + iuplo = 2; + sqre1 = 0; + +/* Update singular vectors if desired. */ + + if (*ncvt > 0) { + slasr_("L", "V", "F", &np1, ncvt, &work[1], &work[np1], &vt[ + vt_offset], ldvt); + } + } + +/* + If matrix lower bidiagonal, rotate to be upper bidiagonal + by applying Givens rotations on the left. +*/ + + if (iuplo == 2) { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + slartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + if (rotate) { + work[i__] = cs; + work[*n + i__] = sn; + } +/* L20: */ + } + +/* + If matrix (N+1)-by-N lower bidiagonal, one additional + rotation is needed. +*/ + + if (sqre1 == 1) { + slartg_(&d__[*n], &e[*n], &cs, &sn, &r__); + d__[*n] = r__; + if (rotate) { + work[*n] = cs; + work[*n + *n] = sn; + } + } + +/* Update singular vectors if desired. */ + + if (*nru > 0) { + if (sqre1 == 0) { + slasr_("R", "V", "F", nru, n, &work[1], &work[np1], &u[ + u_offset], ldu); + } else { + slasr_("R", "V", "F", nru, &np1, &work[1], &work[np1], &u[ + u_offset], ldu); + } + } + if (*ncc > 0) { + if (sqre1 == 0) { + slasr_("L", "V", "F", n, ncc, &work[1], &work[np1], &c__[ + c_offset], ldc); + } else { + slasr_("L", "V", "F", &np1, ncc, &work[1], &work[np1], &c__[ + c_offset], ldc); + } + } + } + +/* + Call SBDSQR to compute the SVD of the reduced real + N-by-N upper bidiagonal matrix. +*/ + + sbdsqr_("U", n, ncvt, nru, ncc, &d__[1], &e[1], &vt[vt_offset], ldvt, &u[ + u_offset], ldu, &c__[c_offset], ldc, &work[1], info); + +/* + Sort the singular values into ascending order (insertion sort on + singular values, but only one transposition per singular vector) +*/ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Scan for smallest D(I). */ + + isub = i__; + smin = d__[i__]; + i__2 = *n; + for (j = i__ + 1; j <= i__2; ++j) { + if (d__[j] < smin) { + isub = j; + smin = d__[j]; + } +/* L30: */ + } + if (isub != i__) { + +/* Swap singular values and vectors. */ + + d__[isub] = d__[i__]; + d__[i__] = smin; + if (*ncvt > 0) { + sswap_(ncvt, &vt[isub + vt_dim1], ldvt, &vt[i__ + vt_dim1], + ldvt); + } + if (*nru > 0) { + sswap_(nru, &u[isub * u_dim1 + 1], &c__1, &u[i__ * u_dim1 + 1] + , &c__1); + } + if (*ncc > 0) { + sswap_(ncc, &c__[isub + c_dim1], ldc, &c__[i__ + c_dim1], ldc) + ; + } + } +/* L40: */ + } + + return 0; + +/* End of SLASDQ */ + +} /* slasdq_ */ + +/* Subroutine */ int slasdt_(integer *n, integer *lvl, integer *nd, integer * + inode, integer *ndiml, integer *ndimr, integer *msub) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + static integer i__, il, ir, maxn; + static real temp; + static integer nlvl, llst, ncrnt; + + +/* + -- LAPACK auxiliary routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + SLASDT creates a tree of subproblems for bidiagonal divide and + conquer. + + Arguments + ========= + + N (input) INTEGER + On entry, the number of diagonal elements of the + bidiagonal matrix. + + LVL (output) INTEGER + On exit, the number of levels on the computation tree. + + ND (output) INTEGER + On exit, the number of nodes on the tree. + + INODE (output) INTEGER array, dimension ( N ) + On exit, centers of subproblems. + + NDIML (output) INTEGER array, dimension ( N ) + On exit, row dimensions of left children. + + NDIMR (output) INTEGER array, dimension ( N ) + On exit, row dimensions of right children. + + MSUB (input) INTEGER + On entry, the maximum row dimension each subproblem at the + bottom of the tree can be of. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Find the number of levels on the tree. +*/ + + /* Parameter adjustments */ + --ndimr; + --ndiml; + --inode; + + /* Function Body */ + maxn = max(1,*n); + temp = log((real) maxn / (real) (*msub + 1)) / log(2.f); + *lvl = (integer) temp + 1; + + i__ = *n / 2; + inode[1] = i__ + 1; + ndiml[1] = i__; + ndimr[1] = *n - i__ - 1; + il = 0; + ir = 1; + llst = 1; + i__1 = *lvl - 1; + for (nlvl = 1; nlvl <= i__1; ++nlvl) { + +/* + Constructing the tree at (NLVL+1)-st level. The number of + nodes created on this level is LLST * 2. +*/ + + i__2 = llst - 1; + for (i__ = 0; i__ <= i__2; ++i__) { + il += 2; + ir += 2; + ncrnt = llst + i__; + ndiml[il] = ndiml[ncrnt] / 2; + ndimr[il] = ndiml[ncrnt] - ndiml[il] - 1; + inode[il] = inode[ncrnt] - ndimr[il] - 1; + ndiml[ir] = ndimr[ncrnt] / 2; + ndimr[ir] = ndimr[ncrnt] - ndiml[ir] - 1; + inode[ir] = inode[ncrnt] + ndiml[ir] + 1; +/* L10: */ + } + llst <<= 1; +/* L20: */ + } + *nd = (llst << 1) - 1; + + return 0; + +/* End of SLASDT */ + +} /* slasdt_ */ + +/* Subroutine */ int slaset_(char *uplo, integer *m, integer *n, real *alpha, + real *beta, real *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASET initializes an m-by-n matrix A to BETA on the diagonal and + ALPHA on the offdiagonals. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be set. + = 'U': Upper triangular part is set; the strictly lower + triangular part of A is not changed. + = 'L': Lower triangular part is set; the strictly upper + triangular part of A is not changed. + Otherwise: All of the matrix A is set. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + ALPHA (input) REAL + The constant to which the offdiagonal elements are to be set. + + BETA (input) REAL + The constant to which the diagonal elements are to be set. + + A (input/output) REAL array, dimension (LDA,N) + On exit, the leading m-by-n submatrix of A is set as follows: + + if UPLO = 'U', A(i,j) = ALPHA, 1<=i<=j-1, 1<=j<=n, + if UPLO = 'L', A(i,j) = ALPHA, j+1<=i<=m, 1<=j<=n, + otherwise, A(i,j) = ALPHA, 1<=i<=m, 1<=j<=n, i.ne.j, + + and, for all UPLO, A(i,i) = BETA, 1<=i<=min(m,n). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + +/* + Set the strictly upper triangular or trapezoidal part of the + array to ALPHA. +*/ + + i__1 = *n; + for (j = 2; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = j - 1; + i__2 = min(i__3,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = *alpha; +/* L10: */ + } +/* L20: */ + } + + } else if (lsame_(uplo, "L")) { + +/* + Set the strictly lower triangular or trapezoidal part of the + array to ALPHA. +*/ + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j + 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = *alpha; +/* L30: */ + } +/* L40: */ + } + + } else { + +/* Set the leading m-by-n submatrix to ALPHA. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = *alpha; +/* L50: */ + } +/* L60: */ + } + } + +/* Set the first min(M,N) diagonal elements to BETA. */ + + i__1 = min(*m,*n); + for (i__ = 1; i__ <= i__1; ++i__) { + a[i__ + i__ * a_dim1] = *beta; +/* L70: */ + } + + return 0; + +/* End of SLASET */ + +} /* slaset_ */ + +/* Subroutine */ int slasq1_(integer *n, real *d__, real *e, real *work, + integer *info) +{ + /* System generated locals */ + integer i__1, i__2; + real r__1, r__2, r__3; + + /* Local variables */ + static integer i__; + static real eps; + extern /* Subroutine */ int slas2_(real *, real *, real *, real *, real *) + ; + static real scale; + static integer iinfo; + static real sigmn, sigmx; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *), slasq2_(integer *, real *, integer *); + extern doublereal slamch_(char *); + static real safmin; + extern /* Subroutine */ int xerbla_(char *, integer *), slascl_( + char *, integer *, integer *, real *, real *, integer *, integer * + , real *, integer *, integer *), slasrt_(char *, integer * + , real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + SLASQ1 computes the singular values of a real N-by-N bidiagonal + matrix with diagonal D and off-diagonal E. The singular values + are computed to high relative accuracy, in the absence of + denormalization, underflow and overflow. The algorithm was first + presented in + + "Accurate singular values and differential qd algorithms" by K. V. + Fernando and B. N. Parlett, Numer. Math., Vol-67, No. 2, pp. 191-230, + 1994, + + and the present implementation is described in "An implementation of + the dqds Algorithm (Positive Case)", LAPACK Working Note. + + Arguments + ========= + + N (input) INTEGER + The number of rows and columns in the matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, D contains the diagonal elements of the + bidiagonal matrix whose SVD is desired. On normal exit, + D contains the singular values in decreasing order. + + E (input/output) REAL array, dimension (N) + On entry, elements E(1:N-1) contain the off-diagonal elements + of the bidiagonal matrix whose SVD is desired. + On exit, E is overwritten. + + WORK (workspace) REAL array, dimension (4*N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: the algorithm failed + = 1, a split was marked by a positive value in E + = 2, current block of Z not diagonalized after 30*N + iterations (in inner while loop) + = 3, termination criterion of outer while loop not met + (program created more than N unreduced blocks) + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --work; + --e; + --d__; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -2; + i__1 = -(*info); + xerbla_("SLASQ1", &i__1); + return 0; + } else if (*n == 0) { + return 0; + } else if (*n == 1) { + d__[1] = dabs(d__[1]); + return 0; + } else if (*n == 2) { + slas2_(&d__[1], &e[1], &d__[2], &sigmn, &sigmx); + d__[1] = sigmx; + d__[2] = sigmn; + return 0; + } + +/* Estimate the largest singular value. */ + + sigmx = 0.f; + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + d__[i__] = (r__1 = d__[i__], dabs(r__1)); +/* Computing MAX */ + r__2 = sigmx, r__3 = (r__1 = e[i__], dabs(r__1)); + sigmx = dmax(r__2,r__3); +/* L10: */ + } + d__[*n] = (r__1 = d__[*n], dabs(r__1)); + +/* Early return if SIGMX is zero (matrix is already diagonal). */ + + if (sigmx == 0.f) { + slasrt_("D", n, &d__[1], &iinfo); + return 0; + } + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + r__1 = sigmx, r__2 = d__[i__]; + sigmx = dmax(r__1,r__2); +/* L20: */ + } + +/* + Copy D and E into WORK (in the Z format) and scale (squaring the + input data makes scaling by a power of the radix pointless). +*/ + + eps = slamch_("Precision"); + safmin = slamch_("Safe minimum"); + scale = sqrt(eps / safmin); + scopy_(n, &d__[1], &c__1, &work[1], &c__2); + i__1 = *n - 1; + scopy_(&i__1, &e[1], &c__1, &work[2], &c__2); + i__1 = (*n << 1) - 1; + i__2 = (*n << 1) - 1; + slascl_("G", &c__0, &c__0, &sigmx, &scale, &i__1, &c__1, &work[1], &i__2, + &iinfo); + +/* Compute the q's and e's. */ + + i__1 = (*n << 1) - 1; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing 2nd power */ + r__1 = work[i__]; + work[i__] = r__1 * r__1; +/* L30: */ + } + work[*n * 2] = 0.f; + + slasq2_(n, &work[1], info); + + if (*info == 0) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d__[i__] = sqrt(work[i__]); +/* L40: */ + } + slascl_("G", &c__0, &c__0, &scale, &sigmx, n, &c__1, &d__[1], n, & + iinfo); + } + + return 0; + +/* End of SLASQ1 */ + +} /* slasq1_ */ + +/* Subroutine */ int slasq2_(integer *n, real *z__, integer *info) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + real r__1, r__2; + + /* Local variables */ + static real d__, e, g; + static integer k; + static real s, t; + static integer i0, i4, n0; + static real dn; + static integer pp; + static real dn1, dn2, dee, eps, tau, tol; + static integer ipn4; + static real tol2; + static logical ieee; + static integer nbig; + static real dmin__, emin, emax; + static integer kmin, ndiv, iter; + static real qmin, temp, qmax, zmax; + static integer splt; + static real dmin1, dmin2; + static integer nfail; + static real desig, trace, sigma; + static integer iinfo, ttype; + extern /* Subroutine */ int slasq3_(integer *, integer *, real *, integer + *, real *, real *, real *, real *, integer *, integer *, integer * + , logical *, integer *, real *, real *, real *, real *, real *, + real *, real *); + static real deemin; + extern doublereal slamch_(char *); + static integer iwhila, iwhilb; + static real oldemn, safmin; + extern /* Subroutine */ int xerbla_(char *, integer *), slasrt_( + char *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + SLASQ2 computes all the eigenvalues of the symmetric positive + definite tridiagonal matrix associated with the qd array Z to high + relative accuracy are computed to high relative accuracy, in the + absence of denormalization, underflow and overflow. + + To see the relation of Z to the tridiagonal matrix, let L be a + unit lower bidiagonal matrix with subdiagonals Z(2,4,6,,..) and + let U be an upper bidiagonal matrix with 1's above and diagonal + Z(1,3,5,,..). The tridiagonal is L*U or, if you prefer, the + symmetric tridiagonal to which it is similar. + + Note : SLASQ2 defines a logical variable, IEEE, which is true + on machines which follow ieee-754 floating-point standard in their + handling of infinities and NaNs, and false otherwise. This variable + is passed to SLASQ3. + + Arguments + ========= + + N (input) INTEGER + The number of rows and columns in the matrix. N >= 0. + + Z (input/output) REAL array, dimension ( 4*N ) + On entry Z holds the qd array. On exit, entries 1 to N hold + the eigenvalues in decreasing order, Z( 2*N+1 ) holds the + trace, and Z( 2*N+2 ) holds the sum of the eigenvalues. If + N > 2, then Z( 2*N+3 ) holds the iteration count, Z( 2*N+4 ) + holds NDIVS/NIN^2, and Z( 2*N+5 ) holds the percentage of + shifts that failed. + + INFO (output) INTEGER + = 0: successful exit + < 0: if the i-th argument is a scalar and had an illegal + value, then INFO = -i, if the i-th argument is an + array and the j-entry had an illegal value, then + INFO = -(i*100+j) + > 0: the algorithm failed + = 1, a split was marked by a positive value in E + = 2, current block of Z not diagonalized after 30*N + iterations (in inner while loop) + = 3, termination criterion of outer while loop not met + (program created more than N unreduced blocks) + + Further Details + =============== + Local Variables: I0:N0 defines a current unreduced segment of Z. + The shifts are accumulated in SIGMA. Iteration count is in ITER. + Ping-pong is controlled by PP (alternates between 0 and 1). + + ===================================================================== + + + Test the input arguments. + (in case SLASQ2 is not called by SLASQ1) +*/ + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + *info = 0; + eps = slamch_("Precision"); + safmin = slamch_("Safe minimum"); + tol = eps * 100.f; +/* Computing 2nd power */ + r__1 = tol; + tol2 = r__1 * r__1; + + if (*n < 0) { + *info = -1; + xerbla_("SLASQ2", &c__1); + return 0; + } else if (*n == 0) { + return 0; + } else if (*n == 1) { + +/* 1-by-1 case. */ + + if (z__[1] < 0.f) { + *info = -201; + xerbla_("SLASQ2", &c__2); + } + return 0; + } else if (*n == 2) { + +/* 2-by-2 case. */ + + if (z__[2] < 0.f || z__[3] < 0.f) { + *info = -2; + xerbla_("SLASQ2", &c__2); + return 0; + } else if (z__[3] > z__[1]) { + d__ = z__[3]; + z__[3] = z__[1]; + z__[1] = d__; + } + z__[5] = z__[1] + z__[2] + z__[3]; + if (z__[2] > z__[3] * tol2) { + t = (z__[1] - z__[3] + z__[2]) * .5f; + s = z__[3] * (z__[2] / t); + if (s <= t) { + s = z__[3] * (z__[2] / (t * (sqrt(s / t + 1.f) + 1.f))); + } else { + s = z__[3] * (z__[2] / (t + sqrt(t) * sqrt(t + s))); + } + t = z__[1] + (s + z__[2]); + z__[3] *= z__[1] / t; + z__[1] = t; + } + z__[2] = z__[3]; + z__[6] = z__[2] + z__[1]; + return 0; + } + +/* Check for negative data and compute sums of q's and e's. */ + + z__[*n * 2] = 0.f; + emin = z__[2]; + qmax = 0.f; + zmax = 0.f; + d__ = 0.f; + e = 0.f; + + i__1 = *n - 1 << 1; + for (k = 1; k <= i__1; k += 2) { + if (z__[k] < 0.f) { + *info = -(k + 200); + xerbla_("SLASQ2", &c__2); + return 0; + } else if (z__[k + 1] < 0.f) { + *info = -(k + 201); + xerbla_("SLASQ2", &c__2); + return 0; + } + d__ += z__[k]; + e += z__[k + 1]; +/* Computing MAX */ + r__1 = qmax, r__2 = z__[k]; + qmax = dmax(r__1,r__2); +/* Computing MIN */ + r__1 = emin, r__2 = z__[k + 1]; + emin = dmin(r__1,r__2); +/* Computing MAX */ + r__1 = max(qmax,zmax), r__2 = z__[k + 1]; + zmax = dmax(r__1,r__2); +/* L10: */ + } + if (z__[(*n << 1) - 1] < 0.f) { + *info = -((*n << 1) + 199); + xerbla_("SLASQ2", &c__2); + return 0; + } + d__ += z__[(*n << 1) - 1]; +/* Computing MAX */ + r__1 = qmax, r__2 = z__[(*n << 1) - 1]; + qmax = dmax(r__1,r__2); + zmax = dmax(qmax,zmax); + +/* Check for diagonality. */ + + if (e == 0.f) { + i__1 = *n; + for (k = 2; k <= i__1; ++k) { + z__[k] = z__[(k << 1) - 1]; +/* L20: */ + } + slasrt_("D", n, &z__[1], &iinfo); + z__[(*n << 1) - 1] = d__; + return 0; + } + + trace = d__ + e; + +/* Check for zero data. */ + + if (trace == 0.f) { + z__[(*n << 1) - 1] = 0.f; + return 0; + } + +/* + Check whether the machine is IEEE conformable. + + IEEE = ILAENV( 10, 'SLASQ2', 'N', 1, 2, 3, 4 ).EQ.1 .AND. + $ ILAENV( 11, 'SLASQ2', 'N', 1, 2, 3, 4 ).EQ.1 + + [11/15/2008] The case IEEE=.TRUE. has a problem in single precision with + some the test matrices of type 16. The double precision code is fine. +*/ + + ieee = FALSE_; + +/* Rearrange data for locality: Z=(q1,qq1,e1,ee1,q2,qq2,e2,ee2,...). */ + + for (k = *n << 1; k >= 2; k += -2) { + z__[k * 2] = 0.f; + z__[(k << 1) - 1] = z__[k]; + z__[(k << 1) - 2] = 0.f; + z__[(k << 1) - 3] = z__[k - 1]; +/* L30: */ + } + + i0 = 1; + n0 = *n; + +/* Reverse the qd-array, if warranted. */ + + if (z__[(i0 << 2) - 3] * 1.5f < z__[(n0 << 2) - 3]) { + ipn4 = i0 + n0 << 2; + i__1 = i0 + n0 - 1 << 1; + for (i4 = i0 << 2; i4 <= i__1; i4 += 4) { + temp = z__[i4 - 3]; + z__[i4 - 3] = z__[ipn4 - i4 - 3]; + z__[ipn4 - i4 - 3] = temp; + temp = z__[i4 - 1]; + z__[i4 - 1] = z__[ipn4 - i4 - 5]; + z__[ipn4 - i4 - 5] = temp; +/* L40: */ + } + } + +/* Initial split checking via dqd and Li's test. */ + + pp = 0; + + for (k = 1; k <= 2; ++k) { + + d__ = z__[(n0 << 2) + pp - 3]; + i__1 = (i0 << 2) + pp; + for (i4 = (n0 - 1 << 2) + pp; i4 >= i__1; i4 += -4) { + if (z__[i4 - 1] <= tol2 * d__) { + z__[i4 - 1] = -0.f; + d__ = z__[i4 - 3]; + } else { + d__ = z__[i4 - 3] * (d__ / (d__ + z__[i4 - 1])); + } +/* L50: */ + } + +/* dqd maps Z to ZZ plus Li's test. */ + + emin = z__[(i0 << 2) + pp + 1]; + d__ = z__[(i0 << 2) + pp - 3]; + i__1 = (n0 - 1 << 2) + pp; + for (i4 = (i0 << 2) + pp; i4 <= i__1; i4 += 4) { + z__[i4 - (pp << 1) - 2] = d__ + z__[i4 - 1]; + if (z__[i4 - 1] <= tol2 * d__) { + z__[i4 - 1] = -0.f; + z__[i4 - (pp << 1) - 2] = d__; + z__[i4 - (pp << 1)] = 0.f; + d__ = z__[i4 + 1]; + } else if (safmin * z__[i4 + 1] < z__[i4 - (pp << 1) - 2] && + safmin * z__[i4 - (pp << 1) - 2] < z__[i4 + 1]) { + temp = z__[i4 + 1] / z__[i4 - (pp << 1) - 2]; + z__[i4 - (pp << 1)] = z__[i4 - 1] * temp; + d__ *= temp; + } else { + z__[i4 - (pp << 1)] = z__[i4 + 1] * (z__[i4 - 1] / z__[i4 - ( + pp << 1) - 2]); + d__ = z__[i4 + 1] * (d__ / z__[i4 - (pp << 1) - 2]); + } +/* Computing MIN */ + r__1 = emin, r__2 = z__[i4 - (pp << 1)]; + emin = dmin(r__1,r__2); +/* L60: */ + } + z__[(n0 << 2) - pp - 2] = d__; + +/* Now find qmax. */ + + qmax = z__[(i0 << 2) - pp - 2]; + i__1 = (n0 << 2) - pp - 2; + for (i4 = (i0 << 2) - pp + 2; i4 <= i__1; i4 += 4) { +/* Computing MAX */ + r__1 = qmax, r__2 = z__[i4]; + qmax = dmax(r__1,r__2); +/* L70: */ + } + +/* Prepare for the next iteration on K. */ + + pp = 1 - pp; +/* L80: */ + } + +/* Initialise variables to pass to SLASQ3. */ + + ttype = 0; + dmin1 = 0.f; + dmin2 = 0.f; + dn = 0.f; + dn1 = 0.f; + dn2 = 0.f; + g = 0.f; + tau = 0.f; + + iter = 2; + nfail = 0; + ndiv = n0 - i0 << 1; + + i__1 = *n + 1; + for (iwhila = 1; iwhila <= i__1; ++iwhila) { + if (n0 < 1) { + goto L170; + } + +/* + While array unfinished do + + E(N0) holds the value of SIGMA when submatrix in I0:N0 + splits from the rest of the array, but is negated. +*/ + + desig = 0.f; + if (n0 == *n) { + sigma = 0.f; + } else { + sigma = -z__[(n0 << 2) - 1]; + } + if (sigma < 0.f) { + *info = 1; + return 0; + } + +/* + Find last unreduced submatrix's top index I0, find QMAX and + EMIN. Find Gershgorin-type bound if Q's much greater than E's. +*/ + + emax = 0.f; + if (n0 > i0) { + emin = (r__1 = z__[(n0 << 2) - 5], dabs(r__1)); + } else { + emin = 0.f; + } + qmin = z__[(n0 << 2) - 3]; + qmax = qmin; + for (i4 = n0 << 2; i4 >= 8; i4 += -4) { + if (z__[i4 - 5] <= 0.f) { + goto L100; + } + if (qmin >= emax * 4.f) { +/* Computing MIN */ + r__1 = qmin, r__2 = z__[i4 - 3]; + qmin = dmin(r__1,r__2); +/* Computing MAX */ + r__1 = emax, r__2 = z__[i4 - 5]; + emax = dmax(r__1,r__2); + } +/* Computing MAX */ + r__1 = qmax, r__2 = z__[i4 - 7] + z__[i4 - 5]; + qmax = dmax(r__1,r__2); +/* Computing MIN */ + r__1 = emin, r__2 = z__[i4 - 5]; + emin = dmin(r__1,r__2); +/* L90: */ + } + i4 = 4; + +L100: + i0 = i4 / 4; + pp = 0; + + if (n0 - i0 > 1) { + dee = z__[(i0 << 2) - 3]; + deemin = dee; + kmin = i0; + i__2 = (n0 << 2) - 3; + for (i4 = (i0 << 2) + 1; i4 <= i__2; i4 += 4) { + dee = z__[i4] * (dee / (dee + z__[i4 - 2])); + if (dee <= deemin) { + deemin = dee; + kmin = (i4 + 3) / 4; + } +/* L110: */ + } + if (kmin - i0 << 1 < n0 - kmin && deemin <= z__[(n0 << 2) - 3] * + .5f) { + ipn4 = i0 + n0 << 2; + pp = 2; + i__2 = i0 + n0 - 1 << 1; + for (i4 = i0 << 2; i4 <= i__2; i4 += 4) { + temp = z__[i4 - 3]; + z__[i4 - 3] = z__[ipn4 - i4 - 3]; + z__[ipn4 - i4 - 3] = temp; + temp = z__[i4 - 2]; + z__[i4 - 2] = z__[ipn4 - i4 - 2]; + z__[ipn4 - i4 - 2] = temp; + temp = z__[i4 - 1]; + z__[i4 - 1] = z__[ipn4 - i4 - 5]; + z__[ipn4 - i4 - 5] = temp; + temp = z__[i4]; + z__[i4] = z__[ipn4 - i4 - 4]; + z__[ipn4 - i4 - 4] = temp; +/* L120: */ + } + } + } + +/* + Put -(initial shift) into DMIN. + + Computing MAX +*/ + r__1 = 0.f, r__2 = qmin - sqrt(qmin) * 2.f * sqrt(emax); + dmin__ = -dmax(r__1,r__2); + +/* + Now I0:N0 is unreduced. + PP = 0 for ping, PP = 1 for pong. + PP = 2 indicates that flipping was applied to the Z array and + and that the tests for deflation upon entry in SLASQ3 + should not be performed. +*/ + + nbig = (n0 - i0 + 1) * 30; + i__2 = nbig; + for (iwhilb = 1; iwhilb <= i__2; ++iwhilb) { + if (i0 > n0) { + goto L150; + } + +/* While submatrix unfinished take a good dqds step. */ + + slasq3_(&i0, &n0, &z__[1], &pp, &dmin__, &sigma, &desig, &qmax, & + nfail, &iter, &ndiv, &ieee, &ttype, &dmin1, &dmin2, &dn, & + dn1, &dn2, &g, &tau); + + pp = 1 - pp; + +/* When EMIN is very small check for splits. */ + + if (pp == 0 && n0 - i0 >= 3) { + if (z__[n0 * 4] <= tol2 * qmax || z__[(n0 << 2) - 1] <= tol2 * + sigma) { + splt = i0 - 1; + qmax = z__[(i0 << 2) - 3]; + emin = z__[(i0 << 2) - 1]; + oldemn = z__[i0 * 4]; + i__3 = n0 - 3 << 2; + for (i4 = i0 << 2; i4 <= i__3; i4 += 4) { + if (z__[i4] <= tol2 * z__[i4 - 3] || z__[i4 - 1] <= + tol2 * sigma) { + z__[i4 - 1] = -sigma; + splt = i4 / 4; + qmax = 0.f; + emin = z__[i4 + 3]; + oldemn = z__[i4 + 4]; + } else { +/* Computing MAX */ + r__1 = qmax, r__2 = z__[i4 + 1]; + qmax = dmax(r__1,r__2); +/* Computing MIN */ + r__1 = emin, r__2 = z__[i4 - 1]; + emin = dmin(r__1,r__2); +/* Computing MIN */ + r__1 = oldemn, r__2 = z__[i4]; + oldemn = dmin(r__1,r__2); + } +/* L130: */ + } + z__[(n0 << 2) - 1] = emin; + z__[n0 * 4] = oldemn; + i0 = splt + 1; + } + } + +/* L140: */ + } + + *info = 2; + return 0; + +/* end IWHILB */ + +L150: + +/* L160: */ + ; + } + + *info = 3; + return 0; + +/* end IWHILA */ + +L170: + +/* Move q's to the front. */ + + i__1 = *n; + for (k = 2; k <= i__1; ++k) { + z__[k] = z__[(k << 2) - 3]; +/* L180: */ + } + +/* Sort and compute sum of eigenvalues. */ + + slasrt_("D", n, &z__[1], &iinfo); + + e = 0.f; + for (k = *n; k >= 1; --k) { + e += z__[k]; +/* L190: */ + } + +/* Store trace, sum(eigenvalues) and information on performance. */ + + z__[(*n << 1) + 1] = trace; + z__[(*n << 1) + 2] = e; + z__[(*n << 1) + 3] = (real) iter; +/* Computing 2nd power */ + i__1 = *n; + z__[(*n << 1) + 4] = (real) ndiv / (real) (i__1 * i__1); + z__[(*n << 1) + 5] = nfail * 100.f / (real) iter; + return 0; + +/* End of SLASQ2 */ + +} /* slasq2_ */ + +/* Subroutine */ int slasq3_(integer *i0, integer *n0, real *z__, integer *pp, + real *dmin__, real *sigma, real *desig, real *qmax, integer *nfail, + integer *iter, integer *ndiv, logical *ieee, integer *ttype, real * + dmin1, real *dmin2, real *dn, real *dn1, real *dn2, real *g, real * + tau) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2; + + /* Local variables */ + static real s, t; + static integer j4, nn; + static real eps, tol; + static integer n0in, ipn4; + static real tol2, temp; + extern /* Subroutine */ int slasq4_(integer *, integer *, real *, integer + *, integer *, real *, real *, real *, real *, real *, real *, + real *, integer *, real *), slasq5_(integer *, integer *, real *, + integer *, real *, real *, real *, real *, real *, real *, real *, + logical *), slasq6_(integer *, integer *, real *, integer *, + real *, real *, real *, real *, real *, real *); + extern doublereal slamch_(char *); + extern logical sisnan_(real *); + + +/* + -- LAPACK routine (version 3.2.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- June 2010 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + SLASQ3 checks for deflation, computes a shift (TAU) and calls dqds. + In case of failure it changes shifts, and tries again until output + is positive. + + Arguments + ========= + + I0 (input) INTEGER + First index. + + N0 (input/output) INTEGER + Last index. + + Z (input) REAL array, dimension ( 4*N ) + Z holds the qd array. + + PP (input/output) INTEGER + PP=0 for ping, PP=1 for pong. + PP=2 indicates that flipping was applied to the Z array + and that the initial tests for deflation should not be + performed. + + DMIN (output) REAL + Minimum value of d. + + SIGMA (output) REAL + Sum of shifts used in current segment. + + DESIG (input/output) REAL + Lower order part of SIGMA + + QMAX (input) REAL + Maximum value of q. + + NFAIL (output) INTEGER + Number of times shift was too big. + + ITER (output) INTEGER + Number of iterations. + + NDIV (output) INTEGER + Number of divisions. + + IEEE (input) LOGICAL + Flag for IEEE or non IEEE arithmetic (passed to SLASQ5). + + TTYPE (input/output) INTEGER + Shift type. + + DMIN1 (input/output) REAL + + DMIN2 (input/output) REAL + + DN (input/output) REAL + + DN1 (input/output) REAL + + DN2 (input/output) REAL + + G (input/output) REAL + + TAU (input/output) REAL + + These are passed as arguments in order to save their values + between calls to SLASQ3. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + n0in = *n0; + eps = slamch_("Precision"); + tol = eps * 100.f; +/* Computing 2nd power */ + r__1 = tol; + tol2 = r__1 * r__1; + +/* Check for deflation. */ + +L10: + + if (*n0 < *i0) { + return 0; + } + if (*n0 == *i0) { + goto L20; + } + nn = (*n0 << 2) + *pp; + if (*n0 == *i0 + 1) { + goto L40; + } + +/* Check whether E(N0-1) is negligible, 1 eigenvalue. */ + + if (z__[nn - 5] > tol2 * (*sigma + z__[nn - 3]) && z__[nn - (*pp << 1) - + 4] > tol2 * z__[nn - 7]) { + goto L30; + } + +L20: + + z__[(*n0 << 2) - 3] = z__[(*n0 << 2) + *pp - 3] + *sigma; + --(*n0); + goto L10; + +/* Check whether E(N0-2) is negligible, 2 eigenvalues. */ + +L30: + + if (z__[nn - 9] > tol2 * *sigma && z__[nn - (*pp << 1) - 8] > tol2 * z__[ + nn - 11]) { + goto L50; + } + +L40: + + if (z__[nn - 3] > z__[nn - 7]) { + s = z__[nn - 3]; + z__[nn - 3] = z__[nn - 7]; + z__[nn - 7] = s; + } + if (z__[nn - 5] > z__[nn - 3] * tol2) { + t = (z__[nn - 7] - z__[nn - 3] + z__[nn - 5]) * .5f; + s = z__[nn - 3] * (z__[nn - 5] / t); + if (s <= t) { + s = z__[nn - 3] * (z__[nn - 5] / (t * (sqrt(s / t + 1.f) + 1.f))); + } else { + s = z__[nn - 3] * (z__[nn - 5] / (t + sqrt(t) * sqrt(t + s))); + } + t = z__[nn - 7] + (s + z__[nn - 5]); + z__[nn - 3] *= z__[nn - 7] / t; + z__[nn - 7] = t; + } + z__[(*n0 << 2) - 7] = z__[nn - 7] + *sigma; + z__[(*n0 << 2) - 3] = z__[nn - 3] + *sigma; + *n0 += -2; + goto L10; + +L50: + if (*pp == 2) { + *pp = 0; + } + +/* Reverse the qd-array, if warranted. */ + + if (*dmin__ <= 0.f || *n0 < n0in) { + if (z__[(*i0 << 2) + *pp - 3] * 1.5f < z__[(*n0 << 2) + *pp - 3]) { + ipn4 = *i0 + *n0 << 2; + i__1 = *i0 + *n0 - 1 << 1; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + temp = z__[j4 - 3]; + z__[j4 - 3] = z__[ipn4 - j4 - 3]; + z__[ipn4 - j4 - 3] = temp; + temp = z__[j4 - 2]; + z__[j4 - 2] = z__[ipn4 - j4 - 2]; + z__[ipn4 - j4 - 2] = temp; + temp = z__[j4 - 1]; + z__[j4 - 1] = z__[ipn4 - j4 - 5]; + z__[ipn4 - j4 - 5] = temp; + temp = z__[j4]; + z__[j4] = z__[ipn4 - j4 - 4]; + z__[ipn4 - j4 - 4] = temp; +/* L60: */ + } + if (*n0 - *i0 <= 4) { + z__[(*n0 << 2) + *pp - 1] = z__[(*i0 << 2) + *pp - 1]; + z__[(*n0 << 2) - *pp] = z__[(*i0 << 2) - *pp]; + } +/* Computing MIN */ + r__1 = *dmin2, r__2 = z__[(*n0 << 2) + *pp - 1]; + *dmin2 = dmin(r__1,r__2); +/* Computing MIN */ + r__1 = z__[(*n0 << 2) + *pp - 1], r__2 = z__[(*i0 << 2) + *pp - 1] + , r__1 = min(r__1,r__2), r__2 = z__[(*i0 << 2) + *pp + 3]; + z__[(*n0 << 2) + *pp - 1] = dmin(r__1,r__2); +/* Computing MIN */ + r__1 = z__[(*n0 << 2) - *pp], r__2 = z__[(*i0 << 2) - *pp], r__1 = + min(r__1,r__2), r__2 = z__[(*i0 << 2) - *pp + 4]; + z__[(*n0 << 2) - *pp] = dmin(r__1,r__2); +/* Computing MAX */ + r__1 = *qmax, r__2 = z__[(*i0 << 2) + *pp - 3], r__1 = max(r__1, + r__2), r__2 = z__[(*i0 << 2) + *pp + 1]; + *qmax = dmax(r__1,r__2); + *dmin__ = -0.f; + } + } + +/* Choose a shift. */ + + slasq4_(i0, n0, &z__[1], pp, &n0in, dmin__, dmin1, dmin2, dn, dn1, dn2, + tau, ttype, g); + +/* Call dqds until DMIN > 0. */ + +L70: + + slasq5_(i0, n0, &z__[1], pp, tau, dmin__, dmin1, dmin2, dn, dn1, dn2, + ieee); + + *ndiv += *n0 - *i0 + 2; + ++(*iter); + +/* Check status. */ + + if (*dmin__ >= 0.f && *dmin1 > 0.f) { + +/* Success. */ + + goto L90; + + } else if (*dmin__ < 0.f && *dmin1 > 0.f && z__[(*n0 - 1 << 2) - *pp] < + tol * (*sigma + *dn1) && dabs(*dn) < tol * *sigma) { + +/* Convergence hidden by negative DN. */ + + z__[(*n0 - 1 << 2) - *pp + 2] = 0.f; + *dmin__ = 0.f; + goto L90; + } else if (*dmin__ < 0.f) { + +/* TAU too big. Select new TAU and try again. */ + + ++(*nfail); + if (*ttype < -22) { + +/* Failed twice. Play it safe. */ + + *tau = 0.f; + } else if (*dmin1 > 0.f) { + +/* Late failure. Gives excellent shift. */ + + *tau = (*tau + *dmin__) * (1.f - eps * 2.f); + *ttype += -11; + } else { + +/* Early failure. Divide by 4. */ + + *tau *= .25f; + *ttype += -12; + } + goto L70; + } else if (sisnan_(dmin__)) { + +/* NaN. */ + + if (*tau == 0.f) { + goto L80; + } else { + *tau = 0.f; + goto L70; + } + } else { + +/* Possible underflow. Play it safe. */ + + goto L80; + } + +/* Risk of underflow. */ + +L80: + slasq6_(i0, n0, &z__[1], pp, dmin__, dmin1, dmin2, dn, dn1, dn2); + *ndiv += *n0 - *i0 + 2; + ++(*iter); + *tau = 0.f; + +L90: + if (*tau < *sigma) { + *desig += *tau; + t = *sigma + *desig; + *desig -= t - *sigma; + } else { + t = *sigma + *tau; + *desig = *sigma - (t - *tau) + *desig; + } + *sigma = t; + + return 0; + +/* End of SLASQ3 */ + +} /* slasq3_ */ + +/* Subroutine */ int slasq4_(integer *i0, integer *n0, real *z__, integer *pp, + integer *n0in, real *dmin__, real *dmin1, real *dmin2, real *dn, + real *dn1, real *dn2, real *tau, integer *ttype, real *g) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2; + + /* Local variables */ + static real s, a2, b1, b2; + static integer i4, nn, np; + static real gam, gap1, gap2; + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + SLASQ4 computes an approximation TAU to the smallest eigenvalue + using values of d from the previous transform. + + I0 (input) INTEGER + First index. + + N0 (input) INTEGER + Last index. + + Z (input) REAL array, dimension ( 4*N ) + Z holds the qd array. + + PP (input) INTEGER + PP=0 for ping, PP=1 for pong. + + NOIN (input) INTEGER + The value of N0 at start of EIGTEST. + + DMIN (input) REAL + Minimum value of d. + + DMIN1 (input) REAL + Minimum value of d, excluding D( N0 ). + + DMIN2 (input) REAL + Minimum value of d, excluding D( N0 ) and D( N0-1 ). + + DN (input) REAL + d(N) + + DN1 (input) REAL + d(N-1) + + DN2 (input) REAL + d(N-2) + + TAU (output) REAL + This is the shift. + + TTYPE (output) INTEGER + Shift type. + + G (input/output) REAL + G is passed as an argument in order to save its value between + calls to SLASQ4. + + Further Details + =============== + CNST1 = 9/16 + + ===================================================================== + + + A negative DMIN forces the shift to take that absolute value + TTYPE records the type of shift. +*/ + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + if (*dmin__ <= 0.f) { + *tau = -(*dmin__); + *ttype = -1; + return 0; + } + + nn = (*n0 << 2) + *pp; + if (*n0in == *n0) { + +/* No eigenvalues deflated. */ + + if (*dmin__ == *dn || *dmin__ == *dn1) { + + b1 = sqrt(z__[nn - 3]) * sqrt(z__[nn - 5]); + b2 = sqrt(z__[nn - 7]) * sqrt(z__[nn - 9]); + a2 = z__[nn - 7] + z__[nn - 5]; + +/* Cases 2 and 3. */ + + if (*dmin__ == *dn && *dmin1 == *dn1) { + gap2 = *dmin2 - a2 - *dmin2 * .25f; + if (gap2 > 0.f && gap2 > b2) { + gap1 = a2 - *dn - b2 / gap2 * b2; + } else { + gap1 = a2 - *dn - (b1 + b2); + } + if (gap1 > 0.f && gap1 > b1) { +/* Computing MAX */ + r__1 = *dn - b1 / gap1 * b1, r__2 = *dmin__ * .5f; + s = dmax(r__1,r__2); + *ttype = -2; + } else { + s = 0.f; + if (*dn > b1) { + s = *dn - b1; + } + if (a2 > b1 + b2) { +/* Computing MIN */ + r__1 = s, r__2 = a2 - (b1 + b2); + s = dmin(r__1,r__2); + } +/* Computing MAX */ + r__1 = s, r__2 = *dmin__ * .333f; + s = dmax(r__1,r__2); + *ttype = -3; + } + } else { + +/* Case 4. */ + + *ttype = -4; + s = *dmin__ * .25f; + if (*dmin__ == *dn) { + gam = *dn; + a2 = 0.f; + if (z__[nn - 5] > z__[nn - 7]) { + return 0; + } + b2 = z__[nn - 5] / z__[nn - 7]; + np = nn - 9; + } else { + np = nn - (*pp << 1); + b2 = z__[np - 2]; + gam = *dn1; + if (z__[np - 4] > z__[np - 2]) { + return 0; + } + a2 = z__[np - 4] / z__[np - 2]; + if (z__[nn - 9] > z__[nn - 11]) { + return 0; + } + b2 = z__[nn - 9] / z__[nn - 11]; + np = nn - 13; + } + +/* Approximate contribution to norm squared from I < NN-1. */ + + a2 += b2; + i__1 = (*i0 << 2) - 1 + *pp; + for (i4 = np; i4 >= i__1; i4 += -4) { + if (b2 == 0.f) { + goto L20; + } + b1 = b2; + if (z__[i4] > z__[i4 - 2]) { + return 0; + } + b2 *= z__[i4] / z__[i4 - 2]; + a2 += b2; + if (dmax(b2,b1) * 100.f < a2 || .563f < a2) { + goto L20; + } +/* L10: */ + } +L20: + a2 *= 1.05f; + +/* Rayleigh quotient residual bound. */ + + if (a2 < .563f) { + s = gam * (1.f - sqrt(a2)) / (a2 + 1.f); + } + } + } else if (*dmin__ == *dn2) { + +/* Case 5. */ + + *ttype = -5; + s = *dmin__ * .25f; + +/* Compute contribution to norm squared from I > NN-2. */ + + np = nn - (*pp << 1); + b1 = z__[np - 2]; + b2 = z__[np - 6]; + gam = *dn2; + if (z__[np - 8] > b2 || z__[np - 4] > b1) { + return 0; + } + a2 = z__[np - 8] / b2 * (z__[np - 4] / b1 + 1.f); + +/* Approximate contribution to norm squared from I < NN-2. */ + + if (*n0 - *i0 > 2) { + b2 = z__[nn - 13] / z__[nn - 15]; + a2 += b2; + i__1 = (*i0 << 2) - 1 + *pp; + for (i4 = nn - 17; i4 >= i__1; i4 += -4) { + if (b2 == 0.f) { + goto L40; + } + b1 = b2; + if (z__[i4] > z__[i4 - 2]) { + return 0; + } + b2 *= z__[i4] / z__[i4 - 2]; + a2 += b2; + if (dmax(b2,b1) * 100.f < a2 || .563f < a2) { + goto L40; + } +/* L30: */ + } +L40: + a2 *= 1.05f; + } + + if (a2 < .563f) { + s = gam * (1.f - sqrt(a2)) / (a2 + 1.f); + } + } else { + +/* Case 6, no information to guide us. */ + + if (*ttype == -6) { + *g += (1.f - *g) * .333f; + } else if (*ttype == -18) { + *g = .083250000000000005f; + } else { + *g = .25f; + } + s = *g * *dmin__; + *ttype = -6; + } + + } else if (*n0in == *n0 + 1) { + +/* One eigenvalue just deflated. Use DMIN1, DN1 for DMIN and DN. */ + + if (*dmin1 == *dn1 && *dmin2 == *dn2) { + +/* Cases 7 and 8. */ + + *ttype = -7; + s = *dmin1 * .333f; + if (z__[nn - 5] > z__[nn - 7]) { + return 0; + } + b1 = z__[nn - 5] / z__[nn - 7]; + b2 = b1; + if (b2 == 0.f) { + goto L60; + } + i__1 = (*i0 << 2) - 1 + *pp; + for (i4 = (*n0 << 2) - 9 + *pp; i4 >= i__1; i4 += -4) { + a2 = b1; + if (z__[i4] > z__[i4 - 2]) { + return 0; + } + b1 *= z__[i4] / z__[i4 - 2]; + b2 += b1; + if (dmax(b1,a2) * 100.f < b2) { + goto L60; + } +/* L50: */ + } +L60: + b2 = sqrt(b2 * 1.05f); +/* Computing 2nd power */ + r__1 = b2; + a2 = *dmin1 / (r__1 * r__1 + 1.f); + gap2 = *dmin2 * .5f - a2; + if (gap2 > 0.f && gap2 > b2 * a2) { +/* Computing MAX */ + r__1 = s, r__2 = a2 * (1.f - a2 * 1.01f * (b2 / gap2) * b2); + s = dmax(r__1,r__2); + } else { +/* Computing MAX */ + r__1 = s, r__2 = a2 * (1.f - b2 * 1.01f); + s = dmax(r__1,r__2); + *ttype = -8; + } + } else { + +/* Case 9. */ + + s = *dmin1 * .25f; + if (*dmin1 == *dn1) { + s = *dmin1 * .5f; + } + *ttype = -9; + } + + } else if (*n0in == *n0 + 2) { + +/* + Two eigenvalues deflated. Use DMIN2, DN2 for DMIN and DN. + + Cases 10 and 11. +*/ + + if (*dmin2 == *dn2 && z__[nn - 5] * 2.f < z__[nn - 7]) { + *ttype = -10; + s = *dmin2 * .333f; + if (z__[nn - 5] > z__[nn - 7]) { + return 0; + } + b1 = z__[nn - 5] / z__[nn - 7]; + b2 = b1; + if (b2 == 0.f) { + goto L80; + } + i__1 = (*i0 << 2) - 1 + *pp; + for (i4 = (*n0 << 2) - 9 + *pp; i4 >= i__1; i4 += -4) { + if (z__[i4] > z__[i4 - 2]) { + return 0; + } + b1 *= z__[i4] / z__[i4 - 2]; + b2 += b1; + if (b1 * 100.f < b2) { + goto L80; + } +/* L70: */ + } +L80: + b2 = sqrt(b2 * 1.05f); +/* Computing 2nd power */ + r__1 = b2; + a2 = *dmin2 / (r__1 * r__1 + 1.f); + gap2 = z__[nn - 7] + z__[nn - 9] - sqrt(z__[nn - 11]) * sqrt(z__[ + nn - 9]) - a2; + if (gap2 > 0.f && gap2 > b2 * a2) { +/* Computing MAX */ + r__1 = s, r__2 = a2 * (1.f - a2 * 1.01f * (b2 / gap2) * b2); + s = dmax(r__1,r__2); + } else { +/* Computing MAX */ + r__1 = s, r__2 = a2 * (1.f - b2 * 1.01f); + s = dmax(r__1,r__2); + } + } else { + s = *dmin2 * .25f; + *ttype = -11; + } + } else if (*n0in > *n0 + 2) { + +/* Case 12, more than two eigenvalues deflated. No information. */ + + s = 0.f; + *ttype = -12; + } + + *tau = s; + return 0; + +/* End of SLASQ4 */ + +} /* slasq4_ */ + +/* Subroutine */ int slasq5_(integer *i0, integer *n0, real *z__, integer *pp, + real *tau, real *dmin__, real *dmin1, real *dmin2, real *dn, real * + dnm1, real *dnm2, logical *ieee) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2; + + /* Local variables */ + static real d__; + static integer j4, j4p2; + static real emin, temp; + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + SLASQ5 computes one dqds transform in ping-pong form, one + version for IEEE machines another for non IEEE machines. + + Arguments + ========= + + I0 (input) INTEGER + First index. + + N0 (input) INTEGER + Last index. + + Z (input) REAL array, dimension ( 4*N ) + Z holds the qd array. EMIN is stored in Z(4*N0) to avoid + an extra argument. + + PP (input) INTEGER + PP=0 for ping, PP=1 for pong. + + TAU (input) REAL + This is the shift. + + DMIN (output) REAL + Minimum value of d. + + DMIN1 (output) REAL + Minimum value of d, excluding D( N0 ). + + DMIN2 (output) REAL + Minimum value of d, excluding D( N0 ) and D( N0-1 ). + + DN (output) REAL + d(N0), the last value of d. + + DNM1 (output) REAL + d(N0-1). + + DNM2 (output) REAL + d(N0-2). + + IEEE (input) LOGICAL + Flag for IEEE or non IEEE arithmetic. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + if (*n0 - *i0 - 1 <= 0) { + return 0; + } + + j4 = (*i0 << 2) + *pp - 3; + emin = z__[j4 + 4]; + d__ = z__[j4] - *tau; + *dmin__ = d__; + *dmin1 = -z__[j4]; + + if (*ieee) { + +/* Code for IEEE arithmetic. */ + + if (*pp == 0) { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 2] = d__ + z__[j4 - 1]; + temp = z__[j4 + 1] / z__[j4 - 2]; + d__ = d__ * temp - *tau; + *dmin__ = dmin(*dmin__,d__); + z__[j4] = z__[j4 - 1] * temp; +/* Computing MIN */ + r__1 = z__[j4]; + emin = dmin(r__1,emin); +/* L10: */ + } + } else { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 3] = d__ + z__[j4]; + temp = z__[j4 + 2] / z__[j4 - 3]; + d__ = d__ * temp - *tau; + *dmin__ = dmin(*dmin__,d__); + z__[j4 - 1] = z__[j4] * temp; +/* Computing MIN */ + r__1 = z__[j4 - 1]; + emin = dmin(r__1,emin); +/* L20: */ + } + } + +/* Unroll last two steps. */ + + *dnm2 = d__; + *dmin2 = *dmin__; + j4 = (*n0 - 2 << 2) - *pp; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm2 + z__[j4p2]; + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]) - *tau; + *dmin__ = dmin(*dmin__,*dnm1); + + *dmin1 = *dmin__; + j4 += 4; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm1 + z__[j4p2]; + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]) - *tau; + *dmin__ = dmin(*dmin__,*dn); + + } else { + +/* Code for non IEEE arithmetic. */ + + if (*pp == 0) { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 2] = d__ + z__[j4 - 1]; + if (d__ < 0.f) { + return 0; + } else { + z__[j4] = z__[j4 + 1] * (z__[j4 - 1] / z__[j4 - 2]); + d__ = z__[j4 + 1] * (d__ / z__[j4 - 2]) - *tau; + } + *dmin__ = dmin(*dmin__,d__); +/* Computing MIN */ + r__1 = emin, r__2 = z__[j4]; + emin = dmin(r__1,r__2); +/* L30: */ + } + } else { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 3] = d__ + z__[j4]; + if (d__ < 0.f) { + return 0; + } else { + z__[j4 - 1] = z__[j4 + 2] * (z__[j4] / z__[j4 - 3]); + d__ = z__[j4 + 2] * (d__ / z__[j4 - 3]) - *tau; + } + *dmin__ = dmin(*dmin__,d__); +/* Computing MIN */ + r__1 = emin, r__2 = z__[j4 - 1]; + emin = dmin(r__1,r__2); +/* L40: */ + } + } + +/* Unroll last two steps. */ + + *dnm2 = d__; + *dmin2 = *dmin__; + j4 = (*n0 - 2 << 2) - *pp; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm2 + z__[j4p2]; + if (*dnm2 < 0.f) { + return 0; + } else { + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]) - *tau; + } + *dmin__ = dmin(*dmin__,*dnm1); + + *dmin1 = *dmin__; + j4 += 4; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm1 + z__[j4p2]; + if (*dnm1 < 0.f) { + return 0; + } else { + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]) - *tau; + } + *dmin__ = dmin(*dmin__,*dn); + + } + + z__[j4 + 2] = *dn; + z__[(*n0 << 2) - *pp] = emin; + return 0; + +/* End of SLASQ5 */ + +} /* slasq5_ */ + +/* Subroutine */ int slasq6_(integer *i0, integer *n0, real *z__, integer *pp, + real *dmin__, real *dmin1, real *dmin2, real *dn, real *dnm1, real * + dnm2) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2; + + /* Local variables */ + static real d__; + static integer j4, j4p2; + static real emin, temp; + extern doublereal slamch_(char *); + static real safmin; + + +/* + -- LAPACK routine (version 3.2) -- + + -- Contributed by Osni Marques of the Lawrence Berkeley National -- + -- Laboratory and Beresford Parlett of the Univ. of California at -- + -- Berkeley -- + -- November 2008 -- + + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + + + Purpose + ======= + + SLASQ6 computes one dqd (shift equal to zero) transform in + ping-pong form, with protection against underflow and overflow. + + Arguments + ========= + + I0 (input) INTEGER + First index. + + N0 (input) INTEGER + Last index. + + Z (input) REAL array, dimension ( 4*N ) + Z holds the qd array. EMIN is stored in Z(4*N0) to avoid + an extra argument. + + PP (input) INTEGER + PP=0 for ping, PP=1 for pong. + + DMIN (output) REAL + Minimum value of d. + + DMIN1 (output) REAL + Minimum value of d, excluding D( N0 ). + + DMIN2 (output) REAL + Minimum value of d, excluding D( N0 ) and D( N0-1 ). + + DN (output) REAL + d(N0), the last value of d. + + DNM1 (output) REAL + d(N0-1). + + DNM2 (output) REAL + d(N0-2). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --z__; + + /* Function Body */ + if (*n0 - *i0 - 1 <= 0) { + return 0; + } + + safmin = slamch_("Safe minimum"); + j4 = (*i0 << 2) + *pp - 3; + emin = z__[j4 + 4]; + d__ = z__[j4]; + *dmin__ = d__; + + if (*pp == 0) { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 2] = d__ + z__[j4 - 1]; + if (z__[j4 - 2] == 0.f) { + z__[j4] = 0.f; + d__ = z__[j4 + 1]; + *dmin__ = d__; + emin = 0.f; + } else if (safmin * z__[j4 + 1] < z__[j4 - 2] && safmin * z__[j4 + - 2] < z__[j4 + 1]) { + temp = z__[j4 + 1] / z__[j4 - 2]; + z__[j4] = z__[j4 - 1] * temp; + d__ *= temp; + } else { + z__[j4] = z__[j4 + 1] * (z__[j4 - 1] / z__[j4 - 2]); + d__ = z__[j4 + 1] * (d__ / z__[j4 - 2]); + } + *dmin__ = dmin(*dmin__,d__); +/* Computing MIN */ + r__1 = emin, r__2 = z__[j4]; + emin = dmin(r__1,r__2); +/* L10: */ + } + } else { + i__1 = *n0 - 3 << 2; + for (j4 = *i0 << 2; j4 <= i__1; j4 += 4) { + z__[j4 - 3] = d__ + z__[j4]; + if (z__[j4 - 3] == 0.f) { + z__[j4 - 1] = 0.f; + d__ = z__[j4 + 2]; + *dmin__ = d__; + emin = 0.f; + } else if (safmin * z__[j4 + 2] < z__[j4 - 3] && safmin * z__[j4 + - 3] < z__[j4 + 2]) { + temp = z__[j4 + 2] / z__[j4 - 3]; + z__[j4 - 1] = z__[j4] * temp; + d__ *= temp; + } else { + z__[j4 - 1] = z__[j4 + 2] * (z__[j4] / z__[j4 - 3]); + d__ = z__[j4 + 2] * (d__ / z__[j4 - 3]); + } + *dmin__ = dmin(*dmin__,d__); +/* Computing MIN */ + r__1 = emin, r__2 = z__[j4 - 1]; + emin = dmin(r__1,r__2); +/* L20: */ + } + } + +/* Unroll last two steps. */ + + *dnm2 = d__; + *dmin2 = *dmin__; + j4 = (*n0 - 2 << 2) - *pp; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm2 + z__[j4p2]; + if (z__[j4 - 2] == 0.f) { + z__[j4] = 0.f; + *dnm1 = z__[j4p2 + 2]; + *dmin__ = *dnm1; + emin = 0.f; + } else if (safmin * z__[j4p2 + 2] < z__[j4 - 2] && safmin * z__[j4 - 2] < + z__[j4p2 + 2]) { + temp = z__[j4p2 + 2] / z__[j4 - 2]; + z__[j4] = z__[j4p2] * temp; + *dnm1 = *dnm2 * temp; + } else { + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dnm1 = z__[j4p2 + 2] * (*dnm2 / z__[j4 - 2]); + } + *dmin__ = dmin(*dmin__,*dnm1); + + *dmin1 = *dmin__; + j4 += 4; + j4p2 = j4 + (*pp << 1) - 1; + z__[j4 - 2] = *dnm1 + z__[j4p2]; + if (z__[j4 - 2] == 0.f) { + z__[j4] = 0.f; + *dn = z__[j4p2 + 2]; + *dmin__ = *dn; + emin = 0.f; + } else if (safmin * z__[j4p2 + 2] < z__[j4 - 2] && safmin * z__[j4 - 2] < + z__[j4p2 + 2]) { + temp = z__[j4p2 + 2] / z__[j4 - 2]; + z__[j4] = z__[j4p2] * temp; + *dn = *dnm1 * temp; + } else { + z__[j4] = z__[j4p2 + 2] * (z__[j4p2] / z__[j4 - 2]); + *dn = z__[j4p2 + 2] * (*dnm1 / z__[j4 - 2]); + } + *dmin__ = dmin(*dmin__,*dn); + + z__[j4 + 2] = *dn; + z__[(*n0 << 2) - *pp] = emin; + return 0; + +/* End of SLASQ6 */ + +} /* slasq6_ */ + +/* Subroutine */ int slasr_(char *side, char *pivot, char *direct, integer *m, + integer *n, real *c__, real *s, real *a, integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, info; + static real temp; + extern logical lsame_(char *, char *); + static real ctemp, stemp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASR applies a sequence of plane rotations to a real matrix A, + from either the left or the right. + + When SIDE = 'L', the transformation takes the form + + A := P*A + + and when SIDE = 'R', the transformation takes the form + + A := A*P**T + + where P is an orthogonal matrix consisting of a sequence of z plane + rotations, with z = M when SIDE = 'L' and z = N when SIDE = 'R', + and P**T is the transpose of P. + + When DIRECT = 'F' (Forward sequence), then + + P = P(z-1) * ... * P(2) * P(1) + + and when DIRECT = 'B' (Backward sequence), then + + P = P(1) * P(2) * ... * P(z-1) + + where P(k) is a plane rotation matrix defined by the 2-by-2 rotation + + R(k) = ( c(k) s(k) ) + = ( -s(k) c(k) ). + + When PIVOT = 'V' (Variable pivot), the rotation is performed + for the plane (k,k+1), i.e., P(k) has the form + + P(k) = ( 1 ) + ( ... ) + ( 1 ) + ( c(k) s(k) ) + ( -s(k) c(k) ) + ( 1 ) + ( ... ) + ( 1 ) + + where R(k) appears as a rank-2 modification to the identity matrix in + rows and columns k and k+1. + + When PIVOT = 'T' (Top pivot), the rotation is performed for the + plane (1,k+1), so P(k) has the form + + P(k) = ( c(k) s(k) ) + ( 1 ) + ( ... ) + ( 1 ) + ( -s(k) c(k) ) + ( 1 ) + ( ... ) + ( 1 ) + + where R(k) appears in rows and columns 1 and k+1. + + Similarly, when PIVOT = 'B' (Bottom pivot), the rotation is + performed for the plane (k,z), giving P(k) the form + + P(k) = ( 1 ) + ( ... ) + ( 1 ) + ( c(k) s(k) ) + ( 1 ) + ( ... ) + ( 1 ) + ( -s(k) c(k) ) + + where R(k) appears in rows and columns k and z. The rotations are + performed without ever forming P(k) explicitly. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + Specifies whether the plane rotation matrix P is applied to + A on the left or the right. + = 'L': Left, compute A := P*A + = 'R': Right, compute A:= A*P**T + + PIVOT (input) CHARACTER*1 + Specifies the plane for which P(k) is a plane rotation + matrix. + = 'V': Variable pivot, the plane (k,k+1) + = 'T': Top pivot, the plane (1,k+1) + = 'B': Bottom pivot, the plane (k,z) + + DIRECT (input) CHARACTER*1 + Specifies whether P is a forward or backward sequence of + plane rotations. + = 'F': Forward, P = P(z-1)*...*P(2)*P(1) + = 'B': Backward, P = P(1)*P(2)*...*P(z-1) + + M (input) INTEGER + The number of rows of the matrix A. If m <= 1, an immediate + return is effected. + + N (input) INTEGER + The number of columns of the matrix A. If n <= 1, an + immediate return is effected. + + C (input) REAL array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + The cosines c(k) of the plane rotations. + + S (input) REAL array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + The sines s(k) of the plane rotations. The 2-by-2 plane + rotation part of the matrix P(k), R(k), has the form + R(k) = ( c(k) s(k) ) + ( -s(k) c(k) ). + + A (input/output) REAL array, dimension (LDA,N) + The M-by-N matrix A. On exit, A is overwritten by P*A if + SIDE = 'R' or by A*P**T if SIDE = 'L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + --c__; + --s; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (! (lsame_(side, "L") || lsame_(side, "R"))) { + info = 1; + } else if (! (lsame_(pivot, "V") || lsame_(pivot, + "T") || lsame_(pivot, "B"))) { + info = 2; + } else if (! (lsame_(direct, "F") || lsame_(direct, + "B"))) { + info = 3; + } else if (*m < 0) { + info = 4; + } else if (*n < 0) { + info = 5; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("SLASR ", &info); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + if (lsame_(side, "L")) { + +/* Form P * A */ + + if (lsame_(pivot, "V")) { + if (lsame_(direct, "F")) { + i__1 = *m - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[j + 1 + i__ * a_dim1]; + a[j + 1 + i__ * a_dim1] = ctemp * temp - stemp * + a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = stemp * temp + ctemp * a[j + + i__ * a_dim1]; +/* L10: */ + } + } +/* L20: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[j + 1 + i__ * a_dim1]; + a[j + 1 + i__ * a_dim1] = ctemp * temp - stemp * + a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = stemp * temp + ctemp * a[j + + i__ * a_dim1]; +/* L30: */ + } + } +/* L40: */ + } + } + } else if (lsame_(pivot, "T")) { + if (lsame_(direct, "F")) { + i__1 = *m; + for (j = 2; j <= i__1; ++j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = ctemp * temp - stemp * a[ + i__ * a_dim1 + 1]; + a[i__ * a_dim1 + 1] = stemp * temp + ctemp * a[ + i__ * a_dim1 + 1]; +/* L50: */ + } + } +/* L60: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m; j >= 2; --j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = ctemp * temp - stemp * a[ + i__ * a_dim1 + 1]; + a[i__ * a_dim1 + 1] = stemp * temp + ctemp * a[ + i__ * a_dim1 + 1]; +/* L70: */ + } + } +/* L80: */ + } + } + } else if (lsame_(pivot, "B")) { + if (lsame_(direct, "F")) { + i__1 = *m - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = stemp * a[*m + i__ * a_dim1] + + ctemp * temp; + a[*m + i__ * a_dim1] = ctemp * a[*m + i__ * + a_dim1] - stemp * temp; +/* L90: */ + } + } +/* L100: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[j + i__ * a_dim1]; + a[j + i__ * a_dim1] = stemp * a[*m + i__ * a_dim1] + + ctemp * temp; + a[*m + i__ * a_dim1] = ctemp * a[*m + i__ * + a_dim1] - stemp * temp; +/* L110: */ + } + } +/* L120: */ + } + } + } + } else if (lsame_(side, "R")) { + +/* Form A * P' */ + + if (lsame_(pivot, "V")) { + if (lsame_(direct, "F")) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[i__ + (j + 1) * a_dim1]; + a[i__ + (j + 1) * a_dim1] = ctemp * temp - stemp * + a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = stemp * temp + ctemp * a[ + i__ + j * a_dim1]; +/* L130: */ + } + } +/* L140: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[i__ + (j + 1) * a_dim1]; + a[i__ + (j + 1) * a_dim1] = ctemp * temp - stemp * + a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = stemp * temp + ctemp * a[ + i__ + j * a_dim1]; +/* L150: */ + } + } +/* L160: */ + } + } + } else if (lsame_(pivot, "T")) { + if (lsame_(direct, "F")) { + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = ctemp * temp - stemp * a[ + i__ + a_dim1]; + a[i__ + a_dim1] = stemp * temp + ctemp * a[i__ + + a_dim1]; +/* L170: */ + } + } +/* L180: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n; j >= 2; --j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = ctemp * temp - stemp * a[ + i__ + a_dim1]; + a[i__ + a_dim1] = stemp * temp + ctemp * a[i__ + + a_dim1]; +/* L190: */ + } + } +/* L200: */ + } + } + } else if (lsame_(pivot, "B")) { + if (lsame_(direct, "F")) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = stemp * a[i__ + *n * a_dim1] + + ctemp * temp; + a[i__ + *n * a_dim1] = ctemp * a[i__ + *n * + a_dim1] - stemp * temp; +/* L210: */ + } + } +/* L220: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1.f || stemp != 0.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + temp = a[i__ + j * a_dim1]; + a[i__ + j * a_dim1] = stemp * a[i__ + *n * a_dim1] + + ctemp * temp; + a[i__ + *n * a_dim1] = ctemp * a[i__ + *n * + a_dim1] - stemp * temp; +/* L230: */ + } + } +/* L240: */ + } + } + } + } + + return 0; + +/* End of SLASR */ + +} /* slasr_ */ + +/* Subroutine */ int slasrt_(char *id, integer *n, real *d__, integer *info) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + static integer i__, j; + static real d1, d2, d3; + static integer dir; + static real tmp; + static integer endd; + extern logical lsame_(char *, char *); + static integer stack[64] /* was [2][32] */; + static real dmnmx; + static integer start; + extern /* Subroutine */ int xerbla_(char *, integer *); + static integer stkpnt; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + Sort the numbers in D in increasing order (if ID = 'I') or + in decreasing order (if ID = 'D' ). + + Use Quick Sort, reverting to Insertion sort on arrays of + size <= 20. Dimension of STACK limits N to about 2**32. + + Arguments + ========= + + ID (input) CHARACTER*1 + = 'I': sort D in increasing order; + = 'D': sort D in decreasing order. + + N (input) INTEGER + The length of the array D. + + D (input/output) REAL array, dimension (N) + On entry, the array to be sorted. + On exit, D has been sorted into increasing order + (D(1) <= ... <= D(N) ) or into decreasing order + (D(1) >= ... >= D(N) ), depending on ID. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input paramters. +*/ + + /* Parameter adjustments */ + --d__; + + /* Function Body */ + *info = 0; + dir = -1; + if (lsame_(id, "D")) { + dir = 0; + } else if (lsame_(id, "I")) { + dir = 1; + } + if (dir == -1) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLASRT", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 1) { + return 0; + } + + stkpnt = 1; + stack[0] = 1; + stack[1] = *n; +L10: + start = stack[(stkpnt << 1) - 2]; + endd = stack[(stkpnt << 1) - 1]; + --stkpnt; + if (endd - start <= 20 && endd - start > 0) { + +/* Do Insertion sort on D( START:ENDD ) */ + + if (dir == 0) { + +/* Sort into decreasing order */ + + i__1 = endd; + for (i__ = start + 1; i__ <= i__1; ++i__) { + i__2 = start + 1; + for (j = i__; j >= i__2; --j) { + if (d__[j] > d__[j - 1]) { + dmnmx = d__[j]; + d__[j] = d__[j - 1]; + d__[j - 1] = dmnmx; + } else { + goto L30; + } +/* L20: */ + } +L30: + ; + } + + } else { + +/* Sort into increasing order */ + + i__1 = endd; + for (i__ = start + 1; i__ <= i__1; ++i__) { + i__2 = start + 1; + for (j = i__; j >= i__2; --j) { + if (d__[j] < d__[j - 1]) { + dmnmx = d__[j]; + d__[j] = d__[j - 1]; + d__[j - 1] = dmnmx; + } else { + goto L50; + } +/* L40: */ + } +L50: + ; + } + + } + + } else if (endd - start > 20) { + +/* + Partition D( START:ENDD ) and stack parts, largest one first + + Choose partition entry as median of 3 +*/ + + d1 = d__[start]; + d2 = d__[endd]; + i__ = (start + endd) / 2; + d3 = d__[i__]; + if (d1 < d2) { + if (d3 < d1) { + dmnmx = d1; + } else if (d3 < d2) { + dmnmx = d3; + } else { + dmnmx = d2; + } + } else { + if (d3 < d2) { + dmnmx = d2; + } else if (d3 < d1) { + dmnmx = d3; + } else { + dmnmx = d1; + } + } + + if (dir == 0) { + +/* Sort into decreasing order */ + + i__ = start - 1; + j = endd + 1; +L60: +L70: + --j; + if (d__[j] < dmnmx) { + goto L70; + } +L80: + ++i__; + if (d__[i__] > dmnmx) { + goto L80; + } + if (i__ < j) { + tmp = d__[i__]; + d__[i__] = d__[j]; + d__[j] = tmp; + goto L60; + } + if (j - start > endd - j - 1) { + ++stkpnt; + stack[(stkpnt << 1) - 2] = start; + stack[(stkpnt << 1) - 1] = j; + ++stkpnt; + stack[(stkpnt << 1) - 2] = j + 1; + stack[(stkpnt << 1) - 1] = endd; + } else { + ++stkpnt; + stack[(stkpnt << 1) - 2] = j + 1; + stack[(stkpnt << 1) - 1] = endd; + ++stkpnt; + stack[(stkpnt << 1) - 2] = start; + stack[(stkpnt << 1) - 1] = j; + } + } else { + +/* Sort into increasing order */ + + i__ = start - 1; + j = endd + 1; +L90: +L100: + --j; + if (d__[j] > dmnmx) { + goto L100; + } +L110: + ++i__; + if (d__[i__] < dmnmx) { + goto L110; + } + if (i__ < j) { + tmp = d__[i__]; + d__[i__] = d__[j]; + d__[j] = tmp; + goto L90; + } + if (j - start > endd - j - 1) { + ++stkpnt; + stack[(stkpnt << 1) - 2] = start; + stack[(stkpnt << 1) - 1] = j; + ++stkpnt; + stack[(stkpnt << 1) - 2] = j + 1; + stack[(stkpnt << 1) - 1] = endd; + } else { + ++stkpnt; + stack[(stkpnt << 1) - 2] = j + 1; + stack[(stkpnt << 1) - 1] = endd; + ++stkpnt; + stack[(stkpnt << 1) - 2] = start; + stack[(stkpnt << 1) - 1] = j; + } + } + } + if (stkpnt > 0) { + goto L10; + } + return 0; + +/* End of SLASRT */ + +} /* slasrt_ */ + +/* Subroutine */ int slassq_(integer *n, real *x, integer *incx, real *scale, + real *sumsq) +{ + /* System generated locals */ + integer i__1, i__2; + real r__1; + + /* Local variables */ + static integer ix; + static real absxi; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASSQ returns the values scl and smsq such that + + ( scl**2 )*smsq = x( 1 )**2 +...+ x( n )**2 + ( scale**2 )*sumsq, + + where x( i ) = X( 1 + ( i - 1 )*INCX ). The value of sumsq is + assumed to be non-negative and scl returns the value + + scl = max( scale, abs( x( i ) ) ). + + scale and sumsq must be supplied in SCALE and SUMSQ and + scl and smsq are overwritten on SCALE and SUMSQ respectively. + + The routine makes only one pass through the vector x. + + Arguments + ========= + + N (input) INTEGER + The number of elements to be used from the vector X. + + X (input) REAL array, dimension (N) + The vector for which a scaled sum of squares is computed. + x( i ) = X( 1 + ( i - 1 )*INCX ), 1 <= i <= n. + + INCX (input) INTEGER + The increment between successive values of the vector X. + INCX > 0. + + SCALE (input/output) REAL + On entry, the value scale in the equation above. + On exit, SCALE is overwritten with scl , the scaling factor + for the sum of squares. + + SUMSQ (input/output) REAL + On entry, the value sumsq in the equation above. + On exit, SUMSQ is overwritten with smsq , the basic sum of + squares from which scl has been factored out. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n > 0) { + i__1 = (*n - 1) * *incx + 1; + i__2 = *incx; + for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) { + if (x[ix] != 0.f) { + absxi = (r__1 = x[ix], dabs(r__1)); + if (*scale < absxi) { +/* Computing 2nd power */ + r__1 = *scale / absxi; + *sumsq = *sumsq * (r__1 * r__1) + 1; + *scale = absxi; + } else { +/* Computing 2nd power */ + r__1 = absxi / *scale; + *sumsq += r__1 * r__1; + } + } +/* L10: */ + } + } + return 0; + +/* End of SLASSQ */ + +} /* slassq_ */ + +/* Subroutine */ int slasv2_(real *f, real *g, real *h__, real *ssmin, real * + ssmax, real *snr, real *csr, real *snl, real *csl) +{ + /* System generated locals */ + real r__1; + + /* Local variables */ + static real a, d__, l, m, r__, s, t, fa, ga, ha, ft, gt, ht, mm, tt, clt, + crt, slt, srt; + static integer pmax; + static real temp; + static logical swap; + static real tsign; + static logical gasmal; + extern doublereal slamch_(char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASV2 computes the singular value decomposition of a 2-by-2 + triangular matrix + [ F G ] + [ 0 H ]. + On return, abs(SSMAX) is the larger singular value, abs(SSMIN) is the + smaller singular value, and (CSL,SNL) and (CSR,SNR) are the left and + right singular vectors for abs(SSMAX), giving the decomposition + + [ CSL SNL ] [ F G ] [ CSR -SNR ] = [ SSMAX 0 ] + [-SNL CSL ] [ 0 H ] [ SNR CSR ] [ 0 SSMIN ]. + + Arguments + ========= + + F (input) REAL + The (1,1) element of the 2-by-2 matrix. + + G (input) REAL + The (1,2) element of the 2-by-2 matrix. + + H (input) REAL + The (2,2) element of the 2-by-2 matrix. + + SSMIN (output) REAL + abs(SSMIN) is the smaller singular value. + + SSMAX (output) REAL + abs(SSMAX) is the larger singular value. + + SNL (output) REAL + CSL (output) REAL + The vector (CSL, SNL) is a unit left singular vector for the + singular value abs(SSMAX). + + SNR (output) REAL + CSR (output) REAL + The vector (CSR, SNR) is a unit right singular vector for the + singular value abs(SSMAX). + + Further Details + =============== + + Any input parameter may be aliased with any output parameter. + + Barring over/underflow and assuming a guard digit in subtraction, all + output quantities are correct to within a few units in the last + place (ulps). + + In IEEE arithmetic, the code works correctly if one matrix element is + infinite. + + Overflow will not occur unless the largest singular value itself + overflows or is within a few ulps of overflow. (On machines with + partial overflow, like the Cray, overflow may occur if the largest + singular value is within a factor of 2 of overflow.) + + Underflow is harmless if underflow is gradual. Otherwise, results + may correspond to a matrix modified by perturbations of size near + the underflow threshold. + + ===================================================================== +*/ + + + ft = *f; + fa = dabs(ft); + ht = *h__; + ha = dabs(*h__); + +/* + PMAX points to the maximum absolute element of matrix + PMAX = 1 if F largest in absolute values + PMAX = 2 if G largest in absolute values + PMAX = 3 if H largest in absolute values +*/ + + pmax = 1; + swap = ha > fa; + if (swap) { + pmax = 3; + temp = ft; + ft = ht; + ht = temp; + temp = fa; + fa = ha; + ha = temp; + +/* Now FA .ge. HA */ + + } + gt = *g; + ga = dabs(gt); + if (ga == 0.f) { + +/* Diagonal matrix */ + + *ssmin = ha; + *ssmax = fa; + clt = 1.f; + crt = 1.f; + slt = 0.f; + srt = 0.f; + } else { + gasmal = TRUE_; + if (ga > fa) { + pmax = 2; + if (fa / ga < slamch_("EPS")) { + +/* Case of very large GA */ + + gasmal = FALSE_; + *ssmax = ga; + if (ha > 1.f) { + *ssmin = fa / (ga / ha); + } else { + *ssmin = fa / ga * ha; + } + clt = 1.f; + slt = ht / gt; + srt = 1.f; + crt = ft / gt; + } + } + if (gasmal) { + +/* Normal case */ + + d__ = fa - ha; + if (d__ == fa) { + +/* Copes with infinite F or H */ + + l = 1.f; + } else { + l = d__ / fa; + } + +/* Note that 0 .le. L .le. 1 */ + + m = gt / ft; + +/* Note that abs(M) .le. 1/macheps */ + + t = 2.f - l; + +/* Note that T .ge. 1 */ + + mm = m * m; + tt = t * t; + s = sqrt(tt + mm); + +/* Note that 1 .le. S .le. 1 + 1/macheps */ + + if (l == 0.f) { + r__ = dabs(m); + } else { + r__ = sqrt(l * l + mm); + } + +/* Note that 0 .le. R .le. 1 + 1/macheps */ + + a = (s + r__) * .5f; + +/* Note that 1 .le. A .le. 1 + abs(M) */ + + *ssmin = ha / a; + *ssmax = fa * a; + if (mm == 0.f) { + +/* Note that M is very tiny */ + + if (l == 0.f) { + t = r_sign(&c_b2863, &ft) * r_sign(&c_b15, >); + } else { + t = gt / r_sign(&d__, &ft) + m / t; + } + } else { + t = (m / (s + t) + m / (r__ + l)) * (a + 1.f); + } + l = sqrt(t * t + 4.f); + crt = 2.f / l; + srt = t / l; + clt = (crt + srt * m) / a; + slt = ht / ft * srt / a; + } + } + if (swap) { + *csl = srt; + *snl = crt; + *csr = slt; + *snr = clt; + } else { + *csl = clt; + *snl = slt; + *csr = crt; + *snr = srt; + } + +/* Correct signs of SSMAX and SSMIN */ + + if (pmax == 1) { + tsign = r_sign(&c_b15, csr) * r_sign(&c_b15, csl) * r_sign(&c_b15, f); + } + if (pmax == 2) { + tsign = r_sign(&c_b15, snr) * r_sign(&c_b15, csl) * r_sign(&c_b15, g); + } + if (pmax == 3) { + tsign = r_sign(&c_b15, snr) * r_sign(&c_b15, snl) * r_sign(&c_b15, + h__); + } + *ssmax = r_sign(ssmax, &tsign); + r__1 = tsign * r_sign(&c_b15, f) * r_sign(&c_b15, h__); + *ssmin = r_sign(ssmin, &r__1); + return 0; + +/* End of SLASV2 */ + +} /* slasv2_ */ + +/* Subroutine */ int slaswp_(integer *n, real *a, integer *lda, integer *k1, + integer *k2, integer *ipiv, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, k, i1, i2, n32, ip, ix, ix0, inc; + static real temp; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASWP performs a series of row interchanges on the matrix A. + One row interchange is initiated for each of rows K1 through K2 of A. + + Arguments + ========= + + N (input) INTEGER + The number of columns of the matrix A. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the matrix of column dimension N to which the row + interchanges will be applied. + On exit, the permuted matrix. + + LDA (input) INTEGER + The leading dimension of the array A. + + K1 (input) INTEGER + The first element of IPIV for which a row interchange will + be done. + + K2 (input) INTEGER + The last element of IPIV for which a row interchange will + be done. + + IPIV (input) INTEGER array, dimension (K2*abs(INCX)) + The vector of pivot indices. Only the elements in positions + K1 through K2 of IPIV are accessed. + IPIV(K) = L implies rows K and L are to be interchanged. + + INCX (input) INTEGER + The increment between successive values of IPIV. If IPIV + is negative, the pivots are applied in reverse order. + + Further Details + =============== + + Modified by + R. C. Whaley, Computer Science Dept., Univ. of Tenn., Knoxville, USA + + ===================================================================== + + + Interchange row I with row IPIV(I) for each of rows K1 through K2. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + if (*incx > 0) { + ix0 = *k1; + i1 = *k1; + i2 = *k2; + inc = 1; + } else if (*incx < 0) { + ix0 = (1 - *k2) * *incx + 1; + i1 = *k2; + i2 = *k1; + inc = -1; + } else { + return 0; + } + + n32 = *n / 32 << 5; + if (n32 != 0) { + i__1 = n32; + for (j = 1; j <= i__1; j += 32) { + ix = ix0; + i__2 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__3) + { + ip = ipiv[ix]; + if (ip != i__) { + i__4 = j + 31; + for (k = j; k <= i__4; ++k) { + temp = a[i__ + k * a_dim1]; + a[i__ + k * a_dim1] = a[ip + k * a_dim1]; + a[ip + k * a_dim1] = temp; +/* L10: */ + } + } + ix += *incx; +/* L20: */ + } +/* L30: */ + } + } + if (n32 != *n) { + ++n32; + ix = ix0; + i__1 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__3) { + ip = ipiv[ix]; + if (ip != i__) { + i__2 = *n; + for (k = n32; k <= i__2; ++k) { + temp = a[i__ + k * a_dim1]; + a[i__ + k * a_dim1] = a[ip + k * a_dim1]; + a[ip + k * a_dim1] = temp; +/* L40: */ + } + } + ix += *incx; +/* L50: */ + } + } + + return 0; + +/* End of SLASWP */ + +} /* slaswp_ */ + +/* Subroutine */ int slasy2_(logical *ltranl, logical *ltranr, integer *isgn, + integer *n1, integer *n2, real *tl, integer *ldtl, real *tr, integer * + ldtr, real *b, integer *ldb, real *scale, real *x, integer *ldx, real + *xnorm, integer *info) +{ + /* Initialized data */ + + static integer locu12[4] = { 3,4,1,2 }; + static integer locl21[4] = { 2,1,4,3 }; + static integer locu22[4] = { 4,3,2,1 }; + static logical xswpiv[4] = { FALSE_,FALSE_,TRUE_,TRUE_ }; + static logical bswpiv[4] = { FALSE_,TRUE_,FALSE_,TRUE_ }; + + /* System generated locals */ + integer b_dim1, b_offset, tl_dim1, tl_offset, tr_dim1, tr_offset, x_dim1, + x_offset; + real r__1, r__2, r__3, r__4, r__5, r__6, r__7, r__8; + + /* Local variables */ + static integer i__, j, k; + static real x2[2], l21, u11, u12; + static integer ip, jp; + static real u22, t16[16] /* was [4][4] */, gam, bet, eps, sgn, tmp[4], + tau1, btmp[4], smin; + static integer ipiv; + static real temp; + static integer jpiv[4]; + static real xmax; + static integer ipsv, jpsv; + static logical bswap; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *), sswap_(integer *, real *, integer *, real *, integer * + ); + static logical xswap; + extern doublereal slamch_(char *); + extern integer isamax_(integer *, real *, integer *); + static real smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLASY2 solves for the N1 by N2 matrix X, 1 <= N1,N2 <= 2, in + + op(TL)*X + ISGN*X*op(TR) = SCALE*B, + + where TL is N1 by N1, TR is N2 by N2, B is N1 by N2, and ISGN = 1 or + -1. op(T) = T or T', where T' denotes the transpose of T. + + Arguments + ========= + + LTRANL (input) LOGICAL + On entry, LTRANL specifies the op(TL): + = .FALSE., op(TL) = TL, + = .TRUE., op(TL) = TL'. + + LTRANR (input) LOGICAL + On entry, LTRANR specifies the op(TR): + = .FALSE., op(TR) = TR, + = .TRUE., op(TR) = TR'. + + ISGN (input) INTEGER + On entry, ISGN specifies the sign of the equation + as described before. ISGN may only be 1 or -1. + + N1 (input) INTEGER + On entry, N1 specifies the order of matrix TL. + N1 may only be 0, 1 or 2. + + N2 (input) INTEGER + On entry, N2 specifies the order of matrix TR. + N2 may only be 0, 1 or 2. + + TL (input) REAL array, dimension (LDTL,2) + On entry, TL contains an N1 by N1 matrix. + + LDTL (input) INTEGER + The leading dimension of the matrix TL. LDTL >= max(1,N1). + + TR (input) REAL array, dimension (LDTR,2) + On entry, TR contains an N2 by N2 matrix. + + LDTR (input) INTEGER + The leading dimension of the matrix TR. LDTR >= max(1,N2). + + B (input) REAL array, dimension (LDB,2) + On entry, the N1 by N2 matrix B contains the right-hand + side of the equation. + + LDB (input) INTEGER + The leading dimension of the matrix B. LDB >= max(1,N1). + + SCALE (output) REAL + On exit, SCALE contains the scale factor. SCALE is chosen + less than or equal to 1 to prevent the solution overflowing. + + X (output) REAL array, dimension (LDX,2) + On exit, X contains the N1 by N2 solution. + + LDX (input) INTEGER + The leading dimension of the matrix X. LDX >= max(1,N1). + + XNORM (output) REAL + On exit, XNORM is the infinity-norm of the solution. + + INFO (output) INTEGER + On exit, INFO is set to + 0: successful exit. + 1: TL and TR have too close eigenvalues, so TL or + TR is perturbed to get a nonsingular equation. + NOTE: In the interests of speed, this routine does not + check the inputs for errors. + + ===================================================================== +*/ + + /* Parameter adjustments */ + tl_dim1 = *ldtl; + tl_offset = 1 + tl_dim1; + tl -= tl_offset; + tr_dim1 = *ldtr; + tr_offset = 1 + tr_dim1; + tr -= tr_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + + /* Function Body */ + +/* Do not check the input parameters for errors */ + + *info = 0; + +/* Quick return if possible */ + + if (*n1 == 0 || *n2 == 0) { + return 0; + } + +/* Set constants to control overflow */ + + eps = slamch_("P"); + smlnum = slamch_("S") / eps; + sgn = (real) (*isgn); + + k = *n1 + *n1 + *n2 - 2; + switch (k) { + case 1: goto L10; + case 2: goto L20; + case 3: goto L30; + case 4: goto L50; + } + +/* 1 by 1: TL11*X + SGN*X*TR11 = B11 */ + +L10: + tau1 = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1]; + bet = dabs(tau1); + if (bet <= smlnum) { + tau1 = smlnum; + bet = smlnum; + *info = 1; + } + + *scale = 1.f; + gam = (r__1 = b[b_dim1 + 1], dabs(r__1)); + if (smlnum * gam > bet) { + *scale = 1.f / gam; + } + + x[x_dim1 + 1] = b[b_dim1 + 1] * *scale / tau1; + *xnorm = (r__1 = x[x_dim1 + 1], dabs(r__1)); + return 0; + +/* + 1 by 2: + TL11*[X11 X12] + ISGN*[X11 X12]*op[TR11 TR12] = [B11 B12] + [TR21 TR22] +*/ + +L20: + +/* + Computing MAX + Computing MAX +*/ + r__7 = (r__1 = tl[tl_dim1 + 1], dabs(r__1)), r__8 = (r__2 = tr[tr_dim1 + + 1], dabs(r__2)), r__7 = max(r__7,r__8), r__8 = (r__3 = tr[( + tr_dim1 << 1) + 1], dabs(r__3)), r__7 = max(r__7,r__8), r__8 = ( + r__4 = tr[tr_dim1 + 2], dabs(r__4)), r__7 = max(r__7,r__8), r__8 = + (r__5 = tr[(tr_dim1 << 1) + 2], dabs(r__5)); + r__6 = eps * dmax(r__7,r__8); + smin = dmax(r__6,smlnum); + tmp[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1]; + tmp[3] = tl[tl_dim1 + 1] + sgn * tr[(tr_dim1 << 1) + 2]; + if (*ltranr) { + tmp[1] = sgn * tr[tr_dim1 + 2]; + tmp[2] = sgn * tr[(tr_dim1 << 1) + 1]; + } else { + tmp[1] = sgn * tr[(tr_dim1 << 1) + 1]; + tmp[2] = sgn * tr[tr_dim1 + 2]; + } + btmp[0] = b[b_dim1 + 1]; + btmp[1] = b[(b_dim1 << 1) + 1]; + goto L40; + +/* + 2 by 1: + op[TL11 TL12]*[X11] + ISGN* [X11]*TR11 = [B11] + [TL21 TL22] [X21] [X21] [B21] +*/ + +L30: +/* + Computing MAX + Computing MAX +*/ + r__7 = (r__1 = tr[tr_dim1 + 1], dabs(r__1)), r__8 = (r__2 = tl[tl_dim1 + + 1], dabs(r__2)), r__7 = max(r__7,r__8), r__8 = (r__3 = tl[( + tl_dim1 << 1) + 1], dabs(r__3)), r__7 = max(r__7,r__8), r__8 = ( + r__4 = tl[tl_dim1 + 2], dabs(r__4)), r__7 = max(r__7,r__8), r__8 = + (r__5 = tl[(tl_dim1 << 1) + 2], dabs(r__5)); + r__6 = eps * dmax(r__7,r__8); + smin = dmax(r__6,smlnum); + tmp[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1]; + tmp[3] = tl[(tl_dim1 << 1) + 2] + sgn * tr[tr_dim1 + 1]; + if (*ltranl) { + tmp[1] = tl[(tl_dim1 << 1) + 1]; + tmp[2] = tl[tl_dim1 + 2]; + } else { + tmp[1] = tl[tl_dim1 + 2]; + tmp[2] = tl[(tl_dim1 << 1) + 1]; + } + btmp[0] = b[b_dim1 + 1]; + btmp[1] = b[b_dim1 + 2]; +L40: + +/* + Solve 2 by 2 system using complete pivoting. + Set pivots less than SMIN to SMIN. +*/ + + ipiv = isamax_(&c__4, tmp, &c__1); + u11 = tmp[ipiv - 1]; + if (dabs(u11) <= smin) { + *info = 1; + u11 = smin; + } + u12 = tmp[locu12[ipiv - 1] - 1]; + l21 = tmp[locl21[ipiv - 1] - 1] / u11; + u22 = tmp[locu22[ipiv - 1] - 1] - u12 * l21; + xswap = xswpiv[ipiv - 1]; + bswap = bswpiv[ipiv - 1]; + if (dabs(u22) <= smin) { + *info = 1; + u22 = smin; + } + if (bswap) { + temp = btmp[1]; + btmp[1] = btmp[0] - l21 * temp; + btmp[0] = temp; + } else { + btmp[1] -= l21 * btmp[0]; + } + *scale = 1.f; + if (smlnum * 2.f * dabs(btmp[1]) > dabs(u22) || smlnum * 2.f * dabs(btmp[ + 0]) > dabs(u11)) { +/* Computing MAX */ + r__1 = dabs(btmp[0]), r__2 = dabs(btmp[1]); + *scale = .5f / dmax(r__1,r__2); + btmp[0] *= *scale; + btmp[1] *= *scale; + } + x2[1] = btmp[1] / u22; + x2[0] = btmp[0] / u11 - u12 / u11 * x2[1]; + if (xswap) { + temp = x2[1]; + x2[1] = x2[0]; + x2[0] = temp; + } + x[x_dim1 + 1] = x2[0]; + if (*n1 == 1) { + x[(x_dim1 << 1) + 1] = x2[1]; + *xnorm = (r__1 = x[x_dim1 + 1], dabs(r__1)) + (r__2 = x[(x_dim1 << 1) + + 1], dabs(r__2)); + } else { + x[x_dim1 + 2] = x2[1]; +/* Computing MAX */ + r__3 = (r__1 = x[x_dim1 + 1], dabs(r__1)), r__4 = (r__2 = x[x_dim1 + + 2], dabs(r__2)); + *xnorm = dmax(r__3,r__4); + } + return 0; + +/* + 2 by 2: + op[TL11 TL12]*[X11 X12] +ISGN* [X11 X12]*op[TR11 TR12] = [B11 B12] + [TL21 TL22] [X21 X22] [X21 X22] [TR21 TR22] [B21 B22] + + Solve equivalent 4 by 4 system using complete pivoting. + Set pivots less than SMIN to SMIN. +*/ + +L50: +/* Computing MAX */ + r__5 = (r__1 = tr[tr_dim1 + 1], dabs(r__1)), r__6 = (r__2 = tr[(tr_dim1 << + 1) + 1], dabs(r__2)), r__5 = max(r__5,r__6), r__6 = (r__3 = tr[ + tr_dim1 + 2], dabs(r__3)), r__5 = max(r__5,r__6), r__6 = (r__4 = + tr[(tr_dim1 << 1) + 2], dabs(r__4)); + smin = dmax(r__5,r__6); +/* Computing MAX */ + r__5 = smin, r__6 = (r__1 = tl[tl_dim1 + 1], dabs(r__1)), r__5 = max(r__5, + r__6), r__6 = (r__2 = tl[(tl_dim1 << 1) + 1], dabs(r__2)), r__5 = + max(r__5,r__6), r__6 = (r__3 = tl[tl_dim1 + 2], dabs(r__3)), r__5 + = max(r__5,r__6), r__6 = (r__4 = tl[(tl_dim1 << 1) + 2], dabs( + r__4)); + smin = dmax(r__5,r__6); +/* Computing MAX */ + r__1 = eps * smin; + smin = dmax(r__1,smlnum); + btmp[0] = 0.f; + scopy_(&c__16, btmp, &c__0, t16, &c__1); + t16[0] = tl[tl_dim1 + 1] + sgn * tr[tr_dim1 + 1]; + t16[5] = tl[(tl_dim1 << 1) + 2] + sgn * tr[tr_dim1 + 1]; + t16[10] = tl[tl_dim1 + 1] + sgn * tr[(tr_dim1 << 1) + 2]; + t16[15] = tl[(tl_dim1 << 1) + 2] + sgn * tr[(tr_dim1 << 1) + 2]; + if (*ltranl) { + t16[4] = tl[tl_dim1 + 2]; + t16[1] = tl[(tl_dim1 << 1) + 1]; + t16[14] = tl[tl_dim1 + 2]; + t16[11] = tl[(tl_dim1 << 1) + 1]; + } else { + t16[4] = tl[(tl_dim1 << 1) + 1]; + t16[1] = tl[tl_dim1 + 2]; + t16[14] = tl[(tl_dim1 << 1) + 1]; + t16[11] = tl[tl_dim1 + 2]; + } + if (*ltranr) { + t16[8] = sgn * tr[(tr_dim1 << 1) + 1]; + t16[13] = sgn * tr[(tr_dim1 << 1) + 1]; + t16[2] = sgn * tr[tr_dim1 + 2]; + t16[7] = sgn * tr[tr_dim1 + 2]; + } else { + t16[8] = sgn * tr[tr_dim1 + 2]; + t16[13] = sgn * tr[tr_dim1 + 2]; + t16[2] = sgn * tr[(tr_dim1 << 1) + 1]; + t16[7] = sgn * tr[(tr_dim1 << 1) + 1]; + } + btmp[0] = b[b_dim1 + 1]; + btmp[1] = b[b_dim1 + 2]; + btmp[2] = b[(b_dim1 << 1) + 1]; + btmp[3] = b[(b_dim1 << 1) + 2]; + +/* Perform elimination */ + + for (i__ = 1; i__ <= 3; ++i__) { + xmax = 0.f; + for (ip = i__; ip <= 4; ++ip) { + for (jp = i__; jp <= 4; ++jp) { + if ((r__1 = t16[ip + (jp << 2) - 5], dabs(r__1)) >= xmax) { + xmax = (r__1 = t16[ip + (jp << 2) - 5], dabs(r__1)); + ipsv = ip; + jpsv = jp; + } +/* L60: */ + } +/* L70: */ + } + if (ipsv != i__) { + sswap_(&c__4, &t16[ipsv - 1], &c__4, &t16[i__ - 1], &c__4); + temp = btmp[i__ - 1]; + btmp[i__ - 1] = btmp[ipsv - 1]; + btmp[ipsv - 1] = temp; + } + if (jpsv != i__) { + sswap_(&c__4, &t16[(jpsv << 2) - 4], &c__1, &t16[(i__ << 2) - 4], + &c__1); + } + jpiv[i__ - 1] = jpsv; + if ((r__1 = t16[i__ + (i__ << 2) - 5], dabs(r__1)) < smin) { + *info = 1; + t16[i__ + (i__ << 2) - 5] = smin; + } + for (j = i__ + 1; j <= 4; ++j) { + t16[j + (i__ << 2) - 5] /= t16[i__ + (i__ << 2) - 5]; + btmp[j - 1] -= t16[j + (i__ << 2) - 5] * btmp[i__ - 1]; + for (k = i__ + 1; k <= 4; ++k) { + t16[j + (k << 2) - 5] -= t16[j + (i__ << 2) - 5] * t16[i__ + ( + k << 2) - 5]; +/* L80: */ + } +/* L90: */ + } +/* L100: */ + } + if (dabs(t16[15]) < smin) { + t16[15] = smin; + } + *scale = 1.f; + if (smlnum * 8.f * dabs(btmp[0]) > dabs(t16[0]) || smlnum * 8.f * dabs( + btmp[1]) > dabs(t16[5]) || smlnum * 8.f * dabs(btmp[2]) > dabs( + t16[10]) || smlnum * 8.f * dabs(btmp[3]) > dabs(t16[15])) { +/* Computing MAX */ + r__1 = dabs(btmp[0]), r__2 = dabs(btmp[1]), r__1 = max(r__1,r__2), + r__2 = dabs(btmp[2]), r__1 = max(r__1,r__2), r__2 = dabs(btmp[ + 3]); + *scale = .125f / dmax(r__1,r__2); + btmp[0] *= *scale; + btmp[1] *= *scale; + btmp[2] *= *scale; + btmp[3] *= *scale; + } + for (i__ = 1; i__ <= 4; ++i__) { + k = 5 - i__; + temp = 1.f / t16[k + (k << 2) - 5]; + tmp[k - 1] = btmp[k - 1] * temp; + for (j = k + 1; j <= 4; ++j) { + tmp[k - 1] -= temp * t16[k + (j << 2) - 5] * tmp[j - 1]; +/* L110: */ + } +/* L120: */ + } + for (i__ = 1; i__ <= 3; ++i__) { + if (jpiv[4 - i__ - 1] != 4 - i__) { + temp = tmp[4 - i__ - 1]; + tmp[4 - i__ - 1] = tmp[jpiv[4 - i__ - 1] - 1]; + tmp[jpiv[4 - i__ - 1] - 1] = temp; + } +/* L130: */ + } + x[x_dim1 + 1] = tmp[0]; + x[x_dim1 + 2] = tmp[1]; + x[(x_dim1 << 1) + 1] = tmp[2]; + x[(x_dim1 << 1) + 2] = tmp[3]; +/* Computing MAX */ + r__1 = dabs(tmp[0]) + dabs(tmp[2]), r__2 = dabs(tmp[1]) + dabs(tmp[3]); + *xnorm = dmax(r__1,r__2); + return 0; + +/* End of SLASY2 */ + +} /* slasy2_ */ + +/* Subroutine */ int slatrd_(char *uplo, integer *n, integer *nb, real *a, + integer *lda, real *e, real *tau, real *w, integer *ldw) +{ + /* System generated locals */ + integer a_dim1, a_offset, w_dim1, w_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, iw; + extern doublereal sdot_(integer *, real *, integer *, real *, integer *); + static real alpha; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + sgemv_(char *, integer *, integer *, real *, real *, integer *, + real *, integer *, real *, real *, integer *), saxpy_( + integer *, real *, real *, integer *, real *, integer *), ssymv_( + char *, integer *, real *, real *, integer *, real *, integer *, + real *, real *, integer *), slarfg_(integer *, real *, + real *, integer *, real *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLATRD reduces NB rows and columns of a real symmetric matrix A to + symmetric tridiagonal form by an orthogonal similarity + transformation Q' * A * Q, and returns the matrices V and W which are + needed to apply the transformation to the unreduced part of A. + + If UPLO = 'U', SLATRD reduces the last NB rows and columns of a + matrix, of which the upper triangle is supplied; + if UPLO = 'L', SLATRD reduces the first NB rows and columns of a + matrix, of which the lower triangle is supplied. + + This is an auxiliary routine called by SSYTRD. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is stored: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. + + NB (input) INTEGER + The number of rows and columns to be reduced. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + n-by-n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n-by-n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit: + if UPLO = 'U', the last NB columns have been reduced to + tridiagonal form, with the diagonal elements overwriting + the diagonal elements of A; the elements above the diagonal + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors; + if UPLO = 'L', the first NB columns have been reduced to + tridiagonal form, with the diagonal elements overwriting + the diagonal elements of A; the elements below the diagonal + with the array TAU, represent the orthogonal matrix Q as a + product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= (1,N). + + E (output) REAL array, dimension (N-1) + If UPLO = 'U', E(n-nb:n-1) contains the superdiagonal + elements of the last NB columns of the reduced matrix; + if UPLO = 'L', E(1:nb) contains the subdiagonal elements of + the first NB columns of the reduced matrix. + + TAU (output) REAL array, dimension (N-1) + The scalar factors of the elementary reflectors, stored in + TAU(n-nb:n-1) if UPLO = 'U', and in TAU(1:nb) if UPLO = 'L'. + See Further Details. + + W (output) REAL array, dimension (LDW,NB) + The n-by-nb matrix W required to update the unreduced part + of A. + + LDW (input) INTEGER + The leading dimension of the array W. LDW >= max(1,N). + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n) H(n-1) . . . H(n-nb+1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i:n) = 0 and v(i-1) = 1; v(1:i-1) is stored on exit in A(1:i-1,i), + and tau in TAU(i-1). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(nb). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0 and v(i+1) = 1; v(i+1:n) is stored on exit in A(i+1:n,i), + and tau in TAU(i). + + The elements of the vectors v together form the n-by-nb matrix V + which is needed, with W, to apply the transformation to the unreduced + part of the matrix, using a symmetric rank-2k update of the form: + A := A - V*W' - W*V'. + + The contents of A on exit are illustrated by the following examples + with n = 5 and nb = 2: + + if UPLO = 'U': if UPLO = 'L': + + ( a a a v4 v5 ) ( d ) + ( a a v4 v5 ) ( 1 d ) + ( a 1 v5 ) ( v1 1 a ) + ( d 1 ) ( v1 v2 a a ) + ( d ) ( v1 v2 a a a ) + + where d denotes a diagonal element of the reduced matrix, a denotes + an element of the original matrix that is unchanged, and vi denotes + an element of the vector defining H(i). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --e; + --tau; + w_dim1 = *ldw; + w_offset = 1 + w_dim1; + w -= w_offset; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + + if (lsame_(uplo, "U")) { + +/* Reduce last NB columns of upper triangle */ + + i__1 = *n - *nb + 1; + for (i__ = *n; i__ >= i__1; --i__) { + iw = i__ - *n + *nb; + if (i__ < *n) { + +/* Update A(1:i,i) */ + + i__2 = *n - i__; + sgemv_("No transpose", &i__, &i__2, &c_b151, &a[(i__ + 1) * + a_dim1 + 1], lda, &w[i__ + (iw + 1) * w_dim1], ldw, & + c_b15, &a[i__ * a_dim1 + 1], &c__1); + i__2 = *n - i__; + sgemv_("No transpose", &i__, &i__2, &c_b151, &w[(iw + 1) * + w_dim1 + 1], ldw, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b15, &a[i__ * a_dim1 + 1], &c__1); + } + if (i__ > 1) { + +/* + Generate elementary reflector H(i) to annihilate + A(1:i-2,i) +*/ + + i__2 = i__ - 1; + slarfg_(&i__2, &a[i__ - 1 + i__ * a_dim1], &a[i__ * a_dim1 + + 1], &c__1, &tau[i__ - 1]); + e[i__ - 1] = a[i__ - 1 + i__ * a_dim1]; + a[i__ - 1 + i__ * a_dim1] = 1.f; + +/* Compute W(1:i-1,i) */ + + i__2 = i__ - 1; + ssymv_("Upper", &i__2, &c_b15, &a[a_offset], lda, &a[i__ * + a_dim1 + 1], &c__1, &c_b29, &w[iw * w_dim1 + 1], & + c__1); + if (i__ < *n) { + i__2 = i__ - 1; + i__3 = *n - i__; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &w[(iw + 1) * + w_dim1 + 1], ldw, &a[i__ * a_dim1 + 1], &c__1, & + c_b29, &w[i__ + 1 + iw * w_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &a[(i__ + 1) + * a_dim1 + 1], lda, &w[i__ + 1 + iw * w_dim1], & + c__1, &c_b15, &w[iw * w_dim1 + 1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ * a_dim1 + 1], &c__1, & + c_b29, &w[i__ + 1 + iw * w_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &w[(iw + 1) + * w_dim1 + 1], ldw, &w[i__ + 1 + iw * w_dim1], & + c__1, &c_b15, &w[iw * w_dim1 + 1], &c__1); + } + i__2 = i__ - 1; + sscal_(&i__2, &tau[i__ - 1], &w[iw * w_dim1 + 1], &c__1); + i__2 = i__ - 1; + alpha = tau[i__ - 1] * -.5f * sdot_(&i__2, &w[iw * w_dim1 + 1] + , &c__1, &a[i__ * a_dim1 + 1], &c__1); + i__2 = i__ - 1; + saxpy_(&i__2, &alpha, &a[i__ * a_dim1 + 1], &c__1, &w[iw * + w_dim1 + 1], &c__1); + } + +/* L10: */ + } + } else { + +/* Reduce first NB columns of lower triangle */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i:n,i) */ + + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + a_dim1], + lda, &w[i__ + w_dim1], ldw, &c_b15, &a[i__ + i__ * a_dim1] + , &c__1); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &w[i__ + w_dim1], + ldw, &a[i__ + a_dim1], lda, &c_b15, &a[i__ + i__ * a_dim1] + , &c__1); + if (i__ < *n) { + +/* + Generate elementary reflector H(i) to annihilate + A(i+2:n,i) +*/ + + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + slarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + + i__ * a_dim1], &c__1, &tau[i__]); + e[i__] = a[i__ + 1 + i__ * a_dim1]; + a[i__ + 1 + i__ * a_dim1] = 1.f; + +/* Compute W(i+1:n,i) */ + + i__2 = *n - i__; + ssymv_("Lower", &i__2, &c_b15, &a[i__ + 1 + (i__ + 1) * + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b29, &w[i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &w[i__ + 1 + w_dim1] + , ldw, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &w[ + i__ * w_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &a[i__ + 1 + + a_dim1], lda, &w[i__ * w_dim1 + 1], &c__1, &c_b15, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + a_dim1] + , lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &w[ + i__ * w_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &w[i__ + 1 + + w_dim1], ldw, &w[i__ * w_dim1 + 1], &c__1, &c_b15, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + sscal_(&i__2, &tau[i__], &w[i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + alpha = tau[i__] * -.5f * sdot_(&i__2, &w[i__ + 1 + i__ * + w_dim1], &c__1, &a[i__ + 1 + i__ * a_dim1], &c__1); + i__2 = *n - i__; + saxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + } + +/* L20: */ + } + } + + return 0; + +/* End of SLATRD */ + +} /* slatrd_ */ + +/* Subroutine */ int slauu2_(char *uplo, integer *n, real *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__; + static real aii; + extern doublereal sdot_(integer *, real *, integer *, real *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + sgemv_(char *, integer *, integer *, real *, real *, integer *, + real *, integer *, real *, real *, integer *); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAUU2 computes the product U * U' or L' * L, where the triangular + factor U or L is stored in the upper or lower triangular part of + the array A. + + If UPLO = 'U' or 'u' then the upper triangle of the result is stored, + overwriting the factor U in A. + If UPLO = 'L' or 'l' then the lower triangle of the result is stored, + overwriting the factor L in A. + + This is the unblocked form of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the triangular factor stored in the array A + is upper or lower triangular: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the triangular factor U or L. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the triangular factor U or L. + On exit, if UPLO = 'U', the upper triangle of A is + overwritten with the upper triangle of the product U * U'; + if UPLO = 'L', the lower triangle of A is overwritten with + the lower triangle of the product L' * L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAUU2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the product U * U'. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + aii = a[i__ + i__ * a_dim1]; + if (i__ < *n) { + i__2 = *n - i__ + 1; + a[i__ + i__ * a_dim1] = sdot_(&i__2, &a[i__ + i__ * a_dim1], + lda, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ - 1; + i__3 = *n - i__; + sgemv_("No transpose", &i__2, &i__3, &c_b15, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ + (i__ + 1) * a_dim1], lda, & + aii, &a[i__ * a_dim1 + 1], &c__1); + } else { + sscal_(&i__, &aii, &a[i__ * a_dim1 + 1], &c__1); + } +/* L10: */ + } + + } else { + +/* Compute the product L' * L. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + aii = a[i__ + i__ * a_dim1]; + if (i__ < *n) { + i__2 = *n - i__ + 1; + a[i__ + i__ * a_dim1] = sdot_(&i__2, &a[i__ + i__ * a_dim1], & + c__1, &a[i__ + i__ * a_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + sgemv_("Transpose", &i__2, &i__3, &c_b15, &a[i__ + 1 + a_dim1] + , lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &aii, &a[ + i__ + a_dim1], lda); + } else { + sscal_(&i__, &aii, &a[i__ + a_dim1], lda); + } +/* L20: */ + } + } + + return 0; + +/* End of SLAUU2 */ + +} /* slauu2_ */ + +/* Subroutine */ int slauum_(char *uplo, integer *n, real *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, ib, nb; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static logical upper; + extern /* Subroutine */ int strmm_(char *, char *, char *, char *, + integer *, integer *, real *, real *, integer *, real *, integer * + ), ssyrk_(char *, char *, integer + *, integer *, real *, real *, integer *, real *, real *, integer * + ), slauu2_(char *, integer *, real *, integer *, + integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SLAUUM computes the product U * U' or L' * L, where the triangular + factor U or L is stored in the upper or lower triangular part of + the array A. + + If UPLO = 'U' or 'u' then the upper triangle of the result is stored, + overwriting the factor U in A. + If UPLO = 'L' or 'l' then the lower triangle of the result is stored, + overwriting the factor L in A. + + This is the blocked form of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the triangular factor stored in the array A + is upper or lower triangular: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the triangular factor U or L. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the triangular factor U or L. + On exit, if UPLO = 'U', the upper triangle of A is + overwritten with the upper triangle of the product U * U'; + if UPLO = 'L', the lower triangle of A is overwritten with + the lower triangle of the product L' * L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SLAUUM", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "SLAUUM", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code */ + + slauu2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code */ + + if (upper) { + +/* Compute the product U * U'. */ + + i__1 = *n; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = nb, i__4 = *n - i__ + 1; + ib = min(i__3,i__4); + i__3 = i__ - 1; + strmm_("Right", "Upper", "Transpose", "Non-unit", &i__3, &ib, + &c_b15, &a[i__ + i__ * a_dim1], lda, &a[i__ * a_dim1 + + 1], lda) + ; + slauu2_("Upper", &ib, &a[i__ + i__ * a_dim1], lda, info); + if (i__ + ib <= *n) { + i__3 = i__ - 1; + i__4 = *n - i__ - ib + 1; + sgemm_("No transpose", "Transpose", &i__3, &ib, &i__4, & + c_b15, &a[(i__ + ib) * a_dim1 + 1], lda, &a[i__ + + (i__ + ib) * a_dim1], lda, &c_b15, &a[i__ * + a_dim1 + 1], lda); + i__3 = *n - i__ - ib + 1; + ssyrk_("Upper", "No transpose", &ib, &i__3, &c_b15, &a[ + i__ + (i__ + ib) * a_dim1], lda, &c_b15, &a[i__ + + i__ * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the product L' * L. */ + + i__2 = *n; + i__1 = nb; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { +/* Computing MIN */ + i__3 = nb, i__4 = *n - i__ + 1; + ib = min(i__3,i__4); + i__3 = i__ - 1; + strmm_("Left", "Lower", "Transpose", "Non-unit", &ib, &i__3, & + c_b15, &a[i__ + i__ * a_dim1], lda, &a[i__ + a_dim1], + lda); + slauu2_("Lower", &ib, &a[i__ + i__ * a_dim1], lda, info); + if (i__ + ib <= *n) { + i__3 = i__ - 1; + i__4 = *n - i__ - ib + 1; + sgemm_("Transpose", "No transpose", &ib, &i__3, &i__4, & + c_b15, &a[i__ + ib + i__ * a_dim1], lda, &a[i__ + + ib + a_dim1], lda, &c_b15, &a[i__ + a_dim1], lda); + i__3 = *n - i__ - ib + 1; + ssyrk_("Lower", "Transpose", &ib, &i__3, &c_b15, &a[i__ + + ib + i__ * a_dim1], lda, &c_b15, &a[i__ + i__ * + a_dim1], lda); + } +/* L20: */ + } + } + } + + return 0; + +/* End of SLAUUM */ + +} /* slauum_ */ + +/* Subroutine */ int sorg2r_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + slarf_(char *, integer *, integer *, real *, integer *, real *, + real *, integer *, real *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORG2R generates an m by n real matrix Q with orthonormal columns, + which is defined as the first n columns of a product of k elementary + reflectors of order m + + Q = H(1) H(2) . . . H(k) + + as returned by SGEQRF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. M >= N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. N >= K >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the i-th column must contain the vector which + defines the elementary reflector H(i), for i = 1,2,...,k, as + returned by SGEQRF in the first k columns of its array + argument A. + On exit, the m-by-n matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGEQRF. + + WORK (workspace) REAL array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0 || *n > *m) { + *info = -2; + } else if (*k < 0 || *k > *n) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORG2R", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + return 0; + } + +/* Initialise columns k+1:n to columns of the unit matrix */ + + i__1 = *n; + for (j = *k + 1; j <= i__1; ++j) { + i__2 = *m; + for (l = 1; l <= i__2; ++l) { + a[l + j * a_dim1] = 0.f; +/* L10: */ + } + a[j + j * a_dim1] = 1.f; +/* L20: */ + } + + for (i__ = *k; i__ >= 1; --i__) { + +/* Apply H(i) to A(i:m,i:n) from the left */ + + if (i__ < *n) { + a[i__ + i__ * a_dim1] = 1.f; + i__1 = *m - i__ + 1; + i__2 = *n - i__; + slarf_("Left", &i__1, &i__2, &a[i__ + i__ * a_dim1], &c__1, &tau[ + i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + } + if (i__ < *m) { + i__1 = *m - i__; + r__1 = -tau[i__]; + sscal_(&i__1, &r__1, &a[i__ + 1 + i__ * a_dim1], &c__1); + } + a[i__ + i__ * a_dim1] = 1.f - tau[i__]; + +/* Set A(1:i-1,i) to zero */ + + i__1 = i__ - 1; + for (l = 1; l <= i__1; ++l) { + a[l + i__ * a_dim1] = 0.f; +/* L30: */ + } +/* L40: */ + } + return 0; + +/* End of SORG2R */ + +} /* sorg2r_ */ + +/* Subroutine */ int sorgbr_(char *vect, integer *m, integer *n, integer *k, + real *a, integer *lda, real *tau, real *work, integer *lwork, integer + *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, nb, mn; + extern logical lsame_(char *, char *); + static integer iinfo; + static logical wantq; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int sorglq_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *, integer *), sorgqr_( + integer *, integer *, integer *, real *, integer *, real *, real * + , integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORGBR generates one of the real orthogonal matrices Q or P**T + determined by SGEBRD when reducing a real matrix A to bidiagonal + form: A = Q * B * P**T. Q and P**T are defined as products of + elementary reflectors H(i) or G(i) respectively. + + If VECT = 'Q', A is assumed to have been an M-by-K matrix, and Q + is of order M: + if m >= k, Q = H(1) H(2) . . . H(k) and SORGBR returns the first n + columns of Q, where m >= n >= k; + if m < k, Q = H(1) H(2) . . . H(m-1) and SORGBR returns Q as an + M-by-M matrix. + + If VECT = 'P', A is assumed to have been a K-by-N matrix, and P**T + is of order N: + if k < n, P**T = G(k) . . . G(2) G(1) and SORGBR returns the first m + rows of P**T, where n >= m >= k; + if k >= n, P**T = G(n-1) . . . G(2) G(1) and SORGBR returns P**T as + an N-by-N matrix. + + Arguments + ========= + + VECT (input) CHARACTER*1 + Specifies whether the matrix Q or the matrix P**T is + required, as defined in the transformation applied by SGEBRD: + = 'Q': generate Q; + = 'P': generate P**T. + + M (input) INTEGER + The number of rows of the matrix Q or P**T to be returned. + M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q or P**T to be returned. + N >= 0. + If VECT = 'Q', M >= N >= min(M,K); + if VECT = 'P', N >= M >= min(N,K). + + K (input) INTEGER + If VECT = 'Q', the number of columns in the original M-by-K + matrix reduced by SGEBRD. + If VECT = 'P', the number of rows in the original K-by-N + matrix reduced by SGEBRD. + K >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the vectors which define the elementary reflectors, + as returned by SGEBRD. + On exit, the M-by-N matrix Q or P**T. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (input) REAL array, dimension + (min(M,K)) if VECT = 'Q' + (min(N,K)) if VECT = 'P' + TAU(i) must contain the scalar factor of the elementary + reflector H(i) or G(i), which determines Q or P**T, as + returned by SGEBRD in its array argument TAUQ or TAUP. + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,min(M,N)). + For optimum performance LWORK >= min(M,N)*NB, where NB + is the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + wantq = lsame_(vect, "Q"); + mn = min(*m,*n); + lquery = *lwork == -1; + if (! wantq && ! lsame_(vect, "P")) { + *info = -1; + } else if (*m < 0) { + *info = -2; + } else if (*n < 0 || wantq && (*n > *m || *n < min(*m,*k)) || ! wantq && ( + *m > *n || *m < min(*n,*k))) { + *info = -3; + } else if (*k < 0) { + *info = -4; + } else if (*lda < max(1,*m)) { + *info = -6; + } else if (*lwork < max(1,mn) && ! lquery) { + *info = -9; + } + + if (*info == 0) { + if (wantq) { + nb = ilaenv_(&c__1, "SORGQR", " ", m, n, k, &c_n1, (ftnlen)6, ( + ftnlen)1); + } else { + nb = ilaenv_(&c__1, "SORGLQ", " ", m, n, k, &c_n1, (ftnlen)6, ( + ftnlen)1); + } + lwkopt = max(1,mn) * nb; + work[1] = (real) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORGBR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + work[1] = 1.f; + return 0; + } + + if (wantq) { + +/* + Form Q, determined by a call to SGEBRD to reduce an m-by-k + matrix +*/ + + if (*m >= *k) { + +/* If m >= k, assume m >= n >= k */ + + sorgqr_(m, n, k, &a[a_offset], lda, &tau[1], &work[1], lwork, & + iinfo); + + } else { + +/* + If m < k, assume m = n + + Shift the vectors which define the elementary reflectors one + column to the right, and set the first row and column of Q + to those of the unit matrix +*/ + + for (j = *m; j >= 2; --j) { + a[j * a_dim1 + 1] = 0.f; + i__1 = *m; + for (i__ = j + 1; i__ <= i__1; ++i__) { + a[i__ + j * a_dim1] = a[i__ + (j - 1) * a_dim1]; +/* L10: */ + } +/* L20: */ + } + a[a_dim1 + 1] = 1.f; + i__1 = *m; + for (i__ = 2; i__ <= i__1; ++i__) { + a[i__ + a_dim1] = 0.f; +/* L30: */ + } + if (*m > 1) { + +/* Form Q(2:m,2:m) */ + + i__1 = *m - 1; + i__2 = *m - 1; + i__3 = *m - 1; + sorgqr_(&i__1, &i__2, &i__3, &a[(a_dim1 << 1) + 2], lda, &tau[ + 1], &work[1], lwork, &iinfo); + } + } + } else { + +/* + Form P', determined by a call to SGEBRD to reduce a k-by-n + matrix +*/ + + if (*k < *n) { + +/* If k < n, assume k <= m <= n */ + + sorglq_(m, n, k, &a[a_offset], lda, &tau[1], &work[1], lwork, & + iinfo); + + } else { + +/* + If k >= n, assume m = n + + Shift the vectors which define the elementary reflectors one + row downward, and set the first row and column of P' to + those of the unit matrix +*/ + + a[a_dim1 + 1] = 1.f; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + a[i__ + a_dim1] = 0.f; +/* L40: */ + } + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + for (i__ = j - 1; i__ >= 2; --i__) { + a[i__ + j * a_dim1] = a[i__ - 1 + j * a_dim1]; +/* L50: */ + } + a[j * a_dim1 + 1] = 0.f; +/* L60: */ + } + if (*n > 1) { + +/* Form P'(2:n,2:n) */ + + i__1 = *n - 1; + i__2 = *n - 1; + i__3 = *n - 1; + sorglq_(&i__1, &i__2, &i__3, &a[(a_dim1 << 1) + 2], lda, &tau[ + 1], &work[1], lwork, &iinfo); + } + } + } + work[1] = (real) lwkopt; + return 0; + +/* End of SORGBR */ + +} /* sorgbr_ */ + +/* Subroutine */ int sorghr_(integer *n, integer *ilo, integer *ihi, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, nb, nh, iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int sorgqr_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *, integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORGHR generates a real orthogonal matrix Q which is defined as the + product of IHI-ILO elementary reflectors of order N, as returned by + SGEHRD: + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Arguments + ========= + + N (input) INTEGER + The order of the matrix Q. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + ILO and IHI must have the same values as in the previous call + of SGEHRD. Q is equal to the unit matrix except in the + submatrix Q(ilo+1:ihi,ilo+1:ihi). + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the vectors which define the elementary reflectors, + as returned by SGEHRD. + On exit, the N-by-N orthogonal matrix Q. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (input) REAL array, dimension (N-1) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGEHRD. + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= IHI-ILO. + For optimum performance LWORK >= (IHI-ILO)*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nh = *ihi - *ilo; + lquery = *lwork == -1; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*lwork < max(1,nh) && ! lquery) { + *info = -8; + } + + if (*info == 0) { + nb = ilaenv_(&c__1, "SORGQR", " ", &nh, &nh, &nh, &c_n1, (ftnlen)6, ( + ftnlen)1); + lwkopt = max(1,nh) * nb; + work[1] = (real) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORGHR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + work[1] = 1.f; + return 0; + } + +/* + Shift the vectors which define the elementary reflectors one + column to the right, and set the first ilo and the last n-ihi + rows and columns to those of the unit matrix +*/ + + i__1 = *ilo + 1; + for (j = *ihi; j >= i__1; --j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.f; +/* L10: */ + } + i__2 = *ihi; + for (i__ = j + 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = a[i__ + (j - 1) * a_dim1]; +/* L20: */ + } + i__2 = *n; + for (i__ = *ihi + 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.f; +/* L30: */ + } +/* L40: */ + } + i__1 = *ilo; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.f; +/* L50: */ + } + a[j + j * a_dim1] = 1.f; +/* L60: */ + } + i__1 = *n; + for (j = *ihi + 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.f; +/* L70: */ + } + a[j + j * a_dim1] = 1.f; +/* L80: */ + } + + if (nh > 0) { + +/* Generate Q(ilo+1:ihi,ilo+1:ihi) */ + + sorgqr_(&nh, &nh, &nh, &a[*ilo + 1 + (*ilo + 1) * a_dim1], lda, &tau[* + ilo], &work[1], lwork, &iinfo); + } + work[1] = (real) lwkopt; + return 0; + +/* End of SORGHR */ + +} /* sorghr_ */ + +/* Subroutine */ int sorgl2_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + slarf_(char *, integer *, integer *, real *, integer *, real *, + real *, integer *, real *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORGL2 generates an m by n real matrix Q with orthonormal rows, + which is defined as the first m rows of a product of k elementary + reflectors of order n + + Q = H(k) . . . H(2) H(1) + + as returned by SGELQF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. N >= M. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. M >= K >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the i-th row must contain the vector which defines + the elementary reflector H(i), for i = 1,2,...,k, as returned + by SGELQF in the first k rows of its array argument A. + On exit, the m-by-n matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGELQF. + + WORK (workspace) REAL array, dimension (M) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < *m) { + *info = -2; + } else if (*k < 0 || *k > *m) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORGL2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m <= 0) { + return 0; + } + + if (*k < *m) { + +/* Initialise rows k+1:m to rows of the unit matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (l = *k + 1; l <= i__2; ++l) { + a[l + j * a_dim1] = 0.f; +/* L10: */ + } + if (j > *k && j <= *m) { + a[j + j * a_dim1] = 1.f; + } +/* L20: */ + } + } + + for (i__ = *k; i__ >= 1; --i__) { + +/* Apply H(i) to A(i:m,i:n) from the right */ + + if (i__ < *n) { + if (i__ < *m) { + a[i__ + i__ * a_dim1] = 1.f; + i__1 = *m - i__; + i__2 = *n - i__ + 1; + slarf_("Right", &i__1, &i__2, &a[i__ + i__ * a_dim1], lda, & + tau[i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + i__1 = *n - i__; + r__1 = -tau[i__]; + sscal_(&i__1, &r__1, &a[i__ + (i__ + 1) * a_dim1], lda); + } + a[i__ + i__ * a_dim1] = 1.f - tau[i__]; + +/* Set A(i,1:i-1) to zero */ + + i__1 = i__ - 1; + for (l = 1; l <= i__1; ++l) { + a[i__ + l * a_dim1] = 0.f; +/* L30: */ + } +/* L40: */ + } + return 0; + +/* End of SORGL2 */ + +} /* sorgl2_ */ + +/* Subroutine */ int sorglq_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int sorgl2_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *), slarfb_(char *, char *, + char *, char *, integer *, integer *, integer *, real *, integer * + , real *, integer *, real *, integer *, real *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slarft_(char *, char *, integer *, integer *, + real *, integer *, real *, real *, integer *); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORGLQ generates an M-by-N real matrix Q with orthonormal rows, + which is defined as the first M rows of a product of K elementary + reflectors of order N + + Q = H(k) . . . H(2) H(1) + + as returned by SGELQF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. N >= M. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. M >= K >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the i-th row must contain the vector which defines + the elementary reflector H(i), for i = 1,2,...,k, as returned + by SGELQF in the first k rows of its array argument A. + On exit, the M-by-N matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGELQF. + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,M). + For optimum performance LWORK >= M*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "SORGLQ", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1); + lwkopt = max(1,*m) * nb; + work[1] = (real) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < *m) { + *info = -2; + } else if (*k < 0 || *k > *m) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*lwork < max(1,*m) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORGLQ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m <= 0) { + work[1] = 1.f; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *m; + if (nb > 1 && nb < *k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "SORGLQ", " ", m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *m; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "SORGLQ", " ", m, n, k, &c_n1, + (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < *k && nx < *k) { + +/* + Use blocked code after the last block. + The first kk rows are handled by the block method. +*/ + + ki = (*k - nx - 1) / nb * nb; +/* Computing MIN */ + i__1 = *k, i__2 = ki + nb; + kk = min(i__1,i__2); + +/* Set A(kk+1:m,1:kk) to zero. */ + + i__1 = kk; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = kk + 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + kk = 0; + } + +/* Use unblocked code for the last or only block. */ + + if (kk < *m) { + i__1 = *m - kk; + i__2 = *n - kk; + i__3 = *k - kk; + sorgl2_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, & + tau[kk + 1], &work[1], &iinfo); + } + + if (kk > 0) { + +/* Use blocked code */ + + i__1 = -nb; + for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) { +/* Computing MIN */ + i__2 = nb, i__3 = *k - i__ + 1; + ib = min(i__2,i__3); + if (i__ + ib <= *m) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__2 = *n - i__ + 1; + slarft_("Forward", "Rowwise", &i__2, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H' to A(i+ib:m,i:n) from the right */ + + i__2 = *m - i__ - ib + 1; + i__3 = *n - i__ + 1; + slarfb_("Right", "Transpose", "Forward", "Rowwise", &i__2, & + i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[1], & + ldwork, &a[i__ + ib + i__ * a_dim1], lda, &work[ib + + 1], &ldwork); + } + +/* Apply H' to columns i:n of current block */ + + i__2 = *n - i__ + 1; + sorgl2_(&ib, &i__2, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], & + work[1], &iinfo); + +/* Set columns 1:i-1 of current block to zero */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = i__ + ib - 1; + for (l = i__; l <= i__3; ++l) { + a[l + j * a_dim1] = 0.f; +/* L30: */ + } +/* L40: */ + } +/* L50: */ + } + } + + work[1] = (real) iws; + return 0; + +/* End of SORGLQ */ + +} /* sorglq_ */ + +/* Subroutine */ int sorgqr_(integer *m, integer *n, integer *k, real *a, + integer *lda, real *tau, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int sorg2r_(integer *, integer *, integer *, real + *, integer *, real *, real *, integer *), slarfb_(char *, char *, + char *, char *, integer *, integer *, integer *, real *, integer * + , real *, integer *, real *, integer *, real *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slarft_(char *, char *, integer *, integer *, + real *, integer *, real *, real *, integer *); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORGQR generates an M-by-N real matrix Q with orthonormal columns, + which is defined as the first N columns of a product of K elementary + reflectors of order M + + Q = H(1) H(2) . . . H(k) + + as returned by SGEQRF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. M >= N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. N >= K >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the i-th column must contain the vector which + defines the elementary reflector H(i), for i = 1,2,...,k, as + returned by SGEQRF in the first k columns of its array + argument A. + On exit, the M-by-N matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGEQRF. + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "SORGQR", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1); + lwkopt = max(1,*n) * nb; + work[1] = (real) lwkopt; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0 || *n > *m) { + *info = -2; + } else if (*k < 0 || *k > *n) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORGQR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + work[1] = 1.f; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *n; + if (nb > 1 && nb < *k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "SORGQR", " ", m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "SORGQR", " ", m, n, k, &c_n1, + (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < *k && nx < *k) { + +/* + Use blocked code after the last block. + The first kk columns are handled by the block method. +*/ + + ki = (*k - nx - 1) / nb * nb; +/* Computing MIN */ + i__1 = *k, i__2 = ki + nb; + kk = min(i__1,i__2); + +/* Set A(1:kk,kk+1:n) to zero. */ + + i__1 = *n; + for (j = kk + 1; j <= i__1; ++j) { + i__2 = kk; + for (i__ = 1; i__ <= i__2; ++i__) { + a[i__ + j * a_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + kk = 0; + } + +/* Use unblocked code for the last or only block. */ + + if (kk < *n) { + i__1 = *m - kk; + i__2 = *n - kk; + i__3 = *k - kk; + sorg2r_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, & + tau[kk + 1], &work[1], &iinfo); + } + + if (kk > 0) { + +/* Use blocked code */ + + i__1 = -nb; + for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) { +/* Computing MIN */ + i__2 = nb, i__3 = *k - i__ + 1; + ib = min(i__2,i__3); + if (i__ + ib <= *n) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__2 = *m - i__ + 1; + slarft_("Forward", "Columnwise", &i__2, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H to A(i:m,i+ib:n) from the left */ + + i__2 = *m - i__ + 1; + i__3 = *n - i__ - ib + 1; + slarfb_("Left", "No transpose", "Forward", "Columnwise", & + i__2, &i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[ + 1], &ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, & + work[ib + 1], &ldwork); + } + +/* Apply H to rows i:m of current block */ + + i__2 = *m - i__ + 1; + sorg2r_(&i__2, &ib, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], & + work[1], &iinfo); + +/* Set rows 1:i-1 of current block to zero */ + + i__2 = i__ + ib - 1; + for (j = i__; j <= i__2; ++j) { + i__3 = i__ - 1; + for (l = 1; l <= i__3; ++l) { + a[l + j * a_dim1] = 0.f; +/* L30: */ + } +/* L40: */ + } +/* L50: */ + } + } + + work[1] = (real) iws; + return 0; + +/* End of SORGQR */ + +} /* sorgqr_ */ + +/* Subroutine */ int sorm2l_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2; + + /* Local variables */ + static integer i__, i1, i2, i3, mi, ni, nq; + static real aii; + static logical left; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), xerbla_( + char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORM2L overwrites the general real m by n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'T', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'T', + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by SGEQLF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'T': apply Q' (Transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) REAL array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + SGEQLF in the last k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGEQLF. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) REAL array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORM2L", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + } else { + mi = *m; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) is applied to C(1:m-k+i,1:n) */ + + mi = *m - *k + i__; + } else { + +/* H(i) is applied to C(1:m,1:n-k+i) */ + + ni = *n - *k + i__; + } + +/* Apply H(i) */ + + aii = a[nq - *k + i__ + i__ * a_dim1]; + a[nq - *k + i__ + i__ * a_dim1] = 1.f; + slarf_(side, &mi, &ni, &a[i__ * a_dim1 + 1], &c__1, &tau[i__], &c__[ + c_offset], ldc, &work[1]); + a[nq - *k + i__ + i__ * a_dim1] = aii; +/* L10: */ + } + return 0; + +/* End of SORM2L */ + +} /* sorm2l_ */ + +/* Subroutine */ int sorm2r_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2; + + /* Local variables */ + static integer i__, i1, i2, i3, ic, jc, mi, ni, nq; + static real aii; + static logical left; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), xerbla_( + char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORM2R overwrites the general real m by n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'T', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'T', + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(1) H(2) . . . H(k) + + as returned by SGEQRF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'T': apply Q' (Transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) REAL array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + SGEQRF in the first k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGEQRF. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) REAL array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORM2R", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && ! notran || ! left && notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H(i) is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H(i) */ + + aii = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.f; + slarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], &c__1, &tau[i__], &c__[ + ic + jc * c_dim1], ldc, &work[1]); + a[i__ + i__ * a_dim1] = aii; +/* L10: */ + } + return 0; + +/* End of SORM2R */ + +} /* sorm2r_ */ + +/* Subroutine */ int sormbr_(char *vect, char *side, char *trans, integer *m, + integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, + integer *ldc, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2]; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical notran, applyq; + static char transt[1]; + extern /* Subroutine */ int sormlq_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *, integer *); + static integer lwkopt; + static logical lquery; + extern /* Subroutine */ int sormqr_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + If VECT = 'Q', SORMBR overwrites the general real M-by-N matrix C + with + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + If VECT = 'P', SORMBR overwrites the general real M-by-N matrix C + with + SIDE = 'L' SIDE = 'R' + TRANS = 'N': P * C C * P + TRANS = 'T': P**T * C C * P**T + + Here Q and P**T are the orthogonal matrices determined by SGEBRD when + reducing a real matrix A to bidiagonal form: A = Q * B * P**T. Q and + P**T are defined as products of elementary reflectors H(i) and G(i) + respectively. + + Let nq = m if SIDE = 'L' and nq = n if SIDE = 'R'. Thus nq is the + order of the orthogonal matrix Q or P**T that is applied. + + If VECT = 'Q', A is assumed to have been an NQ-by-K matrix: + if nq >= k, Q = H(1) H(2) . . . H(k); + if nq < k, Q = H(1) H(2) . . . H(nq-1). + + If VECT = 'P', A is assumed to have been a K-by-NQ matrix: + if k < nq, P = G(1) G(2) . . . G(k); + if k >= nq, P = G(1) G(2) . . . G(nq-1). + + Arguments + ========= + + VECT (input) CHARACTER*1 + = 'Q': apply Q or Q**T; + = 'P': apply P or P**T. + + SIDE (input) CHARACTER*1 + = 'L': apply Q, Q**T, P or P**T from the Left; + = 'R': apply Q, Q**T, P or P**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q or P; + = 'T': Transpose, apply Q**T or P**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + If VECT = 'Q', the number of columns in the original + matrix reduced by SGEBRD. + If VECT = 'P', the number of rows in the original + matrix reduced by SGEBRD. + K >= 0. + + A (input) REAL array, dimension + (LDA,min(nq,K)) if VECT = 'Q' + (LDA,nq) if VECT = 'P' + The vectors which define the elementary reflectors H(i) and + G(i), whose products determine the matrices Q and P, as + returned by SGEBRD. + + LDA (input) INTEGER + The leading dimension of the array A. + If VECT = 'Q', LDA >= max(1,nq); + if VECT = 'P', LDA >= max(1,min(nq,K)). + + TAU (input) REAL array, dimension (min(nq,K)) + TAU(i) must contain the scalar factor of the elementary + reflector H(i) or G(i) which determines Q or P, as returned + by SGEBRD in the array argument TAUQ or TAUP. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q + or P*C or P**T*C or C*P or C*P**T. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + applyq = lsame_(vect, "Q"); + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q or P and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! applyq && ! lsame_(vect, "P")) { + *info = -1; + } else if (! left && ! lsame_(side, "R")) { + *info = -2; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -3; + } else if (*m < 0) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*k < 0) { + *info = -6; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = 1, i__2 = min(nq,*k); + if (applyq && *lda < max(1,nq) || ! applyq && *lda < max(i__1,i__2)) { + *info = -8; + } else if (*ldc < max(1,*m)) { + *info = -11; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -13; + } + } + + if (*info == 0) { + if (applyq) { + if (left) { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *m - 1; + i__2 = *m - 1; + nb = ilaenv_(&c__1, "SORMQR", ch__1, &i__1, n, &i__2, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *n - 1; + i__2 = *n - 1; + nb = ilaenv_(&c__1, "SORMQR", ch__1, m, &i__1, &i__2, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } else { + if (left) { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *m - 1; + i__2 = *m - 1; + nb = ilaenv_(&c__1, "SORMLQ", ch__1, &i__1, n, &i__2, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *n - 1; + i__2 = *n - 1; + nb = ilaenv_(&c__1, "SORMLQ", ch__1, m, &i__1, &i__2, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } + lwkopt = max(1,nw) * nb; + work[1] = (real) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORMBR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + work[1] = 1.f; + if (*m == 0 || *n == 0) { + return 0; + } + + if (applyq) { + +/* Apply Q */ + + if (nq >= *k) { + +/* Q was determined by a call to SGEBRD with nq >= k */ + + sormqr_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], lwork, &iinfo); + } else if (nq > 1) { + +/* Q was determined by a call to SGEBRD with nq < k */ + + if (left) { + mi = *m - 1; + ni = *n; + i1 = 2; + i2 = 1; + } else { + mi = *m; + ni = *n - 1; + i1 = 1; + i2 = 2; + } + i__1 = nq - 1; + sormqr_(side, trans, &mi, &ni, &i__1, &a[a_dim1 + 2], lda, &tau[1] + , &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + } + } else { + +/* Apply P */ + + if (notran) { + *(unsigned char *)transt = 'T'; + } else { + *(unsigned char *)transt = 'N'; + } + if (nq > *k) { + +/* P was determined by a call to SGEBRD with nq > k */ + + sormlq_(side, transt, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], lwork, &iinfo); + } else if (nq > 1) { + +/* P was determined by a call to SGEBRD with nq <= k */ + + if (left) { + mi = *m - 1; + ni = *n; + i1 = 2; + i2 = 1; + } else { + mi = *m; + ni = *n - 1; + i1 = 1; + i2 = 2; + } + i__1 = nq - 1; + sormlq_(side, transt, &mi, &ni, &i__1, &a[(a_dim1 << 1) + 1], lda, + &tau[1], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, & + iinfo); + } + } + work[1] = (real) lwkopt; + return 0; + +/* End of SORMBR */ + +} /* sormbr_ */ + +/* Subroutine */ int sormhr_(char *side, char *trans, integer *m, integer *n, + integer *ilo, integer *ihi, real *a, integer *lda, real *tau, real * + c__, integer *ldc, real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, nh, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer lwkopt; + static logical lquery; + extern /* Subroutine */ int sormqr_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORMHR overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix of order nq, with nq = m if + SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of + IHI-ILO elementary reflectors, as returned by SGEHRD: + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + ILO and IHI must have the same values as in the previous call + of SGEHRD. Q is equal to the unit matrix except in the + submatrix Q(ilo+1:ihi,ilo+1:ihi). + If SIDE = 'L', then 1 <= ILO <= IHI <= M, if M > 0, and + ILO = 1 and IHI = 0, if M = 0; + if SIDE = 'R', then 1 <= ILO <= IHI <= N, if N > 0, and + ILO = 1 and IHI = 0, if N = 0. + + A (input) REAL array, dimension + (LDA,M) if SIDE = 'L' + (LDA,N) if SIDE = 'R' + The vectors which define the elementary reflectors, as + returned by SGEHRD. + + LDA (input) INTEGER + The leading dimension of the array A. + LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. + + TAU (input) REAL array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGEHRD. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + nh = *ihi - *ilo; + left = lsame_(side, "L"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*ilo < 1 || *ilo > max(1,nq)) { + *info = -5; + } else if (*ihi < min(*ilo,nq) || *ihi > nq) { + *info = -6; + } else if (*lda < max(1,nq)) { + *info = -8; + } else if (*ldc < max(1,*m)) { + *info = -11; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -13; + } + + if (*info == 0) { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "SORMQR", ch__1, &nh, n, &nh, &c_n1, (ftnlen) + 6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "SORMQR", ch__1, m, &nh, &nh, &c_n1, (ftnlen) + 6, (ftnlen)2); + } + lwkopt = max(1,nw) * nb; + work[1] = (real) lwkopt; + } + + if (*info != 0) { + i__2 = -(*info); + xerbla_("SORMHR", &i__2); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || nh == 0) { + work[1] = 1.f; + return 0; + } + + if (left) { + mi = nh; + ni = *n; + i1 = *ilo + 1; + i2 = 1; + } else { + mi = *m; + ni = nh; + i1 = 1; + i2 = *ilo + 1; + } + + sormqr_(side, trans, &mi, &ni, &nh, &a[*ilo + 1 + *ilo * a_dim1], lda, & + tau[*ilo], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + + work[1] = (real) lwkopt; + return 0; + +/* End of SORMHR */ + +} /* sormhr_ */ + +/* Subroutine */ int sorml2_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2; + + /* Local variables */ + static integer i__, i1, i2, i3, ic, jc, mi, ni, nq; + static real aii; + static logical left; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int slarf_(char *, integer *, integer *, real *, + integer *, real *, real *, integer *, real *), xerbla_( + char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORML2 overwrites the general real m by n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'T', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'T', + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by SGELQF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'T': apply Q' (Transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) REAL array, dimension + (LDA,M) if SIDE = 'L', + (LDA,N) if SIDE = 'R' + The i-th row must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + SGELQF in the first k rows of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,K). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGELQF. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the m by n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) REAL array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,*k)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORML2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H(i) is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H(i) */ + + aii = a[i__ + i__ * a_dim1]; + a[i__ + i__ * a_dim1] = 1.f; + slarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], lda, &tau[i__], &c__[ + ic + jc * c_dim1], ldc, &work[1]); + a[i__ + i__ * a_dim1] = aii; +/* L10: */ + } + return 0; + +/* End of SORML2 */ + +} /* sorml2_ */ + +/* Subroutine */ int sormlq_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static real t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int sorml2_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *), slarfb_(char *, char *, char *, char * + , integer *, integer *, integer *, real *, integer *, real *, + integer *, real *, integer *, real *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slarft_(char *, char *, integer *, integer *, + real *, integer *, real *, real *, integer *); + static logical notran; + static integer ldwork; + static char transt[1]; + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORMLQ overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by SGELQF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) REAL array, dimension + (LDA,M) if SIDE = 'L', + (LDA,N) if SIDE = 'R' + The i-th row must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + SGELQF in the first k rows of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,K). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGELQF. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,*k)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + +/* + Determine the block size. NB may be at most NBMAX, where NBMAX + is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "SORMLQ", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = max(1,nw) * nb; + work[1] = (real) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORMLQ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + work[1] = 1.f; + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "SORMLQ", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + sorml2_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + if (notran) { + *(unsigned char *)transt = 'T'; + } else { + *(unsigned char *)transt = 'N'; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__4 = nq - i__ + 1; + slarft_("Forward", "Rowwise", &i__4, &ib, &a[i__ + i__ * a_dim1], + lda, &tau[i__], t, &c__65); + if (left) { + +/* H or H' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H or H' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H or H' */ + + slarfb_(side, transt, "Forward", "Rowwise", &mi, &ni, &ib, &a[i__ + + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * c_dim1], + ldc, &work[1], &ldwork); +/* L10: */ + } + } + work[1] = (real) lwkopt; + return 0; + +/* End of SORMLQ */ + +} /* sormlq_ */ + +/* Subroutine */ int sormql_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static real t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int sorm2l_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *), slarfb_(char *, char *, char *, char * + , integer *, integer *, integer *, real *, integer *, real *, + integer *, real *, integer *, real *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slarft_(char *, char *, integer *, integer *, + real *, integer *, real *, real *, integer *); + static logical notran; + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORMQL overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by SGEQLF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) REAL array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + SGEQLF in the last k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGEQLF. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = max(1,*n); + } else { + nq = *n; + nw = max(1,*m); + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + + if (*info == 0) { + if (*m == 0 || *n == 0) { + lwkopt = 1; + } else { + +/* + Determine the block size. NB may be at most NBMAX, where + NBMAX is used to define the local array T. + + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "SORMQL", ch__1, m, n, k, &c_n1, + (ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = nw * nb; + } + work[1] = (real) lwkopt; + + if (*lwork < nw && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORMQL", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "SORMQL", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + sorm2l_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + } else { + mi = *m; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i+ib-1) . . . H(i+1) H(i) +*/ + + i__4 = nq - *k + i__ + ib - 1; + slarft_("Backward", "Columnwise", &i__4, &ib, &a[i__ * a_dim1 + 1] + , lda, &tau[i__], t, &c__65); + if (left) { + +/* H or H' is applied to C(1:m-k+i+ib-1,1:n) */ + + mi = *m - *k + i__ + ib - 1; + } else { + +/* H or H' is applied to C(1:m,1:n-k+i+ib-1) */ + + ni = *n - *k + i__ + ib - 1; + } + +/* Apply H or H' */ + + slarfb_(side, trans, "Backward", "Columnwise", &mi, &ni, &ib, &a[ + i__ * a_dim1 + 1], lda, t, &c__65, &c__[c_offset], ldc, & + work[1], &ldwork); +/* L10: */ + } + } + work[1] = (real) lwkopt; + return 0; + +/* End of SORMQL */ + +} /* sormql_ */ + +/* Subroutine */ int sormqr_(char *side, char *trans, integer *m, integer *n, + integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static real t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int sorm2r_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *), slarfb_(char *, char *, char *, char * + , integer *, integer *, integer *, real *, integer *, real *, + integer *, real *, integer *, real *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slarft_(char *, char *, integer *, integer *, + real *, integer *, real *, real *, integer *); + static logical notran; + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORMQR overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix defined as the product of k + elementary reflectors + + Q = H(1) H(2) . . . H(k) + + as returned by SGEQRF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) REAL array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + SGEQRF in the first k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) REAL array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SGEQRF. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + +/* + Determine the block size. NB may be at most NBMAX, where NBMAX + is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "SORMQR", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = max(1,nw) * nb; + work[1] = (real) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SORMQR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + work[1] = 1.f; + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "SORMQR", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + sorm2r_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && ! notran || ! left && notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__4 = nq - i__ + 1; + slarft_("Forward", "Columnwise", &i__4, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], t, &c__65) + ; + if (left) { + +/* H or H' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H or H' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H or H' */ + + slarfb_(side, trans, "Forward", "Columnwise", &mi, &ni, &ib, &a[ + i__ + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * + c_dim1], ldc, &work[1], &ldwork); +/* L10: */ + } + } + work[1] = (real) lwkopt; + return 0; + +/* End of SORMQR */ + +} /* sormqr_ */ + +/* Subroutine */ int sormtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, real *a, integer *lda, real *tau, real *c__, integer *ldc, + real *work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2, i__3; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int sormql_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *, integer *); + static integer lwkopt; + static logical lquery; + extern /* Subroutine */ int sormqr_(char *, char *, integer *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SORMTR overwrites the general real M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'T': Q**T * C C * Q**T + + where Q is a real orthogonal matrix of order nq, with nq = m if + SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of + nq-1 elementary reflectors, as returned by SSYTRD: + + if UPLO = 'U', Q = H(nq-1) . . . H(2) H(1); + + if UPLO = 'L', Q = H(1) H(2) . . . H(nq-1). + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**T from the Left; + = 'R': apply Q or Q**T from the Right. + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A contains elementary reflectors + from SSYTRD; + = 'L': Lower triangle of A contains elementary reflectors + from SSYTRD. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'T': Transpose, apply Q**T. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + A (input) REAL array, dimension + (LDA,M) if SIDE = 'L' + (LDA,N) if SIDE = 'R' + The vectors which define the elementary reflectors, as + returned by SSYTRD. + + LDA (input) INTEGER + The leading dimension of the array A. + LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. + + TAU (input) REAL array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by SSYTRD. + + C (input/output) REAL array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + upper = lsame_(uplo, "U"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! upper && ! lsame_(uplo, "L")) { + *info = -2; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T")) { + *info = -3; + } else if (*m < 0) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + if (upper) { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *m - 1; + i__3 = *m - 1; + nb = ilaenv_(&c__1, "SORMQL", ch__1, &i__2, n, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *n - 1; + i__3 = *n - 1; + nb = ilaenv_(&c__1, "SORMQL", ch__1, m, &i__2, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } else { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *m - 1; + i__3 = *m - 1; + nb = ilaenv_(&c__1, "SORMQR", ch__1, &i__2, n, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *n - 1; + i__3 = *n - 1; + nb = ilaenv_(&c__1, "SORMQR", ch__1, m, &i__2, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } + lwkopt = max(1,nw) * nb; + work[1] = (real) lwkopt; + } + + if (*info != 0) { + i__2 = -(*info); + xerbla_("SORMTR", &i__2); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || nq == 1) { + work[1] = 1.f; + return 0; + } + + if (left) { + mi = *m - 1; + ni = *n; + } else { + mi = *m; + ni = *n - 1; + } + + if (upper) { + +/* Q was determined by a call to SSYTRD with UPLO = 'U' */ + + i__2 = nq - 1; + sormql_(side, trans, &mi, &ni, &i__2, &a[(a_dim1 << 1) + 1], lda, & + tau[1], &c__[c_offset], ldc, &work[1], lwork, &iinfo); + } else { + +/* Q was determined by a call to SSYTRD with UPLO = 'L' */ + + if (left) { + i1 = 2; + i2 = 1; + } else { + i1 = 1; + i2 = 2; + } + i__2 = nq - 1; + sormqr_(side, trans, &mi, &ni, &i__2, &a[a_dim1 + 2], lda, &tau[1], & + c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + } + work[1] = (real) lwkopt; + return 0; + +/* End of SORMTR */ + +} /* sormtr_ */ + +/* Subroutine */ int spotf2_(char *uplo, integer *n, real *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + real r__1; + + /* Local variables */ + static integer j; + static real ajj; + extern doublereal sdot_(integer *, real *, integer *, real *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + sgemv_(char *, integer *, integer *, real *, real *, integer *, + real *, integer *, real *, real *, integer *); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern logical sisnan_(real *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SPOTF2 computes the Cholesky factorization of a real symmetric + positive definite matrix A. + + The factorization has the form + A = U' * U , if UPLO = 'U', or + A = L * L', if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the unblocked version of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is stored. + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + n by n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U'*U or A = L*L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, the leading minor of order k is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SPOTF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute U(J,J) and test for non-positive-definiteness. */ + + i__2 = j - 1; + ajj = a[j + j * a_dim1] - sdot_(&i__2, &a[j * a_dim1 + 1], &c__1, + &a[j * a_dim1 + 1], &c__1); + if (ajj <= 0.f || sisnan_(&ajj)) { + a[j + j * a_dim1] = ajj; + goto L30; + } + ajj = sqrt(ajj); + a[j + j * a_dim1] = ajj; + +/* Compute elements J+1:N of row J. */ + + if (j < *n) { + i__2 = j - 1; + i__3 = *n - j; + sgemv_("Transpose", &i__2, &i__3, &c_b151, &a[(j + 1) * + a_dim1 + 1], lda, &a[j * a_dim1 + 1], &c__1, &c_b15, & + a[j + (j + 1) * a_dim1], lda); + i__2 = *n - j; + r__1 = 1.f / ajj; + sscal_(&i__2, &r__1, &a[j + (j + 1) * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute L(J,J) and test for non-positive-definiteness. */ + + i__2 = j - 1; + ajj = a[j + j * a_dim1] - sdot_(&i__2, &a[j + a_dim1], lda, &a[j + + a_dim1], lda); + if (ajj <= 0.f || sisnan_(&ajj)) { + a[j + j * a_dim1] = ajj; + goto L30; + } + ajj = sqrt(ajj); + a[j + j * a_dim1] = ajj; + +/* Compute elements J+1:N of column J. */ + + if (j < *n) { + i__2 = *n - j; + i__3 = j - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b151, &a[j + 1 + + a_dim1], lda, &a[j + a_dim1], lda, &c_b15, &a[j + 1 + + j * a_dim1], &c__1); + i__2 = *n - j; + r__1 = 1.f / ajj; + sscal_(&i__2, &r__1, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + goto L40; + +L30: + *info = j; + +L40: + return 0; + +/* End of SPOTF2 */ + +} /* spotf2_ */ + +/* Subroutine */ int spotrf_(char *uplo, integer *n, real *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer j, jb, nb; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static logical upper; + extern /* Subroutine */ int strsm_(char *, char *, char *, char *, + integer *, integer *, real *, real *, integer *, real *, integer * + ), ssyrk_(char *, char *, integer + *, integer *, real *, real *, integer *, real *, real *, integer * + ), spotf2_(char *, integer *, real *, integer *, + integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SPOTRF computes the Cholesky factorization of a real symmetric + positive definite matrix A. + + The factorization has the form + A = U**T * U, if UPLO = 'U', or + A = L * L**T, if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the block version of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U**T*U or A = L*L**T. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the leading minor of order i is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SPOTRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "SPOTRF", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code. */ + + spotf2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code. */ + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + ssyrk_("Upper", "Transpose", &jb, &i__3, &c_b151, &a[j * + a_dim1 + 1], lda, &c_b15, &a[j + j * a_dim1], lda); + spotf2_("Upper", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block row. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + sgemm_("Transpose", "No transpose", &jb, &i__3, &i__4, & + c_b151, &a[j * a_dim1 + 1], lda, &a[(j + jb) * + a_dim1 + 1], lda, &c_b15, &a[j + (j + jb) * + a_dim1], lda); + i__3 = *n - j - jb + 1; + strsm_("Left", "Upper", "Transpose", "Non-unit", &jb, & + i__3, &c_b15, &a[j + j * a_dim1], lda, &a[j + (j + + jb) * a_dim1], lda); + } +/* L10: */ + } + + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__2 = *n; + i__1 = nb; + for (j = 1; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + ssyrk_("Lower", "No transpose", &jb, &i__3, &c_b151, &a[j + + a_dim1], lda, &c_b15, &a[j + j * a_dim1], lda); + spotf2_("Lower", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block column. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + sgemm_("No transpose", "Transpose", &i__3, &jb, &i__4, & + c_b151, &a[j + jb + a_dim1], lda, &a[j + a_dim1], + lda, &c_b15, &a[j + jb + j * a_dim1], lda); + i__3 = *n - j - jb + 1; + strsm_("Right", "Lower", "Transpose", "Non-unit", &i__3, & + jb, &c_b15, &a[j + j * a_dim1], lda, &a[j + jb + + j * a_dim1], lda); + } +/* L20: */ + } + } + } + goto L40; + +L30: + *info = *info + j - 1; + +L40: + return 0; + +/* End of SPOTRF */ + +} /* spotrf_ */ + +/* Subroutine */ int spotri_(char *uplo, integer *n, real *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *), slauum_( + char *, integer *, real *, integer *, integer *), strtri_( + char *, char *, integer *, real *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SPOTRI computes the inverse of a real symmetric positive definite + matrix A using the Cholesky factorization A = U**T*U or A = L*L**T + computed by SPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the triangular factor U or L from the Cholesky + factorization A = U**T*U or A = L*L**T, as computed by + SPOTRF. + On exit, the upper or lower triangle of the (symmetric) + inverse of A, overwriting the input factor U or L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the (i,i) element of the factor U or L is + zero, and the inverse could not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SPOTRI", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Invert the triangular Cholesky factor U or L. */ + + strtri_(uplo, "Non-unit", n, &a[a_offset], lda, info); + if (*info > 0) { + return 0; + } + +/* Form inv(U)*inv(U)' or inv(L)'*inv(L). */ + + slauum_(uplo, n, &a[a_offset], lda, info); + + return 0; + +/* End of SPOTRI */ + +} /* spotri_ */ + +/* Subroutine */ int spotrs_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + static logical upper; + extern /* Subroutine */ int strsm_(char *, char *, char *, char *, + integer *, integer *, real *, real *, integer *, real *, integer * + ), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SPOTRS solves a system of linear equations A*X = B with a symmetric + positive definite matrix A using the Cholesky factorization + A = U**T*U or A = L*L**T computed by SPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) REAL array, dimension (LDA,N) + The triangular factor U or L from the Cholesky factorization + A = U**T*U or A = L*L**T, as computed by SPOTRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + B (input/output) REAL array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SPOTRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (upper) { + +/* + Solve A*X = B where A = U'*U. + + Solve U'*X = B, overwriting B with X. +*/ + + strsm_("Left", "Upper", "Transpose", "Non-unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + strsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b15, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A*X = B where A = L*L'. + + Solve L*X = B, overwriting B with X. +*/ + + strsm_("Left", "Lower", "No transpose", "Non-unit", n, nrhs, &c_b15, & + a[a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + strsm_("Left", "Lower", "Transpose", "Non-unit", n, nrhs, &c_b15, &a[ + a_offset], lda, &b[b_offset], ldb); + } + + return 0; + +/* End of SPOTRS */ + +} /* spotrs_ */ + +/* Subroutine */ int sstedc_(char *compz, integer *n, real *d__, real *e, + real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, + integer *liwork, integer *info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2; + real r__1, r__2; + + /* Local variables */ + static integer i__, j, k, m; + static real p; + static integer ii, lgn; + static real eps, tiny; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static integer lwmin, start; + extern /* Subroutine */ int sswap_(integer *, real *, integer *, real *, + integer *), slaed0_(integer *, integer *, integer *, real *, real + *, real *, integer *, real *, integer *, real *, integer *, + integer *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer finish; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *), slacpy_(char *, integer *, integer *, real *, integer *, + real *, integer *), slaset_(char *, integer *, integer *, + real *, real *, real *, integer *); + static integer liwmin, icompz; + static real orgnrm; + extern doublereal slanst_(char *, integer *, real *, real *); + extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *), + slasrt_(char *, integer *, real *, integer *); + static logical lquery; + static integer smlsiz; + extern /* Subroutine */ int ssteqr_(char *, integer *, real *, real *, + real *, integer *, real *, integer *); + static integer storez, strtrw; + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SSTEDC computes all eigenvalues and, optionally, eigenvectors of a + symmetric tridiagonal matrix using the divide and conquer method. + The eigenvectors of a full or band real symmetric matrix can also be + found if SSYTRD or SSPTRD or SSBTRD has been used to reduce this + matrix to tridiagonal form. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. See SLAED3 for details. + + Arguments + ========= + + COMPZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only. + = 'I': Compute eigenvectors of tridiagonal matrix also. + = 'V': Compute eigenvectors of original dense symmetric + matrix also. On entry, Z contains the orthogonal + matrix used to reduce the original matrix to + tridiagonal form. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) REAL array, dimension (N-1) + On entry, the subdiagonal elements of the tridiagonal matrix. + On exit, E has been destroyed. + + Z (input/output) REAL array, dimension (LDZ,N) + On entry, if COMPZ = 'V', then Z contains the orthogonal + matrix used in the reduction to tridiagonal form. + On exit, if INFO = 0, then if COMPZ = 'V', Z contains the + orthonormal eigenvectors of the original symmetric matrix, + and if COMPZ = 'I', Z contains the orthonormal eigenvectors + of the symmetric tridiagonal matrix. + If COMPZ = 'N', then Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= 1. + If eigenvectors are desired, then LDZ >= max(1,N). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If COMPZ = 'N' or N <= 1 then LWORK must be at least 1. + If COMPZ = 'V' and N > 1 then LWORK must be at least + ( 1 + 3*N + 2*N*lg N + 3*N**2 ), + where lg( N ) = smallest integer k such + that 2**k >= N. + If COMPZ = 'I' and N > 1 then LWORK must be at least + ( 1 + 4*N + N**2 ). + Note that for COMPZ = 'I' or 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LWORK need + only be max(1,2*(N-1)). + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) + On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. + + LIWORK (input) INTEGER + The dimension of the array IWORK. + If COMPZ = 'N' or N <= 1 then LIWORK must be at least 1. + If COMPZ = 'V' and N > 1 then LIWORK must be at least + ( 6 + 6*N + 5*N*lg N ). + If COMPZ = 'I' and N > 1 then LIWORK must be at least + ( 3 + 5*N ). + Note that for COMPZ = 'I' or 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LIWORK + need only be 1. + + If LIWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal size of the IWORK array, + returns this value as the first entry of the IWORK array, and + no error message related to LIWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute an eigenvalue while + working on the submatrix lying in rows and columns + INFO/(N+1) through mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + --iwork; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1 || *liwork == -1; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + + if (*info == 0) { + +/* Compute the workspace requirements */ + + smlsiz = ilaenv_(&c__9, "SSTEDC", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + if (*n <= 1 || icompz == 0) { + liwmin = 1; + lwmin = 1; + } else if (*n <= smlsiz) { + liwmin = 1; + lwmin = *n - 1 << 1; + } else { + lgn = (integer) (log((real) (*n)) / log(2.f)); + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (icompz == 1) { +/* Computing 2nd power */ + i__1 = *n; + lwmin = *n * 3 + 1 + (*n << 1) * lgn + i__1 * i__1 * 3; + liwmin = *n * 6 + 6 + *n * 5 * lgn; + } else if (icompz == 2) { +/* Computing 2nd power */ + i__1 = *n; + lwmin = (*n << 2) + 1 + i__1 * i__1; + liwmin = *n * 5 + 3; + } + } + work[1] = (real) lwmin; + iwork[1] = liwmin; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*liwork < liwmin && ! lquery) { + *info = -10; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SSTEDC", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*n == 1) { + if (icompz != 0) { + z__[z_dim1 + 1] = 1.f; + } + return 0; + } + +/* + If the following conditional clause is removed, then the routine + will use the Divide and Conquer routine to compute only the + eigenvalues, which requires (3N + 3N**2) real workspace and + (2 + 5N + 2N lg(N)) integer workspace. + Since on many architectures SSTERF is much faster than any other + algorithm for finding eigenvalues only, it is used here + as the default. If the conditional clause is removed, then + information on the size of workspace needs to be changed. + + If COMPZ = 'N', use SSTERF to compute the eigenvalues. +*/ + + if (icompz == 0) { + ssterf_(n, &d__[1], &e[1], info); + goto L50; + } + +/* + If N is smaller than the minimum divide size (SMLSIZ+1), then + solve the problem with another solver. +*/ + + if (*n <= smlsiz) { + + ssteqr_(compz, n, &d__[1], &e[1], &z__[z_offset], ldz, &work[1], info); + + } else { + +/* + If COMPZ = 'V', the Z matrix must be stored elsewhere for later + use. +*/ + + if (icompz == 1) { + storez = *n * *n + 1; + } else { + storez = 1; + } + + if (icompz == 2) { + slaset_("Full", n, n, &c_b29, &c_b15, &z__[z_offset], ldz); + } + +/* Scale. */ + + orgnrm = slanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.f) { + goto L50; + } + + eps = slamch_("Epsilon"); + + start = 1; + +/* while ( START <= N ) */ + +L10: + if (start <= *n) { + +/* + Let FINISH be the position of the next subdiagonal entry + such that E( FINISH ) <= TINY or FINISH = N if no such + subdiagonal exists. The matrix identified by the elements + between START and FINISH constitutes an independent + sub-problem. +*/ + + finish = start; +L20: + if (finish < *n) { + tiny = eps * sqrt((r__1 = d__[finish], dabs(r__1))) * sqrt(( + r__2 = d__[finish + 1], dabs(r__2))); + if ((r__1 = e[finish], dabs(r__1)) > tiny) { + ++finish; + goto L20; + } + } + +/* (Sub) Problem determined. Compute its size and solve it. */ + + m = finish - start + 1; + if (m == 1) { + start = finish + 1; + goto L10; + } + if (m > smlsiz) { + +/* Scale. */ + + orgnrm = slanst_("M", &m, &d__[start], &e[start]); + slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &m, &c__1, &d__[ + start], &m, info); + i__1 = m - 1; + i__2 = m - 1; + slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &i__1, &c__1, &e[ + start], &i__2, info); + + if (icompz == 1) { + strtrw = 1; + } else { + strtrw = start; + } + slaed0_(&icompz, n, &m, &d__[start], &e[start], &z__[strtrw + + start * z_dim1], ldz, &work[1], n, &work[storez], & + iwork[1], info); + if (*info != 0) { + *info = (*info / (m + 1) + start - 1) * (*n + 1) + *info % + (m + 1) + start - 1; + goto L50; + } + +/* Scale back. */ + + slascl_("G", &c__0, &c__0, &c_b15, &orgnrm, &m, &c__1, &d__[ + start], &m, info); + + } else { + if (icompz == 1) { + +/* + Since QR won't update a Z matrix which is larger than + the length of D, we must solve the sub-problem in a + workspace and then multiply back into Z. +*/ + + ssteqr_("I", &m, &d__[start], &e[start], &work[1], &m, & + work[m * m + 1], info); + slacpy_("A", n, &m, &z__[start * z_dim1 + 1], ldz, &work[ + storez], n); + sgemm_("N", "N", n, &m, &m, &c_b15, &work[storez], n, & + work[1], &m, &c_b29, &z__[start * z_dim1 + 1], + ldz); + } else if (icompz == 2) { + ssteqr_("I", &m, &d__[start], &e[start], &z__[start + + start * z_dim1], ldz, &work[1], info); + } else { + ssterf_(&m, &d__[start], &e[start], info); + } + if (*info != 0) { + *info = start * (*n + 1) + finish; + goto L50; + } + } + + start = finish + 1; + goto L10; + } + +/* + endwhile + + If the problem split any number of times, then the eigenvalues + will not be properly ordered. Here we permute the eigenvalues + (and the associated eigenvectors) into ascending order. +*/ + + if (m != *n) { + if (icompz == 0) { + +/* Use Quick Sort */ + + slasrt_("I", n, &d__[1], info); + + } else { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L30: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + sswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * + z_dim1 + 1], &c__1); + } +/* L40: */ + } + } + } + } + +L50: + work[1] = (real) lwmin; + iwork[1] = liwmin; + + return 0; + +/* End of SSTEDC */ + +} /* sstedc_ */ + +/* Subroutine */ int ssteqr_(char *compz, integer *n, real *d__, real *e, + real *z__, integer *ldz, real *work, integer *info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2; + real r__1, r__2; + + /* Local variables */ + static real b, c__, f, g; + static integer i__, j, k, l, m; + static real p, r__, s; + static integer l1, ii, mm, lm1, mm1, nm1; + static real rt1, rt2, eps; + static integer lsv; + static real tst, eps2; + static integer lend, jtot; + extern /* Subroutine */ int slae2_(real *, real *, real *, real *, real *) + ; + extern logical lsame_(char *, char *); + static real anorm; + extern /* Subroutine */ int slasr_(char *, char *, char *, integer *, + integer *, real *, real *, real *, integer *), sswap_(integer *, real *, integer *, real *, integer *); + static integer lendm1, lendp1; + extern /* Subroutine */ int slaev2_(real *, real *, real *, real *, real * + , real *, real *); + extern doublereal slapy2_(real *, real *); + static integer iscale; + extern doublereal slamch_(char *); + static real safmin; + extern /* Subroutine */ int xerbla_(char *, integer *); + static real safmax; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *); + static integer lendsv; + extern /* Subroutine */ int slartg_(real *, real *, real *, real *, real * + ), slaset_(char *, integer *, integer *, real *, real *, real *, + integer *); + static real ssfmin; + static integer nmaxit, icompz; + static real ssfmax; + extern doublereal slanst_(char *, integer *, real *, real *); + extern /* Subroutine */ int slasrt_(char *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SSTEQR computes all eigenvalues and, optionally, eigenvectors of a + symmetric tridiagonal matrix using the implicit QL or QR method. + The eigenvectors of a full or band symmetric matrix can also be found + if SSYTRD or SSPTRD or SSBTRD has been used to reduce this matrix to + tridiagonal form. + + Arguments + ========= + + COMPZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only. + = 'V': Compute eigenvalues and eigenvectors of the original + symmetric matrix. On entry, Z must contain the + orthogonal matrix used to reduce the original matrix + to tridiagonal form. + = 'I': Compute eigenvalues and eigenvectors of the + tridiagonal matrix. Z is initialized to the identity + matrix. + + N (input) INTEGER + The order of the matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) REAL array, dimension (N-1) + On entry, the (n-1) subdiagonal elements of the tridiagonal + matrix. + On exit, E has been destroyed. + + Z (input/output) REAL array, dimension (LDZ, N) + On entry, if COMPZ = 'V', then Z contains the orthogonal + matrix used in the reduction to tridiagonal form. + On exit, if INFO = 0, then if COMPZ = 'V', Z contains the + orthonormal eigenvectors of the original symmetric matrix, + and if COMPZ = 'I', Z contains the orthonormal eigenvectors + of the symmetric tridiagonal matrix. + If COMPZ = 'N', then Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= 1, and if + eigenvectors are desired, then LDZ >= max(1,N). + + WORK (workspace) REAL array, dimension (max(1,2*N-2)) + If COMPZ = 'N', then WORK is not referenced. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: the algorithm has failed to find all the eigenvalues in + a total of 30*N iterations; if INFO = i, then i + elements of E have not converged to zero; on exit, D + and E contain the elements of a symmetric tridiagonal + matrix which is orthogonally similar to the original + matrix. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SSTEQR", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (*n == 1) { + if (icompz == 2) { + z__[z_dim1 + 1] = 1.f; + } + return 0; + } + +/* Determine the unit roundoff and over/underflow thresholds. */ + + eps = slamch_("E"); +/* Computing 2nd power */ + r__1 = eps; + eps2 = r__1 * r__1; + safmin = slamch_("S"); + safmax = 1.f / safmin; + ssfmax = sqrt(safmax) / 3.f; + ssfmin = sqrt(safmin) / eps2; + +/* + Compute the eigenvalues and eigenvectors of the tridiagonal + matrix. +*/ + + if (icompz == 2) { + slaset_("Full", n, n, &c_b29, &c_b15, &z__[z_offset], ldz); + } + + nmaxit = *n * 30; + jtot = 0; + +/* + Determine where the matrix splits and choose QL or QR iteration + for each block, according to whether top or bottom diagonal + element is smaller. +*/ + + l1 = 1; + nm1 = *n - 1; + +L10: + if (l1 > *n) { + goto L160; + } + if (l1 > 1) { + e[l1 - 1] = 0.f; + } + if (l1 <= nm1) { + i__1 = nm1; + for (m = l1; m <= i__1; ++m) { + tst = (r__1 = e[m], dabs(r__1)); + if (tst == 0.f) { + goto L30; + } + if (tst <= sqrt((r__1 = d__[m], dabs(r__1))) * sqrt((r__2 = d__[m + + 1], dabs(r__2))) * eps) { + e[m] = 0.f; + goto L30; + } +/* L20: */ + } + } + m = *n; + +L30: + l = l1; + lsv = l; + lend = m; + lendsv = lend; + l1 = m + 1; + if (lend == l) { + goto L10; + } + +/* Scale submatrix in rows and columns L to LEND */ + + i__1 = lend - l + 1; + anorm = slanst_("I", &i__1, &d__[l], &e[l]); + iscale = 0; + if (anorm == 0.f) { + goto L10; + } + if (anorm > ssfmax) { + iscale = 1; + i__1 = lend - l + 1; + slascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + slascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, + info); + } else if (anorm < ssfmin) { + iscale = 2; + i__1 = lend - l + 1; + slascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + slascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, + info); + } + +/* Choose between QL and QR iteration */ + + if ((r__1 = d__[lend], dabs(r__1)) < (r__2 = d__[l], dabs(r__2))) { + lend = lsv; + l = lendsv; + } + + if (lend > l) { + +/* + QL Iteration + + Look for small subdiagonal element. +*/ + +L40: + if (l != lend) { + lendm1 = lend - 1; + i__1 = lendm1; + for (m = l; m <= i__1; ++m) { +/* Computing 2nd power */ + r__2 = (r__1 = e[m], dabs(r__1)); + tst = r__2 * r__2; + if (tst <= eps2 * (r__1 = d__[m], dabs(r__1)) * (r__2 = d__[m + + 1], dabs(r__2)) + safmin) { + goto L60; + } +/* L50: */ + } + } + + m = lend; + +L60: + if (m < lend) { + e[m] = 0.f; + } + p = d__[l]; + if (m == l) { + goto L80; + } + +/* + If remaining matrix is 2-by-2, use SLAE2 or SLAEV2 + to compute its eigensystem. +*/ + + if (m == l + 1) { + if (icompz > 0) { + slaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); + work[l] = c__; + work[*n - 1 + l] = s; + slasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], & + z__[l * z_dim1 + 1], ldz); + } else { + slae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); + } + d__[l] = rt1; + d__[l + 1] = rt2; + e[l] = 0.f; + l += 2; + if (l <= lend) { + goto L40; + } + goto L140; + } + + if (jtot == nmaxit) { + goto L140; + } + ++jtot; + +/* Form shift. */ + + g = (d__[l + 1] - p) / (e[l] * 2.f); + r__ = slapy2_(&g, &c_b15); + g = d__[m] - p + e[l] / (g + r_sign(&r__, &g)); + + s = 1.f; + c__ = 1.f; + p = 0.f; + +/* Inner loop */ + + mm1 = m - 1; + i__1 = l; + for (i__ = mm1; i__ >= i__1; --i__) { + f = s * e[i__]; + b = c__ * e[i__]; + slartg_(&g, &f, &c__, &s, &r__); + if (i__ != m - 1) { + e[i__ + 1] = r__; + } + g = d__[i__ + 1] - p; + r__ = (d__[i__] - g) * s + c__ * 2.f * b; + p = s * r__; + d__[i__ + 1] = g + p; + g = c__ * r__ - b; + +/* If eigenvectors are desired, then save rotations. */ + + if (icompz > 0) { + work[i__] = c__; + work[*n - 1 + i__] = -s; + } + +/* L70: */ + } + +/* If eigenvectors are desired, then apply saved rotations. */ + + if (icompz > 0) { + mm = m - l + 1; + slasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l + * z_dim1 + 1], ldz); + } + + d__[l] -= p; + e[l] = g; + goto L40; + +/* Eigenvalue found. */ + +L80: + d__[l] = p; + + ++l; + if (l <= lend) { + goto L40; + } + goto L140; + + } else { + +/* + QR Iteration + + Look for small superdiagonal element. +*/ + +L90: + if (l != lend) { + lendp1 = lend + 1; + i__1 = lendp1; + for (m = l; m >= i__1; --m) { +/* Computing 2nd power */ + r__2 = (r__1 = e[m - 1], dabs(r__1)); + tst = r__2 * r__2; + if (tst <= eps2 * (r__1 = d__[m], dabs(r__1)) * (r__2 = d__[m + - 1], dabs(r__2)) + safmin) { + goto L110; + } +/* L100: */ + } + } + + m = lend; + +L110: + if (m > lend) { + e[m - 1] = 0.f; + } + p = d__[l]; + if (m == l) { + goto L130; + } + +/* + If remaining matrix is 2-by-2, use SLAE2 or SLAEV2 + to compute its eigensystem. +*/ + + if (m == l - 1) { + if (icompz > 0) { + slaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) + ; + work[m] = c__; + work[*n - 1 + m] = s; + slasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], & + z__[(l - 1) * z_dim1 + 1], ldz); + } else { + slae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); + } + d__[l - 1] = rt1; + d__[l] = rt2; + e[l - 1] = 0.f; + l += -2; + if (l >= lend) { + goto L90; + } + goto L140; + } + + if (jtot == nmaxit) { + goto L140; + } + ++jtot; + +/* Form shift. */ + + g = (d__[l - 1] - p) / (e[l - 1] * 2.f); + r__ = slapy2_(&g, &c_b15); + g = d__[m] - p + e[l - 1] / (g + r_sign(&r__, &g)); + + s = 1.f; + c__ = 1.f; + p = 0.f; + +/* Inner loop */ + + lm1 = l - 1; + i__1 = lm1; + for (i__ = m; i__ <= i__1; ++i__) { + f = s * e[i__]; + b = c__ * e[i__]; + slartg_(&g, &f, &c__, &s, &r__); + if (i__ != m) { + e[i__ - 1] = r__; + } + g = d__[i__] - p; + r__ = (d__[i__ + 1] - g) * s + c__ * 2.f * b; + p = s * r__; + d__[i__] = g + p; + g = c__ * r__ - b; + +/* If eigenvectors are desired, then save rotations. */ + + if (icompz > 0) { + work[i__] = c__; + work[*n - 1 + i__] = s; + } + +/* L120: */ + } + +/* If eigenvectors are desired, then apply saved rotations. */ + + if (icompz > 0) { + mm = l - m + 1; + slasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m + * z_dim1 + 1], ldz); + } + + d__[l] -= p; + e[lm1] = g; + goto L90; + +/* Eigenvalue found. */ + +L130: + d__[l] = p; + + --l; + if (l >= lend) { + goto L90; + } + goto L140; + + } + +/* Undo scaling if necessary */ + +L140: + if (iscale == 1) { + i__1 = lendsv - lsv + 1; + slascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + i__1 = lendsv - lsv; + slascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, + info); + } else if (iscale == 2) { + i__1 = lendsv - lsv + 1; + slascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + i__1 = lendsv - lsv; + slascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, + info); + } + +/* + Check for no convergence to an eigenvalue after a total + of N*MAXIT iterations. +*/ + + if (jtot < nmaxit) { + goto L10; + } + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (e[i__] != 0.f) { + ++(*info); + } +/* L150: */ + } + goto L190; + +/* Order eigenvalues and eigenvectors. */ + +L160: + if (icompz == 0) { + +/* Use Quick Sort */ + + slasrt_("I", n, &d__[1], info); + + } else { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L170: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + sswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], + &c__1); + } +/* L180: */ + } + } + +L190: + return 0; + +/* End of SSTEQR */ + +} /* ssteqr_ */ + +/* Subroutine */ int ssterf_(integer *n, real *d__, real *e, integer *info) +{ + /* System generated locals */ + integer i__1; + real r__1, r__2, r__3; + + /* Local variables */ + static real c__; + static integer i__, l, m; + static real p, r__, s; + static integer l1; + static real bb, rt1, rt2, eps, rte; + static integer lsv; + static real eps2, oldc; + static integer lend, jtot; + extern /* Subroutine */ int slae2_(real *, real *, real *, real *, real *) + ; + static real gamma, alpha, sigma, anorm; + extern doublereal slapy2_(real *, real *); + static integer iscale; + static real oldgam; + extern doublereal slamch_(char *); + static real safmin; + extern /* Subroutine */ int xerbla_(char *, integer *); + static real safmax; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *); + static integer lendsv; + static real ssfmin; + static integer nmaxit; + static real ssfmax; + extern doublereal slanst_(char *, integer *, real *, real *); + extern /* Subroutine */ int slasrt_(char *, integer *, real *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SSTERF computes all eigenvalues of a symmetric tridiagonal matrix + using the Pal-Walker-Kahan variant of the QL or QR algorithm. + + Arguments + ========= + + N (input) INTEGER + The order of the matrix. N >= 0. + + D (input/output) REAL array, dimension (N) + On entry, the n diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) REAL array, dimension (N-1) + On entry, the (n-1) subdiagonal elements of the tridiagonal + matrix. + On exit, E has been destroyed. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: the algorithm failed to find all of the eigenvalues in + a total of 30*N iterations; if INFO = i, then i + elements of E have not converged to zero. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --e; + --d__; + + /* Function Body */ + *info = 0; + +/* Quick return if possible */ + + if (*n < 0) { + *info = -1; + i__1 = -(*info); + xerbla_("SSTERF", &i__1); + return 0; + } + if (*n <= 1) { + return 0; + } + +/* Determine the unit roundoff for this environment. */ + + eps = slamch_("E"); +/* Computing 2nd power */ + r__1 = eps; + eps2 = r__1 * r__1; + safmin = slamch_("S"); + safmax = 1.f / safmin; + ssfmax = sqrt(safmax) / 3.f; + ssfmin = sqrt(safmin) / eps2; + +/* Compute the eigenvalues of the tridiagonal matrix. */ + + nmaxit = *n * 30; + sigma = 0.f; + jtot = 0; + +/* + Determine where the matrix splits and choose QL or QR iteration + for each block, according to whether top or bottom diagonal + element is smaller. +*/ + + l1 = 1; + +L10: + if (l1 > *n) { + goto L170; + } + if (l1 > 1) { + e[l1 - 1] = 0.f; + } + i__1 = *n - 1; + for (m = l1; m <= i__1; ++m) { + if ((r__3 = e[m], dabs(r__3)) <= sqrt((r__1 = d__[m], dabs(r__1))) * + sqrt((r__2 = d__[m + 1], dabs(r__2))) * eps) { + e[m] = 0.f; + goto L30; + } +/* L20: */ + } + m = *n; + +L30: + l = l1; + lsv = l; + lend = m; + lendsv = lend; + l1 = m + 1; + if (lend == l) { + goto L10; + } + +/* Scale submatrix in rows and columns L to LEND */ + + i__1 = lend - l + 1; + anorm = slanst_("I", &i__1, &d__[l], &e[l]); + iscale = 0; + if (anorm > ssfmax) { + iscale = 1; + i__1 = lend - l + 1; + slascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + slascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, + info); + } else if (anorm < ssfmin) { + iscale = 2; + i__1 = lend - l + 1; + slascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + slascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, + info); + } + + i__1 = lend - 1; + for (i__ = l; i__ <= i__1; ++i__) { +/* Computing 2nd power */ + r__1 = e[i__]; + e[i__] = r__1 * r__1; +/* L40: */ + } + +/* Choose between QL and QR iteration */ + + if ((r__1 = d__[lend], dabs(r__1)) < (r__2 = d__[l], dabs(r__2))) { + lend = lsv; + l = lendsv; + } + + if (lend >= l) { + +/* + QL Iteration + + Look for small subdiagonal element. +*/ + +L50: + if (l != lend) { + i__1 = lend - 1; + for (m = l; m <= i__1; ++m) { + if ((r__2 = e[m], dabs(r__2)) <= eps2 * (r__1 = d__[m] * d__[ + m + 1], dabs(r__1))) { + goto L70; + } +/* L60: */ + } + } + m = lend; + +L70: + if (m < lend) { + e[m] = 0.f; + } + p = d__[l]; + if (m == l) { + goto L90; + } + +/* + If remaining matrix is 2 by 2, use SLAE2 to compute its + eigenvalues. +*/ + + if (m == l + 1) { + rte = sqrt(e[l]); + slae2_(&d__[l], &rte, &d__[l + 1], &rt1, &rt2); + d__[l] = rt1; + d__[l + 1] = rt2; + e[l] = 0.f; + l += 2; + if (l <= lend) { + goto L50; + } + goto L150; + } + + if (jtot == nmaxit) { + goto L150; + } + ++jtot; + +/* Form shift. */ + + rte = sqrt(e[l]); + sigma = (d__[l + 1] - p) / (rte * 2.f); + r__ = slapy2_(&sigma, &c_b15); + sigma = p - rte / (sigma + r_sign(&r__, &sigma)); + + c__ = 1.f; + s = 0.f; + gamma = d__[m] - sigma; + p = gamma * gamma; + +/* Inner loop */ + + i__1 = l; + for (i__ = m - 1; i__ >= i__1; --i__) { + bb = e[i__]; + r__ = p + bb; + if (i__ != m - 1) { + e[i__ + 1] = s * r__; + } + oldc = c__; + c__ = p / r__; + s = bb / r__; + oldgam = gamma; + alpha = d__[i__]; + gamma = c__ * (alpha - sigma) - s * oldgam; + d__[i__ + 1] = oldgam + (alpha - gamma); + if (c__ != 0.f) { + p = gamma * gamma / c__; + } else { + p = oldc * bb; + } +/* L80: */ + } + + e[l] = s * p; + d__[l] = sigma + gamma; + goto L50; + +/* Eigenvalue found. */ + +L90: + d__[l] = p; + + ++l; + if (l <= lend) { + goto L50; + } + goto L150; + + } else { + +/* + QR Iteration + + Look for small superdiagonal element. +*/ + +L100: + i__1 = lend + 1; + for (m = l; m >= i__1; --m) { + if ((r__2 = e[m - 1], dabs(r__2)) <= eps2 * (r__1 = d__[m] * d__[ + m - 1], dabs(r__1))) { + goto L120; + } +/* L110: */ + } + m = lend; + +L120: + if (m > lend) { + e[m - 1] = 0.f; + } + p = d__[l]; + if (m == l) { + goto L140; + } + +/* + If remaining matrix is 2 by 2, use SLAE2 to compute its + eigenvalues. +*/ + + if (m == l - 1) { + rte = sqrt(e[l - 1]); + slae2_(&d__[l], &rte, &d__[l - 1], &rt1, &rt2); + d__[l] = rt1; + d__[l - 1] = rt2; + e[l - 1] = 0.f; + l += -2; + if (l >= lend) { + goto L100; + } + goto L150; + } + + if (jtot == nmaxit) { + goto L150; + } + ++jtot; + +/* Form shift. */ + + rte = sqrt(e[l - 1]); + sigma = (d__[l - 1] - p) / (rte * 2.f); + r__ = slapy2_(&sigma, &c_b15); + sigma = p - rte / (sigma + r_sign(&r__, &sigma)); + + c__ = 1.f; + s = 0.f; + gamma = d__[m] - sigma; + p = gamma * gamma; + +/* Inner loop */ + + i__1 = l - 1; + for (i__ = m; i__ <= i__1; ++i__) { + bb = e[i__]; + r__ = p + bb; + if (i__ != m) { + e[i__ - 1] = s * r__; + } + oldc = c__; + c__ = p / r__; + s = bb / r__; + oldgam = gamma; + alpha = d__[i__ + 1]; + gamma = c__ * (alpha - sigma) - s * oldgam; + d__[i__] = oldgam + (alpha - gamma); + if (c__ != 0.f) { + p = gamma * gamma / c__; + } else { + p = oldc * bb; + } +/* L130: */ + } + + e[l - 1] = s * p; + d__[l] = sigma + gamma; + goto L100; + +/* Eigenvalue found. */ + +L140: + d__[l] = p; + + --l; + if (l >= lend) { + goto L100; + } + goto L150; + + } + +/* Undo scaling if necessary */ + +L150: + if (iscale == 1) { + i__1 = lendsv - lsv + 1; + slascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + } + if (iscale == 2) { + i__1 = lendsv - lsv + 1; + slascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + } + +/* + Check for no convergence to an eigenvalue after a total + of N*MAXIT iterations. +*/ + + if (jtot < nmaxit) { + goto L10; + } + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (e[i__] != 0.f) { + ++(*info); + } +/* L160: */ + } + goto L180; + +/* Sort eigenvalues in increasing order. */ + +L170: + slasrt_("I", n, &d__[1], info); + +L180: + return 0; + +/* End of SSTERF */ + +} /* ssterf_ */ + +/* Subroutine */ int ssyevd_(char *jobz, char *uplo, integer *n, real *a, + integer *lda, real *w, real *work, integer *lwork, integer *iwork, + integer *liwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + real r__1; + + /* Local variables */ + static real eps; + static integer inde; + static real anrm, rmin, rmax; + static integer lopt; + static real sigma; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + static integer lwmin, liopt; + static logical lower, wantz; + static integer indwk2, llwrk2, iscale; + extern doublereal slamch_(char *); + static real safmin; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *); + static real bignum; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *); + static integer indtau; + extern /* Subroutine */ int sstedc_(char *, integer *, real *, real *, + real *, integer *, real *, integer *, integer *, integer *, + integer *), slacpy_(char *, integer *, integer *, real *, + integer *, real *, integer *); + static integer indwrk, liwmin; + extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *); + extern doublereal slansy_(char *, char *, integer *, real *, integer *, + real *); + static integer llwork; + static real smlnum; + static logical lquery; + extern /* Subroutine */ int sormtr_(char *, char *, char *, integer *, + integer *, real *, integer *, real *, real *, integer *, real *, + integer *, integer *), ssytrd_(char *, + integer *, real *, integer *, real *, real *, real *, real *, + integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SSYEVD computes all eigenvalues and, optionally, eigenvectors of a + real symmetric matrix A. If eigenvectors are desired, it uses a + divide and conquer algorithm. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Because of large use of BLAS of level 3, SSYEVD needs N**2 more + workspace than SSYEVX. + + Arguments + ========= + + JOBZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only; + = 'V': Compute eigenvalues and eigenvectors. + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA, N) + On entry, the symmetric matrix A. If UPLO = 'U', the + leading N-by-N upper triangular part of A contains the + upper triangular part of the matrix A. If UPLO = 'L', + the leading N-by-N lower triangular part of A contains + the lower triangular part of the matrix A. + On exit, if JOBZ = 'V', then if INFO = 0, A contains the + orthonormal eigenvectors of the matrix A. + If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') + or the upper triangle (if UPLO='U') of A, including the + diagonal, is destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + W (output) REAL array, dimension (N) + If INFO = 0, the eigenvalues in ascending order. + + WORK (workspace/output) REAL array, + dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If N <= 1, LWORK must be at least 1. + If JOBZ = 'N' and N > 1, LWORK must be at least 2*N+1. + If JOBZ = 'V' and N > 1, LWORK must be at least + 1 + 6*N + 2*N**2. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal sizes of the WORK and IWORK + arrays, returns these values as the first entries of the WORK + and IWORK arrays, and no error message related to LWORK or + LIWORK is issued by XERBLA. + + IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) + On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. + + LIWORK (input) INTEGER + The dimension of the array IWORK. + If N <= 1, LIWORK must be at least 1. + If JOBZ = 'N' and N > 1, LIWORK must be at least 1. + If JOBZ = 'V' and N > 1, LIWORK must be at least 3 + 5*N. + + If LIWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK and + IWORK arrays, returns these values as the first entries of + the WORK and IWORK arrays, and no error message related to + LWORK or LIWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i and JOBZ = 'N', then the algorithm failed + to converge; i off-diagonal elements of an intermediate + tridiagonal form did not converge to zero; + if INFO = i and JOBZ = 'V', then the algorithm failed + to compute an eigenvalue while working on the submatrix + lying in rows and columns INFO/(N+1) through + mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + Modified by Francoise Tisseur, University of Tennessee. + + Modified description of INFO. Sven, 16 Feb 05. + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --w; + --work; + --iwork; + + /* Function Body */ + wantz = lsame_(jobz, "V"); + lower = lsame_(uplo, "L"); + lquery = *lwork == -1 || *liwork == -1; + + *info = 0; + if (! (wantz || lsame_(jobz, "N"))) { + *info = -1; + } else if (! (lower || lsame_(uplo, "U"))) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + + if (*info == 0) { + if (*n <= 1) { + liwmin = 1; + lwmin = 1; + lopt = lwmin; + liopt = liwmin; + } else { + if (wantz) { + liwmin = *n * 5 + 3; +/* Computing 2nd power */ + i__1 = *n; + lwmin = *n * 6 + 1 + (i__1 * i__1 << 1); + } else { + liwmin = 1; + lwmin = (*n << 1) + 1; + } +/* Computing MAX */ + i__1 = lwmin, i__2 = (*n << 1) + ilaenv_(&c__1, "SSYTRD", uplo, n, + &c_n1, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + lopt = max(i__1,i__2); + liopt = liwmin; + } + work[1] = (real) lopt; + iwork[1] = liopt; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*liwork < liwmin && ! lquery) { + *info = -10; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SSYEVD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (*n == 1) { + w[1] = a[a_dim1 + 1]; + if (wantz) { + a[a_dim1 + 1] = 1.f; + } + return 0; + } + +/* Get machine constants. */ + + safmin = slamch_("Safe minimum"); + eps = slamch_("Precision"); + smlnum = safmin / eps; + bignum = 1.f / smlnum; + rmin = sqrt(smlnum); + rmax = sqrt(bignum); + +/* Scale matrix to allowable range, if necessary. */ + + anrm = slansy_("M", uplo, n, &a[a_offset], lda, &work[1]); + iscale = 0; + if (anrm > 0.f && anrm < rmin) { + iscale = 1; + sigma = rmin / anrm; + } else if (anrm > rmax) { + iscale = 1; + sigma = rmax / anrm; + } + if (iscale == 1) { + slascl_(uplo, &c__0, &c__0, &c_b15, &sigma, n, n, &a[a_offset], lda, + info); + } + +/* Call SSYTRD to reduce symmetric matrix to tridiagonal form. */ + + inde = 1; + indtau = inde + *n; + indwrk = indtau + *n; + llwork = *lwork - indwrk + 1; + indwk2 = indwrk + *n * *n; + llwrk2 = *lwork - indwk2 + 1; + + ssytrd_(uplo, n, &a[a_offset], lda, &w[1], &work[inde], &work[indtau], & + work[indwrk], &llwork, &iinfo); + +/* + For eigenvalues only, call SSTERF. For eigenvectors, first call + SSTEDC to generate the eigenvector matrix, WORK(INDWRK), of the + tridiagonal matrix, then call SORMTR to multiply it by the + Householder transformations stored in A. +*/ + + if (! wantz) { + ssterf_(n, &w[1], &work[inde], info); + } else { + sstedc_("I", n, &w[1], &work[inde], &work[indwrk], n, &work[indwk2], & + llwrk2, &iwork[1], liwork, info); + sormtr_("L", uplo, "N", n, n, &a[a_offset], lda, &work[indtau], &work[ + indwrk], n, &work[indwk2], &llwrk2, &iinfo); + slacpy_("A", n, n, &work[indwrk], n, &a[a_offset], lda); + } + +/* If matrix was scaled, then rescale eigenvalues appropriately. */ + + if (iscale == 1) { + r__1 = 1.f / sigma; + sscal_(n, &r__1, &w[1], &c__1); + } + + work[1] = (real) lopt; + iwork[1] = liopt; + + return 0; + +/* End of SSYEVD */ + +} /* ssyevd_ */ + +/* Subroutine */ int ssytd2_(char *uplo, integer *n, real *a, integer *lda, + real *d__, real *e, real *tau, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__; + static real taui; + extern doublereal sdot_(integer *, real *, integer *, real *, integer *); + extern /* Subroutine */ int ssyr2_(char *, integer *, real *, real *, + integer *, real *, integer *, real *, integer *); + static real alpha; + extern logical lsame_(char *, char *); + static logical upper; + extern /* Subroutine */ int saxpy_(integer *, real *, real *, integer *, + real *, integer *), ssymv_(char *, integer *, real *, real *, + integer *, real *, integer *, real *, real *, integer *), + xerbla_(char *, integer *), slarfg_(integer *, real *, + real *, integer *, real *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SSYTD2 reduces a real symmetric matrix A to symmetric tridiagonal + form T by an orthogonal similarity transformation: Q' * A * Q = T. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is stored: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + n-by-n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n-by-n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit, if UPLO = 'U', the diagonal and first superdiagonal + of A are overwritten by the corresponding elements of the + tridiagonal matrix T, and the elements above the first + superdiagonal, with the array TAU, represent the orthogonal + matrix Q as a product of elementary reflectors; if UPLO + = 'L', the diagonal and first subdiagonal of A are over- + written by the corresponding elements of the tridiagonal + matrix T, and the elements below the first subdiagonal, with + the array TAU, represent the orthogonal matrix Q as a product + of elementary reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + D (output) REAL array, dimension (N) + The diagonal elements of the tridiagonal matrix T: + D(i) = A(i,i). + + E (output) REAL array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix T: + E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. + + TAU (output) REAL array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-1) . . . H(2) H(1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in + A(1:i-1,i+1), and tau in TAU(i). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(n-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v2 v3 v4 ) ( d ) + ( d e v3 v4 ) ( e d ) + ( d e v4 ) ( v1 e d ) + ( d e ) ( v1 v2 e d ) + ( d ) ( v1 v2 v3 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tau; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SSYTD2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + return 0; + } + + if (upper) { + +/* Reduce the upper triangle of A */ + + for (i__ = *n - 1; i__ >= 1; --i__) { + +/* + Generate elementary reflector H(i) = I - tau * v * v' + to annihilate A(1:i-1,i+1) +*/ + + slarfg_(&i__, &a[i__ + (i__ + 1) * a_dim1], &a[(i__ + 1) * a_dim1 + + 1], &c__1, &taui); + e[i__] = a[i__ + (i__ + 1) * a_dim1]; + + if (taui != 0.f) { + +/* Apply H(i) from both sides to A(1:i,1:i) */ + + a[i__ + (i__ + 1) * a_dim1] = 1.f; + +/* Compute x := tau * A * v storing x in TAU(1:i) */ + + ssymv_(uplo, &i__, &taui, &a[a_offset], lda, &a[(i__ + 1) * + a_dim1 + 1], &c__1, &c_b29, &tau[1], &c__1) + ; + +/* Compute w := x - 1/2 * tau * (x'*v) * v */ + + alpha = taui * -.5f * sdot_(&i__, &tau[1], &c__1, &a[(i__ + 1) + * a_dim1 + 1], &c__1); + saxpy_(&i__, &alpha, &a[(i__ + 1) * a_dim1 + 1], &c__1, &tau[ + 1], &c__1); + +/* + Apply the transformation as a rank-2 update: + A := A - v * w' - w * v' +*/ + + ssyr2_(uplo, &i__, &c_b151, &a[(i__ + 1) * a_dim1 + 1], &c__1, + &tau[1], &c__1, &a[a_offset], lda); + + a[i__ + (i__ + 1) * a_dim1] = e[i__]; + } + d__[i__ + 1] = a[i__ + 1 + (i__ + 1) * a_dim1]; + tau[i__] = taui; +/* L10: */ + } + d__[1] = a[a_dim1 + 1]; + } else { + +/* Reduce the lower triangle of A */ + + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* + Generate elementary reflector H(i) = I - tau * v * v' + to annihilate A(i+2:n,i) +*/ + + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + slarfg_(&i__2, &a[i__ + 1 + i__ * a_dim1], &a[min(i__3,*n) + i__ * + a_dim1], &c__1, &taui); + e[i__] = a[i__ + 1 + i__ * a_dim1]; + + if (taui != 0.f) { + +/* Apply H(i) from both sides to A(i+1:n,i+1:n) */ + + a[i__ + 1 + i__ * a_dim1] = 1.f; + +/* Compute x := tau * A * v storing y in TAU(i:n-1) */ + + i__2 = *n - i__; + ssymv_(uplo, &i__2, &taui, &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b29, &tau[ + i__], &c__1); + +/* Compute w := x - 1/2 * tau * (x'*v) * v */ + + i__2 = *n - i__; + alpha = taui * -.5f * sdot_(&i__2, &tau[i__], &c__1, &a[i__ + + 1 + i__ * a_dim1], &c__1); + i__2 = *n - i__; + saxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &c__1); + +/* + Apply the transformation as a rank-2 update: + A := A - v * w' - w * v' +*/ + + i__2 = *n - i__; + ssyr2_(uplo, &i__2, &c_b151, &a[i__ + 1 + i__ * a_dim1], & + c__1, &tau[i__], &c__1, &a[i__ + 1 + (i__ + 1) * + a_dim1], lda); + + a[i__ + 1 + i__ * a_dim1] = e[i__]; + } + d__[i__] = a[i__ + i__ * a_dim1]; + tau[i__] = taui; +/* L20: */ + } + d__[*n] = a[*n + *n * a_dim1]; + } + + return 0; + +/* End of SSYTD2 */ + +} /* ssytd2_ */ + +/* Subroutine */ int ssytrd_(char *uplo, integer *n, real *a, integer *lda, + real *d__, real *e, real *tau, real *work, integer *lwork, integer * + info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, nb, kk, nx, iws; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + static logical upper; + extern /* Subroutine */ int ssytd2_(char *, integer *, real *, integer *, + real *, real *, real *, integer *), ssyr2k_(char *, char * + , integer *, integer *, real *, real *, integer *, real *, + integer *, real *, real *, integer *), xerbla_( + char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int slatrd_(char *, integer *, integer *, real *, + integer *, real *, real *, real *, integer *); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + SSYTRD reduces a real symmetric matrix A to real symmetric + tridiagonal form T by an orthogonal similarity transformation: + Q**T * A * Q = T. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit, if UPLO = 'U', the diagonal and first superdiagonal + of A are overwritten by the corresponding elements of the + tridiagonal matrix T, and the elements above the first + superdiagonal, with the array TAU, represent the orthogonal + matrix Q as a product of elementary reflectors; if UPLO + = 'L', the diagonal and first subdiagonal of A are over- + written by the corresponding elements of the tridiagonal + matrix T, and the elements below the first subdiagonal, with + the array TAU, represent the orthogonal matrix Q as a product + of elementary reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + D (output) REAL array, dimension (N) + The diagonal elements of the tridiagonal matrix T: + D(i) = A(i,i). + + E (output) REAL array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix T: + E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. + + TAU (output) REAL array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) REAL array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= 1. + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-1) . . . H(2) H(1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in + A(1:i-1,i+1), and tau in TAU(i). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(n-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v2 v3 v4 ) ( d ) + ( d e v3 v4 ) ( e d ) + ( d e v4 ) ( v1 e d ) + ( d e ) ( v1 v2 e d ) + ( d ) ( v1 v2 v3 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tau; + --work; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + lquery = *lwork == -1; + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*lwork < 1 && ! lquery) { + *info = -9; + } + + if (*info == 0) { + +/* Determine the block size. */ + + nb = ilaenv_(&c__1, "SSYTRD", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, + (ftnlen)1); + lwkopt = *n * nb; + work[1] = (real) lwkopt; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("SSYTRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + work[1] = 1.f; + return 0; + } + + nx = *n; + iws = 1; + if (nb > 1 && nb < *n) { + +/* + Determine when to cross over from blocked to unblocked code + (last block is always handled by unblocked code). + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "SSYTRD", uplo, n, &c_n1, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *n) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: determine the + minimum value of NB, and reduce NB or force use of + unblocked code by setting NX = N. + + Computing MAX +*/ + i__1 = *lwork / ldwork; + nb = max(i__1,1); + nbmin = ilaenv_(&c__2, "SSYTRD", uplo, n, &c_n1, &c_n1, &c_n1, + (ftnlen)6, (ftnlen)1); + if (nb < nbmin) { + nx = *n; + } + } + } else { + nx = *n; + } + } else { + nb = 1; + } + + if (upper) { + +/* + Reduce the upper triangle of A. + Columns 1:kk are handled by the unblocked method. +*/ + + kk = *n - (*n - nx + nb - 1) / nb * nb; + i__1 = kk + 1; + i__2 = -nb; + for (i__ = *n - nb + 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { + +/* + Reduce columns i:i+nb-1 to tridiagonal form and form the + matrix W which is needed to update the unreduced part of + the matrix +*/ + + i__3 = i__ + nb - 1; + slatrd_(uplo, &i__3, &nb, &a[a_offset], lda, &e[1], &tau[1], & + work[1], &ldwork); + +/* + Update the unreduced submatrix A(1:i-1,1:i-1), using an + update of the form: A := A - V*W' - W*V' +*/ + + i__3 = i__ - 1; + ssyr2k_(uplo, "No transpose", &i__3, &nb, &c_b151, &a[i__ * + a_dim1 + 1], lda, &work[1], &ldwork, &c_b15, &a[a_offset], + lda); + +/* + Copy superdiagonal elements back into A, and diagonal + elements into D +*/ + + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + a[j - 1 + j * a_dim1] = e[j - 1]; + d__[j] = a[j + j * a_dim1]; +/* L10: */ + } +/* L20: */ + } + +/* Use unblocked code to reduce the last or only block */ + + ssytd2_(uplo, &kk, &a[a_offset], lda, &d__[1], &e[1], &tau[1], &iinfo); + } else { + +/* Reduce the lower triangle of A */ + + i__2 = *n - nx; + i__1 = nb; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { + +/* + Reduce columns i:i+nb-1 to tridiagonal form and form the + matrix W which is needed to update the unreduced part of + the matrix +*/ + + i__3 = *n - i__ + 1; + slatrd_(uplo, &i__3, &nb, &a[i__ + i__ * a_dim1], lda, &e[i__], & + tau[i__], &work[1], &ldwork); + +/* + Update the unreduced submatrix A(i+ib:n,i+ib:n), using + an update of the form: A := A - V*W' - W*V' +*/ + + i__3 = *n - i__ - nb + 1; + ssyr2k_(uplo, "No transpose", &i__3, &nb, &c_b151, &a[i__ + nb + + i__ * a_dim1], lda, &work[nb + 1], &ldwork, &c_b15, &a[ + i__ + nb + (i__ + nb) * a_dim1], lda); + +/* + Copy subdiagonal elements back into A, and diagonal + elements into D +*/ + + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + a[j + 1 + j * a_dim1] = e[j]; + d__[j] = a[j + j * a_dim1]; +/* L30: */ + } +/* L40: */ + } + +/* Use unblocked code to reduce the last or only block */ + + i__1 = *n - i__ + 1; + ssytd2_(uplo, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], + &tau[i__], &iinfo); + } + + work[1] = (real) lwkopt; + return 0; + +/* End of SSYTRD */ + +} /* ssytrd_ */ + +/* Subroutine */ int strevc_(char *side, char *howmny, logical *select, + integer *n, real *t, integer *ldt, real *vl, integer *ldvl, real *vr, + integer *ldvr, integer *mm, integer *m, real *work, integer *info) +{ + /* System generated locals */ + integer t_dim1, t_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, + i__2, i__3; + real r__1, r__2, r__3, r__4; + + /* Local variables */ + static integer i__, j, k; + static real x[4] /* was [2][2] */; + static integer j1, j2, n2, ii, ki, ip, is; + static real wi, wr, rec, ulp, beta, emax; + static logical pair, allv; + static integer ierr; + static real unfl, ovfl, smin; + extern doublereal sdot_(integer *, real *, integer *, real *, integer *); + static logical over; + static real vmax; + static integer jnxt; + static real scale; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + static real remax; + static logical leftv; + extern /* Subroutine */ int sgemv_(char *, integer *, integer *, real *, + real *, integer *, real *, integer *, real *, real *, integer *); + static logical bothv; + static real vcrit; + static logical somev; + extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, + integer *); + static real xnorm; + extern /* Subroutine */ int saxpy_(integer *, real *, real *, integer *, + real *, integer *), slaln2_(logical *, integer *, integer *, real + *, real *, real *, integer *, real *, real *, real *, integer *, + real *, real *, real *, integer *, real *, real *, integer *), + slabad_(real *, real *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static real bignum; + extern integer isamax_(integer *, real *, integer *); + static logical rightv; + static real smlnum; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + STREVC computes some or all of the right and/or left eigenvectors of + a real upper quasi-triangular matrix T. + Matrices of this type are produced by the Schur factorization of + a real general matrix: A = Q*T*Q**T, as computed by SHSEQR. + + The right eigenvector x and the left eigenvector y of T corresponding + to an eigenvalue w are defined by: + + T*x = w*x, (y**H)*T = w*(y**H) + + where y**H denotes the conjugate transpose of y. + The eigenvalues are not input to this routine, but are read directly + from the diagonal blocks of T. + + This routine returns the matrices X and/or Y of right and left + eigenvectors of T, or the products Q*X and/or Q*Y, where Q is an + input matrix. If Q is the orthogonal factor that reduces a matrix + A to Schur form T, then Q*X and Q*Y are the matrices of right and + left eigenvectors of A. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'R': compute right eigenvectors only; + = 'L': compute left eigenvectors only; + = 'B': compute both right and left eigenvectors. + + HOWMNY (input) CHARACTER*1 + = 'A': compute all right and/or left eigenvectors; + = 'B': compute all right and/or left eigenvectors, + backtransformed by the matrices in VR and/or VL; + = 'S': compute selected right and/or left eigenvectors, + as indicated by the logical array SELECT. + + SELECT (input/output) LOGICAL array, dimension (N) + If HOWMNY = 'S', SELECT specifies the eigenvectors to be + computed. + If w(j) is a real eigenvalue, the corresponding real + eigenvector is computed if SELECT(j) is .TRUE.. + If w(j) and w(j+1) are the real and imaginary parts of a + complex eigenvalue, the corresponding complex eigenvector is + computed if either SELECT(j) or SELECT(j+1) is .TRUE., and + on exit SELECT(j) is set to .TRUE. and SELECT(j+1) is set to + .FALSE.. + Not referenced if HOWMNY = 'A' or 'B'. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input) REAL array, dimension (LDT,N) + The upper quasi-triangular matrix T in Schur canonical form. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + VL (input/output) REAL array, dimension (LDVL,MM) + On entry, if SIDE = 'L' or 'B' and HOWMNY = 'B', VL must + contain an N-by-N matrix Q (usually the orthogonal matrix Q + of Schur vectors returned by SHSEQR). + On exit, if SIDE = 'L' or 'B', VL contains: + if HOWMNY = 'A', the matrix Y of left eigenvectors of T; + if HOWMNY = 'B', the matrix Q*Y; + if HOWMNY = 'S', the left eigenvectors of T specified by + SELECT, stored consecutively in the columns + of VL, in the same order as their + eigenvalues. + A complex eigenvector corresponding to a complex eigenvalue + is stored in two consecutive columns, the first holding the + real part, and the second the imaginary part. + Not referenced if SIDE = 'R'. + + LDVL (input) INTEGER + The leading dimension of the array VL. LDVL >= 1, and if + SIDE = 'L' or 'B', LDVL >= N. + + VR (input/output) REAL array, dimension (LDVR,MM) + On entry, if SIDE = 'R' or 'B' and HOWMNY = 'B', VR must + contain an N-by-N matrix Q (usually the orthogonal matrix Q + of Schur vectors returned by SHSEQR). + On exit, if SIDE = 'R' or 'B', VR contains: + if HOWMNY = 'A', the matrix X of right eigenvectors of T; + if HOWMNY = 'B', the matrix Q*X; + if HOWMNY = 'S', the right eigenvectors of T specified by + SELECT, stored consecutively in the columns + of VR, in the same order as their + eigenvalues. + A complex eigenvector corresponding to a complex eigenvalue + is stored in two consecutive columns, the first holding the + real part and the second the imaginary part. + Not referenced if SIDE = 'L'. + + LDVR (input) INTEGER + The leading dimension of the array VR. LDVR >= 1, and if + SIDE = 'R' or 'B', LDVR >= N. + + MM (input) INTEGER + The number of columns in the arrays VL and/or VR. MM >= M. + + M (output) INTEGER + The number of columns in the arrays VL and/or VR actually + used to store the eigenvectors. + If HOWMNY = 'A' or 'B', M is set to N. + Each selected real eigenvector occupies one column and each + selected complex eigenvector occupies two columns. + + WORK (workspace) REAL array, dimension (3*N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The algorithm used in this program is basically backward (forward) + substitution, with scaling to make the the code robust against + possible overflow. + + Each eigenvector is normalized so that the element of largest + magnitude has magnitude 1; here the magnitude of a complex number + (x,y) is taken to be |x| + |y|. + + ===================================================================== + + + Decode and test the input parameters +*/ + + /* Parameter adjustments */ + --select; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + vl_dim1 = *ldvl; + vl_offset = 1 + vl_dim1; + vl -= vl_offset; + vr_dim1 = *ldvr; + vr_offset = 1 + vr_dim1; + vr -= vr_offset; + --work; + + /* Function Body */ + bothv = lsame_(side, "B"); + rightv = lsame_(side, "R") || bothv; + leftv = lsame_(side, "L") || bothv; + + allv = lsame_(howmny, "A"); + over = lsame_(howmny, "B"); + somev = lsame_(howmny, "S"); + + *info = 0; + if (! rightv && ! leftv) { + *info = -1; + } else if (! allv && ! over && ! somev) { + *info = -2; + } else if (*n < 0) { + *info = -4; + } else if (*ldt < max(1,*n)) { + *info = -6; + } else if (*ldvl < 1 || leftv && *ldvl < *n) { + *info = -8; + } else if (*ldvr < 1 || rightv && *ldvr < *n) { + *info = -10; + } else { + +/* + Set M to the number of columns required to store the selected + eigenvectors, standardize the array SELECT if necessary, and + test MM. +*/ + + if (somev) { + *m = 0; + pair = FALSE_; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (pair) { + pair = FALSE_; + select[j] = FALSE_; + } else { + if (j < *n) { + if (t[j + 1 + j * t_dim1] == 0.f) { + if (select[j]) { + ++(*m); + } + } else { + pair = TRUE_; + if (select[j] || select[j + 1]) { + select[j] = TRUE_; + *m += 2; + } + } + } else { + if (select[*n]) { + ++(*m); + } + } + } +/* L10: */ + } + } else { + *m = *n; + } + + if (*mm < *m) { + *info = -11; + } + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("STREVC", &i__1); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + +/* Set the constants to control overflow. */ + + unfl = slamch_("Safe minimum"); + ovfl = 1.f / unfl; + slabad_(&unfl, &ovfl); + ulp = slamch_("Precision"); + smlnum = unfl * (*n / ulp); + bignum = (1.f - ulp) / smlnum; + +/* + Compute 1-norm of each column of strictly upper triangular + part of T to control overflow in triangular solver. +*/ + + work[1] = 0.f; + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + work[j] = 0.f; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + work[j] += (r__1 = t[i__ + j * t_dim1], dabs(r__1)); +/* L20: */ + } +/* L30: */ + } + +/* + Index IP is used to specify the real or complex eigenvalue: + IP = 0, real eigenvalue, + 1, first of conjugate complex pair: (wr,wi) + -1, second of conjugate complex pair: (wr,wi) +*/ + + n2 = *n << 1; + + if (rightv) { + +/* Compute right eigenvectors. */ + + ip = 0; + is = *m; + for (ki = *n; ki >= 1; --ki) { + + if (ip == 1) { + goto L130; + } + if (ki == 1) { + goto L40; + } + if (t[ki + (ki - 1) * t_dim1] == 0.f) { + goto L40; + } + ip = -1; + +L40: + if (somev) { + if (ip == 0) { + if (! select[ki]) { + goto L130; + } + } else { + if (! select[ki - 1]) { + goto L130; + } + } + } + +/* Compute the KI-th eigenvalue (WR,WI). */ + + wr = t[ki + ki * t_dim1]; + wi = 0.f; + if (ip != 0) { + wi = sqrt((r__1 = t[ki + (ki - 1) * t_dim1], dabs(r__1))) * + sqrt((r__2 = t[ki - 1 + ki * t_dim1], dabs(r__2))); + } +/* Computing MAX */ + r__1 = ulp * (dabs(wr) + dabs(wi)); + smin = dmax(r__1,smlnum); + + if (ip == 0) { + +/* Real right eigenvector */ + + work[ki + *n] = 1.f; + +/* Form right-hand side */ + + i__1 = ki - 1; + for (k = 1; k <= i__1; ++k) { + work[k + *n] = -t[k + ki * t_dim1]; +/* L50: */ + } + +/* + Solve the upper quasi-triangular system: + (T(1:KI-1,1:KI-1) - WR)*X = SCALE*WORK. +*/ + + jnxt = ki - 1; + for (j = ki - 1; j >= 1; --j) { + if (j > jnxt) { + goto L60; + } + j1 = j; + j2 = j; + jnxt = j - 1; + if (j > 1) { + if (t[j + (j - 1) * t_dim1] != 0.f) { + j1 = j - 1; + jnxt = j - 2; + } + } + + if (j1 == j2) { + +/* 1-by-1 diagonal block */ + + slaln2_(&c_false, &c__1, &c__1, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &c_b29, x, &c__2, &scale, &xnorm, + &ierr); + +/* + Scale X(1,1) to avoid overflow when updating + the right-hand side. +*/ + + if (xnorm > 1.f) { + if (work[j] > bignum / xnorm) { + x[0] /= xnorm; + scale /= xnorm; + } + } + +/* Scale if necessary */ + + if (scale != 1.f) { + sscal_(&ki, &scale, &work[*n + 1], &c__1); + } + work[j + *n] = x[0]; + +/* Update right-hand side */ + + i__1 = j - 1; + r__1 = -x[0]; + saxpy_(&i__1, &r__1, &t[j * t_dim1 + 1], &c__1, &work[ + *n + 1], &c__1); + + } else { + +/* 2-by-2 diagonal block */ + + slaln2_(&c_false, &c__2, &c__1, &smin, &c_b15, &t[j - + 1 + (j - 1) * t_dim1], ldt, &c_b15, &c_b15, & + work[j - 1 + *n], n, &wr, &c_b29, x, &c__2, & + scale, &xnorm, &ierr); + +/* + Scale X(1,1) and X(2,1) to avoid overflow when + updating the right-hand side. +*/ + + if (xnorm > 1.f) { +/* Computing MAX */ + r__1 = work[j - 1], r__2 = work[j]; + beta = dmax(r__1,r__2); + if (beta > bignum / xnorm) { + x[0] /= xnorm; + x[1] /= xnorm; + scale /= xnorm; + } + } + +/* Scale if necessary */ + + if (scale != 1.f) { + sscal_(&ki, &scale, &work[*n + 1], &c__1); + } + work[j - 1 + *n] = x[0]; + work[j + *n] = x[1]; + +/* Update right-hand side */ + + i__1 = j - 2; + r__1 = -x[0]; + saxpy_(&i__1, &r__1, &t[(j - 1) * t_dim1 + 1], &c__1, + &work[*n + 1], &c__1); + i__1 = j - 2; + r__1 = -x[1]; + saxpy_(&i__1, &r__1, &t[j * t_dim1 + 1], &c__1, &work[ + *n + 1], &c__1); + } +L60: + ; + } + +/* Copy the vector x or Q*x to VR and normalize. */ + + if (! over) { + scopy_(&ki, &work[*n + 1], &c__1, &vr[is * vr_dim1 + 1], & + c__1); + + ii = isamax_(&ki, &vr[is * vr_dim1 + 1], &c__1); + remax = 1.f / (r__1 = vr[ii + is * vr_dim1], dabs(r__1)); + sscal_(&ki, &remax, &vr[is * vr_dim1 + 1], &c__1); + + i__1 = *n; + for (k = ki + 1; k <= i__1; ++k) { + vr[k + is * vr_dim1] = 0.f; +/* L70: */ + } + } else { + if (ki > 1) { + i__1 = ki - 1; + sgemv_("N", n, &i__1, &c_b15, &vr[vr_offset], ldvr, & + work[*n + 1], &c__1, &work[ki + *n], &vr[ki * + vr_dim1 + 1], &c__1); + } + + ii = isamax_(n, &vr[ki * vr_dim1 + 1], &c__1); + remax = 1.f / (r__1 = vr[ii + ki * vr_dim1], dabs(r__1)); + sscal_(n, &remax, &vr[ki * vr_dim1 + 1], &c__1); + } + + } else { + +/* + Complex right eigenvector. + + Initial solve + [ (T(KI-1,KI-1) T(KI-1,KI) ) - (WR + I* WI)]*X = 0. + [ (T(KI,KI-1) T(KI,KI) ) ] +*/ + + if ((r__1 = t[ki - 1 + ki * t_dim1], dabs(r__1)) >= (r__2 = t[ + ki + (ki - 1) * t_dim1], dabs(r__2))) { + work[ki - 1 + *n] = 1.f; + work[ki + n2] = wi / t[ki - 1 + ki * t_dim1]; + } else { + work[ki - 1 + *n] = -wi / t[ki + (ki - 1) * t_dim1]; + work[ki + n2] = 1.f; + } + work[ki + *n] = 0.f; + work[ki - 1 + n2] = 0.f; + +/* Form right-hand side */ + + i__1 = ki - 2; + for (k = 1; k <= i__1; ++k) { + work[k + *n] = -work[ki - 1 + *n] * t[k + (ki - 1) * + t_dim1]; + work[k + n2] = -work[ki + n2] * t[k + ki * t_dim1]; +/* L80: */ + } + +/* + Solve upper quasi-triangular system: + (T(1:KI-2,1:KI-2) - (WR+i*WI))*X = SCALE*(WORK+i*WORK2) +*/ + + jnxt = ki - 2; + for (j = ki - 2; j >= 1; --j) { + if (j > jnxt) { + goto L90; + } + j1 = j; + j2 = j; + jnxt = j - 1; + if (j > 1) { + if (t[j + (j - 1) * t_dim1] != 0.f) { + j1 = j - 1; + jnxt = j - 2; + } + } + + if (j1 == j2) { + +/* 1-by-1 diagonal block */ + + slaln2_(&c_false, &c__1, &c__2, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &wi, x, &c__2, &scale, &xnorm, & + ierr); + +/* + Scale X(1,1) and X(1,2) to avoid overflow when + updating the right-hand side. +*/ + + if (xnorm > 1.f) { + if (work[j] > bignum / xnorm) { + x[0] /= xnorm; + x[2] /= xnorm; + scale /= xnorm; + } + } + +/* Scale if necessary */ + + if (scale != 1.f) { + sscal_(&ki, &scale, &work[*n + 1], &c__1); + sscal_(&ki, &scale, &work[n2 + 1], &c__1); + } + work[j + *n] = x[0]; + work[j + n2] = x[2]; + +/* Update the right-hand side */ + + i__1 = j - 1; + r__1 = -x[0]; + saxpy_(&i__1, &r__1, &t[j * t_dim1 + 1], &c__1, &work[ + *n + 1], &c__1); + i__1 = j - 1; + r__1 = -x[2]; + saxpy_(&i__1, &r__1, &t[j * t_dim1 + 1], &c__1, &work[ + n2 + 1], &c__1); + + } else { + +/* 2-by-2 diagonal block */ + + slaln2_(&c_false, &c__2, &c__2, &smin, &c_b15, &t[j - + 1 + (j - 1) * t_dim1], ldt, &c_b15, &c_b15, & + work[j - 1 + *n], n, &wr, &wi, x, &c__2, & + scale, &xnorm, &ierr); + +/* + Scale X to avoid overflow when updating + the right-hand side. +*/ + + if (xnorm > 1.f) { +/* Computing MAX */ + r__1 = work[j - 1], r__2 = work[j]; + beta = dmax(r__1,r__2); + if (beta > bignum / xnorm) { + rec = 1.f / xnorm; + x[0] *= rec; + x[2] *= rec; + x[1] *= rec; + x[3] *= rec; + scale *= rec; + } + } + +/* Scale if necessary */ + + if (scale != 1.f) { + sscal_(&ki, &scale, &work[*n + 1], &c__1); + sscal_(&ki, &scale, &work[n2 + 1], &c__1); + } + work[j - 1 + *n] = x[0]; + work[j + *n] = x[1]; + work[j - 1 + n2] = x[2]; + work[j + n2] = x[3]; + +/* Update the right-hand side */ + + i__1 = j - 2; + r__1 = -x[0]; + saxpy_(&i__1, &r__1, &t[(j - 1) * t_dim1 + 1], &c__1, + &work[*n + 1], &c__1); + i__1 = j - 2; + r__1 = -x[1]; + saxpy_(&i__1, &r__1, &t[j * t_dim1 + 1], &c__1, &work[ + *n + 1], &c__1); + i__1 = j - 2; + r__1 = -x[2]; + saxpy_(&i__1, &r__1, &t[(j - 1) * t_dim1 + 1], &c__1, + &work[n2 + 1], &c__1); + i__1 = j - 2; + r__1 = -x[3]; + saxpy_(&i__1, &r__1, &t[j * t_dim1 + 1], &c__1, &work[ + n2 + 1], &c__1); + } +L90: + ; + } + +/* Copy the vector x or Q*x to VR and normalize. */ + + if (! over) { + scopy_(&ki, &work[*n + 1], &c__1, &vr[(is - 1) * vr_dim1 + + 1], &c__1); + scopy_(&ki, &work[n2 + 1], &c__1, &vr[is * vr_dim1 + 1], & + c__1); + + emax = 0.f; + i__1 = ki; + for (k = 1; k <= i__1; ++k) { +/* Computing MAX */ + r__3 = emax, r__4 = (r__1 = vr[k + (is - 1) * vr_dim1] + , dabs(r__1)) + (r__2 = vr[k + is * vr_dim1], + dabs(r__2)); + emax = dmax(r__3,r__4); +/* L100: */ + } + + remax = 1.f / emax; + sscal_(&ki, &remax, &vr[(is - 1) * vr_dim1 + 1], &c__1); + sscal_(&ki, &remax, &vr[is * vr_dim1 + 1], &c__1); + + i__1 = *n; + for (k = ki + 1; k <= i__1; ++k) { + vr[k + (is - 1) * vr_dim1] = 0.f; + vr[k + is * vr_dim1] = 0.f; +/* L110: */ + } + + } else { + + if (ki > 2) { + i__1 = ki - 2; + sgemv_("N", n, &i__1, &c_b15, &vr[vr_offset], ldvr, & + work[*n + 1], &c__1, &work[ki - 1 + *n], &vr[( + ki - 1) * vr_dim1 + 1], &c__1); + i__1 = ki - 2; + sgemv_("N", n, &i__1, &c_b15, &vr[vr_offset], ldvr, & + work[n2 + 1], &c__1, &work[ki + n2], &vr[ki * + vr_dim1 + 1], &c__1); + } else { + sscal_(n, &work[ki - 1 + *n], &vr[(ki - 1) * vr_dim1 + + 1], &c__1); + sscal_(n, &work[ki + n2], &vr[ki * vr_dim1 + 1], & + c__1); + } + + emax = 0.f; + i__1 = *n; + for (k = 1; k <= i__1; ++k) { +/* Computing MAX */ + r__3 = emax, r__4 = (r__1 = vr[k + (ki - 1) * vr_dim1] + , dabs(r__1)) + (r__2 = vr[k + ki * vr_dim1], + dabs(r__2)); + emax = dmax(r__3,r__4); +/* L120: */ + } + remax = 1.f / emax; + sscal_(n, &remax, &vr[(ki - 1) * vr_dim1 + 1], &c__1); + sscal_(n, &remax, &vr[ki * vr_dim1 + 1], &c__1); + } + } + + --is; + if (ip != 0) { + --is; + } +L130: + if (ip == 1) { + ip = 0; + } + if (ip == -1) { + ip = 1; + } +/* L140: */ + } + } + + if (leftv) { + +/* Compute left eigenvectors. */ + + ip = 0; + is = 1; + i__1 = *n; + for (ki = 1; ki <= i__1; ++ki) { + + if (ip == -1) { + goto L250; + } + if (ki == *n) { + goto L150; + } + if (t[ki + 1 + ki * t_dim1] == 0.f) { + goto L150; + } + ip = 1; + +L150: + if (somev) { + if (! select[ki]) { + goto L250; + } + } + +/* Compute the KI-th eigenvalue (WR,WI). */ + + wr = t[ki + ki * t_dim1]; + wi = 0.f; + if (ip != 0) { + wi = sqrt((r__1 = t[ki + (ki + 1) * t_dim1], dabs(r__1))) * + sqrt((r__2 = t[ki + 1 + ki * t_dim1], dabs(r__2))); + } +/* Computing MAX */ + r__1 = ulp * (dabs(wr) + dabs(wi)); + smin = dmax(r__1,smlnum); + + if (ip == 0) { + +/* Real left eigenvector. */ + + work[ki + *n] = 1.f; + +/* Form right-hand side */ + + i__2 = *n; + for (k = ki + 1; k <= i__2; ++k) { + work[k + *n] = -t[ki + k * t_dim1]; +/* L160: */ + } + +/* + Solve the quasi-triangular system: + (T(KI+1:N,KI+1:N) - WR)'*X = SCALE*WORK +*/ + + vmax = 1.f; + vcrit = bignum; + + jnxt = ki + 1; + i__2 = *n; + for (j = ki + 1; j <= i__2; ++j) { + if (j < jnxt) { + goto L170; + } + j1 = j; + j2 = j; + jnxt = j + 1; + if (j < *n) { + if (t[j + 1 + j * t_dim1] != 0.f) { + j2 = j + 1; + jnxt = j + 2; + } + } + + if (j1 == j2) { + +/* + 1-by-1 diagonal block + + Scale if necessary to avoid overflow when forming + the right-hand side. +*/ + + if (work[j] > vcrit) { + rec = 1.f / vmax; + i__3 = *n - ki + 1; + sscal_(&i__3, &rec, &work[ki + *n], &c__1); + vmax = 1.f; + vcrit = bignum; + } + + i__3 = j - ki - 1; + work[j + *n] -= sdot_(&i__3, &t[ki + 1 + j * t_dim1], + &c__1, &work[ki + 1 + *n], &c__1); + +/* Solve (T(J,J)-WR)'*X = WORK */ + + slaln2_(&c_false, &c__1, &c__1, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &c_b29, x, &c__2, &scale, &xnorm, + &ierr); + +/* Scale if necessary */ + + if (scale != 1.f) { + i__3 = *n - ki + 1; + sscal_(&i__3, &scale, &work[ki + *n], &c__1); + } + work[j + *n] = x[0]; +/* Computing MAX */ + r__2 = (r__1 = work[j + *n], dabs(r__1)); + vmax = dmax(r__2,vmax); + vcrit = bignum / vmax; + + } else { + +/* + 2-by-2 diagonal block + + Scale if necessary to avoid overflow when forming + the right-hand side. + + Computing MAX +*/ + r__1 = work[j], r__2 = work[j + 1]; + beta = dmax(r__1,r__2); + if (beta > vcrit) { + rec = 1.f / vmax; + i__3 = *n - ki + 1; + sscal_(&i__3, &rec, &work[ki + *n], &c__1); + vmax = 1.f; + vcrit = bignum; + } + + i__3 = j - ki - 1; + work[j + *n] -= sdot_(&i__3, &t[ki + 1 + j * t_dim1], + &c__1, &work[ki + 1 + *n], &c__1); + + i__3 = j - ki - 1; + work[j + 1 + *n] -= sdot_(&i__3, &t[ki + 1 + (j + 1) * + t_dim1], &c__1, &work[ki + 1 + *n], &c__1); + +/* + Solve + [T(J,J)-WR T(J,J+1) ]'* X = SCALE*( WORK1 ) + [T(J+1,J) T(J+1,J+1)-WR] ( WORK2 ) +*/ + + slaln2_(&c_true, &c__2, &c__1, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &c_b29, x, &c__2, &scale, &xnorm, + &ierr); + +/* Scale if necessary */ + + if (scale != 1.f) { + i__3 = *n - ki + 1; + sscal_(&i__3, &scale, &work[ki + *n], &c__1); + } + work[j + *n] = x[0]; + work[j + 1 + *n] = x[1]; + +/* Computing MAX */ + r__3 = (r__1 = work[j + *n], dabs(r__1)), r__4 = ( + r__2 = work[j + 1 + *n], dabs(r__2)), r__3 = + max(r__3,r__4); + vmax = dmax(r__3,vmax); + vcrit = bignum / vmax; + + } +L170: + ; + } + +/* Copy the vector x or Q*x to VL and normalize. */ + + if (! over) { + i__2 = *n - ki + 1; + scopy_(&i__2, &work[ki + *n], &c__1, &vl[ki + is * + vl_dim1], &c__1); + + i__2 = *n - ki + 1; + ii = isamax_(&i__2, &vl[ki + is * vl_dim1], &c__1) + ki - + 1; + remax = 1.f / (r__1 = vl[ii + is * vl_dim1], dabs(r__1)); + i__2 = *n - ki + 1; + sscal_(&i__2, &remax, &vl[ki + is * vl_dim1], &c__1); + + i__2 = ki - 1; + for (k = 1; k <= i__2; ++k) { + vl[k + is * vl_dim1] = 0.f; +/* L180: */ + } + + } else { + + if (ki < *n) { + i__2 = *n - ki; + sgemv_("N", n, &i__2, &c_b15, &vl[(ki + 1) * vl_dim1 + + 1], ldvl, &work[ki + 1 + *n], &c__1, &work[ + ki + *n], &vl[ki * vl_dim1 + 1], &c__1); + } + + ii = isamax_(n, &vl[ki * vl_dim1 + 1], &c__1); + remax = 1.f / (r__1 = vl[ii + ki * vl_dim1], dabs(r__1)); + sscal_(n, &remax, &vl[ki * vl_dim1 + 1], &c__1); + + } + + } else { + +/* + Complex left eigenvector. + + Initial solve: + ((T(KI,KI) T(KI,KI+1) )' - (WR - I* WI))*X = 0. + ((T(KI+1,KI) T(KI+1,KI+1)) ) +*/ + + if ((r__1 = t[ki + (ki + 1) * t_dim1], dabs(r__1)) >= (r__2 = + t[ki + 1 + ki * t_dim1], dabs(r__2))) { + work[ki + *n] = wi / t[ki + (ki + 1) * t_dim1]; + work[ki + 1 + n2] = 1.f; + } else { + work[ki + *n] = 1.f; + work[ki + 1 + n2] = -wi / t[ki + 1 + ki * t_dim1]; + } + work[ki + 1 + *n] = 0.f; + work[ki + n2] = 0.f; + +/* Form right-hand side */ + + i__2 = *n; + for (k = ki + 2; k <= i__2; ++k) { + work[k + *n] = -work[ki + *n] * t[ki + k * t_dim1]; + work[k + n2] = -work[ki + 1 + n2] * t[ki + 1 + k * t_dim1] + ; +/* L190: */ + } + +/* + Solve complex quasi-triangular system: + ( T(KI+2,N:KI+2,N) - (WR-i*WI) )*X = WORK1+i*WORK2 +*/ + + vmax = 1.f; + vcrit = bignum; + + jnxt = ki + 2; + i__2 = *n; + for (j = ki + 2; j <= i__2; ++j) { + if (j < jnxt) { + goto L200; + } + j1 = j; + j2 = j; + jnxt = j + 1; + if (j < *n) { + if (t[j + 1 + j * t_dim1] != 0.f) { + j2 = j + 1; + jnxt = j + 2; + } + } + + if (j1 == j2) { + +/* + 1-by-1 diagonal block + + Scale if necessary to avoid overflow when + forming the right-hand side elements. +*/ + + if (work[j] > vcrit) { + rec = 1.f / vmax; + i__3 = *n - ki + 1; + sscal_(&i__3, &rec, &work[ki + *n], &c__1); + i__3 = *n - ki + 1; + sscal_(&i__3, &rec, &work[ki + n2], &c__1); + vmax = 1.f; + vcrit = bignum; + } + + i__3 = j - ki - 2; + work[j + *n] -= sdot_(&i__3, &t[ki + 2 + j * t_dim1], + &c__1, &work[ki + 2 + *n], &c__1); + i__3 = j - ki - 2; + work[j + n2] -= sdot_(&i__3, &t[ki + 2 + j * t_dim1], + &c__1, &work[ki + 2 + n2], &c__1); + +/* Solve (T(J,J)-(WR-i*WI))*(X11+i*X12)= WK+I*WK2 */ + + r__1 = -wi; + slaln2_(&c_false, &c__1, &c__2, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &r__1, x, &c__2, &scale, &xnorm, & + ierr); + +/* Scale if necessary */ + + if (scale != 1.f) { + i__3 = *n - ki + 1; + sscal_(&i__3, &scale, &work[ki + *n], &c__1); + i__3 = *n - ki + 1; + sscal_(&i__3, &scale, &work[ki + n2], &c__1); + } + work[j + *n] = x[0]; + work[j + n2] = x[2]; +/* Computing MAX */ + r__3 = (r__1 = work[j + *n], dabs(r__1)), r__4 = ( + r__2 = work[j + n2], dabs(r__2)), r__3 = max( + r__3,r__4); + vmax = dmax(r__3,vmax); + vcrit = bignum / vmax; + + } else { + +/* + 2-by-2 diagonal block + + Scale if necessary to avoid overflow when forming + the right-hand side elements. + + Computing MAX +*/ + r__1 = work[j], r__2 = work[j + 1]; + beta = dmax(r__1,r__2); + if (beta > vcrit) { + rec = 1.f / vmax; + i__3 = *n - ki + 1; + sscal_(&i__3, &rec, &work[ki + *n], &c__1); + i__3 = *n - ki + 1; + sscal_(&i__3, &rec, &work[ki + n2], &c__1); + vmax = 1.f; + vcrit = bignum; + } + + i__3 = j - ki - 2; + work[j + *n] -= sdot_(&i__3, &t[ki + 2 + j * t_dim1], + &c__1, &work[ki + 2 + *n], &c__1); + + i__3 = j - ki - 2; + work[j + n2] -= sdot_(&i__3, &t[ki + 2 + j * t_dim1], + &c__1, &work[ki + 2 + n2], &c__1); + + i__3 = j - ki - 2; + work[j + 1 + *n] -= sdot_(&i__3, &t[ki + 2 + (j + 1) * + t_dim1], &c__1, &work[ki + 2 + *n], &c__1); + + i__3 = j - ki - 2; + work[j + 1 + n2] -= sdot_(&i__3, &t[ki + 2 + (j + 1) * + t_dim1], &c__1, &work[ki + 2 + n2], &c__1); + +/* + Solve 2-by-2 complex linear equation + ([T(j,j) T(j,j+1) ]'-(wr-i*wi)*I)*X = SCALE*B + ([T(j+1,j) T(j+1,j+1)] ) +*/ + + r__1 = -wi; + slaln2_(&c_true, &c__2, &c__2, &smin, &c_b15, &t[j + + j * t_dim1], ldt, &c_b15, &c_b15, &work[j + * + n], n, &wr, &r__1, x, &c__2, &scale, &xnorm, & + ierr); + +/* Scale if necessary */ + + if (scale != 1.f) { + i__3 = *n - ki + 1; + sscal_(&i__3, &scale, &work[ki + *n], &c__1); + i__3 = *n - ki + 1; + sscal_(&i__3, &scale, &work[ki + n2], &c__1); + } + work[j + *n] = x[0]; + work[j + n2] = x[2]; + work[j + 1 + *n] = x[1]; + work[j + 1 + n2] = x[3]; +/* Computing MAX */ + r__1 = dabs(x[0]), r__2 = dabs(x[2]), r__1 = max(r__1, + r__2), r__2 = dabs(x[1]), r__1 = max(r__1, + r__2), r__2 = dabs(x[3]), r__1 = max(r__1, + r__2); + vmax = dmax(r__1,vmax); + vcrit = bignum / vmax; + + } +L200: + ; + } + +/* Copy the vector x or Q*x to VL and normalize. */ + + if (! over) { + i__2 = *n - ki + 1; + scopy_(&i__2, &work[ki + *n], &c__1, &vl[ki + is * + vl_dim1], &c__1); + i__2 = *n - ki + 1; + scopy_(&i__2, &work[ki + n2], &c__1, &vl[ki + (is + 1) * + vl_dim1], &c__1); + + emax = 0.f; + i__2 = *n; + for (k = ki; k <= i__2; ++k) { +/* Computing MAX */ + r__3 = emax, r__4 = (r__1 = vl[k + is * vl_dim1], + dabs(r__1)) + (r__2 = vl[k + (is + 1) * + vl_dim1], dabs(r__2)); + emax = dmax(r__3,r__4); +/* L220: */ + } + remax = 1.f / emax; + i__2 = *n - ki + 1; + sscal_(&i__2, &remax, &vl[ki + is * vl_dim1], &c__1); + i__2 = *n - ki + 1; + sscal_(&i__2, &remax, &vl[ki + (is + 1) * vl_dim1], &c__1) + ; + + i__2 = ki - 1; + for (k = 1; k <= i__2; ++k) { + vl[k + is * vl_dim1] = 0.f; + vl[k + (is + 1) * vl_dim1] = 0.f; +/* L230: */ + } + } else { + if (ki < *n - 1) { + i__2 = *n - ki - 1; + sgemv_("N", n, &i__2, &c_b15, &vl[(ki + 2) * vl_dim1 + + 1], ldvl, &work[ki + 2 + *n], &c__1, &work[ + ki + *n], &vl[ki * vl_dim1 + 1], &c__1); + i__2 = *n - ki - 1; + sgemv_("N", n, &i__2, &c_b15, &vl[(ki + 2) * vl_dim1 + + 1], ldvl, &work[ki + 2 + n2], &c__1, &work[ + ki + 1 + n2], &vl[(ki + 1) * vl_dim1 + 1], & + c__1); + } else { + sscal_(n, &work[ki + *n], &vl[ki * vl_dim1 + 1], & + c__1); + sscal_(n, &work[ki + 1 + n2], &vl[(ki + 1) * vl_dim1 + + 1], &c__1); + } + + emax = 0.f; + i__2 = *n; + for (k = 1; k <= i__2; ++k) { +/* Computing MAX */ + r__3 = emax, r__4 = (r__1 = vl[k + ki * vl_dim1], + dabs(r__1)) + (r__2 = vl[k + (ki + 1) * + vl_dim1], dabs(r__2)); + emax = dmax(r__3,r__4); +/* L240: */ + } + remax = 1.f / emax; + sscal_(n, &remax, &vl[ki * vl_dim1 + 1], &c__1); + sscal_(n, &remax, &vl[(ki + 1) * vl_dim1 + 1], &c__1); + + } + + } + + ++is; + if (ip != 0) { + ++is; + } +L250: + if (ip == -1) { + ip = 0; + } + if (ip == 1) { + ip = -1; + } + +/* L260: */ + } + + } + + return 0; + +/* End of STREVC */ + +} /* strevc_ */ + +/* Subroutine */ int strexc_(char *compq, integer *n, real *t, integer *ldt, + real *q, integer *ldq, integer *ifst, integer *ilst, real *work, + integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, t_dim1, t_offset, i__1; + + /* Local variables */ + static integer nbf, nbl, here; + extern logical lsame_(char *, char *); + static logical wantq; + extern /* Subroutine */ int xerbla_(char *, integer *), slaexc_( + logical *, integer *, real *, integer *, real *, integer *, + integer *, integer *, integer *, real *, integer *); + static integer nbnext; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + STREXC reorders the real Schur factorization of a real matrix + A = Q*T*Q**T, so that the diagonal block of T with row index IFST is + moved to row ILST. + + The real Schur form T is reordered by an orthogonal similarity + transformation Z**T*T*Z, and optionally the matrix Q of Schur vectors + is updated by postmultiplying it with Z. + + T must be in Schur canonical form (as returned by SHSEQR), that is, + block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each + 2-by-2 diagonal block has its diagonal elements equal and its + off-diagonal elements of opposite sign. + + Arguments + ========= + + COMPQ (input) CHARACTER*1 + = 'V': update the matrix Q of Schur vectors; + = 'N': do not update Q. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input/output) REAL array, dimension (LDT,N) + On entry, the upper quasi-triangular matrix T, in Schur + Schur canonical form. + On exit, the reordered upper quasi-triangular matrix, again + in Schur canonical form. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + Q (input/output) REAL array, dimension (LDQ,N) + On entry, if COMPQ = 'V', the matrix Q of Schur vectors. + On exit, if COMPQ = 'V', Q has been postmultiplied by the + orthogonal transformation matrix Z which reorders T. + If COMPQ = 'N', Q is not referenced. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + IFST (input/output) INTEGER + ILST (input/output) INTEGER + Specify the reordering of the diagonal blocks of T. + The block with row index IFST is moved to row ILST, by a + sequence of transpositions between adjacent blocks. + On exit, if IFST pointed on entry to the second row of a + 2-by-2 block, it is changed to point to the first row; ILST + always points to the first row of the block in its final + position (which may differ from its input value by +1 or -1). + 1 <= IFST <= N; 1 <= ILST <= N. + + WORK (workspace) REAL array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + = 1: two adjacent blocks were too close to swap (the problem + is very ill-conditioned); T may have been partially + reordered, and ILST points to the first row of the + current position of the block being moved. + + ===================================================================== + + + Decode and test the input arguments. +*/ + + /* Parameter adjustments */ + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --work; + + /* Function Body */ + *info = 0; + wantq = lsame_(compq, "V"); + if (! wantq && ! lsame_(compq, "N")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldt < max(1,*n)) { + *info = -4; + } else if (*ldq < 1 || wantq && *ldq < max(1,*n)) { + *info = -6; + } else if (*ifst < 1 || *ifst > *n) { + *info = -7; + } else if (*ilst < 1 || *ilst > *n) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("STREXC", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 1) { + return 0; + } + +/* + Determine the first row of specified block + and find out it is 1 by 1 or 2 by 2. +*/ + + if (*ifst > 1) { + if (t[*ifst + (*ifst - 1) * t_dim1] != 0.f) { + --(*ifst); + } + } + nbf = 1; + if (*ifst < *n) { + if (t[*ifst + 1 + *ifst * t_dim1] != 0.f) { + nbf = 2; + } + } + +/* + Determine the first row of the final block + and find out it is 1 by 1 or 2 by 2. +*/ + + if (*ilst > 1) { + if (t[*ilst + (*ilst - 1) * t_dim1] != 0.f) { + --(*ilst); + } + } + nbl = 1; + if (*ilst < *n) { + if (t[*ilst + 1 + *ilst * t_dim1] != 0.f) { + nbl = 2; + } + } + + if (*ifst == *ilst) { + return 0; + } + + if (*ifst < *ilst) { + +/* Update ILST */ + + if (nbf == 2 && nbl == 1) { + --(*ilst); + } + if (nbf == 1 && nbl == 2) { + ++(*ilst); + } + + here = *ifst; + +L10: + +/* Swap block with next one below */ + + if (nbf == 1 || nbf == 2) { + +/* Current block either 1 by 1 or 2 by 2 */ + + nbnext = 1; + if (here + nbf + 1 <= *n) { + if (t[here + nbf + 1 + (here + nbf) * t_dim1] != 0.f) { + nbnext = 2; + } + } + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &here, & + nbf, &nbnext, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + here += nbnext; + +/* Test if 2 by 2 block breaks into two 1 by 1 blocks */ + + if (nbf == 2) { + if (t[here + 1 + here * t_dim1] == 0.f) { + nbf = 3; + } + } + + } else { + +/* + Current block consists of two 1 by 1 blocks each of which + must be swapped individually +*/ + + nbnext = 1; + if (here + 3 <= *n) { + if (t[here + 3 + (here + 2) * t_dim1] != 0.f) { + nbnext = 2; + } + } + i__1 = here + 1; + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, & + c__1, &nbnext, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + if (nbnext == 1) { + +/* Swap two 1 by 1 blocks, no problems possible */ + + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &c__1, &nbnext, &work[1], info); + ++here; + } else { + +/* Recompute NBNEXT in case 2 by 2 split */ + + if (t[here + 2 + (here + 1) * t_dim1] == 0.f) { + nbnext = 1; + } + if (nbnext == 2) { + +/* 2 by 2 Block did not split */ + + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &c__1, &nbnext, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + here += 2; + } else { + +/* 2 by 2 Block did split */ + + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &c__1, &c__1, &work[1], info); + i__1 = here + 1; + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + i__1, &c__1, &c__1, &work[1], info); + here += 2; + } + } + } + if (here < *ilst) { + goto L10; + } + + } else { + + here = *ifst; +L20: + +/* Swap block with next one above */ + + if (nbf == 1 || nbf == 2) { + +/* Current block either 1 by 1 or 2 by 2 */ + + nbnext = 1; + if (here >= 3) { + if (t[here - 1 + (here - 2) * t_dim1] != 0.f) { + nbnext = 2; + } + } + i__1 = here - nbnext; + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, & + nbnext, &nbf, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + here -= nbnext; + +/* Test if 2 by 2 block breaks into two 1 by 1 blocks */ + + if (nbf == 2) { + if (t[here + 1 + here * t_dim1] == 0.f) { + nbf = 3; + } + } + + } else { + +/* + Current block consists of two 1 by 1 blocks each of which + must be swapped individually +*/ + + nbnext = 1; + if (here >= 3) { + if (t[here - 1 + (here - 2) * t_dim1] != 0.f) { + nbnext = 2; + } + } + i__1 = here - nbnext; + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, &i__1, & + nbnext, &c__1, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + if (nbnext == 1) { + +/* Swap two 1 by 1 blocks, no problems possible */ + + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &nbnext, &c__1, &work[1], info); + --here; + } else { + +/* Recompute NBNEXT in case 2 by 2 split */ + + if (t[here + (here - 1) * t_dim1] == 0.f) { + nbnext = 1; + } + if (nbnext == 2) { + +/* 2 by 2 Block did not split */ + + i__1 = here - 1; + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + i__1, &c__2, &c__1, &work[1], info); + if (*info != 0) { + *ilst = here; + return 0; + } + here += -2; + } else { + +/* 2 by 2 Block did split */ + + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + here, &c__1, &c__1, &work[1], info); + i__1 = here - 1; + slaexc_(&wantq, n, &t[t_offset], ldt, &q[q_offset], ldq, & + i__1, &c__1, &c__1, &work[1], info); + here += -2; + } + } + } + if (here > *ilst) { + goto L20; + } + } + *ilst = here; + + return 0; + +/* End of STREXC */ + +} /* strexc_ */ + +/* Subroutine */ int strti2_(char *uplo, char *diag, integer *n, real *a, + integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer j; + static real ajj; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *); + static logical upper; + extern /* Subroutine */ int strmv_(char *, char *, char *, integer *, + real *, integer *, real *, integer *), + xerbla_(char *, integer *); + static logical nounit; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + STRTI2 computes the inverse of a real upper or lower triangular + matrix. + + This is the Level 2 BLAS version of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the matrix A is upper or lower triangular. + = 'U': Upper triangular + = 'L': Lower triangular + + DIAG (input) CHARACTER*1 + Specifies whether or not the matrix A is unit triangular. + = 'N': Non-unit triangular + = 'U': Unit triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the triangular matrix A. If UPLO = 'U', the + leading n by n upper triangular part of the array A contains + the upper triangular matrix, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of the array A contains + the lower triangular matrix, and the strictly upper + triangular part of A is not referenced. If DIAG = 'U', the + diagonal elements of A are also not referenced and are + assumed to be 1. + + On exit, the (triangular) inverse of the original matrix, in + the same storage format. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + nounit = lsame_(diag, "N"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("STRTI2", &i__1); + return 0; + } + + if (upper) { + +/* Compute inverse of upper triangular matrix. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (nounit) { + a[j + j * a_dim1] = 1.f / a[j + j * a_dim1]; + ajj = -a[j + j * a_dim1]; + } else { + ajj = -1.f; + } + +/* Compute elements 1:j-1 of j-th column. */ + + i__2 = j - 1; + strmv_("Upper", "No transpose", diag, &i__2, &a[a_offset], lda, & + a[j * a_dim1 + 1], &c__1); + i__2 = j - 1; + sscal_(&i__2, &ajj, &a[j * a_dim1 + 1], &c__1); +/* L10: */ + } + } else { + +/* Compute inverse of lower triangular matrix. */ + + for (j = *n; j >= 1; --j) { + if (nounit) { + a[j + j * a_dim1] = 1.f / a[j + j * a_dim1]; + ajj = -a[j + j * a_dim1]; + } else { + ajj = -1.f; + } + if (j < *n) { + +/* Compute elements j+1:n of j-th column. */ + + i__1 = *n - j; + strmv_("Lower", "No transpose", diag, &i__1, &a[j + 1 + (j + + 1) * a_dim1], lda, &a[j + 1 + j * a_dim1], &c__1); + i__1 = *n - j; + sscal_(&i__1, &ajj, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + + return 0; + +/* End of STRTI2 */ + +} /* strti2_ */ + +/* Subroutine */ int strtri_(char *uplo, char *diag, integer *n, real *a, + integer *lda, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, i__1, i__2[2], i__3, i__4, i__5; + char ch__1[2]; + + /* Local variables */ + static integer j, jb, nb, nn; + extern logical lsame_(char *, char *); + static logical upper; + extern /* Subroutine */ int strmm_(char *, char *, char *, char *, + integer *, integer *, real *, real *, integer *, real *, integer * + ), strsm_(char *, char *, char *, + char *, integer *, integer *, real *, real *, integer *, real *, + integer *), strti2_(char *, char * + , integer *, real *, integer *, integer *), + xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical nounit; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + STRTRI computes the inverse of a real upper or lower triangular + matrix A. + + This is the Level 3 BLAS version of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': A is upper triangular; + = 'L': A is lower triangular. + + DIAG (input) CHARACTER*1 + = 'N': A is non-unit triangular; + = 'U': A is unit triangular. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the triangular matrix A. If UPLO = 'U', the + leading N-by-N upper triangular part of the array A contains + the upper triangular matrix, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of the array A contains + the lower triangular matrix, and the strictly upper + triangular part of A is not referenced. If DIAG = 'U', the + diagonal elements of A are also not referenced and are + assumed to be 1. + On exit, the (triangular) inverse of the original matrix, in + the same storage format. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, A(i,i) is exactly zero. The triangular + matrix is singular and its inverse can not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + nounit = lsame_(diag, "N"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("STRTRI", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Check for singularity if non-unit. */ + + if (nounit) { + i__1 = *n; + for (*info = 1; *info <= i__1; ++(*info)) { + if (a[*info + *info * a_dim1] == 0.f) { + return 0; + } +/* L10: */ + } + *info = 0; + } + +/* + Determine the block size for this environment. + + Writing concatenation +*/ + i__2[0] = 1, a__1[0] = uplo; + i__2[1] = 1, a__1[1] = diag; + s_cat(ch__1, a__1, i__2, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "STRTRI", ch__1, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)2); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code */ + + strti2_(uplo, diag, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code */ + + if (upper) { + +/* Compute inverse of upper triangular matrix */ + + i__1 = *n; + i__3 = nb; + for (j = 1; i__3 < 0 ? j >= i__1 : j <= i__1; j += i__3) { +/* Computing MIN */ + i__4 = nb, i__5 = *n - j + 1; + jb = min(i__4,i__5); + +/* Compute rows 1:j-1 of current block column */ + + i__4 = j - 1; + strmm_("Left", "Upper", "No transpose", diag, &i__4, &jb, & + c_b15, &a[a_offset], lda, &a[j * a_dim1 + 1], lda); + i__4 = j - 1; + strsm_("Right", "Upper", "No transpose", diag, &i__4, &jb, & + c_b151, &a[j + j * a_dim1], lda, &a[j * a_dim1 + 1], + lda); + +/* Compute inverse of current diagonal block */ + + strti2_("Upper", diag, &jb, &a[j + j * a_dim1], lda, info); +/* L20: */ + } + } else { + +/* Compute inverse of lower triangular matrix */ + + nn = (*n - 1) / nb * nb + 1; + i__3 = -nb; + for (j = nn; i__3 < 0 ? j >= 1 : j <= 1; j += i__3) { +/* Computing MIN */ + i__1 = nb, i__4 = *n - j + 1; + jb = min(i__1,i__4); + if (j + jb <= *n) { + +/* Compute rows j+jb:n of current block column */ + + i__1 = *n - j - jb + 1; + strmm_("Left", "Lower", "No transpose", diag, &i__1, &jb, + &c_b15, &a[j + jb + (j + jb) * a_dim1], lda, &a[j + + jb + j * a_dim1], lda); + i__1 = *n - j - jb + 1; + strsm_("Right", "Lower", "No transpose", diag, &i__1, &jb, + &c_b151, &a[j + j * a_dim1], lda, &a[j + jb + j * + a_dim1], lda); + } + +/* Compute inverse of current diagonal block */ + + strti2_("Lower", diag, &jb, &a[j + j * a_dim1], lda, info); +/* L30: */ + } + } + } + + return 0; + +/* End of STRTRI */ + +} /* strtri_ */ + diff --git a/numpy/linalg/lapack_lite/f2c_z_lapack.c b/numpy/linalg/lapack_lite/f2c_z_lapack.c new file mode 100644 index 0000000..0f11f2e --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c_z_lapack.c @@ -0,0 +1,29996 @@ +/* +NOTE: This is generated code. Look in Misc/lapack_lite for information on + remaking this file. +*/ +#include "f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal dlamch_(char *); +#define EPSILON dlamch_("Epsilon") +#define SAFEMINIMUM dlamch_("Safe minimum") +#define PRECISION dlamch_("Precision") +#define BASE dlamch_("Base") +#endif + +extern doublereal dlapy2_(doublereal *x, doublereal *y); + +/* +f2c knows the exact rules for precedence, and so omits parentheses where not +strictly necessary. Since this is generated code, we don't really care if +it's readable, and we know what is written is correct. So don't warn about +them. +*/ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wparentheses" +#endif + + +/* Table of constant values */ + +static integer c__1 = 1; +static doublecomplex c_b56 = {0.,0.}; +static doublecomplex c_b57 = {1.,0.}; +static integer c_n1 = -1; +static integer c__3 = 3; +static integer c__2 = 2; +static integer c__0 = 0; +static integer c__65 = 65; +static integer c__9 = 9; +static integer c__6 = 6; +static doublereal c_b328 = 0.; +static doublereal c_b1034 = 1.; +static integer c__12 = 12; +static integer c__49 = 49; +static doublereal c_b1276 = -1.; +static integer c__13 = 13; +static integer c__15 = 15; +static integer c__14 = 14; +static integer c__16 = 16; +static logical c_false = FALSE_; +static logical c_true = TRUE_; +static doublereal c_b2435 = .5; + +/* Subroutine */ int zgebak_(char *job, char *side, integer *n, integer *ilo, + integer *ihi, doublereal *scale, integer *m, doublecomplex *v, + integer *ldv, integer *info) +{ + /* System generated locals */ + integer v_dim1, v_offset, i__1; + + /* Local variables */ + static integer i__, k; + static doublereal s; + static integer ii; + extern logical lsame_(char *, char *); + static logical leftv; + extern /* Subroutine */ int zswap_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), xerbla_(char *, integer *), + zdscal_(integer *, doublereal *, doublecomplex *, integer *); + static logical rightv; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGEBAK forms the right or left eigenvectors of a complex general + matrix by backward transformation on the computed eigenvectors of the + balanced matrix output by ZGEBAL. + + Arguments + ========= + + JOB (input) CHARACTER*1 + Specifies the type of backward transformation required: + = 'N', do nothing, return immediately; + = 'P', do backward transformation for permutation only; + = 'S', do backward transformation for scaling only; + = 'B', do backward transformations for both permutation and + scaling. + JOB must be the same as the argument JOB supplied to ZGEBAL. + + SIDE (input) CHARACTER*1 + = 'R': V contains right eigenvectors; + = 'L': V contains left eigenvectors. + + N (input) INTEGER + The number of rows of the matrix V. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + The integers ILO and IHI determined by ZGEBAL. + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + SCALE (input) DOUBLE PRECISION array, dimension (N) + Details of the permutation and scaling factors, as returned + by ZGEBAL. + + M (input) INTEGER + The number of columns of the matrix V. M >= 0. + + V (input/output) COMPLEX*16 array, dimension (LDV,M) + On entry, the matrix of right or left eigenvectors to be + transformed, as returned by ZHSEIN or ZTREVC. + On exit, V is overwritten by the transformed eigenvectors. + + LDV (input) INTEGER + The leading dimension of the array V. LDV >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Decode and Test the input parameters +*/ + + /* Parameter adjustments */ + --scale; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + + /* Function Body */ + rightv = lsame_(side, "R"); + leftv = lsame_(side, "L"); + + *info = 0; + if (! lsame_(job, "N") && ! lsame_(job, "P") && ! lsame_(job, "S") + && ! lsame_(job, "B")) { + *info = -1; + } else if (! rightv && ! leftv) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -4; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -5; + } else if (*m < 0) { + *info = -7; + } else if (*ldv < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGEBAK", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*m == 0) { + return 0; + } + if (lsame_(job, "N")) { + return 0; + } + + if (*ilo == *ihi) { + goto L30; + } + +/* Backward balance */ + + if (lsame_(job, "S") || lsame_(job, "B")) { + + if (rightv) { + i__1 = *ihi; + for (i__ = *ilo; i__ <= i__1; ++i__) { + s = scale[i__]; + zdscal_(m, &s, &v[i__ + v_dim1], ldv); +/* L10: */ + } + } + + if (leftv) { + i__1 = *ihi; + for (i__ = *ilo; i__ <= i__1; ++i__) { + s = 1. / scale[i__]; + zdscal_(m, &s, &v[i__ + v_dim1], ldv); +/* L20: */ + } + } + + } + +/* + Backward permutation + + For I = ILO-1 step -1 until 1, + IHI+1 step 1 until N do -- +*/ + +L30: + if (lsame_(job, "P") || lsame_(job, "B")) { + if (rightv) { + i__1 = *n; + for (ii = 1; ii <= i__1; ++ii) { + i__ = ii; + if (i__ >= *ilo && i__ <= *ihi) { + goto L40; + } + if (i__ < *ilo) { + i__ = *ilo - ii; + } + k = (integer) scale[i__]; + if (k == i__) { + goto L40; + } + zswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv); +L40: + ; + } + } + + if (leftv) { + i__1 = *n; + for (ii = 1; ii <= i__1; ++ii) { + i__ = ii; + if (i__ >= *ilo && i__ <= *ihi) { + goto L50; + } + if (i__ < *ilo) { + i__ = *ilo - ii; + } + k = (integer) scale[i__]; + if (k == i__) { + goto L50; + } + zswap_(m, &v[i__ + v_dim1], ldv, &v[k + v_dim1], ldv); +L50: + ; + } + } + } + + return 0; + +/* End of ZGEBAK */ + +} /* zgebak_ */ + +/* Subroutine */ int zgebal_(char *job, integer *n, doublecomplex *a, integer + *lda, integer *ilo, integer *ihi, doublereal *scale, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal c__, f, g; + static integer i__, j, k, l, m; + static doublereal r__, s, ca, ra; + static integer ica, ira, iexc; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zswap_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static doublereal sfmin1, sfmin2, sfmax1, sfmax2; + + extern logical disnan_(doublereal *); + extern /* Subroutine */ int xerbla_(char *, integer *), zdscal_( + integer *, doublereal *, doublecomplex *, integer *); + extern integer izamax_(integer *, doublecomplex *, integer *); + static logical noconv; + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + ZGEBAL balances a general complex matrix A. This involves, first, + permuting A by a similarity transformation to isolate eigenvalues + in the first 1 to ILO-1 and last IHI+1 to N elements on the + diagonal; and second, applying a diagonal similarity transformation + to rows and columns ILO to IHI to make the rows and columns as + close in norm as possible. Both steps are optional. + + Balancing may reduce the 1-norm of the matrix, and improve the + accuracy of the computed eigenvalues and/or eigenvectors. + + Arguments + ========= + + JOB (input) CHARACTER*1 + Specifies the operations to be performed on A: + = 'N': none: simply set ILO = 1, IHI = N, SCALE(I) = 1.0 + for i = 1,...,N; + = 'P': permute only; + = 'S': scale only; + = 'B': both permute and scale. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the input matrix A. + On exit, A is overwritten by the balanced matrix. + If JOB = 'N', A is not referenced. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + ILO (output) INTEGER + IHI (output) INTEGER + ILO and IHI are set to integers such that on exit + A(i,j) = 0 if i > j and j = 1,...,ILO-1 or I = IHI+1,...,N. + If JOB = 'N' or 'S', ILO = 1 and IHI = N. + + SCALE (output) DOUBLE PRECISION array, dimension (N) + Details of the permutations and scaling factors applied to + A. If P(j) is the index of the row and column interchanged + with row and column j and D(j) is the scaling factor + applied to row and column j, then + SCALE(j) = P(j) for j = 1,...,ILO-1 + = D(j) for j = ILO,...,IHI + = P(j) for j = IHI+1,...,N. + The order in which the interchanges are made is N to IHI+1, + then 1 to ILO-1. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The permutations consist of row and column interchanges which put + the matrix in the form + + ( T1 X Y ) + P A P = ( 0 B Z ) + ( 0 0 T2 ) + + where T1 and T2 are upper triangular matrices whose eigenvalues lie + along the diagonal. The column indices ILO and IHI mark the starting + and ending columns of the submatrix B. Balancing consists of applying + a diagonal similarity transformation inv(D) * B * D to make the + 1-norms of each row of B and its corresponding column nearly equal. + The output matrix is + + ( T1 X*D Y ) + ( 0 inv(D)*B*D inv(D)*Z ). + ( 0 0 T2 ) + + Information about the permutations P and the diagonal matrix D is + returned in the vector SCALE. + + This subroutine is based on the EISPACK routine CBAL. + + Modified by Tzu-Yi Chen, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --scale; + + /* Function Body */ + *info = 0; + if (! lsame_(job, "N") && ! lsame_(job, "P") && ! lsame_(job, "S") + && ! lsame_(job, "B")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGEBAL", &i__1); + return 0; + } + + k = 1; + l = *n; + + if (*n == 0) { + goto L210; + } + + if (lsame_(job, "N")) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + scale[i__] = 1.; +/* L10: */ + } + goto L210; + } + + if (lsame_(job, "S")) { + goto L120; + } + +/* Permutation to isolate eigenvalues if possible */ + + goto L50; + +/* Row and column exchange. */ + +L20: + scale[m] = (doublereal) j; + if (j == m) { + goto L30; + } + + zswap_(&l, &a[j * a_dim1 + 1], &c__1, &a[m * a_dim1 + 1], &c__1); + i__1 = *n - k + 1; + zswap_(&i__1, &a[j + k * a_dim1], lda, &a[m + k * a_dim1], lda); + +L30: + switch (iexc) { + case 1: goto L40; + case 2: goto L80; + } + +/* Search for rows isolating an eigenvalue and push them down. */ + +L40: + if (l == 1) { + goto L210; + } + --l; + +L50: + for (j = l; j >= 1; --j) { + + i__1 = l; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__ == j) { + goto L60; + } + i__2 = j + i__ * a_dim1; + if (a[i__2].r != 0. || d_imag(&a[j + i__ * a_dim1]) != 0.) { + goto L70; + } +L60: + ; + } + + m = l; + iexc = 1; + goto L20; +L70: + ; + } + + goto L90; + +/* Search for columns isolating an eigenvalue and push them left. */ + +L80: + ++k; + +L90: + i__1 = l; + for (j = k; j <= i__1; ++j) { + + i__2 = l; + for (i__ = k; i__ <= i__2; ++i__) { + if (i__ == j) { + goto L100; + } + i__3 = i__ + j * a_dim1; + if (a[i__3].r != 0. || d_imag(&a[i__ + j * a_dim1]) != 0.) { + goto L110; + } +L100: + ; + } + + m = k; + iexc = 2; + goto L20; +L110: + ; + } + +L120: + i__1 = l; + for (i__ = k; i__ <= i__1; ++i__) { + scale[i__] = 1.; +/* L130: */ + } + + if (lsame_(job, "P")) { + goto L210; + } + +/* + Balance the submatrix in rows K to L. + + Iterative loop for norm reduction +*/ + + sfmin1 = SAFEMINIMUM / PRECISION; + sfmax1 = 1. / sfmin1; + sfmin2 = sfmin1 * 2.; + sfmax2 = 1. / sfmin2; +L140: + noconv = FALSE_; + + i__1 = l; + for (i__ = k; i__ <= i__1; ++i__) { + c__ = 0.; + r__ = 0.; + + i__2 = l; + for (j = k; j <= i__2; ++j) { + if (j == i__) { + goto L150; + } + i__3 = j + i__ * a_dim1; + c__ += (d__1 = a[i__3].r, abs(d__1)) + (d__2 = d_imag(&a[j + i__ * + a_dim1]), abs(d__2)); + i__3 = i__ + j * a_dim1; + r__ += (d__1 = a[i__3].r, abs(d__1)) + (d__2 = d_imag(&a[i__ + j * + a_dim1]), abs(d__2)); +L150: + ; + } + ica = izamax_(&l, &a[i__ * a_dim1 + 1], &c__1); + ca = z_abs(&a[ica + i__ * a_dim1]); + i__2 = *n - k + 1; + ira = izamax_(&i__2, &a[i__ + k * a_dim1], lda); + ra = z_abs(&a[i__ + (ira + k - 1) * a_dim1]); + +/* Guard against zero C or R due to underflow. */ + + if (c__ == 0. || r__ == 0.) { + goto L200; + } + g = r__ / 2.; + f = 1.; + s = c__ + r__; +L160: +/* Computing MAX */ + d__1 = max(f,c__); +/* Computing MIN */ + d__2 = min(r__,g); + if (c__ >= g || max(d__1,ca) >= sfmax2 || min(d__2,ra) <= sfmin2) { + goto L170; + } + d__1 = c__ + f + ca + r__ + g + ra; + if (disnan_(&d__1)) { + +/* Exit if NaN to avoid infinite loop */ + + *info = -3; + i__2 = -(*info); + xerbla_("ZGEBAL", &i__2); + return 0; + } + f *= 2.; + c__ *= 2.; + ca *= 2.; + r__ /= 2.; + g /= 2.; + ra /= 2.; + goto L160; + +L170: + g = c__ / 2.; +L180: +/* Computing MIN */ + d__1 = min(f,c__), d__1 = min(d__1,g); + if (g < r__ || max(r__,ra) >= sfmax2 || min(d__1,ca) <= sfmin2) { + goto L190; + } + f /= 2.; + c__ /= 2.; + g /= 2.; + ca /= 2.; + r__ *= 2.; + ra *= 2.; + goto L180; + +/* Now balance. */ + +L190: + if (c__ + r__ >= s * .95) { + goto L200; + } + if (f < 1. && scale[i__] < 1.) { + if (f * scale[i__] <= sfmin1) { + goto L200; + } + } + if (f > 1. && scale[i__] > 1.) { + if (scale[i__] >= sfmax1 / f) { + goto L200; + } + } + g = 1. / f; + scale[i__] *= f; + noconv = TRUE_; + + i__2 = *n - k + 1; + zdscal_(&i__2, &g, &a[i__ + k * a_dim1], lda); + zdscal_(&l, &f, &a[i__ * a_dim1 + 1], &c__1); + +L200: + ; + } + + if (noconv) { + goto L140; + } + +L210: + *ilo = k; + *ihi = l; + + return 0; + +/* End of ZGEBAL */ + +} /* zgebal_ */ + +/* Subroutine */ int zgebd2_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *d__, doublereal *e, doublecomplex *tauq, + doublecomplex *taup, doublecomplex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__; + static doublecomplex alpha; + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *), zlarfg_(integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), zlacgv_(integer *, doublecomplex *, + integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGEBD2 reduces a complex general m by n matrix A to upper or lower + real bidiagonal form B by a unitary transformation: Q' * A * P = B. + + If m >= n, B is upper bidiagonal; if m < n, B is lower bidiagonal. + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. M >= 0. + + N (input) INTEGER + The number of columns in the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the m by n general matrix to be reduced. + On exit, + if m >= n, the diagonal and the first superdiagonal are + overwritten with the upper bidiagonal matrix B; the + elements below the diagonal, with the array TAUQ, represent + the unitary matrix Q as a product of elementary + reflectors, and the elements above the first superdiagonal, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors; + if m < n, the diagonal and the first subdiagonal are + overwritten with the lower bidiagonal matrix B; the + elements below the first subdiagonal, with the array TAUQ, + represent the unitary matrix Q as a product of + elementary reflectors, and the elements above the diagonal, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) DOUBLE PRECISION array, dimension (min(M,N)) + The diagonal elements of the bidiagonal matrix B: + D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (min(M,N)-1) + The off-diagonal elements of the bidiagonal matrix B: + if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1; + if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1. + + TAUQ (output) COMPLEX*16 array dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the unitary matrix Q. See Further Details. + + TAUP (output) COMPLEX*16 array, dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the unitary matrix P. See Further Details. + + WORK (workspace) COMPLEX*16 array, dimension (max(M,N)) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + If m >= n, + + Q = H(1) H(2) . . . H(n) and P = G(1) G(2) . . . G(n-1) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, and v and u are complex + vectors; v(1:i-1) = 0, v(i) = 1, and v(i+1:m) is stored on exit in + A(i+1:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+2:n) is stored on exit in + A(i,i+2:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, + + Q = H(1) H(2) . . . H(m-1) and P = G(1) G(2) . . . G(m) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, v and u are complex vectors; + v(1:i) = 0, v(i+1) = 1, and v(i+2:m) is stored on exit in A(i+2:m,i); + u(1:i-1) = 0, u(i) = 1, and u(i+1:n) is stored on exit in A(i,i+1:n); + tauq is stored in TAUQ(i) and taup in TAUP(i). + + The contents of A on exit are illustrated by the following examples: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) + ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) + ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) + ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) + ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) + ( v1 v2 v3 v4 v5 ) + + where d and e denote diagonal and off-diagonal elements of B, vi + denotes an element of the vector defining H(i), and ui an element of + the vector defining G(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info < 0) { + i__1 = -(*info); + xerbla_("ZGEBD2", &i__1); + return 0; + } + + if (*m >= *n) { + +/* Reduce to upper bidiagonal form */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ + + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + zlarfg_(&i__2, &alpha, &a[min(i__3,*m) + i__ * a_dim1], &c__1, & + tauq[i__]); + i__2 = i__; + d__[i__2] = alpha.r; + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Apply H(i)' to A(i:m,i+1:n) from the left */ + + if (i__ < *n) { + i__2 = *m - i__ + 1; + i__3 = *n - i__; + d_cnjg(&z__1, &tauq[i__]); + zlarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, & + z__1, &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + } + i__2 = i__ + i__ * a_dim1; + i__3 = i__; + a[i__2].r = d__[i__3], a[i__2].i = 0.; + + if (i__ < *n) { + +/* + Generate elementary reflector G(i) to annihilate + A(i,i+2:n) +*/ + + i__2 = *n - i__; + zlacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ + (i__ + 1) * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + zlarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, & + taup[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + (i__ + 1) * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Apply G(i) to A(i+1:m,i+1:n) from the right */ + + i__2 = *m - i__; + i__3 = *n - i__; + zlarf_("Right", &i__2, &i__3, &a[i__ + (i__ + 1) * a_dim1], + lda, &taup[i__], &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &work[1]); + i__2 = *n - i__; + zlacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ + (i__ + 1) * a_dim1; + i__3 = i__; + a[i__2].r = e[i__3], a[i__2].i = 0.; + } else { + i__2 = i__; + taup[i__2].r = 0., taup[i__2].i = 0.; + } +/* L10: */ + } + } else { + +/* Reduce to lower bidiagonal form */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector G(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; + zlacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + zlarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, & + taup[i__]); + i__2 = i__; + d__[i__2] = alpha.r; + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Apply G(i) to A(i+1:m,i:n) from the right */ + + if (i__ < *m) { + i__2 = *m - i__; + i__3 = *n - i__ + 1; + zlarf_("Right", &i__2, &i__3, &a[i__ + i__ * a_dim1], lda, & + taup[i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + i__2 = *n - i__ + 1; + zlacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + i__3 = i__; + a[i__2].r = d__[i__3], a[i__2].i = 0.; + + if (i__ < *m) { + +/* + Generate elementary reflector H(i) to annihilate + A(i+2:m,i) +*/ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *m - i__; +/* Computing MIN */ + i__3 = i__ + 2; + zlarfg_(&i__2, &alpha, &a[min(i__3,*m) + i__ * a_dim1], &c__1, + &tauq[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Apply H(i)' to A(i+1:m,i+1:n) from the left */ + + i__2 = *m - i__; + i__3 = *n - i__; + d_cnjg(&z__1, &tauq[i__]); + zlarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], & + c__1, &z__1, &a[i__ + 1 + (i__ + 1) * a_dim1], lda, & + work[1]); + i__2 = i__ + 1 + i__ * a_dim1; + i__3 = i__; + a[i__2].r = e[i__3], a[i__2].i = 0.; + } else { + i__2 = i__; + tauq[i__2].r = 0., tauq[i__2].i = 0.; + } +/* L20: */ + } + } + return 0; + +/* End of ZGEBD2 */ + +} /* zgebd2_ */ + +/* Subroutine */ int zgebrd_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *d__, doublereal *e, doublecomplex *tauq, + doublecomplex *taup, doublecomplex *work, integer *lwork, integer * + info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, nb, nx; + static doublereal ws; + static integer nbmin, iinfo, minmn; + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), zgebd2_(integer *, integer *, + doublecomplex *, integer *, doublereal *, doublereal *, + doublecomplex *, doublecomplex *, doublecomplex *, integer *), + xerbla_(char *, integer *), zlabrd_(integer *, integer *, + integer *, doublecomplex *, integer *, doublereal *, doublereal *, + doublecomplex *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer ldwrkx, ldwrky, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGEBRD reduces a general complex M-by-N matrix A to upper or lower + bidiagonal form B by a unitary transformation: Q**H * A * P = B. + + If m >= n, B is upper bidiagonal; if m < n, B is lower bidiagonal. + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. M >= 0. + + N (input) INTEGER + The number of columns in the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the M-by-N general matrix to be reduced. + On exit, + if m >= n, the diagonal and the first superdiagonal are + overwritten with the upper bidiagonal matrix B; the + elements below the diagonal, with the array TAUQ, represent + the unitary matrix Q as a product of elementary + reflectors, and the elements above the first superdiagonal, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors; + if m < n, the diagonal and the first subdiagonal are + overwritten with the lower bidiagonal matrix B; the + elements below the first subdiagonal, with the array TAUQ, + represent the unitary matrix Q as a product of + elementary reflectors, and the elements above the diagonal, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) DOUBLE PRECISION array, dimension (min(M,N)) + The diagonal elements of the bidiagonal matrix B: + D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (min(M,N)-1) + The off-diagonal elements of the bidiagonal matrix B: + if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1; + if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1. + + TAUQ (output) COMPLEX*16 array dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the unitary matrix Q. See Further Details. + + TAUP (output) COMPLEX*16 array, dimension (min(M,N)) + The scalar factors of the elementary reflectors which + represent the unitary matrix P. See Further Details. + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. LWORK >= max(1,M,N). + For optimum performance LWORK >= (M+N)*NB, where NB + is the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + If m >= n, + + Q = H(1) H(2) . . . H(n) and P = G(1) G(2) . . . G(n-1) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, and v and u are complex + vectors; v(1:i-1) = 0, v(i) = 1, and v(i+1:m) is stored on exit in + A(i+1:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+2:n) is stored on exit in + A(i,i+2:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, + + Q = H(1) H(2) . . . H(m-1) and P = G(1) G(2) . . . G(m) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, and v and u are complex + vectors; v(1:i) = 0, v(i+1) = 1, and v(i+2:m) is stored on exit in + A(i+2:m,i); u(1:i-1) = 0, u(i) = 1, and u(i+1:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + The contents of A on exit are illustrated by the following examples: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) + ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) + ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) + ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) + ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) + ( v1 v2 v3 v4 v5 ) + + where d and e denote diagonal and off-diagonal elements of B, vi + denotes an element of the vector defining H(i), and ui an element of + the vector defining G(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + --work; + + /* Function Body */ + *info = 0; +/* Computing MAX */ + i__1 = 1, i__2 = ilaenv_(&c__1, "ZGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = max(i__1,i__2); + lwkopt = (*m + *n) * nb; + d__1 = (doublereal) lwkopt; + work[1].r = d__1, work[1].i = 0.; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = max(1,*m); + if (*lwork < max(i__1,*n) && ! lquery) { + *info = -10; + } + } + if (*info < 0) { + i__1 = -(*info); + xerbla_("ZGEBRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + minmn = min(*m,*n); + if (minmn == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + ws = (doublereal) max(*m,*n); + ldwrkx = *m; + ldwrky = *n; + + if (nb > 1 && nb < minmn) { + +/* + Set the crossover point NX. + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "ZGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + +/* Determine when to switch from blocked to unblocked code. */ + + if (nx < minmn) { + ws = (doublereal) ((*m + *n) * nb); + if ((doublereal) (*lwork) < ws) { + +/* + Not enough work space for the optimal NB, consider using + a smaller block size. +*/ + + nbmin = ilaenv_(&c__2, "ZGEBRD", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + if (*lwork >= (*m + *n) * nbmin) { + nb = *lwork / (*m + *n); + } else { + nb = 1; + nx = minmn; + } + } + } + } else { + nx = minmn; + } + + i__1 = minmn - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + +/* + Reduce rows and columns i:i+ib-1 to bidiagonal form and return + the matrices X and Y which are needed to update the unreduced + part of the matrix +*/ + + i__3 = *m - i__ + 1; + i__4 = *n - i__ + 1; + zlabrd_(&i__3, &i__4, &nb, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[ + i__], &tauq[i__], &taup[i__], &work[1], &ldwrkx, &work[ldwrkx + * nb + 1], &ldwrky); + +/* + Update the trailing submatrix A(i+ib:m,i+ib:n), using + an update of the form A := A - V*Y' - X*U' +*/ + + i__3 = *m - i__ - nb + 1; + i__4 = *n - i__ - nb + 1; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "Conjugate transpose", &i__3, &i__4, &nb, & + z__1, &a[i__ + nb + i__ * a_dim1], lda, &work[ldwrkx * nb + + nb + 1], &ldwrky, &c_b57, &a[i__ + nb + (i__ + nb) * a_dim1], + lda); + i__3 = *m - i__ - nb + 1; + i__4 = *n - i__ - nb + 1; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "No transpose", &i__3, &i__4, &nb, &z__1, & + work[nb + 1], &ldwrkx, &a[i__ + (i__ + nb) * a_dim1], lda, & + c_b57, &a[i__ + nb + (i__ + nb) * a_dim1], lda); + +/* Copy diagonal and off-diagonal elements of B back into A */ + + if (*m >= *n) { + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + i__4 = j + j * a_dim1; + i__5 = j; + a[i__4].r = d__[i__5], a[i__4].i = 0.; + i__4 = j + (j + 1) * a_dim1; + i__5 = j; + a[i__4].r = e[i__5], a[i__4].i = 0.; +/* L10: */ + } + } else { + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + i__4 = j + j * a_dim1; + i__5 = j; + a[i__4].r = d__[i__5], a[i__4].i = 0.; + i__4 = j + 1 + j * a_dim1; + i__5 = j; + a[i__4].r = e[i__5], a[i__4].i = 0.; +/* L20: */ + } + } +/* L30: */ + } + +/* Use unblocked code to reduce the remainder of the matrix */ + + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + zgebd2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], & + tauq[i__], &taup[i__], &work[1], &iinfo); + work[1].r = ws, work[1].i = 0.; + return 0; + +/* End of ZGEBRD */ + +} /* zgebrd_ */ + +/* Subroutine */ int zgeev_(char *jobvl, char *jobvr, integer *n, + doublecomplex *a, integer *lda, doublecomplex *w, doublecomplex *vl, + integer *ldvl, doublecomplex *vr, integer *ldvr, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, + i__2, i__3; + doublereal d__1, d__2; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, k, ihi; + static doublereal scl; + static integer ilo; + static doublereal dum[1], eps; + static doublecomplex tmp; + static integer ibal; + static char side[1]; + static doublereal anrm; + static integer ierr, itau, iwrk, nout; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *), dlabad_(doublereal *, doublereal *); + extern doublereal dznrm2_(integer *, doublecomplex *, integer *); + static logical scalea; + + static doublereal cscale; + extern /* Subroutine */ int zgebak_(char *, char *, integer *, integer *, + integer *, doublereal *, integer *, doublecomplex *, integer *, + integer *), zgebal_(char *, integer *, + doublecomplex *, integer *, integer *, integer *, doublereal *, + integer *); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical select[1]; + extern /* Subroutine */ int zdscal_(integer *, doublereal *, + doublecomplex *, integer *); + static doublereal bignum; + extern doublereal zlange_(char *, integer *, integer *, doublecomplex *, + integer *, doublereal *); + extern /* Subroutine */ int zgehrd_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *), zlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublecomplex *, + integer *, integer *), zlacpy_(char *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, integer *); + static integer minwrk, maxwrk; + static logical wantvl; + static doublereal smlnum; + static integer hswork, irwork; + extern /* Subroutine */ int zhseqr_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *), ztrevc_(char *, char *, logical *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, integer *, integer *, doublecomplex *, + doublereal *, integer *); + static logical lquery, wantvr; + extern /* Subroutine */ int zunghr_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGEEV computes for an N-by-N complex nonsymmetric matrix A, the + eigenvalues and, optionally, the left and/or right eigenvectors. + + The right eigenvector v(j) of A satisfies + A * v(j) = lambda(j) * v(j) + where lambda(j) is its eigenvalue. + The left eigenvector u(j) of A satisfies + u(j)**H * A = lambda(j) * u(j)**H + where u(j)**H denotes the conjugate transpose of u(j). + + The computed eigenvectors are normalized to have Euclidean norm + equal to 1 and largest component real. + + Arguments + ========= + + JOBVL (input) CHARACTER*1 + = 'N': left eigenvectors of A are not computed; + = 'V': left eigenvectors of are computed. + + JOBVR (input) CHARACTER*1 + = 'N': right eigenvectors of A are not computed; + = 'V': right eigenvectors of A are computed. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the N-by-N matrix A. + On exit, A has been overwritten. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + W (output) COMPLEX*16 array, dimension (N) + W contains the computed eigenvalues. + + VL (output) COMPLEX*16 array, dimension (LDVL,N) + If JOBVL = 'V', the left eigenvectors u(j) are stored one + after another in the columns of VL, in the same order + as their eigenvalues. + If JOBVL = 'N', VL is not referenced. + u(j) = VL(:,j), the j-th column of VL. + + LDVL (input) INTEGER + The leading dimension of the array VL. LDVL >= 1; if + JOBVL = 'V', LDVL >= N. + + VR (output) COMPLEX*16 array, dimension (LDVR,N) + If JOBVR = 'V', the right eigenvectors v(j) are stored one + after another in the columns of VR, in the same order + as their eigenvalues. + If JOBVR = 'N', VR is not referenced. + v(j) = VR(:,j), the j-th column of VR. + + LDVR (input) INTEGER + The leading dimension of the array VR. LDVR >= 1; if + JOBVR = 'V', LDVR >= N. + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,2*N). + For good performance, LWORK must generally be larger. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + RWORK (workspace) DOUBLE PRECISION array, dimension (2*N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = i, the QR algorithm failed to compute all the + eigenvalues, and no eigenvectors have been computed; + elements and i+1:N of W contain eigenvalues which have + converged. + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --w; + vl_dim1 = *ldvl; + vl_offset = 1 + vl_dim1; + vl -= vl_offset; + vr_dim1 = *ldvr; + vr_offset = 1 + vr_dim1; + vr -= vr_offset; + --work; + --rwork; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1; + wantvl = lsame_(jobvl, "V"); + wantvr = lsame_(jobvr, "V"); + if (! wantvl && ! lsame_(jobvl, "N")) { + *info = -1; + } else if (! wantvr && ! lsame_(jobvr, "N")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldvl < 1 || wantvl && *ldvl < *n) { + *info = -8; + } else if (*ldvr < 1 || wantvr && *ldvr < *n) { + *info = -10; + } + +/* + Compute workspace + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + CWorkspace refers to complex workspace, and RWorkspace to real + workspace. NB refers to the optimal block size for the + immediately following subroutine, as returned by ILAENV. + HSWORK refers to the workspace preferred by ZHSEQR, as + calculated below. HSWORK is computed assuming ILO=1 and IHI=N, + the worst case.) +*/ + + if (*info == 0) { + if (*n == 0) { + minwrk = 1; + maxwrk = 1; + } else { + maxwrk = *n + *n * ilaenv_(&c__1, "ZGEHRD", " ", n, &c__1, n, & + c__0, (ftnlen)6, (ftnlen)1); + minwrk = *n << 1; + if (wantvl) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + (*n - 1) * ilaenv_(&c__1, "ZUNGHR", + " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); + zhseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &w[1], &vl[ + vl_offset], ldvl, &work[1], &c_n1, info); + } else if (wantvr) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n + (*n - 1) * ilaenv_(&c__1, "ZUNGHR", + " ", n, &c__1, n, &c_n1, (ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); + zhseqr_("S", "V", n, &c__1, n, &a[a_offset], lda, &w[1], &vr[ + vr_offset], ldvr, &work[1], &c_n1, info); + } else { + zhseqr_("E", "N", n, &c__1, n, &a[a_offset], lda, &w[1], &vr[ + vr_offset], ldvr, &work[1], &c_n1, info); + } + hswork = (integer) work[1].r; +/* Computing MAX */ + i__1 = max(maxwrk,hswork); + maxwrk = max(i__1,minwrk); + } + work[1].r = (doublereal) maxwrk, work[1].i = 0.; + + if (*lwork < minwrk && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGEEV ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Get machine constants */ + + eps = PRECISION; + smlnum = SAFEMINIMUM; + bignum = 1. / smlnum; + dlabad_(&smlnum, &bignum); + smlnum = sqrt(smlnum) / eps; + bignum = 1. / smlnum; + +/* Scale A if max element outside range [SMLNUM,BIGNUM] */ + + anrm = zlange_("M", n, n, &a[a_offset], lda, dum); + scalea = FALSE_; + if (anrm > 0. && anrm < smlnum) { + scalea = TRUE_; + cscale = smlnum; + } else if (anrm > bignum) { + scalea = TRUE_; + cscale = bignum; + } + if (scalea) { + zlascl_("G", &c__0, &c__0, &anrm, &cscale, n, n, &a[a_offset], lda, & + ierr); + } + +/* + Balance the matrix + (CWorkspace: none) + (RWorkspace: need N) +*/ + + ibal = 1; + zgebal_("B", n, &a[a_offset], lda, &ilo, &ihi, &rwork[ibal], &ierr); + +/* + Reduce to upper Hessenberg form + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: none) +*/ + + itau = 1; + iwrk = itau + *n; + i__1 = *lwork - iwrk + 1; + zgehrd_(n, &ilo, &ihi, &a[a_offset], lda, &work[itau], &work[iwrk], &i__1, + &ierr); + + if (wantvl) { + +/* + Want left eigenvectors + Copy Householder vectors to VL +*/ + + *(unsigned char *)side = 'L'; + zlacpy_("L", n, n, &a[a_offset], lda, &vl[vl_offset], ldvl) + ; + +/* + Generate unitary matrix in VL + (CWorkspace: need 2*N-1, prefer N+(N-1)*NB) + (RWorkspace: none) +*/ + + i__1 = *lwork - iwrk + 1; + zunghr_(n, &ilo, &ihi, &vl[vl_offset], ldvl, &work[itau], &work[iwrk], + &i__1, &ierr); + +/* + Perform QR iteration, accumulating Schur vectors in VL + (CWorkspace: need 1, prefer HSWORK (see comments) ) + (RWorkspace: none) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + zhseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &w[1], &vl[ + vl_offset], ldvl, &work[iwrk], &i__1, info); + + if (wantvr) { + +/* + Want left and right eigenvectors + Copy Schur vectors to VR +*/ + + *(unsigned char *)side = 'B'; + zlacpy_("F", n, n, &vl[vl_offset], ldvl, &vr[vr_offset], ldvr); + } + + } else if (wantvr) { + +/* + Want right eigenvectors + Copy Householder vectors to VR +*/ + + *(unsigned char *)side = 'R'; + zlacpy_("L", n, n, &a[a_offset], lda, &vr[vr_offset], ldvr) + ; + +/* + Generate unitary matrix in VR + (CWorkspace: need 2*N-1, prefer N+(N-1)*NB) + (RWorkspace: none) +*/ + + i__1 = *lwork - iwrk + 1; + zunghr_(n, &ilo, &ihi, &vr[vr_offset], ldvr, &work[itau], &work[iwrk], + &i__1, &ierr); + +/* + Perform QR iteration, accumulating Schur vectors in VR + (CWorkspace: need 1, prefer HSWORK (see comments) ) + (RWorkspace: none) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + zhseqr_("S", "V", n, &ilo, &ihi, &a[a_offset], lda, &w[1], &vr[ + vr_offset], ldvr, &work[iwrk], &i__1, info); + + } else { + +/* + Compute eigenvalues only + (CWorkspace: need 1, prefer HSWORK (see comments) ) + (RWorkspace: none) +*/ + + iwrk = itau; + i__1 = *lwork - iwrk + 1; + zhseqr_("E", "N", n, &ilo, &ihi, &a[a_offset], lda, &w[1], &vr[ + vr_offset], ldvr, &work[iwrk], &i__1, info); + } + +/* If INFO > 0 from ZHSEQR, then quit */ + + if (*info > 0) { + goto L50; + } + + if (wantvl || wantvr) { + +/* + Compute left and/or right eigenvectors + (CWorkspace: need 2*N) + (RWorkspace: need 2*N) +*/ + + irwork = ibal + *n; + ztrevc_(side, "B", select, n, &a[a_offset], lda, &vl[vl_offset], ldvl, + &vr[vr_offset], ldvr, n, &nout, &work[iwrk], &rwork[irwork], + &ierr); + } + + if (wantvl) { + +/* + Undo balancing of left eigenvectors + (CWorkspace: none) + (RWorkspace: need N) +*/ + + zgebak_("B", "L", n, &ilo, &ihi, &rwork[ibal], n, &vl[vl_offset], + ldvl, &ierr); + +/* Normalize left eigenvectors and make largest component real */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + scl = 1. / dznrm2_(n, &vl[i__ * vl_dim1 + 1], &c__1); + zdscal_(n, &scl, &vl[i__ * vl_dim1 + 1], &c__1); + i__2 = *n; + for (k = 1; k <= i__2; ++k) { + i__3 = k + i__ * vl_dim1; +/* Computing 2nd power */ + d__1 = vl[i__3].r; +/* Computing 2nd power */ + d__2 = d_imag(&vl[k + i__ * vl_dim1]); + rwork[irwork + k - 1] = d__1 * d__1 + d__2 * d__2; +/* L10: */ + } + k = idamax_(n, &rwork[irwork], &c__1); + d_cnjg(&z__2, &vl[k + i__ * vl_dim1]); + d__1 = sqrt(rwork[irwork + k - 1]); + z__1.r = z__2.r / d__1, z__1.i = z__2.i / d__1; + tmp.r = z__1.r, tmp.i = z__1.i; + zscal_(n, &tmp, &vl[i__ * vl_dim1 + 1], &c__1); + i__2 = k + i__ * vl_dim1; + i__3 = k + i__ * vl_dim1; + d__1 = vl[i__3].r; + z__1.r = d__1, z__1.i = 0.; + vl[i__2].r = z__1.r, vl[i__2].i = z__1.i; +/* L20: */ + } + } + + if (wantvr) { + +/* + Undo balancing of right eigenvectors + (CWorkspace: none) + (RWorkspace: need N) +*/ + + zgebak_("B", "R", n, &ilo, &ihi, &rwork[ibal], n, &vr[vr_offset], + ldvr, &ierr); + +/* Normalize right eigenvectors and make largest component real */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + scl = 1. / dznrm2_(n, &vr[i__ * vr_dim1 + 1], &c__1); + zdscal_(n, &scl, &vr[i__ * vr_dim1 + 1], &c__1); + i__2 = *n; + for (k = 1; k <= i__2; ++k) { + i__3 = k + i__ * vr_dim1; +/* Computing 2nd power */ + d__1 = vr[i__3].r; +/* Computing 2nd power */ + d__2 = d_imag(&vr[k + i__ * vr_dim1]); + rwork[irwork + k - 1] = d__1 * d__1 + d__2 * d__2; +/* L30: */ + } + k = idamax_(n, &rwork[irwork], &c__1); + d_cnjg(&z__2, &vr[k + i__ * vr_dim1]); + d__1 = sqrt(rwork[irwork + k - 1]); + z__1.r = z__2.r / d__1, z__1.i = z__2.i / d__1; + tmp.r = z__1.r, tmp.i = z__1.i; + zscal_(n, &tmp, &vr[i__ * vr_dim1 + 1], &c__1); + i__2 = k + i__ * vr_dim1; + i__3 = k + i__ * vr_dim1; + d__1 = vr[i__3].r; + z__1.r = d__1, z__1.i = 0.; + vr[i__2].r = z__1.r, vr[i__2].i = z__1.i; +/* L40: */ + } + } + +/* Undo scaling if necessary */ + +L50: + if (scalea) { + i__1 = *n - *info; +/* Computing MAX */ + i__3 = *n - *info; + i__2 = max(i__3,1); + zlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &w[*info + 1] + , &i__2, &ierr); + if (*info > 0) { + i__1 = ilo - 1; + zlascl_("G", &c__0, &c__0, &cscale, &anrm, &i__1, &c__1, &w[1], n, + &ierr); + } + } + + work[1].r = (doublereal) maxwrk, work[1].i = 0.; + return 0; + +/* End of ZGEEV */ + +} /* zgeev_ */ + +/* Subroutine */ int zgehd2_(integer *n, integer *ilo, integer *ihi, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__; + static doublecomplex alpha; + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *), zlarfg_(integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGEHD2 reduces a complex general matrix A to upper Hessenberg form H + by a unitary similarity transformation: Q' * A * Q = H . + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that A is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to ZGEBAL; otherwise they should be + set to 1 and N respectively. See Further Details. + 1 <= ILO <= IHI <= max(1,N). + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the n by n general matrix to be reduced. + On exit, the upper triangle and the first subdiagonal of A + are overwritten with the upper Hessenberg matrix H, and the + elements below the first subdiagonal, with the array TAU, + represent the unitary matrix Q as a product of elementary + reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) COMPLEX*16 array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) COMPLEX*16 array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrix Q is represented as a product of (ihi-ilo) elementary + reflectors + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on + exit in A(i+2:ihi,i), and tau in TAU(i). + + The contents of A are illustrated by the following example, with + n = 7, ilo = 2 and ihi = 6: + + on entry, on exit, + + ( a a a a a a a ) ( a a h h h h a ) + ( a a a a a a ) ( a h h h h a ) + ( a a a a a a ) ( h h h h h h ) + ( a a a a a a ) ( v2 h h h h h ) + ( a a a a a a ) ( v2 v3 h h h h ) + ( a a a a a a ) ( v2 v3 v4 h h h ) + ( a ) ( a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGEHD2", &i__1); + return 0; + } + + i__1 = *ihi - 1; + for (i__ = *ilo; i__ <= i__1; ++i__) { + +/* Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) */ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *ihi - i__; +/* Computing MIN */ + i__3 = i__ + 2; + zlarfg_(&i__2, &alpha, &a[min(i__3,*n) + i__ * a_dim1], &c__1, &tau[ + i__]); + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Apply H(i) to A(1:ihi,i+1:ihi) from the right */ + + i__2 = *ihi - i__; + zlarf_("Right", ihi, &i__2, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &a[(i__ + 1) * a_dim1 + 1], lda, &work[1]); + +/* Apply H(i)' to A(i+1:ihi,i+1:n) from the left */ + + i__2 = *ihi - i__; + i__3 = *n - i__; + d_cnjg(&z__1, &tau[i__]); + zlarf_("Left", &i__2, &i__3, &a[i__ + 1 + i__ * a_dim1], &c__1, &z__1, + &a[i__ + 1 + (i__ + 1) * a_dim1], lda, &work[1]); + + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = alpha.r, a[i__2].i = alpha.i; +/* L10: */ + } + + return 0; + +/* End of ZGEHD2 */ + +} /* zgehd2_ */ + +/* Subroutine */ int zgehrd_(integer *n, integer *ilo, integer *ihi, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j; + static doublecomplex t[4160] /* was [65][64] */; + static integer ib; + static doublecomplex ei; + static integer nb, nh, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), ztrmm_(char *, char *, char *, char *, + integer *, integer *, doublecomplex *, doublecomplex *, integer * + , doublecomplex *, integer *), + zaxpy_(integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *), zgehd2_(integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *), zlahr2_(integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *), xerbla_( + char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlarfb_(char *, char *, char *, char *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + -- April 2009 -- + + + Purpose + ======= + + ZGEHRD reduces a complex general matrix A to upper Hessenberg form H by + an unitary similarity transformation: Q' * A * Q = H . + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that A is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to ZGEBAL; otherwise they should be + set to 1 and N respectively. See Further Details. + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the N-by-N general matrix to be reduced. + On exit, the upper triangle and the first subdiagonal of A + are overwritten with the upper Hessenberg matrix H, and the + elements below the first subdiagonal, with the array TAU, + represent the unitary matrix Q as a product of elementary + reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) COMPLEX*16 array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). Elements 1:ILO-1 and IHI:N-1 of TAU are set to + zero. + + WORK (workspace/output) COMPLEX*16 array, dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + The matrix Q is represented as a product of (ihi-ilo) elementary + reflectors + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on + exit in A(i+2:ihi,i), and tau in TAU(i). + + The contents of A are illustrated by the following example, with + n = 7, ilo = 2 and ihi = 6: + + on entry, on exit, + + ( a a a a a a a ) ( a a h h h h a ) + ( a a a a a a ) ( a h h h h a ) + ( a a a a a a ) ( h h h h h h ) + ( a a a a a a ) ( v2 h h h h h ) + ( a a a a a a ) ( v2 v3 h h h h ) + ( a a a a a a ) ( v2 v3 v4 h h h ) + ( a ) ( a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + This file is a slight modification of LAPACK-3.0's DGEHRD + subroutine incorporating improvements proposed by Quintana-Orti and + Van de Geijn (2006). (See DLAHR2.) + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; +/* Computing MIN */ + i__1 = 64, i__2 = ilaenv_(&c__1, "ZGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = min(i__1,i__2); + lwkopt = *n * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + lquery = *lwork == -1; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGEHRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Set elements 1:ILO-1 and IHI:N-1 of TAU to zero */ + + i__1 = *ilo - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + tau[i__2].r = 0., tau[i__2].i = 0.; +/* L10: */ + } + i__1 = *n - 1; + for (i__ = max(1,*ihi); i__ <= i__1; ++i__) { + i__2 = i__; + tau[i__2].r = 0., tau[i__2].i = 0.; +/* L20: */ + } + +/* Quick return if possible */ + + nh = *ihi - *ilo + 1; + if (nh <= 1) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + +/* + Determine the block size + + Computing MIN +*/ + i__1 = 64, i__2 = ilaenv_(&c__1, "ZGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nb = min(i__1,i__2); + nbmin = 2; + iws = 1; + if (nb > 1 && nb < nh) { + +/* + Determine when to cross over from blocked to unblocked code + (last block is always handled by unblocked code) + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "ZGEHRD", " ", n, ilo, ihi, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < nh) { + +/* Determine if workspace is large enough for blocked code */ + + iws = *n * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: determine the + minimum value of NB, and reduce NB or force use of + unblocked code + + Computing MAX +*/ + i__1 = 2, i__2 = ilaenv_(&c__2, "ZGEHRD", " ", n, ilo, ihi, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + if (*lwork >= *n * nbmin) { + nb = *lwork / *n; + } else { + nb = 1; + } + } + } + } + ldwork = *n; + + if (nb < nbmin || nb >= nh) { + +/* Use unblocked code below */ + + i__ = *ilo; + + } else { + +/* Use blocked code */ + + i__1 = *ihi - 1 - nx; + i__2 = nb; + for (i__ = *ilo; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = nb, i__4 = *ihi - i__; + ib = min(i__3,i__4); + +/* + Reduce columns i:i+ib-1 to Hessenberg form, returning the + matrices V and T of the block reflector H = I - V*T*V' + which performs the reduction, and also the matrix Y = A*V*T +*/ + + zlahr2_(ihi, &i__, &ib, &a[i__ * a_dim1 + 1], lda, &tau[i__], t, & + c__65, &work[1], &ldwork); + +/* + Apply the block reflector H to A(1:ihi,i+ib:ihi) from the + right, computing A := A - Y * V'. V(i+ib,ib-1) must be set + to 1 +*/ + + i__3 = i__ + ib + (i__ + ib - 1) * a_dim1; + ei.r = a[i__3].r, ei.i = a[i__3].i; + i__3 = i__ + ib + (i__ + ib - 1) * a_dim1; + a[i__3].r = 1., a[i__3].i = 0.; + i__3 = *ihi - i__ - ib + 1; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "Conjugate transpose", ihi, &i__3, &ib, & + z__1, &work[1], &ldwork, &a[i__ + ib + i__ * a_dim1], lda, + &c_b57, &a[(i__ + ib) * a_dim1 + 1], lda); + i__3 = i__ + ib + (i__ + ib - 1) * a_dim1; + a[i__3].r = ei.r, a[i__3].i = ei.i; + +/* + Apply the block reflector H to A(1:i,i+1:i+ib-1) from the + right +*/ + + i__3 = ib - 1; + ztrmm_("Right", "Lower", "Conjugate transpose", "Unit", &i__, & + i__3, &c_b57, &a[i__ + 1 + i__ * a_dim1], lda, &work[1], & + ldwork); + i__3 = ib - 2; + for (j = 0; j <= i__3; ++j) { + z__1.r = -1., z__1.i = -0.; + zaxpy_(&i__, &z__1, &work[ldwork * j + 1], &c__1, &a[(i__ + j + + 1) * a_dim1 + 1], &c__1); +/* L30: */ + } + +/* + Apply the block reflector H to A(i+1:ihi,i+ib:n) from the + left +*/ + + i__3 = *ihi - i__; + i__4 = *n - i__ - ib + 1; + zlarfb_("Left", "Conjugate transpose", "Forward", "Columnwise", & + i__3, &i__4, &ib, &a[i__ + 1 + i__ * a_dim1], lda, t, & + c__65, &a[i__ + 1 + (i__ + ib) * a_dim1], lda, &work[1], & + ldwork); +/* L40: */ + } + } + +/* Use unblocked code to reduce the rest of the matrix */ + + zgehd2_(n, &i__, ihi, &a[a_offset], lda, &tau[1], &work[1], &iinfo); + work[1].r = (doublereal) iws, work[1].i = 0.; + + return 0; + +/* End of ZGEHRD */ + +} /* zgehrd_ */ + +/* Subroutine */ int zgelq2_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, k; + static doublecomplex alpha; + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *), zlarfg_(integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), zlacgv_(integer *, doublecomplex *, + integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + ZGELQ2 computes an LQ factorization of a complex m by n matrix A: + A = L * Q. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, the elements on and below the diagonal of the array + contain the m by min(m,n) lower trapezoidal matrix L (L is + lower triangular if m <= n); the elements above the diagonal, + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) COMPLEX*16 array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) COMPLEX*16 array, dimension (M) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(k)' . . . H(2)' H(1)', where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i-1) = 0 and v(i) = 1; conjg(v(i+1:n)) is stored on exit in + A(i,i+1:n), and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGELQ2", &i__1); + return 0; + } + + k = min(*m,*n); + + i__1 = k; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i,i+1:n) */ + + i__2 = *n - i__ + 1; + zlacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + zlarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, &tau[i__] + ); + if (i__ < *m) { + +/* Apply H(i) to A(i+1:m,i:n) from the right */ + + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + i__2 = *m - i__; + i__3 = *n - i__ + 1; + zlarf_("Right", &i__2, &i__3, &a[i__ + i__ * a_dim1], lda, &tau[ + i__], &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + i__2 = i__ + i__ * a_dim1; + a[i__2].r = alpha.r, a[i__2].i = alpha.i; + i__2 = *n - i__ + 1; + zlacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); +/* L10: */ + } + return 0; + +/* End of ZGELQ2 */ + +} /* zgelq2_ */ + +/* Subroutine */ int zgelqf_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, k, ib, nb, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int zgelq2_(integer *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *), xerbla_( + char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlarfb_(char *, char *, char *, char *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static integer ldwork; + extern /* Subroutine */ int zlarft_(char *, char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGELQF computes an LQ factorization of a complex M-by-N matrix A: + A = L * Q. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, the elements on and below the diagonal of the array + contain the m-by-min(m,n) lower trapezoidal matrix L (L is + lower triangular if m <= n); the elements above the diagonal, + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) COMPLEX*16 array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,M). + For optimum performance LWORK >= M*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(k)' . . . H(2)' H(1)', where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i-1) = 0 and v(i) = 1; conjg(v(i+1:n)) is stored on exit in + A(i,i+1:n), and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "ZGELQF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + lwkopt = *m * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else if (*lwork < max(1,*m) && ! lquery) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGELQF", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + k = min(*m,*n); + if (k == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *m; + if (nb > 1 && nb < k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "ZGELQF", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *m; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "ZGELQF", " ", m, n, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < k && nx < k) { + +/* Use blocked code initially */ + + i__1 = k - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = k - i__ + 1; + ib = min(i__3,nb); + +/* + Compute the LQ factorization of the current block + A(i:i+ib-1,i:n) +*/ + + i__3 = *n - i__ + 1; + zgelq2_(&ib, &i__3, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[ + 1], &iinfo); + if (i__ + ib <= *m) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__3 = *n - i__ + 1; + zlarft_("Forward", "Rowwise", &i__3, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H to A(i+ib:m,i:n) from the right */ + + i__3 = *m - i__ - ib + 1; + i__4 = *n - i__ + 1; + zlarfb_("Right", "No transpose", "Forward", "Rowwise", &i__3, + &i__4, &ib, &a[i__ + i__ * a_dim1], lda, &work[1], & + ldwork, &a[i__ + ib + i__ * a_dim1], lda, &work[ib + + 1], &ldwork); + } +/* L10: */ + } + } else { + i__ = 1; + } + +/* Use unblocked code to factor the last or only block. */ + + if (i__ <= k) { + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + zgelq2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[1] + , &iinfo); + } + + work[1].r = (doublereal) iws, work[1].i = 0.; + return 0; + +/* End of ZGELQF */ + +} /* zgelqf_ */ + +/* Subroutine */ int zgelsd_(integer *m, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + doublereal *s, doublereal *rcond, integer *rank, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *iwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer ie, il, mm; + static doublereal eps, anrm, bnrm; + static integer itau, nlvl, iascl, ibscl; + static doublereal sfmin; + static integer minmn, maxmn, itaup, itauq, mnthr, nwork; + extern /* Subroutine */ int dlabad_(doublereal *, doublereal *); + + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dlaset_(char *, integer *, integer + *, doublereal *, doublereal *, doublereal *, integer *), + xerbla_(char *, integer *), zgebrd_(integer *, integer *, + doublecomplex *, integer *, doublereal *, doublereal *, + doublecomplex *, doublecomplex *, doublecomplex *, integer *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern doublereal zlange_(char *, integer *, integer *, doublecomplex *, + integer *, doublereal *); + static doublereal bignum; + extern /* Subroutine */ int zgelqf_(integer *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *, integer * + ), zlalsd_(char *, integer *, integer *, integer *, doublereal *, + doublereal *, doublecomplex *, integer *, doublereal *, integer *, + doublecomplex *, doublereal *, integer *, integer *), + zlascl_(char *, integer *, integer *, doublereal *, doublereal *, + integer *, integer *, doublecomplex *, integer *, integer *), zgeqrf_(integer *, integer *, doublecomplex *, integer *, + doublecomplex *, doublecomplex *, integer *, integer *); + static integer ldwork; + extern /* Subroutine */ int zlacpy_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *), + zlaset_(char *, integer *, integer *, doublecomplex *, + doublecomplex *, doublecomplex *, integer *); + static integer liwork, minwrk, maxwrk; + static doublereal smlnum; + extern /* Subroutine */ int zunmbr_(char *, char *, char *, integer *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer * + ); + static integer lrwork; + static logical lquery; + static integer nrwork, smlsiz; + extern /* Subroutine */ int zunmlq_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *), zunmqr_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGELSD computes the minimum-norm solution to a real linear least + squares problem: + minimize 2-norm(| b - A*x |) + using the singular value decomposition (SVD) of A. A is an M-by-N + matrix which may be rank-deficient. + + Several right hand side vectors b and solution vectors x can be + handled in a single call; they are stored as the columns of the + M-by-NRHS right hand side matrix B and the N-by-NRHS solution + matrix X. + + The problem is solved in three steps: + (1) Reduce the coefficient matrix A to bidiagonal form with + Householder tranformations, reducing the original problem + into a "bidiagonal least squares problem" (BLS) + (2) Solve the BLS using a divide and conquer approach. + (3) Apply back all the Householder tranformations to solve + the original least squares problem. + + The effective rank of A is determined by treating as zero those + singular values which are less than RCOND times the largest singular + value. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrices B and X. NRHS >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, A has been destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + B (input/output) COMPLEX*16 array, dimension (LDB,NRHS) + On entry, the M-by-NRHS right hand side matrix B. + On exit, B is overwritten by the N-by-NRHS solution matrix X. + If m >= n and RANK = n, the residual sum-of-squares for + the solution in the i-th column is given by the sum of + squares of the modulus of elements n+1:m in that column. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,M,N). + + S (output) DOUBLE PRECISION array, dimension (min(M,N)) + The singular values of A in decreasing order. + The condition number of A in the 2-norm = S(1)/S(min(m,n)). + + RCOND (input) DOUBLE PRECISION + RCOND is used to determine the effective rank of A. + Singular values S(i) <= RCOND*S(1) are treated as zero. + If RCOND < 0, machine precision is used instead. + + RANK (output) INTEGER + The effective rank of A, i.e., the number of singular values + which are greater than RCOND*S(1). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK must be at least 1. + The exact minimum amount of workspace needed depends on M, + N and NRHS. As long as LWORK is at least + 2*N + N*NRHS + if M is greater than or equal to N or + 2*M + M*NRHS + if M is less than N, the code will execute correctly. + For good performance, LWORK should generally be larger. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the array WORK and the + minimum sizes of the arrays RWORK and IWORK, and returns + these values as the first entries of the WORK, RWORK and + IWORK arrays, and no error message related to LWORK is issued + by XERBLA. + + RWORK (workspace) DOUBLE PRECISION array, dimension (MAX(1,LRWORK)) + LRWORK >= + 10*N + 2*N*SMLSIZ + 8*N*NLVL + 3*SMLSIZ*NRHS + + MAX( (SMLSIZ+1)**2, N*(1+NRHS) + 2*NRHS ) + if M is greater than or equal to N or + 10*M + 2*M*SMLSIZ + 8*M*NLVL + 3*SMLSIZ*NRHS + + MAX( (SMLSIZ+1)**2, N*(1+NRHS) + 2*NRHS ) + if M is less than N, the code will execute correctly. + SMLSIZ is returned by ILAENV and is equal to the maximum + size of the subproblems at the bottom of the computation + tree (usually about 25), and + NLVL = MAX( 0, INT( LOG_2( MIN( M,N )/(SMLSIZ+1) ) ) + 1 ) + On exit, if INFO = 0, RWORK(1) returns the minimum LRWORK. + + IWORK (workspace) INTEGER array, dimension (MAX(1,LIWORK)) + LIWORK >= max(1, 3*MINMN*NLVL + 11*MINMN), + where MINMN = MIN( M,N ). + On exit, if INFO = 0, IWORK(1) returns the minimum LIWORK. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: the algorithm for computing the SVD failed to converge; + if INFO = i, i off-diagonal elements of an intermediate + bidiagonal form did not converge to zero. + + Further Details + =============== + + Based on contributions by + Ming Gu and Ren-Cang Li, Computer Science Division, University of + California at Berkeley, USA + Osni Marques, LBNL/NERSC, USA + + ===================================================================== + + + Test the input arguments. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + --s; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + minmn = min(*m,*n); + maxmn = max(*m,*n); + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*ldb < max(1,maxmn)) { + *info = -7; + } + +/* + Compute workspace. + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + NB refers to the optimal block size for the immediately + following subroutine, as returned by ILAENV.) +*/ + + if (*info == 0) { + minwrk = 1; + maxwrk = 1; + liwork = 1; + lrwork = 1; + if (minmn > 0) { + smlsiz = ilaenv_(&c__9, "ZGELSD", " ", &c__0, &c__0, &c__0, &c__0, + (ftnlen)6, (ftnlen)1); + mnthr = ilaenv_(&c__6, "ZGELSD", " ", m, n, nrhs, &c_n1, (ftnlen) + 6, (ftnlen)1); +/* Computing MAX */ + i__1 = (integer) (log((doublereal) minmn / (doublereal) (smlsiz + + 1)) / log(2.)) + 1; + nlvl = max(i__1,0); + liwork = minmn * 3 * nlvl + minmn * 11; + mm = *m; + if (*m >= *n && *m >= mnthr) { + +/* + Path 1a - overdetermined, with many more rows than + columns. +*/ + + mm = *n; +/* Computing MAX */ + i__1 = maxwrk, i__2 = *n * ilaenv_(&c__1, "ZGEQRF", " ", m, n, + &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *nrhs * ilaenv_(&c__1, "ZUNMQR", "LC", + m, nrhs, n, &c_n1, (ftnlen)6, (ftnlen)2); + maxwrk = max(i__1,i__2); + } + if (*m >= *n) { + +/* + Path 1 - overdetermined or exactly determined. + + Computing MAX + Computing 2nd power +*/ + i__3 = smlsiz + 1; + i__1 = i__3 * i__3, i__2 = *n * (*nrhs + 1) + (*nrhs << 1); + lrwork = *n * 10 + (*n << 1) * smlsiz + (*n << 3) * nlvl + + smlsiz * 3 * *nrhs + max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + (mm + *n) * ilaenv_(&c__1, + "ZGEBRD", " ", &mm, n, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *nrhs * ilaenv_(&c__1, + "ZUNMBR", "QLC", &mm, nrhs, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + (*n - 1) * ilaenv_(&c__1, + "ZUNMBR", "PLN", n, nrhs, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * *nrhs; + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = (*n << 1) + mm, i__2 = (*n << 1) + *n * *nrhs; + minwrk = max(i__1,i__2); + } + if (*n > *m) { +/* + Computing MAX + Computing 2nd power +*/ + i__3 = smlsiz + 1; + i__1 = i__3 * i__3, i__2 = *n * (*nrhs + 1) + (*nrhs << 1); + lrwork = *m * 10 + (*m << 1) * smlsiz + (*m << 3) * nlvl + + smlsiz * 3 * *nrhs + max(i__1,i__2); + if (*n >= mnthr) { + +/* + Path 2a - underdetermined, with many more columns + than rows. +*/ + + maxwrk = *m + *m * ilaenv_(&c__1, "ZGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 2) + (*m << 1) * + ilaenv_(&c__1, "ZGEBRD", " ", m, m, &c_n1, &c_n1, + (ftnlen)6, (ftnlen)1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 2) + *nrhs * + ilaenv_(&c__1, "ZUNMBR", "QLC", m, nrhs, m, &c_n1, + (ftnlen)6, (ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 2) + (*m - 1) * + ilaenv_(&c__1, "ZUNMLQ", "LC", n, nrhs, m, &c_n1, + (ftnlen)6, (ftnlen)2); + maxwrk = max(i__1,i__2); + if (*nrhs > 1) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + *m + *m * *nrhs; + maxwrk = max(i__1,i__2); + } else { +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 1); + maxwrk = max(i__1,i__2); + } +/* Computing MAX */ + i__1 = maxwrk, i__2 = *m * *m + (*m << 2) + *m * *nrhs; + maxwrk = max(i__1,i__2); +/* + XXX: Ensure the Path 2a case below is triggered. The workspace + calculation should use queries for all routines eventually. + Computing MAX + Computing MAX +*/ + i__3 = *m, i__4 = (*m << 1) - 4, i__3 = max(i__3,i__4), + i__3 = max(i__3,*nrhs), i__4 = *n - *m * 3; + i__1 = maxwrk, i__2 = (*m << 2) + *m * *m + max(i__3,i__4) + ; + maxwrk = max(i__1,i__2); + } else { + +/* Path 2 - underdetermined. */ + + maxwrk = (*m << 1) + (*n + *m) * ilaenv_(&c__1, "ZGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *nrhs * ilaenv_(&c__1, + "ZUNMBR", "QLC", m, nrhs, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "PLN", n, nrhs, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * *nrhs; + maxwrk = max(i__1,i__2); + } +/* Computing MAX */ + i__1 = (*m << 1) + *n, i__2 = (*m << 1) + *m * *nrhs; + minwrk = max(i__1,i__2); + } + } + minwrk = min(minwrk,maxwrk); + work[1].r = (doublereal) maxwrk, work[1].i = 0.; + iwork[1] = liwork; + rwork[1] = (doublereal) lrwork; + + if (*lwork < minwrk && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGELSD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0) { + *rank = 0; + return 0; + } + +/* Get machine parameters. */ + + eps = PRECISION; + sfmin = SAFEMINIMUM; + smlnum = sfmin / eps; + bignum = 1. / smlnum; + dlabad_(&smlnum, &bignum); + +/* Scale A if max entry outside range [SMLNUM,BIGNUM]. */ + + anrm = zlange_("M", m, n, &a[a_offset], lda, &rwork[1]); + iascl = 0; + if (anrm > 0. && anrm < smlnum) { + +/* Scale matrix norm up to SMLNUM */ + + zlascl_("G", &c__0, &c__0, &anrm, &smlnum, m, n, &a[a_offset], lda, + info); + iascl = 1; + } else if (anrm > bignum) { + +/* Scale matrix norm down to BIGNUM. */ + + zlascl_("G", &c__0, &c__0, &anrm, &bignum, m, n, &a[a_offset], lda, + info); + iascl = 2; + } else if (anrm == 0.) { + +/* Matrix all zero. Return zero solution. */ + + i__1 = max(*m,*n); + zlaset_("F", &i__1, nrhs, &c_b56, &c_b56, &b[b_offset], ldb); + dlaset_("F", &minmn, &c__1, &c_b328, &c_b328, &s[1], &c__1) + ; + *rank = 0; + goto L10; + } + +/* Scale B if max entry outside range [SMLNUM,BIGNUM]. */ + + bnrm = zlange_("M", m, nrhs, &b[b_offset], ldb, &rwork[1]); + ibscl = 0; + if (bnrm > 0. && bnrm < smlnum) { + +/* Scale matrix norm up to SMLNUM. */ + + zlascl_("G", &c__0, &c__0, &bnrm, &smlnum, m, nrhs, &b[b_offset], ldb, + info); + ibscl = 1; + } else if (bnrm > bignum) { + +/* Scale matrix norm down to BIGNUM. */ + + zlascl_("G", &c__0, &c__0, &bnrm, &bignum, m, nrhs, &b[b_offset], ldb, + info); + ibscl = 2; + } + +/* If M < N make sure B(M+1:N,:) = 0 */ + + if (*m < *n) { + i__1 = *n - *m; + zlaset_("F", &i__1, nrhs, &c_b56, &c_b56, &b[*m + 1 + b_dim1], ldb); + } + +/* Overdetermined case. */ + + if (*m >= *n) { + +/* Path 1 - overdetermined or exactly determined. */ + + mm = *m; + if (*m >= mnthr) { + +/* Path 1a - overdetermined, with many more rows than columns */ + + mm = *n; + itau = 1; + nwork = itau + *n; + +/* + Compute A=Q*R. + (RWorkspace: need N) + (CWorkspace: need N, prefer N*NB) +*/ + + i__1 = *lwork - nwork + 1; + zgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], &i__1, + info); + +/* + Multiply B by transpose(Q). + (RWorkspace: need N) + (CWorkspace: need NRHS, prefer NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + zunmqr_("L", "C", m, nrhs, n, &a[a_offset], lda, &work[itau], &b[ + b_offset], ldb, &work[nwork], &i__1, info); + +/* Zero out below R. */ + + if (*n > 1) { + i__1 = *n - 1; + i__2 = *n - 1; + zlaset_("L", &i__1, &i__2, &c_b56, &c_b56, &a[a_dim1 + 2], + lda); + } + } + + itauq = 1; + itaup = itauq + *n; + nwork = itaup + *n; + ie = 1; + nrwork = ie + *n; + +/* + Bidiagonalize R in A. + (RWorkspace: need N) + (CWorkspace: need 2*N+MM, prefer 2*N+(MM+N)*NB) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(&mm, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], & + work[itaup], &work[nwork], &i__1, info); + +/* + Multiply B by transpose of left bidiagonalizing vectors of R. + (CWorkspace: need 2*N+NRHS, prefer 2*N+NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "C", &mm, nrhs, n, &a[a_offset], lda, &work[itauq], + &b[b_offset], ldb, &work[nwork], &i__1, info); + +/* Solve the bidiagonal least squares problem. */ + + zlalsd_("U", &smlsiz, n, nrhs, &s[1], &rwork[ie], &b[b_offset], ldb, + rcond, rank, &work[nwork], &rwork[nrwork], &iwork[1], info); + if (*info != 0) { + goto L10; + } + +/* Multiply B by right bidiagonalizing vectors of R. */ + + i__1 = *lwork - nwork + 1; + zunmbr_("P", "L", "N", n, nrhs, n, &a[a_offset], lda, &work[itaup], & + b[b_offset], ldb, &work[nwork], &i__1, info); + + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = *m, i__2 = (*m << 1) - 4, i__1 = max(i__1,i__2), i__1 = max( + i__1,*nrhs), i__2 = *n - *m * 3; + if (*n >= mnthr && *lwork >= (*m << 2) + *m * *m + max(i__1,i__2)) { + +/* + Path 2a - underdetermined, with many more columns than rows + and sufficient workspace for an efficient algorithm. +*/ + + ldwork = *m; +/* + Computing MAX + Computing MAX +*/ + i__3 = *m, i__4 = (*m << 1) - 4, i__3 = max(i__3,i__4), i__3 = + max(i__3,*nrhs), i__4 = *n - *m * 3; + i__1 = (*m << 2) + *m * *lda + max(i__3,i__4), i__2 = *m * *lda + + *m + *m * *nrhs; + if (*lwork >= max(i__1,i__2)) { + ldwork = *lda; + } + itau = 1; + nwork = *m + 1; + +/* + Compute A=L*Q. + (CWorkspace: need 2*M, prefer M+M*NB) +*/ + + i__1 = *lwork - nwork + 1; + zgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], &i__1, + info); + il = nwork; + +/* Copy L to WORK(IL), zeroing out above its diagonal. */ + + zlacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwork); + i__1 = *m - 1; + i__2 = *m - 1; + zlaset_("U", &i__1, &i__2, &c_b56, &c_b56, &work[il + ldwork], & + ldwork); + itauq = il + ldwork * *m; + itaup = itauq + *m; + nwork = itaup + *m; + ie = 1; + nrwork = ie + *m; + +/* + Bidiagonalize L in WORK(IL). + (RWorkspace: need M) + (CWorkspace: need M*M+4*M, prefer M*M+4*M+2*M*NB) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(m, m, &work[il], &ldwork, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__1, info); + +/* + Multiply B by transpose of left bidiagonalizing vectors of L. + (CWorkspace: need M*M+4*M+NRHS, prefer M*M+4*M+NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "C", m, nrhs, m, &work[il], &ldwork, &work[ + itauq], &b[b_offset], ldb, &work[nwork], &i__1, info); + +/* Solve the bidiagonal least squares problem. */ + + zlalsd_("U", &smlsiz, m, nrhs, &s[1], &rwork[ie], &b[b_offset], + ldb, rcond, rank, &work[nwork], &rwork[nrwork], &iwork[1], + info); + if (*info != 0) { + goto L10; + } + +/* Multiply B by right bidiagonalizing vectors of L. */ + + i__1 = *lwork - nwork + 1; + zunmbr_("P", "L", "N", m, nrhs, m, &work[il], &ldwork, &work[ + itaup], &b[b_offset], ldb, &work[nwork], &i__1, info); + +/* Zero out below first M rows of B. */ + + i__1 = *n - *m; + zlaset_("F", &i__1, nrhs, &c_b56, &c_b56, &b[*m + 1 + b_dim1], + ldb); + nwork = itau + *m; + +/* + Multiply transpose(Q) by B. + (CWorkspace: need NRHS, prefer NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + zunmlq_("L", "C", n, nrhs, m, &a[a_offset], lda, &work[itau], &b[ + b_offset], ldb, &work[nwork], &i__1, info); + + } else { + +/* Path 2 - remaining underdetermined cases. */ + + itauq = 1; + itaup = itauq + *m; + nwork = itaup + *m; + ie = 1; + nrwork = ie + *m; + +/* + Bidiagonalize A. + (RWorkspace: need M) + (CWorkspace: need 2*M+N, prefer 2*M+(M+N)*NB) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__1, info); + +/* + Multiply B by transpose of left bidiagonalizing vectors. + (CWorkspace: need 2*M+NRHS, prefer 2*M+NRHS*NB) +*/ + + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "C", m, nrhs, n, &a[a_offset], lda, &work[itauq] + , &b[b_offset], ldb, &work[nwork], &i__1, info); + +/* Solve the bidiagonal least squares problem. */ + + zlalsd_("L", &smlsiz, m, nrhs, &s[1], &rwork[ie], &b[b_offset], + ldb, rcond, rank, &work[nwork], &rwork[nrwork], &iwork[1], + info); + if (*info != 0) { + goto L10; + } + +/* Multiply B by right bidiagonalizing vectors of A. */ + + i__1 = *lwork - nwork + 1; + zunmbr_("P", "L", "N", n, nrhs, m, &a[a_offset], lda, &work[itaup] + , &b[b_offset], ldb, &work[nwork], &i__1, info); + + } + } + +/* Undo scaling. */ + + if (iascl == 1) { + zlascl_("G", &c__0, &c__0, &anrm, &smlnum, n, nrhs, &b[b_offset], ldb, + info); + dlascl_("G", &c__0, &c__0, &smlnum, &anrm, &minmn, &c__1, &s[1], & + minmn, info); + } else if (iascl == 2) { + zlascl_("G", &c__0, &c__0, &anrm, &bignum, n, nrhs, &b[b_offset], ldb, + info); + dlascl_("G", &c__0, &c__0, &bignum, &anrm, &minmn, &c__1, &s[1], & + minmn, info); + } + if (ibscl == 1) { + zlascl_("G", &c__0, &c__0, &smlnum, &bnrm, n, nrhs, &b[b_offset], ldb, + info); + } else if (ibscl == 2) { + zlascl_("G", &c__0, &c__0, &bignum, &bnrm, n, nrhs, &b[b_offset], ldb, + info); + } + +L10: + work[1].r = (doublereal) maxwrk, work[1].i = 0.; + iwork[1] = liwork; + rwork[1] = (doublereal) lrwork; + return 0; + +/* End of ZGELSD */ + +} /* zgelsd_ */ + +/* Subroutine */ int zgeqr2_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__, k; + static doublecomplex alpha; + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *), zlarfg_(integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + ZGEQR2 computes a QR factorization of a complex m by n matrix A: + A = Q * R. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, the elements on and above the diagonal of the array + contain the min(m,n) by n upper trapezoidal matrix R (R is + upper triangular if m >= n); the elements below the diagonal, + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors (see Further Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) COMPLEX*16 array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace) COMPLEX*16 array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(1) H(2) . . . H(k), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGEQR2", &i__1); + return 0; + } + + k = min(*m,*n); + + i__1 = k; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Generate elementary reflector H(i) to annihilate A(i+1:m,i) */ + + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + zlarfg_(&i__2, &a[i__ + i__ * a_dim1], &a[min(i__3,*m) + i__ * a_dim1] + , &c__1, &tau[i__]); + if (i__ < *n) { + +/* Apply H(i)' to A(i:m,i+1:n) from the left */ + + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + i__2 = *m - i__ + 1; + i__3 = *n - i__; + d_cnjg(&z__1, &tau[i__]); + zlarf_("Left", &i__2, &i__3, &a[i__ + i__ * a_dim1], &c__1, &z__1, + &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + i__2 = i__ + i__ * a_dim1; + a[i__2].r = alpha.r, a[i__2].i = alpha.i; + } +/* L10: */ + } + return 0; + +/* End of ZGEQR2 */ + +} /* zgeqr2_ */ + +/* Subroutine */ int zgeqrf_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, k, ib, nb, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int zgeqr2_(integer *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *), xerbla_( + char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlarfb_(char *, char *, char *, char *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static integer ldwork; + extern /* Subroutine */ int zlarft_(char *, char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGEQRF computes a QR factorization of a complex M-by-N matrix A: + A = Q * R. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, the elements on and above the diagonal of the array + contain the min(M,N)-by-N upper trapezoidal matrix R (R is + upper triangular if m >= n); the elements below the diagonal, + with the array TAU, represent the unitary matrix Q as a + product of min(m,n) elementary reflectors (see Further + Details). + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + TAU (output) COMPLEX*16 array, dimension (min(M,N)) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The matrix Q is represented as a product of elementary reflectors + + Q = H(1) H(2) . . . H(k), where k = min(m,n). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), + and tau in TAU(i). + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "ZGEQRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + lwkopt = *n * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGEQRF", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + k = min(*m,*n); + if (k == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *n; + if (nb > 1 && nb < k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "ZGEQRF", " ", m, n, &c_n1, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "ZGEQRF", " ", m, n, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < k && nx < k) { + +/* Use blocked code initially */ + + i__1 = k - nx; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = k - i__ + 1; + ib = min(i__3,nb); + +/* + Compute the QR factorization of the current block + A(i:m,i:i+ib-1) +*/ + + i__3 = *m - i__ + 1; + zgeqr2_(&i__3, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[ + 1], &iinfo); + if (i__ + ib <= *n) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__3 = *m - i__ + 1; + zlarft_("Forward", "Columnwise", &i__3, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H' to A(i:m,i+ib:n) from the left */ + + i__3 = *m - i__ + 1; + i__4 = *n - i__ - ib + 1; + zlarfb_("Left", "Conjugate transpose", "Forward", "Columnwise" + , &i__3, &i__4, &ib, &a[i__ + i__ * a_dim1], lda, & + work[1], &ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, + &work[ib + 1], &ldwork); + } +/* L10: */ + } + } else { + i__ = 1; + } + +/* Use unblocked code to factor the last or only block. */ + + if (i__ <= k) { + i__2 = *m - i__ + 1; + i__1 = *n - i__ + 1; + zgeqr2_(&i__2, &i__1, &a[i__ + i__ * a_dim1], lda, &tau[i__], &work[1] + , &iinfo); + } + + work[1].r = (doublereal) iws, work[1].i = 0.; + return 0; + +/* End of ZGEQRF */ + +} /* zgeqrf_ */ + +/* Subroutine */ int zgesdd_(char *jobz, integer *m, integer *n, + doublecomplex *a, integer *lda, doublereal *s, doublecomplex *u, + integer *ldu, doublecomplex *vt, integer *ldvt, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *iwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, u_dim1, u_offset, vt_dim1, vt_offset, i__1, + i__2, i__3; + + /* Local variables */ + static integer i__, ie, il, ir, iu, blk; + static doublereal dum[1], eps; + static integer iru, ivt, iscl; + static doublereal anrm; + static integer idum[1], ierr, itau, irvt; + extern logical lsame_(char *, char *); + static integer chunk, minmn; + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer wrkbl, itaup, itauq; + static logical wntqa; + static integer nwork; + static logical wntqn, wntqo, wntqs; + extern /* Subroutine */ int zlacp2_(char *, integer *, integer *, + doublereal *, integer *, doublecomplex *, integer *); + static integer mnthr1, mnthr2; + extern /* Subroutine */ int dbdsdc_(char *, char *, integer *, doublereal + *, doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *, doublereal *, integer *, integer *); + + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), xerbla_(char *, integer *), + zgebrd_(integer *, integer *, doublecomplex *, integer *, + doublereal *, doublereal *, doublecomplex *, doublecomplex *, + doublecomplex *, integer *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static doublereal bignum; + extern doublereal zlange_(char *, integer *, integer *, doublecomplex *, + integer *, doublereal *); + extern /* Subroutine */ int zgelqf_(integer *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *, integer * + ), zlacrm_(integer *, integer *, doublecomplex *, integer *, + doublereal *, integer *, doublecomplex *, integer *, doublereal *) + , zlarcm_(integer *, integer *, doublereal *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublereal *), zlascl_(char *, integer *, integer *, doublereal *, + doublereal *, integer *, integer *, doublecomplex *, integer *, + integer *), zgeqrf_(integer *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *, integer * + ); + static integer ldwrkl; + extern /* Subroutine */ int zlacpy_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *), + zlaset_(char *, integer *, integer *, doublecomplex *, + doublecomplex *, doublecomplex *, integer *); + static integer ldwrkr, minwrk, ldwrku, maxwrk; + extern /* Subroutine */ int zungbr_(char *, integer *, integer *, integer + *, doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *); + static integer ldwkvt; + static doublereal smlnum; + static logical wntqas; + extern /* Subroutine */ int zunmbr_(char *, char *, char *, integer *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer * + ), zunglq_(integer *, integer *, integer * + , doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *); + static integer nrwork; + extern /* Subroutine */ int zungqr_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + 8-15-00: Improve consistency of WS calculations (eca) + + + Purpose + ======= + + ZGESDD computes the singular value decomposition (SVD) of a complex + M-by-N matrix A, optionally computing the left and/or right singular + vectors, by using divide-and-conquer method. The SVD is written + + A = U * SIGMA * conjugate-transpose(V) + + where SIGMA is an M-by-N matrix which is zero except for its + min(m,n) diagonal elements, U is an M-by-M unitary matrix, and + V is an N-by-N unitary matrix. The diagonal elements of SIGMA + are the singular values of A; they are real and non-negative, and + are returned in descending order. The first min(m,n) columns of + U and V are the left and right singular vectors of A. + + Note that the routine returns VT = V**H, not V. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + JOBZ (input) CHARACTER*1 + Specifies options for computing all or part of the matrix U: + = 'A': all M columns of U and all N rows of V**H are + returned in the arrays U and VT; + = 'S': the first min(M,N) columns of U and the first + min(M,N) rows of V**H are returned in the arrays U + and VT; + = 'O': If M >= N, the first N columns of U are overwritten + in the array A and all rows of V**H are returned in + the array VT; + otherwise, all columns of U are returned in the + array U and the first M rows of V**H are overwritten + in the array A; + = 'N': no columns of U or rows of V**H are computed. + + M (input) INTEGER + The number of rows of the input matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the input matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the M-by-N matrix A. + On exit, + if JOBZ = 'O', A is overwritten with the first N columns + of U (the left singular vectors, stored + columnwise) if M >= N; + A is overwritten with the first M rows + of V**H (the right singular vectors, stored + rowwise) otherwise. + if JOBZ .ne. 'O', the contents of A are destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + S (output) DOUBLE PRECISION array, dimension (min(M,N)) + The singular values of A, sorted so that S(i) >= S(i+1). + + U (output) COMPLEX*16 array, dimension (LDU,UCOL) + UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N; + UCOL = min(M,N) if JOBZ = 'S'. + If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M + unitary matrix U; + if JOBZ = 'S', U contains the first min(M,N) columns of U + (the left singular vectors, stored columnwise); + if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced. + + LDU (input) INTEGER + The leading dimension of the array U. LDU >= 1; if + JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M. + + VT (output) COMPLEX*16 array, dimension (LDVT,N) + If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the + N-by-N unitary matrix V**H; + if JOBZ = 'S', VT contains the first min(M,N) rows of + V**H (the right singular vectors, stored rowwise); + if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced. + + LDVT (input) INTEGER + The leading dimension of the array VT. LDVT >= 1; if + JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N; + if JOBZ = 'S', LDVT >= min(M,N). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= 1. + if JOBZ = 'N', LWORK >= 2*min(M,N)+max(M,N). + if JOBZ = 'O', + LWORK >= 2*min(M,N)*min(M,N)+2*min(M,N)+max(M,N). + if JOBZ = 'S' or 'A', + LWORK >= min(M,N)*min(M,N)+2*min(M,N)+max(M,N). + For good performance, LWORK should generally be larger. + + If LWORK = -1, a workspace query is assumed. The optimal + size for the WORK array is calculated and stored in WORK(1), + and no other work except argument checking is performed. + + RWORK (workspace) DOUBLE PRECISION array, dimension (MAX(1,LRWORK)) + If JOBZ = 'N', LRWORK >= 5*min(M,N). + Otherwise, + LRWORK >= min(M,N)*max(5*min(M,N)+7,2*max(M,N)+2*min(M,N)+1) + + IWORK (workspace) INTEGER array, dimension (8*min(M,N)) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The updating process of DBDSDC did not converge. + + Further Details + =============== + + Based on contributions by + Ming Gu and Huan Ren, Computer Science Division, University of + California at Berkeley, USA + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --s; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + vt_dim1 = *ldvt; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + minmn = min(*m,*n); + mnthr1 = (integer) (minmn * 17. / 9.); + mnthr2 = (integer) (minmn * 5. / 3.); + wntqa = lsame_(jobz, "A"); + wntqs = lsame_(jobz, "S"); + wntqas = wntqa || wntqs; + wntqo = lsame_(jobz, "O"); + wntqn = lsame_(jobz, "N"); + minwrk = 1; + maxwrk = 1; + + if (! (wntqa || wntqs || wntqo || wntqn)) { + *info = -1; + } else if (*m < 0) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*ldu < 1 || wntqas && *ldu < *m || wntqo && *m < *n && *ldu < * + m) { + *info = -8; + } else if (*ldvt < 1 || wntqa && *ldvt < *n || wntqs && *ldvt < minmn || + wntqo && *m >= *n && *ldvt < *n) { + *info = -10; + } + +/* + Compute workspace + (Note: Comments in the code beginning "Workspace:" describe the + minimal amount of workspace needed at that point in the code, + as well as the preferred amount for good performance. + CWorkspace refers to complex workspace, and RWorkspace to + real workspace. NB refers to the optimal block size for the + immediately following subroutine, as returned by ILAENV.) +*/ + + if (*info == 0 && *m > 0 && *n > 0) { + if (*m >= *n) { + +/* + There is no complex work space needed for bidiagonal SVD + The real work space needed for bidiagonal SVD is BDSPAC + for computing singular values and singular vectors; BDSPAN + for computing singular values only. + BDSPAC = 5*N*N + 7*N + BDSPAN = MAX(7*N+4, 3*N+2+SMLSIZ*(SMLSIZ+8)) +*/ + + if (*m >= mnthr1) { + if (wntqn) { + +/* Path 1 (M much larger than N, JOBZ='N') */ + + maxwrk = *n + *n * ilaenv_(&c__1, "ZGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + (*n << 1) * ilaenv_(& + c__1, "ZGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + maxwrk = max(i__1,i__2); + minwrk = *n * 3; + } else if (wntqo) { + +/* Path 2 (M much larger than N, JOBZ='O') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "ZGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *n * ilaenv_(&c__1, "ZUNGQR", + " ", m, n, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + (*n << 1) * ilaenv_(& + c__1, "ZGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "QLN", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *m * *n + *n * *n + wrkbl; + minwrk = (*n << 1) * *n + *n * 3; + } else if (wntqs) { + +/* Path 3 (M much larger than N, JOBZ='S') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "ZGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *n * ilaenv_(&c__1, "ZUNGQR", + " ", m, n, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + (*n << 1) * ilaenv_(& + c__1, "ZGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "QLN", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *n * *n + wrkbl; + minwrk = *n * *n + *n * 3; + } else if (wntqa) { + +/* Path 4 (M much larger than N, JOBZ='A') */ + + wrkbl = *n + *n * ilaenv_(&c__1, "ZGEQRF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *n + *m * ilaenv_(&c__1, "ZUNGQR", + " ", m, m, n, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + (*n << 1) * ilaenv_(& + c__1, "ZGEBRD", " ", n, n, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "QLN", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *n * *n + wrkbl; + minwrk = *n * *n + (*n << 1) + *m; + } + } else if (*m >= mnthr2) { + +/* Path 5 (M much larger than N, but not as much as MNTHR1) */ + + maxwrk = (*n << 1) + (*m + *n) * ilaenv_(&c__1, "ZGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + minwrk = (*n << 1) + *m; + if (wntqo) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNGBR", "P", n, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNGBR", "Q", m, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + maxwrk += *m * *n; + minwrk += *n * *n; + } else if (wntqs) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNGBR", "P", n, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNGBR", "Q", m, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + } else if (wntqa) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNGBR", "P", n, n, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "Q", m, m, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + } + } else { + +/* Path 6 (M at least N, but not much larger) */ + + maxwrk = (*n << 1) + (*m + *n) * ilaenv_(&c__1, "ZGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + minwrk = (*n << 1) + *m; + if (wntqo) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "QLN", m, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + maxwrk += *m * *n; + minwrk += *n * *n; + } else if (wntqs) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNMBR", "QLN", m, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + } else if (wntqa) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *n * ilaenv_(&c__1, + "ZUNGBR", "PRC", n, n, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*n << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "QLN", m, m, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + } + } + } else { + +/* + There is no complex work space needed for bidiagonal SVD + The real work space needed for bidiagonal SVD is BDSPAC + for computing singular values and singular vectors; BDSPAN + for computing singular values only. + BDSPAC = 5*M*M + 7*M + BDSPAN = MAX(7*M+4, 3*M+2+SMLSIZ*(SMLSIZ+8)) +*/ + + if (*n >= mnthr1) { + if (wntqn) { + +/* Path 1t (N much larger than M, JOBZ='N') */ + + maxwrk = *m + *m * ilaenv_(&c__1, "ZGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + (*m << 1) * ilaenv_(& + c__1, "ZGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + maxwrk = max(i__1,i__2); + minwrk = *m * 3; + } else if (wntqo) { + +/* Path 2t (N much larger than M, JOBZ='O') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "ZGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *m * ilaenv_(&c__1, "ZUNGLQ", + " ", m, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + (*m << 1) * ilaenv_(& + c__1, "ZGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "PRC", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "QLN", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *m * *n + *m * *m + wrkbl; + minwrk = (*m << 1) * *m + *m * 3; + } else if (wntqs) { + +/* Path 3t (N much larger than M, JOBZ='S') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "ZGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *m * ilaenv_(&c__1, "ZUNGLQ", + " ", m, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + (*m << 1) * ilaenv_(& + c__1, "ZGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "PRC", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "QLN", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *m * *m + wrkbl; + minwrk = *m * *m + *m * 3; + } else if (wntqa) { + +/* Path 4t (N much larger than M, JOBZ='A') */ + + wrkbl = *m + *m * ilaenv_(&c__1, "ZGELQF", " ", m, n, & + c_n1, &c_n1, (ftnlen)6, (ftnlen)1); +/* Computing MAX */ + i__1 = wrkbl, i__2 = *m + *n * ilaenv_(&c__1, "ZUNGLQ", + " ", n, n, m, &c_n1, (ftnlen)6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + (*m << 1) * ilaenv_(& + c__1, "ZGEBRD", " ", m, m, &c_n1, &c_n1, (ftnlen) + 6, (ftnlen)1); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "PRC", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); +/* Computing MAX */ + i__1 = wrkbl, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "QLN", m, m, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + wrkbl = max(i__1,i__2); + maxwrk = *m * *m + wrkbl; + minwrk = *m * *m + (*m << 1) + *n; + } + } else if (*n >= mnthr2) { + +/* Path 5t (N much larger than M, but not as much as MNTHR1) */ + + maxwrk = (*m << 1) + (*m + *n) * ilaenv_(&c__1, "ZGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + minwrk = (*m << 1) + *n; + if (wntqo) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "P", m, n, m, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "Q", m, m, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + maxwrk += *m * *n; + minwrk += *m * *m; + } else if (wntqs) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "P", m, n, m, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "Q", m, m, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + } else if (wntqa) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *n * ilaenv_(&c__1, + "ZUNGBR", "P", n, n, m, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "Q", m, m, n, &c_n1, (ftnlen)6, (ftnlen) + 1); + maxwrk = max(i__1,i__2); + } + } else { + +/* Path 6t (N greater than M, but not much larger) */ + + maxwrk = (*m << 1) + (*m + *n) * ilaenv_(&c__1, "ZGEBRD", + " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + minwrk = (*m << 1) + *n; + if (wntqo) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "PRC", m, n, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNMBR", "QLN", m, m, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + maxwrk += *m * *n; + minwrk += *m * *m; + } else if (wntqs) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "PRC", m, n, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "QLN", m, m, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + } else if (wntqa) { +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *n * ilaenv_(&c__1, + "ZUNGBR", "PRC", n, n, m, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); +/* Computing MAX */ + i__1 = maxwrk, i__2 = (*m << 1) + *m * ilaenv_(&c__1, + "ZUNGBR", "QLN", m, m, n, &c_n1, (ftnlen)6, ( + ftnlen)3); + maxwrk = max(i__1,i__2); + } + } + } + maxwrk = max(maxwrk,minwrk); + } + if (*info == 0) { + work[1].r = (doublereal) maxwrk, work[1].i = 0.; + if (*lwork < minwrk && *lwork != -1) { + *info = -13; + } + } + +/* Quick returns */ + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGESDD", &i__1); + return 0; + } + if (*lwork == -1) { + return 0; + } + if (*m == 0 || *n == 0) { + return 0; + } + +/* Get machine constants */ + + eps = PRECISION; + smlnum = sqrt(SAFEMINIMUM) / eps; + bignum = 1. / smlnum; + +/* Scale A if max element outside range [SMLNUM,BIGNUM] */ + + anrm = zlange_("M", m, n, &a[a_offset], lda, dum); + iscl = 0; + if (anrm > 0. && anrm < smlnum) { + iscl = 1; + zlascl_("G", &c__0, &c__0, &anrm, &smlnum, m, n, &a[a_offset], lda, & + ierr); + } else if (anrm > bignum) { + iscl = 1; + zlascl_("G", &c__0, &c__0, &anrm, &bignum, m, n, &a[a_offset], lda, & + ierr); + } + + if (*m >= *n) { + +/* + A has at least as many rows as columns. If A has sufficiently + more rows than columns, first reduce using the QR + decomposition (if sufficient workspace available) +*/ + + if (*m >= mnthr1) { + + if (wntqn) { + +/* + Path 1 (M much larger than N, JOBZ='N') + No singular vectors to be computed +*/ + + itau = 1; + nwork = itau + *n; + +/* + Compute A=Q*R + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: need 0) +*/ + + i__1 = *lwork - nwork + 1; + zgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Zero out below R */ + + i__1 = *n - 1; + i__2 = *n - 1; + zlaset_("L", &i__1, &i__2, &c_b56, &c_b56, &a[a_dim1 + 2], + lda); + ie = 1; + itauq = 1; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A + (CWorkspace: need 3*N, prefer 2*N+2*N*NB) + (RWorkspace: need N) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(n, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + nrwork = ie + *n; + +/* + Perform bidiagonal SVD, compute singular values only + (CWorkspace: 0) + (RWorkspace: need BDSPAN) +*/ + + dbdsdc_("U", "N", n, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + + } else if (wntqo) { + +/* + Path 2 (M much larger than N, JOBZ='O') + N left singular vectors to be overwritten on A and + N right singular vectors to be computed in VT +*/ + + iu = 1; + +/* WORK(IU) is N by N */ + + ldwrku = *n; + ir = iu + ldwrku * *n; + if (*lwork >= *m * *n + *n * *n + *n * 3) { + +/* WORK(IR) is M by N */ + + ldwrkr = *m; + } else { + ldwrkr = (*lwork - *n * *n - *n * 3) / *n; + } + itau = ir + ldwrkr * *n; + nwork = itau + *n; + +/* + Compute A=Q*R + (CWorkspace: need N*N+2*N, prefer M*N+N+N*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + zgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Copy R to WORK( IR ), zeroing out below it */ + + zlacpy_("U", n, n, &a[a_offset], lda, &work[ir], &ldwrkr); + i__1 = *n - 1; + i__2 = *n - 1; + zlaset_("L", &i__1, &i__2, &c_b56, &c_b56, &work[ir + 1], & + ldwrkr); + +/* + Generate Q in A + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + zungqr_(m, n, n, &a[a_offset], lda, &work[itau], &work[nwork], + &i__1, &ierr); + ie = 1; + itauq = itau; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in WORK(IR) + (CWorkspace: need N*N+3*N, prefer M*N+2*N+2*N*NB) + (RWorkspace: need N) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(n, n, &work[ir], &ldwrkr, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of R in WORK(IRU) and computing right singular vectors + of R in WORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *n; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix WORK(IU) + Overwrite WORK(IU) by the left singular vectors of R + (CWorkspace: need 2*N*N+3*N, prefer M*N+N*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[iru], n, &work[iu], &ldwrku); + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", n, n, n, &work[ir], &ldwrkr, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__1, & + ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by the right singular vectors of R + (CWorkspace: need N*N+3*N, prefer M*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", n, n, n, &work[ir], &ldwrkr, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + +/* + Multiply Q in A by left singular vectors of R in + WORK(IU), storing result in WORK(IR) and copying to A + (CWorkspace: need 2*N*N, prefer N*N+M*N) + (RWorkspace: 0) +*/ + + i__1 = *m; + i__2 = ldwrkr; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrkr); + zgemm_("N", "N", &chunk, n, n, &c_b57, &a[i__ + a_dim1], + lda, &work[iu], &ldwrku, &c_b56, &work[ir], & + ldwrkr); + zlacpy_("F", &chunk, n, &work[ir], &ldwrkr, &a[i__ + + a_dim1], lda); +/* L10: */ + } + + } else if (wntqs) { + +/* + Path 3 (M much larger than N, JOBZ='S') + N left singular vectors to be computed in U and + N right singular vectors to be computed in VT +*/ + + ir = 1; + +/* WORK(IR) is N by N */ + + ldwrkr = *n; + itau = ir + ldwrkr * *n; + nwork = itau + *n; + +/* + Compute A=Q*R + (CWorkspace: need N*N+2*N, prefer N*N+N+N*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + zgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Copy R to WORK(IR), zeroing out below it */ + + zlacpy_("U", n, n, &a[a_offset], lda, &work[ir], &ldwrkr); + i__2 = *n - 1; + i__1 = *n - 1; + zlaset_("L", &i__2, &i__1, &c_b56, &c_b56, &work[ir + 1], & + ldwrkr); + +/* + Generate Q in A + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + zungqr_(m, n, n, &a[a_offset], lda, &work[itau], &work[nwork], + &i__2, &ierr); + ie = 1; + itauq = itau; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in WORK(IR) + (CWorkspace: need N*N+3*N, prefer N*N+2*N+2*N*NB) + (RWorkspace: need N) +*/ + + i__2 = *lwork - nwork + 1; + zgebrd_(n, n, &work[ir], &ldwrkr, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *n; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of R + (CWorkspace: need N*N+3*N, prefer N*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[iru], n, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", n, n, n, &work[ir], &ldwrkr, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of R + (CWorkspace: need N*N+3*N, prefer N*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", n, n, n, &work[ir], &ldwrkr, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply Q in A by left singular vectors of R in + WORK(IR), storing result in U + (CWorkspace: need N*N) + (RWorkspace: 0) +*/ + + zlacpy_("F", n, n, &u[u_offset], ldu, &work[ir], &ldwrkr); + zgemm_("N", "N", m, n, n, &c_b57, &a[a_offset], lda, &work[ir] + , &ldwrkr, &c_b56, &u[u_offset], ldu); + + } else if (wntqa) { + +/* + Path 4 (M much larger than N, JOBZ='A') + M left singular vectors to be computed in U and + N right singular vectors to be computed in VT +*/ + + iu = 1; + +/* WORK(IU) is N by N */ + + ldwrku = *n; + itau = iu + ldwrku * *n; + nwork = itau + *n; + +/* + Compute A=Q*R, copying result to U + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + zgeqrf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + zlacpy_("L", m, n, &a[a_offset], lda, &u[u_offset], ldu); + +/* + Generate Q in U + (CWorkspace: need N+M, prefer N+M*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + zungqr_(m, m, n, &u[u_offset], ldu, &work[itau], &work[nwork], + &i__2, &ierr); + +/* Produce R in A, zeroing out below it */ + + i__2 = *n - 1; + i__1 = *n - 1; + zlaset_("L", &i__2, &i__1, &c_b56, &c_b56, &a[a_dim1 + 2], + lda); + ie = 1; + itauq = itau; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize R in A + (CWorkspace: need 3*N, prefer 2*N+2*N*NB) + (RWorkspace: need N) +*/ + + i__2 = *lwork - nwork + 1; + zgebrd_(n, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + iru = ie + *n; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix WORK(IU) + Overwrite WORK(IU) by left singular vectors of R + (CWorkspace: need N*N+3*N, prefer N*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[iru], n, &work[iu], &ldwrku); + i__2 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", n, n, n, &a[a_offset], lda, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__2, & + ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of R + (CWorkspace: need 3*N, prefer 2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply Q in U by left singular vectors of R in + WORK(IU), storing result in A + (CWorkspace: need N*N) + (RWorkspace: 0) +*/ + + zgemm_("N", "N", m, n, n, &c_b57, &u[u_offset], ldu, &work[iu] + , &ldwrku, &c_b56, &a[a_offset], lda); + +/* Copy left singular vectors of A from A to U */ + + zlacpy_("F", m, n, &a[a_offset], lda, &u[u_offset], ldu); + + } + + } else if (*m >= mnthr2) { + +/* + MNTHR2 <= M < MNTHR1 + + Path 5 (M much larger than N, but not as much as MNTHR1) + Reduce to bidiagonal form without QR decomposition, use + ZUNGBR and matrix multiplication to compute singular vectors +*/ + + ie = 1; + nrwork = ie + *n; + itauq = 1; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize A + (CWorkspace: need 2*N+M, prefer 2*N+(M+N)*NB) + (RWorkspace: need N) +*/ + + i__2 = *lwork - nwork + 1; + zgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__2, &ierr); + if (wntqn) { + +/* + Compute singular values only + (Cworkspace: 0) + (Rworkspace: need BDSPAN) +*/ + + dbdsdc_("U", "N", n, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + } else if (wntqo) { + iu = nwork; + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + zlacpy_("U", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + zungbr_("P", n, n, n, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Generate Q in A + (CWorkspace: need 2*N, prefer N+N*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + zungbr_("Q", m, n, n, &a[a_offset], lda, &work[itauq], &work[ + nwork], &i__2, &ierr); + + if (*lwork >= *m * *n + *n * 3) { + +/* WORK( IU ) is M by N */ + + ldwrku = *m; + } else { + +/* WORK(IU) is LDWRKU by N */ + + ldwrku = (*lwork - *n * 3) / *n; + } + nwork = iu + ldwrku * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in WORK(IU), copying to VT + (Cworkspace: need 0) + (Rworkspace: need 3*N*N) +*/ + + zlarcm_(n, n, &rwork[irvt], n, &vt[vt_offset], ldvt, &work[iu] + , &ldwrku, &rwork[nrwork]); + zlacpy_("F", n, n, &work[iu], &ldwrku, &vt[vt_offset], ldvt); + +/* + Multiply Q in A by real matrix RWORK(IRU), storing the + result in WORK(IU), copying to A + (CWorkspace: need N*N, prefer M*N) + (Rworkspace: need 3*N*N, prefer N*N+2*M*N) +*/ + + nrwork = irvt; + i__2 = *m; + i__1 = ldwrku; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrku); + zlacrm_(&chunk, n, &a[i__ + a_dim1], lda, &rwork[iru], n, + &work[iu], &ldwrku, &rwork[nrwork]); + zlacpy_("F", &chunk, n, &work[iu], &ldwrku, &a[i__ + + a_dim1], lda); +/* L20: */ + } + + } else if (wntqs) { + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + zlacpy_("U", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + zungbr_("P", n, n, n, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__1, &ierr); + +/* + Copy A to U, generate Q + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + zlacpy_("L", m, n, &a[a_offset], lda, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + zungbr_("Q", m, n, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in A, copying to VT + (Cworkspace: need 0) + (Rworkspace: need 3*N*N) +*/ + + zlarcm_(n, n, &rwork[irvt], n, &vt[vt_offset], ldvt, &a[ + a_offset], lda, &rwork[nrwork]); + zlacpy_("F", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + +/* + Multiply Q in U by real matrix RWORK(IRU), storing the + result in A, copying to U + (CWorkspace: need 0) + (Rworkspace: need N*N+2*M*N) +*/ + + nrwork = irvt; + zlacrm_(m, n, &u[u_offset], ldu, &rwork[iru], n, &a[a_offset], + lda, &rwork[nrwork]); + zlacpy_("F", m, n, &a[a_offset], lda, &u[u_offset], ldu); + } else { + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + zlacpy_("U", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + zungbr_("P", n, n, n, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__1, &ierr); + +/* + Copy A to U, generate Q + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: 0) +*/ + + zlacpy_("L", m, n, &a[a_offset], lda, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + zungbr_("Q", m, m, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in A, copying to VT + (Cworkspace: need 0) + (Rworkspace: need 3*N*N) +*/ + + zlarcm_(n, n, &rwork[irvt], n, &vt[vt_offset], ldvt, &a[ + a_offset], lda, &rwork[nrwork]); + zlacpy_("F", n, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + +/* + Multiply Q in U by real matrix RWORK(IRU), storing the + result in A, copying to U + (CWorkspace: 0) + (Rworkspace: need 3*N*N) +*/ + + nrwork = irvt; + zlacrm_(m, n, &u[u_offset], ldu, &rwork[iru], n, &a[a_offset], + lda, &rwork[nrwork]); + zlacpy_("F", m, n, &a[a_offset], lda, &u[u_offset], ldu); + } + + } else { + +/* + M .LT. MNTHR2 + + Path 6 (M at least N, but not much larger) + Reduce to bidiagonal form without QR decomposition + Use ZUNMBR to compute singular vectors +*/ + + ie = 1; + nrwork = ie + *n; + itauq = 1; + itaup = itauq + *n; + nwork = itaup + *n; + +/* + Bidiagonalize A + (CWorkspace: need 2*N+M, prefer 2*N+(M+N)*NB) + (RWorkspace: need N) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__1, &ierr); + if (wntqn) { + +/* + Compute singular values only + (Cworkspace: 0) + (Rworkspace: need BDSPAN) +*/ + + dbdsdc_("U", "N", n, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + } else if (wntqo) { + iu = nwork; + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + if (*lwork >= *m * *n + *n * 3) { + +/* WORK( IU ) is M by N */ + + ldwrku = *m; + } else { + +/* WORK( IU ) is LDWRKU by N */ + + ldwrku = (*lwork - *n * 3) / *n; + } + nwork = iu + ldwrku * *n; + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: need 0) +*/ + + zlacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + + if (*lwork >= *m * *n + *n * 3) { + +/* + Copy real matrix RWORK(IRU) to complex matrix WORK(IU) + Overwrite WORK(IU) by left singular vectors of A, copying + to A + (Cworkspace: need M*N+2*N, prefer M*N+N+N*NB) + (Rworkspace: need 0) +*/ + + zlaset_("F", m, n, &c_b56, &c_b56, &work[iu], &ldwrku); + zlacp2_("F", n, n, &rwork[iru], n, &work[iu], &ldwrku); + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, n, n, &a[a_offset], lda, &work[ + itauq], &work[iu], &ldwrku, &work[nwork], &i__1, & + ierr); + zlacpy_("F", m, n, &work[iu], &ldwrku, &a[a_offset], lda); + } else { + +/* + Generate Q in A + (Cworkspace: need 2*N, prefer N+N*NB) + (Rworkspace: need 0) +*/ + + i__1 = *lwork - nwork + 1; + zungbr_("Q", m, n, n, &a[a_offset], lda, &work[itauq], & + work[nwork], &i__1, &ierr); + +/* + Multiply Q in A by real matrix RWORK(IRU), storing the + result in WORK(IU), copying to A + (CWorkspace: need N*N, prefer M*N) + (Rworkspace: need 3*N*N, prefer N*N+2*M*N) +*/ + + nrwork = irvt; + i__1 = *m; + i__2 = ldwrku; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *m - i__ + 1; + chunk = min(i__3,ldwrku); + zlacrm_(&chunk, n, &a[i__ + a_dim1], lda, &rwork[iru], + n, &work[iu], &ldwrku, &rwork[nrwork]); + zlacpy_("F", &chunk, n, &work[iu], &ldwrku, &a[i__ + + a_dim1], lda); +/* L30: */ + } + } + + } else if (wntqs) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (CWorkspace: need 3*N, prefer 2*N+N*NB) + (RWorkspace: 0) +*/ + + zlaset_("F", m, n, &c_b56, &c_b56, &u[u_offset], ldu); + zlacp2_("F", n, n, &rwork[iru], n, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, n, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (CWorkspace: need 3*N, prefer 2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + } else { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = nrwork; + irvt = iru + *n * *n; + nrwork = irvt + *n * *n; + dbdsdc_("U", "I", n, &s[1], &rwork[ie], &rwork[iru], n, & + rwork[irvt], n, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* Set the right corner of U to identity matrix */ + + zlaset_("F", m, m, &c_b56, &c_b56, &u[u_offset], ldu); + if (*m > *n) { + i__2 = *m - *n; + i__1 = *m - *n; + zlaset_("F", &i__2, &i__1, &c_b56, &c_b57, &u[*n + 1 + (* + n + 1) * u_dim1], ldu); + } + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (CWorkspace: need 2*N+M, prefer 2*N+M*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[iru], n, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (CWorkspace: need 3*N, prefer 2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", n, n, &rwork[irvt], n, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", n, n, n, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__2, & + ierr); + } + + } + + } else { + +/* + A has more columns than rows. If A has sufficiently more + columns than rows, first reduce using the LQ decomposition (if + sufficient workspace available) +*/ + + if (*n >= mnthr1) { + + if (wntqn) { + +/* + Path 1t (N much larger than M, JOBZ='N') + No singular vectors to be computed +*/ + + itau = 1; + nwork = itau + *m; + +/* + Compute A=L*Q + (CWorkspace: need 2*M, prefer M+M*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + zgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Zero out above L */ + + i__2 = *m - 1; + i__1 = *m - 1; + zlaset_("U", &i__2, &i__1, &c_b56, &c_b56, &a[(a_dim1 << 1) + + 1], lda); + ie = 1; + itauq = 1; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in A + (CWorkspace: need 3*M, prefer 2*M+2*M*NB) + (RWorkspace: need M) +*/ + + i__2 = *lwork - nwork + 1; + zgebrd_(m, m, &a[a_offset], lda, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + nrwork = ie + *m; + +/* + Perform bidiagonal SVD, compute singular values only + (CWorkspace: 0) + (RWorkspace: need BDSPAN) +*/ + + dbdsdc_("U", "N", m, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + + } else if (wntqo) { + +/* + Path 2t (N much larger than M, JOBZ='O') + M right singular vectors to be overwritten on A and + M left singular vectors to be computed in U +*/ + + ivt = 1; + ldwkvt = *m; + +/* WORK(IVT) is M by M */ + + il = ivt + ldwkvt * *m; + if (*lwork >= *m * *n + *m * *m + *m * 3) { + +/* WORK(IL) M by N */ + + ldwrkl = *m; + chunk = *n; + } else { + +/* WORK(IL) is M by CHUNK */ + + ldwrkl = *m; + chunk = (*lwork - *m * *m - *m * 3) / *m; + } + itau = il + ldwrkl * chunk; + nwork = itau + *m; + +/* + Compute A=L*Q + (CWorkspace: need 2*M, prefer M+M*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + zgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__2, &ierr); + +/* Copy L to WORK(IL), zeroing about above it */ + + zlacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwrkl); + i__2 = *m - 1; + i__1 = *m - 1; + zlaset_("U", &i__2, &i__1, &c_b56, &c_b56, &work[il + ldwrkl], + &ldwrkl); + +/* + Generate Q in A + (CWorkspace: need M*M+2*M, prefer M*M+M+M*NB) + (RWorkspace: 0) +*/ + + i__2 = *lwork - nwork + 1; + zunglq_(m, n, m, &a[a_offset], lda, &work[itau], &work[nwork], + &i__2, &ierr); + ie = 1; + itauq = itau; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IL) + (CWorkspace: need M*M+3*M, prefer M*M+2*M+2*M*NB) + (RWorkspace: need M) +*/ + + i__2 = *lwork - nwork + 1; + zgebrd_(m, m, &work[il], &ldwrkl, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *m; + irvt = iru + *m * *m; + nrwork = irvt + *m * *m; + dbdsdc_("U", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix WORK(IU) + Overwrite WORK(IU) by the left singular vectors of L + (CWorkspace: need N*N+3*N, prefer M*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, m, m, &work[il], &ldwrkl, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix WORK(IVT) + Overwrite WORK(IVT) by the right singular vectors of L + (CWorkspace: need N*N+3*N, prefer M*N+2*N+N*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", m, m, &rwork[irvt], m, &work[ivt], &ldwkvt); + i__2 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", m, m, m, &work[il], &ldwrkl, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__2, & + ierr); + +/* + Multiply right singular vectors of L in WORK(IL) by Q + in A, storing result in WORK(IL) and copying to A + (CWorkspace: need 2*M*M, prefer M*M+M*N)) + (RWorkspace: 0) +*/ + + i__2 = *n; + i__1 = chunk; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + zgemm_("N", "N", m, &blk, m, &c_b57, &work[ivt], m, &a[ + i__ * a_dim1 + 1], lda, &c_b56, &work[il], & + ldwrkl); + zlacpy_("F", m, &blk, &work[il], &ldwrkl, &a[i__ * a_dim1 + + 1], lda); +/* L40: */ + } + + } else if (wntqs) { + +/* + Path 3t (N much larger than M, JOBZ='S') + M right singular vectors to be computed in VT and + M left singular vectors to be computed in U +*/ + + il = 1; + +/* WORK(IL) is M by M */ + + ldwrkl = *m; + itau = il + ldwrkl * *m; + nwork = itau + *m; + +/* + Compute A=L*Q + (CWorkspace: need 2*M, prefer M+M*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + zgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + +/* Copy L to WORK(IL), zeroing out above it */ + + zlacpy_("L", m, m, &a[a_offset], lda, &work[il], &ldwrkl); + i__1 = *m - 1; + i__2 = *m - 1; + zlaset_("U", &i__1, &i__2, &c_b56, &c_b56, &work[il + ldwrkl], + &ldwrkl); + +/* + Generate Q in A + (CWorkspace: need M*M+2*M, prefer M*M+M+M*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + zunglq_(m, n, m, &a[a_offset], lda, &work[itau], &work[nwork], + &i__1, &ierr); + ie = 1; + itauq = itau; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in WORK(IL) + (CWorkspace: need M*M+3*M, prefer M*M+2*M+2*M*NB) + (RWorkspace: need M) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(m, m, &work[il], &ldwrkl, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *m; + irvt = iru + *m * *m; + nrwork = irvt + *m * *m; + dbdsdc_("U", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of L + (CWorkspace: need M*M+3*M, prefer M*M+2*M+M*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, m, m, &work[il], &ldwrkl, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by left singular vectors of L + (CWorkspace: need M*M+3*M, prefer M*M+2*M+M*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", m, m, &rwork[irvt], m, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", m, m, m, &work[il], &ldwrkl, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + +/* + Copy VT to WORK(IL), multiply right singular vectors of L + in WORK(IL) by Q in A, storing result in VT + (CWorkspace: need M*M) + (RWorkspace: 0) +*/ + + zlacpy_("F", m, m, &vt[vt_offset], ldvt, &work[il], &ldwrkl); + zgemm_("N", "N", m, n, m, &c_b57, &work[il], &ldwrkl, &a[ + a_offset], lda, &c_b56, &vt[vt_offset], ldvt); + + } else if (wntqa) { + +/* + Path 9t (N much larger than M, JOBZ='A') + N right singular vectors to be computed in VT and + M left singular vectors to be computed in U +*/ + + ivt = 1; + +/* WORK(IVT) is M by M */ + + ldwkvt = *m; + itau = ivt + ldwkvt * *m; + nwork = itau + *m; + +/* + Compute A=L*Q, copying result to VT + (CWorkspace: need 2*M, prefer M+M*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + zgelqf_(m, n, &a[a_offset], lda, &work[itau], &work[nwork], & + i__1, &ierr); + zlacpy_("U", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + +/* + Generate Q in VT + (CWorkspace: need M+N, prefer M+N*NB) + (RWorkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + zunglq_(n, n, m, &vt[vt_offset], ldvt, &work[itau], &work[ + nwork], &i__1, &ierr); + +/* Produce L in A, zeroing out above it */ + + i__1 = *m - 1; + i__2 = *m - 1; + zlaset_("U", &i__1, &i__2, &c_b56, &c_b56, &a[(a_dim1 << 1) + + 1], lda); + ie = 1; + itauq = itau; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize L in A + (CWorkspace: need M*M+3*M, prefer M*M+2*M+2*M*NB) + (RWorkspace: need M) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(m, m, &a[a_offset], lda, &s[1], &rwork[ie], &work[ + itauq], &work[itaup], &work[nwork], &i__1, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + iru = ie + *m; + irvt = iru + *m * *m; + nrwork = irvt + *m * *m; + dbdsdc_("U", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of L + (CWorkspace: need 3*M, prefer 2*M+M*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, m, m, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix WORK(IVT) + Overwrite WORK(IVT) by right singular vectors of L + (CWorkspace: need M*M+3*M, prefer M*M+2*M+M*NB) + (RWorkspace: 0) +*/ + + zlacp2_("F", m, m, &rwork[irvt], m, &work[ivt], &ldwkvt); + i__1 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", m, m, m, &a[a_offset], lda, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__1, & + ierr); + +/* + Multiply right singular vectors of L in WORK(IVT) by + Q in VT, storing result in A + (CWorkspace: need M*M) + (RWorkspace: 0) +*/ + + zgemm_("N", "N", m, n, m, &c_b57, &work[ivt], &ldwkvt, &vt[ + vt_offset], ldvt, &c_b56, &a[a_offset], lda); + +/* Copy right singular vectors of A from A to VT */ + + zlacpy_("F", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + + } + + } else if (*n >= mnthr2) { + +/* + MNTHR2 <= N < MNTHR1 + + Path 5t (N much larger than M, but not as much as MNTHR1) + Reduce to bidiagonal form without QR decomposition, use + ZUNGBR and matrix multiplication to compute singular vectors +*/ + + + ie = 1; + nrwork = ie + *m; + itauq = 1; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize A + (CWorkspace: need 2*M+N, prefer 2*M+(M+N)*NB) + (RWorkspace: M) +*/ + + i__1 = *lwork - nwork + 1; + zgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__1, &ierr); + + if (wntqn) { + +/* + Compute singular values only + (Cworkspace: 0) + (Rworkspace: need BDSPAN) +*/ + + dbdsdc_("L", "N", m, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + } else if (wntqo) { + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + ivt = nwork; + +/* + Copy A to U, generate Q + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + zlacpy_("L", m, m, &a[a_offset], lda, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + zungbr_("Q", m, m, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__1, &ierr); + +/* + Generate P**H in A + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + i__1 = *lwork - nwork + 1; + zungbr_("P", m, n, m, &a[a_offset], lda, &work[itaup], &work[ + nwork], &i__1, &ierr); + + ldwkvt = *m; + if (*lwork >= *m * *n + *m * 3) { + +/* WORK( IVT ) is M by N */ + + nwork = ivt + ldwkvt * *n; + chunk = *n; + } else { + +/* WORK( IVT ) is M by CHUNK */ + + chunk = (*lwork - *m * 3) / *m; + nwork = ivt + ldwkvt * chunk; + } + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + dbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply Q in U by real matrix RWORK(IRVT) + storing the result in WORK(IVT), copying to U + (Cworkspace: need 0) + (Rworkspace: need 2*M*M) +*/ + + zlacrm_(m, m, &u[u_offset], ldu, &rwork[iru], m, &work[ivt], & + ldwkvt, &rwork[nrwork]); + zlacpy_("F", m, m, &work[ivt], &ldwkvt, &u[u_offset], ldu); + +/* + Multiply RWORK(IRVT) by P**H in A, storing the + result in WORK(IVT), copying to A + (CWorkspace: need M*M, prefer M*N) + (Rworkspace: need 2*M*M, prefer 2*M*N) +*/ + + nrwork = iru; + i__1 = *n; + i__2 = chunk; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + zlarcm_(m, &blk, &rwork[irvt], m, &a[i__ * a_dim1 + 1], + lda, &work[ivt], &ldwkvt, &rwork[nrwork]); + zlacpy_("F", m, &blk, &work[ivt], &ldwkvt, &a[i__ * + a_dim1 + 1], lda); +/* L50: */ + } + } else if (wntqs) { + +/* + Copy A to U, generate Q + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + zlacpy_("L", m, m, &a[a_offset], lda, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + zungbr_("Q", m, m, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__2, &ierr); + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + zlacpy_("U", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + zungbr_("P", m, n, m, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + dbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply Q in U by real matrix RWORK(IRU), storing the + result in A, copying to U + (CWorkspace: need 0) + (Rworkspace: need 3*M*M) +*/ + + zlacrm_(m, m, &u[u_offset], ldu, &rwork[iru], m, &a[a_offset], + lda, &rwork[nrwork]); + zlacpy_("F", m, m, &a[a_offset], lda, &u[u_offset], ldu); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in A, copying to VT + (Cworkspace: need 0) + (Rworkspace: need M*M+2*M*N) +*/ + + nrwork = iru; + zlarcm_(m, n, &rwork[irvt], m, &vt[vt_offset], ldvt, &a[ + a_offset], lda, &rwork[nrwork]); + zlacpy_("F", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + } else { + +/* + Copy A to U, generate Q + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + zlacpy_("L", m, m, &a[a_offset], lda, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + zungbr_("Q", m, m, n, &u[u_offset], ldu, &work[itauq], &work[ + nwork], &i__2, &ierr); + +/* + Copy A to VT, generate P**H + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: 0) +*/ + + zlacpy_("U", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + i__2 = *lwork - nwork + 1; + zungbr_("P", n, n, m, &vt[vt_offset], ldvt, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + dbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Multiply Q in U by real matrix RWORK(IRU), storing the + result in A, copying to U + (CWorkspace: need 0) + (Rworkspace: need 3*M*M) +*/ + + zlacrm_(m, m, &u[u_offset], ldu, &rwork[iru], m, &a[a_offset], + lda, &rwork[nrwork]); + zlacpy_("F", m, m, &a[a_offset], lda, &u[u_offset], ldu); + +/* + Multiply real matrix RWORK(IRVT) by P**H in VT, + storing the result in A, copying to VT + (Cworkspace: need 0) + (Rworkspace: need M*M+2*M*N) +*/ + + zlarcm_(m, n, &rwork[irvt], m, &vt[vt_offset], ldvt, &a[ + a_offset], lda, &rwork[nrwork]); + zlacpy_("F", m, n, &a[a_offset], lda, &vt[vt_offset], ldvt); + } + + } else { + +/* + N .LT. MNTHR2 + + Path 6t (N greater than M, but not much larger) + Reduce to bidiagonal form without LQ decomposition + Use ZUNMBR to compute singular vectors +*/ + + ie = 1; + nrwork = ie + *m; + itauq = 1; + itaup = itauq + *m; + nwork = itaup + *m; + +/* + Bidiagonalize A + (CWorkspace: need 2*M+N, prefer 2*M+(M+N)*NB) + (RWorkspace: M) +*/ + + i__2 = *lwork - nwork + 1; + zgebrd_(m, n, &a[a_offset], lda, &s[1], &rwork[ie], &work[itauq], + &work[itaup], &work[nwork], &i__2, &ierr); + if (wntqn) { + +/* + Compute singular values only + (Cworkspace: 0) + (Rworkspace: need BDSPAN) +*/ + + dbdsdc_("L", "N", m, &s[1], &rwork[ie], dum, &c__1, dum, & + c__1, dum, idum, &rwork[nrwork], &iwork[1], info); + } else if (wntqo) { + ldwkvt = *m; + ivt = nwork; + if (*lwork >= *m * *n + *m * 3) { + +/* WORK( IVT ) is M by N */ + + zlaset_("F", m, n, &c_b56, &c_b56, &work[ivt], &ldwkvt); + nwork = ivt + ldwkvt * *n; + } else { + +/* WORK( IVT ) is M by CHUNK */ + + chunk = (*lwork - *m * 3) / *m; + nwork = ivt + ldwkvt * chunk; + } + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + dbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: need 0) +*/ + + zlacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__2 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__2, &ierr); + + if (*lwork >= *m * *n + *m * 3) { + +/* + Copy real matrix RWORK(IRVT) to complex matrix WORK(IVT) + Overwrite WORK(IVT) by right singular vectors of A, + copying to A + (Cworkspace: need M*N+2*M, prefer M*N+M+M*NB) + (Rworkspace: need 0) +*/ + + zlacp2_("F", m, m, &rwork[irvt], m, &work[ivt], &ldwkvt); + i__2 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", m, n, m, &a[a_offset], lda, &work[ + itaup], &work[ivt], &ldwkvt, &work[nwork], &i__2, + &ierr); + zlacpy_("F", m, n, &work[ivt], &ldwkvt, &a[a_offset], lda); + } else { + +/* + Generate P**H in A + (Cworkspace: need 2*M, prefer M+M*NB) + (Rworkspace: need 0) +*/ + + i__2 = *lwork - nwork + 1; + zungbr_("P", m, n, m, &a[a_offset], lda, &work[itaup], & + work[nwork], &i__2, &ierr); + +/* + Multiply Q in A by real matrix RWORK(IRU), storing the + result in WORK(IU), copying to A + (CWorkspace: need M*M, prefer M*N) + (Rworkspace: need 3*M*M, prefer M*M+2*M*N) +*/ + + nrwork = iru; + i__2 = *n; + i__1 = chunk; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += + i__1) { +/* Computing MIN */ + i__3 = *n - i__ + 1; + blk = min(i__3,chunk); + zlarcm_(m, &blk, &rwork[irvt], m, &a[i__ * a_dim1 + 1] + , lda, &work[ivt], &ldwkvt, &rwork[nrwork]); + zlacpy_("F", m, &blk, &work[ivt], &ldwkvt, &a[i__ * + a_dim1 + 1], lda); +/* L60: */ + } + } + } else if (wntqs) { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + dbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (CWorkspace: need 3*M, prefer 2*M+M*NB) + (RWorkspace: M*M) +*/ + + zlacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (CWorkspace: need 3*M, prefer 2*M+M*NB) + (RWorkspace: M*M) +*/ + + zlaset_("F", m, n, &c_b56, &c_b56, &vt[vt_offset], ldvt); + zlacp2_("F", m, m, &rwork[irvt], m, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", m, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } else { + +/* + Perform bidiagonal SVD, computing left singular vectors + of bidiagonal matrix in RWORK(IRU) and computing right + singular vectors of bidiagonal matrix in RWORK(IRVT) + (CWorkspace: need 0) + (RWorkspace: need BDSPAC) +*/ + + irvt = nrwork; + iru = irvt + *m * *m; + nrwork = iru + *m * *m; + + dbdsdc_("L", "I", m, &s[1], &rwork[ie], &rwork[iru], m, & + rwork[irvt], m, dum, idum, &rwork[nrwork], &iwork[1], + info); + +/* + Copy real matrix RWORK(IRU) to complex matrix U + Overwrite U by left singular vectors of A + (CWorkspace: need 3*M, prefer 2*M+M*NB) + (RWorkspace: M*M) +*/ + + zlacp2_("F", m, m, &rwork[iru], m, &u[u_offset], ldu); + i__1 = *lwork - nwork + 1; + zunmbr_("Q", "L", "N", m, m, n, &a[a_offset], lda, &work[ + itauq], &u[u_offset], ldu, &work[nwork], &i__1, &ierr); + +/* Set all of VT to identity matrix */ + + zlaset_("F", n, n, &c_b56, &c_b57, &vt[vt_offset], ldvt); + +/* + Copy real matrix RWORK(IRVT) to complex matrix VT + Overwrite VT by right singular vectors of A + (CWorkspace: need 2*M+N, prefer 2*M+N*NB) + (RWorkspace: M*M) +*/ + + zlacp2_("F", m, m, &rwork[irvt], m, &vt[vt_offset], ldvt); + i__1 = *lwork - nwork + 1; + zunmbr_("P", "R", "C", n, n, m, &a[a_offset], lda, &work[ + itaup], &vt[vt_offset], ldvt, &work[nwork], &i__1, & + ierr); + } + + } + + } + +/* Undo scaling if necessary */ + + if (iscl == 1) { + if (anrm > bignum) { + dlascl_("G", &c__0, &c__0, &bignum, &anrm, &minmn, &c__1, &s[1], & + minmn, &ierr); + } + if (*info != 0 && anrm > bignum) { + i__1 = minmn - 1; + dlascl_("G", &c__0, &c__0, &bignum, &anrm, &i__1, &c__1, &rwork[ + ie], &minmn, &ierr); + } + if (anrm < smlnum) { + dlascl_("G", &c__0, &c__0, &smlnum, &anrm, &minmn, &c__1, &s[1], & + minmn, &ierr); + } + if (*info != 0 && anrm < smlnum) { + i__1 = minmn - 1; + dlascl_("G", &c__0, &c__0, &smlnum, &anrm, &i__1, &c__1, &rwork[ + ie], &minmn, &ierr); + } + } + +/* Return optimal workspace in WORK(1) */ + + work[1].r = (doublereal) maxwrk, work[1].i = 0.; + + return 0; + +/* End of ZGESDD */ + +} /* zgesdd_ */ + +/* Subroutine */ int zgesv_(integer *n, integer *nrhs, doublecomplex *a, + integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, integer * + info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern /* Subroutine */ int xerbla_(char *, integer *), zgetrf_( + integer *, integer *, doublecomplex *, integer *, integer *, + integer *), zgetrs_(char *, integer *, integer *, doublecomplex *, + integer *, integer *, doublecomplex *, integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGESV computes the solution to a complex system of linear equations + A * X = B, + where A is an N-by-N matrix and X and B are N-by-NRHS matrices. + + The LU decomposition with partial pivoting and row interchanges is + used to factor A as + A = P * L * U, + where P is a permutation matrix, L is unit lower triangular, and U is + upper triangular. The factored form of A is then used to solve the + system of equations A * X = B. + + Arguments + ========= + + N (input) INTEGER + The number of linear equations, i.e., the order of the + matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the N-by-N coefficient matrix A. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (output) INTEGER array, dimension (N) + The pivot indices that define the permutation matrix P; + row i of the matrix was interchanged with row IPIV(i). + + B (input/output) COMPLEX*16 array, dimension (LDB,NRHS) + On entry, the N-by-NRHS matrix of right hand side matrix B. + On exit, if INFO = 0, the N-by-NRHS solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, so the solution could not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + if (*n < 0) { + *info = -1; + } else if (*nrhs < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGESV ", &i__1); + return 0; + } + +/* Compute the LU factorization of A. */ + + zgetrf_(n, n, &a[a_offset], lda, &ipiv[1], info); + if (*info == 0) { + +/* Solve the system A*X = B, overwriting B with X. */ + + zgetrs_("No transpose", n, nrhs, &a[a_offset], lda, &ipiv[1], &b[ + b_offset], ldb, info); + } + return 0; + +/* End of ZGESV */ + +} /* zgesv_ */ + +/* Subroutine */ int zgetf2_(integer *m, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, jp; + static doublereal sfmin; + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *), zgeru_(integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, integer *), zswap_(integer *, + doublecomplex *, integer *, doublecomplex *, integer *); + + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer izamax_(integer *, doublecomplex *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGETF2 computes an LU factorization of a general m-by-n matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 2 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the m by n matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, U(k,k) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGETF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Compute machine safe minimum */ + + sfmin = SAFEMINIMUM; + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + +/* Find pivot and test for singularity. */ + + i__2 = *m - j + 1; + jp = j - 1 + izamax_(&i__2, &a[j + j * a_dim1], &c__1); + ipiv[j] = jp; + i__2 = jp + j * a_dim1; + if (a[i__2].r != 0. || a[i__2].i != 0.) { + +/* Apply the interchange to columns 1:N. */ + + if (jp != j) { + zswap_(n, &a[j + a_dim1], lda, &a[jp + a_dim1], lda); + } + +/* Compute elements J+1:M of J-th column. */ + + if (j < *m) { + if (z_abs(&a[j + j * a_dim1]) >= sfmin) { + i__2 = *m - j; + z_div(&z__1, &c_b57, &a[j + j * a_dim1]); + zscal_(&i__2, &z__1, &a[j + 1 + j * a_dim1], &c__1); + } else { + i__2 = *m - j; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ + j * a_dim1; + z_div(&z__1, &a[j + i__ + j * a_dim1], &a[j + j * + a_dim1]); + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L20: */ + } + } + } + + } else if (*info == 0) { + + *info = j; + } + + if (j < min(*m,*n)) { + +/* Update trailing submatrix. */ + + i__2 = *m - j; + i__3 = *n - j; + z__1.r = -1., z__1.i = -0.; + zgeru_(&i__2, &i__3, &z__1, &a[j + 1 + j * a_dim1], &c__1, &a[j + + (j + 1) * a_dim1], lda, &a[j + 1 + (j + 1) * a_dim1], lda) + ; + } +/* L10: */ + } + return 0; + +/* End of ZGETF2 */ + +} /* zgetf2_ */ + +/* Subroutine */ int zgetrf_(integer *m, integer *n, doublecomplex *a, + integer *lda, integer *ipiv, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, jb, nb, iinfo; + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), ztrsm_(char *, char *, char *, char *, + integer *, integer *, doublecomplex *, doublecomplex *, integer * + , doublecomplex *, integer *), + zgetf2_(integer *, integer *, doublecomplex *, integer *, integer + *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlaswp_(integer *, doublecomplex *, integer *, + integer *, integer *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGETRF computes an LU factorization of a general M-by-N matrix A + using partial pivoting with row interchanges. + + The factorization has the form + A = P * L * U + where P is a permutation matrix, L is lower triangular with unit + diagonal elements (lower trapezoidal if m > n), and U is upper + triangular (upper trapezoidal if m < n). + + This is the right-looking Level 3 BLAS version of the algorithm. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the M-by-N matrix to be factored. + On exit, the factors L and U from the factorization + A = P*L*U; the unit diagonal elements of L are not stored. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + IPIV (output) INTEGER array, dimension (min(M,N)) + The pivot indices; for 1 <= i <= min(M,N), row i of the + matrix was interchanged with row IPIV(i). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, U(i,i) is exactly zero. The factorization + has been completed, but the factor U is exactly + singular, and division by zero will occur if it is used + to solve a system of equations. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*m)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGETRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "ZGETRF", " ", m, n, &c_n1, &c_n1, (ftnlen)6, (ftnlen) + 1); + if (nb <= 1 || nb >= min(*m,*n)) { + +/* Use unblocked code. */ + + zgetf2_(m, n, &a[a_offset], lda, &ipiv[1], info); + } else { + +/* Use blocked code. */ + + i__1 = min(*m,*n); + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { +/* Computing MIN */ + i__3 = min(*m,*n) - j + 1; + jb = min(i__3,nb); + +/* + Factor diagonal and subdiagonal blocks and test for exact + singularity. +*/ + + i__3 = *m - j + 1; + zgetf2_(&i__3, &jb, &a[j + j * a_dim1], lda, &ipiv[j], &iinfo); + +/* Adjust INFO and the pivot indices. */ + + if (*info == 0 && iinfo > 0) { + *info = iinfo + j - 1; + } +/* Computing MIN */ + i__4 = *m, i__5 = j + jb - 1; + i__3 = min(i__4,i__5); + for (i__ = j; i__ <= i__3; ++i__) { + ipiv[i__] = j - 1 + ipiv[i__]; +/* L10: */ + } + +/* Apply interchanges to columns 1:J-1. */ + + i__3 = j - 1; + i__4 = j + jb - 1; + zlaswp_(&i__3, &a[a_offset], lda, &j, &i__4, &ipiv[1], &c__1); + + if (j + jb <= *n) { + +/* Apply interchanges to columns J+JB:N. */ + + i__3 = *n - j - jb + 1; + i__4 = j + jb - 1; + zlaswp_(&i__3, &a[(j + jb) * a_dim1 + 1], lda, &j, &i__4, & + ipiv[1], &c__1); + +/* Compute block row of U. */ + + i__3 = *n - j - jb + 1; + ztrsm_("Left", "Lower", "No transpose", "Unit", &jb, &i__3, & + c_b57, &a[j + j * a_dim1], lda, &a[j + (j + jb) * + a_dim1], lda); + if (j + jb <= *m) { + +/* Update trailing submatrix. */ + + i__3 = *m - j - jb + 1; + i__4 = *n - j - jb + 1; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "No transpose", &i__3, &i__4, &jb, + &z__1, &a[j + jb + j * a_dim1], lda, &a[j + (j + + jb) * a_dim1], lda, &c_b57, &a[j + jb + (j + jb) * + a_dim1], lda); + } + } +/* L20: */ + } + } + return 0; + +/* End of ZGETRF */ + +} /* zgetrf_ */ + +/* Subroutine */ int zgetrs_(char *trans, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, + integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int ztrsm_(char *, char *, char *, char *, + integer *, integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *), + xerbla_(char *, integer *); + static logical notran; + extern /* Subroutine */ int zlaswp_(integer *, doublecomplex *, integer *, + integer *, integer *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZGETRS solves a system of linear equations + A * X = B, A**T * X = B, or A**H * X = B + with a general N-by-N matrix A using the LU factorization computed + by ZGETRF. + + Arguments + ========= + + TRANS (input) CHARACTER*1 + Specifies the form of the system of equations: + = 'N': A * X = B (No transpose) + = 'T': A**T * X = B (Transpose) + = 'C': A**H * X = B (Conjugate transpose) + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,N) + The factors L and U from the factorization A = P*L*U + as computed by ZGETRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + IPIV (input) INTEGER array, dimension (N) + The pivot indices from ZGETRF; for 1<=i<=N, row i of the + matrix was interchanged with row IPIV(i). + + B (input/output) COMPLEX*16 array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + notran = lsame_(trans, "N"); + if (! notran && ! lsame_(trans, "T") && ! lsame_( + trans, "C")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZGETRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (notran) { + +/* + Solve A * X = B. + + Apply row interchanges to the right hand sides. +*/ + + zlaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c__1); + +/* Solve L*X = B, overwriting B with X. */ + + ztrsm_("Left", "Lower", "No transpose", "Unit", n, nrhs, &c_b57, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + ztrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b57, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A**T * X = B or A**H * X = B. + + Solve U'*X = B, overwriting B with X. +*/ + + ztrsm_("Left", "Upper", trans, "Non-unit", n, nrhs, &c_b57, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + ztrsm_("Left", "Lower", trans, "Unit", n, nrhs, &c_b57, &a[a_offset], + lda, &b[b_offset], ldb); + +/* Apply row interchanges to the solution vectors. */ + + zlaswp_(nrhs, &b[b_offset], ldb, &c__1, n, &ipiv[1], &c_n1); + } + + return 0; + +/* End of ZGETRS */ + +} /* zgetrs_ */ + +/* Subroutine */ int zheevd_(char *jobz, char *uplo, integer *n, + doublecomplex *a, integer *lda, doublereal *w, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, + integer *liwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static doublereal eps; + static integer inde; + static doublereal anrm; + static integer imax; + static doublereal rmin, rmax; + static integer lopt; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + static doublereal sigma; + extern logical lsame_(char *, char *); + static integer iinfo, lwmin, liopt; + static logical lower; + static integer llrwk, lropt; + static logical wantz; + static integer indwk2, llwrk2; + + static integer iscale; + static doublereal safmin; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *); + static doublereal bignum; + extern doublereal zlanhe_(char *, char *, integer *, doublecomplex *, + integer *, doublereal *); + static integer indtau; + extern /* Subroutine */ int dsterf_(integer *, doublereal *, doublereal *, + integer *), zlascl_(char *, integer *, integer *, doublereal *, + doublereal *, integer *, integer *, doublecomplex *, integer *, + integer *), zstedc_(char *, integer *, doublereal *, + doublereal *, doublecomplex *, integer *, doublecomplex *, + integer *, doublereal *, integer *, integer *, integer *, integer + *); + static integer indrwk, indwrk, liwmin; + extern /* Subroutine */ int zhetrd_(char *, integer *, doublecomplex *, + integer *, doublereal *, doublereal *, doublecomplex *, + doublecomplex *, integer *, integer *), zlacpy_(char *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + integer *); + static integer lrwmin, llwork; + static doublereal smlnum; + static logical lquery; + extern /* Subroutine */ int zunmtr_(char *, char *, char *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *); + + +/* + -- LAPACK driver routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZHEEVD computes all eigenvalues and, optionally, eigenvectors of a + complex Hermitian matrix A. If eigenvectors are desired, it uses a + divide and conquer algorithm. + + The divide and conquer algorithm makes very mild assumptions about + floating point arithmetic. It will work on machines with a guard + digit in add/subtract, or on those binary machines without guard + digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or + Cray-2. It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + JOBZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only; + = 'V': Compute eigenvalues and eigenvectors. + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA, N) + On entry, the Hermitian matrix A. If UPLO = 'U', the + leading N-by-N upper triangular part of A contains the + upper triangular part of the matrix A. If UPLO = 'L', + the leading N-by-N lower triangular part of A contains + the lower triangular part of the matrix A. + On exit, if JOBZ = 'V', then if INFO = 0, A contains the + orthonormal eigenvectors of the matrix A. + If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') + or the upper triangle (if UPLO='U') of A, including the + diagonal, is destroyed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + W (output) DOUBLE PRECISION array, dimension (N) + If INFO = 0, the eigenvalues in ascending order. + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The length of the array WORK. + If N <= 1, LWORK must be at least 1. + If JOBZ = 'N' and N > 1, LWORK must be at least N + 1. + If JOBZ = 'V' and N > 1, LWORK must be at least 2*N + N**2. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal sizes of the WORK, RWORK and + IWORK arrays, returns these values as the first entries of + the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + RWORK (workspace/output) DOUBLE PRECISION array, + dimension (LRWORK) + On exit, if INFO = 0, RWORK(1) returns the optimal LRWORK. + + LRWORK (input) INTEGER + The dimension of the array RWORK. + If N <= 1, LRWORK must be at least 1. + If JOBZ = 'N' and N > 1, LRWORK must be at least N. + If JOBZ = 'V' and N > 1, LRWORK must be at least + 1 + 5*N + 2*N**2. + + If LRWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK, RWORK + and IWORK arrays, returns these values as the first entries + of the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) + On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. + + LIWORK (input) INTEGER + The dimension of the array IWORK. + If N <= 1, LIWORK must be at least 1. + If JOBZ = 'N' and N > 1, LIWORK must be at least 1. + If JOBZ = 'V' and N > 1, LIWORK must be at least 3 + 5*N. + + If LIWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK, RWORK + and IWORK arrays, returns these values as the first entries + of the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i and JOBZ = 'N', then the algorithm failed + to converge; i off-diagonal elements of an intermediate + tridiagonal form did not converge to zero; + if INFO = i and JOBZ = 'V', then the algorithm failed + to compute an eigenvalue while working on the submatrix + lying in rows and columns INFO/(N+1) through + mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + Modified description of INFO. Sven, 16 Feb 05. + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --w; + --work; + --rwork; + --iwork; + + /* Function Body */ + wantz = lsame_(jobz, "V"); + lower = lsame_(uplo, "L"); + lquery = *lwork == -1 || *lrwork == -1 || *liwork == -1; + + *info = 0; + if (! (wantz || lsame_(jobz, "N"))) { + *info = -1; + } else if (! (lower || lsame_(uplo, "U"))) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + + if (*info == 0) { + if (*n <= 1) { + lwmin = 1; + lrwmin = 1; + liwmin = 1; + lopt = lwmin; + lropt = lrwmin; + liopt = liwmin; + } else { + if (wantz) { + lwmin = (*n << 1) + *n * *n; +/* Computing 2nd power */ + i__1 = *n; + lrwmin = *n * 5 + 1 + (i__1 * i__1 << 1); + liwmin = *n * 5 + 3; + } else { + lwmin = *n + 1; + lrwmin = *n; + liwmin = 1; + } +/* Computing MAX */ + i__1 = lwmin, i__2 = *n + ilaenv_(&c__1, "ZHETRD", uplo, n, &c_n1, + &c_n1, &c_n1, (ftnlen)6, (ftnlen)1); + lopt = max(i__1,i__2); + lropt = lrwmin; + liopt = liwmin; + } + work[1].r = (doublereal) lopt, work[1].i = 0.; + rwork[1] = (doublereal) lropt; + iwork[1] = liopt; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*lrwork < lrwmin && ! lquery) { + *info = -10; + } else if (*liwork < liwmin && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZHEEVD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (*n == 1) { + i__1 = a_dim1 + 1; + w[1] = a[i__1].r; + if (wantz) { + i__1 = a_dim1 + 1; + a[i__1].r = 1., a[i__1].i = 0.; + } + return 0; + } + +/* Get machine constants. */ + + safmin = SAFEMINIMUM; + eps = PRECISION; + smlnum = safmin / eps; + bignum = 1. / smlnum; + rmin = sqrt(smlnum); + rmax = sqrt(bignum); + +/* Scale matrix to allowable range, if necessary. */ + + anrm = zlanhe_("M", uplo, n, &a[a_offset], lda, &rwork[1]); + iscale = 0; + if (anrm > 0. && anrm < rmin) { + iscale = 1; + sigma = rmin / anrm; + } else if (anrm > rmax) { + iscale = 1; + sigma = rmax / anrm; + } + if (iscale == 1) { + zlascl_(uplo, &c__0, &c__0, &c_b1034, &sigma, n, n, &a[a_offset], lda, + info); + } + +/* Call ZHETRD to reduce Hermitian matrix to tridiagonal form. */ + + inde = 1; + indtau = 1; + indwrk = indtau + *n; + indrwk = inde + *n; + indwk2 = indwrk + *n * *n; + llwork = *lwork - indwrk + 1; + llwrk2 = *lwork - indwk2 + 1; + llrwk = *lrwork - indrwk + 1; + zhetrd_(uplo, n, &a[a_offset], lda, &w[1], &rwork[inde], &work[indtau], & + work[indwrk], &llwork, &iinfo); + +/* + For eigenvalues only, call DSTERF. For eigenvectors, first call + ZSTEDC to generate the eigenvector matrix, WORK(INDWRK), of the + tridiagonal matrix, then call ZUNMTR to multiply it to the + Householder transformations represented as Householder vectors in + A. +*/ + + if (! wantz) { + dsterf_(n, &w[1], &rwork[inde], info); + } else { + zstedc_("I", n, &w[1], &rwork[inde], &work[indwrk], n, &work[indwk2], + &llwrk2, &rwork[indrwk], &llrwk, &iwork[1], liwork, info); + zunmtr_("L", uplo, "N", n, n, &a[a_offset], lda, &work[indtau], &work[ + indwrk], n, &work[indwk2], &llwrk2, &iinfo); + zlacpy_("A", n, n, &work[indwrk], n, &a[a_offset], lda); + } + +/* If matrix was scaled, then rescale eigenvalues appropriately. */ + + if (iscale == 1) { + if (*info == 0) { + imax = *n; + } else { + imax = *info - 1; + } + d__1 = 1. / sigma; + dscal_(&imax, &d__1, &w[1], &c__1); + } + + work[1].r = (doublereal) lopt, work[1].i = 0.; + rwork[1] = (doublereal) lropt; + iwork[1] = liopt; + + return 0; + +/* End of ZHEEVD */ + +} /* zheevd_ */ + +/* Subroutine */ int zhetd2_(char *uplo, integer *n, doublecomplex *a, + integer *lda, doublereal *d__, doublereal *e, doublecomplex *tau, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1; + doublecomplex z__1, z__2, z__3, z__4; + + /* Local variables */ + static integer i__; + static doublecomplex taui; + extern /* Subroutine */ int zher2_(char *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static doublecomplex alpha; + extern logical lsame_(char *, char *); + extern /* Double Complex */ VOID zdotc_(doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *); + extern /* Subroutine */ int zhemv_(char *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, doublecomplex *, integer *); + static logical upper; + extern /* Subroutine */ int zaxpy_(integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *), xerbla_( + char *, integer *), zlarfg_(integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZHETD2 reduces a complex Hermitian matrix A to real symmetric + tridiagonal form T by a unitary similarity transformation: + Q' * A * Q = T. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + Hermitian matrix A is stored: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + n-by-n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n-by-n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit, if UPLO = 'U', the diagonal and first superdiagonal + of A are overwritten by the corresponding elements of the + tridiagonal matrix T, and the elements above the first + superdiagonal, with the array TAU, represent the unitary + matrix Q as a product of elementary reflectors; if UPLO + = 'L', the diagonal and first subdiagonal of A are over- + written by the corresponding elements of the tridiagonal + matrix T, and the elements below the first subdiagonal, with + the array TAU, represent the unitary matrix Q as a product + of elementary reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + D (output) DOUBLE PRECISION array, dimension (N) + The diagonal elements of the tridiagonal matrix T: + D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix T: + E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. + + TAU (output) COMPLEX*16 array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-1) . . . H(2) H(1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in + A(1:i-1,i+1), and tau in TAU(i). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(n-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v2 v3 v4 ) ( d ) + ( d e v3 v4 ) ( e d ) + ( d e v4 ) ( v1 e d ) + ( d e ) ( v1 v2 e d ) + ( d ) ( v1 v2 v3 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tau; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZHETD2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + return 0; + } + + if (upper) { + +/* Reduce the upper triangle of A */ + + i__1 = *n + *n * a_dim1; + i__2 = *n + *n * a_dim1; + d__1 = a[i__2].r; + a[i__1].r = d__1, a[i__1].i = 0.; + for (i__ = *n - 1; i__ >= 1; --i__) { + +/* + Generate elementary reflector H(i) = I - tau * v * v' + to annihilate A(1:i-1,i+1) +*/ + + i__1 = i__ + (i__ + 1) * a_dim1; + alpha.r = a[i__1].r, alpha.i = a[i__1].i; + zlarfg_(&i__, &alpha, &a[(i__ + 1) * a_dim1 + 1], &c__1, &taui); + i__1 = i__; + e[i__1] = alpha.r; + + if (taui.r != 0. || taui.i != 0.) { + +/* Apply H(i) from both sides to A(1:i,1:i) */ + + i__1 = i__ + (i__ + 1) * a_dim1; + a[i__1].r = 1., a[i__1].i = 0.; + +/* Compute x := tau * A * v storing x in TAU(1:i) */ + + zhemv_(uplo, &i__, &taui, &a[a_offset], lda, &a[(i__ + 1) * + a_dim1 + 1], &c__1, &c_b56, &tau[1], &c__1) + ; + +/* Compute w := x - 1/2 * tau * (x'*v) * v */ + + z__3.r = -.5, z__3.i = -0.; + z__2.r = z__3.r * taui.r - z__3.i * taui.i, z__2.i = z__3.r * + taui.i + z__3.i * taui.r; + zdotc_(&z__4, &i__, &tau[1], &c__1, &a[(i__ + 1) * a_dim1 + 1] + , &c__1); + z__1.r = z__2.r * z__4.r - z__2.i * z__4.i, z__1.i = z__2.r * + z__4.i + z__2.i * z__4.r; + alpha.r = z__1.r, alpha.i = z__1.i; + zaxpy_(&i__, &alpha, &a[(i__ + 1) * a_dim1 + 1], &c__1, &tau[ + 1], &c__1); + +/* + Apply the transformation as a rank-2 update: + A := A - v * w' - w * v' +*/ + + z__1.r = -1., z__1.i = -0.; + zher2_(uplo, &i__, &z__1, &a[(i__ + 1) * a_dim1 + 1], &c__1, & + tau[1], &c__1, &a[a_offset], lda); + + } else { + i__1 = i__ + i__ * a_dim1; + i__2 = i__ + i__ * a_dim1; + d__1 = a[i__2].r; + a[i__1].r = d__1, a[i__1].i = 0.; + } + i__1 = i__ + (i__ + 1) * a_dim1; + i__2 = i__; + a[i__1].r = e[i__2], a[i__1].i = 0.; + i__1 = i__ + 1; + i__2 = i__ + 1 + (i__ + 1) * a_dim1; + d__[i__1] = a[i__2].r; + i__1 = i__; + tau[i__1].r = taui.r, tau[i__1].i = taui.i; +/* L10: */ + } + i__1 = a_dim1 + 1; + d__[1] = a[i__1].r; + } else { + +/* Reduce the lower triangle of A */ + + i__1 = a_dim1 + 1; + i__2 = a_dim1 + 1; + d__1 = a[i__2].r; + a[i__1].r = d__1, a[i__1].i = 0.; + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* + Generate elementary reflector H(i) = I - tau * v * v' + to annihilate A(i+2:n,i) +*/ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + zlarfg_(&i__2, &alpha, &a[min(i__3,*n) + i__ * a_dim1], &c__1, & + taui); + i__2 = i__; + e[i__2] = alpha.r; + + if (taui.r != 0. || taui.i != 0.) { + +/* Apply H(i) from both sides to A(i+1:n,i+1:n) */ + + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Compute x := tau * A * v storing y in TAU(i:n-1) */ + + i__2 = *n - i__; + zhemv_(uplo, &i__2, &taui, &a[i__ + 1 + (i__ + 1) * a_dim1], + lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_b56, &tau[ + i__], &c__1); + +/* Compute w := x - 1/2 * tau * (x'*v) * v */ + + z__3.r = -.5, z__3.i = -0.; + z__2.r = z__3.r * taui.r - z__3.i * taui.i, z__2.i = z__3.r * + taui.i + z__3.i * taui.r; + i__2 = *n - i__; + zdotc_(&z__4, &i__2, &tau[i__], &c__1, &a[i__ + 1 + i__ * + a_dim1], &c__1); + z__1.r = z__2.r * z__4.r - z__2.i * z__4.i, z__1.i = z__2.r * + z__4.i + z__2.i * z__4.r; + alpha.r = z__1.r, alpha.i = z__1.i; + i__2 = *n - i__; + zaxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &tau[ + i__], &c__1); + +/* + Apply the transformation as a rank-2 update: + A := A - v * w' - w * v' +*/ + + i__2 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zher2_(uplo, &i__2, &z__1, &a[i__ + 1 + i__ * a_dim1], &c__1, + &tau[i__], &c__1, &a[i__ + 1 + (i__ + 1) * a_dim1], + lda); + + } else { + i__2 = i__ + 1 + (i__ + 1) * a_dim1; + i__3 = i__ + 1 + (i__ + 1) * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + } + i__2 = i__ + 1 + i__ * a_dim1; + i__3 = i__; + a[i__2].r = e[i__3], a[i__2].i = 0.; + i__2 = i__; + i__3 = i__ + i__ * a_dim1; + d__[i__2] = a[i__3].r; + i__2 = i__; + tau[i__2].r = taui.r, tau[i__2].i = taui.i; +/* L20: */ + } + i__1 = *n; + i__2 = *n + *n * a_dim1; + d__[i__1] = a[i__2].r; + } + + return 0; + +/* End of ZHETD2 */ + +} /* zhetd2_ */ + +/* Subroutine */ int zhetrd_(char *uplo, integer *n, doublecomplex *a, + integer *lda, doublereal *d__, doublereal *e, doublecomplex *tau, + doublecomplex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, nb, kk, nx, iws; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + static logical upper; + extern /* Subroutine */ int zhetd2_(char *, integer *, doublecomplex *, + integer *, doublereal *, doublereal *, doublecomplex *, integer *), zher2k_(char *, char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublereal *, doublecomplex *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlatrd_(char *, integer *, integer *, + doublecomplex *, integer *, doublereal *, doublecomplex *, + doublecomplex *, integer *); + static integer ldwork, lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZHETRD reduces a complex Hermitian matrix A to real symmetric + tridiagonal form T by a unitary similarity transformation: + Q**H * A * Q = T. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit, if UPLO = 'U', the diagonal and first superdiagonal + of A are overwritten by the corresponding elements of the + tridiagonal matrix T, and the elements above the first + superdiagonal, with the array TAU, represent the unitary + matrix Q as a product of elementary reflectors; if UPLO + = 'L', the diagonal and first subdiagonal of A are over- + written by the corresponding elements of the tridiagonal + matrix T, and the elements below the first subdiagonal, with + the array TAU, represent the unitary matrix Q as a product + of elementary reflectors. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + D (output) DOUBLE PRECISION array, dimension (N) + The diagonal elements of the tridiagonal matrix T: + D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (N-1) + The off-diagonal elements of the tridiagonal matrix T: + E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. + + TAU (output) COMPLEX*16 array, dimension (N-1) + The scalar factors of the elementary reflectors (see Further + Details). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= 1. + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-1) . . . H(2) H(1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in + A(1:i-1,i+1), and tau in TAU(i). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(n-1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v2 v3 v4 ) ( d ) + ( d e v3 v4 ) ( e d ) + ( d e v4 ) ( v1 e d ) + ( d e ) ( v1 v2 e d ) + ( d ) ( v1 v2 v3 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tau; + --work; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + lquery = *lwork == -1; + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } else if (*lwork < 1 && ! lquery) { + *info = -9; + } + + if (*info == 0) { + +/* Determine the block size. */ + + nb = ilaenv_(&c__1, "ZHETRD", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, + (ftnlen)1); + lwkopt = *n * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZHETRD", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + nx = *n; + iws = 1; + if (nb > 1 && nb < *n) { + +/* + Determine when to cross over from blocked to unblocked code + (last block is always handled by unblocked code). + + Computing MAX +*/ + i__1 = nb, i__2 = ilaenv_(&c__3, "ZHETRD", uplo, n, &c_n1, &c_n1, & + c_n1, (ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *n) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: determine the + minimum value of NB, and reduce NB or force use of + unblocked code by setting NX = N. + + Computing MAX +*/ + i__1 = *lwork / ldwork; + nb = max(i__1,1); + nbmin = ilaenv_(&c__2, "ZHETRD", uplo, n, &c_n1, &c_n1, &c_n1, + (ftnlen)6, (ftnlen)1); + if (nb < nbmin) { + nx = *n; + } + } + } else { + nx = *n; + } + } else { + nb = 1; + } + + if (upper) { + +/* + Reduce the upper triangle of A. + Columns 1:kk are handled by the unblocked method. +*/ + + kk = *n - (*n - nx + nb - 1) / nb * nb; + i__1 = kk + 1; + i__2 = -nb; + for (i__ = *n - nb + 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += + i__2) { + +/* + Reduce columns i:i+nb-1 to tridiagonal form and form the + matrix W which is needed to update the unreduced part of + the matrix +*/ + + i__3 = i__ + nb - 1; + zlatrd_(uplo, &i__3, &nb, &a[a_offset], lda, &e[1], &tau[1], & + work[1], &ldwork); + +/* + Update the unreduced submatrix A(1:i-1,1:i-1), using an + update of the form: A := A - V*W' - W*V' +*/ + + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zher2k_(uplo, "No transpose", &i__3, &nb, &z__1, &a[i__ * a_dim1 + + 1], lda, &work[1], &ldwork, &c_b1034, &a[a_offset], lda); + +/* + Copy superdiagonal elements back into A, and diagonal + elements into D +*/ + + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + i__4 = j - 1 + j * a_dim1; + i__5 = j - 1; + a[i__4].r = e[i__5], a[i__4].i = 0.; + i__4 = j; + i__5 = j + j * a_dim1; + d__[i__4] = a[i__5].r; +/* L10: */ + } +/* L20: */ + } + +/* Use unblocked code to reduce the last or only block */ + + zhetd2_(uplo, &kk, &a[a_offset], lda, &d__[1], &e[1], &tau[1], &iinfo); + } else { + +/* Reduce the lower triangle of A */ + + i__2 = *n - nx; + i__1 = nb; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { + +/* + Reduce columns i:i+nb-1 to tridiagonal form and form the + matrix W which is needed to update the unreduced part of + the matrix +*/ + + i__3 = *n - i__ + 1; + zlatrd_(uplo, &i__3, &nb, &a[i__ + i__ * a_dim1], lda, &e[i__], & + tau[i__], &work[1], &ldwork); + +/* + Update the unreduced submatrix A(i+nb:n,i+nb:n), using + an update of the form: A := A - V*W' - W*V' +*/ + + i__3 = *n - i__ - nb + 1; + z__1.r = -1., z__1.i = -0.; + zher2k_(uplo, "No transpose", &i__3, &nb, &z__1, &a[i__ + nb + + i__ * a_dim1], lda, &work[nb + 1], &ldwork, &c_b1034, &a[ + i__ + nb + (i__ + nb) * a_dim1], lda); + +/* + Copy subdiagonal elements back into A, and diagonal + elements into D +*/ + + i__3 = i__ + nb - 1; + for (j = i__; j <= i__3; ++j) { + i__4 = j + 1 + j * a_dim1; + i__5 = j; + a[i__4].r = e[i__5], a[i__4].i = 0.; + i__4 = j; + i__5 = j + j * a_dim1; + d__[i__4] = a[i__5].r; +/* L30: */ + } +/* L40: */ + } + +/* Use unblocked code to reduce the last or only block */ + + i__1 = *n - i__ + 1; + zhetd2_(uplo, &i__1, &a[i__ + i__ * a_dim1], lda, &d__[i__], &e[i__], + &tau[i__], &iinfo); + } + + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZHETRD */ + +} /* zhetrd_ */ + +/* Subroutine */ int zhseqr_(char *job, char *compz, integer *n, integer *ilo, + integer *ihi, doublecomplex *h__, integer *ldh, doublecomplex *w, + doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3[2]; + doublereal d__1, d__2, d__3; + doublecomplex z__1; + char ch__1[2]; + + /* Local variables */ + static doublecomplex hl[2401] /* was [49][49] */; + static integer kbot, nmin; + extern logical lsame_(char *, char *); + static logical initz; + static doublecomplex workl[49]; + static logical wantt, wantz; + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), zlaqr0_(logical *, logical *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, integer *), xerbla_(char *, integer * + ); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlahqr_(logical *, logical *, integer *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + integer *, integer *, doublecomplex *, integer *, integer *), + zlacpy_(char *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *), zlaset_(char *, integer *, + integer *, doublecomplex *, doublecomplex *, doublecomplex *, + integer *); + static logical lquery; + + +/* + -- LAPACK computational routine (version 3.2.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + June 2010 + + Purpose + ======= + + ZHSEQR computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**H, where T is an upper triangular matrix (the + Schur form), and Z is the unitary matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input unitary + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the unitary matrix Q: A = Q*H*Q**H = (QZ)*H*(QZ)**H. + + Arguments + ========= + + JOB (input) CHARACTER*1 + = 'E': compute eigenvalues only; + = 'S': compute eigenvalues and the Schur form T. + + COMPZ (input) CHARACTER*1 + = 'N': no Schur vectors are computed; + = 'I': Z is initialized to the unit matrix and the matrix Z + of Schur vectors of H is returned; + = 'V': Z must contain an unitary matrix Q on entry, and + the product Q*Z is returned. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N. ILO and IHI are normally + set by a previous call to ZGEBAL, and then passed to ZGEHRD + when the matrix output by ZGEBAL is reduced to Hessenberg + form. Otherwise ILO and IHI should be set to 1 and N + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) COMPLEX*16 array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and JOB = 'S', H contains the upper + triangular matrix T from the Schur decomposition (the + Schur form). If INFO = 0 and JOB = 'E', the contents of + H are unspecified on exit. (The output value of H when + INFO.GT.0 is given under the description of INFO below.) + + Unlike earlier versions of ZHSEQR, this subroutine may + explicitly H(i,j) = 0 for i.GT.j and j = 1, 2, ... ILO-1 + or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + W (output) COMPLEX*16 array, dimension (N) + The computed eigenvalues. If JOB = 'S', the eigenvalues are + stored in the same order as on the diagonal of the Schur + form returned in H, with W(i) = H(i,i). + + Z (input/output) COMPLEX*16 array, dimension (LDZ,N) + If COMPZ = 'N', Z is not referenced. + If COMPZ = 'I', on entry Z need not be set and on exit, + if INFO = 0, Z contains the unitary matrix Z of the Schur + vectors of H. If COMPZ = 'V', on entry Z must contain an + N-by-N matrix Q, which is assumed to be equal to the unit + matrix except for the submatrix Z(ILO:IHI,ILO:IHI). On exit, + if INFO = 0, Z contains Q*Z. + Normally Q is the unitary matrix generated by ZUNGHR + after the call to ZGEHRD which formed the Hessenberg matrix + H. (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if COMPZ = 'I' or + COMPZ = 'V', then LDZ.GE.MAX(1,N). Otherwize, LDZ.GE.1. + + WORK (workspace/output) COMPLEX*16 array, dimension (LWORK) + On exit, if INFO = 0, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient and delivers very good and sometimes + optimal performance. However, LWORK as large as 11*N + may be required for optimal performance. A workspace + query is recommended to determine the optimal workspace + size. + + If LWORK = -1, then ZHSEQR does a workspace query. + In this case, ZHSEQR checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .LT. 0: if INFO = -i, the i-th argument had an illegal + value + .GT. 0: if INFO = i, ZHSEQR failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and JOB = 'E', then on exit, the + remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and JOB = 'S', then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is a unitary matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and COMPZ = 'V', then on exit + + (final value of Z) = (initial value of Z)*U + + where U is the unitary matrix in (*) (regard- + less of the value of JOB.) + + If INFO .GT. 0 and COMPZ = 'I', then on exit + (final value of Z) = U + where U is the unitary matrix in (*) (regard- + less of the value of JOB.) + + If INFO .GT. 0 and COMPZ = 'N', then Z is not + accessed. + + ================================================================ + Default values supplied by + ILAENV(ISPEC,'ZHSEQR',JOB(:1)//COMPZ(:1),N,ILO,IHI,LWORK). + It is suggested that these defaults be adjusted in order + to attain best performance in each particular + computational environment. + + ISPEC=12: The ZLAHQR vs ZLAQR0 crossover point. + Default: 75. (Must be at least 11.) + + ISPEC=13: Recommended deflation window size. + This depends on ILO, IHI and NS. NS is the + number of simultaneous shifts returned + by ILAENV(ISPEC=15). (See ISPEC=15 below.) + The default for (IHI-ILO+1).LE.500 is NS. + The default for (IHI-ILO+1).GT.500 is 3*NS/2. + + ISPEC=14: Nibble crossover point. (See IPARMQ for + details.) Default: 14% of deflation window + size. + + ISPEC=15: Number of simultaneous shifts in a multishift + QR iteration. + + If IHI-ILO+1 is ... + + greater than ...but less ... the + or equal to ... than default is + + 1 30 NS = 2(+) + 30 60 NS = 4(+) + 60 150 NS = 10(+) + 150 590 NS = ** + 590 3000 NS = 64 + 3000 6000 NS = 128 + 6000 infinity NS = 256 + + (+) By default some or all matrices of this order + are passed to the implicit double shift routine + ZLAHQR and this parameter is ignored. See + ISPEC=12 above and comments in IPARMQ for + details. + + (**) The asterisks (**) indicate an ad-hoc + function of N increasing from 10 to 64. + + ISPEC=16: Select structured matrix multiply. + If the number of simultaneous shifts (specified + by ISPEC=15) is less than 14, then the default + for ISPEC=16 is 0. Otherwise the default for + ISPEC=16 is 2. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . ZLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== NL allocates some local workspace to help small matrices + . through a rare ZLAHQR failure. NL .GT. NTINY = 11 is + . required and NL .LE. NMIN = ILAENV(ISPEC=12,...) is recom- + . mended. (The default value of NMIN is 75.) Using NL = 49 + . allows up to six simultaneous shifts and a 16-by-16 + . deflation window. ==== + + ==== Decode and check the input parameters. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --w; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + wantt = lsame_(job, "S"); + initz = lsame_(compz, "I"); + wantz = initz || lsame_(compz, "V"); + d__1 = (doublereal) max(1,*n); + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + lquery = *lwork == -1; + + *info = 0; + if (! lsame_(job, "E") && ! wantt) { + *info = -1; + } else if (! lsame_(compz, "N") && ! wantz) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -4; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -5; + } else if (*ldh < max(1,*n)) { + *info = -7; + } else if (*ldz < 1 || wantz && *ldz < max(1,*n)) { + *info = -10; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -12; + } + + if (*info != 0) { + +/* ==== Quick return in case of invalid argument. ==== */ + + i__1 = -(*info); + xerbla_("ZHSEQR", &i__1); + return 0; + + } else if (*n == 0) { + +/* ==== Quick return in case N = 0; nothing to do. ==== */ + + return 0; + + } else if (lquery) { + +/* ==== Quick return in case of a workspace query ==== */ + + zlaqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], ilo, + ihi, &z__[z_offset], ldz, &work[1], lwork, info); +/* + ==== Ensure reported workspace size is backward-compatible with + . previous LAPACK versions. ==== + Computing MAX +*/ + d__2 = work[1].r, d__3 = (doublereal) max(1,*n); + d__1 = max(d__2,d__3); + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + return 0; + + } else { + +/* ==== copy eigenvalues isolated by ZGEBAL ==== */ + + if (*ilo > 1) { + i__1 = *ilo - 1; + i__2 = *ldh + 1; + zcopy_(&i__1, &h__[h_offset], &i__2, &w[1], &c__1); + } + if (*ihi < *n) { + i__1 = *n - *ihi; + i__2 = *ldh + 1; + zcopy_(&i__1, &h__[*ihi + 1 + (*ihi + 1) * h_dim1], &i__2, &w[* + ihi + 1], &c__1); + } + +/* ==== Initialize Z, if requested ==== */ + + if (initz) { + zlaset_("A", n, n, &c_b56, &c_b57, &z__[z_offset], ldz) + ; + } + +/* ==== Quick return if possible ==== */ + + if (*ilo == *ihi) { + i__1 = *ilo; + i__2 = *ilo + *ilo * h_dim1; + w[i__1].r = h__[i__2].r, w[i__1].i = h__[i__2].i; + return 0; + } + +/* + ==== ZLAHQR/ZLAQR0 crossover point ==== + + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = job; + i__3[1] = 1, a__1[1] = compz; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + nmin = ilaenv_(&c__12, "ZHSEQR", ch__1, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nmin = max(11,nmin); + +/* ==== ZLAQR0 for big matrices; ZLAHQR for small ones ==== */ + + if (*n > nmin) { + zlaqr0_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], + ilo, ihi, &z__[z_offset], ldz, &work[1], lwork, info); + } else { + +/* ==== Small matrix ==== */ + + zlahqr_(&wantt, &wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], + ilo, ihi, &z__[z_offset], ldz, info); + + if (*info > 0) { + +/* + ==== A rare ZLAHQR failure! ZLAQR0 sometimes succeeds + . when ZLAHQR fails. ==== +*/ + + kbot = *info; + + if (*n >= 49) { + +/* + ==== Larger matrices have enough subdiagonal scratch + . space to call ZLAQR0 directly. ==== +*/ + + zlaqr0_(&wantt, &wantz, n, ilo, &kbot, &h__[h_offset], + ldh, &w[1], ilo, ihi, &z__[z_offset], ldz, &work[ + 1], lwork, info); + + } else { + +/* + ==== Tiny matrices don't have enough subdiagonal + . scratch space to benefit from ZLAQR0. Hence, + . tiny matrices must be copied into a larger + . array before calling ZLAQR0. ==== +*/ + + zlacpy_("A", n, n, &h__[h_offset], ldh, hl, &c__49); + i__1 = *n + 1 + *n * 49 - 50; + hl[i__1].r = 0., hl[i__1].i = 0.; + i__1 = 49 - *n; + zlaset_("A", &c__49, &i__1, &c_b56, &c_b56, &hl[(*n + 1) * + 49 - 49], &c__49); + zlaqr0_(&wantt, &wantz, &c__49, ilo, &kbot, hl, &c__49, & + w[1], ilo, ihi, &z__[z_offset], ldz, workl, & + c__49, info); + if (wantt || *info != 0) { + zlacpy_("A", n, n, hl, &c__49, &h__[h_offset], ldh); + } + } + } + } + +/* ==== Clear out the trash, if necessary. ==== */ + + if ((wantt || *info != 0) && *n > 2) { + i__1 = *n - 2; + i__2 = *n - 2; + zlaset_("L", &i__1, &i__2, &c_b56, &c_b56, &h__[h_dim1 + 3], ldh); + } + +/* + ==== Ensure reported workspace size is backward-compatible with + . previous LAPACK versions. ==== + + Computing MAX +*/ + d__2 = (doublereal) max(1,*n), d__3 = work[1].r; + d__1 = max(d__2,d__3); + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + } + +/* ==== End of ZHSEQR ==== */ + + return 0; +} /* zhseqr_ */ + +/* Subroutine */ int zlabrd_(integer *m, integer *n, integer *nb, + doublecomplex *a, integer *lda, doublereal *d__, doublereal *e, + doublecomplex *tauq, doublecomplex *taup, doublecomplex *x, integer * + ldx, doublecomplex *y, integer *ldy) +{ + /* System generated locals */ + integer a_dim1, a_offset, x_dim1, x_offset, y_dim1, y_offset, i__1, i__2, + i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__; + static doublecomplex alpha; + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *), zgemv_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *), + zlarfg_(integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *), zlacgv_(integer *, doublecomplex *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLABRD reduces the first NB rows and columns of a complex general + m by n matrix A to upper or lower real bidiagonal form by a unitary + transformation Q' * A * P, and returns the matrices X and Y which + are needed to apply the transformation to the unreduced part of A. + + If m >= n, A is reduced to upper bidiagonal form; if m < n, to lower + bidiagonal form. + + This is an auxiliary routine called by ZGEBRD + + Arguments + ========= + + M (input) INTEGER + The number of rows in the matrix A. + + N (input) INTEGER + The number of columns in the matrix A. + + NB (input) INTEGER + The number of leading rows and columns of A to be reduced. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the m by n general matrix to be reduced. + On exit, the first NB rows and columns of the matrix are + overwritten; the rest of the array is unchanged. + If m >= n, elements on and below the diagonal in the first NB + columns, with the array TAUQ, represent the unitary + matrix Q as a product of elementary reflectors; and + elements above the diagonal in the first NB rows, with the + array TAUP, represent the unitary matrix P as a product + of elementary reflectors. + If m < n, elements below the diagonal in the first NB + columns, with the array TAUQ, represent the unitary + matrix Q as a product of elementary reflectors, and + elements on and above the diagonal in the first NB rows, + with the array TAUP, represent the unitary matrix P as + a product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + D (output) DOUBLE PRECISION array, dimension (NB) + The diagonal elements of the first NB rows and columns of + the reduced matrix. D(i) = A(i,i). + + E (output) DOUBLE PRECISION array, dimension (NB) + The off-diagonal elements of the first NB rows and columns of + the reduced matrix. + + TAUQ (output) COMPLEX*16 array dimension (NB) + The scalar factors of the elementary reflectors which + represent the unitary matrix Q. See Further Details. + + TAUP (output) COMPLEX*16 array, dimension (NB) + The scalar factors of the elementary reflectors which + represent the unitary matrix P. See Further Details. + + X (output) COMPLEX*16 array, dimension (LDX,NB) + The m-by-nb matrix X required to update the unreduced part + of A. + + LDX (input) INTEGER + The leading dimension of the array X. LDX >= max(1,M). + + Y (output) COMPLEX*16 array, dimension (LDY,NB) + The n-by-nb matrix Y required to update the unreduced part + of A. + + LDY (input) INTEGER + The leading dimension of the array Y. LDY >= max(1,N). + + Further Details + =============== + + The matrices Q and P are represented as products of elementary + reflectors: + + Q = H(1) H(2) . . . H(nb) and P = G(1) G(2) . . . G(nb) + + Each H(i) and G(i) has the form: + + H(i) = I - tauq * v * v' and G(i) = I - taup * u * u' + + where tauq and taup are complex scalars, and v and u are complex + vectors. + + If m >= n, v(1:i-1) = 0, v(i) = 1, and v(i:m) is stored on exit in + A(i:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+1:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + If m < n, v(1:i) = 0, v(i+1) = 1, and v(i+1:m) is stored on exit in + A(i+2:m,i); u(1:i-1) = 0, u(i) = 1, and u(i:n) is stored on exit in + A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i). + + The elements of the vectors v and u together form the m-by-nb matrix + V and the nb-by-n matrix U' which are needed, with X and Y, to apply + the transformation to the unreduced part of the matrix, using a block + update of the form: A := A - V*Y' - X*U'. + + The contents of A on exit are illustrated by the following examples + with nb = 2: + + m = 6 and n = 5 (m > n): m = 5 and n = 6 (m < n): + + ( 1 1 u1 u1 u1 ) ( 1 u1 u1 u1 u1 u1 ) + ( v1 1 1 u2 u2 ) ( 1 1 u2 u2 u2 u2 ) + ( v1 v2 a a a ) ( v1 1 a a a a ) + ( v1 v2 a a a ) ( v1 v2 a a a a ) + ( v1 v2 a a a ) ( v1 v2 a a a a ) + ( v1 v2 a a a ) + + where a denotes an element of the original matrix which is unchanged, + vi denotes an element of the vector defining H(i), and ui an element + of the vector defining G(i). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --d__; + --e; + --tauq; + --taup; + x_dim1 = *ldx; + x_offset = 1 + x_dim1; + x -= x_offset; + y_dim1 = *ldy; + y_offset = 1 + y_dim1; + y -= y_offset; + + /* Function Body */ + if (*m <= 0 || *n <= 0) { + return 0; + } + + if (*m >= *n) { + +/* Reduce to upper bidiagonal form */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i:m,i) */ + + i__2 = i__ - 1; + zlacgv_(&i__2, &y[i__ + y_dim1], ldy); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &a[i__ + a_dim1], lda, + &y[i__ + y_dim1], ldy, &c_b57, &a[i__ + i__ * a_dim1], & + c__1); + i__2 = i__ - 1; + zlacgv_(&i__2, &y[i__ + y_dim1], ldy); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &x[i__ + x_dim1], ldx, + &a[i__ * a_dim1 + 1], &c__1, &c_b57, &a[i__ + i__ * + a_dim1], &c__1); + +/* Generate reflection Q(i) to annihilate A(i+1:m,i) */ + + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *m - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + zlarfg_(&i__2, &alpha, &a[min(i__3,*m) + i__ * a_dim1], &c__1, & + tauq[i__]); + i__2 = i__; + d__[i__2] = alpha.r; + if (i__ < *n) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Compute Y(i+1:n,i) */ + + i__2 = *m - i__ + 1; + i__3 = *n - i__; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + ( + i__ + 1) * a_dim1], lda, &a[i__ + i__ * a_dim1], & + c__1, &c_b56, &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + a_dim1], lda, &a[i__ + i__ * a_dim1], &c__1, &c_b56, & + y[i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &y[i__ + 1 + + y_dim1], ldy, &y[i__ * y_dim1 + 1], &c__1, &c_b57, &y[ + i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__ + 1; + i__3 = i__ - 1; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &x[i__ + + x_dim1], ldx, &a[i__ + i__ * a_dim1], &c__1, &c_b56, & + y[i__ * y_dim1 + 1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("Conjugate transpose", &i__2, &i__3, &z__1, &a[(i__ + + 1) * a_dim1 + 1], lda, &y[i__ * y_dim1 + 1], &c__1, & + c_b57, &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *n - i__; + zscal_(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1); + +/* Update A(i,i+1:n) */ + + i__2 = *n - i__; + zlacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + zlacgv_(&i__, &a[i__ + a_dim1], lda); + i__2 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__, &z__1, &y[i__ + 1 + + y_dim1], ldy, &a[i__ + a_dim1], lda, &c_b57, &a[i__ + + (i__ + 1) * a_dim1], lda); + zlacgv_(&i__, &a[i__ + a_dim1], lda); + i__2 = i__ - 1; + zlacgv_(&i__2, &x[i__ + x_dim1], ldx); + i__2 = i__ - 1; + i__3 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("Conjugate transpose", &i__2, &i__3, &z__1, &a[(i__ + + 1) * a_dim1 + 1], lda, &x[i__ + x_dim1], ldx, &c_b57, + &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ - 1; + zlacgv_(&i__2, &x[i__ + x_dim1], ldx); + +/* Generate reflection P(i) to annihilate A(i,i+2:n) */ + + i__2 = i__ + (i__ + 1) * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + zlarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, & + taup[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + (i__ + 1) * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Compute X(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = *n - i__; + zgemv_("No transpose", &i__2, &i__3, &c_b57, &a[i__ + 1 + ( + i__ + 1) * a_dim1], lda, &a[i__ + (i__ + 1) * a_dim1], + lda, &c_b56, &x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__; + zgemv_("Conjugate transpose", &i__2, &i__, &c_b57, &y[i__ + 1 + + y_dim1], ldy, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b56, &x[i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__, &z__1, &a[i__ + 1 + + a_dim1], lda, &x[i__ * x_dim1 + 1], &c__1, &c_b57, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + zgemv_("No transpose", &i__2, &i__3, &c_b57, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b56, &x[i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &x[i__ + 1 + + x_dim1], ldx, &x[i__ * x_dim1 + 1], &c__1, &c_b57, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *m - i__; + zscal_(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__; + zlacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Reduce to lower bidiagonal form */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i,i:n) */ + + i__2 = *n - i__ + 1; + zlacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + i__2 = i__ - 1; + zlacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &y[i__ + y_dim1], ldy, + &a[i__ + a_dim1], lda, &c_b57, &a[i__ + i__ * a_dim1], + lda); + i__2 = i__ - 1; + zlacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = i__ - 1; + zlacgv_(&i__2, &x[i__ + x_dim1], ldx); + i__2 = i__ - 1; + i__3 = *n - i__ + 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("Conjugate transpose", &i__2, &i__3, &z__1, &a[i__ * + a_dim1 + 1], lda, &x[i__ + x_dim1], ldx, &c_b57, &a[i__ + + i__ * a_dim1], lda); + i__2 = i__ - 1; + zlacgv_(&i__2, &x[i__ + x_dim1], ldx); + +/* Generate reflection P(i) to annihilate A(i,i+1:n) */ + + i__2 = i__ + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__ + 1; +/* Computing MIN */ + i__3 = i__ + 1; + zlarfg_(&i__2, &alpha, &a[i__ + min(i__3,*n) * a_dim1], lda, & + taup[i__]); + i__2 = i__; + d__[i__2] = alpha.r; + if (i__ < *m) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Compute X(i+1:m,i) */ + + i__2 = *m - i__; + i__3 = *n - i__ + 1; + zgemv_("No transpose", &i__2, &i__3, &c_b57, &a[i__ + 1 + i__ + * a_dim1], lda, &a[i__ + i__ * a_dim1], lda, &c_b56, & + x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &y[i__ + + y_dim1], ldy, &a[i__ + i__ * a_dim1], lda, &c_b56, &x[ + i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &a[i__ + 1 + + a_dim1], lda, &x[i__ * x_dim1 + 1], &c__1, &c_b57, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__ + 1; + zgemv_("No transpose", &i__2, &i__3, &c_b57, &a[i__ * a_dim1 + + 1], lda, &a[i__ + i__ * a_dim1], lda, &c_b56, &x[ + i__ * x_dim1 + 1], &c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &x[i__ + 1 + + x_dim1], ldx, &x[i__ * x_dim1 + 1], &c__1, &c_b57, &x[ + i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *m - i__; + zscal_(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1); + i__2 = *n - i__ + 1; + zlacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + +/* Update A(i+1:m,i) */ + + i__2 = i__ - 1; + zlacgv_(&i__2, &y[i__ + y_dim1], ldy); + i__2 = *m - i__; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &a[i__ + 1 + + a_dim1], lda, &y[i__ + y_dim1], ldy, &c_b57, &a[i__ + + 1 + i__ * a_dim1], &c__1); + i__2 = i__ - 1; + zlacgv_(&i__2, &y[i__ + y_dim1], ldy); + i__2 = *m - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__, &z__1, &x[i__ + 1 + + x_dim1], ldx, &a[i__ * a_dim1 + 1], &c__1, &c_b57, &a[ + i__ + 1 + i__ * a_dim1], &c__1); + +/* Generate reflection Q(i) to annihilate A(i+2:m,i) */ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *m - i__; +/* Computing MIN */ + i__3 = i__ + 2; + zlarfg_(&i__2, &alpha, &a[min(i__3,*m) + i__ * a_dim1], &c__1, + &tauq[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Compute Y(i+1:n,i) */ + + i__2 = *m - i__; + i__3 = *n - i__; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + 1 + (i__ + 1) * a_dim1], lda, &a[i__ + 1 + i__ * + a_dim1], &c__1, &c_b56, &y[i__ + 1 + i__ * y_dim1], & + c__1); + i__2 = *m - i__; + i__3 = i__ - 1; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + 1 + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &y[i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &y[i__ + 1 + + y_dim1], ldy, &y[i__ * y_dim1 + 1], &c__1, &c_b57, &y[ + i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *m - i__; + zgemv_("Conjugate transpose", &i__2, &i__, &c_b57, &x[i__ + 1 + + x_dim1], ldx, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &y[i__ * y_dim1 + 1], &c__1); + i__2 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("Conjugate transpose", &i__, &i__2, &z__1, &a[(i__ + 1) + * a_dim1 + 1], lda, &y[i__ * y_dim1 + 1], &c__1, & + c_b57, &y[i__ + 1 + i__ * y_dim1], &c__1); + i__2 = *n - i__; + zscal_(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1); + } else { + i__2 = *n - i__ + 1; + zlacgv_(&i__2, &a[i__ + i__ * a_dim1], lda); + } +/* L20: */ + } + } + return 0; + +/* End of ZLABRD */ + +} /* zlabrd_ */ + +/* Subroutine */ int zlacgv_(integer *n, doublecomplex *x, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2; + doublecomplex z__1; + + /* Local variables */ + static integer i__, ioff; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLACGV conjugates a complex vector of length N. + + Arguments + ========= + + N (input) INTEGER + The length of the vector X. N >= 0. + + X (input/output) COMPLEX*16 array, dimension + (1+(N-1)*abs(INCX)) + On entry, the vector of length N to be conjugated. + On exit, X is overwritten with conjg(X). + + INCX (input) INTEGER + The spacing between successive elements of X. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*incx == 1) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + d_cnjg(&z__1, &x[i__]); + x[i__2].r = z__1.r, x[i__2].i = z__1.i; +/* L10: */ + } + } else { + ioff = 1; + if (*incx < 0) { + ioff = 1 - (*n - 1) * *incx; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ioff; + d_cnjg(&z__1, &x[ioff]); + x[i__2].r = z__1.r, x[i__2].i = z__1.i; + ioff += *incx; +/* L20: */ + } + } + return 0; + +/* End of ZLACGV */ + +} /* zlacgv_ */ + +/* Subroutine */ int zlacp2_(char *uplo, integer *m, integer *n, doublereal * + a, integer *lda, doublecomplex *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLACP2 copies all or part of a real two-dimensional matrix A to a + complex matrix B. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be copied to B. + = 'U': Upper triangular part + = 'L': Lower triangular part + Otherwise: All of the matrix A + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA,N) + The m by n matrix A. If UPLO = 'U', only the upper trapezium + is accessed; if UPLO = 'L', only the lower trapezium is + accessed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + B (output) COMPLEX*16 array, dimension (LDB,N) + On exit, B = A in the locations specified by UPLO. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4], b[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + + } else if (lsame_(uplo, "L")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4], b[i__3].i = 0.; +/* L30: */ + } +/* L40: */ + } + + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4], b[i__3].i = 0.; +/* L50: */ + } +/* L60: */ + } + } + + return 0; + +/* End of ZLACP2 */ + +} /* zlacp2_ */ + +/* Subroutine */ int zlacpy_(char *uplo, integer *m, integer *n, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLACPY copies all or part of a two-dimensional matrix A to another + matrix B. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be copied to B. + = 'U': Upper triangular part + = 'L': Lower triangular part + Otherwise: All of the matrix A + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,N) + The m by n matrix A. If UPLO = 'U', only the upper trapezium + is accessed; if UPLO = 'L', only the lower trapezium is + accessed. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + B (output) COMPLEX*16 array, dimension (LDB,N) + On exit, B = A in the locations specified by UPLO. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4].r, b[i__3].i = a[i__4].i; +/* L10: */ + } +/* L20: */ + } + + } else if (lsame_(uplo, "L")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4].r, b[i__3].i = a[i__4].i; +/* L30: */ + } +/* L40: */ + } + + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + i__4 = i__ + j * a_dim1; + b[i__3].r = a[i__4].r, b[i__3].i = a[i__4].i; +/* L50: */ + } +/* L60: */ + } + } + + return 0; + +/* End of ZLACPY */ + +} /* zlacpy_ */ + +/* Subroutine */ int zlacrm_(integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *b, integer *ldb, doublecomplex *c__, + integer *ldc, doublereal *rwork) +{ + /* System generated locals */ + integer b_dim1, b_offset, a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, + i__3, i__4, i__5; + doublereal d__1; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLACRM performs a very simple matrix-matrix multiplication: + C := A * B, + where A is M by N and complex; B is N by N and real; + C is M by N and complex. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A and of the matrix C. + M >= 0. + + N (input) INTEGER + The number of columns and rows of the matrix B and + the number of columns of the matrix C. + N >= 0. + + A (input) COMPLEX*16 array, dimension (LDA, N) + A contains the M by N matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >=max(1,M). + + B (input) DOUBLE PRECISION array, dimension (LDB, N) + B contains the N by N matrix B. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >=max(1,N). + + C (input) COMPLEX*16 array, dimension (LDC, N) + C contains the M by N matrix C. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >=max(1,N). + + RWORK (workspace) DOUBLE PRECISION array, dimension (2*M*N) + + ===================================================================== + + + Quick return if possible. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --rwork; + + /* Function Body */ + if (*m == 0 || *n == 0) { + return 0; + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + rwork[(j - 1) * *m + i__] = a[i__3].r; +/* L10: */ + } +/* L20: */ + } + + l = *m * *n + 1; + dgemm_("N", "N", m, n, n, &c_b1034, &rwork[1], m, &b[b_offset], ldb, & + c_b328, &rwork[l], m); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = l + (j - 1) * *m + i__ - 1; + c__[i__3].r = rwork[i__4], c__[i__3].i = 0.; +/* L30: */ + } +/* L40: */ + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + rwork[(j - 1) * *m + i__] = d_imag(&a[i__ + j * a_dim1]); +/* L50: */ + } +/* L60: */ + } + dgemm_("N", "N", m, n, n, &c_b1034, &rwork[1], m, &b[b_offset], ldb, & + c_b328, &rwork[l], m); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + d__1 = c__[i__4].r; + i__5 = l + (j - 1) * *m + i__ - 1; + z__1.r = d__1, z__1.i = rwork[i__5]; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L70: */ + } +/* L80: */ + } + + return 0; + +/* End of ZLACRM */ + +} /* zlacrm_ */ + +/* Double Complex */ VOID zladiv_(doublecomplex * ret_val, doublecomplex *x, + doublecomplex *y) +{ + /* System generated locals */ + doublereal d__1, d__2, d__3, d__4; + doublecomplex z__1; + + /* Local variables */ + static doublereal zi, zr; + extern /* Subroutine */ int dladiv_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLADIV := X / Y, where X and Y are complex. The computation of X / Y + will not overflow on an intermediary step unless the results + overflows. + + Arguments + ========= + + X (input) COMPLEX*16 + Y (input) COMPLEX*16 + The complex scalars X and Y. + + ===================================================================== +*/ + + + d__1 = x->r; + d__2 = d_imag(x); + d__3 = y->r; + d__4 = d_imag(y); + dladiv_(&d__1, &d__2, &d__3, &d__4, &zr, &zi); + z__1.r = zr, z__1.i = zi; + ret_val->r = z__1.r, ret_val->i = z__1.i; + + return ; + +/* End of ZLADIV */ + +} /* zladiv_ */ + +/* Subroutine */ int zlaed0_(integer *qsiz, integer *n, doublereal *d__, + doublereal *e, doublecomplex *q, integer *ldq, doublecomplex *qstore, + integer *ldqs, doublereal *rwork, integer *iwork, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, qstore_dim1, qstore_offset, i__1, i__2; + doublereal d__1; + + /* Local variables */ + static integer i__, j, k, ll, iq, lgn, msd2, smm1, spm1, spm2; + static doublereal temp; + static integer curr, iperm; + extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *, + doublereal *, integer *); + static integer indxq, iwrem, iqptr, tlvls; + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), zlaed7_(integer *, integer *, + integer *, integer *, integer *, integer *, doublereal *, + doublecomplex *, integer *, doublereal *, integer *, doublereal *, + integer *, integer *, integer *, integer *, integer *, + doublereal *, doublecomplex *, doublereal *, integer *, integer *) + ; + static integer igivcl; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlacrm_(integer *, integer *, doublecomplex *, + integer *, doublereal *, integer *, doublecomplex *, integer *, + doublereal *); + static integer igivnm, submat, curprb, subpbs, igivpt; + extern /* Subroutine */ int dsteqr_(char *, integer *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, integer *); + static integer curlvl, matsiz, iprmpt, smlsiz; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + Using the divide and conquer method, ZLAED0 computes all eigenvalues + of a symmetric tridiagonal matrix which is one diagonal block of + those from reducing a dense or band Hermitian matrix and + corresponding eigenvectors of the dense or band matrix. + + Arguments + ========= + + QSIZ (input) INTEGER + The dimension of the unitary matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N if ICOMPQ = 1. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, the eigenvalues in ascending order. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + On entry, the off-diagonal elements of the tridiagonal matrix. + On exit, E has been destroyed. + + Q (input/output) COMPLEX*16 array, dimension (LDQ,N) + On entry, Q must contain an QSIZ x N matrix whose columns + unitarily orthonormal. It is a part of the unitary matrix + that reduces the full dense Hermitian matrix to a + (reducible) symmetric tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + IWORK (workspace) INTEGER array, + the dimension of IWORK must be at least + 6 + 6*N + 5*N*lg N + ( lg( N ) = smallest integer k + such that 2^k >= N ) + + RWORK (workspace) DOUBLE PRECISION array, + dimension (1 + 3*N + 2*N*lg N + 3*N**2) + ( lg( N ) = smallest integer k + such that 2^k >= N ) + + QSTORE (workspace) COMPLEX*16 array, dimension (LDQS, N) + Used to store parts of + the eigenvector matrix when the updating matrix multiplies + take place. + + LDQS (input) INTEGER + The leading dimension of the array QSTORE. + LDQS >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute an eigenvalue while + working on the submatrix lying in rows and columns + INFO/(N+1) through mod(INFO,N+1). + + ===================================================================== + + Warning: N could be as big as QSIZ! + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + qstore_dim1 = *ldqs; + qstore_offset = 1 + qstore_dim1; + qstore -= qstore_offset; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + +/* + IF( ICOMPQ .LT. 0 .OR. ICOMPQ .GT. 2 ) THEN + INFO = -1 + ELSE IF( ( ICOMPQ .EQ. 1 ) .AND. ( QSIZ .LT. MAX( 0, N ) ) ) + $ THEN +*/ + if (*qsiz < max(0,*n)) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldq < max(1,*n)) { + *info = -6; + } else if (*ldqs < max(1,*n)) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLAED0", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + smlsiz = ilaenv_(&c__9, "ZLAED0", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + +/* + Determine the size and placement of the submatrices, and save in + the leading elements of IWORK. +*/ + + iwork[1] = *n; + subpbs = 1; + tlvls = 0; +L10: + if (iwork[subpbs] > smlsiz) { + for (j = subpbs; j >= 1; --j) { + iwork[j * 2] = (iwork[j] + 1) / 2; + iwork[(j << 1) - 1] = iwork[j] / 2; +/* L20: */ + } + ++tlvls; + subpbs <<= 1; + goto L10; + } + i__1 = subpbs; + for (j = 2; j <= i__1; ++j) { + iwork[j] += iwork[j - 1]; +/* L30: */ + } + +/* + Divide the matrix into SUBPBS submatrices of size at most SMLSIZ+1 + using rank-1 modifications (cuts). +*/ + + spm1 = subpbs - 1; + i__1 = spm1; + for (i__ = 1; i__ <= i__1; ++i__) { + submat = iwork[i__] + 1; + smm1 = submat - 1; + d__[smm1] -= (d__1 = e[smm1], abs(d__1)); + d__[submat] -= (d__1 = e[smm1], abs(d__1)); +/* L40: */ + } + + indxq = (*n << 2) + 3; + +/* + Set up workspaces for eigenvalues only/accumulate new vectors + routine +*/ + + temp = log((doublereal) (*n)) / log(2.); + lgn = (integer) temp; + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + iprmpt = indxq + *n + 1; + iperm = iprmpt + *n * lgn; + iqptr = iperm + *n * lgn; + igivpt = iqptr + *n + 2; + igivcl = igivpt + *n * lgn; + + igivnm = 1; + iq = igivnm + (*n << 1) * lgn; +/* Computing 2nd power */ + i__1 = *n; + iwrem = iq + i__1 * i__1 + 1; +/* Initialize pointers */ + i__1 = subpbs; + for (i__ = 0; i__ <= i__1; ++i__) { + iwork[iprmpt + i__] = 1; + iwork[igivpt + i__] = 1; +/* L50: */ + } + iwork[iqptr] = 1; + +/* + Solve each submatrix eigenproblem at the bottom of the divide and + conquer tree. +*/ + + curr = 0; + i__1 = spm1; + for (i__ = 0; i__ <= i__1; ++i__) { + if (i__ == 0) { + submat = 1; + matsiz = iwork[1]; + } else { + submat = iwork[i__] + 1; + matsiz = iwork[i__ + 1] - iwork[i__]; + } + ll = iq - 1 + iwork[iqptr + curr]; + dsteqr_("I", &matsiz, &d__[submat], &e[submat], &rwork[ll], &matsiz, & + rwork[1], info); + zlacrm_(qsiz, &matsiz, &q[submat * q_dim1 + 1], ldq, &rwork[ll], & + matsiz, &qstore[submat * qstore_dim1 + 1], ldqs, &rwork[iwrem] + ); +/* Computing 2nd power */ + i__2 = matsiz; + iwork[iqptr + curr + 1] = iwork[iqptr + curr] + i__2 * i__2; + ++curr; + if (*info > 0) { + *info = submat * (*n + 1) + submat + matsiz - 1; + return 0; + } + k = 1; + i__2 = iwork[i__ + 1]; + for (j = submat; j <= i__2; ++j) { + iwork[indxq + j] = k; + ++k; +/* L60: */ + } +/* L70: */ + } + +/* + Successively merge eigensystems of adjacent submatrices + into eigensystem for the corresponding larger matrix. + + while ( SUBPBS > 1 ) +*/ + + curlvl = 1; +L80: + if (subpbs > 1) { + spm2 = subpbs - 2; + i__1 = spm2; + for (i__ = 0; i__ <= i__1; i__ += 2) { + if (i__ == 0) { + submat = 1; + matsiz = iwork[2]; + msd2 = iwork[1]; + curprb = 0; + } else { + submat = iwork[i__] + 1; + matsiz = iwork[i__ + 2] - iwork[i__]; + msd2 = matsiz / 2; + ++curprb; + } + +/* + Merge lower order eigensystems (of size MSD2 and MATSIZ - MSD2) + into an eigensystem of size MATSIZ. ZLAED7 handles the case + when the eigenvectors of a full or band Hermitian matrix (which + was reduced to tridiagonal form) are desired. + + I am free to use Q as a valuable working space until Loop 150. +*/ + + zlaed7_(&matsiz, &msd2, qsiz, &tlvls, &curlvl, &curprb, &d__[ + submat], &qstore[submat * qstore_dim1 + 1], ldqs, &e[ + submat + msd2 - 1], &iwork[indxq + submat], &rwork[iq], & + iwork[iqptr], &iwork[iprmpt], &iwork[iperm], &iwork[ + igivpt], &iwork[igivcl], &rwork[igivnm], &q[submat * + q_dim1 + 1], &rwork[iwrem], &iwork[subpbs + 1], info); + if (*info > 0) { + *info = submat * (*n + 1) + submat + matsiz - 1; + return 0; + } + iwork[i__ / 2 + 1] = iwork[i__ + 2]; +/* L90: */ + } + subpbs /= 2; + ++curlvl; + goto L80; + } + +/* + end while + + Re-merge the eigenvalues/vectors which were deflated at the final + merge step. +*/ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + j = iwork[indxq + i__]; + rwork[i__] = d__[j]; + zcopy_(qsiz, &qstore[j * qstore_dim1 + 1], &c__1, &q[i__ * q_dim1 + 1] + , &c__1); +/* L100: */ + } + dcopy_(n, &rwork[1], &c__1, &d__[1], &c__1); + + return 0; + +/* End of ZLAED0 */ + +} /* zlaed0_ */ + +/* Subroutine */ int zlaed7_(integer *n, integer *cutpnt, integer *qsiz, + integer *tlvls, integer *curlvl, integer *curpbm, doublereal *d__, + doublecomplex *q, integer *ldq, doublereal *rho, integer *indxq, + doublereal *qstore, integer *qptr, integer *prmptr, integer *perm, + integer *givptr, integer *givcol, doublereal *givnum, doublecomplex * + work, doublereal *rwork, integer *iwork, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, i__1, i__2; + + /* Local variables */ + static integer i__, k, n1, n2, iq, iw, iz, ptr, indx, curr, indxc, indxp; + extern /* Subroutine */ int dlaed9_(integer *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + doublereal *, doublereal *, doublereal *, integer *, integer *), + zlaed8_(integer *, integer *, integer *, doublecomplex *, integer + *, doublereal *, doublereal *, integer *, doublereal *, + doublereal *, doublecomplex *, integer *, doublereal *, integer *, + integer *, integer *, integer *, integer *, integer *, + doublereal *, integer *), dlaeda_(integer *, integer *, integer *, + integer *, integer *, integer *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, doublereal *, + integer *); + static integer idlmda; + extern /* Subroutine */ int dlamrg_(integer *, integer *, doublereal *, + integer *, integer *, integer *), xerbla_(char *, integer *), zlacrm_(integer *, integer *, doublecomplex *, integer *, + doublereal *, integer *, doublecomplex *, integer *, doublereal * + ); + static integer coltyp; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLAED7 computes the updated eigensystem of a diagonal + matrix after modification by a rank-one symmetric matrix. This + routine is used only for the eigenproblem which requires all + eigenvalues and optionally eigenvectors of a dense or banded + Hermitian matrix that has been reduced to tridiagonal form. + + T = Q(in) ( D(in) + RHO * Z*Z' ) Q'(in) = Q(out) * D(out) * Q'(out) + + where Z = Q'u, u is a vector of length N with ones in the + CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. + + The eigenvectors of the original matrix are stored in Q, and the + eigenvalues are in D. The algorithm consists of three stages: + + The first stage consists of deflating the size of the problem + when there are multiple eigenvalues or if there is a zero in + the Z vector. For each such occurence the dimension of the + secular equation problem is reduced by one. This stage is + performed by the routine DLAED2. + + The second stage consists of calculating the updated + eigenvalues. This is done by finding the roots of the secular + equation via the routine DLAED4 (as called by SLAED3). + This routine also calculates the eigenvectors of the current + problem. + + The final stage consists of computing the updated eigenvectors + directly using the updated eigenvalues. The eigenvectors for + the current problem are multiplied with the eigenvectors from + the overall problem. + + Arguments + ========= + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + CUTPNT (input) INTEGER + Contains the location of the last eigenvalue in the leading + sub-matrix. min(1,N) <= CUTPNT <= N. + + QSIZ (input) INTEGER + The dimension of the unitary matrix used to reduce + the full matrix to tridiagonal form. QSIZ >= N. + + TLVLS (input) INTEGER + The total number of merging levels in the overall divide and + conquer tree. + + CURLVL (input) INTEGER + The current level in the overall merge routine, + 0 <= curlvl <= tlvls. + + CURPBM (input) INTEGER + The current problem in the current level in the overall + merge routine (counting from upper left to lower right). + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the eigenvalues of the rank-1-perturbed matrix. + On exit, the eigenvalues of the repaired matrix. + + Q (input/output) COMPLEX*16 array, dimension (LDQ,N) + On entry, the eigenvectors of the rank-1-perturbed matrix. + On exit, the eigenvectors of the repaired tridiagonal matrix. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + RHO (input) DOUBLE PRECISION + Contains the subdiagonal element used to create the rank-1 + modification. + + INDXQ (output) INTEGER array, dimension (N) + This contains the permutation which will reintegrate the + subproblem just solved back into sorted order, + ie. D( INDXQ( I = 1, N ) ) will be in ascending order. + + IWORK (workspace) INTEGER array, dimension (4*N) + + RWORK (workspace) DOUBLE PRECISION array, + dimension (3*N+2*QSIZ*N) + + WORK (workspace) COMPLEX*16 array, dimension (QSIZ*N) + + QSTORE (input/output) DOUBLE PRECISION array, dimension (N**2+1) + Stores eigenvectors of submatrices encountered during + divide and conquer, packed together. QPTR points to + beginning of the submatrices. + + QPTR (input/output) INTEGER array, dimension (N+2) + List of indices pointing to beginning of submatrices stored + in QSTORE. The submatrices are numbered starting at the + bottom left of the divide and conquer tree, from left to + right and bottom to top. + + PRMPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in PERM a + level's permutation is stored. PRMPTR(i+1) - PRMPTR(i) + indicates the size of the permutation and also the size of + the full, non-deflated problem. + + PERM (input) INTEGER array, dimension (N lg N) + Contains the permutations (from deflation and sorting) to be + applied to each eigenblock. + + GIVPTR (input) INTEGER array, dimension (N lg N) + Contains a list of pointers which indicate where in GIVCOL a + level's Givens rotations are stored. GIVPTR(i+1) - GIVPTR(i) + indicates the number of Givens rotations. + + GIVCOL (input) INTEGER array, dimension (2, N lg N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (input) DOUBLE PRECISION array, dimension (2, N lg N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: if INFO = 1, an eigenvalue did not converge + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --indxq; + --qstore; + --qptr; + --prmptr; + --perm; + --givptr; + givcol -= 3; + givnum -= 3; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + +/* + IF( ICOMPQ.LT.0 .OR. ICOMPQ.GT.1 ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN +*/ + if (*n < 0) { + *info = -1; + } else if (min(1,*n) > *cutpnt || *n < *cutpnt) { + *info = -2; + } else if (*qsiz < *n) { + *info = -3; + } else if (*ldq < max(1,*n)) { + *info = -9; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLAED7", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* + The following values are for bookkeeping purposes only. They are + integer pointers which indicate the portion of the workspace + used by a particular array in DLAED2 and SLAED3. +*/ + + iz = 1; + idlmda = iz + *n; + iw = idlmda + *n; + iq = iw + *n; + + indx = 1; + indxc = indx + *n; + coltyp = indxc + *n; + indxp = coltyp + *n; + +/* + Form the z-vector which consists of the last row of Q_1 and the + first row of Q_2. +*/ + + ptr = pow_ii(&c__2, tlvls) + 1; + i__1 = *curlvl - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *tlvls - i__; + ptr += pow_ii(&c__2, &i__2); +/* L10: */ + } + curr = ptr + *curpbm; + dlaeda_(n, tlvls, curlvl, curpbm, &prmptr[1], &perm[1], &givptr[1], & + givcol[3], &givnum[3], &qstore[1], &qptr[1], &rwork[iz], &rwork[ + iz + *n], info); + +/* + When solving the final problem, we no longer need the stored data, + so we will overwrite the data from this level onto the previously + used storage space. +*/ + + if (*curlvl == *tlvls) { + qptr[curr] = 1; + prmptr[curr] = 1; + givptr[curr] = 1; + } + +/* Sort and Deflate eigenvalues. */ + + zlaed8_(&k, n, qsiz, &q[q_offset], ldq, &d__[1], rho, cutpnt, &rwork[iz], + &rwork[idlmda], &work[1], qsiz, &rwork[iw], &iwork[indxp], &iwork[ + indx], &indxq[1], &perm[prmptr[curr]], &givptr[curr + 1], &givcol[ + (givptr[curr] << 1) + 1], &givnum[(givptr[curr] << 1) + 1], info); + prmptr[curr + 1] = prmptr[curr] + *n; + givptr[curr + 1] += givptr[curr]; + +/* Solve Secular Equation. */ + + if (k != 0) { + dlaed9_(&k, &c__1, &k, n, &d__[1], &rwork[iq], &k, rho, &rwork[idlmda] + , &rwork[iw], &qstore[qptr[curr]], &k, info); + zlacrm_(qsiz, &k, &work[1], qsiz, &qstore[qptr[curr]], &k, &q[ + q_offset], ldq, &rwork[iq]); +/* Computing 2nd power */ + i__1 = k; + qptr[curr + 1] = qptr[curr] + i__1 * i__1; + if (*info != 0) { + return 0; + } + +/* Prepare the INDXQ sorting premutation. */ + + n1 = k; + n2 = *n - k; + dlamrg_(&n1, &n2, &d__[1], &c__1, &c_n1, &indxq[1]); + } else { + qptr[curr + 1] = qptr[curr]; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + indxq[i__] = i__; +/* L20: */ + } + } + + return 0; + +/* End of ZLAED7 */ + +} /* zlaed7_ */ + +/* Subroutine */ int zlaed8_(integer *k, integer *n, integer *qsiz, + doublecomplex *q, integer *ldq, doublereal *d__, doublereal *rho, + integer *cutpnt, doublereal *z__, doublereal *dlamda, doublecomplex * + q2, integer *ldq2, doublereal *w, integer *indxp, integer *indx, + integer *indxq, integer *perm, integer *givptr, integer *givcol, + doublereal *givnum, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, q2_dim1, q2_offset, i__1; + doublereal d__1; + + /* Local variables */ + static doublereal c__; + static integer i__, j; + static doublereal s, t; + static integer k2, n1, n2, jp, n1p1; + static doublereal eps, tau, tol; + static integer jlam, imax, jmax; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *), dcopy_(integer *, doublereal *, integer *, doublereal + *, integer *), zdrot_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublereal *, doublereal *), zcopy_( + integer *, doublecomplex *, integer *, doublecomplex *, integer *) + ; + + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dlamrg_(integer *, integer *, doublereal *, + integer *, integer *, integer *), xerbla_(char *, integer *), zlacpy_(char *, integer *, integer *, doublecomplex *, + integer *, doublecomplex *, integer *); + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + ZLAED8 merges the two sets of eigenvalues together into a single + sorted set. Then it tries to deflate the size of the problem. + There are two ways in which deflation can occur: when two or more + eigenvalues are close together or if there is a tiny element in the + Z vector. For each such occurrence the order of the related secular + equation problem is reduced by one. + + Arguments + ========= + + K (output) INTEGER + Contains the number of non-deflated eigenvalues. + This is the order of the related secular equation. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + QSIZ (input) INTEGER + The dimension of the unitary matrix used to reduce + the dense or band matrix to tridiagonal form. + QSIZ >= N if ICOMPQ = 1. + + Q (input/output) COMPLEX*16 array, dimension (LDQ,N) + On entry, Q contains the eigenvectors of the partially solved + system which has been previously updated in matrix + multiplies with other partially solved eigensystems. + On exit, Q contains the trailing (N-K) updated eigenvectors + (those which were deflated) in its last N-K columns. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max( 1, N ). + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, D contains the eigenvalues of the two submatrices to + be combined. On exit, D contains the trailing (N-K) updated + eigenvalues (those which were deflated) sorted into increasing + order. + + RHO (input/output) DOUBLE PRECISION + Contains the off diagonal element associated with the rank-1 + cut which originally split the two submatrices which are now + being recombined. RHO is modified during the computation to + the value required by DLAED3. + + CUTPNT (input) INTEGER + Contains the location of the last eigenvalue in the leading + sub-matrix. MIN(1,N) <= CUTPNT <= N. + + Z (input) DOUBLE PRECISION array, dimension (N) + On input this vector contains the updating vector (the last + row of the first sub-eigenvector matrix and the first row of + the second sub-eigenvector matrix). The contents of Z are + destroyed during the updating process. + + DLAMDA (output) DOUBLE PRECISION array, dimension (N) + Contains a copy of the first K eigenvalues which will be used + by DLAED3 to form the secular equation. + + Q2 (output) COMPLEX*16 array, dimension (LDQ2,N) + If ICOMPQ = 0, Q2 is not referenced. Otherwise, + Contains a copy of the first K eigenvectors which will be used + by DLAED7 in a matrix multiply (DGEMM) to update the new + eigenvectors. + + LDQ2 (input) INTEGER + The leading dimension of the array Q2. LDQ2 >= max( 1, N ). + + W (output) DOUBLE PRECISION array, dimension (N) + This will hold the first k values of the final + deflation-altered z-vector and will be passed to DLAED3. + + INDXP (workspace) INTEGER array, dimension (N) + This will contain the permutation used to place deflated + values of D at the end of the array. On output INDXP(1:K) + points to the nondeflated D-values and INDXP(K+1:N) + points to the deflated eigenvalues. + + INDX (workspace) INTEGER array, dimension (N) + This will contain the permutation used to sort the contents of + D into ascending order. + + INDXQ (input) INTEGER array, dimension (N) + This contains the permutation which separately sorts the two + sub-problems in D into ascending order. Note that elements in + the second half of this permutation must first have CUTPNT + added to their values in order to be accurate. + + PERM (output) INTEGER array, dimension (N) + Contains the permutations (from deflation and sorting) to be + applied to each eigenblock. + + GIVPTR (output) INTEGER + Contains the number of Givens rotations which took place in + this subproblem. + + GIVCOL (output) INTEGER array, dimension (2, N) + Each pair of numbers indicates a pair of columns to take place + in a Givens rotation. + + GIVNUM (output) DOUBLE PRECISION array, dimension (2, N) + Each number indicates the S value to be used in the + corresponding Givens rotation. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + --d__; + --z__; + --dlamda; + q2_dim1 = *ldq2; + q2_offset = 1 + q2_dim1; + q2 -= q2_offset; + --w; + --indxp; + --indx; + --indxq; + --perm; + givcol -= 3; + givnum -= 3; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -2; + } else if (*qsiz < *n) { + *info = -3; + } else if (*ldq < max(1,*n)) { + *info = -5; + } else if (*cutpnt < min(1,*n) || *cutpnt > *n) { + *info = -8; + } else if (*ldq2 < max(1,*n)) { + *info = -12; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLAED8", &i__1); + return 0; + } + +/* + Need to initialize GIVPTR to O here in case of quick exit + to prevent an unspecified code behavior (usually sigfault) + when IWORK array on entry to *stedc is not zeroed + (or at least some IWORK entries which used in *laed7 for GIVPTR). +*/ + + *givptr = 0; + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + n1 = *cutpnt; + n2 = *n - n1; + n1p1 = n1 + 1; + + if (*rho < 0.) { + dscal_(&n2, &c_b1276, &z__[n1p1], &c__1); + } + +/* Normalize z so that norm(z) = 1 */ + + t = 1. / sqrt(2.); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + indx[j] = j; +/* L10: */ + } + dscal_(n, &t, &z__[1], &c__1); + *rho = (d__1 = *rho * 2., abs(d__1)); + +/* Sort the eigenvalues into increasing order */ + + i__1 = *n; + for (i__ = *cutpnt + 1; i__ <= i__1; ++i__) { + indxq[i__] += *cutpnt; +/* L20: */ + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + dlamda[i__] = d__[indxq[i__]]; + w[i__] = z__[indxq[i__]]; +/* L30: */ + } + i__ = 1; + j = *cutpnt + 1; + dlamrg_(&n1, &n2, &dlamda[1], &c__1, &c__1, &indx[1]); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + d__[i__] = dlamda[indx[i__]]; + z__[i__] = w[indx[i__]]; +/* L40: */ + } + +/* Calculate the allowable deflation tolerance */ + + imax = idamax_(n, &z__[1], &c__1); + jmax = idamax_(n, &d__[1], &c__1); + eps = EPSILON; + tol = eps * 8. * (d__1 = d__[jmax], abs(d__1)); + +/* + If the rank-1 modifier is small enough, no more needs to be done + -- except to reorganize Q so that its columns correspond with the + elements in D. +*/ + + if (*rho * (d__1 = z__[imax], abs(d__1)) <= tol) { + *k = 0; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + perm[j] = indxq[indx[j]]; + zcopy_(qsiz, &q[perm[j] * q_dim1 + 1], &c__1, &q2[j * q2_dim1 + 1] + , &c__1); +/* L50: */ + } + zlacpy_("A", qsiz, n, &q2[q2_dim1 + 1], ldq2, &q[q_dim1 + 1], ldq); + return 0; + } + +/* + If there are multiple eigenvalues then the problem deflates. Here + the number of equal eigenvalues are found. As each equal + eigenvalue is found, an elementary reflector is computed to rotate + the corresponding eigensubspace so that the corresponding + components of Z are zero in this new basis. +*/ + + *k = 0; + k2 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*rho * (d__1 = z__[j], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + indxp[k2] = j; + if (j == *n) { + goto L100; + } + } else { + jlam = j; + goto L70; + } +/* L60: */ + } +L70: + ++j; + if (j > *n) { + goto L90; + } + if (*rho * (d__1 = z__[j], abs(d__1)) <= tol) { + +/* Deflate due to small z component. */ + + --k2; + indxp[k2] = j; + } else { + +/* Check if eigenvalues are close enough to allow deflation. */ + + s = z__[jlam]; + c__ = z__[j]; + +/* + Find sqrt(a**2+b**2) without overflow or + destructive underflow. +*/ + + tau = dlapy2_(&c__, &s); + t = d__[j] - d__[jlam]; + c__ /= tau; + s = -s / tau; + if ((d__1 = t * c__ * s, abs(d__1)) <= tol) { + +/* Deflation is possible. */ + + z__[j] = tau; + z__[jlam] = 0.; + +/* Record the appropriate Givens rotation */ + + ++(*givptr); + givcol[(*givptr << 1) + 1] = indxq[indx[jlam]]; + givcol[(*givptr << 1) + 2] = indxq[indx[j]]; + givnum[(*givptr << 1) + 1] = c__; + givnum[(*givptr << 1) + 2] = s; + zdrot_(qsiz, &q[indxq[indx[jlam]] * q_dim1 + 1], &c__1, &q[indxq[ + indx[j]] * q_dim1 + 1], &c__1, &c__, &s); + t = d__[jlam] * c__ * c__ + d__[j] * s * s; + d__[j] = d__[jlam] * s * s + d__[j] * c__ * c__; + d__[jlam] = t; + --k2; + i__ = 1; +L80: + if (k2 + i__ <= *n) { + if (d__[jlam] < d__[indxp[k2 + i__]]) { + indxp[k2 + i__ - 1] = indxp[k2 + i__]; + indxp[k2 + i__] = jlam; + ++i__; + goto L80; + } else { + indxp[k2 + i__ - 1] = jlam; + } + } else { + indxp[k2 + i__ - 1] = jlam; + } + jlam = j; + } else { + ++(*k); + w[*k] = z__[jlam]; + dlamda[*k] = d__[jlam]; + indxp[*k] = jlam; + jlam = j; + } + } + goto L70; +L90: + +/* Record the last eigenvalue. */ + + ++(*k); + w[*k] = z__[jlam]; + dlamda[*k] = d__[jlam]; + indxp[*k] = jlam; + +L100: + +/* + Sort the eigenvalues and corresponding eigenvectors into DLAMDA + and Q2 respectively. The eigenvalues/vectors which were not + deflated go into the first K slots of DLAMDA and Q2 respectively, + while those which were deflated go into the last N - K slots. +*/ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + jp = indxp[j]; + dlamda[j] = d__[jp]; + perm[j] = indxq[indx[jp]]; + zcopy_(qsiz, &q[perm[j] * q_dim1 + 1], &c__1, &q2[j * q2_dim1 + 1], & + c__1); +/* L110: */ + } + +/* + The deflated eigenvalues and their corresponding vectors go back + into the last N - K slots of D and Q respectively. +*/ + + if (*k < *n) { + i__1 = *n - *k; + dcopy_(&i__1, &dlamda[*k + 1], &c__1, &d__[*k + 1], &c__1); + i__1 = *n - *k; + zlacpy_("A", qsiz, &i__1, &q2[(*k + 1) * q2_dim1 + 1], ldq2, &q[(*k + + 1) * q_dim1 + 1], ldq); + } + + return 0; + +/* End of ZLAED8 */ + +} /* zlaed8_ */ + +/* Subroutine */ int zlahqr_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, + doublecomplex *w, integer *iloz, integer *ihiz, doublecomplex *z__, + integer *ldz, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2, d__3, d__4, d__5, d__6; + doublecomplex z__1, z__2, z__3, z__4, z__5, z__6, z__7; + + /* Local variables */ + static integer i__, j, k, l, m; + static doublereal s; + static doublecomplex t, u, v[2], x, y; + static integer i1, i2; + static doublecomplex t1; + static doublereal t2; + static doublecomplex v2; + static doublereal aa, ab, ba, bb, h10; + static doublecomplex h11; + static doublereal h21; + static doublecomplex h22, sc; + static integer nh, nz; + static doublereal sx; + static integer jhi; + static doublecomplex h11s; + static integer jlo, its; + static doublereal ulp; + static doublecomplex sum; + static doublereal tst; + static doublecomplex temp; + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *); + static doublereal rtemp; + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), dlabad_(doublereal *, doublereal *); + + static doublereal safmin, safmax; + extern /* Subroutine */ int zlarfg_(integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *); + extern /* Double Complex */ VOID zladiv_(doublecomplex *, doublecomplex *, + doublecomplex *); + static doublereal smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Purpose + ======= + + ZLAHQR is an auxiliary routine called by CHSEQR to update the + eigenvalues and Schur decomposition already computed by CHSEQR, by + dealing with the Hessenberg submatrix in rows and columns ILO to + IHI. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows and + columns IHI+1:N, and that H(ILO,ILO-1) = 0 (unless ILO = 1). + ZLAHQR works primarily with the Hessenberg submatrix in rows + and columns ILO to IHI, but applies transformations to all of + H if WANTT is .TRUE.. + 1 <= ILO <= max(1,IHI); IHI <= N. + + H (input/output) COMPLEX*16 array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO is zero and if WANTT is .TRUE., then H + is upper triangular in rows and columns ILO:IHI. If INFO + is zero and if WANTT is .FALSE., then the contents of H + are unspecified on exit. The output state of H in case + INF is positive is below under the description of INFO. + + LDH (input) INTEGER + The leading dimension of the array H. LDH >= max(1,N). + + W (output) COMPLEX*16 array, dimension (N) + The computed eigenvalues ILO to IHI are stored in the + corresponding elements of W. If WANTT is .TRUE., the + eigenvalues are stored in the same order as on the diagonal + of the Schur form returned in H, with W(i) = H(i,i). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. + 1 <= ILOZ <= ILO; IHI <= IHIZ <= N. + + Z (input/output) COMPLEX*16 array, dimension (LDZ,N) + If WANTZ is .TRUE., on entry Z must contain the current + matrix Z of transformations accumulated by CHSEQR, and on + exit Z has been updated; transformations are applied only to + the submatrix Z(ILOZ:IHIZ,ILO:IHI). + If WANTZ is .FALSE., Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, ZLAHQR failed to compute all the + eigenvalues ILO to IHI in a total of 30 iterations + per eigenvalue; elements i+1:ihi of W contain + those eigenvalues which have been successfully + computed. + + If INFO .GT. 0 and WANTT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the + eigenvalues of the upper Hessenberg matrix + rows and columns ILO thorugh INFO of the final, + output value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + (*) (initial value of H)*U = U*(final value of H) + where U is an orthognal matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + (final value of Z) = (initial value of Z)*U + where U is the orthogonal matrix in (*) + (regardless of the value of WANTT.) + + Further Details + =============== + + 02-96 Based on modifications by + David Day, Sandia National Laboratory, USA + + 12-04 Further modifications by + Ralph Byers, University of Kansas, USA + This is a modified version of ZLAHQR from LAPACK version 3.0. + It is (1) more robust against overflow and underflow and + (2) adopts the more conservative Ahues & Tisseur stopping + criterion (LAWN 122, 1997). + + ========================================================= +*/ + + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --w; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + + /* Function Body */ + *info = 0; + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*ilo == *ihi) { + i__1 = *ilo; + i__2 = *ilo + *ilo * h_dim1; + w[i__1].r = h__[i__2].r, w[i__1].i = h__[i__2].i; + return 0; + } + +/* ==== clear out the trash ==== */ + i__1 = *ihi - 3; + for (j = *ilo; j <= i__1; ++j) { + i__2 = j + 2 + j * h_dim1; + h__[i__2].r = 0., h__[i__2].i = 0.; + i__2 = j + 3 + j * h_dim1; + h__[i__2].r = 0., h__[i__2].i = 0.; +/* L10: */ + } + if (*ilo <= *ihi - 2) { + i__1 = *ihi + (*ihi - 2) * h_dim1; + h__[i__1].r = 0., h__[i__1].i = 0.; + } +/* ==== ensure that subdiagonal entries are real ==== */ + if (*wantt) { + jlo = 1; + jhi = *n; + } else { + jlo = *ilo; + jhi = *ihi; + } + i__1 = *ihi; + for (i__ = *ilo + 1; i__ <= i__1; ++i__) { + if (d_imag(&h__[i__ + (i__ - 1) * h_dim1]) != 0.) { +/* + ==== The following redundant normalization + . avoids problems with both gradual and + . sudden underflow in ABS(H(I,I-1)) ==== +*/ + i__2 = i__ + (i__ - 1) * h_dim1; + i__3 = i__ + (i__ - 1) * h_dim1; + d__3 = (d__1 = h__[i__3].r, abs(d__1)) + (d__2 = d_imag(&h__[i__ + + (i__ - 1) * h_dim1]), abs(d__2)); + z__1.r = h__[i__2].r / d__3, z__1.i = h__[i__2].i / d__3; + sc.r = z__1.r, sc.i = z__1.i; + d_cnjg(&z__2, &sc); + d__1 = z_abs(&sc); + z__1.r = z__2.r / d__1, z__1.i = z__2.i / d__1; + sc.r = z__1.r, sc.i = z__1.i; + i__2 = i__ + (i__ - 1) * h_dim1; + d__1 = z_abs(&h__[i__ + (i__ - 1) * h_dim1]); + h__[i__2].r = d__1, h__[i__2].i = 0.; + i__2 = jhi - i__ + 1; + zscal_(&i__2, &sc, &h__[i__ + i__ * h_dim1], ldh); +/* Computing MIN */ + i__3 = jhi, i__4 = i__ + 1; + i__2 = min(i__3,i__4) - jlo + 1; + d_cnjg(&z__1, &sc); + zscal_(&i__2, &z__1, &h__[jlo + i__ * h_dim1], &c__1); + if (*wantz) { + i__2 = *ihiz - *iloz + 1; + d_cnjg(&z__1, &sc); + zscal_(&i__2, &z__1, &z__[*iloz + i__ * z_dim1], &c__1); + } + } +/* L20: */ + } + + nh = *ihi - *ilo + 1; + nz = *ihiz - *iloz + 1; + +/* Set machine-dependent constants for the stopping criterion. */ + + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + dlabad_(&safmin, &safmax); + ulp = PRECISION; + smlnum = safmin * ((doublereal) nh / ulp); + +/* + I1 and I2 are the indices of the first row and last column of H + to which transformations must be applied. If eigenvalues only are + being computed, I1 and I2 are set inside the main loop. +*/ + + if (*wantt) { + i1 = 1; + i2 = *n; + } + +/* + The main loop begins here. I is the loop index and decreases from + IHI to ILO in steps of 1. Each iteration of the loop works + with the active submatrix in rows and columns L to I. + Eigenvalues I+1 to IHI have already converged. Either L = ILO, or + H(L,L-1) is negligible so that the matrix splits. +*/ + + i__ = *ihi; +L30: + if (i__ < *ilo) { + goto L150; + } + +/* + Perform QR iterations on rows and columns ILO to I until a + submatrix of order 1 splits off at the bottom because a + subdiagonal element has become negligible. +*/ + + l = *ilo; + for (its = 0; its <= 30; ++its) { + +/* Look for a single small subdiagonal element. */ + + i__1 = l + 1; + for (k = i__; k >= i__1; --k) { + i__2 = k + (k - 1) * h_dim1; + if ((d__1 = h__[i__2].r, abs(d__1)) + (d__2 = d_imag(&h__[k + (k + - 1) * h_dim1]), abs(d__2)) <= smlnum) { + goto L50; + } + i__2 = k - 1 + (k - 1) * h_dim1; + i__3 = k + k * h_dim1; + tst = (d__1 = h__[i__2].r, abs(d__1)) + (d__2 = d_imag(&h__[k - 1 + + (k - 1) * h_dim1]), abs(d__2)) + ((d__3 = h__[i__3].r, + abs(d__3)) + (d__4 = d_imag(&h__[k + k * h_dim1]), abs( + d__4))); + if (tst == 0.) { + if (k - 2 >= *ilo) { + i__2 = k - 1 + (k - 2) * h_dim1; + tst += (d__1 = h__[i__2].r, abs(d__1)); + } + if (k + 1 <= *ihi) { + i__2 = k + 1 + k * h_dim1; + tst += (d__1 = h__[i__2].r, abs(d__1)); + } + } +/* + ==== The following is a conservative small subdiagonal + . deflation criterion due to Ahues & Tisseur (LAWN 122, + . 1997). It has better mathematical foundation and + . improves accuracy in some examples. ==== +*/ + i__2 = k + (k - 1) * h_dim1; + if ((d__1 = h__[i__2].r, abs(d__1)) <= ulp * tst) { +/* Computing MAX */ + i__2 = k + (k - 1) * h_dim1; + i__3 = k - 1 + k * h_dim1; + d__5 = (d__1 = h__[i__2].r, abs(d__1)) + (d__2 = d_imag(&h__[ + k + (k - 1) * h_dim1]), abs(d__2)), d__6 = (d__3 = + h__[i__3].r, abs(d__3)) + (d__4 = d_imag(&h__[k - 1 + + k * h_dim1]), abs(d__4)); + ab = max(d__5,d__6); +/* Computing MIN */ + i__2 = k + (k - 1) * h_dim1; + i__3 = k - 1 + k * h_dim1; + d__5 = (d__1 = h__[i__2].r, abs(d__1)) + (d__2 = d_imag(&h__[ + k + (k - 1) * h_dim1]), abs(d__2)), d__6 = (d__3 = + h__[i__3].r, abs(d__3)) + (d__4 = d_imag(&h__[k - 1 + + k * h_dim1]), abs(d__4)); + ba = min(d__5,d__6); + i__2 = k - 1 + (k - 1) * h_dim1; + i__3 = k + k * h_dim1; + z__2.r = h__[i__2].r - h__[i__3].r, z__2.i = h__[i__2].i - + h__[i__3].i; + z__1.r = z__2.r, z__1.i = z__2.i; +/* Computing MAX */ + i__4 = k + k * h_dim1; + d__5 = (d__1 = h__[i__4].r, abs(d__1)) + (d__2 = d_imag(&h__[ + k + k * h_dim1]), abs(d__2)), d__6 = (d__3 = z__1.r, + abs(d__3)) + (d__4 = d_imag(&z__1), abs(d__4)); + aa = max(d__5,d__6); + i__2 = k - 1 + (k - 1) * h_dim1; + i__3 = k + k * h_dim1; + z__2.r = h__[i__2].r - h__[i__3].r, z__2.i = h__[i__2].i - + h__[i__3].i; + z__1.r = z__2.r, z__1.i = z__2.i; +/* Computing MIN */ + i__4 = k + k * h_dim1; + d__5 = (d__1 = h__[i__4].r, abs(d__1)) + (d__2 = d_imag(&h__[ + k + k * h_dim1]), abs(d__2)), d__6 = (d__3 = z__1.r, + abs(d__3)) + (d__4 = d_imag(&z__1), abs(d__4)); + bb = min(d__5,d__6); + s = aa + ab; +/* Computing MAX */ + d__1 = smlnum, d__2 = ulp * (bb * (aa / s)); + if (ba * (ab / s) <= max(d__1,d__2)) { + goto L50; + } + } +/* L40: */ + } +L50: + l = k; + if (l > *ilo) { + +/* H(L,L-1) is negligible */ + + i__1 = l + (l - 1) * h_dim1; + h__[i__1].r = 0., h__[i__1].i = 0.; + } + +/* Exit from loop if a submatrix of order 1 has split off. */ + + if (l >= i__) { + goto L140; + } + +/* + Now the active submatrix is in rows and columns L to I. If + eigenvalues only are being computed, only the active submatrix + need be transformed. +*/ + + if (! (*wantt)) { + i1 = l; + i2 = i__; + } + + if (its == 10) { + +/* Exceptional shift. */ + + i__1 = l + 1 + l * h_dim1; + s = (d__1 = h__[i__1].r, abs(d__1)) * .75; + i__1 = l + l * h_dim1; + z__1.r = s + h__[i__1].r, z__1.i = h__[i__1].i; + t.r = z__1.r, t.i = z__1.i; + } else if (its == 20) { + +/* Exceptional shift. */ + + i__1 = i__ + (i__ - 1) * h_dim1; + s = (d__1 = h__[i__1].r, abs(d__1)) * .75; + i__1 = i__ + i__ * h_dim1; + z__1.r = s + h__[i__1].r, z__1.i = h__[i__1].i; + t.r = z__1.r, t.i = z__1.i; + } else { + +/* Wilkinson's shift. */ + + i__1 = i__ + i__ * h_dim1; + t.r = h__[i__1].r, t.i = h__[i__1].i; + z_sqrt(&z__2, &h__[i__ - 1 + i__ * h_dim1]); + z_sqrt(&z__3, &h__[i__ + (i__ - 1) * h_dim1]); + z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, z__1.i = z__2.r * + z__3.i + z__2.i * z__3.r; + u.r = z__1.r, u.i = z__1.i; + s = (d__1 = u.r, abs(d__1)) + (d__2 = d_imag(&u), abs(d__2)); + if (s != 0.) { + i__1 = i__ - 1 + (i__ - 1) * h_dim1; + z__2.r = h__[i__1].r - t.r, z__2.i = h__[i__1].i - t.i; + z__1.r = z__2.r * .5, z__1.i = z__2.i * .5; + x.r = z__1.r, x.i = z__1.i; + sx = (d__1 = x.r, abs(d__1)) + (d__2 = d_imag(&x), abs(d__2)); +/* Computing MAX */ + d__3 = s, d__4 = (d__1 = x.r, abs(d__1)) + (d__2 = d_imag(&x), + abs(d__2)); + s = max(d__3,d__4); + z__5.r = x.r / s, z__5.i = x.i / s; + pow_zi(&z__4, &z__5, &c__2); + z__7.r = u.r / s, z__7.i = u.i / s; + pow_zi(&z__6, &z__7, &c__2); + z__3.r = z__4.r + z__6.r, z__3.i = z__4.i + z__6.i; + z_sqrt(&z__2, &z__3); + z__1.r = s * z__2.r, z__1.i = s * z__2.i; + y.r = z__1.r, y.i = z__1.i; + if (sx > 0.) { + z__1.r = x.r / sx, z__1.i = x.i / sx; + z__2.r = x.r / sx, z__2.i = x.i / sx; + if (z__1.r * y.r + d_imag(&z__2) * d_imag(&y) < 0.) { + z__3.r = -y.r, z__3.i = -y.i; + y.r = z__3.r, y.i = z__3.i; + } + } + z__4.r = x.r + y.r, z__4.i = x.i + y.i; + zladiv_(&z__3, &u, &z__4); + z__2.r = u.r * z__3.r - u.i * z__3.i, z__2.i = u.r * z__3.i + + u.i * z__3.r; + z__1.r = t.r - z__2.r, z__1.i = t.i - z__2.i; + t.r = z__1.r, t.i = z__1.i; + } + } + +/* Look for two consecutive small subdiagonal elements. */ + + i__1 = l + 1; + for (m = i__ - 1; m >= i__1; --m) { + +/* + Determine the effect of starting the single-shift QR + iteration at row M, and see if this would make H(M,M-1) + negligible. +*/ + + i__2 = m + m * h_dim1; + h11.r = h__[i__2].r, h11.i = h__[i__2].i; + i__2 = m + 1 + (m + 1) * h_dim1; + h22.r = h__[i__2].r, h22.i = h__[i__2].i; + z__1.r = h11.r - t.r, z__1.i = h11.i - t.i; + h11s.r = z__1.r, h11s.i = z__1.i; + i__2 = m + 1 + m * h_dim1; + h21 = h__[i__2].r; + s = (d__1 = h11s.r, abs(d__1)) + (d__2 = d_imag(&h11s), abs(d__2)) + + abs(h21); + z__1.r = h11s.r / s, z__1.i = h11s.i / s; + h11s.r = z__1.r, h11s.i = z__1.i; + h21 /= s; + v[0].r = h11s.r, v[0].i = h11s.i; + v[1].r = h21, v[1].i = 0.; + i__2 = m + (m - 1) * h_dim1; + h10 = h__[i__2].r; + if (abs(h10) * abs(h21) <= ulp * (((d__1 = h11s.r, abs(d__1)) + ( + d__2 = d_imag(&h11s), abs(d__2))) * ((d__3 = h11.r, abs( + d__3)) + (d__4 = d_imag(&h11), abs(d__4)) + ((d__5 = + h22.r, abs(d__5)) + (d__6 = d_imag(&h22), abs(d__6)))))) { + goto L70; + } +/* L60: */ + } + i__1 = l + l * h_dim1; + h11.r = h__[i__1].r, h11.i = h__[i__1].i; + i__1 = l + 1 + (l + 1) * h_dim1; + h22.r = h__[i__1].r, h22.i = h__[i__1].i; + z__1.r = h11.r - t.r, z__1.i = h11.i - t.i; + h11s.r = z__1.r, h11s.i = z__1.i; + i__1 = l + 1 + l * h_dim1; + h21 = h__[i__1].r; + s = (d__1 = h11s.r, abs(d__1)) + (d__2 = d_imag(&h11s), abs(d__2)) + + abs(h21); + z__1.r = h11s.r / s, z__1.i = h11s.i / s; + h11s.r = z__1.r, h11s.i = z__1.i; + h21 /= s; + v[0].r = h11s.r, v[0].i = h11s.i; + v[1].r = h21, v[1].i = 0.; +L70: + +/* Single-shift QR step */ + + i__1 = i__ - 1; + for (k = m; k <= i__1; ++k) { + +/* + The first iteration of this loop determines a reflection G + from the vector V and applies it from left and right to H, + thus creating a nonzero bulge below the subdiagonal. + + Each subsequent iteration determines a reflection G to + restore the Hessenberg form in the (K-1)th column, and thus + chases the bulge one step toward the bottom of the active + submatrix. + + V(2) is always real before the call to ZLARFG, and hence + after the call T2 ( = T1*V(2) ) is also real. +*/ + + if (k > m) { + zcopy_(&c__2, &h__[k + (k - 1) * h_dim1], &c__1, v, &c__1); + } + zlarfg_(&c__2, v, &v[1], &c__1, &t1); + if (k > m) { + i__2 = k + (k - 1) * h_dim1; + h__[i__2].r = v[0].r, h__[i__2].i = v[0].i; + i__2 = k + 1 + (k - 1) * h_dim1; + h__[i__2].r = 0., h__[i__2].i = 0.; + } + v2.r = v[1].r, v2.i = v[1].i; + z__1.r = t1.r * v2.r - t1.i * v2.i, z__1.i = t1.r * v2.i + t1.i * + v2.r; + t2 = z__1.r; + +/* + Apply G from the left to transform the rows of the matrix + in columns K to I2. +*/ + + i__2 = i2; + for (j = k; j <= i__2; ++j) { + d_cnjg(&z__3, &t1); + i__3 = k + j * h_dim1; + z__2.r = z__3.r * h__[i__3].r - z__3.i * h__[i__3].i, z__2.i = + z__3.r * h__[i__3].i + z__3.i * h__[i__3].r; + i__4 = k + 1 + j * h_dim1; + z__4.r = t2 * h__[i__4].r, z__4.i = t2 * h__[i__4].i; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + sum.r = z__1.r, sum.i = z__1.i; + i__3 = k + j * h_dim1; + i__4 = k + j * h_dim1; + z__1.r = h__[i__4].r - sum.r, z__1.i = h__[i__4].i - sum.i; + h__[i__3].r = z__1.r, h__[i__3].i = z__1.i; + i__3 = k + 1 + j * h_dim1; + i__4 = k + 1 + j * h_dim1; + z__2.r = sum.r * v2.r - sum.i * v2.i, z__2.i = sum.r * v2.i + + sum.i * v2.r; + z__1.r = h__[i__4].r - z__2.r, z__1.i = h__[i__4].i - z__2.i; + h__[i__3].r = z__1.r, h__[i__3].i = z__1.i; +/* L80: */ + } + +/* + Apply G from the right to transform the columns of the + matrix in rows I1 to min(K+2,I). + + Computing MIN +*/ + i__3 = k + 2; + i__2 = min(i__3,i__); + for (j = i1; j <= i__2; ++j) { + i__3 = j + k * h_dim1; + z__2.r = t1.r * h__[i__3].r - t1.i * h__[i__3].i, z__2.i = + t1.r * h__[i__3].i + t1.i * h__[i__3].r; + i__4 = j + (k + 1) * h_dim1; + z__3.r = t2 * h__[i__4].r, z__3.i = t2 * h__[i__4].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + sum.r = z__1.r, sum.i = z__1.i; + i__3 = j + k * h_dim1; + i__4 = j + k * h_dim1; + z__1.r = h__[i__4].r - sum.r, z__1.i = h__[i__4].i - sum.i; + h__[i__3].r = z__1.r, h__[i__3].i = z__1.i; + i__3 = j + (k + 1) * h_dim1; + i__4 = j + (k + 1) * h_dim1; + d_cnjg(&z__3, &v2); + z__2.r = sum.r * z__3.r - sum.i * z__3.i, z__2.i = sum.r * + z__3.i + sum.i * z__3.r; + z__1.r = h__[i__4].r - z__2.r, z__1.i = h__[i__4].i - z__2.i; + h__[i__3].r = z__1.r, h__[i__3].i = z__1.i; +/* L90: */ + } + + if (*wantz) { + +/* Accumulate transformations in the matrix Z */ + + i__2 = *ihiz; + for (j = *iloz; j <= i__2; ++j) { + i__3 = j + k * z_dim1; + z__2.r = t1.r * z__[i__3].r - t1.i * z__[i__3].i, z__2.i = + t1.r * z__[i__3].i + t1.i * z__[i__3].r; + i__4 = j + (k + 1) * z_dim1; + z__3.r = t2 * z__[i__4].r, z__3.i = t2 * z__[i__4].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + sum.r = z__1.r, sum.i = z__1.i; + i__3 = j + k * z_dim1; + i__4 = j + k * z_dim1; + z__1.r = z__[i__4].r - sum.r, z__1.i = z__[i__4].i - + sum.i; + z__[i__3].r = z__1.r, z__[i__3].i = z__1.i; + i__3 = j + (k + 1) * z_dim1; + i__4 = j + (k + 1) * z_dim1; + d_cnjg(&z__3, &v2); + z__2.r = sum.r * z__3.r - sum.i * z__3.i, z__2.i = sum.r * + z__3.i + sum.i * z__3.r; + z__1.r = z__[i__4].r - z__2.r, z__1.i = z__[i__4].i - + z__2.i; + z__[i__3].r = z__1.r, z__[i__3].i = z__1.i; +/* L100: */ + } + } + + if (k == m && m > l) { + +/* + If the QR step was started at row M > L because two + consecutive small subdiagonals were found, then extra + scaling must be performed to ensure that H(M,M-1) remains + real. +*/ + + z__1.r = 1. - t1.r, z__1.i = 0. - t1.i; + temp.r = z__1.r, temp.i = z__1.i; + d__1 = z_abs(&temp); + z__1.r = temp.r / d__1, z__1.i = temp.i / d__1; + temp.r = z__1.r, temp.i = z__1.i; + i__2 = m + 1 + m * h_dim1; + i__3 = m + 1 + m * h_dim1; + d_cnjg(&z__2, &temp); + z__1.r = h__[i__3].r * z__2.r - h__[i__3].i * z__2.i, z__1.i = + h__[i__3].r * z__2.i + h__[i__3].i * z__2.r; + h__[i__2].r = z__1.r, h__[i__2].i = z__1.i; + if (m + 2 <= i__) { + i__2 = m + 2 + (m + 1) * h_dim1; + i__3 = m + 2 + (m + 1) * h_dim1; + z__1.r = h__[i__3].r * temp.r - h__[i__3].i * temp.i, + z__1.i = h__[i__3].r * temp.i + h__[i__3].i * + temp.r; + h__[i__2].r = z__1.r, h__[i__2].i = z__1.i; + } + i__2 = i__; + for (j = m; j <= i__2; ++j) { + if (j != m + 1) { + if (i2 > j) { + i__3 = i2 - j; + zscal_(&i__3, &temp, &h__[j + (j + 1) * h_dim1], + ldh); + } + i__3 = j - i1; + d_cnjg(&z__1, &temp); + zscal_(&i__3, &z__1, &h__[i1 + j * h_dim1], &c__1); + if (*wantz) { + d_cnjg(&z__1, &temp); + zscal_(&nz, &z__1, &z__[*iloz + j * z_dim1], & + c__1); + } + } +/* L110: */ + } + } +/* L120: */ + } + +/* Ensure that H(I,I-1) is real. */ + + i__1 = i__ + (i__ - 1) * h_dim1; + temp.r = h__[i__1].r, temp.i = h__[i__1].i; + if (d_imag(&temp) != 0.) { + rtemp = z_abs(&temp); + i__1 = i__ + (i__ - 1) * h_dim1; + h__[i__1].r = rtemp, h__[i__1].i = 0.; + z__1.r = temp.r / rtemp, z__1.i = temp.i / rtemp; + temp.r = z__1.r, temp.i = z__1.i; + if (i2 > i__) { + i__1 = i2 - i__; + d_cnjg(&z__1, &temp); + zscal_(&i__1, &z__1, &h__[i__ + (i__ + 1) * h_dim1], ldh); + } + i__1 = i__ - i1; + zscal_(&i__1, &temp, &h__[i1 + i__ * h_dim1], &c__1); + if (*wantz) { + zscal_(&nz, &temp, &z__[*iloz + i__ * z_dim1], &c__1); + } + } + +/* L130: */ + } + +/* Failure to converge in remaining number of iterations */ + + *info = i__; + return 0; + +L140: + +/* H(I,I-1) is negligible: one eigenvalue has converged. */ + + i__1 = i__; + i__2 = i__ + i__ * h_dim1; + w[i__1].r = h__[i__2].r, w[i__1].i = h__[i__2].i; + +/* return to start of the main loop with new value of I. */ + + i__ = l - 1; + goto L30; + +L150: + return 0; + +/* End of ZLAHQR */ + +} /* zlahqr_ */ + +/* Subroutine */ int zlahr2_(integer *n, integer *k, integer *nb, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *t, + integer *ldt, doublecomplex *y, integer *ldy) +{ + /* System generated locals */ + integer a_dim1, a_offset, t_dim1, t_offset, y_dim1, y_offset, i__1, i__2, + i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__; + static doublecomplex ei; + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *), zgemm_(char *, char *, integer *, + integer *, integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), zgemv_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *), + zcopy_(integer *, doublecomplex *, integer *, doublecomplex *, + integer *), ztrmm_(char *, char *, char *, char *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *), + zaxpy_(integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *), ztrmv_(char *, char *, char *, + integer *, doublecomplex *, integer *, doublecomplex *, integer *), zlarfg_(integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *), zlacgv_(integer *, + doublecomplex *, integer *), zlacpy_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + -- April 2009 -- + + + Purpose + ======= + + ZLAHR2 reduces the first NB columns of A complex general n-BY-(n-k+1) + matrix A so that elements below the k-th subdiagonal are zero. The + reduction is performed by an unitary similarity transformation + Q' * A * Q. The routine returns the matrices V and T which determine + Q as a block reflector I - V*T*V', and also the matrix Y = A * V * T. + + This is an auxiliary routine called by ZGEHRD. + + Arguments + ========= + + N (input) INTEGER + The order of the matrix A. + + K (input) INTEGER + The offset for the reduction. Elements below the k-th + subdiagonal in the first NB columns are reduced to zero. + K < N. + + NB (input) INTEGER + The number of columns to be reduced. + + A (input/output) COMPLEX*16 array, dimension (LDA,N-K+1) + On entry, the n-by-(n-k+1) general matrix A. + On exit, the elements on and above the k-th subdiagonal in + the first NB columns are overwritten with the corresponding + elements of the reduced matrix; the elements below the k-th + subdiagonal, with the array TAU, represent the matrix Q as a + product of elementary reflectors. The other columns of A are + unchanged. See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (output) COMPLEX*16 array, dimension (NB) + The scalar factors of the elementary reflectors. See Further + Details. + + T (output) COMPLEX*16 array, dimension (LDT,NB) + The upper triangular matrix T. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= NB. + + Y (output) COMPLEX*16 array, dimension (LDY,NB) + The n-by-nb matrix Y. + + LDY (input) INTEGER + The leading dimension of the array Y. LDY >= N. + + Further Details + =============== + + The matrix Q is represented as a product of nb elementary reflectors + + Q = H(1) H(2) . . . H(nb). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i+k-1) = 0, v(i+k) = 1; v(i+k+1:n) is stored on exit in + A(i+k+1:n,i), and tau in TAU(i). + + The elements of the vectors v together form the (n-k+1)-by-nb matrix + V which is needed, with T and Y, to apply the transformation to the + unreduced part of the matrix, using an update of the form: + A := (I - V*T*V') * (A - Y*V'). + + The contents of A on exit are illustrated by the following example + with n = 7, k = 3 and nb = 2: + + ( a a a a a ) + ( a a a a a ) + ( a a a a a ) + ( h h a a a ) + ( v1 h a a a ) + ( v1 v2 a a a ) + ( v1 v2 a a a ) + + where a denotes an element of the original matrix A, h denotes a + modified element of the upper Hessenberg matrix H, and vi denotes an + element of the vector defining H(i). + + This subroutine is a slight modification of LAPACK-3.0's DLAHRD + incorporating improvements proposed by Quintana-Orti and Van de + Gejin. Note that the entries of A(1:K,2:NB) differ from those + returned by the original LAPACK-3.0's DLAHRD routine. (This + subroutine is not backward compatible with LAPACK-3.0's DLAHRD.) + + References + ========== + + Gregorio Quintana-Orti and Robert van de Geijn, "Improving the + performance of reduction to Hessenberg form," ACM Transactions on + Mathematical Software, 32(2):180-194, June 2006. + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + --tau; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + y_dim1 = *ldy; + y_offset = 1 + y_dim1; + y -= y_offset; + + /* Function Body */ + if (*n <= 1) { + return 0; + } + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__ > 1) { + +/* + Update A(K+1:N,I) + + Update I-th column of A - Y * V' +*/ + + i__2 = i__ - 1; + zlacgv_(&i__2, &a[*k + i__ - 1 + a_dim1], lda); + i__2 = *n - *k; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("NO TRANSPOSE", &i__2, &i__3, &z__1, &y[*k + 1 + y_dim1], + ldy, &a[*k + i__ - 1 + a_dim1], lda, &c_b57, &a[*k + 1 + + i__ * a_dim1], &c__1); + i__2 = i__ - 1; + zlacgv_(&i__2, &a[*k + i__ - 1 + a_dim1], lda); + +/* + Apply I - V * T' * V' to this column (call it b) from the + left, using the last column of T as workspace + + Let V = ( V1 ) and b = ( b1 ) (first I-1 rows) + ( V2 ) ( b2 ) + + where V1 is unit lower triangular + + w := V1' * b1 +*/ + + i__2 = i__ - 1; + zcopy_(&i__2, &a[*k + 1 + i__ * a_dim1], &c__1, &t[*nb * t_dim1 + + 1], &c__1); + i__2 = i__ - 1; + ztrmv_("Lower", "Conjugate transpose", "UNIT", &i__2, &a[*k + 1 + + a_dim1], lda, &t[*nb * t_dim1 + 1], &c__1); + +/* w := w + V2'*b2 */ + + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[*k + i__ + + a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b57, + &t[*nb * t_dim1 + 1], &c__1); + +/* w := T'*w */ + + i__2 = i__ - 1; + ztrmv_("Upper", "Conjugate transpose", "NON-UNIT", &i__2, &t[ + t_offset], ldt, &t[*nb * t_dim1 + 1], &c__1); + +/* b2 := b2 - V2*w */ + + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("NO TRANSPOSE", &i__2, &i__3, &z__1, &a[*k + i__ + a_dim1], + lda, &t[*nb * t_dim1 + 1], &c__1, &c_b57, &a[*k + i__ + + i__ * a_dim1], &c__1); + +/* b1 := b1 - V1*w */ + + i__2 = i__ - 1; + ztrmv_("Lower", "NO TRANSPOSE", "UNIT", &i__2, &a[*k + 1 + a_dim1] + , lda, &t[*nb * t_dim1 + 1], &c__1); + i__2 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zaxpy_(&i__2, &z__1, &t[*nb * t_dim1 + 1], &c__1, &a[*k + 1 + i__ + * a_dim1], &c__1); + + i__2 = *k + i__ - 1 + (i__ - 1) * a_dim1; + a[i__2].r = ei.r, a[i__2].i = ei.i; + } + +/* + Generate the elementary reflector H(I) to annihilate + A(K+I+1:N,I) +*/ + + i__2 = *n - *k - i__ + 1; +/* Computing MIN */ + i__3 = *k + i__ + 1; + zlarfg_(&i__2, &a[*k + i__ + i__ * a_dim1], &a[min(i__3,*n) + i__ * + a_dim1], &c__1, &tau[i__]); + i__2 = *k + i__ + i__ * a_dim1; + ei.r = a[i__2].r, ei.i = a[i__2].i; + i__2 = *k + i__ + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Compute Y(K+1:N,I) */ + + i__2 = *n - *k; + i__3 = *n - *k - i__ + 1; + zgemv_("NO TRANSPOSE", &i__2, &i__3, &c_b57, &a[*k + 1 + (i__ + 1) * + a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b56, &y[* + k + 1 + i__ * y_dim1], &c__1); + i__2 = *n - *k - i__ + 1; + i__3 = i__ - 1; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[*k + i__ + + a_dim1], lda, &a[*k + i__ + i__ * a_dim1], &c__1, &c_b56, &t[ + i__ * t_dim1 + 1], &c__1); + i__2 = *n - *k; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("NO TRANSPOSE", &i__2, &i__3, &z__1, &y[*k + 1 + y_dim1], ldy, + &t[i__ * t_dim1 + 1], &c__1, &c_b57, &y[*k + 1 + i__ * y_dim1] + , &c__1); + i__2 = *n - *k; + zscal_(&i__2, &tau[i__], &y[*k + 1 + i__ * y_dim1], &c__1); + +/* Compute T(1:I,I) */ + + i__2 = i__ - 1; + i__3 = i__; + z__1.r = -tau[i__3].r, z__1.i = -tau[i__3].i; + zscal_(&i__2, &z__1, &t[i__ * t_dim1 + 1], &c__1); + i__2 = i__ - 1; + ztrmv_("Upper", "No Transpose", "NON-UNIT", &i__2, &t[t_offset], ldt, + &t[i__ * t_dim1 + 1], &c__1) + ; + i__2 = i__ + i__ * t_dim1; + i__3 = i__; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + +/* L10: */ + } + i__1 = *k + *nb + *nb * a_dim1; + a[i__1].r = ei.r, a[i__1].i = ei.i; + +/* Compute Y(1:K,1:NB) */ + + zlacpy_("ALL", k, nb, &a[(a_dim1 << 1) + 1], lda, &y[y_offset], ldy); + ztrmm_("RIGHT", "Lower", "NO TRANSPOSE", "UNIT", k, nb, &c_b57, &a[*k + 1 + + a_dim1], lda, &y[y_offset], ldy); + if (*n > *k + *nb) { + i__1 = *n - *k - *nb; + zgemm_("NO TRANSPOSE", "NO TRANSPOSE", k, nb, &i__1, &c_b57, &a[(*nb + + 2) * a_dim1 + 1], lda, &a[*k + 1 + *nb + a_dim1], lda, & + c_b57, &y[y_offset], ldy); + } + ztrmm_("RIGHT", "Upper", "NO TRANSPOSE", "NON-UNIT", k, nb, &c_b57, &t[ + t_offset], ldt, &y[y_offset], ldy); + + return 0; + +/* End of ZLAHR2 */ + +} /* zlahr2_ */ + +/* Subroutine */ int zlals0_(integer *icompq, integer *nl, integer *nr, + integer *sqre, integer *nrhs, doublecomplex *b, integer *ldb, + doublecomplex *bx, integer *ldbx, integer *perm, integer *givptr, + integer *givcol, integer *ldgcol, doublereal *givnum, integer *ldgnum, + doublereal *poles, doublereal *difl, doublereal *difr, doublereal * + z__, integer *k, doublereal *c__, doublereal *s, doublereal *rwork, + integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, difr_dim1, difr_offset, givnum_dim1, + givnum_offset, poles_dim1, poles_offset, b_dim1, b_offset, + bx_dim1, bx_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, m, n; + static doublereal dj; + static integer nlp1, jcol; + static doublereal temp; + static integer jrow; + extern doublereal dnrm2_(integer *, doublereal *, integer *); + static doublereal diflj, difrj, dsigj; + extern /* Subroutine */ int dgemv_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, doublereal *, integer *, + doublereal *, doublereal *, integer *), zdrot_(integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublereal *, doublereal *); + extern doublereal dlamc3_(doublereal *, doublereal *); + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), xerbla_(char *, integer *); + static doublereal dsigjp; + extern /* Subroutine */ int zdscal_(integer *, doublereal *, + doublecomplex *, integer *), zlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublecomplex * + , integer *, integer *), zlacpy_(char *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLALS0 applies back the multiplying factors of either the left or the + right singular vector matrix of a diagonal matrix appended by a row + to the right hand side matrix B in solving the least squares problem + using the divide-and-conquer SVD approach. + + For the left singular vector matrix, three types of orthogonal + matrices are involved: + + (1L) Givens rotations: the number of such rotations is GIVPTR; the + pairs of columns/rows they were applied to are stored in GIVCOL; + and the C- and S-values of these rotations are stored in GIVNUM. + + (2L) Permutation. The (NL+1)-st row of B is to be moved to the first + row, and for J=2:N, PERM(J)-th row of B is to be moved to the + J-th row. + + (3L) The left singular vector matrix of the remaining matrix. + + For the right singular vector matrix, four types of orthogonal + matrices are involved: + + (1R) The right singular vector matrix of the remaining matrix. + + (2R) If SQRE = 1, one extra Givens rotation to generate the right + null space. + + (3R) The inverse transformation of (2L). + + (4R) The inverse transformation of (1L). + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether singular vectors are to be computed in + factored form: + = 0: Left singular vector matrix. + = 1: Right singular vector matrix. + + NL (input) INTEGER + The row dimension of the upper block. NL >= 1. + + NR (input) INTEGER + The row dimension of the lower block. NR >= 1. + + SQRE (input) INTEGER + = 0: the lower block is an NR-by-NR square matrix. + = 1: the lower block is an NR-by-(NR+1) rectangular matrix. + + The bidiagonal matrix has row dimension N = NL + NR + 1, + and column dimension M = N + SQRE. + + NRHS (input) INTEGER + The number of columns of B and BX. NRHS must be at least 1. + + B (input/output) COMPLEX*16 array, dimension ( LDB, NRHS ) + On input, B contains the right hand sides of the least + squares problem in rows 1 through M. On output, B contains + the solution X in rows 1 through N. + + LDB (input) INTEGER + The leading dimension of B. LDB must be at least + max(1,MAX( M, N ) ). + + BX (workspace) COMPLEX*16 array, dimension ( LDBX, NRHS ) + + LDBX (input) INTEGER + The leading dimension of BX. + + PERM (input) INTEGER array, dimension ( N ) + The permutations (from deflation and sorting) applied + to the two blocks. + + GIVPTR (input) INTEGER + The number of Givens rotations which took place in this + subproblem. + + GIVCOL (input) INTEGER array, dimension ( LDGCOL, 2 ) + Each pair of numbers indicates a pair of rows/columns + involved in a Givens rotation. + + LDGCOL (input) INTEGER + The leading dimension of GIVCOL, must be at least N. + + GIVNUM (input) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ) + Each number indicates the C or S value used in the + corresponding Givens rotation. + + LDGNUM (input) INTEGER + The leading dimension of arrays DIFR, POLES and + GIVNUM, must be at least K. + + POLES (input) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ) + On entry, POLES(1:K, 1) contains the new singular + values obtained from solving the secular equation, and + POLES(1:K, 2) is an array containing the poles in the secular + equation. + + DIFL (input) DOUBLE PRECISION array, dimension ( K ). + On entry, DIFL(I) is the distance between I-th updated + (undeflated) singular value and the I-th (undeflated) old + singular value. + + DIFR (input) DOUBLE PRECISION array, dimension ( LDGNUM, 2 ). + On entry, DIFR(I, 1) contains the distances between I-th + updated (undeflated) singular value and the I+1-th + (undeflated) old singular value. And DIFR(I, 2) is the + normalizing factor for the I-th right singular vector. + + Z (input) DOUBLE PRECISION array, dimension ( K ) + Contain the components of the deflation-adjusted updating row + vector. + + K (input) INTEGER + Contains the dimension of the non-deflated matrix, + This is the order of the related secular equation. 1 <= K <=N. + + C (input) DOUBLE PRECISION + C contains garbage if SQRE =0 and the C-value of a Givens + rotation related to the right null space if SQRE = 1. + + S (input) DOUBLE PRECISION + S contains garbage if SQRE =0 and the S-value of a Givens + rotation related to the right null space if SQRE = 1. + + RWORK (workspace) DOUBLE PRECISION array, dimension + ( K*(1+NRHS) + 2*NRHS ) + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Ming Gu and Ren-Cang Li, Computer Science Division, University of + California at Berkeley, USA + Osni Marques, LBNL/NERSC, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + bx_dim1 = *ldbx; + bx_offset = 1 + bx_dim1; + bx -= bx_offset; + --perm; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + difr_dim1 = *ldgnum; + difr_offset = 1 + difr_dim1; + difr -= difr_offset; + poles_dim1 = *ldgnum; + poles_offset = 1 + poles_dim1; + poles -= poles_offset; + givnum_dim1 = *ldgnum; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + --difl; + --z__; + --rwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*nl < 1) { + *info = -2; + } else if (*nr < 1) { + *info = -3; + } else if (*sqre < 0 || *sqre > 1) { + *info = -4; + } + + n = *nl + *nr + 1; + + if (*nrhs < 1) { + *info = -5; + } else if (*ldb < n) { + *info = -7; + } else if (*ldbx < n) { + *info = -9; + } else if (*givptr < 0) { + *info = -11; + } else if (*ldgcol < n) { + *info = -13; + } else if (*ldgnum < n) { + *info = -15; + } else if (*k < 1) { + *info = -20; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLALS0", &i__1); + return 0; + } + + m = n + *sqre; + nlp1 = *nl + 1; + + if (*icompq == 0) { + +/* + Apply back orthogonal transformations from the left. + + Step (1L): apply back the Givens rotations performed. +*/ + + i__1 = *givptr; + for (i__ = 1; i__ <= i__1; ++i__) { + zdrot_(nrhs, &b[givcol[i__ + (givcol_dim1 << 1)] + b_dim1], ldb, & + b[givcol[i__ + givcol_dim1] + b_dim1], ldb, &givnum[i__ + + (givnum_dim1 << 1)], &givnum[i__ + givnum_dim1]); +/* L10: */ + } + +/* Step (2L): permute rows of B. */ + + zcopy_(nrhs, &b[nlp1 + b_dim1], ldb, &bx[bx_dim1 + 1], ldbx); + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + zcopy_(nrhs, &b[perm[i__] + b_dim1], ldb, &bx[i__ + bx_dim1], + ldbx); +/* L20: */ + } + +/* + Step (3L): apply the inverse of the left singular vector + matrix to BX. +*/ + + if (*k == 1) { + zcopy_(nrhs, &bx[bx_offset], ldbx, &b[b_offset], ldb); + if (z__[1] < 0.) { + zdscal_(nrhs, &c_b1276, &b[b_offset], ldb); + } + } else { + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + diflj = difl[j]; + dj = poles[j + poles_dim1]; + dsigj = -poles[j + (poles_dim1 << 1)]; + if (j < *k) { + difrj = -difr[j + difr_dim1]; + dsigjp = -poles[j + 1 + (poles_dim1 << 1)]; + } + if (z__[j] == 0. || poles[j + (poles_dim1 << 1)] == 0.) { + rwork[j] = 0.; + } else { + rwork[j] = -poles[j + (poles_dim1 << 1)] * z__[j] / diflj + / (poles[j + (poles_dim1 << 1)] + dj); + } + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + if (z__[i__] == 0. || poles[i__ + (poles_dim1 << 1)] == + 0.) { + rwork[i__] = 0.; + } else { + rwork[i__] = poles[i__ + (poles_dim1 << 1)] * z__[i__] + / (dlamc3_(&poles[i__ + (poles_dim1 << 1)], & + dsigj) - diflj) / (poles[i__ + (poles_dim1 << + 1)] + dj); + } +/* L30: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + if (z__[i__] == 0. || poles[i__ + (poles_dim1 << 1)] == + 0.) { + rwork[i__] = 0.; + } else { + rwork[i__] = poles[i__ + (poles_dim1 << 1)] * z__[i__] + / (dlamc3_(&poles[i__ + (poles_dim1 << 1)], & + dsigjp) + difrj) / (poles[i__ + (poles_dim1 << + 1)] + dj); + } +/* L40: */ + } + rwork[1] = -1.; + temp = dnrm2_(k, &rwork[1], &c__1); + +/* + Since B and BX are complex, the following call to DGEMV + is performed in two steps (real and imaginary parts). + + CALL DGEMV( 'T', K, NRHS, ONE, BX, LDBX, WORK, 1, ZERO, + $ B( J, 1 ), LDB ) +*/ + + i__ = *k + (*nrhs << 1); + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = *k; + for (jrow = 1; jrow <= i__3; ++jrow) { + ++i__; + i__4 = jrow + jcol * bx_dim1; + rwork[i__] = bx[i__4].r; +/* L50: */ + } +/* L60: */ + } + dgemv_("T", k, nrhs, &c_b1034, &rwork[*k + 1 + (*nrhs << 1)], + k, &rwork[1], &c__1, &c_b328, &rwork[*k + 1], &c__1); + i__ = *k + (*nrhs << 1); + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = *k; + for (jrow = 1; jrow <= i__3; ++jrow) { + ++i__; + rwork[i__] = d_imag(&bx[jrow + jcol * bx_dim1]); +/* L70: */ + } +/* L80: */ + } + dgemv_("T", k, nrhs, &c_b1034, &rwork[*k + 1 + (*nrhs << 1)], + k, &rwork[1], &c__1, &c_b328, &rwork[*k + 1 + *nrhs], + &c__1); + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = j + jcol * b_dim1; + i__4 = jcol + *k; + i__5 = jcol + *k + *nrhs; + z__1.r = rwork[i__4], z__1.i = rwork[i__5]; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L90: */ + } + zlascl_("G", &c__0, &c__0, &temp, &c_b1034, &c__1, nrhs, &b[j + + b_dim1], ldb, info); +/* L100: */ + } + } + +/* Move the deflated rows of BX to B also. */ + + if (*k < max(m,n)) { + i__1 = n - *k; + zlacpy_("A", &i__1, nrhs, &bx[*k + 1 + bx_dim1], ldbx, &b[*k + 1 + + b_dim1], ldb); + } + } else { + +/* + Apply back the right orthogonal transformations. + + Step (1R): apply back the new right singular vector matrix + to B. +*/ + + if (*k == 1) { + zcopy_(nrhs, &b[b_offset], ldb, &bx[bx_offset], ldbx); + } else { + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + dsigj = poles[j + (poles_dim1 << 1)]; + if (z__[j] == 0.) { + rwork[j] = 0.; + } else { + rwork[j] = -z__[j] / difl[j] / (dsigj + poles[j + + poles_dim1]) / difr[j + (difr_dim1 << 1)]; + } + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + if (z__[j] == 0.) { + rwork[i__] = 0.; + } else { + d__1 = -poles[i__ + 1 + (poles_dim1 << 1)]; + rwork[i__] = z__[j] / (dlamc3_(&dsigj, &d__1) - difr[ + i__ + difr_dim1]) / (dsigj + poles[i__ + + poles_dim1]) / difr[i__ + (difr_dim1 << 1)]; + } +/* L110: */ + } + i__2 = *k; + for (i__ = j + 1; i__ <= i__2; ++i__) { + if (z__[j] == 0.) { + rwork[i__] = 0.; + } else { + d__1 = -poles[i__ + (poles_dim1 << 1)]; + rwork[i__] = z__[j] / (dlamc3_(&dsigj, &d__1) - difl[ + i__]) / (dsigj + poles[i__ + poles_dim1]) / + difr[i__ + (difr_dim1 << 1)]; + } +/* L120: */ + } + +/* + Since B and BX are complex, the following call to DGEMV + is performed in two steps (real and imaginary parts). + + CALL DGEMV( 'T', K, NRHS, ONE, B, LDB, WORK, 1, ZERO, + $ BX( J, 1 ), LDBX ) +*/ + + i__ = *k + (*nrhs << 1); + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = *k; + for (jrow = 1; jrow <= i__3; ++jrow) { + ++i__; + i__4 = jrow + jcol * b_dim1; + rwork[i__] = b[i__4].r; +/* L130: */ + } +/* L140: */ + } + dgemv_("T", k, nrhs, &c_b1034, &rwork[*k + 1 + (*nrhs << 1)], + k, &rwork[1], &c__1, &c_b328, &rwork[*k + 1], &c__1); + i__ = *k + (*nrhs << 1); + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = *k; + for (jrow = 1; jrow <= i__3; ++jrow) { + ++i__; + rwork[i__] = d_imag(&b[jrow + jcol * b_dim1]); +/* L150: */ + } +/* L160: */ + } + dgemv_("T", k, nrhs, &c_b1034, &rwork[*k + 1 + (*nrhs << 1)], + k, &rwork[1], &c__1, &c_b328, &rwork[*k + 1 + *nrhs], + &c__1); + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = j + jcol * bx_dim1; + i__4 = jcol + *k; + i__5 = jcol + *k + *nrhs; + z__1.r = rwork[i__4], z__1.i = rwork[i__5]; + bx[i__3].r = z__1.r, bx[i__3].i = z__1.i; +/* L170: */ + } +/* L180: */ + } + } + +/* + Step (2R): if SQRE = 1, apply back the rotation that is + related to the right null space of the subproblem. +*/ + + if (*sqre == 1) { + zcopy_(nrhs, &b[m + b_dim1], ldb, &bx[m + bx_dim1], ldbx); + zdrot_(nrhs, &bx[bx_dim1 + 1], ldbx, &bx[m + bx_dim1], ldbx, c__, + s); + } + if (*k < max(m,n)) { + i__1 = n - *k; + zlacpy_("A", &i__1, nrhs, &b[*k + 1 + b_dim1], ldb, &bx[*k + 1 + + bx_dim1], ldbx); + } + +/* Step (3R): permute rows of B. */ + + zcopy_(nrhs, &bx[bx_dim1 + 1], ldbx, &b[nlp1 + b_dim1], ldb); + if (*sqre == 1) { + zcopy_(nrhs, &bx[m + bx_dim1], ldbx, &b[m + b_dim1], ldb); + } + i__1 = n; + for (i__ = 2; i__ <= i__1; ++i__) { + zcopy_(nrhs, &bx[i__ + bx_dim1], ldbx, &b[perm[i__] + b_dim1], + ldb); +/* L190: */ + } + +/* Step (4R): apply back the Givens rotations performed. */ + + for (i__ = *givptr; i__ >= 1; --i__) { + d__1 = -givnum[i__ + givnum_dim1]; + zdrot_(nrhs, &b[givcol[i__ + (givcol_dim1 << 1)] + b_dim1], ldb, & + b[givcol[i__ + givcol_dim1] + b_dim1], ldb, &givnum[i__ + + (givnum_dim1 << 1)], &d__1); +/* L200: */ + } + } + + return 0; + +/* End of ZLALS0 */ + +} /* zlals0_ */ + +/* Subroutine */ int zlalsa_(integer *icompq, integer *smlsiz, integer *n, + integer *nrhs, doublecomplex *b, integer *ldb, doublecomplex *bx, + integer *ldbx, doublereal *u, integer *ldu, doublereal *vt, integer * + k, doublereal *difl, doublereal *difr, doublereal *z__, doublereal * + poles, integer *givptr, integer *givcol, integer *ldgcol, integer * + perm, doublereal *givnum, doublereal *c__, doublereal *s, doublereal * + rwork, integer *iwork, integer *info) +{ + /* System generated locals */ + integer givcol_dim1, givcol_offset, perm_dim1, perm_offset, difl_dim1, + difl_offset, difr_dim1, difr_offset, givnum_dim1, givnum_offset, + poles_dim1, poles_offset, u_dim1, u_offset, vt_dim1, vt_offset, + z_dim1, z_offset, b_dim1, b_offset, bx_dim1, bx_offset, i__1, + i__2, i__3, i__4, i__5, i__6; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, i1, ic, lf, nd, ll, nl, nr, im1, nlf, nrf, lvl, + ndb1, nlp1, lvl2, nrp1, jcol, nlvl, sqre, jrow, jimag; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer jreal, inode, ndiml, ndimr; + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), zlals0_(integer *, integer *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, integer *, integer *, integer *, + integer *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, doublereal *, + doublereal *, integer *), dlasdt_(integer *, integer *, integer * + , integer *, integer *, integer *, integer *), xerbla_(char *, + integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLALSA is an itermediate step in solving the least squares problem + by computing the SVD of the coefficient matrix in compact form (The + singular vectors are computed as products of simple orthorgonal + matrices.). + + If ICOMPQ = 0, ZLALSA applies the inverse of the left singular vector + matrix of an upper bidiagonal matrix to the right hand side; and if + ICOMPQ = 1, ZLALSA applies the right singular vector matrix to the + right hand side. The singular vector matrices were generated in + compact form by ZLALSA. + + Arguments + ========= + + ICOMPQ (input) INTEGER + Specifies whether the left or the right singular vector + matrix is involved. + = 0: Left singular vector matrix + = 1: Right singular vector matrix + + SMLSIZ (input) INTEGER + The maximum size of the subproblems at the bottom of the + computation tree. + + N (input) INTEGER + The row and column dimensions of the upper bidiagonal matrix. + + NRHS (input) INTEGER + The number of columns of B and BX. NRHS must be at least 1. + + B (input/output) COMPLEX*16 array, dimension ( LDB, NRHS ) + On input, B contains the right hand sides of the least + squares problem in rows 1 through M. + On output, B contains the solution X in rows 1 through N. + + LDB (input) INTEGER + The leading dimension of B in the calling subprogram. + LDB must be at least max(1,MAX( M, N ) ). + + BX (output) COMPLEX*16 array, dimension ( LDBX, NRHS ) + On exit, the result of applying the left or right singular + vector matrix to B. + + LDBX (input) INTEGER + The leading dimension of BX. + + U (input) DOUBLE PRECISION array, dimension ( LDU, SMLSIZ ). + On entry, U contains the left singular vector matrices of all + subproblems at the bottom level. + + LDU (input) INTEGER, LDU = > N. + The leading dimension of arrays U, VT, DIFL, DIFR, + POLES, GIVNUM, and Z. + + VT (input) DOUBLE PRECISION array, dimension ( LDU, SMLSIZ+1 ). + On entry, VT' contains the right singular vector matrices of + all subproblems at the bottom level. + + K (input) INTEGER array, dimension ( N ). + + DIFL (input) DOUBLE PRECISION array, dimension ( LDU, NLVL ). + where NLVL = INT(log_2 (N/(SMLSIZ+1))) + 1. + + DIFR (input) DOUBLE PRECISION array, dimension ( LDU, 2 * NLVL ). + On entry, DIFL(*, I) and DIFR(*, 2 * I -1) record + distances between singular values on the I-th level and + singular values on the (I -1)-th level, and DIFR(*, 2 * I) + record the normalizing factors of the right singular vectors + matrices of subproblems on I-th level. + + Z (input) DOUBLE PRECISION array, dimension ( LDU, NLVL ). + On entry, Z(1, I) contains the components of the deflation- + adjusted updating row vector for subproblems on the I-th + level. + + POLES (input) DOUBLE PRECISION array, dimension ( LDU, 2 * NLVL ). + On entry, POLES(*, 2 * I -1: 2 * I) contains the new and old + singular values involved in the secular equations on the I-th + level. + + GIVPTR (input) INTEGER array, dimension ( N ). + On entry, GIVPTR( I ) records the number of Givens + rotations performed on the I-th problem on the computation + tree. + + GIVCOL (input) INTEGER array, dimension ( LDGCOL, 2 * NLVL ). + On entry, for each I, GIVCOL(*, 2 * I - 1: 2 * I) records the + locations of Givens rotations performed on the I-th level on + the computation tree. + + LDGCOL (input) INTEGER, LDGCOL = > N. + The leading dimension of arrays GIVCOL and PERM. + + PERM (input) INTEGER array, dimension ( LDGCOL, NLVL ). + On entry, PERM(*, I) records permutations done on the I-th + level of the computation tree. + + GIVNUM (input) DOUBLE PRECISION array, dimension ( LDU, 2 * NLVL ). + On entry, GIVNUM(*, 2 *I -1 : 2 * I) records the C- and S- + values of Givens rotations performed on the I-th level on the + computation tree. + + C (input) DOUBLE PRECISION array, dimension ( N ). + On entry, if the I-th subproblem is not square, + C( I ) contains the C-value of a Givens rotation related to + the right null space of the I-th subproblem. + + S (input) DOUBLE PRECISION array, dimension ( N ). + On entry, if the I-th subproblem is not square, + S( I ) contains the S-value of a Givens rotation related to + the right null space of the I-th subproblem. + + RWORK (workspace) DOUBLE PRECISION array, dimension at least + MAX( (SMLSZ+1)*NRHS*3, N*(1+NRHS) + 2*NRHS ). + + IWORK (workspace) INTEGER array. + The dimension must be at least 3 * N + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + + Further Details + =============== + + Based on contributions by + Ming Gu and Ren-Cang Li, Computer Science Division, University of + California at Berkeley, USA + Osni Marques, LBNL/NERSC, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + bx_dim1 = *ldbx; + bx_offset = 1 + bx_dim1; + bx -= bx_offset; + givnum_dim1 = *ldu; + givnum_offset = 1 + givnum_dim1; + givnum -= givnum_offset; + poles_dim1 = *ldu; + poles_offset = 1 + poles_dim1; + poles -= poles_offset; + z_dim1 = *ldu; + z_offset = 1 + z_dim1; + z__ -= z_offset; + difr_dim1 = *ldu; + difr_offset = 1 + difr_dim1; + difr -= difr_offset; + difl_dim1 = *ldu; + difl_offset = 1 + difl_dim1; + difl -= difl_offset; + vt_dim1 = *ldu; + vt_offset = 1 + vt_dim1; + vt -= vt_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + --k; + --givptr; + perm_dim1 = *ldgcol; + perm_offset = 1 + perm_dim1; + perm -= perm_offset; + givcol_dim1 = *ldgcol; + givcol_offset = 1 + givcol_dim1; + givcol -= givcol_offset; + --c__; + --s; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + + if (*icompq < 0 || *icompq > 1) { + *info = -1; + } else if (*smlsiz < 3) { + *info = -2; + } else if (*n < *smlsiz) { + *info = -3; + } else if (*nrhs < 1) { + *info = -4; + } else if (*ldb < *n) { + *info = -6; + } else if (*ldbx < *n) { + *info = -8; + } else if (*ldu < *n) { + *info = -10; + } else if (*ldgcol < *n) { + *info = -19; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLALSA", &i__1); + return 0; + } + +/* Book-keeping and setting up the computation tree. */ + + inode = 1; + ndiml = inode + *n; + ndimr = ndiml + *n; + + dlasdt_(n, &nlvl, &nd, &iwork[inode], &iwork[ndiml], &iwork[ndimr], + smlsiz); + +/* + The following code applies back the left singular vector factors. + For applying back the right singular vector factors, go to 170. +*/ + + if (*icompq == 1) { + goto L170; + } + +/* + The nodes on the bottom level of the tree were solved + by DLASDQ. The corresponding left and right singular vector + matrices are in explicit form. First apply back the left + singular vector matrices. +*/ + + ndb1 = (nd + 1) / 2; + i__1 = nd; + for (i__ = ndb1; i__ <= i__1; ++i__) { + +/* + IC : center row of each node + NL : number of rows of left subproblem + NR : number of rows of right subproblem + NLF: starting row of the left subproblem + NRF: starting row of the right subproblem +*/ + + i1 = i__ - 1; + ic = iwork[inode + i1]; + nl = iwork[ndiml + i1]; + nr = iwork[ndimr + i1]; + nlf = ic - nl; + nrf = ic + 1; + +/* + Since B and BX are complex, the following call to DGEMM + is performed in two steps (real and imaginary parts). + + CALL DGEMM( 'T', 'N', NL, NRHS, NL, ONE, U( NLF, 1 ), LDU, + $ B( NLF, 1 ), LDB, ZERO, BX( NLF, 1 ), LDBX ) +*/ + + j = nl * *nrhs << 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nlf + nl - 1; + for (jrow = nlf; jrow <= i__3; ++jrow) { + ++j; + i__4 = jrow + jcol * b_dim1; + rwork[j] = b[i__4].r; +/* L10: */ + } +/* L20: */ + } + dgemm_("T", "N", &nl, nrhs, &nl, &c_b1034, &u[nlf + u_dim1], ldu, & + rwork[(nl * *nrhs << 1) + 1], &nl, &c_b328, &rwork[1], &nl); + j = nl * *nrhs << 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nlf + nl - 1; + for (jrow = nlf; jrow <= i__3; ++jrow) { + ++j; + rwork[j] = d_imag(&b[jrow + jcol * b_dim1]); +/* L30: */ + } +/* L40: */ + } + dgemm_("T", "N", &nl, nrhs, &nl, &c_b1034, &u[nlf + u_dim1], ldu, & + rwork[(nl * *nrhs << 1) + 1], &nl, &c_b328, &rwork[nl * *nrhs + + 1], &nl); + jreal = 0; + jimag = nl * *nrhs; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nlf + nl - 1; + for (jrow = nlf; jrow <= i__3; ++jrow) { + ++jreal; + ++jimag; + i__4 = jrow + jcol * bx_dim1; + i__5 = jreal; + i__6 = jimag; + z__1.r = rwork[i__5], z__1.i = rwork[i__6]; + bx[i__4].r = z__1.r, bx[i__4].i = z__1.i; +/* L50: */ + } +/* L60: */ + } + +/* + Since B and BX are complex, the following call to DGEMM + is performed in two steps (real and imaginary parts). + + CALL DGEMM( 'T', 'N', NR, NRHS, NR, ONE, U( NRF, 1 ), LDU, + $ B( NRF, 1 ), LDB, ZERO, BX( NRF, 1 ), LDBX ) +*/ + + j = nr * *nrhs << 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nrf + nr - 1; + for (jrow = nrf; jrow <= i__3; ++jrow) { + ++j; + i__4 = jrow + jcol * b_dim1; + rwork[j] = b[i__4].r; +/* L70: */ + } +/* L80: */ + } + dgemm_("T", "N", &nr, nrhs, &nr, &c_b1034, &u[nrf + u_dim1], ldu, & + rwork[(nr * *nrhs << 1) + 1], &nr, &c_b328, &rwork[1], &nr); + j = nr * *nrhs << 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nrf + nr - 1; + for (jrow = nrf; jrow <= i__3; ++jrow) { + ++j; + rwork[j] = d_imag(&b[jrow + jcol * b_dim1]); +/* L90: */ + } +/* L100: */ + } + dgemm_("T", "N", &nr, nrhs, &nr, &c_b1034, &u[nrf + u_dim1], ldu, & + rwork[(nr * *nrhs << 1) + 1], &nr, &c_b328, &rwork[nr * *nrhs + + 1], &nr); + jreal = 0; + jimag = nr * *nrhs; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nrf + nr - 1; + for (jrow = nrf; jrow <= i__3; ++jrow) { + ++jreal; + ++jimag; + i__4 = jrow + jcol * bx_dim1; + i__5 = jreal; + i__6 = jimag; + z__1.r = rwork[i__5], z__1.i = rwork[i__6]; + bx[i__4].r = z__1.r, bx[i__4].i = z__1.i; +/* L110: */ + } +/* L120: */ + } + +/* L130: */ + } + +/* + Next copy the rows of B that correspond to unchanged rows + in the bidiagonal matrix to BX. +*/ + + i__1 = nd; + for (i__ = 1; i__ <= i__1; ++i__) { + ic = iwork[inode + i__ - 1]; + zcopy_(nrhs, &b[ic + b_dim1], ldb, &bx[ic + bx_dim1], ldbx); +/* L140: */ + } + +/* + Finally go through the left singular vector matrices of all + the other subproblems bottom-up on the tree. +*/ + + j = pow_ii(&c__2, &nlvl); + sqre = 0; + + for (lvl = nlvl; lvl >= 1; --lvl) { + lvl2 = (lvl << 1) - 1; + +/* + find the first node LF and last node LL on + the current level LVL +*/ + + if (lvl == 1) { + lf = 1; + ll = 1; + } else { + i__1 = lvl - 1; + lf = pow_ii(&c__2, &i__1); + ll = (lf << 1) - 1; + } + i__1 = ll; + for (i__ = lf; i__ <= i__1; ++i__) { + im1 = i__ - 1; + ic = iwork[inode + im1]; + nl = iwork[ndiml + im1]; + nr = iwork[ndimr + im1]; + nlf = ic - nl; + nrf = ic + 1; + --j; + zlals0_(icompq, &nl, &nr, &sqre, nrhs, &bx[nlf + bx_dim1], ldbx, & + b[nlf + b_dim1], ldb, &perm[nlf + lvl * perm_dim1], & + givptr[j], &givcol[nlf + lvl2 * givcol_dim1], ldgcol, & + givnum[nlf + lvl2 * givnum_dim1], ldu, &poles[nlf + lvl2 * + poles_dim1], &difl[nlf + lvl * difl_dim1], &difr[nlf + + lvl2 * difr_dim1], &z__[nlf + lvl * z_dim1], &k[j], &c__[ + j], &s[j], &rwork[1], info); +/* L150: */ + } +/* L160: */ + } + goto L330; + +/* ICOMPQ = 1: applying back the right singular vector factors. */ + +L170: + +/* + First now go through the right singular vector matrices of all + the tree nodes top-down. +*/ + + j = 0; + i__1 = nlvl; + for (lvl = 1; lvl <= i__1; ++lvl) { + lvl2 = (lvl << 1) - 1; + +/* + Find the first node LF and last node LL on + the current level LVL. +*/ + + if (lvl == 1) { + lf = 1; + ll = 1; + } else { + i__2 = lvl - 1; + lf = pow_ii(&c__2, &i__2); + ll = (lf << 1) - 1; + } + i__2 = lf; + for (i__ = ll; i__ >= i__2; --i__) { + im1 = i__ - 1; + ic = iwork[inode + im1]; + nl = iwork[ndiml + im1]; + nr = iwork[ndimr + im1]; + nlf = ic - nl; + nrf = ic + 1; + if (i__ == ll) { + sqre = 0; + } else { + sqre = 1; + } + ++j; + zlals0_(icompq, &nl, &nr, &sqre, nrhs, &b[nlf + b_dim1], ldb, &bx[ + nlf + bx_dim1], ldbx, &perm[nlf + lvl * perm_dim1], & + givptr[j], &givcol[nlf + lvl2 * givcol_dim1], ldgcol, & + givnum[nlf + lvl2 * givnum_dim1], ldu, &poles[nlf + lvl2 * + poles_dim1], &difl[nlf + lvl * difl_dim1], &difr[nlf + + lvl2 * difr_dim1], &z__[nlf + lvl * z_dim1], &k[j], &c__[ + j], &s[j], &rwork[1], info); +/* L180: */ + } +/* L190: */ + } + +/* + The nodes on the bottom level of the tree were solved + by DLASDQ. The corresponding right singular vector + matrices are in explicit form. Apply them back. +*/ + + ndb1 = (nd + 1) / 2; + i__1 = nd; + for (i__ = ndb1; i__ <= i__1; ++i__) { + i1 = i__ - 1; + ic = iwork[inode + i1]; + nl = iwork[ndiml + i1]; + nr = iwork[ndimr + i1]; + nlp1 = nl + 1; + if (i__ == nd) { + nrp1 = nr; + } else { + nrp1 = nr + 1; + } + nlf = ic - nl; + nrf = ic + 1; + +/* + Since B and BX are complex, the following call to DGEMM is + performed in two steps (real and imaginary parts). + + CALL DGEMM( 'T', 'N', NLP1, NRHS, NLP1, ONE, VT( NLF, 1 ), LDU, + $ B( NLF, 1 ), LDB, ZERO, BX( NLF, 1 ), LDBX ) +*/ + + j = nlp1 * *nrhs << 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nlf + nlp1 - 1; + for (jrow = nlf; jrow <= i__3; ++jrow) { + ++j; + i__4 = jrow + jcol * b_dim1; + rwork[j] = b[i__4].r; +/* L200: */ + } +/* L210: */ + } + dgemm_("T", "N", &nlp1, nrhs, &nlp1, &c_b1034, &vt[nlf + vt_dim1], + ldu, &rwork[(nlp1 * *nrhs << 1) + 1], &nlp1, &c_b328, &rwork[ + 1], &nlp1); + j = nlp1 * *nrhs << 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nlf + nlp1 - 1; + for (jrow = nlf; jrow <= i__3; ++jrow) { + ++j; + rwork[j] = d_imag(&b[jrow + jcol * b_dim1]); +/* L220: */ + } +/* L230: */ + } + dgemm_("T", "N", &nlp1, nrhs, &nlp1, &c_b1034, &vt[nlf + vt_dim1], + ldu, &rwork[(nlp1 * *nrhs << 1) + 1], &nlp1, &c_b328, &rwork[ + nlp1 * *nrhs + 1], &nlp1); + jreal = 0; + jimag = nlp1 * *nrhs; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nlf + nlp1 - 1; + for (jrow = nlf; jrow <= i__3; ++jrow) { + ++jreal; + ++jimag; + i__4 = jrow + jcol * bx_dim1; + i__5 = jreal; + i__6 = jimag; + z__1.r = rwork[i__5], z__1.i = rwork[i__6]; + bx[i__4].r = z__1.r, bx[i__4].i = z__1.i; +/* L240: */ + } +/* L250: */ + } + +/* + Since B and BX are complex, the following call to DGEMM is + performed in two steps (real and imaginary parts). + + CALL DGEMM( 'T', 'N', NRP1, NRHS, NRP1, ONE, VT( NRF, 1 ), LDU, + $ B( NRF, 1 ), LDB, ZERO, BX( NRF, 1 ), LDBX ) +*/ + + j = nrp1 * *nrhs << 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nrf + nrp1 - 1; + for (jrow = nrf; jrow <= i__3; ++jrow) { + ++j; + i__4 = jrow + jcol * b_dim1; + rwork[j] = b[i__4].r; +/* L260: */ + } +/* L270: */ + } + dgemm_("T", "N", &nrp1, nrhs, &nrp1, &c_b1034, &vt[nrf + vt_dim1], + ldu, &rwork[(nrp1 * *nrhs << 1) + 1], &nrp1, &c_b328, &rwork[ + 1], &nrp1); + j = nrp1 * *nrhs << 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nrf + nrp1 - 1; + for (jrow = nrf; jrow <= i__3; ++jrow) { + ++j; + rwork[j] = d_imag(&b[jrow + jcol * b_dim1]); +/* L280: */ + } +/* L290: */ + } + dgemm_("T", "N", &nrp1, nrhs, &nrp1, &c_b1034, &vt[nrf + vt_dim1], + ldu, &rwork[(nrp1 * *nrhs << 1) + 1], &nrp1, &c_b328, &rwork[ + nrp1 * *nrhs + 1], &nrp1); + jreal = 0; + jimag = nrp1 * *nrhs; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = nrf + nrp1 - 1; + for (jrow = nrf; jrow <= i__3; ++jrow) { + ++jreal; + ++jimag; + i__4 = jrow + jcol * bx_dim1; + i__5 = jreal; + i__6 = jimag; + z__1.r = rwork[i__5], z__1.i = rwork[i__6]; + bx[i__4].r = z__1.r, bx[i__4].i = z__1.i; +/* L300: */ + } +/* L310: */ + } + +/* L320: */ + } + +L330: + + return 0; + +/* End of ZLALSA */ + +} /* zlalsa_ */ + +/* Subroutine */ int zlalsd_(char *uplo, integer *smlsiz, integer *n, integer + *nrhs, doublereal *d__, doublereal *e, doublecomplex *b, integer *ldb, + doublereal *rcond, integer *rank, doublecomplex *work, doublereal * + rwork, integer *iwork, integer *info) +{ + /* System generated locals */ + integer b_dim1, b_offset, i__1, i__2, i__3, i__4, i__5, i__6; + doublereal d__1; + doublecomplex z__1; + + /* Local variables */ + static integer c__, i__, j, k; + static doublereal r__; + static integer s, u, z__; + static doublereal cs; + static integer bx; + static doublereal sn; + static integer st, vt, nm1, st1; + static doublereal eps; + static integer iwk; + static doublereal tol; + static integer difl, difr; + static doublereal rcnd; + static integer jcol, irwb, perm, nsub, nlvl, sqre, bxst, jrow, irwu, + jimag; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + static integer jreal, irwib, poles, sizei, irwrb, nsize; + extern /* Subroutine */ int zdrot_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublereal *, doublereal *), zcopy_( + integer *, doublecomplex *, integer *, doublecomplex *, integer *) + ; + static integer irwvt, icmpq1, icmpq2; + + extern /* Subroutine */ int dlasda_(integer *, integer *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *, + doublereal *, integer *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *, integer *, integer *, integer *, + doublereal *, doublereal *, doublereal *, doublereal *, integer *, + integer *), dlascl_(char *, integer *, integer *, doublereal *, + doublereal *, integer *, integer *, doublereal *, integer *, + integer *); + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int dlasdq_(char *, integer *, integer *, integer + *, integer *, integer *, doublereal *, doublereal *, doublereal *, + integer *, doublereal *, integer *, doublereal *, integer *, + doublereal *, integer *), dlaset_(char *, integer *, + integer *, doublereal *, doublereal *, doublereal *, integer *), dlartg_(doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *), xerbla_(char *, integer *); + static integer givcol; + extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); + extern /* Subroutine */ int zlalsa_(integer *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, integer *, + doublereal *, integer *, doublereal *, integer *, doublereal *, + doublereal *, doublereal *, doublereal *, integer *, integer *, + integer *, integer *, doublereal *, doublereal *, doublereal *, + doublereal *, integer *, integer *), zlascl_(char *, integer *, + integer *, doublereal *, doublereal *, integer *, integer *, + doublecomplex *, integer *, integer *), dlasrt_(char *, + integer *, doublereal *, integer *), zlacpy_(char *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + integer *), zlaset_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, doublecomplex *, integer *); + static doublereal orgnrm; + static integer givnum, givptr, nrwork, irwwrk, smlszp; + + +/* + -- LAPACK routine (version 3.2.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + June 2010 + + + Purpose + ======= + + ZLALSD uses the singular value decomposition of A to solve the least + squares problem of finding X to minimize the Euclidean norm of each + column of A*X-B, where A is N-by-N upper bidiagonal, and X and B + are N-by-NRHS. The solution X overwrites B. + + The singular values of A smaller than RCOND times the largest + singular value are treated as zero in solving the least squares + problem; in this case a minimum norm solution is returned. + The actual singular values are returned in D in ascending order. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray XMP, Cray YMP, Cray C 90, or Cray 2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': D and E define an upper bidiagonal matrix. + = 'L': D and E define a lower bidiagonal matrix. + + SMLSIZ (input) INTEGER + The maximum size of the subproblems at the bottom of the + computation tree. + + N (input) INTEGER + The dimension of the bidiagonal matrix. N >= 0. + + NRHS (input) INTEGER + The number of columns of B. NRHS must be at least 1. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry D contains the main diagonal of the bidiagonal + matrix. On exit, if INFO = 0, D contains its singular values. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + Contains the super-diagonal entries of the bidiagonal matrix. + On exit, E has been destroyed. + + B (input/output) COMPLEX*16 array, dimension (LDB,NRHS) + On input, B contains the right hand sides of the least + squares problem. On output, B contains the solution X. + + LDB (input) INTEGER + The leading dimension of B in the calling subprogram. + LDB must be at least max(1,N). + + RCOND (input) DOUBLE PRECISION + The singular values of A less than or equal to RCOND times + the largest singular value are treated as zero in solving + the least squares problem. If RCOND is negative, + machine precision is used instead. + For example, if diag(S)*X=B were the least squares problem, + where diag(S) is a diagonal matrix of singular values, the + solution would be X(i) = B(i) / S(i) if S(i) is greater than + RCOND*max(S), and X(i) = 0 if S(i) is less than or equal to + RCOND*max(S). + + RANK (output) INTEGER + The number of singular values of A greater than RCOND times + the largest singular value. + + WORK (workspace) COMPLEX*16 array, dimension at least + (N * NRHS). + + RWORK (workspace) DOUBLE PRECISION array, dimension at least + (9*N + 2*N*SMLSIZ + 8*N*NLVL + 3*SMLSIZ*NRHS + + MAX( (SMLSIZ+1)**2, N*(1+NRHS) + 2*NRHS ), + where + NLVL = MAX( 0, INT( LOG_2( MIN( M,N )/(SMLSIZ+1) ) ) + 1 ) + + IWORK (workspace) INTEGER array, dimension at least + (3*N*NLVL + 11*N). + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute a singular value while + working on the submatrix lying in rows and columns + INFO/(N+1) through MOD(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Ming Gu and Ren-Cang Li, Computer Science Division, University of + California at Berkeley, USA + Osni Marques, LBNL/NERSC, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + + if (*n < 0) { + *info = -3; + } else if (*nrhs < 1) { + *info = -4; + } else if (*ldb < 1 || *ldb < *n) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLALSD", &i__1); + return 0; + } + + eps = EPSILON; + +/* Set up the tolerance. */ + + if (*rcond <= 0. || *rcond >= 1.) { + rcnd = eps; + } else { + rcnd = *rcond; + } + + *rank = 0; + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } else if (*n == 1) { + if (d__[1] == 0.) { + zlaset_("A", &c__1, nrhs, &c_b56, &c_b56, &b[b_offset], ldb); + } else { + *rank = 1; + zlascl_("G", &c__0, &c__0, &d__[1], &c_b1034, &c__1, nrhs, &b[ + b_offset], ldb, info); + d__[1] = abs(d__[1]); + } + return 0; + } + +/* Rotate the matrix if it is lower bidiagonal. */ + + if (*(unsigned char *)uplo == 'L') { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + dlartg_(&d__[i__], &e[i__], &cs, &sn, &r__); + d__[i__] = r__; + e[i__] = sn * d__[i__ + 1]; + d__[i__ + 1] = cs * d__[i__ + 1]; + if (*nrhs == 1) { + zdrot_(&c__1, &b[i__ + b_dim1], &c__1, &b[i__ + 1 + b_dim1], & + c__1, &cs, &sn); + } else { + rwork[(i__ << 1) - 1] = cs; + rwork[i__ * 2] = sn; + } +/* L10: */ + } + if (*nrhs > 1) { + i__1 = *nrhs; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = *n - 1; + for (j = 1; j <= i__2; ++j) { + cs = rwork[(j << 1) - 1]; + sn = rwork[j * 2]; + zdrot_(&c__1, &b[j + i__ * b_dim1], &c__1, &b[j + 1 + i__ + * b_dim1], &c__1, &cs, &sn); +/* L20: */ + } +/* L30: */ + } + } + } + +/* Scale. */ + + nm1 = *n - 1; + orgnrm = dlanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.) { + zlaset_("A", n, nrhs, &c_b56, &c_b56, &b[b_offset], ldb); + return 0; + } + + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b1034, n, &c__1, &d__[1], n, info); + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b1034, &nm1, &c__1, &e[1], &nm1, + info); + +/* + If N is smaller than the minimum divide size SMLSIZ, then solve + the problem with another solver. +*/ + + if (*n <= *smlsiz) { + irwu = 1; + irwvt = irwu + *n * *n; + irwwrk = irwvt + *n * *n; + irwrb = irwwrk; + irwib = irwrb + *n * *nrhs; + irwb = irwib + *n * *nrhs; + dlaset_("A", n, n, &c_b328, &c_b1034, &rwork[irwu], n); + dlaset_("A", n, n, &c_b328, &c_b1034, &rwork[irwvt], n); + dlasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &rwork[irwvt], n, + &rwork[irwu], n, &rwork[irwwrk], &c__1, &rwork[irwwrk], info); + if (*info != 0) { + return 0; + } + +/* + In the real version, B is passed to DLASDQ and multiplied + internally by Q'. Here B is complex and that product is + computed below in two steps (real and imaginary parts). +*/ + + j = irwb - 1; + i__1 = *nrhs; + for (jcol = 1; jcol <= i__1; ++jcol) { + i__2 = *n; + for (jrow = 1; jrow <= i__2; ++jrow) { + ++j; + i__3 = jrow + jcol * b_dim1; + rwork[j] = b[i__3].r; +/* L40: */ + } +/* L50: */ + } + dgemm_("T", "N", n, nrhs, n, &c_b1034, &rwork[irwu], n, &rwork[irwb], + n, &c_b328, &rwork[irwrb], n); + j = irwb - 1; + i__1 = *nrhs; + for (jcol = 1; jcol <= i__1; ++jcol) { + i__2 = *n; + for (jrow = 1; jrow <= i__2; ++jrow) { + ++j; + rwork[j] = d_imag(&b[jrow + jcol * b_dim1]); +/* L60: */ + } +/* L70: */ + } + dgemm_("T", "N", n, nrhs, n, &c_b1034, &rwork[irwu], n, &rwork[irwb], + n, &c_b328, &rwork[irwib], n); + jreal = irwrb - 1; + jimag = irwib - 1; + i__1 = *nrhs; + for (jcol = 1; jcol <= i__1; ++jcol) { + i__2 = *n; + for (jrow = 1; jrow <= i__2; ++jrow) { + ++jreal; + ++jimag; + i__3 = jrow + jcol * b_dim1; + i__4 = jreal; + i__5 = jimag; + z__1.r = rwork[i__4], z__1.i = rwork[i__5]; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L80: */ + } +/* L90: */ + } + + tol = rcnd * (d__1 = d__[idamax_(n, &d__[1], &c__1)], abs(d__1)); + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if (d__[i__] <= tol) { + zlaset_("A", &c__1, nrhs, &c_b56, &c_b56, &b[i__ + b_dim1], + ldb); + } else { + zlascl_("G", &c__0, &c__0, &d__[i__], &c_b1034, &c__1, nrhs, & + b[i__ + b_dim1], ldb, info); + ++(*rank); + } +/* L100: */ + } + +/* + Since B is complex, the following call to DGEMM is performed + in two steps (real and imaginary parts). That is for V * B + (in the real version of the code V' is stored in WORK). + + CALL DGEMM( 'T', 'N', N, NRHS, N, ONE, WORK, N, B, LDB, ZERO, + $ WORK( NWORK ), N ) +*/ + + j = irwb - 1; + i__1 = *nrhs; + for (jcol = 1; jcol <= i__1; ++jcol) { + i__2 = *n; + for (jrow = 1; jrow <= i__2; ++jrow) { + ++j; + i__3 = jrow + jcol * b_dim1; + rwork[j] = b[i__3].r; +/* L110: */ + } +/* L120: */ + } + dgemm_("T", "N", n, nrhs, n, &c_b1034, &rwork[irwvt], n, &rwork[irwb], + n, &c_b328, &rwork[irwrb], n); + j = irwb - 1; + i__1 = *nrhs; + for (jcol = 1; jcol <= i__1; ++jcol) { + i__2 = *n; + for (jrow = 1; jrow <= i__2; ++jrow) { + ++j; + rwork[j] = d_imag(&b[jrow + jcol * b_dim1]); +/* L130: */ + } +/* L140: */ + } + dgemm_("T", "N", n, nrhs, n, &c_b1034, &rwork[irwvt], n, &rwork[irwb], + n, &c_b328, &rwork[irwib], n); + jreal = irwrb - 1; + jimag = irwib - 1; + i__1 = *nrhs; + for (jcol = 1; jcol <= i__1; ++jcol) { + i__2 = *n; + for (jrow = 1; jrow <= i__2; ++jrow) { + ++jreal; + ++jimag; + i__3 = jrow + jcol * b_dim1; + i__4 = jreal; + i__5 = jimag; + z__1.r = rwork[i__4], z__1.i = rwork[i__5]; + b[i__3].r = z__1.r, b[i__3].i = z__1.i; +/* L150: */ + } +/* L160: */ + } + +/* Unscale. */ + + dlascl_("G", &c__0, &c__0, &c_b1034, &orgnrm, n, &c__1, &d__[1], n, + info); + dlasrt_("D", n, &d__[1], info); + zlascl_("G", &c__0, &c__0, &orgnrm, &c_b1034, n, nrhs, &b[b_offset], + ldb, info); + + return 0; + } + +/* Book-keeping and setting up some constants. */ + + nlvl = (integer) (log((doublereal) (*n) / (doublereal) (*smlsiz + 1)) / + log(2.)) + 1; + + smlszp = *smlsiz + 1; + + u = 1; + vt = *smlsiz * *n + 1; + difl = vt + smlszp * *n; + difr = difl + nlvl * *n; + z__ = difr + (nlvl * *n << 1); + c__ = z__ + nlvl * *n; + s = c__ + *n; + poles = s + *n; + givnum = poles + (nlvl << 1) * *n; + nrwork = givnum + (nlvl << 1) * *n; + bx = 1; + + irwrb = nrwork; + irwib = irwrb + *smlsiz * *nrhs; + irwb = irwib + *smlsiz * *nrhs; + + sizei = *n + 1; + k = sizei + *n; + givptr = k + *n; + perm = givptr + *n; + givcol = perm + nlvl * *n; + iwk = givcol + (nlvl * *n << 1); + + st = 1; + sqre = 0; + icmpq1 = 1; + icmpq2 = 0; + nsub = 0; + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((d__1 = d__[i__], abs(d__1)) < eps) { + d__[i__] = d_sign(&eps, &d__[i__]); + } +/* L170: */ + } + + i__1 = nm1; + for (i__ = 1; i__ <= i__1; ++i__) { + if ((d__1 = e[i__], abs(d__1)) < eps || i__ == nm1) { + ++nsub; + iwork[nsub] = st; + +/* + Subproblem found. First determine its size and then + apply divide and conquer on it. +*/ + + if (i__ < nm1) { + +/* A subproblem with E(I) small for I < NM1. */ + + nsize = i__ - st + 1; + iwork[sizei + nsub - 1] = nsize; + } else if ((d__1 = e[i__], abs(d__1)) >= eps) { + +/* A subproblem with E(NM1) not too small but I = NM1. */ + + nsize = *n - st + 1; + iwork[sizei + nsub - 1] = nsize; + } else { + +/* + A subproblem with E(NM1) small. This implies an + 1-by-1 subproblem at D(N), which is not solved + explicitly. +*/ + + nsize = i__ - st + 1; + iwork[sizei + nsub - 1] = nsize; + ++nsub; + iwork[nsub] = *n; + iwork[sizei + nsub - 1] = 1; + zcopy_(nrhs, &b[*n + b_dim1], ldb, &work[bx + nm1], n); + } + st1 = st - 1; + if (nsize == 1) { + +/* + This is a 1-by-1 subproblem and is not solved + explicitly. +*/ + + zcopy_(nrhs, &b[st + b_dim1], ldb, &work[bx + st1], n); + } else if (nsize <= *smlsiz) { + +/* This is a small subproblem and is solved by DLASDQ. */ + + dlaset_("A", &nsize, &nsize, &c_b328, &c_b1034, &rwork[vt + + st1], n); + dlaset_("A", &nsize, &nsize, &c_b328, &c_b1034, &rwork[u + + st1], n); + dlasdq_("U", &c__0, &nsize, &nsize, &nsize, &c__0, &d__[st], & + e[st], &rwork[vt + st1], n, &rwork[u + st1], n, & + rwork[nrwork], &c__1, &rwork[nrwork], info) + ; + if (*info != 0) { + return 0; + } + +/* + In the real version, B is passed to DLASDQ and multiplied + internally by Q'. Here B is complex and that product is + computed below in two steps (real and imaginary parts). +*/ + + j = irwb - 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = st + nsize - 1; + for (jrow = st; jrow <= i__3; ++jrow) { + ++j; + i__4 = jrow + jcol * b_dim1; + rwork[j] = b[i__4].r; +/* L180: */ + } +/* L190: */ + } + dgemm_("T", "N", &nsize, nrhs, &nsize, &c_b1034, &rwork[u + + st1], n, &rwork[irwb], &nsize, &c_b328, &rwork[irwrb], + &nsize); + j = irwb - 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = st + nsize - 1; + for (jrow = st; jrow <= i__3; ++jrow) { + ++j; + rwork[j] = d_imag(&b[jrow + jcol * b_dim1]); +/* L200: */ + } +/* L210: */ + } + dgemm_("T", "N", &nsize, nrhs, &nsize, &c_b1034, &rwork[u + + st1], n, &rwork[irwb], &nsize, &c_b328, &rwork[irwib], + &nsize); + jreal = irwrb - 1; + jimag = irwib - 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = st + nsize - 1; + for (jrow = st; jrow <= i__3; ++jrow) { + ++jreal; + ++jimag; + i__4 = jrow + jcol * b_dim1; + i__5 = jreal; + i__6 = jimag; + z__1.r = rwork[i__5], z__1.i = rwork[i__6]; + b[i__4].r = z__1.r, b[i__4].i = z__1.i; +/* L220: */ + } +/* L230: */ + } + + zlacpy_("A", &nsize, nrhs, &b[st + b_dim1], ldb, &work[bx + + st1], n); + } else { + +/* A large problem. Solve it using divide and conquer. */ + + dlasda_(&icmpq1, smlsiz, &nsize, &sqre, &d__[st], &e[st], & + rwork[u + st1], n, &rwork[vt + st1], &iwork[k + st1], + &rwork[difl + st1], &rwork[difr + st1], &rwork[z__ + + st1], &rwork[poles + st1], &iwork[givptr + st1], & + iwork[givcol + st1], n, &iwork[perm + st1], &rwork[ + givnum + st1], &rwork[c__ + st1], &rwork[s + st1], & + rwork[nrwork], &iwork[iwk], info); + if (*info != 0) { + return 0; + } + bxst = bx + st1; + zlalsa_(&icmpq2, smlsiz, &nsize, nrhs, &b[st + b_dim1], ldb, & + work[bxst], n, &rwork[u + st1], n, &rwork[vt + st1], & + iwork[k + st1], &rwork[difl + st1], &rwork[difr + st1] + , &rwork[z__ + st1], &rwork[poles + st1], &iwork[ + givptr + st1], &iwork[givcol + st1], n, &iwork[perm + + st1], &rwork[givnum + st1], &rwork[c__ + st1], &rwork[ + s + st1], &rwork[nrwork], &iwork[iwk], info); + if (*info != 0) { + return 0; + } + } + st = i__ + 1; + } +/* L240: */ + } + +/* Apply the singular values and treat the tiny ones as zero. */ + + tol = rcnd * (d__1 = d__[idamax_(n, &d__[1], &c__1)], abs(d__1)); + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* + Some of the elements in D can be negative because 1-by-1 + subproblems were not solved explicitly. +*/ + + if ((d__1 = d__[i__], abs(d__1)) <= tol) { + zlaset_("A", &c__1, nrhs, &c_b56, &c_b56, &work[bx + i__ - 1], n); + } else { + ++(*rank); + zlascl_("G", &c__0, &c__0, &d__[i__], &c_b1034, &c__1, nrhs, & + work[bx + i__ - 1], n, info); + } + d__[i__] = (d__1 = d__[i__], abs(d__1)); +/* L250: */ + } + +/* Now apply back the right singular vectors. */ + + icmpq2 = 1; + i__1 = nsub; + for (i__ = 1; i__ <= i__1; ++i__) { + st = iwork[i__]; + st1 = st - 1; + nsize = iwork[sizei + i__ - 1]; + bxst = bx + st1; + if (nsize == 1) { + zcopy_(nrhs, &work[bxst], n, &b[st + b_dim1], ldb); + } else if (nsize <= *smlsiz) { + +/* + Since B and BX are complex, the following call to DGEMM + is performed in two steps (real and imaginary parts). + + CALL DGEMM( 'T', 'N', NSIZE, NRHS, NSIZE, ONE, + $ RWORK( VT+ST1 ), N, RWORK( BXST ), N, ZERO, + $ B( ST, 1 ), LDB ) +*/ + + j = bxst - *n - 1; + jreal = irwb - 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + j += *n; + i__3 = nsize; + for (jrow = 1; jrow <= i__3; ++jrow) { + ++jreal; + i__4 = j + jrow; + rwork[jreal] = work[i__4].r; +/* L260: */ + } +/* L270: */ + } + dgemm_("T", "N", &nsize, nrhs, &nsize, &c_b1034, &rwork[vt + st1], + n, &rwork[irwb], &nsize, &c_b328, &rwork[irwrb], &nsize); + j = bxst - *n - 1; + jimag = irwb - 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + j += *n; + i__3 = nsize; + for (jrow = 1; jrow <= i__3; ++jrow) { + ++jimag; + rwork[jimag] = d_imag(&work[j + jrow]); +/* L280: */ + } +/* L290: */ + } + dgemm_("T", "N", &nsize, nrhs, &nsize, &c_b1034, &rwork[vt + st1], + n, &rwork[irwb], &nsize, &c_b328, &rwork[irwib], &nsize); + jreal = irwrb - 1; + jimag = irwib - 1; + i__2 = *nrhs; + for (jcol = 1; jcol <= i__2; ++jcol) { + i__3 = st + nsize - 1; + for (jrow = st; jrow <= i__3; ++jrow) { + ++jreal; + ++jimag; + i__4 = jrow + jcol * b_dim1; + i__5 = jreal; + i__6 = jimag; + z__1.r = rwork[i__5], z__1.i = rwork[i__6]; + b[i__4].r = z__1.r, b[i__4].i = z__1.i; +/* L300: */ + } +/* L310: */ + } + } else { + zlalsa_(&icmpq2, smlsiz, &nsize, nrhs, &work[bxst], n, &b[st + + b_dim1], ldb, &rwork[u + st1], n, &rwork[vt + st1], & + iwork[k + st1], &rwork[difl + st1], &rwork[difr + st1], & + rwork[z__ + st1], &rwork[poles + st1], &iwork[givptr + + st1], &iwork[givcol + st1], n, &iwork[perm + st1], &rwork[ + givnum + st1], &rwork[c__ + st1], &rwork[s + st1], &rwork[ + nrwork], &iwork[iwk], info); + if (*info != 0) { + return 0; + } + } +/* L320: */ + } + +/* Unscale and sort the singular values. */ + + dlascl_("G", &c__0, &c__0, &c_b1034, &orgnrm, n, &c__1, &d__[1], n, info); + dlasrt_("D", n, &d__[1], info); + zlascl_("G", &c__0, &c__0, &orgnrm, &c_b1034, n, nrhs, &b[b_offset], ldb, + info); + + return 0; + +/* End of ZLALSD */ + +} /* zlalsd_ */ + +doublereal zlange_(char *norm, integer *m, integer *n, doublecomplex *a, + integer *lda, doublereal *work) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal ret_val, d__1, d__2; + + /* Local variables */ + static integer i__, j; + static doublereal sum, scale; + extern logical lsame_(char *, char *); + static doublereal value; + extern /* Subroutine */ int zlassq_(integer *, doublecomplex *, integer *, + doublereal *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLANGE returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + complex matrix A. + + Description + =========== + + ZLANGE returns the value + + ZLANGE = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in ZLANGE as described + above. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. When M = 0, + ZLANGE is set to zero. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. When N = 0, + ZLANGE is set to zero. + + A (input) COMPLEX*16 array, dimension (LDA,N) + The m by n matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(M,1). + + WORK (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)), + where LWORK >= M when NORM = 'I'; otherwise, WORK is not + referenced. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (min(*m,*n) == 0) { + value = 0.; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + value = 0.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__1 = value, d__2 = z_abs(&a[i__ + j * a_dim1]); + value = max(d__1,d__2); +/* L10: */ + } +/* L20: */ + } + } else if (lsame_(norm, "O") || *(unsigned char *) + norm == '1') { + +/* Find norm1(A). */ + + value = 0.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = 0.; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + sum += z_abs(&a[i__ + j * a_dim1]); +/* L30: */ + } + value = max(value,sum); +/* L40: */ + } + } else if (lsame_(norm, "I")) { + +/* Find normI(A). */ + + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.; +/* L50: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + work[i__] += z_abs(&a[i__ + j * a_dim1]); +/* L60: */ + } +/* L70: */ + } + value = 0.; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__1 = value, d__2 = work[i__]; + value = max(d__1,d__2); +/* L80: */ + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.; + sum = 1.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + zlassq_(m, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L90: */ + } + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of ZLANGE */ + +} /* zlange_ */ + +doublereal zlanhe_(char *norm, char *uplo, integer *n, doublecomplex *a, + integer *lda, doublereal *work) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublereal ret_val, d__1, d__2, d__3; + + /* Local variables */ + static integer i__, j; + static doublereal sum, absa, scale; + extern logical lsame_(char *, char *); + static doublereal value; + extern /* Subroutine */ int zlassq_(integer *, doublecomplex *, integer *, + doublereal *, doublereal *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLANHE returns the value of the one norm, or the Frobenius norm, or + the infinity norm, or the element of largest absolute value of a + complex hermitian matrix A. + + Description + =========== + + ZLANHE returns the value + + ZLANHE = ( max(abs(A(i,j))), NORM = 'M' or 'm' + ( + ( norm1(A), NORM = '1', 'O' or 'o' + ( + ( normI(A), NORM = 'I' or 'i' + ( + ( normF(A), NORM = 'F', 'f', 'E' or 'e' + + where norm1 denotes the one norm of a matrix (maximum column sum), + normI denotes the infinity norm of a matrix (maximum row sum) and + normF denotes the Frobenius norm of a matrix (square root of sum of + squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. + + Arguments + ========= + + NORM (input) CHARACTER*1 + Specifies the value to be returned in ZLANHE as described + above. + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + hermitian matrix A is to be referenced. + = 'U': Upper triangular part of A is referenced + = 'L': Lower triangular part of A is referenced + + N (input) INTEGER + The order of the matrix A. N >= 0. When N = 0, ZLANHE is + set to zero. + + A (input) COMPLEX*16 array, dimension (LDA,N) + The hermitian matrix A. If UPLO = 'U', the leading n by n + upper triangular part of A contains the upper triangular part + of the matrix A, and the strictly lower triangular part of A + is not referenced. If UPLO = 'L', the leading n by n lower + triangular part of A contains the lower triangular part of + the matrix A, and the strictly upper triangular part of A is + not referenced. Note that the imaginary parts of the diagonal + elements need not be set and are assumed to be zero. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(N,1). + + WORK (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)), + where LWORK >= N when NORM = 'I' or '1' or 'O'; otherwise, + WORK is not referenced. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --work; + + /* Function Body */ + if (*n == 0) { + value = 0.; + } else if (lsame_(norm, "M")) { + +/* Find max(abs(A(i,j))). */ + + value = 0.; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__1 = value, d__2 = z_abs(&a[i__ + j * a_dim1]); + value = max(d__1,d__2); +/* L10: */ + } +/* Computing MAX */ + i__2 = j + j * a_dim1; + d__2 = value, d__3 = (d__1 = a[i__2].r, abs(d__1)); + value = max(d__2,d__3); +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = j + j * a_dim1; + d__2 = value, d__3 = (d__1 = a[i__2].r, abs(d__1)); + value = max(d__2,d__3); + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { +/* Computing MAX */ + d__1 = value, d__2 = z_abs(&a[i__ + j * a_dim1]); + value = max(d__1,d__2); +/* L30: */ + } +/* L40: */ + } + } + } else if (lsame_(norm, "I") || lsame_(norm, "O") || *(unsigned char *)norm == '1') { + +/* Find normI(A) ( = norm1(A), since A is hermitian). */ + + value = 0.; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + sum = 0.; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + absa = z_abs(&a[i__ + j * a_dim1]); + sum += absa; + work[i__] += absa; +/* L50: */ + } + i__2 = j + j * a_dim1; + work[j] = sum + (d__1 = a[i__2].r, abs(d__1)); +/* L60: */ + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { +/* Computing MAX */ + d__1 = value, d__2 = work[i__]; + value = max(d__1,d__2); +/* L70: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + work[i__] = 0.; +/* L80: */ + } + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j + j * a_dim1; + sum = work[j] + (d__1 = a[i__2].r, abs(d__1)); + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + absa = z_abs(&a[i__ + j * a_dim1]); + sum += absa; + work[i__] += absa; +/* L90: */ + } + value = max(value,sum); +/* L100: */ + } + } + } else if (lsame_(norm, "F") || lsame_(norm, "E")) { + +/* Find normF(A). */ + + scale = 0.; + sum = 1.; + if (lsame_(uplo, "U")) { + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + i__2 = j - 1; + zlassq_(&i__2, &a[j * a_dim1 + 1], &c__1, &scale, &sum); +/* L110: */ + } + } else { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = *n - j; + zlassq_(&i__2, &a[j + 1 + j * a_dim1], &c__1, &scale, &sum); +/* L120: */ + } + } + sum *= 2; + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + if (a[i__2].r != 0.) { + i__2 = i__ + i__ * a_dim1; + absa = (d__1 = a[i__2].r, abs(d__1)); + if (scale < absa) { +/* Computing 2nd power */ + d__1 = scale / absa; + sum = sum * (d__1 * d__1) + 1.; + scale = absa; + } else { +/* Computing 2nd power */ + d__1 = absa / scale; + sum += d__1 * d__1; + } + } +/* L130: */ + } + value = scale * sqrt(sum); + } + + ret_val = value; + return ret_val; + +/* End of ZLANHE */ + +} /* zlanhe_ */ + +/* Subroutine */ int zlaqr0_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, + doublecomplex *w, integer *iloz, integer *ihiz, doublecomplex *z__, + integer *ldz, doublecomplex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1, d__2, d__3, d__4, d__5, d__6, d__7, d__8; + doublecomplex z__1, z__2, z__3, z__4, z__5; + + /* Local variables */ + static integer i__, k; + static doublereal s; + static doublecomplex aa, bb, cc, dd; + static integer ld, nh, it, ks, kt, ku, kv, ls, ns, nw; + static doublecomplex tr2, det; + static integer inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, kbot, + nmin; + static doublecomplex swap; + static integer ktop; + static doublecomplex zdum[1] /* was [1][1] */; + static integer kacc22, itmax, nsmax, nwmax, kwtop; + extern /* Subroutine */ int zlaqr3_(logical *, logical *, integer *, + integer *, integer *, integer *, doublecomplex *, integer *, + integer *, integer *, doublecomplex *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, integer *, + doublecomplex *, integer *, integer *, doublecomplex *, integer * + , doublecomplex *, integer *), zlaqr4_(logical *, logical *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, integer *), zlaqr5_(logical *, + logical *, integer *, integer *, integer *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, integer *, doublecomplex *, integer *, + integer *, doublecomplex *, integer *); + static integer nibble; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static char jbcmpz[2]; + static doublecomplex rtdisc; + static integer nwupbd; + static logical sorted; + extern /* Subroutine */ int zlahqr_(logical *, logical *, integer *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + integer *, integer *, doublecomplex *, integer *, integer *), + zlacpy_(char *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Purpose + ======= + + ZLAQR0 computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**H, where T is an upper triangular matrix (the + Schur form), and Z is the unitary matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input unitary + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the unitary matrix Q: A = Q*H*Q**H = (QZ)*H*(QZ)**H. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1, + H(ILO,ILO-1) is zero. ILO and IHI are normally set by a + previous call to ZGEBAL, and then passed to ZGEHRD when the + matrix output by ZGEBAL is reduced to Hessenberg form. + Otherwise, ILO and IHI should be set to 1 and N, + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) COMPLEX*16 array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and WANTT is .TRUE., then H + contains the upper triangular matrix T from the Schur + decomposition (the Schur form). If INFO = 0 and WANT is + .FALSE., then the contents of H are unspecified on exit. + (The output value of H when INFO.GT.0 is given under the + description of INFO below.) + + This subroutine may explicitly set H(i,j) = 0 for i.GT.j and + j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + W (output) COMPLEX*16 array, dimension (N) + The computed eigenvalues of H(ILO:IHI,ILO:IHI) are stored + in W(ILO:IHI). If WANTT is .TRUE., then the eigenvalues are + stored in the same order as on the diagonal of the Schur + form returned in H, with W(i) = H(i,i). + + Z (input/output) COMPLEX*16 array, dimension (LDZ,IHI) + If WANTZ is .FALSE., then Z is not referenced. + If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is + replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the + orthogonal Schur factor of H(ILO:IHI,ILO:IHI). + (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if WANTZ is .TRUE. + then LDZ.GE.MAX(1,IHIZ). Otherwize, LDZ.GE.1. + + WORK (workspace/output) COMPLEX*16 array, dimension LWORK + On exit, if LWORK = -1, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient, but LWORK typically as large as 6*N may + be required for optimal performance. A workspace query + to determine the optimal workspace size is recommended. + + If LWORK = -1, then ZLAQR0 does a workspace query. + In this case, ZLAQR0 checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, ZLAQR0 failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and WANT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is a unitary matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + + (final value of Z(ILO:IHI,ILOZ:IHIZ) + = (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U + + where U is the unitary matrix in (*) (regard- + less of the value of WANTT.) + + If INFO .GT. 0 and WANTZ is .FALSE., then Z is not + accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . ZLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== Exceptional deflation windows: try to cure rare + . slow convergence by varying the size of the + . deflation window after KEXNW iterations. ==== + + ==== Exceptional shifts: try to cure rare slow convergence + . with ad-hoc exceptional shifts every KEXSH iterations. + . ==== + + ==== The constant WILK1 is used to form the exceptional + . shifts. ==== +*/ + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --w; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + +/* ==== Quick return for N = 0: nothing to do. ==== */ + + if (*n == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + if (*n <= 11) { + +/* ==== Tiny matrices must use ZLAHQR. ==== */ + + lwkopt = 1; + if (*lwork != -1) { + zlahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], + iloz, ihiz, &z__[z_offset], ldz, info); + } + } else { + +/* + ==== Use small bulge multi-shift QR with aggressive early + . deflation on larger-than-tiny matrices. ==== + + ==== Hope for the best. ==== +*/ + + *info = 0; + +/* ==== Set up job flags for ILAENV. ==== */ + + if (*wantt) { + *(unsigned char *)jbcmpz = 'S'; + } else { + *(unsigned char *)jbcmpz = 'E'; + } + if (*wantz) { + *(unsigned char *)&jbcmpz[1] = 'V'; + } else { + *(unsigned char *)&jbcmpz[1] = 'N'; + } + +/* + ==== NWR = recommended deflation window size. At this + . point, N .GT. NTINY = 11, so there is enough + . subdiagonal workspace for NWR.GE.2 as required. + . (In fact, there is enough subdiagonal space for + . NWR.GE.3.) ==== +*/ + + nwr = ilaenv_(&c__13, "ZLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nwr = max(2,nwr); +/* Computing MIN */ + i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2); + nwr = min(i__1,nwr); + +/* + ==== NSR = recommended number of simultaneous shifts. + . At this point N .GT. NTINY = 11, so there is at + . enough subdiagonal workspace for NSR to be even + . and greater than or equal to two as required. ==== +*/ + + nsr = ilaenv_(&c__15, "ZLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); +/* Computing MIN */ + i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - + *ilo; + nsr = min(i__1,i__2); +/* Computing MAX */ + i__1 = 2, i__2 = nsr - nsr % 2; + nsr = max(i__1,i__2); + +/* + ==== Estimate optimal workspace ==== + + ==== Workspace query call to ZLAQR3 ==== +*/ + + i__1 = nwr + 1; + zlaqr3_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, + ihiz, &z__[z_offset], ldz, &ls, &ld, &w[1], &h__[h_offset], + ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], ldh, &work[1], + &c_n1); + +/* + ==== Optimal workspace = MAX(ZLAQR5, ZLAQR3) ==== + + Computing MAX +*/ + i__1 = nsr * 3 / 2, i__2 = (integer) work[1].r; + lwkopt = max(i__1,i__2); + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + d__1 = (doublereal) lwkopt; + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + return 0; + } + +/* ==== ZLAHQR/ZLAQR0 crossover point ==== */ + + nmin = ilaenv_(&c__12, "ZLAQR0", jbcmpz, n, ilo, ihi, lwork, (ftnlen) + 6, (ftnlen)2); + nmin = max(11,nmin); + +/* ==== Nibble crossover point ==== */ + + nibble = ilaenv_(&c__14, "ZLAQR0", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + nibble = max(0,nibble); + +/* + ==== Accumulate reflections during ttswp? Use block + . 2-by-2 structure during matrix-matrix multiply? ==== +*/ + + kacc22 = ilaenv_(&c__16, "ZLAQR0", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + kacc22 = max(0,kacc22); + kacc22 = min(2,kacc22); + +/* + ==== NWMAX = the largest possible deflation window for + . which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n - 1) / 3, i__2 = *lwork / 2; + nwmax = min(i__1,i__2); + nw = nwmax; + +/* + ==== NSMAX = the Largest number of simultaneous shifts + . for which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3; + nsmax = min(i__1,i__2); + nsmax -= nsmax % 2; + +/* ==== NDFL: an iteration count restarted at deflation. ==== */ + + ndfl = 1; + +/* + ==== ITMAX = iteration limit ==== + + Computing MAX +*/ + i__1 = 10, i__2 = *ihi - *ilo + 1; + itmax = max(i__1,i__2) * 30; + +/* ==== Last row and column in the active block ==== */ + + kbot = *ihi; + +/* ==== Main Loop ==== */ + + i__1 = itmax; + for (it = 1; it <= i__1; ++it) { + +/* ==== Done when KBOT falls below ILO ==== */ + + if (kbot < *ilo) { + goto L80; + } + +/* ==== Locate active block ==== */ + + i__2 = *ilo + 1; + for (k = kbot; k >= i__2; --k) { + i__3 = k + (k - 1) * h_dim1; + if (h__[i__3].r == 0. && h__[i__3].i == 0.) { + goto L20; + } +/* L10: */ + } + k = *ilo; +L20: + ktop = k; + +/* + ==== Select deflation window size: + . Typical Case: + . If possible and advisable, nibble the entire + . active block. If not, use size MIN(NWR,NWMAX) + . or MIN(NWR+1,NWMAX) depending upon which has + . the smaller corresponding subdiagonal entry + . (a heuristic). + . + . Exceptional Case: + . If there have been no deflations in KEXNW or + . more iterations, then vary the deflation window + . size. At first, because, larger windows are, + . in general, more powerful than smaller ones, + . rapidly increase the window to the maximum possible. + . Then, gradually reduce the window size. ==== +*/ + + nh = kbot - ktop + 1; + nwupbd = min(nh,nwmax); + if (ndfl < 5) { + nw = min(nwupbd,nwr); + } else { +/* Computing MIN */ + i__2 = nwupbd, i__3 = nw << 1; + nw = min(i__2,i__3); + } + if (nw < nwmax) { + if (nw >= nh - 1) { + nw = nh; + } else { + kwtop = kbot - nw + 1; + i__2 = kwtop + (kwtop - 1) * h_dim1; + i__3 = kwtop - 1 + (kwtop - 2) * h_dim1; + if ((d__1 = h__[i__2].r, abs(d__1)) + (d__2 = d_imag(&h__[ + kwtop + (kwtop - 1) * h_dim1]), abs(d__2)) > ( + d__3 = h__[i__3].r, abs(d__3)) + (d__4 = d_imag(& + h__[kwtop - 1 + (kwtop - 2) * h_dim1]), abs(d__4)) + ) { + ++nw; + } + } + } + if (ndfl < 5) { + ndec = -1; + } else if (ndec >= 0 || nw >= nwupbd) { + ++ndec; + if (nw - ndec < 2) { + ndec = 0; + } + nw -= ndec; + } + +/* + ==== Aggressive early deflation: + . split workspace under the subdiagonal into + . - an nw-by-nw work array V in the lower + . left-hand-corner, + . - an NW-by-at-least-NW-but-more-is-better + . (NW-by-NHO) horizontal work array along + . the bottom edge, + . - an at-least-NW-but-more-is-better (NHV-by-NW) + . vertical work array along the left-hand-edge. + . ==== +*/ + + kv = *n - nw + 1; + kt = nw + 1; + nho = *n - nw - 1 - kt + 1; + kwv = nw + 2; + nve = *n - nw - kwv + 1; + +/* ==== Aggressive early deflation ==== */ + + zlaqr3_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, + iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &w[1], &h__[kv + + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], ldh, &nve, & + h__[kwv + h_dim1], ldh, &work[1], lwork); + +/* ==== Adjust KBOT accounting for new deflations. ==== */ + + kbot -= ld; + +/* ==== KS points to the shifts. ==== */ + + ks = kbot - ls + 1; + +/* + ==== Skip an expensive QR sweep if there is a (partly + . heuristic) reason to expect that many eigenvalues + . will deflate without it. Here, the QR sweep is + . skipped if many eigenvalues have just been deflated + . or if the remaining active block is small. +*/ + + if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min( + nmin,nwmax)) { + +/* + ==== NS = nominal number of simultaneous shifts. + . This may be lowered (slightly) if ZLAQR3 + . did not provide that many shifts. ==== + + Computing MIN + Computing MAX +*/ + i__4 = 2, i__5 = kbot - ktop; + i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5); + ns = min(i__2,i__3); + ns -= ns % 2; + +/* + ==== If there have been no deflations + . in a multiple of KEXSH iterations, + . then try exceptional shifts. + . Otherwise use shifts provided by + . ZLAQR3 above or from the eigenvalues + . of a trailing principal submatrix. ==== +*/ + + if (ndfl % 6 == 0) { + ks = kbot - ns + 1; + i__2 = ks + 1; + for (i__ = kbot; i__ >= i__2; i__ += -2) { + i__3 = i__; + i__4 = i__ + i__ * h_dim1; + i__5 = i__ + (i__ - 1) * h_dim1; + d__3 = ((d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[i__ + (i__ - 1) * h_dim1]), abs( + d__2))) * .75; + z__1.r = h__[i__4].r + d__3, z__1.i = h__[i__4].i; + w[i__3].r = z__1.r, w[i__3].i = z__1.i; + i__3 = i__ - 1; + i__4 = i__; + w[i__3].r = w[i__4].r, w[i__3].i = w[i__4].i; +/* L30: */ + } + } else { + +/* + ==== Got NS/2 or fewer shifts? Use ZLAQR4 or + . ZLAHQR on a trailing principal submatrix to + . get more. (Since NS.LE.NSMAX.LE.(N+6)/9, + . there is enough space below the subdiagonal + . to fit an NS-by-NS scratch array.) ==== +*/ + + if (kbot - ks + 1 <= ns / 2) { + ks = kbot - ns + 1; + kt = *n - ns + 1; + zlacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, & + h__[kt + h_dim1], ldh); + if (ns > nmin) { + zlaqr4_(&c_false, &c_false, &ns, &c__1, &ns, &h__[ + kt + h_dim1], ldh, &w[ks], &c__1, &c__1, + zdum, &c__1, &work[1], lwork, &inf); + } else { + zlahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[ + kt + h_dim1], ldh, &w[ks], &c__1, &c__1, + zdum, &c__1, &inf); + } + ks += inf; + +/* + ==== In case of a rare QR failure use + . eigenvalues of the trailing 2-by-2 + . principal submatrix. Scale to avoid + . overflows, underflows and subnormals. + . (The scale factor S can not be zero, + . because H(KBOT,KBOT-1) is nonzero.) ==== +*/ + + if (ks >= kbot) { + i__2 = kbot - 1 + (kbot - 1) * h_dim1; + i__3 = kbot + (kbot - 1) * h_dim1; + i__4 = kbot - 1 + kbot * h_dim1; + i__5 = kbot + kbot * h_dim1; + s = (d__1 = h__[i__2].r, abs(d__1)) + (d__2 = + d_imag(&h__[kbot - 1 + (kbot - 1) * + h_dim1]), abs(d__2)) + ((d__3 = h__[i__3] + .r, abs(d__3)) + (d__4 = d_imag(&h__[kbot + + (kbot - 1) * h_dim1]), abs(d__4))) + (( + d__5 = h__[i__4].r, abs(d__5)) + (d__6 = + d_imag(&h__[kbot - 1 + kbot * h_dim1]), + abs(d__6))) + ((d__7 = h__[i__5].r, abs( + d__7)) + (d__8 = d_imag(&h__[kbot + kbot * + h_dim1]), abs(d__8))); + i__2 = kbot - 1 + (kbot - 1) * h_dim1; + z__1.r = h__[i__2].r / s, z__1.i = h__[i__2].i / + s; + aa.r = z__1.r, aa.i = z__1.i; + i__2 = kbot + (kbot - 1) * h_dim1; + z__1.r = h__[i__2].r / s, z__1.i = h__[i__2].i / + s; + cc.r = z__1.r, cc.i = z__1.i; + i__2 = kbot - 1 + kbot * h_dim1; + z__1.r = h__[i__2].r / s, z__1.i = h__[i__2].i / + s; + bb.r = z__1.r, bb.i = z__1.i; + i__2 = kbot + kbot * h_dim1; + z__1.r = h__[i__2].r / s, z__1.i = h__[i__2].i / + s; + dd.r = z__1.r, dd.i = z__1.i; + z__2.r = aa.r + dd.r, z__2.i = aa.i + dd.i; + z__1.r = z__2.r / 2., z__1.i = z__2.i / 2.; + tr2.r = z__1.r, tr2.i = z__1.i; + z__3.r = aa.r - tr2.r, z__3.i = aa.i - tr2.i; + z__4.r = dd.r - tr2.r, z__4.i = dd.i - tr2.i; + z__2.r = z__3.r * z__4.r - z__3.i * z__4.i, + z__2.i = z__3.r * z__4.i + z__3.i * + z__4.r; + z__5.r = bb.r * cc.r - bb.i * cc.i, z__5.i = bb.r + * cc.i + bb.i * cc.r; + z__1.r = z__2.r - z__5.r, z__1.i = z__2.i - + z__5.i; + det.r = z__1.r, det.i = z__1.i; + z__2.r = -det.r, z__2.i = -det.i; + z_sqrt(&z__1, &z__2); + rtdisc.r = z__1.r, rtdisc.i = z__1.i; + i__2 = kbot - 1; + z__2.r = tr2.r + rtdisc.r, z__2.i = tr2.i + + rtdisc.i; + z__1.r = s * z__2.r, z__1.i = s * z__2.i; + w[i__2].r = z__1.r, w[i__2].i = z__1.i; + i__2 = kbot; + z__2.r = tr2.r - rtdisc.r, z__2.i = tr2.i - + rtdisc.i; + z__1.r = s * z__2.r, z__1.i = s * z__2.i; + w[i__2].r = z__1.r, w[i__2].i = z__1.i; + + ks = kbot - 1; + } + } + + if (kbot - ks + 1 > ns) { + +/* ==== Sort the shifts (Helps a little) ==== */ + + sorted = FALSE_; + i__2 = ks + 1; + for (k = kbot; k >= i__2; --k) { + if (sorted) { + goto L60; + } + sorted = TRUE_; + i__3 = k - 1; + for (i__ = ks; i__ <= i__3; ++i__) { + i__4 = i__; + i__5 = i__ + 1; + if ((d__1 = w[i__4].r, abs(d__1)) + (d__2 = + d_imag(&w[i__]), abs(d__2)) < (d__3 = + w[i__5].r, abs(d__3)) + (d__4 = + d_imag(&w[i__ + 1]), abs(d__4))) { + sorted = FALSE_; + i__4 = i__; + swap.r = w[i__4].r, swap.i = w[i__4].i; + i__4 = i__; + i__5 = i__ + 1; + w[i__4].r = w[i__5].r, w[i__4].i = w[i__5] + .i; + i__4 = i__ + 1; + w[i__4].r = swap.r, w[i__4].i = swap.i; + } +/* L40: */ + } +/* L50: */ + } +L60: + ; + } + } + +/* + ==== If there are only two shifts, then use + . only one. ==== +*/ + + if (kbot - ks + 1 == 2) { + i__2 = kbot; + i__3 = kbot + kbot * h_dim1; + z__2.r = w[i__2].r - h__[i__3].r, z__2.i = w[i__2].i - + h__[i__3].i; + z__1.r = z__2.r, z__1.i = z__2.i; + i__4 = kbot - 1; + i__5 = kbot + kbot * h_dim1; + z__4.r = w[i__4].r - h__[i__5].r, z__4.i = w[i__4].i - + h__[i__5].i; + z__3.r = z__4.r, z__3.i = z__4.i; + if ((d__1 = z__1.r, abs(d__1)) + (d__2 = d_imag(&z__1), + abs(d__2)) < (d__3 = z__3.r, abs(d__3)) + (d__4 = + d_imag(&z__3), abs(d__4))) { + i__2 = kbot - 1; + i__3 = kbot; + w[i__2].r = w[i__3].r, w[i__2].i = w[i__3].i; + } else { + i__2 = kbot; + i__3 = kbot - 1; + w[i__2].r = w[i__3].r, w[i__2].i = w[i__3].i; + } + } + +/* + ==== Use up to NS of the the smallest magnatiude + . shifts. If there aren't NS shifts available, + . then use them all, possibly dropping one to + . make the number of shifts even. ==== + + Computing MIN +*/ + i__2 = ns, i__3 = kbot - ks + 1; + ns = min(i__2,i__3); + ns -= ns % 2; + ks = kbot - ns + 1; + +/* + ==== Small-bulge multi-shift QR sweep: + . split workspace under the subdiagonal into + . - a KDU-by-KDU work array U in the lower + . left-hand-corner, + . - a KDU-by-at-least-KDU-but-more-is-better + . (KDU-by-NHo) horizontal work array WH along + . the bottom edge, + . - and an at-least-KDU-but-more-is-better-by-KDU + . (NVE-by-KDU) vertical work WV arrow along + . the left-hand-edge. ==== +*/ + + kdu = ns * 3 - 3; + ku = *n - kdu + 1; + kwh = kdu + 1; + nho = *n - kdu - 3 - (kdu + 1) + 1; + kwv = kdu + 4; + nve = *n - kdu - kwv + 1; + +/* ==== Small-bulge multi-shift QR sweep ==== */ + + zlaqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &w[ks], & + h__[h_offset], ldh, iloz, ihiz, &z__[z_offset], ldz, & + work[1], &c__3, &h__[ku + h_dim1], ldh, &nve, &h__[ + kwv + h_dim1], ldh, &nho, &h__[ku + kwh * h_dim1], + ldh); + } + +/* ==== Note progress (or the lack of it). ==== */ + + if (ld > 0) { + ndfl = 1; + } else { + ++ndfl; + } + +/* + ==== End of main loop ==== + L70: +*/ + } + +/* + ==== Iteration limit exceeded. Set INFO to show where + . the problem occurred and exit. ==== +*/ + + *info = kbot; +L80: + ; + } + +/* ==== Return the optimal value of LWORK. ==== */ + + d__1 = (doublereal) lwkopt; + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + +/* ==== End of ZLAQR0 ==== */ + + return 0; +} /* zlaqr0_ */ + +/* Subroutine */ int zlaqr1_(integer *n, doublecomplex *h__, integer *ldh, + doublecomplex *s1, doublecomplex *s2, doublecomplex *v) +{ + /* System generated locals */ + integer h_dim1, h_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2, d__3, d__4, d__5, d__6; + doublecomplex z__1, z__2, z__3, z__4, z__5, z__6, z__7, z__8; + + /* Local variables */ + static doublereal s; + static doublecomplex h21s, h31s; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + Given a 2-by-2 or 3-by-3 matrix H, ZLAQR1 sets v to a + scalar multiple of the first column of the product + + (*) K = (H - s1*I)*(H - s2*I) + + scaling to avoid overflows and most underflows. + + This is useful for starting double implicit shift bulges + in the QR algorithm. + + + N (input) integer + Order of the matrix H. N must be either 2 or 3. + + H (input) COMPLEX*16 array of dimension (LDH,N) + The 2-by-2 or 3-by-3 matrix H in (*). + + LDH (input) integer + The leading dimension of H as declared in + the calling procedure. LDH.GE.N + + S1 (input) COMPLEX*16 + S2 S1 and S2 are the shifts defining K in (*) above. + + V (output) COMPLEX*16 array of dimension N + A scalar multiple of the first column of the + matrix K in (*). + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --v; + + /* Function Body */ + if (*n == 2) { + i__1 = h_dim1 + 1; + z__2.r = h__[i__1].r - s2->r, z__2.i = h__[i__1].i - s2->i; + z__1.r = z__2.r, z__1.i = z__2.i; + i__2 = h_dim1 + 2; + s = (d__1 = z__1.r, abs(d__1)) + (d__2 = d_imag(&z__1), abs(d__2)) + ( + (d__3 = h__[i__2].r, abs(d__3)) + (d__4 = d_imag(&h__[h_dim1 + + 2]), abs(d__4))); + if (s == 0.) { + v[1].r = 0., v[1].i = 0.; + v[2].r = 0., v[2].i = 0.; + } else { + i__1 = h_dim1 + 2; + z__1.r = h__[i__1].r / s, z__1.i = h__[i__1].i / s; + h21s.r = z__1.r, h21s.i = z__1.i; + i__1 = (h_dim1 << 1) + 1; + z__2.r = h21s.r * h__[i__1].r - h21s.i * h__[i__1].i, z__2.i = + h21s.r * h__[i__1].i + h21s.i * h__[i__1].r; + i__2 = h_dim1 + 1; + z__4.r = h__[i__2].r - s1->r, z__4.i = h__[i__2].i - s1->i; + i__3 = h_dim1 + 1; + z__6.r = h__[i__3].r - s2->r, z__6.i = h__[i__3].i - s2->i; + z__5.r = z__6.r / s, z__5.i = z__6.i / s; + z__3.r = z__4.r * z__5.r - z__4.i * z__5.i, z__3.i = z__4.r * + z__5.i + z__4.i * z__5.r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + v[1].r = z__1.r, v[1].i = z__1.i; + i__1 = h_dim1 + 1; + i__2 = (h_dim1 << 1) + 2; + z__4.r = h__[i__1].r + h__[i__2].r, z__4.i = h__[i__1].i + h__[ + i__2].i; + z__3.r = z__4.r - s1->r, z__3.i = z__4.i - s1->i; + z__2.r = z__3.r - s2->r, z__2.i = z__3.i - s2->i; + z__1.r = h21s.r * z__2.r - h21s.i * z__2.i, z__1.i = h21s.r * + z__2.i + h21s.i * z__2.r; + v[2].r = z__1.r, v[2].i = z__1.i; + } + } else { + i__1 = h_dim1 + 1; + z__2.r = h__[i__1].r - s2->r, z__2.i = h__[i__1].i - s2->i; + z__1.r = z__2.r, z__1.i = z__2.i; + i__2 = h_dim1 + 2; + i__3 = h_dim1 + 3; + s = (d__1 = z__1.r, abs(d__1)) + (d__2 = d_imag(&z__1), abs(d__2)) + ( + (d__3 = h__[i__2].r, abs(d__3)) + (d__4 = d_imag(&h__[h_dim1 + + 2]), abs(d__4))) + ((d__5 = h__[i__3].r, abs(d__5)) + (d__6 + = d_imag(&h__[h_dim1 + 3]), abs(d__6))); + if (s == 0.) { + v[1].r = 0., v[1].i = 0.; + v[2].r = 0., v[2].i = 0.; + v[3].r = 0., v[3].i = 0.; + } else { + i__1 = h_dim1 + 2; + z__1.r = h__[i__1].r / s, z__1.i = h__[i__1].i / s; + h21s.r = z__1.r, h21s.i = z__1.i; + i__1 = h_dim1 + 3; + z__1.r = h__[i__1].r / s, z__1.i = h__[i__1].i / s; + h31s.r = z__1.r, h31s.i = z__1.i; + i__1 = h_dim1 + 1; + z__4.r = h__[i__1].r - s1->r, z__4.i = h__[i__1].i - s1->i; + i__2 = h_dim1 + 1; + z__6.r = h__[i__2].r - s2->r, z__6.i = h__[i__2].i - s2->i; + z__5.r = z__6.r / s, z__5.i = z__6.i / s; + z__3.r = z__4.r * z__5.r - z__4.i * z__5.i, z__3.i = z__4.r * + z__5.i + z__4.i * z__5.r; + i__3 = (h_dim1 << 1) + 1; + z__7.r = h__[i__3].r * h21s.r - h__[i__3].i * h21s.i, z__7.i = + h__[i__3].r * h21s.i + h__[i__3].i * h21s.r; + z__2.r = z__3.r + z__7.r, z__2.i = z__3.i + z__7.i; + i__4 = h_dim1 * 3 + 1; + z__8.r = h__[i__4].r * h31s.r - h__[i__4].i * h31s.i, z__8.i = + h__[i__4].r * h31s.i + h__[i__4].i * h31s.r; + z__1.r = z__2.r + z__8.r, z__1.i = z__2.i + z__8.i; + v[1].r = z__1.r, v[1].i = z__1.i; + i__1 = h_dim1 + 1; + i__2 = (h_dim1 << 1) + 2; + z__5.r = h__[i__1].r + h__[i__2].r, z__5.i = h__[i__1].i + h__[ + i__2].i; + z__4.r = z__5.r - s1->r, z__4.i = z__5.i - s1->i; + z__3.r = z__4.r - s2->r, z__3.i = z__4.i - s2->i; + z__2.r = h21s.r * z__3.r - h21s.i * z__3.i, z__2.i = h21s.r * + z__3.i + h21s.i * z__3.r; + i__3 = h_dim1 * 3 + 2; + z__6.r = h__[i__3].r * h31s.r - h__[i__3].i * h31s.i, z__6.i = + h__[i__3].r * h31s.i + h__[i__3].i * h31s.r; + z__1.r = z__2.r + z__6.r, z__1.i = z__2.i + z__6.i; + v[2].r = z__1.r, v[2].i = z__1.i; + i__1 = h_dim1 + 1; + i__2 = h_dim1 * 3 + 3; + z__5.r = h__[i__1].r + h__[i__2].r, z__5.i = h__[i__1].i + h__[ + i__2].i; + z__4.r = z__5.r - s1->r, z__4.i = z__5.i - s1->i; + z__3.r = z__4.r - s2->r, z__3.i = z__4.i - s2->i; + z__2.r = h31s.r * z__3.r - h31s.i * z__3.i, z__2.i = h31s.r * + z__3.i + h31s.i * z__3.r; + i__3 = (h_dim1 << 1) + 3; + z__6.r = h21s.r * h__[i__3].r - h21s.i * h__[i__3].i, z__6.i = + h21s.r * h__[i__3].i + h21s.i * h__[i__3].r; + z__1.r = z__2.r + z__6.r, z__1.i = z__2.i + z__6.i; + v[3].r = z__1.r, v[3].i = z__1.i; + } + } + return 0; +} /* zlaqr1_ */ + +/* Subroutine */ int zlaqr2_(logical *wantt, logical *wantz, integer *n, + integer *ktop, integer *kbot, integer *nw, doublecomplex *h__, + integer *ldh, integer *iloz, integer *ihiz, doublecomplex *z__, + integer *ldz, integer *ns, integer *nd, doublecomplex *sh, + doublecomplex *v, integer *ldv, integer *nh, doublecomplex *t, + integer *ldt, integer *nv, doublecomplex *wv, integer *ldwv, + doublecomplex *work, integer *lwork) +{ + /* System generated locals */ + integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, + wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2, d__3, d__4, d__5, d__6; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, j; + static doublecomplex s; + static integer jw; + static doublereal foo; + static integer kln; + static doublecomplex tau; + static integer knt; + static doublereal ulp; + static integer lwk1, lwk2; + static doublecomplex beta; + static integer kcol, info, ifst, ilst, ltop, krow; + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *); + static integer infqr; + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer kwtop; + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), dlabad_(doublereal *, doublereal *); + + static doublereal safmin, safmax; + extern /* Subroutine */ int zgehrd_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *), zlarfg_(integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *), zlahqr_(logical *, + logical *, integer *, integer *, integer *, doublecomplex *, + integer *, doublecomplex *, integer *, integer *, doublecomplex *, + integer *, integer *), zlacpy_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *), + zlaset_(char *, integer *, integer *, doublecomplex *, + doublecomplex *, doublecomplex *, integer *); + static doublereal smlnum; + extern /* Subroutine */ int ztrexc_(char *, integer *, doublecomplex *, + integer *, doublecomplex *, integer *, integer *, integer *, + integer *); + static integer lwkopt; + extern /* Subroutine */ int zunmhr_(char *, char *, integer *, integer *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer * + ); + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + -- April 2009 -- + + + This subroutine is identical to ZLAQR3 except that it avoids + recursion by calling ZLAHQR instead of ZLAQR4. + + + ****************************************************************** + Aggressive early deflation: + + This subroutine accepts as input an upper Hessenberg matrix + H and performs an unitary similarity transformation + designed to detect and deflate fully converged eigenvalues from + a trailing principal submatrix. On output H has been over- + written by a new Hessenberg matrix that is a perturbation of + an unitary similarity transformation of H. It is to be + hoped that the final version of H has many zero subdiagonal + entries. + + ****************************************************************** + WANTT (input) LOGICAL + If .TRUE., then the Hessenberg matrix H is fully updated + so that the triangular Schur factor may be + computed (in cooperation with the calling subroutine). + If .FALSE., then only enough of H is updated to preserve + the eigenvalues. + + WANTZ (input) LOGICAL + If .TRUE., then the unitary matrix Z is updated so + so that the unitary Schur factor may be computed + (in cooperation with the calling subroutine). + If .FALSE., then Z is not referenced. + + N (input) INTEGER + The order of the matrix H and (if WANTZ is .TRUE.) the + order of the unitary matrix Z. + + KTOP (input) INTEGER + It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0. + KBOT and KTOP together determine an isolated block + along the diagonal of the Hessenberg matrix. + + KBOT (input) INTEGER + It is assumed without a check that either + KBOT = N or H(KBOT+1,KBOT)=0. KBOT and KTOP together + determine an isolated block along the diagonal of the + Hessenberg matrix. + + NW (input) INTEGER + Deflation window size. 1 .LE. NW .LE. (KBOT-KTOP+1). + + H (input/output) COMPLEX*16 array, dimension (LDH,N) + On input the initial N-by-N section of H stores the + Hessenberg matrix undergoing aggressive early deflation. + On output H has been transformed by a unitary + similarity transformation, perturbed, and the returned + to Hessenberg form that (it is to be hoped) has some + zero subdiagonal entries. + + LDH (input) integer + Leading dimension of H just as declared in the calling + subroutine. N .LE. LDH + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N. + + Z (input/output) COMPLEX*16 array, dimension (LDZ,N) + IF WANTZ is .TRUE., then on output, the unitary + similarity transformation mentioned above has been + accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ is .FALSE., then Z is unreferenced. + + LDZ (input) integer + The leading dimension of Z just as declared in the + calling subroutine. 1 .LE. LDZ. + + NS (output) integer + The number of unconverged (ie approximate) eigenvalues + returned in SR and SI that may be used as shifts by the + calling subroutine. + + ND (output) integer + The number of converged eigenvalues uncovered by this + subroutine. + + SH (output) COMPLEX*16 array, dimension KBOT + On output, approximate eigenvalues that may + be used for shifts are stored in SH(KBOT-ND-NS+1) + through SR(KBOT-ND). Converged eigenvalues are + stored in SH(KBOT-ND+1) through SH(KBOT). + + V (workspace) COMPLEX*16 array, dimension (LDV,NW) + An NW-by-NW work array. + + LDV (input) integer scalar + The leading dimension of V just as declared in the + calling subroutine. NW .LE. LDV + + NH (input) integer scalar + The number of columns of T. NH.GE.NW. + + T (workspace) COMPLEX*16 array, dimension (LDT,NW) + + LDT (input) integer + The leading dimension of T just as declared in the + calling subroutine. NW .LE. LDT + + NV (input) integer + The number of rows of work array WV available for + workspace. NV.GE.NW. + + WV (workspace) COMPLEX*16 array, dimension (LDWV,NW) + + LDWV (input) integer + The leading dimension of W just as declared in the + calling subroutine. NW .LE. LDV + + WORK (workspace) COMPLEX*16 array, dimension LWORK. + On exit, WORK(1) is set to an estimate of the optimal value + of LWORK for the given values of N, NW, KTOP and KBOT. + + LWORK (input) integer + The dimension of the work array WORK. LWORK = 2*NW + suffices, but greater efficiency may result from larger + values of LWORK. + + If LWORK = -1, then a workspace query is assumed; ZLAQR2 + only estimates the optimal workspace size for the given + values of N, NW, KTOP and KBOT. The estimate is returned + in WORK(1). No error message related to LWORK is issued + by XERBLA. Neither H nor Z are accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + + ==== Estimate optimal workspace. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --sh; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + --work; + + /* Function Body */ +/* Computing MIN */ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + if (jw <= 2) { + lwkopt = 1; + } else { + +/* ==== Workspace query call to ZGEHRD ==== */ + + i__1 = jw - 1; + zgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], & + c_n1, &info); + lwk1 = (integer) work[1].r; + +/* ==== Workspace query call to ZUNMHR ==== */ + + i__1 = jw - 1; + zunmhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[1], &c_n1, &info); + lwk2 = (integer) work[1].r; + +/* ==== Optimal workspace ==== */ + + lwkopt = jw + max(lwk1,lwk2); + } + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + d__1 = (doublereal) lwkopt; + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + return 0; + } + +/* + ==== Nothing to do ... + ... for an empty active block ... ==== +*/ + *ns = 0; + *nd = 0; + work[1].r = 1., work[1].i = 0.; + if (*ktop > *kbot) { + return 0; + } +/* ... nor for an empty deflation window. ==== */ + if (*nw < 1) { + return 0; + } + +/* ==== Machine constants ==== */ + + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + dlabad_(&safmin, &safmax); + ulp = PRECISION; + smlnum = safmin * ((doublereal) (*n) / ulp); + +/* + ==== Setup deflation window ==== + + Computing MIN +*/ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + kwtop = *kbot - jw + 1; + if (kwtop == *ktop) { + s.r = 0., s.i = 0.; + } else { + i__1 = kwtop + (kwtop - 1) * h_dim1; + s.r = h__[i__1].r, s.i = h__[i__1].i; + } + + if (*kbot == kwtop) { + +/* ==== 1-by-1 deflation window: not much to do ==== */ + + i__1 = kwtop; + i__2 = kwtop + kwtop * h_dim1; + sh[i__1].r = h__[i__2].r, sh[i__1].i = h__[i__2].i; + *ns = 1; + *nd = 0; +/* Computing MAX */ + i__1 = kwtop + kwtop * h_dim1; + d__5 = smlnum, d__6 = ulp * ((d__1 = h__[i__1].r, abs(d__1)) + (d__2 = + d_imag(&h__[kwtop + kwtop * h_dim1]), abs(d__2))); + if ((d__3 = s.r, abs(d__3)) + (d__4 = d_imag(&s), abs(d__4)) <= max( + d__5,d__6)) { + *ns = 0; + *nd = 1; + if (kwtop > *ktop) { + i__1 = kwtop + (kwtop - 1) * h_dim1; + h__[i__1].r = 0., h__[i__1].i = 0.; + } + } + work[1].r = 1., work[1].i = 0.; + return 0; + } + +/* + ==== Convert to spike-triangular form. (In case of a + . rare QR failure, this routine continues to do + . aggressive early deflation using that part of + . the deflation window that converged using INFQR + . here and there to keep track.) ==== +*/ + + zlacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], + ldt); + i__1 = jw - 1; + i__2 = *ldh + 1; + i__3 = *ldt + 1; + zcopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], & + i__3); + + zlaset_("A", &jw, &jw, &c_b56, &c_b57, &v[v_offset], ldv); + zlahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sh[kwtop], + &c__1, &jw, &v[v_offset], ldv, &infqr); + +/* ==== Deflation detection loop ==== */ + + *ns = jw; + ilst = infqr + 1; + i__1 = jw; + for (knt = infqr + 1; knt <= i__1; ++knt) { + +/* ==== Small spike tip deflation test ==== */ + + i__2 = *ns + *ns * t_dim1; + foo = (d__1 = t[i__2].r, abs(d__1)) + (d__2 = d_imag(&t[*ns + *ns * + t_dim1]), abs(d__2)); + if (foo == 0.) { + foo = (d__1 = s.r, abs(d__1)) + (d__2 = d_imag(&s), abs(d__2)); + } + i__2 = *ns * v_dim1 + 1; +/* Computing MAX */ + d__5 = smlnum, d__6 = ulp * foo; + if (((d__1 = s.r, abs(d__1)) + (d__2 = d_imag(&s), abs(d__2))) * (( + d__3 = v[i__2].r, abs(d__3)) + (d__4 = d_imag(&v[*ns * v_dim1 + + 1]), abs(d__4))) <= max(d__5,d__6)) { + +/* ==== One more converged eigenvalue ==== */ + + --(*ns); + } else { + +/* + ==== One undeflatable eigenvalue. Move it up out of the + . way. (ZTREXC can not fail in this case.) ==== +*/ + + ifst = *ns; + ztrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, & + ilst, &info); + ++ilst; + } +/* L10: */ + } + +/* ==== Return to Hessenberg form ==== */ + + if (*ns == 0) { + s.r = 0., s.i = 0.; + } + + if (*ns < jw) { + +/* + ==== sorting the diagonal of T improves accuracy for + . graded matrices. ==== +*/ + + i__1 = *ns; + for (i__ = infqr + 1; i__ <= i__1; ++i__) { + ifst = i__; + i__2 = *ns; + for (j = i__ + 1; j <= i__2; ++j) { + i__3 = j + j * t_dim1; + i__4 = ifst + ifst * t_dim1; + if ((d__1 = t[i__3].r, abs(d__1)) + (d__2 = d_imag(&t[j + j * + t_dim1]), abs(d__2)) > (d__3 = t[i__4].r, abs(d__3)) + + (d__4 = d_imag(&t[ifst + ifst * t_dim1]), abs(d__4)) + ) { + ifst = j; + } +/* L20: */ + } + ilst = i__; + if (ifst != ilst) { + ztrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &info); + } +/* L30: */ + } + } + +/* ==== Restore shift/eigenvalue array from T ==== */ + + i__1 = jw; + for (i__ = infqr + 1; i__ <= i__1; ++i__) { + i__2 = kwtop + i__ - 1; + i__3 = i__ + i__ * t_dim1; + sh[i__2].r = t[i__3].r, sh[i__2].i = t[i__3].i; +/* L40: */ + } + + + if (*ns < jw || s.r == 0. && s.i == 0.) { + if (*ns > 1 && (s.r != 0. || s.i != 0.)) { + +/* ==== Reflect spike back into lower triangle ==== */ + + zcopy_(ns, &v[v_offset], ldv, &work[1], &c__1); + i__1 = *ns; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + d_cnjg(&z__1, &work[i__]); + work[i__2].r = z__1.r, work[i__2].i = z__1.i; +/* L50: */ + } + beta.r = work[1].r, beta.i = work[1].i; + zlarfg_(ns, &beta, &work[2], &c__1, &tau); + work[1].r = 1., work[1].i = 0.; + + i__1 = jw - 2; + i__2 = jw - 2; + zlaset_("L", &i__1, &i__2, &c_b56, &c_b56, &t[t_dim1 + 3], ldt); + + d_cnjg(&z__1, &tau); + zlarf_("L", ns, &jw, &work[1], &c__1, &z__1, &t[t_offset], ldt, & + work[jw + 1]); + zlarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + zlarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, & + work[jw + 1]); + + i__1 = *lwork - jw; + zgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1] + , &i__1, &info); + } + +/* ==== Copy updated reduced window into place ==== */ + + if (kwtop > 1) { + i__1 = kwtop + (kwtop - 1) * h_dim1; + d_cnjg(&z__2, &v[v_dim1 + 1]); + z__1.r = s.r * z__2.r - s.i * z__2.i, z__1.i = s.r * z__2.i + s.i + * z__2.r; + h__[i__1].r = z__1.r, h__[i__1].i = z__1.i; + } + zlacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1] + , ldh); + i__1 = jw - 1; + i__2 = *ldt + 1; + i__3 = *ldh + 1; + zcopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1], + &i__3); + +/* + ==== Accumulate orthogonal matrix in order update + . H and Z, if requested. ==== +*/ + + if (*ns > 1 && (s.r != 0. || s.i != 0.)) { + i__1 = *lwork - jw; + zunmhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[jw + 1], &i__1, &info); + } + +/* ==== Update vertical slab in H ==== */ + + if (*wantt) { + ltop = 1; + } else { + ltop = *ktop; + } + i__1 = kwtop - 1; + i__2 = *nv; + for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = kwtop - krow; + kln = min(i__3,i__4); + zgemm_("N", "N", &kln, &jw, &jw, &c_b57, &h__[krow + kwtop * + h_dim1], ldh, &v[v_offset], ldv, &c_b56, &wv[wv_offset], + ldwv); + zlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * + h_dim1], ldh); +/* L60: */ + } + +/* ==== Update horizontal slab in H ==== */ + + if (*wantt) { + i__2 = *n; + i__1 = *nh; + for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; + kcol += i__1) { +/* Computing MIN */ + i__3 = *nh, i__4 = *n - kcol + 1; + kln = min(i__3,i__4); + zgemm_("C", "N", &jw, &kln, &jw, &c_b57, &v[v_offset], ldv, & + h__[kwtop + kcol * h_dim1], ldh, &c_b56, &t[t_offset], + ldt); + zlacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol * + h_dim1], ldh); +/* L70: */ + } + } + +/* ==== Update vertical slab in Z ==== */ + + if (*wantz) { + i__1 = *ihiz; + i__2 = *nv; + for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = *ihiz - krow + 1; + kln = min(i__3,i__4); + zgemm_("N", "N", &kln, &jw, &jw, &c_b57, &z__[krow + kwtop * + z_dim1], ldz, &v[v_offset], ldv, &c_b56, &wv[ + wv_offset], ldwv); + zlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + + kwtop * z_dim1], ldz); +/* L80: */ + } + } + } + +/* ==== Return the number of deflations ... ==== */ + + *nd = jw - *ns; + +/* + ==== ... and the number of shifts. (Subtracting + . INFQR from the spike length takes care + . of the case of a rare QR failure while + . calculating eigenvalues of the deflation + . window.) ==== +*/ + + *ns -= infqr; + +/* ==== Return optimal workspace. ==== */ + + d__1 = (doublereal) lwkopt; + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + +/* ==== End of ZLAQR2 ==== */ + + return 0; +} /* zlaqr2_ */ + +/* Subroutine */ int zlaqr3_(logical *wantt, logical *wantz, integer *n, + integer *ktop, integer *kbot, integer *nw, doublecomplex *h__, + integer *ldh, integer *iloz, integer *ihiz, doublecomplex *z__, + integer *ldz, integer *ns, integer *nd, doublecomplex *sh, + doublecomplex *v, integer *ldv, integer *nh, doublecomplex *t, + integer *ldt, integer *nv, doublecomplex *wv, integer *ldwv, + doublecomplex *work, integer *lwork) +{ + /* System generated locals */ + integer h_dim1, h_offset, t_dim1, t_offset, v_dim1, v_offset, wv_dim1, + wv_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2, d__3, d__4, d__5, d__6; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, j; + static doublecomplex s; + static integer jw; + static doublereal foo; + static integer kln; + static doublecomplex tau; + static integer knt; + static doublereal ulp; + static integer lwk1, lwk2, lwk3; + static doublecomplex beta; + static integer kcol, info, nmin, ifst, ilst, ltop, krow; + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *); + static integer infqr; + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer kwtop; + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), dlabad_(doublereal *, doublereal *), + zlaqr4_(logical *, logical *, integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, integer * + ); + + static doublereal safmin; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static doublereal safmax; + extern /* Subroutine */ int zgehrd_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *), zlarfg_(integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *), zlahqr_(logical *, + logical *, integer *, integer *, integer *, doublecomplex *, + integer *, doublecomplex *, integer *, integer *, doublecomplex *, + integer *, integer *), zlacpy_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *), + zlaset_(char *, integer *, integer *, doublecomplex *, + doublecomplex *, doublecomplex *, integer *); + static doublereal smlnum; + extern /* Subroutine */ int ztrexc_(char *, integer *, doublecomplex *, + integer *, doublecomplex *, integer *, integer *, integer *, + integer *); + static integer lwkopt; + extern /* Subroutine */ int zunmhr_(char *, char *, integer *, integer *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer * + ); + + +/* + -- LAPACK auxiliary routine (version 3.2.1) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + -- April 2009 -- + + + ****************************************************************** + Aggressive early deflation: + + This subroutine accepts as input an upper Hessenberg matrix + H and performs an unitary similarity transformation + designed to detect and deflate fully converged eigenvalues from + a trailing principal submatrix. On output H has been over- + written by a new Hessenberg matrix that is a perturbation of + an unitary similarity transformation of H. It is to be + hoped that the final version of H has many zero subdiagonal + entries. + + ****************************************************************** + WANTT (input) LOGICAL + If .TRUE., then the Hessenberg matrix H is fully updated + so that the triangular Schur factor may be + computed (in cooperation with the calling subroutine). + If .FALSE., then only enough of H is updated to preserve + the eigenvalues. + + WANTZ (input) LOGICAL + If .TRUE., then the unitary matrix Z is updated so + so that the unitary Schur factor may be computed + (in cooperation with the calling subroutine). + If .FALSE., then Z is not referenced. + + N (input) INTEGER + The order of the matrix H and (if WANTZ is .TRUE.) the + order of the unitary matrix Z. + + KTOP (input) INTEGER + It is assumed that either KTOP = 1 or H(KTOP,KTOP-1)=0. + KBOT and KTOP together determine an isolated block + along the diagonal of the Hessenberg matrix. + + KBOT (input) INTEGER + It is assumed without a check that either + KBOT = N or H(KBOT+1,KBOT)=0. KBOT and KTOP together + determine an isolated block along the diagonal of the + Hessenberg matrix. + + NW (input) INTEGER + Deflation window size. 1 .LE. NW .LE. (KBOT-KTOP+1). + + H (input/output) COMPLEX*16 array, dimension (LDH,N) + On input the initial N-by-N section of H stores the + Hessenberg matrix undergoing aggressive early deflation. + On output H has been transformed by a unitary + similarity transformation, perturbed, and the returned + to Hessenberg form that (it is to be hoped) has some + zero subdiagonal entries. + + LDH (input) integer + Leading dimension of H just as declared in the calling + subroutine. N .LE. LDH + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N. + + Z (input/output) COMPLEX*16 array, dimension (LDZ,N) + IF WANTZ is .TRUE., then on output, the unitary + similarity transformation mentioned above has been + accumulated into Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ is .FALSE., then Z is unreferenced. + + LDZ (input) integer + The leading dimension of Z just as declared in the + calling subroutine. 1 .LE. LDZ. + + NS (output) integer + The number of unconverged (ie approximate) eigenvalues + returned in SR and SI that may be used as shifts by the + calling subroutine. + + ND (output) integer + The number of converged eigenvalues uncovered by this + subroutine. + + SH (output) COMPLEX*16 array, dimension KBOT + On output, approximate eigenvalues that may + be used for shifts are stored in SH(KBOT-ND-NS+1) + through SR(KBOT-ND). Converged eigenvalues are + stored in SH(KBOT-ND+1) through SH(KBOT). + + V (workspace) COMPLEX*16 array, dimension (LDV,NW) + An NW-by-NW work array. + + LDV (input) integer scalar + The leading dimension of V just as declared in the + calling subroutine. NW .LE. LDV + + NH (input) integer scalar + The number of columns of T. NH.GE.NW. + + T (workspace) COMPLEX*16 array, dimension (LDT,NW) + + LDT (input) integer + The leading dimension of T just as declared in the + calling subroutine. NW .LE. LDT + + NV (input) integer + The number of rows of work array WV available for + workspace. NV.GE.NW. + + WV (workspace) COMPLEX*16 array, dimension (LDWV,NW) + + LDWV (input) integer + The leading dimension of W just as declared in the + calling subroutine. NW .LE. LDV + + WORK (workspace) COMPLEX*16 array, dimension LWORK. + On exit, WORK(1) is set to an estimate of the optimal value + of LWORK for the given values of N, NW, KTOP and KBOT. + + LWORK (input) integer + The dimension of the work array WORK. LWORK = 2*NW + suffices, but greater efficiency may result from larger + values of LWORK. + + If LWORK = -1, then a workspace query is assumed; ZLAQR3 + only estimates the optimal workspace size for the given + values of N, NW, KTOP and KBOT. The estimate is returned + in WORK(1). No error message related to LWORK is issued + by XERBLA. Neither H nor Z are accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + + ==== Estimate optimal workspace. ==== +*/ + + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --sh; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + --work; + + /* Function Body */ +/* Computing MIN */ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + if (jw <= 2) { + lwkopt = 1; + } else { + +/* ==== Workspace query call to ZGEHRD ==== */ + + i__1 = jw - 1; + zgehrd_(&jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], &work[1], & + c_n1, &info); + lwk1 = (integer) work[1].r; + +/* ==== Workspace query call to ZUNMHR ==== */ + + i__1 = jw - 1; + zunmhr_("R", "N", &jw, &jw, &c__1, &i__1, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[1], &c_n1, &info); + lwk2 = (integer) work[1].r; + +/* ==== Workspace query call to ZLAQR4 ==== */ + + zlaqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sh[1], + &c__1, &jw, &v[v_offset], ldv, &work[1], &c_n1, &infqr); + lwk3 = (integer) work[1].r; + +/* + ==== Optimal workspace ==== + + Computing MAX +*/ + i__1 = jw + max(lwk1,lwk2); + lwkopt = max(i__1,lwk3); + } + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + d__1 = (doublereal) lwkopt; + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + return 0; + } + +/* + ==== Nothing to do ... + ... for an empty active block ... ==== +*/ + *ns = 0; + *nd = 0; + work[1].r = 1., work[1].i = 0.; + if (*ktop > *kbot) { + return 0; + } +/* ... nor for an empty deflation window. ==== */ + if (*nw < 1) { + return 0; + } + +/* ==== Machine constants ==== */ + + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + dlabad_(&safmin, &safmax); + ulp = PRECISION; + smlnum = safmin * ((doublereal) (*n) / ulp); + +/* + ==== Setup deflation window ==== + + Computing MIN +*/ + i__1 = *nw, i__2 = *kbot - *ktop + 1; + jw = min(i__1,i__2); + kwtop = *kbot - jw + 1; + if (kwtop == *ktop) { + s.r = 0., s.i = 0.; + } else { + i__1 = kwtop + (kwtop - 1) * h_dim1; + s.r = h__[i__1].r, s.i = h__[i__1].i; + } + + if (*kbot == kwtop) { + +/* ==== 1-by-1 deflation window: not much to do ==== */ + + i__1 = kwtop; + i__2 = kwtop + kwtop * h_dim1; + sh[i__1].r = h__[i__2].r, sh[i__1].i = h__[i__2].i; + *ns = 1; + *nd = 0; +/* Computing MAX */ + i__1 = kwtop + kwtop * h_dim1; + d__5 = smlnum, d__6 = ulp * ((d__1 = h__[i__1].r, abs(d__1)) + (d__2 = + d_imag(&h__[kwtop + kwtop * h_dim1]), abs(d__2))); + if ((d__3 = s.r, abs(d__3)) + (d__4 = d_imag(&s), abs(d__4)) <= max( + d__5,d__6)) { + *ns = 0; + *nd = 1; + if (kwtop > *ktop) { + i__1 = kwtop + (kwtop - 1) * h_dim1; + h__[i__1].r = 0., h__[i__1].i = 0.; + } + } + work[1].r = 1., work[1].i = 0.; + return 0; + } + +/* + ==== Convert to spike-triangular form. (In case of a + . rare QR failure, this routine continues to do + . aggressive early deflation using that part of + . the deflation window that converged using INFQR + . here and there to keep track.) ==== +*/ + + zlacpy_("U", &jw, &jw, &h__[kwtop + kwtop * h_dim1], ldh, &t[t_offset], + ldt); + i__1 = jw - 1; + i__2 = *ldh + 1; + i__3 = *ldt + 1; + zcopy_(&i__1, &h__[kwtop + 1 + kwtop * h_dim1], &i__2, &t[t_dim1 + 2], & + i__3); + + zlaset_("A", &jw, &jw, &c_b56, &c_b57, &v[v_offset], ldv); + nmin = ilaenv_(&c__12, "ZLAQR3", "SV", &jw, &c__1, &jw, lwork, (ftnlen)6, + (ftnlen)2); + if (jw > nmin) { + zlaqr4_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sh[ + kwtop], &c__1, &jw, &v[v_offset], ldv, &work[1], lwork, & + infqr); + } else { + zlahqr_(&c_true, &c_true, &jw, &c__1, &jw, &t[t_offset], ldt, &sh[ + kwtop], &c__1, &jw, &v[v_offset], ldv, &infqr); + } + +/* ==== Deflation detection loop ==== */ + + *ns = jw; + ilst = infqr + 1; + i__1 = jw; + for (knt = infqr + 1; knt <= i__1; ++knt) { + +/* ==== Small spike tip deflation test ==== */ + + i__2 = *ns + *ns * t_dim1; + foo = (d__1 = t[i__2].r, abs(d__1)) + (d__2 = d_imag(&t[*ns + *ns * + t_dim1]), abs(d__2)); + if (foo == 0.) { + foo = (d__1 = s.r, abs(d__1)) + (d__2 = d_imag(&s), abs(d__2)); + } + i__2 = *ns * v_dim1 + 1; +/* Computing MAX */ + d__5 = smlnum, d__6 = ulp * foo; + if (((d__1 = s.r, abs(d__1)) + (d__2 = d_imag(&s), abs(d__2))) * (( + d__3 = v[i__2].r, abs(d__3)) + (d__4 = d_imag(&v[*ns * v_dim1 + + 1]), abs(d__4))) <= max(d__5,d__6)) { + +/* ==== One more converged eigenvalue ==== */ + + --(*ns); + } else { + +/* + ==== One undeflatable eigenvalue. Move it up out of the + . way. (ZTREXC can not fail in this case.) ==== +*/ + + ifst = *ns; + ztrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, & + ilst, &info); + ++ilst; + } +/* L10: */ + } + +/* ==== Return to Hessenberg form ==== */ + + if (*ns == 0) { + s.r = 0., s.i = 0.; + } + + if (*ns < jw) { + +/* + ==== sorting the diagonal of T improves accuracy for + . graded matrices. ==== +*/ + + i__1 = *ns; + for (i__ = infqr + 1; i__ <= i__1; ++i__) { + ifst = i__; + i__2 = *ns; + for (j = i__ + 1; j <= i__2; ++j) { + i__3 = j + j * t_dim1; + i__4 = ifst + ifst * t_dim1; + if ((d__1 = t[i__3].r, abs(d__1)) + (d__2 = d_imag(&t[j + j * + t_dim1]), abs(d__2)) > (d__3 = t[i__4].r, abs(d__3)) + + (d__4 = d_imag(&t[ifst + ifst * t_dim1]), abs(d__4)) + ) { + ifst = j; + } +/* L20: */ + } + ilst = i__; + if (ifst != ilst) { + ztrexc_("V", &jw, &t[t_offset], ldt, &v[v_offset], ldv, &ifst, + &ilst, &info); + } +/* L30: */ + } + } + +/* ==== Restore shift/eigenvalue array from T ==== */ + + i__1 = jw; + for (i__ = infqr + 1; i__ <= i__1; ++i__) { + i__2 = kwtop + i__ - 1; + i__3 = i__ + i__ * t_dim1; + sh[i__2].r = t[i__3].r, sh[i__2].i = t[i__3].i; +/* L40: */ + } + + + if (*ns < jw || s.r == 0. && s.i == 0.) { + if (*ns > 1 && (s.r != 0. || s.i != 0.)) { + +/* ==== Reflect spike back into lower triangle ==== */ + + zcopy_(ns, &v[v_offset], ldv, &work[1], &c__1); + i__1 = *ns; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + d_cnjg(&z__1, &work[i__]); + work[i__2].r = z__1.r, work[i__2].i = z__1.i; +/* L50: */ + } + beta.r = work[1].r, beta.i = work[1].i; + zlarfg_(ns, &beta, &work[2], &c__1, &tau); + work[1].r = 1., work[1].i = 0.; + + i__1 = jw - 2; + i__2 = jw - 2; + zlaset_("L", &i__1, &i__2, &c_b56, &c_b56, &t[t_dim1 + 3], ldt); + + d_cnjg(&z__1, &tau); + zlarf_("L", ns, &jw, &work[1], &c__1, &z__1, &t[t_offset], ldt, & + work[jw + 1]); + zlarf_("R", ns, ns, &work[1], &c__1, &tau, &t[t_offset], ldt, & + work[jw + 1]); + zlarf_("R", &jw, ns, &work[1], &c__1, &tau, &v[v_offset], ldv, & + work[jw + 1]); + + i__1 = *lwork - jw; + zgehrd_(&jw, &c__1, ns, &t[t_offset], ldt, &work[1], &work[jw + 1] + , &i__1, &info); + } + +/* ==== Copy updated reduced window into place ==== */ + + if (kwtop > 1) { + i__1 = kwtop + (kwtop - 1) * h_dim1; + d_cnjg(&z__2, &v[v_dim1 + 1]); + z__1.r = s.r * z__2.r - s.i * z__2.i, z__1.i = s.r * z__2.i + s.i + * z__2.r; + h__[i__1].r = z__1.r, h__[i__1].i = z__1.i; + } + zlacpy_("U", &jw, &jw, &t[t_offset], ldt, &h__[kwtop + kwtop * h_dim1] + , ldh); + i__1 = jw - 1; + i__2 = *ldt + 1; + i__3 = *ldh + 1; + zcopy_(&i__1, &t[t_dim1 + 2], &i__2, &h__[kwtop + 1 + kwtop * h_dim1], + &i__3); + +/* + ==== Accumulate orthogonal matrix in order update + . H and Z, if requested. ==== +*/ + + if (*ns > 1 && (s.r != 0. || s.i != 0.)) { + i__1 = *lwork - jw; + zunmhr_("R", "N", &jw, ns, &c__1, ns, &t[t_offset], ldt, &work[1], + &v[v_offset], ldv, &work[jw + 1], &i__1, &info); + } + +/* ==== Update vertical slab in H ==== */ + + if (*wantt) { + ltop = 1; + } else { + ltop = *ktop; + } + i__1 = kwtop - 1; + i__2 = *nv; + for (krow = ltop; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = kwtop - krow; + kln = min(i__3,i__4); + zgemm_("N", "N", &kln, &jw, &jw, &c_b57, &h__[krow + kwtop * + h_dim1], ldh, &v[v_offset], ldv, &c_b56, &wv[wv_offset], + ldwv); + zlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &h__[krow + kwtop * + h_dim1], ldh); +/* L60: */ + } + +/* ==== Update horizontal slab in H ==== */ + + if (*wantt) { + i__2 = *n; + i__1 = *nh; + for (kcol = *kbot + 1; i__1 < 0 ? kcol >= i__2 : kcol <= i__2; + kcol += i__1) { +/* Computing MIN */ + i__3 = *nh, i__4 = *n - kcol + 1; + kln = min(i__3,i__4); + zgemm_("C", "N", &jw, &kln, &jw, &c_b57, &v[v_offset], ldv, & + h__[kwtop + kcol * h_dim1], ldh, &c_b56, &t[t_offset], + ldt); + zlacpy_("A", &jw, &kln, &t[t_offset], ldt, &h__[kwtop + kcol * + h_dim1], ldh); +/* L70: */ + } + } + +/* ==== Update vertical slab in Z ==== */ + + if (*wantz) { + i__1 = *ihiz; + i__2 = *nv; + for (krow = *iloz; i__2 < 0 ? krow >= i__1 : krow <= i__1; krow += + i__2) { +/* Computing MIN */ + i__3 = *nv, i__4 = *ihiz - krow + 1; + kln = min(i__3,i__4); + zgemm_("N", "N", &kln, &jw, &jw, &c_b57, &z__[krow + kwtop * + z_dim1], ldz, &v[v_offset], ldv, &c_b56, &wv[ + wv_offset], ldwv); + zlacpy_("A", &kln, &jw, &wv[wv_offset], ldwv, &z__[krow + + kwtop * z_dim1], ldz); +/* L80: */ + } + } + } + +/* ==== Return the number of deflations ... ==== */ + + *nd = jw - *ns; + +/* + ==== ... and the number of shifts. (Subtracting + . INFQR from the spike length takes care + . of the case of a rare QR failure while + . calculating eigenvalues of the deflation + . window.) ==== +*/ + + *ns -= infqr; + +/* ==== Return optimal workspace. ==== */ + + d__1 = (doublereal) lwkopt; + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + +/* ==== End of ZLAQR3 ==== */ + + return 0; +} /* zlaqr3_ */ + +/* Subroutine */ int zlaqr4_(logical *wantt, logical *wantz, integer *n, + integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, + doublecomplex *w, integer *iloz, integer *ihiz, doublecomplex *z__, + integer *ldz, doublecomplex *work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer h_dim1, h_offset, z_dim1, z_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1, d__2, d__3, d__4, d__5, d__6, d__7, d__8; + doublecomplex z__1, z__2, z__3, z__4, z__5; + + /* Local variables */ + static integer i__, k; + static doublereal s; + static doublecomplex aa, bb, cc, dd; + static integer ld, nh, it, ks, kt, ku, kv, ls, ns, nw; + static doublecomplex tr2, det; + static integer inf, kdu, nho, nve, kwh, nsr, nwr, kwv, ndec, ndfl, kbot, + nmin; + static doublecomplex swap; + static integer ktop; + static doublecomplex zdum[1] /* was [1][1] */; + static integer kacc22, itmax, nsmax, nwmax, kwtop; + extern /* Subroutine */ int zlaqr2_(logical *, logical *, integer *, + integer *, integer *, integer *, doublecomplex *, integer *, + integer *, integer *, doublecomplex *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, integer *, + doublecomplex *, integer *, integer *, doublecomplex *, integer * + , doublecomplex *, integer *), zlaqr5_(logical *, logical *, + integer *, integer *, integer *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, integer *, doublecomplex *, integer *, + integer *, doublecomplex *, integer *); + static integer nibble; + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static char jbcmpz[2]; + static doublecomplex rtdisc; + static integer nwupbd; + static logical sorted; + extern /* Subroutine */ int zlahqr_(logical *, logical *, integer *, + integer *, integer *, doublecomplex *, integer *, doublecomplex *, + integer *, integer *, doublecomplex *, integer *, integer *), + zlacpy_(char *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static integer lwkopt; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + This subroutine implements one level of recursion for ZLAQR0. + It is a complete implementation of the small bulge multi-shift + QR algorithm. It may be called by ZLAQR0 and, for large enough + deflation window size, it may be called by ZLAQR3. This + subroutine is identical to ZLAQR0 except that it calls ZLAQR2 + instead of ZLAQR3. + + Purpose + ======= + + ZLAQR4 computes the eigenvalues of a Hessenberg matrix H + and, optionally, the matrices T and Z from the Schur decomposition + H = Z T Z**H, where T is an upper triangular matrix (the + Schur form), and Z is the unitary matrix of Schur vectors. + + Optionally Z may be postmultiplied into an input unitary + matrix Q so that this routine can give the Schur factorization + of a matrix A which has been reduced to the Hessenberg form H + by the unitary matrix Q: A = Q*H*Q**H = (QZ)*H*(QZ)**H. + + Arguments + ========= + + WANTT (input) LOGICAL + = .TRUE. : the full Schur form T is required; + = .FALSE.: only eigenvalues are required. + + WANTZ (input) LOGICAL + = .TRUE. : the matrix of Schur vectors Z is required; + = .FALSE.: Schur vectors are not required. + + N (input) INTEGER + The order of the matrix H. N .GE. 0. + + ILO (input) INTEGER + IHI (input) INTEGER + It is assumed that H is already upper triangular in rows + and columns 1:ILO-1 and IHI+1:N and, if ILO.GT.1, + H(ILO,ILO-1) is zero. ILO and IHI are normally set by a + previous call to ZGEBAL, and then passed to ZGEHRD when the + matrix output by ZGEBAL is reduced to Hessenberg form. + Otherwise, ILO and IHI should be set to 1 and N, + respectively. If N.GT.0, then 1.LE.ILO.LE.IHI.LE.N. + If N = 0, then ILO = 1 and IHI = 0. + + H (input/output) COMPLEX*16 array, dimension (LDH,N) + On entry, the upper Hessenberg matrix H. + On exit, if INFO = 0 and WANTT is .TRUE., then H + contains the upper triangular matrix T from the Schur + decomposition (the Schur form). If INFO = 0 and WANT is + .FALSE., then the contents of H are unspecified on exit. + (The output value of H when INFO.GT.0 is given under the + description of INFO below.) + + This subroutine may explicitly set H(i,j) = 0 for i.GT.j and + j = 1, 2, ... ILO-1 or j = IHI+1, IHI+2, ... N. + + LDH (input) INTEGER + The leading dimension of the array H. LDH .GE. max(1,N). + + W (output) COMPLEX*16 array, dimension (N) + The computed eigenvalues of H(ILO:IHI,ILO:IHI) are stored + in W(ILO:IHI). If WANTT is .TRUE., then the eigenvalues are + stored in the same order as on the diagonal of the Schur + form returned in H, with W(i) = H(i,i). + + Z (input/output) COMPLEX*16 array, dimension (LDZ,IHI) + If WANTZ is .FALSE., then Z is not referenced. + If WANTZ is .TRUE., then Z(ILO:IHI,ILOZ:IHIZ) is + replaced by Z(ILO:IHI,ILOZ:IHIZ)*U where U is the + orthogonal Schur factor of H(ILO:IHI,ILO:IHI). + (The output value of Z when INFO.GT.0 is given under + the description of INFO below.) + + LDZ (input) INTEGER + The leading dimension of the array Z. if WANTZ is .TRUE. + then LDZ.GE.MAX(1,IHIZ). Otherwize, LDZ.GE.1. + + WORK (workspace/output) COMPLEX*16 array, dimension LWORK + On exit, if LWORK = -1, WORK(1) returns an estimate of + the optimal value for LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK .GE. max(1,N) + is sufficient, but LWORK typically as large as 6*N may + be required for optimal performance. A workspace query + to determine the optimal workspace size is recommended. + + If LWORK = -1, then ZLAQR4 does a workspace query. + In this case, ZLAQR4 checks the input parameters and + estimates the optimal workspace size for the given + values of N, ILO and IHI. The estimate is returned + in WORK(1). No error message related to LWORK is + issued by XERBLA. Neither H nor Z are accessed. + + + INFO (output) INTEGER + = 0: successful exit + .GT. 0: if INFO = i, ZLAQR4 failed to compute all of + the eigenvalues. Elements 1:ilo-1 and i+1:n of WR + and WI contain those eigenvalues which have been + successfully computed. (Failures are rare.) + + If INFO .GT. 0 and WANT is .FALSE., then on exit, + the remaining unconverged eigenvalues are the eigen- + values of the upper Hessenberg matrix rows and + columns ILO through INFO of the final, output + value of H. + + If INFO .GT. 0 and WANTT is .TRUE., then on exit + + (*) (initial value of H)*U = U*(final value of H) + + where U is a unitary matrix. The final + value of H is upper Hessenberg and triangular in + rows and columns INFO+1 through IHI. + + If INFO .GT. 0 and WANTZ is .TRUE., then on exit + + (final value of Z(ILO:IHI,ILOZ:IHIZ) + = (initial value of Z(ILO:IHI,ILOZ:IHIZ)*U + + where U is the unitary matrix in (*) (regard- + less of the value of WANTT.) + + If INFO .GT. 0 and WANTZ is .FALSE., then Z is not + accessed. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + References: + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and Level 3 + Performance, SIAM Journal of Matrix Analysis, volume 23, pages + 929--947, 2002. + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part II: Aggressive Early Deflation, SIAM Journal + of Matrix Analysis, volume 23, pages 948--973, 2002. + + ================================================================ + + ==== Matrices of order NTINY or smaller must be processed by + . ZLAHQR because of insufficient subdiagonal scratch space. + . (This is a hard limit.) ==== + + ==== Exceptional deflation windows: try to cure rare + . slow convergence by varying the size of the + . deflation window after KEXNW iterations. ==== + + ==== Exceptional shifts: try to cure rare slow convergence + . with ad-hoc exceptional shifts every KEXSH iterations. + . ==== + + ==== The constant WILK1 is used to form the exceptional + . shifts. ==== +*/ + /* Parameter adjustments */ + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + --w; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + +/* ==== Quick return for N = 0: nothing to do. ==== */ + + if (*n == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + if (*n <= 11) { + +/* ==== Tiny matrices must use ZLAHQR. ==== */ + + lwkopt = 1; + if (*lwork != -1) { + zlahqr_(wantt, wantz, n, ilo, ihi, &h__[h_offset], ldh, &w[1], + iloz, ihiz, &z__[z_offset], ldz, info); + } + } else { + +/* + ==== Use small bulge multi-shift QR with aggressive early + . deflation on larger-than-tiny matrices. ==== + + ==== Hope for the best. ==== +*/ + + *info = 0; + +/* ==== Set up job flags for ILAENV. ==== */ + + if (*wantt) { + *(unsigned char *)jbcmpz = 'S'; + } else { + *(unsigned char *)jbcmpz = 'E'; + } + if (*wantz) { + *(unsigned char *)&jbcmpz[1] = 'V'; + } else { + *(unsigned char *)&jbcmpz[1] = 'N'; + } + +/* + ==== NWR = recommended deflation window size. At this + . point, N .GT. NTINY = 11, so there is enough + . subdiagonal workspace for NWR.GE.2 as required. + . (In fact, there is enough subdiagonal space for + . NWR.GE.3.) ==== +*/ + + nwr = ilaenv_(&c__13, "ZLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); + nwr = max(2,nwr); +/* Computing MIN */ + i__1 = *ihi - *ilo + 1, i__2 = (*n - 1) / 3, i__1 = min(i__1,i__2); + nwr = min(i__1,nwr); + +/* + ==== NSR = recommended number of simultaneous shifts. + . At this point N .GT. NTINY = 11, so there is at + . enough subdiagonal workspace for NSR to be even + . and greater than or equal to two as required. ==== +*/ + + nsr = ilaenv_(&c__15, "ZLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen)6, + (ftnlen)2); +/* Computing MIN */ + i__1 = nsr, i__2 = (*n + 6) / 9, i__1 = min(i__1,i__2), i__2 = *ihi - + *ilo; + nsr = min(i__1,i__2); +/* Computing MAX */ + i__1 = 2, i__2 = nsr - nsr % 2; + nsr = max(i__1,i__2); + +/* + ==== Estimate optimal workspace ==== + + ==== Workspace query call to ZLAQR2 ==== +*/ + + i__1 = nwr + 1; + zlaqr2_(wantt, wantz, n, ilo, ihi, &i__1, &h__[h_offset], ldh, iloz, + ihiz, &z__[z_offset], ldz, &ls, &ld, &w[1], &h__[h_offset], + ldh, n, &h__[h_offset], ldh, n, &h__[h_offset], ldh, &work[1], + &c_n1); + +/* + ==== Optimal workspace = MAX(ZLAQR5, ZLAQR2) ==== + + Computing MAX +*/ + i__1 = nsr * 3 / 2, i__2 = (integer) work[1].r; + lwkopt = max(i__1,i__2); + +/* ==== Quick return in case of workspace query. ==== */ + + if (*lwork == -1) { + d__1 = (doublereal) lwkopt; + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + return 0; + } + +/* ==== ZLAHQR/ZLAQR0 crossover point ==== */ + + nmin = ilaenv_(&c__12, "ZLAQR4", jbcmpz, n, ilo, ihi, lwork, (ftnlen) + 6, (ftnlen)2); + nmin = max(11,nmin); + +/* ==== Nibble crossover point ==== */ + + nibble = ilaenv_(&c__14, "ZLAQR4", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + nibble = max(0,nibble); + +/* + ==== Accumulate reflections during ttswp? Use block + . 2-by-2 structure during matrix-matrix multiply? ==== +*/ + + kacc22 = ilaenv_(&c__16, "ZLAQR4", jbcmpz, n, ilo, ihi, lwork, ( + ftnlen)6, (ftnlen)2); + kacc22 = max(0,kacc22); + kacc22 = min(2,kacc22); + +/* + ==== NWMAX = the largest possible deflation window for + . which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n - 1) / 3, i__2 = *lwork / 2; + nwmax = min(i__1,i__2); + nw = nwmax; + +/* + ==== NSMAX = the Largest number of simultaneous shifts + . for which there is sufficient workspace. ==== + + Computing MIN +*/ + i__1 = (*n + 6) / 9, i__2 = (*lwork << 1) / 3; + nsmax = min(i__1,i__2); + nsmax -= nsmax % 2; + +/* ==== NDFL: an iteration count restarted at deflation. ==== */ + + ndfl = 1; + +/* + ==== ITMAX = iteration limit ==== + + Computing MAX +*/ + i__1 = 10, i__2 = *ihi - *ilo + 1; + itmax = max(i__1,i__2) * 30; + +/* ==== Last row and column in the active block ==== */ + + kbot = *ihi; + +/* ==== Main Loop ==== */ + + i__1 = itmax; + for (it = 1; it <= i__1; ++it) { + +/* ==== Done when KBOT falls below ILO ==== */ + + if (kbot < *ilo) { + goto L80; + } + +/* ==== Locate active block ==== */ + + i__2 = *ilo + 1; + for (k = kbot; k >= i__2; --k) { + i__3 = k + (k - 1) * h_dim1; + if (h__[i__3].r == 0. && h__[i__3].i == 0.) { + goto L20; + } +/* L10: */ + } + k = *ilo; +L20: + ktop = k; + +/* + ==== Select deflation window size: + . Typical Case: + . If possible and advisable, nibble the entire + . active block. If not, use size MIN(NWR,NWMAX) + . or MIN(NWR+1,NWMAX) depending upon which has + . the smaller corresponding subdiagonal entry + . (a heuristic). + . + . Exceptional Case: + . If there have been no deflations in KEXNW or + . more iterations, then vary the deflation window + . size. At first, because, larger windows are, + . in general, more powerful than smaller ones, + . rapidly increase the window to the maximum possible. + . Then, gradually reduce the window size. ==== +*/ + + nh = kbot - ktop + 1; + nwupbd = min(nh,nwmax); + if (ndfl < 5) { + nw = min(nwupbd,nwr); + } else { +/* Computing MIN */ + i__2 = nwupbd, i__3 = nw << 1; + nw = min(i__2,i__3); + } + if (nw < nwmax) { + if (nw >= nh - 1) { + nw = nh; + } else { + kwtop = kbot - nw + 1; + i__2 = kwtop + (kwtop - 1) * h_dim1; + i__3 = kwtop - 1 + (kwtop - 2) * h_dim1; + if ((d__1 = h__[i__2].r, abs(d__1)) + (d__2 = d_imag(&h__[ + kwtop + (kwtop - 1) * h_dim1]), abs(d__2)) > ( + d__3 = h__[i__3].r, abs(d__3)) + (d__4 = d_imag(& + h__[kwtop - 1 + (kwtop - 2) * h_dim1]), abs(d__4)) + ) { + ++nw; + } + } + } + if (ndfl < 5) { + ndec = -1; + } else if (ndec >= 0 || nw >= nwupbd) { + ++ndec; + if (nw - ndec < 2) { + ndec = 0; + } + nw -= ndec; + } + +/* + ==== Aggressive early deflation: + . split workspace under the subdiagonal into + . - an nw-by-nw work array V in the lower + . left-hand-corner, + . - an NW-by-at-least-NW-but-more-is-better + . (NW-by-NHO) horizontal work array along + . the bottom edge, + . - an at-least-NW-but-more-is-better (NHV-by-NW) + . vertical work array along the left-hand-edge. + . ==== +*/ + + kv = *n - nw + 1; + kt = nw + 1; + nho = *n - nw - 1 - kt + 1; + kwv = nw + 2; + nve = *n - nw - kwv + 1; + +/* ==== Aggressive early deflation ==== */ + + zlaqr2_(wantt, wantz, n, &ktop, &kbot, &nw, &h__[h_offset], ldh, + iloz, ihiz, &z__[z_offset], ldz, &ls, &ld, &w[1], &h__[kv + + h_dim1], ldh, &nho, &h__[kv + kt * h_dim1], ldh, &nve, & + h__[kwv + h_dim1], ldh, &work[1], lwork); + +/* ==== Adjust KBOT accounting for new deflations. ==== */ + + kbot -= ld; + +/* ==== KS points to the shifts. ==== */ + + ks = kbot - ls + 1; + +/* + ==== Skip an expensive QR sweep if there is a (partly + . heuristic) reason to expect that many eigenvalues + . will deflate without it. Here, the QR sweep is + . skipped if many eigenvalues have just been deflated + . or if the remaining active block is small. +*/ + + if (ld == 0 || ld * 100 <= nw * nibble && kbot - ktop + 1 > min( + nmin,nwmax)) { + +/* + ==== NS = nominal number of simultaneous shifts. + . This may be lowered (slightly) if ZLAQR2 + . did not provide that many shifts. ==== + + Computing MIN + Computing MAX +*/ + i__4 = 2, i__5 = kbot - ktop; + i__2 = min(nsmax,nsr), i__3 = max(i__4,i__5); + ns = min(i__2,i__3); + ns -= ns % 2; + +/* + ==== If there have been no deflations + . in a multiple of KEXSH iterations, + . then try exceptional shifts. + . Otherwise use shifts provided by + . ZLAQR2 above or from the eigenvalues + . of a trailing principal submatrix. ==== +*/ + + if (ndfl % 6 == 0) { + ks = kbot - ns + 1; + i__2 = ks + 1; + for (i__ = kbot; i__ >= i__2; i__ += -2) { + i__3 = i__; + i__4 = i__ + i__ * h_dim1; + i__5 = i__ + (i__ - 1) * h_dim1; + d__3 = ((d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[i__ + (i__ - 1) * h_dim1]), abs( + d__2))) * .75; + z__1.r = h__[i__4].r + d__3, z__1.i = h__[i__4].i; + w[i__3].r = z__1.r, w[i__3].i = z__1.i; + i__3 = i__ - 1; + i__4 = i__; + w[i__3].r = w[i__4].r, w[i__3].i = w[i__4].i; +/* L30: */ + } + } else { + +/* + ==== Got NS/2 or fewer shifts? Use ZLAHQR + . on a trailing principal submatrix to + . get more. (Since NS.LE.NSMAX.LE.(N+6)/9, + . there is enough space below the subdiagonal + . to fit an NS-by-NS scratch array.) ==== +*/ + + if (kbot - ks + 1 <= ns / 2) { + ks = kbot - ns + 1; + kt = *n - ns + 1; + zlacpy_("A", &ns, &ns, &h__[ks + ks * h_dim1], ldh, & + h__[kt + h_dim1], ldh); + zlahqr_(&c_false, &c_false, &ns, &c__1, &ns, &h__[kt + + h_dim1], ldh, &w[ks], &c__1, &c__1, zdum, & + c__1, &inf); + ks += inf; + +/* + ==== In case of a rare QR failure use + . eigenvalues of the trailing 2-by-2 + . principal submatrix. Scale to avoid + . overflows, underflows and subnormals. + . (The scale factor S can not be zero, + . because H(KBOT,KBOT-1) is nonzero.) ==== +*/ + + if (ks >= kbot) { + i__2 = kbot - 1 + (kbot - 1) * h_dim1; + i__3 = kbot + (kbot - 1) * h_dim1; + i__4 = kbot - 1 + kbot * h_dim1; + i__5 = kbot + kbot * h_dim1; + s = (d__1 = h__[i__2].r, abs(d__1)) + (d__2 = + d_imag(&h__[kbot - 1 + (kbot - 1) * + h_dim1]), abs(d__2)) + ((d__3 = h__[i__3] + .r, abs(d__3)) + (d__4 = d_imag(&h__[kbot + + (kbot - 1) * h_dim1]), abs(d__4))) + (( + d__5 = h__[i__4].r, abs(d__5)) + (d__6 = + d_imag(&h__[kbot - 1 + kbot * h_dim1]), + abs(d__6))) + ((d__7 = h__[i__5].r, abs( + d__7)) + (d__8 = d_imag(&h__[kbot + kbot * + h_dim1]), abs(d__8))); + i__2 = kbot - 1 + (kbot - 1) * h_dim1; + z__1.r = h__[i__2].r / s, z__1.i = h__[i__2].i / + s; + aa.r = z__1.r, aa.i = z__1.i; + i__2 = kbot + (kbot - 1) * h_dim1; + z__1.r = h__[i__2].r / s, z__1.i = h__[i__2].i / + s; + cc.r = z__1.r, cc.i = z__1.i; + i__2 = kbot - 1 + kbot * h_dim1; + z__1.r = h__[i__2].r / s, z__1.i = h__[i__2].i / + s; + bb.r = z__1.r, bb.i = z__1.i; + i__2 = kbot + kbot * h_dim1; + z__1.r = h__[i__2].r / s, z__1.i = h__[i__2].i / + s; + dd.r = z__1.r, dd.i = z__1.i; + z__2.r = aa.r + dd.r, z__2.i = aa.i + dd.i; + z__1.r = z__2.r / 2., z__1.i = z__2.i / 2.; + tr2.r = z__1.r, tr2.i = z__1.i; + z__3.r = aa.r - tr2.r, z__3.i = aa.i - tr2.i; + z__4.r = dd.r - tr2.r, z__4.i = dd.i - tr2.i; + z__2.r = z__3.r * z__4.r - z__3.i * z__4.i, + z__2.i = z__3.r * z__4.i + z__3.i * + z__4.r; + z__5.r = bb.r * cc.r - bb.i * cc.i, z__5.i = bb.r + * cc.i + bb.i * cc.r; + z__1.r = z__2.r - z__5.r, z__1.i = z__2.i - + z__5.i; + det.r = z__1.r, det.i = z__1.i; + z__2.r = -det.r, z__2.i = -det.i; + z_sqrt(&z__1, &z__2); + rtdisc.r = z__1.r, rtdisc.i = z__1.i; + i__2 = kbot - 1; + z__2.r = tr2.r + rtdisc.r, z__2.i = tr2.i + + rtdisc.i; + z__1.r = s * z__2.r, z__1.i = s * z__2.i; + w[i__2].r = z__1.r, w[i__2].i = z__1.i; + i__2 = kbot; + z__2.r = tr2.r - rtdisc.r, z__2.i = tr2.i - + rtdisc.i; + z__1.r = s * z__2.r, z__1.i = s * z__2.i; + w[i__2].r = z__1.r, w[i__2].i = z__1.i; + + ks = kbot - 1; + } + } + + if (kbot - ks + 1 > ns) { + +/* ==== Sort the shifts (Helps a little) ==== */ + + sorted = FALSE_; + i__2 = ks + 1; + for (k = kbot; k >= i__2; --k) { + if (sorted) { + goto L60; + } + sorted = TRUE_; + i__3 = k - 1; + for (i__ = ks; i__ <= i__3; ++i__) { + i__4 = i__; + i__5 = i__ + 1; + if ((d__1 = w[i__4].r, abs(d__1)) + (d__2 = + d_imag(&w[i__]), abs(d__2)) < (d__3 = + w[i__5].r, abs(d__3)) + (d__4 = + d_imag(&w[i__ + 1]), abs(d__4))) { + sorted = FALSE_; + i__4 = i__; + swap.r = w[i__4].r, swap.i = w[i__4].i; + i__4 = i__; + i__5 = i__ + 1; + w[i__4].r = w[i__5].r, w[i__4].i = w[i__5] + .i; + i__4 = i__ + 1; + w[i__4].r = swap.r, w[i__4].i = swap.i; + } +/* L40: */ + } +/* L50: */ + } +L60: + ; + } + } + +/* + ==== If there are only two shifts, then use + . only one. ==== +*/ + + if (kbot - ks + 1 == 2) { + i__2 = kbot; + i__3 = kbot + kbot * h_dim1; + z__2.r = w[i__2].r - h__[i__3].r, z__2.i = w[i__2].i - + h__[i__3].i; + z__1.r = z__2.r, z__1.i = z__2.i; + i__4 = kbot - 1; + i__5 = kbot + kbot * h_dim1; + z__4.r = w[i__4].r - h__[i__5].r, z__4.i = w[i__4].i - + h__[i__5].i; + z__3.r = z__4.r, z__3.i = z__4.i; + if ((d__1 = z__1.r, abs(d__1)) + (d__2 = d_imag(&z__1), + abs(d__2)) < (d__3 = z__3.r, abs(d__3)) + (d__4 = + d_imag(&z__3), abs(d__4))) { + i__2 = kbot - 1; + i__3 = kbot; + w[i__2].r = w[i__3].r, w[i__2].i = w[i__3].i; + } else { + i__2 = kbot; + i__3 = kbot - 1; + w[i__2].r = w[i__3].r, w[i__2].i = w[i__3].i; + } + } + +/* + ==== Use up to NS of the the smallest magnatiude + . shifts. If there aren't NS shifts available, + . then use them all, possibly dropping one to + . make the number of shifts even. ==== + + Computing MIN +*/ + i__2 = ns, i__3 = kbot - ks + 1; + ns = min(i__2,i__3); + ns -= ns % 2; + ks = kbot - ns + 1; + +/* + ==== Small-bulge multi-shift QR sweep: + . split workspace under the subdiagonal into + . - a KDU-by-KDU work array U in the lower + . left-hand-corner, + . - a KDU-by-at-least-KDU-but-more-is-better + . (KDU-by-NHo) horizontal work array WH along + . the bottom edge, + . - and an at-least-KDU-but-more-is-better-by-KDU + . (NVE-by-KDU) vertical work WV arrow along + . the left-hand-edge. ==== +*/ + + kdu = ns * 3 - 3; + ku = *n - kdu + 1; + kwh = kdu + 1; + nho = *n - kdu - 3 - (kdu + 1) + 1; + kwv = kdu + 4; + nve = *n - kdu - kwv + 1; + +/* ==== Small-bulge multi-shift QR sweep ==== */ + + zlaqr5_(wantt, wantz, &kacc22, n, &ktop, &kbot, &ns, &w[ks], & + h__[h_offset], ldh, iloz, ihiz, &z__[z_offset], ldz, & + work[1], &c__3, &h__[ku + h_dim1], ldh, &nve, &h__[ + kwv + h_dim1], ldh, &nho, &h__[ku + kwh * h_dim1], + ldh); + } + +/* ==== Note progress (or the lack of it). ==== */ + + if (ld > 0) { + ndfl = 1; + } else { + ++ndfl; + } + +/* + ==== End of main loop ==== + L70: +*/ + } + +/* + ==== Iteration limit exceeded. Set INFO to show where + . the problem occurred and exit. ==== +*/ + + *info = kbot; +L80: + ; + } + +/* ==== Return the optimal value of LWORK. ==== */ + + d__1 = (doublereal) lwkopt; + z__1.r = d__1, z__1.i = 0.; + work[1].r = z__1.r, work[1].i = z__1.i; + +/* ==== End of ZLAQR4 ==== */ + + return 0; +} /* zlaqr4_ */ + +/* Subroutine */ int zlaqr5_(logical *wantt, logical *wantz, integer *kacc22, + integer *n, integer *ktop, integer *kbot, integer *nshfts, + doublecomplex *s, doublecomplex *h__, integer *ldh, integer *iloz, + integer *ihiz, doublecomplex *z__, integer *ldz, doublecomplex *v, + integer *ldv, doublecomplex *u, integer *ldu, integer *nv, + doublecomplex *wv, integer *ldwv, integer *nh, doublecomplex *wh, + integer *ldwh) +{ + /* System generated locals */ + integer h_dim1, h_offset, u_dim1, u_offset, v_dim1, v_offset, wh_dim1, + wh_offset, wv_dim1, wv_offset, z_dim1, z_offset, i__1, i__2, i__3, + i__4, i__5, i__6, i__7, i__8, i__9, i__10, i__11; + doublereal d__1, d__2, d__3, d__4, d__5, d__6, d__7, d__8, d__9, d__10; + doublecomplex z__1, z__2, z__3, z__4, z__5, z__6, z__7, z__8; + + /* Local variables */ + static integer j, k, m, i2, j2, i4, j4, k1; + static doublereal h11, h12, h21, h22; + static integer m22, ns, nu; + static doublecomplex vt[3]; + static doublereal scl; + static integer kdu, kms; + static doublereal ulp; + static integer knz, kzs; + static doublereal tst1, tst2; + static doublecomplex beta; + static logical blk22, bmp22; + static integer mend, jcol, jlen, jbot, mbot, jtop, jrow, mtop; + static doublecomplex alpha; + static logical accum; + static integer ndcol, incol, krcol, nbmps; + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), ztrmm_(char *, char *, char *, char *, + integer *, integer *, doublecomplex *, doublecomplex *, integer * + , doublecomplex *, integer *), + dlabad_(doublereal *, doublereal *), zlaqr1_(integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + doublecomplex *); + + static doublereal safmin, safmax; + extern /* Subroutine */ int zlarfg_(integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *); + static doublecomplex refsum; + extern /* Subroutine */ int zlacpy_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *), + zlaset_(char *, integer *, integer *, doublecomplex *, + doublecomplex *, doublecomplex *, integer *); + static integer mstart; + static doublereal smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + Univ. of Tennessee, Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.. + November 2006 + + + This auxiliary subroutine called by ZLAQR0 performs a + single small-bulge multi-shift QR sweep. + + WANTT (input) logical scalar + WANTT = .true. if the triangular Schur factor + is being computed. WANTT is set to .false. otherwise. + + WANTZ (input) logical scalar + WANTZ = .true. if the unitary Schur factor is being + computed. WANTZ is set to .false. otherwise. + + KACC22 (input) integer with value 0, 1, or 2. + Specifies the computation mode of far-from-diagonal + orthogonal updates. + = 0: ZLAQR5 does not accumulate reflections and does not + use matrix-matrix multiply to update far-from-diagonal + matrix entries. + = 1: ZLAQR5 accumulates reflections and uses matrix-matrix + multiply to update the far-from-diagonal matrix entries. + = 2: ZLAQR5 accumulates reflections, uses matrix-matrix + multiply to update the far-from-diagonal matrix entries, + and takes advantage of 2-by-2 block structure during + matrix multiplies. + + N (input) integer scalar + N is the order of the Hessenberg matrix H upon which this + subroutine operates. + + KTOP (input) integer scalar + KBOT (input) integer scalar + These are the first and last rows and columns of an + isolated diagonal block upon which the QR sweep is to be + applied. It is assumed without a check that + either KTOP = 1 or H(KTOP,KTOP-1) = 0 + and + either KBOT = N or H(KBOT+1,KBOT) = 0. + + NSHFTS (input) integer scalar + NSHFTS gives the number of simultaneous shifts. NSHFTS + must be positive and even. + + S (input/output) COMPLEX*16 array of size (NSHFTS) + S contains the shifts of origin that define the multi- + shift QR sweep. On output S may be reordered. + + H (input/output) COMPLEX*16 array of size (LDH,N) + On input H contains a Hessenberg matrix. On output a + multi-shift QR sweep with shifts SR(J)+i*SI(J) is applied + to the isolated diagonal block in rows and columns KTOP + through KBOT. + + LDH (input) integer scalar + LDH is the leading dimension of H just as declared in the + calling procedure. LDH.GE.MAX(1,N). + + ILOZ (input) INTEGER + IHIZ (input) INTEGER + Specify the rows of Z to which transformations must be + applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N + + Z (input/output) COMPLEX*16 array of size (LDZ,IHI) + If WANTZ = .TRUE., then the QR Sweep unitary + similarity transformation is accumulated into + Z(ILOZ:IHIZ,ILO:IHI) from the right. + If WANTZ = .FALSE., then Z is unreferenced. + + LDZ (input) integer scalar + LDA is the leading dimension of Z just as declared in + the calling procedure. LDZ.GE.N. + + V (workspace) COMPLEX*16 array of size (LDV,NSHFTS/2) + + LDV (input) integer scalar + LDV is the leading dimension of V as declared in the + calling procedure. LDV.GE.3. + + U (workspace) COMPLEX*16 array of size + (LDU,3*NSHFTS-3) + + LDU (input) integer scalar + LDU is the leading dimension of U just as declared in the + in the calling subroutine. LDU.GE.3*NSHFTS-3. + + NH (input) integer scalar + NH is the number of columns in array WH available for + workspace. NH.GE.1. + + WH (workspace) COMPLEX*16 array of size (LDWH,NH) + + LDWH (input) integer scalar + Leading dimension of WH just as declared in the + calling procedure. LDWH.GE.3*NSHFTS-3. + + NV (input) integer scalar + NV is the number of rows in WV agailable for workspace. + NV.GE.1. + + WV (workspace) COMPLEX*16 array of size + (LDWV,3*NSHFTS-3) + + LDWV (input) integer scalar + LDWV is the leading dimension of WV as declared in the + in the calling subroutine. LDWV.GE.NV. + + ================================================================ + Based on contributions by + Karen Braman and Ralph Byers, Department of Mathematics, + University of Kansas, USA + + ================================================================ + Reference: + + K. Braman, R. Byers and R. Mathias, The Multi-Shift QR + Algorithm Part I: Maintaining Well Focused Shifts, and + Level 3 Performance, SIAM Journal of Matrix Analysis, + volume 23, pages 929--947, 2002. + + ================================================================ + + + ==== If there are no shifts, then there is nothing to do. ==== +*/ + + /* Parameter adjustments */ + --s; + h_dim1 = *ldh; + h_offset = 1 + h_dim1; + h__ -= h_offset; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + u_dim1 = *ldu; + u_offset = 1 + u_dim1; + u -= u_offset; + wv_dim1 = *ldwv; + wv_offset = 1 + wv_dim1; + wv -= wv_offset; + wh_dim1 = *ldwh; + wh_offset = 1 + wh_dim1; + wh -= wh_offset; + + /* Function Body */ + if (*nshfts < 2) { + return 0; + } + +/* + ==== If the active block is empty or 1-by-1, then there + . is nothing to do. ==== +*/ + + if (*ktop >= *kbot) { + return 0; + } + +/* + ==== NSHFTS is supposed to be even, but if it is odd, + . then simply reduce it by one. ==== +*/ + + ns = *nshfts - *nshfts % 2; + +/* ==== Machine constants for deflation ==== */ + + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + dlabad_(&safmin, &safmax); + ulp = PRECISION; + smlnum = safmin * ((doublereal) (*n) / ulp); + +/* + ==== Use accumulated reflections to update far-from-diagonal + . entries ? ==== +*/ + + accum = *kacc22 == 1 || *kacc22 == 2; + +/* ==== If so, exploit the 2-by-2 block structure? ==== */ + + blk22 = ns > 2 && *kacc22 == 2; + +/* ==== clear trash ==== */ + + if (*ktop + 2 <= *kbot) { + i__1 = *ktop + 2 + *ktop * h_dim1; + h__[i__1].r = 0., h__[i__1].i = 0.; + } + +/* ==== NBMPS = number of 2-shift bulges in the chain ==== */ + + nbmps = ns / 2; + +/* ==== KDU = width of slab ==== */ + + kdu = nbmps * 6 - 3; + +/* ==== Create and chase chains of NBMPS bulges ==== */ + + i__1 = *kbot - 2; + i__2 = nbmps * 3 - 2; + for (incol = (1 - nbmps) * 3 + *ktop - 1; i__2 < 0 ? incol >= i__1 : + incol <= i__1; incol += i__2) { + ndcol = incol + kdu; + if (accum) { + zlaset_("ALL", &kdu, &kdu, &c_b56, &c_b57, &u[u_offset], ldu); + } + +/* + ==== Near-the-diagonal bulge chase. The following loop + . performs the near-the-diagonal part of a small bulge + . multi-shift QR sweep. Each 6*NBMPS-2 column diagonal + . chunk extends from column INCOL to column NDCOL + . (including both column INCOL and column NDCOL). The + . following loop chases a 3*NBMPS column long chain of + . NBMPS bulges 3*NBMPS-2 columns to the right. (INCOL + . may be less than KTOP and and NDCOL may be greater than + . KBOT indicating phantom columns from which to chase + . bulges before they are actually introduced or to which + . to chase bulges beyond column KBOT.) ==== + + Computing MIN +*/ + i__4 = incol + nbmps * 3 - 3, i__5 = *kbot - 2; + i__3 = min(i__4,i__5); + for (krcol = incol; krcol <= i__3; ++krcol) { + +/* + ==== Bulges number MTOP to MBOT are active double implicit + . shift bulges. There may or may not also be small + . 2-by-2 bulge, if there is room. The inactive bulges + . (if any) must wait until the active bulges have moved + . down the diagonal to make room. The phantom matrix + . paradigm described above helps keep track. ==== + + Computing MAX +*/ + i__4 = 1, i__5 = (*ktop - 1 - krcol + 2) / 3 + 1; + mtop = max(i__4,i__5); +/* Computing MIN */ + i__4 = nbmps, i__5 = (*kbot - krcol) / 3; + mbot = min(i__4,i__5); + m22 = mbot + 1; + bmp22 = mbot < nbmps && krcol + (m22 - 1) * 3 == *kbot - 2; + +/* + ==== Generate reflections to chase the chain right + . one column. (The minimum value of K is KTOP-1.) ==== +*/ + + i__4 = mbot; + for (m = mtop; m <= i__4; ++m) { + k = krcol + (m - 1) * 3; + if (k == *ktop - 1) { + zlaqr1_(&c__3, &h__[*ktop + *ktop * h_dim1], ldh, &s[(m << + 1) - 1], &s[m * 2], &v[m * v_dim1 + 1]); + i__5 = m * v_dim1 + 1; + alpha.r = v[i__5].r, alpha.i = v[i__5].i; + zlarfg_(&c__3, &alpha, &v[m * v_dim1 + 2], &c__1, &v[m * + v_dim1 + 1]); + } else { + i__5 = k + 1 + k * h_dim1; + beta.r = h__[i__5].r, beta.i = h__[i__5].i; + i__5 = m * v_dim1 + 2; + i__6 = k + 2 + k * h_dim1; + v[i__5].r = h__[i__6].r, v[i__5].i = h__[i__6].i; + i__5 = m * v_dim1 + 3; + i__6 = k + 3 + k * h_dim1; + v[i__5].r = h__[i__6].r, v[i__5].i = h__[i__6].i; + zlarfg_(&c__3, &beta, &v[m * v_dim1 + 2], &c__1, &v[m * + v_dim1 + 1]); + +/* + ==== A Bulge may collapse because of vigilant + . deflation or destructive underflow. In the + . underflow case, try the two-small-subdiagonals + . trick to try to reinflate the bulge. ==== +*/ + + i__5 = k + 3 + k * h_dim1; + i__6 = k + 3 + (k + 1) * h_dim1; + i__7 = k + 3 + (k + 2) * h_dim1; + if (h__[i__5].r != 0. || h__[i__5].i != 0. || (h__[i__6] + .r != 0. || h__[i__6].i != 0.) || h__[i__7].r == + 0. && h__[i__7].i == 0.) { + +/* ==== Typical case: not collapsed (yet). ==== */ + + i__5 = k + 1 + k * h_dim1; + h__[i__5].r = beta.r, h__[i__5].i = beta.i; + i__5 = k + 2 + k * h_dim1; + h__[i__5].r = 0., h__[i__5].i = 0.; + i__5 = k + 3 + k * h_dim1; + h__[i__5].r = 0., h__[i__5].i = 0.; + } else { + +/* + ==== Atypical case: collapsed. Attempt to + . reintroduce ignoring H(K+1,K) and H(K+2,K). + . If the fill resulting from the new + . reflector is too large, then abandon it. + . Otherwise, use the new one. ==== +*/ + + zlaqr1_(&c__3, &h__[k + 1 + (k + 1) * h_dim1], ldh, & + s[(m << 1) - 1], &s[m * 2], vt); + alpha.r = vt[0].r, alpha.i = vt[0].i; + zlarfg_(&c__3, &alpha, &vt[1], &c__1, vt); + d_cnjg(&z__2, vt); + i__5 = k + 1 + k * h_dim1; + d_cnjg(&z__5, &vt[1]); + i__6 = k + 2 + k * h_dim1; + z__4.r = z__5.r * h__[i__6].r - z__5.i * h__[i__6].i, + z__4.i = z__5.r * h__[i__6].i + z__5.i * h__[ + i__6].r; + z__3.r = h__[i__5].r + z__4.r, z__3.i = h__[i__5].i + + z__4.i; + z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, z__1.i = + z__2.r * z__3.i + z__2.i * z__3.r; + refsum.r = z__1.r, refsum.i = z__1.i; + + i__5 = k + 2 + k * h_dim1; + z__3.r = refsum.r * vt[1].r - refsum.i * vt[1].i, + z__3.i = refsum.r * vt[1].i + refsum.i * vt[1] + .r; + z__2.r = h__[i__5].r - z__3.r, z__2.i = h__[i__5].i - + z__3.i; + z__1.r = z__2.r, z__1.i = z__2.i; + z__5.r = refsum.r * vt[2].r - refsum.i * vt[2].i, + z__5.i = refsum.r * vt[2].i + refsum.i * vt[2] + .r; + z__4.r = z__5.r, z__4.i = z__5.i; + i__6 = k + k * h_dim1; + i__7 = k + 1 + (k + 1) * h_dim1; + i__8 = k + 2 + (k + 2) * h_dim1; + if ((d__1 = z__1.r, abs(d__1)) + (d__2 = d_imag(&z__1) + , abs(d__2)) + ((d__3 = z__4.r, abs(d__3)) + ( + d__4 = d_imag(&z__4), abs(d__4))) > ulp * (( + d__5 = h__[i__6].r, abs(d__5)) + (d__6 = + d_imag(&h__[k + k * h_dim1]), abs(d__6)) + (( + d__7 = h__[i__7].r, abs(d__7)) + (d__8 = + d_imag(&h__[k + 1 + (k + 1) * h_dim1]), abs( + d__8))) + ((d__9 = h__[i__8].r, abs(d__9)) + ( + d__10 = d_imag(&h__[k + 2 + (k + 2) * h_dim1]) + , abs(d__10))))) { + +/* + ==== Starting a new bulge here would + . create non-negligible fill. Use + . the old one with trepidation. ==== +*/ + + i__5 = k + 1 + k * h_dim1; + h__[i__5].r = beta.r, h__[i__5].i = beta.i; + i__5 = k + 2 + k * h_dim1; + h__[i__5].r = 0., h__[i__5].i = 0.; + i__5 = k + 3 + k * h_dim1; + h__[i__5].r = 0., h__[i__5].i = 0.; + } else { + +/* + ==== Stating a new bulge here would + . create only negligible fill. + . Replace the old reflector with + . the new one. ==== +*/ + + i__5 = k + 1 + k * h_dim1; + i__6 = k + 1 + k * h_dim1; + z__1.r = h__[i__6].r - refsum.r, z__1.i = h__[ + i__6].i - refsum.i; + h__[i__5].r = z__1.r, h__[i__5].i = z__1.i; + i__5 = k + 2 + k * h_dim1; + h__[i__5].r = 0., h__[i__5].i = 0.; + i__5 = k + 3 + k * h_dim1; + h__[i__5].r = 0., h__[i__5].i = 0.; + i__5 = m * v_dim1 + 1; + v[i__5].r = vt[0].r, v[i__5].i = vt[0].i; + i__5 = m * v_dim1 + 2; + v[i__5].r = vt[1].r, v[i__5].i = vt[1].i; + i__5 = m * v_dim1 + 3; + v[i__5].r = vt[2].r, v[i__5].i = vt[2].i; + } + } + } +/* L10: */ + } + +/* ==== Generate a 2-by-2 reflection, if needed. ==== */ + + k = krcol + (m22 - 1) * 3; + if (bmp22) { + if (k == *ktop - 1) { + zlaqr1_(&c__2, &h__[k + 1 + (k + 1) * h_dim1], ldh, &s[( + m22 << 1) - 1], &s[m22 * 2], &v[m22 * v_dim1 + 1]) + ; + i__4 = m22 * v_dim1 + 1; + beta.r = v[i__4].r, beta.i = v[i__4].i; + zlarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 + * v_dim1 + 1]); + } else { + i__4 = k + 1 + k * h_dim1; + beta.r = h__[i__4].r, beta.i = h__[i__4].i; + i__4 = m22 * v_dim1 + 2; + i__5 = k + 2 + k * h_dim1; + v[i__4].r = h__[i__5].r, v[i__4].i = h__[i__5].i; + zlarfg_(&c__2, &beta, &v[m22 * v_dim1 + 2], &c__1, &v[m22 + * v_dim1 + 1]); + i__4 = k + 1 + k * h_dim1; + h__[i__4].r = beta.r, h__[i__4].i = beta.i; + i__4 = k + 2 + k * h_dim1; + h__[i__4].r = 0., h__[i__4].i = 0.; + } + } + +/* ==== Multiply H by reflections from the left ==== */ + + if (accum) { + jbot = min(ndcol,*kbot); + } else if (*wantt) { + jbot = *n; + } else { + jbot = *kbot; + } + i__4 = jbot; + for (j = max(*ktop,krcol); j <= i__4; ++j) { +/* Computing MIN */ + i__5 = mbot, i__6 = (j - krcol + 2) / 3; + mend = min(i__5,i__6); + i__5 = mend; + for (m = mtop; m <= i__5; ++m) { + k = krcol + (m - 1) * 3; + d_cnjg(&z__2, &v[m * v_dim1 + 1]); + i__6 = k + 1 + j * h_dim1; + d_cnjg(&z__6, &v[m * v_dim1 + 2]); + i__7 = k + 2 + j * h_dim1; + z__5.r = z__6.r * h__[i__7].r - z__6.i * h__[i__7].i, + z__5.i = z__6.r * h__[i__7].i + z__6.i * h__[i__7] + .r; + z__4.r = h__[i__6].r + z__5.r, z__4.i = h__[i__6].i + + z__5.i; + d_cnjg(&z__8, &v[m * v_dim1 + 3]); + i__8 = k + 3 + j * h_dim1; + z__7.r = z__8.r * h__[i__8].r - z__8.i * h__[i__8].i, + z__7.i = z__8.r * h__[i__8].i + z__8.i * h__[i__8] + .r; + z__3.r = z__4.r + z__7.r, z__3.i = z__4.i + z__7.i; + z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, z__1.i = + z__2.r * z__3.i + z__2.i * z__3.r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__6 = k + 1 + j * h_dim1; + i__7 = k + 1 + j * h_dim1; + z__1.r = h__[i__7].r - refsum.r, z__1.i = h__[i__7].i - + refsum.i; + h__[i__6].r = z__1.r, h__[i__6].i = z__1.i; + i__6 = k + 2 + j * h_dim1; + i__7 = k + 2 + j * h_dim1; + i__8 = m * v_dim1 + 2; + z__2.r = refsum.r * v[i__8].r - refsum.i * v[i__8].i, + z__2.i = refsum.r * v[i__8].i + refsum.i * v[i__8] + .r; + z__1.r = h__[i__7].r - z__2.r, z__1.i = h__[i__7].i - + z__2.i; + h__[i__6].r = z__1.r, h__[i__6].i = z__1.i; + i__6 = k + 3 + j * h_dim1; + i__7 = k + 3 + j * h_dim1; + i__8 = m * v_dim1 + 3; + z__2.r = refsum.r * v[i__8].r - refsum.i * v[i__8].i, + z__2.i = refsum.r * v[i__8].i + refsum.i * v[i__8] + .r; + z__1.r = h__[i__7].r - z__2.r, z__1.i = h__[i__7].i - + z__2.i; + h__[i__6].r = z__1.r, h__[i__6].i = z__1.i; +/* L20: */ + } +/* L30: */ + } + if (bmp22) { + k = krcol + (m22 - 1) * 3; +/* Computing MAX */ + i__4 = k + 1; + i__5 = jbot; + for (j = max(i__4,*ktop); j <= i__5; ++j) { + d_cnjg(&z__2, &v[m22 * v_dim1 + 1]); + i__4 = k + 1 + j * h_dim1; + d_cnjg(&z__5, &v[m22 * v_dim1 + 2]); + i__6 = k + 2 + j * h_dim1; + z__4.r = z__5.r * h__[i__6].r - z__5.i * h__[i__6].i, + z__4.i = z__5.r * h__[i__6].i + z__5.i * h__[i__6] + .r; + z__3.r = h__[i__4].r + z__4.r, z__3.i = h__[i__4].i + + z__4.i; + z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, z__1.i = + z__2.r * z__3.i + z__2.i * z__3.r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__4 = k + 1 + j * h_dim1; + i__6 = k + 1 + j * h_dim1; + z__1.r = h__[i__6].r - refsum.r, z__1.i = h__[i__6].i - + refsum.i; + h__[i__4].r = z__1.r, h__[i__4].i = z__1.i; + i__4 = k + 2 + j * h_dim1; + i__6 = k + 2 + j * h_dim1; + i__7 = m22 * v_dim1 + 2; + z__2.r = refsum.r * v[i__7].r - refsum.i * v[i__7].i, + z__2.i = refsum.r * v[i__7].i + refsum.i * v[i__7] + .r; + z__1.r = h__[i__6].r - z__2.r, z__1.i = h__[i__6].i - + z__2.i; + h__[i__4].r = z__1.r, h__[i__4].i = z__1.i; +/* L40: */ + } + } + +/* + ==== Multiply H by reflections from the right. + . Delay filling in the last row until the + . vigilant deflation check is complete. ==== +*/ + + if (accum) { + jtop = max(*ktop,incol); + } else if (*wantt) { + jtop = 1; + } else { + jtop = *ktop; + } + i__5 = mbot; + for (m = mtop; m <= i__5; ++m) { + i__4 = m * v_dim1 + 1; + if (v[i__4].r != 0. || v[i__4].i != 0.) { + k = krcol + (m - 1) * 3; +/* Computing MIN */ + i__6 = *kbot, i__7 = k + 3; + i__4 = min(i__6,i__7); + for (j = jtop; j <= i__4; ++j) { + i__6 = m * v_dim1 + 1; + i__7 = j + (k + 1) * h_dim1; + i__8 = m * v_dim1 + 2; + i__9 = j + (k + 2) * h_dim1; + z__4.r = v[i__8].r * h__[i__9].r - v[i__8].i * h__[ + i__9].i, z__4.i = v[i__8].r * h__[i__9].i + v[ + i__8].i * h__[i__9].r; + z__3.r = h__[i__7].r + z__4.r, z__3.i = h__[i__7].i + + z__4.i; + i__10 = m * v_dim1 + 3; + i__11 = j + (k + 3) * h_dim1; + z__5.r = v[i__10].r * h__[i__11].r - v[i__10].i * h__[ + i__11].i, z__5.i = v[i__10].r * h__[i__11].i + + v[i__10].i * h__[i__11].r; + z__2.r = z__3.r + z__5.r, z__2.i = z__3.i + z__5.i; + z__1.r = v[i__6].r * z__2.r - v[i__6].i * z__2.i, + z__1.i = v[i__6].r * z__2.i + v[i__6].i * + z__2.r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__6 = j + (k + 1) * h_dim1; + i__7 = j + (k + 1) * h_dim1; + z__1.r = h__[i__7].r - refsum.r, z__1.i = h__[i__7].i + - refsum.i; + h__[i__6].r = z__1.r, h__[i__6].i = z__1.i; + i__6 = j + (k + 2) * h_dim1; + i__7 = j + (k + 2) * h_dim1; + d_cnjg(&z__3, &v[m * v_dim1 + 2]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, + z__2.i = refsum.r * z__3.i + refsum.i * + z__3.r; + z__1.r = h__[i__7].r - z__2.r, z__1.i = h__[i__7].i - + z__2.i; + h__[i__6].r = z__1.r, h__[i__6].i = z__1.i; + i__6 = j + (k + 3) * h_dim1; + i__7 = j + (k + 3) * h_dim1; + d_cnjg(&z__3, &v[m * v_dim1 + 3]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, + z__2.i = refsum.r * z__3.i + refsum.i * + z__3.r; + z__1.r = h__[i__7].r - z__2.r, z__1.i = h__[i__7].i - + z__2.i; + h__[i__6].r = z__1.r, h__[i__6].i = z__1.i; +/* L50: */ + } + + if (accum) { + +/* + ==== Accumulate U. (If necessary, update Z later + . with with an efficient matrix-matrix + . multiply.) ==== +*/ + + kms = k - incol; +/* Computing MAX */ + i__4 = 1, i__6 = *ktop - incol; + i__7 = kdu; + for (j = max(i__4,i__6); j <= i__7; ++j) { + i__4 = m * v_dim1 + 1; + i__6 = j + (kms + 1) * u_dim1; + i__8 = m * v_dim1 + 2; + i__9 = j + (kms + 2) * u_dim1; + z__4.r = v[i__8].r * u[i__9].r - v[i__8].i * u[ + i__9].i, z__4.i = v[i__8].r * u[i__9].i + + v[i__8].i * u[i__9].r; + z__3.r = u[i__6].r + z__4.r, z__3.i = u[i__6].i + + z__4.i; + i__10 = m * v_dim1 + 3; + i__11 = j + (kms + 3) * u_dim1; + z__5.r = v[i__10].r * u[i__11].r - v[i__10].i * u[ + i__11].i, z__5.i = v[i__10].r * u[i__11] + .i + v[i__10].i * u[i__11].r; + z__2.r = z__3.r + z__5.r, z__2.i = z__3.i + + z__5.i; + z__1.r = v[i__4].r * z__2.r - v[i__4].i * z__2.i, + z__1.i = v[i__4].r * z__2.i + v[i__4].i * + z__2.r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__4 = j + (kms + 1) * u_dim1; + i__6 = j + (kms + 1) * u_dim1; + z__1.r = u[i__6].r - refsum.r, z__1.i = u[i__6].i + - refsum.i; + u[i__4].r = z__1.r, u[i__4].i = z__1.i; + i__4 = j + (kms + 2) * u_dim1; + i__6 = j + (kms + 2) * u_dim1; + d_cnjg(&z__3, &v[m * v_dim1 + 2]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, + z__2.i = refsum.r * z__3.i + refsum.i * + z__3.r; + z__1.r = u[i__6].r - z__2.r, z__1.i = u[i__6].i - + z__2.i; + u[i__4].r = z__1.r, u[i__4].i = z__1.i; + i__4 = j + (kms + 3) * u_dim1; + i__6 = j + (kms + 3) * u_dim1; + d_cnjg(&z__3, &v[m * v_dim1 + 3]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, + z__2.i = refsum.r * z__3.i + refsum.i * + z__3.r; + z__1.r = u[i__6].r - z__2.r, z__1.i = u[i__6].i - + z__2.i; + u[i__4].r = z__1.r, u[i__4].i = z__1.i; +/* L60: */ + } + } else if (*wantz) { + +/* + ==== U is not accumulated, so update Z + . now by multiplying by reflections + . from the right. ==== +*/ + + i__7 = *ihiz; + for (j = *iloz; j <= i__7; ++j) { + i__4 = m * v_dim1 + 1; + i__6 = j + (k + 1) * z_dim1; + i__8 = m * v_dim1 + 2; + i__9 = j + (k + 2) * z_dim1; + z__4.r = v[i__8].r * z__[i__9].r - v[i__8].i * + z__[i__9].i, z__4.i = v[i__8].r * z__[ + i__9].i + v[i__8].i * z__[i__9].r; + z__3.r = z__[i__6].r + z__4.r, z__3.i = z__[i__6] + .i + z__4.i; + i__10 = m * v_dim1 + 3; + i__11 = j + (k + 3) * z_dim1; + z__5.r = v[i__10].r * z__[i__11].r - v[i__10].i * + z__[i__11].i, z__5.i = v[i__10].r * z__[ + i__11].i + v[i__10].i * z__[i__11].r; + z__2.r = z__3.r + z__5.r, z__2.i = z__3.i + + z__5.i; + z__1.r = v[i__4].r * z__2.r - v[i__4].i * z__2.i, + z__1.i = v[i__4].r * z__2.i + v[i__4].i * + z__2.r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__4 = j + (k + 1) * z_dim1; + i__6 = j + (k + 1) * z_dim1; + z__1.r = z__[i__6].r - refsum.r, z__1.i = z__[ + i__6].i - refsum.i; + z__[i__4].r = z__1.r, z__[i__4].i = z__1.i; + i__4 = j + (k + 2) * z_dim1; + i__6 = j + (k + 2) * z_dim1; + d_cnjg(&z__3, &v[m * v_dim1 + 2]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, + z__2.i = refsum.r * z__3.i + refsum.i * + z__3.r; + z__1.r = z__[i__6].r - z__2.r, z__1.i = z__[i__6] + .i - z__2.i; + z__[i__4].r = z__1.r, z__[i__4].i = z__1.i; + i__4 = j + (k + 3) * z_dim1; + i__6 = j + (k + 3) * z_dim1; + d_cnjg(&z__3, &v[m * v_dim1 + 3]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, + z__2.i = refsum.r * z__3.i + refsum.i * + z__3.r; + z__1.r = z__[i__6].r - z__2.r, z__1.i = z__[i__6] + .i - z__2.i; + z__[i__4].r = z__1.r, z__[i__4].i = z__1.i; +/* L70: */ + } + } + } +/* L80: */ + } + +/* ==== Special case: 2-by-2 reflection (if needed) ==== */ + + k = krcol + (m22 - 1) * 3; + i__5 = m22 * v_dim1 + 1; + if (bmp22 && (v[i__5].r != 0. || v[i__5].i != 0.)) { +/* Computing MIN */ + i__7 = *kbot, i__4 = k + 3; + i__5 = min(i__7,i__4); + for (j = jtop; j <= i__5; ++j) { + i__7 = m22 * v_dim1 + 1; + i__4 = j + (k + 1) * h_dim1; + i__6 = m22 * v_dim1 + 2; + i__8 = j + (k + 2) * h_dim1; + z__3.r = v[i__6].r * h__[i__8].r - v[i__6].i * h__[i__8] + .i, z__3.i = v[i__6].r * h__[i__8].i + v[i__6].i * + h__[i__8].r; + z__2.r = h__[i__4].r + z__3.r, z__2.i = h__[i__4].i + + z__3.i; + z__1.r = v[i__7].r * z__2.r - v[i__7].i * z__2.i, z__1.i = + v[i__7].r * z__2.i + v[i__7].i * z__2.r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__7 = j + (k + 1) * h_dim1; + i__4 = j + (k + 1) * h_dim1; + z__1.r = h__[i__4].r - refsum.r, z__1.i = h__[i__4].i - + refsum.i; + h__[i__7].r = z__1.r, h__[i__7].i = z__1.i; + i__7 = j + (k + 2) * h_dim1; + i__4 = j + (k + 2) * h_dim1; + d_cnjg(&z__3, &v[m22 * v_dim1 + 2]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, z__2.i = + refsum.r * z__3.i + refsum.i * z__3.r; + z__1.r = h__[i__4].r - z__2.r, z__1.i = h__[i__4].i - + z__2.i; + h__[i__7].r = z__1.r, h__[i__7].i = z__1.i; +/* L90: */ + } + + if (accum) { + kms = k - incol; +/* Computing MAX */ + i__5 = 1, i__7 = *ktop - incol; + i__4 = kdu; + for (j = max(i__5,i__7); j <= i__4; ++j) { + i__5 = m22 * v_dim1 + 1; + i__7 = j + (kms + 1) * u_dim1; + i__6 = m22 * v_dim1 + 2; + i__8 = j + (kms + 2) * u_dim1; + z__3.r = v[i__6].r * u[i__8].r - v[i__6].i * u[i__8] + .i, z__3.i = v[i__6].r * u[i__8].i + v[i__6] + .i * u[i__8].r; + z__2.r = u[i__7].r + z__3.r, z__2.i = u[i__7].i + + z__3.i; + z__1.r = v[i__5].r * z__2.r - v[i__5].i * z__2.i, + z__1.i = v[i__5].r * z__2.i + v[i__5].i * + z__2.r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__5 = j + (kms + 1) * u_dim1; + i__7 = j + (kms + 1) * u_dim1; + z__1.r = u[i__7].r - refsum.r, z__1.i = u[i__7].i - + refsum.i; + u[i__5].r = z__1.r, u[i__5].i = z__1.i; + i__5 = j + (kms + 2) * u_dim1; + i__7 = j + (kms + 2) * u_dim1; + d_cnjg(&z__3, &v[m22 * v_dim1 + 2]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, + z__2.i = refsum.r * z__3.i + refsum.i * + z__3.r; + z__1.r = u[i__7].r - z__2.r, z__1.i = u[i__7].i - + z__2.i; + u[i__5].r = z__1.r, u[i__5].i = z__1.i; +/* L100: */ + } + } else if (*wantz) { + i__4 = *ihiz; + for (j = *iloz; j <= i__4; ++j) { + i__5 = m22 * v_dim1 + 1; + i__7 = j + (k + 1) * z_dim1; + i__6 = m22 * v_dim1 + 2; + i__8 = j + (k + 2) * z_dim1; + z__3.r = v[i__6].r * z__[i__8].r - v[i__6].i * z__[ + i__8].i, z__3.i = v[i__6].r * z__[i__8].i + v[ + i__6].i * z__[i__8].r; + z__2.r = z__[i__7].r + z__3.r, z__2.i = z__[i__7].i + + z__3.i; + z__1.r = v[i__5].r * z__2.r - v[i__5].i * z__2.i, + z__1.i = v[i__5].r * z__2.i + v[i__5].i * + z__2.r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__5 = j + (k + 1) * z_dim1; + i__7 = j + (k + 1) * z_dim1; + z__1.r = z__[i__7].r - refsum.r, z__1.i = z__[i__7].i + - refsum.i; + z__[i__5].r = z__1.r, z__[i__5].i = z__1.i; + i__5 = j + (k + 2) * z_dim1; + i__7 = j + (k + 2) * z_dim1; + d_cnjg(&z__3, &v[m22 * v_dim1 + 2]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, + z__2.i = refsum.r * z__3.i + refsum.i * + z__3.r; + z__1.r = z__[i__7].r - z__2.r, z__1.i = z__[i__7].i - + z__2.i; + z__[i__5].r = z__1.r, z__[i__5].i = z__1.i; +/* L110: */ + } + } + } + +/* ==== Vigilant deflation check ==== */ + + mstart = mtop; + if (krcol + (mstart - 1) * 3 < *ktop) { + ++mstart; + } + mend = mbot; + if (bmp22) { + ++mend; + } + if (krcol == *kbot - 2) { + ++mend; + } + i__4 = mend; + for (m = mstart; m <= i__4; ++m) { +/* Computing MIN */ + i__5 = *kbot - 1, i__7 = krcol + (m - 1) * 3; + k = min(i__5,i__7); + +/* + ==== The following convergence test requires that + . the tradition small-compared-to-nearby-diagonals + . criterion and the Ahues & Tisseur (LAWN 122, 1997) + . criteria both be satisfied. The latter improves + . accuracy in some examples. Falling back on an + . alternate convergence criterion when TST1 or TST2 + . is zero (as done here) is traditional but probably + . unnecessary. ==== +*/ + + i__5 = k + 1 + k * h_dim1; + if (h__[i__5].r != 0. || h__[i__5].i != 0.) { + i__5 = k + k * h_dim1; + i__7 = k + 1 + (k + 1) * h_dim1; + tst1 = (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = d_imag(& + h__[k + k * h_dim1]), abs(d__2)) + ((d__3 = h__[ + i__7].r, abs(d__3)) + (d__4 = d_imag(&h__[k + 1 + + (k + 1) * h_dim1]), abs(d__4))); + if (tst1 == 0.) { + if (k >= *ktop + 1) { + i__5 = k + (k - 1) * h_dim1; + tst1 += (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + (k - 1) * h_dim1]), abs( + d__2)); + } + if (k >= *ktop + 2) { + i__5 = k + (k - 2) * h_dim1; + tst1 += (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + (k - 2) * h_dim1]), abs( + d__2)); + } + if (k >= *ktop + 3) { + i__5 = k + (k - 3) * h_dim1; + tst1 += (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + (k - 3) * h_dim1]), abs( + d__2)); + } + if (k <= *kbot - 2) { + i__5 = k + 2 + (k + 1) * h_dim1; + tst1 += (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + 2 + (k + 1) * h_dim1]), + abs(d__2)); + } + if (k <= *kbot - 3) { + i__5 = k + 3 + (k + 1) * h_dim1; + tst1 += (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + 3 + (k + 1) * h_dim1]), + abs(d__2)); + } + if (k <= *kbot - 4) { + i__5 = k + 4 + (k + 1) * h_dim1; + tst1 += (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + 4 + (k + 1) * h_dim1]), + abs(d__2)); + } + } + i__5 = k + 1 + k * h_dim1; +/* Computing MAX */ + d__3 = smlnum, d__4 = ulp * tst1; + if ((d__1 = h__[i__5].r, abs(d__1)) + (d__2 = d_imag(&h__[ + k + 1 + k * h_dim1]), abs(d__2)) <= max(d__3,d__4) + ) { +/* Computing MAX */ + i__5 = k + 1 + k * h_dim1; + i__7 = k + (k + 1) * h_dim1; + d__5 = (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + 1 + k * h_dim1]), abs(d__2)), + d__6 = (d__3 = h__[i__7].r, abs(d__3)) + ( + d__4 = d_imag(&h__[k + (k + 1) * h_dim1]), + abs(d__4)); + h12 = max(d__5,d__6); +/* Computing MIN */ + i__5 = k + 1 + k * h_dim1; + i__7 = k + (k + 1) * h_dim1; + d__5 = (d__1 = h__[i__5].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + 1 + k * h_dim1]), abs(d__2)), + d__6 = (d__3 = h__[i__7].r, abs(d__3)) + ( + d__4 = d_imag(&h__[k + (k + 1) * h_dim1]), + abs(d__4)); + h21 = min(d__5,d__6); + i__5 = k + k * h_dim1; + i__7 = k + 1 + (k + 1) * h_dim1; + z__2.r = h__[i__5].r - h__[i__7].r, z__2.i = h__[i__5] + .i - h__[i__7].i; + z__1.r = z__2.r, z__1.i = z__2.i; +/* Computing MAX */ + i__6 = k + 1 + (k + 1) * h_dim1; + d__5 = (d__1 = h__[i__6].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + 1 + (k + 1) * h_dim1]), abs( + d__2)), d__6 = (d__3 = z__1.r, abs(d__3)) + ( + d__4 = d_imag(&z__1), abs(d__4)); + h11 = max(d__5,d__6); + i__5 = k + k * h_dim1; + i__7 = k + 1 + (k + 1) * h_dim1; + z__2.r = h__[i__5].r - h__[i__7].r, z__2.i = h__[i__5] + .i - h__[i__7].i; + z__1.r = z__2.r, z__1.i = z__2.i; +/* Computing MIN */ + i__6 = k + 1 + (k + 1) * h_dim1; + d__5 = (d__1 = h__[i__6].r, abs(d__1)) + (d__2 = + d_imag(&h__[k + 1 + (k + 1) * h_dim1]), abs( + d__2)), d__6 = (d__3 = z__1.r, abs(d__3)) + ( + d__4 = d_imag(&z__1), abs(d__4)); + h22 = min(d__5,d__6); + scl = h11 + h12; + tst2 = h22 * (h11 / scl); + +/* Computing MAX */ + d__1 = smlnum, d__2 = ulp * tst2; + if (tst2 == 0. || h21 * (h12 / scl) <= max(d__1,d__2)) + { + i__5 = k + 1 + k * h_dim1; + h__[i__5].r = 0., h__[i__5].i = 0.; + } + } + } +/* L120: */ + } + +/* + ==== Fill in the last row of each bulge. ==== + + Computing MIN +*/ + i__4 = nbmps, i__5 = (*kbot - krcol - 1) / 3; + mend = min(i__4,i__5); + i__4 = mend; + for (m = mtop; m <= i__4; ++m) { + k = krcol + (m - 1) * 3; + i__5 = m * v_dim1 + 1; + i__7 = m * v_dim1 + 3; + z__2.r = v[i__5].r * v[i__7].r - v[i__5].i * v[i__7].i, + z__2.i = v[i__5].r * v[i__7].i + v[i__5].i * v[i__7] + .r; + i__6 = k + 4 + (k + 3) * h_dim1; + z__1.r = z__2.r * h__[i__6].r - z__2.i * h__[i__6].i, z__1.i = + z__2.r * h__[i__6].i + z__2.i * h__[i__6].r; + refsum.r = z__1.r, refsum.i = z__1.i; + i__5 = k + 4 + (k + 1) * h_dim1; + z__1.r = -refsum.r, z__1.i = -refsum.i; + h__[i__5].r = z__1.r, h__[i__5].i = z__1.i; + i__5 = k + 4 + (k + 2) * h_dim1; + z__2.r = -refsum.r, z__2.i = -refsum.i; + d_cnjg(&z__3, &v[m * v_dim1 + 2]); + z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, z__1.i = z__2.r * + z__3.i + z__2.i * z__3.r; + h__[i__5].r = z__1.r, h__[i__5].i = z__1.i; + i__5 = k + 4 + (k + 3) * h_dim1; + i__7 = k + 4 + (k + 3) * h_dim1; + d_cnjg(&z__3, &v[m * v_dim1 + 3]); + z__2.r = refsum.r * z__3.r - refsum.i * z__3.i, z__2.i = + refsum.r * z__3.i + refsum.i * z__3.r; + z__1.r = h__[i__7].r - z__2.r, z__1.i = h__[i__7].i - z__2.i; + h__[i__5].r = z__1.r, h__[i__5].i = z__1.i; +/* L130: */ + } + +/* + ==== End of near-the-diagonal bulge chase. ==== + + L140: +*/ + } + +/* + ==== Use U (if accumulated) to update far-from-diagonal + . entries in H. If required, use U to update Z as + . well. ==== +*/ + + if (accum) { + if (*wantt) { + jtop = 1; + jbot = *n; + } else { + jtop = *ktop; + jbot = *kbot; + } + if (! blk22 || incol < *ktop || ndcol > *kbot || ns <= 2) { + +/* + ==== Updates not exploiting the 2-by-2 block + . structure of U. K1 and NU keep track of + . the location and size of U in the special + . cases of introducing bulges and chasing + . bulges off the bottom. In these special + . cases and in case the number of shifts + . is NS = 2, there is no 2-by-2 block + . structure to exploit. ==== + + Computing MAX +*/ + i__3 = 1, i__4 = *ktop - incol; + k1 = max(i__3,i__4); +/* Computing MAX */ + i__3 = 0, i__4 = ndcol - *kbot; + nu = kdu - max(i__3,i__4) - k1 + 1; + +/* ==== Horizontal Multiply ==== */ + + i__3 = jbot; + i__4 = *nh; + for (jcol = min(ndcol,*kbot) + 1; i__4 < 0 ? jcol >= i__3 : + jcol <= i__3; jcol += i__4) { +/* Computing MIN */ + i__5 = *nh, i__7 = jbot - jcol + 1; + jlen = min(i__5,i__7); + zgemm_("C", "N", &nu, &jlen, &nu, &c_b57, &u[k1 + k1 * + u_dim1], ldu, &h__[incol + k1 + jcol * h_dim1], + ldh, &c_b56, &wh[wh_offset], ldwh); + zlacpy_("ALL", &nu, &jlen, &wh[wh_offset], ldwh, &h__[ + incol + k1 + jcol * h_dim1], ldh); +/* L150: */ + } + +/* ==== Vertical multiply ==== */ + + i__4 = max(*ktop,incol) - 1; + i__3 = *nv; + for (jrow = jtop; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; + jrow += i__3) { +/* Computing MIN */ + i__5 = *nv, i__7 = max(*ktop,incol) - jrow; + jlen = min(i__5,i__7); + zgemm_("N", "N", &jlen, &nu, &nu, &c_b57, &h__[jrow + ( + incol + k1) * h_dim1], ldh, &u[k1 + k1 * u_dim1], + ldu, &c_b56, &wv[wv_offset], ldwv); + zlacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &h__[ + jrow + (incol + k1) * h_dim1], ldh); +/* L160: */ + } + +/* ==== Z multiply (also vertical) ==== */ + + if (*wantz) { + i__3 = *ihiz; + i__4 = *nv; + for (jrow = *iloz; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; + jrow += i__4) { +/* Computing MIN */ + i__5 = *nv, i__7 = *ihiz - jrow + 1; + jlen = min(i__5,i__7); + zgemm_("N", "N", &jlen, &nu, &nu, &c_b57, &z__[jrow + + (incol + k1) * z_dim1], ldz, &u[k1 + k1 * + u_dim1], ldu, &c_b56, &wv[wv_offset], ldwv); + zlacpy_("ALL", &jlen, &nu, &wv[wv_offset], ldwv, &z__[ + jrow + (incol + k1) * z_dim1], ldz) + ; +/* L170: */ + } + } + } else { + +/* + ==== Updates exploiting U's 2-by-2 block structure. + . (I2, I4, J2, J4 are the last rows and columns + . of the blocks.) ==== +*/ + + i2 = (kdu + 1) / 2; + i4 = kdu; + j2 = i4 - i2; + j4 = kdu; + +/* + ==== KZS and KNZ deal with the band of zeros + . along the diagonal of one of the triangular + . blocks. ==== +*/ + + kzs = j4 - j2 - (ns + 1); + knz = ns + 1; + +/* ==== Horizontal multiply ==== */ + + i__4 = jbot; + i__3 = *nh; + for (jcol = min(ndcol,*kbot) + 1; i__3 < 0 ? jcol >= i__4 : + jcol <= i__4; jcol += i__3) { +/* Computing MIN */ + i__5 = *nh, i__7 = jbot - jcol + 1; + jlen = min(i__5,i__7); + +/* + ==== Copy bottom of H to top+KZS of scratch ==== + (The first KZS rows get multiplied by zero.) ==== +*/ + + zlacpy_("ALL", &knz, &jlen, &h__[incol + 1 + j2 + jcol * + h_dim1], ldh, &wh[kzs + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U21' ==== */ + + zlaset_("ALL", &kzs, &jlen, &c_b56, &c_b56, &wh[wh_offset] + , ldwh); + ztrmm_("L", "U", "C", "N", &knz, &jlen, &c_b57, &u[j2 + 1 + + (kzs + 1) * u_dim1], ldu, &wh[kzs + 1 + wh_dim1] + , ldwh); + +/* ==== Multiply top of H by U11' ==== */ + + zgemm_("C", "N", &i2, &jlen, &j2, &c_b57, &u[u_offset], + ldu, &h__[incol + 1 + jcol * h_dim1], ldh, &c_b57, + &wh[wh_offset], ldwh); + +/* ==== Copy top of H to bottom of WH ==== */ + + zlacpy_("ALL", &j2, &jlen, &h__[incol + 1 + jcol * h_dim1] + , ldh, &wh[i2 + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U21' ==== */ + + ztrmm_("L", "L", "C", "N", &j2, &jlen, &c_b57, &u[(i2 + 1) + * u_dim1 + 1], ldu, &wh[i2 + 1 + wh_dim1], ldwh); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + zgemm_("C", "N", &i__5, &jlen, &i__7, &c_b57, &u[j2 + 1 + + (i2 + 1) * u_dim1], ldu, &h__[incol + 1 + j2 + + jcol * h_dim1], ldh, &c_b57, &wh[i2 + 1 + wh_dim1] + , ldwh); + +/* ==== Copy it back ==== */ + + zlacpy_("ALL", &kdu, &jlen, &wh[wh_offset], ldwh, &h__[ + incol + 1 + jcol * h_dim1], ldh); +/* L180: */ + } + +/* ==== Vertical multiply ==== */ + + i__3 = max(incol,*ktop) - 1; + i__4 = *nv; + for (jrow = jtop; i__4 < 0 ? jrow >= i__3 : jrow <= i__3; + jrow += i__4) { +/* Computing MIN */ + i__5 = *nv, i__7 = max(incol,*ktop) - jrow; + jlen = min(i__5,i__7); + +/* + ==== Copy right of H to scratch (the first KZS + . columns get multiplied by zero) ==== +*/ + + zlacpy_("ALL", &jlen, &knz, &h__[jrow + (incol + 1 + j2) * + h_dim1], ldh, &wv[(kzs + 1) * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U21 ==== */ + + zlaset_("ALL", &jlen, &kzs, &c_b56, &c_b56, &wv[wv_offset] + , ldwv); + ztrmm_("R", "U", "N", "N", &jlen, &knz, &c_b57, &u[j2 + 1 + + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Multiply by U11 ==== */ + + zgemm_("N", "N", &jlen, &i2, &j2, &c_b57, &h__[jrow + ( + incol + 1) * h_dim1], ldh, &u[u_offset], ldu, & + c_b57, &wv[wv_offset], ldwv) + ; + +/* ==== Copy left of H to right of scratch ==== */ + + zlacpy_("ALL", &jlen, &j2, &h__[jrow + (incol + 1) * + h_dim1], ldh, &wv[(i2 + 1) * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U21 ==== */ + + i__5 = i4 - i2; + ztrmm_("R", "L", "N", "N", &jlen, &i__5, &c_b57, &u[(i2 + + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * wv_dim1 + 1] + , ldwv); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + zgemm_("N", "N", &jlen, &i__5, &i__7, &c_b57, &h__[jrow + + (incol + 1 + j2) * h_dim1], ldh, &u[j2 + 1 + (i2 + + 1) * u_dim1], ldu, &c_b57, &wv[(i2 + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Copy it back ==== */ + + zlacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, &h__[ + jrow + (incol + 1) * h_dim1], ldh); +/* L190: */ + } + +/* ==== Multiply Z (also vertical) ==== */ + + if (*wantz) { + i__4 = *ihiz; + i__3 = *nv; + for (jrow = *iloz; i__3 < 0 ? jrow >= i__4 : jrow <= i__4; + jrow += i__3) { +/* Computing MIN */ + i__5 = *nv, i__7 = *ihiz - jrow + 1; + jlen = min(i__5,i__7); + +/* + ==== Copy right of Z to left of scratch (first + . KZS columns get multiplied by zero) ==== +*/ + + zlacpy_("ALL", &jlen, &knz, &z__[jrow + (incol + 1 + + j2) * z_dim1], ldz, &wv[(kzs + 1) * wv_dim1 + + 1], ldwv); + +/* ==== Multiply by U12 ==== */ + + zlaset_("ALL", &jlen, &kzs, &c_b56, &c_b56, &wv[ + wv_offset], ldwv); + ztrmm_("R", "U", "N", "N", &jlen, &knz, &c_b57, &u[j2 + + 1 + (kzs + 1) * u_dim1], ldu, &wv[(kzs + 1) + * wv_dim1 + 1], ldwv); + +/* ==== Multiply by U11 ==== */ + + zgemm_("N", "N", &jlen, &i2, &j2, &c_b57, &z__[jrow + + (incol + 1) * z_dim1], ldz, &u[u_offset], ldu, + &c_b57, &wv[wv_offset], ldwv); + +/* ==== Copy left of Z to right of scratch ==== */ + + zlacpy_("ALL", &jlen, &j2, &z__[jrow + (incol + 1) * + z_dim1], ldz, &wv[(i2 + 1) * wv_dim1 + 1], + ldwv); + +/* ==== Multiply by U21 ==== */ + + i__5 = i4 - i2; + ztrmm_("R", "L", "N", "N", &jlen, &i__5, &c_b57, &u[( + i2 + 1) * u_dim1 + 1], ldu, &wv[(i2 + 1) * + wv_dim1 + 1], ldwv); + +/* ==== Multiply by U22 ==== */ + + i__5 = i4 - i2; + i__7 = j4 - j2; + zgemm_("N", "N", &jlen, &i__5, &i__7, &c_b57, &z__[ + jrow + (incol + 1 + j2) * z_dim1], ldz, &u[j2 + + 1 + (i2 + 1) * u_dim1], ldu, &c_b57, &wv[( + i2 + 1) * wv_dim1 + 1], ldwv); + +/* ==== Copy the result back to Z ==== */ + + zlacpy_("ALL", &jlen, &kdu, &wv[wv_offset], ldwv, & + z__[jrow + (incol + 1) * z_dim1], ldz); +/* L200: */ + } + } + } + } +/* L210: */ + } + +/* ==== End of ZLAQR5 ==== */ + + return 0; +} /* zlaqr5_ */ + +/* Subroutine */ int zlarcm_(integer *m, integer *n, doublereal *a, integer * + lda, doublecomplex *b, integer *ldb, doublecomplex *c__, integer *ldc, + doublereal *rwork) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3, i__4, i__5; + doublereal d__1; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int dgemm_(char *, char *, integer *, integer *, + integer *, doublereal *, doublereal *, integer *, doublereal *, + integer *, doublereal *, doublereal *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLARCM performs a very simple matrix-matrix multiplication: + C := A * B, + where A is M by M and real; B is M by N and complex; + C is M by N and complex. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix A and of the matrix C. + M >= 0. + + N (input) INTEGER + The number of columns and rows of the matrix B and + the number of columns of the matrix C. + N >= 0. + + A (input) DOUBLE PRECISION array, dimension (LDA, M) + A contains the M by M matrix A. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >=max(1,M). + + B (input) DOUBLE PRECISION array, dimension (LDB, N) + B contains the M by N matrix B. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >=max(1,M). + + C (input) COMPLEX*16 array, dimension (LDC, N) + C contains the M by N matrix C. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >=max(1,M). + + RWORK (workspace) DOUBLE PRECISION array, dimension (2*M*N) + + ===================================================================== + + + Quick return if possible. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --rwork; + + /* Function Body */ + if (*m == 0 || *n == 0) { + return 0; + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * b_dim1; + rwork[(j - 1) * *m + i__] = b[i__3].r; +/* L10: */ + } +/* L20: */ + } + + l = *m * *n + 1; + dgemm_("N", "N", m, n, m, &c_b1034, &a[a_offset], lda, &rwork[1], m, & + c_b328, &rwork[l], m); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = l + (j - 1) * *m + i__ - 1; + c__[i__3].r = rwork[i__4], c__[i__3].i = 0.; +/* L30: */ + } +/* L40: */ + } + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + rwork[(j - 1) * *m + i__] = d_imag(&b[i__ + j * b_dim1]); +/* L50: */ + } +/* L60: */ + } + dgemm_("N", "N", m, n, m, &c_b1034, &a[a_offset], lda, &rwork[1], m, & + c_b328, &rwork[l], m); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + d__1 = c__[i__4].r; + i__5 = l + (j - 1) * *m + i__ - 1; + z__1.r = d__1, z__1.i = rwork[i__5]; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L70: */ + } +/* L80: */ + } + + return 0; + +/* End of ZLARCM */ + +} /* zlarcm_ */ + +/* Subroutine */ int zlarf_(char *side, integer *m, integer *n, doublecomplex + *v, integer *incv, doublecomplex *tau, doublecomplex *c__, integer * + ldc, doublecomplex *work) +{ + /* System generated locals */ + integer c_dim1, c_offset, i__1; + doublecomplex z__1; + + /* Local variables */ + static integer i__; + static logical applyleft; + extern logical lsame_(char *, char *); + static integer lastc; + extern /* Subroutine */ int zgerc_(integer *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *), zgemv_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *); + static integer lastv; + extern integer ilazlc_(integer *, integer *, doublecomplex *, integer *), + ilazlr_(integer *, integer *, doublecomplex *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLARF applies a complex elementary reflector H to a complex M-by-N + matrix C, from either the left or the right. H is represented in the + form + + H = I - tau * v * v' + + where tau is a complex scalar and v is a complex vector. + + If tau = 0, then H is taken to be the unit matrix. + + To apply H' (the conjugate transpose of H), supply conjg(tau) instead + tau. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': form H * C + = 'R': form C * H + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + V (input) COMPLEX*16 array, dimension + (1 + (M-1)*abs(INCV)) if SIDE = 'L' + or (1 + (N-1)*abs(INCV)) if SIDE = 'R' + The vector v in the representation of H. V is not used if + TAU = 0. + + INCV (input) INTEGER + The increment between elements of v. INCV <> 0. + + TAU (input) COMPLEX*16 + The value tau in the representation of H. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by the matrix H * C if SIDE = 'L', + or C * H if SIDE = 'R'. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX*16 array, dimension + (N) if SIDE = 'L' + or (M) if SIDE = 'R' + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --v; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + applyleft = lsame_(side, "L"); + lastv = 0; + lastc = 0; + if (tau->r != 0. || tau->i != 0.) { +/* + Set up variables for scanning V. LASTV begins pointing to the end + of V. +*/ + if (applyleft) { + lastv = *m; + } else { + lastv = *n; + } + if (*incv > 0) { + i__ = (lastv - 1) * *incv + 1; + } else { + i__ = 1; + } +/* Look for the last non-zero row in V. */ + for(;;) { /* while(complicated condition) */ + i__1 = i__; + if (!(lastv > 0 && (v[i__1].r == 0. && v[i__1].i == 0.))) + break; + --lastv; + i__ -= *incv; + } + if (applyleft) { +/* Scan for the last non-zero column in C(1:lastv,:). */ + lastc = ilazlc_(&lastv, n, &c__[c_offset], ldc); + } else { +/* Scan for the last non-zero row in C(:,1:lastv). */ + lastc = ilazlr_(m, &lastv, &c__[c_offset], ldc); + } + } +/* + Note that lastc.eq.0 renders the BLAS operations null; no special + case is needed at this level. +*/ + if (applyleft) { + +/* Form H * C */ + + if (lastv > 0) { + +/* w(1:lastc,1) := C(1:lastv,1:lastc)' * v(1:lastv,1) */ + + zgemv_("Conjugate transpose", &lastv, &lastc, &c_b57, &c__[ + c_offset], ldc, &v[1], incv, &c_b56, &work[1], &c__1); + +/* C(1:lastv,1:lastc) := C(...) - v(1:lastv,1) * w(1:lastc,1)' */ + + z__1.r = -tau->r, z__1.i = -tau->i; + zgerc_(&lastv, &lastc, &z__1, &v[1], incv, &work[1], &c__1, &c__[ + c_offset], ldc); + } + } else { + +/* Form C * H */ + + if (lastv > 0) { + +/* w(1:lastc,1) := C(1:lastc,1:lastv) * v(1:lastv,1) */ + + zgemv_("No transpose", &lastc, &lastv, &c_b57, &c__[c_offset], + ldc, &v[1], incv, &c_b56, &work[1], &c__1); + +/* C(1:lastc,1:lastv) := C(...) - w(1:lastc,1) * v(1:lastv,1)' */ + + z__1.r = -tau->r, z__1.i = -tau->i; + zgerc_(&lastc, &lastv, &z__1, &work[1], &c__1, &v[1], incv, &c__[ + c_offset], ldc); + } + } + return 0; + +/* End of ZLARF */ + +} /* zlarf_ */ + +/* Subroutine */ int zlarfb_(char *side, char *trans, char *direct, char * + storev, integer *m, integer *n, integer *k, doublecomplex *v, integer + *ldv, doublecomplex *t, integer *ldt, doublecomplex *c__, integer * + ldc, doublecomplex *work, integer *ldwork) +{ + /* System generated locals */ + integer c_dim1, c_offset, t_dim1, t_offset, v_dim1, v_offset, work_dim1, + work_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + static integer lastc; + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer lastv; + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), ztrmm_(char *, char *, char *, char * + , integer *, integer *, doublecomplex *, doublecomplex *, integer + *, doublecomplex *, integer *); + extern integer ilazlc_(integer *, integer *, doublecomplex *, integer *); + extern /* Subroutine */ int zlacgv_(integer *, doublecomplex *, integer *) + ; + extern integer ilazlr_(integer *, integer *, doublecomplex *, integer *); + static char transt[1]; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLARFB applies a complex block reflector H or its transpose H' to a + complex M-by-N matrix C, from either the left or the right. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply H or H' from the Left + = 'R': apply H or H' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply H (No transpose) + = 'C': apply H' (Conjugate transpose) + + DIRECT (input) CHARACTER*1 + Indicates how H is formed from a product of elementary + reflectors + = 'F': H = H(1) H(2) . . . H(k) (Forward) + = 'B': H = H(k) . . . H(2) H(1) (Backward) + + STOREV (input) CHARACTER*1 + Indicates how the vectors which define the elementary + reflectors are stored: + = 'C': Columnwise + = 'R': Rowwise + + M (input) INTEGER + The number of rows of the matrix C. + + N (input) INTEGER + The number of columns of the matrix C. + + K (input) INTEGER + The order of the matrix T (= the number of elementary + reflectors whose product defines the block reflector). + + V (input) COMPLEX*16 array, dimension + (LDV,K) if STOREV = 'C' + (LDV,M) if STOREV = 'R' and SIDE = 'L' + (LDV,N) if STOREV = 'R' and SIDE = 'R' + The matrix V. See further details. + + LDV (input) INTEGER + The leading dimension of the array V. + If STOREV = 'C' and SIDE = 'L', LDV >= max(1,M); + if STOREV = 'C' and SIDE = 'R', LDV >= max(1,N); + if STOREV = 'R', LDV >= K. + + T (input) COMPLEX*16 array, dimension (LDT,K) + The triangular K-by-K matrix T in the representation of the + block reflector. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= K. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by H*C or H'*C or C*H or C*H'. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX*16 array, dimension (LDWORK,K) + + LDWORK (input) INTEGER + The leading dimension of the array WORK. + If SIDE = 'L', LDWORK >= max(1,N); + if SIDE = 'R', LDWORK >= max(1,M). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + work_dim1 = *ldwork; + work_offset = 1 + work_dim1; + work -= work_offset; + + /* Function Body */ + if (*m <= 0 || *n <= 0) { + return 0; + } + + if (lsame_(trans, "N")) { + *(unsigned char *)transt = 'C'; + } else { + *(unsigned char *)transt = 'N'; + } + + if (lsame_(storev, "C")) { + + if (lsame_(direct, "F")) { + +/* + Let V = ( V1 ) (first K rows) + ( V2 ) + where V1 is unit lower triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilazlr_(m, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilazlc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK) + + W := C1' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + zcopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 + + 1], &c__1); + zlacgv_(&lastc, &work[j * work_dim1 + 1], &c__1); +/* L10: */ + } + +/* W := W * V1 */ + + ztrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b57, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2'*V2 */ + + i__1 = lastv - *k; + zgemm_("Conjugate transpose", "No transpose", &lastc, k, & + i__1, &c_b57, &c__[*k + 1 + c_dim1], ldc, &v[*k + + 1 + v_dim1], ldv, &c_b57, &work[work_offset], + ldwork); + } + +/* W := W * T' or W * T */ + + ztrmm_("Right", "Upper", transt, "Non-unit", &lastc, k, & + c_b57, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V * W' */ + + if (*m > *k) { + +/* C2 := C2 - V2 * W' */ + + i__1 = lastv - *k; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "Conjugate transpose", &i__1, & + lastc, k, &z__1, &v[*k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork, &c_b57, &c__[*k + 1 + + c_dim1], ldc); + } + +/* W := W * V1' */ + + ztrmm_("Right", "Lower", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[v_offset], ldv, &work[ + work_offset], ldwork); + +/* C1 := C1 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ * c_dim1; + i__4 = j + i__ * c_dim1; + d_cnjg(&z__2, &work[i__ + j * work_dim1]); + z__1.r = c__[i__4].r - z__2.r, z__1.i = c__[i__4].i - + z__2.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L20: */ + } +/* L30: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilazlr_(n, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilazlr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V = (C1*V1 + C2*V2) (stored in WORK) + + W := C1 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + zcopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * + work_dim1 + 1], &c__1); +/* L40: */ + } + +/* W := W * V1 */ + + ztrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b57, &v[v_offset], ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2 * V2 */ + + i__1 = lastv - *k; + zgemm_("No transpose", "No transpose", &lastc, k, &i__1, & + c_b57, &c__[(*k + 1) * c_dim1 + 1], ldc, &v[*k + + 1 + v_dim1], ldv, &c_b57, &work[work_offset], + ldwork); + } + +/* W := W * T or W * T' */ + + ztrmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b57, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V' */ + + if (lastv > *k) { + +/* C2 := C2 - W * V2' */ + + i__1 = lastv - *k; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "Conjugate transpose", &lastc, & + i__1, k, &z__1, &work[work_offset], ldwork, &v[*k + + 1 + v_dim1], ldv, &c_b57, &c__[(*k + 1) * + c_dim1 + 1], ldc); + } + +/* W := W * V1' */ + + ztrmm_("Right", "Lower", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[v_offset], ldv, &work[ + work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * work_dim1; + z__1.r = c__[i__4].r - work[i__5].r, z__1.i = c__[ + i__4].i - work[i__5].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L50: */ + } +/* L60: */ + } + } + + } else { + +/* + Let V = ( V1 ) + ( V2 ) (last K rows) + where V2 is unit upper triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilazlr_(m, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilazlc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK) + + W := C2' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + zcopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[ + j * work_dim1 + 1], &c__1); + zlacgv_(&lastc, &work[j * work_dim1 + 1], &c__1); +/* L70: */ + } + +/* W := W * V2 */ + + ztrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b57, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1'*V1 */ + + i__1 = lastv - *k; + zgemm_("Conjugate transpose", "No transpose", &lastc, k, & + i__1, &c_b57, &c__[c_offset], ldc, &v[v_offset], + ldv, &c_b57, &work[work_offset], ldwork); + } + +/* W := W * T' or W * T */ + + ztrmm_("Right", "Lower", transt, "Non-unit", &lastc, k, & + c_b57, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V * W' */ + + if (lastv > *k) { + +/* C1 := C1 - V1 * W' */ + + i__1 = lastv - *k; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "Conjugate transpose", &i__1, & + lastc, k, &z__1, &v[v_offset], ldv, &work[ + work_offset], ldwork, &c_b57, &c__[c_offset], ldc); + } + +/* W := W * V2' */ + + ztrmm_("Right", "Upper", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[lastv - *k + 1 + v_dim1], ldv, & + work[work_offset], ldwork); + +/* C2 := C2 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = lastv - *k + j + i__ * c_dim1; + i__4 = lastv - *k + j + i__ * c_dim1; + d_cnjg(&z__2, &work[i__ + j * work_dim1]); + z__1.r = c__[i__4].r - z__2.r, z__1.i = c__[i__4].i - + z__2.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L80: */ + } +/* L90: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilazlr_(n, k, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilazlr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V = (C1*V1 + C2*V2) (stored in WORK) + + W := C2 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + zcopy_(&lastc, &c__[(lastv - *k + j) * c_dim1 + 1], &c__1, + &work[j * work_dim1 + 1], &c__1); +/* L100: */ + } + +/* W := W * V2 */ + + ztrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b57, &v[lastv - *k + 1 + v_dim1], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1 * V1 */ + + i__1 = lastv - *k; + zgemm_("No transpose", "No transpose", &lastc, k, &i__1, & + c_b57, &c__[c_offset], ldc, &v[v_offset], ldv, & + c_b57, &work[work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + ztrmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b57, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V' */ + + if (lastv > *k) { + +/* C1 := C1 - W * V1' */ + + i__1 = lastv - *k; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "Conjugate transpose", &lastc, & + i__1, k, &z__1, &work[work_offset], ldwork, &v[ + v_offset], ldv, &c_b57, &c__[c_offset], ldc); + } + +/* W := W * V2' */ + + ztrmm_("Right", "Upper", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[lastv - *k + 1 + v_dim1], ldv, & + work[work_offset], ldwork); + +/* C2 := C2 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + (lastv - *k + j) * c_dim1; + i__4 = i__ + (lastv - *k + j) * c_dim1; + i__5 = i__ + j * work_dim1; + z__1.r = c__[i__4].r - work[i__5].r, z__1.i = c__[ + i__4].i - work[i__5].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L110: */ + } +/* L120: */ + } + } + } + + } else if (lsame_(storev, "R")) { + + if (lsame_(direct, "F")) { + +/* + Let V = ( V1 V2 ) (V1: first K columns) + where V1 is unit upper triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilazlc_(k, m, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilazlc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK) + + W := C1' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + zcopy_(&lastc, &c__[j + c_dim1], ldc, &work[j * work_dim1 + + 1], &c__1); + zlacgv_(&lastc, &work[j * work_dim1 + 1], &c__1); +/* L130: */ + } + +/* W := W * V1' */ + + ztrmm_("Right", "Upper", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[v_offset], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2'*V2' */ + + i__1 = lastv - *k; + zgemm_("Conjugate transpose", "Conjugate transpose", & + lastc, k, &i__1, &c_b57, &c__[*k + 1 + c_dim1], + ldc, &v[(*k + 1) * v_dim1 + 1], ldv, &c_b57, & + work[work_offset], ldwork) + ; + } + +/* W := W * T' or W * T */ + + ztrmm_("Right", "Upper", transt, "Non-unit", &lastc, k, & + c_b57, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V' * W' */ + + if (lastv > *k) { + +/* C2 := C2 - V2' * W' */ + + i__1 = lastv - *k; + z__1.r = -1., z__1.i = -0.; + zgemm_("Conjugate transpose", "Conjugate transpose", & + i__1, &lastc, k, &z__1, &v[(*k + 1) * v_dim1 + 1], + ldv, &work[work_offset], ldwork, &c_b57, &c__[*k + + 1 + c_dim1], ldc); + } + +/* W := W * V1 */ + + ztrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b57, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ * c_dim1; + i__4 = j + i__ * c_dim1; + d_cnjg(&z__2, &work[i__ + j * work_dim1]); + z__1.r = c__[i__4].r - z__2.r, z__1.i = c__[i__4].i - + z__2.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L140: */ + } +/* L150: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilazlc_(k, n, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilazlr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V' = (C1*V1' + C2*V2') (stored in WORK) + + W := C1 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + zcopy_(&lastc, &c__[j * c_dim1 + 1], &c__1, &work[j * + work_dim1 + 1], &c__1); +/* L160: */ + } + +/* W := W * V1' */ + + ztrmm_("Right", "Upper", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[v_offset], ldv, &work[ + work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C2 * V2' */ + + i__1 = lastv - *k; + zgemm_("No transpose", "Conjugate transpose", &lastc, k, & + i__1, &c_b57, &c__[(*k + 1) * c_dim1 + 1], ldc, & + v[(*k + 1) * v_dim1 + 1], ldv, &c_b57, &work[ + work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + ztrmm_("Right", "Upper", trans, "Non-unit", &lastc, k, &c_b57, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V */ + + if (lastv > *k) { + +/* C2 := C2 - W * V2 */ + + i__1 = lastv - *k; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "No transpose", &lastc, &i__1, k, & + z__1, &work[work_offset], ldwork, &v[(*k + 1) * + v_dim1 + 1], ldv, &c_b57, &c__[(*k + 1) * c_dim1 + + 1], ldc); + } + +/* W := W * V1 */ + + ztrmm_("Right", "Upper", "No transpose", "Unit", &lastc, k, & + c_b57, &v[v_offset], ldv, &work[work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * c_dim1; + i__4 = i__ + j * c_dim1; + i__5 = i__ + j * work_dim1; + z__1.r = c__[i__4].r - work[i__5].r, z__1.i = c__[ + i__4].i - work[i__5].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L170: */ + } +/* L180: */ + } + + } + + } else { + +/* + Let V = ( V1 V2 ) (V2: last K columns) + where V2 is unit lower triangular. +*/ + + if (lsame_(side, "L")) { + +/* + Form H * C or H' * C where C = ( C1 ) + ( C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilazlc_(k, m, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilazlc_(&lastv, n, &c__[c_offset], ldc); + +/* + W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK) + + W := C2' +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + zcopy_(&lastc, &c__[lastv - *k + j + c_dim1], ldc, &work[ + j * work_dim1 + 1], &c__1); + zlacgv_(&lastc, &work[j * work_dim1 + 1], &c__1); +/* L190: */ + } + +/* W := W * V2' */ + + ztrmm_("Right", "Lower", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[(lastv - *k + 1) * v_dim1 + 1], + ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1'*V1' */ + + i__1 = lastv - *k; + zgemm_("Conjugate transpose", "Conjugate transpose", & + lastc, k, &i__1, &c_b57, &c__[c_offset], ldc, &v[ + v_offset], ldv, &c_b57, &work[work_offset], + ldwork); + } + +/* W := W * T' or W * T */ + + ztrmm_("Right", "Lower", transt, "Non-unit", &lastc, k, & + c_b57, &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - V' * W' */ + + if (lastv > *k) { + +/* C1 := C1 - V1' * W' */ + + i__1 = lastv - *k; + z__1.r = -1., z__1.i = -0.; + zgemm_("Conjugate transpose", "Conjugate transpose", & + i__1, &lastc, k, &z__1, &v[v_offset], ldv, &work[ + work_offset], ldwork, &c_b57, &c__[c_offset], ldc); + } + +/* W := W * V2 */ + + ztrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b57, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + +/* C2 := C2 - W' */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = lastv - *k + j + i__ * c_dim1; + i__4 = lastv - *k + j + i__ * c_dim1; + d_cnjg(&z__2, &work[i__ + j * work_dim1]); + z__1.r = c__[i__4].r - z__2.r, z__1.i = c__[i__4].i - + z__2.i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L200: */ + } +/* L210: */ + } + + } else if (lsame_(side, "R")) { + +/* + Form C * H or C * H' where C = ( C1 C2 ) + + Computing MAX +*/ + i__1 = *k, i__2 = ilazlc_(k, n, &v[v_offset], ldv); + lastv = max(i__1,i__2); + lastc = ilazlr_(m, &lastv, &c__[c_offset], ldc); + +/* + W := C * V' = (C1*V1' + C2*V2') (stored in WORK) + + W := C2 +*/ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + zcopy_(&lastc, &c__[(lastv - *k + j) * c_dim1 + 1], &c__1, + &work[j * work_dim1 + 1], &c__1); +/* L220: */ + } + +/* W := W * V2' */ + + ztrmm_("Right", "Lower", "Conjugate transpose", "Unit", & + lastc, k, &c_b57, &v[(lastv - *k + 1) * v_dim1 + 1], + ldv, &work[work_offset], ldwork); + if (lastv > *k) { + +/* W := W + C1 * V1' */ + + i__1 = lastv - *k; + zgemm_("No transpose", "Conjugate transpose", &lastc, k, & + i__1, &c_b57, &c__[c_offset], ldc, &v[v_offset], + ldv, &c_b57, &work[work_offset], ldwork); + } + +/* W := W * T or W * T' */ + + ztrmm_("Right", "Lower", trans, "Non-unit", &lastc, k, &c_b57, + &t[t_offset], ldt, &work[work_offset], ldwork); + +/* C := C - W * V */ + + if (lastv > *k) { + +/* C1 := C1 - W * V1 */ + + i__1 = lastv - *k; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "No transpose", &lastc, &i__1, k, & + z__1, &work[work_offset], ldwork, &v[v_offset], + ldv, &c_b57, &c__[c_offset], ldc); + } + +/* W := W * V2 */ + + ztrmm_("Right", "Lower", "No transpose", "Unit", &lastc, k, & + c_b57, &v[(lastv - *k + 1) * v_dim1 + 1], ldv, &work[ + work_offset], ldwork); + +/* C1 := C1 - W */ + + i__1 = *k; + for (j = 1; j <= i__1; ++j) { + i__2 = lastc; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + (lastv - *k + j) * c_dim1; + i__4 = i__ + (lastv - *k + j) * c_dim1; + i__5 = i__ + j * work_dim1; + z__1.r = c__[i__4].r - work[i__5].r, z__1.i = c__[ + i__4].i - work[i__5].i; + c__[i__3].r = z__1.r, c__[i__3].i = z__1.i; +/* L230: */ + } +/* L240: */ + } + + } + + } + } + + return 0; + +/* End of ZLARFB */ + +} /* zlarfb_ */ + +/* Subroutine */ int zlarfg_(integer *n, doublecomplex *alpha, doublecomplex * + x, integer *incx, doublecomplex *tau) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer j, knt; + static doublereal beta, alphi, alphr; + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *); + static doublereal xnorm; + extern doublereal dlapy3_(doublereal *, doublereal *, doublereal *), + dznrm2_(integer *, doublecomplex *, integer *), dlamch_(char *); + static doublereal safmin; + extern /* Subroutine */ int zdscal_(integer *, doublereal *, + doublecomplex *, integer *); + static doublereal rsafmn; + extern /* Double Complex */ VOID zladiv_(doublecomplex *, doublecomplex *, + doublecomplex *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLARFG generates a complex elementary reflector H of order n, such + that + + H' * ( alpha ) = ( beta ), H' * H = I. + ( x ) ( 0 ) + + where alpha and beta are scalars, with beta real, and x is an + (n-1)-element complex vector. H is represented in the form + + H = I - tau * ( 1 ) * ( 1 v' ) , + ( v ) + + where tau is a complex scalar and v is a complex (n-1)-element + vector. Note that H is not hermitian. + + If the elements of x are all zero and alpha is real, then tau = 0 + and H is taken to be the unit matrix. + + Otherwise 1 <= real(tau) <= 2 and abs(tau-1) <= 1 . + + Arguments + ========= + + N (input) INTEGER + The order of the elementary reflector. + + ALPHA (input/output) COMPLEX*16 + On entry, the value alpha. + On exit, it is overwritten with the value beta. + + X (input/output) COMPLEX*16 array, dimension + (1+(N-2)*abs(INCX)) + On entry, the vector x. + On exit, it is overwritten with the vector v. + + INCX (input) INTEGER + The increment between elements of X. INCX > 0. + + TAU (output) COMPLEX*16 + The value tau. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n <= 0) { + tau->r = 0., tau->i = 0.; + return 0; + } + + i__1 = *n - 1; + xnorm = dznrm2_(&i__1, &x[1], incx); + alphr = alpha->r; + alphi = d_imag(alpha); + + if (xnorm == 0. && alphi == 0.) { + +/* H = I */ + + tau->r = 0., tau->i = 0.; + } else { + +/* general case */ + + d__1 = dlapy3_(&alphr, &alphi, &xnorm); + beta = -d_sign(&d__1, &alphr); + safmin = SAFEMINIMUM / EPSILON; + rsafmn = 1. / safmin; + + knt = 0; + if (abs(beta) < safmin) { + +/* XNORM, BETA may be inaccurate; scale X and recompute them */ + +L10: + ++knt; + i__1 = *n - 1; + zdscal_(&i__1, &rsafmn, &x[1], incx); + beta *= rsafmn; + alphi *= rsafmn; + alphr *= rsafmn; + if (abs(beta) < safmin) { + goto L10; + } + +/* New BETA is at most 1, at least SAFMIN */ + + i__1 = *n - 1; + xnorm = dznrm2_(&i__1, &x[1], incx); + z__1.r = alphr, z__1.i = alphi; + alpha->r = z__1.r, alpha->i = z__1.i; + d__1 = dlapy3_(&alphr, &alphi, &xnorm); + beta = -d_sign(&d__1, &alphr); + } + d__1 = (beta - alphr) / beta; + d__2 = -alphi / beta; + z__1.r = d__1, z__1.i = d__2; + tau->r = z__1.r, tau->i = z__1.i; + z__2.r = alpha->r - beta, z__2.i = alpha->i; + zladiv_(&z__1, &c_b57, &z__2); + alpha->r = z__1.r, alpha->i = z__1.i; + i__1 = *n - 1; + zscal_(&i__1, alpha, &x[1], incx); + +/* If ALPHA is subnormal, it may lose relative accuracy */ + + i__1 = knt; + for (j = 1; j <= i__1; ++j) { + beta *= safmin; +/* L20: */ + } + alpha->r = beta, alpha->i = 0.; + } + + return 0; + +/* End of ZLARFG */ + +} /* zlarfg_ */ + +/* Subroutine */ int zlarft_(char *direct, char *storev, integer *n, integer * + k, doublecomplex *v, integer *ldv, doublecomplex *tau, doublecomplex * + t, integer *ldt) +{ + /* System generated locals */ + integer t_dim1, t_offset, v_dim1, v_offset, i__1, i__2, i__3, i__4; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, prevlastv; + static doublecomplex vii; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zgemv_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *); + static integer lastv; + extern /* Subroutine */ int ztrmv_(char *, char *, char *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *), zlacgv_(integer *, doublecomplex *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLARFT forms the triangular factor T of a complex block reflector H + of order n, which is defined as a product of k elementary reflectors. + + If DIRECT = 'F', H = H(1) H(2) . . . H(k) and T is upper triangular; + + If DIRECT = 'B', H = H(k) . . . H(2) H(1) and T is lower triangular. + + If STOREV = 'C', the vector which defines the elementary reflector + H(i) is stored in the i-th column of the array V, and + + H = I - V * T * V' + + If STOREV = 'R', the vector which defines the elementary reflector + H(i) is stored in the i-th row of the array V, and + + H = I - V' * T * V + + Arguments + ========= + + DIRECT (input) CHARACTER*1 + Specifies the order in which the elementary reflectors are + multiplied to form the block reflector: + = 'F': H = H(1) H(2) . . . H(k) (Forward) + = 'B': H = H(k) . . . H(2) H(1) (Backward) + + STOREV (input) CHARACTER*1 + Specifies how the vectors which define the elementary + reflectors are stored (see also Further Details): + = 'C': columnwise + = 'R': rowwise + + N (input) INTEGER + The order of the block reflector H. N >= 0. + + K (input) INTEGER + The order of the triangular factor T (= the number of + elementary reflectors). K >= 1. + + V (input/output) COMPLEX*16 array, dimension + (LDV,K) if STOREV = 'C' + (LDV,N) if STOREV = 'R' + The matrix V. See further details. + + LDV (input) INTEGER + The leading dimension of the array V. + If STOREV = 'C', LDV >= max(1,N); if STOREV = 'R', LDV >= K. + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i). + + T (output) COMPLEX*16 array, dimension (LDT,K) + The k by k triangular factor T of the block reflector. + If DIRECT = 'F', T is upper triangular; if DIRECT = 'B', T is + lower triangular. The rest of the array is not used. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= K. + + Further Details + =============== + + The shape of the matrix V and the storage of the vectors which define + the H(i) is best illustrated by the following example with n = 5 and + k = 3. The elements equal to 1 are not stored; the corresponding + array elements are modified but restored on exit. The rest of the + array is not used. + + DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': + + V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) + ( v1 1 ) ( 1 v2 v2 v2 ) + ( v1 v2 1 ) ( 1 v3 v3 ) + ( v1 v2 v3 ) + ( v1 v2 v3 ) + + DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': + + V = ( v1 v2 v3 ) V = ( v1 v1 1 ) + ( v1 v2 v3 ) ( v2 v2 v2 1 ) + ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) + ( 1 v3 ) + ( 1 ) + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + v_dim1 = *ldv; + v_offset = 1 + v_dim1; + v -= v_offset; + --tau; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + + /* Function Body */ + if (*n == 0) { + return 0; + } + + if (lsame_(direct, "F")) { + prevlastv = *n; + i__1 = *k; + for (i__ = 1; i__ <= i__1; ++i__) { + prevlastv = max(prevlastv,i__); + i__2 = i__; + if (tau[i__2].r == 0. && tau[i__2].i == 0.) { + +/* H(i) = I */ + + i__2 = i__; + for (j = 1; j <= i__2; ++j) { + i__3 = j + i__ * t_dim1; + t[i__3].r = 0., t[i__3].i = 0.; +/* L10: */ + } + } else { + +/* general case */ + + i__2 = i__ + i__ * v_dim1; + vii.r = v[i__2].r, vii.i = v[i__2].i; + i__2 = i__ + i__ * v_dim1; + v[i__2].r = 1., v[i__2].i = 0.; + if (lsame_(storev, "C")) { +/* Skip any trailing zeros. */ + i__2 = i__ + 1; + for (lastv = *n; lastv >= i__2; --lastv) { + i__3 = lastv + i__ * v_dim1; + if (v[i__3].r != 0. || v[i__3].i != 0.) { + goto L15; + } + } +L15: + j = min(lastv,prevlastv); + +/* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)' * V(i:j,i) */ + + i__2 = j - i__ + 1; + i__3 = i__ - 1; + i__4 = i__; + z__1.r = -tau[i__4].r, z__1.i = -tau[i__4].i; + zgemv_("Conjugate transpose", &i__2, &i__3, &z__1, &v[i__ + + v_dim1], ldv, &v[i__ + i__ * v_dim1], &c__1, & + c_b56, &t[i__ * t_dim1 + 1], &c__1); + } else { +/* Skip any trailing zeros. */ + i__2 = i__ + 1; + for (lastv = *n; lastv >= i__2; --lastv) { + i__3 = i__ + lastv * v_dim1; + if (v[i__3].r != 0. || v[i__3].i != 0.) { + goto L16; + } + } +L16: + j = min(lastv,prevlastv); + +/* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)' */ + + if (i__ < j) { + i__2 = j - i__; + zlacgv_(&i__2, &v[i__ + (i__ + 1) * v_dim1], ldv); + } + i__2 = i__ - 1; + i__3 = j - i__ + 1; + i__4 = i__; + z__1.r = -tau[i__4].r, z__1.i = -tau[i__4].i; + zgemv_("No transpose", &i__2, &i__3, &z__1, &v[i__ * + v_dim1 + 1], ldv, &v[i__ + i__ * v_dim1], ldv, & + c_b56, &t[i__ * t_dim1 + 1], &c__1); + if (i__ < j) { + i__2 = j - i__; + zlacgv_(&i__2, &v[i__ + (i__ + 1) * v_dim1], ldv); + } + } + i__2 = i__ + i__ * v_dim1; + v[i__2].r = vii.r, v[i__2].i = vii.i; + +/* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */ + + i__2 = i__ - 1; + ztrmv_("Upper", "No transpose", "Non-unit", &i__2, &t[ + t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1); + i__2 = i__ + i__ * t_dim1; + i__3 = i__; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + if (i__ > 1) { + prevlastv = max(prevlastv,lastv); + } else { + prevlastv = lastv; + } + } +/* L20: */ + } + } else { + prevlastv = 1; + for (i__ = *k; i__ >= 1; --i__) { + i__1 = i__; + if (tau[i__1].r == 0. && tau[i__1].i == 0.) { + +/* H(i) = I */ + + i__1 = *k; + for (j = i__; j <= i__1; ++j) { + i__2 = j + i__ * t_dim1; + t[i__2].r = 0., t[i__2].i = 0.; +/* L30: */ + } + } else { + +/* general case */ + + if (i__ < *k) { + if (lsame_(storev, "C")) { + i__1 = *n - *k + i__ + i__ * v_dim1; + vii.r = v[i__1].r, vii.i = v[i__1].i; + i__1 = *n - *k + i__ + i__ * v_dim1; + v[i__1].r = 1., v[i__1].i = 0.; +/* Skip any leading zeros. */ + i__1 = i__ - 1; + for (lastv = 1; lastv <= i__1; ++lastv) { + i__2 = lastv + i__ * v_dim1; + if (v[i__2].r != 0. || v[i__2].i != 0.) { + goto L35; + } + } +L35: + j = max(lastv,prevlastv); + +/* + T(i+1:k,i) := + - tau(i) * V(j:n-k+i,i+1:k)' * V(j:n-k+i,i) +*/ + + i__1 = *n - *k + i__ - j + 1; + i__2 = *k - i__; + i__3 = i__; + z__1.r = -tau[i__3].r, z__1.i = -tau[i__3].i; + zgemv_("Conjugate transpose", &i__1, &i__2, &z__1, &v[ + j + (i__ + 1) * v_dim1], ldv, &v[j + i__ * + v_dim1], &c__1, &c_b56, &t[i__ + 1 + i__ * + t_dim1], &c__1); + i__1 = *n - *k + i__ + i__ * v_dim1; + v[i__1].r = vii.r, v[i__1].i = vii.i; + } else { + i__1 = i__ + (*n - *k + i__) * v_dim1; + vii.r = v[i__1].r, vii.i = v[i__1].i; + i__1 = i__ + (*n - *k + i__) * v_dim1; + v[i__1].r = 1., v[i__1].i = 0.; +/* Skip any leading zeros. */ + i__1 = i__ - 1; + for (lastv = 1; lastv <= i__1; ++lastv) { + i__2 = i__ + lastv * v_dim1; + if (v[i__2].r != 0. || v[i__2].i != 0.) { + goto L36; + } + } +L36: + j = max(lastv,prevlastv); + +/* + T(i+1:k,i) := + - tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)' +*/ + + i__1 = *n - *k + i__ - 1 - j + 1; + zlacgv_(&i__1, &v[i__ + j * v_dim1], ldv); + i__1 = *k - i__; + i__2 = *n - *k + i__ - j + 1; + i__3 = i__; + z__1.r = -tau[i__3].r, z__1.i = -tau[i__3].i; + zgemv_("No transpose", &i__1, &i__2, &z__1, &v[i__ + + 1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], + ldv, &c_b56, &t[i__ + 1 + i__ * t_dim1], & + c__1); + i__1 = *n - *k + i__ - 1 - j + 1; + zlacgv_(&i__1, &v[i__ + j * v_dim1], ldv); + i__1 = i__ + (*n - *k + i__) * v_dim1; + v[i__1].r = vii.r, v[i__1].i = vii.i; + } + +/* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */ + + i__1 = *k - i__; + ztrmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ + + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ * + t_dim1], &c__1) + ; + if (i__ > 1) { + prevlastv = min(prevlastv,lastv); + } else { + prevlastv = lastv; + } + } + i__1 = i__ + i__ * t_dim1; + i__2 = i__; + t[i__1].r = tau[i__2].r, t[i__1].i = tau[i__2].i; + } +/* L40: */ + } + } + return 0; + +/* End of ZLARFT */ + +} /* zlarft_ */ + +/* Subroutine */ int zlartg_(doublecomplex *f, doublecomplex *g, doublereal * + cs, doublecomplex *sn, doublecomplex *r__) +{ + /* System generated locals */ + integer i__1; + doublereal d__1, d__2, d__3, d__4, d__5, d__6, d__7, d__8, d__9, d__10; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static doublereal d__; + static integer i__; + static doublereal f2, g2; + static doublecomplex ff; + static doublereal di, dr; + static doublecomplex fs, gs; + static doublereal f2s, g2s, eps, scale; + static integer count; + static doublereal safmn2; + extern doublereal dlapy2_(doublereal *, doublereal *); + static doublereal safmx2; + + static doublereal safmin; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLARTG generates a plane rotation so that + + [ CS SN ] [ F ] [ R ] + [ __ ] . [ ] = [ ] where CS**2 + |SN|**2 = 1. + [ -SN CS ] [ G ] [ 0 ] + + This is a faster version of the BLAS1 routine ZROTG, except for + the following differences: + F and G are unchanged on return. + If G=0, then CS=1 and SN=0. + If F=0, then CS=0 and SN is chosen so that R is real. + + Arguments + ========= + + F (input) COMPLEX*16 + The first component of vector to be rotated. + + G (input) COMPLEX*16 + The second component of vector to be rotated. + + CS (output) DOUBLE PRECISION + The cosine of the rotation. + + SN (output) COMPLEX*16 + The sine of the rotation. + + R (output) COMPLEX*16 + The nonzero component of the rotated vector. + + Further Details + ======= ======= + + 3-5-96 - Modified with a new algorithm by W. Kahan and J. Demmel + + This version has a few statements commented out for thread safety + (machine parameters are computed on each entry). 10 feb 03, SJH. + + ===================================================================== + + LOGICAL FIRST + SAVE FIRST, SAFMX2, SAFMIN, SAFMN2 + DATA FIRST / .TRUE. / + + IF( FIRST ) THEN +*/ + safmin = SAFEMINIMUM; + eps = EPSILON; + d__1 = BASE; + i__1 = (integer) (log(safmin / eps) / log(BASE) / 2.); + safmn2 = pow_di(&d__1, &i__1); + safmx2 = 1. / safmn2; +/* + FIRST = .FALSE. + END IF + Computing MAX + Computing MAX +*/ + d__7 = (d__1 = f->r, abs(d__1)), d__8 = (d__2 = d_imag(f), abs(d__2)); +/* Computing MAX */ + d__9 = (d__3 = g->r, abs(d__3)), d__10 = (d__4 = d_imag(g), abs(d__4)); + d__5 = max(d__7,d__8), d__6 = max(d__9,d__10); + scale = max(d__5,d__6); + fs.r = f->r, fs.i = f->i; + gs.r = g->r, gs.i = g->i; + count = 0; + if (scale >= safmx2) { +L10: + ++count; + z__1.r = safmn2 * fs.r, z__1.i = safmn2 * fs.i; + fs.r = z__1.r, fs.i = z__1.i; + z__1.r = safmn2 * gs.r, z__1.i = safmn2 * gs.i; + gs.r = z__1.r, gs.i = z__1.i; + scale *= safmn2; + if (scale >= safmx2) { + goto L10; + } + } else if (scale <= safmn2) { + if (g->r == 0. && g->i == 0.) { + *cs = 1.; + sn->r = 0., sn->i = 0.; + r__->r = f->r, r__->i = f->i; + return 0; + } +L20: + --count; + z__1.r = safmx2 * fs.r, z__1.i = safmx2 * fs.i; + fs.r = z__1.r, fs.i = z__1.i; + z__1.r = safmx2 * gs.r, z__1.i = safmx2 * gs.i; + gs.r = z__1.r, gs.i = z__1.i; + scale *= safmx2; + if (scale <= safmn2) { + goto L20; + } + } +/* Computing 2nd power */ + d__1 = fs.r; +/* Computing 2nd power */ + d__2 = d_imag(&fs); + f2 = d__1 * d__1 + d__2 * d__2; +/* Computing 2nd power */ + d__1 = gs.r; +/* Computing 2nd power */ + d__2 = d_imag(&gs); + g2 = d__1 * d__1 + d__2 * d__2; + if (f2 <= max(g2,1.) * safmin) { + +/* This is a rare case: F is very small. */ + + if (f->r == 0. && f->i == 0.) { + *cs = 0.; + d__2 = g->r; + d__3 = d_imag(g); + d__1 = dlapy2_(&d__2, &d__3); + r__->r = d__1, r__->i = 0.; +/* Do complex/real division explicitly with two real divisions */ + d__1 = gs.r; + d__2 = d_imag(&gs); + d__ = dlapy2_(&d__1, &d__2); + d__1 = gs.r / d__; + d__2 = -d_imag(&gs) / d__; + z__1.r = d__1, z__1.i = d__2; + sn->r = z__1.r, sn->i = z__1.i; + return 0; + } + d__1 = fs.r; + d__2 = d_imag(&fs); + f2s = dlapy2_(&d__1, &d__2); +/* + G2 and G2S are accurate + G2 is at least SAFMIN, and G2S is at least SAFMN2 +*/ + g2s = sqrt(g2); +/* + Error in CS from underflow in F2S is at most + UNFL / SAFMN2 .lt. sqrt(UNFL*EPS) .lt. EPS + If MAX(G2,ONE)=G2, then F2 .lt. G2*SAFMIN, + and so CS .lt. sqrt(SAFMIN) + If MAX(G2,ONE)=ONE, then F2 .lt. SAFMIN + and so CS .lt. sqrt(SAFMIN)/SAFMN2 = sqrt(EPS) + Therefore, CS = F2S/G2S / sqrt( 1 + (F2S/G2S)**2 ) = F2S/G2S +*/ + *cs = f2s / g2s; +/* + Make sure abs(FF) = 1 + Do complex/real division explicitly with 2 real divisions + Computing MAX +*/ + d__3 = (d__1 = f->r, abs(d__1)), d__4 = (d__2 = d_imag(f), abs(d__2)); + if (max(d__3,d__4) > 1.) { + d__1 = f->r; + d__2 = d_imag(f); + d__ = dlapy2_(&d__1, &d__2); + d__1 = f->r / d__; + d__2 = d_imag(f) / d__; + z__1.r = d__1, z__1.i = d__2; + ff.r = z__1.r, ff.i = z__1.i; + } else { + dr = safmx2 * f->r; + di = safmx2 * d_imag(f); + d__ = dlapy2_(&dr, &di); + d__1 = dr / d__; + d__2 = di / d__; + z__1.r = d__1, z__1.i = d__2; + ff.r = z__1.r, ff.i = z__1.i; + } + d__1 = gs.r / g2s; + d__2 = -d_imag(&gs) / g2s; + z__2.r = d__1, z__2.i = d__2; + z__1.r = ff.r * z__2.r - ff.i * z__2.i, z__1.i = ff.r * z__2.i + ff.i + * z__2.r; + sn->r = z__1.r, sn->i = z__1.i; + z__2.r = *cs * f->r, z__2.i = *cs * f->i; + z__3.r = sn->r * g->r - sn->i * g->i, z__3.i = sn->r * g->i + sn->i * + g->r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + r__->r = z__1.r, r__->i = z__1.i; + } else { + +/* + This is the most common case. + Neither F2 nor F2/G2 are less than SAFMIN + F2S cannot overflow, and it is accurate +*/ + + f2s = sqrt(g2 / f2 + 1.); +/* Do the F2S(real)*FS(complex) multiply with two real multiplies */ + d__1 = f2s * fs.r; + d__2 = f2s * d_imag(&fs); + z__1.r = d__1, z__1.i = d__2; + r__->r = z__1.r, r__->i = z__1.i; + *cs = 1. / f2s; + d__ = f2 + g2; +/* Do complex/real division explicitly with two real divisions */ + d__1 = r__->r / d__; + d__2 = d_imag(r__) / d__; + z__1.r = d__1, z__1.i = d__2; + sn->r = z__1.r, sn->i = z__1.i; + d_cnjg(&z__2, &gs); + z__1.r = sn->r * z__2.r - sn->i * z__2.i, z__1.i = sn->r * z__2.i + + sn->i * z__2.r; + sn->r = z__1.r, sn->i = z__1.i; + if (count != 0) { + if (count > 0) { + i__1 = count; + for (i__ = 1; i__ <= i__1; ++i__) { + z__1.r = safmx2 * r__->r, z__1.i = safmx2 * r__->i; + r__->r = z__1.r, r__->i = z__1.i; +/* L30: */ + } + } else { + i__1 = -count; + for (i__ = 1; i__ <= i__1; ++i__) { + z__1.r = safmn2 * r__->r, z__1.i = safmn2 * r__->i; + r__->r = z__1.r, r__->i = z__1.i; +/* L40: */ + } + } + } + } + return 0; + +/* End of ZLARTG */ + +} /* zlartg_ */ + +/* Subroutine */ int zlascl_(char *type__, integer *kl, integer *ku, + doublereal *cfrom, doublereal *cto, integer *m, integer *n, + doublecomplex *a, integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, k1, k2, k3, k4; + static doublereal mul, cto1; + static logical done; + static doublereal ctoc; + extern logical lsame_(char *, char *); + static integer itype; + static doublereal cfrom1; + + static doublereal cfromc; + extern logical disnan_(doublereal *); + extern /* Subroutine */ int xerbla_(char *, integer *); + static doublereal bignum, smlnum; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLASCL multiplies the M by N complex matrix A by the real scalar + CTO/CFROM. This is done without over/underflow as long as the final + result CTO*A(I,J)/CFROM does not over/underflow. TYPE specifies that + A may be full, upper triangular, lower triangular, upper Hessenberg, + or banded. + + Arguments + ========= + + TYPE (input) CHARACTER*1 + TYPE indices the storage type of the input matrix. + = 'G': A is a full matrix. + = 'L': A is a lower triangular matrix. + = 'U': A is an upper triangular matrix. + = 'H': A is an upper Hessenberg matrix. + = 'B': A is a symmetric band matrix with lower bandwidth KL + and upper bandwidth KU and with the only the lower + half stored. + = 'Q': A is a symmetric band matrix with lower bandwidth KL + and upper bandwidth KU and with the only the upper + half stored. + = 'Z': A is a band matrix with lower bandwidth KL and upper + bandwidth KU. + + KL (input) INTEGER + The lower bandwidth of A. Referenced only if TYPE = 'B', + 'Q' or 'Z'. + + KU (input) INTEGER + The upper bandwidth of A. Referenced only if TYPE = 'B', + 'Q' or 'Z'. + + CFROM (input) DOUBLE PRECISION + CTO (input) DOUBLE PRECISION + The matrix A is multiplied by CTO/CFROM. A(I,J) is computed + without over/underflow if the final result CTO*A(I,J)/CFROM + can be represented without over/underflow. CFROM must be + nonzero. + + M (input) INTEGER + The number of rows of the matrix A. M >= 0. + + N (input) INTEGER + The number of columns of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + The matrix to be multiplied by CTO/CFROM. See TYPE for the + storage type. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + INFO (output) INTEGER + 0 - successful exit + <0 - if INFO = -i, the i-th argument had an illegal value. + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + + if (lsame_(type__, "G")) { + itype = 0; + } else if (lsame_(type__, "L")) { + itype = 1; + } else if (lsame_(type__, "U")) { + itype = 2; + } else if (lsame_(type__, "H")) { + itype = 3; + } else if (lsame_(type__, "B")) { + itype = 4; + } else if (lsame_(type__, "Q")) { + itype = 5; + } else if (lsame_(type__, "Z")) { + itype = 6; + } else { + itype = -1; + } + + if (itype == -1) { + *info = -1; + } else if (*cfrom == 0. || disnan_(cfrom)) { + *info = -4; + } else if (disnan_(cto)) { + *info = -5; + } else if (*m < 0) { + *info = -6; + } else if (*n < 0 || itype == 4 && *n != *m || itype == 5 && *n != *m) { + *info = -7; + } else if (itype <= 3 && *lda < max(1,*m)) { + *info = -9; + } else if (itype >= 4) { +/* Computing MAX */ + i__1 = *m - 1; + if (*kl < 0 || *kl > max(i__1,0)) { + *info = -2; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = *n - 1; + if (*ku < 0 || *ku > max(i__1,0) || (itype == 4 || itype == 5) && + *kl != *ku) { + *info = -3; + } else if (itype == 4 && *lda < *kl + 1 || itype == 5 && *lda < * + ku + 1 || itype == 6 && *lda < (*kl << 1) + *ku + 1) { + *info = -9; + } + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLASCL", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *m == 0) { + return 0; + } + +/* Get machine parameters */ + + smlnum = SAFEMINIMUM; + bignum = 1. / smlnum; + + cfromc = *cfrom; + ctoc = *cto; + +L10: + cfrom1 = cfromc * smlnum; + if (cfrom1 == cfromc) { +/* + CFROMC is an inf. Multiply by a correctly signed zero for + finite CTOC, or a NaN if CTOC is infinite. +*/ + mul = ctoc / cfromc; + done = TRUE_; + cto1 = ctoc; + } else { + cto1 = ctoc / bignum; + if (cto1 == ctoc) { +/* + CTOC is either 0 or an inf. In both cases, CTOC itself + serves as the correct multiplication factor. +*/ + mul = ctoc; + done = TRUE_; + cfromc = 1.; + } else if (abs(cfrom1) > abs(ctoc) && ctoc != 0.) { + mul = smlnum; + done = FALSE_; + cfromc = cfrom1; + } else if (abs(cto1) > abs(cfromc)) { + mul = bignum; + done = FALSE_; + ctoc = cto1; + } else { + mul = ctoc / cfromc; + done = TRUE_; + } + } + + if (itype == 0) { + +/* Full matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + z__1.r = mul * a[i__4].r, z__1.i = mul * a[i__4].i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L20: */ + } +/* L30: */ + } + + } else if (itype == 1) { + +/* Lower triangular matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + z__1.r = mul * a[i__4].r, z__1.i = mul * a[i__4].i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L40: */ + } +/* L50: */ + } + + } else if (itype == 2) { + +/* Upper triangular matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = min(j,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + z__1.r = mul * a[i__4].r, z__1.i = mul * a[i__4].i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L60: */ + } +/* L70: */ + } + + } else if (itype == 3) { + +/* Upper Hessenberg matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = j + 1; + i__2 = min(i__3,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + z__1.r = mul * a[i__4].r, z__1.i = mul * a[i__4].i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L80: */ + } +/* L90: */ + } + + } else if (itype == 4) { + +/* Lower half of a symmetric band matrix */ + + k3 = *kl + 1; + k4 = *n + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = k3, i__4 = k4 - j; + i__2 = min(i__3,i__4); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + z__1.r = mul * a[i__4].r, z__1.i = mul * a[i__4].i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L100: */ + } +/* L110: */ + } + + } else if (itype == 5) { + +/* Upper half of a symmetric band matrix */ + + k1 = *ku + 2; + k3 = *ku + 1; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = k1 - j; + i__3 = k3; + for (i__ = max(i__2,1); i__ <= i__3; ++i__) { + i__2 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + z__1.r = mul * a[i__4].r, z__1.i = mul * a[i__4].i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; +/* L120: */ + } +/* L130: */ + } + + } else if (itype == 6) { + +/* Band matrix */ + + k1 = *kl + *ku + 2; + k2 = *kl + 1; + k3 = (*kl << 1) + *ku + 1; + k4 = *kl + *ku + 1 + *m; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__3 = k1 - j; +/* Computing MIN */ + i__4 = k3, i__5 = k4 - j; + i__2 = min(i__4,i__5); + for (i__ = max(i__3,k2); i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + j * a_dim1; + z__1.r = mul * a[i__4].r, z__1.i = mul * a[i__4].i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L140: */ + } +/* L150: */ + } + + } + + if (! done) { + goto L10; + } + + return 0; + +/* End of ZLASCL */ + +} /* zlascl_ */ + +/* Subroutine */ int zlaset_(char *uplo, integer *m, integer *n, + doublecomplex *alpha, doublecomplex *beta, doublecomplex *a, integer * + lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j; + extern logical lsame_(char *, char *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLASET initializes a 2-D array A to BETA on the diagonal and + ALPHA on the offdiagonals. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies the part of the matrix A to be set. + = 'U': Upper triangular part is set. The lower triangle + is unchanged. + = 'L': Lower triangular part is set. The upper triangle + is unchanged. + Otherwise: All of the matrix A is set. + + M (input) INTEGER + On entry, M specifies the number of rows of A. + + N (input) INTEGER + On entry, N specifies the number of columns of A. + + ALPHA (input) COMPLEX*16 + All the offdiagonal array elements are set to ALPHA. + + BETA (input) COMPLEX*16 + All the diagonal array elements are set to BETA. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the m by n matrix A. + On exit, A(i,j) = ALPHA, 1 <= i <= m, 1 <= j <= n, i.ne.j; + A(i,i) = BETA , 1 <= i <= min(m,n) + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + if (lsame_(uplo, "U")) { + +/* + Set the diagonal to BETA and the strictly upper triangular + part of the array to ALPHA. +*/ + + i__1 = *n; + for (j = 2; j <= i__1; ++j) { +/* Computing MIN */ + i__3 = j - 1; + i__2 = min(i__3,*m); + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = alpha->r, a[i__3].i = alpha->i; +/* L10: */ + } +/* L20: */ + } + i__1 = min(*n,*m); + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = beta->r, a[i__2].i = beta->i; +/* L30: */ + } + + } else if (lsame_(uplo, "L")) { + +/* + Set the diagonal to BETA and the strictly lower triangular + part of the array to ALPHA. +*/ + + i__1 = min(*m,*n); + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = alpha->r, a[i__3].i = alpha->i; +/* L40: */ + } +/* L50: */ + } + i__1 = min(*n,*m); + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = beta->r, a[i__2].i = beta->i; +/* L60: */ + } + + } else { + +/* + Set the array to BETA on the diagonal and ALPHA on the + offdiagonal. +*/ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = alpha->r, a[i__3].i = alpha->i; +/* L70: */ + } +/* L80: */ + } + i__1 = min(*m,*n); + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + a[i__2].r = beta->r, a[i__2].i = beta->i; +/* L90: */ + } + } + + return 0; + +/* End of ZLASET */ + +} /* zlaset_ */ + +/* Subroutine */ int zlasr_(char *side, char *pivot, char *direct, integer *m, + integer *n, doublereal *c__, doublereal *s, doublecomplex *a, + integer *lda) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + doublecomplex z__1, z__2, z__3; + + /* Local variables */ + static integer i__, j, info; + static doublecomplex temp; + extern logical lsame_(char *, char *); + static doublereal ctemp, stemp; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLASR applies a sequence of real plane rotations to a complex matrix + A, from either the left or the right. + + When SIDE = 'L', the transformation takes the form + + A := P*A + + and when SIDE = 'R', the transformation takes the form + + A := A*P**T + + where P is an orthogonal matrix consisting of a sequence of z plane + rotations, with z = M when SIDE = 'L' and z = N when SIDE = 'R', + and P**T is the transpose of P. + + When DIRECT = 'F' (Forward sequence), then + + P = P(z-1) * ... * P(2) * P(1) + + and when DIRECT = 'B' (Backward sequence), then + + P = P(1) * P(2) * ... * P(z-1) + + where P(k) is a plane rotation matrix defined by the 2-by-2 rotation + + R(k) = ( c(k) s(k) ) + = ( -s(k) c(k) ). + + When PIVOT = 'V' (Variable pivot), the rotation is performed + for the plane (k,k+1), i.e., P(k) has the form + + P(k) = ( 1 ) + ( ... ) + ( 1 ) + ( c(k) s(k) ) + ( -s(k) c(k) ) + ( 1 ) + ( ... ) + ( 1 ) + + where R(k) appears as a rank-2 modification to the identity matrix in + rows and columns k and k+1. + + When PIVOT = 'T' (Top pivot), the rotation is performed for the + plane (1,k+1), so P(k) has the form + + P(k) = ( c(k) s(k) ) + ( 1 ) + ( ... ) + ( 1 ) + ( -s(k) c(k) ) + ( 1 ) + ( ... ) + ( 1 ) + + where R(k) appears in rows and columns 1 and k+1. + + Similarly, when PIVOT = 'B' (Bottom pivot), the rotation is + performed for the plane (k,z), giving P(k) the form + + P(k) = ( 1 ) + ( ... ) + ( 1 ) + ( c(k) s(k) ) + ( 1 ) + ( ... ) + ( 1 ) + ( -s(k) c(k) ) + + where R(k) appears in rows and columns k and z. The rotations are + performed without ever forming P(k) explicitly. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + Specifies whether the plane rotation matrix P is applied to + A on the left or the right. + = 'L': Left, compute A := P*A + = 'R': Right, compute A:= A*P**T + + PIVOT (input) CHARACTER*1 + Specifies the plane for which P(k) is a plane rotation + matrix. + = 'V': Variable pivot, the plane (k,k+1) + = 'T': Top pivot, the plane (1,k+1) + = 'B': Bottom pivot, the plane (k,z) + + DIRECT (input) CHARACTER*1 + Specifies whether P is a forward or backward sequence of + plane rotations. + = 'F': Forward, P = P(z-1)*...*P(2)*P(1) + = 'B': Backward, P = P(1)*P(2)*...*P(z-1) + + M (input) INTEGER + The number of rows of the matrix A. If m <= 1, an immediate + return is effected. + + N (input) INTEGER + The number of columns of the matrix A. If n <= 1, an + immediate return is effected. + + C (input) DOUBLE PRECISION array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + The cosines c(k) of the plane rotations. + + S (input) DOUBLE PRECISION array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + The sines s(k) of the plane rotations. The 2-by-2 plane + rotation part of the matrix P(k), R(k), has the form + R(k) = ( c(k) s(k) ) + ( -s(k) c(k) ). + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + The M-by-N matrix A. On exit, A is overwritten by P*A if + SIDE = 'R' or by A*P**T if SIDE = 'L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,M). + + ===================================================================== + + + Test the input parameters +*/ + + /* Parameter adjustments */ + --c__; + --s; + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + info = 0; + if (! (lsame_(side, "L") || lsame_(side, "R"))) { + info = 1; + } else if (! (lsame_(pivot, "V") || lsame_(pivot, + "T") || lsame_(pivot, "B"))) { + info = 2; + } else if (! (lsame_(direct, "F") || lsame_(direct, + "B"))) { + info = 3; + } else if (*m < 0) { + info = 4; + } else if (*n < 0) { + info = 5; + } else if (*lda < max(1,*m)) { + info = 9; + } + if (info != 0) { + xerbla_("ZLASR ", &info); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + if (lsame_(side, "L")) { + +/* Form P * A */ + + if (lsame_(pivot, "V")) { + if (lsame_(direct, "F")) { + i__1 = *m - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + 1 + i__ * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = j + 1 + i__ * a_dim1; + z__2.r = ctemp * temp.r, z__2.i = ctemp * temp.i; + i__4 = j + i__ * a_dim1; + z__3.r = stemp * a[i__4].r, z__3.i = stemp * a[ + i__4].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + i__3 = j + i__ * a_dim1; + z__2.r = stemp * temp.r, z__2.i = stemp * temp.i; + i__4 = j + i__ * a_dim1; + z__3.r = ctemp * a[i__4].r, z__3.i = ctemp * a[ + i__4].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L10: */ + } + } +/* L20: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = j + 1 + i__ * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = j + 1 + i__ * a_dim1; + z__2.r = ctemp * temp.r, z__2.i = ctemp * temp.i; + i__3 = j + i__ * a_dim1; + z__3.r = stemp * a[i__3].r, z__3.i = stemp * a[ + i__3].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; + i__2 = j + i__ * a_dim1; + z__2.r = stemp * temp.r, z__2.i = stemp * temp.i; + i__3 = j + i__ * a_dim1; + z__3.r = ctemp * a[i__3].r, z__3.i = ctemp * a[ + i__3].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; +/* L30: */ + } + } +/* L40: */ + } + } + } else if (lsame_(pivot, "T")) { + if (lsame_(direct, "F")) { + i__1 = *m; + for (j = 2; j <= i__1; ++j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = j + i__ * a_dim1; + z__2.r = ctemp * temp.r, z__2.i = ctemp * temp.i; + i__4 = i__ * a_dim1 + 1; + z__3.r = stemp * a[i__4].r, z__3.i = stemp * a[ + i__4].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + i__3 = i__ * a_dim1 + 1; + z__2.r = stemp * temp.r, z__2.i = stemp * temp.i; + i__4 = i__ * a_dim1 + 1; + z__3.r = ctemp * a[i__4].r, z__3.i = ctemp * a[ + i__4].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L50: */ + } + } +/* L60: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m; j >= 2; --j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = j + i__ * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = j + i__ * a_dim1; + z__2.r = ctemp * temp.r, z__2.i = ctemp * temp.i; + i__3 = i__ * a_dim1 + 1; + z__3.r = stemp * a[i__3].r, z__3.i = stemp * a[ + i__3].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; + i__2 = i__ * a_dim1 + 1; + z__2.r = stemp * temp.r, z__2.i = stemp * temp.i; + i__3 = i__ * a_dim1 + 1; + z__3.r = ctemp * a[i__3].r, z__3.i = ctemp * a[ + i__3].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; +/* L70: */ + } + } +/* L80: */ + } + } + } else if (lsame_(pivot, "B")) { + if (lsame_(direct, "F")) { + i__1 = *m - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = j + i__ * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = j + i__ * a_dim1; + i__4 = *m + i__ * a_dim1; + z__2.r = stemp * a[i__4].r, z__2.i = stemp * a[ + i__4].i; + z__3.r = ctemp * temp.r, z__3.i = ctemp * temp.i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + i__3 = *m + i__ * a_dim1; + i__4 = *m + i__ * a_dim1; + z__2.r = ctemp * a[i__4].r, z__2.i = ctemp * a[ + i__4].i; + z__3.r = stemp * temp.r, z__3.i = stemp * temp.i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L90: */ + } + } +/* L100: */ + } + } else if (lsame_(direct, "B")) { + for (j = *m - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = j + i__ * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = j + i__ * a_dim1; + i__3 = *m + i__ * a_dim1; + z__2.r = stemp * a[i__3].r, z__2.i = stemp * a[ + i__3].i; + z__3.r = ctemp * temp.r, z__3.i = ctemp * temp.i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; + i__2 = *m + i__ * a_dim1; + i__3 = *m + i__ * a_dim1; + z__2.r = ctemp * a[i__3].r, z__2.i = ctemp * a[ + i__3].i; + z__3.r = stemp * temp.r, z__3.i = stemp * temp.i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; +/* L110: */ + } + } +/* L120: */ + } + } + } + } else if (lsame_(side, "R")) { + +/* Form A * P' */ + + if (lsame_(pivot, "V")) { + if (lsame_(direct, "F")) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + (j + 1) * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = i__ + (j + 1) * a_dim1; + z__2.r = ctemp * temp.r, z__2.i = ctemp * temp.i; + i__4 = i__ + j * a_dim1; + z__3.r = stemp * a[i__4].r, z__3.i = stemp * a[ + i__4].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + i__3 = i__ + j * a_dim1; + z__2.r = stemp * temp.r, z__2.i = stemp * temp.i; + i__4 = i__ + j * a_dim1; + z__3.r = ctemp * a[i__4].r, z__3.i = ctemp * a[ + i__4].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L130: */ + } + } +/* L140: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + (j + 1) * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = i__ + (j + 1) * a_dim1; + z__2.r = ctemp * temp.r, z__2.i = ctemp * temp.i; + i__3 = i__ + j * a_dim1; + z__3.r = stemp * a[i__3].r, z__3.i = stemp * a[ + i__3].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; + i__2 = i__ + j * a_dim1; + z__2.r = stemp * temp.r, z__2.i = stemp * temp.i; + i__3 = i__ + j * a_dim1; + z__3.r = ctemp * a[i__3].r, z__3.i = ctemp * a[ + i__3].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; +/* L150: */ + } + } +/* L160: */ + } + } + } else if (lsame_(pivot, "T")) { + if (lsame_(direct, "F")) { + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = i__ + j * a_dim1; + z__2.r = ctemp * temp.r, z__2.i = ctemp * temp.i; + i__4 = i__ + a_dim1; + z__3.r = stemp * a[i__4].r, z__3.i = stemp * a[ + i__4].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + i__3 = i__ + a_dim1; + z__2.r = stemp * temp.r, z__2.i = stemp * temp.i; + i__4 = i__ + a_dim1; + z__3.r = ctemp * a[i__4].r, z__3.i = ctemp * a[ + i__4].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L170: */ + } + } +/* L180: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n; j >= 2; --j) { + ctemp = c__[j - 1]; + stemp = s[j - 1]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = i__ + j * a_dim1; + z__2.r = ctemp * temp.r, z__2.i = ctemp * temp.i; + i__3 = i__ + a_dim1; + z__3.r = stemp * a[i__3].r, z__3.i = stemp * a[ + i__3].i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; + i__2 = i__ + a_dim1; + z__2.r = stemp * temp.r, z__2.i = stemp * temp.i; + i__3 = i__ + a_dim1; + z__3.r = ctemp * a[i__3].r, z__3.i = ctemp * a[ + i__3].i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; +/* L190: */ + } + } +/* L200: */ + } + } + } else if (lsame_(pivot, "B")) { + if (lsame_(direct, "F")) { + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + temp.r = a[i__3].r, temp.i = a[i__3].i; + i__3 = i__ + j * a_dim1; + i__4 = i__ + *n * a_dim1; + z__2.r = stemp * a[i__4].r, z__2.i = stemp * a[ + i__4].i; + z__3.r = ctemp * temp.r, z__3.i = ctemp * temp.i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; + i__3 = i__ + *n * a_dim1; + i__4 = i__ + *n * a_dim1; + z__2.r = ctemp * a[i__4].r, z__2.i = ctemp * a[ + i__4].i; + z__3.r = stemp * temp.r, z__3.i = stemp * temp.i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__3].r = z__1.r, a[i__3].i = z__1.i; +/* L210: */ + } + } +/* L220: */ + } + } else if (lsame_(direct, "B")) { + for (j = *n - 1; j >= 1; --j) { + ctemp = c__[j]; + stemp = s[j]; + if (ctemp != 1. || stemp != 0.) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * a_dim1; + temp.r = a[i__2].r, temp.i = a[i__2].i; + i__2 = i__ + j * a_dim1; + i__3 = i__ + *n * a_dim1; + z__2.r = stemp * a[i__3].r, z__2.i = stemp * a[ + i__3].i; + z__3.r = ctemp * temp.r, z__3.i = ctemp * temp.i; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; + i__2 = i__ + *n * a_dim1; + i__3 = i__ + *n * a_dim1; + z__2.r = ctemp * a[i__3].r, z__2.i = ctemp * a[ + i__3].i; + z__3.r = stemp * temp.r, z__3.i = stemp * temp.i; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - + z__3.i; + a[i__2].r = z__1.r, a[i__2].i = z__1.i; +/* L230: */ + } + } +/* L240: */ + } + } + } + } + + return 0; + +/* End of ZLASR */ + +} /* zlasr_ */ + +/* Subroutine */ int zlassq_(integer *n, doublecomplex *x, integer *incx, + doublereal *scale, doublereal *sumsq) +{ + /* System generated locals */ + integer i__1, i__2, i__3; + doublereal d__1; + + /* Local variables */ + static integer ix; + static doublereal temp1; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLASSQ returns the values scl and ssq such that + + ( scl**2 )*ssq = x( 1 )**2 +...+ x( n )**2 + ( scale**2 )*sumsq, + + where x( i ) = abs( X( 1 + ( i - 1 )*INCX ) ). The value of sumsq is + assumed to be at least unity and the value of ssq will then satisfy + + 1.0 .le. ssq .le. ( sumsq + 2*n ). + + scale is assumed to be non-negative and scl returns the value + + scl = max( scale, abs( real( x( i ) ) ), abs( aimag( x( i ) ) ) ), + i + + scale and sumsq must be supplied in SCALE and SUMSQ respectively. + SCALE and SUMSQ are overwritten by scl and ssq respectively. + + The routine makes only one pass through the vector X. + + Arguments + ========= + + N (input) INTEGER + The number of elements to be used from the vector X. + + X (input) COMPLEX*16 array, dimension (N) + The vector x as described above. + x( i ) = X( 1 + ( i - 1 )*INCX ), 1 <= i <= n. + + INCX (input) INTEGER + The increment between successive values of the vector X. + INCX > 0. + + SCALE (input/output) DOUBLE PRECISION + On entry, the value scale in the equation above. + On exit, SCALE is overwritten with the value scl . + + SUMSQ (input/output) DOUBLE PRECISION + On entry, the value sumsq in the equation above. + On exit, SUMSQ is overwritten with the value ssq . + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --x; + + /* Function Body */ + if (*n > 0) { + i__1 = (*n - 1) * *incx + 1; + i__2 = *incx; + for (ix = 1; i__2 < 0 ? ix >= i__1 : ix <= i__1; ix += i__2) { + i__3 = ix; + if (x[i__3].r != 0.) { + i__3 = ix; + temp1 = (d__1 = x[i__3].r, abs(d__1)); + if (*scale < temp1) { +/* Computing 2nd power */ + d__1 = *scale / temp1; + *sumsq = *sumsq * (d__1 * d__1) + 1; + *scale = temp1; + } else { +/* Computing 2nd power */ + d__1 = temp1 / *scale; + *sumsq += d__1 * d__1; + } + } + if (d_imag(&x[ix]) != 0.) { + temp1 = (d__1 = d_imag(&x[ix]), abs(d__1)); + if (*scale < temp1) { +/* Computing 2nd power */ + d__1 = *scale / temp1; + *sumsq = *sumsq * (d__1 * d__1) + 1; + *scale = temp1; + } else { +/* Computing 2nd power */ + d__1 = temp1 / *scale; + *sumsq += d__1 * d__1; + } + } +/* L10: */ + } + } + + return 0; + +/* End of ZLASSQ */ + +} /* zlassq_ */ + +/* Subroutine */ int zlaswp_(integer *n, doublecomplex *a, integer *lda, + integer *k1, integer *k2, integer *ipiv, integer *incx) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5, i__6; + + /* Local variables */ + static integer i__, j, k, i1, i2, n32, ip, ix, ix0, inc; + static doublecomplex temp; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLASWP performs a series of row interchanges on the matrix A. + One row interchange is initiated for each of rows K1 through K2 of A. + + Arguments + ========= + + N (input) INTEGER + The number of columns of the matrix A. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the matrix of column dimension N to which the row + interchanges will be applied. + On exit, the permuted matrix. + + LDA (input) INTEGER + The leading dimension of the array A. + + K1 (input) INTEGER + The first element of IPIV for which a row interchange will + be done. + + K2 (input) INTEGER + The last element of IPIV for which a row interchange will + be done. + + IPIV (input) INTEGER array, dimension (K2*abs(INCX)) + The vector of pivot indices. Only the elements in positions + K1 through K2 of IPIV are accessed. + IPIV(K) = L implies rows K and L are to be interchanged. + + INCX (input) INTEGER + The increment between successive values of IPIV. If IPIV + is negative, the pivots are applied in reverse order. + + Further Details + =============== + + Modified by + R. C. Whaley, Computer Science Dept., Univ. of Tenn., Knoxville, USA + + ===================================================================== + + + Interchange row I with row IPIV(I) for each of rows K1 through K2. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --ipiv; + + /* Function Body */ + if (*incx > 0) { + ix0 = *k1; + i1 = *k1; + i2 = *k2; + inc = 1; + } else if (*incx < 0) { + ix0 = (1 - *k2) * *incx + 1; + i1 = *k2; + i2 = *k1; + inc = -1; + } else { + return 0; + } + + n32 = *n / 32 << 5; + if (n32 != 0) { + i__1 = n32; + for (j = 1; j <= i__1; j += 32) { + ix = ix0; + i__2 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__3) + { + ip = ipiv[ix]; + if (ip != i__) { + i__4 = j + 31; + for (k = j; k <= i__4; ++k) { + i__5 = i__ + k * a_dim1; + temp.r = a[i__5].r, temp.i = a[i__5].i; + i__5 = i__ + k * a_dim1; + i__6 = ip + k * a_dim1; + a[i__5].r = a[i__6].r, a[i__5].i = a[i__6].i; + i__5 = ip + k * a_dim1; + a[i__5].r = temp.r, a[i__5].i = temp.i; +/* L10: */ + } + } + ix += *incx; +/* L20: */ + } +/* L30: */ + } + } + if (n32 != *n) { + ++n32; + ix = ix0; + i__1 = i2; + i__3 = inc; + for (i__ = i1; i__3 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__3) { + ip = ipiv[ix]; + if (ip != i__) { + i__2 = *n; + for (k = n32; k <= i__2; ++k) { + i__4 = i__ + k * a_dim1; + temp.r = a[i__4].r, temp.i = a[i__4].i; + i__4 = i__ + k * a_dim1; + i__5 = ip + k * a_dim1; + a[i__4].r = a[i__5].r, a[i__4].i = a[i__5].i; + i__4 = ip + k * a_dim1; + a[i__4].r = temp.r, a[i__4].i = temp.i; +/* L40: */ + } + } + ix += *incx; +/* L50: */ + } + } + + return 0; + +/* End of ZLASWP */ + +} /* zlaswp_ */ + +/* Subroutine */ int zlatrd_(char *uplo, integer *n, integer *nb, + doublecomplex *a, integer *lda, doublereal *e, doublecomplex *tau, + doublecomplex *w, integer *ldw) +{ + /* System generated locals */ + integer a_dim1, a_offset, w_dim1, w_offset, i__1, i__2, i__3; + doublereal d__1; + doublecomplex z__1, z__2, z__3, z__4; + + /* Local variables */ + static integer i__, iw; + static doublecomplex alpha; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *); + extern /* Double Complex */ VOID zdotc_(doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *); + extern /* Subroutine */ int zgemv_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *), + zhemv_(char *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *), zaxpy_(integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *), zlarfg_(integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), zlacgv_(integer *, doublecomplex *, + integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLATRD reduces NB rows and columns of a complex Hermitian matrix A to + Hermitian tridiagonal form by a unitary similarity + transformation Q' * A * Q, and returns the matrices V and W which are + needed to apply the transformation to the unreduced part of A. + + If UPLO = 'U', ZLATRD reduces the last NB rows and columns of a + matrix, of which the upper triangle is supplied; + if UPLO = 'L', ZLATRD reduces the first NB rows and columns of a + matrix, of which the lower triangle is supplied. + + This is an auxiliary routine called by ZHETRD. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + Hermitian matrix A is stored: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. + + NB (input) INTEGER + The number of rows and columns to be reduced. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + n-by-n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n-by-n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + On exit: + if UPLO = 'U', the last NB columns have been reduced to + tridiagonal form, with the diagonal elements overwriting + the diagonal elements of A; the elements above the diagonal + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors; + if UPLO = 'L', the first NB columns have been reduced to + tridiagonal form, with the diagonal elements overwriting + the diagonal elements of A; the elements below the diagonal + with the array TAU, represent the unitary matrix Q as a + product of elementary reflectors. + See Further Details. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + E (output) DOUBLE PRECISION array, dimension (N-1) + If UPLO = 'U', E(n-nb:n-1) contains the superdiagonal + elements of the last NB columns of the reduced matrix; + if UPLO = 'L', E(1:nb) contains the subdiagonal elements of + the first NB columns of the reduced matrix. + + TAU (output) COMPLEX*16 array, dimension (N-1) + The scalar factors of the elementary reflectors, stored in + TAU(n-nb:n-1) if UPLO = 'U', and in TAU(1:nb) if UPLO = 'L'. + See Further Details. + + W (output) COMPLEX*16 array, dimension (LDW,NB) + The n-by-nb matrix W required to update the unreduced part + of A. + + LDW (input) INTEGER + The leading dimension of the array W. LDW >= max(1,N). + + Further Details + =============== + + If UPLO = 'U', the matrix Q is represented as a product of elementary + reflectors + + Q = H(n) H(n-1) . . . H(n-nb+1). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i:n) = 0 and v(i-1) = 1; v(1:i-1) is stored on exit in A(1:i-1,i), + and tau in TAU(i-1). + + If UPLO = 'L', the matrix Q is represented as a product of elementary + reflectors + + Q = H(1) H(2) . . . H(nb). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(1:i) = 0 and v(i+1) = 1; v(i+1:n) is stored on exit in A(i+1:n,i), + and tau in TAU(i). + + The elements of the vectors v together form the n-by-nb matrix V + which is needed, with W, to apply the transformation to the unreduced + part of the matrix, using a Hermitian rank-2k update of the form: + A := A - V*W' - W*V'. + + The contents of A on exit are illustrated by the following examples + with n = 5 and nb = 2: + + if UPLO = 'U': if UPLO = 'L': + + ( a a a v4 v5 ) ( d ) + ( a a v4 v5 ) ( 1 d ) + ( a 1 v5 ) ( v1 1 a ) + ( d 1 ) ( v1 v2 a a ) + ( d ) ( v1 v2 a a a ) + + where d denotes a diagonal element of the reduced matrix, a denotes + an element of the original matrix that is unchanged, and vi denotes + an element of the vector defining H(i). + + ===================================================================== + + + Quick return if possible +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --e; + --tau; + w_dim1 = *ldw; + w_offset = 1 + w_dim1; + w -= w_offset; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + + if (lsame_(uplo, "U")) { + +/* Reduce last NB columns of upper triangle */ + + i__1 = *n - *nb + 1; + for (i__ = *n; i__ >= i__1; --i__) { + iw = i__ - *n + *nb; + if (i__ < *n) { + +/* Update A(1:i,i) */ + + i__2 = i__ + i__ * a_dim1; + i__3 = i__ + i__ * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + i__2 = *n - i__; + zlacgv_(&i__2, &w[i__ + (iw + 1) * w_dim1], ldw); + i__2 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__, &i__2, &z__1, &a[(i__ + 1) * + a_dim1 + 1], lda, &w[i__ + (iw + 1) * w_dim1], ldw, & + c_b57, &a[i__ * a_dim1 + 1], &c__1); + i__2 = *n - i__; + zlacgv_(&i__2, &w[i__ + (iw + 1) * w_dim1], ldw); + i__2 = *n - i__; + zlacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__, &i__2, &z__1, &w[(iw + 1) * + w_dim1 + 1], ldw, &a[i__ + (i__ + 1) * a_dim1], lda, & + c_b57, &a[i__ * a_dim1 + 1], &c__1); + i__2 = *n - i__; + zlacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + i__3 = i__ + i__ * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + } + if (i__ > 1) { + +/* + Generate elementary reflector H(i) to annihilate + A(1:i-2,i) +*/ + + i__2 = i__ - 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = i__ - 1; + zlarfg_(&i__2, &alpha, &a[i__ * a_dim1 + 1], &c__1, &tau[i__ + - 1]); + i__2 = i__ - 1; + e[i__2] = alpha.r; + i__2 = i__ - 1 + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Compute W(1:i-1,i) */ + + i__2 = i__ - 1; + zhemv_("Upper", &i__2, &c_b57, &a[a_offset], lda, &a[i__ * + a_dim1 + 1], &c__1, &c_b56, &w[iw * w_dim1 + 1], & + c__1); + if (i__ < *n) { + i__2 = i__ - 1; + i__3 = *n - i__; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &w[( + iw + 1) * w_dim1 + 1], ldw, &a[i__ * a_dim1 + 1], + &c__1, &c_b56, &w[i__ + 1 + iw * w_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &a[(i__ + 1) * + a_dim1 + 1], lda, &w[i__ + 1 + iw * w_dim1], & + c__1, &c_b57, &w[iw * w_dim1 + 1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[( + i__ + 1) * a_dim1 + 1], lda, &a[i__ * a_dim1 + 1], + &c__1, &c_b56, &w[i__ + 1 + iw * w_dim1], &c__1); + i__2 = i__ - 1; + i__3 = *n - i__; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &w[(iw + 1) * + w_dim1 + 1], ldw, &w[i__ + 1 + iw * w_dim1], & + c__1, &c_b57, &w[iw * w_dim1 + 1], &c__1); + } + i__2 = i__ - 1; + zscal_(&i__2, &tau[i__ - 1], &w[iw * w_dim1 + 1], &c__1); + z__3.r = -.5, z__3.i = -0.; + i__2 = i__ - 1; + z__2.r = z__3.r * tau[i__2].r - z__3.i * tau[i__2].i, z__2.i = + z__3.r * tau[i__2].i + z__3.i * tau[i__2].r; + i__3 = i__ - 1; + zdotc_(&z__4, &i__3, &w[iw * w_dim1 + 1], &c__1, &a[i__ * + a_dim1 + 1], &c__1); + z__1.r = z__2.r * z__4.r - z__2.i * z__4.i, z__1.i = z__2.r * + z__4.i + z__2.i * z__4.r; + alpha.r = z__1.r, alpha.i = z__1.i; + i__2 = i__ - 1; + zaxpy_(&i__2, &alpha, &a[i__ * a_dim1 + 1], &c__1, &w[iw * + w_dim1 + 1], &c__1); + } + +/* L10: */ + } + } else { + +/* Reduce first NB columns of lower triangle */ + + i__1 = *nb; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Update A(i:n,i) */ + + i__2 = i__ + i__ * a_dim1; + i__3 = i__ + i__ * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + i__2 = i__ - 1; + zlacgv_(&i__2, &w[i__ + w_dim1], ldw); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &a[i__ + a_dim1], lda, + &w[i__ + w_dim1], ldw, &c_b57, &a[i__ + i__ * a_dim1], & + c__1); + i__2 = i__ - 1; + zlacgv_(&i__2, &w[i__ + w_dim1], ldw); + i__2 = i__ - 1; + zlacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = *n - i__ + 1; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &w[i__ + w_dim1], ldw, + &a[i__ + a_dim1], lda, &c_b57, &a[i__ + i__ * a_dim1], & + c__1); + i__2 = i__ - 1; + zlacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = i__ + i__ * a_dim1; + i__3 = i__ + i__ * a_dim1; + d__1 = a[i__3].r; + a[i__2].r = d__1, a[i__2].i = 0.; + if (i__ < *n) { + +/* + Generate elementary reflector H(i) to annihilate + A(i+2:n,i) +*/ + + i__2 = i__ + 1 + i__ * a_dim1; + alpha.r = a[i__2].r, alpha.i = a[i__2].i; + i__2 = *n - i__; +/* Computing MIN */ + i__3 = i__ + 2; + zlarfg_(&i__2, &alpha, &a[min(i__3,*n) + i__ * a_dim1], &c__1, + &tau[i__]); + i__2 = i__; + e[i__2] = alpha.r; + i__2 = i__ + 1 + i__ * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + +/* Compute W(i+1:n,i) */ + + i__2 = *n - i__; + zhemv_("Lower", &i__2, &c_b57, &a[i__ + 1 + (i__ + 1) * + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &w[i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &w[i__ + + 1 + w_dim1], ldw, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &w[i__ * w_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &a[i__ + 1 + + a_dim1], lda, &w[i__ * w_dim1 + 1], &c__1, &c_b57, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + 1 + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + c_b56, &w[i__ * w_dim1 + 1], &c__1); + i__2 = *n - i__; + i__3 = i__ - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &w[i__ + 1 + + w_dim1], ldw, &w[i__ * w_dim1 + 1], &c__1, &c_b57, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + i__2 = *n - i__; + zscal_(&i__2, &tau[i__], &w[i__ + 1 + i__ * w_dim1], &c__1); + z__3.r = -.5, z__3.i = -0.; + i__2 = i__; + z__2.r = z__3.r * tau[i__2].r - z__3.i * tau[i__2].i, z__2.i = + z__3.r * tau[i__2].i + z__3.i * tau[i__2].r; + i__3 = *n - i__; + zdotc_(&z__4, &i__3, &w[i__ + 1 + i__ * w_dim1], &c__1, &a[ + i__ + 1 + i__ * a_dim1], &c__1); + z__1.r = z__2.r * z__4.r - z__2.i * z__4.i, z__1.i = z__2.r * + z__4.i + z__2.i * z__4.r; + alpha.r = z__1.r, alpha.i = z__1.i; + i__2 = *n - i__; + zaxpy_(&i__2, &alpha, &a[i__ + 1 + i__ * a_dim1], &c__1, &w[ + i__ + 1 + i__ * w_dim1], &c__1); + } + +/* L20: */ + } + } + + return 0; + +/* End of ZLATRD */ + +} /* zlatrd_ */ + +/* Subroutine */ int zlatrs_(char *uplo, char *trans, char *diag, char * + normin, integer *n, doublecomplex *a, integer *lda, doublecomplex *x, + doublereal *scale, doublereal *cnorm, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1, d__2, d__3, d__4; + doublecomplex z__1, z__2, z__3, z__4; + + /* Local variables */ + static integer i__, j; + static doublereal xj, rec, tjj; + static integer jinc; + static doublereal xbnd; + static integer imax; + static doublereal tmax; + static doublecomplex tjjs; + static doublereal xmax, grow; + extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *, + integer *); + extern logical lsame_(char *, char *); + static doublereal tscal; + static doublecomplex uscal; + static integer jlast; + static doublecomplex csumj; + extern /* Double Complex */ VOID zdotc_(doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *); + static logical upper; + extern /* Double Complex */ VOID zdotu_(doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *); + extern /* Subroutine */ int zaxpy_(integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *), ztrsv_( + char *, char *, char *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *), dlabad_( + doublereal *, doublereal *); + + extern integer idamax_(integer *, doublereal *, integer *); + extern /* Subroutine */ int xerbla_(char *, integer *), zdscal_( + integer *, doublereal *, doublecomplex *, integer *); + static doublereal bignum; + extern integer izamax_(integer *, doublecomplex *, integer *); + extern /* Double Complex */ VOID zladiv_(doublecomplex *, doublecomplex *, + doublecomplex *); + static logical notran; + static integer jfirst; + extern doublereal dzasum_(integer *, doublecomplex *, integer *); + static doublereal smlnum; + static logical nounit; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLATRS solves one of the triangular systems + + A * x = s*b, A**T * x = s*b, or A**H * x = s*b, + + with scaling to prevent overflow. Here A is an upper or lower + triangular matrix, A**T denotes the transpose of A, A**H denotes the + conjugate transpose of A, x and b are n-element vectors, and s is a + scaling factor, usually less than or equal to 1, chosen so that the + components of x will be less than the overflow threshold. If the + unscaled problem will not cause overflow, the Level 2 BLAS routine + ZTRSV is called. If the matrix A is singular (A(j,j) = 0 for some j), + then s is set to 0 and a non-trivial solution to A*x = 0 is returned. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the matrix A is upper or lower triangular. + = 'U': Upper triangular + = 'L': Lower triangular + + TRANS (input) CHARACTER*1 + Specifies the operation applied to A. + = 'N': Solve A * x = s*b (No transpose) + = 'T': Solve A**T * x = s*b (Transpose) + = 'C': Solve A**H * x = s*b (Conjugate transpose) + + DIAG (input) CHARACTER*1 + Specifies whether or not the matrix A is unit triangular. + = 'N': Non-unit triangular + = 'U': Unit triangular + + NORMIN (input) CHARACTER*1 + Specifies whether CNORM has been set or not. + = 'Y': CNORM contains the column norms on entry + = 'N': CNORM is not set on entry. On exit, the norms will + be computed and stored in CNORM. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,N) + The triangular matrix A. If UPLO = 'U', the leading n by n + upper triangular part of the array A contains the upper + triangular matrix, and the strictly lower triangular part of + A is not referenced. If UPLO = 'L', the leading n by n lower + triangular part of the array A contains the lower triangular + matrix, and the strictly upper triangular part of A is not + referenced. If DIAG = 'U', the diagonal elements of A are + also not referenced and are assumed to be 1. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max (1,N). + + X (input/output) COMPLEX*16 array, dimension (N) + On entry, the right hand side b of the triangular system. + On exit, X is overwritten by the solution vector x. + + SCALE (output) DOUBLE PRECISION + The scaling factor s for the triangular system + A * x = s*b, A**T * x = s*b, or A**H * x = s*b. + If SCALE = 0, the matrix A is singular or badly scaled, and + the vector x is an exact or approximate solution to A*x = 0. + + CNORM (input or output) DOUBLE PRECISION array, dimension (N) + + If NORMIN = 'Y', CNORM is an input argument and CNORM(j) + contains the norm of the off-diagonal part of the j-th column + of A. If TRANS = 'N', CNORM(j) must be greater than or equal + to the infinity-norm, and if TRANS = 'T' or 'C', CNORM(j) + must be greater than or equal to the 1-norm. + + If NORMIN = 'N', CNORM is an output argument and CNORM(j) + returns the 1-norm of the offdiagonal part of the j-th column + of A. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + Further Details + ======= ======= + + A rough bound on x is computed; if that is less than overflow, ZTRSV + is called, otherwise, specific code is used which checks for possible + overflow or divide-by-zero at every operation. + + A columnwise scheme is used for solving A*x = b. The basic algorithm + if A is lower triangular is + + x[1:n] := b[1:n] + for j = 1, ..., n + x(j) := x(j) / A(j,j) + x[j+1:n] := x[j+1:n] - x(j) * A[j+1:n,j] + end + + Define bounds on the components of x after j iterations of the loop: + M(j) = bound on x[1:j] + G(j) = bound on x[j+1:n] + Initially, let M(0) = 0 and G(0) = max{x(i), i=1,...,n}. + + Then for iteration j+1 we have + M(j+1) <= G(j) / | A(j+1,j+1) | + G(j+1) <= G(j) + M(j+1) * | A[j+2:n,j+1] | + <= G(j) ( 1 + CNORM(j+1) / | A(j+1,j+1) | ) + + where CNORM(j+1) is greater than or equal to the infinity-norm of + column j+1 of A, not counting the diagonal. Hence + + G(j) <= G(0) product ( 1 + CNORM(i) / | A(i,i) | ) + 1<=i<=j + and + + |x(j)| <= ( G(0) / |A(j,j)| ) product ( 1 + CNORM(i) / |A(i,i)| ) + 1<=i< j + + Since |x(j)| <= M(j), we use the Level 2 BLAS routine ZTRSV if the + reciprocal of the largest M(j), j=1,..,n, is larger than + max(underflow, 1/overflow). + + The bound on x(j) is also used to determine when a step in the + columnwise method can be performed without fear of overflow. If + the computed bound is greater than a large constant, x is scaled to + prevent overflow, but if the bound overflows, x is set to 0, x(j) to + 1, and scale to 0, and a non-trivial solution to A*x = 0 is found. + + Similarly, a row-wise scheme is used to solve A**T *x = b or + A**H *x = b. The basic algorithm for A upper triangular is + + for j = 1, ..., n + x(j) := ( b(j) - A[1:j-1,j]' * x[1:j-1] ) / A(j,j) + end + + We simultaneously compute two bounds + G(j) = bound on ( b(i) - A[1:i-1,i]' * x[1:i-1] ), 1<=i<=j + M(j) = bound on x(i), 1<=i<=j + + The initial values are G(0) = 0, M(0) = max{b(i), i=1,..,n}, and we + add the constraint G(j) >= G(j-1) and M(j) >= M(j-1) for j >= 1. + Then the bound on x(j) is + + M(j) <= M(j-1) * ( 1 + CNORM(j) ) / | A(j,j) | + + <= M(0) * product ( ( 1 + CNORM(i) ) / |A(i,i)| ) + 1<=i<=j + + and we can safely call ZTRSV if 1/M(n) and 1/G(n) are both greater + than max(underflow, 1/overflow). + + ===================================================================== +*/ + + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --cnorm; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + notran = lsame_(trans, "N"); + nounit = lsame_(diag, "N"); + +/* Test the input parameters. */ + + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "T") && ! + lsame_(trans, "C")) { + *info = -2; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -3; + } else if (! lsame_(normin, "Y") && ! lsame_(normin, + "N")) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*lda < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLATRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine machine dependent parameters to control overflow. */ + + smlnum = SAFEMINIMUM; + bignum = 1. / smlnum; + dlabad_(&smlnum, &bignum); + smlnum /= PRECISION; + bignum = 1. / smlnum; + *scale = 1.; + + if (lsame_(normin, "N")) { + +/* Compute the 1-norm of each column, not including the diagonal. */ + + if (upper) { + +/* A is upper triangular. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j - 1; + cnorm[j] = dzasum_(&i__2, &a[j * a_dim1 + 1], &c__1); +/* L10: */ + } + } else { + +/* A is lower triangular. */ + + i__1 = *n - 1; + for (j = 1; j <= i__1; ++j) { + i__2 = *n - j; + cnorm[j] = dzasum_(&i__2, &a[j + 1 + j * a_dim1], &c__1); +/* L20: */ + } + cnorm[*n] = 0.; + } + } + +/* + Scale the column norms by TSCAL if the maximum element in CNORM is + greater than BIGNUM/2. +*/ + + imax = idamax_(n, &cnorm[1], &c__1); + tmax = cnorm[imax]; + if (tmax <= bignum * .5) { + tscal = 1.; + } else { + tscal = .5 / (smlnum * tmax); + dscal_(n, &tscal, &cnorm[1], &c__1); + } + +/* + Compute a bound on the computed solution vector to see if the + Level 2 BLAS routine ZTRSV can be used. +*/ + + xmax = 0.; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { +/* Computing MAX */ + i__2 = j; + d__3 = xmax, d__4 = (d__1 = x[i__2].r / 2., abs(d__1)) + (d__2 = + d_imag(&x[j]) / 2., abs(d__2)); + xmax = max(d__3,d__4); +/* L30: */ + } + xbnd = xmax; + + if (notran) { + +/* Compute the growth in A * x = b. */ + + if (upper) { + jfirst = *n; + jlast = 1; + jinc = -1; + } else { + jfirst = 1; + jlast = *n; + jinc = 1; + } + + if (tscal != 1.) { + grow = 0.; + goto L60; + } + + if (nounit) { + +/* + A is non-unit triangular. + + Compute GROW = 1/G(j) and XBND = 1/M(j). + Initially, G(0) = max{x(i), i=1,...,n}. +*/ + + grow = .5 / max(xbnd,smlnum); + xbnd = grow; + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L60; + } + + i__3 = j + j * a_dim1; + tjjs.r = a[i__3].r, tjjs.i = a[i__3].i; + tjj = (d__1 = tjjs.r, abs(d__1)) + (d__2 = d_imag(&tjjs), abs( + d__2)); + + if (tjj >= smlnum) { + +/* + M(j) = G(j-1) / abs(A(j,j)) + + Computing MIN +*/ + d__1 = xbnd, d__2 = min(1.,tjj) * grow; + xbnd = min(d__1,d__2); + } else { + +/* M(j) could overflow, set XBND to 0. */ + + xbnd = 0.; + } + + if (tjj + cnorm[j] >= smlnum) { + +/* G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) */ + + grow *= tjj / (tjj + cnorm[j]); + } else { + +/* G(j) could overflow, set GROW to 0. */ + + grow = 0.; + } +/* L40: */ + } + grow = xbnd; + } else { + +/* + A is unit triangular. + + Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. + + Computing MIN +*/ + d__1 = 1., d__2 = .5 / max(xbnd,smlnum); + grow = min(d__1,d__2); + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L60; + } + +/* G(j) = G(j-1)*( 1 + CNORM(j) ) */ + + grow *= 1. / (cnorm[j] + 1.); +/* L50: */ + } + } +L60: + + ; + } else { + +/* Compute the growth in A**T * x = b or A**H * x = b. */ + + if (upper) { + jfirst = 1; + jlast = *n; + jinc = 1; + } else { + jfirst = *n; + jlast = 1; + jinc = -1; + } + + if (tscal != 1.) { + grow = 0.; + goto L90; + } + + if (nounit) { + +/* + A is non-unit triangular. + + Compute GROW = 1/G(j) and XBND = 1/M(j). + Initially, M(0) = max{x(i), i=1,...,n}. +*/ + + grow = .5 / max(xbnd,smlnum); + xbnd = grow; + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L90; + } + +/* G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) */ + + xj = cnorm[j] + 1.; +/* Computing MIN */ + d__1 = grow, d__2 = xbnd / xj; + grow = min(d__1,d__2); + + i__3 = j + j * a_dim1; + tjjs.r = a[i__3].r, tjjs.i = a[i__3].i; + tjj = (d__1 = tjjs.r, abs(d__1)) + (d__2 = d_imag(&tjjs), abs( + d__2)); + + if (tjj >= smlnum) { + +/* M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) */ + + if (xj > tjj) { + xbnd *= tjj / xj; + } + } else { + +/* M(j) could overflow, set XBND to 0. */ + + xbnd = 0.; + } +/* L70: */ + } + grow = min(grow,xbnd); + } else { + +/* + A is unit triangular. + + Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. + + Computing MIN +*/ + d__1 = 1., d__2 = .5 / max(xbnd,smlnum); + grow = min(d__1,d__2); + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* Exit the loop if the growth factor is too small. */ + + if (grow <= smlnum) { + goto L90; + } + +/* G(j) = ( 1 + CNORM(j) )*G(j-1) */ + + xj = cnorm[j] + 1.; + grow /= xj; +/* L80: */ + } + } +L90: + ; + } + + if (grow * tscal > smlnum) { + +/* + Use the Level 2 BLAS solve if the reciprocal of the bound on + elements of X is not too small. +*/ + + ztrsv_(uplo, trans, diag, n, &a[a_offset], lda, &x[1], &c__1); + } else { + +/* Use a Level 1 BLAS solve, scaling intermediate results. */ + + if (xmax > bignum * .5) { + +/* + Scale X so that its components are less than or equal to + BIGNUM in absolute value. +*/ + + *scale = bignum * .5 / xmax; + zdscal_(n, scale, &x[1], &c__1); + xmax = bignum; + } else { + xmax *= 2.; + } + + if (notran) { + +/* Solve A * x = b */ + + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* Compute x(j) = b(j) / A(j,j), scaling x if necessary. */ + + i__3 = j; + xj = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag(&x[j]), + abs(d__2)); + if (nounit) { + i__3 = j + j * a_dim1; + z__1.r = tscal * a[i__3].r, z__1.i = tscal * a[i__3].i; + tjjs.r = z__1.r, tjjs.i = z__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.; + if (tscal == 1.) { + goto L110; + } + } + tjj = (d__1 = tjjs.r, abs(d__1)) + (d__2 = d_imag(&tjjs), abs( + d__2)); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.) { + if (xj > tjj * bignum) { + +/* Scale x by 1/b(j). */ + + rec = 1. / xj; + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + i__3 = j; + zladiv_(&z__1, &x[j], &tjjs); + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + i__3 = j; + xj = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag(&x[j]) + , abs(d__2)); + } else if (tjj > 0.) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* + Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM + to avoid overflow when dividing by A(j,j). +*/ + + rec = tjj * bignum / xj; + if (cnorm[j] > 1.) { + +/* + Scale by 1/CNORM(j) to avoid overflow when + multiplying x(j) times column j. +*/ + + rec /= cnorm[j]; + } + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + i__3 = j; + zladiv_(&z__1, &x[j], &tjjs); + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + i__3 = j; + xj = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag(&x[j]) + , abs(d__2)); + } else { + +/* + A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and + scale = 0, and compute a solution to A*x = 0. +*/ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__; + x[i__4].r = 0., x[i__4].i = 0.; +/* L100: */ + } + i__3 = j; + x[i__3].r = 1., x[i__3].i = 0.; + xj = 1.; + *scale = 0.; + xmax = 0.; + } +L110: + +/* + Scale x if necessary to avoid overflow when adding a + multiple of column j of A. +*/ + + if (xj > 1.) { + rec = 1. / xj; + if (cnorm[j] > (bignum - xmax) * rec) { + +/* Scale x by 1/(2*abs(x(j))). */ + + rec *= .5; + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + } + } else if (xj * cnorm[j] > bignum - xmax) { + +/* Scale x by 1/2. */ + + zdscal_(n, &c_b2435, &x[1], &c__1); + *scale *= .5; + } + + if (upper) { + if (j > 1) { + +/* + Compute the update + x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j) +*/ + + i__3 = j - 1; + i__4 = j; + z__2.r = -x[i__4].r, z__2.i = -x[i__4].i; + z__1.r = tscal * z__2.r, z__1.i = tscal * z__2.i; + zaxpy_(&i__3, &z__1, &a[j * a_dim1 + 1], &c__1, &x[1], + &c__1); + i__3 = j - 1; + i__ = izamax_(&i__3, &x[1], &c__1); + i__3 = i__; + xmax = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag( + &x[i__]), abs(d__2)); + } + } else { + if (j < *n) { + +/* + Compute the update + x(j+1:n) := x(j+1:n) - x(j) * A(j+1:n,j) +*/ + + i__3 = *n - j; + i__4 = j; + z__2.r = -x[i__4].r, z__2.i = -x[i__4].i; + z__1.r = tscal * z__2.r, z__1.i = tscal * z__2.i; + zaxpy_(&i__3, &z__1, &a[j + 1 + j * a_dim1], &c__1, & + x[j + 1], &c__1); + i__3 = *n - j; + i__ = j + izamax_(&i__3, &x[j + 1], &c__1); + i__3 = i__; + xmax = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag( + &x[i__]), abs(d__2)); + } + } +/* L120: */ + } + + } else if (lsame_(trans, "T")) { + +/* Solve A**T * x = b */ + + i__2 = jlast; + i__1 = jinc; + for (j = jfirst; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* + Compute x(j) = b(j) - sum A(k,j)*x(k). + k<>j +*/ + + i__3 = j; + xj = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag(&x[j]), + abs(d__2)); + uscal.r = tscal, uscal.i = 0.; + rec = 1. / max(xmax,1.); + if (cnorm[j] > (bignum - xj) * rec) { + +/* If x(j) could overflow, scale x by 1/(2*XMAX). */ + + rec *= .5; + if (nounit) { + i__3 = j + j * a_dim1; + z__1.r = tscal * a[i__3].r, z__1.i = tscal * a[i__3] + .i; + tjjs.r = z__1.r, tjjs.i = z__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.; + } + tjj = (d__1 = tjjs.r, abs(d__1)) + (d__2 = d_imag(&tjjs), + abs(d__2)); + if (tjj > 1.) { + +/* + Divide by A(j,j) when scaling x if A(j,j) > 1. + + Computing MIN +*/ + d__1 = 1., d__2 = rec * tjj; + rec = min(d__1,d__2); + zladiv_(&z__1, &uscal, &tjjs); + uscal.r = z__1.r, uscal.i = z__1.i; + } + if (rec < 1.) { + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + + csumj.r = 0., csumj.i = 0.; + if (uscal.r == 1. && uscal.i == 0.) { + +/* + If the scaling needed for A in the dot product is 1, + call ZDOTU to perform the dot product. +*/ + + if (upper) { + i__3 = j - 1; + zdotu_(&z__1, &i__3, &a[j * a_dim1 + 1], &c__1, &x[1], + &c__1); + csumj.r = z__1.r, csumj.i = z__1.i; + } else if (j < *n) { + i__3 = *n - j; + zdotu_(&z__1, &i__3, &a[j + 1 + j * a_dim1], &c__1, & + x[j + 1], &c__1); + csumj.r = z__1.r, csumj.i = z__1.i; + } + } else { + +/* Otherwise, use in-line code for the dot product. */ + + if (upper) { + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * a_dim1; + z__3.r = a[i__4].r * uscal.r - a[i__4].i * + uscal.i, z__3.i = a[i__4].r * uscal.i + a[ + i__4].i * uscal.r; + i__5 = i__; + z__2.r = z__3.r * x[i__5].r - z__3.i * x[i__5].i, + z__2.i = z__3.r * x[i__5].i + z__3.i * x[ + i__5].r; + z__1.r = csumj.r + z__2.r, z__1.i = csumj.i + + z__2.i; + csumj.r = z__1.r, csumj.i = z__1.i; +/* L130: */ + } + } else if (j < *n) { + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + i__4 = i__ + j * a_dim1; + z__3.r = a[i__4].r * uscal.r - a[i__4].i * + uscal.i, z__3.i = a[i__4].r * uscal.i + a[ + i__4].i * uscal.r; + i__5 = i__; + z__2.r = z__3.r * x[i__5].r - z__3.i * x[i__5].i, + z__2.i = z__3.r * x[i__5].i + z__3.i * x[ + i__5].r; + z__1.r = csumj.r + z__2.r, z__1.i = csumj.i + + z__2.i; + csumj.r = z__1.r, csumj.i = z__1.i; +/* L140: */ + } + } + } + + z__1.r = tscal, z__1.i = 0.; + if (uscal.r == z__1.r && uscal.i == z__1.i) { + +/* + Compute x(j) := ( x(j) - CSUMJ ) / A(j,j) if 1/A(j,j) + was not used to scale the dotproduct. +*/ + + i__3 = j; + i__4 = j; + z__1.r = x[i__4].r - csumj.r, z__1.i = x[i__4].i - + csumj.i; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + i__3 = j; + xj = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag(&x[j]) + , abs(d__2)); + if (nounit) { + i__3 = j + j * a_dim1; + z__1.r = tscal * a[i__3].r, z__1.i = tscal * a[i__3] + .i; + tjjs.r = z__1.r, tjjs.i = z__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.; + if (tscal == 1.) { + goto L160; + } + } + +/* Compute x(j) = x(j) / A(j,j), scaling if necessary. */ + + tjj = (d__1 = tjjs.r, abs(d__1)) + (d__2 = d_imag(&tjjs), + abs(d__2)); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.) { + if (xj > tjj * bignum) { + +/* Scale X by 1/abs(x(j)). */ + + rec = 1. / xj; + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + i__3 = j; + zladiv_(&z__1, &x[j], &tjjs); + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + } else if (tjj > 0.) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. */ + + rec = tjj * bignum / xj; + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + i__3 = j; + zladiv_(&z__1, &x[j], &tjjs); + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + } else { + +/* + A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and + scale = 0 and compute a solution to A**T *x = 0. +*/ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__; + x[i__4].r = 0., x[i__4].i = 0.; +/* L150: */ + } + i__3 = j; + x[i__3].r = 1., x[i__3].i = 0.; + *scale = 0.; + xmax = 0.; + } +L160: + ; + } else { + +/* + Compute x(j) := x(j) / A(j,j) - CSUMJ if the dot + product has already been divided by 1/A(j,j). +*/ + + i__3 = j; + zladiv_(&z__2, &x[j], &tjjs); + z__1.r = z__2.r - csumj.r, z__1.i = z__2.i - csumj.i; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + } +/* Computing MAX */ + i__3 = j; + d__3 = xmax, d__4 = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = + d_imag(&x[j]), abs(d__2)); + xmax = max(d__3,d__4); +/* L170: */ + } + + } else { + +/* Solve A**H * x = b */ + + i__1 = jlast; + i__2 = jinc; + for (j = jfirst; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* + Compute x(j) = b(j) - sum A(k,j)*x(k). + k<>j +*/ + + i__3 = j; + xj = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag(&x[j]), + abs(d__2)); + uscal.r = tscal, uscal.i = 0.; + rec = 1. / max(xmax,1.); + if (cnorm[j] > (bignum - xj) * rec) { + +/* If x(j) could overflow, scale x by 1/(2*XMAX). */ + + rec *= .5; + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z__1.r = tscal * z__2.r, z__1.i = tscal * z__2.i; + tjjs.r = z__1.r, tjjs.i = z__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.; + } + tjj = (d__1 = tjjs.r, abs(d__1)) + (d__2 = d_imag(&tjjs), + abs(d__2)); + if (tjj > 1.) { + +/* + Divide by A(j,j) when scaling x if A(j,j) > 1. + + Computing MIN +*/ + d__1 = 1., d__2 = rec * tjj; + rec = min(d__1,d__2); + zladiv_(&z__1, &uscal, &tjjs); + uscal.r = z__1.r, uscal.i = z__1.i; + } + if (rec < 1.) { + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + + csumj.r = 0., csumj.i = 0.; + if (uscal.r == 1. && uscal.i == 0.) { + +/* + If the scaling needed for A in the dot product is 1, + call ZDOTC to perform the dot product. +*/ + + if (upper) { + i__3 = j - 1; + zdotc_(&z__1, &i__3, &a[j * a_dim1 + 1], &c__1, &x[1], + &c__1); + csumj.r = z__1.r, csumj.i = z__1.i; + } else if (j < *n) { + i__3 = *n - j; + zdotc_(&z__1, &i__3, &a[j + 1 + j * a_dim1], &c__1, & + x[j + 1], &c__1); + csumj.r = z__1.r, csumj.i = z__1.i; + } + } else { + +/* Otherwise, use in-line code for the dot product. */ + + if (upper) { + i__3 = j - 1; + for (i__ = 1; i__ <= i__3; ++i__) { + d_cnjg(&z__4, &a[i__ + j * a_dim1]); + z__3.r = z__4.r * uscal.r - z__4.i * uscal.i, + z__3.i = z__4.r * uscal.i + z__4.i * + uscal.r; + i__4 = i__; + z__2.r = z__3.r * x[i__4].r - z__3.i * x[i__4].i, + z__2.i = z__3.r * x[i__4].i + z__3.i * x[ + i__4].r; + z__1.r = csumj.r + z__2.r, z__1.i = csumj.i + + z__2.i; + csumj.r = z__1.r, csumj.i = z__1.i; +/* L180: */ + } + } else if (j < *n) { + i__3 = *n; + for (i__ = j + 1; i__ <= i__3; ++i__) { + d_cnjg(&z__4, &a[i__ + j * a_dim1]); + z__3.r = z__4.r * uscal.r - z__4.i * uscal.i, + z__3.i = z__4.r * uscal.i + z__4.i * + uscal.r; + i__4 = i__; + z__2.r = z__3.r * x[i__4].r - z__3.i * x[i__4].i, + z__2.i = z__3.r * x[i__4].i + z__3.i * x[ + i__4].r; + z__1.r = csumj.r + z__2.r, z__1.i = csumj.i + + z__2.i; + csumj.r = z__1.r, csumj.i = z__1.i; +/* L190: */ + } + } + } + + z__1.r = tscal, z__1.i = 0.; + if (uscal.r == z__1.r && uscal.i == z__1.i) { + +/* + Compute x(j) := ( x(j) - CSUMJ ) / A(j,j) if 1/A(j,j) + was not used to scale the dotproduct. +*/ + + i__3 = j; + i__4 = j; + z__1.r = x[i__4].r - csumj.r, z__1.i = x[i__4].i - + csumj.i; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + i__3 = j; + xj = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = d_imag(&x[j]) + , abs(d__2)); + if (nounit) { + d_cnjg(&z__2, &a[j + j * a_dim1]); + z__1.r = tscal * z__2.r, z__1.i = tscal * z__2.i; + tjjs.r = z__1.r, tjjs.i = z__1.i; + } else { + tjjs.r = tscal, tjjs.i = 0.; + if (tscal == 1.) { + goto L210; + } + } + +/* Compute x(j) = x(j) / A(j,j), scaling if necessary. */ + + tjj = (d__1 = tjjs.r, abs(d__1)) + (d__2 = d_imag(&tjjs), + abs(d__2)); + if (tjj > smlnum) { + +/* abs(A(j,j)) > SMLNUM: */ + + if (tjj < 1.) { + if (xj > tjj * bignum) { + +/* Scale X by 1/abs(x(j)). */ + + rec = 1. / xj; + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + } + i__3 = j; + zladiv_(&z__1, &x[j], &tjjs); + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + } else if (tjj > 0.) { + +/* 0 < abs(A(j,j)) <= SMLNUM: */ + + if (xj > tjj * bignum) { + +/* Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. */ + + rec = tjj * bignum / xj; + zdscal_(n, &rec, &x[1], &c__1); + *scale *= rec; + xmax *= rec; + } + i__3 = j; + zladiv_(&z__1, &x[j], &tjjs); + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + } else { + +/* + A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and + scale = 0 and compute a solution to A**H *x = 0. +*/ + + i__3 = *n; + for (i__ = 1; i__ <= i__3; ++i__) { + i__4 = i__; + x[i__4].r = 0., x[i__4].i = 0.; +/* L200: */ + } + i__3 = j; + x[i__3].r = 1., x[i__3].i = 0.; + *scale = 0.; + xmax = 0.; + } +L210: + ; + } else { + +/* + Compute x(j) := x(j) / A(j,j) - CSUMJ if the dot + product has already been divided by 1/A(j,j). +*/ + + i__3 = j; + zladiv_(&z__2, &x[j], &tjjs); + z__1.r = z__2.r - csumj.r, z__1.i = z__2.i - csumj.i; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + } +/* Computing MAX */ + i__3 = j; + d__3 = xmax, d__4 = (d__1 = x[i__3].r, abs(d__1)) + (d__2 = + d_imag(&x[j]), abs(d__2)); + xmax = max(d__3,d__4); +/* L220: */ + } + } + *scale /= tscal; + } + +/* Scale the column norms by 1/TSCAL for return. */ + + if (tscal != 1.) { + d__1 = 1. / tscal; + dscal_(n, &d__1, &cnorm[1], &c__1); + } + + return 0; + +/* End of ZLATRS */ + +} /* zlatrs_ */ + +/* Subroutine */ int zlauu2_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1; + doublecomplex z__1; + + /* Local variables */ + static integer i__; + static doublereal aii; + extern logical lsame_(char *, char *); + extern /* Double Complex */ VOID zdotc_(doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *); + extern /* Subroutine */ int zgemv_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *), zdscal_( + integer *, doublereal *, doublecomplex *, integer *), zlacgv_( + integer *, doublecomplex *, integer *); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLAUU2 computes the product U * U' or L' * L, where the triangular + factor U or L is stored in the upper or lower triangular part of + the array A. + + If UPLO = 'U' or 'u' then the upper triangle of the result is stored, + overwriting the factor U in A. + If UPLO = 'L' or 'l' then the lower triangle of the result is stored, + overwriting the factor L in A. + + This is the unblocked form of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the triangular factor stored in the array A + is upper or lower triangular: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the triangular factor U or L. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the triangular factor U or L. + On exit, if UPLO = 'U', the upper triangle of A is + overwritten with the upper triangle of the product U * U'; + if UPLO = 'L', the lower triangle of A is overwritten with + the lower triangle of the product L' * L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLAUU2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the product U * U'. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + aii = a[i__2].r; + if (i__ < *n) { + i__2 = i__ + i__ * a_dim1; + i__3 = *n - i__; + zdotc_(&z__1, &i__3, &a[i__ + (i__ + 1) * a_dim1], lda, &a[ + i__ + (i__ + 1) * a_dim1], lda); + d__1 = aii * aii + z__1.r; + a[i__2].r = d__1, a[i__2].i = 0.; + i__2 = *n - i__; + zlacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + i__2 = i__ - 1; + i__3 = *n - i__; + z__1.r = aii, z__1.i = 0.; + zgemv_("No transpose", &i__2, &i__3, &c_b57, &a[(i__ + 1) * + a_dim1 + 1], lda, &a[i__ + (i__ + 1) * a_dim1], lda, & + z__1, &a[i__ * a_dim1 + 1], &c__1); + i__2 = *n - i__; + zlacgv_(&i__2, &a[i__ + (i__ + 1) * a_dim1], lda); + } else { + zdscal_(&i__, &aii, &a[i__ * a_dim1 + 1], &c__1); + } +/* L10: */ + } + + } else { + +/* Compute the product L' * L. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + i__ * a_dim1; + aii = a[i__2].r; + if (i__ < *n) { + i__2 = i__ + i__ * a_dim1; + i__3 = *n - i__; + zdotc_(&z__1, &i__3, &a[i__ + 1 + i__ * a_dim1], &c__1, &a[ + i__ + 1 + i__ * a_dim1], &c__1); + d__1 = aii * aii + z__1.r; + a[i__2].r = d__1, a[i__2].i = 0.; + i__2 = i__ - 1; + zlacgv_(&i__2, &a[i__ + a_dim1], lda); + i__2 = *n - i__; + i__3 = i__ - 1; + z__1.r = aii, z__1.i = 0.; + zgemv_("Conjugate transpose", &i__2, &i__3, &c_b57, &a[i__ + + 1 + a_dim1], lda, &a[i__ + 1 + i__ * a_dim1], &c__1, & + z__1, &a[i__ + a_dim1], lda); + i__2 = i__ - 1; + zlacgv_(&i__2, &a[i__ + a_dim1], lda); + } else { + zdscal_(&i__, &aii, &a[i__ + a_dim1], lda); + } +/* L20: */ + } + } + + return 0; + +/* End of ZLAUU2 */ + +} /* zlauu2_ */ + +/* Subroutine */ int zlauum_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, ib, nb; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), zherk_(char *, char *, integer *, + integer *, doublereal *, doublecomplex *, integer *, doublereal *, + doublecomplex *, integer *); + static logical upper; + extern /* Subroutine */ int ztrmm_(char *, char *, char *, char *, + integer *, integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *), + zlauu2_(char *, integer *, doublecomplex *, integer *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZLAUUM computes the product U * U' or L' * L, where the triangular + factor U or L is stored in the upper or lower triangular part of + the array A. + + If UPLO = 'U' or 'u' then the upper triangle of the result is stored, + overwriting the factor U in A. + If UPLO = 'L' or 'l' then the lower triangle of the result is stored, + overwriting the factor L in A. + + This is the blocked form of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the triangular factor stored in the array A + is upper or lower triangular: + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the triangular factor U or L. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the triangular factor U or L. + On exit, if UPLO = 'U', the upper triangle of A is + overwritten with the upper triangle of the product U * U'; + if UPLO = 'L', the lower triangle of A is overwritten with + the lower triangle of the product L' * L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZLAUUM", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "ZLAUUM", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code */ + + zlauu2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code */ + + if (upper) { + +/* Compute the product U * U'. */ + + i__1 = *n; + i__2 = nb; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__3 = nb, i__4 = *n - i__ + 1; + ib = min(i__3,i__4); + i__3 = i__ - 1; + ztrmm_("Right", "Upper", "Conjugate transpose", "Non-unit", & + i__3, &ib, &c_b57, &a[i__ + i__ * a_dim1], lda, &a[ + i__ * a_dim1 + 1], lda); + zlauu2_("Upper", &ib, &a[i__ + i__ * a_dim1], lda, info); + if (i__ + ib <= *n) { + i__3 = i__ - 1; + i__4 = *n - i__ - ib + 1; + zgemm_("No transpose", "Conjugate transpose", &i__3, &ib, + &i__4, &c_b57, &a[(i__ + ib) * a_dim1 + 1], lda, & + a[i__ + (i__ + ib) * a_dim1], lda, &c_b57, &a[i__ + * a_dim1 + 1], lda); + i__3 = *n - i__ - ib + 1; + zherk_("Upper", "No transpose", &ib, &i__3, &c_b1034, &a[ + i__ + (i__ + ib) * a_dim1], lda, &c_b1034, &a[i__ + + i__ * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the product L' * L. */ + + i__2 = *n; + i__1 = nb; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { +/* Computing MIN */ + i__3 = nb, i__4 = *n - i__ + 1; + ib = min(i__3,i__4); + i__3 = i__ - 1; + ztrmm_("Left", "Lower", "Conjugate transpose", "Non-unit", & + ib, &i__3, &c_b57, &a[i__ + i__ * a_dim1], lda, &a[ + i__ + a_dim1], lda); + zlauu2_("Lower", &ib, &a[i__ + i__ * a_dim1], lda, info); + if (i__ + ib <= *n) { + i__3 = i__ - 1; + i__4 = *n - i__ - ib + 1; + zgemm_("Conjugate transpose", "No transpose", &ib, &i__3, + &i__4, &c_b57, &a[i__ + ib + i__ * a_dim1], lda, & + a[i__ + ib + a_dim1], lda, &c_b57, &a[i__ + + a_dim1], lda); + i__3 = *n - i__ - ib + 1; + zherk_("Lower", "Conjugate transpose", &ib, &i__3, & + c_b1034, &a[i__ + ib + i__ * a_dim1], lda, & + c_b1034, &a[i__ + i__ * a_dim1], lda); + } +/* L20: */ + } + } + } + + return 0; + +/* End of ZLAUUM */ + +} /* zlauum_ */ + +/* Subroutine */ int zpotf2_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublereal d__1; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer j; + static doublereal ajj; + extern logical lsame_(char *, char *); + extern /* Double Complex */ VOID zdotc_(doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *); + extern /* Subroutine */ int zgemv_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *); + static logical upper; + extern logical disnan_(doublereal *); + extern /* Subroutine */ int xerbla_(char *, integer *), zdscal_( + integer *, doublereal *, doublecomplex *, integer *), zlacgv_( + integer *, doublecomplex *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZPOTF2 computes the Cholesky factorization of a complex Hermitian + positive definite matrix A. + + The factorization has the form + A = U' * U , if UPLO = 'U', or + A = L * L', if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the unblocked version of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + Hermitian matrix A is stored. + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + n by n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U'*U or A = L*L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, the leading minor of order k is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZPOTF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute U(J,J) and test for non-positive-definiteness. */ + + i__2 = j + j * a_dim1; + d__1 = a[i__2].r; + i__3 = j - 1; + zdotc_(&z__2, &i__3, &a[j * a_dim1 + 1], &c__1, &a[j * a_dim1 + 1] + , &c__1); + z__1.r = d__1 - z__2.r, z__1.i = -z__2.i; + ajj = z__1.r; + if (ajj <= 0. || disnan_(&ajj)) { + i__2 = j + j * a_dim1; + a[i__2].r = ajj, a[i__2].i = 0.; + goto L30; + } + ajj = sqrt(ajj); + i__2 = j + j * a_dim1; + a[i__2].r = ajj, a[i__2].i = 0.; + +/* Compute elements J+1:N of row J. */ + + if (j < *n) { + i__2 = j - 1; + zlacgv_(&i__2, &a[j * a_dim1 + 1], &c__1); + i__2 = j - 1; + i__3 = *n - j; + z__1.r = -1., z__1.i = -0.; + zgemv_("Transpose", &i__2, &i__3, &z__1, &a[(j + 1) * a_dim1 + + 1], lda, &a[j * a_dim1 + 1], &c__1, &c_b57, &a[j + ( + j + 1) * a_dim1], lda); + i__2 = j - 1; + zlacgv_(&i__2, &a[j * a_dim1 + 1], &c__1); + i__2 = *n - j; + d__1 = 1. / ajj; + zdscal_(&i__2, &d__1, &a[j + (j + 1) * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute L(J,J) and test for non-positive-definiteness. */ + + i__2 = j + j * a_dim1; + d__1 = a[i__2].r; + i__3 = j - 1; + zdotc_(&z__2, &i__3, &a[j + a_dim1], lda, &a[j + a_dim1], lda); + z__1.r = d__1 - z__2.r, z__1.i = -z__2.i; + ajj = z__1.r; + if (ajj <= 0. || disnan_(&ajj)) { + i__2 = j + j * a_dim1; + a[i__2].r = ajj, a[i__2].i = 0.; + goto L30; + } + ajj = sqrt(ajj); + i__2 = j + j * a_dim1; + a[i__2].r = ajj, a[i__2].i = 0.; + +/* Compute elements J+1:N of column J. */ + + if (j < *n) { + i__2 = j - 1; + zlacgv_(&i__2, &a[j + a_dim1], lda); + i__2 = *n - j; + i__3 = j - 1; + z__1.r = -1., z__1.i = -0.; + zgemv_("No transpose", &i__2, &i__3, &z__1, &a[j + 1 + a_dim1] + , lda, &a[j + a_dim1], lda, &c_b57, &a[j + 1 + j * + a_dim1], &c__1); + i__2 = j - 1; + zlacgv_(&i__2, &a[j + a_dim1], lda); + i__2 = *n - j; + d__1 = 1. / ajj; + zdscal_(&i__2, &d__1, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + goto L40; + +L30: + *info = j; + +L40: + return 0; + +/* End of ZPOTF2 */ + +} /* zpotf2_ */ + +/* Subroutine */ int zpotrf_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + doublecomplex z__1; + + /* Local variables */ + static integer j, jb, nb; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zgemm_(char *, char *, integer *, integer *, + integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), zherk_(char *, char *, integer *, + integer *, doublereal *, doublecomplex *, integer *, doublereal *, + doublecomplex *, integer *); + static logical upper; + extern /* Subroutine */ int ztrsm_(char *, char *, char *, char *, + integer *, integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *), + zpotf2_(char *, integer *, doublecomplex *, integer *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZPOTRF computes the Cholesky factorization of a complex Hermitian + positive definite matrix A. + + The factorization has the form + A = U**H * U, if UPLO = 'U', or + A = L * L**H, if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the block version of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the Hermitian matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U**H*U or A = L*L**H. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the leading minor of order i is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZPOTRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "ZPOTRF", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code. */ + + zpotf2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code. */ + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + zherk_("Upper", "Conjugate transpose", &jb, &i__3, &c_b1276, & + a[j * a_dim1 + 1], lda, &c_b1034, &a[j + j * a_dim1], + lda); + zpotf2_("Upper", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block row. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + z__1.r = -1., z__1.i = -0.; + zgemm_("Conjugate transpose", "No transpose", &jb, &i__3, + &i__4, &z__1, &a[j * a_dim1 + 1], lda, &a[(j + jb) + * a_dim1 + 1], lda, &c_b57, &a[j + (j + jb) * + a_dim1], lda); + i__3 = *n - j - jb + 1; + ztrsm_("Left", "Upper", "Conjugate transpose", "Non-unit", + &jb, &i__3, &c_b57, &a[j + j * a_dim1], lda, &a[ + j + (j + jb) * a_dim1], lda); + } +/* L10: */ + } + + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__2 = *n; + i__1 = nb; + for (j = 1; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + zherk_("Lower", "No transpose", &jb, &i__3, &c_b1276, &a[j + + a_dim1], lda, &c_b1034, &a[j + j * a_dim1], lda); + zpotf2_("Lower", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block column. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + z__1.r = -1., z__1.i = -0.; + zgemm_("No transpose", "Conjugate transpose", &i__3, &jb, + &i__4, &z__1, &a[j + jb + a_dim1], lda, &a[j + + a_dim1], lda, &c_b57, &a[j + jb + j * a_dim1], + lda); + i__3 = *n - j - jb + 1; + ztrsm_("Right", "Lower", "Conjugate transpose", "Non-unit" + , &i__3, &jb, &c_b57, &a[j + j * a_dim1], lda, &a[ + j + jb + j * a_dim1], lda); + } +/* L20: */ + } + } + } + goto L40; + +L30: + *info = *info + j - 1; + +L40: + return 0; + +/* End of ZPOTRF */ + +} /* zpotrf_ */ + +/* Subroutine */ int zpotri_(char *uplo, integer *n, doublecomplex *a, + integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *), zlauum_( + char *, integer *, doublecomplex *, integer *, integer *), + ztrtri_(char *, char *, integer *, doublecomplex *, integer *, + integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZPOTRI computes the inverse of a complex Hermitian positive definite + matrix A using the Cholesky factorization A = U**H*U or A = L*L**H + computed by ZPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the triangular factor U or L from the Cholesky + factorization A = U**H*U or A = L*L**H, as computed by + ZPOTRF. + On exit, the upper or lower triangle of the (Hermitian) + inverse of A, overwriting the input factor U or L. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the (i,i) element of the factor U or L is + zero, and the inverse could not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZPOTRI", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Invert the triangular Cholesky factor U or L. */ + + ztrtri_(uplo, "Non-unit", n, &a[a_offset], lda, info); + if (*info > 0) { + return 0; + } + +/* Form inv(U)*inv(U)' or inv(L)'*inv(L). */ + + zlauum_(uplo, n, &a[a_offset], lda, info); + + return 0; + +/* End of ZPOTRI */ + +} /* zpotri_ */ + +/* Subroutine */ int zpotrs_(char *uplo, integer *n, integer *nrhs, + doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + static logical upper; + extern /* Subroutine */ int ztrsm_(char *, char *, char *, char *, + integer *, integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *), + xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZPOTRS solves a system of linear equations A*X = B with a Hermitian + positive definite matrix A using the Cholesky factorization + A = U**H*U or A = L*L**H computed by ZPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,N) + The triangular factor U or L from the Cholesky factorization + A = U**H*U or A = L*L**H, as computed by ZPOTRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + B (input/output) COMPLEX*16 array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZPOTRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (upper) { + +/* + Solve A*X = B where A = U'*U. + + Solve U'*X = B, overwriting B with X. +*/ + + ztrsm_("Left", "Upper", "Conjugate transpose", "Non-unit", n, nrhs, & + c_b57, &a[a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + ztrsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b57, & + a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A*X = B where A = L*L'. + + Solve L*X = B, overwriting B with X. +*/ + + ztrsm_("Left", "Lower", "No transpose", "Non-unit", n, nrhs, &c_b57, & + a[a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + ztrsm_("Left", "Lower", "Conjugate transpose", "Non-unit", n, nrhs, & + c_b57, &a[a_offset], lda, &b[b_offset], ldb); + } + + return 0; + +/* End of ZPOTRS */ + +} /* zpotrs_ */ + +/* Subroutine */ int zrot_(integer *n, doublecomplex *cx, integer *incx, + doublecomplex *cy, integer *incy, doublereal *c__, doublecomplex *s) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4; + doublecomplex z__1, z__2, z__3, z__4; + + /* Local variables */ + static integer i__, ix, iy; + static doublecomplex stemp; + + +/* + -- LAPACK auxiliary routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZROT applies a plane rotation, where the cos (C) is real and the + sin (S) is complex, and the vectors CX and CY are complex. + + Arguments + ========= + + N (input) INTEGER + The number of elements in the vectors CX and CY. + + CX (input/output) COMPLEX*16 array, dimension (N) + On input, the vector X. + On output, CX is overwritten with C*X + S*Y. + + INCX (input) INTEGER + The increment between successive values of CY. INCX <> 0. + + CY (input/output) COMPLEX*16 array, dimension (N) + On input, the vector Y. + On output, CY is overwritten with -CONJG(S)*X + C*Y. + + INCY (input) INTEGER + The increment between successive values of CY. INCX <> 0. + + C (input) DOUBLE PRECISION + S (input) COMPLEX*16 + C and S define a rotation + [ C S ] + [ -conjg(S) C ] + where C*C + S*CONJG(S) = 1.0. + + ===================================================================== +*/ + + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + if (*n <= 0) { + return 0; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* Code for unequal increments or equal increments not equal to 1 */ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = ix; + z__2.r = *c__ * cx[i__2].r, z__2.i = *c__ * cx[i__2].i; + i__3 = iy; + z__3.r = s->r * cy[i__3].r - s->i * cy[i__3].i, z__3.i = s->r * cy[ + i__3].i + s->i * cy[i__3].r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + stemp.r = z__1.r, stemp.i = z__1.i; + i__2 = iy; + i__3 = iy; + z__2.r = *c__ * cy[i__3].r, z__2.i = *c__ * cy[i__3].i; + d_cnjg(&z__4, s); + i__4 = ix; + z__3.r = z__4.r * cx[i__4].r - z__4.i * cx[i__4].i, z__3.i = z__4.r * + cx[i__4].i + z__4.i * cx[i__4].r; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - z__3.i; + cy[i__2].r = z__1.r, cy[i__2].i = z__1.i; + i__2 = ix; + cx[i__2].r = stemp.r, cx[i__2].i = stemp.i; + ix += *incx; + iy += *incy; +/* L10: */ + } + return 0; + +/* Code for both increments equal to 1 */ + +L20: + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + z__2.r = *c__ * cx[i__2].r, z__2.i = *c__ * cx[i__2].i; + i__3 = i__; + z__3.r = s->r * cy[i__3].r - s->i * cy[i__3].i, z__3.i = s->r * cy[ + i__3].i + s->i * cy[i__3].r; + z__1.r = z__2.r + z__3.r, z__1.i = z__2.i + z__3.i; + stemp.r = z__1.r, stemp.i = z__1.i; + i__2 = i__; + i__3 = i__; + z__2.r = *c__ * cy[i__3].r, z__2.i = *c__ * cy[i__3].i; + d_cnjg(&z__4, s); + i__4 = i__; + z__3.r = z__4.r * cx[i__4].r - z__4.i * cx[i__4].i, z__3.i = z__4.r * + cx[i__4].i + z__4.i * cx[i__4].r; + z__1.r = z__2.r - z__3.r, z__1.i = z__2.i - z__3.i; + cy[i__2].r = z__1.r, cy[i__2].i = z__1.i; + i__2 = i__; + cx[i__2].r = stemp.r, cx[i__2].i = stemp.i; +/* L30: */ + } + return 0; +} /* zrot_ */ + +/* Subroutine */ int zstedc_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublecomplex *z__, integer *ldz, doublecomplex *work, + integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, + integer *liwork, integer *info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2, i__3, i__4; + doublereal d__1, d__2; + + /* Local variables */ + static integer i__, j, k, m; + static doublereal p; + static integer ii, ll, lgn; + static doublereal eps, tiny; + extern logical lsame_(char *, char *); + static integer lwmin, start; + extern /* Subroutine */ int zswap_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), zlaed0_(integer *, integer *, + doublereal *, doublereal *, doublecomplex *, integer *, + doublecomplex *, integer *, doublereal *, integer *, integer *); + + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *), dstedc_(char *, integer *, + doublereal *, doublereal *, doublereal *, integer *, doublereal *, + integer *, integer *, integer *, integer *), dlaset_( + char *, integer *, integer *, doublereal *, doublereal *, + doublereal *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer finish; + extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); + extern /* Subroutine */ int dsterf_(integer *, doublereal *, doublereal *, + integer *), zlacrm_(integer *, integer *, doublecomplex *, + integer *, doublereal *, integer *, doublecomplex *, integer *, + doublereal *); + static integer liwmin, icompz; + extern /* Subroutine */ int dsteqr_(char *, integer *, doublereal *, + doublereal *, doublereal *, integer *, doublereal *, integer *), zlacpy_(char *, integer *, integer *, doublecomplex *, + integer *, doublecomplex *, integer *); + static doublereal orgnrm; + static integer lrwmin; + static logical lquery; + static integer smlsiz; + extern /* Subroutine */ int zsteqr_(char *, integer *, doublereal *, + doublereal *, doublecomplex *, integer *, doublereal *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZSTEDC computes all eigenvalues and, optionally, eigenvectors of a + symmetric tridiagonal matrix using the divide and conquer method. + The eigenvectors of a full or band complex Hermitian matrix can also + be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this + matrix to tridiagonal form. + + This code makes very mild assumptions about floating point + arithmetic. It will work on machines with a guard digit in + add/subtract, or on those binary machines without guard digits + which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. + It could conceivably fail on hexadecimal or decimal machines + without guard digits, but we know of none. See DLAED3 for details. + + Arguments + ========= + + COMPZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only. + = 'I': Compute eigenvectors of tridiagonal matrix also. + = 'V': Compute eigenvectors of original Hermitian matrix + also. On entry, Z contains the unitary matrix used + to reduce the original matrix to tridiagonal form. + + N (input) INTEGER + The dimension of the symmetric tridiagonal matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + On entry, the subdiagonal elements of the tridiagonal matrix. + On exit, E has been destroyed. + + Z (input/output) COMPLEX*16 array, dimension (LDZ,N) + On entry, if COMPZ = 'V', then Z contains the unitary + matrix used in the reduction to tridiagonal form. + On exit, if INFO = 0, then if COMPZ = 'V', Z contains the + orthonormal eigenvectors of the original Hermitian matrix, + and if COMPZ = 'I', Z contains the orthonormal eigenvectors + of the symmetric tridiagonal matrix. + If COMPZ = 'N', then Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= 1. + If eigenvectors are desired, then LDZ >= max(1,N). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If COMPZ = 'N' or 'I', or N <= 1, LWORK must be at least 1. + If COMPZ = 'V' and N > 1, LWORK must be at least N*N. + Note that for COMPZ = 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LWORK need + only be 1. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal sizes of the WORK, RWORK and + IWORK arrays, returns these values as the first entries of + the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + RWORK (workspace/output) DOUBLE PRECISION array, + dimension (LRWORK) + On exit, if INFO = 0, RWORK(1) returns the optimal LRWORK. + + LRWORK (input) INTEGER + The dimension of the array RWORK. + If COMPZ = 'N' or N <= 1, LRWORK must be at least 1. + If COMPZ = 'V' and N > 1, LRWORK must be at least + 1 + 3*N + 2*N*lg N + 3*N**2 , + where lg( N ) = smallest integer k such + that 2**k >= N. + If COMPZ = 'I' and N > 1, LRWORK must be at least + 1 + 4*N + 2*N**2 . + Note that for COMPZ = 'I' or 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LRWORK + need only be max(1,2*(N-1)). + + If LRWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK, RWORK + and IWORK arrays, returns these values as the first entries + of the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) + On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. + + LIWORK (input) INTEGER + The dimension of the array IWORK. + If COMPZ = 'N' or N <= 1, LIWORK must be at least 1. + If COMPZ = 'V' or N > 1, LIWORK must be at least + 6 + 6*N + 5*N*lg N. + If COMPZ = 'I' or N > 1, LIWORK must be at least + 3 + 5*N . + Note that for COMPZ = 'I' or 'V', then if N is less than or + equal to the minimum divide size, usually 25, then LIWORK + need only be 1. + + If LIWORK = -1, then a workspace query is assumed; the + routine only calculates the optimal sizes of the WORK, RWORK + and IWORK arrays, returns these values as the first entries + of the WORK, RWORK and IWORK arrays, and no error message + related to LWORK or LRWORK or LIWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit. + < 0: if INFO = -i, the i-th argument had an illegal value. + > 0: The algorithm failed to compute an eigenvalue while + working on the submatrix lying in rows and columns + INFO/(N+1) through mod(INFO,N+1). + + Further Details + =============== + + Based on contributions by + Jeff Rutter, Computer Science Division, University of California + at Berkeley, USA + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1 || *lrwork == -1 || *liwork == -1; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + + if (*info == 0) { + +/* Compute the workspace requirements */ + + smlsiz = ilaenv_(&c__9, "ZSTEDC", " ", &c__0, &c__0, &c__0, &c__0, ( + ftnlen)6, (ftnlen)1); + if (*n <= 1 || icompz == 0) { + lwmin = 1; + liwmin = 1; + lrwmin = 1; + } else if (*n <= smlsiz) { + lwmin = 1; + liwmin = 1; + lrwmin = *n - 1 << 1; + } else if (icompz == 1) { + lgn = (integer) (log((doublereal) (*n)) / log(2.)); + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + lwmin = *n * *n; +/* Computing 2nd power */ + i__1 = *n; + lrwmin = *n * 3 + 1 + (*n << 1) * lgn + i__1 * i__1 * 3; + liwmin = *n * 6 + 6 + *n * 5 * lgn; + } else if (icompz == 2) { + lwmin = 1; +/* Computing 2nd power */ + i__1 = *n; + lrwmin = (*n << 2) + 1 + (i__1 * i__1 << 1); + liwmin = *n * 5 + 3; + } + work[1].r = (doublereal) lwmin, work[1].i = 0.; + rwork[1] = (doublereal) lrwmin; + iwork[1] = liwmin; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*lrwork < lrwmin && ! lquery) { + *info = -10; + } else if (*liwork < liwmin && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZSTEDC", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*n == 1) { + if (icompz != 0) { + i__1 = z_dim1 + 1; + z__[i__1].r = 1., z__[i__1].i = 0.; + } + return 0; + } + +/* + If the following conditional clause is removed, then the routine + will use the Divide and Conquer routine to compute only the + eigenvalues, which requires (3N + 3N**2) real workspace and + (2 + 5N + 2N lg(N)) integer workspace. + Since on many architectures DSTERF is much faster than any other + algorithm for finding eigenvalues only, it is used here + as the default. If the conditional clause is removed, then + information on the size of workspace needs to be changed. + + If COMPZ = 'N', use DSTERF to compute the eigenvalues. +*/ + + if (icompz == 0) { + dsterf_(n, &d__[1], &e[1], info); + goto L70; + } + +/* + If N is smaller than the minimum divide size (SMLSIZ+1), then + solve the problem with another solver. +*/ + + if (*n <= smlsiz) { + + zsteqr_(compz, n, &d__[1], &e[1], &z__[z_offset], ldz, &rwork[1], + info); + + } else { + +/* If COMPZ = 'I', we simply call DSTEDC instead. */ + + if (icompz == 2) { + dlaset_("Full", n, n, &c_b328, &c_b1034, &rwork[1], n); + ll = *n * *n + 1; + i__1 = *lrwork - ll + 1; + dstedc_("I", n, &d__[1], &e[1], &rwork[1], n, &rwork[ll], &i__1, & + iwork[1], liwork, info); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * z_dim1; + i__4 = (j - 1) * *n + i__; + z__[i__3].r = rwork[i__4], z__[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + goto L70; + } + +/* + From now on, only option left to be handled is COMPZ = 'V', + i.e. ICOMPZ = 1. + + Scale. +*/ + + orgnrm = dlanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.) { + goto L70; + } + + eps = EPSILON; + + start = 1; + +/* while ( START <= N ) */ + +L30: + if (start <= *n) { + +/* + Let FINISH be the position of the next subdiagonal entry + such that E( FINISH ) <= TINY or FINISH = N if no such + subdiagonal exists. The matrix identified by the elements + between START and FINISH constitutes an independent + sub-problem. +*/ + + finish = start; +L40: + if (finish < *n) { + tiny = eps * sqrt((d__1 = d__[finish], abs(d__1))) * sqrt(( + d__2 = d__[finish + 1], abs(d__2))); + if ((d__1 = e[finish], abs(d__1)) > tiny) { + ++finish; + goto L40; + } + } + +/* (Sub) Problem determined. Compute its size and solve it. */ + + m = finish - start + 1; + if (m > smlsiz) { + +/* Scale. */ + + orgnrm = dlanst_("M", &m, &d__[start], &e[start]); + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b1034, &m, &c__1, &d__[ + start], &m, info); + i__1 = m - 1; + i__2 = m - 1; + dlascl_("G", &c__0, &c__0, &orgnrm, &c_b1034, &i__1, &c__1, & + e[start], &i__2, info); + + zlaed0_(n, &m, &d__[start], &e[start], &z__[start * z_dim1 + + 1], ldz, &work[1], n, &rwork[1], &iwork[1], info); + if (*info > 0) { + *info = (*info / (m + 1) + start - 1) * (*n + 1) + *info % + (m + 1) + start - 1; + goto L70; + } + +/* Scale back. */ + + dlascl_("G", &c__0, &c__0, &c_b1034, &orgnrm, &m, &c__1, &d__[ + start], &m, info); + + } else { + dsteqr_("I", &m, &d__[start], &e[start], &rwork[1], &m, & + rwork[m * m + 1], info); + zlacrm_(n, &m, &z__[start * z_dim1 + 1], ldz, &rwork[1], &m, & + work[1], n, &rwork[m * m + 1]); + zlacpy_("A", n, &m, &work[1], n, &z__[start * z_dim1 + 1], + ldz); + if (*info > 0) { + *info = start * (*n + 1) + finish; + goto L70; + } + } + + start = finish + 1; + goto L30; + } + +/* + endwhile + + If the problem split any number of times, then the eigenvalues + will not be properly ordered. Here we permute the eigenvalues + (and the associated eigenvectors) into ascending order. +*/ + + if (m != *n) { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L50: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + zswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + + 1], &c__1); + } +/* L60: */ + } + } + } + +L70: + work[1].r = (doublereal) lwmin, work[1].i = 0.; + rwork[1] = (doublereal) lrwmin; + iwork[1] = liwmin; + + return 0; + +/* End of ZSTEDC */ + +} /* zstedc_ */ + +/* Subroutine */ int zsteqr_(char *compz, integer *n, doublereal *d__, + doublereal *e, doublecomplex *z__, integer *ldz, doublereal *work, + integer *info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2; + doublereal d__1, d__2; + + /* Local variables */ + static doublereal b, c__, f, g; + static integer i__, j, k, l, m; + static doublereal p, r__, s; + static integer l1, ii, mm, lm1, mm1, nm1; + static doublereal rt1, rt2, eps; + static integer lsv; + static doublereal tst, eps2; + static integer lend, jtot; + extern /* Subroutine */ int dlae2_(doublereal *, doublereal *, doublereal + *, doublereal *, doublereal *); + extern logical lsame_(char *, char *); + static doublereal anorm; + extern /* Subroutine */ int zlasr_(char *, char *, char *, integer *, + integer *, doublereal *, doublereal *, doublecomplex *, integer *), zswap_(integer *, doublecomplex *, + integer *, doublecomplex *, integer *), dlaev2_(doublereal *, + doublereal *, doublereal *, doublereal *, doublereal *, + doublereal *, doublereal *); + static integer lendm1, lendp1; + + static integer iscale; + extern /* Subroutine */ int dlascl_(char *, integer *, integer *, + doublereal *, doublereal *, integer *, integer *, doublereal *, + integer *, integer *); + static doublereal safmin; + extern /* Subroutine */ int dlartg_(doublereal *, doublereal *, + doublereal *, doublereal *, doublereal *); + static doublereal safmax; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern doublereal dlanst_(char *, integer *, doublereal *, doublereal *); + extern /* Subroutine */ int dlasrt_(char *, integer *, doublereal *, + integer *); + static integer lendsv; + static doublereal ssfmin; + static integer nmaxit, icompz; + static doublereal ssfmax; + extern /* Subroutine */ int zlaset_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, doublecomplex *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZSTEQR computes all eigenvalues and, optionally, eigenvectors of a + symmetric tridiagonal matrix using the implicit QL or QR method. + The eigenvectors of a full or band complex Hermitian matrix can also + be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this + matrix to tridiagonal form. + + Arguments + ========= + + COMPZ (input) CHARACTER*1 + = 'N': Compute eigenvalues only. + = 'V': Compute eigenvalues and eigenvectors of the original + Hermitian matrix. On entry, Z must contain the + unitary matrix used to reduce the original matrix + to tridiagonal form. + = 'I': Compute eigenvalues and eigenvectors of the + tridiagonal matrix. Z is initialized to the identity + matrix. + + N (input) INTEGER + The order of the matrix. N >= 0. + + D (input/output) DOUBLE PRECISION array, dimension (N) + On entry, the diagonal elements of the tridiagonal matrix. + On exit, if INFO = 0, the eigenvalues in ascending order. + + E (input/output) DOUBLE PRECISION array, dimension (N-1) + On entry, the (n-1) subdiagonal elements of the tridiagonal + matrix. + On exit, E has been destroyed. + + Z (input/output) COMPLEX*16 array, dimension (LDZ, N) + On entry, if COMPZ = 'V', then Z contains the unitary + matrix used in the reduction to tridiagonal form. + On exit, if INFO = 0, then if COMPZ = 'V', Z contains the + orthonormal eigenvectors of the original Hermitian matrix, + and if COMPZ = 'I', Z contains the orthonormal eigenvectors + of the symmetric tridiagonal matrix. + If COMPZ = 'N', then Z is not referenced. + + LDZ (input) INTEGER + The leading dimension of the array Z. LDZ >= 1, and if + eigenvectors are desired, then LDZ >= max(1,N). + + WORK (workspace) DOUBLE PRECISION array, dimension (max(1,2*N-2)) + If COMPZ = 'N', then WORK is not referenced. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: the algorithm has failed to find all the eigenvalues in + a total of 30*N iterations; if INFO = i, then i + elements of E have not converged to zero; on exit, D + and E contain the elements of a symmetric tridiagonal + matrix which is unitarily similar to the original + matrix. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + + /* Function Body */ + *info = 0; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZSTEQR", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (*n == 1) { + if (icompz == 2) { + i__1 = z_dim1 + 1; + z__[i__1].r = 1., z__[i__1].i = 0.; + } + return 0; + } + +/* Determine the unit roundoff and over/underflow thresholds. */ + + eps = EPSILON; +/* Computing 2nd power */ + d__1 = eps; + eps2 = d__1 * d__1; + safmin = SAFEMINIMUM; + safmax = 1. / safmin; + ssfmax = sqrt(safmax) / 3.; + ssfmin = sqrt(safmin) / eps2; + +/* + Compute the eigenvalues and eigenvectors of the tridiagonal + matrix. +*/ + + if (icompz == 2) { + zlaset_("Full", n, n, &c_b56, &c_b57, &z__[z_offset], ldz); + } + + nmaxit = *n * 30; + jtot = 0; + +/* + Determine where the matrix splits and choose QL or QR iteration + for each block, according to whether top or bottom diagonal + element is smaller. +*/ + + l1 = 1; + nm1 = *n - 1; + +L10: + if (l1 > *n) { + goto L160; + } + if (l1 > 1) { + e[l1 - 1] = 0.; + } + if (l1 <= nm1) { + i__1 = nm1; + for (m = l1; m <= i__1; ++m) { + tst = (d__1 = e[m], abs(d__1)); + if (tst == 0.) { + goto L30; + } + if (tst <= sqrt((d__1 = d__[m], abs(d__1))) * sqrt((d__2 = d__[m + + 1], abs(d__2))) * eps) { + e[m] = 0.; + goto L30; + } +/* L20: */ + } + } + m = *n; + +L30: + l = l1; + lsv = l; + lend = m; + lendsv = lend; + l1 = m + 1; + if (lend == l) { + goto L10; + } + +/* Scale submatrix in rows and columns L to LEND */ + + i__1 = lend - l + 1; + anorm = dlanst_("I", &i__1, &d__[l], &e[l]); + iscale = 0; + if (anorm == 0.) { + goto L10; + } + if (anorm > ssfmax) { + iscale = 1; + i__1 = lend - l + 1; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmax, &i__1, &c__1, &e[l], n, + info); + } else if (anorm < ssfmin) { + iscale = 2; + i__1 = lend - l + 1; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &d__[l], n, + info); + i__1 = lend - l; + dlascl_("G", &c__0, &c__0, &anorm, &ssfmin, &i__1, &c__1, &e[l], n, + info); + } + +/* Choose between QL and QR iteration */ + + if ((d__1 = d__[lend], abs(d__1)) < (d__2 = d__[l], abs(d__2))) { + lend = lsv; + l = lendsv; + } + + if (lend > l) { + +/* + QL Iteration + + Look for small subdiagonal element. +*/ + +L40: + if (l != lend) { + lendm1 = lend - 1; + i__1 = lendm1; + for (m = l; m <= i__1; ++m) { +/* Computing 2nd power */ + d__2 = (d__1 = e[m], abs(d__1)); + tst = d__2 * d__2; + if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m + + 1], abs(d__2)) + safmin) { + goto L60; + } +/* L50: */ + } + } + + m = lend; + +L60: + if (m < lend) { + e[m] = 0.; + } + p = d__[l]; + if (m == l) { + goto L80; + } + +/* + If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 + to compute its eigensystem. +*/ + + if (m == l + 1) { + if (icompz > 0) { + dlaev2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2, &c__, &s); + work[l] = c__; + work[*n - 1 + l] = s; + zlasr_("R", "V", "B", n, &c__2, &work[l], &work[*n - 1 + l], & + z__[l * z_dim1 + 1], ldz); + } else { + dlae2_(&d__[l], &e[l], &d__[l + 1], &rt1, &rt2); + } + d__[l] = rt1; + d__[l + 1] = rt2; + e[l] = 0.; + l += 2; + if (l <= lend) { + goto L40; + } + goto L140; + } + + if (jtot == nmaxit) { + goto L140; + } + ++jtot; + +/* Form shift. */ + + g = (d__[l + 1] - p) / (e[l] * 2.); + r__ = dlapy2_(&g, &c_b1034); + g = d__[m] - p + e[l] / (g + d_sign(&r__, &g)); + + s = 1.; + c__ = 1.; + p = 0.; + +/* Inner loop */ + + mm1 = m - 1; + i__1 = l; + for (i__ = mm1; i__ >= i__1; --i__) { + f = s * e[i__]; + b = c__ * e[i__]; + dlartg_(&g, &f, &c__, &s, &r__); + if (i__ != m - 1) { + e[i__ + 1] = r__; + } + g = d__[i__ + 1] - p; + r__ = (d__[i__] - g) * s + c__ * 2. * b; + p = s * r__; + d__[i__ + 1] = g + p; + g = c__ * r__ - b; + +/* If eigenvectors are desired, then save rotations. */ + + if (icompz > 0) { + work[i__] = c__; + work[*n - 1 + i__] = -s; + } + +/* L70: */ + } + +/* If eigenvectors are desired, then apply saved rotations. */ + + if (icompz > 0) { + mm = m - l + 1; + zlasr_("R", "V", "B", n, &mm, &work[l], &work[*n - 1 + l], &z__[l + * z_dim1 + 1], ldz); + } + + d__[l] -= p; + e[l] = g; + goto L40; + +/* Eigenvalue found. */ + +L80: + d__[l] = p; + + ++l; + if (l <= lend) { + goto L40; + } + goto L140; + + } else { + +/* + QR Iteration + + Look for small superdiagonal element. +*/ + +L90: + if (l != lend) { + lendp1 = lend + 1; + i__1 = lendp1; + for (m = l; m >= i__1; --m) { +/* Computing 2nd power */ + d__2 = (d__1 = e[m - 1], abs(d__1)); + tst = d__2 * d__2; + if (tst <= eps2 * (d__1 = d__[m], abs(d__1)) * (d__2 = d__[m + - 1], abs(d__2)) + safmin) { + goto L110; + } +/* L100: */ + } + } + + m = lend; + +L110: + if (m > lend) { + e[m - 1] = 0.; + } + p = d__[l]; + if (m == l) { + goto L130; + } + +/* + If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 + to compute its eigensystem. +*/ + + if (m == l - 1) { + if (icompz > 0) { + dlaev2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2, &c__, &s) + ; + work[m] = c__; + work[*n - 1 + m] = s; + zlasr_("R", "V", "F", n, &c__2, &work[m], &work[*n - 1 + m], & + z__[(l - 1) * z_dim1 + 1], ldz); + } else { + dlae2_(&d__[l - 1], &e[l - 1], &d__[l], &rt1, &rt2); + } + d__[l - 1] = rt1; + d__[l] = rt2; + e[l - 1] = 0.; + l += -2; + if (l >= lend) { + goto L90; + } + goto L140; + } + + if (jtot == nmaxit) { + goto L140; + } + ++jtot; + +/* Form shift. */ + + g = (d__[l - 1] - p) / (e[l - 1] * 2.); + r__ = dlapy2_(&g, &c_b1034); + g = d__[m] - p + e[l - 1] / (g + d_sign(&r__, &g)); + + s = 1.; + c__ = 1.; + p = 0.; + +/* Inner loop */ + + lm1 = l - 1; + i__1 = lm1; + for (i__ = m; i__ <= i__1; ++i__) { + f = s * e[i__]; + b = c__ * e[i__]; + dlartg_(&g, &f, &c__, &s, &r__); + if (i__ != m) { + e[i__ - 1] = r__; + } + g = d__[i__] - p; + r__ = (d__[i__ + 1] - g) * s + c__ * 2. * b; + p = s * r__; + d__[i__] = g + p; + g = c__ * r__ - b; + +/* If eigenvectors are desired, then save rotations. */ + + if (icompz > 0) { + work[i__] = c__; + work[*n - 1 + i__] = s; + } + +/* L120: */ + } + +/* If eigenvectors are desired, then apply saved rotations. */ + + if (icompz > 0) { + mm = l - m + 1; + zlasr_("R", "V", "F", n, &mm, &work[m], &work[*n - 1 + m], &z__[m + * z_dim1 + 1], ldz); + } + + d__[l] -= p; + e[lm1] = g; + goto L90; + +/* Eigenvalue found. */ + +L130: + d__[l] = p; + + --l; + if (l >= lend) { + goto L90; + } + goto L140; + + } + +/* Undo scaling if necessary */ + +L140: + if (iscale == 1) { + i__1 = lendsv - lsv + 1; + dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + i__1 = lendsv - lsv; + dlascl_("G", &c__0, &c__0, &ssfmax, &anorm, &i__1, &c__1, &e[lsv], n, + info); + } else if (iscale == 2) { + i__1 = lendsv - lsv + 1; + dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &d__[lsv], + n, info); + i__1 = lendsv - lsv; + dlascl_("G", &c__0, &c__0, &ssfmin, &anorm, &i__1, &c__1, &e[lsv], n, + info); + } + +/* + Check for no convergence to an eigenvalue after a total + of N*MAXIT iterations. +*/ + + if (jtot == nmaxit) { + i__1 = *n - 1; + for (i__ = 1; i__ <= i__1; ++i__) { + if (e[i__] != 0.) { + ++(*info); + } +/* L150: */ + } + return 0; + } + goto L10; + +/* Order eigenvalues and eigenvectors. */ + +L160: + if (icompz == 0) { + +/* Use Quick Sort */ + + dlasrt_("I", n, &d__[1], info); + + } else { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L170: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + zswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + 1], + &c__1); + } +/* L180: */ + } + } + return 0; + +/* End of ZSTEQR */ + +} /* zsteqr_ */ + +/* Subroutine */ int ztrevc_(char *side, char *howmny, logical *select, + integer *n, doublecomplex *t, integer *ldt, doublecomplex *vl, + integer *ldvl, doublecomplex *vr, integer *ldvr, integer *mm, integer + *m, doublecomplex *work, doublereal *rwork, integer *info) +{ + /* System generated locals */ + integer t_dim1, t_offset, vl_dim1, vl_offset, vr_dim1, vr_offset, i__1, + i__2, i__3, i__4, i__5; + doublereal d__1, d__2, d__3; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, j, k, ii, ki, is; + static doublereal ulp; + static logical allv; + static doublereal unfl, ovfl, smin; + static logical over; + static doublereal scale; + extern logical lsame_(char *, char *); + static doublereal remax; + static logical leftv, bothv; + extern /* Subroutine */ int zgemv_(char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *, doublecomplex *, doublecomplex *, integer *); + static logical somev; + extern /* Subroutine */ int zcopy_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *), dlabad_(doublereal *, doublereal *); + + extern /* Subroutine */ int xerbla_(char *, integer *), zdscal_( + integer *, doublereal *, doublecomplex *, integer *); + extern integer izamax_(integer *, doublecomplex *, integer *); + static logical rightv; + extern doublereal dzasum_(integer *, doublecomplex *, integer *); + static doublereal smlnum; + extern /* Subroutine */ int zlatrs_(char *, char *, char *, char *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublereal *, doublereal *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZTREVC computes some or all of the right and/or left eigenvectors of + a complex upper triangular matrix T. + Matrices of this type are produced by the Schur factorization of + a complex general matrix: A = Q*T*Q**H, as computed by ZHSEQR. + + The right eigenvector x and the left eigenvector y of T corresponding + to an eigenvalue w are defined by: + + T*x = w*x, (y**H)*T = w*(y**H) + + where y**H denotes the conjugate transpose of the vector y. + The eigenvalues are not input to this routine, but are read directly + from the diagonal of T. + + This routine returns the matrices X and/or Y of right and left + eigenvectors of T, or the products Q*X and/or Q*Y, where Q is an + input matrix. If Q is the unitary factor that reduces a matrix A to + Schur form T, then Q*X and Q*Y are the matrices of right and left + eigenvectors of A. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'R': compute right eigenvectors only; + = 'L': compute left eigenvectors only; + = 'B': compute both right and left eigenvectors. + + HOWMNY (input) CHARACTER*1 + = 'A': compute all right and/or left eigenvectors; + = 'B': compute all right and/or left eigenvectors, + backtransformed using the matrices supplied in + VR and/or VL; + = 'S': compute selected right and/or left eigenvectors, + as indicated by the logical array SELECT. + + SELECT (input) LOGICAL array, dimension (N) + If HOWMNY = 'S', SELECT specifies the eigenvectors to be + computed. + The eigenvector corresponding to the j-th eigenvalue is + computed if SELECT(j) = .TRUE.. + Not referenced if HOWMNY = 'A' or 'B'. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input/output) COMPLEX*16 array, dimension (LDT,N) + The upper triangular matrix T. T is modified, but restored + on exit. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + VL (input/output) COMPLEX*16 array, dimension (LDVL,MM) + On entry, if SIDE = 'L' or 'B' and HOWMNY = 'B', VL must + contain an N-by-N matrix Q (usually the unitary matrix Q of + Schur vectors returned by ZHSEQR). + On exit, if SIDE = 'L' or 'B', VL contains: + if HOWMNY = 'A', the matrix Y of left eigenvectors of T; + if HOWMNY = 'B', the matrix Q*Y; + if HOWMNY = 'S', the left eigenvectors of T specified by + SELECT, stored consecutively in the columns + of VL, in the same order as their + eigenvalues. + Not referenced if SIDE = 'R'. + + LDVL (input) INTEGER + The leading dimension of the array VL. LDVL >= 1, and if + SIDE = 'L' or 'B', LDVL >= N. + + VR (input/output) COMPLEX*16 array, dimension (LDVR,MM) + On entry, if SIDE = 'R' or 'B' and HOWMNY = 'B', VR must + contain an N-by-N matrix Q (usually the unitary matrix Q of + Schur vectors returned by ZHSEQR). + On exit, if SIDE = 'R' or 'B', VR contains: + if HOWMNY = 'A', the matrix X of right eigenvectors of T; + if HOWMNY = 'B', the matrix Q*X; + if HOWMNY = 'S', the right eigenvectors of T specified by + SELECT, stored consecutively in the columns + of VR, in the same order as their + eigenvalues. + Not referenced if SIDE = 'L'. + + LDVR (input) INTEGER + The leading dimension of the array VR. LDVR >= 1, and if + SIDE = 'R' or 'B'; LDVR >= N. + + MM (input) INTEGER + The number of columns in the arrays VL and/or VR. MM >= M. + + M (output) INTEGER + The number of columns in the arrays VL and/or VR actually + used to store the eigenvectors. If HOWMNY = 'A' or 'B', M + is set to N. Each selected eigenvector occupies one + column. + + WORK (workspace) COMPLEX*16 array, dimension (2*N) + + RWORK (workspace) DOUBLE PRECISION array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + Further Details + =============== + + The algorithm used in this program is basically backward (forward) + substitution, with scaling to make the the code robust against + possible overflow. + + Each eigenvector is normalized so that the element of largest + magnitude has magnitude 1; here the magnitude of a complex number + (x,y) is taken to be |x| + |y|. + + ===================================================================== + + + Decode and test the input parameters +*/ + + /* Parameter adjustments */ + --select; + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + vl_dim1 = *ldvl; + vl_offset = 1 + vl_dim1; + vl -= vl_offset; + vr_dim1 = *ldvr; + vr_offset = 1 + vr_dim1; + vr -= vr_offset; + --work; + --rwork; + + /* Function Body */ + bothv = lsame_(side, "B"); + rightv = lsame_(side, "R") || bothv; + leftv = lsame_(side, "L") || bothv; + + allv = lsame_(howmny, "A"); + over = lsame_(howmny, "B"); + somev = lsame_(howmny, "S"); + +/* + Set M to the number of columns required to store the selected + eigenvectors. +*/ + + if (somev) { + *m = 0; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (select[j]) { + ++(*m); + } +/* L10: */ + } + } else { + *m = *n; + } + + *info = 0; + if (! rightv && ! leftv) { + *info = -1; + } else if (! allv && ! over && ! somev) { + *info = -2; + } else if (*n < 0) { + *info = -4; + } else if (*ldt < max(1,*n)) { + *info = -6; + } else if (*ldvl < 1 || leftv && *ldvl < *n) { + *info = -8; + } else if (*ldvr < 1 || rightv && *ldvr < *n) { + *info = -10; + } else if (*mm < *m) { + *info = -11; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZTREVC", &i__1); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + +/* Set the constants to control overflow. */ + + unfl = SAFEMINIMUM; + ovfl = 1. / unfl; + dlabad_(&unfl, &ovfl); + ulp = PRECISION; + smlnum = unfl * (*n / ulp); + +/* Store the diagonal elements of T in working array WORK. */ + + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__ + *n; + i__3 = i__ + i__ * t_dim1; + work[i__2].r = t[i__3].r, work[i__2].i = t[i__3].i; +/* L20: */ + } + +/* + Compute 1-norm of each column of strictly upper triangular + part of T to control overflow in triangular solver. +*/ + + rwork[1] = 0.; + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + i__2 = j - 1; + rwork[j] = dzasum_(&i__2, &t[j * t_dim1 + 1], &c__1); +/* L30: */ + } + + if (rightv) { + +/* Compute right eigenvectors. */ + + is = *m; + for (ki = *n; ki >= 1; --ki) { + + if (somev) { + if (! select[ki]) { + goto L80; + } + } +/* Computing MAX */ + i__1 = ki + ki * t_dim1; + d__3 = ulp * ((d__1 = t[i__1].r, abs(d__1)) + (d__2 = d_imag(&t[ + ki + ki * t_dim1]), abs(d__2))); + smin = max(d__3,smlnum); + + work[1].r = 1., work[1].i = 0.; + +/* Form right-hand side. */ + + i__1 = ki - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = k; + i__3 = k + ki * t_dim1; + z__1.r = -t[i__3].r, z__1.i = -t[i__3].i; + work[i__2].r = z__1.r, work[i__2].i = z__1.i; +/* L40: */ + } + +/* + Solve the triangular system: + (T(1:KI-1,1:KI-1) - T(KI,KI))*X = SCALE*WORK. +*/ + + i__1 = ki - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = k + k * t_dim1; + i__3 = k + k * t_dim1; + i__4 = ki + ki * t_dim1; + z__1.r = t[i__3].r - t[i__4].r, z__1.i = t[i__3].i - t[i__4] + .i; + t[i__2].r = z__1.r, t[i__2].i = z__1.i; + i__2 = k + k * t_dim1; + if ((d__1 = t[i__2].r, abs(d__1)) + (d__2 = d_imag(&t[k + k * + t_dim1]), abs(d__2)) < smin) { + i__3 = k + k * t_dim1; + t[i__3].r = smin, t[i__3].i = 0.; + } +/* L50: */ + } + + if (ki > 1) { + i__1 = ki - 1; + zlatrs_("Upper", "No transpose", "Non-unit", "Y", &i__1, &t[ + t_offset], ldt, &work[1], &scale, &rwork[1], info); + i__1 = ki; + work[i__1].r = scale, work[i__1].i = 0.; + } + +/* Copy the vector x or Q*x to VR and normalize. */ + + if (! over) { + zcopy_(&ki, &work[1], &c__1, &vr[is * vr_dim1 + 1], &c__1); + + ii = izamax_(&ki, &vr[is * vr_dim1 + 1], &c__1); + i__1 = ii + is * vr_dim1; + remax = 1. / ((d__1 = vr[i__1].r, abs(d__1)) + (d__2 = d_imag( + &vr[ii + is * vr_dim1]), abs(d__2))); + zdscal_(&ki, &remax, &vr[is * vr_dim1 + 1], &c__1); + + i__1 = *n; + for (k = ki + 1; k <= i__1; ++k) { + i__2 = k + is * vr_dim1; + vr[i__2].r = 0., vr[i__2].i = 0.; +/* L60: */ + } + } else { + if (ki > 1) { + i__1 = ki - 1; + z__1.r = scale, z__1.i = 0.; + zgemv_("N", n, &i__1, &c_b57, &vr[vr_offset], ldvr, &work[ + 1], &c__1, &z__1, &vr[ki * vr_dim1 + 1], &c__1); + } + + ii = izamax_(n, &vr[ki * vr_dim1 + 1], &c__1); + i__1 = ii + ki * vr_dim1; + remax = 1. / ((d__1 = vr[i__1].r, abs(d__1)) + (d__2 = d_imag( + &vr[ii + ki * vr_dim1]), abs(d__2))); + zdscal_(n, &remax, &vr[ki * vr_dim1 + 1], &c__1); + } + +/* Set back the original diagonal elements of T. */ + + i__1 = ki - 1; + for (k = 1; k <= i__1; ++k) { + i__2 = k + k * t_dim1; + i__3 = k + *n; + t[i__2].r = work[i__3].r, t[i__2].i = work[i__3].i; +/* L70: */ + } + + --is; +L80: + ; + } + } + + if (leftv) { + +/* Compute left eigenvectors. */ + + is = 1; + i__1 = *n; + for (ki = 1; ki <= i__1; ++ki) { + + if (somev) { + if (! select[ki]) { + goto L130; + } + } +/* Computing MAX */ + i__2 = ki + ki * t_dim1; + d__3 = ulp * ((d__1 = t[i__2].r, abs(d__1)) + (d__2 = d_imag(&t[ + ki + ki * t_dim1]), abs(d__2))); + smin = max(d__3,smlnum); + + i__2 = *n; + work[i__2].r = 1., work[i__2].i = 0.; + +/* Form right-hand side. */ + + i__2 = *n; + for (k = ki + 1; k <= i__2; ++k) { + i__3 = k; + d_cnjg(&z__2, &t[ki + k * t_dim1]); + z__1.r = -z__2.r, z__1.i = -z__2.i; + work[i__3].r = z__1.r, work[i__3].i = z__1.i; +/* L90: */ + } + +/* + Solve the triangular system: + (T(KI+1:N,KI+1:N) - T(KI,KI))'*X = SCALE*WORK. +*/ + + i__2 = *n; + for (k = ki + 1; k <= i__2; ++k) { + i__3 = k + k * t_dim1; + i__4 = k + k * t_dim1; + i__5 = ki + ki * t_dim1; + z__1.r = t[i__4].r - t[i__5].r, z__1.i = t[i__4].i - t[i__5] + .i; + t[i__3].r = z__1.r, t[i__3].i = z__1.i; + i__3 = k + k * t_dim1; + if ((d__1 = t[i__3].r, abs(d__1)) + (d__2 = d_imag(&t[k + k * + t_dim1]), abs(d__2)) < smin) { + i__4 = k + k * t_dim1; + t[i__4].r = smin, t[i__4].i = 0.; + } +/* L100: */ + } + + if (ki < *n) { + i__2 = *n - ki; + zlatrs_("Upper", "Conjugate transpose", "Non-unit", "Y", & + i__2, &t[ki + 1 + (ki + 1) * t_dim1], ldt, &work[ki + + 1], &scale, &rwork[1], info); + i__2 = ki; + work[i__2].r = scale, work[i__2].i = 0.; + } + +/* Copy the vector x or Q*x to VL and normalize. */ + + if (! over) { + i__2 = *n - ki + 1; + zcopy_(&i__2, &work[ki], &c__1, &vl[ki + is * vl_dim1], &c__1) + ; + + i__2 = *n - ki + 1; + ii = izamax_(&i__2, &vl[ki + is * vl_dim1], &c__1) + ki - 1; + i__2 = ii + is * vl_dim1; + remax = 1. / ((d__1 = vl[i__2].r, abs(d__1)) + (d__2 = d_imag( + &vl[ii + is * vl_dim1]), abs(d__2))); + i__2 = *n - ki + 1; + zdscal_(&i__2, &remax, &vl[ki + is * vl_dim1], &c__1); + + i__2 = ki - 1; + for (k = 1; k <= i__2; ++k) { + i__3 = k + is * vl_dim1; + vl[i__3].r = 0., vl[i__3].i = 0.; +/* L110: */ + } + } else { + if (ki < *n) { + i__2 = *n - ki; + z__1.r = scale, z__1.i = 0.; + zgemv_("N", n, &i__2, &c_b57, &vl[(ki + 1) * vl_dim1 + 1], + ldvl, &work[ki + 1], &c__1, &z__1, &vl[ki * + vl_dim1 + 1], &c__1); + } + + ii = izamax_(n, &vl[ki * vl_dim1 + 1], &c__1); + i__2 = ii + ki * vl_dim1; + remax = 1. / ((d__1 = vl[i__2].r, abs(d__1)) + (d__2 = d_imag( + &vl[ii + ki * vl_dim1]), abs(d__2))); + zdscal_(n, &remax, &vl[ki * vl_dim1 + 1], &c__1); + } + +/* Set back the original diagonal elements of T. */ + + i__2 = *n; + for (k = ki + 1; k <= i__2; ++k) { + i__3 = k + k * t_dim1; + i__4 = k + *n; + t[i__3].r = work[i__4].r, t[i__3].i = work[i__4].i; +/* L120: */ + } + + ++is; +L130: + ; + } + } + + return 0; + +/* End of ZTREVC */ + +} /* ztrevc_ */ + +/* Subroutine */ int ztrexc_(char *compq, integer *n, doublecomplex *t, + integer *ldt, doublecomplex *q, integer *ldq, integer *ifst, integer * + ilst, integer *info) +{ + /* System generated locals */ + integer q_dim1, q_offset, t_dim1, t_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer k, m1, m2, m3; + static doublereal cs; + static doublecomplex t11, t22, sn, temp; + extern /* Subroutine */ int zrot_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublereal *, doublecomplex *); + extern logical lsame_(char *, char *); + static logical wantq; + extern /* Subroutine */ int xerbla_(char *, integer *), zlartg_( + doublecomplex *, doublecomplex *, doublereal *, doublecomplex *, + doublecomplex *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZTREXC reorders the Schur factorization of a complex matrix + A = Q*T*Q**H, so that the diagonal element of T with row index IFST + is moved to row ILST. + + The Schur form T is reordered by a unitary similarity transformation + Z**H*T*Z, and optionally the matrix Q of Schur vectors is updated by + postmultplying it with Z. + + Arguments + ========= + + COMPQ (input) CHARACTER*1 + = 'V': update the matrix Q of Schur vectors; + = 'N': do not update Q. + + N (input) INTEGER + The order of the matrix T. N >= 0. + + T (input/output) COMPLEX*16 array, dimension (LDT,N) + On entry, the upper triangular matrix T. + On exit, the reordered upper triangular matrix. + + LDT (input) INTEGER + The leading dimension of the array T. LDT >= max(1,N). + + Q (input/output) COMPLEX*16 array, dimension (LDQ,N) + On entry, if COMPQ = 'V', the matrix Q of Schur vectors. + On exit, if COMPQ = 'V', Q has been postmultiplied by the + unitary transformation matrix Z which reorders T. + If COMPQ = 'N', Q is not referenced. + + LDQ (input) INTEGER + The leading dimension of the array Q. LDQ >= max(1,N). + + IFST (input) INTEGER + ILST (input) INTEGER + Specify the reordering of the diagonal elements of T: + The element with row index IFST is moved to row ILST by a + sequence of transpositions between adjacent elements. + 1 <= IFST <= N; 1 <= ILST <= N. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Decode and test the input parameters. +*/ + + /* Parameter adjustments */ + t_dim1 = *ldt; + t_offset = 1 + t_dim1; + t -= t_offset; + q_dim1 = *ldq; + q_offset = 1 + q_dim1; + q -= q_offset; + + /* Function Body */ + *info = 0; + wantq = lsame_(compq, "V"); + if (! lsame_(compq, "N") && ! wantq) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldt < max(1,*n)) { + *info = -4; + } else if (*ldq < 1 || wantq && *ldq < max(1,*n)) { + *info = -6; + } else if (*ifst < 1 || *ifst > *n) { + *info = -7; + } else if (*ilst < 1 || *ilst > *n) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZTREXC", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 1 || *ifst == *ilst) { + return 0; + } + + if (*ifst < *ilst) { + +/* Move the IFST-th diagonal element forward down the diagonal. */ + + m1 = 0; + m2 = -1; + m3 = 1; + } else { + +/* Move the IFST-th diagonal element backward up the diagonal. */ + + m1 = -1; + m2 = 0; + m3 = -1; + } + + i__1 = *ilst + m2; + i__2 = m3; + for (k = *ifst + m1; i__2 < 0 ? k >= i__1 : k <= i__1; k += i__2) { + +/* Interchange the k-th and (k+1)-th diagonal elements. */ + + i__3 = k + k * t_dim1; + t11.r = t[i__3].r, t11.i = t[i__3].i; + i__3 = k + 1 + (k + 1) * t_dim1; + t22.r = t[i__3].r, t22.i = t[i__3].i; + +/* Determine the transformation to perform the interchange. */ + + z__1.r = t22.r - t11.r, z__1.i = t22.i - t11.i; + zlartg_(&t[k + (k + 1) * t_dim1], &z__1, &cs, &sn, &temp); + +/* Apply transformation to the matrix T. */ + + if (k + 2 <= *n) { + i__3 = *n - k - 1; + zrot_(&i__3, &t[k + (k + 2) * t_dim1], ldt, &t[k + 1 + (k + 2) * + t_dim1], ldt, &cs, &sn); + } + i__3 = k - 1; + d_cnjg(&z__1, &sn); + zrot_(&i__3, &t[k * t_dim1 + 1], &c__1, &t[(k + 1) * t_dim1 + 1], & + c__1, &cs, &z__1); + + i__3 = k + k * t_dim1; + t[i__3].r = t22.r, t[i__3].i = t22.i; + i__3 = k + 1 + (k + 1) * t_dim1; + t[i__3].r = t11.r, t[i__3].i = t11.i; + + if (wantq) { + +/* Accumulate transformation in the matrix Q. */ + + d_cnjg(&z__1, &sn); + zrot_(n, &q[k * q_dim1 + 1], &c__1, &q[(k + 1) * q_dim1 + 1], & + c__1, &cs, &z__1); + } + +/* L10: */ + } + + return 0; + +/* End of ZTREXC */ + +} /* ztrexc_ */ + +/* Subroutine */ int ztrti2_(char *uplo, char *diag, integer *n, + doublecomplex *a, integer *lda, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + doublecomplex z__1; + + /* Local variables */ + static integer j; + static doublecomplex ajj; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *); + static logical upper; + extern /* Subroutine */ int ztrmv_(char *, char *, char *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *), xerbla_(char *, integer *); + static logical nounit; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZTRTI2 computes the inverse of a complex upper or lower triangular + matrix. + + This is the Level 2 BLAS version of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the matrix A is upper or lower triangular. + = 'U': Upper triangular + = 'L': Lower triangular + + DIAG (input) CHARACTER*1 + Specifies whether or not the matrix A is unit triangular. + = 'N': Non-unit triangular + = 'U': Unit triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the triangular matrix A. If UPLO = 'U', the + leading n by n upper triangular part of the array A contains + the upper triangular matrix, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of the array A contains + the lower triangular matrix, and the strictly upper + triangular part of A is not referenced. If DIAG = 'U', the + diagonal elements of A are also not referenced and are + assumed to be 1. + + On exit, the (triangular) inverse of the original matrix, in + the same storage format. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + nounit = lsame_(diag, "N"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZTRTI2", &i__1); + return 0; + } + + if (upper) { + +/* Compute inverse of upper triangular matrix. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (nounit) { + i__2 = j + j * a_dim1; + z_div(&z__1, &c_b57, &a[j + j * a_dim1]); + a[i__2].r = z__1.r, a[i__2].i = z__1.i; + i__2 = j + j * a_dim1; + z__1.r = -a[i__2].r, z__1.i = -a[i__2].i; + ajj.r = z__1.r, ajj.i = z__1.i; + } else { + z__1.r = -1., z__1.i = -0.; + ajj.r = z__1.r, ajj.i = z__1.i; + } + +/* Compute elements 1:j-1 of j-th column. */ + + i__2 = j - 1; + ztrmv_("Upper", "No transpose", diag, &i__2, &a[a_offset], lda, & + a[j * a_dim1 + 1], &c__1); + i__2 = j - 1; + zscal_(&i__2, &ajj, &a[j * a_dim1 + 1], &c__1); +/* L10: */ + } + } else { + +/* Compute inverse of lower triangular matrix. */ + + for (j = *n; j >= 1; --j) { + if (nounit) { + i__1 = j + j * a_dim1; + z_div(&z__1, &c_b57, &a[j + j * a_dim1]); + a[i__1].r = z__1.r, a[i__1].i = z__1.i; + i__1 = j + j * a_dim1; + z__1.r = -a[i__1].r, z__1.i = -a[i__1].i; + ajj.r = z__1.r, ajj.i = z__1.i; + } else { + z__1.r = -1., z__1.i = -0.; + ajj.r = z__1.r, ajj.i = z__1.i; + } + if (j < *n) { + +/* Compute elements j+1:n of j-th column. */ + + i__1 = *n - j; + ztrmv_("Lower", "No transpose", diag, &i__1, &a[j + 1 + (j + + 1) * a_dim1], lda, &a[j + 1 + j * a_dim1], &c__1); + i__1 = *n - j; + zscal_(&i__1, &ajj, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + + return 0; + +/* End of ZTRTI2 */ + +} /* ztrti2_ */ + +/* Subroutine */ int ztrtri_(char *uplo, char *diag, integer *n, + doublecomplex *a, integer *lda, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, i__1, i__2, i__3[2], i__4, i__5; + doublecomplex z__1; + char ch__1[2]; + + /* Local variables */ + static integer j, jb, nb, nn; + extern logical lsame_(char *, char *); + static logical upper; + extern /* Subroutine */ int ztrmm_(char *, char *, char *, char *, + integer *, integer *, doublecomplex *, doublecomplex *, integer *, + doublecomplex *, integer *), + ztrsm_(char *, char *, char *, char *, integer *, integer *, + doublecomplex *, doublecomplex *, integer *, doublecomplex *, + integer *), ztrti2_(char *, char * + , integer *, doublecomplex *, integer *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical nounit; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZTRTRI computes the inverse of a complex upper or lower triangular + matrix A. + + This is the Level 3 BLAS version of the algorithm. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': A is upper triangular; + = 'L': A is lower triangular. + + DIAG (input) CHARACTER*1 + = 'N': A is non-unit triangular; + = 'U': A is unit triangular. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the triangular matrix A. If UPLO = 'U', the + leading N-by-N upper triangular part of the array A contains + the upper triangular matrix, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of the array A contains + the lower triangular matrix, and the strictly upper + triangular part of A is not referenced. If DIAG = 'U', the + diagonal elements of A are also not referenced and are + assumed to be 1. + On exit, the (triangular) inverse of the original matrix, in + the same storage format. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, A(i,i) is exactly zero. The triangular + matrix is singular and its inverse can not be computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + nounit = lsame_(diag, "N"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (! nounit && ! lsame_(diag, "U")) { + *info = -2; + } else if (*n < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZTRTRI", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Check for singularity if non-unit. */ + + if (nounit) { + i__1 = *n; + for (*info = 1; *info <= i__1; ++(*info)) { + i__2 = *info + *info * a_dim1; + if (a[i__2].r == 0. && a[i__2].i == 0.) { + return 0; + } +/* L10: */ + } + *info = 0; + } + +/* + Determine the block size for this environment. + + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = uplo; + i__3[1] = 1, a__1[1] = diag; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "ZTRTRI", ch__1, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)2); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code */ + + ztrti2_(uplo, diag, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code */ + + if (upper) { + +/* Compute inverse of upper triangular matrix */ + + i__1 = *n; + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *n - j + 1; + jb = min(i__4,i__5); + +/* Compute rows 1:j-1 of current block column */ + + i__4 = j - 1; + ztrmm_("Left", "Upper", "No transpose", diag, &i__4, &jb, & + c_b57, &a[a_offset], lda, &a[j * a_dim1 + 1], lda); + i__4 = j - 1; + z__1.r = -1., z__1.i = -0.; + ztrsm_("Right", "Upper", "No transpose", diag, &i__4, &jb, & + z__1, &a[j + j * a_dim1], lda, &a[j * a_dim1 + 1], + lda); + +/* Compute inverse of current diagonal block */ + + ztrti2_("Upper", diag, &jb, &a[j + j * a_dim1], lda, info); +/* L20: */ + } + } else { + +/* Compute inverse of lower triangular matrix */ + + nn = (*n - 1) / nb * nb + 1; + i__2 = -nb; + for (j = nn; i__2 < 0 ? j >= 1 : j <= 1; j += i__2) { +/* Computing MIN */ + i__1 = nb, i__4 = *n - j + 1; + jb = min(i__1,i__4); + if (j + jb <= *n) { + +/* Compute rows j+jb:n of current block column */ + + i__1 = *n - j - jb + 1; + ztrmm_("Left", "Lower", "No transpose", diag, &i__1, &jb, + &c_b57, &a[j + jb + (j + jb) * a_dim1], lda, &a[j + + jb + j * a_dim1], lda); + i__1 = *n - j - jb + 1; + z__1.r = -1., z__1.i = -0.; + ztrsm_("Right", "Lower", "No transpose", diag, &i__1, &jb, + &z__1, &a[j + j * a_dim1], lda, &a[j + jb + j * + a_dim1], lda); + } + +/* Compute inverse of current diagonal block */ + + ztrti2_("Lower", diag, &jb, &a[j + j * a_dim1], lda, info); +/* L30: */ + } + } + } + + return 0; + +/* End of ZTRTRI */ + +} /* ztrtri_ */ + +/* Subroutine */ int zung2r_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *), zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNG2R generates an m by n complex matrix Q with orthonormal columns, + which is defined as the first n columns of a product of k elementary + reflectors of order m + + Q = H(1) H(2) . . . H(k) + + as returned by ZGEQRF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. M >= N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. N >= K >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the i-th column must contain the vector which + defines the elementary reflector H(i), for i = 1,2,...,k, as + returned by ZGEQRF in the first k columns of its array + argument A. + On exit, the m by n matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGEQRF. + + WORK (workspace) COMPLEX*16 array, dimension (N) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < 0 || *n > *m) { + *info = -2; + } else if (*k < 0 || *k > *n) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNG2R", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + return 0; + } + +/* Initialise columns k+1:n to columns of the unit matrix */ + + i__1 = *n; + for (j = *k + 1; j <= i__1; ++j) { + i__2 = *m; + for (l = 1; l <= i__2; ++l) { + i__3 = l + j * a_dim1; + a[i__3].r = 0., a[i__3].i = 0.; +/* L10: */ + } + i__2 = j + j * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; +/* L20: */ + } + + for (i__ = *k; i__ >= 1; --i__) { + +/* Apply H(i) to A(i:m,i:n) from the left */ + + if (i__ < *n) { + i__1 = i__ + i__ * a_dim1; + a[i__1].r = 1., a[i__1].i = 0.; + i__1 = *m - i__ + 1; + i__2 = *n - i__; + zlarf_("Left", &i__1, &i__2, &a[i__ + i__ * a_dim1], &c__1, &tau[ + i__], &a[i__ + (i__ + 1) * a_dim1], lda, &work[1]); + } + if (i__ < *m) { + i__1 = *m - i__; + i__2 = i__; + z__1.r = -tau[i__2].r, z__1.i = -tau[i__2].i; + zscal_(&i__1, &z__1, &a[i__ + 1 + i__ * a_dim1], &c__1); + } + i__1 = i__ + i__ * a_dim1; + i__2 = i__; + z__1.r = 1. - tau[i__2].r, z__1.i = 0. - tau[i__2].i; + a[i__1].r = z__1.r, a[i__1].i = z__1.i; + +/* Set A(1:i-1,i) to zero */ + + i__1 = i__ - 1; + for (l = 1; l <= i__1; ++l) { + i__2 = l + i__ * a_dim1; + a[i__2].r = 0., a[i__2].i = 0.; +/* L30: */ + } +/* L40: */ + } + return 0; + +/* End of ZUNG2R */ + +} /* zung2r_ */ + +/* Subroutine */ int zungbr_(char *vect, integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, nb, mn; + extern logical lsame_(char *, char *); + static integer iinfo; + static logical wantq; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer lwkopt; + static logical lquery; + extern /* Subroutine */ int zunglq_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *), zungqr_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNGBR generates one of the complex unitary matrices Q or P**H + determined by ZGEBRD when reducing a complex matrix A to bidiagonal + form: A = Q * B * P**H. Q and P**H are defined as products of + elementary reflectors H(i) or G(i) respectively. + + If VECT = 'Q', A is assumed to have been an M-by-K matrix, and Q + is of order M: + if m >= k, Q = H(1) H(2) . . . H(k) and ZUNGBR returns the first n + columns of Q, where m >= n >= k; + if m < k, Q = H(1) H(2) . . . H(m-1) and ZUNGBR returns Q as an + M-by-M matrix. + + If VECT = 'P', A is assumed to have been a K-by-N matrix, and P**H + is of order N: + if k < n, P**H = G(k) . . . G(2) G(1) and ZUNGBR returns the first m + rows of P**H, where n >= m >= k; + if k >= n, P**H = G(n-1) . . . G(2) G(1) and ZUNGBR returns P**H as + an N-by-N matrix. + + Arguments + ========= + + VECT (input) CHARACTER*1 + Specifies whether the matrix Q or the matrix P**H is + required, as defined in the transformation applied by ZGEBRD: + = 'Q': generate Q; + = 'P': generate P**H. + + M (input) INTEGER + The number of rows of the matrix Q or P**H to be returned. + M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q or P**H to be returned. + N >= 0. + If VECT = 'Q', M >= N >= min(M,K); + if VECT = 'P', N >= M >= min(N,K). + + K (input) INTEGER + If VECT = 'Q', the number of columns in the original M-by-K + matrix reduced by ZGEBRD. + If VECT = 'P', the number of rows in the original K-by-N + matrix reduced by ZGEBRD. + K >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the vectors which define the elementary reflectors, + as returned by ZGEBRD. + On exit, the M-by-N matrix Q or P**H. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= M. + + TAU (input) COMPLEX*16 array, dimension + (min(M,K)) if VECT = 'Q' + (min(N,K)) if VECT = 'P' + TAU(i) must contain the scalar factor of the elementary + reflector H(i) or G(i), which determines Q or P**H, as + returned by ZGEBRD in its array argument TAUQ or TAUP. + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,min(M,N)). + For optimum performance LWORK >= min(M,N)*NB, where NB + is the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + wantq = lsame_(vect, "Q"); + mn = min(*m,*n); + lquery = *lwork == -1; + if (! wantq && ! lsame_(vect, "P")) { + *info = -1; + } else if (*m < 0) { + *info = -2; + } else if (*n < 0 || wantq && (*n > *m || *n < min(*m,*k)) || ! wantq && ( + *m > *n || *m < min(*n,*k))) { + *info = -3; + } else if (*k < 0) { + *info = -4; + } else if (*lda < max(1,*m)) { + *info = -6; + } else if (*lwork < max(1,mn) && ! lquery) { + *info = -9; + } + + if (*info == 0) { + if (wantq) { + nb = ilaenv_(&c__1, "ZUNGQR", " ", m, n, k, &c_n1, (ftnlen)6, ( + ftnlen)1); + } else { + nb = ilaenv_(&c__1, "ZUNGLQ", " ", m, n, k, &c_n1, (ftnlen)6, ( + ftnlen)1); + } + lwkopt = max(1,mn) * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNGBR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + if (wantq) { + +/* + Form Q, determined by a call to ZGEBRD to reduce an m-by-k + matrix +*/ + + if (*m >= *k) { + +/* If m >= k, assume m >= n >= k */ + + zungqr_(m, n, k, &a[a_offset], lda, &tau[1], &work[1], lwork, & + iinfo); + + } else { + +/* + If m < k, assume m = n + + Shift the vectors which define the elementary reflectors one + column to the right, and set the first row and column of Q + to those of the unit matrix +*/ + + for (j = *m; j >= 2; --j) { + i__1 = j * a_dim1 + 1; + a[i__1].r = 0., a[i__1].i = 0.; + i__1 = *m; + for (i__ = j + 1; i__ <= i__1; ++i__) { + i__2 = i__ + j * a_dim1; + i__3 = i__ + (j - 1) * a_dim1; + a[i__2].r = a[i__3].r, a[i__2].i = a[i__3].i; +/* L10: */ + } +/* L20: */ + } + i__1 = a_dim1 + 1; + a[i__1].r = 1., a[i__1].i = 0.; + i__1 = *m; + for (i__ = 2; i__ <= i__1; ++i__) { + i__2 = i__ + a_dim1; + a[i__2].r = 0., a[i__2].i = 0.; +/* L30: */ + } + if (*m > 1) { + +/* Form Q(2:m,2:m) */ + + i__1 = *m - 1; + i__2 = *m - 1; + i__3 = *m - 1; + zungqr_(&i__1, &i__2, &i__3, &a[(a_dim1 << 1) + 2], lda, &tau[ + 1], &work[1], lwork, &iinfo); + } + } + } else { + +/* + Form P', determined by a call to ZGEBRD to reduce a k-by-n + matrix +*/ + + if (*k < *n) { + +/* If k < n, assume k <= m <= n */ + + zunglq_(m, n, k, &a[a_offset], lda, &tau[1], &work[1], lwork, & + iinfo); + + } else { + +/* + If k >= n, assume m = n + + Shift the vectors which define the elementary reflectors one + row downward, and set the first row and column of P' to + those of the unit matrix +*/ + + i__1 = a_dim1 + 1; + a[i__1].r = 1., a[i__1].i = 0.; + i__1 = *n; + for (i__ = 2; i__ <= i__1; ++i__) { + i__2 = i__ + a_dim1; + a[i__2].r = 0., a[i__2].i = 0.; +/* L40: */ + } + i__1 = *n; + for (j = 2; j <= i__1; ++j) { + for (i__ = j - 1; i__ >= 2; --i__) { + i__2 = i__ + j * a_dim1; + i__3 = i__ - 1 + j * a_dim1; + a[i__2].r = a[i__3].r, a[i__2].i = a[i__3].i; +/* L50: */ + } + i__2 = j * a_dim1 + 1; + a[i__2].r = 0., a[i__2].i = 0.; +/* L60: */ + } + if (*n > 1) { + +/* Form P'(2:n,2:n) */ + + i__1 = *n - 1; + i__2 = *n - 1; + i__3 = *n - 1; + zunglq_(&i__1, &i__2, &i__3, &a[(a_dim1 << 1) + 2], lda, &tau[ + 1], &work[1], lwork, &iinfo); + } + } + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZUNGBR */ + +} /* zungbr_ */ + +/* Subroutine */ int zunghr_(integer *n, integer *ilo, integer *ihi, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, nb, nh, iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer lwkopt; + static logical lquery; + extern /* Subroutine */ int zungqr_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNGHR generates a complex unitary matrix Q which is defined as the + product of IHI-ILO elementary reflectors of order N, as returned by + ZGEHRD: + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Arguments + ========= + + N (input) INTEGER + The order of the matrix Q. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + ILO and IHI must have the same values as in the previous call + of ZGEHRD. Q is equal to the unit matrix except in the + submatrix Q(ilo+1:ihi,ilo+1:ihi). + 1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the vectors which define the elementary reflectors, + as returned by ZGEHRD. + On exit, the N-by-N unitary matrix Q. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + TAU (input) COMPLEX*16 array, dimension (N-1) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGEHRD. + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= IHI-ILO. + For optimum performance LWORK >= (IHI-ILO)*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nh = *ihi - *ilo; + lquery = *lwork == -1; + if (*n < 0) { + *info = -1; + } else if (*ilo < 1 || *ilo > max(1,*n)) { + *info = -2; + } else if (*ihi < min(*ilo,*n) || *ihi > *n) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*lwork < max(1,nh) && ! lquery) { + *info = -8; + } + + if (*info == 0) { + nb = ilaenv_(&c__1, "ZUNGQR", " ", &nh, &nh, &nh, &c_n1, (ftnlen)6, ( + ftnlen)1); + lwkopt = max(1,nh) * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNGHR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + +/* + Shift the vectors which define the elementary reflectors one + column to the right, and set the first ilo and the last n-ihi + rows and columns to those of the unit matrix +*/ + + i__1 = *ilo + 1; + for (j = *ihi; j >= i__1; --j) { + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0., a[i__3].i = 0.; +/* L10: */ + } + i__2 = *ihi; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + i__4 = i__ + (j - 1) * a_dim1; + a[i__3].r = a[i__4].r, a[i__3].i = a[i__4].i; +/* L20: */ + } + i__2 = *n; + for (i__ = *ihi + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0., a[i__3].i = 0.; +/* L30: */ + } +/* L40: */ + } + i__1 = *ilo; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0., a[i__3].i = 0.; +/* L50: */ + } + i__2 = j + j * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; +/* L60: */ + } + i__1 = *n; + for (j = *ihi + 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0., a[i__3].i = 0.; +/* L70: */ + } + i__2 = j + j * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; +/* L80: */ + } + + if (nh > 0) { + +/* Generate Q(ilo+1:ihi,ilo+1:ihi) */ + + zungqr_(&nh, &nh, &nh, &a[*ilo + 1 + (*ilo + 1) * a_dim1], lda, &tau[* + ilo], &work[1], lwork, &iinfo); + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZUNGHR */ + +} /* zunghr_ */ + +/* Subroutine */ int zungl2_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + doublecomplex z__1, z__2; + + /* Local variables */ + static integer i__, j, l; + extern /* Subroutine */ int zscal_(integer *, doublecomplex *, + doublecomplex *, integer *), zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *), zlacgv_(integer *, doublecomplex *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNGL2 generates an m-by-n complex matrix Q with orthonormal rows, + which is defined as the first m rows of a product of k elementary + reflectors of order n + + Q = H(k)' . . . H(2)' H(1)' + + as returned by ZGELQF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. N >= M. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. M >= K >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the i-th row must contain the vector which defines + the elementary reflector H(i), for i = 1,2,...,k, as returned + by ZGELQF in the first k rows of its array argument A. + On exit, the m by n matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGELQF. + + WORK (workspace) COMPLEX*16 array, dimension (M) + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + if (*m < 0) { + *info = -1; + } else if (*n < *m) { + *info = -2; + } else if (*k < 0 || *k > *m) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNGL2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m <= 0) { + return 0; + } + + if (*k < *m) { + +/* Initialise rows k+1:m to rows of the unit matrix */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (l = *k + 1; l <= i__2; ++l) { + i__3 = l + j * a_dim1; + a[i__3].r = 0., a[i__3].i = 0.; +/* L10: */ + } + if (j > *k && j <= *m) { + i__2 = j + j * a_dim1; + a[i__2].r = 1., a[i__2].i = 0.; + } +/* L20: */ + } + } + + for (i__ = *k; i__ >= 1; --i__) { + +/* Apply H(i)' to A(i:m,i:n) from the right */ + + if (i__ < *n) { + i__1 = *n - i__; + zlacgv_(&i__1, &a[i__ + (i__ + 1) * a_dim1], lda); + if (i__ < *m) { + i__1 = i__ + i__ * a_dim1; + a[i__1].r = 1., a[i__1].i = 0.; + i__1 = *m - i__; + i__2 = *n - i__ + 1; + d_cnjg(&z__1, &tau[i__]); + zlarf_("Right", &i__1, &i__2, &a[i__ + i__ * a_dim1], lda, & + z__1, &a[i__ + 1 + i__ * a_dim1], lda, &work[1]); + } + i__1 = *n - i__; + i__2 = i__; + z__1.r = -tau[i__2].r, z__1.i = -tau[i__2].i; + zscal_(&i__1, &z__1, &a[i__ + (i__ + 1) * a_dim1], lda); + i__1 = *n - i__; + zlacgv_(&i__1, &a[i__ + (i__ + 1) * a_dim1], lda); + } + i__1 = i__ + i__ * a_dim1; + d_cnjg(&z__2, &tau[i__]); + z__1.r = 1. - z__2.r, z__1.i = 0. - z__2.i; + a[i__1].r = z__1.r, a[i__1].i = z__1.i; + +/* Set A(i,1:i-1) to zero */ + + i__1 = i__ - 1; + for (l = 1; l <= i__1; ++l) { + i__2 = i__ + l * a_dim1; + a[i__2].r = 0., a[i__2].i = 0.; +/* L30: */ + } +/* L40: */ + } + return 0; + +/* End of ZUNGL2 */ + +} /* zungl2_ */ + +/* Subroutine */ int zunglq_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int zungl2_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlarfb_(char *, char *, char *, char *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static integer ldwork; + extern /* Subroutine */ int zlarft_(char *, char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static logical lquery; + static integer lwkopt; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNGLQ generates an M-by-N complex matrix Q with orthonormal rows, + which is defined as the first M rows of a product of K elementary + reflectors of order N + + Q = H(k)' . . . H(2)' H(1)' + + as returned by ZGELQF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. N >= M. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. M >= K >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the i-th row must contain the vector which defines + the elementary reflector H(i), for i = 1,2,...,k, as returned + by ZGELQF in the first k rows of its array argument A. + On exit, the M-by-N matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGELQF. + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,M). + For optimum performance LWORK >= M*NB, where NB is + the optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit; + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "ZUNGLQ", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1); + lwkopt = max(1,*m) * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < *m) { + *info = -2; + } else if (*k < 0 || *k > *m) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*lwork < max(1,*m) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNGLQ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m <= 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *m; + if (nb > 1 && nb < *k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "ZUNGLQ", " ", m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *m; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "ZUNGLQ", " ", m, n, k, &c_n1, + (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < *k && nx < *k) { + +/* + Use blocked code after the last block. + The first kk rows are handled by the block method. +*/ + + ki = (*k - nx - 1) / nb * nb; +/* Computing MIN */ + i__1 = *k, i__2 = ki + nb; + kk = min(i__1,i__2); + +/* Set A(kk+1:m,1:kk) to zero. */ + + i__1 = kk; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = kk + 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0., a[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + kk = 0; + } + +/* Use unblocked code for the last or only block. */ + + if (kk < *m) { + i__1 = *m - kk; + i__2 = *n - kk; + i__3 = *k - kk; + zungl2_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, & + tau[kk + 1], &work[1], &iinfo); + } + + if (kk > 0) { + +/* Use blocked code */ + + i__1 = -nb; + for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) { +/* Computing MIN */ + i__2 = nb, i__3 = *k - i__ + 1; + ib = min(i__2,i__3); + if (i__ + ib <= *m) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__2 = *n - i__ + 1; + zlarft_("Forward", "Rowwise", &i__2, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H' to A(i+ib:m,i:n) from the right */ + + i__2 = *m - i__ - ib + 1; + i__3 = *n - i__ + 1; + zlarfb_("Right", "Conjugate transpose", "Forward", "Rowwise", + &i__2, &i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[ + 1], &ldwork, &a[i__ + ib + i__ * a_dim1], lda, &work[ + ib + 1], &ldwork); + } + +/* Apply H' to columns i:n of current block */ + + i__2 = *n - i__ + 1; + zungl2_(&ib, &i__2, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], & + work[1], &iinfo); + +/* Set columns 1:i-1 of current block to zero */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = i__ + ib - 1; + for (l = i__; l <= i__3; ++l) { + i__4 = l + j * a_dim1; + a[i__4].r = 0., a[i__4].i = 0.; +/* L30: */ + } +/* L40: */ + } +/* L50: */ + } + } + + work[1].r = (doublereal) iws, work[1].i = 0.; + return 0; + +/* End of ZUNGLQ */ + +} /* zunglq_ */ + +/* Subroutine */ int zungqr_(integer *m, integer *n, integer *k, + doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer i__, j, l, ib, nb, ki, kk, nx, iws, nbmin, iinfo; + extern /* Subroutine */ int zung2r_(integer *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlarfb_(char *, char *, char *, char *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static integer ldwork; + extern /* Subroutine */ int zlarft_(char *, char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNGQR generates an M-by-N complex matrix Q with orthonormal columns, + which is defined as the first N columns of a product of K elementary + reflectors of order M + + Q = H(1) H(2) . . . H(k) + + as returned by ZGEQRF. + + Arguments + ========= + + M (input) INTEGER + The number of rows of the matrix Q. M >= 0. + + N (input) INTEGER + The number of columns of the matrix Q. M >= N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines the + matrix Q. N >= K >= 0. + + A (input/output) COMPLEX*16 array, dimension (LDA,N) + On entry, the i-th column must contain the vector which + defines the elementary reflector H(i), for i = 1,2,...,k, as + returned by ZGEQRF in the first k columns of its array + argument A. + On exit, the M-by-N matrix Q. + + LDA (input) INTEGER + The first dimension of the array A. LDA >= max(1,M). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGEQRF. + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. LWORK >= max(1,N). + For optimum performance LWORK >= N*NB, where NB is the + optimal blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument has an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + --work; + + /* Function Body */ + *info = 0; + nb = ilaenv_(&c__1, "ZUNGQR", " ", m, n, k, &c_n1, (ftnlen)6, (ftnlen)1); + lwkopt = max(1,*n) * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + lquery = *lwork == -1; + if (*m < 0) { + *info = -1; + } else if (*n < 0 || *n > *m) { + *info = -2; + } else if (*k < 0 || *k > *n) { + *info = -3; + } else if (*lda < max(1,*m)) { + *info = -5; + } else if (*lwork < max(1,*n) && ! lquery) { + *info = -8; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNGQR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n <= 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + nbmin = 2; + nx = 0; + iws = *n; + if (nb > 1 && nb < *k) { + +/* + Determine when to cross over from blocked to unblocked code. + + Computing MAX +*/ + i__1 = 0, i__2 = ilaenv_(&c__3, "ZUNGQR", " ", m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)1); + nx = max(i__1,i__2); + if (nx < *k) { + +/* Determine if workspace is large enough for blocked code. */ + + ldwork = *n; + iws = ldwork * nb; + if (*lwork < iws) { + +/* + Not enough workspace to use optimal NB: reduce NB and + determine the minimum value of NB. +*/ + + nb = *lwork / ldwork; +/* Computing MAX */ + i__1 = 2, i__2 = ilaenv_(&c__2, "ZUNGQR", " ", m, n, k, &c_n1, + (ftnlen)6, (ftnlen)1); + nbmin = max(i__1,i__2); + } + } + } + + if (nb >= nbmin && nb < *k && nx < *k) { + +/* + Use blocked code after the last block. + The first kk columns are handled by the block method. +*/ + + ki = (*k - nx - 1) / nb * nb; +/* Computing MIN */ + i__1 = *k, i__2 = ki + nb; + kk = min(i__1,i__2); + +/* Set A(1:kk,kk+1:n) to zero. */ + + i__1 = *n; + for (j = kk + 1; j <= i__1; ++j) { + i__2 = kk; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * a_dim1; + a[i__3].r = 0., a[i__3].i = 0.; +/* L10: */ + } +/* L20: */ + } + } else { + kk = 0; + } + +/* Use unblocked code for the last or only block. */ + + if (kk < *n) { + i__1 = *m - kk; + i__2 = *n - kk; + i__3 = *k - kk; + zung2r_(&i__1, &i__2, &i__3, &a[kk + 1 + (kk + 1) * a_dim1], lda, & + tau[kk + 1], &work[1], &iinfo); + } + + if (kk > 0) { + +/* Use blocked code */ + + i__1 = -nb; + for (i__ = ki + 1; i__1 < 0 ? i__ >= 1 : i__ <= 1; i__ += i__1) { +/* Computing MIN */ + i__2 = nb, i__3 = *k - i__ + 1; + ib = min(i__2,i__3); + if (i__ + ib <= *n) { + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__2 = *m - i__ + 1; + zlarft_("Forward", "Columnwise", &i__2, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], &work[1], &ldwork); + +/* Apply H to A(i:m,i+ib:n) from the left */ + + i__2 = *m - i__ + 1; + i__3 = *n - i__ - ib + 1; + zlarfb_("Left", "No transpose", "Forward", "Columnwise", & + i__2, &i__3, &ib, &a[i__ + i__ * a_dim1], lda, &work[ + 1], &ldwork, &a[i__ + (i__ + ib) * a_dim1], lda, & + work[ib + 1], &ldwork); + } + +/* Apply H to rows i:m of current block */ + + i__2 = *m - i__ + 1; + zung2r_(&i__2, &ib, &ib, &a[i__ + i__ * a_dim1], lda, &tau[i__], & + work[1], &iinfo); + +/* Set rows 1:i-1 of current block to zero */ + + i__2 = i__ + ib - 1; + for (j = i__; j <= i__2; ++j) { + i__3 = i__ - 1; + for (l = 1; l <= i__3; ++l) { + i__4 = l + j * a_dim1; + a[i__4].r = 0., a[i__4].i = 0.; +/* L30: */ + } +/* L40: */ + } +/* L50: */ + } + } + + work[1].r = (doublereal) iws, work[1].i = 0.; + return 0; + +/* End of ZUNGQR */ + +} /* zungqr_ */ + +/* Subroutine */ int zunm2l_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__, i1, i2, i3, mi, ni, nq; + static doublecomplex aii; + static logical left; + static doublecomplex taui; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNM2L overwrites the general complex m-by-n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'C', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'C', + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by ZGEQLF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'C': apply Q' (Conjugate transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + ZGEQLF in the last k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGEQLF. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the m-by-n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX*16 array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNM2L", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + } else { + mi = *m; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) or H(i)' is applied to C(1:m-k+i,1:n) */ + + mi = *m - *k + i__; + } else { + +/* H(i) or H(i)' is applied to C(1:m,1:n-k+i) */ + + ni = *n - *k + i__; + } + +/* Apply H(i) or H(i)' */ + + if (notran) { + i__3 = i__; + taui.r = tau[i__3].r, taui.i = tau[i__3].i; + } else { + d_cnjg(&z__1, &tau[i__]); + taui.r = z__1.r, taui.i = z__1.i; + } + i__3 = nq - *k + i__ + i__ * a_dim1; + aii.r = a[i__3].r, aii.i = a[i__3].i; + i__3 = nq - *k + i__ + i__ * a_dim1; + a[i__3].r = 1., a[i__3].i = 0.; + zlarf_(side, &mi, &ni, &a[i__ * a_dim1 + 1], &c__1, &taui, &c__[ + c_offset], ldc, &work[1]); + i__3 = nq - *k + i__ + i__ * a_dim1; + a[i__3].r = aii.r, a[i__3].i = aii.i; +/* L10: */ + } + return 0; + +/* End of ZUNM2L */ + +} /* zunm2l_ */ + +/* Subroutine */ int zunm2r_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__, i1, i2, i3, ic, jc, mi, ni, nq; + static doublecomplex aii; + static logical left; + static doublecomplex taui; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNM2R overwrites the general complex m-by-n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'C', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'C', + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(1) H(2) . . . H(k) + + as returned by ZGEQRF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'C': apply Q' (Conjugate transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + ZGEQRF in the first k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGEQRF. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the m-by-n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX*16 array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNM2R", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && ! notran || ! left && notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) or H(i)' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H(i) or H(i)' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H(i) or H(i)' */ + + if (notran) { + i__3 = i__; + taui.r = tau[i__3].r, taui.i = tau[i__3].i; + } else { + d_cnjg(&z__1, &tau[i__]); + taui.r = z__1.r, taui.i = z__1.i; + } + i__3 = i__ + i__ * a_dim1; + aii.r = a[i__3].r, aii.i = a[i__3].i; + i__3 = i__ + i__ * a_dim1; + a[i__3].r = 1., a[i__3].i = 0.; + zlarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], &c__1, &taui, &c__[ic + + jc * c_dim1], ldc, &work[1]); + i__3 = i__ + i__ * a_dim1; + a[i__3].r = aii.r, a[i__3].i = aii.i; +/* L10: */ + } + return 0; + +/* End of ZUNM2R */ + +} /* zunm2r_ */ + +/* Subroutine */ int zunmbr_(char *vect, char *side, char *trans, integer *m, + integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex + *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer * + lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2]; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static logical notran, applyq; + static char transt[1]; + static integer lwkopt; + static logical lquery; + extern /* Subroutine */ int zunmlq_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *), zunmqr_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + If VECT = 'Q', ZUNMBR overwrites the general complex M-by-N matrix C + with + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + If VECT = 'P', ZUNMBR overwrites the general complex M-by-N matrix C + with + SIDE = 'L' SIDE = 'R' + TRANS = 'N': P * C C * P + TRANS = 'C': P**H * C C * P**H + + Here Q and P**H are the unitary matrices determined by ZGEBRD when + reducing a complex matrix A to bidiagonal form: A = Q * B * P**H. Q + and P**H are defined as products of elementary reflectors H(i) and + G(i) respectively. + + Let nq = m if SIDE = 'L' and nq = n if SIDE = 'R'. Thus nq is the + order of the unitary matrix Q or P**H that is applied. + + If VECT = 'Q', A is assumed to have been an NQ-by-K matrix: + if nq >= k, Q = H(1) H(2) . . . H(k); + if nq < k, Q = H(1) H(2) . . . H(nq-1). + + If VECT = 'P', A is assumed to have been a K-by-NQ matrix: + if k < nq, P = G(1) G(2) . . . G(k); + if k >= nq, P = G(1) G(2) . . . G(nq-1). + + Arguments + ========= + + VECT (input) CHARACTER*1 + = 'Q': apply Q or Q**H; + = 'P': apply P or P**H. + + SIDE (input) CHARACTER*1 + = 'L': apply Q, Q**H, P or P**H from the Left; + = 'R': apply Q, Q**H, P or P**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q or P; + = 'C': Conjugate transpose, apply Q**H or P**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + If VECT = 'Q', the number of columns in the original + matrix reduced by ZGEBRD. + If VECT = 'P', the number of rows in the original + matrix reduced by ZGEBRD. + K >= 0. + + A (input) COMPLEX*16 array, dimension + (LDA,min(nq,K)) if VECT = 'Q' + (LDA,nq) if VECT = 'P' + The vectors which define the elementary reflectors H(i) and + G(i), whose products determine the matrices Q and P, as + returned by ZGEBRD. + + LDA (input) INTEGER + The leading dimension of the array A. + If VECT = 'Q', LDA >= max(1,nq); + if VECT = 'P', LDA >= max(1,min(nq,K)). + + TAU (input) COMPLEX*16 array, dimension (min(nq,K)) + TAU(i) must contain the scalar factor of the elementary + reflector H(i) or G(i) which determines Q or P, as returned + by ZGEBRD in the array argument TAUQ or TAUP. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q + or P*C or P**H*C or C*P or C*P**H. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M); + if N = 0 or M = 0, LWORK >= 1. + For optimum performance LWORK >= max(1,N*NB) if SIDE = 'L', + and LWORK >= max(1,M*NB) if SIDE = 'R', where NB is the + optimal blocksize. (NB = 0 if M = 0 or N = 0.) + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + applyq = lsame_(vect, "Q"); + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q or P and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (*m == 0 || *n == 0) { + nw = 0; + } + if (! applyq && ! lsame_(vect, "P")) { + *info = -1; + } else if (! left && ! lsame_(side, "R")) { + *info = -2; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -3; + } else if (*m < 0) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*k < 0) { + *info = -6; + } else /* if(complicated condition) */ { +/* Computing MAX */ + i__1 = 1, i__2 = min(nq,*k); + if (applyq && *lda < max(1,nq) || ! applyq && *lda < max(i__1,i__2)) { + *info = -8; + } else if (*ldc < max(1,*m)) { + *info = -11; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -13; + } + } + + if (*info == 0) { + if (nw > 0) { + if (applyq) { + if (left) { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *m - 1; + i__2 = *m - 1; + nb = ilaenv_(&c__1, "ZUNMQR", ch__1, &i__1, n, &i__2, & + c_n1, (ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *n - 1; + i__2 = *n - 1; + nb = ilaenv_(&c__1, "ZUNMQR", ch__1, m, &i__1, &i__2, & + c_n1, (ftnlen)6, (ftnlen)2); + } + } else { + if (left) { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *m - 1; + i__2 = *m - 1; + nb = ilaenv_(&c__1, "ZUNMLQ", ch__1, &i__1, n, &i__2, & + c_n1, (ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = *n - 1; + i__2 = *n - 1; + nb = ilaenv_(&c__1, "ZUNMLQ", ch__1, m, &i__1, &i__2, & + c_n1, (ftnlen)6, (ftnlen)2); + } + } +/* Computing MAX */ + i__1 = 1, i__2 = nw * nb; + lwkopt = max(i__1,i__2); + } else { + lwkopt = 1; + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNMBR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + + if (applyq) { + +/* Apply Q */ + + if (nq >= *k) { + +/* Q was determined by a call to ZGEBRD with nq >= k */ + + zunmqr_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], lwork, &iinfo); + } else if (nq > 1) { + +/* Q was determined by a call to ZGEBRD with nq < k */ + + if (left) { + mi = *m - 1; + ni = *n; + i1 = 2; + i2 = 1; + } else { + mi = *m; + ni = *n - 1; + i1 = 1; + i2 = 2; + } + i__1 = nq - 1; + zunmqr_(side, trans, &mi, &ni, &i__1, &a[a_dim1 + 2], lda, &tau[1] + , &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + } + } else { + +/* Apply P */ + + if (notran) { + *(unsigned char *)transt = 'C'; + } else { + *(unsigned char *)transt = 'N'; + } + if (nq > *k) { + +/* P was determined by a call to ZGEBRD with nq > k */ + + zunmlq_(side, transt, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], lwork, &iinfo); + } else if (nq > 1) { + +/* P was determined by a call to ZGEBRD with nq <= k */ + + if (left) { + mi = *m - 1; + ni = *n; + i1 = 2; + i2 = 1; + } else { + mi = *m; + ni = *n - 1; + i1 = 1; + i2 = 2; + } + i__1 = nq - 1; + zunmlq_(side, transt, &mi, &ni, &i__1, &a[(a_dim1 << 1) + 1], lda, + &tau[1], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, & + iinfo); + } + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZUNMBR */ + +} /* zunmbr_ */ + +/* Subroutine */ int zunmhr_(char *side, char *trans, integer *m, integer *n, + integer *ilo, integer *ihi, doublecomplex *a, integer *lda, + doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex * + work, integer *lwork, integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, nh, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer lwkopt; + static logical lquery; + extern /* Subroutine */ int zunmqr_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNMHR overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix of order nq, with nq = m if + SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of + IHI-ILO elementary reflectors, as returned by ZGEHRD: + + Q = H(ilo) H(ilo+1) . . . H(ihi-1). + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'C': apply Q**H (Conjugate transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + ILO (input) INTEGER + IHI (input) INTEGER + ILO and IHI must have the same values as in the previous call + of ZGEHRD. Q is equal to the unit matrix except in the + submatrix Q(ilo+1:ihi,ilo+1:ihi). + If SIDE = 'L', then 1 <= ILO <= IHI <= M, if M > 0, and + ILO = 1 and IHI = 0, if M = 0; + if SIDE = 'R', then 1 <= ILO <= IHI <= N, if N > 0, and + ILO = 1 and IHI = 0, if N = 0. + + A (input) COMPLEX*16 array, dimension + (LDA,M) if SIDE = 'L' + (LDA,N) if SIDE = 'R' + The vectors which define the elementary reflectors, as + returned by ZGEHRD. + + LDA (input) INTEGER + The leading dimension of the array A. + LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. + + TAU (input) COMPLEX*16 array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGEHRD. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + nh = *ihi - *ilo; + left = lsame_(side, "L"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*ilo < 1 || *ilo > max(1,nq)) { + *info = -5; + } else if (*ihi < min(*ilo,nq) || *ihi > nq) { + *info = -6; + } else if (*lda < max(1,nq)) { + *info = -8; + } else if (*ldc < max(1,*m)) { + *info = -11; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -13; + } + + if (*info == 0) { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "ZUNMQR", ch__1, &nh, n, &nh, &c_n1, (ftnlen) + 6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + nb = ilaenv_(&c__1, "ZUNMQR", ch__1, m, &nh, &nh, &c_n1, (ftnlen) + 6, (ftnlen)2); + } + lwkopt = max(1,nw) * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + } + + if (*info != 0) { + i__2 = -(*info); + xerbla_("ZUNMHR", &i__2); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || nh == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + if (left) { + mi = nh; + ni = *n; + i1 = *ilo + 1; + i2 = 1; + } else { + mi = *m; + ni = nh; + i1 = 1; + i2 = *ilo + 1; + } + + zunmqr_(side, trans, &mi, &ni, &nh, &a[*ilo + 1 + *ilo * a_dim1], lda, & + tau[*ilo], &c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZUNMHR */ + +} /* zunmhr_ */ + +/* Subroutine */ int zunml2_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + doublecomplex z__1; + + /* Local variables */ + static integer i__, i1, i2, i3, ic, jc, mi, ni, nq; + static doublecomplex aii; + static logical left; + static doublecomplex taui; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int zlarf_(char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *, doublecomplex *), xerbla_(char *, integer *), zlacgv_(integer *, doublecomplex *, integer *); + static logical notran; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNML2 overwrites the general complex m-by-n matrix C with + + Q * C if SIDE = 'L' and TRANS = 'N', or + + Q'* C if SIDE = 'L' and TRANS = 'C', or + + C * Q if SIDE = 'R' and TRANS = 'N', or + + C * Q' if SIDE = 'R' and TRANS = 'C', + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(k)' . . . H(2)' H(1)' + + as returned by ZGELQF. Q is of order m if SIDE = 'L' and of order n + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q' from the Left + = 'R': apply Q or Q' from the Right + + TRANS (input) CHARACTER*1 + = 'N': apply Q (No transpose) + = 'C': apply Q' (Conjugate transpose) + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX*16 array, dimension + (LDA,M) if SIDE = 'L', + (LDA,N) if SIDE = 'R' + The i-th row must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + ZGELQF in the first k rows of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,K). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGELQF. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the m-by-n matrix C. + On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace) COMPLEX*16 array, dimension + (N) if SIDE = 'L', + (M) if SIDE = 'R' + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + +/* NQ is the order of Q */ + + if (left) { + nq = *m; + } else { + nq = *n; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,*k)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNML2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + return 0; + } + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = 1; + } else { + i1 = *k; + i2 = 1; + i3 = -1; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + if (left) { + +/* H(i) or H(i)' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H(i) or H(i)' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H(i) or H(i)' */ + + if (notran) { + d_cnjg(&z__1, &tau[i__]); + taui.r = z__1.r, taui.i = z__1.i; + } else { + i__3 = i__; + taui.r = tau[i__3].r, taui.i = tau[i__3].i; + } + if (i__ < nq) { + i__3 = nq - i__; + zlacgv_(&i__3, &a[i__ + (i__ + 1) * a_dim1], lda); + } + i__3 = i__ + i__ * a_dim1; + aii.r = a[i__3].r, aii.i = a[i__3].i; + i__3 = i__ + i__ * a_dim1; + a[i__3].r = 1., a[i__3].i = 0.; + zlarf_(side, &mi, &ni, &a[i__ + i__ * a_dim1], lda, &taui, &c__[ic + + jc * c_dim1], ldc, &work[1]); + i__3 = i__ + i__ * a_dim1; + a[i__3].r = aii.r, a[i__3].i = aii.i; + if (i__ < nq) { + i__3 = nq - i__; + zlacgv_(&i__3, &a[i__ + (i__ + 1) * a_dim1], lda); + } +/* L10: */ + } + return 0; + +/* End of ZUNML2 */ + +} /* zunml2_ */ + +/* Subroutine */ int zunmlq_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static doublecomplex t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int zunml2_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlarfb_(char *, char *, char *, char *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static logical notran; + static integer ldwork; + extern /* Subroutine */ int zlarft_(char *, char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static char transt[1]; + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNMLQ overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(k)' . . . H(2)' H(1)' + + as returned by ZGELQF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'C': Conjugate transpose, apply Q**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX*16 array, dimension + (LDA,M) if SIDE = 'L', + (LDA,N) if SIDE = 'R' + The i-th row must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + ZGELQF in the first k rows of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,K). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGELQF. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,*k)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + +/* + Determine the block size. NB may be at most NBMAX, where NBMAX + is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "ZUNMLQ", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = max(1,nw) * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNMLQ", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "ZUNMLQ", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + zunml2_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + if (notran) { + *(unsigned char *)transt = 'C'; + } else { + *(unsigned char *)transt = 'N'; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__4 = nq - i__ + 1; + zlarft_("Forward", "Rowwise", &i__4, &ib, &a[i__ + i__ * a_dim1], + lda, &tau[i__], t, &c__65); + if (left) { + +/* H or H' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H or H' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H or H' */ + + zlarfb_(side, transt, "Forward", "Rowwise", &mi, &ni, &ib, &a[i__ + + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * c_dim1], + ldc, &work[1], &ldwork); +/* L10: */ + } + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZUNMLQ */ + +} /* zunmlq_ */ + +/* Subroutine */ int zunmql_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static doublecomplex t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int zunm2l_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlarfb_(char *, char *, char *, char *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static logical notran; + static integer ldwork; + extern /* Subroutine */ int zlarft_(char *, char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNMQL overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(k) . . . H(2) H(1) + + as returned by ZGEQLF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'C': Transpose, apply Q**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + ZGEQLF in the last k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGEQLF. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = max(1,*n); + } else { + nq = *n; + nw = max(1,*m); + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } + + if (*info == 0) { + if (*m == 0 || *n == 0) { + lwkopt = 1; + } else { + +/* + Determine the block size. NB may be at most NBMAX, where + NBMAX is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "ZUNMQL", ch__1, m, n, k, &c_n1, + (ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = nw * nb; + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + + if (*lwork < nw && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNMQL", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0) { + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "ZUNMQL", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + zunm2l_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && notran || ! left && ! notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + } else { + mi = *m; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i+ib-1) . . . H(i+1) H(i) +*/ + + i__4 = nq - *k + i__ + ib - 1; + zlarft_("Backward", "Columnwise", &i__4, &ib, &a[i__ * a_dim1 + 1] + , lda, &tau[i__], t, &c__65); + if (left) { + +/* H or H' is applied to C(1:m-k+i+ib-1,1:n) */ + + mi = *m - *k + i__ + ib - 1; + } else { + +/* H or H' is applied to C(1:m,1:n-k+i+ib-1) */ + + ni = *n - *k + i__ + ib - 1; + } + +/* Apply H or H' */ + + zlarfb_(side, trans, "Backward", "Columnwise", &mi, &ni, &ib, &a[ + i__ * a_dim1 + 1], lda, t, &c__65, &c__[c_offset], ldc, & + work[1], &ldwork); +/* L10: */ + } + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZUNMQL */ + +} /* zunmql_ */ + +/* Subroutine */ int zunmqr_(char *side, char *trans, integer *m, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3[2], i__4, + i__5; + char ch__1[2]; + + /* Local variables */ + static integer i__; + static doublecomplex t[4160] /* was [65][64] */; + static integer i1, i2, i3, ib, ic, jc, nb, mi, ni, nq, nw, iws; + static logical left; + extern logical lsame_(char *, char *); + static integer nbmin, iinfo; + extern /* Subroutine */ int zunm2r_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + extern /* Subroutine */ int zlarfb_(char *, char *, char *, char *, + integer *, integer *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *, integer *, + doublecomplex *, integer *); + static logical notran; + static integer ldwork; + extern /* Subroutine */ int zlarft_(char *, char *, integer *, integer *, + doublecomplex *, integer *, doublecomplex *, doublecomplex *, + integer *); + static integer lwkopt; + static logical lquery; + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNMQR overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix defined as the product of k + elementary reflectors + + Q = H(1) H(2) . . . H(k) + + as returned by ZGEQRF. Q is of order M if SIDE = 'L' and of order N + if SIDE = 'R'. + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'C': Conjugate transpose, apply Q**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + K (input) INTEGER + The number of elementary reflectors whose product defines + the matrix Q. + If SIDE = 'L', M >= K >= 0; + if SIDE = 'R', N >= K >= 0. + + A (input) COMPLEX*16 array, dimension (LDA,K) + The i-th column must contain the vector which defines the + elementary reflector H(i), for i = 1,2,...,k, as returned by + ZGEQRF in the first k columns of its array argument A. + A is modified by the routine but restored on exit. + + LDA (input) INTEGER + The leading dimension of the array A. + If SIDE = 'L', LDA >= max(1,M); + if SIDE = 'R', LDA >= max(1,N). + + TAU (input) COMPLEX*16 array, dimension (K) + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZGEQRF. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >= M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + notran = lsame_(trans, "N"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! notran && ! lsame_(trans, "C")) { + *info = -2; + } else if (*m < 0) { + *info = -3; + } else if (*n < 0) { + *info = -4; + } else if (*k < 0 || *k > nq) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + +/* + Determine the block size. NB may be at most NBMAX, where NBMAX + is used to define the local array T. + + Computing MIN + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 64, i__2 = ilaenv_(&c__1, "ZUNMQR", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nb = min(i__1,i__2); + lwkopt = max(1,nw) * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("ZUNMQR", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || *k == 0) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + nbmin = 2; + ldwork = nw; + if (nb > 1 && nb < *k) { + iws = nw * nb; + if (*lwork < iws) { + nb = *lwork / ldwork; +/* + Computing MAX + Writing concatenation +*/ + i__3[0] = 1, a__1[0] = side; + i__3[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__3, &c__2, (ftnlen)2); + i__1 = 2, i__2 = ilaenv_(&c__2, "ZUNMQR", ch__1, m, n, k, &c_n1, ( + ftnlen)6, (ftnlen)2); + nbmin = max(i__1,i__2); + } + } else { + iws = nw; + } + + if (nb < nbmin || nb >= *k) { + +/* Use unblocked code */ + + zunm2r_(side, trans, m, n, k, &a[a_offset], lda, &tau[1], &c__[ + c_offset], ldc, &work[1], &iinfo); + } else { + +/* Use blocked code */ + + if (left && ! notran || ! left && notran) { + i1 = 1; + i2 = *k; + i3 = nb; + } else { + i1 = (*k - 1) / nb * nb + 1; + i2 = 1; + i3 = -nb; + } + + if (left) { + ni = *n; + jc = 1; + } else { + mi = *m; + ic = 1; + } + + i__1 = i2; + i__2 = i3; + for (i__ = i1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { +/* Computing MIN */ + i__4 = nb, i__5 = *k - i__ + 1; + ib = min(i__4,i__5); + +/* + Form the triangular factor of the block reflector + H = H(i) H(i+1) . . . H(i+ib-1) +*/ + + i__4 = nq - i__ + 1; + zlarft_("Forward", "Columnwise", &i__4, &ib, &a[i__ + i__ * + a_dim1], lda, &tau[i__], t, &c__65) + ; + if (left) { + +/* H or H' is applied to C(i:m,1:n) */ + + mi = *m - i__ + 1; + ic = i__; + } else { + +/* H or H' is applied to C(1:m,i:n) */ + + ni = *n - i__ + 1; + jc = i__; + } + +/* Apply H or H' */ + + zlarfb_(side, trans, "Forward", "Columnwise", &mi, &ni, &ib, &a[ + i__ + i__ * a_dim1], lda, t, &c__65, &c__[ic + jc * + c_dim1], ldc, &work[1], &ldwork); +/* L10: */ + } + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZUNMQR */ + +} /* zunmqr_ */ + +/* Subroutine */ int zunmtr_(char *side, char *uplo, char *trans, integer *m, + integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, + doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, + integer *info) +{ + /* System generated locals */ + address a__1[2]; + integer a_dim1, a_offset, c_dim1, c_offset, i__1[2], i__2, i__3; + char ch__1[2]; + + /* Local variables */ + static integer i1, i2, nb, mi, ni, nq, nw; + static logical left; + extern logical lsame_(char *, char *); + static integer iinfo; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + static integer lwkopt; + static logical lquery; + extern /* Subroutine */ int zunmql_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *), zunmqr_(char *, char *, integer *, integer *, + integer *, doublecomplex *, integer *, doublecomplex *, + doublecomplex *, integer *, doublecomplex *, integer *, integer *); + + +/* + -- LAPACK routine (version 3.2) -- + -- LAPACK is a software package provided by Univ. of Tennessee, -- + -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- + November 2006 + + + Purpose + ======= + + ZUNMTR overwrites the general complex M-by-N matrix C with + + SIDE = 'L' SIDE = 'R' + TRANS = 'N': Q * C C * Q + TRANS = 'C': Q**H * C C * Q**H + + where Q is a complex unitary matrix of order nq, with nq = m if + SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of + nq-1 elementary reflectors, as returned by ZHETRD: + + if UPLO = 'U', Q = H(nq-1) . . . H(2) H(1); + + if UPLO = 'L', Q = H(1) H(2) . . . H(nq-1). + + Arguments + ========= + + SIDE (input) CHARACTER*1 + = 'L': apply Q or Q**H from the Left; + = 'R': apply Q or Q**H from the Right. + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A contains elementary reflectors + from ZHETRD; + = 'L': Lower triangle of A contains elementary reflectors + from ZHETRD. + + TRANS (input) CHARACTER*1 + = 'N': No transpose, apply Q; + = 'C': Conjugate transpose, apply Q**H. + + M (input) INTEGER + The number of rows of the matrix C. M >= 0. + + N (input) INTEGER + The number of columns of the matrix C. N >= 0. + + A (input) COMPLEX*16 array, dimension + (LDA,M) if SIDE = 'L' + (LDA,N) if SIDE = 'R' + The vectors which define the elementary reflectors, as + returned by ZHETRD. + + LDA (input) INTEGER + The leading dimension of the array A. + LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. + + TAU (input) COMPLEX*16 array, dimension + (M-1) if SIDE = 'L' + (N-1) if SIDE = 'R' + TAU(i) must contain the scalar factor of the elementary + reflector H(i), as returned by ZHETRD. + + C (input/output) COMPLEX*16 array, dimension (LDC,N) + On entry, the M-by-N matrix C. + On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q. + + LDC (input) INTEGER + The leading dimension of the array C. LDC >= max(1,M). + + WORK (workspace/output) COMPLEX*16 array, dimension (MAX(1,LWORK)) + On exit, if INFO = 0, WORK(1) returns the optimal LWORK. + + LWORK (input) INTEGER + The dimension of the array WORK. + If SIDE = 'L', LWORK >= max(1,N); + if SIDE = 'R', LWORK >= max(1,M). + For optimum performance LWORK >= N*NB if SIDE = 'L', and + LWORK >=M*NB if SIDE = 'R', where NB is the optimal + blocksize. + + If LWORK = -1, then a workspace query is assumed; the routine + only calculates the optimal size of the WORK array, returns + this value as the first entry of the WORK array, and no error + message related to LWORK is issued by XERBLA. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input arguments +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --tau; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + --work; + + /* Function Body */ + *info = 0; + left = lsame_(side, "L"); + upper = lsame_(uplo, "U"); + lquery = *lwork == -1; + +/* NQ is the order of Q and NW is the minimum dimension of WORK */ + + if (left) { + nq = *m; + nw = *n; + } else { + nq = *n; + nw = *m; + } + if (! left && ! lsame_(side, "R")) { + *info = -1; + } else if (! upper && ! lsame_(uplo, "L")) { + *info = -2; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "C")) { + *info = -3; + } else if (*m < 0) { + *info = -4; + } else if (*n < 0) { + *info = -5; + } else if (*lda < max(1,nq)) { + *info = -7; + } else if (*ldc < max(1,*m)) { + *info = -10; + } else if (*lwork < max(1,nw) && ! lquery) { + *info = -12; + } + + if (*info == 0) { + if (upper) { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *m - 1; + i__3 = *m - 1; + nb = ilaenv_(&c__1, "ZUNMQL", ch__1, &i__2, n, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *n - 1; + i__3 = *n - 1; + nb = ilaenv_(&c__1, "ZUNMQL", ch__1, m, &i__2, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } else { + if (left) { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *m - 1; + i__3 = *m - 1; + nb = ilaenv_(&c__1, "ZUNMQR", ch__1, &i__2, n, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } else { +/* Writing concatenation */ + i__1[0] = 1, a__1[0] = side; + i__1[1] = 1, a__1[1] = trans; + s_cat(ch__1, a__1, i__1, &c__2, (ftnlen)2); + i__2 = *n - 1; + i__3 = *n - 1; + nb = ilaenv_(&c__1, "ZUNMQR", ch__1, m, &i__2, &i__3, &c_n1, ( + ftnlen)6, (ftnlen)2); + } + } + lwkopt = max(1,nw) * nb; + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + } + + if (*info != 0) { + i__2 = -(*info); + xerbla_("ZUNMTR", &i__2); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*m == 0 || *n == 0 || nq == 1) { + work[1].r = 1., work[1].i = 0.; + return 0; + } + + if (left) { + mi = *m - 1; + ni = *n; + } else { + mi = *m; + ni = *n - 1; + } + + if (upper) { + +/* Q was determined by a call to ZHETRD with UPLO = 'U' */ + + i__2 = nq - 1; + zunmql_(side, trans, &mi, &ni, &i__2, &a[(a_dim1 << 1) + 1], lda, & + tau[1], &c__[c_offset], ldc, &work[1], lwork, &iinfo); + } else { + +/* Q was determined by a call to ZHETRD with UPLO = 'L' */ + + if (left) { + i1 = 2; + i2 = 1; + } else { + i1 = 1; + i2 = 2; + } + i__2 = nq - 1; + zunmqr_(side, trans, &mi, &ni, &i__2, &a[a_dim1 + 2], lda, &tau[1], & + c__[i1 + i2 * c_dim1], ldc, &work[1], lwork, &iinfo); + } + work[1].r = (doublereal) lwkopt, work[1].i = 0.; + return 0; + +/* End of ZUNMTR */ + +} /* zunmtr_ */ + diff --git a/numpy/linalg/lapack_lite/python_xerbla.c b/numpy/linalg/lapack_lite/python_xerbla.c new file mode 100644 index 0000000..dfc1955 --- /dev/null +++ b/numpy/linalg/lapack_lite/python_xerbla.c @@ -0,0 +1,48 @@ +#include "Python.h" + +#undef c_abs +#include "f2c.h" + +/* + From the original manpage: + -------------------------- + XERBLA is an error handler for the LAPACK routines. + It is called by an LAPACK routine if an input parameter has an invalid value. + A message is printed and execution stops. + + Instead of printing a message and stopping the execution, a + ValueError is raised with the message. + + Parameters: + ----------- + srname: Subroutine name to use in error message, maximum six characters. + Spaces at the end are skipped. + info: Number of the invalid parameter. +*/ + +int xerbla_(char *srname, integer *info) +{ + static const char format[] = "On entry to %.*s" \ + " parameter number %d had an illegal value"; + char buf[sizeof(format) + 6 + 4]; /* 6 for name, 4 for param. num. */ + + int len = 0; /* length of subroutine name*/ +#ifdef WITH_THREAD + PyGILState_STATE save; +#endif + + while( len<6 && srname[len]!='\0' ) + len++; + while( len && srname[len-1]==' ' ) + len--; +#ifdef WITH_THREAD + save = PyGILState_Ensure(); +#endif + PyOS_snprintf(buf, sizeof(buf), format, len, srname, *info); + PyErr_SetString(PyExc_ValueError, buf); +#ifdef WITH_THREAD + PyGILState_Release(save); +#endif + + return 0; +} diff --git a/numpy/linalg/lapack_litemodule.c b/numpy/linalg/lapack_litemodule.c new file mode 100644 index 0000000..f321d6a --- /dev/null +++ b/numpy/linalg/lapack_litemodule.c @@ -0,0 +1,358 @@ +/*This module contributed by Doug Heisterkamp +Modified by Jim Hugunin +More modifications by Jeff Whitaker +*/ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" +#include "numpy/arrayobject.h" + +#ifdef NO_APPEND_FORTRAN +# define FNAME(x) x +#else +# define FNAME(x) x##_ +#endif + +typedef struct { float r, i; } f2c_complex; +typedef struct { double r, i; } f2c_doublecomplex; +/* typedef long int (*L_fp)(); */ + +extern int FNAME(dgelsd)(int *m, int *n, int *nrhs, + double a[], int *lda, double b[], int *ldb, + double s[], double *rcond, int *rank, + double work[], int *lwork, int iwork[], int *info); + +extern int FNAME(zgelsd)(int *m, int *n, int *nrhs, + f2c_doublecomplex a[], int *lda, + f2c_doublecomplex b[], int *ldb, + double s[], double *rcond, int *rank, + f2c_doublecomplex work[], int *lwork, + double rwork[], int iwork[], int *info); + +extern int FNAME(dgeqrf)(int *m, int *n, double a[], int *lda, + double tau[], double work[], + int *lwork, int *info); + +extern int FNAME(zgeqrf)(int *m, int *n, f2c_doublecomplex a[], int *lda, + f2c_doublecomplex tau[], f2c_doublecomplex work[], + int *lwork, int *info); + +extern int FNAME(dorgqr)(int *m, int *n, int *k, double a[], int *lda, + double tau[], double work[], + int *lwork, int *info); + +extern int FNAME(zungqr)(int *m, int *n, int *k, f2c_doublecomplex a[], + int *lda, f2c_doublecomplex tau[], + f2c_doublecomplex work[], int *lwork, int *info); + +extern int FNAME(xerbla)(char *srname, int *info); + +static PyObject *LapackError; + +#define TRY(E) if (!(E)) return NULL + +static int +check_object(PyObject *ob, int t, char *obname, + char *tname, char *funname) +{ + if (!PyArray_Check(ob)) { + PyErr_Format(LapackError, + "Expected an array for parameter %s in lapack_lite.%s", + obname, funname); + return 0; + } + else if (!PyArray_IS_C_CONTIGUOUS((PyArrayObject *)ob)) { + PyErr_Format(LapackError, + "Parameter %s is not contiguous in lapack_lite.%s", + obname, funname); + return 0; + } + else if (!(PyArray_TYPE((PyArrayObject *)ob) == t)) { + PyErr_Format(LapackError, + "Parameter %s is not of type %s in lapack_lite.%s", + obname, tname, funname); + return 0; + } + else if (PyArray_ISBYTESWAPPED((PyArrayObject *)ob)) { + PyErr_Format(LapackError, + "Parameter %s has non-native byte order in lapack_lite.%s", + obname, funname); + return 0; + } + else { + return 1; + } +} + +#define CHDATA(p) ((char *) PyArray_DATA((PyArrayObject *)p)) +#define SHDATA(p) ((short int *) PyArray_DATA((PyArrayObject *)p)) +#define DDATA(p) ((double *) PyArray_DATA((PyArrayObject *)p)) +#define FDATA(p) ((float *) PyArray_DATA((PyArrayObject *)p)) +#define CDATA(p) ((f2c_complex *) PyArray_DATA((PyArrayObject *)p)) +#define ZDATA(p) ((f2c_doublecomplex *) PyArray_DATA((PyArrayObject *)p)) +#define IDATA(p) ((int *) PyArray_DATA((PyArrayObject *)p)) + +static PyObject * +lapack_lite_dgelsd(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int lapack_lite_status; + int m; + int n; + int nrhs; + PyObject *a; + int lda; + PyObject *b; + int ldb; + PyObject *s; + double rcond; + int rank; + PyObject *work; + PyObject *iwork; + int lwork; + int info; + TRY(PyArg_ParseTuple(args,"iiiOiOiOdiOiOi:dgelsd", + &m,&n,&nrhs,&a,&lda,&b,&ldb,&s,&rcond, + &rank,&work,&lwork,&iwork,&info)); + + TRY(check_object(a,NPY_DOUBLE,"a","NPY_DOUBLE","dgelsd")); + TRY(check_object(b,NPY_DOUBLE,"b","NPY_DOUBLE","dgelsd")); + TRY(check_object(s,NPY_DOUBLE,"s","NPY_DOUBLE","dgelsd")); + TRY(check_object(work,NPY_DOUBLE,"work","NPY_DOUBLE","dgelsd")); + TRY(check_object(iwork,NPY_INT,"iwork","NPY_INT","dgelsd")); + + lapack_lite_status = + FNAME(dgelsd)(&m,&n,&nrhs,DDATA(a),&lda,DDATA(b),&ldb, + DDATA(s),&rcond,&rank,DDATA(work),&lwork, + IDATA(iwork),&info); + if (PyErr_Occurred()) { + return NULL; + } + + return Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:d,s:i,s:i,s:i}","dgelsd_", + lapack_lite_status,"m",m,"n",n,"nrhs",nrhs, + "lda",lda,"ldb",ldb,"rcond",rcond,"rank",rank, + "lwork",lwork,"info",info); +} + +static PyObject * +lapack_lite_dgeqrf(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int lapack_lite_status; + int m, n, lwork; + PyObject *a, *tau, *work; + int lda; + int info; + + TRY(PyArg_ParseTuple(args,"iiOiOOii:dgeqrf",&m,&n,&a,&lda,&tau,&work,&lwork,&info)); + + /* check objects and convert to right storage order */ + TRY(check_object(a,NPY_DOUBLE,"a","NPY_DOUBLE","dgeqrf")); + TRY(check_object(tau,NPY_DOUBLE,"tau","NPY_DOUBLE","dgeqrf")); + TRY(check_object(work,NPY_DOUBLE,"work","NPY_DOUBLE","dgeqrf")); + + lapack_lite_status = + FNAME(dgeqrf)(&m, &n, DDATA(a), &lda, DDATA(tau), + DDATA(work), &lwork, &info); + if (PyErr_Occurred()) { + return NULL; + } + + return Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i}","dgeqrf_", + lapack_lite_status,"m",m,"n",n,"lda",lda, + "lwork",lwork,"info",info); +} + + +static PyObject * +lapack_lite_dorgqr(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int lapack_lite_status; + int m, n, k, lwork; + PyObject *a, *tau, *work; + int lda; + int info; + + TRY(PyArg_ParseTuple(args,"iiiOiOOii:dorgqr", &m, &n, &k, &a, &lda, &tau, &work, &lwork, &info)); + TRY(check_object(a,NPY_DOUBLE,"a","NPY_DOUBLE","dorgqr")); + TRY(check_object(tau,NPY_DOUBLE,"tau","NPY_DOUBLE","dorgqr")); + TRY(check_object(work,NPY_DOUBLE,"work","NPY_DOUBLE","dorgqr")); + lapack_lite_status = + FNAME(dorgqr)(&m, &n, &k, DDATA(a), &lda, DDATA(tau), DDATA(work), + &lwork, &info); + if (PyErr_Occurred()) { + return NULL; + } + + return Py_BuildValue("{s:i,s:i}","dorgqr_",lapack_lite_status, + "info",info); +} + + +static PyObject * +lapack_lite_zgelsd(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int lapack_lite_status; + int m; + int n; + int nrhs; + PyObject *a; + int lda; + PyObject *b; + int ldb; + PyObject *s; + double rcond; + int rank; + PyObject *work; + int lwork; + PyObject *rwork; + PyObject *iwork; + int info; + TRY(PyArg_ParseTuple(args,"iiiOiOiOdiOiOOi:zgelsd", + &m,&n,&nrhs,&a,&lda,&b,&ldb,&s,&rcond, + &rank,&work,&lwork,&rwork,&iwork,&info)); + + TRY(check_object(a,NPY_CDOUBLE,"a","NPY_CDOUBLE","zgelsd")); + TRY(check_object(b,NPY_CDOUBLE,"b","NPY_CDOUBLE","zgelsd")); + TRY(check_object(s,NPY_DOUBLE,"s","NPY_DOUBLE","zgelsd")); + TRY(check_object(work,NPY_CDOUBLE,"work","NPY_CDOUBLE","zgelsd")); + TRY(check_object(rwork,NPY_DOUBLE,"rwork","NPY_DOUBLE","zgelsd")); + TRY(check_object(iwork,NPY_INT,"iwork","NPY_INT","zgelsd")); + + lapack_lite_status = + FNAME(zgelsd)(&m,&n,&nrhs,ZDATA(a),&lda,ZDATA(b),&ldb,DDATA(s),&rcond, + &rank,ZDATA(work),&lwork,DDATA(rwork),IDATA(iwork),&info); + if (PyErr_Occurred()) { + return NULL; + } + + return Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}","zgelsd_", + lapack_lite_status,"m",m,"n",n,"nrhs",nrhs,"lda",lda, + "ldb",ldb,"rank",rank,"lwork",lwork,"info",info); +} + +static PyObject * +lapack_lite_zgeqrf(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int lapack_lite_status; + int m, n, lwork; + PyObject *a, *tau, *work; + int lda; + int info; + + TRY(PyArg_ParseTuple(args,"iiOiOOii:zgeqrf",&m,&n,&a,&lda,&tau,&work,&lwork,&info)); + +/* check objects and convert to right storage order */ + TRY(check_object(a,NPY_CDOUBLE,"a","NPY_CDOUBLE","zgeqrf")); + TRY(check_object(tau,NPY_CDOUBLE,"tau","NPY_CDOUBLE","zgeqrf")); + TRY(check_object(work,NPY_CDOUBLE,"work","NPY_CDOUBLE","zgeqrf")); + + lapack_lite_status = + FNAME(zgeqrf)(&m, &n, ZDATA(a), &lda, ZDATA(tau), ZDATA(work), + &lwork, &info); + if (PyErr_Occurred()) { + return NULL; + } + + return Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i}","zgeqrf_",lapack_lite_status,"m",m,"n",n,"lda",lda,"lwork",lwork,"info",info); +} + + +static PyObject * +lapack_lite_zungqr(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int lapack_lite_status; + int m, n, k, lwork; + PyObject *a, *tau, *work; + int lda; + int info; + + TRY(PyArg_ParseTuple(args,"iiiOiOOii:zungqr", &m, &n, &k, &a, &lda, &tau, &work, &lwork, &info)); + TRY(check_object(a,NPY_CDOUBLE,"a","NPY_CDOUBLE","zungqr")); + TRY(check_object(tau,NPY_CDOUBLE,"tau","NPY_CDOUBLE","zungqr")); + TRY(check_object(work,NPY_CDOUBLE,"work","NPY_CDOUBLE","zungqr")); + + + lapack_lite_status = + FNAME(zungqr)(&m, &n, &k, ZDATA(a), &lda, ZDATA(tau), ZDATA(work), + &lwork, &info); + if (PyErr_Occurred()) { + return NULL; + } + + return Py_BuildValue("{s:i,s:i}","zungqr_",lapack_lite_status, + "info",info); +} + + +static PyObject * +lapack_lite_xerbla(PyObject *NPY_UNUSED(self), PyObject *args) +{ + int info = -1; + + NPY_BEGIN_THREADS_DEF; + NPY_BEGIN_THREADS; + FNAME(xerbla)("test", &info); + NPY_END_THREADS; + + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_NONE; +} + + +#define STR(x) #x +#define lameth(name) {STR(name), lapack_lite_##name, METH_VARARGS, NULL} +static struct PyMethodDef lapack_lite_module_methods[] = { + lameth(dgelsd), + lameth(dgeqrf), + lameth(dorgqr), + lameth(zgelsd), + lameth(zgeqrf), + lameth(zungqr), + lameth(xerbla), + { NULL,NULL,0, NULL} +}; + + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "lapack_lite", + NULL, + -1, + lapack_lite_module_methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +/* Initialization function for the module */ +#if PY_MAJOR_VERSION >= 3 +#define RETVAL m +PyMODINIT_FUNC PyInit_lapack_lite(void) +#else +#define RETVAL +PyMODINIT_FUNC +initlapack_lite(void) +#endif +{ + PyObject *m,*d; +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule4("lapack_lite", lapack_lite_module_methods, + "", (PyObject*)NULL,PYTHON_API_VERSION); +#endif + if (m == NULL) { + return RETVAL; + } + import_array(); + d = PyModule_GetDict(m); + LapackError = PyErr_NewException("lapack_lite.LapackError", NULL, NULL); + PyDict_SetItemString(d, "LapackError", LapackError); + + return RETVAL; +} diff --git a/numpy/linalg/linalg.py b/numpy/linalg/linalg.py new file mode 100644 index 0000000..e42de82 --- /dev/null +++ b/numpy/linalg/linalg.py @@ -0,0 +1,2521 @@ +"""Lite version of scipy.linalg. + +Notes +----- +This module is a lite version of the linalg.py module in SciPy which +contains high-level Python interface to the LAPACK library. The lite +version only accesses the following LAPACK functions: dgesv, zgesv, +dgeev, zgeev, dgesdd, zgesdd, dgelsd, zgelsd, dsyevd, zheevd, dgetrf, +zgetrf, dpotrf, zpotrf, dgeqrf, zgeqrf, zungqr, dorgqr. +""" +from __future__ import division, absolute_import, print_function + + +__all__ = ['matrix_power', 'solve', 'tensorsolve', 'tensorinv', 'inv', + 'cholesky', 'eigvals', 'eigvalsh', 'pinv', 'slogdet', 'det', + 'svd', 'eig', 'eigh', 'lstsq', 'norm', 'qr', 'cond', 'matrix_rank', + 'LinAlgError', 'multi_dot'] + +import warnings + +from numpy.core import ( + array, asarray, zeros, empty, empty_like, intc, single, double, + csingle, cdouble, inexact, complexfloating, newaxis, ravel, all, Inf, dot, + add, multiply, sqrt, maximum, fastCopyAndTranspose, sum, isfinite, size, + finfo, errstate, geterrobj, longdouble, moveaxis, amin, amax, product, abs, + broadcast, atleast_2d, intp, asanyarray, object_, ones, matmul, + swapaxes, divide, count_nonzero +) +from numpy.core.multiarray import normalize_axis_index +from numpy.lib import triu, asfarray +from numpy.linalg import lapack_lite, _umath_linalg +from numpy.matrixlib.defmatrix import matrix_power + +# For Python2/3 compatibility +_N = b'N' +_V = b'V' +_A = b'A' +_S = b'S' +_L = b'L' + +fortran_int = intc + +# Error object +class LinAlgError(Exception): + """ + Generic Python-exception-derived object raised by linalg functions. + + General purpose exception class, derived from Python's exception.Exception + class, programmatically raised in linalg functions when a Linear + Algebra-related condition would prevent further correct execution of the + function. + + Parameters + ---------- + None + + Examples + -------- + >>> from numpy import linalg as LA + >>> LA.inv(np.zeros((2,2))) + Traceback (most recent call last): + File "", line 1, in + File "...linalg.py", line 350, + in inv return wrap(solve(a, identity(a.shape[0], dtype=a.dtype))) + File "...linalg.py", line 249, + in solve + raise LinAlgError('Singular matrix') + numpy.linalg.LinAlgError: Singular matrix + + """ + pass + + +def _determine_error_states(): + errobj = geterrobj() + bufsize = errobj[0] + + with errstate(invalid='call', over='ignore', + divide='ignore', under='ignore'): + invalid_call_errmask = geterrobj()[1] + + return [bufsize, invalid_call_errmask, None] + +# Dealing with errors in _umath_linalg +_linalg_error_extobj = _determine_error_states() +del _determine_error_states + +def _raise_linalgerror_singular(err, flag): + raise LinAlgError("Singular matrix") + +def _raise_linalgerror_nonposdef(err, flag): + raise LinAlgError("Matrix is not positive definite") + +def _raise_linalgerror_eigenvalues_nonconvergence(err, flag): + raise LinAlgError("Eigenvalues did not converge") + +def _raise_linalgerror_svd_nonconvergence(err, flag): + raise LinAlgError("SVD did not converge") + +def get_linalg_error_extobj(callback): + extobj = list(_linalg_error_extobj) # make a copy + extobj[2] = callback + return extobj + +def _makearray(a): + new = asarray(a) + wrap = getattr(a, "__array_prepare__", new.__array_wrap__) + return new, wrap + +def isComplexType(t): + return issubclass(t, complexfloating) + +_real_types_map = {single : single, + double : double, + csingle : single, + cdouble : double} + +_complex_types_map = {single : csingle, + double : cdouble, + csingle : csingle, + cdouble : cdouble} + +def _realType(t, default=double): + return _real_types_map.get(t, default) + +def _complexType(t, default=cdouble): + return _complex_types_map.get(t, default) + +def _linalgRealType(t): + """Cast the type t to either double or cdouble.""" + return double + +_complex_types_map = {single : csingle, + double : cdouble, + csingle : csingle, + cdouble : cdouble} + +def _commonType(*arrays): + # in lite version, use higher precision (always double or cdouble) + result_type = single + is_complex = False + for a in arrays: + if issubclass(a.dtype.type, inexact): + if isComplexType(a.dtype.type): + is_complex = True + rt = _realType(a.dtype.type, default=None) + if rt is None: + # unsupported inexact scalar + raise TypeError("array type %s is unsupported in linalg" % + (a.dtype.name,)) + else: + rt = double + if rt is double: + result_type = double + if is_complex: + t = cdouble + result_type = _complex_types_map[result_type] + else: + t = double + return t, result_type + + +# _fastCopyAndTranpose assumes the input is 2D (as all the calls in here are). + +_fastCT = fastCopyAndTranspose + +def _to_native_byte_order(*arrays): + ret = [] + for arr in arrays: + if arr.dtype.byteorder not in ('=', '|'): + ret.append(asarray(arr, dtype=arr.dtype.newbyteorder('='))) + else: + ret.append(arr) + if len(ret) == 1: + return ret[0] + else: + return ret + +def _fastCopyAndTranspose(type, *arrays): + cast_arrays = () + for a in arrays: + if a.dtype.type is type: + cast_arrays = cast_arrays + (_fastCT(a),) + else: + cast_arrays = cast_arrays + (_fastCT(a.astype(type)),) + if len(cast_arrays) == 1: + return cast_arrays[0] + else: + return cast_arrays + +def _assertRank2(*arrays): + for a in arrays: + if a.ndim != 2: + raise LinAlgError('%d-dimensional array given. Array must be ' + 'two-dimensional' % a.ndim) + +def _assertRankAtLeast2(*arrays): + for a in arrays: + if a.ndim < 2: + raise LinAlgError('%d-dimensional array given. Array must be ' + 'at least two-dimensional' % a.ndim) + +def _assertSquareness(*arrays): + for a in arrays: + if max(a.shape) != min(a.shape): + raise LinAlgError('Array must be square') + +def _assertNdSquareness(*arrays): + for a in arrays: + if max(a.shape[-2:]) != min(a.shape[-2:]): + raise LinAlgError('Last 2 dimensions of the array must be square') + +def _assertFinite(*arrays): + for a in arrays: + if not (isfinite(a).all()): + raise LinAlgError("Array must not contain infs or NaNs") + +def _isEmpty2d(arr): + # check size first for efficiency + return arr.size == 0 and product(arr.shape[-2:]) == 0 + +def _assertNoEmpty2d(*arrays): + for a in arrays: + if _isEmpty2d(a): + raise LinAlgError("Arrays cannot be empty") + +def transpose(a): + """ + Transpose each matrix in a stack of matrices. + + Unlike np.transpose, this only swaps the last two axes, rather than all of + them + + Parameters + ---------- + a : (...,M,N) array_like + + Returns + ------- + aT : (...,N,M) ndarray + """ + return swapaxes(a, -1, -2) + +# Linear equations + +def tensorsolve(a, b, axes=None): + """ + Solve the tensor equation ``a x = b`` for x. + + It is assumed that all indices of `x` are summed over in the product, + together with the rightmost indices of `a`, as is done in, for example, + ``tensordot(a, x, axes=b.ndim)``. + + Parameters + ---------- + a : array_like + Coefficient tensor, of shape ``b.shape + Q``. `Q`, a tuple, equals + the shape of that sub-tensor of `a` consisting of the appropriate + number of its rightmost indices, and must be such that + ``prod(Q) == prod(b.shape)`` (in which sense `a` is said to be + 'square'). + b : array_like + Right-hand tensor, which can be of any shape. + axes : tuple of ints, optional + Axes in `a` to reorder to the right, before inversion. + If None (default), no reordering is done. + + Returns + ------- + x : ndarray, shape Q + + Raises + ------ + LinAlgError + If `a` is singular or not 'square' (in the above sense). + + See Also + -------- + numpy.tensordot, tensorinv, numpy.einsum + + Examples + -------- + >>> a = np.eye(2*3*4) + >>> a.shape = (2*3, 4, 2, 3, 4) + >>> b = np.random.randn(2*3, 4) + >>> x = np.linalg.tensorsolve(a, b) + >>> x.shape + (2, 3, 4) + >>> np.allclose(np.tensordot(a, x, axes=3), b) + True + + """ + a, wrap = _makearray(a) + b = asarray(b) + an = a.ndim + + if axes is not None: + allaxes = list(range(0, an)) + for k in axes: + allaxes.remove(k) + allaxes.insert(an, k) + a = a.transpose(allaxes) + + oldshape = a.shape[-(an-b.ndim):] + prod = 1 + for k in oldshape: + prod *= k + + a = a.reshape(-1, prod) + b = b.ravel() + res = wrap(solve(a, b)) + res.shape = oldshape + return res + +def solve(a, b): + """ + Solve a linear matrix equation, or system of linear scalar equations. + + Computes the "exact" solution, `x`, of the well-determined, i.e., full + rank, linear matrix equation `ax = b`. + + Parameters + ---------- + a : (..., M, M) array_like + Coefficient matrix. + b : {(..., M,), (..., M, K)}, array_like + Ordinate or "dependent variable" values. + + Returns + ------- + x : {(..., M,), (..., M, K)} ndarray + Solution to the system a x = b. Returned shape is identical to `b`. + + Raises + ------ + LinAlgError + If `a` is singular or not square. + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The solutions are computed using LAPACK routine _gesv + + `a` must be square and of full-rank, i.e., all rows (or, equivalently, + columns) must be linearly independent; if either is not true, use + `lstsq` for the least-squares best "solution" of the + system/equation. + + References + ---------- + .. [1] G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando, + FL, Academic Press, Inc., 1980, pg. 22. + + Examples + -------- + Solve the system of equations ``3 * x0 + x1 = 9`` and ``x0 + 2 * x1 = 8``: + + >>> a = np.array([[3,1], [1,2]]) + >>> b = np.array([9,8]) + >>> x = np.linalg.solve(a, b) + >>> x + array([ 2., 3.]) + + Check that the solution is correct: + + >>> np.allclose(np.dot(a, x), b) + True + + """ + a, _ = _makearray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + b, wrap = _makearray(b) + t, result_t = _commonType(a, b) + + # We use the b = (..., M,) logic, only if the number of extra dimensions + # match exactly + if b.ndim == a.ndim - 1: + gufunc = _umath_linalg.solve1 + else: + gufunc = _umath_linalg.solve + + signature = 'DD->D' if isComplexType(t) else 'dd->d' + extobj = get_linalg_error_extobj(_raise_linalgerror_singular) + r = gufunc(a, b, signature=signature, extobj=extobj) + + return wrap(r.astype(result_t, copy=False)) + + +def tensorinv(a, ind=2): + """ + Compute the 'inverse' of an N-dimensional array. + + The result is an inverse for `a` relative to the tensordot operation + ``tensordot(a, b, ind)``, i. e., up to floating-point accuracy, + ``tensordot(tensorinv(a), a, ind)`` is the "identity" tensor for the + tensordot operation. + + Parameters + ---------- + a : array_like + Tensor to 'invert'. Its shape must be 'square', i. e., + ``prod(a.shape[:ind]) == prod(a.shape[ind:])``. + ind : int, optional + Number of first indices that are involved in the inverse sum. + Must be a positive integer, default is 2. + + Returns + ------- + b : ndarray + `a`'s tensordot inverse, shape ``a.shape[ind:] + a.shape[:ind]``. + + Raises + ------ + LinAlgError + If `a` is singular or not 'square' (in the above sense). + + See Also + -------- + numpy.tensordot, tensorsolve + + Examples + -------- + >>> a = np.eye(4*6) + >>> a.shape = (4, 6, 8, 3) + >>> ainv = np.linalg.tensorinv(a, ind=2) + >>> ainv.shape + (8, 3, 4, 6) + >>> b = np.random.randn(4, 6) + >>> np.allclose(np.tensordot(ainv, b), np.linalg.tensorsolve(a, b)) + True + + >>> a = np.eye(4*6) + >>> a.shape = (24, 8, 3) + >>> ainv = np.linalg.tensorinv(a, ind=1) + >>> ainv.shape + (8, 3, 24) + >>> b = np.random.randn(24) + >>> np.allclose(np.tensordot(ainv, b, 1), np.linalg.tensorsolve(a, b)) + True + + """ + a = asarray(a) + oldshape = a.shape + prod = 1 + if ind > 0: + invshape = oldshape[ind:] + oldshape[:ind] + for k in oldshape[ind:]: + prod *= k + else: + raise ValueError("Invalid ind argument.") + a = a.reshape(prod, -1) + ia = inv(a) + return ia.reshape(*invshape) + + +# Matrix inversion + +def inv(a): + """ + Compute the (multiplicative) inverse of a matrix. + + Given a square matrix `a`, return the matrix `ainv` satisfying + ``dot(a, ainv) = dot(ainv, a) = eye(a.shape[0])``. + + Parameters + ---------- + a : (..., M, M) array_like + Matrix to be inverted. + + Returns + ------- + ainv : (..., M, M) ndarray or matrix + (Multiplicative) inverse of the matrix `a`. + + Raises + ------ + LinAlgError + If `a` is not square or inversion fails. + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + Examples + -------- + >>> from numpy.linalg import inv + >>> a = np.array([[1., 2.], [3., 4.]]) + >>> ainv = inv(a) + >>> np.allclose(np.dot(a, ainv), np.eye(2)) + True + >>> np.allclose(np.dot(ainv, a), np.eye(2)) + True + + If a is a matrix object, then the return value is a matrix as well: + + >>> ainv = inv(np.matrix(a)) + >>> ainv + matrix([[-2. , 1. ], + [ 1.5, -0.5]]) + + Inverses of several matrices can be computed at once: + + >>> a = np.array([[[1., 2.], [3., 4.]], [[1, 3], [3, 5]]]) + >>> inv(a) + array([[[-2. , 1. ], + [ 1.5, -0.5]], + [[-5. , 2. ], + [ 3. , -1. ]]]) + + """ + a, wrap = _makearray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + t, result_t = _commonType(a) + + signature = 'D->D' if isComplexType(t) else 'd->d' + extobj = get_linalg_error_extobj(_raise_linalgerror_singular) + ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj) + return wrap(ainv.astype(result_t, copy=False)) + + +# Cholesky decomposition + +def cholesky(a): + """ + Cholesky decomposition. + + Return the Cholesky decomposition, `L * L.H`, of the square matrix `a`, + where `L` is lower-triangular and .H is the conjugate transpose operator + (which is the ordinary transpose if `a` is real-valued). `a` must be + Hermitian (symmetric if real-valued) and positive-definite. Only `L` is + actually returned. + + Parameters + ---------- + a : (..., M, M) array_like + Hermitian (symmetric if all elements are real), positive-definite + input matrix. + + Returns + ------- + L : (..., M, M) array_like + Upper or lower-triangular Cholesky factor of `a`. Returns a + matrix object if `a` is a matrix object. + + Raises + ------ + LinAlgError + If the decomposition fails, for example, if `a` is not + positive-definite. + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The Cholesky decomposition is often used as a fast way of solving + + .. math:: A \\mathbf{x} = \\mathbf{b} + + (when `A` is both Hermitian/symmetric and positive-definite). + + First, we solve for :math:`\\mathbf{y}` in + + .. math:: L \\mathbf{y} = \\mathbf{b}, + + and then for :math:`\\mathbf{x}` in + + .. math:: L.H \\mathbf{x} = \\mathbf{y}. + + Examples + -------- + >>> A = np.array([[1,-2j],[2j,5]]) + >>> A + array([[ 1.+0.j, 0.-2.j], + [ 0.+2.j, 5.+0.j]]) + >>> L = np.linalg.cholesky(A) + >>> L + array([[ 1.+0.j, 0.+0.j], + [ 0.+2.j, 1.+0.j]]) + >>> np.dot(L, L.T.conj()) # verify that L * L.H = A + array([[ 1.+0.j, 0.-2.j], + [ 0.+2.j, 5.+0.j]]) + >>> A = [[1,-2j],[2j,5]] # what happens if A is only array_like? + >>> np.linalg.cholesky(A) # an ndarray object is returned + array([[ 1.+0.j, 0.+0.j], + [ 0.+2.j, 1.+0.j]]) + >>> # But a matrix object is returned if A is a matrix object + >>> LA.cholesky(np.matrix(A)) + matrix([[ 1.+0.j, 0.+0.j], + [ 0.+2.j, 1.+0.j]]) + + """ + extobj = get_linalg_error_extobj(_raise_linalgerror_nonposdef) + gufunc = _umath_linalg.cholesky_lo + a, wrap = _makearray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + t, result_t = _commonType(a) + signature = 'D->D' if isComplexType(t) else 'd->d' + r = gufunc(a, signature=signature, extobj=extobj) + return wrap(r.astype(result_t, copy=False)) + +# QR decompostion + +def qr(a, mode='reduced'): + """ + Compute the qr factorization of a matrix. + + Factor the matrix `a` as *qr*, where `q` is orthonormal and `r` is + upper-triangular. + + Parameters + ---------- + a : array_like, shape (M, N) + Matrix to be factored. + mode : {'reduced', 'complete', 'r', 'raw', 'full', 'economic'}, optional + If K = min(M, N), then + + * 'reduced' : returns q, r with dimensions (M, K), (K, N) (default) + * 'complete' : returns q, r with dimensions (M, M), (M, N) + * 'r' : returns r only with dimensions (K, N) + * 'raw' : returns h, tau with dimensions (N, M), (K,) + * 'full' : alias of 'reduced', deprecated + * 'economic' : returns h from 'raw', deprecated. + + The options 'reduced', 'complete, and 'raw' are new in numpy 1.8, + see the notes for more information. The default is 'reduced', and to + maintain backward compatibility with earlier versions of numpy both + it and the old default 'full' can be omitted. Note that array h + returned in 'raw' mode is transposed for calling Fortran. The + 'economic' mode is deprecated. The modes 'full' and 'economic' may + be passed using only the first letter for backwards compatibility, + but all others must be spelled out. See the Notes for more + explanation. + + + Returns + ------- + q : ndarray of float or complex, optional + A matrix with orthonormal columns. When mode = 'complete' the + result is an orthogonal/unitary matrix depending on whether or not + a is real/complex. The determinant may be either +/- 1 in that + case. + r : ndarray of float or complex, optional + The upper-triangular matrix. + (h, tau) : ndarrays of np.double or np.cdouble, optional + The array h contains the Householder reflectors that generate q + along with r. The tau array contains scaling factors for the + reflectors. In the deprecated 'economic' mode only h is returned. + + Raises + ------ + LinAlgError + If factoring fails. + + Notes + ----- + This is an interface to the LAPACK routines dgeqrf, zgeqrf, + dorgqr, and zungqr. + + For more information on the qr factorization, see for example: + http://en.wikipedia.org/wiki/QR_factorization + + Subclasses of `ndarray` are preserved except for the 'raw' mode. So if + `a` is of type `matrix`, all the return values will be matrices too. + + New 'reduced', 'complete', and 'raw' options for mode were added in + NumPy 1.8.0 and the old option 'full' was made an alias of 'reduced'. In + addition the options 'full' and 'economic' were deprecated. Because + 'full' was the previous default and 'reduced' is the new default, + backward compatibility can be maintained by letting `mode` default. + The 'raw' option was added so that LAPACK routines that can multiply + arrays by q using the Householder reflectors can be used. Note that in + this case the returned arrays are of type np.double or np.cdouble and + the h array is transposed to be FORTRAN compatible. No routines using + the 'raw' return are currently exposed by numpy, but some are available + in lapack_lite and just await the necessary work. + + Examples + -------- + >>> a = np.random.randn(9, 6) + >>> q, r = np.linalg.qr(a) + >>> np.allclose(a, np.dot(q, r)) # a does equal qr + True + >>> r2 = np.linalg.qr(a, mode='r') + >>> r3 = np.linalg.qr(a, mode='economic') + >>> np.allclose(r, r2) # mode='r' returns the same r as mode='full' + True + >>> # But only triu parts are guaranteed equal when mode='economic' + >>> np.allclose(r, np.triu(r3[:6,:6], k=0)) + True + + Example illustrating a common use of `qr`: solving of least squares + problems + + What are the least-squares-best `m` and `y0` in ``y = y0 + mx`` for + the following data: {(0,1), (1,0), (1,2), (2,1)}. (Graph the points + and you'll see that it should be y0 = 0, m = 1.) The answer is provided + by solving the over-determined matrix equation ``Ax = b``, where:: + + A = array([[0, 1], [1, 1], [1, 1], [2, 1]]) + x = array([[y0], [m]]) + b = array([[1], [0], [2], [1]]) + + If A = qr such that q is orthonormal (which is always possible via + Gram-Schmidt), then ``x = inv(r) * (q.T) * b``. (In numpy practice, + however, we simply use `lstsq`.) + + >>> A = np.array([[0, 1], [1, 1], [1, 1], [2, 1]]) + >>> A + array([[0, 1], + [1, 1], + [1, 1], + [2, 1]]) + >>> b = np.array([1, 0, 2, 1]) + >>> q, r = LA.qr(A) + >>> p = np.dot(q.T, b) + >>> np.dot(LA.inv(r), p) + array([ 1.1e-16, 1.0e+00]) + + """ + if mode not in ('reduced', 'complete', 'r', 'raw'): + if mode in ('f', 'full'): + # 2013-04-01, 1.8 + msg = "".join(( + "The 'full' option is deprecated in favor of 'reduced'.\n", + "For backward compatibility let mode default.")) + warnings.warn(msg, DeprecationWarning, stacklevel=2) + mode = 'reduced' + elif mode in ('e', 'economic'): + # 2013-04-01, 1.8 + msg = "The 'economic' option is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=2) + mode = 'economic' + else: + raise ValueError("Unrecognized mode '%s'" % mode) + + a, wrap = _makearray(a) + _assertRank2(a) + _assertNoEmpty2d(a) + m, n = a.shape + t, result_t = _commonType(a) + a = _fastCopyAndTranspose(t, a) + a = _to_native_byte_order(a) + mn = min(m, n) + tau = zeros((mn,), t) + if isComplexType(t): + lapack_routine = lapack_lite.zgeqrf + routine_name = 'zgeqrf' + else: + lapack_routine = lapack_lite.dgeqrf + routine_name = 'dgeqrf' + + # calculate optimal size of work data 'work' + lwork = 1 + work = zeros((lwork,), t) + results = lapack_routine(m, n, a, m, tau, work, -1, 0) + if results['info'] != 0: + raise LinAlgError('%s returns %d' % (routine_name, results['info'])) + + # do qr decomposition + lwork = int(abs(work[0])) + work = zeros((lwork,), t) + results = lapack_routine(m, n, a, m, tau, work, lwork, 0) + if results['info'] != 0: + raise LinAlgError('%s returns %d' % (routine_name, results['info'])) + + # handle modes that don't return q + if mode == 'r': + r = _fastCopyAndTranspose(result_t, a[:, :mn]) + return wrap(triu(r)) + + if mode == 'raw': + return a, tau + + if mode == 'economic': + if t != result_t : + a = a.astype(result_t, copy=False) + return wrap(a.T) + + # generate q from a + if mode == 'complete' and m > n: + mc = m + q = empty((m, m), t) + else: + mc = mn + q = empty((n, m), t) + q[:n] = a + + if isComplexType(t): + lapack_routine = lapack_lite.zungqr + routine_name = 'zungqr' + else: + lapack_routine = lapack_lite.dorgqr + routine_name = 'dorgqr' + + # determine optimal lwork + lwork = 1 + work = zeros((lwork,), t) + results = lapack_routine(m, mc, mn, q, m, tau, work, -1, 0) + if results['info'] != 0: + raise LinAlgError('%s returns %d' % (routine_name, results['info'])) + + # compute q + lwork = int(abs(work[0])) + work = zeros((lwork,), t) + results = lapack_routine(m, mc, mn, q, m, tau, work, lwork, 0) + if results['info'] != 0: + raise LinAlgError('%s returns %d' % (routine_name, results['info'])) + + q = _fastCopyAndTranspose(result_t, q[:mc]) + r = _fastCopyAndTranspose(result_t, a[:, :mc]) + + return wrap(q), wrap(triu(r)) + + +# Eigenvalues + + +def eigvals(a): + """ + Compute the eigenvalues of a general matrix. + + Main difference between `eigvals` and `eig`: the eigenvectors aren't + returned. + + Parameters + ---------- + a : (..., M, M) array_like + A complex- or real-valued matrix whose eigenvalues will be computed. + + Returns + ------- + w : (..., M,) ndarray + The eigenvalues, each repeated according to its multiplicity. + They are not necessarily ordered, nor are they necessarily + real for real matrices. + + Raises + ------ + LinAlgError + If the eigenvalue computation does not converge. + + See Also + -------- + eig : eigenvalues and right eigenvectors of general arrays + eigvalsh : eigenvalues of symmetric or Hermitian arrays. + eigh : eigenvalues and eigenvectors of symmetric/Hermitian arrays. + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + This is implemented using the _geev LAPACK routines which compute + the eigenvalues and eigenvectors of general square arrays. + + Examples + -------- + Illustration, using the fact that the eigenvalues of a diagonal matrix + are its diagonal elements, that multiplying a matrix on the left + by an orthogonal matrix, `Q`, and on the right by `Q.T` (the transpose + of `Q`), preserves the eigenvalues of the "middle" matrix. In other words, + if `Q` is orthogonal, then ``Q * A * Q.T`` has the same eigenvalues as + ``A``: + + >>> from numpy import linalg as LA + >>> x = np.random.random() + >>> Q = np.array([[np.cos(x), -np.sin(x)], [np.sin(x), np.cos(x)]]) + >>> LA.norm(Q[0, :]), LA.norm(Q[1, :]), np.dot(Q[0, :],Q[1, :]) + (1.0, 1.0, 0.0) + + Now multiply a diagonal matrix by Q on one side and by Q.T on the other: + + >>> D = np.diag((-1,1)) + >>> LA.eigvals(D) + array([-1., 1.]) + >>> A = np.dot(Q, D) + >>> A = np.dot(A, Q.T) + >>> LA.eigvals(A) + array([ 1., -1.]) + + """ + a, wrap = _makearray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + _assertFinite(a) + t, result_t = _commonType(a) + + extobj = get_linalg_error_extobj( + _raise_linalgerror_eigenvalues_nonconvergence) + signature = 'D->D' if isComplexType(t) else 'd->D' + w = _umath_linalg.eigvals(a, signature=signature, extobj=extobj) + + if not isComplexType(t): + if all(w.imag == 0): + w = w.real + result_t = _realType(result_t) + else: + result_t = _complexType(result_t) + + return w.astype(result_t, copy=False) + +def eigvalsh(a, UPLO='L'): + """ + Compute the eigenvalues of a Hermitian or real symmetric matrix. + + Main difference from eigh: the eigenvectors are not computed. + + Parameters + ---------- + a : (..., M, M) array_like + A complex- or real-valued matrix whose eigenvalues are to be + computed. + UPLO : {'L', 'U'}, optional + Specifies whether the calculation is done with the lower triangular + part of `a` ('L', default) or the upper triangular part ('U'). + Irrespective of this value only the real parts of the diagonal will + be considered in the computation to preserve the notion of a Hermitian + matrix. It therefore follows that the imaginary part of the diagonal + will always be treated as zero. + + Returns + ------- + w : (..., M,) ndarray + The eigenvalues in ascending order, each repeated according to + its multiplicity. + + Raises + ------ + LinAlgError + If the eigenvalue computation does not converge. + + See Also + -------- + eigh : eigenvalues and eigenvectors of symmetric/Hermitian arrays. + eigvals : eigenvalues of general real or complex arrays. + eig : eigenvalues and right eigenvectors of general real or complex + arrays. + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The eigenvalues are computed using LAPACK routines _syevd, _heevd + + Examples + -------- + >>> from numpy import linalg as LA + >>> a = np.array([[1, -2j], [2j, 5]]) + >>> LA.eigvalsh(a) + array([ 0.17157288, 5.82842712]) + + >>> # demonstrate the treatment of the imaginary part of the diagonal + >>> a = np.array([[5+2j, 9-2j], [0+2j, 2-1j]]) + >>> a + array([[ 5.+2.j, 9.-2.j], + [ 0.+2.j, 2.-1.j]]) + >>> # with UPLO='L' this is numerically equivalent to using LA.eigvals() + >>> # with: + >>> b = np.array([[5.+0.j, 0.-2.j], [0.+2.j, 2.-0.j]]) + >>> b + array([[ 5.+0.j, 0.-2.j], + [ 0.+2.j, 2.+0.j]]) + >>> wa = LA.eigvalsh(a) + >>> wb = LA.eigvals(b) + >>> wa; wb + array([ 1., 6.]) + array([ 6.+0.j, 1.+0.j]) + + """ + UPLO = UPLO.upper() + if UPLO not in ('L', 'U'): + raise ValueError("UPLO argument must be 'L' or 'U'") + + extobj = get_linalg_error_extobj( + _raise_linalgerror_eigenvalues_nonconvergence) + if UPLO == 'L': + gufunc = _umath_linalg.eigvalsh_lo + else: + gufunc = _umath_linalg.eigvalsh_up + + a, wrap = _makearray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + t, result_t = _commonType(a) + signature = 'D->d' if isComplexType(t) else 'd->d' + w = gufunc(a, signature=signature, extobj=extobj) + return w.astype(_realType(result_t), copy=False) + +def _convertarray(a): + t, result_t = _commonType(a) + a = _fastCT(a.astype(t)) + return a, t, result_t + + +# Eigenvectors + + +def eig(a): + """ + Compute the eigenvalues and right eigenvectors of a square array. + + Parameters + ---------- + a : (..., M, M) array + Matrices for which the eigenvalues and right eigenvectors will + be computed + + Returns + ------- + w : (..., M) array + The eigenvalues, each repeated according to its multiplicity. + The eigenvalues are not necessarily ordered. The resulting + array will be of complex type, unless the imaginary part is + zero in which case it will be cast to a real type. When `a` + is real the resulting eigenvalues will be real (0 imaginary + part) or occur in conjugate pairs + + v : (..., M, M) array + The normalized (unit "length") eigenvectors, such that the + column ``v[:,i]`` is the eigenvector corresponding to the + eigenvalue ``w[i]``. + + Raises + ------ + LinAlgError + If the eigenvalue computation does not converge. + + See Also + -------- + eigvals : eigenvalues of a non-symmetric array. + + eigh : eigenvalues and eigenvectors of a symmetric or Hermitian + (conjugate symmetric) array. + + eigvalsh : eigenvalues of a symmetric or Hermitian (conjugate symmetric) + array. + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + This is implemented using the _geev LAPACK routines which compute + the eigenvalues and eigenvectors of general square arrays. + + The number `w` is an eigenvalue of `a` if there exists a vector + `v` such that ``dot(a,v) = w * v``. Thus, the arrays `a`, `w`, and + `v` satisfy the equations ``dot(a[:,:], v[:,i]) = w[i] * v[:,i]`` + for :math:`i \\in \\{0,...,M-1\\}`. + + The array `v` of eigenvectors may not be of maximum rank, that is, some + of the columns may be linearly dependent, although round-off error may + obscure that fact. If the eigenvalues are all different, then theoretically + the eigenvectors are linearly independent. Likewise, the (complex-valued) + matrix of eigenvectors `v` is unitary if the matrix `a` is normal, i.e., + if ``dot(a, a.H) = dot(a.H, a)``, where `a.H` denotes the conjugate + transpose of `a`. + + Finally, it is emphasized that `v` consists of the *right* (as in + right-hand side) eigenvectors of `a`. A vector `y` satisfying + ``dot(y.T, a) = z * y.T`` for some number `z` is called a *left* + eigenvector of `a`, and, in general, the left and right eigenvectors + of a matrix are not necessarily the (perhaps conjugate) transposes + of each other. + + References + ---------- + G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando, FL, + Academic Press, Inc., 1980, Various pp. + + Examples + -------- + >>> from numpy import linalg as LA + + (Almost) trivial example with real e-values and e-vectors. + + >>> w, v = LA.eig(np.diag((1, 2, 3))) + >>> w; v + array([ 1., 2., 3.]) + array([[ 1., 0., 0.], + [ 0., 1., 0.], + [ 0., 0., 1.]]) + + Real matrix possessing complex e-values and e-vectors; note that the + e-values are complex conjugates of each other. + + >>> w, v = LA.eig(np.array([[1, -1], [1, 1]])) + >>> w; v + array([ 1. + 1.j, 1. - 1.j]) + array([[ 0.70710678+0.j , 0.70710678+0.j ], + [ 0.00000000-0.70710678j, 0.00000000+0.70710678j]]) + + Complex-valued matrix with real e-values (but complex-valued e-vectors); + note that a.conj().T = a, i.e., a is Hermitian. + + >>> a = np.array([[1, 1j], [-1j, 1]]) + >>> w, v = LA.eig(a) + >>> w; v + array([ 2.00000000e+00+0.j, 5.98651912e-36+0.j]) # i.e., {2, 0} + array([[ 0.00000000+0.70710678j, 0.70710678+0.j ], + [ 0.70710678+0.j , 0.00000000+0.70710678j]]) + + Be careful about round-off error! + + >>> a = np.array([[1 + 1e-9, 0], [0, 1 - 1e-9]]) + >>> # Theor. e-values are 1 +/- 1e-9 + >>> w, v = LA.eig(a) + >>> w; v + array([ 1., 1.]) + array([[ 1., 0.], + [ 0., 1.]]) + + """ + a, wrap = _makearray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + _assertFinite(a) + t, result_t = _commonType(a) + + extobj = get_linalg_error_extobj( + _raise_linalgerror_eigenvalues_nonconvergence) + signature = 'D->DD' if isComplexType(t) else 'd->DD' + w, vt = _umath_linalg.eig(a, signature=signature, extobj=extobj) + + if not isComplexType(t) and all(w.imag == 0.0): + w = w.real + vt = vt.real + result_t = _realType(result_t) + else: + result_t = _complexType(result_t) + + vt = vt.astype(result_t, copy=False) + return w.astype(result_t, copy=False), wrap(vt) + + +def eigh(a, UPLO='L'): + """ + Return the eigenvalues and eigenvectors of a Hermitian or symmetric matrix. + + Returns two objects, a 1-D array containing the eigenvalues of `a`, and + a 2-D square array or matrix (depending on the input type) of the + corresponding eigenvectors (in columns). + + Parameters + ---------- + a : (..., M, M) array + Hermitian/Symmetric matrices whose eigenvalues and + eigenvectors are to be computed. + UPLO : {'L', 'U'}, optional + Specifies whether the calculation is done with the lower triangular + part of `a` ('L', default) or the upper triangular part ('U'). + Irrespective of this value only the real parts of the diagonal will + be considered in the computation to preserve the notion of a Hermitian + matrix. It therefore follows that the imaginary part of the diagonal + will always be treated as zero. + + Returns + ------- + w : (..., M) ndarray + The eigenvalues in ascending order, each repeated according to + its multiplicity. + v : {(..., M, M) ndarray, (..., M, M) matrix} + The column ``v[:, i]`` is the normalized eigenvector corresponding + to the eigenvalue ``w[i]``. Will return a matrix object if `a` is + a matrix object. + + Raises + ------ + LinAlgError + If the eigenvalue computation does not converge. + + See Also + -------- + eigvalsh : eigenvalues of symmetric or Hermitian arrays. + eig : eigenvalues and right eigenvectors for non-symmetric arrays. + eigvals : eigenvalues of non-symmetric arrays. + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The eigenvalues/eigenvectors are computed using LAPACK routines _syevd, + _heevd + + The eigenvalues of real symmetric or complex Hermitian matrices are + always real. [1]_ The array `v` of (column) eigenvectors is unitary + and `a`, `w`, and `v` satisfy the equations + ``dot(a, v[:, i]) = w[i] * v[:, i]``. + + References + ---------- + .. [1] G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando, + FL, Academic Press, Inc., 1980, pg. 222. + + Examples + -------- + >>> from numpy import linalg as LA + >>> a = np.array([[1, -2j], [2j, 5]]) + >>> a + array([[ 1.+0.j, 0.-2.j], + [ 0.+2.j, 5.+0.j]]) + >>> w, v = LA.eigh(a) + >>> w; v + array([ 0.17157288, 5.82842712]) + array([[-0.92387953+0.j , -0.38268343+0.j ], + [ 0.00000000+0.38268343j, 0.00000000-0.92387953j]]) + + >>> np.dot(a, v[:, 0]) - w[0] * v[:, 0] # verify 1st e-val/vec pair + array([2.77555756e-17 + 0.j, 0. + 1.38777878e-16j]) + >>> np.dot(a, v[:, 1]) - w[1] * v[:, 1] # verify 2nd e-val/vec pair + array([ 0.+0.j, 0.+0.j]) + + >>> A = np.matrix(a) # what happens if input is a matrix object + >>> A + matrix([[ 1.+0.j, 0.-2.j], + [ 0.+2.j, 5.+0.j]]) + >>> w, v = LA.eigh(A) + >>> w; v + array([ 0.17157288, 5.82842712]) + matrix([[-0.92387953+0.j , -0.38268343+0.j ], + [ 0.00000000+0.38268343j, 0.00000000-0.92387953j]]) + + >>> # demonstrate the treatment of the imaginary part of the diagonal + >>> a = np.array([[5+2j, 9-2j], [0+2j, 2-1j]]) + >>> a + array([[ 5.+2.j, 9.-2.j], + [ 0.+2.j, 2.-1.j]]) + >>> # with UPLO='L' this is numerically equivalent to using LA.eig() with: + >>> b = np.array([[5.+0.j, 0.-2.j], [0.+2.j, 2.-0.j]]) + >>> b + array([[ 5.+0.j, 0.-2.j], + [ 0.+2.j, 2.+0.j]]) + >>> wa, va = LA.eigh(a) + >>> wb, vb = LA.eig(b) + >>> wa; wb + array([ 1., 6.]) + array([ 6.+0.j, 1.+0.j]) + >>> va; vb + array([[-0.44721360-0.j , -0.89442719+0.j ], + [ 0.00000000+0.89442719j, 0.00000000-0.4472136j ]]) + array([[ 0.89442719+0.j , 0.00000000-0.4472136j], + [ 0.00000000-0.4472136j, 0.89442719+0.j ]]) + """ + UPLO = UPLO.upper() + if UPLO not in ('L', 'U'): + raise ValueError("UPLO argument must be 'L' or 'U'") + + a, wrap = _makearray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + t, result_t = _commonType(a) + + extobj = get_linalg_error_extobj( + _raise_linalgerror_eigenvalues_nonconvergence) + if UPLO == 'L': + gufunc = _umath_linalg.eigh_lo + else: + gufunc = _umath_linalg.eigh_up + + signature = 'D->dD' if isComplexType(t) else 'd->dd' + w, vt = gufunc(a, signature=signature, extobj=extobj) + w = w.astype(_realType(result_t), copy=False) + vt = vt.astype(result_t, copy=False) + return w, wrap(vt) + + +# Singular value decomposition + +def svd(a, full_matrices=True, compute_uv=True): + """ + Singular Value Decomposition. + + When `a` is a 2D array, it is factorized as ``u @ np.diag(s) @ vh + = (u * s) @ vh``, where `u` and `vh` are 2D unitary arrays and `s` is a 1D + array of `a`'s singular values. When `a` is higher-dimensional, SVD is + applied in stacked mode as explained below. + + Parameters + ---------- + a : (..., M, N) array_like + A real or complex array with ``a.ndim >= 2``. + full_matrices : bool, optional + If True (default), `u` and `vh` have the shapes ``(..., M, M)`` and + ``(..., N, N)``, respectively. Otherwise, the shapes are + ``(..., M, K)`` and ``(..., K, N)``, respectively, where + ``K = min(M, N)``. + compute_uv : bool, optional + Whether or not to compute `u` and `vh` in addition to `s`. True + by default. + + Returns + ------- + u : { (..., M, M), (..., M, K) } array + Unitary array(s). The first ``a.ndim - 2`` dimensions have the same + size as those of the input `a`. The size of the last two dimensions + depends on the value of `full_matrices`. Only returned when + `compute_uv` is True. + s : (..., K) array + Vector(s) with the singular values, within each vector sorted in + descending order. The first ``a.ndim - 2`` dimensions have the same + size as those of the input `a`. + vh : { (..., N, N), (..., K, N) } array + Unitary array(s). The first ``a.ndim - 2`` dimensions have the same + size as those of the input `a`. The size of the last two dimensions + depends on the value of `full_matrices`. Only returned when + `compute_uv` is True. + + Raises + ------ + LinAlgError + If SVD computation does not converge. + + Notes + ----- + + .. versionchanged:: 1.8.0 + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The decomposition is performed using LAPACK routine ``_gesdd``. + + SVD is usually described for the factorization of a 2D matrix :math:`A`. + The higher-dimensional case will be discussed below. In the 2D case, SVD is + written as :math:`A = U S V^H`, where :math:`A = a`, :math:`U= u`, + :math:`S= \\mathtt{np.diag}(s)` and :math:`V^H = vh`. The 1D array `s` + contains the singular values of `a` and `u` and `vh` are unitary. The rows + of `vh` are the eigenvectors of :math:`A^H A` and the columns of `u` are + the eigenvectors of :math:`A A^H`. In both cases the corresponding + (possibly non-zero) eigenvalues are given by ``s**2``. + + If `a` has more than two dimensions, then broadcasting rules apply, as + explained in :ref:`routines.linalg-broadcasting`. This means that SVD is + working in "stacked" mode: it iterates over all indices of the first + ``a.ndim - 2`` dimensions and for each combination SVD is applied to the + last two indices. The matrix `a` can be reconstructed from the + decomposition with either ``(u * s[..., None, :]) @ vh`` or + ``u @ (s[..., None] * vh)``. (The ``@`` operator can be replaced by the + function ``np.matmul`` for python versions below 3.5.) + + If `a` is a ``matrix`` object (as opposed to an ``ndarray``), then so are + all the return values. + + Examples + -------- + >>> a = np.random.randn(9, 6) + 1j*np.random.randn(9, 6) + >>> b = np.random.randn(2, 7, 8, 3) + 1j*np.random.randn(2, 7, 8, 3) + + Reconstruction based on full SVD, 2D case: + + >>> u, s, vh = np.linalg.svd(a, full_matrices=True) + >>> u.shape, s.shape, vh.shape + ((9, 9), (6,), (6, 6)) + >>> np.allclose(a, np.dot(u[:, :6] * s, vh)) + True + >>> smat = np.zeros((9, 6), dtype=complex) + >>> smat[:6, :6] = np.diag(s) + >>> np.allclose(a, np.dot(u, np.dot(smat, vh))) + True + + Reconstruction based on reduced SVD, 2D case: + + >>> u, s, vh = np.linalg.svd(a, full_matrices=False) + >>> u.shape, s.shape, vh.shape + ((9, 6), (6,), (6, 6)) + >>> np.allclose(a, np.dot(u * s, vh)) + True + >>> smat = np.diag(s) + >>> np.allclose(a, np.dot(u, np.dot(smat, vh))) + True + + Reconstruction based on full SVD, 4D case: + + >>> u, s, vh = np.linalg.svd(b, full_matrices=True) + >>> u.shape, s.shape, vh.shape + ((2, 7, 8, 8), (2, 7, 3), (2, 7, 3, 3)) + >>> np.allclose(b, np.matmul(u[..., :3] * s[..., None, :], vh)) + True + >>> np.allclose(b, np.matmul(u[..., :3], s[..., None] * vh)) + True + + Reconstruction based on reduced SVD, 4D case: + + >>> u, s, vh = np.linalg.svd(b, full_matrices=False) + >>> u.shape, s.shape, vh.shape + ((2, 7, 8, 3), (2, 7, 3), (2, 7, 3, 3)) + >>> np.allclose(b, np.matmul(u * s[..., None, :], vh)) + True + >>> np.allclose(b, np.matmul(u, s[..., None] * vh)) + True + + """ + a, wrap = _makearray(a) + _assertNoEmpty2d(a) + _assertRankAtLeast2(a) + t, result_t = _commonType(a) + + extobj = get_linalg_error_extobj(_raise_linalgerror_svd_nonconvergence) + + m = a.shape[-2] + n = a.shape[-1] + if compute_uv: + if full_matrices: + if m < n: + gufunc = _umath_linalg.svd_m_f + else: + gufunc = _umath_linalg.svd_n_f + else: + if m < n: + gufunc = _umath_linalg.svd_m_s + else: + gufunc = _umath_linalg.svd_n_s + + signature = 'D->DdD' if isComplexType(t) else 'd->ddd' + u, s, vh = gufunc(a, signature=signature, extobj=extobj) + u = u.astype(result_t, copy=False) + s = s.astype(_realType(result_t), copy=False) + vh = vh.astype(result_t, copy=False) + return wrap(u), s, wrap(vh) + else: + if m < n: + gufunc = _umath_linalg.svd_m + else: + gufunc = _umath_linalg.svd_n + + signature = 'D->d' if isComplexType(t) else 'd->d' + s = gufunc(a, signature=signature, extobj=extobj) + s = s.astype(_realType(result_t), copy=False) + return s + + +def cond(x, p=None): + """ + Compute the condition number of a matrix. + + This function is capable of returning the condition number using + one of seven different norms, depending on the value of `p` (see + Parameters below). + + Parameters + ---------- + x : (..., M, N) array_like + The matrix whose condition number is sought. + p : {None, 1, -1, 2, -2, inf, -inf, 'fro'}, optional + Order of the norm: + + ===== ============================ + p norm for matrices + ===== ============================ + None 2-norm, computed directly using the ``SVD`` + 'fro' Frobenius norm + inf max(sum(abs(x), axis=1)) + -inf min(sum(abs(x), axis=1)) + 1 max(sum(abs(x), axis=0)) + -1 min(sum(abs(x), axis=0)) + 2 2-norm (largest sing. value) + -2 smallest singular value + ===== ============================ + + inf means the numpy.inf object, and the Frobenius norm is + the root-of-sum-of-squares norm. + + Returns + ------- + c : {float, inf} + The condition number of the matrix. May be infinite. + + See Also + -------- + numpy.linalg.norm + + Notes + ----- + The condition number of `x` is defined as the norm of `x` times the + norm of the inverse of `x` [1]_; the norm can be the usual L2-norm + (root-of-sum-of-squares) or one of a number of other matrix norms. + + References + ---------- + .. [1] G. Strang, *Linear Algebra and Its Applications*, Orlando, FL, + Academic Press, Inc., 1980, pg. 285. + + Examples + -------- + >>> from numpy import linalg as LA + >>> a = np.array([[1, 0, -1], [0, 1, 0], [1, 0, 1]]) + >>> a + array([[ 1, 0, -1], + [ 0, 1, 0], + [ 1, 0, 1]]) + >>> LA.cond(a) + 1.4142135623730951 + >>> LA.cond(a, 'fro') + 3.1622776601683795 + >>> LA.cond(a, np.inf) + 2.0 + >>> LA.cond(a, -np.inf) + 1.0 + >>> LA.cond(a, 1) + 2.0 + >>> LA.cond(a, -1) + 1.0 + >>> LA.cond(a, 2) + 1.4142135623730951 + >>> LA.cond(a, -2) + 0.70710678118654746 + >>> min(LA.svd(a, compute_uv=0))*min(LA.svd(LA.inv(a), compute_uv=0)) + 0.70710678118654746 + + """ + x = asarray(x) # in case we have a matrix + if p is None: + s = svd(x, compute_uv=False) + return s[..., 0]/s[..., -1] + else: + return norm(x, p, axis=(-2, -1)) * norm(inv(x), p, axis=(-2, -1)) + + +def matrix_rank(M, tol=None, hermitian=False): + """ + Return matrix rank of array using SVD method + + Rank of the array is the number of singular values of the array that are + greater than `tol`. + + .. versionchanged:: 1.14 + Can now operate on stacks of matrices + + Parameters + ---------- + M : {(M,), (..., M, N)} array_like + input vector or stack of matrices + tol : (...) array_like, float, optional + threshold below which SVD values are considered zero. If `tol` is + None, and ``S`` is an array with singular values for `M`, and + ``eps`` is the epsilon value for datatype of ``S``, then `tol` is + set to ``S.max() * max(M.shape) * eps``. + + .. versionchanged:: 1.14 + Broadcasted against the stack of matrices + hermitian : bool, optional + If True, `M` is assumed to be Hermitian (symmetric if real-valued), + enabling a more efficient method for finding singular values. + Defaults to False. + + .. versionadded:: 1.14 + + Notes + ----- + The default threshold to detect rank deficiency is a test on the magnitude + of the singular values of `M`. By default, we identify singular values less + than ``S.max() * max(M.shape) * eps`` as indicating rank deficiency (with + the symbols defined above). This is the algorithm MATLAB uses [1]. It also + appears in *Numerical recipes* in the discussion of SVD solutions for linear + least squares [2]. + + This default threshold is designed to detect rank deficiency accounting for + the numerical errors of the SVD computation. Imagine that there is a column + in `M` that is an exact (in floating point) linear combination of other + columns in `M`. Computing the SVD on `M` will not produce a singular value + exactly equal to 0 in general: any difference of the smallest SVD value from + 0 will be caused by numerical imprecision in the calculation of the SVD. + Our threshold for small SVD values takes this numerical imprecision into + account, and the default threshold will detect such numerical rank + deficiency. The threshold may declare a matrix `M` rank deficient even if + the linear combination of some columns of `M` is not exactly equal to + another column of `M` but only numerically very close to another column of + `M`. + + We chose our default threshold because it is in wide use. Other thresholds + are possible. For example, elsewhere in the 2007 edition of *Numerical + recipes* there is an alternative threshold of ``S.max() * + np.finfo(M.dtype).eps / 2. * np.sqrt(m + n + 1.)``. The authors describe + this threshold as being based on "expected roundoff error" (p 71). + + The thresholds above deal with floating point roundoff error in the + calculation of the SVD. However, you may have more information about the + sources of error in `M` that would make you consider other tolerance values + to detect *effective* rank deficiency. The most useful measure of the + tolerance depends on the operations you intend to use on your matrix. For + example, if your data come from uncertain measurements with uncertainties + greater than floating point epsilon, choosing a tolerance near that + uncertainty may be preferable. The tolerance may be absolute if the + uncertainties are absolute rather than relative. + + References + ---------- + .. [1] MATLAB reference documention, "Rank" + http://www.mathworks.com/help/techdoc/ref/rank.html + .. [2] W. H. Press, S. A. Teukolsky, W. T. Vetterling and B. P. Flannery, + "Numerical Recipes (3rd edition)", Cambridge University Press, 2007, + page 795. + + Examples + -------- + >>> from numpy.linalg import matrix_rank + >>> matrix_rank(np.eye(4)) # Full rank matrix + 4 + >>> I=np.eye(4); I[-1,-1] = 0. # rank deficient matrix + >>> matrix_rank(I) + 3 + >>> matrix_rank(np.ones((4,))) # 1 dimension - rank 1 unless all 0 + 1 + >>> matrix_rank(np.zeros((4,))) + 0 + """ + M = asarray(M) + if M.ndim < 2: + return int(not all(M==0)) + if hermitian: + S = abs(eigvalsh(M)) + else: + S = svd(M, compute_uv=False) + if tol is None: + tol = S.max(axis=-1, keepdims=True) * max(M.shape[-2:]) * finfo(S.dtype).eps + else: + tol = asarray(tol)[..., newaxis] + return count_nonzero(S > tol, axis=-1) + + +# Generalized inverse + +def pinv(a, rcond=1e-15 ): + """ + Compute the (Moore-Penrose) pseudo-inverse of a matrix. + + Calculate the generalized inverse of a matrix using its + singular-value decomposition (SVD) and including all + *large* singular values. + + .. versionchanged:: 1.14 + Can now operate on stacks of matrices + + Parameters + ---------- + a : (..., M, N) array_like + Matrix or stack of matrices to be pseudo-inverted. + rcond : (...) array_like of float + Cutoff for small singular values. + Singular values smaller (in modulus) than + `rcond` * largest_singular_value (again, in modulus) + are set to zero. Broadcasts against the stack of matrices + + Returns + ------- + B : (..., N, M) ndarray + The pseudo-inverse of `a`. If `a` is a `matrix` instance, then so + is `B`. + + Raises + ------ + LinAlgError + If the SVD computation does not converge. + + Notes + ----- + The pseudo-inverse of a matrix A, denoted :math:`A^+`, is + defined as: "the matrix that 'solves' [the least-squares problem] + :math:`Ax = b`," i.e., if :math:`\\bar{x}` is said solution, then + :math:`A^+` is that matrix such that :math:`\\bar{x} = A^+b`. + + It can be shown that if :math:`Q_1 \\Sigma Q_2^T = A` is the singular + value decomposition of A, then + :math:`A^+ = Q_2 \\Sigma^+ Q_1^T`, where :math:`Q_{1,2}` are + orthogonal matrices, :math:`\\Sigma` is a diagonal matrix consisting + of A's so-called singular values, (followed, typically, by + zeros), and then :math:`\\Sigma^+` is simply the diagonal matrix + consisting of the reciprocals of A's singular values + (again, followed by zeros). [1]_ + + References + ---------- + .. [1] G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando, + FL, Academic Press, Inc., 1980, pp. 139-142. + + Examples + -------- + The following example checks that ``a * a+ * a == a`` and + ``a+ * a * a+ == a+``: + + >>> a = np.random.randn(9, 6) + >>> B = np.linalg.pinv(a) + >>> np.allclose(a, np.dot(a, np.dot(B, a))) + True + >>> np.allclose(B, np.dot(B, np.dot(a, B))) + True + + """ + a, wrap = _makearray(a) + rcond = asarray(rcond) + if _isEmpty2d(a): + res = empty(a.shape[:-2] + (a.shape[-1], a.shape[-2]), dtype=a.dtype) + return wrap(res) + a = a.conjugate() + u, s, vt = svd(a, full_matrices=False) + + # discard small singular values + cutoff = rcond[..., newaxis] * amax(s, axis=-1, keepdims=True) + large = s > cutoff + s = divide(1, s, where=large, out=s) + s[~large] = 0 + + res = matmul(transpose(vt), multiply(s[..., newaxis], transpose(u))) + return wrap(res) + +# Determinant + +def slogdet(a): + """ + Compute the sign and (natural) logarithm of the determinant of an array. + + If an array has a very small or very large determinant, then a call to + `det` may overflow or underflow. This routine is more robust against such + issues, because it computes the logarithm of the determinant rather than + the determinant itself. + + Parameters + ---------- + a : (..., M, M) array_like + Input array, has to be a square 2-D array. + + Returns + ------- + sign : (...) array_like + A number representing the sign of the determinant. For a real matrix, + this is 1, 0, or -1. For a complex matrix, this is a complex number + with absolute value 1 (i.e., it is on the unit circle), or else 0. + logdet : (...) array_like + The natural log of the absolute value of the determinant. + + If the determinant is zero, then `sign` will be 0 and `logdet` will be + -Inf. In all cases, the determinant is equal to ``sign * np.exp(logdet)``. + + See Also + -------- + det + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + .. versionadded:: 1.6.0 + + The determinant is computed via LU factorization using the LAPACK + routine z/dgetrf. + + + Examples + -------- + The determinant of a 2-D array ``[[a, b], [c, d]]`` is ``ad - bc``: + + >>> a = np.array([[1, 2], [3, 4]]) + >>> (sign, logdet) = np.linalg.slogdet(a) + >>> (sign, logdet) + (-1, 0.69314718055994529) + >>> sign * np.exp(logdet) + -2.0 + + Computing log-determinants for a stack of matrices: + + >>> a = np.array([ [[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]] ]) + >>> a.shape + (3, 2, 2) + >>> sign, logdet = np.linalg.slogdet(a) + >>> (sign, logdet) + (array([-1., -1., -1.]), array([ 0.69314718, 1.09861229, 2.07944154])) + >>> sign * np.exp(logdet) + array([-2., -3., -8.]) + + This routine succeeds where ordinary `det` does not: + + >>> np.linalg.det(np.eye(500) * 0.1) + 0.0 + >>> np.linalg.slogdet(np.eye(500) * 0.1) + (1, -1151.2925464970228) + + """ + a = asarray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + t, result_t = _commonType(a) + real_t = _realType(result_t) + signature = 'D->Dd' if isComplexType(t) else 'd->dd' + sign, logdet = _umath_linalg.slogdet(a, signature=signature) + sign = sign.astype(result_t, copy=False) + logdet = logdet.astype(real_t, copy=False) + return sign, logdet + +def det(a): + """ + Compute the determinant of an array. + + Parameters + ---------- + a : (..., M, M) array_like + Input array to compute determinants for. + + Returns + ------- + det : (...) array_like + Determinant of `a`. + + See Also + -------- + slogdet : Another way to representing the determinant, more suitable + for large matrices where underflow/overflow may occur. + + Notes + ----- + + .. versionadded:: 1.8.0 + + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The determinant is computed via LU factorization using the LAPACK + routine z/dgetrf. + + Examples + -------- + The determinant of a 2-D array [[a, b], [c, d]] is ad - bc: + + >>> a = np.array([[1, 2], [3, 4]]) + >>> np.linalg.det(a) + -2.0 + + Computing determinants for a stack of matrices: + + >>> a = np.array([ [[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]] ]) + >>> a.shape + (3, 2, 2) + >>> np.linalg.det(a) + array([-2., -3., -8.]) + + """ + a = asarray(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + t, result_t = _commonType(a) + signature = 'D->D' if isComplexType(t) else 'd->d' + r = _umath_linalg.det(a, signature=signature) + r = r.astype(result_t, copy=False) + return r + +# Linear Least Squares + +def lstsq(a, b, rcond="warn"): + """ + Return the least-squares solution to a linear matrix equation. + + Solves the equation `a x = b` by computing a vector `x` that + minimizes the Euclidean 2-norm `|| b - a x ||^2`. The equation may + be under-, well-, or over- determined (i.e., the number of + linearly independent rows of `a` can be less than, equal to, or + greater than its number of linearly independent columns). If `a` + is square and of full rank, then `x` (but for round-off error) is + the "exact" solution of the equation. + + Parameters + ---------- + a : (M, N) array_like + "Coefficient" matrix. + b : {(M,), (M, K)} array_like + Ordinate or "dependent variable" values. If `b` is two-dimensional, + the least-squares solution is calculated for each of the `K` columns + of `b`. + rcond : float, optional + Cut-off ratio for small singular values of `a`. + For the purposes of rank determination, singular values are treated + as zero if they are smaller than `rcond` times the largest singular + value of `a`. + + .. versionchanged:: 1.14.0 + If not set, a FutureWarning is given. The previous default + of ``-1`` will use the machine precision as `rcond` parameter, + the new default will use the machine precision times `max(M, N)`. + To silence the warning and use the new default, use ``rcond=None``, + to keep using the old behavior, use ``rcond=-1``. + + Returns + ------- + x : {(N,), (N, K)} ndarray + Least-squares solution. If `b` is two-dimensional, + the solutions are in the `K` columns of `x`. + residuals : {(1,), (K,), (0,)} ndarray + Sums of residuals; squared Euclidean 2-norm for each column in + ``b - a*x``. + If the rank of `a` is < N or M <= N, this is an empty array. + If `b` is 1-dimensional, this is a (1,) shape array. + Otherwise the shape is (K,). + rank : int + Rank of matrix `a`. + s : (min(M, N),) ndarray + Singular values of `a`. + + Raises + ------ + LinAlgError + If computation does not converge. + + Notes + ----- + If `b` is a matrix, then all array results are returned as matrices. + + Examples + -------- + Fit a line, ``y = mx + c``, through some noisy data-points: + + >>> x = np.array([0, 1, 2, 3]) + >>> y = np.array([-1, 0.2, 0.9, 2.1]) + + By examining the coefficients, we see that the line should have a + gradient of roughly 1 and cut the y-axis at, more or less, -1. + + We can rewrite the line equation as ``y = Ap``, where ``A = [[x 1]]`` + and ``p = [[m], [c]]``. Now use `lstsq` to solve for `p`: + + >>> A = np.vstack([x, np.ones(len(x))]).T + >>> A + array([[ 0., 1.], + [ 1., 1.], + [ 2., 1.], + [ 3., 1.]]) + + >>> m, c = np.linalg.lstsq(A, y)[0] + >>> print(m, c) + 1.0 -0.95 + + Plot the data along with the fitted line: + + >>> import matplotlib.pyplot as plt + >>> plt.plot(x, y, 'o', label='Original data', markersize=10) + >>> plt.plot(x, m*x + c, 'r', label='Fitted line') + >>> plt.legend() + >>> plt.show() + + """ + import math + a, _ = _makearray(a) + b, wrap = _makearray(b) + is_1d = b.ndim == 1 + if is_1d: + b = b[:, newaxis] + _assertRank2(a, b) + _assertNoEmpty2d(a, b) # TODO: relax this constraint + m = a.shape[0] + n = a.shape[1] + n_rhs = b.shape[1] + ldb = max(n, m) + if m != b.shape[0]: + raise LinAlgError('Incompatible dimensions') + + t, result_t = _commonType(a, b) + real_t = _linalgRealType(t) + result_real_t = _realType(result_t) + + # Determine default rcond value + if rcond == "warn": + # 2017-08-19, 1.14.0 + warnings.warn("`rcond` parameter will change to the default of " + "machine precision times ``max(M, N)`` where M and N " + "are the input matrix dimensions.\n" + "To use the future default and silence this warning " + "we advise to pass `rcond=None`, to keep using the old, " + "explicitly pass `rcond=-1`.", + FutureWarning, stacklevel=2) + rcond = -1 + if rcond is None: + rcond = finfo(t).eps * ldb + + bstar = zeros((ldb, n_rhs), t) + bstar[:m, :n_rhs] = b + a, bstar = _fastCopyAndTranspose(t, a, bstar) + a, bstar = _to_native_byte_order(a, bstar) + s = zeros((min(m, n),), real_t) + # This line: + # * is incorrect, according to the LAPACK documentation + # * raises a ValueError if min(m,n) == 0 + # * should not be calculated here anyway, as LAPACK should calculate + # `liwork` for us. But that only works if our version of lapack does + # not have this bug: + # http://icl.cs.utk.edu/lapack-forum/archives/lapack/msg00899.html + # Lapack_lite does have that bug... + nlvl = max( 0, int( math.log( float(min(m, n))/2. ) ) + 1 ) + iwork = zeros((3*min(m, n)*nlvl+11*min(m, n),), fortran_int) + if isComplexType(t): + lapack_routine = lapack_lite.zgelsd + lwork = 1 + rwork = zeros((lwork,), real_t) + work = zeros((lwork,), t) + results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond, + 0, work, -1, rwork, iwork, 0) + lrwork = int(rwork[0]) + lwork = int(work[0].real) + work = zeros((lwork,), t) + rwork = zeros((lrwork,), real_t) + results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond, + 0, work, lwork, rwork, iwork, 0) + else: + lapack_routine = lapack_lite.dgelsd + lwork = 1 + work = zeros((lwork,), t) + results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond, + 0, work, -1, iwork, 0) + lwork = int(work[0]) + work = zeros((lwork,), t) + results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond, + 0, work, lwork, iwork, 0) + if results['info'] > 0: + raise LinAlgError('SVD did not converge in Linear Least Squares') + + # undo transpose imposed by fortran-order arrays + b_out = bstar.T + + # b_out contains both the solution and the components of the residuals + x = b_out[:n,:] + r_parts = b_out[n:,:] + if isComplexType(t): + resids = sum(abs(r_parts)**2, axis=-2) + else: + resids = sum(r_parts**2, axis=-2) + + rank = results['rank'] + + # remove the axis we added + if is_1d: + x = x.squeeze(axis=-1) + # we probably should squeeze resids too, but we can't + # without breaking compatibility. + + # as documented + if rank != n or m <= n: + resids = array([], result_real_t) + + # coerce output arrays + s = s.astype(result_real_t, copy=False) + resids = resids.astype(result_real_t, copy=False) + x = x.astype(result_t, copy=True) # Copying lets the memory in r_parts be freed + return wrap(x), wrap(resids), rank, s + + +def _multi_svd_norm(x, row_axis, col_axis, op): + """Compute a function of the singular values of the 2-D matrices in `x`. + + This is a private utility function used by numpy.linalg.norm(). + + Parameters + ---------- + x : ndarray + row_axis, col_axis : int + The axes of `x` that hold the 2-D matrices. + op : callable + This should be either numpy.amin or numpy.amax or numpy.sum. + + Returns + ------- + result : float or ndarray + If `x` is 2-D, the return values is a float. + Otherwise, it is an array with ``x.ndim - 2`` dimensions. + The return values are either the minimum or maximum or sum of the + singular values of the matrices, depending on whether `op` + is `numpy.amin` or `numpy.amax` or `numpy.sum`. + + """ + y = moveaxis(x, (row_axis, col_axis), (-2, -1)) + result = op(svd(y, compute_uv=0), axis=-1) + return result + + +def norm(x, ord=None, axis=None, keepdims=False): + """ + Matrix or vector norm. + + This function is able to return one of eight different matrix norms, + or one of an infinite number of vector norms (described below), depending + on the value of the ``ord`` parameter. + + Parameters + ---------- + x : array_like + Input array. If `axis` is None, `x` must be 1-D or 2-D. + ord : {non-zero int, inf, -inf, 'fro', 'nuc'}, optional + Order of the norm (see table under ``Notes``). inf means numpy's + `inf` object. + axis : {int, 2-tuple of ints, None}, optional + If `axis` is an integer, it specifies the axis of `x` along which to + compute the vector norms. If `axis` is a 2-tuple, it specifies the + axes that hold 2-D matrices, and the matrix norms of these matrices + are computed. If `axis` is None then either a vector norm (when `x` + is 1-D) or a matrix norm (when `x` is 2-D) is returned. + keepdims : bool, optional + If this is set to True, the axes which are normed over are left in the + result as dimensions with size one. With this option the result will + broadcast correctly against the original `x`. + + .. versionadded:: 1.10.0 + + Returns + ------- + n : float or ndarray + Norm of the matrix or vector(s). + + Notes + ----- + For values of ``ord <= 0``, the result is, strictly speaking, not a + mathematical 'norm', but it may still be useful for various numerical + purposes. + + The following norms can be calculated: + + ===== ============================ ========================== + ord norm for matrices norm for vectors + ===== ============================ ========================== + None Frobenius norm 2-norm + 'fro' Frobenius norm -- + 'nuc' nuclear norm -- + inf max(sum(abs(x), axis=1)) max(abs(x)) + -inf min(sum(abs(x), axis=1)) min(abs(x)) + 0 -- sum(x != 0) + 1 max(sum(abs(x), axis=0)) as below + -1 min(sum(abs(x), axis=0)) as below + 2 2-norm (largest sing. value) as below + -2 smallest singular value as below + other -- sum(abs(x)**ord)**(1./ord) + ===== ============================ ========================== + + The Frobenius norm is given by [1]_: + + :math:`||A||_F = [\\sum_{i,j} abs(a_{i,j})^2]^{1/2}` + + The nuclear norm is the sum of the singular values. + + References + ---------- + .. [1] G. H. Golub and C. F. Van Loan, *Matrix Computations*, + Baltimore, MD, Johns Hopkins University Press, 1985, pg. 15 + + Examples + -------- + >>> from numpy import linalg as LA + >>> a = np.arange(9) - 4 + >>> a + array([-4, -3, -2, -1, 0, 1, 2, 3, 4]) + >>> b = a.reshape((3, 3)) + >>> b + array([[-4, -3, -2], + [-1, 0, 1], + [ 2, 3, 4]]) + + >>> LA.norm(a) + 7.745966692414834 + >>> LA.norm(b) + 7.745966692414834 + >>> LA.norm(b, 'fro') + 7.745966692414834 + >>> LA.norm(a, np.inf) + 4.0 + >>> LA.norm(b, np.inf) + 9.0 + >>> LA.norm(a, -np.inf) + 0.0 + >>> LA.norm(b, -np.inf) + 2.0 + + >>> LA.norm(a, 1) + 20.0 + >>> LA.norm(b, 1) + 7.0 + >>> LA.norm(a, -1) + -4.6566128774142013e-010 + >>> LA.norm(b, -1) + 6.0 + >>> LA.norm(a, 2) + 7.745966692414834 + >>> LA.norm(b, 2) + 7.3484692283495345 + + >>> LA.norm(a, -2) + nan + >>> LA.norm(b, -2) + 1.8570331885190563e-016 + >>> LA.norm(a, 3) + 5.8480354764257312 + >>> LA.norm(a, -3) + nan + + Using the `axis` argument to compute vector norms: + + >>> c = np.array([[ 1, 2, 3], + ... [-1, 1, 4]]) + >>> LA.norm(c, axis=0) + array([ 1.41421356, 2.23606798, 5. ]) + >>> LA.norm(c, axis=1) + array([ 3.74165739, 4.24264069]) + >>> LA.norm(c, ord=1, axis=1) + array([ 6., 6.]) + + Using the `axis` argument to compute matrix norms: + + >>> m = np.arange(8).reshape(2,2,2) + >>> LA.norm(m, axis=(1,2)) + array([ 3.74165739, 11.22497216]) + >>> LA.norm(m[0, :, :]), LA.norm(m[1, :, :]) + (3.7416573867739413, 11.224972160321824) + + """ + x = asarray(x) + + if not issubclass(x.dtype.type, (inexact, object_)): + x = x.astype(float) + + # Immediately handle some default, simple, fast, and common cases. + if axis is None: + ndim = x.ndim + if ((ord is None) or + (ord in ('f', 'fro') and ndim == 2) or + (ord == 2 and ndim == 1)): + + x = x.ravel(order='K') + if isComplexType(x.dtype.type): + sqnorm = dot(x.real, x.real) + dot(x.imag, x.imag) + else: + sqnorm = dot(x, x) + ret = sqrt(sqnorm) + if keepdims: + ret = ret.reshape(ndim*[1]) + return ret + + # Normalize the `axis` argument to a tuple. + nd = x.ndim + if axis is None: + axis = tuple(range(nd)) + elif not isinstance(axis, tuple): + try: + axis = int(axis) + except Exception: + raise TypeError("'axis' must be None, an integer or a tuple of integers") + axis = (axis,) + + if len(axis) == 1: + if ord == Inf: + return abs(x).max(axis=axis, keepdims=keepdims) + elif ord == -Inf: + return abs(x).min(axis=axis, keepdims=keepdims) + elif ord == 0: + # Zero norm + return (x != 0).astype(x.real.dtype).sum(axis=axis, keepdims=keepdims) + elif ord == 1: + # special case for speedup + return add.reduce(abs(x), axis=axis, keepdims=keepdims) + elif ord is None or ord == 2: + # special case for speedup + s = (x.conj() * x).real + return sqrt(add.reduce(s, axis=axis, keepdims=keepdims)) + else: + try: + ord + 1 + except TypeError: + raise ValueError("Invalid norm order for vectors.") + absx = abs(x) + absx **= ord + ret = add.reduce(absx, axis=axis, keepdims=keepdims) + ret **= (1 / ord) + return ret + elif len(axis) == 2: + row_axis, col_axis = axis + row_axis = normalize_axis_index(row_axis, nd) + col_axis = normalize_axis_index(col_axis, nd) + if row_axis == col_axis: + raise ValueError('Duplicate axes given.') + if ord == 2: + ret = _multi_svd_norm(x, row_axis, col_axis, amax) + elif ord == -2: + ret = _multi_svd_norm(x, row_axis, col_axis, amin) + elif ord == 1: + if col_axis > row_axis: + col_axis -= 1 + ret = add.reduce(abs(x), axis=row_axis).max(axis=col_axis) + elif ord == Inf: + if row_axis > col_axis: + row_axis -= 1 + ret = add.reduce(abs(x), axis=col_axis).max(axis=row_axis) + elif ord == -1: + if col_axis > row_axis: + col_axis -= 1 + ret = add.reduce(abs(x), axis=row_axis).min(axis=col_axis) + elif ord == -Inf: + if row_axis > col_axis: + row_axis -= 1 + ret = add.reduce(abs(x), axis=col_axis).min(axis=row_axis) + elif ord in [None, 'fro', 'f']: + ret = sqrt(add.reduce((x.conj() * x).real, axis=axis)) + elif ord == 'nuc': + ret = _multi_svd_norm(x, row_axis, col_axis, sum) + else: + raise ValueError("Invalid norm order for matrices.") + if keepdims: + ret_shape = list(x.shape) + ret_shape[axis[0]] = 1 + ret_shape[axis[1]] = 1 + ret = ret.reshape(ret_shape) + return ret + else: + raise ValueError("Improper number of dimensions to norm.") + + +# multi_dot + +def multi_dot(arrays): + """ + Compute the dot product of two or more arrays in a single function call, + while automatically selecting the fastest evaluation order. + + `multi_dot` chains `numpy.dot` and uses optimal parenthesization + of the matrices [1]_ [2]_. Depending on the shapes of the matrices, + this can speed up the multiplication a lot. + + If the first argument is 1-D it is treated as a row vector. + If the last argument is 1-D it is treated as a column vector. + The other arguments must be 2-D. + + Think of `multi_dot` as:: + + def multi_dot(arrays): return functools.reduce(np.dot, arrays) + + + Parameters + ---------- + arrays : sequence of array_like + If the first argument is 1-D it is treated as row vector. + If the last argument is 1-D it is treated as column vector. + The other arguments must be 2-D. + + Returns + ------- + output : ndarray + Returns the dot product of the supplied arrays. + + See Also + -------- + dot : dot multiplication with two arguments. + + References + ---------- + + .. [1] Cormen, "Introduction to Algorithms", Chapter 15.2, p. 370-378 + .. [2] http://en.wikipedia.org/wiki/Matrix_chain_multiplication + + Examples + -------- + `multi_dot` allows you to write:: + + >>> from numpy.linalg import multi_dot + >>> # Prepare some data + >>> A = np.random.random(10000, 100) + >>> B = np.random.random(100, 1000) + >>> C = np.random.random(1000, 5) + >>> D = np.random.random(5, 333) + >>> # the actual dot multiplication + >>> multi_dot([A, B, C, D]) + + instead of:: + + >>> np.dot(np.dot(np.dot(A, B), C), D) + >>> # or + >>> A.dot(B).dot(C).dot(D) + + Notes + ----- + The cost for a matrix multiplication can be calculated with the + following function:: + + def cost(A, B): + return A.shape[0] * A.shape[1] * B.shape[1] + + Let's assume we have three matrices + :math:`A_{10x100}, B_{100x5}, C_{5x50}`. + + The costs for the two different parenthesizations are as follows:: + + cost((AB)C) = 10*100*5 + 10*5*50 = 5000 + 2500 = 7500 + cost(A(BC)) = 10*100*50 + 100*5*50 = 50000 + 25000 = 75000 + + """ + n = len(arrays) + # optimization only makes sense for len(arrays) > 2 + if n < 2: + raise ValueError("Expecting at least two arrays.") + elif n == 2: + return dot(arrays[0], arrays[1]) + + arrays = [asanyarray(a) for a in arrays] + + # save original ndim to reshape the result array into the proper form later + ndim_first, ndim_last = arrays[0].ndim, arrays[-1].ndim + # Explicitly convert vectors to 2D arrays to keep the logic of the internal + # _multi_dot_* functions as simple as possible. + if arrays[0].ndim == 1: + arrays[0] = atleast_2d(arrays[0]) + if arrays[-1].ndim == 1: + arrays[-1] = atleast_2d(arrays[-1]).T + _assertRank2(*arrays) + + # _multi_dot_three is much faster than _multi_dot_matrix_chain_order + if n == 3: + result = _multi_dot_three(arrays[0], arrays[1], arrays[2]) + else: + order = _multi_dot_matrix_chain_order(arrays) + result = _multi_dot(arrays, order, 0, n - 1) + + # return proper shape + if ndim_first == 1 and ndim_last == 1: + return result[0, 0] # scalar + elif ndim_first == 1 or ndim_last == 1: + return result.ravel() # 1-D + else: + return result + + +def _multi_dot_three(A, B, C): + """ + Find the best order for three arrays and do the multiplication. + + For three arguments `_multi_dot_three` is approximately 15 times faster + than `_multi_dot_matrix_chain_order` + + """ + a0, a1b0 = A.shape + b1c0, c1 = C.shape + # cost1 = cost((AB)C) = a0*a1b0*b1c0 + a0*b1c0*c1 + cost1 = a0 * b1c0 * (a1b0 + c1) + # cost2 = cost(A(BC)) = a1b0*b1c0*c1 + a0*a1b0*c1 + cost2 = a1b0 * c1 * (a0 + b1c0) + + if cost1 < cost2: + return dot(dot(A, B), C) + else: + return dot(A, dot(B, C)) + + +def _multi_dot_matrix_chain_order(arrays, return_costs=False): + """ + Return a np.array that encodes the optimal order of mutiplications. + + The optimal order array is then used by `_multi_dot()` to do the + multiplication. + + Also return the cost matrix if `return_costs` is `True` + + The implementation CLOSELY follows Cormen, "Introduction to Algorithms", + Chapter 15.2, p. 370-378. Note that Cormen uses 1-based indices. + + cost[i, j] = min([ + cost[prefix] + cost[suffix] + cost_mult(prefix, suffix) + for k in range(i, j)]) + + """ + n = len(arrays) + # p stores the dimensions of the matrices + # Example for p: A_{10x100}, B_{100x5}, C_{5x50} --> p = [10, 100, 5, 50] + p = [a.shape[0] for a in arrays] + [arrays[-1].shape[1]] + # m is a matrix of costs of the subproblems + # m[i,j]: min number of scalar multiplications needed to compute A_{i..j} + m = zeros((n, n), dtype=double) + # s is the actual ordering + # s[i, j] is the value of k at which we split the product A_i..A_j + s = empty((n, n), dtype=intp) + + for l in range(1, n): + for i in range(n - l): + j = i + l + m[i, j] = Inf + for k in range(i, j): + q = m[i, k] + m[k+1, j] + p[i]*p[k+1]*p[j+1] + if q < m[i, j]: + m[i, j] = q + s[i, j] = k # Note that Cormen uses 1-based index + + return (s, m) if return_costs else s + + +def _multi_dot(arrays, order, i, j): + """Actually do the multiplication with the given order.""" + if i == j: + return arrays[i] + else: + return dot(_multi_dot(arrays, order, i, order[i, j]), + _multi_dot(arrays, order, order[i, j] + 1, j)) diff --git a/numpy/linalg/setup.py b/numpy/linalg/setup.py new file mode 100644 index 0000000..66c07c9 --- /dev/null +++ b/numpy/linalg/setup.py @@ -0,0 +1,60 @@ +from __future__ import division, print_function + +import os +import sys + +def configuration(parent_package='', top_path=None): + from numpy.distutils.misc_util import Configuration + from numpy.distutils.system_info import get_info + config = Configuration('linalg', parent_package, top_path) + + config.add_data_dir('tests') + + # Configure lapack_lite + + src_dir = 'lapack_lite' + lapack_lite_src = [ + os.path.join(src_dir, 'python_xerbla.c'), + os.path.join(src_dir, 'f2c_z_lapack.c'), + os.path.join(src_dir, 'f2c_c_lapack.c'), + os.path.join(src_dir, 'f2c_d_lapack.c'), + os.path.join(src_dir, 'f2c_s_lapack.c'), + os.path.join(src_dir, 'f2c_lapack.c'), + os.path.join(src_dir, 'f2c_blas.c'), + os.path.join(src_dir, 'f2c_config.c'), + os.path.join(src_dir, 'f2c.c'), + ] + all_sources = config.paths(lapack_lite_src) + + lapack_info = get_info('lapack_opt', 0) # and {} + + def get_lapack_lite_sources(ext, build_dir): + if not lapack_info: + print("### Warning: Using unoptimized lapack ###") + return all_sources + else: + if sys.platform == 'win32': + print("### Warning: python_xerbla.c is disabled ###") + return [] + return [all_sources[0]] + + config.add_extension( + 'lapack_lite', + sources=['lapack_litemodule.c', get_lapack_lite_sources], + depends=['lapack_lite/f2c.h'], + extra_info=lapack_info, + ) + + # umath_linalg module + config.add_extension( + '_umath_linalg', + sources=['umath_linalg.c.src', get_lapack_lite_sources], + depends=['lapack_lite/f2c.h'], + extra_info=lapack_info, + libraries=['npymath'], + ) + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/linalg/tests/__init__.py b/numpy/linalg/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/linalg/tests/__init__.py diff --git a/numpy/linalg/tests/test_build.py b/numpy/linalg/tests/test_build.py new file mode 100644 index 0000000..b46a72c --- /dev/null +++ b/numpy/linalg/tests/test_build.py @@ -0,0 +1,57 @@ +from __future__ import division, absolute_import, print_function + +from subprocess import PIPE, Popen +import sys +import re + +from numpy.linalg import lapack_lite +from numpy.testing import run_module_suite, assert_, dec + + +class FindDependenciesLdd(object): + + def __init__(self): + self.cmd = ['ldd'] + + try: + p = Popen(self.cmd, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + except OSError: + raise RuntimeError("command %s cannot be run" % self.cmd) + + def get_dependencies(self, lfile): + p = Popen(self.cmd + [lfile], stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + if not (p.returncode == 0): + raise RuntimeError("failed dependencies check for %s" % lfile) + + return stdout + + def grep_dependencies(self, lfile, deps): + stdout = self.get_dependencies(lfile) + + rdeps = dict([(dep, re.compile(dep)) for dep in deps]) + founds = [] + for l in stdout.splitlines(): + for k, v in rdeps.items(): + if v.search(l): + founds.append(k) + + return founds + + +class TestF77Mismatch(object): + + @dec.skipif(not(sys.platform[:5] == 'linux'), + "Skipping fortran compiler mismatch on non Linux platform") + def test_lapack(self): + f = FindDependenciesLdd() + deps = f.grep_dependencies(lapack_lite.__file__, + [b'libg2c', b'libgfortran']) + assert_(len(deps) <= 1, + """Both g77 and gfortran runtimes linked in lapack_lite ! This is likely to +cause random crashes and wrong results. See numpy INSTALL.txt for more +information.""") + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/linalg/tests/test_deprecations.py b/numpy/linalg/tests/test_deprecations.py new file mode 100644 index 0000000..9b6fe34 --- /dev/null +++ b/numpy/linalg/tests/test_deprecations.py @@ -0,0 +1,26 @@ +"""Test deprecation and future warnings. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import assert_warns, run_module_suite + + +def test_qr_mode_full_future_warning(): + """Check mode='full' FutureWarning. + + In numpy 1.8 the mode options 'full' and 'economic' in linalg.qr were + deprecated. The release date will probably be sometime in the summer + of 2013. + + """ + a = np.eye(2) + assert_warns(DeprecationWarning, np.linalg.qr, a, mode='full') + assert_warns(DeprecationWarning, np.linalg.qr, a, mode='f') + assert_warns(DeprecationWarning, np.linalg.qr, a, mode='economic') + assert_warns(DeprecationWarning, np.linalg.qr, a, mode='e') + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/linalg/tests/test_linalg.py b/numpy/linalg/tests/test_linalg.py new file mode 100644 index 0000000..0a6566b --- /dev/null +++ b/numpy/linalg/tests/test_linalg.py @@ -0,0 +1,1722 @@ +""" Test functions for linalg module + +""" +from __future__ import division, absolute_import, print_function + +import os +import sys +import itertools +import traceback +import warnings + +import numpy as np +from numpy import array, single, double, csingle, cdouble, dot, identity +from numpy import multiply, atleast_2d, inf, asarray, matrix +from numpy import linalg +from numpy.linalg import matrix_power, norm, matrix_rank, multi_dot, LinAlgError +from numpy.linalg.linalg import _multi_dot_matrix_chain_order +from numpy.testing import ( + assert_, assert_equal, assert_raises, assert_array_equal, + assert_almost_equal, assert_allclose, run_module_suite, + dec, SkipTest, suppress_warnings +) + + +def ifthen(a, b): + return not a or b + + +def imply(a, b): + return not a or b + + +old_assert_almost_equal = assert_almost_equal + + +def assert_almost_equal(a, b, single_decimal=6, double_decimal=12, **kw): + if asarray(a).dtype.type in (single, csingle): + decimal = single_decimal + else: + decimal = double_decimal + old_assert_almost_equal(a, b, decimal=decimal, **kw) + + +def get_real_dtype(dtype): + return {single: single, double: double, + csingle: single, cdouble: double}[dtype] + + +def get_complex_dtype(dtype): + return {single: csingle, double: cdouble, + csingle: csingle, cdouble: cdouble}[dtype] + + +def get_rtol(dtype): + # Choose a safe rtol + if dtype in (single, csingle): + return 1e-5 + else: + return 1e-11 + + +# used to categorize tests +all_tags = { + 'square', 'nonsquare', 'hermitian', # mutually exclusive + 'generalized', 'size-0', 'strided' # optional additions +} + +class LinalgCase(object): + def __init__(self, name, a, b, tags=set()): + """ + A bundle of arguments to be passed to a test case, with an identifying + name, the operands a and b, and a set of tags to filter the tests + """ + assert_(isinstance(name, str)) + self.name = name + self.a = a + self.b = b + self.tags = frozenset(tags) # prevent shared tags + + def check(self, do): + """ + Run the function `do` on this test case, expanding arguments + """ + do(self.a, self.b, tags=self.tags) + + def __repr__(self): + return "" % (self.name,) + +def apply_tag(tag, cases): + """ + Add the given tag (a string) to each of the cases (a list of LinalgCase + objects) + """ + assert tag in all_tags, "Invalid tag" + for case in cases: + case.tags = case.tags | {tag} + return cases + + +# +# Base test cases +# + +np.random.seed(1234) + +CASES = [] + +# square test cases +CASES += apply_tag('square', [ + LinalgCase("single", + array([[1., 2.], [3., 4.]], dtype=single), + array([2., 1.], dtype=single)), + LinalgCase("double", + array([[1., 2.], [3., 4.]], dtype=double), + array([2., 1.], dtype=double)), + LinalgCase("double_2", + array([[1., 2.], [3., 4.]], dtype=double), + array([[2., 1., 4.], [3., 4., 6.]], dtype=double)), + LinalgCase("csingle", + array([[1. + 2j, 2 + 3j], [3 + 4j, 4 + 5j]], dtype=csingle), + array([2. + 1j, 1. + 2j], dtype=csingle)), + LinalgCase("cdouble", + array([[1. + 2j, 2 + 3j], [3 + 4j, 4 + 5j]], dtype=cdouble), + array([2. + 1j, 1. + 2j], dtype=cdouble)), + LinalgCase("cdouble_2", + array([[1. + 2j, 2 + 3j], [3 + 4j, 4 + 5j]], dtype=cdouble), + array([[2. + 1j, 1. + 2j, 1 + 3j], [1 - 2j, 1 - 3j, 1 - 6j]], dtype=cdouble)), + LinalgCase("0x0", + np.empty((0, 0), dtype=double), + np.empty((0,), dtype=double), + tags={'size-0'}), + LinalgCase("0x0_matrix", + np.empty((0, 0), dtype=double).view(np.matrix), + np.empty((0, 1), dtype=double).view(np.matrix), + tags={'size-0'}), + LinalgCase("8x8", + np.random.rand(8, 8), + np.random.rand(8)), + LinalgCase("1x1", + np.random.rand(1, 1), + np.random.rand(1)), + LinalgCase("nonarray", + [[1, 2], [3, 4]], + [2, 1]), + LinalgCase("matrix_b_only", + array([[1., 2.], [3., 4.]]), + matrix([2., 1.]).T), + LinalgCase("matrix_a_and_b", + matrix([[1., 2.], [3., 4.]]), + matrix([2., 1.]).T), +]) + +# non-square test-cases +CASES += apply_tag('nonsquare', [ + LinalgCase("single_nsq_1", + array([[1., 2., 3.], [3., 4., 6.]], dtype=single), + array([2., 1.], dtype=single)), + LinalgCase("single_nsq_2", + array([[1., 2.], [3., 4.], [5., 6.]], dtype=single), + array([2., 1., 3.], dtype=single)), + LinalgCase("double_nsq_1", + array([[1., 2., 3.], [3., 4., 6.]], dtype=double), + array([2., 1.], dtype=double)), + LinalgCase("double_nsq_2", + array([[1., 2.], [3., 4.], [5., 6.]], dtype=double), + array([2., 1., 3.], dtype=double)), + LinalgCase("csingle_nsq_1", + array( + [[1. + 1j, 2. + 2j, 3. - 3j], [3. - 5j, 4. + 9j, 6. + 2j]], dtype=csingle), + array([2. + 1j, 1. + 2j], dtype=csingle)), + LinalgCase("csingle_nsq_2", + array( + [[1. + 1j, 2. + 2j], [3. - 3j, 4. - 9j], [5. - 4j, 6. + 8j]], dtype=csingle), + array([2. + 1j, 1. + 2j, 3. - 3j], dtype=csingle)), + LinalgCase("cdouble_nsq_1", + array( + [[1. + 1j, 2. + 2j, 3. - 3j], [3. - 5j, 4. + 9j, 6. + 2j]], dtype=cdouble), + array([2. + 1j, 1. + 2j], dtype=cdouble)), + LinalgCase("cdouble_nsq_2", + array( + [[1. + 1j, 2. + 2j], [3. - 3j, 4. - 9j], [5. - 4j, 6. + 8j]], dtype=cdouble), + array([2. + 1j, 1. + 2j, 3. - 3j], dtype=cdouble)), + LinalgCase("cdouble_nsq_1_2", + array( + [[1. + 1j, 2. + 2j, 3. - 3j], [3. - 5j, 4. + 9j, 6. + 2j]], dtype=cdouble), + array([[2. + 1j, 1. + 2j], [1 - 1j, 2 - 2j]], dtype=cdouble)), + LinalgCase("cdouble_nsq_2_2", + array( + [[1. + 1j, 2. + 2j], [3. - 3j, 4. - 9j], [5. - 4j, 6. + 8j]], dtype=cdouble), + array([[2. + 1j, 1. + 2j], [1 - 1j, 2 - 2j], [1 - 1j, 2 - 2j]], dtype=cdouble)), + LinalgCase("8x11", + np.random.rand(8, 11), + np.random.rand(8)), + LinalgCase("1x5", + np.random.rand(1, 5), + np.random.rand(1)), + LinalgCase("5x1", + np.random.rand(5, 1), + np.random.rand(5)), + LinalgCase("0x4", + np.random.rand(0, 4), + np.random.rand(0), + tags={'size-0'}), + LinalgCase("4x0", + np.random.rand(4, 0), + np.random.rand(4), + tags={'size-0'}), +]) + +# hermitian test-cases +CASES += apply_tag('hermitian', [ + LinalgCase("hsingle", + array([[1., 2.], [2., 1.]], dtype=single), + None), + LinalgCase("hdouble", + array([[1., 2.], [2., 1.]], dtype=double), + None), + LinalgCase("hcsingle", + array([[1., 2 + 3j], [2 - 3j, 1]], dtype=csingle), + None), + LinalgCase("hcdouble", + array([[1., 2 + 3j], [2 - 3j, 1]], dtype=cdouble), + None), + LinalgCase("hempty", + np.empty((0, 0), dtype=double), + None, + tags={'size-0'}), + LinalgCase("hnonarray", + [[1, 2], [2, 1]], + None), + LinalgCase("matrix_b_only", + array([[1., 2.], [2., 1.]]), + None), + LinalgCase("hmatrix_a_and_b", + matrix([[1., 2.], [2., 1.]]), + None), + LinalgCase("hmatrix_1x1", + np.random.rand(1, 1), + None), +]) + + +# +# Gufunc test cases +# +def _make_generalized_cases(): + new_cases = [] + + for case in CASES: + if not isinstance(case.a, np.ndarray): + continue + + a = np.array([case.a, 2 * case.a, 3 * case.a]) + if case.b is None: + b = None + else: + b = np.array([case.b, 7 * case.b, 6 * case.b]) + new_case = LinalgCase(case.name + "_tile3", a, b, + tags=case.tags | {'generalized'}) + new_cases.append(new_case) + + a = np.array([case.a] * 2 * 3).reshape((3, 2) + case.a.shape) + if case.b is None: + b = None + else: + b = np.array([case.b] * 2 * 3).reshape((3, 2) + case.b.shape) + new_case = LinalgCase(case.name + "_tile213", a, b, + tags=case.tags | {'generalized'}) + new_cases.append(new_case) + + return new_cases + +CASES += _make_generalized_cases() + +# +# Generate stride combination variations of the above +# + +def _stride_comb_iter(x): + """ + Generate cartesian product of strides for all axes + """ + + if not isinstance(x, np.ndarray): + yield x, "nop" + return + + stride_set = [(1,)] * x.ndim + stride_set[-1] = (1, 3, -4) + if x.ndim > 1: + stride_set[-2] = (1, 3, -4) + if x.ndim > 2: + stride_set[-3] = (1, -4) + + for repeats in itertools.product(*tuple(stride_set)): + new_shape = [abs(a * b) for a, b in zip(x.shape, repeats)] + slices = tuple([slice(None, None, repeat) for repeat in repeats]) + + # new array with different strides, but same data + xi = np.empty(new_shape, dtype=x.dtype) + xi.view(np.uint32).fill(0xdeadbeef) + xi = xi[slices] + xi[...] = x + xi = xi.view(x.__class__) + assert_(np.all(xi == x)) + yield xi, "stride_" + "_".join(["%+d" % j for j in repeats]) + + # generate also zero strides if possible + if x.ndim >= 1 and x.shape[-1] == 1: + s = list(x.strides) + s[-1] = 0 + xi = np.lib.stride_tricks.as_strided(x, strides=s) + yield xi, "stride_xxx_0" + if x.ndim >= 2 and x.shape[-2] == 1: + s = list(x.strides) + s[-2] = 0 + xi = np.lib.stride_tricks.as_strided(x, strides=s) + yield xi, "stride_xxx_0_x" + if x.ndim >= 2 and x.shape[:-2] == (1, 1): + s = list(x.strides) + s[-1] = 0 + s[-2] = 0 + xi = np.lib.stride_tricks.as_strided(x, strides=s) + yield xi, "stride_xxx_0_0" + +def _make_strided_cases(): + new_cases = [] + for case in CASES: + for a, a_label in _stride_comb_iter(case.a): + for b, b_label in _stride_comb_iter(case.b): + new_case = LinalgCase(case.name + "_" + a_label + "_" + b_label, a, b, + tags=case.tags | {'strided'}) + new_cases.append(new_case) + return new_cases + +CASES += _make_strided_cases() + + +# +# Test different routines against the above cases +# + +def _check_cases(func, require=set(), exclude=set()): + """ + Run func on each of the cases with all of the tags in require, and none + of the tags in exclude + """ + for case in CASES: + # filter by require and exclude + if case.tags & require != require: + continue + if case.tags & exclude: + continue + + try: + case.check(func) + except Exception: + msg = "In test case: %r\n\n" % case + msg += traceback.format_exc() + raise AssertionError(msg) + + +class LinalgSquareTestCase(object): + + def test_sq_cases(self): + _check_cases(self.do, require={'square'}, exclude={'generalized', 'size-0'}) + + def test_empty_sq_cases(self): + _check_cases(self.do, require={'square', 'size-0'}, exclude={'generalized'}) + + +class LinalgNonsquareTestCase(object): + + def test_nonsq_cases(self): + _check_cases(self.do, require={'nonsquare'}, exclude={'generalized', 'size-0'}) + + def test_empty_nonsq_cases(self): + _check_cases(self.do, require={'nonsquare', 'size-0'}, exclude={'generalized'}) + +class HermitianTestCase(object): + + def test_herm_cases(self): + _check_cases(self.do, require={'hermitian'}, exclude={'generalized', 'size-0'}) + + def test_empty_herm_cases(self): + _check_cases(self.do, require={'hermitian', 'size-0'}, exclude={'generalized'}) + + +class LinalgGeneralizedSquareTestCase(object): + + @dec.slow + def test_generalized_sq_cases(self): + _check_cases(self.do, require={'generalized', 'square'}, exclude={'size-0'}) + + @dec.slow + def test_generalized_empty_sq_cases(self): + _check_cases(self.do, require={'generalized', 'square', 'size-0'}) + + +class LinalgGeneralizedNonsquareTestCase(object): + + @dec.slow + def test_generalized_nonsq_cases(self): + _check_cases(self.do, require={'generalized', 'nonsquare'}, exclude={'size-0'}) + + @dec.slow + def test_generalized_empty_nonsq_cases(self): + _check_cases(self.do, require={'generalized', 'nonsquare', 'size-0'}) + + +class HermitianGeneralizedTestCase(object): + + @dec.slow + def test_generalized_herm_cases(self): + _check_cases(self.do, + require={'generalized', 'hermitian'}, + exclude={'size-0'}) + + @dec.slow + def test_generalized_empty_herm_cases(self): + _check_cases(self.do, + require={'generalized', 'hermitian', 'size-0'}, + exclude={'none'}) + + +def dot_generalized(a, b): + a = asarray(a) + if a.ndim >= 3: + if a.ndim == b.ndim: + # matrix x matrix + new_shape = a.shape[:-1] + b.shape[-1:] + elif a.ndim == b.ndim + 1: + # matrix x vector + new_shape = a.shape[:-1] + else: + raise ValueError("Not implemented...") + r = np.empty(new_shape, dtype=np.common_type(a, b)) + for c in itertools.product(*map(range, a.shape[:-2])): + r[c] = dot(a[c], b[c]) + return r + else: + return dot(a, b) + + +def identity_like_generalized(a): + a = asarray(a) + if a.ndim >= 3: + r = np.empty(a.shape, dtype=a.dtype) + for c in itertools.product(*map(range, a.shape[:-2])): + r[c] = identity(a.shape[-2]) + return r + else: + return identity(a.shape[0]) + + +class TestSolve(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase): + + def do(self, a, b, tags): + x = linalg.solve(a, b) + assert_almost_equal(b, dot_generalized(a, x)) + assert_(imply(isinstance(b, matrix), isinstance(x, matrix))) + + def test_types(self): + def check(dtype): + x = np.array([[1, 0.5], [0.5, 1]], dtype=dtype) + assert_equal(linalg.solve(x, x).dtype, dtype) + for dtype in [single, double, csingle, cdouble]: + yield check, dtype + + def test_0_size(self): + class ArraySubclass(np.ndarray): + pass + # Test system of 0x0 matrices + a = np.arange(8).reshape(2, 2, 2) + b = np.arange(6).reshape(1, 2, 3).view(ArraySubclass) + + expected = linalg.solve(a, b)[:, 0:0, :] + result = linalg.solve(a[:, 0:0, 0:0], b[:, 0:0, :]) + assert_array_equal(result, expected) + assert_(isinstance(result, ArraySubclass)) + + # Test errors for non-square and only b's dimension being 0 + assert_raises(linalg.LinAlgError, linalg.solve, a[:, 0:0, 0:1], b) + assert_raises(ValueError, linalg.solve, a, b[:, 0:0, :]) + + # Test broadcasting error + b = np.arange(6).reshape(1, 3, 2) # broadcasting error + assert_raises(ValueError, linalg.solve, a, b) + assert_raises(ValueError, linalg.solve, a[0:0], b[0:0]) + + # Test zero "single equations" with 0x0 matrices. + b = np.arange(2).reshape(1, 2).view(ArraySubclass) + expected = linalg.solve(a, b)[:, 0:0] + result = linalg.solve(a[:, 0:0, 0:0], b[:, 0:0]) + assert_array_equal(result, expected) + assert_(isinstance(result, ArraySubclass)) + + b = np.arange(3).reshape(1, 3) + assert_raises(ValueError, linalg.solve, a, b) + assert_raises(ValueError, linalg.solve, a[0:0], b[0:0]) + assert_raises(ValueError, linalg.solve, a[:, 0:0, 0:0], b) + + def test_0_size_k(self): + # test zero multiple equation (K=0) case. + class ArraySubclass(np.ndarray): + pass + a = np.arange(4).reshape(1, 2, 2) + b = np.arange(6).reshape(3, 2, 1).view(ArraySubclass) + + expected = linalg.solve(a, b)[:, :, 0:0] + result = linalg.solve(a, b[:, :, 0:0]) + assert_array_equal(result, expected) + assert_(isinstance(result, ArraySubclass)) + + # test both zero. + expected = linalg.solve(a, b)[:, 0:0, 0:0] + result = linalg.solve(a[:, 0:0, 0:0], b[:, 0:0, 0:0]) + assert_array_equal(result, expected) + assert_(isinstance(result, ArraySubclass)) + + +class TestInv(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase): + + def do(self, a, b, tags): + a_inv = linalg.inv(a) + assert_almost_equal(dot_generalized(a, a_inv), + identity_like_generalized(a)) + assert_(imply(isinstance(a, matrix), isinstance(a_inv, matrix))) + + def test_types(self): + def check(dtype): + x = np.array([[1, 0.5], [0.5, 1]], dtype=dtype) + assert_equal(linalg.inv(x).dtype, dtype) + for dtype in [single, double, csingle, cdouble]: + yield check, dtype + + def test_0_size(self): + # Check that all kinds of 0-sized arrays work + class ArraySubclass(np.ndarray): + pass + a = np.zeros((0, 1, 1), dtype=np.int_).view(ArraySubclass) + res = linalg.inv(a) + assert_(res.dtype.type is np.float64) + assert_equal(a.shape, res.shape) + assert_(isinstance(res, ArraySubclass)) + + a = np.zeros((0, 0), dtype=np.complex64).view(ArraySubclass) + res = linalg.inv(a) + assert_(res.dtype.type is np.complex64) + assert_equal(a.shape, res.shape) + assert_(isinstance(res, ArraySubclass)) + + +class TestEigvals(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase): + + def do(self, a, b, tags): + ev = linalg.eigvals(a) + evalues, evectors = linalg.eig(a) + assert_almost_equal(ev, evalues) + + def test_types(self): + def check(dtype): + x = np.array([[1, 0.5], [0.5, 1]], dtype=dtype) + assert_equal(linalg.eigvals(x).dtype, dtype) + x = np.array([[1, 0.5], [-1, 1]], dtype=dtype) + assert_equal(linalg.eigvals(x).dtype, get_complex_dtype(dtype)) + for dtype in [single, double, csingle, cdouble]: + yield check, dtype + + def test_0_size(self): + # Check that all kinds of 0-sized arrays work + class ArraySubclass(np.ndarray): + pass + a = np.zeros((0, 1, 1), dtype=np.int_).view(ArraySubclass) + res = linalg.eigvals(a) + assert_(res.dtype.type is np.float64) + assert_equal((0, 1), res.shape) + # This is just for documentation, it might make sense to change: + assert_(isinstance(res, np.ndarray)) + + a = np.zeros((0, 0), dtype=np.complex64).view(ArraySubclass) + res = linalg.eigvals(a) + assert_(res.dtype.type is np.complex64) + assert_equal((0,), res.shape) + # This is just for documentation, it might make sense to change: + assert_(isinstance(res, np.ndarray)) + + +class TestEig(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase): + + def do(self, a, b, tags): + evalues, evectors = linalg.eig(a) + assert_allclose(dot_generalized(a, evectors), + np.asarray(evectors) * np.asarray(evalues)[..., None, :], + rtol=get_rtol(evalues.dtype)) + assert_(imply(isinstance(a, matrix), isinstance(evectors, matrix))) + + def test_types(self): + def check(dtype): + x = np.array([[1, 0.5], [0.5, 1]], dtype=dtype) + w, v = np.linalg.eig(x) + assert_equal(w.dtype, dtype) + assert_equal(v.dtype, dtype) + + x = np.array([[1, 0.5], [-1, 1]], dtype=dtype) + w, v = np.linalg.eig(x) + assert_equal(w.dtype, get_complex_dtype(dtype)) + assert_equal(v.dtype, get_complex_dtype(dtype)) + + for dtype in [single, double, csingle, cdouble]: + yield check, dtype + + def test_0_size(self): + # Check that all kinds of 0-sized arrays work + class ArraySubclass(np.ndarray): + pass + a = np.zeros((0, 1, 1), dtype=np.int_).view(ArraySubclass) + res, res_v = linalg.eig(a) + assert_(res_v.dtype.type is np.float64) + assert_(res.dtype.type is np.float64) + assert_equal(a.shape, res_v.shape) + assert_equal((0, 1), res.shape) + # This is just for documentation, it might make sense to change: + assert_(isinstance(a, np.ndarray)) + + a = np.zeros((0, 0), dtype=np.complex64).view(ArraySubclass) + res, res_v = linalg.eig(a) + assert_(res_v.dtype.type is np.complex64) + assert_(res.dtype.type is np.complex64) + assert_equal(a.shape, res_v.shape) + assert_equal((0,), res.shape) + # This is just for documentation, it might make sense to change: + assert_(isinstance(a, np.ndarray)) + + +class TestSVD(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase): + + def do(self, a, b, tags): + if 'size-0' in tags: + assert_raises(LinAlgError, linalg.svd, a, 0) + return + + u, s, vt = linalg.svd(a, 0) + assert_allclose(a, dot_generalized(np.asarray(u) * np.asarray(s)[..., None, :], + np.asarray(vt)), + rtol=get_rtol(u.dtype)) + assert_(imply(isinstance(a, matrix), isinstance(u, matrix))) + assert_(imply(isinstance(a, matrix), isinstance(vt, matrix))) + + def test_types(self): + def check(dtype): + x = np.array([[1, 0.5], [0.5, 1]], dtype=dtype) + u, s, vh = linalg.svd(x) + assert_equal(u.dtype, dtype) + assert_equal(s.dtype, get_real_dtype(dtype)) + assert_equal(vh.dtype, dtype) + s = linalg.svd(x, compute_uv=False) + assert_equal(s.dtype, get_real_dtype(dtype)) + + for dtype in [single, double, csingle, cdouble]: + yield check, dtype + + def test_0_size(self): + # These raise errors currently + # (which does not mean that it may not make sense) + a = np.zeros((0, 0), dtype=np.complex64) + assert_raises(linalg.LinAlgError, linalg.svd, a) + a = np.zeros((0, 1), dtype=np.complex64) + assert_raises(linalg.LinAlgError, linalg.svd, a) + a = np.zeros((1, 0), dtype=np.complex64) + assert_raises(linalg.LinAlgError, linalg.svd, a) + + +class TestCondSVD(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase): + + def do(self, a, b, tags): + c = asarray(a) # a might be a matrix + if 'size-0' in tags: + assert_raises(LinAlgError, linalg.svd, c, compute_uv=False) + return + s = linalg.svd(c, compute_uv=False) + assert_almost_equal( + s[..., 0] / s[..., -1], linalg.cond(a), + single_decimal=5, double_decimal=11) + + def test_stacked_arrays_explicitly(self): + A = np.array([[1., 2., 1.], [0, -2., 0], [6., 2., 3.]]) + assert_equal(linalg.cond(A), linalg.cond(A[None, ...])[0]) + + +class TestCond2(LinalgSquareTestCase): + + def do(self, a, b, tags): + c = asarray(a) # a might be a matrix + if 'size-0' in tags: + assert_raises(LinAlgError, linalg.svd, c, compute_uv=False) + return + s = linalg.svd(c, compute_uv=False) + assert_almost_equal( + s[..., 0] / s[..., -1], linalg.cond(a, 2), + single_decimal=5, double_decimal=11) + + def test_stacked_arrays_explicitly(self): + A = np.array([[1., 2., 1.], [0, -2., 0], [6., 2., 3.]]) + assert_equal(linalg.cond(A, 2), linalg.cond(A[None, ...], 2)[0]) + + +class TestCondInf(object): + + def test(self): + A = array([[1., 0, 0], [0, -2., 0], [0, 0, 3.]]) + assert_almost_equal(linalg.cond(A, inf), 3.) + + +class TestPinv(LinalgSquareTestCase, + LinalgNonsquareTestCase, + LinalgGeneralizedSquareTestCase, + LinalgGeneralizedNonsquareTestCase): + + def do(self, a, b, tags): + a_ginv = linalg.pinv(a) + # `a @ a_ginv == I` does not hold if a is singular + dot = dot_generalized + assert_almost_equal(dot(dot(a, a_ginv), a), a, single_decimal=5, double_decimal=11) + assert_(imply(isinstance(a, matrix), isinstance(a_ginv, matrix))) + + +class TestDet(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase): + + def do(self, a, b, tags): + d = linalg.det(a) + (s, ld) = linalg.slogdet(a) + if asarray(a).dtype.type in (single, double): + ad = asarray(a).astype(double) + else: + ad = asarray(a).astype(cdouble) + ev = linalg.eigvals(ad) + assert_almost_equal(d, multiply.reduce(ev, axis=-1)) + assert_almost_equal(s * np.exp(ld), multiply.reduce(ev, axis=-1)) + + s = np.atleast_1d(s) + ld = np.atleast_1d(ld) + m = (s != 0) + assert_almost_equal(np.abs(s[m]), 1) + assert_equal(ld[~m], -inf) + + def test_zero(self): + assert_equal(linalg.det([[0.0]]), 0.0) + assert_equal(type(linalg.det([[0.0]])), double) + assert_equal(linalg.det([[0.0j]]), 0.0) + assert_equal(type(linalg.det([[0.0j]])), cdouble) + + assert_equal(linalg.slogdet([[0.0]]), (0.0, -inf)) + assert_equal(type(linalg.slogdet([[0.0]])[0]), double) + assert_equal(type(linalg.slogdet([[0.0]])[1]), double) + assert_equal(linalg.slogdet([[0.0j]]), (0.0j, -inf)) + assert_equal(type(linalg.slogdet([[0.0j]])[0]), cdouble) + assert_equal(type(linalg.slogdet([[0.0j]])[1]), double) + + def test_types(self): + def check(dtype): + x = np.array([[1, 0.5], [0.5, 1]], dtype=dtype) + assert_equal(np.linalg.det(x).dtype, dtype) + ph, s = np.linalg.slogdet(x) + assert_equal(s.dtype, get_real_dtype(dtype)) + assert_equal(ph.dtype, dtype) + for dtype in [single, double, csingle, cdouble]: + yield check, dtype + + def test_0_size(self): + a = np.zeros((0, 0), dtype=np.complex64) + res = linalg.det(a) + assert_equal(res, 1.) + assert_(res.dtype.type is np.complex64) + res = linalg.slogdet(a) + assert_equal(res, (1, 0)) + assert_(res[0].dtype.type is np.complex64) + assert_(res[1].dtype.type is np.float32) + + a = np.zeros((0, 0), dtype=np.float64) + res = linalg.det(a) + assert_equal(res, 1.) + assert_(res.dtype.type is np.float64) + res = linalg.slogdet(a) + assert_equal(res, (1, 0)) + assert_(res[0].dtype.type is np.float64) + assert_(res[1].dtype.type is np.float64) + + +class TestLstsq(LinalgSquareTestCase, LinalgNonsquareTestCase): + + def do(self, a, b, tags): + if 'size-0' in tags: + assert_raises(LinAlgError, linalg.lstsq, a, b) + return + + arr = np.asarray(a) + m, n = arr.shape + u, s, vt = linalg.svd(a, 0) + x, residuals, rank, sv = linalg.lstsq(a, b, rcond=-1) + if m <= n: + assert_almost_equal(b, dot(a, x)) + assert_equal(rank, m) + else: + assert_equal(rank, n) + assert_almost_equal(sv, sv.__array_wrap__(s)) + if rank == n and m > n: + expect_resids = ( + np.asarray(abs(np.dot(a, x) - b)) ** 2).sum(axis=0) + expect_resids = np.asarray(expect_resids) + if np.asarray(b).ndim == 1: + expect_resids.shape = (1,) + assert_equal(residuals.shape, expect_resids.shape) + else: + expect_resids = np.array([]).view(type(x)) + assert_almost_equal(residuals, expect_resids) + assert_(np.issubdtype(residuals.dtype, np.floating)) + assert_(imply(isinstance(b, matrix), isinstance(x, matrix))) + assert_(imply(isinstance(b, matrix), isinstance(residuals, matrix))) + + def test_future_rcond(self): + a = np.array([[0., 1., 0., 1., 2., 0.], + [0., 2., 0., 0., 1., 0.], + [1., 0., 1., 0., 0., 4.], + [0., 0., 0., 2., 3., 0.]]).T + + b = np.array([1, 0, 0, 0, 0, 0]) + with suppress_warnings() as sup: + w = sup.record(FutureWarning, "`rcond` parameter will change") + x, residuals, rank, s = linalg.lstsq(a, b) + assert_(rank == 4) + x, residuals, rank, s = linalg.lstsq(a, b, rcond=-1) + assert_(rank == 4) + x, residuals, rank, s = linalg.lstsq(a, b, rcond=None) + assert_(rank == 3) + # Warning should be raised exactly once (first command) + assert_(len(w) == 1) + +class TestMatrixPower(object): + R90 = array([[0, 1], [-1, 0]]) + Arb22 = array([[4, -7], [-2, 10]]) + noninv = array([[1, 0], [0, 0]]) + arbfloat = array([[0.1, 3.2], [1.2, 0.7]]) + + large = identity(10) + t = large[1, :].copy() + large[1, :] = large[0,:] + large[0, :] = t + + def test_large_power(self): + assert_equal( + matrix_power(self.R90, 2 ** 100 + 2 ** 10 + 2 ** 5 + 1), self.R90) + + def test_large_power_trailing_zero(self): + assert_equal( + matrix_power(self.R90, 2 ** 100 + 2 ** 10 + 2 ** 5), identity(2)) + + def testip_zero(self): + def tz(M): + mz = matrix_power(M, 0) + assert_equal(mz, identity(M.shape[0])) + assert_equal(mz.dtype, M.dtype) + for M in [self.Arb22, self.arbfloat, self.large]: + yield tz, M + + def testip_one(self): + def tz(M): + mz = matrix_power(M, 1) + assert_equal(mz, M) + assert_equal(mz.dtype, M.dtype) + for M in [self.Arb22, self.arbfloat, self.large]: + yield tz, M + + def testip_two(self): + def tz(M): + mz = matrix_power(M, 2) + assert_equal(mz, dot(M, M)) + assert_equal(mz.dtype, M.dtype) + for M in [self.Arb22, self.arbfloat, self.large]: + yield tz, M + + def testip_invert(self): + def tz(M): + mz = matrix_power(M, -1) + assert_almost_equal(identity(M.shape[0]), dot(mz, M)) + for M in [self.R90, self.Arb22, self.arbfloat, self.large]: + yield tz, M + + def test_invert_noninvertible(self): + import numpy.linalg + assert_raises(numpy.linalg.linalg.LinAlgError, + lambda: matrix_power(self.noninv, -1)) + + +class TestBoolPower(object): + + def test_square(self): + A = array([[True, False], [True, True]]) + assert_equal(matrix_power(A, 2), A) + + +class TestEigvalsh(HermitianTestCase, HermitianGeneralizedTestCase): + + def do(self, a, b, tags): + # note that eigenvalue arrays returned by eig must be sorted since + # their order isn't guaranteed. + ev = linalg.eigvalsh(a, 'L') + evalues, evectors = linalg.eig(a) + evalues.sort(axis=-1) + assert_allclose(ev, evalues, rtol=get_rtol(ev.dtype)) + + ev2 = linalg.eigvalsh(a, 'U') + assert_allclose(ev2, evalues, rtol=get_rtol(ev.dtype)) + + def test_types(self): + def check(dtype): + x = np.array([[1, 0.5], [0.5, 1]], dtype=dtype) + w = np.linalg.eigvalsh(x) + assert_equal(w.dtype, get_real_dtype(dtype)) + for dtype in [single, double, csingle, cdouble]: + yield check, dtype + + def test_invalid(self): + x = np.array([[1, 0.5], [0.5, 1]], dtype=np.float32) + assert_raises(ValueError, np.linalg.eigvalsh, x, UPLO="lrong") + assert_raises(ValueError, np.linalg.eigvalsh, x, "lower") + assert_raises(ValueError, np.linalg.eigvalsh, x, "upper") + + def test_UPLO(self): + Klo = np.array([[0, 0], [1, 0]], dtype=np.double) + Kup = np.array([[0, 1], [0, 0]], dtype=np.double) + tgt = np.array([-1, 1], dtype=np.double) + rtol = get_rtol(np.double) + + # Check default is 'L' + w = np.linalg.eigvalsh(Klo) + assert_allclose(w, tgt, rtol=rtol) + # Check 'L' + w = np.linalg.eigvalsh(Klo, UPLO='L') + assert_allclose(w, tgt, rtol=rtol) + # Check 'l' + w = np.linalg.eigvalsh(Klo, UPLO='l') + assert_allclose(w, tgt, rtol=rtol) + # Check 'U' + w = np.linalg.eigvalsh(Kup, UPLO='U') + assert_allclose(w, tgt, rtol=rtol) + # Check 'u' + w = np.linalg.eigvalsh(Kup, UPLO='u') + assert_allclose(w, tgt, rtol=rtol) + + def test_0_size(self): + # Check that all kinds of 0-sized arrays work + class ArraySubclass(np.ndarray): + pass + a = np.zeros((0, 1, 1), dtype=np.int_).view(ArraySubclass) + res = linalg.eigvalsh(a) + assert_(res.dtype.type is np.float64) + assert_equal((0, 1), res.shape) + # This is just for documentation, it might make sense to change: + assert_(isinstance(res, np.ndarray)) + + a = np.zeros((0, 0), dtype=np.complex64).view(ArraySubclass) + res = linalg.eigvalsh(a) + assert_(res.dtype.type is np.float32) + assert_equal((0,), res.shape) + # This is just for documentation, it might make sense to change: + assert_(isinstance(res, np.ndarray)) + + +class TestEigh(HermitianTestCase, HermitianGeneralizedTestCase): + + def do(self, a, b, tags): + # note that eigenvalue arrays returned by eig must be sorted since + # their order isn't guaranteed. + ev, evc = linalg.eigh(a) + evalues, evectors = linalg.eig(a) + evalues.sort(axis=-1) + assert_almost_equal(ev, evalues) + + assert_allclose(dot_generalized(a, evc), + np.asarray(ev)[..., None, :] * np.asarray(evc), + rtol=get_rtol(ev.dtype)) + + ev2, evc2 = linalg.eigh(a, 'U') + assert_almost_equal(ev2, evalues) + + assert_allclose(dot_generalized(a, evc2), + np.asarray(ev2)[..., None, :] * np.asarray(evc2), + rtol=get_rtol(ev.dtype), err_msg=repr(a)) + + def test_types(self): + def check(dtype): + x = np.array([[1, 0.5], [0.5, 1]], dtype=dtype) + w, v = np.linalg.eigh(x) + assert_equal(w.dtype, get_real_dtype(dtype)) + assert_equal(v.dtype, dtype) + for dtype in [single, double, csingle, cdouble]: + yield check, dtype + + def test_invalid(self): + x = np.array([[1, 0.5], [0.5, 1]], dtype=np.float32) + assert_raises(ValueError, np.linalg.eigh, x, UPLO="lrong") + assert_raises(ValueError, np.linalg.eigh, x, "lower") + assert_raises(ValueError, np.linalg.eigh, x, "upper") + + def test_UPLO(self): + Klo = np.array([[0, 0], [1, 0]], dtype=np.double) + Kup = np.array([[0, 1], [0, 0]], dtype=np.double) + tgt = np.array([-1, 1], dtype=np.double) + rtol = get_rtol(np.double) + + # Check default is 'L' + w, v = np.linalg.eigh(Klo) + assert_allclose(w, tgt, rtol=rtol) + # Check 'L' + w, v = np.linalg.eigh(Klo, UPLO='L') + assert_allclose(w, tgt, rtol=rtol) + # Check 'l' + w, v = np.linalg.eigh(Klo, UPLO='l') + assert_allclose(w, tgt, rtol=rtol) + # Check 'U' + w, v = np.linalg.eigh(Kup, UPLO='U') + assert_allclose(w, tgt, rtol=rtol) + # Check 'u' + w, v = np.linalg.eigh(Kup, UPLO='u') + assert_allclose(w, tgt, rtol=rtol) + + def test_0_size(self): + # Check that all kinds of 0-sized arrays work + class ArraySubclass(np.ndarray): + pass + a = np.zeros((0, 1, 1), dtype=np.int_).view(ArraySubclass) + res, res_v = linalg.eigh(a) + assert_(res_v.dtype.type is np.float64) + assert_(res.dtype.type is np.float64) + assert_equal(a.shape, res_v.shape) + assert_equal((0, 1), res.shape) + # This is just for documentation, it might make sense to change: + assert_(isinstance(a, np.ndarray)) + + a = np.zeros((0, 0), dtype=np.complex64).view(ArraySubclass) + res, res_v = linalg.eigh(a) + assert_(res_v.dtype.type is np.complex64) + assert_(res.dtype.type is np.float32) + assert_equal(a.shape, res_v.shape) + assert_equal((0,), res.shape) + # This is just for documentation, it might make sense to change: + assert_(isinstance(a, np.ndarray)) + + +class _TestNorm(object): + + dt = None + dec = None + + def test_empty(self): + assert_equal(norm([]), 0.0) + assert_equal(norm(array([], dtype=self.dt)), 0.0) + assert_equal(norm(atleast_2d(array([], dtype=self.dt))), 0.0) + + def test_vector_return_type(self): + a = np.array([1, 0, 1]) + + exact_types = np.typecodes['AllInteger'] + inexact_types = np.typecodes['AllFloat'] + + all_types = exact_types + inexact_types + + for each_inexact_types in all_types: + at = a.astype(each_inexact_types) + + an = norm(at, -np.inf) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 0.0) + + with suppress_warnings() as sup: + sup.filter(RuntimeWarning, "divide by zero encountered") + an = norm(at, -1) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 0.0) + + an = norm(at, 0) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 2) + + an = norm(at, 1) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 2.0) + + an = norm(at, 2) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, an.dtype.type(2.0)**an.dtype.type(1.0/2.0)) + + an = norm(at, 4) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, an.dtype.type(2.0)**an.dtype.type(1.0/4.0)) + + an = norm(at, np.inf) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 1.0) + + def test_matrix_return_type(self): + a = np.array([[1, 0, 1], [0, 1, 1]]) + + exact_types = np.typecodes['AllInteger'] + + # float32, complex64, float64, complex128 types are the only types + # allowed by `linalg`, which performs the matrix operations used + # within `norm`. + inexact_types = 'fdFD' + + all_types = exact_types + inexact_types + + for each_inexact_types in all_types: + at = a.astype(each_inexact_types) + + an = norm(at, -np.inf) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 2.0) + + with suppress_warnings() as sup: + sup.filter(RuntimeWarning, "divide by zero encountered") + an = norm(at, -1) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 1.0) + + an = norm(at, 1) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 2.0) + + an = norm(at, 2) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 3.0**(1.0/2.0)) + + an = norm(at, -2) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 1.0) + + an = norm(at, np.inf) + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 2.0) + + an = norm(at, 'fro') + assert_(issubclass(an.dtype.type, np.floating)) + assert_almost_equal(an, 2.0) + + an = norm(at, 'nuc') + assert_(issubclass(an.dtype.type, np.floating)) + # Lower bar needed to support low precision floats. + # They end up being off by 1 in the 7th place. + old_assert_almost_equal(an, 2.7320508075688772, decimal=6) + + def test_vector(self): + a = [1, 2, 3, 4] + b = [-1, -2, -3, -4] + c = [-1, 2, -3, 4] + + def _test(v): + np.testing.assert_almost_equal(norm(v), 30 ** 0.5, + decimal=self.dec) + np.testing.assert_almost_equal(norm(v, inf), 4.0, + decimal=self.dec) + np.testing.assert_almost_equal(norm(v, -inf), 1.0, + decimal=self.dec) + np.testing.assert_almost_equal(norm(v, 1), 10.0, + decimal=self.dec) + np.testing.assert_almost_equal(norm(v, -1), 12.0 / 25, + decimal=self.dec) + np.testing.assert_almost_equal(norm(v, 2), 30 ** 0.5, + decimal=self.dec) + np.testing.assert_almost_equal(norm(v, -2), ((205. / 144) ** -0.5), + decimal=self.dec) + np.testing.assert_almost_equal(norm(v, 0), 4, + decimal=self.dec) + + for v in (a, b, c,): + _test(v) + + for v in (array(a, dtype=self.dt), array(b, dtype=self.dt), + array(c, dtype=self.dt)): + _test(v) + + def test_matrix_2x2(self): + A = matrix([[1, 3], [5, 7]], dtype=self.dt) + assert_almost_equal(norm(A), 84 ** 0.5) + assert_almost_equal(norm(A, 'fro'), 84 ** 0.5) + assert_almost_equal(norm(A, 'nuc'), 10.0) + assert_almost_equal(norm(A, inf), 12.0) + assert_almost_equal(norm(A, -inf), 4.0) + assert_almost_equal(norm(A, 1), 10.0) + assert_almost_equal(norm(A, -1), 6.0) + assert_almost_equal(norm(A, 2), 9.1231056256176615) + assert_almost_equal(norm(A, -2), 0.87689437438234041) + + assert_raises(ValueError, norm, A, 'nofro') + assert_raises(ValueError, norm, A, -3) + assert_raises(ValueError, norm, A, 0) + + def test_matrix_3x3(self): + # This test has been added because the 2x2 example + # happened to have equal nuclear norm and induced 1-norm. + # The 1/10 scaling factor accommodates the absolute tolerance + # used in assert_almost_equal. + A = (1 / 10) * \ + np.array([[1, 2, 3], [6, 0, 5], [3, 2, 1]], dtype=self.dt) + assert_almost_equal(norm(A), (1 / 10) * 89 ** 0.5) + assert_almost_equal(norm(A, 'fro'), (1 / 10) * 89 ** 0.5) + assert_almost_equal(norm(A, 'nuc'), 1.3366836911774836) + assert_almost_equal(norm(A, inf), 1.1) + assert_almost_equal(norm(A, -inf), 0.6) + assert_almost_equal(norm(A, 1), 1.0) + assert_almost_equal(norm(A, -1), 0.4) + assert_almost_equal(norm(A, 2), 0.88722940323461277) + assert_almost_equal(norm(A, -2), 0.19456584790481812) + + def test_axis(self): + # Vector norms. + # Compare the use of `axis` with computing the norm of each row + # or column separately. + A = array([[1, 2, 3], [4, 5, 6]], dtype=self.dt) + for order in [None, -1, 0, 1, 2, 3, np.Inf, -np.Inf]: + expected0 = [norm(A[:, k], ord=order) for k in range(A.shape[1])] + assert_almost_equal(norm(A, ord=order, axis=0), expected0) + expected1 = [norm(A[k, :], ord=order) for k in range(A.shape[0])] + assert_almost_equal(norm(A, ord=order, axis=1), expected1) + + # Matrix norms. + B = np.arange(1, 25, dtype=self.dt).reshape(2, 3, 4) + nd = B.ndim + for order in [None, -2, 2, -1, 1, np.Inf, -np.Inf, 'fro']: + for axis in itertools.combinations(range(-nd, nd), 2): + row_axis, col_axis = axis + if row_axis < 0: + row_axis += nd + if col_axis < 0: + col_axis += nd + if row_axis == col_axis: + assert_raises(ValueError, norm, B, ord=order, axis=axis) + else: + n = norm(B, ord=order, axis=axis) + + # The logic using k_index only works for nd = 3. + # This has to be changed if nd is increased. + k_index = nd - (row_axis + col_axis) + if row_axis < col_axis: + expected = [norm(B[:].take(k, axis=k_index), ord=order) + for k in range(B.shape[k_index])] + else: + expected = [norm(B[:].take(k, axis=k_index).T, ord=order) + for k in range(B.shape[k_index])] + assert_almost_equal(n, expected) + + def test_keepdims(self): + A = np.arange(1, 25, dtype=self.dt).reshape(2, 3, 4) + + allclose_err = 'order {0}, axis = {1}' + shape_err = 'Shape mismatch found {0}, expected {1}, order={2}, axis={3}' + + # check the order=None, axis=None case + expected = norm(A, ord=None, axis=None) + found = norm(A, ord=None, axis=None, keepdims=True) + assert_allclose(np.squeeze(found), expected, + err_msg=allclose_err.format(None, None)) + expected_shape = (1, 1, 1) + assert_(found.shape == expected_shape, + shape_err.format(found.shape, expected_shape, None, None)) + + # Vector norms. + for order in [None, -1, 0, 1, 2, 3, np.Inf, -np.Inf]: + for k in range(A.ndim): + expected = norm(A, ord=order, axis=k) + found = norm(A, ord=order, axis=k, keepdims=True) + assert_allclose(np.squeeze(found), expected, + err_msg=allclose_err.format(order, k)) + expected_shape = list(A.shape) + expected_shape[k] = 1 + expected_shape = tuple(expected_shape) + assert_(found.shape == expected_shape, + shape_err.format(found.shape, expected_shape, order, k)) + + # Matrix norms. + for order in [None, -2, 2, -1, 1, np.Inf, -np.Inf, 'fro', 'nuc']: + for k in itertools.permutations(range(A.ndim), 2): + expected = norm(A, ord=order, axis=k) + found = norm(A, ord=order, axis=k, keepdims=True) + assert_allclose(np.squeeze(found), expected, + err_msg=allclose_err.format(order, k)) + expected_shape = list(A.shape) + expected_shape[k[0]] = 1 + expected_shape[k[1]] = 1 + expected_shape = tuple(expected_shape) + assert_(found.shape == expected_shape, + shape_err.format(found.shape, expected_shape, order, k)) + + def test_bad_args(self): + # Check that bad arguments raise the appropriate exceptions. + + A = array([[1, 2, 3], [4, 5, 6]], dtype=self.dt) + B = np.arange(1, 25, dtype=self.dt).reshape(2, 3, 4) + + # Using `axis=` or passing in a 1-D array implies vector + # norms are being computed, so also using `ord='fro'` + # or `ord='nuc'` raises a ValueError. + assert_raises(ValueError, norm, A, 'fro', 0) + assert_raises(ValueError, norm, A, 'nuc', 0) + assert_raises(ValueError, norm, [3, 4], 'fro', None) + assert_raises(ValueError, norm, [3, 4], 'nuc', None) + + # Similarly, norm should raise an exception when ord is any finite + # number other than 1, 2, -1 or -2 when computing matrix norms. + for order in [0, 3]: + assert_raises(ValueError, norm, A, order, None) + assert_raises(ValueError, norm, A, order, (0, 1)) + assert_raises(ValueError, norm, B, order, (1, 2)) + + # Invalid axis + assert_raises(np.AxisError, norm, B, None, 3) + assert_raises(np.AxisError, norm, B, None, (2, 3)) + assert_raises(ValueError, norm, B, None, (0, 1, 2)) + + +class TestNorm_NonSystematic(object): + + def test_longdouble_norm(self): + # Non-regression test: p-norm of longdouble would previously raise + # UnboundLocalError. + x = np.arange(10, dtype=np.longdouble) + old_assert_almost_equal(norm(x, ord=3), 12.65, decimal=2) + + def test_intmin(self): + # Non-regression test: p-norm of signed integer would previously do + # float cast and abs in the wrong order. + x = np.array([-2 ** 31], dtype=np.int32) + old_assert_almost_equal(norm(x, ord=3), 2 ** 31, decimal=5) + + def test_complex_high_ord(self): + # gh-4156 + d = np.empty((2,), dtype=np.clongdouble) + d[0] = 6 + 7j + d[1] = -6 + 7j + res = 11.615898132184 + old_assert_almost_equal(np.linalg.norm(d, ord=3), res, decimal=10) + d = d.astype(np.complex128) + old_assert_almost_equal(np.linalg.norm(d, ord=3), res, decimal=9) + d = d.astype(np.complex64) + old_assert_almost_equal(np.linalg.norm(d, ord=3), res, decimal=5) + + +class TestNormDouble(_TestNorm): + dt = np.double + dec = 12 + + +class TestNormSingle(_TestNorm): + dt = np.float32 + dec = 6 + + +class TestNormInt64(_TestNorm): + dt = np.int64 + dec = 12 + + +class TestMatrixRank(object): + + def test_matrix_rank(self): + # Full rank matrix + yield assert_equal, 4, matrix_rank(np.eye(4)) + # rank deficient matrix + I = np.eye(4) + I[-1, -1] = 0. + yield assert_equal, matrix_rank(I), 3 + # All zeros - zero rank + yield assert_equal, matrix_rank(np.zeros((4, 4))), 0 + # 1 dimension - rank 1 unless all 0 + yield assert_equal, matrix_rank([1, 0, 0, 0]), 1 + yield assert_equal, matrix_rank(np.zeros((4,))), 0 + # accepts array-like + yield assert_equal, matrix_rank([1]), 1 + # greater than 2 dimensions treated as stacked matrices + ms = np.array([I, np.eye(4), np.zeros((4,4))]) + yield assert_equal, matrix_rank(ms), np.array([3, 4, 0]) + # works on scalar + yield assert_equal, matrix_rank(1), 1 + + def test_symmetric_rank(self): + yield assert_equal, 4, matrix_rank(np.eye(4), hermitian=True) + yield assert_equal, 1, matrix_rank(np.ones((4, 4)), hermitian=True) + yield assert_equal, 0, matrix_rank(np.zeros((4, 4)), hermitian=True) + # rank deficient matrix + I = np.eye(4) + I[-1, -1] = 0. + yield assert_equal, 3, matrix_rank(I, hermitian=True) + # manually supplied tolerance + I[-1, -1] = 1e-8 + yield assert_equal, 4, matrix_rank(I, hermitian=True, tol=0.99e-8) + yield assert_equal, 3, matrix_rank(I, hermitian=True, tol=1.01e-8) + + +def test_reduced_rank(): + # Test matrices with reduced rank + rng = np.random.RandomState(20120714) + for i in range(100): + # Make a rank deficient matrix + X = rng.normal(size=(40, 10)) + X[:, 0] = X[:, 1] + X[:, 2] + # Assert that matrix_rank detected deficiency + assert_equal(matrix_rank(X), 9) + X[:, 3] = X[:, 4] + X[:, 5] + assert_equal(matrix_rank(X), 8) + + +class TestQR(object): + + def check_qr(self, a): + # This test expects the argument `a` to be an ndarray or + # a subclass of an ndarray of inexact type. + a_type = type(a) + a_dtype = a.dtype + m, n = a.shape + k = min(m, n) + + # mode == 'complete' + q, r = linalg.qr(a, mode='complete') + assert_(q.dtype == a_dtype) + assert_(r.dtype == a_dtype) + assert_(isinstance(q, a_type)) + assert_(isinstance(r, a_type)) + assert_(q.shape == (m, m)) + assert_(r.shape == (m, n)) + assert_almost_equal(dot(q, r), a) + assert_almost_equal(dot(q.T.conj(), q), np.eye(m)) + assert_almost_equal(np.triu(r), r) + + # mode == 'reduced' + q1, r1 = linalg.qr(a, mode='reduced') + assert_(q1.dtype == a_dtype) + assert_(r1.dtype == a_dtype) + assert_(isinstance(q1, a_type)) + assert_(isinstance(r1, a_type)) + assert_(q1.shape == (m, k)) + assert_(r1.shape == (k, n)) + assert_almost_equal(dot(q1, r1), a) + assert_almost_equal(dot(q1.T.conj(), q1), np.eye(k)) + assert_almost_equal(np.triu(r1), r1) + + # mode == 'r' + r2 = linalg.qr(a, mode='r') + assert_(r2.dtype == a_dtype) + assert_(isinstance(r2, a_type)) + assert_almost_equal(r2, r1) + + def test_qr_empty(self): + a = np.zeros((0, 2)) + assert_raises(linalg.LinAlgError, linalg.qr, a) + + def test_mode_raw(self): + # The factorization is not unique and varies between libraries, + # so it is not possible to check against known values. Functional + # testing is a possibility, but awaits the exposure of more + # of the functions in lapack_lite. Consequently, this test is + # very limited in scope. Note that the results are in FORTRAN + # order, hence the h arrays are transposed. + a = array([[1, 2], [3, 4], [5, 6]], dtype=np.double) + + # Test double + h, tau = linalg.qr(a, mode='raw') + assert_(h.dtype == np.double) + assert_(tau.dtype == np.double) + assert_(h.shape == (2, 3)) + assert_(tau.shape == (2,)) + + h, tau = linalg.qr(a.T, mode='raw') + assert_(h.dtype == np.double) + assert_(tau.dtype == np.double) + assert_(h.shape == (3, 2)) + assert_(tau.shape == (2,)) + + def test_mode_all_but_economic(self): + a = array([[1, 2], [3, 4]]) + b = array([[1, 2], [3, 4], [5, 6]]) + for dt in "fd": + m1 = a.astype(dt) + m2 = b.astype(dt) + self.check_qr(m1) + self.check_qr(m2) + self.check_qr(m2.T) + self.check_qr(matrix(m1)) + for dt in "fd": + m1 = 1 + 1j * a.astype(dt) + m2 = 1 + 1j * b.astype(dt) + self.check_qr(m1) + self.check_qr(m2) + self.check_qr(m2.T) + self.check_qr(matrix(m1)) + + def test_0_size(self): + # There may be good ways to do (some of this) reasonably: + a = np.zeros((0, 0)) + assert_raises(linalg.LinAlgError, linalg.qr, a) + a = np.zeros((0, 1)) + assert_raises(linalg.LinAlgError, linalg.qr, a) + a = np.zeros((1, 0)) + assert_raises(linalg.LinAlgError, linalg.qr, a) + + +class TestCholesky(object): + # TODO: are there no other tests for cholesky? + + def test_basic_property(self): + # Check A = L L^H + shapes = [(1, 1), (2, 2), (3, 3), (50, 50), (3, 10, 10)] + dtypes = (np.float32, np.float64, np.complex64, np.complex128) + + for shape, dtype in itertools.product(shapes, dtypes): + np.random.seed(1) + a = np.random.randn(*shape) + if np.issubdtype(dtype, np.complexfloating): + a = a + 1j*np.random.randn(*shape) + + t = list(range(len(shape))) + t[-2:] = -1, -2 + + a = np.matmul(a.transpose(t).conj(), a) + a = np.asarray(a, dtype=dtype) + + c = np.linalg.cholesky(a) + + b = np.matmul(c, c.transpose(t).conj()) + assert_allclose(b, a, + err_msg="{} {}\n{}\n{}".format(shape, dtype, a, c), + atol=500 * a.shape[0] * np.finfo(dtype).eps) + + def test_0_size(self): + class ArraySubclass(np.ndarray): + pass + a = np.zeros((0, 1, 1), dtype=np.int_).view(ArraySubclass) + res = linalg.cholesky(a) + assert_equal(a.shape, res.shape) + assert_(res.dtype.type is np.float64) + # for documentation purpose: + assert_(isinstance(res, np.ndarray)) + + a = np.zeros((1, 0, 0), dtype=np.complex64).view(ArraySubclass) + res = linalg.cholesky(a) + assert_equal(a.shape, res.shape) + assert_(res.dtype.type is np.complex64) + assert_(isinstance(res, np.ndarray)) + + +def test_byteorder_check(): + # Byte order check should pass for native order + if sys.byteorder == 'little': + native = '<' + else: + native = '>' + + for dtt in (np.float32, np.float64): + arr = np.eye(4, dtype=dtt) + n_arr = arr.newbyteorder(native) + sw_arr = arr.newbyteorder('S').byteswap() + assert_equal(arr.dtype.byteorder, '=') + for routine in (linalg.inv, linalg.det, linalg.pinv): + # Normal call + res = routine(arr) + # Native but not '=' + assert_array_equal(res, routine(n_arr)) + # Swapped + assert_array_equal(res, routine(sw_arr)) + + +def test_generalized_raise_multiloop(): + # It should raise an error even if the error doesn't occur in the + # last iteration of the ufunc inner loop + + invertible = np.array([[1, 2], [3, 4]]) + non_invertible = np.array([[1, 1], [1, 1]]) + + x = np.zeros([4, 4, 2, 2])[1::2] + x[...] = invertible + x[0, 0] = non_invertible + + assert_raises(np.linalg.LinAlgError, np.linalg.inv, x) + + +def test_xerbla_override(): + # Check that our xerbla has been successfully linked in. If it is not, + # the default xerbla routine is called, which prints a message to stdout + # and may, or may not, abort the process depending on the LAPACK package. + + XERBLA_OK = 255 + + try: + pid = os.fork() + except (OSError, AttributeError): + # fork failed, or not running on POSIX + raise SkipTest("Not POSIX or fork failed.") + + if pid == 0: + # child; close i/o file handles + os.close(1) + os.close(0) + # Avoid producing core files. + import resource + resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) + # These calls may abort. + try: + np.linalg.lapack_lite.xerbla() + except ValueError: + pass + except Exception: + os._exit(os.EX_CONFIG) + + try: + a = np.array([[1.]]) + np.linalg.lapack_lite.dorgqr( + 1, 1, 1, a, + 0, # <- invalid value + a, a, 0, 0) + except ValueError as e: + if "DORGQR parameter number 5" in str(e): + # success, reuse error code to mark success as + # FORTRAN STOP returns as success. + os._exit(XERBLA_OK) + + # Did not abort, but our xerbla was not linked in. + os._exit(os.EX_CONFIG) + else: + # parent + pid, status = os.wait() + if os.WEXITSTATUS(status) != XERBLA_OK: + raise SkipTest('Numpy xerbla not linked in.') + + +class TestMultiDot(object): + + def test_basic_function_with_three_arguments(self): + # multi_dot with three arguments uses a fast hand coded algorithm to + # determine the optimal order. Therefore test it separately. + A = np.random.random((6, 2)) + B = np.random.random((2, 6)) + C = np.random.random((6, 2)) + + assert_almost_equal(multi_dot([A, B, C]), A.dot(B).dot(C)) + assert_almost_equal(multi_dot([A, B, C]), np.dot(A, np.dot(B, C))) + + def test_basic_function_with_dynamic_programing_optimization(self): + # multi_dot with four or more arguments uses the dynamic programing + # optimization and therefore deserve a separate + A = np.random.random((6, 2)) + B = np.random.random((2, 6)) + C = np.random.random((6, 2)) + D = np.random.random((2, 1)) + assert_almost_equal(multi_dot([A, B, C, D]), A.dot(B).dot(C).dot(D)) + + def test_vector_as_first_argument(self): + # The first argument can be 1-D + A1d = np.random.random(2) # 1-D + B = np.random.random((2, 6)) + C = np.random.random((6, 2)) + D = np.random.random((2, 2)) + + # the result should be 1-D + assert_equal(multi_dot([A1d, B, C, D]).shape, (2,)) + + def test_vector_as_last_argument(self): + # The last argument can be 1-D + A = np.random.random((6, 2)) + B = np.random.random((2, 6)) + C = np.random.random((6, 2)) + D1d = np.random.random(2) # 1-D + + # the result should be 1-D + assert_equal(multi_dot([A, B, C, D1d]).shape, (6,)) + + def test_vector_as_first_and_last_argument(self): + # The first and last arguments can be 1-D + A1d = np.random.random(2) # 1-D + B = np.random.random((2, 6)) + C = np.random.random((6, 2)) + D1d = np.random.random(2) # 1-D + + # the result should be a scalar + assert_equal(multi_dot([A1d, B, C, D1d]).shape, ()) + + def test_dynamic_programming_logic(self): + # Test for the dynamic programming part + # This test is directly taken from Cormen page 376. + arrays = [np.random.random((30, 35)), + np.random.random((35, 15)), + np.random.random((15, 5)), + np.random.random((5, 10)), + np.random.random((10, 20)), + np.random.random((20, 25))] + m_expected = np.array([[0., 15750., 7875., 9375., 11875., 15125.], + [0., 0., 2625., 4375., 7125., 10500.], + [0., 0., 0., 750., 2500., 5375.], + [0., 0., 0., 0., 1000., 3500.], + [0., 0., 0., 0., 0., 5000.], + [0., 0., 0., 0., 0., 0.]]) + s_expected = np.array([[0, 1, 1, 3, 3, 3], + [0, 0, 2, 3, 3, 3], + [0, 0, 0, 3, 3, 3], + [0, 0, 0, 0, 4, 5], + [0, 0, 0, 0, 0, 5], + [0, 0, 0, 0, 0, 0]], dtype=int) + s_expected -= 1 # Cormen uses 1-based index, python does not. + + s, m = _multi_dot_matrix_chain_order(arrays, return_costs=True) + + # Only the upper triangular part (without the diagonal) is interesting. + assert_almost_equal(np.triu(s[:-1, 1:]), + np.triu(s_expected[:-1, 1:])) + assert_almost_equal(np.triu(m), np.triu(m_expected)) + + def test_too_few_input_arrays(self): + assert_raises(ValueError, multi_dot, []) + assert_raises(ValueError, multi_dot, [np.random.random((3, 3))]) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/linalg/tests/test_regression.py b/numpy/linalg/tests/test_regression.py new file mode 100644 index 0000000..c11689b --- /dev/null +++ b/numpy/linalg/tests/test_regression.py @@ -0,0 +1,154 @@ +""" Test functions for linalg module +""" +from __future__ import division, absolute_import, print_function + +import warnings + +import numpy as np +from numpy import linalg, arange, float64, array, dot, transpose +from numpy.testing import ( + run_module_suite, assert_, assert_raises, assert_equal, assert_array_equal, + assert_array_almost_equal, assert_array_less +) + + +class TestRegression(object): + + def test_eig_build(self): + # Ticket #652 + rva = array([1.03221168e+02 + 0.j, + -1.91843603e+01 + 0.j, + -6.04004526e-01 + 15.84422474j, + -6.04004526e-01 - 15.84422474j, + -1.13692929e+01 + 0.j, + -6.57612485e-01 + 10.41755503j, + -6.57612485e-01 - 10.41755503j, + 1.82126812e+01 + 0.j, + 1.06011014e+01 + 0.j, + 7.80732773e+00 + 0.j, + -7.65390898e-01 + 0.j, + 1.51971555e-15 + 0.j, + -1.51308713e-15 + 0.j]) + a = arange(13 * 13, dtype=float64) + a.shape = (13, 13) + a = a % 17 + va, ve = linalg.eig(a) + va.sort() + rva.sort() + assert_array_almost_equal(va, rva) + + def test_eigh_build(self): + # Ticket 662. + rvals = [68.60568999, 89.57756725, 106.67185574] + + cov = array([[77.70273908, 3.51489954, 15.64602427], + [3.51489954, 88.97013878, -1.07431931], + [15.64602427, -1.07431931, 98.18223512]]) + + vals, vecs = linalg.eigh(cov) + assert_array_almost_equal(vals, rvals) + + def test_svd_build(self): + # Ticket 627. + a = array([[0., 1.], [1., 1.], [2., 1.], [3., 1.]]) + m, n = a.shape + u, s, vh = linalg.svd(a) + + b = dot(transpose(u[:, n:]), a) + + assert_array_almost_equal(b, np.zeros((2, 2))) + + def test_norm_vector_badarg(self): + # Regression for #786: Froebenius norm for vectors raises + # TypeError. + assert_raises(ValueError, linalg.norm, array([1., 2., 3.]), 'fro') + + def test_lapack_endian(self): + # For bug #1482 + a = array([[5.7998084, -2.1825367], + [-2.1825367, 9.85910595]], dtype='>f8') + b = array(a, dtype=' 0.5) + assert_equal(c, 1) + assert_equal(np.linalg.matrix_rank(a), 1) + assert_array_less(1, np.linalg.norm(a, ord=2)) + + def test_norm_object_array(self): + # gh-7575 + testvector = np.array([np.array([0, 1]), 0, 0], dtype=object) + + norm = linalg.norm(testvector) + assert_array_equal(norm, [0, 1]) + assert_(norm.dtype == np.dtype('float64')) + + norm = linalg.norm(testvector, ord=1) + assert_array_equal(norm, [0, 1]) + assert_(norm.dtype != np.dtype('float64')) + + norm = linalg.norm(testvector, ord=2) + assert_array_equal(norm, [0, 1]) + assert_(norm.dtype == np.dtype('float64')) + + assert_raises(ValueError, linalg.norm, testvector, ord='fro') + assert_raises(ValueError, linalg.norm, testvector, ord='nuc') + assert_raises(ValueError, linalg.norm, testvector, ord=np.inf) + assert_raises(ValueError, linalg.norm, testvector, ord=-np.inf) + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + assert_raises((AttributeError, DeprecationWarning), + linalg.norm, testvector, ord=0) + assert_raises(ValueError, linalg.norm, testvector, ord=-1) + assert_raises(ValueError, linalg.norm, testvector, ord=-2) + + testmatrix = np.array([[np.array([0, 1]), 0, 0], + [0, 0, 0]], dtype=object) + + norm = linalg.norm(testmatrix) + assert_array_equal(norm, [0, 1]) + assert_(norm.dtype == np.dtype('float64')) + + norm = linalg.norm(testmatrix, ord='fro') + assert_array_equal(norm, [0, 1]) + assert_(norm.dtype == np.dtype('float64')) + + assert_raises(TypeError, linalg.norm, testmatrix, ord='nuc') + assert_raises(ValueError, linalg.norm, testmatrix, ord=np.inf) + assert_raises(ValueError, linalg.norm, testmatrix, ord=-np.inf) + assert_raises(ValueError, linalg.norm, testmatrix, ord=0) + assert_raises(ValueError, linalg.norm, testmatrix, ord=1) + assert_raises(ValueError, linalg.norm, testmatrix, ord=-1) + assert_raises(TypeError, linalg.norm, testmatrix, ord=2) + assert_raises(TypeError, linalg.norm, testmatrix, ord=-2) + assert_raises(ValueError, linalg.norm, testmatrix, ord=3) + + def test_lstsq_complex_larger_rhs(self): + # gh-9891 + size = 20 + n_rhs = 70 + G = np.random.randn(size, size) + 1j * np.random.randn(size, size) + u = np.random.randn(size, n_rhs) + 1j * np.random.randn(size, n_rhs) + b = G.dot(u) + # This should work without segmentation fault. + u_lstsq, res, rank, sv = linalg.lstsq(G, b, rcond=None) + # check results just in case + assert_array_almost_equal(u_lstsq, u) + + +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/linalg/umath_linalg.c.src b/numpy/linalg/umath_linalg.c.src new file mode 100644 index 0000000..36b99b5 --- /dev/null +++ b/numpy/linalg/umath_linalg.c.src @@ -0,0 +1,3303 @@ +/* -*- c -*- */ + +/* + ***************************************************************************** + ** INCLUDES ** + ***************************************************************************** + */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "Python.h" +#include "numpy/arrayobject.h" +#include "numpy/ufuncobject.h" + +#include "npy_pycompat.h" + +#include "npy_config.h" + +#include +#include +#include +#include + + +static const char* umath_linalg_version_string = "0.1.5"; + +/* + **************************************************************************** + * Debugging support * + **************************************************************************** + */ +#define TRACE_TXT(...) do { fprintf (stderr, __VA_ARGS__); } while (0) +#define STACK_TRACE do {} while (0) +#define TRACE\ + do { \ + fprintf (stderr, \ + "%s:%d:%s\n", \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + STACK_TRACE; \ + } while (0) + +#if 0 +#include +void +dbg_stack_trace() +{ + void *trace[32]; + size_t size; + + size = backtrace(trace, sizeof(trace)/sizeof(trace[0])); + backtrace_symbols_fd(trace, size, 1); +} + +#undef STACK_TRACE +#define STACK_TRACE do { dbg_stack_trace(); } while (0) +#endif + +/* + ***************************************************************************** + * BLAS/LAPACK calling macros * + ***************************************************************************** + */ + +#ifdef NO_APPEND_FORTRAN +# define FNAME(x) x +#else +# define FNAME(x) x##_ +#endif + +typedef struct { float r, i; } f2c_complex; +typedef struct { double r, i; } f2c_doublecomplex; +/* typedef long int (*L_fp)(); */ + +extern int +FNAME(sgeev)(char *jobvl, char *jobvr, int *n, + float a[], int *lda, float wr[], float wi[], + float vl[], int *ldvl, float vr[], int *ldvr, + float work[], int lwork[], + int *info); +extern int +FNAME(dgeev)(char *jobvl, char *jobvr, int *n, + double a[], int *lda, double wr[], double wi[], + double vl[], int *ldvl, double vr[], int *ldvr, + double work[], int lwork[], + int *info); +extern int +FNAME(cgeev)(char *jobvl, char *jobvr, int *n, + f2c_doublecomplex a[], int *lda, + f2c_doublecomplex w[], + f2c_doublecomplex vl[], int *ldvl, + f2c_doublecomplex vr[], int *ldvr, + f2c_doublecomplex work[], int *lwork, + double rwork[], + int *info); +extern int +FNAME(zgeev)(char *jobvl, char *jobvr, int *n, + f2c_doublecomplex a[], int *lda, + f2c_doublecomplex w[], + f2c_doublecomplex vl[], int *ldvl, + f2c_doublecomplex vr[], int *ldvr, + f2c_doublecomplex work[], int *lwork, + double rwork[], + int *info); + +extern int +FNAME(ssyevd)(char *jobz, char *uplo, int *n, + float a[], int *lda, float w[], float work[], + int *lwork, int iwork[], int *liwork, + int *info); +extern int +FNAME(dsyevd)(char *jobz, char *uplo, int *n, + double a[], int *lda, double w[], double work[], + int *lwork, int iwork[], int *liwork, + int *info); +extern int +FNAME(cheevd)(char *jobz, char *uplo, int *n, + f2c_complex a[], int *lda, + float w[], f2c_complex work[], + int *lwork, float rwork[], int *lrwork, int iwork[], + int *liwork, + int *info); +extern int +FNAME(zheevd)(char *jobz, char *uplo, int *n, + f2c_doublecomplex a[], int *lda, + double w[], f2c_doublecomplex work[], + int *lwork, double rwork[], int *lrwork, int iwork[], + int *liwork, + int *info); + +extern int +FNAME(dgelsd)(int *m, int *n, int *nrhs, + double a[], int *lda, double b[], int *ldb, + double s[], double *rcond, int *rank, + double work[], int *lwork, int iwork[], + int *info); +extern int +FNAME(zgelsd)(int *m, int *n, int *nrhs, + f2c_doublecomplex a[], int *lda, + f2c_doublecomplex b[], int *ldb, + double s[], double *rcond, int *rank, + f2c_doublecomplex work[], int *lwork, + double rwork[], int iwork[], + int *info); + +extern int +FNAME(sgesv)(int *n, int *nrhs, + float a[], int *lda, + int ipiv[], + float b[], int *ldb, + int *info); +extern int +FNAME(dgesv)(int *n, int *nrhs, + double a[], int *lda, + int ipiv[], + double b[], int *ldb, + int *info); +extern int +FNAME(cgesv)(int *n, int *nrhs, + f2c_complex a[], int *lda, + int ipiv[], + f2c_complex b[], int *ldb, + int *info); +extern int +FNAME(zgesv)(int *n, int *nrhs, + f2c_doublecomplex a[], int *lda, + int ipiv[], + f2c_doublecomplex b[], int *ldb, + int *info); + +extern int +FNAME(sgetrf)(int *m, int *n, + float a[], int *lda, + int ipiv[], + int *info); +extern int +FNAME(dgetrf)(int *m, int *n, + double a[], int *lda, + int ipiv[], + int *info); +extern int +FNAME(cgetrf)(int *m, int *n, + f2c_complex a[], int *lda, + int ipiv[], + int *info); +extern int +FNAME(zgetrf)(int *m, int *n, + f2c_doublecomplex a[], int *lda, + int ipiv[], + int *info); + +extern int +FNAME(spotrf)(char *uplo, int *n, + float a[], int *lda, + int *info); +extern int +FNAME(dpotrf)(char *uplo, int *n, + double a[], int *lda, + int *info); +extern int +FNAME(cpotrf)(char *uplo, int *n, + f2c_complex a[], int *lda, + int *info); +extern int +FNAME(zpotrf)(char *uplo, int *n, + f2c_doublecomplex a[], int *lda, + int *info); + +extern int +FNAME(sgesdd)(char *jobz, int *m, int *n, + float a[], int *lda, float s[], float u[], + int *ldu, float vt[], int *ldvt, float work[], + int *lwork, int iwork[], int *info); +extern int +FNAME(dgesdd)(char *jobz, int *m, int *n, + double a[], int *lda, double s[], double u[], + int *ldu, double vt[], int *ldvt, double work[], + int *lwork, int iwork[], int *info); +extern int +FNAME(cgesdd)(char *jobz, int *m, int *n, + f2c_complex a[], int *lda, + float s[], f2c_complex u[], int *ldu, + f2c_complex vt[], int *ldvt, + f2c_complex work[], int *lwork, + float rwork[], int iwork[], int *info); +extern int +FNAME(zgesdd)(char *jobz, int *m, int *n, + f2c_doublecomplex a[], int *lda, + double s[], f2c_doublecomplex u[], int *ldu, + f2c_doublecomplex vt[], int *ldvt, + f2c_doublecomplex work[], int *lwork, + double rwork[], int iwork[], int *info); + +extern int +FNAME(spotrs)(char *uplo, int *n, int *nrhs, + float a[], int *lda, + float b[], int *ldb, + int *info); +extern int +FNAME(dpotrs)(char *uplo, int *n, int *nrhs, + double a[], int *lda, + double b[], int *ldb, + int *info); +extern int +FNAME(cpotrs)(char *uplo, int *n, int *nrhs, + f2c_complex a[], int *lda, + f2c_complex b[], int *ldb, + int *info); +extern int +FNAME(zpotrs)(char *uplo, int *n, int *nrhs, + f2c_doublecomplex a[], int *lda, + f2c_doublecomplex b[], int *ldb, + int *info); + +extern int +FNAME(spotri)(char *uplo, int *n, + float a[], int *lda, + int *info); +extern int +FNAME(dpotri)(char *uplo, int *n, + double a[], int *lda, + int *info); +extern int +FNAME(cpotri)(char *uplo, int *n, + f2c_complex a[], int *lda, + int *info); +extern int +FNAME(zpotri)(char *uplo, int *n, + f2c_doublecomplex a[], int *lda, + int *info); + +extern int +FNAME(scopy)(int *n, + float *sx, int *incx, + float *sy, int *incy); +extern int +FNAME(dcopy)(int *n, + double *sx, int *incx, + double *sy, int *incy); +extern int +FNAME(ccopy)(int *n, + f2c_complex *sx, int *incx, + f2c_complex *sy, int *incy); +extern int +FNAME(zcopy)(int *n, + f2c_doublecomplex *sx, int *incx, + f2c_doublecomplex *sy, int *incy); + +extern float +FNAME(sdot)(int *n, + float *sx, int *incx, + float *sy, int *incy); +extern double +FNAME(ddot)(int *n, + double *sx, int *incx, + double *sy, int *incy); +extern void +FNAME(cdotu)(f2c_complex *ret, int *n, + f2c_complex *sx, int *incx, + f2c_complex *sy, int *incy); +extern void +FNAME(zdotu)(f2c_doublecomplex *ret, int *n, + f2c_doublecomplex *sx, int *incx, + f2c_doublecomplex *sy, int *incy); +extern void +FNAME(cdotc)(f2c_complex *ret, int *n, + f2c_complex *sx, int *incx, + f2c_complex *sy, int *incy); +extern void +FNAME(zdotc)(f2c_doublecomplex *ret, int *n, + f2c_doublecomplex *sx, int *incx, + f2c_doublecomplex *sy, int *incy); + +extern int +FNAME(sgemm)(char *transa, char *transb, + int *m, int *n, int *k, + float *alpha, + float *a, int *lda, + float *b, int *ldb, + float *beta, + float *c, int *ldc); +extern int +FNAME(dgemm)(char *transa, char *transb, + int *m, int *n, int *k, + double *alpha, + double *a, int *lda, + double *b, int *ldb, + double *beta, + double *c, int *ldc); +extern int +FNAME(cgemm)(char *transa, char *transb, + int *m, int *n, int *k, + f2c_complex *alpha, + f2c_complex *a, int *lda, + f2c_complex *b, int *ldb, + f2c_complex *beta, + f2c_complex *c, int *ldc); +extern int +FNAME(zgemm)(char *transa, char *transb, + int *m, int *n, int *k, + f2c_doublecomplex *alpha, + f2c_doublecomplex *a, int *lda, + f2c_doublecomplex *b, int *ldb, + f2c_doublecomplex *beta, + f2c_doublecomplex *c, int *ldc); + + +#define LAPACK_T(FUNC) \ + TRACE_TXT("Calling LAPACK ( " # FUNC " )\n"); \ + FNAME(FUNC) + +#define BLAS(FUNC) \ + FNAME(FUNC) + +#define LAPACK(FUNC) \ + FNAME(FUNC) + +typedef int fortran_int; +typedef float fortran_real; +typedef double fortran_doublereal; +typedef f2c_complex fortran_complex; +typedef f2c_doublecomplex fortran_doublecomplex; + + +/* + ***************************************************************************** + ** Some handy functions ** + ***************************************************************************** + */ + +static NPY_INLINE void * +offset_ptr(void* ptr, ptrdiff_t offset) +{ + return (void*)((npy_uint8*)ptr + offset); +} + +static NPY_INLINE int +get_fp_invalid_and_clear(void) +{ + int status; + status = npy_clear_floatstatus(); + return !!(status & NPY_FPE_INVALID); +} + +static NPY_INLINE void +set_fp_invalid_or_clear(int error_occurred) +{ + if (error_occurred) { + npy_set_floatstatus_invalid(); + } + else { + npy_clear_floatstatus(); + } +} + +/* + ***************************************************************************** + ** Some handy constants ** + ***************************************************************************** + */ + +#define UMATH_LINALG_MODULE_NAME "_umath_linalg" + +typedef union { + fortran_complex f; + npy_cfloat npy; + float array[2]; +} COMPLEX_t; + +typedef union { + fortran_doublecomplex f; + npy_cdouble npy; + double array[2]; +} DOUBLECOMPLEX_t; + +static float s_one; +static float s_zero; +static float s_minus_one; +static float s_ninf; +static float s_nan; +static double d_one; +static double d_zero; +static double d_minus_one; +static double d_ninf; +static double d_nan; +static COMPLEX_t c_one; +static COMPLEX_t c_zero; +static COMPLEX_t c_minus_one; +static COMPLEX_t c_ninf; +static COMPLEX_t c_nan; +static DOUBLECOMPLEX_t z_one; +static DOUBLECOMPLEX_t z_zero; +static DOUBLECOMPLEX_t z_minus_one; +static DOUBLECOMPLEX_t z_ninf; +static DOUBLECOMPLEX_t z_nan; + +static void init_constants(void) +{ + /* + this is needed as NPY_INFINITY and NPY_NAN macros + can't be used as initializers. I prefer to just set + all the constants the same way. + */ + s_one = 1.0f; + s_zero = 0.0f; + s_minus_one = -1.0f; + s_ninf = -NPY_INFINITYF; + s_nan = NPY_NANF; + + d_one = 1.0; + d_zero = 0.0; + d_minus_one = -1.0; + d_ninf = -NPY_INFINITY; + d_nan = NPY_NAN; + + c_one.array[0] = 1.0f; + c_one.array[1] = 0.0f; + c_zero.array[0] = 0.0f; + c_zero.array[1] = 0.0f; + c_minus_one.array[0] = -1.0f; + c_minus_one.array[1] = 0.0f; + c_ninf.array[0] = -NPY_INFINITYF; + c_ninf.array[1] = 0.0f; + c_nan.array[0] = NPY_NANF; + c_nan.array[1] = NPY_NANF; + + z_one.array[0] = 1.0; + z_one.array[1] = 0.0; + z_zero.array[0] = 0.0; + z_zero.array[1] = 0.0; + z_minus_one.array[0] = -1.0; + z_minus_one.array[1] = 0.0; + z_ninf.array[0] = -NPY_INFINITY; + z_ninf.array[1] = 0.0; + z_nan.array[0] = NPY_NAN; + z_nan.array[1] = NPY_NAN; +} + +/* + ***************************************************************************** + ** Structs used for data rearrangement ** + ***************************************************************************** + */ + + +/* this struct contains information about how to linearize in a local buffer + a matrix so that it can be used by blas functions. + All strides are specified in number of elements (similar to what blas + expects) + + dst_row_strides: number of elements between different row. Matrix is + considered row-major + dst_column_strides: number of elements between different columns in the + destination buffer + rows: number of rows of the matrix + columns: number of columns of the matrix + src_row_strides: strides needed to access the next row in the source matrix + src_column_strides: strides needed to access the next column in the source + matrix + */ +typedef struct linearize_data_struct +{ + size_t rows; + size_t columns; + ptrdiff_t row_strides; + ptrdiff_t column_strides; +} LINEARIZE_DATA_t; + +static NPY_INLINE void +init_linearize_data(LINEARIZE_DATA_t *lin_data, + int rows, + int columns, + ptrdiff_t row_strides, + ptrdiff_t column_strides) +{ + lin_data->rows = rows; + lin_data->columns = columns; + lin_data->row_strides = row_strides; + lin_data->column_strides = column_strides; +} + +static NPY_INLINE void +dump_ufunc_object(PyUFuncObject* ufunc) +{ + TRACE_TXT("\n\n%s '%s' (%d input(s), %d output(s), %d specialization(s).\n", + ufunc->core_enabled? "generalized ufunc" : "scalar ufunc", + ufunc->name, ufunc->nin, ufunc->nout, ufunc->ntypes); + if (ufunc->core_enabled) { + int arg; + int dim; + TRACE_TXT("\t%s (%d dimension(s) detected).\n", + ufunc->core_signature, ufunc->core_num_dim_ix); + + for (arg = 0; arg < ufunc->nargs; arg++){ + int * arg_dim_ix = ufunc->core_dim_ixs + ufunc->core_offsets[arg]; + TRACE_TXT("\t\targ %d (%s) has %d dimension(s): (", + arg, arg < ufunc->nin? "INPUT" : "OUTPUT", + ufunc->core_num_dims[arg]); + for (dim = 0; dim < ufunc->core_num_dims[arg]; dim ++) { + TRACE_TXT(" %d", arg_dim_ix[dim]); + } + TRACE_TXT(" )\n"); + } + } +} + +static NPY_INLINE void +dump_linearize_data(const char* name, const LINEARIZE_DATA_t* params) +{ + TRACE_TXT("\n\t%s rows: %zd columns: %zd"\ + "\n\t\trow_strides: %td column_strides: %td"\ + "\n", name, params->rows, params->columns, + params->row_strides, params->column_strides); +} + + +static NPY_INLINE float +FLOAT_add(float op1, float op2) +{ + return op1 + op2; +} + +static NPY_INLINE double +DOUBLE_add(double op1, double op2) +{ + return op1 + op2; +} + +static NPY_INLINE COMPLEX_t +CFLOAT_add(COMPLEX_t op1, COMPLEX_t op2) +{ + COMPLEX_t result; + result.array[0] = op1.array[0] + op2.array[0]; + result.array[1] = op1.array[1] + op2.array[1]; + + return result; +} + +static NPY_INLINE DOUBLECOMPLEX_t +CDOUBLE_add(DOUBLECOMPLEX_t op1, DOUBLECOMPLEX_t op2) +{ + DOUBLECOMPLEX_t result; + result.array[0] = op1.array[0] + op2.array[0]; + result.array[1] = op1.array[1] + op2.array[1]; + + return result; +} + +static NPY_INLINE float +FLOAT_mul(float op1, float op2) +{ + return op1*op2; +} + +static NPY_INLINE double +DOUBLE_mul(double op1, double op2) +{ + return op1*op2; +} + + +static NPY_INLINE COMPLEX_t +CFLOAT_mul(COMPLEX_t op1, COMPLEX_t op2) +{ + COMPLEX_t result; + result.array[0] = op1.array[0]*op2.array[0] - op1.array[1]*op2.array[1]; + result.array[1] = op1.array[1]*op2.array[0] + op1.array[0]*op2.array[1]; + + return result; +} + +static NPY_INLINE DOUBLECOMPLEX_t +CDOUBLE_mul(DOUBLECOMPLEX_t op1, DOUBLECOMPLEX_t op2) +{ + DOUBLECOMPLEX_t result; + result.array[0] = op1.array[0]*op2.array[0] - op1.array[1]*op2.array[1]; + result.array[1] = op1.array[1]*op2.array[0] + op1.array[0]*op2.array[1]; + + return result; +} + +static NPY_INLINE float +FLOAT_mulc(float op1, float op2) +{ + return op1*op2; +} + +static NPY_INLINE double +DOUBLE_mulc(float op1, float op2) +{ + return op1*op2; +} + +static NPY_INLINE COMPLEX_t +CFLOAT_mulc(COMPLEX_t op1, COMPLEX_t op2) +{ + COMPLEX_t result; + result.array[0] = op1.array[0]*op2.array[0] + op1.array[1]*op2.array[1]; + result.array[1] = op1.array[0]*op2.array[1] - op1.array[1]*op2.array[0]; + + return result; +} + +static NPY_INLINE DOUBLECOMPLEX_t +CDOUBLE_mulc(DOUBLECOMPLEX_t op1, DOUBLECOMPLEX_t op2) +{ + DOUBLECOMPLEX_t result; + result.array[0] = op1.array[0]*op2.array[0] + op1.array[1]*op2.array[1]; + result.array[1] = op1.array[0]*op2.array[1] - op1.array[1]*op2.array[0]; + + return result; +} + +static NPY_INLINE void +print_FLOAT(npy_float s) +{ + TRACE_TXT(" %8.4f", s); +} +static NPY_INLINE void +print_DOUBLE(npy_double d) +{ + TRACE_TXT(" %10.6f", d); +} +static NPY_INLINE void +print_CFLOAT(npy_cfloat c) +{ + float* c_parts = (float*)&c; + TRACE_TXT("(%8.4f, %8.4fj)", c_parts[0], c_parts[1]); +} +static NPY_INLINE void +print_CDOUBLE(npy_cdouble z) +{ + double* z_parts = (double*)&z; + TRACE_TXT("(%8.4f, %8.4fj)", z_parts[0], z_parts[1]); +} + +/**begin repeat + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #typ = npy_float, npy_double, npy_cfloat, npy_cdouble# + */ +static NPY_INLINE void +dump_@TYPE@_matrix(const char* name, + size_t rows, size_t columns, + const @typ@* ptr) +{ + size_t i, j; + + TRACE_TXT("\n%s %p (%zd, %zd)\n", name, ptr, rows, columns); + for (i = 0; i < rows; i++) + { + TRACE_TXT("| "); + for (j = 0; j < columns; j++) + { + print_@TYPE@(ptr[j*rows + i]); + TRACE_TXT(", "); + } + TRACE_TXT(" |\n"); + } +} +/**end repeat**/ + + +/* + ***************************************************************************** + ** Basics ** + ***************************************************************************** + */ + +static NPY_INLINE fortran_int +fortran_int_min(fortran_int x, fortran_int y) { + return x < y ? x : y; +} + +static NPY_INLINE fortran_int +fortran_int_max(fortran_int x, fortran_int y) { + return x > y ? x : y; +} + +#define INIT_OUTER_LOOP_1 \ + npy_intp dN = *dimensions++;\ + npy_intp N_;\ + npy_intp s0 = *steps++; + +#define INIT_OUTER_LOOP_2 \ + INIT_OUTER_LOOP_1\ + npy_intp s1 = *steps++; + +#define INIT_OUTER_LOOP_3 \ + INIT_OUTER_LOOP_2\ + npy_intp s2 = *steps++; + +#define INIT_OUTER_LOOP_4 \ + INIT_OUTER_LOOP_3\ + npy_intp s3 = *steps++; + +#define INIT_OUTER_LOOP_5 \ + INIT_OUTER_LOOP_4\ + npy_intp s4 = *steps++; + +#define INIT_OUTER_LOOP_6 \ + INIT_OUTER_LOOP_5\ + npy_intp s5 = *steps++; + +#define BEGIN_OUTER_LOOP_2 \ + for (N_ = 0;\ + N_ < dN;\ + N_++, args[0] += s0,\ + args[1] += s1) { + +#define BEGIN_OUTER_LOOP_3 \ + for (N_ = 0;\ + N_ < dN;\ + N_++, args[0] += s0,\ + args[1] += s1,\ + args[2] += s2) { + +#define BEGIN_OUTER_LOOP_4 \ + for (N_ = 0;\ + N_ < dN;\ + N_++, args[0] += s0,\ + args[1] += s1,\ + args[2] += s2,\ + args[3] += s3) { + +#define BEGIN_OUTER_LOOP_5 \ + for (N_ = 0;\ + N_ < dN;\ + N_++, args[0] += s0,\ + args[1] += s1,\ + args[2] += s2,\ + args[3] += s3,\ + args[4] += s4) { + +#define BEGIN_OUTER_LOOP_6 \ + for (N_ = 0;\ + N_ < dN;\ + N_++, args[0] += s0,\ + args[1] += s1,\ + args[2] += s2,\ + args[3] += s3,\ + args[4] += s4,\ + args[5] += s5) { + +#define END_OUTER_LOOP } + +static NPY_INLINE void +update_pointers(npy_uint8** bases, ptrdiff_t* offsets, size_t count) +{ + size_t i; + for (i = 0; i < count; ++i) { + bases[i] += offsets[i]; + } +} + + +/* disable -Wmaybe-uninitialized as there is some code that generate false + positives with this warning +*/ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + +/* + ***************************************************************************** + ** HELPER FUNCS ** + ***************************************************************************** + */ + + /* rearranging of 2D matrices using blas */ + +/**begin repeat + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #typ = float, double, COMPLEX_t, DOUBLECOMPLEX_t# + #copy = scopy, dcopy, ccopy, zcopy# + #nan = s_nan, d_nan, c_nan, z_nan# + */ +static NPY_INLINE void * +linearize_@TYPE@_matrix(void *dst_in, + void *src_in, + const LINEARIZE_DATA_t* data) +{ + @typ@ *src = (@typ@ *) src_in; + @typ@ *dst = (@typ@ *) dst_in; + + if (dst) { + int i, j; + @typ@* rv = dst; + fortran_int columns = (fortran_int)data->columns; + fortran_int column_strides = + (fortran_int)(data->column_strides/sizeof(@typ@)); + fortran_int one = 1; + for (i = 0; i < data->rows; i++) { + if (column_strides > 0) { + FNAME(@copy@)(&columns, + (void*)src, &column_strides, + (void*)dst, &one); + } + else if (column_strides < 0) { + FNAME(@copy@)(&columns, + (void*)((@typ@*)src + (columns-1)*column_strides), + &column_strides, + (void*)dst, &one); + } + else { + /* + * Zero stride has undefined behavior in some BLAS + * implementations (e.g. OSX Accelerate), so do it + * manually + */ + for (j = 0; j < columns; ++j) { + memcpy((@typ@*)dst + j, (@typ@*)src, sizeof(@typ@)); + } + } + src += data->row_strides/sizeof(@typ@); + dst += data->columns; + } + return rv; + } else { + return src; + } +} + +static NPY_INLINE void * +delinearize_@TYPE@_matrix(void *dst_in, + void *src_in, + const LINEARIZE_DATA_t* data) +{ + @typ@ *src = (@typ@ *) src_in; + @typ@ *dst = (@typ@ *) dst_in; + + if (src) { + int i; + @typ@ *rv = src; + fortran_int columns = (fortran_int)data->columns; + fortran_int column_strides = + (fortran_int)(data->column_strides/sizeof(@typ@)); + fortran_int one = 1; + for (i = 0; i < data->rows; i++) { + if (column_strides > 0) { + FNAME(@copy@)(&columns, + (void*)src, &one, + (void*)dst, &column_strides); + } + else if (column_strides < 0) { + FNAME(@copy@)(&columns, + (void*)src, &one, + (void*)((@typ@*)dst + (columns-1)*column_strides), + &column_strides); + } + else { + /* + * Zero stride has undefined behavior in some BLAS + * implementations (e.g. OSX Accelerate), so do it + * manually + */ + if (columns > 0) { + memcpy((@typ@*)dst, + (@typ@*)src + (columns-1), + sizeof(@typ@)); + } + } + src += data->columns; + dst += data->row_strides/sizeof(@typ@); + } + + return rv; + } else { + return src; + } +} + +static NPY_INLINE void +nan_@TYPE@_matrix(void *dst_in, const LINEARIZE_DATA_t* data) +{ + @typ@ *dst = (@typ@ *) dst_in; + + int i, j; + for (i = 0; i < data->rows; i++) { + @typ@ *cp = dst; + ptrdiff_t cs = data->column_strides/sizeof(@typ@); + for (j = 0; j < data->columns; ++j) { + *cp = @nan@; + cp += cs; + } + dst += data->row_strides/sizeof(@typ@); + } +} + +/**end repeat**/ + + /* identity square matrix generation */ +/**begin repeat + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #typ = float, double, COMPLEX_t, DOUBLECOMPLEX_t# + #cblas_type = s, d, c, z# + */ +static NPY_INLINE void +identity_@TYPE@_matrix(void *ptr, size_t n) +{ + size_t i; + @typ@ *matrix = (@typ@*) ptr; + /* in IEEE floating point, zeroes are represented as bitwise 0 */ + memset(matrix, 0, n*n*sizeof(@typ@)); + + for (i = 0; i < n; ++i) + { + *matrix = @cblas_type@_one; + matrix += n+1; + } +} +/**end repeat**/ + + /* lower/upper triangular matrix using blas (in place) */ +/**begin repeat + + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #typ = float, double, COMPLEX_t, DOUBLECOMPLEX_t# + #cblas_type = s, d, c, z# + */ + +static NPY_INLINE void +triu_@TYPE@_matrix(void *ptr, size_t n) +{ + size_t i, j; + @typ@ *matrix = (@typ@*)ptr; + matrix += n; + for (i = 1; i < n; ++i) { + for (j = 0; j < i; ++j) { + matrix[j] = @cblas_type@_zero; + } + matrix += n; + } +} +/**end repeat**/ + + +/* -------------------------------------------------------------------------- */ + /* Determinants */ + +/**begin repeat + #TYPE = FLOAT, DOUBLE# + #typ = npy_float, npy_double# + #log_func = npy_logf, npy_log# + #exp_func = npy_expf, npy_exp# + #zero = 0.0f, 0.0# +*/ + +static NPY_INLINE void +@TYPE@_slogdet_from_factored_diagonal(@typ@* src, + fortran_int m, + @typ@ *sign, + @typ@ *logdet) +{ + @typ@ acc_sign = *sign; + @typ@ acc_logdet = @zero@; + int i; + for (i = 0; i < m; i++) { + @typ@ abs_element = *src; + if (abs_element < @zero@) { + acc_sign = -acc_sign; + abs_element = -abs_element; + } + + acc_logdet += @log_func@(abs_element); + src += m+1; + } + + *sign = acc_sign; + *logdet = acc_logdet; +} + +static NPY_INLINE @typ@ +@TYPE@_det_from_slogdet(@typ@ sign, @typ@ logdet) +{ + @typ@ result = sign * @exp_func@(logdet); + return result; +} + +/**end repeat**/ + + +/**begin repeat + #TYPE = CFLOAT, CDOUBLE# + #typ = npy_cfloat, npy_cdouble# + #basetyp = npy_float, npy_double# + #abs_func = npy_cabsf, npy_cabs# + #log_func = npy_logf, npy_log# + #exp_func = npy_expf, npy_exp# + #zero = 0.0f, 0.0# +*/ +#define RE(COMPLEX) (((@basetyp@*)(&COMPLEX))[0]) +#define IM(COMPLEX) (((@basetyp@*)(&COMPLEX))[1]) + +static NPY_INLINE @typ@ +@TYPE@_mult(@typ@ op1, @typ@ op2) +{ + @typ@ rv; + + RE(rv) = RE(op1)*RE(op2) - IM(op1)*IM(op2); + IM(rv) = RE(op1)*IM(op2) + IM(op1)*RE(op2); + + return rv; +} + + +static NPY_INLINE void +@TYPE@_slogdet_from_factored_diagonal(@typ@* src, + fortran_int m, + @typ@ *sign, + @basetyp@ *logdet) +{ + int i; + @typ@ sign_acc = *sign; + @basetyp@ logdet_acc = @zero@; + + for (i = 0; i < m; i++) + { + @basetyp@ abs_element = @abs_func@(*src); + @typ@ sign_element; + RE(sign_element) = RE(*src) / abs_element; + IM(sign_element) = IM(*src) / abs_element; + + sign_acc = @TYPE@_mult(sign_acc, sign_element); + logdet_acc += @log_func@(abs_element); + src += m + 1; + } + + *sign = sign_acc; + *logdet = logdet_acc; +} + +static NPY_INLINE @typ@ +@TYPE@_det_from_slogdet(@typ@ sign, @basetyp@ logdet) +{ + @typ@ tmp; + RE(tmp) = @exp_func@(logdet); + IM(tmp) = @zero@; + return @TYPE@_mult(sign, tmp); +} +#undef RE +#undef IM +/**end repeat**/ + + +/* As in the linalg package, the determinant is computed via LU factorization + * using LAPACK. + * slogdet computes sign + log(determinant). + * det computes sign * exp(slogdet). + */ +/**begin repeat + + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #typ = npy_float, npy_double, npy_cfloat, npy_cdouble# + #basetyp = npy_float, npy_double, npy_float, npy_double# + #cblas_type = s, d, c, z# +*/ + +static NPY_INLINE void +@TYPE@_slogdet_single_element(fortran_int m, + void* src, + fortran_int* pivots, + @typ@ *sign, + @basetyp@ *logdet) +{ + fortran_int info = 0; + fortran_int lda = fortran_int_max(m, 1); + int i; + /* note: done in place */ + LAPACK(@cblas_type@getrf)(&m, &m, (void *)src, &lda, pivots, &info); + + if (info == 0) { + int change_sign = 0; + /* note: fortran uses 1 based indexing */ + for (i = 0; i < m; i++) + { + change_sign += (pivots[i] != (i+1)); + } + + memcpy(sign, + (change_sign % 2)? + &@cblas_type@_minus_one : + &@cblas_type@_one + , sizeof(*sign)); + @TYPE@_slogdet_from_factored_diagonal(src, m, sign, logdet); + } else { + /* + if getrf fails, use 0 as sign and -inf as logdet + */ + memcpy(sign, &@cblas_type@_zero, sizeof(*sign)); + memcpy(logdet, &@cblas_type@_ninf, sizeof(*logdet)); + } +} + +static void +@TYPE@_slogdet(char **args, + npy_intp *dimensions, + npy_intp *steps, + void *NPY_UNUSED(func)) +{ + fortran_int m; + npy_uint8 *tmp_buff = NULL; + size_t matrix_size; + size_t pivot_size; + size_t safe_m; + /* notes: + * matrix will need to be copied always, as factorization in lapack is + * made inplace + * matrix will need to be in column-major order, as expected by lapack + * code (fortran) + * always a square matrix + * need to allocate memory for both, matrix_buffer and pivot buffer + */ + INIT_OUTER_LOOP_3 + m = (fortran_int) dimensions[0]; + safe_m = m; + matrix_size = safe_m * safe_m * sizeof(@typ@); + pivot_size = safe_m * sizeof(fortran_int); + tmp_buff = (npy_uint8 *)malloc(matrix_size + pivot_size); + + if (tmp_buff) { + LINEARIZE_DATA_t lin_data; + /* swapped steps to get matrix in FORTRAN order */ + init_linearize_data(&lin_data, m, m, + (ptrdiff_t)steps[1], + (ptrdiff_t)steps[0]); + BEGIN_OUTER_LOOP_3 + linearize_@TYPE@_matrix(tmp_buff, args[0], &lin_data); + @TYPE@_slogdet_single_element(m, + (void*)tmp_buff, + (fortran_int*)(tmp_buff+matrix_size), + (@typ@*)args[1], + (@basetyp@*)args[2]); + END_OUTER_LOOP + + free(tmp_buff); + } +} + +static void +@TYPE@_det(char **args, + npy_intp *dimensions, + npy_intp *steps, + void *NPY_UNUSED(func)) +{ + fortran_int m; + npy_uint8 *tmp_buff; + size_t matrix_size; + size_t pivot_size; + size_t safe_m; + /* notes: + * matrix will need to be copied always, as factorization in lapack is + * made inplace + * matrix will need to be in column-major order, as expected by lapack + * code (fortran) + * always a square matrix + * need to allocate memory for both, matrix_buffer and pivot buffer + */ + INIT_OUTER_LOOP_2 + m = (fortran_int) dimensions[0]; + safe_m = m; + matrix_size = safe_m * safe_m * sizeof(@typ@); + pivot_size = safe_m * sizeof(fortran_int); + tmp_buff = (npy_uint8 *)malloc(matrix_size + pivot_size); + + if (tmp_buff) { + LINEARIZE_DATA_t lin_data; + @typ@ sign; + @basetyp@ logdet; + /* swapped steps to get matrix in FORTRAN order */ + init_linearize_data(&lin_data, m, m, + (ptrdiff_t)steps[1], + (ptrdiff_t)steps[0]); + + BEGIN_OUTER_LOOP_2 + linearize_@TYPE@_matrix(tmp_buff, args[0], &lin_data); + @TYPE@_slogdet_single_element(m, + (void*)tmp_buff, + (fortran_int*)(tmp_buff+matrix_size), + &sign, + &logdet); + *(@typ@ *)args[1] = @TYPE@_det_from_slogdet(sign, logdet); + END_OUTER_LOOP + + free(tmp_buff); + } +} +/**end repeat**/ + + +/* -------------------------------------------------------------------------- */ + /* Eigh family */ + +typedef struct eigh_params_struct { + void *A; /* matrix */ + void *W; /* eigenvalue vector */ + void *WORK; /* main work buffer */ + void *RWORK; /* secondary work buffer (for complex versions) */ + void *IWORK; + fortran_int N; + fortran_int LWORK; + fortran_int LRWORK; + fortran_int LIWORK; + char JOBZ; + char UPLO; + fortran_int LDA; +} EIGH_PARAMS_t; + +/**begin repeat + #TYPE = FLOAT, DOUBLE# + #typ = npy_float, npy_double# + #ftyp = fortran_real, fortran_doublereal# + #lapack_func = ssyevd, dsyevd# +*/ + +static NPY_INLINE fortran_int +call_@lapack_func@(EIGH_PARAMS_t *params) +{ + fortran_int rv; + LAPACK(@lapack_func@)(¶ms->JOBZ, ¶ms->UPLO, ¶ms->N, + params->A, ¶ms->LDA, params->W, + params->WORK, ¶ms->LWORK, + params->IWORK, ¶ms->LIWORK, + &rv); + return rv; +} + +/* + * Initialize the parameters to use in for the lapack function _syevd + * Handles buffer allocation + */ +static NPY_INLINE int +init_@lapack_func@(EIGH_PARAMS_t* params, char JOBZ, char UPLO, + fortran_int N) +{ + npy_uint8 *mem_buff = NULL; + npy_uint8 *mem_buff2 = NULL; + fortran_int lwork; + fortran_int liwork; + npy_uint8 *a, *w, *work, *iwork; + size_t safe_N = N; + size_t alloc_size = safe_N * (safe_N + 1) * sizeof(@typ@); + fortran_int lda = fortran_int_max(N, 1); + + mem_buff = malloc(alloc_size); + + if (!mem_buff) { + goto error; + } + a = mem_buff; + w = mem_buff + safe_N * safe_N * sizeof(@typ@); + + params->A = a; + params->W = w; + params->RWORK = NULL; /* unused */ + params->N = N; + params->LRWORK = 0; /* unused */ + params->JOBZ = JOBZ; + params->UPLO = UPLO; + params->LDA = lda; + + /* Work size query */ + { + @typ@ query_work_size; + fortran_int query_iwork_size; + + params->LWORK = -1; + params->LIWORK = -1; + params->WORK = &query_work_size; + params->IWORK = &query_iwork_size; + + if (call_@lapack_func@(params) != 0) { + goto error; + } + + lwork = (fortran_int)query_work_size; + liwork = query_iwork_size; + } + + mem_buff2 = malloc(lwork*sizeof(@typ@) + liwork*sizeof(fortran_int)); + if (!mem_buff2) { + goto error; + } + + work = mem_buff2; + iwork = mem_buff2 + lwork*sizeof(@typ@); + + params->LWORK = lwork; + params->WORK = work; + params->LIWORK = liwork; + params->IWORK = iwork; + + return 1; + + error: + /* something failed */ + memset(params, 0, sizeof(*params)); + free(mem_buff2); + free(mem_buff); + + return 0; +} +/**end repeat**/ + + +/**begin repeat + #TYPE = CFLOAT, CDOUBLE# + #typ = npy_cfloat, npy_cdouble# + #basetyp = npy_float, npy_double# + #ftyp = fortran_complex, fortran_doublecomplex# + #fbasetyp = fortran_real, fortran_doublereal# + #lapack_func = cheevd, zheevd# +*/ +static NPY_INLINE fortran_int +call_@lapack_func@(EIGH_PARAMS_t *params) +{ + fortran_int rv; + LAPACK(@lapack_func@)(¶ms->JOBZ, ¶ms->UPLO, ¶ms->N, + params->A, ¶ms->LDA, params->W, + params->WORK, ¶ms->LWORK, + params->RWORK, ¶ms->LRWORK, + params->IWORK, ¶ms->LIWORK, + &rv); + return rv; +} + +/* + * Initialize the parameters to use in for the lapack function _heev + * Handles buffer allocation + */ +static NPY_INLINE int +init_@lapack_func@(EIGH_PARAMS_t *params, + char JOBZ, + char UPLO, + fortran_int N) +{ + npy_uint8 *mem_buff = NULL; + npy_uint8 *mem_buff2 = NULL; + fortran_int lwork; + fortran_int lrwork; + fortran_int liwork; + npy_uint8 *a, *w, *work, *rwork, *iwork; + size_t safe_N = N; + fortran_int lda = fortran_int_max(N, 1); + + mem_buff = malloc(safe_N * safe_N * sizeof(@typ@) + + safe_N * sizeof(@basetyp@)); + if (!mem_buff) { + goto error; + } + a = mem_buff; + w = mem_buff + safe_N * safe_N * sizeof(@typ@); + + params->A = a; + params->W = w; + params->N = N; + params->JOBZ = JOBZ; + params->UPLO = UPLO; + params->LDA = lda; + + /* Work size query */ + { + @ftyp@ query_work_size; + @fbasetyp@ query_rwork_size; + fortran_int query_iwork_size; + + params->LWORK = -1; + params->LRWORK = -1; + params->LIWORK = -1; + params->WORK = &query_work_size; + params->RWORK = &query_rwork_size; + params->IWORK = &query_iwork_size; + + if (call_@lapack_func@(params) != 0) { + goto error; + } + + lwork = (fortran_int)*(@fbasetyp@*)&query_work_size; + lrwork = (fortran_int)query_rwork_size; + liwork = query_iwork_size; + } + + mem_buff2 = malloc(lwork*sizeof(@typ@) + + lrwork*sizeof(@basetyp@) + + liwork*sizeof(fortran_int)); + if (!mem_buff2) { + goto error; + } + + work = mem_buff2; + rwork = work + lwork*sizeof(@typ@); + iwork = rwork + lrwork*sizeof(@basetyp@); + + params->WORK = work; + params->RWORK = rwork; + params->IWORK = iwork; + params->LWORK = lwork; + params->LRWORK = lrwork; + params->LIWORK = liwork; + + return 1; + + /* something failed */ +error: + memset(params, 0, sizeof(*params)); + free(mem_buff2); + free(mem_buff); + + return 0; +} +/**end repeat**/ + + +/**begin repeat + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #BASETYPE = FLOAT, DOUBLE, FLOAT, DOUBLE# + #typ = npy_float, npy_double, npy_cfloat, npy_cdouble# + #basetyp = npy_float, npy_double, npy_float, npy_double# + #lapack_func = ssyevd, dsyevd, cheevd, zheevd# +**/ +/* + * (M, M)->(M,)(M, M) + * dimensions[1] -> M + * args[0] -> A[in] + * args[1] -> W + * args[2] -> A[out] + */ + +static NPY_INLINE void +release_@lapack_func@(EIGH_PARAMS_t *params) +{ + /* allocated memory in A and WORK */ + free(params->A); + free(params->WORK); + memset(params, 0, sizeof(*params)); +} + + +static NPY_INLINE void +@TYPE@_eigh_wrapper(char JOBZ, + char UPLO, + char**args, + npy_intp* dimensions, + npy_intp* steps) +{ + ptrdiff_t outer_steps[3]; + size_t iter; + size_t outer_dim = *dimensions++; + size_t op_count = (JOBZ=='N')?2:3; + EIGH_PARAMS_t eigh_params; + int error_occurred = get_fp_invalid_and_clear(); + + for (iter = 0; iter < op_count; ++iter) { + outer_steps[iter] = (ptrdiff_t) steps[iter]; + } + steps += op_count; + + if (init_@lapack_func@(&eigh_params, + JOBZ, + UPLO, + (fortran_int)dimensions[0])) { + LINEARIZE_DATA_t matrix_in_ld; + LINEARIZE_DATA_t eigenvectors_out_ld; + LINEARIZE_DATA_t eigenvalues_out_ld; + + init_linearize_data(&matrix_in_ld, + eigh_params.N, eigh_params.N, + steps[1], steps[0]); + init_linearize_data(&eigenvalues_out_ld, + 1, eigh_params.N, + 0, steps[2]); + if ('V' == eigh_params.JOBZ) { + init_linearize_data(&eigenvectors_out_ld, + eigh_params.N, eigh_params.N, + steps[4], steps[3]); + } + + for (iter = 0; iter < outer_dim; ++iter) { + int not_ok; + /* copy the matrix in */ + linearize_@TYPE@_matrix(eigh_params.A, args[0], &matrix_in_ld); + not_ok = call_@lapack_func@(&eigh_params); + if (!not_ok) { + /* lapack ok, copy result out */ + delinearize_@BASETYPE@_matrix(args[1], + eigh_params.W, + &eigenvalues_out_ld); + + if ('V' == eigh_params.JOBZ) { + delinearize_@TYPE@_matrix(args[2], + eigh_params.A, + &eigenvectors_out_ld); + } + } else { + /* lapack fail, set result to nan */ + error_occurred = 1; + nan_@BASETYPE@_matrix(args[1], &eigenvalues_out_ld); + if ('V' == eigh_params.JOBZ) { + nan_@TYPE@_matrix(args[2], &eigenvectors_out_ld); + } + } + update_pointers((npy_uint8**)args, outer_steps, op_count); + } + + release_@lapack_func@(&eigh_params); + } + + set_fp_invalid_or_clear(error_occurred); +} +/**end repeat**/ + + +/**begin repeat + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + */ +static void +@TYPE@_eighlo(char **args, + npy_intp *dimensions, + npy_intp *steps, + void *NPY_UNUSED(func)) +{ + @TYPE@_eigh_wrapper('V', 'L', args, dimensions, steps); +} + +static void +@TYPE@_eighup(char **args, + npy_intp *dimensions, + npy_intp *steps, + void* NPY_UNUSED(func)) +{ + @TYPE@_eigh_wrapper('V', 'U', args, dimensions, steps); +} + +static void +@TYPE@_eigvalshlo(char **args, + npy_intp *dimensions, + npy_intp *steps, + void* NPY_UNUSED(func)) +{ + @TYPE@_eigh_wrapper('N', 'L', args, dimensions, steps); +} + +static void +@TYPE@_eigvalshup(char **args, + npy_intp *dimensions, + npy_intp *steps, + void* NPY_UNUSED(func)) +{ + @TYPE@_eigh_wrapper('N', 'U', args, dimensions, steps); +} +/**end repeat**/ + +/* -------------------------------------------------------------------------- */ + /* Solve family (includes inv) */ + +typedef struct gesv_params_struct +{ + void *A; /* A is (N, N) of base type */ + void *B; /* B is (N, NRHS) of base type */ + fortran_int * IPIV; /* IPIV is (N) */ + + fortran_int N; + fortran_int NRHS; + fortran_int LDA; + fortran_int LDB; +} GESV_PARAMS_t; + +/**begin repeat + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #typ = npy_float, npy_double, npy_cfloat, npy_cdouble# + #ftyp = fortran_real, fortran_doublereal, + fortran_complex, fortran_doublecomplex# + #lapack_func = sgesv, dgesv, cgesv, zgesv# +*/ + +static NPY_INLINE fortran_int +call_@lapack_func@(GESV_PARAMS_t *params) +{ + fortran_int rv; + LAPACK(@lapack_func@)(¶ms->N, ¶ms->NRHS, + params->A, ¶ms->LDA, + params->IPIV, + params->B, ¶ms->LDB, + &rv); + return rv; +} + +/* + * Initialize the parameters to use in for the lapack function _heev + * Handles buffer allocation + */ +static NPY_INLINE int +init_@lapack_func@(GESV_PARAMS_t *params, fortran_int N, fortran_int NRHS) +{ + npy_uint8 *mem_buff = NULL; + npy_uint8 *a, *b, *ipiv; + size_t safe_N = N; + size_t safe_NRHS = NRHS; + fortran_int ld = fortran_int_max(N, 1); + mem_buff = malloc(safe_N * safe_N * sizeof(@ftyp@) + + safe_N * safe_NRHS*sizeof(@ftyp@) + + safe_N * sizeof(fortran_int)); + if (!mem_buff) { + goto error; + } + a = mem_buff; + b = a + safe_N * safe_N * sizeof(@ftyp@); + ipiv = b + safe_N * safe_NRHS * sizeof(@ftyp@); + + params->A = a; + params->B = b; + params->IPIV = (fortran_int*)ipiv; + params->N = N; + params->NRHS = NRHS; + params->LDA = ld; + params->LDB = ld; + + return 1; + error: + free(mem_buff); + memset(params, 0, sizeof(*params)); + + return 0; +} + +static NPY_INLINE void +release_@lapack_func@(GESV_PARAMS_t *params) +{ + /* memory block base is in A */ + free(params->A); + memset(params, 0, sizeof(*params)); +} + +static void +@TYPE@_solve(char **args, npy_intp *dimensions, npy_intp *steps, + void *NPY_UNUSED(func)) +{ + GESV_PARAMS_t params; + fortran_int n, nrhs; + int error_occurred = get_fp_invalid_and_clear(); + INIT_OUTER_LOOP_3 + + n = (fortran_int)dimensions[0]; + nrhs = (fortran_int)dimensions[1]; + if (init_@lapack_func@(¶ms, n, nrhs)) { + LINEARIZE_DATA_t a_in, b_in, r_out; + + init_linearize_data(&a_in, n, n, steps[1], steps[0]); + init_linearize_data(&b_in, nrhs, n, steps[3], steps[2]); + init_linearize_data(&r_out, nrhs, n, steps[5], steps[4]); + + BEGIN_OUTER_LOOP_3 + int not_ok; + linearize_@TYPE@_matrix(params.A, args[0], &a_in); + linearize_@TYPE@_matrix(params.B, args[1], &b_in); + not_ok =call_@lapack_func@(¶ms); + if (!not_ok) { + delinearize_@TYPE@_matrix(args[2], params.B, &r_out); + } else { + error_occurred = 1; + nan_@TYPE@_matrix(args[2], &r_out); + } + END_OUTER_LOOP + + release_@lapack_func@(¶ms); + } + + set_fp_invalid_or_clear(error_occurred); +} + +static void +@TYPE@_solve1(char **args, npy_intp *dimensions, npy_intp *steps, + void *NPY_UNUSED(func)) +{ + GESV_PARAMS_t params; + int error_occurred = get_fp_invalid_and_clear(); + fortran_int n; + INIT_OUTER_LOOP_3 + + n = (fortran_int)dimensions[0]; + if (init_@lapack_func@(¶ms, n, 1)) { + LINEARIZE_DATA_t a_in, b_in, r_out; + init_linearize_data(&a_in, n, n, steps[1], steps[0]); + init_linearize_data(&b_in, 1, n, 1, steps[2]); + init_linearize_data(&r_out, 1, n, 1, steps[3]); + + BEGIN_OUTER_LOOP_3 + int not_ok; + linearize_@TYPE@_matrix(params.A, args[0], &a_in); + linearize_@TYPE@_matrix(params.B, args[1], &b_in); + not_ok = call_@lapack_func@(¶ms); + if (!not_ok) { + delinearize_@TYPE@_matrix(args[2], params.B, &r_out); + } else { + error_occurred = 1; + nan_@TYPE@_matrix(args[2], &r_out); + } + END_OUTER_LOOP + + release_@lapack_func@(¶ms); + } + + set_fp_invalid_or_clear(error_occurred); +} + +static void +@TYPE@_inv(char **args, npy_intp *dimensions, npy_intp *steps, + void *NPY_UNUSED(func)) +{ + GESV_PARAMS_t params; + fortran_int n; + int error_occurred = get_fp_invalid_and_clear(); + INIT_OUTER_LOOP_2 + + n = (fortran_int)dimensions[0]; + if (init_@lapack_func@(¶ms, n, n)) { + LINEARIZE_DATA_t a_in, r_out; + init_linearize_data(&a_in, n, n, steps[1], steps[0]); + init_linearize_data(&r_out, n, n, steps[3], steps[2]); + + BEGIN_OUTER_LOOP_2 + int not_ok; + linearize_@TYPE@_matrix(params.A, args[0], &a_in); + identity_@TYPE@_matrix(params.B, n); + not_ok = call_@lapack_func@(¶ms); + if (!not_ok) { + delinearize_@TYPE@_matrix(args[1], params.B, &r_out); + } else { + error_occurred = 1; + nan_@TYPE@_matrix(args[1], &r_out); + } + END_OUTER_LOOP + + release_@lapack_func@(¶ms); + } + + set_fp_invalid_or_clear(error_occurred); +} + +/**end repeat**/ + + +/* -------------------------------------------------------------------------- */ + /* Cholesky decomposition */ + +typedef struct potr_params_struct +{ + void *A; + fortran_int N; + fortran_int LDA; + char UPLO; +} POTR_PARAMS_t; + +/**begin repeat + + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #ftyp = fortran_real, fortran_doublereal, + fortran_complex, fortran_doublecomplex# + #lapack_func = spotrf, dpotrf, cpotrf, zpotrf# + */ + +static NPY_INLINE fortran_int +call_@lapack_func@(POTR_PARAMS_t *params) +{ + fortran_int rv; + LAPACK(@lapack_func@)(¶ms->UPLO, + ¶ms->N, params->A, ¶ms->LDA, + &rv); + return rv; +} + +static NPY_INLINE int +init_@lapack_func@(POTR_PARAMS_t *params, char UPLO, fortran_int N) +{ + npy_uint8 *mem_buff = NULL; + npy_uint8 *a; + size_t safe_N = N; + fortran_int lda = fortran_int_max(N, 1); + + mem_buff = malloc(safe_N * safe_N * sizeof(@ftyp@)); + if (!mem_buff) { + goto error; + } + + a = mem_buff; + + params->A = a; + params->N = N; + params->LDA = lda; + params->UPLO = UPLO; + + return 1; + error: + free(mem_buff); + memset(params, 0, sizeof(*params)); + + return 0; +} + +static NPY_INLINE void +release_@lapack_func@(POTR_PARAMS_t *params) +{ + /* memory block base in A */ + free(params->A); + memset(params, 0, sizeof(*params)); +} + +static void +@TYPE@_cholesky(char uplo, char **args, npy_intp *dimensions, npy_intp *steps) +{ + POTR_PARAMS_t params; + int error_occurred = get_fp_invalid_and_clear(); + fortran_int n; + INIT_OUTER_LOOP_2 + + assert(uplo == 'L'); + + n = (fortran_int)dimensions[0]; + if (init_@lapack_func@(¶ms, uplo, n)) { + LINEARIZE_DATA_t a_in, r_out; + init_linearize_data(&a_in, n, n, steps[1], steps[0]); + init_linearize_data(&r_out, n, n, steps[3], steps[2]); + BEGIN_OUTER_LOOP_2 + int not_ok; + linearize_@TYPE@_matrix(params.A, args[0], &a_in); + not_ok = call_@lapack_func@(¶ms); + if (!not_ok) { + triu_@TYPE@_matrix(params.A, params.N); + delinearize_@TYPE@_matrix(args[1], params.A, &r_out); + } else { + error_occurred = 1; + nan_@TYPE@_matrix(args[1], &r_out); + } + END_OUTER_LOOP + release_@lapack_func@(¶ms); + } + + set_fp_invalid_or_clear(error_occurred); +} + +static void +@TYPE@_cholesky_lo(char **args, npy_intp *dimensions, npy_intp *steps, + void *NPY_UNUSED(func)) +{ + @TYPE@_cholesky('L', args, dimensions, steps); +} + +/**end repeat**/ + +/* -------------------------------------------------------------------------- */ + /* eig family */ + +typedef struct geev_params_struct { + void *A; + void *WR; /* RWORK in complex versions, REAL W buffer for (sd)geev*/ + void *WI; + void *VLR; /* REAL VL buffers for _geev where _ is s, d */ + void *VRR; /* REAL VR buffers for _geev hwere _ is s, d */ + void *WORK; + void *W; /* final w */ + void *VL; /* final vl */ + void *VR; /* final vr */ + + fortran_int N; + fortran_int LDA; + fortran_int LDVL; + fortran_int LDVR; + fortran_int LWORK; + + char JOBVL; + char JOBVR; +} GEEV_PARAMS_t; + +static NPY_INLINE void +dump_geev_params(const char *name, GEEV_PARAMS_t* params) +{ + TRACE_TXT("\n%s\n" + + "\t%10s: %p\n"\ + "\t%10s: %p\n"\ + "\t%10s: %p\n"\ + "\t%10s: %p\n"\ + "\t%10s: %p\n"\ + "\t%10s: %p\n"\ + "\t%10s: %p\n"\ + "\t%10s: %p\n"\ + "\t%10s: %p\n"\ + + "\t%10s: %d\n"\ + "\t%10s: %d\n"\ + "\t%10s: %d\n"\ + "\t%10s: %d\n"\ + "\t%10s: %d\n"\ + + "\t%10s: %c\n"\ + "\t%10s: %c\n", + + name, + + "A", params->A, + "WR", params->WR, + "WI", params->WI, + "VLR", params->VLR, + "VRR", params->VRR, + "WORK", params->WORK, + "W", params->W, + "VL", params->VL, + "VR", params->VR, + + "N", (int)params->N, + "LDA", (int)params->LDA, + "LDVL", (int)params->LDVL, + "LDVR", (int)params->LDVR, + "LWORK", (int)params->LWORK, + + "JOBVL", params->JOBVL, + "JOBVR", params->JOBVR); +} + +/**begin repeat + #TYPE = FLOAT, DOUBLE# + #CTYPE = CFLOAT, CDOUBLE# + #typ = float, double# + #complextyp = COMPLEX_t, DOUBLECOMPLEX_t# + #lapack_func = sgeev, dgeev# + #zero = 0.0f, 0.0# +*/ + +static NPY_INLINE fortran_int +call_@lapack_func@(GEEV_PARAMS_t* params) +{ + fortran_int rv; + LAPACK(@lapack_func@)(¶ms->JOBVL, ¶ms->JOBVR, + ¶ms->N, params->A, ¶ms->LDA, + params->WR, params->WI, + params->VLR, ¶ms->LDVL, + params->VRR, ¶ms->LDVR, + params->WORK, ¶ms->LWORK, + &rv); + return rv; +} + +static NPY_INLINE int +init_@lapack_func@(GEEV_PARAMS_t *params, char jobvl, char jobvr, fortran_int n) +{ + npy_uint8 *mem_buff = NULL; + npy_uint8 *mem_buff2 = NULL; + npy_uint8 *a, *wr, *wi, *vlr, *vrr, *work, *w, *vl, *vr; + size_t safe_n = n; + size_t a_size = safe_n * safe_n * sizeof(@typ@); + size_t wr_size = safe_n * sizeof(@typ@); + size_t wi_size = safe_n * sizeof(@typ@); + size_t vlr_size = jobvl=='V' ? safe_n * safe_n * sizeof(@typ@) : 0; + size_t vrr_size = jobvr=='V' ? safe_n * safe_n * sizeof(@typ@) : 0; + size_t w_size = wr_size*2; + size_t vl_size = vlr_size*2; + size_t vr_size = vrr_size*2; + size_t work_count = 0; + fortran_int ld = fortran_int_max(n, 1); + + /* allocate data for known sizes (all but work) */ + mem_buff = malloc(a_size + wr_size + wi_size + + vlr_size + vrr_size + + w_size + vl_size + vr_size); + if (!mem_buff) { + goto error; + } + + a = mem_buff; + wr = a + a_size; + wi = wr + wr_size; + vlr = wi + wi_size; + vrr = vlr + vlr_size; + w = vrr + vrr_size; + vl = w + w_size; + vr = vl + vl_size; + + params->A = a; + params->WR = wr; + params->WI = wi; + params->VLR = vlr; + params->VRR = vrr; + params->W = w; + params->VL = vl; + params->VR = vr; + params->N = n; + params->LDA = ld; + params->LDVL = ld; + params->LDVR = ld; + params->JOBVL = jobvl; + params->JOBVR = jobvr; + + /* Work size query */ + { + @typ@ work_size_query; + + params->LWORK = -1; + params->WORK = &work_size_query; + + if (call_@lapack_func@(params) != 0) { + goto error; + } + + work_count = (size_t)work_size_query; + } + + mem_buff2 = malloc(work_count*sizeof(@typ@)); + if (!mem_buff2) { + goto error; + } + work = mem_buff2; + + params->LWORK = (fortran_int)work_count; + params->WORK = work; + + return 1; + error: + free(mem_buff2); + free(mem_buff); + memset(params, 0, sizeof(*params)); + + return 0; +} + +static NPY_INLINE void +mk_@TYPE@_complex_array_from_real(@complextyp@ *c, const @typ@ *re, size_t n) +{ + size_t iter; + for (iter = 0; iter < n; ++iter) { + c[iter].array[0] = re[iter]; + c[iter].array[1] = @zero@; + } +} + +static NPY_INLINE void +mk_@TYPE@_complex_array(@complextyp@ *c, + const @typ@ *re, + const @typ@ *im, + size_t n) +{ + size_t iter; + for (iter = 0; iter < n; ++iter) { + c[iter].array[0] = re[iter]; + c[iter].array[1] = im[iter]; + } +} + +static NPY_INLINE void +mk_@TYPE@_complex_array_conjugate_pair(@complextyp@ *c, + const @typ@ *r, + size_t n) +{ + size_t iter; + for (iter = 0; iter < n; ++iter) { + @typ@ re = r[iter]; + @typ@ im = r[iter+n]; + c[iter].array[0] = re; + c[iter].array[1] = im; + c[iter+n].array[0] = re; + c[iter+n].array[1] = -im; + } +} + +/* + * make the complex eigenvectors from the real array produced by sgeev/zgeev. + * c is the array where the results will be left. + * r is the source array of reals produced by sgeev/zgeev + * i is the eigenvalue imaginary part produced by sgeev/zgeev + * n is so that the order of the matrix is n by n + */ +static NPY_INLINE void +mk_@lapack_func@_complex_eigenvectors(@complextyp@ *c, + const @typ@ *r, + const @typ@ *i, + size_t n) +{ + size_t iter = 0; + while (iter < n) + { + if (i[iter] == @zero@) { + /* eigenvalue was real, eigenvectors as well... */ + mk_@TYPE@_complex_array_from_real(c, r, n); + c += n; + r += n; + iter ++; + } else { + /* eigenvalue was complex, generate a pair of eigenvectors */ + mk_@TYPE@_complex_array_conjugate_pair(c, r, n); + c += 2*n; + r += 2*n; + iter += 2; + } + } +} + + +static NPY_INLINE void +process_@lapack_func@_results(GEEV_PARAMS_t *params) +{ + /* REAL versions of geev need the results to be translated + * into complex versions. This is the way to deal with imaginary + * results. In our gufuncs we will always return complex arrays! + */ + mk_@TYPE@_complex_array(params->W, params->WR, params->WI, params->N); + + /* handle the eigenvectors */ + if ('V' == params->JOBVL) { + mk_@lapack_func@_complex_eigenvectors(params->VL, params->VLR, + params->WI, params->N); + } + if ('V' == params->JOBVR) { + mk_@lapack_func@_complex_eigenvectors(params->VR, params->VRR, + params->WI, params->N); + } +} + +/**end repeat**/ + + +/**begin repeat + #TYPE = CFLOAT, CDOUBLE# + #typ = COMPLEX_t, DOUBLECOMPLEX_t# + #ftyp = fortran_complex, fortran_doublecomplex# + #realtyp = float, double# + #lapack_func = cgeev, zgeev# + */ + +static NPY_INLINE fortran_int +call_@lapack_func@(GEEV_PARAMS_t* params) +{ + fortran_int rv; + + LAPACK(@lapack_func@)(¶ms->JOBVL, ¶ms->JOBVR, + ¶ms->N, params->A, ¶ms->LDA, + params->W, + params->VL, ¶ms->LDVL, + params->VR, ¶ms->LDVR, + params->WORK, ¶ms->LWORK, + params->WR, /* actually RWORK */ + &rv); + return rv; +} + +static NPY_INLINE int +init_@lapack_func@(GEEV_PARAMS_t* params, + char jobvl, + char jobvr, + fortran_int n) +{ + npy_uint8 *mem_buff = NULL; + npy_uint8 *mem_buff2 = NULL; + npy_uint8 *a, *w, *vl, *vr, *work, *rwork; + size_t safe_n = n; + size_t a_size = safe_n * safe_n * sizeof(@ftyp@); + size_t w_size = safe_n * sizeof(@ftyp@); + size_t vl_size = jobvl=='V'? safe_n * safe_n * sizeof(@ftyp@) : 0; + size_t vr_size = jobvr=='V'? safe_n * safe_n * sizeof(@ftyp@) : 0; + size_t rwork_size = 2 * safe_n * sizeof(@realtyp@); + size_t work_count = 0; + size_t total_size = a_size + w_size + vl_size + vr_size + rwork_size; + fortran_int ld = fortran_int_max(n, 1); + + mem_buff = malloc(total_size); + if (!mem_buff) { + goto error; + } + + a = mem_buff; + w = a + a_size; + vl = w + w_size; + vr = vl + vl_size; + rwork = vr + vr_size; + + params->A = a; + params->WR = rwork; + params->WI = NULL; + params->VLR = NULL; + params->VRR = NULL; + params->VL = vl; + params->VR = vr; + params->W = w; + params->N = n; + params->LDA = ld; + params->LDVL = ld; + params->LDVR = ld; + params->JOBVL = jobvl; + params->JOBVR = jobvr; + + /* Work size query */ + { + @typ@ work_size_query; + + params->LWORK = -1; + params->WORK = &work_size_query; + + if (call_@lapack_func@(params) != 0) { + goto error; + } + + work_count = (size_t) work_size_query.array[0]; + /* Fix a bug in lapack 3.0.0 */ + if(work_count == 0) work_count = 1; + } + + mem_buff2 = malloc(work_count*sizeof(@ftyp@)); + if (!mem_buff2) { + goto error; + } + + work = mem_buff2; + + params->LWORK = (fortran_int)work_count; + params->WORK = work; + + return 1; + error: + free(mem_buff2); + free(mem_buff); + memset(params, 0, sizeof(*params)); + + return 0; +} + + +static NPY_INLINE void +process_@lapack_func@_results(GEEV_PARAMS_t *NPY_UNUSED(params)) +{ + /* nothing to do here, complex versions are ready to copy out */ +} +/**end repeat**/ + + +/**begin repeat + #TYPE = FLOAT, DOUBLE, CDOUBLE# + #COMPLEXTYPE = CFLOAT, CDOUBLE, CDOUBLE# + #ftype = fortran_real, fortran_doublereal, fortran_doublecomplex# + #lapack_func = sgeev, dgeev, zgeev# + */ + +static NPY_INLINE void +release_@lapack_func@(GEEV_PARAMS_t *params) +{ + free(params->WORK); + free(params->A); + memset(params, 0, sizeof(*params)); +} + +static NPY_INLINE void +@TYPE@_eig_wrapper(char JOBVL, + char JOBVR, + char**args, + npy_intp* dimensions, + npy_intp* steps) +{ + ptrdiff_t outer_steps[4]; + size_t iter; + size_t outer_dim = *dimensions++; + size_t op_count = 2; + int error_occurred = get_fp_invalid_and_clear(); + GEEV_PARAMS_t geev_params; + + assert(JOBVL == 'N'); + + STACK_TRACE; + op_count += 'V'==JOBVL?1:0; + op_count += 'V'==JOBVR?1:0; + + for (iter = 0; iter < op_count; ++iter) { + outer_steps[iter] = (ptrdiff_t) steps[iter]; + } + steps += op_count; + + if (init_@lapack_func@(&geev_params, + JOBVL, JOBVR, + (fortran_int)dimensions[0])) { + LINEARIZE_DATA_t a_in; + LINEARIZE_DATA_t w_out; + LINEARIZE_DATA_t vl_out; + LINEARIZE_DATA_t vr_out; + + init_linearize_data(&a_in, + geev_params.N, geev_params.N, + steps[1], steps[0]); + steps += 2; + init_linearize_data(&w_out, + 1, geev_params.N, + 0, steps[0]); + steps += 1; + if ('V' == geev_params.JOBVL) { + init_linearize_data(&vl_out, + geev_params.N, geev_params.N, + steps[1], steps[0]); + steps += 2; + } + if ('V' == geev_params.JOBVR) { + init_linearize_data(&vr_out, + geev_params.N, geev_params.N, + steps[1], steps[0]); + } + + for (iter = 0; iter < outer_dim; ++iter) { + int not_ok; + char **arg_iter = args; + /* copy the matrix in */ + linearize_@TYPE@_matrix(geev_params.A, *arg_iter++, &a_in); + not_ok = call_@lapack_func@(&geev_params); + + if (!not_ok) { + process_@lapack_func@_results(&geev_params); + delinearize_@COMPLEXTYPE@_matrix(*arg_iter++, + geev_params.W, + &w_out); + + if ('V' == geev_params.JOBVL) { + delinearize_@COMPLEXTYPE@_matrix(*arg_iter++, + geev_params.VL, + &vl_out); + } + if ('V' == geev_params.JOBVR) { + delinearize_@COMPLEXTYPE@_matrix(*arg_iter++, + geev_params.VR, + &vr_out); + } + } else { + /* geev failed */ + error_occurred = 1; + nan_@COMPLEXTYPE@_matrix(*arg_iter++, &w_out); + if ('V' == geev_params.JOBVL) { + nan_@COMPLEXTYPE@_matrix(*arg_iter++, &vl_out); + } + if ('V' == geev_params.JOBVR) { + nan_@COMPLEXTYPE@_matrix(*arg_iter++, &vr_out); + } + } + update_pointers((npy_uint8**)args, outer_steps, op_count); + } + + release_@lapack_func@(&geev_params); + } + + set_fp_invalid_or_clear(error_occurred); +} + +static void +@TYPE@_eig(char **args, + npy_intp *dimensions, + npy_intp *steps, + void *NPY_UNUSED(func)) +{ + @TYPE@_eig_wrapper('N', 'V', args, dimensions, steps); +} + +static void +@TYPE@_eigvals(char **args, + npy_intp *dimensions, + npy_intp *steps, + void *NPY_UNUSED(func)) +{ + @TYPE@_eig_wrapper('N', 'N', args, dimensions, steps); +} + +/**end repeat**/ + + +/* -------------------------------------------------------------------------- */ + /* singular value decomposition */ + +typedef struct gessd_params_struct +{ + void *A; + void *S; + void *U; + void *VT; + void *WORK; + void *RWORK; + void *IWORK; + + fortran_int M; + fortran_int N; + fortran_int LDA; + fortran_int LDU; + fortran_int LDVT; + fortran_int LWORK; + char JOBZ; +} GESDD_PARAMS_t; + + +static NPY_INLINE void +dump_gesdd_params(const char *name, + GESDD_PARAMS_t *params) +{ + TRACE_TXT("\n%s:\n"\ + + "%14s: %18p\n"\ + "%14s: %18p\n"\ + "%14s: %18p\n"\ + "%14s: %18p\n"\ + "%14s: %18p\n"\ + "%14s: %18p\n"\ + "%14s: %18p\n"\ + + "%14s: %18d\n"\ + "%14s: %18d\n"\ + "%14s: %18d\n"\ + "%14s: %18d\n"\ + "%14s: %18d\n"\ + "%14s: %18d\n"\ + + "%14s: %15c'%c'\n", + + name, + + "A", params->A, + "S", params->S, + "U", params->U, + "VT", params->VT, + "WORK", params->WORK, + "RWORK", params->RWORK, + "IWORK", params->IWORK, + + "M", (int)params->M, + "N", (int)params->N, + "LDA", (int)params->LDA, + "LDU", (int)params->LDU, + "LDVT", (int)params->LDVT, + "LWORK", (int)params->LWORK, + + "JOBZ", ' ', params->JOBZ); +} + +static NPY_INLINE int +compute_urows_vtcolumns(char jobz, + fortran_int m, fortran_int n, + fortran_int *urows, fortran_int *vtcolumns) +{ + fortran_int min_m_n = fortran_int_min(m, n); + switch(jobz) + { + case 'N': + *urows = 0; + *vtcolumns = 0; + break; + case 'A': + *urows = m; + *vtcolumns = n; + break; + case 'S': + { + *urows = min_m_n; + *vtcolumns = min_m_n; + } + break; + default: + return 0; + } + + return 1; +} + + +/**begin repeat + #TYPE = FLOAT, DOUBLE# + #lapack_func = sgesdd, dgesdd# + #ftyp = fortran_real, fortran_doublereal# + */ + +static NPY_INLINE fortran_int +call_@lapack_func@(GESDD_PARAMS_t *params) +{ + fortran_int rv; + LAPACK(@lapack_func@)(¶ms->JOBZ, ¶ms->M, ¶ms->N, + params->A, ¶ms->LDA, + params->S, + params->U, ¶ms->LDU, + params->VT, ¶ms->LDVT, + params->WORK, ¶ms->LWORK, + params->IWORK, + &rv); + return rv; +} + +static NPY_INLINE int +init_@lapack_func@(GESDD_PARAMS_t *params, + char jobz, + fortran_int m, + fortran_int n) +{ + npy_uint8 *mem_buff = NULL; + npy_uint8 *mem_buff2 = NULL; + npy_uint8 *a, *s, *u, *vt, *work, *iwork; + size_t safe_m = m; + size_t safe_n = n; + size_t a_size = safe_m * safe_n * sizeof(@ftyp@); + fortran_int min_m_n = fortran_int_min(m, n); + size_t safe_min_m_n = min_m_n; + size_t s_size = safe_min_m_n * sizeof(@ftyp@); + fortran_int u_row_count, vt_column_count; + size_t safe_u_row_count, safe_vt_column_count; + size_t u_size, vt_size; + fortran_int work_count; + size_t work_size; + size_t iwork_size = 8 * safe_min_m_n * sizeof(fortran_int); + fortran_int ld = fortran_int_max(m, 1); + + if (!compute_urows_vtcolumns(jobz, m, n, &u_row_count, &vt_column_count)) { + goto error; + } + + safe_u_row_count = u_row_count; + safe_vt_column_count = vt_column_count; + + u_size = safe_u_row_count * safe_m * sizeof(@ftyp@); + vt_size = safe_n * safe_vt_column_count * sizeof(@ftyp@); + + mem_buff = malloc(a_size + s_size + u_size + vt_size + iwork_size); + + if (!mem_buff) { + goto error; + } + + a = mem_buff; + s = a + a_size; + u = s + s_size; + vt = u + u_size; + iwork = vt + vt_size; + + /* fix vt_column_count so that it is a valid lapack parameter (0 is not) */ + vt_column_count = fortran_int_max(1, vt_column_count); + + params->M = m; + params->N = n; + params->A = a; + params->S = s; + params->U = u; + params->VT = vt; + params->RWORK = NULL; + params->IWORK = iwork; + params->M = m; + params->N = n; + params->LDA = ld; + params->LDU = ld; + params->LDVT = vt_column_count; + params->JOBZ = jobz; + + /* Work size query */ + { + @ftyp@ work_size_query; + + params->LWORK = -1; + params->WORK = &work_size_query; + + if (call_@lapack_func@(params) != 0) { + goto error; + } + + work_count = (fortran_int)work_size_query; + /* Fix a bug in lapack 3.0.0 */ + if(work_count == 0) work_count = 1; + work_size = (size_t)work_count * sizeof(@ftyp@); + } + + mem_buff2 = malloc(work_size); + if (!mem_buff2) { + goto error; + } + + work = mem_buff2; + + params->LWORK = work_count; + params->WORK = work; + + return 1; + error: + TRACE_TXT("%s failed init\n", __FUNCTION__); + free(mem_buff); + free(mem_buff2); + memset(params, 0, sizeof(*params)); + + return 0; +} + +/**end repeat**/ + +/**begin repeat + #TYPE = CFLOAT, CDOUBLE# + #ftyp = fortran_complex, fortran_doublecomplex# + #frealtyp = fortran_real, fortran_doublereal# + #typ = COMPLEX_t, DOUBLECOMPLEX_t# + #lapack_func = cgesdd, zgesdd# + */ + +static NPY_INLINE fortran_int +call_@lapack_func@(GESDD_PARAMS_t *params) +{ + fortran_int rv; + LAPACK(@lapack_func@)(¶ms->JOBZ, ¶ms->M, ¶ms->N, + params->A, ¶ms->LDA, + params->S, + params->U, ¶ms->LDU, + params->VT, ¶ms->LDVT, + params->WORK, ¶ms->LWORK, + params->RWORK, + params->IWORK, + &rv); + return rv; +} + +static NPY_INLINE int +init_@lapack_func@(GESDD_PARAMS_t *params, + char jobz, + fortran_int m, + fortran_int n) +{ + npy_uint8 *mem_buff = NULL, *mem_buff2 = NULL; + npy_uint8 *a,*s, *u, *vt, *work, *rwork, *iwork; + size_t a_size, s_size, u_size, vt_size, work_size, rwork_size, iwork_size; + size_t safe_u_row_count, safe_vt_column_count; + fortran_int u_row_count, vt_column_count, work_count; + size_t safe_m = m; + size_t safe_n = n; + fortran_int min_m_n = fortran_int_min(m, n); + size_t safe_min_m_n = min_m_n; + fortran_int ld = fortran_int_max(m, 1); + + if (!compute_urows_vtcolumns(jobz, m, n, &u_row_count, &vt_column_count)) { + goto error; + } + + safe_u_row_count = u_row_count; + safe_vt_column_count = vt_column_count; + + a_size = safe_m * safe_n * sizeof(@ftyp@); + s_size = safe_min_m_n * sizeof(@frealtyp@); + u_size = safe_u_row_count * safe_m * sizeof(@ftyp@); + vt_size = safe_n * safe_vt_column_count * sizeof(@ftyp@); + rwork_size = 'N'==jobz? + (7 * safe_min_m_n) : + (5*safe_min_m_n * safe_min_m_n + 5*safe_min_m_n); + rwork_size *= sizeof(@ftyp@); + iwork_size = 8 * safe_min_m_n* sizeof(fortran_int); + + mem_buff = malloc(a_size + + s_size + + u_size + + vt_size + + rwork_size + + iwork_size); + if (!mem_buff) { + goto error; + } + + a = mem_buff; + s = a + a_size; + u = s + s_size; + vt = u + u_size; + rwork = vt + vt_size; + iwork = rwork + rwork_size; + + /* fix vt_column_count so that it is a valid lapack parameter (0 is not) */ + vt_column_count = fortran_int_max(1, vt_column_count); + + params->A = a; + params->S = s; + params->U = u; + params->VT = vt; + params->RWORK = rwork; + params->IWORK = iwork; + params->M = m; + params->N = n; + params->LDA = ld; + params->LDU = ld; + params->LDVT = vt_column_count; + params->JOBZ = jobz; + + /* Work size query */ + { + @ftyp@ work_size_query; + + params->LWORK = -1; + params->WORK = &work_size_query; + + if (call_@lapack_func@(params) != 0) { + goto error; + } + + work_count = (fortran_int)((@typ@*)&work_size_query)->array[0]; + /* Fix a bug in lapack 3.0.0 */ + if(work_count == 0) work_count = 1; + work_size = (size_t)work_count * sizeof(@ftyp@); + } + + mem_buff2 = malloc(work_size); + if (!mem_buff2) { + goto error; + } + + work = mem_buff2; + + params->LWORK = work_count; + params->WORK = work; + + return 1; + error: + TRACE_TXT("%s failed init\n", __FUNCTION__); + free(mem_buff2); + free(mem_buff); + memset(params, 0, sizeof(*params)); + + return 0; +} +/**end repeat**/ + + +/**begin repeat + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + #REALTYPE = FLOAT, DOUBLE, FLOAT, DOUBLE# + #lapack_func = sgesdd, dgesdd, cgesdd, zgesdd# + */ +static NPY_INLINE void +release_@lapack_func@(GESDD_PARAMS_t* params) +{ + /* A and WORK contain allocated blocks */ + free(params->A); + free(params->WORK); + memset(params, 0, sizeof(*params)); +} + +static NPY_INLINE void +@TYPE@_svd_wrapper(char JOBZ, + char **args, + npy_intp* dimensions, + npy_intp* steps) +{ + ptrdiff_t outer_steps[4]; + int error_occurred = get_fp_invalid_and_clear(); + size_t iter; + size_t outer_dim = *dimensions++; + size_t op_count = (JOBZ=='N')?2:4; + GESDD_PARAMS_t params; + + for (iter = 0; iter < op_count; ++iter) { + outer_steps[iter] = (ptrdiff_t) steps[iter]; + } + steps += op_count; + + if (init_@lapack_func@(¶ms, + JOBZ, + (fortran_int)dimensions[0], + (fortran_int)dimensions[1])) { + LINEARIZE_DATA_t a_in, u_out, s_out, v_out; + + init_linearize_data(&a_in, params.N, params.M, steps[1], steps[0]); + if ('N' == params.JOBZ) { + /* only the singular values are wanted */ + fortran_int min_m_n = params.M < params.N? params.M : params.N; + init_linearize_data(&s_out, 1, min_m_n, 0, steps[2]); + } else { + fortran_int u_columns, v_rows; + fortran_int min_m_n = params.M < params.N? params.M : params.N; + if ('S' == params.JOBZ) { + u_columns = min_m_n; + v_rows = min_m_n; + } else { + u_columns = params.M; + v_rows = params.N; + } + init_linearize_data(&u_out, + u_columns, params.M, + steps[3], steps[2]); + init_linearize_data(&s_out, + 1, min_m_n, + 0, steps[4]); + init_linearize_data(&v_out, + params.N, v_rows, + steps[6], steps[5]); + } + + for (iter = 0; iter < outer_dim; ++iter) { + int not_ok; + /* copy the matrix in */ + linearize_@TYPE@_matrix(params.A, args[0], &a_in); + not_ok = call_@lapack_func@(¶ms); + if (!not_ok) { + if ('N' == params.JOBZ) { + delinearize_@REALTYPE@_matrix(args[1], params.S, &s_out); + } else { + delinearize_@TYPE@_matrix(args[1], params.U, &u_out); + delinearize_@REALTYPE@_matrix(args[2], params.S, &s_out); + delinearize_@TYPE@_matrix(args[3], params.VT, &v_out); + } + } else { + error_occurred = 1; + if ('N' == params.JOBZ) { + nan_@REALTYPE@_matrix(args[1], &s_out); + } else { + nan_@TYPE@_matrix(args[1], &u_out); + nan_@REALTYPE@_matrix(args[2], &s_out); + nan_@TYPE@_matrix(args[3], &v_out); + } + } + update_pointers((npy_uint8**)args, outer_steps, op_count); + } + + release_@lapack_func@(¶ms); + } + + set_fp_invalid_or_clear(error_occurred); +} +/**end repeat*/ + + +/* svd gufunc entry points */ +/**begin repeat + #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE# + */ +static void +@TYPE@_svd_N(char **args, + npy_intp *dimensions, + npy_intp *steps, + void *NPY_UNUSED(func)) +{ + @TYPE@_svd_wrapper('N', args, dimensions, steps); +} + +static void +@TYPE@_svd_S(char **args, + npy_intp *dimensions, + npy_intp *steps, + void *NPY_UNUSED(func)) +{ + @TYPE@_svd_wrapper('S', args, dimensions, steps); +} + +static void +@TYPE@_svd_A(char **args, + npy_intp *dimensions, + npy_intp *steps, + void *NPY_UNUSED(func)) +{ + @TYPE@_svd_wrapper('A', args, dimensions, steps); +} + +/**end repeat**/ + +#pragma GCC diagnostic pop + +/* -------------------------------------------------------------------------- */ + /* gufunc registration */ + +static void *array_of_nulls[] = { + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL +}; + +#define FUNC_ARRAY_NAME(NAME) NAME ## _funcs + +#define GUFUNC_FUNC_ARRAY_REAL(NAME) \ + static PyUFuncGenericFunction \ + FUNC_ARRAY_NAME(NAME)[] = { \ + FLOAT_ ## NAME, \ + DOUBLE_ ## NAME \ + } + +#define GUFUNC_FUNC_ARRAY_REAL_COMPLEX(NAME) \ + static PyUFuncGenericFunction \ + FUNC_ARRAY_NAME(NAME)[] = { \ + FLOAT_ ## NAME, \ + DOUBLE_ ## NAME, \ + CFLOAT_ ## NAME, \ + CDOUBLE_ ## NAME \ + } + +/* There are problems with eig in complex single precision. + * That kernel is disabled + */ +#define GUFUNC_FUNC_ARRAY_EIG(NAME) \ + static PyUFuncGenericFunction \ + FUNC_ARRAY_NAME(NAME)[] = { \ + FLOAT_ ## NAME, \ + DOUBLE_ ## NAME, \ + CDOUBLE_ ## NAME \ + } + + +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(slogdet); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(det); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(eighlo); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(eighup); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(eigvalshlo); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(eigvalshup); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(solve); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(solve1); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(inv); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(cholesky_lo); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(svd_N); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(svd_S); +GUFUNC_FUNC_ARRAY_REAL_COMPLEX(svd_A); +GUFUNC_FUNC_ARRAY_EIG(eig); +GUFUNC_FUNC_ARRAY_EIG(eigvals); + +static char equal_2_types[] = { + NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, + NPY_CFLOAT, NPY_CFLOAT, + NPY_CDOUBLE, NPY_CDOUBLE +}; + +static char equal_3_types[] = { + NPY_FLOAT, NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, + NPY_CFLOAT, NPY_CFLOAT, NPY_CFLOAT, + NPY_CDOUBLE, NPY_CDOUBLE, NPY_CDOUBLE +}; + +/* second result is logdet, that will always be a REAL */ +static char slogdet_types[] = { + NPY_FLOAT, NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, + NPY_CFLOAT, NPY_CFLOAT, NPY_FLOAT, + NPY_CDOUBLE, NPY_CDOUBLE, NPY_DOUBLE +}; + +static char eigh_types[] = { + NPY_FLOAT, NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, + NPY_CFLOAT, NPY_FLOAT, NPY_CFLOAT, + NPY_CDOUBLE, NPY_DOUBLE, NPY_CDOUBLE +}; + +static char eighvals_types[] = { + NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, + NPY_CFLOAT, NPY_FLOAT, + NPY_CDOUBLE, NPY_DOUBLE +}; + +static char eig_types[] = { + NPY_FLOAT, NPY_CFLOAT, NPY_CFLOAT, + NPY_DOUBLE, NPY_CDOUBLE, NPY_CDOUBLE, + NPY_CDOUBLE, NPY_CDOUBLE, NPY_CDOUBLE +}; + +static char eigvals_types[] = { + NPY_FLOAT, NPY_CFLOAT, + NPY_DOUBLE, NPY_CDOUBLE, + NPY_CDOUBLE, NPY_CDOUBLE +}; + +static char svd_1_1_types[] = { + NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, + NPY_CFLOAT, NPY_FLOAT, + NPY_CDOUBLE, NPY_DOUBLE +}; + +static char svd_1_3_types[] = { + NPY_FLOAT, NPY_FLOAT, NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, + NPY_CFLOAT, NPY_CFLOAT, NPY_FLOAT, NPY_CFLOAT, + NPY_CDOUBLE, NPY_CDOUBLE, NPY_DOUBLE, NPY_CDOUBLE +}; + +typedef struct gufunc_descriptor_struct { + char *name; + char *signature; + char *doc; + int ntypes; + int nin; + int nout; + PyUFuncGenericFunction *funcs; + char *types; +} GUFUNC_DESCRIPTOR_t; + +GUFUNC_DESCRIPTOR_t gufunc_descriptors [] = { + { + "slogdet", + "(m,m)->(),()", + "slogdet on the last two dimensions and broadcast on the rest. \n"\ + "Results in two arrays, one with sign and the other with log of the"\ + " determinants. \n"\ + " \"(m,m)->(),()\" \n", + 4, 1, 2, + FUNC_ARRAY_NAME(slogdet), + slogdet_types + }, + { + "det", + "(m,m)->()", + "det of the last two dimensions and broadcast on the rest. \n"\ + " \"(m,m)->()\" \n", + 4, 1, 1, + FUNC_ARRAY_NAME(det), + equal_2_types + }, + { + "eigh_lo", + "(m,m)->(m),(m,m)", + "eigh on the last two dimension and broadcast to the rest, using"\ + " lower triangle \n"\ + "Results in a vector of eigenvalues and a matrix with the"\ + "eigenvectors. \n"\ + " \"(m,m)->(m),(m,m)\" \n", + 4, 1, 2, + FUNC_ARRAY_NAME(eighlo), + eigh_types + }, + { + "eigh_up", + "(m,m)->(m),(m,m)", + "eigh on the last two dimension and broadcast to the rest, using"\ + " upper triangle. \n"\ + "Results in a vector of eigenvalues and a matrix with the"\ + " eigenvectors. \n"\ + " \"(m,m)->(m),(m,m)\" \n", + 4, 1, 2, + FUNC_ARRAY_NAME(eighup), + eigh_types + }, + { + "eigvalsh_lo", + "(m,m)->(m)", + "eigh on the last two dimension and broadcast to the rest, using"\ + " lower triangle. \n"\ + "Results in a vector of eigenvalues and a matrix with the"\ + "eigenvectors. \n"\ + " \"(m,m)->(m)\" \n", + 4, 1, 1, + FUNC_ARRAY_NAME(eigvalshlo), + eighvals_types + }, + { + "eigvalsh_up", + "(m,m)->(m)", + "eigvalsh on the last two dimension and broadcast to the rest,"\ + " using upper triangle. \n"\ + "Results in a vector of eigenvalues and a matrix with the"\ + "eigenvectors.\n"\ + " \"(m,m)->(m)\" \n", + 4, 1, 1, + FUNC_ARRAY_NAME(eigvalshup), + eighvals_types + }, + { + "solve", + "(m,m),(m,n)->(m,n)", + "solve the system a x = b, on the last two dimensions, broadcast"\ + " to the rest. \n"\ + "Results in a matrices with the solutions. \n"\ + " \"(m,m),(m,n)->(m,n)\" \n", + 4, 2, 1, + FUNC_ARRAY_NAME(solve), + equal_3_types + }, + { + "solve1", + "(m,m),(m)->(m)", + "solve the system a x = b, for b being a vector, broadcast in"\ + " the outer dimensions. \n"\ + "Results in vectors with the solutions. \n"\ + " \"(m,m),(m)->(m)\" \n", + 4, 2, 1, + FUNC_ARRAY_NAME(solve1), + equal_3_types + }, + { + "inv", + "(m, m)->(m, m)", + "compute the inverse of the last two dimensions and broadcast"\ + " to the rest. \n"\ + "Results in the inverse matrices. \n"\ + " \"(m,m)->(m,m)\" \n", + 4, 1, 1, + FUNC_ARRAY_NAME(inv), + equal_2_types + }, + { + "cholesky_lo", + "(m,m)->(m,m)", + "cholesky decomposition of hermitian positive-definite matrices. \n"\ + "Broadcast to all outer dimensions. \n"\ + " \"(m,m)->(m,m)\" \n", + 4, 1, 1, + FUNC_ARRAY_NAME(cholesky_lo), + equal_2_types + }, + { + "svd_m", + "(m,n)->(m)", + "svd when n>=m. ", + 4, 1, 1, + FUNC_ARRAY_NAME(svd_N), + svd_1_1_types + }, + { + "svd_n", + "(m,n)->(n)", + "svd when n<=m", + 4, 1, 1, + FUNC_ARRAY_NAME(svd_N), + svd_1_1_types + }, + { + "svd_m_s", + "(m,n)->(m,m),(m),(m,n)", + "svd when m<=n", + 4, 1, 3, + FUNC_ARRAY_NAME(svd_S), + svd_1_3_types + }, + { + "svd_n_s", + "(m,n)->(m,n),(n),(n,n)", + "svd when m>=n", + 4, 1, 3, + FUNC_ARRAY_NAME(svd_S), + svd_1_3_types + }, + { + "svd_m_f", + "(m,n)->(m,m),(m),(n,n)", + "svd when m<=n", + 4, 1, 3, + FUNC_ARRAY_NAME(svd_A), + svd_1_3_types + }, + { + "svd_n_f", + "(m,n)->(m,m),(n),(n,n)", + "svd when m>=n", + 4, 1, 3, + FUNC_ARRAY_NAME(svd_A), + svd_1_3_types + }, + { + "eig", + "(m,m)->(m),(m,m)", + "eig on the last two dimension and broadcast to the rest. \n"\ + "Results in a vector with the eigenvalues and a matrix with the"\ + " eigenvectors. \n"\ + " \"(m,m)->(m),(m,m)\" \n", + 3, 1, 2, + FUNC_ARRAY_NAME(eig), + eig_types + }, + { + "eigvals", + "(m,m)->(m)", + "eigvals on the last two dimension and broadcast to the rest. \n"\ + "Results in a vector of eigenvalues. \n"\ + " \"(m,m)->(m),(m,m)\" \n", + 3, 1, 1, + FUNC_ARRAY_NAME(eigvals), + eigvals_types + }, +}; + +static void +addUfuncs(PyObject *dictionary) { + PyObject *f; + int i; + const int gufunc_count = sizeof(gufunc_descriptors)/ + sizeof(gufunc_descriptors[0]); + for (i = 0; i < gufunc_count; i++) { + GUFUNC_DESCRIPTOR_t* d = &gufunc_descriptors[i]; + f = PyUFunc_FromFuncAndDataAndSignature(d->funcs, + array_of_nulls, + d->types, + d->ntypes, + d->nin, + d->nout, + PyUFunc_None, + d->name, + d->doc, + 0, + d->signature); + PyDict_SetItemString(dictionary, d->name, f); +#if 0 + dump_ufunc_object((PyUFuncObject*) f); +#endif + Py_DECREF(f); + } +} + + + +/* -------------------------------------------------------------------------- */ + /* Module initialization stuff */ + +static PyMethodDef UMath_LinAlgMethods[] = { + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + UMATH_LINALG_MODULE_NAME, + NULL, + -1, + UMath_LinAlgMethods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#if defined(NPY_PY3K) +#define RETVAL m +PyObject *PyInit__umath_linalg(void) +#else +#define RETVAL +PyMODINIT_FUNC +init_umath_linalg(void) +#endif +{ + PyObject *m; + PyObject *d; + PyObject *version; + + init_constants(); +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule(UMATH_LINALG_MODULE_NAME, UMath_LinAlgMethods); +#endif + if (m == NULL) { + return RETVAL; + } + + import_array(); + import_ufunc(); + + d = PyModule_GetDict(m); + + version = PyString_FromString(umath_linalg_version_string); + PyDict_SetItemString(d, "__version__", version); + Py_DECREF(version); + + /* Load the ufunc operators into the module's namespace */ + addUfuncs(d); + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot load _umath_linalg module."); + } + + return RETVAL; +} diff --git a/numpy/ma/__init__.py b/numpy/ma/__init__.py new file mode 100644 index 0000000..fbefc47 --- /dev/null +++ b/numpy/ma/__init__.py @@ -0,0 +1,56 @@ +""" +============= +Masked Arrays +============= + +Arrays sometimes contain invalid or missing data. When doing operations +on such arrays, we wish to suppress invalid values, which is the purpose masked +arrays fulfill (an example of typical use is given below). + +For example, examine the following array: + +>>> x = np.array([2, 1, 3, np.nan, 5, 2, 3, np.nan]) + +When we try to calculate the mean of the data, the result is undetermined: + +>>> np.mean(x) +nan + +The mean is calculated using roughly ``np.sum(x)/len(x)``, but since +any number added to ``NaN`` [1]_ produces ``NaN``, this doesn't work. Enter +masked arrays: + +>>> m = np.ma.masked_array(x, np.isnan(x)) +>>> m +masked_array(data = [2.0 1.0 3.0 -- 5.0 2.0 3.0 --], + mask = [False False False True False False False True], + fill_value=1e+20) + +Here, we construct a masked array that suppress all ``NaN`` values. We +may now proceed to calculate the mean of the other values: + +>>> np.mean(m) +2.6666666666666665 + +.. [1] Not-a-Number, a floating point value that is the result of an + invalid operation. + +.. moduleauthor:: Pierre Gerard-Marchant +.. moduleauthor:: Jarrod Millman + +""" +from __future__ import division, absolute_import, print_function + +from . import core +from .core import * + +from . import extras +from .extras import * + +__all__ = ['core', 'extras'] +__all__ += core.__all__ +__all__ += extras.__all__ + +from numpy.testing import _numpy_tester +test = _numpy_tester().test +bench = _numpy_tester().bench diff --git a/numpy/ma/bench.py b/numpy/ma/bench.py new file mode 100644 index 0000000..a9ba42d --- /dev/null +++ b/numpy/ma/bench.py @@ -0,0 +1,133 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import division, print_function + +import timeit +import numpy + + +############################################################################### +# Global variables # +############################################################################### + + +# Small arrays +xs = numpy.random.uniform(-1, 1, 6).reshape(2, 3) +ys = numpy.random.uniform(-1, 1, 6).reshape(2, 3) +zs = xs + 1j * ys +m1 = [[True, False, False], [False, False, True]] +m2 = [[True, False, True], [False, False, True]] +nmxs = numpy.ma.array(xs, mask=m1) +nmys = numpy.ma.array(ys, mask=m2) +nmzs = numpy.ma.array(zs, mask=m1) + +# Big arrays +xl = numpy.random.uniform(-1, 1, 100*100).reshape(100, 100) +yl = numpy.random.uniform(-1, 1, 100*100).reshape(100, 100) +zl = xl + 1j * yl +maskx = xl > 0.8 +masky = yl < -0.8 +nmxl = numpy.ma.array(xl, mask=maskx) +nmyl = numpy.ma.array(yl, mask=masky) +nmzl = numpy.ma.array(zl, mask=maskx) + + +############################################################################### +# Functions # +############################################################################### + + +def timer(s, v='', nloop=500, nrep=3): + units = ["s", "ms", "µs", "ns"] + scaling = [1, 1e3, 1e6, 1e9] + print("%s : %-50s : " % (v, s), end=' ') + varnames = ["%ss,nm%ss,%sl,nm%sl" % tuple(x*4) for x in 'xyz'] + setup = 'from __main__ import numpy, ma, %s' % ','.join(varnames) + Timer = timeit.Timer(stmt=s, setup=setup) + best = min(Timer.repeat(nrep, nloop)) / nloop + if best > 0.0: + order = min(-int(numpy.floor(numpy.log10(best)) // 3), 3) + else: + order = 3 + print("%d loops, best of %d: %.*g %s per loop" % (nloop, nrep, + 3, + best * scaling[order], + units[order])) + + +def compare_functions_1v(func, nloop=500, + xs=xs, nmxs=nmxs, xl=xl, nmxl=nmxl): + funcname = func.__name__ + print("-"*50) + print("%s on small arrays" % funcname) + module, data = "numpy.ma", "nmxs" + timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop) + + print("%s on large arrays" % funcname) + module, data = "numpy.ma", "nmxl" + timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop) + return + +def compare_methods(methodname, args, vars='x', nloop=500, test=True, + xs=xs, nmxs=nmxs, xl=xl, nmxl=nmxl): + print("-"*50) + print("%s on small arrays" % methodname) + data, ver = "nm%ss" % vars, 'numpy.ma' + timer("%(data)s.%(methodname)s(%(args)s)" % locals(), v=ver, nloop=nloop) + + print("%s on large arrays" % methodname) + data, ver = "nm%sl" % vars, 'numpy.ma' + timer("%(data)s.%(methodname)s(%(args)s)" % locals(), v=ver, nloop=nloop) + return + +def compare_functions_2v(func, nloop=500, test=True, + xs=xs, nmxs=nmxs, + ys=ys, nmys=nmys, + xl=xl, nmxl=nmxl, + yl=yl, nmyl=nmyl): + funcname = func.__name__ + print("-"*50) + print("%s on small arrays" % funcname) + module, data = "numpy.ma", "nmxs,nmys" + timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop) + + print("%s on large arrays" % funcname) + module, data = "numpy.ma", "nmxl,nmyl" + timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop) + return + + +if __name__ == '__main__': + compare_functions_1v(numpy.sin) + compare_functions_1v(numpy.log) + compare_functions_1v(numpy.sqrt) + + compare_functions_2v(numpy.multiply) + compare_functions_2v(numpy.divide) + compare_functions_2v(numpy.power) + + compare_methods('ravel', '', nloop=1000) + compare_methods('conjugate', '', 'z', nloop=1000) + compare_methods('transpose', '', nloop=1000) + compare_methods('compressed', '', nloop=1000) + compare_methods('__getitem__', '0', nloop=1000) + compare_methods('__getitem__', '(0,0)', nloop=1000) + compare_methods('__getitem__', '[0,-1]', nloop=1000) + compare_methods('__setitem__', '0, 17', nloop=1000, test=False) + compare_methods('__setitem__', '(0,0), 17', nloop=1000, test=False) + + print("-"*50) + print("__setitem__ on small arrays") + timer('nmxs.__setitem__((-1,0),numpy.ma.masked)', 'numpy.ma ', nloop=10000) + + print("-"*50) + print("__setitem__ on large arrays") + timer('nmxl.__setitem__((-1,0),numpy.ma.masked)', 'numpy.ma ', nloop=10000) + + print("-"*50) + print("where on small arrays") + timer('numpy.ma.where(nmxs>2,nmxs,nmys)', 'numpy.ma ', nloop=1000) + print("-"*50) + print("where on large arrays") + timer('numpy.ma.where(nmxl>2,nmxl,nmyl)', 'numpy.ma ', nloop=100) diff --git a/numpy/ma/core.py b/numpy/ma/core.py new file mode 100644 index 0000000..57a4827 --- /dev/null +++ b/numpy/ma/core.py @@ -0,0 +1,8113 @@ +""" +numpy.ma : a package to handle missing or invalid values. + +This package was initially written for numarray by Paul F. Dubois +at Lawrence Livermore National Laboratory. +In 2006, the package was completely rewritten by Pierre Gerard-Marchant +(University of Georgia) to make the MaskedArray class a subclass of ndarray, +and to improve support of structured arrays. + + +Copyright 1999, 2000, 2001 Regents of the University of California. +Released for unlimited redistribution. + +* Adapted for numpy_core 2005 by Travis Oliphant and (mainly) Paul Dubois. +* Subclassing of the base `ndarray` 2006 by Pierre Gerard-Marchant + (pgmdevlist_AT_gmail_DOT_com) +* Improvements suggested by Reggie Dugard (reggie_AT_merfinllc_DOT_com) + +.. moduleauthor:: Pierre Gerard-Marchant + +""" +# pylint: disable-msg=E1002 +from __future__ import division, absolute_import, print_function + +import sys +import operator +import warnings +import textwrap +from functools import reduce + +if sys.version_info[0] >= 3: + import builtins +else: + import __builtin__ as builtins + +import numpy as np +import numpy.core.umath as umath +import numpy.core.numerictypes as ntypes +from numpy import ndarray, amax, amin, iscomplexobj, bool_, _NoValue +from numpy import array as narray +from numpy.lib.function_base import angle +from numpy.compat import ( + getargspec, formatargspec, long, basestring, unicode, bytes + ) +from numpy import expand_dims as n_expand_dims +from numpy.core.multiarray import normalize_axis_index +from numpy.core.numeric import normalize_axis_tuple + + +if sys.version_info[0] >= 3: + import pickle +else: + import cPickle as pickle + +__all__ = [ + 'MAError', 'MaskError', 'MaskType', 'MaskedArray', 'abs', 'absolute', + 'add', 'all', 'allclose', 'allequal', 'alltrue', 'amax', 'amin', + 'angle', 'anom', 'anomalies', 'any', 'append', 'arange', 'arccos', + 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh', + 'argmax', 'argmin', 'argsort', 'around', 'array', 'asanyarray', + 'asarray', 'bitwise_and', 'bitwise_or', 'bitwise_xor', 'bool_', 'ceil', + 'choose', 'clip', 'common_fill_value', 'compress', 'compressed', + 'concatenate', 'conjugate', 'convolve', 'copy', 'correlate', 'cos', 'cosh', + 'count', 'cumprod', 'cumsum', 'default_fill_value', 'diag', 'diagonal', + 'diff', 'divide', 'dump', 'dumps', 'empty', 'empty_like', 'equal', 'exp', + 'expand_dims', 'fabs', 'filled', 'fix_invalid', 'flatten_mask', + 'flatten_structured_array', 'floor', 'floor_divide', 'fmod', + 'frombuffer', 'fromflex', 'fromfunction', 'getdata', 'getmask', + 'getmaskarray', 'greater', 'greater_equal', 'harden_mask', 'hypot', + 'identity', 'ids', 'indices', 'inner', 'innerproduct', 'isMA', + 'isMaskedArray', 'is_mask', 'is_masked', 'isarray', 'left_shift', + 'less', 'less_equal', 'load', 'loads', 'log', 'log10', 'log2', + 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'make_mask', + 'make_mask_descr', 'make_mask_none', 'mask_or', 'masked', + 'masked_array', 'masked_equal', 'masked_greater', + 'masked_greater_equal', 'masked_inside', 'masked_invalid', + 'masked_less', 'masked_less_equal', 'masked_not_equal', + 'masked_object', 'masked_outside', 'masked_print_option', + 'masked_singleton', 'masked_values', 'masked_where', 'max', 'maximum', + 'maximum_fill_value', 'mean', 'min', 'minimum', 'minimum_fill_value', + 'mod', 'multiply', 'mvoid', 'ndim', 'negative', 'nomask', 'nonzero', + 'not_equal', 'ones', 'outer', 'outerproduct', 'power', 'prod', + 'product', 'ptp', 'put', 'putmask', 'rank', 'ravel', 'remainder', + 'repeat', 'reshape', 'resize', 'right_shift', 'round', 'round_', + 'set_fill_value', 'shape', 'sin', 'sinh', 'size', 'soften_mask', + 'sometrue', 'sort', 'sqrt', 'squeeze', 'std', 'subtract', 'sum', + 'swapaxes', 'take', 'tan', 'tanh', 'trace', 'transpose', 'true_divide', + 'var', 'where', 'zeros', + ] + +MaskType = np.bool_ +nomask = MaskType(0) + +class MaskedArrayFutureWarning(FutureWarning): + pass + +def _deprecate_argsort_axis(arr): + """ + Adjust the axis passed to argsort, warning if necessary + + Parameters + ---------- + arr + The array which argsort was called on + + np.ma.argsort has a long-term bug where the default of the axis argument + is wrong (gh-8701), which now must be kept for backwards compatibiity. + Thankfully, this only makes a difference when arrays are 2- or more- + dimensional, so we only need a warning then. + """ + if arr.ndim <= 1: + # no warning needed - but switch to -1 anyway, to avoid surprising + # subclasses, which are more likely to implement scalar axes. + return -1 + else: + # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default + warnings.warn( + "In the future the default for argsort will be axis=-1, not the " + "current None, to match its documentation and np.argsort. " + "Explicitly pass -1 or None to silence this warning.", + MaskedArrayFutureWarning, stacklevel=3) + return None + + +def doc_note(initialdoc, note): + """ + Adds a Notes section to an existing docstring. + + """ + if initialdoc is None: + return + if note is None: + return initialdoc + + # FIXME: disable this function for the moment until we figure out what to + # do with it. Currently it may result in duplicate Notes sections or Notes + # sections in the wrong place + return initialdoc + + newdoc = """ + %s + + Notes + ----- + %s + """ + return newdoc % (initialdoc, note) + + +def get_object_signature(obj): + """ + Get the signature from obj + + """ + try: + sig = formatargspec(*getargspec(obj)) + except TypeError: + sig = '' + return sig + + +############################################################################### +# Exceptions # +############################################################################### + + +class MAError(Exception): + """ + Class for masked array related errors. + + """ + pass + + +class MaskError(MAError): + """ + Class for mask related errors. + + """ + pass + + +############################################################################### +# Filling options # +############################################################################### + + +# b: boolean - c: complex - f: floats - i: integer - O: object - S: string +default_filler = {'b': True, + 'c': 1.e20 + 0.0j, + 'f': 1.e20, + 'i': 999999, + 'O': '?', + 'S': b'N/A', + 'u': 999999, + 'V': b'???', + 'U': u'N/A' + } + +# Add datetime64 and timedelta64 types +for v in ["Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", "ps", + "fs", "as"]: + default_filler["M8[" + v + "]"] = np.datetime64("NaT", v) + default_filler["m8[" + v + "]"] = np.timedelta64("NaT", v) + +max_filler = ntypes._minvals +max_filler.update([(k, -np.inf) for k in [np.float32, np.float64]]) +min_filler = ntypes._maxvals +min_filler.update([(k, +np.inf) for k in [np.float32, np.float64]]) +if 'float128' in ntypes.typeDict: + max_filler.update([(np.float128, -np.inf)]) + min_filler.update([(np.float128, +np.inf)]) + + +def _recursive_fill_value(dtype, f): + """ + Recursively produce a fill value for `dtype`, calling f on scalar dtypes + """ + if dtype.names: + vals = tuple(_recursive_fill_value(dtype[name], f) for name in dtype.names) + return np.array(vals, dtype=dtype)[()] # decay to void scalar from 0d + elif dtype.subdtype: + subtype, shape = dtype.subdtype + subval = _recursive_fill_value(subtype, f) + return np.full(shape, subval) + else: + return f(dtype) + + +def _get_dtype_of(obj): + """ Convert the argument for *_fill_value into a dtype """ + if isinstance(obj, np.dtype): + return obj + elif hasattr(obj, 'dtype'): + return obj.dtype + else: + return np.asanyarray(obj).dtype + + +def default_fill_value(obj): + """ + Return the default fill value for the argument object. + + The default filling value depends on the datatype of the input + array or the type of the input scalar: + + ======== ======== + datatype default + ======== ======== + bool True + int 999999 + float 1.e20 + complex 1.e20+0j + object '?' + string 'N/A' + ======== ======== + + For structured types, a structured scalar is returned, with each field the + default fill value for its type. + + For subarray types, the fill value is an array of the same size containing + the default scalar fill value. + + Parameters + ---------- + obj : ndarray, dtype or scalar + The array data-type or scalar for which the default fill value + is returned. + + Returns + ------- + fill_value : scalar + The default fill value. + + Examples + -------- + >>> np.ma.default_fill_value(1) + 999999 + >>> np.ma.default_fill_value(np.array([1.1, 2., np.pi])) + 1e+20 + >>> np.ma.default_fill_value(np.dtype(complex)) + (1e+20+0j) + + """ + def _scalar_fill_value(dtype): + if dtype.kind in 'Mm': + return default_filler.get(dtype.str[1:], '?') + else: + return default_filler.get(dtype.kind, '?') + + dtype = _get_dtype_of(obj) + return _recursive_fill_value(dtype, _scalar_fill_value) + + +def _extremum_fill_value(obj, extremum, extremum_name): + + def _scalar_fill_value(dtype): + try: + return extremum[dtype] + except KeyError: + raise TypeError( + "Unsuitable type {} for calculating {}." + .format(dtype, extremum_name) + ) + + dtype = _get_dtype_of(obj) + return _recursive_fill_value(dtype, _scalar_fill_value) + + +def minimum_fill_value(obj): + """ + Return the maximum value that can be represented by the dtype of an object. + + This function is useful for calculating a fill value suitable for + taking the minimum of an array with a given dtype. + + Parameters + ---------- + obj : ndarray, dtype or scalar + An object that can be queried for it's numeric type. + + Returns + ------- + val : scalar + The maximum representable value. + + Raises + ------ + TypeError + If `obj` isn't a suitable numeric type. + + See Also + -------- + maximum_fill_value : The inverse function. + set_fill_value : Set the filling value of a masked array. + MaskedArray.fill_value : Return current fill value. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.int8() + >>> ma.minimum_fill_value(a) + 127 + >>> a = np.int32() + >>> ma.minimum_fill_value(a) + 2147483647 + + An array of numeric data can also be passed. + + >>> a = np.array([1, 2, 3], dtype=np.int8) + >>> ma.minimum_fill_value(a) + 127 + >>> a = np.array([1, 2, 3], dtype=np.float32) + >>> ma.minimum_fill_value(a) + inf + + """ + return _extremum_fill_value(obj, min_filler, "minimum") + + +def maximum_fill_value(obj): + """ + Return the minimum value that can be represented by the dtype of an object. + + This function is useful for calculating a fill value suitable for + taking the maximum of an array with a given dtype. + + Parameters + ---------- + obj : ndarray, dtype or scalar + An object that can be queried for it's numeric type. + + Returns + ------- + val : scalar + The minimum representable value. + + Raises + ------ + TypeError + If `obj` isn't a suitable numeric type. + + See Also + -------- + minimum_fill_value : The inverse function. + set_fill_value : Set the filling value of a masked array. + MaskedArray.fill_value : Return current fill value. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.int8() + >>> ma.maximum_fill_value(a) + -128 + >>> a = np.int32() + >>> ma.maximum_fill_value(a) + -2147483648 + + An array of numeric data can also be passed. + + >>> a = np.array([1, 2, 3], dtype=np.int8) + >>> ma.maximum_fill_value(a) + -128 + >>> a = np.array([1, 2, 3], dtype=np.float32) + >>> ma.maximum_fill_value(a) + -inf + + """ + return _extremum_fill_value(obj, max_filler, "maximum") + + +def _recursive_set_fill_value(fillvalue, dt): + """ + Create a fill value for a structured dtype. + + Parameters + ---------- + fillvalue: scalar or array_like + Scalar or array representing the fill value. If it is of shorter + length than the number of fields in dt, it will be resized. + dt: dtype + The structured dtype for which to create the fill value. + + Returns + ------- + val: tuple + A tuple of values corresponding to the structured fill value. + + """ + fillvalue = np.resize(fillvalue, len(dt.names)) + output_value = [] + for (fval, name) in zip(fillvalue, dt.names): + cdtype = dt[name] + if cdtype.subdtype: + cdtype = cdtype.subdtype[0] + + if cdtype.names: + output_value.append(tuple(_recursive_set_fill_value(fval, cdtype))) + else: + output_value.append(np.array(fval, dtype=cdtype).item()) + return tuple(output_value) + + +def _check_fill_value(fill_value, ndtype): + """ + Private function validating the given `fill_value` for the given dtype. + + If fill_value is None, it is set to the default corresponding to the dtype. + + If fill_value is not None, its value is forced to the given dtype. + + The result is always a 0d array. + """ + ndtype = np.dtype(ndtype) + fields = ndtype.fields + if fill_value is None: + fill_value = default_fill_value(ndtype) + elif fields: + fdtype = [(_[0], _[1]) for _ in ndtype.descr] + if isinstance(fill_value, (ndarray, np.void)): + try: + fill_value = np.array(fill_value, copy=False, dtype=fdtype) + except ValueError: + err_msg = "Unable to transform %s to dtype %s" + raise ValueError(err_msg % (fill_value, fdtype)) + else: + fill_value = np.asarray(fill_value, dtype=object) + fill_value = np.array(_recursive_set_fill_value(fill_value, ndtype), + dtype=ndtype) + else: + if isinstance(fill_value, basestring) and (ndtype.char not in 'OSVU'): + err_msg = "Cannot set fill value of string with array of dtype %s" + raise TypeError(err_msg % ndtype) + else: + # In case we want to convert 1e20 to int. + try: + fill_value = np.array(fill_value, copy=False, dtype=ndtype) + except OverflowError: + # Raise TypeError instead of OverflowError. OverflowError + # is seldom used, and the real problem here is that the + # passed fill_value is not compatible with the ndtype. + err_msg = "Fill value %s overflows dtype %s" + raise TypeError(err_msg % (fill_value, ndtype)) + return np.array(fill_value) + + +def set_fill_value(a, fill_value): + """ + Set the filling value of a, if a is a masked array. + + This function changes the fill value of the masked array `a` in place. + If `a` is not a masked array, the function returns silently, without + doing anything. + + Parameters + ---------- + a : array_like + Input array. + fill_value : dtype + Filling value. A consistency test is performed to make sure + the value is compatible with the dtype of `a`. + + Returns + ------- + None + Nothing returned by this function. + + See Also + -------- + maximum_fill_value : Return the default fill value for a dtype. + MaskedArray.fill_value : Return current fill value. + MaskedArray.set_fill_value : Equivalent method. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(5) + >>> a + array([0, 1, 2, 3, 4]) + >>> a = ma.masked_where(a < 3, a) + >>> a + masked_array(data = [-- -- -- 3 4], + mask = [ True True True False False], + fill_value=999999) + >>> ma.set_fill_value(a, -999) + >>> a + masked_array(data = [-- -- -- 3 4], + mask = [ True True True False False], + fill_value=-999) + + Nothing happens if `a` is not a masked array. + + >>> a = range(5) + >>> a + [0, 1, 2, 3, 4] + >>> ma.set_fill_value(a, 100) + >>> a + [0, 1, 2, 3, 4] + >>> a = np.arange(5) + >>> a + array([0, 1, 2, 3, 4]) + >>> ma.set_fill_value(a, 100) + >>> a + array([0, 1, 2, 3, 4]) + + """ + if isinstance(a, MaskedArray): + a.set_fill_value(fill_value) + return + + +def get_fill_value(a): + """ + Return the filling value of a, if any. Otherwise, returns the + default filling value for that type. + + """ + if isinstance(a, MaskedArray): + result = a.fill_value + else: + result = default_fill_value(a) + return result + + +def common_fill_value(a, b): + """ + Return the common filling value of two masked arrays, if any. + + If ``a.fill_value == b.fill_value``, return the fill value, + otherwise return None. + + Parameters + ---------- + a, b : MaskedArray + The masked arrays for which to compare fill values. + + Returns + ------- + fill_value : scalar or None + The common fill value, or None. + + Examples + -------- + >>> x = np.ma.array([0, 1.], fill_value=3) + >>> y = np.ma.array([0, 1.], fill_value=3) + >>> np.ma.common_fill_value(x, y) + 3.0 + + """ + t1 = get_fill_value(a) + t2 = get_fill_value(b) + if t1 == t2: + return t1 + return None + + +def filled(a, fill_value=None): + """ + Return input as an array with masked data replaced by a fill value. + + If `a` is not a `MaskedArray`, `a` itself is returned. + If `a` is a `MaskedArray` and `fill_value` is None, `fill_value` is set to + ``a.fill_value``. + + Parameters + ---------- + a : MaskedArray or array_like + An input object. + fill_value : scalar, optional + Filling value. Default is None. + + Returns + ------- + a : ndarray + The filled array. + + See Also + -------- + compressed + + Examples + -------- + >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0], + ... [1, 0, 0], + ... [0, 0, 0]]) + >>> x.filled() + array([[999999, 1, 2], + [999999, 4, 5], + [ 6, 7, 8]]) + + """ + if hasattr(a, 'filled'): + return a.filled(fill_value) + elif isinstance(a, ndarray): + # Should we check for contiguity ? and a.flags['CONTIGUOUS']: + return a + elif isinstance(a, dict): + return np.array(a, 'O') + else: + return np.array(a) + + +def get_masked_subclass(*arrays): + """ + Return the youngest subclass of MaskedArray from a list of (masked) arrays. + + In case of siblings, the first listed takes over. + + """ + if len(arrays) == 1: + arr = arrays[0] + if isinstance(arr, MaskedArray): + rcls = type(arr) + else: + rcls = MaskedArray + else: + arrcls = [type(a) for a in arrays] + rcls = arrcls[0] + if not issubclass(rcls, MaskedArray): + rcls = MaskedArray + for cls in arrcls[1:]: + if issubclass(cls, rcls): + rcls = cls + # Don't return MaskedConstant as result: revert to MaskedArray + if rcls.__name__ == 'MaskedConstant': + return MaskedArray + return rcls + + +def getdata(a, subok=True): + """ + Return the data of a masked array as an ndarray. + + Return the data of `a` (if any) as an ndarray if `a` is a ``MaskedArray``, + else return `a` as a ndarray or subclass (depending on `subok`) if not. + + Parameters + ---------- + a : array_like + Input ``MaskedArray``, alternatively a ndarray or a subclass thereof. + subok : bool + Whether to force the output to be a `pure` ndarray (False) or to + return a subclass of ndarray if appropriate (True, default). + + See Also + -------- + getmask : Return the mask of a masked array, or nomask. + getmaskarray : Return the mask of a masked array, or full array of False. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = ma.masked_equal([[1,2],[3,4]], 2) + >>> a + masked_array(data = + [[1 --] + [3 4]], + mask = + [[False True] + [False False]], + fill_value=999999) + >>> ma.getdata(a) + array([[1, 2], + [3, 4]]) + + Equivalently use the ``MaskedArray`` `data` attribute. + + >>> a.data + array([[1, 2], + [3, 4]]) + + """ + try: + data = a._data + except AttributeError: + data = np.array(a, copy=False, subok=subok) + if not subok: + return data.view(ndarray) + return data + + +get_data = getdata + + +def fix_invalid(a, mask=nomask, copy=True, fill_value=None): + """ + Return input with invalid data masked and replaced by a fill value. + + Invalid data means values of `nan`, `inf`, etc. + + Parameters + ---------- + a : array_like + Input array, a (subclass of) ndarray. + mask : sequence, optional + Mask. Must be convertible to an array of booleans with the same + shape as `data`. True indicates a masked (i.e. invalid) data. + copy : bool, optional + Whether to use a copy of `a` (True) or to fix `a` in place (False). + Default is True. + fill_value : scalar, optional + Value used for fixing invalid data. Default is None, in which case + the ``a.fill_value`` is used. + + Returns + ------- + b : MaskedArray + The input array with invalid entries fixed. + + Notes + ----- + A copy is performed by default. + + Examples + -------- + >>> x = np.ma.array([1., -1, np.nan, np.inf], mask=[1] + [0]*3) + >>> x + masked_array(data = [-- -1.0 nan inf], + mask = [ True False False False], + fill_value = 1e+20) + >>> np.ma.fix_invalid(x) + masked_array(data = [-- -1.0 -- --], + mask = [ True False True True], + fill_value = 1e+20) + + >>> fixed = np.ma.fix_invalid(x) + >>> fixed.data + array([ 1.00000000e+00, -1.00000000e+00, 1.00000000e+20, + 1.00000000e+20]) + >>> x.data + array([ 1., -1., NaN, Inf]) + + """ + a = masked_array(a, copy=copy, mask=mask, subok=True) + invalid = np.logical_not(np.isfinite(a._data)) + if not invalid.any(): + return a + a._mask |= invalid + if fill_value is None: + fill_value = a.fill_value + a._data[invalid] = fill_value + return a + + +############################################################################### +# Ufuncs # +############################################################################### + + +ufunc_domain = {} +ufunc_fills = {} + + +class _DomainCheckInterval(object): + """ + Define a valid interval, so that : + + ``domain_check_interval(a,b)(x) == True`` where + ``x < a`` or ``x > b``. + + """ + + def __init__(self, a, b): + "domain_check_interval(a,b)(x) = true where x < a or y > b" + if (a > b): + (a, b) = (b, a) + self.a = a + self.b = b + + def __call__(self, x): + "Execute the call behavior." + # nans at masked positions cause RuntimeWarnings, even though + # they are masked. To avoid this we suppress warnings. + with np.errstate(invalid='ignore'): + return umath.logical_or(umath.greater(x, self.b), + umath.less(x, self.a)) + + +class _DomainTan(object): + """ + Define a valid interval for the `tan` function, so that: + + ``domain_tan(eps) = True`` where ``abs(cos(x)) < eps`` + + """ + + def __init__(self, eps): + "domain_tan(eps) = true where abs(cos(x)) < eps)" + self.eps = eps + + def __call__(self, x): + "Executes the call behavior." + with np.errstate(invalid='ignore'): + return umath.less(umath.absolute(umath.cos(x)), self.eps) + + +class _DomainSafeDivide(object): + """ + Define a domain for safe division. + + """ + + def __init__(self, tolerance=None): + self.tolerance = tolerance + + def __call__(self, a, b): + # Delay the selection of the tolerance to here in order to reduce numpy + # import times. The calculation of these parameters is a substantial + # component of numpy's import time. + if self.tolerance is None: + self.tolerance = np.finfo(float).tiny + # don't call ma ufuncs from __array_wrap__ which would fail for scalars + a, b = np.asarray(a), np.asarray(b) + with np.errstate(invalid='ignore'): + return umath.absolute(a) * self.tolerance >= umath.absolute(b) + + +class _DomainGreater(object): + """ + DomainGreater(v)(x) is True where x <= v. + + """ + + def __init__(self, critical_value): + "DomainGreater(v)(x) = true where x <= v" + self.critical_value = critical_value + + def __call__(self, x): + "Executes the call behavior." + with np.errstate(invalid='ignore'): + return umath.less_equal(x, self.critical_value) + + +class _DomainGreaterEqual(object): + """ + DomainGreaterEqual(v)(x) is True where x < v. + + """ + + def __init__(self, critical_value): + "DomainGreaterEqual(v)(x) = true where x < v" + self.critical_value = critical_value + + def __call__(self, x): + "Executes the call behavior." + with np.errstate(invalid='ignore'): + return umath.less(x, self.critical_value) + + +class _MaskedUFunc(object): + def __init__(self, ufunc): + self.f = ufunc + self.__doc__ = ufunc.__doc__ + self.__name__ = ufunc.__name__ + + def __str__(self): + return "Masked version of {}".format(self.f) + + +class _MaskedUnaryOperation(_MaskedUFunc): + """ + Defines masked version of unary operations, where invalid values are + pre-masked. + + Parameters + ---------- + mufunc : callable + The function for which to define a masked version. Made available + as ``_MaskedUnaryOperation.f``. + fill : scalar, optional + Filling value, default is 0. + domain : class instance + Domain for the function. Should be one of the ``_Domain*`` + classes. Default is None. + + """ + + def __init__(self, mufunc, fill=0, domain=None): + super(_MaskedUnaryOperation, self).__init__(mufunc) + self.fill = fill + self.domain = domain + ufunc_domain[mufunc] = domain + ufunc_fills[mufunc] = fill + + def __call__(self, a, *args, **kwargs): + """ + Execute the call behavior. + + """ + d = getdata(a) + # Deal with domain + if self.domain is not None: + # Case 1.1. : Domained function + # nans at masked positions cause RuntimeWarnings, even though + # they are masked. To avoid this we suppress warnings. + with np.errstate(divide='ignore', invalid='ignore'): + result = self.f(d, *args, **kwargs) + # Make a mask + m = ~umath.isfinite(result) + m |= self.domain(d) + m |= getmask(a) + else: + # Case 1.2. : Function without a domain + # Get the result and the mask + with np.errstate(divide='ignore', invalid='ignore'): + result = self.f(d, *args, **kwargs) + m = getmask(a) + + if not result.ndim: + # Case 2.1. : The result is scalarscalar + if m: + return masked + return result + + if m is not nomask: + # Case 2.2. The result is an array + # We need to fill the invalid data back w/ the input Now, + # that's plain silly: in C, we would just skip the element and + # keep the original, but we do have to do it that way in Python + + # In case result has a lower dtype than the inputs (as in + # equal) + try: + np.copyto(result, d, where=m) + except TypeError: + pass + # Transform to + masked_result = result.view(get_masked_subclass(a)) + masked_result._mask = m + masked_result._update_from(a) + return masked_result + + +class _MaskedBinaryOperation(_MaskedUFunc): + """ + Define masked version of binary operations, where invalid + values are pre-masked. + + Parameters + ---------- + mbfunc : function + The function for which to define a masked version. Made available + as ``_MaskedBinaryOperation.f``. + domain : class instance + Default domain for the function. Should be one of the ``_Domain*`` + classes. Default is None. + fillx : scalar, optional + Filling value for the first argument, default is 0. + filly : scalar, optional + Filling value for the second argument, default is 0. + + """ + + def __init__(self, mbfunc, fillx=0, filly=0): + """ + abfunc(fillx, filly) must be defined. + + abfunc(x, filly) = x for all x to enable reduce. + + """ + super(_MaskedBinaryOperation, self).__init__(mbfunc) + self.fillx = fillx + self.filly = filly + ufunc_domain[mbfunc] = None + ufunc_fills[mbfunc] = (fillx, filly) + + def __call__(self, a, b, *args, **kwargs): + """ + Execute the call behavior. + + """ + # Get the data, as ndarray + (da, db) = (getdata(a), getdata(b)) + # Get the result + with np.errstate(): + np.seterr(divide='ignore', invalid='ignore') + result = self.f(da, db, *args, **kwargs) + # Get the mask for the result + (ma, mb) = (getmask(a), getmask(b)) + if ma is nomask: + if mb is nomask: + m = nomask + else: + m = umath.logical_or(getmaskarray(a), mb) + elif mb is nomask: + m = umath.logical_or(ma, getmaskarray(b)) + else: + m = umath.logical_or(ma, mb) + + # Case 1. : scalar + if not result.ndim: + if m: + return masked + return result + + # Case 2. : array + # Revert result to da where masked + if m is not nomask and m.any(): + # any errors, just abort; impossible to guarantee masked values + try: + np.copyto(result, da, casting='unsafe', where=m) + except Exception: + pass + + # Transforms to a (subclass of) MaskedArray + masked_result = result.view(get_masked_subclass(a, b)) + masked_result._mask = m + if isinstance(a, MaskedArray): + masked_result._update_from(a) + elif isinstance(b, MaskedArray): + masked_result._update_from(b) + return masked_result + + def reduce(self, target, axis=0, dtype=None): + """ + Reduce `target` along the given `axis`. + + """ + tclass = get_masked_subclass(target) + m = getmask(target) + t = filled(target, self.filly) + if t.shape == (): + t = t.reshape(1) + if m is not nomask: + m = make_mask(m, copy=1) + m.shape = (1,) + + if m is nomask: + tr = self.f.reduce(t, axis) + mr = nomask + else: + tr = self.f.reduce(t, axis, dtype=dtype or t.dtype) + mr = umath.logical_and.reduce(m, axis) + + if not tr.shape: + if mr: + return masked + else: + return tr + masked_tr = tr.view(tclass) + masked_tr._mask = mr + return masked_tr + + def outer(self, a, b): + """ + Return the function applied to the outer product of a and b. + + """ + (da, db) = (getdata(a), getdata(b)) + d = self.f.outer(da, db) + ma = getmask(a) + mb = getmask(b) + if ma is nomask and mb is nomask: + m = nomask + else: + ma = getmaskarray(a) + mb = getmaskarray(b) + m = umath.logical_or.outer(ma, mb) + if (not m.ndim) and m: + return masked + if m is not nomask: + np.copyto(d, da, where=m) + if not d.shape: + return d + masked_d = d.view(get_masked_subclass(a, b)) + masked_d._mask = m + return masked_d + + def accumulate(self, target, axis=0): + """Accumulate `target` along `axis` after filling with y fill + value. + + """ + tclass = get_masked_subclass(target) + t = filled(target, self.filly) + result = self.f.accumulate(t, axis) + masked_result = result.view(tclass) + return masked_result + + + +class _DomainedBinaryOperation(_MaskedUFunc): + """ + Define binary operations that have a domain, like divide. + + They have no reduce, outer or accumulate. + + Parameters + ---------- + mbfunc : function + The function for which to define a masked version. Made available + as ``_DomainedBinaryOperation.f``. + domain : class instance + Default domain for the function. Should be one of the ``_Domain*`` + classes. + fillx : scalar, optional + Filling value for the first argument, default is 0. + filly : scalar, optional + Filling value for the second argument, default is 0. + + """ + + def __init__(self, dbfunc, domain, fillx=0, filly=0): + """abfunc(fillx, filly) must be defined. + abfunc(x, filly) = x for all x to enable reduce. + """ + super(_DomainedBinaryOperation, self).__init__(dbfunc) + self.domain = domain + self.fillx = fillx + self.filly = filly + ufunc_domain[dbfunc] = domain + ufunc_fills[dbfunc] = (fillx, filly) + + def __call__(self, a, b, *args, **kwargs): + "Execute the call behavior." + # Get the data + (da, db) = (getdata(a), getdata(b)) + # Get the result + with np.errstate(divide='ignore', invalid='ignore'): + result = self.f(da, db, *args, **kwargs) + # Get the mask as a combination of the source masks and invalid + m = ~umath.isfinite(result) + m |= getmask(a) + m |= getmask(b) + # Apply the domain + domain = ufunc_domain.get(self.f, None) + if domain is not None: + m |= domain(da, db) + # Take care of the scalar case first + if (not m.ndim): + if m: + return masked + else: + return result + # When the mask is True, put back da if possible + # any errors, just abort; impossible to guarantee masked values + try: + np.copyto(result, 0, casting='unsafe', where=m) + # avoid using "*" since this may be overlaid + masked_da = umath.multiply(m, da) + # only add back if it can be cast safely + if np.can_cast(masked_da.dtype, result.dtype, casting='safe'): + result += masked_da + except Exception: + pass + + # Transforms to a (subclass of) MaskedArray + masked_result = result.view(get_masked_subclass(a, b)) + masked_result._mask = m + if isinstance(a, MaskedArray): + masked_result._update_from(a) + elif isinstance(b, MaskedArray): + masked_result._update_from(b) + return masked_result + + +# Unary ufuncs +exp = _MaskedUnaryOperation(umath.exp) +conjugate = _MaskedUnaryOperation(umath.conjugate) +sin = _MaskedUnaryOperation(umath.sin) +cos = _MaskedUnaryOperation(umath.cos) +tan = _MaskedUnaryOperation(umath.tan) +arctan = _MaskedUnaryOperation(umath.arctan) +arcsinh = _MaskedUnaryOperation(umath.arcsinh) +sinh = _MaskedUnaryOperation(umath.sinh) +cosh = _MaskedUnaryOperation(umath.cosh) +tanh = _MaskedUnaryOperation(umath.tanh) +abs = absolute = _MaskedUnaryOperation(umath.absolute) +angle = _MaskedUnaryOperation(angle) # from numpy.lib.function_base +fabs = _MaskedUnaryOperation(umath.fabs) +negative = _MaskedUnaryOperation(umath.negative) +floor = _MaskedUnaryOperation(umath.floor) +ceil = _MaskedUnaryOperation(umath.ceil) +around = _MaskedUnaryOperation(np.round_) +logical_not = _MaskedUnaryOperation(umath.logical_not) + +# Domained unary ufuncs +sqrt = _MaskedUnaryOperation(umath.sqrt, 0.0, + _DomainGreaterEqual(0.0)) +log = _MaskedUnaryOperation(umath.log, 1.0, + _DomainGreater(0.0)) +log2 = _MaskedUnaryOperation(umath.log2, 1.0, + _DomainGreater(0.0)) +log10 = _MaskedUnaryOperation(umath.log10, 1.0, + _DomainGreater(0.0)) +tan = _MaskedUnaryOperation(umath.tan, 0.0, + _DomainTan(1e-35)) +arcsin = _MaskedUnaryOperation(umath.arcsin, 0.0, + _DomainCheckInterval(-1.0, 1.0)) +arccos = _MaskedUnaryOperation(umath.arccos, 0.0, + _DomainCheckInterval(-1.0, 1.0)) +arccosh = _MaskedUnaryOperation(umath.arccosh, 1.0, + _DomainGreaterEqual(1.0)) +arctanh = _MaskedUnaryOperation(umath.arctanh, 0.0, + _DomainCheckInterval(-1.0 + 1e-15, 1.0 - 1e-15)) + +# Binary ufuncs +add = _MaskedBinaryOperation(umath.add) +subtract = _MaskedBinaryOperation(umath.subtract) +multiply = _MaskedBinaryOperation(umath.multiply, 1, 1) +arctan2 = _MaskedBinaryOperation(umath.arctan2, 0.0, 1.0) +equal = _MaskedBinaryOperation(umath.equal) +equal.reduce = None +not_equal = _MaskedBinaryOperation(umath.not_equal) +not_equal.reduce = None +less_equal = _MaskedBinaryOperation(umath.less_equal) +less_equal.reduce = None +greater_equal = _MaskedBinaryOperation(umath.greater_equal) +greater_equal.reduce = None +less = _MaskedBinaryOperation(umath.less) +less.reduce = None +greater = _MaskedBinaryOperation(umath.greater) +greater.reduce = None +logical_and = _MaskedBinaryOperation(umath.logical_and) +alltrue = _MaskedBinaryOperation(umath.logical_and, 1, 1).reduce +logical_or = _MaskedBinaryOperation(umath.logical_or) +sometrue = logical_or.reduce +logical_xor = _MaskedBinaryOperation(umath.logical_xor) +bitwise_and = _MaskedBinaryOperation(umath.bitwise_and) +bitwise_or = _MaskedBinaryOperation(umath.bitwise_or) +bitwise_xor = _MaskedBinaryOperation(umath.bitwise_xor) +hypot = _MaskedBinaryOperation(umath.hypot) + +# Domained binary ufuncs +divide = _DomainedBinaryOperation(umath.divide, _DomainSafeDivide(), 0, 1) +true_divide = _DomainedBinaryOperation(umath.true_divide, + _DomainSafeDivide(), 0, 1) +floor_divide = _DomainedBinaryOperation(umath.floor_divide, + _DomainSafeDivide(), 0, 1) +remainder = _DomainedBinaryOperation(umath.remainder, + _DomainSafeDivide(), 0, 1) +fmod = _DomainedBinaryOperation(umath.fmod, _DomainSafeDivide(), 0, 1) +mod = _DomainedBinaryOperation(umath.mod, _DomainSafeDivide(), 0, 1) + + +############################################################################### +# Mask creation functions # +############################################################################### + + +def _replace_dtype_fields_recursive(dtype, primitive_dtype): + "Private function allowing recursion in _replace_dtype_fields." + _recurse = _replace_dtype_fields_recursive + + # Do we have some name fields ? + if dtype.names: + descr = [] + for name in dtype.names: + field = dtype.fields[name] + if len(field) == 3: + # Prepend the title to the name + name = (field[-1], name) + descr.append((name, _recurse(field[0], primitive_dtype))) + new_dtype = np.dtype(descr) + + # Is this some kind of composite a la (float,2) + elif dtype.subdtype: + descr = list(dtype.subdtype) + descr[0] = _recurse(dtype.subdtype[0], primitive_dtype) + new_dtype = np.dtype(tuple(descr)) + + # this is a primitive type, so do a direct replacement + else: + new_dtype = primitive_dtype + + # preserve identity of dtypes + if new_dtype == dtype: + new_dtype = dtype + + return new_dtype + + +def _replace_dtype_fields(dtype, primitive_dtype): + """ + Construct a dtype description list from a given dtype. + + Returns a new dtype object, with all fields and subtypes in the given type + recursively replaced with `primitive_dtype`. + + Arguments are coerced to dtypes first. + """ + dtype = np.dtype(dtype) + primitive_dtype = np.dtype(primitive_dtype) + return _replace_dtype_fields_recursive(dtype, primitive_dtype) + + +def make_mask_descr(ndtype): + """ + Construct a dtype description list from a given dtype. + + Returns a new dtype object, with the type of all fields in `ndtype` to a + boolean type. Field names are not altered. + + Parameters + ---------- + ndtype : dtype + The dtype to convert. + + Returns + ------- + result : dtype + A dtype that looks like `ndtype`, the type of all fields is boolean. + + Examples + -------- + >>> import numpy.ma as ma + >>> dtype = np.dtype({'names':['foo', 'bar'], + 'formats':[np.float32, int]}) + >>> dtype + dtype([('foo', '>> ma.make_mask_descr(dtype) + dtype([('foo', '|b1'), ('bar', '|b1')]) + >>> ma.make_mask_descr(np.float32) + dtype('bool') + + """ + return _replace_dtype_fields(ndtype, MaskType) + + +def getmask(a): + """ + Return the mask of a masked array, or nomask. + + Return the mask of `a` as an ndarray if `a` is a `MaskedArray` and the + mask is not `nomask`, else return `nomask`. To guarantee a full array + of booleans of the same shape as a, use `getmaskarray`. + + Parameters + ---------- + a : array_like + Input `MaskedArray` for which the mask is required. + + See Also + -------- + getdata : Return the data of a masked array as an ndarray. + getmaskarray : Return the mask of a masked array, or full array of False. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = ma.masked_equal([[1,2],[3,4]], 2) + >>> a + masked_array(data = + [[1 --] + [3 4]], + mask = + [[False True] + [False False]], + fill_value=999999) + >>> ma.getmask(a) + array([[False, True], + [False, False]]) + + Equivalently use the `MaskedArray` `mask` attribute. + + >>> a.mask + array([[False, True], + [False, False]]) + + Result when mask == `nomask` + + >>> b = ma.masked_array([[1,2],[3,4]]) + >>> b + masked_array(data = + [[1 2] + [3 4]], + mask = + False, + fill_value=999999) + >>> ma.nomask + False + >>> ma.getmask(b) == ma.nomask + True + >>> b.mask == ma.nomask + True + + """ + return getattr(a, '_mask', nomask) + + +get_mask = getmask + + +def getmaskarray(arr): + """ + Return the mask of a masked array, or full boolean array of False. + + Return the mask of `arr` as an ndarray if `arr` is a `MaskedArray` and + the mask is not `nomask`, else return a full boolean array of False of + the same shape as `arr`. + + Parameters + ---------- + arr : array_like + Input `MaskedArray` for which the mask is required. + + See Also + -------- + getmask : Return the mask of a masked array, or nomask. + getdata : Return the data of a masked array as an ndarray. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = ma.masked_equal([[1,2],[3,4]], 2) + >>> a + masked_array(data = + [[1 --] + [3 4]], + mask = + [[False True] + [False False]], + fill_value=999999) + >>> ma.getmaskarray(a) + array([[False, True], + [False, False]]) + + Result when mask == ``nomask`` + + >>> b = ma.masked_array([[1,2],[3,4]]) + >>> b + masked_array(data = + [[1 2] + [3 4]], + mask = + False, + fill_value=999999) + >>> >ma.getmaskarray(b) + array([[False, False], + [False, False]]) + + """ + mask = getmask(arr) + if mask is nomask: + mask = make_mask_none(np.shape(arr), getattr(arr, 'dtype', None)) + return mask + + +def is_mask(m): + """ + Return True if m is a valid, standard mask. + + This function does not check the contents of the input, only that the + type is MaskType. In particular, this function returns False if the + mask has a flexible dtype. + + Parameters + ---------- + m : array_like + Array to test. + + Returns + ------- + result : bool + True if `m.dtype.type` is MaskType, False otherwise. + + See Also + -------- + isMaskedArray : Test whether input is an instance of MaskedArray. + + Examples + -------- + >>> import numpy.ma as ma + >>> m = ma.masked_equal([0, 1, 0, 2, 3], 0) + >>> m + masked_array(data = [-- 1 -- 2 3], + mask = [ True False True False False], + fill_value=999999) + >>> ma.is_mask(m) + False + >>> ma.is_mask(m.mask) + True + + Input must be an ndarray (or have similar attributes) + for it to be considered a valid mask. + + >>> m = [False, True, False] + >>> ma.is_mask(m) + False + >>> m = np.array([False, True, False]) + >>> m + array([False, True, False]) + >>> ma.is_mask(m) + True + + Arrays with complex dtypes don't return True. + + >>> dtype = np.dtype({'names':['monty', 'pithon'], + 'formats':[bool, bool]}) + >>> dtype + dtype([('monty', '|b1'), ('pithon', '|b1')]) + >>> m = np.array([(True, False), (False, True), (True, False)], + dtype=dtype) + >>> m + array([(True, False), (False, True), (True, False)], + dtype=[('monty', '|b1'), ('pithon', '|b1')]) + >>> ma.is_mask(m) + False + + """ + try: + return m.dtype.type is MaskType + except AttributeError: + return False + + +def _shrink_mask(m): + """ + Shrink a mask to nomask if possible + """ + if not m.dtype.names and not m.any(): + return nomask + else: + return m + + +def make_mask(m, copy=False, shrink=True, dtype=MaskType): + """ + Create a boolean mask from an array. + + Return `m` as a boolean mask, creating a copy if necessary or requested. + The function can accept any sequence that is convertible to integers, + or ``nomask``. Does not require that contents must be 0s and 1s, values + of 0 are interepreted as False, everything else as True. + + Parameters + ---------- + m : array_like + Potential mask. + copy : bool, optional + Whether to return a copy of `m` (True) or `m` itself (False). + shrink : bool, optional + Whether to shrink `m` to ``nomask`` if all its values are False. + dtype : dtype, optional + Data-type of the output mask. By default, the output mask has a + dtype of MaskType (bool). If the dtype is flexible, each field has + a boolean dtype. This is ignored when `m` is ``nomask``, in which + case ``nomask`` is always returned. + + Returns + ------- + result : ndarray + A boolean mask derived from `m`. + + Examples + -------- + >>> import numpy.ma as ma + >>> m = [True, False, True, True] + >>> ma.make_mask(m) + array([ True, False, True, True]) + >>> m = [1, 0, 1, 1] + >>> ma.make_mask(m) + array([ True, False, True, True]) + >>> m = [1, 0, 2, -3] + >>> ma.make_mask(m) + array([ True, False, True, True]) + + Effect of the `shrink` parameter. + + >>> m = np.zeros(4) + >>> m + array([ 0., 0., 0., 0.]) + >>> ma.make_mask(m) + False + >>> ma.make_mask(m, shrink=False) + array([False, False, False, False]) + + Using a flexible `dtype`. + + >>> m = [1, 0, 1, 1] + >>> n = [0, 1, 0, 0] + >>> arr = [] + >>> for man, mouse in zip(m, n): + ... arr.append((man, mouse)) + >>> arr + [(1, 0), (0, 1), (1, 0), (1, 0)] + >>> dtype = np.dtype({'names':['man', 'mouse'], + 'formats':[int, int]}) + >>> arr = np.array(arr, dtype=dtype) + >>> arr + array([(1, 0), (0, 1), (1, 0), (1, 0)], + dtype=[('man', '>> ma.make_mask(arr, dtype=dtype) + array([(True, False), (False, True), (True, False), (True, False)], + dtype=[('man', '|b1'), ('mouse', '|b1')]) + + """ + if m is nomask: + return nomask + + # Make sure the input dtype is valid. + dtype = make_mask_descr(dtype) + + # legacy boolean special case: "existence of fields implies true" + if isinstance(m, ndarray) and m.dtype.fields and dtype == np.bool_: + return np.ones(m.shape, dtype=dtype) + + # Fill the mask in case there are missing data; turn it into an ndarray. + result = np.array(filled(m, True), copy=copy, dtype=dtype, subok=True) + # Bas les masques ! + if shrink: + result = _shrink_mask(result) + return result + + +def make_mask_none(newshape, dtype=None): + """ + Return a boolean mask of the given shape, filled with False. + + This function returns a boolean ndarray with all entries False, that can + be used in common mask manipulations. If a complex dtype is specified, the + type of each field is converted to a boolean type. + + Parameters + ---------- + newshape : tuple + A tuple indicating the shape of the mask. + dtype : {None, dtype}, optional + If None, use a MaskType instance. Otherwise, use a new datatype with + the same fields as `dtype`, converted to boolean types. + + Returns + ------- + result : ndarray + An ndarray of appropriate shape and dtype, filled with False. + + See Also + -------- + make_mask : Create a boolean mask from an array. + make_mask_descr : Construct a dtype description list from a given dtype. + + Examples + -------- + >>> import numpy.ma as ma + >>> ma.make_mask_none((3,)) + array([False, False, False]) + + Defining a more complex dtype. + + >>> dtype = np.dtype({'names':['foo', 'bar'], + 'formats':[np.float32, int]}) + >>> dtype + dtype([('foo', '>> ma.make_mask_none((3,), dtype=dtype) + array([(False, False), (False, False), (False, False)], + dtype=[('foo', '|b1'), ('bar', '|b1')]) + + """ + if dtype is None: + result = np.zeros(newshape, dtype=MaskType) + else: + result = np.zeros(newshape, dtype=make_mask_descr(dtype)) + return result + + +def mask_or(m1, m2, copy=False, shrink=True): + """ + Combine two masks with the ``logical_or`` operator. + + The result may be a view on `m1` or `m2` if the other is `nomask` + (i.e. False). + + Parameters + ---------- + m1, m2 : array_like + Input masks. + copy : bool, optional + If copy is False and one of the inputs is `nomask`, return a view + of the other input mask. Defaults to False. + shrink : bool, optional + Whether to shrink the output to `nomask` if all its values are + False. Defaults to True. + + Returns + ------- + mask : output mask + The result masks values that are masked in either `m1` or `m2`. + + Raises + ------ + ValueError + If `m1` and `m2` have different flexible dtypes. + + Examples + -------- + >>> m1 = np.ma.make_mask([0, 1, 1, 0]) + >>> m2 = np.ma.make_mask([1, 0, 0, 0]) + >>> np.ma.mask_or(m1, m2) + array([ True, True, True, False]) + + """ + + def _recursive_mask_or(m1, m2, newmask): + names = m1.dtype.names + for name in names: + current1 = m1[name] + if current1.dtype.names: + _recursive_mask_or(current1, m2[name], newmask[name]) + else: + umath.logical_or(current1, m2[name], newmask[name]) + return + + if (m1 is nomask) or (m1 is False): + dtype = getattr(m2, 'dtype', MaskType) + return make_mask(m2, copy=copy, shrink=shrink, dtype=dtype) + if (m2 is nomask) or (m2 is False): + dtype = getattr(m1, 'dtype', MaskType) + return make_mask(m1, copy=copy, shrink=shrink, dtype=dtype) + if m1 is m2 and is_mask(m1): + return m1 + (dtype1, dtype2) = (getattr(m1, 'dtype', None), getattr(m2, 'dtype', None)) + if (dtype1 != dtype2): + raise ValueError("Incompatible dtypes '%s'<>'%s'" % (dtype1, dtype2)) + if dtype1.names: + # Allocate an output mask array with the properly broadcast shape. + newmask = np.empty(np.broadcast(m1, m2).shape, dtype1) + _recursive_mask_or(m1, m2, newmask) + return newmask + return make_mask(umath.logical_or(m1, m2), copy=copy, shrink=shrink) + + +def flatten_mask(mask): + """ + Returns a completely flattened version of the mask, where nested fields + are collapsed. + + Parameters + ---------- + mask : array_like + Input array, which will be interpreted as booleans. + + Returns + ------- + flattened_mask : ndarray of bools + The flattened input. + + Examples + -------- + >>> mask = np.array([0, 0, 1]) + >>> flatten_mask(mask) + array([False, False, True]) + + >>> mask = np.array([(0, 0), (0, 1)], dtype=[('a', bool), ('b', bool)]) + >>> flatten_mask(mask) + array([False, False, False, True]) + + >>> mdtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])] + >>> mask = np.array([(0, (0, 0)), (0, (0, 1))], dtype=mdtype) + >>> flatten_mask(mask) + array([False, False, False, False, False, True]) + + """ + + def _flatmask(mask): + "Flatten the mask and returns a (maybe nested) sequence of booleans." + mnames = mask.dtype.names + if mnames: + return [flatten_mask(mask[name]) for name in mnames] + else: + return mask + + def _flatsequence(sequence): + "Generates a flattened version of the sequence." + try: + for element in sequence: + if hasattr(element, '__iter__'): + for f in _flatsequence(element): + yield f + else: + yield element + except TypeError: + yield sequence + + mask = np.asarray(mask) + flattened = _flatsequence(_flatmask(mask)) + return np.array([_ for _ in flattened], dtype=bool) + + +def _check_mask_axis(mask, axis, keepdims=np._NoValue): + "Check whether there are masked values along the given axis" + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + if mask is not nomask: + return mask.all(axis=axis, **kwargs) + return nomask + + +############################################################################### +# Masking functions # +############################################################################### + +def masked_where(condition, a, copy=True): + """ + Mask an array where a condition is met. + + Return `a` as an array masked where `condition` is True. + Any masked values of `a` or `condition` are also masked in the output. + + Parameters + ---------- + condition : array_like + Masking condition. When `condition` tests floating point values for + equality, consider using ``masked_values`` instead. + a : array_like + Array to mask. + copy : bool + If True (default) make a copy of `a` in the result. If False modify + `a` in place and return a view. + + Returns + ------- + result : MaskedArray + The result of masking `a` where `condition` is True. + + See Also + -------- + masked_values : Mask using floating point equality. + masked_equal : Mask where equal to a given value. + masked_not_equal : Mask where `not` equal to a given value. + masked_less_equal : Mask where less than or equal to a given value. + masked_greater_equal : Mask where greater than or equal to a given value. + masked_less : Mask where less than a given value. + masked_greater : Mask where greater than a given value. + masked_inside : Mask inside a given interval. + masked_outside : Mask outside a given interval. + masked_invalid : Mask invalid values (NaNs or infs). + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(4) + >>> a + array([0, 1, 2, 3]) + >>> ma.masked_where(a <= 2, a) + masked_array(data = [-- -- -- 3], + mask = [ True True True False], + fill_value=999999) + + Mask array `b` conditional on `a`. + + >>> b = ['a', 'b', 'c', 'd'] + >>> ma.masked_where(a == 2, b) + masked_array(data = [a b -- d], + mask = [False False True False], + fill_value=N/A) + + Effect of the `copy` argument. + + >>> c = ma.masked_where(a <= 2, a) + >>> c + masked_array(data = [-- -- -- 3], + mask = [ True True True False], + fill_value=999999) + >>> c[0] = 99 + >>> c + masked_array(data = [99 -- -- 3], + mask = [False True True False], + fill_value=999999) + >>> a + array([0, 1, 2, 3]) + >>> c = ma.masked_where(a <= 2, a, copy=False) + >>> c[0] = 99 + >>> c + masked_array(data = [99 -- -- 3], + mask = [False True True False], + fill_value=999999) + >>> a + array([99, 1, 2, 3]) + + When `condition` or `a` contain masked values. + + >>> a = np.arange(4) + >>> a = ma.masked_where(a == 2, a) + >>> a + masked_array(data = [0 1 -- 3], + mask = [False False True False], + fill_value=999999) + >>> b = np.arange(4) + >>> b = ma.masked_where(b == 0, b) + >>> b + masked_array(data = [-- 1 2 3], + mask = [ True False False False], + fill_value=999999) + >>> ma.masked_where(a == 3, b) + masked_array(data = [-- 1 -- --], + mask = [ True False True True], + fill_value=999999) + + """ + # Make sure that condition is a valid standard-type mask. + cond = make_mask(condition, shrink=False) + a = np.array(a, copy=copy, subok=True) + + (cshape, ashape) = (cond.shape, a.shape) + if cshape and cshape != ashape: + raise IndexError("Inconsistent shape between the condition and the input" + " (got %s and %s)" % (cshape, ashape)) + if hasattr(a, '_mask'): + cond = mask_or(cond, a._mask) + cls = type(a) + else: + cls = MaskedArray + result = a.view(cls) + # Assign to *.mask so that structured masks are handled correctly. + result.mask = _shrink_mask(cond) + return result + + +def masked_greater(x, value, copy=True): + """ + Mask an array where greater than a given value. + + This function is a shortcut to ``masked_where``, with + `condition` = (x > value). + + See Also + -------- + masked_where : Mask where a condition is met. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(4) + >>> a + array([0, 1, 2, 3]) + >>> ma.masked_greater(a, 2) + masked_array(data = [0 1 2 --], + mask = [False False False True], + fill_value=999999) + + """ + return masked_where(greater(x, value), x, copy=copy) + + +def masked_greater_equal(x, value, copy=True): + """ + Mask an array where greater than or equal to a given value. + + This function is a shortcut to ``masked_where``, with + `condition` = (x >= value). + + See Also + -------- + masked_where : Mask where a condition is met. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(4) + >>> a + array([0, 1, 2, 3]) + >>> ma.masked_greater_equal(a, 2) + masked_array(data = [0 1 -- --], + mask = [False False True True], + fill_value=999999) + + """ + return masked_where(greater_equal(x, value), x, copy=copy) + + +def masked_less(x, value, copy=True): + """ + Mask an array where less than a given value. + + This function is a shortcut to ``masked_where``, with + `condition` = (x < value). + + See Also + -------- + masked_where : Mask where a condition is met. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(4) + >>> a + array([0, 1, 2, 3]) + >>> ma.masked_less(a, 2) + masked_array(data = [-- -- 2 3], + mask = [ True True False False], + fill_value=999999) + + """ + return masked_where(less(x, value), x, copy=copy) + + +def masked_less_equal(x, value, copy=True): + """ + Mask an array where less than or equal to a given value. + + This function is a shortcut to ``masked_where``, with + `condition` = (x <= value). + + See Also + -------- + masked_where : Mask where a condition is met. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(4) + >>> a + array([0, 1, 2, 3]) + >>> ma.masked_less_equal(a, 2) + masked_array(data = [-- -- -- 3], + mask = [ True True True False], + fill_value=999999) + + """ + return masked_where(less_equal(x, value), x, copy=copy) + + +def masked_not_equal(x, value, copy=True): + """ + Mask an array where `not` equal to a given value. + + This function is a shortcut to ``masked_where``, with + `condition` = (x != value). + + See Also + -------- + masked_where : Mask where a condition is met. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(4) + >>> a + array([0, 1, 2, 3]) + >>> ma.masked_not_equal(a, 2) + masked_array(data = [-- -- 2 --], + mask = [ True True False True], + fill_value=999999) + + """ + return masked_where(not_equal(x, value), x, copy=copy) + + +def masked_equal(x, value, copy=True): + """ + Mask an array where equal to a given value. + + This function is a shortcut to ``masked_where``, with + `condition` = (x == value). For floating point arrays, + consider using ``masked_values(x, value)``. + + See Also + -------- + masked_where : Mask where a condition is met. + masked_values : Mask using floating point equality. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(4) + >>> a + array([0, 1, 2, 3]) + >>> ma.masked_equal(a, 2) + masked_array(data = [0 1 -- 3], + mask = [False False True False], + fill_value=999999) + + """ + output = masked_where(equal(x, value), x, copy=copy) + output.fill_value = value + return output + + +def masked_inside(x, v1, v2, copy=True): + """ + Mask an array inside a given interval. + + Shortcut to ``masked_where``, where `condition` is True for `x` inside + the interval [v1,v2] (v1 <= x <= v2). The boundaries `v1` and `v2` + can be given in either order. + + See Also + -------- + masked_where : Mask where a condition is met. + + Notes + ----- + The array `x` is prefilled with its filling value. + + Examples + -------- + >>> import numpy.ma as ma + >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1] + >>> ma.masked_inside(x, -0.3, 0.3) + masked_array(data = [0.31 1.2 -- -- -0.4 -1.1], + mask = [False False True True False False], + fill_value=1e+20) + + The order of `v1` and `v2` doesn't matter. + + >>> ma.masked_inside(x, 0.3, -0.3) + masked_array(data = [0.31 1.2 -- -- -0.4 -1.1], + mask = [False False True True False False], + fill_value=1e+20) + + """ + if v2 < v1: + (v1, v2) = (v2, v1) + xf = filled(x) + condition = (xf >= v1) & (xf <= v2) + return masked_where(condition, x, copy=copy) + + +def masked_outside(x, v1, v2, copy=True): + """ + Mask an array outside a given interval. + + Shortcut to ``masked_where``, where `condition` is True for `x` outside + the interval [v1,v2] (x < v1)|(x > v2). + The boundaries `v1` and `v2` can be given in either order. + + See Also + -------- + masked_where : Mask where a condition is met. + + Notes + ----- + The array `x` is prefilled with its filling value. + + Examples + -------- + >>> import numpy.ma as ma + >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1] + >>> ma.masked_outside(x, -0.3, 0.3) + masked_array(data = [-- -- 0.01 0.2 -- --], + mask = [ True True False False True True], + fill_value=1e+20) + + The order of `v1` and `v2` doesn't matter. + + >>> ma.masked_outside(x, 0.3, -0.3) + masked_array(data = [-- -- 0.01 0.2 -- --], + mask = [ True True False False True True], + fill_value=1e+20) + + """ + if v2 < v1: + (v1, v2) = (v2, v1) + xf = filled(x) + condition = (xf < v1) | (xf > v2) + return masked_where(condition, x, copy=copy) + + +def masked_object(x, value, copy=True, shrink=True): + """ + Mask the array `x` where the data are exactly equal to value. + + This function is similar to `masked_values`, but only suitable + for object arrays: for floating point, use `masked_values` instead. + + Parameters + ---------- + x : array_like + Array to mask + value : object + Comparison value + copy : {True, False}, optional + Whether to return a copy of `x`. + shrink : {True, False}, optional + Whether to collapse a mask full of False to nomask + + Returns + ------- + result : MaskedArray + The result of masking `x` where equal to `value`. + + See Also + -------- + masked_where : Mask where a condition is met. + masked_equal : Mask where equal to a given value (integers). + masked_values : Mask using floating point equality. + + Examples + -------- + >>> import numpy.ma as ma + >>> food = np.array(['green_eggs', 'ham'], dtype=object) + >>> # don't eat spoiled food + >>> eat = ma.masked_object(food, 'green_eggs') + >>> print(eat) + [-- ham] + >>> # plain ol` ham is boring + >>> fresh_food = np.array(['cheese', 'ham', 'pineapple'], dtype=object) + >>> eat = ma.masked_object(fresh_food, 'green_eggs') + >>> print(eat) + [cheese ham pineapple] + + Note that `mask` is set to ``nomask`` if possible. + + >>> eat + masked_array(data = [cheese ham pineapple], + mask = False, + fill_value=?) + + """ + if isMaskedArray(x): + condition = umath.equal(x._data, value) + mask = x._mask + else: + condition = umath.equal(np.asarray(x), value) + mask = nomask + mask = mask_or(mask, make_mask(condition, shrink=shrink)) + return masked_array(x, mask=mask, copy=copy, fill_value=value) + + +def masked_values(x, value, rtol=1e-5, atol=1e-8, copy=True, shrink=True): + """ + Mask using floating point equality. + + Return a MaskedArray, masked where the data in array `x` are approximately + equal to `value`, determined using `isclose`. The default tolerances for + `masked_values` are the same as those for `isclose`. + + For integer types, exact equality is used, in the same way as + `masked_equal`. + + The fill_value is set to `value` and the mask is set to ``nomask`` if + possible. + + Parameters + ---------- + x : array_like + Array to mask. + value : float + Masking value. + rtol, atol : float, optional + Tolerance parameters passed on to `isclose` + copy : bool, optional + Whether to return a copy of `x`. + shrink : bool, optional + Whether to collapse a mask full of False to ``nomask``. + + Returns + ------- + result : MaskedArray + The result of masking `x` where approximately equal to `value`. + + See Also + -------- + masked_where : Mask where a condition is met. + masked_equal : Mask where equal to a given value (integers). + + Examples + -------- + >>> import numpy.ma as ma + >>> x = np.array([1, 1.1, 2, 1.1, 3]) + >>> ma.masked_values(x, 1.1) + masked_array(data = [1.0 -- 2.0 -- 3.0], + mask = [False True False True False], + fill_value=1.1) + + Note that `mask` is set to ``nomask`` if possible. + + >>> ma.masked_values(x, 1.5) + masked_array(data = [ 1. 1.1 2. 1.1 3. ], + mask = False, + fill_value=1.5) + + For integers, the fill value will be different in general to the + result of ``masked_equal``. + + >>> x = np.arange(5) + >>> x + array([0, 1, 2, 3, 4]) + >>> ma.masked_values(x, 2) + masked_array(data = [0 1 -- 3 4], + mask = [False False True False False], + fill_value=2) + >>> ma.masked_equal(x, 2) + masked_array(data = [0 1 -- 3 4], + mask = [False False True False False], + fill_value=999999) + + """ + xnew = filled(x, value) + if np.issubdtype(xnew.dtype, np.floating): + mask = np.isclose(xnew, value, atol=atol, rtol=rtol) + else: + mask = umath.equal(xnew, value) + return masked_array( + xnew, mask=mask, copy=copy, fill_value=value, shrink=shrink) + + +def masked_invalid(a, copy=True): + """ + Mask an array where invalid values occur (NaNs or infs). + + This function is a shortcut to ``masked_where``, with + `condition` = ~(np.isfinite(a)). Any pre-existing mask is conserved. + Only applies to arrays with a dtype where NaNs or infs make sense + (i.e. floating point types), but accepts any array_like object. + + See Also + -------- + masked_where : Mask where a condition is met. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(5, dtype=float) + >>> a[2] = np.NaN + >>> a[3] = np.PINF + >>> a + array([ 0., 1., NaN, Inf, 4.]) + >>> ma.masked_invalid(a) + masked_array(data = [0.0 1.0 -- -- 4.0], + mask = [False False True True False], + fill_value=1e+20) + + """ + a = np.array(a, copy=copy, subok=True) + mask = getattr(a, '_mask', None) + if mask is not None: + condition = ~(np.isfinite(getdata(a))) + if mask is not nomask: + condition |= mask + cls = type(a) + else: + condition = ~(np.isfinite(a)) + cls = MaskedArray + result = a.view(cls) + result._mask = condition + return result + + +############################################################################### +# Printing options # +############################################################################### + + +class _MaskedPrintOption(object): + """ + Handle the string used to represent missing data in a masked array. + + """ + + def __init__(self, display): + """ + Create the masked_print_option object. + + """ + self._display = display + self._enabled = True + + def display(self): + """ + Display the string to print for masked values. + + """ + return self._display + + def set_display(self, s): + """ + Set the string to print for masked values. + + """ + self._display = s + + def enabled(self): + """ + Is the use of the display value enabled? + + """ + return self._enabled + + def enable(self, shrink=1): + """ + Set the enabling shrink to `shrink`. + + """ + self._enabled = shrink + + def __str__(self): + return str(self._display) + + __repr__ = __str__ + +# if you single index into a masked location you get this object. +masked_print_option = _MaskedPrintOption('--') + + +def _recursive_printoption(result, mask, printopt): + """ + Puts printoptions in result where mask is True. + + Private function allowing for recursion + + """ + names = result.dtype.names + if names: + for name in names: + curdata = result[name] + curmask = mask[name] + _recursive_printoption(curdata, curmask, printopt) + else: + np.copyto(result, printopt, where=mask) + return + +# For better or worse, these end in a newline +_legacy_print_templates = dict( + long_std=textwrap.dedent("""\ + masked_%(name)s(data = + %(data)s, + %(nlen)s mask = + %(mask)s, + %(nlen)s fill_value = %(fill)s) + """), + long_flx=textwrap.dedent("""\ + masked_%(name)s(data = + %(data)s, + %(nlen)s mask = + %(mask)s, + %(nlen)s fill_value = %(fill)s, + %(nlen)s dtype = %(dtype)s) + """), + short_std=textwrap.dedent("""\ + masked_%(name)s(data = %(data)s, + %(nlen)s mask = %(mask)s, + %(nlen)s fill_value = %(fill)s) + """), + short_flx=textwrap.dedent("""\ + masked_%(name)s(data = %(data)s, + %(nlen)s mask = %(mask)s, + %(nlen)s fill_value = %(fill)s, + %(nlen)s dtype = %(dtype)s) + """) +) + +############################################################################### +# MaskedArray class # +############################################################################### + + +def _recursive_filled(a, mask, fill_value): + """ + Recursively fill `a` with `fill_value`. + + """ + names = a.dtype.names + for name in names: + current = a[name] + if current.dtype.names: + _recursive_filled(current, mask[name], fill_value[name]) + else: + np.copyto(current, fill_value[name], where=mask[name]) + + +def flatten_structured_array(a): + """ + Flatten a structured array. + + The data type of the output is chosen such that it can represent all of the + (nested) fields. + + Parameters + ---------- + a : structured array + + Returns + ------- + output : masked array or ndarray + A flattened masked array if the input is a masked array, otherwise a + standard ndarray. + + Examples + -------- + >>> ndtype = [('a', int), ('b', float)] + >>> a = np.array([(1, 1), (2, 2)], dtype=ndtype) + >>> flatten_structured_array(a) + array([[1., 1.], + [2., 2.]]) + + """ + + def flatten_sequence(iterable): + """ + Flattens a compound of nested iterables. + + """ + for elm in iter(iterable): + if hasattr(elm, '__iter__'): + for f in flatten_sequence(elm): + yield f + else: + yield elm + + a = np.asanyarray(a) + inishape = a.shape + a = a.ravel() + if isinstance(a, MaskedArray): + out = np.array([tuple(flatten_sequence(d.item())) for d in a._data]) + out = out.view(MaskedArray) + out._mask = np.array([tuple(flatten_sequence(d.item())) + for d in getmaskarray(a)]) + else: + out = np.array([tuple(flatten_sequence(d.item())) for d in a]) + if len(inishape) > 1: + newshape = list(out.shape) + newshape[0] = inishape + out.shape = tuple(flatten_sequence(newshape)) + return out + + +def _arraymethod(funcname, onmask=True): + """ + Return a class method wrapper around a basic array method. + + Creates a class method which returns a masked array, where the new + ``_data`` array is the output of the corresponding basic method called + on the original ``_data``. + + If `onmask` is True, the new mask is the output of the method called + on the initial mask. Otherwise, the new mask is just a reference + to the initial mask. + + Parameters + ---------- + funcname : str + Name of the function to apply on data. + onmask : bool + Whether the mask must be processed also (True) or left + alone (False). Default is True. Make available as `_onmask` + attribute. + + Returns + ------- + method : instancemethod + Class method wrapper of the specified basic array method. + + """ + def wrapped_method(self, *args, **params): + result = getattr(self._data, funcname)(*args, **params) + result = result.view(type(self)) + result._update_from(self) + mask = self._mask + if not onmask: + result.__setmask__(mask) + elif mask is not nomask: + # __setmask__ makes a copy, which we don't want + result._mask = getattr(mask, funcname)(*args, **params) + return result + methdoc = getattr(ndarray, funcname, None) or getattr(np, funcname, None) + if methdoc is not None: + wrapped_method.__doc__ = methdoc.__doc__ + wrapped_method.__name__ = funcname + return wrapped_method + + +class MaskedIterator(object): + """ + Flat iterator object to iterate over masked arrays. + + A `MaskedIterator` iterator is returned by ``x.flat`` for any masked array + `x`. It allows iterating over the array as if it were a 1-D array, + either in a for-loop or by calling its `next` method. + + Iteration is done in C-contiguous style, with the last index varying the + fastest. The iterator can also be indexed using basic slicing or + advanced indexing. + + See Also + -------- + MaskedArray.flat : Return a flat iterator over an array. + MaskedArray.flatten : Returns a flattened copy of an array. + + Notes + ----- + `MaskedIterator` is not exported by the `ma` module. Instead of + instantiating a `MaskedIterator` directly, use `MaskedArray.flat`. + + Examples + -------- + >>> x = np.ma.array(arange(6).reshape(2, 3)) + >>> fl = x.flat + >>> type(fl) + + >>> for item in fl: + ... print(item) + ... + 0 + 1 + 2 + 3 + 4 + 5 + + Extracting more than a single element b indexing the `MaskedIterator` + returns a masked array: + + >>> fl[2:4] + masked_array(data = [2 3], + mask = False, + fill_value = 999999) + + """ + + def __init__(self, ma): + self.ma = ma + self.dataiter = ma._data.flat + + if ma._mask is nomask: + self.maskiter = None + else: + self.maskiter = ma._mask.flat + + def __iter__(self): + return self + + def __getitem__(self, indx): + result = self.dataiter.__getitem__(indx).view(type(self.ma)) + if self.maskiter is not None: + _mask = self.maskiter.__getitem__(indx) + if isinstance(_mask, ndarray): + # set shape to match that of data; this is needed for matrices + _mask.shape = result.shape + result._mask = _mask + elif isinstance(_mask, np.void): + return mvoid(result, mask=_mask, hardmask=self.ma._hardmask) + elif _mask: # Just a scalar, masked + return masked + return result + + # This won't work if ravel makes a copy + def __setitem__(self, index, value): + self.dataiter[index] = getdata(value) + if self.maskiter is not None: + self.maskiter[index] = getmaskarray(value) + + def __next__(self): + """ + Return the next value, or raise StopIteration. + + Examples + -------- + >>> x = np.ma.array([3, 2], mask=[0, 1]) + >>> fl = x.flat + >>> fl.next() + 3 + >>> fl.next() + masked_array(data = --, + mask = True, + fill_value = 1e+20) + >>> fl.next() + Traceback (most recent call last): + File "", line 1, in + File "/home/ralf/python/numpy/numpy/ma/core.py", line 2243, in next + d = self.dataiter.next() + StopIteration + + """ + d = next(self.dataiter) + if self.maskiter is not None: + m = next(self.maskiter) + if isinstance(m, np.void): + return mvoid(d, mask=m, hardmask=self.ma._hardmask) + elif m: # Just a scalar, masked + return masked + return d + + next = __next__ + + +class MaskedArray(ndarray): + """ + An array class with possibly masked values. + + Masked values of True exclude the corresponding element from any + computation. + + Construction:: + + x = MaskedArray(data, mask=nomask, dtype=None, copy=False, subok=True, + ndmin=0, fill_value=None, keep_mask=True, hard_mask=None, + shrink=True, order=None) + + Parameters + ---------- + data : array_like + Input data. + mask : sequence, optional + Mask. Must be convertible to an array of booleans with the same + shape as `data`. True indicates a masked (i.e. invalid) data. + dtype : dtype, optional + Data type of the output. + If `dtype` is None, the type of the data argument (``data.dtype``) + is used. If `dtype` is not None and different from ``data.dtype``, + a copy is performed. + copy : bool, optional + Whether to copy the input data (True), or to use a reference instead. + Default is False. + subok : bool, optional + Whether to return a subclass of `MaskedArray` if possible (True) or a + plain `MaskedArray`. Default is True. + ndmin : int, optional + Minimum number of dimensions. Default is 0. + fill_value : scalar, optional + Value used to fill in the masked values when necessary. + If None, a default based on the data-type is used. + keep_mask : bool, optional + Whether to combine `mask` with the mask of the input data, if any + (True), or to use only `mask` for the output (False). Default is True. + hard_mask : bool, optional + Whether to use a hard mask or not. With a hard mask, masked values + cannot be unmasked. Default is False. + shrink : bool, optional + Whether to force compression of an empty mask. Default is True. + order : {'C', 'F', 'A'}, optional + Specify the order of the array. If order is 'C', then the array + will be in C-contiguous order (last-index varies the fastest). + If order is 'F', then the returned array will be in + Fortran-contiguous order (first-index varies the fastest). + If order is 'A' (default), then the returned array may be + in any order (either C-, Fortran-contiguous, or even discontiguous), + unless a copy is required, in which case it will be C-contiguous. + + """ + + __array_priority__ = 15 + _defaultmask = nomask + _defaulthardmask = False + _baseclass = ndarray + + # Maximum number of elements per axis used when printing an array. The + # 1d case is handled separately because we need more values in this case. + _print_width = 100 + _print_width_1d = 1500 + + def __new__(cls, data=None, mask=nomask, dtype=None, copy=False, + subok=True, ndmin=0, fill_value=None, keep_mask=True, + hard_mask=None, shrink=True, order=None, **options): + """ + Create a new masked array from scratch. + + Notes + ----- + A masked array can also be created by taking a .view(MaskedArray). + + """ + # Process data. + _data = np.array(data, dtype=dtype, copy=copy, + order=order, subok=True, ndmin=ndmin) + _baseclass = getattr(data, '_baseclass', type(_data)) + # Check that we're not erasing the mask. + if isinstance(data, MaskedArray) and (data.shape != _data.shape): + copy = True + + # Here, we copy the _view_, so that we can attach new properties to it + # we must never do .view(MaskedConstant), as that would create a new + # instance of np.ma.masked, which make identity comparison fail + if isinstance(data, cls) and subok and not isinstance(data, MaskedConstant): + _data = ndarray.view(_data, type(data)) + else: + _data = ndarray.view(_data, cls) + # Backwards compatibility w/ numpy.core.ma. + if hasattr(data, '_mask') and not isinstance(data, ndarray): + _data._mask = data._mask + # FIXME _sharedmask is never used. + _sharedmask = True + # Process mask. + # Number of named fields (or zero if none) + names_ = _data.dtype.names or () + # Type of the mask + if names_: + mdtype = make_mask_descr(_data.dtype) + else: + mdtype = MaskType + + if mask is nomask: + # Case 1. : no mask in input. + # Erase the current mask ? + if not keep_mask: + # With a reduced version + if shrink: + _data._mask = nomask + # With full version + else: + _data._mask = np.zeros(_data.shape, dtype=mdtype) + # Check whether we missed something + elif isinstance(data, (tuple, list)): + try: + # If data is a sequence of masked array + mask = np.array([getmaskarray(m) for m in data], + dtype=mdtype) + except ValueError: + # If data is nested + mask = nomask + # Force shrinking of the mask if needed (and possible) + if (mdtype == MaskType) and mask.any(): + _data._mask = mask + _data._sharedmask = False + else: + if copy: + _data._mask = _data._mask.copy() + _data._sharedmask = False + # Reset the shape of the original mask + if getmask(data) is not nomask: + data._mask.shape = data.shape + else: + _data._sharedmask = True + else: + # Case 2. : With a mask in input. + # If mask is boolean, create an array of True or False + if mask is True and mdtype == MaskType: + mask = np.ones(_data.shape, dtype=mdtype) + elif mask is False and mdtype == MaskType: + mask = np.zeros(_data.shape, dtype=mdtype) + else: + # Read the mask with the current mdtype + try: + mask = np.array(mask, copy=copy, dtype=mdtype) + # Or assume it's a sequence of bool/int + except TypeError: + mask = np.array([tuple([m] * len(mdtype)) for m in mask], + dtype=mdtype) + # Make sure the mask and the data have the same shape + if mask.shape != _data.shape: + (nd, nm) = (_data.size, mask.size) + if nm == 1: + mask = np.resize(mask, _data.shape) + elif nm == nd: + mask = np.reshape(mask, _data.shape) + else: + msg = "Mask and data not compatible: data size is %i, " + \ + "mask size is %i." + raise MaskError(msg % (nd, nm)) + copy = True + # Set the mask to the new value + if _data._mask is nomask: + _data._mask = mask + _data._sharedmask = not copy + else: + if not keep_mask: + _data._mask = mask + _data._sharedmask = not copy + else: + if names_: + def _recursive_or(a, b): + "do a|=b on each field of a, recursively" + for name in a.dtype.names: + (af, bf) = (a[name], b[name]) + if af.dtype.names: + _recursive_or(af, bf) + else: + af |= bf + return + _recursive_or(_data._mask, mask) + else: + _data._mask = np.logical_or(mask, _data._mask) + _data._sharedmask = False + # Update fill_value. + if fill_value is None: + fill_value = getattr(data, '_fill_value', None) + # But don't run the check unless we have something to check. + if fill_value is not None: + _data._fill_value = _check_fill_value(fill_value, _data.dtype) + # Process extra options .. + if hard_mask is None: + _data._hardmask = getattr(data, '_hardmask', False) + else: + _data._hardmask = hard_mask + _data._baseclass = _baseclass + return _data + + + def _update_from(self, obj): + """ + Copies some attributes of obj to self. + + """ + if isinstance(obj, ndarray): + _baseclass = type(obj) + else: + _baseclass = ndarray + # We need to copy the _basedict to avoid backward propagation + _optinfo = {} + _optinfo.update(getattr(obj, '_optinfo', {})) + _optinfo.update(getattr(obj, '_basedict', {})) + if not isinstance(obj, MaskedArray): + _optinfo.update(getattr(obj, '__dict__', {})) + _dict = dict(_fill_value=getattr(obj, '_fill_value', None), + _hardmask=getattr(obj, '_hardmask', False), + _sharedmask=getattr(obj, '_sharedmask', False), + _isfield=getattr(obj, '_isfield', False), + _baseclass=getattr(obj, '_baseclass', _baseclass), + _optinfo=_optinfo, + _basedict=_optinfo) + self.__dict__.update(_dict) + self.__dict__.update(_optinfo) + return + + def __array_finalize__(self, obj): + """ + Finalizes the masked array. + + """ + # Get main attributes. + self._update_from(obj) + + # We have to decide how to initialize self.mask, based on + # obj.mask. This is very difficult. There might be some + # correspondence between the elements in the array we are being + # created from (= obj) and us. Or there might not. This method can + # be called in all kinds of places for all kinds of reasons -- could + # be empty_like, could be slicing, could be a ufunc, could be a view. + # The numpy subclassing interface simply doesn't give us any way + # to know, which means that at best this method will be based on + # guesswork and heuristics. To make things worse, there isn't even any + # clear consensus about what the desired behavior is. For instance, + # most users think that np.empty_like(marr) -- which goes via this + # method -- should return a masked array with an empty mask (see + # gh-3404 and linked discussions), but others disagree, and they have + # existing code which depends on empty_like returning an array that + # matches the input mask. + # + # Historically our algorithm was: if the template object mask had the + # same *number of elements* as us, then we used *it's mask object + # itself* as our mask, so that writes to us would also write to the + # original array. This is horribly broken in multiple ways. + # + # Now what we do instead is, if the template object mask has the same + # number of elements as us, and we do not have the same base pointer + # as the template object (b/c views like arr[...] should keep the same + # mask), then we make a copy of the template object mask and use + # that. This is also horribly broken but somewhat less so. Maybe. + if isinstance(obj, ndarray): + # XX: This looks like a bug -- shouldn't it check self.dtype + # instead? + if obj.dtype.names: + _mask = getmaskarray(obj) + else: + _mask = getmask(obj) + + # If self and obj point to exactly the same data, then probably + # self is a simple view of obj (e.g., self = obj[...]), so they + # should share the same mask. (This isn't 100% reliable, e.g. self + # could be the first row of obj, or have strange strides, but as a + # heuristic it's not bad.) In all other cases, we make a copy of + # the mask, so that future modifications to 'self' do not end up + # side-effecting 'obj' as well. + if (obj.__array_interface__["data"][0] + != self.__array_interface__["data"][0]): + _mask = _mask.copy() + else: + _mask = nomask + self._mask = _mask + # Finalize the mask + if self._mask is not nomask: + try: + self._mask.shape = self.shape + except ValueError: + self._mask = nomask + except (TypeError, AttributeError): + # When _mask.shape is not writable (because it's a void) + pass + # Finalize the fill_value for structured arrays + if self.dtype.names: + if self._fill_value is None: + self._fill_value = _check_fill_value(None, self.dtype) + return + + def __array_wrap__(self, obj, context=None): + """ + Special hook for ufuncs. + + Wraps the numpy array and sets the mask according to context. + + """ + if obj is self: # for in-place operations + result = obj + else: + result = obj.view(type(self)) + result._update_from(self) + + if context is not None: + result._mask = result._mask.copy() + func, args, out_i = context + # args sometimes contains outputs (gh-10459), which we don't want + input_args = args[:func.nin] + m = reduce(mask_or, [getmaskarray(arg) for arg in input_args]) + # Get the domain mask + domain = ufunc_domain.get(func, None) + if domain is not None: + # Take the domain, and make sure it's a ndarray + if len(input_args) > 2: + with np.errstate(divide='ignore', invalid='ignore'): + d = filled(reduce(domain, input_args), True) + else: + with np.errstate(divide='ignore', invalid='ignore'): + d = filled(domain(*input_args), True) + + if d.any(): + # Fill the result where the domain is wrong + try: + # Binary domain: take the last value + fill_value = ufunc_fills[func][-1] + except TypeError: + # Unary domain: just use this one + fill_value = ufunc_fills[func] + except KeyError: + # Domain not recognized, use fill_value instead + fill_value = self.fill_value + + np.copyto(result, fill_value, where=d) + + # Update the mask + if m is nomask: + m = d + else: + # Don't modify inplace, we risk back-propagation + m = (m | d) + + # Make sure the mask has the proper size + if result is not self and result.shape == () and m: + return masked + else: + result._mask = m + result._sharedmask = False + + return result + + def view(self, dtype=None, type=None, fill_value=None): + """ + Return a view of the MaskedArray data + + Parameters + ---------- + dtype : data-type or ndarray sub-class, optional + Data-type descriptor of the returned view, e.g., float32 or int16. + The default, None, results in the view having the same data-type + as `a`. As with ``ndarray.view``, dtype can also be specified as + an ndarray sub-class, which then specifies the type of the + returned object (this is equivalent to setting the ``type`` + parameter). + type : Python type, optional + Type of the returned view, e.g., ndarray or matrix. Again, the + default None results in type preservation. + + Notes + ----- + + ``a.view()`` is used two different ways: + + ``a.view(some_dtype)`` or ``a.view(dtype=some_dtype)`` constructs a view + of the array's memory with a different data-type. This can cause a + reinterpretation of the bytes of memory. + + ``a.view(ndarray_subclass)`` or ``a.view(type=ndarray_subclass)`` just + returns an instance of `ndarray_subclass` that looks at the same array + (same shape, dtype, etc.) This does not cause a reinterpretation of the + memory. + + If `fill_value` is not specified, but `dtype` is specified (and is not + an ndarray sub-class), the `fill_value` of the MaskedArray will be + reset. If neither `fill_value` nor `dtype` are specified (or if + `dtype` is an ndarray sub-class), then the fill value is preserved. + Finally, if `fill_value` is specified, but `dtype` is not, the fill + value is set to the specified value. + + For ``a.view(some_dtype)``, if ``some_dtype`` has a different number of + bytes per entry than the previous dtype (for example, converting a + regular array to a structured array), then the behavior of the view + cannot be predicted just from the superficial appearance of ``a`` (shown + by ``print(a)``). It also depends on exactly how ``a`` is stored in + memory. Therefore if ``a`` is C-ordered versus fortran-ordered, versus + defined as a slice or transpose, etc., the view may give different + results. + """ + + if dtype is None: + if type is None: + output = ndarray.view(self) + else: + output = ndarray.view(self, type) + elif type is None: + try: + if issubclass(dtype, ndarray): + output = ndarray.view(self, dtype) + dtype = None + else: + output = ndarray.view(self, dtype) + except TypeError: + output = ndarray.view(self, dtype) + else: + output = ndarray.view(self, dtype, type) + + # also make the mask be a view (so attr changes to the view's + # mask do no affect original object's mask) + # (especially important to avoid affecting np.masked singleton) + if (getmask(output) is not nomask): + output._mask = output._mask.view() + + # Make sure to reset the _fill_value if needed + if getattr(output, '_fill_value', None) is not None: + if fill_value is None: + if dtype is None: + pass # leave _fill_value as is + else: + output._fill_value = None + else: + output.fill_value = fill_value + return output + view.__doc__ = ndarray.view.__doc__ + + def astype(self, newtype): + """ + Returns a copy of the MaskedArray cast to given newtype. + + Returns + ------- + output : MaskedArray + A copy of self cast to input newtype. + The returned record shape matches self.shape. + + Examples + -------- + >>> x = np.ma.array([[1,2,3.1],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) + >>> print(x) + [[1.0 -- 3.1] + [-- 5.0 --] + [7.0 -- 9.0]] + >>> print(x.astype(int32)) + [[1 -- 3] + [-- 5 --] + [7 -- 9]] + + """ + newtype = np.dtype(newtype) + newmasktype = make_mask_descr(newtype) + + output = self._data.astype(newtype).view(type(self)) + output._update_from(self) + + if self._mask is nomask: + output._mask = nomask + else: + output._mask = self._mask.astype(newmasktype) + + # Don't check _fill_value if it's None, that'll speed things up + if self._fill_value is not None: + output._fill_value = _check_fill_value(self._fill_value, newtype) + return output + + def __getitem__(self, indx): + """ + x.__getitem__(y) <==> x[y] + + Return the item described by i, as a masked array. + + """ + # We could directly use ndarray.__getitem__ on self. + # But then we would have to modify __array_finalize__ to prevent the + # mask of being reshaped if it hasn't been set up properly yet + # So it's easier to stick to the current version + dout = self.data[indx] + _mask = self._mask + + def _is_scalar(m): + return not isinstance(m, np.ndarray) + + def _scalar_heuristic(arr, elem): + """ + Return whether `elem` is a scalar result of indexing `arr`, or None + if undecidable without promoting nomask to a full mask + """ + # obviously a scalar + if not isinstance(elem, np.ndarray): + return True + + # object array scalar indexing can return anything + elif arr.dtype.type is np.object_: + if arr.dtype is not elem.dtype: + # elem is an array, but dtypes do not match, so must be + # an element + return True + + # well-behaved subclass that only returns 0d arrays when + # expected - this is not a scalar + elif type(arr).__getitem__ == ndarray.__getitem__: + return False + + return None + + if _mask is not nomask: + # _mask cannot be a subclass, so it tells us whether we should + # expect a scalar. It also cannot be of dtype object. + mout = _mask[indx] + scalar_expected = _is_scalar(mout) + + else: + # attempt to apply the heuristic to avoid constructing a full mask + mout = nomask + scalar_expected = _scalar_heuristic(self.data, dout) + if scalar_expected is None: + # heuristics have failed + # construct a full array, so we can be certain. This is costly. + # we could also fall back on ndarray.__getitem__(self.data, indx) + scalar_expected = _is_scalar(getmaskarray(self)[indx]) + + # Did we extract a single item? + if scalar_expected: + # A record + if isinstance(dout, np.void): + # We should always re-cast to mvoid, otherwise users can + # change masks on rows that already have masked values, but not + # on rows that have no masked values, which is inconsistent. + return mvoid(dout, mask=mout, hardmask=self._hardmask) + + # special case introduced in gh-5962 + elif (self.dtype.type is np.object_ and + isinstance(dout, np.ndarray) and + dout is not masked): + # If masked, turn into a MaskedArray, with everything masked. + if mout: + return MaskedArray(dout, mask=True) + else: + return dout + + # Just a scalar + else: + if mout: + return masked + else: + return dout + else: + # Force dout to MA + dout = dout.view(type(self)) + # Inherit attributes from self + dout._update_from(self) + # Check the fill_value + if isinstance(indx, basestring): + if self._fill_value is not None: + dout._fill_value = self._fill_value[indx] + + # If we're indexing a multidimensional field in a + # structured array (such as dtype("(2,)i2,(2,)i1")), + # dimensionality goes up (M[field].ndim == M.ndim + + # M.dtype[field].ndim). That's fine for + # M[field] but problematic for M[field].fill_value + # which should have shape () to avoid breaking several + # methods. There is no great way out, so set to + # first element. See issue #6723. + if dout._fill_value.ndim > 0: + if not (dout._fill_value == + dout._fill_value.flat[0]).all(): + warnings.warn( + "Upon accessing multidimensional field " + "{indx:s}, need to keep dimensionality " + "of fill_value at 0. Discarding " + "heterogeneous fill_value and setting " + "all to {fv!s}.".format(indx=indx, + fv=dout._fill_value[0]), + stacklevel=2) + dout._fill_value = dout._fill_value.flat[0] + dout._isfield = True + # Update the mask if needed + if mout is not nomask: + # set shape to match that of data; this is needed for matrices + dout._mask = reshape(mout, dout.shape) + dout._sharedmask = True + # Note: Don't try to check for m.any(), that'll take too long + return dout + + def __setitem__(self, indx, value): + """ + x.__setitem__(i, y) <==> x[i]=y + + Set item described by index. If value is masked, masks those + locations. + + """ + if self is masked: + raise MaskError('Cannot alter the masked element.') + _data = self._data + _mask = self._mask + if isinstance(indx, basestring): + _data[indx] = value + if _mask is nomask: + self._mask = _mask = make_mask_none(self.shape, self.dtype) + _mask[indx] = getmask(value) + return + + _dtype = _data.dtype + nbfields = len(_dtype.names or ()) + + if value is masked: + # The mask wasn't set: create a full version. + if _mask is nomask: + _mask = self._mask = make_mask_none(self.shape, _dtype) + # Now, set the mask to its value. + if nbfields: + _mask[indx] = tuple([True] * nbfields) + else: + _mask[indx] = True + return + + # Get the _data part of the new value + dval = getattr(value, '_data', value) + # Get the _mask part of the new value + mval = getmask(value) + if nbfields and mval is nomask: + mval = tuple([False] * nbfields) + if _mask is nomask: + # Set the data, then the mask + _data[indx] = dval + if mval is not nomask: + _mask = self._mask = make_mask_none(self.shape, _dtype) + _mask[indx] = mval + elif not self._hardmask: + # Set the data, then the mask + _data[indx] = dval + _mask[indx] = mval + elif hasattr(indx, 'dtype') and (indx.dtype == MaskType): + indx = indx * umath.logical_not(_mask) + _data[indx] = dval + else: + if nbfields: + err_msg = "Flexible 'hard' masks are not yet supported." + raise NotImplementedError(err_msg) + mindx = mask_or(_mask[indx], mval, copy=True) + dindx = self._data[indx] + if dindx.size > 1: + np.copyto(dindx, dval, where=~mindx) + elif mindx is nomask: + dindx = dval + _data[indx] = dindx + _mask[indx] = mindx + return + + def __setattr__(self, attr, value): + super(MaskedArray, self).__setattr__(attr, value) + if attr == 'dtype' and self._mask is not nomask: + self._mask = self._mask.view(make_mask_descr(value), ndarray) + # Try to reset the shape of the mask (if we don't have a void) + # This raises a ValueError if the dtype change won't work + try: + self._mask.shape = self.shape + except (AttributeError, TypeError): + pass + + def __setmask__(self, mask, copy=False): + """ + Set the mask. + + """ + idtype = self.dtype + current_mask = self._mask + if mask is masked: + mask = True + + if (current_mask is nomask): + # Make sure the mask is set + # Just don't do anything if there's nothing to do. + if mask is nomask: + return + current_mask = self._mask = make_mask_none(self.shape, idtype) + + if idtype.names is None: + # No named fields. + # Hardmask: don't unmask the data + if self._hardmask: + current_mask |= mask + # Softmask: set everything to False + # If it's obviously a compatible scalar, use a quick update + # method. + elif isinstance(mask, (int, float, np.bool_, np.number)): + current_mask[...] = mask + # Otherwise fall back to the slower, general purpose way. + else: + current_mask.flat = mask + else: + # Named fields w/ + mdtype = current_mask.dtype + mask = np.array(mask, copy=False) + # Mask is a singleton + if not mask.ndim: + # It's a boolean : make a record + if mask.dtype.kind == 'b': + mask = np.array(tuple([mask.item()] * len(mdtype)), + dtype=mdtype) + # It's a record: make sure the dtype is correct + else: + mask = mask.astype(mdtype) + # Mask is a sequence + else: + # Make sure the new mask is a ndarray with the proper dtype + try: + mask = np.array(mask, copy=copy, dtype=mdtype) + # Or assume it's a sequence of bool/int + except TypeError: + mask = np.array([tuple([m] * len(mdtype)) for m in mask], + dtype=mdtype) + # Hardmask: don't unmask the data + if self._hardmask: + for n in idtype.names: + current_mask[n] |= mask[n] + # Softmask: set everything to False + # If it's obviously a compatible scalar, use a quick update + # method. + elif isinstance(mask, (int, float, np.bool_, np.number)): + current_mask[...] = mask + # Otherwise fall back to the slower, general purpose way. + else: + current_mask.flat = mask + # Reshape if needed + if current_mask.shape: + current_mask.shape = self.shape + return + + _set_mask = __setmask__ + + def _get_mask(self): + """Return the current mask. + + """ + # We could try to force a reshape, but that wouldn't work in some + # cases. + return self._mask + + mask = property(fget=_get_mask, fset=__setmask__, doc="Mask") + + def _get_recordmask(self): + """ + Return the mask of the records. + + A record is masked when all the fields are masked. + + """ + _mask = self._mask.view(ndarray) + if _mask.dtype.names is None: + return _mask + return np.all(flatten_structured_array(_mask), axis=-1) + + def _set_recordmask(self): + """ + Return the mask of the records. + + A record is masked when all the fields are masked. + + """ + raise NotImplementedError("Coming soon: setting the mask per records!") + + recordmask = property(fget=_get_recordmask) + + def harden_mask(self): + """ + Force the mask to hard. + + Whether the mask of a masked array is hard or soft is determined by + its `hardmask` property. `harden_mask` sets `hardmask` to True. + + See Also + -------- + hardmask + + """ + self._hardmask = True + return self + + def soften_mask(self): + """ + Force the mask to soft. + + Whether the mask of a masked array is hard or soft is determined by + its `hardmask` property. `soften_mask` sets `hardmask` to False. + + See Also + -------- + hardmask + + """ + self._hardmask = False + return self + + hardmask = property(fget=lambda self: self._hardmask, + doc="Hardness of the mask") + + def unshare_mask(self): + """ + Copy the mask and set the sharedmask flag to False. + + Whether the mask is shared between masked arrays can be seen from + the `sharedmask` property. `unshare_mask` ensures the mask is not shared. + A copy of the mask is only made if it was shared. + + See Also + -------- + sharedmask + + """ + if self._sharedmask: + self._mask = self._mask.copy() + self._sharedmask = False + return self + + sharedmask = property(fget=lambda self: self._sharedmask, + doc="Share status of the mask (read-only).") + + def shrink_mask(self): + """ + Reduce a mask to nomask when possible. + + Parameters + ---------- + None + + Returns + ------- + None + + Examples + -------- + >>> x = np.ma.array([[1,2 ], [3, 4]], mask=[0]*4) + >>> x.mask + array([[False, False], + [False, False]]) + >>> x.shrink_mask() + >>> x.mask + False + + """ + self._mask = _shrink_mask(self._mask) + return self + + baseclass = property(fget=lambda self: self._baseclass, + doc="Class of the underlying data (read-only).") + + def _get_data(self): + """Return the current data, as a view of the original + underlying data. + + """ + return ndarray.view(self, self._baseclass) + + _data = property(fget=_get_data) + data = property(fget=_get_data) + + def _get_flat(self): + "Return a flat iterator." + return MaskedIterator(self) + + def _set_flat(self, value): + "Set a flattened version of self to value." + y = self.ravel() + y[:] = value + + flat = property(fget=_get_flat, fset=_set_flat, + doc="Flat version of the array.") + + def get_fill_value(self): + """ + Return the filling value of the masked array. + + Returns + ------- + fill_value : scalar + The filling value. + + Examples + -------- + >>> for dt in [np.int32, np.int64, np.float64, np.complex128]: + ... np.ma.array([0, 1], dtype=dt).get_fill_value() + ... + 999999 + 999999 + 1e+20 + (1e+20+0j) + + >>> x = np.ma.array([0, 1.], fill_value=-np.inf) + >>> x.get_fill_value() + -inf + + """ + if self._fill_value is None: + self._fill_value = _check_fill_value(None, self.dtype) + + # Temporary workaround to account for the fact that str and bytes + # scalars cannot be indexed with (), whereas all other numpy + # scalars can. See issues #7259 and #7267. + # The if-block can be removed after #7267 has been fixed. + if isinstance(self._fill_value, ndarray): + return self._fill_value[()] + return self._fill_value + + def set_fill_value(self, value=None): + """ + Set the filling value of the masked array. + + Parameters + ---------- + value : scalar, optional + The new filling value. Default is None, in which case a default + based on the data type is used. + + See Also + -------- + ma.set_fill_value : Equivalent function. + + Examples + -------- + >>> x = np.ma.array([0, 1.], fill_value=-np.inf) + >>> x.fill_value + -inf + >>> x.set_fill_value(np.pi) + >>> x.fill_value + 3.1415926535897931 + + Reset to default: + + >>> x.set_fill_value() + >>> x.fill_value + 1e+20 + + """ + target = _check_fill_value(value, self.dtype) + _fill_value = self._fill_value + if _fill_value is None: + # Create the attribute if it was undefined + self._fill_value = target + else: + # Don't overwrite the attribute, just fill it (for propagation) + _fill_value[()] = target + + fill_value = property(fget=get_fill_value, fset=set_fill_value, + doc="Filling value.") + + def filled(self, fill_value=None): + """ + Return a copy of self, with masked values filled with a given value. + **However**, if there are no masked values to fill, self will be + returned instead as an ndarray. + + Parameters + ---------- + fill_value : scalar, optional + The value to use for invalid entries (None by default). + If None, the `fill_value` attribute of the array is used instead. + + Returns + ------- + filled_array : ndarray + A copy of ``self`` with invalid entries replaced by *fill_value* + (be it the function argument or the attribute of ``self``), or + ``self`` itself as an ndarray if there are no invalid entries to + be replaced. + + Notes + ----- + The result is **not** a MaskedArray! + + Examples + -------- + >>> x = np.ma.array([1,2,3,4,5], mask=[0,0,1,0,1], fill_value=-999) + >>> x.filled() + array([1, 2, -999, 4, -999]) + >>> type(x.filled()) + + + Subclassing is preserved. This means that if the data part of the masked + array is a matrix, `filled` returns a matrix: + + >>> x = np.ma.array(np.matrix([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]]) + >>> x.filled() + matrix([[ 1, 999999], + [999999, 4]]) + + """ + m = self._mask + if m is nomask: + return self._data + + if fill_value is None: + fill_value = self.fill_value + else: + fill_value = _check_fill_value(fill_value, self.dtype) + + if self is masked_singleton: + return np.asanyarray(fill_value) + + if m.dtype.names: + result = self._data.copy('K') + _recursive_filled(result, self._mask, fill_value) + elif not m.any(): + return self._data + else: + result = self._data.copy('K') + try: + np.copyto(result, fill_value, where=m) + except (TypeError, AttributeError): + fill_value = narray(fill_value, dtype=object) + d = result.astype(object) + result = np.choose(m, (d, fill_value)) + except IndexError: + # ok, if scalar + if self._data.shape: + raise + elif m: + result = np.array(fill_value, dtype=self.dtype) + else: + result = self._data + return result + + def compressed(self): + """ + Return all the non-masked data as a 1-D array. + + Returns + ------- + data : ndarray + A new `ndarray` holding the non-masked data is returned. + + Notes + ----- + The result is **not** a MaskedArray! + + Examples + -------- + >>> x = np.ma.array(np.arange(5), mask=[0]*2 + [1]*3) + >>> x.compressed() + array([0, 1]) + >>> type(x.compressed()) + + + """ + data = ndarray.ravel(self._data) + if self._mask is not nomask: + data = data.compress(np.logical_not(ndarray.ravel(self._mask))) + return data + + def compress(self, condition, axis=None, out=None): + """ + Return `a` where condition is ``True``. + + If condition is a `MaskedArray`, missing values are considered + as ``False``. + + Parameters + ---------- + condition : var + Boolean 1-d array selecting which entries to return. If len(condition) + is less than the size of a along the axis, then output is truncated + to length of condition array. + axis : {None, int}, optional + Axis along which the operation must be performed. + out : {None, ndarray}, optional + Alternative output array in which to place the result. It must have + the same shape as the expected output but the type will be cast if + necessary. + + Returns + ------- + result : MaskedArray + A :class:`MaskedArray` object. + + Notes + ----- + Please note the difference with :meth:`compressed` ! + The output of :meth:`compress` has a mask, the output of + :meth:`compressed` does not. + + Examples + -------- + >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) + >>> print(x) + [[1 -- 3] + [-- 5 --] + [7 -- 9]] + >>> x.compress([1, 0, 1]) + masked_array(data = [1 3], + mask = [False False], + fill_value=999999) + + >>> x.compress([1, 0, 1], axis=1) + masked_array(data = + [[1 3] + [-- --] + [7 9]], + mask = + [[False False] + [ True True] + [False False]], + fill_value=999999) + + """ + # Get the basic components + (_data, _mask) = (self._data, self._mask) + + # Force the condition to a regular ndarray and forget the missing + # values. + condition = np.array(condition, copy=False, subok=False) + + _new = _data.compress(condition, axis=axis, out=out).view(type(self)) + _new._update_from(self) + if _mask is not nomask: + _new._mask = _mask.compress(condition, axis=axis) + return _new + + def _insert_masked_print(self): + """ + Replace masked values with masked_print_option, casting all innermost + dtypes to object. + """ + if masked_print_option.enabled(): + mask = self._mask + if mask is nomask: + res = self._data + else: + # convert to object array to make filled work + data = self._data + # For big arrays, to avoid a costly conversion to the + # object dtype, extract the corners before the conversion. + print_width = (self._print_width if self.ndim > 1 + else self._print_width_1d) + for axis in range(self.ndim): + if data.shape[axis] > print_width: + ind = print_width // 2 + arr = np.split(data, (ind, -ind), axis=axis) + data = np.concatenate((arr[0], arr[2]), axis=axis) + arr = np.split(mask, (ind, -ind), axis=axis) + mask = np.concatenate((arr[0], arr[2]), axis=axis) + + rdtype = _replace_dtype_fields(self.dtype, "O") + res = data.astype(rdtype) + _recursive_printoption(res, mask, masked_print_option) + else: + res = self.filled(self.fill_value) + return res + + def __str__(self): + return str(self._insert_masked_print()) + + if sys.version_info.major < 3: + def __unicode__(self): + return unicode(self._insert_masked_print()) + + def __repr__(self): + """ + Literal string representation. + + """ + if self._baseclass is np.ndarray: + name = 'array' + else: + name = self._baseclass.__name__ + + + # 2016-11-19: Demoted to legacy format + if np.get_printoptions()['legacy'] == '1.13': + is_long = self.ndim > 1 + parameters = dict( + name=name, + nlen=" " * len(name), + data=str(self), + mask=str(self._mask), + fill=str(self.fill_value), + dtype=str(self.dtype) + ) + is_structured = bool(self.dtype.names) + key = '{}_{}'.format( + 'long' if is_long else 'short', + 'flx' if is_structured else 'std' + ) + return _legacy_print_templates[key] % parameters + + prefix = 'masked_{}('.format(name) + + dtype_needed = ( + not np.core.arrayprint.dtype_is_implied(self.dtype) or + np.all(self.mask) or + self.size == 0 + ) + + # determine which keyword args need to be shown + keys = ['data', 'mask', 'fill_value'] + if dtype_needed: + keys.append('dtype') + + # array has only one row (non-column) + is_one_row = builtins.all(dim == 1 for dim in self.shape[:-1]) + + # choose what to indent each keyword with + min_indent = 2 + if is_one_row: + # first key on the same line as the type, remaining keys + # aligned by equals + indents = {} + indents[keys[0]] = prefix + for k in keys[1:]: + n = builtins.max(min_indent, len(prefix + keys[0]) - len(k)) + indents[k] = ' ' * n + prefix = '' # absorbed into the first indent + else: + # each key on its own line, indented by two spaces + indents = {k: ' ' * min_indent for k in keys} + prefix = prefix + '\n' # first key on the next line + + # format the field values + reprs = {} + reprs['data'] = np.array2string( + self._insert_masked_print(), + separator=", ", + prefix=indents['data'] + 'data=', + suffix=',') + reprs['mask'] = np.array2string( + self._mask, + separator=", ", + prefix=indents['mask'] + 'mask=', + suffix=',') + reprs['fill_value'] = repr(self.fill_value) + if dtype_needed: + reprs['dtype'] = np.core.arrayprint.dtype_short_repr(self.dtype) + + # join keys with values and indentations + result = ',\n'.join( + '{}{}={}'.format(indents[k], k, reprs[k]) + for k in keys + ) + return prefix + result + ')' + + def _delegate_binop(self, other): + # This emulates the logic in + # private/binop_override.h:forward_binop_should_defer + if isinstance(other, type(self)): + return False + array_ufunc = getattr(other, "__array_ufunc__", False) + if array_ufunc is False: + other_priority = getattr(other, "__array_priority__", -1000000) + return self.__array_priority__ < other_priority + else: + # If array_ufunc is not None, it will be called inside the ufunc; + # None explicitly tells us to not call the ufunc, i.e., defer. + return array_ufunc is None + + def _comparison(self, other, compare): + """Compare self with other using operator.eq or operator.ne. + + When either of the elements is masked, the result is masked as well, + but the underlying boolean data are still set, with self and other + considered equal if both are masked, and unequal otherwise. + + For structured arrays, all fields are combined, with masked values + ignored. The result is masked if all fields were masked, with self + and other considered equal only if both were fully masked. + """ + omask = getmask(other) + smask = self.mask + mask = mask_or(smask, omask, copy=True) + + odata = getdata(other) + if mask.dtype.names: + # For possibly masked structured arrays we need to be careful, + # since the standard structured array comparison will use all + # fields, masked or not. To avoid masked fields influencing the + # outcome, we set all masked fields in self to other, so they'll + # count as equal. To prepare, we ensure we have the right shape. + broadcast_shape = np.broadcast(self, odata).shape + sbroadcast = np.broadcast_to(self, broadcast_shape, subok=True) + sbroadcast._mask = mask + sdata = sbroadcast.filled(odata) + # Now take care of the mask; the merged mask should have an item + # masked if all fields were masked (in one and/or other). + mask = (mask == np.ones((), mask.dtype)) + + else: + # For regular arrays, just use the data as they come. + sdata = self.data + + check = compare(sdata, odata) + + if isinstance(check, (np.bool_, bool)): + return masked if mask else check + + if mask is not nomask: + # Adjust elements that were masked, which should be treated + # as equal if masked in both, unequal if masked in one. + # Note that this works automatically for structured arrays too. + check = np.where(mask, compare(smask, omask), check) + if mask.shape != check.shape: + # Guarantee consistency of the shape, making a copy since the + # the mask may need to get written to later. + mask = np.broadcast_to(mask, check.shape).copy() + + check = check.view(type(self)) + check._update_from(self) + check._mask = mask + return check + + def __eq__(self, other): + """Check whether other equals self elementwise. + + When either of the elements is masked, the result is masked as well, + but the underlying boolean data are still set, with self and other + considered equal if both are masked, and unequal otherwise. + + For structured arrays, all fields are combined, with masked values + ignored. The result is masked if all fields were masked, with self + and other considered equal only if both were fully masked. + """ + return self._comparison(other, operator.eq) + + def __ne__(self, other): + """Check whether other does not equal self elementwise. + + When either of the elements is masked, the result is masked as well, + but the underlying boolean data are still set, with self and other + considered equal if both are masked, and unequal otherwise. + + For structured arrays, all fields are combined, with masked values + ignored. The result is masked if all fields were masked, with self + and other considered equal only if both were fully masked. + """ + return self._comparison(other, operator.ne) + + def __add__(self, other): + """ + Add self to other, and return a new masked array. + + """ + if self._delegate_binop(other): + return NotImplemented + return add(self, other) + + def __radd__(self, other): + """ + Add other to self, and return a new masked array. + + """ + # In analogy with __rsub__ and __rdiv__, use original order: + # we get here from `other + self`. + return add(other, self) + + def __sub__(self, other): + """ + Subtract other from self, and return a new masked array. + + """ + if self._delegate_binop(other): + return NotImplemented + return subtract(self, other) + + def __rsub__(self, other): + """ + Subtract self from other, and return a new masked array. + + """ + return subtract(other, self) + + def __mul__(self, other): + "Multiply self by other, and return a new masked array." + if self._delegate_binop(other): + return NotImplemented + return multiply(self, other) + + def __rmul__(self, other): + """ + Multiply other by self, and return a new masked array. + + """ + # In analogy with __rsub__ and __rdiv__, use original order: + # we get here from `other * self`. + return multiply(other, self) + + def __div__(self, other): + """ + Divide other into self, and return a new masked array. + + """ + if self._delegate_binop(other): + return NotImplemented + return divide(self, other) + + def __truediv__(self, other): + """ + Divide other into self, and return a new masked array. + + """ + if self._delegate_binop(other): + return NotImplemented + return true_divide(self, other) + + def __rtruediv__(self, other): + """ + Divide self into other, and return a new masked array. + + """ + return true_divide(other, self) + + def __floordiv__(self, other): + """ + Divide other into self, and return a new masked array. + + """ + if self._delegate_binop(other): + return NotImplemented + return floor_divide(self, other) + + def __rfloordiv__(self, other): + """ + Divide self into other, and return a new masked array. + + """ + return floor_divide(other, self) + + def __pow__(self, other): + """ + Raise self to the power other, masking the potential NaNs/Infs + + """ + if self._delegate_binop(other): + return NotImplemented + return power(self, other) + + def __rpow__(self, other): + """ + Raise other to the power self, masking the potential NaNs/Infs + + """ + return power(other, self) + + def __iadd__(self, other): + """ + Add other to self in-place. + + """ + m = getmask(other) + if self._mask is nomask: + if m is not nomask and m.any(): + self._mask = make_mask_none(self.shape, self.dtype) + self._mask += m + else: + if m is not nomask: + self._mask += m + self._data.__iadd__(np.where(self._mask, self.dtype.type(0), + getdata(other))) + return self + + def __isub__(self, other): + """ + Subtract other from self in-place. + + """ + m = getmask(other) + if self._mask is nomask: + if m is not nomask and m.any(): + self._mask = make_mask_none(self.shape, self.dtype) + self._mask += m + elif m is not nomask: + self._mask += m + self._data.__isub__(np.where(self._mask, self.dtype.type(0), + getdata(other))) + return self + + def __imul__(self, other): + """ + Multiply self by other in-place. + + """ + m = getmask(other) + if self._mask is nomask: + if m is not nomask and m.any(): + self._mask = make_mask_none(self.shape, self.dtype) + self._mask += m + elif m is not nomask: + self._mask += m + self._data.__imul__(np.where(self._mask, self.dtype.type(1), + getdata(other))) + return self + + def __idiv__(self, other): + """ + Divide self by other in-place. + + """ + other_data = getdata(other) + dom_mask = _DomainSafeDivide().__call__(self._data, other_data) + other_mask = getmask(other) + new_mask = mask_or(other_mask, dom_mask) + # The following 3 lines control the domain filling + if dom_mask.any(): + (_, fval) = ufunc_fills[np.divide] + other_data = np.where(dom_mask, fval, other_data) + self._mask |= new_mask + self._data.__idiv__(np.where(self._mask, self.dtype.type(1), + other_data)) + return self + + def __ifloordiv__(self, other): + """ + Floor divide self by other in-place. + + """ + other_data = getdata(other) + dom_mask = _DomainSafeDivide().__call__(self._data, other_data) + other_mask = getmask(other) + new_mask = mask_or(other_mask, dom_mask) + # The following 3 lines control the domain filling + if dom_mask.any(): + (_, fval) = ufunc_fills[np.floor_divide] + other_data = np.where(dom_mask, fval, other_data) + self._mask |= new_mask + self._data.__ifloordiv__(np.where(self._mask, self.dtype.type(1), + other_data)) + return self + + def __itruediv__(self, other): + """ + True divide self by other in-place. + + """ + other_data = getdata(other) + dom_mask = _DomainSafeDivide().__call__(self._data, other_data) + other_mask = getmask(other) + new_mask = mask_or(other_mask, dom_mask) + # The following 3 lines control the domain filling + if dom_mask.any(): + (_, fval) = ufunc_fills[np.true_divide] + other_data = np.where(dom_mask, fval, other_data) + self._mask |= new_mask + self._data.__itruediv__(np.where(self._mask, self.dtype.type(1), + other_data)) + return self + + def __ipow__(self, other): + """ + Raise self to the power other, in place. + + """ + other_data = getdata(other) + other_mask = getmask(other) + with np.errstate(divide='ignore', invalid='ignore'): + self._data.__ipow__(np.where(self._mask, self.dtype.type(1), + other_data)) + invalid = np.logical_not(np.isfinite(self._data)) + if invalid.any(): + if self._mask is not nomask: + self._mask |= invalid + else: + self._mask = invalid + np.copyto(self._data, self.fill_value, where=invalid) + new_mask = mask_or(other_mask, invalid) + self._mask = mask_or(self._mask, new_mask) + return self + + def __float__(self): + """ + Convert to float. + + """ + if self.size > 1: + raise TypeError("Only length-1 arrays can be converted " + "to Python scalars") + elif self._mask: + warnings.warn("Warning: converting a masked element to nan.", stacklevel=2) + return np.nan + return float(self.item()) + + def __int__(self): + """ + Convert to int. + + """ + if self.size > 1: + raise TypeError("Only length-1 arrays can be converted " + "to Python scalars") + elif self._mask: + raise MaskError('Cannot convert masked element to a Python int.') + return int(self.item()) + + def __long__(self): + """ + Convert to long. + """ + if self.size > 1: + raise TypeError("Only length-1 arrays can be conveted " + "to Python scalars") + elif self._mask: + raise MaskError('Cannot convert masked element to a Python long.') + return long(self.item()) + + + def get_imag(self): + """ + Return the imaginary part of the masked array. + + The returned array is a view on the imaginary part of the `MaskedArray` + whose `get_imag` method is called. + + Parameters + ---------- + None + + Returns + ------- + result : MaskedArray + The imaginary part of the masked array. + + See Also + -------- + get_real, real, imag + + Examples + -------- + >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False]) + >>> x.get_imag() + masked_array(data = [1.0 -- 1.6], + mask = [False True False], + fill_value = 1e+20) + + """ + result = self._data.imag.view(type(self)) + result.__setmask__(self._mask) + return result + + imag = property(fget=get_imag, doc="Imaginary part.") + + def get_real(self): + """ + Return the real part of the masked array. + + The returned array is a view on the real part of the `MaskedArray` + whose `get_real` method is called. + + Parameters + ---------- + None + + Returns + ------- + result : MaskedArray + The real part of the masked array. + + See Also + -------- + get_imag, real, imag + + Examples + -------- + >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False]) + >>> x.get_real() + masked_array(data = [1.0 -- 3.45], + mask = [False True False], + fill_value = 1e+20) + + """ + result = self._data.real.view(type(self)) + result.__setmask__(self._mask) + return result + real = property(fget=get_real, doc="Real part") + + def count(self, axis=None, keepdims=np._NoValue): + """ + Count the non-masked elements of the array along the given axis. + + Parameters + ---------- + axis : None or int or tuple of ints, optional + Axis or axes along which the count is performed. + The default (`axis` = `None`) performs the count over all + the dimensions of the input array. `axis` may be negative, in + which case it counts from the last to the first axis. + + .. versionadded:: 1.10.0 + + If this is a tuple of ints, the count is performed on multiple + axes, instead of a single axis or all the axes as before. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the array. + + Returns + ------- + result : ndarray or scalar + An array with the same shape as the input array, with the specified + axis removed. If the array is a 0-d array, or if `axis` is None, a + scalar is returned. + + See Also + -------- + count_masked : Count masked elements in array or along a given axis. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = ma.arange(6).reshape((2, 3)) + >>> a[1, :] = ma.masked + >>> a + masked_array(data = + [[0 1 2] + [-- -- --]], + mask = + [[False False False] + [ True True True]], + fill_value = 999999) + >>> a.count() + 3 + + When the `axis` keyword is specified an array of appropriate size is + returned. + + >>> a.count(axis=0) + array([1, 1, 1]) + >>> a.count(axis=1) + array([3, 0]) + + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + m = self._mask + # special case for matrices (we assume no other subclasses modify + # their dimensions) + if isinstance(self.data, np.matrix): + if m is nomask: + m = np.zeros(self.shape, dtype=np.bool_) + m = m.view(type(self.data)) + + if m is nomask: + # compare to _count_reduce_items in _methods.py + + if self.shape is (): + if axis not in (None, 0): + raise np.AxisError(axis=axis, ndim=self.ndim) + return 1 + elif axis is None: + if kwargs.get('keepdims', False): + return np.array(self.size, dtype=np.intp, ndmin=self.ndim) + return self.size + + axes = normalize_axis_tuple(axis, self.ndim) + items = 1 + for ax in axes: + items *= self.shape[ax] + + if kwargs.get('keepdims', False): + out_dims = list(self.shape) + for a in axes: + out_dims[a] = 1 + else: + out_dims = [d for n, d in enumerate(self.shape) + if n not in axes] + # make sure to return a 0-d array if axis is supplied + return np.full(out_dims, items, dtype=np.intp) + + # take care of the masked singleton + if self is masked: + return 0 + + return (~m).sum(axis=axis, dtype=np.intp, **kwargs) + + def ravel(self, order='C'): + """ + Returns a 1D version of self, as a view. + + Parameters + ---------- + order : {'C', 'F', 'A', 'K'}, optional + The elements of `a` are read using this index order. 'C' means to + index the elements in C-like order, with the last axis index + changing fastest, back to the first axis index changing slowest. + 'F' means to index the elements in Fortran-like index order, with + the first index changing fastest, and the last index changing + slowest. Note that the 'C' and 'F' options take no account of the + memory layout of the underlying array, and only refer to the order + of axis indexing. 'A' means to read the elements in Fortran-like + index order if `m` is Fortran *contiguous* in memory, C-like order + otherwise. 'K' means to read the elements in the order they occur + in memory, except for reversing the data when strides are negative. + By default, 'C' index order is used. + + Returns + ------- + MaskedArray + Output view is of shape ``(self.size,)`` (or + ``(np.ma.product(self.shape),)``). + + Examples + -------- + >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) + >>> print(x) + [[1 -- 3] + [-- 5 --] + [7 -- 9]] + >>> print(x.ravel()) + [1 -- 3 -- 5 -- 7 -- 9] + + """ + r = ndarray.ravel(self._data, order=order).view(type(self)) + r._update_from(self) + if self._mask is not nomask: + r._mask = ndarray.ravel(self._mask, order=order).reshape(r.shape) + else: + r._mask = nomask + return r + + + def reshape(self, *s, **kwargs): + """ + Give a new shape to the array without changing its data. + + Returns a masked array containing the same data, but with a new shape. + The result is a view on the original array; if this is not possible, a + ValueError is raised. + + Parameters + ---------- + shape : int or tuple of ints + The new shape should be compatible with the original shape. If an + integer is supplied, then the result will be a 1-D array of that + length. + order : {'C', 'F'}, optional + Determines whether the array data should be viewed as in C + (row-major) or FORTRAN (column-major) order. + + Returns + ------- + reshaped_array : array + A new view on the array. + + See Also + -------- + reshape : Equivalent function in the masked array module. + numpy.ndarray.reshape : Equivalent method on ndarray object. + numpy.reshape : Equivalent function in the NumPy module. + + Notes + ----- + The reshaping operation cannot guarantee that a copy will not be made, + to modify the shape in place, use ``a.shape = s`` + + Examples + -------- + >>> x = np.ma.array([[1,2],[3,4]], mask=[1,0,0,1]) + >>> print(x) + [[-- 2] + [3 --]] + >>> x = x.reshape((4,1)) + >>> print(x) + [[--] + [2] + [3] + [--]] + + """ + kwargs.update(order=kwargs.get('order', 'C')) + result = self._data.reshape(*s, **kwargs).view(type(self)) + result._update_from(self) + mask = self._mask + if mask is not nomask: + result._mask = mask.reshape(*s, **kwargs) + return result + + def resize(self, newshape, refcheck=True, order=False): + """ + .. warning:: + + This method does nothing, except raise a ValueError exception. A + masked array does not own its data and therefore cannot safely be + resized in place. Use the `numpy.ma.resize` function instead. + + This method is difficult to implement safely and may be deprecated in + future releases of NumPy. + + """ + # Note : the 'order' keyword looks broken, let's just drop it + errmsg = "A masked array does not own its data "\ + "and therefore cannot be resized.\n" \ + "Use the numpy.ma.resize function instead." + raise ValueError(errmsg) + + def put(self, indices, values, mode='raise'): + """ + Set storage-indexed locations to corresponding values. + + Sets self._data.flat[n] = values[n] for each n in indices. + If `values` is shorter than `indices` then it will repeat. + If `values` has some masked values, the initial mask is updated + in consequence, else the corresponding values are unmasked. + + Parameters + ---------- + indices : 1-D array_like + Target indices, interpreted as integers. + values : array_like + Values to place in self._data copy at target indices. + mode : {'raise', 'wrap', 'clip'}, optional + Specifies how out-of-bounds indices will behave. + 'raise' : raise an error. + 'wrap' : wrap around. + 'clip' : clip to the range. + + Notes + ----- + `values` can be a scalar or length 1 array. + + Examples + -------- + >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) + >>> print(x) + [[1 -- 3] + [-- 5 --] + [7 -- 9]] + >>> x.put([0,4,8],[10,20,30]) + >>> print(x) + [[10 -- 3] + [-- 20 --] + [7 -- 30]] + + >>> x.put(4,999) + >>> print(x) + [[10 -- 3] + [-- 999 --] + [7 -- 30]] + + """ + # Hard mask: Get rid of the values/indices that fall on masked data + if self._hardmask and self._mask is not nomask: + mask = self._mask[indices] + indices = narray(indices, copy=False) + values = narray(values, copy=False, subok=True) + values.resize(indices.shape) + indices = indices[~mask] + values = values[~mask] + + self._data.put(indices, values, mode=mode) + + # short circuit if neither self nor values are masked + if self._mask is nomask and getmask(values) is nomask: + return + + m = getmaskarray(self) + + if getmask(values) is nomask: + m.put(indices, False, mode=mode) + else: + m.put(indices, values._mask, mode=mode) + m = make_mask(m, copy=False, shrink=True) + self._mask = m + return + + def ids(self): + """ + Return the addresses of the data and mask areas. + + Parameters + ---------- + None + + Examples + -------- + >>> x = np.ma.array([1, 2, 3], mask=[0, 1, 1]) + >>> x.ids() + (166670640, 166659832) + + If the array has no mask, the address of `nomask` is returned. This address + is typically not close to the data in memory: + + >>> x = np.ma.array([1, 2, 3]) + >>> x.ids() + (166691080, 3083169284L) + + """ + if self._mask is nomask: + return (self.ctypes.data, id(nomask)) + return (self.ctypes.data, self._mask.ctypes.data) + + def iscontiguous(self): + """ + Return a boolean indicating whether the data is contiguous. + + Parameters + ---------- + None + + Examples + -------- + >>> x = np.ma.array([1, 2, 3]) + >>> x.iscontiguous() + True + + `iscontiguous` returns one of the flags of the masked array: + + >>> x.flags + C_CONTIGUOUS : True + F_CONTIGUOUS : True + OWNDATA : False + WRITEABLE : True + ALIGNED : True + WRITEBACKIFCOPY : False + UPDATEIFCOPY : False + + """ + return self.flags['CONTIGUOUS'] + + def all(self, axis=None, out=None, keepdims=np._NoValue): + """ + Returns True if all elements evaluate to True. + + The output array is masked where all the values along the given axis + are masked: if the output would have been a scalar and that all the + values are masked, then the output is `masked`. + + Refer to `numpy.all` for full documentation. + + See Also + -------- + ndarray.all : corresponding function for ndarrays + numpy.all : equivalent function + + Examples + -------- + >>> np.ma.array([1,2,3]).all() + True + >>> a = np.ma.array([1,2,3], mask=True) + >>> (a.all() is np.ma.masked) + True + + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + mask = _check_mask_axis(self._mask, axis, **kwargs) + if out is None: + d = self.filled(True).all(axis=axis, **kwargs).view(type(self)) + if d.ndim: + d.__setmask__(mask) + elif mask: + return masked + return d + self.filled(True).all(axis=axis, out=out, **kwargs) + if isinstance(out, MaskedArray): + if out.ndim or mask: + out.__setmask__(mask) + return out + + def any(self, axis=None, out=None, keepdims=np._NoValue): + """ + Returns True if any of the elements of `a` evaluate to True. + + Masked values are considered as False during computation. + + Refer to `numpy.any` for full documentation. + + See Also + -------- + ndarray.any : corresponding function for ndarrays + numpy.any : equivalent function + + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + mask = _check_mask_axis(self._mask, axis, **kwargs) + if out is None: + d = self.filled(False).any(axis=axis, **kwargs).view(type(self)) + if d.ndim: + d.__setmask__(mask) + elif mask: + d = masked + return d + self.filled(False).any(axis=axis, out=out, **kwargs) + if isinstance(out, MaskedArray): + if out.ndim or mask: + out.__setmask__(mask) + return out + + def nonzero(self): + """ + Return the indices of unmasked elements that are not zero. + + Returns a tuple of arrays, one for each dimension, containing the + indices of the non-zero elements in that dimension. The corresponding + non-zero values can be obtained with:: + + a[a.nonzero()] + + To group the indices by element, rather than dimension, use + instead:: + + np.transpose(a.nonzero()) + + The result of this is always a 2d array, with a row for each non-zero + element. + + Parameters + ---------- + None + + Returns + ------- + tuple_of_arrays : tuple + Indices of elements that are non-zero. + + See Also + -------- + numpy.nonzero : + Function operating on ndarrays. + flatnonzero : + Return indices that are non-zero in the flattened version of the input + array. + ndarray.nonzero : + Equivalent ndarray method. + count_nonzero : + Counts the number of non-zero elements in the input array. + + Examples + -------- + >>> import numpy.ma as ma + >>> x = ma.array(np.eye(3)) + >>> x + masked_array(data = + [[ 1. 0. 0.] + [ 0. 1. 0.] + [ 0. 0. 1.]], + mask = + False, + fill_value=1e+20) + >>> x.nonzero() + (array([0, 1, 2]), array([0, 1, 2])) + + Masked elements are ignored. + + >>> x[1, 1] = ma.masked + >>> x + masked_array(data = + [[1.0 0.0 0.0] + [0.0 -- 0.0] + [0.0 0.0 1.0]], + mask = + [[False False False] + [False True False] + [False False False]], + fill_value=1e+20) + >>> x.nonzero() + (array([0, 2]), array([0, 2])) + + Indices can also be grouped by element. + + >>> np.transpose(x.nonzero()) + array([[0, 0], + [2, 2]]) + + A common use for ``nonzero`` is to find the indices of an array, where + a condition is True. Given an array `a`, the condition `a` > 3 is a + boolean array and since False is interpreted as 0, ma.nonzero(a > 3) + yields the indices of the `a` where the condition is true. + + >>> a = ma.array([[1,2,3],[4,5,6],[7,8,9]]) + >>> a > 3 + masked_array(data = + [[False False False] + [ True True True] + [ True True True]], + mask = + False, + fill_value=999999) + >>> ma.nonzero(a > 3) + (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2])) + + The ``nonzero`` method of the condition array can also be called. + + >>> (a > 3).nonzero() + (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2])) + + """ + return narray(self.filled(0), copy=False).nonzero() + + def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None): + """ + (this docstring should be overwritten) + """ + #!!!: implement out + test! + m = self._mask + if m is nomask: + result = super(MaskedArray, self).trace(offset=offset, axis1=axis1, + axis2=axis2, out=out) + return result.astype(dtype) + else: + D = self.diagonal(offset=offset, axis1=axis1, axis2=axis2) + return D.astype(dtype).filled(0).sum(axis=-1, out=out) + trace.__doc__ = ndarray.trace.__doc__ + + def dot(self, b, out=None, strict=False): + """ + a.dot(b, out=None) + + Masked dot product of two arrays. Note that `out` and `strict` are + located in different positions than in `ma.dot`. In order to + maintain compatibility with the functional version, it is + recommended that the optional arguments be treated as keyword only. + At some point that may be mandatory. + + .. versionadded:: 1.10.0 + + Parameters + ---------- + b : masked_array_like + Inputs array. + out : masked_array, optional + Output argument. This must have the exact kind that would be + returned if it was not used. In particular, it must have the + right type, must be C-contiguous, and its dtype must be the + dtype that would be returned for `ma.dot(a,b)`. This is a + performance feature. Therefore, if these conditions are not + met, an exception is raised, instead of attempting to be + flexible. + strict : bool, optional + Whether masked data are propagated (True) or set to 0 (False) + for the computation. Default is False. Propagating the mask + means that if a masked value appears in a row or column, the + whole row or column is considered masked. + + .. versionadded:: 1.10.2 + + See Also + -------- + numpy.ma.dot : equivalent function + + """ + return dot(self, b, out=out, strict=strict) + + def sum(self, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Return the sum of the array elements over the given axis. + + Masked elements are set to 0 internally. + + Refer to `numpy.sum` for full documentation. + + See Also + -------- + ndarray.sum : corresponding function for ndarrays + numpy.sum : equivalent function + + Examples + -------- + >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) + >>> print(x) + [[1 -- 3] + [-- 5 --] + [7 -- 9]] + >>> print(x.sum()) + 25 + >>> print(x.sum(axis=1)) + [4 5 16] + >>> print(x.sum(axis=0)) + [8 5 12] + >>> print(type(x.sum(axis=0, dtype=np.int64)[0])) + + + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + _mask = self._mask + newmask = _check_mask_axis(_mask, axis, **kwargs) + # No explicit output + if out is None: + result = self.filled(0).sum(axis, dtype=dtype, **kwargs) + rndim = getattr(result, 'ndim', 0) + if rndim: + result = result.view(type(self)) + result.__setmask__(newmask) + elif newmask: + result = masked + return result + # Explicit output + result = self.filled(0).sum(axis, dtype=dtype, out=out, **kwargs) + if isinstance(out, MaskedArray): + outmask = getmask(out) + if (outmask is nomask): + outmask = out._mask = make_mask_none(out.shape) + outmask.flat = newmask + return out + + def cumsum(self, axis=None, dtype=None, out=None): + """ + Return the cumulative sum of the array elements over the given axis. + + Masked values are set to 0 internally during the computation. + However, their position is saved, and the result will be masked at + the same locations. + + Refer to `numpy.cumsum` for full documentation. + + Notes + ----- + The mask is lost if `out` is not a valid :class:`MaskedArray` ! + + Arithmetic is modular when using integer types, and no error is + raised on overflow. + + See Also + -------- + ndarray.cumsum : corresponding function for ndarrays + numpy.cumsum : equivalent function + + Examples + -------- + >>> marr = np.ma.array(np.arange(10), mask=[0,0,0,1,1,1,0,0,0,0]) + >>> print(marr.cumsum()) + [0 1 3 -- -- -- 9 16 24 33] + + """ + result = self.filled(0).cumsum(axis=axis, dtype=dtype, out=out) + if out is not None: + if isinstance(out, MaskedArray): + out.__setmask__(self.mask) + return out + result = result.view(type(self)) + result.__setmask__(self._mask) + return result + + def prod(self, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Return the product of the array elements over the given axis. + + Masked elements are set to 1 internally for computation. + + Refer to `numpy.prod` for full documentation. + + Notes + ----- + Arithmetic is modular when using integer types, and no error is raised + on overflow. + + See Also + -------- + ndarray.prod : corresponding function for ndarrays + numpy.prod : equivalent function + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + _mask = self._mask + newmask = _check_mask_axis(_mask, axis, **kwargs) + # No explicit output + if out is None: + result = self.filled(1).prod(axis, dtype=dtype, **kwargs) + rndim = getattr(result, 'ndim', 0) + if rndim: + result = result.view(type(self)) + result.__setmask__(newmask) + elif newmask: + result = masked + return result + # Explicit output + result = self.filled(1).prod(axis, dtype=dtype, out=out, **kwargs) + if isinstance(out, MaskedArray): + outmask = getmask(out) + if (outmask is nomask): + outmask = out._mask = make_mask_none(out.shape) + outmask.flat = newmask + return out + product = prod + + def cumprod(self, axis=None, dtype=None, out=None): + """ + Return the cumulative product of the array elements over the given axis. + + Masked values are set to 1 internally during the computation. + However, their position is saved, and the result will be masked at + the same locations. + + Refer to `numpy.cumprod` for full documentation. + + Notes + ----- + The mask is lost if `out` is not a valid MaskedArray ! + + Arithmetic is modular when using integer types, and no error is + raised on overflow. + + See Also + -------- + ndarray.cumprod : corresponding function for ndarrays + numpy.cumprod : equivalent function + """ + result = self.filled(1).cumprod(axis=axis, dtype=dtype, out=out) + if out is not None: + if isinstance(out, MaskedArray): + out.__setmask__(self._mask) + return out + result = result.view(type(self)) + result.__setmask__(self._mask) + return result + + def mean(self, axis=None, dtype=None, out=None, keepdims=np._NoValue): + """ + Returns the average of the array elements along given axis. + + Masked entries are ignored, and result elements which are not + finite will be masked. + + Refer to `numpy.mean` for full documentation. + + See Also + -------- + ndarray.mean : corresponding function for ndarrays + numpy.mean : Equivalent function + numpy.ma.average: Weighted average. + + Examples + -------- + >>> a = np.ma.array([1,2,3], mask=[False, False, True]) + >>> a + masked_array(data = [1 2 --], + mask = [False False True], + fill_value = 999999) + >>> a.mean() + 1.5 + + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + if self._mask is nomask: + result = super(MaskedArray, self).mean(axis=axis, + dtype=dtype, **kwargs)[()] + else: + dsum = self.sum(axis=axis, dtype=dtype, **kwargs) + cnt = self.count(axis=axis, **kwargs) + if cnt.shape == () and (cnt == 0): + result = masked + else: + result = dsum * 1. / cnt + if out is not None: + out.flat = result + if isinstance(out, MaskedArray): + outmask = getmask(out) + if (outmask is nomask): + outmask = out._mask = make_mask_none(out.shape) + outmask.flat = getmask(result) + return out + return result + + def anom(self, axis=None, dtype=None): + """ + Compute the anomalies (deviations from the arithmetic mean) + along the given axis. + + Returns an array of anomalies, with the same shape as the input and + where the arithmetic mean is computed along the given axis. + + Parameters + ---------- + axis : int, optional + Axis over which the anomalies are taken. + The default is to use the mean of the flattened array as reference. + dtype : dtype, optional + Type to use in computing the variance. For arrays of integer type + the default is float32; for arrays of float types it is the same as + the array type. + + See Also + -------- + mean : Compute the mean of the array. + + Examples + -------- + >>> a = np.ma.array([1,2,3]) + >>> a.anom() + masked_array(data = [-1. 0. 1.], + mask = False, + fill_value = 1e+20) + + """ + m = self.mean(axis, dtype) + if m is masked: + return m + + if not axis: + return (self - m) + else: + return (self - expand_dims(m, axis)) + + def var(self, axis=None, dtype=None, out=None, ddof=0, + keepdims=np._NoValue): + """ + Returns the variance of the array elements along given axis. + + Masked entries are ignored, and result elements which are not + finite will be masked. + + Refer to `numpy.var` for full documentation. + + See Also + -------- + ndarray.var : corresponding function for ndarrays + numpy.var : Equivalent function + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + # Easy case: nomask, business as usual + if self._mask is nomask: + ret = super(MaskedArray, self).var(axis=axis, dtype=dtype, out=out, + ddof=ddof, **kwargs)[()] + if out is not None: + if isinstance(out, MaskedArray): + out.__setmask__(nomask) + return out + return ret + + # Some data are masked, yay! + cnt = self.count(axis=axis, **kwargs) - ddof + danom = self - self.mean(axis, dtype, keepdims=True) + if iscomplexobj(self): + danom = umath.absolute(danom) ** 2 + else: + danom *= danom + dvar = divide(danom.sum(axis, **kwargs), cnt).view(type(self)) + # Apply the mask if it's not a scalar + if dvar.ndim: + dvar._mask = mask_or(self._mask.all(axis, **kwargs), (cnt <= 0)) + dvar._update_from(self) + elif getmask(dvar): + # Make sure that masked is returned when the scalar is masked. + dvar = masked + if out is not None: + if isinstance(out, MaskedArray): + out.flat = 0 + out.__setmask__(True) + elif out.dtype.kind in 'biu': + errmsg = "Masked data information would be lost in one or "\ + "more location." + raise MaskError(errmsg) + else: + out.flat = np.nan + return out + # In case with have an explicit output + if out is not None: + # Set the data + out.flat = dvar + # Set the mask if needed + if isinstance(out, MaskedArray): + out.__setmask__(dvar.mask) + return out + return dvar + var.__doc__ = np.var.__doc__ + + def std(self, axis=None, dtype=None, out=None, ddof=0, + keepdims=np._NoValue): + """ + Returns the standard deviation of the array elements along given axis. + + Masked entries are ignored. + + Refer to `numpy.std` for full documentation. + + See Also + -------- + ndarray.std : corresponding function for ndarrays + numpy.std : Equivalent function + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + dvar = self.var(axis, dtype, out, ddof, **kwargs) + if dvar is not masked: + if out is not None: + np.power(out, 0.5, out=out, casting='unsafe') + return out + dvar = sqrt(dvar) + return dvar + + def round(self, decimals=0, out=None): + """ + Return each element rounded to the given number of decimals. + + Refer to `numpy.around` for full documentation. + + See Also + -------- + ndarray.around : corresponding function for ndarrays + numpy.around : equivalent function + """ + result = self._data.round(decimals=decimals, out=out).view(type(self)) + if result.ndim > 0: + result._mask = self._mask + result._update_from(self) + elif self._mask: + # Return masked when the scalar is masked + result = masked + # No explicit output: we're done + if out is None: + return result + if isinstance(out, MaskedArray): + out.__setmask__(self._mask) + return out + + def argsort(self, axis=np._NoValue, kind='quicksort', order=None, + endwith=True, fill_value=None): + """ + Return an ndarray of indices that sort the array along the + specified axis. Masked values are filled beforehand to + `fill_value`. + + Parameters + ---------- + axis : int, optional + Axis along which to sort. If None, the default, the flattened array + is used. + + .. versionchanged:: 1.13.0 + Previously, the default was documented to be -1, but that was + in error. At some future date, the default will change to -1, as + originally intended. + Until then, the axis should be given explicitly when + ``arr.ndim > 1``, to avoid a FutureWarning. + kind : {'quicksort', 'mergesort', 'heapsort'}, optional + Sorting algorithm. + order : list, optional + When `a` is an array with fields defined, this argument specifies + which fields to compare first, second, etc. Not all fields need be + specified. + endwith : {True, False}, optional + Whether missing values (if any) should be treated as the largest values + (True) or the smallest values (False) + When the array contains unmasked values at the same extremes of the + datatype, the ordering of these values and the masked values is + undefined. + fill_value : {var}, optional + Value used internally for the masked values. + If ``fill_value`` is not None, it supersedes ``endwith``. + + Returns + ------- + index_array : ndarray, int + Array of indices that sort `a` along the specified axis. + In other words, ``a[index_array]`` yields a sorted `a`. + + See Also + -------- + MaskedArray.sort : Describes sorting algorithms used. + lexsort : Indirect stable sort with multiple keys. + ndarray.sort : Inplace sort. + + Notes + ----- + See `sort` for notes on the different sorting algorithms. + + Examples + -------- + >>> a = np.ma.array([3,2,1], mask=[False, False, True]) + >>> a + masked_array(data = [3 2 --], + mask = [False False True], + fill_value = 999999) + >>> a.argsort() + array([1, 0, 2]) + + """ + + # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default + if axis is np._NoValue: + axis = _deprecate_argsort_axis(self) + + if fill_value is None: + if endwith: + # nan > inf + if np.issubdtype(self.dtype, np.floating): + fill_value = np.nan + else: + fill_value = minimum_fill_value(self) + else: + fill_value = maximum_fill_value(self) + + filled = self.filled(fill_value) + return filled.argsort(axis=axis, kind=kind, order=order) + + def argmin(self, axis=None, fill_value=None, out=None): + """ + Return array of indices to the minimum values along the given axis. + + Parameters + ---------- + axis : {None, integer} + If None, the index is into the flattened array, otherwise along + the specified axis + fill_value : {var}, optional + Value used to fill in the masked values. If None, the output of + minimum_fill_value(self._data) is used instead. + out : {None, array}, optional + Array into which the result can be placed. Its type is preserved + and it must be of the right shape to hold the output. + + Returns + ------- + ndarray or scalar + If multi-dimension input, returns a new ndarray of indices to the + minimum values along the given axis. Otherwise, returns a scalar + of index to the minimum values along the given axis. + + Examples + -------- + >>> x = np.ma.array(arange(4), mask=[1,1,0,0]) + >>> x.shape = (2,2) + >>> print(x) + [[-- --] + [2 3]] + >>> print(x.argmin(axis=0, fill_value=-1)) + [0 0] + >>> print(x.argmin(axis=0, fill_value=9)) + [1 1] + + """ + if fill_value is None: + fill_value = minimum_fill_value(self) + d = self.filled(fill_value).view(ndarray) + return d.argmin(axis, out=out) + + def argmax(self, axis=None, fill_value=None, out=None): + """ + Returns array of indices of the maximum values along the given axis. + Masked values are treated as if they had the value fill_value. + + Parameters + ---------- + axis : {None, integer} + If None, the index is into the flattened array, otherwise along + the specified axis + fill_value : {var}, optional + Value used to fill in the masked values. If None, the output of + maximum_fill_value(self._data) is used instead. + out : {None, array}, optional + Array into which the result can be placed. Its type is preserved + and it must be of the right shape to hold the output. + + Returns + ------- + index_array : {integer_array} + + Examples + -------- + >>> a = np.arange(6).reshape(2,3) + >>> a.argmax() + 5 + >>> a.argmax(0) + array([1, 1, 1]) + >>> a.argmax(1) + array([2, 2]) + + """ + if fill_value is None: + fill_value = maximum_fill_value(self._data) + d = self.filled(fill_value).view(ndarray) + return d.argmax(axis, out=out) + + def sort(self, axis=-1, kind='quicksort', order=None, + endwith=True, fill_value=None): + """ + Sort the array, in-place + + Parameters + ---------- + a : array_like + Array to be sorted. + axis : int, optional + Axis along which to sort. If None, the array is flattened before + sorting. The default is -1, which sorts along the last axis. + kind : {'quicksort', 'mergesort', 'heapsort'}, optional + Sorting algorithm. Default is 'quicksort'. + order : list, optional + When `a` is a structured array, this argument specifies which fields + to compare first, second, and so on. This list does not need to + include all of the fields. + endwith : {True, False}, optional + Whether missing values (if any) should be treated as the largest values + (True) or the smallest values (False) + When the array contains unmasked values at the same extremes of the + datatype, the ordering of these values and the masked values is + undefined. + fill_value : {var}, optional + Value used internally for the masked values. + If ``fill_value`` is not None, it supersedes ``endwith``. + + Returns + ------- + sorted_array : ndarray + Array of the same type and shape as `a`. + + See Also + -------- + ndarray.sort : Method to sort an array in-place. + argsort : Indirect sort. + lexsort : Indirect stable sort on multiple keys. + searchsorted : Find elements in a sorted array. + + Notes + ----- + See ``sort`` for notes on the different sorting algorithms. + + Examples + -------- + >>> a = ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0]) + >>> # Default + >>> a.sort() + >>> print(a) + [1 3 5 -- --] + + >>> a = ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0]) + >>> # Put missing values in the front + >>> a.sort(endwith=False) + >>> print(a) + [-- -- 1 3 5] + + >>> a = ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0]) + >>> # fill_value takes over endwith + >>> a.sort(endwith=False, fill_value=3) + >>> print(a) + [1 -- -- 3 5] + + """ + if self._mask is nomask: + ndarray.sort(self, axis=axis, kind=kind, order=order) + return + + if self is masked: + return + + sidx = self.argsort(axis=axis, kind=kind, order=order, + fill_value=fill_value, endwith=endwith) + + # save memory for 1d arrays + if self.ndim == 1: + idx = sidx + else: + idx = list(np.ix_(*[np.arange(x) for x in self.shape])) + idx[axis] = sidx + + self[...] = self[idx] + + def min(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue): + """ + Return the minimum along a given axis. + + Parameters + ---------- + axis : {None, int}, optional + Axis along which to operate. By default, ``axis`` is None and the + flattened input is used. + out : array_like, optional + Alternative output array in which to place the result. Must be of + the same shape and buffer length as the expected output. + fill_value : {var}, optional + Value used to fill in the masked values. + If None, use the output of `minimum_fill_value`. + + Returns + ------- + amin : array_like + New array holding the result. + If ``out`` was specified, ``out`` is returned. + + See Also + -------- + minimum_fill_value + Returns the minimum filling value for a given datatype. + + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + _mask = self._mask + newmask = _check_mask_axis(_mask, axis, **kwargs) + if fill_value is None: + fill_value = minimum_fill_value(self) + # No explicit output + if out is None: + result = self.filled(fill_value).min( + axis=axis, out=out, **kwargs).view(type(self)) + if result.ndim: + # Set the mask + result.__setmask__(newmask) + # Get rid of Infs + if newmask.ndim: + np.copyto(result, result.fill_value, where=newmask) + elif newmask: + result = masked + return result + # Explicit output + result = self.filled(fill_value).min(axis=axis, out=out, **kwargs) + if isinstance(out, MaskedArray): + outmask = getmask(out) + if (outmask is nomask): + outmask = out._mask = make_mask_none(out.shape) + outmask.flat = newmask + else: + if out.dtype.kind in 'biu': + errmsg = "Masked data information would be lost in one or more"\ + " location." + raise MaskError(errmsg) + np.copyto(out, np.nan, where=newmask) + return out + + # unique to masked arrays + def mini(self, axis=None): + """ + Return the array minimum along the specified axis. + + .. deprecated:: 1.13.0 + This function is identical to both: + + * ``self.min(keepdims=True, axis=axis).squeeze(axis=axis)`` + * ``np.ma.minimum.reduce(self, axis=axis)`` + + Typically though, ``self.min(axis=axis)`` is sufficient. + + Parameters + ---------- + axis : int, optional + The axis along which to find the minima. Default is None, in which case + the minimum value in the whole array is returned. + + Returns + ------- + min : scalar or MaskedArray + If `axis` is None, the result is a scalar. Otherwise, if `axis` is + given and the array is at least 2-D, the result is a masked array with + dimension one smaller than the array on which `mini` is called. + + Examples + -------- + >>> x = np.ma.array(np.arange(6), mask=[0 ,1, 0, 0, 0 ,1]).reshape(3, 2) + >>> print(x) + [[0 --] + [2 3] + [4 --]] + >>> x.mini() + 0 + >>> x.mini(axis=0) + masked_array(data = [0 3], + mask = [False False], + fill_value = 999999) + >>> print(x.mini(axis=1)) + [0 2 4] + + There is a small difference between `mini` and `min`: + + >>> x[:,1].mini(axis=0) + masked_array(data = --, + mask = True, + fill_value = 999999) + >>> x[:,1].min(axis=0) + masked + """ + + # 2016-04-13, 1.13.0, gh-8764 + warnings.warn( + "`mini` is deprecated; use the `min` method or " + "`np.ma.minimum.reduce instead.", + DeprecationWarning, stacklevel=2) + return minimum.reduce(self, axis) + + def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue): + """ + Return the maximum along a given axis. + + Parameters + ---------- + axis : {None, int}, optional + Axis along which to operate. By default, ``axis`` is None and the + flattened input is used. + out : array_like, optional + Alternative output array in which to place the result. Must + be of the same shape and buffer length as the expected output. + fill_value : {var}, optional + Value used to fill in the masked values. + If None, use the output of maximum_fill_value(). + + Returns + ------- + amax : array_like + New array holding the result. + If ``out`` was specified, ``out`` is returned. + + See Also + -------- + maximum_fill_value + Returns the maximum filling value for a given datatype. + + """ + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + _mask = self._mask + newmask = _check_mask_axis(_mask, axis, **kwargs) + if fill_value is None: + fill_value = maximum_fill_value(self) + # No explicit output + if out is None: + result = self.filled(fill_value).max( + axis=axis, out=out, **kwargs).view(type(self)) + if result.ndim: + # Set the mask + result.__setmask__(newmask) + # Get rid of Infs + if newmask.ndim: + np.copyto(result, result.fill_value, where=newmask) + elif newmask: + result = masked + return result + # Explicit output + result = self.filled(fill_value).max(axis=axis, out=out, **kwargs) + if isinstance(out, MaskedArray): + outmask = getmask(out) + if (outmask is nomask): + outmask = out._mask = make_mask_none(out.shape) + outmask.flat = newmask + else: + + if out.dtype.kind in 'biu': + errmsg = "Masked data information would be lost in one or more"\ + " location." + raise MaskError(errmsg) + np.copyto(out, np.nan, where=newmask) + return out + + def ptp(self, axis=None, out=None, fill_value=None): + """ + Return (maximum - minimum) along the given dimension + (i.e. peak-to-peak value). + + Parameters + ---------- + axis : {None, int}, optional + Axis along which to find the peaks. If None (default) the + flattened array is used. + out : {None, array_like}, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output + but the type will be cast if necessary. + fill_value : {var}, optional + Value used to fill in the masked values. + + Returns + ------- + ptp : ndarray. + A new array holding the result, unless ``out`` was + specified, in which case a reference to ``out`` is returned. + + """ + if out is None: + result = self.max(axis=axis, fill_value=fill_value) + result -= self.min(axis=axis, fill_value=fill_value) + return result + out.flat = self.max(axis=axis, out=out, fill_value=fill_value) + min_value = self.min(axis=axis, fill_value=fill_value) + np.subtract(out, min_value, out=out, casting='unsafe') + return out + + def partition(self, *args, **kwargs): + warnings.warn("Warning: 'partition' will ignore the 'mask' " + "of the {}.".format(self.__class__.__name__), + stacklevel=2) + return super(MaskedArray, self).partition(*args, **kwargs) + + def argpartition(self, *args, **kwargs): + warnings.warn("Warning: 'argpartition' will ignore the 'mask' " + "of the {}.".format(self.__class__.__name__), + stacklevel=2) + return super(MaskedArray, self).argpartition(*args, **kwargs) + + def take(self, indices, axis=None, out=None, mode='raise'): + """ + """ + (_data, _mask) = (self._data, self._mask) + cls = type(self) + # Make sure the indices are not masked + maskindices = getmask(indices) + if maskindices is not nomask: + indices = indices.filled(0) + # Get the data, promoting scalars to 0d arrays with [...] so that + # .view works correctly + if out is None: + out = _data.take(indices, axis=axis, mode=mode)[...].view(cls) + else: + np.take(_data, indices, axis=axis, mode=mode, out=out) + # Get the mask + if isinstance(out, MaskedArray): + if _mask is nomask: + outmask = maskindices + else: + outmask = _mask.take(indices, axis=axis, mode=mode) + outmask |= maskindices + out.__setmask__(outmask) + # demote 0d arrays back to scalars, for consistency with ndarray.take + return out[()] + + # Array methods + clip = _arraymethod('clip', onmask=False) + copy = _arraymethod('copy') + diagonal = _arraymethod('diagonal') + flatten = _arraymethod('flatten') + repeat = _arraymethod('repeat') + squeeze = _arraymethod('squeeze') + swapaxes = _arraymethod('swapaxes') + T = property(fget=lambda self: self.transpose()) + transpose = _arraymethod('transpose') + + def tolist(self, fill_value=None): + """ + Return the data portion of the masked array as a hierarchical Python list. + + Data items are converted to the nearest compatible Python type. + Masked values are converted to `fill_value`. If `fill_value` is None, + the corresponding entries in the output list will be ``None``. + + Parameters + ---------- + fill_value : scalar, optional + The value to use for invalid entries. Default is None. + + Returns + ------- + result : list + The Python list representation of the masked array. + + Examples + -------- + >>> x = np.ma.array([[1,2,3], [4,5,6], [7,8,9]], mask=[0] + [1,0]*4) + >>> x.tolist() + [[1, None, 3], [None, 5, None], [7, None, 9]] + >>> x.tolist(-999) + [[1, -999, 3], [-999, 5, -999], [7, -999, 9]] + + """ + _mask = self._mask + # No mask ? Just return .data.tolist ? + if _mask is nomask: + return self._data.tolist() + # Explicit fill_value: fill the array and get the list + if fill_value is not None: + return self.filled(fill_value).tolist() + # Structured array. + names = self.dtype.names + if names: + result = self._data.astype([(_, object) for _ in names]) + for n in names: + result[n][_mask[n]] = None + return result.tolist() + # Standard arrays. + if _mask is nomask: + return [None] + # Set temps to save time when dealing w/ marrays. + inishape = self.shape + result = np.array(self._data.ravel(), dtype=object) + result[_mask.ravel()] = None + result.shape = inishape + return result.tolist() + + def tostring(self, fill_value=None, order='C'): + """ + This function is a compatibility alias for tobytes. Despite its name it + returns bytes not strings. + """ + + return self.tobytes(fill_value, order='C') + + def tobytes(self, fill_value=None, order='C'): + """ + Return the array data as a string containing the raw bytes in the array. + + The array is filled with a fill value before the string conversion. + + .. versionadded:: 1.9.0 + + Parameters + ---------- + fill_value : scalar, optional + Value used to fill in the masked values. Default is None, in which + case `MaskedArray.fill_value` is used. + order : {'C','F','A'}, optional + Order of the data item in the copy. Default is 'C'. + + - 'C' -- C order (row major). + - 'F' -- Fortran order (column major). + - 'A' -- Any, current order of array. + - None -- Same as 'A'. + + See Also + -------- + ndarray.tobytes + tolist, tofile + + Notes + ----- + As for `ndarray.tobytes`, information about the shape, dtype, etc., + but also about `fill_value`, will be lost. + + Examples + -------- + >>> x = np.ma.array(np.array([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]]) + >>> x.tobytes() + '\\x01\\x00\\x00\\x00?B\\x0f\\x00?B\\x0f\\x00\\x04\\x00\\x00\\x00' + + """ + return self.filled(fill_value).tobytes(order=order) + + def tofile(self, fid, sep="", format="%s"): + """ + Save a masked array to a file in binary format. + + .. warning:: + This function is not implemented yet. + + Raises + ------ + NotImplementedError + When `tofile` is called. + + """ + raise NotImplementedError("MaskedArray.tofile() not implemented yet.") + + def toflex(self): + """ + Transforms a masked array into a flexible-type array. + + The flexible type array that is returned will have two fields: + + * the ``_data`` field stores the ``_data`` part of the array. + * the ``_mask`` field stores the ``_mask`` part of the array. + + Parameters + ---------- + None + + Returns + ------- + record : ndarray + A new flexible-type `ndarray` with two fields: the first element + containing a value, the second element containing the corresponding + mask boolean. The returned record shape matches self.shape. + + Notes + ----- + A side-effect of transforming a masked array into a flexible `ndarray` is + that meta information (``fill_value``, ...) will be lost. + + Examples + -------- + >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4) + >>> print(x) + [[1 -- 3] + [-- 5 --] + [7 -- 9]] + >>> print(x.toflex()) + [[(1, False) (2, True) (3, False)] + [(4, True) (5, False) (6, True)] + [(7, False) (8, True) (9, False)]] + + """ + # Get the basic dtype. + ddtype = self.dtype + # Make sure we have a mask + _mask = self._mask + if _mask is None: + _mask = make_mask_none(self.shape, ddtype) + # And get its dtype + mdtype = self._mask.dtype + + record = np.ndarray(shape=self.shape, + dtype=[('_data', ddtype), ('_mask', mdtype)]) + record['_data'] = self._data + record['_mask'] = self._mask + return record + torecords = toflex + + # Pickling + def __getstate__(self): + """Return the internal state of the masked array, for pickling + purposes. + + """ + cf = 'CF'[self.flags.fnc] + data_state = super(MaskedArray, self).__reduce__()[2] + return data_state + (getmaskarray(self).tobytes(cf), self._fill_value) + + def __setstate__(self, state): + """Restore the internal state of the masked array, for + pickling purposes. ``state`` is typically the output of the + ``__getstate__`` output, and is a 5-tuple: + + - class name + - a tuple giving the shape of the data + - a typecode for the data + - a binary string for the data + - a binary string for the mask. + + """ + (_, shp, typ, isf, raw, msk, flv) = state + super(MaskedArray, self).__setstate__((shp, typ, isf, raw)) + self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk)) + self.fill_value = flv + + def __reduce__(self): + """Return a 3-tuple for pickling a MaskedArray. + + """ + return (_mareconstruct, + (self.__class__, self._baseclass, (0,), 'b',), + self.__getstate__()) + + def __deepcopy__(self, memo=None): + from copy import deepcopy + copied = MaskedArray.__new__(type(self), self, copy=True) + if memo is None: + memo = {} + memo[id(self)] = copied + for (k, v) in self.__dict__.items(): + copied.__dict__[k] = deepcopy(v, memo) + return copied + + +def _mareconstruct(subtype, baseclass, baseshape, basetype,): + """Internal function that builds a new MaskedArray from the + information stored in a pickle. + + """ + _data = ndarray.__new__(baseclass, baseshape, basetype) + _mask = ndarray.__new__(ndarray, baseshape, make_mask_descr(basetype)) + return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,) + + +class mvoid(MaskedArray): + """ + Fake a 'void' object to use for masked array with structured dtypes. + """ + + def __new__(self, data, mask=nomask, dtype=None, fill_value=None, + hardmask=False, copy=False, subok=True): + _data = np.array(data, copy=copy, subok=subok, dtype=dtype) + _data = _data.view(self) + _data._hardmask = hardmask + if mask is not nomask: + if isinstance(mask, np.void): + _data._mask = mask + else: + try: + # Mask is already a 0D array + _data._mask = np.void(mask) + except TypeError: + # Transform the mask to a void + mdtype = make_mask_descr(dtype) + _data._mask = np.array(mask, dtype=mdtype)[()] + if fill_value is not None: + _data.fill_value = fill_value + return _data + + def _get_data(self): + # Make sure that the _data part is a np.void + return super(mvoid, self)._data[()] + + _data = property(fget=_get_data) + + def __getitem__(self, indx): + """ + Get the index. + + """ + m = self._mask + if isinstance(m[indx], ndarray): + # Can happen when indx is a multi-dimensional field: + # A = ma.masked_array(data=[([0,1],)], mask=[([True, + # False],)], dtype=[("A", ">i2", (2,))]) + # x = A[0]; y = x["A"]; then y.mask["A"].size==2 + # and we can not say masked/unmasked. + # The result is no longer mvoid! + # See also issue #6724. + return masked_array( + data=self._data[indx], mask=m[indx], + fill_value=self._fill_value[indx], + hard_mask=self._hardmask) + if m is not nomask and m[indx]: + return masked + return self._data[indx] + + def __setitem__(self, indx, value): + self._data[indx] = value + if self._hardmask: + self._mask[indx] |= getattr(value, "_mask", False) + else: + self._mask[indx] = getattr(value, "_mask", False) + + def __str__(self): + m = self._mask + if m is nomask: + return str(self._data) + + rdtype = _replace_dtype_fields(self._data.dtype, "O") + data_arr = super(mvoid, self)._data + res = data_arr.astype(rdtype) + _recursive_printoption(res, self._mask, masked_print_option) + return str(res) + + __repr__ = __str__ + + def __iter__(self): + "Defines an iterator for mvoid" + (_data, _mask) = (self._data, self._mask) + if _mask is nomask: + for d in _data: + yield d + else: + for (d, m) in zip(_data, _mask): + if m: + yield masked + else: + yield d + + def __len__(self): + return self._data.__len__() + + def filled(self, fill_value=None): + """ + Return a copy with masked fields filled with a given value. + + Parameters + ---------- + fill_value : scalar, optional + The value to use for invalid entries (None by default). + If None, the `fill_value` attribute is used instead. + + Returns + ------- + filled_void + A `np.void` object + + See Also + -------- + MaskedArray.filled + + """ + return asarray(self).filled(fill_value)[()] + + def tolist(self): + """ + Transforms the mvoid object into a tuple. + + Masked fields are replaced by None. + + Returns + ------- + returned_tuple + Tuple of fields + """ + _mask = self._mask + if _mask is nomask: + return self._data.tolist() + result = [] + for (d, m) in zip(self._data, self._mask): + if m: + result.append(None) + else: + # .item() makes sure we return a standard Python object + result.append(d.item()) + return tuple(result) + + +############################################################################## +# Shortcuts # +############################################################################## + + +def isMaskedArray(x): + """ + Test whether input is an instance of MaskedArray. + + This function returns True if `x` is an instance of MaskedArray + and returns False otherwise. Any object is accepted as input. + + Parameters + ---------- + x : object + Object to test. + + Returns + ------- + result : bool + True if `x` is a MaskedArray. + + See Also + -------- + isMA : Alias to isMaskedArray. + isarray : Alias to isMaskedArray. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.eye(3, 3) + >>> a + array([[ 1., 0., 0.], + [ 0., 1., 0.], + [ 0., 0., 1.]]) + >>> m = ma.masked_values(a, 0) + >>> m + masked_array(data = + [[1.0 -- --] + [-- 1.0 --] + [-- -- 1.0]], + mask = + [[False True True] + [ True False True] + [ True True False]], + fill_value=0.0) + >>> ma.isMaskedArray(a) + False + >>> ma.isMaskedArray(m) + True + >>> ma.isMaskedArray([0, 1, 2]) + False + + """ + return isinstance(x, MaskedArray) + + +isarray = isMaskedArray +isMA = isMaskedArray # backward compatibility + + +class MaskedConstant(MaskedArray): + # the lone np.ma.masked instance + __singleton = None + + @classmethod + def __has_singleton(cls): + # second case ensures `cls.__singleton` is not just a view on the + # superclass singleton + return cls.__singleton is not None and type(cls.__singleton) is cls + + def __new__(cls): + if not cls.__has_singleton(): + # We define the masked singleton as a float for higher precedence. + # Note that it can be tricky sometimes w/ type comparison + data = np.array(0.) + mask = np.array(True) + + # prevent any modifications + data.flags.writeable = False + mask.flags.writeable = False + + # don't fall back on MaskedArray.__new__(MaskedConstant), since + # that might confuse it - this way, the construction is entirely + # within our control + cls.__singleton = MaskedArray(data, mask=mask).view(cls) + + return cls.__singleton + + def __array_finalize__(self, obj): + if not self.__has_singleton(): + # this handles the `.view` in __new__, which we want to copy across + # properties normally + return super(MaskedConstant, self).__array_finalize__(obj) + elif self is self.__singleton: + # not clear how this can happen, play it safe + pass + else: + # everywhere else, we want to downcast to MaskedArray, to prevent a + # duplicate maskedconstant. + self.__class__ = MaskedArray + MaskedArray.__array_finalize__(self, obj) + + def __array_prepare__(self, obj, context=None): + return self.view(MaskedArray).__array_prepare__(obj, context) + + def __array_wrap__(self, obj, context=None): + return self.view(MaskedArray).__array_wrap__(obj, context) + + def __str__(self): + return str(masked_print_option._display) + + if sys.version_info.major < 3: + def __unicode__(self): + return unicode(masked_print_option._display) + + def __repr__(self): + if self is MaskedConstant.__singleton: + return 'masked' + else: + # it's a subclass, or something is wrong, make it obvious + return object.__repr__(self) + + def __reduce__(self): + """Override of MaskedArray's __reduce__. + """ + return (self.__class__, ()) + + # inplace operations have no effect. We have to override them to avoid + # trying to modify the readonly data and mask arrays + def __iop__(self, other): + return self + __iadd__ = \ + __isub__ = \ + __imul__ = \ + __ifloordiv__ = \ + __itruediv__ = \ + __ipow__ = \ + __iop__ + del __iop__ # don't leave this around + + def copy(self, *args, **kwargs): + """ Copy is a no-op on the maskedconstant, as it is a scalar """ + # maskedconstant is a scalar, so copy doesn't need to copy. There's + # precedent for this with `np.bool_` scalars. + return self + + +masked = masked_singleton = MaskedConstant() +masked_array = MaskedArray + + +def array(data, dtype=None, copy=False, order=None, + mask=nomask, fill_value=None, keep_mask=True, + hard_mask=False, shrink=True, subok=True, ndmin=0): + """ + Shortcut to MaskedArray. + + The options are in a different order for convenience and backwards + compatibility. + + """ + return MaskedArray(data, mask=mask, dtype=dtype, copy=copy, + subok=subok, keep_mask=keep_mask, + hard_mask=hard_mask, fill_value=fill_value, + ndmin=ndmin, shrink=shrink, order=order) +array.__doc__ = masked_array.__doc__ + + +def is_masked(x): + """ + Determine whether input has masked values. + + Accepts any object as input, but always returns False unless the + input is a MaskedArray containing masked values. + + Parameters + ---------- + x : array_like + Array to check for masked values. + + Returns + ------- + result : bool + True if `x` is a MaskedArray with masked values, False otherwise. + + Examples + -------- + >>> import numpy.ma as ma + >>> x = ma.masked_equal([0, 1, 0, 2, 3], 0) + >>> x + masked_array(data = [-- 1 -- 2 3], + mask = [ True False True False False], + fill_value=999999) + >>> ma.is_masked(x) + True + >>> x = ma.masked_equal([0, 1, 0, 2, 3], 42) + >>> x + masked_array(data = [0 1 0 2 3], + mask = False, + fill_value=999999) + >>> ma.is_masked(x) + False + + Always returns False if `x` isn't a MaskedArray. + + >>> x = [False, True, False] + >>> ma.is_masked(x) + False + >>> x = 'a string' + >>> ma.is_masked(x) + False + + """ + m = getmask(x) + if m is nomask: + return False + elif m.any(): + return True + return False + + +############################################################################## +# Extrema functions # +############################################################################## + + +class _extrema_operation(_MaskedUFunc): + """ + Generic class for maximum/minimum functions. + + .. note:: + This is the base class for `_maximum_operation` and + `_minimum_operation`. + + """ + def __init__(self, ufunc, compare, fill_value): + super(_extrema_operation, self).__init__(ufunc) + self.compare = compare + self.fill_value_func = fill_value + + def __call__(self, a, b=None): + "Executes the call behavior." + if b is None: + # 2016-04-13, 1.13.0 + warnings.warn( + "Single-argument form of np.ma.{0} is deprecated. Use " + "np.ma.{0}.reduce instead.".format(self.__name__), + DeprecationWarning, stacklevel=2) + return self.reduce(a) + return where(self.compare(a, b), a, b) + + def reduce(self, target, axis=np._NoValue): + "Reduce target along the given axis." + target = narray(target, copy=False, subok=True) + m = getmask(target) + + if axis is np._NoValue and target.ndim > 1: + # 2017-05-06, Numpy 1.13.0: warn on axis default + warnings.warn( + "In the future the default for ma.{0}.reduce will be axis=0, " + "not the current None, to match np.{0}.reduce. " + "Explicitly pass 0 or None to silence this warning.".format( + self.__name__ + ), + MaskedArrayFutureWarning, stacklevel=2) + axis = None + + if axis is not np._NoValue: + kwargs = dict(axis=axis) + else: + kwargs = dict() + + if m is nomask: + t = self.f.reduce(target, **kwargs) + else: + target = target.filled( + self.fill_value_func(target)).view(type(target)) + t = self.f.reduce(target, **kwargs) + m = umath.logical_and.reduce(m, **kwargs) + if hasattr(t, '_mask'): + t._mask = m + elif m: + t = masked + return t + + def outer(self, a, b): + "Return the function applied to the outer product of a and b." + ma = getmask(a) + mb = getmask(b) + if ma is nomask and mb is nomask: + m = nomask + else: + ma = getmaskarray(a) + mb = getmaskarray(b) + m = logical_or.outer(ma, mb) + result = self.f.outer(filled(a), filled(b)) + if not isinstance(result, MaskedArray): + result = result.view(MaskedArray) + result._mask = m + return result + +def min(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue): + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + try: + return obj.min(axis=axis, fill_value=fill_value, out=out, **kwargs) + except (AttributeError, TypeError): + # If obj doesn't have a min method, or if the method doesn't accept a + # fill_value argument + return asanyarray(obj).min(axis=axis, fill_value=fill_value, + out=out, **kwargs) +min.__doc__ = MaskedArray.min.__doc__ + +def max(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue): + kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims} + + try: + return obj.max(axis=axis, fill_value=fill_value, out=out, **kwargs) + except (AttributeError, TypeError): + # If obj doesn't have a max method, or if the method doesn't accept a + # fill_value argument + return asanyarray(obj).max(axis=axis, fill_value=fill_value, + out=out, **kwargs) +max.__doc__ = MaskedArray.max.__doc__ + + +def ptp(obj, axis=None, out=None, fill_value=None): + """ + a.ptp(axis=None) = a.max(axis) - a.min(axis) + + """ + try: + return obj.ptp(axis, out=out, fill_value=fill_value) + except (AttributeError, TypeError): + # If obj doesn't have a ptp method or if the method doesn't accept + # a fill_value argument + return asanyarray(obj).ptp(axis=axis, fill_value=fill_value, out=out) +ptp.__doc__ = MaskedArray.ptp.__doc__ + + +############################################################################## +# Definition of functions from the corresponding methods # +############################################################################## + + +class _frommethod(object): + """ + Define functions from existing MaskedArray methods. + + Parameters + ---------- + methodname : str + Name of the method to transform. + + """ + + def __init__(self, methodname, reversed=False): + self.__name__ = methodname + self.__doc__ = self.getdoc() + self.reversed = reversed + + def getdoc(self): + "Return the doc of the function (from the doc of the method)." + meth = getattr(MaskedArray, self.__name__, None) or\ + getattr(np, self.__name__, None) + signature = self.__name__ + get_object_signature(meth) + if meth is not None: + doc = """ %s\n%s""" % ( + signature, getattr(meth, '__doc__', None)) + return doc + + def __call__(self, a, *args, **params): + if self.reversed: + args = list(args) + a, args[0] = args[0], a + + marr = asanyarray(a) + method_name = self.__name__ + method = getattr(type(marr), method_name, None) + if method is None: + # use the corresponding np function + method = getattr(np, method_name) + + return method(marr, *args, **params) + + +all = _frommethod('all') +anomalies = anom = _frommethod('anom') +any = _frommethod('any') +compress = _frommethod('compress', reversed=True) +cumprod = _frommethod('cumprod') +cumsum = _frommethod('cumsum') +copy = _frommethod('copy') +diagonal = _frommethod('diagonal') +harden_mask = _frommethod('harden_mask') +ids = _frommethod('ids') +maximum = _extrema_operation(umath.maximum, greater, maximum_fill_value) +mean = _frommethod('mean') +minimum = _extrema_operation(umath.minimum, less, minimum_fill_value) +nonzero = _frommethod('nonzero') +prod = _frommethod('prod') +product = _frommethod('prod') +ravel = _frommethod('ravel') +repeat = _frommethod('repeat') +shrink_mask = _frommethod('shrink_mask') +soften_mask = _frommethod('soften_mask') +std = _frommethod('std') +sum = _frommethod('sum') +swapaxes = _frommethod('swapaxes') +#take = _frommethod('take') +trace = _frommethod('trace') +var = _frommethod('var') + +count = _frommethod('count') + +def take(a, indices, axis=None, out=None, mode='raise'): + """ + """ + a = masked_array(a) + return a.take(indices, axis=axis, out=out, mode=mode) + + +def power(a, b, third=None): + """ + Returns element-wise base array raised to power from second array. + + This is the masked array version of `numpy.power`. For details see + `numpy.power`. + + See Also + -------- + numpy.power + + Notes + ----- + The *out* argument to `numpy.power` is not supported, `third` has to be + None. + + """ + if third is not None: + raise MaskError("3-argument power not supported.") + # Get the masks + ma = getmask(a) + mb = getmask(b) + m = mask_or(ma, mb) + # Get the rawdata + fa = getdata(a) + fb = getdata(b) + # Get the type of the result (so that we preserve subclasses) + if isinstance(a, MaskedArray): + basetype = type(a) + else: + basetype = MaskedArray + # Get the result and view it as a (subclass of) MaskedArray + with np.errstate(divide='ignore', invalid='ignore'): + result = np.where(m, fa, umath.power(fa, fb)).view(basetype) + result._update_from(a) + # Find where we're in trouble w/ NaNs and Infs + invalid = np.logical_not(np.isfinite(result.view(ndarray))) + # Add the initial mask + if m is not nomask: + if not (result.ndim): + return masked + result._mask = np.logical_or(m, invalid) + # Fix the invalid parts + if invalid.any(): + if not result.ndim: + return masked + elif result._mask is nomask: + result._mask = invalid + result._data[invalid] = result.fill_value + return result + +argmin = _frommethod('argmin') +argmax = _frommethod('argmax') + +def argsort(a, axis=np._NoValue, kind='quicksort', order=None, endwith=True, fill_value=None): + "Function version of the eponymous method." + a = np.asanyarray(a) + + # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default + if axis is np._NoValue: + axis = _deprecate_argsort_axis(a) + + if isinstance(a, MaskedArray): + return a.argsort(axis=axis, kind=kind, order=order, + endwith=endwith, fill_value=fill_value) + else: + return a.argsort(axis=axis, kind=kind, order=order) +argsort.__doc__ = MaskedArray.argsort.__doc__ + +def sort(a, axis=-1, kind='quicksort', order=None, endwith=True, fill_value=None): + "Function version of the eponymous method." + a = np.array(a, copy=True, subok=True) + if axis is None: + a = a.flatten() + axis = 0 + + if isinstance(a, MaskedArray): + a.sort(axis=axis, kind=kind, order=order, + endwith=endwith, fill_value=fill_value) + else: + a.sort(axis=axis, kind=kind, order=order) + return a +sort.__doc__ = MaskedArray.sort.__doc__ + + +def compressed(x): + """ + Return all the non-masked data as a 1-D array. + + This function is equivalent to calling the "compressed" method of a + `MaskedArray`, see `MaskedArray.compressed` for details. + + See Also + -------- + MaskedArray.compressed + Equivalent method. + + """ + return asanyarray(x).compressed() + + +def concatenate(arrays, axis=0): + """ + Concatenate a sequence of arrays along the given axis. + + Parameters + ---------- + arrays : sequence of array_like + The arrays must have the same shape, except in the dimension + corresponding to `axis` (the first, by default). + axis : int, optional + The axis along which the arrays will be joined. Default is 0. + + Returns + ------- + result : MaskedArray + The concatenated array with any masked entries preserved. + + See Also + -------- + numpy.concatenate : Equivalent function in the top-level NumPy module. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = ma.arange(3) + >>> a[1] = ma.masked + >>> b = ma.arange(2, 5) + >>> a + masked_array(data = [0 -- 2], + mask = [False True False], + fill_value = 999999) + >>> b + masked_array(data = [2 3 4], + mask = False, + fill_value = 999999) + >>> ma.concatenate([a, b]) + masked_array(data = [0 -- 2 2 3 4], + mask = [False True False False False False], + fill_value = 999999) + + """ + d = np.concatenate([getdata(a) for a in arrays], axis) + rcls = get_masked_subclass(*arrays) + data = d.view(rcls) + # Check whether one of the arrays has a non-empty mask. + for x in arrays: + if getmask(x) is not nomask: + break + else: + return data + # OK, so we have to concatenate the masks + dm = np.concatenate([getmaskarray(a) for a in arrays], axis) + dm = dm.reshape(d.shape) + + # If we decide to keep a '_shrinkmask' option, we want to check that + # all of them are True, and then check for dm.any() + data._mask = _shrink_mask(dm) + return data + + +def diag(v, k=0): + """ + Extract a diagonal or construct a diagonal array. + + This function is the equivalent of `numpy.diag` that takes masked + values into account, see `numpy.diag` for details. + + See Also + -------- + numpy.diag : Equivalent function for ndarrays. + + """ + output = np.diag(v, k).view(MaskedArray) + if getmask(v) is not nomask: + output._mask = np.diag(v._mask, k) + return output + + +def expand_dims(x, axis): + """ + Expand the shape of an array. + + Expands the shape of the array by including a new axis before the one + specified by the `axis` parameter. This function behaves the same as + `numpy.expand_dims` but preserves masked elements. + + See Also + -------- + numpy.expand_dims : Equivalent function in top-level NumPy module. + + Examples + -------- + >>> import numpy.ma as ma + >>> x = ma.array([1, 2, 4]) + >>> x[1] = ma.masked + >>> x + masked_array(data = [1 -- 4], + mask = [False True False], + fill_value = 999999) + >>> np.expand_dims(x, axis=0) + array([[1, 2, 4]]) + >>> ma.expand_dims(x, axis=0) + masked_array(data = + [[1 -- 4]], + mask = + [[False True False]], + fill_value = 999999) + + The same result can be achieved using slicing syntax with `np.newaxis`. + + >>> x[np.newaxis, :] + masked_array(data = + [[1 -- 4]], + mask = + [[False True False]], + fill_value = 999999) + + """ + result = n_expand_dims(x, axis) + if isinstance(x, MaskedArray): + new_shape = result.shape + result = x.view() + result.shape = new_shape + if result._mask is not nomask: + result._mask.shape = new_shape + return result + + +def left_shift(a, n): + """ + Shift the bits of an integer to the left. + + This is the masked array version of `numpy.left_shift`, for details + see that function. + + See Also + -------- + numpy.left_shift + + """ + m = getmask(a) + if m is nomask: + d = umath.left_shift(filled(a), n) + return masked_array(d) + else: + d = umath.left_shift(filled(a, 0), n) + return masked_array(d, mask=m) + + +def right_shift(a, n): + """ + Shift the bits of an integer to the right. + + This is the masked array version of `numpy.right_shift`, for details + see that function. + + See Also + -------- + numpy.right_shift + + """ + m = getmask(a) + if m is nomask: + d = umath.right_shift(filled(a), n) + return masked_array(d) + else: + d = umath.right_shift(filled(a, 0), n) + return masked_array(d, mask=m) + + +def put(a, indices, values, mode='raise'): + """ + Set storage-indexed locations to corresponding values. + + This function is equivalent to `MaskedArray.put`, see that method + for details. + + See Also + -------- + MaskedArray.put + + """ + # We can't use 'frommethod', the order of arguments is different + try: + return a.put(indices, values, mode=mode) + except AttributeError: + return narray(a, copy=False).put(indices, values, mode=mode) + + +def putmask(a, mask, values): # , mode='raise'): + """ + Changes elements of an array based on conditional and input values. + + This is the masked array version of `numpy.putmask`, for details see + `numpy.putmask`. + + See Also + -------- + numpy.putmask + + Notes + ----- + Using a masked array as `values` will **not** transform a `ndarray` into + a `MaskedArray`. + + """ + # We can't use 'frommethod', the order of arguments is different + if not isinstance(a, MaskedArray): + a = a.view(MaskedArray) + (valdata, valmask) = (getdata(values), getmask(values)) + if getmask(a) is nomask: + if valmask is not nomask: + a._sharedmask = True + a._mask = make_mask_none(a.shape, a.dtype) + np.copyto(a._mask, valmask, where=mask) + elif a._hardmask: + if valmask is not nomask: + m = a._mask.copy() + np.copyto(m, valmask, where=mask) + a.mask |= m + else: + if valmask is nomask: + valmask = getmaskarray(values) + np.copyto(a._mask, valmask, where=mask) + np.copyto(a._data, valdata, where=mask) + return + + +def transpose(a, axes=None): + """ + Permute the dimensions of an array. + + This function is exactly equivalent to `numpy.transpose`. + + See Also + -------- + numpy.transpose : Equivalent function in top-level NumPy module. + + Examples + -------- + >>> import numpy.ma as ma + >>> x = ma.arange(4).reshape((2,2)) + >>> x[1, 1] = ma.masked + >>>> x + masked_array(data = + [[0 1] + [2 --]], + mask = + [[False False] + [False True]], + fill_value = 999999) + >>> ma.transpose(x) + masked_array(data = + [[0 2] + [1 --]], + mask = + [[False False] + [False True]], + fill_value = 999999) + + """ + # We can't use 'frommethod', as 'transpose' doesn't take keywords + try: + return a.transpose(axes) + except AttributeError: + return narray(a, copy=False).transpose(axes).view(MaskedArray) + + +def reshape(a, new_shape, order='C'): + """ + Returns an array containing the same data with a new shape. + + Refer to `MaskedArray.reshape` for full documentation. + + See Also + -------- + MaskedArray.reshape : equivalent function + + """ + # We can't use 'frommethod', it whine about some parameters. Dmmit. + try: + return a.reshape(new_shape, order=order) + except AttributeError: + _tmp = narray(a, copy=False).reshape(new_shape, order=order) + return _tmp.view(MaskedArray) + + +def resize(x, new_shape): + """ + Return a new masked array with the specified size and shape. + + This is the masked equivalent of the `numpy.resize` function. The new + array is filled with repeated copies of `x` (in the order that the + data are stored in memory). If `x` is masked, the new array will be + masked, and the new mask will be a repetition of the old one. + + See Also + -------- + numpy.resize : Equivalent function in the top level NumPy module. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = ma.array([[1, 2] ,[3, 4]]) + >>> a[0, 1] = ma.masked + >>> a + masked_array(data = + [[1 --] + [3 4]], + mask = + [[False True] + [False False]], + fill_value = 999999) + >>> np.resize(a, (3, 3)) + array([[1, 2, 3], + [4, 1, 2], + [3, 4, 1]]) + >>> ma.resize(a, (3, 3)) + masked_array(data = + [[1 -- 3] + [4 1 --] + [3 4 1]], + mask = + [[False True False] + [False False True] + [False False False]], + fill_value = 999999) + + A MaskedArray is always returned, regardless of the input type. + + >>> a = np.array([[1, 2] ,[3, 4]]) + >>> ma.resize(a, (3, 3)) + masked_array(data = + [[1 2 3] + [4 1 2] + [3 4 1]], + mask = + False, + fill_value = 999999) + + """ + # We can't use _frommethods here, as N.resize is notoriously whiny. + m = getmask(x) + if m is not nomask: + m = np.resize(m, new_shape) + result = np.resize(x, new_shape).view(get_masked_subclass(x)) + if result.ndim: + result._mask = m + return result + + +def rank(obj): + """ + maskedarray version of the numpy function. + + .. note:: + Deprecated since 1.10.0 + + """ + # 2015-04-12, 1.10.0 + warnings.warn( + "`rank` is deprecated; use the `ndim` function instead. ", + np.VisibleDeprecationWarning, stacklevel=2) + return np.ndim(getdata(obj)) + +rank.__doc__ = np.rank.__doc__ + + +def ndim(obj): + """ + maskedarray version of the numpy function. + + """ + return np.ndim(getdata(obj)) + +ndim.__doc__ = np.ndim.__doc__ + + +def shape(obj): + "maskedarray version of the numpy function." + return np.shape(getdata(obj)) +shape.__doc__ = np.shape.__doc__ + + +def size(obj, axis=None): + "maskedarray version of the numpy function." + return np.size(getdata(obj), axis) +size.__doc__ = np.size.__doc__ + + +############################################################################## +# Extra functions # +############################################################################## + + +def where(condition, x=_NoValue, y=_NoValue): + """ + Return a masked array with elements from x or y, depending on condition. + + Returns a masked array, shaped like condition, where the elements + are from `x` when `condition` is True, and from `y` otherwise. + If neither `x` nor `y` are given, the function returns a tuple of + indices where `condition` is True (the result of + ``condition.nonzero()``). + + Parameters + ---------- + condition : array_like, bool + The condition to meet. For each True element, yield the corresponding + element from `x`, otherwise from `y`. + x, y : array_like, optional + Values from which to choose. `x`, `y` and `condition` need to be + broadcastable to some shape. + + Returns + ------- + out : MaskedArray or tuple of ndarrays + The resulting masked array if `x` and `y` were given, otherwise + the result of ``condition.nonzero()``. + + See Also + -------- + numpy.where : Equivalent function in the top-level NumPy module. + + Examples + -------- + >>> x = np.ma.array(np.arange(9.).reshape(3, 3), mask=[[0, 1, 0], + ... [1, 0, 1], + ... [0, 1, 0]]) + >>> print(x) + [[0.0 -- 2.0] + [-- 4.0 --] + [6.0 -- 8.0]] + >>> np.ma.where(x > 5) # return the indices where x > 5 + (array([2, 2]), array([0, 2])) + + >>> print(np.ma.where(x > 5, x, -3.1416)) + [[-3.1416 -- -3.1416] + [-- -3.1416 --] + [6.0 -- 8.0]] + + """ + + # handle the single-argument case + missing = (x is _NoValue, y is _NoValue).count(True) + if missing == 1: + raise ValueError("Must provide both 'x' and 'y' or neither.") + if missing == 2: + return nonzero(condition) + + # we only care if the condition is true - false or masked pick y + cf = filled(condition, False) + xd = getdata(x) + yd = getdata(y) + + # we need the full arrays here for correct final dimensions + cm = getmaskarray(condition) + xm = getmaskarray(x) + ym = getmaskarray(y) + + # deal with the fact that masked.dtype == float64, but we don't actually + # want to treat it as that. + if x is masked and y is not masked: + xd = np.zeros((), dtype=yd.dtype) + xm = np.ones((), dtype=ym.dtype) + elif y is masked and x is not masked: + yd = np.zeros((), dtype=xd.dtype) + ym = np.ones((), dtype=xm.dtype) + + data = np.where(cf, xd, yd) + mask = np.where(cf, xm, ym) + mask = np.where(cm, np.ones((), dtype=mask.dtype), mask) + + # collapse the mask, for backwards compatibility + mask = _shrink_mask(mask) + + return masked_array(data, mask=mask) + + +def choose(indices, choices, out=None, mode='raise'): + """ + Use an index array to construct a new array from a set of choices. + + Given an array of integers and a set of n choice arrays, this method + will create a new array that merges each of the choice arrays. Where a + value in `a` is i, the new array will have the value that choices[i] + contains in the same place. + + Parameters + ---------- + a : ndarray of ints + This array must contain integers in ``[0, n-1]``, where n is the + number of choices. + choices : sequence of arrays + Choice arrays. The index array and all of the choices should be + broadcastable to the same shape. + out : array, optional + If provided, the result will be inserted into this array. It should + be of the appropriate shape and `dtype`. + mode : {'raise', 'wrap', 'clip'}, optional + Specifies how out-of-bounds indices will behave. + + * 'raise' : raise an error + * 'wrap' : wrap around + * 'clip' : clip to the range + + Returns + ------- + merged_array : array + + See Also + -------- + choose : equivalent function + + Examples + -------- + >>> choice = np.array([[1,1,1], [2,2,2], [3,3,3]]) + >>> a = np.array([2, 1, 0]) + >>> np.ma.choose(a, choice) + masked_array(data = [3 2 1], + mask = False, + fill_value=999999) + + """ + def fmask(x): + "Returns the filled array, or True if masked." + if x is masked: + return True + return filled(x) + + def nmask(x): + "Returns the mask, True if ``masked``, False if ``nomask``." + if x is masked: + return True + return getmask(x) + # Get the indices. + c = filled(indices, 0) + # Get the masks. + masks = [nmask(x) for x in choices] + data = [fmask(x) for x in choices] + # Construct the mask + outputmask = np.choose(c, masks, mode=mode) + outputmask = make_mask(mask_or(outputmask, getmask(indices)), + copy=0, shrink=True) + # Get the choices. + d = np.choose(c, data, mode=mode, out=out).view(MaskedArray) + if out is not None: + if isinstance(out, MaskedArray): + out.__setmask__(outputmask) + return out + d.__setmask__(outputmask) + return d + + +def round_(a, decimals=0, out=None): + """ + Return a copy of a, rounded to 'decimals' places. + + When 'decimals' is negative, it specifies the number of positions + to the left of the decimal point. The real and imaginary parts of + complex numbers are rounded separately. Nothing is done if the + array is not of float type and 'decimals' is greater than or equal + to 0. + + Parameters + ---------- + decimals : int + Number of decimals to round to. May be negative. + out : array_like + Existing array to use for output. + If not given, returns a default copy of a. + + Notes + ----- + If out is given and does not have a mask attribute, the mask of a + is lost! + + """ + if out is None: + return np.round_(a, decimals, out) + else: + np.round_(getdata(a), decimals, out) + if hasattr(out, '_mask'): + out._mask = getmask(a) + return out +round = round_ + + +# Needed by dot, so move here from extras.py. It will still be exported +# from extras.py for compatibility. +def mask_rowcols(a, axis=None): + """ + Mask rows and/or columns of a 2D array that contain masked values. + + Mask whole rows and/or columns of a 2D array that contain + masked values. The masking behavior is selected using the + `axis` parameter. + + - If `axis` is None, rows *and* columns are masked. + - If `axis` is 0, only rows are masked. + - If `axis` is 1 or -1, only columns are masked. + + Parameters + ---------- + a : array_like, MaskedArray + The array to mask. If not a MaskedArray instance (or if no array + elements are masked). The result is a MaskedArray with `mask` set + to `nomask` (False). Must be a 2D array. + axis : int, optional + Axis along which to perform the operation. If None, applies to a + flattened version of the array. + + Returns + ------- + a : MaskedArray + A modified version of the input array, masked depending on the value + of the `axis` parameter. + + Raises + ------ + NotImplementedError + If input array `a` is not 2D. + + See Also + -------- + mask_rows : Mask rows of a 2D array that contain masked values. + mask_cols : Mask cols of a 2D array that contain masked values. + masked_where : Mask where a condition is met. + + Notes + ----- + The input array's mask is modified by this function. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.zeros((3, 3), dtype=int) + >>> a[1, 1] = 1 + >>> a + array([[0, 0, 0], + [0, 1, 0], + [0, 0, 0]]) + >>> a = ma.masked_equal(a, 1) + >>> a + masked_array(data = + [[0 0 0] + [0 -- 0] + [0 0 0]], + mask = + [[False False False] + [False True False] + [False False False]], + fill_value=999999) + >>> ma.mask_rowcols(a) + masked_array(data = + [[0 -- 0] + [-- -- --] + [0 -- 0]], + mask = + [[False True False] + [ True True True] + [False True False]], + fill_value=999999) + + """ + a = array(a, subok=False) + if a.ndim != 2: + raise NotImplementedError("mask_rowcols works for 2D arrays only.") + m = getmask(a) + # Nothing is masked: return a + if m is nomask or not m.any(): + return a + maskedval = m.nonzero() + a._mask = a._mask.copy() + if not axis: + a[np.unique(maskedval[0])] = masked + if axis in [None, 1, -1]: + a[:, np.unique(maskedval[1])] = masked + return a + + +# Include masked dot here to avoid import problems in getting it from +# extras.py. Note that it is not included in __all__, but rather exported +# from extras in order to avoid backward compatibility problems. +def dot(a, b, strict=False, out=None): + """ + Return the dot product of two arrays. + + This function is the equivalent of `numpy.dot` that takes masked values + into account. Note that `strict` and `out` are in different position + than in the method version. In order to maintain compatibility with the + corresponding method, it is recommended that the optional arguments be + treated as keyword only. At some point that may be mandatory. + + .. note:: + Works only with 2-D arrays at the moment. + + + Parameters + ---------- + a, b : masked_array_like + Inputs arrays. + strict : bool, optional + Whether masked data are propagated (True) or set to 0 (False) for + the computation. Default is False. Propagating the mask means that + if a masked value appears in a row or column, the whole row or + column is considered masked. + out : masked_array, optional + Output argument. This must have the exact kind that would be returned + if it was not used. In particular, it must have the right type, must be + C-contiguous, and its dtype must be the dtype that would be returned + for `dot(a,b)`. This is a performance feature. Therefore, if these + conditions are not met, an exception is raised, instead of attempting + to be flexible. + + .. versionadded:: 1.10.2 + + See Also + -------- + numpy.dot : Equivalent function for ndarrays. + + Examples + -------- + >>> a = ma.array([[1, 2, 3], [4, 5, 6]], mask=[[1, 0, 0], [0, 0, 0]]) + >>> b = ma.array([[1, 2], [3, 4], [5, 6]], mask=[[1, 0], [0, 0], [0, 0]]) + >>> np.ma.dot(a, b) + masked_array(data = + [[21 26] + [45 64]], + mask = + [[False False] + [False False]], + fill_value = 999999) + >>> np.ma.dot(a, b, strict=True) + masked_array(data = + [[-- --] + [-- 64]], + mask = + [[ True True] + [ True False]], + fill_value = 999999) + + """ + # !!!: Works only with 2D arrays. There should be a way to get it to run + # with higher dimension + if strict and (a.ndim == 2) and (b.ndim == 2): + a = mask_rowcols(a, 0) + b = mask_rowcols(b, 1) + am = ~getmaskarray(a) + bm = ~getmaskarray(b) + + if out is None: + d = np.dot(filled(a, 0), filled(b, 0)) + m = ~np.dot(am, bm) + if d.ndim == 0: + d = np.asarray(d) + r = d.view(get_masked_subclass(a, b)) + r.__setmask__(m) + return r + else: + d = np.dot(filled(a, 0), filled(b, 0), out._data) + if out.mask.shape != d.shape: + out._mask = np.empty(d.shape, MaskType) + np.dot(am, bm, out._mask) + np.logical_not(out._mask, out._mask) + return out + + +def inner(a, b): + """ + Returns the inner product of a and b for arrays of floating point types. + + Like the generic NumPy equivalent the product sum is over the last dimension + of a and b. The first argument is not conjugated. + + """ + fa = filled(a, 0) + fb = filled(b, 0) + if fa.ndim == 0: + fa.shape = (1,) + if fb.ndim == 0: + fb.shape = (1,) + return np.inner(fa, fb).view(MaskedArray) +inner.__doc__ = doc_note(np.inner.__doc__, + "Masked values are replaced by 0.") +innerproduct = inner + + +def outer(a, b): + "maskedarray version of the numpy function." + fa = filled(a, 0).ravel() + fb = filled(b, 0).ravel() + d = np.outer(fa, fb) + ma = getmask(a) + mb = getmask(b) + if ma is nomask and mb is nomask: + return masked_array(d) + ma = getmaskarray(a) + mb = getmaskarray(b) + m = make_mask(1 - np.outer(1 - ma, 1 - mb), copy=0) + return masked_array(d, mask=m) +outer.__doc__ = doc_note(np.outer.__doc__, + "Masked values are replaced by 0.") +outerproduct = outer + + +def _convolve_or_correlate(f, a, v, mode, propagate_mask): + """ + Helper function for ma.correlate and ma.convolve + """ + if propagate_mask: + # results which are contributed to by either item in any pair being invalid + mask = ( + f(getmaskarray(a), np.ones(np.shape(v), dtype=bool), mode=mode) + | f(np.ones(np.shape(a), dtype=bool), getmaskarray(v), mode=mode) + ) + data = f(getdata(a), getdata(v), mode=mode) + else: + # results which are not contributed to by any pair of valid elements + mask = ~f(~getmaskarray(a), ~getmaskarray(v)) + data = f(filled(a, 0), filled(v, 0), mode=mode) + + return masked_array(data, mask=mask) + + +def correlate(a, v, mode='valid', propagate_mask=True): + """ + Cross-correlation of two 1-dimensional sequences. + + Parameters + ---------- + a, v : array_like + Input sequences. + mode : {'valid', 'same', 'full'}, optional + Refer to the `np.convolve` docstring. Note that the default + is 'valid', unlike `convolve`, which uses 'full'. + propagate_mask : bool + If True, then a result element is masked if any masked element contributes towards it. + If False, then a result element is only masked if no non-masked element + contribute towards it + + Returns + ------- + out : MaskedArray + Discrete cross-correlation of `a` and `v`. + + See Also + -------- + numpy.correlate : Equivalent function in the top-level NumPy module. + """ + return _convolve_or_correlate(np.correlate, a, v, mode, propagate_mask) + + +def convolve(a, v, mode='full', propagate_mask=True): + """ + Returns the discrete, linear convolution of two one-dimensional sequences. + + Parameters + ---------- + a, v : array_like + Input sequences. + mode : {'valid', 'same', 'full'}, optional + Refer to the `np.convolve` docstring. + propagate_mask : bool + If True, then if any masked element is included in the sum for a result + element, then the result is masked. + If False, then the result element is only masked if no non-masked cells + contribute towards it + + Returns + ------- + out : MaskedArray + Discrete, linear convolution of `a` and `v`. + + See Also + -------- + numpy.convolve : Equivalent function in the top-level NumPy module. + """ + return _convolve_or_correlate(np.convolve, a, v, mode, propagate_mask) + + +def allequal(a, b, fill_value=True): + """ + Return True if all entries of a and b are equal, using + fill_value as a truth value where either or both are masked. + + Parameters + ---------- + a, b : array_like + Input arrays to compare. + fill_value : bool, optional + Whether masked values in a or b are considered equal (True) or not + (False). + + Returns + ------- + y : bool + Returns True if the two arrays are equal within the given + tolerance, False otherwise. If either array contains NaN, + then False is returned. + + See Also + -------- + all, any + numpy.ma.allclose + + Examples + -------- + >>> a = ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1]) + >>> a + masked_array(data = [10000000000.0 1e-07 --], + mask = [False False True], + fill_value=1e+20) + + >>> b = array([1e10, 1e-7, -42.0]) + >>> b + array([ 1.00000000e+10, 1.00000000e-07, -4.20000000e+01]) + >>> ma.allequal(a, b, fill_value=False) + False + >>> ma.allequal(a, b) + True + + """ + m = mask_or(getmask(a), getmask(b)) + if m is nomask: + x = getdata(a) + y = getdata(b) + d = umath.equal(x, y) + return d.all() + elif fill_value: + x = getdata(a) + y = getdata(b) + d = umath.equal(x, y) + dm = array(d, mask=m, copy=False) + return dm.filled(True).all(None) + else: + return False + + +def allclose(a, b, masked_equal=True, rtol=1e-5, atol=1e-8): + """ + Returns True if two arrays are element-wise equal within a tolerance. + + This function is equivalent to `allclose` except that masked values + are treated as equal (default) or unequal, depending on the `masked_equal` + argument. + + Parameters + ---------- + a, b : array_like + Input arrays to compare. + masked_equal : bool, optional + Whether masked values in `a` and `b` are considered equal (True) or not + (False). They are considered equal by default. + rtol : float, optional + Relative tolerance. The relative difference is equal to ``rtol * b``. + Default is 1e-5. + atol : float, optional + Absolute tolerance. The absolute difference is equal to `atol`. + Default is 1e-8. + + Returns + ------- + y : bool + Returns True if the two arrays are equal within the given + tolerance, False otherwise. If either array contains NaN, then + False is returned. + + See Also + -------- + all, any + numpy.allclose : the non-masked `allclose`. + + Notes + ----- + If the following equation is element-wise True, then `allclose` returns + True:: + + absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`)) + + Return True if all elements of `a` and `b` are equal subject to + given tolerances. + + Examples + -------- + >>> a = ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1]) + >>> a + masked_array(data = [10000000000.0 1e-07 --], + mask = [False False True], + fill_value = 1e+20) + >>> b = ma.array([1e10, 1e-8, -42.0], mask=[0, 0, 1]) + >>> ma.allclose(a, b) + False + + >>> a = ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1]) + >>> b = ma.array([1.00001e10, 1e-9, -42.0], mask=[0, 0, 1]) + >>> ma.allclose(a, b) + True + >>> ma.allclose(a, b, masked_equal=False) + False + + Masked values are not compared directly. + + >>> a = ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1]) + >>> b = ma.array([1.00001e10, 1e-9, 42.0], mask=[0, 0, 1]) + >>> ma.allclose(a, b) + True + >>> ma.allclose(a, b, masked_equal=False) + False + + """ + x = masked_array(a, copy=False) + y = masked_array(b, copy=False) + + # make sure y is an inexact type to avoid abs(MIN_INT); will cause + # casting of x later. + dtype = np.result_type(y, 1.) + if y.dtype != dtype: + y = masked_array(y, dtype=dtype, copy=False) + + m = mask_or(getmask(x), getmask(y)) + xinf = np.isinf(masked_array(x, copy=False, mask=m)).filled(False) + # If we have some infs, they should fall at the same place. + if not np.all(xinf == filled(np.isinf(y), False)): + return False + # No infs at all + if not np.any(xinf): + d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)), + masked_equal) + return np.all(d) + + if not np.all(filled(x[xinf] == y[xinf], masked_equal)): + return False + x = x[~xinf] + y = y[~xinf] + + d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)), + masked_equal) + + return np.all(d) + + +def asarray(a, dtype=None, order=None): + """ + Convert the input to a masked array of the given data-type. + + No copy is performed if the input is already an `ndarray`. If `a` is + a subclass of `MaskedArray`, a base class `MaskedArray` is returned. + + Parameters + ---------- + a : array_like + Input data, in any form that can be converted to a masked array. This + includes lists, lists of tuples, tuples, tuples of tuples, tuples + of lists, ndarrays and masked arrays. + dtype : dtype, optional + By default, the data-type is inferred from the input data. + order : {'C', 'F'}, optional + Whether to use row-major ('C') or column-major ('FORTRAN') memory + representation. Default is 'C'. + + Returns + ------- + out : MaskedArray + Masked array interpretation of `a`. + + See Also + -------- + asanyarray : Similar to `asarray`, but conserves subclasses. + + Examples + -------- + >>> x = np.arange(10.).reshape(2, 5) + >>> x + array([[ 0., 1., 2., 3., 4.], + [ 5., 6., 7., 8., 9.]]) + >>> np.ma.asarray(x) + masked_array(data = + [[ 0. 1. 2. 3. 4.] + [ 5. 6. 7. 8. 9.]], + mask = + False, + fill_value = 1e+20) + >>> type(np.ma.asarray(x)) + + + """ + order = order or 'C' + return masked_array(a, dtype=dtype, copy=False, keep_mask=True, + subok=False, order=order) + + +def asanyarray(a, dtype=None): + """ + Convert the input to a masked array, conserving subclasses. + + If `a` is a subclass of `MaskedArray`, its class is conserved. + No copy is performed if the input is already an `ndarray`. + + Parameters + ---------- + a : array_like + Input data, in any form that can be converted to an array. + dtype : dtype, optional + By default, the data-type is inferred from the input data. + order : {'C', 'F'}, optional + Whether to use row-major ('C') or column-major ('FORTRAN') memory + representation. Default is 'C'. + + Returns + ------- + out : MaskedArray + MaskedArray interpretation of `a`. + + See Also + -------- + asarray : Similar to `asanyarray`, but does not conserve subclass. + + Examples + -------- + >>> x = np.arange(10.).reshape(2, 5) + >>> x + array([[ 0., 1., 2., 3., 4.], + [ 5., 6., 7., 8., 9.]]) + >>> np.ma.asanyarray(x) + masked_array(data = + [[ 0. 1. 2. 3. 4.] + [ 5. 6. 7. 8. 9.]], + mask = + False, + fill_value = 1e+20) + >>> type(np.ma.asanyarray(x)) + + + """ + # workaround for #8666, to preserve identity. Ideally the bottom line + # would handle this for us. + if isinstance(a, MaskedArray) and (dtype is None or dtype == a.dtype): + return a + return masked_array(a, dtype=dtype, copy=False, keep_mask=True, subok=True) + + +############################################################################## +# Pickling # +############################################################################## +def dump(a, F): + """ + Pickle a masked array to a file. + + This is a wrapper around ``cPickle.dump``. + + Parameters + ---------- + a : MaskedArray + The array to be pickled. + F : str or file-like object + The file to pickle `a` to. If a string, the full path to the file. + + """ + if not hasattr(F, 'readline'): + with open(F, 'w') as F: + pickle.dump(a, F) + else: + pickle.dump(a, F) + + +def dumps(a): + """ + Return a string corresponding to the pickling of a masked array. + + This is a wrapper around ``cPickle.dumps``. + + Parameters + ---------- + a : MaskedArray + The array for which the string representation of the pickle is + returned. + + """ + return pickle.dumps(a) + + +def load(F): + """ + Wrapper around ``cPickle.load`` which accepts either a file-like object + or a filename. + + Parameters + ---------- + F : str or file + The file or file name to load. + + See Also + -------- + dump : Pickle an array + + Notes + ----- + This is different from `numpy.load`, which does not use cPickle but loads + the NumPy binary .npy format. + + """ + if not hasattr(F, 'readline'): + with open(F, 'r') as F: + return pickle.load(F) + else: + return pickle.load(F) + + +def loads(strg): + """ + Load a pickle from the current string. + + The result of ``cPickle.loads(strg)`` is returned. + + Parameters + ---------- + strg : str + The string to load. + + See Also + -------- + dumps : Return a string corresponding to the pickling of a masked array. + + """ + return pickle.loads(strg) + + +def fromfile(file, dtype=float, count=-1, sep=''): + raise NotImplementedError( + "fromfile() not yet implemented for a MaskedArray.") + + +def fromflex(fxarray): + """ + Build a masked array from a suitable flexible-type array. + + The input array has to have a data-type with ``_data`` and ``_mask`` + fields. This type of array is output by `MaskedArray.toflex`. + + Parameters + ---------- + fxarray : ndarray + The structured input array, containing ``_data`` and ``_mask`` + fields. If present, other fields are discarded. + + Returns + ------- + result : MaskedArray + The constructed masked array. + + See Also + -------- + MaskedArray.toflex : Build a flexible-type array from a masked array. + + Examples + -------- + >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[0] + [1, 0] * 4) + >>> rec = x.toflex() + >>> rec + array([[(0, False), (1, True), (2, False)], + [(3, True), (4, False), (5, True)], + [(6, False), (7, True), (8, False)]], + dtype=[('_data', '>> x2 = np.ma.fromflex(rec) + >>> x2 + masked_array(data = + [[0 -- 2] + [-- 4 --] + [6 -- 8]], + mask = + [[False True False] + [ True False True] + [False True False]], + fill_value = 999999) + + Extra fields can be present in the structured array but are discarded: + + >>> dt = [('_data', '>> rec2 = np.zeros((2, 2), dtype=dt) + >>> rec2 + array([[(0, False, 0.0), (0, False, 0.0)], + [(0, False, 0.0), (0, False, 0.0)]], + dtype=[('_data', '>> y = np.ma.fromflex(rec2) + >>> y + masked_array(data = + [[0 0] + [0 0]], + mask = + [[False False] + [False False]], + fill_value = 999999) + + """ + return masked_array(fxarray['_data'], mask=fxarray['_mask']) + + +class _convert2ma(object): + + """ + Convert functions from numpy to numpy.ma. + + Parameters + ---------- + _methodname : string + Name of the method to transform. + + """ + __doc__ = None + + def __init__(self, funcname, params=None): + self._func = getattr(np, funcname) + self.__doc__ = self.getdoc() + self._extras = params or {} + + def getdoc(self): + "Return the doc of the function (from the doc of the method)." + doc = getattr(self._func, '__doc__', None) + sig = get_object_signature(self._func) + if doc: + # Add the signature of the function at the beginning of the doc + if sig: + sig = "%s%s\n" % (self._func.__name__, sig) + doc = sig + doc + return doc + + def __call__(self, *args, **params): + # Find the common parameters to the call and the definition + _extras = self._extras + common_params = set(params).intersection(_extras) + # Drop the common parameters from the call + for p in common_params: + _extras[p] = params.pop(p) + # Get the result + result = self._func.__call__(*args, **params).view(MaskedArray) + if "fill_value" in common_params: + result.fill_value = _extras.get("fill_value", None) + if "hardmask" in common_params: + result._hardmask = bool(_extras.get("hard_mask", False)) + return result + +arange = _convert2ma('arange', params=dict(fill_value=None, hardmask=False)) +clip = np.clip +diff = np.diff +empty = _convert2ma('empty', params=dict(fill_value=None, hardmask=False)) +empty_like = _convert2ma('empty_like') +frombuffer = _convert2ma('frombuffer') +fromfunction = _convert2ma('fromfunction') +identity = _convert2ma( + 'identity', params=dict(fill_value=None, hardmask=False)) +indices = np.indices +ones = _convert2ma('ones', params=dict(fill_value=None, hardmask=False)) +ones_like = np.ones_like +squeeze = np.squeeze +zeros = _convert2ma('zeros', params=dict(fill_value=None, hardmask=False)) +zeros_like = np.zeros_like + + +def append(a, b, axis=None): + """Append values to the end of an array. + + .. versionadded:: 1.9.0 + + Parameters + ---------- + a : array_like + Values are appended to a copy of this array. + b : array_like + These values are appended to a copy of `a`. It must be of the + correct shape (the same shape as `a`, excluding `axis`). If `axis` + is not specified, `b` can be any shape and will be flattened + before use. + axis : int, optional + The axis along which `v` are appended. If `axis` is not given, + both `a` and `b` are flattened before use. + + Returns + ------- + append : MaskedArray + A copy of `a` with `b` appended to `axis`. Note that `append` + does not occur in-place: a new array is allocated and filled. If + `axis` is None, the result is a flattened array. + + See Also + -------- + numpy.append : Equivalent function in the top-level NumPy module. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = ma.masked_values([1, 2, 3], 2) + >>> b = ma.masked_values([[4, 5, 6], [7, 8, 9]], 7) + >>> print(ma.append(a, b)) + [1 -- 3 4 5 6 -- 8 9] + """ + return concatenate([a, b], axis) diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py new file mode 100644 index 0000000..8f98e12 --- /dev/null +++ b/numpy/ma/extras.py @@ -0,0 +1,1882 @@ +""" +Masked arrays add-ons. + +A collection of utilities for `numpy.ma`. + +:author: Pierre Gerard-Marchant +:contact: pierregm_at_uga_dot_edu +:version: $Id: extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $ + +""" +from __future__ import division, absolute_import, print_function + +__all__ = [ + 'apply_along_axis', 'apply_over_axes', 'atleast_1d', 'atleast_2d', + 'atleast_3d', 'average', 'clump_masked', 'clump_unmasked', + 'column_stack', 'compress_cols', 'compress_nd', 'compress_rowcols', + 'compress_rows', 'count_masked', 'corrcoef', 'cov', 'diagflat', 'dot', + 'dstack', 'ediff1d', 'flatnotmasked_contiguous', 'flatnotmasked_edges', + 'hsplit', 'hstack', 'isin', 'in1d', 'intersect1d', 'mask_cols', 'mask_rowcols', + 'mask_rows', 'masked_all', 'masked_all_like', 'median', 'mr_', + 'notmasked_contiguous', 'notmasked_edges', 'polyfit', 'row_stack', + 'setdiff1d', 'setxor1d', 'unique', 'union1d', 'vander', 'vstack', + ] + +import itertools +import warnings + +from . import core as ma +from .core import ( + MaskedArray, MAError, add, array, asarray, concatenate, filled, count, + getmask, getmaskarray, make_mask_descr, masked, masked_array, mask_or, + nomask, ones, sort, zeros, getdata, get_masked_subclass, dot, + mask_rowcols + ) + +import numpy as np +from numpy import ndarray, array as nxarray +import numpy.core.umath as umath +from numpy.core.multiarray import normalize_axis_index +from numpy.core.numeric import normalize_axis_tuple +from numpy.lib.function_base import _ureduce +from numpy.lib.index_tricks import AxisConcatenator + + +def issequence(seq): + """ + Is seq a sequence (ndarray, list or tuple)? + + """ + return isinstance(seq, (ndarray, tuple, list)) + + +def count_masked(arr, axis=None): + """ + Count the number of masked elements along the given axis. + + Parameters + ---------- + arr : array_like + An array with (possibly) masked elements. + axis : int, optional + Axis along which to count. If None (default), a flattened + version of the array is used. + + Returns + ------- + count : int, ndarray + The total number of masked elements (axis=None) or the number + of masked elements along each slice of the given axis. + + See Also + -------- + MaskedArray.count : Count non-masked elements. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.arange(9).reshape((3,3)) + >>> a = ma.array(a) + >>> a[1, 0] = ma.masked + >>> a[1, 2] = ma.masked + >>> a[2, 1] = ma.masked + >>> a + masked_array(data = + [[0 1 2] + [-- 4 --] + [6 -- 8]], + mask = + [[False False False] + [ True False True] + [False True False]], + fill_value=999999) + >>> ma.count_masked(a) + 3 + + When the `axis` keyword is used an array is returned. + + >>> ma.count_masked(a, axis=0) + array([1, 1, 1]) + >>> ma.count_masked(a, axis=1) + array([0, 2, 1]) + + """ + m = getmaskarray(arr) + return m.sum(axis) + + +def masked_all(shape, dtype=float): + """ + Empty masked array with all elements masked. + + Return an empty masked array of the given shape and dtype, where all the + data are masked. + + Parameters + ---------- + shape : tuple + Shape of the required MaskedArray. + dtype : dtype, optional + Data type of the output. + + Returns + ------- + a : MaskedArray + A masked array with all data masked. + + See Also + -------- + masked_all_like : Empty masked array modelled on an existing array. + + Examples + -------- + >>> import numpy.ma as ma + >>> ma.masked_all((3, 3)) + masked_array(data = + [[-- -- --] + [-- -- --] + [-- -- --]], + mask = + [[ True True True] + [ True True True] + [ True True True]], + fill_value=1e+20) + + The `dtype` parameter defines the underlying data type. + + >>> a = ma.masked_all((3, 3)) + >>> a.dtype + dtype('float64') + >>> a = ma.masked_all((3, 3), dtype=np.int32) + >>> a.dtype + dtype('int32') + + """ + a = masked_array(np.empty(shape, dtype), + mask=np.ones(shape, make_mask_descr(dtype))) + return a + + +def masked_all_like(arr): + """ + Empty masked array with the properties of an existing array. + + Return an empty masked array of the same shape and dtype as + the array `arr`, where all the data are masked. + + Parameters + ---------- + arr : ndarray + An array describing the shape and dtype of the required MaskedArray. + + Returns + ------- + a : MaskedArray + A masked array with all data masked. + + Raises + ------ + AttributeError + If `arr` doesn't have a shape attribute (i.e. not an ndarray) + + See Also + -------- + masked_all : Empty masked array with all elements masked. + + Examples + -------- + >>> import numpy.ma as ma + >>> arr = np.zeros((2, 3), dtype=np.float32) + >>> arr + array([[ 0., 0., 0.], + [ 0., 0., 0.]], dtype=float32) + >>> ma.masked_all_like(arr) + masked_array(data = + [[-- -- --] + [-- -- --]], + mask = + [[ True True True] + [ True True True]], + fill_value=1e+20) + + The dtype of the masked array matches the dtype of `arr`. + + >>> arr.dtype + dtype('float32') + >>> ma.masked_all_like(arr).dtype + dtype('float32') + + """ + a = np.empty_like(arr).view(MaskedArray) + a._mask = np.ones(a.shape, dtype=make_mask_descr(a.dtype)) + return a + + +#####-------------------------------------------------------------------------- +#---- --- Standard functions --- +#####-------------------------------------------------------------------------- +class _fromnxfunction(object): + """ + Defines a wrapper to adapt NumPy functions to masked arrays. + + + An instance of `_fromnxfunction` can be called with the same parameters + as the wrapped NumPy function. The docstring of `newfunc` is adapted from + the wrapped function as well, see `getdoc`. + + This class should not be used directly. Instead, one of its extensions that + provides support for a specific type of input should be used. + + Parameters + ---------- + funcname : str + The name of the function to be adapted. The function should be + in the NumPy namespace (i.e. ``np.funcname``). + + """ + + def __init__(self, funcname): + self.__name__ = funcname + self.__doc__ = self.getdoc() + + def getdoc(self): + """ + Retrieve the docstring and signature from the function. + + The ``__doc__`` attribute of the function is used as the docstring for + the new masked array version of the function. A note on application + of the function to the mask is appended. + + .. warning:: + If the function docstring already contained a Notes section, the + new docstring will have two Notes sections instead of appending a note + to the existing section. + + Parameters + ---------- + None + + """ + npfunc = getattr(np, self.__name__, None) + doc = getattr(npfunc, '__doc__', None) + if doc: + sig = self.__name__ + ma.get_object_signature(npfunc) + locdoc = "Notes\n-----\nThe function is applied to both the _data"\ + " and the _mask, if any." + return '\n'.join((sig, doc, locdoc)) + return + + def __call__(self, *args, **params): + pass + + +class _fromnxfunction_single(_fromnxfunction): + """ + A version of `_fromnxfunction` that is called with a single array + argument followed by auxiliary args that are passed verbatim for + both the data and mask calls. + """ + def __call__(self, x, *args, **params): + func = getattr(np, self.__name__) + if isinstance(x, ndarray): + _d = func(x.__array__(), *args, **params) + _m = func(getmaskarray(x), *args, **params) + return masked_array(_d, mask=_m) + else: + _d = func(np.asarray(x), *args, **params) + _m = func(getmaskarray(x), *args, **params) + return masked_array(_d, mask=_m) + + +class _fromnxfunction_seq(_fromnxfunction): + """ + A version of `_fromnxfunction` that is called with a single sequence + of arrays followed by auxiliary args that are passed verbatim for + both the data and mask calls. + """ + def __call__(self, x, *args, **params): + func = getattr(np, self.__name__) + _d = func(tuple([np.asarray(a) for a in x]), *args, **params) + _m = func(tuple([getmaskarray(a) for a in x]), *args, **params) + return masked_array(_d, mask=_m) + + +class _fromnxfunction_args(_fromnxfunction): + """ + A version of `_fromnxfunction` that is called with multiple array + arguments. The first non-array-like input marks the beginning of the + arguments that are passed verbatim for both the data and mask calls. + Array arguments are processed independently and the results are + returned in a list. If only one array is found, the return value is + just the processed array instead of a list. + """ + def __call__(self, *args, **params): + func = getattr(np, self.__name__) + arrays = [] + args = list(args) + while len(args) > 0 and issequence(args[0]): + arrays.append(args.pop(0)) + res = [] + for x in arrays: + _d = func(np.asarray(x), *args, **params) + _m = func(getmaskarray(x), *args, **params) + res.append(masked_array(_d, mask=_m)) + if len(arrays) == 1: + return res[0] + return res + + +class _fromnxfunction_allargs(_fromnxfunction): + """ + A version of `_fromnxfunction` that is called with multiple array + arguments. Similar to `_fromnxfunction_args` except that all args + are converted to arrays even if they are not so already. This makes + it possible to process scalars as 1-D arrays. Only keyword arguments + are passed through verbatim for the data and mask calls. Arrays + arguments are processed independently and the results are returned + in a list. If only one arg is present, the return value is just the + processed array instead of a list. + """ + def __call__(self, *args, **params): + func = getattr(np, self.__name__) + res = [] + for x in args: + _d = func(np.asarray(x), **params) + _m = func(getmaskarray(x), **params) + res.append(masked_array(_d, mask=_m)) + if len(args) == 1: + return res[0] + return res + + +atleast_1d = _fromnxfunction_allargs('atleast_1d') +atleast_2d = _fromnxfunction_allargs('atleast_2d') +atleast_3d = _fromnxfunction_allargs('atleast_3d') + +vstack = row_stack = _fromnxfunction_seq('vstack') +hstack = _fromnxfunction_seq('hstack') +column_stack = _fromnxfunction_seq('column_stack') +dstack = _fromnxfunction_seq('dstack') + +hsplit = _fromnxfunction_single('hsplit') + +diagflat = _fromnxfunction_single('diagflat') + + +#####-------------------------------------------------------------------------- +#---- +#####-------------------------------------------------------------------------- +def flatten_inplace(seq): + """Flatten a sequence in place.""" + k = 0 + while (k != len(seq)): + while hasattr(seq[k], '__iter__'): + seq[k:(k + 1)] = seq[k] + k += 1 + return seq + + +def apply_along_axis(func1d, axis, arr, *args, **kwargs): + """ + (This docstring should be overwritten) + """ + arr = array(arr, copy=False, subok=True) + nd = arr.ndim + axis = normalize_axis_index(axis, nd) + ind = [0] * (nd - 1) + i = np.zeros(nd, 'O') + indlist = list(range(nd)) + indlist.remove(axis) + i[axis] = slice(None, None) + outshape = np.asarray(arr.shape).take(indlist) + i.put(indlist, ind) + j = i.copy() + res = func1d(arr[tuple(i.tolist())], *args, **kwargs) + # if res is a number, then we have a smaller output array + asscalar = np.isscalar(res) + if not asscalar: + try: + len(res) + except TypeError: + asscalar = True + # Note: we shouldn't set the dtype of the output from the first result + # so we force the type to object, and build a list of dtypes. We'll + # just take the largest, to avoid some downcasting + dtypes = [] + if asscalar: + dtypes.append(np.asarray(res).dtype) + outarr = zeros(outshape, object) + outarr[tuple(ind)] = res + Ntot = np.product(outshape) + k = 1 + while k < Ntot: + # increment the index + ind[-1] += 1 + n = -1 + while (ind[n] >= outshape[n]) and (n > (1 - nd)): + ind[n - 1] += 1 + ind[n] = 0 + n -= 1 + i.put(indlist, ind) + res = func1d(arr[tuple(i.tolist())], *args, **kwargs) + outarr[tuple(ind)] = res + dtypes.append(asarray(res).dtype) + k += 1 + else: + res = array(res, copy=False, subok=True) + j = i.copy() + j[axis] = ([slice(None, None)] * res.ndim) + j.put(indlist, ind) + Ntot = np.product(outshape) + holdshape = outshape + outshape = list(arr.shape) + outshape[axis] = res.shape + dtypes.append(asarray(res).dtype) + outshape = flatten_inplace(outshape) + outarr = zeros(outshape, object) + outarr[tuple(flatten_inplace(j.tolist()))] = res + k = 1 + while k < Ntot: + # increment the index + ind[-1] += 1 + n = -1 + while (ind[n] >= holdshape[n]) and (n > (1 - nd)): + ind[n - 1] += 1 + ind[n] = 0 + n -= 1 + i.put(indlist, ind) + j.put(indlist, ind) + res = func1d(arr[tuple(i.tolist())], *args, **kwargs) + outarr[tuple(flatten_inplace(j.tolist()))] = res + dtypes.append(asarray(res).dtype) + k += 1 + max_dtypes = np.dtype(np.asarray(dtypes).max()) + if not hasattr(arr, '_mask'): + result = np.asarray(outarr, dtype=max_dtypes) + else: + result = asarray(outarr, dtype=max_dtypes) + result.fill_value = ma.default_fill_value(result) + return result +apply_along_axis.__doc__ = np.apply_along_axis.__doc__ + + +def apply_over_axes(func, a, axes): + """ + (This docstring will be overwritten) + """ + val = asarray(a) + N = a.ndim + if array(axes).ndim == 0: + axes = (axes,) + for axis in axes: + if axis < 0: + axis = N + axis + args = (val, axis) + res = func(*args) + if res.ndim == val.ndim: + val = res + else: + res = ma.expand_dims(res, axis) + if res.ndim == val.ndim: + val = res + else: + raise ValueError("function is not returning " + "an array of the correct shape") + return val + +if apply_over_axes.__doc__ is not None: + apply_over_axes.__doc__ = np.apply_over_axes.__doc__[ + :np.apply_over_axes.__doc__.find('Notes')].rstrip() + \ + """ + + Examples + -------- + >>> a = ma.arange(24).reshape(2,3,4) + >>> a[:,0,1] = ma.masked + >>> a[:,1,:] = ma.masked + >>> print(a) + [[[0 -- 2 3] + [-- -- -- --] + [8 9 10 11]] + + [[12 -- 14 15] + [-- -- -- --] + [20 21 22 23]]] + >>> print(ma.apply_over_axes(ma.sum, a, [0,2])) + [[[46] + [--] + [124]]] + + Tuple axis arguments to ufuncs are equivalent: + + >>> print(ma.sum(a, axis=(0,2)).reshape((1,-1,1))) + [[[46] + [--] + [124]]] + """ + + +def average(a, axis=None, weights=None, returned=False): + """ + Return the weighted average of array over the given axis. + + Parameters + ---------- + a : array_like + Data to be averaged. + Masked entries are not taken into account in the computation. + axis : int, optional + Axis along which to average `a`. If `None`, averaging is done over + the flattened array. + weights : array_like, optional + The importance that each element has in the computation of the average. + The weights array can either be 1-D (in which case its length must be + the size of `a` along the given axis) or of the same shape as `a`. + If ``weights=None``, then all data in `a` are assumed to have a + weight equal to one. If `weights` is complex, the imaginary parts + are ignored. + returned : bool, optional + Flag indicating whether a tuple ``(result, sum of weights)`` + should be returned as output (True), or just the result (False). + Default is False. + + Returns + ------- + average, [sum_of_weights] : (tuple of) scalar or MaskedArray + The average along the specified axis. When returned is `True`, + return a tuple with the average as the first element and the sum + of the weights as the second element. The return type is `np.float64` + if `a` is of integer type and floats smaller than `float64`, or the + input data-type, otherwise. If returned, `sum_of_weights` is always + `float64`. + + Examples + -------- + >>> a = np.ma.array([1., 2., 3., 4.], mask=[False, False, True, True]) + >>> np.ma.average(a, weights=[3, 1, 0, 0]) + 1.25 + + >>> x = np.ma.arange(6.).reshape(3, 2) + >>> print(x) + [[ 0. 1.] + [ 2. 3.] + [ 4. 5.]] + >>> avg, sumweights = np.ma.average(x, axis=0, weights=[1, 2, 3], + ... returned=True) + >>> print(avg) + [2.66666666667 3.66666666667] + + """ + a = asarray(a) + m = getmask(a) + + # inspired by 'average' in numpy/lib/function_base.py + + if weights is None: + avg = a.mean(axis) + scl = avg.dtype.type(a.count(axis)) + else: + wgt = np.asanyarray(weights) + + if issubclass(a.dtype.type, (np.integer, np.bool_)): + result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8') + else: + result_dtype = np.result_type(a.dtype, wgt.dtype) + + # Sanity checks + if a.shape != wgt.shape: + if axis is None: + raise TypeError( + "Axis must be specified when shapes of a and weights " + "differ.") + if wgt.ndim != 1: + raise TypeError( + "1D weights expected when shapes of a and weights differ.") + if wgt.shape[0] != a.shape[axis]: + raise ValueError( + "Length of weights not compatible with specified axis.") + + # setup wgt to broadcast along axis + wgt = np.broadcast_to(wgt, (a.ndim-1)*(1,) + wgt.shape) + wgt = wgt.swapaxes(-1, axis) + + if m is not nomask: + wgt = wgt*(~a.mask) + + scl = wgt.sum(axis=axis, dtype=result_dtype) + avg = np.multiply(a, wgt, dtype=result_dtype).sum(axis)/scl + + if returned: + if scl.shape != avg.shape: + scl = np.broadcast_to(scl, avg.shape).copy() + return avg, scl + else: + return avg + + +def median(a, axis=None, out=None, overwrite_input=False, keepdims=False): + """ + Compute the median along the specified axis. + + Returns the median of the array elements. + + Parameters + ---------- + a : array_like + Input array or object that can be converted to an array. + axis : int, optional + Axis along which the medians are computed. The default (None) is + to compute the median along a flattened version of the array. + out : ndarray, optional + Alternative output array in which to place the result. It must + have the same shape and buffer length as the expected output + but the type will be cast if necessary. + overwrite_input : bool, optional + If True, then allow use of memory of input array (a) for + calculations. The input array will be modified by the call to + median. This will save memory when you do not need to preserve + the contents of the input array. Treat the input as undefined, + but it will probably be fully or partially sorted. Default is + False. Note that, if `overwrite_input` is True, and the input + is not already an `ndarray`, an error will be raised. + keepdims : bool, optional + If this is set to True, the axes which are reduced are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + .. versionadded:: 1.10.0 + + Returns + ------- + median : ndarray + A new array holding the result is returned unless out is + specified, in which case a reference to out is returned. + Return data-type is `float64` for integers and floats smaller than + `float64`, or the input data-type, otherwise. + + See Also + -------- + mean + + Notes + ----- + Given a vector ``V`` with ``N`` non masked values, the median of ``V`` + is the middle value of a sorted copy of ``V`` (``Vs``) - i.e. + ``Vs[(N-1)/2]``, when ``N`` is odd, or ``{Vs[N/2 - 1] + Vs[N/2]}/2`` + when ``N`` is even. + + Examples + -------- + >>> x = np.ma.array(np.arange(8), mask=[0]*4 + [1]*4) + >>> np.ma.median(x) + 1.5 + + >>> x = np.ma.array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4) + >>> np.ma.median(x) + 2.5 + >>> np.ma.median(x, axis=-1, overwrite_input=True) + masked_array(data = [ 2. 5.], + mask = False, + fill_value = 1e+20) + + """ + if not hasattr(a, 'mask'): + m = np.median(getdata(a, subok=True), axis=axis, + out=out, overwrite_input=overwrite_input, + keepdims=keepdims) + if isinstance(m, np.ndarray) and 1 <= m.ndim: + return masked_array(m, copy=False) + else: + return m + + r, k = _ureduce(a, func=_median, axis=axis, out=out, + overwrite_input=overwrite_input) + if keepdims: + return r.reshape(k) + else: + return r + +def _median(a, axis=None, out=None, overwrite_input=False): + # when an unmasked NaN is present return it, so we need to sort the NaN + # values behind the mask + if np.issubdtype(a.dtype, np.inexact): + fill_value = np.inf + else: + fill_value = None + if overwrite_input: + if axis is None: + asorted = a.ravel() + asorted.sort(fill_value=fill_value) + else: + a.sort(axis=axis, fill_value=fill_value) + asorted = a + else: + asorted = sort(a, axis=axis, fill_value=fill_value) + + if axis is None: + axis = 0 + else: + axis = normalize_axis_index(axis, asorted.ndim) + + if asorted.shape[axis] == 0: + # for empty axis integer indices fail so use slicing to get same result + # as median (which is mean of empty slice = nan) + indexer = [slice(None)] * asorted.ndim + indexer[axis] = slice(0, 0) + return np.ma.mean(asorted[indexer], axis=axis, out=out) + + if asorted.ndim == 1: + counts = count(asorted) + idx, odd = divmod(count(asorted), 2) + mid = asorted[idx + odd - 1:idx + 1] + if np.issubdtype(asorted.dtype, np.inexact) and asorted.size > 0: + # avoid inf / x = masked + s = mid.sum(out=out) + if not odd: + s = np.true_divide(s, 2., casting='safe', out=out) + s = np.lib.utils._median_nancheck(asorted, s, axis, out) + else: + s = mid.mean(out=out) + + # if result is masked either the input contained enough + # minimum_fill_value so that it would be the median or all values + # masked + if np.ma.is_masked(s) and not np.all(asorted.mask): + return np.ma.minimum_fill_value(asorted) + return s + + counts = count(asorted, axis=axis) + h = counts // 2 + + # create indexing mesh grid for all but reduced axis + axes_grid = [np.arange(x) for i, x in enumerate(asorted.shape) + if i != axis] + ind = np.meshgrid(*axes_grid, sparse=True, indexing='ij') + + # insert indices of low and high median + ind.insert(axis, h - 1) + low = asorted[tuple(ind)] + ind[axis] = np.minimum(h, asorted.shape[axis] - 1) + high = asorted[tuple(ind)] + + def replace_masked(s): + # Replace masked entries with minimum_full_value unless it all values + # are masked. This is required as the sort order of values equal or + # larger than the fill value is undefined and a valid value placed + # elsewhere, e.g. [4, --, inf]. + if np.ma.is_masked(s): + rep = (~np.all(asorted.mask, axis=axis)) & s.mask + s.data[rep] = np.ma.minimum_fill_value(asorted) + s.mask[rep] = False + + replace_masked(low) + replace_masked(high) + + # duplicate high if odd number of elements so mean does nothing + odd = counts % 2 == 1 + np.copyto(low, high, where=odd) + # not necessary for scalar True/False masks + try: + np.copyto(low.mask, high.mask, where=odd) + except Exception: + pass + + if np.issubdtype(asorted.dtype, np.inexact): + # avoid inf / x = masked + s = np.ma.sum([low, high], axis=0, out=out) + np.true_divide(s.data, 2., casting='unsafe', out=s.data) + + s = np.lib.utils._median_nancheck(asorted, s, axis, out) + else: + s = np.ma.mean([low, high], axis=0, out=out) + + return s + + +def compress_nd(x, axis=None): + """Suppress slices from multiple dimensions which contain masked values. + + Parameters + ---------- + x : array_like, MaskedArray + The array to operate on. If not a MaskedArray instance (or if no array + elements are masked, `x` is interpreted as a MaskedArray with `mask` + set to `nomask`. + axis : tuple of ints or int, optional + Which dimensions to suppress slices from can be configured with this + parameter. + - If axis is a tuple of ints, those are the axes to suppress slices from. + - If axis is an int, then that is the only axis to suppress slices from. + - If axis is None, all axis are selected. + + Returns + ------- + compress_array : ndarray + The compressed array. + """ + x = asarray(x) + m = getmask(x) + # Set axis to tuple of ints + if axis is None: + axis = tuple(range(x.ndim)) + else: + axis = normalize_axis_tuple(axis, x.ndim) + + # Nothing is masked: return x + if m is nomask or not m.any(): + return x._data + # All is masked: return empty + if m.all(): + return nxarray([]) + # Filter elements through boolean indexing + data = x._data + for ax in axis: + axes = tuple(list(range(ax)) + list(range(ax + 1, x.ndim))) + data = data[(slice(None),)*ax + (~m.any(axis=axes),)] + return data + +def compress_rowcols(x, axis=None): + """ + Suppress the rows and/or columns of a 2-D array that contain + masked values. + + The suppression behavior is selected with the `axis` parameter. + + - If axis is None, both rows and columns are suppressed. + - If axis is 0, only rows are suppressed. + - If axis is 1 or -1, only columns are suppressed. + + Parameters + ---------- + x : array_like, MaskedArray + The array to operate on. If not a MaskedArray instance (or if no array + elements are masked), `x` is interpreted as a MaskedArray with + `mask` set to `nomask`. Must be a 2D array. + axis : int, optional + Axis along which to perform the operation. Default is None. + + Returns + ------- + compressed_array : ndarray + The compressed array. + + Examples + -------- + >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0], + ... [1, 0, 0], + ... [0, 0, 0]]) + >>> x + masked_array(data = + [[-- 1 2] + [-- 4 5] + [6 7 8]], + mask = + [[ True False False] + [ True False False] + [False False False]], + fill_value = 999999) + + >>> np.ma.compress_rowcols(x) + array([[7, 8]]) + >>> np.ma.compress_rowcols(x, 0) + array([[6, 7, 8]]) + >>> np.ma.compress_rowcols(x, 1) + array([[1, 2], + [4, 5], + [7, 8]]) + + """ + if asarray(x).ndim != 2: + raise NotImplementedError("compress_rowcols works for 2D arrays only.") + return compress_nd(x, axis=axis) + + +def compress_rows(a): + """ + Suppress whole rows of a 2-D array that contain masked values. + + This is equivalent to ``np.ma.compress_rowcols(a, 0)``, see + `extras.compress_rowcols` for details. + + See Also + -------- + extras.compress_rowcols + + """ + a = asarray(a) + if a.ndim != 2: + raise NotImplementedError("compress_rows works for 2D arrays only.") + return compress_rowcols(a, 0) + +def compress_cols(a): + """ + Suppress whole columns of a 2-D array that contain masked values. + + This is equivalent to ``np.ma.compress_rowcols(a, 1)``, see + `extras.compress_rowcols` for details. + + See Also + -------- + extras.compress_rowcols + + """ + a = asarray(a) + if a.ndim != 2: + raise NotImplementedError("compress_cols works for 2D arrays only.") + return compress_rowcols(a, 1) + +def mask_rows(a, axis=None): + """ + Mask rows of a 2D array that contain masked values. + + This function is a shortcut to ``mask_rowcols`` with `axis` equal to 0. + + See Also + -------- + mask_rowcols : Mask rows and/or columns of a 2D array. + masked_where : Mask where a condition is met. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.zeros((3, 3), dtype=int) + >>> a[1, 1] = 1 + >>> a + array([[0, 0, 0], + [0, 1, 0], + [0, 0, 0]]) + >>> a = ma.masked_equal(a, 1) + >>> a + masked_array(data = + [[0 0 0] + [0 -- 0] + [0 0 0]], + mask = + [[False False False] + [False True False] + [False False False]], + fill_value=999999) + >>> ma.mask_rows(a) + masked_array(data = + [[0 0 0] + [-- -- --] + [0 0 0]], + mask = + [[False False False] + [ True True True] + [False False False]], + fill_value=999999) + + """ + return mask_rowcols(a, 0) + +def mask_cols(a, axis=None): + """ + Mask columns of a 2D array that contain masked values. + + This function is a shortcut to ``mask_rowcols`` with `axis` equal to 1. + + See Also + -------- + mask_rowcols : Mask rows and/or columns of a 2D array. + masked_where : Mask where a condition is met. + + Examples + -------- + >>> import numpy.ma as ma + >>> a = np.zeros((3, 3), dtype=int) + >>> a[1, 1] = 1 + >>> a + array([[0, 0, 0], + [0, 1, 0], + [0, 0, 0]]) + >>> a = ma.masked_equal(a, 1) + >>> a + masked_array(data = + [[0 0 0] + [0 -- 0] + [0 0 0]], + mask = + [[False False False] + [False True False] + [False False False]], + fill_value=999999) + >>> ma.mask_cols(a) + masked_array(data = + [[0 -- 0] + [0 -- 0] + [0 -- 0]], + mask = + [[False True False] + [False True False] + [False True False]], + fill_value=999999) + + """ + return mask_rowcols(a, 1) + + +#####-------------------------------------------------------------------------- +#---- --- arraysetops --- +#####-------------------------------------------------------------------------- + +def ediff1d(arr, to_end=None, to_begin=None): + """ + Compute the differences between consecutive elements of an array. + + This function is the equivalent of `numpy.ediff1d` that takes masked + values into account, see `numpy.ediff1d` for details. + + See Also + -------- + numpy.ediff1d : Equivalent function for ndarrays. + + """ + arr = ma.asanyarray(arr).flat + ed = arr[1:] - arr[:-1] + arrays = [ed] + # + if to_begin is not None: + arrays.insert(0, to_begin) + if to_end is not None: + arrays.append(to_end) + # + if len(arrays) != 1: + # We'll save ourselves a copy of a potentially large array in the common + # case where neither to_begin or to_end was given. + ed = hstack(arrays) + # + return ed + + +def unique(ar1, return_index=False, return_inverse=False): + """ + Finds the unique elements of an array. + + Masked values are considered the same element (masked). The output array + is always a masked array. See `numpy.unique` for more details. + + See Also + -------- + numpy.unique : Equivalent function for ndarrays. + + """ + output = np.unique(ar1, + return_index=return_index, + return_inverse=return_inverse) + if isinstance(output, tuple): + output = list(output) + output[0] = output[0].view(MaskedArray) + output = tuple(output) + else: + output = output.view(MaskedArray) + return output + + +def intersect1d(ar1, ar2, assume_unique=False): + """ + Returns the unique elements common to both arrays. + + Masked values are considered equal one to the other. + The output is always a masked array. + + See `numpy.intersect1d` for more details. + + See Also + -------- + numpy.intersect1d : Equivalent function for ndarrays. + + Examples + -------- + >>> x = array([1, 3, 3, 3], mask=[0, 0, 0, 1]) + >>> y = array([3, 1, 1, 1], mask=[0, 0, 0, 1]) + >>> intersect1d(x, y) + masked_array(data = [1 3 --], + mask = [False False True], + fill_value = 999999) + + """ + if assume_unique: + aux = ma.concatenate((ar1, ar2)) + else: + # Might be faster than unique( intersect1d( ar1, ar2 ) )? + aux = ma.concatenate((unique(ar1), unique(ar2))) + aux.sort() + return aux[:-1][aux[1:] == aux[:-1]] + + +def setxor1d(ar1, ar2, assume_unique=False): + """ + Set exclusive-or of 1-D arrays with unique elements. + + The output is always a masked array. See `numpy.setxor1d` for more details. + + See Also + -------- + numpy.setxor1d : Equivalent function for ndarrays. + + """ + if not assume_unique: + ar1 = unique(ar1) + ar2 = unique(ar2) + + aux = ma.concatenate((ar1, ar2)) + if aux.size == 0: + return aux + aux.sort() + auxf = aux.filled() +# flag = ediff1d( aux, to_end = 1, to_begin = 1 ) == 0 + flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True])) +# flag2 = ediff1d( flag ) == 0 + flag2 = (flag[1:] == flag[:-1]) + return aux[flag2] + + +def in1d(ar1, ar2, assume_unique=False, invert=False): + """ + Test whether each element of an array is also present in a second + array. + + The output is always a masked array. See `numpy.in1d` for more details. + + We recommend using :func:`isin` instead of `in1d` for new code. + + See Also + -------- + isin : Version of this function that preserves the shape of ar1. + numpy.in1d : Equivalent function for ndarrays. + + Notes + ----- + .. versionadded:: 1.4.0 + + """ + if not assume_unique: + ar1, rev_idx = unique(ar1, return_inverse=True) + ar2 = unique(ar2) + + ar = ma.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 = ma.concatenate((bool_ar, [invert])) + indx = order.argsort(kind='mergesort')[:len(ar1)] + + if assume_unique: + return flag[indx] + else: + return flag[indx][rev_idx] + + +def isin(element, test_elements, assume_unique=False, invert=False): + """ + Calculates `element in test_elements`, broadcasting over + `element` only. + + The output is always a masked array of the same shape as `element`. + See `numpy.isin` for more details. + + See Also + -------- + in1d : Flattened version of this function. + numpy.isin : Equivalent function for ndarrays. + + Notes + ----- + .. versionadded:: 1.13.0 + + """ + element = ma.asarray(element) + return in1d(element, test_elements, assume_unique=assume_unique, + invert=invert).reshape(element.shape) + + +def union1d(ar1, ar2): + """ + Union of two arrays. + + The output is always a masked array. See `numpy.union1d` for more details. + + See also + -------- + numpy.union1d : Equivalent function for ndarrays. + + """ + return unique(ma.concatenate((ar1, ar2), axis=None)) + + +def setdiff1d(ar1, ar2, assume_unique=False): + """ + Set difference of 1D arrays with unique elements. + + The output is always a masked array. See `numpy.setdiff1d` for more + details. + + See Also + -------- + numpy.setdiff1d : Equivalent function for ndarrays. + + Examples + -------- + >>> x = np.ma.array([1, 2, 3, 4], mask=[0, 1, 0, 1]) + >>> np.ma.setdiff1d(x, [1, 2]) + masked_array(data = [3 --], + mask = [False True], + fill_value = 999999) + + """ + if assume_unique: + ar1 = ma.asarray(ar1).ravel() + else: + ar1 = unique(ar1) + ar2 = unique(ar2) + return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)] + + +############################################################################### +# Covariance # +############################################################################### + + +def _covhelper(x, y=None, rowvar=True, allow_masked=True): + """ + Private function for the computation of covariance and correlation + coefficients. + + """ + x = ma.array(x, ndmin=2, copy=True, dtype=float) + xmask = ma.getmaskarray(x) + # Quick exit if we can't process masked data + if not allow_masked and xmask.any(): + raise ValueError("Cannot process masked data.") + # + if x.shape[0] == 1: + rowvar = True + # Make sure that rowvar is either 0 or 1 + rowvar = int(bool(rowvar)) + axis = 1 - rowvar + if rowvar: + tup = (slice(None), None) + else: + tup = (None, slice(None)) + # + if y is None: + xnotmask = np.logical_not(xmask).astype(int) + else: + y = array(y, copy=False, ndmin=2, dtype=float) + ymask = ma.getmaskarray(y) + if not allow_masked and ymask.any(): + raise ValueError("Cannot process masked data.") + if xmask.any() or ymask.any(): + if y.shape == x.shape: + # Define some common mask + common_mask = np.logical_or(xmask, ymask) + if common_mask is not nomask: + xmask = x._mask = y._mask = ymask = common_mask + x._sharedmask = False + y._sharedmask = False + x = ma.concatenate((x, y), axis) + xnotmask = np.logical_not(np.concatenate((xmask, ymask), axis)).astype(int) + x -= x.mean(axis=rowvar)[tup] + return (x, xnotmask, rowvar) + + +def cov(x, y=None, rowvar=True, bias=False, allow_masked=True, ddof=None): + """ + Estimate the covariance matrix. + + Except for the handling of missing data this function does the same as + `numpy.cov`. For more details and examples, see `numpy.cov`. + + By default, masked values are recognized as such. If `x` and `y` have the + same shape, a common mask is allocated: if ``x[i,j]`` is masked, then + ``y[i,j]`` will also be masked. + Setting `allow_masked` to False will raise an exception if values are + missing in either of the input arrays. + + Parameters + ---------- + x : array_like + A 1-D or 2-D array containing multiple variables and observations. + Each row of `x` represents a variable, and each column a single + observation of all those variables. Also see `rowvar` below. + y : array_like, optional + An additional set of variables and observations. `y` has the same + form as `x`. + rowvar : bool, optional + If `rowvar` is True (default), then each row represents a + variable, with observations in the columns. Otherwise, the relationship + is transposed: each column represents a variable, while the rows + contain observations. + bias : bool, optional + Default normalization (False) is by ``(N-1)``, where ``N`` is the + number of observations given (unbiased estimate). If `bias` is True, + then normalization is by ``N``. This keyword can be overridden by + the keyword ``ddof`` in numpy versions >= 1.5. + allow_masked : bool, optional + If True, masked values are propagated pair-wise: if a value is masked + in `x`, the corresponding value is masked in `y`. + If False, raises a `ValueError` exception when some values are missing. + ddof : {None, int}, optional + If not ``None`` normalization is by ``(N - ddof)``, where ``N`` is + the number of observations; this overrides the value implied by + ``bias``. The default value is ``None``. + + .. versionadded:: 1.5 + + Raises + ------ + ValueError + Raised if some values are missing and `allow_masked` is False. + + See Also + -------- + numpy.cov + + """ + # Check inputs + if ddof is not None and ddof != int(ddof): + raise ValueError("ddof must be an integer") + # Set up ddof + if ddof is None: + if bias: + ddof = 0 + else: + ddof = 1 + + (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked) + if not rowvar: + fact = np.dot(xnotmask.T, xnotmask) * 1. - ddof + result = (dot(x.T, x.conj(), strict=False) / fact).squeeze() + else: + fact = np.dot(xnotmask, xnotmask.T) * 1. - ddof + result = (dot(x, x.T.conj(), strict=False) / fact).squeeze() + return result + + +def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, allow_masked=True, + ddof=np._NoValue): + """ + Return Pearson product-moment correlation coefficients. + + Except for the handling of missing data this function does the same as + `numpy.corrcoef`. For more details and examples, see `numpy.corrcoef`. + + Parameters + ---------- + x : array_like + A 1-D or 2-D array containing multiple variables and observations. + Each row of `x` represents a variable, and each column a single + observation of all those variables. Also see `rowvar` below. + y : array_like, optional + An additional set of variables and observations. `y` has the same + shape as `x`. + rowvar : bool, optional + If `rowvar` is True (default), then each row represents a + variable, with observations in the columns. Otherwise, the relationship + is transposed: each column represents a variable, while the rows + contain observations. + bias : _NoValue, optional + Has no effect, do not use. + + .. deprecated:: 1.10.0 + allow_masked : bool, optional + If True, masked values are propagated pair-wise: if a value is masked + in `x`, the corresponding value is masked in `y`. + If False, raises an exception. Because `bias` is deprecated, this + argument needs to be treated as keyword only to avoid a warning. + ddof : _NoValue, optional + Has no effect, do not use. + + .. deprecated:: 1.10.0 + + See Also + -------- + numpy.corrcoef : Equivalent function in top-level NumPy module. + cov : Estimate the covariance matrix. + + Notes + ----- + This function accepts but discards arguments `bias` and `ddof`. This is + for backwards compatibility with previous versions of this function. These + arguments had no effect on the return values of the function and can be + safely ignored in this and previous versions of numpy. + """ + msg = 'bias and ddof have no effect and are deprecated' + if bias is not np._NoValue or ddof is not np._NoValue: + # 2015-03-15, 1.10 + warnings.warn(msg, DeprecationWarning, stacklevel=2) + # Get the data + (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked) + # Compute the covariance matrix + if not rowvar: + fact = np.dot(xnotmask.T, xnotmask) * 1. + c = (dot(x.T, x.conj(), strict=False) / fact).squeeze() + else: + fact = np.dot(xnotmask, xnotmask.T) * 1. + c = (dot(x, x.T.conj(), strict=False) / fact).squeeze() + # Check whether we have a scalar + try: + diag = ma.diagonal(c) + except ValueError: + return 1 + # + if xnotmask.all(): + _denom = ma.sqrt(ma.multiply.outer(diag, diag)) + else: + _denom = diagflat(diag) + _denom._sharedmask = False # We know return is always a copy + n = x.shape[1 - rowvar] + if rowvar: + for i in range(n - 1): + for j in range(i + 1, n): + _x = mask_cols(vstack((x[i], x[j]))).var(axis=1) + _denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x)) + else: + for i in range(n - 1): + for j in range(i + 1, n): + _x = mask_cols( + vstack((x[:, i], x[:, j]))).var(axis=1) + _denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x)) + return c / _denom + +#####-------------------------------------------------------------------------- +#---- --- Concatenation helpers --- +#####-------------------------------------------------------------------------- + +class MAxisConcatenator(AxisConcatenator): + """ + Translate slice objects to concatenation along an axis. + + For documentation on usage, see `mr_class`. + + See Also + -------- + mr_class + + """ + concatenate = staticmethod(concatenate) + + @staticmethod + def makemat(arr): + return array(arr.data.view(np.matrix), mask=arr.mask) + + def __getitem__(self, key): + # matrix builder syntax, like 'a, b; c, d' + if isinstance(key, str): + raise MAError("Unavailable for masked array.") + + return super(MAxisConcatenator, self).__getitem__(key) + + +class mr_class(MAxisConcatenator): + """ + Translate slice objects to concatenation along the first axis. + + This is the masked array version of `lib.index_tricks.RClass`. + + See Also + -------- + lib.index_tricks.RClass + + Examples + -------- + >>> np.ma.mr_[np.ma.array([1,2,3]), 0, 0, np.ma.array([4,5,6])] + array([1, 2, 3, 0, 0, 4, 5, 6]) + + """ + def __init__(self): + MAxisConcatenator.__init__(self, 0) + +mr_ = mr_class() + +#####-------------------------------------------------------------------------- +#---- Find unmasked data --- +#####-------------------------------------------------------------------------- + +def flatnotmasked_edges(a): + """ + Find the indices of the first and last unmasked values. + + Expects a 1-D `MaskedArray`, returns None if all values are masked. + + Parameters + ---------- + a : array_like + Input 1-D `MaskedArray` + + Returns + ------- + edges : ndarray or None + The indices of first and last non-masked value in the array. + Returns None if all values are masked. + + See Also + -------- + flatnotmasked_contiguous, notmasked_contiguous, notmasked_edges, + clump_masked, clump_unmasked + + Notes + ----- + Only accepts 1-D arrays. + + Examples + -------- + >>> a = np.ma.arange(10) + >>> flatnotmasked_edges(a) + [0,-1] + + >>> mask = (a < 3) | (a > 8) | (a == 5) + >>> a[mask] = np.ma.masked + >>> np.array(a[~a.mask]) + array([3, 4, 6, 7, 8]) + + >>> flatnotmasked_edges(a) + array([3, 8]) + + >>> a[:] = np.ma.masked + >>> print(flatnotmasked_edges(ma)) + None + + """ + m = getmask(a) + if m is nomask or not np.any(m): + return np.array([0, a.size - 1]) + unmasked = np.flatnonzero(~m) + if len(unmasked) > 0: + return unmasked[[0, -1]] + else: + return None + + +def notmasked_edges(a, axis=None): + """ + Find the indices of the first and last unmasked values along an axis. + + If all values are masked, return None. Otherwise, return a list + of two tuples, corresponding to the indices of the first and last + unmasked values respectively. + + Parameters + ---------- + a : array_like + The input array. + axis : int, optional + Axis along which to perform the operation. + If None (default), applies to a flattened version of the array. + + Returns + ------- + edges : ndarray or list + An array of start and end indexes if there are any masked data in + the array. If there are no masked data in the array, `edges` is a + list of the first and last index. + + See Also + -------- + flatnotmasked_contiguous, flatnotmasked_edges, notmasked_contiguous, + clump_masked, clump_unmasked + + Examples + -------- + >>> a = np.arange(9).reshape((3, 3)) + >>> m = np.zeros_like(a) + >>> m[1:, 1:] = 1 + + >>> am = np.ma.array(a, mask=m) + >>> np.array(am[~am.mask]) + array([0, 1, 2, 3, 6]) + + >>> np.ma.notmasked_edges(ma) + array([0, 6]) + + """ + a = asarray(a) + if axis is None or a.ndim == 1: + return flatnotmasked_edges(a) + m = getmaskarray(a) + idx = array(np.indices(a.shape), mask=np.asarray([m] * a.ndim)) + return [tuple([idx[i].min(axis).compressed() for i in range(a.ndim)]), + tuple([idx[i].max(axis).compressed() for i in range(a.ndim)]), ] + + +def flatnotmasked_contiguous(a): + """ + Find contiguous unmasked data in a masked array along the given axis. + + Parameters + ---------- + a : narray + The input array. + + Returns + ------- + slice_list : list + A sorted sequence of slices (start index, end index). + + See Also + -------- + flatnotmasked_edges, notmasked_contiguous, notmasked_edges, + clump_masked, clump_unmasked + + Notes + ----- + Only accepts 2-D arrays at most. + + Examples + -------- + >>> a = np.ma.arange(10) + >>> np.ma.flatnotmasked_contiguous(a) + slice(0, 10, None) + + >>> mask = (a < 3) | (a > 8) | (a == 5) + >>> a[mask] = np.ma.masked + >>> np.array(a[~a.mask]) + array([3, 4, 6, 7, 8]) + + >>> np.ma.flatnotmasked_contiguous(a) + [slice(3, 5, None), slice(6, 9, None)] + >>> a[:] = np.ma.masked + >>> print(np.ma.flatnotmasked_edges(a)) + None + + """ + m = getmask(a) + if m is nomask: + return slice(0, a.size, None) + i = 0 + result = [] + for (k, g) in itertools.groupby(m.ravel()): + n = len(list(g)) + if not k: + result.append(slice(i, i + n)) + i += n + return result or None + +def notmasked_contiguous(a, axis=None): + """ + Find contiguous unmasked data in a masked array along the given axis. + + Parameters + ---------- + a : array_like + The input array. + axis : int, optional + Axis along which to perform the operation. + If None (default), applies to a flattened version of the array. + + Returns + ------- + endpoints : list + A list of slices (start and end indexes) of unmasked indexes + in the array. + + See Also + -------- + flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges, + clump_masked, clump_unmasked + + Notes + ----- + Only accepts 2-D arrays at most. + + Examples + -------- + >>> a = np.arange(9).reshape((3, 3)) + >>> mask = np.zeros_like(a) + >>> mask[1:, 1:] = 1 + + >>> ma = np.ma.array(a, mask=mask) + >>> np.array(ma[~ma.mask]) + array([0, 1, 2, 3, 6]) + + >>> np.ma.notmasked_contiguous(ma) + [slice(0, 4, None), slice(6, 7, None)] + + """ + a = asarray(a) + nd = a.ndim + if nd > 2: + raise NotImplementedError("Currently limited to atmost 2D array.") + if axis is None or nd == 1: + return flatnotmasked_contiguous(a) + # + result = [] + # + other = (axis + 1) % 2 + idx = [0, 0] + idx[axis] = slice(None, None) + # + for i in range(a.shape[other]): + idx[other] = i + result.append(flatnotmasked_contiguous(a[idx]) or None) + return result + + +def _ezclump(mask): + """ + Finds the clumps (groups of data with the same values) for a 1D bool array. + + Returns a series of slices. + """ + if mask.ndim > 1: + mask = mask.ravel() + idx = (mask[1:] ^ mask[:-1]).nonzero() + idx = idx[0] + 1 + + if mask[0]: + if len(idx) == 0: + return [slice(0, mask.size)] + + r = [slice(0, idx[0])] + r.extend((slice(left, right) + for left, right in zip(idx[1:-1:2], idx[2::2]))) + else: + if len(idx) == 0: + return [] + + r = [slice(left, right) for left, right in zip(idx[:-1:2], idx[1::2])] + + if mask[-1]: + r.append(slice(idx[-1], mask.size)) + return r + + +def clump_unmasked(a): + """ + Return list of slices corresponding to the unmasked clumps of a 1-D array. + (A "clump" is defined as a contiguous region of the array). + + Parameters + ---------- + a : ndarray + A one-dimensional masked array. + + Returns + ------- + slices : list of slice + The list of slices, one for each continuous region of unmasked + elements in `a`. + + Notes + ----- + .. versionadded:: 1.4.0 + + See Also + -------- + flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges, + notmasked_contiguous, clump_masked + + Examples + -------- + >>> a = np.ma.masked_array(np.arange(10)) + >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked + >>> np.ma.clump_unmasked(a) + [slice(3, 6, None), slice(7, 8, None)] + + """ + mask = getattr(a, '_mask', nomask) + if mask is nomask: + return [slice(0, a.size)] + return _ezclump(~mask) + + +def clump_masked(a): + """ + Returns a list of slices corresponding to the masked clumps of a 1-D array. + (A "clump" is defined as a contiguous region of the array). + + Parameters + ---------- + a : ndarray + A one-dimensional masked array. + + Returns + ------- + slices : list of slice + The list of slices, one for each continuous region of masked elements + in `a`. + + Notes + ----- + .. versionadded:: 1.4.0 + + See Also + -------- + flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges, + notmasked_contiguous, clump_unmasked + + Examples + -------- + >>> a = np.ma.masked_array(np.arange(10)) + >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked + >>> np.ma.clump_masked(a) + [slice(0, 3, None), slice(6, 7, None), slice(8, 10, None)] + + """ + mask = ma.getmask(a) + if mask is nomask: + return [] + return _ezclump(mask) + + +############################################################################### +# Polynomial fit # +############################################################################### + + +def vander(x, n=None): + """ + Masked values in the input array result in rows of zeros. + + """ + _vander = np.vander(x, n) + m = getmask(x) + if m is not nomask: + _vander[m] = 0 + return _vander + +vander.__doc__ = ma.doc_note(np.vander.__doc__, vander.__doc__) + + +def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False): + """ + Any masked values in x is propagated in y, and vice-versa. + + """ + x = asarray(x) + y = asarray(y) + + m = getmask(x) + if y.ndim == 1: + m = mask_or(m, getmask(y)) + elif y.ndim == 2: + my = getmask(mask_rows(y)) + if my is not nomask: + m = mask_or(m, my[:, 0]) + else: + raise TypeError("Expected a 1D or 2D array for y!") + + if w is not None: + w = asarray(w) + if w.ndim != 1: + raise TypeError("expected a 1-d array for weights") + if w.shape[0] != y.shape[0]: + raise TypeError("expected w and y to have the same length") + m = mask_or(m, getmask(w)) + + if m is not nomask: + not_m = ~m + if w is not None: + w = w[not_m] + return np.polyfit(x[not_m], y[not_m], deg, rcond, full, w, cov) + else: + return np.polyfit(x, y, deg, rcond, full, w, cov) + +polyfit.__doc__ = ma.doc_note(np.polyfit.__doc__, polyfit.__doc__) diff --git a/numpy/ma/mrecords.py b/numpy/ma/mrecords.py new file mode 100644 index 0000000..90a5141 --- /dev/null +++ b/numpy/ma/mrecords.py @@ -0,0 +1,796 @@ +""":mod:`numpy.ma..mrecords` + +Defines the equivalent of :class:`numpy.recarrays` for masked arrays, +where fields can be accessed as attributes. +Note that :class:`numpy.ma.MaskedArray` already supports structured datatypes +and the masking of individual fields. + +.. moduleauthor:: Pierre Gerard-Marchant + +""" +from __future__ import division, absolute_import, print_function + +# We should make sure that no field is called '_mask','mask','_fieldmask', +# or whatever restricted keywords. An idea would be to no bother in the +# first place, and then rename the invalid fields with a trailing +# underscore. Maybe we could just overload the parser function ? + +import sys +import warnings + +import numpy as np +import numpy.core.numerictypes as ntypes +from numpy.compat import basestring +from numpy import ( + bool_, dtype, ndarray, recarray, array as narray + ) +from numpy.core.records import ( + fromarrays as recfromarrays, fromrecords as recfromrecords + ) + +_byteorderconv = np.core.records._byteorderconv +_typestr = ntypes._typestr + +import numpy.ma as ma +from numpy.ma import ( + MAError, MaskedArray, masked, nomask, masked_array, getdata, + getmaskarray, filled + ) + +_check_fill_value = ma.core._check_fill_value + + +__all__ = [ + 'MaskedRecords', 'mrecarray', 'fromarrays', 'fromrecords', + 'fromtextfile', 'addfield', + ] + +reserved_fields = ['_data', '_mask', '_fieldmask', 'dtype'] + + +def _getformats(data): + """ + Returns the formats of arrays in arraylist as a comma-separated string. + + """ + if hasattr(data, 'dtype'): + return ",".join([desc[1] for desc in data.dtype.descr]) + + formats = '' + for obj in data: + obj = np.asarray(obj) + formats += _typestr[obj.dtype.type] + if issubclass(obj.dtype.type, ntypes.flexible): + formats += repr(obj.itemsize) + formats += ',' + return formats[:-1] + + +def _checknames(descr, names=None): + """ + Checks that field names ``descr`` are not reserved keywords. + + If this is the case, a default 'f%i' is substituted. If the argument + `names` is not None, updates the field names to valid names. + + """ + ndescr = len(descr) + default_names = ['f%i' % i for i in range(ndescr)] + if names is None: + new_names = default_names + else: + if isinstance(names, (tuple, list)): + new_names = names + elif isinstance(names, str): + new_names = names.split(',') + else: + raise NameError("illegal input names %s" % repr(names)) + nnames = len(new_names) + if nnames < ndescr: + new_names += default_names[nnames:] + ndescr = [] + for (n, d, t) in zip(new_names, default_names, descr.descr): + if n in reserved_fields: + if t[0] in reserved_fields: + ndescr.append((d, t[1])) + else: + ndescr.append(t) + else: + ndescr.append((n, t[1])) + return np.dtype(ndescr) + + +def _get_fieldmask(self): + mdescr = [(n, '|b1') for n in self.dtype.names] + fdmask = np.empty(self.shape, dtype=mdescr) + fdmask.flat = tuple([False] * len(mdescr)) + return fdmask + + +class MaskedRecords(MaskedArray, object): + """ + + Attributes + ---------- + _data : recarray + Underlying data, as a record array. + _mask : boolean array + Mask of the records. A record is masked when all its fields are + masked. + _fieldmask : boolean recarray + Record array of booleans, setting the mask of each individual field + of each record. + _fill_value : record + Filling values for each field. + + """ + + def __new__(cls, shape, dtype=None, buf=None, offset=0, strides=None, + formats=None, names=None, titles=None, + byteorder=None, aligned=False, + mask=nomask, hard_mask=False, fill_value=None, keep_mask=True, + copy=False, + **options): + + self = recarray.__new__(cls, shape, dtype=dtype, buf=buf, offset=offset, + strides=strides, formats=formats, names=names, + titles=titles, byteorder=byteorder, + aligned=aligned,) + + mdtype = ma.make_mask_descr(self.dtype) + if mask is nomask or not np.size(mask): + if not keep_mask: + self._mask = tuple([False] * len(mdtype)) + else: + mask = np.array(mask, copy=copy) + if mask.shape != self.shape: + (nd, nm) = (self.size, mask.size) + if nm == 1: + mask = np.resize(mask, self.shape) + elif nm == nd: + mask = np.reshape(mask, self.shape) + else: + msg = "Mask and data not compatible: data size is %i, " + \ + "mask size is %i." + raise MAError(msg % (nd, nm)) + copy = True + if not keep_mask: + self.__setmask__(mask) + self._sharedmask = True + else: + if mask.dtype == mdtype: + _mask = mask + else: + _mask = np.array([tuple([m] * len(mdtype)) for m in mask], + dtype=mdtype) + self._mask = _mask + return self + + def __array_finalize__(self, obj): + # Make sure we have a _fieldmask by default + _mask = getattr(obj, '_mask', None) + if _mask is None: + objmask = getattr(obj, '_mask', nomask) + _dtype = ndarray.__getattribute__(self, 'dtype') + if objmask is nomask: + _mask = ma.make_mask_none(self.shape, dtype=_dtype) + else: + mdescr = ma.make_mask_descr(_dtype) + _mask = narray([tuple([m] * len(mdescr)) for m in objmask], + dtype=mdescr).view(recarray) + # Update some of the attributes + _dict = self.__dict__ + _dict.update(_mask=_mask) + self._update_from(obj) + if _dict['_baseclass'] == ndarray: + _dict['_baseclass'] = recarray + return + + def _getdata(self): + """ + Returns the data as a recarray. + + """ + return ndarray.view(self, recarray) + + _data = property(fget=_getdata) + + def _getfieldmask(self): + """ + Alias to mask. + + """ + return self._mask + + _fieldmask = property(fget=_getfieldmask) + + def __len__(self): + """ + Returns the length + + """ + # We have more than one record + if self.ndim: + return len(self._data) + # We have only one record: return the nb of fields + return len(self.dtype) + + def __getattribute__(self, attr): + try: + return object.__getattribute__(self, attr) + except AttributeError: + # attr must be a fieldname + pass + fielddict = ndarray.__getattribute__(self, 'dtype').fields + try: + res = fielddict[attr][:2] + except (TypeError, KeyError): + raise AttributeError("record array has no attribute %s" % attr) + # So far, so good + _localdict = ndarray.__getattribute__(self, '__dict__') + _data = ndarray.view(self, _localdict['_baseclass']) + obj = _data.getfield(*res) + if obj.dtype.fields: + raise NotImplementedError("MaskedRecords is currently limited to" + "simple records.") + # Get some special attributes + # Reset the object's mask + hasmasked = False + _mask = _localdict.get('_mask', None) + if _mask is not None: + try: + _mask = _mask[attr] + except IndexError: + # Couldn't find a mask: use the default (nomask) + pass + hasmasked = _mask.view((bool, (len(_mask.dtype) or 1))).any() + if (obj.shape or hasmasked): + obj = obj.view(MaskedArray) + obj._baseclass = ndarray + obj._isfield = True + obj._mask = _mask + # Reset the field values + _fill_value = _localdict.get('_fill_value', None) + if _fill_value is not None: + try: + obj._fill_value = _fill_value[attr] + except ValueError: + obj._fill_value = None + else: + obj = obj.item() + return obj + + def __setattr__(self, attr, val): + """ + Sets the attribute attr to the value val. + + """ + # Should we call __setmask__ first ? + if attr in ['mask', 'fieldmask']: + self.__setmask__(val) + return + # Create a shortcut (so that we don't have to call getattr all the time) + _localdict = object.__getattribute__(self, '__dict__') + # Check whether we're creating a new field + newattr = attr not in _localdict + try: + # Is attr a generic attribute ? + ret = object.__setattr__(self, attr, val) + except Exception: + # Not a generic attribute: exit if it's not a valid field + fielddict = ndarray.__getattribute__(self, 'dtype').fields or {} + optinfo = ndarray.__getattribute__(self, '_optinfo') or {} + if not (attr in fielddict or attr in optinfo): + exctype, value = sys.exc_info()[:2] + raise exctype(value) + else: + # Get the list of names + fielddict = ndarray.__getattribute__(self, 'dtype').fields or {} + # Check the attribute + if attr not in fielddict: + return ret + if newattr: + # We just added this one or this setattr worked on an + # internal attribute. + try: + object.__delattr__(self, attr) + except Exception: + return ret + # Let's try to set the field + try: + res = fielddict[attr][:2] + except (TypeError, KeyError): + raise AttributeError("record array has no attribute %s" % attr) + + if val is masked: + _fill_value = _localdict['_fill_value'] + if _fill_value is not None: + dval = _localdict['_fill_value'][attr] + else: + dval = val + mval = True + else: + dval = filled(val) + mval = getmaskarray(val) + obj = ndarray.__getattribute__(self, '_data').setfield(dval, *res) + _localdict['_mask'].__setitem__(attr, mval) + return obj + + def __getitem__(self, indx): + """ + Returns all the fields sharing the same fieldname base. + + The fieldname base is either `_data` or `_mask`. + + """ + _localdict = self.__dict__ + _mask = ndarray.__getattribute__(self, '_mask') + _data = ndarray.view(self, _localdict['_baseclass']) + # We want a field + if isinstance(indx, basestring): + # Make sure _sharedmask is True to propagate back to _fieldmask + # Don't use _set_mask, there are some copies being made that + # break propagation Don't force the mask to nomask, that wreaks + # easy masking + obj = _data[indx].view(MaskedArray) + obj._mask = _mask[indx] + obj._sharedmask = True + fval = _localdict['_fill_value'] + if fval is not None: + obj._fill_value = fval[indx] + # Force to masked if the mask is True + if not obj.ndim and obj._mask: + return masked + return obj + # We want some elements. + # First, the data. + obj = np.array(_data[indx], copy=False).view(mrecarray) + obj._mask = np.array(_mask[indx], copy=False).view(recarray) + return obj + + def __setitem__(self, indx, value): + """ + Sets the given record to value. + + """ + MaskedArray.__setitem__(self, indx, value) + if isinstance(indx, basestring): + self._mask[indx] = ma.getmaskarray(value) + + def __str__(self): + """ + Calculates the string representation. + + """ + if self.size > 1: + mstr = ["(%s)" % ",".join([str(i) for i in s]) + for s in zip(*[getattr(self, f) for f in self.dtype.names])] + return "[%s]" % ", ".join(mstr) + else: + mstr = ["%s" % ",".join([str(i) for i in s]) + for s in zip([getattr(self, f) for f in self.dtype.names])] + return "(%s)" % ", ".join(mstr) + + def __repr__(self): + """ + Calculates the repr representation. + + """ + _names = self.dtype.names + fmt = "%%%is : %%s" % (max([len(n) for n in _names]) + 4,) + reprstr = [fmt % (f, getattr(self, f)) for f in self.dtype.names] + reprstr.insert(0, 'masked_records(') + reprstr.extend([fmt % (' fill_value', self.fill_value), + ' )']) + return str("\n".join(reprstr)) + + def view(self, dtype=None, type=None): + """ + Returns a view of the mrecarray. + + """ + # OK, basic copy-paste from MaskedArray.view. + if dtype is None: + if type is None: + output = ndarray.view(self) + else: + output = ndarray.view(self, type) + # Here again. + elif type is None: + try: + if issubclass(dtype, ndarray): + output = ndarray.view(self, dtype) + dtype = None + else: + output = ndarray.view(self, dtype) + # OK, there's the change + except TypeError: + dtype = np.dtype(dtype) + # we need to revert to MaskedArray, but keeping the possibility + # of subclasses (eg, TimeSeriesRecords), so we'll force a type + # set to the first parent + if dtype.fields is None: + basetype = self.__class__.__bases__[0] + output = self.__array__().view(dtype, basetype) + output._update_from(self) + else: + output = ndarray.view(self, dtype) + output._fill_value = None + else: + output = ndarray.view(self, dtype, type) + # Update the mask, just like in MaskedArray.view + if (getattr(output, '_mask', nomask) is not nomask): + mdtype = ma.make_mask_descr(output.dtype) + output._mask = self._mask.view(mdtype, ndarray) + output._mask.shape = output.shape + return output + + def harden_mask(self): + """ + Forces the mask to hard. + + """ + self._hardmask = True + + def soften_mask(self): + """ + Forces the mask to soft + + """ + self._hardmask = False + + def copy(self): + """ + Returns a copy of the masked record. + + """ + copied = self._data.copy().view(type(self)) + copied._mask = self._mask.copy() + return copied + + def tolist(self, fill_value=None): + """ + Return the data portion of the array as a list. + + Data items are converted to the nearest compatible Python type. + Masked values are converted to fill_value. If fill_value is None, + the corresponding entries in the output list will be ``None``. + + """ + if fill_value is not None: + return self.filled(fill_value).tolist() + result = narray(self.filled().tolist(), dtype=object) + mask = narray(self._mask.tolist()) + result[mask] = None + return result.tolist() + + def __getstate__(self): + """Return the internal state of the masked array. + + This is for pickling. + + """ + state = (1, + self.shape, + self.dtype, + self.flags.fnc, + self._data.tobytes(), + self._mask.tobytes(), + self._fill_value, + ) + return state + + def __setstate__(self, state): + """ + Restore the internal state of the masked array. + + This is for pickling. ``state`` is typically the output of the + ``__getstate__`` output, and is a 5-tuple: + + - class name + - a tuple giving the shape of the data + - a typecode for the data + - a binary string for the data + - a binary string for the mask. + + """ + (ver, shp, typ, isf, raw, msk, flv) = state + ndarray.__setstate__(self, (shp, typ, isf, raw)) + mdtype = dtype([(k, bool_) for (k, _) in self.dtype.descr]) + self.__dict__['_mask'].__setstate__((shp, mdtype, isf, msk)) + self.fill_value = flv + + def __reduce__(self): + """ + Return a 3-tuple for pickling a MaskedArray. + + """ + return (_mrreconstruct, + (self.__class__, self._baseclass, (0,), 'b',), + self.__getstate__()) + +def _mrreconstruct(subtype, baseclass, baseshape, basetype,): + """ + Build a new MaskedArray from the information stored in a pickle. + + """ + _data = ndarray.__new__(baseclass, baseshape, basetype).view(subtype) + _mask = ndarray.__new__(ndarray, baseshape, 'b1') + return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,) + +mrecarray = MaskedRecords + + +############################################################################### +# Constructors # +############################################################################### + + +def fromarrays(arraylist, dtype=None, shape=None, formats=None, + names=None, titles=None, aligned=False, byteorder=None, + fill_value=None): + """ + Creates a mrecarray from a (flat) list of masked arrays. + + Parameters + ---------- + arraylist : sequence + A list of (masked) arrays. Each element of the sequence is first converted + to a masked array if needed. If a 2D array is passed as argument, it is + processed line by line + dtype : {None, dtype}, optional + Data type descriptor. + shape : {None, integer}, optional + Number of records. If None, shape is defined from the shape of the + first array in the list. + formats : {None, sequence}, optional + Sequence of formats for each individual field. If None, the formats will + be autodetected by inspecting the fields and selecting the highest dtype + possible. + names : {None, sequence}, optional + Sequence of the names of each field. + fill_value : {None, sequence}, optional + Sequence of data to be used as filling values. + + Notes + ----- + Lists of tuples should be preferred over lists of lists for faster processing. + + """ + datalist = [getdata(x) for x in arraylist] + masklist = [np.atleast_1d(getmaskarray(x)) for x in arraylist] + _array = recfromarrays(datalist, + dtype=dtype, shape=shape, formats=formats, + names=names, titles=titles, aligned=aligned, + byteorder=byteorder).view(mrecarray) + _array._mask.flat = list(zip(*masklist)) + if fill_value is not None: + _array.fill_value = fill_value + return _array + + +def fromrecords(reclist, dtype=None, shape=None, formats=None, names=None, + titles=None, aligned=False, byteorder=None, + fill_value=None, mask=nomask): + """ + Creates a MaskedRecords from a list of records. + + Parameters + ---------- + reclist : sequence + A list of records. Each element of the sequence is first converted + to a masked array if needed. If a 2D array is passed as argument, it is + processed line by line + dtype : {None, dtype}, optional + Data type descriptor. + shape : {None,int}, optional + Number of records. If None, ``shape`` is defined from the shape of the + first array in the list. + formats : {None, sequence}, optional + Sequence of formats for each individual field. If None, the formats will + be autodetected by inspecting the fields and selecting the highest dtype + possible. + names : {None, sequence}, optional + Sequence of the names of each field. + fill_value : {None, sequence}, optional + Sequence of data to be used as filling values. + mask : {nomask, sequence}, optional. + External mask to apply on the data. + + Notes + ----- + Lists of tuples should be preferred over lists of lists for faster processing. + + """ + # Grab the initial _fieldmask, if needed: + _mask = getattr(reclist, '_mask', None) + # Get the list of records. + if isinstance(reclist, ndarray): + # Make sure we don't have some hidden mask + if isinstance(reclist, MaskedArray): + reclist = reclist.filled().view(ndarray) + # Grab the initial dtype, just in case + if dtype is None: + dtype = reclist.dtype + reclist = reclist.tolist() + mrec = recfromrecords(reclist, dtype=dtype, shape=shape, formats=formats, + names=names, titles=titles, + aligned=aligned, byteorder=byteorder).view(mrecarray) + # Set the fill_value if needed + if fill_value is not None: + mrec.fill_value = fill_value + # Now, let's deal w/ the mask + if mask is not nomask: + mask = np.array(mask, copy=False) + maskrecordlength = len(mask.dtype) + if maskrecordlength: + mrec._mask.flat = mask + elif mask.ndim == 2: + mrec._mask.flat = [tuple(m) for m in mask] + else: + mrec.__setmask__(mask) + if _mask is not None: + mrec._mask[:] = _mask + return mrec + + +def _guessvartypes(arr): + """ + Tries to guess the dtypes of the str_ ndarray `arr`. + + Guesses by testing element-wise conversion. Returns a list of dtypes. + The array is first converted to ndarray. If the array is 2D, the test + is performed on the first line. An exception is raised if the file is + 3D or more. + + """ + vartypes = [] + arr = np.asarray(arr) + if arr.ndim == 2: + arr = arr[0] + elif arr.ndim > 2: + raise ValueError("The array should be 2D at most!") + # Start the conversion loop. + for f in arr: + try: + int(f) + except (ValueError, TypeError): + try: + float(f) + except (ValueError, TypeError): + try: + complex(f) + except (ValueError, TypeError): + vartypes.append(arr.dtype) + else: + vartypes.append(np.dtype(complex)) + else: + vartypes.append(np.dtype(float)) + else: + vartypes.append(np.dtype(int)) + return vartypes + + +def openfile(fname): + """ + Opens the file handle of file `fname`. + + """ + # A file handle + if hasattr(fname, 'readline'): + return fname + # Try to open the file and guess its type + try: + f = open(fname) + except IOError: + raise IOError("No such file: '%s'" % fname) + if f.readline()[:2] != "\\x": + f.seek(0, 0) + return f + f.close() + raise NotImplementedError("Wow, binary file") + + +def fromtextfile(fname, delimitor=None, commentchar='#', missingchar='', + varnames=None, vartypes=None): + """ + Creates a mrecarray from data stored in the file `filename`. + + Parameters + ---------- + fname : {file name/handle} + Handle of an opened file. + delimitor : {None, string}, optional + Alphanumeric character used to separate columns in the file. + If None, any (group of) white spacestring(s) will be used. + commentchar : {'#', string}, optional + Alphanumeric character used to mark the start of a comment. + missingchar : {'', string}, optional + String indicating missing data, and used to create the masks. + varnames : {None, sequence}, optional + Sequence of the variable names. If None, a list will be created from + the first non empty line of the file. + vartypes : {None, sequence}, optional + Sequence of the variables dtypes. If None, it will be estimated from + the first non-commented line. + + + Ultra simple: the varnames are in the header, one line""" + # Try to open the file. + ftext = openfile(fname) + + # Get the first non-empty line as the varnames + while True: + line = ftext.readline() + firstline = line[:line.find(commentchar)].strip() + _varnames = firstline.split(delimitor) + if len(_varnames) > 1: + break + if varnames is None: + varnames = _varnames + + # Get the data. + _variables = masked_array([line.strip().split(delimitor) for line in ftext + if line[0] != commentchar and len(line) > 1]) + (_, nfields) = _variables.shape + ftext.close() + + # Try to guess the dtype. + if vartypes is None: + vartypes = _guessvartypes(_variables[0]) + else: + vartypes = [np.dtype(v) for v in vartypes] + if len(vartypes) != nfields: + msg = "Attempting to %i dtypes for %i fields!" + msg += " Reverting to default." + warnings.warn(msg % (len(vartypes), nfields), stacklevel=2) + vartypes = _guessvartypes(_variables[0]) + + # Construct the descriptor. + mdescr = [(n, f) for (n, f) in zip(varnames, vartypes)] + mfillv = [ma.default_fill_value(f) for f in vartypes] + + # Get the data and the mask. + # We just need a list of masked_arrays. It's easier to create it like that: + _mask = (_variables.T == missingchar) + _datalist = [masked_array(a, mask=m, dtype=t, fill_value=f) + for (a, m, t, f) in zip(_variables.T, _mask, vartypes, mfillv)] + + return fromarrays(_datalist, dtype=mdescr) + + +def addfield(mrecord, newfield, newfieldname=None): + """Adds a new field to the masked record array + + Uses `newfield` as data and `newfieldname` as name. If `newfieldname` + is None, the new field name is set to 'fi', where `i` is the number of + existing fields. + + """ + _data = mrecord._data + _mask = mrecord._mask + if newfieldname is None or newfieldname in reserved_fields: + newfieldname = 'f%i' % len(_data.dtype) + newfield = ma.array(newfield) + # Get the new data. + # Create a new empty recarray + newdtype = np.dtype(_data.dtype.descr + [(newfieldname, newfield.dtype)]) + newdata = recarray(_data.shape, newdtype) + # Add the existing field + [newdata.setfield(_data.getfield(*f), *f) + for f in _data.dtype.fields.values()] + # Add the new field + newdata.setfield(newfield._data, *newdata.dtype.fields[newfieldname]) + newdata = newdata.view(MaskedRecords) + # Get the new mask + # Create a new empty recarray + newmdtype = np.dtype([(n, bool_) for n in newdtype.names]) + newmask = recarray(_data.shape, newmdtype) + # Add the old masks + [newmask.setfield(_mask.getfield(*f), *f) + for f in _mask.dtype.fields.values()] + # Add the mask of the new field + newmask.setfield(getmaskarray(newfield), + *newmask.dtype.fields[newfieldname]) + newdata._mask = newmask + return newdata diff --git a/numpy/ma/setup.py b/numpy/ma/setup.py new file mode 100644 index 0000000..d1d6c89 --- /dev/null +++ b/numpy/ma/setup.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +from __future__ import division, print_function + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('ma', parent_package, top_path) + config.add_data_dir('tests') + return config + +if __name__ == "__main__": + from numpy.distutils.core import setup + config = configuration(top_path='').todict() + setup(**config) diff --git a/numpy/ma/tests/__init__.py b/numpy/ma/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/ma/tests/__init__.py diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py new file mode 100644 index 0000000..708c12e --- /dev/null +++ b/numpy/ma/tests/test_core.py @@ -0,0 +1,5089 @@ +# pylint: disable-msg=W0400,W0511,W0611,W0612,W0614,R0201,E1102 +"""Tests suite for MaskedArray & subclassing. + +:author: Pierre Gerard-Marchant +:contact: pierregm_at_uga_dot_edu +""" +from __future__ import division, absolute_import, print_function + +__author__ = "Pierre GF Gerard-Marchant" + +import sys +import warnings +import pickle +import operator +import itertools +import sys +import textwrap +from functools import reduce + + +import numpy as np +import numpy.ma.core +import numpy.core.fromnumeric as fromnumeric +import numpy.core.umath as umath +from numpy.testing import ( + run_module_suite, assert_raises, assert_warns, suppress_warnings, dec + ) +from numpy import ndarray +from numpy.compat import asbytes, asbytes_nested +from numpy.ma.testutils import ( + assert_, assert_array_equal, assert_equal, assert_almost_equal, + assert_equal_records, fail_if_equal, assert_not_equal, + assert_mask_equal + ) +from numpy.ma.core import ( + MAError, MaskError, MaskType, MaskedArray, abs, absolute, add, all, + allclose, allequal, alltrue, angle, anom, arange, arccos, arccosh, arctan2, + arcsin, arctan, argsort, array, asarray, choose, concatenate, + conjugate, cos, cosh, count, default_fill_value, diag, divide, empty, + empty_like, equal, exp, flatten_mask, filled, fix_invalid, + flatten_structured_array, fromflex, getmask, getmaskarray, greater, + greater_equal, identity, inner, isMaskedArray, less, less_equal, log, + log10, make_mask, make_mask_descr, mask_or, masked, masked_array, + masked_equal, masked_greater, masked_greater_equal, masked_inside, + masked_less, masked_less_equal, masked_not_equal, masked_outside, + masked_print_option, masked_values, masked_where, max, maximum, + maximum_fill_value, min, minimum, minimum_fill_value, mod, multiply, + mvoid, nomask, not_equal, ones, outer, power, product, put, putmask, + ravel, repeat, reshape, resize, shape, sin, sinh, sometrue, sort, sqrt, + subtract, sum, take, tan, tanh, transpose, where, zeros, + ) +from numpy.testing import dec + +pi = np.pi + + +suppress_copy_mask_on_assignment = suppress_warnings() +suppress_copy_mask_on_assignment.filter( + numpy.ma.core.MaskedArrayFutureWarning, + "setting an item on a masked array which has a shared mask will not copy") + + +class TestMaskedArray(object): + # Base test class for MaskedArrays. + + def setup(self): + # Base data definition. + x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.]) + y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.]) + a10 = 10. + m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0] + m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1] + xm = masked_array(x, mask=m1) + ym = masked_array(y, mask=m2) + z = np.array([-.5, 0., .5, .8]) + zm = masked_array(z, mask=[0, 1, 0, 0]) + xf = np.where(m1, 1e+20, x) + xm.set_fill_value(1e+20) + self.d = (x, y, a10, m1, m2, xm, ym, z, zm, xf) + + def test_basicattributes(self): + # Tests some basic array attributes. + a = array([1, 3, 2]) + b = array([1, 3, 2], mask=[1, 0, 1]) + assert_equal(a.ndim, 1) + assert_equal(b.ndim, 1) + assert_equal(a.size, 3) + assert_equal(b.size, 3) + assert_equal(a.shape, (3,)) + assert_equal(b.shape, (3,)) + + def test_basic0d(self): + # Checks masking a scalar + x = masked_array(0) + assert_equal(str(x), '0') + x = masked_array(0, mask=True) + assert_equal(str(x), str(masked_print_option)) + x = masked_array(0, mask=False) + assert_equal(str(x), '0') + x = array(0, mask=1) + assert_(x.filled().dtype is x._data.dtype) + + def test_basic1d(self): + # Test of basic array creation and properties in 1 dimension. + (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d + assert_(not isMaskedArray(x)) + assert_(isMaskedArray(xm)) + assert_((xm - ym).filled(0).any()) + fail_if_equal(xm.mask.astype(int), ym.mask.astype(int)) + s = x.shape + assert_equal(np.shape(xm), s) + assert_equal(xm.shape, s) + assert_equal(xm.dtype, x.dtype) + assert_equal(zm.dtype, z.dtype) + assert_equal(xm.size, reduce(lambda x, y:x * y, s)) + assert_equal(count(xm), len(m1) - reduce(lambda x, y:x + y, m1)) + assert_array_equal(xm, xf) + assert_array_equal(filled(xm, 1.e20), xf) + assert_array_equal(x, xm) + + def test_basic2d(self): + # Test of basic array creation and properties in 2 dimensions. + (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d + for s in [(4, 3), (6, 2)]: + x.shape = s + y.shape = s + xm.shape = s + ym.shape = s + xf.shape = s + + assert_(not isMaskedArray(x)) + assert_(isMaskedArray(xm)) + assert_equal(shape(xm), s) + assert_equal(xm.shape, s) + assert_equal(xm.size, reduce(lambda x, y:x * y, s)) + assert_equal(count(xm), len(m1) - reduce(lambda x, y:x + y, m1)) + assert_equal(xm, xf) + assert_equal(filled(xm, 1.e20), xf) + assert_equal(x, xm) + + def test_concatenate_basic(self): + # Tests concatenations. + (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d + # basic concatenation + assert_equal(np.concatenate((x, y)), concatenate((xm, ym))) + assert_equal(np.concatenate((x, y)), concatenate((x, y))) + assert_equal(np.concatenate((x, y)), concatenate((xm, y))) + assert_equal(np.concatenate((x, y, x)), concatenate((x, ym, x))) + + def test_concatenate_alongaxis(self): + # Tests concatenations. + (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d + # Concatenation along an axis + s = (3, 4) + x.shape = y.shape = xm.shape = ym.shape = s + assert_equal(xm.mask, np.reshape(m1, s)) + assert_equal(ym.mask, np.reshape(m2, s)) + xmym = concatenate((xm, ym), 1) + assert_equal(np.concatenate((x, y), 1), xmym) + assert_equal(np.concatenate((xm.mask, ym.mask), 1), xmym._mask) + + x = zeros(2) + y = array(ones(2), mask=[False, True]) + z = concatenate((x, y)) + assert_array_equal(z, [0, 0, 1, 1]) + assert_array_equal(z.mask, [False, False, False, True]) + z = concatenate((y, x)) + assert_array_equal(z, [1, 1, 0, 0]) + assert_array_equal(z.mask, [False, True, False, False]) + + def test_concatenate_flexible(self): + # Tests the concatenation on flexible arrays. + data = masked_array(list(zip(np.random.rand(10), + np.arange(10))), + dtype=[('a', float), ('b', int)]) + + test = concatenate([data[:5], data[5:]]) + assert_equal_records(test, data) + + def test_creation_ndmin(self): + # Check the use of ndmin + x = array([1, 2, 3], mask=[1, 0, 0], ndmin=2) + assert_equal(x.shape, (1, 3)) + assert_equal(x._data, [[1, 2, 3]]) + assert_equal(x._mask, [[1, 0, 0]]) + + def test_creation_ndmin_from_maskedarray(self): + # Make sure we're not losing the original mask w/ ndmin + x = array([1, 2, 3]) + x[-1] = masked + xx = array(x, ndmin=2, dtype=float) + assert_equal(x.shape, x._mask.shape) + assert_equal(xx.shape, xx._mask.shape) + + def test_creation_maskcreation(self): + # Tests how masks are initialized at the creation of Maskedarrays. + data = arange(24, dtype=float) + data[[3, 6, 15]] = masked + dma_1 = MaskedArray(data) + assert_equal(dma_1.mask, data.mask) + dma_2 = MaskedArray(dma_1) + assert_equal(dma_2.mask, dma_1.mask) + dma_3 = MaskedArray(dma_1, mask=[1, 0, 0, 0] * 6) + fail_if_equal(dma_3.mask, dma_1.mask) + + x = array([1, 2, 3], mask=True) + assert_equal(x._mask, [True, True, True]) + x = array([1, 2, 3], mask=False) + assert_equal(x._mask, [False, False, False]) + y = array([1, 2, 3], mask=x._mask, copy=False) + assert_(np.may_share_memory(x.mask, y.mask)) + y = array([1, 2, 3], mask=x._mask, copy=True) + assert_(not np.may_share_memory(x.mask, y.mask)) + + def test_creation_with_list_of_maskedarrays(self): + # Tests creating a masked array from a list of masked arrays. + x = array(np.arange(5), mask=[1, 0, 0, 0, 0]) + data = array((x, x[::-1])) + assert_equal(data, [[0, 1, 2, 3, 4], [4, 3, 2, 1, 0]]) + assert_equal(data._mask, [[1, 0, 0, 0, 0], [0, 0, 0, 0, 1]]) + + x.mask = nomask + data = array((x, x[::-1])) + assert_equal(data, [[0, 1, 2, 3, 4], [4, 3, 2, 1, 0]]) + assert_(data.mask is nomask) + + def test_creation_from_ndarray_with_padding(self): + x = np.array([('A', 0)], dtype={'names':['f0','f1'], + 'formats':['S4','i8'], + 'offsets':[0,8]}) + data = array(x) # used to fail due to 'V' padding field in x.dtype.descr + + def test_asarray(self): + (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d + xm.fill_value = -9999 + xm._hardmask = True + xmm = asarray(xm) + assert_equal(xmm._data, xm._data) + assert_equal(xmm._mask, xm._mask) + assert_equal(xmm.fill_value, xm.fill_value) + assert_equal(xmm._hardmask, xm._hardmask) + + def test_asarray_default_order(self): + # See Issue #6646 + m = np.eye(3).T + assert_(not m.flags.c_contiguous) + + new_m = asarray(m) + assert_(new_m.flags.c_contiguous) + + def test_asarray_enforce_order(self): + # See Issue #6646 + m = np.eye(3).T + assert_(not m.flags.c_contiguous) + + new_m = asarray(m, order='C') + assert_(new_m.flags.c_contiguous) + + def test_fix_invalid(self): + # Checks fix_invalid. + with np.errstate(invalid='ignore'): + data = masked_array([np.nan, 0., 1.], mask=[0, 0, 1]) + data_fixed = fix_invalid(data) + assert_equal(data_fixed._data, [data.fill_value, 0., 1.]) + assert_equal(data_fixed._mask, [1., 0., 1.]) + + def test_maskedelement(self): + # Test of masked element + x = arange(6) + x[1] = masked + assert_(str(masked) == '--') + assert_(x[1] is masked) + assert_equal(filled(x[1], 0), 0) + + def test_set_element_as_object(self): + # Tests setting elements with object + a = empty(1, dtype=object) + x = (1, 2, 3, 4, 5) + a[0] = x + assert_equal(a[0], x) + assert_(a[0] is x) + + import datetime + dt = datetime.datetime.now() + a[0] = dt + assert_(a[0] is dt) + + def test_indexing(self): + # Tests conversions and indexing + x1 = np.array([1, 2, 4, 3]) + x2 = array(x1, mask=[1, 0, 0, 0]) + x3 = array(x1, mask=[0, 1, 0, 1]) + x4 = array(x1) + # test conversion to strings + str(x2) # raises? + repr(x2) # raises? + assert_equal(np.sort(x1), sort(x2, endwith=False)) + # tests of indexing + assert_(type(x2[1]) is type(x1[1])) + assert_(x1[1] == x2[1]) + assert_(x2[0] is masked) + assert_equal(x1[2], x2[2]) + assert_equal(x1[2:5], x2[2:5]) + assert_equal(x1[:], x2[:]) + assert_equal(x1[1:], x3[1:]) + x1[2] = 9 + x2[2] = 9 + assert_equal(x1, x2) + x1[1:3] = 99 + x2[1:3] = 99 + assert_equal(x1, x2) + x2[1] = masked + assert_equal(x1, x2) + x2[1:3] = masked + assert_equal(x1, x2) + x2[:] = x1 + x2[1] = masked + assert_(allequal(getmask(x2), array([0, 1, 0, 0]))) + x3[:] = masked_array([1, 2, 3, 4], [0, 1, 1, 0]) + assert_(allequal(getmask(x3), array([0, 1, 1, 0]))) + x4[:] = masked_array([1, 2, 3, 4], [0, 1, 1, 0]) + assert_(allequal(getmask(x4), array([0, 1, 1, 0]))) + assert_(allequal(x4, array([1, 2, 3, 4]))) + x1 = np.arange(5) * 1.0 + x2 = masked_values(x1, 3.0) + assert_equal(x1, x2) + assert_(allequal(array([0, 0, 0, 1, 0], MaskType), x2.mask)) + assert_equal(3.0, x2.fill_value) + x1 = array([1, 'hello', 2, 3], object) + x2 = np.array([1, 'hello', 2, 3], object) + s1 = x1[1] + s2 = x2[1] + assert_equal(type(s2), str) + assert_equal(type(s1), str) + assert_equal(s1, s2) + assert_(x1[1:1].shape == (0,)) + + def test_matrix_indexing(self): + # Tests conversions and indexing + x1 = np.matrix([[1, 2, 3], [4, 3, 2]]) + x2 = array(x1, mask=[[1, 0, 0], [0, 1, 0]]) + x3 = array(x1, mask=[[0, 1, 0], [1, 0, 0]]) + x4 = array(x1) + # test conversion to strings + str(x2) # raises? + repr(x2) # raises? + # tests of indexing + assert_(type(x2[1, 0]) is type(x1[1, 0])) + assert_(x1[1, 0] == x2[1, 0]) + assert_(x2[1, 1] is masked) + assert_equal(x1[0, 2], x2[0, 2]) + assert_equal(x1[0, 1:], x2[0, 1:]) + assert_equal(x1[:, 2], x2[:, 2]) + assert_equal(x1[:], x2[:]) + assert_equal(x1[1:], x3[1:]) + x1[0, 2] = 9 + x2[0, 2] = 9 + assert_equal(x1, x2) + x1[0, 1:] = 99 + x2[0, 1:] = 99 + assert_equal(x1, x2) + x2[0, 1] = masked + assert_equal(x1, x2) + x2[0, 1:] = masked + assert_equal(x1, x2) + x2[0, :] = x1[0, :] + x2[0, 1] = masked + assert_(allequal(getmask(x2), np.array([[0, 1, 0], [0, 1, 0]]))) + x3[1, :] = masked_array([1, 2, 3], [1, 1, 0]) + assert_(allequal(getmask(x3)[1], array([1, 1, 0]))) + assert_(allequal(getmask(x3[1]), array([1, 1, 0]))) + x4[1, :] = masked_array([1, 2, 3], [1, 1, 0]) + assert_(allequal(getmask(x4[1]), array([1, 1, 0]))) + assert_(allequal(x4[1], array([1, 2, 3]))) + x1 = np.matrix(np.arange(5) * 1.0) + x2 = masked_values(x1, 3.0) + assert_equal(x1, x2) + assert_(allequal(array([0, 0, 0, 1, 0], MaskType), x2.mask)) + assert_equal(3.0, x2.fill_value) + + @suppress_copy_mask_on_assignment + def test_copy(self): + # Tests of some subtle points of copying and sizing. + n = [0, 0, 1, 0, 0] + m = make_mask(n) + m2 = make_mask(m) + assert_(m is m2) + m3 = make_mask(m, copy=1) + assert_(m is not m3) + + x1 = np.arange(5) + y1 = array(x1, mask=m) + assert_equal(y1._data.__array_interface__, x1.__array_interface__) + assert_(allequal(x1, y1.data)) + assert_equal(y1._mask.__array_interface__, m.__array_interface__) + + y1a = array(y1) + assert_(y1a._data.__array_interface__ == + y1._data.__array_interface__) + assert_(y1a.mask is y1.mask) + + y2 = array(x1, mask=m3) + assert_(y2._data.__array_interface__ == x1.__array_interface__) + assert_(y2._mask.__array_interface__ == m3.__array_interface__) + assert_(y2[2] is masked) + y2[2] = 9 + assert_(y2[2] is not masked) + assert_(y2._mask.__array_interface__ == m3.__array_interface__) + assert_(allequal(y2.mask, 0)) + + y2a = array(x1, mask=m, copy=1) + assert_(y2a._data.__array_interface__ != x1.__array_interface__) + #assert_( y2a.mask is not m) + assert_(y2a._mask.__array_interface__ != m.__array_interface__) + assert_(y2a[2] is masked) + y2a[2] = 9 + assert_(y2a[2] is not masked) + #assert_( y2a.mask is not m) + assert_(y2a._mask.__array_interface__ != m.__array_interface__) + assert_(allequal(y2a.mask, 0)) + + y3 = array(x1 * 1.0, mask=m) + assert_(filled(y3).dtype is (x1 * 1.0).dtype) + + x4 = arange(4) + x4[2] = masked + y4 = resize(x4, (8,)) + assert_equal(concatenate([x4, x4]), y4) + assert_equal(getmask(y4), [0, 0, 1, 0, 0, 0, 1, 0]) + y5 = repeat(x4, (2, 2, 2, 2), axis=0) + assert_equal(y5, [0, 0, 1, 1, 2, 2, 3, 3]) + y6 = repeat(x4, 2, axis=0) + assert_equal(y5, y6) + y7 = x4.repeat((2, 2, 2, 2), axis=0) + assert_equal(y5, y7) + y8 = x4.repeat(2, 0) + assert_equal(y5, y8) + + y9 = x4.copy() + assert_equal(y9._data, x4._data) + assert_equal(y9._mask, x4._mask) + + x = masked_array([1, 2, 3], mask=[0, 1, 0]) + # Copy is False by default + y = masked_array(x) + assert_equal(y._data.ctypes.data, x._data.ctypes.data) + assert_equal(y._mask.ctypes.data, x._mask.ctypes.data) + y = masked_array(x, copy=True) + assert_not_equal(y._data.ctypes.data, x._data.ctypes.data) + assert_not_equal(y._mask.ctypes.data, x._mask.ctypes.data) + + def test_copy_0d(self): + # gh-9430 + x = np.ma.array(43, mask=True) + xc = x.copy() + assert_equal(xc.mask, True) + + def test_copy_on_python_builtins(self): + # Tests copy works on python builtins (issue#8019) + assert_(isMaskedArray(np.ma.copy([1,2,3]))) + assert_(isMaskedArray(np.ma.copy((1,2,3)))) + + def test_copy_immutable(self): + # Tests that the copy method is immutable, GitHub issue #5247 + a = np.ma.array([1, 2, 3]) + b = np.ma.array([4, 5, 6]) + a_copy_method = a.copy + b.copy + assert_equal(a_copy_method(), [1, 2, 3]) + + def test_deepcopy(self): + from copy import deepcopy + a = array([0, 1, 2], mask=[False, True, False]) + copied = deepcopy(a) + assert_equal(copied.mask, a.mask) + assert_not_equal(id(a._mask), id(copied._mask)) + + copied[1] = 1 + assert_equal(copied.mask, [0, 0, 0]) + assert_equal(a.mask, [0, 1, 0]) + + copied = deepcopy(a) + assert_equal(copied.mask, a.mask) + copied.mask[1] = False + assert_equal(copied.mask, [0, 0, 0]) + assert_equal(a.mask, [0, 1, 0]) + + def test_str_repr(self): + a = array([0, 1, 2], mask=[False, True, False]) + assert_equal(str(a), '[0 -- 2]') + assert_equal( + repr(a), + textwrap.dedent('''\ + masked_array(data=[0, --, 2], + mask=[False, True, False], + fill_value=999999)''') + ) + + # arrays with a continuation + a = np.ma.arange(2000) + a[1:50] = np.ma.masked + assert_equal( + repr(a), + textwrap.dedent('''\ + masked_array(data=[0, --, --, ..., 1997, 1998, 1999], + mask=[False, True, True, ..., False, False, False], + fill_value=999999)''') + ) + + # line-wrapped 1d arrays are correctly aligned + a = np.ma.arange(20) + assert_equal( + repr(a), + textwrap.dedent('''\ + masked_array(data=[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19], + mask=False, + fill_value=999999)''') + ) + + # 2d arrays cause wrapping + a = array([[1, 2, 3], [4, 5, 6]], dtype=np.int8) + a[1,1] = np.ma.masked + assert_equal( + repr(a), + textwrap.dedent('''\ + masked_array( + data=[[1, 2, 3], + [4, --, 6]], + mask=[[False, False, False], + [False, True, False]], + fill_value=999999, + dtype=int8)''') + ) + + # but not it they're a row vector + assert_equal( + repr(a[:1]), + textwrap.dedent('''\ + masked_array(data=[[1, 2, 3]], + mask=[[False, False, False]], + fill_value=999999, + dtype=int8)''') + ) + + # dtype=int is implied, so not shown + assert_equal( + repr(a.astype(int)), + textwrap.dedent('''\ + masked_array( + data=[[1, 2, 3], + [4, --, 6]], + mask=[[False, False, False], + [False, True, False]], + fill_value=999999)''') + ) + + + + def test_str_repr_legacy(self): + oldopts = np.get_printoptions() + np.set_printoptions(legacy='1.13') + try: + a = array([0, 1, 2], mask=[False, True, False]) + assert_equal(str(a), '[0 -- 2]') + assert_equal(repr(a), 'masked_array(data = [0 -- 2],\n' + ' mask = [False True False],\n' + ' fill_value = 999999)\n') + + a = np.ma.arange(2000) + a[1:50] = np.ma.masked + assert_equal( + repr(a), + 'masked_array(data = [0 -- -- ..., 1997 1998 1999],\n' + ' mask = [False True True ..., False False False],\n' + ' fill_value = 999999)\n' + ) + finally: + np.set_printoptions(**oldopts) + + def test_0d_unicode(self): + u = u'caf\xe9' + utype = type(u) + + arr_nomask = np.ma.array(u) + arr_masked = np.ma.array(u, mask=True) + + assert_equal(utype(arr_nomask), u) + assert_equal(utype(arr_masked), u'--') + + def test_pickling(self): + # Tests pickling + for dtype in (int, float, str, object): + a = arange(10).astype(dtype) + a.fill_value = 999 + + masks = ([0, 0, 0, 1, 0, 1, 0, 1, 0, 1], # partially masked + True, # Fully masked + False) # Fully unmasked + + for mask in masks: + a.mask = mask + a_pickled = pickle.loads(a.dumps()) + assert_equal(a_pickled._mask, a._mask) + assert_equal(a_pickled._data, a._data) + if dtype in (object, int): + assert_equal(a_pickled.fill_value, 999) + else: + assert_equal(a_pickled.fill_value, dtype(999)) + assert_array_equal(a_pickled.mask, mask) + + def test_pickling_subbaseclass(self): + # Test pickling w/ a subclass of ndarray + a = array(np.matrix(list(range(10))), mask=[1, 0, 1, 0, 0] * 2) + a_pickled = pickle.loads(a.dumps()) + assert_equal(a_pickled._mask, a._mask) + assert_equal(a_pickled, a) + assert_(isinstance(a_pickled._data, np.matrix)) + + def test_pickling_maskedconstant(self): + # Test pickling MaskedConstant + mc = np.ma.masked + mc_pickled = pickle.loads(mc.dumps()) + assert_equal(mc_pickled._baseclass, mc._baseclass) + assert_equal(mc_pickled._mask, mc._mask) + assert_equal(mc_pickled._data, mc._data) + + def test_pickling_wstructured(self): + # Tests pickling w/ structured array + a = array([(1, 1.), (2, 2.)], mask=[(0, 0), (0, 1)], + dtype=[('a', int), ('b', float)]) + a_pickled = pickle.loads(a.dumps()) + assert_equal(a_pickled._mask, a._mask) + assert_equal(a_pickled, a) + + def test_pickling_keepalignment(self): + # Tests pickling w/ F_CONTIGUOUS arrays + a = arange(10) + a.shape = (-1, 2) + b = a.T + test = pickle.loads(pickle.dumps(b)) + assert_equal(test, b) + + def test_single_element_subscript(self): + # Tests single element subscripts of Maskedarrays. + a = array([1, 3, 2]) + b = array([1, 3, 2], mask=[1, 0, 1]) + assert_equal(a[0].shape, ()) + assert_equal(b[0].shape, ()) + assert_equal(b[1].shape, ()) + + def test_topython(self): + # Tests some communication issues with Python. + assert_equal(1, int(array(1))) + assert_equal(1.0, float(array(1))) + assert_equal(1, int(array([[[1]]]))) + assert_equal(1.0, float(array([[1]]))) + assert_raises(TypeError, float, array([1, 1])) + + with suppress_warnings() as sup: + sup.filter(UserWarning, 'Warning: converting a masked element') + assert_(np.isnan(float(array([1], mask=[1])))) + + a = array([1, 2, 3], mask=[1, 0, 0]) + assert_raises(TypeError, lambda: float(a)) + assert_equal(float(a[-1]), 3.) + assert_(np.isnan(float(a[0]))) + assert_raises(TypeError, int, a) + assert_equal(int(a[-1]), 3) + assert_raises(MAError, lambda:int(a[0])) + + def test_oddfeatures_1(self): + # Test of other odd features + x = arange(20) + x = x.reshape(4, 5) + x.flat[5] = 12 + assert_(x[1, 0] == 12) + z = x + 10j * x + assert_equal(z.real, x) + assert_equal(z.imag, 10 * x) + assert_equal((z * conjugate(z)).real, 101 * x * x) + z.imag[...] = 0.0 + + x = arange(10) + x[3] = masked + assert_(str(x[3]) == str(masked)) + c = x >= 8 + assert_(count(where(c, masked, masked)) == 0) + assert_(shape(where(c, masked, masked)) == c.shape) + + z = masked_where(c, x) + assert_(z.dtype is x.dtype) + assert_(z[3] is masked) + assert_(z[4] is not masked) + assert_(z[7] is not masked) + assert_(z[8] is masked) + assert_(z[9] is masked) + assert_equal(x, z) + + def test_oddfeatures_2(self): + # Tests some more features. + x = array([1., 2., 3., 4., 5.]) + c = array([1, 1, 1, 0, 0]) + x[2] = masked + z = where(c, x, -x) + assert_equal(z, [1., 2., 0., -4., -5]) + c[0] = masked + z = where(c, x, -x) + assert_equal(z, [1., 2., 0., -4., -5]) + assert_(z[0] is masked) + assert_(z[1] is not masked) + assert_(z[2] is masked) + + @suppress_copy_mask_on_assignment + def test_oddfeatures_3(self): + # Tests some generic features + atest = array([10], mask=True) + btest = array([20]) + idx = atest.mask + atest[idx] = btest[idx] + assert_equal(atest, [20]) + + def test_filled_with_object_dtype(self): + a = np.ma.masked_all(1, dtype='O') + assert_equal(a.filled('x')[0], 'x') + + def test_filled_with_flexible_dtype(self): + # Test filled w/ flexible dtype + flexi = array([(1, 1, 1)], + dtype=[('i', int), ('s', '|S8'), ('f', float)]) + flexi[0] = masked + assert_equal(flexi.filled(), + np.array([(default_fill_value(0), + default_fill_value('0'), + default_fill_value(0.),)], dtype=flexi.dtype)) + flexi[0] = masked + assert_equal(flexi.filled(1), + np.array([(1, '1', 1.)], dtype=flexi.dtype)) + + def test_filled_with_mvoid(self): + # Test filled w/ mvoid + ndtype = [('a', int), ('b', float)] + a = mvoid((1, 2.), mask=[(0, 1)], dtype=ndtype) + # Filled using default + test = a.filled() + assert_equal(tuple(test), (1, default_fill_value(1.))) + # Explicit fill_value + test = a.filled((-1, -1)) + assert_equal(tuple(test), (1, -1)) + # Using predefined filling values + a.fill_value = (-999, -999) + assert_equal(tuple(a.filled()), (1, -999)) + + def test_filled_with_nested_dtype(self): + # Test filled w/ nested dtype + ndtype = [('A', int), ('B', [('BA', int), ('BB', int)])] + a = array([(1, (1, 1)), (2, (2, 2))], + mask=[(0, (1, 0)), (0, (0, 1))], dtype=ndtype) + test = a.filled(0) + control = np.array([(1, (0, 1)), (2, (2, 0))], dtype=ndtype) + assert_equal(test, control) + + test = a['B'].filled(0) + control = np.array([(0, 1), (2, 0)], dtype=a['B'].dtype) + assert_equal(test, control) + + # test if mask gets set correctly (see #6760) + Z = numpy.ma.zeros(2, numpy.dtype([("A", "(2,2)i1,(2,2)i1", (2,2))])) + assert_equal(Z.data.dtype, numpy.dtype([('A', [('f0', 'i1', (2, 2)), + ('f1', 'i1', (2, 2))], (2, 2))])) + assert_equal(Z.mask.dtype, numpy.dtype([('A', [('f0', '?', (2, 2)), + ('f1', '?', (2, 2))], (2, 2))])) + + def test_filled_with_f_order(self): + # Test filled w/ F-contiguous array + a = array(np.array([(0, 1, 2), (4, 5, 6)], order='F'), + mask=np.array([(0, 0, 1), (1, 0, 0)], order='F'), + order='F') # this is currently ignored + assert_(a.flags['F_CONTIGUOUS']) + assert_(a.filled(0).flags['F_CONTIGUOUS']) + + def test_optinfo_propagation(self): + # Checks that _optinfo dictionary isn't back-propagated + x = array([1, 2, 3, ], dtype=float) + x._optinfo['info'] = '???' + y = x.copy() + assert_equal(y._optinfo['info'], '???') + y._optinfo['info'] = '!!!' + assert_equal(x._optinfo['info'], '???') + + def test_optinfo_forward_propagation(self): + a = array([1,2,2,4]) + a._optinfo["key"] = "value" + assert_equal(a._optinfo["key"], (a == 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], (a != 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], (a > 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], (a >= 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], (a <= 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], (a + 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], (a - 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], (a * 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], (a / 2)._optinfo["key"]) + assert_equal(a._optinfo["key"], a[:2]._optinfo["key"]) + assert_equal(a._optinfo["key"], a[[0,0,2]]._optinfo["key"]) + assert_equal(a._optinfo["key"], np.exp(a)._optinfo["key"]) + assert_equal(a._optinfo["key"], np.abs(a)._optinfo["key"]) + assert_equal(a._optinfo["key"], array(a, copy=True)._optinfo["key"]) + assert_equal(a._optinfo["key"], np.zeros_like(a)._optinfo["key"]) + + def test_fancy_printoptions(self): + # Test printing a masked array w/ fancy dtype. + fancydtype = np.dtype([('x', int), ('y', [('t', int), ('s', float)])]) + test = array([(1, (2, 3.0)), (4, (5, 6.0))], + mask=[(1, (0, 1)), (0, (1, 0))], + dtype=fancydtype) + control = "[(--, (2, --)) (4, (--, 6.0))]" + assert_equal(str(test), control) + + # Test 0-d array with multi-dimensional dtype + t_2d0 = masked_array(data = (0, [[0.0, 0.0, 0.0], + [0.0, 0.0, 0.0]], + 0.0), + mask = (False, [[True, False, True], + [False, False, True]], + False), + dtype = "int, (2,3)float, float") + control = "(0, [[--, 0.0, --], [0.0, 0.0, --]], 0.0)" + assert_equal(str(t_2d0), control) + + + def test_flatten_structured_array(self): + # Test flatten_structured_array on arrays + # On ndarray + ndtype = [('a', int), ('b', float)] + a = np.array([(1, 1), (2, 2)], dtype=ndtype) + test = flatten_structured_array(a) + control = np.array([[1., 1.], [2., 2.]], dtype=float) + assert_equal(test, control) + assert_equal(test.dtype, control.dtype) + # On masked_array + a = array([(1, 1), (2, 2)], mask=[(0, 1), (1, 0)], dtype=ndtype) + test = flatten_structured_array(a) + control = array([[1., 1.], [2., 2.]], + mask=[[0, 1], [1, 0]], dtype=float) + assert_equal(test, control) + assert_equal(test.dtype, control.dtype) + assert_equal(test.mask, control.mask) + # On masked array with nested structure + ndtype = [('a', int), ('b', [('ba', int), ('bb', float)])] + a = array([(1, (1, 1.1)), (2, (2, 2.2))], + mask=[(0, (1, 0)), (1, (0, 1))], dtype=ndtype) + test = flatten_structured_array(a) + control = array([[1., 1., 1.1], [2., 2., 2.2]], + mask=[[0, 1, 0], [1, 0, 1]], dtype=float) + assert_equal(test, control) + assert_equal(test.dtype, control.dtype) + assert_equal(test.mask, control.mask) + # Keeping the initial shape + ndtype = [('a', int), ('b', float)] + a = np.array([[(1, 1), ], [(2, 2), ]], dtype=ndtype) + test = flatten_structured_array(a) + control = np.array([[[1., 1.], ], [[2., 2.], ]], dtype=float) + assert_equal(test, control) + assert_equal(test.dtype, control.dtype) + + def test_void0d(self): + # Test creating a mvoid object + ndtype = [('a', int), ('b', int)] + a = np.array([(1, 2,)], dtype=ndtype)[0] + f = mvoid(a) + assert_(isinstance(f, mvoid)) + + a = masked_array([(1, 2)], mask=[(1, 0)], dtype=ndtype)[0] + assert_(isinstance(a, mvoid)) + + a = masked_array([(1, 2), (1, 2)], mask=[(1, 0), (0, 0)], dtype=ndtype) + f = mvoid(a._data[0], a._mask[0]) + assert_(isinstance(f, mvoid)) + + def test_mvoid_getitem(self): + # Test mvoid.__getitem__ + ndtype = [('a', int), ('b', int)] + a = masked_array([(1, 2,), (3, 4)], mask=[(0, 0), (1, 0)], + dtype=ndtype) + # w/o mask + f = a[0] + assert_(isinstance(f, mvoid)) + assert_equal((f[0], f['a']), (1, 1)) + assert_equal(f['b'], 2) + # w/ mask + f = a[1] + assert_(isinstance(f, mvoid)) + assert_(f[0] is masked) + assert_(f['a'] is masked) + assert_equal(f[1], 4) + + # exotic dtype + A = masked_array(data=[([0,1],)], + mask=[([True, False],)], + dtype=[("A", ">i2", (2,))]) + assert_equal(A[0]["A"], A["A"][0]) + assert_equal(A[0]["A"], masked_array(data=[0, 1], + mask=[True, False], dtype=">i2")) + + def test_mvoid_iter(self): + # Test iteration on __getitem__ + ndtype = [('a', int), ('b', int)] + a = masked_array([(1, 2,), (3, 4)], mask=[(0, 0), (1, 0)], + dtype=ndtype) + # w/o mask + assert_equal(list(a[0]), [1, 2]) + # w/ mask + assert_equal(list(a[1]), [masked, 4]) + + def test_mvoid_print(self): + # Test printing a mvoid + mx = array([(1, 1), (2, 2)], dtype=[('a', int), ('b', int)]) + assert_equal(str(mx[0]), "(1, 1)") + mx['b'][0] = masked + ini_display = masked_print_option._display + masked_print_option.set_display("-X-") + try: + assert_equal(str(mx[0]), "(1, -X-)") + assert_equal(repr(mx[0]), "(1, -X-)") + finally: + masked_print_option.set_display(ini_display) + + # also check if there are object datatypes (see gh-7493) + mx = array([(1,), (2,)], dtype=[('a', 'O')]) + assert_equal(str(mx[0]), "(1,)") + + def test_mvoid_multidim_print(self): + + # regression test for gh-6019 + t_ma = masked_array(data = [([1, 2, 3],)], + mask = [([False, True, False],)], + fill_value = ([999999, 999999, 999999],), + dtype = [('a', ' 1: + assert_equal(np.concatenate((x, y), 1), concatenate((xm, ym), 1)) + assert_equal(np.add.reduce(x, 1), add.reduce(x, 1)) + assert_equal(np.sum(x, 1), sum(x, 1)) + assert_equal(np.product(x, 1), product(x, 1)) + + def test_binops_d2D(self): + # Test binary operations on 2D data + a = array([[1.], [2.], [3.]], mask=[[False], [True], [True]]) + b = array([[2., 3.], [4., 5.], [6., 7.]]) + + test = a * b + control = array([[2., 3.], [2., 2.], [3., 3.]], + mask=[[0, 0], [1, 1], [1, 1]]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + test = b * a + control = array([[2., 3.], [4., 5.], [6., 7.]], + mask=[[0, 0], [1, 1], [1, 1]]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + a = array([[1.], [2.], [3.]]) + b = array([[2., 3.], [4., 5.], [6., 7.]], + mask=[[0, 0], [0, 0], [0, 1]]) + test = a * b + control = array([[2, 3], [8, 10], [18, 3]], + mask=[[0, 0], [0, 0], [0, 1]]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + test = b * a + control = array([[2, 3], [8, 10], [18, 7]], + mask=[[0, 0], [0, 0], [0, 1]]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + def test_domained_binops_d2D(self): + # Test domained binary operations on 2D data + a = array([[1.], [2.], [3.]], mask=[[False], [True], [True]]) + b = array([[2., 3.], [4., 5.], [6., 7.]]) + + test = a / b + control = array([[1. / 2., 1. / 3.], [2., 2.], [3., 3.]], + mask=[[0, 0], [1, 1], [1, 1]]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + test = b / a + control = array([[2. / 1., 3. / 1.], [4., 5.], [6., 7.]], + mask=[[0, 0], [1, 1], [1, 1]]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + a = array([[1.], [2.], [3.]]) + b = array([[2., 3.], [4., 5.], [6., 7.]], + mask=[[0, 0], [0, 0], [0, 1]]) + test = a / b + control = array([[1. / 2, 1. / 3], [2. / 4, 2. / 5], [3. / 6, 3]], + mask=[[0, 0], [0, 0], [0, 1]]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + test = b / a + control = array([[2 / 1., 3 / 1.], [4 / 2., 5 / 2.], [6 / 3., 7]], + mask=[[0, 0], [0, 0], [0, 1]]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + def test_noshrinking(self): + # Check that we don't shrink a mask when not wanted + # Binary operations + a = masked_array([1., 2., 3.], mask=[False, False, False], + shrink=False) + b = a + 1 + assert_equal(b.mask, [0, 0, 0]) + # In place binary operation + a += 1 + assert_equal(a.mask, [0, 0, 0]) + # Domained binary operation + b = a / 1. + assert_equal(b.mask, [0, 0, 0]) + # In place binary operation + a /= 1. + assert_equal(a.mask, [0, 0, 0]) + + def test_ufunc_nomask(self): + # check the case ufuncs should set the mask to false + m = np.ma.array([1]) + # check we don't get array([False], dtype=bool) + assert_equal(np.true_divide(m, 5).mask.shape, ()) + + def test_noshink_on_creation(self): + # Check that the mask is not shrunk on array creation when not wanted + a = np.ma.masked_values([1., 2.5, 3.1], 1.5, shrink=False) + assert_equal(a.mask, [0, 0, 0]) + + def test_mod(self): + # Tests mod + (x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d + assert_equal(mod(x, y), mod(xm, ym)) + test = mod(ym, xm) + assert_equal(test, np.mod(ym, xm)) + assert_equal(test.mask, mask_or(xm.mask, ym.mask)) + test = mod(xm, ym) + assert_equal(test, np.mod(xm, ym)) + assert_equal(test.mask, mask_or(mask_or(xm.mask, ym.mask), (ym == 0))) + + def test_TakeTransposeInnerOuter(self): + # Test of take, transpose, inner, outer products + x = arange(24) + y = np.arange(24) + x[5:6] = masked + x = x.reshape(2, 3, 4) + y = y.reshape(2, 3, 4) + assert_equal(np.transpose(y, (2, 0, 1)), transpose(x, (2, 0, 1))) + assert_equal(np.take(y, (2, 0, 1), 1), take(x, (2, 0, 1), 1)) + assert_equal(np.inner(filled(x, 0), filled(y, 0)), + inner(x, y)) + assert_equal(np.outer(filled(x, 0), filled(y, 0)), + outer(x, y)) + y = array(['abc', 1, 'def', 2, 3], object) + y[2] = masked + t = take(y, [0, 3, 4]) + assert_(t[0] == 'abc') + assert_(t[1] == 2) + assert_(t[2] == 3) + + def test_imag_real(self): + # Check complex + xx = array([1 + 10j, 20 + 2j], mask=[1, 0]) + assert_equal(xx.imag, [10, 2]) + assert_equal(xx.imag.filled(), [1e+20, 2]) + assert_equal(xx.imag.dtype, xx._data.imag.dtype) + assert_equal(xx.real, [1, 20]) + assert_equal(xx.real.filled(), [1e+20, 20]) + assert_equal(xx.real.dtype, xx._data.real.dtype) + + def test_methods_with_output(self): + xm = array(np.random.uniform(0, 10, 12)).reshape(3, 4) + xm[:, 0] = xm[0] = xm[-1, -1] = masked + + funclist = ('sum', 'prod', 'var', 'std', 'max', 'min', 'ptp', 'mean',) + + for funcname in funclist: + npfunc = getattr(np, funcname) + xmmeth = getattr(xm, funcname) + # A ndarray as explicit input + output = np.empty(4, dtype=float) + output.fill(-9999) + result = npfunc(xm, axis=0, out=output) + # ... the result should be the given output + assert_(result is output) + assert_equal(result, xmmeth(axis=0, out=output)) + + output = empty(4, dtype=int) + result = xmmeth(axis=0, out=output) + assert_(result is output) + assert_(output[0] is masked) + + def test_count_mean_with_matrix(self): + m = np.ma.array(np.matrix([[1,2],[3,4]]), mask=np.zeros((2,2))) + + assert_equal(m.count(axis=0).shape, (1,2)) + assert_equal(m.count(axis=1).shape, (2,1)) + + #make sure broadcasting inside mean and var work + assert_equal(m.mean(axis=0), [[2., 3.]]) + assert_equal(m.mean(axis=1), [[1.5], [3.5]]) + + def test_eq_on_structured(self): + # Test the equality of structured arrays + ndtype = [('A', int), ('B', int)] + a = array([(1, 1), (2, 2)], mask=[(0, 1), (0, 0)], dtype=ndtype) + test = (a == a) + assert_equal(test.data, [True, True]) + assert_equal(test.mask, [False, False]) + test = (a == a[0]) + assert_equal(test.data, [True, False]) + assert_equal(test.mask, [False, False]) + b = array([(1, 1), (2, 2)], mask=[(1, 0), (0, 0)], dtype=ndtype) + test = (a == b) + assert_equal(test.data, [False, True]) + assert_equal(test.mask, [True, False]) + test = (a[0] == b) + assert_equal(test.data, [False, False]) + assert_equal(test.mask, [True, False]) + b = array([(1, 1), (2, 2)], mask=[(0, 1), (1, 0)], dtype=ndtype) + test = (a == b) + assert_equal(test.data, [True, True]) + assert_equal(test.mask, [False, False]) + # complicated dtype, 2-dimensional array. + ndtype = [('A', int), ('B', [('BA', int), ('BB', int)])] + a = array([[(1, (1, 1)), (2, (2, 2))], + [(3, (3, 3)), (4, (4, 4))]], + mask=[[(0, (1, 0)), (0, (0, 1))], + [(1, (0, 0)), (1, (1, 1))]], dtype=ndtype) + test = (a[0, 0] == a) + assert_equal(test.data, [[True, False], [False, False]]) + assert_equal(test.mask, [[False, False], [False, True]]) + + def test_ne_on_structured(self): + # Test the equality of structured arrays + ndtype = [('A', int), ('B', int)] + a = array([(1, 1), (2, 2)], mask=[(0, 1), (0, 0)], dtype=ndtype) + test = (a != a) + assert_equal(test.data, [False, False]) + assert_equal(test.mask, [False, False]) + test = (a != a[0]) + assert_equal(test.data, [False, True]) + assert_equal(test.mask, [False, False]) + b = array([(1, 1), (2, 2)], mask=[(1, 0), (0, 0)], dtype=ndtype) + test = (a != b) + assert_equal(test.data, [True, False]) + assert_equal(test.mask, [True, False]) + test = (a[0] != b) + assert_equal(test.data, [True, True]) + assert_equal(test.mask, [True, False]) + b = array([(1, 1), (2, 2)], mask=[(0, 1), (1, 0)], dtype=ndtype) + test = (a != b) + assert_equal(test.data, [False, False]) + assert_equal(test.mask, [False, False]) + # complicated dtype, 2-dimensional array. + ndtype = [('A', int), ('B', [('BA', int), ('BB', int)])] + a = array([[(1, (1, 1)), (2, (2, 2))], + [(3, (3, 3)), (4, (4, 4))]], + mask=[[(0, (1, 0)), (0, (0, 1))], + [(1, (0, 0)), (1, (1, 1))]], dtype=ndtype) + test = (a[0, 0] != a) + assert_equal(test.data, [[False, True], [True, True]]) + assert_equal(test.mask, [[False, False], [False, True]]) + + def test_eq_ne_structured_extra(self): + # ensure simple examples are symmetric and make sense. + # from https://github.com/numpy/numpy/pull/8590#discussion_r101126465 + dt = np.dtype('i4,i4') + for m1 in (mvoid((1, 2), mask=(0, 0), dtype=dt), + mvoid((1, 2), mask=(0, 1), dtype=dt), + mvoid((1, 2), mask=(1, 0), dtype=dt), + mvoid((1, 2), mask=(1, 1), dtype=dt)): + ma1 = m1.view(MaskedArray) + r1 = ma1.view('2i4') + for m2 in (np.array((1, 1), dtype=dt), + mvoid((1, 1), dtype=dt), + mvoid((1, 0), mask=(0, 1), dtype=dt), + mvoid((3, 2), mask=(0, 1), dtype=dt)): + ma2 = m2.view(MaskedArray) + r2 = ma2.view('2i4') + eq_expected = (r1 == r2).all() + assert_equal(m1 == m2, eq_expected) + assert_equal(m2 == m1, eq_expected) + assert_equal(ma1 == m2, eq_expected) + assert_equal(m1 == ma2, eq_expected) + assert_equal(ma1 == ma2, eq_expected) + # Also check it is the same if we do it element by element. + el_by_el = [m1[name] == m2[name] for name in dt.names] + assert_equal(array(el_by_el, dtype=bool).all(), eq_expected) + ne_expected = (r1 != r2).any() + assert_equal(m1 != m2, ne_expected) + assert_equal(m2 != m1, ne_expected) + assert_equal(ma1 != m2, ne_expected) + assert_equal(m1 != ma2, ne_expected) + assert_equal(ma1 != ma2, ne_expected) + el_by_el = [m1[name] != m2[name] for name in dt.names] + assert_equal(array(el_by_el, dtype=bool).any(), ne_expected) + + def test_eq_with_None(self): + # Really, comparisons with None should not be done, but check them + # anyway. Note that pep8 will flag these tests. + # Deprecation is in place for arrays, and when it happens this + # test will fail (and have to be changed accordingly). + + # With partial mask + with suppress_warnings() as sup: + sup.filter(FutureWarning, "Comparison to `None`") + a = array([None, 1], mask=[0, 1]) + assert_equal(a == None, array([True, False], mask=[0, 1])) + assert_equal(a.data == None, [True, False]) + assert_equal(a != None, array([False, True], mask=[0, 1])) + # With nomask + a = array([None, 1], mask=False) + assert_equal(a == None, [True, False]) + assert_equal(a != None, [False, True]) + # With complete mask + a = array([None, 2], mask=True) + assert_equal(a == None, array([False, True], mask=True)) + assert_equal(a != None, array([True, False], mask=True)) + # Fully masked, even comparison to None should return "masked" + a = masked + assert_equal(a == None, masked) + + def test_eq_with_scalar(self): + a = array(1) + assert_equal(a == 1, True) + assert_equal(a == 0, False) + assert_equal(a != 1, False) + assert_equal(a != 0, True) + b = array(1, mask=True) + assert_equal(b == 0, masked) + assert_equal(b == 1, masked) + assert_equal(b != 0, masked) + assert_equal(b != 1, masked) + + def test_eq_different_dimensions(self): + m1 = array([1, 1], mask=[0, 1]) + # test comparison with both masked and regular arrays. + for m2 in (array([[0, 1], [1, 2]]), + np.array([[0, 1], [1, 2]])): + test = (m1 == m2) + assert_equal(test.data, [[False, False], + [True, False]]) + assert_equal(test.mask, [[False, True], + [False, True]]) + + def test_numpyarithmetics(self): + # Check that the mask is not back-propagated when using numpy functions + a = masked_array([-1, 0, 1, 2, 3], mask=[0, 0, 0, 0, 1]) + control = masked_array([np.nan, np.nan, 0, np.log(2), -1], + mask=[1, 1, 0, 0, 1]) + + test = log(a) + assert_equal(test, control) + assert_equal(test.mask, control.mask) + assert_equal(a.mask, [0, 0, 0, 0, 1]) + + test = np.log(a) + assert_equal(test, control) + assert_equal(test.mask, control.mask) + assert_equal(a.mask, [0, 0, 0, 0, 1]) + + +class TestMaskedArrayAttributes(object): + + def test_keepmask(self): + # Tests the keep mask flag + x = masked_array([1, 2, 3], mask=[1, 0, 0]) + mx = masked_array(x) + assert_equal(mx.mask, x.mask) + mx = masked_array(x, mask=[0, 1, 0], keep_mask=False) + assert_equal(mx.mask, [0, 1, 0]) + mx = masked_array(x, mask=[0, 1, 0], keep_mask=True) + assert_equal(mx.mask, [1, 1, 0]) + # We default to true + mx = masked_array(x, mask=[0, 1, 0]) + assert_equal(mx.mask, [1, 1, 0]) + + def test_hardmask(self): + # Test hard_mask + d = arange(5) + n = [0, 0, 0, 1, 1] + m = make_mask(n) + xh = array(d, mask=m, hard_mask=True) + # We need to copy, to avoid updating d in xh ! + xs = array(d, mask=m, hard_mask=False, copy=True) + xh[[1, 4]] = [10, 40] + xs[[1, 4]] = [10, 40] + assert_equal(xh._data, [0, 10, 2, 3, 4]) + assert_equal(xs._data, [0, 10, 2, 3, 40]) + assert_equal(xs.mask, [0, 0, 0, 1, 0]) + assert_(xh._hardmask) + assert_(not xs._hardmask) + xh[1:4] = [10, 20, 30] + xs[1:4] = [10, 20, 30] + assert_equal(xh._data, [0, 10, 20, 3, 4]) + assert_equal(xs._data, [0, 10, 20, 30, 40]) + assert_equal(xs.mask, nomask) + xh[0] = masked + xs[0] = masked + assert_equal(xh.mask, [1, 0, 0, 1, 1]) + assert_equal(xs.mask, [1, 0, 0, 0, 0]) + xh[:] = 1 + xs[:] = 1 + assert_equal(xh._data, [0, 1, 1, 3, 4]) + assert_equal(xs._data, [1, 1, 1, 1, 1]) + assert_equal(xh.mask, [1, 0, 0, 1, 1]) + assert_equal(xs.mask, nomask) + # Switch to soft mask + xh.soften_mask() + xh[:] = arange(5) + assert_equal(xh._data, [0, 1, 2, 3, 4]) + assert_equal(xh.mask, nomask) + # Switch back to hard mask + xh.harden_mask() + xh[xh < 3] = masked + assert_equal(xh._data, [0, 1, 2, 3, 4]) + assert_equal(xh._mask, [1, 1, 1, 0, 0]) + xh[filled(xh > 1, False)] = 5 + assert_equal(xh._data, [0, 1, 2, 5, 5]) + assert_equal(xh._mask, [1, 1, 1, 0, 0]) + + xh = array([[1, 2], [3, 4]], mask=[[1, 0], [0, 0]], hard_mask=True) + xh[0] = 0 + assert_equal(xh._data, [[1, 0], [3, 4]]) + assert_equal(xh._mask, [[1, 0], [0, 0]]) + xh[-1, -1] = 5 + assert_equal(xh._data, [[1, 0], [3, 5]]) + assert_equal(xh._mask, [[1, 0], [0, 0]]) + xh[filled(xh < 5, False)] = 2 + assert_equal(xh._data, [[1, 2], [2, 5]]) + assert_equal(xh._mask, [[1, 0], [0, 0]]) + + def test_hardmask_again(self): + # Another test of hardmask + d = arange(5) + n = [0, 0, 0, 1, 1] + m = make_mask(n) + xh = array(d, mask=m, hard_mask=True) + xh[4:5] = 999 + xh[0:1] = 999 + assert_equal(xh._data, [999, 1, 2, 3, 4]) + + def test_hardmask_oncemore_yay(self): + # OK, yet another test of hardmask + # Make sure that harden_mask/soften_mask//unshare_mask returns self + a = array([1, 2, 3], mask=[1, 0, 0]) + b = a.harden_mask() + assert_equal(a, b) + b[0] = 0 + assert_equal(a, b) + assert_equal(b, array([1, 2, 3], mask=[1, 0, 0])) + a = b.soften_mask() + a[0] = 0 + assert_equal(a, b) + assert_equal(b, array([0, 2, 3], mask=[0, 0, 0])) + + def test_smallmask(self): + # Checks the behaviour of _smallmask + a = arange(10) + a[1] = masked + a[1] = 1 + assert_equal(a._mask, nomask) + a = arange(10) + a._smallmask = False + a[1] = masked + a[1] = 1 + assert_equal(a._mask, zeros(10)) + + def test_shrink_mask(self): + # Tests .shrink_mask() + a = array([1, 2, 3], mask=[0, 0, 0]) + b = a.shrink_mask() + assert_equal(a, b) + assert_equal(a.mask, nomask) + + # Mask cannot be shrunk on structured types, so is a no-op + a = np.ma.array([(1, 2.0)], [('a', int), ('b', float)]) + b = a.copy() + a.shrink_mask() + assert_equal(a.mask, b.mask) + + def test_flat(self): + # Test that flat can return all types of items [#4585, #4615] + # test simple access + test = masked_array(np.matrix([[1, 2, 3]]), mask=[0, 0, 1]) + assert_equal(test.flat[1], 2) + assert_equal(test.flat[2], masked) + assert_(np.all(test.flat[0:2] == test[0, 0:2])) + # Test flat on masked_matrices + test = masked_array(np.matrix([[1, 2, 3]]), mask=[0, 0, 1]) + test.flat = masked_array([3, 2, 1], mask=[1, 0, 0]) + control = masked_array(np.matrix([[3, 2, 1]]), mask=[1, 0, 0]) + assert_equal(test, control) + # Test setting + test = masked_array(np.matrix([[1, 2, 3]]), mask=[0, 0, 1]) + testflat = test.flat + testflat[:] = testflat[[2, 1, 0]] + assert_equal(test, control) + testflat[0] = 9 + assert_equal(test[0, 0], 9) + # test 2-D record array + # ... on structured array w/ masked records + x = array([[(1, 1.1, 'one'), (2, 2.2, 'two'), (3, 3.3, 'thr')], + [(4, 4.4, 'fou'), (5, 5.5, 'fiv'), (6, 6.6, 'six')]], + dtype=[('a', int), ('b', float), ('c', '|S8')]) + x['a'][0, 1] = masked + x['b'][1, 0] = masked + x['c'][0, 2] = masked + x[-1, -1] = masked + xflat = x.flat + assert_equal(xflat[0], x[0, 0]) + assert_equal(xflat[1], x[0, 1]) + assert_equal(xflat[2], x[0, 2]) + assert_equal(xflat[:3], x[0]) + assert_equal(xflat[3], x[1, 0]) + assert_equal(xflat[4], x[1, 1]) + assert_equal(xflat[5], x[1, 2]) + assert_equal(xflat[3:], x[1]) + assert_equal(xflat[-1], x[-1, -1]) + i = 0 + j = 0 + for xf in xflat: + assert_equal(xf, x[j, i]) + i += 1 + if i >= x.shape[-1]: + i = 0 + j += 1 + # test that matrices keep the correct shape (#4615) + a = masked_array(np.matrix(np.eye(2)), mask=0) + b = a.flat + b01 = b[:2] + assert_equal(b01.data, array([[1., 0.]])) + assert_equal(b01.mask, array([[False, False]])) + + def test_assign_dtype(self): + # check that the mask's dtype is updated when dtype is changed + a = np.zeros(4, dtype='f4,i4') + + m = np.ma.array(a) + m.dtype = np.dtype('f4') + repr(m) # raises? + assert_equal(m.dtype, np.dtype('f4')) + + # check that dtype changes that change shape of mask too much + # are not allowed + def assign(): + m = np.ma.array(a) + m.dtype = np.dtype('f8') + assert_raises(ValueError, assign) + + b = a.view(dtype='f4', type=np.ma.MaskedArray) # raises? + assert_equal(b.dtype, np.dtype('f4')) + + # check that nomask is preserved + a = np.zeros(4, dtype='f4') + m = np.ma.array(a) + m.dtype = np.dtype('f4,i4') + assert_equal(m.dtype, np.dtype('f4,i4')) + assert_equal(m._mask, np.ma.nomask) + + +class TestFillingValues(object): + + def test_check_on_scalar(self): + # Test _check_fill_value set to valid and invalid values + _check_fill_value = np.ma.core._check_fill_value + + fval = _check_fill_value(0, int) + assert_equal(fval, 0) + fval = _check_fill_value(None, int) + assert_equal(fval, default_fill_value(0)) + + fval = _check_fill_value(0, "|S3") + assert_equal(fval, b"0") + fval = _check_fill_value(None, "|S3") + assert_equal(fval, default_fill_value(b"camelot!")) + assert_raises(TypeError, _check_fill_value, 1e+20, int) + assert_raises(TypeError, _check_fill_value, 'stuff', int) + + def test_check_on_fields(self): + # Tests _check_fill_value with records + _check_fill_value = np.ma.core._check_fill_value + ndtype = [('a', int), ('b', float), ('c', "|S3")] + # A check on a list should return a single record + fval = _check_fill_value([-999, -12345678.9, "???"], ndtype) + assert_(isinstance(fval, ndarray)) + assert_equal(fval.item(), [-999, -12345678.9, b"???"]) + # A check on None should output the defaults + fval = _check_fill_value(None, ndtype) + assert_(isinstance(fval, ndarray)) + assert_equal(fval.item(), [default_fill_value(0), + default_fill_value(0.), + asbytes(default_fill_value("0"))]) + #.....Using a structured type as fill_value should work + fill_val = np.array((-999, -12345678.9, "???"), dtype=ndtype) + fval = _check_fill_value(fill_val, ndtype) + assert_(isinstance(fval, ndarray)) + assert_equal(fval.item(), [-999, -12345678.9, b"???"]) + + #.....Using a flexible type w/ a different type shouldn't matter + # BEHAVIOR in 1.5 and earlier, and 1.13 and later: match structured + # types by position + fill_val = np.array((-999, -12345678.9, "???"), + dtype=[("A", int), ("B", float), ("C", "|S3")]) + fval = _check_fill_value(fill_val, ndtype) + assert_(isinstance(fval, ndarray)) + assert_equal(fval.item(), [-999, -12345678.9, b"???"]) + + #.....Using an object-array shouldn't matter either + fill_val = np.ndarray(shape=(1,), dtype=object) + fill_val[0] = (-999, -12345678.9, b"???") + fval = _check_fill_value(fill_val, object) + assert_(isinstance(fval, ndarray)) + assert_equal(fval.item(), [-999, -12345678.9, b"???"]) + # NOTE: This test was never run properly as "fill_value" rather than + # "fill_val" was assigned. Written properly, it fails. + #fill_val = np.array((-999, -12345678.9, "???")) + #fval = _check_fill_value(fill_val, ndtype) + #assert_(isinstance(fval, ndarray)) + #assert_equal(fval.item(), [-999, -12345678.9, b"???"]) + #.....One-field-only flexible type should work as well + ndtype = [("a", int)] + fval = _check_fill_value(-999999999, ndtype) + assert_(isinstance(fval, ndarray)) + assert_equal(fval.item(), (-999999999,)) + + def test_fillvalue_conversion(self): + # Tests the behavior of fill_value during conversion + # We had a tailored comment to make sure special attributes are + # properly dealt with + a = array([b'3', b'4', b'5']) + a._optinfo.update({'comment':"updated!"}) + + b = array(a, dtype=int) + assert_equal(b._data, [3, 4, 5]) + assert_equal(b.fill_value, default_fill_value(0)) + + b = array(a, dtype=float) + assert_equal(b._data, [3, 4, 5]) + assert_equal(b.fill_value, default_fill_value(0.)) + + b = a.astype(int) + assert_equal(b._data, [3, 4, 5]) + assert_equal(b.fill_value, default_fill_value(0)) + assert_equal(b._optinfo['comment'], "updated!") + + b = a.astype([('a', '|S3')]) + assert_equal(b['a']._data, a._data) + assert_equal(b['a'].fill_value, a.fill_value) + + def test_default_fill_value(self): + # check all calling conventions + f1 = default_fill_value(1.) + f2 = default_fill_value(np.array(1.)) + f3 = default_fill_value(np.array(1.).dtype) + assert_equal(f1, f2) + assert_equal(f1, f3) + + def test_default_fill_value_structured(self): + fields = array([(1, 1, 1)], + dtype=[('i', int), ('s', '|S8'), ('f', float)]) + + f1 = default_fill_value(fields) + f2 = default_fill_value(fields.dtype) + expected = np.array((default_fill_value(0), + default_fill_value('0'), + default_fill_value(0.)), dtype=fields.dtype) + assert_equal(f1, expected) + assert_equal(f2, expected) + + def test_default_fill_value_void(self): + dt = np.dtype([('v', 'V7')]) + f = default_fill_value(dt) + assert_equal(f['v'], np.array(default_fill_value(dt['v']), dt['v'])) + + def test_fillvalue(self): + # Yet more fun with the fill_value + data = masked_array([1, 2, 3], fill_value=-999) + series = data[[0, 2, 1]] + assert_equal(series._fill_value, data._fill_value) + + mtype = [('f', float), ('s', '|S3')] + x = array([(1, 'a'), (2, 'b'), (pi, 'pi')], dtype=mtype) + x.fill_value = 999 + assert_equal(x.fill_value.item(), [999., b'999']) + assert_equal(x['f'].fill_value, 999) + assert_equal(x['s'].fill_value, b'999') + + x.fill_value = (9, '???') + assert_equal(x.fill_value.item(), (9, b'???')) + assert_equal(x['f'].fill_value, 9) + assert_equal(x['s'].fill_value, b'???') + + x = array([1, 2, 3.1]) + x.fill_value = 999 + assert_equal(np.asarray(x.fill_value).dtype, float) + assert_equal(x.fill_value, 999.) + assert_equal(x._fill_value, np.array(999.)) + + def test_fillvalue_exotic_dtype(self): + # Tests yet more exotic flexible dtypes + _check_fill_value = np.ma.core._check_fill_value + ndtype = [('i', int), ('s', '|S8'), ('f', float)] + control = np.array((default_fill_value(0), + default_fill_value('0'), + default_fill_value(0.),), + dtype=ndtype) + assert_equal(_check_fill_value(None, ndtype), control) + # The shape shouldn't matter + ndtype = [('f0', float, (2, 2))] + control = np.array((default_fill_value(0.),), + dtype=[('f0', float)]).astype(ndtype) + assert_equal(_check_fill_value(None, ndtype), control) + control = np.array((0,), dtype=[('f0', float)]).astype(ndtype) + assert_equal(_check_fill_value(0, ndtype), control) + + ndtype = np.dtype("int, (2,3)float, float") + control = np.array((default_fill_value(0), + default_fill_value(0.), + default_fill_value(0.),), + dtype="int, float, float").astype(ndtype) + test = _check_fill_value(None, ndtype) + assert_equal(test, control) + control = np.array((0, 0, 0), dtype="int, float, float").astype(ndtype) + assert_equal(_check_fill_value(0, ndtype), control) + # but when indexing, fill value should become scalar not tuple + # See issue #6723 + M = masked_array(control) + assert_equal(M["f1"].fill_value.ndim, 0) + + def test_fillvalue_datetime_timedelta(self): + # Test default fillvalue for datetime64 and timedelta64 types. + # See issue #4476, this would return '?' which would cause errors + # elsewhere + + for timecode in ("as", "fs", "ps", "ns", "us", "ms", "s", "m", + "h", "D", "W", "M", "Y"): + control = numpy.datetime64("NaT", timecode) + test = default_fill_value(numpy.dtype(" 0 + + # test different unary domains + sqrt(m) + log(m) + tan(m) + arcsin(m) + arccos(m) + arccosh(m) + + # test binary domains + divide(m, 2) + + # also check that allclose uses ma ufuncs, to avoid warning + allclose(m, 0.5) + +class TestMaskedArrayInPlaceArithmetics(object): + # Test MaskedArray Arithmetics + + def setup(self): + x = arange(10) + y = arange(10) + xm = arange(10) + xm[2] = masked + self.intdata = (x, y, xm) + self.floatdata = (x.astype(float), y.astype(float), xm.astype(float)) + self.othertypes = np.typecodes['AllInteger'] + np.typecodes['AllFloat'] + self.othertypes = [np.dtype(_).type for _ in self.othertypes] + self.uint8data = ( + x.astype(np.uint8), + y.astype(np.uint8), + xm.astype(np.uint8) + ) + + def test_inplace_addition_scalar(self): + # Test of inplace additions + (x, y, xm) = self.intdata + xm[2] = masked + x += 1 + assert_equal(x, y + 1) + xm += 1 + assert_equal(xm, y + 1) + + (x, _, xm) = self.floatdata + id1 = x.data.ctypes._data + x += 1. + assert_(id1 == x.data.ctypes._data) + assert_equal(x, y + 1.) + + def test_inplace_addition_array(self): + # Test of inplace additions + (x, y, xm) = self.intdata + m = xm.mask + a = arange(10, dtype=np.int16) + a[-1] = masked + x += a + xm += a + assert_equal(x, y + a) + assert_equal(xm, y + a) + assert_equal(xm.mask, mask_or(m, a.mask)) + + def test_inplace_subtraction_scalar(self): + # Test of inplace subtractions + (x, y, xm) = self.intdata + x -= 1 + assert_equal(x, y - 1) + xm -= 1 + assert_equal(xm, y - 1) + + def test_inplace_subtraction_array(self): + # Test of inplace subtractions + (x, y, xm) = self.floatdata + m = xm.mask + a = arange(10, dtype=float) + a[-1] = masked + x -= a + xm -= a + assert_equal(x, y - a) + assert_equal(xm, y - a) + assert_equal(xm.mask, mask_or(m, a.mask)) + + def test_inplace_multiplication_scalar(self): + # Test of inplace multiplication + (x, y, xm) = self.floatdata + x *= 2.0 + assert_equal(x, y * 2) + xm *= 2.0 + assert_equal(xm, y * 2) + + def test_inplace_multiplication_array(self): + # Test of inplace multiplication + (x, y, xm) = self.floatdata + m = xm.mask + a = arange(10, dtype=float) + a[-1] = masked + x *= a + xm *= a + assert_equal(x, y * a) + assert_equal(xm, y * a) + assert_equal(xm.mask, mask_or(m, a.mask)) + + def test_inplace_division_scalar_int(self): + # Test of inplace division + (x, y, xm) = self.intdata + x = arange(10) * 2 + xm = arange(10) * 2 + xm[2] = masked + x //= 2 + assert_equal(x, y) + xm //= 2 + assert_equal(xm, y) + + def test_inplace_division_scalar_float(self): + # Test of inplace division + (x, y, xm) = self.floatdata + x /= 2.0 + assert_equal(x, y / 2.0) + xm /= arange(10) + assert_equal(xm, ones((10,))) + + def test_inplace_division_array_float(self): + # Test of inplace division + (x, y, xm) = self.floatdata + m = xm.mask + a = arange(10, dtype=float) + a[-1] = masked + x /= a + xm /= a + assert_equal(x, y / a) + assert_equal(xm, y / a) + assert_equal(xm.mask, mask_or(mask_or(m, a.mask), (a == 0))) + + def test_inplace_division_misc(self): + + x = [1., 1., 1., -2., pi / 2., 4., 5., -10., 10., 1., 2., 3.] + y = [5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.] + m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0] + m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1] + xm = masked_array(x, mask=m1) + ym = masked_array(y, mask=m2) + + z = xm / ym + assert_equal(z._mask, [1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1]) + assert_equal(z._data, + [1., 1., 1., -1., -pi / 2., 4., 5., 1., 1., 1., 2., 3.]) + + xm = xm.copy() + xm /= ym + assert_equal(xm._mask, [1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1]) + assert_equal(z._data, + [1., 1., 1., -1., -pi / 2., 4., 5., 1., 1., 1., 2., 3.]) + + def test_datafriendly_add(self): + # Test keeping data w/ (inplace) addition + x = array([1, 2, 3], mask=[0, 0, 1]) + # Test add w/ scalar + xx = x + 1 + assert_equal(xx.data, [2, 3, 3]) + assert_equal(xx.mask, [0, 0, 1]) + # Test iadd w/ scalar + x += 1 + assert_equal(x.data, [2, 3, 3]) + assert_equal(x.mask, [0, 0, 1]) + # Test add w/ array + x = array([1, 2, 3], mask=[0, 0, 1]) + xx = x + array([1, 2, 3], mask=[1, 0, 0]) + assert_equal(xx.data, [1, 4, 3]) + assert_equal(xx.mask, [1, 0, 1]) + # Test iadd w/ array + x = array([1, 2, 3], mask=[0, 0, 1]) + x += array([1, 2, 3], mask=[1, 0, 0]) + assert_equal(x.data, [1, 4, 3]) + assert_equal(x.mask, [1, 0, 1]) + + def test_datafriendly_sub(self): + # Test keeping data w/ (inplace) subtraction + # Test sub w/ scalar + x = array([1, 2, 3], mask=[0, 0, 1]) + xx = x - 1 + assert_equal(xx.data, [0, 1, 3]) + assert_equal(xx.mask, [0, 0, 1]) + # Test isub w/ scalar + x = array([1, 2, 3], mask=[0, 0, 1]) + x -= 1 + assert_equal(x.data, [0, 1, 3]) + assert_equal(x.mask, [0, 0, 1]) + # Test sub w/ array + x = array([1, 2, 3], mask=[0, 0, 1]) + xx = x - array([1, 2, 3], mask=[1, 0, 0]) + assert_equal(xx.data, [1, 0, 3]) + assert_equal(xx.mask, [1, 0, 1]) + # Test isub w/ array + x = array([1, 2, 3], mask=[0, 0, 1]) + x -= array([1, 2, 3], mask=[1, 0, 0]) + assert_equal(x.data, [1, 0, 3]) + assert_equal(x.mask, [1, 0, 1]) + + def test_datafriendly_mul(self): + # Test keeping data w/ (inplace) multiplication + # Test mul w/ scalar + x = array([1, 2, 3], mask=[0, 0, 1]) + xx = x * 2 + assert_equal(xx.data, [2, 4, 3]) + assert_equal(xx.mask, [0, 0, 1]) + # Test imul w/ scalar + x = array([1, 2, 3], mask=[0, 0, 1]) + x *= 2 + assert_equal(x.data, [2, 4, 3]) + assert_equal(x.mask, [0, 0, 1]) + # Test mul w/ array + x = array([1, 2, 3], mask=[0, 0, 1]) + xx = x * array([10, 20, 30], mask=[1, 0, 0]) + assert_equal(xx.data, [1, 40, 3]) + assert_equal(xx.mask, [1, 0, 1]) + # Test imul w/ array + x = array([1, 2, 3], mask=[0, 0, 1]) + x *= array([10, 20, 30], mask=[1, 0, 0]) + assert_equal(x.data, [1, 40, 3]) + assert_equal(x.mask, [1, 0, 1]) + + def test_datafriendly_div(self): + # Test keeping data w/ (inplace) division + # Test div on scalar + x = array([1, 2, 3], mask=[0, 0, 1]) + xx = x / 2. + assert_equal(xx.data, [1 / 2., 2 / 2., 3]) + assert_equal(xx.mask, [0, 0, 1]) + # Test idiv on scalar + x = array([1., 2., 3.], mask=[0, 0, 1]) + x /= 2. + assert_equal(x.data, [1 / 2., 2 / 2., 3]) + assert_equal(x.mask, [0, 0, 1]) + # Test div on array + x = array([1., 2., 3.], mask=[0, 0, 1]) + xx = x / array([10., 20., 30.], mask=[1, 0, 0]) + assert_equal(xx.data, [1., 2. / 20., 3.]) + assert_equal(xx.mask, [1, 0, 1]) + # Test idiv on array + x = array([1., 2., 3.], mask=[0, 0, 1]) + x /= array([10., 20., 30.], mask=[1, 0, 0]) + assert_equal(x.data, [1., 2 / 20., 3.]) + assert_equal(x.mask, [1, 0, 1]) + + def test_datafriendly_pow(self): + # Test keeping data w/ (inplace) power + # Test pow on scalar + x = array([1., 2., 3.], mask=[0, 0, 1]) + xx = x ** 2.5 + assert_equal(xx.data, [1., 2. ** 2.5, 3.]) + assert_equal(xx.mask, [0, 0, 1]) + # Test ipow on scalar + x **= 2.5 + assert_equal(x.data, [1., 2. ** 2.5, 3]) + assert_equal(x.mask, [0, 0, 1]) + + def test_datafriendly_add_arrays(self): + a = array([[1, 1], [3, 3]]) + b = array([1, 1], mask=[0, 0]) + a += b + assert_equal(a, [[2, 2], [4, 4]]) + if a.mask is not nomask: + assert_equal(a.mask, [[0, 0], [0, 0]]) + + a = array([[1, 1], [3, 3]]) + b = array([1, 1], mask=[0, 1]) + a += b + assert_equal(a, [[2, 2], [4, 4]]) + assert_equal(a.mask, [[0, 1], [0, 1]]) + + def test_datafriendly_sub_arrays(self): + a = array([[1, 1], [3, 3]]) + b = array([1, 1], mask=[0, 0]) + a -= b + assert_equal(a, [[0, 0], [2, 2]]) + if a.mask is not nomask: + assert_equal(a.mask, [[0, 0], [0, 0]]) + + a = array([[1, 1], [3, 3]]) + b = array([1, 1], mask=[0, 1]) + a -= b + assert_equal(a, [[0, 0], [2, 2]]) + assert_equal(a.mask, [[0, 1], [0, 1]]) + + def test_datafriendly_mul_arrays(self): + a = array([[1, 1], [3, 3]]) + b = array([1, 1], mask=[0, 0]) + a *= b + assert_equal(a, [[1, 1], [3, 3]]) + if a.mask is not nomask: + assert_equal(a.mask, [[0, 0], [0, 0]]) + + a = array([[1, 1], [3, 3]]) + b = array([1, 1], mask=[0, 1]) + a *= b + assert_equal(a, [[1, 1], [3, 3]]) + assert_equal(a.mask, [[0, 1], [0, 1]]) + + def test_inplace_addition_scalar_type(self): + # Test of inplace additions + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + xm[2] = masked + x += t(1) + assert_equal(x, y + t(1)) + xm += t(1) + assert_equal(xm, y + t(1)) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + def test_inplace_addition_array_type(self): + # Test of inplace additions + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + m = xm.mask + a = arange(10, dtype=t) + a[-1] = masked + x += a + xm += a + assert_equal(x, y + a) + assert_equal(xm, y + a) + assert_equal(xm.mask, mask_or(m, a.mask)) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + def test_inplace_subtraction_scalar_type(self): + # Test of inplace subtractions + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + x -= t(1) + assert_equal(x, y - t(1)) + xm -= t(1) + assert_equal(xm, y - t(1)) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + def test_inplace_subtraction_array_type(self): + # Test of inplace subtractions + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + m = xm.mask + a = arange(10, dtype=t) + a[-1] = masked + x -= a + xm -= a + assert_equal(x, y - a) + assert_equal(xm, y - a) + assert_equal(xm.mask, mask_or(m, a.mask)) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + def test_inplace_multiplication_scalar_type(self): + # Test of inplace multiplication + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + x *= t(2) + assert_equal(x, y * t(2)) + xm *= t(2) + assert_equal(xm, y * t(2)) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + def test_inplace_multiplication_array_type(self): + # Test of inplace multiplication + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + m = xm.mask + a = arange(10, dtype=t) + a[-1] = masked + x *= a + xm *= a + assert_equal(x, y * a) + assert_equal(xm, y * a) + assert_equal(xm.mask, mask_or(m, a.mask)) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + def test_inplace_floor_division_scalar_type(self): + # Test of inplace division + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + x = arange(10, dtype=t) * t(2) + xm = arange(10, dtype=t) * t(2) + xm[2] = masked + x //= t(2) + xm //= t(2) + assert_equal(x, y) + assert_equal(xm, y) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + def test_inplace_floor_division_array_type(self): + # Test of inplace division + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + m = xm.mask + a = arange(10, dtype=t) + a[-1] = masked + x //= a + xm //= a + assert_equal(x, y // a) + assert_equal(xm, y // a) + assert_equal( + xm.mask, + mask_or(mask_or(m, a.mask), (a == t(0))) + ) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + def test_inplace_division_scalar_type(self): + # Test of inplace division + for t in self.othertypes: + with suppress_warnings() as sup: + sup.record(UserWarning) + + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + x = arange(10, dtype=t) * t(2) + xm = arange(10, dtype=t) * t(2) + xm[2] = masked + + # May get a DeprecationWarning or a TypeError. + # + # This is a consequence of the fact that this is true divide + # and will require casting to float for calculation and + # casting back to the original type. This will only be raised + # with integers. Whether it is an error or warning is only + # dependent on how stringent the casting rules are. + # + # Will handle the same way. + try: + x /= t(2) + assert_equal(x, y) + except (DeprecationWarning, TypeError) as e: + warnings.warn(str(e), stacklevel=1) + try: + xm /= t(2) + assert_equal(xm, y) + except (DeprecationWarning, TypeError) as e: + warnings.warn(str(e), stacklevel=1) + + if issubclass(t, np.integer): + assert_equal(len(sup.log), 2, "Failed on type=%s." % t) + else: + assert_equal(len(sup.log), 0, "Failed on type=%s." % t) + + def test_inplace_division_array_type(self): + # Test of inplace division + for t in self.othertypes: + with suppress_warnings() as sup: + sup.record(UserWarning) + (x, y, xm) = (_.astype(t) for _ in self.uint8data) + m = xm.mask + a = arange(10, dtype=t) + a[-1] = masked + + # May get a DeprecationWarning or a TypeError. + # + # This is a consequence of the fact that this is true divide + # and will require casting to float for calculation and + # casting back to the original type. This will only be raised + # with integers. Whether it is an error or warning is only + # dependent on how stringent the casting rules are. + # + # Will handle the same way. + try: + x /= a + assert_equal(x, y / a) + except (DeprecationWarning, TypeError) as e: + warnings.warn(str(e), stacklevel=1) + try: + xm /= a + assert_equal(xm, y / a) + assert_equal( + xm.mask, + mask_or(mask_or(m, a.mask), (a == t(0))) + ) + except (DeprecationWarning, TypeError) as e: + warnings.warn(str(e), stacklevel=1) + + if issubclass(t, np.integer): + assert_equal(len(sup.log), 2, "Failed on type=%s." % t) + else: + assert_equal(len(sup.log), 0, "Failed on type=%s." % t) + + def test_inplace_pow_type(self): + # Test keeping data w/ (inplace) power + for t in self.othertypes: + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings("always") + # Test pow on scalar + x = array([1, 2, 3], mask=[0, 0, 1], dtype=t) + xx = x ** t(2) + xx_r = array([1, 2 ** 2, 3], mask=[0, 0, 1], dtype=t) + assert_equal(xx.data, xx_r.data) + assert_equal(xx.mask, xx_r.mask) + # Test ipow on scalar + x **= t(2) + assert_equal(x.data, xx_r.data) + assert_equal(x.mask, xx_r.mask) + + assert_equal(len(w), 0, "Failed on type=%s." % t) + + +class TestMaskedArrayMethods(object): + # Test class for miscellaneous MaskedArrays methods. + def setup(self): + # Base data definition. + x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928, + 8.43, 7.78, 9.865, 5.878, 8.979, 4.732, + 3.012, 6.022, 5.095, 3.116, 5.238, 3.957, + 6.04, 9.63, 7.712, 3.382, 4.489, 6.479, + 7.189, 9.645, 5.395, 4.961, 9.894, 2.893, + 7.357, 9.828, 6.272, 3.758, 6.693, 0.993]) + X = x.reshape(6, 6) + XX = x.reshape(3, 2, 2, 3) + + m = np.array([0, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 1, 0]) + mx = array(data=x, mask=m) + mX = array(data=X, mask=m.reshape(X.shape)) + mXX = array(data=XX, mask=m.reshape(XX.shape)) + + m2 = np.array([1, 1, 0, 1, 0, 0, + 1, 1, 1, 1, 0, 1, + 0, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 1, 0, + 0, 0, 1, 0, 1, 1]) + m2x = array(data=x, mask=m2) + m2X = array(data=X, mask=m2.reshape(X.shape)) + m2XX = array(data=XX, mask=m2.reshape(XX.shape)) + self.d = (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) + + def test_generic_methods(self): + # Tests some MaskedArray methods. + a = array([1, 3, 2]) + assert_equal(a.any(), a._data.any()) + assert_equal(a.all(), a._data.all()) + assert_equal(a.argmax(), a._data.argmax()) + assert_equal(a.argmin(), a._data.argmin()) + assert_equal(a.choose(0, 1, 2, 3, 4), a._data.choose(0, 1, 2, 3, 4)) + assert_equal(a.compress([1, 0, 1]), a._data.compress([1, 0, 1])) + assert_equal(a.conj(), a._data.conj()) + assert_equal(a.conjugate(), a._data.conjugate()) + + m = array([[1, 2], [3, 4]]) + assert_equal(m.diagonal(), m._data.diagonal()) + assert_equal(a.sum(), a._data.sum()) + assert_equal(a.take([1, 2]), a._data.take([1, 2])) + assert_equal(m.transpose(), m._data.transpose()) + + def test_allclose(self): + # Tests allclose on arrays + a = np.random.rand(10) + b = a + np.random.rand(10) * 1e-8 + assert_(allclose(a, b)) + # Test allclose w/ infs + a[0] = np.inf + assert_(not allclose(a, b)) + b[0] = np.inf + assert_(allclose(a, b)) + # Test allclose w/ masked + a = masked_array(a) + a[-1] = masked + assert_(allclose(a, b, masked_equal=True)) + assert_(not allclose(a, b, masked_equal=False)) + # Test comparison w/ scalar + a *= 1e-8 + a[0] = 0 + assert_(allclose(a, 0, masked_equal=True)) + + # Test that the function works for MIN_INT integer typed arrays + a = masked_array([np.iinfo(np.int_).min], dtype=np.int_) + assert_(allclose(a, a)) + + def test_allany(self): + # Checks the any/all methods/functions. + x = np.array([[0.13, 0.26, 0.90], + [0.28, 0.33, 0.63], + [0.31, 0.87, 0.70]]) + m = np.array([[True, False, False], + [False, False, False], + [True, True, False]], dtype=np.bool_) + mx = masked_array(x, mask=m) + mxbig = (mx > 0.5) + mxsmall = (mx < 0.5) + + assert_(not mxbig.all()) + assert_(mxbig.any()) + assert_equal(mxbig.all(0), [False, False, True]) + assert_equal(mxbig.all(1), [False, False, True]) + assert_equal(mxbig.any(0), [False, False, True]) + assert_equal(mxbig.any(1), [True, True, True]) + + assert_(not mxsmall.all()) + assert_(mxsmall.any()) + assert_equal(mxsmall.all(0), [True, True, False]) + assert_equal(mxsmall.all(1), [False, False, False]) + assert_equal(mxsmall.any(0), [True, True, False]) + assert_equal(mxsmall.any(1), [True, True, False]) + + def test_allany_onmatrices(self): + x = np.array([[0.13, 0.26, 0.90], + [0.28, 0.33, 0.63], + [0.31, 0.87, 0.70]]) + X = np.matrix(x) + m = np.array([[True, False, False], + [False, False, False], + [True, True, False]], dtype=np.bool_) + mX = masked_array(X, mask=m) + mXbig = (mX > 0.5) + mXsmall = (mX < 0.5) + + assert_(not mXbig.all()) + assert_(mXbig.any()) + assert_equal(mXbig.all(0), np.matrix([False, False, True])) + assert_equal(mXbig.all(1), np.matrix([False, False, True]).T) + assert_equal(mXbig.any(0), np.matrix([False, False, True])) + assert_equal(mXbig.any(1), np.matrix([True, True, True]).T) + + assert_(not mXsmall.all()) + assert_(mXsmall.any()) + assert_equal(mXsmall.all(0), np.matrix([True, True, False])) + assert_equal(mXsmall.all(1), np.matrix([False, False, False]).T) + assert_equal(mXsmall.any(0), np.matrix([True, True, False])) + assert_equal(mXsmall.any(1), np.matrix([True, True, False]).T) + + def test_allany_oddities(self): + # Some fun with all and any + store = empty((), dtype=bool) + full = array([1, 2, 3], mask=True) + + assert_(full.all() is masked) + full.all(out=store) + assert_(store) + assert_(store._mask, True) + assert_(store is not masked) + + store = empty((), dtype=bool) + assert_(full.any() is masked) + full.any(out=store) + assert_(not store) + assert_(store._mask, True) + assert_(store is not masked) + + def test_argmax_argmin(self): + # Tests argmin & argmax on MaskedArrays. + (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d + + assert_equal(mx.argmin(), 35) + assert_equal(mX.argmin(), 35) + assert_equal(m2x.argmin(), 4) + assert_equal(m2X.argmin(), 4) + assert_equal(mx.argmax(), 28) + assert_equal(mX.argmax(), 28) + assert_equal(m2x.argmax(), 31) + assert_equal(m2X.argmax(), 31) + + assert_equal(mX.argmin(0), [2, 2, 2, 5, 0, 5]) + assert_equal(m2X.argmin(0), [2, 2, 4, 5, 0, 4]) + assert_equal(mX.argmax(0), [0, 5, 0, 5, 4, 0]) + assert_equal(m2X.argmax(0), [5, 5, 0, 5, 1, 0]) + + assert_equal(mX.argmin(1), [4, 1, 0, 0, 5, 5, ]) + assert_equal(m2X.argmin(1), [4, 4, 0, 0, 5, 3]) + assert_equal(mX.argmax(1), [2, 4, 1, 1, 4, 1]) + assert_equal(m2X.argmax(1), [2, 4, 1, 1, 1, 1]) + + def test_clip(self): + # Tests clip on MaskedArrays. + x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928, + 8.43, 7.78, 9.865, 5.878, 8.979, 4.732, + 3.012, 6.022, 5.095, 3.116, 5.238, 3.957, + 6.04, 9.63, 7.712, 3.382, 4.489, 6.479, + 7.189, 9.645, 5.395, 4.961, 9.894, 2.893, + 7.357, 9.828, 6.272, 3.758, 6.693, 0.993]) + m = np.array([0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0]) + mx = array(x, mask=m) + clipped = mx.clip(2, 8) + assert_equal(clipped.mask, mx.mask) + assert_equal(clipped._data, x.clip(2, 8)) + assert_equal(clipped._data, mx._data.clip(2, 8)) + + def test_compress(self): + # test compress + a = masked_array([1., 2., 3., 4., 5.], fill_value=9999) + condition = (a > 1.5) & (a < 3.5) + assert_equal(a.compress(condition), [2., 3.]) + + a[[2, 3]] = masked + b = a.compress(condition) + assert_equal(b._data, [2., 3.]) + assert_equal(b._mask, [0, 1]) + assert_equal(b.fill_value, 9999) + assert_equal(b, a[condition]) + + condition = (a < 4.) + b = a.compress(condition) + assert_equal(b._data, [1., 2., 3.]) + assert_equal(b._mask, [0, 0, 1]) + assert_equal(b.fill_value, 9999) + assert_equal(b, a[condition]) + + a = masked_array([[10, 20, 30], [40, 50, 60]], + mask=[[0, 0, 1], [1, 0, 0]]) + b = a.compress(a.ravel() >= 22) + assert_equal(b._data, [30, 40, 50, 60]) + assert_equal(b._mask, [1, 1, 0, 0]) + + x = np.array([3, 1, 2]) + b = a.compress(x >= 2, axis=1) + assert_equal(b._data, [[10, 30], [40, 60]]) + assert_equal(b._mask, [[0, 1], [1, 0]]) + + def test_compressed(self): + # Tests compressed + a = array([1, 2, 3, 4], mask=[0, 0, 0, 0]) + b = a.compressed() + assert_equal(b, a) + a[0] = masked + b = a.compressed() + assert_equal(b, [2, 3, 4]) + + a = array(np.matrix([1, 2, 3, 4]), mask=[0, 0, 0, 0]) + b = a.compressed() + assert_equal(b, a) + assert_(isinstance(b, np.matrix)) + a[0, 0] = masked + b = a.compressed() + assert_equal(b, [[2, 3, 4]]) + + def test_empty(self): + # Tests empty/like + datatype = [('a', int), ('b', float), ('c', '|S8')] + a = masked_array([(1, 1.1, '1.1'), (2, 2.2, '2.2'), (3, 3.3, '3.3')], + dtype=datatype) + assert_equal(len(a.fill_value.item()), len(datatype)) + + b = empty_like(a) + assert_equal(b.shape, a.shape) + assert_equal(b.fill_value, a.fill_value) + + b = empty(len(a), dtype=datatype) + assert_equal(b.shape, a.shape) + assert_equal(b.fill_value, a.fill_value) + + # check empty_like mask handling + a = masked_array([1, 2, 3], mask=[False, True, False]) + b = empty_like(a) + assert_(not np.may_share_memory(a.mask, b.mask)) + b = a.view(masked_array) + assert_(np.may_share_memory(a.mask, b.mask)) + + @suppress_copy_mask_on_assignment + def test_put(self): + # Tests put. + d = arange(5) + n = [0, 0, 0, 1, 1] + m = make_mask(n) + x = array(d, mask=m) + assert_(x[3] is masked) + assert_(x[4] is masked) + x[[1, 4]] = [10, 40] + assert_(x[3] is masked) + assert_(x[4] is not masked) + assert_equal(x, [0, 10, 2, -1, 40]) + + x = masked_array(arange(10), mask=[1, 0, 0, 0, 0] * 2) + i = [0, 2, 4, 6] + x.put(i, [6, 4, 2, 0]) + assert_equal(x, asarray([6, 1, 4, 3, 2, 5, 0, 7, 8, 9, ])) + assert_equal(x.mask, [0, 0, 0, 0, 0, 1, 0, 0, 0, 0]) + x.put(i, masked_array([0, 2, 4, 6], [1, 0, 1, 0])) + assert_array_equal(x, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ]) + assert_equal(x.mask, [1, 0, 0, 0, 1, 1, 0, 0, 0, 0]) + + x = masked_array(arange(10), mask=[1, 0, 0, 0, 0] * 2) + put(x, i, [6, 4, 2, 0]) + assert_equal(x, asarray([6, 1, 4, 3, 2, 5, 0, 7, 8, 9, ])) + assert_equal(x.mask, [0, 0, 0, 0, 0, 1, 0, 0, 0, 0]) + put(x, i, masked_array([0, 2, 4, 6], [1, 0, 1, 0])) + assert_array_equal(x, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ]) + assert_equal(x.mask, [1, 0, 0, 0, 1, 1, 0, 0, 0, 0]) + + def test_put_nomask(self): + # GitHub issue 6425 + x = zeros(10) + z = array([3., -1.], mask=[False, True]) + + x.put([1, 2], z) + assert_(x[0] is not masked) + assert_equal(x[0], 0) + assert_(x[1] is not masked) + assert_equal(x[1], 3) + assert_(x[2] is masked) + assert_(x[3] is not masked) + assert_equal(x[3], 0) + + def test_put_hardmask(self): + # Tests put on hardmask + d = arange(5) + n = [0, 0, 0, 1, 1] + m = make_mask(n) + xh = array(d + 1, mask=m, hard_mask=True, copy=True) + xh.put([4, 2, 0, 1, 3], [1, 2, 3, 4, 5]) + assert_equal(xh._data, [3, 4, 2, 4, 5]) + + def test_putmask(self): + x = arange(6) + 1 + mx = array(x, mask=[0, 0, 0, 1, 1, 1]) + mask = [0, 0, 1, 0, 0, 1] + # w/o mask, w/o masked values + xx = x.copy() + putmask(xx, mask, 99) + assert_equal(xx, [1, 2, 99, 4, 5, 99]) + # w/ mask, w/o masked values + mxx = mx.copy() + putmask(mxx, mask, 99) + assert_equal(mxx._data, [1, 2, 99, 4, 5, 99]) + assert_equal(mxx._mask, [0, 0, 0, 1, 1, 0]) + # w/o mask, w/ masked values + values = array([10, 20, 30, 40, 50, 60], mask=[1, 1, 1, 0, 0, 0]) + xx = x.copy() + putmask(xx, mask, values) + assert_equal(xx._data, [1, 2, 30, 4, 5, 60]) + assert_equal(xx._mask, [0, 0, 1, 0, 0, 0]) + # w/ mask, w/ masked values + mxx = mx.copy() + putmask(mxx, mask, values) + assert_equal(mxx._data, [1, 2, 30, 4, 5, 60]) + assert_equal(mxx._mask, [0, 0, 1, 1, 1, 0]) + # w/ mask, w/ masked values + hardmask + mxx = mx.copy() + mxx.harden_mask() + putmask(mxx, mask, values) + assert_equal(mxx, [1, 2, 30, 4, 5, 60]) + + def test_ravel(self): + # Tests ravel + a = array([[1, 2, 3, 4, 5]], mask=[[0, 1, 0, 0, 0]]) + aravel = a.ravel() + assert_equal(aravel._mask.shape, aravel.shape) + a = array([0, 0], mask=[1, 1]) + aravel = a.ravel() + assert_equal(aravel._mask.shape, a.shape) + a = array(np.matrix([1, 2, 3, 4, 5]), mask=[[0, 1, 0, 0, 0]]) + aravel = a.ravel() + assert_equal(aravel.shape, (1, 5)) + assert_equal(aravel._mask.shape, a.shape) + # Checks that small_mask is preserved + a = array([1, 2, 3, 4], mask=[0, 0, 0, 0], shrink=False) + assert_equal(a.ravel()._mask, [0, 0, 0, 0]) + # Test that the fill_value is preserved + a.fill_value = -99 + a.shape = (2, 2) + ar = a.ravel() + assert_equal(ar._mask, [0, 0, 0, 0]) + assert_equal(ar._data, [1, 2, 3, 4]) + assert_equal(ar.fill_value, -99) + # Test index ordering + assert_equal(a.ravel(order='C'), [1, 2, 3, 4]) + assert_equal(a.ravel(order='F'), [1, 3, 2, 4]) + + def test_reshape(self): + # Tests reshape + x = arange(4) + x[0] = masked + y = x.reshape(2, 2) + assert_equal(y.shape, (2, 2,)) + assert_equal(y._mask.shape, (2, 2,)) + assert_equal(x.shape, (4,)) + assert_equal(x._mask.shape, (4,)) + + def test_sort(self): + # Test sort + x = array([1, 4, 2, 3], mask=[0, 1, 0, 0], dtype=np.uint8) + + sortedx = sort(x) + assert_equal(sortedx._data, [1, 2, 3, 4]) + assert_equal(sortedx._mask, [0, 0, 0, 1]) + + sortedx = sort(x, endwith=False) + assert_equal(sortedx._data, [4, 1, 2, 3]) + assert_equal(sortedx._mask, [1, 0, 0, 0]) + + x.sort() + assert_equal(x._data, [1, 2, 3, 4]) + assert_equal(x._mask, [0, 0, 0, 1]) + + x = array([1, 4, 2, 3], mask=[0, 1, 0, 0], dtype=np.uint8) + x.sort(endwith=False) + assert_equal(x._data, [4, 1, 2, 3]) + assert_equal(x._mask, [1, 0, 0, 0]) + + x = [1, 4, 2, 3] + sortedx = sort(x) + assert_(not isinstance(sorted, MaskedArray)) + + x = array([0, 1, -1, -2, 2], mask=nomask, dtype=np.int8) + sortedx = sort(x, endwith=False) + assert_equal(sortedx._data, [-2, -1, 0, 1, 2]) + x = array([0, 1, -1, -2, 2], mask=[0, 1, 0, 0, 1], dtype=np.int8) + sortedx = sort(x, endwith=False) + assert_equal(sortedx._data, [1, 2, -2, -1, 0]) + assert_equal(sortedx._mask, [1, 1, 0, 0, 0]) + + def test_argsort_matches_sort(self): + x = array([1, 4, 2, 3], mask=[0, 1, 0, 0], dtype=np.uint8) + + for kwargs in [dict(), + dict(endwith=True), + dict(endwith=False), + dict(fill_value=2), + dict(fill_value=2, endwith=True), + dict(fill_value=2, endwith=False)]: + sortedx = sort(x, **kwargs) + argsortedx = x[argsort(x, **kwargs)] + assert_equal(sortedx._data, argsortedx._data) + assert_equal(sortedx._mask, argsortedx._mask) + + def test_sort_2d(self): + # Check sort of 2D array. + # 2D array w/o mask + a = masked_array([[8, 4, 1], [2, 0, 9]]) + a.sort(0) + assert_equal(a, [[2, 0, 1], [8, 4, 9]]) + a = masked_array([[8, 4, 1], [2, 0, 9]]) + a.sort(1) + assert_equal(a, [[1, 4, 8], [0, 2, 9]]) + # 2D array w/mask + a = masked_array([[8, 4, 1], [2, 0, 9]], mask=[[1, 0, 0], [0, 0, 1]]) + a.sort(0) + assert_equal(a, [[2, 0, 1], [8, 4, 9]]) + assert_equal(a._mask, [[0, 0, 0], [1, 0, 1]]) + a = masked_array([[8, 4, 1], [2, 0, 9]], mask=[[1, 0, 0], [0, 0, 1]]) + a.sort(1) + assert_equal(a, [[1, 4, 8], [0, 2, 9]]) + assert_equal(a._mask, [[0, 0, 1], [0, 0, 1]]) + # 3D + a = masked_array([[[7, 8, 9], [4, 5, 6], [1, 2, 3]], + [[1, 2, 3], [7, 8, 9], [4, 5, 6]], + [[7, 8, 9], [1, 2, 3], [4, 5, 6]], + [[4, 5, 6], [1, 2, 3], [7, 8, 9]]]) + a[a % 4 == 0] = masked + am = a.copy() + an = a.filled(99) + am.sort(0) + an.sort(0) + assert_equal(am, an) + am = a.copy() + an = a.filled(99) + am.sort(1) + an.sort(1) + assert_equal(am, an) + am = a.copy() + an = a.filled(99) + am.sort(2) + an.sort(2) + assert_equal(am, an) + + def test_sort_flexible(self): + # Test sort on structured dtype. + a = array( + data=[(3, 3), (3, 2), (2, 2), (2, 1), (1, 0), (1, 1), (1, 2)], + mask=[(0, 0), (0, 1), (0, 0), (0, 0), (1, 0), (0, 0), (0, 0)], + dtype=[('A', int), ('B', int)]) + mask_last = array( + data=[(1, 1), (1, 2), (2, 1), (2, 2), (3, 3), (3, 2), (1, 0)], + mask=[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 1), (1, 0)], + dtype=[('A', int), ('B', int)]) + mask_first = array( + data=[(1, 0), (1, 1), (1, 2), (2, 1), (2, 2), (3, 2), (3, 3)], + mask=[(1, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 1), (0, 0)], + dtype=[('A', int), ('B', int)]) + + test = sort(a) + assert_equal(test, mask_last) + assert_equal(test.mask, mask_last.mask) + + test = sort(a, endwith=False) + assert_equal(test, mask_first) + assert_equal(test.mask, mask_first.mask) + + # Test sort on dtype with subarray (gh-8069) + dt = np.dtype([('v', int, 2)]) + a = a.view(dt) + mask_last = mask_last.view(dt) + mask_first = mask_first.view(dt) + + test = sort(a) + assert_equal(test, mask_last) + assert_equal(test.mask, mask_last.mask) + + test = sort(a, endwith=False) + assert_equal(test, mask_first) + assert_equal(test.mask, mask_first.mask) + + def test_argsort(self): + # Test argsort + a = array([1, 5, 2, 4, 3], mask=[1, 0, 0, 1, 0]) + assert_equal(np.argsort(a), argsort(a)) + + def test_squeeze(self): + # Check squeeze + data = masked_array([[1, 2, 3]]) + assert_equal(data.squeeze(), [1, 2, 3]) + data = masked_array([[1, 2, 3]], mask=[[1, 1, 1]]) + assert_equal(data.squeeze(), [1, 2, 3]) + assert_equal(data.squeeze()._mask, [1, 1, 1]) + + # normal ndarrays return a view + arr = np.array([[1]]) + arr_sq = arr.squeeze() + assert_equal(arr_sq, 1) + arr_sq[...] = 2 + assert_equal(arr[0,0], 2) + + # so maskedarrays should too + m_arr = masked_array([[1]], mask=True) + m_arr_sq = m_arr.squeeze() + assert_(m_arr_sq is not np.ma.masked) + assert_equal(m_arr_sq.mask, True) + m_arr_sq[...] = 2 + assert_equal(m_arr[0,0], 2) + + def test_swapaxes(self): + # Tests swapaxes on MaskedArrays. + x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928, + 8.43, 7.78, 9.865, 5.878, 8.979, 4.732, + 3.012, 6.022, 5.095, 3.116, 5.238, 3.957, + 6.04, 9.63, 7.712, 3.382, 4.489, 6.479, + 7.189, 9.645, 5.395, 4.961, 9.894, 2.893, + 7.357, 9.828, 6.272, 3.758, 6.693, 0.993]) + m = np.array([0, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 1, 0]) + mX = array(x, mask=m).reshape(6, 6) + mXX = mX.reshape(3, 2, 2, 3) + + mXswapped = mX.swapaxes(0, 1) + assert_equal(mXswapped[-1], mX[:, -1]) + + mXXswapped = mXX.swapaxes(0, 2) + assert_equal(mXXswapped.shape, (2, 2, 3, 3)) + + def test_take(self): + # Tests take + x = masked_array([10, 20, 30, 40], [0, 1, 0, 1]) + assert_equal(x.take([0, 0, 3]), masked_array([10, 10, 40], [0, 0, 1])) + assert_equal(x.take([0, 0, 3]), x[[0, 0, 3]]) + assert_equal(x.take([[0, 1], [0, 1]]), + masked_array([[10, 20], [10, 20]], [[0, 1], [0, 1]])) + + # assert_equal crashes when passed np.ma.mask + assert_(x[1] is np.ma.masked) + assert_(x.take(1) is np.ma.masked) + + x = array([[10, 20, 30], [40, 50, 60]], mask=[[0, 0, 1], [1, 0, 0, ]]) + assert_equal(x.take([0, 2], axis=1), + array([[10, 30], [40, 60]], mask=[[0, 1], [1, 0]])) + assert_equal(take(x, [0, 2], axis=1), + array([[10, 30], [40, 60]], mask=[[0, 1], [1, 0]])) + + def test_take_masked_indices(self): + # Test take w/ masked indices + a = np.array((40, 18, 37, 9, 22)) + indices = np.arange(3)[None,:] + np.arange(5)[:, None] + mindices = array(indices, mask=(indices >= len(a))) + # No mask + test = take(a, mindices, mode='clip') + ctrl = array([[40, 18, 37], + [18, 37, 9], + [37, 9, 22], + [9, 22, 22], + [22, 22, 22]]) + assert_equal(test, ctrl) + # Masked indices + test = take(a, mindices) + ctrl = array([[40, 18, 37], + [18, 37, 9], + [37, 9, 22], + [9, 22, 40], + [22, 40, 40]]) + ctrl[3, 2] = ctrl[4, 1] = ctrl[4, 2] = masked + assert_equal(test, ctrl) + assert_equal(test.mask, ctrl.mask) + # Masked input + masked indices + a = array((40, 18, 37, 9, 22), mask=(0, 1, 0, 0, 0)) + test = take(a, mindices) + ctrl[0, 1] = ctrl[1, 0] = masked + assert_equal(test, ctrl) + assert_equal(test.mask, ctrl.mask) + + def test_tolist(self): + # Tests to list + # ... on 1D + x = array(np.arange(12)) + x[[1, -2]] = masked + xlist = x.tolist() + assert_(xlist[1] is None) + assert_(xlist[-2] is None) + # ... on 2D + x.shape = (3, 4) + xlist = x.tolist() + ctrl = [[0, None, 2, 3], [4, 5, 6, 7], [8, 9, None, 11]] + assert_equal(xlist[0], [0, None, 2, 3]) + assert_equal(xlist[1], [4, 5, 6, 7]) + assert_equal(xlist[2], [8, 9, None, 11]) + assert_equal(xlist, ctrl) + # ... on structured array w/ masked records + x = array(list(zip([1, 2, 3], + [1.1, 2.2, 3.3], + ['one', 'two', 'thr'])), + dtype=[('a', int), ('b', float), ('c', '|S8')]) + x[-1] = masked + assert_equal(x.tolist(), + [(1, 1.1, b'one'), + (2, 2.2, b'two'), + (None, None, None)]) + # ... on structured array w/ masked fields + a = array([(1, 2,), (3, 4)], mask=[(0, 1), (0, 0)], + dtype=[('a', int), ('b', int)]) + test = a.tolist() + assert_equal(test, [[1, None], [3, 4]]) + # ... on mvoid + a = a[0] + test = a.tolist() + assert_equal(test, [1, None]) + + def test_tolist_specialcase(self): + # Test mvoid.tolist: make sure we return a standard Python object + a = array([(0, 1), (2, 3)], dtype=[('a', int), ('b', int)]) + # w/o mask: each entry is a np.void whose elements are standard Python + for entry in a: + for item in entry.tolist(): + assert_(not isinstance(item, np.generic)) + # w/ mask: each entry is a ma.void whose elements should be + # standard Python + a.mask[0] = (0, 1) + for entry in a: + for item in entry.tolist(): + assert_(not isinstance(item, np.generic)) + + def test_toflex(self): + # Test the conversion to records + data = arange(10) + record = data.toflex() + assert_equal(record['_data'], data._data) + assert_equal(record['_mask'], data._mask) + + data[[0, 1, 2, -1]] = masked + record = data.toflex() + assert_equal(record['_data'], data._data) + assert_equal(record['_mask'], data._mask) + + ndtype = [('i', int), ('s', '|S3'), ('f', float)] + data = array([(i, s, f) for (i, s, f) in zip(np.arange(10), + 'ABCDEFGHIJKLM', + np.random.rand(10))], + dtype=ndtype) + data[[0, 1, 2, -1]] = masked + record = data.toflex() + assert_equal(record['_data'], data._data) + assert_equal(record['_mask'], data._mask) + + ndtype = np.dtype("int, (2,3)float, float") + data = array([(i, f, ff) for (i, f, ff) in zip(np.arange(10), + np.random.rand(10), + np.random.rand(10))], + dtype=ndtype) + data[[0, 1, 2, -1]] = masked + record = data.toflex() + assert_equal_records(record['_data'], data._data) + assert_equal_records(record['_mask'], data._mask) + + def test_fromflex(self): + # Test the reconstruction of a masked_array from a record + a = array([1, 2, 3]) + test = fromflex(a.toflex()) + assert_equal(test, a) + assert_equal(test.mask, a.mask) + + a = array([1, 2, 3], mask=[0, 0, 1]) + test = fromflex(a.toflex()) + assert_equal(test, a) + assert_equal(test.mask, a.mask) + + a = array([(1, 1.), (2, 2.), (3, 3.)], mask=[(1, 0), (0, 0), (0, 1)], + dtype=[('A', int), ('B', float)]) + test = fromflex(a.toflex()) + assert_equal(test, a) + assert_equal(test.data, a.data) + + def test_arraymethod(self): + # Test a _arraymethod w/ n argument + marray = masked_array([[1, 2, 3, 4, 5]], mask=[0, 0, 1, 0, 0]) + control = masked_array([[1], [2], [3], [4], [5]], + mask=[0, 0, 1, 0, 0]) + assert_equal(marray.T, control) + assert_equal(marray.transpose(), control) + + assert_equal(MaskedArray.cumsum(marray.T, 0), control.cumsum(0)) + + def test_arraymethod_0d(self): + # gh-9430 + x = np.ma.array(42, mask=True) + assert_equal(x.T.mask, x.mask) + assert_equal(x.T.data, x.data) + + def test_transpose_view(self): + x = np.ma.array([[1, 2, 3], [4, 5, 6]]) + x[0,1] = np.ma.masked + xt = x.T + + xt[1,0] = 10 + xt[0,1] = np.ma.masked + + assert_equal(x.data, xt.T.data) + assert_equal(x.mask, xt.T.mask) + + def test_diagonal_view(self): + x = np.ma.zeros((3,3)) + x[0,0] = 10 + x[1,1] = np.ma.masked + x[2,2] = 20 + xd = x.diagonal() + x[1,1] = 15 + assert_equal(xd.mask, x.diagonal().mask) + assert_equal(xd.data, x.diagonal().data) + + +class TestMaskedArrayMathMethods(object): + + def setup(self): + # Base data definition. + x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928, + 8.43, 7.78, 9.865, 5.878, 8.979, 4.732, + 3.012, 6.022, 5.095, 3.116, 5.238, 3.957, + 6.04, 9.63, 7.712, 3.382, 4.489, 6.479, + 7.189, 9.645, 5.395, 4.961, 9.894, 2.893, + 7.357, 9.828, 6.272, 3.758, 6.693, 0.993]) + X = x.reshape(6, 6) + XX = x.reshape(3, 2, 2, 3) + + m = np.array([0, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 1, 0]) + mx = array(data=x, mask=m) + mX = array(data=X, mask=m.reshape(X.shape)) + mXX = array(data=XX, mask=m.reshape(XX.shape)) + + m2 = np.array([1, 1, 0, 1, 0, 0, + 1, 1, 1, 1, 0, 1, + 0, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 1, 0, + 0, 0, 1, 0, 1, 1]) + m2x = array(data=x, mask=m2) + m2X = array(data=X, mask=m2.reshape(X.shape)) + m2XX = array(data=XX, mask=m2.reshape(XX.shape)) + self.d = (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) + + def test_cumsumprod(self): + # Tests cumsum & cumprod on MaskedArrays. + (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d + mXcp = mX.cumsum(0) + assert_equal(mXcp._data, mX.filled(0).cumsum(0)) + mXcp = mX.cumsum(1) + assert_equal(mXcp._data, mX.filled(0).cumsum(1)) + + mXcp = mX.cumprod(0) + assert_equal(mXcp._data, mX.filled(1).cumprod(0)) + mXcp = mX.cumprod(1) + assert_equal(mXcp._data, mX.filled(1).cumprod(1)) + + def test_cumsumprod_with_output(self): + # Tests cumsum/cumprod w/ output + xm = array(np.random.uniform(0, 10, 12)).reshape(3, 4) + xm[:, 0] = xm[0] = xm[-1, -1] = masked + + for funcname in ('cumsum', 'cumprod'): + npfunc = getattr(np, funcname) + xmmeth = getattr(xm, funcname) + + # A ndarray as explicit input + output = np.empty((3, 4), dtype=float) + output.fill(-9999) + result = npfunc(xm, axis=0, out=output) + # ... the result should be the given output + assert_(result is output) + assert_equal(result, xmmeth(axis=0, out=output)) + + output = empty((3, 4), dtype=int) + result = xmmeth(axis=0, out=output) + assert_(result is output) + + def test_ptp(self): + # Tests ptp on MaskedArrays. + (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d + (n, m) = X.shape + assert_equal(mx.ptp(), mx.compressed().ptp()) + rows = np.zeros(n, float) + cols = np.zeros(m, float) + for k in range(m): + cols[k] = mX[:, k].compressed().ptp() + for k in range(n): + rows[k] = mX[k].compressed().ptp() + assert_equal(mX.ptp(0), cols) + assert_equal(mX.ptp(1), rows) + + def test_add_object(self): + x = masked_array(['a', 'b'], mask=[1, 0], dtype=object) + y = x + 'x' + assert_equal(y[1], 'bx') + assert_(y.mask[0]) + + def test_sum_object(self): + # Test sum on object dtype + a = masked_array([1, 2, 3], mask=[1, 0, 0], dtype=object) + assert_equal(a.sum(), 5) + a = masked_array([[1, 2, 3], [4, 5, 6]], dtype=object) + assert_equal(a.sum(axis=0), [5, 7, 9]) + + def test_prod_object(self): + # Test prod on object dtype + a = masked_array([1, 2, 3], mask=[1, 0, 0], dtype=object) + assert_equal(a.prod(), 2 * 3) + a = masked_array([[1, 2, 3], [4, 5, 6]], dtype=object) + assert_equal(a.prod(axis=0), [4, 10, 18]) + + def test_meananom_object(self): + # Test mean/anom on object dtype + a = masked_array([1, 2, 3], dtype=object) + assert_equal(a.mean(), 2) + assert_equal(a.anom(), [-1, 0, 1]) + + def test_trace(self): + # Tests trace on MaskedArrays. + (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d + mXdiag = mX.diagonal() + assert_equal(mX.trace(), mX.diagonal().compressed().sum()) + assert_almost_equal(mX.trace(), + X.trace() - sum(mXdiag.mask * X.diagonal(), + axis=0)) + assert_equal(np.trace(mX), mX.trace()) + + # gh-5560 + arr = np.arange(2*4*4).reshape(2,4,4) + m_arr = np.ma.masked_array(arr, False) + assert_equal(arr.trace(axis1=1, axis2=2), m_arr.trace(axis1=1, axis2=2)) + + def test_dot(self): + # Tests dot on MaskedArrays. + (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d + fx = mx.filled(0) + r = mx.dot(mx) + assert_almost_equal(r.filled(0), fx.dot(fx)) + assert_(r.mask is nomask) + + fX = mX.filled(0) + r = mX.dot(mX) + assert_almost_equal(r.filled(0), fX.dot(fX)) + assert_(r.mask[1,3]) + r1 = empty_like(r) + mX.dot(mX, out=r1) + assert_almost_equal(r, r1) + + mYY = mXX.swapaxes(-1, -2) + fXX, fYY = mXX.filled(0), mYY.filled(0) + r = mXX.dot(mYY) + assert_almost_equal(r.filled(0), fXX.dot(fYY)) + r1 = empty_like(r) + mXX.dot(mYY, out=r1) + assert_almost_equal(r, r1) + + def test_dot_shape_mismatch(self): + # regression test + x = masked_array([[1,2],[3,4]], mask=[[0,1],[0,0]]) + y = masked_array([[1,2],[3,4]], mask=[[0,1],[0,0]]) + z = masked_array([[0,1],[3,3]]) + x.dot(y, out=z) + assert_almost_equal(z.filled(0), [[1, 0], [15, 16]]) + assert_almost_equal(z.mask, [[0, 1], [0, 0]]) + + def test_varmean_nomask(self): + # gh-5769 + foo = array([1,2,3,4], dtype='f8') + bar = array([1,2,3,4], dtype='f8') + assert_equal(type(foo.mean()), np.float64) + assert_equal(type(foo.var()), np.float64) + assert((foo.mean() == bar.mean()) is np.bool_(True)) + + # check array type is preserved and out works + foo = array(np.arange(16).reshape((4,4)), dtype='f8') + bar = empty(4, dtype='f4') + assert_equal(type(foo.mean(axis=1)), MaskedArray) + assert_equal(type(foo.var(axis=1)), MaskedArray) + assert_(foo.mean(axis=1, out=bar) is bar) + assert_(foo.var(axis=1, out=bar) is bar) + + def test_varstd(self): + # Tests var & std on MaskedArrays. + (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d + assert_almost_equal(mX.var(axis=None), mX.compressed().var()) + assert_almost_equal(mX.std(axis=None), mX.compressed().std()) + assert_almost_equal(mX.std(axis=None, ddof=1), + mX.compressed().std(ddof=1)) + assert_almost_equal(mX.var(axis=None, ddof=1), + mX.compressed().var(ddof=1)) + assert_equal(mXX.var(axis=3).shape, XX.var(axis=3).shape) + assert_equal(mX.var().shape, X.var().shape) + (mXvar0, mXvar1) = (mX.var(axis=0), mX.var(axis=1)) + assert_almost_equal(mX.var(axis=None, ddof=2), + mX.compressed().var(ddof=2)) + assert_almost_equal(mX.std(axis=None, ddof=2), + mX.compressed().std(ddof=2)) + for k in range(6): + assert_almost_equal(mXvar1[k], mX[k].compressed().var()) + assert_almost_equal(mXvar0[k], mX[:, k].compressed().var()) + assert_almost_equal(np.sqrt(mXvar0[k]), + mX[:, k].compressed().std()) + + @dec.knownfailureif(sys.platform=='win32' and sys.version_info < (3, 6), + msg='Fails on Python < 3.6 (Issue #9671)') + @suppress_copy_mask_on_assignment + def test_varstd_specialcases(self): + # Test a special case for var + nout = np.array(-1, dtype=float) + mout = array(-1, dtype=float) + + x = array(arange(10), mask=True) + for methodname in ('var', 'std'): + method = getattr(x, methodname) + assert_(method() is masked) + assert_(method(0) is masked) + assert_(method(-1) is masked) + # Using a masked array as explicit output + method(out=mout) + assert_(mout is not masked) + assert_equal(mout.mask, True) + # Using a ndarray as explicit output + method(out=nout) + assert_(np.isnan(nout)) + + x = array(arange(10), mask=True) + x[-1] = 9 + for methodname in ('var', 'std'): + method = getattr(x, methodname) + assert_(method(ddof=1) is masked) + assert_(method(0, ddof=1) is masked) + assert_(method(-1, ddof=1) is masked) + # Using a masked array as explicit output + method(out=mout, ddof=1) + assert_(mout is not masked) + assert_equal(mout.mask, True) + # Using a ndarray as explicit output + method(out=nout, ddof=1) + assert_(np.isnan(nout)) + + def test_varstd_ddof(self): + a = array([[1, 1, 0], [1, 1, 0]], mask=[[0, 0, 1], [0, 0, 1]]) + test = a.std(axis=0, ddof=0) + assert_equal(test.filled(0), [0, 0, 0]) + assert_equal(test.mask, [0, 0, 1]) + test = a.std(axis=0, ddof=1) + assert_equal(test.filled(0), [0, 0, 0]) + assert_equal(test.mask, [0, 0, 1]) + test = a.std(axis=0, ddof=2) + assert_equal(test.filled(0), [0, 0, 0]) + assert_equal(test.mask, [1, 1, 1]) + + def test_diag(self): + # Test diag + x = arange(9).reshape((3, 3)) + x[1, 1] = masked + out = np.diag(x) + assert_equal(out, [0, 4, 8]) + out = diag(x) + assert_equal(out, [0, 4, 8]) + assert_equal(out.mask, [0, 1, 0]) + out = diag(out) + control = array([[0, 0, 0], [0, 4, 0], [0, 0, 8]], + mask=[[0, 0, 0], [0, 1, 0], [0, 0, 0]]) + assert_equal(out, control) + + def test_axis_methods_nomask(self): + # Test the combination nomask & methods w/ axis + a = array([[1, 2, 3], [4, 5, 6]]) + + assert_equal(a.sum(0), [5, 7, 9]) + assert_equal(a.sum(-1), [6, 15]) + assert_equal(a.sum(1), [6, 15]) + + assert_equal(a.prod(0), [4, 10, 18]) + assert_equal(a.prod(-1), [6, 120]) + assert_equal(a.prod(1), [6, 120]) + + assert_equal(a.min(0), [1, 2, 3]) + assert_equal(a.min(-1), [1, 4]) + assert_equal(a.min(1), [1, 4]) + + assert_equal(a.max(0), [4, 5, 6]) + assert_equal(a.max(-1), [3, 6]) + assert_equal(a.max(1), [3, 6]) + + +class TestMaskedArrayMathMethodsComplex(object): + # Test class for miscellaneous MaskedArrays methods. + def setup(self): + # Base data definition. + x = np.array([8.375j, 7.545j, 8.828j, 8.5j, 1.757j, 5.928, + 8.43, 7.78, 9.865, 5.878, 8.979, 4.732, + 3.012, 6.022, 5.095, 3.116, 5.238, 3.957, + 6.04, 9.63, 7.712, 3.382, 4.489, 6.479j, + 7.189j, 9.645, 5.395, 4.961, 9.894, 2.893, + 7.357, 9.828, 6.272, 3.758, 6.693, 0.993j]) + X = x.reshape(6, 6) + XX = x.reshape(3, 2, 2, 3) + + m = np.array([0, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 1, 0]) + mx = array(data=x, mask=m) + mX = array(data=X, mask=m.reshape(X.shape)) + mXX = array(data=XX, mask=m.reshape(XX.shape)) + + m2 = np.array([1, 1, 0, 1, 0, 0, + 1, 1, 1, 1, 0, 1, + 0, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 1, 0, + 0, 0, 1, 0, 1, 1]) + m2x = array(data=x, mask=m2) + m2X = array(data=X, mask=m2.reshape(X.shape)) + m2XX = array(data=XX, mask=m2.reshape(XX.shape)) + self.d = (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) + + def test_varstd(self): + # Tests var & std on MaskedArrays. + (x, X, XX, m, mx, mX, mXX, m2x, m2X, m2XX) = self.d + assert_almost_equal(mX.var(axis=None), mX.compressed().var()) + assert_almost_equal(mX.std(axis=None), mX.compressed().std()) + assert_equal(mXX.var(axis=3).shape, XX.var(axis=3).shape) + assert_equal(mX.var().shape, X.var().shape) + (mXvar0, mXvar1) = (mX.var(axis=0), mX.var(axis=1)) + assert_almost_equal(mX.var(axis=None, ddof=2), + mX.compressed().var(ddof=2)) + assert_almost_equal(mX.std(axis=None, ddof=2), + mX.compressed().std(ddof=2)) + for k in range(6): + assert_almost_equal(mXvar1[k], mX[k].compressed().var()) + assert_almost_equal(mXvar0[k], mX[:, k].compressed().var()) + assert_almost_equal(np.sqrt(mXvar0[k]), + mX[:, k].compressed().std()) + + +class TestMaskedArrayFunctions(object): + # Test class for miscellaneous functions. + + def setup(self): + x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.]) + y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.]) + m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0] + m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1] + xm = masked_array(x, mask=m1) + ym = masked_array(y, mask=m2) + xm.set_fill_value(1e+20) + self.info = (xm, ym) + + def test_masked_where_bool(self): + x = [1, 2] + y = masked_where(False, x) + assert_equal(y, [1, 2]) + assert_equal(y[1], 2) + + def test_masked_equal_wlist(self): + x = [1, 2, 3] + mx = masked_equal(x, 3) + assert_equal(mx, x) + assert_equal(mx._mask, [0, 0, 1]) + mx = masked_not_equal(x, 3) + assert_equal(mx, x) + assert_equal(mx._mask, [1, 1, 0]) + + def test_masked_equal_fill_value(self): + x = [1, 2, 3] + mx = masked_equal(x, 3) + assert_equal(mx._mask, [0, 0, 1]) + assert_equal(mx.fill_value, 3) + + def test_masked_where_condition(self): + # Tests masking functions. + x = array([1., 2., 3., 4., 5.]) + x[2] = masked + assert_equal(masked_where(greater(x, 2), x), masked_greater(x, 2)) + assert_equal(masked_where(greater_equal(x, 2), x), + masked_greater_equal(x, 2)) + assert_equal(masked_where(less(x, 2), x), masked_less(x, 2)) + assert_equal(masked_where(less_equal(x, 2), x), + masked_less_equal(x, 2)) + assert_equal(masked_where(not_equal(x, 2), x), masked_not_equal(x, 2)) + assert_equal(masked_where(equal(x, 2), x), masked_equal(x, 2)) + assert_equal(masked_where(not_equal(x, 2), x), masked_not_equal(x, 2)) + assert_equal(masked_where([1, 1, 0, 0, 0], [1, 2, 3, 4, 5]), + [99, 99, 3, 4, 5]) + + def test_masked_where_oddities(self): + # Tests some generic features. + atest = ones((10, 10, 10), dtype=float) + btest = zeros(atest.shape, MaskType) + ctest = masked_where(btest, atest) + assert_equal(atest, ctest) + + def test_masked_where_shape_constraint(self): + a = arange(10) + try: + test = masked_equal(1, a) + except IndexError: + pass + else: + raise AssertionError("Should have failed...") + test = masked_equal(a, 1) + assert_equal(test.mask, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0]) + + def test_masked_where_structured(self): + # test that masked_where on a structured array sets a structured + # mask (see issue #2972) + a = np.zeros(10, dtype=[("A", " 6, x) + + def test_masked_otherfunctions(self): + assert_equal(masked_inside(list(range(5)), 1, 3), + [0, 199, 199, 199, 4]) + assert_equal(masked_outside(list(range(5)), 1, 3), [199, 1, 2, 3, 199]) + assert_equal(masked_inside(array(list(range(5)), + mask=[1, 0, 0, 0, 0]), 1, 3).mask, + [1, 1, 1, 1, 0]) + assert_equal(masked_outside(array(list(range(5)), + mask=[0, 1, 0, 0, 0]), 1, 3).mask, + [1, 1, 0, 0, 1]) + assert_equal(masked_equal(array(list(range(5)), + mask=[1, 0, 0, 0, 0]), 2).mask, + [1, 0, 1, 0, 0]) + assert_equal(masked_not_equal(array([2, 2, 1, 2, 1], + mask=[1, 0, 0, 0, 0]), 2).mask, + [1, 0, 1, 0, 1]) + + def test_round(self): + a = array([1.23456, 2.34567, 3.45678, 4.56789, 5.67890], + mask=[0, 1, 0, 0, 0]) + assert_equal(a.round(), [1., 2., 3., 5., 6.]) + assert_equal(a.round(1), [1.2, 2.3, 3.5, 4.6, 5.7]) + assert_equal(a.round(3), [1.235, 2.346, 3.457, 4.568, 5.679]) + b = empty_like(a) + a.round(out=b) + assert_equal(b, [1., 2., 3., 5., 6.]) + + x = array([1., 2., 3., 4., 5.]) + c = array([1, 1, 1, 0, 0]) + x[2] = masked + z = where(c, x, -x) + assert_equal(z, [1., 2., 0., -4., -5]) + c[0] = masked + z = where(c, x, -x) + assert_equal(z, [1., 2., 0., -4., -5]) + assert_(z[0] is masked) + assert_(z[1] is not masked) + assert_(z[2] is masked) + + def test_round_with_output(self): + # Testing round with an explicit output + + xm = array(np.random.uniform(0, 10, 12)).reshape(3, 4) + xm[:, 0] = xm[0] = xm[-1, -1] = masked + + # A ndarray as explicit input + output = np.empty((3, 4), dtype=float) + output.fill(-9999) + result = np.round(xm, decimals=2, out=output) + # ... the result should be the given output + assert_(result is output) + assert_equal(result, xm.round(decimals=2, out=output)) + + output = empty((3, 4), dtype=float) + result = xm.round(decimals=2, out=output) + assert_(result is output) + + def test_round_with_scalar(self): + # Testing round with scalar/zero dimension input + # GH issue 2244 + a = array(1.1, mask=[False]) + assert_equal(a.round(), 1) + + a = array(1.1, mask=[True]) + assert_(a.round() is masked) + + a = array(1.1, mask=[False]) + output = np.empty(1, dtype=float) + output.fill(-9999) + a.round(out=output) + assert_equal(output, 1) + + a = array(1.1, mask=[False]) + output = array(-9999., mask=[True]) + a.round(out=output) + assert_equal(output[()], 1) + + a = array(1.1, mask=[True]) + output = array(-9999., mask=[False]) + a.round(out=output) + assert_(output[()] is masked) + + def test_identity(self): + a = identity(5) + assert_(isinstance(a, MaskedArray)) + assert_equal(a, np.identity(5)) + + def test_power(self): + x = -1.1 + assert_almost_equal(power(x, 2.), 1.21) + assert_(power(x, masked) is masked) + x = array([-1.1, -1.1, 1.1, 1.1, 0.]) + b = array([0.5, 2., 0.5, 2., -1.], mask=[0, 0, 0, 0, 1]) + y = power(x, b) + assert_almost_equal(y, [0, 1.21, 1.04880884817, 1.21, 0.]) + assert_equal(y._mask, [1, 0, 0, 0, 1]) + b.mask = nomask + y = power(x, b) + assert_equal(y._mask, [1, 0, 0, 0, 1]) + z = x ** b + assert_equal(z._mask, y._mask) + assert_almost_equal(z, y) + assert_almost_equal(z._data, y._data) + x **= b + assert_equal(x._mask, y._mask) + assert_almost_equal(x, y) + assert_almost_equal(x._data, y._data) + + def test_power_with_broadcasting(self): + # Test power w/ broadcasting + a2 = np.array([[1., 2., 3.], [4., 5., 6.]]) + a2m = array(a2, mask=[[1, 0, 0], [0, 0, 1]]) + b1 = np.array([2, 4, 3]) + b2 = np.array([b1, b1]) + b2m = array(b2, mask=[[0, 1, 0], [0, 1, 0]]) + + ctrl = array([[1 ** 2, 2 ** 4, 3 ** 3], [4 ** 2, 5 ** 4, 6 ** 3]], + mask=[[1, 1, 0], [0, 1, 1]]) + # No broadcasting, base & exp w/ mask + test = a2m ** b2m + assert_equal(test, ctrl) + assert_equal(test.mask, ctrl.mask) + # No broadcasting, base w/ mask, exp w/o mask + test = a2m ** b2 + assert_equal(test, ctrl) + assert_equal(test.mask, a2m.mask) + # No broadcasting, base w/o mask, exp w/ mask + test = a2 ** b2m + assert_equal(test, ctrl) + assert_equal(test.mask, b2m.mask) + + ctrl = array([[2 ** 2, 4 ** 4, 3 ** 3], [2 ** 2, 4 ** 4, 3 ** 3]], + mask=[[0, 1, 0], [0, 1, 0]]) + test = b1 ** b2m + assert_equal(test, ctrl) + assert_equal(test.mask, ctrl.mask) + test = b2m ** b1 + assert_equal(test, ctrl) + assert_equal(test.mask, ctrl.mask) + + def test_where(self): + # Test the where function + x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.]) + y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.]) + m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0] + m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1] + xm = masked_array(x, mask=m1) + ym = masked_array(y, mask=m2) + xm.set_fill_value(1e+20) + + d = where(xm > 2, xm, -9) + assert_equal(d, [-9., -9., -9., -9., -9., 4., + -9., -9., 10., -9., -9., 3.]) + assert_equal(d._mask, xm._mask) + d = where(xm > 2, -9, ym) + assert_equal(d, [5., 0., 3., 2., -1., -9., + -9., -10., -9., 1., 0., -9.]) + assert_equal(d._mask, [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0]) + d = where(xm > 2, xm, masked) + assert_equal(d, [-9., -9., -9., -9., -9., 4., + -9., -9., 10., -9., -9., 3.]) + tmp = xm._mask.copy() + tmp[(xm <= 2).filled(True)] = True + assert_equal(d._mask, tmp) + + ixm = xm.astype(int) + d = where(ixm > 2, ixm, masked) + assert_equal(d, [-9, -9, -9, -9, -9, 4, -9, -9, 10, -9, -9, 3]) + assert_equal(d.dtype, ixm.dtype) + + def test_where_object(self): + a = np.array(None) + b = masked_array(None) + r = b.copy() + assert_equal(np.ma.where(True, a, a), r) + assert_equal(np.ma.where(True, b, b), r) + + def test_where_with_masked_choice(self): + x = arange(10) + x[3] = masked + c = x >= 8 + # Set False to masked + z = where(c, x, masked) + assert_(z.dtype is x.dtype) + assert_(z[3] is masked) + assert_(z[4] is masked) + assert_(z[7] is masked) + assert_(z[8] is not masked) + assert_(z[9] is not masked) + assert_equal(x, z) + # Set True to masked + z = where(c, masked, x) + assert_(z.dtype is x.dtype) + assert_(z[3] is masked) + assert_(z[4] is not masked) + assert_(z[7] is not masked) + assert_(z[8] is masked) + assert_(z[9] is masked) + + def test_where_with_masked_condition(self): + x = array([1., 2., 3., 4., 5.]) + c = array([1, 1, 1, 0, 0]) + x[2] = masked + z = where(c, x, -x) + assert_equal(z, [1., 2., 0., -4., -5]) + c[0] = masked + z = where(c, x, -x) + assert_equal(z, [1., 2., 0., -4., -5]) + assert_(z[0] is masked) + assert_(z[1] is not masked) + assert_(z[2] is masked) + + x = arange(1, 6) + x[-1] = masked + y = arange(1, 6) * 10 + y[2] = masked + c = array([1, 1, 1, 0, 0], mask=[1, 0, 0, 0, 0]) + cm = c.filled(1) + z = where(c, x, y) + zm = where(cm, x, y) + assert_equal(z, zm) + assert_(getmask(zm) is nomask) + assert_equal(zm, [1, 2, 3, 40, 50]) + z = where(c, masked, 1) + assert_equal(z, [99, 99, 99, 1, 1]) + z = where(c, 1, masked) + assert_equal(z, [99, 1, 1, 99, 99]) + + def test_where_type(self): + # Test the type conservation with where + x = np.arange(4, dtype=np.int32) + y = np.arange(4, dtype=np.float32) * 2.2 + test = where(x > 1.5, y, x).dtype + control = np.find_common_type([np.int32, np.float32], []) + assert_equal(test, control) + + def test_where_broadcast(self): + # Issue 8599 + x = np.arange(9).reshape(3, 3) + y = np.zeros(3) + core = np.where([1, 0, 1], x, y) + ma = where([1, 0, 1], x, y) + + assert_equal(core, ma) + assert_equal(core.dtype, ma.dtype) + + def test_where_structured(self): + # Issue 8600 + dt = np.dtype([('a', int), ('b', int)]) + x = np.array([(1, 2), (3, 4), (5, 6)], dtype=dt) + y = np.array((10, 20), dtype=dt) + core = np.where([0, 1, 1], x, y) + ma = np.where([0, 1, 1], x, y) + + assert_equal(core, ma) + assert_equal(core.dtype, ma.dtype) + + def test_where_structured_masked(self): + dt = np.dtype([('a', int), ('b', int)]) + x = np.array([(1, 2), (3, 4), (5, 6)], dtype=dt) + + ma = where([0, 1, 1], x, masked) + expected = masked_where([1, 0, 0], x) + + assert_equal(ma.dtype, expected.dtype) + assert_equal(ma, expected) + assert_equal(ma.mask, expected.mask) + + def test_choose(self): + # Test choose + choices = [[0, 1, 2, 3], [10, 11, 12, 13], + [20, 21, 22, 23], [30, 31, 32, 33]] + chosen = choose([2, 3, 1, 0], choices) + assert_equal(chosen, array([20, 31, 12, 3])) + chosen = choose([2, 4, 1, 0], choices, mode='clip') + assert_equal(chosen, array([20, 31, 12, 3])) + chosen = choose([2, 4, 1, 0], choices, mode='wrap') + assert_equal(chosen, array([20, 1, 12, 3])) + # Check with some masked indices + indices_ = array([2, 4, 1, 0], mask=[1, 0, 0, 1]) + chosen = choose(indices_, choices, mode='wrap') + assert_equal(chosen, array([99, 1, 12, 99])) + assert_equal(chosen.mask, [1, 0, 0, 1]) + # Check with some masked choices + choices = array(choices, mask=[[0, 0, 0, 1], [1, 1, 0, 1], + [1, 0, 0, 0], [0, 0, 0, 0]]) + indices_ = [2, 3, 1, 0] + chosen = choose(indices_, choices, mode='wrap') + assert_equal(chosen, array([20, 31, 12, 3])) + assert_equal(chosen.mask, [1, 0, 0, 1]) + + def test_choose_with_out(self): + # Test choose with an explicit out keyword + choices = [[0, 1, 2, 3], [10, 11, 12, 13], + [20, 21, 22, 23], [30, 31, 32, 33]] + store = empty(4, dtype=int) + chosen = choose([2, 3, 1, 0], choices, out=store) + assert_equal(store, array([20, 31, 12, 3])) + assert_(store is chosen) + # Check with some masked indices + out + store = empty(4, dtype=int) + indices_ = array([2, 3, 1, 0], mask=[1, 0, 0, 1]) + chosen = choose(indices_, choices, mode='wrap', out=store) + assert_equal(store, array([99, 31, 12, 99])) + assert_equal(store.mask, [1, 0, 0, 1]) + # Check with some masked choices + out ina ndarray ! + choices = array(choices, mask=[[0, 0, 0, 1], [1, 1, 0, 1], + [1, 0, 0, 0], [0, 0, 0, 0]]) + indices_ = [2, 3, 1, 0] + store = empty(4, dtype=int).view(ndarray) + chosen = choose(indices_, choices, mode='wrap', out=store) + assert_equal(store, array([999999, 31, 12, 999999])) + + def test_reshape(self): + a = arange(10) + a[0] = masked + # Try the default + b = a.reshape((5, 2)) + assert_equal(b.shape, (5, 2)) + assert_(b.flags['C']) + # Try w/ arguments as list instead of tuple + b = a.reshape(5, 2) + assert_equal(b.shape, (5, 2)) + assert_(b.flags['C']) + # Try w/ order + b = a.reshape((5, 2), order='F') + assert_equal(b.shape, (5, 2)) + assert_(b.flags['F']) + # Try w/ order + b = a.reshape(5, 2, order='F') + assert_equal(b.shape, (5, 2)) + assert_(b.flags['F']) + + c = np.reshape(a, (2, 5)) + assert_(isinstance(c, MaskedArray)) + assert_equal(c.shape, (2, 5)) + assert_(c[0, 0] is masked) + assert_(c.flags['C']) + + def test_make_mask_descr(self): + # Flexible + ntype = [('a', float), ('b', float)] + test = make_mask_descr(ntype) + assert_equal(test, [('a', bool), ('b', bool)]) + assert_(test is make_mask_descr(test)) + + # Standard w/ shape + ntype = (float, 2) + test = make_mask_descr(ntype) + assert_equal(test, (bool, 2)) + assert_(test is make_mask_descr(test)) + + # Standard standard + ntype = float + test = make_mask_descr(ntype) + assert_equal(test, np.dtype(bool)) + assert_(test is make_mask_descr(test)) + + # Nested + ntype = [('a', float), ('b', [('ba', float), ('bb', float)])] + test = make_mask_descr(ntype) + control = np.dtype([('a', 'b1'), ('b', [('ba', 'b1'), ('bb', 'b1')])]) + assert_equal(test, control) + assert_(test is make_mask_descr(test)) + + # Named+ shape + ntype = [('a', (float, 2))] + test = make_mask_descr(ntype) + assert_equal(test, np.dtype([('a', (bool, 2))])) + assert_(test is make_mask_descr(test)) + + # 2 names + ntype = [(('A', 'a'), float)] + test = make_mask_descr(ntype) + assert_equal(test, np.dtype([(('A', 'a'), bool)])) + assert_(test is make_mask_descr(test)) + + # nested boolean types should preserve identity + base_type = np.dtype([('a', int, 3)]) + base_mtype = make_mask_descr(base_type) + sub_type = np.dtype([('a', int), ('b', base_mtype)]) + test = make_mask_descr(sub_type) + assert_equal(test, np.dtype([('a', bool), ('b', [('a', bool, 3)])])) + assert_(test.fields['b'][0] is base_mtype) + + def test_make_mask(self): + # Test make_mask + # w/ a list as an input + mask = [0, 1] + test = make_mask(mask) + assert_equal(test.dtype, MaskType) + assert_equal(test, [0, 1]) + # w/ a ndarray as an input + mask = np.array([0, 1], dtype=bool) + test = make_mask(mask) + assert_equal(test.dtype, MaskType) + assert_equal(test, [0, 1]) + # w/ a flexible-type ndarray as an input - use default + mdtype = [('a', bool), ('b', bool)] + mask = np.array([(0, 0), (0, 1)], dtype=mdtype) + test = make_mask(mask) + assert_equal(test.dtype, MaskType) + assert_equal(test, [1, 1]) + # w/ a flexible-type ndarray as an input - use input dtype + mdtype = [('a', bool), ('b', bool)] + mask = np.array([(0, 0), (0, 1)], dtype=mdtype) + test = make_mask(mask, dtype=mask.dtype) + assert_equal(test.dtype, mdtype) + assert_equal(test, mask) + # w/ a flexible-type ndarray as an input - use input dtype + mdtype = [('a', float), ('b', float)] + bdtype = [('a', bool), ('b', bool)] + mask = np.array([(0, 0), (0, 1)], dtype=mdtype) + test = make_mask(mask, dtype=mask.dtype) + assert_equal(test.dtype, bdtype) + assert_equal(test, np.array([(0, 0), (0, 1)], dtype=bdtype)) + # Ensure this also works for void + mask = np.array((False, True), dtype='?,?')[()] + assert_(isinstance(mask, np.void)) + test = make_mask(mask, dtype=mask.dtype) + assert_equal(test, mask) + assert_(test is not mask) + mask = np.array((0, 1), dtype='i4,i4')[()] + test2 = make_mask(mask, dtype=mask.dtype) + assert_equal(test2, test) + # test that nomask is returned when m is nomask. + bools = [True, False] + dtypes = [MaskType, float] + msgformat = 'copy=%s, shrink=%s, dtype=%s' + for cpy, shr, dt in itertools.product(bools, bools, dtypes): + res = make_mask(nomask, copy=cpy, shrink=shr, dtype=dt) + assert_(res is nomask, msgformat % (cpy, shr, dt)) + + def test_mask_or(self): + # Initialize + mtype = [('a', bool), ('b', bool)] + mask = np.array([(0, 0), (0, 1), (1, 0), (0, 0)], dtype=mtype) + # Test using nomask as input + test = mask_or(mask, nomask) + assert_equal(test, mask) + test = mask_or(nomask, mask) + assert_equal(test, mask) + # Using False as input + test = mask_or(mask, False) + assert_equal(test, mask) + # Using another array w / the same dtype + other = np.array([(0, 1), (0, 1), (0, 1), (0, 1)], dtype=mtype) + test = mask_or(mask, other) + control = np.array([(0, 1), (0, 1), (1, 1), (0, 1)], dtype=mtype) + assert_equal(test, control) + # Using another array w / a different dtype + othertype = [('A', bool), ('B', bool)] + other = np.array([(0, 1), (0, 1), (0, 1), (0, 1)], dtype=othertype) + try: + test = mask_or(mask, other) + except ValueError: + pass + # Using nested arrays + dtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])] + amask = np.array([(0, (1, 0)), (0, (1, 0))], dtype=dtype) + bmask = np.array([(1, (0, 1)), (0, (0, 0))], dtype=dtype) + cntrl = np.array([(1, (1, 1)), (0, (1, 0))], dtype=dtype) + assert_equal(mask_or(amask, bmask), cntrl) + + def test_flatten_mask(self): + # Tests flatten mask + # Standard dtype + mask = np.array([0, 0, 1], dtype=bool) + assert_equal(flatten_mask(mask), mask) + # Flexible dtype + mask = np.array([(0, 0), (0, 1)], dtype=[('a', bool), ('b', bool)]) + test = flatten_mask(mask) + control = np.array([0, 0, 0, 1], dtype=bool) + assert_equal(test, control) + + mdtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])] + data = [(0, (0, 0)), (0, (0, 1))] + mask = np.array(data, dtype=mdtype) + test = flatten_mask(mask) + control = np.array([0, 0, 0, 0, 0, 1], dtype=bool) + assert_equal(test, control) + + def test_on_ndarray(self): + # Test functions on ndarrays + a = np.array([1, 2, 3, 4]) + m = array(a, mask=False) + test = anom(a) + assert_equal(test, m.anom()) + test = reshape(a, (2, 2)) + assert_equal(test, m.reshape(2, 2)) + + def test_compress(self): + # Test compress function on ndarray and masked array + # Address Github #2495. + arr = np.arange(8) + arr.shape = 4, 2 + cond = np.array([True, False, True, True]) + control = arr[[0, 2, 3]] + test = np.ma.compress(cond, arr, axis=0) + assert_equal(test, control) + marr = np.ma.array(arr) + test = np.ma.compress(cond, marr, axis=0) + assert_equal(test, control) + + def test_compressed(self): + # Test ma.compressed function. + # Address gh-4026 + a = np.ma.array([1, 2]) + test = np.ma.compressed(a) + assert_(type(test) is np.ndarray) + + # Test case when input data is ndarray subclass + class A(np.ndarray): + pass + + a = np.ma.array(A(shape=0)) + test = np.ma.compressed(a) + assert_(type(test) is A) + + # Test that compress flattens + test = np.ma.compressed([[1],[2]]) + assert_equal(test.ndim, 1) + test = np.ma.compressed([[[[[1]]]]]) + assert_equal(test.ndim, 1) + + # Test case when input is MaskedArray subclass + class M(MaskedArray): + pass + + test = np.ma.compressed(M(shape=(0,1,2))) + assert_equal(test.ndim, 1) + + # with .compressed() overridden + class M(MaskedArray): + def compressed(self): + return 42 + + test = np.ma.compressed(M(shape=(0,1,2))) + assert_equal(test, 42) + + def test_convolve(self): + a = masked_equal(np.arange(5), 2) + b = np.array([1, 1]) + test = np.ma.convolve(a, b) + assert_equal(test, masked_equal([0, 1, -1, -1, 7, 4], -1)) + + test = np.ma.convolve(a, b, propagate_mask=False) + assert_equal(test, masked_equal([0, 1, 1, 3, 7, 4], -1)) + + test = np.ma.convolve([1, 1], [1, 1, 1]) + assert_equal(test, masked_equal([1, 2, 2, 1], -1)) + + a = [1, 1] + b = masked_equal([1, -1, -1, 1], -1) + test = np.ma.convolve(a, b, propagate_mask=False) + assert_equal(test, masked_equal([1, 1, -1, 1, 1], -1)) + test = np.ma.convolve(a, b, propagate_mask=True) + assert_equal(test, masked_equal([-1, -1, -1, -1, -1], -1)) + + +class TestMaskedFields(object): + + def setup(self): + ilist = [1, 2, 3, 4, 5] + flist = [1.1, 2.2, 3.3, 4.4, 5.5] + slist = ['one', 'two', 'three', 'four', 'five'] + ddtype = [('a', int), ('b', float), ('c', '|S8')] + mdtype = [('a', bool), ('b', bool), ('c', bool)] + mask = [0, 1, 0, 0, 1] + base = array(list(zip(ilist, flist, slist)), mask=mask, dtype=ddtype) + self.data = dict(base=base, mask=mask, ddtype=ddtype, mdtype=mdtype) + + def test_set_records_masks(self): + base = self.data['base'] + mdtype = self.data['mdtype'] + # Set w/ nomask or masked + base.mask = nomask + assert_equal_records(base._mask, np.zeros(base.shape, dtype=mdtype)) + base.mask = masked + assert_equal_records(base._mask, np.ones(base.shape, dtype=mdtype)) + # Set w/ simple boolean + base.mask = False + assert_equal_records(base._mask, np.zeros(base.shape, dtype=mdtype)) + base.mask = True + assert_equal_records(base._mask, np.ones(base.shape, dtype=mdtype)) + # Set w/ list + base.mask = [0, 0, 0, 1, 1] + assert_equal_records(base._mask, + np.array([(x, x, x) for x in [0, 0, 0, 1, 1]], + dtype=mdtype)) + + def test_set_record_element(self): + # Check setting an element of a record) + base = self.data['base'] + (base_a, base_b, base_c) = (base['a'], base['b'], base['c']) + base[0] = (pi, pi, 'pi') + + assert_equal(base_a.dtype, int) + assert_equal(base_a._data, [3, 2, 3, 4, 5]) + + assert_equal(base_b.dtype, float) + assert_equal(base_b._data, [pi, 2.2, 3.3, 4.4, 5.5]) + + assert_equal(base_c.dtype, '|S8') + assert_equal(base_c._data, + [b'pi', b'two', b'three', b'four', b'five']) + + def test_set_record_slice(self): + base = self.data['base'] + (base_a, base_b, base_c) = (base['a'], base['b'], base['c']) + base[:3] = (pi, pi, 'pi') + + assert_equal(base_a.dtype, int) + assert_equal(base_a._data, [3, 3, 3, 4, 5]) + + assert_equal(base_b.dtype, float) + assert_equal(base_b._data, [pi, pi, pi, 4.4, 5.5]) + + assert_equal(base_c.dtype, '|S8') + assert_equal(base_c._data, + [b'pi', b'pi', b'pi', b'four', b'five']) + + def test_mask_element(self): + "Check record access" + base = self.data['base'] + base[0] = masked + + for n in ('a', 'b', 'c'): + assert_equal(base[n].mask, [1, 1, 0, 0, 1]) + assert_equal(base[n]._data, base._data[n]) + + def test_getmaskarray(self): + # Test getmaskarray on flexible dtype + ndtype = [('a', int), ('b', float)] + test = empty(3, dtype=ndtype) + assert_equal(getmaskarray(test), + np.array([(0, 0), (0, 0), (0, 0)], + dtype=[('a', '|b1'), ('b', '|b1')])) + test[:] = masked + assert_equal(getmaskarray(test), + np.array([(1, 1), (1, 1), (1, 1)], + dtype=[('a', '|b1'), ('b', '|b1')])) + + def test_view(self): + # Test view w/ flexible dtype + iterator = list(zip(np.arange(10), np.random.rand(10))) + data = np.array(iterator) + a = array(iterator, dtype=[('a', float), ('b', float)]) + a.mask[0] = (1, 0) + controlmask = np.array([1] + 19 * [0], dtype=bool) + # Transform globally to simple dtype + test = a.view(float) + assert_equal(test, data.ravel()) + assert_equal(test.mask, controlmask) + # Transform globally to dty + test = a.view((float, 2)) + assert_equal(test, data) + assert_equal(test.mask, controlmask.reshape(-1, 2)) + + test = a.view((float, 2), np.matrix) + assert_equal(test, data) + assert_(isinstance(test, np.matrix)) + + def test_getitem(self): + ndtype = [('a', float), ('b', float)] + a = array(list(zip(np.random.rand(10), np.arange(10))), dtype=ndtype) + a.mask = np.array(list(zip([0, 0, 0, 0, 0, 0, 0, 0, 1, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 1, 0])), + dtype=[('a', bool), ('b', bool)]) + + def _test_index(i): + assert_equal(type(a[i]), mvoid) + assert_equal_records(a[i]._data, a._data[i]) + assert_equal_records(a[i]._mask, a._mask[i]) + + assert_equal(type(a[i, ...]), MaskedArray) + assert_equal_records(a[i,...]._data, a._data[i,...]) + assert_equal_records(a[i,...]._mask, a._mask[i,...]) + + _test_index(1) # No mask + _test_index(0) # One element masked + _test_index(-2) # All element masked + + def test_setitem(self): + # Issue 4866: check that one can set individual items in [record][col] + # and [col][record] order + ndtype = np.dtype([('a', float), ('b', int)]) + ma = np.ma.MaskedArray([(1.0, 1), (2.0, 2)], dtype=ndtype) + ma['a'][1] = 3.0 + assert_equal(ma['a'], np.array([1.0, 3.0])) + ma[1]['a'] = 4.0 + assert_equal(ma['a'], np.array([1.0, 4.0])) + # Issue 2403 + mdtype = np.dtype([('a', bool), ('b', bool)]) + # soft mask + control = np.array([(False, True), (True, True)], dtype=mdtype) + a = np.ma.masked_all((2,), dtype=ndtype) + a['a'][0] = 2 + assert_equal(a.mask, control) + a = np.ma.masked_all((2,), dtype=ndtype) + a[0]['a'] = 2 + assert_equal(a.mask, control) + # hard mask + control = np.array([(True, True), (True, True)], dtype=mdtype) + a = np.ma.masked_all((2,), dtype=ndtype) + a.harden_mask() + a['a'][0] = 2 + assert_equal(a.mask, control) + a = np.ma.masked_all((2,), dtype=ndtype) + a.harden_mask() + a[0]['a'] = 2 + assert_equal(a.mask, control) + + def test_setitem_scalar(self): + # 8510 + mask_0d = np.ma.masked_array(1, mask=True) + arr = np.ma.arange(3) + arr[0] = mask_0d + assert_array_equal(arr.mask, [True, False, False]) + + def test_element_len(self): + # check that len() works for mvoid (Github issue #576) + for rec in self.data['base']: + assert_equal(len(rec), len(self.data['ddtype'])) + + +class TestMaskedObjectArray(object): + + def test_getitem(self): + arr = np.ma.array([None, None]) + for dt in [float, object]: + a0 = np.eye(2).astype(dt) + a1 = np.eye(3).astype(dt) + arr[0] = a0 + arr[1] = a1 + + assert_(arr[0] is a0) + assert_(arr[1] is a1) + assert_(isinstance(arr[0,...], MaskedArray)) + assert_(isinstance(arr[1,...], MaskedArray)) + assert_(arr[0,...][()] is a0) + assert_(arr[1,...][()] is a1) + + arr[0] = np.ma.masked + + assert_(arr[1] is a1) + assert_(isinstance(arr[0,...], MaskedArray)) + assert_(isinstance(arr[1,...], MaskedArray)) + assert_equal(arr[0,...].mask, True) + assert_(arr[1,...][()] is a1) + + # gh-5962 - object arrays of arrays do something special + assert_equal(arr[0].data, a0) + assert_equal(arr[0].mask, True) + assert_equal(arr[0,...][()].data, a0) + assert_equal(arr[0,...][()].mask, True) + + def test_nested_ma(self): + + arr = np.ma.array([None, None]) + # set the first object to be an unmasked masked constant. A little fiddly + arr[0,...] = np.array([np.ma.masked], object)[0,...] + + # check the above line did what we were aiming for + assert_(arr.data[0] is np.ma.masked) + + # test that getitem returned the value by identity + assert_(arr[0] is np.ma.masked) + + # now mask the masked value! + arr[0] = np.ma.masked + assert_(arr[0] is np.ma.masked) + + +class TestMaskedView(object): + + def setup(self): + iterator = list(zip(np.arange(10), np.random.rand(10))) + data = np.array(iterator) + a = array(iterator, dtype=[('a', float), ('b', float)]) + a.mask[0] = (1, 0) + controlmask = np.array([1] + 19 * [0], dtype=bool) + self.data = (data, a, controlmask) + + def test_view_to_nothing(self): + (data, a, controlmask) = self.data + test = a.view() + assert_(isinstance(test, MaskedArray)) + assert_equal(test._data, a._data) + assert_equal(test._mask, a._mask) + + def test_view_to_type(self): + (data, a, controlmask) = self.data + test = a.view(np.ndarray) + assert_(not isinstance(test, MaskedArray)) + assert_equal(test, a._data) + assert_equal_records(test, data.view(a.dtype).squeeze()) + + def test_view_to_simple_dtype(self): + (data, a, controlmask) = self.data + # View globally + test = a.view(float) + assert_(isinstance(test, MaskedArray)) + assert_equal(test, data.ravel()) + assert_equal(test.mask, controlmask) + + def test_view_to_flexible_dtype(self): + (data, a, controlmask) = self.data + + test = a.view([('A', float), ('B', float)]) + assert_equal(test.mask.dtype.names, ('A', 'B')) + assert_equal(test['A'], a['a']) + assert_equal(test['B'], a['b']) + + test = a[0].view([('A', float), ('B', float)]) + assert_(isinstance(test, MaskedArray)) + assert_equal(test.mask.dtype.names, ('A', 'B')) + assert_equal(test['A'], a['a'][0]) + assert_equal(test['B'], a['b'][0]) + + test = a[-1].view([('A', float), ('B', float)]) + assert_(isinstance(test, MaskedArray)) + assert_equal(test.dtype.names, ('A', 'B')) + assert_equal(test['A'], a['a'][-1]) + assert_equal(test['B'], a['b'][-1]) + + def test_view_to_subdtype(self): + (data, a, controlmask) = self.data + # View globally + test = a.view((float, 2)) + assert_(isinstance(test, MaskedArray)) + assert_equal(test, data) + assert_equal(test.mask, controlmask.reshape(-1, 2)) + # View on 1 masked element + test = a[0].view((float, 2)) + assert_(isinstance(test, MaskedArray)) + assert_equal(test, data[0]) + assert_equal(test.mask, (1, 0)) + # View on 1 unmasked element + test = a[-1].view((float, 2)) + assert_(isinstance(test, MaskedArray)) + assert_equal(test, data[-1]) + + def test_view_to_dtype_and_type(self): + (data, a, controlmask) = self.data + + test = a.view((float, 2), np.matrix) + assert_equal(test, data) + assert_(isinstance(test, np.matrix)) + assert_(not isinstance(test, MaskedArray)) + +class TestOptionalArgs(object): + def test_ndarrayfuncs(self): + # test axis arg behaves the same as ndarray (including multiple axes) + + d = np.arange(24.0).reshape((2,3,4)) + m = np.zeros(24, dtype=bool).reshape((2,3,4)) + # mask out last element of last dimension + m[:,:,-1] = True + a = np.ma.array(d, mask=m) + + def testaxis(f, a, d): + numpy_f = numpy.__getattribute__(f) + ma_f = np.ma.__getattribute__(f) + + # test axis arg + assert_equal(ma_f(a, axis=1)[...,:-1], numpy_f(d[...,:-1], axis=1)) + assert_equal(ma_f(a, axis=(0,1))[...,:-1], + numpy_f(d[...,:-1], axis=(0,1))) + + def testkeepdims(f, a, d): + numpy_f = numpy.__getattribute__(f) + ma_f = np.ma.__getattribute__(f) + + # test keepdims arg + assert_equal(ma_f(a, keepdims=True).shape, + numpy_f(d, keepdims=True).shape) + assert_equal(ma_f(a, keepdims=False).shape, + numpy_f(d, keepdims=False).shape) + + # test both at once + assert_equal(ma_f(a, axis=1, keepdims=True)[...,:-1], + numpy_f(d[...,:-1], axis=1, keepdims=True)) + assert_equal(ma_f(a, axis=(0,1), keepdims=True)[...,:-1], + numpy_f(d[...,:-1], axis=(0,1), keepdims=True)) + + for f in ['sum', 'prod', 'mean', 'var', 'std']: + testaxis(f, a, d) + testkeepdims(f, a, d) + + for f in ['min', 'max']: + testaxis(f, a, d) + + d = (np.arange(24).reshape((2,3,4))%2 == 0) + a = np.ma.array(d, mask=m) + for f in ['all', 'any']: + testaxis(f, a, d) + testkeepdims(f, a, d) + + def test_count(self): + # test np.ma.count specially + + d = np.arange(24.0).reshape((2,3,4)) + m = np.zeros(24, dtype=bool).reshape((2,3,4)) + m[:,0,:] = True + a = np.ma.array(d, mask=m) + + assert_equal(count(a), 16) + assert_equal(count(a, axis=1), 2*ones((2,4))) + assert_equal(count(a, axis=(0,1)), 4*ones((4,))) + assert_equal(count(a, keepdims=True), 16*ones((1,1,1))) + assert_equal(count(a, axis=1, keepdims=True), 2*ones((2,1,4))) + assert_equal(count(a, axis=(0,1), keepdims=True), 4*ones((1,1,4))) + assert_equal(count(a, axis=-2), 2*ones((2,4))) + assert_raises(ValueError, count, a, axis=(1,1)) + assert_raises(np.AxisError, count, a, axis=3) + + # check the 'nomask' path + a = np.ma.array(d, mask=nomask) + + assert_equal(count(a), 24) + assert_equal(count(a, axis=1), 3*ones((2,4))) + assert_equal(count(a, axis=(0,1)), 6*ones((4,))) + assert_equal(count(a, keepdims=True), 24*ones((1,1,1))) + assert_equal(np.ndim(count(a, keepdims=True)), 3) + assert_equal(count(a, axis=1, keepdims=True), 3*ones((2,1,4))) + assert_equal(count(a, axis=(0,1), keepdims=True), 6*ones((1,1,4))) + assert_equal(count(a, axis=-2), 3*ones((2,4))) + assert_raises(ValueError, count, a, axis=(1,1)) + assert_raises(np.AxisError, count, a, axis=3) + + # check the 'masked' singleton + assert_equal(count(np.ma.masked), 0) + + # check 0-d arrays do not allow axis > 0 + assert_raises(np.AxisError, count, np.ma.array(1), axis=1) + + +class TestMaskedConstant(object): + def _do_add_test(self, add): + # sanity check + assert_(add(np.ma.masked, 1) is np.ma.masked) + + # now try with a vector + vector = np.array([1, 2, 3]) + result = add(np.ma.masked, vector) + + # lots of things could go wrong here + assert_(result is not np.ma.masked) + assert_(not isinstance(result, np.ma.core.MaskedConstant)) + assert_equal(result.shape, vector.shape) + assert_equal(np.ma.getmask(result), np.ones(vector.shape, dtype=bool)) + + def test_ufunc(self): + self._do_add_test(np.add) + + def test_operator(self): + self._do_add_test(lambda a, b: a + b) + + def test_ctor(self): + m = np.ma.array(np.ma.masked) + + # most importantly, we do not want to create a new MaskedConstant + # instance + assert_(not isinstance(m, np.ma.core.MaskedConstant)) + assert_(m is not np.ma.masked) + + def test_repr(self): + # copies should not exist, but if they do, it should be obvious that + # something is wrong + assert_equal(repr(np.ma.masked), 'masked') + + # create a new instance in a weird way + masked2 = np.ma.MaskedArray.__new__(np.ma.core.MaskedConstant) + assert_not_equal(repr(masked2), 'masked') + + def test_pickle(self): + from io import BytesIO + import pickle + + with BytesIO() as f: + pickle.dump(np.ma.masked, f) + f.seek(0) + res = pickle.load(f) + assert_(res is np.ma.masked) + + def test_copy(self): + # gh-9328 + # copy is a no-op, like it is with np.True_ + assert_equal( + np.ma.masked.copy() is np.ma.masked, + np.True_.copy() is np.True_) + + def test_immutable(self): + orig = np.ma.masked + assert_raises(np.ma.core.MaskError, operator.setitem, orig, (), 1) + assert_raises(ValueError,operator.setitem, orig.data, (), 1) + assert_raises(ValueError, operator.setitem, orig.mask, (), False) + + view = np.ma.masked.view(np.ma.MaskedArray) + assert_raises(ValueError, operator.setitem, view, (), 1) + assert_raises(ValueError, operator.setitem, view.data, (), 1) + assert_raises(ValueError, operator.setitem, view.mask, (), False) + + def test_coercion_int(self): + a_i = np.zeros((), int) + assert_raises(MaskError, operator.setitem, a_i, (), np.ma.masked) + assert_raises(MaskError, int, np.ma.masked) + + @dec.skipif(sys.version_info.major == 3, "long doesn't exist in Python 3") + def test_coercion_long(self): + assert_raises(MaskError, long, np.ma.masked) + + def test_coercion_float(self): + a_f = np.zeros((), float) + assert_warns(UserWarning, operator.setitem, a_f, (), np.ma.masked) + assert_(np.isnan(a_f[()])) + + @dec.knownfailureif(True, "See gh-9750") + def test_coercion_unicode(self): + a_u = np.zeros((), 'U10') + a_u[()] = np.ma.masked + assert_equal(a_u[()], u'--') + + @dec.knownfailureif(True, "See gh-9750") + def test_coercion_bytes(self): + a_b = np.zeros((), 'S10') + a_b[()] = np.ma.masked + assert_equal(a_b[()], b'--') + + def test_subclass(self): + # https://github.com/astropy/astropy/issues/6645 + class Sub(type(np.ma.masked)): pass + + a = Sub() + assert_(a is Sub()) + assert_(a is not np.ma.masked) + assert_not_equal(repr(a), 'masked') + + +class TestMaskedWhereAliases(object): + + # TODO: Test masked_object, masked_equal, ... + + def test_masked_values(self): + res = masked_values(np.array([-32768.0]), np.int16(-32768)) + assert_equal(res.mask, [True]) + + res = masked_values(np.inf, np.inf) + assert_equal(res.mask, True) + + res = np.ma.masked_values(np.inf, -np.inf) + assert_equal(res.mask, False) + + +def test_masked_array(): + a = np.ma.array([0, 1, 2, 3], mask=[0, 0, 1, 0]) + assert_equal(np.argwhere(a), [[1], [3]]) + +def test_append_masked_array(): + a = np.ma.masked_equal([1,2,3], value=2) + b = np.ma.masked_equal([4,3,2], value=2) + + result = np.ma.append(a, b) + expected_data = [1, 2, 3, 4, 3, 2] + expected_mask = [False, True, False, False, False, True] + assert_array_equal(result.data, expected_data) + assert_array_equal(result.mask, expected_mask) + + a = np.ma.masked_all((2,2)) + b = np.ma.ones((3,1)) + + result = np.ma.append(a, b) + expected_data = [1] * 3 + expected_mask = [True] * 4 + [False] * 3 + assert_array_equal(result.data[-3], expected_data) + assert_array_equal(result.mask, expected_mask) + + result = np.ma.append(a, b, axis=None) + assert_array_equal(result.data[-3], expected_data) + assert_array_equal(result.mask, expected_mask) + + +def test_append_masked_array_along_axis(): + a = np.ma.masked_equal([1,2,3], value=2) + b = np.ma.masked_values([[4, 5, 6], [7, 8, 9]], 7) + + # When `axis` is specified, `values` must have the correct shape. + assert_raises(ValueError, np.ma.append, a, b, axis=0) + + result = np.ma.append(a[np.newaxis,:], b, axis=0) + expected = np.ma.arange(1, 10) + expected[[1, 6]] = np.ma.masked + expected = expected.reshape((3,3)) + assert_array_equal(result.data, expected.data) + assert_array_equal(result.mask, expected.mask) + + +def test_default_fill_value_complex(): + # regression test for Python 3, where 'unicode' was not defined + assert_(default_fill_value(1 + 1j) == 1.e20 + 0.0j) + + +def test_ufunc_with_output(): + # check that giving an output argument always returns that output. + # Regression test for gh-8416. + x = array([1., 2., 3.], mask=[0, 0, 1]) + y = np.add(x, 1., out=x) + assert_(y is x) + + +def test_ufunc_with_out_varied(): + """ Test that masked arrays are immune to gh-10459 """ + # the mask of the output should not affect the result, however it is passed + a = array([ 1, 2, 3], mask=[1, 0, 0]) + b = array([10, 20, 30], mask=[1, 0, 0]) + out = array([ 0, 0, 0], mask=[0, 0, 1]) + expected = array([11, 22, 33], mask=[1, 0, 0]) + + out_pos = out.copy() + res_pos = np.add(a, b, out_pos) + + out_kw = out.copy() + res_kw = np.add(a, b, out=out_kw) + + out_tup = out.copy() + res_tup = np.add(a, b, out=(out_tup,)) + + assert_equal(res_kw.mask, expected.mask) + assert_equal(res_kw.data, expected.data) + assert_equal(res_tup.mask, expected.mask) + assert_equal(res_tup.data, expected.data) + assert_equal(res_pos.mask, expected.mask) + assert_equal(res_pos.data, expected.data) + + +def test_astype(): + descr = [('v', int, 3), ('x', [('y', float)])] + x = array(([1, 2, 3], (1.0,)), dtype=descr) + assert_equal(x, x.astype(descr)) + + +############################################################################### +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/ma/tests/test_deprecations.py b/numpy/ma/tests/test_deprecations.py new file mode 100644 index 0000000..23c0954 --- /dev/null +++ b/numpy/ma/tests/test_deprecations.py @@ -0,0 +1,74 @@ +"""Test deprecation and future warnings. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import run_module_suite, assert_warns +from numpy.ma.testutils import assert_equal +from numpy.ma.core import MaskedArrayFutureWarning + +class TestArgsort(object): + """ gh-8701 """ + def _test_base(self, argsort, cls): + arr_0d = np.array(1).view(cls) + argsort(arr_0d) + + arr_1d = np.array([1, 2, 3]).view(cls) + argsort(arr_1d) + + # argsort has a bad default for >1d arrays + arr_2d = np.array([[1, 2], [3, 4]]).view(cls) + result = assert_warns( + np.ma.core.MaskedArrayFutureWarning, argsort, arr_2d) + assert_equal(result, argsort(arr_2d, axis=None)) + + # should be no warnings for explicitly specifying it + argsort(arr_2d, axis=None) + argsort(arr_2d, axis=-1) + + def test_function_ndarray(self): + return self._test_base(np.ma.argsort, np.ndarray) + + def test_function_maskedarray(self): + return self._test_base(np.ma.argsort, np.ma.MaskedArray) + + def test_method(self): + return self._test_base(np.ma.MaskedArray.argsort, np.ma.MaskedArray) + + +class TestMinimumMaximum(object): + def test_minimum(self): + assert_warns(DeprecationWarning, np.ma.minimum, np.ma.array([1, 2])) + + def test_maximum(self): + assert_warns(DeprecationWarning, np.ma.maximum, np.ma.array([1, 2])) + + def test_axis_default(self): + # NumPy 1.13, 2017-05-06 + + data1d = np.ma.arange(6) + data2d = data1d.reshape(2, 3) + + ma_min = np.ma.minimum.reduce + ma_max = np.ma.maximum.reduce + + # check that the default axis is still None, but warns on 2d arrays + result = assert_warns(MaskedArrayFutureWarning, ma_max, data2d) + assert_equal(result, ma_max(data2d, axis=None)) + + result = assert_warns(MaskedArrayFutureWarning, ma_min, data2d) + assert_equal(result, ma_min(data2d, axis=None)) + + # no warnings on 1d, as both new and old defaults are equivalent + result = ma_min(data1d) + assert_equal(result, ma_min(data1d, axis=None)) + assert_equal(result, ma_min(data1d, axis=0)) + + result = ma_max(data1d) + assert_equal(result, ma_max(data1d, axis=None)) + assert_equal(result, ma_max(data1d, axis=0)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/ma/tests/test_extras.py b/numpy/ma/tests/test_extras.py new file mode 100644 index 0000000..e768eff --- /dev/null +++ b/numpy/ma/tests/test_extras.py @@ -0,0 +1,1592 @@ +# pylint: disable-msg=W0611, W0612, W0511 +"""Tests suite for MaskedArray. +Adapted from the original test_ma by Pierre Gerard-Marchant + +:author: Pierre Gerard-Marchant +:contact: pierregm_at_uga_dot_edu +:version: $Id: test_extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $ + +""" +from __future__ import division, absolute_import, print_function + +import warnings +import itertools + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_warns, suppress_warnings, assert_raises, + ) +from numpy.ma.testutils import ( + assert_, assert_array_equal, assert_equal, assert_almost_equal + ) +from numpy.ma.core import ( + array, arange, masked, MaskedArray, masked_array, getmaskarray, shape, + nomask, ones, zeros, count + ) +from numpy.ma.extras import ( + atleast_1d, atleast_2d, atleast_3d, mr_, dot, polyfit, cov, corrcoef, + median, average, unique, setxor1d, setdiff1d, union1d, intersect1d, in1d, + ediff1d, apply_over_axes, apply_along_axis, compress_nd, compress_rowcols, + mask_rowcols, clump_masked, clump_unmasked, flatnotmasked_contiguous, + notmasked_contiguous, notmasked_edges, masked_all, masked_all_like, isin, + diagflat + ) +import numpy.ma.extras as mae + + +class TestGeneric(object): + # + def test_masked_all(self): + # Tests masked_all + # Standard dtype + test = masked_all((2,), dtype=float) + control = array([1, 1], mask=[1, 1], dtype=float) + assert_equal(test, control) + # Flexible dtype + dt = np.dtype({'names': ['a', 'b'], 'formats': ['f', 'f']}) + test = masked_all((2,), dtype=dt) + control = array([(0, 0), (0, 0)], mask=[(1, 1), (1, 1)], dtype=dt) + assert_equal(test, control) + test = masked_all((2, 2), dtype=dt) + control = array([[(0, 0), (0, 0)], [(0, 0), (0, 0)]], + mask=[[(1, 1), (1, 1)], [(1, 1), (1, 1)]], + dtype=dt) + assert_equal(test, control) + # Nested dtype + dt = np.dtype([('a', 'f'), ('b', [('ba', 'f'), ('bb', 'f')])]) + test = masked_all((2,), dtype=dt) + control = array([(1, (1, 1)), (1, (1, 1))], + mask=[(1, (1, 1)), (1, (1, 1))], dtype=dt) + assert_equal(test, control) + test = masked_all((2,), dtype=dt) + control = array([(1, (1, 1)), (1, (1, 1))], + mask=[(1, (1, 1)), (1, (1, 1))], dtype=dt) + assert_equal(test, control) + test = masked_all((1, 1), dtype=dt) + control = array([[(1, (1, 1))]], mask=[[(1, (1, 1))]], dtype=dt) + assert_equal(test, control) + + def test_masked_all_like(self): + # Tests masked_all + # Standard dtype + base = array([1, 2], dtype=float) + test = masked_all_like(base) + control = array([1, 1], mask=[1, 1], dtype=float) + assert_equal(test, control) + # Flexible dtype + dt = np.dtype({'names': ['a', 'b'], 'formats': ['f', 'f']}) + base = array([(0, 0), (0, 0)], mask=[(1, 1), (1, 1)], dtype=dt) + test = masked_all_like(base) + control = array([(10, 10), (10, 10)], mask=[(1, 1), (1, 1)], dtype=dt) + assert_equal(test, control) + # Nested dtype + dt = np.dtype([('a', 'f'), ('b', [('ba', 'f'), ('bb', 'f')])]) + control = array([(1, (1, 1)), (1, (1, 1))], + mask=[(1, (1, 1)), (1, (1, 1))], dtype=dt) + test = masked_all_like(control) + assert_equal(test, control) + + def check_clump(self, f): + for i in range(1, 7): + for j in range(2**i): + k = np.arange(i, dtype=int) + ja = np.full(i, j, dtype=int) + a = masked_array(2**k) + a.mask = (ja & (2**k)) != 0 + s = 0 + for sl in f(a): + s += a.data[sl].sum() + if f == clump_unmasked: + assert_equal(a.compressed().sum(), s) + else: + a.mask = ~a.mask + assert_equal(a.compressed().sum(), s) + + def test_clump_masked(self): + # Test clump_masked + a = masked_array(np.arange(10)) + a[[0, 1, 2, 6, 8, 9]] = masked + # + test = clump_masked(a) + control = [slice(0, 3), slice(6, 7), slice(8, 10)] + assert_equal(test, control) + + self.check_clump(clump_masked) + + def test_clump_unmasked(self): + # Test clump_unmasked + a = masked_array(np.arange(10)) + a[[0, 1, 2, 6, 8, 9]] = masked + test = clump_unmasked(a) + control = [slice(3, 6), slice(7, 8), ] + assert_equal(test, control) + + self.check_clump(clump_unmasked) + + def test_flatnotmasked_contiguous(self): + # Test flatnotmasked_contiguous + a = arange(10) + # No mask + test = flatnotmasked_contiguous(a) + assert_equal(test, slice(0, a.size)) + # Some mask + a[(a < 3) | (a > 8) | (a == 5)] = masked + test = flatnotmasked_contiguous(a) + assert_equal(test, [slice(3, 5), slice(6, 9)]) + # + a[:] = masked + test = flatnotmasked_contiguous(a) + assert_equal(test, None) + + +class TestAverage(object): + # Several tests of average. Why so many ? Good point... + def test_testAverage1(self): + # Test of average. + ott = array([0., 1., 2., 3.], mask=[True, False, False, False]) + assert_equal(2.0, average(ott, axis=0)) + assert_equal(2.0, average(ott, weights=[1., 1., 2., 1.])) + result, wts = average(ott, weights=[1., 1., 2., 1.], returned=1) + assert_equal(2.0, result) + assert_(wts == 4.0) + ott[:] = masked + assert_equal(average(ott, axis=0).mask, [True]) + ott = array([0., 1., 2., 3.], mask=[True, False, False, False]) + ott = ott.reshape(2, 2) + ott[:, 1] = masked + assert_equal(average(ott, axis=0), [2.0, 0.0]) + assert_equal(average(ott, axis=1).mask[0], [True]) + assert_equal([2., 0.], average(ott, axis=0)) + result, wts = average(ott, axis=0, returned=1) + assert_equal(wts, [1., 0.]) + + def test_testAverage2(self): + # More tests of average. + w1 = [0, 1, 1, 1, 1, 0] + w2 = [[0, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 1]] + x = arange(6, dtype=np.float_) + assert_equal(average(x, axis=0), 2.5) + assert_equal(average(x, axis=0, weights=w1), 2.5) + y = array([arange(6, dtype=np.float_), 2.0 * arange(6)]) + assert_equal(average(y, None), np.add.reduce(np.arange(6)) * 3. / 12.) + assert_equal(average(y, axis=0), np.arange(6) * 3. / 2.) + assert_equal(average(y, axis=1), + [average(x, axis=0), average(x, axis=0) * 2.0]) + assert_equal(average(y, None, weights=w2), 20. / 6.) + assert_equal(average(y, axis=0, weights=w2), + [0., 1., 2., 3., 4., 10.]) + assert_equal(average(y, axis=1), + [average(x, axis=0), average(x, axis=0) * 2.0]) + m1 = zeros(6) + m2 = [0, 0, 1, 1, 0, 0] + m3 = [[0, 0, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0]] + m4 = ones(6) + m5 = [0, 1, 1, 1, 1, 1] + assert_equal(average(masked_array(x, m1), axis=0), 2.5) + assert_equal(average(masked_array(x, m2), axis=0), 2.5) + assert_equal(average(masked_array(x, m4), axis=0).mask, [True]) + assert_equal(average(masked_array(x, m5), axis=0), 0.0) + assert_equal(count(average(masked_array(x, m4), axis=0)), 0) + z = masked_array(y, m3) + assert_equal(average(z, None), 20. / 6.) + assert_equal(average(z, axis=0), [0., 1., 99., 99., 4.0, 7.5]) + assert_equal(average(z, axis=1), [2.5, 5.0]) + assert_equal(average(z, axis=0, weights=w2), + [0., 1., 99., 99., 4.0, 10.0]) + + def test_testAverage3(self): + # Yet more tests of average! + a = arange(6) + b = arange(6) * 3 + r1, w1 = average([[a, b], [b, a]], axis=1, returned=1) + assert_equal(shape(r1), shape(w1)) + assert_equal(r1.shape, w1.shape) + r2, w2 = average(ones((2, 2, 3)), axis=0, weights=[3, 1], returned=1) + assert_equal(shape(w2), shape(r2)) + r2, w2 = average(ones((2, 2, 3)), returned=1) + assert_equal(shape(w2), shape(r2)) + r2, w2 = average(ones((2, 2, 3)), weights=ones((2, 2, 3)), returned=1) + assert_equal(shape(w2), shape(r2)) + a2d = array([[1, 2], [0, 4]], float) + a2dm = masked_array(a2d, [[False, False], [True, False]]) + a2da = average(a2d, axis=0) + assert_equal(a2da, [0.5, 3.0]) + a2dma = average(a2dm, axis=0) + assert_equal(a2dma, [1.0, 3.0]) + a2dma = average(a2dm, axis=None) + assert_equal(a2dma, 7. / 3.) + a2dma = average(a2dm, axis=1) + assert_equal(a2dma, [1.5, 4.0]) + + def test_onintegers_with_mask(self): + # Test average on integers with mask + a = average(array([1, 2])) + assert_equal(a, 1.5) + a = average(array([1, 2, 3, 4], mask=[False, False, True, True])) + assert_equal(a, 1.5) + + def test_complex(self): + # Test with complex data. + # (Regression test for https://github.com/numpy/numpy/issues/2684) + mask = np.array([[0, 0, 0, 1, 0], + [0, 1, 0, 0, 0]], dtype=bool) + a = masked_array([[0, 1+2j, 3+4j, 5+6j, 7+8j], + [9j, 0+1j, 2+3j, 4+5j, 7+7j]], + mask=mask) + + av = average(a) + expected = np.average(a.compressed()) + assert_almost_equal(av.real, expected.real) + assert_almost_equal(av.imag, expected.imag) + + av0 = average(a, axis=0) + expected0 = average(a.real, axis=0) + average(a.imag, axis=0)*1j + assert_almost_equal(av0.real, expected0.real) + assert_almost_equal(av0.imag, expected0.imag) + + av1 = average(a, axis=1) + expected1 = average(a.real, axis=1) + average(a.imag, axis=1)*1j + assert_almost_equal(av1.real, expected1.real) + assert_almost_equal(av1.imag, expected1.imag) + + # Test with the 'weights' argument. + wts = np.array([[0.5, 1.0, 2.0, 1.0, 0.5], + [1.0, 1.0, 1.0, 1.0, 1.0]]) + wav = average(a, weights=wts) + expected = np.average(a.compressed(), weights=wts[~mask]) + assert_almost_equal(wav.real, expected.real) + assert_almost_equal(wav.imag, expected.imag) + + wav0 = average(a, weights=wts, axis=0) + expected0 = (average(a.real, weights=wts, axis=0) + + average(a.imag, weights=wts, axis=0)*1j) + assert_almost_equal(wav0.real, expected0.real) + assert_almost_equal(wav0.imag, expected0.imag) + + wav1 = average(a, weights=wts, axis=1) + expected1 = (average(a.real, weights=wts, axis=1) + + average(a.imag, weights=wts, axis=1)*1j) + assert_almost_equal(wav1.real, expected1.real) + assert_almost_equal(wav1.imag, expected1.imag) + + +class TestConcatenator(object): + # Tests for mr_, the equivalent of r_ for masked arrays. + + def test_1d(self): + # Tests mr_ on 1D arrays. + assert_array_equal(mr_[1, 2, 3, 4, 5, 6], array([1, 2, 3, 4, 5, 6])) + b = ones(5) + m = [1, 0, 0, 0, 0] + d = masked_array(b, mask=m) + c = mr_[d, 0, 0, d] + assert_(isinstance(c, MaskedArray)) + assert_array_equal(c, [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1]) + assert_array_equal(c.mask, mr_[m, 0, 0, m]) + + def test_2d(self): + # Tests mr_ on 2D arrays. + a_1 = np.random.rand(5, 5) + a_2 = np.random.rand(5, 5) + m_1 = np.round_(np.random.rand(5, 5), 0) + m_2 = np.round_(np.random.rand(5, 5), 0) + b_1 = masked_array(a_1, mask=m_1) + b_2 = masked_array(a_2, mask=m_2) + # append columns + d = mr_['1', b_1, b_2] + assert_(d.shape == (5, 10)) + assert_array_equal(d[:, :5], b_1) + assert_array_equal(d[:, 5:], b_2) + assert_array_equal(d.mask, np.r_['1', m_1, m_2]) + d = mr_[b_1, b_2] + assert_(d.shape == (10, 5)) + assert_array_equal(d[:5,:], b_1) + assert_array_equal(d[5:,:], b_2) + assert_array_equal(d.mask, np.r_[m_1, m_2]) + + def test_matrix_builder(self): + assert_raises(np.ma.MAError, lambda: mr_['1, 2; 3, 4']) + + def test_matrix(self): + actual = mr_['r', 1, 2, 3] + expected = np.ma.array(np.r_['r', 1, 2, 3]) + assert_array_equal(actual, expected) + + # outer type is masked array, inner type is matrix + assert_equal(type(actual), type(expected)) + assert_equal(type(actual.data), type(expected.data)) + + +class TestNotMasked(object): + # Tests notmasked_edges and notmasked_contiguous. + + def test_edges(self): + # Tests unmasked_edges + data = masked_array(np.arange(25).reshape(5, 5), + mask=[[0, 0, 1, 0, 0], + [0, 0, 0, 1, 1], + [1, 1, 0, 0, 0], + [0, 0, 0, 0, 0], + [1, 1, 1, 0, 0]],) + test = notmasked_edges(data, None) + assert_equal(test, [0, 24]) + test = notmasked_edges(data, 0) + assert_equal(test[0], [(0, 0, 1, 0, 0), (0, 1, 2, 3, 4)]) + assert_equal(test[1], [(3, 3, 3, 4, 4), (0, 1, 2, 3, 4)]) + test = notmasked_edges(data, 1) + assert_equal(test[0], [(0, 1, 2, 3, 4), (0, 0, 2, 0, 3)]) + assert_equal(test[1], [(0, 1, 2, 3, 4), (4, 2, 4, 4, 4)]) + # + test = notmasked_edges(data.data, None) + assert_equal(test, [0, 24]) + test = notmasked_edges(data.data, 0) + assert_equal(test[0], [(0, 0, 0, 0, 0), (0, 1, 2, 3, 4)]) + assert_equal(test[1], [(4, 4, 4, 4, 4), (0, 1, 2, 3, 4)]) + test = notmasked_edges(data.data, -1) + assert_equal(test[0], [(0, 1, 2, 3, 4), (0, 0, 0, 0, 0)]) + assert_equal(test[1], [(0, 1, 2, 3, 4), (4, 4, 4, 4, 4)]) + # + data[-2] = masked + test = notmasked_edges(data, 0) + assert_equal(test[0], [(0, 0, 1, 0, 0), (0, 1, 2, 3, 4)]) + assert_equal(test[1], [(1, 1, 2, 4, 4), (0, 1, 2, 3, 4)]) + test = notmasked_edges(data, -1) + assert_equal(test[0], [(0, 1, 2, 4), (0, 0, 2, 3)]) + assert_equal(test[1], [(0, 1, 2, 4), (4, 2, 4, 4)]) + + def test_contiguous(self): + # Tests notmasked_contiguous + a = masked_array(np.arange(24).reshape(3, 8), + mask=[[0, 0, 0, 0, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 1, 0], ]) + tmp = notmasked_contiguous(a, None) + assert_equal(tmp[-1], slice(23, 24, None)) + assert_equal(tmp[-2], slice(16, 22, None)) + assert_equal(tmp[-3], slice(0, 4, None)) + # + tmp = notmasked_contiguous(a, 0) + assert_(len(tmp[-1]) == 1) + assert_(tmp[-2] is None) + assert_equal(tmp[-3], tmp[-1]) + assert_(len(tmp[0]) == 2) + # + tmp = notmasked_contiguous(a, 1) + assert_equal(tmp[0][-1], slice(0, 4, None)) + assert_(tmp[1] is None) + assert_equal(tmp[2][-1], slice(7, 8, None)) + assert_equal(tmp[2][-2], slice(0, 6, None)) + + +class TestCompressFunctions(object): + + def test_compress_nd(self): + # Tests compress_nd + x = np.array(list(range(3*4*5))).reshape(3, 4, 5) + m = np.zeros((3,4,5)).astype(bool) + m[1,1,1] = True + x = array(x, mask=m) + + # axis=None + a = compress_nd(x) + assert_equal(a, [[[ 0, 2, 3, 4], + [10, 12, 13, 14], + [15, 17, 18, 19]], + [[40, 42, 43, 44], + [50, 52, 53, 54], + [55, 57, 58, 59]]]) + + # axis=0 + a = compress_nd(x, 0) + assert_equal(a, [[[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14], + [15, 16, 17, 18, 19]], + [[40, 41, 42, 43, 44], + [45, 46, 47, 48, 49], + [50, 51, 52, 53, 54], + [55, 56, 57, 58, 59]]]) + + # axis=1 + a = compress_nd(x, 1) + assert_equal(a, [[[ 0, 1, 2, 3, 4], + [10, 11, 12, 13, 14], + [15, 16, 17, 18, 19]], + [[20, 21, 22, 23, 24], + [30, 31, 32, 33, 34], + [35, 36, 37, 38, 39]], + [[40, 41, 42, 43, 44], + [50, 51, 52, 53, 54], + [55, 56, 57, 58, 59]]]) + + a2 = compress_nd(x, (1,)) + a3 = compress_nd(x, -2) + a4 = compress_nd(x, (-2,)) + assert_equal(a, a2) + assert_equal(a, a3) + assert_equal(a, a4) + + # axis=2 + a = compress_nd(x, 2) + assert_equal(a, [[[ 0, 2, 3, 4], + [ 5, 7, 8, 9], + [10, 12, 13, 14], + [15, 17, 18, 19]], + [[20, 22, 23, 24], + [25, 27, 28, 29], + [30, 32, 33, 34], + [35, 37, 38, 39]], + [[40, 42, 43, 44], + [45, 47, 48, 49], + [50, 52, 53, 54], + [55, 57, 58, 59]]]) + + a2 = compress_nd(x, (2,)) + a3 = compress_nd(x, -1) + a4 = compress_nd(x, (-1,)) + assert_equal(a, a2) + assert_equal(a, a3) + assert_equal(a, a4) + + # axis=(0, 1) + a = compress_nd(x, (0, 1)) + assert_equal(a, [[[ 0, 1, 2, 3, 4], + [10, 11, 12, 13, 14], + [15, 16, 17, 18, 19]], + [[40, 41, 42, 43, 44], + [50, 51, 52, 53, 54], + [55, 56, 57, 58, 59]]]) + a2 = compress_nd(x, (0, -2)) + assert_equal(a, a2) + + # axis=(1, 2) + a = compress_nd(x, (1, 2)) + assert_equal(a, [[[ 0, 2, 3, 4], + [10, 12, 13, 14], + [15, 17, 18, 19]], + [[20, 22, 23, 24], + [30, 32, 33, 34], + [35, 37, 38, 39]], + [[40, 42, 43, 44], + [50, 52, 53, 54], + [55, 57, 58, 59]]]) + + a2 = compress_nd(x, (-2, 2)) + a3 = compress_nd(x, (1, -1)) + a4 = compress_nd(x, (-2, -1)) + assert_equal(a, a2) + assert_equal(a, a3) + assert_equal(a, a4) + + # axis=(0, 2) + a = compress_nd(x, (0, 2)) + assert_equal(a, [[[ 0, 2, 3, 4], + [ 5, 7, 8, 9], + [10, 12, 13, 14], + [15, 17, 18, 19]], + [[40, 42, 43, 44], + [45, 47, 48, 49], + [50, 52, 53, 54], + [55, 57, 58, 59]]]) + + a2 = compress_nd(x, (0, -1)) + assert_equal(a, a2) + + def test_compress_rowcols(self): + # Tests compress_rowcols + x = array(np.arange(9).reshape(3, 3), + mask=[[1, 0, 0], [0, 0, 0], [0, 0, 0]]) + assert_equal(compress_rowcols(x), [[4, 5], [7, 8]]) + assert_equal(compress_rowcols(x, 0), [[3, 4, 5], [6, 7, 8]]) + assert_equal(compress_rowcols(x, 1), [[1, 2], [4, 5], [7, 8]]) + x = array(x._data, mask=[[0, 0, 0], [0, 1, 0], [0, 0, 0]]) + assert_equal(compress_rowcols(x), [[0, 2], [6, 8]]) + assert_equal(compress_rowcols(x, 0), [[0, 1, 2], [6, 7, 8]]) + assert_equal(compress_rowcols(x, 1), [[0, 2], [3, 5], [6, 8]]) + x = array(x._data, mask=[[1, 0, 0], [0, 1, 0], [0, 0, 0]]) + assert_equal(compress_rowcols(x), [[8]]) + assert_equal(compress_rowcols(x, 0), [[6, 7, 8]]) + assert_equal(compress_rowcols(x, 1,), [[2], [5], [8]]) + x = array(x._data, mask=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + assert_equal(compress_rowcols(x).size, 0) + assert_equal(compress_rowcols(x, 0).size, 0) + assert_equal(compress_rowcols(x, 1).size, 0) + + def test_mask_rowcols(self): + # Tests mask_rowcols. + x = array(np.arange(9).reshape(3, 3), + mask=[[1, 0, 0], [0, 0, 0], [0, 0, 0]]) + assert_equal(mask_rowcols(x).mask, + [[1, 1, 1], [1, 0, 0], [1, 0, 0]]) + assert_equal(mask_rowcols(x, 0).mask, + [[1, 1, 1], [0, 0, 0], [0, 0, 0]]) + assert_equal(mask_rowcols(x, 1).mask, + [[1, 0, 0], [1, 0, 0], [1, 0, 0]]) + x = array(x._data, mask=[[0, 0, 0], [0, 1, 0], [0, 0, 0]]) + assert_equal(mask_rowcols(x).mask, + [[0, 1, 0], [1, 1, 1], [0, 1, 0]]) + assert_equal(mask_rowcols(x, 0).mask, + [[0, 0, 0], [1, 1, 1], [0, 0, 0]]) + assert_equal(mask_rowcols(x, 1).mask, + [[0, 1, 0], [0, 1, 0], [0, 1, 0]]) + x = array(x._data, mask=[[1, 0, 0], [0, 1, 0], [0, 0, 0]]) + assert_equal(mask_rowcols(x).mask, + [[1, 1, 1], [1, 1, 1], [1, 1, 0]]) + assert_equal(mask_rowcols(x, 0).mask, + [[1, 1, 1], [1, 1, 1], [0, 0, 0]]) + assert_equal(mask_rowcols(x, 1,).mask, + [[1, 1, 0], [1, 1, 0], [1, 1, 0]]) + x = array(x._data, mask=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + assert_(mask_rowcols(x).all() is masked) + assert_(mask_rowcols(x, 0).all() is masked) + assert_(mask_rowcols(x, 1).all() is masked) + assert_(mask_rowcols(x).mask.all()) + assert_(mask_rowcols(x, 0).mask.all()) + assert_(mask_rowcols(x, 1).mask.all()) + + def test_dot(self): + # Tests dot product + n = np.arange(1, 7) + # + m = [1, 0, 0, 0, 0, 0] + a = masked_array(n, mask=m).reshape(2, 3) + b = masked_array(n, mask=m).reshape(3, 2) + c = dot(a, b, strict=True) + assert_equal(c.mask, [[1, 1], [1, 0]]) + c = dot(b, a, strict=True) + assert_equal(c.mask, [[1, 1, 1], [1, 0, 0], [1, 0, 0]]) + c = dot(a, b, strict=False) + assert_equal(c, np.dot(a.filled(0), b.filled(0))) + c = dot(b, a, strict=False) + assert_equal(c, np.dot(b.filled(0), a.filled(0))) + # + m = [0, 0, 0, 0, 0, 1] + a = masked_array(n, mask=m).reshape(2, 3) + b = masked_array(n, mask=m).reshape(3, 2) + c = dot(a, b, strict=True) + assert_equal(c.mask, [[0, 1], [1, 1]]) + c = dot(b, a, strict=True) + assert_equal(c.mask, [[0, 0, 1], [0, 0, 1], [1, 1, 1]]) + c = dot(a, b, strict=False) + assert_equal(c, np.dot(a.filled(0), b.filled(0))) + assert_equal(c, dot(a, b)) + c = dot(b, a, strict=False) + assert_equal(c, np.dot(b.filled(0), a.filled(0))) + # + m = [0, 0, 0, 0, 0, 0] + a = masked_array(n, mask=m).reshape(2, 3) + b = masked_array(n, mask=m).reshape(3, 2) + c = dot(a, b) + assert_equal(c.mask, nomask) + c = dot(b, a) + assert_equal(c.mask, nomask) + # + a = masked_array(n, mask=[1, 0, 0, 0, 0, 0]).reshape(2, 3) + b = masked_array(n, mask=[0, 0, 0, 0, 0, 0]).reshape(3, 2) + c = dot(a, b, strict=True) + assert_equal(c.mask, [[1, 1], [0, 0]]) + c = dot(a, b, strict=False) + assert_equal(c, np.dot(a.filled(0), b.filled(0))) + c = dot(b, a, strict=True) + assert_equal(c.mask, [[1, 0, 0], [1, 0, 0], [1, 0, 0]]) + c = dot(b, a, strict=False) + assert_equal(c, np.dot(b.filled(0), a.filled(0))) + # + a = masked_array(n, mask=[0, 0, 0, 0, 0, 1]).reshape(2, 3) + b = masked_array(n, mask=[0, 0, 0, 0, 0, 0]).reshape(3, 2) + c = dot(a, b, strict=True) + assert_equal(c.mask, [[0, 0], [1, 1]]) + c = dot(a, b) + assert_equal(c, np.dot(a.filled(0), b.filled(0))) + c = dot(b, a, strict=True) + assert_equal(c.mask, [[0, 0, 1], [0, 0, 1], [0, 0, 1]]) + c = dot(b, a, strict=False) + assert_equal(c, np.dot(b.filled(0), a.filled(0))) + # + a = masked_array(n, mask=[0, 0, 0, 0, 0, 1]).reshape(2, 3) + b = masked_array(n, mask=[0, 0, 1, 0, 0, 0]).reshape(3, 2) + c = dot(a, b, strict=True) + assert_equal(c.mask, [[1, 0], [1, 1]]) + c = dot(a, b, strict=False) + assert_equal(c, np.dot(a.filled(0), b.filled(0))) + c = dot(b, a, strict=True) + assert_equal(c.mask, [[0, 0, 1], [1, 1, 1], [0, 0, 1]]) + c = dot(b, a, strict=False) + assert_equal(c, np.dot(b.filled(0), a.filled(0))) + + def test_dot_returns_maskedarray(self): + # See gh-6611 + a = np.eye(3) + b = array(a) + assert_(type(dot(a, a)) is MaskedArray) + assert_(type(dot(a, b)) is MaskedArray) + assert_(type(dot(b, a)) is MaskedArray) + assert_(type(dot(b, b)) is MaskedArray) + + def test_dot_out(self): + a = array(np.eye(3)) + out = array(np.zeros((3, 3))) + res = dot(a, a, out=out) + assert_(res is out) + assert_equal(a, res) + + +class TestApplyAlongAxis(object): + # Tests 2D functions + def test_3d(self): + a = arange(12.).reshape(2, 2, 3) + + def myfunc(b): + return b[1] + + xa = apply_along_axis(myfunc, 2, a) + assert_equal(xa, [[1, 4], [7, 10]]) + + # Tests kwargs functions + def test_3d_kwargs(self): + a = arange(12).reshape(2, 2, 3) + + def myfunc(b, offset=0): + return b[1+offset] + + xa = apply_along_axis(myfunc, 2, a, offset=1) + assert_equal(xa, [[2, 5], [8, 11]]) + + +class TestApplyOverAxes(object): + # Tests apply_over_axes + def test_basic(self): + a = arange(24).reshape(2, 3, 4) + test = apply_over_axes(np.sum, a, [0, 2]) + ctrl = np.array([[[60], [92], [124]]]) + assert_equal(test, ctrl) + a[(a % 2).astype(bool)] = masked + test = apply_over_axes(np.sum, a, [0, 2]) + ctrl = np.array([[[28], [44], [60]]]) + assert_equal(test, ctrl) + + +class TestMedian(object): + def test_pytype(self): + r = np.ma.median([[np.inf, np.inf], [np.inf, np.inf]], axis=-1) + assert_equal(r, np.inf) + + def test_inf(self): + # test that even which computes handles inf / x = masked + r = np.ma.median(np.ma.masked_array([[np.inf, np.inf], + [np.inf, np.inf]]), axis=-1) + assert_equal(r, np.inf) + r = np.ma.median(np.ma.masked_array([[np.inf, np.inf], + [np.inf, np.inf]]), axis=None) + assert_equal(r, np.inf) + # all masked + r = np.ma.median(np.ma.masked_array([[np.inf, np.inf], + [np.inf, np.inf]], mask=True), + axis=-1) + assert_equal(r.mask, True) + r = np.ma.median(np.ma.masked_array([[np.inf, np.inf], + [np.inf, np.inf]], mask=True), + axis=None) + assert_equal(r.mask, True) + + def test_non_masked(self): + x = np.arange(9) + assert_equal(np.ma.median(x), 4.) + assert_(type(np.ma.median(x)) is not MaskedArray) + x = range(8) + assert_equal(np.ma.median(x), 3.5) + assert_(type(np.ma.median(x)) is not MaskedArray) + x = 5 + assert_equal(np.ma.median(x), 5.) + assert_(type(np.ma.median(x)) is not MaskedArray) + # integer + x = np.arange(9 * 8).reshape(9, 8) + assert_equal(np.ma.median(x, axis=0), np.median(x, axis=0)) + assert_equal(np.ma.median(x, axis=1), np.median(x, axis=1)) + assert_(np.ma.median(x, axis=1) is not MaskedArray) + # float + x = np.arange(9 * 8.).reshape(9, 8) + assert_equal(np.ma.median(x, axis=0), np.median(x, axis=0)) + assert_equal(np.ma.median(x, axis=1), np.median(x, axis=1)) + assert_(np.ma.median(x, axis=1) is not MaskedArray) + + def test_docstring_examples(self): + "test the examples given in the docstring of ma.median" + x = array(np.arange(8), mask=[0]*4 + [1]*4) + assert_equal(np.ma.median(x), 1.5) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + x = array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4) + assert_equal(np.ma.median(x), 2.5) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + ma_x = np.ma.median(x, axis=-1, overwrite_input=True) + assert_equal(ma_x, [2., 5.]) + assert_equal(ma_x.shape, (2,), "shape mismatch") + assert_(type(ma_x) is MaskedArray) + + def test_axis_argument_errors(self): + msg = "mask = %s, ndim = %s, axis = %s, overwrite_input = %s" + for ndmin in range(5): + for mask in [False, True]: + x = array(1, ndmin=ndmin, mask=mask) + + # Valid axis values should not raise exception + args = itertools.product(range(-ndmin, ndmin), [False, True]) + for axis, over in args: + try: + np.ma.median(x, axis=axis, overwrite_input=over) + except Exception: + raise AssertionError(msg % (mask, ndmin, axis, over)) + + # Invalid axis values should raise exception + args = itertools.product([-(ndmin + 1), ndmin], [False, True]) + for axis, over in args: + try: + np.ma.median(x, axis=axis, overwrite_input=over) + except np.AxisError: + pass + else: + raise AssertionError(msg % (mask, ndmin, axis, over)) + + def test_masked_0d(self): + # Check values + x = array(1, mask=False) + assert_equal(np.ma.median(x), 1) + x = array(1, mask=True) + assert_equal(np.ma.median(x), np.ma.masked) + + def test_masked_1d(self): + x = array(np.arange(5), mask=True) + assert_equal(np.ma.median(x), np.ma.masked) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is np.ma.core.MaskedConstant) + x = array(np.arange(5), mask=False) + assert_equal(np.ma.median(x), 2.) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + x = array(np.arange(5), mask=[0,1,0,0,0]) + assert_equal(np.ma.median(x), 2.5) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + x = array(np.arange(5), mask=[0,1,1,1,1]) + assert_equal(np.ma.median(x), 0.) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + # integer + x = array(np.arange(5), mask=[0,1,1,0,0]) + assert_equal(np.ma.median(x), 3.) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + # float + x = array(np.arange(5.), mask=[0,1,1,0,0]) + assert_equal(np.ma.median(x), 3.) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + # integer + x = array(np.arange(6), mask=[0,1,1,1,1,0]) + assert_equal(np.ma.median(x), 2.5) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + # float + x = array(np.arange(6.), mask=[0,1,1,1,1,0]) + assert_equal(np.ma.median(x), 2.5) + assert_equal(np.ma.median(x).shape, (), "shape mismatch") + assert_(type(np.ma.median(x)) is not MaskedArray) + + def test_1d_shape_consistency(self): + assert_equal(np.ma.median(array([1,2,3],mask=[0,0,0])).shape, + np.ma.median(array([1,2,3],mask=[0,1,0])).shape ) + + def test_2d(self): + # Tests median w/ 2D + (n, p) = (101, 30) + x = masked_array(np.linspace(-1., 1., n),) + x[:10] = x[-10:] = masked + z = masked_array(np.empty((n, p), dtype=float)) + z[:, 0] = x[:] + idx = np.arange(len(x)) + for i in range(1, p): + np.random.shuffle(idx) + z[:, i] = x[idx] + assert_equal(median(z[:, 0]), 0) + assert_equal(median(z), 0) + assert_equal(median(z, axis=0), np.zeros(p)) + assert_equal(median(z.T, axis=1), np.zeros(p)) + + def test_2d_waxis(self): + # Tests median w/ 2D arrays and different axis. + x = masked_array(np.arange(30).reshape(10, 3)) + x[:3] = x[-3:] = masked + assert_equal(median(x), 14.5) + assert_(type(np.ma.median(x)) is not MaskedArray) + assert_equal(median(x, axis=0), [13.5, 14.5, 15.5]) + assert_(type(np.ma.median(x, axis=0)) is MaskedArray) + assert_equal(median(x, axis=1), [0, 0, 0, 10, 13, 16, 19, 0, 0, 0]) + assert_(type(np.ma.median(x, axis=1)) is MaskedArray) + assert_equal(median(x, axis=1).mask, [1, 1, 1, 0, 0, 0, 0, 1, 1, 1]) + + def test_3d(self): + # Tests median w/ 3D + x = np.ma.arange(24).reshape(3, 4, 2) + x[x % 3 == 0] = masked + assert_equal(median(x, 0), [[12, 9], [6, 15], [12, 9], [18, 15]]) + x.shape = (4, 3, 2) + assert_equal(median(x, 0), [[99, 10], [11, 99], [13, 14]]) + x = np.ma.arange(24).reshape(4, 3, 2) + x[x % 5 == 0] = masked + assert_equal(median(x, 0), [[12, 10], [8, 9], [16, 17]]) + + def test_neg_axis(self): + x = masked_array(np.arange(30).reshape(10, 3)) + x[:3] = x[-3:] = masked + assert_equal(median(x, axis=-1), median(x, axis=1)) + + def test_out_1d(self): + # integer float even odd + for v in (30, 30., 31, 31.): + x = masked_array(np.arange(v)) + x[:3] = x[-3:] = masked + out = masked_array(np.ones(())) + r = median(x, out=out) + if v == 30: + assert_equal(out, 14.5) + else: + assert_equal(out, 15.) + assert_(r is out) + assert_(type(r) is MaskedArray) + + def test_out(self): + # integer float even odd + for v in (40, 40., 30, 30.): + x = masked_array(np.arange(v).reshape(10, -1)) + x[:3] = x[-3:] = masked + out = masked_array(np.ones(10)) + r = median(x, axis=1, out=out) + if v == 30: + e = masked_array([0.]*3 + [10, 13, 16, 19] + [0.]*3, + mask=[True] * 3 + [False] * 4 + [True] * 3) + else: + e = masked_array([0.]*3 + [13.5, 17.5, 21.5, 25.5] + [0.]*3, + mask=[True]*3 + [False]*4 + [True]*3) + assert_equal(r, e) + assert_(r is out) + assert_(type(r) is MaskedArray) + + def test_single_non_masked_value_on_axis(self): + data = [[1., 0.], + [0., 3.], + [0., 0.]] + masked_arr = np.ma.masked_equal(data, 0) + expected = [1., 3.] + assert_array_equal(np.ma.median(masked_arr, axis=0), + expected) + + def test_nan(self): + with suppress_warnings() as w: + w.record(RuntimeWarning) + for mask in (False, np.zeros(6, dtype=bool)): + dm = np.ma.array([[1, np.nan, 3], [1, 2, 3]]) + dm.mask = mask + + # scalar result + r = np.ma.median(dm, axis=None) + assert_(np.isscalar(r)) + assert_array_equal(r, np.nan) + r = np.ma.median(dm.ravel(), axis=0) + assert_(np.isscalar(r)) + assert_array_equal(r, np.nan) + + r = np.ma.median(dm, axis=0) + assert_equal(type(r), MaskedArray) + assert_array_equal(r, [1, np.nan, 3]) + r = np.ma.median(dm, axis=1) + assert_equal(type(r), MaskedArray) + assert_array_equal(r, [np.nan, 2]) + r = np.ma.median(dm, axis=-1) + assert_equal(type(r), MaskedArray) + assert_array_equal(r, [np.nan, 2]) + + dm = np.ma.array([[1, np.nan, 3], [1, 2, 3]]) + dm[:, 2] = np.ma.masked + assert_array_equal(np.ma.median(dm, axis=None), np.nan) + assert_array_equal(np.ma.median(dm, axis=0), [1, np.nan, 3]) + assert_array_equal(np.ma.median(dm, axis=1), [np.nan, 1.5]) + assert_equal([x.category is RuntimeWarning for x in w.log], + [True]*13) + + def test_out_nan(self): + with warnings.catch_warnings(record=True): + warnings.filterwarnings('always', '', RuntimeWarning) + o = np.ma.masked_array(np.zeros((4,))) + d = np.ma.masked_array(np.ones((3, 4))) + d[2, 1] = np.nan + d[2, 2] = np.ma.masked + assert_equal(np.ma.median(d, 0, out=o), o) + o = np.ma.masked_array(np.zeros((3,))) + assert_equal(np.ma.median(d, 1, out=o), o) + o = np.ma.masked_array(np.zeros(())) + assert_equal(np.ma.median(d, out=o), o) + + def test_nan_behavior(self): + a = np.ma.masked_array(np.arange(24, dtype=float)) + a[::3] = np.ma.masked + a[2] = np.nan + with suppress_warnings() as w: + w.record(RuntimeWarning) + assert_array_equal(np.ma.median(a), np.nan) + assert_array_equal(np.ma.median(a, axis=0), np.nan) + assert_(w.log[0].category is RuntimeWarning) + assert_(w.log[1].category is RuntimeWarning) + + a = np.ma.masked_array(np.arange(24, dtype=float).reshape(2, 3, 4)) + a.mask = np.arange(a.size) % 2 == 1 + aorig = a.copy() + a[1, 2, 3] = np.nan + a[1, 1, 2] = np.nan + + # no axis + with suppress_warnings() as w: + w.record(RuntimeWarning) + warnings.filterwarnings('always', '', RuntimeWarning) + assert_array_equal(np.ma.median(a), np.nan) + assert_(np.isscalar(np.ma.median(a))) + assert_(w.log[0].category is RuntimeWarning) + + # axis0 + b = np.ma.median(aorig, axis=0) + b[2, 3] = np.nan + b[1, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.ma.median(a, 0), b) + assert_equal(len(w), 1) + + # axis1 + b = np.ma.median(aorig, axis=1) + b[1, 3] = np.nan + b[1, 2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.ma.median(a, 1), b) + assert_equal(len(w), 1) + + # axis02 + b = np.ma.median(aorig, axis=(0, 2)) + b[1] = np.nan + b[2] = np.nan + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.ma.median(a, (0, 2)), b) + assert_equal(len(w), 1) + + def test_ambigous_fill(self): + # 255 is max value, used as filler for sort + a = np.array([[3, 3, 255], [3, 3, 255]], dtype=np.uint8) + a = np.ma.masked_array(a, mask=a == 3) + assert_array_equal(np.ma.median(a, axis=1), 255) + assert_array_equal(np.ma.median(a, axis=1).mask, False) + assert_array_equal(np.ma.median(a, axis=0), a[0]) + assert_array_equal(np.ma.median(a), 255) + + def test_special(self): + for inf in [np.inf, -np.inf]: + a = np.array([[inf, np.nan], [np.nan, np.nan]]) + a = np.ma.masked_array(a, mask=np.isnan(a)) + assert_equal(np.ma.median(a, axis=0), [inf, np.nan]) + assert_equal(np.ma.median(a, axis=1), [inf, np.nan]) + assert_equal(np.ma.median(a), inf) + + a = np.array([[np.nan, np.nan, inf], [np.nan, np.nan, inf]]) + a = np.ma.masked_array(a, mask=np.isnan(a)) + assert_array_equal(np.ma.median(a, axis=1), inf) + assert_array_equal(np.ma.median(a, axis=1).mask, False) + assert_array_equal(np.ma.median(a, axis=0), a[0]) + assert_array_equal(np.ma.median(a), inf) + + # no mask + a = np.array([[inf, inf], [inf, inf]]) + assert_equal(np.ma.median(a), inf) + assert_equal(np.ma.median(a, axis=0), inf) + assert_equal(np.ma.median(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) + a = np.ma.masked_array(a, mask=np.isnan(a)) + if inf > 0: + assert_equal(np.ma.median(a, axis=0), [4., 7., -inf, 5.]) + assert_equal(np.ma.median(a), 4.5) + else: + assert_equal(np.ma.median(a, axis=0), [-10., 7., -inf, -9.]) + assert_equal(np.ma.median(a), -2.5) + assert_equal(np.ma.median(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) + a = np.ma.masked_array(a, mask=np.isnan(a)) + assert_equal(np.ma.median(a), inf) + assert_equal(np.ma.median(a, axis=1), inf) + assert_equal(np.ma.median(a, axis=0), + ([np.nan] * i) + [inf] * j) + + def test_empty(self): + # empty arrays + a = np.ma.masked_array(np.array([], dtype=float)) + with suppress_warnings() as w: + w.record(RuntimeWarning) + assert_array_equal(np.ma.median(a), np.nan) + assert_(w.log[0].category is RuntimeWarning) + + # multiple dimensions + a = np.ma.masked_array(np.array([], dtype=float, ndmin=3)) + # no axis + with suppress_warnings() as w: + w.record(RuntimeWarning) + warnings.filterwarnings('always', '', RuntimeWarning) + assert_array_equal(np.ma.median(a), np.nan) + assert_(w.log[0].category is RuntimeWarning) + + # axis 0 and 1 + b = np.ma.masked_array(np.array([], dtype=float, ndmin=2)) + assert_equal(np.ma.median(a, axis=0), b) + assert_equal(np.ma.median(a, axis=1), b) + + # axis 2 + b = np.ma.masked_array(np.array(np.nan, dtype=float, ndmin=2)) + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', '', RuntimeWarning) + assert_equal(np.ma.median(a, axis=2), b) + assert_(w[0].category is RuntimeWarning) + + def test_object(self): + o = np.ma.masked_array(np.arange(7.)) + assert_(type(np.ma.median(o.astype(object))), float) + o[2] = np.nan + assert_(type(np.ma.median(o.astype(object))), float) + + +class TestCov(object): + + def setup(self): + self.data = array(np.random.rand(12)) + + def test_1d_without_missing(self): + # Test cov on 1D variable w/o missing values + x = self.data + assert_almost_equal(np.cov(x), cov(x)) + assert_almost_equal(np.cov(x, rowvar=False), cov(x, rowvar=False)) + assert_almost_equal(np.cov(x, rowvar=False, bias=True), + cov(x, rowvar=False, bias=True)) + + def test_2d_without_missing(self): + # Test cov on 1 2D variable w/o missing values + x = self.data.reshape(3, 4) + assert_almost_equal(np.cov(x), cov(x)) + assert_almost_equal(np.cov(x, rowvar=False), cov(x, rowvar=False)) + assert_almost_equal(np.cov(x, rowvar=False, bias=True), + cov(x, rowvar=False, bias=True)) + + def test_1d_with_missing(self): + # Test cov 1 1D variable w/missing values + x = self.data + x[-1] = masked + x -= x.mean() + nx = x.compressed() + assert_almost_equal(np.cov(nx), cov(x)) + assert_almost_equal(np.cov(nx, rowvar=False), cov(x, rowvar=False)) + assert_almost_equal(np.cov(nx, rowvar=False, bias=True), + cov(x, rowvar=False, bias=True)) + # + try: + cov(x, allow_masked=False) + except ValueError: + pass + # + # 2 1D variables w/ missing values + nx = x[1:-1] + assert_almost_equal(np.cov(nx, nx[::-1]), cov(x, x[::-1])) + assert_almost_equal(np.cov(nx, nx[::-1], rowvar=False), + cov(x, x[::-1], rowvar=False)) + assert_almost_equal(np.cov(nx, nx[::-1], rowvar=False, bias=True), + cov(x, x[::-1], rowvar=False, bias=True)) + + def test_2d_with_missing(self): + # Test cov on 2D variable w/ missing value + x = self.data + x[-1] = masked + x = x.reshape(3, 4) + valid = np.logical_not(getmaskarray(x)).astype(int) + frac = np.dot(valid, valid.T) + xf = (x - x.mean(1)[:, None]).filled(0) + assert_almost_equal(cov(x), + np.cov(xf) * (x.shape[1] - 1) / (frac - 1.)) + assert_almost_equal(cov(x, bias=True), + np.cov(xf, bias=True) * x.shape[1] / frac) + frac = np.dot(valid.T, valid) + xf = (x - x.mean(0)).filled(0) + assert_almost_equal(cov(x, rowvar=False), + (np.cov(xf, rowvar=False) * + (x.shape[0] - 1) / (frac - 1.))) + assert_almost_equal(cov(x, rowvar=False, bias=True), + (np.cov(xf, rowvar=False, bias=True) * + x.shape[0] / frac)) + + +class TestCorrcoef(object): + + def setup(self): + self.data = array(np.random.rand(12)) + self.data2 = array(np.random.rand(12)) + + def test_ddof(self): + # ddof raises DeprecationWarning + x, y = self.data, self.data2 + expected = np.corrcoef(x) + expected2 = np.corrcoef(x, y) + with suppress_warnings() as sup: + warnings.simplefilter("always") + assert_warns(DeprecationWarning, corrcoef, x, ddof=-1) + sup.filter(DeprecationWarning, "bias and ddof have no effect") + # ddof has no or negligible effect on the function + assert_almost_equal(np.corrcoef(x, ddof=0), corrcoef(x, ddof=0)) + assert_almost_equal(corrcoef(x, ddof=-1), expected) + assert_almost_equal(corrcoef(x, y, ddof=-1), expected2) + assert_almost_equal(corrcoef(x, ddof=3), expected) + assert_almost_equal(corrcoef(x, y, ddof=3), expected2) + + def test_bias(self): + x, y = self.data, self.data2 + expected = np.corrcoef(x) + # bias raises DeprecationWarning + with suppress_warnings() as sup: + warnings.simplefilter("always") + assert_warns(DeprecationWarning, corrcoef, x, y, True, False) + assert_warns(DeprecationWarning, corrcoef, x, y, True, True) + assert_warns(DeprecationWarning, corrcoef, x, bias=False) + sup.filter(DeprecationWarning, "bias and ddof have no effect") + # bias has no or negligible effect on the function + assert_almost_equal(corrcoef(x, bias=1), expected) + + def test_1d_without_missing(self): + # Test cov on 1D variable w/o missing values + x = self.data + assert_almost_equal(np.corrcoef(x), corrcoef(x)) + assert_almost_equal(np.corrcoef(x, rowvar=False), + corrcoef(x, rowvar=False)) + with suppress_warnings() as sup: + sup.filter(DeprecationWarning, "bias and ddof have no effect") + assert_almost_equal(np.corrcoef(x, rowvar=False, bias=True), + corrcoef(x, rowvar=False, bias=True)) + + def test_2d_without_missing(self): + # Test corrcoef on 1 2D variable w/o missing values + x = self.data.reshape(3, 4) + assert_almost_equal(np.corrcoef(x), corrcoef(x)) + assert_almost_equal(np.corrcoef(x, rowvar=False), + corrcoef(x, rowvar=False)) + with suppress_warnings() as sup: + sup.filter(DeprecationWarning, "bias and ddof have no effect") + assert_almost_equal(np.corrcoef(x, rowvar=False, bias=True), + corrcoef(x, rowvar=False, bias=True)) + + def test_1d_with_missing(self): + # Test corrcoef 1 1D variable w/missing values + x = self.data + x[-1] = masked + x -= x.mean() + nx = x.compressed() + assert_almost_equal(np.corrcoef(nx), corrcoef(x)) + assert_almost_equal(np.corrcoef(nx, rowvar=False), + corrcoef(x, rowvar=False)) + with suppress_warnings() as sup: + sup.filter(DeprecationWarning, "bias and ddof have no effect") + assert_almost_equal(np.corrcoef(nx, rowvar=False, bias=True), + corrcoef(x, rowvar=False, bias=True)) + try: + corrcoef(x, allow_masked=False) + except ValueError: + pass + # 2 1D variables w/ missing values + nx = x[1:-1] + assert_almost_equal(np.corrcoef(nx, nx[::-1]), corrcoef(x, x[::-1])) + assert_almost_equal(np.corrcoef(nx, nx[::-1], rowvar=False), + corrcoef(x, x[::-1], rowvar=False)) + with suppress_warnings() as sup: + sup.filter(DeprecationWarning, "bias and ddof have no effect") + # ddof and bias have no or negligible effect on the function + assert_almost_equal(np.corrcoef(nx, nx[::-1]), + corrcoef(x, x[::-1], bias=1)) + assert_almost_equal(np.corrcoef(nx, nx[::-1]), + corrcoef(x, x[::-1], ddof=2)) + + def test_2d_with_missing(self): + # Test corrcoef on 2D variable w/ missing value + x = self.data + x[-1] = masked + x = x.reshape(3, 4) + + test = corrcoef(x) + control = np.corrcoef(x) + assert_almost_equal(test[:-1, :-1], control[:-1, :-1]) + with suppress_warnings() as sup: + sup.filter(DeprecationWarning, "bias and ddof have no effect") + # ddof and bias have no or negligible effect on the function + assert_almost_equal(corrcoef(x, ddof=-2)[:-1, :-1], + control[:-1, :-1]) + assert_almost_equal(corrcoef(x, ddof=3)[:-1, :-1], + control[:-1, :-1]) + assert_almost_equal(corrcoef(x, bias=1)[:-1, :-1], + control[:-1, :-1]) + + +class TestPolynomial(object): + # + def test_polyfit(self): + # Tests polyfit + # On ndarrays + x = np.random.rand(10) + y = np.random.rand(20).reshape(-1, 2) + assert_almost_equal(polyfit(x, y, 3), np.polyfit(x, y, 3)) + # ON 1D maskedarrays + x = x.view(MaskedArray) + x[0] = masked + y = y.view(MaskedArray) + y[0, 0] = y[-1, -1] = masked + # + (C, R, K, S, D) = polyfit(x, y[:, 0], 3, full=True) + (c, r, k, s, d) = np.polyfit(x[1:], y[1:, 0].compressed(), 3, + full=True) + for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)): + assert_almost_equal(a, a_) + # + (C, R, K, S, D) = polyfit(x, y[:, -1], 3, full=True) + (c, r, k, s, d) = np.polyfit(x[1:-1], y[1:-1, -1], 3, full=True) + for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)): + assert_almost_equal(a, a_) + # + (C, R, K, S, D) = polyfit(x, y, 3, full=True) + (c, r, k, s, d) = np.polyfit(x[1:-1], y[1:-1,:], 3, full=True) + for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)): + assert_almost_equal(a, a_) + # + w = np.random.rand(10) + 1 + wo = w.copy() + xs = x[1:-1] + ys = y[1:-1] + ws = w[1:-1] + (C, R, K, S, D) = polyfit(x, y, 3, full=True, w=w) + (c, r, k, s, d) = np.polyfit(xs, ys, 3, full=True, w=ws) + assert_equal(w, wo) + for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)): + assert_almost_equal(a, a_) + + def test_polyfit_with_masked_NaNs(self): + x = np.random.rand(10) + y = np.random.rand(20).reshape(-1, 2) + + x[0] = np.nan + y[-1,-1] = np.nan + x = x.view(MaskedArray) + y = y.view(MaskedArray) + x[0] = masked + y[-1,-1] = masked + + (C, R, K, S, D) = polyfit(x, y, 3, full=True) + (c, r, k, s, d) = np.polyfit(x[1:-1], y[1:-1,:], 3, full=True) + for (a, a_) in zip((C, R, K, S, D), (c, r, k, s, d)): + assert_almost_equal(a, a_) + + +class TestArraySetOps(object): + + def test_unique_onlist(self): + # Test unique on list + data = [1, 1, 1, 2, 2, 3] + test = unique(data, return_index=True, return_inverse=True) + assert_(isinstance(test[0], MaskedArray)) + assert_equal(test[0], masked_array([1, 2, 3], mask=[0, 0, 0])) + assert_equal(test[1], [0, 3, 5]) + assert_equal(test[2], [0, 0, 0, 1, 1, 2]) + + def test_unique_onmaskedarray(self): + # Test unique on masked data w/use_mask=True + data = masked_array([1, 1, 1, 2, 2, 3], mask=[0, 0, 1, 0, 1, 0]) + test = unique(data, return_index=True, return_inverse=True) + assert_equal(test[0], masked_array([1, 2, 3, -1], mask=[0, 0, 0, 1])) + assert_equal(test[1], [0, 3, 5, 2]) + assert_equal(test[2], [0, 0, 3, 1, 3, 2]) + # + data.fill_value = 3 + data = masked_array(data=[1, 1, 1, 2, 2, 3], + mask=[0, 0, 1, 0, 1, 0], fill_value=3) + test = unique(data, return_index=True, return_inverse=True) + assert_equal(test[0], masked_array([1, 2, 3, -1], mask=[0, 0, 0, 1])) + assert_equal(test[1], [0, 3, 5, 2]) + assert_equal(test[2], [0, 0, 3, 1, 3, 2]) + + def test_unique_allmasked(self): + # Test all masked + data = masked_array([1, 1, 1], mask=True) + test = unique(data, return_index=True, return_inverse=True) + assert_equal(test[0], masked_array([1, ], mask=[True])) + assert_equal(test[1], [0]) + assert_equal(test[2], [0, 0, 0]) + # + # Test masked + data = masked + test = unique(data, return_index=True, return_inverse=True) + assert_equal(test[0], masked_array(masked)) + assert_equal(test[1], [0]) + assert_equal(test[2], [0]) + + def test_ediff1d(self): + # Tests mediff1d + x = masked_array(np.arange(5), mask=[1, 0, 0, 0, 1]) + control = array([1, 1, 1, 4], mask=[1, 0, 0, 1]) + test = ediff1d(x) + assert_equal(test, control) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + + def test_ediff1d_tobegin(self): + # Test ediff1d w/ to_begin + x = masked_array(np.arange(5), mask=[1, 0, 0, 0, 1]) + test = ediff1d(x, to_begin=masked) + control = array([0, 1, 1, 1, 4], mask=[1, 1, 0, 0, 1]) + assert_equal(test, control) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + # + test = ediff1d(x, to_begin=[1, 2, 3]) + control = array([1, 2, 3, 1, 1, 1, 4], mask=[0, 0, 0, 1, 0, 0, 1]) + assert_equal(test, control) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + + def test_ediff1d_toend(self): + # Test ediff1d w/ to_end + x = masked_array(np.arange(5), mask=[1, 0, 0, 0, 1]) + test = ediff1d(x, to_end=masked) + control = array([1, 1, 1, 4, 0], mask=[1, 0, 0, 1, 1]) + assert_equal(test, control) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + # + test = ediff1d(x, to_end=[1, 2, 3]) + control = array([1, 1, 1, 4, 1, 2, 3], mask=[1, 0, 0, 1, 0, 0, 0]) + assert_equal(test, control) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + + def test_ediff1d_tobegin_toend(self): + # Test ediff1d w/ to_begin and to_end + x = masked_array(np.arange(5), mask=[1, 0, 0, 0, 1]) + test = ediff1d(x, to_end=masked, to_begin=masked) + control = array([0, 1, 1, 1, 4, 0], mask=[1, 1, 0, 0, 1, 1]) + assert_equal(test, control) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + # + test = ediff1d(x, to_end=[1, 2, 3], to_begin=masked) + control = array([0, 1, 1, 1, 4, 1, 2, 3], + mask=[1, 1, 0, 0, 1, 0, 0, 0]) + assert_equal(test, control) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + + def test_ediff1d_ndarray(self): + # Test ediff1d w/ a ndarray + x = np.arange(5) + test = ediff1d(x) + control = array([1, 1, 1, 1], mask=[0, 0, 0, 0]) + assert_equal(test, control) + assert_(isinstance(test, MaskedArray)) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + # + test = ediff1d(x, to_end=masked, to_begin=masked) + control = array([0, 1, 1, 1, 1, 0], mask=[1, 0, 0, 0, 0, 1]) + assert_(isinstance(test, MaskedArray)) + assert_equal(test.filled(0), control.filled(0)) + assert_equal(test.mask, control.mask) + + def test_intersect1d(self): + # Test intersect1d + x = array([1, 3, 3, 3], mask=[0, 0, 0, 1]) + y = array([3, 1, 1, 1], mask=[0, 0, 0, 1]) + test = intersect1d(x, y) + control = array([1, 3, -1], mask=[0, 0, 1]) + assert_equal(test, control) + + def test_setxor1d(self): + # Test setxor1d + a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1]) + b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, 1]) + test = setxor1d(a, b) + assert_equal(test, array([3, 4, 7])) + # + a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1]) + b = [1, 2, 3, 4, 5] + test = setxor1d(a, b) + assert_equal(test, array([3, 4, 7, -1], mask=[0, 0, 0, 1])) + # + a = array([1, 2, 3]) + b = array([6, 5, 4]) + test = setxor1d(a, b) + assert_(isinstance(test, MaskedArray)) + assert_equal(test, [1, 2, 3, 4, 5, 6]) + # + a = array([1, 8, 2, 3], mask=[0, 1, 0, 0]) + b = array([6, 5, 4, 8], mask=[0, 0, 0, 1]) + test = setxor1d(a, b) + assert_(isinstance(test, MaskedArray)) + assert_equal(test, [1, 2, 3, 4, 5, 6]) + # + assert_array_equal([], setxor1d([], [])) + + 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. + a = np.arange(24).reshape([2, 3, 4]) + mask = np.zeros([2, 3, 4]) + mask[1, 2, 0] = 1 + a = array(a, mask=mask) + b = array(data=[0, 10, 20, 30, 1, 3, 11, 22, 33], + mask=[0, 1, 0, 1, 0, 1, 0, 1, 0]) + ec = zeros((2, 3, 4), dtype=bool) + ec[0, 0, 0] = True + ec[0, 0, 1] = True + ec[0, 2, 3] = True + c = isin(a, b) + assert_(isinstance(c, MaskedArray)) + assert_array_equal(c, ec) + #compare results of np.isin to ma.isin + d = np.isin(a, b[~b.mask]) & ~a.mask + assert_array_equal(c, d) + + def test_in1d(self): + # Test in1d + a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1]) + b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, 1]) + test = in1d(a, b) + assert_equal(test, [True, True, True, False, True]) + # + a = array([5, 5, 2, 1, -1], mask=[0, 0, 0, 0, 1]) + b = array([1, 5, -1], mask=[0, 0, 1]) + test = in1d(a, b) + assert_equal(test, [True, True, False, True, True]) + # + assert_array_equal([], in1d([], [])) + + def test_in1d_invert(self): + # Test in1d's invert parameter + a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1]) + b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, 1]) + assert_equal(np.invert(in1d(a, b)), in1d(a, b, invert=True)) + + a = array([5, 5, 2, 1, -1], mask=[0, 0, 0, 0, 1]) + b = array([1, 5, -1], mask=[0, 0, 1]) + assert_equal(np.invert(in1d(a, b)), in1d(a, b, invert=True)) + + assert_array_equal([], in1d([], [], invert=True)) + + def test_union1d(self): + # Test union1d + a = array([1, 2, 5, 7, 5, -1], mask=[0, 0, 0, 0, 0, 1]) + b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, 1]) + test = union1d(a, b) + control = array([1, 2, 3, 4, 5, 7, -1], mask=[0, 0, 0, 0, 0, 0, 1]) + assert_equal(test, control) + + # Tests gh-10340, arguments to union1d should be + # flattened if they are not already 1D + x = array([[0, 1, 2], [3, 4, 5]], mask=[[0, 0, 0], [0, 0, 1]]) + y = array([0, 1, 2, 3, 4], mask=[0, 0, 0, 0, 1]) + ez = array([0, 1, 2, 3, 4, 5], mask=[0, 0, 0, 0, 0, 1]) + z = union1d(x, y) + assert_equal(z, ez) + # + assert_array_equal([], union1d([], [])) + + def test_setdiff1d(self): + # Test setdiff1d + a = array([6, 5, 4, 7, 7, 1, 2, 1], mask=[0, 0, 0, 0, 0, 0, 0, 1]) + b = array([2, 4, 3, 3, 2, 1, 5]) + test = setdiff1d(a, b) + assert_equal(test, array([6, 7, -1], mask=[0, 0, 1])) + # + a = arange(10) + b = arange(8) + assert_equal(setdiff1d(a, b), array([8, 9])) + a = array([], np.uint32, mask=[]) + assert_equal(setdiff1d(a, []).dtype, np.uint32) + + def test_setdiff1d_char_array(self): + # Test setdiff1d_charray + a = np.array(['a', 'b', 'c']) + b = np.array(['a', 'b', 's']) + assert_array_equal(setdiff1d(a, b), np.array(['c'])) + + +class TestShapeBase(object): + + def test_atleast_2d(self): + # Test atleast_2d + a = masked_array([0, 1, 2], mask=[0, 1, 0]) + b = atleast_2d(a) + assert_equal(b.shape, (1, 3)) + assert_equal(b.mask.shape, b.data.shape) + assert_equal(a.shape, (3,)) + assert_equal(a.mask.shape, a.data.shape) + assert_equal(b.mask.shape, b.data.shape) + + def test_shape_scalar(self): + # the atleast and diagflat function should work with scalars + # GitHub issue #3367 + # Additionally, the atleast functions should accept multiple scalars + # correctly + b = atleast_1d(1.0) + assert_equal(b.shape, (1,)) + assert_equal(b.mask.shape, b.shape) + assert_equal(b.data.shape, b.shape) + + b = atleast_1d(1.0, 2.0) + for a in b: + assert_equal(a.shape, (1,)) + assert_equal(a.mask.shape, a.shape) + assert_equal(a.data.shape, a.shape) + + b = atleast_2d(1.0) + assert_equal(b.shape, (1, 1)) + assert_equal(b.mask.shape, b.shape) + assert_equal(b.data.shape, b.shape) + + b = atleast_2d(1.0, 2.0) + for a in b: + assert_equal(a.shape, (1, 1)) + assert_equal(a.mask.shape, a.shape) + assert_equal(a.data.shape, a.shape) + + b = atleast_3d(1.0) + assert_equal(b.shape, (1, 1, 1)) + assert_equal(b.mask.shape, b.shape) + assert_equal(b.data.shape, b.shape) + + b = atleast_3d(1.0, 2.0) + for a in b: + assert_equal(a.shape, (1, 1, 1)) + assert_equal(a.mask.shape, a.shape) + assert_equal(a.data.shape, a.shape) + + + b = diagflat(1.0) + assert_equal(b.shape, (1, 1)) + assert_equal(b.mask.shape, b.data.shape) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/ma/tests/test_mrecords.py b/numpy/ma/tests/test_mrecords.py new file mode 100644 index 0000000..1ca8e17 --- /dev/null +++ b/numpy/ma/tests/test_mrecords.py @@ -0,0 +1,500 @@ +# pylint: disable-msg=W0611, W0612, W0511,R0201 +"""Tests suite for mrecords. + +:author: Pierre Gerard-Marchant +:contact: pierregm_at_uga_dot_edu + +""" +from __future__ import division, absolute_import, print_function + +import warnings +import pickle + +import numpy as np +import numpy.ma as ma +from numpy import recarray +from numpy.ma import masked, nomask +from numpy.testing import run_module_suite, temppath +from numpy.core.records import ( + fromrecords as recfromrecords, fromarrays as recfromarrays + ) +from numpy.ma.mrecords import ( + MaskedRecords, mrecarray, fromarrays, fromtextfile, fromrecords, + addfield + ) +from numpy.ma.testutils import ( + assert_, assert_equal, + assert_equal_records, + ) + + +class TestMRecords(object): + + ilist = [1, 2, 3, 4, 5] + flist = [1.1, 2.2, 3.3, 4.4, 5.5] + slist = [b'one', b'two', b'three', b'four', b'five'] + ddtype = [('a', int), ('b', float), ('c', '|S8')] + mask = [0, 1, 0, 0, 1] + base = ma.array(list(zip(ilist, flist, slist)), mask=mask, dtype=ddtype) + + def test_byview(self): + # Test creation by view + base = self.base + mbase = base.view(mrecarray) + assert_equal(mbase.recordmask, base.recordmask) + assert_equal_records(mbase._mask, base._mask) + assert_(isinstance(mbase._data, recarray)) + assert_equal_records(mbase._data, base._data.view(recarray)) + for field in ('a', 'b', 'c'): + assert_equal(base[field], mbase[field]) + assert_equal_records(mbase.view(mrecarray), mbase) + + def test_get(self): + # Tests fields retrieval + base = self.base.copy() + mbase = base.view(mrecarray) + # As fields.......... + for field in ('a', 'b', 'c'): + assert_equal(getattr(mbase, field), mbase[field]) + assert_equal(base[field], mbase[field]) + # as elements ....... + mbase_first = mbase[0] + assert_(isinstance(mbase_first, mrecarray)) + assert_equal(mbase_first.dtype, mbase.dtype) + assert_equal(mbase_first.tolist(), (1, 1.1, b'one')) + # Used to be mask, now it's recordmask + assert_equal(mbase_first.recordmask, nomask) + assert_equal(mbase_first._mask.item(), (False, False, False)) + assert_equal(mbase_first['a'], mbase['a'][0]) + mbase_last = mbase[-1] + assert_(isinstance(mbase_last, mrecarray)) + assert_equal(mbase_last.dtype, mbase.dtype) + assert_equal(mbase_last.tolist(), (None, None, None)) + # Used to be mask, now it's recordmask + assert_equal(mbase_last.recordmask, True) + assert_equal(mbase_last._mask.item(), (True, True, True)) + assert_equal(mbase_last['a'], mbase['a'][-1]) + assert_((mbase_last['a'] is masked)) + # as slice .......... + mbase_sl = mbase[:2] + assert_(isinstance(mbase_sl, mrecarray)) + assert_equal(mbase_sl.dtype, mbase.dtype) + # Used to be mask, now it's recordmask + assert_equal(mbase_sl.recordmask, [0, 1]) + assert_equal_records(mbase_sl.mask, + np.array([(False, False, False), + (True, True, True)], + dtype=mbase._mask.dtype)) + assert_equal_records(mbase_sl, base[:2].view(mrecarray)) + for field in ('a', 'b', 'c'): + assert_equal(getattr(mbase_sl, field), base[:2][field]) + + def test_set_fields(self): + # Tests setting fields. + base = self.base.copy() + mbase = base.view(mrecarray) + mbase = mbase.copy() + mbase.fill_value = (999999, 1e20, 'N/A') + # Change the data, the mask should be conserved + mbase.a._data[:] = 5 + assert_equal(mbase['a']._data, [5, 5, 5, 5, 5]) + assert_equal(mbase['a']._mask, [0, 1, 0, 0, 1]) + # Change the elements, and the mask will follow + mbase.a = 1 + assert_equal(mbase['a']._data, [1]*5) + assert_equal(ma.getmaskarray(mbase['a']), [0]*5) + # Use to be _mask, now it's recordmask + assert_equal(mbase.recordmask, [False]*5) + assert_equal(mbase._mask.tolist(), + np.array([(0, 0, 0), + (0, 1, 1), + (0, 0, 0), + (0, 0, 0), + (0, 1, 1)], + dtype=bool)) + # Set a field to mask ........................ + mbase.c = masked + # Use to be mask, and now it's still mask ! + assert_equal(mbase.c.mask, [1]*5) + assert_equal(mbase.c.recordmask, [1]*5) + assert_equal(ma.getmaskarray(mbase['c']), [1]*5) + assert_equal(ma.getdata(mbase['c']), [b'N/A']*5) + assert_equal(mbase._mask.tolist(), + np.array([(0, 0, 1), + (0, 1, 1), + (0, 0, 1), + (0, 0, 1), + (0, 1, 1)], + dtype=bool)) + # Set fields by slices ....................... + mbase = base.view(mrecarray).copy() + mbase.a[3:] = 5 + assert_equal(mbase.a, [1, 2, 3, 5, 5]) + assert_equal(mbase.a._mask, [0, 1, 0, 0, 0]) + mbase.b[3:] = masked + assert_equal(mbase.b, base['b']) + assert_equal(mbase.b._mask, [0, 1, 0, 1, 1]) + # Set fields globally.......................... + ndtype = [('alpha', '|S1'), ('num', int)] + data = ma.array([('a', 1), ('b', 2), ('c', 3)], dtype=ndtype) + rdata = data.view(MaskedRecords) + val = ma.array([10, 20, 30], mask=[1, 0, 0]) + + rdata['num'] = val + assert_equal(rdata.num, val) + assert_equal(rdata.num.mask, [1, 0, 0]) + + def test_set_fields_mask(self): + # Tests setting the mask of a field. + base = self.base.copy() + # This one has already a mask.... + mbase = base.view(mrecarray) + mbase['a'][-2] = masked + assert_equal(mbase.a, [1, 2, 3, 4, 5]) + assert_equal(mbase.a._mask, [0, 1, 0, 1, 1]) + # This one has not yet + mbase = fromarrays([np.arange(5), np.random.rand(5)], + dtype=[('a', int), ('b', float)]) + mbase['a'][-2] = masked + assert_equal(mbase.a, [0, 1, 2, 3, 4]) + assert_equal(mbase.a._mask, [0, 0, 0, 1, 0]) + + def test_set_mask(self): + base = self.base.copy() + mbase = base.view(mrecarray) + # Set the mask to True ....................... + mbase.mask = masked + assert_equal(ma.getmaskarray(mbase['b']), [1]*5) + assert_equal(mbase['a']._mask, mbase['b']._mask) + assert_equal(mbase['a']._mask, mbase['c']._mask) + assert_equal(mbase._mask.tolist(), + np.array([(1, 1, 1)]*5, dtype=bool)) + # Delete the mask ............................ + mbase.mask = nomask + assert_equal(ma.getmaskarray(mbase['c']), [0]*5) + assert_equal(mbase._mask.tolist(), + np.array([(0, 0, 0)]*5, dtype=bool)) + + def test_set_mask_fromarray(self): + base = self.base.copy() + mbase = base.view(mrecarray) + # Sets the mask w/ an array + mbase.mask = [1, 0, 0, 0, 1] + assert_equal(mbase.a.mask, [1, 0, 0, 0, 1]) + assert_equal(mbase.b.mask, [1, 0, 0, 0, 1]) + assert_equal(mbase.c.mask, [1, 0, 0, 0, 1]) + # Yay, once more ! + mbase.mask = [0, 0, 0, 0, 1] + assert_equal(mbase.a.mask, [0, 0, 0, 0, 1]) + assert_equal(mbase.b.mask, [0, 0, 0, 0, 1]) + assert_equal(mbase.c.mask, [0, 0, 0, 0, 1]) + + def test_set_mask_fromfields(self): + mbase = self.base.copy().view(mrecarray) + + nmask = np.array( + [(0, 1, 0), (0, 1, 0), (1, 0, 1), (1, 0, 1), (0, 0, 0)], + dtype=[('a', bool), ('b', bool), ('c', bool)]) + mbase.mask = nmask + assert_equal(mbase.a.mask, [0, 0, 1, 1, 0]) + assert_equal(mbase.b.mask, [1, 1, 0, 0, 0]) + assert_equal(mbase.c.mask, [0, 0, 1, 1, 0]) + # Reinitialize and redo + mbase.mask = False + mbase.fieldmask = nmask + assert_equal(mbase.a.mask, [0, 0, 1, 1, 0]) + assert_equal(mbase.b.mask, [1, 1, 0, 0, 0]) + assert_equal(mbase.c.mask, [0, 0, 1, 1, 0]) + + def test_set_elements(self): + base = self.base.copy() + # Set an element to mask ..................... + mbase = base.view(mrecarray).copy() + mbase[-2] = masked + assert_equal( + mbase._mask.tolist(), + np.array([(0, 0, 0), (1, 1, 1), (0, 0, 0), (1, 1, 1), (1, 1, 1)], + dtype=bool)) + # Used to be mask, now it's recordmask! + assert_equal(mbase.recordmask, [0, 1, 0, 1, 1]) + # Set slices ................................. + mbase = base.view(mrecarray).copy() + mbase[:2] = (5, 5, 5) + assert_equal(mbase.a._data, [5, 5, 3, 4, 5]) + assert_equal(mbase.a._mask, [0, 0, 0, 0, 1]) + assert_equal(mbase.b._data, [5., 5., 3.3, 4.4, 5.5]) + assert_equal(mbase.b._mask, [0, 0, 0, 0, 1]) + assert_equal(mbase.c._data, + [b'5', b'5', b'three', b'four', b'five']) + assert_equal(mbase.b._mask, [0, 0, 0, 0, 1]) + + mbase = base.view(mrecarray).copy() + mbase[:2] = masked + assert_equal(mbase.a._data, [1, 2, 3, 4, 5]) + assert_equal(mbase.a._mask, [1, 1, 0, 0, 1]) + assert_equal(mbase.b._data, [1.1, 2.2, 3.3, 4.4, 5.5]) + assert_equal(mbase.b._mask, [1, 1, 0, 0, 1]) + assert_equal(mbase.c._data, + [b'one', b'two', b'three', b'four', b'five']) + assert_equal(mbase.b._mask, [1, 1, 0, 0, 1]) + + def test_setslices_hardmask(self): + # Tests setting slices w/ hardmask. + base = self.base.copy() + mbase = base.view(mrecarray) + mbase.harden_mask() + try: + mbase[-2:] = (5, 5, 5) + assert_equal(mbase.a._data, [1, 2, 3, 5, 5]) + assert_equal(mbase.b._data, [1.1, 2.2, 3.3, 5, 5.5]) + assert_equal(mbase.c._data, + [b'one', b'two', b'three', b'5', b'five']) + assert_equal(mbase.a._mask, [0, 1, 0, 0, 1]) + assert_equal(mbase.b._mask, mbase.a._mask) + assert_equal(mbase.b._mask, mbase.c._mask) + except NotImplementedError: + # OK, not implemented yet... + pass + except AssertionError: + raise + else: + raise Exception("Flexible hard masks should be supported !") + # Not using a tuple should crash + try: + mbase[-2:] = 3 + except (NotImplementedError, TypeError): + pass + else: + raise TypeError("Should have expected a readable buffer object!") + + def test_hardmask(self): + # Test hardmask + base = self.base.copy() + mbase = base.view(mrecarray) + mbase.harden_mask() + assert_(mbase._hardmask) + mbase.mask = nomask + assert_equal_records(mbase._mask, base._mask) + mbase.soften_mask() + assert_(not mbase._hardmask) + mbase.mask = nomask + # So, the mask of a field is no longer set to nomask... + assert_equal_records(mbase._mask, + ma.make_mask_none(base.shape, base.dtype)) + assert_(ma.make_mask(mbase['b']._mask) is nomask) + assert_equal(mbase['a']._mask, mbase['b']._mask) + + def test_pickling(self): + # Test pickling + base = self.base.copy() + mrec = base.view(mrecarray) + _ = pickle.dumps(mrec) + mrec_ = pickle.loads(_) + assert_equal(mrec_.dtype, mrec.dtype) + assert_equal_records(mrec_._data, mrec._data) + assert_equal(mrec_._mask, mrec._mask) + assert_equal_records(mrec_._mask, mrec._mask) + + def test_filled(self): + # Test filling the array + _a = ma.array([1, 2, 3], mask=[0, 0, 1], dtype=int) + _b = ma.array([1.1, 2.2, 3.3], mask=[0, 0, 1], dtype=float) + _c = ma.array(['one', 'two', 'three'], mask=[0, 0, 1], dtype='|S8') + ddtype = [('a', int), ('b', float), ('c', '|S8')] + mrec = fromarrays([_a, _b, _c], dtype=ddtype, + fill_value=(99999, 99999., 'N/A')) + mrecfilled = mrec.filled() + assert_equal(mrecfilled['a'], np.array((1, 2, 99999), dtype=int)) + assert_equal(mrecfilled['b'], np.array((1.1, 2.2, 99999.), + dtype=float)) + assert_equal(mrecfilled['c'], np.array(('one', 'two', 'N/A'), + dtype='|S8')) + + def test_tolist(self): + # Test tolist. + _a = ma.array([1, 2, 3], mask=[0, 0, 1], dtype=int) + _b = ma.array([1.1, 2.2, 3.3], mask=[0, 0, 1], dtype=float) + _c = ma.array(['one', 'two', 'three'], mask=[1, 0, 0], dtype='|S8') + ddtype = [('a', int), ('b', float), ('c', '|S8')] + mrec = fromarrays([_a, _b, _c], dtype=ddtype, + fill_value=(99999, 99999., 'N/A')) + + assert_equal(mrec.tolist(), + [(1, 1.1, None), (2, 2.2, b'two'), + (None, None, b'three')]) + + def test_withnames(self): + # Test the creation w/ format and names + x = mrecarray(1, formats=float, names='base') + x[0]['base'] = 10 + assert_equal(x['base'][0], 10) + + def test_exotic_formats(self): + # Test that 'exotic' formats are processed properly + easy = mrecarray(1, dtype=[('i', int), ('s', '|S8'), ('f', float)]) + easy[0] = masked + assert_equal(easy.filled(1).item(), (1, b'1', 1.)) + + solo = mrecarray(1, dtype=[('f0', ' 1: + assert_(eq(np.concatenate((x, y), 1), + concatenate((xm, ym), 1))) + assert_(eq(np.add.reduce(x, 1), add.reduce(x, 1))) + assert_(eq(np.sum(x, 1), sum(x, 1))) + assert_(eq(np.product(x, 1), product(x, 1))) + + def test_testCI(self): + # Test of conversions and indexing + x1 = np.array([1, 2, 4, 3]) + x2 = array(x1, mask=[1, 0, 0, 0]) + x3 = array(x1, mask=[0, 1, 0, 1]) + x4 = array(x1) + # test conversion to strings + str(x2) # raises? + repr(x2) # raises? + assert_(eq(np.sort(x1), sort(x2, fill_value=0))) + # tests of indexing + assert_(type(x2[1]) is type(x1[1])) + assert_(x1[1] == x2[1]) + assert_(x2[0] is masked) + assert_(eq(x1[2], x2[2])) + assert_(eq(x1[2:5], x2[2:5])) + assert_(eq(x1[:], x2[:])) + assert_(eq(x1[1:], x3[1:])) + x1[2] = 9 + x2[2] = 9 + assert_(eq(x1, x2)) + x1[1:3] = 99 + x2[1:3] = 99 + assert_(eq(x1, x2)) + x2[1] = masked + assert_(eq(x1, x2)) + x2[1:3] = masked + assert_(eq(x1, x2)) + x2[:] = x1 + x2[1] = masked + assert_(allequal(getmask(x2), array([0, 1, 0, 0]))) + x3[:] = masked_array([1, 2, 3, 4], [0, 1, 1, 0]) + assert_(allequal(getmask(x3), array([0, 1, 1, 0]))) + x4[:] = masked_array([1, 2, 3, 4], [0, 1, 1, 0]) + assert_(allequal(getmask(x4), array([0, 1, 1, 0]))) + assert_(allequal(x4, array([1, 2, 3, 4]))) + x1 = np.arange(5) * 1.0 + x2 = masked_values(x1, 3.0) + assert_(eq(x1, x2)) + assert_(allequal(array([0, 0, 0, 1, 0], MaskType), x2.mask)) + assert_(eq(3.0, x2.fill_value)) + x1 = array([1, 'hello', 2, 3], object) + x2 = np.array([1, 'hello', 2, 3], object) + s1 = x1[1] + s2 = x2[1] + assert_equal(type(s2), str) + assert_equal(type(s1), str) + assert_equal(s1, s2) + assert_(x1[1:1].shape == (0,)) + + def test_testCopySize(self): + # Tests of some subtle points of copying and sizing. + n = [0, 0, 1, 0, 0] + m = make_mask(n) + m2 = make_mask(m) + assert_(m is m2) + m3 = make_mask(m, copy=1) + assert_(m is not m3) + + x1 = np.arange(5) + y1 = array(x1, mask=m) + assert_(y1._data is not x1) + assert_(allequal(x1, y1._data)) + assert_(y1.mask is m) + + y1a = array(y1, copy=0) + assert_(y1a.mask is y1.mask) + + y2 = array(x1, mask=m3, copy=0) + assert_(y2.mask is m3) + assert_(y2[2] is masked) + y2[2] = 9 + assert_(y2[2] is not masked) + assert_(y2.mask is m3) + assert_(allequal(y2.mask, 0)) + + y2a = array(x1, mask=m, copy=1) + assert_(y2a.mask is not m) + assert_(y2a[2] is masked) + y2a[2] = 9 + assert_(y2a[2] is not masked) + assert_(y2a.mask is not m) + assert_(allequal(y2a.mask, 0)) + + y3 = array(x1 * 1.0, mask=m) + assert_(filled(y3).dtype is (x1 * 1.0).dtype) + + x4 = arange(4) + x4[2] = masked + y4 = resize(x4, (8,)) + assert_(eq(concatenate([x4, x4]), y4)) + assert_(eq(getmask(y4), [0, 0, 1, 0, 0, 0, 1, 0])) + y5 = repeat(x4, (2, 2, 2, 2), axis=0) + assert_(eq(y5, [0, 0, 1, 1, 2, 2, 3, 3])) + y6 = repeat(x4, 2, axis=0) + assert_(eq(y5, y6)) + + def test_testPut(self): + # Test of put + d = arange(5) + n = [0, 0, 0, 1, 1] + m = make_mask(n) + m2 = m.copy() + x = array(d, mask=m) + assert_(x[3] is masked) + assert_(x[4] is masked) + x[[1, 4]] = [10, 40] + assert_(x.mask is m) + assert_(x[3] is masked) + assert_(x[4] is not masked) + assert_(eq(x, [0, 10, 2, -1, 40])) + + x = array(d, mask=m2, copy=True) + x.put([0, 1, 2], [-1, 100, 200]) + assert_(x.mask is not m2) + assert_(x[3] is masked) + assert_(x[4] is masked) + assert_(eq(x, [-1, 100, 200, 0, 0])) + + def test_testPut2(self): + # Test of put + d = arange(5) + x = array(d, mask=[0, 0, 0, 0, 0]) + z = array([10, 40], mask=[1, 0]) + assert_(x[2] is not masked) + assert_(x[3] is not masked) + x[2:4] = z + assert_(x[2] is masked) + assert_(x[3] is not masked) + assert_(eq(x, [0, 1, 10, 40, 4])) + + d = arange(5) + x = array(d, mask=[0, 0, 0, 0, 0]) + y = x[2:4] + z = array([10, 40], mask=[1, 0]) + assert_(x[2] is not masked) + assert_(x[3] is not masked) + y[:] = z + assert_(y[0] is masked) + assert_(y[1] is not masked) + assert_(eq(y, [10, 40])) + assert_(x[2] is masked) + assert_(x[3] is not masked) + assert_(eq(x, [0, 1, 10, 40, 4])) + + def test_testMaPut(self): + (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d + m = [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1] + i = np.nonzero(m)[0] + put(ym, i, zm) + assert_(all(take(ym, i, axis=0) == zm)) + + def test_testOddFeatures(self): + # Test of other odd features + x = arange(20) + x = x.reshape(4, 5) + x.flat[5] = 12 + assert_(x[1, 0] == 12) + z = x + 10j * x + assert_(eq(z.real, x)) + assert_(eq(z.imag, 10 * x)) + assert_(eq((z * conjugate(z)).real, 101 * x * x)) + z.imag[...] = 0.0 + + x = arange(10) + x[3] = masked + assert_(str(x[3]) == str(masked)) + c = x >= 8 + assert_(count(where(c, masked, masked)) == 0) + assert_(shape(where(c, masked, masked)) == c.shape) + z = where(c, x, masked) + assert_(z.dtype is x.dtype) + assert_(z[3] is masked) + assert_(z[4] is masked) + assert_(z[7] is masked) + assert_(z[8] is not masked) + assert_(z[9] is not masked) + assert_(eq(x, z)) + z = where(c, masked, x) + assert_(z.dtype is x.dtype) + assert_(z[3] is masked) + assert_(z[4] is not masked) + assert_(z[7] is not masked) + assert_(z[8] is masked) + assert_(z[9] is masked) + z = masked_where(c, x) + assert_(z.dtype is x.dtype) + assert_(z[3] is masked) + assert_(z[4] is not masked) + assert_(z[7] is not masked) + assert_(z[8] is masked) + assert_(z[9] is masked) + assert_(eq(x, z)) + x = array([1., 2., 3., 4., 5.]) + c = array([1, 1, 1, 0, 0]) + x[2] = masked + z = where(c, x, -x) + assert_(eq(z, [1., 2., 0., -4., -5])) + c[0] = masked + z = where(c, x, -x) + assert_(eq(z, [1., 2., 0., -4., -5])) + assert_(z[0] is masked) + assert_(z[1] is not masked) + assert_(z[2] is masked) + assert_(eq(masked_where(greater(x, 2), x), masked_greater(x, 2))) + assert_(eq(masked_where(greater_equal(x, 2), x), + masked_greater_equal(x, 2))) + assert_(eq(masked_where(less(x, 2), x), masked_less(x, 2))) + assert_(eq(masked_where(less_equal(x, 2), x), masked_less_equal(x, 2))) + assert_(eq(masked_where(not_equal(x, 2), x), masked_not_equal(x, 2))) + assert_(eq(masked_where(equal(x, 2), x), masked_equal(x, 2))) + assert_(eq(masked_where(not_equal(x, 2), x), masked_not_equal(x, 2))) + assert_(eq(masked_inside(list(range(5)), 1, 3), [0, 199, 199, 199, 4])) + assert_(eq(masked_outside(list(range(5)), 1, 3), [199, 1, 2, 3, 199])) + assert_(eq(masked_inside(array(list(range(5)), + mask=[1, 0, 0, 0, 0]), 1, 3).mask, + [1, 1, 1, 1, 0])) + assert_(eq(masked_outside(array(list(range(5)), + mask=[0, 1, 0, 0, 0]), 1, 3).mask, + [1, 1, 0, 0, 1])) + assert_(eq(masked_equal(array(list(range(5)), + mask=[1, 0, 0, 0, 0]), 2).mask, + [1, 0, 1, 0, 0])) + assert_(eq(masked_not_equal(array([2, 2, 1, 2, 1], + mask=[1, 0, 0, 0, 0]), 2).mask, + [1, 0, 1, 0, 1])) + assert_(eq(masked_where([1, 1, 0, 0, 0], [1, 2, 3, 4, 5]), + [99, 99, 3, 4, 5])) + atest = ones((10, 10, 10), dtype=np.float32) + btest = zeros(atest.shape, MaskType) + ctest = masked_where(btest, atest) + assert_(eq(atest, ctest)) + z = choose(c, (-x, x)) + assert_(eq(z, [1., 2., 0., -4., -5])) + assert_(z[0] is masked) + assert_(z[1] is not masked) + assert_(z[2] is masked) + x = arange(6) + x[5] = masked + y = arange(6) * 10 + y[2] = masked + c = array([1, 1, 1, 0, 0, 0], mask=[1, 0, 0, 0, 0, 0]) + cm = c.filled(1) + z = where(c, x, y) + zm = where(cm, x, y) + assert_(eq(z, zm)) + assert_(getmask(zm) is nomask) + assert_(eq(zm, [0, 1, 2, 30, 40, 50])) + z = where(c, masked, 1) + assert_(eq(z, [99, 99, 99, 1, 1, 1])) + z = where(c, 1, masked) + assert_(eq(z, [99, 1, 1, 99, 99, 99])) + + def test_testMinMax2(self): + # Test of minimum, maximum. + assert_(eq(minimum([1, 2, 3], [4, 0, 9]), [1, 0, 3])) + assert_(eq(maximum([1, 2, 3], [4, 0, 9]), [4, 2, 9])) + x = arange(5) + y = arange(5) - 2 + x[3] = masked + y[0] = masked + assert_(eq(minimum(x, y), where(less(x, y), x, y))) + assert_(eq(maximum(x, y), where(greater(x, y), x, y))) + assert_(minimum.reduce(x) == 0) + assert_(maximum.reduce(x) == 4) + + def test_testTakeTransposeInnerOuter(self): + # Test of take, transpose, inner, outer products + x = arange(24) + y = np.arange(24) + x[5:6] = masked + x = x.reshape(2, 3, 4) + y = y.reshape(2, 3, 4) + assert_(eq(np.transpose(y, (2, 0, 1)), transpose(x, (2, 0, 1)))) + assert_(eq(np.take(y, (2, 0, 1), 1), take(x, (2, 0, 1), 1))) + assert_(eq(np.inner(filled(x, 0), filled(y, 0)), + inner(x, y))) + assert_(eq(np.outer(filled(x, 0), filled(y, 0)), + outer(x, y))) + y = array(['abc', 1, 'def', 2, 3], object) + y[2] = masked + t = take(y, [0, 3, 4]) + assert_(t[0] == 'abc') + assert_(t[1] == 2) + assert_(t[2] == 3) + + def test_testInplace(self): + # Test of inplace operations and rich comparisons + y = arange(10) + + x = arange(10) + xm = arange(10) + xm[2] = masked + x += 1 + assert_(eq(x, y + 1)) + xm += 1 + assert_(eq(x, y + 1)) + + x = arange(10) + xm = arange(10) + xm[2] = masked + x -= 1 + assert_(eq(x, y - 1)) + xm -= 1 + assert_(eq(xm, y - 1)) + + x = arange(10) * 1.0 + xm = arange(10) * 1.0 + xm[2] = masked + x *= 2.0 + assert_(eq(x, y * 2)) + xm *= 2.0 + assert_(eq(xm, y * 2)) + + x = arange(10) * 2 + xm = arange(10) + xm[2] = masked + x //= 2 + assert_(eq(x, y)) + xm //= 2 + assert_(eq(x, y)) + + x = arange(10) * 1.0 + xm = arange(10) * 1.0 + xm[2] = masked + x /= 2.0 + assert_(eq(x, y / 2.0)) + xm /= arange(10) + assert_(eq(xm, ones((10,)))) + + x = arange(10).astype(np.float32) + xm = arange(10) + xm[2] = masked + x += 1. + assert_(eq(x, y + 1.)) + + def test_testPickle(self): + # Test of pickling + import pickle + x = arange(12) + x[4:10:2] = masked + x = x.reshape(4, 3) + s = pickle.dumps(x) + y = pickle.loads(s) + assert_(eq(x, y)) + + def test_testMasked(self): + # Test of masked element + xx = arange(6) + xx[1] = masked + assert_(str(masked) == '--') + assert_(xx[1] is masked) + assert_equal(filled(xx[1], 0), 0) + + def test_testAverage1(self): + # Test of average. + ott = array([0., 1., 2., 3.], mask=[1, 0, 0, 0]) + assert_(eq(2.0, average(ott, axis=0))) + assert_(eq(2.0, average(ott, weights=[1., 1., 2., 1.]))) + result, wts = average(ott, weights=[1., 1., 2., 1.], returned=1) + assert_(eq(2.0, result)) + assert_(wts == 4.0) + ott[:] = masked + assert_(average(ott, axis=0) is masked) + ott = array([0., 1., 2., 3.], mask=[1, 0, 0, 0]) + ott = ott.reshape(2, 2) + ott[:, 1] = masked + assert_(eq(average(ott, axis=0), [2.0, 0.0])) + assert_(average(ott, axis=1)[0] is masked) + assert_(eq([2., 0.], average(ott, axis=0))) + result, wts = average(ott, axis=0, returned=1) + assert_(eq(wts, [1., 0.])) + + def test_testAverage2(self): + # More tests of average. + w1 = [0, 1, 1, 1, 1, 0] + w2 = [[0, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 1]] + x = arange(6) + assert_(allclose(average(x, axis=0), 2.5)) + assert_(allclose(average(x, axis=0, weights=w1), 2.5)) + y = array([arange(6), 2.0 * arange(6)]) + assert_(allclose(average(y, None), + np.add.reduce(np.arange(6)) * 3. / 12.)) + assert_(allclose(average(y, axis=0), np.arange(6) * 3. / 2.)) + assert_(allclose(average(y, axis=1), + [average(x, axis=0), average(x, axis=0)*2.0])) + assert_(allclose(average(y, None, weights=w2), 20. / 6.)) + assert_(allclose(average(y, axis=0, weights=w2), + [0., 1., 2., 3., 4., 10.])) + assert_(allclose(average(y, axis=1), + [average(x, axis=0), average(x, axis=0)*2.0])) + m1 = zeros(6) + m2 = [0, 0, 1, 1, 0, 0] + m3 = [[0, 0, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0]] + m4 = ones(6) + m5 = [0, 1, 1, 1, 1, 1] + assert_(allclose(average(masked_array(x, m1), axis=0), 2.5)) + assert_(allclose(average(masked_array(x, m2), axis=0), 2.5)) + assert_(average(masked_array(x, m4), axis=0) is masked) + assert_equal(average(masked_array(x, m5), axis=0), 0.0) + assert_equal(count(average(masked_array(x, m4), axis=0)), 0) + z = masked_array(y, m3) + assert_(allclose(average(z, None), 20. / 6.)) + assert_(allclose(average(z, axis=0), + [0., 1., 99., 99., 4.0, 7.5])) + assert_(allclose(average(z, axis=1), [2.5, 5.0])) + assert_(allclose(average(z, axis=0, weights=w2), + [0., 1., 99., 99., 4.0, 10.0])) + + a = arange(6) + b = arange(6) * 3 + r1, w1 = average([[a, b], [b, a]], axis=1, returned=1) + assert_equal(shape(r1), shape(w1)) + assert_equal(r1.shape, w1.shape) + r2, w2 = average(ones((2, 2, 3)), axis=0, weights=[3, 1], returned=1) + assert_equal(shape(w2), shape(r2)) + r2, w2 = average(ones((2, 2, 3)), returned=1) + assert_equal(shape(w2), shape(r2)) + r2, w2 = average(ones((2, 2, 3)), weights=ones((2, 2, 3)), returned=1) + assert_(shape(w2) == shape(r2)) + a2d = array([[1, 2], [0, 4]], float) + a2dm = masked_array(a2d, [[0, 0], [1, 0]]) + a2da = average(a2d, axis=0) + assert_(eq(a2da, [0.5, 3.0])) + a2dma = average(a2dm, axis=0) + assert_(eq(a2dma, [1.0, 3.0])) + a2dma = average(a2dm, axis=None) + assert_(eq(a2dma, 7. / 3.)) + a2dma = average(a2dm, axis=1) + assert_(eq(a2dma, [1.5, 4.0])) + + def test_testToPython(self): + assert_equal(1, int(array(1))) + assert_equal(1.0, float(array(1))) + assert_equal(1, int(array([[[1]]]))) + assert_equal(1.0, float(array([[1]]))) + assert_raises(TypeError, float, array([1, 1])) + assert_raises(ValueError, bool, array([0, 1])) + assert_raises(ValueError, bool, array([0, 0], mask=[0, 1])) + + def test_testScalarArithmetic(self): + xm = array(0, mask=1) + #TODO FIXME: Find out what the following raises a warning in r8247 + with np.errstate(divide='ignore'): + assert_((1 / array(0)).mask) + assert_((1 + xm).mask) + assert_((-xm).mask) + assert_((-xm).mask) + assert_(maximum(xm, xm).mask) + assert_(minimum(xm, xm).mask) + assert_(xm.filled().dtype is xm._data.dtype) + x = array(0, mask=0) + assert_(x.filled() == x._data) + assert_equal(str(xm), str(masked_print_option)) + + def test_testArrayMethods(self): + a = array([1, 3, 2]) + assert_(eq(a.any(), a._data.any())) + assert_(eq(a.all(), a._data.all())) + assert_(eq(a.argmax(), a._data.argmax())) + assert_(eq(a.argmin(), a._data.argmin())) + assert_(eq(a.choose(0, 1, 2, 3, 4), + a._data.choose(0, 1, 2, 3, 4))) + assert_(eq(a.compress([1, 0, 1]), a._data.compress([1, 0, 1]))) + assert_(eq(a.conj(), a._data.conj())) + assert_(eq(a.conjugate(), a._data.conjugate())) + m = array([[1, 2], [3, 4]]) + assert_(eq(m.diagonal(), m._data.diagonal())) + assert_(eq(a.sum(), a._data.sum())) + assert_(eq(a.take([1, 2]), a._data.take([1, 2]))) + assert_(eq(m.transpose(), m._data.transpose())) + + def test_testArrayAttributes(self): + a = array([1, 3, 2]) + assert_equal(a.ndim, 1) + + def test_testAPI(self): + assert_(not [m for m in dir(np.ndarray) + if m not in dir(MaskedArray) and + not m.startswith('_')]) + + def test_testSingleElementSubscript(self): + a = array([1, 3, 2]) + b = array([1, 3, 2], mask=[1, 0, 1]) + assert_equal(a[0].shape, ()) + assert_equal(b[0].shape, ()) + assert_equal(b[1].shape, ()) + + +class TestUfuncs(object): + def setup(self): + self.d = (array([1.0, 0, -1, pi / 2] * 2, mask=[0, 1] + [0] * 6), + array([1.0, 0, -1, pi / 2] * 2, mask=[1, 0] + [0] * 6),) + + def test_testUfuncRegression(self): + f_invalid_ignore = [ + 'sqrt', 'arctanh', 'arcsin', 'arccos', + 'arccosh', 'arctanh', 'log', 'log10', 'divide', + 'true_divide', 'floor_divide', 'remainder', 'fmod'] + for f in ['sqrt', 'log', 'log10', 'exp', 'conjugate', + 'sin', 'cos', 'tan', + 'arcsin', 'arccos', 'arctan', + 'sinh', 'cosh', 'tanh', + 'arcsinh', + 'arccosh', + 'arctanh', + 'absolute', 'fabs', 'negative', + 'floor', 'ceil', + 'logical_not', + 'add', 'subtract', 'multiply', + 'divide', 'true_divide', 'floor_divide', + 'remainder', 'fmod', 'hypot', 'arctan2', + 'equal', 'not_equal', 'less_equal', 'greater_equal', + 'less', 'greater', + 'logical_and', 'logical_or', 'logical_xor']: + try: + uf = getattr(umath, f) + except AttributeError: + uf = getattr(fromnumeric, f) + mf = getattr(np.ma, f) + args = self.d[:uf.nin] + with np.errstate(): + if f in f_invalid_ignore: + np.seterr(invalid='ignore') + if f in ['arctanh', 'log', 'log10']: + np.seterr(divide='ignore') + ur = uf(*args) + mr = mf(*args) + assert_(eq(ur.filled(0), mr.filled(0), f)) + assert_(eqmask(ur.mask, mr.mask)) + + def test_reduce(self): + a = self.d[0] + assert_(not alltrue(a, axis=0)) + assert_(sometrue(a, axis=0)) + assert_equal(sum(a[:3], axis=0), 0) + assert_equal(product(a, axis=0), 0) + + def test_minmax(self): + a = arange(1, 13).reshape(3, 4) + amask = masked_where(a < 5, a) + assert_equal(amask.max(), a.max()) + assert_equal(amask.min(), 5) + assert_((amask.max(0) == a.max(0)).all()) + assert_((amask.min(0) == [5, 6, 7, 8]).all()) + assert_(amask.max(1)[0].mask) + assert_(amask.min(1)[0].mask) + + def test_nonzero(self): + for t in "?bhilqpBHILQPfdgFDGO": + x = array([1, 0, 2, 0], mask=[0, 0, 1, 1]) + assert_(eq(nonzero(x), [0])) + + +class TestArrayMethods(object): + + def setup(self): + x = np.array([8.375, 7.545, 8.828, 8.5, 1.757, 5.928, + 8.43, 7.78, 9.865, 5.878, 8.979, 4.732, + 3.012, 6.022, 5.095, 3.116, 5.238, 3.957, + 6.04, 9.63, 7.712, 3.382, 4.489, 6.479, + 7.189, 9.645, 5.395, 4.961, 9.894, 2.893, + 7.357, 9.828, 6.272, 3.758, 6.693, 0.993]) + X = x.reshape(6, 6) + XX = x.reshape(3, 2, 2, 3) + + m = np.array([0, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 1, 0]) + mx = array(data=x, mask=m) + mX = array(data=X, mask=m.reshape(X.shape)) + mXX = array(data=XX, mask=m.reshape(XX.shape)) + + self.d = (x, X, XX, m, mx, mX, mXX) + + def test_trace(self): + (x, X, XX, m, mx, mX, mXX,) = self.d + mXdiag = mX.diagonal() + assert_equal(mX.trace(), mX.diagonal().compressed().sum()) + assert_(eq(mX.trace(), + X.trace() - sum(mXdiag.mask * X.diagonal(), + axis=0))) + + def test_clip(self): + (x, X, XX, m, mx, mX, mXX,) = self.d + clipped = mx.clip(2, 8) + assert_(eq(clipped.mask, mx.mask)) + assert_(eq(clipped._data, x.clip(2, 8))) + assert_(eq(clipped._data, mx._data.clip(2, 8))) + + def test_ptp(self): + (x, X, XX, m, mx, mX, mXX,) = self.d + (n, m) = X.shape + assert_equal(mx.ptp(), mx.compressed().ptp()) + rows = np.zeros(n, np.float_) + cols = np.zeros(m, np.float_) + for k in range(m): + cols[k] = mX[:, k].compressed().ptp() + for k in range(n): + rows[k] = mX[k].compressed().ptp() + assert_(eq(mX.ptp(0), cols)) + assert_(eq(mX.ptp(1), rows)) + + def test_swapaxes(self): + (x, X, XX, m, mx, mX, mXX,) = self.d + mXswapped = mX.swapaxes(0, 1) + assert_(eq(mXswapped[-1], mX[:, -1])) + mXXswapped = mXX.swapaxes(0, 2) + assert_equal(mXXswapped.shape, (2, 2, 3, 3)) + + def test_cumprod(self): + (x, X, XX, m, mx, mX, mXX,) = self.d + mXcp = mX.cumprod(0) + assert_(eq(mXcp._data, mX.filled(1).cumprod(0))) + mXcp = mX.cumprod(1) + assert_(eq(mXcp._data, mX.filled(1).cumprod(1))) + + def test_cumsum(self): + (x, X, XX, m, mx, mX, mXX,) = self.d + mXcp = mX.cumsum(0) + assert_(eq(mXcp._data, mX.filled(0).cumsum(0))) + mXcp = mX.cumsum(1) + assert_(eq(mXcp._data, mX.filled(0).cumsum(1))) + + def test_varstd(self): + (x, X, XX, m, mx, mX, mXX,) = self.d + assert_(eq(mX.var(axis=None), mX.compressed().var())) + assert_(eq(mX.std(axis=None), mX.compressed().std())) + assert_(eq(mXX.var(axis=3).shape, XX.var(axis=3).shape)) + assert_(eq(mX.var().shape, X.var().shape)) + (mXvar0, mXvar1) = (mX.var(axis=0), mX.var(axis=1)) + for k in range(6): + assert_(eq(mXvar1[k], mX[k].compressed().var())) + assert_(eq(mXvar0[k], mX[:, k].compressed().var())) + assert_(eq(np.sqrt(mXvar0[k]), + mX[:, k].compressed().std())) + + +def eqmask(m1, m2): + if m1 is nomask: + return m2 is nomask + if m2 is nomask: + return m1 is nomask + return (m1 == m2).all() + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/ma/tests/test_regression.py b/numpy/ma/tests/test_regression.py new file mode 100644 index 0000000..925b21a --- /dev/null +++ b/numpy/ma/tests/test_regression.py @@ -0,0 +1,80 @@ +from __future__ import division, absolute_import, print_function + +import warnings + +import numpy as np +from numpy.testing import ( + assert_, assert_array_equal, assert_allclose, run_module_suite, + suppress_warnings + ) + + +class TestRegression(object): + def test_masked_array_create(self): + # Ticket #17 + x = np.ma.masked_array([0, 1, 2, 3, 0, 4, 5, 6], + mask=[0, 0, 0, 1, 1, 1, 0, 0]) + assert_array_equal(np.ma.nonzero(x), [[1, 2, 6, 7]]) + + def test_masked_array(self): + # Ticket #61 + np.ma.array(1, mask=[1]) + + def test_mem_masked_where(self): + # Ticket #62 + from numpy.ma import masked_where, MaskType + a = np.zeros((1, 1)) + b = np.zeros(a.shape, MaskType) + c = masked_where(b, a) + a-c + + def test_masked_array_multiply(self): + # Ticket #254 + a = np.ma.zeros((4, 1)) + a[2, 0] = np.ma.masked + b = np.zeros((4, 2)) + a*b + b*a + + def test_masked_array_repeat(self): + # Ticket #271 + np.ma.array([1], mask=False).repeat(10) + + def test_masked_array_repr_unicode(self): + # Ticket #1256 + repr(np.ma.array(u"Unicode")) + + def test_atleast_2d(self): + # Ticket #1559 + a = np.ma.masked_array([0.0, 1.2, 3.5], mask=[False, True, False]) + b = np.atleast_2d(a) + assert_(a.mask.ndim == 1) + assert_(b.mask.ndim == 2) + + def test_set_fill_value_unicode_py3(self): + # Ticket #2733 + a = np.ma.masked_array(['a', 'b', 'c'], mask=[1, 0, 0]) + a.fill_value = 'X' + assert_(a.fill_value == 'X') + + def test_var_sets_maskedarray_scalar(self): + # Issue gh-2757 + a = np.ma.array(np.arange(5), mask=True) + mout = np.ma.array(-1, dtype=float) + a.var(out=mout) + assert_(mout._data == 0) + + def test_ddof_corrcoef(self): + # See gh-3336 + x = np.ma.masked_equal([1, 2, 3, 4, 5], 4) + y = np.array([2, 2.5, 3.1, 3, 5]) + # this test can be removed after deprecation. + with suppress_warnings() as sup: + sup.filter(DeprecationWarning, "bias and ddof have no effect") + r0 = np.ma.corrcoef(x, y, ddof=0) + r1 = np.ma.corrcoef(x, y, ddof=1) + # ddof should not have an effect (it gets cancelled out) + assert_allclose(r0.data, r1.data) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/ma/tests/test_subclassing.py b/numpy/ma/tests/test_subclassing.py new file mode 100644 index 0000000..a545746 --- /dev/null +++ b/numpy/ma/tests/test_subclassing.py @@ -0,0 +1,377 @@ +# pylint: disable-msg=W0611, W0612, W0511,R0201 +"""Tests suite for MaskedArray & subclassing. + +:author: Pierre Gerard-Marchant +:contact: pierregm_at_uga_dot_edu +:version: $Id: test_subclassing.py 3473 2007-10-29 15:18:13Z jarrod.millman $ + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import run_module_suite, assert_, assert_raises, dec +from numpy.ma.testutils import assert_equal +from numpy.ma.core import ( + array, arange, masked, MaskedArray, masked_array, log, add, hypot, + divide, asarray, asanyarray, nomask + ) +# from numpy.ma.core import ( + +def assert_startswith(a, b): + # produces a better error message than assert_(a.startswith(b)) + assert_equal(a[:len(b)], b) + +class SubArray(np.ndarray): + # Defines a generic np.ndarray subclass, that stores some metadata + # in the dictionary `info`. + def __new__(cls,arr,info={}): + x = np.asanyarray(arr).view(cls) + x.info = info.copy() + return x + + def __array_finalize__(self, obj): + if callable(getattr(super(SubArray, self), + '__array_finalize__', None)): + super(SubArray, self).__array_finalize__(obj) + self.info = getattr(obj, 'info', {}).copy() + return + + def __add__(self, other): + result = super(SubArray, self).__add__(other) + result.info['added'] = result.info.get('added', 0) + 1 + return result + + def __iadd__(self, other): + result = super(SubArray, self).__iadd__(other) + result.info['iadded'] = result.info.get('iadded', 0) + 1 + return result + + +subarray = SubArray + + +class SubMaskedArray(MaskedArray): + """Pure subclass of MaskedArray, keeping some info on subclass.""" + def __new__(cls, info=None, **kwargs): + obj = super(SubMaskedArray, cls).__new__(cls, **kwargs) + obj._optinfo['info'] = info + return obj + + +class MSubArray(SubArray, MaskedArray): + + def __new__(cls, data, info={}, mask=nomask): + subarr = SubArray(data, info) + _data = MaskedArray.__new__(cls, data=subarr, mask=mask) + _data.info = subarr.info + return _data + + def _get_series(self): + _view = self.view(MaskedArray) + _view._sharedmask = False + return _view + _series = property(fget=_get_series) + +msubarray = MSubArray + + +class MMatrix(MaskedArray, np.matrix,): + + def __new__(cls, data, mask=nomask): + mat = np.matrix(data) + _data = MaskedArray.__new__(cls, data=mat, mask=mask) + return _data + + def __array_finalize__(self, obj): + np.matrix.__array_finalize__(self, obj) + MaskedArray.__array_finalize__(self, obj) + return + + def _get_series(self): + _view = self.view(MaskedArray) + _view._sharedmask = False + return _view + _series = property(fget=_get_series) + +mmatrix = MMatrix + + +# Also a subclass that overrides __str__, __repr__ and __setitem__, disallowing +# setting to non-class values (and thus np.ma.core.masked_print_option) +# and overrides __array_wrap__, updating the info dict, to check that this +# doesn't get destroyed by MaskedArray._update_from. But this one also needs +# its own iterator... +class CSAIterator(object): + """ + Flat iterator object that uses its own setter/getter + (works around ndarray.flat not propagating subclass setters/getters + see https://github.com/numpy/numpy/issues/4564) + roughly following MaskedIterator + """ + def __init__(self, a): + self._original = a + self._dataiter = a.view(np.ndarray).flat + + def __iter__(self): + return self + + def __getitem__(self, indx): + out = self._dataiter.__getitem__(indx) + if not isinstance(out, np.ndarray): + out = out.__array__() + out = out.view(type(self._original)) + return out + + def __setitem__(self, index, value): + self._dataiter[index] = self._original._validate_input(value) + + def __next__(self): + return next(self._dataiter).__array__().view(type(self._original)) + + next = __next__ + + +class ComplicatedSubArray(SubArray): + + def __str__(self): + return 'myprefix {0} mypostfix'.format(self.view(SubArray)) + + def __repr__(self): + # Return a repr that does not start with 'name(' + return '<{0} {1}>'.format(self.__class__.__name__, self) + + def _validate_input(self, value): + if not isinstance(value, ComplicatedSubArray): + raise ValueError("Can only set to MySubArray values") + return value + + def __setitem__(self, item, value): + # validation ensures direct assignment with ndarray or + # masked_print_option will fail + super(ComplicatedSubArray, self).__setitem__( + item, self._validate_input(value)) + + def __getitem__(self, item): + # ensure getter returns our own class also for scalars + value = super(ComplicatedSubArray, self).__getitem__(item) + if not isinstance(value, np.ndarray): # scalar + value = value.__array__().view(ComplicatedSubArray) + return value + + @property + def flat(self): + return CSAIterator(self) + + @flat.setter + def flat(self, value): + y = self.ravel() + y[:] = value + + def __array_wrap__(self, obj, context=None): + obj = super(ComplicatedSubArray, self).__array_wrap__(obj, context) + if context is not None and context[0] is np.multiply: + obj.info['multiplied'] = obj.info.get('multiplied', 0) + 1 + + return obj + + +class TestSubclassing(object): + # Test suite for masked subclasses of ndarray. + + def setup(self): + x = np.arange(5, dtype='float') + mx = mmatrix(x, mask=[0, 1, 0, 0, 0]) + self.data = (x, mx) + + def test_data_subclassing(self): + # Tests whether the subclass is kept. + x = np.arange(5) + m = [0, 0, 1, 0, 0] + xsub = SubArray(x) + xmsub = masked_array(xsub, mask=m) + assert_(isinstance(xmsub, MaskedArray)) + assert_equal(xmsub._data, xsub) + assert_(isinstance(xmsub._data, SubArray)) + + def test_maskedarray_subclassing(self): + # Tests subclassing MaskedArray + (x, mx) = self.data + assert_(isinstance(mx._data, np.matrix)) + + def test_masked_unary_operations(self): + # Tests masked_unary_operation + (x, mx) = self.data + with np.errstate(divide='ignore'): + assert_(isinstance(log(mx), mmatrix)) + assert_equal(log(x), np.log(x)) + + def test_masked_binary_operations(self): + # Tests masked_binary_operation + (x, mx) = self.data + # Result should be a mmatrix + assert_(isinstance(add(mx, mx), mmatrix)) + assert_(isinstance(add(mx, x), mmatrix)) + # Result should work + assert_equal(add(mx, x), mx+x) + assert_(isinstance(add(mx, mx)._data, np.matrix)) + assert_(isinstance(add.outer(mx, mx), mmatrix)) + assert_(isinstance(hypot(mx, mx), mmatrix)) + assert_(isinstance(hypot(mx, x), mmatrix)) + + def test_masked_binary_operations2(self): + # Tests domained_masked_binary_operation + (x, mx) = self.data + xmx = masked_array(mx.data.__array__(), mask=mx.mask) + assert_(isinstance(divide(mx, mx), mmatrix)) + assert_(isinstance(divide(mx, x), mmatrix)) + assert_equal(divide(mx, mx), divide(xmx, xmx)) + + def test_attributepropagation(self): + x = array(arange(5), mask=[0]+[1]*4) + my = masked_array(subarray(x)) + ym = msubarray(x) + # + z = (my+1) + assert_(isinstance(z, MaskedArray)) + assert_(not isinstance(z, MSubArray)) + assert_(isinstance(z._data, SubArray)) + assert_equal(z._data.info, {}) + # + z = (ym+1) + assert_(isinstance(z, MaskedArray)) + assert_(isinstance(z, MSubArray)) + assert_(isinstance(z._data, SubArray)) + assert_(z._data.info['added'] > 0) + # Test that inplace methods from data get used (gh-4617) + ym += 1 + assert_(isinstance(ym, MaskedArray)) + assert_(isinstance(ym, MSubArray)) + assert_(isinstance(ym._data, SubArray)) + assert_(ym._data.info['iadded'] > 0) + # + ym._set_mask([1, 0, 0, 0, 1]) + assert_equal(ym._mask, [1, 0, 0, 0, 1]) + ym._series._set_mask([0, 0, 0, 0, 1]) + assert_equal(ym._mask, [0, 0, 0, 0, 1]) + # + xsub = subarray(x, info={'name':'x'}) + mxsub = masked_array(xsub) + assert_(hasattr(mxsub, 'info')) + assert_equal(mxsub.info, xsub.info) + + def test_subclasspreservation(self): + # Checks that masked_array(...,subok=True) preserves the class. + x = np.arange(5) + m = [0, 0, 1, 0, 0] + xinfo = [(i, j) for (i, j) in zip(x, m)] + xsub = MSubArray(x, mask=m, info={'xsub':xinfo}) + # + mxsub = masked_array(xsub, subok=False) + assert_(not isinstance(mxsub, MSubArray)) + assert_(isinstance(mxsub, MaskedArray)) + assert_equal(mxsub._mask, m) + # + mxsub = asarray(xsub) + assert_(not isinstance(mxsub, MSubArray)) + assert_(isinstance(mxsub, MaskedArray)) + assert_equal(mxsub._mask, m) + # + mxsub = masked_array(xsub, subok=True) + assert_(isinstance(mxsub, MSubArray)) + assert_equal(mxsub.info, xsub.info) + assert_equal(mxsub._mask, xsub._mask) + # + mxsub = asanyarray(xsub) + assert_(isinstance(mxsub, MSubArray)) + assert_equal(mxsub.info, xsub.info) + assert_equal(mxsub._mask, m) + + def test_subclass_items(self): + """test that getter and setter go via baseclass""" + x = np.arange(5) + xcsub = ComplicatedSubArray(x) + mxcsub = masked_array(xcsub, mask=[True, False, True, False, False]) + # getter should return a ComplicatedSubArray, even for single item + # first check we wrote ComplicatedSubArray correctly + assert_(isinstance(xcsub[1], ComplicatedSubArray)) + assert_(isinstance(xcsub[1,...], ComplicatedSubArray)) + assert_(isinstance(xcsub[1:4], ComplicatedSubArray)) + + # now that it propagates inside the MaskedArray + assert_(isinstance(mxcsub[1], ComplicatedSubArray)) + assert_(isinstance(mxcsub[1,...].data, ComplicatedSubArray)) + assert_(mxcsub[0] is masked) + assert_(isinstance(mxcsub[0,...].data, ComplicatedSubArray)) + assert_(isinstance(mxcsub[1:4].data, ComplicatedSubArray)) + + # also for flattened version (which goes via MaskedIterator) + assert_(isinstance(mxcsub.flat[1].data, ComplicatedSubArray)) + assert_(mxcsub.flat[0] is masked) + assert_(isinstance(mxcsub.flat[1:4].base, ComplicatedSubArray)) + + # setter should only work with ComplicatedSubArray input + # first check we wrote ComplicatedSubArray correctly + assert_raises(ValueError, xcsub.__setitem__, 1, x[4]) + # now that it propagates inside the MaskedArray + assert_raises(ValueError, mxcsub.__setitem__, 1, x[4]) + assert_raises(ValueError, mxcsub.__setitem__, slice(1, 4), x[1:4]) + mxcsub[1] = xcsub[4] + mxcsub[1:4] = xcsub[1:4] + # also for flattened version (which goes via MaskedIterator) + assert_raises(ValueError, mxcsub.flat.__setitem__, 1, x[4]) + assert_raises(ValueError, mxcsub.flat.__setitem__, slice(1, 4), x[1:4]) + mxcsub.flat[1] = xcsub[4] + mxcsub.flat[1:4] = xcsub[1:4] + + def test_subclass_nomask_items(self): + x = np.arange(5) + xcsub = ComplicatedSubArray(x) + mxcsub_nomask = masked_array(xcsub) + + assert_(isinstance(mxcsub_nomask[1,...].data, ComplicatedSubArray)) + assert_(isinstance(mxcsub_nomask[0,...].data, ComplicatedSubArray)) + + assert_(isinstance(mxcsub_nomask[1], ComplicatedSubArray)) + assert_(isinstance(mxcsub_nomask[0], ComplicatedSubArray)) + + def test_subclass_repr(self): + """test that repr uses the name of the subclass + and 'array' for np.ndarray""" + x = np.arange(5) + mx = masked_array(x, mask=[True, False, True, False, False]) + assert_startswith(repr(mx), 'masked_array') + xsub = SubArray(x) + mxsub = masked_array(xsub, mask=[True, False, True, False, False]) + assert_startswith(repr(mxsub), + 'masked_{0}(data=[--, 1, --, 3, 4]'.format(SubArray.__name__)) + + def test_subclass_str(self): + """test str with subclass that has overridden str, setitem""" + # first without override + x = np.arange(5) + xsub = SubArray(x) + mxsub = masked_array(xsub, mask=[True, False, True, False, False]) + assert_equal(str(mxsub), '[-- 1 -- 3 4]') + + xcsub = ComplicatedSubArray(x) + assert_raises(ValueError, xcsub.__setitem__, 0, + np.ma.core.masked_print_option) + mxcsub = masked_array(xcsub, mask=[True, False, True, False, False]) + assert_equal(str(mxcsub), 'myprefix [-- 1 -- 3 4] mypostfix') + + def test_pure_subclass_info_preservation(self): + # Test that ufuncs and methods conserve extra information consistently; + # see gh-7122. + arr1 = SubMaskedArray('test', data=[1,2,3,4,5,6]) + arr2 = SubMaskedArray(data=[0,1,2,3,4,5]) + diff1 = np.subtract(arr1, arr2) + assert_('info' in diff1._optinfo) + assert_(diff1._optinfo['info'] == 'test') + diff2 = arr1 - arr2 + assert_('info' in diff2._optinfo) + assert_(diff2._optinfo['info'] == 'test') + + +############################################################################### +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/ma/testutils.py b/numpy/ma/testutils.py new file mode 100644 index 0000000..a95c170 --- /dev/null +++ b/numpy/ma/testutils.py @@ -0,0 +1,289 @@ +"""Miscellaneous functions for testing masked arrays and subclasses + +:author: Pierre Gerard-Marchant +:contact: pierregm_at_uga_dot_edu +:version: $Id: testutils.py 3529 2007-11-13 08:01:14Z jarrod.millman $ + +""" +from __future__ import division, absolute_import, print_function + +import operator + +import numpy as np +from numpy import ndarray, float_ +import numpy.core.umath as umath +import numpy.testing +from numpy.testing import ( + TestCase, assert_, assert_allclose, assert_array_almost_equal_nulp, + assert_raises, build_err_msg, run_module_suite + ) +from .core import mask_or, getmask, masked_array, nomask, masked, filled + +__all__masked = [ + 'almost', 'approx', 'assert_almost_equal', 'assert_array_almost_equal', + 'assert_array_approx_equal', 'assert_array_compare', + 'assert_array_equal', 'assert_array_less', 'assert_close', + 'assert_equal', 'assert_equal_records', 'assert_mask_equal', + 'assert_not_equal', 'fail_if_array_equal', + ] + +# Include some normal test functions to avoid breaking other projects who +# have mistakenly included them from this file. SciPy is one. That is +# unfortunate, as some of these functions are not intended to work with +# masked arrays. But there was no way to tell before. +__some__from_testing = [ + 'TestCase', 'assert_', 'assert_allclose', + 'assert_array_almost_equal_nulp', 'assert_raises', 'run_module_suite', + ] + +__all__ = __all__masked + __some__from_testing + + +def approx(a, b, fill_value=True, rtol=1e-5, atol=1e-8): + """ + Returns true if all components of a and b are equal to given tolerances. + + If fill_value is True, masked values considered equal. Otherwise, + masked values are considered unequal. The relative error rtol should + be positive and << 1.0 The absolute error atol comes into play for + those elements of b that are very small or zero; it says how small a + must be also. + + """ + m = mask_or(getmask(a), getmask(b)) + d1 = filled(a) + d2 = filled(b) + if d1.dtype.char == "O" or d2.dtype.char == "O": + return np.equal(d1, d2).ravel() + x = filled(masked_array(d1, copy=False, mask=m), fill_value).astype(float_) + y = filled(masked_array(d2, copy=False, mask=m), 1).astype(float_) + d = np.less_equal(umath.absolute(x - y), atol + rtol * umath.absolute(y)) + return d.ravel() + + +def almost(a, b, decimal=6, fill_value=True): + """ + Returns True if a and b are equal up to decimal places. + + If fill_value is True, masked values considered equal. Otherwise, + masked values are considered unequal. + + """ + m = mask_or(getmask(a), getmask(b)) + d1 = filled(a) + d2 = filled(b) + if d1.dtype.char == "O" or d2.dtype.char == "O": + return np.equal(d1, d2).ravel() + x = filled(masked_array(d1, copy=False, mask=m), fill_value).astype(float_) + y = filled(masked_array(d2, copy=False, mask=m), 1).astype(float_) + d = np.around(np.abs(x - y), decimal) <= 10.0 ** (-decimal) + return d.ravel() + + +def _assert_equal_on_sequences(actual, desired, err_msg=''): + """ + Asserts the equality of two non-array sequences. + + """ + assert_equal(len(actual), len(desired), err_msg) + for k in range(len(desired)): + assert_equal(actual[k], desired[k], 'item=%r\n%s' % (k, err_msg)) + return + + +def assert_equal_records(a, b): + """ + Asserts that two records are equal. + + Pretty crude for now. + + """ + assert_equal(a.dtype, b.dtype) + for f in a.dtype.names: + (af, bf) = (operator.getitem(a, f), operator.getitem(b, f)) + if not (af is masked) and not (bf is masked): + assert_equal(operator.getitem(a, f), operator.getitem(b, f)) + return + + +def assert_equal(actual, desired, err_msg=''): + """ + Asserts that two items are equal. + + """ + # Case #1: dictionary ..... + if isinstance(desired, dict): + if not isinstance(actual, dict): + raise AssertionError(repr(type(actual))) + assert_equal(len(actual), len(desired), err_msg) + for k, i in desired.items(): + if k not in actual: + raise AssertionError("%s not in %s" % (k, actual)) + assert_equal(actual[k], desired[k], 'key=%r\n%s' % (k, err_msg)) + return + # Case #2: lists ..... + if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)): + return _assert_equal_on_sequences(actual, desired, err_msg='') + if not (isinstance(actual, ndarray) or isinstance(desired, ndarray)): + msg = build_err_msg([actual, desired], err_msg,) + if not desired == actual: + raise AssertionError(msg) + return + # Case #4. arrays or equivalent + if ((actual is masked) and not (desired is masked)) or \ + ((desired is masked) and not (actual is masked)): + msg = build_err_msg([actual, desired], + err_msg, header='', names=('x', 'y')) + raise ValueError(msg) + actual = np.array(actual, copy=False, subok=True) + desired = np.array(desired, copy=False, subok=True) + (actual_dtype, desired_dtype) = (actual.dtype, desired.dtype) + if actual_dtype.char == "S" and desired_dtype.char == "S": + return _assert_equal_on_sequences(actual.tolist(), + desired.tolist(), + err_msg='') + return assert_array_equal(actual, desired, err_msg) + + +def fail_if_equal(actual, desired, err_msg='',): + """ + Raises an assertion error if two items are equal. + + """ + if isinstance(desired, dict): + if not isinstance(actual, dict): + raise AssertionError(repr(type(actual))) + fail_if_equal(len(actual), len(desired), err_msg) + for k, i in desired.items(): + if k not in actual: + raise AssertionError(repr(k)) + fail_if_equal(actual[k], desired[k], 'key=%r\n%s' % (k, err_msg)) + return + if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)): + fail_if_equal(len(actual), len(desired), err_msg) + for k in range(len(desired)): + fail_if_equal(actual[k], desired[k], 'item=%r\n%s' % (k, err_msg)) + return + if isinstance(actual, np.ndarray) or isinstance(desired, np.ndarray): + return fail_if_array_equal(actual, desired, err_msg) + msg = build_err_msg([actual, desired], err_msg) + if not desired != actual: + raise AssertionError(msg) + + +assert_not_equal = fail_if_equal + + +def assert_almost_equal(actual, desired, decimal=7, err_msg='', verbose=True): + """ + Asserts that two items are almost equal. + + The test is equivalent to abs(desired-actual) < 0.5 * 10**(-decimal). + + """ + if isinstance(actual, np.ndarray) or isinstance(desired, np.ndarray): + return assert_array_almost_equal(actual, desired, decimal=decimal, + err_msg=err_msg, verbose=verbose) + msg = build_err_msg([actual, desired], + err_msg=err_msg, verbose=verbose) + if not round(abs(desired - actual), decimal) == 0: + raise AssertionError(msg) + + +assert_close = assert_almost_equal + + +def assert_array_compare(comparison, x, y, err_msg='', verbose=True, header='', + fill_value=True): + """ + Asserts that comparison between two masked arrays is satisfied. + + The comparison is elementwise. + + """ + # Allocate a common mask and refill + m = mask_or(getmask(x), getmask(y)) + x = masked_array(x, copy=False, mask=m, keep_mask=False, subok=False) + y = masked_array(y, copy=False, mask=m, keep_mask=False, subok=False) + if ((x is masked) and not (y is masked)) or \ + ((y is masked) and not (x is masked)): + msg = build_err_msg([x, y], err_msg=err_msg, verbose=verbose, + header=header, names=('x', 'y')) + raise ValueError(msg) + # OK, now run the basic tests on filled versions + return np.testing.assert_array_compare(comparison, + x.filled(fill_value), + y.filled(fill_value), + err_msg=err_msg, + verbose=verbose, header=header) + + +def assert_array_equal(x, y, err_msg='', verbose=True): + """ + Checks the elementwise equality of two masked arrays. + + """ + assert_array_compare(operator.__eq__, x, y, + err_msg=err_msg, verbose=verbose, + header='Arrays are not equal') + + +def fail_if_array_equal(x, y, err_msg='', verbose=True): + """ + Raises an assertion error if two masked arrays are not equal elementwise. + + """ + def compare(x, y): + return (not np.alltrue(approx(x, y))) + assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose, + header='Arrays are not equal') + + +def assert_array_approx_equal(x, y, decimal=6, err_msg='', verbose=True): + """ + Checks the equality of two masked arrays, up to given number odecimals. + + The equality is checked elementwise. + + """ + def compare(x, y): + "Returns the result of the loose comparison between x and y)." + return approx(x, y, rtol=10. ** -decimal) + assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose, + header='Arrays are not almost equal') + + +def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True): + """ + Checks the equality of two masked arrays, up to given number odecimals. + + The equality is checked elementwise. + + """ + def compare(x, y): + "Returns the result of the loose comparison between x and y)." + return almost(x, y, decimal) + assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose, + header='Arrays are not almost equal') + + +def assert_array_less(x, y, err_msg='', verbose=True): + """ + Checks that x is smaller than y elementwise. + + """ + assert_array_compare(operator.__lt__, x, y, + err_msg=err_msg, verbose=verbose, + header='Arrays are not less-ordered') + + +def assert_mask_equal(m1, m2, err_msg=''): + """ + Asserts the equality of two masks. + + """ + if m1 is nomask: + assert_(m2 is nomask) + if m2 is nomask: + assert_(m1 is nomask) + assert_array_equal(m1, m2, err_msg=err_msg) diff --git a/numpy/ma/timer_comparison.py b/numpy/ma/timer_comparison.py new file mode 100644 index 0000000..68104ed --- /dev/null +++ b/numpy/ma/timer_comparison.py @@ -0,0 +1,440 @@ +from __future__ import division, absolute_import, print_function + +import timeit +from functools import reduce + +import numpy as np +from numpy import float_ +import numpy.core.fromnumeric as fromnumeric + +from numpy.testing import build_err_msg + +# Fixme: this does not look right. +np.seterr(all='ignore') + +pi = np.pi + + +class ModuleTester(object): + def __init__(self, module): + self.module = module + self.allequal = module.allequal + self.arange = module.arange + self.array = module.array + self.concatenate = module.concatenate + self.count = module.count + self.equal = module.equal + self.filled = module.filled + self.getmask = module.getmask + self.getmaskarray = module.getmaskarray + self.id = id + self.inner = module.inner + self.make_mask = module.make_mask + self.masked = module.masked + self.masked_array = module.masked_array + self.masked_values = module.masked_values + self.mask_or = module.mask_or + self.nomask = module.nomask + self.ones = module.ones + self.outer = module.outer + self.repeat = module.repeat + self.resize = module.resize + self.sort = module.sort + self.take = module.take + self.transpose = module.transpose + self.zeros = module.zeros + self.MaskType = module.MaskType + try: + self.umath = module.umath + except AttributeError: + self.umath = module.core.umath + self.testnames = [] + + def assert_array_compare(self, comparison, x, y, err_msg='', header='', + fill_value=True): + """ + Assert that a comparison of two masked arrays is satisfied elementwise. + + """ + xf = self.filled(x) + yf = self.filled(y) + m = self.mask_or(self.getmask(x), self.getmask(y)) + + x = self.filled(self.masked_array(xf, mask=m), fill_value) + y = self.filled(self.masked_array(yf, mask=m), fill_value) + if (x.dtype.char != "O"): + x = x.astype(float_) + if isinstance(x, np.ndarray) and x.size > 1: + x[np.isnan(x)] = 0 + elif np.isnan(x): + x = 0 + if (y.dtype.char != "O"): + y = y.astype(float_) + if isinstance(y, np.ndarray) and y.size > 1: + y[np.isnan(y)] = 0 + elif np.isnan(y): + y = 0 + try: + cond = (x.shape == () or y.shape == ()) or x.shape == y.shape + if not cond: + msg = build_err_msg([x, y], + err_msg + + '\n(shapes %s, %s mismatch)' % (x.shape, + y.shape), + header=header, + names=('x', 'y')) + assert cond, msg + val = comparison(x, y) + if m is not self.nomask and fill_value: + val = self.masked_array(val, mask=m) + if isinstance(val, bool): + cond = val + reduced = [0] + else: + reduced = val.ravel() + cond = reduced.all() + reduced = reduced.tolist() + if not cond: + match = 100-100.0*reduced.count(1)/len(reduced) + msg = build_err_msg([x, y], + err_msg + + '\n(mismatch %s%%)' % (match,), + header=header, + names=('x', 'y')) + assert cond, msg + except ValueError: + msg = build_err_msg([x, y], err_msg, header=header, names=('x', 'y')) + raise ValueError(msg) + + def assert_array_equal(self, x, y, err_msg=''): + """ + Checks the elementwise equality of two masked arrays. + + """ + self.assert_array_compare(self.equal, x, y, err_msg=err_msg, + header='Arrays are not equal') + + def test_0(self): + """ + Tests creation + + """ + x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.]) + m = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0] + xm = self.masked_array(x, mask=m) + xm[0] + + def test_1(self): + """ + Tests creation + + """ + x = np.array([1., 1., 1., -2., pi/2.0, 4., 5., -10., 10., 1., 2., 3.]) + y = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.]) + m1 = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0] + m2 = [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1] + xm = self.masked_array(x, mask=m1) + ym = self.masked_array(y, mask=m2) + xf = np.where(m1, 1.e+20, x) + xm.set_fill_value(1.e+20) + + assert((xm-ym).filled(0).any()) + s = x.shape + assert(xm.size == reduce(lambda x, y:x*y, s)) + assert(self.count(xm) == len(m1) - reduce(lambda x, y:x+y, m1)) + + for s in [(4, 3), (6, 2)]: + x.shape = s + y.shape = s + xm.shape = s + ym.shape = s + xf.shape = s + assert(self.count(xm) == len(m1) - reduce(lambda x, y:x+y, m1)) + + def test_2(self): + """ + Tests conversions and indexing. + + """ + x1 = np.array([1, 2, 4, 3]) + x2 = self.array(x1, mask=[1, 0, 0, 0]) + x3 = self.array(x1, mask=[0, 1, 0, 1]) + x4 = self.array(x1) + # test conversion to strings, no errors + str(x2) + repr(x2) + # tests of indexing + assert type(x2[1]) is type(x1[1]) + assert x1[1] == x2[1] + x1[2] = 9 + x2[2] = 9 + self.assert_array_equal(x1, x2) + x1[1:3] = 99 + x2[1:3] = 99 + x2[1] = self.masked + x2[1:3] = self.masked + x2[:] = x1 + x2[1] = self.masked + x3[:] = self.masked_array([1, 2, 3, 4], [0, 1, 1, 0]) + x4[:] = self.masked_array([1, 2, 3, 4], [0, 1, 1, 0]) + x1 = np.arange(5)*1.0 + x2 = self.masked_values(x1, 3.0) + x1 = self.array([1, 'hello', 2, 3], object) + x2 = np.array([1, 'hello', 2, 3], object) + # check that no error occurs. + x1[1] + x2[1] + assert x1[1:1].shape == (0,) + # Tests copy-size + n = [0, 0, 1, 0, 0] + m = self.make_mask(n) + m2 = self.make_mask(m) + assert(m is m2) + m3 = self.make_mask(m, copy=1) + assert(m is not m3) + + def test_3(self): + """ + Tests resize/repeat + + """ + x4 = self.arange(4) + x4[2] = self.masked + y4 = self.resize(x4, (8,)) + assert self.allequal(self.concatenate([x4, x4]), y4) + assert self.allequal(self.getmask(y4), [0, 0, 1, 0, 0, 0, 1, 0]) + y5 = self.repeat(x4, (2, 2, 2, 2), axis=0) + self.assert_array_equal(y5, [0, 0, 1, 1, 2, 2, 3, 3]) + y6 = self.repeat(x4, 2, axis=0) + assert self.allequal(y5, y6) + y7 = x4.repeat((2, 2, 2, 2), axis=0) + assert self.allequal(y5, y7) + y8 = x4.repeat(2, 0) + assert self.allequal(y5, y8) + + def test_4(self): + """ + Test of take, transpose, inner, outer products. + + """ + x = self.arange(24) + y = np.arange(24) + x[5:6] = self.masked + x = x.reshape(2, 3, 4) + y = y.reshape(2, 3, 4) + assert self.allequal(np.transpose(y, (2, 0, 1)), self.transpose(x, (2, 0, 1))) + assert self.allequal(np.take(y, (2, 0, 1), 1), self.take(x, (2, 0, 1), 1)) + assert self.allequal(np.inner(self.filled(x, 0), self.filled(y, 0)), + self.inner(x, y)) + assert self.allequal(np.outer(self.filled(x, 0), self.filled(y, 0)), + self.outer(x, y)) + y = self.array(['abc', 1, 'def', 2, 3], object) + y[2] = self.masked + t = self.take(y, [0, 3, 4]) + assert t[0] == 'abc' + assert t[1] == 2 + assert t[2] == 3 + + def test_5(self): + """ + Tests inplace w/ scalar + + """ + x = self.arange(10) + y = self.arange(10) + xm = self.arange(10) + xm[2] = self.masked + x += 1 + assert self.allequal(x, y+1) + xm += 1 + assert self.allequal(xm, y+1) + + x = self.arange(10) + xm = self.arange(10) + xm[2] = self.masked + x -= 1 + assert self.allequal(x, y-1) + xm -= 1 + assert self.allequal(xm, y-1) + + x = self.arange(10)*1.0 + xm = self.arange(10)*1.0 + xm[2] = self.masked + x *= 2.0 + assert self.allequal(x, y*2) + xm *= 2.0 + assert self.allequal(xm, y*2) + + x = self.arange(10)*2 + xm = self.arange(10)*2 + xm[2] = self.masked + x /= 2 + assert self.allequal(x, y) + xm /= 2 + assert self.allequal(xm, y) + + x = self.arange(10)*1.0 + xm = self.arange(10)*1.0 + xm[2] = self.masked + x /= 2.0 + assert self.allequal(x, y/2.0) + xm /= self.arange(10) + self.assert_array_equal(xm, self.ones((10,))) + + x = self.arange(10).astype(float_) + xm = self.arange(10) + xm[2] = self.masked + x += 1. + assert self.allequal(x, y + 1.) + + def test_6(self): + """ + Tests inplace w/ array + + """ + x = self.arange(10, dtype=float_) + y = self.arange(10) + xm = self.arange(10, dtype=float_) + xm[2] = self.masked + m = xm.mask + a = self.arange(10, dtype=float_) + a[-1] = self.masked + x += a + xm += a + assert self.allequal(x, y+a) + assert self.allequal(xm, y+a) + assert self.allequal(xm.mask, self.mask_or(m, a.mask)) + + x = self.arange(10, dtype=float_) + xm = self.arange(10, dtype=float_) + xm[2] = self.masked + m = xm.mask + a = self.arange(10, dtype=float_) + a[-1] = self.masked + x -= a + xm -= a + assert self.allequal(x, y-a) + assert self.allequal(xm, y-a) + assert self.allequal(xm.mask, self.mask_or(m, a.mask)) + + x = self.arange(10, dtype=float_) + xm = self.arange(10, dtype=float_) + xm[2] = self.masked + m = xm.mask + a = self.arange(10, dtype=float_) + a[-1] = self.masked + x *= a + xm *= a + assert self.allequal(x, y*a) + assert self.allequal(xm, y*a) + assert self.allequal(xm.mask, self.mask_or(m, a.mask)) + + x = self.arange(10, dtype=float_) + xm = self.arange(10, dtype=float_) + xm[2] = self.masked + m = xm.mask + a = self.arange(10, dtype=float_) + a[-1] = self.masked + x /= a + xm /= a + + def test_7(self): + "Tests ufunc" + d = (self.array([1.0, 0, -1, pi/2]*2, mask=[0, 1]+[0]*6), + self.array([1.0, 0, -1, pi/2]*2, mask=[1, 0]+[0]*6),) + for f in ['sqrt', 'log', 'log10', 'exp', 'conjugate', +# 'sin', 'cos', 'tan', +# 'arcsin', 'arccos', 'arctan', +# 'sinh', 'cosh', 'tanh', +# 'arcsinh', +# 'arccosh', +# 'arctanh', +# 'absolute', 'fabs', 'negative', +# # 'nonzero', 'around', +# 'floor', 'ceil', +# # 'sometrue', 'alltrue', +# 'logical_not', +# 'add', 'subtract', 'multiply', +# 'divide', 'true_divide', 'floor_divide', +# 'remainder', 'fmod', 'hypot', 'arctan2', +# 'equal', 'not_equal', 'less_equal', 'greater_equal', +# 'less', 'greater', +# 'logical_and', 'logical_or', 'logical_xor', + ]: + try: + uf = getattr(self.umath, f) + except AttributeError: + uf = getattr(fromnumeric, f) + mf = getattr(self.module, f) + args = d[:uf.nin] + ur = uf(*args) + mr = mf(*args) + self.assert_array_equal(ur.filled(0), mr.filled(0), f) + self.assert_array_equal(ur._mask, mr._mask) + + def test_99(self): + # test average + ott = self.array([0., 1., 2., 3.], mask=[1, 0, 0, 0]) + self.assert_array_equal(2.0, self.average(ott, axis=0)) + self.assert_array_equal(2.0, self.average(ott, weights=[1., 1., 2., 1.])) + result, wts = self.average(ott, weights=[1., 1., 2., 1.], returned=1) + self.assert_array_equal(2.0, result) + assert(wts == 4.0) + ott[:] = self.masked + assert(self.average(ott, axis=0) is self.masked) + ott = self.array([0., 1., 2., 3.], mask=[1, 0, 0, 0]) + ott = ott.reshape(2, 2) + ott[:, 1] = self.masked + self.assert_array_equal(self.average(ott, axis=0), [2.0, 0.0]) + assert(self.average(ott, axis=1)[0] is self.masked) + self.assert_array_equal([2., 0.], self.average(ott, axis=0)) + result, wts = self.average(ott, axis=0, returned=1) + self.assert_array_equal(wts, [1., 0.]) + w1 = [0, 1, 1, 1, 1, 0] + w2 = [[0, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 1]] + x = self.arange(6) + self.assert_array_equal(self.average(x, axis=0), 2.5) + self.assert_array_equal(self.average(x, axis=0, weights=w1), 2.5) + y = self.array([self.arange(6), 2.0*self.arange(6)]) + self.assert_array_equal(self.average(y, None), np.add.reduce(np.arange(6))*3./12.) + self.assert_array_equal(self.average(y, axis=0), np.arange(6) * 3./2.) + self.assert_array_equal(self.average(y, axis=1), [self.average(x, axis=0), self.average(x, axis=0) * 2.0]) + self.assert_array_equal(self.average(y, None, weights=w2), 20./6.) + self.assert_array_equal(self.average(y, axis=0, weights=w2), [0., 1., 2., 3., 4., 10.]) + self.assert_array_equal(self.average(y, axis=1), [self.average(x, axis=0), self.average(x, axis=0) * 2.0]) + m1 = self.zeros(6) + m2 = [0, 0, 1, 1, 0, 0] + m3 = [[0, 0, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0]] + m4 = self.ones(6) + m5 = [0, 1, 1, 1, 1, 1] + self.assert_array_equal(self.average(self.masked_array(x, m1), axis=0), 2.5) + self.assert_array_equal(self.average(self.masked_array(x, m2), axis=0), 2.5) + self.assert_array_equal(self.average(self.masked_array(x, m5), axis=0), 0.0) + self.assert_array_equal(self.count(self.average(self.masked_array(x, m4), axis=0)), 0) + z = self.masked_array(y, m3) + self.assert_array_equal(self.average(z, None), 20./6.) + self.assert_array_equal(self.average(z, axis=0), [0., 1., 99., 99., 4.0, 7.5]) + self.assert_array_equal(self.average(z, axis=1), [2.5, 5.0]) + self.assert_array_equal(self.average(z, axis=0, weights=w2), [0., 1., 99., 99., 4.0, 10.0]) + + def test_A(self): + x = self.arange(24) + x[5:6] = self.masked + x = x.reshape(2, 3, 4) + + +if __name__ == '__main__': + setup_base = ("from __main__ import ModuleTester \n" + "import numpy\n" + "tester = ModuleTester(module)\n") + setup_cur = "import numpy.ma.core as module\n" + setup_base + (nrepeat, nloop) = (10, 10) + + if 1: + for i in range(1, 8): + func = 'tester.test_%i()' % i + cur = timeit.Timer(func, setup_cur).repeat(nrepeat, nloop*10) + cur = np.sort(cur) + print("#%i" % i + 50*'.') + print(eval("ModuleTester.test_%i.__doc__" % i)) + print("core_current : %.3f - %.3f" % (cur[0], cur[1])) diff --git a/numpy/ma/version.py b/numpy/ma/version.py new file mode 100644 index 0000000..a2c5c42 --- /dev/null +++ b/numpy/ma/version.py @@ -0,0 +1,14 @@ +"""Version number + +""" +from __future__ import division, absolute_import, print_function + +version = '1.00' +release = False + +if not release: + from . import core + from . import extras + revision = [core.__revision__.split(':')[-1][:-1].strip(), + extras.__revision__.split(':')[-1][:-1].strip(),] + version += '.dev%04i' % max([int(rev) for rev in revision]) diff --git a/numpy/matlib.py b/numpy/matlib.py new file mode 100644 index 0000000..004e5f0 --- /dev/null +++ b/numpy/matlib.py @@ -0,0 +1,363 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.matrixlib.defmatrix import matrix, asmatrix +# need * as we're copying the numpy namespace +from numpy import * + +__version__ = np.__version__ + +__all__ = np.__all__[:] # copy numpy namespace +__all__ += ['rand', 'randn', 'repmat'] + +def empty(shape, dtype=None, order='C'): + """Return a new matrix of given shape and type, without initializing entries. + + Parameters + ---------- + shape : int or tuple of int + Shape of the empty matrix. + dtype : data-type, optional + Desired output data-type. + order : {'C', 'F'}, optional + Whether to store multi-dimensional data in row-major + (C-style) or column-major (Fortran-style) order in + memory. + + See Also + -------- + empty_like, zeros + + Notes + ----- + `empty`, unlike `zeros`, does not set the matrix values to zero, + and may therefore be marginally faster. On the other hand, it requires + the user to manually set all the values in the array, and should be + used with caution. + + Examples + -------- + >>> import numpy.matlib + >>> np.matlib.empty((2, 2)) # filled with random data + matrix([[ 6.76425276e-320, 9.79033856e-307], + [ 7.39337286e-309, 3.22135945e-309]]) #random + >>> np.matlib.empty((2, 2), dtype=int) + matrix([[ 6600475, 0], + [ 6586976, 22740995]]) #random + + """ + return ndarray.__new__(matrix, shape, dtype, order=order) + +def ones(shape, dtype=None, order='C'): + """ + Matrix of ones. + + Return a matrix of given shape and type, filled with ones. + + Parameters + ---------- + shape : {sequence of ints, int} + Shape of the matrix + dtype : data-type, optional + The desired data-type for the matrix, default is np.float64. + order : {'C', 'F'}, optional + Whether to store matrix in C- or Fortran-contiguous order, + default is 'C'. + + Returns + ------- + out : matrix + Matrix of ones of given shape, dtype, and order. + + See Also + -------- + ones : Array of ones. + matlib.zeros : Zero matrix. + + Notes + ----- + If `shape` has length one i.e. ``(N,)``, or is a scalar ``N``, + `out` becomes a single row matrix of shape ``(1,N)``. + + Examples + -------- + >>> np.matlib.ones((2,3)) + matrix([[ 1., 1., 1.], + [ 1., 1., 1.]]) + + >>> np.matlib.ones(2) + matrix([[ 1., 1.]]) + + """ + a = ndarray.__new__(matrix, shape, dtype, order=order) + a.fill(1) + return a + +def zeros(shape, dtype=None, order='C'): + """ + Return a matrix of given shape and type, filled with zeros. + + Parameters + ---------- + shape : int or sequence of ints + Shape of the matrix + dtype : data-type, optional + The desired data-type for the matrix, default is float. + order : {'C', 'F'}, optional + Whether to store the result in C- or Fortran-contiguous order, + default is 'C'. + + Returns + ------- + out : matrix + Zero matrix of given shape, dtype, and order. + + See Also + -------- + numpy.zeros : Equivalent array function. + matlib.ones : Return a matrix of ones. + + Notes + ----- + If `shape` has length one i.e. ``(N,)``, or is a scalar ``N``, + `out` becomes a single row matrix of shape ``(1,N)``. + + Examples + -------- + >>> import numpy.matlib + >>> np.matlib.zeros((2, 3)) + matrix([[ 0., 0., 0.], + [ 0., 0., 0.]]) + + >>> np.matlib.zeros(2) + matrix([[ 0., 0.]]) + + """ + a = ndarray.__new__(matrix, shape, dtype, order=order) + a.fill(0) + return a + +def identity(n,dtype=None): + """ + Returns the square identity matrix of given size. + + Parameters + ---------- + n : int + Size of the returned identity matrix. + dtype : data-type, optional + Data-type of the output. Defaults to ``float``. + + Returns + ------- + out : matrix + `n` x `n` matrix with its main diagonal set to one, + and all other elements zero. + + See Also + -------- + numpy.identity : Equivalent array function. + matlib.eye : More general matrix identity function. + + Examples + -------- + >>> import numpy.matlib + >>> np.matlib.identity(3, dtype=int) + matrix([[1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + + """ + a = array([1]+n*[0], dtype=dtype) + b = empty((n, n), dtype=dtype) + b.flat = a + return b + +def eye(n,M=None, k=0, dtype=float, order='C'): + """ + Return a matrix with ones on the diagonal and zeros elsewhere. + + Parameters + ---------- + n : int + Number of rows in the output. + M : int, optional + Number of columns in the output, defaults to `n`. + k : int, optional + Index of the diagonal: 0 refers to the main diagonal, + a positive value refers to an upper diagonal, + and a negative value to a lower diagonal. + dtype : dtype, optional + Data-type of the returned matrix. + order : {'C', 'F'}, optional + Whether the output should be stored in row-major (C-style) or + column-major (Fortran-style) order in memory. + + .. versionadded:: 1.14.0 + + Returns + ------- + I : matrix + A `n` x `M` matrix where all elements are equal to zero, + except for the `k`-th diagonal, whose values are equal to one. + + See Also + -------- + numpy.eye : Equivalent array function. + identity : Square identity matrix. + + Examples + -------- + >>> import numpy.matlib + >>> np.matlib.eye(3, k=1, dtype=float) + matrix([[ 0., 1., 0.], + [ 0., 0., 1.], + [ 0., 0., 0.]]) + + """ + return asmatrix(np.eye(n, M=M, k=k, dtype=dtype, order=order)) + +def rand(*args): + """ + Return a matrix of random values with given shape. + + Create a matrix of the given shape and propagate it with + random samples from a uniform distribution over ``[0, 1)``. + + Parameters + ---------- + \\*args : Arguments + Shape of the output. + If given as N integers, each integer specifies the size of one + dimension. + If given as a tuple, this tuple gives the complete shape. + + Returns + ------- + out : ndarray + The matrix of random values with shape given by `\\*args`. + + See Also + -------- + randn, numpy.random.rand + + Examples + -------- + >>> import numpy.matlib + >>> np.matlib.rand(2, 3) + matrix([[ 0.68340382, 0.67926887, 0.83271405], + [ 0.00793551, 0.20468222, 0.95253525]]) #random + >>> np.matlib.rand((2, 3)) + matrix([[ 0.84682055, 0.73626594, 0.11308016], + [ 0.85429008, 0.3294825 , 0.89139555]]) #random + + If the first argument is a tuple, other arguments are ignored: + + >>> np.matlib.rand((2, 3), 4) + matrix([[ 0.46898646, 0.15163588, 0.95188261], + [ 0.59208621, 0.09561818, 0.00583606]]) #random + + """ + if isinstance(args[0], tuple): + args = args[0] + return asmatrix(np.random.rand(*args)) + +def randn(*args): + """ + Return a random matrix with data from the "standard normal" distribution. + + `randn` generates a matrix filled with random floats sampled from a + univariate "normal" (Gaussian) distribution of mean 0 and variance 1. + + Parameters + ---------- + \\*args : Arguments + Shape of the output. + If given as N integers, each integer specifies the size of one + dimension. If given as a tuple, this tuple gives the complete shape. + + Returns + ------- + Z : matrix of floats + A matrix of floating-point samples drawn from the standard normal + distribution. + + See Also + -------- + rand, random.randn + + Notes + ----- + For random samples from :math:`N(\\mu, \\sigma^2)`, use: + + ``sigma * np.matlib.randn(...) + mu`` + + Examples + -------- + >>> import numpy.matlib + >>> np.matlib.randn(1) + matrix([[-0.09542833]]) #random + >>> np.matlib.randn(1, 2, 3) + matrix([[ 0.16198284, 0.0194571 , 0.18312985], + [-0.7509172 , 1.61055 , 0.45298599]]) #random + + Two-by-four matrix of samples from :math:`N(3, 6.25)`: + + >>> 2.5 * np.matlib.randn((2, 4)) + 3 + matrix([[ 4.74085004, 8.89381862, 4.09042411, 4.83721922], + [ 7.52373709, 5.07933944, -2.64043543, 0.45610557]]) #random + + """ + if isinstance(args[0], tuple): + args = args[0] + return asmatrix(np.random.randn(*args)) + +def repmat(a, m, n): + """ + Repeat a 0-D to 2-D array or matrix MxN times. + + Parameters + ---------- + a : array_like + The array or matrix to be repeated. + m, n : int + The number of times `a` is repeated along the first and second axes. + + Returns + ------- + out : ndarray + The result of repeating `a`. + + Examples + -------- + >>> import numpy.matlib + >>> a0 = np.array(1) + >>> np.matlib.repmat(a0, 2, 3) + array([[1, 1, 1], + [1, 1, 1]]) + + >>> a1 = np.arange(4) + >>> np.matlib.repmat(a1, 2, 2) + array([[0, 1, 2, 3, 0, 1, 2, 3], + [0, 1, 2, 3, 0, 1, 2, 3]]) + + >>> a2 = np.asmatrix(np.arange(6).reshape(2, 3)) + >>> np.matlib.repmat(a2, 2, 3) + matrix([[0, 1, 2, 0, 1, 2, 0, 1, 2], + [3, 4, 5, 3, 4, 5, 3, 4, 5], + [0, 1, 2, 0, 1, 2, 0, 1, 2], + [3, 4, 5, 3, 4, 5, 3, 4, 5]]) + + """ + a = asanyarray(a) + ndim = a.ndim + if ndim == 0: + origrows, origcols = (1, 1) + elif ndim == 1: + origrows, origcols = (1, a.shape[0]) + else: + origrows, origcols = a.shape + rows = origrows * m + cols = origcols * n + c = a.reshape(1, a.size).repeat(m, 0).reshape(rows, origcols).repeat(n, 0) + return c.reshape(rows, cols) diff --git a/numpy/matrixlib/__init__.py b/numpy/matrixlib/__init__.py new file mode 100644 index 0000000..11dce29 --- /dev/null +++ b/numpy/matrixlib/__init__.py @@ -0,0 +1,12 @@ +"""Sub-package containing the matrix class and related functions. + +""" +from __future__ import division, absolute_import, print_function + +from .defmatrix import * + +__all__ = defmatrix.__all__ + +from numpy.testing import _numpy_tester +test = _numpy_tester().test +bench = _numpy_tester().bench diff --git a/numpy/matrixlib/defmatrix.py b/numpy/matrixlib/defmatrix.py new file mode 100644 index 0000000..1f5c949 --- /dev/null +++ b/numpy/matrixlib/defmatrix.py @@ -0,0 +1,1197 @@ +from __future__ import division, absolute_import, print_function + +__all__ = ['matrix', 'bmat', 'mat', 'asmatrix'] + +import sys +import ast +import numpy.core.numeric as N +from numpy.core.numeric import concatenate, isscalar, binary_repr, identity, asanyarray +from numpy.core.numerictypes import issubdtype + +def _convert_from_string(data): + for char in '[]': + data = data.replace(char, '') + + rows = data.split(';') + newdata = [] + count = 0 + for row in rows: + trow = row.split(',') + newrow = [] + for col in trow: + temp = col.split() + newrow.extend(map(ast.literal_eval, temp)) + if count == 0: + Ncols = len(newrow) + elif len(newrow) != Ncols: + raise ValueError("Rows not the same size.") + count += 1 + newdata.append(newrow) + return newdata + +def asmatrix(data, dtype=None): + """ + Interpret the input as a matrix. + + Unlike `matrix`, `asmatrix` does not make a copy if the input is already + a matrix or an ndarray. Equivalent to ``matrix(data, copy=False)``. + + Parameters + ---------- + data : array_like + Input data. + dtype : data-type + Data-type of the output matrix. + + Returns + ------- + mat : matrix + `data` interpreted as a matrix. + + Examples + -------- + >>> x = np.array([[1, 2], [3, 4]]) + + >>> m = np.asmatrix(x) + + >>> x[0,0] = 5 + + >>> m + matrix([[5, 2], + [3, 4]]) + + """ + return matrix(data, dtype=dtype, copy=False) + +def matrix_power(M, n): + """ + Raise a square matrix to the (integer) power `n`. + + For positive integers `n`, the power is computed by repeated matrix + squarings and matrix multiplications. If ``n == 0``, the identity matrix + of the same shape as M is returned. If ``n < 0``, the inverse + is computed and then raised to the ``abs(n)``. + + Parameters + ---------- + M : ndarray or matrix object + Matrix to be "powered." Must be square, i.e. ``M.shape == (m, m)``, + with `m` a positive integer. + n : int + The exponent can be any integer or long integer, positive, + negative, or zero. + + Returns + ------- + M**n : ndarray or matrix object + The return value is the same shape and type as `M`; + if the exponent is positive or zero then the type of the + elements is the same as those of `M`. If the exponent is + negative the elements are floating-point. + + Raises + ------ + LinAlgError + If the matrix is not numerically invertible. + + See Also + -------- + matrix + Provides an equivalent function as the exponentiation operator + (``**``, not ``^``). + + Examples + -------- + >>> from numpy import linalg as LA + >>> i = np.array([[0, 1], [-1, 0]]) # matrix equiv. of the imaginary unit + >>> LA.matrix_power(i, 3) # should = -i + array([[ 0, -1], + [ 1, 0]]) + >>> LA.matrix_power(np.matrix(i), 3) # matrix arg returns matrix + matrix([[ 0, -1], + [ 1, 0]]) + >>> LA.matrix_power(i, 0) + array([[1, 0], + [0, 1]]) + >>> LA.matrix_power(i, -3) # should = 1/(-i) = i, but w/ f.p. elements + array([[ 0., 1.], + [-1., 0.]]) + + Somewhat more sophisticated example + + >>> q = np.zeros((4, 4)) + >>> q[0:2, 0:2] = -i + >>> q[2:4, 2:4] = i + >>> q # one of the three quaternion units not equal to 1 + array([[ 0., -1., 0., 0.], + [ 1., 0., 0., 0.], + [ 0., 0., 0., 1.], + [ 0., 0., -1., 0.]]) + >>> LA.matrix_power(q, 2) # = -np.eye(4) + array([[-1., 0., 0., 0.], + [ 0., -1., 0., 0.], + [ 0., 0., -1., 0.], + [ 0., 0., 0., -1.]]) + + """ + M = asanyarray(M) + if M.ndim != 2 or M.shape[0] != M.shape[1]: + raise ValueError("input must be a square array") + if not issubdtype(type(n), N.integer): + raise TypeError("exponent must be an integer") + + from numpy.linalg import inv + + if n==0: + M = M.copy() + M[:] = identity(M.shape[0]) + return M + elif n<0: + M = inv(M) + n *= -1 + + result = M + if n <= 3: + for _ in range(n-1): + result=N.dot(result, M) + return result + + # binary decomposition to reduce the number of Matrix + # multiplications for n > 3. + beta = binary_repr(n) + Z, q, t = M, 0, len(beta) + while beta[t-q-1] == '0': + Z = N.dot(Z, Z) + q += 1 + result = Z + for k in range(q+1, t): + Z = N.dot(Z, Z) + if beta[t-k-1] == '1': + result = N.dot(result, Z) + return result + + +class matrix(N.ndarray): + """ + matrix(data, dtype=None, copy=True) + + Returns a matrix from an array-like object, or from a string of data. + A matrix is a specialized 2-D array that retains its 2-D nature + through operations. It has certain special operators, such as ``*`` + (matrix multiplication) and ``**`` (matrix power). + + Parameters + ---------- + data : array_like or string + If `data` is a string, it is interpreted as a matrix with commas + or spaces separating columns, and semicolons separating rows. + dtype : data-type + Data-type of the output matrix. + copy : bool + If `data` is already an `ndarray`, then this flag determines + whether the data is copied (the default), or whether a view is + constructed. + + See Also + -------- + array + + Examples + -------- + >>> a = np.matrix('1 2; 3 4') + >>> print(a) + [[1 2] + [3 4]] + + >>> np.matrix([[1, 2], [3, 4]]) + matrix([[1, 2], + [3, 4]]) + + """ + __array_priority__ = 10.0 + def __new__(subtype, data, dtype=None, copy=True): + if isinstance(data, matrix): + dtype2 = data.dtype + if (dtype is None): + dtype = dtype2 + if (dtype2 == dtype) and (not copy): + return data + return data.astype(dtype) + + if isinstance(data, N.ndarray): + if dtype is None: + intype = data.dtype + else: + intype = N.dtype(dtype) + new = data.view(subtype) + if intype != data.dtype: + return new.astype(intype) + if copy: return new.copy() + else: return new + + if isinstance(data, str): + data = _convert_from_string(data) + + # now convert data to an array + arr = N.array(data, dtype=dtype, copy=copy) + ndim = arr.ndim + shape = arr.shape + if (ndim > 2): + raise ValueError("matrix must be 2-dimensional") + elif ndim == 0: + shape = (1, 1) + elif ndim == 1: + shape = (1, shape[0]) + + order = 'C' + if (ndim == 2) and arr.flags.fortran: + order = 'F' + + if not (order or arr.flags.contiguous): + arr = arr.copy() + + ret = N.ndarray.__new__(subtype, shape, arr.dtype, + buffer=arr, + order=order) + return ret + + def __array_finalize__(self, obj): + self._getitem = False + if (isinstance(obj, matrix) and obj._getitem): return + ndim = self.ndim + if (ndim == 2): + return + if (ndim > 2): + newshape = tuple([x for x in self.shape if x > 1]) + ndim = len(newshape) + if ndim == 2: + self.shape = newshape + return + elif (ndim > 2): + raise ValueError("shape too large to be a matrix.") + else: + newshape = self.shape + if ndim == 0: + self.shape = (1, 1) + elif ndim == 1: + self.shape = (1, newshape[0]) + return + + def __getitem__(self, index): + self._getitem = True + + try: + out = N.ndarray.__getitem__(self, index) + finally: + self._getitem = False + + if not isinstance(out, N.ndarray): + return out + + if out.ndim == 0: + return out[()] + if out.ndim == 1: + sh = out.shape[0] + # Determine when we should have a column array + try: + n = len(index) + except Exception: + n = 0 + if n > 1 and isscalar(index[1]): + out.shape = (sh, 1) + else: + out.shape = (1, sh) + return out + + def __mul__(self, other): + if isinstance(other, (N.ndarray, list, tuple)) : + # This promotes 1-D vectors to row vectors + return N.dot(self, asmatrix(other)) + if isscalar(other) or not hasattr(other, '__rmul__') : + return N.dot(self, other) + return NotImplemented + + def __rmul__(self, other): + return N.dot(other, self) + + def __imul__(self, other): + self[:] = self * other + return self + + def __pow__(self, other): + return matrix_power(self, other) + + def __ipow__(self, other): + self[:] = self ** other + return self + + def __rpow__(self, other): + return NotImplemented + + def _align(self, axis): + """A convenience function for operations that need to preserve axis + orientation. + """ + if axis is None: + return self[0, 0] + elif axis==0: + return self + elif axis==1: + return self.transpose() + else: + raise ValueError("unsupported axis") + + def _collapse(self, axis): + """A convenience function for operations that want to collapse + to a scalar like _align, but are using keepdims=True + """ + if axis is None: + return self[0, 0] + else: + return self + + # Necessary because base-class tolist expects dimension + # reduction by x[0] + def tolist(self): + """ + Return the matrix as a (possibly nested) list. + + See `ndarray.tolist` for full documentation. + + See Also + -------- + ndarray.tolist + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.tolist() + [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]] + + """ + return self.__array__().tolist() + + # To preserve orientation of result... + def sum(self, axis=None, dtype=None, out=None): + """ + Returns the sum of the matrix elements, along the given axis. + + Refer to `numpy.sum` for full documentation. + + See Also + -------- + numpy.sum + + Notes + ----- + This is the same as `ndarray.sum`, except that where an `ndarray` would + be returned, a `matrix` object is returned instead. + + Examples + -------- + >>> x = np.matrix([[1, 2], [4, 3]]) + >>> x.sum() + 10 + >>> x.sum(axis=1) + matrix([[3], + [7]]) + >>> x.sum(axis=1, dtype='float') + matrix([[ 3.], + [ 7.]]) + >>> out = np.zeros((1, 2), dtype='float') + >>> x.sum(axis=1, dtype='float', out=out) + matrix([[ 3.], + [ 7.]]) + + """ + return N.ndarray.sum(self, axis, dtype, out, keepdims=True)._collapse(axis) + + + # To update docstring from array to matrix... + def squeeze(self, axis=None): + """ + Return a possibly reshaped matrix. + + Refer to `numpy.squeeze` for more documentation. + + Parameters + ---------- + axis : None or int or tuple of ints, optional + Selects a subset of the single-dimensional entries in the shape. + If an axis is selected with shape entry greater than one, + an error is raised. + + Returns + ------- + squeezed : matrix + The matrix, but as a (1, N) matrix if it had shape (N, 1). + + See Also + -------- + numpy.squeeze : related function + + Notes + ----- + If `m` has a single column then that column is returned + as the single row of a matrix. Otherwise `m` is returned. + The returned matrix is always either `m` itself or a view into `m`. + Supplying an axis keyword argument will not affect the returned matrix + but it may cause an error to be raised. + + Examples + -------- + >>> c = np.matrix([[1], [2]]) + >>> c + matrix([[1], + [2]]) + >>> c.squeeze() + matrix([[1, 2]]) + >>> r = c.T + >>> r + matrix([[1, 2]]) + >>> r.squeeze() + matrix([[1, 2]]) + >>> m = np.matrix([[1, 2], [3, 4]]) + >>> m.squeeze() + matrix([[1, 2], + [3, 4]]) + + """ + return N.ndarray.squeeze(self, axis=axis) + + + # To update docstring from array to matrix... + def flatten(self, order='C'): + """ + Return a flattened copy of the matrix. + + All `N` elements of the matrix are placed into a single row. + + Parameters + ---------- + order : {'C', 'F', 'A', 'K'}, optional + 'C' means to flatten in row-major (C-style) order. 'F' means to + flatten in column-major (Fortran-style) order. 'A' means to + flatten in column-major order if `m` is Fortran *contiguous* in + memory, row-major order otherwise. 'K' means to flatten `m` in + the order the elements occur in memory. The default is 'C'. + + Returns + ------- + y : matrix + A copy of the matrix, flattened to a `(1, N)` matrix where `N` + is the number of elements in the original matrix. + + See Also + -------- + ravel : Return a flattened array. + flat : A 1-D flat iterator over the matrix. + + Examples + -------- + >>> m = np.matrix([[1,2], [3,4]]) + >>> m.flatten() + matrix([[1, 2, 3, 4]]) + >>> m.flatten('F') + matrix([[1, 3, 2, 4]]) + + """ + return N.ndarray.flatten(self, order=order) + + def mean(self, axis=None, dtype=None, out=None): + """ + Returns the average of the matrix elements along the given axis. + + Refer to `numpy.mean` for full documentation. + + See Also + -------- + numpy.mean + + Notes + ----- + Same as `ndarray.mean` except that, where that returns an `ndarray`, + this returns a `matrix` object. + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3, 4))) + >>> x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.mean() + 5.5 + >>> x.mean(0) + matrix([[ 4., 5., 6., 7.]]) + >>> x.mean(1) + matrix([[ 1.5], + [ 5.5], + [ 9.5]]) + + """ + return N.ndarray.mean(self, axis, dtype, out, keepdims=True)._collapse(axis) + + def std(self, axis=None, dtype=None, out=None, ddof=0): + """ + Return the standard deviation of the array elements along the given axis. + + Refer to `numpy.std` for full documentation. + + See Also + -------- + numpy.std + + Notes + ----- + This is the same as `ndarray.std`, except that where an `ndarray` would + be returned, a `matrix` object is returned instead. + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3, 4))) + >>> x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.std() + 3.4520525295346629 + >>> x.std(0) + matrix([[ 3.26598632, 3.26598632, 3.26598632, 3.26598632]]) + >>> x.std(1) + matrix([[ 1.11803399], + [ 1.11803399], + [ 1.11803399]]) + + """ + return N.ndarray.std(self, axis, dtype, out, ddof, keepdims=True)._collapse(axis) + + def var(self, axis=None, dtype=None, out=None, ddof=0): + """ + Returns the variance of the matrix elements, along the given axis. + + Refer to `numpy.var` for full documentation. + + See Also + -------- + numpy.var + + Notes + ----- + This is the same as `ndarray.var`, except that where an `ndarray` would + be returned, a `matrix` object is returned instead. + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3, 4))) + >>> x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.var() + 11.916666666666666 + >>> x.var(0) + matrix([[ 10.66666667, 10.66666667, 10.66666667, 10.66666667]]) + >>> x.var(1) + matrix([[ 1.25], + [ 1.25], + [ 1.25]]) + + """ + return N.ndarray.var(self, axis, dtype, out, ddof, keepdims=True)._collapse(axis) + + def prod(self, axis=None, dtype=None, out=None): + """ + Return the product of the array elements over the given axis. + + Refer to `prod` for full documentation. + + See Also + -------- + prod, ndarray.prod + + Notes + ----- + Same as `ndarray.prod`, except, where that returns an `ndarray`, this + returns a `matrix` object instead. + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.prod() + 0 + >>> x.prod(0) + matrix([[ 0, 45, 120, 231]]) + >>> x.prod(1) + matrix([[ 0], + [ 840], + [7920]]) + + """ + return N.ndarray.prod(self, axis, dtype, out, keepdims=True)._collapse(axis) + + def any(self, axis=None, out=None): + """ + Test whether any array element along a given axis evaluates to True. + + Refer to `numpy.any` for full documentation. + + Parameters + ---------- + axis : int, optional + Axis along which logical OR is performed + out : ndarray, optional + Output to existing array instead of creating new one, must have + same shape as expected output + + Returns + ------- + any : bool, ndarray + Returns a single bool if `axis` is ``None``; otherwise, + returns `ndarray` + + """ + return N.ndarray.any(self, axis, out, keepdims=True)._collapse(axis) + + def all(self, axis=None, out=None): + """ + Test whether all matrix elements along a given axis evaluate to True. + + Parameters + ---------- + See `numpy.all` for complete descriptions + + See Also + -------- + numpy.all + + Notes + ----- + This is the same as `ndarray.all`, but it returns a `matrix` object. + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> y = x[0]; y + matrix([[0, 1, 2, 3]]) + >>> (x == y) + matrix([[ True, True, True, True], + [False, False, False, False], + [False, False, False, False]]) + >>> (x == y).all() + False + >>> (x == y).all(0) + matrix([[False, False, False, False]]) + >>> (x == y).all(1) + matrix([[ True], + [False], + [False]]) + + """ + return N.ndarray.all(self, axis, out, keepdims=True)._collapse(axis) + + def max(self, axis=None, out=None): + """ + Return the maximum value along an axis. + + Parameters + ---------- + See `amax` for complete descriptions + + See Also + -------- + amax, ndarray.max + + Notes + ----- + This is the same as `ndarray.max`, but returns a `matrix` object + where `ndarray.max` would return an ndarray. + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.max() + 11 + >>> x.max(0) + matrix([[ 8, 9, 10, 11]]) + >>> x.max(1) + matrix([[ 3], + [ 7], + [11]]) + + """ + return N.ndarray.max(self, axis, out, keepdims=True)._collapse(axis) + + def argmax(self, axis=None, out=None): + """ + Indexes of the maximum values along an axis. + + Return the indexes of the first occurrences of the maximum values + along the specified axis. If axis is None, the index is for the + flattened matrix. + + Parameters + ---------- + See `numpy.argmax` for complete descriptions + + See Also + -------- + numpy.argmax + + Notes + ----- + This is the same as `ndarray.argmax`, but returns a `matrix` object + where `ndarray.argmax` would return an `ndarray`. + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.argmax() + 11 + >>> x.argmax(0) + matrix([[2, 2, 2, 2]]) + >>> x.argmax(1) + matrix([[3], + [3], + [3]]) + + """ + return N.ndarray.argmax(self, axis, out)._align(axis) + + def min(self, axis=None, out=None): + """ + Return the minimum value along an axis. + + Parameters + ---------- + See `amin` for complete descriptions. + + See Also + -------- + amin, ndarray.min + + Notes + ----- + This is the same as `ndarray.min`, but returns a `matrix` object + where `ndarray.min` would return an ndarray. + + Examples + -------- + >>> x = -np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, -1, -2, -3], + [ -4, -5, -6, -7], + [ -8, -9, -10, -11]]) + >>> x.min() + -11 + >>> x.min(0) + matrix([[ -8, -9, -10, -11]]) + >>> x.min(1) + matrix([[ -3], + [ -7], + [-11]]) + + """ + return N.ndarray.min(self, axis, out, keepdims=True)._collapse(axis) + + def argmin(self, axis=None, out=None): + """ + Indexes of the minimum values along an axis. + + Return the indexes of the first occurrences of the minimum values + along the specified axis. If axis is None, the index is for the + flattened matrix. + + Parameters + ---------- + See `numpy.argmin` for complete descriptions. + + See Also + -------- + numpy.argmin + + Notes + ----- + This is the same as `ndarray.argmin`, but returns a `matrix` object + where `ndarray.argmin` would return an `ndarray`. + + Examples + -------- + >>> x = -np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, -1, -2, -3], + [ -4, -5, -6, -7], + [ -8, -9, -10, -11]]) + >>> x.argmin() + 11 + >>> x.argmin(0) + matrix([[2, 2, 2, 2]]) + >>> x.argmin(1) + matrix([[3], + [3], + [3]]) + + """ + return N.ndarray.argmin(self, axis, out)._align(axis) + + def ptp(self, axis=None, out=None): + """ + Peak-to-peak (maximum - minimum) value along the given axis. + + Refer to `numpy.ptp` for full documentation. + + See Also + -------- + numpy.ptp + + Notes + ----- + Same as `ndarray.ptp`, except, where that would return an `ndarray` object, + this returns a `matrix` object. + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.ptp() + 11 + >>> x.ptp(0) + matrix([[8, 8, 8, 8]]) + >>> x.ptp(1) + matrix([[3], + [3], + [3]]) + + """ + return N.ndarray.ptp(self, axis, out)._align(axis) + + def getI(self): + """ + Returns the (multiplicative) inverse of invertible `self`. + + Parameters + ---------- + None + + Returns + ------- + ret : matrix object + If `self` is non-singular, `ret` is such that ``ret * self`` == + ``self * ret`` == ``np.matrix(np.eye(self[0,:].size)`` all return + ``True``. + + Raises + ------ + numpy.linalg.LinAlgError: Singular matrix + If `self` is singular. + + See Also + -------- + linalg.inv + + Examples + -------- + >>> m = np.matrix('[1, 2; 3, 4]'); m + matrix([[1, 2], + [3, 4]]) + >>> m.getI() + matrix([[-2. , 1. ], + [ 1.5, -0.5]]) + >>> m.getI() * m + matrix([[ 1., 0.], + [ 0., 1.]]) + + """ + M, N = self.shape + if M == N: + from numpy.dual import inv as func + else: + from numpy.dual import pinv as func + return asmatrix(func(self)) + + def getA(self): + """ + Return `self` as an `ndarray` object. + + Equivalent to ``np.asarray(self)``. + + Parameters + ---------- + None + + Returns + ------- + ret : ndarray + `self` as an `ndarray` + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.getA() + array([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + + """ + return self.__array__() + + def getA1(self): + """ + Return `self` as a flattened `ndarray`. + + Equivalent to ``np.asarray(x).ravel()`` + + Parameters + ---------- + None + + Returns + ------- + ret : ndarray + `self`, 1-D, as an `ndarray` + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))); x + matrix([[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]) + >>> x.getA1() + array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) + + """ + return self.__array__().ravel() + + + def ravel(self, order='C'): + """ + Return a flattened matrix. + + Refer to `numpy.ravel` for more documentation. + + Parameters + ---------- + order : {'C', 'F', 'A', 'K'}, optional + The elements of `m` are read using this index order. 'C' means to + index the elements in C-like order, with the last axis index + changing fastest, back to the first axis index changing slowest. + 'F' means to index the elements in Fortran-like index order, with + the first index changing fastest, and the last index changing + slowest. Note that the 'C' and 'F' options take no account of the + memory layout of the underlying array, and only refer to the order + of axis indexing. 'A' means to read the elements in Fortran-like + index order if `m` is Fortran *contiguous* in memory, C-like order + otherwise. 'K' means to read the elements in the order they occur + in memory, except for reversing the data when strides are negative. + By default, 'C' index order is used. + + Returns + ------- + ret : matrix + Return the matrix flattened to shape `(1, N)` where `N` + is the number of elements in the original matrix. + A copy is made only if necessary. + + See Also + -------- + matrix.flatten : returns a similar output matrix but always a copy + matrix.flat : a flat iterator on the array. + numpy.ravel : related function which returns an ndarray + + """ + return N.ndarray.ravel(self, order=order) + + + def getT(self): + """ + Returns the transpose of the matrix. + + Does *not* conjugate! For the complex conjugate transpose, use ``.H``. + + Parameters + ---------- + None + + Returns + ------- + ret : matrix object + The (non-conjugated) transpose of the matrix. + + See Also + -------- + transpose, getH + + Examples + -------- + >>> m = np.matrix('[1, 2; 3, 4]') + >>> m + matrix([[1, 2], + [3, 4]]) + >>> m.getT() + matrix([[1, 3], + [2, 4]]) + + """ + return self.transpose() + + def getH(self): + """ + Returns the (complex) conjugate transpose of `self`. + + Equivalent to ``np.transpose(self)`` if `self` is real-valued. + + Parameters + ---------- + None + + Returns + ------- + ret : matrix object + complex conjugate transpose of `self` + + Examples + -------- + >>> x = np.matrix(np.arange(12).reshape((3,4))) + >>> z = x - 1j*x; z + matrix([[ 0. +0.j, 1. -1.j, 2. -2.j, 3. -3.j], + [ 4. -4.j, 5. -5.j, 6. -6.j, 7. -7.j], + [ 8. -8.j, 9. -9.j, 10.-10.j, 11.-11.j]]) + >>> z.getH() + matrix([[ 0. +0.j, 4. +4.j, 8. +8.j], + [ 1. +1.j, 5. +5.j, 9. +9.j], + [ 2. +2.j, 6. +6.j, 10.+10.j], + [ 3. +3.j, 7. +7.j, 11.+11.j]]) + + """ + if issubclass(self.dtype.type, N.complexfloating): + return self.transpose().conjugate() + else: + return self.transpose() + + T = property(getT, None) + A = property(getA, None) + A1 = property(getA1, None) + H = property(getH, None) + I = property(getI, None) + +def _from_string(str, gdict, ldict): + rows = str.split(';') + rowtup = [] + for row in rows: + trow = row.split(',') + newrow = [] + for x in trow: + newrow.extend(x.split()) + trow = newrow + coltup = [] + for col in trow: + col = col.strip() + try: + thismat = ldict[col] + except KeyError: + try: + thismat = gdict[col] + except KeyError: + raise KeyError("%s not found" % (col,)) + + coltup.append(thismat) + rowtup.append(concatenate(coltup, axis=-1)) + return concatenate(rowtup, axis=0) + + +def bmat(obj, ldict=None, gdict=None): + """ + Build a matrix object from a string, nested sequence, or array. + + Parameters + ---------- + obj : str or array_like + Input data. If a string, variables in the current scope may be + referenced by name. + ldict : dict, optional + A dictionary that replaces local operands in current frame. + Ignored if `obj` is not a string or `gdict` is `None`. + gdict : dict, optional + A dictionary that replaces global operands in current frame. + Ignored if `obj` is not a string. + + Returns + ------- + out : matrix + Returns a matrix object, which is a specialized 2-D array. + + See Also + -------- + block : + A generalization of this function for N-d arrays, that returns normal + ndarrays. + + Examples + -------- + >>> A = np.mat('1 1; 1 1') + >>> B = np.mat('2 2; 2 2') + >>> C = np.mat('3 4; 5 6') + >>> D = np.mat('7 8; 9 0') + + All the following expressions construct the same block matrix: + + >>> np.bmat([[A, B], [C, D]]) + matrix([[1, 1, 2, 2], + [1, 1, 2, 2], + [3, 4, 7, 8], + [5, 6, 9, 0]]) + >>> np.bmat(np.r_[np.c_[A, B], np.c_[C, D]]) + matrix([[1, 1, 2, 2], + [1, 1, 2, 2], + [3, 4, 7, 8], + [5, 6, 9, 0]]) + >>> np.bmat('A,B; C,D') + matrix([[1, 1, 2, 2], + [1, 1, 2, 2], + [3, 4, 7, 8], + [5, 6, 9, 0]]) + + """ + if isinstance(obj, str): + if gdict is None: + # get previous frame + frame = sys._getframe().f_back + glob_dict = frame.f_globals + loc_dict = frame.f_locals + else: + glob_dict = gdict + loc_dict = ldict + + return matrix(_from_string(obj, glob_dict, loc_dict)) + + if isinstance(obj, (tuple, list)): + # [[A,B],[C,D]] + arr_rows = [] + for row in obj: + if isinstance(row, N.ndarray): # not 2-d + return matrix(concatenate(obj, axis=-1)) + else: + arr_rows.append(concatenate(row, axis=-1)) + return matrix(concatenate(arr_rows, axis=0)) + if isinstance(obj, N.ndarray): + return matrix(obj) + +mat = asmatrix diff --git a/numpy/matrixlib/setup.py b/numpy/matrixlib/setup.py new file mode 100644 index 0000000..8c383ce --- /dev/null +++ b/numpy/matrixlib/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +from __future__ import division, print_function + +import os + +def configuration(parent_package='', top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('matrixlib', parent_package, top_path) + config.add_data_dir('tests') + return config + +if __name__ == "__main__": + from numpy.distutils.core import setup + config = configuration(top_path='').todict() + setup(**config) diff --git a/numpy/matrixlib/tests/__init__.py b/numpy/matrixlib/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/matrixlib/tests/__init__.py diff --git a/numpy/matrixlib/tests/test_defmatrix.py b/numpy/matrixlib/tests/test_defmatrix.py new file mode 100644 index 0000000..77f2620 --- /dev/null +++ b/numpy/matrixlib/tests/test_defmatrix.py @@ -0,0 +1,459 @@ +from __future__ import division, absolute_import, print_function + +import collections + +import numpy as np +from numpy import matrix, asmatrix, bmat +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_almost_equal, + assert_array_equal, assert_array_almost_equal, assert_raises +) +from numpy.matrixlib.defmatrix import matrix_power +from numpy.matrixlib import mat + +class TestCtor(object): + def test_basic(self): + A = np.array([[1, 2], [3, 4]]) + mA = matrix(A) + assert_(np.all(mA.A == A)) + + B = bmat("A,A;A,A") + C = bmat([[A, A], [A, A]]) + D = np.array([[1, 2, 1, 2], + [3, 4, 3, 4], + [1, 2, 1, 2], + [3, 4, 3, 4]]) + assert_(np.all(B.A == D)) + assert_(np.all(C.A == D)) + + E = np.array([[5, 6], [7, 8]]) + AEresult = matrix([[1, 2, 5, 6], [3, 4, 7, 8]]) + assert_(np.all(bmat([A, E]) == AEresult)) + + vec = np.arange(5) + mvec = matrix(vec) + assert_(mvec.shape == (1, 5)) + + def test_exceptions(self): + # Check for ValueError when called with invalid string data. + assert_raises(ValueError, matrix, "invalid") + + def test_bmat_nondefault_str(self): + A = np.array([[1, 2], [3, 4]]) + B = np.array([[5, 6], [7, 8]]) + Aresult = np.array([[1, 2, 1, 2], + [3, 4, 3, 4], + [1, 2, 1, 2], + [3, 4, 3, 4]]) + mixresult = np.array([[1, 2, 5, 6], + [3, 4, 7, 8], + [5, 6, 1, 2], + [7, 8, 3, 4]]) + assert_(np.all(bmat("A,A;A,A") == Aresult)) + assert_(np.all(bmat("A,A;A,A", ldict={'A':B}) == Aresult)) + assert_raises(TypeError, bmat, "A,A;A,A", gdict={'A':B}) + assert_( + np.all(bmat("A,A;A,A", ldict={'A':A}, gdict={'A':B}) == Aresult)) + b2 = bmat("A,B;C,D", ldict={'A':A,'B':B}, gdict={'C':B,'D':A}) + assert_(np.all(b2 == mixresult)) + + +class TestProperties(object): + def test_sum(self): + """Test whether matrix.sum(axis=1) preserves orientation. + Fails in NumPy <= 0.9.6.2127. + """ + M = matrix([[1, 2, 0, 0], + [3, 4, 0, 0], + [1, 2, 1, 2], + [3, 4, 3, 4]]) + sum0 = matrix([8, 12, 4, 6]) + sum1 = matrix([3, 7, 6, 14]).T + sumall = 30 + assert_array_equal(sum0, M.sum(axis=0)) + assert_array_equal(sum1, M.sum(axis=1)) + assert_equal(sumall, M.sum()) + + assert_array_equal(sum0, np.sum(M, axis=0)) + assert_array_equal(sum1, np.sum(M, axis=1)) + assert_equal(sumall, np.sum(M)) + + def test_prod(self): + x = matrix([[1, 2, 3], [4, 5, 6]]) + assert_equal(x.prod(), 720) + assert_equal(x.prod(0), matrix([[4, 10, 18]])) + assert_equal(x.prod(1), matrix([[6], [120]])) + + assert_equal(np.prod(x), 720) + assert_equal(np.prod(x, axis=0), matrix([[4, 10, 18]])) + assert_equal(np.prod(x, axis=1), matrix([[6], [120]])) + + y = matrix([0, 1, 3]) + assert_(y.prod() == 0) + + def test_max(self): + x = matrix([[1, 2, 3], [4, 5, 6]]) + assert_equal(x.max(), 6) + assert_equal(x.max(0), matrix([[4, 5, 6]])) + assert_equal(x.max(1), matrix([[3], [6]])) + + assert_equal(np.max(x), 6) + assert_equal(np.max(x, axis=0), matrix([[4, 5, 6]])) + assert_equal(np.max(x, axis=1), matrix([[3], [6]])) + + def test_min(self): + x = matrix([[1, 2, 3], [4, 5, 6]]) + assert_equal(x.min(), 1) + assert_equal(x.min(0), matrix([[1, 2, 3]])) + assert_equal(x.min(1), matrix([[1], [4]])) + + assert_equal(np.min(x), 1) + assert_equal(np.min(x, axis=0), matrix([[1, 2, 3]])) + assert_equal(np.min(x, axis=1), matrix([[1], [4]])) + + def test_ptp(self): + x = np.arange(4).reshape((2, 2)) + assert_(x.ptp() == 3) + assert_(np.all(x.ptp(0) == np.array([2, 2]))) + assert_(np.all(x.ptp(1) == np.array([1, 1]))) + + def test_var(self): + x = np.arange(9).reshape((3, 3)) + mx = x.view(np.matrix) + assert_equal(x.var(ddof=0), mx.var(ddof=0)) + assert_equal(x.var(ddof=1), mx.var(ddof=1)) + + def test_basic(self): + import numpy.linalg as linalg + + A = np.array([[1., 2.], + [3., 4.]]) + mA = matrix(A) + assert_(np.allclose(linalg.inv(A), mA.I)) + assert_(np.all(np.array(np.transpose(A) == mA.T))) + assert_(np.all(np.array(np.transpose(A) == mA.H))) + assert_(np.all(A == mA.A)) + + B = A + 2j*A + mB = matrix(B) + assert_(np.allclose(linalg.inv(B), mB.I)) + assert_(np.all(np.array(np.transpose(B) == mB.T))) + assert_(np.all(np.array(np.transpose(B).conj() == mB.H))) + + def test_pinv(self): + x = matrix(np.arange(6).reshape(2, 3)) + xpinv = matrix([[-0.77777778, 0.27777778], + [-0.11111111, 0.11111111], + [ 0.55555556, -0.05555556]]) + assert_almost_equal(x.I, xpinv) + + def test_comparisons(self): + A = np.arange(100).reshape(10, 10) + mA = matrix(A) + mB = matrix(A) + 0.1 + assert_(np.all(mB == A+0.1)) + assert_(np.all(mB == matrix(A+0.1))) + assert_(not np.any(mB == matrix(A-0.1))) + assert_(np.all(mA < mB)) + assert_(np.all(mA <= mB)) + assert_(np.all(mA <= mA)) + assert_(not np.any(mA < mA)) + + assert_(not np.any(mB < mA)) + assert_(np.all(mB >= mA)) + assert_(np.all(mB >= mB)) + assert_(not np.any(mB > mB)) + + assert_(np.all(mA == mA)) + assert_(not np.any(mA == mB)) + assert_(np.all(mB != mA)) + + assert_(not np.all(abs(mA) > 0)) + assert_(np.all(abs(mB > 0))) + + def test_asmatrix(self): + A = np.arange(100).reshape(10, 10) + mA = asmatrix(A) + A[0, 0] = -10 + assert_(A[0, 0] == mA[0, 0]) + + def test_noaxis(self): + A = matrix([[1, 0], [0, 1]]) + assert_(A.sum() == matrix(2)) + assert_(A.mean() == matrix(0.5)) + + def test_repr(self): + A = matrix([[1, 0], [0, 1]]) + assert_(repr(A) == "matrix([[1, 0],\n [0, 1]])") + + def test_make_bool_matrix_from_str(self): + A = matrix('True; True; False') + B = matrix([[True], [True], [False]]) + assert_array_equal(A, B) + +class TestCasting(object): + def test_basic(self): + A = np.arange(100).reshape(10, 10) + mA = matrix(A) + + mB = mA.copy() + O = np.ones((10, 10), np.float64) * 0.1 + mB = mB + O + assert_(mB.dtype.type == np.float64) + assert_(np.all(mA != mB)) + assert_(np.all(mB == mA+0.1)) + + mC = mA.copy() + O = np.ones((10, 10), np.complex128) + mC = mC * O + assert_(mC.dtype.type == np.complex128) + assert_(np.all(mA != mB)) + + +class TestAlgebra(object): + def test_basic(self): + import numpy.linalg as linalg + + A = np.array([[1., 2.], [3., 4.]]) + mA = matrix(A) + + B = np.identity(2) + for i in range(6): + assert_(np.allclose((mA ** i).A, B)) + B = np.dot(B, A) + + Ainv = linalg.inv(A) + B = np.identity(2) + for i in range(6): + assert_(np.allclose((mA ** -i).A, B)) + B = np.dot(B, Ainv) + + assert_(np.allclose((mA * mA).A, np.dot(A, A))) + assert_(np.allclose((mA + mA).A, (A + A))) + assert_(np.allclose((3*mA).A, (3*A))) + + mA2 = matrix(A) + mA2 *= 3 + assert_(np.allclose(mA2.A, 3*A)) + + def test_pow(self): + """Test raising a matrix to an integer power works as expected.""" + m = matrix("1. 2.; 3. 4.") + m2 = m.copy() + m2 **= 2 + mi = m.copy() + mi **= -1 + m4 = m2.copy() + m4 **= 2 + assert_array_almost_equal(m2, m**2) + assert_array_almost_equal(m4, np.dot(m2, m2)) + assert_array_almost_equal(np.dot(mi, m), np.eye(2)) + + def test_scalar_type_pow(self): + m = matrix([[1, 2], [3, 4]]) + for scalar_t in [np.int8, np.uint8]: + two = scalar_t(2) + assert_array_almost_equal(m ** 2, m ** two) + + def test_notimplemented(self): + '''Check that 'not implemented' operations produce a failure.''' + A = matrix([[1., 2.], + [3., 4.]]) + + # __rpow__ + try: + 1.0**A + except TypeError: + pass + else: + self.fail("matrix.__rpow__ doesn't raise a TypeError") + + # __mul__ with something not a list, ndarray, tuple, or scalar + try: + A*object() + except TypeError: + pass + else: + self.fail("matrix.__mul__ with non-numeric object doesn't raise" + "a TypeError") + +class TestMatrixReturn(object): + def test_instance_methods(self): + a = matrix([1.0], dtype='f8') + methodargs = { + 'astype': ('intc',), + 'clip': (0.0, 1.0), + 'compress': ([1],), + 'repeat': (1,), + 'reshape': (1,), + 'swapaxes': (0, 0), + 'dot': np.array([1.0]), + } + excluded_methods = [ + 'argmin', 'choose', 'dump', 'dumps', 'fill', 'getfield', + 'getA', 'getA1', 'item', 'nonzero', 'put', 'putmask', 'resize', + 'searchsorted', 'setflags', 'setfield', 'sort', + 'partition', 'argpartition', + 'take', 'tofile', 'tolist', 'tostring', 'tobytes', 'all', 'any', + 'sum', 'argmax', 'argmin', 'min', 'max', 'mean', 'var', 'ptp', + 'prod', 'std', 'ctypes', 'itemset', + ] + for attrib in dir(a): + if attrib.startswith('_') or attrib in excluded_methods: + continue + f = getattr(a, attrib) + if isinstance(f, collections.Callable): + # reset contents of a + a.astype('f8') + a.fill(1.0) + if attrib in methodargs: + args = methodargs[attrib] + else: + args = () + b = f(*args) + assert_(type(b) is matrix, "%s" % attrib) + assert_(type(a.real) is matrix) + assert_(type(a.imag) is matrix) + c, d = matrix([0.0]).nonzero() + assert_(type(c) is np.ndarray) + assert_(type(d) is np.ndarray) + + +class TestIndexing(object): + def test_basic(self): + x = asmatrix(np.zeros((3, 2), float)) + y = np.zeros((3, 1), float) + y[:, 0] = [0.8, 0.2, 0.3] + x[:, 1] = y > 0.5 + assert_equal(x, [[0, 1], [0, 0], [0, 0]]) + + +class TestNewScalarIndexing(object): + a = matrix([[1, 2], [3, 4]]) + + def test_dimesions(self): + a = self.a + x = a[0] + assert_equal(x.ndim, 2) + + def test_array_from_matrix_list(self): + a = self.a + x = np.array([a, a]) + assert_equal(x.shape, [2, 2, 2]) + + def test_array_to_list(self): + a = self.a + assert_equal(a.tolist(), [[1, 2], [3, 4]]) + + def test_fancy_indexing(self): + a = self.a + x = a[1, [0, 1, 0]] + assert_(isinstance(x, matrix)) + assert_equal(x, matrix([[3, 4, 3]])) + x = a[[1, 0]] + assert_(isinstance(x, matrix)) + assert_equal(x, matrix([[3, 4], [1, 2]])) + x = a[[[1], [0]], [[1, 0], [0, 1]]] + assert_(isinstance(x, matrix)) + assert_equal(x, matrix([[4, 3], [1, 2]])) + + def test_matrix_element(self): + x = matrix([[1, 2, 3], [4, 5, 6]]) + assert_equal(x[0][0], matrix([[1, 2, 3]])) + assert_equal(x[0][0].shape, (1, 3)) + assert_equal(x[0].shape, (1, 3)) + assert_equal(x[:, 0].shape, (2, 1)) + + x = matrix(0) + assert_equal(x[0, 0], 0) + assert_equal(x[0], 0) + assert_equal(x[:, 0].shape, x.shape) + + def test_scalar_indexing(self): + x = asmatrix(np.zeros((3, 2), float)) + assert_equal(x[0, 0], x[0][0]) + + def test_row_column_indexing(self): + x = asmatrix(np.eye(2)) + assert_array_equal(x[0,:], [[1, 0]]) + assert_array_equal(x[1,:], [[0, 1]]) + assert_array_equal(x[:, 0], [[1], [0]]) + assert_array_equal(x[:, 1], [[0], [1]]) + + def test_boolean_indexing(self): + A = np.arange(6) + A.shape = (3, 2) + x = asmatrix(A) + assert_array_equal(x[:, np.array([True, False])], x[:, 0]) + assert_array_equal(x[np.array([True, False, False]),:], x[0,:]) + + def test_list_indexing(self): + A = np.arange(6) + A.shape = (3, 2) + x = asmatrix(A) + assert_array_equal(x[:, [1, 0]], x[:, ::-1]) + assert_array_equal(x[[2, 1, 0],:], x[::-1,:]) + + +class TestPower(object): + def test_returntype(self): + a = np.array([[0, 1], [0, 0]]) + assert_(type(matrix_power(a, 2)) is np.ndarray) + a = mat(a) + assert_(type(matrix_power(a, 2)) is matrix) + + def test_list(self): + assert_array_equal(matrix_power([[0, 1], [0, 0]], 2), [[0, 0], [0, 0]]) + + +class TestShape(object): + + a = np.array([[1], [2]]) + m = matrix([[1], [2]]) + + def test_shape(self): + assert_equal(self.a.shape, (2, 1)) + assert_equal(self.m.shape, (2, 1)) + + def test_numpy_ravel(self): + assert_equal(np.ravel(self.a).shape, (2,)) + assert_equal(np.ravel(self.m).shape, (2,)) + + def test_member_ravel(self): + assert_equal(self.a.ravel().shape, (2,)) + assert_equal(self.m.ravel().shape, (1, 2)) + + def test_member_flatten(self): + assert_equal(self.a.flatten().shape, (2,)) + assert_equal(self.m.flatten().shape, (1, 2)) + + def test_numpy_ravel_order(self): + x = np.array([[1, 2, 3], [4, 5, 6]]) + assert_equal(np.ravel(x), [1, 2, 3, 4, 5, 6]) + assert_equal(np.ravel(x, order='F'), [1, 4, 2, 5, 3, 6]) + assert_equal(np.ravel(x.T), [1, 4, 2, 5, 3, 6]) + assert_equal(np.ravel(x.T, order='A'), [1, 2, 3, 4, 5, 6]) + x = matrix([[1, 2, 3], [4, 5, 6]]) + assert_equal(np.ravel(x), [1, 2, 3, 4, 5, 6]) + assert_equal(np.ravel(x, order='F'), [1, 4, 2, 5, 3, 6]) + assert_equal(np.ravel(x.T), [1, 4, 2, 5, 3, 6]) + assert_equal(np.ravel(x.T, order='A'), [1, 2, 3, 4, 5, 6]) + + def test_matrix_ravel_order(self): + x = matrix([[1, 2, 3], [4, 5, 6]]) + assert_equal(x.ravel(), [[1, 2, 3, 4, 5, 6]]) + assert_equal(x.ravel(order='F'), [[1, 4, 2, 5, 3, 6]]) + assert_equal(x.T.ravel(), [[1, 4, 2, 5, 3, 6]]) + assert_equal(x.T.ravel(order='A'), [[1, 2, 3, 4, 5, 6]]) + + def test_array_memory_sharing(self): + assert_(np.may_share_memory(self.a, self.a.ravel())) + assert_(not np.may_share_memory(self.a, self.a.flatten())) + + def test_matrix_memory_sharing(self): + assert_(np.may_share_memory(self.m, self.m.ravel())) + assert_(not np.may_share_memory(self.m, self.m.flatten())) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/matrixlib/tests/test_multiarray.py b/numpy/matrixlib/tests/test_multiarray.py new file mode 100644 index 0000000..bf891a1 --- /dev/null +++ b/numpy/matrixlib/tests/test_multiarray.py @@ -0,0 +1,23 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_equal, assert_array_equal +) + +class TestView(object): + def test_type(self): + x = np.array([1, 2, 3]) + assert_(isinstance(x.view(np.matrix), np.matrix)) + + def test_keywords(self): + x = np.array([(1, 2)], dtype=[('a', np.int8), ('b', np.int8)]) + # We must be specific about the endianness here: + y = x.view(dtype='= 2.6. + +""" +from __future__ import division, absolute_import, print_function + +from abc import ABCMeta, abstractmethod, abstractproperty +from numbers import Number + +import numpy as np +from . import polyutils as pu + +__all__ = ['ABCPolyBase'] + +class ABCPolyBase(object): + """An abstract base class for series classes. + + ABCPolyBase provides the standard Python numerical methods + '+', '-', '*', '//', '%', 'divmod', '**', and '()' along with the + methods listed below. + + .. versionadded:: 1.9.0 + + Parameters + ---------- + coef : array_like + Series coefficients in order of increasing degree, i.e., + ``(1, 2, 3)`` gives ``1*P_0(x) + 2*P_1(x) + 3*P_2(x)``, where + ``P_i`` is the basis polynomials of degree ``i``. + domain : (2,) array_like, optional + Domain to use. The interval ``[domain[0], domain[1]]`` is mapped + to the interval ``[window[0], window[1]]`` by shifting and scaling. + The default value is the derived class domain. + window : (2,) array_like, optional + Window, see domain for its use. The default value is the + derived class window. + + Attributes + ---------- + coef : (N,) ndarray + Series coefficients in order of increasing degree. + domain : (2,) ndarray + Domain that is mapped to window. + window : (2,) ndarray + Window that domain is mapped to. + + Class Attributes + ---------------- + maxpower : int + Maximum power allowed, i.e., the largest number ``n`` such that + ``p(x)**n`` is allowed. This is to limit runaway polynomial size. + domain : (2,) ndarray + Default domain of the class. + window : (2,) ndarray + Default window of the class. + + """ + __metaclass__ = ABCMeta + + # Not hashable + __hash__ = None + + # Opt out of numpy ufuncs and Python ops with ndarray subclasses. + __array_ufunc__ = None + + # Limit runaway size. T_n^m has degree n*m + maxpower = 100 + + @abstractproperty + def domain(self): + pass + + @abstractproperty + def window(self): + pass + + @abstractproperty + def nickname(self): + pass + + @abstractmethod + def _add(self): + pass + + @abstractmethod + def _sub(self): + pass + + @abstractmethod + def _mul(self): + pass + + @abstractmethod + def _div(self): + pass + + @abstractmethod + def _pow(self): + pass + + @abstractmethod + def _val(self): + pass + + @abstractmethod + def _int(self): + pass + + @abstractmethod + def _der(self): + pass + + @abstractmethod + def _fit(self): + pass + + @abstractmethod + def _line(self): + pass + + @abstractmethod + def _roots(self): + pass + + @abstractmethod + def _fromroots(self): + pass + + def has_samecoef(self, other): + """Check if coefficients match. + + .. versionadded:: 1.6.0 + + Parameters + ---------- + other : class instance + The other class must have the ``coef`` attribute. + + Returns + ------- + bool : boolean + True if the coefficients are the same, False otherwise. + + """ + if len(self.coef) != len(other.coef): + return False + elif not np.all(self.coef == other.coef): + return False + else: + return True + + def has_samedomain(self, other): + """Check if domains match. + + .. versionadded:: 1.6.0 + + Parameters + ---------- + other : class instance + The other class must have the ``domain`` attribute. + + Returns + ------- + bool : boolean + True if the domains are the same, False otherwise. + + """ + return np.all(self.domain == other.domain) + + def has_samewindow(self, other): + """Check if windows match. + + .. versionadded:: 1.6.0 + + Parameters + ---------- + other : class instance + The other class must have the ``window`` attribute. + + Returns + ------- + bool : boolean + True if the windows are the same, False otherwise. + + """ + return np.all(self.window == other.window) + + def has_sametype(self, other): + """Check if types match. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + other : object + Class instance. + + Returns + ------- + bool : boolean + True if other is same class as self + + """ + return isinstance(other, self.__class__) + + def _get_coefficients(self, other): + """Interpret other as polynomial coefficients. + + The `other` argument is checked to see if it is of the same + class as self with identical domain and window. If so, + return its coefficients, otherwise return `other`. + + .. versionadded:: 1.9.0 + + Parameters + ---------- + other : anything + Object to be checked. + + Returns + ------- + coef + The coefficients of`other` if it is a compatible instance, + of ABCPolyBase, otherwise `other`. + + Raises + ------ + TypeError + When `other` is an incompatible instance of ABCPolyBase. + + """ + if isinstance(other, ABCPolyBase): + if not isinstance(other, self.__class__): + raise TypeError("Polynomial types differ") + elif not np.all(self.domain == other.domain): + raise TypeError("Domains differ") + elif not np.all(self.window == other.window): + raise TypeError("Windows differ") + return other.coef + return other + + def __init__(self, coef, domain=None, window=None): + [coef] = pu.as_series([coef], trim=False) + self.coef = coef + + if domain is not None: + [domain] = pu.as_series([domain], trim=False) + if len(domain) != 2: + raise ValueError("Domain has wrong number of elements.") + self.domain = domain + + if window is not None: + [window] = pu.as_series([window], trim=False) + if len(window) != 2: + raise ValueError("Window has wrong number of elements.") + self.window = window + + def __repr__(self): + format = "%s(%s, domain=%s, window=%s)" + coef = repr(self.coef)[6:-1] + domain = repr(self.domain)[6:-1] + window = repr(self.window)[6:-1] + name = self.__class__.__name__ + return format % (name, coef, domain, window) + + def __str__(self): + format = "%s(%s)" + coef = str(self.coef) + name = self.nickname + return format % (name, coef) + + # Pickle and copy + + def __getstate__(self): + ret = self.__dict__.copy() + ret['coef'] = self.coef.copy() + ret['domain'] = self.domain.copy() + ret['window'] = self.window.copy() + return ret + + def __setstate__(self, dict): + self.__dict__ = dict + + # Call + + def __call__(self, arg): + off, scl = pu.mapparms(self.domain, self.window) + arg = off + scl*arg + return self._val(arg, self.coef) + + def __iter__(self): + return iter(self.coef) + + def __len__(self): + return len(self.coef) + + # Numeric properties. + + def __neg__(self): + return self.__class__(-self.coef, self.domain, self.window) + + def __pos__(self): + return self + + def __add__(self, other): + othercoef = self._get_coefficients(other) + try: + coef = self._add(self.coef, othercoef) + except Exception: + return NotImplemented + return self.__class__(coef, self.domain, self.window) + + def __sub__(self, other): + othercoef = self._get_coefficients(other) + try: + coef = self._sub(self.coef, othercoef) + except Exception: + return NotImplemented + return self.__class__(coef, self.domain, self.window) + + def __mul__(self, other): + othercoef = self._get_coefficients(other) + try: + coef = self._mul(self.coef, othercoef) + except Exception: + return NotImplemented + return self.__class__(coef, self.domain, self.window) + + def __div__(self, other): + # set to __floordiv__, /, for now. + return self.__floordiv__(other) + + def __truediv__(self, other): + # there is no true divide if the rhs is not a Number, although it + # could return the first n elements of an infinite series. + # It is hard to see where n would come from, though. + if not isinstance(other, Number) or isinstance(other, bool): + form = "unsupported types for true division: '%s', '%s'" + raise TypeError(form % (type(self), type(other))) + return self.__floordiv__(other) + + def __floordiv__(self, other): + res = self.__divmod__(other) + if res is NotImplemented: + return res + return res[0] + + def __mod__(self, other): + res = self.__divmod__(other) + if res is NotImplemented: + return res + return res[1] + + def __divmod__(self, other): + othercoef = self._get_coefficients(other) + try: + quo, rem = self._div(self.coef, othercoef) + except ZeroDivisionError as e: + raise e + except Exception: + return NotImplemented + quo = self.__class__(quo, self.domain, self.window) + rem = self.__class__(rem, self.domain, self.window) + return quo, rem + + def __pow__(self, other): + coef = self._pow(self.coef, other, maxpower=self.maxpower) + res = self.__class__(coef, self.domain, self.window) + return res + + def __radd__(self, other): + try: + coef = self._add(other, self.coef) + except Exception: + return NotImplemented + return self.__class__(coef, self.domain, self.window) + + def __rsub__(self, other): + try: + coef = self._sub(other, self.coef) + except Exception: + return NotImplemented + return self.__class__(coef, self.domain, self.window) + + def __rmul__(self, other): + try: + coef = self._mul(other, self.coef) + except Exception: + return NotImplemented + return self.__class__(coef, self.domain, self.window) + + def __rdiv__(self, other): + # set to __floordiv__ /. + return self.__rfloordiv__(other) + + def __rtruediv__(self, other): + # An instance of ABCPolyBase is not considered a + # Number. + return NotImplemented + + def __rfloordiv__(self, other): + res = self.__rdivmod__(other) + if res is NotImplemented: + return res + return res[0] + + def __rmod__(self, other): + res = self.__rdivmod__(other) + if res is NotImplemented: + return res + return res[1] + + def __rdivmod__(self, other): + try: + quo, rem = self._div(other, self.coef) + except ZeroDivisionError as e: + raise e + except Exception: + return NotImplemented + quo = self.__class__(quo, self.domain, self.window) + rem = self.__class__(rem, self.domain, self.window) + return quo, rem + + # Enhance me + # some augmented arithmetic operations could be added here + + def __eq__(self, other): + res = (isinstance(other, self.__class__) and + np.all(self.domain == other.domain) and + np.all(self.window == other.window) and + (self.coef.shape == other.coef.shape) and + np.all(self.coef == other.coef)) + return res + + def __ne__(self, other): + return not self.__eq__(other) + + # + # Extra methods. + # + + def copy(self): + """Return a copy. + + Returns + ------- + new_series : series + Copy of self. + + """ + return self.__class__(self.coef, self.domain, self.window) + + def degree(self): + """The degree of the series. + + .. versionadded:: 1.5.0 + + Returns + ------- + degree : int + Degree of the series, one less than the number of coefficients. + + """ + return len(self) - 1 + + def cutdeg(self, deg): + """Truncate series to the given degree. + + Reduce the degree of the series to `deg` by discarding the + high order terms. If `deg` is greater than the current degree a + copy of the current series is returned. This can be useful in least + squares where the coefficients of the high degree terms may be very + small. + + .. versionadded:: 1.5.0 + + Parameters + ---------- + deg : non-negative int + The series is reduced to degree `deg` by discarding the high + order terms. The value of `deg` must be a non-negative integer. + + Returns + ------- + new_series : series + New instance of series with reduced degree. + + """ + return self.truncate(deg + 1) + + def trim(self, tol=0): + """Remove trailing coefficients + + Remove trailing coefficients until a coefficient is reached whose + absolute value greater than `tol` or the beginning of the series is + reached. If all the coefficients would be removed the series is set + to ``[0]``. A new series instance is returned with the new + coefficients. The current instance remains unchanged. + + Parameters + ---------- + tol : non-negative number. + All trailing coefficients less than `tol` will be removed. + + Returns + ------- + new_series : series + Contains the new set of coefficients. + + """ + coef = pu.trimcoef(self.coef, tol) + return self.__class__(coef, self.domain, self.window) + + def truncate(self, size): + """Truncate series to length `size`. + + Reduce the series to length `size` by discarding the high + degree terms. The value of `size` must be a positive integer. This + can be useful in least squares where the coefficients of the + high degree terms may be very small. + + Parameters + ---------- + size : positive int + The series is reduced to length `size` by discarding the high + degree terms. The value of `size` must be a positive integer. + + Returns + ------- + new_series : series + New instance of series with truncated coefficients. + + """ + isize = int(size) + if isize != size or isize < 1: + raise ValueError("size must be a positive integer") + if isize >= len(self.coef): + coef = self.coef + else: + coef = self.coef[:isize] + return self.__class__(coef, self.domain, self.window) + + def convert(self, domain=None, kind=None, window=None): + """Convert series to a different kind and/or domain and/or window. + + Parameters + ---------- + domain : array_like, optional + The domain of the converted series. If the value is None, + the default domain of `kind` is used. + kind : class, optional + The polynomial series type class to which the current instance + should be converted. If kind is None, then the class of the + current instance is used. + window : array_like, optional + The window of the converted series. If the value is None, + the default window of `kind` is used. + + Returns + ------- + new_series : series + The returned class can be of different type than the current + instance and/or have a different domain and/or different + window. + + Notes + ----- + Conversion between domains and class types can result in + numerically ill defined series. + + Examples + -------- + + """ + if kind is None: + kind = self.__class__ + if domain is None: + domain = kind.domain + if window is None: + window = kind.window + return self(kind.identity(domain, window=window)) + + def mapparms(self): + """Return the mapping parameters. + + The returned values define a linear map ``off + scl*x`` that is + applied to the input arguments before the series is evaluated. The + map depends on the ``domain`` and ``window``; if the current + ``domain`` is equal to the ``window`` the resulting map is the + identity. If the coefficients of the series instance are to be + used by themselves outside this class, then the linear function + must be substituted for the ``x`` in the standard representation of + the base polynomials. + + Returns + ------- + off, scl : float or complex + The mapping function is defined by ``off + scl*x``. + + Notes + ----- + If the current domain is the interval ``[l1, r1]`` and the window + is ``[l2, r2]``, then the linear mapping function ``L`` is + defined by the equations:: + + L(l1) = l2 + L(r1) = r2 + + """ + return pu.mapparms(self.domain, self.window) + + def integ(self, m=1, k=[], lbnd=None): + """Integrate. + + Return a series instance that is the definite integral of the + current series. + + Parameters + ---------- + m : non-negative int + The number of integrations to perform. + k : array_like + Integration constants. The first constant is applied to the + first integration, the second to the second, and so on. The + list of values must less than or equal to `m` in length and any + missing values are set to zero. + lbnd : Scalar + The lower bound of the definite integral. + + Returns + ------- + new_series : series + A new series representing the integral. The domain is the same + as the domain of the integrated series. + + """ + off, scl = self.mapparms() + if lbnd is None: + lbnd = 0 + else: + lbnd = off + scl*lbnd + coef = self._int(self.coef, m, k, lbnd, 1./scl) + return self.__class__(coef, self.domain, self.window) + + def deriv(self, m=1): + """Differentiate. + + Return a series instance of that is the derivative of the current + series. + + Parameters + ---------- + m : non-negative int + Find the derivative of order `m`. + + Returns + ------- + new_series : series + A new series representing the derivative. The domain is the same + as the domain of the differentiated series. + + """ + off, scl = self.mapparms() + coef = self._der(self.coef, m, scl) + return self.__class__(coef, self.domain, self.window) + + def roots(self): + """Return the roots of the series polynomial. + + Compute the roots for the series. Note that the accuracy of the + roots decrease the further outside the domain they lie. + + Returns + ------- + roots : ndarray + Array containing the roots of the series. + + """ + roots = self._roots(self.coef) + return pu.mapdomain(roots, self.window, self.domain) + + def linspace(self, n=100, domain=None): + """Return x, y values at equally spaced points in domain. + + Returns the x, y values at `n` linearly spaced points across the + domain. Here y is the value of the polynomial at the points x. By + default the domain is the same as that of the series instance. + This method is intended mostly as a plotting aid. + + .. versionadded:: 1.5.0 + + Parameters + ---------- + n : int, optional + Number of point pairs to return. The default value is 100. + domain : {None, array_like}, optional + If not None, the specified domain is used instead of that of + the calling instance. It should be of the form ``[beg,end]``. + The default is None which case the class domain is used. + + Returns + ------- + x, y : ndarray + x is equal to linspace(self.domain[0], self.domain[1], n) and + y is the series evaluated at element of x. + + """ + if domain is None: + domain = self.domain + x = np.linspace(domain[0], domain[1], n) + y = self(x) + return x, y + + @classmethod + def fit(cls, x, y, deg, domain=None, rcond=None, full=False, w=None, + window=None): + """Least squares fit to data. + + Return a series instance that is the least squares fit to the data + `y` sampled at `x`. The domain of the returned instance can be + specified and this will often result in a superior fit with less + chance of ill conditioning. + + Parameters + ---------- + x : array_like, shape (M,) + x-coordinates of the M sample points ``(x[i], y[i])``. + y : array_like, shape (M,) or (M, K) + y-coordinates of the sample points. Several data sets of sample + points sharing the same x-coordinates can be fitted at once by + passing in a 2D-array that contains one dataset per column. + deg : int or 1-D array_like + Degree(s) of the fitting polynomials. If `deg` is a single integer + all terms up to and including the `deg`'th term are included in the + fit. For NumPy versions >= 1.11.0 a list of integers specifying the + degrees of the terms to include may be used instead. + domain : {None, [beg, end], []}, optional + Domain to use for the returned series. If ``None``, + then a minimal domain that covers the points `x` is chosen. If + ``[]`` the class domain is used. The default value was the + class domain in NumPy 1.4 and ``None`` in later versions. + The ``[]`` option was added in numpy 1.5.0. + rcond : float, optional + Relative condition number of the fit. Singular values smaller + than this relative to the largest singular value will be + ignored. The default value is len(x)*eps, where eps is the + relative precision of the float type, about 2e-16 in most + cases. + full : bool, optional + Switch determining nature of return value. When it is False + (the default) just the coefficients are returned, when True + diagnostic information from the singular value decomposition is + also returned. + w : array_like, shape (M,), optional + Weights. If not None the contribution of each point + ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the + weights are chosen so that the errors of the products + ``w[i]*y[i]`` all have the same variance. The default value is + None. + + .. versionadded:: 1.5.0 + window : {[beg, end]}, optional + Window to use for the returned series. The default + value is the default class domain + + .. versionadded:: 1.6.0 + + Returns + ------- + new_series : series + A series that represents the least squares fit to the data and + has the domain specified in the call. + + [resid, rank, sv, rcond] : list + These values are only returned if `full` = True + + resid -- sum of squared residuals of the least squares fit + rank -- the numerical rank of the scaled Vandermonde matrix + sv -- singular values of the scaled Vandermonde matrix + rcond -- value of `rcond`. + + For more details, see `linalg.lstsq`. + + """ + if domain is None: + domain = pu.getdomain(x) + elif type(domain) is list and len(domain) == 0: + domain = cls.domain + + if window is None: + window = cls.window + + xnew = pu.mapdomain(x, domain, window) + res = cls._fit(xnew, y, deg, w=w, rcond=rcond, full=full) + if full: + [coef, status] = res + return cls(coef, domain=domain, window=window), status + else: + coef = res + return cls(coef, domain=domain, window=window) + + @classmethod + def fromroots(cls, roots, domain=[], window=None): + """Return series instance that has the specified roots. + + Returns a series representing the product + ``(x - r[0])*(x - r[1])*...*(x - r[n-1])``, where ``r`` is a + list of roots. + + Parameters + ---------- + roots : array_like + List of roots. + domain : {[], None, array_like}, optional + Domain for the resulting series. If None the domain is the + interval from the smallest root to the largest. If [] the + domain is the class domain. The default is []. + window : {None, array_like}, optional + Window for the returned series. If None the class window is + used. The default is None. + + Returns + ------- + new_series : series + Series with the specified roots. + + """ + [roots] = pu.as_series([roots], trim=False) + if domain is None: + domain = pu.getdomain(roots) + elif type(domain) is list and len(domain) == 0: + domain = cls.domain + + if window is None: + window = cls.window + + deg = len(roots) + off, scl = pu.mapparms(domain, window) + rnew = off + scl*roots + coef = cls._fromroots(rnew) / scl**deg + return cls(coef, domain=domain, window=window) + + @classmethod + def identity(cls, domain=None, window=None): + """Identity function. + + If ``p`` is the returned series, then ``p(x) == x`` for all + values of x. + + Parameters + ---------- + domain : {None, array_like}, optional + If given, the array must be of the form ``[beg, end]``, where + ``beg`` and ``end`` are the endpoints of the domain. If None is + given then the class domain is used. The default is None. + window : {None, array_like}, optional + If given, the resulting array must be if the form + ``[beg, end]``, where ``beg`` and ``end`` are the endpoints of + the window. If None is given then the class window is used. The + default is None. + + Returns + ------- + new_series : series + Series of representing the identity. + + """ + if domain is None: + domain = cls.domain + if window is None: + window = cls.window + off, scl = pu.mapparms(window, domain) + coef = cls._line(off, scl) + return cls(coef, domain, window) + + @classmethod + def basis(cls, deg, domain=None, window=None): + """Series basis polynomial of degree `deg`. + + Returns the series representing the basis polynomial of degree `deg`. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + deg : int + Degree of the basis polynomial for the series. Must be >= 0. + domain : {None, array_like}, optional + If given, the array must be of the form ``[beg, end]``, where + ``beg`` and ``end`` are the endpoints of the domain. If None is + given then the class domain is used. The default is None. + window : {None, array_like}, optional + If given, the resulting array must be if the form + ``[beg, end]``, where ``beg`` and ``end`` are the endpoints of + the window. If None is given then the class window is used. The + default is None. + + Returns + ------- + new_series : series + A series with the coefficient of the `deg` term set to one and + all others zero. + + """ + if domain is None: + domain = cls.domain + if window is None: + window = cls.window + ideg = int(deg) + + if ideg != deg or ideg < 0: + raise ValueError("deg must be non-negative integer") + return cls([0]*ideg + [1], domain, window) + + @classmethod + def cast(cls, series, domain=None, window=None): + """Convert series to series of this class. + + The `series` is expected to be an instance of some polynomial + series of one of the types supported by by the numpy.polynomial + module, but could be some other class that supports the convert + method. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + series : series + The series instance to be converted. + domain : {None, array_like}, optional + If given, the array must be of the form ``[beg, end]``, where + ``beg`` and ``end`` are the endpoints of the domain. If None is + given then the class domain is used. The default is None. + window : {None, array_like}, optional + If given, the resulting array must be if the form + ``[beg, end]``, where ``beg`` and ``end`` are the endpoints of + the window. If None is given then the class window is used. The + default is None. + + Returns + ------- + new_series : series + A series of the same kind as the calling class and equal to + `series` when evaluated. + + See Also + -------- + convert : similar instance method + + """ + if domain is None: + domain = cls.domain + if window is None: + window = cls.window + return series.convert(domain, cls, window) diff --git a/numpy/polynomial/chebyshev.py b/numpy/polynomial/chebyshev.py new file mode 100644 index 0000000..8add0ac --- /dev/null +++ b/numpy/polynomial/chebyshev.py @@ -0,0 +1,2190 @@ +""" +Objects for dealing with Chebyshev series. + +This module provides a number of objects (mostly functions) useful for +dealing with Chebyshev series, including a `Chebyshev` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Constants +--------- +- `chebdomain` -- Chebyshev series default domain, [-1,1]. +- `chebzero` -- (Coefficients of the) Chebyshev series that evaluates + identically to 0. +- `chebone` -- (Coefficients of the) Chebyshev series that evaluates + identically to 1. +- `chebx` -- (Coefficients of the) Chebyshev series for the identity map, + ``f(x) = x``. + +Arithmetic +---------- +- `chebadd` -- add two Chebyshev series. +- `chebsub` -- subtract one Chebyshev series from another. +- `chebmul` -- multiply two Chebyshev series. +- `chebdiv` -- divide one Chebyshev series by another. +- `chebpow` -- raise a Chebyshev series to an positive integer power +- `chebval` -- evaluate a Chebyshev series at given points. +- `chebval2d` -- evaluate a 2D Chebyshev series at given points. +- `chebval3d` -- evaluate a 3D Chebyshev series at given points. +- `chebgrid2d` -- evaluate a 2D Chebyshev series on a Cartesian product. +- `chebgrid3d` -- evaluate a 3D Chebyshev series on a Cartesian product. + +Calculus +-------- +- `chebder` -- differentiate a Chebyshev series. +- `chebint` -- integrate a Chebyshev series. + +Misc Functions +-------------- +- `chebfromroots` -- create a Chebyshev series with specified roots. +- `chebroots` -- find the roots of a Chebyshev series. +- `chebvander` -- Vandermonde-like matrix for Chebyshev polynomials. +- `chebvander2d` -- Vandermonde-like matrix for 2D power series. +- `chebvander3d` -- Vandermonde-like matrix for 3D power series. +- `chebgauss` -- Gauss-Chebyshev quadrature, points and weights. +- `chebweight` -- Chebyshev weight function. +- `chebcompanion` -- symmetrized companion matrix in Chebyshev form. +- `chebfit` -- least-squares fit returning a Chebyshev series. +- `chebpts1` -- Chebyshev points of the first kind. +- `chebpts2` -- Chebyshev points of the second kind. +- `chebtrim` -- trim leading coefficients from a Chebyshev series. +- `chebline` -- Chebyshev series representing given straight line. +- `cheb2poly` -- convert a Chebyshev series to a polynomial. +- `poly2cheb` -- convert a polynomial to a Chebyshev series. +- `chebinterpolate` -- interpolate a function at the Chebyshev points. + +Classes +------- +- `Chebyshev` -- A Chebyshev series class. + +See also +-------- +`numpy.polynomial` + +Notes +----- +The implementations of multiplication, division, integration, and +differentiation use the algebraic identities [1]_: + +.. math :: + T_n(x) = \\frac{z^n + z^{-n}}{2} \\\\ + z\\frac{dx}{dz} = \\frac{z - z^{-1}}{2}. + +where + +.. math :: x = \\frac{z + z^{-1}}{2}. + +These identities allow a Chebyshev series to be expressed as a finite, +symmetric Laurent series. In this module, this sort of Laurent series +is referred to as a "z-series." + +References +---------- +.. [1] A. T. Benjamin, et al., "Combinatorial Trigonometry with Chebyshev + Polynomials," *Journal of Statistical Planning and Inference 14*, 2008 + (preprint: http://www.math.hmc.edu/~benjamin/papers/CombTrig.pdf, pg. 4) + +""" +from __future__ import division, absolute_import, print_function + +import numbers +import warnings +import numpy as np +import numpy.linalg as la +from numpy.core.multiarray import normalize_axis_index + +from . import polyutils as pu +from ._polybase import ABCPolyBase + +__all__ = [ + 'chebzero', 'chebone', 'chebx', 'chebdomain', 'chebline', 'chebadd', + 'chebsub', 'chebmulx', 'chebmul', 'chebdiv', 'chebpow', 'chebval', + 'chebder', 'chebint', 'cheb2poly', 'poly2cheb', 'chebfromroots', + 'chebvander', 'chebfit', 'chebtrim', 'chebroots', 'chebpts1', + 'chebpts2', 'Chebyshev', 'chebval2d', 'chebval3d', 'chebgrid2d', + 'chebgrid3d', 'chebvander2d', 'chebvander3d', 'chebcompanion', + 'chebgauss', 'chebweight', 'chebinterpolate'] + +chebtrim = pu.trimcoef + +# +# A collection of functions for manipulating z-series. These are private +# functions and do minimal error checking. +# + +def _cseries_to_zseries(c): + """Covert Chebyshev series to z-series. + + Covert a Chebyshev series to the equivalent z-series. The result is + never an empty array. The dtype of the return is the same as that of + the input. No checks are run on the arguments as this routine is for + internal use. + + Parameters + ---------- + c : 1-D ndarray + Chebyshev coefficients, ordered from low to high + + Returns + ------- + zs : 1-D ndarray + Odd length symmetric z-series, ordered from low to high. + + """ + n = c.size + zs = np.zeros(2*n-1, dtype=c.dtype) + zs[n-1:] = c/2 + return zs + zs[::-1] + + +def _zseries_to_cseries(zs): + """Covert z-series to a Chebyshev series. + + Covert a z series to the equivalent Chebyshev series. The result is + never an empty array. The dtype of the return is the same as that of + the input. No checks are run on the arguments as this routine is for + internal use. + + Parameters + ---------- + zs : 1-D ndarray + Odd length symmetric z-series, ordered from low to high. + + Returns + ------- + c : 1-D ndarray + Chebyshev coefficients, ordered from low to high. + + """ + n = (zs.size + 1)//2 + c = zs[n-1:].copy() + c[1:n] *= 2 + return c + + +def _zseries_mul(z1, z2): + """Multiply two z-series. + + Multiply two z-series to produce a z-series. + + Parameters + ---------- + z1, z2 : 1-D ndarray + The arrays must be 1-D but this is not checked. + + Returns + ------- + product : 1-D ndarray + The product z-series. + + Notes + ----- + This is simply convolution. If symmetric/anti-symmetric z-series are + denoted by S/A then the following rules apply: + + S*S, A*A -> S + S*A, A*S -> A + + """ + return np.convolve(z1, z2) + + +def _zseries_div(z1, z2): + """Divide the first z-series by the second. + + Divide `z1` by `z2` and return the quotient and remainder as z-series. + Warning: this implementation only applies when both z1 and z2 have the + same symmetry, which is sufficient for present purposes. + + Parameters + ---------- + z1, z2 : 1-D ndarray + The arrays must be 1-D and have the same symmetry, but this is not + checked. + + Returns + ------- + + (quotient, remainder) : 1-D ndarrays + Quotient and remainder as z-series. + + Notes + ----- + This is not the same as polynomial division on account of the desired form + of the remainder. If symmetric/anti-symmetric z-series are denoted by S/A + then the following rules apply: + + S/S -> S,S + A/A -> S,A + + The restriction to types of the same symmetry could be fixed but seems like + unneeded generality. There is no natural form for the remainder in the case + where there is no symmetry. + + """ + z1 = z1.copy() + z2 = z2.copy() + len1 = len(z1) + len2 = len(z2) + if len2 == 1: + z1 /= z2 + return z1, z1[:1]*0 + elif len1 < len2: + return z1[:1]*0, z1 + else: + dlen = len1 - len2 + scl = z2[0] + z2 /= scl + quo = np.empty(dlen + 1, dtype=z1.dtype) + i = 0 + j = dlen + while i < j: + r = z1[i] + quo[i] = z1[i] + quo[dlen - i] = r + tmp = r*z2 + z1[i:i+len2] -= tmp + z1[j:j+len2] -= tmp + i += 1 + j -= 1 + r = z1[i] + quo[i] = r + tmp = r*z2 + z1[i:i+len2] -= tmp + quo /= scl + rem = z1[i+1:i-1+len2].copy() + return quo, rem + + +def _zseries_der(zs): + """Differentiate a z-series. + + The derivative is with respect to x, not z. This is achieved using the + chain rule and the value of dx/dz given in the module notes. + + Parameters + ---------- + zs : z-series + The z-series to differentiate. + + Returns + ------- + derivative : z-series + The derivative + + Notes + ----- + The zseries for x (ns) has been multiplied by two in order to avoid + using floats that are incompatible with Decimal and likely other + specialized scalar types. This scaling has been compensated by + multiplying the value of zs by two also so that the two cancels in the + division. + + """ + n = len(zs)//2 + ns = np.array([-1, 0, 1], dtype=zs.dtype) + zs *= np.arange(-n, n+1)*2 + d, r = _zseries_div(zs, ns) + return d + + +def _zseries_int(zs): + """Integrate a z-series. + + The integral is with respect to x, not z. This is achieved by a change + of variable using dx/dz given in the module notes. + + Parameters + ---------- + zs : z-series + The z-series to integrate + + Returns + ------- + integral : z-series + The indefinite integral + + Notes + ----- + The zseries for x (ns) has been multiplied by two in order to avoid + using floats that are incompatible with Decimal and likely other + specialized scalar types. This scaling has been compensated by + dividing the resulting zs by two. + + """ + n = 1 + len(zs)//2 + ns = np.array([-1, 0, 1], dtype=zs.dtype) + zs = _zseries_mul(zs, ns) + div = np.arange(-n, n+1)*2 + zs[:n] /= div[:n] + zs[n+1:] /= div[n+1:] + zs[n] = 0 + return zs + +# +# Chebyshev series functions +# + + +def poly2cheb(pol): + """ + Convert a polynomial to a Chebyshev series. + + Convert an array representing the coefficients of a polynomial (relative + to the "standard" basis) ordered from lowest degree to highest, to an + array of the coefficients of the equivalent Chebyshev series, ordered + from lowest to highest degree. + + Parameters + ---------- + pol : array_like + 1-D array containing the polynomial coefficients + + Returns + ------- + c : ndarray + 1-D array containing the coefficients of the equivalent Chebyshev + series. + + See Also + -------- + cheb2poly + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy import polynomial as P + >>> p = P.Polynomial(range(4)) + >>> p + Polynomial([ 0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1]) + >>> c = p.convert(kind=P.Chebyshev) + >>> c + Chebyshev([ 1. , 3.25, 1. , 0.75], domain=[-1, 1], window=[-1, 1]) + >>> P.poly2cheb(range(4)) + array([ 1. , 3.25, 1. , 0.75]) + + """ + [pol] = pu.as_series([pol]) + deg = len(pol) - 1 + res = 0 + for i in range(deg, -1, -1): + res = chebadd(chebmulx(res), pol[i]) + return res + + +def cheb2poly(c): + """ + Convert a Chebyshev series to a polynomial. + + Convert an array representing the coefficients of a Chebyshev series, + ordered from lowest degree to highest, to an array of the coefficients + of the equivalent polynomial (relative to the "standard" basis) ordered + from lowest to highest degree. + + Parameters + ---------- + c : array_like + 1-D array containing the Chebyshev series coefficients, ordered + from lowest order term to highest. + + Returns + ------- + pol : ndarray + 1-D array containing the coefficients of the equivalent polynomial + (relative to the "standard" basis) ordered from lowest order term + to highest. + + See Also + -------- + poly2cheb + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy import polynomial as P + >>> c = P.Chebyshev(range(4)) + >>> c + Chebyshev([ 0., 1., 2., 3.], [-1., 1.]) + >>> p = c.convert(kind=P.Polynomial) + >>> p + Polynomial([ -2., -8., 4., 12.], [-1., 1.]) + >>> P.cheb2poly(range(4)) + array([ -2., -8., 4., 12.]) + + """ + from .polynomial import polyadd, polysub, polymulx + + [c] = pu.as_series([c]) + n = len(c) + if n < 3: + return c + else: + c0 = c[-2] + c1 = c[-1] + # i is the current degree of c1 + for i in range(n - 1, 1, -1): + tmp = c0 + c0 = polysub(c[i - 2], c1) + c1 = polyadd(tmp, polymulx(c1)*2) + return polyadd(c0, polymulx(c1)) + + +# +# These are constant arrays are of integer type so as to be compatible +# with the widest range of other types, such as Decimal. +# + +# Chebyshev default domain. +chebdomain = np.array([-1, 1]) + +# Chebyshev coefficients representing zero. +chebzero = np.array([0]) + +# Chebyshev coefficients representing one. +chebone = np.array([1]) + +# Chebyshev coefficients representing the identity x. +chebx = np.array([0, 1]) + + +def chebline(off, scl): + """ + Chebyshev series whose graph is a straight line. + + + + Parameters + ---------- + off, scl : scalars + The specified line is given by ``off + scl*x``. + + Returns + ------- + y : ndarray + This module's representation of the Chebyshev series for + ``off + scl*x``. + + See Also + -------- + polyline + + Examples + -------- + >>> import numpy.polynomial.chebyshev as C + >>> C.chebline(3,2) + array([3, 2]) + >>> C.chebval(-3, C.chebline(3,2)) # should be -3 + -3.0 + + """ + if scl != 0: + return np.array([off, scl]) + else: + return np.array([off]) + + +def chebfromroots(roots): + """ + Generate a Chebyshev series with given roots. + + The function returns the coefficients of the polynomial + + .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n), + + in Chebyshev form, where the `r_n` are the roots specified in `roots`. + If a zero has multiplicity n, then it must appear in `roots` n times. + For instance, if 2 is a root of multiplicity three and 3 is a root of + multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The + roots can appear in any order. + + If the returned coefficients are `c`, then + + .. math:: p(x) = c_0 + c_1 * T_1(x) + ... + c_n * T_n(x) + + The coefficient of the last term is not generally 1 for monic + polynomials in Chebyshev form. + + Parameters + ---------- + roots : array_like + Sequence containing the roots. + + Returns + ------- + out : ndarray + 1-D array of coefficients. If all roots are real then `out` is a + real array, if some of the roots are complex, then `out` is complex + even if all the coefficients in the result are real (see Examples + below). + + See Also + -------- + polyfromroots, legfromroots, lagfromroots, hermfromroots, + hermefromroots. + + Examples + -------- + >>> import numpy.polynomial.chebyshev as C + >>> C.chebfromroots((-1,0,1)) # x^3 - x relative to the standard basis + array([ 0. , -0.25, 0. , 0.25]) + >>> j = complex(0,1) + >>> C.chebfromroots((-j,j)) # x^2 + 1 relative to the standard basis + array([ 1.5+0.j, 0.0+0.j, 0.5+0.j]) + + """ + if len(roots) == 0: + return np.ones(1) + else: + [roots] = pu.as_series([roots], trim=False) + roots.sort() + p = [chebline(-r, 1) for r in roots] + n = len(p) + while n > 1: + m, r = divmod(n, 2) + tmp = [chebmul(p[i], p[i+m]) for i in range(m)] + if r: + tmp[0] = chebmul(tmp[0], p[-1]) + p = tmp + n = m + return p[0] + + +def chebadd(c1, c2): + """ + Add one Chebyshev series to another. + + Returns the sum of two Chebyshev series `c1` + `c2`. The arguments + are sequences of coefficients ordered from lowest order term to + highest, i.e., [1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Chebyshev series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the Chebyshev series of their sum. + + See Also + -------- + chebsub, chebmul, chebdiv, chebpow + + Notes + ----- + Unlike multiplication, division, etc., the sum of two Chebyshev series + is a Chebyshev series (without having to "reproject" the result onto + the basis set) so addition, just like that of "standard" polynomials, + is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial import chebyshev as C + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> C.chebadd(c1,c2) + array([ 4., 4., 4.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] += c2 + ret = c1 + else: + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def chebsub(c1, c2): + """ + Subtract one Chebyshev series from another. + + Returns the difference of two Chebyshev series `c1` - `c2`. The + sequences of coefficients are from lowest order term to highest, i.e., + [1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Chebyshev series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Chebyshev series coefficients representing their difference. + + See Also + -------- + chebadd, chebmul, chebdiv, chebpow + + Notes + ----- + Unlike multiplication, division, etc., the difference of two Chebyshev + series is a Chebyshev series (without having to "reproject" the result + onto the basis set) so subtraction, just like that of "standard" + polynomials, is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial import chebyshev as C + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> C.chebsub(c1,c2) + array([-2., 0., 2.]) + >>> C.chebsub(c2,c1) # -C.chebsub(c1,c2) + array([ 2., 0., -2.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] -= c2 + ret = c1 + else: + c2 = -c2 + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def chebmulx(c): + """Multiply a Chebyshev series by x. + + Multiply the polynomial `c` by x, where x is the independent + variable. + + + Parameters + ---------- + c : array_like + 1-D array of Chebyshev series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the result of the multiplication. + + Notes + ----- + + .. versionadded:: 1.5.0 + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + # The zero series needs special treatment + if len(c) == 1 and c[0] == 0: + return c + + prd = np.empty(len(c) + 1, dtype=c.dtype) + prd[0] = c[0]*0 + prd[1] = c[0] + if len(c) > 1: + tmp = c[1:]/2 + prd[2:] = tmp + prd[0:-2] += tmp + return prd + + +def chebmul(c1, c2): + """ + Multiply one Chebyshev series by another. + + Returns the product of two Chebyshev series `c1` * `c2`. The arguments + are sequences of coefficients, from lowest order "term" to highest, + e.g., [1,2,3] represents the series ``T_0 + 2*T_1 + 3*T_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Chebyshev series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Chebyshev series coefficients representing their product. + + See Also + -------- + chebadd, chebsub, chebdiv, chebpow + + Notes + ----- + In general, the (polynomial) product of two C-series results in terms + that are not in the Chebyshev polynomial basis set. Thus, to express + the product as a C-series, it is typically necessary to "reproject" + the product onto said basis set, which typically produces + "unintuitive live" (but correct) results; see Examples section below. + + Examples + -------- + >>> from numpy.polynomial import chebyshev as C + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> C.chebmul(c1,c2) # multiplication requires "reprojection" + array([ 6.5, 12. , 12. , 4. , 1.5]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + z1 = _cseries_to_zseries(c1) + z2 = _cseries_to_zseries(c2) + prd = _zseries_mul(z1, z2) + ret = _zseries_to_cseries(prd) + return pu.trimseq(ret) + + +def chebdiv(c1, c2): + """ + Divide one Chebyshev series by another. + + Returns the quotient-with-remainder of two Chebyshev series + `c1` / `c2`. The arguments are sequences of coefficients from lowest + order "term" to highest, e.g., [1,2,3] represents the series + ``T_0 + 2*T_1 + 3*T_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Chebyshev series coefficients ordered from low to + high. + + Returns + ------- + [quo, rem] : ndarrays + Of Chebyshev series coefficients representing the quotient and + remainder. + + See Also + -------- + chebadd, chebsub, chebmul, chebpow + + Notes + ----- + In general, the (polynomial) division of one C-series by another + results in quotient and remainder terms that are not in the Chebyshev + polynomial basis set. Thus, to express these results as C-series, it + is typically necessary to "reproject" the results onto said basis + set, which typically produces "unintuitive" (but correct) results; + see Examples section below. + + Examples + -------- + >>> from numpy.polynomial import chebyshev as C + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> C.chebdiv(c1,c2) # quotient "intuitive," remainder not + (array([ 3.]), array([-8., -4.])) + >>> c2 = (0,1,2,3) + >>> C.chebdiv(c2,c1) # neither "intuitive" + (array([ 0., 2.]), array([-2., -4.])) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if c2[-1] == 0: + raise ZeroDivisionError() + + lc1 = len(c1) + lc2 = len(c2) + if lc1 < lc2: + return c1[:1]*0, c1 + elif lc2 == 1: + return c1/c2[-1], c1[:1]*0 + else: + z1 = _cseries_to_zseries(c1) + z2 = _cseries_to_zseries(c2) + quo, rem = _zseries_div(z1, z2) + quo = pu.trimseq(_zseries_to_cseries(quo)) + rem = pu.trimseq(_zseries_to_cseries(rem)) + return quo, rem + + +def chebpow(c, pow, maxpower=16): + """Raise a Chebyshev series to a power. + + Returns the Chebyshev series `c` raised to the power `pow`. The + argument `c` is a sequence of coefficients ordered from low to high. + i.e., [1,2,3] is the series ``T_0 + 2*T_1 + 3*T_2.`` + + Parameters + ---------- + c : array_like + 1-D array of Chebyshev series coefficients ordered from low to + high. + pow : integer + Power to which the series will be raised + maxpower : integer, optional + Maximum power allowed. This is mainly to limit growth of the series + to unmanageable size. Default is 16 + + Returns + ------- + coef : ndarray + Chebyshev series of power. + + See Also + -------- + chebadd, chebsub, chebmul, chebdiv + + Examples + -------- + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + power = int(pow) + if power != pow or power < 0: + raise ValueError("Power must be a non-negative integer.") + elif maxpower is not None and power > maxpower: + raise ValueError("Power is too large") + elif power == 0: + return np.array([1], dtype=c.dtype) + elif power == 1: + return c + else: + # This can be made more efficient by using powers of two + # in the usual way. + zs = _cseries_to_zseries(c) + prd = zs + for i in range(2, power + 1): + prd = np.convolve(prd, zs) + return _zseries_to_cseries(prd) + + +def chebder(c, m=1, scl=1, axis=0): + """ + Differentiate a Chebyshev series. + + Returns the Chebyshev series coefficients `c` differentiated `m` times + along `axis`. At each iteration the result is multiplied by `scl` (the + scaling factor is for use in a linear change of variable). The argument + `c` is an array of coefficients from low to high degree along each + axis, e.g., [1,2,3] represents the series ``1*T_0 + 2*T_1 + 3*T_2`` + while [[1,2],[1,2]] represents ``1*T_0(x)*T_0(y) + 1*T_1(x)*T_0(y) + + 2*T_0(x)*T_1(y) + 2*T_1(x)*T_1(y)`` if axis=0 is ``x`` and axis=1 is + ``y``. + + Parameters + ---------- + c : array_like + Array of Chebyshev series coefficients. If c is multidimensional + the different axis correspond to different variables with the + degree in each axis given by the corresponding index. + m : int, optional + Number of derivatives taken, must be non-negative. (Default: 1) + scl : scalar, optional + Each differentiation is multiplied by `scl`. The end result is + multiplication by ``scl**m``. This is for use in a linear change of + variable. (Default: 1) + axis : int, optional + Axis over which the derivative is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + der : ndarray + Chebyshev series of the derivative. + + See Also + -------- + chebint + + Notes + ----- + In general, the result of differentiating a C-series needs to be + "reprojected" onto the C-series basis set. Thus, typically, the + result of this function is "unintuitive," albeit correct; see Examples + section below. + + Examples + -------- + >>> from numpy.polynomial import chebyshev as C + >>> c = (1,2,3,4) + >>> C.chebder(c) + array([ 14., 12., 24.]) + >>> C.chebder(c,3) + array([ 96.]) + >>> C.chebder(c,scl=-1) + array([-14., -12., -24.]) + >>> C.chebder(c,2,-1) + array([ 12., 96.]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of derivation must be integer") + if cnt < 0: + raise ValueError("The order of derivation must be non-negative") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + n = len(c) + if cnt >= n: + c = c[:1]*0 + else: + for i in range(cnt): + n = n - 1 + c *= scl + der = np.empty((n,) + c.shape[1:], dtype=c.dtype) + for j in range(n, 2, -1): + der[j - 1] = (2*j)*c[j] + c[j - 2] += (j*c[j])/(j - 2) + if n > 1: + der[1] = 4*c[2] + der[0] = c[1] + c = der + c = np.moveaxis(c, 0, iaxis) + return c + + +def chebint(c, m=1, k=[], lbnd=0, scl=1, axis=0): + """ + Integrate a Chebyshev series. + + Returns the Chebyshev series coefficients `c` integrated `m` times from + `lbnd` along `axis`. At each iteration the resulting series is + **multiplied** by `scl` and an integration constant, `k`, is added. + The scaling factor is for use in a linear change of variable. ("Buyer + beware": note that, depending on what one is doing, one may want `scl` + to be the reciprocal of what one might expect; for more information, + see the Notes section below.) The argument `c` is an array of + coefficients from low to high degree along each axis, e.g., [1,2,3] + represents the series ``T_0 + 2*T_1 + 3*T_2`` while [[1,2],[1,2]] + represents ``1*T_0(x)*T_0(y) + 1*T_1(x)*T_0(y) + 2*T_0(x)*T_1(y) + + 2*T_1(x)*T_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. + + Parameters + ---------- + c : array_like + Array of Chebyshev series coefficients. If c is multidimensional + the different axis correspond to different variables with the + degree in each axis given by the corresponding index. + m : int, optional + Order of integration, must be positive. (Default: 1) + k : {[], list, scalar}, optional + Integration constant(s). The value of the first integral at zero + is the first value in the list, the value of the second integral + at zero is the second value, etc. If ``k == []`` (the default), + all constants are set to zero. If ``m == 1``, a single scalar can + be given instead of a list. + lbnd : scalar, optional + The lower bound of the integral. (Default: 0) + scl : scalar, optional + Following each integration the result is *multiplied* by `scl` + before the integration constant is added. (Default: 1) + axis : int, optional + Axis over which the integral is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + S : ndarray + C-series coefficients of the integral. + + Raises + ------ + ValueError + If ``m < 1``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or + ``np.ndim(scl) != 0``. + + See Also + -------- + chebder + + Notes + ----- + Note that the result of each integration is *multiplied* by `scl`. + Why is this important to note? Say one is making a linear change of + variable :math:`u = ax + b` in an integral relative to `x`. Then + :math:`dx = du/a`, so one will need to set `scl` equal to + :math:`1/a`- perhaps not what one would have first thought. + + Also note that, in general, the result of integrating a C-series needs + to be "reprojected" onto the C-series basis set. Thus, typically, + the result of this function is "unintuitive," albeit correct; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial import chebyshev as C + >>> c = (1,2,3) + >>> C.chebint(c) + array([ 0.5, -0.5, 0.5, 0.5]) + >>> C.chebint(c,3) + array([ 0.03125 , -0.1875 , 0.04166667, -0.05208333, 0.01041667, + 0.00625 ]) + >>> C.chebint(c, k=3) + array([ 3.5, -0.5, 0.5, 0.5]) + >>> C.chebint(c,lbnd=-2) + array([ 8.5, -0.5, 0.5, 0.5]) + >>> C.chebint(c,scl=-2) + array([-1., 1., -1., -1.]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if not np.iterable(k): + k = [k] + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of integration must be integer") + if cnt < 0: + raise ValueError("The order of integration must be non-negative") + if len(k) > cnt: + raise ValueError("Too many integration constants") + if np.ndim(lbnd) != 0: + raise ValueError("lbnd must be a scalar.") + if np.ndim(scl) != 0: + raise ValueError("scl must be a scalar.") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + k = list(k) + [0]*(cnt - len(k)) + for i in range(cnt): + n = len(c) + c *= scl + if n == 1 and np.all(c[0] == 0): + c[0] += k[i] + else: + tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype) + tmp[0] = c[0]*0 + tmp[1] = c[0] + if n > 1: + tmp[2] = c[1]/4 + for j in range(2, n): + t = c[j]/(2*j + 1) + tmp[j + 1] = c[j]/(2*(j + 1)) + tmp[j - 1] -= c[j]/(2*(j - 1)) + tmp[0] += k[i] - chebval(lbnd, tmp) + c = tmp + c = np.moveaxis(c, 0, iaxis) + return c + + +def chebval(x, c, tensor=True): + """ + Evaluate a Chebyshev series at points x. + + If `c` is of length `n + 1`, this function returns the value: + + .. math:: p(x) = c_0 * T_0(x) + c_1 * T_1(x) + ... + c_n * T_n(x) + + The parameter `x` is converted to an array only if it is a tuple or a + list, otherwise it is treated as a scalar. In either case, either `x` + or its elements must support multiplication and addition both with + themselves and with the elements of `c`. + + If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If + `c` is multidimensional, then the shape of the result depends on the + value of `tensor`. If `tensor` is true the shape will be c.shape[1:] + + x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that + scalars have shape (,). + + Trailing zeros in the coefficients will be used in the evaluation, so + they should be avoided if efficiency is a concern. + + Parameters + ---------- + x : array_like, compatible object + If `x` is a list or tuple, it is converted to an ndarray, otherwise + it is left unchanged and treated as a scalar. In either case, `x` + or its elements must support addition and multiplication with + with themselves and with the elements of `c`. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree n are contained in c[n]. If `c` is multidimensional the + remaining indices enumerate multiple polynomials. In the two + dimensional case the coefficients may be thought of as stored in + the columns of `c`. + tensor : boolean, optional + If True, the shape of the coefficient array is extended with ones + on the right, one for each dimension of `x`. Scalars have dimension 0 + for this action. The result is that every column of coefficients in + `c` is evaluated for every element of `x`. If False, `x` is broadcast + over the columns of `c` for the evaluation. This keyword is useful + when `c` is multidimensional. The default value is True. + + .. versionadded:: 1.7.0 + + Returns + ------- + values : ndarray, algebra_like + The shape of the return value is described above. + + See Also + -------- + chebval2d, chebgrid2d, chebval3d, chebgrid3d + + Notes + ----- + The evaluation uses Clenshaw recursion, aka synthetic division. + + Examples + -------- + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if isinstance(x, (tuple, list)): + x = np.asarray(x) + if isinstance(x, np.ndarray) and tensor: + c = c.reshape(c.shape + (1,)*x.ndim) + + if len(c) == 1: + c0 = c[0] + c1 = 0 + elif len(c) == 2: + c0 = c[0] + c1 = c[1] + else: + x2 = 2*x + c0 = c[-2] + c1 = c[-1] + for i in range(3, len(c) + 1): + tmp = c0 + c0 = c[-i] - c1 + c1 = tmp + c1*x2 + return c0 + c1*x + + +def chebval2d(x, y, c): + """ + Evaluate a 2-D Chebyshev series at points (x, y). + + This function returns the values: + + .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * T_i(x) * T_j(y) + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars and they + must have the same shape after conversion. In either case, either `x` + and `y` or their elements must support multiplication and addition both + with themselves and with the elements of `c`. + + If `c` is a 1-D array a one is implicitly appended to its shape to make + it 2-D. The shape of the result will be c.shape[2:] + x.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points `(x, y)`, + where `x` and `y` must have the same shape. If `x` or `y` is a list + or tuple, it is first converted to an ndarray, otherwise it is left + unchanged and if it isn't an ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term + of multi-degree i,j is contained in ``c[i,j]``. If `c` has + dimension greater than 2 the remaining indices enumerate multiple + sets of coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional Chebyshev series at points formed + from pairs of corresponding values from `x` and `y`. + + See Also + -------- + chebval, chebgrid2d, chebval3d, chebgrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y = np.array((x, y), copy=0) + except Exception: + raise ValueError('x, y are incompatible') + + c = chebval(x, c) + c = chebval(y, c, tensor=False) + return c + + +def chebgrid2d(x, y, c): + """ + Evaluate a 2-D Chebyshev series on the Cartesian product of x and y. + + This function returns the values: + + .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * T_i(a) * T_j(b), + + where the points `(a, b)` consist of all pairs formed by taking + `a` from `x` and `b` from `y`. The resulting points form a grid with + `x` in the first dimension and `y` in the second. + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars. In either + case, either `x` and `y` or their elements must support multiplication + and addition both with themselves and with the elements of `c`. + + If `c` has fewer than two dimensions, ones are implicitly appended to + its shape to make it 2-D. The shape of the result will be c.shape[2:] + + x.shape + y.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points in the + Cartesian product of `x` and `y`. If `x` or `y` is a list or + tuple, it is first converted to an ndarray, otherwise it is left + unchanged and, if it isn't an ndarray, it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j is contained in `c[i,j]`. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional Chebyshev series at points in the + Cartesian product of `x` and `y`. + + See Also + -------- + chebval, chebval2d, chebval3d, chebgrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = chebval(x, c) + c = chebval(y, c) + return c + + +def chebval3d(x, y, z, c): + """ + Evaluate a 3-D Chebyshev series at points (x, y, z). + + This function returns the values: + + .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * T_i(x) * T_j(y) * T_k(z) + + The parameters `x`, `y`, and `z` are converted to arrays only if + they are tuples or a lists, otherwise they are treated as a scalars and + they must have the same shape after conversion. In either case, either + `x`, `y`, and `z` or their elements must support multiplication and + addition both with themselves and with the elements of `c`. + + If `c` has fewer than 3 dimensions, ones are implicitly appended to its + shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape. + + Parameters + ---------- + x, y, z : array_like, compatible object + The three dimensional series is evaluated at the points + `(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If + any of `x`, `y`, or `z` is a list or tuple, it is first converted + to an ndarray, otherwise it is left unchanged and if it isn't an + ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension + greater than 3 the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the multidimensional polynomial on points formed with + triples of corresponding values from `x`, `y`, and `z`. + + See Also + -------- + chebval, chebval2d, chebgrid2d, chebgrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y, z = np.array((x, y, z), copy=0) + except Exception: + raise ValueError('x, y, z are incompatible') + + c = chebval(x, c) + c = chebval(y, c, tensor=False) + c = chebval(z, c, tensor=False) + return c + + +def chebgrid3d(x, y, z, c): + """ + Evaluate a 3-D Chebyshev series on the Cartesian product of x, y, and z. + + This function returns the values: + + .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * T_i(a) * T_j(b) * T_k(c) + + where the points `(a, b, c)` consist of all triples formed by taking + `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form + a grid with `x` in the first dimension, `y` in the second, and `z` in + the third. + + The parameters `x`, `y`, and `z` are converted to arrays only if they + are tuples or a lists, otherwise they are treated as a scalars. In + either case, either `x`, `y`, and `z` or their elements must support + multiplication and addition both with themselves and with the elements + of `c`. + + If `c` has fewer than three dimensions, ones are implicitly appended to + its shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape + y.shape + z.shape. + + Parameters + ---------- + x, y, z : array_like, compatible objects + The three dimensional series is evaluated at the points in the + Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a + list or tuple, it is first converted to an ndarray, otherwise it is + left unchanged and, if it isn't an ndarray, it is treated as a + scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + chebval, chebval2d, chebgrid2d, chebval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = chebval(x, c) + c = chebval(y, c) + c = chebval(z, c) + return c + + +def chebvander(x, deg): + """Pseudo-Vandermonde matrix of given degree. + + Returns the pseudo-Vandermonde matrix of degree `deg` and sample points + `x`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., i] = T_i(x), + + where `0 <= i <= deg`. The leading indices of `V` index the elements of + `x` and the last index is the degree of the Chebyshev polynomial. + + If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the + matrix ``V = chebvander(x, n)``, then ``np.dot(V, c)`` and + ``chebval(x, c)`` are the same up to roundoff. This equivalence is + useful both for least squares fitting and for the evaluation of a large + number of Chebyshev series of the same degree and sample points. + + Parameters + ---------- + x : array_like + Array of points. The dtype is converted to float64 or complex128 + depending on whether any of the elements are complex. If `x` is + scalar it is converted to a 1-D array. + deg : int + Degree of the resulting matrix. + + Returns + ------- + vander : ndarray + The pseudo Vandermonde matrix. The shape of the returned matrix is + ``x.shape + (deg + 1,)``, where The last index is the degree of the + corresponding Chebyshev polynomial. The dtype will be the same as + the converted `x`. + + """ + ideg = int(deg) + if ideg != deg: + raise ValueError("deg must be integer") + if ideg < 0: + raise ValueError("deg must be non-negative") + + x = np.array(x, copy=0, ndmin=1) + 0.0 + dims = (ideg + 1,) + x.shape + dtyp = x.dtype + v = np.empty(dims, dtype=dtyp) + # Use forward recursion to generate the entries. + v[0] = x*0 + 1 + if ideg > 0: + x2 = 2*x + v[1] = x + for i in range(2, ideg + 1): + v[i] = v[i-1]*x2 - v[i-2] + return np.moveaxis(v, 0, -1) + + +def chebvander2d(x, y, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y)`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (deg[1] + 1)*i + j] = T_i(x) * T_j(y), + + where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of + `V` index the points `(x, y)` and the last index encodes the degrees of + the Chebyshev polynomials. + + If ``V = chebvander2d(x, y, [xdeg, ydeg])``, then the columns of `V` + correspond to the elements of a 2-D coefficient array `c` of shape + (xdeg + 1, ydeg + 1) in the order + + .. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ... + + and ``np.dot(V, c.flat)`` and ``chebval2d(x, y, c)`` will be the same + up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 2-D Chebyshev + series of the same degrees and sample points. + + Parameters + ---------- + x, y : array_like + Arrays of point coordinates, all of the same shape. The dtypes + will be converted to either float64 or complex128 depending on + whether any of the elements are complex. Scalars are converted to + 1-D arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg]. + + Returns + ------- + vander2d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)`. The dtype will be the same + as the converted `x` and `y`. + + See Also + -------- + chebvander, chebvander3d. chebval2d, chebval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy = ideg + x, y = np.array((x, y), copy=0) + 0.0 + + vx = chebvander(x, degx) + vy = chebvander(y, degy) + v = vx[..., None]*vy[..., None,:] + return v.reshape(v.shape[:-2] + (-1,)) + + +def chebvander3d(x, y, z, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`, + then The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = T_i(x)*T_j(y)*T_k(z), + + where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading + indices of `V` index the points `(x, y, z)` and the last index encodes + the degrees of the Chebyshev polynomials. + + If ``V = chebvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns + of `V` correspond to the elements of a 3-D coefficient array `c` of + shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order + + .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},... + + and ``np.dot(V, c.flat)`` and ``chebval3d(x, y, z, c)`` will be the + same up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 3-D Chebyshev + series of the same degrees and sample points. + + Parameters + ---------- + x, y, z : array_like + Arrays of point coordinates, all of the same shape. The dtypes will + be converted to either float64 or complex128 depending on whether + any of the elements are complex. Scalars are converted to 1-D + arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg, z_deg]. + + Returns + ------- + vander3d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)*(deg[2]+1)`. The dtype will + be the same as the converted `x`, `y`, and `z`. + + See Also + -------- + chebvander, chebvander3d. chebval2d, chebval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy, degz = ideg + x, y, z = np.array((x, y, z), copy=0) + 0.0 + + vx = chebvander(x, degx) + vy = chebvander(y, degy) + vz = chebvander(z, degz) + v = vx[..., None, None]*vy[..., None,:, None]*vz[..., None, None,:] + return v.reshape(v.shape[:-3] + (-1,)) + + +def chebfit(x, y, deg, rcond=None, full=False, w=None): + """ + Least squares fit of Chebyshev series to data. + + Return the coefficients of a Chebyshev series of degree `deg` that is the + least squares fit to the data values `y` given at points `x`. If `y` is + 1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple + fits are done, one for each column of `y`, and the resulting + coefficients are stored in the corresponding columns of a 2-D return. + The fitted polynomial(s) are in the form + + .. math:: p(x) = c_0 + c_1 * T_1(x) + ... + c_n * T_n(x), + + where `n` is `deg`. + + Parameters + ---------- + x : array_like, shape (M,) + x-coordinates of the M sample points ``(x[i], y[i])``. + y : array_like, shape (M,) or (M, K) + y-coordinates of the sample points. Several data sets of sample + points sharing the same x-coordinates can be fitted at once by + passing in a 2D-array that contains one dataset per column. + deg : int or 1-D array_like + Degree(s) of the fitting polynomials. If `deg` is a single integer, + all terms up to and including the `deg`'th term are included in the + fit. For NumPy versions >= 1.11.0 a list of integers specifying the + degrees of the terms to include may be used instead. + rcond : float, optional + Relative condition number of the fit. Singular values smaller than + this relative to the largest singular value will be ignored. The + default value is len(x)*eps, where eps is the relative precision of + the float type, about 2e-16 in most cases. + full : bool, optional + Switch determining nature of return value. When it is False (the + default) just the coefficients are returned, when True diagnostic + information from the singular value decomposition is also returned. + w : array_like, shape (`M`,), optional + Weights. If not None, the contribution of each point + ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the + weights are chosen so that the errors of the products ``w[i]*y[i]`` + all have the same variance. The default value is None. + + .. versionadded:: 1.5.0 + + Returns + ------- + coef : ndarray, shape (M,) or (M, K) + Chebyshev coefficients ordered from low to high. If `y` was 2-D, + the coefficients for the data in column k of `y` are in column + `k`. + + [residuals, rank, singular_values, rcond] : list + These values are only returned if `full` = True + + resid -- sum of squared residuals of the least squares fit + rank -- the numerical rank of the scaled Vandermonde matrix + sv -- singular values of the scaled Vandermonde matrix + rcond -- value of `rcond`. + + For more details, see `linalg.lstsq`. + + Warns + ----- + RankWarning + The rank of the coefficient matrix in the least-squares fit is + deficient. The warning is only raised if `full` = False. The + warnings can be turned off by + + >>> import warnings + >>> warnings.simplefilter('ignore', RankWarning) + + See Also + -------- + polyfit, legfit, lagfit, hermfit, hermefit + chebval : Evaluates a Chebyshev series. + chebvander : Vandermonde matrix of Chebyshev series. + chebweight : Chebyshev weight function. + linalg.lstsq : Computes a least-squares fit from the matrix. + scipy.interpolate.UnivariateSpline : Computes spline fits. + + Notes + ----- + The solution is the coefficients of the Chebyshev series `p` that + minimizes the sum of the weighted squared errors + + .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2, + + where :math:`w_j` are the weights. This problem is solved by setting up + as the (typically) overdetermined matrix equation + + .. math:: V(x) * c = w * y, + + where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the + coefficients to be solved for, `w` are the weights, and `y` are the + observed values. This equation is then solved using the singular value + decomposition of `V`. + + If some of the singular values of `V` are so small that they are + neglected, then a `RankWarning` will be issued. This means that the + coefficient values may be poorly determined. Using a lower order fit + will usually get rid of the warning. The `rcond` parameter can also be + set to a value smaller than its default, but the resulting fit may be + spurious and have large contributions from roundoff error. + + Fits using Chebyshev series are usually better conditioned than fits + using power series, but much can depend on the distribution of the + sample points and the smoothness of the data. If the quality of the fit + is inadequate splines may be a good alternative. + + References + ---------- + .. [1] Wikipedia, "Curve fitting", + http://en.wikipedia.org/wiki/Curve_fitting + + Examples + -------- + + """ + x = np.asarray(x) + 0.0 + y = np.asarray(y) + 0.0 + deg = np.asarray(deg) + + # check arguments. + if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0: + raise TypeError("deg must be an int or non-empty 1-D array of int") + if deg.min() < 0: + raise ValueError("expected deg >= 0") + if x.ndim != 1: + raise TypeError("expected 1D vector for x") + if x.size == 0: + raise TypeError("expected non-empty vector for x") + if y.ndim < 1 or y.ndim > 2: + raise TypeError("expected 1D or 2D array for y") + if len(x) != len(y): + raise TypeError("expected x and y to have same length") + + if deg.ndim == 0: + lmax = deg + order = lmax + 1 + van = chebvander(x, lmax) + else: + deg = np.sort(deg) + lmax = deg[-1] + order = len(deg) + van = chebvander(x, lmax)[:, deg] + + # set up the least squares matrices in transposed form + lhs = van.T + rhs = y.T + if w is not None: + w = np.asarray(w) + 0.0 + if w.ndim != 1: + raise TypeError("expected 1D vector for w") + if len(x) != len(w): + raise TypeError("expected x and w to have same length") + # apply weights. Don't use inplace operations as they + # can cause problems with NA. + lhs = lhs * w + rhs = rhs * w + + # set rcond + if rcond is None: + rcond = len(x)*np.finfo(x.dtype).eps + + # Determine the norms of the design matrix columns. + if issubclass(lhs.dtype.type, np.complexfloating): + scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1)) + else: + scl = np.sqrt(np.square(lhs).sum(1)) + scl[scl == 0] = 1 + + # Solve the least squares problem. + c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond) + c = (c.T/scl).T + + # Expand c to include non-fitted coefficients which are set to zero + if deg.ndim > 0: + if c.ndim == 2: + cc = np.zeros((lmax + 1, c.shape[1]), dtype=c.dtype) + else: + cc = np.zeros(lmax + 1, dtype=c.dtype) + cc[deg] = c + c = cc + + # warn on rank reduction + if rank != order and not full: + msg = "The fit may be poorly conditioned" + warnings.warn(msg, pu.RankWarning, stacklevel=2) + + if full: + return c, [resids, rank, s, rcond] + else: + return c + + +def chebcompanion(c): + """Return the scaled companion matrix of c. + + The basis polynomials are scaled so that the companion matrix is + symmetric when `c` is a Chebyshev basis polynomial. This provides + better eigenvalue estimates than the unscaled case and for basis + polynomials the eigenvalues are guaranteed to be real if + `numpy.linalg.eigvalsh` is used to obtain them. + + Parameters + ---------- + c : array_like + 1-D array of Chebyshev series coefficients ordered from low to high + degree. + + Returns + ------- + mat : ndarray + Scaled companion matrix of dimensions (deg, deg). + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + raise ValueError('Series must have maximum degree of at least 1.') + if len(c) == 2: + return np.array([[-c[0]/c[1]]]) + + n = len(c) - 1 + mat = np.zeros((n, n), dtype=c.dtype) + scl = np.array([1.] + [np.sqrt(.5)]*(n-1)) + top = mat.reshape(-1)[1::n+1] + bot = mat.reshape(-1)[n::n+1] + top[0] = np.sqrt(.5) + top[1:] = 1/2 + bot[...] = top + mat[:, -1] -= (c[:-1]/c[-1])*(scl/scl[-1])*.5 + return mat + + +def chebroots(c): + """ + Compute the roots of a Chebyshev series. + + Return the roots (a.k.a. "zeros") of the polynomial + + .. math:: p(x) = \\sum_i c[i] * T_i(x). + + Parameters + ---------- + c : 1-D array_like + 1-D array of coefficients. + + Returns + ------- + out : ndarray + Array of the roots of the series. If all the roots are real, + then `out` is also real, otherwise it is complex. + + See Also + -------- + polyroots, legroots, lagroots, hermroots, hermeroots + + Notes + ----- + The root estimates are obtained as the eigenvalues of the companion + matrix, Roots far from the origin of the complex plane may have large + errors due to the numerical instability of the series for such + values. Roots with multiplicity greater than 1 will also show larger + errors as the value of the series near such points is relatively + insensitive to errors in the roots. Isolated roots near the origin can + be improved by a few iterations of Newton's method. + + The Chebyshev series basis polynomials aren't powers of `x` so the + results of this function may seem unintuitive. + + Examples + -------- + >>> import numpy.polynomial.chebyshev as cheb + >>> cheb.chebroots((-1, 1,-1, 1)) # T3 - T2 + T1 - T0 has real roots + array([ -5.00000000e-01, 2.60860684e-17, 1.00000000e+00]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + return np.array([], dtype=c.dtype) + if len(c) == 2: + return np.array([-c[0]/c[1]]) + + m = chebcompanion(c) + r = la.eigvals(m) + r.sort() + return r + + +def chebinterpolate(func, deg, args=()): + """Interpolate a function at the Chebyshev points of the first kind. + + Returns the Chebyshev series that interpolates `func` at the Chebyshev + points of the first kind in the interval [-1, 1]. The interpolating + series tends to a minmax approximation to `func` with increasing `deg` + if the function is continuous in the interval. + + .. versionadded:: 1.14.0 + + Parameters + ---------- + func : function + The function to be approximated. It must be a function of a single + variable of the form ``f(x, a, b, c...)``, where ``a, b, c...`` are + extra arguments passed in the `args` parameter. + deg : int + Degree of the interpolating polynomial + args : tuple, optional + Extra arguments to be used in the function call. Default is no extra + arguments. + + Returns + ------- + coef : ndarray, shape (deg + 1,) + Chebyshev coefficients of the interpolating series ordered from low to + high. + + Examples + -------- + >>> import numpy.polynomial.chebyshev as C + >>> C.chebfromfunction(lambda x: np.tanh(x) + 0.5, 8) + array([ 5.00000000e-01, 8.11675684e-01, -9.86864911e-17, + -5.42457905e-02, -2.71387850e-16, 4.51658839e-03, + 2.46716228e-17, -3.79694221e-04, -3.26899002e-16]) + + Notes + ----- + + The Chebyshev polynomials used in the interpolation are orthogonal when + sampled at the Chebyshev points of the first kind. If it is desired to + constrain some of the coefficients they can simply be set to the desired + value after the interpolation, no new interpolation or fit is needed. This + is especially useful if it is known apriori that some of coefficients are + zero. For instance, if the function is even then the coefficients of the + terms of odd degree in the result can be set to zero. + + """ + deg = np.asarray(deg) + + # check arguments. + if deg.ndim > 0 or deg.dtype.kind not in 'iu' or deg.size == 0: + raise TypeError("deg must be an int") + if deg < 0: + raise ValueError("expected deg >= 0") + + order = deg + 1 + xcheb = chebpts1(order) + yfunc = func(xcheb, *args) + m = chebvander(xcheb, deg) + c = np.dot(m.T, yfunc) + c[0] /= order + c[1:] /= 0.5*order + + return c + + +def chebgauss(deg): + """ + Gauss-Chebyshev quadrature. + + Computes the sample points and weights for Gauss-Chebyshev quadrature. + These sample points and weights will correctly integrate polynomials of + degree :math:`2*deg - 1` or less over the interval :math:`[-1, 1]` with + the weight function :math:`f(x) = 1/\\sqrt{1 - x^2}`. + + Parameters + ---------- + deg : int + Number of sample points and weights. It must be >= 1. + + Returns + ------- + x : ndarray + 1-D ndarray containing the sample points. + y : ndarray + 1-D ndarray containing the weights. + + Notes + ----- + + .. versionadded:: 1.7.0 + + The results have only been tested up to degree 100, higher degrees may + be problematic. For Gauss-Chebyshev there are closed form solutions for + the sample points and weights. If n = `deg`, then + + .. math:: x_i = \\cos(\\pi (2 i - 1) / (2 n)) + + .. math:: w_i = \\pi / n + + """ + ideg = int(deg) + if ideg != deg or ideg < 1: + raise ValueError("deg must be a non-negative integer") + + x = np.cos(np.pi * np.arange(1, 2*ideg, 2) / (2.0*ideg)) + w = np.ones(ideg)*(np.pi/ideg) + + return x, w + + +def chebweight(x): + """ + The weight function of the Chebyshev polynomials. + + The weight function is :math:`1/\\sqrt{1 - x^2}` and the interval of + integration is :math:`[-1, 1]`. The Chebyshev polynomials are + orthogonal, but not normalized, with respect to this weight function. + + Parameters + ---------- + x : array_like + Values at which the weight function will be computed. + + Returns + ------- + w : ndarray + The weight function at `x`. + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + w = 1./(np.sqrt(1. + x) * np.sqrt(1. - x)) + return w + + +def chebpts1(npts): + """ + Chebyshev points of the first kind. + + The Chebyshev points of the first kind are the points ``cos(x)``, + where ``x = [pi*(k + .5)/npts for k in range(npts)]``. + + Parameters + ---------- + npts : int + Number of sample points desired. + + Returns + ------- + pts : ndarray + The Chebyshev points of the first kind. + + See Also + -------- + chebpts2 + + Notes + ----- + + .. versionadded:: 1.5.0 + + """ + _npts = int(npts) + if _npts != npts: + raise ValueError("npts must be integer") + if _npts < 1: + raise ValueError("npts must be >= 1") + + x = np.linspace(-np.pi, 0, _npts, endpoint=False) + np.pi/(2*_npts) + return np.cos(x) + + +def chebpts2(npts): + """ + Chebyshev points of the second kind. + + The Chebyshev points of the second kind are the points ``cos(x)``, + where ``x = [pi*k/(npts - 1) for k in range(npts)]``. + + Parameters + ---------- + npts : int + Number of sample points desired. + + Returns + ------- + pts : ndarray + The Chebyshev points of the second kind. + + Notes + ----- + + .. versionadded:: 1.5.0 + + """ + _npts = int(npts) + if _npts != npts: + raise ValueError("npts must be integer") + if _npts < 2: + raise ValueError("npts must be >= 2") + + x = np.linspace(-np.pi, 0, _npts) + return np.cos(x) + + +# +# Chebyshev series class +# + +class Chebyshev(ABCPolyBase): + """A Chebyshev series class. + + The Chebyshev class provides the standard Python numerical methods + '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the + methods listed below. + + Parameters + ---------- + coef : array_like + Chebyshev coefficients in order of increasing degree, i.e., + ``(1, 2, 3)`` gives ``1*T_0(x) + 2*T_1(x) + 3*T_2(x)``. + domain : (2,) array_like, optional + Domain to use. The interval ``[domain[0], domain[1]]`` is mapped + to the interval ``[window[0], window[1]]`` by shifting and scaling. + The default value is [-1, 1]. + window : (2,) array_like, optional + Window, see `domain` for its use. The default value is [-1, 1]. + + .. versionadded:: 1.6.0 + + """ + # Virtual Functions + _add = staticmethod(chebadd) + _sub = staticmethod(chebsub) + _mul = staticmethod(chebmul) + _div = staticmethod(chebdiv) + _pow = staticmethod(chebpow) + _val = staticmethod(chebval) + _int = staticmethod(chebint) + _der = staticmethod(chebder) + _fit = staticmethod(chebfit) + _line = staticmethod(chebline) + _roots = staticmethod(chebroots) + _fromroots = staticmethod(chebfromroots) + + @classmethod + def interpolate(cls, func, deg, domain=None, args=()): + """Interpolate a function at the Chebyshev points of the first kind. + + Returns the series that interpolates `func` at the Chebyshev points of + the first kind scaled and shifted to the `domain`. The resulting series + tends to a minmax approximation of `func` when the function is + continuous in the domain. + + .. versionadded:: 1.14.0 + + Parameters + ---------- + func : function + The function to be interpolated. It must be a function of a single + variable of the form ``f(x, a, b, c...)``, where ``a, b, c...`` are + extra arguments passed in the `args` parameter. + deg : int + Degree of the interpolating polynomial. + domain : {None, [beg, end]}, optional + Domain over which `func` is interpolated. The default is None, in + which case the domain is [-1, 1]. + args : tuple, optional + Extra arguments to be used in the function call. Default is no + extra arguments. + + Returns + ------- + polynomial : Chebyshev instance + Interpolating Chebyshev instance. + + Notes + ----- + See `numpy.polynomial.chebfromfunction` for more details. + + """ + if domain is None: + domain = cls.domain + xfunc = lambda x: func(pu.mapdomain(x, cls.window, domain), *args) + coef = chebinterpolate(xfunc, deg) + return cls(coef, domain=domain) + + # Virtual properties + nickname = 'cheb' + domain = np.array(chebdomain) + window = np.array(chebdomain) diff --git a/numpy/polynomial/hermite.py b/numpy/polynomial/hermite.py new file mode 100644 index 0000000..58e9e18 --- /dev/null +++ b/numpy/polynomial/hermite.py @@ -0,0 +1,1853 @@ +""" +Objects for dealing with Hermite series. + +This module provides a number of objects (mostly functions) useful for +dealing with Hermite series, including a `Hermite` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Constants +--------- +- `hermdomain` -- Hermite series default domain, [-1,1]. +- `hermzero` -- Hermite series that evaluates identically to 0. +- `hermone` -- Hermite series that evaluates identically to 1. +- `hermx` -- Hermite series for the identity map, ``f(x) = x``. + +Arithmetic +---------- +- `hermmulx` -- multiply a Hermite series in ``P_i(x)`` by ``x``. +- `hermadd` -- add two Hermite series. +- `hermsub` -- subtract one Hermite series from another. +- `hermmul` -- multiply two Hermite series. +- `hermdiv` -- divide one Hermite series by another. +- `hermval` -- evaluate a Hermite series at given points. +- `hermval2d` -- evaluate a 2D Hermite series at given points. +- `hermval3d` -- evaluate a 3D Hermite series at given points. +- `hermgrid2d` -- evaluate a 2D Hermite series on a Cartesian product. +- `hermgrid3d` -- evaluate a 3D Hermite series on a Cartesian product. + +Calculus +-------- +- `hermder` -- differentiate a Hermite series. +- `hermint` -- integrate a Hermite series. + +Misc Functions +-------------- +- `hermfromroots` -- create a Hermite series with specified roots. +- `hermroots` -- find the roots of a Hermite series. +- `hermvander` -- Vandermonde-like matrix for Hermite polynomials. +- `hermvander2d` -- Vandermonde-like matrix for 2D power series. +- `hermvander3d` -- Vandermonde-like matrix for 3D power series. +- `hermgauss` -- Gauss-Hermite quadrature, points and weights. +- `hermweight` -- Hermite weight function. +- `hermcompanion` -- symmetrized companion matrix in Hermite form. +- `hermfit` -- least-squares fit returning a Hermite series. +- `hermtrim` -- trim leading coefficients from a Hermite series. +- `hermline` -- Hermite series of given straight line. +- `herm2poly` -- convert a Hermite series to a polynomial. +- `poly2herm` -- convert a polynomial to a Hermite series. + +Classes +------- +- `Hermite` -- A Hermite series class. + +See also +-------- +`numpy.polynomial` + +""" +from __future__ import division, absolute_import, print_function + +import warnings +import numpy as np +import numpy.linalg as la +from numpy.core.multiarray import normalize_axis_index + +from . import polyutils as pu +from ._polybase import ABCPolyBase + +__all__ = [ + 'hermzero', 'hermone', 'hermx', 'hermdomain', 'hermline', 'hermadd', + 'hermsub', 'hermmulx', 'hermmul', 'hermdiv', 'hermpow', 'hermval', + 'hermder', 'hermint', 'herm2poly', 'poly2herm', 'hermfromroots', + 'hermvander', 'hermfit', 'hermtrim', 'hermroots', 'Hermite', + 'hermval2d', 'hermval3d', 'hermgrid2d', 'hermgrid3d', 'hermvander2d', + 'hermvander3d', 'hermcompanion', 'hermgauss', 'hermweight'] + +hermtrim = pu.trimcoef + + +def poly2herm(pol): + """ + poly2herm(pol) + + Convert a polynomial to a Hermite series. + + Convert an array representing the coefficients of a polynomial (relative + to the "standard" basis) ordered from lowest degree to highest, to an + array of the coefficients of the equivalent Hermite series, ordered + from lowest to highest degree. + + Parameters + ---------- + pol : array_like + 1-D array containing the polynomial coefficients + + Returns + ------- + c : ndarray + 1-D array containing the coefficients of the equivalent Hermite + series. + + See Also + -------- + herm2poly + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy.polynomial.hermite import poly2herm + >>> poly2herm(np.arange(4)) + array([ 1. , 2.75 , 0.5 , 0.375]) + + """ + [pol] = pu.as_series([pol]) + deg = len(pol) - 1 + res = 0 + for i in range(deg, -1, -1): + res = hermadd(hermmulx(res), pol[i]) + return res + + +def herm2poly(c): + """ + Convert a Hermite series to a polynomial. + + Convert an array representing the coefficients of a Hermite series, + ordered from lowest degree to highest, to an array of the coefficients + of the equivalent polynomial (relative to the "standard" basis) ordered + from lowest to highest degree. + + Parameters + ---------- + c : array_like + 1-D array containing the Hermite series coefficients, ordered + from lowest order term to highest. + + Returns + ------- + pol : ndarray + 1-D array containing the coefficients of the equivalent polynomial + (relative to the "standard" basis) ordered from lowest order term + to highest. + + See Also + -------- + poly2herm + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy.polynomial.hermite import herm2poly + >>> herm2poly([ 1. , 2.75 , 0.5 , 0.375]) + array([ 0., 1., 2., 3.]) + + """ + from .polynomial import polyadd, polysub, polymulx + + [c] = pu.as_series([c]) + n = len(c) + if n == 1: + return c + if n == 2: + c[1] *= 2 + return c + else: + c0 = c[-2] + c1 = c[-1] + # i is the current degree of c1 + for i in range(n - 1, 1, -1): + tmp = c0 + c0 = polysub(c[i - 2], c1*(2*(i - 1))) + c1 = polyadd(tmp, polymulx(c1)*2) + return polyadd(c0, polymulx(c1)*2) + +# +# These are constant arrays are of integer type so as to be compatible +# with the widest range of other types, such as Decimal. +# + +# Hermite +hermdomain = np.array([-1, 1]) + +# Hermite coefficients representing zero. +hermzero = np.array([0]) + +# Hermite coefficients representing one. +hermone = np.array([1]) + +# Hermite coefficients representing the identity x. +hermx = np.array([0, 1/2]) + + +def hermline(off, scl): + """ + Hermite series whose graph is a straight line. + + + + Parameters + ---------- + off, scl : scalars + The specified line is given by ``off + scl*x``. + + Returns + ------- + y : ndarray + This module's representation of the Hermite series for + ``off + scl*x``. + + See Also + -------- + polyline, chebline + + Examples + -------- + >>> from numpy.polynomial.hermite import hermline, hermval + >>> hermval(0,hermline(3, 2)) + 3.0 + >>> hermval(1,hermline(3, 2)) + 5.0 + + """ + if scl != 0: + return np.array([off, scl/2]) + else: + return np.array([off]) + + +def hermfromroots(roots): + """ + Generate a Hermite series with given roots. + + The function returns the coefficients of the polynomial + + .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n), + + in Hermite form, where the `r_n` are the roots specified in `roots`. + If a zero has multiplicity n, then it must appear in `roots` n times. + For instance, if 2 is a root of multiplicity three and 3 is a root of + multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The + roots can appear in any order. + + If the returned coefficients are `c`, then + + .. math:: p(x) = c_0 + c_1 * H_1(x) + ... + c_n * H_n(x) + + The coefficient of the last term is not generally 1 for monic + polynomials in Hermite form. + + Parameters + ---------- + roots : array_like + Sequence containing the roots. + + Returns + ------- + out : ndarray + 1-D array of coefficients. If all roots are real then `out` is a + real array, if some of the roots are complex, then `out` is complex + even if all the coefficients in the result are real (see Examples + below). + + See Also + -------- + polyfromroots, legfromroots, lagfromroots, chebfromroots, + hermefromroots. + + Examples + -------- + >>> from numpy.polynomial.hermite import hermfromroots, hermval + >>> coef = hermfromroots((-1, 0, 1)) + >>> hermval((-1, 0, 1), coef) + array([ 0., 0., 0.]) + >>> coef = hermfromroots((-1j, 1j)) + >>> hermval((-1j, 1j), coef) + array([ 0.+0.j, 0.+0.j]) + + """ + if len(roots) == 0: + return np.ones(1) + else: + [roots] = pu.as_series([roots], trim=False) + roots.sort() + p = [hermline(-r, 1) for r in roots] + n = len(p) + while n > 1: + m, r = divmod(n, 2) + tmp = [hermmul(p[i], p[i+m]) for i in range(m)] + if r: + tmp[0] = hermmul(tmp[0], p[-1]) + p = tmp + n = m + return p[0] + + +def hermadd(c1, c2): + """ + Add one Hermite series to another. + + Returns the sum of two Hermite series `c1` + `c2`. The arguments + are sequences of coefficients ordered from lowest order term to + highest, i.e., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Hermite series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the Hermite series of their sum. + + See Also + -------- + hermsub, hermmul, hermdiv, hermpow + + Notes + ----- + Unlike multiplication, division, etc., the sum of two Hermite series + is a Hermite series (without having to "reproject" the result onto + the basis set) so addition, just like that of "standard" polynomials, + is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial.hermite import hermadd + >>> hermadd([1, 2, 3], [1, 2, 3, 4]) + array([ 2., 4., 6., 4.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] += c2 + ret = c1 + else: + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def hermsub(c1, c2): + """ + Subtract one Hermite series from another. + + Returns the difference of two Hermite series `c1` - `c2`. The + sequences of coefficients are from lowest order term to highest, i.e., + [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Hermite series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Hermite series coefficients representing their difference. + + See Also + -------- + hermadd, hermmul, hermdiv, hermpow + + Notes + ----- + Unlike multiplication, division, etc., the difference of two Hermite + series is a Hermite series (without having to "reproject" the result + onto the basis set) so subtraction, just like that of "standard" + polynomials, is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial.hermite import hermsub + >>> hermsub([1, 2, 3, 4], [1, 2, 3]) + array([ 0., 0., 0., 4.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] -= c2 + ret = c1 + else: + c2 = -c2 + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def hermmulx(c): + """Multiply a Hermite series by x. + + Multiply the Hermite series `c` by x, where x is the independent + variable. + + + Parameters + ---------- + c : array_like + 1-D array of Hermite series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the result of the multiplication. + + Notes + ----- + The multiplication uses the recursion relationship for Hermite + polynomials in the form + + .. math:: + + xP_i(x) = (P_{i + 1}(x)/2 + i*P_{i - 1}(x)) + + Examples + -------- + >>> from numpy.polynomial.hermite import hermmulx + >>> hermmulx([1, 2, 3]) + array([ 2. , 6.5, 1. , 1.5]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + # The zero series needs special treatment + if len(c) == 1 and c[0] == 0: + return c + + prd = np.empty(len(c) + 1, dtype=c.dtype) + prd[0] = c[0]*0 + prd[1] = c[0]/2 + for i in range(1, len(c)): + prd[i + 1] = c[i]/2 + prd[i - 1] += c[i]*i + return prd + + +def hermmul(c1, c2): + """ + Multiply one Hermite series by another. + + Returns the product of two Hermite series `c1` * `c2`. The arguments + are sequences of coefficients, from lowest order "term" to highest, + e.g., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Hermite series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Hermite series coefficients representing their product. + + See Also + -------- + hermadd, hermsub, hermdiv, hermpow + + Notes + ----- + In general, the (polynomial) product of two C-series results in terms + that are not in the Hermite polynomial basis set. Thus, to express + the product as a Hermite series, it is necessary to "reproject" the + product onto said basis set, which may produce "unintuitive" (but + correct) results; see Examples section below. + + Examples + -------- + >>> from numpy.polynomial.hermite import hermmul + >>> hermmul([1, 2, 3], [0, 1, 2]) + array([ 52., 29., 52., 7., 6.]) + + """ + # s1, s2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + + if len(c1) > len(c2): + c = c2 + xs = c1 + else: + c = c1 + xs = c2 + + if len(c) == 1: + c0 = c[0]*xs + c1 = 0 + elif len(c) == 2: + c0 = c[0]*xs + c1 = c[1]*xs + else: + nd = len(c) + c0 = c[-2]*xs + c1 = c[-1]*xs + for i in range(3, len(c) + 1): + tmp = c0 + nd = nd - 1 + c0 = hermsub(c[-i]*xs, c1*(2*(nd - 1))) + c1 = hermadd(tmp, hermmulx(c1)*2) + return hermadd(c0, hermmulx(c1)*2) + + +def hermdiv(c1, c2): + """ + Divide one Hermite series by another. + + Returns the quotient-with-remainder of two Hermite series + `c1` / `c2`. The arguments are sequences of coefficients from lowest + order "term" to highest, e.g., [1,2,3] represents the series + ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Hermite series coefficients ordered from low to + high. + + Returns + ------- + [quo, rem] : ndarrays + Of Hermite series coefficients representing the quotient and + remainder. + + See Also + -------- + hermadd, hermsub, hermmul, hermpow + + Notes + ----- + In general, the (polynomial) division of one Hermite series by another + results in quotient and remainder terms that are not in the Hermite + polynomial basis set. Thus, to express these results as a Hermite + series, it is necessary to "reproject" the results onto the Hermite + basis set, which may produce "unintuitive" (but correct) results; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial.hermite import hermdiv + >>> hermdiv([ 52., 29., 52., 7., 6.], [0, 1, 2]) + (array([ 1., 2., 3.]), array([ 0.])) + >>> hermdiv([ 54., 31., 52., 7., 6.], [0, 1, 2]) + (array([ 1., 2., 3.]), array([ 2., 2.])) + >>> hermdiv([ 53., 30., 52., 7., 6.], [0, 1, 2]) + (array([ 1., 2., 3.]), array([ 1., 1.])) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if c2[-1] == 0: + raise ZeroDivisionError() + + lc1 = len(c1) + lc2 = len(c2) + if lc1 < lc2: + return c1[:1]*0, c1 + elif lc2 == 1: + return c1/c2[-1], c1[:1]*0 + else: + quo = np.empty(lc1 - lc2 + 1, dtype=c1.dtype) + rem = c1 + for i in range(lc1 - lc2, - 1, -1): + p = hermmul([0]*i + [1], c2) + q = rem[-1]/p[-1] + rem = rem[:-1] - q*p[:-1] + quo[i] = q + return quo, pu.trimseq(rem) + + +def hermpow(c, pow, maxpower=16): + """Raise a Hermite series to a power. + + Returns the Hermite series `c` raised to the power `pow`. The + argument `c` is a sequence of coefficients ordered from low to high. + i.e., [1,2,3] is the series ``P_0 + 2*P_1 + 3*P_2.`` + + Parameters + ---------- + c : array_like + 1-D array of Hermite series coefficients ordered from low to + high. + pow : integer + Power to which the series will be raised + maxpower : integer, optional + Maximum power allowed. This is mainly to limit growth of the series + to unmanageable size. Default is 16 + + Returns + ------- + coef : ndarray + Hermite series of power. + + See Also + -------- + hermadd, hermsub, hermmul, hermdiv + + Examples + -------- + >>> from numpy.polynomial.hermite import hermpow + >>> hermpow([1, 2, 3], 2) + array([ 81., 52., 82., 12., 9.]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + power = int(pow) + if power != pow or power < 0: + raise ValueError("Power must be a non-negative integer.") + elif maxpower is not None and power > maxpower: + raise ValueError("Power is too large") + elif power == 0: + return np.array([1], dtype=c.dtype) + elif power == 1: + return c + else: + # This can be made more efficient by using powers of two + # in the usual way. + prd = c + for i in range(2, power + 1): + prd = hermmul(prd, c) + return prd + + +def hermder(c, m=1, scl=1, axis=0): + """ + Differentiate a Hermite series. + + Returns the Hermite series coefficients `c` differentiated `m` times + along `axis`. At each iteration the result is multiplied by `scl` (the + scaling factor is for use in a linear change of variable). The argument + `c` is an array of coefficients from low to high degree along each + axis, e.g., [1,2,3] represents the series ``1*H_0 + 2*H_1 + 3*H_2`` + while [[1,2],[1,2]] represents ``1*H_0(x)*H_0(y) + 1*H_1(x)*H_0(y) + + 2*H_0(x)*H_1(y) + 2*H_1(x)*H_1(y)`` if axis=0 is ``x`` and axis=1 is + ``y``. + + Parameters + ---------- + c : array_like + Array of Hermite series coefficients. If `c` is multidimensional the + different axis correspond to different variables with the degree in + each axis given by the corresponding index. + m : int, optional + Number of derivatives taken, must be non-negative. (Default: 1) + scl : scalar, optional + Each differentiation is multiplied by `scl`. The end result is + multiplication by ``scl**m``. This is for use in a linear change of + variable. (Default: 1) + axis : int, optional + Axis over which the derivative is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + der : ndarray + Hermite series of the derivative. + + See Also + -------- + hermint + + Notes + ----- + In general, the result of differentiating a Hermite series does not + resemble the same operation on a power series. Thus the result of this + function may be "unintuitive," albeit correct; see Examples section + below. + + Examples + -------- + >>> from numpy.polynomial.hermite import hermder + >>> hermder([ 1. , 0.5, 0.5, 0.5]) + array([ 1., 2., 3.]) + >>> hermder([-0.5, 1./2., 1./8., 1./12., 1./16.], m=2) + array([ 1., 2., 3.]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of derivation must be integer") + if cnt < 0: + raise ValueError("The order of derivation must be non-negative") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + n = len(c) + if cnt >= n: + c = c[:1]*0 + else: + for i in range(cnt): + n = n - 1 + c *= scl + der = np.empty((n,) + c.shape[1:], dtype=c.dtype) + for j in range(n, 0, -1): + der[j - 1] = (2*j)*c[j] + c = der + c = np.moveaxis(c, 0, iaxis) + return c + + +def hermint(c, m=1, k=[], lbnd=0, scl=1, axis=0): + """ + Integrate a Hermite series. + + Returns the Hermite series coefficients `c` integrated `m` times from + `lbnd` along `axis`. At each iteration the resulting series is + **multiplied** by `scl` and an integration constant, `k`, is added. + The scaling factor is for use in a linear change of variable. ("Buyer + beware": note that, depending on what one is doing, one may want `scl` + to be the reciprocal of what one might expect; for more information, + see the Notes section below.) The argument `c` is an array of + coefficients from low to high degree along each axis, e.g., [1,2,3] + represents the series ``H_0 + 2*H_1 + 3*H_2`` while [[1,2],[1,2]] + represents ``1*H_0(x)*H_0(y) + 1*H_1(x)*H_0(y) + 2*H_0(x)*H_1(y) + + 2*H_1(x)*H_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. + + Parameters + ---------- + c : array_like + Array of Hermite series coefficients. If c is multidimensional the + different axis correspond to different variables with the degree in + each axis given by the corresponding index. + m : int, optional + Order of integration, must be positive. (Default: 1) + k : {[], list, scalar}, optional + Integration constant(s). The value of the first integral at + ``lbnd`` is the first value in the list, the value of the second + integral at ``lbnd`` is the second value, etc. If ``k == []`` (the + default), all constants are set to zero. If ``m == 1``, a single + scalar can be given instead of a list. + lbnd : scalar, optional + The lower bound of the integral. (Default: 0) + scl : scalar, optional + Following each integration the result is *multiplied* by `scl` + before the integration constant is added. (Default: 1) + axis : int, optional + Axis over which the integral is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + S : ndarray + Hermite series coefficients of the integral. + + Raises + ------ + ValueError + If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or + ``np.ndim(scl) != 0``. + + See Also + -------- + hermder + + Notes + ----- + Note that the result of each integration is *multiplied* by `scl`. + Why is this important to note? Say one is making a linear change of + variable :math:`u = ax + b` in an integral relative to `x`. Then + :math:`dx = du/a`, so one will need to set `scl` equal to + :math:`1/a` - perhaps not what one would have first thought. + + Also note that, in general, the result of integrating a C-series needs + to be "reprojected" onto the C-series basis set. Thus, typically, + the result of this function is "unintuitive," albeit correct; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial.hermite import hermint + >>> hermint([1,2,3]) # integrate once, value 0 at 0. + array([ 1. , 0.5, 0.5, 0.5]) + >>> hermint([1,2,3], m=2) # integrate twice, value & deriv 0 at 0 + array([-0.5 , 0.5 , 0.125 , 0.08333333, 0.0625 ]) + >>> hermint([1,2,3], k=1) # integrate once, value 1 at 0. + array([ 2. , 0.5, 0.5, 0.5]) + >>> hermint([1,2,3], lbnd=-1) # integrate once, value 0 at -1 + array([-2. , 0.5, 0.5, 0.5]) + >>> hermint([1,2,3], m=2, k=[1,2], lbnd=-1) + array([ 1.66666667, -0.5 , 0.125 , 0.08333333, 0.0625 ]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if not np.iterable(k): + k = [k] + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of integration must be integer") + if cnt < 0: + raise ValueError("The order of integration must be non-negative") + if len(k) > cnt: + raise ValueError("Too many integration constants") + if np.ndim(lbnd) != 0: + raise ValueError("lbnd must be a scalar.") + if np.ndim(scl) != 0: + raise ValueError("scl must be a scalar.") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + k = list(k) + [0]*(cnt - len(k)) + for i in range(cnt): + n = len(c) + c *= scl + if n == 1 and np.all(c[0] == 0): + c[0] += k[i] + else: + tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype) + tmp[0] = c[0]*0 + tmp[1] = c[0]/2 + for j in range(1, n): + tmp[j + 1] = c[j]/(2*(j + 1)) + tmp[0] += k[i] - hermval(lbnd, tmp) + c = tmp + c = np.moveaxis(c, 0, iaxis) + return c + + +def hermval(x, c, tensor=True): + """ + Evaluate an Hermite series at points x. + + If `c` is of length `n + 1`, this function returns the value: + + .. math:: p(x) = c_0 * H_0(x) + c_1 * H_1(x) + ... + c_n * H_n(x) + + The parameter `x` is converted to an array only if it is a tuple or a + list, otherwise it is treated as a scalar. In either case, either `x` + or its elements must support multiplication and addition both with + themselves and with the elements of `c`. + + If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If + `c` is multidimensional, then the shape of the result depends on the + value of `tensor`. If `tensor` is true the shape will be c.shape[1:] + + x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that + scalars have shape (,). + + Trailing zeros in the coefficients will be used in the evaluation, so + they should be avoided if efficiency is a concern. + + Parameters + ---------- + x : array_like, compatible object + If `x` is a list or tuple, it is converted to an ndarray, otherwise + it is left unchanged and treated as a scalar. In either case, `x` + or its elements must support addition and multiplication with + with themselves and with the elements of `c`. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree n are contained in c[n]. If `c` is multidimensional the + remaining indices enumerate multiple polynomials. In the two + dimensional case the coefficients may be thought of as stored in + the columns of `c`. + tensor : boolean, optional + If True, the shape of the coefficient array is extended with ones + on the right, one for each dimension of `x`. Scalars have dimension 0 + for this action. The result is that every column of coefficients in + `c` is evaluated for every element of `x`. If False, `x` is broadcast + over the columns of `c` for the evaluation. This keyword is useful + when `c` is multidimensional. The default value is True. + + .. versionadded:: 1.7.0 + + Returns + ------- + values : ndarray, algebra_like + The shape of the return value is described above. + + See Also + -------- + hermval2d, hermgrid2d, hermval3d, hermgrid3d + + Notes + ----- + The evaluation uses Clenshaw recursion, aka synthetic division. + + Examples + -------- + >>> from numpy.polynomial.hermite import hermval + >>> coef = [1,2,3] + >>> hermval(1, coef) + 11.0 + >>> hermval([[1,2],[3,4]], coef) + array([[ 11., 51.], + [ 115., 203.]]) + + """ + c = np.array(c, ndmin=1, copy=0) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if isinstance(x, (tuple, list)): + x = np.asarray(x) + if isinstance(x, np.ndarray) and tensor: + c = c.reshape(c.shape + (1,)*x.ndim) + + x2 = x*2 + if len(c) == 1: + c0 = c[0] + c1 = 0 + elif len(c) == 2: + c0 = c[0] + c1 = c[1] + else: + nd = len(c) + c0 = c[-2] + c1 = c[-1] + for i in range(3, len(c) + 1): + tmp = c0 + nd = nd - 1 + c0 = c[-i] - c1*(2*(nd - 1)) + c1 = tmp + c1*x2 + return c0 + c1*x2 + + +def hermval2d(x, y, c): + """ + Evaluate a 2-D Hermite series at points (x, y). + + This function returns the values: + + .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * H_i(x) * H_j(y) + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars and they + must have the same shape after conversion. In either case, either `x` + and `y` or their elements must support multiplication and addition both + with themselves and with the elements of `c`. + + If `c` is a 1-D array a one is implicitly appended to its shape to make + it 2-D. The shape of the result will be c.shape[2:] + x.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points `(x, y)`, + where `x` and `y` must have the same shape. If `x` or `y` is a list + or tuple, it is first converted to an ndarray, otherwise it is left + unchanged and if it isn't an ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term + of multi-degree i,j is contained in ``c[i,j]``. If `c` has + dimension greater than two the remaining indices enumerate multiple + sets of coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points formed with + pairs of corresponding values from `x` and `y`. + + See Also + -------- + hermval, hermgrid2d, hermval3d, hermgrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y = np.array((x, y), copy=0) + except Exception: + raise ValueError('x, y are incompatible') + + c = hermval(x, c) + c = hermval(y, c, tensor=False) + return c + + +def hermgrid2d(x, y, c): + """ + Evaluate a 2-D Hermite series on the Cartesian product of x and y. + + This function returns the values: + + .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * H_i(a) * H_j(b) + + where the points `(a, b)` consist of all pairs formed by taking + `a` from `x` and `b` from `y`. The resulting points form a grid with + `x` in the first dimension and `y` in the second. + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars. In either + case, either `x` and `y` or their elements must support multiplication + and addition both with themselves and with the elements of `c`. + + If `c` has fewer than two dimensions, ones are implicitly appended to + its shape to make it 2-D. The shape of the result will be c.shape[2:] + + x.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points in the + Cartesian product of `x` and `y`. If `x` or `y` is a list or + tuple, it is first converted to an ndarray, otherwise it is left + unchanged and, if it isn't an ndarray, it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + hermval, hermval2d, hermval3d, hermgrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = hermval(x, c) + c = hermval(y, c) + return c + + +def hermval3d(x, y, z, c): + """ + Evaluate a 3-D Hermite series at points (x, y, z). + + This function returns the values: + + .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * H_i(x) * H_j(y) * H_k(z) + + The parameters `x`, `y`, and `z` are converted to arrays only if + they are tuples or a lists, otherwise they are treated as a scalars and + they must have the same shape after conversion. In either case, either + `x`, `y`, and `z` or their elements must support multiplication and + addition both with themselves and with the elements of `c`. + + If `c` has fewer than 3 dimensions, ones are implicitly appended to its + shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape. + + Parameters + ---------- + x, y, z : array_like, compatible object + The three dimensional series is evaluated at the points + `(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If + any of `x`, `y`, or `z` is a list or tuple, it is first converted + to an ndarray, otherwise it is left unchanged and if it isn't an + ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension + greater than 3 the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the multidimensional polynomial on points formed with + triples of corresponding values from `x`, `y`, and `z`. + + See Also + -------- + hermval, hermval2d, hermgrid2d, hermgrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y, z = np.array((x, y, z), copy=0) + except Exception: + raise ValueError('x, y, z are incompatible') + + c = hermval(x, c) + c = hermval(y, c, tensor=False) + c = hermval(z, c, tensor=False) + return c + + +def hermgrid3d(x, y, z, c): + """ + Evaluate a 3-D Hermite series on the Cartesian product of x, y, and z. + + This function returns the values: + + .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * H_i(a) * H_j(b) * H_k(c) + + where the points `(a, b, c)` consist of all triples formed by taking + `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form + a grid with `x` in the first dimension, `y` in the second, and `z` in + the third. + + The parameters `x`, `y`, and `z` are converted to arrays only if they + are tuples or a lists, otherwise they are treated as a scalars. In + either case, either `x`, `y`, and `z` or their elements must support + multiplication and addition both with themselves and with the elements + of `c`. + + If `c` has fewer than three dimensions, ones are implicitly appended to + its shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape + y.shape + z.shape. + + Parameters + ---------- + x, y, z : array_like, compatible objects + The three dimensional series is evaluated at the points in the + Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a + list or tuple, it is first converted to an ndarray, otherwise it is + left unchanged and, if it isn't an ndarray, it is treated as a + scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + hermval, hermval2d, hermgrid2d, hermval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = hermval(x, c) + c = hermval(y, c) + c = hermval(z, c) + return c + + +def hermvander(x, deg): + """Pseudo-Vandermonde matrix of given degree. + + Returns the pseudo-Vandermonde matrix of degree `deg` and sample points + `x`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., i] = H_i(x), + + where `0 <= i <= deg`. The leading indices of `V` index the elements of + `x` and the last index is the degree of the Hermite polynomial. + + If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the + array ``V = hermvander(x, n)``, then ``np.dot(V, c)`` and + ``hermval(x, c)`` are the same up to roundoff. This equivalence is + useful both for least squares fitting and for the evaluation of a large + number of Hermite series of the same degree and sample points. + + Parameters + ---------- + x : array_like + Array of points. The dtype is converted to float64 or complex128 + depending on whether any of the elements are complex. If `x` is + scalar it is converted to a 1-D array. + deg : int + Degree of the resulting matrix. + + Returns + ------- + vander : ndarray + The pseudo-Vandermonde matrix. The shape of the returned matrix is + ``x.shape + (deg + 1,)``, where The last index is the degree of the + corresponding Hermite polynomial. The dtype will be the same as + the converted `x`. + + Examples + -------- + >>> from numpy.polynomial.hermite import hermvander + >>> x = np.array([-1, 0, 1]) + >>> hermvander(x, 3) + array([[ 1., -2., 2., 4.], + [ 1., 0., -2., -0.], + [ 1., 2., 2., -4.]]) + + """ + ideg = int(deg) + if ideg != deg: + raise ValueError("deg must be integer") + if ideg < 0: + raise ValueError("deg must be non-negative") + + x = np.array(x, copy=0, ndmin=1) + 0.0 + dims = (ideg + 1,) + x.shape + dtyp = x.dtype + v = np.empty(dims, dtype=dtyp) + v[0] = x*0 + 1 + if ideg > 0: + x2 = x*2 + v[1] = x2 + for i in range(2, ideg + 1): + v[i] = (v[i-1]*x2 - v[i-2]*(2*(i - 1))) + return np.moveaxis(v, 0, -1) + + +def hermvander2d(x, y, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y)`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (deg[1] + 1)*i + j] = H_i(x) * H_j(y), + + where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of + `V` index the points `(x, y)` and the last index encodes the degrees of + the Hermite polynomials. + + If ``V = hermvander2d(x, y, [xdeg, ydeg])``, then the columns of `V` + correspond to the elements of a 2-D coefficient array `c` of shape + (xdeg + 1, ydeg + 1) in the order + + .. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ... + + and ``np.dot(V, c.flat)`` and ``hermval2d(x, y, c)`` will be the same + up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 2-D Hermite + series of the same degrees and sample points. + + Parameters + ---------- + x, y : array_like + Arrays of point coordinates, all of the same shape. The dtypes + will be converted to either float64 or complex128 depending on + whether any of the elements are complex. Scalars are converted to 1-D + arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg]. + + Returns + ------- + vander2d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)`. The dtype will be the same + as the converted `x` and `y`. + + See Also + -------- + hermvander, hermvander3d. hermval2d, hermval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy = ideg + x, y = np.array((x, y), copy=0) + 0.0 + + vx = hermvander(x, degx) + vy = hermvander(y, degy) + v = vx[..., None]*vy[..., None,:] + return v.reshape(v.shape[:-2] + (-1,)) + + +def hermvander3d(x, y, z, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`, + then The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = H_i(x)*H_j(y)*H_k(z), + + where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading + indices of `V` index the points `(x, y, z)` and the last index encodes + the degrees of the Hermite polynomials. + + If ``V = hermvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns + of `V` correspond to the elements of a 3-D coefficient array `c` of + shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order + + .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},... + + and ``np.dot(V, c.flat)`` and ``hermval3d(x, y, z, c)`` will be the + same up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 3-D Hermite + series of the same degrees and sample points. + + Parameters + ---------- + x, y, z : array_like + Arrays of point coordinates, all of the same shape. The dtypes will + be converted to either float64 or complex128 depending on whether + any of the elements are complex. Scalars are converted to 1-D + arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg, z_deg]. + + Returns + ------- + vander3d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)*(deg[2]+1)`. The dtype will + be the same as the converted `x`, `y`, and `z`. + + See Also + -------- + hermvander, hermvander3d. hermval2d, hermval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy, degz = ideg + x, y, z = np.array((x, y, z), copy=0) + 0.0 + + vx = hermvander(x, degx) + vy = hermvander(y, degy) + vz = hermvander(z, degz) + v = vx[..., None, None]*vy[..., None,:, None]*vz[..., None, None,:] + return v.reshape(v.shape[:-3] + (-1,)) + + +def hermfit(x, y, deg, rcond=None, full=False, w=None): + """ + Least squares fit of Hermite series to data. + + Return the coefficients of a Hermite series of degree `deg` that is the + least squares fit to the data values `y` given at points `x`. If `y` is + 1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple + fits are done, one for each column of `y`, and the resulting + coefficients are stored in the corresponding columns of a 2-D return. + The fitted polynomial(s) are in the form + + .. math:: p(x) = c_0 + c_1 * H_1(x) + ... + c_n * H_n(x), + + where `n` is `deg`. + + Parameters + ---------- + x : array_like, shape (M,) + x-coordinates of the M sample points ``(x[i], y[i])``. + y : array_like, shape (M,) or (M, K) + y-coordinates of the sample points. Several data sets of sample + points sharing the same x-coordinates can be fitted at once by + passing in a 2D-array that contains one dataset per column. + deg : int or 1-D array_like + Degree(s) of the fitting polynomials. If `deg` is a single integer + all terms up to and including the `deg`'th term are included in the + fit. For NumPy versions >= 1.11.0 a list of integers specifying the + degrees of the terms to include may be used instead. + rcond : float, optional + Relative condition number of the fit. Singular values smaller than + this relative to the largest singular value will be ignored. The + default value is len(x)*eps, where eps is the relative precision of + the float type, about 2e-16 in most cases. + full : bool, optional + Switch determining nature of return value. When it is False (the + default) just the coefficients are returned, when True diagnostic + information from the singular value decomposition is also returned. + w : array_like, shape (`M`,), optional + Weights. If not None, the contribution of each point + ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the + weights are chosen so that the errors of the products ``w[i]*y[i]`` + all have the same variance. The default value is None. + + Returns + ------- + coef : ndarray, shape (M,) or (M, K) + Hermite coefficients ordered from low to high. If `y` was 2-D, + the coefficients for the data in column k of `y` are in column + `k`. + + [residuals, rank, singular_values, rcond] : list + These values are only returned if `full` = True + + resid -- sum of squared residuals of the least squares fit + rank -- the numerical rank of the scaled Vandermonde matrix + sv -- singular values of the scaled Vandermonde matrix + rcond -- value of `rcond`. + + For more details, see `linalg.lstsq`. + + Warns + ----- + RankWarning + The rank of the coefficient matrix in the least-squares fit is + deficient. The warning is only raised if `full` = False. The + warnings can be turned off by + + >>> import warnings + >>> warnings.simplefilter('ignore', RankWarning) + + See Also + -------- + chebfit, legfit, lagfit, polyfit, hermefit + hermval : Evaluates a Hermite series. + hermvander : Vandermonde matrix of Hermite series. + hermweight : Hermite weight function + linalg.lstsq : Computes a least-squares fit from the matrix. + scipy.interpolate.UnivariateSpline : Computes spline fits. + + Notes + ----- + The solution is the coefficients of the Hermite series `p` that + minimizes the sum of the weighted squared errors + + .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2, + + where the :math:`w_j` are the weights. This problem is solved by + setting up the (typically) overdetermined matrix equation + + .. math:: V(x) * c = w * y, + + where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the + coefficients to be solved for, `w` are the weights, `y` are the + observed values. This equation is then solved using the singular value + decomposition of `V`. + + If some of the singular values of `V` are so small that they are + neglected, then a `RankWarning` will be issued. This means that the + coefficient values may be poorly determined. Using a lower order fit + will usually get rid of the warning. The `rcond` parameter can also be + set to a value smaller than its default, but the resulting fit may be + spurious and have large contributions from roundoff error. + + Fits using Hermite series are probably most useful when the data can be + approximated by ``sqrt(w(x)) * p(x)``, where `w(x)` is the Hermite + weight. In that case the weight ``sqrt(w(x[i])`` should be used + together with data values ``y[i]/sqrt(w(x[i])``. The weight function is + available as `hermweight`. + + References + ---------- + .. [1] Wikipedia, "Curve fitting", + http://en.wikipedia.org/wiki/Curve_fitting + + Examples + -------- + >>> from numpy.polynomial.hermite import hermfit, hermval + >>> x = np.linspace(-10, 10) + >>> err = np.random.randn(len(x))/10 + >>> y = hermval(x, [1, 2, 3]) + err + >>> hermfit(x, y, 2) + array([ 0.97902637, 1.99849131, 3.00006 ]) + + """ + x = np.asarray(x) + 0.0 + y = np.asarray(y) + 0.0 + deg = np.asarray(deg) + + # check arguments. + if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0: + raise TypeError("deg must be an int or non-empty 1-D array of int") + if deg.min() < 0: + raise ValueError("expected deg >= 0") + if x.ndim != 1: + raise TypeError("expected 1D vector for x") + if x.size == 0: + raise TypeError("expected non-empty vector for x") + if y.ndim < 1 or y.ndim > 2: + raise TypeError("expected 1D or 2D array for y") + if len(x) != len(y): + raise TypeError("expected x and y to have same length") + + if deg.ndim == 0: + lmax = deg + order = lmax + 1 + van = hermvander(x, lmax) + else: + deg = np.sort(deg) + lmax = deg[-1] + order = len(deg) + van = hermvander(x, lmax)[:, deg] + + # set up the least squares matrices in transposed form + lhs = van.T + rhs = y.T + if w is not None: + w = np.asarray(w) + 0.0 + if w.ndim != 1: + raise TypeError("expected 1D vector for w") + if len(x) != len(w): + raise TypeError("expected x and w to have same length") + # apply weights. Don't use inplace operations as they + # can cause problems with NA. + lhs = lhs * w + rhs = rhs * w + + # set rcond + if rcond is None: + rcond = len(x)*np.finfo(x.dtype).eps + + # Determine the norms of the design matrix columns. + if issubclass(lhs.dtype.type, np.complexfloating): + scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1)) + else: + scl = np.sqrt(np.square(lhs).sum(1)) + scl[scl == 0] = 1 + + # Solve the least squares problem. + c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond) + c = (c.T/scl).T + + # Expand c to include non-fitted coefficients which are set to zero + if deg.ndim > 0: + if c.ndim == 2: + cc = np.zeros((lmax+1, c.shape[1]), dtype=c.dtype) + else: + cc = np.zeros(lmax+1, dtype=c.dtype) + cc[deg] = c + c = cc + + # warn on rank reduction + if rank != order and not full: + msg = "The fit may be poorly conditioned" + warnings.warn(msg, pu.RankWarning, stacklevel=2) + + if full: + return c, [resids, rank, s, rcond] + else: + return c + + +def hermcompanion(c): + """Return the scaled companion matrix of c. + + The basis polynomials are scaled so that the companion matrix is + symmetric when `c` is an Hermite basis polynomial. This provides + better eigenvalue estimates than the unscaled case and for basis + polynomials the eigenvalues are guaranteed to be real if + `numpy.linalg.eigvalsh` is used to obtain them. + + Parameters + ---------- + c : array_like + 1-D array of Hermite series coefficients ordered from low to high + degree. + + Returns + ------- + mat : ndarray + Scaled companion matrix of dimensions (deg, deg). + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + raise ValueError('Series must have maximum degree of at least 1.') + if len(c) == 2: + return np.array([[-.5*c[0]/c[1]]]) + + n = len(c) - 1 + mat = np.zeros((n, n), dtype=c.dtype) + scl = np.hstack((1., 1./np.sqrt(2.*np.arange(n - 1, 0, -1)))) + scl = np.multiply.accumulate(scl)[::-1] + top = mat.reshape(-1)[1::n+1] + bot = mat.reshape(-1)[n::n+1] + top[...] = np.sqrt(.5*np.arange(1, n)) + bot[...] = top + mat[:, -1] -= scl*c[:-1]/(2.0*c[-1]) + return mat + + +def hermroots(c): + """ + Compute the roots of a Hermite series. + + Return the roots (a.k.a. "zeros") of the polynomial + + .. math:: p(x) = \\sum_i c[i] * H_i(x). + + Parameters + ---------- + c : 1-D array_like + 1-D array of coefficients. + + Returns + ------- + out : ndarray + Array of the roots of the series. If all the roots are real, + then `out` is also real, otherwise it is complex. + + See Also + -------- + polyroots, legroots, lagroots, chebroots, hermeroots + + Notes + ----- + The root estimates are obtained as the eigenvalues of the companion + matrix, Roots far from the origin of the complex plane may have large + errors due to the numerical instability of the series for such + values. Roots with multiplicity greater than 1 will also show larger + errors as the value of the series near such points is relatively + insensitive to errors in the roots. Isolated roots near the origin can + be improved by a few iterations of Newton's method. + + The Hermite series basis polynomials aren't powers of `x` so the + results of this function may seem unintuitive. + + Examples + -------- + >>> from numpy.polynomial.hermite import hermroots, hermfromroots + >>> coef = hermfromroots([-1, 0, 1]) + >>> coef + array([ 0. , 0.25 , 0. , 0.125]) + >>> hermroots(coef) + array([ -1.00000000e+00, -1.38777878e-17, 1.00000000e+00]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) <= 1: + return np.array([], dtype=c.dtype) + if len(c) == 2: + return np.array([-.5*c[0]/c[1]]) + + m = hermcompanion(c) + r = la.eigvals(m) + r.sort() + return r + + +def _normed_hermite_n(x, n): + """ + Evaluate a normalized Hermite polynomial. + + Compute the value of the normalized Hermite polynomial of degree ``n`` + at the points ``x``. + + + Parameters + ---------- + x : ndarray of double. + Points at which to evaluate the function + n : int + Degree of the normalized Hermite function to be evaluated. + + Returns + ------- + values : ndarray + The shape of the return value is described above. + + Notes + ----- + .. versionadded:: 1.10.0 + + This function is needed for finding the Gauss points and integration + weights for high degrees. The values of the standard Hermite functions + overflow when n >= 207. + + """ + if n == 0: + return np.ones(x.shape)/np.sqrt(np.sqrt(np.pi)) + + c0 = 0. + c1 = 1./np.sqrt(np.sqrt(np.pi)) + nd = float(n) + for i in range(n - 1): + tmp = c0 + c0 = -c1*np.sqrt((nd - 1.)/nd) + c1 = tmp + c1*x*np.sqrt(2./nd) + nd = nd - 1.0 + return c0 + c1*x*np.sqrt(2) + + +def hermgauss(deg): + """ + Gauss-Hermite quadrature. + + Computes the sample points and weights for Gauss-Hermite quadrature. + These sample points and weights will correctly integrate polynomials of + degree :math:`2*deg - 1` or less over the interval :math:`[-\\inf, \\inf]` + with the weight function :math:`f(x) = \\exp(-x^2)`. + + Parameters + ---------- + deg : int + Number of sample points and weights. It must be >= 1. + + Returns + ------- + x : ndarray + 1-D ndarray containing the sample points. + y : ndarray + 1-D ndarray containing the weights. + + Notes + ----- + + .. versionadded:: 1.7.0 + + The results have only been tested up to degree 100, higher degrees may + be problematic. The weights are determined by using the fact that + + .. math:: w_k = c / (H'_n(x_k) * H_{n-1}(x_k)) + + where :math:`c` is a constant independent of :math:`k` and :math:`x_k` + is the k'th root of :math:`H_n`, and then scaling the results to get + the right value when integrating 1. + + """ + ideg = int(deg) + if ideg != deg or ideg < 1: + raise ValueError("deg must be a non-negative integer") + + # first approximation of roots. We use the fact that the companion + # matrix is symmetric in this case in order to obtain better zeros. + c = np.array([0]*deg + [1], dtype=np.float64) + m = hermcompanion(c) + x = la.eigvalsh(m) + + # improve roots by one application of Newton + dy = _normed_hermite_n(x, ideg) + df = _normed_hermite_n(x, ideg - 1) * np.sqrt(2*ideg) + x -= dy/df + + # compute the weights. We scale the factor to avoid possible numerical + # overflow. + fm = _normed_hermite_n(x, ideg - 1) + fm /= np.abs(fm).max() + w = 1/(fm * fm) + + # for Hermite we can also symmetrize + w = (w + w[::-1])/2 + x = (x - x[::-1])/2 + + # scale w to get the right value + w *= np.sqrt(np.pi) / w.sum() + + return x, w + + +def hermweight(x): + """ + Weight function of the Hermite polynomials. + + The weight function is :math:`\\exp(-x^2)` and the interval of + integration is :math:`[-\\inf, \\inf]`. the Hermite polynomials are + orthogonal, but not normalized, with respect to this weight function. + + Parameters + ---------- + x : array_like + Values at which the weight function will be computed. + + Returns + ------- + w : ndarray + The weight function at `x`. + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + w = np.exp(-x**2) + return w + + +# +# Hermite series class +# + +class Hermite(ABCPolyBase): + """An Hermite series class. + + The Hermite class provides the standard Python numerical methods + '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the + attributes and methods listed in the `ABCPolyBase` documentation. + + Parameters + ---------- + coef : array_like + Hermite coefficients in order of increasing degree, i.e, + ``(1, 2, 3)`` gives ``1*H_0(x) + 2*H_1(X) + 3*H_2(x)``. + domain : (2,) array_like, optional + Domain to use. The interval ``[domain[0], domain[1]]`` is mapped + to the interval ``[window[0], window[1]]`` by shifting and scaling. + The default value is [-1, 1]. + window : (2,) array_like, optional + Window, see `domain` for its use. The default value is [-1, 1]. + + .. versionadded:: 1.6.0 + + """ + # Virtual Functions + _add = staticmethod(hermadd) + _sub = staticmethod(hermsub) + _mul = staticmethod(hermmul) + _div = staticmethod(hermdiv) + _pow = staticmethod(hermpow) + _val = staticmethod(hermval) + _int = staticmethod(hermint) + _der = staticmethod(hermder) + _fit = staticmethod(hermfit) + _line = staticmethod(hermline) + _roots = staticmethod(hermroots) + _fromroots = staticmethod(hermfromroots) + + # Virtual properties + nickname = 'herm' + domain = np.array(hermdomain) + window = np.array(hermdomain) diff --git a/numpy/polynomial/hermite_e.py b/numpy/polynomial/hermite_e.py new file mode 100644 index 0000000..47b2a9f --- /dev/null +++ b/numpy/polynomial/hermite_e.py @@ -0,0 +1,1850 @@ +""" +Objects for dealing with Hermite_e series. + +This module provides a number of objects (mostly functions) useful for +dealing with Hermite_e series, including a `HermiteE` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Constants +--------- +- `hermedomain` -- Hermite_e series default domain, [-1,1]. +- `hermezero` -- Hermite_e series that evaluates identically to 0. +- `hermeone` -- Hermite_e series that evaluates identically to 1. +- `hermex` -- Hermite_e series for the identity map, ``f(x) = x``. + +Arithmetic +---------- +- `hermemulx` -- multiply a Hermite_e series in ``P_i(x)`` by ``x``. +- `hermeadd` -- add two Hermite_e series. +- `hermesub` -- subtract one Hermite_e series from another. +- `hermemul` -- multiply two Hermite_e series. +- `hermediv` -- divide one Hermite_e series by another. +- `hermeval` -- evaluate a Hermite_e series at given points. +- `hermeval2d` -- evaluate a 2D Hermite_e series at given points. +- `hermeval3d` -- evaluate a 3D Hermite_e series at given points. +- `hermegrid2d` -- evaluate a 2D Hermite_e series on a Cartesian product. +- `hermegrid3d` -- evaluate a 3D Hermite_e series on a Cartesian product. + +Calculus +-------- +- `hermeder` -- differentiate a Hermite_e series. +- `hermeint` -- integrate a Hermite_e series. + +Misc Functions +-------------- +- `hermefromroots` -- create a Hermite_e series with specified roots. +- `hermeroots` -- find the roots of a Hermite_e series. +- `hermevander` -- Vandermonde-like matrix for Hermite_e polynomials. +- `hermevander2d` -- Vandermonde-like matrix for 2D power series. +- `hermevander3d` -- Vandermonde-like matrix for 3D power series. +- `hermegauss` -- Gauss-Hermite_e quadrature, points and weights. +- `hermeweight` -- Hermite_e weight function. +- `hermecompanion` -- symmetrized companion matrix in Hermite_e form. +- `hermefit` -- least-squares fit returning a Hermite_e series. +- `hermetrim` -- trim leading coefficients from a Hermite_e series. +- `hermeline` -- Hermite_e series of given straight line. +- `herme2poly` -- convert a Hermite_e series to a polynomial. +- `poly2herme` -- convert a polynomial to a Hermite_e series. + +Classes +------- +- `HermiteE` -- A Hermite_e series class. + +See also +-------- +`numpy.polynomial` + +""" +from __future__ import division, absolute_import, print_function + +import warnings +import numpy as np +import numpy.linalg as la +from numpy.core.multiarray import normalize_axis_index + +from . import polyutils as pu +from ._polybase import ABCPolyBase + +__all__ = [ + 'hermezero', 'hermeone', 'hermex', 'hermedomain', 'hermeline', + 'hermeadd', 'hermesub', 'hermemulx', 'hermemul', 'hermediv', + 'hermepow', 'hermeval', 'hermeder', 'hermeint', 'herme2poly', + 'poly2herme', 'hermefromroots', 'hermevander', 'hermefit', 'hermetrim', + 'hermeroots', 'HermiteE', 'hermeval2d', 'hermeval3d', 'hermegrid2d', + 'hermegrid3d', 'hermevander2d', 'hermevander3d', 'hermecompanion', + 'hermegauss', 'hermeweight'] + +hermetrim = pu.trimcoef + + +def poly2herme(pol): + """ + poly2herme(pol) + + Convert a polynomial to a Hermite series. + + Convert an array representing the coefficients of a polynomial (relative + to the "standard" basis) ordered from lowest degree to highest, to an + array of the coefficients of the equivalent Hermite series, ordered + from lowest to highest degree. + + Parameters + ---------- + pol : array_like + 1-D array containing the polynomial coefficients + + Returns + ------- + c : ndarray + 1-D array containing the coefficients of the equivalent Hermite + series. + + See Also + -------- + herme2poly + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import poly2herme + >>> poly2herme(np.arange(4)) + array([ 2., 10., 2., 3.]) + + """ + [pol] = pu.as_series([pol]) + deg = len(pol) - 1 + res = 0 + for i in range(deg, -1, -1): + res = hermeadd(hermemulx(res), pol[i]) + return res + + +def herme2poly(c): + """ + Convert a Hermite series to a polynomial. + + Convert an array representing the coefficients of a Hermite series, + ordered from lowest degree to highest, to an array of the coefficients + of the equivalent polynomial (relative to the "standard" basis) ordered + from lowest to highest degree. + + Parameters + ---------- + c : array_like + 1-D array containing the Hermite series coefficients, ordered + from lowest order term to highest. + + Returns + ------- + pol : ndarray + 1-D array containing the coefficients of the equivalent polynomial + (relative to the "standard" basis) ordered from lowest order term + to highest. + + See Also + -------- + poly2herme + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import herme2poly + >>> herme2poly([ 2., 10., 2., 3.]) + array([ 0., 1., 2., 3.]) + + """ + from .polynomial import polyadd, polysub, polymulx + + [c] = pu.as_series([c]) + n = len(c) + if n == 1: + return c + if n == 2: + return c + else: + c0 = c[-2] + c1 = c[-1] + # i is the current degree of c1 + for i in range(n - 1, 1, -1): + tmp = c0 + c0 = polysub(c[i - 2], c1*(i - 1)) + c1 = polyadd(tmp, polymulx(c1)) + return polyadd(c0, polymulx(c1)) + +# +# These are constant arrays are of integer type so as to be compatible +# with the widest range of other types, such as Decimal. +# + +# Hermite +hermedomain = np.array([-1, 1]) + +# Hermite coefficients representing zero. +hermezero = np.array([0]) + +# Hermite coefficients representing one. +hermeone = np.array([1]) + +# Hermite coefficients representing the identity x. +hermex = np.array([0, 1]) + + +def hermeline(off, scl): + """ + Hermite series whose graph is a straight line. + + + + Parameters + ---------- + off, scl : scalars + The specified line is given by ``off + scl*x``. + + Returns + ------- + y : ndarray + This module's representation of the Hermite series for + ``off + scl*x``. + + See Also + -------- + polyline, chebline + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermeline + >>> from numpy.polynomial.hermite_e import hermeline, hermeval + >>> hermeval(0,hermeline(3, 2)) + 3.0 + >>> hermeval(1,hermeline(3, 2)) + 5.0 + + """ + if scl != 0: + return np.array([off, scl]) + else: + return np.array([off]) + + +def hermefromroots(roots): + """ + Generate a HermiteE series with given roots. + + The function returns the coefficients of the polynomial + + .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n), + + in HermiteE form, where the `r_n` are the roots specified in `roots`. + If a zero has multiplicity n, then it must appear in `roots` n times. + For instance, if 2 is a root of multiplicity three and 3 is a root of + multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The + roots can appear in any order. + + If the returned coefficients are `c`, then + + .. math:: p(x) = c_0 + c_1 * He_1(x) + ... + c_n * He_n(x) + + The coefficient of the last term is not generally 1 for monic + polynomials in HermiteE form. + + Parameters + ---------- + roots : array_like + Sequence containing the roots. + + Returns + ------- + out : ndarray + 1-D array of coefficients. If all roots are real then `out` is a + real array, if some of the roots are complex, then `out` is complex + even if all the coefficients in the result are real (see Examples + below). + + See Also + -------- + polyfromroots, legfromroots, lagfromroots, hermfromroots, + chebfromroots. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermefromroots, hermeval + >>> coef = hermefromroots((-1, 0, 1)) + >>> hermeval((-1, 0, 1), coef) + array([ 0., 0., 0.]) + >>> coef = hermefromroots((-1j, 1j)) + >>> hermeval((-1j, 1j), coef) + array([ 0.+0.j, 0.+0.j]) + + """ + if len(roots) == 0: + return np.ones(1) + else: + [roots] = pu.as_series([roots], trim=False) + roots.sort() + p = [hermeline(-r, 1) for r in roots] + n = len(p) + while n > 1: + m, r = divmod(n, 2) + tmp = [hermemul(p[i], p[i+m]) for i in range(m)] + if r: + tmp[0] = hermemul(tmp[0], p[-1]) + p = tmp + n = m + return p[0] + + +def hermeadd(c1, c2): + """ + Add one Hermite series to another. + + Returns the sum of two Hermite series `c1` + `c2`. The arguments + are sequences of coefficients ordered from lowest order term to + highest, i.e., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Hermite series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the Hermite series of their sum. + + See Also + -------- + hermesub, hermemul, hermediv, hermepow + + Notes + ----- + Unlike multiplication, division, etc., the sum of two Hermite series + is a Hermite series (without having to "reproject" the result onto + the basis set) so addition, just like that of "standard" polynomials, + is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermeadd + >>> hermeadd([1, 2, 3], [1, 2, 3, 4]) + array([ 2., 4., 6., 4.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] += c2 + ret = c1 + else: + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def hermesub(c1, c2): + """ + Subtract one Hermite series from another. + + Returns the difference of two Hermite series `c1` - `c2`. The + sequences of coefficients are from lowest order term to highest, i.e., + [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Hermite series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Hermite series coefficients representing their difference. + + See Also + -------- + hermeadd, hermemul, hermediv, hermepow + + Notes + ----- + Unlike multiplication, division, etc., the difference of two Hermite + series is a Hermite series (without having to "reproject" the result + onto the basis set) so subtraction, just like that of "standard" + polynomials, is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermesub + >>> hermesub([1, 2, 3, 4], [1, 2, 3]) + array([ 0., 0., 0., 4.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] -= c2 + ret = c1 + else: + c2 = -c2 + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def hermemulx(c): + """Multiply a Hermite series by x. + + Multiply the Hermite series `c` by x, where x is the independent + variable. + + + Parameters + ---------- + c : array_like + 1-D array of Hermite series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the result of the multiplication. + + Notes + ----- + The multiplication uses the recursion relationship for Hermite + polynomials in the form + + .. math:: + + xP_i(x) = (P_{i + 1}(x) + iP_{i - 1}(x))) + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermemulx + >>> hermemulx([1, 2, 3]) + array([ 2., 7., 2., 3.]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + # The zero series needs special treatment + if len(c) == 1 and c[0] == 0: + return c + + prd = np.empty(len(c) + 1, dtype=c.dtype) + prd[0] = c[0]*0 + prd[1] = c[0] + for i in range(1, len(c)): + prd[i + 1] = c[i] + prd[i - 1] += c[i]*i + return prd + + +def hermemul(c1, c2): + """ + Multiply one Hermite series by another. + + Returns the product of two Hermite series `c1` * `c2`. The arguments + are sequences of coefficients, from lowest order "term" to highest, + e.g., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Hermite series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Hermite series coefficients representing their product. + + See Also + -------- + hermeadd, hermesub, hermediv, hermepow + + Notes + ----- + In general, the (polynomial) product of two C-series results in terms + that are not in the Hermite polynomial basis set. Thus, to express + the product as a Hermite series, it is necessary to "reproject" the + product onto said basis set, which may produce "unintuitive" (but + correct) results; see Examples section below. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermemul + >>> hermemul([1, 2, 3], [0, 1, 2]) + array([ 14., 15., 28., 7., 6.]) + + """ + # s1, s2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + + if len(c1) > len(c2): + c = c2 + xs = c1 + else: + c = c1 + xs = c2 + + if len(c) == 1: + c0 = c[0]*xs + c1 = 0 + elif len(c) == 2: + c0 = c[0]*xs + c1 = c[1]*xs + else: + nd = len(c) + c0 = c[-2]*xs + c1 = c[-1]*xs + for i in range(3, len(c) + 1): + tmp = c0 + nd = nd - 1 + c0 = hermesub(c[-i]*xs, c1*(nd - 1)) + c1 = hermeadd(tmp, hermemulx(c1)) + return hermeadd(c0, hermemulx(c1)) + + +def hermediv(c1, c2): + """ + Divide one Hermite series by another. + + Returns the quotient-with-remainder of two Hermite series + `c1` / `c2`. The arguments are sequences of coefficients from lowest + order "term" to highest, e.g., [1,2,3] represents the series + ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Hermite series coefficients ordered from low to + high. + + Returns + ------- + [quo, rem] : ndarrays + Of Hermite series coefficients representing the quotient and + remainder. + + See Also + -------- + hermeadd, hermesub, hermemul, hermepow + + Notes + ----- + In general, the (polynomial) division of one Hermite series by another + results in quotient and remainder terms that are not in the Hermite + polynomial basis set. Thus, to express these results as a Hermite + series, it is necessary to "reproject" the results onto the Hermite + basis set, which may produce "unintuitive" (but correct) results; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermediv + >>> hermediv([ 14., 15., 28., 7., 6.], [0, 1, 2]) + (array([ 1., 2., 3.]), array([ 0.])) + >>> hermediv([ 15., 17., 28., 7., 6.], [0, 1, 2]) + (array([ 1., 2., 3.]), array([ 1., 2.])) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if c2[-1] == 0: + raise ZeroDivisionError() + + lc1 = len(c1) + lc2 = len(c2) + if lc1 < lc2: + return c1[:1]*0, c1 + elif lc2 == 1: + return c1/c2[-1], c1[:1]*0 + else: + quo = np.empty(lc1 - lc2 + 1, dtype=c1.dtype) + rem = c1 + for i in range(lc1 - lc2, - 1, -1): + p = hermemul([0]*i + [1], c2) + q = rem[-1]/p[-1] + rem = rem[:-1] - q*p[:-1] + quo[i] = q + return quo, pu.trimseq(rem) + + +def hermepow(c, pow, maxpower=16): + """Raise a Hermite series to a power. + + Returns the Hermite series `c` raised to the power `pow`. The + argument `c` is a sequence of coefficients ordered from low to high. + i.e., [1,2,3] is the series ``P_0 + 2*P_1 + 3*P_2.`` + + Parameters + ---------- + c : array_like + 1-D array of Hermite series coefficients ordered from low to + high. + pow : integer + Power to which the series will be raised + maxpower : integer, optional + Maximum power allowed. This is mainly to limit growth of the series + to unmanageable size. Default is 16 + + Returns + ------- + coef : ndarray + Hermite series of power. + + See Also + -------- + hermeadd, hermesub, hermemul, hermediv + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermepow + >>> hermepow([1, 2, 3], 2) + array([ 23., 28., 46., 12., 9.]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + power = int(pow) + if power != pow or power < 0: + raise ValueError("Power must be a non-negative integer.") + elif maxpower is not None and power > maxpower: + raise ValueError("Power is too large") + elif power == 0: + return np.array([1], dtype=c.dtype) + elif power == 1: + return c + else: + # This can be made more efficient by using powers of two + # in the usual way. + prd = c + for i in range(2, power + 1): + prd = hermemul(prd, c) + return prd + + +def hermeder(c, m=1, scl=1, axis=0): + """ + Differentiate a Hermite_e series. + + Returns the series coefficients `c` differentiated `m` times along + `axis`. At each iteration the result is multiplied by `scl` (the + scaling factor is for use in a linear change of variable). The argument + `c` is an array of coefficients from low to high degree along each + axis, e.g., [1,2,3] represents the series ``1*He_0 + 2*He_1 + 3*He_2`` + while [[1,2],[1,2]] represents ``1*He_0(x)*He_0(y) + 1*He_1(x)*He_0(y) + + 2*He_0(x)*He_1(y) + 2*He_1(x)*He_1(y)`` if axis=0 is ``x`` and axis=1 + is ``y``. + + Parameters + ---------- + c : array_like + Array of Hermite_e series coefficients. If `c` is multidimensional + the different axis correspond to different variables with the + degree in each axis given by the corresponding index. + m : int, optional + Number of derivatives taken, must be non-negative. (Default: 1) + scl : scalar, optional + Each differentiation is multiplied by `scl`. The end result is + multiplication by ``scl**m``. This is for use in a linear change of + variable. (Default: 1) + axis : int, optional + Axis over which the derivative is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + der : ndarray + Hermite series of the derivative. + + See Also + -------- + hermeint + + Notes + ----- + In general, the result of differentiating a Hermite series does not + resemble the same operation on a power series. Thus the result of this + function may be "unintuitive," albeit correct; see Examples section + below. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermeder + >>> hermeder([ 1., 1., 1., 1.]) + array([ 1., 2., 3.]) + >>> hermeder([-0.25, 1., 1./2., 1./3., 1./4 ], m=2) + array([ 1., 2., 3.]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of derivation must be integer") + if cnt < 0: + raise ValueError("The order of derivation must be non-negative") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + n = len(c) + if cnt >= n: + return c[:1]*0 + else: + for i in range(cnt): + n = n - 1 + c *= scl + der = np.empty((n,) + c.shape[1:], dtype=c.dtype) + for j in range(n, 0, -1): + der[j - 1] = j*c[j] + c = der + c = np.moveaxis(c, 0, iaxis) + return c + + +def hermeint(c, m=1, k=[], lbnd=0, scl=1, axis=0): + """ + Integrate a Hermite_e series. + + Returns the Hermite_e series coefficients `c` integrated `m` times from + `lbnd` along `axis`. At each iteration the resulting series is + **multiplied** by `scl` and an integration constant, `k`, is added. + The scaling factor is for use in a linear change of variable. ("Buyer + beware": note that, depending on what one is doing, one may want `scl` + to be the reciprocal of what one might expect; for more information, + see the Notes section below.) The argument `c` is an array of + coefficients from low to high degree along each axis, e.g., [1,2,3] + represents the series ``H_0 + 2*H_1 + 3*H_2`` while [[1,2],[1,2]] + represents ``1*H_0(x)*H_0(y) + 1*H_1(x)*H_0(y) + 2*H_0(x)*H_1(y) + + 2*H_1(x)*H_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. + + Parameters + ---------- + c : array_like + Array of Hermite_e series coefficients. If c is multidimensional + the different axis correspond to different variables with the + degree in each axis given by the corresponding index. + m : int, optional + Order of integration, must be positive. (Default: 1) + k : {[], list, scalar}, optional + Integration constant(s). The value of the first integral at + ``lbnd`` is the first value in the list, the value of the second + integral at ``lbnd`` is the second value, etc. If ``k == []`` (the + default), all constants are set to zero. If ``m == 1``, a single + scalar can be given instead of a list. + lbnd : scalar, optional + The lower bound of the integral. (Default: 0) + scl : scalar, optional + Following each integration the result is *multiplied* by `scl` + before the integration constant is added. (Default: 1) + axis : int, optional + Axis over which the integral is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + S : ndarray + Hermite_e series coefficients of the integral. + + Raises + ------ + ValueError + If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or + ``np.ndim(scl) != 0``. + + See Also + -------- + hermeder + + Notes + ----- + Note that the result of each integration is *multiplied* by `scl`. + Why is this important to note? Say one is making a linear change of + variable :math:`u = ax + b` in an integral relative to `x`. Then + :math:`dx = du/a`, so one will need to set `scl` equal to + :math:`1/a` - perhaps not what one would have first thought. + + Also note that, in general, the result of integrating a C-series needs + to be "reprojected" onto the C-series basis set. Thus, typically, + the result of this function is "unintuitive," albeit correct; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermeint + >>> hermeint([1, 2, 3]) # integrate once, value 0 at 0. + array([ 1., 1., 1., 1.]) + >>> hermeint([1, 2, 3], m=2) # integrate twice, value & deriv 0 at 0 + array([-0.25 , 1. , 0.5 , 0.33333333, 0.25 ]) + >>> hermeint([1, 2, 3], k=1) # integrate once, value 1 at 0. + array([ 2., 1., 1., 1.]) + >>> hermeint([1, 2, 3], lbnd=-1) # integrate once, value 0 at -1 + array([-1., 1., 1., 1.]) + >>> hermeint([1, 2, 3], m=2, k=[1, 2], lbnd=-1) + array([ 1.83333333, 0. , 0.5 , 0.33333333, 0.25 ]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if not np.iterable(k): + k = [k] + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of integration must be integer") + if cnt < 0: + raise ValueError("The order of integration must be non-negative") + if len(k) > cnt: + raise ValueError("Too many integration constants") + if np.ndim(lbnd) != 0: + raise ValueError("lbnd must be a scalar.") + if np.ndim(scl) != 0: + raise ValueError("scl must be a scalar.") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + k = list(k) + [0]*(cnt - len(k)) + for i in range(cnt): + n = len(c) + c *= scl + if n == 1 and np.all(c[0] == 0): + c[0] += k[i] + else: + tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype) + tmp[0] = c[0]*0 + tmp[1] = c[0] + for j in range(1, n): + tmp[j + 1] = c[j]/(j + 1) + tmp[0] += k[i] - hermeval(lbnd, tmp) + c = tmp + c = np.moveaxis(c, 0, iaxis) + return c + + +def hermeval(x, c, tensor=True): + """ + Evaluate an HermiteE series at points x. + + If `c` is of length `n + 1`, this function returns the value: + + .. math:: p(x) = c_0 * He_0(x) + c_1 * He_1(x) + ... + c_n * He_n(x) + + The parameter `x` is converted to an array only if it is a tuple or a + list, otherwise it is treated as a scalar. In either case, either `x` + or its elements must support multiplication and addition both with + themselves and with the elements of `c`. + + If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If + `c` is multidimensional, then the shape of the result depends on the + value of `tensor`. If `tensor` is true the shape will be c.shape[1:] + + x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that + scalars have shape (,). + + Trailing zeros in the coefficients will be used in the evaluation, so + they should be avoided if efficiency is a concern. + + Parameters + ---------- + x : array_like, compatible object + If `x` is a list or tuple, it is converted to an ndarray, otherwise + it is left unchanged and treated as a scalar. In either case, `x` + or its elements must support addition and multiplication with + with themselves and with the elements of `c`. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree n are contained in c[n]. If `c` is multidimensional the + remaining indices enumerate multiple polynomials. In the two + dimensional case the coefficients may be thought of as stored in + the columns of `c`. + tensor : boolean, optional + If True, the shape of the coefficient array is extended with ones + on the right, one for each dimension of `x`. Scalars have dimension 0 + for this action. The result is that every column of coefficients in + `c` is evaluated for every element of `x`. If False, `x` is broadcast + over the columns of `c` for the evaluation. This keyword is useful + when `c` is multidimensional. The default value is True. + + .. versionadded:: 1.7.0 + + Returns + ------- + values : ndarray, algebra_like + The shape of the return value is described above. + + See Also + -------- + hermeval2d, hermegrid2d, hermeval3d, hermegrid3d + + Notes + ----- + The evaluation uses Clenshaw recursion, aka synthetic division. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermeval + >>> coef = [1,2,3] + >>> hermeval(1, coef) + 3.0 + >>> hermeval([[1,2],[3,4]], coef) + array([[ 3., 14.], + [ 31., 54.]]) + + """ + c = np.array(c, ndmin=1, copy=0) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if isinstance(x, (tuple, list)): + x = np.asarray(x) + if isinstance(x, np.ndarray) and tensor: + c = c.reshape(c.shape + (1,)*x.ndim) + + if len(c) == 1: + c0 = c[0] + c1 = 0 + elif len(c) == 2: + c0 = c[0] + c1 = c[1] + else: + nd = len(c) + c0 = c[-2] + c1 = c[-1] + for i in range(3, len(c) + 1): + tmp = c0 + nd = nd - 1 + c0 = c[-i] - c1*(nd - 1) + c1 = tmp + c1*x + return c0 + c1*x + + +def hermeval2d(x, y, c): + """ + Evaluate a 2-D HermiteE series at points (x, y). + + This function returns the values: + + .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * He_i(x) * He_j(y) + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars and they + must have the same shape after conversion. In either case, either `x` + and `y` or their elements must support multiplication and addition both + with themselves and with the elements of `c`. + + If `c` is a 1-D array a one is implicitly appended to its shape to make + it 2-D. The shape of the result will be c.shape[2:] + x.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points `(x, y)`, + where `x` and `y` must have the same shape. If `x` or `y` is a list + or tuple, it is first converted to an ndarray, otherwise it is left + unchanged and if it isn't an ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term + of multi-degree i,j is contained in ``c[i,j]``. If `c` has + dimension greater than two the remaining indices enumerate multiple + sets of coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points formed with + pairs of corresponding values from `x` and `y`. + + See Also + -------- + hermeval, hermegrid2d, hermeval3d, hermegrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y = np.array((x, y), copy=0) + except Exception: + raise ValueError('x, y are incompatible') + + c = hermeval(x, c) + c = hermeval(y, c, tensor=False) + return c + + +def hermegrid2d(x, y, c): + """ + Evaluate a 2-D HermiteE series on the Cartesian product of x and y. + + This function returns the values: + + .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * H_i(a) * H_j(b) + + where the points `(a, b)` consist of all pairs formed by taking + `a` from `x` and `b` from `y`. The resulting points form a grid with + `x` in the first dimension and `y` in the second. + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars. In either + case, either `x` and `y` or their elements must support multiplication + and addition both with themselves and with the elements of `c`. + + If `c` has fewer than two dimensions, ones are implicitly appended to + its shape to make it 2-D. The shape of the result will be c.shape[2:] + + x.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points in the + Cartesian product of `x` and `y`. If `x` or `y` is a list or + tuple, it is first converted to an ndarray, otherwise it is left + unchanged and, if it isn't an ndarray, it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + hermeval, hermeval2d, hermeval3d, hermegrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = hermeval(x, c) + c = hermeval(y, c) + return c + + +def hermeval3d(x, y, z, c): + """ + Evaluate a 3-D Hermite_e series at points (x, y, z). + + This function returns the values: + + .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * He_i(x) * He_j(y) * He_k(z) + + The parameters `x`, `y`, and `z` are converted to arrays only if + they are tuples or a lists, otherwise they are treated as a scalars and + they must have the same shape after conversion. In either case, either + `x`, `y`, and `z` or their elements must support multiplication and + addition both with themselves and with the elements of `c`. + + If `c` has fewer than 3 dimensions, ones are implicitly appended to its + shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape. + + Parameters + ---------- + x, y, z : array_like, compatible object + The three dimensional series is evaluated at the points + `(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If + any of `x`, `y`, or `z` is a list or tuple, it is first converted + to an ndarray, otherwise it is left unchanged and if it isn't an + ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension + greater than 3 the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the multidimensional polynomial on points formed with + triples of corresponding values from `x`, `y`, and `z`. + + See Also + -------- + hermeval, hermeval2d, hermegrid2d, hermegrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y, z = np.array((x, y, z), copy=0) + except Exception: + raise ValueError('x, y, z are incompatible') + + c = hermeval(x, c) + c = hermeval(y, c, tensor=False) + c = hermeval(z, c, tensor=False) + return c + + +def hermegrid3d(x, y, z, c): + """ + Evaluate a 3-D HermiteE series on the Cartesian product of x, y, and z. + + This function returns the values: + + .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * He_i(a) * He_j(b) * He_k(c) + + where the points `(a, b, c)` consist of all triples formed by taking + `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form + a grid with `x` in the first dimension, `y` in the second, and `z` in + the third. + + The parameters `x`, `y`, and `z` are converted to arrays only if they + are tuples or a lists, otherwise they are treated as a scalars. In + either case, either `x`, `y`, and `z` or their elements must support + multiplication and addition both with themselves and with the elements + of `c`. + + If `c` has fewer than three dimensions, ones are implicitly appended to + its shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape + y.shape + z.shape. + + Parameters + ---------- + x, y, z : array_like, compatible objects + The three dimensional series is evaluated at the points in the + Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a + list or tuple, it is first converted to an ndarray, otherwise it is + left unchanged and, if it isn't an ndarray, it is treated as a + scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + hermeval, hermeval2d, hermegrid2d, hermeval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = hermeval(x, c) + c = hermeval(y, c) + c = hermeval(z, c) + return c + + +def hermevander(x, deg): + """Pseudo-Vandermonde matrix of given degree. + + Returns the pseudo-Vandermonde matrix of degree `deg` and sample points + `x`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., i] = He_i(x), + + where `0 <= i <= deg`. The leading indices of `V` index the elements of + `x` and the last index is the degree of the HermiteE polynomial. + + If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the + array ``V = hermevander(x, n)``, then ``np.dot(V, c)`` and + ``hermeval(x, c)`` are the same up to roundoff. This equivalence is + useful both for least squares fitting and for the evaluation of a large + number of HermiteE series of the same degree and sample points. + + Parameters + ---------- + x : array_like + Array of points. The dtype is converted to float64 or complex128 + depending on whether any of the elements are complex. If `x` is + scalar it is converted to a 1-D array. + deg : int + Degree of the resulting matrix. + + Returns + ------- + vander : ndarray + The pseudo-Vandermonde matrix. The shape of the returned matrix is + ``x.shape + (deg + 1,)``, where The last index is the degree of the + corresponding HermiteE polynomial. The dtype will be the same as + the converted `x`. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermevander + >>> x = np.array([-1, 0, 1]) + >>> hermevander(x, 3) + array([[ 1., -1., 0., 2.], + [ 1., 0., -1., -0.], + [ 1., 1., 0., -2.]]) + + """ + ideg = int(deg) + if ideg != deg: + raise ValueError("deg must be integer") + if ideg < 0: + raise ValueError("deg must be non-negative") + + x = np.array(x, copy=0, ndmin=1) + 0.0 + dims = (ideg + 1,) + x.shape + dtyp = x.dtype + v = np.empty(dims, dtype=dtyp) + v[0] = x*0 + 1 + if ideg > 0: + v[1] = x + for i in range(2, ideg + 1): + v[i] = (v[i-1]*x - v[i-2]*(i - 1)) + return np.moveaxis(v, 0, -1) + + +def hermevander2d(x, y, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y)`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (deg[1] + 1)*i + j] = He_i(x) * He_j(y), + + where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of + `V` index the points `(x, y)` and the last index encodes the degrees of + the HermiteE polynomials. + + If ``V = hermevander2d(x, y, [xdeg, ydeg])``, then the columns of `V` + correspond to the elements of a 2-D coefficient array `c` of shape + (xdeg + 1, ydeg + 1) in the order + + .. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ... + + and ``np.dot(V, c.flat)`` and ``hermeval2d(x, y, c)`` will be the same + up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 2-D HermiteE + series of the same degrees and sample points. + + Parameters + ---------- + x, y : array_like + Arrays of point coordinates, all of the same shape. The dtypes + will be converted to either float64 or complex128 depending on + whether any of the elements are complex. Scalars are converted to + 1-D arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg]. + + Returns + ------- + vander2d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)`. The dtype will be the same + as the converted `x` and `y`. + + See Also + -------- + hermevander, hermevander3d. hermeval2d, hermeval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy = ideg + x, y = np.array((x, y), copy=0) + 0.0 + + vx = hermevander(x, degx) + vy = hermevander(y, degy) + v = vx[..., None]*vy[..., None,:] + return v.reshape(v.shape[:-2] + (-1,)) + + +def hermevander3d(x, y, z, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`, + then Hehe pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = He_i(x)*He_j(y)*He_k(z), + + where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading + indices of `V` index the points `(x, y, z)` and the last index encodes + the degrees of the HermiteE polynomials. + + If ``V = hermevander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns + of `V` correspond to the elements of a 3-D coefficient array `c` of + shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order + + .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},... + + and ``np.dot(V, c.flat)`` and ``hermeval3d(x, y, z, c)`` will be the + same up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 3-D HermiteE + series of the same degrees and sample points. + + Parameters + ---------- + x, y, z : array_like + Arrays of point coordinates, all of the same shape. The dtypes will + be converted to either float64 or complex128 depending on whether + any of the elements are complex. Scalars are converted to 1-D + arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg, z_deg]. + + Returns + ------- + vander3d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)*(deg[2]+1)`. The dtype will + be the same as the converted `x`, `y`, and `z`. + + See Also + -------- + hermevander, hermevander3d. hermeval2d, hermeval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy, degz = ideg + x, y, z = np.array((x, y, z), copy=0) + 0.0 + + vx = hermevander(x, degx) + vy = hermevander(y, degy) + vz = hermevander(z, degz) + v = vx[..., None, None]*vy[..., None,:, None]*vz[..., None, None,:] + return v.reshape(v.shape[:-3] + (-1,)) + + +def hermefit(x, y, deg, rcond=None, full=False, w=None): + """ + Least squares fit of Hermite series to data. + + Return the coefficients of a HermiteE series of degree `deg` that is + the least squares fit to the data values `y` given at points `x`. If + `y` is 1-D the returned coefficients will also be 1-D. If `y` is 2-D + multiple fits are done, one for each column of `y`, and the resulting + coefficients are stored in the corresponding columns of a 2-D return. + The fitted polynomial(s) are in the form + + .. math:: p(x) = c_0 + c_1 * He_1(x) + ... + c_n * He_n(x), + + where `n` is `deg`. + + Parameters + ---------- + x : array_like, shape (M,) + x-coordinates of the M sample points ``(x[i], y[i])``. + y : array_like, shape (M,) or (M, K) + y-coordinates of the sample points. Several data sets of sample + points sharing the same x-coordinates can be fitted at once by + passing in a 2D-array that contains one dataset per column. + deg : int or 1-D array_like + Degree(s) of the fitting polynomials. If `deg` is a single integer + all terms up to and including the `deg`'th term are included in the + fit. For NumPy versions >= 1.11.0 a list of integers specifying the + degrees of the terms to include may be used instead. + rcond : float, optional + Relative condition number of the fit. Singular values smaller than + this relative to the largest singular value will be ignored. The + default value is len(x)*eps, where eps is the relative precision of + the float type, about 2e-16 in most cases. + full : bool, optional + Switch determining nature of return value. When it is False (the + default) just the coefficients are returned, when True diagnostic + information from the singular value decomposition is also returned. + w : array_like, shape (`M`,), optional + Weights. If not None, the contribution of each point + ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the + weights are chosen so that the errors of the products ``w[i]*y[i]`` + all have the same variance. The default value is None. + + Returns + ------- + coef : ndarray, shape (M,) or (M, K) + Hermite coefficients ordered from low to high. If `y` was 2-D, + the coefficients for the data in column k of `y` are in column + `k`. + + [residuals, rank, singular_values, rcond] : list + These values are only returned if `full` = True + + resid -- sum of squared residuals of the least squares fit + rank -- the numerical rank of the scaled Vandermonde matrix + sv -- singular values of the scaled Vandermonde matrix + rcond -- value of `rcond`. + + For more details, see `linalg.lstsq`. + + Warns + ----- + RankWarning + The rank of the coefficient matrix in the least-squares fit is + deficient. The warning is only raised if `full` = False. The + warnings can be turned off by + + >>> import warnings + >>> warnings.simplefilter('ignore', RankWarning) + + See Also + -------- + chebfit, legfit, polyfit, hermfit, polyfit + hermeval : Evaluates a Hermite series. + hermevander : pseudo Vandermonde matrix of Hermite series. + hermeweight : HermiteE weight function. + linalg.lstsq : Computes a least-squares fit from the matrix. + scipy.interpolate.UnivariateSpline : Computes spline fits. + + Notes + ----- + The solution is the coefficients of the HermiteE series `p` that + minimizes the sum of the weighted squared errors + + .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2, + + where the :math:`w_j` are the weights. This problem is solved by + setting up the (typically) overdetermined matrix equation + + .. math:: V(x) * c = w * y, + + where `V` is the pseudo Vandermonde matrix of `x`, the elements of `c` + are the coefficients to be solved for, and the elements of `y` are the + observed values. This equation is then solved using the singular value + decomposition of `V`. + + If some of the singular values of `V` are so small that they are + neglected, then a `RankWarning` will be issued. This means that the + coefficient values may be poorly determined. Using a lower order fit + will usually get rid of the warning. The `rcond` parameter can also be + set to a value smaller than its default, but the resulting fit may be + spurious and have large contributions from roundoff error. + + Fits using HermiteE series are probably most useful when the data can + be approximated by ``sqrt(w(x)) * p(x)``, where `w(x)` is the HermiteE + weight. In that case the weight ``sqrt(w(x[i])`` should be used + together with data values ``y[i]/sqrt(w(x[i])``. The weight function is + available as `hermeweight`. + + References + ---------- + .. [1] Wikipedia, "Curve fitting", + http://en.wikipedia.org/wiki/Curve_fitting + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermefit, hermeval + >>> x = np.linspace(-10, 10) + >>> err = np.random.randn(len(x))/10 + >>> y = hermeval(x, [1, 2, 3]) + err + >>> hermefit(x, y, 2) + array([ 1.01690445, 1.99951418, 2.99948696]) + + """ + x = np.asarray(x) + 0.0 + y = np.asarray(y) + 0.0 + deg = np.asarray(deg) + + # check arguments. + if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0: + raise TypeError("deg must be an int or non-empty 1-D array of int") + if deg.min() < 0: + raise ValueError("expected deg >= 0") + if x.ndim != 1: + raise TypeError("expected 1D vector for x") + if x.size == 0: + raise TypeError("expected non-empty vector for x") + if y.ndim < 1 or y.ndim > 2: + raise TypeError("expected 1D or 2D array for y") + if len(x) != len(y): + raise TypeError("expected x and y to have same length") + + if deg.ndim == 0: + lmax = deg + order = lmax + 1 + van = hermevander(x, lmax) + else: + deg = np.sort(deg) + lmax = deg[-1] + order = len(deg) + van = hermevander(x, lmax)[:, deg] + + # set up the least squares matrices in transposed form + lhs = van.T + rhs = y.T + if w is not None: + w = np.asarray(w) + 0.0 + if w.ndim != 1: + raise TypeError("expected 1D vector for w") + if len(x) != len(w): + raise TypeError("expected x and w to have same length") + # apply weights. Don't use inplace operations as they + # can cause problems with NA. + lhs = lhs * w + rhs = rhs * w + + # set rcond + if rcond is None: + rcond = len(x)*np.finfo(x.dtype).eps + + # Determine the norms of the design matrix columns. + if issubclass(lhs.dtype.type, np.complexfloating): + scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1)) + else: + scl = np.sqrt(np.square(lhs).sum(1)) + scl[scl == 0] = 1 + + # Solve the least squares problem. + c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond) + c = (c.T/scl).T + + # Expand c to include non-fitted coefficients which are set to zero + if deg.ndim > 0: + if c.ndim == 2: + cc = np.zeros((lmax+1, c.shape[1]), dtype=c.dtype) + else: + cc = np.zeros(lmax+1, dtype=c.dtype) + cc[deg] = c + c = cc + + # warn on rank reduction + if rank != order and not full: + msg = "The fit may be poorly conditioned" + warnings.warn(msg, pu.RankWarning, stacklevel=2) + + if full: + return c, [resids, rank, s, rcond] + else: + return c + + +def hermecompanion(c): + """ + Return the scaled companion matrix of c. + + The basis polynomials are scaled so that the companion matrix is + symmetric when `c` is an HermiteE basis polynomial. This provides + better eigenvalue estimates than the unscaled case and for basis + polynomials the eigenvalues are guaranteed to be real if + `numpy.linalg.eigvalsh` is used to obtain them. + + Parameters + ---------- + c : array_like + 1-D array of HermiteE series coefficients ordered from low to high + degree. + + Returns + ------- + mat : ndarray + Scaled companion matrix of dimensions (deg, deg). + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + raise ValueError('Series must have maximum degree of at least 1.') + if len(c) == 2: + return np.array([[-c[0]/c[1]]]) + + n = len(c) - 1 + mat = np.zeros((n, n), dtype=c.dtype) + scl = np.hstack((1., 1./np.sqrt(np.arange(n - 1, 0, -1)))) + scl = np.multiply.accumulate(scl)[::-1] + top = mat.reshape(-1)[1::n+1] + bot = mat.reshape(-1)[n::n+1] + top[...] = np.sqrt(np.arange(1, n)) + bot[...] = top + mat[:, -1] -= scl*c[:-1]/c[-1] + return mat + + +def hermeroots(c): + """ + Compute the roots of a HermiteE series. + + Return the roots (a.k.a. "zeros") of the polynomial + + .. math:: p(x) = \\sum_i c[i] * He_i(x). + + Parameters + ---------- + c : 1-D array_like + 1-D array of coefficients. + + Returns + ------- + out : ndarray + Array of the roots of the series. If all the roots are real, + then `out` is also real, otherwise it is complex. + + See Also + -------- + polyroots, legroots, lagroots, hermroots, chebroots + + Notes + ----- + The root estimates are obtained as the eigenvalues of the companion + matrix, Roots far from the origin of the complex plane may have large + errors due to the numerical instability of the series for such + values. Roots with multiplicity greater than 1 will also show larger + errors as the value of the series near such points is relatively + insensitive to errors in the roots. Isolated roots near the origin can + be improved by a few iterations of Newton's method. + + The HermiteE series basis polynomials aren't powers of `x` so the + results of this function may seem unintuitive. + + Examples + -------- + >>> from numpy.polynomial.hermite_e import hermeroots, hermefromroots + >>> coef = hermefromroots([-1, 0, 1]) + >>> coef + array([ 0., 2., 0., 1.]) + >>> hermeroots(coef) + array([-1., 0., 1.]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) <= 1: + return np.array([], dtype=c.dtype) + if len(c) == 2: + return np.array([-c[0]/c[1]]) + + m = hermecompanion(c) + r = la.eigvals(m) + r.sort() + return r + + +def _normed_hermite_e_n(x, n): + """ + Evaluate a normalized HermiteE polynomial. + + Compute the value of the normalized HermiteE polynomial of degree ``n`` + at the points ``x``. + + + Parameters + ---------- + x : ndarray of double. + Points at which to evaluate the function + n : int + Degree of the normalized HermiteE function to be evaluated. + + Returns + ------- + values : ndarray + The shape of the return value is described above. + + Notes + ----- + .. versionadded:: 1.10.0 + + This function is needed for finding the Gauss points and integration + weights for high degrees. The values of the standard HermiteE functions + overflow when n >= 207. + + """ + if n == 0: + return np.ones(x.shape)/np.sqrt(np.sqrt(2*np.pi)) + + c0 = 0. + c1 = 1./np.sqrt(np.sqrt(2*np.pi)) + nd = float(n) + for i in range(n - 1): + tmp = c0 + c0 = -c1*np.sqrt((nd - 1.)/nd) + c1 = tmp + c1*x*np.sqrt(1./nd) + nd = nd - 1.0 + return c0 + c1*x + + +def hermegauss(deg): + """ + Gauss-HermiteE quadrature. + + Computes the sample points and weights for Gauss-HermiteE quadrature. + These sample points and weights will correctly integrate polynomials of + degree :math:`2*deg - 1` or less over the interval :math:`[-\\inf, \\inf]` + with the weight function :math:`f(x) = \\exp(-x^2/2)`. + + Parameters + ---------- + deg : int + Number of sample points and weights. It must be >= 1. + + Returns + ------- + x : ndarray + 1-D ndarray containing the sample points. + y : ndarray + 1-D ndarray containing the weights. + + Notes + ----- + + .. versionadded:: 1.7.0 + + The results have only been tested up to degree 100, higher degrees may + be problematic. The weights are determined by using the fact that + + .. math:: w_k = c / (He'_n(x_k) * He_{n-1}(x_k)) + + where :math:`c` is a constant independent of :math:`k` and :math:`x_k` + is the k'th root of :math:`He_n`, and then scaling the results to get + the right value when integrating 1. + + """ + ideg = int(deg) + if ideg != deg or ideg < 1: + raise ValueError("deg must be a non-negative integer") + + # first approximation of roots. We use the fact that the companion + # matrix is symmetric in this case in order to obtain better zeros. + c = np.array([0]*deg + [1]) + m = hermecompanion(c) + x = la.eigvalsh(m) + + # improve roots by one application of Newton + dy = _normed_hermite_e_n(x, ideg) + df = _normed_hermite_e_n(x, ideg - 1) * np.sqrt(ideg) + x -= dy/df + + # compute the weights. We scale the factor to avoid possible numerical + # overflow. + fm = _normed_hermite_e_n(x, ideg - 1) + fm /= np.abs(fm).max() + w = 1/(fm * fm) + + # for Hermite_e we can also symmetrize + w = (w + w[::-1])/2 + x = (x - x[::-1])/2 + + # scale w to get the right value + w *= np.sqrt(2*np.pi) / w.sum() + + return x, w + + +def hermeweight(x): + """Weight function of the Hermite_e polynomials. + + The weight function is :math:`\\exp(-x^2/2)` and the interval of + integration is :math:`[-\\inf, \\inf]`. the HermiteE polynomials are + orthogonal, but not normalized, with respect to this weight function. + + Parameters + ---------- + x : array_like + Values at which the weight function will be computed. + + Returns + ------- + w : ndarray + The weight function at `x`. + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + w = np.exp(-.5*x**2) + return w + + +# +# HermiteE series class +# + +class HermiteE(ABCPolyBase): + """An HermiteE series class. + + The HermiteE class provides the standard Python numerical methods + '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the + attributes and methods listed in the `ABCPolyBase` documentation. + + Parameters + ---------- + coef : array_like + HermiteE coefficients in order of increasing degree, i.e, + ``(1, 2, 3)`` gives ``1*He_0(x) + 2*He_1(X) + 3*He_2(x)``. + domain : (2,) array_like, optional + Domain to use. The interval ``[domain[0], domain[1]]`` is mapped + to the interval ``[window[0], window[1]]`` by shifting and scaling. + The default value is [-1, 1]. + window : (2,) array_like, optional + Window, see `domain` for its use. The default value is [-1, 1]. + + .. versionadded:: 1.6.0 + + """ + # Virtual Functions + _add = staticmethod(hermeadd) + _sub = staticmethod(hermesub) + _mul = staticmethod(hermemul) + _div = staticmethod(hermediv) + _pow = staticmethod(hermepow) + _val = staticmethod(hermeval) + _int = staticmethod(hermeint) + _der = staticmethod(hermeder) + _fit = staticmethod(hermefit) + _line = staticmethod(hermeline) + _roots = staticmethod(hermeroots) + _fromroots = staticmethod(hermefromroots) + + # Virtual properties + nickname = 'herme' + domain = np.array(hermedomain) + window = np.array(hermedomain) diff --git a/numpy/polynomial/laguerre.py b/numpy/polynomial/laguerre.py new file mode 100644 index 0000000..5a9a511 --- /dev/null +++ b/numpy/polynomial/laguerre.py @@ -0,0 +1,1803 @@ +""" +Objects for dealing with Laguerre series. + +This module provides a number of objects (mostly functions) useful for +dealing with Laguerre series, including a `Laguerre` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Constants +--------- +- `lagdomain` -- Laguerre series default domain, [-1,1]. +- `lagzero` -- Laguerre series that evaluates identically to 0. +- `lagone` -- Laguerre series that evaluates identically to 1. +- `lagx` -- Laguerre series for the identity map, ``f(x) = x``. + +Arithmetic +---------- +- `lagmulx` -- multiply a Laguerre series in ``P_i(x)`` by ``x``. +- `lagadd` -- add two Laguerre series. +- `lagsub` -- subtract one Laguerre series from another. +- `lagmul` -- multiply two Laguerre series. +- `lagdiv` -- divide one Laguerre series by another. +- `lagval` -- evaluate a Laguerre series at given points. +- `lagval2d` -- evaluate a 2D Laguerre series at given points. +- `lagval3d` -- evaluate a 3D Laguerre series at given points. +- `laggrid2d` -- evaluate a 2D Laguerre series on a Cartesian product. +- `laggrid3d` -- evaluate a 3D Laguerre series on a Cartesian product. + +Calculus +-------- +- `lagder` -- differentiate a Laguerre series. +- `lagint` -- integrate a Laguerre series. + +Misc Functions +-------------- +- `lagfromroots` -- create a Laguerre series with specified roots. +- `lagroots` -- find the roots of a Laguerre series. +- `lagvander` -- Vandermonde-like matrix for Laguerre polynomials. +- `lagvander2d` -- Vandermonde-like matrix for 2D power series. +- `lagvander3d` -- Vandermonde-like matrix for 3D power series. +- `laggauss` -- Gauss-Laguerre quadrature, points and weights. +- `lagweight` -- Laguerre weight function. +- `lagcompanion` -- symmetrized companion matrix in Laguerre form. +- `lagfit` -- least-squares fit returning a Laguerre series. +- `lagtrim` -- trim leading coefficients from a Laguerre series. +- `lagline` -- Laguerre series of given straight line. +- `lag2poly` -- convert a Laguerre series to a polynomial. +- `poly2lag` -- convert a polynomial to a Laguerre series. + +Classes +------- +- `Laguerre` -- A Laguerre series class. + +See also +-------- +`numpy.polynomial` + +""" +from __future__ import division, absolute_import, print_function + +import warnings +import numpy as np +import numpy.linalg as la +from numpy.core.multiarray import normalize_axis_index + +from . import polyutils as pu +from ._polybase import ABCPolyBase + +__all__ = [ + 'lagzero', 'lagone', 'lagx', 'lagdomain', 'lagline', 'lagadd', + 'lagsub', 'lagmulx', 'lagmul', 'lagdiv', 'lagpow', 'lagval', 'lagder', + 'lagint', 'lag2poly', 'poly2lag', 'lagfromroots', 'lagvander', + 'lagfit', 'lagtrim', 'lagroots', 'Laguerre', 'lagval2d', 'lagval3d', + 'laggrid2d', 'laggrid3d', 'lagvander2d', 'lagvander3d', 'lagcompanion', + 'laggauss', 'lagweight'] + +lagtrim = pu.trimcoef + + +def poly2lag(pol): + """ + poly2lag(pol) + + Convert a polynomial to a Laguerre series. + + Convert an array representing the coefficients of a polynomial (relative + to the "standard" basis) ordered from lowest degree to highest, to an + array of the coefficients of the equivalent Laguerre series, ordered + from lowest to highest degree. + + Parameters + ---------- + pol : array_like + 1-D array containing the polynomial coefficients + + Returns + ------- + c : ndarray + 1-D array containing the coefficients of the equivalent Laguerre + series. + + See Also + -------- + lag2poly + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy.polynomial.laguerre import poly2lag + >>> poly2lag(np.arange(4)) + array([ 23., -63., 58., -18.]) + + """ + [pol] = pu.as_series([pol]) + deg = len(pol) - 1 + res = 0 + for i in range(deg, -1, -1): + res = lagadd(lagmulx(res), pol[i]) + return res + + +def lag2poly(c): + """ + Convert a Laguerre series to a polynomial. + + Convert an array representing the coefficients of a Laguerre series, + ordered from lowest degree to highest, to an array of the coefficients + of the equivalent polynomial (relative to the "standard" basis) ordered + from lowest to highest degree. + + Parameters + ---------- + c : array_like + 1-D array containing the Laguerre series coefficients, ordered + from lowest order term to highest. + + Returns + ------- + pol : ndarray + 1-D array containing the coefficients of the equivalent polynomial + (relative to the "standard" basis) ordered from lowest order term + to highest. + + See Also + -------- + poly2lag + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lag2poly + >>> lag2poly([ 23., -63., 58., -18.]) + array([ 0., 1., 2., 3.]) + + """ + from .polynomial import polyadd, polysub, polymulx + + [c] = pu.as_series([c]) + n = len(c) + if n == 1: + return c + else: + c0 = c[-2] + c1 = c[-1] + # i is the current degree of c1 + for i in range(n - 1, 1, -1): + tmp = c0 + c0 = polysub(c[i - 2], (c1*(i - 1))/i) + c1 = polyadd(tmp, polysub((2*i - 1)*c1, polymulx(c1))/i) + return polyadd(c0, polysub(c1, polymulx(c1))) + +# +# These are constant arrays are of integer type so as to be compatible +# with the widest range of other types, such as Decimal. +# + +# Laguerre +lagdomain = np.array([0, 1]) + +# Laguerre coefficients representing zero. +lagzero = np.array([0]) + +# Laguerre coefficients representing one. +lagone = np.array([1]) + +# Laguerre coefficients representing the identity x. +lagx = np.array([1, -1]) + + +def lagline(off, scl): + """ + Laguerre series whose graph is a straight line. + + + + Parameters + ---------- + off, scl : scalars + The specified line is given by ``off + scl*x``. + + Returns + ------- + y : ndarray + This module's representation of the Laguerre series for + ``off + scl*x``. + + See Also + -------- + polyline, chebline + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagline, lagval + >>> lagval(0,lagline(3, 2)) + 3.0 + >>> lagval(1,lagline(3, 2)) + 5.0 + + """ + if scl != 0: + return np.array([off + scl, -scl]) + else: + return np.array([off]) + + +def lagfromroots(roots): + """ + Generate a Laguerre series with given roots. + + The function returns the coefficients of the polynomial + + .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n), + + in Laguerre form, where the `r_n` are the roots specified in `roots`. + If a zero has multiplicity n, then it must appear in `roots` n times. + For instance, if 2 is a root of multiplicity three and 3 is a root of + multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The + roots can appear in any order. + + If the returned coefficients are `c`, then + + .. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x) + + The coefficient of the last term is not generally 1 for monic + polynomials in Laguerre form. + + Parameters + ---------- + roots : array_like + Sequence containing the roots. + + Returns + ------- + out : ndarray + 1-D array of coefficients. If all roots are real then `out` is a + real array, if some of the roots are complex, then `out` is complex + even if all the coefficients in the result are real (see Examples + below). + + See Also + -------- + polyfromroots, legfromroots, chebfromroots, hermfromroots, + hermefromroots. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagfromroots, lagval + >>> coef = lagfromroots((-1, 0, 1)) + >>> lagval((-1, 0, 1), coef) + array([ 0., 0., 0.]) + >>> coef = lagfromroots((-1j, 1j)) + >>> lagval((-1j, 1j), coef) + array([ 0.+0.j, 0.+0.j]) + + """ + if len(roots) == 0: + return np.ones(1) + else: + [roots] = pu.as_series([roots], trim=False) + roots.sort() + p = [lagline(-r, 1) for r in roots] + n = len(p) + while n > 1: + m, r = divmod(n, 2) + tmp = [lagmul(p[i], p[i+m]) for i in range(m)] + if r: + tmp[0] = lagmul(tmp[0], p[-1]) + p = tmp + n = m + return p[0] + + +def lagadd(c1, c2): + """ + Add one Laguerre series to another. + + Returns the sum of two Laguerre series `c1` + `c2`. The arguments + are sequences of coefficients ordered from lowest order term to + highest, i.e., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Laguerre series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the Laguerre series of their sum. + + See Also + -------- + lagsub, lagmul, lagdiv, lagpow + + Notes + ----- + Unlike multiplication, division, etc., the sum of two Laguerre series + is a Laguerre series (without having to "reproject" the result onto + the basis set) so addition, just like that of "standard" polynomials, + is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagadd + >>> lagadd([1, 2, 3], [1, 2, 3, 4]) + array([ 2., 4., 6., 4.]) + + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] += c2 + ret = c1 + else: + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def lagsub(c1, c2): + """ + Subtract one Laguerre series from another. + + Returns the difference of two Laguerre series `c1` - `c2`. The + sequences of coefficients are from lowest order term to highest, i.e., + [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Laguerre series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Laguerre series coefficients representing their difference. + + See Also + -------- + lagadd, lagmul, lagdiv, lagpow + + Notes + ----- + Unlike multiplication, division, etc., the difference of two Laguerre + series is a Laguerre series (without having to "reproject" the result + onto the basis set) so subtraction, just like that of "standard" + polynomials, is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagsub + >>> lagsub([1, 2, 3, 4], [1, 2, 3]) + array([ 0., 0., 0., 4.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] -= c2 + ret = c1 + else: + c2 = -c2 + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def lagmulx(c): + """Multiply a Laguerre series by x. + + Multiply the Laguerre series `c` by x, where x is the independent + variable. + + + Parameters + ---------- + c : array_like + 1-D array of Laguerre series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the result of the multiplication. + + Notes + ----- + The multiplication uses the recursion relationship for Laguerre + polynomials in the form + + .. math:: + + xP_i(x) = (-(i + 1)*P_{i + 1}(x) + (2i + 1)P_{i}(x) - iP_{i - 1}(x)) + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagmulx + >>> lagmulx([1, 2, 3]) + array([ -1., -1., 11., -9.]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + # The zero series needs special treatment + if len(c) == 1 and c[0] == 0: + return c + + prd = np.empty(len(c) + 1, dtype=c.dtype) + prd[0] = c[0] + prd[1] = -c[0] + for i in range(1, len(c)): + prd[i + 1] = -c[i]*(i + 1) + prd[i] += c[i]*(2*i + 1) + prd[i - 1] -= c[i]*i + return prd + + +def lagmul(c1, c2): + """ + Multiply one Laguerre series by another. + + Returns the product of two Laguerre series `c1` * `c2`. The arguments + are sequences of coefficients, from lowest order "term" to highest, + e.g., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Laguerre series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Laguerre series coefficients representing their product. + + See Also + -------- + lagadd, lagsub, lagdiv, lagpow + + Notes + ----- + In general, the (polynomial) product of two C-series results in terms + that are not in the Laguerre polynomial basis set. Thus, to express + the product as a Laguerre series, it is necessary to "reproject" the + product onto said basis set, which may produce "unintuitive" (but + correct) results; see Examples section below. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagmul + >>> lagmul([1, 2, 3], [0, 1, 2]) + array([ 8., -13., 38., -51., 36.]) + + """ + # s1, s2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + + if len(c1) > len(c2): + c = c2 + xs = c1 + else: + c = c1 + xs = c2 + + if len(c) == 1: + c0 = c[0]*xs + c1 = 0 + elif len(c) == 2: + c0 = c[0]*xs + c1 = c[1]*xs + else: + nd = len(c) + c0 = c[-2]*xs + c1 = c[-1]*xs + for i in range(3, len(c) + 1): + tmp = c0 + nd = nd - 1 + c0 = lagsub(c[-i]*xs, (c1*(nd - 1))/nd) + c1 = lagadd(tmp, lagsub((2*nd - 1)*c1, lagmulx(c1))/nd) + return lagadd(c0, lagsub(c1, lagmulx(c1))) + + +def lagdiv(c1, c2): + """ + Divide one Laguerre series by another. + + Returns the quotient-with-remainder of two Laguerre series + `c1` / `c2`. The arguments are sequences of coefficients from lowest + order "term" to highest, e.g., [1,2,3] represents the series + ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Laguerre series coefficients ordered from low to + high. + + Returns + ------- + [quo, rem] : ndarrays + Of Laguerre series coefficients representing the quotient and + remainder. + + See Also + -------- + lagadd, lagsub, lagmul, lagpow + + Notes + ----- + In general, the (polynomial) division of one Laguerre series by another + results in quotient and remainder terms that are not in the Laguerre + polynomial basis set. Thus, to express these results as a Laguerre + series, it is necessary to "reproject" the results onto the Laguerre + basis set, which may produce "unintuitive" (but correct) results; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagdiv + >>> lagdiv([ 8., -13., 38., -51., 36.], [0, 1, 2]) + (array([ 1., 2., 3.]), array([ 0.])) + >>> lagdiv([ 9., -12., 38., -51., 36.], [0, 1, 2]) + (array([ 1., 2., 3.]), array([ 1., 1.])) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if c2[-1] == 0: + raise ZeroDivisionError() + + lc1 = len(c1) + lc2 = len(c2) + if lc1 < lc2: + return c1[:1]*0, c1 + elif lc2 == 1: + return c1/c2[-1], c1[:1]*0 + else: + quo = np.empty(lc1 - lc2 + 1, dtype=c1.dtype) + rem = c1 + for i in range(lc1 - lc2, - 1, -1): + p = lagmul([0]*i + [1], c2) + q = rem[-1]/p[-1] + rem = rem[:-1] - q*p[:-1] + quo[i] = q + return quo, pu.trimseq(rem) + + +def lagpow(c, pow, maxpower=16): + """Raise a Laguerre series to a power. + + Returns the Laguerre series `c` raised to the power `pow`. The + argument `c` is a sequence of coefficients ordered from low to high. + i.e., [1,2,3] is the series ``P_0 + 2*P_1 + 3*P_2.`` + + Parameters + ---------- + c : array_like + 1-D array of Laguerre series coefficients ordered from low to + high. + pow : integer + Power to which the series will be raised + maxpower : integer, optional + Maximum power allowed. This is mainly to limit growth of the series + to unmanageable size. Default is 16 + + Returns + ------- + coef : ndarray + Laguerre series of power. + + See Also + -------- + lagadd, lagsub, lagmul, lagdiv + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagpow + >>> lagpow([1, 2, 3], 2) + array([ 14., -16., 56., -72., 54.]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + power = int(pow) + if power != pow or power < 0: + raise ValueError("Power must be a non-negative integer.") + elif maxpower is not None and power > maxpower: + raise ValueError("Power is too large") + elif power == 0: + return np.array([1], dtype=c.dtype) + elif power == 1: + return c + else: + # This can be made more efficient by using powers of two + # in the usual way. + prd = c + for i in range(2, power + 1): + prd = lagmul(prd, c) + return prd + + +def lagder(c, m=1, scl=1, axis=0): + """ + Differentiate a Laguerre series. + + Returns the Laguerre series coefficients `c` differentiated `m` times + along `axis`. At each iteration the result is multiplied by `scl` (the + scaling factor is for use in a linear change of variable). The argument + `c` is an array of coefficients from low to high degree along each + axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2`` + while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + + 2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is + ``y``. + + Parameters + ---------- + c : array_like + Array of Laguerre series coefficients. If `c` is multidimensional + the different axis correspond to different variables with the + degree in each axis given by the corresponding index. + m : int, optional + Number of derivatives taken, must be non-negative. (Default: 1) + scl : scalar, optional + Each differentiation is multiplied by `scl`. The end result is + multiplication by ``scl**m``. This is for use in a linear change of + variable. (Default: 1) + axis : int, optional + Axis over which the derivative is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + der : ndarray + Laguerre series of the derivative. + + See Also + -------- + lagint + + Notes + ----- + In general, the result of differentiating a Laguerre series does not + resemble the same operation on a power series. Thus the result of this + function may be "unintuitive," albeit correct; see Examples section + below. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagder + >>> lagder([ 1., 1., 1., -3.]) + array([ 1., 2., 3.]) + >>> lagder([ 1., 0., 0., -4., 3.], m=2) + array([ 1., 2., 3.]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of derivation must be integer") + if cnt < 0: + raise ValueError("The order of derivation must be non-negative") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + n = len(c) + if cnt >= n: + c = c[:1]*0 + else: + for i in range(cnt): + n = n - 1 + c *= scl + der = np.empty((n,) + c.shape[1:], dtype=c.dtype) + for j in range(n, 1, -1): + der[j - 1] = -c[j] + c[j - 1] += c[j] + der[0] = -c[1] + c = der + c = np.moveaxis(c, 0, iaxis) + return c + + +def lagint(c, m=1, k=[], lbnd=0, scl=1, axis=0): + """ + Integrate a Laguerre series. + + Returns the Laguerre series coefficients `c` integrated `m` times from + `lbnd` along `axis`. At each iteration the resulting series is + **multiplied** by `scl` and an integration constant, `k`, is added. + The scaling factor is for use in a linear change of variable. ("Buyer + beware": note that, depending on what one is doing, one may want `scl` + to be the reciprocal of what one might expect; for more information, + see the Notes section below.) The argument `c` is an array of + coefficients from low to high degree along each axis, e.g., [1,2,3] + represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]] + represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) + + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. + + + Parameters + ---------- + c : array_like + Array of Laguerre series coefficients. If `c` is multidimensional + the different axis correspond to different variables with the + degree in each axis given by the corresponding index. + m : int, optional + Order of integration, must be positive. (Default: 1) + k : {[], list, scalar}, optional + Integration constant(s). The value of the first integral at + ``lbnd`` is the first value in the list, the value of the second + integral at ``lbnd`` is the second value, etc. If ``k == []`` (the + default), all constants are set to zero. If ``m == 1``, a single + scalar can be given instead of a list. + lbnd : scalar, optional + The lower bound of the integral. (Default: 0) + scl : scalar, optional + Following each integration the result is *multiplied* by `scl` + before the integration constant is added. (Default: 1) + axis : int, optional + Axis over which the integral is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + S : ndarray + Laguerre series coefficients of the integral. + + Raises + ------ + ValueError + If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or + ``np.ndim(scl) != 0``. + + See Also + -------- + lagder + + Notes + ----- + Note that the result of each integration is *multiplied* by `scl`. + Why is this important to note? Say one is making a linear change of + variable :math:`u = ax + b` in an integral relative to `x`. Then + :math:`dx = du/a`, so one will need to set `scl` equal to + :math:`1/a` - perhaps not what one would have first thought. + + Also note that, in general, the result of integrating a C-series needs + to be "reprojected" onto the C-series basis set. Thus, typically, + the result of this function is "unintuitive," albeit correct; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagint + >>> lagint([1,2,3]) + array([ 1., 1., 1., -3.]) + >>> lagint([1,2,3], m=2) + array([ 1., 0., 0., -4., 3.]) + >>> lagint([1,2,3], k=1) + array([ 2., 1., 1., -3.]) + >>> lagint([1,2,3], lbnd=-1) + array([ 11.5, 1. , 1. , -3. ]) + >>> lagint([1,2], m=2, k=[1,2], lbnd=-1) + array([ 11.16666667, -5. , -3. , 2. ]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if not np.iterable(k): + k = [k] + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of integration must be integer") + if cnt < 0: + raise ValueError("The order of integration must be non-negative") + if len(k) > cnt: + raise ValueError("Too many integration constants") + if np.ndim(lbnd) != 0: + raise ValueError("lbnd must be a scalar.") + if np.ndim(scl) != 0: + raise ValueError("scl must be a scalar.") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + k = list(k) + [0]*(cnt - len(k)) + for i in range(cnt): + n = len(c) + c *= scl + if n == 1 and np.all(c[0] == 0): + c[0] += k[i] + else: + tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype) + tmp[0] = c[0] + tmp[1] = -c[0] + for j in range(1, n): + tmp[j] += c[j] + tmp[j + 1] = -c[j] + tmp[0] += k[i] - lagval(lbnd, tmp) + c = tmp + c = np.moveaxis(c, 0, iaxis) + return c + + +def lagval(x, c, tensor=True): + """ + Evaluate a Laguerre series at points x. + + If `c` is of length `n + 1`, this function returns the value: + + .. math:: p(x) = c_0 * L_0(x) + c_1 * L_1(x) + ... + c_n * L_n(x) + + The parameter `x` is converted to an array only if it is a tuple or a + list, otherwise it is treated as a scalar. In either case, either `x` + or its elements must support multiplication and addition both with + themselves and with the elements of `c`. + + If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If + `c` is multidimensional, then the shape of the result depends on the + value of `tensor`. If `tensor` is true the shape will be c.shape[1:] + + x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that + scalars have shape (,). + + Trailing zeros in the coefficients will be used in the evaluation, so + they should be avoided if efficiency is a concern. + + Parameters + ---------- + x : array_like, compatible object + If `x` is a list or tuple, it is converted to an ndarray, otherwise + it is left unchanged and treated as a scalar. In either case, `x` + or its elements must support addition and multiplication with + with themselves and with the elements of `c`. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree n are contained in c[n]. If `c` is multidimensional the + remaining indices enumerate multiple polynomials. In the two + dimensional case the coefficients may be thought of as stored in + the columns of `c`. + tensor : boolean, optional + If True, the shape of the coefficient array is extended with ones + on the right, one for each dimension of `x`. Scalars have dimension 0 + for this action. The result is that every column of coefficients in + `c` is evaluated for every element of `x`. If False, `x` is broadcast + over the columns of `c` for the evaluation. This keyword is useful + when `c` is multidimensional. The default value is True. + + .. versionadded:: 1.7.0 + + Returns + ------- + values : ndarray, algebra_like + The shape of the return value is described above. + + See Also + -------- + lagval2d, laggrid2d, lagval3d, laggrid3d + + Notes + ----- + The evaluation uses Clenshaw recursion, aka synthetic division. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagval + >>> coef = [1,2,3] + >>> lagval(1, coef) + -0.5 + >>> lagval([[1,2],[3,4]], coef) + array([[-0.5, -4. ], + [-4.5, -2. ]]) + + """ + c = np.array(c, ndmin=1, copy=0) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if isinstance(x, (tuple, list)): + x = np.asarray(x) + if isinstance(x, np.ndarray) and tensor: + c = c.reshape(c.shape + (1,)*x.ndim) + + if len(c) == 1: + c0 = c[0] + c1 = 0 + elif len(c) == 2: + c0 = c[0] + c1 = c[1] + else: + nd = len(c) + c0 = c[-2] + c1 = c[-1] + for i in range(3, len(c) + 1): + tmp = c0 + nd = nd - 1 + c0 = c[-i] - (c1*(nd - 1))/nd + c1 = tmp + (c1*((2*nd - 1) - x))/nd + return c0 + c1*(1 - x) + + +def lagval2d(x, y, c): + """ + Evaluate a 2-D Laguerre series at points (x, y). + + This function returns the values: + + .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * L_i(x) * L_j(y) + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars and they + must have the same shape after conversion. In either case, either `x` + and `y` or their elements must support multiplication and addition both + with themselves and with the elements of `c`. + + If `c` is a 1-D array a one is implicitly appended to its shape to make + it 2-D. The shape of the result will be c.shape[2:] + x.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points `(x, y)`, + where `x` and `y` must have the same shape. If `x` or `y` is a list + or tuple, it is first converted to an ndarray, otherwise it is left + unchanged and if it isn't an ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term + of multi-degree i,j is contained in ``c[i,j]``. If `c` has + dimension greater than two the remaining indices enumerate multiple + sets of coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points formed with + pairs of corresponding values from `x` and `y`. + + See Also + -------- + lagval, laggrid2d, lagval3d, laggrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y = np.array((x, y), copy=0) + except Exception: + raise ValueError('x, y are incompatible') + + c = lagval(x, c) + c = lagval(y, c, tensor=False) + return c + + +def laggrid2d(x, y, c): + """ + Evaluate a 2-D Laguerre series on the Cartesian product of x and y. + + This function returns the values: + + .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * L_i(a) * L_j(b) + + where the points `(a, b)` consist of all pairs formed by taking + `a` from `x` and `b` from `y`. The resulting points form a grid with + `x` in the first dimension and `y` in the second. + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars. In either + case, either `x` and `y` or their elements must support multiplication + and addition both with themselves and with the elements of `c`. + + If `c` has fewer than two dimensions, ones are implicitly appended to + its shape to make it 2-D. The shape of the result will be c.shape[2:] + + x.shape + y.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points in the + Cartesian product of `x` and `y`. If `x` or `y` is a list or + tuple, it is first converted to an ndarray, otherwise it is left + unchanged and, if it isn't an ndarray, it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j is contained in `c[i,j]`. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional Chebyshev series at points in the + Cartesian product of `x` and `y`. + + See Also + -------- + lagval, lagval2d, lagval3d, laggrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = lagval(x, c) + c = lagval(y, c) + return c + + +def lagval3d(x, y, z, c): + """ + Evaluate a 3-D Laguerre series at points (x, y, z). + + This function returns the values: + + .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * L_i(x) * L_j(y) * L_k(z) + + The parameters `x`, `y`, and `z` are converted to arrays only if + they are tuples or a lists, otherwise they are treated as a scalars and + they must have the same shape after conversion. In either case, either + `x`, `y`, and `z` or their elements must support multiplication and + addition both with themselves and with the elements of `c`. + + If `c` has fewer than 3 dimensions, ones are implicitly appended to its + shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape. + + Parameters + ---------- + x, y, z : array_like, compatible object + The three dimensional series is evaluated at the points + `(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If + any of `x`, `y`, or `z` is a list or tuple, it is first converted + to an ndarray, otherwise it is left unchanged and if it isn't an + ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension + greater than 3 the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the multidimension polynomial on points formed with + triples of corresponding values from `x`, `y`, and `z`. + + See Also + -------- + lagval, lagval2d, laggrid2d, laggrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y, z = np.array((x, y, z), copy=0) + except Exception: + raise ValueError('x, y, z are incompatible') + + c = lagval(x, c) + c = lagval(y, c, tensor=False) + c = lagval(z, c, tensor=False) + return c + + +def laggrid3d(x, y, z, c): + """ + Evaluate a 3-D Laguerre series on the Cartesian product of x, y, and z. + + This function returns the values: + + .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * L_i(a) * L_j(b) * L_k(c) + + where the points `(a, b, c)` consist of all triples formed by taking + `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form + a grid with `x` in the first dimension, `y` in the second, and `z` in + the third. + + The parameters `x`, `y`, and `z` are converted to arrays only if they + are tuples or a lists, otherwise they are treated as a scalars. In + either case, either `x`, `y`, and `z` or their elements must support + multiplication and addition both with themselves and with the elements + of `c`. + + If `c` has fewer than three dimensions, ones are implicitly appended to + its shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape + y.shape + z.shape. + + Parameters + ---------- + x, y, z : array_like, compatible objects + The three dimensional series is evaluated at the points in the + Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a + list or tuple, it is first converted to an ndarray, otherwise it is + left unchanged and, if it isn't an ndarray, it is treated as a + scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + lagval, lagval2d, laggrid2d, lagval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = lagval(x, c) + c = lagval(y, c) + c = lagval(z, c) + return c + + +def lagvander(x, deg): + """Pseudo-Vandermonde matrix of given degree. + + Returns the pseudo-Vandermonde matrix of degree `deg` and sample points + `x`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., i] = L_i(x) + + where `0 <= i <= deg`. The leading indices of `V` index the elements of + `x` and the last index is the degree of the Laguerre polynomial. + + If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the + array ``V = lagvander(x, n)``, then ``np.dot(V, c)`` and + ``lagval(x, c)`` are the same up to roundoff. This equivalence is + useful both for least squares fitting and for the evaluation of a large + number of Laguerre series of the same degree and sample points. + + Parameters + ---------- + x : array_like + Array of points. The dtype is converted to float64 or complex128 + depending on whether any of the elements are complex. If `x` is + scalar it is converted to a 1-D array. + deg : int + Degree of the resulting matrix. + + Returns + ------- + vander : ndarray + The pseudo-Vandermonde matrix. The shape of the returned matrix is + ``x.shape + (deg + 1,)``, where The last index is the degree of the + corresponding Laguerre polynomial. The dtype will be the same as + the converted `x`. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagvander + >>> x = np.array([0, 1, 2]) + >>> lagvander(x, 3) + array([[ 1. , 1. , 1. , 1. ], + [ 1. , 0. , -0.5 , -0.66666667], + [ 1. , -1. , -1. , -0.33333333]]) + + """ + ideg = int(deg) + if ideg != deg: + raise ValueError("deg must be integer") + if ideg < 0: + raise ValueError("deg must be non-negative") + + x = np.array(x, copy=0, ndmin=1) + 0.0 + dims = (ideg + 1,) + x.shape + dtyp = x.dtype + v = np.empty(dims, dtype=dtyp) + v[0] = x*0 + 1 + if ideg > 0: + v[1] = 1 - x + for i in range(2, ideg + 1): + v[i] = (v[i-1]*(2*i - 1 - x) - v[i-2]*(i - 1))/i + return np.moveaxis(v, 0, -1) + + +def lagvander2d(x, y, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y)`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (deg[1] + 1)*i + j] = L_i(x) * L_j(y), + + where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of + `V` index the points `(x, y)` and the last index encodes the degrees of + the Laguerre polynomials. + + If ``V = lagvander2d(x, y, [xdeg, ydeg])``, then the columns of `V` + correspond to the elements of a 2-D coefficient array `c` of shape + (xdeg + 1, ydeg + 1) in the order + + .. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ... + + and ``np.dot(V, c.flat)`` and ``lagval2d(x, y, c)`` will be the same + up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 2-D Laguerre + series of the same degrees and sample points. + + Parameters + ---------- + x, y : array_like + Arrays of point coordinates, all of the same shape. The dtypes + will be converted to either float64 or complex128 depending on + whether any of the elements are complex. Scalars are converted to + 1-D arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg]. + + Returns + ------- + vander2d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)`. The dtype will be the same + as the converted `x` and `y`. + + See Also + -------- + lagvander, lagvander3d. lagval2d, lagval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy = ideg + x, y = np.array((x, y), copy=0) + 0.0 + + vx = lagvander(x, degx) + vy = lagvander(y, degy) + v = vx[..., None]*vy[..., None,:] + return v.reshape(v.shape[:-2] + (-1,)) + + +def lagvander3d(x, y, z, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`, + then The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = L_i(x)*L_j(y)*L_k(z), + + where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading + indices of `V` index the points `(x, y, z)` and the last index encodes + the degrees of the Laguerre polynomials. + + If ``V = lagvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns + of `V` correspond to the elements of a 3-D coefficient array `c` of + shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order + + .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},... + + and ``np.dot(V, c.flat)`` and ``lagval3d(x, y, z, c)`` will be the + same up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 3-D Laguerre + series of the same degrees and sample points. + + Parameters + ---------- + x, y, z : array_like + Arrays of point coordinates, all of the same shape. The dtypes will + be converted to either float64 or complex128 depending on whether + any of the elements are complex. Scalars are converted to 1-D + arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg, z_deg]. + + Returns + ------- + vander3d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)*(deg[2]+1)`. The dtype will + be the same as the converted `x`, `y`, and `z`. + + See Also + -------- + lagvander, lagvander3d. lagval2d, lagval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy, degz = ideg + x, y, z = np.array((x, y, z), copy=0) + 0.0 + + vx = lagvander(x, degx) + vy = lagvander(y, degy) + vz = lagvander(z, degz) + v = vx[..., None, None]*vy[..., None,:, None]*vz[..., None, None,:] + return v.reshape(v.shape[:-3] + (-1,)) + + +def lagfit(x, y, deg, rcond=None, full=False, w=None): + """ + Least squares fit of Laguerre series to data. + + Return the coefficients of a Laguerre series of degree `deg` that is the + least squares fit to the data values `y` given at points `x`. If `y` is + 1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple + fits are done, one for each column of `y`, and the resulting + coefficients are stored in the corresponding columns of a 2-D return. + The fitted polynomial(s) are in the form + + .. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x), + + where `n` is `deg`. + + Parameters + ---------- + x : array_like, shape (M,) + x-coordinates of the M sample points ``(x[i], y[i])``. + y : array_like, shape (M,) or (M, K) + y-coordinates of the sample points. Several data sets of sample + points sharing the same x-coordinates can be fitted at once by + passing in a 2D-array that contains one dataset per column. + deg : int or 1-D array_like + Degree(s) of the fitting polynomials. If `deg` is a single integer + all terms up to and including the `deg`'th term are included in the + fit. For NumPy versions >= 1.11.0 a list of integers specifying the + degrees of the terms to include may be used instead. + rcond : float, optional + Relative condition number of the fit. Singular values smaller than + this relative to the largest singular value will be ignored. The + default value is len(x)*eps, where eps is the relative precision of + the float type, about 2e-16 in most cases. + full : bool, optional + Switch determining nature of return value. When it is False (the + default) just the coefficients are returned, when True diagnostic + information from the singular value decomposition is also returned. + w : array_like, shape (`M`,), optional + Weights. If not None, the contribution of each point + ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the + weights are chosen so that the errors of the products ``w[i]*y[i]`` + all have the same variance. The default value is None. + + Returns + ------- + coef : ndarray, shape (M,) or (M, K) + Laguerre coefficients ordered from low to high. If `y` was 2-D, + the coefficients for the data in column k of `y` are in column + `k`. + + [residuals, rank, singular_values, rcond] : list + These values are only returned if `full` = True + + resid -- sum of squared residuals of the least squares fit + rank -- the numerical rank of the scaled Vandermonde matrix + sv -- singular values of the scaled Vandermonde matrix + rcond -- value of `rcond`. + + For more details, see `linalg.lstsq`. + + Warns + ----- + RankWarning + The rank of the coefficient matrix in the least-squares fit is + deficient. The warning is only raised if `full` = False. The + warnings can be turned off by + + >>> import warnings + >>> warnings.simplefilter('ignore', RankWarning) + + See Also + -------- + chebfit, legfit, polyfit, hermfit, hermefit + lagval : Evaluates a Laguerre series. + lagvander : pseudo Vandermonde matrix of Laguerre series. + lagweight : Laguerre weight function. + linalg.lstsq : Computes a least-squares fit from the matrix. + scipy.interpolate.UnivariateSpline : Computes spline fits. + + Notes + ----- + The solution is the coefficients of the Laguerre series `p` that + minimizes the sum of the weighted squared errors + + .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2, + + where the :math:`w_j` are the weights. This problem is solved by + setting up as the (typically) overdetermined matrix equation + + .. math:: V(x) * c = w * y, + + where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the + coefficients to be solved for, `w` are the weights, and `y` are the + observed values. This equation is then solved using the singular value + decomposition of `V`. + + If some of the singular values of `V` are so small that they are + neglected, then a `RankWarning` will be issued. This means that the + coefficient values may be poorly determined. Using a lower order fit + will usually get rid of the warning. The `rcond` parameter can also be + set to a value smaller than its default, but the resulting fit may be + spurious and have large contributions from roundoff error. + + Fits using Laguerre series are probably most useful when the data can + be approximated by ``sqrt(w(x)) * p(x)``, where `w(x)` is the Laguerre + weight. In that case the weight ``sqrt(w(x[i])`` should be used + together with data values ``y[i]/sqrt(w(x[i])``. The weight function is + available as `lagweight`. + + References + ---------- + .. [1] Wikipedia, "Curve fitting", + http://en.wikipedia.org/wiki/Curve_fitting + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagfit, lagval + >>> x = np.linspace(0, 10) + >>> err = np.random.randn(len(x))/10 + >>> y = lagval(x, [1, 2, 3]) + err + >>> lagfit(x, y, 2) + array([ 0.96971004, 2.00193749, 3.00288744]) + + """ + x = np.asarray(x) + 0.0 + y = np.asarray(y) + 0.0 + deg = np.asarray(deg) + + # check arguments. + if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0: + raise TypeError("deg must be an int or non-empty 1-D array of int") + if deg.min() < 0: + raise ValueError("expected deg >= 0") + if x.ndim != 1: + raise TypeError("expected 1D vector for x") + if x.size == 0: + raise TypeError("expected non-empty vector for x") + if y.ndim < 1 or y.ndim > 2: + raise TypeError("expected 1D or 2D array for y") + if len(x) != len(y): + raise TypeError("expected x and y to have same length") + + if deg.ndim == 0: + lmax = deg + order = lmax + 1 + van = lagvander(x, lmax) + else: + deg = np.sort(deg) + lmax = deg[-1] + order = len(deg) + van = lagvander(x, lmax)[:, deg] + + # set up the least squares matrices in transposed form + lhs = van.T + rhs = y.T + if w is not None: + w = np.asarray(w) + 0.0 + if w.ndim != 1: + raise TypeError("expected 1D vector for w") + if len(x) != len(w): + raise TypeError("expected x and w to have same length") + # apply weights. Don't use inplace operations as they + # can cause problems with NA. + lhs = lhs * w + rhs = rhs * w + + # set rcond + if rcond is None: + rcond = len(x)*np.finfo(x.dtype).eps + + # Determine the norms of the design matrix columns. + if issubclass(lhs.dtype.type, np.complexfloating): + scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1)) + else: + scl = np.sqrt(np.square(lhs).sum(1)) + scl[scl == 0] = 1 + + # Solve the least squares problem. + c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond) + c = (c.T/scl).T + + # Expand c to include non-fitted coefficients which are set to zero + if deg.ndim > 0: + if c.ndim == 2: + cc = np.zeros((lmax+1, c.shape[1]), dtype=c.dtype) + else: + cc = np.zeros(lmax+1, dtype=c.dtype) + cc[deg] = c + c = cc + + # warn on rank reduction + if rank != order and not full: + msg = "The fit may be poorly conditioned" + warnings.warn(msg, pu.RankWarning, stacklevel=2) + + if full: + return c, [resids, rank, s, rcond] + else: + return c + + +def lagcompanion(c): + """ + Return the companion matrix of c. + + The usual companion matrix of the Laguerre polynomials is already + symmetric when `c` is a basis Laguerre polynomial, so no scaling is + applied. + + Parameters + ---------- + c : array_like + 1-D array of Laguerre series coefficients ordered from low to high + degree. + + Returns + ------- + mat : ndarray + Companion matrix of dimensions (deg, deg). + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + raise ValueError('Series must have maximum degree of at least 1.') + if len(c) == 2: + return np.array([[1 + c[0]/c[1]]]) + + n = len(c) - 1 + mat = np.zeros((n, n), dtype=c.dtype) + top = mat.reshape(-1)[1::n+1] + mid = mat.reshape(-1)[0::n+1] + bot = mat.reshape(-1)[n::n+1] + top[...] = -np.arange(1, n) + mid[...] = 2.*np.arange(n) + 1. + bot[...] = top + mat[:, -1] += (c[:-1]/c[-1])*n + return mat + + +def lagroots(c): + """ + Compute the roots of a Laguerre series. + + Return the roots (a.k.a. "zeros") of the polynomial + + .. math:: p(x) = \\sum_i c[i] * L_i(x). + + Parameters + ---------- + c : 1-D array_like + 1-D array of coefficients. + + Returns + ------- + out : ndarray + Array of the roots of the series. If all the roots are real, + then `out` is also real, otherwise it is complex. + + See Also + -------- + polyroots, legroots, chebroots, hermroots, hermeroots + + Notes + ----- + The root estimates are obtained as the eigenvalues of the companion + matrix, Roots far from the origin of the complex plane may have large + errors due to the numerical instability of the series for such + values. Roots with multiplicity greater than 1 will also show larger + errors as the value of the series near such points is relatively + insensitive to errors in the roots. Isolated roots near the origin can + be improved by a few iterations of Newton's method. + + The Laguerre series basis polynomials aren't powers of `x` so the + results of this function may seem unintuitive. + + Examples + -------- + >>> from numpy.polynomial.laguerre import lagroots, lagfromroots + >>> coef = lagfromroots([0, 1, 2]) + >>> coef + array([ 2., -8., 12., -6.]) + >>> lagroots(coef) + array([ -4.44089210e-16, 1.00000000e+00, 2.00000000e+00]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) <= 1: + return np.array([], dtype=c.dtype) + if len(c) == 2: + return np.array([1 + c[0]/c[1]]) + + m = lagcompanion(c) + r = la.eigvals(m) + r.sort() + return r + + +def laggauss(deg): + """ + Gauss-Laguerre quadrature. + + Computes the sample points and weights for Gauss-Laguerre quadrature. + These sample points and weights will correctly integrate polynomials of + degree :math:`2*deg - 1` or less over the interval :math:`[0, \\inf]` + with the weight function :math:`f(x) = \\exp(-x)`. + + Parameters + ---------- + deg : int + Number of sample points and weights. It must be >= 1. + + Returns + ------- + x : ndarray + 1-D ndarray containing the sample points. + y : ndarray + 1-D ndarray containing the weights. + + Notes + ----- + + .. versionadded:: 1.7.0 + + The results have only been tested up to degree 100 higher degrees may + be problematic. The weights are determined by using the fact that + + .. math:: w_k = c / (L'_n(x_k) * L_{n-1}(x_k)) + + where :math:`c` is a constant independent of :math:`k` and :math:`x_k` + is the k'th root of :math:`L_n`, and then scaling the results to get + the right value when integrating 1. + + """ + ideg = int(deg) + if ideg != deg or ideg < 1: + raise ValueError("deg must be a non-negative integer") + + # first approximation of roots. We use the fact that the companion + # matrix is symmetric in this case in order to obtain better zeros. + c = np.array([0]*deg + [1]) + m = lagcompanion(c) + x = la.eigvalsh(m) + + # improve roots by one application of Newton + dy = lagval(x, c) + df = lagval(x, lagder(c)) + x -= dy/df + + # compute the weights. We scale the factor to avoid possible numerical + # overflow. + fm = lagval(x, c[1:]) + fm /= np.abs(fm).max() + df /= np.abs(df).max() + w = 1/(fm * df) + + # scale w to get the right value, 1 in this case + w /= w.sum() + + return x, w + + +def lagweight(x): + """Weight function of the Laguerre polynomials. + + The weight function is :math:`exp(-x)` and the interval of integration + is :math:`[0, \\inf]`. The Laguerre polynomials are orthogonal, but not + normalized, with respect to this weight function. + + Parameters + ---------- + x : array_like + Values at which the weight function will be computed. + + Returns + ------- + w : ndarray + The weight function at `x`. + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + w = np.exp(-x) + return w + +# +# Laguerre series class +# + +class Laguerre(ABCPolyBase): + """A Laguerre series class. + + The Laguerre class provides the standard Python numerical methods + '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the + attributes and methods listed in the `ABCPolyBase` documentation. + + Parameters + ---------- + coef : array_like + Laguerre coefficients in order of increasing degree, i.e, + ``(1, 2, 3)`` gives ``1*L_0(x) + 2*L_1(X) + 3*L_2(x)``. + domain : (2,) array_like, optional + Domain to use. The interval ``[domain[0], domain[1]]`` is mapped + to the interval ``[window[0], window[1]]`` by shifting and scaling. + The default value is [0, 1]. + window : (2,) array_like, optional + Window, see `domain` for its use. The default value is [0, 1]. + + .. versionadded:: 1.6.0 + + """ + # Virtual Functions + _add = staticmethod(lagadd) + _sub = staticmethod(lagsub) + _mul = staticmethod(lagmul) + _div = staticmethod(lagdiv) + _pow = staticmethod(lagpow) + _val = staticmethod(lagval) + _int = staticmethod(lagint) + _der = staticmethod(lagder) + _fit = staticmethod(lagfit) + _line = staticmethod(lagline) + _roots = staticmethod(lagroots) + _fromroots = staticmethod(lagfromroots) + + # Virtual properties + nickname = 'lag' + domain = np.array(lagdomain) + window = np.array(lagdomain) diff --git a/numpy/polynomial/legendre.py b/numpy/polynomial/legendre.py new file mode 100644 index 0000000..0d4a49a --- /dev/null +++ b/numpy/polynomial/legendre.py @@ -0,0 +1,1833 @@ +""" +Legendre Series (:mod: `numpy.polynomial.legendre`) +=================================================== + +.. currentmodule:: numpy.polynomial.polynomial + +This module provides a number of objects (mostly functions) useful for +dealing with Legendre series, including a `Legendre` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with such polynomials is in the +docstring for its "parent" sub-package, `numpy.polynomial`). + +Constants +--------- + +.. autosummary:: + :toctree: generated/ + + legdomain Legendre series default domain, [-1,1]. + legzero Legendre series that evaluates identically to 0. + legone Legendre series that evaluates identically to 1. + legx Legendre series for the identity map, ``f(x) = x``. + +Arithmetic +---------- + +.. autosummary:: + :toctree: generated/ + + legmulx multiply a Legendre series in P_i(x) by x. + legadd add two Legendre series. + legsub subtract one Legendre series from another. + legmul multiply two Legendre series. + legdiv divide one Legendre series by another. + legpow raise a Legendre series to an positive integer power + legval evaluate a Legendre series at given points. + legval2d evaluate a 2D Legendre series at given points. + legval3d evaluate a 3D Legendre series at given points. + leggrid2d evaluate a 2D Legendre series on a Cartesian product. + leggrid3d evaluate a 3D Legendre series on a Cartesian product. + +Calculus +-------- + +.. autosummary:: + :toctree: generated/ + + legder differentiate a Legendre series. + legint integrate a Legendre series. + +Misc Functions +-------------- + +.. autosummary:: + :toctree: generated/ + + legfromroots create a Legendre series with specified roots. + legroots find the roots of a Legendre series. + legvander Vandermonde-like matrix for Legendre polynomials. + legvander2d Vandermonde-like matrix for 2D power series. + legvander3d Vandermonde-like matrix for 3D power series. + leggauss Gauss-Legendre quadrature, points and weights. + legweight Legendre weight function. + legcompanion symmetrized companion matrix in Legendre form. + legfit least-squares fit returning a Legendre series. + legtrim trim leading coefficients from a Legendre series. + legline Legendre series representing given straight line. + leg2poly convert a Legendre series to a polynomial. + poly2leg convert a polynomial to a Legendre series. + +Classes +------- + Legendre A Legendre series class. + +See also +-------- +numpy.polynomial.polynomial +numpy.polynomial.chebyshev +numpy.polynomial.laguerre +numpy.polynomial.hermite +numpy.polynomial.hermite_e + +""" +from __future__ import division, absolute_import, print_function + +import warnings +import numpy as np +import numpy.linalg as la +from numpy.core.multiarray import normalize_axis_index + +from . import polyutils as pu +from ._polybase import ABCPolyBase + +__all__ = [ + 'legzero', 'legone', 'legx', 'legdomain', 'legline', 'legadd', + 'legsub', 'legmulx', 'legmul', 'legdiv', 'legpow', 'legval', 'legder', + 'legint', 'leg2poly', 'poly2leg', 'legfromroots', 'legvander', + 'legfit', 'legtrim', 'legroots', 'Legendre', 'legval2d', 'legval3d', + 'leggrid2d', 'leggrid3d', 'legvander2d', 'legvander3d', 'legcompanion', + 'leggauss', 'legweight'] + +legtrim = pu.trimcoef + + +def poly2leg(pol): + """ + Convert a polynomial to a Legendre series. + + Convert an array representing the coefficients of a polynomial (relative + to the "standard" basis) ordered from lowest degree to highest, to an + array of the coefficients of the equivalent Legendre series, ordered + from lowest to highest degree. + + Parameters + ---------- + pol : array_like + 1-D array containing the polynomial coefficients + + Returns + ------- + c : ndarray + 1-D array containing the coefficients of the equivalent Legendre + series. + + See Also + -------- + leg2poly + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> from numpy import polynomial as P + >>> p = P.Polynomial(np.arange(4)) + >>> p + Polynomial([ 0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1]) + >>> c = P.Legendre(P.legendre.poly2leg(p.coef)) + >>> c + Legendre([ 1. , 3.25, 1. , 0.75], domain=[-1, 1], window=[-1, 1]) + + """ + [pol] = pu.as_series([pol]) + deg = len(pol) - 1 + res = 0 + for i in range(deg, -1, -1): + res = legadd(legmulx(res), pol[i]) + return res + + +def leg2poly(c): + """ + Convert a Legendre series to a polynomial. + + Convert an array representing the coefficients of a Legendre series, + ordered from lowest degree to highest, to an array of the coefficients + of the equivalent polynomial (relative to the "standard" basis) ordered + from lowest to highest degree. + + Parameters + ---------- + c : array_like + 1-D array containing the Legendre series coefficients, ordered + from lowest order term to highest. + + Returns + ------- + pol : ndarray + 1-D array containing the coefficients of the equivalent polynomial + (relative to the "standard" basis) ordered from lowest order term + to highest. + + See Also + -------- + poly2leg + + Notes + ----- + The easy way to do conversions between polynomial basis sets + is to use the convert method of a class instance. + + Examples + -------- + >>> c = P.Legendre(range(4)) + >>> c + Legendre([ 0., 1., 2., 3.], [-1., 1.]) + >>> p = c.convert(kind=P.Polynomial) + >>> p + Polynomial([-1. , -3.5, 3. , 7.5], [-1., 1.]) + >>> P.leg2poly(range(4)) + array([-1. , -3.5, 3. , 7.5]) + + + """ + from .polynomial import polyadd, polysub, polymulx + + [c] = pu.as_series([c]) + n = len(c) + if n < 3: + return c + else: + c0 = c[-2] + c1 = c[-1] + # i is the current degree of c1 + for i in range(n - 1, 1, -1): + tmp = c0 + c0 = polysub(c[i - 2], (c1*(i - 1))/i) + c1 = polyadd(tmp, (polymulx(c1)*(2*i - 1))/i) + return polyadd(c0, polymulx(c1)) + +# +# These are constant arrays are of integer type so as to be compatible +# with the widest range of other types, such as Decimal. +# + +# Legendre +legdomain = np.array([-1, 1]) + +# Legendre coefficients representing zero. +legzero = np.array([0]) + +# Legendre coefficients representing one. +legone = np.array([1]) + +# Legendre coefficients representing the identity x. +legx = np.array([0, 1]) + + +def legline(off, scl): + """ + Legendre series whose graph is a straight line. + + + + Parameters + ---------- + off, scl : scalars + The specified line is given by ``off + scl*x``. + + Returns + ------- + y : ndarray + This module's representation of the Legendre series for + ``off + scl*x``. + + See Also + -------- + polyline, chebline + + Examples + -------- + >>> import numpy.polynomial.legendre as L + >>> L.legline(3,2) + array([3, 2]) + >>> L.legval(-3, L.legline(3,2)) # should be -3 + -3.0 + + """ + if scl != 0: + return np.array([off, scl]) + else: + return np.array([off]) + + +def legfromroots(roots): + """ + Generate a Legendre series with given roots. + + The function returns the coefficients of the polynomial + + .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n), + + in Legendre form, where the `r_n` are the roots specified in `roots`. + If a zero has multiplicity n, then it must appear in `roots` n times. + For instance, if 2 is a root of multiplicity three and 3 is a root of + multiplicity 2, then `roots` looks something like [2, 2, 2, 3, 3]. The + roots can appear in any order. + + If the returned coefficients are `c`, then + + .. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x) + + The coefficient of the last term is not generally 1 for monic + polynomials in Legendre form. + + Parameters + ---------- + roots : array_like + Sequence containing the roots. + + Returns + ------- + out : ndarray + 1-D array of coefficients. If all roots are real then `out` is a + real array, if some of the roots are complex, then `out` is complex + even if all the coefficients in the result are real (see Examples + below). + + See Also + -------- + polyfromroots, chebfromroots, lagfromroots, hermfromroots, + hermefromroots. + + Examples + -------- + >>> import numpy.polynomial.legendre as L + >>> L.legfromroots((-1,0,1)) # x^3 - x relative to the standard basis + array([ 0. , -0.4, 0. , 0.4]) + >>> j = complex(0,1) + >>> L.legfromroots((-j,j)) # x^2 + 1 relative to the standard basis + array([ 1.33333333+0.j, 0.00000000+0.j, 0.66666667+0.j]) + + """ + if len(roots) == 0: + return np.ones(1) + else: + [roots] = pu.as_series([roots], trim=False) + roots.sort() + p = [legline(-r, 1) for r in roots] + n = len(p) + while n > 1: + m, r = divmod(n, 2) + tmp = [legmul(p[i], p[i+m]) for i in range(m)] + if r: + tmp[0] = legmul(tmp[0], p[-1]) + p = tmp + n = m + return p[0] + + +def legadd(c1, c2): + """ + Add one Legendre series to another. + + Returns the sum of two Legendre series `c1` + `c2`. The arguments + are sequences of coefficients ordered from lowest order term to + highest, i.e., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Legendre series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the Legendre series of their sum. + + See Also + -------- + legsub, legmul, legdiv, legpow + + Notes + ----- + Unlike multiplication, division, etc., the sum of two Legendre series + is a Legendre series (without having to "reproject" the result onto + the basis set) so addition, just like that of "standard" polynomials, + is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial import legendre as L + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> L.legadd(c1,c2) + array([ 4., 4., 4.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] += c2 + ret = c1 + else: + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def legsub(c1, c2): + """ + Subtract one Legendre series from another. + + Returns the difference of two Legendre series `c1` - `c2`. The + sequences of coefficients are from lowest order term to highest, i.e., + [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Legendre series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Legendre series coefficients representing their difference. + + See Also + -------- + legadd, legmul, legdiv, legpow + + Notes + ----- + Unlike multiplication, division, etc., the difference of two Legendre + series is a Legendre series (without having to "reproject" the result + onto the basis set) so subtraction, just like that of "standard" + polynomials, is simply "component-wise." + + Examples + -------- + >>> from numpy.polynomial import legendre as L + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> L.legsub(c1,c2) + array([-2., 0., 2.]) + >>> L.legsub(c2,c1) # -C.legsub(c1,c2) + array([ 2., 0., -2.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] -= c2 + ret = c1 + else: + c2 = -c2 + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def legmulx(c): + """Multiply a Legendre series by x. + + Multiply the Legendre series `c` by x, where x is the independent + variable. + + + Parameters + ---------- + c : array_like + 1-D array of Legendre series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the result of the multiplication. + + Notes + ----- + The multiplication uses the recursion relationship for Legendre + polynomials in the form + + .. math:: + + xP_i(x) = ((i + 1)*P_{i + 1}(x) + i*P_{i - 1}(x))/(2i + 1) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + # The zero series needs special treatment + if len(c) == 1 and c[0] == 0: + return c + + prd = np.empty(len(c) + 1, dtype=c.dtype) + prd[0] = c[0]*0 + prd[1] = c[0] + for i in range(1, len(c)): + j = i + 1 + k = i - 1 + s = i + j + prd[j] = (c[i]*j)/s + prd[k] += (c[i]*i)/s + return prd + + +def legmul(c1, c2): + """ + Multiply one Legendre series by another. + + Returns the product of two Legendre series `c1` * `c2`. The arguments + are sequences of coefficients, from lowest order "term" to highest, + e.g., [1,2,3] represents the series ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Legendre series coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of Legendre series coefficients representing their product. + + See Also + -------- + legadd, legsub, legdiv, legpow + + Notes + ----- + In general, the (polynomial) product of two C-series results in terms + that are not in the Legendre polynomial basis set. Thus, to express + the product as a Legendre series, it is necessary to "reproject" the + product onto said basis set, which may produce "unintuitive" (but + correct) results; see Examples section below. + + Examples + -------- + >>> from numpy.polynomial import legendre as L + >>> c1 = (1,2,3) + >>> c2 = (3,2) + >>> P.legmul(c1,c2) # multiplication requires "reprojection" + array([ 4.33333333, 10.4 , 11.66666667, 3.6 ]) + + """ + # s1, s2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + + if len(c1) > len(c2): + c = c2 + xs = c1 + else: + c = c1 + xs = c2 + + if len(c) == 1: + c0 = c[0]*xs + c1 = 0 + elif len(c) == 2: + c0 = c[0]*xs + c1 = c[1]*xs + else: + nd = len(c) + c0 = c[-2]*xs + c1 = c[-1]*xs + for i in range(3, len(c) + 1): + tmp = c0 + nd = nd - 1 + c0 = legsub(c[-i]*xs, (c1*(nd - 1))/nd) + c1 = legadd(tmp, (legmulx(c1)*(2*nd - 1))/nd) + return legadd(c0, legmulx(c1)) + + +def legdiv(c1, c2): + """ + Divide one Legendre series by another. + + Returns the quotient-with-remainder of two Legendre series + `c1` / `c2`. The arguments are sequences of coefficients from lowest + order "term" to highest, e.g., [1,2,3] represents the series + ``P_0 + 2*P_1 + 3*P_2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of Legendre series coefficients ordered from low to + high. + + Returns + ------- + quo, rem : ndarrays + Of Legendre series coefficients representing the quotient and + remainder. + + See Also + -------- + legadd, legsub, legmul, legpow + + Notes + ----- + In general, the (polynomial) division of one Legendre series by another + results in quotient and remainder terms that are not in the Legendre + polynomial basis set. Thus, to express these results as a Legendre + series, it is necessary to "reproject" the results onto the Legendre + basis set, which may produce "unintuitive" (but correct) results; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial import legendre as L + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> L.legdiv(c1,c2) # quotient "intuitive," remainder not + (array([ 3.]), array([-8., -4.])) + >>> c2 = (0,1,2,3) + >>> L.legdiv(c2,c1) # neither "intuitive" + (array([-0.07407407, 1.66666667]), array([-1.03703704, -2.51851852])) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if c2[-1] == 0: + raise ZeroDivisionError() + + lc1 = len(c1) + lc2 = len(c2) + if lc1 < lc2: + return c1[:1]*0, c1 + elif lc2 == 1: + return c1/c2[-1], c1[:1]*0 + else: + quo = np.empty(lc1 - lc2 + 1, dtype=c1.dtype) + rem = c1 + for i in range(lc1 - lc2, - 1, -1): + p = legmul([0]*i + [1], c2) + q = rem[-1]/p[-1] + rem = rem[:-1] - q*p[:-1] + quo[i] = q + return quo, pu.trimseq(rem) + + +def legpow(c, pow, maxpower=16): + """Raise a Legendre series to a power. + + Returns the Legendre series `c` raised to the power `pow`. The + argument `c` is a sequence of coefficients ordered from low to high. + i.e., [1,2,3] is the series ``P_0 + 2*P_1 + 3*P_2.`` + + Parameters + ---------- + c : array_like + 1-D array of Legendre series coefficients ordered from low to + high. + pow : integer + Power to which the series will be raised + maxpower : integer, optional + Maximum power allowed. This is mainly to limit growth of the series + to unmanageable size. Default is 16 + + Returns + ------- + coef : ndarray + Legendre series of power. + + See Also + -------- + legadd, legsub, legmul, legdiv + + Examples + -------- + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + power = int(pow) + if power != pow or power < 0: + raise ValueError("Power must be a non-negative integer.") + elif maxpower is not None and power > maxpower: + raise ValueError("Power is too large") + elif power == 0: + return np.array([1], dtype=c.dtype) + elif power == 1: + return c + else: + # This can be made more efficient by using powers of two + # in the usual way. + prd = c + for i in range(2, power + 1): + prd = legmul(prd, c) + return prd + + +def legder(c, m=1, scl=1, axis=0): + """ + Differentiate a Legendre series. + + Returns the Legendre series coefficients `c` differentiated `m` times + along `axis`. At each iteration the result is multiplied by `scl` (the + scaling factor is for use in a linear change of variable). The argument + `c` is an array of coefficients from low to high degree along each + axis, e.g., [1,2,3] represents the series ``1*L_0 + 2*L_1 + 3*L_2`` + while [[1,2],[1,2]] represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + + 2*L_0(x)*L_1(y) + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is + ``y``. + + Parameters + ---------- + c : array_like + Array of Legendre series coefficients. If c is multidimensional the + different axis correspond to different variables with the degree in + each axis given by the corresponding index. + m : int, optional + Number of derivatives taken, must be non-negative. (Default: 1) + scl : scalar, optional + Each differentiation is multiplied by `scl`. The end result is + multiplication by ``scl**m``. This is for use in a linear change of + variable. (Default: 1) + axis : int, optional + Axis over which the derivative is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + der : ndarray + Legendre series of the derivative. + + See Also + -------- + legint + + Notes + ----- + In general, the result of differentiating a Legendre series does not + resemble the same operation on a power series. Thus the result of this + function may be "unintuitive," albeit correct; see Examples section + below. + + Examples + -------- + >>> from numpy.polynomial import legendre as L + >>> c = (1,2,3,4) + >>> L.legder(c) + array([ 6., 9., 20.]) + >>> L.legder(c, 3) + array([ 60.]) + >>> L.legder(c, scl=-1) + array([ -6., -9., -20.]) + >>> L.legder(c, 2,-1) + array([ 9., 60.]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of derivation must be integer") + if cnt < 0: + raise ValueError("The order of derivation must be non-negative") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + n = len(c) + if cnt >= n: + c = c[:1]*0 + else: + for i in range(cnt): + n = n - 1 + c *= scl + der = np.empty((n,) + c.shape[1:], dtype=c.dtype) + for j in range(n, 2, -1): + der[j - 1] = (2*j - 1)*c[j] + c[j - 2] += c[j] + if n > 1: + der[1] = 3*c[2] + der[0] = c[1] + c = der + c = np.moveaxis(c, 0, iaxis) + return c + + +def legint(c, m=1, k=[], lbnd=0, scl=1, axis=0): + """ + Integrate a Legendre series. + + Returns the Legendre series coefficients `c` integrated `m` times from + `lbnd` along `axis`. At each iteration the resulting series is + **multiplied** by `scl` and an integration constant, `k`, is added. + The scaling factor is for use in a linear change of variable. ("Buyer + beware": note that, depending on what one is doing, one may want `scl` + to be the reciprocal of what one might expect; for more information, + see the Notes section below.) The argument `c` is an array of + coefficients from low to high degree along each axis, e.g., [1,2,3] + represents the series ``L_0 + 2*L_1 + 3*L_2`` while [[1,2],[1,2]] + represents ``1*L_0(x)*L_0(y) + 1*L_1(x)*L_0(y) + 2*L_0(x)*L_1(y) + + 2*L_1(x)*L_1(y)`` if axis=0 is ``x`` and axis=1 is ``y``. + + Parameters + ---------- + c : array_like + Array of Legendre series coefficients. If c is multidimensional the + different axis correspond to different variables with the degree in + each axis given by the corresponding index. + m : int, optional + Order of integration, must be positive. (Default: 1) + k : {[], list, scalar}, optional + Integration constant(s). The value of the first integral at + ``lbnd`` is the first value in the list, the value of the second + integral at ``lbnd`` is the second value, etc. If ``k == []`` (the + default), all constants are set to zero. If ``m == 1``, a single + scalar can be given instead of a list. + lbnd : scalar, optional + The lower bound of the integral. (Default: 0) + scl : scalar, optional + Following each integration the result is *multiplied* by `scl` + before the integration constant is added. (Default: 1) + axis : int, optional + Axis over which the integral is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + S : ndarray + Legendre series coefficient array of the integral. + + Raises + ------ + ValueError + If ``m < 0``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or + ``np.ndim(scl) != 0``. + + See Also + -------- + legder + + Notes + ----- + Note that the result of each integration is *multiplied* by `scl`. + Why is this important to note? Say one is making a linear change of + variable :math:`u = ax + b` in an integral relative to `x`. Then + :math:`dx = du/a`, so one will need to set `scl` equal to + :math:`1/a` - perhaps not what one would have first thought. + + Also note that, in general, the result of integrating a C-series needs + to be "reprojected" onto the C-series basis set. Thus, typically, + the result of this function is "unintuitive," albeit correct; see + Examples section below. + + Examples + -------- + >>> from numpy.polynomial import legendre as L + >>> c = (1,2,3) + >>> L.legint(c) + array([ 0.33333333, 0.4 , 0.66666667, 0.6 ]) + >>> L.legint(c, 3) + array([ 1.66666667e-02, -1.78571429e-02, 4.76190476e-02, + -1.73472348e-18, 1.90476190e-02, 9.52380952e-03]) + >>> L.legint(c, k=3) + array([ 3.33333333, 0.4 , 0.66666667, 0.6 ]) + >>> L.legint(c, lbnd=-2) + array([ 7.33333333, 0.4 , 0.66666667, 0.6 ]) + >>> L.legint(c, scl=2) + array([ 0.66666667, 0.8 , 1.33333333, 1.2 ]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if not np.iterable(k): + k = [k] + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of integration must be integer") + if cnt < 0: + raise ValueError("The order of integration must be non-negative") + if len(k) > cnt: + raise ValueError("Too many integration constants") + if np.ndim(lbnd) != 0: + raise ValueError("lbnd must be a scalar.") + if np.ndim(scl) != 0: + raise ValueError("scl must be a scalar.") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + k = list(k) + [0]*(cnt - len(k)) + for i in range(cnt): + n = len(c) + c *= scl + if n == 1 and np.all(c[0] == 0): + c[0] += k[i] + else: + tmp = np.empty((n + 1,) + c.shape[1:], dtype=c.dtype) + tmp[0] = c[0]*0 + tmp[1] = c[0] + if n > 1: + tmp[2] = c[1]/3 + for j in range(2, n): + t = c[j]/(2*j + 1) + tmp[j + 1] = t + tmp[j - 1] -= t + tmp[0] += k[i] - legval(lbnd, tmp) + c = tmp + c = np.moveaxis(c, 0, iaxis) + return c + + +def legval(x, c, tensor=True): + """ + Evaluate a Legendre series at points x. + + If `c` is of length `n + 1`, this function returns the value: + + .. math:: p(x) = c_0 * L_0(x) + c_1 * L_1(x) + ... + c_n * L_n(x) + + The parameter `x` is converted to an array only if it is a tuple or a + list, otherwise it is treated as a scalar. In either case, either `x` + or its elements must support multiplication and addition both with + themselves and with the elements of `c`. + + If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If + `c` is multidimensional, then the shape of the result depends on the + value of `tensor`. If `tensor` is true the shape will be c.shape[1:] + + x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that + scalars have shape (,). + + Trailing zeros in the coefficients will be used in the evaluation, so + they should be avoided if efficiency is a concern. + + Parameters + ---------- + x : array_like, compatible object + If `x` is a list or tuple, it is converted to an ndarray, otherwise + it is left unchanged and treated as a scalar. In either case, `x` + or its elements must support addition and multiplication with + with themselves and with the elements of `c`. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree n are contained in c[n]. If `c` is multidimensional the + remaining indices enumerate multiple polynomials. In the two + dimensional case the coefficients may be thought of as stored in + the columns of `c`. + tensor : boolean, optional + If True, the shape of the coefficient array is extended with ones + on the right, one for each dimension of `x`. Scalars have dimension 0 + for this action. The result is that every column of coefficients in + `c` is evaluated for every element of `x`. If False, `x` is broadcast + over the columns of `c` for the evaluation. This keyword is useful + when `c` is multidimensional. The default value is True. + + .. versionadded:: 1.7.0 + + Returns + ------- + values : ndarray, algebra_like + The shape of the return value is described above. + + See Also + -------- + legval2d, leggrid2d, legval3d, leggrid3d + + Notes + ----- + The evaluation uses Clenshaw recursion, aka synthetic division. + + Examples + -------- + + """ + c = np.array(c, ndmin=1, copy=0) + if c.dtype.char in '?bBhHiIlLqQpP': + c = c.astype(np.double) + if isinstance(x, (tuple, list)): + x = np.asarray(x) + if isinstance(x, np.ndarray) and tensor: + c = c.reshape(c.shape + (1,)*x.ndim) + + if len(c) == 1: + c0 = c[0] + c1 = 0 + elif len(c) == 2: + c0 = c[0] + c1 = c[1] + else: + nd = len(c) + c0 = c[-2] + c1 = c[-1] + for i in range(3, len(c) + 1): + tmp = c0 + nd = nd - 1 + c0 = c[-i] - (c1*(nd - 1))/nd + c1 = tmp + (c1*x*(2*nd - 1))/nd + return c0 + c1*x + + +def legval2d(x, y, c): + """ + Evaluate a 2-D Legendre series at points (x, y). + + This function returns the values: + + .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * L_i(x) * L_j(y) + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars and they + must have the same shape after conversion. In either case, either `x` + and `y` or their elements must support multiplication and addition both + with themselves and with the elements of `c`. + + If `c` is a 1-D array a one is implicitly appended to its shape to make + it 2-D. The shape of the result will be c.shape[2:] + x.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points `(x, y)`, + where `x` and `y` must have the same shape. If `x` or `y` is a list + or tuple, it is first converted to an ndarray, otherwise it is left + unchanged and if it isn't an ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term + of multi-degree i,j is contained in ``c[i,j]``. If `c` has + dimension greater than two the remaining indices enumerate multiple + sets of coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional Legendre series at points formed + from pairs of corresponding values from `x` and `y`. + + See Also + -------- + legval, leggrid2d, legval3d, leggrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y = np.array((x, y), copy=0) + except Exception: + raise ValueError('x, y are incompatible') + + c = legval(x, c) + c = legval(y, c, tensor=False) + return c + + +def leggrid2d(x, y, c): + """ + Evaluate a 2-D Legendre series on the Cartesian product of x and y. + + This function returns the values: + + .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * L_i(a) * L_j(b) + + where the points `(a, b)` consist of all pairs formed by taking + `a` from `x` and `b` from `y`. The resulting points form a grid with + `x` in the first dimension and `y` in the second. + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars. In either + case, either `x` and `y` or their elements must support multiplication + and addition both with themselves and with the elements of `c`. + + If `c` has fewer than two dimensions, ones are implicitly appended to + its shape to make it 2-D. The shape of the result will be c.shape[2:] + + x.shape + y.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points in the + Cartesian product of `x` and `y`. If `x` or `y` is a list or + tuple, it is first converted to an ndarray, otherwise it is left + unchanged and, if it isn't an ndarray, it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j is contained in `c[i,j]`. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional Chebyshev series at points in the + Cartesian product of `x` and `y`. + + See Also + -------- + legval, legval2d, legval3d, leggrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = legval(x, c) + c = legval(y, c) + return c + + +def legval3d(x, y, z, c): + """ + Evaluate a 3-D Legendre series at points (x, y, z). + + This function returns the values: + + .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * L_i(x) * L_j(y) * L_k(z) + + The parameters `x`, `y`, and `z` are converted to arrays only if + they are tuples or a lists, otherwise they are treated as a scalars and + they must have the same shape after conversion. In either case, either + `x`, `y`, and `z` or their elements must support multiplication and + addition both with themselves and with the elements of `c`. + + If `c` has fewer than 3 dimensions, ones are implicitly appended to its + shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape. + + Parameters + ---------- + x, y, z : array_like, compatible object + The three dimensional series is evaluated at the points + `(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If + any of `x`, `y`, or `z` is a list or tuple, it is first converted + to an ndarray, otherwise it is left unchanged and if it isn't an + ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension + greater than 3 the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the multidimensional polynomial on points formed with + triples of corresponding values from `x`, `y`, and `z`. + + See Also + -------- + legval, legval2d, leggrid2d, leggrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y, z = np.array((x, y, z), copy=0) + except Exception: + raise ValueError('x, y, z are incompatible') + + c = legval(x, c) + c = legval(y, c, tensor=False) + c = legval(z, c, tensor=False) + return c + + +def leggrid3d(x, y, z, c): + """ + Evaluate a 3-D Legendre series on the Cartesian product of x, y, and z. + + This function returns the values: + + .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * L_i(a) * L_j(b) * L_k(c) + + where the points `(a, b, c)` consist of all triples formed by taking + `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form + a grid with `x` in the first dimension, `y` in the second, and `z` in + the third. + + The parameters `x`, `y`, and `z` are converted to arrays only if they + are tuples or a lists, otherwise they are treated as a scalars. In + either case, either `x`, `y`, and `z` or their elements must support + multiplication and addition both with themselves and with the elements + of `c`. + + If `c` has fewer than three dimensions, ones are implicitly appended to + its shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape + y.shape + z.shape. + + Parameters + ---------- + x, y, z : array_like, compatible objects + The three dimensional series is evaluated at the points in the + Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a + list or tuple, it is first converted to an ndarray, otherwise it is + left unchanged and, if it isn't an ndarray, it is treated as a + scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + legval, legval2d, leggrid2d, legval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = legval(x, c) + c = legval(y, c) + c = legval(z, c) + return c + + +def legvander(x, deg): + """Pseudo-Vandermonde matrix of given degree. + + Returns the pseudo-Vandermonde matrix of degree `deg` and sample points + `x`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., i] = L_i(x) + + where `0 <= i <= deg`. The leading indices of `V` index the elements of + `x` and the last index is the degree of the Legendre polynomial. + + If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the + array ``V = legvander(x, n)``, then ``np.dot(V, c)`` and + ``legval(x, c)`` are the same up to roundoff. This equivalence is + useful both for least squares fitting and for the evaluation of a large + number of Legendre series of the same degree and sample points. + + Parameters + ---------- + x : array_like + Array of points. The dtype is converted to float64 or complex128 + depending on whether any of the elements are complex. If `x` is + scalar it is converted to a 1-D array. + deg : int + Degree of the resulting matrix. + + Returns + ------- + vander : ndarray + The pseudo-Vandermonde matrix. The shape of the returned matrix is + ``x.shape + (deg + 1,)``, where The last index is the degree of the + corresponding Legendre polynomial. The dtype will be the same as + the converted `x`. + + """ + ideg = int(deg) + if ideg != deg: + raise ValueError("deg must be integer") + if ideg < 0: + raise ValueError("deg must be non-negative") + + x = np.array(x, copy=0, ndmin=1) + 0.0 + dims = (ideg + 1,) + x.shape + dtyp = x.dtype + v = np.empty(dims, dtype=dtyp) + # Use forward recursion to generate the entries. This is not as accurate + # as reverse recursion in this application but it is more efficient. + v[0] = x*0 + 1 + if ideg > 0: + v[1] = x + for i in range(2, ideg + 1): + v[i] = (v[i-1]*x*(2*i - 1) - v[i-2]*(i - 1))/i + return np.moveaxis(v, 0, -1) + + +def legvander2d(x, y, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y)`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (deg[1] + 1)*i + j] = L_i(x) * L_j(y), + + where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of + `V` index the points `(x, y)` and the last index encodes the degrees of + the Legendre polynomials. + + If ``V = legvander2d(x, y, [xdeg, ydeg])``, then the columns of `V` + correspond to the elements of a 2-D coefficient array `c` of shape + (xdeg + 1, ydeg + 1) in the order + + .. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ... + + and ``np.dot(V, c.flat)`` and ``legval2d(x, y, c)`` will be the same + up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 2-D Legendre + series of the same degrees and sample points. + + Parameters + ---------- + x, y : array_like + Arrays of point coordinates, all of the same shape. The dtypes + will be converted to either float64 or complex128 depending on + whether any of the elements are complex. Scalars are converted to + 1-D arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg]. + + Returns + ------- + vander2d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)`. The dtype will be the same + as the converted `x` and `y`. + + See Also + -------- + legvander, legvander3d. legval2d, legval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy = ideg + x, y = np.array((x, y), copy=0) + 0.0 + + vx = legvander(x, degx) + vy = legvander(y, degy) + v = vx[..., None]*vy[..., None,:] + return v.reshape(v.shape[:-2] + (-1,)) + + +def legvander3d(x, y, z, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`, + then The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = L_i(x)*L_j(y)*L_k(z), + + where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading + indices of `V` index the points `(x, y, z)` and the last index encodes + the degrees of the Legendre polynomials. + + If ``V = legvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns + of `V` correspond to the elements of a 3-D coefficient array `c` of + shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order + + .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},... + + and ``np.dot(V, c.flat)`` and ``legval3d(x, y, z, c)`` will be the + same up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 3-D Legendre + series of the same degrees and sample points. + + Parameters + ---------- + x, y, z : array_like + Arrays of point coordinates, all of the same shape. The dtypes will + be converted to either float64 or complex128 depending on whether + any of the elements are complex. Scalars are converted to 1-D + arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg, z_deg]. + + Returns + ------- + vander3d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)*(deg[2]+1)`. The dtype will + be the same as the converted `x`, `y`, and `z`. + + See Also + -------- + legvander, legvander3d. legval2d, legval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy, degz = ideg + x, y, z = np.array((x, y, z), copy=0) + 0.0 + + vx = legvander(x, degx) + vy = legvander(y, degy) + vz = legvander(z, degz) + v = vx[..., None, None]*vy[..., None,:, None]*vz[..., None, None,:] + return v.reshape(v.shape[:-3] + (-1,)) + + +def legfit(x, y, deg, rcond=None, full=False, w=None): + """ + Least squares fit of Legendre series to data. + + Return the coefficients of a Legendre series of degree `deg` that is the + least squares fit to the data values `y` given at points `x`. If `y` is + 1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple + fits are done, one for each column of `y`, and the resulting + coefficients are stored in the corresponding columns of a 2-D return. + The fitted polynomial(s) are in the form + + .. math:: p(x) = c_0 + c_1 * L_1(x) + ... + c_n * L_n(x), + + where `n` is `deg`. + + Parameters + ---------- + x : array_like, shape (M,) + x-coordinates of the M sample points ``(x[i], y[i])``. + y : array_like, shape (M,) or (M, K) + y-coordinates of the sample points. Several data sets of sample + points sharing the same x-coordinates can be fitted at once by + passing in a 2D-array that contains one dataset per column. + deg : int or 1-D array_like + Degree(s) of the fitting polynomials. If `deg` is a single integer + all terms up to and including the `deg`'th term are included in the + fit. For NumPy versions >= 1.11.0 a list of integers specifying the + degrees of the terms to include may be used instead. + rcond : float, optional + Relative condition number of the fit. Singular values smaller than + this relative to the largest singular value will be ignored. The + default value is len(x)*eps, where eps is the relative precision of + the float type, about 2e-16 in most cases. + full : bool, optional + Switch determining nature of return value. When it is False (the + default) just the coefficients are returned, when True diagnostic + information from the singular value decomposition is also returned. + w : array_like, shape (`M`,), optional + Weights. If not None, the contribution of each point + ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the + weights are chosen so that the errors of the products ``w[i]*y[i]`` + all have the same variance. The default value is None. + + .. versionadded:: 1.5.0 + + Returns + ------- + coef : ndarray, shape (M,) or (M, K) + Legendre coefficients ordered from low to high. If `y` was + 2-D, the coefficients for the data in column k of `y` are in + column `k`. If `deg` is specified as a list, coefficients for + terms not included in the fit are set equal to zero in the + returned `coef`. + + [residuals, rank, singular_values, rcond] : list + These values are only returned if `full` = True + + resid -- sum of squared residuals of the least squares fit + rank -- the numerical rank of the scaled Vandermonde matrix + sv -- singular values of the scaled Vandermonde matrix + rcond -- value of `rcond`. + + For more details, see `linalg.lstsq`. + + Warns + ----- + RankWarning + The rank of the coefficient matrix in the least-squares fit is + deficient. The warning is only raised if `full` = False. The + warnings can be turned off by + + >>> import warnings + >>> warnings.simplefilter('ignore', RankWarning) + + See Also + -------- + chebfit, polyfit, lagfit, hermfit, hermefit + legval : Evaluates a Legendre series. + legvander : Vandermonde matrix of Legendre series. + legweight : Legendre weight function (= 1). + linalg.lstsq : Computes a least-squares fit from the matrix. + scipy.interpolate.UnivariateSpline : Computes spline fits. + + Notes + ----- + The solution is the coefficients of the Legendre series `p` that + minimizes the sum of the weighted squared errors + + .. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2, + + where :math:`w_j` are the weights. This problem is solved by setting up + as the (typically) overdetermined matrix equation + + .. math:: V(x) * c = w * y, + + where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the + coefficients to be solved for, `w` are the weights, and `y` are the + observed values. This equation is then solved using the singular value + decomposition of `V`. + + If some of the singular values of `V` are so small that they are + neglected, then a `RankWarning` will be issued. This means that the + coefficient values may be poorly determined. Using a lower order fit + will usually get rid of the warning. The `rcond` parameter can also be + set to a value smaller than its default, but the resulting fit may be + spurious and have large contributions from roundoff error. + + Fits using Legendre series are usually better conditioned than fits + using power series, but much can depend on the distribution of the + sample points and the smoothness of the data. If the quality of the fit + is inadequate splines may be a good alternative. + + References + ---------- + .. [1] Wikipedia, "Curve fitting", + http://en.wikipedia.org/wiki/Curve_fitting + + Examples + -------- + + """ + x = np.asarray(x) + 0.0 + y = np.asarray(y) + 0.0 + deg = np.asarray(deg) + + # check arguments. + if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0: + raise TypeError("deg must be an int or non-empty 1-D array of int") + if deg.min() < 0: + raise ValueError("expected deg >= 0") + if x.ndim != 1: + raise TypeError("expected 1D vector for x") + if x.size == 0: + raise TypeError("expected non-empty vector for x") + if y.ndim < 1 or y.ndim > 2: + raise TypeError("expected 1D or 2D array for y") + if len(x) != len(y): + raise TypeError("expected x and y to have same length") + + if deg.ndim == 0: + lmax = deg + order = lmax + 1 + van = legvander(x, lmax) + else: + deg = np.sort(deg) + lmax = deg[-1] + order = len(deg) + van = legvander(x, lmax)[:, deg] + + # set up the least squares matrices in transposed form + lhs = van.T + rhs = y.T + if w is not None: + w = np.asarray(w) + 0.0 + if w.ndim != 1: + raise TypeError("expected 1D vector for w") + if len(x) != len(w): + raise TypeError("expected x and w to have same length") + # apply weights. Don't use inplace operations as they + # can cause problems with NA. + lhs = lhs * w + rhs = rhs * w + + # set rcond + if rcond is None: + rcond = len(x)*np.finfo(x.dtype).eps + + # Determine the norms of the design matrix columns. + if issubclass(lhs.dtype.type, np.complexfloating): + scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1)) + else: + scl = np.sqrt(np.square(lhs).sum(1)) + scl[scl == 0] = 1 + + # Solve the least squares problem. + c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond) + c = (c.T/scl).T + + # Expand c to include non-fitted coefficients which are set to zero + if deg.ndim > 0: + if c.ndim == 2: + cc = np.zeros((lmax+1, c.shape[1]), dtype=c.dtype) + else: + cc = np.zeros(lmax+1, dtype=c.dtype) + cc[deg] = c + c = cc + + # warn on rank reduction + if rank != order and not full: + msg = "The fit may be poorly conditioned" + warnings.warn(msg, pu.RankWarning, stacklevel=2) + + if full: + return c, [resids, rank, s, rcond] + else: + return c + + +def legcompanion(c): + """Return the scaled companion matrix of c. + + The basis polynomials are scaled so that the companion matrix is + symmetric when `c` is an Legendre basis polynomial. This provides + better eigenvalue estimates than the unscaled case and for basis + polynomials the eigenvalues are guaranteed to be real if + `numpy.linalg.eigvalsh` is used to obtain them. + + Parameters + ---------- + c : array_like + 1-D array of Legendre series coefficients ordered from low to high + degree. + + Returns + ------- + mat : ndarray + Scaled companion matrix of dimensions (deg, deg). + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + raise ValueError('Series must have maximum degree of at least 1.') + if len(c) == 2: + return np.array([[-c[0]/c[1]]]) + + n = len(c) - 1 + mat = np.zeros((n, n), dtype=c.dtype) + scl = 1./np.sqrt(2*np.arange(n) + 1) + top = mat.reshape(-1)[1::n+1] + bot = mat.reshape(-1)[n::n+1] + top[...] = np.arange(1, n)*scl[:n-1]*scl[1:n] + bot[...] = top + mat[:, -1] -= (c[:-1]/c[-1])*(scl/scl[-1])*(n/(2*n - 1)) + return mat + + +def legroots(c): + """ + Compute the roots of a Legendre series. + + Return the roots (a.k.a. "zeros") of the polynomial + + .. math:: p(x) = \\sum_i c[i] * L_i(x). + + Parameters + ---------- + c : 1-D array_like + 1-D array of coefficients. + + Returns + ------- + out : ndarray + Array of the roots of the series. If all the roots are real, + then `out` is also real, otherwise it is complex. + + See Also + -------- + polyroots, chebroots, lagroots, hermroots, hermeroots + + Notes + ----- + The root estimates are obtained as the eigenvalues of the companion + matrix, Roots far from the origin of the complex plane may have large + errors due to the numerical instability of the series for such values. + Roots with multiplicity greater than 1 will also show larger errors as + the value of the series near such points is relatively insensitive to + errors in the roots. Isolated roots near the origin can be improved by + a few iterations of Newton's method. + + The Legendre series basis polynomials aren't powers of ``x`` so the + results of this function may seem unintuitive. + + Examples + -------- + >>> import numpy.polynomial.legendre as leg + >>> leg.legroots((1, 2, 3, 4)) # 4L_3 + 3L_2 + 2L_1 + 1L_0, all real roots + array([-0.85099543, -0.11407192, 0.51506735]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + return np.array([], dtype=c.dtype) + if len(c) == 2: + return np.array([-c[0]/c[1]]) + + m = legcompanion(c) + r = la.eigvals(m) + r.sort() + return r + + +def leggauss(deg): + """ + Gauss-Legendre quadrature. + + Computes the sample points and weights for Gauss-Legendre quadrature. + These sample points and weights will correctly integrate polynomials of + degree :math:`2*deg - 1` or less over the interval :math:`[-1, 1]` with + the weight function :math:`f(x) = 1`. + + Parameters + ---------- + deg : int + Number of sample points and weights. It must be >= 1. + + Returns + ------- + x : ndarray + 1-D ndarray containing the sample points. + y : ndarray + 1-D ndarray containing the weights. + + Notes + ----- + + .. versionadded:: 1.7.0 + + The results have only been tested up to degree 100, higher degrees may + be problematic. The weights are determined by using the fact that + + .. math:: w_k = c / (L'_n(x_k) * L_{n-1}(x_k)) + + where :math:`c` is a constant independent of :math:`k` and :math:`x_k` + is the k'th root of :math:`L_n`, and then scaling the results to get + the right value when integrating 1. + + """ + ideg = int(deg) + if ideg != deg or ideg < 1: + raise ValueError("deg must be a non-negative integer") + + # first approximation of roots. We use the fact that the companion + # matrix is symmetric in this case in order to obtain better zeros. + c = np.array([0]*deg + [1]) + m = legcompanion(c) + x = la.eigvalsh(m) + + # improve roots by one application of Newton + dy = legval(x, c) + df = legval(x, legder(c)) + x -= dy/df + + # compute the weights. We scale the factor to avoid possible numerical + # overflow. + fm = legval(x, c[1:]) + fm /= np.abs(fm).max() + df /= np.abs(df).max() + w = 1/(fm * df) + + # for Legendre we can also symmetrize + w = (w + w[::-1])/2 + x = (x - x[::-1])/2 + + # scale w to get the right value + w *= 2. / w.sum() + + return x, w + + +def legweight(x): + """ + Weight function of the Legendre polynomials. + + The weight function is :math:`1` and the interval of integration is + :math:`[-1, 1]`. The Legendre polynomials are orthogonal, but not + normalized, with respect to this weight function. + + Parameters + ---------- + x : array_like + Values at which the weight function will be computed. + + Returns + ------- + w : ndarray + The weight function at `x`. + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + w = x*0.0 + 1.0 + return w + +# +# Legendre series class +# + +class Legendre(ABCPolyBase): + """A Legendre series class. + + The Legendre class provides the standard Python numerical methods + '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the + attributes and methods listed in the `ABCPolyBase` documentation. + + Parameters + ---------- + coef : array_like + Legendre coefficients in order of increasing degree, i.e., + ``(1, 2, 3)`` gives ``1*P_0(x) + 2*P_1(x) + 3*P_2(x)``. + domain : (2,) array_like, optional + Domain to use. The interval ``[domain[0], domain[1]]`` is mapped + to the interval ``[window[0], window[1]]`` by shifting and scaling. + The default value is [-1, 1]. + window : (2,) array_like, optional + Window, see `domain` for its use. The default value is [-1, 1]. + + .. versionadded:: 1.6.0 + + """ + # Virtual Functions + _add = staticmethod(legadd) + _sub = staticmethod(legsub) + _mul = staticmethod(legmul) + _div = staticmethod(legdiv) + _pow = staticmethod(legpow) + _val = staticmethod(legval) + _int = staticmethod(legint) + _der = staticmethod(legder) + _fit = staticmethod(legfit) + _line = staticmethod(legline) + _roots = staticmethod(legroots) + _fromroots = staticmethod(legfromroots) + + # Virtual properties + nickname = 'leg' + domain = np.array(legdomain) + window = np.array(legdomain) diff --git a/numpy/polynomial/polynomial.py b/numpy/polynomial/polynomial.py new file mode 100644 index 0000000..a71e5b5 --- /dev/null +++ b/numpy/polynomial/polynomial.py @@ -0,0 +1,1645 @@ +""" +Objects for dealing with polynomials. + +This module provides a number of objects (mostly functions) useful for +dealing with polynomials, including a `Polynomial` class that +encapsulates the usual arithmetic operations. (General information +on how this module represents and works with polynomial objects is in +the docstring for its "parent" sub-package, `numpy.polynomial`). + +Constants +--------- +- `polydomain` -- Polynomial default domain, [-1,1]. +- `polyzero` -- (Coefficients of the) "zero polynomial." +- `polyone` -- (Coefficients of the) constant polynomial 1. +- `polyx` -- (Coefficients of the) identity map polynomial, ``f(x) = x``. + +Arithmetic +---------- +- `polyadd` -- add two polynomials. +- `polysub` -- subtract one polynomial from another. +- `polymul` -- multiply two polynomials. +- `polydiv` -- divide one polynomial by another. +- `polypow` -- raise a polynomial to an positive integer power +- `polyval` -- evaluate a polynomial at given points. +- `polyval2d` -- evaluate a 2D polynomial at given points. +- `polyval3d` -- evaluate a 3D polynomial at given points. +- `polygrid2d` -- evaluate a 2D polynomial on a Cartesian product. +- `polygrid3d` -- evaluate a 3D polynomial on a Cartesian product. + +Calculus +-------- +- `polyder` -- differentiate a polynomial. +- `polyint` -- integrate a polynomial. + +Misc Functions +-------------- +- `polyfromroots` -- create a polynomial with specified roots. +- `polyroots` -- find the roots of a polynomial. +- `polyvalfromroots` -- evalute a polynomial at given points from roots. +- `polyvander` -- Vandermonde-like matrix for powers. +- `polyvander2d` -- Vandermonde-like matrix for 2D power series. +- `polyvander3d` -- Vandermonde-like matrix for 3D power series. +- `polycompanion` -- companion matrix in power series form. +- `polyfit` -- least-squares fit returning a polynomial. +- `polytrim` -- trim leading coefficients from a polynomial. +- `polyline` -- polynomial representing given straight line. + +Classes +------- +- `Polynomial` -- polynomial class. + +See Also +-------- +`numpy.polynomial` + +""" +from __future__ import division, absolute_import, print_function + +__all__ = [ + 'polyzero', 'polyone', 'polyx', 'polydomain', 'polyline', 'polyadd', + 'polysub', 'polymulx', 'polymul', 'polydiv', 'polypow', 'polyval', + 'polyvalfromroots', 'polyder', 'polyint', 'polyfromroots', 'polyvander', + 'polyfit', 'polytrim', 'polyroots', 'Polynomial', 'polyval2d', 'polyval3d', + 'polygrid2d', 'polygrid3d', 'polyvander2d', 'polyvander3d'] + +import warnings +import numpy as np +import numpy.linalg as la +from numpy.core.multiarray import normalize_axis_index + +from . import polyutils as pu +from ._polybase import ABCPolyBase + +polytrim = pu.trimcoef + +# +# These are constant arrays are of integer type so as to be compatible +# with the widest range of other types, such as Decimal. +# + +# Polynomial default domain. +polydomain = np.array([-1, 1]) + +# Polynomial coefficients representing zero. +polyzero = np.array([0]) + +# Polynomial coefficients representing one. +polyone = np.array([1]) + +# Polynomial coefficients representing the identity x. +polyx = np.array([0, 1]) + +# +# Polynomial series functions +# + + +def polyline(off, scl): + """ + Returns an array representing a linear polynomial. + + Parameters + ---------- + off, scl : scalars + The "y-intercept" and "slope" of the line, respectively. + + Returns + ------- + y : ndarray + This module's representation of the linear polynomial ``off + + scl*x``. + + See Also + -------- + chebline + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> P.polyline(1,-1) + array([ 1, -1]) + >>> P.polyval(1, P.polyline(1,-1)) # should be 0 + 0.0 + + """ + if scl != 0: + return np.array([off, scl]) + else: + return np.array([off]) + + +def polyfromroots(roots): + """ + Generate a monic polynomial with given roots. + + Return the coefficients of the polynomial + + .. math:: p(x) = (x - r_0) * (x - r_1) * ... * (x - r_n), + + where the `r_n` are the roots specified in `roots`. If a zero has + multiplicity n, then it must appear in `roots` n times. For instance, + if 2 is a root of multiplicity three and 3 is a root of multiplicity 2, + then `roots` looks something like [2, 2, 2, 3, 3]. The roots can appear + in any order. + + If the returned coefficients are `c`, then + + .. math:: p(x) = c_0 + c_1 * x + ... + x^n + + The coefficient of the last term is 1 for monic polynomials in this + form. + + Parameters + ---------- + roots : array_like + Sequence containing the roots. + + Returns + ------- + out : ndarray + 1-D array of the polynomial's coefficients If all the roots are + real, then `out` is also real, otherwise it is complex. (see + Examples below). + + See Also + -------- + chebfromroots, legfromroots, lagfromroots, hermfromroots + hermefromroots + + Notes + ----- + The coefficients are determined by multiplying together linear factors + of the form `(x - r_i)`, i.e. + + .. math:: p(x) = (x - r_0) (x - r_1) ... (x - r_n) + + where ``n == len(roots) - 1``; note that this implies that `1` is always + returned for :math:`a_n`. + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> P.polyfromroots((-1,0,1)) # x(x - 1)(x + 1) = x^3 - x + array([ 0., -1., 0., 1.]) + >>> j = complex(0,1) + >>> P.polyfromroots((-j,j)) # complex returned, though values are real + array([ 1.+0.j, 0.+0.j, 1.+0.j]) + + """ + if len(roots) == 0: + return np.ones(1) + else: + [roots] = pu.as_series([roots], trim=False) + roots.sort() + p = [polyline(-r, 1) for r in roots] + n = len(p) + while n > 1: + m, r = divmod(n, 2) + tmp = [polymul(p[i], p[i+m]) for i in range(m)] + if r: + tmp[0] = polymul(tmp[0], p[-1]) + p = tmp + n = m + return p[0] + + +def polyadd(c1, c2): + """ + Add one polynomial to another. + + Returns the sum of two polynomials `c1` + `c2`. The arguments are + sequences of coefficients from lowest order term to highest, i.e., + [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of polynomial coefficients ordered from low to high. + + Returns + ------- + out : ndarray + The coefficient array representing their sum. + + See Also + -------- + polysub, polymul, polydiv, polypow + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> sum = P.polyadd(c1,c2); sum + array([ 4., 4., 4.]) + >>> P.polyval(2, sum) # 4 + 4(2) + 4(2**2) + 28.0 + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] += c2 + ret = c1 + else: + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def polysub(c1, c2): + """ + Subtract one polynomial from another. + + Returns the difference of two polynomials `c1` - `c2`. The arguments + are sequences of coefficients from lowest order term to highest, i.e., + [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of polynomial coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Of coefficients representing their difference. + + See Also + -------- + polyadd, polymul, polydiv, polypow + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> P.polysub(c1,c2) + array([-2., 0., 2.]) + >>> P.polysub(c2,c1) # -P.polysub(c1,c2) + array([ 2., 0., -2.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if len(c1) > len(c2): + c1[:c2.size] -= c2 + ret = c1 + else: + c2 = -c2 + c2[:c1.size] += c1 + ret = c2 + return pu.trimseq(ret) + + +def polymulx(c): + """Multiply a polynomial by x. + + Multiply the polynomial `c` by x, where x is the independent + variable. + + + Parameters + ---------- + c : array_like + 1-D array of polynomial coefficients ordered from low to + high. + + Returns + ------- + out : ndarray + Array representing the result of the multiplication. + + Notes + ----- + + .. versionadded:: 1.5.0 + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + # The zero series needs special treatment + if len(c) == 1 and c[0] == 0: + return c + + prd = np.empty(len(c) + 1, dtype=c.dtype) + prd[0] = c[0]*0 + prd[1:] = c + return prd + + +def polymul(c1, c2): + """ + Multiply one polynomial by another. + + Returns the product of two polynomials `c1` * `c2`. The arguments are + sequences of coefficients, from lowest order term to highest, e.g., + [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2.`` + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of coefficients representing a polynomial, relative to the + "standard" basis, and ordered from lowest order term to highest. + + Returns + ------- + out : ndarray + Of the coefficients of their product. + + See Also + -------- + polyadd, polysub, polydiv, polypow + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> P.polymul(c1,c2) + array([ 3., 8., 14., 8., 3.]) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + ret = np.convolve(c1, c2) + return pu.trimseq(ret) + + +def polydiv(c1, c2): + """ + Divide one polynomial by another. + + Returns the quotient-with-remainder of two polynomials `c1` / `c2`. + The arguments are sequences of coefficients, from lowest order term + to highest, e.g., [1,2,3] represents ``1 + 2*x + 3*x**2``. + + Parameters + ---------- + c1, c2 : array_like + 1-D arrays of polynomial coefficients ordered from low to high. + + Returns + ------- + [quo, rem] : ndarrays + Of coefficient series representing the quotient and remainder. + + See Also + -------- + polyadd, polysub, polymul, polypow + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> c1 = (1,2,3) + >>> c2 = (3,2,1) + >>> P.polydiv(c1,c2) + (array([ 3.]), array([-8., -4.])) + >>> P.polydiv(c2,c1) + (array([ 0.33333333]), array([ 2.66666667, 1.33333333])) + + """ + # c1, c2 are trimmed copies + [c1, c2] = pu.as_series([c1, c2]) + if c2[-1] == 0: + raise ZeroDivisionError() + + len1 = len(c1) + len2 = len(c2) + if len2 == 1: + return c1/c2[-1], c1[:1]*0 + elif len1 < len2: + return c1[:1]*0, c1 + else: + dlen = len1 - len2 + scl = c2[-1] + c2 = c2[:-1]/scl + i = dlen + j = len1 - 1 + while i >= 0: + c1[i:j] -= c2*c1[j] + i -= 1 + j -= 1 + return c1[j+1:]/scl, pu.trimseq(c1[:j+1]) + + +def polypow(c, pow, maxpower=None): + """Raise a polynomial to a power. + + Returns the polynomial `c` raised to the power `pow`. The argument + `c` is a sequence of coefficients ordered from low to high. i.e., + [1,2,3] is the series ``1 + 2*x + 3*x**2.`` + + Parameters + ---------- + c : array_like + 1-D array of array of series coefficients ordered from low to + high degree. + pow : integer + Power to which the series will be raised + maxpower : integer, optional + Maximum power allowed. This is mainly to limit growth of the series + to unmanageable size. Default is 16 + + Returns + ------- + coef : ndarray + Power series of power. + + See Also + -------- + polyadd, polysub, polymul, polydiv + + Examples + -------- + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + power = int(pow) + if power != pow or power < 0: + raise ValueError("Power must be a non-negative integer.") + elif maxpower is not None and power > maxpower: + raise ValueError("Power is too large") + elif power == 0: + return np.array([1], dtype=c.dtype) + elif power == 1: + return c + else: + # This can be made more efficient by using powers of two + # in the usual way. + prd = c + for i in range(2, power + 1): + prd = np.convolve(prd, c) + return prd + + +def polyder(c, m=1, scl=1, axis=0): + """ + Differentiate a polynomial. + + Returns the polynomial coefficients `c` differentiated `m` times along + `axis`. At each iteration the result is multiplied by `scl` (the + scaling factor is for use in a linear change of variable). The + argument `c` is an array of coefficients from low to high degree along + each axis, e.g., [1,2,3] represents the polynomial ``1 + 2*x + 3*x**2`` + while [[1,2],[1,2]] represents ``1 + 1*x + 2*y + 2*x*y`` if axis=0 is + ``x`` and axis=1 is ``y``. + + Parameters + ---------- + c : array_like + Array of polynomial coefficients. If c is multidimensional the + different axis correspond to different variables with the degree + in each axis given by the corresponding index. + m : int, optional + Number of derivatives taken, must be non-negative. (Default: 1) + scl : scalar, optional + Each differentiation is multiplied by `scl`. The end result is + multiplication by ``scl**m``. This is for use in a linear change + of variable. (Default: 1) + axis : int, optional + Axis over which the derivative is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + der : ndarray + Polynomial coefficients of the derivative. + + See Also + -------- + polyint + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> c = (1,2,3,4) # 1 + 2x + 3x**2 + 4x**3 + >>> P.polyder(c) # (d/dx)(c) = 2 + 6x + 12x**2 + array([ 2., 6., 12.]) + >>> P.polyder(c,3) # (d**3/dx**3)(c) = 24 + array([ 24.]) + >>> P.polyder(c,scl=-1) # (d/d(-x))(c) = -2 - 6x - 12x**2 + array([ -2., -6., -12.]) + >>> P.polyder(c,2,-1) # (d**2/d(-x)**2)(c) = 6 + 24x + array([ 6., 24.]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + # astype fails with NA + c = c + 0.0 + cdt = c.dtype + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of derivation must be integer") + if cnt < 0: + raise ValueError("The order of derivation must be non-negative") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + c = np.moveaxis(c, iaxis, 0) + n = len(c) + if cnt >= n: + c = c[:1]*0 + else: + for i in range(cnt): + n = n - 1 + c *= scl + der = np.empty((n,) + c.shape[1:], dtype=cdt) + for j in range(n, 0, -1): + der[j - 1] = j*c[j] + c = der + c = np.moveaxis(c, 0, iaxis) + return c + + +def polyint(c, m=1, k=[], lbnd=0, scl=1, axis=0): + """ + Integrate a polynomial. + + Returns the polynomial coefficients `c` integrated `m` times from + `lbnd` along `axis`. At each iteration the resulting series is + **multiplied** by `scl` and an integration constant, `k`, is added. + The scaling factor is for use in a linear change of variable. ("Buyer + beware": note that, depending on what one is doing, one may want `scl` + to be the reciprocal of what one might expect; for more information, + see the Notes section below.) The argument `c` is an array of + coefficients, from low to high degree along each axis, e.g., [1,2,3] + represents the polynomial ``1 + 2*x + 3*x**2`` while [[1,2],[1,2]] + represents ``1 + 1*x + 2*y + 2*x*y`` if axis=0 is ``x`` and axis=1 is + ``y``. + + Parameters + ---------- + c : array_like + 1-D array of polynomial coefficients, ordered from low to high. + m : int, optional + Order of integration, must be positive. (Default: 1) + k : {[], list, scalar}, optional + Integration constant(s). The value of the first integral at zero + is the first value in the list, the value of the second integral + at zero is the second value, etc. If ``k == []`` (the default), + all constants are set to zero. If ``m == 1``, a single scalar can + be given instead of a list. + lbnd : scalar, optional + The lower bound of the integral. (Default: 0) + scl : scalar, optional + Following each integration the result is *multiplied* by `scl` + before the integration constant is added. (Default: 1) + axis : int, optional + Axis over which the integral is taken. (Default: 0). + + .. versionadded:: 1.7.0 + + Returns + ------- + S : ndarray + Coefficient array of the integral. + + Raises + ------ + ValueError + If ``m < 1``, ``len(k) > m``, ``np.ndim(lbnd) != 0``, or + ``np.ndim(scl) != 0``. + + See Also + -------- + polyder + + Notes + ----- + Note that the result of each integration is *multiplied* by `scl`. Why + is this important to note? Say one is making a linear change of + variable :math:`u = ax + b` in an integral relative to `x`. Then + :math:`dx = du/a`, so one will need to set `scl` equal to + :math:`1/a` - perhaps not what one would have first thought. + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> c = (1,2,3) + >>> P.polyint(c) # should return array([0, 1, 1, 1]) + array([ 0., 1., 1., 1.]) + >>> P.polyint(c,3) # should return array([0, 0, 0, 1/6, 1/12, 1/20]) + array([ 0. , 0. , 0. , 0.16666667, 0.08333333, + 0.05 ]) + >>> P.polyint(c,k=3) # should return array([3, 1, 1, 1]) + array([ 3., 1., 1., 1.]) + >>> P.polyint(c,lbnd=-2) # should return array([6, 1, 1, 1]) + array([ 6., 1., 1., 1.]) + >>> P.polyint(c,scl=-2) # should return array([0, -2, -2, -2]) + array([ 0., -2., -2., -2.]) + + """ + c = np.array(c, ndmin=1, copy=1) + if c.dtype.char in '?bBhHiIlLqQpP': + # astype doesn't preserve mask attribute. + c = c + 0.0 + cdt = c.dtype + if not np.iterable(k): + k = [k] + cnt, iaxis = [int(t) for t in [m, axis]] + + if cnt != m: + raise ValueError("The order of integration must be integer") + if cnt < 0: + raise ValueError("The order of integration must be non-negative") + if len(k) > cnt: + raise ValueError("Too many integration constants") + if np.ndim(lbnd) != 0: + raise ValueError("lbnd must be a scalar.") + if np.ndim(scl) != 0: + raise ValueError("scl must be a scalar.") + if iaxis != axis: + raise ValueError("The axis must be integer") + iaxis = normalize_axis_index(iaxis, c.ndim) + + if cnt == 0: + return c + + k = list(k) + [0]*(cnt - len(k)) + c = np.moveaxis(c, iaxis, 0) + for i in range(cnt): + n = len(c) + c *= scl + if n == 1 and np.all(c[0] == 0): + c[0] += k[i] + else: + tmp = np.empty((n + 1,) + c.shape[1:], dtype=cdt) + tmp[0] = c[0]*0 + tmp[1] = c[0] + for j in range(1, n): + tmp[j + 1] = c[j]/(j + 1) + tmp[0] += k[i] - polyval(lbnd, tmp) + c = tmp + c = np.moveaxis(c, 0, iaxis) + return c + + +def polyval(x, c, tensor=True): + """ + Evaluate a polynomial at points x. + + If `c` is of length `n + 1`, this function returns the value + + .. math:: p(x) = c_0 + c_1 * x + ... + c_n * x^n + + The parameter `x` is converted to an array only if it is a tuple or a + list, otherwise it is treated as a scalar. In either case, either `x` + or its elements must support multiplication and addition both with + themselves and with the elements of `c`. + + If `c` is a 1-D array, then `p(x)` will have the same shape as `x`. If + `c` is multidimensional, then the shape of the result depends on the + value of `tensor`. If `tensor` is true the shape will be c.shape[1:] + + x.shape. If `tensor` is false the shape will be c.shape[1:]. Note that + scalars have shape (,). + + Trailing zeros in the coefficients will be used in the evaluation, so + they should be avoided if efficiency is a concern. + + Parameters + ---------- + x : array_like, compatible object + If `x` is a list or tuple, it is converted to an ndarray, otherwise + it is left unchanged and treated as a scalar. In either case, `x` + or its elements must support addition and multiplication with + with themselves and with the elements of `c`. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree n are contained in c[n]. If `c` is multidimensional the + remaining indices enumerate multiple polynomials. In the two + dimensional case the coefficients may be thought of as stored in + the columns of `c`. + tensor : boolean, optional + If True, the shape of the coefficient array is extended with ones + on the right, one for each dimension of `x`. Scalars have dimension 0 + for this action. The result is that every column of coefficients in + `c` is evaluated for every element of `x`. If False, `x` is broadcast + over the columns of `c` for the evaluation. This keyword is useful + when `c` is multidimensional. The default value is True. + + .. versionadded:: 1.7.0 + + Returns + ------- + values : ndarray, compatible object + The shape of the returned array is described above. + + See Also + -------- + polyval2d, polygrid2d, polyval3d, polygrid3d + + Notes + ----- + The evaluation uses Horner's method. + + Examples + -------- + >>> from numpy.polynomial.polynomial import polyval + >>> polyval(1, [1,2,3]) + 6.0 + >>> a = np.arange(4).reshape(2,2) + >>> a + array([[0, 1], + [2, 3]]) + >>> polyval(a, [1,2,3]) + array([[ 1., 6.], + [ 17., 34.]]) + >>> coef = np.arange(4).reshape(2,2) # multidimensional coefficients + >>> coef + array([[0, 1], + [2, 3]]) + >>> polyval([1,2], coef, tensor=True) + array([[ 2., 4.], + [ 4., 7.]]) + >>> polyval([1,2], coef, tensor=False) + array([ 2., 7.]) + + """ + c = np.array(c, ndmin=1, copy=0) + if c.dtype.char in '?bBhHiIlLqQpP': + # astype fails with NA + c = c + 0.0 + if isinstance(x, (tuple, list)): + x = np.asarray(x) + if isinstance(x, np.ndarray) and tensor: + c = c.reshape(c.shape + (1,)*x.ndim) + + c0 = c[-1] + x*0 + for i in range(2, len(c) + 1): + c0 = c[-i] + c0*x + return c0 + + +def polyvalfromroots(x, r, tensor=True): + """ + Evaluate a polynomial specified by its roots at points x. + + If `r` is of length `N`, this function returns the value + + .. math:: p(x) = \\prod_{n=1}^{N} (x - r_n) + + The parameter `x` is converted to an array only if it is a tuple or a + list, otherwise it is treated as a scalar. In either case, either `x` + or its elements must support multiplication and addition both with + themselves and with the elements of `r`. + + If `r` is a 1-D array, then `p(x)` will have the same shape as `x`. If `r` + is multidimensional, then the shape of the result depends on the value of + `tensor`. If `tensor is ``True`` the shape will be r.shape[1:] + x.shape; + that is, each polynomial is evaluated at every value of `x`. If `tensor` is + ``False``, the shape will be r.shape[1:]; that is, each polynomial is + evaluated only for the corresponding broadcast value of `x`. Note that + scalars have shape (,). + + .. versionadded:: 1.12 + + Parameters + ---------- + x : array_like, compatible object + If `x` is a list or tuple, it is converted to an ndarray, otherwise + it is left unchanged and treated as a scalar. In either case, `x` + or its elements must support addition and multiplication with + with themselves and with the elements of `r`. + r : array_like + Array of roots. If `r` is multidimensional the first index is the + root index, while the remaining indices enumerate multiple + polynomials. For instance, in the two dimensional case the roots + of each polynomial may be thought of as stored in the columns of `r`. + tensor : boolean, optional + If True, the shape of the roots array is extended with ones on the + right, one for each dimension of `x`. Scalars have dimension 0 for this + action. The result is that every column of coefficients in `r` is + evaluated for every element of `x`. If False, `x` is broadcast over the + columns of `r` for the evaluation. This keyword is useful when `r` is + multidimensional. The default value is True. + + Returns + ------- + values : ndarray, compatible object + The shape of the returned array is described above. + + See Also + -------- + polyroots, polyfromroots, polyval + + Examples + -------- + >>> from numpy.polynomial.polynomial import polyvalfromroots + >>> polyvalfromroots(1, [1,2,3]) + 0.0 + >>> a = np.arange(4).reshape(2,2) + >>> a + array([[0, 1], + [2, 3]]) + >>> polyvalfromroots(a, [-1, 0, 1]) + array([[ -0., 0.], + [ 6., 24.]]) + >>> r = np.arange(-2, 2).reshape(2,2) # multidimensional coefficients + >>> r # each column of r defines one polynomial + array([[-2, -1], + [ 0, 1]]) + >>> b = [-2, 1] + >>> polyvalfromroots(b, r, tensor=True) + array([[-0., 3.], + [ 3., 0.]]) + >>> polyvalfromroots(b, r, tensor=False) + array([-0., 0.]) + """ + r = np.array(r, ndmin=1, copy=0) + if r.dtype.char in '?bBhHiIlLqQpP': + r = r.astype(np.double) + if isinstance(x, (tuple, list)): + x = np.asarray(x) + if isinstance(x, np.ndarray): + if tensor: + r = r.reshape(r.shape + (1,)*x.ndim) + elif x.ndim >= r.ndim: + raise ValueError("x.ndim must be < r.ndim when tensor == False") + return np.prod(x - r, axis=0) + + +def polyval2d(x, y, c): + """ + Evaluate a 2-D polynomial at points (x, y). + + This function returns the value + + .. math:: p(x,y) = \\sum_{i,j} c_{i,j} * x^i * y^j + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars and they + must have the same shape after conversion. In either case, either `x` + and `y` or their elements must support multiplication and addition both + with themselves and with the elements of `c`. + + If `c` has fewer than two dimensions, ones are implicitly appended to + its shape to make it 2-D. The shape of the result will be c.shape[2:] + + x.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points `(x, y)`, + where `x` and `y` must have the same shape. If `x` or `y` is a list + or tuple, it is first converted to an ndarray, otherwise it is left + unchanged and, if it isn't an ndarray, it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term + of multi-degree i,j is contained in `c[i,j]`. If `c` has + dimension greater than two the remaining indices enumerate multiple + sets of coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points formed with + pairs of corresponding values from `x` and `y`. + + See Also + -------- + polyval, polygrid2d, polyval3d, polygrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y = np.array((x, y), copy=0) + except Exception: + raise ValueError('x, y are incompatible') + + c = polyval(x, c) + c = polyval(y, c, tensor=False) + return c + + +def polygrid2d(x, y, c): + """ + Evaluate a 2-D polynomial on the Cartesian product of x and y. + + This function returns the values: + + .. math:: p(a,b) = \\sum_{i,j} c_{i,j} * a^i * b^j + + where the points `(a, b)` consist of all pairs formed by taking + `a` from `x` and `b` from `y`. The resulting points form a grid with + `x` in the first dimension and `y` in the second. + + The parameters `x` and `y` are converted to arrays only if they are + tuples or a lists, otherwise they are treated as a scalars. In either + case, either `x` and `y` or their elements must support multiplication + and addition both with themselves and with the elements of `c`. + + If `c` has fewer than two dimensions, ones are implicitly appended to + its shape to make it 2-D. The shape of the result will be c.shape[2:] + + x.shape + y.shape. + + Parameters + ---------- + x, y : array_like, compatible objects + The two dimensional series is evaluated at the points in the + Cartesian product of `x` and `y`. If `x` or `y` is a list or + tuple, it is first converted to an ndarray, otherwise it is left + unchanged and, if it isn't an ndarray, it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + polyval, polyval2d, polyval3d, polygrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = polyval(x, c) + c = polyval(y, c) + return c + + +def polyval3d(x, y, z, c): + """ + Evaluate a 3-D polynomial at points (x, y, z). + + This function returns the values: + + .. math:: p(x,y,z) = \\sum_{i,j,k} c_{i,j,k} * x^i * y^j * z^k + + The parameters `x`, `y`, and `z` are converted to arrays only if + they are tuples or a lists, otherwise they are treated as a scalars and + they must have the same shape after conversion. In either case, either + `x`, `y`, and `z` or their elements must support multiplication and + addition both with themselves and with the elements of `c`. + + If `c` has fewer than 3 dimensions, ones are implicitly appended to its + shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape. + + Parameters + ---------- + x, y, z : array_like, compatible object + The three dimensional series is evaluated at the points + `(x, y, z)`, where `x`, `y`, and `z` must have the same shape. If + any of `x`, `y`, or `z` is a list or tuple, it is first converted + to an ndarray, otherwise it is left unchanged and if it isn't an + ndarray it is treated as a scalar. + c : array_like + Array of coefficients ordered so that the coefficient of the term of + multi-degree i,j,k is contained in ``c[i,j,k]``. If `c` has dimension + greater than 3 the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the multidimensional polynomial on points formed with + triples of corresponding values from `x`, `y`, and `z`. + + See Also + -------- + polyval, polyval2d, polygrid2d, polygrid3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + try: + x, y, z = np.array((x, y, z), copy=0) + except Exception: + raise ValueError('x, y, z are incompatible') + + c = polyval(x, c) + c = polyval(y, c, tensor=False) + c = polyval(z, c, tensor=False) + return c + + +def polygrid3d(x, y, z, c): + """ + Evaluate a 3-D polynomial on the Cartesian product of x, y and z. + + This function returns the values: + + .. math:: p(a,b,c) = \\sum_{i,j,k} c_{i,j,k} * a^i * b^j * c^k + + where the points `(a, b, c)` consist of all triples formed by taking + `a` from `x`, `b` from `y`, and `c` from `z`. The resulting points form + a grid with `x` in the first dimension, `y` in the second, and `z` in + the third. + + The parameters `x`, `y`, and `z` are converted to arrays only if they + are tuples or a lists, otherwise they are treated as a scalars. In + either case, either `x`, `y`, and `z` or their elements must support + multiplication and addition both with themselves and with the elements + of `c`. + + If `c` has fewer than three dimensions, ones are implicitly appended to + its shape to make it 3-D. The shape of the result will be c.shape[3:] + + x.shape + y.shape + z.shape. + + Parameters + ---------- + x, y, z : array_like, compatible objects + The three dimensional series is evaluated at the points in the + Cartesian product of `x`, `y`, and `z`. If `x`,`y`, or `z` is a + list or tuple, it is first converted to an ndarray, otherwise it is + left unchanged and, if it isn't an ndarray, it is treated as a + scalar. + c : array_like + Array of coefficients ordered so that the coefficients for terms of + degree i,j are contained in ``c[i,j]``. If `c` has dimension + greater than two the remaining indices enumerate multiple sets of + coefficients. + + Returns + ------- + values : ndarray, compatible object + The values of the two dimensional polynomial at points in the Cartesian + product of `x` and `y`. + + See Also + -------- + polyval, polyval2d, polygrid2d, polyval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + c = polyval(x, c) + c = polyval(y, c) + c = polyval(z, c) + return c + + +def polyvander(x, deg): + """Vandermonde matrix of given degree. + + Returns the Vandermonde matrix of degree `deg` and sample points + `x`. The Vandermonde matrix is defined by + + .. math:: V[..., i] = x^i, + + where `0 <= i <= deg`. The leading indices of `V` index the elements of + `x` and the last index is the power of `x`. + + If `c` is a 1-D array of coefficients of length `n + 1` and `V` is the + matrix ``V = polyvander(x, n)``, then ``np.dot(V, c)`` and + ``polyval(x, c)`` are the same up to roundoff. This equivalence is + useful both for least squares fitting and for the evaluation of a large + number of polynomials of the same degree and sample points. + + Parameters + ---------- + x : array_like + Array of points. The dtype is converted to float64 or complex128 + depending on whether any of the elements are complex. If `x` is + scalar it is converted to a 1-D array. + deg : int + Degree of the resulting matrix. + + Returns + ------- + vander : ndarray. + The Vandermonde matrix. The shape of the returned matrix is + ``x.shape + (deg + 1,)``, where the last index is the power of `x`. + The dtype will be the same as the converted `x`. + + See Also + -------- + polyvander2d, polyvander3d + + """ + ideg = int(deg) + if ideg != deg: + raise ValueError("deg must be integer") + if ideg < 0: + raise ValueError("deg must be non-negative") + + x = np.array(x, copy=0, ndmin=1) + 0.0 + dims = (ideg + 1,) + x.shape + dtyp = x.dtype + v = np.empty(dims, dtype=dtyp) + v[0] = x*0 + 1 + if ideg > 0: + v[1] = x + for i in range(2, ideg + 1): + v[i] = v[i-1]*x + return np.moveaxis(v, 0, -1) + + +def polyvander2d(x, y, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y)`. The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (deg[1] + 1)*i + j] = x^i * y^j, + + where `0 <= i <= deg[0]` and `0 <= j <= deg[1]`. The leading indices of + `V` index the points `(x, y)` and the last index encodes the powers of + `x` and `y`. + + If ``V = polyvander2d(x, y, [xdeg, ydeg])``, then the columns of `V` + correspond to the elements of a 2-D coefficient array `c` of shape + (xdeg + 1, ydeg + 1) in the order + + .. math:: c_{00}, c_{01}, c_{02} ... , c_{10}, c_{11}, c_{12} ... + + and ``np.dot(V, c.flat)`` and ``polyval2d(x, y, c)`` will be the same + up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 2-D polynomials + of the same degrees and sample points. + + Parameters + ---------- + x, y : array_like + Arrays of point coordinates, all of the same shape. The dtypes + will be converted to either float64 or complex128 depending on + whether any of the elements are complex. Scalars are converted to + 1-D arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg]. + + Returns + ------- + vander2d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)`. The dtype will be the same + as the converted `x` and `y`. + + See Also + -------- + polyvander, polyvander3d. polyval2d, polyval3d + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy = ideg + x, y = np.array((x, y), copy=0) + 0.0 + + vx = polyvander(x, degx) + vy = polyvander(y, degy) + v = vx[..., None]*vy[..., None,:] + # einsum bug + #v = np.einsum("...i,...j->...ij", vx, vy) + return v.reshape(v.shape[:-2] + (-1,)) + + +def polyvander3d(x, y, z, deg): + """Pseudo-Vandermonde matrix of given degrees. + + Returns the pseudo-Vandermonde matrix of degrees `deg` and sample + points `(x, y, z)`. If `l, m, n` are the given degrees in `x, y, z`, + then The pseudo-Vandermonde matrix is defined by + + .. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = x^i * y^j * z^k, + + where `0 <= i <= l`, `0 <= j <= m`, and `0 <= j <= n`. The leading + indices of `V` index the points `(x, y, z)` and the last index encodes + the powers of `x`, `y`, and `z`. + + If ``V = polyvander3d(x, y, z, [xdeg, ydeg, zdeg])``, then the columns + of `V` correspond to the elements of a 3-D coefficient array `c` of + shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order + + .. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},... + + and ``np.dot(V, c.flat)`` and ``polyval3d(x, y, z, c)`` will be the + same up to roundoff. This equivalence is useful both for least squares + fitting and for the evaluation of a large number of 3-D polynomials + of the same degrees and sample points. + + Parameters + ---------- + x, y, z : array_like + Arrays of point coordinates, all of the same shape. The dtypes will + be converted to either float64 or complex128 depending on whether + any of the elements are complex. Scalars are converted to 1-D + arrays. + deg : list of ints + List of maximum degrees of the form [x_deg, y_deg, z_deg]. + + Returns + ------- + vander3d : ndarray + The shape of the returned matrix is ``x.shape + (order,)``, where + :math:`order = (deg[0]+1)*(deg([1]+1)*(deg[2]+1)`. The dtype will + be the same as the converted `x`, `y`, and `z`. + + See Also + -------- + polyvander, polyvander3d. polyval2d, polyval3d + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + ideg = [int(d) for d in deg] + is_valid = [id == d and id >= 0 for id, d in zip(ideg, deg)] + if is_valid != [1, 1, 1]: + raise ValueError("degrees must be non-negative integers") + degx, degy, degz = ideg + x, y, z = np.array((x, y, z), copy=0) + 0.0 + + vx = polyvander(x, degx) + vy = polyvander(y, degy) + vz = polyvander(z, degz) + v = vx[..., None, None]*vy[..., None,:, None]*vz[..., None, None,:] + # einsum bug + #v = np.einsum("...i, ...j, ...k->...ijk", vx, vy, vz) + return v.reshape(v.shape[:-3] + (-1,)) + + +def polyfit(x, y, deg, rcond=None, full=False, w=None): + """ + Least-squares fit of a polynomial to data. + + Return the coefficients of a polynomial of degree `deg` that is the + least squares fit to the data values `y` given at points `x`. If `y` is + 1-D the returned coefficients will also be 1-D. If `y` is 2-D multiple + fits are done, one for each column of `y`, and the resulting + coefficients are stored in the corresponding columns of a 2-D return. + The fitted polynomial(s) are in the form + + .. math:: p(x) = c_0 + c_1 * x + ... + c_n * x^n, + + where `n` is `deg`. + + Parameters + ---------- + x : array_like, shape (`M`,) + x-coordinates of the `M` sample (data) points ``(x[i], y[i])``. + y : array_like, shape (`M`,) or (`M`, `K`) + y-coordinates of the sample points. Several sets of sample points + sharing the same x-coordinates can be (independently) fit with one + call to `polyfit` by passing in for `y` a 2-D array that contains + one data set per column. + deg : int or 1-D array_like + Degree(s) of the fitting polynomials. If `deg` is a single integer + all terms up to and including the `deg`'th term are included in the + fit. For NumPy versions >= 1.11.0 a list of integers specifying the + degrees of the terms to include may be used instead. + rcond : float, optional + Relative condition number of the fit. Singular values smaller + than `rcond`, relative to the largest singular value, will be + ignored. The default value is ``len(x)*eps``, where `eps` is the + relative precision of the platform's float type, about 2e-16 in + most cases. + full : bool, optional + Switch determining the nature of the return value. When ``False`` + (the default) just the coefficients are returned; when ``True``, + diagnostic information from the singular value decomposition (used + to solve the fit's matrix equation) is also returned. + w : array_like, shape (`M`,), optional + Weights. If not None, the contribution of each point + ``(x[i],y[i])`` to the fit is weighted by `w[i]`. Ideally the + weights are chosen so that the errors of the products ``w[i]*y[i]`` + all have the same variance. The default value is None. + + .. versionadded:: 1.5.0 + + Returns + ------- + coef : ndarray, shape (`deg` + 1,) or (`deg` + 1, `K`) + Polynomial coefficients ordered from low to high. If `y` was 2-D, + the coefficients in column `k` of `coef` represent the polynomial + fit to the data in `y`'s `k`-th column. + + [residuals, rank, singular_values, rcond] : list + These values are only returned if `full` = True + + resid -- sum of squared residuals of the least squares fit + rank -- the numerical rank of the scaled Vandermonde matrix + sv -- singular values of the scaled Vandermonde matrix + rcond -- value of `rcond`. + + For more details, see `linalg.lstsq`. + + Raises + ------ + RankWarning + Raised if the matrix in the least-squares fit is rank deficient. + The warning is only raised if `full` == False. The warnings can + be turned off by: + + >>> import warnings + >>> warnings.simplefilter('ignore', RankWarning) + + See Also + -------- + chebfit, legfit, lagfit, hermfit, hermefit + polyval : Evaluates a polynomial. + polyvander : Vandermonde matrix for powers. + linalg.lstsq : Computes a least-squares fit from the matrix. + scipy.interpolate.UnivariateSpline : Computes spline fits. + + Notes + ----- + The solution is the coefficients of the polynomial `p` that minimizes + the sum of the weighted squared errors + + .. math :: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2, + + where the :math:`w_j` are the weights. This problem is solved by + setting up the (typically) over-determined matrix equation: + + .. math :: V(x) * c = w * y, + + where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the + coefficients to be solved for, `w` are the weights, and `y` are the + observed values. This equation is then solved using the singular value + decomposition of `V`. + + If some of the singular values of `V` are so small that they are + neglected (and `full` == ``False``), a `RankWarning` will be raised. + This means that the coefficient values may be poorly determined. + Fitting to a lower order polynomial will usually get rid of the warning + (but may not be what you want, of course; if you have independent + reason(s) for choosing the degree which isn't working, you may have to: + a) reconsider those reasons, and/or b) reconsider the quality of your + data). The `rcond` parameter can also be set to a value smaller than + its default, but the resulting fit may be spurious and have large + contributions from roundoff error. + + Polynomial fits using double precision tend to "fail" at about + (polynomial) degree 20. Fits using Chebyshev or Legendre series are + generally better conditioned, but much can still depend on the + distribution of the sample points and the smoothness of the data. If + the quality of the fit is inadequate, splines may be a good + alternative. + + Examples + -------- + >>> from numpy.polynomial import polynomial as P + >>> x = np.linspace(-1,1,51) # x "data": [-1, -0.96, ..., 0.96, 1] + >>> y = x**3 - x + np.random.randn(len(x)) # x^3 - x + N(0,1) "noise" + >>> c, stats = P.polyfit(x,y,3,full=True) + >>> c # c[0], c[2] should be approx. 0, c[1] approx. -1, c[3] approx. 1 + array([ 0.01909725, -1.30598256, -0.00577963, 1.02644286]) + >>> stats # note the large SSR, explaining the rather poor results + [array([ 38.06116253]), 4, array([ 1.38446749, 1.32119158, 0.50443316, + 0.28853036]), 1.1324274851176597e-014] + + Same thing without the added noise + + >>> y = x**3 - x + >>> c, stats = P.polyfit(x,y,3,full=True) + >>> c # c[0], c[2] should be "very close to 0", c[1] ~= -1, c[3] ~= 1 + array([ -1.73362882e-17, -1.00000000e+00, -2.67471909e-16, + 1.00000000e+00]) + >>> stats # note the minuscule SSR + [array([ 7.46346754e-31]), 4, array([ 1.38446749, 1.32119158, + 0.50443316, 0.28853036]), 1.1324274851176597e-014] + + """ + x = np.asarray(x) + 0.0 + y = np.asarray(y) + 0.0 + deg = np.asarray(deg) + + # check arguments. + if deg.ndim > 1 or deg.dtype.kind not in 'iu' or deg.size == 0: + raise TypeError("deg must be an int or non-empty 1-D array of int") + if deg.min() < 0: + raise ValueError("expected deg >= 0") + if x.ndim != 1: + raise TypeError("expected 1D vector for x") + if x.size == 0: + raise TypeError("expected non-empty vector for x") + if y.ndim < 1 or y.ndim > 2: + raise TypeError("expected 1D or 2D array for y") + if len(x) != len(y): + raise TypeError("expected x and y to have same length") + + if deg.ndim == 0: + lmax = deg + order = lmax + 1 + van = polyvander(x, lmax) + else: + deg = np.sort(deg) + lmax = deg[-1] + order = len(deg) + van = polyvander(x, lmax)[:, deg] + + # set up the least squares matrices in transposed form + lhs = van.T + rhs = y.T + if w is not None: + w = np.asarray(w) + 0.0 + if w.ndim != 1: + raise TypeError("expected 1D vector for w") + if len(x) != len(w): + raise TypeError("expected x and w to have same length") + # apply weights. Don't use inplace operations as they + # can cause problems with NA. + lhs = lhs * w + rhs = rhs * w + + # set rcond + if rcond is None: + rcond = len(x)*np.finfo(x.dtype).eps + + # Determine the norms of the design matrix columns. + if issubclass(lhs.dtype.type, np.complexfloating): + scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1)) + else: + scl = np.sqrt(np.square(lhs).sum(1)) + scl[scl == 0] = 1 + + # Solve the least squares problem. + c, resids, rank, s = la.lstsq(lhs.T/scl, rhs.T, rcond) + c = (c.T/scl).T + + # Expand c to include non-fitted coefficients which are set to zero + if deg.ndim == 1: + if c.ndim == 2: + cc = np.zeros((lmax + 1, c.shape[1]), dtype=c.dtype) + else: + cc = np.zeros(lmax + 1, dtype=c.dtype) + cc[deg] = c + c = cc + + # warn on rank reduction + if rank != order and not full: + msg = "The fit may be poorly conditioned" + warnings.warn(msg, pu.RankWarning, stacklevel=2) + + if full: + return c, [resids, rank, s, rcond] + else: + return c + + +def polycompanion(c): + """ + Return the companion matrix of c. + + The companion matrix for power series cannot be made symmetric by + scaling the basis, so this function differs from those for the + orthogonal polynomials. + + Parameters + ---------- + c : array_like + 1-D array of polynomial coefficients ordered from low to high + degree. + + Returns + ------- + mat : ndarray + Companion matrix of dimensions (deg, deg). + + Notes + ----- + + .. versionadded:: 1.7.0 + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + raise ValueError('Series must have maximum degree of at least 1.') + if len(c) == 2: + return np.array([[-c[0]/c[1]]]) + + n = len(c) - 1 + mat = np.zeros((n, n), dtype=c.dtype) + bot = mat.reshape(-1)[n::n+1] + bot[...] = 1 + mat[:, -1] -= c[:-1]/c[-1] + return mat + + +def polyroots(c): + """ + Compute the roots of a polynomial. + + Return the roots (a.k.a. "zeros") of the polynomial + + .. math:: p(x) = \\sum_i c[i] * x^i. + + Parameters + ---------- + c : 1-D array_like + 1-D array of polynomial coefficients. + + Returns + ------- + out : ndarray + Array of the roots of the polynomial. If all the roots are real, + then `out` is also real, otherwise it is complex. + + See Also + -------- + chebroots + + Notes + ----- + The root estimates are obtained as the eigenvalues of the companion + matrix, Roots far from the origin of the complex plane may have large + errors due to the numerical instability of the power series for such + values. Roots with multiplicity greater than 1 will also show larger + errors as the value of the series near such points is relatively + insensitive to errors in the roots. Isolated roots near the origin can + be improved by a few iterations of Newton's method. + + Examples + -------- + >>> import numpy.polynomial.polynomial as poly + >>> poly.polyroots(poly.polyfromroots((-1,0,1))) + array([-1., 0., 1.]) + >>> poly.polyroots(poly.polyfromroots((-1,0,1))).dtype + dtype('float64') + >>> j = complex(0,1) + >>> poly.polyroots(poly.polyfromroots((-j,0,j))) + array([ 0.00000000e+00+0.j, 0.00000000e+00+1.j, 2.77555756e-17-1.j]) + + """ + # c is a trimmed copy + [c] = pu.as_series([c]) + if len(c) < 2: + return np.array([], dtype=c.dtype) + if len(c) == 2: + return np.array([-c[0]/c[1]]) + + m = polycompanion(c) + r = la.eigvals(m) + r.sort() + return r + + +# +# polynomial class +# + +class Polynomial(ABCPolyBase): + """A power series class. + + The Polynomial class provides the standard Python numerical methods + '+', '-', '*', '//', '%', 'divmod', '**', and '()' as well as the + attributes and methods listed in the `ABCPolyBase` documentation. + + Parameters + ---------- + coef : array_like + Polynomial coefficients in order of increasing degree, i.e., + ``(1, 2, 3)`` give ``1 + 2*x + 3*x**2``. + domain : (2,) array_like, optional + Domain to use. The interval ``[domain[0], domain[1]]`` is mapped + to the interval ``[window[0], window[1]]`` by shifting and scaling. + The default value is [-1, 1]. + window : (2,) array_like, optional + Window, see `domain` for its use. The default value is [-1, 1]. + + .. versionadded:: 1.6.0 + + """ + # Virtual Functions + _add = staticmethod(polyadd) + _sub = staticmethod(polysub) + _mul = staticmethod(polymul) + _div = staticmethod(polydiv) + _pow = staticmethod(polypow) + _val = staticmethod(polyval) + _int = staticmethod(polyint) + _der = staticmethod(polyder) + _fit = staticmethod(polyfit) + _line = staticmethod(polyline) + _roots = staticmethod(polyroots) + _fromroots = staticmethod(polyfromroots) + + # Virtual properties + nickname = 'poly' + domain = np.array(polydomain) + window = np.array(polydomain) diff --git a/numpy/polynomial/polyutils.py b/numpy/polynomial/polyutils.py new file mode 100644 index 0000000..c1ed0c9 --- /dev/null +++ b/numpy/polynomial/polyutils.py @@ -0,0 +1,412 @@ +""" +Utility classes and functions for the polynomial modules. + +This module provides: error and warning objects; a polynomial base class; +and some routines used in both the `polynomial` and `chebyshev` modules. + +Error objects +------------- + +.. autosummary:: + :toctree: generated/ + + PolyError base class for this sub-package's errors. + PolyDomainError raised when domains are mismatched. + +Warning objects +--------------- + +.. autosummary:: + :toctree: generated/ + + RankWarning raised in least-squares fit for rank-deficient matrix. + +Base class +---------- + +.. autosummary:: + :toctree: generated/ + + PolyBase Obsolete base class for the polynomial classes. Do not use. + +Functions +--------- + +.. autosummary:: + :toctree: generated/ + + as_series convert list of array_likes into 1-D arrays of common type. + trimseq remove trailing zeros. + trimcoef remove small trailing coefficients. + getdomain return the domain appropriate for a given set of abscissae. + mapdomain maps points between domains. + mapparms parameters of the linear map between domains. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np + +__all__ = [ + 'RankWarning', 'PolyError', 'PolyDomainError', 'as_series', 'trimseq', + 'trimcoef', 'getdomain', 'mapdomain', 'mapparms', 'PolyBase'] + +# +# Warnings and Exceptions +# + +class RankWarning(UserWarning): + """Issued by chebfit when the design matrix is rank deficient.""" + pass + +class PolyError(Exception): + """Base class for errors in this module.""" + pass + +class PolyDomainError(PolyError): + """Issued by the generic Poly class when two domains don't match. + + This is raised when an binary operation is passed Poly objects with + different domains. + + """ + pass + +# +# Base class for all polynomial types +# + +class PolyBase(object): + """ + Base class for all polynomial types. + + Deprecated in numpy 1.9.0, use the abstract + ABCPolyBase class instead. Note that the latter + requires a number of virtual functions to be + implemented. + + """ + pass + +# +# Helper functions to convert inputs to 1-D arrays +# +def trimseq(seq): + """Remove small Poly series coefficients. + + Parameters + ---------- + seq : sequence + Sequence of Poly series coefficients. This routine fails for + empty sequences. + + Returns + ------- + series : sequence + Subsequence with trailing zeros removed. If the resulting sequence + would be empty, return the first element. The returned sequence may + or may not be a view. + + Notes + ----- + Do not lose the type info if the sequence contains unknown objects. + + """ + if len(seq) == 0: + return seq + else: + for i in range(len(seq) - 1, -1, -1): + if seq[i] != 0: + break + return seq[:i+1] + + +def as_series(alist, trim=True): + """ + Return argument as a list of 1-d arrays. + + The returned list contains array(s) of dtype double, complex double, or + object. A 1-d argument of shape ``(N,)`` is parsed into ``N`` arrays of + size one; a 2-d argument of shape ``(M,N)`` is parsed into ``M`` arrays + of size ``N`` (i.e., is "parsed by row"); and a higher dimensional array + raises a Value Error if it is not first reshaped into either a 1-d or 2-d + array. + + Parameters + ---------- + alist : array_like + A 1- or 2-d array_like + trim : boolean, optional + When True, trailing zeros are removed from the inputs. + When False, the inputs are passed through intact. + + Returns + ------- + [a1, a2,...] : list of 1-D arrays + A copy of the input data as a list of 1-d arrays. + + Raises + ------ + ValueError + Raised when `as_series` cannot convert its input to 1-d arrays, or at + least one of the resulting arrays is empty. + + Examples + -------- + >>> from numpy.polynomial import polyutils as pu + >>> a = np.arange(4) + >>> pu.as_series(a) + [array([ 0.]), array([ 1.]), array([ 2.]), array([ 3.])] + >>> b = np.arange(6).reshape((2,3)) + >>> pu.as_series(b) + [array([ 0., 1., 2.]), array([ 3., 4., 5.])] + + >>> pu.as_series((1, np.arange(3), np.arange(2, dtype=np.float16))) + [array([ 1.]), array([ 0., 1., 2.]), array([ 0., 1.])] + + >>> pu.as_series([2, [1.1, 0.]]) + [array([ 2.]), array([ 1.1])] + + >>> pu.as_series([2, [1.1, 0.]], trim=False) + [array([ 2.]), array([ 1.1, 0. ])] + + """ + arrays = [np.array(a, ndmin=1, copy=0) for a in alist] + if min([a.size for a in arrays]) == 0: + raise ValueError("Coefficient array is empty") + if any([a.ndim != 1 for a in arrays]): + raise ValueError("Coefficient array is not 1-d") + if trim: + arrays = [trimseq(a) for a in arrays] + + if any([a.dtype == np.dtype(object) for a in arrays]): + ret = [] + for a in arrays: + if a.dtype != np.dtype(object): + tmp = np.empty(len(a), dtype=np.dtype(object)) + tmp[:] = a[:] + ret.append(tmp) + else: + ret.append(a.copy()) + else: + try: + dtype = np.common_type(*arrays) + except Exception: + raise ValueError("Coefficient arrays have no common type") + ret = [np.array(a, copy=1, dtype=dtype) for a in arrays] + return ret + + +def trimcoef(c, tol=0): + """ + Remove "small" "trailing" coefficients from a polynomial. + + "Small" means "small in absolute value" and is controlled by the + parameter `tol`; "trailing" means highest order coefficient(s), e.g., in + ``[0, 1, 1, 0, 0]`` (which represents ``0 + x + x**2 + 0*x**3 + 0*x**4``) + both the 3-rd and 4-th order coefficients would be "trimmed." + + Parameters + ---------- + c : array_like + 1-d array of coefficients, ordered from lowest order to highest. + tol : number, optional + Trailing (i.e., highest order) elements with absolute value less + than or equal to `tol` (default value is zero) are removed. + + Returns + ------- + trimmed : ndarray + 1-d array with trailing zeros removed. If the resulting series + would be empty, a series containing a single zero is returned. + + Raises + ------ + ValueError + If `tol` < 0 + + See Also + -------- + trimseq + + Examples + -------- + >>> from numpy.polynomial import polyutils as pu + >>> pu.trimcoef((0,0,3,0,5,0,0)) + array([ 0., 0., 3., 0., 5.]) + >>> pu.trimcoef((0,0,1e-3,0,1e-5,0,0),1e-3) # item == tol is trimmed + array([ 0.]) + >>> i = complex(0,1) # works for complex + >>> pu.trimcoef((3e-4,1e-3*(1-i),5e-4,2e-5*(1+i)), 1e-3) + array([ 0.0003+0.j , 0.0010-0.001j]) + + """ + if tol < 0: + raise ValueError("tol must be non-negative") + + [c] = as_series([c]) + [ind] = np.nonzero(np.abs(c) > tol) + if len(ind) == 0: + return c[:1]*0 + else: + return c[:ind[-1] + 1].copy() + +def getdomain(x): + """ + Return a domain suitable for given abscissae. + + Find a domain suitable for a polynomial or Chebyshev series + defined at the values supplied. + + Parameters + ---------- + x : array_like + 1-d array of abscissae whose domain will be determined. + + Returns + ------- + domain : ndarray + 1-d array containing two values. If the inputs are complex, then + the two returned points are the lower left and upper right corners + of the smallest rectangle (aligned with the axes) in the complex + plane containing the points `x`. If the inputs are real, then the + two points are the ends of the smallest interval containing the + points `x`. + + See Also + -------- + mapparms, mapdomain + + Examples + -------- + >>> from numpy.polynomial import polyutils as pu + >>> points = np.arange(4)**2 - 5; points + array([-5, -4, -1, 4]) + >>> pu.getdomain(points) + array([-5., 4.]) + >>> c = np.exp(complex(0,1)*np.pi*np.arange(12)/6) # unit circle + >>> pu.getdomain(c) + array([-1.-1.j, 1.+1.j]) + + """ + [x] = as_series([x], trim=False) + if x.dtype.char in np.typecodes['Complex']: + rmin, rmax = x.real.min(), x.real.max() + imin, imax = x.imag.min(), x.imag.max() + return np.array((complex(rmin, imin), complex(rmax, imax))) + else: + return np.array((x.min(), x.max())) + +def mapparms(old, new): + """ + Linear map parameters between domains. + + Return the parameters of the linear map ``offset + scale*x`` that maps + `old` to `new` such that ``old[i] -> new[i]``, ``i = 0, 1``. + + Parameters + ---------- + old, new : array_like + Domains. Each domain must (successfully) convert to a 1-d array + containing precisely two values. + + Returns + ------- + offset, scale : scalars + The map ``L(x) = offset + scale*x`` maps the first domain to the + second. + + See Also + -------- + getdomain, mapdomain + + Notes + ----- + Also works for complex numbers, and thus can be used to calculate the + parameters required to map any line in the complex plane to any other + line therein. + + Examples + -------- + >>> from numpy.polynomial import polyutils as pu + >>> pu.mapparms((-1,1),(-1,1)) + (0.0, 1.0) + >>> pu.mapparms((1,-1),(-1,1)) + (0.0, -1.0) + >>> i = complex(0,1) + >>> pu.mapparms((-i,-1),(1,i)) + ((1+1j), (1+0j)) + + """ + oldlen = old[1] - old[0] + newlen = new[1] - new[0] + off = (old[1]*new[0] - old[0]*new[1])/oldlen + scl = newlen/oldlen + return off, scl + +def mapdomain(x, old, new): + """ + Apply linear map to input points. + + The linear map ``offset + scale*x`` that maps the domain `old` to + the domain `new` is applied to the points `x`. + + Parameters + ---------- + x : array_like + Points to be mapped. If `x` is a subtype of ndarray the subtype + will be preserved. + old, new : array_like + The two domains that determine the map. Each must (successfully) + convert to 1-d arrays containing precisely two values. + + Returns + ------- + x_out : ndarray + Array of points of the same shape as `x`, after application of the + linear map between the two domains. + + See Also + -------- + getdomain, mapparms + + Notes + ----- + Effectively, this implements: + + .. math :: + x\\_out = new[0] + m(x - old[0]) + + where + + .. math :: + m = \\frac{new[1]-new[0]}{old[1]-old[0]} + + Examples + -------- + >>> from numpy.polynomial import polyutils as pu + >>> old_domain = (-1,1) + >>> new_domain = (0,2*np.pi) + >>> x = np.linspace(-1,1,6); x + array([-1. , -0.6, -0.2, 0.2, 0.6, 1. ]) + >>> x_out = pu.mapdomain(x, old_domain, new_domain); x_out + array([ 0. , 1.25663706, 2.51327412, 3.76991118, 5.02654825, + 6.28318531]) + >>> x - pu.mapdomain(x_out, new_domain, old_domain) + array([ 0., 0., 0., 0., 0., 0.]) + + Also works for complex numbers (and thus can be used to map any line in + the complex plane to any other line therein). + + >>> i = complex(0,1) + >>> old = (-1 - i, 1 + i) + >>> new = (-1 + i, 1 - i) + >>> z = np.linspace(old[0], old[1], 6); z + array([-1.0-1.j , -0.6-0.6j, -0.2-0.2j, 0.2+0.2j, 0.6+0.6j, 1.0+1.j ]) + >>> new_z = P.mapdomain(z, old, new); new_z + array([-1.0+1.j , -0.6+0.6j, -0.2+0.2j, 0.2-0.2j, 0.6-0.6j, 1.0-1.j ]) + + """ + x = np.asanyarray(x) + off, scl = mapparms(old, new) + return off + scl*x diff --git a/numpy/polynomial/setup.py b/numpy/polynomial/setup.py new file mode 100644 index 0000000..cb59ee1 --- /dev/null +++ b/numpy/polynomial/setup.py @@ -0,0 +1,11 @@ +from __future__ import division, print_function + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('polynomial', parent_package, top_path) + config.add_data_dir('tests') + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/polynomial/tests/__init__.py b/numpy/polynomial/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/polynomial/tests/__init__.py diff --git a/numpy/polynomial/tests/test_chebyshev.py b/numpy/polynomial/tests/test_chebyshev.py new file mode 100644 index 0000000..f003081 --- /dev/null +++ b/numpy/polynomial/tests/test_chebyshev.py @@ -0,0 +1,614 @@ +"""Tests for chebyshev module. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +import numpy.polynomial.chebyshev as cheb +from numpy.polynomial.polynomial import polyval +from numpy.testing import ( + assert_almost_equal, assert_raises, assert_equal, assert_, + run_module_suite + ) + + +def trim(x): + return cheb.chebtrim(x, tol=1e-6) + +T0 = [1] +T1 = [0, 1] +T2 = [-1, 0, 2] +T3 = [0, -3, 0, 4] +T4 = [1, 0, -8, 0, 8] +T5 = [0, 5, 0, -20, 0, 16] +T6 = [-1, 0, 18, 0, -48, 0, 32] +T7 = [0, -7, 0, 56, 0, -112, 0, 64] +T8 = [1, 0, -32, 0, 160, 0, -256, 0, 128] +T9 = [0, 9, 0, -120, 0, 432, 0, -576, 0, 256] + +Tlist = [T0, T1, T2, T3, T4, T5, T6, T7, T8, T9] + + +class TestPrivate(object): + + def test__cseries_to_zseries(self): + for i in range(5): + inp = np.array([2] + [1]*i, np.double) + tgt = np.array([.5]*i + [2] + [.5]*i, np.double) + res = cheb._cseries_to_zseries(inp) + assert_equal(res, tgt) + + def test__zseries_to_cseries(self): + for i in range(5): + inp = np.array([.5]*i + [2] + [.5]*i, np.double) + tgt = np.array([2] + [1]*i, np.double) + res = cheb._zseries_to_cseries(inp) + assert_equal(res, tgt) + + +class TestConstants(object): + + def test_chebdomain(self): + assert_equal(cheb.chebdomain, [-1, 1]) + + def test_chebzero(self): + assert_equal(cheb.chebzero, [0]) + + def test_chebone(self): + assert_equal(cheb.chebone, [1]) + + def test_chebx(self): + assert_equal(cheb.chebx, [0, 1]) + + +class TestArithmetic(object): + + def test_chebadd(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] += 1 + res = cheb.chebadd([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_chebsub(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] -= 1 + res = cheb.chebsub([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_chebmulx(self): + assert_equal(cheb.chebmulx([0]), [0]) + assert_equal(cheb.chebmulx([1]), [0, 1]) + for i in range(1, 5): + ser = [0]*i + [1] + tgt = [0]*(i - 1) + [.5, 0, .5] + assert_equal(cheb.chebmulx(ser), tgt) + + def test_chebmul(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(i + j + 1) + tgt[i + j] += .5 + tgt[abs(i - j)] += .5 + res = cheb.chebmul([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_chebdiv(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + ci = [0]*i + [1] + cj = [0]*j + [1] + tgt = cheb.chebadd(ci, cj) + quo, rem = cheb.chebdiv(tgt, ci) + res = cheb.chebadd(cheb.chebmul(quo, ci), rem) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + +class TestEvaluation(object): + # coefficients of 1 + 2*x + 3*x**2 + c1d = np.array([2.5, 2., 1.5]) + c2d = np.einsum('i,j->ij', c1d, c1d) + c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d) + + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + y = polyval(x, [1., 2., 3.]) + + def test_chebval(self): + #check empty input + assert_equal(cheb.chebval([], [1]).size, 0) + + #check normal input) + x = np.linspace(-1, 1) + y = [polyval(x, c) for c in Tlist] + for i in range(10): + msg = "At i=%d" % i + tgt = y[i] + res = cheb.chebval(x, [0]*i + [1]) + assert_almost_equal(res, tgt, err_msg=msg) + + #check that shape is preserved + for i in range(3): + dims = [2]*i + x = np.zeros(dims) + assert_equal(cheb.chebval(x, [1]).shape, dims) + assert_equal(cheb.chebval(x, [1, 0]).shape, dims) + assert_equal(cheb.chebval(x, [1, 0, 0]).shape, dims) + + def test_chebval2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, cheb.chebval2d, x1, x2[:2], self.c2d) + + #test values + tgt = y1*y2 + res = cheb.chebval2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = cheb.chebval2d(z, z, self.c2d) + assert_(res.shape == (2, 3)) + + def test_chebval3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, cheb.chebval3d, x1, x2, x3[:2], self.c3d) + + #test values + tgt = y1*y2*y3 + res = cheb.chebval3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = cheb.chebval3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)) + + def test_chebgrid2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j->ij', y1, y2) + res = cheb.chebgrid2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = cheb.chebgrid2d(z, z, self.c2d) + assert_(res.shape == (2, 3)*2) + + def test_chebgrid3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j,k->ijk', y1, y2, y3) + res = cheb.chebgrid3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = cheb.chebgrid3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)*3) + + +class TestIntegral(object): + + def test_chebint(self): + # check exceptions + assert_raises(ValueError, cheb.chebint, [0], .5) + assert_raises(ValueError, cheb.chebint, [0], -1) + assert_raises(ValueError, cheb.chebint, [0], 1, [0, 0]) + assert_raises(ValueError, cheb.chebint, [0], lbnd=[0]) + assert_raises(ValueError, cheb.chebint, [0], scl=[0]) + assert_raises(ValueError, cheb.chebint, [0], axis=.5) + + # test integration of zero polynomial + for i in range(2, 5): + k = [0]*(i - 2) + [1] + res = cheb.chebint([0], m=i, k=k) + assert_almost_equal(res, [0, 1]) + + # check single integration with integration constant + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [1/scl] + chebpol = cheb.poly2cheb(pol) + chebint = cheb.chebint(chebpol, m=1, k=[i]) + res = cheb.cheb2poly(chebint) + assert_almost_equal(trim(res), trim(tgt)) + + # check single integration with integration constant and lbnd + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + chebpol = cheb.poly2cheb(pol) + chebint = cheb.chebint(chebpol, m=1, k=[i], lbnd=-1) + assert_almost_equal(cheb.chebval(-1, chebint), i) + + # check single integration with integration constant and scaling + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [2/scl] + chebpol = cheb.poly2cheb(pol) + chebint = cheb.chebint(chebpol, m=1, k=[i], scl=2) + res = cheb.cheb2poly(chebint) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with default k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = cheb.chebint(tgt, m=1) + res = cheb.chebint(pol, m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with defined k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = cheb.chebint(tgt, m=1, k=[k]) + res = cheb.chebint(pol, m=j, k=list(range(j))) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with lbnd + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = cheb.chebint(tgt, m=1, k=[k], lbnd=-1) + res = cheb.chebint(pol, m=j, k=list(range(j)), lbnd=-1) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with scaling + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = cheb.chebint(tgt, m=1, k=[k], scl=2) + res = cheb.chebint(pol, m=j, k=list(range(j)), scl=2) + assert_almost_equal(trim(res), trim(tgt)) + + def test_chebint_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([cheb.chebint(c) for c in c2d.T]).T + res = cheb.chebint(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([cheb.chebint(c) for c in c2d]) + res = cheb.chebint(c2d, axis=1) + assert_almost_equal(res, tgt) + + tgt = np.vstack([cheb.chebint(c, k=3) for c in c2d]) + res = cheb.chebint(c2d, k=3, axis=1) + assert_almost_equal(res, tgt) + + +class TestDerivative(object): + + def test_chebder(self): + # check exceptions + assert_raises(ValueError, cheb.chebder, [0], .5) + assert_raises(ValueError, cheb.chebder, [0], -1) + + # check that zeroth derivative does nothing + for i in range(5): + tgt = [0]*i + [1] + res = cheb.chebder(tgt, m=0) + assert_equal(trim(res), trim(tgt)) + + # check that derivation is the inverse of integration + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = cheb.chebder(cheb.chebint(tgt, m=j), m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check derivation with scaling + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = cheb.chebder(cheb.chebint(tgt, m=j, scl=2), m=j, scl=.5) + assert_almost_equal(trim(res), trim(tgt)) + + def test_chebder_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([cheb.chebder(c) for c in c2d.T]).T + res = cheb.chebder(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([cheb.chebder(c) for c in c2d]) + res = cheb.chebder(c2d, axis=1) + assert_almost_equal(res, tgt) + + +class TestVander(object): + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + + def test_chebvander(self): + # check for 1d x + x = np.arange(3) + v = cheb.chebvander(x, 3) + assert_(v.shape == (3, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], cheb.chebval(x, coef)) + + # check for 2d x + x = np.array([[1, 2], [3, 4], [5, 6]]) + v = cheb.chebvander(x, 3) + assert_(v.shape == (3, 2, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], cheb.chebval(x, coef)) + + def test_chebvander2d(self): + # also tests chebval2d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3)) + van = cheb.chebvander2d(x1, x2, [1, 2]) + tgt = cheb.chebval2d(x1, x2, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = cheb.chebvander2d([x1], [x2], [1, 2]) + assert_(van.shape == (1, 5, 6)) + + def test_chebvander3d(self): + # also tests chebval3d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3, 4)) + van = cheb.chebvander3d(x1, x2, x3, [1, 2, 3]) + tgt = cheb.chebval3d(x1, x2, x3, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = cheb.chebvander3d([x1], [x2], [x3], [1, 2, 3]) + assert_(van.shape == (1, 5, 24)) + + +class TestFitting(object): + + def test_chebfit(self): + def f(x): + return x*(x - 1)*(x - 2) + + def f2(x): + return x**4 + x**2 + 1 + + # Test exceptions + assert_raises(ValueError, cheb.chebfit, [1], [1], -1) + assert_raises(TypeError, cheb.chebfit, [[1]], [1], 0) + assert_raises(TypeError, cheb.chebfit, [], [1], 0) + assert_raises(TypeError, cheb.chebfit, [1], [[[1]]], 0) + assert_raises(TypeError, cheb.chebfit, [1, 2], [1], 0) + assert_raises(TypeError, cheb.chebfit, [1], [1, 2], 0) + assert_raises(TypeError, cheb.chebfit, [1], [1], 0, w=[[1]]) + assert_raises(TypeError, cheb.chebfit, [1], [1], 0, w=[1, 1]) + assert_raises(ValueError, cheb.chebfit, [1], [1], [-1,]) + assert_raises(ValueError, cheb.chebfit, [1], [1], [2, -1, 6]) + assert_raises(TypeError, cheb.chebfit, [1], [1], []) + + # Test fit + x = np.linspace(0, 2) + y = f(x) + # + coef3 = cheb.chebfit(x, y, 3) + assert_equal(len(coef3), 4) + assert_almost_equal(cheb.chebval(x, coef3), y) + coef3 = cheb.chebfit(x, y, [0, 1, 2, 3]) + assert_equal(len(coef3), 4) + assert_almost_equal(cheb.chebval(x, coef3), y) + # + coef4 = cheb.chebfit(x, y, 4) + assert_equal(len(coef4), 5) + assert_almost_equal(cheb.chebval(x, coef4), y) + coef4 = cheb.chebfit(x, y, [0, 1, 2, 3, 4]) + assert_equal(len(coef4), 5) + assert_almost_equal(cheb.chebval(x, coef4), y) + # check things still work if deg is not in strict increasing + coef4 = cheb.chebfit(x, y, [2, 3, 4, 1, 0]) + assert_equal(len(coef4), 5) + assert_almost_equal(cheb.chebval(x, coef4), y) + # + coef2d = cheb.chebfit(x, np.array([y, y]).T, 3) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + coef2d = cheb.chebfit(x, np.array([y, y]).T, [0, 1, 2, 3]) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + # test weighting + w = np.zeros_like(x) + yw = y.copy() + w[1::2] = 1 + y[0::2] = 0 + wcoef3 = cheb.chebfit(x, yw, 3, w=w) + assert_almost_equal(wcoef3, coef3) + wcoef3 = cheb.chebfit(x, yw, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef3, coef3) + # + wcoef2d = cheb.chebfit(x, np.array([yw, yw]).T, 3, w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + wcoef2d = cheb.chebfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + # test scaling with complex values x points whose square + # is zero when summed. + x = [1, 1j, -1, -1j] + assert_almost_equal(cheb.chebfit(x, x, 1), [0, 1]) + assert_almost_equal(cheb.chebfit(x, x, [0, 1]), [0, 1]) + # test fitting only even polynomials + x = np.linspace(-1, 1) + y = f2(x) + coef1 = cheb.chebfit(x, y, 4) + assert_almost_equal(cheb.chebval(x, coef1), y) + coef2 = cheb.chebfit(x, y, [0, 2, 4]) + assert_almost_equal(cheb.chebval(x, coef2), y) + assert_almost_equal(coef1, coef2) + + +class TestInterpolate(object): + + def f(self, x): + return x * (x - 1) * (x - 2) + + def test_raises(self): + assert_raises(ValueError, cheb.chebinterpolate, self.f, -1) + assert_raises(TypeError, cheb.chebinterpolate, self.f, 10.) + + def test_dimensions(self): + for deg in range(1, 5): + assert_(cheb.chebinterpolate(self.f, deg).shape == (deg + 1,)) + + def test_approximation(self): + + def powx(x, p): + return x**p + + x = np.linspace(-1, 1, 10) + for deg in range(0, 10): + for p in range(0, deg + 1): + c = cheb.chebinterpolate(powx, deg, (p,)) + assert_almost_equal(cheb.chebval(x, c), powx(x, p), decimal=12) + + +class TestCompanion(object): + + def test_raises(self): + assert_raises(ValueError, cheb.chebcompanion, []) + assert_raises(ValueError, cheb.chebcompanion, [1]) + + def test_dimensions(self): + for i in range(1, 5): + coef = [0]*i + [1] + assert_(cheb.chebcompanion(coef).shape == (i, i)) + + def test_linear_root(self): + assert_(cheb.chebcompanion([1, 2])[0, 0] == -.5) + + +class TestGauss(object): + + def test_100(self): + x, w = cheb.chebgauss(100) + + # test orthogonality. Note that the results need to be normalized, + # otherwise the huge values that can arise from fast growing + # functions like Laguerre can be very confusing. + v = cheb.chebvander(x, 99) + vv = np.dot(v.T * w, v) + vd = 1/np.sqrt(vv.diagonal()) + vv = vd[:, None] * vv * vd + assert_almost_equal(vv, np.eye(100)) + + # check that the integral of 1 is correct + tgt = np.pi + assert_almost_equal(w.sum(), tgt) + + +class TestMisc(object): + + def test_chebfromroots(self): + res = cheb.chebfromroots([]) + assert_almost_equal(trim(res), [1]) + for i in range(1, 5): + roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2]) + tgt = [0]*i + [1] + res = cheb.chebfromroots(roots)*2**(i-1) + assert_almost_equal(trim(res), trim(tgt)) + + def test_chebroots(self): + assert_almost_equal(cheb.chebroots([1]), []) + assert_almost_equal(cheb.chebroots([1, 2]), [-.5]) + for i in range(2, 5): + tgt = np.linspace(-1, 1, i) + res = cheb.chebroots(cheb.chebfromroots(tgt)) + assert_almost_equal(trim(res), trim(tgt)) + + def test_chebtrim(self): + coef = [2, -1, 1, 0] + + # Test exceptions + assert_raises(ValueError, cheb.chebtrim, coef, -1) + + # Test results + assert_equal(cheb.chebtrim(coef), coef[:-1]) + assert_equal(cheb.chebtrim(coef, 1), coef[:-3]) + assert_equal(cheb.chebtrim(coef, 2), [0]) + + def test_chebline(self): + assert_equal(cheb.chebline(3, 4), [3, 4]) + + def test_cheb2poly(self): + for i in range(10): + assert_almost_equal(cheb.cheb2poly([0]*i + [1]), Tlist[i]) + + def test_poly2cheb(self): + for i in range(10): + assert_almost_equal(cheb.poly2cheb(Tlist[i]), [0]*i + [1]) + + def test_weight(self): + x = np.linspace(-1, 1, 11)[1:-1] + tgt = 1./(np.sqrt(1 + x) * np.sqrt(1 - x)) + res = cheb.chebweight(x) + assert_almost_equal(res, tgt) + + def test_chebpts1(self): + #test exceptions + assert_raises(ValueError, cheb.chebpts1, 1.5) + assert_raises(ValueError, cheb.chebpts1, 0) + + #test points + tgt = [0] + assert_almost_equal(cheb.chebpts1(1), tgt) + tgt = [-0.70710678118654746, 0.70710678118654746] + assert_almost_equal(cheb.chebpts1(2), tgt) + tgt = [-0.86602540378443871, 0, 0.86602540378443871] + assert_almost_equal(cheb.chebpts1(3), tgt) + tgt = [-0.9238795325, -0.3826834323, 0.3826834323, 0.9238795325] + assert_almost_equal(cheb.chebpts1(4), tgt) + + def test_chebpts2(self): + #test exceptions + assert_raises(ValueError, cheb.chebpts2, 1.5) + assert_raises(ValueError, cheb.chebpts2, 1) + + #test points + tgt = [-1, 1] + assert_almost_equal(cheb.chebpts2(2), tgt) + tgt = [-1, 0, 1] + assert_almost_equal(cheb.chebpts2(3), tgt) + tgt = [-1, -0.5, .5, 1] + assert_almost_equal(cheb.chebpts2(4), tgt) + tgt = [-1.0, -0.707106781187, 0, 0.707106781187, 1.0] + assert_almost_equal(cheb.chebpts2(5), tgt) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/polynomial/tests/test_classes.py b/numpy/polynomial/tests/test_classes.py new file mode 100644 index 0000000..2ec8277 --- /dev/null +++ b/numpy/polynomial/tests/test_classes.py @@ -0,0 +1,612 @@ +"""Test inter-conversion of different polynomial classes. + +This tests the convert and cast methods of all the polynomial classes. + +""" +from __future__ import division, absolute_import, print_function + +import operator as op +from numbers import Number + +import numpy as np +from numpy.polynomial import ( + Polynomial, Legendre, Chebyshev, Laguerre, Hermite, HermiteE) +from numpy.testing import ( + assert_almost_equal, assert_raises, assert_equal, assert_, + run_module_suite) +from numpy.compat import long + + +classes = ( + Polynomial, Legendre, Chebyshev, Laguerre, + Hermite, HermiteE) + + +def test_class_methods(): + for Poly1 in classes: + for Poly2 in classes: + yield check_conversion, Poly1, Poly2 + yield check_cast, Poly1, Poly2 + for Poly in classes: + yield check_call, Poly + yield check_identity, Poly + yield check_basis, Poly + yield check_fromroots, Poly + yield check_fit, Poly + yield check_equal, Poly + yield check_not_equal, Poly + yield check_add, Poly + yield check_sub, Poly + yield check_mul, Poly + yield check_floordiv, Poly + yield check_truediv, Poly + yield check_mod, Poly + yield check_divmod, Poly + yield check_pow, Poly + yield check_integ, Poly + yield check_deriv, Poly + yield check_roots, Poly + yield check_linspace, Poly + yield check_mapparms, Poly + yield check_degree, Poly + yield check_copy, Poly + yield check_cutdeg, Poly + yield check_truncate, Poly + yield check_trim, Poly + yield check_ufunc_override, Poly + + +# +# helper functions +# +random = np.random.random + + +def assert_poly_almost_equal(p1, p2, msg=""): + try: + assert_(np.all(p1.domain == p2.domain)) + assert_(np.all(p1.window == p2.window)) + assert_almost_equal(p1.coef, p2.coef) + except AssertionError: + msg = "Result: %s\nTarget: %s", (p1, p2) + raise AssertionError(msg) + + +# +# conversion methods that depend on two classes +# + + +def check_conversion(Poly1, Poly2): + x = np.linspace(0, 1, 10) + coef = random((3,)) + + d1 = Poly1.domain + random((2,))*.25 + w1 = Poly1.window + random((2,))*.25 + p1 = Poly1(coef, domain=d1, window=w1) + + d2 = Poly2.domain + random((2,))*.25 + w2 = Poly2.window + random((2,))*.25 + p2 = p1.convert(kind=Poly2, domain=d2, window=w2) + + assert_almost_equal(p2.domain, d2) + assert_almost_equal(p2.window, w2) + assert_almost_equal(p2(x), p1(x)) + + +def check_cast(Poly1, Poly2): + x = np.linspace(0, 1, 10) + coef = random((3,)) + + d1 = Poly1.domain + random((2,))*.25 + w1 = Poly1.window + random((2,))*.25 + p1 = Poly1(coef, domain=d1, window=w1) + + d2 = Poly2.domain + random((2,))*.25 + w2 = Poly2.window + random((2,))*.25 + p2 = Poly2.cast(p1, domain=d2, window=w2) + + assert_almost_equal(p2.domain, d2) + assert_almost_equal(p2.window, w2) + assert_almost_equal(p2(x), p1(x)) + + +# +# methods that depend on one class +# + + +def check_identity(Poly): + d = Poly.domain + random((2,))*.25 + w = Poly.window + random((2,))*.25 + x = np.linspace(d[0], d[1], 11) + p = Poly.identity(domain=d, window=w) + assert_equal(p.domain, d) + assert_equal(p.window, w) + assert_almost_equal(p(x), x) + + +def check_basis(Poly): + d = Poly.domain + random((2,))*.25 + w = Poly.window + random((2,))*.25 + p = Poly.basis(5, domain=d, window=w) + assert_equal(p.domain, d) + assert_equal(p.window, w) + assert_equal(p.coef, [0]*5 + [1]) + + +def check_fromroots(Poly): + # check that requested roots are zeros of a polynomial + # of correct degree, domain, and window. + d = Poly.domain + random((2,))*.25 + w = Poly.window + random((2,))*.25 + r = random((5,)) + p1 = Poly.fromroots(r, domain=d, window=w) + assert_equal(p1.degree(), len(r)) + assert_equal(p1.domain, d) + assert_equal(p1.window, w) + assert_almost_equal(p1(r), 0) + + # check that polynomial is monic + pdom = Polynomial.domain + pwin = Polynomial.window + p2 = Polynomial.cast(p1, domain=pdom, window=pwin) + assert_almost_equal(p2.coef[-1], 1) + + +def check_fit(Poly): + + def f(x): + return x*(x - 1)*(x - 2) + x = np.linspace(0, 3) + y = f(x) + + # check default value of domain and window + p = Poly.fit(x, y, 3) + assert_almost_equal(p.domain, [0, 3]) + assert_almost_equal(p(x), y) + assert_equal(p.degree(), 3) + + # check with given domains and window + d = Poly.domain + random((2,))*.25 + w = Poly.window + random((2,))*.25 + p = Poly.fit(x, y, 3, domain=d, window=w) + assert_almost_equal(p(x), y) + assert_almost_equal(p.domain, d) + assert_almost_equal(p.window, w) + p = Poly.fit(x, y, [0, 1, 2, 3], domain=d, window=w) + assert_almost_equal(p(x), y) + assert_almost_equal(p.domain, d) + assert_almost_equal(p.window, w) + + # check with class domain default + p = Poly.fit(x, y, 3, []) + assert_equal(p.domain, Poly.domain) + assert_equal(p.window, Poly.window) + p = Poly.fit(x, y, [0, 1, 2, 3], []) + assert_equal(p.domain, Poly.domain) + assert_equal(p.window, Poly.window) + + # check that fit accepts weights. + w = np.zeros_like(x) + z = y + random(y.shape)*.25 + w[::2] = 1 + p1 = Poly.fit(x[::2], z[::2], 3) + p2 = Poly.fit(x, z, 3, w=w) + p3 = Poly.fit(x, z, [0, 1, 2, 3], w=w) + assert_almost_equal(p1(x), p2(x)) + assert_almost_equal(p2(x), p3(x)) + + +def check_equal(Poly): + p1 = Poly([1, 2, 3], domain=[0, 1], window=[2, 3]) + p2 = Poly([1, 1, 1], domain=[0, 1], window=[2, 3]) + p3 = Poly([1, 2, 3], domain=[1, 2], window=[2, 3]) + p4 = Poly([1, 2, 3], domain=[0, 1], window=[1, 2]) + assert_(p1 == p1) + assert_(not p1 == p2) + assert_(not p1 == p3) + assert_(not p1 == p4) + + +def check_not_equal(Poly): + p1 = Poly([1, 2, 3], domain=[0, 1], window=[2, 3]) + p2 = Poly([1, 1, 1], domain=[0, 1], window=[2, 3]) + p3 = Poly([1, 2, 3], domain=[1, 2], window=[2, 3]) + p4 = Poly([1, 2, 3], domain=[0, 1], window=[1, 2]) + assert_(not p1 != p1) + assert_(p1 != p2) + assert_(p1 != p3) + assert_(p1 != p4) + + +def check_add(Poly): + # This checks commutation, not numerical correctness + c1 = list(random((4,)) + .5) + c2 = list(random((3,)) + .5) + p1 = Poly(c1) + p2 = Poly(c2) + p3 = p1 + p2 + assert_poly_almost_equal(p2 + p1, p3) + assert_poly_almost_equal(p1 + c2, p3) + assert_poly_almost_equal(c2 + p1, p3) + assert_poly_almost_equal(p1 + tuple(c2), p3) + assert_poly_almost_equal(tuple(c2) + p1, p3) + assert_poly_almost_equal(p1 + np.array(c2), p3) + assert_poly_almost_equal(np.array(c2) + p1, p3) + assert_raises(TypeError, op.add, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, op.add, p1, Poly([0], window=Poly.window + 1)) + if Poly is Polynomial: + assert_raises(TypeError, op.add, p1, Chebyshev([0])) + else: + assert_raises(TypeError, op.add, p1, Polynomial([0])) + + +def check_sub(Poly): + # This checks commutation, not numerical correctness + c1 = list(random((4,)) + .5) + c2 = list(random((3,)) + .5) + p1 = Poly(c1) + p2 = Poly(c2) + p3 = p1 - p2 + assert_poly_almost_equal(p2 - p1, -p3) + assert_poly_almost_equal(p1 - c2, p3) + assert_poly_almost_equal(c2 - p1, -p3) + assert_poly_almost_equal(p1 - tuple(c2), p3) + assert_poly_almost_equal(tuple(c2) - p1, -p3) + assert_poly_almost_equal(p1 - np.array(c2), p3) + assert_poly_almost_equal(np.array(c2) - p1, -p3) + assert_raises(TypeError, op.sub, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, op.sub, p1, Poly([0], window=Poly.window + 1)) + if Poly is Polynomial: + assert_raises(TypeError, op.sub, p1, Chebyshev([0])) + else: + assert_raises(TypeError, op.sub, p1, Polynomial([0])) + + +def check_mul(Poly): + c1 = list(random((4,)) + .5) + c2 = list(random((3,)) + .5) + p1 = Poly(c1) + p2 = Poly(c2) + p3 = p1 * p2 + assert_poly_almost_equal(p2 * p1, p3) + assert_poly_almost_equal(p1 * c2, p3) + assert_poly_almost_equal(c2 * p1, p3) + assert_poly_almost_equal(p1 * tuple(c2), p3) + assert_poly_almost_equal(tuple(c2) * p1, p3) + assert_poly_almost_equal(p1 * np.array(c2), p3) + assert_poly_almost_equal(np.array(c2) * p1, p3) + assert_poly_almost_equal(p1 * 2, p1 * Poly([2])) + assert_poly_almost_equal(2 * p1, p1 * Poly([2])) + assert_raises(TypeError, op.mul, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, op.mul, p1, Poly([0], window=Poly.window + 1)) + if Poly is Polynomial: + assert_raises(TypeError, op.mul, p1, Chebyshev([0])) + else: + assert_raises(TypeError, op.mul, p1, Polynomial([0])) + + +def check_floordiv(Poly): + c1 = list(random((4,)) + .5) + c2 = list(random((3,)) + .5) + c3 = list(random((2,)) + .5) + p1 = Poly(c1) + p2 = Poly(c2) + p3 = Poly(c3) + p4 = p1 * p2 + p3 + c4 = list(p4.coef) + assert_poly_almost_equal(p4 // p2, p1) + assert_poly_almost_equal(p4 // c2, p1) + assert_poly_almost_equal(c4 // p2, p1) + assert_poly_almost_equal(p4 // tuple(c2), p1) + assert_poly_almost_equal(tuple(c4) // p2, p1) + assert_poly_almost_equal(p4 // np.array(c2), p1) + assert_poly_almost_equal(np.array(c4) // p2, p1) + assert_poly_almost_equal(2 // p2, Poly([0])) + assert_poly_almost_equal(p2 // 2, 0.5*p2) + assert_raises( + TypeError, op.floordiv, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises( + TypeError, op.floordiv, p1, Poly([0], window=Poly.window + 1)) + if Poly is Polynomial: + assert_raises(TypeError, op.floordiv, p1, Chebyshev([0])) + else: + assert_raises(TypeError, op.floordiv, p1, Polynomial([0])) + + +def check_truediv(Poly): + # true division is valid only if the denominator is a Number and + # not a python bool. + p1 = Poly([1,2,3]) + p2 = p1 * 5 + + for stype in np.ScalarType: + if not issubclass(stype, Number) or issubclass(stype, bool): + continue + s = stype(5) + assert_poly_almost_equal(op.truediv(p2, s), p1) + assert_raises(TypeError, op.truediv, s, p2) + for stype in (int, long, float): + s = stype(5) + assert_poly_almost_equal(op.truediv(p2, s), p1) + assert_raises(TypeError, op.truediv, s, p2) + for stype in [complex]: + s = stype(5, 0) + assert_poly_almost_equal(op.truediv(p2, s), p1) + assert_raises(TypeError, op.truediv, s, p2) + for s in [tuple(), list(), dict(), bool(), np.array([1])]: + assert_raises(TypeError, op.truediv, p2, s) + assert_raises(TypeError, op.truediv, s, p2) + for ptype in classes: + assert_raises(TypeError, op.truediv, p2, ptype(1)) + + +def check_mod(Poly): + # This checks commutation, not numerical correctness + c1 = list(random((4,)) + .5) + c2 = list(random((3,)) + .5) + c3 = list(random((2,)) + .5) + p1 = Poly(c1) + p2 = Poly(c2) + p3 = Poly(c3) + p4 = p1 * p2 + p3 + c4 = list(p4.coef) + assert_poly_almost_equal(p4 % p2, p3) + assert_poly_almost_equal(p4 % c2, p3) + assert_poly_almost_equal(c4 % p2, p3) + assert_poly_almost_equal(p4 % tuple(c2), p3) + assert_poly_almost_equal(tuple(c4) % p2, p3) + assert_poly_almost_equal(p4 % np.array(c2), p3) + assert_poly_almost_equal(np.array(c4) % p2, p3) + assert_poly_almost_equal(2 % p2, Poly([2])) + assert_poly_almost_equal(p2 % 2, Poly([0])) + assert_raises(TypeError, op.mod, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, op.mod, p1, Poly([0], window=Poly.window + 1)) + if Poly is Polynomial: + assert_raises(TypeError, op.mod, p1, Chebyshev([0])) + else: + assert_raises(TypeError, op.mod, p1, Polynomial([0])) + + +def check_divmod(Poly): + # This checks commutation, not numerical correctness + c1 = list(random((4,)) + .5) + c2 = list(random((3,)) + .5) + c3 = list(random((2,)) + .5) + p1 = Poly(c1) + p2 = Poly(c2) + p3 = Poly(c3) + p4 = p1 * p2 + p3 + c4 = list(p4.coef) + quo, rem = divmod(p4, p2) + assert_poly_almost_equal(quo, p1) + assert_poly_almost_equal(rem, p3) + quo, rem = divmod(p4, c2) + assert_poly_almost_equal(quo, p1) + assert_poly_almost_equal(rem, p3) + quo, rem = divmod(c4, p2) + assert_poly_almost_equal(quo, p1) + assert_poly_almost_equal(rem, p3) + quo, rem = divmod(p4, tuple(c2)) + assert_poly_almost_equal(quo, p1) + assert_poly_almost_equal(rem, p3) + quo, rem = divmod(tuple(c4), p2) + assert_poly_almost_equal(quo, p1) + assert_poly_almost_equal(rem, p3) + quo, rem = divmod(p4, np.array(c2)) + assert_poly_almost_equal(quo, p1) + assert_poly_almost_equal(rem, p3) + quo, rem = divmod(np.array(c4), p2) + assert_poly_almost_equal(quo, p1) + assert_poly_almost_equal(rem, p3) + quo, rem = divmod(p2, 2) + assert_poly_almost_equal(quo, 0.5*p2) + assert_poly_almost_equal(rem, Poly([0])) + quo, rem = divmod(2, p2) + assert_poly_almost_equal(quo, Poly([0])) + assert_poly_almost_equal(rem, Poly([2])) + assert_raises(TypeError, divmod, p1, Poly([0], domain=Poly.domain + 1)) + assert_raises(TypeError, divmod, p1, Poly([0], window=Poly.window + 1)) + if Poly is Polynomial: + assert_raises(TypeError, divmod, p1, Chebyshev([0])) + else: + assert_raises(TypeError, divmod, p1, Polynomial([0])) + + +def check_roots(Poly): + d = Poly.domain + random((2,))*.25 + w = Poly.window + random((2,))*.25 + tgt = np.sort(random((5,))) + res = np.sort(Poly.fromroots(tgt, domain=d, window=w).roots()) + assert_almost_equal(res, tgt) + # default domain and window + res = np.sort(Poly.fromroots(tgt).roots()) + assert_almost_equal(res, tgt) + + +def check_degree(Poly): + p = Poly.basis(5) + assert_equal(p.degree(), 5) + + +def check_copy(Poly): + p1 = Poly.basis(5) + p2 = p1.copy() + assert_(p1 == p2) + assert_(p1 is not p2) + assert_(p1.coef is not p2.coef) + assert_(p1.domain is not p2.domain) + assert_(p1.window is not p2.window) + + +def check_integ(Poly): + P = Polynomial + # Check defaults + p0 = Poly.cast(P([1*2, 2*3, 3*4])) + p1 = P.cast(p0.integ()) + p2 = P.cast(p0.integ(2)) + assert_poly_almost_equal(p1, P([0, 2, 3, 4])) + assert_poly_almost_equal(p2, P([0, 0, 1, 1, 1])) + # Check with k + p0 = Poly.cast(P([1*2, 2*3, 3*4])) + p1 = P.cast(p0.integ(k=1)) + p2 = P.cast(p0.integ(2, k=[1, 1])) + assert_poly_almost_equal(p1, P([1, 2, 3, 4])) + assert_poly_almost_equal(p2, P([1, 1, 1, 1, 1])) + # Check with lbnd + p0 = Poly.cast(P([1*2, 2*3, 3*4])) + p1 = P.cast(p0.integ(lbnd=1)) + p2 = P.cast(p0.integ(2, lbnd=1)) + assert_poly_almost_equal(p1, P([-9, 2, 3, 4])) + assert_poly_almost_equal(p2, P([6, -9, 1, 1, 1])) + # Check scaling + d = 2*Poly.domain + p0 = Poly.cast(P([1*2, 2*3, 3*4]), domain=d) + p1 = P.cast(p0.integ()) + p2 = P.cast(p0.integ(2)) + assert_poly_almost_equal(p1, P([0, 2, 3, 4])) + assert_poly_almost_equal(p2, P([0, 0, 1, 1, 1])) + + +def check_deriv(Poly): + # Check that the derivative is the inverse of integration. It is + # assumes that the integration has been checked elsewhere. + d = Poly.domain + random((2,))*.25 + w = Poly.window + random((2,))*.25 + p1 = Poly([1, 2, 3], domain=d, window=w) + p2 = p1.integ(2, k=[1, 2]) + p3 = p1.integ(1, k=[1]) + assert_almost_equal(p2.deriv(1).coef, p3.coef) + assert_almost_equal(p2.deriv(2).coef, p1.coef) + # default domain and window + p1 = Poly([1, 2, 3]) + p2 = p1.integ(2, k=[1, 2]) + p3 = p1.integ(1, k=[1]) + assert_almost_equal(p2.deriv(1).coef, p3.coef) + assert_almost_equal(p2.deriv(2).coef, p1.coef) + + +def check_linspace(Poly): + d = Poly.domain + random((2,))*.25 + w = Poly.window + random((2,))*.25 + p = Poly([1, 2, 3], domain=d, window=w) + # check default domain + xtgt = np.linspace(d[0], d[1], 20) + ytgt = p(xtgt) + xres, yres = p.linspace(20) + assert_almost_equal(xres, xtgt) + assert_almost_equal(yres, ytgt) + # check specified domain + xtgt = np.linspace(0, 2, 20) + ytgt = p(xtgt) + xres, yres = p.linspace(20, domain=[0, 2]) + assert_almost_equal(xres, xtgt) + assert_almost_equal(yres, ytgt) + + +def check_pow(Poly): + d = Poly.domain + random((2,))*.25 + w = Poly.window + random((2,))*.25 + tgt = Poly([1], domain=d, window=w) + tst = Poly([1, 2, 3], domain=d, window=w) + for i in range(5): + assert_poly_almost_equal(tst**i, tgt) + tgt = tgt * tst + # default domain and window + tgt = Poly([1]) + tst = Poly([1, 2, 3]) + for i in range(5): + assert_poly_almost_equal(tst**i, tgt) + tgt = tgt * tst + # check error for invalid powers + assert_raises(ValueError, op.pow, tgt, 1.5) + assert_raises(ValueError, op.pow, tgt, -1) + + +def check_call(Poly): + P = Polynomial + d = Poly.domain + x = np.linspace(d[0], d[1], 11) + + # Check defaults + p = Poly.cast(P([1, 2, 3])) + tgt = 1 + x*(2 + 3*x) + res = p(x) + assert_almost_equal(res, tgt) + + +def check_cutdeg(Poly): + p = Poly([1, 2, 3]) + assert_raises(ValueError, p.cutdeg, .5) + assert_raises(ValueError, p.cutdeg, -1) + assert_equal(len(p.cutdeg(3)), 3) + assert_equal(len(p.cutdeg(2)), 3) + assert_equal(len(p.cutdeg(1)), 2) + assert_equal(len(p.cutdeg(0)), 1) + + +def check_truncate(Poly): + p = Poly([1, 2, 3]) + assert_raises(ValueError, p.truncate, .5) + assert_raises(ValueError, p.truncate, 0) + assert_equal(len(p.truncate(4)), 3) + assert_equal(len(p.truncate(3)), 3) + assert_equal(len(p.truncate(2)), 2) + assert_equal(len(p.truncate(1)), 1) + + +def check_trim(Poly): + c = [1, 1e-6, 1e-12, 0] + p = Poly(c) + assert_equal(p.trim().coef, c[:3]) + assert_equal(p.trim(1e-10).coef, c[:2]) + assert_equal(p.trim(1e-5).coef, c[:1]) + + +def check_mapparms(Poly): + # check with defaults. Should be identity. + d = Poly.domain + w = Poly.window + p = Poly([1], domain=d, window=w) + assert_almost_equal([0, 1], p.mapparms()) + # + w = 2*d + 1 + p = Poly([1], domain=d, window=w) + assert_almost_equal([1, 2], p.mapparms()) + + +def check_ufunc_override(Poly): + p = Poly([1, 2, 3]) + x = np.ones(3) + assert_raises(TypeError, np.add, p, x) + assert_raises(TypeError, np.add, x, p) + + +class TestInterpolate(object): + + def f(self, x): + return x * (x - 1) * (x - 2) + + def test_raises(self): + assert_raises(ValueError, Chebyshev.interpolate, self.f, -1) + assert_raises(TypeError, Chebyshev.interpolate, self.f, 10.) + + def test_dimensions(self): + for deg in range(1, 5): + assert_(Chebyshev.interpolate(self.f, deg).degree() == deg) + + def test_approximation(self): + + def powx(x, p): + return x**p + + x = np.linspace(0, 2, 10) + for deg in range(0, 10): + for t in range(0, deg + 1): + p = Chebyshev.interpolate(powx, deg, domain=[0, 2], args=(t,)) + assert_almost_equal(p(x), powx(x, t), decimal=12) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/polynomial/tests/test_hermite.py b/numpy/polynomial/tests/test_hermite.py new file mode 100644 index 0000000..08b0a88 --- /dev/null +++ b/numpy/polynomial/tests/test_hermite.py @@ -0,0 +1,551 @@ +"""Tests for hermite module. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +import numpy.polynomial.hermite as herm +from numpy.polynomial.polynomial import polyval +from numpy.testing import ( + assert_almost_equal, assert_raises, assert_equal, assert_, + run_module_suite + ) + +H0 = np.array([1]) +H1 = np.array([0, 2]) +H2 = np.array([-2, 0, 4]) +H3 = np.array([0, -12, 0, 8]) +H4 = np.array([12, 0, -48, 0, 16]) +H5 = np.array([0, 120, 0, -160, 0, 32]) +H6 = np.array([-120, 0, 720, 0, -480, 0, 64]) +H7 = np.array([0, -1680, 0, 3360, 0, -1344, 0, 128]) +H8 = np.array([1680, 0, -13440, 0, 13440, 0, -3584, 0, 256]) +H9 = np.array([0, 30240, 0, -80640, 0, 48384, 0, -9216, 0, 512]) + +Hlist = [H0, H1, H2, H3, H4, H5, H6, H7, H8, H9] + + +def trim(x): + return herm.hermtrim(x, tol=1e-6) + + +class TestConstants(object): + + def test_hermdomain(self): + assert_equal(herm.hermdomain, [-1, 1]) + + def test_hermzero(self): + assert_equal(herm.hermzero, [0]) + + def test_hermone(self): + assert_equal(herm.hermone, [1]) + + def test_hermx(self): + assert_equal(herm.hermx, [0, .5]) + + +class TestArithmetic(object): + x = np.linspace(-3, 3, 100) + + def test_hermadd(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] += 1 + res = herm.hermadd([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_hermsub(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] -= 1 + res = herm.hermsub([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_hermmulx(self): + assert_equal(herm.hermmulx([0]), [0]) + assert_equal(herm.hermmulx([1]), [0, .5]) + for i in range(1, 5): + ser = [0]*i + [1] + tgt = [0]*(i - 1) + [i, 0, .5] + assert_equal(herm.hermmulx(ser), tgt) + + def test_hermmul(self): + # check values of result + for i in range(5): + pol1 = [0]*i + [1] + val1 = herm.hermval(self.x, pol1) + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + pol2 = [0]*j + [1] + val2 = herm.hermval(self.x, pol2) + pol3 = herm.hermmul(pol1, pol2) + val3 = herm.hermval(self.x, pol3) + assert_(len(pol3) == i + j + 1, msg) + assert_almost_equal(val3, val1*val2, err_msg=msg) + + def test_hermdiv(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + ci = [0]*i + [1] + cj = [0]*j + [1] + tgt = herm.hermadd(ci, cj) + quo, rem = herm.hermdiv(tgt, ci) + res = herm.hermadd(herm.hermmul(quo, ci), rem) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + +class TestEvaluation(object): + # coefficients of 1 + 2*x + 3*x**2 + c1d = np.array([2.5, 1., .75]) + c2d = np.einsum('i,j->ij', c1d, c1d) + c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d) + + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + y = polyval(x, [1., 2., 3.]) + + def test_hermval(self): + #check empty input + assert_equal(herm.hermval([], [1]).size, 0) + + #check normal input) + x = np.linspace(-1, 1) + y = [polyval(x, c) for c in Hlist] + for i in range(10): + msg = "At i=%d" % i + tgt = y[i] + res = herm.hermval(x, [0]*i + [1]) + assert_almost_equal(res, tgt, err_msg=msg) + + #check that shape is preserved + for i in range(3): + dims = [2]*i + x = np.zeros(dims) + assert_equal(herm.hermval(x, [1]).shape, dims) + assert_equal(herm.hermval(x, [1, 0]).shape, dims) + assert_equal(herm.hermval(x, [1, 0, 0]).shape, dims) + + def test_hermval2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, herm.hermval2d, x1, x2[:2], self.c2d) + + #test values + tgt = y1*y2 + res = herm.hermval2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = herm.hermval2d(z, z, self.c2d) + assert_(res.shape == (2, 3)) + + def test_hermval3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, herm.hermval3d, x1, x2, x3[:2], self.c3d) + + #test values + tgt = y1*y2*y3 + res = herm.hermval3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = herm.hermval3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)) + + def test_hermgrid2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j->ij', y1, y2) + res = herm.hermgrid2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = herm.hermgrid2d(z, z, self.c2d) + assert_(res.shape == (2, 3)*2) + + def test_hermgrid3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j,k->ijk', y1, y2, y3) + res = herm.hermgrid3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = herm.hermgrid3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)*3) + + +class TestIntegral(object): + + def test_hermint(self): + # check exceptions + assert_raises(ValueError, herm.hermint, [0], .5) + assert_raises(ValueError, herm.hermint, [0], -1) + assert_raises(ValueError, herm.hermint, [0], 1, [0, 0]) + assert_raises(ValueError, herm.hermint, [0], lbnd=[0]) + assert_raises(ValueError, herm.hermint, [0], scl=[0]) + assert_raises(ValueError, herm.hermint, [0], axis=.5) + + # test integration of zero polynomial + for i in range(2, 5): + k = [0]*(i - 2) + [1] + res = herm.hermint([0], m=i, k=k) + assert_almost_equal(res, [0, .5]) + + # check single integration with integration constant + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [1/scl] + hermpol = herm.poly2herm(pol) + hermint = herm.hermint(hermpol, m=1, k=[i]) + res = herm.herm2poly(hermint) + assert_almost_equal(trim(res), trim(tgt)) + + # check single integration with integration constant and lbnd + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + hermpol = herm.poly2herm(pol) + hermint = herm.hermint(hermpol, m=1, k=[i], lbnd=-1) + assert_almost_equal(herm.hermval(-1, hermint), i) + + # check single integration with integration constant and scaling + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [2/scl] + hermpol = herm.poly2herm(pol) + hermint = herm.hermint(hermpol, m=1, k=[i], scl=2) + res = herm.herm2poly(hermint) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with default k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = herm.hermint(tgt, m=1) + res = herm.hermint(pol, m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with defined k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = herm.hermint(tgt, m=1, k=[k]) + res = herm.hermint(pol, m=j, k=list(range(j))) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with lbnd + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = herm.hermint(tgt, m=1, k=[k], lbnd=-1) + res = herm.hermint(pol, m=j, k=list(range(j)), lbnd=-1) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with scaling + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = herm.hermint(tgt, m=1, k=[k], scl=2) + res = herm.hermint(pol, m=j, k=list(range(j)), scl=2) + assert_almost_equal(trim(res), trim(tgt)) + + def test_hermint_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([herm.hermint(c) for c in c2d.T]).T + res = herm.hermint(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([herm.hermint(c) for c in c2d]) + res = herm.hermint(c2d, axis=1) + assert_almost_equal(res, tgt) + + tgt = np.vstack([herm.hermint(c, k=3) for c in c2d]) + res = herm.hermint(c2d, k=3, axis=1) + assert_almost_equal(res, tgt) + + +class TestDerivative(object): + + def test_hermder(self): + # check exceptions + assert_raises(ValueError, herm.hermder, [0], .5) + assert_raises(ValueError, herm.hermder, [0], -1) + + # check that zeroth derivative does nothing + for i in range(5): + tgt = [0]*i + [1] + res = herm.hermder(tgt, m=0) + assert_equal(trim(res), trim(tgt)) + + # check that derivation is the inverse of integration + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = herm.hermder(herm.hermint(tgt, m=j), m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check derivation with scaling + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = herm.hermder(herm.hermint(tgt, m=j, scl=2), m=j, scl=.5) + assert_almost_equal(trim(res), trim(tgt)) + + def test_hermder_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([herm.hermder(c) for c in c2d.T]).T + res = herm.hermder(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([herm.hermder(c) for c in c2d]) + res = herm.hermder(c2d, axis=1) + assert_almost_equal(res, tgt) + + +class TestVander(object): + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + + def test_hermvander(self): + # check for 1d x + x = np.arange(3) + v = herm.hermvander(x, 3) + assert_(v.shape == (3, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], herm.hermval(x, coef)) + + # check for 2d x + x = np.array([[1, 2], [3, 4], [5, 6]]) + v = herm.hermvander(x, 3) + assert_(v.shape == (3, 2, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], herm.hermval(x, coef)) + + def test_hermvander2d(self): + # also tests hermval2d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3)) + van = herm.hermvander2d(x1, x2, [1, 2]) + tgt = herm.hermval2d(x1, x2, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = herm.hermvander2d([x1], [x2], [1, 2]) + assert_(van.shape == (1, 5, 6)) + + def test_hermvander3d(self): + # also tests hermval3d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3, 4)) + van = herm.hermvander3d(x1, x2, x3, [1, 2, 3]) + tgt = herm.hermval3d(x1, x2, x3, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = herm.hermvander3d([x1], [x2], [x3], [1, 2, 3]) + assert_(van.shape == (1, 5, 24)) + + +class TestFitting(object): + + def test_hermfit(self): + def f(x): + return x*(x - 1)*(x - 2) + + def f2(x): + return x**4 + x**2 + 1 + + # Test exceptions + assert_raises(ValueError, herm.hermfit, [1], [1], -1) + assert_raises(TypeError, herm.hermfit, [[1]], [1], 0) + assert_raises(TypeError, herm.hermfit, [], [1], 0) + assert_raises(TypeError, herm.hermfit, [1], [[[1]]], 0) + assert_raises(TypeError, herm.hermfit, [1, 2], [1], 0) + assert_raises(TypeError, herm.hermfit, [1], [1, 2], 0) + assert_raises(TypeError, herm.hermfit, [1], [1], 0, w=[[1]]) + assert_raises(TypeError, herm.hermfit, [1], [1], 0, w=[1, 1]) + assert_raises(ValueError, herm.hermfit, [1], [1], [-1,]) + assert_raises(ValueError, herm.hermfit, [1], [1], [2, -1, 6]) + assert_raises(TypeError, herm.hermfit, [1], [1], []) + + # Test fit + x = np.linspace(0, 2) + y = f(x) + # + coef3 = herm.hermfit(x, y, 3) + assert_equal(len(coef3), 4) + assert_almost_equal(herm.hermval(x, coef3), y) + coef3 = herm.hermfit(x, y, [0, 1, 2, 3]) + assert_equal(len(coef3), 4) + assert_almost_equal(herm.hermval(x, coef3), y) + # + coef4 = herm.hermfit(x, y, 4) + assert_equal(len(coef4), 5) + assert_almost_equal(herm.hermval(x, coef4), y) + coef4 = herm.hermfit(x, y, [0, 1, 2, 3, 4]) + assert_equal(len(coef4), 5) + assert_almost_equal(herm.hermval(x, coef4), y) + # check things still work if deg is not in strict increasing + coef4 = herm.hermfit(x, y, [2, 3, 4, 1, 0]) + assert_equal(len(coef4), 5) + assert_almost_equal(herm.hermval(x, coef4), y) + # + coef2d = herm.hermfit(x, np.array([y, y]).T, 3) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + coef2d = herm.hermfit(x, np.array([y, y]).T, [0, 1, 2, 3]) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + # test weighting + w = np.zeros_like(x) + yw = y.copy() + w[1::2] = 1 + y[0::2] = 0 + wcoef3 = herm.hermfit(x, yw, 3, w=w) + assert_almost_equal(wcoef3, coef3) + wcoef3 = herm.hermfit(x, yw, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef3, coef3) + # + wcoef2d = herm.hermfit(x, np.array([yw, yw]).T, 3, w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + wcoef2d = herm.hermfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + # test scaling with complex values x points whose square + # is zero when summed. + x = [1, 1j, -1, -1j] + assert_almost_equal(herm.hermfit(x, x, 1), [0, .5]) + assert_almost_equal(herm.hermfit(x, x, [0, 1]), [0, .5]) + # test fitting only even Legendre polynomials + x = np.linspace(-1, 1) + y = f2(x) + coef1 = herm.hermfit(x, y, 4) + assert_almost_equal(herm.hermval(x, coef1), y) + coef2 = herm.hermfit(x, y, [0, 2, 4]) + assert_almost_equal(herm.hermval(x, coef2), y) + assert_almost_equal(coef1, coef2) + + +class TestCompanion(object): + + def test_raises(self): + assert_raises(ValueError, herm.hermcompanion, []) + assert_raises(ValueError, herm.hermcompanion, [1]) + + def test_dimensions(self): + for i in range(1, 5): + coef = [0]*i + [1] + assert_(herm.hermcompanion(coef).shape == (i, i)) + + def test_linear_root(self): + assert_(herm.hermcompanion([1, 2])[0, 0] == -.25) + + +class TestGauss(object): + + def test_100(self): + x, w = herm.hermgauss(100) + + # test orthogonality. Note that the results need to be normalized, + # otherwise the huge values that can arise from fast growing + # functions like Laguerre can be very confusing. + v = herm.hermvander(x, 99) + vv = np.dot(v.T * w, v) + vd = 1/np.sqrt(vv.diagonal()) + vv = vd[:, None] * vv * vd + assert_almost_equal(vv, np.eye(100)) + + # check that the integral of 1 is correct + tgt = np.sqrt(np.pi) + assert_almost_equal(w.sum(), tgt) + + +class TestMisc(object): + + def test_hermfromroots(self): + res = herm.hermfromroots([]) + assert_almost_equal(trim(res), [1]) + for i in range(1, 5): + roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2]) + pol = herm.hermfromroots(roots) + res = herm.hermval(roots, pol) + tgt = 0 + assert_(len(pol) == i + 1) + assert_almost_equal(herm.herm2poly(pol)[-1], 1) + assert_almost_equal(res, tgt) + + def test_hermroots(self): + assert_almost_equal(herm.hermroots([1]), []) + assert_almost_equal(herm.hermroots([1, 1]), [-.5]) + for i in range(2, 5): + tgt = np.linspace(-1, 1, i) + res = herm.hermroots(herm.hermfromroots(tgt)) + assert_almost_equal(trim(res), trim(tgt)) + + def test_hermtrim(self): + coef = [2, -1, 1, 0] + + # Test exceptions + assert_raises(ValueError, herm.hermtrim, coef, -1) + + # Test results + assert_equal(herm.hermtrim(coef), coef[:-1]) + assert_equal(herm.hermtrim(coef, 1), coef[:-3]) + assert_equal(herm.hermtrim(coef, 2), [0]) + + def test_hermline(self): + assert_equal(herm.hermline(3, 4), [3, 2]) + + def test_herm2poly(self): + for i in range(10): + assert_almost_equal(herm.herm2poly([0]*i + [1]), Hlist[i]) + + def test_poly2herm(self): + for i in range(10): + assert_almost_equal(herm.poly2herm(Hlist[i]), [0]*i + [1]) + + def test_weight(self): + x = np.linspace(-5, 5, 11) + tgt = np.exp(-x**2) + res = herm.hermweight(x) + assert_almost_equal(res, tgt) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/polynomial/tests/test_hermite_e.py b/numpy/polynomial/tests/test_hermite_e.py new file mode 100644 index 0000000..ab05a2a --- /dev/null +++ b/numpy/polynomial/tests/test_hermite_e.py @@ -0,0 +1,552 @@ +"""Tests for hermite_e module. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +import numpy.polynomial.hermite_e as herme +from numpy.polynomial.polynomial import polyval +from numpy.testing import ( + assert_almost_equal, assert_raises, assert_equal, assert_, + run_module_suite + ) + +He0 = np.array([1]) +He1 = np.array([0, 1]) +He2 = np.array([-1, 0, 1]) +He3 = np.array([0, -3, 0, 1]) +He4 = np.array([3, 0, -6, 0, 1]) +He5 = np.array([0, 15, 0, -10, 0, 1]) +He6 = np.array([-15, 0, 45, 0, -15, 0, 1]) +He7 = np.array([0, -105, 0, 105, 0, -21, 0, 1]) +He8 = np.array([105, 0, -420, 0, 210, 0, -28, 0, 1]) +He9 = np.array([0, 945, 0, -1260, 0, 378, 0, -36, 0, 1]) + +Helist = [He0, He1, He2, He3, He4, He5, He6, He7, He8, He9] + + +def trim(x): + return herme.hermetrim(x, tol=1e-6) + + +class TestConstants(object): + + def test_hermedomain(self): + assert_equal(herme.hermedomain, [-1, 1]) + + def test_hermezero(self): + assert_equal(herme.hermezero, [0]) + + def test_hermeone(self): + assert_equal(herme.hermeone, [1]) + + def test_hermex(self): + assert_equal(herme.hermex, [0, 1]) + + +class TestArithmetic(object): + x = np.linspace(-3, 3, 100) + + def test_hermeadd(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] += 1 + res = herme.hermeadd([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_hermesub(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] -= 1 + res = herme.hermesub([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_hermemulx(self): + assert_equal(herme.hermemulx([0]), [0]) + assert_equal(herme.hermemulx([1]), [0, 1]) + for i in range(1, 5): + ser = [0]*i + [1] + tgt = [0]*(i - 1) + [i, 0, 1] + assert_equal(herme.hermemulx(ser), tgt) + + def test_hermemul(self): + # check values of result + for i in range(5): + pol1 = [0]*i + [1] + val1 = herme.hermeval(self.x, pol1) + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + pol2 = [0]*j + [1] + val2 = herme.hermeval(self.x, pol2) + pol3 = herme.hermemul(pol1, pol2) + val3 = herme.hermeval(self.x, pol3) + assert_(len(pol3) == i + j + 1, msg) + assert_almost_equal(val3, val1*val2, err_msg=msg) + + def test_hermediv(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + ci = [0]*i + [1] + cj = [0]*j + [1] + tgt = herme.hermeadd(ci, cj) + quo, rem = herme.hermediv(tgt, ci) + res = herme.hermeadd(herme.hermemul(quo, ci), rem) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + +class TestEvaluation(object): + # coefficients of 1 + 2*x + 3*x**2 + c1d = np.array([4., 2., 3.]) + c2d = np.einsum('i,j->ij', c1d, c1d) + c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d) + + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + y = polyval(x, [1., 2., 3.]) + + def test_hermeval(self): + #check empty input + assert_equal(herme.hermeval([], [1]).size, 0) + + #check normal input) + x = np.linspace(-1, 1) + y = [polyval(x, c) for c in Helist] + for i in range(10): + msg = "At i=%d" % i + tgt = y[i] + res = herme.hermeval(x, [0]*i + [1]) + assert_almost_equal(res, tgt, err_msg=msg) + + #check that shape is preserved + for i in range(3): + dims = [2]*i + x = np.zeros(dims) + assert_equal(herme.hermeval(x, [1]).shape, dims) + assert_equal(herme.hermeval(x, [1, 0]).shape, dims) + assert_equal(herme.hermeval(x, [1, 0, 0]).shape, dims) + + def test_hermeval2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, herme.hermeval2d, x1, x2[:2], self.c2d) + + #test values + tgt = y1*y2 + res = herme.hermeval2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = herme.hermeval2d(z, z, self.c2d) + assert_(res.shape == (2, 3)) + + def test_hermeval3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, herme.hermeval3d, x1, x2, x3[:2], self.c3d) + + #test values + tgt = y1*y2*y3 + res = herme.hermeval3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = herme.hermeval3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)) + + def test_hermegrid2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j->ij', y1, y2) + res = herme.hermegrid2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = herme.hermegrid2d(z, z, self.c2d) + assert_(res.shape == (2, 3)*2) + + def test_hermegrid3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j,k->ijk', y1, y2, y3) + res = herme.hermegrid3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = herme.hermegrid3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)*3) + + +class TestIntegral(object): + + def test_hermeint(self): + # check exceptions + assert_raises(ValueError, herme.hermeint, [0], .5) + assert_raises(ValueError, herme.hermeint, [0], -1) + assert_raises(ValueError, herme.hermeint, [0], 1, [0, 0]) + assert_raises(ValueError, herme.hermeint, [0], lbnd=[0]) + assert_raises(ValueError, herme.hermeint, [0], scl=[0]) + assert_raises(ValueError, herme.hermeint, [0], axis=.5) + + # test integration of zero polynomial + for i in range(2, 5): + k = [0]*(i - 2) + [1] + res = herme.hermeint([0], m=i, k=k) + assert_almost_equal(res, [0, 1]) + + # check single integration with integration constant + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [1/scl] + hermepol = herme.poly2herme(pol) + hermeint = herme.hermeint(hermepol, m=1, k=[i]) + res = herme.herme2poly(hermeint) + assert_almost_equal(trim(res), trim(tgt)) + + # check single integration with integration constant and lbnd + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + hermepol = herme.poly2herme(pol) + hermeint = herme.hermeint(hermepol, m=1, k=[i], lbnd=-1) + assert_almost_equal(herme.hermeval(-1, hermeint), i) + + # check single integration with integration constant and scaling + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [2/scl] + hermepol = herme.poly2herme(pol) + hermeint = herme.hermeint(hermepol, m=1, k=[i], scl=2) + res = herme.herme2poly(hermeint) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with default k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = herme.hermeint(tgt, m=1) + res = herme.hermeint(pol, m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with defined k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = herme.hermeint(tgt, m=1, k=[k]) + res = herme.hermeint(pol, m=j, k=list(range(j))) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with lbnd + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = herme.hermeint(tgt, m=1, k=[k], lbnd=-1) + res = herme.hermeint(pol, m=j, k=list(range(j)), lbnd=-1) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with scaling + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = herme.hermeint(tgt, m=1, k=[k], scl=2) + res = herme.hermeint(pol, m=j, k=list(range(j)), scl=2) + assert_almost_equal(trim(res), trim(tgt)) + + def test_hermeint_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([herme.hermeint(c) for c in c2d.T]).T + res = herme.hermeint(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([herme.hermeint(c) for c in c2d]) + res = herme.hermeint(c2d, axis=1) + assert_almost_equal(res, tgt) + + tgt = np.vstack([herme.hermeint(c, k=3) for c in c2d]) + res = herme.hermeint(c2d, k=3, axis=1) + assert_almost_equal(res, tgt) + + +class TestDerivative(object): + + def test_hermeder(self): + # check exceptions + assert_raises(ValueError, herme.hermeder, [0], .5) + assert_raises(ValueError, herme.hermeder, [0], -1) + + # check that zeroth derivative does nothing + for i in range(5): + tgt = [0]*i + [1] + res = herme.hermeder(tgt, m=0) + assert_equal(trim(res), trim(tgt)) + + # check that derivation is the inverse of integration + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = herme.hermeder(herme.hermeint(tgt, m=j), m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check derivation with scaling + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = herme.hermeder( + herme.hermeint(tgt, m=j, scl=2), m=j, scl=.5) + assert_almost_equal(trim(res), trim(tgt)) + + def test_hermeder_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([herme.hermeder(c) for c in c2d.T]).T + res = herme.hermeder(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([herme.hermeder(c) for c in c2d]) + res = herme.hermeder(c2d, axis=1) + assert_almost_equal(res, tgt) + + +class TestVander(object): + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + + def test_hermevander(self): + # check for 1d x + x = np.arange(3) + v = herme.hermevander(x, 3) + assert_(v.shape == (3, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], herme.hermeval(x, coef)) + + # check for 2d x + x = np.array([[1, 2], [3, 4], [5, 6]]) + v = herme.hermevander(x, 3) + assert_(v.shape == (3, 2, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], herme.hermeval(x, coef)) + + def test_hermevander2d(self): + # also tests hermeval2d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3)) + van = herme.hermevander2d(x1, x2, [1, 2]) + tgt = herme.hermeval2d(x1, x2, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = herme.hermevander2d([x1], [x2], [1, 2]) + assert_(van.shape == (1, 5, 6)) + + def test_hermevander3d(self): + # also tests hermeval3d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3, 4)) + van = herme.hermevander3d(x1, x2, x3, [1, 2, 3]) + tgt = herme.hermeval3d(x1, x2, x3, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = herme.hermevander3d([x1], [x2], [x3], [1, 2, 3]) + assert_(van.shape == (1, 5, 24)) + + +class TestFitting(object): + + def test_hermefit(self): + def f(x): + return x*(x - 1)*(x - 2) + + def f2(x): + return x**4 + x**2 + 1 + + # Test exceptions + assert_raises(ValueError, herme.hermefit, [1], [1], -1) + assert_raises(TypeError, herme.hermefit, [[1]], [1], 0) + assert_raises(TypeError, herme.hermefit, [], [1], 0) + assert_raises(TypeError, herme.hermefit, [1], [[[1]]], 0) + assert_raises(TypeError, herme.hermefit, [1, 2], [1], 0) + assert_raises(TypeError, herme.hermefit, [1], [1, 2], 0) + assert_raises(TypeError, herme.hermefit, [1], [1], 0, w=[[1]]) + assert_raises(TypeError, herme.hermefit, [1], [1], 0, w=[1, 1]) + assert_raises(ValueError, herme.hermefit, [1], [1], [-1,]) + assert_raises(ValueError, herme.hermefit, [1], [1], [2, -1, 6]) + assert_raises(TypeError, herme.hermefit, [1], [1], []) + + # Test fit + x = np.linspace(0, 2) + y = f(x) + # + coef3 = herme.hermefit(x, y, 3) + assert_equal(len(coef3), 4) + assert_almost_equal(herme.hermeval(x, coef3), y) + coef3 = herme.hermefit(x, y, [0, 1, 2, 3]) + assert_equal(len(coef3), 4) + assert_almost_equal(herme.hermeval(x, coef3), y) + # + coef4 = herme.hermefit(x, y, 4) + assert_equal(len(coef4), 5) + assert_almost_equal(herme.hermeval(x, coef4), y) + coef4 = herme.hermefit(x, y, [0, 1, 2, 3, 4]) + assert_equal(len(coef4), 5) + assert_almost_equal(herme.hermeval(x, coef4), y) + # check things still work if deg is not in strict increasing + coef4 = herme.hermefit(x, y, [2, 3, 4, 1, 0]) + assert_equal(len(coef4), 5) + assert_almost_equal(herme.hermeval(x, coef4), y) + # + coef2d = herme.hermefit(x, np.array([y, y]).T, 3) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + coef2d = herme.hermefit(x, np.array([y, y]).T, [0, 1, 2, 3]) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + # test weighting + w = np.zeros_like(x) + yw = y.copy() + w[1::2] = 1 + y[0::2] = 0 + wcoef3 = herme.hermefit(x, yw, 3, w=w) + assert_almost_equal(wcoef3, coef3) + wcoef3 = herme.hermefit(x, yw, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef3, coef3) + # + wcoef2d = herme.hermefit(x, np.array([yw, yw]).T, 3, w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + wcoef2d = herme.hermefit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + # test scaling with complex values x points whose square + # is zero when summed. + x = [1, 1j, -1, -1j] + assert_almost_equal(herme.hermefit(x, x, 1), [0, 1]) + assert_almost_equal(herme.hermefit(x, x, [0, 1]), [0, 1]) + # test fitting only even Legendre polynomials + x = np.linspace(-1, 1) + y = f2(x) + coef1 = herme.hermefit(x, y, 4) + assert_almost_equal(herme.hermeval(x, coef1), y) + coef2 = herme.hermefit(x, y, [0, 2, 4]) + assert_almost_equal(herme.hermeval(x, coef2), y) + assert_almost_equal(coef1, coef2) + + +class TestCompanion(object): + + def test_raises(self): + assert_raises(ValueError, herme.hermecompanion, []) + assert_raises(ValueError, herme.hermecompanion, [1]) + + def test_dimensions(self): + for i in range(1, 5): + coef = [0]*i + [1] + assert_(herme.hermecompanion(coef).shape == (i, i)) + + def test_linear_root(self): + assert_(herme.hermecompanion([1, 2])[0, 0] == -.5) + + +class TestGauss(object): + + def test_100(self): + x, w = herme.hermegauss(100) + + # test orthogonality. Note that the results need to be normalized, + # otherwise the huge values that can arise from fast growing + # functions like Laguerre can be very confusing. + v = herme.hermevander(x, 99) + vv = np.dot(v.T * w, v) + vd = 1/np.sqrt(vv.diagonal()) + vv = vd[:, None] * vv * vd + assert_almost_equal(vv, np.eye(100)) + + # check that the integral of 1 is correct + tgt = np.sqrt(2*np.pi) + assert_almost_equal(w.sum(), tgt) + + +class TestMisc(object): + + def test_hermefromroots(self): + res = herme.hermefromroots([]) + assert_almost_equal(trim(res), [1]) + for i in range(1, 5): + roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2]) + pol = herme.hermefromroots(roots) + res = herme.hermeval(roots, pol) + tgt = 0 + assert_(len(pol) == i + 1) + assert_almost_equal(herme.herme2poly(pol)[-1], 1) + assert_almost_equal(res, tgt) + + def test_hermeroots(self): + assert_almost_equal(herme.hermeroots([1]), []) + assert_almost_equal(herme.hermeroots([1, 1]), [-1]) + for i in range(2, 5): + tgt = np.linspace(-1, 1, i) + res = herme.hermeroots(herme.hermefromroots(tgt)) + assert_almost_equal(trim(res), trim(tgt)) + + def test_hermetrim(self): + coef = [2, -1, 1, 0] + + # Test exceptions + assert_raises(ValueError, herme.hermetrim, coef, -1) + + # Test results + assert_equal(herme.hermetrim(coef), coef[:-1]) + assert_equal(herme.hermetrim(coef, 1), coef[:-3]) + assert_equal(herme.hermetrim(coef, 2), [0]) + + def test_hermeline(self): + assert_equal(herme.hermeline(3, 4), [3, 4]) + + def test_herme2poly(self): + for i in range(10): + assert_almost_equal(herme.herme2poly([0]*i + [1]), Helist[i]) + + def test_poly2herme(self): + for i in range(10): + assert_almost_equal(herme.poly2herme(Helist[i]), [0]*i + [1]) + + def test_weight(self): + x = np.linspace(-5, 5, 11) + tgt = np.exp(-.5*x**2) + res = herme.hermeweight(x) + assert_almost_equal(res, tgt) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/polynomial/tests/test_laguerre.py b/numpy/polynomial/tests/test_laguerre.py new file mode 100644 index 0000000..c6b01ff --- /dev/null +++ b/numpy/polynomial/tests/test_laguerre.py @@ -0,0 +1,533 @@ +"""Tests for laguerre module. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +import numpy.polynomial.laguerre as lag +from numpy.polynomial.polynomial import polyval +from numpy.testing import ( + assert_almost_equal, assert_raises, assert_equal, assert_, + run_module_suite + ) + +L0 = np.array([1])/1 +L1 = np.array([1, -1])/1 +L2 = np.array([2, -4, 1])/2 +L3 = np.array([6, -18, 9, -1])/6 +L4 = np.array([24, -96, 72, -16, 1])/24 +L5 = np.array([120, -600, 600, -200, 25, -1])/120 +L6 = np.array([720, -4320, 5400, -2400, 450, -36, 1])/720 + +Llist = [L0, L1, L2, L3, L4, L5, L6] + + +def trim(x): + return lag.lagtrim(x, tol=1e-6) + + +class TestConstants(object): + + def test_lagdomain(self): + assert_equal(lag.lagdomain, [0, 1]) + + def test_lagzero(self): + assert_equal(lag.lagzero, [0]) + + def test_lagone(self): + assert_equal(lag.lagone, [1]) + + def test_lagx(self): + assert_equal(lag.lagx, [1, -1]) + + +class TestArithmetic(object): + x = np.linspace(-3, 3, 100) + + def test_lagadd(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] += 1 + res = lag.lagadd([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_lagsub(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] -= 1 + res = lag.lagsub([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_lagmulx(self): + assert_equal(lag.lagmulx([0]), [0]) + assert_equal(lag.lagmulx([1]), [1, -1]) + for i in range(1, 5): + ser = [0]*i + [1] + tgt = [0]*(i - 1) + [-i, 2*i + 1, -(i + 1)] + assert_almost_equal(lag.lagmulx(ser), tgt) + + def test_lagmul(self): + # check values of result + for i in range(5): + pol1 = [0]*i + [1] + val1 = lag.lagval(self.x, pol1) + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + pol2 = [0]*j + [1] + val2 = lag.lagval(self.x, pol2) + pol3 = lag.lagmul(pol1, pol2) + val3 = lag.lagval(self.x, pol3) + assert_(len(pol3) == i + j + 1, msg) + assert_almost_equal(val3, val1*val2, err_msg=msg) + + def test_lagdiv(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + ci = [0]*i + [1] + cj = [0]*j + [1] + tgt = lag.lagadd(ci, cj) + quo, rem = lag.lagdiv(tgt, ci) + res = lag.lagadd(lag.lagmul(quo, ci), rem) + assert_almost_equal(trim(res), trim(tgt), err_msg=msg) + + +class TestEvaluation(object): + # coefficients of 1 + 2*x + 3*x**2 + c1d = np.array([9., -14., 6.]) + c2d = np.einsum('i,j->ij', c1d, c1d) + c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d) + + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + y = polyval(x, [1., 2., 3.]) + + def test_lagval(self): + #check empty input + assert_equal(lag.lagval([], [1]).size, 0) + + #check normal input) + x = np.linspace(-1, 1) + y = [polyval(x, c) for c in Llist] + for i in range(7): + msg = "At i=%d" % i + tgt = y[i] + res = lag.lagval(x, [0]*i + [1]) + assert_almost_equal(res, tgt, err_msg=msg) + + #check that shape is preserved + for i in range(3): + dims = [2]*i + x = np.zeros(dims) + assert_equal(lag.lagval(x, [1]).shape, dims) + assert_equal(lag.lagval(x, [1, 0]).shape, dims) + assert_equal(lag.lagval(x, [1, 0, 0]).shape, dims) + + def test_lagval2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, lag.lagval2d, x1, x2[:2], self.c2d) + + #test values + tgt = y1*y2 + res = lag.lagval2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = lag.lagval2d(z, z, self.c2d) + assert_(res.shape == (2, 3)) + + def test_lagval3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, lag.lagval3d, x1, x2, x3[:2], self.c3d) + + #test values + tgt = y1*y2*y3 + res = lag.lagval3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = lag.lagval3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)) + + def test_laggrid2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j->ij', y1, y2) + res = lag.laggrid2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = lag.laggrid2d(z, z, self.c2d) + assert_(res.shape == (2, 3)*2) + + def test_laggrid3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j,k->ijk', y1, y2, y3) + res = lag.laggrid3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = lag.laggrid3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)*3) + + +class TestIntegral(object): + + def test_lagint(self): + # check exceptions + assert_raises(ValueError, lag.lagint, [0], .5) + assert_raises(ValueError, lag.lagint, [0], -1) + assert_raises(ValueError, lag.lagint, [0], 1, [0, 0]) + assert_raises(ValueError, lag.lagint, [0], lbnd=[0]) + assert_raises(ValueError, lag.lagint, [0], scl=[0]) + assert_raises(ValueError, lag.lagint, [0], axis=.5) + + # test integration of zero polynomial + for i in range(2, 5): + k = [0]*(i - 2) + [1] + res = lag.lagint([0], m=i, k=k) + assert_almost_equal(res, [1, -1]) + + # check single integration with integration constant + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [1/scl] + lagpol = lag.poly2lag(pol) + lagint = lag.lagint(lagpol, m=1, k=[i]) + res = lag.lag2poly(lagint) + assert_almost_equal(trim(res), trim(tgt)) + + # check single integration with integration constant and lbnd + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + lagpol = lag.poly2lag(pol) + lagint = lag.lagint(lagpol, m=1, k=[i], lbnd=-1) + assert_almost_equal(lag.lagval(-1, lagint), i) + + # check single integration with integration constant and scaling + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [2/scl] + lagpol = lag.poly2lag(pol) + lagint = lag.lagint(lagpol, m=1, k=[i], scl=2) + res = lag.lag2poly(lagint) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with default k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = lag.lagint(tgt, m=1) + res = lag.lagint(pol, m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with defined k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = lag.lagint(tgt, m=1, k=[k]) + res = lag.lagint(pol, m=j, k=list(range(j))) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with lbnd + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = lag.lagint(tgt, m=1, k=[k], lbnd=-1) + res = lag.lagint(pol, m=j, k=list(range(j)), lbnd=-1) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with scaling + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = lag.lagint(tgt, m=1, k=[k], scl=2) + res = lag.lagint(pol, m=j, k=list(range(j)), scl=2) + assert_almost_equal(trim(res), trim(tgt)) + + def test_lagint_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([lag.lagint(c) for c in c2d.T]).T + res = lag.lagint(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([lag.lagint(c) for c in c2d]) + res = lag.lagint(c2d, axis=1) + assert_almost_equal(res, tgt) + + tgt = np.vstack([lag.lagint(c, k=3) for c in c2d]) + res = lag.lagint(c2d, k=3, axis=1) + assert_almost_equal(res, tgt) + + +class TestDerivative(object): + + def test_lagder(self): + # check exceptions + assert_raises(ValueError, lag.lagder, [0], .5) + assert_raises(ValueError, lag.lagder, [0], -1) + + # check that zeroth derivative does nothing + for i in range(5): + tgt = [0]*i + [1] + res = lag.lagder(tgt, m=0) + assert_equal(trim(res), trim(tgt)) + + # check that derivation is the inverse of integration + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = lag.lagder(lag.lagint(tgt, m=j), m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check derivation with scaling + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = lag.lagder(lag.lagint(tgt, m=j, scl=2), m=j, scl=.5) + assert_almost_equal(trim(res), trim(tgt)) + + def test_lagder_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([lag.lagder(c) for c in c2d.T]).T + res = lag.lagder(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([lag.lagder(c) for c in c2d]) + res = lag.lagder(c2d, axis=1) + assert_almost_equal(res, tgt) + + +class TestVander(object): + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + + def test_lagvander(self): + # check for 1d x + x = np.arange(3) + v = lag.lagvander(x, 3) + assert_(v.shape == (3, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], lag.lagval(x, coef)) + + # check for 2d x + x = np.array([[1, 2], [3, 4], [5, 6]]) + v = lag.lagvander(x, 3) + assert_(v.shape == (3, 2, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], lag.lagval(x, coef)) + + def test_lagvander2d(self): + # also tests lagval2d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3)) + van = lag.lagvander2d(x1, x2, [1, 2]) + tgt = lag.lagval2d(x1, x2, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = lag.lagvander2d([x1], [x2], [1, 2]) + assert_(van.shape == (1, 5, 6)) + + def test_lagvander3d(self): + # also tests lagval3d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3, 4)) + van = lag.lagvander3d(x1, x2, x3, [1, 2, 3]) + tgt = lag.lagval3d(x1, x2, x3, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = lag.lagvander3d([x1], [x2], [x3], [1, 2, 3]) + assert_(van.shape == (1, 5, 24)) + + +class TestFitting(object): + + def test_lagfit(self): + def f(x): + return x*(x - 1)*(x - 2) + + # Test exceptions + assert_raises(ValueError, lag.lagfit, [1], [1], -1) + assert_raises(TypeError, lag.lagfit, [[1]], [1], 0) + assert_raises(TypeError, lag.lagfit, [], [1], 0) + assert_raises(TypeError, lag.lagfit, [1], [[[1]]], 0) + assert_raises(TypeError, lag.lagfit, [1, 2], [1], 0) + assert_raises(TypeError, lag.lagfit, [1], [1, 2], 0) + assert_raises(TypeError, lag.lagfit, [1], [1], 0, w=[[1]]) + assert_raises(TypeError, lag.lagfit, [1], [1], 0, w=[1, 1]) + assert_raises(ValueError, lag.lagfit, [1], [1], [-1,]) + assert_raises(ValueError, lag.lagfit, [1], [1], [2, -1, 6]) + assert_raises(TypeError, lag.lagfit, [1], [1], []) + + # Test fit + x = np.linspace(0, 2) + y = f(x) + # + coef3 = lag.lagfit(x, y, 3) + assert_equal(len(coef3), 4) + assert_almost_equal(lag.lagval(x, coef3), y) + coef3 = lag.lagfit(x, y, [0, 1, 2, 3]) + assert_equal(len(coef3), 4) + assert_almost_equal(lag.lagval(x, coef3), y) + # + coef4 = lag.lagfit(x, y, 4) + assert_equal(len(coef4), 5) + assert_almost_equal(lag.lagval(x, coef4), y) + coef4 = lag.lagfit(x, y, [0, 1, 2, 3, 4]) + assert_equal(len(coef4), 5) + assert_almost_equal(lag.lagval(x, coef4), y) + # + coef2d = lag.lagfit(x, np.array([y, y]).T, 3) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + coef2d = lag.lagfit(x, np.array([y, y]).T, [0, 1, 2, 3]) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + # test weighting + w = np.zeros_like(x) + yw = y.copy() + w[1::2] = 1 + y[0::2] = 0 + wcoef3 = lag.lagfit(x, yw, 3, w=w) + assert_almost_equal(wcoef3, coef3) + wcoef3 = lag.lagfit(x, yw, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef3, coef3) + # + wcoef2d = lag.lagfit(x, np.array([yw, yw]).T, 3, w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + wcoef2d = lag.lagfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + # test scaling with complex values x points whose square + # is zero when summed. + x = [1, 1j, -1, -1j] + assert_almost_equal(lag.lagfit(x, x, 1), [1, -1]) + assert_almost_equal(lag.lagfit(x, x, [0, 1]), [1, -1]) + + +class TestCompanion(object): + + def test_raises(self): + assert_raises(ValueError, lag.lagcompanion, []) + assert_raises(ValueError, lag.lagcompanion, [1]) + + def test_dimensions(self): + for i in range(1, 5): + coef = [0]*i + [1] + assert_(lag.lagcompanion(coef).shape == (i, i)) + + def test_linear_root(self): + assert_(lag.lagcompanion([1, 2])[0, 0] == 1.5) + + +class TestGauss(object): + + def test_100(self): + x, w = lag.laggauss(100) + + # test orthogonality. Note that the results need to be normalized, + # otherwise the huge values that can arise from fast growing + # functions like Laguerre can be very confusing. + v = lag.lagvander(x, 99) + vv = np.dot(v.T * w, v) + vd = 1/np.sqrt(vv.diagonal()) + vv = vd[:, None] * vv * vd + assert_almost_equal(vv, np.eye(100)) + + # check that the integral of 1 is correct + tgt = 1.0 + assert_almost_equal(w.sum(), tgt) + + +class TestMisc(object): + + def test_lagfromroots(self): + res = lag.lagfromroots([]) + assert_almost_equal(trim(res), [1]) + for i in range(1, 5): + roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2]) + pol = lag.lagfromroots(roots) + res = lag.lagval(roots, pol) + tgt = 0 + assert_(len(pol) == i + 1) + assert_almost_equal(lag.lag2poly(pol)[-1], 1) + assert_almost_equal(res, tgt) + + def test_lagroots(self): + assert_almost_equal(lag.lagroots([1]), []) + assert_almost_equal(lag.lagroots([0, 1]), [1]) + for i in range(2, 5): + tgt = np.linspace(0, 3, i) + res = lag.lagroots(lag.lagfromroots(tgt)) + assert_almost_equal(trim(res), trim(tgt)) + + def test_lagtrim(self): + coef = [2, -1, 1, 0] + + # Test exceptions + assert_raises(ValueError, lag.lagtrim, coef, -1) + + # Test results + assert_equal(lag.lagtrim(coef), coef[:-1]) + assert_equal(lag.lagtrim(coef, 1), coef[:-3]) + assert_equal(lag.lagtrim(coef, 2), [0]) + + def test_lagline(self): + assert_equal(lag.lagline(3, 4), [7, -4]) + + def test_lag2poly(self): + for i in range(7): + assert_almost_equal(lag.lag2poly([0]*i + [1]), Llist[i]) + + def test_poly2lag(self): + for i in range(7): + assert_almost_equal(lag.poly2lag(Llist[i]), [0]*i + [1]) + + def test_weight(self): + x = np.linspace(0, 10, 11) + tgt = np.exp(-x) + res = lag.lagweight(x) + assert_almost_equal(res, tgt) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/polynomial/tests/test_legendre.py b/numpy/polynomial/tests/test_legendre.py new file mode 100644 index 0000000..8547c90 --- /dev/null +++ b/numpy/polynomial/tests/test_legendre.py @@ -0,0 +1,552 @@ +"""Tests for legendre module. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +import numpy.polynomial.legendre as leg +from numpy.polynomial.polynomial import polyval +from numpy.testing import ( + assert_almost_equal, assert_raises, assert_equal, assert_, + run_module_suite + ) + +L0 = np.array([1]) +L1 = np.array([0, 1]) +L2 = np.array([-1, 0, 3])/2 +L3 = np.array([0, -3, 0, 5])/2 +L4 = np.array([3, 0, -30, 0, 35])/8 +L5 = np.array([0, 15, 0, -70, 0, 63])/8 +L6 = np.array([-5, 0, 105, 0, -315, 0, 231])/16 +L7 = np.array([0, -35, 0, 315, 0, -693, 0, 429])/16 +L8 = np.array([35, 0, -1260, 0, 6930, 0, -12012, 0, 6435])/128 +L9 = np.array([0, 315, 0, -4620, 0, 18018, 0, -25740, 0, 12155])/128 + +Llist = [L0, L1, L2, L3, L4, L5, L6, L7, L8, L9] + + +def trim(x): + return leg.legtrim(x, tol=1e-6) + + +class TestConstants(object): + + def test_legdomain(self): + assert_equal(leg.legdomain, [-1, 1]) + + def test_legzero(self): + assert_equal(leg.legzero, [0]) + + def test_legone(self): + assert_equal(leg.legone, [1]) + + def test_legx(self): + assert_equal(leg.legx, [0, 1]) + + +class TestArithmetic(object): + x = np.linspace(-1, 1, 100) + + def test_legadd(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] += 1 + res = leg.legadd([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_legsub(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] -= 1 + res = leg.legsub([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_legmulx(self): + assert_equal(leg.legmulx([0]), [0]) + assert_equal(leg.legmulx([1]), [0, 1]) + for i in range(1, 5): + tmp = 2*i + 1 + ser = [0]*i + [1] + tgt = [0]*(i - 1) + [i/tmp, 0, (i + 1)/tmp] + assert_equal(leg.legmulx(ser), tgt) + + def test_legmul(self): + # check values of result + for i in range(5): + pol1 = [0]*i + [1] + val1 = leg.legval(self.x, pol1) + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + pol2 = [0]*j + [1] + val2 = leg.legval(self.x, pol2) + pol3 = leg.legmul(pol1, pol2) + val3 = leg.legval(self.x, pol3) + assert_(len(pol3) == i + j + 1, msg) + assert_almost_equal(val3, val1*val2, err_msg=msg) + + def test_legdiv(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + ci = [0]*i + [1] + cj = [0]*j + [1] + tgt = leg.legadd(ci, cj) + quo, rem = leg.legdiv(tgt, ci) + res = leg.legadd(leg.legmul(quo, ci), rem) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + +class TestEvaluation(object): + # coefficients of 1 + 2*x + 3*x**2 + c1d = np.array([2., 2., 2.]) + c2d = np.einsum('i,j->ij', c1d, c1d) + c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d) + + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + y = polyval(x, [1., 2., 3.]) + + def test_legval(self): + #check empty input + assert_equal(leg.legval([], [1]).size, 0) + + #check normal input) + x = np.linspace(-1, 1) + y = [polyval(x, c) for c in Llist] + for i in range(10): + msg = "At i=%d" % i + tgt = y[i] + res = leg.legval(x, [0]*i + [1]) + assert_almost_equal(res, tgt, err_msg=msg) + + #check that shape is preserved + for i in range(3): + dims = [2]*i + x = np.zeros(dims) + assert_equal(leg.legval(x, [1]).shape, dims) + assert_equal(leg.legval(x, [1, 0]).shape, dims) + assert_equal(leg.legval(x, [1, 0, 0]).shape, dims) + + def test_legval2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, leg.legval2d, x1, x2[:2], self.c2d) + + #test values + tgt = y1*y2 + res = leg.legval2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = leg.legval2d(z, z, self.c2d) + assert_(res.shape == (2, 3)) + + def test_legval3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, leg.legval3d, x1, x2, x3[:2], self.c3d) + + #test values + tgt = y1*y2*y3 + res = leg.legval3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = leg.legval3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)) + + def test_leggrid2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j->ij', y1, y2) + res = leg.leggrid2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = leg.leggrid2d(z, z, self.c2d) + assert_(res.shape == (2, 3)*2) + + def test_leggrid3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j,k->ijk', y1, y2, y3) + res = leg.leggrid3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = leg.leggrid3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)*3) + + +class TestIntegral(object): + + def test_legint(self): + # check exceptions + assert_raises(ValueError, leg.legint, [0], .5) + assert_raises(ValueError, leg.legint, [0], -1) + assert_raises(ValueError, leg.legint, [0], 1, [0, 0]) + assert_raises(ValueError, leg.legint, [0], lbnd=[0]) + assert_raises(ValueError, leg.legint, [0], scl=[0]) + assert_raises(ValueError, leg.legint, [0], axis=.5) + + # test integration of zero polynomial + for i in range(2, 5): + k = [0]*(i - 2) + [1] + res = leg.legint([0], m=i, k=k) + assert_almost_equal(res, [0, 1]) + + # check single integration with integration constant + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [1/scl] + legpol = leg.poly2leg(pol) + legint = leg.legint(legpol, m=1, k=[i]) + res = leg.leg2poly(legint) + assert_almost_equal(trim(res), trim(tgt)) + + # check single integration with integration constant and lbnd + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + legpol = leg.poly2leg(pol) + legint = leg.legint(legpol, m=1, k=[i], lbnd=-1) + assert_almost_equal(leg.legval(-1, legint), i) + + # check single integration with integration constant and scaling + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [2/scl] + legpol = leg.poly2leg(pol) + legint = leg.legint(legpol, m=1, k=[i], scl=2) + res = leg.leg2poly(legint) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with default k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = leg.legint(tgt, m=1) + res = leg.legint(pol, m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with defined k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = leg.legint(tgt, m=1, k=[k]) + res = leg.legint(pol, m=j, k=list(range(j))) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with lbnd + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = leg.legint(tgt, m=1, k=[k], lbnd=-1) + res = leg.legint(pol, m=j, k=list(range(j)), lbnd=-1) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with scaling + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = leg.legint(tgt, m=1, k=[k], scl=2) + res = leg.legint(pol, m=j, k=list(range(j)), scl=2) + assert_almost_equal(trim(res), trim(tgt)) + + def test_legint_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([leg.legint(c) for c in c2d.T]).T + res = leg.legint(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([leg.legint(c) for c in c2d]) + res = leg.legint(c2d, axis=1) + assert_almost_equal(res, tgt) + + tgt = np.vstack([leg.legint(c, k=3) for c in c2d]) + res = leg.legint(c2d, k=3, axis=1) + assert_almost_equal(res, tgt) + + +class TestDerivative(object): + + def test_legder(self): + # check exceptions + assert_raises(ValueError, leg.legder, [0], .5) + assert_raises(ValueError, leg.legder, [0], -1) + + # check that zeroth derivative does nothing + for i in range(5): + tgt = [0]*i + [1] + res = leg.legder(tgt, m=0) + assert_equal(trim(res), trim(tgt)) + + # check that derivation is the inverse of integration + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = leg.legder(leg.legint(tgt, m=j), m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check derivation with scaling + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = leg.legder(leg.legint(tgt, m=j, scl=2), m=j, scl=.5) + assert_almost_equal(trim(res), trim(tgt)) + + def test_legder_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([leg.legder(c) for c in c2d.T]).T + res = leg.legder(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([leg.legder(c) for c in c2d]) + res = leg.legder(c2d, axis=1) + assert_almost_equal(res, tgt) + + +class TestVander(object): + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + + def test_legvander(self): + # check for 1d x + x = np.arange(3) + v = leg.legvander(x, 3) + assert_(v.shape == (3, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], leg.legval(x, coef)) + + # check for 2d x + x = np.array([[1, 2], [3, 4], [5, 6]]) + v = leg.legvander(x, 3) + assert_(v.shape == (3, 2, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], leg.legval(x, coef)) + + def test_legvander2d(self): + # also tests polyval2d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3)) + van = leg.legvander2d(x1, x2, [1, 2]) + tgt = leg.legval2d(x1, x2, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = leg.legvander2d([x1], [x2], [1, 2]) + assert_(van.shape == (1, 5, 6)) + + def test_legvander3d(self): + # also tests polyval3d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3, 4)) + van = leg.legvander3d(x1, x2, x3, [1, 2, 3]) + tgt = leg.legval3d(x1, x2, x3, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = leg.legvander3d([x1], [x2], [x3], [1, 2, 3]) + assert_(van.shape == (1, 5, 24)) + + +class TestFitting(object): + + def test_legfit(self): + def f(x): + return x*(x - 1)*(x - 2) + + def f2(x): + return x**4 + x**2 + 1 + + # Test exceptions + assert_raises(ValueError, leg.legfit, [1], [1], -1) + assert_raises(TypeError, leg.legfit, [[1]], [1], 0) + assert_raises(TypeError, leg.legfit, [], [1], 0) + assert_raises(TypeError, leg.legfit, [1], [[[1]]], 0) + assert_raises(TypeError, leg.legfit, [1, 2], [1], 0) + assert_raises(TypeError, leg.legfit, [1], [1, 2], 0) + assert_raises(TypeError, leg.legfit, [1], [1], 0, w=[[1]]) + assert_raises(TypeError, leg.legfit, [1], [1], 0, w=[1, 1]) + assert_raises(ValueError, leg.legfit, [1], [1], [-1,]) + assert_raises(ValueError, leg.legfit, [1], [1], [2, -1, 6]) + assert_raises(TypeError, leg.legfit, [1], [1], []) + + # Test fit + x = np.linspace(0, 2) + y = f(x) + # + coef3 = leg.legfit(x, y, 3) + assert_equal(len(coef3), 4) + assert_almost_equal(leg.legval(x, coef3), y) + coef3 = leg.legfit(x, y, [0, 1, 2, 3]) + assert_equal(len(coef3), 4) + assert_almost_equal(leg.legval(x, coef3), y) + # + coef4 = leg.legfit(x, y, 4) + assert_equal(len(coef4), 5) + assert_almost_equal(leg.legval(x, coef4), y) + coef4 = leg.legfit(x, y, [0, 1, 2, 3, 4]) + assert_equal(len(coef4), 5) + assert_almost_equal(leg.legval(x, coef4), y) + # check things still work if deg is not in strict increasing + coef4 = leg.legfit(x, y, [2, 3, 4, 1, 0]) + assert_equal(len(coef4), 5) + assert_almost_equal(leg.legval(x, coef4), y) + # + coef2d = leg.legfit(x, np.array([y, y]).T, 3) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + coef2d = leg.legfit(x, np.array([y, y]).T, [0, 1, 2, 3]) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + # test weighting + w = np.zeros_like(x) + yw = y.copy() + w[1::2] = 1 + y[0::2] = 0 + wcoef3 = leg.legfit(x, yw, 3, w=w) + assert_almost_equal(wcoef3, coef3) + wcoef3 = leg.legfit(x, yw, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef3, coef3) + # + wcoef2d = leg.legfit(x, np.array([yw, yw]).T, 3, w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + wcoef2d = leg.legfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + # test scaling with complex values x points whose square + # is zero when summed. + x = [1, 1j, -1, -1j] + assert_almost_equal(leg.legfit(x, x, 1), [0, 1]) + assert_almost_equal(leg.legfit(x, x, [0, 1]), [0, 1]) + # test fitting only even Legendre polynomials + x = np.linspace(-1, 1) + y = f2(x) + coef1 = leg.legfit(x, y, 4) + assert_almost_equal(leg.legval(x, coef1), y) + coef2 = leg.legfit(x, y, [0, 2, 4]) + assert_almost_equal(leg.legval(x, coef2), y) + assert_almost_equal(coef1, coef2) + + +class TestCompanion(object): + + def test_raises(self): + assert_raises(ValueError, leg.legcompanion, []) + assert_raises(ValueError, leg.legcompanion, [1]) + + def test_dimensions(self): + for i in range(1, 5): + coef = [0]*i + [1] + assert_(leg.legcompanion(coef).shape == (i, i)) + + def test_linear_root(self): + assert_(leg.legcompanion([1, 2])[0, 0] == -.5) + + +class TestGauss(object): + + def test_100(self): + x, w = leg.leggauss(100) + + # test orthogonality. Note that the results need to be normalized, + # otherwise the huge values that can arise from fast growing + # functions like Laguerre can be very confusing. + v = leg.legvander(x, 99) + vv = np.dot(v.T * w, v) + vd = 1/np.sqrt(vv.diagonal()) + vv = vd[:, None] * vv * vd + assert_almost_equal(vv, np.eye(100)) + + # check that the integral of 1 is correct + tgt = 2.0 + assert_almost_equal(w.sum(), tgt) + + +class TestMisc(object): + + def test_legfromroots(self): + res = leg.legfromroots([]) + assert_almost_equal(trim(res), [1]) + for i in range(1, 5): + roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2]) + pol = leg.legfromroots(roots) + res = leg.legval(roots, pol) + tgt = 0 + assert_(len(pol) == i + 1) + assert_almost_equal(leg.leg2poly(pol)[-1], 1) + assert_almost_equal(res, tgt) + + def test_legroots(self): + assert_almost_equal(leg.legroots([1]), []) + assert_almost_equal(leg.legroots([1, 2]), [-.5]) + for i in range(2, 5): + tgt = np.linspace(-1, 1, i) + res = leg.legroots(leg.legfromroots(tgt)) + assert_almost_equal(trim(res), trim(tgt)) + + def test_legtrim(self): + coef = [2, -1, 1, 0] + + # Test exceptions + assert_raises(ValueError, leg.legtrim, coef, -1) + + # Test results + assert_equal(leg.legtrim(coef), coef[:-1]) + assert_equal(leg.legtrim(coef, 1), coef[:-3]) + assert_equal(leg.legtrim(coef, 2), [0]) + + def test_legline(self): + assert_equal(leg.legline(3, 4), [3, 4]) + + def test_leg2poly(self): + for i in range(10): + assert_almost_equal(leg.leg2poly([0]*i + [1]), Llist[i]) + + def test_poly2leg(self): + for i in range(10): + assert_almost_equal(leg.poly2leg(Llist[i]), [0]*i + [1]) + + def test_weight(self): + x = np.linspace(-1, 1, 11) + tgt = 1. + res = leg.legweight(x) + assert_almost_equal(res, tgt) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/polynomial/tests/test_polynomial.py b/numpy/polynomial/tests/test_polynomial.py new file mode 100644 index 0000000..370fbd6 --- /dev/null +++ b/numpy/polynomial/tests/test_polynomial.py @@ -0,0 +1,572 @@ +"""Tests for polynomial module. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +import numpy.polynomial.polynomial as poly +from numpy.testing import ( + assert_almost_equal, assert_raises, assert_equal, assert_, + run_module_suite + ) + + +def trim(x): + return poly.polytrim(x, tol=1e-6) + +T0 = [1] +T1 = [0, 1] +T2 = [-1, 0, 2] +T3 = [0, -3, 0, 4] +T4 = [1, 0, -8, 0, 8] +T5 = [0, 5, 0, -20, 0, 16] +T6 = [-1, 0, 18, 0, -48, 0, 32] +T7 = [0, -7, 0, 56, 0, -112, 0, 64] +T8 = [1, 0, -32, 0, 160, 0, -256, 0, 128] +T9 = [0, 9, 0, -120, 0, 432, 0, -576, 0, 256] + +Tlist = [T0, T1, T2, T3, T4, T5, T6, T7, T8, T9] + + +class TestConstants(object): + + def test_polydomain(self): + assert_equal(poly.polydomain, [-1, 1]) + + def test_polyzero(self): + assert_equal(poly.polyzero, [0]) + + def test_polyone(self): + assert_equal(poly.polyone, [1]) + + def test_polyx(self): + assert_equal(poly.polyx, [0, 1]) + + +class TestArithmetic(object): + + def test_polyadd(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] += 1 + res = poly.polyadd([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_polysub(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(max(i, j) + 1) + tgt[i] += 1 + tgt[j] -= 1 + res = poly.polysub([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_polymulx(self): + assert_equal(poly.polymulx([0]), [0]) + assert_equal(poly.polymulx([1]), [0, 1]) + for i in range(1, 5): + ser = [0]*i + [1] + tgt = [0]*(i + 1) + [1] + assert_equal(poly.polymulx(ser), tgt) + + def test_polymul(self): + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + tgt = np.zeros(i + j + 1) + tgt[i + j] += 1 + res = poly.polymul([0]*i + [1], [0]*j + [1]) + assert_equal(trim(res), trim(tgt), err_msg=msg) + + def test_polydiv(self): + # check zero division + assert_raises(ZeroDivisionError, poly.polydiv, [1], [0]) + + # check scalar division + quo, rem = poly.polydiv([2], [2]) + assert_equal((quo, rem), (1, 0)) + quo, rem = poly.polydiv([2, 2], [2]) + assert_equal((quo, rem), ((1, 1), 0)) + + # check rest. + for i in range(5): + for j in range(5): + msg = "At i=%d, j=%d" % (i, j) + ci = [0]*i + [1, 2] + cj = [0]*j + [1, 2] + tgt = poly.polyadd(ci, cj) + quo, rem = poly.polydiv(tgt, ci) + res = poly.polyadd(poly.polymul(quo, ci), rem) + assert_equal(res, tgt, err_msg=msg) + + +class TestEvaluation(object): + # coefficients of 1 + 2*x + 3*x**2 + c1d = np.array([1., 2., 3.]) + c2d = np.einsum('i,j->ij', c1d, c1d) + c3d = np.einsum('i,j,k->ijk', c1d, c1d, c1d) + + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + y = poly.polyval(x, [1., 2., 3.]) + + def test_polyval(self): + #check empty input + assert_equal(poly.polyval([], [1]).size, 0) + + #check normal input) + x = np.linspace(-1, 1) + y = [x**i for i in range(5)] + for i in range(5): + tgt = y[i] + res = poly.polyval(x, [0]*i + [1]) + assert_almost_equal(res, tgt) + tgt = x*(x**2 - 1) + res = poly.polyval(x, [0, -1, 0, 1]) + assert_almost_equal(res, tgt) + + #check that shape is preserved + for i in range(3): + dims = [2]*i + x = np.zeros(dims) + assert_equal(poly.polyval(x, [1]).shape, dims) + assert_equal(poly.polyval(x, [1, 0]).shape, dims) + assert_equal(poly.polyval(x, [1, 0, 0]).shape, dims) + + def test_polyvalfromroots(self): + # check exception for broadcasting x values over root array with + # too few dimensions + assert_raises(ValueError, poly.polyvalfromroots, + [1], [1], tensor=False) + + # check empty input + assert_equal(poly.polyvalfromroots([], [1]).size, 0) + assert_(poly.polyvalfromroots([], [1]).shape == (0,)) + + # check empty input + multidimensional roots + assert_equal(poly.polyvalfromroots([], [[1] * 5]).size, 0) + assert_(poly.polyvalfromroots([], [[1] * 5]).shape == (5, 0)) + + # check scalar input + assert_equal(poly.polyvalfromroots(1, 1), 0) + assert_(poly.polyvalfromroots(1, np.ones((3, 3))).shape == (3,)) + + # check normal input) + x = np.linspace(-1, 1) + y = [x**i for i in range(5)] + for i in range(1, 5): + tgt = y[i] + res = poly.polyvalfromroots(x, [0]*i) + assert_almost_equal(res, tgt) + tgt = x*(x - 1)*(x + 1) + res = poly.polyvalfromroots(x, [-1, 0, 1]) + assert_almost_equal(res, tgt) + + # check that shape is preserved + for i in range(3): + dims = [2]*i + x = np.zeros(dims) + assert_equal(poly.polyvalfromroots(x, [1]).shape, dims) + assert_equal(poly.polyvalfromroots(x, [1, 0]).shape, dims) + assert_equal(poly.polyvalfromroots(x, [1, 0, 0]).shape, dims) + + # check compatibility with factorization + ptest = [15, 2, -16, -2, 1] + r = poly.polyroots(ptest) + x = np.linspace(-1, 1) + assert_almost_equal(poly.polyval(x, ptest), + poly.polyvalfromroots(x, r)) + + # check multidimensional arrays of roots and values + # check tensor=False + rshape = (3, 5) + x = np.arange(-3, 2) + r = np.random.randint(-5, 5, size=rshape) + res = poly.polyvalfromroots(x, r, tensor=False) + tgt = np.empty(r.shape[1:]) + for ii in range(tgt.size): + tgt[ii] = poly.polyvalfromroots(x[ii], r[:, ii]) + assert_equal(res, tgt) + + # check tensor=True + x = np.vstack([x, 2*x]) + res = poly.polyvalfromroots(x, r, tensor=True) + tgt = np.empty(r.shape[1:] + x.shape) + for ii in range(r.shape[1]): + for jj in range(x.shape[0]): + tgt[ii, jj, :] = poly.polyvalfromroots(x[jj], r[:, ii]) + assert_equal(res, tgt) + + def test_polyval2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, poly.polyval2d, x1, x2[:2], self.c2d) + + #test values + tgt = y1*y2 + res = poly.polyval2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = poly.polyval2d(z, z, self.c2d) + assert_(res.shape == (2, 3)) + + def test_polyval3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test exceptions + assert_raises(ValueError, poly.polyval3d, x1, x2, x3[:2], self.c3d) + + #test values + tgt = y1*y2*y3 + res = poly.polyval3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = poly.polyval3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)) + + def test_polygrid2d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j->ij', y1, y2) + res = poly.polygrid2d(x1, x2, self.c2d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = poly.polygrid2d(z, z, self.c2d) + assert_(res.shape == (2, 3)*2) + + def test_polygrid3d(self): + x1, x2, x3 = self.x + y1, y2, y3 = self.y + + #test values + tgt = np.einsum('i,j,k->ijk', y1, y2, y3) + res = poly.polygrid3d(x1, x2, x3, self.c3d) + assert_almost_equal(res, tgt) + + #test shape + z = np.ones((2, 3)) + res = poly.polygrid3d(z, z, z, self.c3d) + assert_(res.shape == (2, 3)*3) + + +class TestIntegral(object): + + def test_polyint(self): + # check exceptions + assert_raises(ValueError, poly.polyint, [0], .5) + assert_raises(ValueError, poly.polyint, [0], -1) + assert_raises(ValueError, poly.polyint, [0], 1, [0, 0]) + assert_raises(ValueError, poly.polyint, [0], lbnd=[0]) + assert_raises(ValueError, poly.polyint, [0], scl=[0]) + assert_raises(ValueError, poly.polyint, [0], axis=.5) + + # test integration of zero polynomial + for i in range(2, 5): + k = [0]*(i - 2) + [1] + res = poly.polyint([0], m=i, k=k) + assert_almost_equal(res, [0, 1]) + + # check single integration with integration constant + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [1/scl] + res = poly.polyint(pol, m=1, k=[i]) + assert_almost_equal(trim(res), trim(tgt)) + + # check single integration with integration constant and lbnd + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + res = poly.polyint(pol, m=1, k=[i], lbnd=-1) + assert_almost_equal(poly.polyval(-1, res), i) + + # check single integration with integration constant and scaling + for i in range(5): + scl = i + 1 + pol = [0]*i + [1] + tgt = [i] + [0]*i + [2/scl] + res = poly.polyint(pol, m=1, k=[i], scl=2) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with default k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = poly.polyint(tgt, m=1) + res = poly.polyint(pol, m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with defined k + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = poly.polyint(tgt, m=1, k=[k]) + res = poly.polyint(pol, m=j, k=list(range(j))) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with lbnd + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = poly.polyint(tgt, m=1, k=[k], lbnd=-1) + res = poly.polyint(pol, m=j, k=list(range(j)), lbnd=-1) + assert_almost_equal(trim(res), trim(tgt)) + + # check multiple integrations with scaling + for i in range(5): + for j in range(2, 5): + pol = [0]*i + [1] + tgt = pol[:] + for k in range(j): + tgt = poly.polyint(tgt, m=1, k=[k], scl=2) + res = poly.polyint(pol, m=j, k=list(range(j)), scl=2) + assert_almost_equal(trim(res), trim(tgt)) + + def test_polyint_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([poly.polyint(c) for c in c2d.T]).T + res = poly.polyint(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([poly.polyint(c) for c in c2d]) + res = poly.polyint(c2d, axis=1) + assert_almost_equal(res, tgt) + + tgt = np.vstack([poly.polyint(c, k=3) for c in c2d]) + res = poly.polyint(c2d, k=3, axis=1) + assert_almost_equal(res, tgt) + + +class TestDerivative(object): + + def test_polyder(self): + # check exceptions + assert_raises(ValueError, poly.polyder, [0], .5) + assert_raises(ValueError, poly.polyder, [0], -1) + + # check that zeroth derivative does nothing + for i in range(5): + tgt = [0]*i + [1] + res = poly.polyder(tgt, m=0) + assert_equal(trim(res), trim(tgt)) + + # check that derivation is the inverse of integration + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = poly.polyder(poly.polyint(tgt, m=j), m=j) + assert_almost_equal(trim(res), trim(tgt)) + + # check derivation with scaling + for i in range(5): + for j in range(2, 5): + tgt = [0]*i + [1] + res = poly.polyder(poly.polyint(tgt, m=j, scl=2), m=j, scl=.5) + assert_almost_equal(trim(res), trim(tgt)) + + def test_polyder_axis(self): + # check that axis keyword works + c2d = np.random.random((3, 4)) + + tgt = np.vstack([poly.polyder(c) for c in c2d.T]).T + res = poly.polyder(c2d, axis=0) + assert_almost_equal(res, tgt) + + tgt = np.vstack([poly.polyder(c) for c in c2d]) + res = poly.polyder(c2d, axis=1) + assert_almost_equal(res, tgt) + + +class TestVander(object): + # some random values in [-1, 1) + x = np.random.random((3, 5))*2 - 1 + + def test_polyvander(self): + # check for 1d x + x = np.arange(3) + v = poly.polyvander(x, 3) + assert_(v.shape == (3, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], poly.polyval(x, coef)) + + # check for 2d x + x = np.array([[1, 2], [3, 4], [5, 6]]) + v = poly.polyvander(x, 3) + assert_(v.shape == (3, 2, 4)) + for i in range(4): + coef = [0]*i + [1] + assert_almost_equal(v[..., i], poly.polyval(x, coef)) + + def test_polyvander2d(self): + # also tests polyval2d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3)) + van = poly.polyvander2d(x1, x2, [1, 2]) + tgt = poly.polyval2d(x1, x2, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = poly.polyvander2d([x1], [x2], [1, 2]) + assert_(van.shape == (1, 5, 6)) + + def test_polyvander3d(self): + # also tests polyval3d for non-square coefficient array + x1, x2, x3 = self.x + c = np.random.random((2, 3, 4)) + van = poly.polyvander3d(x1, x2, x3, [1, 2, 3]) + tgt = poly.polyval3d(x1, x2, x3, c) + res = np.dot(van, c.flat) + assert_almost_equal(res, tgt) + + # check shape + van = poly.polyvander3d([x1], [x2], [x3], [1, 2, 3]) + assert_(van.shape == (1, 5, 24)) + + +class TestCompanion(object): + + def test_raises(self): + assert_raises(ValueError, poly.polycompanion, []) + assert_raises(ValueError, poly.polycompanion, [1]) + + def test_dimensions(self): + for i in range(1, 5): + coef = [0]*i + [1] + assert_(poly.polycompanion(coef).shape == (i, i)) + + def test_linear_root(self): + assert_(poly.polycompanion([1, 2])[0, 0] == -.5) + + +class TestMisc(object): + + def test_polyfromroots(self): + res = poly.polyfromroots([]) + assert_almost_equal(trim(res), [1]) + for i in range(1, 5): + roots = np.cos(np.linspace(-np.pi, 0, 2*i + 1)[1::2]) + tgt = Tlist[i] + res = poly.polyfromroots(roots)*2**(i-1) + assert_almost_equal(trim(res), trim(tgt)) + + def test_polyroots(self): + assert_almost_equal(poly.polyroots([1]), []) + assert_almost_equal(poly.polyroots([1, 2]), [-.5]) + for i in range(2, 5): + tgt = np.linspace(-1, 1, i) + res = poly.polyroots(poly.polyfromroots(tgt)) + assert_almost_equal(trim(res), trim(tgt)) + + def test_polyfit(self): + def f(x): + return x*(x - 1)*(x - 2) + + def f2(x): + return x**4 + x**2 + 1 + + # Test exceptions + assert_raises(ValueError, poly.polyfit, [1], [1], -1) + assert_raises(TypeError, poly.polyfit, [[1]], [1], 0) + assert_raises(TypeError, poly.polyfit, [], [1], 0) + assert_raises(TypeError, poly.polyfit, [1], [[[1]]], 0) + assert_raises(TypeError, poly.polyfit, [1, 2], [1], 0) + assert_raises(TypeError, poly.polyfit, [1], [1, 2], 0) + assert_raises(TypeError, poly.polyfit, [1], [1], 0, w=[[1]]) + assert_raises(TypeError, poly.polyfit, [1], [1], 0, w=[1, 1]) + assert_raises(ValueError, poly.polyfit, [1], [1], [-1,]) + assert_raises(ValueError, poly.polyfit, [1], [1], [2, -1, 6]) + assert_raises(TypeError, poly.polyfit, [1], [1], []) + + # Test fit + x = np.linspace(0, 2) + y = f(x) + # + coef3 = poly.polyfit(x, y, 3) + assert_equal(len(coef3), 4) + assert_almost_equal(poly.polyval(x, coef3), y) + coef3 = poly.polyfit(x, y, [0, 1, 2, 3]) + assert_equal(len(coef3), 4) + assert_almost_equal(poly.polyval(x, coef3), y) + # + coef4 = poly.polyfit(x, y, 4) + assert_equal(len(coef4), 5) + assert_almost_equal(poly.polyval(x, coef4), y) + coef4 = poly.polyfit(x, y, [0, 1, 2, 3, 4]) + assert_equal(len(coef4), 5) + assert_almost_equal(poly.polyval(x, coef4), y) + # + coef2d = poly.polyfit(x, np.array([y, y]).T, 3) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + coef2d = poly.polyfit(x, np.array([y, y]).T, [0, 1, 2, 3]) + assert_almost_equal(coef2d, np.array([coef3, coef3]).T) + # test weighting + w = np.zeros_like(x) + yw = y.copy() + w[1::2] = 1 + yw[0::2] = 0 + wcoef3 = poly.polyfit(x, yw, 3, w=w) + assert_almost_equal(wcoef3, coef3) + wcoef3 = poly.polyfit(x, yw, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef3, coef3) + # + wcoef2d = poly.polyfit(x, np.array([yw, yw]).T, 3, w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + wcoef2d = poly.polyfit(x, np.array([yw, yw]).T, [0, 1, 2, 3], w=w) + assert_almost_equal(wcoef2d, np.array([coef3, coef3]).T) + # test scaling with complex values x points whose square + # is zero when summed. + x = [1, 1j, -1, -1j] + assert_almost_equal(poly.polyfit(x, x, 1), [0, 1]) + assert_almost_equal(poly.polyfit(x, x, [0, 1]), [0, 1]) + # test fitting only even Polyendre polynomials + x = np.linspace(-1, 1) + y = f2(x) + coef1 = poly.polyfit(x, y, 4) + assert_almost_equal(poly.polyval(x, coef1), y) + coef2 = poly.polyfit(x, y, [0, 2, 4]) + assert_almost_equal(poly.polyval(x, coef2), y) + assert_almost_equal(coef1, coef2) + + def test_polytrim(self): + coef = [2, -1, 1, 0] + + # Test exceptions + assert_raises(ValueError, poly.polytrim, coef, -1) + + # Test results + assert_equal(poly.polytrim(coef), coef[:-1]) + assert_equal(poly.polytrim(coef, 1), coef[:-3]) + assert_equal(poly.polytrim(coef, 2), [0]) + + def test_polyline(self): + assert_equal(poly.polyline(3, 4), [3, 4]) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/polynomial/tests/test_polyutils.py b/numpy/polynomial/tests/test_polyutils.py new file mode 100644 index 0000000..bd1cb20 --- /dev/null +++ b/numpy/polynomial/tests/test_polyutils.py @@ -0,0 +1,110 @@ +"""Tests for polyutils module. + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np +import numpy.polynomial.polyutils as pu +from numpy.testing import ( + assert_almost_equal, assert_raises, assert_equal, assert_, + run_module_suite + ) + + +class TestMisc(object): + + def test_trimseq(self): + for i in range(5): + tgt = [1] + res = pu.trimseq([1] + [0]*5) + assert_equal(res, tgt) + + def test_as_series(self): + # check exceptions + assert_raises(ValueError, pu.as_series, [[]]) + assert_raises(ValueError, pu.as_series, [[[1, 2]]]) + assert_raises(ValueError, pu.as_series, [[1], ['a']]) + # check common types + types = ['i', 'd', 'O'] + for i in range(len(types)): + for j in range(i): + ci = np.ones(1, types[i]) + cj = np.ones(1, types[j]) + [resi, resj] = pu.as_series([ci, cj]) + assert_(resi.dtype.char == resj.dtype.char) + assert_(resj.dtype.char == types[i]) + + def test_trimcoef(self): + coef = [2, -1, 1, 0] + # Test exceptions + assert_raises(ValueError, pu.trimcoef, coef, -1) + # Test results + assert_equal(pu.trimcoef(coef), coef[:-1]) + assert_equal(pu.trimcoef(coef, 1), coef[:-3]) + assert_equal(pu.trimcoef(coef, 2), [0]) + + +class TestDomain(object): + + def test_getdomain(self): + # test for real values + x = [1, 10, 3, -1] + tgt = [-1, 10] + res = pu.getdomain(x) + assert_almost_equal(res, tgt) + + # test for complex values + x = [1 + 1j, 1 - 1j, 0, 2] + tgt = [-1j, 2 + 1j] + res = pu.getdomain(x) + assert_almost_equal(res, tgt) + + def test_mapdomain(self): + # test for real values + dom1 = [0, 4] + dom2 = [1, 3] + tgt = dom2 + res = pu. mapdomain(dom1, dom1, dom2) + assert_almost_equal(res, tgt) + + # test for complex values + dom1 = [0 - 1j, 2 + 1j] + dom2 = [-2, 2] + tgt = dom2 + x = dom1 + res = pu.mapdomain(x, dom1, dom2) + assert_almost_equal(res, tgt) + + # test for multidimensional arrays + dom1 = [0, 4] + dom2 = [1, 3] + tgt = np.array([dom2, dom2]) + x = np.array([dom1, dom1]) + res = pu.mapdomain(x, dom1, dom2) + assert_almost_equal(res, tgt) + + # test that subtypes are preserved. + dom1 = [0, 4] + dom2 = [1, 3] + x = np.matrix([dom1, dom1]) + res = pu.mapdomain(x, dom1, dom2) + assert_(isinstance(res, np.matrix)) + + def test_mapparms(self): + # test for real values + dom1 = [0, 4] + dom2 = [1, 3] + tgt = [1, .5] + res = pu. mapparms(dom1, dom2) + assert_almost_equal(res, tgt) + + # test for complex values + dom1 = [0 - 1j, 2 + 1j] + dom2 = [-2, 2] + tgt = [-1 + 1j, 1 - 1j] + res = pu.mapparms(dom1, dom2) + assert_almost_equal(res, tgt) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/polynomial/tests/test_printing.py b/numpy/polynomial/tests/test_printing.py new file mode 100644 index 0000000..939d48a --- /dev/null +++ b/numpy/polynomial/tests/test_printing.py @@ -0,0 +1,74 @@ +from __future__ import division, absolute_import, print_function + +import numpy.polynomial as poly +from numpy.testing import run_module_suite, assert_equal + + +class TestStr(object): + def test_polynomial_str(self): + res = str(poly.Polynomial([0, 1])) + tgt = 'poly([0. 1.])' + assert_equal(res, tgt) + + def test_chebyshev_str(self): + res = str(poly.Chebyshev([0, 1])) + tgt = 'cheb([0. 1.])' + assert_equal(res, tgt) + + def test_legendre_str(self): + res = str(poly.Legendre([0, 1])) + tgt = 'leg([0. 1.])' + assert_equal(res, tgt) + + def test_hermite_str(self): + res = str(poly.Hermite([0, 1])) + tgt = 'herm([0. 1.])' + assert_equal(res, tgt) + + def test_hermiteE_str(self): + res = str(poly.HermiteE([0, 1])) + tgt = 'herme([0. 1.])' + assert_equal(res, tgt) + + def test_laguerre_str(self): + res = str(poly.Laguerre([0, 1])) + tgt = 'lag([0. 1.])' + assert_equal(res, tgt) + + +class TestRepr(object): + def test_polynomial_str(self): + res = repr(poly.Polynomial([0, 1])) + tgt = 'Polynomial([0., 1.], domain=[-1, 1], window=[-1, 1])' + assert_equal(res, tgt) + + def test_chebyshev_str(self): + res = repr(poly.Chebyshev([0, 1])) + tgt = 'Chebyshev([0., 1.], domain=[-1, 1], window=[-1, 1])' + assert_equal(res, tgt) + + def test_legendre_repr(self): + res = repr(poly.Legendre([0, 1])) + tgt = 'Legendre([0., 1.], domain=[-1, 1], window=[-1, 1])' + assert_equal(res, tgt) + + def test_hermite_repr(self): + res = repr(poly.Hermite([0, 1])) + tgt = 'Hermite([0., 1.], domain=[-1, 1], window=[-1, 1])' + assert_equal(res, tgt) + + def test_hermiteE_repr(self): + res = repr(poly.HermiteE([0, 1])) + tgt = 'HermiteE([0., 1.], domain=[-1, 1], window=[-1, 1])' + assert_equal(res, tgt) + + def test_laguerre_repr(self): + res = repr(poly.Laguerre([0, 1])) + tgt = 'Laguerre([0., 1.], domain=[0, 1], window=[0, 1])' + assert_equal(res, tgt) + + +# + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/random/__init__.py b/numpy/random/__init__.py new file mode 100644 index 0000000..869818a --- /dev/null +++ b/numpy/random/__init__.py @@ -0,0 +1,122 @@ +""" +======================== +Random Number Generation +======================== + +==================== ========================================================= +Utility functions +============================================================================== +random Uniformly distributed values of a given shape. +bytes Uniformly distributed random bytes. +random_integers Uniformly distributed integers in a given range. +random_sample Uniformly distributed floats in a given range. +random Alias for random_sample +ranf Alias for random_sample +sample Alias for random_sample +choice Generate a weighted random sample from a given array-like +permutation Randomly permute a sequence / generate a random sequence. +shuffle Randomly permute a sequence in place. +seed Seed the random number generator. +==================== ========================================================= + +==================== ========================================================= +Compatibility functions +============================================================================== +rand Uniformly distributed values. +randn Normally distributed values. +ranf Uniformly distributed floating point numbers. +randint Uniformly distributed integers in a given range. +==================== ========================================================= + +==================== ========================================================= +Univariate distributions +============================================================================== +beta Beta distribution over ``[0, 1]``. +binomial Binomial distribution. +chisquare :math:`\\chi^2` distribution. +exponential Exponential distribution. +f F (Fisher-Snedecor) distribution. +gamma Gamma distribution. +geometric Geometric distribution. +gumbel Gumbel distribution. +hypergeometric Hypergeometric distribution. +laplace Laplace distribution. +logistic Logistic distribution. +lognormal Log-normal distribution. +logseries Logarithmic series distribution. +negative_binomial Negative binomial distribution. +noncentral_chisquare Non-central chi-square distribution. +noncentral_f Non-central F distribution. +normal Normal / Gaussian distribution. +pareto Pareto distribution. +poisson Poisson distribution. +power Power distribution. +rayleigh Rayleigh distribution. +triangular Triangular distribution. +uniform Uniform distribution. +vonmises Von Mises circular distribution. +wald Wald (inverse Gaussian) distribution. +weibull Weibull distribution. +zipf Zipf's distribution over ranked data. +==================== ========================================================= + +==================== ========================================================= +Multivariate distributions +============================================================================== +dirichlet Multivariate generalization of Beta distribution. +multinomial Multivariate generalization of the binomial distribution. +multivariate_normal Multivariate generalization of the normal distribution. +==================== ========================================================= + +==================== ========================================================= +Standard distributions +============================================================================== +standard_cauchy Standard Cauchy-Lorentz distribution. +standard_exponential Standard exponential distribution. +standard_gamma Standard Gamma distribution. +standard_normal Standard normal distribution. +standard_t Standard Student's t-distribution. +==================== ========================================================= + +==================== ========================================================= +Internal functions +============================================================================== +get_state Get tuple representing internal state of generator. +set_state Set state of generator. +==================== ========================================================= + +""" +from __future__ import division, absolute_import, print_function + +import warnings + +# To get sub-modules +from .info import __doc__, __all__ + + +with warnings.catch_warnings(): + warnings.filterwarnings("ignore", message="numpy.ndarray size changed") + from .mtrand import * + +# Some aliases: +ranf = random = sample = random_sample +__all__.extend(['ranf', 'random', 'sample']) + +def __RandomState_ctor(): + """Return a RandomState instance. + + This function exists solely to assist (un)pickling. + + Note that the state of the RandomState returned here is irrelevant, as this function's + entire purpose is to return a newly allocated RandomState whose state pickle can set. + Consequently the RandomState returned by this function is a freshly allocated copy + with a seed=0. + + See https://github.com/numpy/numpy/issues/4763 for a detailed discussion + + """ + return RandomState(seed=0) + +from numpy.testing import _numpy_tester +test = _numpy_tester().test +bench = _numpy_tester().bench diff --git a/numpy/random/info.py b/numpy/random/info.py new file mode 100644 index 0000000..be9c8d9 --- /dev/null +++ b/numpy/random/info.py @@ -0,0 +1,139 @@ +""" +======================== +Random Number Generation +======================== + +==================== ========================================================= +Utility functions +============================================================================== +random_sample Uniformly distributed floats over ``[0, 1)``. +random Alias for `random_sample`. +bytes Uniformly distributed random bytes. +random_integers Uniformly distributed integers in a given range. +permutation Randomly permute a sequence / generate a random sequence. +shuffle Randomly permute a sequence in place. +seed Seed the random number generator. +choice Random sample from 1-D array. + +==================== ========================================================= + +==================== ========================================================= +Compatibility functions +============================================================================== +rand Uniformly distributed values. +randn Normally distributed values. +ranf Uniformly distributed floating point numbers. +randint Uniformly distributed integers in a given range. +==================== ========================================================= + +==================== ========================================================= +Univariate distributions +============================================================================== +beta Beta distribution over ``[0, 1]``. +binomial Binomial distribution. +chisquare :math:`\\chi^2` distribution. +exponential Exponential distribution. +f F (Fisher-Snedecor) distribution. +gamma Gamma distribution. +geometric Geometric distribution. +gumbel Gumbel distribution. +hypergeometric Hypergeometric distribution. +laplace Laplace distribution. +logistic Logistic distribution. +lognormal Log-normal distribution. +logseries Logarithmic series distribution. +negative_binomial Negative binomial distribution. +noncentral_chisquare Non-central chi-square distribution. +noncentral_f Non-central F distribution. +normal Normal / Gaussian distribution. +pareto Pareto distribution. +poisson Poisson distribution. +power Power distribution. +rayleigh Rayleigh distribution. +triangular Triangular distribution. +uniform Uniform distribution. +vonmises Von Mises circular distribution. +wald Wald (inverse Gaussian) distribution. +weibull Weibull distribution. +zipf Zipf's distribution over ranked data. +==================== ========================================================= + +==================== ========================================================= +Multivariate distributions +============================================================================== +dirichlet Multivariate generalization of Beta distribution. +multinomial Multivariate generalization of the binomial distribution. +multivariate_normal Multivariate generalization of the normal distribution. +==================== ========================================================= + +==================== ========================================================= +Standard distributions +============================================================================== +standard_cauchy Standard Cauchy-Lorentz distribution. +standard_exponential Standard exponential distribution. +standard_gamma Standard Gamma distribution. +standard_normal Standard normal distribution. +standard_t Standard Student's t-distribution. +==================== ========================================================= + +==================== ========================================================= +Internal functions +============================================================================== +get_state Get tuple representing internal state of generator. +set_state Set state of generator. +==================== ========================================================= + +""" +from __future__ import division, absolute_import, print_function + +depends = ['core'] + +__all__ = [ + 'beta', + 'binomial', + 'bytes', + 'chisquare', + 'choice', + 'dirichlet', + 'exponential', + 'f', + 'gamma', + 'geometric', + 'get_state', + 'gumbel', + 'hypergeometric', + 'laplace', + 'logistic', + 'lognormal', + 'logseries', + 'multinomial', + 'multivariate_normal', + 'negative_binomial', + 'noncentral_chisquare', + 'noncentral_f', + 'normal', + 'pareto', + 'permutation', + 'poisson', + 'power', + 'rand', + 'randint', + 'randn', + 'random_integers', + 'random_sample', + 'rayleigh', + 'seed', + 'set_state', + 'shuffle', + 'standard_cauchy', + 'standard_exponential', + 'standard_gamma', + 'standard_normal', + 'standard_t', + 'triangular', + 'uniform', + 'vonmises', + 'wald', + 'weibull', + 'zipf' +] diff --git a/numpy/random/mtrand/Python.pxi b/numpy/random/mtrand/Python.pxi new file mode 100644 index 0000000..08aadba --- /dev/null +++ b/numpy/random/mtrand/Python.pxi @@ -0,0 +1,43 @@ +# :Author: Robert Kern +# :Copyright: 2004, Enthought, Inc. +# :License: BSD Style + + +cdef extern from "Python.h": + # Not part of the Python API, but we might as well define it here. + # Note that the exact type doesn't actually matter for Pyrex. + ctypedef int size_t + + # String API + char* PyString_AsString(object string) + char* PyString_AS_STRING(object string) + object PyString_FromString(char* c_string) + object PyString_FromStringAndSize(char* c_string, int length) + + # Float API + double PyFloat_AsDouble(object ob) except? -1.0 + long PyInt_AsLong(object ob) except? -1 + + # Memory API + void* PyMem_Malloc(size_t n) + void* PyMem_Realloc(void* buf, size_t n) + void PyMem_Free(void* buf) + + void Py_DECREF(object obj) + void Py_XDECREF(object obj) + void Py_INCREF(object obj) + void Py_XINCREF(object obj) + + # TypeCheck API + int PyFloat_Check(object obj) + int PyInt_Check(object obj) + + # Error API + int PyErr_Occurred() + void PyErr_Clear() + +cdef extern from "string.h": + void *memcpy(void *s1, void *s2, int n) + +cdef extern from "math.h": + double fabs(double x) diff --git a/numpy/random/mtrand/distributions.c b/numpy/random/mtrand/distributions.c new file mode 100644 index 0000000..b7e1579 --- /dev/null +++ b/numpy/random/mtrand/distributions.c @@ -0,0 +1,926 @@ +/* Copyright 2005 Robert Kern (robert.kern@gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* The implementations of rk_hypergeometric_hyp(), rk_hypergeometric_hrua(), + * and rk_triangular() were adapted from Ivan Frohne's rv.py which has this + * license: + * + * Copyright 1998 by Ivan Frohne; Wasilla, Alaska, U.S.A. + * All Rights Reserved + * + * Permission to use, copy, modify and distribute this software and its + * documentation for any purpose, free of charge, is granted subject to the + * following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the software. + * + * THE SOFTWARE AND DOCUMENTATION IS PROVIDED WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR + * OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM OR DAMAGES IN A CONTRACT + * ACTION, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR ITS DOCUMENTATION. + */ + +#include "distributions.h" +#include +#include +#include +#include + +#ifndef min +#define min(x,y) ((xy)?x:y) +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338328 +#endif + +/* + * log-gamma function to support some of these distributions. The + * algorithm comes from SPECFUN by Shanjie Zhang and Jianming Jin and their + * book "Computation of Special Functions", 1996, John Wiley & Sons, Inc. + */ +static double loggam(double x) +{ + double x0, x2, xp, gl, gl0; + long k, n; + + static double a[10] = {8.333333333333333e-02,-2.777777777777778e-03, + 7.936507936507937e-04,-5.952380952380952e-04, + 8.417508417508418e-04,-1.917526917526918e-03, + 6.410256410256410e-03,-2.955065359477124e-02, + 1.796443723688307e-01,-1.39243221690590e+00}; + x0 = x; + n = 0; + if ((x == 1.0) || (x == 2.0)) + { + return 0.0; + } + else if (x <= 7.0) + { + n = (long)(7 - x); + x0 = x + n; + } + x2 = 1.0/(x0*x0); + xp = 2*M_PI; + gl0 = a[9]; + for (k=8; k>=0; k--) + { + gl0 *= x2; + gl0 += a[k]; + } + gl = gl0/x0 + 0.5*log(xp) + (x0-0.5)*log(x0) - x0; + if (x <= 7.0) + { + for (k=1; k<=n; k++) + { + gl -= log(x0-1.0); + x0 -= 1.0; + } + } + return gl; +} + +double rk_normal(rk_state *state, double loc, double scale) +{ + return loc + scale*rk_gauss(state); +} + +double rk_standard_exponential(rk_state *state) +{ + /* We use -log(1-U) since U is [0, 1) */ + return -log(1.0 - rk_double(state)); +} + +double rk_exponential(rk_state *state, double scale) +{ + return scale * rk_standard_exponential(state); +} + +double rk_uniform(rk_state *state, double loc, double scale) +{ + return loc + scale*rk_double(state); +} + +double rk_standard_gamma(rk_state *state, double shape) +{ + double b, c; + double U, V, X, Y; + + if (shape == 1.0) + { + return rk_standard_exponential(state); + } + else if (shape < 1.0) + { + for (;;) + { + U = rk_double(state); + V = rk_standard_exponential(state); + if (U <= 1.0 - shape) + { + X = pow(U, 1./shape); + if (X <= V) + { + return X; + } + } + else + { + Y = -log((1-U)/shape); + X = pow(1.0 - shape + shape*Y, 1./shape); + if (X <= (V + Y)) + { + return X; + } + } + } + } + else + { + b = shape - 1./3.; + c = 1./sqrt(9*b); + for (;;) + { + do + { + X = rk_gauss(state); + V = 1.0 + c*X; + } while (V <= 0.0); + + V = V*V*V; + U = rk_double(state); + if (U < 1.0 - 0.0331*(X*X)*(X*X)) return (b*V); + if (log(U) < 0.5*X*X + b*(1. - V + log(V))) return (b*V); + } + } +} + +double rk_gamma(rk_state *state, double shape, double scale) +{ + return scale * rk_standard_gamma(state, shape); +} + +double rk_beta(rk_state *state, double a, double b) +{ + double Ga, Gb; + + if ((a <= 1.0) && (b <= 1.0)) + { + double U, V, X, Y; + /* Use Johnk's algorithm */ + + while (1) + { + U = rk_double(state); + V = rk_double(state); + X = pow(U, 1.0/a); + Y = pow(V, 1.0/b); + + if ((X + Y) <= 1.0) + { + if (X +Y > 0) + { + return X / (X + Y); + } + else + { + double logX = log(U) / a; + double logY = log(V) / b; + double logM = logX > logY ? logX : logY; + logX -= logM; + logY -= logM; + + return exp(logX - log(exp(logX) + exp(logY))); + } + } + } + } + else + { + Ga = rk_standard_gamma(state, a); + Gb = rk_standard_gamma(state, b); + return Ga/(Ga + Gb); + } +} + +double rk_chisquare(rk_state *state, double df) +{ + return 2.0*rk_standard_gamma(state, df/2.0); +} + +double rk_noncentral_chisquare(rk_state *state, double df, double nonc) +{ + if (nonc == 0){ + return rk_chisquare(state, df); + } + if(1 < df) + { + const double Chi2 = rk_chisquare(state, df - 1); + const double N = rk_gauss(state) + sqrt(nonc); + return Chi2 + N*N; + } + else + { + const long i = rk_poisson(state, nonc / 2.0); + return rk_chisquare(state, df + 2 * i); + } +} + +double rk_f(rk_state *state, double dfnum, double dfden) +{ + return ((rk_chisquare(state, dfnum) * dfden) / + (rk_chisquare(state, dfden) * dfnum)); +} + +double rk_noncentral_f(rk_state *state, double dfnum, double dfden, double nonc) +{ + double t = rk_noncentral_chisquare(state, dfnum, nonc) * dfden; + return t / (rk_chisquare(state, dfden) * dfnum); +} + +long rk_binomial_btpe(rk_state *state, long n, double p) +{ + double r,q,fm,p1,xm,xl,xr,c,laml,lamr,p2,p3,p4; + double a,u,v,s,F,rho,t,A,nrq,x1,x2,f1,f2,z,z2,w,w2,x; + long m,y,k,i; + + if (!(state->has_binomial) || + (state->nsave != n) || + (state->psave != p)) + { + /* initialize */ + state->nsave = n; + state->psave = p; + state->has_binomial = 1; + state->r = r = min(p, 1.0-p); + state->q = q = 1.0 - r; + state->fm = fm = n*r+r; + state->m = m = (long)floor(state->fm); + state->p1 = p1 = floor(2.195*sqrt(n*r*q)-4.6*q) + 0.5; + state->xm = xm = m + 0.5; + state->xl = xl = xm - p1; + state->xr = xr = xm + p1; + state->c = c = 0.134 + 20.5/(15.3 + m); + a = (fm - xl)/(fm-xl*r); + state->laml = laml = a*(1.0 + a/2.0); + a = (xr - fm)/(xr*q); + state->lamr = lamr = a*(1.0 + a/2.0); + state->p2 = p2 = p1*(1.0 + 2.0*c); + state->p3 = p3 = p2 + c/laml; + state->p4 = p4 = p3 + c/lamr; + } + else + { + r = state->r; + q = state->q; + fm = state->fm; + m = state->m; + p1 = state->p1; + xm = state->xm; + xl = state->xl; + xr = state->xr; + c = state->c; + laml = state->laml; + lamr = state->lamr; + p2 = state->p2; + p3 = state->p3; + p4 = state->p4; + } + + /* sigh ... */ + Step10: + nrq = n*r*q; + u = rk_double(state)*p4; + v = rk_double(state); + if (u > p1) goto Step20; + y = (long)floor(xm - p1*v + u); + goto Step60; + + Step20: + if (u > p2) goto Step30; + x = xl + (u - p1)/c; + v = v*c + 1.0 - fabs(m - x + 0.5)/p1; + if (v > 1.0) goto Step10; + y = (long)floor(x); + goto Step50; + + Step30: + if (u > p3) goto Step40; + y = (long)floor(xl + log(v)/laml); + if (y < 0) goto Step10; + v = v*(u-p2)*laml; + goto Step50; + + Step40: + y = (long)floor(xr - log(v)/lamr); + if (y > n) goto Step10; + v = v*(u-p3)*lamr; + + Step50: + k = labs(y - m); + if ((k > 20) && (k < ((nrq)/2.0 - 1))) goto Step52; + + s = r/q; + a = s*(n+1); + F = 1.0; + if (m < y) + { + for (i=m+1; i<=y; i++) + { + F *= (a/i - s); + } + } + else if (m > y) + { + for (i=y+1; i<=m; i++) + { + F /= (a/i - s); + } + } + if (v > F) goto Step10; + goto Step60; + + Step52: + rho = (k/(nrq))*((k*(k/3.0 + 0.625) + 0.16666666666666666)/nrq + 0.5); + t = -k*k/(2*nrq); + A = log(v); + if (A < (t - rho)) goto Step60; + if (A > (t + rho)) goto Step10; + + x1 = y+1; + f1 = m+1; + z = n+1-m; + w = n-y+1; + x2 = x1*x1; + f2 = f1*f1; + z2 = z*z; + w2 = w*w; + if (A > (xm*log(f1/x1) + + (n-m+0.5)*log(z/w) + + (y-m)*log(w*r/(x1*q)) + + (13680.-(462.-(132.-(99.-140./f2)/f2)/f2)/f2)/f1/166320. + + (13680.-(462.-(132.-(99.-140./z2)/z2)/z2)/z2)/z/166320. + + (13680.-(462.-(132.-(99.-140./x2)/x2)/x2)/x2)/x1/166320. + + (13680.-(462.-(132.-(99.-140./w2)/w2)/w2)/w2)/w/166320.)) + { + goto Step10; + } + + Step60: + if (p > 0.5) + { + y = n - y; + } + + return y; +} + +long rk_binomial_inversion(rk_state *state, long n, double p) +{ + double q, qn, np, px, U; + long X, bound; + + if (!(state->has_binomial) || + (state->nsave != n) || + (state->psave != p)) + { + state->nsave = n; + state->psave = p; + state->has_binomial = 1; + state->q = q = 1.0 - p; + state->r = qn = exp(n * log(q)); + state->c = np = n*p; + state->m = bound = min(n, np + 10.0*sqrt(np*q + 1)); + } else + { + q = state->q; + qn = state->r; + np = state->c; + bound = state->m; + } + X = 0; + px = qn; + U = rk_double(state); + while (U > px) + { + X++; + if (X > bound) + { + X = 0; + px = qn; + U = rk_double(state); + } else + { + U -= px; + px = ((n-X+1) * p * px)/(X*q); + } + } + return X; +} + +long rk_binomial(rk_state *state, long n, double p) +{ + double q; + + if (p <= 0.5) + { + if (p*n <= 30.0) + { + return rk_binomial_inversion(state, n, p); + } + else + { + return rk_binomial_btpe(state, n, p); + } + } + else + { + q = 1.0-p; + if (q*n <= 30.0) + { + return n - rk_binomial_inversion(state, n, q); + } + else + { + return n - rk_binomial_btpe(state, n, q); + } + } + +} + +long rk_negative_binomial(rk_state *state, double n, double p) +{ + double Y; + + Y = rk_gamma(state, n, (1-p)/p); + return rk_poisson(state, Y); +} + +long rk_poisson_mult(rk_state *state, double lam) +{ + long X; + double prod, U, enlam; + + enlam = exp(-lam); + X = 0; + prod = 1.0; + while (1) + { + U = rk_double(state); + prod *= U; + if (prod > enlam) + { + X += 1; + } + else + { + return X; + } + } +} + +/* + * The transformed rejection method for generating Poisson random variables + * W. Hoermann + * Insurance: Mathematics and Economics 12, 39-45 (1993) + */ +#define LS2PI 0.91893853320467267 +#define TWELFTH 0.083333333333333333333333 +long rk_poisson_ptrs(rk_state *state, double lam) +{ + long k; + double U, V, slam, loglam, a, b, invalpha, vr, us; + + slam = sqrt(lam); + loglam = log(lam); + b = 0.931 + 2.53*slam; + a = -0.059 + 0.02483*b; + invalpha = 1.1239 + 1.1328/(b-3.4); + vr = 0.9277 - 3.6224/(b-2); + + while (1) + { + U = rk_double(state) - 0.5; + V = rk_double(state); + us = 0.5 - fabs(U); + k = (long)floor((2*a/us + b)*U + lam + 0.43); + if ((us >= 0.07) && (V <= vr)) + { + return k; + } + if ((k < 0) || + ((us < 0.013) && (V > us))) + { + continue; + } + if ((log(V) + log(invalpha) - log(a/(us*us)+b)) <= + (-lam + k*loglam - loggam(k+1))) + { + return k; + } + + + } + +} + +long rk_poisson(rk_state *state, double lam) +{ + if (lam >= 10) + { + return rk_poisson_ptrs(state, lam); + } + else if (lam == 0) + { + return 0; + } + else + { + return rk_poisson_mult(state, lam); + } +} + +double rk_standard_cauchy(rk_state *state) +{ + return rk_gauss(state) / rk_gauss(state); +} + +double rk_standard_t(rk_state *state, double df) +{ + double N, G, X; + + N = rk_gauss(state); + G = rk_standard_gamma(state, df/2); + X = sqrt(df/2)*N/sqrt(G); + return X; +} + +/* Uses the rejection algorithm compared against the wrapped Cauchy + distribution suggested by Best and Fisher and documented in + Chapter 9 of Luc's Non-Uniform Random Variate Generation. + http://cg.scs.carleton.ca/~luc/rnbookindex.html + (but corrected to match the algorithm in R and Python) +*/ +double rk_vonmises(rk_state *state, double mu, double kappa) +{ + double s; + double U, V, W, Y, Z; + double result, mod; + int neg; + + if (kappa < 1e-8) + { + return M_PI * (2*rk_double(state)-1); + } + else + { + /* with double precision rho is zero until 1.4e-8 */ + if (kappa < 1e-5) { + /* + * second order taylor expansion around kappa = 0 + * precise until relatively large kappas as second order is 0 + */ + s = (1./kappa + kappa); + } + else { + double r = 1 + sqrt(1 + 4*kappa*kappa); + double rho = (r - sqrt(2*r)) / (2*kappa); + s = (1 + rho*rho)/(2*rho); + } + + while (1) + { + U = rk_double(state); + Z = cos(M_PI*U); + W = (1 + s*Z)/(s + Z); + Y = kappa * (s - W); + V = rk_double(state); + if ((Y*(2-Y) - V >= 0) || (log(Y/V)+1 - Y >= 0)) + { + break; + } + } + + U = rk_double(state); + + result = acos(W); + if (U < 0.5) + { + result = -result; + } + result += mu; + neg = (result < 0); + mod = fabs(result); + mod = (fmod(mod+M_PI, 2*M_PI)-M_PI); + if (neg) + { + mod *= -1; + } + + return mod; + } +} + +double rk_pareto(rk_state *state, double a) +{ + return exp(rk_standard_exponential(state)/a) - 1; +} + +double rk_weibull(rk_state *state, double a) +{ + return pow(rk_standard_exponential(state), 1./a); +} + +double rk_power(rk_state *state, double a) +{ + return pow(1 - exp(-rk_standard_exponential(state)), 1./a); +} + +double rk_laplace(rk_state *state, double loc, double scale) +{ + double U; + + U = rk_double(state); + if (U < 0.5) + { + U = loc + scale * log(U + U); + } else + { + U = loc - scale * log(2.0 - U - U); + } + return U; +} + +double rk_gumbel(rk_state *state, double loc, double scale) +{ + double U; + + U = 1.0 - rk_double(state); + return loc - scale * log(-log(U)); +} + +double rk_logistic(rk_state *state, double loc, double scale) +{ + double U; + + U = rk_double(state); + return loc + scale * log(U/(1.0 - U)); +} + +double rk_lognormal(rk_state *state, double mean, double sigma) +{ + return exp(rk_normal(state, mean, sigma)); +} + +double rk_rayleigh(rk_state *state, double mode) +{ + return mode*sqrt(-2.0 * log(1.0 - rk_double(state))); +} + +double rk_wald(rk_state *state, double mean, double scale) +{ + double U, X, Y; + double mu_2l; + + mu_2l = mean / (2*scale); + Y = rk_gauss(state); + Y = mean*Y*Y; + X = mean + mu_2l*(Y - sqrt(4*scale*Y + Y*Y)); + U = rk_double(state); + if (U <= mean/(mean+X)) + { + return X; + } else + { + return mean*mean/X; + } +} + +long rk_zipf(rk_state *state, double a) +{ + double am1, b; + + am1 = a - 1.0; + b = pow(2.0, am1); + while (1) { + double T, U, V, X; + + U = 1.0 - rk_double(state); + V = rk_double(state); + X = floor(pow(U, -1.0/am1)); + /* + * The real result may be above what can be represented in a signed + * long. Since this is a straightforward rejection algorithm, we can + * just reject this value. This function then models a Zipf + * distribution truncated to sys.maxint. + */ + if (X > LONG_MAX || X < 1.0) { + continue; + } + + T = pow(1.0 + 1.0/X, am1); + if (V*X*(T - 1.0)/(b - 1.0) <= T/b) { + return (long)X; + } + } +} + +long rk_geometric_search(rk_state *state, double p) +{ + double U; + long X; + double sum, prod, q; + + X = 1; + sum = prod = p; + q = 1.0 - p; + U = rk_double(state); + while (U > sum) + { + prod *= q; + sum += prod; + X++; + } + return X; +} + +long rk_geometric_inversion(rk_state *state, double p) +{ + return (long)ceil(log(1.0-rk_double(state))/log(1.0-p)); +} + +long rk_geometric(rk_state *state, double p) +{ + if (p >= 0.333333333333333333333333) + { + return rk_geometric_search(state, p); + } else + { + return rk_geometric_inversion(state, p); + } +} + +long rk_hypergeometric_hyp(rk_state *state, long good, long bad, long sample) +{ + long d1, K, Z; + double d2, U, Y; + + d1 = bad + good - sample; + d2 = (double)min(bad, good); + + Y = d2; + K = sample; + while (Y > 0.0) + { + U = rk_double(state); + Y -= (long)floor(U + Y/(d1 + K)); + K--; + if (K == 0) break; + } + Z = (long)(d2 - Y); + if (good > bad) Z = sample - Z; + return Z; +} + +/* D1 = 2*sqrt(2/e) */ +/* D2 = 3 - 2*sqrt(3/e) */ +#define D1 1.7155277699214135 +#define D2 0.8989161620588988 +long rk_hypergeometric_hrua(rk_state *state, long good, long bad, long sample) +{ + long mingoodbad, maxgoodbad, popsize, m, d9; + double d4, d5, d6, d7, d8, d10, d11; + long Z; + double T, W, X, Y; + + mingoodbad = min(good, bad); + popsize = good + bad; + maxgoodbad = max(good, bad); + m = min(sample, popsize - sample); + d4 = ((double)mingoodbad) / popsize; + d5 = 1.0 - d4; + d6 = m*d4 + 0.5; + d7 = sqrt((double)(popsize - m) * sample * d4 * d5 / (popsize - 1) + 0.5); + d8 = D1*d7 + D2; + d9 = (long)floor((double)(m + 1) * (mingoodbad + 1) / (popsize + 2)); + d10 = (loggam(d9+1) + loggam(mingoodbad-d9+1) + loggam(m-d9+1) + + loggam(maxgoodbad-m+d9+1)); + d11 = min(min(m, mingoodbad)+1.0, floor(d6+16*d7)); + /* 16 for 16-decimal-digit precision in D1 and D2 */ + + while (1) + { + X = rk_double(state); + Y = rk_double(state); + W = d6 + d8*(Y- 0.5)/X; + + /* fast rejection: */ + if ((W < 0.0) || (W >= d11)) continue; + + Z = (long)floor(W); + T = d10 - (loggam(Z+1) + loggam(mingoodbad-Z+1) + loggam(m-Z+1) + + loggam(maxgoodbad-m+Z+1)); + + /* fast acceptance: */ + if ((X*(4.0-X)-3.0) <= T) break; + + /* fast rejection: */ + if (X*(X-T) >= 1) continue; + + if (2.0*log(X) <= T) break; /* acceptance */ + } + + /* this is a correction to HRUA* by Ivan Frohne in rv.py */ + if (good > bad) Z = m - Z; + + /* another fix from rv.py to allow sample to exceed popsize/2 */ + if (m < sample) Z = good - Z; + + return Z; +} +#undef D1 +#undef D2 + +long rk_hypergeometric(rk_state *state, long good, long bad, long sample) +{ + if (sample > 10) + { + return rk_hypergeometric_hrua(state, good, bad, sample); + } else + { + return rk_hypergeometric_hyp(state, good, bad, sample); + } +} + +double rk_triangular(rk_state *state, double left, double mode, double right) +{ + double base, leftbase, ratio, leftprod, rightprod; + double U; + + base = right - left; + leftbase = mode - left; + ratio = leftbase / base; + leftprod = leftbase*base; + rightprod = (right - mode)*base; + + U = rk_double(state); + if (U <= ratio) + { + return left + sqrt(U*leftprod); + } else + { + return right - sqrt((1.0 - U) * rightprod); + } +} + +long rk_logseries(rk_state *state, double p) +{ + double q, r, U, V; + long result; + + r = log(1.0 - p); + + while (1) { + V = rk_double(state); + if (V >= p) { + return 1; + } + U = rk_double(state); + q = 1.0 - exp(r*U); + if (V <= q*q) { + result = (long)floor(1 + log(V)/log(q)); + if (result < 1) { + continue; + } + else { + return result; + } + } + if (V >= q) { + return 1; + } + return 2; + } +} diff --git a/numpy/random/mtrand/distributions.h b/numpy/random/mtrand/distributions.h new file mode 100644 index 0000000..0b42bc7 --- /dev/null +++ b/numpy/random/mtrand/distributions.h @@ -0,0 +1,185 @@ +/* Copyright 2005 Robert Kern (robert.kern@gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _RK_DISTR_ +#define _RK_DISTR_ + +#include "randomkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* References: + * + * Devroye, Luc. _Non-Uniform Random Variate Generation_. + * Springer-Verlag, New York, 1986. + * http://cgm.cs.mcgill.ca/~luc/rnbookindex.html + * + * Kachitvichyanukul, V. and Schmeiser, B. W. Binomial Random Variate + * Generation. Communications of the ACM, 31, 2 (February, 1988) 216. + * + * Hoermann, W. The Transformed Rejection Method for Generating Poisson Random + * Variables. Insurance: Mathematics and Economics, (to appear) + * http://citeseer.csail.mit.edu/151115.html + * + * Marsaglia, G. and Tsang, W. W. A Simple Method for Generating Gamma + * Variables. ACM Transactions on Mathematical Software, Vol. 26, No. 3, + * September 2000, Pages 363–372. + */ + +/* Normal distribution with mean=loc and standard deviation=scale. */ +extern double rk_normal(rk_state *state, double loc, double scale); + +/* Standard exponential distribution (mean=1) computed by inversion of the + * CDF. */ +extern double rk_standard_exponential(rk_state *state); + +/* Exponential distribution with mean=scale. */ +extern double rk_exponential(rk_state *state, double scale); + +/* Uniform distribution on interval [loc, loc+scale). */ +extern double rk_uniform(rk_state *state, double loc, double scale); + +/* Standard gamma distribution with shape parameter. + * When shape < 1, the algorithm given by (Devroye p. 304) is used. + * When shape == 1, a Exponential variate is generated. + * When shape > 1, the small and fast method of (Marsaglia and Tsang 2000) + * is used. + */ +extern double rk_standard_gamma(rk_state *state, double shape); + +/* Gamma distribution with shape and scale. */ +extern double rk_gamma(rk_state *state, double shape, double scale); + +/* Beta distribution computed by combining two gamma variates (Devroye p. 432). + */ +extern double rk_beta(rk_state *state, double a, double b); + +/* Chi^2 distribution computed by transforming a gamma variate (it being a + * special case Gamma(df/2, 2)). */ +extern double rk_chisquare(rk_state *state, double df); + +/* Noncentral Chi^2 distribution computed by modifying a Chi^2 variate. */ +extern double rk_noncentral_chisquare(rk_state *state, double df, double nonc); + +/* F distribution computed by taking the ratio of two Chi^2 variates. */ +extern double rk_f(rk_state *state, double dfnum, double dfden); + +/* Noncentral F distribution computed by taking the ratio of a noncentral Chi^2 + * and a Chi^2 variate. */ +extern double rk_noncentral_f(rk_state *state, double dfnum, double dfden, double nonc); + +/* Binomial distribution with n Bernoulli trials with success probability p. + * When n*p <= 30, the "Second waiting time method" given by (Devroye p. 525) is + * used. Otherwise, the BTPE algorithm of (Kachitvichyanukul and Schmeiser 1988) + * is used. */ +extern long rk_binomial(rk_state *state, long n, double p); + +/* Binomial distribution using BTPE. */ +extern long rk_binomial_btpe(rk_state *state, long n, double p); + +/* Binomial distribution using inversion and chop-down */ +extern long rk_binomial_inversion(rk_state *state, long n, double p); + +/* Negative binomial distribution computed by generating a Gamma(n, (1-p)/p) + * variate Y and returning a Poisson(Y) variate (Devroye p. 543). */ +extern long rk_negative_binomial(rk_state *state, double n, double p); + +/* Poisson distribution with mean=lam. + * When lam < 10, a basic algorithm using repeated multiplications of uniform + * variates is used (Devroye p. 504). + * When lam >= 10, algorithm PTRS from (Hoermann 1992) is used. + */ +extern long rk_poisson(rk_state *state, double lam); + +/* Poisson distribution computed by repeated multiplication of uniform variates. + */ +extern long rk_poisson_mult(rk_state *state, double lam); + +/* Poisson distribution computer by the PTRS algorithm. */ +extern long rk_poisson_ptrs(rk_state *state, double lam); + +/* Standard Cauchy distribution computed by dividing standard gaussians + * (Devroye p. 451). */ +extern double rk_standard_cauchy(rk_state *state); + +/* Standard t-distribution with df degrees of freedom (Devroye p. 445 as + * corrected in the Errata). */ +extern double rk_standard_t(rk_state *state, double df); + +/* von Mises circular distribution with center mu and shape kappa on [-pi,pi] + * (Devroye p. 476 as corrected in the Errata). */ +extern double rk_vonmises(rk_state *state, double mu, double kappa); + +/* Pareto distribution via inversion (Devroye p. 262) */ +extern double rk_pareto(rk_state *state, double a); + +/* Weibull distribution via inversion (Devroye p. 262) */ +extern double rk_weibull(rk_state *state, double a); + +/* Power distribution via inversion (Devroye p. 262) */ +extern double rk_power(rk_state *state, double a); + +/* Laplace distribution */ +extern double rk_laplace(rk_state *state, double loc, double scale); + +/* Gumbel distribution */ +extern double rk_gumbel(rk_state *state, double loc, double scale); + +/* Logistic distribution */ +extern double rk_logistic(rk_state *state, double loc, double scale); + +/* Log-normal distribution */ +extern double rk_lognormal(rk_state *state, double mean, double sigma); + +/* Rayleigh distribution */ +extern double rk_rayleigh(rk_state *state, double mode); + +/* Wald distribution */ +extern double rk_wald(rk_state *state, double mean, double scale); + +/* Zipf distribution */ +extern long rk_zipf(rk_state *state, double a); + +/* Geometric distribution */ +extern long rk_geometric(rk_state *state, double p); +extern long rk_geometric_search(rk_state *state, double p); +extern long rk_geometric_inversion(rk_state *state, double p); + +/* Hypergeometric distribution */ +extern long rk_hypergeometric(rk_state *state, long good, long bad, long sample); +extern long rk_hypergeometric_hyp(rk_state *state, long good, long bad, long sample); +extern long rk_hypergeometric_hrua(rk_state *state, long good, long bad, long sample); + +/* Triangular distribution */ +extern double rk_triangular(rk_state *state, double left, double mode, double right); + +/* Logarithmic series distribution */ +extern long rk_logseries(rk_state *state, double p); + +#ifdef __cplusplus +} +#endif + + +#endif /* _RK_DISTR_ */ diff --git a/numpy/random/mtrand/generate_mtrand_c.py b/numpy/random/mtrand/generate_mtrand_c.py new file mode 100644 index 0000000..ec935e6 --- /dev/null +++ b/numpy/random/mtrand/generate_mtrand_c.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +from __future__ import division, absolute_import, print_function + +import sys +import re +import os + +unused_internal_funcs = ['__Pyx_PrintItem', + '__Pyx_PrintNewline', + '__Pyx_ReRaise', + #'__Pyx_GetExcValue', + '__Pyx_ArgTypeTest', + '__Pyx_SetVtable', + '__Pyx_GetVtable', + '__Pyx_CreateClass'] + +if __name__ == '__main__': + # Use cython here so that long docstrings are broken up. + # This is needed for some VC++ compilers. + os.system('cython mtrand.pyx') + mtrand_c = open('mtrand.c', 'r') + processed = open('mtrand_pp.c', 'w') + unused_funcs_str = '(' + '|'.join(unused_internal_funcs) + ')' + uifpat = re.compile(r'static \w+ \*?'+unused_funcs_str+r'.*/\*proto\*/') + linepat = re.compile(r'/\* ".*/mtrand.pyx":') + for linenum, line in enumerate(mtrand_c): + m = re.match(r'^(\s+arrayObject\w*\s*=\s*[(])[(]PyObject\s*[*][)]', + line) + if m: + line = '%s(PyArrayObject *)%s' % (m.group(1), line[m.end():]) + m = uifpat.match(line) + if m: + line = '' + m = re.search(unused_funcs_str, line) + if m: + print("%s was declared unused, but is used at line %d" % (m.group(), + linenum+1), file=sys.stderr) + line = linepat.sub(r'/* "mtrand.pyx":', line) + processed.write(line) + mtrand_c.close() + processed.close() + os.rename('mtrand_pp.c', 'mtrand.c') diff --git a/numpy/random/mtrand/initarray.c b/numpy/random/mtrand/initarray.c new file mode 100644 index 0000000..21f1dc0 --- /dev/null +++ b/numpy/random/mtrand/initarray.c @@ -0,0 +1,152 @@ +/* + * These function have been adapted from Python 2.4.1's _randommodule.c + * + * The following changes have been made to it in 2005 by Robert Kern: + * + * * init_by_array has been declared extern, has a void return, and uses the + * rk_state structure to hold its data. + * + * The original file has the following verbatim comments: + * + * ------------------------------------------------------------------ + * The code in this module was based on a download from: + * http://www.math.keio.ac.jp/~matumoto/MT2002/emt19937ar.html + * + * It was modified in 2002 by Raymond Hettinger as follows: + * + * * the principal computational lines untouched except for tabbing. + * + * * renamed genrand_res53() to random_random() and wrapped + * in python calling/return code. + * + * * genrand_int32() and the helper functions, init_genrand() + * and init_by_array(), were declared static, wrapped in + * Python calling/return code. also, their global data + * references were replaced with structure references. + * + * * unused functions from the original were deleted. + * new, original C python code was added to implement the + * Random() interface. + * + * The following are the verbatim comments from the original code: + * + * A C-program for MT19937, with initialization improved 2002/1/26. + * Coded by Takuji Nishimura and Makoto Matsumoto. + * + * Before using, initialize the state by using init_genrand(seed) + * or init_by_array(init_key, key_length). + * + * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Any feedback is very welcome. + * http://www.math.keio.ac.jp/matumoto/emt.html + * email: matumoto@math.keio.ac.jp + */ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "initarray.h" + +static void +init_genrand(rk_state *self, unsigned long s); + +/* initializes mt[RK_STATE_LEN] with a seed */ +static void +init_genrand(rk_state *self, unsigned long s) +{ + int mti; + unsigned long *mt = self->key; + + mt[0] = s & 0xffffffffUL; + for (mti = 1; mti < RK_STATE_LEN; mti++) { + /* + * See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. + * In the previous versions, MSBs of the seed affect + * only MSBs of the array mt[]. + * 2002/01/09 modified by Makoto Matsumoto + */ + mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); + /* for > 32 bit machines */ + mt[mti] &= 0xffffffffUL; + } + self->pos = mti; + return; +} + + +/* + * initialize by an array with array-length + * init_key is the array for initializing keys + * key_length is its length + */ +extern void +init_by_array(rk_state *self, unsigned long init_key[], npy_intp key_length) +{ + /* was signed in the original code. RDH 12/16/2002 */ + npy_intp i = 1; + npy_intp j = 0; + unsigned long *mt = self->key; + npy_intp k; + + init_genrand(self, 19650218UL); + k = (RK_STATE_LEN > key_length ? RK_STATE_LEN : key_length); + for (; k; k--) { + /* non linear */ + mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) + + init_key[j] + j; + /* for > 32 bit machines */ + mt[i] &= 0xffffffffUL; + i++; + j++; + if (i >= RK_STATE_LEN) { + mt[0] = mt[RK_STATE_LEN - 1]; + i = 1; + } + if (j >= key_length) { + j = 0; + } + } + for (k = RK_STATE_LEN - 1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) + - i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i >= RK_STATE_LEN) { + mt[0] = mt[RK_STATE_LEN - 1]; + i = 1; + } + } + + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ + self->gauss = 0; + self->has_gauss = 0; + self->has_binomial = 0; +} diff --git a/numpy/random/mtrand/initarray.h b/numpy/random/mtrand/initarray.h new file mode 100644 index 0000000..f5e5e53 --- /dev/null +++ b/numpy/random/mtrand/initarray.h @@ -0,0 +1,8 @@ +#include "Python.h" +#define NO_IMPORT_ARRAY +#include "numpy/arrayobject.h" +#include "randomkit.h" + +extern void +init_by_array(rk_state *self, unsigned long init_key[], + npy_intp key_length); diff --git a/numpy/random/mtrand/mtrand.c b/numpy/random/mtrand/mtrand.c new file mode 100644 index 0000000..0e159c0 --- /dev/null +++ b/numpy/random/mtrand/mtrand.c @@ -0,0 +1,50804 @@ +/* Generated by Cython 0.28.2 */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.6+ or Python 3.3+. +#else +#define CYTHON_ABI "0_28_2" +#define CYTHON_FUTURE_DIVISION 0 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #if PY_VERSION_HEX >= 0x02070000 + #define HAVE_LONG_LONG + #endif +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#ifdef PYPY_VERSION + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 +#elif defined(PYSTON_VERSION) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #elif !defined(CYTHON_USE_PYTYPE_LOOKUP) + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #elif !defined(CYTHON_USE_PYLONG_INTERNALS) + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT (0 && PY_VERSION_HEX >= 0x03050000) + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1) + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #include "longintrepr.h" + #undef SHIFT + #undef BASE + #undef MASK +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_MAYBE_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int32 uint32_t; + #endif + #endif +#else + #include +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) && __cplusplus >= 201103L + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #elif __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__ ) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) + #define Py_OptimizeFlag 0 +#endif +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) + #define __Pyx_DefaultClassType PyClass_Type +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) + #define __Pyx_DefaultClassType PyType_Type +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #define __Pyx_PyCFunctionFast _PyCFunctionFast + #define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords +#endif +#if CYTHON_FAST_PYCCALL +#define __Pyx_PyFastCFunction_Check(func)\ + ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS))))) +#else +#define __Pyx_PyFastCFunction_Check(func) 0 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_PYSTON + #define __Pyx_PyCode_HasFreeVars(co) PyCode_HasFreeVars(co) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if !CYTHON_FAST_THREAD_STATE || PY_VERSION_HEX < 0x02070000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; // PyThread_create_key reports success always +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif // TSS (Thread Specific Storage) API +#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStr(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +#else +#define __Pyx_PyDict_GetItemStr(dict, name) PyDict_GetItem(dict, name) +#endif +#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111) + #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains) + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) +#else + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t PyInt_AsLong +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) +#else + #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(WIN32) || defined(MS_WINDOWS) + #define _USE_MATH_DEFINES +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + + +#define __PYX_ERR(f_index, lineno, Ln_error) \ +{ \ + __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ +} + +#ifndef __PYX_EXTERN_C + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__mtrand +#define __PYX_HAVE_API__mtrand +/* Early includes */ +#include "string.h" +#include "math.h" +#include +#include +#include "numpy/npy_no_deprecated_api.h" +#include "numpy/arrayobject.h" +#include "numpy/npy_math.h" +#include "mtrand_py_helper.h" +#include "randomkit.h" +#include "distributions.h" +#include "initarray.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT 0 +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s)) +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) { + const Py_UNICODE *u_end = u; + while (*u_end++) ; + return (size_t)(u_end - u - 1); +} +#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u)) +#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False)) +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x)) +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c)); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +static PyObject *__pyx_m = NULL; +static PyObject *__pyx_d; +static PyObject *__pyx_b; +static PyObject *__pyx_cython_runtime; +static PyObject *__pyx_empty_tuple; +static PyObject *__pyx_empty_bytes; +static PyObject *__pyx_empty_unicode; +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm= __FILE__; +static const char *__pyx_filename; + + +static const char *__pyx_f[] = { + "mtrand.pyx", + "randint_helpers.pxi", + "numpy.pxd", + "type.pxd", +}; +/* NoFastGil.proto */ +#define __Pyx_PyGILState_Ensure PyGILState_Ensure +#define __Pyx_PyGILState_Release PyGILState_Release +#define __Pyx_FastGIL_Remember() +#define __Pyx_FastGIL_Forget() +#define __Pyx_FastGilFuncInit() + +/* ForceInitThreads.proto */ +#ifndef __PYX_FORCE_INIT_THREADS + #define __PYX_FORCE_INIT_THREADS 0 +#endif + + +/*--- Type declarations ---*/ +struct __pyx_obj_6mtrand_RandomState; + +/* "mtrand.pyx":126 + * long rk_logseries(rk_state *state, double p) nogil + * + * ctypedef double (* rk_cont0)(rk_state *state) nogil # <<<<<<<<<<<<<< + * ctypedef double (* rk_cont1)(rk_state *state, double a) nogil + * ctypedef double (* rk_cont2)(rk_state *state, double a, double b) nogil + */ +typedef double (*__pyx_t_6mtrand_rk_cont0)(rk_state *); + +/* "mtrand.pyx":127 + * + * ctypedef double (* rk_cont0)(rk_state *state) nogil + * ctypedef double (* rk_cont1)(rk_state *state, double a) nogil # <<<<<<<<<<<<<< + * ctypedef double (* rk_cont2)(rk_state *state, double a, double b) nogil + * ctypedef double (* rk_cont3)(rk_state *state, double a, double b, double c) nogil + */ +typedef double (*__pyx_t_6mtrand_rk_cont1)(rk_state *, double); + +/* "mtrand.pyx":128 + * ctypedef double (* rk_cont0)(rk_state *state) nogil + * ctypedef double (* rk_cont1)(rk_state *state, double a) nogil + * ctypedef double (* rk_cont2)(rk_state *state, double a, double b) nogil # <<<<<<<<<<<<<< + * ctypedef double (* rk_cont3)(rk_state *state, double a, double b, double c) nogil + * + */ +typedef double (*__pyx_t_6mtrand_rk_cont2)(rk_state *, double, double); + +/* "mtrand.pyx":129 + * ctypedef double (* rk_cont1)(rk_state *state, double a) nogil + * ctypedef double (* rk_cont2)(rk_state *state, double a, double b) nogil + * ctypedef double (* rk_cont3)(rk_state *state, double a, double b, double c) nogil # <<<<<<<<<<<<<< + * + * ctypedef long (* rk_disc0)(rk_state *state) nogil + */ +typedef double (*__pyx_t_6mtrand_rk_cont3)(rk_state *, double, double, double); + +/* "mtrand.pyx":131 + * ctypedef double (* rk_cont3)(rk_state *state, double a, double b, double c) nogil + * + * ctypedef long (* rk_disc0)(rk_state *state) nogil # <<<<<<<<<<<<<< + * ctypedef long (* rk_discnp)(rk_state *state, long n, double p) nogil + * ctypedef long (* rk_discdd)(rk_state *state, double n, double p) nogil + */ +typedef long (*__pyx_t_6mtrand_rk_disc0)(rk_state *); + +/* "mtrand.pyx":132 + * + * ctypedef long (* rk_disc0)(rk_state *state) nogil + * ctypedef long (* rk_discnp)(rk_state *state, long n, double p) nogil # <<<<<<<<<<<<<< + * ctypedef long (* rk_discdd)(rk_state *state, double n, double p) nogil + * ctypedef long (* rk_discnmN)(rk_state *state, long n, long m, long N) nogil + */ +typedef long (*__pyx_t_6mtrand_rk_discnp)(rk_state *, long, double); + +/* "mtrand.pyx":133 + * ctypedef long (* rk_disc0)(rk_state *state) nogil + * ctypedef long (* rk_discnp)(rk_state *state, long n, double p) nogil + * ctypedef long (* rk_discdd)(rk_state *state, double n, double p) nogil # <<<<<<<<<<<<<< + * ctypedef long (* rk_discnmN)(rk_state *state, long n, long m, long N) nogil + * ctypedef long (* rk_discd)(rk_state *state, double a) nogil + */ +typedef long (*__pyx_t_6mtrand_rk_discdd)(rk_state *, double, double); + +/* "mtrand.pyx":134 + * ctypedef long (* rk_discnp)(rk_state *state, long n, double p) nogil + * ctypedef long (* rk_discdd)(rk_state *state, double n, double p) nogil + * ctypedef long (* rk_discnmN)(rk_state *state, long n, long m, long N) nogil # <<<<<<<<<<<<<< + * ctypedef long (* rk_discd)(rk_state *state, double a) nogil + * + */ +typedef long (*__pyx_t_6mtrand_rk_discnmN)(rk_state *, long, long, long); + +/* "mtrand.pyx":135 + * ctypedef long (* rk_discdd)(rk_state *state, double n, double p) nogil + * ctypedef long (* rk_discnmN)(rk_state *state, long n, long m, long N) nogil + * ctypedef long (* rk_discd)(rk_state *state, double a) nogil # <<<<<<<<<<<<<< + * + * + */ +typedef long (*__pyx_t_6mtrand_rk_discd)(rk_state *, double); + +/* "mtrand.pyx":593 + * + * + * cdef class RandomState: # <<<<<<<<<<<<<< + * """ + * RandomState(seed=None) + */ +struct __pyx_obj_6mtrand_RandomState { + PyObject_HEAD + struct __pyx_vtabstruct_6mtrand_RandomState *__pyx_vtab; + rk_state *internal_state; + PyObject *lock; + PyObject *state_address; +}; + + + +struct __pyx_vtabstruct_6mtrand_RandomState { + PyObject *(*_shuffle_raw)(struct __pyx_obj_6mtrand_RandomState *, npy_intp, npy_intp, npy_intp, char *, char *); +}; +static struct __pyx_vtabstruct_6mtrand_RandomState *__pyx_vtabptr_6mtrand_RandomState; +static CYTHON_INLINE PyObject *__pyx_f_6mtrand_11RandomState__shuffle_raw(struct __pyx_obj_6mtrand_RandomState *, npy_intp, npy_intp, npy_intp, char *, char *); + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, int); + void (*DECREF)(void*, PyObject*, int); + void (*GOTREF)(void*, PyObject*, int); + void (*GIVEREF)(void*, PyObject*, int); + void* (*SetupContext)(const char*, int, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) +#endif + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\ + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\ + const char* function_name); + +/* GetModuleGlobalName.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name); + +/* PyCFunctionFastCall.proto */ +#if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); +#else +#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) +#endif + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs); +#else +#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) +#endif +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#define __Pyx_PyErr_Occurred() __pyx_tstate->curexc_type +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() PyErr_Occurred() +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* PyObjectLookupSpecial.proto */ +#if CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_LookupSpecial(PyObject* obj, PyObject* attr_name) { + PyObject *res; + PyTypeObject *tp = Py_TYPE(obj); +#if PY_MAJOR_VERSION < 3 + if (unlikely(PyInstance_Check(obj))) + return __Pyx_PyObject_GetAttrStr(obj, attr_name); +#endif + res = _PyType_Lookup(tp, attr_name); + if (likely(res)) { + descrgetfunc f = Py_TYPE(res)->tp_descr_get; + if (!f) { + Py_INCREF(res); + } else { + res = f(res, obj, (PyObject *)tp); + } + } else { + PyErr_SetObject(PyExc_AttributeError, attr_name); + } + return res; +} +#else +#define __Pyx_PyObject_LookupSpecial(o,n) __Pyx_PyObject_GetAttrStr(o,n) +#endif + +/* PyObjectCallNoArg.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); +#else +#define __Pyx_PyObject_CallNoArg(func) __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL) +#endif + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* PyIntBinop.proto */ +#if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_PyInt_EqObjC(PyObject *op1, PyObject *op2, long intval, int inplace); +#else +#define __Pyx_PyInt_EqObjC(op1, op2, intval, inplace)\ + PyObject_RichCompare(op1, op2, Py_EQ) + #endif + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* IncludeStringH.proto */ +#include + +/* BytesEquals.proto */ +static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); + +/* UnicodeEquals.proto */ +static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); + +/* StrEquals.proto */ +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyString_Equals __Pyx_PyUnicode_Equals +#else +#define __Pyx_PyString_Equals __Pyx_PyBytes_Equals +#endif + +/* SliceObject.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice( + PyObject* obj, Py_ssize_t cstart, Py_ssize_t cstop, + PyObject** py_start, PyObject** py_stop, PyObject** py_slice, + int has_cstart, int has_cstop, int wraparound); + +/* RaiseTooManyValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); + +/* RaiseNeedMoreValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); + +/* IterFinish.proto */ +static CYTHON_INLINE int __Pyx_IterFinish(void); + +/* UnpackItemEndCheck.proto */ +static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); + +/* PySequenceContains.proto */ +static CYTHON_INLINE int __Pyx_PySequence_ContainsTF(PyObject* item, PyObject* seq, int eq) { + int result = PySequence_Contains(seq, item); + return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); +} + +/* ObjectGetItem.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject* key); +#else +#define __Pyx_PyObject_GetItem(obj, key) PyObject_GetItem(obj, key) +#endif + +/* PyIntBinop.proto */ +#if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_PyInt_SubtractObjC(PyObject *op1, PyObject *op2, long intval, int inplace); +#else +#define __Pyx_PyInt_SubtractObjC(op1, op2, intval, inplace)\ + (inplace ? PyNumber_InPlaceSubtract(op1, op2) : PyNumber_Subtract(op1, op2)) +#endif + +/* SliceObject.proto */ +#define __Pyx_PyObject_DelSlice(obj, cstart, cstop, py_start, py_stop, py_slice, has_cstart, has_cstop, wraparound)\ + __Pyx_PyObject_SetSlice(obj, (PyObject*)NULL, cstart, cstop, py_start, py_stop, py_slice, has_cstart, has_cstop, wraparound) +static CYTHON_INLINE int __Pyx_PyObject_SetSlice( + PyObject* obj, PyObject* value, Py_ssize_t cstart, Py_ssize_t cstop, + PyObject** py_start, PyObject** py_stop, PyObject** py_slice, + int has_cstart, int has_cstop, int wraparound); + +/* PyObjectSetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +#define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o, n, NULL) +static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value); +#else +#define __Pyx_PyObject_DelAttrStr(o,n) PyObject_DelAttr(o,n) +#define __Pyx_PyObject_SetAttrStr(o,n,v) PyObject_SetAttr(o,n,v) +#endif + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kwdict, const char* function_name, int kw_allowed); + +/* PyIntBinop.proto */ +#if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace); +#else +#define __Pyx_PyInt_AddObjC(op1, op2, intval, inplace)\ + (inplace ? PyNumber_InPlaceAdd(op1, op2) : PyNumber_Add(op1, op2)) +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + PyList_SET_ITEM(list, len, x); + Py_SIZE(list) = len+1; + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* SetItemInt.proto */ +#define __Pyx_SetItemInt(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_SetItemInt_Fast(o, (Py_ssize_t)i, v, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list assignment index out of range"), -1) :\ + __Pyx_SetItemInt_Generic(o, to_py_func(i), v))) +static int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v); +static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, + int is_list, int wraparound, int boundscheck); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* SetVTable.proto */ +static int __Pyx_SetVtable(PyObject *dict, void *vtable); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_bool(npy_bool value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_int8(npy_int8 value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_int16(npy_int16 value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_int32(npy_int32 value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_int64(npy_int64 value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_uint8(npy_uint8 value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_uint16(npy_uint16 value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_uint32(npy_uint32 value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_uint64(npy_uint64 value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_intp(npy_intp value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_intp __Pyx_PyInt_As_npy_intp(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_bool __Pyx_PyInt_As_npy_bool(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_uint8 __Pyx_PyInt_As_npy_uint8(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_int8 __Pyx_PyInt_As_npy_int8(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_uint16 __Pyx_PyInt_As_npy_uint16(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_int16 __Pyx_PyInt_As_npy_int16(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_uint32 __Pyx_PyInt_As_npy_uint32(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_int32 __Pyx_PyInt_As_npy_int32(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_uint64 __Pyx_PyInt_As_npy_uint64(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE npy_int64 __Pyx_PyInt_As_npy_int64(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE unsigned long __Pyx_PyInt_As_unsigned_long(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* CheckBinaryVersion.proto */ +static int __Pyx_check_binary_version(void); + +/* PyIdentifierFromString.proto */ +#if !defined(__Pyx_PyIdentifier_FromString) +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyIdentifier_FromString(s) PyString_FromString(s) +#else + #define __Pyx_PyIdentifier_FromString(s) PyUnicode_FromString(s) +#endif +#endif + +/* ModuleImport.proto */ +static PyObject *__Pyx_ImportModule(const char *name); + +/* TypeImport.proto */ +static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name, size_t size, int strict); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + +static CYTHON_INLINE PyObject *__pyx_f_6mtrand_11RandomState__shuffle_raw(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, npy_intp __pyx_v_n, npy_intp __pyx_v_itemsize, npy_intp __pyx_v_stride, char *__pyx_v_data, char *__pyx_v_buf); /* proto*/ + +/* Module declarations from 'libc.string' */ + +/* Module declarations from 'libc.stdio' */ + +/* Module declarations from '__builtin__' */ + +/* Module declarations from 'cpython.type' */ +static PyTypeObject *__pyx_ptype_7cpython_4type_type = 0; + +/* Module declarations from 'cpython' */ + +/* Module declarations from 'cpython.object' */ + +/* Module declarations from 'cpython.exc' */ + +/* Module declarations from 'numpy' */ + +/* Module declarations from 'libc' */ + +/* Module declarations from 'cython' */ + +/* Module declarations from 'mtrand' */ +static PyTypeObject *__pyx_ptype_6mtrand_dtype = 0; +static PyTypeObject *__pyx_ptype_6mtrand_ndarray = 0; +static PyTypeObject *__pyx_ptype_6mtrand_flatiter = 0; +static PyTypeObject *__pyx_ptype_6mtrand_broadcast = 0; +static PyTypeObject *__pyx_ptype_6mtrand_RandomState = 0; +static CYTHON_INLINE int __pyx_f_6mtrand_import_array(void); /*proto*/ +static PyObject *__pyx_f_6mtrand_cont0_array(rk_state *, __pyx_t_6mtrand_rk_cont0, PyObject *, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_cont1_array_sc(rk_state *, __pyx_t_6mtrand_rk_cont1, PyObject *, double, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_cont1_array(rk_state *, __pyx_t_6mtrand_rk_cont1, PyObject *, PyArrayObject *, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_cont2_array_sc(rk_state *, __pyx_t_6mtrand_rk_cont2, PyObject *, double, double, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_cont2_array(rk_state *, __pyx_t_6mtrand_rk_cont2, PyObject *, PyArrayObject *, PyArrayObject *, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_cont3_array_sc(rk_state *, __pyx_t_6mtrand_rk_cont3, PyObject *, double, double, double, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_cont3_array(rk_state *, __pyx_t_6mtrand_rk_cont3, PyObject *, PyArrayObject *, PyArrayObject *, PyArrayObject *, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_disc0_array(rk_state *, __pyx_t_6mtrand_rk_disc0, PyObject *, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_discnp_array_sc(rk_state *, __pyx_t_6mtrand_rk_discnp, PyObject *, long, double, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_discnp_array(rk_state *, __pyx_t_6mtrand_rk_discnp, PyObject *, PyArrayObject *, PyArrayObject *, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_discdd_array_sc(rk_state *, __pyx_t_6mtrand_rk_discdd, PyObject *, double, double, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_discdd_array(rk_state *, __pyx_t_6mtrand_rk_discdd, PyObject *, PyArrayObject *, PyArrayObject *, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_discnmN_array_sc(rk_state *, __pyx_t_6mtrand_rk_discnmN, PyObject *, long, long, long, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_discnmN_array(rk_state *, __pyx_t_6mtrand_rk_discnmN, PyObject *, PyArrayObject *, PyArrayObject *, PyArrayObject *, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_discd_array_sc(rk_state *, __pyx_t_6mtrand_rk_discd, PyObject *, double, PyObject *); /*proto*/ +static PyObject *__pyx_f_6mtrand_discd_array(rk_state *, __pyx_t_6mtrand_rk_discd, PyObject *, PyArrayObject *, PyObject *); /*proto*/ +static double __pyx_f_6mtrand_kahan_sum(double *, npy_intp); /*proto*/ +#define __Pyx_MODULE_NAME "mtrand" +extern int __pyx_module_is_main_mtrand; +int __pyx_module_is_main_mtrand = 0; + +/* Implementation of 'mtrand' */ +static PyObject *__pyx_builtin_ImportError; +static PyObject *__pyx_builtin_ValueError; +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_TypeError; +static PyObject *__pyx_builtin_OverflowError; +static PyObject *__pyx_builtin_DeprecationWarning; +static PyObject *__pyx_builtin_RuntimeWarning; +static PyObject *__pyx_builtin_reversed; +static const char __pyx_k_L[] = "L"; +static const char __pyx_k_T[] = "T"; +static const char __pyx_k_a[] = "a"; +static const char __pyx_k_b[] = "b"; +static const char __pyx_k_d[] = "d"; +static const char __pyx_k_f[] = "f"; +static const char __pyx_k_l[] = "l"; +static const char __pyx_k_n[] = "n"; +static const char __pyx_k_p[] = "p"; +static const char __pyx_k_df[] = "df"; +static const char __pyx_k_mu[] = "mu"; +static const char __pyx_k_np[] = "np"; +static const char __pyx_k_a_0[] = "a <= 0"; +static const char __pyx_k_add[] = "add"; +static const char __pyx_k_all[] = "all"; +static const char __pyx_k_any[] = "any"; +static const char __pyx_k_b_0[] = "b <= 0"; +static const char __pyx_k_buf[] = "buf"; +static const char __pyx_k_cnt[] = "cnt"; +static const char __pyx_k_cov[] = "cov"; +static const char __pyx_k_dot[] = "dot"; +static const char __pyx_k_eps[] = "eps"; +static const char __pyx_k_int[] = "int"; +static const char __pyx_k_lam[] = "lam"; +static const char __pyx_k_loc[] = "loc"; +static const char __pyx_k_low[] = "low"; +static const char __pyx_k_max[] = "max"; +static const char __pyx_k_n_0[] = "n < 0"; +static const char __pyx_k_off[] = "off"; +static const char __pyx_k_out[] = "out"; +static const char __pyx_k_p_0[] = "p < 0"; +static const char __pyx_k_p_1[] = "p > 1"; +static const char __pyx_k_rng[] = "rng"; +static const char __pyx_k_svd[] = "svd"; +static const char __pyx_k_tol[] = "tol"; +static const char __pyx_k_Lock[] = "Lock"; +static const char __pyx_k_atol[] = "atol"; +static const char __pyx_k_beta[] = "beta"; +static const char __pyx_k_bool[] = "bool_"; +static const char __pyx_k_copy[] = "copy"; +static const char __pyx_k_data[] = "data"; +static const char __pyx_k_df_0[] = "df <= 0"; +static const char __pyx_k_exit[] = "__exit__"; +static const char __pyx_k_high[] = "high"; +static const char __pyx_k_int8[] = "int8"; +static const char __pyx_k_intp[] = "intp"; +static const char __pyx_k_item[] = "item"; +static const char __pyx_k_left[] = "left"; +static const char __pyx_k_less[] = "less"; +static const char __pyx_k_long[] = "long"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_mean[] = "mean"; +static const char __pyx_k_mode[] = "mode"; +static const char __pyx_k_name[] = "name"; +static const char __pyx_k_nbad[] = "nbad"; +static const char __pyx_k_ndim[] = "ndim"; +static const char __pyx_k_nonc[] = "nonc"; +static const char __pyx_k_prod[] = "prod"; +static const char __pyx_k_rand[] = "rand"; +static const char __pyx_k_rtol[] = "rtol"; +static const char __pyx_k_safe[] = "safe"; +static const char __pyx_k_seed[] = "seed"; +static const char __pyx_k_side[] = "side"; +static const char __pyx_k_size[] = "size"; +static const char __pyx_k_sort[] = "sort"; +static const char __pyx_k_sqrt[] = "sqrt"; +static const char __pyx_k_take[] = "take"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_uint[] = "uint"; +static const char __pyx_k_wald[] = "wald"; +static const char __pyx_k_warn[] = "warn"; +static const char __pyx_k_zipf[] = "zipf"; +static const char __pyx_k_a_0_2[] = "a < 0"; +static const char __pyx_k_alpha[] = "alpha"; +static const char __pyx_k_array[] = "array"; +static const char __pyx_k_bytes[] = "bytes"; +static const char __pyx_k_dfden[] = "dfden"; +static const char __pyx_k_dfnum[] = "dfnum"; +static const char __pyx_k_dtype[] = "dtype"; +static const char __pyx_k_empty[] = "empty"; +static const char __pyx_k_enter[] = "__enter__"; +static const char __pyx_k_equal[] = "equal"; +static const char __pyx_k_finfo[] = "finfo"; +static const char __pyx_k_gamma[] = "gamma"; +static const char __pyx_k_iinfo[] = "iinfo"; +static const char __pyx_k_index[] = "index"; +static const char __pyx_k_int16[] = "int16"; +static const char __pyx_k_int32[] = "int32"; +static const char __pyx_k_int64[] = "int64"; +static const char __pyx_k_isnan[] = "isnan"; +static const char __pyx_k_kappa[] = "kappa"; +static const char __pyx_k_lam_0[] = "lam < 0"; +static const char __pyx_k_n_0_2[] = "n <= 0"; +static const char __pyx_k_ngood[] = "ngood"; +static const char __pyx_k_numpy[] = "numpy"; +static const char __pyx_k_p_0_0[] = "p < 0.0"; +static const char __pyx_k_p_1_0[] = "p > 1.0"; +static const char __pyx_k_power[] = "power"; +static const char __pyx_k_pvals[] = "pvals"; +static const char __pyx_k_raise[] = "raise"; +static const char __pyx_k_randn[] = "randn"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_ravel[] = "ravel"; +static const char __pyx_k_right[] = "right"; +static const char __pyx_k_scale[] = "scale"; +static const char __pyx_k_shape[] = "shape"; +static const char __pyx_k_sigma[] = "sigma"; +static const char __pyx_k_state[] = "state"; +static const char __pyx_k_uint8[] = "uint8"; +static const char __pyx_k_zeros[] = "zeros"; +static const char __pyx_k_arange[] = "arange"; +static const char __pyx_k_astype[] = "astype"; +static const char __pyx_k_bool_2[] = "bool"; +static const char __pyx_k_choice[] = "choice"; +static const char __pyx_k_ctypes[] = "ctypes"; +static const char __pyx_k_cumsum[] = "cumsum"; +static const char __pyx_k_format[] = "format"; +static const char __pyx_k_gumbel[] = "gumbel"; +static const char __pyx_k_ignore[] = "ignore"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_mean_0[] = "mean <= 0"; +static const char __pyx_k_mtrand[] = "mtrand"; +static const char __pyx_k_nbad_0[] = "nbad < 0"; +static const char __pyx_k_nonc_0[] = "nonc < 0"; +static const char __pyx_k_normal[] = "normal"; +static const char __pyx_k_pareto[] = "pareto"; +static const char __pyx_k_rand_2[] = "_rand"; +static const char __pyx_k_random[] = "random"; +static const char __pyx_k_reduce[] = "reduce"; +static const char __pyx_k_uint16[] = "uint16"; +static const char __pyx_k_uint32[] = "uint32"; +static const char __pyx_k_uint64[] = "uint64"; +static const char __pyx_k_unique[] = "unique"; +static const char __pyx_k_unsafe[] = "unsafe"; +static const char __pyx_k_MT19937[] = "MT19937"; +static const char __pyx_k_alpha_0[] = "alpha <= 0"; +static const char __pyx_k_asarray[] = "asarray"; +static const char __pyx_k_casting[] = "casting"; +static const char __pyx_k_dfden_0[] = "dfden <= 0"; +static const char __pyx_k_dfnum_0[] = "dfnum <= 0"; +static const char __pyx_k_float64[] = "float64"; +static const char __pyx_k_greater[] = "greater"; +static const char __pyx_k_integer[] = "integer"; +static const char __pyx_k_kappa_0[] = "kappa < 0"; +static const char __pyx_k_laplace[] = "laplace"; +static const char __pyx_k_ndarray[] = "ndarray"; +static const char __pyx_k_ngood_0[] = "ngood < 0"; +static const char __pyx_k_nsample[] = "nsample"; +static const char __pyx_k_p_0_0_2[] = "p <= 0.0"; +static const char __pyx_k_p_1_0_2[] = "p >= 1.0"; +static const char __pyx_k_poisson[] = "poisson"; +static const char __pyx_k_randint[] = "randint"; +static const char __pyx_k_replace[] = "replace"; +static const char __pyx_k_reshape[] = "reshape"; +static const char __pyx_k_scale_0[] = "scale < 0"; +static const char __pyx_k_shape_0[] = "shape < 0"; +static const char __pyx_k_shuffle[] = "shuffle"; +static const char __pyx_k_sigma_0[] = "sigma < 0"; +static const char __pyx_k_signbit[] = "signbit"; +static const char __pyx_k_strides[] = "strides"; +static const char __pyx_k_uniform[] = "uniform"; +static const char __pyx_k_weibull[] = "weibull"; +static const char __pyx_k_allclose[] = "allclose"; +static const char __pyx_k_binomial[] = "binomial"; +static const char __pyx_k_floating[] = "floating"; +static const char __pyx_k_isfinite[] = "isfinite"; +static const char __pyx_k_itemsize[] = "itemsize"; +static const char __pyx_k_logistic[] = "logistic"; +static const char __pyx_k_low_high[] = "low >= high"; +static const char __pyx_k_mean_0_0[] = "mean <= 0.0"; +static const char __pyx_k_operator[] = "operator"; +static const char __pyx_k_p_is_nan[] = "p is nan"; +static const char __pyx_k_rayleigh[] = "rayleigh"; +static const char __pyx_k_reversed[] = "reversed"; +static const char __pyx_k_rngstate[] = "rngstate"; +static const char __pyx_k_subtract[] = "subtract"; +static const char __pyx_k_vonmises[] = "vonmises"; +static const char __pyx_k_warnings[] = "warnings"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_broadcast[] = "broadcast"; +static const char __pyx_k_chisquare[] = "chisquare"; +static const char __pyx_k_dirichlet[] = "dirichlet"; +static const char __pyx_k_geometric[] = "geometric"; +static const char __pyx_k_get_state[] = "get_state"; +static const char __pyx_k_left_mode[] = "left > mode"; +static const char __pyx_k_lognormal[] = "lognormal"; +static const char __pyx_k_logseries[] = "logseries"; +static const char __pyx_k_nsample_1[] = "nsample < 1"; +static const char __pyx_k_rand_bool[] = "_rand_bool"; +static const char __pyx_k_rand_int8[] = "_rand_int8"; +static const char __pyx_k_scale_0_0[] = "scale < 0.0"; +static const char __pyx_k_scale_0_2[] = "scale <= 0"; +static const char __pyx_k_set_state[] = "set_state"; +static const char __pyx_k_sigma_0_0[] = "sigma < 0.0"; +static const char __pyx_k_threading[] = "threading"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_array_data[] = "array_data"; +static const char __pyx_k_empty_like[] = "empty_like"; +static const char __pyx_k_issubdtype[] = "issubdtype"; +static const char __pyx_k_left_right[] = "left == right"; +static const char __pyx_k_less_equal[] = "less_equal"; +static const char __pyx_k_logical_or[] = "logical_or"; +static const char __pyx_k_mode_right[] = "mode > right"; +static const char __pyx_k_mtrand_pyx[] = "mtrand.pyx"; +static const char __pyx_k_numpy_dual[] = "numpy.dual"; +static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; +static const char __pyx_k_rand_int16[] = "_rand_int16"; +static const char __pyx_k_rand_int32[] = "_rand_int32"; +static const char __pyx_k_rand_int64[] = "_rand_int64"; +static const char __pyx_k_rand_uint8[] = "_rand_uint8"; +static const char __pyx_k_standard_t[] = "standard_t"; +static const char __pyx_k_triangular[] = "triangular"; +static const char __pyx_k_ImportError[] = "ImportError"; +static const char __pyx_k_check_valid[] = "check_valid"; +static const char __pyx_k_exponential[] = "exponential"; +static const char __pyx_k_multinomial[] = "multinomial"; +static const char __pyx_k_permutation[] = "permutation"; +static const char __pyx_k_rand_uint16[] = "_rand_uint16"; +static const char __pyx_k_rand_uint32[] = "_rand_uint32"; +static const char __pyx_k_rand_uint64[] = "_rand_uint64"; +static const char __pyx_k_scale_0_0_2[] = "scale <= 0.0"; +static const char __pyx_k_noncentral_f[] = "noncentral_f"; +static const char __pyx_k_randint_type[] = "_randint_type"; +static const char __pyx_k_return_index[] = "return_index"; +static const char __pyx_k_searchsorted[] = "searchsorted"; +static const char __pyx_k_OverflowError[] = "OverflowError"; +static const char __pyx_k_count_nonzero[] = "count_nonzero"; +static const char __pyx_k_greater_equal[] = "greater_equal"; +static const char __pyx_k_random_sample[] = "random_sample"; +static const char __pyx_k_RuntimeWarning[] = "RuntimeWarning"; +static const char __pyx_k_hypergeometric[] = "hypergeometric"; +static const char __pyx_k_standard_gamma[] = "standard_gamma"; +static const char __pyx_k_dummy_threading[] = "dummy_threading"; +static const char __pyx_k_poisson_lam_max[] = "poisson_lam_max"; +static const char __pyx_k_random_integers[] = "random_integers"; +static const char __pyx_k_shape_from_size[] = "_shape_from_size"; +static const char __pyx_k_standard_cauchy[] = "standard_cauchy"; +static const char __pyx_k_standard_normal[] = "standard_normal"; +static const char __pyx_k_sum_pvals_1_1_0[] = "sum(pvals[:-1]) > 1.0"; +static const char __pyx_k_RandomState_ctor[] = "__RandomState_ctor"; +static const char __pyx_k_negative_binomial[] = "negative_binomial"; +static const char __pyx_k_DeprecationWarning[] = "DeprecationWarning"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_ngood_nbad_nsample[] = "ngood + nbad < nsample"; +static const char __pyx_k_a_must_be_non_empty[] = "a must be non-empty"; +static const char __pyx_k_lam_value_too_large[] = "lam value too large"; +static const char __pyx_k_multivariate_normal[] = "multivariate_normal"; +static const char __pyx_k_randint_helpers_pxi[] = "randint_helpers.pxi"; +static const char __pyx_k_noncentral_chisquare[] = "noncentral_chisquare"; +static const char __pyx_k_standard_exponential[] = "standard_exponential"; +static const char __pyx_k_lam_value_too_large_2[] = "lam value too large."; +static const char __pyx_k_Seed_array_must_be_1_d[] = "Seed array must be 1-d"; +static const char __pyx_k_Seed_must_be_non_empty[] = "Seed must be non-empty"; +static const char __pyx_k_RandomState_f_line_1997[] = "RandomState.f (line 1997)"; +static const char __pyx_k_a_must_be_1_dimensional[] = "a must be 1-dimensional"; +static const char __pyx_k_p_must_be_1_dimensional[] = "p must be 1-dimensional"; +static const char __pyx_k_state_must_be_624_longs[] = "state must be 624 longs"; +static const char __pyx_k_a_must_be_greater_than_0[] = "a must be greater than 0"; +static const char __pyx_k_algorithm_must_be_MT19937[] = "algorithm must be 'MT19937'"; +static const char __pyx_k_RandomState_rand_line_1321[] = "RandomState.rand (line 1321)"; +static const char __pyx_k_RandomState_wald_line_3516[] = "RandomState.wald (line 3516)"; +static const char __pyx_k_RandomState_zipf_line_4002[] = "RandomState.zipf (line 4002)"; +static const char __pyx_k_Range_exceeds_valid_bounds[] = "Range exceeds valid bounds"; +static const char __pyx_k_low_is_out_of_bounds_for_s[] = "low is out of bounds for %s"; +static const char __pyx_k_mean_must_be_1_dimensional[] = "mean must be 1 dimensional"; +static const char __pyx_k_RandomState_bytes_line_1004[] = "RandomState.bytes (line 1004)"; +static const char __pyx_k_RandomState_gamma_line_1901[] = "RandomState.gamma (line 1901)"; +static const char __pyx_k_RandomState_power_line_2880[] = "RandomState.power (line 2880)"; +static const char __pyx_k_RandomState_randn_line_1365[] = "RandomState.randn (line 1365)"; +static const char __pyx_k_a_and_p_must_have_same_size[] = "a and p must have same size"; +static const char __pyx_k_a_must_be_a_valid_float_1_0[] = "'a' must be a valid float > 1.0"; +static const char __pyx_k_high_is_out_of_bounds_for_s[] = "high is out of bounds for %s"; +static const char __pyx_k_RandomState_choice_line_1033[] = "RandomState.choice (line 1033)"; +static const char __pyx_k_RandomState_gumbel_line_3089[] = "RandomState.gumbel (line 3089)"; +static const char __pyx_k_RandomState_normal_line_1552[] = "RandomState.normal (line 1552)"; +static const char __pyx_k_RandomState_pareto_line_2660[] = "RandomState.pareto (line 2660)"; +static const char __pyx_k_RandomState_randint_line_910[] = "RandomState.randint (line 910)"; +static const char __pyx_k_RandomState_laplace_line_2991[] = "RandomState.laplace (line 2991)"; +static const char __pyx_k_RandomState_poisson_line_3914[] = "RandomState.poisson (line 3914)"; +static const char __pyx_k_RandomState_shuffle_line_4779[] = "RandomState.shuffle (line 4779)"; +static const char __pyx_k_RandomState_tomaxint_line_863[] = "RandomState.tomaxint (line 863)"; +static const char __pyx_k_RandomState_uniform_line_1215[] = "RandomState.uniform (line 1215)"; +static const char __pyx_k_RandomState_weibull_line_2770[] = "RandomState.weibull (line 2770)"; +static const char __pyx_k_probabilities_do_not_sum_to_1[] = "probabilities do not sum to 1"; +static const char __pyx_k_RandomState_binomial_line_3697[] = "RandomState.binomial (line 3697)"; +static const char __pyx_k_RandomState_logistic_line_3220[] = "RandomState.logistic (line 3220)"; +static const char __pyx_k_RandomState_rayleigh_line_3437[] = "RandomState.rayleigh (line 3437)"; +static const char __pyx_k_RandomState_vonmises_line_2562[] = "RandomState.vonmises (line 2562)"; +static const char __pyx_k_dirichlet_alpha_size_None_Draw[] = "\n dirichlet(alpha, size=None)\n\n Draw samples from the Dirichlet distribution.\n\n Draw `size` samples of dimension k from a Dirichlet distribution. A\n Dirichlet-distributed random variable can be seen as a multivariate\n generalization of a Beta distribution. Dirichlet pdf is the conjugate\n prior of a multinomial in Bayesian inference.\n\n Parameters\n ----------\n alpha : array\n Parameter of the distribution (k dimension for sample of\n dimension k).\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n samples : ndarray,\n The drawn samples, of shape (size, alpha.ndim).\n\n Raises\n -------\n ValueError\n If any value in alpha is less than or equal to zero\n\n Notes\n -----\n .. math:: X \\approx \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}\n\n Uses the following property for computation: for each dimension,\n draw a random sample y_i from a standard gamma generator of shape\n `alpha_i`, then\n :math:`X = \\frac{1}{\\sum_{i=1}^k{y_i}} (y_1, \\ldots, y_n)` is\n Dirichlet distributed.\n\n References\n ----------\n .. [1] David McKay, \"Information Theory, Inference and Learning\n Algorithms,\" chapter 23,\n http://www.inference.phy.cam.ac.uk/mackay/\n .. [2] Wikipedia, \"Dirichlet distribution\",\n http://en.wikipedia.org/wiki/Dirichlet_distribution\n\n Examples\n --------\n Taking an example cited in Wikipedia, this distribution can be used if\n one wanted to cut strings (each of initial length 1.0) into K pieces\n with different lengths, where each piece"" had, on average, a designated\n average length, but allowing some variation in the relative sizes of\n the pieces.\n\n >>> s = np.random.dirichlet((10, 5, 3), 20).transpose()\n\n >>> plt.barh(range(20), s[0])\n >>> plt.barh(range(20), s[1], left=s[0], color='g')\n >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r')\n >>> plt.title(\"Lengths of Strings\")\n\n "; +static const char __pyx_k_laplace_loc_0_0_scale_1_0_size[] = "\n laplace(loc=0.0, scale=1.0, size=None)\n\n Draw samples from the Laplace or double exponential distribution with\n specified location (or mean) and scale (decay).\n\n The Laplace distribution is similar to the Gaussian/normal distribution,\n but is sharper at the peak and has fatter tails. It represents the\n difference between two independent, identically distributed exponential\n random variables.\n\n Parameters\n ----------\n loc : float or array_like of floats, optional\n The position, :math:`\\mu`, of the distribution peak. Default is 0.\n scale : float or array_like of floats, optional\n :math:`\\lambda`, the exponential decay. Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``loc`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Laplace distribution.\n\n Notes\n -----\n It has the probability density function\n\n .. math:: f(x; \\mu, \\lambda) = \\frac{1}{2\\lambda}\n \\exp\\left(-\\frac{|x - \\mu|}{\\lambda}\\right).\n\n The first law of Laplace, from 1774, states that the frequency\n of an error can be expressed as an exponential function of the\n absolute magnitude of the error, which leads to the Laplace\n distribution. For many problems in economics and health\n sciences, this distribution seems to model the data better\n than the standard Gaussian distribution.\n\n References\n ----------\n .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). \"Han""dbook of\n Mathematical Functions with Formulas, Graphs, and Mathematical\n Tables, 9th printing,\" New York: Dover, 1972.\n .. [2] Kotz, Samuel, et. al. \"The Laplace Distribution and\n Generalizations, \" Birkhauser, 2001.\n .. [3] Weisstein, Eric W. \"Laplace Distribution.\"\n From MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/LaplaceDistribution.html\n .. [4] Wikipedia, \"Laplace distribution\",\n http://en.wikipedia.org/wiki/Laplace_distribution\n\n Examples\n --------\n Draw samples from the distribution\n\n >>> loc, scale = 0., 1.\n >>> s = np.random.laplace(loc, scale, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 30, normed=True)\n >>> x = np.arange(-8., 8., .01)\n >>> pdf = np.exp(-abs(x-loc)/scale)/(2.*scale)\n >>> plt.plot(x, pdf)\n\n Plot Gaussian for comparison:\n\n >>> g = (1/(scale * np.sqrt(2 * np.pi)) *\n ... np.exp(-(x - loc)**2 / (2 * scale**2)))\n >>> plt.plot(x,g)\n\n "; +static const char __pyx_k_permutation_x_Randomly_permute[] = "\n permutation(x)\n\n Randomly permute a sequence, or return a permuted range.\n\n If `x` is a multi-dimensional array, it is only shuffled along its\n first index.\n\n Parameters\n ----------\n x : int or array_like\n If `x` is an integer, randomly permute ``np.arange(x)``.\n If `x` is an array, make a copy and shuffle the elements\n randomly.\n\n Returns\n -------\n out : ndarray\n Permuted sequence or array range.\n\n Examples\n --------\n >>> np.random.permutation(10)\n array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6])\n\n >>> np.random.permutation([1, 4, 9, 12, 15])\n array([15, 1, 9, 4, 12])\n\n >>> arr = np.arange(9).reshape((3, 3))\n >>> np.random.permutation(arr)\n array([[6, 7, 8],\n [0, 1, 2],\n [3, 4, 5]])\n\n "; +static const char __pyx_k_poisson_lam_1_0_size_None_Draw[] = "\n poisson(lam=1.0, size=None)\n\n Draw samples from a Poisson distribution.\n\n The Poisson distribution is the limit of the binomial distribution\n for large N.\n\n Parameters\n ----------\n lam : float or array_like of floats\n Expectation of interval, should be >= 0. A sequence of expectation\n intervals must be broadcastable over the requested size.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``lam`` is a scalar. Otherwise,\n ``np.array(lam).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Poisson distribution.\n\n Notes\n -----\n The Poisson distribution\n\n .. math:: f(k; \\lambda)=\\frac{\\lambda^k e^{-\\lambda}}{k!}\n\n For events with an expected separation :math:`\\lambda` the Poisson\n distribution :math:`f(k; \\lambda)` describes the probability of\n :math:`k` events occurring within the observed\n interval :math:`\\lambda`.\n\n Because the output is limited to the range of the C long type, a\n ValueError is raised when `lam` is within 10 sigma of the maximum\n representable value.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Poisson Distribution.\"\n From MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/PoissonDistribution.html\n .. [2] Wikipedia, \"Poisson distribution\",\n http://en.wikipedia.org/wiki/Poisson_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> import numpy as np\n >>> s = np.random.poisson(5, 10000)\n\n Display histo""gram of the sample:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 14, normed=True)\n >>> plt.show()\n\n Draw each 100 values for lambda 100 and 500:\n\n >>> s = np.random.poisson(lam=(100., 500.), size=(100, 2))\n\n "; +static const char __pyx_k_rand_d0_d1_dn_Random_values_in[] = "\n rand(d0, d1, ..., dn)\n\n Random values in a given shape.\n\n Create an array of the given shape and populate it with\n random samples from a uniform distribution\n over ``[0, 1)``.\n\n Parameters\n ----------\n d0, d1, ..., dn : int, optional\n The dimensions of the returned array, should all be positive.\n If no argument is given a single Python float is returned.\n\n Returns\n -------\n out : ndarray, shape ``(d0, d1, ..., dn)``\n Random values.\n\n See Also\n --------\n random\n\n Notes\n -----\n This is a convenience function. If you want an interface that\n takes a shape-tuple as the first argument, refer to\n np.random.random_sample .\n\n Examples\n --------\n >>> np.random.rand(3,2)\n array([[ 0.14022471, 0.96360618], #random\n [ 0.37601032, 0.25528411], #random\n [ 0.49313049, 0.94909878]]) #random\n\n "; +static const char __pyx_k_randn_d0_d1_dn_Return_a_sample[] = "\n randn(d0, d1, ..., dn)\n\n Return a sample (or samples) from the \"standard normal\" distribution.\n\n If positive, int_like or int-convertible arguments are provided,\n `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled\n with random floats sampled from a univariate \"normal\" (Gaussian)\n distribution of mean 0 and variance 1 (if any of the :math:`d_i` are\n floats, they are first converted to integers by truncation). A single\n float randomly sampled from the distribution is returned if no\n argument is provided.\n\n This is a convenience function. If you want an interface that takes a\n tuple as the first argument, use `numpy.random.standard_normal` instead.\n\n Parameters\n ----------\n d0, d1, ..., dn : int, optional\n The dimensions of the returned array, should be all positive.\n If no argument is given a single Python float is returned.\n\n Returns\n -------\n Z : ndarray or float\n A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from\n the standard normal distribution, or a single such float if\n no parameters were supplied.\n\n See Also\n --------\n random.standard_normal : Similar, but takes a tuple as its argument.\n\n Notes\n -----\n For random samples from :math:`N(\\mu, \\sigma^2)`, use:\n\n ``sigma * np.random.randn(...) + mu``\n\n Examples\n --------\n >>> np.random.randn()\n 2.1923875335537315 #random\n\n Two-by-four array of samples from N(3, 6.25):\n\n >>> 2.5 * np.random.randn(2, 4) + 3\n array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random\n [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random\n\n "; +static const char __pyx_k_random_sample_size_None_Return[] = "\n random_sample(size=None)\n\n Return random floats in the half-open interval [0.0, 1.0).\n\n Results are from the \"continuous uniform\" distribution over the\n stated interval. To sample :math:`Unif[a, b), b > a` multiply\n the output of `random_sample` by `(b-a)` and add `a`::\n\n (b - a) * random_sample() + a\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : float or ndarray of floats\n Array of random floats of shape `size` (unless ``size=None``, in which\n case a single float is returned).\n\n Examples\n --------\n >>> np.random.random_sample()\n 0.47108547995356098\n >>> type(np.random.random_sample())\n \n >>> np.random.random_sample((5,))\n array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428])\n\n Three-by-two array of random numbers from [-5, 0):\n\n >>> 5 * np.random.random_sample((3, 2)) - 5\n array([[-3.99149989, -0.52338984],\n [-2.99091858, -0.79479508],\n [-1.23204345, -1.75224494]])\n\n "; +static const char __pyx_k_shuffle_x_Modify_a_sequence_in[] = "\n shuffle(x)\n\n Modify a sequence in-place by shuffling its contents.\n\n This function only shuffles the array along the first axis of a\n multi-dimensional array. The order of sub-arrays is changed but\n their contents remains the same.\n\n Parameters\n ----------\n x : array_like\n The array or list to be shuffled.\n\n Returns\n -------\n None\n\n Examples\n --------\n >>> arr = np.arange(10)\n >>> np.random.shuffle(arr)\n >>> arr\n [1 7 5 2 9 4 3 6 0 8]\n\n Multi-dimensional arrays are only shuffled along the first axis:\n\n >>> arr = np.arange(9).reshape((3, 3))\n >>> np.random.shuffle(arr)\n >>> arr\n array([[3, 4, 5],\n [6, 7, 8],\n [0, 1, 2]])\n\n "; +static const char __pyx_k_standard_cauchy_size_None_Draw[] = "\n standard_cauchy(size=None)\n\n Draw samples from a standard Cauchy distribution with mode = 0.\n\n Also known as the Lorentz distribution.\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n samples : ndarray or scalar\n The drawn samples.\n\n Notes\n -----\n The probability density function for the full Cauchy distribution is\n\n .. math:: P(x; x_0, \\gamma) = \\frac{1}{\\pi \\gamma \\bigl[ 1+\n (\\frac{x-x_0}{\\gamma})^2 \\bigr] }\n\n and the Standard Cauchy distribution just sets :math:`x_0=0` and\n :math:`\\gamma=1`\n\n The Cauchy distribution arises in the solution to the driven harmonic\n oscillator problem, and also describes spectral line broadening. It\n also describes the distribution of values at which a line tilted at\n a random angle will cut the x axis.\n\n When studying hypothesis tests that assume normality, seeing how the\n tests perform on data from a Cauchy distribution is a good indicator of\n their sensitivity to a heavy-tailed distribution, since the Cauchy looks\n very much like a Gaussian distribution, but with heavier tails.\n\n References\n ----------\n .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, \"Cauchy\n Distribution\",\n http://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm\n .. [2] Weisstein, Eric W. \"Cauchy Distribution.\" From MathWorld--A\n Wolfram Web Resource.\n http://mathworld.wolfram.com/CauchyDistribution.html\n .. [3] Wikipedia, \"Cauchy distribution\"\n http://en.wikipedia.org/wiki/C""auchy_distribution\n\n Examples\n --------\n Draw samples and plot the distribution:\n\n >>> s = np.random.standard_cauchy(1000000)\n >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well\n >>> plt.hist(s, bins=100)\n >>> plt.show()\n\n "; +static const char __pyx_k_standard_exponential_size_None[] = "\n standard_exponential(size=None)\n\n Draw samples from the standard exponential distribution.\n\n `standard_exponential` is identical to the exponential distribution\n with a scale parameter of 1.\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : float or ndarray\n Drawn samples.\n\n Examples\n --------\n Output a 3x8000 array:\n\n >>> n = np.random.standard_exponential((3, 8000))\n\n "; +static const char __pyx_k_standard_gamma_shape_size_None[] = "\n standard_gamma(shape, size=None)\n\n Draw samples from a standard Gamma distribution.\n\n Samples are drawn from a Gamma distribution with specified parameters,\n shape (sometimes designated \"k\") and scale=1.\n\n Parameters\n ----------\n shape : float or array_like of floats\n Parameter, should be > 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``shape`` is a scalar. Otherwise,\n ``np.array(shape).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized standard gamma distribution.\n\n See Also\n --------\n scipy.stats.gamma : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Gamma distribution is\n\n .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)},\n\n where :math:`k` is the shape and :math:`\\theta` the scale,\n and :math:`\\Gamma` is the Gamma function.\n\n The Gamma distribution is often used to model the times to failure of\n electronic components, and arises naturally in processes for which the\n waiting times between Poisson distributed events are relevant.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Gamma Distribution.\" From MathWorld--A\n Wolfram Web Resource.\n http://mathworld.wolfram.com/GammaDistribution.html\n .. [2] Wikipedia, \"Gamma distribution\",\n http://en.wikipedia.org/wiki/Gamma_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> shape, scale = 2""., 1. # mean and width\n >>> s = np.random.standard_gamma(shape, 1000000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> import scipy.special as sps\n >>> count, bins, ignored = plt.hist(s, 50, normed=True)\n >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\\n ... (sps.gamma(shape) * scale**shape))\n >>> plt.plot(bins, y, linewidth=2, color='r')\n >>> plt.show()\n\n "; +static const char __pyx_k_standard_normal_size_None_Draw[] = "\n standard_normal(size=None)\n\n Draw samples from a standard Normal distribution (mean=0, stdev=1).\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : float or ndarray\n Drawn samples.\n\n Examples\n --------\n >>> s = np.random.standard_normal(8000)\n >>> s\n array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random\n -0.38672696, -0.4685006 ]) #random\n >>> s.shape\n (8000,)\n >>> s = np.random.standard_normal(size=(3, 4, 2))\n >>> s.shape\n (3, 4, 2)\n\n "; +static const char __pyx_k_wald_mean_scale_size_None_Draw[] = "\n wald(mean, scale, size=None)\n\n Draw samples from a Wald, or inverse Gaussian, distribution.\n\n As the scale approaches infinity, the distribution becomes more like a\n Gaussian. Some references claim that the Wald is an inverse Gaussian\n with mean equal to 1, but this is by no means universal.\n\n The inverse Gaussian distribution was first studied in relationship to\n Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian\n because there is an inverse relationship between the time to cover a\n unit distance and distance covered in unit time.\n\n Parameters\n ----------\n mean : float or array_like of floats\n Distribution mean, should be > 0.\n scale : float or array_like of floats\n Scale parameter, should be >= 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``mean`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Wald distribution.\n\n Notes\n -----\n The probability density function for the Wald distribution is\n\n .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^\n \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x}\n\n As noted above the inverse Gaussian distribution first arise\n from attempts to model Brownian motion. It is also a\n competitor to the Weibull for use in reliability modeling and\n modeling stock returns and interest rate processes.\n\n References\n ----------\n .. [1] Brighton Webs Ltd., Wald Distribution,\n "" http://www.brighton-webs.co.uk/distributions/wald.asp\n .. [2] Chhikara, Raj S., and Folks, J. Leroy, \"The Inverse Gaussian\n Distribution: Theory : Methodology, and Applications\", CRC Press,\n 1988.\n .. [3] Wikipedia, \"Wald distribution\"\n http://en.wikipedia.org/wiki/Wald_distribution\n\n Examples\n --------\n Draw values from the distribution and plot the histogram:\n\n >>> import matplotlib.pyplot as plt\n >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, normed=True)\n >>> plt.show()\n\n "; +static const char __pyx_k_RandomState_chisquare_line_2205[] = "RandomState.chisquare (line 2205)"; +static const char __pyx_k_RandomState_dirichlet_line_4656[] = "RandomState.dirichlet (line 4656)"; +static const char __pyx_k_RandomState_geometric_line_4095[] = "RandomState.geometric (line 4095)"; +static const char __pyx_k_RandomState_hypergeometric_line[] = "RandomState.hypergeometric (line 4163)"; +static const char __pyx_k_RandomState_lognormal_line_3313[] = "RandomState.lognormal (line 3313)"; +static const char __pyx_k_RandomState_logseries_line_4285[] = "RandomState.logseries (line 4285)"; +static const char __pyx_k_RandomState_multivariate_normal[] = "RandomState.multivariate_normal (line 4382)"; +static const char __pyx_k_RandomState_standard_gamma_line[] = "RandomState.standard_gamma (line 1815)"; +static const char __pyx_k_Seed_must_be_between_0_and_2_32[] = "Seed must be between 0 and 2**32 - 1"; +static const char __pyx_k_Unsupported_dtype_s_for_randint[] = "Unsupported dtype \"%s\" for randint"; +static const char __pyx_k_a_must_contain_valid_floats_1_0[] = "'a' must contain valid floats > 1.0"; +static const char __pyx_k_binomial_n_p_size_None_Draw_sam[] = "\n binomial(n, p, size=None)\n\n Draw samples from a binomial distribution.\n\n Samples are drawn from a binomial distribution with specified\n parameters, n trials and p probability of success where\n n an integer >= 0 and p is in the interval [0,1]. (n may be\n input as a float, but it is truncated to an integer in use)\n\n Parameters\n ----------\n n : int or array_like of ints\n Parameter of the distribution, >= 0. Floats are also accepted,\n but they will be truncated to integers.\n p : float or array_like of floats\n Parameter of the distribution, >= 0 and <=1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``n`` and ``p`` are both scalars.\n Otherwise, ``np.broadcast(n, p).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized binomial distribution, where\n each sample is equal to the number of successes over the n trials.\n\n See Also\n --------\n scipy.stats.binom : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the binomial distribution is\n\n .. math:: P(N) = \\binom{n}{N}p^N(1-p)^{n-N},\n\n where :math:`n` is the number of trials, :math:`p` is the probability\n of success, and :math:`N` is the number of successes.\n\n When estimating the standard error of a proportion in a population by\n using a random sample, the normal distribution works well unless the\n product p*n <=5, where p = population proportion estimate, and n =\n number of samples, in which case the binom""ial distribution is used\n instead. For example, a sample of 15 people shows 4 who are left\n handed, and 11 who are right handed. Then p = 4/15 = 27%. 0.27*15 = 4,\n so the binomial distribution should be used in this case.\n\n References\n ----------\n .. [1] Dalgaard, Peter, \"Introductory Statistics with R\",\n Springer-Verlag, 2002.\n .. [2] Glantz, Stanton A. \"Primer of Biostatistics.\", McGraw-Hill,\n Fifth Edition, 2002.\n .. [3] Lentner, Marvin, \"Elementary Applied Statistics\", Bogden\n and Quigley, 1972.\n .. [4] Weisstein, Eric W. \"Binomial Distribution.\" From MathWorld--A\n Wolfram Web Resource.\n http://mathworld.wolfram.com/BinomialDistribution.html\n .. [5] Wikipedia, \"Binomial distribution\",\n http://en.wikipedia.org/wiki/Binomial_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> n, p = 10, .5 # number of trials, probability of each trial\n >>> s = np.random.binomial(n, p, 1000)\n # result of flipping a coin 10 times, tested 1000 times.\n\n A real world example. A company drills 9 wild-cat oil exploration\n wells, each with an estimated probability of success of 0.1. All nine\n wells fail. What is the probability of that happening?\n\n Let's do 20,000 trials of the model, and count the number that\n generate zero positive results.\n\n >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000.\n # answer = 0.38885, or 38%.\n\n "; +static const char __pyx_k_bytes_length_Return_random_byte[] = "\n bytes(length)\n\n Return random bytes.\n\n Parameters\n ----------\n length : int\n Number of random bytes.\n\n Returns\n -------\n out : str\n String of length `length`.\n\n Examples\n --------\n >>> np.random.bytes(10)\n ' eh\\x85\\x022SZ\\xbf\\xa4' #random\n\n "; +static const char __pyx_k_chisquare_df_size_None_Draw_sam[] = "\n chisquare(df, size=None)\n\n Draw samples from a chi-square distribution.\n\n When `df` independent random variables, each with standard normal\n distributions (mean 0, variance 1), are squared and summed, the\n resulting distribution is chi-square (see Notes). This distribution\n is often used in hypothesis testing.\n\n Parameters\n ----------\n df : float or array_like of floats\n Number of degrees of freedom, should be > 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``df`` is a scalar. Otherwise,\n ``np.array(df).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized chi-square distribution.\n\n Raises\n ------\n ValueError\n When `df` <= 0 or when an inappropriate `size` (e.g. ``size=-1``)\n is given.\n\n Notes\n -----\n The variable obtained by summing the squares of `df` independent,\n standard normally distributed random variables:\n\n .. math:: Q = \\sum_{i=0}^{\\mathtt{df}} X^2_i\n\n is chi-square distributed, denoted\n\n .. math:: Q \\sim \\chi^2_k.\n\n The probability density function of the chi-squared distribution is\n\n .. math:: p(x) = \\frac{(1/2)^{k/2}}{\\Gamma(k/2)}\n x^{k/2 - 1} e^{-x/2},\n\n where :math:`\\Gamma` is the gamma function,\n\n .. math:: \\Gamma(x) = \\int_0^{-\\infty} t^{x - 1} e^{-t} dt.\n\n References\n ----------\n .. [1] NIST \"Engineering Statistics Handbook\"\n http://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm\n\n Examples\n --------\n >>> n""p.random.chisquare(2,4)\n array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272])\n\n "; +static const char __pyx_k_choice_a_size_None_replace_True[] = "\n choice(a, size=None, replace=True, p=None)\n\n Generates a random sample from a given 1-D array\n\n .. versionadded:: 1.7.0\n\n Parameters\n -----------\n a : 1-D array-like or int\n If an ndarray, a random sample is generated from its elements.\n If an int, the random sample is generated as if a were np.arange(a)\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n replace : boolean, optional\n Whether the sample is with or without replacement\n p : 1-D array-like, optional\n The probabilities associated with each entry in a.\n If not given the sample assumes a uniform distribution over all\n entries in a.\n\n Returns\n --------\n samples : single item or ndarray\n The generated random samples\n\n Raises\n -------\n ValueError\n If a is an int and less than zero, if a or p are not 1-dimensional,\n if a is an array-like of size 0, if p is not a vector of\n probabilities, if a and p have different lengths, or if\n replace=False and the sample size is greater than the population\n size\n\n See Also\n ---------\n randint, shuffle, permutation\n\n Examples\n ---------\n Generate a uniform random sample from np.arange(5) of size 3:\n\n >>> np.random.choice(5, 3)\n array([0, 3, 4])\n >>> #This is equivalent to np.random.randint(0,5,3)\n\n Generate a non-uniform random sample from np.arange(5) of size 3:\n\n >>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0])\n array([3, 3, 0])\n\n Generate a uniform random sample from np.arange(5) of size 3 without\n ""replacement:\n\n >>> np.random.choice(5, 3, replace=False)\n array([3,1,0])\n >>> #This is equivalent to np.random.permutation(np.arange(5))[:3]\n\n Generate a non-uniform random sample from np.arange(5) of size\n 3 without replacement:\n\n >>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0])\n array([2, 3, 0])\n\n Any of the above can be repeated with an arbitrary array-like\n instead of just integers. For instance:\n\n >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher']\n >>> np.random.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3])\n array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'],\n dtype='|S11')\n\n "; +static const char __pyx_k_f_dfnum_dfden_size_None_Draw_sa[] = "\n f(dfnum, dfden, size=None)\n\n Draw samples from an F distribution.\n\n Samples are drawn from an F distribution with specified parameters,\n `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of\n freedom in denominator), where both parameters should be greater than\n zero.\n\n The random variate of the F distribution (also known as the\n Fisher distribution) is a continuous probability distribution\n that arises in ANOVA tests, and is the ratio of two chi-square\n variates.\n\n Parameters\n ----------\n dfnum : float or array_like of floats\n Degrees of freedom in numerator, should be > 0.\n dfden : float or array_like of float\n Degrees of freedom in denominator, should be > 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``dfnum`` and ``dfden`` are both scalars.\n Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Fisher distribution.\n\n See Also\n --------\n scipy.stats.f : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The F statistic is used to compare in-group variances to between-group\n variances. Calculating the distribution depends on the sampling, and\n so it is a function of the respective degrees of freedom in the\n problem. The variable `dfnum` is the number of samples minus one, the\n between-groups degrees of freedom, while `dfden` is the within-groups\n degrees of freedom, the sum of the number of samples in each group\n minus ""the number of groups.\n\n References\n ----------\n .. [1] Glantz, Stanton A. \"Primer of Biostatistics.\", McGraw-Hill,\n Fifth Edition, 2002.\n .. [2] Wikipedia, \"F-distribution\",\n http://en.wikipedia.org/wiki/F-distribution\n\n Examples\n --------\n An example from Glantz[1], pp 47-40:\n\n Two groups, children of diabetics (25 people) and children from people\n without diabetes (25 controls). Fasting blood glucose was measured,\n case group had a mean value of 86.1, controls had a mean value of\n 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these\n data consistent with the null hypothesis that the parents diabetic\n status does not affect their children's blood glucose levels?\n Calculating the F statistic from the data gives a value of 36.01.\n\n Draw samples from the distribution:\n\n >>> dfnum = 1. # between group degrees of freedom\n >>> dfden = 48. # within groups degrees of freedom\n >>> s = np.random.f(dfnum, dfden, 1000)\n\n The lower bound for the top 1% of the samples is :\n\n >>> sort(s)[-10]\n 7.61988120985\n\n So there is about a 1% chance that the F statistic will exceed 7.62,\n the measured value is 36, so the null hypothesis is rejected at the 1%\n level.\n\n "; +static const char __pyx_k_gamma_shape_scale_1_0_size_None[] = "\n gamma(shape, scale=1.0, size=None)\n\n Draw samples from a Gamma distribution.\n\n Samples are drawn from a Gamma distribution with specified parameters,\n `shape` (sometimes designated \"k\") and `scale` (sometimes designated\n \"theta\"), where both parameters are > 0.\n\n Parameters\n ----------\n shape : float or array_like of floats\n The shape of the gamma distribution. Should be greater than zero.\n scale : float or array_like of floats, optional\n The scale of the gamma distribution. Should be greater than zero.\n Default is equal to 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``shape`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized gamma distribution.\n\n See Also\n --------\n scipy.stats.gamma : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Gamma distribution is\n\n .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)},\n\n where :math:`k` is the shape and :math:`\\theta` the scale,\n and :math:`\\Gamma` is the Gamma function.\n\n The Gamma distribution is often used to model the times to failure of\n electronic components, and arises naturally in processes for which the\n waiting times between Poisson distributed events are relevant.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Gamma Distribution.\" From MathWorld--A\n Wolfram Web Resourc""e.\n http://mathworld.wolfram.com/GammaDistribution.html\n .. [2] Wikipedia, \"Gamma distribution\",\n http://en.wikipedia.org/wiki/Gamma_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> shape, scale = 2., 2. # mean=4, std=2*sqrt(2)\n >>> s = np.random.gamma(shape, scale, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> import scipy.special as sps\n >>> count, bins, ignored = plt.hist(s, 50, normed=True)\n >>> y = bins**(shape-1)*(np.exp(-bins/scale) /\n ... (sps.gamma(shape)*scale**shape))\n >>> plt.plot(bins, y, linewidth=2, color='r')\n >>> plt.show()\n\n "; +static const char __pyx_k_geometric_p_size_None_Draw_samp[] = "\n geometric(p, size=None)\n\n Draw samples from the geometric distribution.\n\n Bernoulli trials are experiments with one of two outcomes:\n success or failure (an example of such an experiment is flipping\n a coin). The geometric distribution models the number of trials\n that must be run in order to achieve success. It is therefore\n supported on the positive integers, ``k = 1, 2, ...``.\n\n The probability mass function of the geometric distribution is\n\n .. math:: f(k) = (1 - p)^{k - 1} p\n\n where `p` is the probability of success of an individual trial.\n\n Parameters\n ----------\n p : float or array_like of floats\n The probability of success of an individual trial.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``p`` is a scalar. Otherwise,\n ``np.array(p).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized geometric distribution.\n\n Examples\n --------\n Draw ten thousand values from the geometric distribution,\n with the probability of an individual success equal to 0.35:\n\n >>> z = np.random.geometric(p=0.35, size=10000)\n\n How many trials succeeded after a single run?\n\n >>> (z == 1).sum() / 10000.\n 0.34889999999999999 #random\n\n "; +static const char __pyx_k_gumbel_loc_0_0_scale_1_0_size_N[] = "\n gumbel(loc=0.0, scale=1.0, size=None)\n\n Draw samples from a Gumbel distribution.\n\n Draw samples from a Gumbel distribution with specified location and\n scale. For more information on the Gumbel distribution, see\n Notes and References below.\n\n Parameters\n ----------\n loc : float or array_like of floats, optional\n The location of the mode of the distribution. Default is 0.\n scale : float or array_like of floats, optional\n The scale parameter of the distribution. Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``loc`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Gumbel distribution.\n\n See Also\n --------\n scipy.stats.gumbel_l\n scipy.stats.gumbel_r\n scipy.stats.genextreme\n weibull\n\n Notes\n -----\n The Gumbel (or Smallest Extreme Value (SEV) or the Smallest Extreme\n Value Type I) distribution is one of a class of Generalized Extreme\n Value (GEV) distributions used in modeling extreme value problems.\n The Gumbel is a special case of the Extreme Value Type I distribution\n for maximums from distributions with \"exponential-like\" tails.\n\n The probability density for the Gumbel distribution is\n\n .. math:: p(x) = \\frac{e^{-(x - \\mu)/ \\beta}}{\\beta} e^{ -e^{-(x - \\mu)/\n \\beta}},\n\n where :math:`\\mu` is the mode, a location parameter, and\n :math:`\\beta` is the scale parameter.\n\n The Gumbel (named for German mathematician ""Emil Julius Gumbel) was used\n very early in the hydrology literature, for modeling the occurrence of\n flood events. It is also used for modeling maximum wind speed and\n rainfall rates. It is a \"fat-tailed\" distribution - the probability of\n an event in the tail of the distribution is larger than if one used a\n Gaussian, hence the surprisingly frequent occurrence of 100-year\n floods. Floods were initially modeled as a Gaussian process, which\n underestimated the frequency of extreme events.\n\n It is one of a class of extreme value distributions, the Generalized\n Extreme Value (GEV) distributions, which also includes the Weibull and\n Frechet.\n\n The function has a mean of :math:`\\mu + 0.57721\\beta` and a variance\n of :math:`\\frac{\\pi^2}{6}\\beta^2`.\n\n References\n ----------\n .. [1] Gumbel, E. J., \"Statistics of Extremes,\"\n New York: Columbia University Press, 1958.\n .. [2] Reiss, R.-D. and Thomas, M., \"Statistical Analysis of Extreme\n Values from Insurance, Finance, Hydrology and Other Fields,\"\n Basel: Birkhauser Verlag, 2001.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> mu, beta = 0, 0.1 # location and scale\n >>> s = np.random.gumbel(mu, beta, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 30, normed=True)\n >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta)\n ... * np.exp( -np.exp( -(bins - mu) /beta) ),\n ... linewidth=2, color='r')\n >>> plt.show()\n\n Show how an extreme value distribution can arise from a Gaussian process\n and compare to a Gaussian:\n\n >>> means = []\n >>> maxima = []\n "" >>> for i in range(0,1000) :\n ... a = np.random.normal(mu, beta, 1000)\n ... means.append(a.mean())\n ... maxima.append(a.max())\n >>> count, bins, ignored = plt.hist(maxima, 30, normed=True)\n >>> beta = np.std(maxima) * np.sqrt(6) / np.pi\n >>> mu = np.mean(maxima) - 0.57721*beta\n >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta)\n ... * np.exp(-np.exp(-(bins - mu)/beta)),\n ... linewidth=2, color='r')\n >>> plt.plot(bins, 1/(beta * np.sqrt(2 * np.pi))\n ... * np.exp(-(bins - mu)**2 / (2 * beta**2)),\n ... linewidth=2, color='g')\n >>> plt.show()\n\n "; +static const char __pyx_k_hypergeometric_ngood_nbad_nsamp[] = "\n hypergeometric(ngood, nbad, nsample, size=None)\n\n Draw samples from a Hypergeometric distribution.\n\n Samples are drawn from a hypergeometric distribution with specified\n parameters, ngood (ways to make a good selection), nbad (ways to make\n a bad selection), and nsample = number of items sampled, which is less\n than or equal to the sum ngood + nbad.\n\n Parameters\n ----------\n ngood : int or array_like of ints\n Number of ways to make a good selection. Must be nonnegative.\n nbad : int or array_like of ints\n Number of ways to make a bad selection. Must be nonnegative.\n nsample : int or array_like of ints\n Number of items sampled. Must be at least 1 and at most\n ``ngood + nbad``.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``ngood``, ``nbad``, and ``nsample``\n are all scalars. Otherwise, ``np.broadcast(ngood, nbad, nsample).size``\n samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized hypergeometric distribution.\n\n See Also\n --------\n scipy.stats.hypergeom : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Hypergeometric distribution is\n\n .. math:: P(x) = \\frac{\\binom{m}{n}\\binom{N-m}{n-x}}{\\binom{N}{n}},\n\n where :math:`0 \\le x \\le m` and :math:`n+m-N \\le x \\le n`\n\n for P(x) the probability of x successes, n = ngood, m = nbad, and\n N = number of samples.\n\n Consider an urn with black and white marbles in it, ngood of them\n black"" and nbad are white. If you draw nsample balls without\n replacement, then the hypergeometric distribution describes the\n distribution of black balls in the drawn sample.\n\n Note that this distribution is very similar to the binomial\n distribution, except that in this case, samples are drawn without\n replacement, whereas in the Binomial case samples are drawn with\n replacement (or the sample space is infinite). As the sample space\n becomes large, this distribution approaches the binomial.\n\n References\n ----------\n .. [1] Lentner, Marvin, \"Elementary Applied Statistics\", Bogden\n and Quigley, 1972.\n .. [2] Weisstein, Eric W. \"Hypergeometric Distribution.\" From\n MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/HypergeometricDistribution.html\n .. [3] Wikipedia, \"Hypergeometric distribution\",\n http://en.wikipedia.org/wiki/Hypergeometric_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> ngood, nbad, nsamp = 100, 2, 10\n # number of good, number of bad, and number of samples\n >>> s = np.random.hypergeometric(ngood, nbad, nsamp, 1000)\n >>> hist(s)\n # note that it is very unlikely to grab both bad items\n\n Suppose you have an urn with 15 white and 15 black marbles.\n If you pull 15 marbles at random, how likely is it that\n 12 or more of them are one color?\n\n >>> s = np.random.hypergeometric(15, 15, 15, 100000)\n >>> sum(s>=12)/100000. + sum(s<=3)/100000.\n # answer = 0.003 ... pretty unlikely!\n\n "; +static const char __pyx_k_logistic_loc_0_0_scale_1_0_size[] = "\n logistic(loc=0.0, scale=1.0, size=None)\n\n Draw samples from a logistic distribution.\n\n Samples are drawn from a logistic distribution with specified\n parameters, loc (location or mean, also median), and scale (>0).\n\n Parameters\n ----------\n loc : float or array_like of floats, optional\n Parameter of the distribution. Default is 0.\n scale : float or array_like of floats, optional\n Parameter of the distribution. Should be greater than zero.\n Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``loc`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized logistic distribution.\n\n See Also\n --------\n scipy.stats.logistic : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Logistic distribution is\n\n .. math:: P(x) = P(x) = \\frac{e^{-(x-\\mu)/s}}{s(1+e^{-(x-\\mu)/s})^2},\n\n where :math:`\\mu` = location and :math:`s` = scale.\n\n The Logistic distribution is used in Extreme Value problems where it\n can act as a mixture of Gumbel distributions, in Epidemiology, and by\n the World Chess Federation (FIDE) where it is used in the Elo ranking\n system, assuming the performance of each player is a logistically\n distributed random variable.\n\n References\n ----------\n .. [1] Reiss, R.-D. and Thomas M. (2001), \"Statistical Analysis of\n Extreme Values, from Insurance, Financ""e, Hydrology and Other\n Fields,\" Birkhauser Verlag, Basel, pp 132-133.\n .. [2] Weisstein, Eric W. \"Logistic Distribution.\" From\n MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/LogisticDistribution.html\n .. [3] Wikipedia, \"Logistic-distribution\",\n http://en.wikipedia.org/wiki/Logistic_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> loc, scale = 10, 1\n >>> s = np.random.logistic(loc, scale, 10000)\n >>> count, bins, ignored = plt.hist(s, bins=50)\n\n # plot against distribution\n\n >>> def logist(x, loc, scale):\n ... return exp((loc-x)/scale)/(scale*(1+exp((loc-x)/scale))**2)\n >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\\\n ... logist(bins, loc, scale).max())\n >>> plt.show()\n\n "; +static const char __pyx_k_lognormal_mean_0_0_sigma_1_0_si[] = "\n lognormal(mean=0.0, sigma=1.0, size=None)\n\n Draw samples from a log-normal distribution.\n\n Draw samples from a log-normal distribution with specified mean,\n standard deviation, and array shape. Note that the mean and standard\n deviation are not the values for the distribution itself, but of the\n underlying normal distribution it is derived from.\n\n Parameters\n ----------\n mean : float or array_like of floats, optional\n Mean value of the underlying normal distribution. Default is 0.\n sigma : float or array_like of floats, optional\n Standard deviation of the underlying normal distribution. Should\n be greater than zero. Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``mean`` and ``sigma`` are both scalars.\n Otherwise, ``np.broadcast(mean, sigma).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized log-normal distribution.\n\n See Also\n --------\n scipy.stats.lognorm : probability density function, distribution,\n cumulative density function, etc.\n\n Notes\n -----\n A variable `x` has a log-normal distribution if `log(x)` is normally\n distributed. The probability density function for the log-normal\n distribution is:\n\n .. math:: p(x) = \\frac{1}{\\sigma x \\sqrt{2\\pi}}\n e^{(-\\frac{(ln(x)-\\mu)^2}{2\\sigma^2})}\n\n where :math:`\\mu` is the mean and :math:`\\sigma` is the standard\n deviation of the normally distributed logarithm of the variable.\n A log-normal distribution results if a random variable is the *produc""t*\n of a large number of independent, identically-distributed variables in\n the same way that a normal distribution results if the variable is the\n *sum* of a large number of independent, identically-distributed\n variables.\n\n References\n ----------\n .. [1] Limpert, E., Stahel, W. A., and Abbt, M., \"Log-normal\n Distributions across the Sciences: Keys and Clues,\"\n BioScience, Vol. 51, No. 5, May, 2001.\n http://stat.ethz.ch/~stahel/lognormal/bioscience.pdf\n .. [2] Reiss, R.D. and Thomas, M., \"Statistical Analysis of Extreme\n Values,\" Basel: Birkhauser Verlag, 2001, pp. 31-32.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> mu, sigma = 3., 1. # mean and standard deviation\n >>> s = np.random.lognormal(mu, sigma, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 100, normed=True, align='mid')\n\n >>> x = np.linspace(min(bins), max(bins), 10000)\n >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2))\n ... / (x * sigma * np.sqrt(2 * np.pi)))\n\n >>> plt.plot(x, pdf, linewidth=2, color='r')\n >>> plt.axis('tight')\n >>> plt.show()\n\n Demonstrate that taking the products of random samples from a uniform\n distribution can be fit well by a log-normal probability density\n function.\n\n >>> # Generate a thousand samples: each is the product of 100 random\n >>> # values, drawn from a normal distribution.\n >>> b = []\n >>> for i in range(1000):\n ... a = 10. + np.random.random(100)\n ... b.append(np.product(a))\n\n >>> b = np.array(b) / np.min(b) # scale values to be positive\n >>> count, bins, ignored = plt.h""ist(b, 100, normed=True, align='mid')\n >>> sigma = np.std(np.log(b))\n >>> mu = np.mean(np.log(b))\n\n >>> x = np.linspace(min(bins), max(bins), 10000)\n >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2))\n ... / (x * sigma * np.sqrt(2 * np.pi)))\n\n >>> plt.plot(x, pdf, color='r', linewidth=2)\n >>> plt.show()\n\n "; +static const char __pyx_k_logseries_p_size_None_Draw_samp[] = "\n logseries(p, size=None)\n\n Draw samples from a logarithmic series distribution.\n\n Samples are drawn from a log series distribution with specified\n shape parameter, 0 < ``p`` < 1.\n\n Parameters\n ----------\n p : float or array_like of floats\n Shape parameter for the distribution. Must be in the range (0, 1).\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``p`` is a scalar. Otherwise,\n ``np.array(p).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized logarithmic series distribution.\n\n See Also\n --------\n scipy.stats.logser : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Log Series distribution is\n\n .. math:: P(k) = \\frac{-p^k}{k \\ln(1-p)},\n\n where p = probability.\n\n The log series distribution is frequently used to represent species\n richness and occurrence, first proposed by Fisher, Corbet, and\n Williams in 1943 [2]. It may also be used to model the numbers of\n occupants seen in cars [3].\n\n References\n ----------\n .. [1] Buzas, Martin A.; Culver, Stephen J., Understanding regional\n species diversity through the log series distribution of\n occurrences: BIODIVERSITY RESEARCH Diversity & Distributions,\n Volume 5, Number 5, September 1999 , pp. 187-195(9).\n .. [2] Fisher, R.A,, A.S. Corbet, and C.B. Williams. 1943. The\n relation between the number of species and the number of\n individuals in a random ""sample of an animal population.\n Journal of Animal Ecology, 12:42-58.\n .. [3] D. J. Hand, F. Daly, D. Lunn, E. Ostrowski, A Handbook of Small\n Data Sets, CRC Press, 1994.\n .. [4] Wikipedia, \"Logarithmic distribution\",\n http://en.wikipedia.org/wiki/Logarithmic_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a = .6\n >>> s = np.random.logseries(a, 10000)\n >>> count, bins, ignored = plt.hist(s)\n\n # plot against distribution\n\n >>> def logseries(k, p):\n ... return -p**k/(k*log(1-p))\n >>> plt.plot(bins, logseries(bins, a)*count.max()/\n logseries(bins, a).max(), 'r')\n >>> plt.show()\n\n "; +static const char __pyx_k_multinomial_n_pvals_size_None_D[] = "\n multinomial(n, pvals, size=None)\n\n Draw samples from a multinomial distribution.\n\n The multinomial distribution is a multivariate generalisation of the\n binomial distribution. Take an experiment with one of ``p``\n possible outcomes. An example of such an experiment is throwing a dice,\n where the outcome can be 1 through 6. Each sample drawn from the\n distribution represents `n` such experiments. Its values,\n ``X_i = [X_0, X_1, ..., X_p]``, represent the number of times the\n outcome was ``i``.\n\n Parameters\n ----------\n n : int\n Number of experiments.\n pvals : sequence of floats, length p\n Probabilities of each of the ``p`` different outcomes. These\n should sum to 1 (however, the last element is always assumed to\n account for the remaining probability, as long as\n ``sum(pvals[:-1]) <= 1)``.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : ndarray\n The drawn samples, of shape *size*, if that was provided. If not,\n the shape is ``(N,)``.\n\n In other words, each entry ``out[i,j,...,:]`` is an N-dimensional\n value drawn from the distribution.\n\n Examples\n --------\n Throw a dice 20 times:\n\n >>> np.random.multinomial(20, [1/6.]*6, size=1)\n array([[4, 1, 7, 5, 2, 1]])\n\n It landed 4 times on 1, once on 2, etc.\n\n Now, throw the dice 20 times, and 20 times again:\n\n >>> np.random.multinomial(20, [1/6.]*6, size=2)\n array([[3, 4, 3, 3, 4, 3],\n [2, 4, 3, 4, 0, 7]])\n\n For the first run, we threw 3 times 1, 4 times 2, etc. Fo""r the second,\n we threw 2 times 1, 4 times 2, etc.\n\n A loaded die is more likely to land on number 6:\n\n >>> np.random.multinomial(100, [1/7.]*5 + [2/7.])\n array([11, 16, 14, 17, 16, 26])\n\n The probability inputs should be normalized. As an implementation\n detail, the value of the last entry is ignored and assumed to take\n up any leftover probability mass, but this should not be relied on.\n A biased coin which has twice as much weight on one side as on the\n other should be sampled like so:\n\n >>> np.random.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT\n array([38, 62])\n\n not like:\n\n >>> np.random.multinomial(100, [1.0, 2.0]) # WRONG\n array([100, 0])\n\n "; +static const char __pyx_k_multivariate_normal_mean_cov_si[] = "\n multivariate_normal(mean, cov[, size, check_valid, tol])\n\n Draw random samples from a multivariate normal distribution.\n\n The multivariate normal, multinormal or Gaussian distribution is a\n generalization of the one-dimensional normal distribution to higher\n dimensions. Such a distribution is specified by its mean and\n covariance matrix. These parameters are analogous to the mean\n (average or \"center\") and variance (standard deviation, or \"width,\"\n squared) of the one-dimensional normal distribution.\n\n Parameters\n ----------\n mean : 1-D array_like, of length N\n Mean of the N-dimensional distribution.\n cov : 2-D array_like, of shape (N, N)\n Covariance matrix of the distribution. It must be symmetric and\n positive-semidefinite for proper sampling.\n size : int or tuple of ints, optional\n Given a shape of, for example, ``(m,n,k)``, ``m*n*k`` samples are\n generated, and packed in an `m`-by-`n`-by-`k` arrangement. Because\n each sample is `N`-dimensional, the output shape is ``(m,n,k,N)``.\n If no shape is specified, a single (`N`-D) sample is returned.\n check_valid : { 'warn', 'raise', 'ignore' }, optional\n Behavior when the covariance matrix is not positive semidefinite.\n tol : float, optional\n Tolerance when checking the singular values in covariance matrix.\n\n Returns\n -------\n out : ndarray\n The drawn samples, of shape *size*, if that was provided. If not,\n the shape is ``(N,)``.\n\n In other words, each entry ``out[i,j,...,:]`` is an N-dimensional\n value drawn from the distribution.\n\n Notes\n -----\n The mean is a coordinate in N-dimensional space, which represents the\n location where samples are most likely to be generated. This ""is\n analogous to the peak of the bell curve for the one-dimensional or\n univariate normal distribution.\n\n Covariance indicates the level to which two variables vary together.\n From the multivariate normal distribution, we draw N-dimensional\n samples, :math:`X = [x_1, x_2, ... x_N]`. The covariance matrix\n element :math:`C_{ij}` is the covariance of :math:`x_i` and :math:`x_j`.\n The element :math:`C_{ii}` is the variance of :math:`x_i` (i.e. its\n \"spread\").\n\n Instead of specifying the full covariance matrix, popular\n approximations include:\n\n - Spherical covariance (`cov` is a multiple of the identity matrix)\n - Diagonal covariance (`cov` has non-negative elements, and only on\n the diagonal)\n\n This geometrical property can be seen in two dimensions by plotting\n generated data-points:\n\n >>> mean = [0, 0]\n >>> cov = [[1, 0], [0, 100]] # diagonal covariance\n\n Diagonal covariance means that points are oriented along x or y-axis:\n\n >>> import matplotlib.pyplot as plt\n >>> x, y = np.random.multivariate_normal(mean, cov, 5000).T\n >>> plt.plot(x, y, 'x')\n >>> plt.axis('equal')\n >>> plt.show()\n\n Note that the covariance matrix must be positive semidefinite (a.k.a.\n nonnegative-definite). Otherwise, the behavior of this method is\n undefined and backwards compatibility is not guaranteed.\n\n References\n ----------\n .. [1] Papoulis, A., \"Probability, Random Variables, and Stochastic\n Processes,\" 3rd ed., New York: McGraw-Hill, 1991.\n .. [2] Duda, R. O., Hart, P. E., and Stork, D. G., \"Pattern\n Classification,\" 2nd ed., New York: Wiley, 2001.\n\n Examples\n --------\n >>> mean = (1, 2)\n >>> cov = [[1, 0], [0, 1]]\n >>> x = np.random.multivariate_normal(mean"", cov, (3, 3))\n >>> x.shape\n (3, 3, 2)\n\n The following is probably true, given that 0.6 is roughly twice the\n standard deviation:\n\n >>> list((x[0,0,:] - mean) < 0.6)\n [True, True]\n\n "; +static const char __pyx_k_negative_binomial_n_p_size_None[] = "\n negative_binomial(n, p, size=None)\n\n Draw samples from a negative binomial distribution.\n\n Samples are drawn from a negative binomial distribution with specified\n parameters, `n` trials and `p` probability of success where `n` is an\n integer > 0 and `p` is in the interval [0, 1].\n\n Parameters\n ----------\n n : int or array_like of ints\n Parameter of the distribution, > 0. Floats are also accepted,\n but they will be truncated to integers.\n p : float or array_like of floats\n Parameter of the distribution, >= 0 and <=1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``n`` and ``p`` are both scalars.\n Otherwise, ``np.broadcast(n, p).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized negative binomial distribution,\n where each sample is equal to N, the number of trials it took to\n achieve n - 1 successes, N - (n - 1) failures, and a success on the,\n (N + n)th trial.\n\n Notes\n -----\n The probability density for the negative binomial distribution is\n\n .. math:: P(N;n,p) = \\binom{N+n-1}{n-1}p^{n}(1-p)^{N},\n\n where :math:`n-1` is the number of successes, :math:`p` is the\n probability of success, and :math:`N+n-1` is the number of trials.\n The negative binomial distribution gives the probability of n-1\n successes and N failures in N+n-1 trials, and success on the (N+n)th\n trial.\n\n If one throws a die repeatedly until the third time a \"1\" appears,\n then the probability distribution of the number of non-\"1\"s that\n appear before the ""third \"1\" is a negative binomial distribution.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Negative Binomial Distribution.\" From\n MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/NegativeBinomialDistribution.html\n .. [2] Wikipedia, \"Negative binomial distribution\",\n http://en.wikipedia.org/wiki/Negative_binomial_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n A real world example. A company drills wild-cat oil\n exploration wells, each with an estimated probability of\n success of 0.1. What is the probability of having one success\n for each successive well, that is what is the probability of a\n single success after drilling 5 wells, after 6 wells, etc.?\n\n >>> s = np.random.negative_binomial(1, 0.1, 100000)\n >>> for i in range(1, 11):\n ... probability = sum(s>> import matplotlib.pyplot as plt\n >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000),\n ... bins=200, normed=True)\n >>> plt.show()\n\n Draw values from a noncentral chisquare with very small noncentrality,\n and compare to a chisquare.\n\n >>> plt.figure()\n >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000),\n ... bins=np.arange(0., 25, .1), normed=True)\n >>> values2 = plt.hist(np.random.chisquare(3, 100000),\n ... bins=np.arange(0., 25, .1), normed=True)\n >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob')\n >>> plt.show()\n\n Demonstrate how large values of non-centrality lead to a more symmetric\n distribution.\n\n >>> plt.figure()\n >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000),\n ... bins=200, normed=True)\n >>> plt.show()\n\n "; +static const char __pyx_k_noncentral_f_dfnum_dfden_nonc_s[] = "\n noncentral_f(dfnum, dfden, nonc, size=None)\n\n Draw samples from the noncentral F distribution.\n\n Samples are drawn from an F distribution with specified parameters,\n `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of\n freedom in denominator), where both parameters > 1.\n `nonc` is the non-centrality parameter.\n\n Parameters\n ----------\n dfnum : float or array_like of floats\n Numerator degrees of freedom, should be > 0.\n\n .. versionchanged:: 1.14.0\n Earlier NumPy versions required dfnum > 1.\n dfden : float or array_like of floats\n Denominator degrees of freedom, should be > 0.\n nonc : float or array_like of floats\n Non-centrality parameter, the sum of the squares of the numerator\n means, should be >= 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``dfnum``, ``dfden``, and ``nonc``\n are all scalars. Otherwise, ``np.broadcast(dfnum, dfden, nonc).size``\n samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized noncentral Fisher distribution.\n\n Notes\n -----\n When calculating the power of an experiment (power = probability of\n rejecting the null hypothesis when a specific alternative is true) the\n non-central F statistic becomes important. When the null hypothesis is\n true, the F statistic follows a central F distribution. When the null\n hypothesis is not true, then it follows a non-central F statistic.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Noncentral F-Distribution.\"\n From MathW""orld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/NoncentralF-Distribution.html\n .. [2] Wikipedia, \"Noncentral F-distribution\",\n http://en.wikipedia.org/wiki/Noncentral_F-distribution\n\n Examples\n --------\n In a study, testing for a specific alternative to the null hypothesis\n requires use of the Noncentral F distribution. We need to calculate the\n area in the tail of the distribution that exceeds the value of the F\n distribution for the null hypothesis. We'll plot the two probability\n distributions for comparison.\n\n >>> dfnum = 3 # between group deg of freedom\n >>> dfden = 20 # within groups degrees of freedom\n >>> nonc = 3.0\n >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000)\n >>> NF = np.histogram(nc_vals, bins=50, normed=True)\n >>> c_vals = np.random.f(dfnum, dfden, 1000000)\n >>> F = np.histogram(c_vals, bins=50, normed=True)\n >>> plt.plot(F[1][1:], F[0])\n >>> plt.plot(NF[1][1:], NF[0])\n >>> plt.show()\n\n "; +static const char __pyx_k_normal_loc_0_0_scale_1_0_size_N[] = "\n normal(loc=0.0, scale=1.0, size=None)\n\n Draw random samples from a normal (Gaussian) distribution.\n\n The probability density function of the normal distribution, first\n derived by De Moivre and 200 years later by both Gauss and Laplace\n independently [2]_, is often called the bell curve because of\n its characteristic shape (see the example below).\n\n The normal distributions occurs often in nature. For example, it\n describes the commonly occurring distribution of samples influenced\n by a large number of tiny, random disturbances, each with its own\n unique distribution [2]_.\n\n Parameters\n ----------\n loc : float or array_like of floats\n Mean (\"centre\") of the distribution.\n scale : float or array_like of floats\n Standard deviation (spread or \"width\") of the distribution.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``loc`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized normal distribution.\n\n See Also\n --------\n scipy.stats.norm : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Gaussian distribution is\n\n .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }}\n e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} },\n\n where :math:`\\mu` is the mean and :math:`\\sigma` the standard\n deviation. The square of the standard deviation, :math:`\\sigma^2`,\n is called the v""ariance.\n\n The function has its peak at the mean, and its \"spread\" increases with\n the standard deviation (the function reaches 0.607 times its maximum at\n :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that\n `numpy.random.normal` is more likely to return samples lying close to\n the mean, rather than those far away.\n\n References\n ----------\n .. [1] Wikipedia, \"Normal distribution\",\n http://en.wikipedia.org/wiki/Normal_distribution\n .. [2] P. R. Peebles Jr., \"Central Limit Theorem\" in \"Probability,\n Random Variables and Random Signal Principles\", 4th ed., 2001,\n pp. 51, 51, 125.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> mu, sigma = 0, 0.1 # mean and standard deviation\n >>> s = np.random.normal(mu, sigma, 1000)\n\n Verify the mean and the variance:\n\n >>> abs(mu - np.mean(s)) < 0.01\n True\n\n >>> abs(sigma - np.std(s, ddof=1)) < 0.01\n True\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 30, normed=True)\n >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *\n ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ),\n ... linewidth=2, color='r')\n >>> plt.show()\n\n "; +static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; +static const char __pyx_k_pareto_a_size_None_Draw_samples[] = "\n pareto(a, size=None)\n\n Draw samples from a Pareto II or Lomax distribution with\n specified shape.\n\n The Lomax or Pareto II distribution is a shifted Pareto\n distribution. The classical Pareto distribution can be\n obtained from the Lomax distribution by adding 1 and\n multiplying by the scale parameter ``m`` (see Notes). The\n smallest value of the Lomax distribution is zero while for the\n classical Pareto distribution it is ``mu``, where the standard\n Pareto distribution has location ``mu = 1``. Lomax can also\n be considered as a simplified version of the Generalized\n Pareto distribution (available in SciPy), with the scale set\n to one and the location set to zero.\n\n The Pareto distribution must be greater than zero, and is\n unbounded above. It is also known as the \"80-20 rule\". In\n this distribution, 80 percent of the weights are in the lowest\n 20 percent of the range, while the other 20 percent fill the\n remaining 80 percent of the range.\n\n Parameters\n ----------\n a : float or array_like of floats\n Shape of the distribution. Should be greater than zero.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` is a scalar. Otherwise,\n ``np.array(a).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Pareto distribution.\n\n See Also\n --------\n scipy.stats.lomax : probability density function, distribution or\n cumulative density function, etc.\n scipy.stats.genpareto : probability density function, distribution or\n cumulative densit""y function, etc.\n\n Notes\n -----\n The probability density for the Pareto distribution is\n\n .. math:: p(x) = \\frac{am^a}{x^{a+1}}\n\n where :math:`a` is the shape and :math:`m` the scale.\n\n The Pareto distribution, named after the Italian economist\n Vilfredo Pareto, is a power law probability distribution\n useful in many real world problems. Outside the field of\n economics it is generally referred to as the Bradford\n distribution. Pareto developed the distribution to describe\n the distribution of wealth in an economy. It has also found\n use in insurance, web page access statistics, oil field sizes,\n and many other problems, including the download frequency for\n projects in Sourceforge [1]_. It is one of the so-called\n \"fat-tailed\" distributions.\n\n\n References\n ----------\n .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of\n Sourceforge projects.\n .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne.\n .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme\n Values, Birkhauser Verlag, Basel, pp 23-30.\n .. [4] Wikipedia, \"Pareto distribution\",\n http://en.wikipedia.org/wiki/Pareto_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a, m = 3., 2. # shape and mode\n >>> s = (np.random.pareto(a, 1000) + 1) * m\n\n Display the histogram of the samples, along with the probability\n density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, _ = plt.hist(s, 100, normed=True)\n >>> fit = a*m**a / bins**(a+1)\n >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r')\n >>> plt.show()\n\n "; +static const char __pyx_k_power_a_size_None_Draws_samples[] = "\n power(a, size=None)\n\n Draws samples in [0, 1] from a power distribution with positive\n exponent a - 1.\n\n Also known as the power function distribution.\n\n Parameters\n ----------\n a : float or array_like of floats\n Parameter of the distribution. Should be greater than zero.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` is a scalar. Otherwise,\n ``np.array(a).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized power distribution.\n\n Raises\n ------\n ValueError\n If a < 1.\n\n Notes\n -----\n The probability density function is\n\n .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0.\n\n The power function distribution is just the inverse of the Pareto\n distribution. It may also be seen as a special case of the Beta\n distribution.\n\n It is used, for example, in modeling the over-reporting of insurance\n claims.\n\n References\n ----------\n .. [1] Christian Kleiber, Samuel Kotz, \"Statistical size distributions\n in economics and actuarial sciences\", Wiley, 2003.\n .. [2] Heckert, N. A. and Filliben, James J. \"NIST Handbook 148:\n Dataplot Reference Manual, Volume 2: Let Subcommands and Library\n Functions\", National Institute of Standards and Technology\n Handbook Series, June 2003.\n http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a = 5. # shape\n >>> samples = 100""0\n >>> s = np.random.power(a, samples)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, bins=30)\n >>> x = np.linspace(0, 1, 100)\n >>> y = a*x**(a-1.)\n >>> normed_y = samples*np.diff(bins)[0]*y\n >>> plt.plot(x, normed_y)\n >>> plt.show()\n\n Compare the power function distribution to the inverse of the Pareto.\n\n >>> from scipy import stats\n >>> rvs = np.random.power(5, 1000000)\n >>> rvsp = np.random.pareto(5, 1000000)\n >>> xx = np.linspace(0,1,100)\n >>> powpdf = stats.powerlaw.pdf(xx,5)\n\n >>> plt.figure()\n >>> plt.hist(rvs, bins=50, normed=True)\n >>> plt.plot(xx,powpdf,'r-')\n >>> plt.title('np.random.power(5)')\n\n >>> plt.figure()\n >>> plt.hist(1./(1.+rvsp), bins=50, normed=True)\n >>> plt.plot(xx,powpdf,'r-')\n >>> plt.title('inverse of 1 + np.random.pareto(5)')\n\n >>> plt.figure()\n >>> plt.hist(1./(1.+rvsp), bins=50, normed=True)\n >>> plt.plot(xx,powpdf,'r-')\n >>> plt.title('inverse of stats.pareto(5)')\n\n "; +static const char __pyx_k_randint_low_high_None_size_None[] = "\n randint(low, high=None, size=None, dtype='l')\n\n Return random integers from `low` (inclusive) to `high` (exclusive).\n\n Return random integers from the \"discrete uniform\" distribution of\n the specified dtype in the \"half-open\" interval [`low`, `high`). If\n `high` is None (the default), then results are from [0, `low`).\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution (unless\n ``high=None``, in which case this parameter is one above the\n *highest* such integer).\n high : int, optional\n If provided, one above the largest (signed) integer to be drawn\n from the distribution (see above for behavior if ``high=None``).\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n dtype : dtype, optional\n Desired dtype of the result. All dtypes are determined by their\n name, i.e., 'int64', 'int', etc, so byteorder is not available\n and a specific precision may have different C types depending\n on the platform. The default value is 'np.int'.\n\n .. versionadded:: 1.11.0\n\n Returns\n -------\n out : int or ndarray of ints\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n See Also\n --------\n random.random_integers : similar to `randint`, only for the closed\n interval [`low`, `high`], and 1 is the lowest value if `high` is\n omitted. In particular, this other one is the one to use to generate\n uniformly distributed discrete non-integers.\n\n Examples\n ---""-----\n >>> np.random.randint(2, size=10)\n array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0])\n >>> np.random.randint(1, size=10)\n array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])\n\n Generate a 2 x 4 array of ints between 0 and 4, inclusive:\n\n >>> np.random.randint(5, size=(2, 4))\n array([[4, 0, 2, 1],\n [3, 2, 2, 0]])\n\n "; +static const char __pyx_k_random_integers_low_high_None_s[] = "\n random_integers(low, high=None, size=None)\n\n Random integers of type np.int between `low` and `high`, inclusive.\n\n Return random integers of type np.int from the \"discrete uniform\"\n distribution in the closed interval [`low`, `high`]. If `high` is\n None (the default), then results are from [1, `low`]. The np.int\n type translates to the C long type used by Python 2 for \"short\"\n integers and its precision is platform dependent.\n\n This function has been deprecated. Use randint instead.\n\n .. deprecated:: 1.11.0\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution (unless\n ``high=None``, in which case this parameter is the *highest* such\n integer).\n high : int, optional\n If provided, the largest (signed) integer to be drawn from the\n distribution (see above for behavior if ``high=None``).\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : int or ndarray of ints\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n See Also\n --------\n random.randint : Similar to `random_integers`, only for the half-open\n interval [`low`, `high`), and 0 is the lowest value if `high` is\n omitted.\n\n Notes\n -----\n To sample from N evenly spaced floating-point numbers between a and b,\n use::\n\n a + (b - a) * (np.random.random_integers(N) - 1) / (N - 1.)\n\n Examples\n --------\n >>> np.random.random_integers(5)\n 4\n >"">> type(np.random.random_integers(5))\n \n >>> np.random.random_integers(5, size=(3,2))\n array([[5, 4],\n [3, 3],\n [4, 5]])\n\n Choose five random numbers from the set of five evenly-spaced\n numbers between 0 and 2.5, inclusive (*i.e.*, from the set\n :math:`{0, 5/8, 10/8, 15/8, 20/8}`):\n\n >>> 2.5 * (np.random.random_integers(5, size=(5,)) - 1) / 4.\n array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ])\n\n Roll two six sided dice 1000 times and sum the results:\n\n >>> d1 = np.random.random_integers(1, 6, 1000)\n >>> d2 = np.random.random_integers(1, 6, 1000)\n >>> dsums = d1 + d2\n\n Display results as a histogram:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(dsums, 11, normed=True)\n >>> plt.show()\n\n "; +static const char __pyx_k_rayleigh_scale_1_0_size_None_Dr[] = "\n rayleigh(scale=1.0, size=None)\n\n Draw samples from a Rayleigh distribution.\n\n The :math:`\\chi` and Weibull distributions are generalizations of the\n Rayleigh.\n\n Parameters\n ----------\n scale : float or array_like of floats, optional\n Scale, also equals the mode. Should be >= 0. Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``scale`` is a scalar. Otherwise,\n ``np.array(scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Rayleigh distribution.\n\n Notes\n -----\n The probability density function for the Rayleigh distribution is\n\n .. math:: P(x;scale) = \\frac{x}{scale^2}e^{\\frac{-x^2}{2 \\cdotp scale^2}}\n\n The Rayleigh distribution would arise, for example, if the East\n and North components of the wind velocity had identical zero-mean\n Gaussian distributions. Then the wind speed would have a Rayleigh\n distribution.\n\n References\n ----------\n .. [1] Brighton Webs Ltd., \"Rayleigh Distribution,\"\n http://www.brighton-webs.co.uk/distributions/rayleigh.asp\n .. [2] Wikipedia, \"Rayleigh distribution\"\n http://en.wikipedia.org/wiki/Rayleigh_distribution\n\n Examples\n --------\n Draw values from the distribution and plot the histogram\n\n >>> values = hist(np.random.rayleigh(3, 100000), bins=200, normed=True)\n\n Wave heights tend to follow a Rayleigh distribution. If the mean wave\n height is 1 meter, what fraction of waves are likely to be larger than 3\n meters?\n\n >>> meanvalue = 1\n >>> mo""devalue = np.sqrt(2 / np.pi) * meanvalue\n >>> s = np.random.rayleigh(modevalue, 1000000)\n\n The percentage of waves larger than 3 meters is:\n\n >>> 100.*sum(s>3)/1000000.\n 0.087300000000000003\n\n "; +static const char __pyx_k_standard_t_df_size_None_Draw_sa[] = "\n standard_t(df, size=None)\n\n Draw samples from a standard Student's t distribution with `df` degrees\n of freedom.\n\n A special case of the hyperbolic distribution. As `df` gets\n large, the result resembles that of the standard normal\n distribution (`standard_normal`).\n\n Parameters\n ----------\n df : float or array_like of floats\n Degrees of freedom, should be > 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``df`` is a scalar. Otherwise,\n ``np.array(df).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized standard Student's t distribution.\n\n Notes\n -----\n The probability density function for the t distribution is\n\n .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df}\n \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2}\n\n The t test is based on an assumption that the data come from a\n Normal distribution. The t test provides a way to test whether\n the sample mean (that is the mean calculated from the data) is\n a good estimate of the true mean.\n\n The derivation of the t-distribution was first published in\n 1908 by William Gosset while working for the Guinness Brewery\n in Dublin. Due to proprietary issues, he had to publish under\n a pseudonym, and so he used the name Student.\n\n References\n ----------\n .. [1] Dalgaard, Peter, \"Introductory Statistics With R\",\n Springer, 2002.\n .. [2] Wikipedia, \"Student's t-distribution\"\n http://en.wikipedia.org/wiki/Student's_t-distrib""ution\n\n Examples\n --------\n From Dalgaard page 83 [1]_, suppose the daily energy intake for 11\n women in Kj is:\n\n >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\\n ... 7515, 8230, 8770])\n\n Does their energy intake deviate systematically from the recommended\n value of 7725 kJ?\n\n We have 10 degrees of freedom, so is the sample mean within 95% of the\n recommended value?\n\n >>> s = np.random.standard_t(10, size=100000)\n >>> np.mean(intake)\n 6753.636363636364\n >>> intake.std(ddof=1)\n 1142.1232221373727\n\n Calculate the t statistic, setting the ddof parameter to the unbiased\n value so the divisor in the standard deviation will be degrees of\n freedom, N-1.\n\n >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake)))\n >>> import matplotlib.pyplot as plt\n >>> h = plt.hist(s, bins=100, normed=True)\n\n For a one-sided t-test, how far out in the distribution does the t\n statistic appear?\n\n >>> np.sum(s>> import matplotlib.pyplot as plt\n >>> h = plt.hist(np.random.triangular(-3, 0, 8, 100000), bins=200,\n ... normed=True)\n >>> plt.show()\n\n "; +static const char __pyx_k_uniform_low_0_0_high_1_0_size_N[] = "\n uniform(low=0.0, high=1.0, size=None)\n\n Draw samples from a uniform distribution.\n\n Samples are uniformly distributed over the half-open interval\n ``[low, high)`` (includes low, but excludes high). In other words,\n any value within the given interval is equally likely to be drawn\n by `uniform`.\n\n Parameters\n ----------\n low : float or array_like of floats, optional\n Lower boundary of the output interval. All values generated will be\n greater than or equal to low. The default value is 0.\n high : float or array_like of floats\n Upper boundary of the output interval. All values generated will be\n less than high. The default value is 1.0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``low`` and ``high`` are both scalars.\n Otherwise, ``np.broadcast(low, high).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized uniform distribution.\n\n See Also\n --------\n randint : Discrete uniform distribution, yielding integers.\n random_integers : Discrete uniform distribution over the closed\n interval ``[low, high]``.\n random_sample : Floats uniformly distributed over ``[0, 1)``.\n random : Alias for `random_sample`.\n rand : Convenience function that accepts dimensions as input, e.g.,\n ``rand(2,2)`` would generate a 2-by-2 array of floats,\n uniformly distributed over ``[0, 1)``.\n\n Notes\n -----\n The probability density function of the uniform distribution is\n\n .. math:: p(x) = \\frac{1}{b - a}\n\n anywhe""re within the interval ``[a, b)``, and zero elsewhere.\n\n When ``high`` == ``low``, values of ``low`` will be returned.\n If ``high`` < ``low``, the results are officially undefined\n and may eventually raise an error, i.e. do not rely on this\n function to behave when passed arguments satisfying that\n inequality condition.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> s = np.random.uniform(-1,0,1000)\n\n All values are within the given interval:\n\n >>> np.all(s >= -1)\n True\n >>> np.all(s < 0)\n True\n\n Display the histogram of the samples, along with the\n probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 15, normed=True)\n >>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r')\n >>> plt.show()\n\n "; +static const char __pyx_k_vonmises_mu_kappa_size_None_Dra[] = "\n vonmises(mu, kappa, size=None)\n\n Draw samples from a von Mises distribution.\n\n Samples are drawn from a von Mises distribution with specified mode\n (mu) and dispersion (kappa), on the interval [-pi, pi].\n\n The von Mises distribution (also known as the circular normal\n distribution) is a continuous probability distribution on the unit\n circle. It may be thought of as the circular analogue of the normal\n distribution.\n\n Parameters\n ----------\n mu : float or array_like of floats\n Mode (\"center\") of the distribution.\n kappa : float or array_like of floats\n Dispersion of the distribution, has to be >=0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``mu`` and ``kappa`` are both scalars.\n Otherwise, ``np.broadcast(mu, kappa).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized von Mises distribution.\n\n See Also\n --------\n scipy.stats.vonmises : probability density function, distribution, or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the von Mises distribution is\n\n .. math:: p(x) = \\frac{e^{\\kappa cos(x-\\mu)}}{2\\pi I_0(\\kappa)},\n\n where :math:`\\mu` is the mode and :math:`\\kappa` the dispersion,\n and :math:`I_0(\\kappa)` is the modified Bessel function of order 0.\n\n The von Mises is named for Richard Edler von Mises, who was born in\n Austria-Hungary, in what is now the Ukraine. He fled to the United\n States in 1939 and became a professor at Harvard. He worked in\n probability theory, aero""dynamics, fluid mechanics, and philosophy of\n science.\n\n References\n ----------\n .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). \"Handbook of\n Mathematical Functions with Formulas, Graphs, and Mathematical\n Tables, 9th printing,\" New York: Dover, 1972.\n .. [2] von Mises, R., \"Mathematical Theory of Probability\n and Statistics\", New York: Academic Press, 1964.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> mu, kappa = 0.0, 4.0 # mean and dispersion\n >>> s = np.random.vonmises(mu, kappa, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> from scipy.special import i0\n >>> plt.hist(s, 50, normed=True)\n >>> x = np.linspace(-np.pi, np.pi, num=51)\n >>> y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa))\n >>> plt.plot(x, y, linewidth=2, color='r')\n >>> plt.show()\n\n "; +static const char __pyx_k_weibull_a_size_None_Draw_sample[] = "\n weibull(a, size=None)\n\n Draw samples from a Weibull distribution.\n\n Draw samples from a 1-parameter Weibull distribution with the given\n shape parameter `a`.\n\n .. math:: X = (-ln(U))^{1/a}\n\n Here, U is drawn from the uniform distribution over (0,1].\n\n The more common 2-parameter Weibull, including a scale parameter\n :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`.\n\n Parameters\n ----------\n a : float or array_like of floats\n Shape of the distribution. Should be greater than zero.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` is a scalar. Otherwise,\n ``np.array(a).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Weibull distribution.\n\n See Also\n --------\n scipy.stats.weibull_max\n scipy.stats.weibull_min\n scipy.stats.genextreme\n gumbel\n\n Notes\n -----\n The Weibull (or Type III asymptotic extreme value distribution\n for smallest values, SEV Type III, or Rosin-Rammler\n distribution) is one of a class of Generalized Extreme Value\n (GEV) distributions used in modeling extreme value problems.\n This class includes the Gumbel and Frechet distributions.\n\n The probability density for the Weibull distribution is\n\n .. math:: p(x) = \\frac{a}\n {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a},\n\n where :math:`a` is the shape and :math:`\\lambda` the scale.\n\n The function has its peak (the mode) at\n :math:`\\lambda(\\frac{a-1}{a})^{1/a}`.\n\n When ``a = 1``, the Weibull di""stribution reduces to the exponential\n distribution.\n\n References\n ----------\n .. [1] Waloddi Weibull, Royal Technical University, Stockholm,\n 1939 \"A Statistical Theory Of The Strength Of Materials\",\n Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939,\n Generalstabens Litografiska Anstalts Forlag, Stockholm.\n .. [2] Waloddi Weibull, \"A Statistical Distribution Function of\n Wide Applicability\", Journal Of Applied Mechanics ASME Paper\n 1951.\n .. [3] Wikipedia, \"Weibull distribution\",\n http://en.wikipedia.org/wiki/Weibull_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a = 5. # shape\n >>> s = np.random.weibull(a, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> x = np.arange(1,100.)/50.\n >>> def weib(x,n,a):\n ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a)\n\n >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000))\n >>> x = np.arange(1,100.)/50.\n >>> scale = count.max()/weib(x, 1., 5.).max()\n >>> plt.plot(x, weib(x, 1., 5.)*scale)\n >>> plt.show()\n\n "; +static const char __pyx_k_zipf_a_size_None_Draw_samples_f[] = "\n zipf(a, size=None)\n\n Draw samples from a Zipf distribution.\n\n Samples are drawn from a Zipf distribution with specified parameter\n `a` > 1.\n\n The Zipf distribution (also known as the zeta distribution) is a\n continuous probability distribution that satisfies Zipf's law: the\n frequency of an item is inversely proportional to its rank in a\n frequency table.\n\n Parameters\n ----------\n a : float or array_like of floats\n Distribution parameter. Should be greater than 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` is a scalar. Otherwise,\n ``np.array(a).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Zipf distribution.\n\n See Also\n --------\n scipy.stats.zipf : probability density function, distribution, or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Zipf distribution is\n\n .. math:: p(x) = \\frac{x^{-a}}{\\zeta(a)},\n\n where :math:`\\zeta` is the Riemann Zeta function.\n\n It is named for the American linguist George Kingsley Zipf, who noted\n that the frequency of any word in a sample of a language is inversely\n proportional to its rank in the frequency table.\n\n References\n ----------\n .. [1] Zipf, G. K., \"Selected Studies of the Principle of Relative\n Frequency in Language,\" Cambridge, MA: Harvard Univ. Press,\n 1932.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a = 2. # parameter\n >>> s = np.random.zipf(a, ""1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> from scipy import special\n\n Truncate s values at 50 so plot is interesting:\n\n >>> count, bins, ignored = plt.hist(s[s<50], 50, normed=True)\n >>> x = np.arange(1., 50.)\n >>> y = x**(-a) / special.zetac(a)\n >>> plt.plot(x, y/max(y), linewidth=2, color='r')\n >>> plt.show()\n\n "; +static const char __pyx_k_Cannot_take_a_larger_sample_than[] = "Cannot take a larger sample than population when 'replace=False'"; +static const char __pyx_k_Fewer_non_zero_entries_in_p_than[] = "Fewer non-zero entries in p than size"; +static const char __pyx_k_RandomState_multinomial_line_454[] = "RandomState.multinomial (line 4543)"; +static const char __pyx_k_RandomState_negative_binomial_li[] = "RandomState.negative_binomial (line 3813)"; +static const char __pyx_k_RandomState_noncentral_chisquare[] = "RandomState.noncentral_chisquare (line 2286)"; +static const char __pyx_k_RandomState_noncentral_f_line_21[] = "RandomState.noncentral_f (line 2104)"; +static const char __pyx_k_RandomState_permutation_line_486[] = "RandomState.permutation (line 4867)"; +static const char __pyx_k_RandomState_random_integers_line[] = "RandomState.random_integers (line 1422)"; +static const char __pyx_k_RandomState_random_sample_line_8[] = "RandomState.random_sample (line 819)"; +static const char __pyx_k_RandomState_standard_cauchy_line[] = "RandomState.standard_cauchy (line 2392)"; +static const char __pyx_k_RandomState_standard_exponential[] = "RandomState.standard_exponential (line 1784)"; +static const char __pyx_k_RandomState_standard_normal_line[] = "RandomState.standard_normal (line 1519)"; +static const char __pyx_k_RandomState_standard_t_line_2456[] = "RandomState.standard_t (line 2456)"; +static const char __pyx_k_RandomState_triangular_line_3603[] = "RandomState.triangular (line 3603)"; +static const char __pyx_k_Seed_values_must_be_between_0_an[] = "Seed values must be between 0 and 2**32 - 1"; +static const char __pyx_k_This_function_is_deprecated_Plea[] = "This function is deprecated. Please call randint(1, {low} + 1) instead"; +static const char __pyx_k_a_must_be_1_dimensional_or_an_in[] = "a must be 1-dimensional or an integer"; +static const char __pyx_k_check_valid_must_equal_warn_rais[] = "check_valid must equal 'warn', 'raise', or 'ignore'"; +static const char __pyx_k_cov_must_be_2_dimensional_and_sq[] = "cov must be 2 dimensional and square"; +static const char __pyx_k_covariance_is_not_positive_semid[] = "covariance is not positive-semidefinite."; +static const char __pyx_k_mean_and_cov_must_have_same_leng[] = "mean and cov must have same length"; +static const char __pyx_k_probabilities_are_not_non_negati[] = "probabilities are not non-negative"; +static const char __pyx_k_size_is_not_compatible_with_inpu[] = "size is not compatible with inputs"; +static const char __pyx_k_This_function_is_deprecated_Plea_2[] = "This function is deprecated. Please call randint({low}, {high} + 1) instead"; +static PyObject *__pyx_kp_s_Cannot_take_a_larger_sample_than; +static PyObject *__pyx_n_s_DeprecationWarning; +static PyObject *__pyx_kp_s_Fewer_non_zero_entries_in_p_than; +static PyObject *__pyx_n_s_ImportError; +static PyObject *__pyx_n_s_L; +static PyObject *__pyx_n_s_Lock; +static PyObject *__pyx_n_s_MT19937; +static PyObject *__pyx_n_s_OverflowError; +static PyObject *__pyx_kp_u_RandomState_binomial_line_3697; +static PyObject *__pyx_kp_u_RandomState_bytes_line_1004; +static PyObject *__pyx_kp_u_RandomState_chisquare_line_2205; +static PyObject *__pyx_kp_u_RandomState_choice_line_1033; +static PyObject *__pyx_n_s_RandomState_ctor; +static PyObject *__pyx_kp_u_RandomState_dirichlet_line_4656; +static PyObject *__pyx_kp_u_RandomState_f_line_1997; +static PyObject *__pyx_kp_u_RandomState_gamma_line_1901; +static PyObject *__pyx_kp_u_RandomState_geometric_line_4095; +static PyObject *__pyx_kp_u_RandomState_gumbel_line_3089; +static PyObject *__pyx_kp_u_RandomState_hypergeometric_line; +static PyObject *__pyx_kp_u_RandomState_laplace_line_2991; +static PyObject *__pyx_kp_u_RandomState_logistic_line_3220; +static PyObject *__pyx_kp_u_RandomState_lognormal_line_3313; +static PyObject *__pyx_kp_u_RandomState_logseries_line_4285; +static PyObject *__pyx_kp_u_RandomState_multinomial_line_454; +static PyObject *__pyx_kp_u_RandomState_multivariate_normal; +static PyObject *__pyx_kp_u_RandomState_negative_binomial_li; +static PyObject *__pyx_kp_u_RandomState_noncentral_chisquare; +static PyObject *__pyx_kp_u_RandomState_noncentral_f_line_21; +static PyObject *__pyx_kp_u_RandomState_normal_line_1552; +static PyObject *__pyx_kp_u_RandomState_pareto_line_2660; +static PyObject *__pyx_kp_u_RandomState_permutation_line_486; +static PyObject *__pyx_kp_u_RandomState_poisson_line_3914; +static PyObject *__pyx_kp_u_RandomState_power_line_2880; +static PyObject *__pyx_kp_u_RandomState_rand_line_1321; +static PyObject *__pyx_kp_u_RandomState_randint_line_910; +static PyObject *__pyx_kp_u_RandomState_randn_line_1365; +static PyObject *__pyx_kp_u_RandomState_random_integers_line; +static PyObject *__pyx_kp_u_RandomState_random_sample_line_8; +static PyObject *__pyx_kp_u_RandomState_rayleigh_line_3437; +static PyObject *__pyx_kp_u_RandomState_shuffle_line_4779; +static PyObject *__pyx_kp_u_RandomState_standard_cauchy_line; +static PyObject *__pyx_kp_u_RandomState_standard_exponential; +static PyObject *__pyx_kp_u_RandomState_standard_gamma_line; +static PyObject *__pyx_kp_u_RandomState_standard_normal_line; +static PyObject *__pyx_kp_u_RandomState_standard_t_line_2456; +static PyObject *__pyx_kp_u_RandomState_tomaxint_line_863; +static PyObject *__pyx_kp_u_RandomState_triangular_line_3603; +static PyObject *__pyx_kp_u_RandomState_uniform_line_1215; +static PyObject *__pyx_kp_u_RandomState_vonmises_line_2562; +static PyObject *__pyx_kp_u_RandomState_wald_line_3516; +static PyObject *__pyx_kp_u_RandomState_weibull_line_2770; +static PyObject *__pyx_kp_u_RandomState_zipf_line_4002; +static PyObject *__pyx_kp_s_Range_exceeds_valid_bounds; +static PyObject *__pyx_n_s_RuntimeWarning; +static PyObject *__pyx_kp_s_Seed_array_must_be_1_d; +static PyObject *__pyx_kp_s_Seed_must_be_between_0_and_2_32; +static PyObject *__pyx_kp_s_Seed_must_be_non_empty; +static PyObject *__pyx_kp_s_Seed_values_must_be_between_0_an; +static PyObject *__pyx_n_s_T; +static PyObject *__pyx_kp_s_This_function_is_deprecated_Plea; +static PyObject *__pyx_kp_s_This_function_is_deprecated_Plea_2; +static PyObject *__pyx_n_s_TypeError; +static PyObject *__pyx_kp_s_Unsupported_dtype_s_for_randint; +static PyObject *__pyx_n_s_ValueError; +static PyObject *__pyx_n_s_a; +static PyObject *__pyx_kp_s_a_0; +static PyObject *__pyx_kp_s_a_0_2; +static PyObject *__pyx_kp_s_a_and_p_must_have_same_size; +static PyObject *__pyx_kp_s_a_must_be_1_dimensional; +static PyObject *__pyx_kp_s_a_must_be_1_dimensional_or_an_in; +static PyObject *__pyx_kp_s_a_must_be_a_valid_float_1_0; +static PyObject *__pyx_kp_s_a_must_be_greater_than_0; +static PyObject *__pyx_kp_s_a_must_be_non_empty; +static PyObject *__pyx_kp_s_a_must_contain_valid_floats_1_0; +static PyObject *__pyx_n_s_add; +static PyObject *__pyx_kp_s_algorithm_must_be_MT19937; +static PyObject *__pyx_n_s_all; +static PyObject *__pyx_n_s_allclose; +static PyObject *__pyx_n_s_alpha; +static PyObject *__pyx_kp_s_alpha_0; +static PyObject *__pyx_n_s_any; +static PyObject *__pyx_n_s_arange; +static PyObject *__pyx_n_s_array; +static PyObject *__pyx_n_s_array_data; +static PyObject *__pyx_n_s_asarray; +static PyObject *__pyx_n_s_astype; +static PyObject *__pyx_n_s_atol; +static PyObject *__pyx_n_s_b; +static PyObject *__pyx_kp_s_b_0; +static PyObject *__pyx_n_s_beta; +static PyObject *__pyx_n_s_binomial; +static PyObject *__pyx_kp_u_binomial_n_p_size_None_Draw_sam; +static PyObject *__pyx_n_s_bool; +static PyObject *__pyx_n_s_bool_2; +static PyObject *__pyx_n_s_broadcast; +static PyObject *__pyx_n_s_buf; +static PyObject *__pyx_n_s_bytes; +static PyObject *__pyx_kp_u_bytes_length_Return_random_byte; +static PyObject *__pyx_n_s_casting; +static PyObject *__pyx_n_s_check_valid; +static PyObject *__pyx_kp_s_check_valid_must_equal_warn_rais; +static PyObject *__pyx_n_s_chisquare; +static PyObject *__pyx_kp_u_chisquare_df_size_None_Draw_sam; +static PyObject *__pyx_n_s_choice; +static PyObject *__pyx_kp_u_choice_a_size_None_replace_True; +static PyObject *__pyx_n_s_cline_in_traceback; +static PyObject *__pyx_n_s_cnt; +static PyObject *__pyx_n_s_copy; +static PyObject *__pyx_n_s_count_nonzero; +static PyObject *__pyx_n_s_cov; +static PyObject *__pyx_kp_s_cov_must_be_2_dimensional_and_sq; +static PyObject *__pyx_kp_s_covariance_is_not_positive_semid; +static PyObject *__pyx_n_s_ctypes; +static PyObject *__pyx_n_s_cumsum; +static PyObject *__pyx_n_s_d; +static PyObject *__pyx_n_s_data; +static PyObject *__pyx_n_s_df; +static PyObject *__pyx_kp_s_df_0; +static PyObject *__pyx_n_s_dfden; +static PyObject *__pyx_kp_s_dfden_0; +static PyObject *__pyx_n_s_dfnum; +static PyObject *__pyx_kp_s_dfnum_0; +static PyObject *__pyx_n_s_dirichlet; +static PyObject *__pyx_kp_u_dirichlet_alpha_size_None_Draw; +static PyObject *__pyx_n_s_dot; +static PyObject *__pyx_n_s_dtype; +static PyObject *__pyx_n_s_dummy_threading; +static PyObject *__pyx_n_s_empty; +static PyObject *__pyx_n_s_empty_like; +static PyObject *__pyx_n_s_enter; +static PyObject *__pyx_n_s_eps; +static PyObject *__pyx_n_s_equal; +static PyObject *__pyx_n_s_exit; +static PyObject *__pyx_n_s_exponential; +static PyObject *__pyx_n_s_f; +static PyObject *__pyx_kp_u_f_dfnum_dfden_size_None_Draw_sa; +static PyObject *__pyx_n_s_finfo; +static PyObject *__pyx_n_s_float64; +static PyObject *__pyx_n_s_floating; +static PyObject *__pyx_n_s_format; +static PyObject *__pyx_n_s_gamma; +static PyObject *__pyx_kp_u_gamma_shape_scale_1_0_size_None; +static PyObject *__pyx_n_s_geometric; +static PyObject *__pyx_kp_u_geometric_p_size_None_Draw_samp; +static PyObject *__pyx_n_s_get_state; +static PyObject *__pyx_n_s_greater; +static PyObject *__pyx_n_s_greater_equal; +static PyObject *__pyx_n_s_gumbel; +static PyObject *__pyx_kp_u_gumbel_loc_0_0_scale_1_0_size_N; +static PyObject *__pyx_n_s_high; +static PyObject *__pyx_kp_s_high_is_out_of_bounds_for_s; +static PyObject *__pyx_n_s_hypergeometric; +static PyObject *__pyx_kp_u_hypergeometric_ngood_nbad_nsamp; +static PyObject *__pyx_n_s_ignore; +static PyObject *__pyx_n_s_iinfo; +static PyObject *__pyx_n_s_import; +static PyObject *__pyx_n_s_index; +static PyObject *__pyx_n_s_int; +static PyObject *__pyx_n_s_int16; +static PyObject *__pyx_n_s_int32; +static PyObject *__pyx_n_s_int64; +static PyObject *__pyx_n_s_int8; +static PyObject *__pyx_n_s_integer; +static PyObject *__pyx_n_s_intp; +static PyObject *__pyx_n_s_isfinite; +static PyObject *__pyx_n_s_isnan; +static PyObject *__pyx_n_s_issubdtype; +static PyObject *__pyx_n_s_item; +static PyObject *__pyx_n_s_itemsize; +static PyObject *__pyx_n_s_kappa; +static PyObject *__pyx_kp_s_kappa_0; +static PyObject *__pyx_n_s_l; +static PyObject *__pyx_n_s_lam; +static PyObject *__pyx_kp_s_lam_0; +static PyObject *__pyx_kp_s_lam_value_too_large; +static PyObject *__pyx_kp_s_lam_value_too_large_2; +static PyObject *__pyx_n_s_laplace; +static PyObject *__pyx_kp_u_laplace_loc_0_0_scale_1_0_size; +static PyObject *__pyx_n_s_left; +static PyObject *__pyx_kp_s_left_mode; +static PyObject *__pyx_kp_s_left_right; +static PyObject *__pyx_n_s_less; +static PyObject *__pyx_n_s_less_equal; +static PyObject *__pyx_n_s_loc; +static PyObject *__pyx_n_s_logical_or; +static PyObject *__pyx_n_s_logistic; +static PyObject *__pyx_kp_u_logistic_loc_0_0_scale_1_0_size; +static PyObject *__pyx_n_s_lognormal; +static PyObject *__pyx_kp_u_lognormal_mean_0_0_sigma_1_0_si; +static PyObject *__pyx_n_s_logseries; +static PyObject *__pyx_kp_u_logseries_p_size_None_Draw_samp; +static PyObject *__pyx_n_s_long; +static PyObject *__pyx_n_s_low; +static PyObject *__pyx_kp_s_low_high; +static PyObject *__pyx_kp_s_low_is_out_of_bounds_for_s; +static PyObject *__pyx_n_s_main; +static PyObject *__pyx_n_s_max; +static PyObject *__pyx_n_s_mean; +static PyObject *__pyx_kp_s_mean_0; +static PyObject *__pyx_kp_s_mean_0_0; +static PyObject *__pyx_kp_s_mean_and_cov_must_have_same_leng; +static PyObject *__pyx_kp_s_mean_must_be_1_dimensional; +static PyObject *__pyx_n_s_mode; +static PyObject *__pyx_kp_s_mode_right; +static PyObject *__pyx_n_s_mtrand; +static PyObject *__pyx_kp_s_mtrand_pyx; +static PyObject *__pyx_n_s_mu; +static PyObject *__pyx_n_s_multinomial; +static PyObject *__pyx_kp_u_multinomial_n_pvals_size_None_D; +static PyObject *__pyx_n_s_multivariate_normal; +static PyObject *__pyx_kp_u_multivariate_normal_mean_cov_si; +static PyObject *__pyx_n_s_n; +static PyObject *__pyx_kp_s_n_0; +static PyObject *__pyx_kp_s_n_0_2; +static PyObject *__pyx_n_s_name; +static PyObject *__pyx_n_s_nbad; +static PyObject *__pyx_kp_s_nbad_0; +static PyObject *__pyx_n_s_ndarray; +static PyObject *__pyx_n_s_ndim; +static PyObject *__pyx_n_s_negative_binomial; +static PyObject *__pyx_kp_u_negative_binomial_n_p_size_None; +static PyObject *__pyx_n_s_ngood; +static PyObject *__pyx_kp_s_ngood_0; +static PyObject *__pyx_kp_s_ngood_nbad_nsample; +static PyObject *__pyx_n_s_nonc; +static PyObject *__pyx_kp_s_nonc_0; +static PyObject *__pyx_n_s_noncentral_chisquare; +static PyObject *__pyx_kp_u_noncentral_chisquare_df_nonc_si; +static PyObject *__pyx_n_s_noncentral_f; +static PyObject *__pyx_kp_u_noncentral_f_dfnum_dfden_nonc_s; +static PyObject *__pyx_n_s_normal; +static PyObject *__pyx_kp_u_normal_loc_0_0_scale_1_0_size_N; +static PyObject *__pyx_n_s_np; +static PyObject *__pyx_n_s_nsample; +static PyObject *__pyx_kp_s_nsample_1; +static PyObject *__pyx_n_s_numpy; +static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; +static PyObject *__pyx_n_s_numpy_dual; +static PyObject *__pyx_n_s_off; +static PyObject *__pyx_n_s_operator; +static PyObject *__pyx_n_s_out; +static PyObject *__pyx_n_s_p; +static PyObject *__pyx_kp_s_p_0; +static PyObject *__pyx_kp_s_p_0_0; +static PyObject *__pyx_kp_s_p_0_0_2; +static PyObject *__pyx_kp_s_p_1; +static PyObject *__pyx_kp_s_p_1_0; +static PyObject *__pyx_kp_s_p_1_0_2; +static PyObject *__pyx_kp_s_p_is_nan; +static PyObject *__pyx_kp_s_p_must_be_1_dimensional; +static PyObject *__pyx_n_s_pareto; +static PyObject *__pyx_kp_u_pareto_a_size_None_Draw_samples; +static PyObject *__pyx_n_s_permutation; +static PyObject *__pyx_kp_u_permutation_x_Randomly_permute; +static PyObject *__pyx_n_s_poisson; +static PyObject *__pyx_kp_u_poisson_lam_1_0_size_None_Draw; +static PyObject *__pyx_n_s_poisson_lam_max; +static PyObject *__pyx_n_s_power; +static PyObject *__pyx_kp_u_power_a_size_None_Draws_samples; +static PyObject *__pyx_kp_s_probabilities_are_not_non_negati; +static PyObject *__pyx_kp_s_probabilities_do_not_sum_to_1; +static PyObject *__pyx_n_s_prod; +static PyObject *__pyx_n_s_pvals; +static PyObject *__pyx_n_s_pyx_vtable; +static PyObject *__pyx_n_s_raise; +static PyObject *__pyx_n_s_rand; +static PyObject *__pyx_n_s_rand_2; +static PyObject *__pyx_n_s_rand_bool; +static PyObject *__pyx_kp_u_rand_d0_d1_dn_Random_values_in; +static PyObject *__pyx_n_s_rand_int16; +static PyObject *__pyx_n_s_rand_int32; +static PyObject *__pyx_n_s_rand_int64; +static PyObject *__pyx_n_s_rand_int8; +static PyObject *__pyx_n_s_rand_uint16; +static PyObject *__pyx_n_s_rand_uint32; +static PyObject *__pyx_n_s_rand_uint64; +static PyObject *__pyx_n_s_rand_uint8; +static PyObject *__pyx_n_s_randint; +static PyObject *__pyx_kp_s_randint_helpers_pxi; +static PyObject *__pyx_kp_u_randint_low_high_None_size_None; +static PyObject *__pyx_n_s_randint_type; +static PyObject *__pyx_n_s_randn; +static PyObject *__pyx_kp_u_randn_d0_d1_dn_Return_a_sample; +static PyObject *__pyx_n_s_random; +static PyObject *__pyx_n_s_random_integers; +static PyObject *__pyx_kp_u_random_integers_low_high_None_s; +static PyObject *__pyx_n_s_random_sample; +static PyObject *__pyx_kp_u_random_sample_size_None_Return; +static PyObject *__pyx_n_s_range; +static PyObject *__pyx_n_s_ravel; +static PyObject *__pyx_n_s_rayleigh; +static PyObject *__pyx_kp_u_rayleigh_scale_1_0_size_None_Dr; +static PyObject *__pyx_n_s_reduce; +static PyObject *__pyx_n_s_replace; +static PyObject *__pyx_n_s_reshape; +static PyObject *__pyx_n_s_return_index; +static PyObject *__pyx_n_s_reversed; +static PyObject *__pyx_n_s_right; +static PyObject *__pyx_n_s_rng; +static PyObject *__pyx_n_s_rngstate; +static PyObject *__pyx_n_s_rtol; +static PyObject *__pyx_n_s_safe; +static PyObject *__pyx_n_s_scale; +static PyObject *__pyx_kp_s_scale_0; +static PyObject *__pyx_kp_s_scale_0_0; +static PyObject *__pyx_kp_s_scale_0_0_2; +static PyObject *__pyx_kp_s_scale_0_2; +static PyObject *__pyx_n_s_searchsorted; +static PyObject *__pyx_n_s_seed; +static PyObject *__pyx_n_s_set_state; +static PyObject *__pyx_n_s_shape; +static PyObject *__pyx_kp_s_shape_0; +static PyObject *__pyx_n_s_shape_from_size; +static PyObject *__pyx_n_s_shuffle; +static PyObject *__pyx_kp_u_shuffle_x_Modify_a_sequence_in; +static PyObject *__pyx_n_s_side; +static PyObject *__pyx_n_s_sigma; +static PyObject *__pyx_kp_s_sigma_0; +static PyObject *__pyx_kp_s_sigma_0_0; +static PyObject *__pyx_n_s_signbit; +static PyObject *__pyx_n_s_size; +static PyObject *__pyx_kp_s_size_is_not_compatible_with_inpu; +static PyObject *__pyx_n_s_sort; +static PyObject *__pyx_n_s_sqrt; +static PyObject *__pyx_n_s_standard_cauchy; +static PyObject *__pyx_kp_u_standard_cauchy_size_None_Draw; +static PyObject *__pyx_n_s_standard_exponential; +static PyObject *__pyx_kp_u_standard_exponential_size_None; +static PyObject *__pyx_n_s_standard_gamma; +static PyObject *__pyx_kp_u_standard_gamma_shape_size_None; +static PyObject *__pyx_n_s_standard_normal; +static PyObject *__pyx_kp_u_standard_normal_size_None_Draw; +static PyObject *__pyx_n_s_standard_t; +static PyObject *__pyx_kp_u_standard_t_df_size_None_Draw_sa; +static PyObject *__pyx_n_s_state; +static PyObject *__pyx_kp_s_state_must_be_624_longs; +static PyObject *__pyx_n_s_strides; +static PyObject *__pyx_n_s_subtract; +static PyObject *__pyx_kp_s_sum_pvals_1_1_0; +static PyObject *__pyx_n_s_svd; +static PyObject *__pyx_n_s_take; +static PyObject *__pyx_n_s_test; +static PyObject *__pyx_n_s_threading; +static PyObject *__pyx_n_s_tol; +static PyObject *__pyx_kp_u_tomaxint_size_None_Random_integ; +static PyObject *__pyx_n_s_triangular; +static PyObject *__pyx_kp_u_triangular_left_mode_right_size; +static PyObject *__pyx_n_s_uint; +static PyObject *__pyx_n_s_uint16; +static PyObject *__pyx_n_s_uint32; +static PyObject *__pyx_n_s_uint64; +static PyObject *__pyx_n_s_uint8; +static PyObject *__pyx_n_s_uniform; +static PyObject *__pyx_kp_u_uniform_low_0_0_high_1_0_size_N; +static PyObject *__pyx_n_s_unique; +static PyObject *__pyx_n_s_unsafe; +static PyObject *__pyx_n_s_vonmises; +static PyObject *__pyx_kp_u_vonmises_mu_kappa_size_None_Dra; +static PyObject *__pyx_n_s_wald; +static PyObject *__pyx_kp_u_wald_mean_scale_size_None_Draw; +static PyObject *__pyx_n_s_warn; +static PyObject *__pyx_n_s_warnings; +static PyObject *__pyx_n_s_weibull; +static PyObject *__pyx_kp_u_weibull_a_size_None_Draw_sample; +static PyObject *__pyx_n_s_zeros; +static PyObject *__pyx_n_s_zipf; +static PyObject *__pyx_kp_u_zipf_a_size_None_Draw_samples_f; +static PyObject *__pyx_pf_6mtrand__rand_bool(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_2_rand_int8(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_4_rand_int16(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_6_rand_int32(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_8_rand_int64(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_10_rand_uint8(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_12_rand_uint16(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_14_rand_uint32(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_16_rand_uint64(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate); /* proto */ +static PyObject *__pyx_pf_6mtrand_18_shape_from_size(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_size, PyObject *__pyx_v_d); /* proto */ +static int __pyx_pf_6mtrand_11RandomState___init__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_seed); /* proto */ +static void __pyx_pf_6mtrand_11RandomState_2__dealloc__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_4seed(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_seed); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_6get_state(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_8set_state(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_state); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_10__getstate__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_12__setstate__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_state); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_14__reduce__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_16random_sample(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_18tomaxint(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_20randint(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_dtype); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_22bytes(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, npy_intp __pyx_v_length); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_24choice(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size, PyObject *__pyx_v_replace, PyObject *__pyx_v_p); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_26uniform(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_28rand(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_args); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_30randn(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_args); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_32random_integers(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_34standard_normal(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_36normal(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_loc, PyObject *__pyx_v_scale, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_38beta(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_40exponential(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_scale, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_42standard_exponential(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_44standard_gamma(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_shape, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_46gamma(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_shape, PyObject *__pyx_v_scale, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_48f(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_dfnum, PyObject *__pyx_v_dfden, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_50noncentral_f(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_dfnum, PyObject *__pyx_v_dfden, PyObject *__pyx_v_nonc, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_52chisquare(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_df, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_54noncentral_chisquare(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_df, PyObject *__pyx_v_nonc, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_56standard_cauchy(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_58standard_t(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_df, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_60vonmises(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_mu, PyObject *__pyx_v_kappa, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_62pareto(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_64weibull(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_66power(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_68laplace(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_loc, PyObject *__pyx_v_scale, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_70gumbel(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_loc, PyObject *__pyx_v_scale, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_72logistic(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_loc, PyObject *__pyx_v_scale, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_74lognormal(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_mean, PyObject *__pyx_v_sigma, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_76rayleigh(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_scale, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_78wald(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_mean, PyObject *__pyx_v_scale, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_80triangular(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_left, PyObject *__pyx_v_mode, PyObject *__pyx_v_right, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_82binomial(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_n, PyObject *__pyx_v_p, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_84negative_binomial(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_n, PyObject *__pyx_v_p, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_86poisson(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_lam, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_88zipf(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_90geometric(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_p, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_92hypergeometric(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_ngood, PyObject *__pyx_v_nbad, PyObject *__pyx_v_nsample, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_94logseries(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_p, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_96multivariate_normal(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_mean, PyObject *__pyx_v_cov, PyObject *__pyx_v_size, PyObject *__pyx_v_check_valid, PyObject *__pyx_v_tol); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_98multinomial(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, npy_intp __pyx_v_n, PyObject *__pyx_v_pvals, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_100dirichlet(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_alpha, PyObject *__pyx_v_size); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_102shuffle(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_x); /* proto */ +static PyObject *__pyx_pf_6mtrand_11RandomState_104permutation(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_x); /* proto */ +static PyObject *__pyx_tp_new_6mtrand_RandomState(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_float_0_0; +static PyObject *__pyx_float_1_0; +static PyObject *__pyx_float_1eneg_8; +static PyObject *__pyx_int_0; +static PyObject *__pyx_int_1; +static PyObject *__pyx_int_2; +static PyObject *__pyx_int_3; +static PyObject *__pyx_int_5; +static PyObject *__pyx_int_10; +static PyObject *__pyx_int_128; +static PyObject *__pyx_int_256; +static PyObject *__pyx_int_624; +static PyObject *__pyx_int_32768; +static PyObject *__pyx_int_65536; +static PyObject *__pyx_int_2147483648; +static PyObject *__pyx_int_4294967296; +static PyObject *__pyx_int_9223372036854775808; +static PyObject *__pyx_int_18446744073709551616; +static PyObject *__pyx_int_neg_1; +static PyObject *__pyx_int_neg_128; +static PyObject *__pyx_int_neg_32768; +static PyObject *__pyx_int_neg_2147483648; +static PyObject *__pyx_int_neg_9223372036854775808; +static PyObject *__pyx_k__50; +static PyObject *__pyx_tuple_; +static PyObject *__pyx_tuple__2; +static PyObject *__pyx_tuple__3; +static PyObject *__pyx_tuple__4; +static PyObject *__pyx_tuple__5; +static PyObject *__pyx_tuple__6; +static PyObject *__pyx_tuple__7; +static PyObject *__pyx_tuple__8; +static PyObject *__pyx_tuple__9; +static PyObject *__pyx_slice__46; +static PyObject *__pyx_slice__47; +static PyObject *__pyx_tuple__10; +static PyObject *__pyx_tuple__11; +static PyObject *__pyx_tuple__12; +static PyObject *__pyx_tuple__13; +static PyObject *__pyx_tuple__14; +static PyObject *__pyx_tuple__15; +static PyObject *__pyx_tuple__16; +static PyObject *__pyx_tuple__17; +static PyObject *__pyx_tuple__18; +static PyObject *__pyx_tuple__19; +static PyObject *__pyx_tuple__20; +static PyObject *__pyx_tuple__21; +static PyObject *__pyx_tuple__22; +static PyObject *__pyx_tuple__23; +static PyObject *__pyx_tuple__24; +static PyObject *__pyx_tuple__25; +static PyObject *__pyx_tuple__26; +static PyObject *__pyx_tuple__27; +static PyObject *__pyx_tuple__28; +static PyObject *__pyx_tuple__29; +static PyObject *__pyx_tuple__30; +static PyObject *__pyx_tuple__31; +static PyObject *__pyx_tuple__32; +static PyObject *__pyx_tuple__33; +static PyObject *__pyx_tuple__34; +static PyObject *__pyx_tuple__35; +static PyObject *__pyx_tuple__36; +static PyObject *__pyx_tuple__37; +static PyObject *__pyx_tuple__38; +static PyObject *__pyx_tuple__39; +static PyObject *__pyx_tuple__40; +static PyObject *__pyx_tuple__41; +static PyObject *__pyx_tuple__42; +static PyObject *__pyx_tuple__43; +static PyObject *__pyx_tuple__44; +static PyObject *__pyx_tuple__45; +static PyObject *__pyx_tuple__48; +static PyObject *__pyx_tuple__49; +static PyObject *__pyx_tuple__51; +static PyObject *__pyx_tuple__52; +static PyObject *__pyx_tuple__53; +static PyObject *__pyx_tuple__54; +static PyObject *__pyx_tuple__55; +static PyObject *__pyx_tuple__56; +static PyObject *__pyx_tuple__57; +static PyObject *__pyx_tuple__58; +static PyObject *__pyx_tuple__59; +static PyObject *__pyx_tuple__60; +static PyObject *__pyx_tuple__61; +static PyObject *__pyx_tuple__62; +static PyObject *__pyx_tuple__63; +static PyObject *__pyx_tuple__64; +static PyObject *__pyx_tuple__65; +static PyObject *__pyx_tuple__66; +static PyObject *__pyx_tuple__67; +static PyObject *__pyx_tuple__68; +static PyObject *__pyx_tuple__69; +static PyObject *__pyx_tuple__70; +static PyObject *__pyx_tuple__71; +static PyObject *__pyx_tuple__72; +static PyObject *__pyx_tuple__73; +static PyObject *__pyx_tuple__74; +static PyObject *__pyx_tuple__75; +static PyObject *__pyx_tuple__76; +static PyObject *__pyx_tuple__77; +static PyObject *__pyx_tuple__78; +static PyObject *__pyx_tuple__79; +static PyObject *__pyx_tuple__80; +static PyObject *__pyx_tuple__81; +static PyObject *__pyx_tuple__82; +static PyObject *__pyx_tuple__83; +static PyObject *__pyx_tuple__84; +static PyObject *__pyx_tuple__85; +static PyObject *__pyx_tuple__86; +static PyObject *__pyx_tuple__87; +static PyObject *__pyx_tuple__88; +static PyObject *__pyx_tuple__89; +static PyObject *__pyx_tuple__90; +static PyObject *__pyx_tuple__91; +static PyObject *__pyx_tuple__92; +static PyObject *__pyx_tuple__93; +static PyObject *__pyx_tuple__94; +static PyObject *__pyx_tuple__95; +static PyObject *__pyx_tuple__96; +static PyObject *__pyx_tuple__97; +static PyObject *__pyx_tuple__98; +static PyObject *__pyx_tuple__99; +static PyObject *__pyx_slice__167; +static PyObject *__pyx_slice__171; +static PyObject *__pyx_tuple__100; +static PyObject *__pyx_tuple__101; +static PyObject *__pyx_tuple__102; +static PyObject *__pyx_tuple__103; +static PyObject *__pyx_tuple__104; +static PyObject *__pyx_tuple__105; +static PyObject *__pyx_tuple__106; +static PyObject *__pyx_tuple__107; +static PyObject *__pyx_tuple__108; +static PyObject *__pyx_tuple__109; +static PyObject *__pyx_tuple__110; +static PyObject *__pyx_tuple__111; +static PyObject *__pyx_tuple__112; +static PyObject *__pyx_tuple__113; +static PyObject *__pyx_tuple__114; +static PyObject *__pyx_tuple__115; +static PyObject *__pyx_tuple__116; +static PyObject *__pyx_tuple__117; +static PyObject *__pyx_tuple__118; +static PyObject *__pyx_tuple__119; +static PyObject *__pyx_tuple__120; +static PyObject *__pyx_tuple__121; +static PyObject *__pyx_tuple__122; +static PyObject *__pyx_tuple__123; +static PyObject *__pyx_tuple__124; +static PyObject *__pyx_tuple__125; +static PyObject *__pyx_tuple__126; +static PyObject *__pyx_tuple__127; +static PyObject *__pyx_tuple__128; +static PyObject *__pyx_tuple__129; +static PyObject *__pyx_tuple__130; +static PyObject *__pyx_tuple__131; +static PyObject *__pyx_tuple__132; +static PyObject *__pyx_tuple__133; +static PyObject *__pyx_tuple__134; +static PyObject *__pyx_tuple__135; +static PyObject *__pyx_tuple__136; +static PyObject *__pyx_tuple__137; +static PyObject *__pyx_tuple__138; +static PyObject *__pyx_tuple__139; +static PyObject *__pyx_tuple__140; +static PyObject *__pyx_tuple__141; +static PyObject *__pyx_tuple__142; +static PyObject *__pyx_tuple__143; +static PyObject *__pyx_tuple__144; +static PyObject *__pyx_tuple__145; +static PyObject *__pyx_tuple__146; +static PyObject *__pyx_tuple__147; +static PyObject *__pyx_tuple__148; +static PyObject *__pyx_tuple__149; +static PyObject *__pyx_tuple__150; +static PyObject *__pyx_tuple__151; +static PyObject *__pyx_tuple__152; +static PyObject *__pyx_tuple__153; +static PyObject *__pyx_tuple__154; +static PyObject *__pyx_tuple__155; +static PyObject *__pyx_tuple__156; +static PyObject *__pyx_tuple__157; +static PyObject *__pyx_tuple__158; +static PyObject *__pyx_tuple__159; +static PyObject *__pyx_tuple__160; +static PyObject *__pyx_tuple__161; +static PyObject *__pyx_tuple__162; +static PyObject *__pyx_tuple__163; +static PyObject *__pyx_tuple__164; +static PyObject *__pyx_tuple__165; +static PyObject *__pyx_tuple__166; +static PyObject *__pyx_tuple__168; +static PyObject *__pyx_tuple__169; +static PyObject *__pyx_tuple__170; +static PyObject *__pyx_tuple__172; +static PyObject *__pyx_tuple__173; +static PyObject *__pyx_tuple__174; +static PyObject *__pyx_tuple__175; +static PyObject *__pyx_tuple__176; +static PyObject *__pyx_tuple__177; +static PyObject *__pyx_tuple__178; +static PyObject *__pyx_tuple__179; +static PyObject *__pyx_tuple__180; +static PyObject *__pyx_tuple__182; +static PyObject *__pyx_tuple__184; +static PyObject *__pyx_tuple__186; +static PyObject *__pyx_tuple__188; +static PyObject *__pyx_tuple__190; +static PyObject *__pyx_tuple__192; +static PyObject *__pyx_tuple__194; +static PyObject *__pyx_tuple__196; +static PyObject *__pyx_tuple__198; +static PyObject *__pyx_tuple__200; +static PyObject *__pyx_tuple__201; +static PyObject *__pyx_codeobj__181; +static PyObject *__pyx_codeobj__183; +static PyObject *__pyx_codeobj__185; +static PyObject *__pyx_codeobj__187; +static PyObject *__pyx_codeobj__189; +static PyObject *__pyx_codeobj__191; +static PyObject *__pyx_codeobj__193; +static PyObject *__pyx_codeobj__195; +static PyObject *__pyx_codeobj__197; +static PyObject *__pyx_codeobj__199; +/* Late includes */ + +/* "randint_helpers.pxi":5 + * """ + * + * def _rand_bool(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_bool(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_1_rand_bool(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand__rand_bool[] = "\n _rand_bool(low, high, size, rngstate)\n\n Return random np.bool_ integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.bool_ type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.bool_\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_1_rand_bool = {"_rand_bool", (PyCFunction)__pyx_pw_6mtrand_1_rand_bool, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand__rand_bool}; +static PyObject *__pyx_pw_6mtrand_1_rand_bool(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_bool (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_bool", 1, 4, 4, 1); __PYX_ERR(1, 5, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_bool", 1, 4, 4, 2); __PYX_ERR(1, 5, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_bool", 1, 4, 4, 3); __PYX_ERR(1, 5, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_bool") < 0)) __PYX_ERR(1, 5, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_bool", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 5, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_bool", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand__rand_bool(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand__rand_bool(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_bool __pyx_v_off; + npy_bool __pyx_v_rng; + npy_bool __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_bool *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_bool __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + __Pyx_RefNannySetupContext("_rand_bool", 0); + + /* "randint_helpers.pxi":40 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 40, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":42 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_bool(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_bool)-1)) && PyErr_Occurred())) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_bool)__pyx_t_3); + + /* "randint_helpers.pxi":43 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_3 = __Pyx_PyInt_As_npy_bool(__pyx_v_low); if (unlikely((__pyx_t_3 == ((npy_bool)-1)) && PyErr_Occurred())) __PYX_ERR(1, 43, __pyx_L1_error) + __pyx_v_off = ((npy_bool)((npy_bool)__pyx_t_3)); + + /* "randint_helpers.pxi":45 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_bool(off, rng, 1, &buf, state) + * return np.bool_(buf) + */ + __pyx_t_4 = (__pyx_v_size == Py_None); + __pyx_t_5 = (__pyx_t_4 != 0); + if (__pyx_t_5) { + + /* "randint_helpers.pxi":46 + * + * if size is None: + * rk_random_bool(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.bool_(buf) + * else: + */ + rk_random_bool(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":47 + * if size is None: + * rk_random_bool(off, rng, 1, &buf, state) + * return np.bool_(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.bool_) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 47, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_bool); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 47, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyInt_From_npy_bool(((npy_bool)__pyx_v_buf)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 47, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_8) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 47, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 47, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 47, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 47, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 47, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":45 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_bool(off, rng, 1, &buf, state) + * return np.bool_(buf) + */ + } + + /* "randint_helpers.pxi":49 + * return np.bool_(buf) + * else: + * array = np.empty(size, np.bool_) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_empty); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_bool); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 49, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 49, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_10, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_10, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_9); + __pyx_t_9 = 0; + + /* "randint_helpers.pxi":50 + * else: + * array = np.empty(size, np.bool_) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":51 + * array = np.empty(size, np.bool_) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_bool(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_bool *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":52 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_bool(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":53 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_bool(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + * + */ + rk_random_bool(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":52 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_bool(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":54 + * with nogil: + * rk_random_bool(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + * + * def _rand_int8(low, high, size, rngstate): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":5 + * """ + * + * def _rand_bool(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_bool(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand._rand_bool", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "randint_helpers.pxi":56 + * return array + * + * def _rand_int8(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int8(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_3_rand_int8(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_2_rand_int8[] = "\n _rand_int8(low, high, size, rngstate)\n\n Return random np.int8 integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.int8 type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.int8\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_3_rand_int8 = {"_rand_int8", (PyCFunction)__pyx_pw_6mtrand_3_rand_int8, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_2_rand_int8}; +static PyObject *__pyx_pw_6mtrand_3_rand_int8(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_int8 (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int8", 1, 4, 4, 1); __PYX_ERR(1, 56, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int8", 1, 4, 4, 2); __PYX_ERR(1, 56, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int8", 1, 4, 4, 3); __PYX_ERR(1, 56, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_int8") < 0)) __PYX_ERR(1, 56, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_int8", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 56, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_int8", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_2_rand_int8(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_2_rand_int8(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_uint8 __pyx_v_off; + npy_uint8 __pyx_v_rng; + npy_uint8 __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_uint8 *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_uint8 __pyx_t_3; + npy_int8 __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + __Pyx_RefNannySetupContext("_rand_int8", 0); + + /* "randint_helpers.pxi":91 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 91, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":93 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 93, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_uint8(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_uint8)-1)) && PyErr_Occurred())) __PYX_ERR(1, 93, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_uint8)__pyx_t_3); + + /* "randint_helpers.pxi":94 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_4 = __Pyx_PyInt_As_npy_int8(__pyx_v_low); if (unlikely((__pyx_t_4 == ((npy_int8)-1)) && PyErr_Occurred())) __PYX_ERR(1, 94, __pyx_L1_error) + __pyx_v_off = ((npy_uint8)((npy_int8)__pyx_t_4)); + + /* "randint_helpers.pxi":96 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint8(off, rng, 1, &buf, state) + * return np.int8(buf) + */ + __pyx_t_5 = (__pyx_v_size == Py_None); + __pyx_t_6 = (__pyx_t_5 != 0); + if (__pyx_t_6) { + + /* "randint_helpers.pxi":97 + * + * if size is None: + * rk_random_uint8(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.int8(buf) + * else: + */ + rk_random_uint8(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":98 + * if size is None: + * rk_random_uint8(off, rng, 1, &buf, state) + * return np.int8(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.int8) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_int8); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyInt_From_npy_int8(((npy_int8)__pyx_v_buf)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (!__pyx_t_9) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL; + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_10, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 98, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":96 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint8(off, rng, 1, &buf, state) + * return np.int8(buf) + */ + } + + /* "randint_helpers.pxi":100 + * return np.int8(buf) + * else: + * array = np.empty(size, np.int8) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_empty); if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_int8); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_10); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_10, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_size, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_size, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_8) { + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_11, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_11, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_10 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_10); + __pyx_t_10 = 0; + + /* "randint_helpers.pxi":101 + * else: + * array = np.empty(size, np.int8) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":102 + * array = np.empty(size, np.int8) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_uint8(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_uint8 *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":103 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint8(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":104 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_uint8(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + * + */ + rk_random_uint8(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":103 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint8(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":105 + * with nogil: + * rk_random_uint8(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + * + * def _rand_int16(low, high, size, rngstate): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":56 + * return array + * + * def _rand_int8(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int8(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("mtrand._rand_int8", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "randint_helpers.pxi":107 + * return array + * + * def _rand_int16(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int16(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_5_rand_int16(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_4_rand_int16[] = "\n _rand_int16(low, high, size, rngstate)\n\n Return random np.int16 integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.int16 type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.int16\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_5_rand_int16 = {"_rand_int16", (PyCFunction)__pyx_pw_6mtrand_5_rand_int16, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_4_rand_int16}; +static PyObject *__pyx_pw_6mtrand_5_rand_int16(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_int16 (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int16", 1, 4, 4, 1); __PYX_ERR(1, 107, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int16", 1, 4, 4, 2); __PYX_ERR(1, 107, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int16", 1, 4, 4, 3); __PYX_ERR(1, 107, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_int16") < 0)) __PYX_ERR(1, 107, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_int16", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 107, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_int16", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_4_rand_int16(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_4_rand_int16(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_uint16 __pyx_v_off; + npy_uint16 __pyx_v_rng; + npy_uint16 __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_uint16 *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_uint16 __pyx_t_3; + npy_int16 __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + __Pyx_RefNannySetupContext("_rand_int16", 0); + + /* "randint_helpers.pxi":142 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 142, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":144 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_uint16(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_uint16)-1)) && PyErr_Occurred())) __PYX_ERR(1, 144, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_uint16)__pyx_t_3); + + /* "randint_helpers.pxi":145 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_4 = __Pyx_PyInt_As_npy_int16(__pyx_v_low); if (unlikely((__pyx_t_4 == ((npy_int16)-1)) && PyErr_Occurred())) __PYX_ERR(1, 145, __pyx_L1_error) + __pyx_v_off = ((npy_uint16)((npy_int16)__pyx_t_4)); + + /* "randint_helpers.pxi":147 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint16(off, rng, 1, &buf, state) + * return np.int16(buf) + */ + __pyx_t_5 = (__pyx_v_size == Py_None); + __pyx_t_6 = (__pyx_t_5 != 0); + if (__pyx_t_6) { + + /* "randint_helpers.pxi":148 + * + * if size is None: + * rk_random_uint16(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.int16(buf) + * else: + */ + rk_random_uint16(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":149 + * if size is None: + * rk_random_uint16(off, rng, 1, &buf, state) + * return np.int16(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.int16) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_int16); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyInt_From_npy_int16(((npy_int16)__pyx_v_buf)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (!__pyx_t_9) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL; + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_10, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 149, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":147 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint16(off, rng, 1, &buf, state) + * return np.int16(buf) + */ + } + + /* "randint_helpers.pxi":151 + * return np.int16(buf) + * else: + * array = np.empty(size, np.int16) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_empty); if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_int16); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_10); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_10, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_size, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_size, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_8) { + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_11, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_11, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_10 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_10); + __pyx_t_10 = 0; + + /* "randint_helpers.pxi":152 + * else: + * array = np.empty(size, np.int16) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":153 + * array = np.empty(size, np.int16) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_uint16(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_uint16 *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":154 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint16(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":155 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_uint16(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + * + */ + rk_random_uint16(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":154 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint16(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":156 + * with nogil: + * rk_random_uint16(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + * + * def _rand_int32(low, high, size, rngstate): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":107 + * return array + * + * def _rand_int16(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int16(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("mtrand._rand_int16", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "randint_helpers.pxi":158 + * return array + * + * def _rand_int32(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int32(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_7_rand_int32(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_6_rand_int32[] = "\n _rand_int32(low, high, size, rngstate)\n\n Return random np.int32 integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.int32 type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.int32\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_7_rand_int32 = {"_rand_int32", (PyCFunction)__pyx_pw_6mtrand_7_rand_int32, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_6_rand_int32}; +static PyObject *__pyx_pw_6mtrand_7_rand_int32(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_int32 (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int32", 1, 4, 4, 1); __PYX_ERR(1, 158, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int32", 1, 4, 4, 2); __PYX_ERR(1, 158, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int32", 1, 4, 4, 3); __PYX_ERR(1, 158, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_int32") < 0)) __PYX_ERR(1, 158, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_int32", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 158, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_int32", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_6_rand_int32(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_6_rand_int32(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_uint32 __pyx_v_off; + npy_uint32 __pyx_v_rng; + npy_uint32 __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_uint32 *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_uint32 __pyx_t_3; + npy_int32 __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + __Pyx_RefNannySetupContext("_rand_int32", 0); + + /* "randint_helpers.pxi":193 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 193, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":195 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 195, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_uint32(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_uint32)-1)) && PyErr_Occurred())) __PYX_ERR(1, 195, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_uint32)__pyx_t_3); + + /* "randint_helpers.pxi":196 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_4 = __Pyx_PyInt_As_npy_int32(__pyx_v_low); if (unlikely((__pyx_t_4 == ((npy_int32)-1)) && PyErr_Occurred())) __PYX_ERR(1, 196, __pyx_L1_error) + __pyx_v_off = ((npy_uint32)((npy_int32)__pyx_t_4)); + + /* "randint_helpers.pxi":198 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint32(off, rng, 1, &buf, state) + * return np.int32(buf) + */ + __pyx_t_5 = (__pyx_v_size == Py_None); + __pyx_t_6 = (__pyx_t_5 != 0); + if (__pyx_t_6) { + + /* "randint_helpers.pxi":199 + * + * if size is None: + * rk_random_uint32(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.int32(buf) + * else: + */ + rk_random_uint32(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":200 + * if size is None: + * rk_random_uint32(off, rng, 1, &buf, state) + * return np.int32(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.int32) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_int32); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyInt_From_npy_int32(((npy_int32)__pyx_v_buf)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (!__pyx_t_9) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 200, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 200, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 200, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL; + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_10, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":198 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint32(off, rng, 1, &buf, state) + * return np.int32(buf) + */ + } + + /* "randint_helpers.pxi":202 + * return np.int32(buf) + * else: + * array = np.empty(size, np.int32) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_empty); if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_int32); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_10); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_10, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_size, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 202, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_size, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 202, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_8) { + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_11, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_11, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_10 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_10); + __pyx_t_10 = 0; + + /* "randint_helpers.pxi":203 + * else: + * array = np.empty(size, np.int32) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":204 + * array = np.empty(size, np.int32) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_uint32(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_uint32 *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":205 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint32(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":206 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_uint32(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + * + */ + rk_random_uint32(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":205 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint32(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":207 + * with nogil: + * rk_random_uint32(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + * + * def _rand_int64(low, high, size, rngstate): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":158 + * return array + * + * def _rand_int32(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int32(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("mtrand._rand_int32", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "randint_helpers.pxi":209 + * return array + * + * def _rand_int64(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int64(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_9_rand_int64(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_8_rand_int64[] = "\n _rand_int64(low, high, size, rngstate)\n\n Return random np.int64 integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.int64 type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.int64\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_9_rand_int64 = {"_rand_int64", (PyCFunction)__pyx_pw_6mtrand_9_rand_int64, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_8_rand_int64}; +static PyObject *__pyx_pw_6mtrand_9_rand_int64(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_int64 (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int64", 1, 4, 4, 1); __PYX_ERR(1, 209, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int64", 1, 4, 4, 2); __PYX_ERR(1, 209, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_int64", 1, 4, 4, 3); __PYX_ERR(1, 209, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_int64") < 0)) __PYX_ERR(1, 209, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_int64", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 209, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_int64", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_8_rand_int64(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_8_rand_int64(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_uint64 __pyx_v_off; + npy_uint64 __pyx_v_rng; + npy_uint64 __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_uint64 *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_uint64 __pyx_t_3; + npy_int64 __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + __Pyx_RefNannySetupContext("_rand_int64", 0); + + /* "randint_helpers.pxi":244 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 244, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":246 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 246, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_uint64(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_uint64)-1)) && PyErr_Occurred())) __PYX_ERR(1, 246, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_uint64)__pyx_t_3); + + /* "randint_helpers.pxi":247 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_4 = __Pyx_PyInt_As_npy_int64(__pyx_v_low); if (unlikely((__pyx_t_4 == ((npy_int64)-1)) && PyErr_Occurred())) __PYX_ERR(1, 247, __pyx_L1_error) + __pyx_v_off = ((npy_uint64)((npy_int64)__pyx_t_4)); + + /* "randint_helpers.pxi":249 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint64(off, rng, 1, &buf, state) + * return np.int64(buf) + */ + __pyx_t_5 = (__pyx_v_size == Py_None); + __pyx_t_6 = (__pyx_t_5 != 0); + if (__pyx_t_6) { + + /* "randint_helpers.pxi":250 + * + * if size is None: + * rk_random_uint64(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.int64(buf) + * else: + */ + rk_random_uint64(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":251 + * if size is None: + * rk_random_uint64(off, rng, 1, &buf, state) + * return np.int64(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.int64) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 251, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_int64); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 251, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyInt_From_npy_int64(((npy_int64)__pyx_v_buf)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 251, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (!__pyx_t_9) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 251, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 251, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 251, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 251, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL; + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_10, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 251, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":249 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint64(off, rng, 1, &buf, state) + * return np.int64(buf) + */ + } + + /* "randint_helpers.pxi":253 + * return np.int64(buf) + * else: + * array = np.empty(size, np.int64) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_empty); if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_int64); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_10); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_10, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_size, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 253, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_size, __pyx_t_7}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 253, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_8) { + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_11, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_11, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 253, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_10 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_10); + __pyx_t_10 = 0; + + /* "randint_helpers.pxi":254 + * else: + * array = np.empty(size, np.int64) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":255 + * array = np.empty(size, np.int64) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_uint64(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_uint64 *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":256 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint64(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":257 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_uint64(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + * + */ + rk_random_uint64(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":256 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint64(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":258 + * with nogil: + * rk_random_uint64(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + * + * def _rand_uint8(low, high, size, rngstate): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":209 + * return array + * + * def _rand_int64(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int64(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("mtrand._rand_int64", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "randint_helpers.pxi":260 + * return array + * + * def _rand_uint8(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint8(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11_rand_uint8(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_10_rand_uint8[] = "\n _rand_uint8(low, high, size, rngstate)\n\n Return random np.uint8 integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.uint8 type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.uint8\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_11_rand_uint8 = {"_rand_uint8", (PyCFunction)__pyx_pw_6mtrand_11_rand_uint8, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_10_rand_uint8}; +static PyObject *__pyx_pw_6mtrand_11_rand_uint8(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_uint8 (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint8", 1, 4, 4, 1); __PYX_ERR(1, 260, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint8", 1, 4, 4, 2); __PYX_ERR(1, 260, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint8", 1, 4, 4, 3); __PYX_ERR(1, 260, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_uint8") < 0)) __PYX_ERR(1, 260, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_uint8", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 260, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_uint8", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_10_rand_uint8(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_10_rand_uint8(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_uint8 __pyx_v_off; + npy_uint8 __pyx_v_rng; + npy_uint8 __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_uint8 *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_uint8 __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + __Pyx_RefNannySetupContext("_rand_uint8", 0); + + /* "randint_helpers.pxi":295 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 295, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":297 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 297, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_uint8(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_uint8)-1)) && PyErr_Occurred())) __PYX_ERR(1, 297, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_uint8)__pyx_t_3); + + /* "randint_helpers.pxi":298 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_3 = __Pyx_PyInt_As_npy_uint8(__pyx_v_low); if (unlikely((__pyx_t_3 == ((npy_uint8)-1)) && PyErr_Occurred())) __PYX_ERR(1, 298, __pyx_L1_error) + __pyx_v_off = ((npy_uint8)((npy_uint8)__pyx_t_3)); + + /* "randint_helpers.pxi":300 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint8(off, rng, 1, &buf, state) + * return np.uint8(buf) + */ + __pyx_t_4 = (__pyx_v_size == Py_None); + __pyx_t_5 = (__pyx_t_4 != 0); + if (__pyx_t_5) { + + /* "randint_helpers.pxi":301 + * + * if size is None: + * rk_random_uint8(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.uint8(buf) + * else: + */ + rk_random_uint8(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":302 + * if size is None: + * rk_random_uint8(off, rng, 1, &buf, state) + * return np.uint8(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.uint8) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 302, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_uint8); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 302, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyInt_From_npy_uint8(((npy_uint8)__pyx_v_buf)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 302, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_8) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 302, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 302, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 302, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 302, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 302, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":300 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint8(off, rng, 1, &buf, state) + * return np.uint8(buf) + */ + } + + /* "randint_helpers.pxi":304 + * return np.uint8(buf) + * else: + * array = np.empty(size, np.uint8) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_empty); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_uint8); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 304, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 304, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_10, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_10, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_9); + __pyx_t_9 = 0; + + /* "randint_helpers.pxi":305 + * else: + * array = np.empty(size, np.uint8) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":306 + * array = np.empty(size, np.uint8) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_uint8(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_uint8 *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":307 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint8(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":308 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_uint8(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + * + */ + rk_random_uint8(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":307 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint8(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":309 + * with nogil: + * rk_random_uint8(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + * + * def _rand_uint16(low, high, size, rngstate): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":260 + * return array + * + * def _rand_uint8(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint8(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand._rand_uint8", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "randint_helpers.pxi":311 + * return array + * + * def _rand_uint16(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint16(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_13_rand_uint16(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_12_rand_uint16[] = "\n _rand_uint16(low, high, size, rngstate)\n\n Return random np.uint16 integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.uint16 type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.uint16\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_13_rand_uint16 = {"_rand_uint16", (PyCFunction)__pyx_pw_6mtrand_13_rand_uint16, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_12_rand_uint16}; +static PyObject *__pyx_pw_6mtrand_13_rand_uint16(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_uint16 (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint16", 1, 4, 4, 1); __PYX_ERR(1, 311, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint16", 1, 4, 4, 2); __PYX_ERR(1, 311, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint16", 1, 4, 4, 3); __PYX_ERR(1, 311, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_uint16") < 0)) __PYX_ERR(1, 311, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_uint16", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 311, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_uint16", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_12_rand_uint16(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_12_rand_uint16(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_uint16 __pyx_v_off; + npy_uint16 __pyx_v_rng; + npy_uint16 __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_uint16 *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_uint16 __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + __Pyx_RefNannySetupContext("_rand_uint16", 0); + + /* "randint_helpers.pxi":346 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 346, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":348 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 348, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_uint16(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_uint16)-1)) && PyErr_Occurred())) __PYX_ERR(1, 348, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_uint16)__pyx_t_3); + + /* "randint_helpers.pxi":349 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_3 = __Pyx_PyInt_As_npy_uint16(__pyx_v_low); if (unlikely((__pyx_t_3 == ((npy_uint16)-1)) && PyErr_Occurred())) __PYX_ERR(1, 349, __pyx_L1_error) + __pyx_v_off = ((npy_uint16)((npy_uint16)__pyx_t_3)); + + /* "randint_helpers.pxi":351 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint16(off, rng, 1, &buf, state) + * return np.uint16(buf) + */ + __pyx_t_4 = (__pyx_v_size == Py_None); + __pyx_t_5 = (__pyx_t_4 != 0); + if (__pyx_t_5) { + + /* "randint_helpers.pxi":352 + * + * if size is None: + * rk_random_uint16(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.uint16(buf) + * else: + */ + rk_random_uint16(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":353 + * if size is None: + * rk_random_uint16(off, rng, 1, &buf, state) + * return np.uint16(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.uint16) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_uint16); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyInt_From_npy_uint16(((npy_uint16)__pyx_v_buf)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_8) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 353, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 353, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 353, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 353, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":351 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint16(off, rng, 1, &buf, state) + * return np.uint16(buf) + */ + } + + /* "randint_helpers.pxi":355 + * return np.uint16(buf) + * else: + * array = np.empty(size, np.uint16) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 355, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_empty); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 355, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 355, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_uint16); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 355, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 355, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 355, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 355, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_10, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_10, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 355, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_9); + __pyx_t_9 = 0; + + /* "randint_helpers.pxi":356 + * else: + * array = np.empty(size, np.uint16) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":357 + * array = np.empty(size, np.uint16) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_uint16(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_uint16 *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":358 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint16(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":359 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_uint16(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + * + */ + rk_random_uint16(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":358 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint16(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":360 + * with nogil: + * rk_random_uint16(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + * + * def _rand_uint32(low, high, size, rngstate): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":311 + * return array + * + * def _rand_uint16(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint16(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand._rand_uint16", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "randint_helpers.pxi":362 + * return array + * + * def _rand_uint32(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint32(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_15_rand_uint32(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_14_rand_uint32[] = "\n _rand_uint32(low, high, size, rngstate)\n\n Return random np.uint32 integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.uint32 type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.uint32\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_15_rand_uint32 = {"_rand_uint32", (PyCFunction)__pyx_pw_6mtrand_15_rand_uint32, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_14_rand_uint32}; +static PyObject *__pyx_pw_6mtrand_15_rand_uint32(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_uint32 (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint32", 1, 4, 4, 1); __PYX_ERR(1, 362, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint32", 1, 4, 4, 2); __PYX_ERR(1, 362, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint32", 1, 4, 4, 3); __PYX_ERR(1, 362, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_uint32") < 0)) __PYX_ERR(1, 362, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_uint32", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 362, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_uint32", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_14_rand_uint32(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_14_rand_uint32(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_uint32 __pyx_v_off; + npy_uint32 __pyx_v_rng; + npy_uint32 __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_uint32 *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_uint32 __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + __Pyx_RefNannySetupContext("_rand_uint32", 0); + + /* "randint_helpers.pxi":397 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 397, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":399 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 399, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_uint32(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_uint32)-1)) && PyErr_Occurred())) __PYX_ERR(1, 399, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_uint32)__pyx_t_3); + + /* "randint_helpers.pxi":400 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_3 = __Pyx_PyInt_As_npy_uint32(__pyx_v_low); if (unlikely((__pyx_t_3 == ((npy_uint32)-1)) && PyErr_Occurred())) __PYX_ERR(1, 400, __pyx_L1_error) + __pyx_v_off = ((npy_uint32)((npy_uint32)__pyx_t_3)); + + /* "randint_helpers.pxi":402 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint32(off, rng, 1, &buf, state) + * return np.uint32(buf) + */ + __pyx_t_4 = (__pyx_v_size == Py_None); + __pyx_t_5 = (__pyx_t_4 != 0); + if (__pyx_t_5) { + + /* "randint_helpers.pxi":403 + * + * if size is None: + * rk_random_uint32(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.uint32(buf) + * else: + */ + rk_random_uint32(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":404 + * if size is None: + * rk_random_uint32(off, rng, 1, &buf, state) + * return np.uint32(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.uint32) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 404, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_uint32); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 404, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyInt_From_npy_uint32(((npy_uint32)__pyx_v_buf)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 404, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_8) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 404, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 404, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 404, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 404, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 404, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":402 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint32(off, rng, 1, &buf, state) + * return np.uint32(buf) + */ + } + + /* "randint_helpers.pxi":406 + * return np.uint32(buf) + * else: + * array = np.empty(size, np.uint32) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 406, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_empty); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 406, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 406, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_uint32); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 406, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 406, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 406, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 406, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_10, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_10, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 406, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_9); + __pyx_t_9 = 0; + + /* "randint_helpers.pxi":407 + * else: + * array = np.empty(size, np.uint32) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":408 + * array = np.empty(size, np.uint32) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_uint32(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_uint32 *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":409 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint32(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":410 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_uint32(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + * + */ + rk_random_uint32(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":409 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint32(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":411 + * with nogil: + * rk_random_uint32(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + * + * def _rand_uint64(low, high, size, rngstate): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":362 + * return array + * + * def _rand_uint32(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint32(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand._rand_uint32", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "randint_helpers.pxi":413 + * return array + * + * def _rand_uint64(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint64(low, high, size, rngstate) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_17_rand_uint64(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_16_rand_uint64[] = "\n _rand_uint64(low, high, size, rngstate)\n\n Return random np.uint64 integers between ``low`` and ``high``, inclusive.\n\n Return random integers from the \"discrete uniform\" distribution in the\n closed interval [``low``, ``high``). On entry the arguments are presumed\n to have been validated for size and order for the np.uint64 type.\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution.\n high : int\n Highest (signed) integer to be drawn from the distribution.\n size : int or tuple of ints\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n rngstate : encapsulated pointer to rk_state\n The specific type depends on the python version. In Python 2 it is\n a PyCObject, in Python 3 a PyCapsule object.\n\n Returns\n -------\n out : python integer or ndarray of np.uint64\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n "; +static PyMethodDef __pyx_mdef_6mtrand_17_rand_uint64 = {"_rand_uint64", (PyCFunction)__pyx_pw_6mtrand_17_rand_uint64, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_16_rand_uint64}; +static PyObject *__pyx_pw_6mtrand_17_rand_uint64(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_rngstate = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_rand_uint64 (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_rngstate,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint64", 1, 4, 4, 1); __PYX_ERR(1, 413, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint64", 1, 4, 4, 2); __PYX_ERR(1, 413, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_rngstate)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_rand_uint64", 1, 4, 4, 3); __PYX_ERR(1, 413, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_rand_uint64") < 0)) __PYX_ERR(1, 413, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_rngstate = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_rand_uint64", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 413, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._rand_uint64", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_16_rand_uint64(__pyx_self, __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_rngstate); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_16_rand_uint64(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_rngstate) { + npy_uint64 __pyx_v_off; + npy_uint64 __pyx_v_rng; + npy_uint64 __pyx_v_buf; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_cnt; + rk_state *__pyx_v_state; + npy_uint64 *__pyx_v_array_data; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + void *__pyx_t_1; + PyObject *__pyx_t_2 = NULL; + npy_uint64 __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + __Pyx_RefNannySetupContext("_rand_uint64", 0); + + /* "randint_helpers.pxi":448 + * cdef ndarray array "arrayObject" + * cdef npy_intp cnt + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) # <<<<<<<<<<<<<< + * + * rng = (high - low) + */ + __pyx_t_1 = PyCapsule_GetPointer(__pyx_v_rngstate, NULL); if (unlikely(__pyx_t_1 == ((void *)NULL) && PyErr_Occurred())) __PYX_ERR(1, 448, __pyx_L1_error) + __pyx_v_state = ((rk_state *)__pyx_t_1); + + /* "randint_helpers.pxi":450 + * cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + * + * rng = (high - low) # <<<<<<<<<<<<<< + * off = (low) + * + */ + __pyx_t_2 = PyNumber_Subtract(__pyx_v_high, __pyx_v_low); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 450, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyInt_As_npy_uint64(__pyx_t_2); if (unlikely((__pyx_t_3 == ((npy_uint64)-1)) && PyErr_Occurred())) __PYX_ERR(1, 450, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_rng = ((npy_uint64)__pyx_t_3); + + /* "randint_helpers.pxi":451 + * + * rng = (high - low) + * off = (low) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_3 = __Pyx_PyInt_As_npy_uint64(__pyx_v_low); if (unlikely((__pyx_t_3 == ((npy_uint64)-1)) && PyErr_Occurred())) __PYX_ERR(1, 451, __pyx_L1_error) + __pyx_v_off = ((npy_uint64)((npy_uint64)__pyx_t_3)); + + /* "randint_helpers.pxi":453 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint64(off, rng, 1, &buf, state) + * return np.uint64(buf) + */ + __pyx_t_4 = (__pyx_v_size == Py_None); + __pyx_t_5 = (__pyx_t_4 != 0); + if (__pyx_t_5) { + + /* "randint_helpers.pxi":454 + * + * if size is None: + * rk_random_uint64(off, rng, 1, &buf, state) # <<<<<<<<<<<<<< + * return np.uint64(buf) + * else: + */ + rk_random_uint64(__pyx_v_off, __pyx_v_rng, 1, (&__pyx_v_buf), __pyx_v_state); + + /* "randint_helpers.pxi":455 + * if size is None: + * rk_random_uint64(off, rng, 1, &buf, state) + * return np.uint64(buf) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.uint64) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 455, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_uint64); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 455, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyInt_From_npy_uint64(((npy_uint64)__pyx_v_buf)); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 455, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_8) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 455, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 455, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 455, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 455, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 455, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "randint_helpers.pxi":453 + * off = (low) + * + * if size is None: # <<<<<<<<<<<<<< + * rk_random_uint64(off, rng, 1, &buf, state) + * return np.uint64(buf) + */ + } + + /* "randint_helpers.pxi":457 + * return np.uint64(buf) + * else: + * array = np.empty(size, np.uint64) # <<<<<<<<<<<<<< + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 457, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_empty); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 457, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 457, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_uint64); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 457, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 457, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_size, __pyx_t_6}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 457, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 457, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_10, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_10, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 457, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_9); + __pyx_t_9 = 0; + + /* "randint_helpers.pxi":458 + * else: + * array = np.empty(size, np.uint64) + * cnt = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with nogil: + */ + __pyx_v_cnt = PyArray_SIZE(arrayObject); + + /* "randint_helpers.pxi":459 + * array = np.empty(size, np.uint64) + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with nogil: + * rk_random_uint64(off, rng, cnt, array_data, state) + */ + __pyx_v_array_data = ((npy_uint64 *)PyArray_DATA(arrayObject)); + + /* "randint_helpers.pxi":460 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint64(off, rng, cnt, array_data, state) + * return array + */ + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "randint_helpers.pxi":461 + * array_data = PyArray_DATA(array) + * with nogil: + * rk_random_uint64(off, rng, cnt, array_data, state) # <<<<<<<<<<<<<< + * return array + */ + rk_random_uint64(__pyx_v_off, __pyx_v_rng, __pyx_v_cnt, __pyx_v_array_data, __pyx_v_state); + } + + /* "randint_helpers.pxi":460 + * cnt = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with nogil: # <<<<<<<<<<<<<< + * rk_random_uint64(off, rng, cnt, array_data, state) + * return array + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L6; + } + __pyx_L6:; + } + } + + /* "randint_helpers.pxi":462 + * with nogil: + * rk_random_uint64(off, rng, cnt, array_data, state) + * return array # <<<<<<<<<<<<<< + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "randint_helpers.pxi":413 + * return array + * + * def _rand_uint64(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint64(low, high, size, rngstate) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand._rand_uint64", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "numpy.pxd":158 + * + * # copied from cython version with addition of PyErr_Print. + * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< + * try: + * _import_array() + */ + +static CYTHON_INLINE int __pyx_f_6mtrand_import_array(void) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("import_array", 0); + + /* "numpy.pxd":159 + * # copied from cython version with addition of PyErr_Print. + * cdef inline int import_array() except -1: + * try: # <<<<<<<<<<<<<< + * _import_array() + * except Exception: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "numpy.pxd":160 + * cdef inline int import_array() except -1: + * try: + * _import_array() # <<<<<<<<<<<<<< + * except Exception: + * PyErr_Print() + */ + __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(2, 160, __pyx_L3_error) + + /* "numpy.pxd":159 + * # copied from cython version with addition of PyErr_Print. + * cdef inline int import_array() except -1: + * try: # <<<<<<<<<<<<<< + * _import_array() + * except Exception: + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L8_try_end; + __pyx_L3_error:; + + /* "numpy.pxd":161 + * try: + * _import_array() + * except Exception: # <<<<<<<<<<<<<< + * PyErr_Print() + * raise ImportError("numpy.core.multiarray failed to import") + */ + __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); + if (__pyx_t_4) { + __Pyx_AddTraceback("mtrand.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(2, 161, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GOTREF(__pyx_t_7); + + /* "numpy.pxd":162 + * _import_array() + * except Exception: + * PyErr_Print() # <<<<<<<<<<<<<< + * raise ImportError("numpy.core.multiarray failed to import") + */ + PyErr_Print(); + + /* "numpy.pxd":163 + * except Exception: + * PyErr_Print() + * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< + */ + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(2, 163, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_Raise(__pyx_t_8, 0, 0, 0); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __PYX_ERR(2, 163, __pyx_L5_except_error) + } + goto __pyx_L5_except_error; + __pyx_L5_except_error:; + + /* "numpy.pxd":159 + * # copied from cython version with addition of PyErr_Print. + * cdef inline int import_array() except -1: + * try: # <<<<<<<<<<<<<< + * _import_array() + * except Exception: + */ + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L1_error; + __pyx_L8_try_end:; + } + + /* "numpy.pxd":158 + * + * # copied from cython version with addition of PyErr_Print. + * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< + * try: + * _import_array() + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":155 + * from dummy_threading import Lock + * + * cdef object cont0_array(rk_state *state, rk_cont0 func, object size, # <<<<<<<<<<<<<< + * object lock): + * cdef double *array_data + */ + +static PyObject *__pyx_f_6mtrand_cont0_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_cont0 __pyx_v_func, PyObject *__pyx_v_size, PyObject *__pyx_v_lock) { + double *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + double __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + PyObject *__pyx_t_12 = NULL; + npy_intp __pyx_t_13; + __Pyx_RefNannySetupContext("cont0_array", 0); + + /* "mtrand.pyx":162 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":163 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 163, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 163, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 163, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 163, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":164 + * if size is None: + * with lock, nogil: + * rv = func(state) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state); + } + + /* "mtrand.pyx":163 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__2, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 163, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":165 + * with lock, nogil: + * rv = func(state) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.float64) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":162 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state) + */ + } + + /* "mtrand.pyx":167 + * return rv + * else: + * array = np.empty(size, np.float64) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_float64); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + { + __pyx_t_12 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_12, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_12, 0+__pyx_t_11, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_12, 1+__pyx_t_11, __pyx_t_10); + __pyx_t_10 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_12, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":168 + * else: + * array = np.empty(size, np.float64) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":169 + * array = np.empty(size, np.float64) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((double *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":170 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 170, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 170, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_12 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_12)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_12); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_12) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_12); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 170, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 170, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":171 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state) + * return array + */ + __pyx_t_13 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_13; __pyx_v_i++) { + + /* "mtrand.pyx":172 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state); + } + } + + /* "mtrand.pyx":170 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__3, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 170, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":173 + * for i from 0 <= i < length: + * array_data[i] = func(state) + * return array # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":155 + * from dummy_threading import Lock + * + * cdef object cont0_array(rk_state *state, rk_cont0 func, object size, # <<<<<<<<<<<<<< + * object lock): + * cdef double *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_AddTraceback("mtrand.cont0_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":176 + * + * + * cdef object cont1_array_sc(rk_state *state, rk_cont1 func, object size, double a, # <<<<<<<<<<<<<< + * object lock): + * cdef double *array_data + */ + +static PyObject *__pyx_f_6mtrand_cont1_array_sc(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_cont1 __pyx_v_func, PyObject *__pyx_v_size, double __pyx_v_a, PyObject *__pyx_v_lock) { + double *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + double __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + PyObject *__pyx_t_12 = NULL; + npy_intp __pyx_t_13; + __Pyx_RefNannySetupContext("cont1_array_sc", 0); + + /* "mtrand.pyx":183 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, a) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":184 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 184, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 184, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 184, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 184, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":185 + * if size is None: + * with lock, nogil: + * rv = func(state, a) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state, __pyx_v_a); + } + + /* "mtrand.pyx":184 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__4, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 184, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":186 + * with lock, nogil: + * rv = func(state, a) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.float64) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 186, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":183 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, a) + */ + } + + /* "mtrand.pyx":188 + * return rv + * else: + * array = np.empty(size, np.float64) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_float64); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + { + __pyx_t_12 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_12, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_12, 0+__pyx_t_11, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_12, 1+__pyx_t_11, __pyx_t_10); + __pyx_t_10 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_12, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":189 + * else: + * array = np.empty(size, np.float64) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":190 + * array = np.empty(size, np.float64) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((double *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":191 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 191, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 191, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_12 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_12)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_12); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_12) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_12); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 191, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 191, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":192 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, a) + * return array + */ + __pyx_t_13 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_13; __pyx_v_i++) { + + /* "mtrand.pyx":193 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, a) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, __pyx_v_a); + } + } + + /* "mtrand.pyx":191 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__5, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 191, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":194 + * for i from 0 <= i < length: + * array_data[i] = func(state, a) + * return array # <<<<<<<<<<<<<< + * + * cdef object cont1_array(rk_state *state, rk_cont1 func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":176 + * + * + * cdef object cont1_array_sc(rk_state *state, rk_cont1 func, object size, double a, # <<<<<<<<<<<<<< + * object lock): + * cdef double *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_AddTraceback("mtrand.cont1_array_sc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":196 + * return array + * + * cdef object cont1_array(rk_state *state, rk_cont1 func, object size, # <<<<<<<<<<<<<< + * ndarray oa, object lock): + * cdef double *array_data + */ + +static PyObject *__pyx_f_6mtrand_cont1_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_cont1 __pyx_v_func, PyObject *__pyx_v_size, PyArrayObject *__pyx_v_oa, PyObject *__pyx_v_lock) { + double *__pyx_v_array_data; + double *__pyx_v_oa_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + PyArrayIterObject *__pyx_v_itera = 0; + PyArrayMultiIterObject *__pyx_v_multi = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + npy_intp __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + int __pyx_t_12; + PyObject *__pyx_t_13 = NULL; + __Pyx_RefNannySetupContext("cont1_array", 0); + + /* "mtrand.pyx":206 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * array = PyArray_SimpleNew(PyArray_NDIM(oa), + * PyArray_DIMS(oa) , NPY_DOUBLE) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":207 + * + * if size is None: + * array = PyArray_SimpleNew(PyArray_NDIM(oa), # <<<<<<<<<<<<<< + * PyArray_DIMS(oa) , NPY_DOUBLE) + * length = PyArray_SIZE(array) + */ + __pyx_t_3 = PyArray_SimpleNew(PyArray_NDIM(__pyx_v_oa), PyArray_DIMS(__pyx_v_oa), NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 207, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "mtrand.pyx":209 + * array = PyArray_SimpleNew(PyArray_NDIM(oa), + * PyArray_DIMS(oa) , NPY_DOUBLE) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":210 + * PyArray_DIMS(oa) , NPY_DOUBLE) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * itera = PyArray_IterNew(oa) + * with lock, nogil: + */ + __pyx_v_array_data = ((double *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":211 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_t_4 = PyArray_IterNew(((PyObject *)__pyx_v_oa)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 211, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_itera = ((PyArrayIterObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":212 + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + */ + /*with:*/ { + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 212, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 212, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 212, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":213 + * itera = PyArray_IterNew(oa) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + * PyArray_ITER_NEXT(itera) + */ + __pyx_t_10 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_10; __pyx_v_i++) { + + /* "mtrand.pyx":214 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) # <<<<<<<<<<<<<< + * PyArray_ITER_NEXT(itera) + * else: + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (((double *)PyArray_ITER_DATA(__pyx_v_itera))[0])); + + /* "mtrand.pyx":215 + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + * PyArray_ITER_NEXT(itera) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.float64) + */ + PyArray_ITER_NEXT(__pyx_v_itera); + } + } + + /* "mtrand.pyx":212 + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_5) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__6, NULL); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L19; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L1_error; + __pyx_L19:; + } + + /* "mtrand.pyx":206 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * array = PyArray_SimpleNew(PyArray_NDIM(oa), + * PyArray_DIMS(oa) , NPY_DOUBLE) + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":217 + * PyArray_ITER_NEXT(itera) + * else: + * array = np.empty(size, np.float64) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * multi = PyArray_MultiIterNew(2, array, + */ + /*else*/ { + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_12 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_12 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_v_size, __pyx_t_11}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_12, 2+__pyx_t_12); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_v_size, __pyx_t_11}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_12, 2+__pyx_t_12); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else + #endif + { + __pyx_t_13 = PyTuple_New(2+__pyx_t_12); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_13, 0+__pyx_t_12, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_11); + PyTuple_SET_ITEM(__pyx_t_13, 1+__pyx_t_12, __pyx_t_11); + __pyx_t_11 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_13, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":218 + * else: + * array = np.empty(size, np.float64) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * multi = PyArray_MultiIterNew(2, array, + * oa) + */ + __pyx_v_array_data = ((double *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":219 + * array = np.empty(size, np.float64) + * array_data = PyArray_DATA(array) + * multi = PyArray_MultiIterNew(2, array, # <<<<<<<<<<<<<< + * oa) + * if (multi.size != PyArray_SIZE(array)): + */ + __pyx_t_6 = PyArray_MultiIterNew(2, ((void *)arrayObject), ((void *)__pyx_v_oa)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 219, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_3 = __pyx_t_6; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":221 + * multi = PyArray_MultiIterNew(2, array, + * oa) + * if (multi.size != PyArray_SIZE(array)): # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: + */ + __pyx_t_2 = ((__pyx_v_multi->size != PyArray_SIZE(arrayObject)) != 0); + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":222 + * oa) + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < multi.size: + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 222, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 222, __pyx_L1_error) + + /* "mtrand.pyx":221 + * multi = PyArray_MultiIterNew(2, array, + * oa) + * if (multi.size != PyArray_SIZE(array)): # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: + */ + } + + /* "mtrand.pyx":223 + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) + */ + /*with:*/ { + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 223, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 223, __pyx_L21_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_13 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_13 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_13)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_13); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (__pyx_t_13) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_13); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 223, __pyx_L21_error) + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 223, __pyx_L21_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":224 + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: + * for i from 0 <= i < multi.size: # <<<<<<<<<<<<<< + * oa_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0]) + */ + __pyx_t_10 = __pyx_v_multi->size; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_10; __pyx_v_i++) { + + /* "mtrand.pyx":225 + * with lock, nogil: + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) # <<<<<<<<<<<<<< + * array_data[i] = func(state, oa_data[0]) + * PyArray_MultiIter_NEXTi(multi, 1) + */ + __pyx_v_oa_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 1)); + + /* "mtrand.pyx":226 + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0]) # <<<<<<<<<<<<<< + * PyArray_MultiIter_NEXTi(multi, 1) + * return array + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (__pyx_v_oa_data[0])); + + /* "mtrand.pyx":227 + * oa_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0]) + * PyArray_MultiIter_NEXTi(multi, 1) # <<<<<<<<<<<<<< + * return array + * + */ + PyArray_MultiIter_NEXTi(__pyx_v_multi, 1); + } + } + + /* "mtrand.pyx":223 + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L33; + } + __pyx_L33:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_5) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__8, NULL); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 223, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L24; + } + __pyx_L24:; + } + goto __pyx_L36; + __pyx_L21_error:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L1_error; + __pyx_L36:; + } + } + __pyx_L3:; + + /* "mtrand.pyx":228 + * array_data[i] = func(state, oa_data[0]) + * PyArray_MultiIter_NEXTi(multi, 1) + * return array # <<<<<<<<<<<<<< + * + * cdef object cont2_array_sc(rk_state *state, rk_cont2 func, object size, double a, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + + /* "mtrand.pyx":196 + * return array + * + * cdef object cont1_array(rk_state *state, rk_cont1 func, object size, # <<<<<<<<<<<<<< + * ndarray oa, object lock): + * cdef double *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_XDECREF(__pyx_t_13); + __Pyx_AddTraceback("mtrand.cont1_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XDECREF((PyObject *)__pyx_v_itera); + __Pyx_XDECREF((PyObject *)__pyx_v_multi); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":230 + * return array + * + * cdef object cont2_array_sc(rk_state *state, rk_cont2 func, object size, double a, # <<<<<<<<<<<<<< + * double b, object lock): + * cdef double *array_data + */ + +static PyObject *__pyx_f_6mtrand_cont2_array_sc(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_cont2 __pyx_v_func, PyObject *__pyx_v_size, double __pyx_v_a, double __pyx_v_b, PyObject *__pyx_v_lock) { + double *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + double __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + PyObject *__pyx_t_12 = NULL; + npy_intp __pyx_t_13; + __Pyx_RefNannySetupContext("cont2_array_sc", 0); + + /* "mtrand.pyx":237 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, a, b) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":238 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a, b) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 238, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 238, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 238, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 238, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":239 + * if size is None: + * with lock, nogil: + * rv = func(state, a, b) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state, __pyx_v_a, __pyx_v_b); + } + + /* "mtrand.pyx":238 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a, b) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__9, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 238, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":240 + * with lock, nogil: + * rv = func(state, a, b) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.float64) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 240, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":237 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, a, b) + */ + } + + /* "mtrand.pyx":242 + * return rv + * else: + * array = np.empty(size, np.float64) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 242, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 242, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 242, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_float64); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 242, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + { + __pyx_t_12 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 242, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_12, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_12, 0+__pyx_t_11, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_12, 1+__pyx_t_11, __pyx_t_10); + __pyx_t_10 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_12, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":243 + * else: + * array = np.empty(size, np.float64) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":244 + * array = np.empty(size, np.float64) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((double *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":245 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 245, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 245, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_12 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_12)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_12); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_12) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_12); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 245, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 245, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":246 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, a, b) + * return array + */ + __pyx_t_13 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_13; __pyx_v_i++) { + + /* "mtrand.pyx":247 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, __pyx_v_a, __pyx_v_b); + } + } + + /* "mtrand.pyx":245 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__10, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 245, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":248 + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b) + * return array # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":230 + * return array + * + * cdef object cont2_array_sc(rk_state *state, rk_cont2 func, object size, double a, # <<<<<<<<<<<<<< + * double b, object lock): + * cdef double *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_AddTraceback("mtrand.cont2_array_sc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":251 + * + * + * cdef object cont2_array(rk_state *state, rk_cont2 func, object size, # <<<<<<<<<<<<<< + * ndarray oa, ndarray ob, object lock): + * cdef double *array_data + */ + +static PyObject *__pyx_f_6mtrand_cont2_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_cont2 __pyx_v_func, PyObject *__pyx_v_size, PyArrayObject *__pyx_v_oa, PyArrayObject *__pyx_v_ob, PyObject *__pyx_v_lock) { + double *__pyx_v_array_data; + double *__pyx_v_oa_data; + double *__pyx_v_ob_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_i; + PyArrayMultiIterObject *__pyx_v_multi = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + npy_intp __pyx_t_13; + npy_intp __pyx_t_14; + npy_intp __pyx_t_15; + __Pyx_RefNannySetupContext("cont2_array", 0); + + /* "mtrand.pyx":260 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(oa, ob) + * array = np.empty(multi.shape, dtype=np.float64) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":261 + * + * if size is None: + * multi = np.broadcast(oa, ob) # <<<<<<<<<<<<<< + * array = np.empty(multi.shape, dtype=np.float64) + * else: + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 261, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 261, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_oa), ((PyObject *)__pyx_v_ob)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 2+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 261, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_oa), ((PyObject *)__pyx_v_ob)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 2+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 261, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_7 = PyTuple_New(2+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 261, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_6, ((PyObject *)__pyx_v_oa)); + __Pyx_INCREF(((PyObject *)__pyx_v_ob)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ob)); + PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_6, ((PyObject *)__pyx_v_ob)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 261, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":262 + * if size is None: + * multi = np.broadcast(oa, ob) + * array = np.empty(multi.shape, dtype=np.float64) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, dtype=np.float64) + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_8) < 0) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 262, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_8; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":260 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(oa, ob) + * array = np.empty(multi.shape, dtype=np.float64) + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":264 + * array = np.empty(multi.shape, dtype=np.float64) + * else: + * array = np.empty(size, dtype=np.float64) # <<<<<<<<<<<<<< + * multi = np.broadcast(oa, ob, array) + * if multi.shape != array.shape: + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_size); + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_float64); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_5, __pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_7); + __pyx_t_7 = 0; + + /* "mtrand.pyx":265 + * else: + * array = np.empty(size, dtype=np.float64) + * multi = np.broadcast(oa, ob, array) # <<<<<<<<<<<<<< + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 265, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 265, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_4, ((PyObject *)__pyx_v_oa), ((PyObject *)__pyx_v_ob), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 265, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_4, ((PyObject *)__pyx_v_oa), ((PyObject *)__pyx_v_ob), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 265, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + { + __pyx_t_8 = PyTuple_New(3+__pyx_t_6); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 265, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_6, ((PyObject *)__pyx_v_oa)); + __Pyx_INCREF(((PyObject *)__pyx_v_ob)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ob)); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_6, ((PyObject *)__pyx_v_ob)); + __Pyx_INCREF(((PyObject *)arrayObject)); + __Pyx_GIVEREF(((PyObject *)arrayObject)); + PyTuple_SET_ITEM(__pyx_t_8, 2+__pyx_t_6, ((PyObject *)arrayObject)); + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 265, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_7; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":266 + * array = np.empty(size, dtype=np.float64) + * multi = np.broadcast(oa, ob, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 266, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject), __pyx_n_s_shape); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 266, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyObject_RichCompare(__pyx_t_5, __pyx_t_7, Py_NE); __Pyx_XGOTREF(__pyx_t_8); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 266, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 266, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":267 + * multi = np.broadcast(oa, ob, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 267, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_Raise(__pyx_t_8, 0, 0, 0); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __PYX_ERR(0, 267, __pyx_L1_error) + + /* "mtrand.pyx":266 + * array = np.empty(size, dtype=np.float64) + * multi = np.broadcast(oa, ob, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + } + } + __pyx_L3:; + + /* "mtrand.pyx":269 + * raise ValueError("size is not compatible with inputs") + * + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * + * with lock, nogil: + */ + __pyx_v_array_data = ((double *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":271 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*with:*/ { + __pyx_t_9 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 271, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 271, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (__pyx_t_5) { + __pyx_t_8 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 271, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + __pyx_t_8 = __Pyx_PyObject_CallNoArg(__pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 271, __pyx_L5_error) + } + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + /*try:*/ { + { + (void)__pyx_t_10; (void)__pyx_t_11; (void)__pyx_t_12; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":272 + * + * with lock, nogil: + * for i in range(multi.size): # <<<<<<<<<<<<<< + * oa_data = PyArray_MultiIter_DATA(multi, 0) + * ob_data = PyArray_MultiIter_DATA(multi, 1) + */ + __pyx_t_13 = __pyx_v_multi->size; + __pyx_t_14 = __pyx_t_13; + for (__pyx_t_15 = 0; __pyx_t_15 < __pyx_t_14; __pyx_t_15+=1) { + __pyx_v_i = __pyx_t_15; + + /* "mtrand.pyx":273 + * with lock, nogil: + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) # <<<<<<<<<<<<<< + * ob_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0], ob_data[0]) + */ + __pyx_v_oa_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 0)); + + /* "mtrand.pyx":274 + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) + * ob_data = PyArray_MultiIter_DATA(multi, 1) # <<<<<<<<<<<<<< + * array_data[i] = func(state, oa_data[0], ob_data[0]) + * PyArray_MultiIter_NEXT(multi) + */ + __pyx_v_ob_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 1)); + + /* "mtrand.pyx":275 + * oa_data = PyArray_MultiIter_DATA(multi, 0) + * ob_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0], ob_data[0]) # <<<<<<<<<<<<<< + * PyArray_MultiIter_NEXT(multi) + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (__pyx_v_oa_data[0]), (__pyx_v_ob_data[0])); + + /* "mtrand.pyx":276 + * ob_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0], ob_data[0]) + * PyArray_MultiIter_NEXT(multi) # <<<<<<<<<<<<<< + * + * return array + */ + PyArray_MultiIter_NEXT(__pyx_v_multi); + } + } + + /* "mtrand.pyx":271 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L17; + } + __pyx_L17:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_9) { + __pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_tuple__12, NULL); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 271, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + goto __pyx_L8; + } + __pyx_L8:; + } + goto __pyx_L20; + __pyx_L5_error:; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L1_error; + __pyx_L20:; + } + + /* "mtrand.pyx":278 + * PyArray_MultiIter_NEXT(multi) + * + * return array # <<<<<<<<<<<<<< + * + * cdef object cont3_array_sc(rk_state *state, rk_cont3 func, object size, double a, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + + /* "mtrand.pyx":251 + * + * + * cdef object cont2_array(rk_state *state, rk_cont2 func, object size, # <<<<<<<<<<<<<< + * ndarray oa, ndarray ob, object lock): + * cdef double *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.cont2_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XDECREF((PyObject *)__pyx_v_multi); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":280 + * return array + * + * cdef object cont3_array_sc(rk_state *state, rk_cont3 func, object size, double a, # <<<<<<<<<<<<<< + * double b, double c, object lock): + * + */ + +static PyObject *__pyx_f_6mtrand_cont3_array_sc(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_cont3 __pyx_v_func, PyObject *__pyx_v_size, double __pyx_v_a, double __pyx_v_b, double __pyx_v_c, PyObject *__pyx_v_lock) { + double *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + double __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + PyObject *__pyx_t_12 = NULL; + npy_intp __pyx_t_13; + __Pyx_RefNannySetupContext("cont3_array_sc", 0); + + /* "mtrand.pyx":288 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, a, b, c) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":289 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a, b, c) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 289, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 289, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 289, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 289, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":290 + * if size is None: + * with lock, nogil: + * rv = func(state, a, b, c) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state, __pyx_v_a, __pyx_v_b, __pyx_v_c); + } + + /* "mtrand.pyx":289 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a, b, c) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__13, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 289, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":291 + * with lock, nogil: + * rv = func(state, a, b, c) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, np.float64) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 291, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":288 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, a, b, c) + */ + } + + /* "mtrand.pyx":293 + * return rv + * else: + * array = np.empty(size, np.float64) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 293, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 293, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 293, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_float64); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 293, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 293, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 293, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + { + __pyx_t_12 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 293, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_12, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_12, 0+__pyx_t_11, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_12, 1+__pyx_t_11, __pyx_t_10); + __pyx_t_10 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_12, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 293, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":294 + * else: + * array = np.empty(size, np.float64) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":295 + * array = np.empty(size, np.float64) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((double *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":296 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b, c) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 296, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 296, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_12 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_12)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_12); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_12) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_12); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 296, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 296, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":297 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, a, b, c) + * return array + */ + __pyx_t_13 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_13; __pyx_v_i++) { + + /* "mtrand.pyx":298 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b, c) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, __pyx_v_a, __pyx_v_b, __pyx_v_c); + } + } + + /* "mtrand.pyx":296 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b, c) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__14, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 296, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":299 + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b, c) + * return array # <<<<<<<<<<<<<< + * + * cdef object cont3_array(rk_state *state, rk_cont3 func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":280 + * return array + * + * cdef object cont3_array_sc(rk_state *state, rk_cont3 func, object size, double a, # <<<<<<<<<<<<<< + * double b, double c, object lock): + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_AddTraceback("mtrand.cont3_array_sc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":301 + * return array + * + * cdef object cont3_array(rk_state *state, rk_cont3 func, object size, # <<<<<<<<<<<<<< + * ndarray oa, ndarray ob, ndarray oc, object lock): + * + */ + +static PyObject *__pyx_f_6mtrand_cont3_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_cont3 __pyx_v_func, PyObject *__pyx_v_size, PyArrayObject *__pyx_v_oa, PyArrayObject *__pyx_v_ob, PyArrayObject *__pyx_v_oc, PyObject *__pyx_v_lock) { + double *__pyx_v_array_data; + double *__pyx_v_oa_data; + double *__pyx_v_ob_data; + double *__pyx_v_oc_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_i; + PyArrayMultiIterObject *__pyx_v_multi = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + npy_intp __pyx_t_13; + npy_intp __pyx_t_14; + npy_intp __pyx_t_15; + __Pyx_RefNannySetupContext("cont3_array", 0); + + /* "mtrand.pyx":312 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(oa, ob, oc) + * array = np.empty(multi.shape, dtype=np.float64) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":313 + * + * if size is None: + * multi = np.broadcast(oa, ob, oc) # <<<<<<<<<<<<<< + * array = np.empty(multi.shape, dtype=np.float64) + * else: + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 313, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 313, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_4, ((PyObject *)__pyx_v_oa), ((PyObject *)__pyx_v_ob), ((PyObject *)__pyx_v_oc)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 313, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_4, ((PyObject *)__pyx_v_oa), ((PyObject *)__pyx_v_ob), ((PyObject *)__pyx_v_oc)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 313, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_7 = PyTuple_New(3+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 313, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_6, ((PyObject *)__pyx_v_oa)); + __Pyx_INCREF(((PyObject *)__pyx_v_ob)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ob)); + PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_6, ((PyObject *)__pyx_v_ob)); + __Pyx_INCREF(((PyObject *)__pyx_v_oc)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oc)); + PyTuple_SET_ITEM(__pyx_t_7, 2+__pyx_t_6, ((PyObject *)__pyx_v_oc)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 313, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":314 + * if size is None: + * multi = np.broadcast(oa, ob, oc) + * array = np.empty(multi.shape, dtype=np.float64) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, dtype=np.float64) + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_8) < 0) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 314, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_8; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":312 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(oa, ob, oc) + * array = np.empty(multi.shape, dtype=np.float64) + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":316 + * array = np.empty(multi.shape, dtype=np.float64) + * else: + * array = np.empty(size, dtype=np.float64) # <<<<<<<<<<<<<< + * multi = np.broadcast(oa, ob, oc, array) + * if multi.shape != array.shape: + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_size); + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_float64); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 316, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_5, __pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_7); + __pyx_t_7 = 0; + + /* "mtrand.pyx":317 + * else: + * array = np.empty(size, dtype=np.float64) + * multi = np.broadcast(oa, ob, oc, array) # <<<<<<<<<<<<<< + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 317, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 317, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[5] = {__pyx_t_4, ((PyObject *)__pyx_v_oa), ((PyObject *)__pyx_v_ob), ((PyObject *)__pyx_v_oc), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 4+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 317, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[5] = {__pyx_t_4, ((PyObject *)__pyx_v_oa), ((PyObject *)__pyx_v_ob), ((PyObject *)__pyx_v_oc), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 4+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 317, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + { + __pyx_t_8 = PyTuple_New(4+__pyx_t_6); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 317, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_6, ((PyObject *)__pyx_v_oa)); + __Pyx_INCREF(((PyObject *)__pyx_v_ob)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ob)); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_6, ((PyObject *)__pyx_v_ob)); + __Pyx_INCREF(((PyObject *)__pyx_v_oc)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oc)); + PyTuple_SET_ITEM(__pyx_t_8, 2+__pyx_t_6, ((PyObject *)__pyx_v_oc)); + __Pyx_INCREF(((PyObject *)arrayObject)); + __Pyx_GIVEREF(((PyObject *)arrayObject)); + PyTuple_SET_ITEM(__pyx_t_8, 3+__pyx_t_6, ((PyObject *)arrayObject)); + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 317, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_7; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":318 + * array = np.empty(size, dtype=np.float64) + * multi = np.broadcast(oa, ob, oc, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 318, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject), __pyx_n_s_shape); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 318, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyObject_RichCompare(__pyx_t_5, __pyx_t_7, Py_NE); __Pyx_XGOTREF(__pyx_t_8); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 318, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 318, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":319 + * multi = np.broadcast(oa, ob, oc, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__15, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_Raise(__pyx_t_8, 0, 0, 0); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __PYX_ERR(0, 319, __pyx_L1_error) + + /* "mtrand.pyx":318 + * array = np.empty(size, dtype=np.float64) + * multi = np.broadcast(oa, ob, oc, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + } + } + __pyx_L3:; + + /* "mtrand.pyx":321 + * raise ValueError("size is not compatible with inputs") + * + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * + * with lock, nogil: + */ + __pyx_v_array_data = ((double *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":323 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*with:*/ { + __pyx_t_9 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 323, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 323, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (__pyx_t_5) { + __pyx_t_8 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 323, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + __pyx_t_8 = __Pyx_PyObject_CallNoArg(__pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 323, __pyx_L5_error) + } + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + /*try:*/ { + { + (void)__pyx_t_10; (void)__pyx_t_11; (void)__pyx_t_12; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":324 + * + * with lock, nogil: + * for i in range(multi.size): # <<<<<<<<<<<<<< + * oa_data = PyArray_MultiIter_DATA(multi, 0) + * ob_data = PyArray_MultiIter_DATA(multi, 1) + */ + __pyx_t_13 = __pyx_v_multi->size; + __pyx_t_14 = __pyx_t_13; + for (__pyx_t_15 = 0; __pyx_t_15 < __pyx_t_14; __pyx_t_15+=1) { + __pyx_v_i = __pyx_t_15; + + /* "mtrand.pyx":325 + * with lock, nogil: + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) # <<<<<<<<<<<<<< + * ob_data = PyArray_MultiIter_DATA(multi, 1) + * oc_data = PyArray_MultiIter_DATA(multi, 2) + */ + __pyx_v_oa_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 0)); + + /* "mtrand.pyx":326 + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) + * ob_data = PyArray_MultiIter_DATA(multi, 1) # <<<<<<<<<<<<<< + * oc_data = PyArray_MultiIter_DATA(multi, 2) + * array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0]) + */ + __pyx_v_ob_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 1)); + + /* "mtrand.pyx":327 + * oa_data = PyArray_MultiIter_DATA(multi, 0) + * ob_data = PyArray_MultiIter_DATA(multi, 1) + * oc_data = PyArray_MultiIter_DATA(multi, 2) # <<<<<<<<<<<<<< + * array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0]) + * PyArray_MultiIter_NEXT(multi) + */ + __pyx_v_oc_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 2)); + + /* "mtrand.pyx":328 + * ob_data = PyArray_MultiIter_DATA(multi, 1) + * oc_data = PyArray_MultiIter_DATA(multi, 2) + * array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0]) # <<<<<<<<<<<<<< + * PyArray_MultiIter_NEXT(multi) + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (__pyx_v_oa_data[0]), (__pyx_v_ob_data[0]), (__pyx_v_oc_data[0])); + + /* "mtrand.pyx":329 + * oc_data = PyArray_MultiIter_DATA(multi, 2) + * array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0]) + * PyArray_MultiIter_NEXT(multi) # <<<<<<<<<<<<<< + * + * return array + */ + PyArray_MultiIter_NEXT(__pyx_v_multi); + } + } + + /* "mtrand.pyx":323 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L17; + } + __pyx_L17:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_9) { + __pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_tuple__16, NULL); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 323, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + goto __pyx_L8; + } + __pyx_L8:; + } + goto __pyx_L20; + __pyx_L5_error:; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L1_error; + __pyx_L20:; + } + + /* "mtrand.pyx":331 + * PyArray_MultiIter_NEXT(multi) + * + * return array # <<<<<<<<<<<<<< + * + * cdef object disc0_array(rk_state *state, rk_disc0 func, object size, object lock): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + + /* "mtrand.pyx":301 + * return array + * + * cdef object cont3_array(rk_state *state, rk_cont3 func, object size, # <<<<<<<<<<<<<< + * ndarray oa, ndarray ob, ndarray oc, object lock): + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.cont3_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XDECREF((PyObject *)__pyx_v_multi); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":333 + * return array + * + * cdef object disc0_array(rk_state *state, rk_disc0 func, object size, object lock): # <<<<<<<<<<<<<< + * cdef long *array_data + * cdef ndarray array "arrayObject" + */ + +static PyObject *__pyx_f_6mtrand_disc0_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_disc0 __pyx_v_func, PyObject *__pyx_v_size, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + long __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + npy_intp __pyx_t_12; + __Pyx_RefNannySetupContext("disc0_array", 0); + + /* "mtrand.pyx":339 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":340 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 340, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 340, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 340, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 340, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":341 + * if size is None: + * with lock, nogil: + * rv = func(state) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state); + } + + /* "mtrand.pyx":340 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__17, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 340, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":342 + * with lock, nogil: + * rv = func(state) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, int) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyInt_From_long(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 342, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":339 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state) + */ + } + + /* "mtrand.pyx":344 + * return rv + * else: + * array = np.empty(size, int) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 344, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 344, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 344, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 344, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 344, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_v_size); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, ((PyObject *)(&PyInt_Type))); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 344, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":345 + * else: + * array = np.empty(size, int) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":346 + * array = np.empty(size, int) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":347 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 347, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_11 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_11)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_11); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_11) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_11); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 347, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 347, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":348 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state) + * return array + */ + __pyx_t_12 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_12; __pyx_v_i++) { + + /* "mtrand.pyx":349 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state); + } + } + + /* "mtrand.pyx":347 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__18, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":350 + * for i from 0 <= i < length: + * array_data[i] = func(state) + * return array # <<<<<<<<<<<<<< + * + * cdef object discnp_array_sc(rk_state *state, rk_discnp func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":333 + * return array + * + * cdef object disc0_array(rk_state *state, rk_disc0 func, object size, object lock): # <<<<<<<<<<<<<< + * cdef long *array_data + * cdef ndarray array "arrayObject" + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("mtrand.disc0_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":352 + * return array + * + * cdef object discnp_array_sc(rk_state *state, rk_discnp func, object size, # <<<<<<<<<<<<<< + * long n, double p, object lock): + * cdef long *array_data + */ + +static PyObject *__pyx_f_6mtrand_discnp_array_sc(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_discnp __pyx_v_func, PyObject *__pyx_v_size, long __pyx_v_n, double __pyx_v_p, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + long __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + npy_intp __pyx_t_12; + __Pyx_RefNannySetupContext("discnp_array_sc", 0); + + /* "mtrand.pyx":359 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, n, p) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":360 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, p) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 360, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 360, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 360, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 360, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":361 + * if size is None: + * with lock, nogil: + * rv = func(state, n, p) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state, __pyx_v_n, __pyx_v_p); + } + + /* "mtrand.pyx":360 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, p) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__19, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 360, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":362 + * with lock, nogil: + * rv = func(state, n, p) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, int) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyInt_From_long(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 362, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":359 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, n, p) + */ + } + + /* "mtrand.pyx":364 + * return rv + * else: + * array = np.empty(size, int) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 364, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 364, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 364, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 364, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 364, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_v_size); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, ((PyObject *)(&PyInt_Type))); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 364, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":365 + * else: + * array = np.empty(size, int) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":366 + * array = np.empty(size, int) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":367 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 367, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 367, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_11 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_11)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_11); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_11) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_11); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 367, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 367, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":368 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, n, p) + * return array + */ + __pyx_t_12 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_12; __pyx_v_i++) { + + /* "mtrand.pyx":369 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, __pyx_v_n, __pyx_v_p); + } + } + + /* "mtrand.pyx":367 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__20, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 367, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":370 + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) + * return array # <<<<<<<<<<<<<< + * + * cdef object discnp_array(rk_state *state, rk_discnp func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":352 + * return array + * + * cdef object discnp_array_sc(rk_state *state, rk_discnp func, object size, # <<<<<<<<<<<<<< + * long n, double p, object lock): + * cdef long *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("mtrand.discnp_array_sc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":372 + * return array + * + * cdef object discnp_array(rk_state *state, rk_discnp func, object size, # <<<<<<<<<<<<<< + * ndarray on, ndarray op, object lock): + * cdef long *array_data + */ + +static PyObject *__pyx_f_6mtrand_discnp_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_discnp __pyx_v_func, PyObject *__pyx_v_size, PyArrayObject *__pyx_v_on, PyArrayObject *__pyx_v_op, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_i; + double *__pyx_v_op_data; + long *__pyx_v_on_data; + PyArrayMultiIterObject *__pyx_v_multi = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + npy_intp __pyx_t_12; + npy_intp __pyx_t_13; + npy_intp __pyx_t_14; + __Pyx_RefNannySetupContext("discnp_array", 0); + + /* "mtrand.pyx":381 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(on, op) + * array = np.empty(multi.shape, dtype=int) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":382 + * + * if size is None: + * multi = np.broadcast(on, op) # <<<<<<<<<<<<<< + * array = np.empty(multi.shape, dtype=int) + * else: + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_op)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 2+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_op)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 2+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_7 = PyTuple_New(2+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_on)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_on)); + PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_6, ((PyObject *)__pyx_v_on)); + __Pyx_INCREF(((PyObject *)__pyx_v_op)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_op)); + PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_6, ((PyObject *)__pyx_v_op)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 382, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":383 + * if size is None: + * multi = np.broadcast(on, op) + * array = np.empty(multi.shape, dtype=int) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, dtype=int) + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 383, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 383, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 383, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 383, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 383, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, ((PyObject *)(&PyInt_Type))) < 0) __PYX_ERR(0, 383, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 383, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":381 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(on, op) + * array = np.empty(multi.shape, dtype=int) + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":385 + * array = np.empty(multi.shape, dtype=int) + * else: + * array = np.empty(size, dtype=int) # <<<<<<<<<<<<<< + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_size); + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_dtype, ((PyObject *)(&PyInt_Type))) < 0) __PYX_ERR(0, 385, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_5, __pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_7); + __pyx_t_7 = 0; + + /* "mtrand.pyx":386 + * else: + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, op, array) # <<<<<<<<<<<<<< + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 386, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 386, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_3, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_op), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 386, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_3, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_op), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 386, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + { + __pyx_t_4 = PyTuple_New(3+__pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 386, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_on)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_on)); + PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_6, ((PyObject *)__pyx_v_on)); + __Pyx_INCREF(((PyObject *)__pyx_v_op)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_op)); + PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_6, ((PyObject *)__pyx_v_op)); + __Pyx_INCREF(((PyObject *)arrayObject)); + __Pyx_GIVEREF(((PyObject *)arrayObject)); + PyTuple_SET_ITEM(__pyx_t_4, 2+__pyx_t_6, ((PyObject *)arrayObject)); + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_4, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 386, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_7; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":387 + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject), __pyx_n_s_shape); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = PyObject_RichCompare(__pyx_t_5, __pyx_t_7, Py_NE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 387, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":388 + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__21, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 388, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 388, __pyx_L1_error) + + /* "mtrand.pyx":387 + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + } + } + __pyx_L3:; + + /* "mtrand.pyx":390 + * raise ValueError("size is not compatible with inputs") + * + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * + * with lock, nogil: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":392 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*with:*/ { + __pyx_t_8 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 392, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 392, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (__pyx_t_5) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 392, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 392, __pyx_L5_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_10; (void)__pyx_t_11; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":393 + * + * with lock, nogil: + * for i in range(multi.size): # <<<<<<<<<<<<<< + * on_data = PyArray_MultiIter_DATA(multi, 0) + * op_data = PyArray_MultiIter_DATA(multi, 1) + */ + __pyx_t_12 = __pyx_v_multi->size; + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) { + __pyx_v_i = __pyx_t_14; + + /* "mtrand.pyx":394 + * with lock, nogil: + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) # <<<<<<<<<<<<<< + * op_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, on_data[0], op_data[0]) + */ + __pyx_v_on_data = ((long *)PyArray_MultiIter_DATA(__pyx_v_multi, 0)); + + /* "mtrand.pyx":395 + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + * op_data = PyArray_MultiIter_DATA(multi, 1) # <<<<<<<<<<<<<< + * array_data[i] = func(state, on_data[0], op_data[0]) + * PyArray_MultiIter_NEXT(multi) + */ + __pyx_v_op_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 1)); + + /* "mtrand.pyx":396 + * on_data = PyArray_MultiIter_DATA(multi, 0) + * op_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, on_data[0], op_data[0]) # <<<<<<<<<<<<<< + * PyArray_MultiIter_NEXT(multi) + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (__pyx_v_on_data[0]), (__pyx_v_op_data[0])); + + /* "mtrand.pyx":397 + * op_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, on_data[0], op_data[0]) + * PyArray_MultiIter_NEXT(multi) # <<<<<<<<<<<<<< + * + * return array + */ + PyArray_MultiIter_NEXT(__pyx_v_multi); + } + } + + /* "mtrand.pyx":392 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L17; + } + __pyx_L17:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_8) { + __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_tuple__22, NULL); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 392, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + goto __pyx_L8; + } + __pyx_L8:; + } + goto __pyx_L20; + __pyx_L5_error:; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L1_error; + __pyx_L20:; + } + + /* "mtrand.pyx":399 + * PyArray_MultiIter_NEXT(multi) + * + * return array # <<<<<<<<<<<<<< + * + * cdef object discdd_array_sc(rk_state *state, rk_discdd func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + + /* "mtrand.pyx":372 + * return array + * + * cdef object discnp_array(rk_state *state, rk_discnp func, object size, # <<<<<<<<<<<<<< + * ndarray on, ndarray op, object lock): + * cdef long *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("mtrand.discnp_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XDECREF((PyObject *)__pyx_v_multi); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":401 + * return array + * + * cdef object discdd_array_sc(rk_state *state, rk_discdd func, object size, # <<<<<<<<<<<<<< + * double n, double p, object lock): + * cdef long *array_data + */ + +static PyObject *__pyx_f_6mtrand_discdd_array_sc(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_discdd __pyx_v_func, PyObject *__pyx_v_size, double __pyx_v_n, double __pyx_v_p, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + long __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + npy_intp __pyx_t_12; + __Pyx_RefNannySetupContext("discdd_array_sc", 0); + + /* "mtrand.pyx":408 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, n, p) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":409 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, p) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 409, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 409, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 409, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 409, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":410 + * if size is None: + * with lock, nogil: + * rv = func(state, n, p) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state, __pyx_v_n, __pyx_v_p); + } + + /* "mtrand.pyx":409 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, p) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__23, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 409, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":411 + * with lock, nogil: + * rv = func(state, n, p) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, int) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyInt_From_long(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 411, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":408 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, n, p) + */ + } + + /* "mtrand.pyx":413 + * return rv + * else: + * array = np.empty(size, int) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 413, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 413, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 413, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 413, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 413, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_v_size); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, ((PyObject *)(&PyInt_Type))); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 413, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":414 + * else: + * array = np.empty(size, int) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":415 + * array = np.empty(size, int) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":416 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 416, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 416, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_11 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_11)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_11); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_11) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_11); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 416, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 416, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":417 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, n, p) + * return array + */ + __pyx_t_12 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_12; __pyx_v_i++) { + + /* "mtrand.pyx":418 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, __pyx_v_n, __pyx_v_p); + } + } + + /* "mtrand.pyx":416 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__24, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 416, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":419 + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) + * return array # <<<<<<<<<<<<<< + * + * cdef object discdd_array(rk_state *state, rk_discdd func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":401 + * return array + * + * cdef object discdd_array_sc(rk_state *state, rk_discdd func, object size, # <<<<<<<<<<<<<< + * double n, double p, object lock): + * cdef long *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("mtrand.discdd_array_sc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":421 + * return array + * + * cdef object discdd_array(rk_state *state, rk_discdd func, object size, # <<<<<<<<<<<<<< + * ndarray on, ndarray op, object lock): + * cdef long *array_data + */ + +static PyObject *__pyx_f_6mtrand_discdd_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_discdd __pyx_v_func, PyObject *__pyx_v_size, PyArrayObject *__pyx_v_on, PyArrayObject *__pyx_v_op, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_i; + double *__pyx_v_op_data; + double *__pyx_v_on_data; + PyArrayMultiIterObject *__pyx_v_multi = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + npy_intp __pyx_t_12; + npy_intp __pyx_t_13; + npy_intp __pyx_t_14; + __Pyx_RefNannySetupContext("discdd_array", 0); + + /* "mtrand.pyx":430 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(on, op) + * array = np.empty(multi.shape, dtype=int) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":431 + * + * if size is None: + * multi = np.broadcast(on, op) # <<<<<<<<<<<<<< + * array = np.empty(multi.shape, dtype=int) + * else: + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_op)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 2+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 431, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_op)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 2+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 431, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_7 = PyTuple_New(2+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_on)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_on)); + PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_6, ((PyObject *)__pyx_v_on)); + __Pyx_INCREF(((PyObject *)__pyx_v_op)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_op)); + PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_6, ((PyObject *)__pyx_v_op)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 431, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":432 + * if size is None: + * multi = np.broadcast(on, op) + * array = np.empty(multi.shape, dtype=int) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, dtype=int) + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, ((PyObject *)(&PyInt_Type))) < 0) __PYX_ERR(0, 432, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":430 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(on, op) + * array = np.empty(multi.shape, dtype=int) + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":434 + * array = np.empty(multi.shape, dtype=int) + * else: + * array = np.empty(size, dtype=int) # <<<<<<<<<<<<<< + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_size); + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_dtype, ((PyObject *)(&PyInt_Type))) < 0) __PYX_ERR(0, 434, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_5, __pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_7); + __pyx_t_7 = 0; + + /* "mtrand.pyx":435 + * else: + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, op, array) # <<<<<<<<<<<<<< + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 435, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 435, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_3, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_op), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 435, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_3, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_op), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 435, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + { + __pyx_t_4 = PyTuple_New(3+__pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 435, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_on)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_on)); + PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_6, ((PyObject *)__pyx_v_on)); + __Pyx_INCREF(((PyObject *)__pyx_v_op)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_op)); + PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_6, ((PyObject *)__pyx_v_op)); + __Pyx_INCREF(((PyObject *)arrayObject)); + __Pyx_GIVEREF(((PyObject *)arrayObject)); + PyTuple_SET_ITEM(__pyx_t_4, 2+__pyx_t_6, ((PyObject *)arrayObject)); + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_4, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 435, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_7; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":436 + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject), __pyx_n_s_shape); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = PyObject_RichCompare(__pyx_t_5, __pyx_t_7, Py_NE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 436, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":437 + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__25, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 437, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 437, __pyx_L1_error) + + /* "mtrand.pyx":436 + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + } + } + __pyx_L3:; + + /* "mtrand.pyx":439 + * raise ValueError("size is not compatible with inputs") + * + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * + * with lock, nogil: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":441 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*with:*/ { + __pyx_t_8 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 441, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 441, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (__pyx_t_5) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 441, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 441, __pyx_L5_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_10; (void)__pyx_t_11; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":442 + * + * with lock, nogil: + * for i in range(multi.size): # <<<<<<<<<<<<<< + * on_data = PyArray_MultiIter_DATA(multi, 0) + * op_data = PyArray_MultiIter_DATA(multi, 1) + */ + __pyx_t_12 = __pyx_v_multi->size; + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) { + __pyx_v_i = __pyx_t_14; + + /* "mtrand.pyx":443 + * with lock, nogil: + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) # <<<<<<<<<<<<<< + * op_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, on_data[0], op_data[0]) + */ + __pyx_v_on_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 0)); + + /* "mtrand.pyx":444 + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + * op_data = PyArray_MultiIter_DATA(multi, 1) # <<<<<<<<<<<<<< + * array_data[i] = func(state, on_data[0], op_data[0]) + * PyArray_MultiIter_NEXT(multi) + */ + __pyx_v_op_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 1)); + + /* "mtrand.pyx":445 + * on_data = PyArray_MultiIter_DATA(multi, 0) + * op_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, on_data[0], op_data[0]) # <<<<<<<<<<<<<< + * PyArray_MultiIter_NEXT(multi) + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (__pyx_v_on_data[0]), (__pyx_v_op_data[0])); + + /* "mtrand.pyx":446 + * op_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, on_data[0], op_data[0]) + * PyArray_MultiIter_NEXT(multi) # <<<<<<<<<<<<<< + * + * return array + */ + PyArray_MultiIter_NEXT(__pyx_v_multi); + } + } + + /* "mtrand.pyx":441 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L17; + } + __pyx_L17:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_8) { + __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_tuple__26, NULL); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 441, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + goto __pyx_L8; + } + __pyx_L8:; + } + goto __pyx_L20; + __pyx_L5_error:; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L1_error; + __pyx_L20:; + } + + /* "mtrand.pyx":448 + * PyArray_MultiIter_NEXT(multi) + * + * return array # <<<<<<<<<<<<<< + * + * cdef object discnmN_array_sc(rk_state *state, rk_discnmN func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + + /* "mtrand.pyx":421 + * return array + * + * cdef object discdd_array(rk_state *state, rk_discdd func, object size, # <<<<<<<<<<<<<< + * ndarray on, ndarray op, object lock): + * cdef long *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("mtrand.discdd_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XDECREF((PyObject *)__pyx_v_multi); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":450 + * return array + * + * cdef object discnmN_array_sc(rk_state *state, rk_discnmN func, object size, # <<<<<<<<<<<<<< + * long n, long m, long N, object lock): + * cdef long *array_data + */ + +static PyObject *__pyx_f_6mtrand_discnmN_array_sc(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_discnmN __pyx_v_func, PyObject *__pyx_v_size, long __pyx_v_n, long __pyx_v_m, long __pyx_v_N, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + long __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + npy_intp __pyx_t_12; + __Pyx_RefNannySetupContext("discnmN_array_sc", 0); + + /* "mtrand.pyx":457 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, n, m, N) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":458 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, m, N) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 458, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 458, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 458, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":459 + * if size is None: + * with lock, nogil: + * rv = func(state, n, m, N) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state, __pyx_v_n, __pyx_v_m, __pyx_v_N); + } + + /* "mtrand.pyx":458 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, m, N) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__27, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":460 + * with lock, nogil: + * rv = func(state, n, m, N) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, int) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyInt_From_long(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 460, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":457 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, n, m, N) + */ + } + + /* "mtrand.pyx":462 + * return rv + * else: + * array = np.empty(size, int) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_v_size); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, ((PyObject *)(&PyInt_Type))); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 462, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":463 + * else: + * array = np.empty(size, int) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":464 + * array = np.empty(size, int) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":465 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, m, N) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 465, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 465, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_11 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_11)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_11); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_11) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_11); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 465, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 465, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":466 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, n, m, N) + * return array + */ + __pyx_t_12 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_12; __pyx_v_i++) { + + /* "mtrand.pyx":467 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, n, m, N) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, __pyx_v_n, __pyx_v_m, __pyx_v_N); + } + } + + /* "mtrand.pyx":465 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, m, N) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__28, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 465, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":468 + * for i from 0 <= i < length: + * array_data[i] = func(state, n, m, N) + * return array # <<<<<<<<<<<<<< + * + * cdef object discnmN_array(rk_state *state, rk_discnmN func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":450 + * return array + * + * cdef object discnmN_array_sc(rk_state *state, rk_discnmN func, object size, # <<<<<<<<<<<<<< + * long n, long m, long N, object lock): + * cdef long *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("mtrand.discnmN_array_sc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":470 + * return array + * + * cdef object discnmN_array(rk_state *state, rk_discnmN func, object size, # <<<<<<<<<<<<<< + * ndarray on, ndarray om, ndarray oN, object lock): + * cdef long *array_data + */ + +static PyObject *__pyx_f_6mtrand_discnmN_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_discnmN __pyx_v_func, PyObject *__pyx_v_size, PyArrayObject *__pyx_v_on, PyArrayObject *__pyx_v_om, PyArrayObject *__pyx_v_oN, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + long *__pyx_v_on_data; + long *__pyx_v_om_data; + long *__pyx_v_oN_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_i; + PyArrayMultiIterObject *__pyx_v_multi = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + npy_intp __pyx_t_12; + npy_intp __pyx_t_13; + npy_intp __pyx_t_14; + __Pyx_RefNannySetupContext("discnmN_array", 0); + + /* "mtrand.pyx":480 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(on, om, oN) + * array = np.empty(multi.shape, dtype=int) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":481 + * + * if size is None: + * multi = np.broadcast(on, om, oN) # <<<<<<<<<<<<<< + * array = np.empty(multi.shape, dtype=int) + * else: + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 481, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 481, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_4, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_om), ((PyObject *)__pyx_v_oN)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 481, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[4] = {__pyx_t_4, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_om), ((PyObject *)__pyx_v_oN)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 3+__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 481, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_7 = PyTuple_New(3+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 481, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_on)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_on)); + PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_6, ((PyObject *)__pyx_v_on)); + __Pyx_INCREF(((PyObject *)__pyx_v_om)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_om)); + PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_6, ((PyObject *)__pyx_v_om)); + __Pyx_INCREF(((PyObject *)__pyx_v_oN)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oN)); + PyTuple_SET_ITEM(__pyx_t_7, 2+__pyx_t_6, ((PyObject *)__pyx_v_oN)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 481, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":482 + * if size is None: + * multi = np.broadcast(on, om, oN) + * array = np.empty(multi.shape, dtype=int) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, dtype=int) + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, ((PyObject *)(&PyInt_Type))) < 0) __PYX_ERR(0, 482, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 482, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":480 + * cdef broadcast multi + * + * if size is None: # <<<<<<<<<<<<<< + * multi = np.broadcast(on, om, oN) + * array = np.empty(multi.shape, dtype=int) + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":484 + * array = np.empty(multi.shape, dtype=int) + * else: + * array = np.empty(size, dtype=int) # <<<<<<<<<<<<<< + * multi = np.broadcast(on, om, oN, array) + * if multi.shape != array.shape: + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 484, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 484, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 484, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_size); + __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 484, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_dtype, ((PyObject *)(&PyInt_Type))) < 0) __PYX_ERR(0, 484, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_5, __pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 484, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_7); + __pyx_t_7 = 0; + + /* "mtrand.pyx":485 + * else: + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, om, oN, array) # <<<<<<<<<<<<<< + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 485, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_broadcast); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 485, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_om), ((PyObject *)__pyx_v_oN), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 4+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 485, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, ((PyObject *)__pyx_v_on), ((PyObject *)__pyx_v_om), ((PyObject *)__pyx_v_oN), ((PyObject *)arrayObject)}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_6, 4+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 485, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + { + __pyx_t_4 = PyTuple_New(4+__pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 485, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_on)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_on)); + PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_6, ((PyObject *)__pyx_v_on)); + __Pyx_INCREF(((PyObject *)__pyx_v_om)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_om)); + PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_6, ((PyObject *)__pyx_v_om)); + __Pyx_INCREF(((PyObject *)__pyx_v_oN)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oN)); + PyTuple_SET_ITEM(__pyx_t_4, 2+__pyx_t_6, ((PyObject *)__pyx_v_oN)); + __Pyx_INCREF(((PyObject *)arrayObject)); + __Pyx_GIVEREF(((PyObject *)arrayObject)); + PyTuple_SET_ITEM(__pyx_t_4, 3+__pyx_t_6, ((PyObject *)arrayObject)); + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_4, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 485, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __pyx_t_7; + __Pyx_INCREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "mtrand.pyx":486 + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, om, oN, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_multi), __pyx_n_s_shape); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 486, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject), __pyx_n_s_shape); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 486, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = PyObject_RichCompare(__pyx_t_5, __pyx_t_7, Py_NE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 486, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 486, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":487 + * multi = np.broadcast(on, om, oN, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__29, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 487, __pyx_L1_error) + + /* "mtrand.pyx":486 + * array = np.empty(size, dtype=int) + * multi = np.broadcast(on, om, oN, array) + * if multi.shape != array.shape: # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * + */ + } + } + __pyx_L3:; + + /* "mtrand.pyx":489 + * raise ValueError("size is not compatible with inputs") + * + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * + * with lock, nogil: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":491 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*with:*/ { + __pyx_t_8 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 491, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 491, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (__pyx_t_5) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 491, __pyx_L5_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 491, __pyx_L5_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_10; (void)__pyx_t_11; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":492 + * + * with lock, nogil: + * for i in range(multi.size): # <<<<<<<<<<<<<< + * on_data = PyArray_MultiIter_DATA(multi, 0) + * om_data = PyArray_MultiIter_DATA(multi, 1) + */ + __pyx_t_12 = __pyx_v_multi->size; + __pyx_t_13 = __pyx_t_12; + for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) { + __pyx_v_i = __pyx_t_14; + + /* "mtrand.pyx":493 + * with lock, nogil: + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) # <<<<<<<<<<<<<< + * om_data = PyArray_MultiIter_DATA(multi, 1) + * oN_data = PyArray_MultiIter_DATA(multi, 2) + */ + __pyx_v_on_data = ((long *)PyArray_MultiIter_DATA(__pyx_v_multi, 0)); + + /* "mtrand.pyx":494 + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + * om_data = PyArray_MultiIter_DATA(multi, 1) # <<<<<<<<<<<<<< + * oN_data = PyArray_MultiIter_DATA(multi, 2) + * array_data[i] = func(state, on_data[0], om_data[0], oN_data[0]) + */ + __pyx_v_om_data = ((long *)PyArray_MultiIter_DATA(__pyx_v_multi, 1)); + + /* "mtrand.pyx":495 + * on_data = PyArray_MultiIter_DATA(multi, 0) + * om_data = PyArray_MultiIter_DATA(multi, 1) + * oN_data = PyArray_MultiIter_DATA(multi, 2) # <<<<<<<<<<<<<< + * array_data[i] = func(state, on_data[0], om_data[0], oN_data[0]) + * PyArray_MultiIter_NEXT(multi) + */ + __pyx_v_oN_data = ((long *)PyArray_MultiIter_DATA(__pyx_v_multi, 2)); + + /* "mtrand.pyx":496 + * om_data = PyArray_MultiIter_DATA(multi, 1) + * oN_data = PyArray_MultiIter_DATA(multi, 2) + * array_data[i] = func(state, on_data[0], om_data[0], oN_data[0]) # <<<<<<<<<<<<<< + * PyArray_MultiIter_NEXT(multi) + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (__pyx_v_on_data[0]), (__pyx_v_om_data[0]), (__pyx_v_oN_data[0])); + + /* "mtrand.pyx":497 + * oN_data = PyArray_MultiIter_DATA(multi, 2) + * array_data[i] = func(state, on_data[0], om_data[0], oN_data[0]) + * PyArray_MultiIter_NEXT(multi) # <<<<<<<<<<<<<< + * + * return array + */ + PyArray_MultiIter_NEXT(__pyx_v_multi); + } + } + + /* "mtrand.pyx":491 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L17; + } + __pyx_L17:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_8) { + __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_tuple__30, NULL); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 491, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + goto __pyx_L8; + } + __pyx_L8:; + } + goto __pyx_L20; + __pyx_L5_error:; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L1_error; + __pyx_L20:; + } + + /* "mtrand.pyx":499 + * PyArray_MultiIter_NEXT(multi) + * + * return array # <<<<<<<<<<<<<< + * + * cdef object discd_array_sc(rk_state *state, rk_discd func, object size, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + + /* "mtrand.pyx":470 + * return array + * + * cdef object discnmN_array(rk_state *state, rk_discnmN func, object size, # <<<<<<<<<<<<<< + * ndarray on, ndarray om, ndarray oN, object lock): + * cdef long *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("mtrand.discnmN_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XDECREF((PyObject *)__pyx_v_multi); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":501 + * return array + * + * cdef object discd_array_sc(rk_state *state, rk_discd func, object size, # <<<<<<<<<<<<<< + * double a, object lock): + * cdef long *array_data + */ + +static PyObject *__pyx_f_6mtrand_discd_array_sc(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_discd __pyx_v_func, PyObject *__pyx_v_size, double __pyx_v_a, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + long __pyx_v_rv; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + npy_intp __pyx_t_12; + __Pyx_RefNannySetupContext("discd_array_sc", 0); + + /* "mtrand.pyx":508 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, a) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":509 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a) + * return rv + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 509, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 509, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (__pyx_t_6) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 509, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 509, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":510 + * if size is None: + * with lock, nogil: + * rv = func(state, a) # <<<<<<<<<<<<<< + * return rv + * else: + */ + __pyx_v_rv = __pyx_v_func(__pyx_v_state, __pyx_v_a); + } + + /* "mtrand.pyx":509 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a) + * return rv + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__31, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 509, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L17; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L17:; + } + + /* "mtrand.pyx":511 + * with lock, nogil: + * rv = func(state, a) + * return rv # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, int) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyInt_From_long(__pyx_v_rv); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":508 + * cdef npy_intp i + * + * if size is None: # <<<<<<<<<<<<<< + * with lock, nogil: + * rv = func(state, a) + */ + } + + /* "mtrand.pyx":513 + * return rv + * else: + * array = np.empty(size, int) # <<<<<<<<<<<<<< + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 513, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 513, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 513, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 513, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 513, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_v_size); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, ((PyObject *)(&PyInt_Type))); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 513, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":514 + * else: + * array = np.empty(size, int) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * with lock, nogil: + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":515 + * array = np.empty(size, int) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":516 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a) + */ + /*with:*/ { + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 516, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_11 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_11)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_11); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_11) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_11); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 516, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else { + __pyx_t_6 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 516, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":517 + * array_data = PyArray_DATA(array) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, a) + * return array + */ + __pyx_t_12 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_12; __pyx_v_i++) { + + /* "mtrand.pyx":518 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, a) # <<<<<<<<<<<<<< + * return array + * + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, __pyx_v_a); + } + } + + /* "mtrand.pyx":516 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L30; + } + __pyx_L30:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_3) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__32, NULL); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L33; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L1_error; + __pyx_L33:; + } + + /* "mtrand.pyx":519 + * for i from 0 <= i < length: + * array_data[i] = func(state, a) + * return array # <<<<<<<<<<<<<< + * + * cdef object discd_array(rk_state *state, rk_discd func, object size, ndarray oa, + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + } + + /* "mtrand.pyx":501 + * return array + * + * cdef object discd_array_sc(rk_state *state, rk_discd func, object size, # <<<<<<<<<<<<<< + * double a, object lock): + * cdef long *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("mtrand.discd_array_sc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":521 + * return array + * + * cdef object discd_array(rk_state *state, rk_discd func, object size, ndarray oa, # <<<<<<<<<<<<<< + * object lock): + * cdef long *array_data + */ + +static PyObject *__pyx_f_6mtrand_discd_array(rk_state *__pyx_v_state, __pyx_t_6mtrand_rk_discd __pyx_v_func, PyObject *__pyx_v_size, PyArrayObject *__pyx_v_oa, PyObject *__pyx_v_lock) { + long *__pyx_v_array_data; + double *__pyx_v_oa_data; + PyArrayObject *arrayObject = 0; + npy_intp __pyx_v_length; + npy_intp __pyx_v_i; + PyArrayMultiIterObject *__pyx_v_multi = 0; + PyArrayIterObject *__pyx_v_itera = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + npy_intp __pyx_t_10; + int __pyx_t_11; + PyObject *__pyx_t_12 = NULL; + __Pyx_RefNannySetupContext("discd_array", 0); + + /* "mtrand.pyx":531 + * cdef flatiter itera + * + * if size is None: # <<<<<<<<<<<<<< + * array = PyArray_SimpleNew(PyArray_NDIM(oa), + * PyArray_DIMS(oa), NPY_LONG) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":532 + * + * if size is None: + * array = PyArray_SimpleNew(PyArray_NDIM(oa), # <<<<<<<<<<<<<< + * PyArray_DIMS(oa), NPY_LONG) + * length = PyArray_SIZE(array) + */ + __pyx_t_3 = PyArray_SimpleNew(PyArray_NDIM(__pyx_v_oa), PyArray_DIMS(__pyx_v_oa), NPY_LONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 532, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_4); + __pyx_t_4 = 0; + + /* "mtrand.pyx":534 + * array = PyArray_SimpleNew(PyArray_NDIM(oa), + * PyArray_DIMS(oa), NPY_LONG) + * length = PyArray_SIZE(array) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) + */ + __pyx_v_length = PyArray_SIZE(arrayObject); + + /* "mtrand.pyx":535 + * PyArray_DIMS(oa), NPY_LONG) + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * itera = PyArray_IterNew(oa) + * with lock, nogil: + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":536 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < length: + */ + __pyx_t_4 = PyArray_IterNew(((PyObject *)__pyx_v_oa)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 536, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_itera = ((PyArrayIterObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":537 + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + */ + /*with:*/ { + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 537, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 537, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 537, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 537, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + /*try:*/ { + { + (void)__pyx_t_7; (void)__pyx_t_8; (void)__pyx_t_9; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":538 + * itera = PyArray_IterNew(oa) + * with lock, nogil: + * for i from 0 <= i < length: # <<<<<<<<<<<<<< + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + * PyArray_ITER_NEXT(itera) + */ + __pyx_t_10 = __pyx_v_length; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_10; __pyx_v_i++) { + + /* "mtrand.pyx":539 + * with lock, nogil: + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) # <<<<<<<<<<<<<< + * PyArray_ITER_NEXT(itera) + * else: + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (((double *)PyArray_ITER_DATA(__pyx_v_itera))[0])); + + /* "mtrand.pyx":540 + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + * PyArray_ITER_NEXT(itera) # <<<<<<<<<<<<<< + * else: + * array = np.empty(size, int) + */ + PyArray_ITER_NEXT(__pyx_v_itera); + } + } + + /* "mtrand.pyx":537 + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_5) { + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__33, NULL); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 537, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L19; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L1_error; + __pyx_L19:; + } + + /* "mtrand.pyx":531 + * cdef flatiter itera + * + * if size is None: # <<<<<<<<<<<<<< + * array = PyArray_SimpleNew(PyArray_NDIM(oa), + * PyArray_DIMS(oa), NPY_LONG) + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":542 + * PyArray_ITER_NEXT(itera) + * else: + * array = np.empty(size, int) # <<<<<<<<<<<<<< + * array_data = PyArray_DATA(array) + * multi = PyArray_MultiIterNew(2, array, oa) + */ + /*else*/ { + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_empty); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_v_size, ((PyObject *)(&PyInt_Type))}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_12 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_12, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_12, 0+__pyx_t_11, __pyx_v_size); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_12, 1+__pyx_t_11, ((PyObject *)(&PyInt_Type))); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_12, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 542, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + arrayObject = ((PyArrayObject *)__pyx_t_6); + __pyx_t_6 = 0; + + /* "mtrand.pyx":543 + * else: + * array = np.empty(size, int) + * array_data = PyArray_DATA(array) # <<<<<<<<<<<<<< + * multi = PyArray_MultiIterNew(2, array, oa) + * if (multi.size != PyArray_SIZE(array)): + */ + __pyx_v_array_data = ((long *)PyArray_DATA(arrayObject)); + + /* "mtrand.pyx":544 + * array = np.empty(size, int) + * array_data = PyArray_DATA(array) + * multi = PyArray_MultiIterNew(2, array, oa) # <<<<<<<<<<<<<< + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") + */ + __pyx_t_6 = PyArray_MultiIterNew(2, ((void *)arrayObject), ((void *)__pyx_v_oa)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 544, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_3 = __pyx_t_6; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_v_multi = ((PyArrayMultiIterObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":545 + * array_data = PyArray_DATA(array) + * multi = PyArray_MultiIterNew(2, array, oa) + * if (multi.size != PyArray_SIZE(array)): # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: + */ + __pyx_t_2 = ((__pyx_v_multi->size != PyArray_SIZE(arrayObject)) != 0); + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":546 + * multi = PyArray_MultiIterNew(2, array, oa) + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < multi.size: + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__34, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 546, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 546, __pyx_L1_error) + + /* "mtrand.pyx":545 + * array_data = PyArray_DATA(array) + * multi = PyArray_MultiIterNew(2, array, oa) + * if (multi.size != PyArray_SIZE(array)): # <<<<<<<<<<<<<< + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: + */ + } + + /* "mtrand.pyx":547 + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) + */ + /*with:*/ { + __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 547, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_LookupSpecial(__pyx_v_lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 547, __pyx_L21_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_12 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_12)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_12); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (__pyx_t_12) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_12); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 547, __pyx_L21_error) + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 547, __pyx_L21_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + /*try:*/ { + { + (void)__pyx_t_9; (void)__pyx_t_8; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":548 + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: + * for i from 0 <= i < multi.size: # <<<<<<<<<<<<<< + * oa_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0]) + */ + __pyx_t_10 = __pyx_v_multi->size; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_10; __pyx_v_i++) { + + /* "mtrand.pyx":549 + * with lock, nogil: + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) # <<<<<<<<<<<<<< + * array_data[i] = func(state, oa_data[0]) + * PyArray_MultiIter_NEXTi(multi, 1) + */ + __pyx_v_oa_data = ((double *)PyArray_MultiIter_DATA(__pyx_v_multi, 1)); + + /* "mtrand.pyx":550 + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0]) # <<<<<<<<<<<<<< + * PyArray_MultiIter_NEXTi(multi, 1) + * return array + */ + (__pyx_v_array_data[__pyx_v_i]) = __pyx_v_func(__pyx_v_state, (__pyx_v_oa_data[0])); + + /* "mtrand.pyx":551 + * oa_data = PyArray_MultiIter_DATA(multi, 1) + * array_data[i] = func(state, oa_data[0]) + * PyArray_MultiIter_NEXTi(multi, 1) # <<<<<<<<<<<<<< + * return array + * + */ + PyArray_MultiIter_NEXTi(__pyx_v_multi, 1); + } + } + + /* "mtrand.pyx":547 + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L33; + } + __pyx_L33:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_5) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__35, NULL); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 547, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L24; + } + __pyx_L24:; + } + goto __pyx_L36; + __pyx_L21_error:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L1_error; + __pyx_L36:; + } + } + __pyx_L3:; + + /* "mtrand.pyx":552 + * array_data[i] = func(state, oa_data[0]) + * PyArray_MultiIter_NEXTi(multi, 1) + * return array # <<<<<<<<<<<<<< + * + * cdef double kahan_sum(double *darr, npy_intp n): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)arrayObject)); + __pyx_r = ((PyObject *)arrayObject); + goto __pyx_L0; + + /* "mtrand.pyx":521 + * return array + * + * cdef object discd_array(rk_state *state, rk_discd func, object size, ndarray oa, # <<<<<<<<<<<<<< + * object lock): + * cdef long *array_data + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_AddTraceback("mtrand.discd_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject); + __Pyx_XDECREF((PyObject *)__pyx_v_multi); + __Pyx_XDECREF((PyObject *)__pyx_v_itera); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":554 + * return array + * + * cdef double kahan_sum(double *darr, npy_intp n): # <<<<<<<<<<<<<< + * cdef double c, y, t, sum + * cdef npy_intp i + */ + +static double __pyx_f_6mtrand_kahan_sum(double *__pyx_v_darr, npy_intp __pyx_v_n) { + double __pyx_v_c; + double __pyx_v_y; + double __pyx_v_t; + double __pyx_v_sum; + npy_intp __pyx_v_i; + double __pyx_r; + __Pyx_RefNannyDeclarations + npy_intp __pyx_t_1; + __Pyx_RefNannySetupContext("kahan_sum", 0); + + /* "mtrand.pyx":557 + * cdef double c, y, t, sum + * cdef npy_intp i + * sum = darr[0] # <<<<<<<<<<<<<< + * c = 0.0 + * for i from 1 <= i < n: + */ + __pyx_v_sum = (__pyx_v_darr[0]); + + /* "mtrand.pyx":558 + * cdef npy_intp i + * sum = darr[0] + * c = 0.0 # <<<<<<<<<<<<<< + * for i from 1 <= i < n: + * y = darr[i] - c + */ + __pyx_v_c = 0.0; + + /* "mtrand.pyx":559 + * sum = darr[0] + * c = 0.0 + * for i from 1 <= i < n: # <<<<<<<<<<<<<< + * y = darr[i] - c + * t = sum + y + */ + __pyx_t_1 = __pyx_v_n; + for (__pyx_v_i = 1; __pyx_v_i < __pyx_t_1; __pyx_v_i++) { + + /* "mtrand.pyx":560 + * c = 0.0 + * for i from 1 <= i < n: + * y = darr[i] - c # <<<<<<<<<<<<<< + * t = sum + y + * c = (t-sum) - y + */ + __pyx_v_y = ((__pyx_v_darr[__pyx_v_i]) - __pyx_v_c); + + /* "mtrand.pyx":561 + * for i from 1 <= i < n: + * y = darr[i] - c + * t = sum + y # <<<<<<<<<<<<<< + * c = (t-sum) - y + * sum = t + */ + __pyx_v_t = (__pyx_v_sum + __pyx_v_y); + + /* "mtrand.pyx":562 + * y = darr[i] - c + * t = sum + y + * c = (t-sum) - y # <<<<<<<<<<<<<< + * sum = t + * return sum + */ + __pyx_v_c = ((__pyx_v_t - __pyx_v_sum) - __pyx_v_y); + + /* "mtrand.pyx":563 + * t = sum + y + * c = (t-sum) - y + * sum = t # <<<<<<<<<<<<<< + * return sum + * + */ + __pyx_v_sum = __pyx_v_t; + } + + /* "mtrand.pyx":564 + * c = (t-sum) - y + * sum = t + * return sum # <<<<<<<<<<<<<< + * + * def _shape_from_size(size, d): + */ + __pyx_r = __pyx_v_sum; + goto __pyx_L0; + + /* "mtrand.pyx":554 + * return array + * + * cdef double kahan_sum(double *darr, npy_intp n): # <<<<<<<<<<<<<< + * cdef double c, y, t, sum + * cdef npy_intp i + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":566 + * return sum + * + * def _shape_from_size(size, d): # <<<<<<<<<<<<<< + * if size is None: + * shape = (d,) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_19_shape_from_size(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_6mtrand_19_shape_from_size = {"_shape_from_size", (PyCFunction)__pyx_pw_6mtrand_19_shape_from_size, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_6mtrand_19_shape_from_size(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_d = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("_shape_from_size (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_size,&__pyx_n_s_d,0}; + PyObject* values[2] = {0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_d)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_shape_from_size", 1, 2, 2, 1); __PYX_ERR(0, 566, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_shape_from_size") < 0)) __PYX_ERR(0, 566, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + } + __pyx_v_size = values[0]; + __pyx_v_d = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_shape_from_size", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 566, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand._shape_from_size", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_18_shape_from_size(__pyx_self, __pyx_v_size, __pyx_v_d); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_18_shape_from_size(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_size, PyObject *__pyx_v_d) { + PyObject *__pyx_v_shape = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + __Pyx_RefNannySetupContext("_shape_from_size", 0); + + /* "mtrand.pyx":567 + * + * def _shape_from_size(size, d): + * if size is None: # <<<<<<<<<<<<<< + * shape = (d,) + * else: + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":568 + * def _shape_from_size(size, d): + * if size is None: + * shape = (d,) # <<<<<<<<<<<<<< + * else: + * try: + */ + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 568, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_d); + __Pyx_GIVEREF(__pyx_v_d); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_d); + __pyx_v_shape = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":567 + * + * def _shape_from_size(size, d): + * if size is None: # <<<<<<<<<<<<<< + * shape = (d,) + * else: + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":570 + * shape = (d,) + * else: + * try: # <<<<<<<<<<<<<< + * shape = (operator.index(size), d) + * except TypeError: + */ + /*else*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_4, &__pyx_t_5, &__pyx_t_6); + __Pyx_XGOTREF(__pyx_t_4); + __Pyx_XGOTREF(__pyx_t_5); + __Pyx_XGOTREF(__pyx_t_6); + /*try:*/ { + + /* "mtrand.pyx":571 + * else: + * try: + * shape = (operator.index(size), d) # <<<<<<<<<<<<<< + * except TypeError: + * shape = tuple(size) + (d,) + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_operator); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 571, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_index); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 571, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (!__pyx_t_7) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_v_size); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 571, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_v_size}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 571, __pyx_L4_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_v_size}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 571, __pyx_L4_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 571, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_size); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 571, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 571, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_3); + __Pyx_INCREF(__pyx_v_d); + __Pyx_GIVEREF(__pyx_v_d); + PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_v_d); + __pyx_t_3 = 0; + __pyx_v_shape = ((PyObject*)__pyx_t_8); + __pyx_t_8 = 0; + + /* "mtrand.pyx":570 + * shape = (d,) + * else: + * try: # <<<<<<<<<<<<<< + * shape = (operator.index(size), d) + * except TypeError: + */ + } + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + goto __pyx_L9_try_end; + __pyx_L4_error:; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + + /* "mtrand.pyx":572 + * try: + * shape = (operator.index(size), d) + * except TypeError: # <<<<<<<<<<<<<< + * shape = tuple(size) + (d,) + * return shape + */ + __pyx_t_10 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_TypeError); + if (__pyx_t_10) { + __Pyx_AddTraceback("mtrand._shape_from_size", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_8, &__pyx_t_3, &__pyx_t_9) < 0) __PYX_ERR(0, 572, __pyx_L6_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GOTREF(__pyx_t_9); + + /* "mtrand.pyx":573 + * shape = (operator.index(size), d) + * except TypeError: + * shape = tuple(size) + (d,) # <<<<<<<<<<<<<< + * return shape + * + */ + __pyx_t_7 = __Pyx_PySequence_Tuple(__pyx_v_size); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 573, __pyx_L6_except_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_11 = PyTuple_New(1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 573, __pyx_L6_except_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_INCREF(__pyx_v_d); + __Pyx_GIVEREF(__pyx_v_d); + PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_v_d); + __pyx_t_12 = PyNumber_Add(__pyx_t_7, __pyx_t_11); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 573, __pyx_L6_except_error) + __Pyx_GOTREF(__pyx_t_12); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_XDECREF_SET(__pyx_v_shape, ((PyObject*)__pyx_t_12)); + __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L5_exception_handled; + } + goto __pyx_L6_except_error; + __pyx_L6_except_error:; + + /* "mtrand.pyx":570 + * shape = (d,) + * else: + * try: # <<<<<<<<<<<<<< + * shape = (operator.index(size), d) + * except TypeError: + */ + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_5); + __Pyx_XGIVEREF(__pyx_t_6); + __Pyx_ExceptionReset(__pyx_t_4, __pyx_t_5, __pyx_t_6); + goto __pyx_L1_error; + __pyx_L5_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_5); + __Pyx_XGIVEREF(__pyx_t_6); + __Pyx_ExceptionReset(__pyx_t_4, __pyx_t_5, __pyx_t_6); + __pyx_L9_try_end:; + } + } + __pyx_L3:; + + /* "mtrand.pyx":574 + * except TypeError: + * shape = tuple(size) + (d,) + * return shape # <<<<<<<<<<<<<< + * + * # Look up table for randint functions keyed by type name. The stored data + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_shape); + __pyx_r = __pyx_v_shape; + goto __pyx_L0; + + /* "mtrand.pyx":566 + * return sum + * + * def _shape_from_size(size, d): # <<<<<<<<<<<<<< + * if size is None: + * shape = (d,) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_AddTraceback("mtrand._shape_from_size", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_shape); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":640 + * poisson_lam_max = np.iinfo('l').max - np.sqrt(np.iinfo('l').max)*10 + * + * def __init__(self, seed=None): # <<<<<<<<<<<<<< + * self.internal_state = PyMem_Malloc(sizeof(rk_state)) + * self.state_address = PyCapsule_New(self.internal_state, NULL, NULL) + */ + +/* Python wrapper */ +static int __pyx_pw_6mtrand_11RandomState_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6mtrand_11RandomState_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_seed = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_seed,0}; + PyObject* values[1] = {0}; + values[0] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_seed); + if (value) { values[0] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 640, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_seed = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 640, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState___init__(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_seed); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6mtrand_11RandomState___init__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_seed) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + __Pyx_RefNannySetupContext("__init__", 0); + + /* "mtrand.pyx":641 + * + * def __init__(self, seed=None): + * self.internal_state = PyMem_Malloc(sizeof(rk_state)) # <<<<<<<<<<<<<< + * self.state_address = PyCapsule_New(self.internal_state, NULL, NULL) + * self.lock = Lock() + */ + __pyx_v_self->internal_state = ((rk_state *)PyMem_Malloc((sizeof(rk_state)))); + + /* "mtrand.pyx":642 + * def __init__(self, seed=None): + * self.internal_state = PyMem_Malloc(sizeof(rk_state)) + * self.state_address = PyCapsule_New(self.internal_state, NULL, NULL) # <<<<<<<<<<<<<< + * self.lock = Lock() + * self.seed(seed) + */ + __pyx_t_1 = PyCapsule_New(__pyx_v_self->internal_state, NULL, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 642, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_v_self->state_address); + __Pyx_DECREF(__pyx_v_self->state_address); + __pyx_v_self->state_address = __pyx_t_1; + __pyx_t_1 = 0; + + /* "mtrand.pyx":643 + * self.internal_state = PyMem_Malloc(sizeof(rk_state)) + * self.state_address = PyCapsule_New(self.internal_state, NULL, NULL) + * self.lock = Lock() # <<<<<<<<<<<<<< + * self.seed(seed) + * + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_Lock); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 643, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (__pyx_t_3) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 643, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else { + __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 643, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_v_self->lock); + __Pyx_DECREF(__pyx_v_self->lock); + __pyx_v_self->lock = __pyx_t_1; + __pyx_t_1 = 0; + + /* "mtrand.pyx":644 + * self.state_address = PyCapsule_New(self.internal_state, NULL, NULL) + * self.lock = Lock() + * self.seed(seed) # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_seed); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_3) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_seed); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_seed}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_seed}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(__pyx_v_seed); + __Pyx_GIVEREF(__pyx_v_seed); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_seed); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":640 + * poisson_lam_max = np.iinfo('l').max - np.sqrt(np.iinfo('l').max)*10 + * + * def __init__(self, seed=None): # <<<<<<<<<<<<<< + * self.internal_state = PyMem_Malloc(sizeof(rk_state)) + * self.state_address = PyCapsule_New(self.internal_state, NULL, NULL) + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("mtrand.RandomState.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":646 + * self.seed(seed) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self.internal_state != NULL: + * PyMem_Free(self.internal_state) + */ + +/* Python wrapper */ +static void __pyx_pw_6mtrand_11RandomState_3__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_6mtrand_11RandomState_3__dealloc__(PyObject *__pyx_v_self) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_pf_6mtrand_11RandomState_2__dealloc__(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_6mtrand_11RandomState_2__dealloc__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self) { + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("__dealloc__", 0); + + /* "mtrand.pyx":647 + * + * def __dealloc__(self): + * if self.internal_state != NULL: # <<<<<<<<<<<<<< + * PyMem_Free(self.internal_state) + * self.internal_state = NULL + */ + __pyx_t_1 = ((__pyx_v_self->internal_state != NULL) != 0); + if (__pyx_t_1) { + + /* "mtrand.pyx":648 + * def __dealloc__(self): + * if self.internal_state != NULL: + * PyMem_Free(self.internal_state) # <<<<<<<<<<<<<< + * self.internal_state = NULL + * + */ + PyMem_Free(__pyx_v_self->internal_state); + + /* "mtrand.pyx":649 + * if self.internal_state != NULL: + * PyMem_Free(self.internal_state) + * self.internal_state = NULL # <<<<<<<<<<<<<< + * + * def seed(self, seed=None): + */ + __pyx_v_self->internal_state = NULL; + + /* "mtrand.pyx":647 + * + * def __dealloc__(self): + * if self.internal_state != NULL: # <<<<<<<<<<<<<< + * PyMem_Free(self.internal_state) + * self.internal_state = NULL + */ + } + + /* "mtrand.pyx":646 + * self.seed(seed) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self.internal_state != NULL: + * PyMem_Free(self.internal_state) + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "mtrand.pyx":651 + * self.internal_state = NULL + * + * def seed(self, seed=None): # <<<<<<<<<<<<<< + * """ + * seed(seed=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_5seed(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_4seed[] = "\n seed(seed=None)\n\n Seed the generator.\n\n This method is called when `RandomState` is initialized. It can be\n called again to re-seed the generator. For details, see `RandomState`.\n\n Parameters\n ----------\n seed : int or 1-d array_like, optional\n Seed for `RandomState`.\n Must be convertible to 32 bit unsigned integers.\n\n See Also\n --------\n RandomState\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_5seed(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_seed = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("seed (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_seed,0}; + PyObject* values[1] = {0}; + values[0] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_seed); + if (value) { values[0] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "seed") < 0)) __PYX_ERR(0, 651, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_seed = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("seed", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 651, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.seed", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_4seed(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_seed); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_4seed(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_seed) { + CYTHON_UNUSED rk_error __pyx_v_errcode; + PyArrayObject *arrayObject_obj = 0; + PyObject *__pyx_v_idx = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + unsigned long __pyx_t_14; + PyObject *__pyx_t_15 = NULL; + int __pyx_t_16; + PyObject *__pyx_t_17 = NULL; + PyObject *__pyx_t_18 = NULL; + PyObject *__pyx_t_19 = NULL; + __Pyx_RefNannySetupContext("seed", 0); + + /* "mtrand.pyx":673 + * cdef rk_error errcode + * cdef ndarray obj "arrayObject_obj" + * try: # <<<<<<<<<<<<<< + * if seed is None: + * with self.lock: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "mtrand.pyx":674 + * cdef ndarray obj "arrayObject_obj" + * try: + * if seed is None: # <<<<<<<<<<<<<< + * with self.lock: + * errcode = rk_randomseed(self.internal_state) + */ + __pyx_t_4 = (__pyx_v_seed == Py_None); + __pyx_t_5 = (__pyx_t_4 != 0); + if (__pyx_t_5) { + + /* "mtrand.pyx":675 + * try: + * if seed is None: + * with self.lock: # <<<<<<<<<<<<<< + * errcode = rk_randomseed(self.internal_state) + * else: + */ + /*with:*/ { + __pyx_t_6 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 675, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 675, __pyx_L10_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (__pyx_t_9) { + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_9); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 675, __pyx_L10_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else { + __pyx_t_7 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 675, __pyx_L10_error) + } + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + /*try:*/ { + { + (void)__pyx_t_10; (void)__pyx_t_11; (void)__pyx_t_12; /* mark used */ + /*try:*/ { + + /* "mtrand.pyx":676 + * if seed is None: + * with self.lock: + * errcode = rk_randomseed(self.internal_state) # <<<<<<<<<<<<<< + * else: + * idx = operator.index(seed) + */ + __pyx_v_errcode = rk_randomseed(__pyx_v_self->internal_state); + + /* "mtrand.pyx":675 + * try: + * if seed is None: + * with self.lock: # <<<<<<<<<<<<<< + * errcode = rk_randomseed(self.internal_state) + * else: + */ + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_6) { + __pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_tuple__36, NULL); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 675, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_12); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + goto __pyx_L13; + } + __pyx_L13:; + } + goto __pyx_L20; + __pyx_L10_error:; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + goto __pyx_L3_error; + __pyx_L20:; + } + + /* "mtrand.pyx":674 + * cdef ndarray obj "arrayObject_obj" + * try: + * if seed is None: # <<<<<<<<<<<<<< + * with self.lock: + * errcode = rk_randomseed(self.internal_state) + */ + goto __pyx_L9; + } + + /* "mtrand.pyx":678 + * errcode = rk_randomseed(self.internal_state) + * else: + * idx = operator.index(seed) # <<<<<<<<<<<<<< + * if (idx >= 2**32) or (idx < 0): + * raise ValueError("Seed must be between 0 and 2**32 - 1") + */ + /*else*/ { + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_operator); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 678, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_index); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 678, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_8) { + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_v_seed); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 678, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_7); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_v_seed}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 678, __pyx_L3_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_v_seed}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 678, __pyx_L3_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else + #endif + { + __pyx_t_13 = PyTuple_New(1+1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 678, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_8); __pyx_t_8 = NULL; + __Pyx_INCREF(__pyx_v_seed); + __Pyx_GIVEREF(__pyx_v_seed); + PyTuple_SET_ITEM(__pyx_t_13, 0+1, __pyx_v_seed); + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_13, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 678, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_v_idx = __pyx_t_7; + __pyx_t_7 = 0; + + /* "mtrand.pyx":679 + * else: + * idx = operator.index(seed) + * if (idx >= 2**32) or (idx < 0): # <<<<<<<<<<<<<< + * raise ValueError("Seed must be between 0 and 2**32 - 1") + * with self.lock: + */ + __pyx_t_7 = PyObject_RichCompare(__pyx_v_idx, __pyx_int_4294967296, Py_GE); __Pyx_XGOTREF(__pyx_t_7); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 679, __pyx_L3_error) + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_7); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 679, __pyx_L3_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (!__pyx_t_4) { + } else { + __pyx_t_5 = __pyx_t_4; + goto __pyx_L22_bool_binop_done; + } + __pyx_t_7 = PyObject_RichCompare(__pyx_v_idx, __pyx_int_0, Py_LT); __Pyx_XGOTREF(__pyx_t_7); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 679, __pyx_L3_error) + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_7); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 679, __pyx_L3_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_5 = __pyx_t_4; + __pyx_L22_bool_binop_done:; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":680 + * idx = operator.index(seed) + * if (idx >= 2**32) or (idx < 0): + * raise ValueError("Seed must be between 0 and 2**32 - 1") # <<<<<<<<<<<<<< + * with self.lock: + * rk_seed(idx, self.internal_state) + */ + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__37, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 680, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_Raise(__pyx_t_7, 0, 0, 0); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __PYX_ERR(0, 680, __pyx_L3_error) + + /* "mtrand.pyx":679 + * else: + * idx = operator.index(seed) + * if (idx >= 2**32) or (idx < 0): # <<<<<<<<<<<<<< + * raise ValueError("Seed must be between 0 and 2**32 - 1") + * with self.lock: + */ + } + + /* "mtrand.pyx":681 + * if (idx >= 2**32) or (idx < 0): + * raise ValueError("Seed must be between 0 and 2**32 - 1") + * with self.lock: # <<<<<<<<<<<<<< + * rk_seed(idx, self.internal_state) + * except TypeError: + */ + /*with:*/ { + __pyx_t_6 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 681, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_9 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 681, __pyx_L24_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_13 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_13 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_13)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_13); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (__pyx_t_13) { + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_13); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 681, __pyx_L24_error) + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } else { + __pyx_t_7 = __Pyx_PyObject_CallNoArg(__pyx_t_9); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 681, __pyx_L24_error) + } + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + /*try:*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_12, &__pyx_t_11, &__pyx_t_10); + __Pyx_XGOTREF(__pyx_t_12); + __Pyx_XGOTREF(__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_10); + /*try:*/ { + + /* "mtrand.pyx":682 + * raise ValueError("Seed must be between 0 and 2**32 - 1") + * with self.lock: + * rk_seed(idx, self.internal_state) # <<<<<<<<<<<<<< + * except TypeError: + * obj = np.asarray(seed) + */ + __pyx_t_14 = __Pyx_PyInt_As_unsigned_long(__pyx_v_idx); if (unlikely((__pyx_t_14 == (unsigned long)-1) && PyErr_Occurred())) __PYX_ERR(0, 682, __pyx_L28_error) + rk_seed(__pyx_t_14, __pyx_v_self->internal_state); + + /* "mtrand.pyx":681 + * if (idx >= 2**32) or (idx < 0): + * raise ValueError("Seed must be between 0 and 2**32 - 1") + * with self.lock: # <<<<<<<<<<<<<< + * rk_seed(idx, self.internal_state) + * except TypeError: + */ + } + __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + goto __pyx_L33_try_end; + __pyx_L28_error:; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + /*except:*/ { + __Pyx_AddTraceback("mtrand.RandomState.seed", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_7, &__pyx_t_9, &__pyx_t_13) < 0) __PYX_ERR(0, 681, __pyx_L30_except_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_8 = PyTuple_Pack(3, __pyx_t_7, __pyx_t_9, __pyx_t_13); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 681, __pyx_L30_except_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 681, __pyx_L30_except_error) + __Pyx_GOTREF(__pyx_t_15); + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_15); + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + if (__pyx_t_5 < 0) __PYX_ERR(0, 681, __pyx_L30_except_error) + __pyx_t_4 = ((!(__pyx_t_5 != 0)) != 0); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_9); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_ErrRestoreWithState(__pyx_t_7, __pyx_t_9, __pyx_t_13); + __pyx_t_7 = 0; __pyx_t_9 = 0; __pyx_t_13 = 0; + __PYX_ERR(0, 681, __pyx_L30_except_error) + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + goto __pyx_L29_exception_handled; + } + __pyx_L30_except_error:; + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_ExceptionReset(__pyx_t_12, __pyx_t_11, __pyx_t_10); + goto __pyx_L3_error; + __pyx_L29_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_ExceptionReset(__pyx_t_12, __pyx_t_11, __pyx_t_10); + __pyx_L33_try_end:; + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_6) { + __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_tuple__38, NULL); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 681, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + goto __pyx_L27; + } + __pyx_L27:; + } + goto __pyx_L37; + __pyx_L24_error:; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + goto __pyx_L3_error; + __pyx_L37:; + } + } + __pyx_L9:; + + /* "mtrand.pyx":673 + * cdef rk_error errcode + * cdef ndarray obj "arrayObject_obj" + * try: # <<<<<<<<<<<<<< + * if seed is None: + * with self.lock: + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L8_try_end; + __pyx_L3_error:; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + + /* "mtrand.pyx":683 + * with self.lock: + * rk_seed(idx, self.internal_state) + * except TypeError: # <<<<<<<<<<<<<< + * obj = np.asarray(seed) + * if obj.size == 0: + */ + __pyx_t_16 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_TypeError); + if (__pyx_t_16) { + __Pyx_AddTraceback("mtrand.RandomState.seed", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_13, &__pyx_t_9, &__pyx_t_7) < 0) __PYX_ERR(0, 683, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GOTREF(__pyx_t_7); + + /* "mtrand.pyx":684 + * rk_seed(idx, self.internal_state) + * except TypeError: + * obj = np.asarray(seed) # <<<<<<<<<<<<<< + * if obj.size == 0: + * raise ValueError("Seed must be non-empty") + */ + __pyx_t_17 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 684, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_17); + __pyx_t_18 = __Pyx_PyObject_GetAttrStr(__pyx_t_17, __pyx_n_s_asarray); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 684, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_18); + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + __pyx_t_17 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_18))) { + __pyx_t_17 = PyMethod_GET_SELF(__pyx_t_18); + if (likely(__pyx_t_17)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_18); + __Pyx_INCREF(__pyx_t_17); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_18, function); + } + } + if (!__pyx_t_17) { + __pyx_t_8 = __Pyx_PyObject_CallOneArg(__pyx_t_18, __pyx_v_seed); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 684, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_18)) { + PyObject *__pyx_temp[2] = {__pyx_t_17, __pyx_v_seed}; + __pyx_t_8 = __Pyx_PyFunction_FastCall(__pyx_t_18, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 684, __pyx_L5_except_error) + __Pyx_XDECREF(__pyx_t_17); __pyx_t_17 = 0; + __Pyx_GOTREF(__pyx_t_8); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_18)) { + PyObject *__pyx_temp[2] = {__pyx_t_17, __pyx_v_seed}; + __pyx_t_8 = __Pyx_PyCFunction_FastCall(__pyx_t_18, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 684, __pyx_L5_except_error) + __Pyx_XDECREF(__pyx_t_17); __pyx_t_17 = 0; + __Pyx_GOTREF(__pyx_t_8); + } else + #endif + { + __pyx_t_19 = PyTuple_New(1+1); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 684, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_19); + __Pyx_GIVEREF(__pyx_t_17); PyTuple_SET_ITEM(__pyx_t_19, 0, __pyx_t_17); __pyx_t_17 = NULL; + __Pyx_INCREF(__pyx_v_seed); + __Pyx_GIVEREF(__pyx_v_seed); + PyTuple_SET_ITEM(__pyx_t_19, 0+1, __pyx_v_seed); + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_18, __pyx_t_19, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 684, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + } + } + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + if (!(likely(((__pyx_t_8) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_8, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 684, __pyx_L5_except_error) + arrayObject_obj = ((PyArrayObject *)__pyx_t_8); + __pyx_t_8 = 0; + + /* "mtrand.pyx":685 + * except TypeError: + * obj = np.asarray(seed) + * if obj.size == 0: # <<<<<<<<<<<<<< + * raise ValueError("Seed must be non-empty") + * obj = obj.astype(np.int64, casting='safe') + */ + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject_obj), __pyx_n_s_size); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 685, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_18 = __Pyx_PyInt_EqObjC(__pyx_t_8, __pyx_int_0, 0, 0); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 685, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_18); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_18); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 685, __pyx_L5_except_error) + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":686 + * obj = np.asarray(seed) + * if obj.size == 0: + * raise ValueError("Seed must be non-empty") # <<<<<<<<<<<<<< + * obj = obj.astype(np.int64, casting='safe') + * if obj.ndim != 1: + */ + __pyx_t_18 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__39, NULL); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 686, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_18); + __Pyx_Raise(__pyx_t_18, 0, 0, 0); + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + __PYX_ERR(0, 686, __pyx_L5_except_error) + + /* "mtrand.pyx":685 + * except TypeError: + * obj = np.asarray(seed) + * if obj.size == 0: # <<<<<<<<<<<<<< + * raise ValueError("Seed must be non-empty") + * obj = obj.astype(np.int64, casting='safe') + */ + } + + /* "mtrand.pyx":687 + * if obj.size == 0: + * raise ValueError("Seed must be non-empty") + * obj = obj.astype(np.int64, casting='safe') # <<<<<<<<<<<<<< + * if obj.ndim != 1: + * raise ValueError("Seed array must be 1-d") + */ + __pyx_t_18 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject_obj), __pyx_n_s_astype); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 687, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_18); + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 687, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_19 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_int64); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 687, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_19); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = PyTuple_New(1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 687, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_19); + PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_19); + __pyx_t_19 = 0; + __pyx_t_19 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 687, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_19); + if (PyDict_SetItem(__pyx_t_19, __pyx_n_s_casting, __pyx_n_s_safe) < 0) __PYX_ERR(0, 687, __pyx_L5_except_error) + __pyx_t_17 = __Pyx_PyObject_Call(__pyx_t_18, __pyx_t_8, __pyx_t_19); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 687, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_17); + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + if (!(likely(((__pyx_t_17) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_17, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 687, __pyx_L5_except_error) + __Pyx_DECREF_SET(arrayObject_obj, ((PyArrayObject *)__pyx_t_17)); + __pyx_t_17 = 0; + + /* "mtrand.pyx":688 + * raise ValueError("Seed must be non-empty") + * obj = obj.astype(np.int64, casting='safe') + * if obj.ndim != 1: # <<<<<<<<<<<<<< + * raise ValueError("Seed array must be 1-d") + * if ((obj >= 2**32) | (obj < 0)).any(): + */ + __pyx_t_17 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject_obj), __pyx_n_s_ndim); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 688, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_17); + __pyx_t_19 = PyObject_RichCompare(__pyx_t_17, __pyx_int_1, Py_NE); __Pyx_XGOTREF(__pyx_t_19); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 688, __pyx_L5_except_error) + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_19); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 688, __pyx_L5_except_error) + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":689 + * obj = obj.astype(np.int64, casting='safe') + * if obj.ndim != 1: + * raise ValueError("Seed array must be 1-d") # <<<<<<<<<<<<<< + * if ((obj >= 2**32) | (obj < 0)).any(): + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + */ + __pyx_t_19 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__40, NULL); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 689, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_19); + __Pyx_Raise(__pyx_t_19, 0, 0, 0); + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + __PYX_ERR(0, 689, __pyx_L5_except_error) + + /* "mtrand.pyx":688 + * raise ValueError("Seed must be non-empty") + * obj = obj.astype(np.int64, casting='safe') + * if obj.ndim != 1: # <<<<<<<<<<<<<< + * raise ValueError("Seed array must be 1-d") + * if ((obj >= 2**32) | (obj < 0)).any(): + */ + } + + /* "mtrand.pyx":690 + * if obj.ndim != 1: + * raise ValueError("Seed array must be 1-d") + * if ((obj >= 2**32) | (obj < 0)).any(): # <<<<<<<<<<<<<< + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + * obj = obj.astype('L', casting='unsafe') + */ + __pyx_t_17 = PyObject_RichCompare(((PyObject *)arrayObject_obj), __pyx_int_4294967296, Py_GE); __Pyx_XGOTREF(__pyx_t_17); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 690, __pyx_L5_except_error) + __pyx_t_8 = PyObject_RichCompare(((PyObject *)arrayObject_obj), __pyx_int_0, Py_LT); __Pyx_XGOTREF(__pyx_t_8); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 690, __pyx_L5_except_error) + __pyx_t_18 = PyNumber_Or(__pyx_t_17, __pyx_t_8); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 690, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_18); + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_18, __pyx_n_s_any); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 690, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + __pyx_t_18 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_18 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_18)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_18); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (__pyx_t_18) { + __pyx_t_19 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_18); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 690, __pyx_L5_except_error) + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + } else { + __pyx_t_19 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 690, __pyx_L5_except_error) + } + __Pyx_GOTREF(__pyx_t_19); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_19); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 690, __pyx_L5_except_error) + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":691 + * raise ValueError("Seed array must be 1-d") + * if ((obj >= 2**32) | (obj < 0)).any(): + * raise ValueError("Seed values must be between 0 and 2**32 - 1") # <<<<<<<<<<<<<< + * obj = obj.astype('L', casting='unsafe') + * with self.lock: + */ + __pyx_t_19 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__41, NULL); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 691, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_19); + __Pyx_Raise(__pyx_t_19, 0, 0, 0); + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + __PYX_ERR(0, 691, __pyx_L5_except_error) + + /* "mtrand.pyx":690 + * if obj.ndim != 1: + * raise ValueError("Seed array must be 1-d") + * if ((obj >= 2**32) | (obj < 0)).any(): # <<<<<<<<<<<<<< + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + * obj = obj.astype('L', casting='unsafe') + */ + } + + /* "mtrand.pyx":692 + * if ((obj >= 2**32) | (obj < 0)).any(): + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + * obj = obj.astype('L', casting='unsafe') # <<<<<<<<<<<<<< + * with self.lock: + * init_by_array(self.internal_state, PyArray_DATA(obj), + */ + __pyx_t_19 = __Pyx_PyObject_GetAttrStr(((PyObject *)arrayObject_obj), __pyx_n_s_astype); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 692, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_19); + __pyx_t_8 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 692, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + if (PyDict_SetItem(__pyx_t_8, __pyx_n_s_casting, __pyx_n_s_unsafe) < 0) __PYX_ERR(0, 692, __pyx_L5_except_error) + __pyx_t_18 = __Pyx_PyObject_Call(__pyx_t_19, __pyx_tuple__42, __pyx_t_8); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 692, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_18); + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (!(likely(((__pyx_t_18) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_18, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 692, __pyx_L5_except_error) + __Pyx_DECREF_SET(arrayObject_obj, ((PyArrayObject *)__pyx_t_18)); + __pyx_t_18 = 0; + + /* "mtrand.pyx":693 + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + * obj = obj.astype('L', casting='unsafe') + * with self.lock: # <<<<<<<<<<<<<< + * init_by_array(self.internal_state, PyArray_DATA(obj), + * PyArray_DIM(obj, 0)) + */ + /*with:*/ { + __pyx_t_6 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 693, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 693, __pyx_L43_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_19 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_19 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_19)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_19); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (__pyx_t_19) { + __pyx_t_18 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_19); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 693, __pyx_L43_error) + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + } else { + __pyx_t_18 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 693, __pyx_L43_error) + } + __Pyx_GOTREF(__pyx_t_18); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + /*try:*/ { + { + (void)__pyx_t_10; (void)__pyx_t_11; (void)__pyx_t_12; /* mark used */ + /*try:*/ { + + /* "mtrand.pyx":694 + * obj = obj.astype('L', casting='unsafe') + * with self.lock: + * init_by_array(self.internal_state, PyArray_DATA(obj), # <<<<<<<<<<<<<< + * PyArray_DIM(obj, 0)) + * + */ + init_by_array(__pyx_v_self->internal_state, ((unsigned long *)PyArray_DATA(arrayObject_obj)), PyArray_DIM(arrayObject_obj, 0)); + + /* "mtrand.pyx":693 + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + * obj = obj.astype('L', casting='unsafe') + * with self.lock: # <<<<<<<<<<<<<< + * init_by_array(self.internal_state, PyArray_DATA(obj), + * PyArray_DIM(obj, 0)) + */ + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_6) { + __pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_tuple__43, NULL); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 693, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_12); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + goto __pyx_L48; + } + __pyx_L48:; + } + goto __pyx_L57; + __pyx_L43_error:; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + goto __pyx_L5_except_error; + __pyx_L57:; + } + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + goto __pyx_L4_exception_handled; + } + goto __pyx_L5_except_error; + __pyx_L5_except_error:; + + /* "mtrand.pyx":673 + * cdef rk_error errcode + * cdef ndarray obj "arrayObject_obj" + * try: # <<<<<<<<<<<<<< + * if seed is None: + * with self.lock: + */ + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L1_error; + __pyx_L4_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + __pyx_L8_try_end:; + } + + /* "mtrand.pyx":651 + * self.internal_state = NULL + * + * def seed(self, seed=None): # <<<<<<<<<<<<<< + * """ + * seed(seed=None) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_13); + __Pyx_XDECREF(__pyx_t_17); + __Pyx_XDECREF(__pyx_t_18); + __Pyx_XDECREF(__pyx_t_19); + __Pyx_AddTraceback("mtrand.RandomState.seed", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject_obj); + __Pyx_XDECREF(__pyx_v_idx); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":697 + * PyArray_DIM(obj, 0)) + * + * def get_state(self): # <<<<<<<<<<<<<< + * """ + * get_state() + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_7get_state(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_6get_state[] = "\n get_state()\n\n Return a tuple representing the internal state of the generator.\n\n For more details, see `set_state`.\n\n Returns\n -------\n out : tuple(str, ndarray of 624 uints, int, int, float)\n The returned tuple has the following items:\n\n 1. the string 'MT19937'.\n 2. a 1-D array of 624 unsigned integer keys.\n 3. an integer ``pos``.\n 4. an integer ``has_gauss``.\n 5. a float ``cached_gaussian``.\n\n See Also\n --------\n set_state\n\n Notes\n -----\n `set_state` and `get_state` are not needed to work with any of the\n random distributions in NumPy. If the internal state is manually altered,\n the user should know exactly what he/she is doing.\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_7get_state(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_state (wrapper)", 0); + __pyx_r = __pyx_pf_6mtrand_11RandomState_6get_state(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_6get_state(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self) { + PyArrayObject *arrayObject_state = 0; + int __pyx_v_has_gauss; + double __pyx_v_gauss; + int __pyx_v_pos; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + double __pyx_t_11; + __Pyx_RefNannySetupContext("get_state", 0); + + /* "mtrand.pyx":728 + * """ + * cdef ndarray state "arrayObject_state" + * state = np.empty(624, np.uint) # <<<<<<<<<<<<<< + * with self.lock: + * memcpy(PyArray_DATA(state), (self.internal_state.key), 624*sizeof(long)) + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 728, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 728, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 728, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_uint); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 728, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_5 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_5 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_int_624, __pyx_t_4}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_5, 2+__pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 728, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_int_624, __pyx_t_4}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_5, 2+__pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 728, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_5); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 728, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(__pyx_int_624); + __Pyx_GIVEREF(__pyx_int_624); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_5, __pyx_int_624); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_5, __pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 728, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + arrayObject_state = ((PyArrayObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":729 + * cdef ndarray state "arrayObject_state" + * state = np.empty(624, np.uint) + * with self.lock: # <<<<<<<<<<<<<< + * memcpy(PyArray_DATA(state), (self.internal_state.key), 624*sizeof(long)) + * has_gauss = self.internal_state.has_gauss + */ + /*with:*/ { + __pyx_t_7 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 729, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 729, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 729, __pyx_L3_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 729, __pyx_L3_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + /*try:*/ { + { + (void)__pyx_t_8; (void)__pyx_t_9; (void)__pyx_t_10; /* mark used */ + /*try:*/ { + + /* "mtrand.pyx":730 + * state = np.empty(624, np.uint) + * with self.lock: + * memcpy(PyArray_DATA(state), (self.internal_state.key), 624*sizeof(long)) # <<<<<<<<<<<<<< + * has_gauss = self.internal_state.has_gauss + * gauss = self.internal_state.gauss + */ + (void)(memcpy(((void *)PyArray_DATA(arrayObject_state)), ((void *)__pyx_v_self->internal_state->key), (0x270 * (sizeof(long))))); + + /* "mtrand.pyx":731 + * with self.lock: + * memcpy(PyArray_DATA(state), (self.internal_state.key), 624*sizeof(long)) + * has_gauss = self.internal_state.has_gauss # <<<<<<<<<<<<<< + * gauss = self.internal_state.gauss + * pos = self.internal_state.pos + */ + __pyx_t_5 = __pyx_v_self->internal_state->has_gauss; + __pyx_v_has_gauss = __pyx_t_5; + + /* "mtrand.pyx":732 + * memcpy(PyArray_DATA(state), (self.internal_state.key), 624*sizeof(long)) + * has_gauss = self.internal_state.has_gauss + * gauss = self.internal_state.gauss # <<<<<<<<<<<<<< + * pos = self.internal_state.pos + * state = np.asarray(state, np.uint32) + */ + __pyx_t_11 = __pyx_v_self->internal_state->gauss; + __pyx_v_gauss = __pyx_t_11; + + /* "mtrand.pyx":733 + * has_gauss = self.internal_state.has_gauss + * gauss = self.internal_state.gauss + * pos = self.internal_state.pos # <<<<<<<<<<<<<< + * state = np.asarray(state, np.uint32) + * return ('MT19937', state, pos, has_gauss, gauss) + */ + __pyx_t_5 = __pyx_v_self->internal_state->pos; + __pyx_v_pos = __pyx_t_5; + + /* "mtrand.pyx":729 + * cdef ndarray state "arrayObject_state" + * state = np.empty(624, np.uint) + * with self.lock: # <<<<<<<<<<<<<< + * memcpy(PyArray_DATA(state), (self.internal_state.key), 624*sizeof(long)) + * has_gauss = self.internal_state.has_gauss + */ + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_7) { + __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_tuple__44, NULL); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 729, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + goto __pyx_L6; + } + __pyx_L6:; + } + goto __pyx_L13; + __pyx_L3_error:; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + goto __pyx_L1_error; + __pyx_L13:; + } + + /* "mtrand.pyx":734 + * gauss = self.internal_state.gauss + * pos = self.internal_state.pos + * state = np.asarray(state, np.uint32) # <<<<<<<<<<<<<< + * return ('MT19937', state, pos, has_gauss, gauss) + * + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 734, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_asarray); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 734, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 734, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_uint32); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 734, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + __pyx_t_5 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_5 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_1, ((PyObject *)arrayObject_state), __pyx_t_4}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_5, 2+__pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 734, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_1, ((PyObject *)arrayObject_state), __pyx_t_4}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_5, 2+__pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 734, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + { + __pyx_t_2 = PyTuple_New(2+__pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 734, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (__pyx_t_1) { + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1); __pyx_t_1 = NULL; + } + __Pyx_INCREF(((PyObject *)arrayObject_state)); + __Pyx_GIVEREF(((PyObject *)arrayObject_state)); + PyTuple_SET_ITEM(__pyx_t_2, 0+__pyx_t_5, ((PyObject *)arrayObject_state)); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_2, 1+__pyx_t_5, __pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_2, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 734, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF_SET(arrayObject_state, ((PyArrayObject *)__pyx_t_6)); + __pyx_t_6 = 0; + + /* "mtrand.pyx":735 + * pos = self.internal_state.pos + * state = np.asarray(state, np.uint32) + * return ('MT19937', state, pos, has_gauss, gauss) # <<<<<<<<<<<<<< + * + * def set_state(self, state): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_6 = __Pyx_PyInt_From_int(__pyx_v_pos); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 735, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_has_gauss); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 735, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_gauss); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 735, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = PyTuple_New(5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 735, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_n_s_MT19937); + __Pyx_GIVEREF(__pyx_n_s_MT19937); + PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_n_s_MT19937); + __Pyx_INCREF(((PyObject *)arrayObject_state)); + __Pyx_GIVEREF(((PyObject *)arrayObject_state)); + PyTuple_SET_ITEM(__pyx_t_4, 1, ((PyObject *)arrayObject_state)); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_4, 3, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_4, 4, __pyx_t_2); + __pyx_t_6 = 0; + __pyx_t_3 = 0; + __pyx_t_2 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":697 + * PyArray_DIM(obj, 0)) + * + * def get_state(self): # <<<<<<<<<<<<<< + * """ + * get_state() + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("mtrand.RandomState.get_state", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject_state); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":737 + * return ('MT19937', state, pos, has_gauss, gauss) + * + * def set_state(self, state): # <<<<<<<<<<<<<< + * """ + * set_state(state) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_9set_state(PyObject *__pyx_v_self, PyObject *__pyx_v_state); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_8set_state[] = "\n set_state(state)\n\n Set the internal state of the generator from a tuple.\n\n For use if one has reason to manually (re-)set the internal state of the\n \"Mersenne Twister\"[1]_ pseudo-random number generating algorithm.\n\n Parameters\n ----------\n state : tuple(str, ndarray of 624 uints, int, int, float)\n The `state` tuple has the following items:\n\n 1. the string 'MT19937', specifying the Mersenne Twister algorithm.\n 2. a 1-D array of 624 unsigned integers ``keys``.\n 3. an integer ``pos``.\n 4. an integer ``has_gauss``.\n 5. a float ``cached_gaussian``.\n\n Returns\n -------\n out : None\n Returns 'None' on success.\n\n See Also\n --------\n get_state\n\n Notes\n -----\n `set_state` and `get_state` are not needed to work with any of the\n random distributions in NumPy. If the internal state is manually altered,\n the user should know exactly what he/she is doing.\n\n For backwards compatibility, the form (str, array of 624 uints, int) is\n also accepted although it is missing some information about the cached\n Gaussian value: ``state = ('MT19937', keys, pos)``.\n\n References\n ----------\n .. [1] M. Matsumoto and T. Nishimura, \"Mersenne Twister: A\n 623-dimensionally equidistributed uniform pseudorandom number\n generator,\" *ACM Trans. on Modeling and Computer Simulation*,\n Vol. 8, No. 1, pp. 3-30, Jan. 1998.\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_9set_state(PyObject *__pyx_v_self, PyObject *__pyx_v_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("set_state (wrapper)", 0); + __pyx_r = __pyx_pf_6mtrand_11RandomState_8set_state(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), ((PyObject *)__pyx_v_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_8set_state(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_state) { + PyArrayObject *arrayObject_obj = 0; + int __pyx_v_pos; + PyObject *__pyx_v_algorithm_name = NULL; + PyObject *__pyx_v_key = NULL; + PyObject *__pyx_v_has_gauss = NULL; + PyObject *__pyx_v_cached_gaussian = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *(*__pyx_t_6)(PyObject *); + int __pyx_t_7; + Py_ssize_t __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + double __pyx_t_14; + PyObject *__pyx_t_15 = NULL; + int __pyx_t_16; + __Pyx_RefNannySetupContext("set_state", 0); + + /* "mtrand.pyx":786 + * cdef ndarray obj "arrayObject_obj" + * cdef int pos + * algorithm_name = state[0] # <<<<<<<<<<<<<< + * if algorithm_name != 'MT19937': + * raise ValueError("algorithm must be 'MT19937'") + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_state, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 786, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_algorithm_name = __pyx_t_1; + __pyx_t_1 = 0; + + /* "mtrand.pyx":787 + * cdef int pos + * algorithm_name = state[0] + * if algorithm_name != 'MT19937': # <<<<<<<<<<<<<< + * raise ValueError("algorithm must be 'MT19937'") + * key, pos = state[1:3] + */ + __pyx_t_2 = (__Pyx_PyString_Equals(__pyx_v_algorithm_name, __pyx_n_s_MT19937, Py_NE)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 787, __pyx_L1_error) + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":788 + * algorithm_name = state[0] + * if algorithm_name != 'MT19937': + * raise ValueError("algorithm must be 'MT19937'") # <<<<<<<<<<<<<< + * key, pos = state[1:3] + * if len(state) == 3: + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__45, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 788, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 788, __pyx_L1_error) + + /* "mtrand.pyx":787 + * cdef int pos + * algorithm_name = state[0] + * if algorithm_name != 'MT19937': # <<<<<<<<<<<<<< + * raise ValueError("algorithm must be 'MT19937'") + * key, pos = state[1:3] + */ + } + + /* "mtrand.pyx":789 + * if algorithm_name != 'MT19937': + * raise ValueError("algorithm must be 'MT19937'") + * key, pos = state[1:3] # <<<<<<<<<<<<<< + * if len(state) == 3: + * has_gauss = 0 + */ + __pyx_t_1 = __Pyx_PyObject_GetSlice(__pyx_v_state, 1, 3, NULL, NULL, &__pyx_slice__46, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 789, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { + PyObject* sequence = __pyx_t_1; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 789, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_3 = PyList_GET_ITEM(sequence, 0); + __pyx_t_4 = PyList_GET_ITEM(sequence, 1); + } + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + #else + __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 789, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 789, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 789, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = Py_TYPE(__pyx_t_5)->tp_iternext; + index = 0; __pyx_t_3 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_3)) goto __pyx_L4_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + index = 1; __pyx_t_4 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_4)) goto __pyx_L4_unpacking_failed; + __Pyx_GOTREF(__pyx_t_4); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_6(__pyx_t_5), 2) < 0) __PYX_ERR(0, 789, __pyx_L1_error) + __pyx_t_6 = NULL; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L5_unpacking_done; + __pyx_L4_unpacking_failed:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 789, __pyx_L1_error) + __pyx_L5_unpacking_done:; + } + __pyx_t_7 = __Pyx_PyInt_As_int(__pyx_t_4); if (unlikely((__pyx_t_7 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 789, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_key = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_v_pos = __pyx_t_7; + + /* "mtrand.pyx":790 + * raise ValueError("algorithm must be 'MT19937'") + * key, pos = state[1:3] + * if len(state) == 3: # <<<<<<<<<<<<<< + * has_gauss = 0 + * cached_gaussian = 0.0 + */ + __pyx_t_8 = PyObject_Length(__pyx_v_state); if (unlikely(__pyx_t_8 == ((Py_ssize_t)-1))) __PYX_ERR(0, 790, __pyx_L1_error) + __pyx_t_2 = ((__pyx_t_8 == 3) != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":791 + * key, pos = state[1:3] + * if len(state) == 3: + * has_gauss = 0 # <<<<<<<<<<<<<< + * cached_gaussian = 0.0 + * else: + */ + __Pyx_INCREF(__pyx_int_0); + __pyx_v_has_gauss = __pyx_int_0; + + /* "mtrand.pyx":792 + * if len(state) == 3: + * has_gauss = 0 + * cached_gaussian = 0.0 # <<<<<<<<<<<<<< + * else: + * has_gauss, cached_gaussian = state[3:5] + */ + __Pyx_INCREF(__pyx_float_0_0); + __pyx_v_cached_gaussian = __pyx_float_0_0; + + /* "mtrand.pyx":790 + * raise ValueError("algorithm must be 'MT19937'") + * key, pos = state[1:3] + * if len(state) == 3: # <<<<<<<<<<<<<< + * has_gauss = 0 + * cached_gaussian = 0.0 + */ + goto __pyx_L6; + } + + /* "mtrand.pyx":794 + * cached_gaussian = 0.0 + * else: + * has_gauss, cached_gaussian = state[3:5] # <<<<<<<<<<<<<< + * try: + * obj = PyArray_ContiguousFromObject(key, NPY_ULONG, 1, 1) + */ + /*else*/ { + __pyx_t_1 = __Pyx_PyObject_GetSlice(__pyx_v_state, 3, 5, NULL, NULL, &__pyx_slice__47, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 794, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) { + PyObject* sequence = __pyx_t_1; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 794, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_4 = PyList_GET_ITEM(sequence, 0); + __pyx_t_3 = PyList_GET_ITEM(sequence, 1); + } + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(__pyx_t_3); + #else + __pyx_t_4 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 794, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 794, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 794, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = Py_TYPE(__pyx_t_5)->tp_iternext; + index = 0; __pyx_t_4 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_4)) goto __pyx_L7_unpacking_failed; + __Pyx_GOTREF(__pyx_t_4); + index = 1; __pyx_t_3 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_3)) goto __pyx_L7_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_6(__pyx_t_5), 2) < 0) __PYX_ERR(0, 794, __pyx_L1_error) + __pyx_t_6 = NULL; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L8_unpacking_done; + __pyx_L7_unpacking_failed:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 794, __pyx_L1_error) + __pyx_L8_unpacking_done:; + } + __pyx_v_has_gauss = __pyx_t_4; + __pyx_t_4 = 0; + __pyx_v_cached_gaussian = __pyx_t_3; + __pyx_t_3 = 0; + } + __pyx_L6:; + + /* "mtrand.pyx":795 + * else: + * has_gauss, cached_gaussian = state[3:5] + * try: # <<<<<<<<<<<<<< + * obj = PyArray_ContiguousFromObject(key, NPY_ULONG, 1, 1) + * except TypeError: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_9, &__pyx_t_10, &__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_9); + __Pyx_XGOTREF(__pyx_t_10); + __Pyx_XGOTREF(__pyx_t_11); + /*try:*/ { + + /* "mtrand.pyx":796 + * has_gauss, cached_gaussian = state[3:5] + * try: + * obj = PyArray_ContiguousFromObject(key, NPY_ULONG, 1, 1) # <<<<<<<<<<<<<< + * except TypeError: + * # compatibility -- could be an older pickle + */ + __pyx_t_1 = PyArray_ContiguousFromObject(__pyx_v_key, NPY_ULONG, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 796, __pyx_L9_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + arrayObject_obj = ((PyArrayObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":795 + * else: + * has_gauss, cached_gaussian = state[3:5] + * try: # <<<<<<<<<<<<<< + * obj = PyArray_ContiguousFromObject(key, NPY_ULONG, 1, 1) + * except TypeError: + */ + } + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; + goto __pyx_L14_try_end; + __pyx_L9_error:; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "mtrand.pyx":797 + * try: + * obj = PyArray_ContiguousFromObject(key, NPY_ULONG, 1, 1) + * except TypeError: # <<<<<<<<<<<<<< + * # compatibility -- could be an older pickle + * obj = PyArray_ContiguousFromObject(key, NPY_LONG, 1, 1) + */ + __pyx_t_7 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_TypeError); + if (__pyx_t_7) { + __Pyx_AddTraceback("mtrand.RandomState.set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_3, &__pyx_t_1, &__pyx_t_4) < 0) __PYX_ERR(0, 797, __pyx_L11_except_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_t_4); + + /* "mtrand.pyx":799 + * except TypeError: + * # compatibility -- could be an older pickle + * obj = PyArray_ContiguousFromObject(key, NPY_LONG, 1, 1) # <<<<<<<<<<<<<< + * if PyArray_DIM(obj, 0) != 624: + * raise ValueError("state must be 624 longs") + */ + __pyx_t_5 = PyArray_ContiguousFromObject(__pyx_v_key, NPY_LONG, 1, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 799, __pyx_L11_except_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_12 = __pyx_t_5; + __Pyx_INCREF(__pyx_t_12); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF_SET(arrayObject_obj, ((PyArrayObject *)__pyx_t_12)); + __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + goto __pyx_L10_exception_handled; + } + goto __pyx_L11_except_error; + __pyx_L11_except_error:; + + /* "mtrand.pyx":795 + * else: + * has_gauss, cached_gaussian = state[3:5] + * try: # <<<<<<<<<<<<<< + * obj = PyArray_ContiguousFromObject(key, NPY_ULONG, 1, 1) + * except TypeError: + */ + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_ExceptionReset(__pyx_t_9, __pyx_t_10, __pyx_t_11); + goto __pyx_L1_error; + __pyx_L10_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_ExceptionReset(__pyx_t_9, __pyx_t_10, __pyx_t_11); + __pyx_L14_try_end:; + } + + /* "mtrand.pyx":800 + * # compatibility -- could be an older pickle + * obj = PyArray_ContiguousFromObject(key, NPY_LONG, 1, 1) + * if PyArray_DIM(obj, 0) != 624: # <<<<<<<<<<<<<< + * raise ValueError("state must be 624 longs") + * with self.lock: + */ + __pyx_t_2 = ((PyArray_DIM(arrayObject_obj, 0) != 0x270) != 0); + if (unlikely(__pyx_t_2)) { + + /* "mtrand.pyx":801 + * obj = PyArray_ContiguousFromObject(key, NPY_LONG, 1, 1) + * if PyArray_DIM(obj, 0) != 624: + * raise ValueError("state must be 624 longs") # <<<<<<<<<<<<<< + * with self.lock: + * memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__48, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 801, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 801, __pyx_L1_error) + + /* "mtrand.pyx":800 + * # compatibility -- could be an older pickle + * obj = PyArray_ContiguousFromObject(key, NPY_LONG, 1, 1) + * if PyArray_DIM(obj, 0) != 624: # <<<<<<<<<<<<<< + * raise ValueError("state must be 624 longs") + * with self.lock: + */ + } + + /* "mtrand.pyx":802 + * if PyArray_DIM(obj, 0) != 624: + * raise ValueError("state must be 624 longs") + * with self.lock: # <<<<<<<<<<<<<< + * memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) + * self.internal_state.pos = pos + */ + /*with:*/ { + __pyx_t_11 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 802, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_1 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 802, __pyx_L18_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (__pyx_t_3) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 802, __pyx_L18_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 802, __pyx_L18_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_10, &__pyx_t_9, &__pyx_t_13); + __Pyx_XGOTREF(__pyx_t_10); + __Pyx_XGOTREF(__pyx_t_9); + __Pyx_XGOTREF(__pyx_t_13); + /*try:*/ { + + /* "mtrand.pyx":803 + * raise ValueError("state must be 624 longs") + * with self.lock: + * memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) # <<<<<<<<<<<<<< + * self.internal_state.pos = pos + * self.internal_state.has_gauss = has_gauss + */ + (void)(memcpy(((void *)__pyx_v_self->internal_state->key), ((void *)PyArray_DATA(arrayObject_obj)), (0x270 * (sizeof(long))))); + + /* "mtrand.pyx":804 + * with self.lock: + * memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) + * self.internal_state.pos = pos # <<<<<<<<<<<<<< + * self.internal_state.has_gauss = has_gauss + * self.internal_state.gauss = cached_gaussian + */ + __pyx_v_self->internal_state->pos = __pyx_v_pos; + + /* "mtrand.pyx":805 + * memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) + * self.internal_state.pos = pos + * self.internal_state.has_gauss = has_gauss # <<<<<<<<<<<<<< + * self.internal_state.gauss = cached_gaussian + * + */ + __pyx_t_7 = __Pyx_PyInt_As_int(__pyx_v_has_gauss); if (unlikely((__pyx_t_7 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 805, __pyx_L22_error) + __pyx_v_self->internal_state->has_gauss = __pyx_t_7; + + /* "mtrand.pyx":806 + * self.internal_state.pos = pos + * self.internal_state.has_gauss = has_gauss + * self.internal_state.gauss = cached_gaussian # <<<<<<<<<<<<<< + * + * # Pickling support: + */ + __pyx_t_14 = __pyx_PyFloat_AsDouble(__pyx_v_cached_gaussian); if (unlikely((__pyx_t_14 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 806, __pyx_L22_error) + __pyx_v_self->internal_state->gauss = __pyx_t_14; + + /* "mtrand.pyx":802 + * if PyArray_DIM(obj, 0) != 624: + * raise ValueError("state must be 624 longs") + * with self.lock: # <<<<<<<<<<<<<< + * memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) + * self.internal_state.pos = pos + */ + } + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + goto __pyx_L27_try_end; + __pyx_L22_error:; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + /*except:*/ { + __Pyx_AddTraceback("mtrand.RandomState.set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_1, &__pyx_t_3) < 0) __PYX_ERR(0, 802, __pyx_L24_except_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_12 = PyTuple_Pack(3, __pyx_t_4, __pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 802, __pyx_L24_except_error) + __Pyx_GOTREF(__pyx_t_12); + __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_12, NULL); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 802, __pyx_L24_except_error) + __Pyx_GOTREF(__pyx_t_15); + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_15); + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + if (__pyx_t_2 < 0) __PYX_ERR(0, 802, __pyx_L24_except_error) + __pyx_t_16 = ((!(__pyx_t_2 != 0)) != 0); + if (__pyx_t_16) { + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ErrRestoreWithState(__pyx_t_4, __pyx_t_1, __pyx_t_3); + __pyx_t_4 = 0; __pyx_t_1 = 0; __pyx_t_3 = 0; + __PYX_ERR(0, 802, __pyx_L24_except_error) + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L23_exception_handled; + } + __pyx_L24_except_error:; + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_ExceptionReset(__pyx_t_10, __pyx_t_9, __pyx_t_13); + goto __pyx_L1_error; + __pyx_L23_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_ExceptionReset(__pyx_t_10, __pyx_t_9, __pyx_t_13); + __pyx_L27_try_end:; + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_11) { + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_tuple__49, NULL); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 802, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } + goto __pyx_L21; + } + __pyx_L21:; + } + goto __pyx_L31; + __pyx_L18_error:; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + goto __pyx_L1_error; + __pyx_L31:; + } + + /* "mtrand.pyx":737 + * return ('MT19937', state, pos, has_gauss, gauss) + * + * def set_state(self, state): # <<<<<<<<<<<<<< + * """ + * set_state(state) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_AddTraceback("mtrand.RandomState.set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject_obj); + __Pyx_XDECREF(__pyx_v_algorithm_name); + __Pyx_XDECREF(__pyx_v_key); + __Pyx_XDECREF(__pyx_v_has_gauss); + __Pyx_XDECREF(__pyx_v_cached_gaussian); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":809 + * + * # Pickling support: + * def __getstate__(self): # <<<<<<<<<<<<<< + * return self.get_state() + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_11__getstate__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6mtrand_11RandomState_11__getstate__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getstate__ (wrapper)", 0); + __pyx_r = __pyx_pf_6mtrand_11RandomState_10__getstate__(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_10__getstate__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + __Pyx_RefNannySetupContext("__getstate__", 0); + + /* "mtrand.pyx":810 + * # Pickling support: + * def __getstate__(self): + * return self.get_state() # <<<<<<<<<<<<<< + * + * def __setstate__(self, state): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_get_state); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 810, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (__pyx_t_3) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 810, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else { + __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 810, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":809 + * + * # Pickling support: + * def __getstate__(self): # <<<<<<<<<<<<<< + * return self.get_state() + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("mtrand.RandomState.__getstate__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":812 + * return self.get_state() + * + * def __setstate__(self, state): # <<<<<<<<<<<<<< + * self.set_state(state) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_13__setstate__(PyObject *__pyx_v_self, PyObject *__pyx_v_state); /*proto*/ +static PyObject *__pyx_pw_6mtrand_11RandomState_13__setstate__(PyObject *__pyx_v_self, PyObject *__pyx_v_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate__ (wrapper)", 0); + __pyx_r = __pyx_pf_6mtrand_11RandomState_12__setstate__(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), ((PyObject *)__pyx_v_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_12__setstate__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + __Pyx_RefNannySetupContext("__setstate__", 0); + + /* "mtrand.pyx":813 + * + * def __setstate__(self, state): + * self.set_state(state) # <<<<<<<<<<<<<< + * + * def __reduce__(self): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_set_state); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 813, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_3) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_state); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 813, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_state}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 813, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_state}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 813, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 813, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_state); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 813, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":812 + * return self.get_state() + * + * def __setstate__(self, state): # <<<<<<<<<<<<<< + * self.set_state(state) + * + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("mtrand.RandomState.__setstate__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":815 + * self.set_state(state) + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return (np.random.__RandomState_ctor, (), self.get_state()) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_15__reduce__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6mtrand_11RandomState_15__reduce__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce__ (wrapper)", 0); + __pyx_r = __pyx_pf_6mtrand_11RandomState_14__reduce__(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_14__reduce__(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + __Pyx_RefNannySetupContext("__reduce__", 0); + + /* "mtrand.pyx":816 + * + * def __reduce__(self): + * return (np.random.__RandomState_ctor, (), self.get_state()) # <<<<<<<<<<<<<< + * + * # Basic distributions: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 816, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_random); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 816, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_RandomState_ctor); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 816, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_get_state); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 816, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + if (__pyx_t_4) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 816, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else { + __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 816, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 816, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1); + __Pyx_INCREF(__pyx_empty_tuple); + __Pyx_GIVEREF(__pyx_empty_tuple); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_empty_tuple); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_t_2); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":815 + * self.set_state(state) + * + * def __reduce__(self): # <<<<<<<<<<<<<< + * return (np.random.__RandomState_ctor, (), self.get_state()) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("mtrand.RandomState.__reduce__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":819 + * + * # Basic distributions: + * def random_sample(self, size=None): # <<<<<<<<<<<<<< + * """ + * random_sample(size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_17random_sample(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_16random_sample[] = "\n random_sample(size=None)\n\n Return random floats in the half-open interval [0.0, 1.0).\n\n Results are from the \"continuous uniform\" distribution over the\n stated interval. To sample :math:`Unif[a, b), b > a` multiply\n the output of `random_sample` by `(b-a)` and add `a`::\n\n (b - a) * random_sample() + a\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : float or ndarray of floats\n Array of random floats of shape `size` (unless ``size=None``, in which\n case a single float is returned).\n\n Examples\n --------\n >>> np.random.random_sample()\n 0.47108547995356098\n >>> type(np.random.random_sample())\n \n >>> np.random.random_sample((5,))\n array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428])\n\n Three-by-two array of random numbers from [-5, 0):\n\n >>> 5 * np.random.random_sample((3, 2)) - 5\n array([[-3.99149989, -0.52338984],\n [-2.99091858, -0.79479508],\n [-1.23204345, -1.75224494]])\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_17random_sample(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("random_sample (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_size,0}; + PyObject* values[1] = {0}; + values[0] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[0] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "random_sample") < 0)) __PYX_ERR(0, 819, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_size = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("random_sample", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 819, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.random_sample", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_16random_sample(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_16random_sample(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + __Pyx_RefNannySetupContext("random_sample", 0); + + /* "mtrand.pyx":861 + * + * """ + * return cont0_array(self.internal_state, rk_double, size, self.lock) # <<<<<<<<<<<<<< + * + * def tomaxint(self, size=None): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = __pyx_f_6mtrand_cont0_array(__pyx_v_self->internal_state, rk_double, __pyx_v_size, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 861, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":819 + * + * # Basic distributions: + * def random_sample(self, size=None): # <<<<<<<<<<<<<< + * """ + * random_sample(size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("mtrand.RandomState.random_sample", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":863 + * return cont0_array(self.internal_state, rk_double, size, self.lock) + * + * def tomaxint(self, size=None): # <<<<<<<<<<<<<< + * """ + * tomaxint(size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_19tomaxint(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_18tomaxint[] = "\n tomaxint(size=None)\n\n Random integers between 0 and ``sys.maxint``, inclusive.\n\n Return a sample of uniformly distributed random integers in the interval\n [0, ``sys.maxint``].\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : ndarray\n Drawn samples, with shape `size`.\n\n See Also\n --------\n randint : Uniform sampling over a given half-open interval of integers.\n random_integers : Uniform sampling over a given closed interval of\n integers.\n\n Examples\n --------\n >>> RS = np.random.mtrand.RandomState() # need a RandomState object\n >>> RS.tomaxint((2,2,2))\n array([[[1170048599, 1600360186],\n [ 739731006, 1947757578]],\n [[1871712945, 752307660],\n [1601631370, 1479324245]]])\n >>> import sys\n >>> sys.maxint\n 2147483647\n >>> RS.tomaxint((2,2,2)) < sys.maxint\n array([[[ True, True],\n [ True, True]],\n [[ True, True],\n [ True, True]]])\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_19tomaxint(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("tomaxint (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_size,0}; + PyObject* values[1] = {0}; + values[0] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[0] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "tomaxint") < 0)) __PYX_ERR(0, 863, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_size = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("tomaxint", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 863, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.tomaxint", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_18tomaxint(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_18tomaxint(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + __Pyx_RefNannySetupContext("tomaxint", 0); + + /* "mtrand.pyx":908 + * + * """ + * return disc0_array(self.internal_state, rk_long, size, self.lock) # <<<<<<<<<<<<<< + * + * def randint(self, low, high=None, size=None, dtype=int): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = __pyx_f_6mtrand_disc0_array(__pyx_v_self->internal_state, rk_long, __pyx_v_size, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 908, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":863 + * return cont0_array(self.internal_state, rk_double, size, self.lock) + * + * def tomaxint(self, size=None): # <<<<<<<<<<<<<< + * """ + * tomaxint(size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("mtrand.RandomState.tomaxint", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":910 + * return disc0_array(self.internal_state, rk_long, size, self.lock) + * + * def randint(self, low, high=None, size=None, dtype=int): # <<<<<<<<<<<<<< + * """ + * randint(low, high=None, size=None, dtype='l') + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_21randint(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_20randint[] = "\n randint(low, high=None, size=None, dtype='l')\n\n Return random integers from `low` (inclusive) to `high` (exclusive).\n\n Return random integers from the \"discrete uniform\" distribution of\n the specified dtype in the \"half-open\" interval [`low`, `high`). If\n `high` is None (the default), then results are from [0, `low`).\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution (unless\n ``high=None``, in which case this parameter is one above the\n *highest* such integer).\n high : int, optional\n If provided, one above the largest (signed) integer to be drawn\n from the distribution (see above for behavior if ``high=None``).\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n dtype : dtype, optional\n Desired dtype of the result. All dtypes are determined by their\n name, i.e., 'int64', 'int', etc, so byteorder is not available\n and a specific precision may have different C types depending\n on the platform. The default value is 'np.int'.\n\n .. versionadded:: 1.11.0\n\n Returns\n -------\n out : int or ndarray of ints\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n See Also\n --------\n random.random_integers : similar to `randint`, only for the closed\n interval [`low`, `high`], and 1 is the lowest value if `high` is\n omitted. In particular, this other one is the one to use to generate\n uniformly distributed discrete non-integers.\n\n Examples\n ---""-----\n >>> np.random.randint(2, size=10)\n array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0])\n >>> np.random.randint(1, size=10)\n array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])\n\n Generate a 2 x 4 array of ints between 0 and 4, inclusive:\n\n >>> np.random.randint(5, size=(2, 4))\n array([[4, 0, 2, 1],\n [3, 2, 2, 0]])\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_21randint(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_dtype = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("randint (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,&__pyx_n_s_dtype,0}; + PyObject* values[4] = {0,0,0,0}; + values[1] = ((PyObject *)Py_None); + values[2] = ((PyObject *)Py_None); + values[3] = __pyx_k__50; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dtype); + if (value) { values[3] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "randint") < 0)) __PYX_ERR(0, 910, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + __pyx_v_dtype = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("randint", 0, 1, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 910, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.randint", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_20randint(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_low, __pyx_v_high, __pyx_v_size, __pyx_v_dtype); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_20randint(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size, PyObject *__pyx_v_dtype) { + PyObject *__pyx_v_key = NULL; + PyObject *__pyx_v_lowbnd = NULL; + PyObject *__pyx_v_highbnd = NULL; + PyObject *__pyx_v_randfunc = NULL; + PyObject *__pyx_v_ilow = NULL; + PyObject *__pyx_v_ihigh = NULL; + PyObject *__pyx_v_ret = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *(*__pyx_t_8)(PyObject *); + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + int __pyx_t_13; + PyObject *__pyx_t_14 = NULL; + __Pyx_RefNannySetupContext("randint", 0); + __Pyx_INCREF(__pyx_v_low); + __Pyx_INCREF(__pyx_v_high); + + /* "mtrand.pyx":968 + * + * """ + * if high is None: # <<<<<<<<<<<<<< + * high = low + * low = 0 + */ + __pyx_t_1 = (__pyx_v_high == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":969 + * """ + * if high is None: + * high = low # <<<<<<<<<<<<<< + * low = 0 + * + */ + __Pyx_INCREF(__pyx_v_low); + __Pyx_DECREF_SET(__pyx_v_high, __pyx_v_low); + + /* "mtrand.pyx":970 + * if high is None: + * high = low + * low = 0 # <<<<<<<<<<<<<< + * + * # '_randint_type' is defined in + */ + __Pyx_INCREF(__pyx_int_0); + __Pyx_DECREF_SET(__pyx_v_low, __pyx_int_0); + + /* "mtrand.pyx":968 + * + * """ + * if high is None: # <<<<<<<<<<<<<< + * high = low + * low = 0 + */ + } + + /* "mtrand.pyx":974 + * # '_randint_type' is defined in + * # 'generate_randint_helpers.py' + * key = np.dtype(dtype).name # <<<<<<<<<<<<<< + * if key not in _randint_type: + * raise TypeError('Unsupported dtype "%s" for randint' % key) + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 974, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_dtype); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 974, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_4) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_dtype); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 974, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_dtype}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 974, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_dtype}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 974, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 974, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_4); __pyx_t_4 = NULL; + __Pyx_INCREF(__pyx_v_dtype); + __Pyx_GIVEREF(__pyx_v_dtype); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_dtype); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 974, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_name); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 974, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_key = __pyx_t_5; + __pyx_t_5 = 0; + + /* "mtrand.pyx":975 + * # 'generate_randint_helpers.py' + * key = np.dtype(dtype).name + * if key not in _randint_type: # <<<<<<<<<<<<<< + * raise TypeError('Unsupported dtype "%s" for randint' % key) + * + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_randint_type); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 975, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_v_key, __pyx_t_5, Py_NE)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 975, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_1 = (__pyx_t_2 != 0); + if (unlikely(__pyx_t_1)) { + + /* "mtrand.pyx":976 + * key = np.dtype(dtype).name + * if key not in _randint_type: + * raise TypeError('Unsupported dtype "%s" for randint' % key) # <<<<<<<<<<<<<< + * + * lowbnd, highbnd, randfunc = _randint_type[key] + */ + __pyx_t_5 = __Pyx_PyString_Format(__pyx_kp_s_Unsupported_dtype_s_for_randint, __pyx_v_key); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 976, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_TypeError, __pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 976, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 976, __pyx_L1_error) + + /* "mtrand.pyx":975 + * # 'generate_randint_helpers.py' + * key = np.dtype(dtype).name + * if key not in _randint_type: # <<<<<<<<<<<<<< + * raise TypeError('Unsupported dtype "%s" for randint' % key) + * + */ + } + + /* "mtrand.pyx":978 + * raise TypeError('Unsupported dtype "%s" for randint' % key) + * + * lowbnd, highbnd, randfunc = _randint_type[key] # <<<<<<<<<<<<<< + * + * # TODO: Do not cast these inputs to Python int + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_randint_type); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 978, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_PyObject_GetItem(__pyx_t_3, __pyx_v_key); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 978, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if ((likely(PyTuple_CheckExact(__pyx_t_5))) || (PyList_CheckExact(__pyx_t_5))) { + PyObject* sequence = __pyx_t_5; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 3)) { + if (size > 3) __Pyx_RaiseTooManyValuesError(3); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 978, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_6 = PyTuple_GET_ITEM(sequence, 1); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 2); + } else { + __pyx_t_3 = PyList_GET_ITEM(sequence, 0); + __pyx_t_6 = PyList_GET_ITEM(sequence, 1); + __pyx_t_4 = PyList_GET_ITEM(sequence, 2); + } + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(__pyx_t_4); + #else + __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 978, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_6 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 978, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_4 = PySequence_ITEM(sequence, 2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 978, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_7 = PyObject_GetIter(__pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 978, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_8 = Py_TYPE(__pyx_t_7)->tp_iternext; + index = 0; __pyx_t_3 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_3)) goto __pyx_L5_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + index = 1; __pyx_t_6 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_6)) goto __pyx_L5_unpacking_failed; + __Pyx_GOTREF(__pyx_t_6); + index = 2; __pyx_t_4 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_4)) goto __pyx_L5_unpacking_failed; + __Pyx_GOTREF(__pyx_t_4); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 3) < 0) __PYX_ERR(0, 978, __pyx_L1_error) + __pyx_t_8 = NULL; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + goto __pyx_L6_unpacking_done; + __pyx_L5_unpacking_failed:; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_8 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 978, __pyx_L1_error) + __pyx_L6_unpacking_done:; + } + __pyx_v_lowbnd = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_v_highbnd = __pyx_t_6; + __pyx_t_6 = 0; + __pyx_v_randfunc = __pyx_t_4; + __pyx_t_4 = 0; + + /* "mtrand.pyx":985 + * # integer comparison and subtraction involving uint64 and non- + * # uint64). Afterwards, remove these two lines. + * ilow = int(low) # <<<<<<<<<<<<<< + * ihigh = int(high) + * + */ + __pyx_t_5 = __Pyx_PyNumber_Int(__pyx_v_low); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 985, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_v_ilow = __pyx_t_5; + __pyx_t_5 = 0; + + /* "mtrand.pyx":986 + * # uint64). Afterwards, remove these two lines. + * ilow = int(low) + * ihigh = int(high) # <<<<<<<<<<<<<< + * + * if ilow < lowbnd: + */ + __pyx_t_5 = __Pyx_PyNumber_Int(__pyx_v_high); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 986, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_v_ihigh = __pyx_t_5; + __pyx_t_5 = 0; + + /* "mtrand.pyx":988 + * ihigh = int(high) + * + * if ilow < lowbnd: # <<<<<<<<<<<<<< + * raise ValueError("low is out of bounds for %s" % (key,)) + * if ihigh > highbnd: + */ + __pyx_t_5 = PyObject_RichCompare(__pyx_v_ilow, __pyx_v_lowbnd, Py_LT); __Pyx_XGOTREF(__pyx_t_5); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 988, __pyx_L1_error) + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_1 < 0)) __PYX_ERR(0, 988, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_t_1)) { + + /* "mtrand.pyx":989 + * + * if ilow < lowbnd: + * raise ValueError("low is out of bounds for %s" % (key,)) # <<<<<<<<<<<<<< + * if ihigh > highbnd: + * raise ValueError("high is out of bounds for %s" % (key,)) + */ + __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 989, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_key); + __Pyx_GIVEREF(__pyx_v_key); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_key); + __pyx_t_4 = __Pyx_PyString_Format(__pyx_kp_s_low_is_out_of_bounds_for_s, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 989, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 989, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 989, __pyx_L1_error) + + /* "mtrand.pyx":988 + * ihigh = int(high) + * + * if ilow < lowbnd: # <<<<<<<<<<<<<< + * raise ValueError("low is out of bounds for %s" % (key,)) + * if ihigh > highbnd: + */ + } + + /* "mtrand.pyx":990 + * if ilow < lowbnd: + * raise ValueError("low is out of bounds for %s" % (key,)) + * if ihigh > highbnd: # <<<<<<<<<<<<<< + * raise ValueError("high is out of bounds for %s" % (key,)) + * if ilow >= ihigh: + */ + __pyx_t_5 = PyObject_RichCompare(__pyx_v_ihigh, __pyx_v_highbnd, Py_GT); __Pyx_XGOTREF(__pyx_t_5); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 990, __pyx_L1_error) + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_1 < 0)) __PYX_ERR(0, 990, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_t_1)) { + + /* "mtrand.pyx":991 + * raise ValueError("low is out of bounds for %s" % (key,)) + * if ihigh > highbnd: + * raise ValueError("high is out of bounds for %s" % (key,)) # <<<<<<<<<<<<<< + * if ilow >= ihigh: + * raise ValueError("low >= high") + */ + __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 991, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_key); + __Pyx_GIVEREF(__pyx_v_key); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_key); + __pyx_t_4 = __Pyx_PyString_Format(__pyx_kp_s_high_is_out_of_bounds_for_s, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 991, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 991, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 991, __pyx_L1_error) + + /* "mtrand.pyx":990 + * if ilow < lowbnd: + * raise ValueError("low is out of bounds for %s" % (key,)) + * if ihigh > highbnd: # <<<<<<<<<<<<<< + * raise ValueError("high is out of bounds for %s" % (key,)) + * if ilow >= ihigh: + */ + } + + /* "mtrand.pyx":992 + * if ihigh > highbnd: + * raise ValueError("high is out of bounds for %s" % (key,)) + * if ilow >= ihigh: # <<<<<<<<<<<<<< + * raise ValueError("low >= high") + * + */ + __pyx_t_5 = PyObject_RichCompare(__pyx_v_ilow, __pyx_v_ihigh, Py_GE); __Pyx_XGOTREF(__pyx_t_5); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 992, __pyx_L1_error) + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_1 < 0)) __PYX_ERR(0, 992, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_t_1)) { + + /* "mtrand.pyx":993 + * raise ValueError("high is out of bounds for %s" % (key,)) + * if ilow >= ihigh: + * raise ValueError("low >= high") # <<<<<<<<<<<<<< + * + * with self.lock: + */ + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__51, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 993, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 993, __pyx_L1_error) + + /* "mtrand.pyx":992 + * if ihigh > highbnd: + * raise ValueError("high is out of bounds for %s" % (key,)) + * if ilow >= ihigh: # <<<<<<<<<<<<<< + * raise ValueError("low >= high") + * + */ + } + + /* "mtrand.pyx":995 + * raise ValueError("low >= high") + * + * with self.lock: # <<<<<<<<<<<<<< + * ret = randfunc(ilow, ihigh - 1, size, self.state_address) + * + */ + /*with:*/ { + __pyx_t_9 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 995, __pyx_L10_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_6) { + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_6); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 995, __pyx_L10_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else { + __pyx_t_5 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 995, __pyx_L10_error) + } + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + /*try:*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_10, &__pyx_t_11, &__pyx_t_12); + __Pyx_XGOTREF(__pyx_t_10); + __Pyx_XGOTREF(__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_12); + /*try:*/ { + + /* "mtrand.pyx":996 + * + * with self.lock: + * ret = randfunc(ilow, ihigh - 1, size, self.state_address) # <<<<<<<<<<<<<< + * + * if size is None: + */ + __pyx_t_4 = __Pyx_PyInt_SubtractObjC(__pyx_v_ihigh, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 996, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_v_randfunc); + __pyx_t_6 = __pyx_v_randfunc; __pyx_t_3 = NULL; + __pyx_t_13 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_13 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_ilow, __pyx_t_4, __pyx_v_size, __pyx_v_self->state_address}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_13, 4+__pyx_t_13); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 996, __pyx_L14_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_ilow, __pyx_t_4, __pyx_v_size, __pyx_v_self->state_address}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_13, 4+__pyx_t_13); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 996, __pyx_L14_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(4+__pyx_t_13); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 996, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_7); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(__pyx_v_ilow); + __Pyx_GIVEREF(__pyx_v_ilow); + PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_13, __pyx_v_ilow); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_13, __pyx_t_4); + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_7, 2+__pyx_t_13, __pyx_v_size); + __Pyx_INCREF(__pyx_v_self->state_address); + __Pyx_GIVEREF(__pyx_v_self->state_address); + PyTuple_SET_ITEM(__pyx_t_7, 3+__pyx_t_13, __pyx_v_self->state_address); + __pyx_t_4 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_7, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 996, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_v_ret = __pyx_t_5; + __pyx_t_5 = 0; + + /* "mtrand.pyx":998 + * ret = randfunc(ilow, ihigh - 1, size, self.state_address) + * + * if size is None: # <<<<<<<<<<<<<< + * if dtype in (np.bool, np.int, np.long): + * return dtype(ret) + */ + __pyx_t_1 = (__pyx_v_size == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":999 + * + * if size is None: + * if dtype in (np.bool, np.int, np.long): # <<<<<<<<<<<<<< + * return dtype(ret) + * + */ + __Pyx_INCREF(__pyx_v_dtype); + __pyx_t_5 = __pyx_v_dtype; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_bool_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = PyObject_RichCompare(__pyx_t_5, __pyx_t_7, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_1 < 0)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (!__pyx_t_1) { + } else { + __pyx_t_2 = __pyx_t_1; + goto __pyx_L22_bool_binop_done; + } + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_int); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = PyObject_RichCompare(__pyx_t_5, __pyx_t_7, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_1 < 0)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (!__pyx_t_1) { + } else { + __pyx_t_2 = __pyx_t_1; + goto __pyx_L22_bool_binop_done; + } + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_long); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = PyObject_RichCompare(__pyx_t_5, __pyx_t_7, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_1 < 0)) __PYX_ERR(0, 999, __pyx_L14_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_2 = __pyx_t_1; + __pyx_L22_bool_binop_done:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_1 = (__pyx_t_2 != 0); + if (__pyx_t_1) { + + /* "mtrand.pyx":1000 + * if size is None: + * if dtype in (np.bool, np.int, np.long): + * return dtype(ret) # <<<<<<<<<<<<<< + * + * return ret + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_dtype); + __pyx_t_6 = __pyx_v_dtype; __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_7) { + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_v_ret); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1000, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_5); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_v_ret}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1000, __pyx_L14_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_v_ret}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1000, __pyx_L14_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1000, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_INCREF(__pyx_v_ret); + __Pyx_GIVEREF(__pyx_v_ret); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_ret); + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_4, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1000, __pyx_L14_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L18_try_return; + + /* "mtrand.pyx":999 + * + * if size is None: + * if dtype in (np.bool, np.int, np.long): # <<<<<<<<<<<<<< + * return dtype(ret) + * + */ + } + + /* "mtrand.pyx":998 + * ret = randfunc(ilow, ihigh - 1, size, self.state_address) + * + * if size is None: # <<<<<<<<<<<<<< + * if dtype in (np.bool, np.int, np.long): + * return dtype(ret) + */ + } + + /* "mtrand.pyx":1002 + * return dtype(ret) + * + * return ret # <<<<<<<<<<<<<< + * + * def bytes(self, npy_intp length): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_ret); + __pyx_r = __pyx_v_ret; + goto __pyx_L18_try_return; + + /* "mtrand.pyx":995 + * raise ValueError("low >= high") + * + * with self.lock: # <<<<<<<<<<<<<< + * ret = randfunc(ilow, ihigh - 1, size, self.state_address) + * + */ + } + __pyx_L14_error:; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + /*except:*/ { + __Pyx_AddTraceback("mtrand.RandomState.randint", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_4) < 0) __PYX_ERR(0, 995, __pyx_L16_except_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = PyTuple_Pack(3, __pyx_t_5, __pyx_t_6, __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 995, __pyx_L16_except_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_7, NULL); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 995, __pyx_L16_except_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_14); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + if (__pyx_t_1 < 0) __PYX_ERR(0, 995, __pyx_L16_except_error) + __pyx_t_2 = ((!(__pyx_t_1 != 0)) != 0); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_ErrRestoreWithState(__pyx_t_5, __pyx_t_6, __pyx_t_4); + __pyx_t_5 = 0; __pyx_t_6 = 0; __pyx_t_4 = 0; + __PYX_ERR(0, 995, __pyx_L16_except_error) + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + goto __pyx_L15_exception_handled; + } + __pyx_L16_except_error:; + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_ExceptionReset(__pyx_t_10, __pyx_t_11, __pyx_t_12); + goto __pyx_L1_error; + __pyx_L18_try_return:; + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_ExceptionReset(__pyx_t_10, __pyx_t_11, __pyx_t_12); + goto __pyx_L11_return; + __pyx_L15_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_ExceptionReset(__pyx_t_10, __pyx_t_11, __pyx_t_12); + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_9) { + __pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_tuple__52, NULL); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + goto __pyx_L13; + } + __pyx_L11_return: { + __pyx_t_12 = __pyx_r; + __pyx_r = 0; + if (__pyx_t_9) { + __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_tuple__53, NULL); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __pyx_r = __pyx_t_12; + __pyx_t_12 = 0; + goto __pyx_L0; + } + __pyx_L13:; + } + goto __pyx_L28; + __pyx_L10_error:; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L1_error; + __pyx_L28:; + } + + /* "mtrand.pyx":910 + * return disc0_array(self.internal_state, rk_long, size, self.lock) + * + * def randint(self, low, high=None, size=None, dtype=int): # <<<<<<<<<<<<<< + * """ + * randint(low, high=None, size=None, dtype='l') + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("mtrand.RandomState.randint", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_key); + __Pyx_XDECREF(__pyx_v_lowbnd); + __Pyx_XDECREF(__pyx_v_highbnd); + __Pyx_XDECREF(__pyx_v_randfunc); + __Pyx_XDECREF(__pyx_v_ilow); + __Pyx_XDECREF(__pyx_v_ihigh); + __Pyx_XDECREF(__pyx_v_ret); + __Pyx_XDECREF(__pyx_v_low); + __Pyx_XDECREF(__pyx_v_high); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1004 + * return ret + * + * def bytes(self, npy_intp length): # <<<<<<<<<<<<<< + * """ + * bytes(length) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_23bytes(PyObject *__pyx_v_self, PyObject *__pyx_arg_length); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_22bytes[] = "\n bytes(length)\n\n Return random bytes.\n\n Parameters\n ----------\n length : int\n Number of random bytes.\n\n Returns\n -------\n out : str\n String of length `length`.\n\n Examples\n --------\n >>> np.random.bytes(10)\n ' eh\\x85\\x022SZ\\xbf\\xa4' #random\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_23bytes(PyObject *__pyx_v_self, PyObject *__pyx_arg_length) { + npy_intp __pyx_v_length; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("bytes (wrapper)", 0); + assert(__pyx_arg_length); { + __pyx_v_length = __Pyx_PyInt_As_npy_intp(__pyx_arg_length); if (unlikely((__pyx_v_length == ((npy_intp)-1)) && PyErr_Occurred())) __PYX_ERR(0, 1004, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.bytes", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_22bytes(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), ((npy_intp)__pyx_v_length)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_22bytes(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, npy_intp __pyx_v_length) { + void *__pyx_v_bytes; + PyObject *__pyx_v_bytestring = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + __Pyx_RefNannySetupContext("bytes", 0); + + /* "mtrand.pyx":1027 + * """ + * cdef void *bytes + * bytestring = empty_py_bytes(length, &bytes) # <<<<<<<<<<<<<< + * with self.lock, nogil: + * rk_fill(bytes, length, self.internal_state) + */ + __pyx_t_1 = empty_py_bytes(__pyx_v_length, (&__pyx_v_bytes)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1027, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_bytestring = __pyx_t_1; + __pyx_t_1 = 0; + + /* "mtrand.pyx":1028 + * cdef void *bytes + * bytestring = empty_py_bytes(length, &bytes) + * with self.lock, nogil: # <<<<<<<<<<<<<< + * rk_fill(bytes, length, self.internal_state) + * return bytestring + */ + /*with:*/ { + __pyx_t_2 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1028, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1028, __pyx_L3_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + if (__pyx_t_4) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1028, __pyx_L3_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else { + __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1028, __pyx_L3_error) + } + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + /*try:*/ { + { + (void)__pyx_t_5; (void)__pyx_t_6; (void)__pyx_t_7; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":1029 + * bytestring = empty_py_bytes(length, &bytes) + * with self.lock, nogil: + * rk_fill(bytes, length, self.internal_state) # <<<<<<<<<<<<<< + * return bytestring + * + */ + rk_fill(__pyx_v_bytes, __pyx_v_length, __pyx_v_self->internal_state); + } + + /* "mtrand.pyx":1028 + * cdef void *bytes + * bytestring = empty_py_bytes(length, &bytes) + * with self.lock, nogil: # <<<<<<<<<<<<<< + * rk_fill(bytes, length, self.internal_state) + * return bytestring + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L15; + } + __pyx_L15:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_2) { + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__54, NULL); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1028, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + goto __pyx_L6; + } + __pyx_L6:; + } + goto __pyx_L16; + __pyx_L3_error:; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + goto __pyx_L1_error; + __pyx_L16:; + } + + /* "mtrand.pyx":1030 + * with self.lock, nogil: + * rk_fill(bytes, length, self.internal_state) + * return bytestring # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_bytestring); + __pyx_r = __pyx_v_bytestring; + goto __pyx_L0; + + /* "mtrand.pyx":1004 + * return ret + * + * def bytes(self, npy_intp length): # <<<<<<<<<<<<<< + * """ + * bytes(length) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("mtrand.RandomState.bytes", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_bytestring); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1033 + * + * + * def choice(self, a, size=None, replace=True, p=None): # <<<<<<<<<<<<<< + * """ + * choice(a, size=None, replace=True, p=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_25choice(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_24choice[] = "\n choice(a, size=None, replace=True, p=None)\n\n Generates a random sample from a given 1-D array\n\n .. versionadded:: 1.7.0\n\n Parameters\n -----------\n a : 1-D array-like or int\n If an ndarray, a random sample is generated from its elements.\n If an int, the random sample is generated as if a were np.arange(a)\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n replace : boolean, optional\n Whether the sample is with or without replacement\n p : 1-D array-like, optional\n The probabilities associated with each entry in a.\n If not given the sample assumes a uniform distribution over all\n entries in a.\n\n Returns\n --------\n samples : single item or ndarray\n The generated random samples\n\n Raises\n -------\n ValueError\n If a is an int and less than zero, if a or p are not 1-dimensional,\n if a is an array-like of size 0, if p is not a vector of\n probabilities, if a and p have different lengths, or if\n replace=False and the sample size is greater than the population\n size\n\n See Also\n ---------\n randint, shuffle, permutation\n\n Examples\n ---------\n Generate a uniform random sample from np.arange(5) of size 3:\n\n >>> np.random.choice(5, 3)\n array([0, 3, 4])\n >>> #This is equivalent to np.random.randint(0,5,3)\n\n Generate a non-uniform random sample from np.arange(5) of size 3:\n\n >>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0])\n array([3, 3, 0])\n\n Generate a uniform random sample from np.arange(5) of size 3 without\n ""replacement:\n\n >>> np.random.choice(5, 3, replace=False)\n array([3,1,0])\n >>> #This is equivalent to np.random.permutation(np.arange(5))[:3]\n\n Generate a non-uniform random sample from np.arange(5) of size\n 3 without replacement:\n\n >>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0])\n array([2, 3, 0])\n\n Any of the above can be repeated with an arbitrary array-like\n instead of just integers. For instance:\n\n >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher']\n >>> np.random.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3])\n array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'],\n dtype='|S11')\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_25choice(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_a = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_replace = 0; + PyObject *__pyx_v_p = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("choice (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_a,&__pyx_n_s_size,&__pyx_n_s_replace,&__pyx_n_s_p,0}; + PyObject* values[4] = {0,0,0,0}; + values[1] = ((PyObject *)Py_None); + values[2] = ((PyObject *)Py_True); + values[3] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_a)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_replace); + if (value) { values[2] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_p); + if (value) { values[3] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "choice") < 0)) __PYX_ERR(0, 1033, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_a = values[0]; + __pyx_v_size = values[1]; + __pyx_v_replace = values[2]; + __pyx_v_p = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("choice", 0, 1, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1033, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.choice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_24choice(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_a, __pyx_v_size, __pyx_v_replace, __pyx_v_p); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_24choice(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size, PyObject *__pyx_v_replace, PyObject *__pyx_v_p) { + PyObject *__pyx_v_pop_size = NULL; + PyObject *__pyx_v_d = NULL; + PyObject *__pyx_v_atol = NULL; + double *__pyx_v_pix; + PyObject *__pyx_v_shape = NULL; + PyObject *__pyx_v_cdf = NULL; + PyObject *__pyx_v_uniform_samples = NULL; + PyObject *__pyx_v_idx = NULL; + PyObject *__pyx_v_n_uniq = NULL; + PyObject *__pyx_v_found = NULL; + PyObject *__pyx_v_flat_found = NULL; + PyObject *__pyx_v_x = NULL; + PyObject *__pyx_v_new = NULL; + CYTHON_UNUSED PyObject *__pyx_v__ = NULL; + PyObject *__pyx_v_unique_indices = NULL; + PyObject *__pyx_v_res = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + int __pyx_t_11; + Py_ssize_t __pyx_t_12; + PyObject *__pyx_t_13 = NULL; + PyObject *__pyx_t_14 = NULL; + npy_intp __pyx_t_15; + PyObject *(*__pyx_t_16)(PyObject *); + int __pyx_t_17; + __Pyx_RefNannySetupContext("choice", 0); + __Pyx_INCREF(__pyx_v_a); + __Pyx_INCREF(__pyx_v_size); + __Pyx_INCREF(__pyx_v_p); + + /* "mtrand.pyx":1112 + * + * # Format and Verify input + * a = np.array(a, copy=False) # <<<<<<<<<<<<<< + * if a.ndim == 0: + * try: + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_array); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v_a); + __Pyx_GIVEREF(__pyx_v_a); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_a); + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 1112, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1112, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF_SET(__pyx_v_a, __pyx_t_4); + __pyx_t_4 = 0; + + /* "mtrand.pyx":1113 + * # Format and Verify input + * a = np.array(a, copy=False) + * if a.ndim == 0: # <<<<<<<<<<<<<< + * try: + * # __index__ must return an integer by python rules. + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_a, __pyx_n_s_ndim); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __Pyx_PyInt_EqObjC(__pyx_t_4, __pyx_int_0, 0, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 1113, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_5) { + + /* "mtrand.pyx":1114 + * a = np.array(a, copy=False) + * if a.ndim == 0: + * try: # <<<<<<<<<<<<<< + * # __index__ must return an integer by python rules. + * pop_size = operator.index(a.item()) + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_6, &__pyx_t_7, &__pyx_t_8); + __Pyx_XGOTREF(__pyx_t_6); + __Pyx_XGOTREF(__pyx_t_7); + __Pyx_XGOTREF(__pyx_t_8); + /*try:*/ { + + /* "mtrand.pyx":1116 + * try: + * # __index__ must return an integer by python rules. + * pop_size = operator.index(a.item()) # <<<<<<<<<<<<<< + * except TypeError: + * raise ValueError("a must be 1-dimensional or an integer") + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_operator); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_index); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_a, __pyx_n_s_item); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (__pyx_t_9) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1116, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_2) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_4}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_4}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1116, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_pop_size = __pyx_t_3; + __pyx_t_3 = 0; + + /* "mtrand.pyx":1114 + * a = np.array(a, copy=False) + * if a.ndim == 0: + * try: # <<<<<<<<<<<<<< + * # __index__ must return an integer by python rules. + * pop_size = operator.index(a.item()) + */ + } + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + goto __pyx_L9_try_end; + __pyx_L4_error:; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "mtrand.pyx":1117 + * # __index__ must return an integer by python rules. + * pop_size = operator.index(a.item()) + * except TypeError: # <<<<<<<<<<<<<< + * raise ValueError("a must be 1-dimensional or an integer") + * if pop_size <= 0: + */ + __pyx_t_10 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_TypeError); + if (__pyx_t_10) { + __Pyx_AddTraceback("mtrand.RandomState.choice", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_3, &__pyx_t_1, &__pyx_t_9) < 0) __PYX_ERR(0, 1117, __pyx_L6_except_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_t_9); + + /* "mtrand.pyx":1118 + * pop_size = operator.index(a.item()) + * except TypeError: + * raise ValueError("a must be 1-dimensional or an integer") # <<<<<<<<<<<<<< + * if pop_size <= 0: + * raise ValueError("a must be greater than 0") + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__55, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1118, __pyx_L6_except_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 1118, __pyx_L6_except_error) + } + goto __pyx_L6_except_error; + __pyx_L6_except_error:; + + /* "mtrand.pyx":1114 + * a = np.array(a, copy=False) + * if a.ndim == 0: + * try: # <<<<<<<<<<<<<< + * # __index__ must return an integer by python rules. + * pop_size = operator.index(a.item()) + */ + __Pyx_XGIVEREF(__pyx_t_6); + __Pyx_XGIVEREF(__pyx_t_7); + __Pyx_XGIVEREF(__pyx_t_8); + __Pyx_ExceptionReset(__pyx_t_6, __pyx_t_7, __pyx_t_8); + goto __pyx_L1_error; + __pyx_L9_try_end:; + } + + /* "mtrand.pyx":1119 + * except TypeError: + * raise ValueError("a must be 1-dimensional or an integer") + * if pop_size <= 0: # <<<<<<<<<<<<<< + * raise ValueError("a must be greater than 0") + * elif a.ndim != 1: + */ + __pyx_t_9 = PyObject_RichCompare(__pyx_v_pop_size, __pyx_int_0, Py_LE); __Pyx_XGOTREF(__pyx_t_9); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1119, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_9); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 1119, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":1120 + * raise ValueError("a must be 1-dimensional or an integer") + * if pop_size <= 0: + * raise ValueError("a must be greater than 0") # <<<<<<<<<<<<<< + * elif a.ndim != 1: + * raise ValueError("a must be 1-dimensional") + */ + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__56, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1120, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_Raise(__pyx_t_9, 0, 0, 0); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __PYX_ERR(0, 1120, __pyx_L1_error) + + /* "mtrand.pyx":1119 + * except TypeError: + * raise ValueError("a must be 1-dimensional or an integer") + * if pop_size <= 0: # <<<<<<<<<<<<<< + * raise ValueError("a must be greater than 0") + * elif a.ndim != 1: + */ + } + + /* "mtrand.pyx":1113 + * # Format and Verify input + * a = np.array(a, copy=False) + * if a.ndim == 0: # <<<<<<<<<<<<<< + * try: + * # __index__ must return an integer by python rules. + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":1121 + * if pop_size <= 0: + * raise ValueError("a must be greater than 0") + * elif a.ndim != 1: # <<<<<<<<<<<<<< + * raise ValueError("a must be 1-dimensional") + * else: + */ + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_v_a, __pyx_n_s_ndim); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1121, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_9, __pyx_int_1, Py_NE); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1121, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 1121, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":1122 + * raise ValueError("a must be greater than 0") + * elif a.ndim != 1: + * raise ValueError("a must be 1-dimensional") # <<<<<<<<<<<<<< + * else: + * pop_size = a.shape[0] + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__57, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 1122, __pyx_L1_error) + + /* "mtrand.pyx":1121 + * if pop_size <= 0: + * raise ValueError("a must be greater than 0") + * elif a.ndim != 1: # <<<<<<<<<<<<<< + * raise ValueError("a must be 1-dimensional") + * else: + */ + } + + /* "mtrand.pyx":1124 + * raise ValueError("a must be 1-dimensional") + * else: + * pop_size = a.shape[0] # <<<<<<<<<<<<<< + * if pop_size is 0: + * raise ValueError("a must be non-empty") + */ + /*else*/ { + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_a, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1124, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_GetItemInt(__pyx_t_1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1124, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_pop_size = __pyx_t_9; + __pyx_t_9 = 0; + + /* "mtrand.pyx":1125 + * else: + * pop_size = a.shape[0] + * if pop_size is 0: # <<<<<<<<<<<<<< + * raise ValueError("a must be non-empty") + * + */ + __pyx_t_5 = (__pyx_v_pop_size == __pyx_int_0); + __pyx_t_11 = (__pyx_t_5 != 0); + if (unlikely(__pyx_t_11)) { + + /* "mtrand.pyx":1126 + * pop_size = a.shape[0] + * if pop_size is 0: + * raise ValueError("a must be non-empty") # <<<<<<<<<<<<<< + * + * if p is not None: + */ + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__58, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_Raise(__pyx_t_9, 0, 0, 0); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __PYX_ERR(0, 1126, __pyx_L1_error) + + /* "mtrand.pyx":1125 + * else: + * pop_size = a.shape[0] + * if pop_size is 0: # <<<<<<<<<<<<<< + * raise ValueError("a must be non-empty") + * + */ + } + } + __pyx_L3:; + + /* "mtrand.pyx":1128 + * raise ValueError("a must be non-empty") + * + * if p is not None: # <<<<<<<<<<<<<< + * d = len(p) + * + */ + __pyx_t_11 = (__pyx_v_p != Py_None); + __pyx_t_5 = (__pyx_t_11 != 0); + if (__pyx_t_5) { + + /* "mtrand.pyx":1129 + * + * if p is not None: + * d = len(p) # <<<<<<<<<<<<<< + * + * atol = np.sqrt(np.finfo(np.float64).eps) + */ + __pyx_t_12 = PyObject_Length(__pyx_v_p); if (unlikely(__pyx_t_12 == ((Py_ssize_t)-1))) __PYX_ERR(0, 1129, __pyx_L1_error) + __pyx_t_9 = PyInt_FromSsize_t(__pyx_t_12); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1129, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_v_d = __pyx_t_9; + __pyx_t_9 = 0; + + /* "mtrand.pyx":1131 + * d = len(p) + * + * atol = np.sqrt(np.finfo(np.float64).eps) # <<<<<<<<<<<<<< + * if isinstance(p, np.ndarray): + * if np.issubdtype(p.dtype, np.floating): + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_sqrt); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_finfo); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_4) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_13); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_13}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_13}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } else + #endif + { + __pyx_t_14 = PyTuple_New(1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_4); __pyx_t_4 = NULL; + __Pyx_GIVEREF(__pyx_t_13); + PyTuple_SET_ITEM(__pyx_t_14, 0+1, __pyx_t_13); + __pyx_t_13 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_14, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_eps); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + if (!__pyx_t_1) { + __pyx_t_9 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_t_2}; + __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_t_2}; + __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_14 = PyTuple_New(1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_1); __pyx_t_1 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_14, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_14, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1131, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + } + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_atol = __pyx_t_9; + __pyx_t_9 = 0; + + /* "mtrand.pyx":1132 + * + * atol = np.sqrt(np.finfo(np.float64).eps) + * if isinstance(p, np.ndarray): # <<<<<<<<<<<<<< + * if np.issubdtype(p.dtype, np.floating): + * atol = max(atol, np.sqrt(np.finfo(p.dtype).eps)) + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1132, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_ndarray); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1132, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_5 = PyObject_IsInstance(__pyx_v_p, __pyx_t_3); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(0, 1132, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_11 = (__pyx_t_5 != 0); + if (__pyx_t_11) { + + /* "mtrand.pyx":1133 + * atol = np.sqrt(np.finfo(np.float64).eps) + * if isinstance(p, np.ndarray): + * if np.issubdtype(p.dtype, np.floating): # <<<<<<<<<<<<<< + * atol = max(atol, np.sqrt(np.finfo(p.dtype).eps)) + * + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_issubdtype); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_v_p, __pyx_n_s_dtype); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_floating); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_10 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_14))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_14); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_14); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_14, function); + __pyx_t_10 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_14)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_t_9, __pyx_t_1}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_14, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_14)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_t_9, __pyx_t_1}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_14, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_13 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_13, 0+__pyx_t_10, __pyx_t_9); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_13, 1+__pyx_t_10, __pyx_t_1); + __pyx_t_9 = 0; + __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_14, __pyx_t_13, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1133, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_11) { + + /* "mtrand.pyx":1134 + * if isinstance(p, np.ndarray): + * if np.issubdtype(p.dtype, np.floating): + * atol = max(atol, np.sqrt(np.finfo(p.dtype).eps)) # <<<<<<<<<<<<<< + * + * p = PyArray_ContiguousFromObject(p, NPY_DOUBLE, 1, 1) + */ + __pyx_t_14 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_14, __pyx_n_s_sqrt); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_finfo); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_p, __pyx_n_s_dtype); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_2) { + __pyx_t_14 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_14); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_1}; + __pyx_t_14 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_1}; + __pyx_t_14 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_4, NULL); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_14, __pyx_n_s_eps); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_14 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_13))) { + __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_13); + if (likely(__pyx_t_14)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_13); + __Pyx_INCREF(__pyx_t_14); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_13, function); + } + } + if (!__pyx_t_14) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_13, __pyx_t_9); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_13)) { + PyObject *__pyx_temp[2] = {__pyx_t_14, __pyx_t_9}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_13, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_13)) { + PyObject *__pyx_temp[2] = {__pyx_t_14, __pyx_t_9}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_13, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_14); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_14); __pyx_t_14 = NULL; + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_9); + __pyx_t_9 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_INCREF(__pyx_v_atol); + __pyx_t_13 = __pyx_v_atol; + __pyx_t_9 = PyObject_RichCompare(__pyx_t_3, __pyx_t_13, Py_GT); __Pyx_XGOTREF(__pyx_t_9); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1134, __pyx_L1_error) + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_9); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1134, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (__pyx_t_11) { + __Pyx_INCREF(__pyx_t_3); + __pyx_t_4 = __pyx_t_3; + } else { + __Pyx_INCREF(__pyx_t_13); + __pyx_t_4 = __pyx_t_13; + } + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __pyx_t_4; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF_SET(__pyx_v_atol, __pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":1133 + * atol = np.sqrt(np.finfo(np.float64).eps) + * if isinstance(p, np.ndarray): + * if np.issubdtype(p.dtype, np.floating): # <<<<<<<<<<<<<< + * atol = max(atol, np.sqrt(np.finfo(p.dtype).eps)) + * + */ + } + + /* "mtrand.pyx":1132 + * + * atol = np.sqrt(np.finfo(np.float64).eps) + * if isinstance(p, np.ndarray): # <<<<<<<<<<<<<< + * if np.issubdtype(p.dtype, np.floating): + * atol = max(atol, np.sqrt(np.finfo(p.dtype).eps)) + */ + } + + /* "mtrand.pyx":1136 + * atol = max(atol, np.sqrt(np.finfo(p.dtype).eps)) + * + * p = PyArray_ContiguousFromObject(p, NPY_DOUBLE, 1, 1) # <<<<<<<<<<<<<< + * pix = PyArray_DATA(p) + * + */ + __pyx_t_3 = PyArray_ContiguousFromObject(__pyx_v_p, NPY_DOUBLE, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1136, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __pyx_t_3; + __Pyx_INCREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF_SET(__pyx_v_p, __pyx_t_4); + __pyx_t_4 = 0; + + /* "mtrand.pyx":1137 + * + * p = PyArray_ContiguousFromObject(p, NPY_DOUBLE, 1, 1) + * pix = PyArray_DATA(p) # <<<<<<<<<<<<<< + * + * if p.ndim != 1: + */ + if (!(likely(((__pyx_v_p) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_p, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 1137, __pyx_L1_error) + __pyx_v_pix = ((double *)PyArray_DATA(((PyArrayObject *)__pyx_v_p))); + + /* "mtrand.pyx":1139 + * pix = PyArray_DATA(p) + * + * if p.ndim != 1: # <<<<<<<<<<<<<< + * raise ValueError("p must be 1-dimensional") + * if p.size != pop_size: + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_p, __pyx_n_s_ndim); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1139, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_4, __pyx_int_1, Py_NE); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1139, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1139, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_11)) { + + /* "mtrand.pyx":1140 + * + * if p.ndim != 1: + * raise ValueError("p must be 1-dimensional") # <<<<<<<<<<<<<< + * if p.size != pop_size: + * raise ValueError("a and p must have same size") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__59, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1140, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 1140, __pyx_L1_error) + + /* "mtrand.pyx":1139 + * pix = PyArray_DATA(p) + * + * if p.ndim != 1: # <<<<<<<<<<<<<< + * raise ValueError("p must be 1-dimensional") + * if p.size != pop_size: + */ + } + + /* "mtrand.pyx":1141 + * if p.ndim != 1: + * raise ValueError("p must be 1-dimensional") + * if p.size != pop_size: # <<<<<<<<<<<<<< + * raise ValueError("a and p must have same size") + * if np.logical_or.reduce(p < 0): + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_p, __pyx_n_s_size); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_pop_size, Py_NE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1141, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1141, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(__pyx_t_11)) { + + /* "mtrand.pyx":1142 + * raise ValueError("p must be 1-dimensional") + * if p.size != pop_size: + * raise ValueError("a and p must have same size") # <<<<<<<<<<<<<< + * if np.logical_or.reduce(p < 0): + * raise ValueError("probabilities are not non-negative") + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__60, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 1142, __pyx_L1_error) + + /* "mtrand.pyx":1141 + * if p.ndim != 1: + * raise ValueError("p must be 1-dimensional") + * if p.size != pop_size: # <<<<<<<<<<<<<< + * raise ValueError("a and p must have same size") + * if np.logical_or.reduce(p < 0): + */ + } + + /* "mtrand.pyx":1143 + * if p.size != pop_size: + * raise ValueError("a and p must have same size") + * if np.logical_or.reduce(p < 0): # <<<<<<<<<<<<<< + * raise ValueError("probabilities are not non-negative") + * if abs(kahan_sum(pix, d) - 1.) > atol: + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_logical_or); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_n_s_reduce); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_t_13 = PyObject_RichCompare(__pyx_v_p, __pyx_int_0, Py_LT); __Pyx_XGOTREF(__pyx_t_13); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1143, __pyx_L1_error) + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + if (!__pyx_t_9) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_13); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_13}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_t_13}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } else + #endif + { + __pyx_t_14 = PyTuple_New(1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_9); __pyx_t_9 = NULL; + __Pyx_GIVEREF(__pyx_t_13); + PyTuple_SET_ITEM(__pyx_t_14, 0+1, __pyx_t_13); + __pyx_t_13 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_14, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + } + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1143, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(__pyx_t_11)) { + + /* "mtrand.pyx":1144 + * raise ValueError("a and p must have same size") + * if np.logical_or.reduce(p < 0): + * raise ValueError("probabilities are not non-negative") # <<<<<<<<<<<<<< + * if abs(kahan_sum(pix, d) - 1.) > atol: + * raise ValueError("probabilities do not sum to 1") + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__61, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 1144, __pyx_L1_error) + + /* "mtrand.pyx":1143 + * if p.size != pop_size: + * raise ValueError("a and p must have same size") + * if np.logical_or.reduce(p < 0): # <<<<<<<<<<<<<< + * raise ValueError("probabilities are not non-negative") + * if abs(kahan_sum(pix, d) - 1.) > atol: + */ + } + + /* "mtrand.pyx":1145 + * if np.logical_or.reduce(p < 0): + * raise ValueError("probabilities are not non-negative") + * if abs(kahan_sum(pix, d) - 1.) > atol: # <<<<<<<<<<<<<< + * raise ValueError("probabilities do not sum to 1") + * + */ + __pyx_t_15 = __Pyx_PyInt_As_npy_intp(__pyx_v_d); if (unlikely((__pyx_t_15 == ((npy_intp)-1)) && PyErr_Occurred())) __PYX_ERR(0, 1145, __pyx_L1_error) + __pyx_t_4 = PyFloat_FromDouble(fabs((__pyx_f_6mtrand_kahan_sum(__pyx_v_pix, __pyx_t_15) - 1.))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1145, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_4, __pyx_v_atol, Py_GT); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1145, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1145, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_11)) { + + /* "mtrand.pyx":1146 + * raise ValueError("probabilities are not non-negative") + * if abs(kahan_sum(pix, d) - 1.) > atol: + * raise ValueError("probabilities do not sum to 1") # <<<<<<<<<<<<<< + * + * shape = size + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__62, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1146, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 1146, __pyx_L1_error) + + /* "mtrand.pyx":1145 + * if np.logical_or.reduce(p < 0): + * raise ValueError("probabilities are not non-negative") + * if abs(kahan_sum(pix, d) - 1.) > atol: # <<<<<<<<<<<<<< + * raise ValueError("probabilities do not sum to 1") + * + */ + } + + /* "mtrand.pyx":1128 + * raise ValueError("a must be non-empty") + * + * if p is not None: # <<<<<<<<<<<<<< + * d = len(p) + * + */ + } + + /* "mtrand.pyx":1148 + * raise ValueError("probabilities do not sum to 1") + * + * shape = size # <<<<<<<<<<<<<< + * if shape is not None: + * size = np.prod(shape, dtype=np.intp) + */ + __Pyx_INCREF(__pyx_v_size); + __pyx_v_shape = __pyx_v_size; + + /* "mtrand.pyx":1149 + * + * shape = size + * if shape is not None: # <<<<<<<<<<<<<< + * size = np.prod(shape, dtype=np.intp) + * else: + */ + __pyx_t_11 = (__pyx_v_shape != Py_None); + __pyx_t_5 = (__pyx_t_11 != 0); + if (__pyx_t_5) { + + /* "mtrand.pyx":1150 + * shape = size + * if shape is not None: + * size = np.prod(shape, dtype=np.intp) # <<<<<<<<<<<<<< + * else: + * size = 1 + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_prod); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_shape); + __pyx_t_14 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_13 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_n_s_intp); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + if (PyDict_SetItem(__pyx_t_14, __pyx_n_s_dtype, __pyx_t_9) < 0) __PYX_ERR(0, 1150, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_3, __pyx_t_14); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF_SET(__pyx_v_size, __pyx_t_9); + __pyx_t_9 = 0; + + /* "mtrand.pyx":1149 + * + * shape = size + * if shape is not None: # <<<<<<<<<<<<<< + * size = np.prod(shape, dtype=np.intp) + * else: + */ + goto __pyx_L21; + } + + /* "mtrand.pyx":1152 + * size = np.prod(shape, dtype=np.intp) + * else: + * size = 1 # <<<<<<<<<<<<<< + * + * # Actual sampling + */ + /*else*/ { + __Pyx_INCREF(__pyx_int_1); + __Pyx_DECREF_SET(__pyx_v_size, __pyx_int_1); + } + __pyx_L21:; + + /* "mtrand.pyx":1155 + * + * # Actual sampling + * if replace: # <<<<<<<<<<<<<< + * if p is not None: + * cdf = p.cumsum() + */ + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_v_replace); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 1155, __pyx_L1_error) + if (__pyx_t_5) { + + /* "mtrand.pyx":1156 + * # Actual sampling + * if replace: + * if p is not None: # <<<<<<<<<<<<<< + * cdf = p.cumsum() + * cdf /= cdf[-1] + */ + __pyx_t_5 = (__pyx_v_p != Py_None); + __pyx_t_11 = (__pyx_t_5 != 0); + if (__pyx_t_11) { + + /* "mtrand.pyx":1157 + * if replace: + * if p is not None: + * cdf = p.cumsum() # <<<<<<<<<<<<<< + * cdf /= cdf[-1] + * uniform_samples = self.random_sample(shape) + */ + __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_p, __pyx_n_s_cumsum); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1157, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_14))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_14); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_14); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_14, function); + } + } + if (__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_CallOneArg(__pyx_t_14, __pyx_t_3); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1157, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else { + __pyx_t_9 = __Pyx_PyObject_CallNoArg(__pyx_t_14); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1157, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_v_cdf = __pyx_t_9; + __pyx_t_9 = 0; + + /* "mtrand.pyx":1158 + * if p is not None: + * cdf = p.cumsum() + * cdf /= cdf[-1] # <<<<<<<<<<<<<< + * uniform_samples = self.random_sample(shape) + * idx = cdf.searchsorted(uniform_samples, side='right') + */ + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_cdf, -1L, long, 1, __Pyx_PyInt_From_long, 0, 1, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_14 = __Pyx_PyNumber_InPlaceDivide(__pyx_v_cdf, __pyx_t_9); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF_SET(__pyx_v_cdf, __pyx_t_14); + __pyx_t_14 = 0; + + /* "mtrand.pyx":1159 + * cdf = p.cumsum() + * cdf /= cdf[-1] + * uniform_samples = self.random_sample(shape) # <<<<<<<<<<<<<< + * idx = cdf.searchsorted(uniform_samples, side='right') + * idx = np.array(idx, copy=False) # searchsorted returns a scalar + */ + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_random_sample); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_3) { + __pyx_t_14 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_v_shape); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_shape}; + __pyx_t_14 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1159, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_14); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_shape}; + __pyx_t_14 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1159, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_14); + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_shape); + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_4, NULL); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_v_uniform_samples = __pyx_t_14; + __pyx_t_14 = 0; + + /* "mtrand.pyx":1160 + * cdf /= cdf[-1] + * uniform_samples = self.random_sample(shape) + * idx = cdf.searchsorted(uniform_samples, side='right') # <<<<<<<<<<<<<< + * idx = np.array(idx, copy=False) # searchsorted returns a scalar + * else: + */ + __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_cdf, __pyx_n_s_searchsorted); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_9 = PyTuple_New(1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_INCREF(__pyx_v_uniform_samples); + __Pyx_GIVEREF(__pyx_v_uniform_samples); + PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_v_uniform_samples); + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_side, __pyx_n_s_right) < 0) __PYX_ERR(0, 1160, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_14, __pyx_t_9, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_idx = __pyx_t_3; + __pyx_t_3 = 0; + + /* "mtrand.pyx":1161 + * uniform_samples = self.random_sample(shape) + * idx = cdf.searchsorted(uniform_samples, side='right') + * idx = np.array(idx, copy=False) # searchsorted returns a scalar # <<<<<<<<<<<<<< + * else: + * idx = self.randint(0, pop_size, size=shape) + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_array); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_v_idx); + __Pyx_GIVEREF(__pyx_v_idx); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_idx); + __pyx_t_9 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (PyDict_SetItem(__pyx_t_9, __pyx_n_s_copy, Py_False) < 0) __PYX_ERR(0, 1161, __pyx_L1_error) + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_3, __pyx_t_9); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF_SET(__pyx_v_idx, __pyx_t_14); + __pyx_t_14 = 0; + + /* "mtrand.pyx":1156 + * # Actual sampling + * if replace: + * if p is not None: # <<<<<<<<<<<<<< + * cdf = p.cumsum() + * cdf /= cdf[-1] + */ + goto __pyx_L23; + } + + /* "mtrand.pyx":1163 + * idx = np.array(idx, copy=False) # searchsorted returns a scalar + * else: + * idx = self.randint(0, pop_size, size=shape) # <<<<<<<<<<<<<< + * else: + * if size > pop_size: + */ + /*else*/ { + __pyx_t_14 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_randint); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1163, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_9 = PyTuple_New(2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1163, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_int_0); + __Pyx_INCREF(__pyx_v_pop_size); + __Pyx_GIVEREF(__pyx_v_pop_size); + PyTuple_SET_ITEM(__pyx_t_9, 1, __pyx_v_pop_size); + __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1163, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_size, __pyx_v_shape) < 0) __PYX_ERR(0, 1163, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_14, __pyx_t_9, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1163, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_idx = __pyx_t_4; + __pyx_t_4 = 0; + } + __pyx_L23:; + + /* "mtrand.pyx":1155 + * + * # Actual sampling + * if replace: # <<<<<<<<<<<<<< + * if p is not None: + * cdf = p.cumsum() + */ + goto __pyx_L22; + } + + /* "mtrand.pyx":1165 + * idx = self.randint(0, pop_size, size=shape) + * else: + * if size > pop_size: # <<<<<<<<<<<<<< + * raise ValueError("Cannot take a larger sample than " + * "population when 'replace=False'") + */ + /*else*/ { + __pyx_t_4 = PyObject_RichCompare(__pyx_v_size, __pyx_v_pop_size, Py_GT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1165, __pyx_L1_error) + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1165, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(__pyx_t_11)) { + + /* "mtrand.pyx":1166 + * else: + * if size > pop_size: + * raise ValueError("Cannot take a larger sample than " # <<<<<<<<<<<<<< + * "population when 'replace=False'") + * + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__63, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 1166, __pyx_L1_error) + + /* "mtrand.pyx":1165 + * idx = self.randint(0, pop_size, size=shape) + * else: + * if size > pop_size: # <<<<<<<<<<<<<< + * raise ValueError("Cannot take a larger sample than " + * "population when 'replace=False'") + */ + } + + /* "mtrand.pyx":1169 + * "population when 'replace=False'") + * + * if p is not None: # <<<<<<<<<<<<<< + * if np.count_nonzero(p > 0) < size: + * raise ValueError("Fewer non-zero entries in p than size") + */ + __pyx_t_11 = (__pyx_v_p != Py_None); + __pyx_t_5 = (__pyx_t_11 != 0); + if (__pyx_t_5) { + + /* "mtrand.pyx":1170 + * + * if p is not None: + * if np.count_nonzero(p > 0) < size: # <<<<<<<<<<<<<< + * raise ValueError("Fewer non-zero entries in p than size") + * n_uniq = 0 + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_count_nonzero); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyObject_RichCompare(__pyx_v_p, __pyx_int_0, Py_GT); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1170, __pyx_L1_error) + __pyx_t_14 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_14)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_14); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_14) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_14, __pyx_t_3}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_14, __pyx_t_3}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_13 = PyTuple_New(1+1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_GIVEREF(__pyx_t_14); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_14); __pyx_t_14 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_13, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_13, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = PyObject_RichCompare(__pyx_t_4, __pyx_v_size, Py_LT); __Pyx_XGOTREF(__pyx_t_9); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_9); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 1170, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":1171 + * if p is not None: + * if np.count_nonzero(p > 0) < size: + * raise ValueError("Fewer non-zero entries in p than size") # <<<<<<<<<<<<<< + * n_uniq = 0 + * p = p.copy() + */ + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__64, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1171, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_Raise(__pyx_t_9, 0, 0, 0); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __PYX_ERR(0, 1171, __pyx_L1_error) + + /* "mtrand.pyx":1170 + * + * if p is not None: + * if np.count_nonzero(p > 0) < size: # <<<<<<<<<<<<<< + * raise ValueError("Fewer non-zero entries in p than size") + * n_uniq = 0 + */ + } + + /* "mtrand.pyx":1172 + * if np.count_nonzero(p > 0) < size: + * raise ValueError("Fewer non-zero entries in p than size") + * n_uniq = 0 # <<<<<<<<<<<<<< + * p = p.copy() + * found = np.zeros(shape, dtype=np.int) + */ + __Pyx_INCREF(__pyx_int_0); + __pyx_v_n_uniq = __pyx_int_0; + + /* "mtrand.pyx":1173 + * raise ValueError("Fewer non-zero entries in p than size") + * n_uniq = 0 + * p = p.copy() # <<<<<<<<<<<<<< + * found = np.zeros(shape, dtype=np.int) + * flat_found = found.ravel() + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_p, __pyx_n_s_copy); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1173, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_13 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_13 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_13)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_13); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_13) { + __pyx_t_9 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_13); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1173, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } else { + __pyx_t_9 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1173, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF_SET(__pyx_v_p, __pyx_t_9); + __pyx_t_9 = 0; + + /* "mtrand.pyx":1174 + * n_uniq = 0 + * p = p.copy() + * found = np.zeros(shape, dtype=np.int) # <<<<<<<<<<<<<< + * flat_found = found.ravel() + * while n_uniq < size: + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_zeros); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = PyTuple_New(1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_v_shape); + __pyx_t_13 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_int); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PyDict_SetItem(__pyx_t_13, __pyx_n_s_dtype, __pyx_t_14) < 0) __PYX_ERR(0, 1174, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_9, __pyx_t_13); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_v_found = __pyx_t_14; + __pyx_t_14 = 0; + + /* "mtrand.pyx":1175 + * p = p.copy() + * found = np.zeros(shape, dtype=np.int) + * flat_found = found.ravel() # <<<<<<<<<<<<<< + * while n_uniq < size: + * x = self.rand(size - n_uniq) + */ + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_v_found, __pyx_n_s_ravel); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1175, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_13))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_13); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_13); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_13, function); + } + } + if (__pyx_t_9) { + __pyx_t_14 = __Pyx_PyObject_CallOneArg(__pyx_t_13, __pyx_t_9); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1175, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else { + __pyx_t_14 = __Pyx_PyObject_CallNoArg(__pyx_t_13); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1175, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_v_flat_found = __pyx_t_14; + __pyx_t_14 = 0; + + /* "mtrand.pyx":1176 + * found = np.zeros(shape, dtype=np.int) + * flat_found = found.ravel() + * while n_uniq < size: # <<<<<<<<<<<<<< + * x = self.rand(size - n_uniq) + * if n_uniq > 0: + */ + while (1) { + __pyx_t_14 = PyObject_RichCompare(__pyx_v_n_uniq, __pyx_v_size, Py_LT); __Pyx_XGOTREF(__pyx_t_14); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1176, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_14); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 1176, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + if (!__pyx_t_5) break; + + /* "mtrand.pyx":1177 + * flat_found = found.ravel() + * while n_uniq < size: + * x = self.rand(size - n_uniq) # <<<<<<<<<<<<<< + * if n_uniq > 0: + * p[flat_found[0:n_uniq]] = 0 + */ + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_rand); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1177, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_9 = PyNumber_Subtract(__pyx_v_size, __pyx_v_n_uniq); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1177, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_4 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_13))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_13); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_13); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_13, function); + } + } + if (!__pyx_t_4) { + __pyx_t_14 = __Pyx_PyObject_CallOneArg(__pyx_t_13, __pyx_t_9); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1177, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_14); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_13)) { + PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_9}; + __pyx_t_14 = __Pyx_PyFunction_FastCall(__pyx_t_13, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1177, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_13)) { + PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_9}; + __pyx_t_14 = __Pyx_PyCFunction_FastCall(__pyx_t_13, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1177, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1177, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4); __pyx_t_4 = NULL; + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_t_9); + __pyx_t_9 = 0; + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_t_3, NULL); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1177, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + } + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_XDECREF_SET(__pyx_v_x, __pyx_t_14); + __pyx_t_14 = 0; + + /* "mtrand.pyx":1178 + * while n_uniq < size: + * x = self.rand(size - n_uniq) + * if n_uniq > 0: # <<<<<<<<<<<<<< + * p[flat_found[0:n_uniq]] = 0 + * cdf = np.cumsum(p) + */ + __pyx_t_14 = PyObject_RichCompare(__pyx_v_n_uniq, __pyx_int_0, Py_GT); __Pyx_XGOTREF(__pyx_t_14); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1178, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_14); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 1178, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + if (__pyx_t_5) { + + /* "mtrand.pyx":1179 + * x = self.rand(size - n_uniq) + * if n_uniq > 0: + * p[flat_found[0:n_uniq]] = 0 # <<<<<<<<<<<<<< + * cdf = np.cumsum(p) + * cdf /= cdf[-1] + */ + __pyx_t_14 = __Pyx_PyObject_GetSlice(__pyx_v_flat_found, 0, 0, NULL, &__pyx_v_n_uniq, NULL, 1, 0, 1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1179, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + if (unlikely(PyObject_SetItem(__pyx_v_p, __pyx_t_14, __pyx_int_0) < 0)) __PYX_ERR(0, 1179, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + + /* "mtrand.pyx":1178 + * while n_uniq < size: + * x = self.rand(size - n_uniq) + * if n_uniq > 0: # <<<<<<<<<<<<<< + * p[flat_found[0:n_uniq]] = 0 + * cdf = np.cumsum(p) + */ + } + + /* "mtrand.pyx":1180 + * if n_uniq > 0: + * p[flat_found[0:n_uniq]] = 0 + * cdf = np.cumsum(p) # <<<<<<<<<<<<<< + * cdf /= cdf[-1] + * new = cdf.searchsorted(x, side='right') + */ + __pyx_t_13 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_n_s_cumsum); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_t_13 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_13 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_13)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_13); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + if (!__pyx_t_13) { + __pyx_t_14 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_p); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_13, __pyx_v_p}; + __pyx_t_14 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1180, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_GOTREF(__pyx_t_14); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_13, __pyx_v_p}; + __pyx_t_14 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1180, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_GOTREF(__pyx_t_14); + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_13); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_13); __pyx_t_13 = NULL; + __Pyx_INCREF(__pyx_v_p); + __Pyx_GIVEREF(__pyx_v_p); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_p); + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF_SET(__pyx_v_cdf, __pyx_t_14); + __pyx_t_14 = 0; + + /* "mtrand.pyx":1181 + * p[flat_found[0:n_uniq]] = 0 + * cdf = np.cumsum(p) + * cdf /= cdf[-1] # <<<<<<<<<<<<<< + * new = cdf.searchsorted(x, side='right') + * _, unique_indices = np.unique(new, return_index=True) + */ + __pyx_t_14 = __Pyx_GetItemInt(__pyx_v_cdf, -1L, long, 1, __Pyx_PyInt_From_long, 0, 1, 1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_3 = __Pyx_PyNumber_InPlaceDivide(__pyx_v_cdf, __pyx_t_14); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF_SET(__pyx_v_cdf, __pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":1182 + * cdf = np.cumsum(p) + * cdf /= cdf[-1] + * new = cdf.searchsorted(x, side='right') # <<<<<<<<<<<<<< + * _, unique_indices = np.unique(new, return_index=True) + * unique_indices.sort() + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_cdf, __pyx_n_s_searchsorted); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_14 = PyTuple_New(1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_INCREF(__pyx_v_x); + __Pyx_GIVEREF(__pyx_v_x); + PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_v_x); + __pyx_t_9 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (PyDict_SetItem(__pyx_t_9, __pyx_n_s_side, __pyx_n_s_right) < 0) __PYX_ERR(0, 1182, __pyx_L1_error) + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_14, __pyx_t_9); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF_SET(__pyx_v_new, __pyx_t_13); + __pyx_t_13 = 0; + + /* "mtrand.pyx":1183 + * cdf /= cdf[-1] + * new = cdf.searchsorted(x, side='right') + * _, unique_indices = np.unique(new, return_index=True) # <<<<<<<<<<<<<< + * unique_indices.sort() + * new = new.take(unique_indices) + */ + __pyx_t_13 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_n_s_unique); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_t_13 = PyTuple_New(1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_INCREF(__pyx_v_new); + __Pyx_GIVEREF(__pyx_v_new); + PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_v_new); + __pyx_t_14 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + if (PyDict_SetItem(__pyx_t_14, __pyx_n_s_return_index, Py_True) < 0) __PYX_ERR(0, 1183, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_13, __pyx_t_14); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) { + PyObject* sequence = __pyx_t_3; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 1183, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_14 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_13 = PyTuple_GET_ITEM(sequence, 1); + } else { + __pyx_t_14 = PyList_GET_ITEM(sequence, 0); + __pyx_t_13 = PyList_GET_ITEM(sequence, 1); + } + __Pyx_INCREF(__pyx_t_14); + __Pyx_INCREF(__pyx_t_13); + #else + __pyx_t_14 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_13 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + #endif + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_9 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_16 = Py_TYPE(__pyx_t_9)->tp_iternext; + index = 0; __pyx_t_14 = __pyx_t_16(__pyx_t_9); if (unlikely(!__pyx_t_14)) goto __pyx_L30_unpacking_failed; + __Pyx_GOTREF(__pyx_t_14); + index = 1; __pyx_t_13 = __pyx_t_16(__pyx_t_9); if (unlikely(!__pyx_t_13)) goto __pyx_L30_unpacking_failed; + __Pyx_GOTREF(__pyx_t_13); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_16(__pyx_t_9), 2) < 0) __PYX_ERR(0, 1183, __pyx_L1_error) + __pyx_t_16 = NULL; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L31_unpacking_done; + __pyx_L30_unpacking_failed:; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_16 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 1183, __pyx_L1_error) + __pyx_L31_unpacking_done:; + } + __Pyx_XDECREF_SET(__pyx_v__, __pyx_t_14); + __pyx_t_14 = 0; + __Pyx_XDECREF_SET(__pyx_v_unique_indices, __pyx_t_13); + __pyx_t_13 = 0; + + /* "mtrand.pyx":1184 + * new = cdf.searchsorted(x, side='right') + * _, unique_indices = np.unique(new, return_index=True) + * unique_indices.sort() # <<<<<<<<<<<<<< + * new = new.take(unique_indices) + * flat_found[n_uniq:n_uniq + new.size] = new + */ + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_v_unique_indices, __pyx_n_s_sort); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1184, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_14 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_13))) { + __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_13); + if (likely(__pyx_t_14)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_13); + __Pyx_INCREF(__pyx_t_14); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_13, function); + } + } + if (__pyx_t_14) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_13, __pyx_t_14); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1184, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_13); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1184, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "mtrand.pyx":1185 + * _, unique_indices = np.unique(new, return_index=True) + * unique_indices.sort() + * new = new.take(unique_indices) # <<<<<<<<<<<<<< + * flat_found[n_uniq:n_uniq + new.size] = new + * n_uniq += new.size + */ + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_v_new, __pyx_n_s_take); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_14 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_13))) { + __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_13); + if (likely(__pyx_t_14)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_13); + __Pyx_INCREF(__pyx_t_14); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_13, function); + } + } + if (!__pyx_t_14) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_13, __pyx_v_unique_indices); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_13)) { + PyObject *__pyx_temp[2] = {__pyx_t_14, __pyx_v_unique_indices}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_13, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1185, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_13)) { + PyObject *__pyx_temp[2] = {__pyx_t_14, __pyx_v_unique_indices}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_13, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1185, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_14); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_14); __pyx_t_14 = NULL; + __Pyx_INCREF(__pyx_v_unique_indices); + __Pyx_GIVEREF(__pyx_v_unique_indices); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_unique_indices); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF_SET(__pyx_v_new, __pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":1186 + * unique_indices.sort() + * new = new.take(unique_indices) + * flat_found[n_uniq:n_uniq + new.size] = new # <<<<<<<<<<<<<< + * n_uniq += new.size + * idx = found + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_new, __pyx_n_s_size); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1186, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_13 = PyNumber_Add(__pyx_v_n_uniq, __pyx_t_3); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1186, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__Pyx_PyObject_SetSlice(__pyx_v_flat_found, __pyx_v_new, 0, 0, &__pyx_v_n_uniq, &__pyx_t_13, NULL, 0, 0, 1) < 0) __PYX_ERR(0, 1186, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + + /* "mtrand.pyx":1187 + * new = new.take(unique_indices) + * flat_found[n_uniq:n_uniq + new.size] = new + * n_uniq += new.size # <<<<<<<<<<<<<< + * idx = found + * else: + */ + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_v_new, __pyx_n_s_size); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_3 = PyNumber_InPlaceAdd(__pyx_v_n_uniq, __pyx_t_13); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF_SET(__pyx_v_n_uniq, __pyx_t_3); + __pyx_t_3 = 0; + } + + /* "mtrand.pyx":1188 + * flat_found[n_uniq:n_uniq + new.size] = new + * n_uniq += new.size + * idx = found # <<<<<<<<<<<<<< + * else: + * idx = self.permutation(pop_size)[:size] + */ + __Pyx_INCREF(__pyx_v_found); + __pyx_v_idx = __pyx_v_found; + + /* "mtrand.pyx":1169 + * "population when 'replace=False'") + * + * if p is not None: # <<<<<<<<<<<<<< + * if np.count_nonzero(p > 0) < size: + * raise ValueError("Fewer non-zero entries in p than size") + */ + goto __pyx_L25; + } + + /* "mtrand.pyx":1190 + * idx = found + * else: + * idx = self.permutation(pop_size)[:size] # <<<<<<<<<<<<<< + * if shape is not None: + * idx.shape = shape + */ + /*else*/ { + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_permutation); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_13))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_13); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_13); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_13, function); + } + } + if (!__pyx_t_9) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_13, __pyx_v_pop_size); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_13)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_v_pop_size}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_13, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1190, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_13)) { + PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_v_pop_size}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_13, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1190, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_14 = PyTuple_New(1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_9); __pyx_t_9 = NULL; + __Pyx_INCREF(__pyx_v_pop_size); + __Pyx_GIVEREF(__pyx_v_pop_size); + PyTuple_SET_ITEM(__pyx_t_14, 0+1, __pyx_v_pop_size); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_t_14, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + } + } + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_t_13 = __Pyx_PyObject_GetSlice(__pyx_t_3, 0, 0, NULL, &__pyx_v_size, NULL, 0, 0, 1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_idx = __pyx_t_13; + __pyx_t_13 = 0; + + /* "mtrand.pyx":1191 + * else: + * idx = self.permutation(pop_size)[:size] + * if shape is not None: # <<<<<<<<<<<<<< + * idx.shape = shape + * + */ + __pyx_t_5 = (__pyx_v_shape != Py_None); + __pyx_t_11 = (__pyx_t_5 != 0); + if (__pyx_t_11) { + + /* "mtrand.pyx":1192 + * idx = self.permutation(pop_size)[:size] + * if shape is not None: + * idx.shape = shape # <<<<<<<<<<<<<< + * + * if shape is None and isinstance(idx, np.ndarray): + */ + if (__Pyx_PyObject_SetAttrStr(__pyx_v_idx, __pyx_n_s_shape, __pyx_v_shape) < 0) __PYX_ERR(0, 1192, __pyx_L1_error) + + /* "mtrand.pyx":1191 + * else: + * idx = self.permutation(pop_size)[:size] + * if shape is not None: # <<<<<<<<<<<<<< + * idx.shape = shape + * + */ + } + } + __pyx_L25:; + } + __pyx_L22:; + + /* "mtrand.pyx":1194 + * idx.shape = shape + * + * if shape is None and isinstance(idx, np.ndarray): # <<<<<<<<<<<<<< + * # In most cases a scalar will have been made an array + * idx = idx.item(0) + */ + __pyx_t_5 = (__pyx_v_shape == Py_None); + __pyx_t_17 = (__pyx_t_5 != 0); + if (__pyx_t_17) { + } else { + __pyx_t_11 = __pyx_t_17; + goto __pyx_L34_bool_binop_done; + } + __pyx_t_13 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1194, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_n_s_ndarray); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1194, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_t_17 = PyObject_IsInstance(__pyx_v_idx, __pyx_t_3); if (unlikely(__pyx_t_17 == ((int)-1))) __PYX_ERR(0, 1194, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_5 = (__pyx_t_17 != 0); + __pyx_t_11 = __pyx_t_5; + __pyx_L34_bool_binop_done:; + if (__pyx_t_11) { + + /* "mtrand.pyx":1196 + * if shape is None and isinstance(idx, np.ndarray): + * # In most cases a scalar will have been made an array + * idx = idx.item(0) # <<<<<<<<<<<<<< + * + * #Use samples as indices for a if a is array-like + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_idx, __pyx_n_s_item); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__65, NULL); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF_SET(__pyx_v_idx, __pyx_t_13); + __pyx_t_13 = 0; + + /* "mtrand.pyx":1194 + * idx.shape = shape + * + * if shape is None and isinstance(idx, np.ndarray): # <<<<<<<<<<<<<< + * # In most cases a scalar will have been made an array + * idx = idx.item(0) + */ + } + + /* "mtrand.pyx":1199 + * + * #Use samples as indices for a if a is array-like + * if a.ndim == 0: # <<<<<<<<<<<<<< + * return idx + * + */ + __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_v_a, __pyx_n_s_ndim); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1199, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_3 = __Pyx_PyInt_EqObjC(__pyx_t_13, __pyx_int_0, 0, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1199, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_11 < 0)) __PYX_ERR(0, 1199, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_11) { + + /* "mtrand.pyx":1200 + * #Use samples as indices for a if a is array-like + * if a.ndim == 0: + * return idx # <<<<<<<<<<<<<< + * + * if shape is not None and idx.ndim == 0: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_idx); + __pyx_r = __pyx_v_idx; + goto __pyx_L0; + + /* "mtrand.pyx":1199 + * + * #Use samples as indices for a if a is array-like + * if a.ndim == 0: # <<<<<<<<<<<<<< + * return idx + * + */ + } + + /* "mtrand.pyx":1202 + * return idx + * + * if shape is not None and idx.ndim == 0: # <<<<<<<<<<<<<< + * # If size == () then the user requested a 0-d array as opposed to + * # a scalar object when size is None. However a[idx] is always a + */ + __pyx_t_5 = (__pyx_v_shape != Py_None); + __pyx_t_17 = (__pyx_t_5 != 0); + if (__pyx_t_17) { + } else { + __pyx_t_11 = __pyx_t_17; + goto __pyx_L38_bool_binop_done; + } + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_idx, __pyx_n_s_ndim); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_13 = __Pyx_PyInt_EqObjC(__pyx_t_3, __pyx_int_0, 0, 0); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_17 = __Pyx_PyObject_IsTrue(__pyx_t_13); if (unlikely(__pyx_t_17 < 0)) __PYX_ERR(0, 1202, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_t_11 = __pyx_t_17; + __pyx_L38_bool_binop_done:; + if (__pyx_t_11) { + + /* "mtrand.pyx":1208 + * # array, taking into account that np.array(item) may not work + * # for object arrays. + * res = np.empty((), dtype=a.dtype) # <<<<<<<<<<<<<< + * res[()] = a[idx] + * return res + */ + __pyx_t_13 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_t_13 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 1208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_a, __pyx_n_s_dtype); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + if (PyDict_SetItem(__pyx_t_13, __pyx_n_s_dtype, __pyx_t_14) < 0) __PYX_ERR(0, 1208, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__66, __pyx_t_13); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __pyx_v_res = __pyx_t_14; + __pyx_t_14 = 0; + + /* "mtrand.pyx":1209 + * # for object arrays. + * res = np.empty((), dtype=a.dtype) + * res[()] = a[idx] # <<<<<<<<<<<<<< + * return res + * + */ + __pyx_t_14 = __Pyx_PyObject_GetItem(__pyx_v_a, __pyx_v_idx); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + if (unlikely(PyObject_SetItem(__pyx_v_res, __pyx_empty_tuple, __pyx_t_14) < 0)) __PYX_ERR(0, 1209, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + + /* "mtrand.pyx":1210 + * res = np.empty((), dtype=a.dtype) + * res[()] = a[idx] + * return res # <<<<<<<<<<<<<< + * + * return a[idx] + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "mtrand.pyx":1202 + * return idx + * + * if shape is not None and idx.ndim == 0: # <<<<<<<<<<<<<< + * # If size == () then the user requested a 0-d array as opposed to + * # a scalar object when size is None. However a[idx] is always a + */ + } + + /* "mtrand.pyx":1212 + * return res + * + * return a[idx] # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_14 = __Pyx_PyObject_GetItem(__pyx_v_a, __pyx_v_idx); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 1212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_r = __pyx_t_14; + __pyx_t_14 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1033 + * + * + * def choice(self, a, size=None, replace=True, p=None): # <<<<<<<<<<<<<< + * """ + * choice(a, size=None, replace=True, p=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_13); + __Pyx_XDECREF(__pyx_t_14); + __Pyx_AddTraceback("mtrand.RandomState.choice", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_pop_size); + __Pyx_XDECREF(__pyx_v_d); + __Pyx_XDECREF(__pyx_v_atol); + __Pyx_XDECREF(__pyx_v_shape); + __Pyx_XDECREF(__pyx_v_cdf); + __Pyx_XDECREF(__pyx_v_uniform_samples); + __Pyx_XDECREF(__pyx_v_idx); + __Pyx_XDECREF(__pyx_v_n_uniq); + __Pyx_XDECREF(__pyx_v_found); + __Pyx_XDECREF(__pyx_v_flat_found); + __Pyx_XDECREF(__pyx_v_x); + __Pyx_XDECREF(__pyx_v_new); + __Pyx_XDECREF(__pyx_v__); + __Pyx_XDECREF(__pyx_v_unique_indices); + __Pyx_XDECREF(__pyx_v_res); + __Pyx_XDECREF(__pyx_v_a); + __Pyx_XDECREF(__pyx_v_size); + __Pyx_XDECREF(__pyx_v_p); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1215 + * + * + * def uniform(self, low=0.0, high=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * uniform(low=0.0, high=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_27uniform(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_26uniform[] = "\n uniform(low=0.0, high=1.0, size=None)\n\n Draw samples from a uniform distribution.\n\n Samples are uniformly distributed over the half-open interval\n ``[low, high)`` (includes low, but excludes high). In other words,\n any value within the given interval is equally likely to be drawn\n by `uniform`.\n\n Parameters\n ----------\n low : float or array_like of floats, optional\n Lower boundary of the output interval. All values generated will be\n greater than or equal to low. The default value is 0.\n high : float or array_like of floats\n Upper boundary of the output interval. All values generated will be\n less than high. The default value is 1.0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``low`` and ``high`` are both scalars.\n Otherwise, ``np.broadcast(low, high).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized uniform distribution.\n\n See Also\n --------\n randint : Discrete uniform distribution, yielding integers.\n random_integers : Discrete uniform distribution over the closed\n interval ``[low, high]``.\n random_sample : Floats uniformly distributed over ``[0, 1)``.\n random : Alias for `random_sample`.\n rand : Convenience function that accepts dimensions as input, e.g.,\n ``rand(2,2)`` would generate a 2-by-2 array of floats,\n uniformly distributed over ``[0, 1)``.\n\n Notes\n -----\n The probability density function of the uniform distribution is\n\n .. math:: p(x) = \\frac{1}{b - a}\n\n anywhe""re within the interval ``[a, b)``, and zero elsewhere.\n\n When ``high`` == ``low``, values of ``low`` will be returned.\n If ``high`` < ``low``, the results are officially undefined\n and may eventually raise an error, i.e. do not rely on this\n function to behave when passed arguments satisfying that\n inequality condition.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> s = np.random.uniform(-1,0,1000)\n\n All values are within the given interval:\n\n >>> np.all(s >= -1)\n True\n >>> np.all(s < 0)\n True\n\n Display the histogram of the samples, along with the\n probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 15, normed=True)\n >>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_27uniform(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("uniform (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[0] = ((PyObject *)__pyx_float_0_0); + values[1] = ((PyObject *)__pyx_float_1_0); + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "uniform") < 0)) __PYX_ERR(0, 1215, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("uniform", 0, 0, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1215, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.uniform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_26uniform(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_low, __pyx_v_high, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_26uniform(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_olow = 0; + PyArrayObject *__pyx_v_ohigh = 0; + PyArrayObject *__pyx_v_odiff = 0; + double __pyx_v_flow; + double __pyx_v_fhigh; + double __pyx_v_fscale; + PyObject *__pyx_v_temp = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + __Pyx_RefNannySetupContext("uniform", 0); + + /* "mtrand.pyx":1296 + * cdef object temp + * + * olow = PyArray_FROM_OTF(low, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * ohigh = PyArray_FROM_OTF(high, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_low, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1296, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_olow = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":1297 + * + * olow = PyArray_FROM_OTF(low, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * ohigh = PyArray_FROM_OTF(high, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if olow.shape == ohigh.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_high, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1297, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_ohigh = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":1299 + * ohigh = PyArray_FROM_OTF(high, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if olow.shape == ohigh.shape == (): # <<<<<<<<<<<<<< + * flow = PyFloat_AsDouble(low) + * fhigh = PyFloat_AsDouble(high) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_olow), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1299, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_ohigh), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1299, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1299, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1299, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1299, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":1300 + * + * if olow.shape == ohigh.shape == (): + * flow = PyFloat_AsDouble(low) # <<<<<<<<<<<<<< + * fhigh = PyFloat_AsDouble(high) + * fscale = fhigh - flow + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_low); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1300, __pyx_L1_error) + __pyx_v_flow = __pyx_t_5; + + /* "mtrand.pyx":1301 + * if olow.shape == ohigh.shape == (): + * flow = PyFloat_AsDouble(low) + * fhigh = PyFloat_AsDouble(high) # <<<<<<<<<<<<<< + * fscale = fhigh - flow + * + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_high); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1301, __pyx_L1_error) + __pyx_v_fhigh = __pyx_t_5; + + /* "mtrand.pyx":1302 + * flow = PyFloat_AsDouble(low) + * fhigh = PyFloat_AsDouble(high) + * fscale = fhigh - flow # <<<<<<<<<<<<<< + * + * if not npy_isfinite(fscale): + */ + __pyx_v_fscale = (__pyx_v_fhigh - __pyx_v_flow); + + /* "mtrand.pyx":1304 + * fscale = fhigh - flow + * + * if not npy_isfinite(fscale): # <<<<<<<<<<<<<< + * raise OverflowError('Range exceeds valid bounds') + * + */ + __pyx_t_4 = ((!(npy_isfinite(__pyx_v_fscale) != 0)) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1305 + * + * if not npy_isfinite(fscale): + * raise OverflowError('Range exceeds valid bounds') # <<<<<<<<<<<<<< + * + * return cont2_array_sc(self.internal_state, rk_uniform, size, flow, + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_OverflowError, __pyx_tuple__67, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1305, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 1305, __pyx_L1_error) + + /* "mtrand.pyx":1304 + * fscale = fhigh - flow + * + * if not npy_isfinite(fscale): # <<<<<<<<<<<<<< + * raise OverflowError('Range exceeds valid bounds') + * + */ + } + + /* "mtrand.pyx":1307 + * raise OverflowError('Range exceeds valid bounds') + * + * return cont2_array_sc(self.internal_state, rk_uniform, size, flow, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1308 + * + * return cont2_array_sc(self.internal_state, rk_uniform, size, flow, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * temp = np.subtract(ohigh, olow) + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":1307 + * raise OverflowError('Range exceeds valid bounds') + * + * return cont2_array_sc(self.internal_state, rk_uniform, size, flow, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_uniform, __pyx_v_size, __pyx_v_flow, __pyx_v_fscale, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1307, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1299 + * ohigh = PyArray_FROM_OTF(high, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if olow.shape == ohigh.shape == (): # <<<<<<<<<<<<<< + * flow = PyFloat_AsDouble(low) + * fhigh = PyFloat_AsDouble(high) + */ + } + + /* "mtrand.pyx":1310 + * fscale, self.lock) + * + * temp = np.subtract(ohigh, olow) # <<<<<<<<<<<<<< + * Py_INCREF(temp) # needed to get around Pyrex's automatic reference-counting + * # rules because EnsureArray steals a reference + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_subtract); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_6 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_6 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_ohigh), ((PyObject *)__pyx_v_olow)}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_6, 2+__pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1310, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_ohigh), ((PyObject *)__pyx_v_olow)}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_6, 2+__pyx_t_6); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1310, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_7 = PyTuple_New(2+__pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_ohigh)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ohigh)); + PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_6, ((PyObject *)__pyx_v_ohigh)); + __Pyx_INCREF(((PyObject *)__pyx_v_olow)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_olow)); + PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_6, ((PyObject *)__pyx_v_olow)); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_temp = __pyx_t_2; + __pyx_t_2 = 0; + + /* "mtrand.pyx":1311 + * + * temp = np.subtract(ohigh, olow) + * Py_INCREF(temp) # needed to get around Pyrex's automatic reference-counting # <<<<<<<<<<<<<< + * # rules because EnsureArray steals a reference + * odiff = PyArray_EnsureArray(temp) + */ + Py_INCREF(__pyx_v_temp); + + /* "mtrand.pyx":1313 + * Py_INCREF(temp) # needed to get around Pyrex's automatic reference-counting + * # rules because EnsureArray steals a reference + * odiff = PyArray_EnsureArray(temp) # <<<<<<<<<<<<<< + * + * if not np.all(np.isfinite(odiff)): + */ + __pyx_t_2 = PyArray_EnsureArray(__pyx_v_temp); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1313, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_odiff = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":1315 + * odiff = PyArray_EnsureArray(temp) + * + * if not np.all(np.isfinite(odiff)): # <<<<<<<<<<<<<< + * raise OverflowError('Range exceeds valid bounds') + * + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_all); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_isfinite); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (!__pyx_t_3) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_8, ((PyObject *)__pyx_v_odiff)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, ((PyObject *)__pyx_v_odiff)}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, ((PyObject *)__pyx_v_odiff)}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_odiff)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_odiff)); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, ((PyObject *)__pyx_v_odiff)); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_8) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1315, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_10 = ((!__pyx_t_4) != 0); + if (unlikely(__pyx_t_10)) { + + /* "mtrand.pyx":1316 + * + * if not np.all(np.isfinite(odiff)): + * raise OverflowError('Range exceeds valid bounds') # <<<<<<<<<<<<<< + * + * return cont2_array(self.internal_state, rk_uniform, size, olow, odiff, + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_OverflowError, __pyx_tuple__68, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 1316, __pyx_L1_error) + + /* "mtrand.pyx":1315 + * odiff = PyArray_EnsureArray(temp) + * + * if not np.all(np.isfinite(odiff)): # <<<<<<<<<<<<<< + * raise OverflowError('Range exceeds valid bounds') + * + */ + } + + /* "mtrand.pyx":1318 + * raise OverflowError('Range exceeds valid bounds') + * + * return cont2_array(self.internal_state, rk_uniform, size, olow, odiff, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1319 + * + * return cont2_array(self.internal_state, rk_uniform, size, olow, odiff, + * self.lock) # <<<<<<<<<<<<<< + * + * def rand(self, *args): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":1318 + * raise OverflowError('Range exceeds valid bounds') + * + * return cont2_array(self.internal_state, rk_uniform, size, olow, odiff, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_uniform, __pyx_v_size, __pyx_v_olow, __pyx_v_odiff, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1318, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1215 + * + * + * def uniform(self, low=0.0, high=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * uniform(low=0.0, high=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.uniform", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_olow); + __Pyx_XDECREF((PyObject *)__pyx_v_ohigh); + __Pyx_XDECREF((PyObject *)__pyx_v_odiff); + __Pyx_XDECREF(__pyx_v_temp); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1321 + * self.lock) + * + * def rand(self, *args): # <<<<<<<<<<<<<< + * """ + * rand(d0, d1, ..., dn) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_29rand(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_28rand[] = "\n rand(d0, d1, ..., dn)\n\n Random values in a given shape.\n\n Create an array of the given shape and populate it with\n random samples from a uniform distribution\n over ``[0, 1)``.\n\n Parameters\n ----------\n d0, d1, ..., dn : int, optional\n The dimensions of the returned array, should all be positive.\n If no argument is given a single Python float is returned.\n\n Returns\n -------\n out : ndarray, shape ``(d0, d1, ..., dn)``\n Random values.\n\n See Also\n --------\n random\n\n Notes\n -----\n This is a convenience function. If you want an interface that\n takes a shape-tuple as the first argument, refer to\n np.random.random_sample .\n\n Examples\n --------\n >>> np.random.rand(3,2)\n array([[ 0.14022471, 0.96360618], #random\n [ 0.37601032, 0.25528411], #random\n [ 0.49313049, 0.94909878]]) #random\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_29rand(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_args = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("rand (wrapper)", 0); + if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "rand", 0))) return NULL; + __Pyx_INCREF(__pyx_args); + __pyx_v_args = __pyx_args; + __pyx_r = __pyx_pf_6mtrand_11RandomState_28rand(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_args); + + /* function exit code */ + __Pyx_XDECREF(__pyx_v_args); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_28rand(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_args) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + __Pyx_RefNannySetupContext("rand", 0); + + /* "mtrand.pyx":1360 + * + * """ + * if len(args) == 0: # <<<<<<<<<<<<<< + * return self.random_sample() + * else: + */ + __pyx_t_1 = PyTuple_GET_SIZE(__pyx_v_args); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 1360, __pyx_L1_error) + __pyx_t_2 = ((__pyx_t_1 == 0) != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":1361 + * """ + * if len(args) == 0: + * return self.random_sample() # <<<<<<<<<<<<<< + * else: + * return self.random_sample(size=args) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_random_sample); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1361, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_5) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1361, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1361, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1360 + * + * """ + * if len(args) == 0: # <<<<<<<<<<<<<< + * return self.random_sample() + * else: + */ + } + + /* "mtrand.pyx":1363 + * return self.random_sample() + * else: + * return self.random_sample(size=args) # <<<<<<<<<<<<<< + * + * def randn(self, *args): + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_random_sample); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1363, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1363, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_size, __pyx_v_args) < 0) __PYX_ERR(0, 1363, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_empty_tuple, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1363, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + } + + /* "mtrand.pyx":1321 + * self.lock) + * + * def rand(self, *args): # <<<<<<<<<<<<<< + * """ + * rand(d0, d1, ..., dn) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("mtrand.RandomState.rand", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1365 + * return self.random_sample(size=args) + * + * def randn(self, *args): # <<<<<<<<<<<<<< + * """ + * randn(d0, d1, ..., dn) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_31randn(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_30randn[] = "\n randn(d0, d1, ..., dn)\n\n Return a sample (or samples) from the \"standard normal\" distribution.\n\n If positive, int_like or int-convertible arguments are provided,\n `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled\n with random floats sampled from a univariate \"normal\" (Gaussian)\n distribution of mean 0 and variance 1 (if any of the :math:`d_i` are\n floats, they are first converted to integers by truncation). A single\n float randomly sampled from the distribution is returned if no\n argument is provided.\n\n This is a convenience function. If you want an interface that takes a\n tuple as the first argument, use `numpy.random.standard_normal` instead.\n\n Parameters\n ----------\n d0, d1, ..., dn : int, optional\n The dimensions of the returned array, should be all positive.\n If no argument is given a single Python float is returned.\n\n Returns\n -------\n Z : ndarray or float\n A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from\n the standard normal distribution, or a single such float if\n no parameters were supplied.\n\n See Also\n --------\n random.standard_normal : Similar, but takes a tuple as its argument.\n\n Notes\n -----\n For random samples from :math:`N(\\mu, \\sigma^2)`, use:\n\n ``sigma * np.random.randn(...) + mu``\n\n Examples\n --------\n >>> np.random.randn()\n 2.1923875335537315 #random\n\n Two-by-four array of samples from N(3, 6.25):\n\n >>> 2.5 * np.random.randn(2, 4) + 3\n array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random\n [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_31randn(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_args = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("randn (wrapper)", 0); + if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "randn", 0))) return NULL; + __Pyx_INCREF(__pyx_args); + __pyx_v_args = __pyx_args; + __pyx_r = __pyx_pf_6mtrand_11RandomState_30randn(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_args); + + /* function exit code */ + __Pyx_XDECREF(__pyx_v_args); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_30randn(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_args) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + __Pyx_RefNannySetupContext("randn", 0); + + /* "mtrand.pyx":1417 + * + * """ + * if len(args) == 0: # <<<<<<<<<<<<<< + * return self.standard_normal() + * else: + */ + __pyx_t_1 = PyTuple_GET_SIZE(__pyx_v_args); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 1417, __pyx_L1_error) + __pyx_t_2 = ((__pyx_t_1 == 0) != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":1418 + * """ + * if len(args) == 0: + * return self.standard_normal() # <<<<<<<<<<<<<< + * else: + * return self.standard_normal(args) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_standard_normal); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1418, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_5) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1418, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1418, __pyx_L1_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1417 + * + * """ + * if len(args) == 0: # <<<<<<<<<<<<<< + * return self.standard_normal() + * else: + */ + } + + /* "mtrand.pyx":1420 + * return self.standard_normal() + * else: + * return self.standard_normal(args) # <<<<<<<<<<<<<< + * + * def random_integers(self, low, high=None, size=None): + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_standard_normal); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1420, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (!__pyx_t_5) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_v_args); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1420, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_v_args}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1420, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_v_args}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1420, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1420, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL; + __Pyx_INCREF(__pyx_v_args); + __Pyx_GIVEREF(__pyx_v_args); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_args); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1420, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + } + + /* "mtrand.pyx":1365 + * return self.random_sample(size=args) + * + * def randn(self, *args): # <<<<<<<<<<<<<< + * """ + * randn(d0, d1, ..., dn) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("mtrand.RandomState.randn", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1422 + * return self.standard_normal(args) + * + * def random_integers(self, low, high=None, size=None): # <<<<<<<<<<<<<< + * """ + * random_integers(low, high=None, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_33random_integers(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_32random_integers[] = "\n random_integers(low, high=None, size=None)\n\n Random integers of type np.int between `low` and `high`, inclusive.\n\n Return random integers of type np.int from the \"discrete uniform\"\n distribution in the closed interval [`low`, `high`]. If `high` is\n None (the default), then results are from [1, `low`]. The np.int\n type translates to the C long type used by Python 2 for \"short\"\n integers and its precision is platform dependent.\n\n This function has been deprecated. Use randint instead.\n\n .. deprecated:: 1.11.0\n\n Parameters\n ----------\n low : int\n Lowest (signed) integer to be drawn from the distribution (unless\n ``high=None``, in which case this parameter is the *highest* such\n integer).\n high : int, optional\n If provided, the largest (signed) integer to be drawn from the\n distribution (see above for behavior if ``high=None``).\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : int or ndarray of ints\n `size`-shaped array of random integers from the appropriate\n distribution, or a single such random int if `size` not provided.\n\n See Also\n --------\n random.randint : Similar to `random_integers`, only for the half-open\n interval [`low`, `high`), and 0 is the lowest value if `high` is\n omitted.\n\n Notes\n -----\n To sample from N evenly spaced floating-point numbers between a and b,\n use::\n\n a + (b - a) * (np.random.random_integers(N) - 1) / (N - 1.)\n\n Examples\n --------\n >>> np.random.random_integers(5)\n 4\n >"">> type(np.random.random_integers(5))\n \n >>> np.random.random_integers(5, size=(3,2))\n array([[5, 4],\n [3, 3],\n [4, 5]])\n\n Choose five random numbers from the set of five evenly-spaced\n numbers between 0 and 2.5, inclusive (*i.e.*, from the set\n :math:`{0, 5/8, 10/8, 15/8, 20/8}`):\n\n >>> 2.5 * (np.random.random_integers(5, size=(5,)) - 1) / 4.\n array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ])\n\n Roll two six sided dice 1000 times and sum the results:\n\n >>> d1 = np.random.random_integers(1, 6, 1000)\n >>> d2 = np.random.random_integers(1, 6, 1000)\n >>> dsums = d1 + d2\n\n Display results as a histogram:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(dsums, 11, normed=True)\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_33random_integers(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_low = 0; + PyObject *__pyx_v_high = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("random_integers (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_low,&__pyx_n_s_high,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[1] = ((PyObject *)Py_None); + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_low)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_high); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "random_integers") < 0)) __PYX_ERR(0, 1422, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_low = values[0]; + __pyx_v_high = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("random_integers", 0, 1, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1422, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.random_integers", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_32random_integers(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_low, __pyx_v_high, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_32random_integers(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_low, PyObject *__pyx_v_high, PyObject *__pyx_v_size) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + __Pyx_RefNannySetupContext("random_integers", 0); + __Pyx_INCREF(__pyx_v_low); + __Pyx_INCREF(__pyx_v_high); + + /* "mtrand.pyx":1502 + * + * """ + * if high is None: # <<<<<<<<<<<<<< + * warnings.warn(("This function is deprecated. Please call " + * "randint(1, {low} + 1) instead".format(low=low)), + */ + __pyx_t_1 = (__pyx_v_high == Py_None); + __pyx_t_2 = (__pyx_t_1 != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":1503 + * """ + * if high is None: + * warnings.warn(("This function is deprecated. Please call " # <<<<<<<<<<<<<< + * "randint(1, {low} + 1) instead".format(low=low)), + * DeprecationWarning) + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_warnings); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1503, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_warn); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1503, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "mtrand.pyx":1504 + * if high is None: + * warnings.warn(("This function is deprecated. Please call " + * "randint(1, {low} + 1) instead".format(low=low)), # <<<<<<<<<<<<<< + * DeprecationWarning) + * high = low + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_This_function_is_deprecated_Plea, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1504, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1504, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_low, __pyx_v_low) < 0) __PYX_ERR(0, 1504, __pyx_L1_error) + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_empty_tuple, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1504, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "mtrand.pyx":1505 + * warnings.warn(("This function is deprecated. Please call " + * "randint(1, {low} + 1) instead".format(low=low)), + * DeprecationWarning) # <<<<<<<<<<<<<< + * high = low + * low = 1 + */ + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_t_7, __pyx_builtin_DeprecationWarning}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1503, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_t_7, __pyx_builtin_DeprecationWarning}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1503, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_4 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1503, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_8, __pyx_t_7); + __Pyx_INCREF(__pyx_builtin_DeprecationWarning); + __Pyx_GIVEREF(__pyx_builtin_DeprecationWarning); + PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_8, __pyx_builtin_DeprecationWarning); + __pyx_t_7 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1503, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "mtrand.pyx":1506 + * "randint(1, {low} + 1) instead".format(low=low)), + * DeprecationWarning) + * high = low # <<<<<<<<<<<<<< + * low = 1 + * + */ + __Pyx_INCREF(__pyx_v_low); + __Pyx_DECREF_SET(__pyx_v_high, __pyx_v_low); + + /* "mtrand.pyx":1507 + * DeprecationWarning) + * high = low + * low = 1 # <<<<<<<<<<<<<< + * + * else: + */ + __Pyx_INCREF(__pyx_int_1); + __Pyx_DECREF_SET(__pyx_v_low, __pyx_int_1); + + /* "mtrand.pyx":1502 + * + * """ + * if high is None: # <<<<<<<<<<<<<< + * warnings.warn(("This function is deprecated. Please call " + * "randint(1, {low} + 1) instead".format(low=low)), + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":1510 + * + * else: + * warnings.warn(("This function is deprecated. Please call " # <<<<<<<<<<<<<< + * "randint({low}, {high} + 1) instead".format( + * low=low, high=high)), DeprecationWarning) + */ + /*else*/ { + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_warnings); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1510, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_warn); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1510, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "mtrand.pyx":1511 + * else: + * warnings.warn(("This function is deprecated. Please call " + * "randint({low}, {high} + 1) instead".format( # <<<<<<<<<<<<<< + * low=low, high=high)), DeprecationWarning) + * + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_This_function_is_deprecated_Plea_2, __pyx_n_s_format); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "mtrand.pyx":1512 + * warnings.warn(("This function is deprecated. Please call " + * "randint({low}, {high} + 1) instead".format( + * low=low, high=high)), DeprecationWarning) # <<<<<<<<<<<<<< + * + * return self.randint(low, high + 1, size=size, dtype='l') + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1512, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_low, __pyx_v_low) < 0) __PYX_ERR(0, 1512, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_high, __pyx_v_high) < 0) __PYX_ERR(0, 1512, __pyx_L1_error) + + /* "mtrand.pyx":1511 + * else: + * warnings.warn(("This function is deprecated. Please call " + * "randint({low}, {high} + 1) instead".format( # <<<<<<<<<<<<<< + * low=low, high=high)), DeprecationWarning) + * + */ + __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_empty_tuple, __pyx_t_7); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":1512 + * warnings.warn(("This function is deprecated. Please call " + * "randint({low}, {high} + 1) instead".format( + * low=low, high=high)), DeprecationWarning) # <<<<<<<<<<<<<< + * + * return self.randint(low, high + 1, size=size, dtype='l') + */ + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_t_6, __pyx_builtin_DeprecationWarning}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1510, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_t_6, __pyx_builtin_DeprecationWarning}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1510, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_5 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1510, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_8, __pyx_t_6); + __Pyx_INCREF(__pyx_builtin_DeprecationWarning); + __Pyx_GIVEREF(__pyx_builtin_DeprecationWarning); + PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_8, __pyx_builtin_DeprecationWarning); + __pyx_t_6 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1510, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __pyx_L3:; + + /* "mtrand.pyx":1514 + * low=low, high=high)), DeprecationWarning) + * + * return self.randint(low, high + 1, size=size, dtype='l') # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_randint); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyInt_AddObjC(__pyx_v_high, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_v_low); + __Pyx_GIVEREF(__pyx_v_low); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_low); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_size, __pyx_v_size) < 0) __PYX_ERR(0, 1514, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_dtype, __pyx_n_s_l) < 0) __PYX_ERR(0, 1514, __pyx_L1_error) + __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, __pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1514, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1422 + * return self.standard_normal(args) + * + * def random_integers(self, low, high=None, size=None): # <<<<<<<<<<<<<< + * """ + * random_integers(low, high=None, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("mtrand.RandomState.random_integers", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_low); + __Pyx_XDECREF(__pyx_v_high); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1519 + * + * # Complicated, continuous distributions: + * def standard_normal(self, size=None): # <<<<<<<<<<<<<< + * """ + * standard_normal(size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_35standard_normal(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_34standard_normal[] = "\n standard_normal(size=None)\n\n Draw samples from a standard Normal distribution (mean=0, stdev=1).\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : float or ndarray\n Drawn samples.\n\n Examples\n --------\n >>> s = np.random.standard_normal(8000)\n >>> s\n array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random\n -0.38672696, -0.4685006 ]) #random\n >>> s.shape\n (8000,)\n >>> s = np.random.standard_normal(size=(3, 4, 2))\n >>> s.shape\n (3, 4, 2)\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_35standard_normal(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("standard_normal (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_size,0}; + PyObject* values[1] = {0}; + values[0] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[0] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "standard_normal") < 0)) __PYX_ERR(0, 1519, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_size = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("standard_normal", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1519, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.standard_normal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_34standard_normal(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_34standard_normal(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + __Pyx_RefNannySetupContext("standard_normal", 0); + + /* "mtrand.pyx":1550 + * + * """ + * return cont0_array(self.internal_state, rk_gauss, size, self.lock) # <<<<<<<<<<<<<< + * + * def normal(self, loc=0.0, scale=1.0, size=None): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + __pyx_t_2 = __pyx_f_6mtrand_cont0_array(__pyx_v_self->internal_state, rk_gauss, __pyx_v_size, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1550, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1519 + * + * # Complicated, continuous distributions: + * def standard_normal(self, size=None): # <<<<<<<<<<<<<< + * """ + * standard_normal(size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("mtrand.RandomState.standard_normal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1552 + * return cont0_array(self.internal_state, rk_gauss, size, self.lock) + * + * def normal(self, loc=0.0, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * normal(loc=0.0, scale=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_37normal(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_36normal[] = "\n normal(loc=0.0, scale=1.0, size=None)\n\n Draw random samples from a normal (Gaussian) distribution.\n\n The probability density function of the normal distribution, first\n derived by De Moivre and 200 years later by both Gauss and Laplace\n independently [2]_, is often called the bell curve because of\n its characteristic shape (see the example below).\n\n The normal distributions occurs often in nature. For example, it\n describes the commonly occurring distribution of samples influenced\n by a large number of tiny, random disturbances, each with its own\n unique distribution [2]_.\n\n Parameters\n ----------\n loc : float or array_like of floats\n Mean (\"centre\") of the distribution.\n scale : float or array_like of floats\n Standard deviation (spread or \"width\") of the distribution.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``loc`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized normal distribution.\n\n See Also\n --------\n scipy.stats.norm : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Gaussian distribution is\n\n .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }}\n e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} },\n\n where :math:`\\mu` is the mean and :math:`\\sigma` the standard\n deviation. The square of the standard deviation, :math:`\\sigma^2`,\n is called the v""ariance.\n\n The function has its peak at the mean, and its \"spread\" increases with\n the standard deviation (the function reaches 0.607 times its maximum at\n :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that\n `numpy.random.normal` is more likely to return samples lying close to\n the mean, rather than those far away.\n\n References\n ----------\n .. [1] Wikipedia, \"Normal distribution\",\n http://en.wikipedia.org/wiki/Normal_distribution\n .. [2] P. R. Peebles Jr., \"Central Limit Theorem\" in \"Probability,\n Random Variables and Random Signal Principles\", 4th ed., 2001,\n pp. 51, 51, 125.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> mu, sigma = 0, 0.1 # mean and standard deviation\n >>> s = np.random.normal(mu, sigma, 1000)\n\n Verify the mean and the variance:\n\n >>> abs(mu - np.mean(s)) < 0.01\n True\n\n >>> abs(sigma - np.std(s, ddof=1)) < 0.01\n True\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 30, normed=True)\n >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *\n ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ),\n ... linewidth=2, color='r')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_37normal(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_loc = 0; + PyObject *__pyx_v_scale = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("normal (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_loc,&__pyx_n_s_scale,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[0] = ((PyObject *)__pyx_float_0_0); + values[1] = ((PyObject *)__pyx_float_1_0); + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_loc); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_scale); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "normal") < 0)) __PYX_ERR(0, 1552, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_loc = values[0]; + __pyx_v_scale = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("normal", 0, 0, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1552, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.normal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_36normal(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_loc, __pyx_v_scale, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_36normal(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_loc, PyObject *__pyx_v_scale, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oloc = 0; + PyArrayObject *__pyx_v_oscale = 0; + double __pyx_v_floc; + double __pyx_v_fscale; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("normal", 0); + + /* "mtrand.pyx":1644 + * cdef double floc, fscale + * + * oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oloc = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":1645 + * + * oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oloc.shape == oscale.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1645, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_oscale = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":1647 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oloc.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oloc), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1647, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oscale), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1647, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1647, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1647, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1647, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":1648 + * + * if oloc.shape == oscale.shape == (): + * floc = PyFloat_AsDouble(loc) # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_loc); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1648, __pyx_L1_error) + __pyx_v_floc = __pyx_t_5; + + /* "mtrand.pyx":1649 + * if oloc.shape == oscale.shape == (): + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) # <<<<<<<<<<<<<< + * if np.signbit(fscale): + * raise ValueError("scale < 0") + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_scale); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1649, __pyx_L1_error) + __pyx_v_fscale = __pyx_t_5; + + /* "mtrand.pyx":1650 + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_normal, size, floc, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fscale); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1650, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1651 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_normal, size, floc, + * fscale, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__69, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1651, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 1651, __pyx_L1_error) + + /* "mtrand.pyx":1650 + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_normal, size, floc, + */ + } + + /* "mtrand.pyx":1652 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_normal, size, floc, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1653 + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_normal, size, floc, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oscale)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":1652 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_normal, size, floc, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_normal, __pyx_v_size, __pyx_v_floc, __pyx_v_fscale, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1652, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1647 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oloc.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + */ + } + + /* "mtrand.pyx":1655 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_normal, size, oloc, oscale, + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oscale)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oscale)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oscale)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oscale)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1655, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1656 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_normal, size, oloc, oscale, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__70, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1656, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 1656, __pyx_L1_error) + + /* "mtrand.pyx":1655 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_normal, size, oloc, oscale, + */ + } + + /* "mtrand.pyx":1657 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_normal, size, oloc, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1658 + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_normal, size, oloc, oscale, + * self.lock) # <<<<<<<<<<<<<< + * + * def beta(self, a, b, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":1657 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_normal, size, oloc, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_normal, __pyx_v_size, __pyx_v_oloc, __pyx_v_oscale, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1657, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1552 + * return cont0_array(self.internal_state, rk_gauss, size, self.lock) + * + * def normal(self, loc=0.0, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * normal(loc=0.0, scale=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.normal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oloc); + __Pyx_XDECREF((PyObject *)__pyx_v_oscale); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1660 + * self.lock) + * + * def beta(self, a, b, size=None): # <<<<<<<<<<<<<< + * """ + * beta(a, b, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_39beta(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_38beta[] = "\n beta(a, b, size=None)\n\n Draw samples from a Beta distribution.\n\n The Beta distribution is a special case of the Dirichlet distribution,\n and is related to the Gamma distribution. It has the probability\n distribution function\n\n .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1}\n (1 - x)^{\\beta - 1},\n\n where the normalisation, B, is the beta function,\n\n .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1}\n (1 - t)^{\\beta - 1} dt.\n\n It is often seen in Bayesian inference and order statistics.\n\n Parameters\n ----------\n a : float or array_like of floats\n Alpha, non-negative.\n b : float or array_like of floats\n Beta, non-negative.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` and ``b`` are both scalars.\n Otherwise, ``np.broadcast(a, b).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized beta distribution.\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_39beta(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_a = 0; + PyObject *__pyx_v_b = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("beta (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_a,&__pyx_n_s_b,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_a)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_b)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("beta", 0, 2, 3, 1); __PYX_ERR(0, 1660, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "beta") < 0)) __PYX_ERR(0, 1660, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_a = values[0]; + __pyx_v_b = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("beta", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1660, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.beta", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_38beta(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_a, __pyx_v_b, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_38beta(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oa = 0; + PyArrayObject *__pyx_v_ob = 0; + double __pyx_v_fa; + double __pyx_v_fb; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("beta", 0); + + /* "mtrand.pyx":1701 + * cdef double fa, fb + * + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * ob = PyArray_FROM_OTF(b, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_a, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1701, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oa = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":1702 + * + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * ob = PyArray_FROM_OTF(b, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oa.shape == ob.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_b, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1702, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_ob = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":1704 + * ob = PyArray_FROM_OTF(b, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == ob.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * fb = PyFloat_AsDouble(b) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oa), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1704, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_ob), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1704, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1704, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1704, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1704, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":1705 + * + * if oa.shape == ob.shape == (): + * fa = PyFloat_AsDouble(a) # <<<<<<<<<<<<<< + * fb = PyFloat_AsDouble(b) + * + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_a); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1705, __pyx_L1_error) + __pyx_v_fa = __pyx_t_5; + + /* "mtrand.pyx":1706 + * if oa.shape == ob.shape == (): + * fa = PyFloat_AsDouble(a) + * fb = PyFloat_AsDouble(b) # <<<<<<<<<<<<<< + * + * if fa <= 0: + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_b); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1706, __pyx_L1_error) + __pyx_v_fb = __pyx_t_5; + + /* "mtrand.pyx":1708 + * fb = PyFloat_AsDouble(b) + * + * if fa <= 0: # <<<<<<<<<<<<<< + * raise ValueError("a <= 0") + * if fb <= 0: + */ + __pyx_t_4 = ((__pyx_v_fa <= 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1709 + * + * if fa <= 0: + * raise ValueError("a <= 0") # <<<<<<<<<<<<<< + * if fb <= 0: + * raise ValueError("b <= 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__71, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1709, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 1709, __pyx_L1_error) + + /* "mtrand.pyx":1708 + * fb = PyFloat_AsDouble(b) + * + * if fa <= 0: # <<<<<<<<<<<<<< + * raise ValueError("a <= 0") + * if fb <= 0: + */ + } + + /* "mtrand.pyx":1710 + * if fa <= 0: + * raise ValueError("a <= 0") + * if fb <= 0: # <<<<<<<<<<<<<< + * raise ValueError("b <= 0") + * return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb, + */ + __pyx_t_4 = ((__pyx_v_fb <= 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1711 + * raise ValueError("a <= 0") + * if fb <= 0: + * raise ValueError("b <= 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb, + * self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__72, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1711, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 1711, __pyx_L1_error) + + /* "mtrand.pyx":1710 + * if fa <= 0: + * raise ValueError("a <= 0") + * if fb <= 0: # <<<<<<<<<<<<<< + * raise ValueError("b <= 0") + * return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb, + */ + } + + /* "mtrand.pyx":1712 + * if fb <= 0: + * raise ValueError("b <= 0") + * return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1713 + * raise ValueError("b <= 0") + * return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb, + * self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(oa, 0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":1712 + * if fb <= 0: + * raise ValueError("b <= 0") + * return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_beta, __pyx_v_size, __pyx_v_fa, __pyx_v_fb, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1712, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1704 + * ob = PyArray_FROM_OTF(b, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == ob.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * fb = PyFloat_AsDouble(b) + */ + } + + /* "mtrand.pyx":1715 + * self.lock) + * + * if np.any(np.less_equal(oa, 0)): # <<<<<<<<<<<<<< + * raise ValueError("a <= 0") + * if np.any(np.less_equal(ob, 0)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_oa), __pyx_int_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_oa), __pyx_int_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_oa)); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_int_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1715, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1716 + * + * if np.any(np.less_equal(oa, 0)): + * raise ValueError("a <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less_equal(ob, 0)): + * raise ValueError("b <= 0") + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__73, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1716, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 1716, __pyx_L1_error) + + /* "mtrand.pyx":1715 + * self.lock) + * + * if np.any(np.less_equal(oa, 0)): # <<<<<<<<<<<<<< + * raise ValueError("a <= 0") + * if np.any(np.less_equal(ob, 0)): + */ + } + + /* "mtrand.pyx":1717 + * if np.any(np.less_equal(oa, 0)): + * raise ValueError("a <= 0") + * if np.any(np.less_equal(ob, 0)): # <<<<<<<<<<<<<< + * raise ValueError("b <= 0") + * return cont2_array(self.internal_state, rk_beta, size, oa, ob, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_ob), __pyx_int_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_ob), __pyx_int_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_ob)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ob)); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_8, ((PyObject *)__pyx_v_ob)); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_8, __pyx_int_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1717, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1718 + * raise ValueError("a <= 0") + * if np.any(np.less_equal(ob, 0)): + * raise ValueError("b <= 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_beta, size, oa, ob, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__74, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1718, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 1718, __pyx_L1_error) + + /* "mtrand.pyx":1717 + * if np.any(np.less_equal(oa, 0)): + * raise ValueError("a <= 0") + * if np.any(np.less_equal(ob, 0)): # <<<<<<<<<<<<<< + * raise ValueError("b <= 0") + * return cont2_array(self.internal_state, rk_beta, size, oa, ob, + */ + } + + /* "mtrand.pyx":1719 + * if np.any(np.less_equal(ob, 0)): + * raise ValueError("b <= 0") + * return cont2_array(self.internal_state, rk_beta, size, oa, ob, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1720 + * raise ValueError("b <= 0") + * return cont2_array(self.internal_state, rk_beta, size, oa, ob, + * self.lock) # <<<<<<<<<<<<<< + * + * def exponential(self, scale=1.0, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":1719 + * if np.any(np.less_equal(ob, 0)): + * raise ValueError("b <= 0") + * return cont2_array(self.internal_state, rk_beta, size, oa, ob, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_9 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_beta, __pyx_v_size, __pyx_v_oa, __pyx_v_ob, __pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1719, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_9; + __pyx_t_9 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1660 + * self.lock) + * + * def beta(self, a, b, size=None): # <<<<<<<<<<<<<< + * """ + * beta(a, b, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.beta", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oa); + __Pyx_XDECREF((PyObject *)__pyx_v_ob); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1722 + * self.lock) + * + * def exponential(self, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * exponential(scale=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_41exponential(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_40exponential[] = "\n exponential(scale=1.0, size=None)\n\n Draw samples from an exponential distribution.\n\n Its probability density function is\n\n .. math:: f(x; \\frac{1}{\\beta}) = \\frac{1}{\\beta} \\exp(-\\frac{x}{\\beta}),\n\n for ``x > 0`` and 0 elsewhere. :math:`\\beta` is the scale parameter,\n which is the inverse of the rate parameter :math:`\\lambda = 1/\\beta`.\n The rate parameter is an alternative, widely used parameterization\n of the exponential distribution [3]_.\n\n The exponential distribution is a continuous analogue of the\n geometric distribution. It describes many common situations, such as\n the size of raindrops measured over many rainstorms [1]_, or the time\n between page requests to Wikipedia [2]_.\n\n Parameters\n ----------\n scale : float or array_like of floats\n The scale parameter, :math:`\\beta = 1/\\lambda`.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``scale`` is a scalar. Otherwise,\n ``np.array(scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized exponential distribution.\n\n References\n ----------\n .. [1] Peyton Z. Peebles Jr., \"Probability, Random Variables and\n Random Signal Principles\", 4th ed, 2001, p. 57.\n .. [2] Wikipedia, \"Poisson process\",\n http://en.wikipedia.org/wiki/Poisson_process\n .. [3] Wikipedia, \"Exponential distribution\",\n http://en.wikipedia.org/wiki/Exponential_distribution\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_41exponential(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_scale = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("exponential (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_scale,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[0] = ((PyObject *)__pyx_float_1_0); + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_scale); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "exponential") < 0)) __PYX_ERR(0, 1722, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_scale = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("exponential", 0, 0, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1722, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.exponential", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_40exponential(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_scale, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_40exponential(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_scale, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oscale = 0; + double __pyx_v_fscale; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("exponential", 0); + + /* "mtrand.pyx":1770 + * cdef double fscale + * + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oscale.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1770, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oscale = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":1772 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oscale.shape == (): # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oscale), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1772, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1772, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 1772, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":1773 + * + * if oscale.shape == (): + * fscale = PyFloat_AsDouble(scale) # <<<<<<<<<<<<<< + * if np.signbit(fscale): + * raise ValueError("scale < 0") + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_scale); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1773, __pyx_L1_error) + __pyx_v_fscale = __pyx_t_4; + + /* "mtrand.pyx":1774 + * if oscale.shape == (): + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_exponential, size, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fscale); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 1774, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":1775 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_exponential, size, + * fscale, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__75, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1775, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 1775, __pyx_L1_error) + + /* "mtrand.pyx":1774 + * if oscale.shape == (): + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_exponential, size, + */ + } + + /* "mtrand.pyx":1776 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_exponential, size, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1777 + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_exponential, size, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oscale)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":1776 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_exponential, size, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_5 = __pyx_f_6mtrand_cont1_array_sc(__pyx_v_self->internal_state, rk_exponential, __pyx_v_size, __pyx_v_fscale, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1776, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1772 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oscale.shape == (): # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + */ + } + + /* "mtrand.pyx":1779 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont1_array(self.internal_state, rk_exponential, size, oscale, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oscale)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oscale)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oscale)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oscale)); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 1779, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":1780 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_exponential, size, oscale, + * self.lock) + */ + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__76, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1780, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 1780, __pyx_L1_error) + + /* "mtrand.pyx":1779 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont1_array(self.internal_state, rk_exponential, size, oscale, + */ + } + + /* "mtrand.pyx":1781 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont1_array(self.internal_state, rk_exponential, size, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1782 + * raise ValueError("scale < 0") + * return cont1_array(self.internal_state, rk_exponential, size, oscale, + * self.lock) # <<<<<<<<<<<<<< + * + * def standard_exponential(self, size=None): + */ + __pyx_t_5 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_5); + + /* "mtrand.pyx":1781 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont1_array(self.internal_state, rk_exponential, size, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont1_array(__pyx_v_self->internal_state, rk_exponential, __pyx_v_size, __pyx_v_oscale, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1781, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1722 + * self.lock) + * + * def exponential(self, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * exponential(scale=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.exponential", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oscale); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1784 + * self.lock) + * + * def standard_exponential(self, size=None): # <<<<<<<<<<<<<< + * """ + * standard_exponential(size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_43standard_exponential(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_42standard_exponential[] = "\n standard_exponential(size=None)\n\n Draw samples from the standard exponential distribution.\n\n `standard_exponential` is identical to the exponential distribution\n with a scale parameter of 1.\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : float or ndarray\n Drawn samples.\n\n Examples\n --------\n Output a 3x8000 array:\n\n >>> n = np.random.standard_exponential((3, 8000))\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_43standard_exponential(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("standard_exponential (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_size,0}; + PyObject* values[1] = {0}; + values[0] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[0] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "standard_exponential") < 0)) __PYX_ERR(0, 1784, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_size = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("standard_exponential", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1784, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.standard_exponential", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_42standard_exponential(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_42standard_exponential(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + __Pyx_RefNannySetupContext("standard_exponential", 0); + + /* "mtrand.pyx":1812 + * + * """ + * return cont0_array(self.internal_state, rk_standard_exponential, size, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1813 + * """ + * return cont0_array(self.internal_state, rk_standard_exponential, size, + * self.lock) # <<<<<<<<<<<<<< + * + * def standard_gamma(self, shape, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":1812 + * + * """ + * return cont0_array(self.internal_state, rk_standard_exponential, size, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont0_array(__pyx_v_self->internal_state, rk_standard_exponential, __pyx_v_size, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1812, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1784 + * self.lock) + * + * def standard_exponential(self, size=None): # <<<<<<<<<<<<<< + * """ + * standard_exponential(size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("mtrand.RandomState.standard_exponential", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1815 + * self.lock) + * + * def standard_gamma(self, shape, size=None): # <<<<<<<<<<<<<< + * """ + * standard_gamma(shape, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_45standard_gamma(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_44standard_gamma[] = "\n standard_gamma(shape, size=None)\n\n Draw samples from a standard Gamma distribution.\n\n Samples are drawn from a Gamma distribution with specified parameters,\n shape (sometimes designated \"k\") and scale=1.\n\n Parameters\n ----------\n shape : float or array_like of floats\n Parameter, should be > 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``shape`` is a scalar. Otherwise,\n ``np.array(shape).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized standard gamma distribution.\n\n See Also\n --------\n scipy.stats.gamma : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Gamma distribution is\n\n .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)},\n\n where :math:`k` is the shape and :math:`\\theta` the scale,\n and :math:`\\Gamma` is the Gamma function.\n\n The Gamma distribution is often used to model the times to failure of\n electronic components, and arises naturally in processes for which the\n waiting times between Poisson distributed events are relevant.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Gamma Distribution.\" From MathWorld--A\n Wolfram Web Resource.\n http://mathworld.wolfram.com/GammaDistribution.html\n .. [2] Wikipedia, \"Gamma distribution\",\n http://en.wikipedia.org/wiki/Gamma_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> shape, scale = 2""., 1. # mean and width\n >>> s = np.random.standard_gamma(shape, 1000000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> import scipy.special as sps\n >>> count, bins, ignored = plt.hist(s, 50, normed=True)\n >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\\n ... (sps.gamma(shape) * scale**shape))\n >>> plt.plot(bins, y, linewidth=2, color='r')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_45standard_gamma(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_shape = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("standard_gamma (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_shape,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_shape)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "standard_gamma") < 0)) __PYX_ERR(0, 1815, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_shape = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("standard_gamma", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1815, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.standard_gamma", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_44standard_gamma(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_shape, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_44standard_gamma(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_shape, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oshape = 0; + double __pyx_v_fshape; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("standard_gamma", 0); + + /* "mtrand.pyx":1887 + * cdef double fshape + * + * oshape = PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oshape.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1887, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oshape = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":1889 + * oshape = PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oshape.shape == (): # <<<<<<<<<<<<<< + * fshape = PyFloat_AsDouble(shape) + * if np.signbit(fshape): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oshape), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1889, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1889, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 1889, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":1890 + * + * if oshape.shape == (): + * fshape = PyFloat_AsDouble(shape) # <<<<<<<<<<<<<< + * if np.signbit(fshape): + * raise ValueError("shape < 0") + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_shape); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1890, __pyx_L1_error) + __pyx_v_fshape = __pyx_t_4; + + /* "mtrand.pyx":1891 + * if oshape.shape == (): + * fshape = PyFloat_AsDouble(shape) + * if np.signbit(fshape): # <<<<<<<<<<<<<< + * raise ValueError("shape < 0") + * return cont1_array_sc(self.internal_state, rk_standard_gamma, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fshape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 1891, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":1892 + * fshape = PyFloat_AsDouble(shape) + * if np.signbit(fshape): + * raise ValueError("shape < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_standard_gamma, + * size, fshape, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__77, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1892, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 1892, __pyx_L1_error) + + /* "mtrand.pyx":1891 + * if oshape.shape == (): + * fshape = PyFloat_AsDouble(shape) + * if np.signbit(fshape): # <<<<<<<<<<<<<< + * raise ValueError("shape < 0") + * return cont1_array_sc(self.internal_state, rk_standard_gamma, + */ + } + + /* "mtrand.pyx":1893 + * if np.signbit(fshape): + * raise ValueError("shape < 0") + * return cont1_array_sc(self.internal_state, rk_standard_gamma, # <<<<<<<<<<<<<< + * size, fshape, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1894 + * raise ValueError("shape < 0") + * return cont1_array_sc(self.internal_state, rk_standard_gamma, + * size, fshape, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oshape)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":1893 + * if np.signbit(fshape): + * raise ValueError("shape < 0") + * return cont1_array_sc(self.internal_state, rk_standard_gamma, # <<<<<<<<<<<<<< + * size, fshape, self.lock) + * + */ + __pyx_t_5 = __pyx_f_6mtrand_cont1_array_sc(__pyx_v_self->internal_state, rk_standard_gamma, __pyx_v_size, __pyx_v_fshape, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1893, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1889 + * oshape = PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oshape.shape == (): # <<<<<<<<<<<<<< + * fshape = PyFloat_AsDouble(shape) + * if np.signbit(fshape): + */ + } + + /* "mtrand.pyx":1896 + * size, fshape, self.lock) + * + * if np.any(np.signbit(oshape)): # <<<<<<<<<<<<<< + * raise ValueError("shape < 0") + * return cont1_array(self.internal_state, rk_standard_gamma, size, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oshape)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oshape)}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oshape)}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oshape)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oshape)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oshape)); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 1896, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":1897 + * + * if np.any(np.signbit(oshape)): + * raise ValueError("shape < 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_standard_gamma, size, + * oshape, self.lock) + */ + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__78, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1897, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 1897, __pyx_L1_error) + + /* "mtrand.pyx":1896 + * size, fshape, self.lock) + * + * if np.any(np.signbit(oshape)): # <<<<<<<<<<<<<< + * raise ValueError("shape < 0") + * return cont1_array(self.internal_state, rk_standard_gamma, size, + */ + } + + /* "mtrand.pyx":1898 + * if np.any(np.signbit(oshape)): + * raise ValueError("shape < 0") + * return cont1_array(self.internal_state, rk_standard_gamma, size, # <<<<<<<<<<<<<< + * oshape, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1899 + * raise ValueError("shape < 0") + * return cont1_array(self.internal_state, rk_standard_gamma, size, + * oshape, self.lock) # <<<<<<<<<<<<<< + * + * def gamma(self, shape, scale=1.0, size=None): + */ + __pyx_t_5 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_5); + + /* "mtrand.pyx":1898 + * if np.any(np.signbit(oshape)): + * raise ValueError("shape < 0") + * return cont1_array(self.internal_state, rk_standard_gamma, size, # <<<<<<<<<<<<<< + * oshape, self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont1_array(__pyx_v_self->internal_state, rk_standard_gamma, __pyx_v_size, __pyx_v_oshape, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1898, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1815 + * self.lock) + * + * def standard_gamma(self, shape, size=None): # <<<<<<<<<<<<<< + * """ + * standard_gamma(shape, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.standard_gamma", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oshape); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1901 + * oshape, self.lock) + * + * def gamma(self, shape, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * gamma(shape, scale=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_47gamma(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_46gamma[] = "\n gamma(shape, scale=1.0, size=None)\n\n Draw samples from a Gamma distribution.\n\n Samples are drawn from a Gamma distribution with specified parameters,\n `shape` (sometimes designated \"k\") and `scale` (sometimes designated\n \"theta\"), where both parameters are > 0.\n\n Parameters\n ----------\n shape : float or array_like of floats\n The shape of the gamma distribution. Should be greater than zero.\n scale : float or array_like of floats, optional\n The scale of the gamma distribution. Should be greater than zero.\n Default is equal to 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``shape`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized gamma distribution.\n\n See Also\n --------\n scipy.stats.gamma : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Gamma distribution is\n\n .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)},\n\n where :math:`k` is the shape and :math:`\\theta` the scale,\n and :math:`\\Gamma` is the Gamma function.\n\n The Gamma distribution is often used to model the times to failure of\n electronic components, and arises naturally in processes for which the\n waiting times between Poisson distributed events are relevant.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Gamma Distribution.\" From MathWorld--A\n Wolfram Web Resourc""e.\n http://mathworld.wolfram.com/GammaDistribution.html\n .. [2] Wikipedia, \"Gamma distribution\",\n http://en.wikipedia.org/wiki/Gamma_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> shape, scale = 2., 2. # mean=4, std=2*sqrt(2)\n >>> s = np.random.gamma(shape, scale, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> import scipy.special as sps\n >>> count, bins, ignored = plt.hist(s, 50, normed=True)\n >>> y = bins**(shape-1)*(np.exp(-bins/scale) /\n ... (sps.gamma(shape)*scale**shape))\n >>> plt.plot(bins, y, linewidth=2, color='r')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_47gamma(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_shape = 0; + PyObject *__pyx_v_scale = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("gamma (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_shape,&__pyx_n_s_scale,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[1] = ((PyObject *)__pyx_float_1_0); + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_shape)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_scale); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "gamma") < 0)) __PYX_ERR(0, 1901, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_shape = values[0]; + __pyx_v_scale = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("gamma", 0, 1, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1901, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.gamma", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_46gamma(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_shape, __pyx_v_scale, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_46gamma(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_shape, PyObject *__pyx_v_scale, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oshape = 0; + PyArrayObject *__pyx_v_oscale = 0; + double __pyx_v_fshape; + double __pyx_v_fscale; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("gamma", 0); + + /* "mtrand.pyx":1977 + * cdef double fshape, fscale + * + * oshape = PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1977, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oshape = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":1978 + * + * oshape = PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oshape.shape == oscale.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1978, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_oscale = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":1980 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oshape.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * fshape = PyFloat_AsDouble(shape) + * fscale = PyFloat_AsDouble(scale) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oshape), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1980, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oscale), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1980, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1980, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1980, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1980, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":1981 + * + * if oshape.shape == oscale.shape == (): + * fshape = PyFloat_AsDouble(shape) # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fshape): + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_shape); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1981, __pyx_L1_error) + __pyx_v_fshape = __pyx_t_5; + + /* "mtrand.pyx":1982 + * if oshape.shape == oscale.shape == (): + * fshape = PyFloat_AsDouble(shape) + * fscale = PyFloat_AsDouble(scale) # <<<<<<<<<<<<<< + * if np.signbit(fshape): + * raise ValueError("shape < 0") + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_scale); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 1982, __pyx_L1_error) + __pyx_v_fscale = __pyx_t_5; + + /* "mtrand.pyx":1983 + * fshape = PyFloat_AsDouble(shape) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fshape): # <<<<<<<<<<<<<< + * raise ValueError("shape < 0") + * if np.signbit(fscale): + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fshape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1983, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1984 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fshape): + * raise ValueError("shape < 0") # <<<<<<<<<<<<<< + * if np.signbit(fscale): + * raise ValueError("scale < 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__79, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1984, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 1984, __pyx_L1_error) + + /* "mtrand.pyx":1983 + * fshape = PyFloat_AsDouble(shape) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fshape): # <<<<<<<<<<<<<< + * raise ValueError("shape < 0") + * if np.signbit(fscale): + */ + } + + /* "mtrand.pyx":1985 + * if np.signbit(fshape): + * raise ValueError("shape < 0") + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_signbit); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_fscale); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_2) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_1}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_1}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1985, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1986 + * raise ValueError("shape < 0") + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, + * fscale, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__80, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1986, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 1986, __pyx_L1_error) + + /* "mtrand.pyx":1985 + * if np.signbit(fshape): + * raise ValueError("shape < 0") + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, + */ + } + + /* "mtrand.pyx":1987 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1988 + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oshape)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":1987 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_gamma, __pyx_v_size, __pyx_v_fshape, __pyx_v_fscale, __pyx_t_3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1980 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oshape.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * fshape = PyFloat_AsDouble(shape) + * fscale = PyFloat_AsDouble(scale) + */ + } + + /* "mtrand.pyx":1990 + * fscale, self.lock) + * + * if np.any(np.signbit(oshape)): # <<<<<<<<<<<<<< + * raise ValueError("shape < 0") + * if np.any(np.signbit(oscale)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_signbit); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_1) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, ((PyObject *)__pyx_v_oshape)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, ((PyObject *)__pyx_v_oshape)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, ((PyObject *)__pyx_v_oshape)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_1); __pyx_t_1 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oshape)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oshape)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oshape)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_3}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_3}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_7); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1990, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1991 + * + * if np.any(np.signbit(oshape)): + * raise ValueError("shape < 0") # <<<<<<<<<<<<<< + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + */ + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__81, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1991, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_Raise(__pyx_t_7, 0, 0, 0); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __PYX_ERR(0, 1991, __pyx_L1_error) + + /* "mtrand.pyx":1990 + * fscale, self.lock) + * + * if np.any(np.signbit(oshape)): # <<<<<<<<<<<<<< + * raise ValueError("shape < 0") + * if np.any(np.signbit(oscale)): + */ + } + + /* "mtrand.pyx":1992 + * if np.any(np.signbit(oshape)): + * raise ValueError("shape < 0") + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale, + */ + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_any); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_signbit); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_3) { + __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_2, ((PyObject *)__pyx_v_oscale)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_6); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_6); + } else + #endif + { + __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oscale)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oscale)); + PyTuple_SET_ITEM(__pyx_t_1, 0+1, ((PyObject *)__pyx_v_oscale)); + __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (!__pyx_t_2) { + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_6}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_6}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 0+1, __pyx_t_6); + __pyx_t_6 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_1, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_7); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 1992, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":1993 + * raise ValueError("shape < 0") + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale, + * self.lock) + */ + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__82, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1993, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_Raise(__pyx_t_7, 0, 0, 0); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __PYX_ERR(0, 1993, __pyx_L1_error) + + /* "mtrand.pyx":1992 + * if np.any(np.signbit(oshape)): + * raise ValueError("shape < 0") + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale, + */ + } + + /* "mtrand.pyx":1994 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":1995 + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale, + * self.lock) # <<<<<<<<<<<<<< + * + * def f(self, dfnum, dfden, size=None): + */ + __pyx_t_7 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_7); + + /* "mtrand.pyx":1994 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_8 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_gamma, __pyx_v_size, __pyx_v_oshape, __pyx_v_oscale, __pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1994, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_r = __pyx_t_8; + __pyx_t_8 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1901 + * oshape, self.lock) + * + * def gamma(self, shape, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * gamma(shape, scale=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.gamma", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oshape); + __Pyx_XDECREF((PyObject *)__pyx_v_oscale); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":1997 + * self.lock) + * + * def f(self, dfnum, dfden, size=None): # <<<<<<<<<<<<<< + * """ + * f(dfnum, dfden, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_49f(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_48f[] = "\n f(dfnum, dfden, size=None)\n\n Draw samples from an F distribution.\n\n Samples are drawn from an F distribution with specified parameters,\n `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of\n freedom in denominator), where both parameters should be greater than\n zero.\n\n The random variate of the F distribution (also known as the\n Fisher distribution) is a continuous probability distribution\n that arises in ANOVA tests, and is the ratio of two chi-square\n variates.\n\n Parameters\n ----------\n dfnum : float or array_like of floats\n Degrees of freedom in numerator, should be > 0.\n dfden : float or array_like of float\n Degrees of freedom in denominator, should be > 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``dfnum`` and ``dfden`` are both scalars.\n Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Fisher distribution.\n\n See Also\n --------\n scipy.stats.f : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The F statistic is used to compare in-group variances to between-group\n variances. Calculating the distribution depends on the sampling, and\n so it is a function of the respective degrees of freedom in the\n problem. The variable `dfnum` is the number of samples minus one, the\n between-groups degrees of freedom, while `dfden` is the within-groups\n degrees of freedom, the sum of the number of samples in each group\n minus ""the number of groups.\n\n References\n ----------\n .. [1] Glantz, Stanton A. \"Primer of Biostatistics.\", McGraw-Hill,\n Fifth Edition, 2002.\n .. [2] Wikipedia, \"F-distribution\",\n http://en.wikipedia.org/wiki/F-distribution\n\n Examples\n --------\n An example from Glantz[1], pp 47-40:\n\n Two groups, children of diabetics (25 people) and children from people\n without diabetes (25 controls). Fasting blood glucose was measured,\n case group had a mean value of 86.1, controls had a mean value of\n 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these\n data consistent with the null hypothesis that the parents diabetic\n status does not affect their children's blood glucose levels?\n Calculating the F statistic from the data gives a value of 36.01.\n\n Draw samples from the distribution:\n\n >>> dfnum = 1. # between group degrees of freedom\n >>> dfden = 48. # within groups degrees of freedom\n >>> s = np.random.f(dfnum, dfden, 1000)\n\n The lower bound for the top 1% of the samples is :\n\n >>> sort(s)[-10]\n 7.61988120985\n\n So there is about a 1% chance that the F statistic will exceed 7.62,\n the measured value is 36, so the null hypothesis is rejected at the 1%\n level.\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_49f(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_dfnum = 0; + PyObject *__pyx_v_dfden = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("f (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_dfnum,&__pyx_n_s_dfden,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dfnum)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dfden)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("f", 0, 2, 3, 1); __PYX_ERR(0, 1997, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "f") < 0)) __PYX_ERR(0, 1997, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_dfnum = values[0]; + __pyx_v_dfden = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("f", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1997, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.f", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_48f(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_dfnum, __pyx_v_dfden, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_48f(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_dfnum, PyObject *__pyx_v_dfden, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_odfnum = 0; + PyArrayObject *__pyx_v_odfden = 0; + double __pyx_v_fdfnum; + double __pyx_v_fdfden; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("f", 0); + + /* "mtrand.pyx":2083 + * cdef double fdfnum, fdfden + * + * odfnum = PyArray_FROM_OTF(dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2083, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_odfnum = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2084 + * + * odfnum = PyArray_FROM_OTF(dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if odfnum.shape == odfden.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_odfden = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":2086 + * odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odfnum.shape == odfden.shape == (): # <<<<<<<<<<<<<< + * fdfnum = PyFloat_AsDouble(dfnum) + * fdfden = PyFloat_AsDouble(dfden) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_odfnum), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2086, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_odfden), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2086, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2086, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2086, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 2086, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":2087 + * + * if odfnum.shape == odfden.shape == (): + * fdfnum = PyFloat_AsDouble(dfnum) # <<<<<<<<<<<<<< + * fdfden = PyFloat_AsDouble(dfden) + * + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_dfnum); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2087, __pyx_L1_error) + __pyx_v_fdfnum = __pyx_t_5; + + /* "mtrand.pyx":2088 + * if odfnum.shape == odfden.shape == (): + * fdfnum = PyFloat_AsDouble(dfnum) + * fdfden = PyFloat_AsDouble(dfden) # <<<<<<<<<<<<<< + * + * if fdfnum <= 0: + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_dfden); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2088, __pyx_L1_error) + __pyx_v_fdfden = __pyx_t_5; + + /* "mtrand.pyx":2090 + * fdfden = PyFloat_AsDouble(dfden) + * + * if fdfnum <= 0: # <<<<<<<<<<<<<< + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: + */ + __pyx_t_4 = ((__pyx_v_fdfnum <= 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2091 + * + * if fdfnum <= 0: + * raise ValueError("dfnum <= 0") # <<<<<<<<<<<<<< + * if fdfden <= 0: + * raise ValueError("dfden <= 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__83, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 2091, __pyx_L1_error) + + /* "mtrand.pyx":2090 + * fdfden = PyFloat_AsDouble(dfden) + * + * if fdfnum <= 0: # <<<<<<<<<<<<<< + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: + */ + } + + /* "mtrand.pyx":2092 + * if fdfnum <= 0: + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: # <<<<<<<<<<<<<< + * raise ValueError("dfden <= 0") + * return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, + */ + __pyx_t_4 = ((__pyx_v_fdfden <= 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2093 + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: + * raise ValueError("dfden <= 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, + * fdfden, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__84, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2093, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 2093, __pyx_L1_error) + + /* "mtrand.pyx":2092 + * if fdfnum <= 0: + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: # <<<<<<<<<<<<<< + * raise ValueError("dfden <= 0") + * return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, + */ + } + + /* "mtrand.pyx":2094 + * if fdfden <= 0: + * raise ValueError("dfden <= 0") + * return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, # <<<<<<<<<<<<<< + * fdfden, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2095 + * raise ValueError("dfden <= 0") + * return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, + * fdfden, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(odfnum, 0.0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":2094 + * if fdfden <= 0: + * raise ValueError("dfden <= 0") + * return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, # <<<<<<<<<<<<<< + * fdfden, self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_f, __pyx_v_size, __pyx_v_fdfnum, __pyx_v_fdfden, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2094, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2086 + * odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odfnum.shape == odfden.shape == (): # <<<<<<<<<<<<<< + * fdfnum = PyFloat_AsDouble(dfnum) + * fdfden = PyFloat_AsDouble(dfden) + */ + } + + /* "mtrand.pyx":2097 + * fdfden, self.lock) + * + * if np.any(np.less_equal(odfnum, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_odfnum), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_odfnum), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_odfnum)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_odfnum)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_odfnum)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 2097, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2098 + * + * if np.any(np.less_equal(odfnum, 0.0)): + * raise ValueError("dfnum <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__85, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2098, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 2098, __pyx_L1_error) + + /* "mtrand.pyx":2097 + * fdfden, self.lock) + * + * if np.any(np.less_equal(odfnum, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): + */ + } + + /* "mtrand.pyx":2099 + * if np.any(np.less_equal(odfnum, 0.0)): + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("dfden <= 0") + * return cont2_array(self.internal_state, rk_f, size, odfnum, odfden, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_odfden), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_odfden), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_odfden)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_odfden)); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_8, ((PyObject *)__pyx_v_odfden)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 2099, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2100 + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_f, size, odfnum, odfden, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__86, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 2100, __pyx_L1_error) + + /* "mtrand.pyx":2099 + * if np.any(np.less_equal(odfnum, 0.0)): + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("dfden <= 0") + * return cont2_array(self.internal_state, rk_f, size, odfnum, odfden, + */ + } + + /* "mtrand.pyx":2101 + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") + * return cont2_array(self.internal_state, rk_f, size, odfnum, odfden, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2102 + * raise ValueError("dfden <= 0") + * return cont2_array(self.internal_state, rk_f, size, odfnum, odfden, + * self.lock) # <<<<<<<<<<<<<< + * + * def noncentral_f(self, dfnum, dfden, nonc, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":2101 + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") + * return cont2_array(self.internal_state, rk_f, size, odfnum, odfden, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_9 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_f, __pyx_v_size, __pyx_v_odfnum, __pyx_v_odfden, __pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_9; + __pyx_t_9 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":1997 + * self.lock) + * + * def f(self, dfnum, dfden, size=None): # <<<<<<<<<<<<<< + * """ + * f(dfnum, dfden, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.f", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_odfnum); + __Pyx_XDECREF((PyObject *)__pyx_v_odfden); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2104 + * self.lock) + * + * def noncentral_f(self, dfnum, dfden, nonc, size=None): # <<<<<<<<<<<<<< + * """ + * noncentral_f(dfnum, dfden, nonc, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_51noncentral_f(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_50noncentral_f[] = "\n noncentral_f(dfnum, dfden, nonc, size=None)\n\n Draw samples from the noncentral F distribution.\n\n Samples are drawn from an F distribution with specified parameters,\n `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of\n freedom in denominator), where both parameters > 1.\n `nonc` is the non-centrality parameter.\n\n Parameters\n ----------\n dfnum : float or array_like of floats\n Numerator degrees of freedom, should be > 0.\n\n .. versionchanged:: 1.14.0\n Earlier NumPy versions required dfnum > 1.\n dfden : float or array_like of floats\n Denominator degrees of freedom, should be > 0.\n nonc : float or array_like of floats\n Non-centrality parameter, the sum of the squares of the numerator\n means, should be >= 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``dfnum``, ``dfden``, and ``nonc``\n are all scalars. Otherwise, ``np.broadcast(dfnum, dfden, nonc).size``\n samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized noncentral Fisher distribution.\n\n Notes\n -----\n When calculating the power of an experiment (power = probability of\n rejecting the null hypothesis when a specific alternative is true) the\n non-central F statistic becomes important. When the null hypothesis is\n true, the F statistic follows a central F distribution. When the null\n hypothesis is not true, then it follows a non-central F statistic.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Noncentral F-Distribution.\"\n From MathW""orld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/NoncentralF-Distribution.html\n .. [2] Wikipedia, \"Noncentral F-distribution\",\n http://en.wikipedia.org/wiki/Noncentral_F-distribution\n\n Examples\n --------\n In a study, testing for a specific alternative to the null hypothesis\n requires use of the Noncentral F distribution. We need to calculate the\n area in the tail of the distribution that exceeds the value of the F\n distribution for the null hypothesis. We'll plot the two probability\n distributions for comparison.\n\n >>> dfnum = 3 # between group deg of freedom\n >>> dfden = 20 # within groups degrees of freedom\n >>> nonc = 3.0\n >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000)\n >>> NF = np.histogram(nc_vals, bins=50, normed=True)\n >>> c_vals = np.random.f(dfnum, dfden, 1000000)\n >>> F = np.histogram(c_vals, bins=50, normed=True)\n >>> plt.plot(F[1][1:], F[0])\n >>> plt.plot(NF[1][1:], NF[0])\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_51noncentral_f(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_dfnum = 0; + PyObject *__pyx_v_dfden = 0; + PyObject *__pyx_v_nonc = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("noncentral_f (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_dfnum,&__pyx_n_s_dfden,&__pyx_n_s_nonc,&__pyx_n_s_size,0}; + PyObject* values[4] = {0,0,0,0}; + values[3] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dfnum)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dfden)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("noncentral_f", 0, 3, 4, 1); __PYX_ERR(0, 2104, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_nonc)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("noncentral_f", 0, 3, 4, 2); __PYX_ERR(0, 2104, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[3] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "noncentral_f") < 0)) __PYX_ERR(0, 2104, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_dfnum = values[0]; + __pyx_v_dfden = values[1]; + __pyx_v_nonc = values[2]; + __pyx_v_size = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("noncentral_f", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2104, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.noncentral_f", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_50noncentral_f(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_dfnum, __pyx_v_dfden, __pyx_v_nonc, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_50noncentral_f(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_dfnum, PyObject *__pyx_v_dfden, PyObject *__pyx_v_nonc, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_odfnum = 0; + PyArrayObject *__pyx_v_odfden = 0; + PyArrayObject *__pyx_v_ononc = 0; + double __pyx_v_fdfnum; + double __pyx_v_fdfden; + double __pyx_v_fnonc; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + double __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("noncentral_f", 0); + + /* "mtrand.pyx":2178 + * cdef double fdfnum, fdfden, fnonc + * + * odfnum = PyArray_FROM_OTF(dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2178, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_odfnum = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2179 + * + * odfnum = PyArray_FROM_OTF(dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2179, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_odfden = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":2180 + * odfnum = PyArray_FROM_OTF(dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if odfnum.shape == odfden.shape == ononc.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_ononc = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2182 + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odfnum.shape == odfden.shape == ononc.shape == (): # <<<<<<<<<<<<<< + * fdfnum = PyFloat_AsDouble(dfnum) + * fdfden = PyFloat_AsDouble(dfden) + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_odfnum), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_odfden), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_t_1, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2182, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_ononc), __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2182, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_4, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2182, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 2182, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_5) { + + /* "mtrand.pyx":2183 + * + * if odfnum.shape == odfden.shape == ononc.shape == (): + * fdfnum = PyFloat_AsDouble(dfnum) # <<<<<<<<<<<<<< + * fdfden = PyFloat_AsDouble(dfden) + * fnonc = PyFloat_AsDouble(nonc) + */ + __pyx_t_6 = PyFloat_AsDouble(__pyx_v_dfnum); if (unlikely(__pyx_t_6 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2183, __pyx_L1_error) + __pyx_v_fdfnum = __pyx_t_6; + + /* "mtrand.pyx":2184 + * if odfnum.shape == odfden.shape == ononc.shape == (): + * fdfnum = PyFloat_AsDouble(dfnum) + * fdfden = PyFloat_AsDouble(dfden) # <<<<<<<<<<<<<< + * fnonc = PyFloat_AsDouble(nonc) + * + */ + __pyx_t_6 = PyFloat_AsDouble(__pyx_v_dfden); if (unlikely(__pyx_t_6 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2184, __pyx_L1_error) + __pyx_v_fdfden = __pyx_t_6; + + /* "mtrand.pyx":2185 + * fdfnum = PyFloat_AsDouble(dfnum) + * fdfden = PyFloat_AsDouble(dfden) + * fnonc = PyFloat_AsDouble(nonc) # <<<<<<<<<<<<<< + * + * if fdfnum <= 0: + */ + __pyx_t_6 = PyFloat_AsDouble(__pyx_v_nonc); if (unlikely(__pyx_t_6 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2185, __pyx_L1_error) + __pyx_v_fnonc = __pyx_t_6; + + /* "mtrand.pyx":2187 + * fnonc = PyFloat_AsDouble(nonc) + * + * if fdfnum <= 0: # <<<<<<<<<<<<<< + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: + */ + __pyx_t_5 = ((__pyx_v_fdfnum <= 0.0) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":2188 + * + * if fdfnum <= 0: + * raise ValueError("dfnum <= 0") # <<<<<<<<<<<<<< + * if fdfden <= 0: + * raise ValueError("dfden <= 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__87, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 2188, __pyx_L1_error) + + /* "mtrand.pyx":2187 + * fnonc = PyFloat_AsDouble(nonc) + * + * if fdfnum <= 0: # <<<<<<<<<<<<<< + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: + */ + } + + /* "mtrand.pyx":2189 + * if fdfnum <= 0: + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: # <<<<<<<<<<<<<< + * raise ValueError("dfden <= 0") + * if fnonc < 0: + */ + __pyx_t_5 = ((__pyx_v_fdfden <= 0.0) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":2190 + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: + * raise ValueError("dfden <= 0") # <<<<<<<<<<<<<< + * if fnonc < 0: + * raise ValueError("nonc < 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__88, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 2190, __pyx_L1_error) + + /* "mtrand.pyx":2189 + * if fdfnum <= 0: + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: # <<<<<<<<<<<<<< + * raise ValueError("dfden <= 0") + * if fnonc < 0: + */ + } + + /* "mtrand.pyx":2191 + * if fdfden <= 0: + * raise ValueError("dfden <= 0") + * if fnonc < 0: # <<<<<<<<<<<<<< + * raise ValueError("nonc < 0") + * return cont3_array_sc(self.internal_state, rk_noncentral_f, size, + */ + __pyx_t_5 = ((__pyx_v_fnonc < 0.0) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":2192 + * raise ValueError("dfden <= 0") + * if fnonc < 0: + * raise ValueError("nonc < 0") # <<<<<<<<<<<<<< + * return cont3_array_sc(self.internal_state, rk_noncentral_f, size, + * fdfnum, fdfden, fnonc, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__89, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2192, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 2192, __pyx_L1_error) + + /* "mtrand.pyx":2191 + * if fdfden <= 0: + * raise ValueError("dfden <= 0") + * if fnonc < 0: # <<<<<<<<<<<<<< + * raise ValueError("nonc < 0") + * return cont3_array_sc(self.internal_state, rk_noncentral_f, size, + */ + } + + /* "mtrand.pyx":2193 + * if fnonc < 0: + * raise ValueError("nonc < 0") + * return cont3_array_sc(self.internal_state, rk_noncentral_f, size, # <<<<<<<<<<<<<< + * fdfnum, fdfden, fnonc, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2194 + * raise ValueError("nonc < 0") + * return cont3_array_sc(self.internal_state, rk_noncentral_f, size, + * fdfnum, fdfden, fnonc, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(odfnum, 0.0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":2193 + * if fnonc < 0: + * raise ValueError("nonc < 0") + * return cont3_array_sc(self.internal_state, rk_noncentral_f, size, # <<<<<<<<<<<<<< + * fdfnum, fdfden, fnonc, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_cont3_array_sc(__pyx_v_self->internal_state, rk_noncentral_f, __pyx_v_size, __pyx_v_fdfnum, __pyx_v_fdfden, __pyx_v_fnonc, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2193, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2182 + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odfnum.shape == odfden.shape == ononc.shape == (): # <<<<<<<<<<<<<< + * fdfnum = PyFloat_AsDouble(dfnum) + * fdfden = PyFloat_AsDouble(dfden) + */ + } + + /* "mtrand.pyx":2196 + * fdfnum, fdfden, fnonc, self.lock) + * + * if np.any(np.less_equal(odfnum, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_odfnum), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_odfnum), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_odfnum)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_odfnum)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_odfnum)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 2196, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":2197 + * + * if np.any(np.less_equal(odfnum, 0.0)): + * raise ValueError("dfnum <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__90, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2197, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 2197, __pyx_L1_error) + + /* "mtrand.pyx":2196 + * fdfnum, fdfden, fnonc, self.lock) + * + * if np.any(np.less_equal(odfnum, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): + */ + } + + /* "mtrand.pyx":2198 + * if np.any(np.less_equal(odfnum, 0.0)): + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("dfden <= 0") + * if np.any(np.less(ononc, 0.0)): + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_odfden), __pyx_float_0_0}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_odfden), __pyx_float_0_0}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_4 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_odfden)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_odfden)); + PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_8, ((PyObject *)__pyx_v_odfden)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 2198, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":2199 + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__91, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2199, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 2199, __pyx_L1_error) + + /* "mtrand.pyx":2198 + * if np.any(np.less_equal(odfnum, 0.0)): + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("dfden <= 0") + * if np.any(np.less(ononc, 0.0)): + */ + } + + /* "mtrand.pyx":2200 + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") + * if np.any(np.less(ononc, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("nonc < 0") + * return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum, + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_any); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, ((PyObject *)__pyx_v_ononc), __pyx_float_0_0}; + __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, ((PyObject *)__pyx_v_ononc), __pyx_float_0_0}; + __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + { + __pyx_t_3 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_ononc)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ononc)); + PyTuple_SET_ITEM(__pyx_t_3, 0+__pyx_t_8, ((PyObject *)__pyx_v_ononc)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_3, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_3, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_9}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_9}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_t_9); + __pyx_t_9 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 2200, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":2201 + * raise ValueError("dfden <= 0") + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") # <<<<<<<<<<<<<< + * return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum, + * odfden, ononc, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__92, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2201, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 2201, __pyx_L1_error) + + /* "mtrand.pyx":2200 + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") + * if np.any(np.less(ononc, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("nonc < 0") + * return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum, + */ + } + + /* "mtrand.pyx":2202 + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") + * return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum, # <<<<<<<<<<<<<< + * odfden, ononc, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2203 + * raise ValueError("nonc < 0") + * return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum, + * odfden, ononc, self.lock) # <<<<<<<<<<<<<< + * + * def chisquare(self, df, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":2202 + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") + * return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum, # <<<<<<<<<<<<<< + * odfden, ononc, self.lock) + * + */ + __pyx_t_4 = __pyx_f_6mtrand_cont3_array(__pyx_v_self->internal_state, rk_noncentral_f, __pyx_v_size, __pyx_v_odfnum, __pyx_v_odfden, __pyx_v_ononc, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 2202, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2104 + * self.lock) + * + * def noncentral_f(self, dfnum, dfden, nonc, size=None): # <<<<<<<<<<<<<< + * """ + * noncentral_f(dfnum, dfden, nonc, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.noncentral_f", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_odfnum); + __Pyx_XDECREF((PyObject *)__pyx_v_odfden); + __Pyx_XDECREF((PyObject *)__pyx_v_ononc); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2205 + * odfden, ononc, self.lock) + * + * def chisquare(self, df, size=None): # <<<<<<<<<<<<<< + * """ + * chisquare(df, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_53chisquare(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_52chisquare[] = "\n chisquare(df, size=None)\n\n Draw samples from a chi-square distribution.\n\n When `df` independent random variables, each with standard normal\n distributions (mean 0, variance 1), are squared and summed, the\n resulting distribution is chi-square (see Notes). This distribution\n is often used in hypothesis testing.\n\n Parameters\n ----------\n df : float or array_like of floats\n Number of degrees of freedom, should be > 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``df`` is a scalar. Otherwise,\n ``np.array(df).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized chi-square distribution.\n\n Raises\n ------\n ValueError\n When `df` <= 0 or when an inappropriate `size` (e.g. ``size=-1``)\n is given.\n\n Notes\n -----\n The variable obtained by summing the squares of `df` independent,\n standard normally distributed random variables:\n\n .. math:: Q = \\sum_{i=0}^{\\mathtt{df}} X^2_i\n\n is chi-square distributed, denoted\n\n .. math:: Q \\sim \\chi^2_k.\n\n The probability density function of the chi-squared distribution is\n\n .. math:: p(x) = \\frac{(1/2)^{k/2}}{\\Gamma(k/2)}\n x^{k/2 - 1} e^{-x/2},\n\n where :math:`\\Gamma` is the gamma function,\n\n .. math:: \\Gamma(x) = \\int_0^{-\\infty} t^{x - 1} e^{-t} dt.\n\n References\n ----------\n .. [1] NIST \"Engineering Statistics Handbook\"\n http://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm\n\n Examples\n --------\n >>> n""p.random.chisquare(2,4)\n array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272])\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_53chisquare(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_df = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("chisquare (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_df,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_df)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "chisquare") < 0)) __PYX_ERR(0, 2205, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_df = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("chisquare", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2205, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.chisquare", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_52chisquare(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_df, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_52chisquare(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_df, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_odf = 0; + double __pyx_v_fdf; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("chisquare", 0); + + /* "mtrand.pyx":2271 + * cdef double fdf + * + * odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if odf.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_df, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2271, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_odf = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2273 + * odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odf.shape == (): # <<<<<<<<<<<<<< + * fdf = PyFloat_AsDouble(df) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_odf), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2273, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2273, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2273, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":2274 + * + * if odf.shape == (): + * fdf = PyFloat_AsDouble(df) # <<<<<<<<<<<<<< + * + * if fdf <= 0: + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_df); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2274, __pyx_L1_error) + __pyx_v_fdf = __pyx_t_4; + + /* "mtrand.pyx":2276 + * fdf = PyFloat_AsDouble(df) + * + * if fdf <= 0: # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf, + */ + __pyx_t_3 = ((__pyx_v_fdf <= 0.0) != 0); + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2277 + * + * if fdf <= 0: + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__93, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2277, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 2277, __pyx_L1_error) + + /* "mtrand.pyx":2276 + * fdf = PyFloat_AsDouble(df) + * + * if fdf <= 0: # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf, + */ + } + + /* "mtrand.pyx":2278 + * if fdf <= 0: + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2279 + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf, + * self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(odf, 0.0)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":2278 + * if fdf <= 0: + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont1_array_sc(__pyx_v_self->internal_state, rk_chisquare, __pyx_v_size, __pyx_v_fdf, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2273 + * odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odf.shape == (): # <<<<<<<<<<<<<< + * fdf = PyFloat_AsDouble(df) + * + */ + } + + /* "mtrand.pyx":2281 + * self.lock) + * + * if np.any(np.less_equal(odf, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_chisquare, size, odf, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_odf), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_odf), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_odf)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_odf)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_odf)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2281, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2282 + * + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_chisquare, size, odf, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__94, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2282, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 2282, __pyx_L1_error) + + /* "mtrand.pyx":2281 + * self.lock) + * + * if np.any(np.less_equal(odf, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_chisquare, size, odf, + */ + } + + /* "mtrand.pyx":2283 + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_chisquare, size, odf, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2284 + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_chisquare, size, odf, + * self.lock) # <<<<<<<<<<<<<< + * + * def noncentral_chisquare(self, df, nonc, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":2283 + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_chisquare, size, odf, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_5 = __pyx_f_6mtrand_cont1_array(__pyx_v_self->internal_state, rk_chisquare, __pyx_v_size, __pyx_v_odf, __pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2283, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2205 + * odfden, ononc, self.lock) + * + * def chisquare(self, df, size=None): # <<<<<<<<<<<<<< + * """ + * chisquare(df, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.chisquare", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_odf); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2286 + * self.lock) + * + * def noncentral_chisquare(self, df, nonc, size=None): # <<<<<<<<<<<<<< + * """ + * noncentral_chisquare(df, nonc, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_55noncentral_chisquare(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_54noncentral_chisquare[] = "\n noncentral_chisquare(df, nonc, size=None)\n\n Draw samples from a noncentral chi-square distribution.\n\n The noncentral :math:`\\chi^2` distribution is a generalisation of\n the :math:`\\chi^2` distribution.\n\n Parameters\n ----------\n df : float or array_like of floats\n Degrees of freedom, should be > 0.\n\n .. versionchanged:: 1.10.0\n Earlier NumPy versions required dfnum > 1.\n nonc : float or array_like of floats\n Non-centrality, should be non-negative.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``df`` and ``nonc`` are both scalars.\n Otherwise, ``np.broadcast(df, nonc).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized noncentral chi-square distribution.\n\n Notes\n -----\n The probability density function for the noncentral Chi-square\n distribution is\n\n .. math:: P(x;df,nonc) = \\sum^{\\infty}_{i=0}\n \\frac{e^{-nonc/2}(nonc/2)^{i}}{i!}\n \\P_{Y_{df+2i}}(x),\n\n where :math:`Y_{q}` is the Chi-square with q degrees of freedom.\n\n In Delhi (2007), it is noted that the noncentral chi-square is\n useful in bombing and coverage problems, the probability of\n killing the point target given by the noncentral chi-squared\n distribution.\n\n References\n ----------\n .. [1] Delhi, M.S. Holla, \"On a noncentral chi-square distribution in\n the analysis of weapon systems effectiveness\", Metrika,\n Volume 15, Number 1 / December, 1970.\n .. [2] Wikipedia, \"Noncentral chi-s""quare distribution\"\n http://en.wikipedia.org/wiki/Noncentral_chi-square_distribution\n\n Examples\n --------\n Draw values from the distribution and plot the histogram\n\n >>> import matplotlib.pyplot as plt\n >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000),\n ... bins=200, normed=True)\n >>> plt.show()\n\n Draw values from a noncentral chisquare with very small noncentrality,\n and compare to a chisquare.\n\n >>> plt.figure()\n >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000),\n ... bins=np.arange(0., 25, .1), normed=True)\n >>> values2 = plt.hist(np.random.chisquare(3, 100000),\n ... bins=np.arange(0., 25, .1), normed=True)\n >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob')\n >>> plt.show()\n\n Demonstrate how large values of non-centrality lead to a more symmetric\n distribution.\n\n >>> plt.figure()\n >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000),\n ... bins=200, normed=True)\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_55noncentral_chisquare(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_df = 0; + PyObject *__pyx_v_nonc = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("noncentral_chisquare (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_df,&__pyx_n_s_nonc,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_df)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_nonc)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("noncentral_chisquare", 0, 2, 3, 1); __PYX_ERR(0, 2286, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "noncentral_chisquare") < 0)) __PYX_ERR(0, 2286, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_df = values[0]; + __pyx_v_nonc = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("noncentral_chisquare", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2286, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.noncentral_chisquare", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_54noncentral_chisquare(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_df, __pyx_v_nonc, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_54noncentral_chisquare(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_df, PyObject *__pyx_v_nonc, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_odf = 0; + PyArrayObject *__pyx_v_ononc = 0; + double __pyx_v_fdf; + double __pyx_v_fnonc; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("noncentral_chisquare", 0); + + /* "mtrand.pyx":2371 + * cdef double fdf, fnonc + * + * odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_df, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2371, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_odf = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2372 + * + * odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if odf.shape == ononc.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2372, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_ononc = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":2374 + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odf.shape == ononc.shape == (): # <<<<<<<<<<<<<< + * fdf = PyFloat_AsDouble(df) + * fnonc = PyFloat_AsDouble(nonc) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_odf), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_ononc), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2374, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2374, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 2374, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":2375 + * + * if odf.shape == ononc.shape == (): + * fdf = PyFloat_AsDouble(df) # <<<<<<<<<<<<<< + * fnonc = PyFloat_AsDouble(nonc) + * + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_df); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2375, __pyx_L1_error) + __pyx_v_fdf = __pyx_t_5; + + /* "mtrand.pyx":2376 + * if odf.shape == ononc.shape == (): + * fdf = PyFloat_AsDouble(df) + * fnonc = PyFloat_AsDouble(nonc) # <<<<<<<<<<<<<< + * + * if fdf <= 0: + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_nonc); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2376, __pyx_L1_error) + __pyx_v_fnonc = __pyx_t_5; + + /* "mtrand.pyx":2378 + * fnonc = PyFloat_AsDouble(nonc) + * + * if fdf <= 0: # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * if fnonc < 0: + */ + __pyx_t_4 = ((__pyx_v_fdf <= 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2379 + * + * if fdf <= 0: + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * if fnonc < 0: + * raise ValueError("nonc < 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__95, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 2379, __pyx_L1_error) + + /* "mtrand.pyx":2378 + * fnonc = PyFloat_AsDouble(nonc) + * + * if fdf <= 0: # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * if fnonc < 0: + */ + } + + /* "mtrand.pyx":2380 + * if fdf <= 0: + * raise ValueError("df <= 0") + * if fnonc < 0: # <<<<<<<<<<<<<< + * raise ValueError("nonc < 0") + * return cont2_array_sc(self.internal_state, rk_noncentral_chisquare, + */ + __pyx_t_4 = ((__pyx_v_fnonc < 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2381 + * raise ValueError("df <= 0") + * if fnonc < 0: + * raise ValueError("nonc < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_noncentral_chisquare, + * size, fdf, fnonc, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__96, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2381, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 2381, __pyx_L1_error) + + /* "mtrand.pyx":2380 + * if fdf <= 0: + * raise ValueError("df <= 0") + * if fnonc < 0: # <<<<<<<<<<<<<< + * raise ValueError("nonc < 0") + * return cont2_array_sc(self.internal_state, rk_noncentral_chisquare, + */ + } + + /* "mtrand.pyx":2382 + * if fnonc < 0: + * raise ValueError("nonc < 0") + * return cont2_array_sc(self.internal_state, rk_noncentral_chisquare, # <<<<<<<<<<<<<< + * size, fdf, fnonc, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2383 + * raise ValueError("nonc < 0") + * return cont2_array_sc(self.internal_state, rk_noncentral_chisquare, + * size, fdf, fnonc, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(odf, 0.0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":2382 + * if fnonc < 0: + * raise ValueError("nonc < 0") + * return cont2_array_sc(self.internal_state, rk_noncentral_chisquare, # <<<<<<<<<<<<<< + * size, fdf, fnonc, self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_noncentral_chisquare, __pyx_v_size, __pyx_v_fdf, __pyx_v_fnonc, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2382, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2374 + * ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odf.shape == ononc.shape == (): # <<<<<<<<<<<<<< + * fdf = PyFloat_AsDouble(df) + * fnonc = PyFloat_AsDouble(nonc) + */ + } + + /* "mtrand.pyx":2385 + * size, fdf, fnonc, self.lock) + * + * if np.any(np.less_equal(odf, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * if np.any(np.less(ononc, 0.0)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_odf), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_odf), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_odf)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_odf)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_odf)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 2385, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2386 + * + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__97, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2386, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 2386, __pyx_L1_error) + + /* "mtrand.pyx":2385 + * size, fdf, fnonc, self.lock) + * + * if np.any(np.less_equal(odf, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * if np.any(np.less(ononc, 0.0)): + */ + } + + /* "mtrand.pyx":2387 + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") + * if np.any(np.less(ononc, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("nonc < 0") + * return cont2_array(self.internal_state, rk_noncentral_chisquare, size, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_ononc), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_ononc), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_ononc)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ononc)); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_8, ((PyObject *)__pyx_v_ononc)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 2387, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2388 + * raise ValueError("df <= 0") + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_noncentral_chisquare, size, + * odf, ononc, self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__98, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2388, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 2388, __pyx_L1_error) + + /* "mtrand.pyx":2387 + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") + * if np.any(np.less(ononc, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("nonc < 0") + * return cont2_array(self.internal_state, rk_noncentral_chisquare, size, + */ + } + + /* "mtrand.pyx":2389 + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") + * return cont2_array(self.internal_state, rk_noncentral_chisquare, size, # <<<<<<<<<<<<<< + * odf, ononc, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2390 + * raise ValueError("nonc < 0") + * return cont2_array(self.internal_state, rk_noncentral_chisquare, size, + * odf, ononc, self.lock) # <<<<<<<<<<<<<< + * + * def standard_cauchy(self, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":2389 + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") + * return cont2_array(self.internal_state, rk_noncentral_chisquare, size, # <<<<<<<<<<<<<< + * odf, ononc, self.lock) + * + */ + __pyx_t_9 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_noncentral_chisquare, __pyx_v_size, __pyx_v_odf, __pyx_v_ononc, __pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2389, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_9; + __pyx_t_9 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2286 + * self.lock) + * + * def noncentral_chisquare(self, df, nonc, size=None): # <<<<<<<<<<<<<< + * """ + * noncentral_chisquare(df, nonc, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.noncentral_chisquare", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_odf); + __Pyx_XDECREF((PyObject *)__pyx_v_ononc); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2392 + * odf, ononc, self.lock) + * + * def standard_cauchy(self, size=None): # <<<<<<<<<<<<<< + * """ + * standard_cauchy(size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_57standard_cauchy(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_56standard_cauchy[] = "\n standard_cauchy(size=None)\n\n Draw samples from a standard Cauchy distribution with mode = 0.\n\n Also known as the Lorentz distribution.\n\n Parameters\n ----------\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n samples : ndarray or scalar\n The drawn samples.\n\n Notes\n -----\n The probability density function for the full Cauchy distribution is\n\n .. math:: P(x; x_0, \\gamma) = \\frac{1}{\\pi \\gamma \\bigl[ 1+\n (\\frac{x-x_0}{\\gamma})^2 \\bigr] }\n\n and the Standard Cauchy distribution just sets :math:`x_0=0` and\n :math:`\\gamma=1`\n\n The Cauchy distribution arises in the solution to the driven harmonic\n oscillator problem, and also describes spectral line broadening. It\n also describes the distribution of values at which a line tilted at\n a random angle will cut the x axis.\n\n When studying hypothesis tests that assume normality, seeing how the\n tests perform on data from a Cauchy distribution is a good indicator of\n their sensitivity to a heavy-tailed distribution, since the Cauchy looks\n very much like a Gaussian distribution, but with heavier tails.\n\n References\n ----------\n .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, \"Cauchy\n Distribution\",\n http://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm\n .. [2] Weisstein, Eric W. \"Cauchy Distribution.\" From MathWorld--A\n Wolfram Web Resource.\n http://mathworld.wolfram.com/CauchyDistribution.html\n .. [3] Wikipedia, \"Cauchy distribution\"\n http://en.wikipedia.org/wiki/C""auchy_distribution\n\n Examples\n --------\n Draw samples and plot the distribution:\n\n >>> s = np.random.standard_cauchy(1000000)\n >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well\n >>> plt.hist(s, bins=100)\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_57standard_cauchy(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("standard_cauchy (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_size,0}; + PyObject* values[1] = {0}; + values[0] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[0] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "standard_cauchy") < 0)) __PYX_ERR(0, 2392, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_size = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("standard_cauchy", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2392, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.standard_cauchy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_56standard_cauchy(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_56standard_cauchy(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_size) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + __Pyx_RefNannySetupContext("standard_cauchy", 0); + + /* "mtrand.pyx":2453 + * + * """ + * return cont0_array(self.internal_state, rk_standard_cauchy, size, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2454 + * """ + * return cont0_array(self.internal_state, rk_standard_cauchy, size, + * self.lock) # <<<<<<<<<<<<<< + * + * def standard_t(self, df, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":2453 + * + * """ + * return cont0_array(self.internal_state, rk_standard_cauchy, size, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont0_array(__pyx_v_self->internal_state, rk_standard_cauchy, __pyx_v_size, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2453, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2392 + * odf, ononc, self.lock) + * + * def standard_cauchy(self, size=None): # <<<<<<<<<<<<<< + * """ + * standard_cauchy(size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("mtrand.RandomState.standard_cauchy", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2456 + * self.lock) + * + * def standard_t(self, df, size=None): # <<<<<<<<<<<<<< + * """ + * standard_t(df, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_59standard_t(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_58standard_t[] = "\n standard_t(df, size=None)\n\n Draw samples from a standard Student's t distribution with `df` degrees\n of freedom.\n\n A special case of the hyperbolic distribution. As `df` gets\n large, the result resembles that of the standard normal\n distribution (`standard_normal`).\n\n Parameters\n ----------\n df : float or array_like of floats\n Degrees of freedom, should be > 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``df`` is a scalar. Otherwise,\n ``np.array(df).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized standard Student's t distribution.\n\n Notes\n -----\n The probability density function for the t distribution is\n\n .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df}\n \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2}\n\n The t test is based on an assumption that the data come from a\n Normal distribution. The t test provides a way to test whether\n the sample mean (that is the mean calculated from the data) is\n a good estimate of the true mean.\n\n The derivation of the t-distribution was first published in\n 1908 by William Gosset while working for the Guinness Brewery\n in Dublin. Due to proprietary issues, he had to publish under\n a pseudonym, and so he used the name Student.\n\n References\n ----------\n .. [1] Dalgaard, Peter, \"Introductory Statistics With R\",\n Springer, 2002.\n .. [2] Wikipedia, \"Student's t-distribution\"\n http://en.wikipedia.org/wiki/Student's_t-distrib""ution\n\n Examples\n --------\n From Dalgaard page 83 [1]_, suppose the daily energy intake for 11\n women in Kj is:\n\n >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\\n ... 7515, 8230, 8770])\n\n Does their energy intake deviate systematically from the recommended\n value of 7725 kJ?\n\n We have 10 degrees of freedom, so is the sample mean within 95% of the\n recommended value?\n\n >>> s = np.random.standard_t(10, size=100000)\n >>> np.mean(intake)\n 6753.636363636364\n >>> intake.std(ddof=1)\n 1142.1232221373727\n\n Calculate the t statistic, setting the ddof parameter to the unbiased\n value so the divisor in the standard deviation will be degrees of\n freedom, N-1.\n\n >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake)))\n >>> import matplotlib.pyplot as plt\n >>> h = plt.hist(s, bins=100, normed=True)\n\n For a one-sided t-test, how far out in the distribution does the t\n statistic appear?\n\n >>> np.sum(s 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "standard_t") < 0)) __PYX_ERR(0, 2456, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_df = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("standard_t", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2456, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.standard_t", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_58standard_t(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_df, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_58standard_t(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_df, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_odf = 0; + double __pyx_v_fdf; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("standard_t", 0); + + /* "mtrand.pyx":2547 + * cdef double fdf + * + * odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if odf.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_df, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2547, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_odf = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2549 + * odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odf.shape == (): # <<<<<<<<<<<<<< + * fdf = PyFloat_AsDouble(df) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_odf), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2549, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2549, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2549, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":2550 + * + * if odf.shape == (): + * fdf = PyFloat_AsDouble(df) # <<<<<<<<<<<<<< + * + * if fdf <= 0: + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_df); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2550, __pyx_L1_error) + __pyx_v_fdf = __pyx_t_4; + + /* "mtrand.pyx":2552 + * fdf = PyFloat_AsDouble(df) + * + * if fdf <= 0: # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_standard_t, size, + */ + __pyx_t_3 = ((__pyx_v_fdf <= 0.0) != 0); + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2553 + * + * if fdf <= 0: + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_standard_t, size, + * fdf, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__99, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2553, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 2553, __pyx_L1_error) + + /* "mtrand.pyx":2552 + * fdf = PyFloat_AsDouble(df) + * + * if fdf <= 0: # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_standard_t, size, + */ + } + + /* "mtrand.pyx":2554 + * if fdf <= 0: + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_standard_t, size, # <<<<<<<<<<<<<< + * fdf, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2555 + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_standard_t, size, + * fdf, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(odf, 0.0)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":2554 + * if fdf <= 0: + * raise ValueError("df <= 0") + * return cont1_array_sc(self.internal_state, rk_standard_t, size, # <<<<<<<<<<<<<< + * fdf, self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont1_array_sc(__pyx_v_self->internal_state, rk_standard_t, __pyx_v_size, __pyx_v_fdf, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2554, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2549 + * odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if odf.shape == (): # <<<<<<<<<<<<<< + * fdf = PyFloat_AsDouble(df) + * + */ + } + + /* "mtrand.pyx":2557 + * fdf, self.lock) + * + * if np.any(np.less_equal(odf, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_standard_t, size, odf, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_odf), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_odf), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_odf)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_odf)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_odf)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2557, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2558 + * + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_standard_t, size, odf, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__100, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2558, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 2558, __pyx_L1_error) + + /* "mtrand.pyx":2557 + * fdf, self.lock) + * + * if np.any(np.less_equal(odf, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_standard_t, size, odf, + */ + } + + /* "mtrand.pyx":2559 + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_standard_t, size, odf, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2560 + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_standard_t, size, odf, + * self.lock) # <<<<<<<<<<<<<< + * + * def vonmises(self, mu, kappa, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":2559 + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") + * return cont1_array(self.internal_state, rk_standard_t, size, odf, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_5 = __pyx_f_6mtrand_cont1_array(__pyx_v_self->internal_state, rk_standard_t, __pyx_v_size, __pyx_v_odf, __pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2559, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2456 + * self.lock) + * + * def standard_t(self, df, size=None): # <<<<<<<<<<<<<< + * """ + * standard_t(df, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.standard_t", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_odf); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2562 + * self.lock) + * + * def vonmises(self, mu, kappa, size=None): # <<<<<<<<<<<<<< + * """ + * vonmises(mu, kappa, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_61vonmises(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_60vonmises[] = "\n vonmises(mu, kappa, size=None)\n\n Draw samples from a von Mises distribution.\n\n Samples are drawn from a von Mises distribution with specified mode\n (mu) and dispersion (kappa), on the interval [-pi, pi].\n\n The von Mises distribution (also known as the circular normal\n distribution) is a continuous probability distribution on the unit\n circle. It may be thought of as the circular analogue of the normal\n distribution.\n\n Parameters\n ----------\n mu : float or array_like of floats\n Mode (\"center\") of the distribution.\n kappa : float or array_like of floats\n Dispersion of the distribution, has to be >=0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``mu`` and ``kappa`` are both scalars.\n Otherwise, ``np.broadcast(mu, kappa).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized von Mises distribution.\n\n See Also\n --------\n scipy.stats.vonmises : probability density function, distribution, or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the von Mises distribution is\n\n .. math:: p(x) = \\frac{e^{\\kappa cos(x-\\mu)}}{2\\pi I_0(\\kappa)},\n\n where :math:`\\mu` is the mode and :math:`\\kappa` the dispersion,\n and :math:`I_0(\\kappa)` is the modified Bessel function of order 0.\n\n The von Mises is named for Richard Edler von Mises, who was born in\n Austria-Hungary, in what is now the Ukraine. He fled to the United\n States in 1939 and became a professor at Harvard. He worked in\n probability theory, aero""dynamics, fluid mechanics, and philosophy of\n science.\n\n References\n ----------\n .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). \"Handbook of\n Mathematical Functions with Formulas, Graphs, and Mathematical\n Tables, 9th printing,\" New York: Dover, 1972.\n .. [2] von Mises, R., \"Mathematical Theory of Probability\n and Statistics\", New York: Academic Press, 1964.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> mu, kappa = 0.0, 4.0 # mean and dispersion\n >>> s = np.random.vonmises(mu, kappa, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> from scipy.special import i0\n >>> plt.hist(s, 50, normed=True)\n >>> x = np.linspace(-np.pi, np.pi, num=51)\n >>> y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa))\n >>> plt.plot(x, y, linewidth=2, color='r')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_61vonmises(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_mu = 0; + PyObject *__pyx_v_kappa = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("vonmises (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_mu,&__pyx_n_s_kappa,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mu)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_kappa)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("vonmises", 0, 2, 3, 1); __PYX_ERR(0, 2562, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "vonmises") < 0)) __PYX_ERR(0, 2562, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_mu = values[0]; + __pyx_v_kappa = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("vonmises", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2562, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.vonmises", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_60vonmises(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_mu, __pyx_v_kappa, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_60vonmises(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_mu, PyObject *__pyx_v_kappa, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_omu = 0; + PyArrayObject *__pyx_v_okappa = 0; + double __pyx_v_fmu; + double __pyx_v_fkappa; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("vonmises", 0); + + /* "mtrand.pyx":2643 + * cdef double fmu, fkappa + * + * omu = PyArray_FROM_OTF(mu, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * okappa = PyArray_FROM_OTF(kappa, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_mu, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2643, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_omu = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2644 + * + * omu = PyArray_FROM_OTF(mu, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * okappa = PyArray_FROM_OTF(kappa, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if omu.shape == okappa.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_kappa, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2644, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_okappa = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":2646 + * okappa = PyArray_FROM_OTF(kappa, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if omu.shape == okappa.shape == (): # <<<<<<<<<<<<<< + * fmu = PyFloat_AsDouble(mu) + * fkappa = PyFloat_AsDouble(kappa) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_omu), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2646, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_okappa), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2646, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2646, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2646, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 2646, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":2647 + * + * if omu.shape == okappa.shape == (): + * fmu = PyFloat_AsDouble(mu) # <<<<<<<<<<<<<< + * fkappa = PyFloat_AsDouble(kappa) + * + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_mu); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2647, __pyx_L1_error) + __pyx_v_fmu = __pyx_t_5; + + /* "mtrand.pyx":2648 + * if omu.shape == okappa.shape == (): + * fmu = PyFloat_AsDouble(mu) + * fkappa = PyFloat_AsDouble(kappa) # <<<<<<<<<<<<<< + * + * if fkappa < 0: + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_kappa); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2648, __pyx_L1_error) + __pyx_v_fkappa = __pyx_t_5; + + /* "mtrand.pyx":2650 + * fkappa = PyFloat_AsDouble(kappa) + * + * if fkappa < 0: # <<<<<<<<<<<<<< + * raise ValueError("kappa < 0") + * return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, + */ + __pyx_t_4 = ((__pyx_v_fkappa < 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2651 + * + * if fkappa < 0: + * raise ValueError("kappa < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, + * fkappa, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__101, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2651, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 2651, __pyx_L1_error) + + /* "mtrand.pyx":2650 + * fkappa = PyFloat_AsDouble(kappa) + * + * if fkappa < 0: # <<<<<<<<<<<<<< + * raise ValueError("kappa < 0") + * return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, + */ + } + + /* "mtrand.pyx":2652 + * if fkappa < 0: + * raise ValueError("kappa < 0") + * return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, # <<<<<<<<<<<<<< + * fkappa, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2653 + * raise ValueError("kappa < 0") + * return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, + * fkappa, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less(okappa, 0.0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":2652 + * if fkappa < 0: + * raise ValueError("kappa < 0") + * return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, # <<<<<<<<<<<<<< + * fkappa, self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_vonmises, __pyx_v_size, __pyx_v_fmu, __pyx_v_fkappa, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2652, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2646 + * okappa = PyArray_FROM_OTF(kappa, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if omu.shape == okappa.shape == (): # <<<<<<<<<<<<<< + * fmu = PyFloat_AsDouble(mu) + * fkappa = PyFloat_AsDouble(kappa) + */ + } + + /* "mtrand.pyx":2655 + * fkappa, self.lock) + * + * if np.any(np.less(okappa, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("kappa < 0") + * return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa, + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_okappa), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_okappa), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_okappa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_okappa)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_okappa)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 2655, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":2656 + * + * if np.any(np.less(okappa, 0.0)): + * raise ValueError("kappa < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__102, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2656, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 2656, __pyx_L1_error) + + /* "mtrand.pyx":2655 + * fkappa, self.lock) + * + * if np.any(np.less(okappa, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("kappa < 0") + * return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa, + */ + } + + /* "mtrand.pyx":2657 + * if np.any(np.less(okappa, 0.0)): + * raise ValueError("kappa < 0") + * return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2658 + * raise ValueError("kappa < 0") + * return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa, + * self.lock) # <<<<<<<<<<<<<< + * + * def pareto(self, a, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":2657 + * if np.any(np.less(okappa, 0.0)): + * raise ValueError("kappa < 0") + * return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_vonmises, __pyx_v_size, __pyx_v_omu, __pyx_v_okappa, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2657, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2562 + * self.lock) + * + * def vonmises(self, mu, kappa, size=None): # <<<<<<<<<<<<<< + * """ + * vonmises(mu, kappa, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.vonmises", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_omu); + __Pyx_XDECREF((PyObject *)__pyx_v_okappa); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2660 + * self.lock) + * + * def pareto(self, a, size=None): # <<<<<<<<<<<<<< + * """ + * pareto(a, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_63pareto(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_62pareto[] = "\n pareto(a, size=None)\n\n Draw samples from a Pareto II or Lomax distribution with\n specified shape.\n\n The Lomax or Pareto II distribution is a shifted Pareto\n distribution. The classical Pareto distribution can be\n obtained from the Lomax distribution by adding 1 and\n multiplying by the scale parameter ``m`` (see Notes). The\n smallest value of the Lomax distribution is zero while for the\n classical Pareto distribution it is ``mu``, where the standard\n Pareto distribution has location ``mu = 1``. Lomax can also\n be considered as a simplified version of the Generalized\n Pareto distribution (available in SciPy), with the scale set\n to one and the location set to zero.\n\n The Pareto distribution must be greater than zero, and is\n unbounded above. It is also known as the \"80-20 rule\". In\n this distribution, 80 percent of the weights are in the lowest\n 20 percent of the range, while the other 20 percent fill the\n remaining 80 percent of the range.\n\n Parameters\n ----------\n a : float or array_like of floats\n Shape of the distribution. Should be greater than zero.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` is a scalar. Otherwise,\n ``np.array(a).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Pareto distribution.\n\n See Also\n --------\n scipy.stats.lomax : probability density function, distribution or\n cumulative density function, etc.\n scipy.stats.genpareto : probability density function, distribution or\n cumulative densit""y function, etc.\n\n Notes\n -----\n The probability density for the Pareto distribution is\n\n .. math:: p(x) = \\frac{am^a}{x^{a+1}}\n\n where :math:`a` is the shape and :math:`m` the scale.\n\n The Pareto distribution, named after the Italian economist\n Vilfredo Pareto, is a power law probability distribution\n useful in many real world problems. Outside the field of\n economics it is generally referred to as the Bradford\n distribution. Pareto developed the distribution to describe\n the distribution of wealth in an economy. It has also found\n use in insurance, web page access statistics, oil field sizes,\n and many other problems, including the download frequency for\n projects in Sourceforge [1]_. It is one of the so-called\n \"fat-tailed\" distributions.\n\n\n References\n ----------\n .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of\n Sourceforge projects.\n .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne.\n .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme\n Values, Birkhauser Verlag, Basel, pp 23-30.\n .. [4] Wikipedia, \"Pareto distribution\",\n http://en.wikipedia.org/wiki/Pareto_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a, m = 3., 2. # shape and mode\n >>> s = (np.random.pareto(a, 1000) + 1) * m\n\n Display the histogram of the samples, along with the probability\n density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, _ = plt.hist(s, 100, normed=True)\n >>> fit = a*m**a / bins**(a+1)\n >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_63pareto(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_a = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("pareto (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_a,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_a)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "pareto") < 0)) __PYX_ERR(0, 2660, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_a = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("pareto", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2660, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.pareto", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_62pareto(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_a, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_62pareto(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oa = 0; + double __pyx_v_fa; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("pareto", 0); + + /* "mtrand.pyx":2756 + * cdef double fa + * + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oa.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_a, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2756, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oa = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2758 + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oa), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2758, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2758, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2758, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":2759 + * + * if oa.shape == (): + * fa = PyFloat_AsDouble(a) # <<<<<<<<<<<<<< + * + * if fa <= 0: + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_a); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2759, __pyx_L1_error) + __pyx_v_fa = __pyx_t_4; + + /* "mtrand.pyx":2761 + * fa = PyFloat_AsDouble(a) + * + * if fa <= 0: # <<<<<<<<<<<<<< + * raise ValueError("a <= 0") + * return cont1_array_sc(self.internal_state, rk_pareto, size, fa, + */ + __pyx_t_3 = ((__pyx_v_fa <= 0.0) != 0); + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2762 + * + * if fa <= 0: + * raise ValueError("a <= 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_pareto, size, fa, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__103, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2762, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 2762, __pyx_L1_error) + + /* "mtrand.pyx":2761 + * fa = PyFloat_AsDouble(a) + * + * if fa <= 0: # <<<<<<<<<<<<<< + * raise ValueError("a <= 0") + * return cont1_array_sc(self.internal_state, rk_pareto, size, fa, + */ + } + + /* "mtrand.pyx":2763 + * if fa <= 0: + * raise ValueError("a <= 0") + * return cont1_array_sc(self.internal_state, rk_pareto, size, fa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2764 + * raise ValueError("a <= 0") + * return cont1_array_sc(self.internal_state, rk_pareto, size, fa, + * self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(oa, 0.0)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":2763 + * if fa <= 0: + * raise ValueError("a <= 0") + * return cont1_array_sc(self.internal_state, rk_pareto, size, fa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont1_array_sc(__pyx_v_self->internal_state, rk_pareto, __pyx_v_size, __pyx_v_fa, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2763, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2758 + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * + */ + } + + /* "mtrand.pyx":2766 + * self.lock) + * + * if np.any(np.less_equal(oa, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("a <= 0") + * return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock) + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_oa), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_oa), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_oa)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2766, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2767 + * + * if np.any(np.less_equal(oa, 0.0)): + * raise ValueError("a <= 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock) + * + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__104, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2767, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 2767, __pyx_L1_error) + + /* "mtrand.pyx":2766 + * self.lock) + * + * if np.any(np.less_equal(oa, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("a <= 0") + * return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock) + */ + } + + /* "mtrand.pyx":2768 + * if np.any(np.less_equal(oa, 0.0)): + * raise ValueError("a <= 0") + * return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock) # <<<<<<<<<<<<<< + * + * def weibull(self, a, size=None): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + __pyx_t_5 = __pyx_f_6mtrand_cont1_array(__pyx_v_self->internal_state, rk_pareto, __pyx_v_size, __pyx_v_oa, __pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2768, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2660 + * self.lock) + * + * def pareto(self, a, size=None): # <<<<<<<<<<<<<< + * """ + * pareto(a, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.pareto", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oa); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2770 + * return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock) + * + * def weibull(self, a, size=None): # <<<<<<<<<<<<<< + * """ + * weibull(a, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_65weibull(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_64weibull[] = "\n weibull(a, size=None)\n\n Draw samples from a Weibull distribution.\n\n Draw samples from a 1-parameter Weibull distribution with the given\n shape parameter `a`.\n\n .. math:: X = (-ln(U))^{1/a}\n\n Here, U is drawn from the uniform distribution over (0,1].\n\n The more common 2-parameter Weibull, including a scale parameter\n :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`.\n\n Parameters\n ----------\n a : float or array_like of floats\n Shape of the distribution. Should be greater than zero.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` is a scalar. Otherwise,\n ``np.array(a).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Weibull distribution.\n\n See Also\n --------\n scipy.stats.weibull_max\n scipy.stats.weibull_min\n scipy.stats.genextreme\n gumbel\n\n Notes\n -----\n The Weibull (or Type III asymptotic extreme value distribution\n for smallest values, SEV Type III, or Rosin-Rammler\n distribution) is one of a class of Generalized Extreme Value\n (GEV) distributions used in modeling extreme value problems.\n This class includes the Gumbel and Frechet distributions.\n\n The probability density for the Weibull distribution is\n\n .. math:: p(x) = \\frac{a}\n {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a},\n\n where :math:`a` is the shape and :math:`\\lambda` the scale.\n\n The function has its peak (the mode) at\n :math:`\\lambda(\\frac{a-1}{a})^{1/a}`.\n\n When ``a = 1``, the Weibull di""stribution reduces to the exponential\n distribution.\n\n References\n ----------\n .. [1] Waloddi Weibull, Royal Technical University, Stockholm,\n 1939 \"A Statistical Theory Of The Strength Of Materials\",\n Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939,\n Generalstabens Litografiska Anstalts Forlag, Stockholm.\n .. [2] Waloddi Weibull, \"A Statistical Distribution Function of\n Wide Applicability\", Journal Of Applied Mechanics ASME Paper\n 1951.\n .. [3] Wikipedia, \"Weibull distribution\",\n http://en.wikipedia.org/wiki/Weibull_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a = 5. # shape\n >>> s = np.random.weibull(a, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> x = np.arange(1,100.)/50.\n >>> def weib(x,n,a):\n ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a)\n\n >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000))\n >>> x = np.arange(1,100.)/50.\n >>> scale = count.max()/weib(x, 1., 5.).max()\n >>> plt.plot(x, weib(x, 1., 5.)*scale)\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_65weibull(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_a = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("weibull (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_a,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_a)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "weibull") < 0)) __PYX_ERR(0, 2770, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_a = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("weibull", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2770, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.weibull", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_64weibull(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_a, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_64weibull(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oa = 0; + double __pyx_v_fa; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("weibull", 0); + + /* "mtrand.pyx":2866 + * cdef double fa + * + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oa.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_a, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2866, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oa = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2868 + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oa), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2868, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2868, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2868, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":2869 + * + * if oa.shape == (): + * fa = PyFloat_AsDouble(a) # <<<<<<<<<<<<<< + * if np.signbit(fa): + * raise ValueError("a < 0") + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_a); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2869, __pyx_L1_error) + __pyx_v_fa = __pyx_t_4; + + /* "mtrand.pyx":2870 + * if oa.shape == (): + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): # <<<<<<<<<<<<<< + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_weibull, size, fa, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fa); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2870, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2871 + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): + * raise ValueError("a < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_weibull, size, fa, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__105, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2871, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 2871, __pyx_L1_error) + + /* "mtrand.pyx":2870 + * if oa.shape == (): + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): # <<<<<<<<<<<<<< + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_weibull, size, fa, + */ + } + + /* "mtrand.pyx":2872 + * if np.signbit(fa): + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_weibull, size, fa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2873 + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_weibull, size, fa, + * self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oa)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":2872 + * if np.signbit(fa): + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_weibull, size, fa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_5 = __pyx_f_6mtrand_cont1_array_sc(__pyx_v_self->internal_state, rk_weibull, __pyx_v_size, __pyx_v_fa, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2872, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2868 + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): + */ + } + + /* "mtrand.pyx":2875 + * self.lock) + * + * if np.any(np.signbit(oa)): # <<<<<<<<<<<<<< + * raise ValueError("a < 0") + * return cont1_array(self.internal_state, rk_weibull, size, oa, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oa)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oa)}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oa)}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oa)); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2875, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2876 + * + * if np.any(np.signbit(oa)): + * raise ValueError("a < 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_weibull, size, oa, + * self.lock) + */ + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__106, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2876, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 2876, __pyx_L1_error) + + /* "mtrand.pyx":2875 + * self.lock) + * + * if np.any(np.signbit(oa)): # <<<<<<<<<<<<<< + * raise ValueError("a < 0") + * return cont1_array(self.internal_state, rk_weibull, size, oa, + */ + } + + /* "mtrand.pyx":2877 + * if np.any(np.signbit(oa)): + * raise ValueError("a < 0") + * return cont1_array(self.internal_state, rk_weibull, size, oa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2878 + * raise ValueError("a < 0") + * return cont1_array(self.internal_state, rk_weibull, size, oa, + * self.lock) # <<<<<<<<<<<<<< + * + * def power(self, a, size=None): + */ + __pyx_t_5 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_5); + + /* "mtrand.pyx":2877 + * if np.any(np.signbit(oa)): + * raise ValueError("a < 0") + * return cont1_array(self.internal_state, rk_weibull, size, oa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont1_array(__pyx_v_self->internal_state, rk_weibull, __pyx_v_size, __pyx_v_oa, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2877, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2770 + * return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock) + * + * def weibull(self, a, size=None): # <<<<<<<<<<<<<< + * """ + * weibull(a, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.weibull", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oa); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2880 + * self.lock) + * + * def power(self, a, size=None): # <<<<<<<<<<<<<< + * """ + * power(a, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_67power(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_66power[] = "\n power(a, size=None)\n\n Draws samples in [0, 1] from a power distribution with positive\n exponent a - 1.\n\n Also known as the power function distribution.\n\n Parameters\n ----------\n a : float or array_like of floats\n Parameter of the distribution. Should be greater than zero.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` is a scalar. Otherwise,\n ``np.array(a).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized power distribution.\n\n Raises\n ------\n ValueError\n If a < 1.\n\n Notes\n -----\n The probability density function is\n\n .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0.\n\n The power function distribution is just the inverse of the Pareto\n distribution. It may also be seen as a special case of the Beta\n distribution.\n\n It is used, for example, in modeling the over-reporting of insurance\n claims.\n\n References\n ----------\n .. [1] Christian Kleiber, Samuel Kotz, \"Statistical size distributions\n in economics and actuarial sciences\", Wiley, 2003.\n .. [2] Heckert, N. A. and Filliben, James J. \"NIST Handbook 148:\n Dataplot Reference Manual, Volume 2: Let Subcommands and Library\n Functions\", National Institute of Standards and Technology\n Handbook Series, June 2003.\n http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a = 5. # shape\n >>> samples = 100""0\n >>> s = np.random.power(a, samples)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, bins=30)\n >>> x = np.linspace(0, 1, 100)\n >>> y = a*x**(a-1.)\n >>> normed_y = samples*np.diff(bins)[0]*y\n >>> plt.plot(x, normed_y)\n >>> plt.show()\n\n Compare the power function distribution to the inverse of the Pareto.\n\n >>> from scipy import stats\n >>> rvs = np.random.power(5, 1000000)\n >>> rvsp = np.random.pareto(5, 1000000)\n >>> xx = np.linspace(0,1,100)\n >>> powpdf = stats.powerlaw.pdf(xx,5)\n\n >>> plt.figure()\n >>> plt.hist(rvs, bins=50, normed=True)\n >>> plt.plot(xx,powpdf,'r-')\n >>> plt.title('np.random.power(5)')\n\n >>> plt.figure()\n >>> plt.hist(1./(1.+rvsp), bins=50, normed=True)\n >>> plt.plot(xx,powpdf,'r-')\n >>> plt.title('inverse of 1 + np.random.pareto(5)')\n\n >>> plt.figure()\n >>> plt.hist(1./(1.+rvsp), bins=50, normed=True)\n >>> plt.plot(xx,powpdf,'r-')\n >>> plt.title('inverse of stats.pareto(5)')\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_67power(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_a = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("power (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_a,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_a)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "power") < 0)) __PYX_ERR(0, 2880, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_a = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("power", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2880, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.power", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_66power(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_a, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_66power(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oa = 0; + double __pyx_v_fa; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("power", 0); + + /* "mtrand.pyx":2978 + * cdef double fa + * + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oa.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_a, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2978, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oa = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":2980 + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oa), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2980, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2980, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2980, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":2981 + * + * if oa.shape == (): + * fa = PyFloat_AsDouble(a) # <<<<<<<<<<<<<< + * if np.signbit(fa): + * raise ValueError("a < 0") + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_a); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 2981, __pyx_L1_error) + __pyx_v_fa = __pyx_t_4; + + /* "mtrand.pyx":2982 + * if oa.shape == (): + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): # <<<<<<<<<<<<<< + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_power, size, fa, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fa); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2982, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2983 + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): + * raise ValueError("a < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_power, size, fa, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__107, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2983, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 2983, __pyx_L1_error) + + /* "mtrand.pyx":2982 + * if oa.shape == (): + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): # <<<<<<<<<<<<<< + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_power, size, fa, + */ + } + + /* "mtrand.pyx":2984 + * if np.signbit(fa): + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_power, size, fa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":2985 + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_power, size, fa, + * self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oa)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":2984 + * if np.signbit(fa): + * raise ValueError("a < 0") + * return cont1_array_sc(self.internal_state, rk_power, size, fa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_5 = __pyx_f_6mtrand_cont1_array_sc(__pyx_v_self->internal_state, rk_power, __pyx_v_size, __pyx_v_fa, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2984, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2980 + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): + */ + } + + /* "mtrand.pyx":2987 + * self.lock) + * + * if np.any(np.signbit(oa)): # <<<<<<<<<<<<<< + * raise ValueError("a < 0") + * return cont1_array(self.internal_state, rk_power, size, oa, self.lock) + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oa)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oa)}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oa)}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oa)); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 2987, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":2988 + * + * if np.any(np.signbit(oa)): + * raise ValueError("a < 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_power, size, oa, self.lock) + * + */ + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__108, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 2988, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 2988, __pyx_L1_error) + + /* "mtrand.pyx":2987 + * self.lock) + * + * if np.any(np.signbit(oa)): # <<<<<<<<<<<<<< + * raise ValueError("a < 0") + * return cont1_array(self.internal_state, rk_power, size, oa, self.lock) + */ + } + + /* "mtrand.pyx":2989 + * if np.any(np.signbit(oa)): + * raise ValueError("a < 0") + * return cont1_array(self.internal_state, rk_power, size, oa, self.lock) # <<<<<<<<<<<<<< + * + * def laplace(self, loc=0.0, scale=1.0, size=None): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_5 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_5); + __pyx_t_7 = __pyx_f_6mtrand_cont1_array(__pyx_v_self->internal_state, rk_power, __pyx_v_size, __pyx_v_oa, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 2989, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2880 + * self.lock) + * + * def power(self, a, size=None): # <<<<<<<<<<<<<< + * """ + * power(a, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.power", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oa); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":2991 + * return cont1_array(self.internal_state, rk_power, size, oa, self.lock) + * + * def laplace(self, loc=0.0, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * laplace(loc=0.0, scale=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_69laplace(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_68laplace[] = "\n laplace(loc=0.0, scale=1.0, size=None)\n\n Draw samples from the Laplace or double exponential distribution with\n specified location (or mean) and scale (decay).\n\n The Laplace distribution is similar to the Gaussian/normal distribution,\n but is sharper at the peak and has fatter tails. It represents the\n difference between two independent, identically distributed exponential\n random variables.\n\n Parameters\n ----------\n loc : float or array_like of floats, optional\n The position, :math:`\\mu`, of the distribution peak. Default is 0.\n scale : float or array_like of floats, optional\n :math:`\\lambda`, the exponential decay. Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``loc`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Laplace distribution.\n\n Notes\n -----\n It has the probability density function\n\n .. math:: f(x; \\mu, \\lambda) = \\frac{1}{2\\lambda}\n \\exp\\left(-\\frac{|x - \\mu|}{\\lambda}\\right).\n\n The first law of Laplace, from 1774, states that the frequency\n of an error can be expressed as an exponential function of the\n absolute magnitude of the error, which leads to the Laplace\n distribution. For many problems in economics and health\n sciences, this distribution seems to model the data better\n than the standard Gaussian distribution.\n\n References\n ----------\n .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). \"Han""dbook of\n Mathematical Functions with Formulas, Graphs, and Mathematical\n Tables, 9th printing,\" New York: Dover, 1972.\n .. [2] Kotz, Samuel, et. al. \"The Laplace Distribution and\n Generalizations, \" Birkhauser, 2001.\n .. [3] Weisstein, Eric W. \"Laplace Distribution.\"\n From MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/LaplaceDistribution.html\n .. [4] Wikipedia, \"Laplace distribution\",\n http://en.wikipedia.org/wiki/Laplace_distribution\n\n Examples\n --------\n Draw samples from the distribution\n\n >>> loc, scale = 0., 1.\n >>> s = np.random.laplace(loc, scale, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 30, normed=True)\n >>> x = np.arange(-8., 8., .01)\n >>> pdf = np.exp(-abs(x-loc)/scale)/(2.*scale)\n >>> plt.plot(x, pdf)\n\n Plot Gaussian for comparison:\n\n >>> g = (1/(scale * np.sqrt(2 * np.pi)) *\n ... np.exp(-(x - loc)**2 / (2 * scale**2)))\n >>> plt.plot(x,g)\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_69laplace(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_loc = 0; + PyObject *__pyx_v_scale = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("laplace (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_loc,&__pyx_n_s_scale,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[0] = ((PyObject *)__pyx_float_0_0); + values[1] = ((PyObject *)__pyx_float_1_0); + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_loc); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_scale); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "laplace") < 0)) __PYX_ERR(0, 2991, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_loc = values[0]; + __pyx_v_scale = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("laplace", 0, 0, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 2991, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.laplace", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_68laplace(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_loc, __pyx_v_scale, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_68laplace(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_loc, PyObject *__pyx_v_scale, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oloc = 0; + PyArrayObject *__pyx_v_oscale = 0; + double __pyx_v_floc; + double __pyx_v_fscale; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("laplace", 0); + + /* "mtrand.pyx":3073 + * cdef double floc, fscale + * + * oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3073, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3073, __pyx_L1_error) + __pyx_v_oloc = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3074 + * + * oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oloc.shape == oscale.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3074, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3074, __pyx_L1_error) + __pyx_v_oscale = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3076 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oloc.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oloc), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3076, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oscale), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3076, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3076, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3076, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3076, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":3077 + * + * if oloc.shape == oscale.shape == (): + * floc = PyFloat_AsDouble(loc) # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_loc); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3077, __pyx_L1_error) + __pyx_v_floc = __pyx_t_5; + + /* "mtrand.pyx":3078 + * if oloc.shape == oscale.shape == (): + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) # <<<<<<<<<<<<<< + * if np.signbit(fscale): + * raise ValueError("scale < 0") + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_scale); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3078, __pyx_L1_error) + __pyx_v_fscale = __pyx_t_5; + + /* "mtrand.pyx":3079 + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_laplace, size, floc, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fscale); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3079, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3080 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_laplace, size, floc, + * fscale, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__109, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3080, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3080, __pyx_L1_error) + + /* "mtrand.pyx":3079 + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_laplace, size, floc, + */ + } + + /* "mtrand.pyx":3081 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_laplace, size, floc, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3082 + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_laplace, size, floc, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oscale)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":3081 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_laplace, size, floc, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_laplace, __pyx_v_size, __pyx_v_floc, __pyx_v_fscale, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3081, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3076 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oloc.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + */ + } + + /* "mtrand.pyx":3084 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale, + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oscale)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oscale)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oscale)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oscale)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3084, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3085 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__110, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3085, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3085, __pyx_L1_error) + + /* "mtrand.pyx":3084 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale, + */ + } + + /* "mtrand.pyx":3086 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3087 + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale, + * self.lock) # <<<<<<<<<<<<<< + * + * def gumbel(self, loc=0.0, scale=1.0, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":3086 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_laplace, __pyx_v_size, __pyx_v_oloc, __pyx_v_oscale, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3086, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":2991 + * return cont1_array(self.internal_state, rk_power, size, oa, self.lock) + * + * def laplace(self, loc=0.0, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * laplace(loc=0.0, scale=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.laplace", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oloc); + __Pyx_XDECREF((PyObject *)__pyx_v_oscale); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3089 + * self.lock) + * + * def gumbel(self, loc=0.0, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * gumbel(loc=0.0, scale=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_71gumbel(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_70gumbel[] = "\n gumbel(loc=0.0, scale=1.0, size=None)\n\n Draw samples from a Gumbel distribution.\n\n Draw samples from a Gumbel distribution with specified location and\n scale. For more information on the Gumbel distribution, see\n Notes and References below.\n\n Parameters\n ----------\n loc : float or array_like of floats, optional\n The location of the mode of the distribution. Default is 0.\n scale : float or array_like of floats, optional\n The scale parameter of the distribution. Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``loc`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Gumbel distribution.\n\n See Also\n --------\n scipy.stats.gumbel_l\n scipy.stats.gumbel_r\n scipy.stats.genextreme\n weibull\n\n Notes\n -----\n The Gumbel (or Smallest Extreme Value (SEV) or the Smallest Extreme\n Value Type I) distribution is one of a class of Generalized Extreme\n Value (GEV) distributions used in modeling extreme value problems.\n The Gumbel is a special case of the Extreme Value Type I distribution\n for maximums from distributions with \"exponential-like\" tails.\n\n The probability density for the Gumbel distribution is\n\n .. math:: p(x) = \\frac{e^{-(x - \\mu)/ \\beta}}{\\beta} e^{ -e^{-(x - \\mu)/\n \\beta}},\n\n where :math:`\\mu` is the mode, a location parameter, and\n :math:`\\beta` is the scale parameter.\n\n The Gumbel (named for German mathematician ""Emil Julius Gumbel) was used\n very early in the hydrology literature, for modeling the occurrence of\n flood events. It is also used for modeling maximum wind speed and\n rainfall rates. It is a \"fat-tailed\" distribution - the probability of\n an event in the tail of the distribution is larger than if one used a\n Gaussian, hence the surprisingly frequent occurrence of 100-year\n floods. Floods were initially modeled as a Gaussian process, which\n underestimated the frequency of extreme events.\n\n It is one of a class of extreme value distributions, the Generalized\n Extreme Value (GEV) distributions, which also includes the Weibull and\n Frechet.\n\n The function has a mean of :math:`\\mu + 0.57721\\beta` and a variance\n of :math:`\\frac{\\pi^2}{6}\\beta^2`.\n\n References\n ----------\n .. [1] Gumbel, E. J., \"Statistics of Extremes,\"\n New York: Columbia University Press, 1958.\n .. [2] Reiss, R.-D. and Thomas, M., \"Statistical Analysis of Extreme\n Values from Insurance, Finance, Hydrology and Other Fields,\"\n Basel: Birkhauser Verlag, 2001.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> mu, beta = 0, 0.1 # location and scale\n >>> s = np.random.gumbel(mu, beta, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 30, normed=True)\n >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta)\n ... * np.exp( -np.exp( -(bins - mu) /beta) ),\n ... linewidth=2, color='r')\n >>> plt.show()\n\n Show how an extreme value distribution can arise from a Gaussian process\n and compare to a Gaussian:\n\n >>> means = []\n >>> maxima = []\n "" >>> for i in range(0,1000) :\n ... a = np.random.normal(mu, beta, 1000)\n ... means.append(a.mean())\n ... maxima.append(a.max())\n >>> count, bins, ignored = plt.hist(maxima, 30, normed=True)\n >>> beta = np.std(maxima) * np.sqrt(6) / np.pi\n >>> mu = np.mean(maxima) - 0.57721*beta\n >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta)\n ... * np.exp(-np.exp(-(bins - mu)/beta)),\n ... linewidth=2, color='r')\n >>> plt.plot(bins, 1/(beta * np.sqrt(2 * np.pi))\n ... * np.exp(-(bins - mu)**2 / (2 * beta**2)),\n ... linewidth=2, color='g')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_71gumbel(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_loc = 0; + PyObject *__pyx_v_scale = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("gumbel (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_loc,&__pyx_n_s_scale,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[0] = ((PyObject *)__pyx_float_0_0); + values[1] = ((PyObject *)__pyx_float_1_0); + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_loc); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_scale); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "gumbel") < 0)) __PYX_ERR(0, 3089, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_loc = values[0]; + __pyx_v_scale = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("gumbel", 0, 0, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3089, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.gumbel", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_70gumbel(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_loc, __pyx_v_scale, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_70gumbel(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_loc, PyObject *__pyx_v_scale, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oloc = 0; + PyArrayObject *__pyx_v_oscale = 0; + double __pyx_v_floc; + double __pyx_v_fscale; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("gumbel", 0); + + /* "mtrand.pyx":3204 + * cdef double floc, fscale + * + * oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3204, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3204, __pyx_L1_error) + __pyx_v_oloc = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3205 + * + * oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oloc.shape == oscale.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3205, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3205, __pyx_L1_error) + __pyx_v_oscale = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3207 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oloc.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oloc), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3207, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oscale), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3207, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3207, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3207, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3207, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":3208 + * + * if oloc.shape == oscale.shape == (): + * floc = PyFloat_AsDouble(loc) # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_loc); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3208, __pyx_L1_error) + __pyx_v_floc = __pyx_t_5; + + /* "mtrand.pyx":3209 + * if oloc.shape == oscale.shape == (): + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) # <<<<<<<<<<<<<< + * if np.signbit(fscale): + * raise ValueError("scale < 0") + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_scale); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3209, __pyx_L1_error) + __pyx_v_fscale = __pyx_t_5; + + /* "mtrand.pyx":3210 + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fscale); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3210, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3211 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, + * fscale, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__111, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3211, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3211, __pyx_L1_error) + + /* "mtrand.pyx":3210 + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, + */ + } + + /* "mtrand.pyx":3212 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3213 + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oscale)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":3212 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_gumbel, __pyx_v_size, __pyx_v_floc, __pyx_v_fscale, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3207 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oloc.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + */ + } + + /* "mtrand.pyx":3215 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale, + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oscale)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oscale)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oscale)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oscale)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3215, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3216 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__112, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3216, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3216, __pyx_L1_error) + + /* "mtrand.pyx":3215 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale, + */ + } + + /* "mtrand.pyx":3217 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3218 + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale, + * self.lock) # <<<<<<<<<<<<<< + * + * def logistic(self, loc=0.0, scale=1.0, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":3217 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_gumbel, __pyx_v_size, __pyx_v_oloc, __pyx_v_oscale, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3217, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3089 + * self.lock) + * + * def gumbel(self, loc=0.0, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * gumbel(loc=0.0, scale=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.gumbel", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oloc); + __Pyx_XDECREF((PyObject *)__pyx_v_oscale); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3220 + * self.lock) + * + * def logistic(self, loc=0.0, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * logistic(loc=0.0, scale=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_73logistic(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_72logistic[] = "\n logistic(loc=0.0, scale=1.0, size=None)\n\n Draw samples from a logistic distribution.\n\n Samples are drawn from a logistic distribution with specified\n parameters, loc (location or mean, also median), and scale (>0).\n\n Parameters\n ----------\n loc : float or array_like of floats, optional\n Parameter of the distribution. Default is 0.\n scale : float or array_like of floats, optional\n Parameter of the distribution. Should be greater than zero.\n Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``loc`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized logistic distribution.\n\n See Also\n --------\n scipy.stats.logistic : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Logistic distribution is\n\n .. math:: P(x) = P(x) = \\frac{e^{-(x-\\mu)/s}}{s(1+e^{-(x-\\mu)/s})^2},\n\n where :math:`\\mu` = location and :math:`s` = scale.\n\n The Logistic distribution is used in Extreme Value problems where it\n can act as a mixture of Gumbel distributions, in Epidemiology, and by\n the World Chess Federation (FIDE) where it is used in the Elo ranking\n system, assuming the performance of each player is a logistically\n distributed random variable.\n\n References\n ----------\n .. [1] Reiss, R.-D. and Thomas M. (2001), \"Statistical Analysis of\n Extreme Values, from Insurance, Financ""e, Hydrology and Other\n Fields,\" Birkhauser Verlag, Basel, pp 132-133.\n .. [2] Weisstein, Eric W. \"Logistic Distribution.\" From\n MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/LogisticDistribution.html\n .. [3] Wikipedia, \"Logistic-distribution\",\n http://en.wikipedia.org/wiki/Logistic_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> loc, scale = 10, 1\n >>> s = np.random.logistic(loc, scale, 10000)\n >>> count, bins, ignored = plt.hist(s, bins=50)\n\n # plot against distribution\n\n >>> def logist(x, loc, scale):\n ... return exp((loc-x)/scale)/(scale*(1+exp((loc-x)/scale))**2)\n >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\\\n ... logist(bins, loc, scale).max())\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_73logistic(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_loc = 0; + PyObject *__pyx_v_scale = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("logistic (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_loc,&__pyx_n_s_scale,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[0] = ((PyObject *)__pyx_float_0_0); + values[1] = ((PyObject *)__pyx_float_1_0); + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_loc); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_scale); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "logistic") < 0)) __PYX_ERR(0, 3220, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_loc = values[0]; + __pyx_v_scale = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("logistic", 0, 0, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3220, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.logistic", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_72logistic(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_loc, __pyx_v_scale, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_72logistic(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_loc, PyObject *__pyx_v_scale, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oloc = 0; + PyArrayObject *__pyx_v_oscale = 0; + double __pyx_v_floc; + double __pyx_v_fscale; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("logistic", 0); + + /* "mtrand.pyx":3297 + * cdef double floc, fscale + * + * oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3297, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3297, __pyx_L1_error) + __pyx_v_oloc = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3298 + * + * oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oloc.shape == oscale.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3298, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3298, __pyx_L1_error) + __pyx_v_oscale = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3300 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oloc.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oloc), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3300, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oscale), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3300, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3300, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3300, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3300, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":3301 + * + * if oloc.shape == oscale.shape == (): + * floc = PyFloat_AsDouble(loc) # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_loc); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3301, __pyx_L1_error) + __pyx_v_floc = __pyx_t_5; + + /* "mtrand.pyx":3302 + * if oloc.shape == oscale.shape == (): + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) # <<<<<<<<<<<<<< + * if np.signbit(fscale): + * raise ValueError("scale < 0") + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_scale); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3302, __pyx_L1_error) + __pyx_v_fscale = __pyx_t_5; + + /* "mtrand.pyx":3303 + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_logistic, size, floc, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fscale); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3303, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3304 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_logistic, size, floc, + * fscale, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__113, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3304, __pyx_L1_error) + + /* "mtrand.pyx":3303 + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_logistic, size, floc, + */ + } + + /* "mtrand.pyx":3305 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_logistic, size, floc, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3306 + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_logistic, size, floc, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oscale)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":3305 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont2_array_sc(self.internal_state, rk_logistic, size, floc, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_logistic, __pyx_v_size, __pyx_v_floc, __pyx_v_fscale, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3305, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3300 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oloc.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * floc = PyFloat_AsDouble(loc) + * fscale = PyFloat_AsDouble(scale) + */ + } + + /* "mtrand.pyx":3308 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_logistic, size, oloc, + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oscale)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oscale)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oscale)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oscale)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3308, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3309 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_logistic, size, oloc, + * oscale, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__114, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3309, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3309, __pyx_L1_error) + + /* "mtrand.pyx":3308 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_logistic, size, oloc, + */ + } + + /* "mtrand.pyx":3310 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_logistic, size, oloc, # <<<<<<<<<<<<<< + * oscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3311 + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_logistic, size, oloc, + * oscale, self.lock) # <<<<<<<<<<<<<< + * + * def lognormal(self, mean=0.0, sigma=1.0, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":3310 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + * return cont2_array(self.internal_state, rk_logistic, size, oloc, # <<<<<<<<<<<<<< + * oscale, self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_logistic, __pyx_v_size, __pyx_v_oloc, __pyx_v_oscale, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3220 + * self.lock) + * + * def logistic(self, loc=0.0, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * logistic(loc=0.0, scale=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.logistic", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oloc); + __Pyx_XDECREF((PyObject *)__pyx_v_oscale); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3313 + * oscale, self.lock) + * + * def lognormal(self, mean=0.0, sigma=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * lognormal(mean=0.0, sigma=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_75lognormal(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_74lognormal[] = "\n lognormal(mean=0.0, sigma=1.0, size=None)\n\n Draw samples from a log-normal distribution.\n\n Draw samples from a log-normal distribution with specified mean,\n standard deviation, and array shape. Note that the mean and standard\n deviation are not the values for the distribution itself, but of the\n underlying normal distribution it is derived from.\n\n Parameters\n ----------\n mean : float or array_like of floats, optional\n Mean value of the underlying normal distribution. Default is 0.\n sigma : float or array_like of floats, optional\n Standard deviation of the underlying normal distribution. Should\n be greater than zero. Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``mean`` and ``sigma`` are both scalars.\n Otherwise, ``np.broadcast(mean, sigma).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized log-normal distribution.\n\n See Also\n --------\n scipy.stats.lognorm : probability density function, distribution,\n cumulative density function, etc.\n\n Notes\n -----\n A variable `x` has a log-normal distribution if `log(x)` is normally\n distributed. The probability density function for the log-normal\n distribution is:\n\n .. math:: p(x) = \\frac{1}{\\sigma x \\sqrt{2\\pi}}\n e^{(-\\frac{(ln(x)-\\mu)^2}{2\\sigma^2})}\n\n where :math:`\\mu` is the mean and :math:`\\sigma` is the standard\n deviation of the normally distributed logarithm of the variable.\n A log-normal distribution results if a random variable is the *produc""t*\n of a large number of independent, identically-distributed variables in\n the same way that a normal distribution results if the variable is the\n *sum* of a large number of independent, identically-distributed\n variables.\n\n References\n ----------\n .. [1] Limpert, E., Stahel, W. A., and Abbt, M., \"Log-normal\n Distributions across the Sciences: Keys and Clues,\"\n BioScience, Vol. 51, No. 5, May, 2001.\n http://stat.ethz.ch/~stahel/lognormal/bioscience.pdf\n .. [2] Reiss, R.D. and Thomas, M., \"Statistical Analysis of Extreme\n Values,\" Basel: Birkhauser Verlag, 2001, pp. 31-32.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> mu, sigma = 3., 1. # mean and standard deviation\n >>> s = np.random.lognormal(mu, sigma, 1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 100, normed=True, align='mid')\n\n >>> x = np.linspace(min(bins), max(bins), 10000)\n >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2))\n ... / (x * sigma * np.sqrt(2 * np.pi)))\n\n >>> plt.plot(x, pdf, linewidth=2, color='r')\n >>> plt.axis('tight')\n >>> plt.show()\n\n Demonstrate that taking the products of random samples from a uniform\n distribution can be fit well by a log-normal probability density\n function.\n\n >>> # Generate a thousand samples: each is the product of 100 random\n >>> # values, drawn from a normal distribution.\n >>> b = []\n >>> for i in range(1000):\n ... a = 10. + np.random.random(100)\n ... b.append(np.product(a))\n\n >>> b = np.array(b) / np.min(b) # scale values to be positive\n >>> count, bins, ignored = plt.h""ist(b, 100, normed=True, align='mid')\n >>> sigma = np.std(np.log(b))\n >>> mu = np.mean(np.log(b))\n\n >>> x = np.linspace(min(bins), max(bins), 10000)\n >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2))\n ... / (x * sigma * np.sqrt(2 * np.pi)))\n\n >>> plt.plot(x, pdf, color='r', linewidth=2)\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_75lognormal(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_mean = 0; + PyObject *__pyx_v_sigma = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("lognormal (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_mean,&__pyx_n_s_sigma,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[0] = ((PyObject *)__pyx_float_0_0); + values[1] = ((PyObject *)__pyx_float_1_0); + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mean); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_sigma); + if (value) { values[1] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "lognormal") < 0)) __PYX_ERR(0, 3313, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_mean = values[0]; + __pyx_v_sigma = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("lognormal", 0, 0, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3313, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.lognormal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_74lognormal(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_mean, __pyx_v_sigma, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_74lognormal(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_mean, PyObject *__pyx_v_sigma, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_omean = 0; + PyArrayObject *__pyx_v_osigma = 0; + double __pyx_v_fmean; + double __pyx_v_fsigma; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("lognormal", 0); + + /* "mtrand.pyx":3421 + * cdef double fmean, fsigma + * + * omean = PyArray_FROM_OTF(mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * osigma = PyArray_FROM_OTF(sigma, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3421, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3421, __pyx_L1_error) + __pyx_v_omean = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3422 + * + * omean = PyArray_FROM_OTF(mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * osigma = PyArray_FROM_OTF(sigma, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if omean.shape == osigma.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_sigma, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3422, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3422, __pyx_L1_error) + __pyx_v_osigma = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3424 + * osigma = PyArray_FROM_OTF(sigma, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if omean.shape == osigma.shape == (): # <<<<<<<<<<<<<< + * fmean = PyFloat_AsDouble(mean) + * fsigma = PyFloat_AsDouble(sigma) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_omean), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_osigma), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3424, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3424, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3424, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3424, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":3425 + * + * if omean.shape == osigma.shape == (): + * fmean = PyFloat_AsDouble(mean) # <<<<<<<<<<<<<< + * fsigma = PyFloat_AsDouble(sigma) + * if np.signbit(fsigma): + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_mean); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3425, __pyx_L1_error) + __pyx_v_fmean = __pyx_t_5; + + /* "mtrand.pyx":3426 + * if omean.shape == osigma.shape == (): + * fmean = PyFloat_AsDouble(mean) + * fsigma = PyFloat_AsDouble(sigma) # <<<<<<<<<<<<<< + * if np.signbit(fsigma): + * raise ValueError("sigma < 0") + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_sigma); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3426, __pyx_L1_error) + __pyx_v_fsigma = __pyx_t_5; + + /* "mtrand.pyx":3427 + * fmean = PyFloat_AsDouble(mean) + * fsigma = PyFloat_AsDouble(sigma) + * if np.signbit(fsigma): # <<<<<<<<<<<<<< + * raise ValueError("sigma < 0") + * return cont2_array_sc(self.internal_state, rk_lognormal, size, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fsigma); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3427, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3428 + * fsigma = PyFloat_AsDouble(sigma) + * if np.signbit(fsigma): + * raise ValueError("sigma < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_lognormal, size, + * fmean, fsigma, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__115, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3428, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3428, __pyx_L1_error) + + /* "mtrand.pyx":3427 + * fmean = PyFloat_AsDouble(mean) + * fsigma = PyFloat_AsDouble(sigma) + * if np.signbit(fsigma): # <<<<<<<<<<<<<< + * raise ValueError("sigma < 0") + * return cont2_array_sc(self.internal_state, rk_lognormal, size, + */ + } + + /* "mtrand.pyx":3429 + * if np.signbit(fsigma): + * raise ValueError("sigma < 0") + * return cont2_array_sc(self.internal_state, rk_lognormal, size, # <<<<<<<<<<<<<< + * fmean, fsigma, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3430 + * raise ValueError("sigma < 0") + * return cont2_array_sc(self.internal_state, rk_lognormal, size, + * fmean, fsigma, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(osigma)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":3429 + * if np.signbit(fsigma): + * raise ValueError("sigma < 0") + * return cont2_array_sc(self.internal_state, rk_lognormal, size, # <<<<<<<<<<<<<< + * fmean, fsigma, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_lognormal, __pyx_v_size, __pyx_v_fmean, __pyx_v_fsigma, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3429, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3424 + * osigma = PyArray_FROM_OTF(sigma, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if omean.shape == osigma.shape == (): # <<<<<<<<<<<<<< + * fmean = PyFloat_AsDouble(mean) + * fsigma = PyFloat_AsDouble(sigma) + */ + } + + /* "mtrand.pyx":3432 + * fmean, fsigma, self.lock) + * + * if np.any(np.signbit(osigma)): # <<<<<<<<<<<<<< + * raise ValueError("sigma < 0.0") + * return cont2_array(self.internal_state, rk_lognormal, size, omean, + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_osigma)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_osigma)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_osigma)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_osigma)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_osigma)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_osigma)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3432, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3433 + * + * if np.any(np.signbit(osigma)): + * raise ValueError("sigma < 0.0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_lognormal, size, omean, + * osigma, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__116, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3433, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3433, __pyx_L1_error) + + /* "mtrand.pyx":3432 + * fmean, fsigma, self.lock) + * + * if np.any(np.signbit(osigma)): # <<<<<<<<<<<<<< + * raise ValueError("sigma < 0.0") + * return cont2_array(self.internal_state, rk_lognormal, size, omean, + */ + } + + /* "mtrand.pyx":3434 + * if np.any(np.signbit(osigma)): + * raise ValueError("sigma < 0.0") + * return cont2_array(self.internal_state, rk_lognormal, size, omean, # <<<<<<<<<<<<<< + * osigma, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3435 + * raise ValueError("sigma < 0.0") + * return cont2_array(self.internal_state, rk_lognormal, size, omean, + * osigma, self.lock) # <<<<<<<<<<<<<< + * + * def rayleigh(self, scale=1.0, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":3434 + * if np.any(np.signbit(osigma)): + * raise ValueError("sigma < 0.0") + * return cont2_array(self.internal_state, rk_lognormal, size, omean, # <<<<<<<<<<<<<< + * osigma, self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_lognormal, __pyx_v_size, __pyx_v_omean, __pyx_v_osigma, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3434, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3313 + * oscale, self.lock) + * + * def lognormal(self, mean=0.0, sigma=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * lognormal(mean=0.0, sigma=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.lognormal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_omean); + __Pyx_XDECREF((PyObject *)__pyx_v_osigma); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3437 + * osigma, self.lock) + * + * def rayleigh(self, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * rayleigh(scale=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_77rayleigh(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_76rayleigh[] = "\n rayleigh(scale=1.0, size=None)\n\n Draw samples from a Rayleigh distribution.\n\n The :math:`\\chi` and Weibull distributions are generalizations of the\n Rayleigh.\n\n Parameters\n ----------\n scale : float or array_like of floats, optional\n Scale, also equals the mode. Should be >= 0. Default is 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``scale`` is a scalar. Otherwise,\n ``np.array(scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Rayleigh distribution.\n\n Notes\n -----\n The probability density function for the Rayleigh distribution is\n\n .. math:: P(x;scale) = \\frac{x}{scale^2}e^{\\frac{-x^2}{2 \\cdotp scale^2}}\n\n The Rayleigh distribution would arise, for example, if the East\n and North components of the wind velocity had identical zero-mean\n Gaussian distributions. Then the wind speed would have a Rayleigh\n distribution.\n\n References\n ----------\n .. [1] Brighton Webs Ltd., \"Rayleigh Distribution,\"\n http://www.brighton-webs.co.uk/distributions/rayleigh.asp\n .. [2] Wikipedia, \"Rayleigh distribution\"\n http://en.wikipedia.org/wiki/Rayleigh_distribution\n\n Examples\n --------\n Draw values from the distribution and plot the histogram\n\n >>> values = hist(np.random.rayleigh(3, 100000), bins=200, normed=True)\n\n Wave heights tend to follow a Rayleigh distribution. If the mean wave\n height is 1 meter, what fraction of waves are likely to be larger than 3\n meters?\n\n >>> meanvalue = 1\n >>> mo""devalue = np.sqrt(2 / np.pi) * meanvalue\n >>> s = np.random.rayleigh(modevalue, 1000000)\n\n The percentage of waves larger than 3 meters is:\n\n >>> 100.*sum(s>3)/1000000.\n 0.087300000000000003\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_77rayleigh(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_scale = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("rayleigh (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_scale,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[0] = ((PyObject *)__pyx_float_1_0); + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_scale); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "rayleigh") < 0)) __PYX_ERR(0, 3437, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_scale = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("rayleigh", 0, 0, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3437, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.rayleigh", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_76rayleigh(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_scale, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_76rayleigh(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_scale, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oscale = 0; + double __pyx_v_fscale; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("rayleigh", 0); + + /* "mtrand.pyx":3502 + * cdef double fscale + * + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oscale.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3502, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oscale = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":3504 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oscale.shape == (): # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oscale), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3504, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3504, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 3504, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":3505 + * + * if oscale.shape == (): + * fscale = PyFloat_AsDouble(scale) # <<<<<<<<<<<<<< + * if np.signbit(fscale): + * raise ValueError("scale < 0") + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_scale); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3505, __pyx_L1_error) + __pyx_v_fscale = __pyx_t_4; + + /* "mtrand.pyx":3506 + * if oscale.shape == (): + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_rayleigh, size, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fscale); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_6) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 3506, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":3507 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_rayleigh, size, + * fscale, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__117, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3507, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3507, __pyx_L1_error) + + /* "mtrand.pyx":3506 + * if oscale.shape == (): + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_rayleigh, size, + */ + } + + /* "mtrand.pyx":3508 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_rayleigh, size, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3509 + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_rayleigh, size, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.signbit(oscale)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":3508 + * if np.signbit(fscale): + * raise ValueError("scale < 0") + * return cont1_array_sc(self.internal_state, rk_rayleigh, size, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_5 = __pyx_f_6mtrand_cont1_array_sc(__pyx_v_self->internal_state, rk_rayleigh, __pyx_v_size, __pyx_v_fscale, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3504 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oscale.shape == (): # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + */ + } + + /* "mtrand.pyx":3511 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0.0") + * return cont1_array(self.internal_state, rk_rayleigh, size, oscale, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_signbit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_2) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_6, ((PyObject *)__pyx_v_oscale)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_2, ((PyObject *)__pyx_v_oscale)}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_2); __pyx_t_2 = NULL; + __Pyx_INCREF(((PyObject *)__pyx_v_oscale)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oscale)); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, ((PyObject *)__pyx_v_oscale)); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_1}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 3511, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":3512 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0.0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_rayleigh, size, oscale, + * self.lock) + */ + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__118, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3512, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_Raise(__pyx_t_5, 0, 0, 0); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __PYX_ERR(0, 3512, __pyx_L1_error) + + /* "mtrand.pyx":3511 + * fscale, self.lock) + * + * if np.any(np.signbit(oscale)): # <<<<<<<<<<<<<< + * raise ValueError("scale < 0.0") + * return cont1_array(self.internal_state, rk_rayleigh, size, oscale, + */ + } + + /* "mtrand.pyx":3513 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0.0") + * return cont1_array(self.internal_state, rk_rayleigh, size, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3514 + * raise ValueError("scale < 0.0") + * return cont1_array(self.internal_state, rk_rayleigh, size, oscale, + * self.lock) # <<<<<<<<<<<<<< + * + * def wald(self, mean, scale, size=None): + */ + __pyx_t_5 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_5); + + /* "mtrand.pyx":3513 + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0.0") + * return cont1_array(self.internal_state, rk_rayleigh, size, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_7 = __pyx_f_6mtrand_cont1_array(__pyx_v_self->internal_state, rk_rayleigh, __pyx_v_size, __pyx_v_oscale, __pyx_t_5); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3513, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_r = __pyx_t_7; + __pyx_t_7 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3437 + * osigma, self.lock) + * + * def rayleigh(self, scale=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * rayleigh(scale=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.rayleigh", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oscale); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3516 + * self.lock) + * + * def wald(self, mean, scale, size=None): # <<<<<<<<<<<<<< + * """ + * wald(mean, scale, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_79wald(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_78wald[] = "\n wald(mean, scale, size=None)\n\n Draw samples from a Wald, or inverse Gaussian, distribution.\n\n As the scale approaches infinity, the distribution becomes more like a\n Gaussian. Some references claim that the Wald is an inverse Gaussian\n with mean equal to 1, but this is by no means universal.\n\n The inverse Gaussian distribution was first studied in relationship to\n Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian\n because there is an inverse relationship between the time to cover a\n unit distance and distance covered in unit time.\n\n Parameters\n ----------\n mean : float or array_like of floats\n Distribution mean, should be > 0.\n scale : float or array_like of floats\n Scale parameter, should be >= 0.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``mean`` and ``scale`` are both scalars.\n Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Wald distribution.\n\n Notes\n -----\n The probability density function for the Wald distribution is\n\n .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^\n \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x}\n\n As noted above the inverse Gaussian distribution first arise\n from attempts to model Brownian motion. It is also a\n competitor to the Weibull for use in reliability modeling and\n modeling stock returns and interest rate processes.\n\n References\n ----------\n .. [1] Brighton Webs Ltd., Wald Distribution,\n "" http://www.brighton-webs.co.uk/distributions/wald.asp\n .. [2] Chhikara, Raj S., and Folks, J. Leroy, \"The Inverse Gaussian\n Distribution: Theory : Methodology, and Applications\", CRC Press,\n 1988.\n .. [3] Wikipedia, \"Wald distribution\"\n http://en.wikipedia.org/wiki/Wald_distribution\n\n Examples\n --------\n Draw values from the distribution and plot the histogram:\n\n >>> import matplotlib.pyplot as plt\n >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, normed=True)\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_79wald(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_mean = 0; + PyObject *__pyx_v_scale = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("wald (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_mean,&__pyx_n_s_scale,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mean)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_scale)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("wald", 0, 2, 3, 1); __PYX_ERR(0, 3516, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "wald") < 0)) __PYX_ERR(0, 3516, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_mean = values[0]; + __pyx_v_scale = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("wald", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3516, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.wald", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_78wald(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_mean, __pyx_v_scale, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_78wald(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_mean, PyObject *__pyx_v_scale, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_omean = 0; + PyArrayObject *__pyx_v_oscale = 0; + double __pyx_v_fmean; + double __pyx_v_fscale; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("wald", 0); + + /* "mtrand.pyx":3582 + * cdef double fmean, fscale + * + * omean = PyArray_FROM_OTF(mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3582, __pyx_L1_error) + __pyx_v_omean = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3583 + * + * omean = PyArray_FROM_OTF(mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if omean.shape == oscale.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3583, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_6mtrand_ndarray))))) __PYX_ERR(0, 3583, __pyx_L1_error) + __pyx_v_oscale = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3585 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if omean.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * fmean = PyFloat_AsDouble(mean) + * fscale = PyFloat_AsDouble(scale) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_omean), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3585, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oscale), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3585, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3585, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3585, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3585, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":3586 + * + * if omean.shape == oscale.shape == (): + * fmean = PyFloat_AsDouble(mean) # <<<<<<<<<<<<<< + * fscale = PyFloat_AsDouble(scale) + * + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_mean); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3586, __pyx_L1_error) + __pyx_v_fmean = __pyx_t_5; + + /* "mtrand.pyx":3587 + * if omean.shape == oscale.shape == (): + * fmean = PyFloat_AsDouble(mean) + * fscale = PyFloat_AsDouble(scale) # <<<<<<<<<<<<<< + * + * if fmean <= 0: + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_scale); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3587, __pyx_L1_error) + __pyx_v_fscale = __pyx_t_5; + + /* "mtrand.pyx":3589 + * fscale = PyFloat_AsDouble(scale) + * + * if fmean <= 0: # <<<<<<<<<<<<<< + * raise ValueError("mean <= 0") + * if fscale <= 0: + */ + __pyx_t_4 = ((__pyx_v_fmean <= 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3590 + * + * if fmean <= 0: + * raise ValueError("mean <= 0") # <<<<<<<<<<<<<< + * if fscale <= 0: + * raise ValueError("scale <= 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__119, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3590, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3590, __pyx_L1_error) + + /* "mtrand.pyx":3589 + * fscale = PyFloat_AsDouble(scale) + * + * if fmean <= 0: # <<<<<<<<<<<<<< + * raise ValueError("mean <= 0") + * if fscale <= 0: + */ + } + + /* "mtrand.pyx":3591 + * if fmean <= 0: + * raise ValueError("mean <= 0") + * if fscale <= 0: # <<<<<<<<<<<<<< + * raise ValueError("scale <= 0") + * return cont2_array_sc(self.internal_state, rk_wald, size, fmean, + */ + __pyx_t_4 = ((__pyx_v_fscale <= 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3592 + * raise ValueError("mean <= 0") + * if fscale <= 0: + * raise ValueError("scale <= 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_wald, size, fmean, + * fscale, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__120, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3592, __pyx_L1_error) + + /* "mtrand.pyx":3591 + * if fmean <= 0: + * raise ValueError("mean <= 0") + * if fscale <= 0: # <<<<<<<<<<<<<< + * raise ValueError("scale <= 0") + * return cont2_array_sc(self.internal_state, rk_wald, size, fmean, + */ + } + + /* "mtrand.pyx":3593 + * if fscale <= 0: + * raise ValueError("scale <= 0") + * return cont2_array_sc(self.internal_state, rk_wald, size, fmean, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3594 + * raise ValueError("scale <= 0") + * return cont2_array_sc(self.internal_state, rk_wald, size, fmean, + * fscale, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(omean,0.0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":3593 + * if fscale <= 0: + * raise ValueError("scale <= 0") + * return cont2_array_sc(self.internal_state, rk_wald, size, fmean, # <<<<<<<<<<<<<< + * fscale, self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_cont2_array_sc(__pyx_v_self->internal_state, rk_wald, __pyx_v_size, __pyx_v_fmean, __pyx_v_fscale, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3593, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3585 + * oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if omean.shape == oscale.shape == (): # <<<<<<<<<<<<<< + * fmean = PyFloat_AsDouble(mean) + * fscale = PyFloat_AsDouble(scale) + */ + } + + /* "mtrand.pyx":3596 + * fscale, self.lock) + * + * if np.any(np.less_equal(omean,0.0)): # <<<<<<<<<<<<<< + * raise ValueError("mean <= 0.0") + * elif np.any(np.less_equal(oscale,0.0)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_omean), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_omean), __pyx_float_0_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_omean)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_omean)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_omean)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3596, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3597 + * + * if np.any(np.less_equal(omean,0.0)): + * raise ValueError("mean <= 0.0") # <<<<<<<<<<<<<< + * elif np.any(np.less_equal(oscale,0.0)): + * raise ValueError("scale <= 0.0") + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__121, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3597, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 3597, __pyx_L1_error) + + /* "mtrand.pyx":3596 + * fscale, self.lock) + * + * if np.any(np.less_equal(omean,0.0)): # <<<<<<<<<<<<<< + * raise ValueError("mean <= 0.0") + * elif np.any(np.less_equal(oscale,0.0)): + */ + } + + /* "mtrand.pyx":3598 + * if np.any(np.less_equal(omean,0.0)): + * raise ValueError("mean <= 0.0") + * elif np.any(np.less_equal(oscale,0.0)): # <<<<<<<<<<<<<< + * raise ValueError("scale <= 0.0") + * return cont2_array(self.internal_state, rk_wald, size, omean, oscale, + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_oscale), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_oscale), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oscale)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oscale)); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_8, ((PyObject *)__pyx_v_oscale)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3598, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3599 + * raise ValueError("mean <= 0.0") + * elif np.any(np.less_equal(oscale,0.0)): + * raise ValueError("scale <= 0.0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_wald, size, omean, oscale, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__122, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3599, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 3599, __pyx_L1_error) + + /* "mtrand.pyx":3598 + * if np.any(np.less_equal(omean,0.0)): + * raise ValueError("mean <= 0.0") + * elif np.any(np.less_equal(oscale,0.0)): # <<<<<<<<<<<<<< + * raise ValueError("scale <= 0.0") + * return cont2_array(self.internal_state, rk_wald, size, omean, oscale, + */ + } + + /* "mtrand.pyx":3600 + * elif np.any(np.less_equal(oscale,0.0)): + * raise ValueError("scale <= 0.0") + * return cont2_array(self.internal_state, rk_wald, size, omean, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3601 + * raise ValueError("scale <= 0.0") + * return cont2_array(self.internal_state, rk_wald, size, omean, oscale, + * self.lock) # <<<<<<<<<<<<<< + * + * def triangular(self, left, mode, right, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":3600 + * elif np.any(np.less_equal(oscale,0.0)): + * raise ValueError("scale <= 0.0") + * return cont2_array(self.internal_state, rk_wald, size, omean, oscale, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_9 = __pyx_f_6mtrand_cont2_array(__pyx_v_self->internal_state, rk_wald, __pyx_v_size, __pyx_v_omean, __pyx_v_oscale, __pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3600, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_9; + __pyx_t_9 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3516 + * self.lock) + * + * def wald(self, mean, scale, size=None): # <<<<<<<<<<<<<< + * """ + * wald(mean, scale, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.wald", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_omean); + __Pyx_XDECREF((PyObject *)__pyx_v_oscale); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3603 + * self.lock) + * + * def triangular(self, left, mode, right, size=None): # <<<<<<<<<<<<<< + * """ + * triangular(left, mode, right, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_81triangular(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_80triangular[] = "\n triangular(left, mode, right, size=None)\n\n Draw samples from the triangular distribution over the\n interval ``[left, right]``.\n\n The triangular distribution is a continuous probability\n distribution with lower limit left, peak at mode, and upper\n limit right. Unlike the other distributions, these parameters\n directly define the shape of the pdf.\n\n Parameters\n ----------\n left : float or array_like of floats\n Lower limit.\n mode : float or array_like of floats\n The value where the peak of the distribution occurs.\n The value should fulfill the condition ``left <= mode <= right``.\n right : float or array_like of floats\n Upper limit, should be larger than `left`.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``left``, ``mode``, and ``right``\n are all scalars. Otherwise, ``np.broadcast(left, mode, right).size``\n samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized triangular distribution.\n\n Notes\n -----\n The probability density function for the triangular distribution is\n\n .. math:: P(x;l, m, r) = \\begin{cases}\n \\frac{2(x-l)}{(r-l)(m-l)}& \\text{for $l \\leq x \\leq m$},\\\\\n \\frac{2(r-x)}{(r-l)(r-m)}& \\text{for $m \\leq x \\leq r$},\\\\\n 0& \\text{otherwise}.\n \\end{cases}\n\n The triangular distribution is often used in ill-defined\n problems where the underlying distribution is not known, but\n some knowledge of the limits and mode exists. Often it is used\n in simulations.\n\n "" References\n ----------\n .. [1] Wikipedia, \"Triangular distribution\"\n http://en.wikipedia.org/wiki/Triangular_distribution\n\n Examples\n --------\n Draw values from the distribution and plot the histogram:\n\n >>> import matplotlib.pyplot as plt\n >>> h = plt.hist(np.random.triangular(-3, 0, 8, 100000), bins=200,\n ... normed=True)\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_81triangular(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_left = 0; + PyObject *__pyx_v_mode = 0; + PyObject *__pyx_v_right = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("triangular (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_left,&__pyx_n_s_mode,&__pyx_n_s_right,&__pyx_n_s_size,0}; + PyObject* values[4] = {0,0,0,0}; + values[3] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_left)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mode)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("triangular", 0, 3, 4, 1); __PYX_ERR(0, 3603, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_right)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("triangular", 0, 3, 4, 2); __PYX_ERR(0, 3603, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[3] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "triangular") < 0)) __PYX_ERR(0, 3603, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_left = values[0]; + __pyx_v_mode = values[1]; + __pyx_v_right = values[2]; + __pyx_v_size = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("triangular", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3603, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.triangular", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_80triangular(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_left, __pyx_v_mode, __pyx_v_right, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_80triangular(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_left, PyObject *__pyx_v_mode, PyObject *__pyx_v_right, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oleft = 0; + PyArrayObject *__pyx_v_omode = 0; + PyArrayObject *__pyx_v_oright = 0; + double __pyx_v_fleft; + double __pyx_v_fmode; + double __pyx_v_fright; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + double __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("triangular", 0); + + /* "mtrand.pyx":3669 + * cdef double fleft, fmode, fright + * + * oleft = PyArray_FROM_OTF(left, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * omode = PyArray_FROM_OTF(mode, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * oright = PyArray_FROM_OTF(right, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_left, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3669, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oleft = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":3670 + * + * oleft = PyArray_FROM_OTF(left, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * omode = PyArray_FROM_OTF(mode, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * oright = PyArray_FROM_OTF(right, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_mode, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3670, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_omode = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3671 + * oleft = PyArray_FROM_OTF(left, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * omode = PyArray_FROM_OTF(mode, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * oright = PyArray_FROM_OTF(right, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oleft.shape == omode.shape == oright.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_right, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3671, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oright = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":3673 + * oright = PyArray_FROM_OTF(right, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oleft.shape == omode.shape == oright.shape == (): # <<<<<<<<<<<<<< + * fleft = PyFloat_AsDouble(left) + * fright = PyFloat_AsDouble(right) + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oleft), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3673, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_omode), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3673, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_t_1, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3673, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oright), __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 3673, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3673, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_4, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3673, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 3673, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_5) { + + /* "mtrand.pyx":3674 + * + * if oleft.shape == omode.shape == oright.shape == (): + * fleft = PyFloat_AsDouble(left) # <<<<<<<<<<<<<< + * fright = PyFloat_AsDouble(right) + * fmode = PyFloat_AsDouble(mode) + */ + __pyx_t_6 = PyFloat_AsDouble(__pyx_v_left); if (unlikely(__pyx_t_6 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3674, __pyx_L1_error) + __pyx_v_fleft = __pyx_t_6; + + /* "mtrand.pyx":3675 + * if oleft.shape == omode.shape == oright.shape == (): + * fleft = PyFloat_AsDouble(left) + * fright = PyFloat_AsDouble(right) # <<<<<<<<<<<<<< + * fmode = PyFloat_AsDouble(mode) + * + */ + __pyx_t_6 = PyFloat_AsDouble(__pyx_v_right); if (unlikely(__pyx_t_6 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3675, __pyx_L1_error) + __pyx_v_fright = __pyx_t_6; + + /* "mtrand.pyx":3676 + * fleft = PyFloat_AsDouble(left) + * fright = PyFloat_AsDouble(right) + * fmode = PyFloat_AsDouble(mode) # <<<<<<<<<<<<<< + * + * if fleft > fmode: + */ + __pyx_t_6 = PyFloat_AsDouble(__pyx_v_mode); if (unlikely(__pyx_t_6 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3676, __pyx_L1_error) + __pyx_v_fmode = __pyx_t_6; + + /* "mtrand.pyx":3678 + * fmode = PyFloat_AsDouble(mode) + * + * if fleft > fmode: # <<<<<<<<<<<<<< + * raise ValueError("left > mode") + * if fmode > fright: + */ + __pyx_t_5 = ((__pyx_v_fleft > __pyx_v_fmode) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":3679 + * + * if fleft > fmode: + * raise ValueError("left > mode") # <<<<<<<<<<<<<< + * if fmode > fright: + * raise ValueError("mode > right") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__123, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3679, __pyx_L1_error) + + /* "mtrand.pyx":3678 + * fmode = PyFloat_AsDouble(mode) + * + * if fleft > fmode: # <<<<<<<<<<<<<< + * raise ValueError("left > mode") + * if fmode > fright: + */ + } + + /* "mtrand.pyx":3680 + * if fleft > fmode: + * raise ValueError("left > mode") + * if fmode > fright: # <<<<<<<<<<<<<< + * raise ValueError("mode > right") + * if fleft == fright: + */ + __pyx_t_5 = ((__pyx_v_fmode > __pyx_v_fright) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":3681 + * raise ValueError("left > mode") + * if fmode > fright: + * raise ValueError("mode > right") # <<<<<<<<<<<<<< + * if fleft == fright: + * raise ValueError("left == right") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__124, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3681, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3681, __pyx_L1_error) + + /* "mtrand.pyx":3680 + * if fleft > fmode: + * raise ValueError("left > mode") + * if fmode > fright: # <<<<<<<<<<<<<< + * raise ValueError("mode > right") + * if fleft == fright: + */ + } + + /* "mtrand.pyx":3682 + * if fmode > fright: + * raise ValueError("mode > right") + * if fleft == fright: # <<<<<<<<<<<<<< + * raise ValueError("left == right") + * return cont3_array_sc(self.internal_state, rk_triangular, size, + */ + __pyx_t_5 = ((__pyx_v_fleft == __pyx_v_fright) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":3683 + * raise ValueError("mode > right") + * if fleft == fright: + * raise ValueError("left == right") # <<<<<<<<<<<<<< + * return cont3_array_sc(self.internal_state, rk_triangular, size, + * fleft, fmode, fright, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__125, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3683, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3683, __pyx_L1_error) + + /* "mtrand.pyx":3682 + * if fmode > fright: + * raise ValueError("mode > right") + * if fleft == fright: # <<<<<<<<<<<<<< + * raise ValueError("left == right") + * return cont3_array_sc(self.internal_state, rk_triangular, size, + */ + } + + /* "mtrand.pyx":3684 + * if fleft == fright: + * raise ValueError("left == right") + * return cont3_array_sc(self.internal_state, rk_triangular, size, # <<<<<<<<<<<<<< + * fleft, fmode, fright, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3685 + * raise ValueError("left == right") + * return cont3_array_sc(self.internal_state, rk_triangular, size, + * fleft, fmode, fright, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.greater(oleft, omode)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":3684 + * if fleft == fright: + * raise ValueError("left == right") + * return cont3_array_sc(self.internal_state, rk_triangular, size, # <<<<<<<<<<<<<< + * fleft, fmode, fright, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_cont3_array_sc(__pyx_v_self->internal_state, rk_triangular, __pyx_v_size, __pyx_v_fleft, __pyx_v_fmode, __pyx_v_fright, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3684, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3673 + * oright = PyArray_FROM_OTF(right, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oleft.shape == omode.shape == oright.shape == (): # <<<<<<<<<<<<<< + * fleft = PyFloat_AsDouble(left) + * fright = PyFloat_AsDouble(right) + */ + } + + /* "mtrand.pyx":3687 + * fleft, fmode, fright, self.lock) + * + * if np.any(np.greater(oleft, omode)): # <<<<<<<<<<<<<< + * raise ValueError("left > mode") + * if np.any(np.greater(omode, oright)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_greater); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_oleft), ((PyObject *)__pyx_v_omode)}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_oleft), ((PyObject *)__pyx_v_omode)}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oleft)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oleft)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_oleft)); + __Pyx_INCREF(((PyObject *)__pyx_v_omode)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_omode)); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, ((PyObject *)__pyx_v_omode)); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 3687, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":3688 + * + * if np.any(np.greater(oleft, omode)): + * raise ValueError("left > mode") # <<<<<<<<<<<<<< + * if np.any(np.greater(omode, oright)): + * raise ValueError("mode > right") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__126, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3688, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3688, __pyx_L1_error) + + /* "mtrand.pyx":3687 + * fleft, fmode, fright, self.lock) + * + * if np.any(np.greater(oleft, omode)): # <<<<<<<<<<<<<< + * raise ValueError("left > mode") + * if np.any(np.greater(omode, oright)): + */ + } + + /* "mtrand.pyx":3689 + * if np.any(np.greater(oleft, omode)): + * raise ValueError("left > mode") + * if np.any(np.greater(omode, oright)): # <<<<<<<<<<<<<< + * raise ValueError("mode > right") + * if np.any(np.equal(oleft, oright)): + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_greater); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_omode), ((PyObject *)__pyx_v_oright)}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_omode), ((PyObject *)__pyx_v_oright)}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_4 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_omode)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_omode)); + PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_8, ((PyObject *)__pyx_v_omode)); + __Pyx_INCREF(((PyObject *)__pyx_v_oright)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oright)); + PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_8, ((PyObject *)__pyx_v_oright)); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 3689, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":3690 + * raise ValueError("left > mode") + * if np.any(np.greater(omode, oright)): + * raise ValueError("mode > right") # <<<<<<<<<<<<<< + * if np.any(np.equal(oleft, oright)): + * raise ValueError("left == right") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__127, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3690, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3690, __pyx_L1_error) + + /* "mtrand.pyx":3689 + * if np.any(np.greater(oleft, omode)): + * raise ValueError("left > mode") + * if np.any(np.greater(omode, oright)): # <<<<<<<<<<<<<< + * raise ValueError("mode > right") + * if np.any(np.equal(oleft, oright)): + */ + } + + /* "mtrand.pyx":3691 + * if np.any(np.greater(omode, oright)): + * raise ValueError("mode > right") + * if np.any(np.equal(oleft, oright)): # <<<<<<<<<<<<<< + * raise ValueError("left == right") + * return cont3_array(self.internal_state, rk_triangular, size, oleft, + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_any); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, ((PyObject *)__pyx_v_oleft), ((PyObject *)__pyx_v_oright)}; + __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, ((PyObject *)__pyx_v_oleft), ((PyObject *)__pyx_v_oright)}; + __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + { + __pyx_t_3 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oleft)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oleft)); + PyTuple_SET_ITEM(__pyx_t_3, 0+__pyx_t_8, ((PyObject *)__pyx_v_oleft)); + __Pyx_INCREF(((PyObject *)__pyx_v_oright)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oright)); + PyTuple_SET_ITEM(__pyx_t_3, 1+__pyx_t_8, ((PyObject *)__pyx_v_oright)); + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_3, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_9}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_9}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_t_9); + __pyx_t_9 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 3691, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":3692 + * raise ValueError("mode > right") + * if np.any(np.equal(oleft, oright)): + * raise ValueError("left == right") # <<<<<<<<<<<<<< + * return cont3_array(self.internal_state, rk_triangular, size, oleft, + * omode, oright, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__128, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3692, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3692, __pyx_L1_error) + + /* "mtrand.pyx":3691 + * if np.any(np.greater(omode, oright)): + * raise ValueError("mode > right") + * if np.any(np.equal(oleft, oright)): # <<<<<<<<<<<<<< + * raise ValueError("left == right") + * return cont3_array(self.internal_state, rk_triangular, size, oleft, + */ + } + + /* "mtrand.pyx":3693 + * if np.any(np.equal(oleft, oright)): + * raise ValueError("left == right") + * return cont3_array(self.internal_state, rk_triangular, size, oleft, # <<<<<<<<<<<<<< + * omode, oright, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3694 + * raise ValueError("left == right") + * return cont3_array(self.internal_state, rk_triangular, size, oleft, + * omode, oright, self.lock) # <<<<<<<<<<<<<< + * + * # Complicated, discrete distributions: + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":3693 + * if np.any(np.equal(oleft, oright)): + * raise ValueError("left == right") + * return cont3_array(self.internal_state, rk_triangular, size, oleft, # <<<<<<<<<<<<<< + * omode, oright, self.lock) + * + */ + __pyx_t_4 = __pyx_f_6mtrand_cont3_array(__pyx_v_self->internal_state, rk_triangular, __pyx_v_size, __pyx_v_oleft, __pyx_v_omode, __pyx_v_oright, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 3693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3603 + * self.lock) + * + * def triangular(self, left, mode, right, size=None): # <<<<<<<<<<<<<< + * """ + * triangular(left, mode, right, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.triangular", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oleft); + __Pyx_XDECREF((PyObject *)__pyx_v_omode); + __Pyx_XDECREF((PyObject *)__pyx_v_oright); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3697 + * + * # Complicated, discrete distributions: + * def binomial(self, n, p, size=None): # <<<<<<<<<<<<<< + * """ + * binomial(n, p, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_83binomial(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_82binomial[] = "\n binomial(n, p, size=None)\n\n Draw samples from a binomial distribution.\n\n Samples are drawn from a binomial distribution with specified\n parameters, n trials and p probability of success where\n n an integer >= 0 and p is in the interval [0,1]. (n may be\n input as a float, but it is truncated to an integer in use)\n\n Parameters\n ----------\n n : int or array_like of ints\n Parameter of the distribution, >= 0. Floats are also accepted,\n but they will be truncated to integers.\n p : float or array_like of floats\n Parameter of the distribution, >= 0 and <=1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``n`` and ``p`` are both scalars.\n Otherwise, ``np.broadcast(n, p).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized binomial distribution, where\n each sample is equal to the number of successes over the n trials.\n\n See Also\n --------\n scipy.stats.binom : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the binomial distribution is\n\n .. math:: P(N) = \\binom{n}{N}p^N(1-p)^{n-N},\n\n where :math:`n` is the number of trials, :math:`p` is the probability\n of success, and :math:`N` is the number of successes.\n\n When estimating the standard error of a proportion in a population by\n using a random sample, the normal distribution works well unless the\n product p*n <=5, where p = population proportion estimate, and n =\n number of samples, in which case the binom""ial distribution is used\n instead. For example, a sample of 15 people shows 4 who are left\n handed, and 11 who are right handed. Then p = 4/15 = 27%. 0.27*15 = 4,\n so the binomial distribution should be used in this case.\n\n References\n ----------\n .. [1] Dalgaard, Peter, \"Introductory Statistics with R\",\n Springer-Verlag, 2002.\n .. [2] Glantz, Stanton A. \"Primer of Biostatistics.\", McGraw-Hill,\n Fifth Edition, 2002.\n .. [3] Lentner, Marvin, \"Elementary Applied Statistics\", Bogden\n and Quigley, 1972.\n .. [4] Weisstein, Eric W. \"Binomial Distribution.\" From MathWorld--A\n Wolfram Web Resource.\n http://mathworld.wolfram.com/BinomialDistribution.html\n .. [5] Wikipedia, \"Binomial distribution\",\n http://en.wikipedia.org/wiki/Binomial_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> n, p = 10, .5 # number of trials, probability of each trial\n >>> s = np.random.binomial(n, p, 1000)\n # result of flipping a coin 10 times, tested 1000 times.\n\n A real world example. A company drills 9 wild-cat oil exploration\n wells, each with an estimated probability of success of 0.1. All nine\n wells fail. What is the probability of that happening?\n\n Let's do 20,000 trials of the model, and count the number that\n generate zero positive results.\n\n >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000.\n # answer = 0.38885, or 38%.\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_83binomial(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_n = 0; + PyObject *__pyx_v_p = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("binomial (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_n,&__pyx_n_s_p,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_n)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_p)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("binomial", 0, 2, 3, 1); __PYX_ERR(0, 3697, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "binomial") < 0)) __PYX_ERR(0, 3697, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_n = values[0]; + __pyx_v_p = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("binomial", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3697, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.binomial", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_82binomial(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_n, __pyx_v_p, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_82binomial(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_n, PyObject *__pyx_v_p, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_on = 0; + PyArrayObject *__pyx_v_op = 0; + long __pyx_v_ln; + double __pyx_v_fp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + long __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_t_9; + PyObject *__pyx_t_10 = NULL; + __Pyx_RefNannySetupContext("binomial", 0); + + /* "mtrand.pyx":3786 + * cdef double fp + * + * on = PyArray_FROM_OTF(n, NPY_LONG, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_n, NPY_LONG, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3786, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_on = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":3787 + * + * on = PyArray_FROM_OTF(n, NPY_LONG, NPY_ARRAY_ALIGNED) + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if on.shape == op.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_p, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3787, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_op = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3789 + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if on.shape == op.shape == (): # <<<<<<<<<<<<<< + * fp = PyFloat_AsDouble(p) + * ln = PyInt_AsLong(n) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_on), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3789, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_op), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3789, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3789, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3789, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3789, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":3790 + * + * if on.shape == op.shape == (): + * fp = PyFloat_AsDouble(p) # <<<<<<<<<<<<<< + * ln = PyInt_AsLong(n) + * + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_p); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3790, __pyx_L1_error) + __pyx_v_fp = __pyx_t_5; + + /* "mtrand.pyx":3791 + * if on.shape == op.shape == (): + * fp = PyFloat_AsDouble(p) + * ln = PyInt_AsLong(n) # <<<<<<<<<<<<<< + * + * if ln < 0: + */ + __pyx_t_6 = PyInt_AsLong(__pyx_v_n); if (unlikely(__pyx_t_6 == ((long)-1L) && PyErr_Occurred())) __PYX_ERR(0, 3791, __pyx_L1_error) + __pyx_v_ln = __pyx_t_6; + + /* "mtrand.pyx":3793 + * ln = PyInt_AsLong(n) + * + * if ln < 0: # <<<<<<<<<<<<<< + * raise ValueError("n < 0") + * if fp < 0: + */ + __pyx_t_4 = ((__pyx_v_ln < 0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3794 + * + * if ln < 0: + * raise ValueError("n < 0") # <<<<<<<<<<<<<< + * if fp < 0: + * raise ValueError("p < 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__129, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3794, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3794, __pyx_L1_error) + + /* "mtrand.pyx":3793 + * ln = PyInt_AsLong(n) + * + * if ln < 0: # <<<<<<<<<<<<<< + * raise ValueError("n < 0") + * if fp < 0: + */ + } + + /* "mtrand.pyx":3795 + * if ln < 0: + * raise ValueError("n < 0") + * if fp < 0: # <<<<<<<<<<<<<< + * raise ValueError("p < 0") + * elif fp > 1: + */ + __pyx_t_4 = ((__pyx_v_fp < 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3796 + * raise ValueError("n < 0") + * if fp < 0: + * raise ValueError("p < 0") # <<<<<<<<<<<<<< + * elif fp > 1: + * raise ValueError("p > 1") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__130, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3796, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3796, __pyx_L1_error) + + /* "mtrand.pyx":3795 + * if ln < 0: + * raise ValueError("n < 0") + * if fp < 0: # <<<<<<<<<<<<<< + * raise ValueError("p < 0") + * elif fp > 1: + */ + } + + /* "mtrand.pyx":3797 + * if fp < 0: + * raise ValueError("p < 0") + * elif fp > 1: # <<<<<<<<<<<<<< + * raise ValueError("p > 1") + * elif np.isnan(fp): + */ + __pyx_t_4 = ((__pyx_v_fp > 1.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3798 + * raise ValueError("p < 0") + * elif fp > 1: + * raise ValueError("p > 1") # <<<<<<<<<<<<<< + * elif np.isnan(fp): + * raise ValueError("p is nan") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__131, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3798, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3798, __pyx_L1_error) + + /* "mtrand.pyx":3797 + * if fp < 0: + * raise ValueError("p < 0") + * elif fp > 1: # <<<<<<<<<<<<<< + * raise ValueError("p > 1") + * elif np.isnan(fp): + */ + } + + /* "mtrand.pyx":3799 + * elif fp > 1: + * raise ValueError("p > 1") + * elif np.isnan(fp): # <<<<<<<<<<<<<< + * raise ValueError("p is nan") + * return discnp_array_sc(self.internal_state, rk_binomial, size, ln, + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_isnan); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_fp); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_7) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3799, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3800 + * raise ValueError("p > 1") + * elif np.isnan(fp): + * raise ValueError("p is nan") # <<<<<<<<<<<<<< + * return discnp_array_sc(self.internal_state, rk_binomial, size, ln, + * fp, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__132, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3800, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3800, __pyx_L1_error) + + /* "mtrand.pyx":3799 + * elif fp > 1: + * raise ValueError("p > 1") + * elif np.isnan(fp): # <<<<<<<<<<<<<< + * raise ValueError("p is nan") + * return discnp_array_sc(self.internal_state, rk_binomial, size, ln, + */ + } + + /* "mtrand.pyx":3801 + * elif np.isnan(fp): + * raise ValueError("p is nan") + * return discnp_array_sc(self.internal_state, rk_binomial, size, ln, # <<<<<<<<<<<<<< + * fp, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3802 + * raise ValueError("p is nan") + * return discnp_array_sc(self.internal_state, rk_binomial, size, ln, + * fp, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less(n, 0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":3801 + * elif np.isnan(fp): + * raise ValueError("p is nan") + * return discnp_array_sc(self.internal_state, rk_binomial, size, ln, # <<<<<<<<<<<<<< + * fp, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_discnp_array_sc(__pyx_v_self->internal_state, rk_binomial, __pyx_v_size, __pyx_v_ln, __pyx_v_fp, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3801, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3789 + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if on.shape == op.shape == (): # <<<<<<<<<<<<<< + * fp = PyFloat_AsDouble(p) + * ln = PyInt_AsLong(n) + */ + } + + /* "mtrand.pyx":3804 + * fp, self.lock) + * + * if np.any(np.less(n, 0)): # <<<<<<<<<<<<<< + * raise ValueError("n < 0") + * if np.any(np.less(p, 0)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_9 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_9 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_v_n, __pyx_int_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_v_n, __pyx_int_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_10 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(__pyx_v_n); + __Pyx_GIVEREF(__pyx_v_n); + PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_9, __pyx_v_n); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_9, __pyx_int_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_10, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3804, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3805 + * + * if np.any(np.less(n, 0)): + * raise ValueError("n < 0") # <<<<<<<<<<<<<< + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__133, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3805, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3805, __pyx_L1_error) + + /* "mtrand.pyx":3804 + * fp, self.lock) + * + * if np.any(np.less(n, 0)): # <<<<<<<<<<<<<< + * raise ValueError("n < 0") + * if np.any(np.less(p, 0)): + */ + } + + /* "mtrand.pyx":3806 + * if np.any(np.less(n, 0)): + * raise ValueError("n < 0") + * if np.any(np.less(p, 0)): # <<<<<<<<<<<<<< + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): + */ + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_any); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_9 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_9 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, __pyx_v_p, __pyx_int_0}; + __pyx_t_8 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_8); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, __pyx_v_p, __pyx_int_0}; + __pyx_t_8 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_8); + } else + #endif + { + __pyx_t_2 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(__pyx_v_p); + __Pyx_GIVEREF(__pyx_v_p); + PyTuple_SET_ITEM(__pyx_t_2, 0+__pyx_t_9, __pyx_v_p); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_2, 1+__pyx_t_9, __pyx_int_0); + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_2, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_10); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_10, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_10, __pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_8}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_8}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else + #endif + { + __pyx_t_2 = PyTuple_New(1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_2, 0+1, __pyx_t_8); + __pyx_t_8 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + } + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3806, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3807 + * raise ValueError("n < 0") + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") # <<<<<<<<<<<<<< + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__134, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3807, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3807, __pyx_L1_error) + + /* "mtrand.pyx":3806 + * if np.any(np.less(n, 0)): + * raise ValueError("n < 0") + * if np.any(np.less(p, 0)): # <<<<<<<<<<<<<< + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): + */ + } + + /* "mtrand.pyx":3808 + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): # <<<<<<<<<<<<<< + * raise ValueError("p > 1") + * return discnp_array(self.internal_state, rk_binomial, size, on, op, + */ + __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_any); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_greater); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = NULL; + __pyx_t_9 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_9 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_p, __pyx_int_1}; + __pyx_t_10 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_10); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_v_p, __pyx_int_1}; + __pyx_t_10 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_10); + } else + #endif + { + __pyx_t_3 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__pyx_t_8) { + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_8); __pyx_t_8 = NULL; + } + __Pyx_INCREF(__pyx_v_p); + __Pyx_GIVEREF(__pyx_v_p); + PyTuple_SET_ITEM(__pyx_t_3, 0+__pyx_t_9, __pyx_v_p); + __Pyx_INCREF(__pyx_int_1); + __Pyx_GIVEREF(__pyx_int_1); + PyTuple_SET_ITEM(__pyx_t_3, 1+__pyx_t_9, __pyx_int_1); + __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_3, NULL); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_10}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_10}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + { + __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_t_10); + __pyx_t_10 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3808, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3809 + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") # <<<<<<<<<<<<<< + * return discnp_array(self.internal_state, rk_binomial, size, on, op, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__135, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3809, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3809, __pyx_L1_error) + + /* "mtrand.pyx":3808 + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): # <<<<<<<<<<<<<< + * raise ValueError("p > 1") + * return discnp_array(self.internal_state, rk_binomial, size, on, op, + */ + } + + /* "mtrand.pyx":3810 + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") + * return discnp_array(self.internal_state, rk_binomial, size, on, op, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3811 + * raise ValueError("p > 1") + * return discnp_array(self.internal_state, rk_binomial, size, on, op, + * self.lock) # <<<<<<<<<<<<<< + * + * def negative_binomial(self, n, p, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":3810 + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") + * return discnp_array(self.internal_state, rk_binomial, size, on, op, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_discnp_array(__pyx_v_self->internal_state, rk_binomial, __pyx_v_size, __pyx_v_on, __pyx_v_op, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3810, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3697 + * + * # Complicated, discrete distributions: + * def binomial(self, n, p, size=None): # <<<<<<<<<<<<<< + * """ + * binomial(n, p, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("mtrand.RandomState.binomial", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_on); + __Pyx_XDECREF((PyObject *)__pyx_v_op); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3813 + * self.lock) + * + * def negative_binomial(self, n, p, size=None): # <<<<<<<<<<<<<< + * """ + * negative_binomial(n, p, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_85negative_binomial(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_84negative_binomial[] = "\n negative_binomial(n, p, size=None)\n\n Draw samples from a negative binomial distribution.\n\n Samples are drawn from a negative binomial distribution with specified\n parameters, `n` trials and `p` probability of success where `n` is an\n integer > 0 and `p` is in the interval [0, 1].\n\n Parameters\n ----------\n n : int or array_like of ints\n Parameter of the distribution, > 0. Floats are also accepted,\n but they will be truncated to integers.\n p : float or array_like of floats\n Parameter of the distribution, >= 0 and <=1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``n`` and ``p`` are both scalars.\n Otherwise, ``np.broadcast(n, p).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized negative binomial distribution,\n where each sample is equal to N, the number of trials it took to\n achieve n - 1 successes, N - (n - 1) failures, and a success on the,\n (N + n)th trial.\n\n Notes\n -----\n The probability density for the negative binomial distribution is\n\n .. math:: P(N;n,p) = \\binom{N+n-1}{n-1}p^{n}(1-p)^{N},\n\n where :math:`n-1` is the number of successes, :math:`p` is the\n probability of success, and :math:`N+n-1` is the number of trials.\n The negative binomial distribution gives the probability of n-1\n successes and N failures in N+n-1 trials, and success on the (N+n)th\n trial.\n\n If one throws a die repeatedly until the third time a \"1\" appears,\n then the probability distribution of the number of non-\"1\"s that\n appear before the ""third \"1\" is a negative binomial distribution.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Negative Binomial Distribution.\" From\n MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/NegativeBinomialDistribution.html\n .. [2] Wikipedia, \"Negative binomial distribution\",\n http://en.wikipedia.org/wiki/Negative_binomial_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n A real world example. A company drills wild-cat oil\n exploration wells, each with an estimated probability of\n success of 0.1. What is the probability of having one success\n for each successive well, that is what is the probability of a\n single success after drilling 5 wells, after 6 wells, etc.?\n\n >>> s = np.random.negative_binomial(1, 0.1, 100000)\n >>> for i in range(1, 11):\n ... probability = sum(s 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "negative_binomial") < 0)) __PYX_ERR(0, 3813, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_n = values[0]; + __pyx_v_p = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("negative_binomial", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3813, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.negative_binomial", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_84negative_binomial(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_n, __pyx_v_p, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_84negative_binomial(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_n, PyObject *__pyx_v_p, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_on = 0; + PyArrayObject *__pyx_v_op = 0; + double __pyx_v_fn; + double __pyx_v_fp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + double __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("negative_binomial", 0); + + /* "mtrand.pyx":3889 + * cdef double fp + * + * on = PyArray_FROM_OTF(n, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_n, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3889, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_on = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":3890 + * + * on = PyArray_FROM_OTF(n, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if on.shape == op.shape == (): + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_p, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3890, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_op = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":3892 + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if on.shape == op.shape == (): # <<<<<<<<<<<<<< + * fp = PyFloat_AsDouble(p) + * fn = PyFloat_AsDouble(n) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_on), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3892, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_op), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3892, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3892, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3892, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3892, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_4) { + + /* "mtrand.pyx":3893 + * + * if on.shape == op.shape == (): + * fp = PyFloat_AsDouble(p) # <<<<<<<<<<<<<< + * fn = PyFloat_AsDouble(n) + * + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_p); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3893, __pyx_L1_error) + __pyx_v_fp = __pyx_t_5; + + /* "mtrand.pyx":3894 + * if on.shape == op.shape == (): + * fp = PyFloat_AsDouble(p) + * fn = PyFloat_AsDouble(n) # <<<<<<<<<<<<<< + * + * if fn <= 0: + */ + __pyx_t_5 = PyFloat_AsDouble(__pyx_v_n); if (unlikely(__pyx_t_5 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3894, __pyx_L1_error) + __pyx_v_fn = __pyx_t_5; + + /* "mtrand.pyx":3896 + * fn = PyFloat_AsDouble(n) + * + * if fn <= 0: # <<<<<<<<<<<<<< + * raise ValueError("n <= 0") + * if fp < 0: + */ + __pyx_t_4 = ((__pyx_v_fn <= 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3897 + * + * if fn <= 0: + * raise ValueError("n <= 0") # <<<<<<<<<<<<<< + * if fp < 0: + * raise ValueError("p < 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__136, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3897, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3897, __pyx_L1_error) + + /* "mtrand.pyx":3896 + * fn = PyFloat_AsDouble(n) + * + * if fn <= 0: # <<<<<<<<<<<<<< + * raise ValueError("n <= 0") + * if fp < 0: + */ + } + + /* "mtrand.pyx":3898 + * if fn <= 0: + * raise ValueError("n <= 0") + * if fp < 0: # <<<<<<<<<<<<<< + * raise ValueError("p < 0") + * elif fp > 1: + */ + __pyx_t_4 = ((__pyx_v_fp < 0.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3899 + * raise ValueError("n <= 0") + * if fp < 0: + * raise ValueError("p < 0") # <<<<<<<<<<<<<< + * elif fp > 1: + * raise ValueError("p > 1") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__137, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3899, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3899, __pyx_L1_error) + + /* "mtrand.pyx":3898 + * if fn <= 0: + * raise ValueError("n <= 0") + * if fp < 0: # <<<<<<<<<<<<<< + * raise ValueError("p < 0") + * elif fp > 1: + */ + } + + /* "mtrand.pyx":3900 + * if fp < 0: + * raise ValueError("p < 0") + * elif fp > 1: # <<<<<<<<<<<<<< + * raise ValueError("p > 1") + * return discdd_array_sc(self.internal_state, rk_negative_binomial, + */ + __pyx_t_4 = ((__pyx_v_fp > 1.0) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3901 + * raise ValueError("p < 0") + * elif fp > 1: + * raise ValueError("p > 1") # <<<<<<<<<<<<<< + * return discdd_array_sc(self.internal_state, rk_negative_binomial, + * size, fn, fp, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__138, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3901, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 3901, __pyx_L1_error) + + /* "mtrand.pyx":3900 + * if fp < 0: + * raise ValueError("p < 0") + * elif fp > 1: # <<<<<<<<<<<<<< + * raise ValueError("p > 1") + * return discdd_array_sc(self.internal_state, rk_negative_binomial, + */ + } + + /* "mtrand.pyx":3902 + * elif fp > 1: + * raise ValueError("p > 1") + * return discdd_array_sc(self.internal_state, rk_negative_binomial, # <<<<<<<<<<<<<< + * size, fn, fp, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3903 + * raise ValueError("p > 1") + * return discdd_array_sc(self.internal_state, rk_negative_binomial, + * size, fn, fp, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(n, 0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":3902 + * elif fp > 1: + * raise ValueError("p > 1") + * return discdd_array_sc(self.internal_state, rk_negative_binomial, # <<<<<<<<<<<<<< + * size, fn, fp, self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_discdd_array_sc(__pyx_v_self->internal_state, rk_negative_binomial, __pyx_v_size, __pyx_v_fn, __pyx_v_fp, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3902, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3892 + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if on.shape == op.shape == (): # <<<<<<<<<<<<<< + * fp = PyFloat_AsDouble(p) + * fn = PyFloat_AsDouble(n) + */ + } + + /* "mtrand.pyx":3905 + * size, fn, fp, self.lock) + * + * if np.any(np.less_equal(n, 0)): # <<<<<<<<<<<<<< + * raise ValueError("n <= 0") + * if np.any(np.less(p, 0)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_v_n, __pyx_int_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_v_n, __pyx_int_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(__pyx_v_n); + __Pyx_GIVEREF(__pyx_v_n); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_v_n); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_int_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3905, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3906 + * + * if np.any(np.less_equal(n, 0)): + * raise ValueError("n <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__139, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3906, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 3906, __pyx_L1_error) + + /* "mtrand.pyx":3905 + * size, fn, fp, self.lock) + * + * if np.any(np.less_equal(n, 0)): # <<<<<<<<<<<<<< + * raise ValueError("n <= 0") + * if np.any(np.less(p, 0)): + */ + } + + /* "mtrand.pyx":3907 + * if np.any(np.less_equal(n, 0)): + * raise ValueError("n <= 0") + * if np.any(np.less(p, 0)): # <<<<<<<<<<<<<< + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, __pyx_v_p, __pyx_int_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, __pyx_v_p, __pyx_int_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(__pyx_v_p); + __Pyx_GIVEREF(__pyx_v_p); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_8, __pyx_v_p); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_8, __pyx_int_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3907, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3908 + * raise ValueError("n <= 0") + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") # <<<<<<<<<<<<<< + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__140, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3908, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 3908, __pyx_L1_error) + + /* "mtrand.pyx":3907 + * if np.any(np.less_equal(n, 0)): + * raise ValueError("n <= 0") + * if np.any(np.less(p, 0)): # <<<<<<<<<<<<<< + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): + */ + } + + /* "mtrand.pyx":3909 + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): # <<<<<<<<<<<<<< + * raise ValueError("p > 1") + * return discdd_array(self.internal_state, rk_negative_binomial, size, + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_any); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_greater); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_1, __pyx_v_p, __pyx_int_1}; + __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_1, __pyx_v_p, __pyx_int_1}; + __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + { + __pyx_t_3 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__pyx_t_1) { + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1); __pyx_t_1 = NULL; + } + __Pyx_INCREF(__pyx_v_p); + __Pyx_GIVEREF(__pyx_v_p); + PyTuple_SET_ITEM(__pyx_t_3, 0+__pyx_t_8, __pyx_v_p); + __Pyx_INCREF(__pyx_int_1); + __Pyx_GIVEREF(__pyx_int_1); + PyTuple_SET_ITEM(__pyx_t_3, 1+__pyx_t_8, __pyx_int_1); + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_3, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_9); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_9}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_9}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_t_9); + __pyx_t_9 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 3909, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":3910 + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") # <<<<<<<<<<<<<< + * return discdd_array(self.internal_state, rk_negative_binomial, size, + * on, op, self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__141, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3910, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 3910, __pyx_L1_error) + + /* "mtrand.pyx":3909 + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): # <<<<<<<<<<<<<< + * raise ValueError("p > 1") + * return discdd_array(self.internal_state, rk_negative_binomial, size, + */ + } + + /* "mtrand.pyx":3911 + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") + * return discdd_array(self.internal_state, rk_negative_binomial, size, # <<<<<<<<<<<<<< + * on, op, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3912 + * raise ValueError("p > 1") + * return discdd_array(self.internal_state, rk_negative_binomial, size, + * on, op, self.lock) # <<<<<<<<<<<<<< + * + * def poisson(self, lam=1.0, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":3911 + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") + * return discdd_array(self.internal_state, rk_negative_binomial, size, # <<<<<<<<<<<<<< + * on, op, self.lock) + * + */ + __pyx_t_6 = __pyx_f_6mtrand_discdd_array(__pyx_v_self->internal_state, rk_negative_binomial, __pyx_v_size, __pyx_v_on, __pyx_v_op, __pyx_t_2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3911, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_6; + __pyx_t_6 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3813 + * self.lock) + * + * def negative_binomial(self, n, p, size=None): # <<<<<<<<<<<<<< + * """ + * negative_binomial(n, p, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.negative_binomial", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_on); + __Pyx_XDECREF((PyObject *)__pyx_v_op); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":3914 + * on, op, self.lock) + * + * def poisson(self, lam=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * poisson(lam=1.0, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_87poisson(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_86poisson[] = "\n poisson(lam=1.0, size=None)\n\n Draw samples from a Poisson distribution.\n\n The Poisson distribution is the limit of the binomial distribution\n for large N.\n\n Parameters\n ----------\n lam : float or array_like of floats\n Expectation of interval, should be >= 0. A sequence of expectation\n intervals must be broadcastable over the requested size.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``lam`` is a scalar. Otherwise,\n ``np.array(lam).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Poisson distribution.\n\n Notes\n -----\n The Poisson distribution\n\n .. math:: f(k; \\lambda)=\\frac{\\lambda^k e^{-\\lambda}}{k!}\n\n For events with an expected separation :math:`\\lambda` the Poisson\n distribution :math:`f(k; \\lambda)` describes the probability of\n :math:`k` events occurring within the observed\n interval :math:`\\lambda`.\n\n Because the output is limited to the range of the C long type, a\n ValueError is raised when `lam` is within 10 sigma of the maximum\n representable value.\n\n References\n ----------\n .. [1] Weisstein, Eric W. \"Poisson Distribution.\"\n From MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/PoissonDistribution.html\n .. [2] Wikipedia, \"Poisson distribution\",\n http://en.wikipedia.org/wiki/Poisson_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> import numpy as np\n >>> s = np.random.poisson(5, 10000)\n\n Display histo""gram of the sample:\n\n >>> import matplotlib.pyplot as plt\n >>> count, bins, ignored = plt.hist(s, 14, normed=True)\n >>> plt.show()\n\n Draw each 100 values for lambda 100 and 500:\n\n >>> s = np.random.poisson(lam=(100., 500.), size=(100, 2))\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_87poisson(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_lam = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("poisson (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_lam,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[0] = ((PyObject *)__pyx_float_1_0); + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_lam); + if (value) { values[0] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "poisson") < 0)) __PYX_ERR(0, 3914, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_lam = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("poisson", 0, 0, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 3914, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.poisson", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_86poisson(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_lam, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_86poisson(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_lam, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_olam = 0; + double __pyx_v_flam; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + __Pyx_RefNannySetupContext("poisson", 0); + + /* "mtrand.pyx":3983 + * cdef double flam + * + * olam = PyArray_FROM_OTF(lam, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if olam.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_lam, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3983, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_olam = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":3985 + * olam = PyArray_FROM_OTF(lam, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if olam.shape == (): # <<<<<<<<<<<<<< + * flam = PyFloat_AsDouble(lam) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_olam), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3985, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3985, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 3985, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":3986 + * + * if olam.shape == (): + * flam = PyFloat_AsDouble(lam) # <<<<<<<<<<<<<< + * + * if lam < 0: + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_lam); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 3986, __pyx_L1_error) + __pyx_v_flam = __pyx_t_4; + + /* "mtrand.pyx":3988 + * flam = PyFloat_AsDouble(lam) + * + * if lam < 0: # <<<<<<<<<<<<<< + * raise ValueError("lam < 0") + * if lam > self.poisson_lam_max: + */ + __pyx_t_1 = PyObject_RichCompare(__pyx_v_lam, __pyx_int_0, Py_LT); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3988, __pyx_L1_error) + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 3988, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":3989 + * + * if lam < 0: + * raise ValueError("lam < 0") # <<<<<<<<<<<<<< + * if lam > self.poisson_lam_max: + * raise ValueError("lam value too large") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__142, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3989, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3989, __pyx_L1_error) + + /* "mtrand.pyx":3988 + * flam = PyFloat_AsDouble(lam) + * + * if lam < 0: # <<<<<<<<<<<<<< + * raise ValueError("lam < 0") + * if lam > self.poisson_lam_max: + */ + } + + /* "mtrand.pyx":3990 + * if lam < 0: + * raise ValueError("lam < 0") + * if lam > self.poisson_lam_max: # <<<<<<<<<<<<<< + * raise ValueError("lam value too large") + * return discd_array_sc(self.internal_state, rk_poisson, size, flam, + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_poisson_lam_max); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3990, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = PyObject_RichCompare(__pyx_v_lam, __pyx_t_1, Py_GT); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3990, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 3990, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":3991 + * raise ValueError("lam < 0") + * if lam > self.poisson_lam_max: + * raise ValueError("lam value too large") # <<<<<<<<<<<<<< + * return discd_array_sc(self.internal_state, rk_poisson, size, flam, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__143, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3991, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 3991, __pyx_L1_error) + + /* "mtrand.pyx":3990 + * if lam < 0: + * raise ValueError("lam < 0") + * if lam > self.poisson_lam_max: # <<<<<<<<<<<<<< + * raise ValueError("lam value too large") + * return discd_array_sc(self.internal_state, rk_poisson, size, flam, + */ + } + + /* "mtrand.pyx":3992 + * if lam > self.poisson_lam_max: + * raise ValueError("lam value too large") + * return discd_array_sc(self.internal_state, rk_poisson, size, flam, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":3993 + * raise ValueError("lam value too large") + * return discd_array_sc(self.internal_state, rk_poisson, size, flam, + * self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less(olam, 0)): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":3992 + * if lam > self.poisson_lam_max: + * raise ValueError("lam value too large") + * return discd_array_sc(self.internal_state, rk_poisson, size, flam, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_discd_array_sc(__pyx_v_self->internal_state, rk_poisson, __pyx_v_size, __pyx_v_flam, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3992, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3985 + * olam = PyArray_FROM_OTF(lam, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if olam.shape == (): # <<<<<<<<<<<<<< + * flam = PyFloat_AsDouble(lam) + * + */ + } + + /* "mtrand.pyx":3995 + * self.lock) + * + * if np.any(np.less(olam, 0)): # <<<<<<<<<<<<<< + * raise ValueError("lam < 0") + * if np.any(np.greater(olam, self.poisson_lam_max)): + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_any); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_olam), __pyx_int_0}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_olam), __pyx_int_0}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_olam)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_olam)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_olam)); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_int_0); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 3995, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":3996 + * + * if np.any(np.less(olam, 0)): + * raise ValueError("lam < 0") # <<<<<<<<<<<<<< + * if np.any(np.greater(olam, self.poisson_lam_max)): + * raise ValueError("lam value too large.") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__144, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3996, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3996, __pyx_L1_error) + + /* "mtrand.pyx":3995 + * self.lock) + * + * if np.any(np.less(olam, 0)): # <<<<<<<<<<<<<< + * raise ValueError("lam < 0") + * if np.any(np.greater(olam, self.poisson_lam_max)): + */ + } + + /* "mtrand.pyx":3997 + * if np.any(np.less(olam, 0)): + * raise ValueError("lam < 0") + * if np.any(np.greater(olam, self.poisson_lam_max)): # <<<<<<<<<<<<<< + * raise ValueError("lam value too large.") + * return discd_array(self.internal_state, rk_poisson, size, olam, + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_greater); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_poisson_lam_max); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_olam), __pyx_t_2}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_olam), __pyx_t_2}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_olam)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_olam)); + PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_8, ((PyObject *)__pyx_v_olam)); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_8, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_10, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_5}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_5}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_10, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 3997, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":3998 + * raise ValueError("lam < 0") + * if np.any(np.greater(olam, self.poisson_lam_max)): + * raise ValueError("lam value too large.") # <<<<<<<<<<<<<< + * return discd_array(self.internal_state, rk_poisson, size, olam, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__145, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3998, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 3998, __pyx_L1_error) + + /* "mtrand.pyx":3997 + * if np.any(np.less(olam, 0)): + * raise ValueError("lam < 0") + * if np.any(np.greater(olam, self.poisson_lam_max)): # <<<<<<<<<<<<<< + * raise ValueError("lam value too large.") + * return discd_array(self.internal_state, rk_poisson, size, olam, + */ + } + + /* "mtrand.pyx":3999 + * if np.any(np.greater(olam, self.poisson_lam_max)): + * raise ValueError("lam value too large.") + * return discd_array(self.internal_state, rk_poisson, size, olam, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":4000 + * raise ValueError("lam value too large.") + * return discd_array(self.internal_state, rk_poisson, size, olam, + * self.lock) # <<<<<<<<<<<<<< + * + * def zipf(self, a, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":3999 + * if np.any(np.greater(olam, self.poisson_lam_max)): + * raise ValueError("lam value too large.") + * return discd_array(self.internal_state, rk_poisson, size, olam, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_9 = __pyx_f_6mtrand_discd_array(__pyx_v_self->internal_state, rk_poisson, __pyx_v_size, __pyx_v_olam, __pyx_t_1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 3999, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_9; + __pyx_t_9 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":3914 + * on, op, self.lock) + * + * def poisson(self, lam=1.0, size=None): # <<<<<<<<<<<<<< + * """ + * poisson(lam=1.0, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("mtrand.RandomState.poisson", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_olam); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4002 + * self.lock) + * + * def zipf(self, a, size=None): # <<<<<<<<<<<<<< + * """ + * zipf(a, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_89zipf(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_88zipf[] = "\n zipf(a, size=None)\n\n Draw samples from a Zipf distribution.\n\n Samples are drawn from a Zipf distribution with specified parameter\n `a` > 1.\n\n The Zipf distribution (also known as the zeta distribution) is a\n continuous probability distribution that satisfies Zipf's law: the\n frequency of an item is inversely proportional to its rank in a\n frequency table.\n\n Parameters\n ----------\n a : float or array_like of floats\n Distribution parameter. Should be greater than 1.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``a`` is a scalar. Otherwise,\n ``np.array(a).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized Zipf distribution.\n\n See Also\n --------\n scipy.stats.zipf : probability density function, distribution, or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Zipf distribution is\n\n .. math:: p(x) = \\frac{x^{-a}}{\\zeta(a)},\n\n where :math:`\\zeta` is the Riemann Zeta function.\n\n It is named for the American linguist George Kingsley Zipf, who noted\n that the frequency of any word in a sample of a language is inversely\n proportional to its rank in the frequency table.\n\n References\n ----------\n .. [1] Zipf, G. K., \"Selected Studies of the Principle of Relative\n Frequency in Language,\" Cambridge, MA: Harvard Univ. Press,\n 1932.\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a = 2. # parameter\n >>> s = np.random.zipf(a, ""1000)\n\n Display the histogram of the samples, along with\n the probability density function:\n\n >>> import matplotlib.pyplot as plt\n >>> from scipy import special\n\n Truncate s values at 50 so plot is interesting:\n\n >>> count, bins, ignored = plt.hist(s[s<50], 50, normed=True)\n >>> x = np.arange(1., 50.)\n >>> y = x**(-a) / special.zetac(a)\n >>> plt.plot(x, y/max(y), linewidth=2, color='r')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_89zipf(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_a = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("zipf (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_a,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_a)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "zipf") < 0)) __PYX_ERR(0, 4002, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_a = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("zipf", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 4002, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.zipf", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_88zipf(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_a, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_88zipf(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_a, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_oa = 0; + double __pyx_v_fa; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + __Pyx_RefNannySetupContext("zipf", 0); + + /* "mtrand.pyx":4079 + * cdef double fa + * + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if oa.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_a, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4079, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_oa = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":4081 + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_oa), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4081, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4081, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 4081, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":4082 + * + * if oa.shape == (): + * fa = PyFloat_AsDouble(a) # <<<<<<<<<<<<<< + * + * # use logic that ensures NaN is rejected. + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_a); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 4082, __pyx_L1_error) + __pyx_v_fa = __pyx_t_4; + + /* "mtrand.pyx":4085 + * + * # use logic that ensures NaN is rejected. + * if not fa > 1.0: # <<<<<<<<<<<<<< + * raise ValueError("'a' must be a valid float > 1.0") + * return discd_array_sc(self.internal_state, rk_zipf, size, fa, + */ + __pyx_t_3 = ((!((__pyx_v_fa > 1.0) != 0)) != 0); + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4086 + * # use logic that ensures NaN is rejected. + * if not fa > 1.0: + * raise ValueError("'a' must be a valid float > 1.0") # <<<<<<<<<<<<<< + * return discd_array_sc(self.internal_state, rk_zipf, size, fa, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__146, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4086, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4086, __pyx_L1_error) + + /* "mtrand.pyx":4085 + * + * # use logic that ensures NaN is rejected. + * if not fa > 1.0: # <<<<<<<<<<<<<< + * raise ValueError("'a' must be a valid float > 1.0") + * return discd_array_sc(self.internal_state, rk_zipf, size, fa, + */ + } + + /* "mtrand.pyx":4087 + * if not fa > 1.0: + * raise ValueError("'a' must be a valid float > 1.0") + * return discd_array_sc(self.internal_state, rk_zipf, size, fa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":4088 + * raise ValueError("'a' must be a valid float > 1.0") + * return discd_array_sc(self.internal_state, rk_zipf, size, fa, + * self.lock) # <<<<<<<<<<<<<< + * + * # use logic that ensures NaN is rejected. + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":4087 + * if not fa > 1.0: + * raise ValueError("'a' must be a valid float > 1.0") + * return discd_array_sc(self.internal_state, rk_zipf, size, fa, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_discd_array_sc(__pyx_v_self->internal_state, rk_zipf, __pyx_v_size, __pyx_v_fa, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4087, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":4081 + * oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if oa.shape == (): # <<<<<<<<<<<<<< + * fa = PyFloat_AsDouble(a) + * + */ + } + + /* "mtrand.pyx":4091 + * + * # use logic that ensures NaN is rejected. + * if not np.all(np.greater(oa, 1.0)): # <<<<<<<<<<<<<< + * raise ValueError("'a' must contain valid floats > 1.0") + * return discd_array(self.internal_state, rk_zipf, size, oa, self.lock) + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_all); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_greater); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_oa), __pyx_float_1_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_oa), __pyx_float_1_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_oa)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_oa)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_oa)); + __Pyx_INCREF(__pyx_float_1_0); + __Pyx_GIVEREF(__pyx_float_1_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_1_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 4091, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_10 = ((!__pyx_t_3) != 0); + if (unlikely(__pyx_t_10)) { + + /* "mtrand.pyx":4092 + * # use logic that ensures NaN is rejected. + * if not np.all(np.greater(oa, 1.0)): + * raise ValueError("'a' must contain valid floats > 1.0") # <<<<<<<<<<<<<< + * return discd_array(self.internal_state, rk_zipf, size, oa, self.lock) + * + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__147, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4092, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 4092, __pyx_L1_error) + + /* "mtrand.pyx":4091 + * + * # use logic that ensures NaN is rejected. + * if not np.all(np.greater(oa, 1.0)): # <<<<<<<<<<<<<< + * raise ValueError("'a' must contain valid floats > 1.0") + * return discd_array(self.internal_state, rk_zipf, size, oa, self.lock) + */ + } + + /* "mtrand.pyx":4093 + * if not np.all(np.greater(oa, 1.0)): + * raise ValueError("'a' must contain valid floats > 1.0") + * return discd_array(self.internal_state, rk_zipf, size, oa, self.lock) # <<<<<<<<<<<<<< + * + * def geometric(self, p, size=None): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + __pyx_t_5 = __pyx_f_6mtrand_discd_array(__pyx_v_self->internal_state, rk_zipf, __pyx_v_size, __pyx_v_oa, __pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4093, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":4002 + * self.lock) + * + * def zipf(self, a, size=None): # <<<<<<<<<<<<<< + * """ + * zipf(a, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.zipf", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_oa); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4095 + * return discd_array(self.internal_state, rk_zipf, size, oa, self.lock) + * + * def geometric(self, p, size=None): # <<<<<<<<<<<<<< + * """ + * geometric(p, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_91geometric(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_90geometric[] = "\n geometric(p, size=None)\n\n Draw samples from the geometric distribution.\n\n Bernoulli trials are experiments with one of two outcomes:\n success or failure (an example of such an experiment is flipping\n a coin). The geometric distribution models the number of trials\n that must be run in order to achieve success. It is therefore\n supported on the positive integers, ``k = 1, 2, ...``.\n\n The probability mass function of the geometric distribution is\n\n .. math:: f(k) = (1 - p)^{k - 1} p\n\n where `p` is the probability of success of an individual trial.\n\n Parameters\n ----------\n p : float or array_like of floats\n The probability of success of an individual trial.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``p`` is a scalar. Otherwise,\n ``np.array(p).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized geometric distribution.\n\n Examples\n --------\n Draw ten thousand values from the geometric distribution,\n with the probability of an individual success equal to 0.35:\n\n >>> z = np.random.geometric(p=0.35, size=10000)\n\n How many trials succeeded after a single run?\n\n >>> (z == 1).sum() / 10000.\n 0.34889999999999999 #random\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_91geometric(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_p = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("geometric (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_p,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_p)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "geometric") < 0)) __PYX_ERR(0, 4095, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_p = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("geometric", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 4095, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.geometric", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_90geometric(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_p, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_90geometric(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_p, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_op = 0; + double __pyx_v_fp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("geometric", 0); + + /* "mtrand.pyx":4144 + * cdef double fp + * + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if op.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_p, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_op = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":4146 + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if op.shape == (): # <<<<<<<<<<<<<< + * fp = PyFloat_AsDouble(p) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_op), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4146, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4146, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 4146, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":4147 + * + * if op.shape == (): + * fp = PyFloat_AsDouble(p) # <<<<<<<<<<<<<< + * + * if fp < 0.0: + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_p); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 4147, __pyx_L1_error) + __pyx_v_fp = __pyx_t_4; + + /* "mtrand.pyx":4149 + * fp = PyFloat_AsDouble(p) + * + * if fp < 0.0: # <<<<<<<<<<<<<< + * raise ValueError("p < 0.0") + * if fp > 1.0: + */ + __pyx_t_3 = ((__pyx_v_fp < 0.0) != 0); + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4150 + * + * if fp < 0.0: + * raise ValueError("p < 0.0") # <<<<<<<<<<<<<< + * if fp > 1.0: + * raise ValueError("p > 1.0") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__148, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4150, __pyx_L1_error) + + /* "mtrand.pyx":4149 + * fp = PyFloat_AsDouble(p) + * + * if fp < 0.0: # <<<<<<<<<<<<<< + * raise ValueError("p < 0.0") + * if fp > 1.0: + */ + } + + /* "mtrand.pyx":4151 + * if fp < 0.0: + * raise ValueError("p < 0.0") + * if fp > 1.0: # <<<<<<<<<<<<<< + * raise ValueError("p > 1.0") + * return discd_array_sc(self.internal_state, rk_geometric, size, fp, + */ + __pyx_t_3 = ((__pyx_v_fp > 1.0) != 0); + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4152 + * raise ValueError("p < 0.0") + * if fp > 1.0: + * raise ValueError("p > 1.0") # <<<<<<<<<<<<<< + * return discd_array_sc(self.internal_state, rk_geometric, size, fp, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__149, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4152, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4152, __pyx_L1_error) + + /* "mtrand.pyx":4151 + * if fp < 0.0: + * raise ValueError("p < 0.0") + * if fp > 1.0: # <<<<<<<<<<<<<< + * raise ValueError("p > 1.0") + * return discd_array_sc(self.internal_state, rk_geometric, size, fp, + */ + } + + /* "mtrand.pyx":4153 + * if fp > 1.0: + * raise ValueError("p > 1.0") + * return discd_array_sc(self.internal_state, rk_geometric, size, fp, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":4154 + * raise ValueError("p > 1.0") + * return discd_array_sc(self.internal_state, rk_geometric, size, fp, + * self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less(op, 0.0)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":4153 + * if fp > 1.0: + * raise ValueError("p > 1.0") + * return discd_array_sc(self.internal_state, rk_geometric, size, fp, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_discd_array_sc(__pyx_v_self->internal_state, rk_geometric, __pyx_v_size, __pyx_v_fp, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4153, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":4146 + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if op.shape == (): # <<<<<<<<<<<<<< + * fp = PyFloat_AsDouble(p) + * + */ + } + + /* "mtrand.pyx":4156 + * self.lock) + * + * if np.any(np.less(op, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("p < 0.0") + * if np.any(np.greater(op, 1.0)): + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_op), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_op), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_op)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_op)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_op)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 4156, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4157 + * + * if np.any(np.less(op, 0.0)): + * raise ValueError("p < 0.0") # <<<<<<<<<<<<<< + * if np.any(np.greater(op, 1.0)): + * raise ValueError("p > 1.0") + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__150, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4157, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 4157, __pyx_L1_error) + + /* "mtrand.pyx":4156 + * self.lock) + * + * if np.any(np.less(op, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("p < 0.0") + * if np.any(np.greater(op, 1.0)): + */ + } + + /* "mtrand.pyx":4158 + * if np.any(np.less(op, 0.0)): + * raise ValueError("p < 0.0") + * if np.any(np.greater(op, 1.0)): # <<<<<<<<<<<<<< + * raise ValueError("p > 1.0") + * return discd_array(self.internal_state, rk_geometric, size, op, + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_greater); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_1, ((PyObject *)__pyx_v_op), __pyx_float_1_0}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_1, ((PyObject *)__pyx_v_op), __pyx_float_1_0}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_1) { + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_1); __pyx_t_1 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_op)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_op)); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_8, ((PyObject *)__pyx_v_op)); + __Pyx_INCREF(__pyx_float_1_0); + __Pyx_GIVEREF(__pyx_float_1_0); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_8, __pyx_float_1_0); + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_5}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_5}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 4158, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4159 + * raise ValueError("p < 0.0") + * if np.any(np.greater(op, 1.0)): + * raise ValueError("p > 1.0") # <<<<<<<<<<<<<< + * return discd_array(self.internal_state, rk_geometric, size, op, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__151, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 4159, __pyx_L1_error) + + /* "mtrand.pyx":4158 + * if np.any(np.less(op, 0.0)): + * raise ValueError("p < 0.0") + * if np.any(np.greater(op, 1.0)): # <<<<<<<<<<<<<< + * raise ValueError("p > 1.0") + * return discd_array(self.internal_state, rk_geometric, size, op, + */ + } + + /* "mtrand.pyx":4160 + * if np.any(np.greater(op, 1.0)): + * raise ValueError("p > 1.0") + * return discd_array(self.internal_state, rk_geometric, size, op, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":4161 + * raise ValueError("p > 1.0") + * return discd_array(self.internal_state, rk_geometric, size, op, + * self.lock) # <<<<<<<<<<<<<< + * + * def hypergeometric(self, ngood, nbad, nsample, size=None): + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":4160 + * if np.any(np.greater(op, 1.0)): + * raise ValueError("p > 1.0") + * return discd_array(self.internal_state, rk_geometric, size, op, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_9 = __pyx_f_6mtrand_discd_array(__pyx_v_self->internal_state, rk_geometric, __pyx_v_size, __pyx_v_op, __pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4160, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_9; + __pyx_t_9 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":4095 + * return discd_array(self.internal_state, rk_zipf, size, oa, self.lock) + * + * def geometric(self, p, size=None): # <<<<<<<<<<<<<< + * """ + * geometric(p, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.geometric", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_op); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4163 + * self.lock) + * + * def hypergeometric(self, ngood, nbad, nsample, size=None): # <<<<<<<<<<<<<< + * """ + * hypergeometric(ngood, nbad, nsample, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_93hypergeometric(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_92hypergeometric[] = "\n hypergeometric(ngood, nbad, nsample, size=None)\n\n Draw samples from a Hypergeometric distribution.\n\n Samples are drawn from a hypergeometric distribution with specified\n parameters, ngood (ways to make a good selection), nbad (ways to make\n a bad selection), and nsample = number of items sampled, which is less\n than or equal to the sum ngood + nbad.\n\n Parameters\n ----------\n ngood : int or array_like of ints\n Number of ways to make a good selection. Must be nonnegative.\n nbad : int or array_like of ints\n Number of ways to make a bad selection. Must be nonnegative.\n nsample : int or array_like of ints\n Number of items sampled. Must be at least 1 and at most\n ``ngood + nbad``.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``ngood``, ``nbad``, and ``nsample``\n are all scalars. Otherwise, ``np.broadcast(ngood, nbad, nsample).size``\n samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized hypergeometric distribution.\n\n See Also\n --------\n scipy.stats.hypergeom : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Hypergeometric distribution is\n\n .. math:: P(x) = \\frac{\\binom{m}{n}\\binom{N-m}{n-x}}{\\binom{N}{n}},\n\n where :math:`0 \\le x \\le m` and :math:`n+m-N \\le x \\le n`\n\n for P(x) the probability of x successes, n = ngood, m = nbad, and\n N = number of samples.\n\n Consider an urn with black and white marbles in it, ngood of them\n black"" and nbad are white. If you draw nsample balls without\n replacement, then the hypergeometric distribution describes the\n distribution of black balls in the drawn sample.\n\n Note that this distribution is very similar to the binomial\n distribution, except that in this case, samples are drawn without\n replacement, whereas in the Binomial case samples are drawn with\n replacement (or the sample space is infinite). As the sample space\n becomes large, this distribution approaches the binomial.\n\n References\n ----------\n .. [1] Lentner, Marvin, \"Elementary Applied Statistics\", Bogden\n and Quigley, 1972.\n .. [2] Weisstein, Eric W. \"Hypergeometric Distribution.\" From\n MathWorld--A Wolfram Web Resource.\n http://mathworld.wolfram.com/HypergeometricDistribution.html\n .. [3] Wikipedia, \"Hypergeometric distribution\",\n http://en.wikipedia.org/wiki/Hypergeometric_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> ngood, nbad, nsamp = 100, 2, 10\n # number of good, number of bad, and number of samples\n >>> s = np.random.hypergeometric(ngood, nbad, nsamp, 1000)\n >>> hist(s)\n # note that it is very unlikely to grab both bad items\n\n Suppose you have an urn with 15 white and 15 black marbles.\n If you pull 15 marbles at random, how likely is it that\n 12 or more of them are one color?\n\n >>> s = np.random.hypergeometric(15, 15, 15, 100000)\n >>> sum(s>=12)/100000. + sum(s<=3)/100000.\n # answer = 0.003 ... pretty unlikely!\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_93hypergeometric(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_ngood = 0; + PyObject *__pyx_v_nbad = 0; + PyObject *__pyx_v_nsample = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("hypergeometric (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ngood,&__pyx_n_s_nbad,&__pyx_n_s_nsample,&__pyx_n_s_size,0}; + PyObject* values[4] = {0,0,0,0}; + values[3] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_ngood)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_nbad)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("hypergeometric", 0, 3, 4, 1); __PYX_ERR(0, 4163, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_nsample)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("hypergeometric", 0, 3, 4, 2); __PYX_ERR(0, 4163, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[3] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "hypergeometric") < 0)) __PYX_ERR(0, 4163, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_ngood = values[0]; + __pyx_v_nbad = values[1]; + __pyx_v_nsample = values[2]; + __pyx_v_size = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("hypergeometric", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 4163, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.hypergeometric", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_92hypergeometric(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_ngood, __pyx_v_nbad, __pyx_v_nsample, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_92hypergeometric(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_ngood, PyObject *__pyx_v_nbad, PyObject *__pyx_v_nsample, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_ongood = 0; + PyArrayObject *__pyx_v_onbad = 0; + PyArrayObject *__pyx_v_onsample = 0; + long __pyx_v_lngood; + long __pyx_v_lnbad; + long __pyx_v_lnsample; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + long __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + __Pyx_RefNannySetupContext("hypergeometric", 0); + + /* "mtrand.pyx":4254 + * cdef long lngood, lnbad, lnsample + * + * ongood = PyArray_FROM_OTF(ngood, NPY_LONG, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * onbad = PyArray_FROM_OTF(nbad, NPY_LONG, NPY_ARRAY_ALIGNED) + * onsample = PyArray_FROM_OTF(nsample, NPY_LONG, NPY_ARRAY_ALIGNED) + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_ngood, NPY_LONG, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4254, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_ongood = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":4255 + * + * ongood = PyArray_FROM_OTF(ngood, NPY_LONG, NPY_ARRAY_ALIGNED) + * onbad = PyArray_FROM_OTF(nbad, NPY_LONG, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * onsample = PyArray_FROM_OTF(nsample, NPY_LONG, NPY_ARRAY_ALIGNED) + * + */ + __pyx_t_2 = PyArray_FROM_OTF(__pyx_v_nbad, NPY_LONG, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4255, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_onbad = ((PyArrayObject *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "mtrand.pyx":4256 + * ongood = PyArray_FROM_OTF(ngood, NPY_LONG, NPY_ARRAY_ALIGNED) + * onbad = PyArray_FROM_OTF(nbad, NPY_LONG, NPY_ARRAY_ALIGNED) + * onsample = PyArray_FROM_OTF(nsample, NPY_LONG, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if ongood.shape == onbad.shape == onsample.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_nsample, NPY_LONG, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4256, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_onsample = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":4258 + * onsample = PyArray_FROM_OTF(nsample, NPY_LONG, NPY_ARRAY_ALIGNED) + * + * if ongood.shape == onbad.shape == onsample.shape == (): # <<<<<<<<<<<<<< + * lngood = PyInt_AsLong(ngood) + * lnbad = PyInt_AsLong(nbad) + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_ongood), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4258, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_onbad), __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4258, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_t_1, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4258, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_onsample), __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4258, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_1, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4258, __pyx_L1_error) + if (__Pyx_PyObject_IsTrue(__pyx_t_3)) { + __Pyx_DECREF(__pyx_t_3); + __pyx_t_3 = PyObject_RichCompare(__pyx_t_4, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4258, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 4258, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_5) { + + /* "mtrand.pyx":4259 + * + * if ongood.shape == onbad.shape == onsample.shape == (): + * lngood = PyInt_AsLong(ngood) # <<<<<<<<<<<<<< + * lnbad = PyInt_AsLong(nbad) + * lnsample = PyInt_AsLong(nsample) + */ + __pyx_t_6 = PyInt_AsLong(__pyx_v_ngood); if (unlikely(__pyx_t_6 == ((long)-1L) && PyErr_Occurred())) __PYX_ERR(0, 4259, __pyx_L1_error) + __pyx_v_lngood = __pyx_t_6; + + /* "mtrand.pyx":4260 + * if ongood.shape == onbad.shape == onsample.shape == (): + * lngood = PyInt_AsLong(ngood) + * lnbad = PyInt_AsLong(nbad) # <<<<<<<<<<<<<< + * lnsample = PyInt_AsLong(nsample) + * + */ + __pyx_t_6 = PyInt_AsLong(__pyx_v_nbad); if (unlikely(__pyx_t_6 == ((long)-1L) && PyErr_Occurred())) __PYX_ERR(0, 4260, __pyx_L1_error) + __pyx_v_lnbad = __pyx_t_6; + + /* "mtrand.pyx":4261 + * lngood = PyInt_AsLong(ngood) + * lnbad = PyInt_AsLong(nbad) + * lnsample = PyInt_AsLong(nsample) # <<<<<<<<<<<<<< + * + * if lngood < 0: + */ + __pyx_t_6 = PyInt_AsLong(__pyx_v_nsample); if (unlikely(__pyx_t_6 == ((long)-1L) && PyErr_Occurred())) __PYX_ERR(0, 4261, __pyx_L1_error) + __pyx_v_lnsample = __pyx_t_6; + + /* "mtrand.pyx":4263 + * lnsample = PyInt_AsLong(nsample) + * + * if lngood < 0: # <<<<<<<<<<<<<< + * raise ValueError("ngood < 0") + * if lnbad < 0: + */ + __pyx_t_5 = ((__pyx_v_lngood < 0) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":4264 + * + * if lngood < 0: + * raise ValueError("ngood < 0") # <<<<<<<<<<<<<< + * if lnbad < 0: + * raise ValueError("nbad < 0") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__152, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 4264, __pyx_L1_error) + + /* "mtrand.pyx":4263 + * lnsample = PyInt_AsLong(nsample) + * + * if lngood < 0: # <<<<<<<<<<<<<< + * raise ValueError("ngood < 0") + * if lnbad < 0: + */ + } + + /* "mtrand.pyx":4265 + * if lngood < 0: + * raise ValueError("ngood < 0") + * if lnbad < 0: # <<<<<<<<<<<<<< + * raise ValueError("nbad < 0") + * if lnsample < 1: + */ + __pyx_t_5 = ((__pyx_v_lnbad < 0) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":4266 + * raise ValueError("ngood < 0") + * if lnbad < 0: + * raise ValueError("nbad < 0") # <<<<<<<<<<<<<< + * if lnsample < 1: + * raise ValueError("nsample < 1") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__153, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4266, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 4266, __pyx_L1_error) + + /* "mtrand.pyx":4265 + * if lngood < 0: + * raise ValueError("ngood < 0") + * if lnbad < 0: # <<<<<<<<<<<<<< + * raise ValueError("nbad < 0") + * if lnsample < 1: + */ + } + + /* "mtrand.pyx":4267 + * if lnbad < 0: + * raise ValueError("nbad < 0") + * if lnsample < 1: # <<<<<<<<<<<<<< + * raise ValueError("nsample < 1") + * if lngood + lnbad < lnsample: + */ + __pyx_t_5 = ((__pyx_v_lnsample < 1) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":4268 + * raise ValueError("nbad < 0") + * if lnsample < 1: + * raise ValueError("nsample < 1") # <<<<<<<<<<<<<< + * if lngood + lnbad < lnsample: + * raise ValueError("ngood + nbad < nsample") + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__154, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4268, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 4268, __pyx_L1_error) + + /* "mtrand.pyx":4267 + * if lnbad < 0: + * raise ValueError("nbad < 0") + * if lnsample < 1: # <<<<<<<<<<<<<< + * raise ValueError("nsample < 1") + * if lngood + lnbad < lnsample: + */ + } + + /* "mtrand.pyx":4269 + * if lnsample < 1: + * raise ValueError("nsample < 1") + * if lngood + lnbad < lnsample: # <<<<<<<<<<<<<< + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array_sc(self.internal_state, rk_hypergeometric, + */ + __pyx_t_5 = (((__pyx_v_lngood + __pyx_v_lnbad) < __pyx_v_lnsample) != 0); + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":4270 + * raise ValueError("nsample < 1") + * if lngood + lnbad < lnsample: + * raise ValueError("ngood + nbad < nsample") # <<<<<<<<<<<<<< + * return discnmN_array_sc(self.internal_state, rk_hypergeometric, + * size, lngood, lnbad, lnsample, self.lock) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__155, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 4270, __pyx_L1_error) + + /* "mtrand.pyx":4269 + * if lnsample < 1: + * raise ValueError("nsample < 1") + * if lngood + lnbad < lnsample: # <<<<<<<<<<<<<< + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array_sc(self.internal_state, rk_hypergeometric, + */ + } + + /* "mtrand.pyx":4271 + * if lngood + lnbad < lnsample: + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array_sc(self.internal_state, rk_hypergeometric, # <<<<<<<<<<<<<< + * size, lngood, lnbad, lnsample, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":4272 + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array_sc(self.internal_state, rk_hypergeometric, + * size, lngood, lnbad, lnsample, self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less(ongood, 0)): + */ + __pyx_t_3 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_3); + + /* "mtrand.pyx":4271 + * if lngood + lnbad < lnsample: + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array_sc(self.internal_state, rk_hypergeometric, # <<<<<<<<<<<<<< + * size, lngood, lnbad, lnsample, self.lock) + * + */ + __pyx_t_1 = __pyx_f_6mtrand_discnmN_array_sc(__pyx_v_self->internal_state, rk_hypergeometric, __pyx_v_size, __pyx_v_lngood, __pyx_v_lnbad, __pyx_v_lnsample, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4271, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":4258 + * onsample = PyArray_FROM_OTF(nsample, NPY_LONG, NPY_ARRAY_ALIGNED) + * + * if ongood.shape == onbad.shape == onsample.shape == (): # <<<<<<<<<<<<<< + * lngood = PyInt_AsLong(ngood) + * lnbad = PyInt_AsLong(nbad) + */ + } + + /* "mtrand.pyx":4274 + * size, lngood, lnbad, lnsample, self.lock) + * + * if np.any(np.less(ongood, 0)): # <<<<<<<<<<<<<< + * raise ValueError("ngood < 0") + * if np.any(np.less(onbad, 0)): + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_any); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_ongood), __pyx_int_0}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, ((PyObject *)__pyx_v_ongood), __pyx_int_0}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_ongood)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ongood)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_ongood)); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_int_0); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_3}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_3); + __pyx_t_3 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 4274, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":4275 + * + * if np.any(np.less(ongood, 0)): + * raise ValueError("ngood < 0") # <<<<<<<<<<<<<< + * if np.any(np.less(onbad, 0)): + * raise ValueError("nbad < 0") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__156, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4275, __pyx_L1_error) + + /* "mtrand.pyx":4274 + * size, lngood, lnbad, lnsample, self.lock) + * + * if np.any(np.less(ongood, 0)): # <<<<<<<<<<<<<< + * raise ValueError("ngood < 0") + * if np.any(np.less(onbad, 0)): + */ + } + + /* "mtrand.pyx":4276 + * if np.any(np.less(ongood, 0)): + * raise ValueError("ngood < 0") + * if np.any(np.less(onbad, 0)): # <<<<<<<<<<<<<< + * raise ValueError("nbad < 0") + * if np.any(np.less(onsample, 1)): + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_onbad), __pyx_int_0}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_3, ((PyObject *)__pyx_v_onbad), __pyx_int_0}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_4 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_onbad)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_onbad)); + PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_8, ((PyObject *)__pyx_v_onbad)); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_8, __pyx_int_0); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_2}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 4276, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":4277 + * raise ValueError("ngood < 0") + * if np.any(np.less(onbad, 0)): + * raise ValueError("nbad < 0") # <<<<<<<<<<<<<< + * if np.any(np.less(onsample, 1)): + * raise ValueError("nsample < 1") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__157, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4277, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4277, __pyx_L1_error) + + /* "mtrand.pyx":4276 + * if np.any(np.less(ongood, 0)): + * raise ValueError("ngood < 0") + * if np.any(np.less(onbad, 0)): # <<<<<<<<<<<<<< + * raise ValueError("nbad < 0") + * if np.any(np.less(onsample, 1)): + */ + } + + /* "mtrand.pyx":4278 + * if np.any(np.less(onbad, 0)): + * raise ValueError("nbad < 0") + * if np.any(np.less(onsample, 1)): # <<<<<<<<<<<<<< + * raise ValueError("nsample < 1") + * if np.any(np.less(np.add(ongood, onbad),onsample)): + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_any); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, ((PyObject *)__pyx_v_onsample), __pyx_int_1}; + __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, ((PyObject *)__pyx_v_onsample), __pyx_int_1}; + __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + { + __pyx_t_3 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_onsample)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_onsample)); + PyTuple_SET_ITEM(__pyx_t_3, 0+__pyx_t_8, ((PyObject *)__pyx_v_onsample)); + __Pyx_INCREF(__pyx_int_1); + __Pyx_GIVEREF(__pyx_int_1); + PyTuple_SET_ITEM(__pyx_t_3, 1+__pyx_t_8, __pyx_int_1); + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_3, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_9}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_9}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_t_9); + __pyx_t_9 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 4278, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":4279 + * raise ValueError("nbad < 0") + * if np.any(np.less(onsample, 1)): + * raise ValueError("nsample < 1") # <<<<<<<<<<<<<< + * if np.any(np.less(np.add(ongood, onbad),onsample)): + * raise ValueError("ngood + nbad < nsample") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__158, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4279, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4279, __pyx_L1_error) + + /* "mtrand.pyx":4278 + * if np.any(np.less(onbad, 0)): + * raise ValueError("nbad < 0") + * if np.any(np.less(onsample, 1)): # <<<<<<<<<<<<<< + * raise ValueError("nsample < 1") + * if np.any(np.less(np.add(ongood, onbad),onsample)): + */ + } + + /* "mtrand.pyx":4280 + * if np.any(np.less(onsample, 1)): + * raise ValueError("nsample < 1") + * if np.any(np.less(np.add(ongood, onbad),onsample)): # <<<<<<<<<<<<<< + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array(self.internal_state, rk_hypergeometric, size, + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_any); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_less); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_add); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_10); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_10, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, ((PyObject *)__pyx_v_ongood), ((PyObject *)__pyx_v_onbad)}; + __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, ((PyObject *)__pyx_v_ongood), ((PyObject *)__pyx_v_onbad)}; + __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else + #endif + { + __pyx_t_11 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_ongood)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_ongood)); + PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_8, ((PyObject *)__pyx_v_ongood)); + __Pyx_INCREF(((PyObject *)__pyx_v_onbad)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_onbad)); + PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_8, ((PyObject *)__pyx_v_onbad)); + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_11, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_10 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_10)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_10); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_10, __pyx_t_9, ((PyObject *)__pyx_v_onsample)}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_10, __pyx_t_9, ((PyObject *)__pyx_v_onsample)}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_11 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + if (__pyx_t_10) { + __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_10); __pyx_t_10 = NULL; + } + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_8, __pyx_t_9); + __Pyx_INCREF(((PyObject *)__pyx_v_onsample)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_onsample)); + PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_8, ((PyObject *)__pyx_v_onsample)); + __pyx_t_9 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_11, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + if (!__pyx_t_7) { + __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_4}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_4}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + { + __pyx_t_11 = PyTuple_New(1+1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_11, 0+1, __pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_11, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 4280, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__pyx_t_5)) { + + /* "mtrand.pyx":4281 + * raise ValueError("nsample < 1") + * if np.any(np.less(np.add(ongood, onbad),onsample)): + * raise ValueError("ngood + nbad < nsample") # <<<<<<<<<<<<<< + * return discnmN_array(self.internal_state, rk_hypergeometric, size, + * ongood, onbad, onsample, self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__159, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4281, __pyx_L1_error) + + /* "mtrand.pyx":4280 + * if np.any(np.less(onsample, 1)): + * raise ValueError("nsample < 1") + * if np.any(np.less(np.add(ongood, onbad),onsample)): # <<<<<<<<<<<<<< + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array(self.internal_state, rk_hypergeometric, size, + */ + } + + /* "mtrand.pyx":4282 + * if np.any(np.less(np.add(ongood, onbad),onsample)): + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array(self.internal_state, rk_hypergeometric, size, # <<<<<<<<<<<<<< + * ongood, onbad, onsample, self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":4283 + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array(self.internal_state, rk_hypergeometric, size, + * ongood, onbad, onsample, self.lock) # <<<<<<<<<<<<<< + * + * def logseries(self, p, size=None): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":4282 + * if np.any(np.less(np.add(ongood, onbad),onsample)): + * raise ValueError("ngood + nbad < nsample") + * return discnmN_array(self.internal_state, rk_hypergeometric, size, # <<<<<<<<<<<<<< + * ongood, onbad, onsample, self.lock) + * + */ + __pyx_t_3 = __pyx_f_6mtrand_discnmN_array(__pyx_v_self->internal_state, rk_hypergeometric, __pyx_v_size, __pyx_v_ongood, __pyx_v_onbad, __pyx_v_onsample, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4282, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":4163 + * self.lock) + * + * def hypergeometric(self, ngood, nbad, nsample, size=None): # <<<<<<<<<<<<<< + * """ + * hypergeometric(ngood, nbad, nsample, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("mtrand.RandomState.hypergeometric", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_ongood); + __Pyx_XDECREF((PyObject *)__pyx_v_onbad); + __Pyx_XDECREF((PyObject *)__pyx_v_onsample); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4285 + * ongood, onbad, onsample, self.lock) + * + * def logseries(self, p, size=None): # <<<<<<<<<<<<<< + * """ + * logseries(p, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_95logseries(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_94logseries[] = "\n logseries(p, size=None)\n\n Draw samples from a logarithmic series distribution.\n\n Samples are drawn from a log series distribution with specified\n shape parameter, 0 < ``p`` < 1.\n\n Parameters\n ----------\n p : float or array_like of floats\n Shape parameter for the distribution. Must be in the range (0, 1).\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. If size is ``None`` (default),\n a single value is returned if ``p`` is a scalar. Otherwise,\n ``np.array(p).size`` samples are drawn.\n\n Returns\n -------\n out : ndarray or scalar\n Drawn samples from the parameterized logarithmic series distribution.\n\n See Also\n --------\n scipy.stats.logser : probability density function, distribution or\n cumulative density function, etc.\n\n Notes\n -----\n The probability density for the Log Series distribution is\n\n .. math:: P(k) = \\frac{-p^k}{k \\ln(1-p)},\n\n where p = probability.\n\n The log series distribution is frequently used to represent species\n richness and occurrence, first proposed by Fisher, Corbet, and\n Williams in 1943 [2]. It may also be used to model the numbers of\n occupants seen in cars [3].\n\n References\n ----------\n .. [1] Buzas, Martin A.; Culver, Stephen J., Understanding regional\n species diversity through the log series distribution of\n occurrences: BIODIVERSITY RESEARCH Diversity & Distributions,\n Volume 5, Number 5, September 1999 , pp. 187-195(9).\n .. [2] Fisher, R.A,, A.S. Corbet, and C.B. Williams. 1943. The\n relation between the number of species and the number of\n individuals in a random ""sample of an animal population.\n Journal of Animal Ecology, 12:42-58.\n .. [3] D. J. Hand, F. Daly, D. Lunn, E. Ostrowski, A Handbook of Small\n Data Sets, CRC Press, 1994.\n .. [4] Wikipedia, \"Logarithmic distribution\",\n http://en.wikipedia.org/wiki/Logarithmic_distribution\n\n Examples\n --------\n Draw samples from the distribution:\n\n >>> a = .6\n >>> s = np.random.logseries(a, 10000)\n >>> count, bins, ignored = plt.hist(s)\n\n # plot against distribution\n\n >>> def logseries(k, p):\n ... return -p**k/(k*log(1-p))\n >>> plt.plot(bins, logseries(bins, a)*count.max()/\n logseries(bins, a).max(), 'r')\n >>> plt.show()\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_95logseries(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_p = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("logseries (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_p,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_p)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "logseries") < 0)) __PYX_ERR(0, 4285, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_p = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("logseries", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 4285, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.logseries", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_94logseries(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_p, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_94logseries(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_p, PyObject *__pyx_v_size) { + PyArrayObject *__pyx_v_op = 0; + double __pyx_v_fp; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + double __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + __Pyx_RefNannySetupContext("logseries", 0); + + /* "mtrand.pyx":4362 + * cdef double fp + * + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) # <<<<<<<<<<<<<< + * + * if op.shape == (): + */ + __pyx_t_1 = PyArray_FROM_OTF(__pyx_v_p, NPY_DOUBLE, NPY_ARRAY_ALIGNED); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4362, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __pyx_t_1; + __Pyx_INCREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_op = ((PyArrayObject *)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":4364 + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if op.shape == (): # <<<<<<<<<<<<<< + * fp = PyFloat_AsDouble(p) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_op), __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4364, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_1 = PyObject_RichCompare(__pyx_t_2, __pyx_empty_tuple, Py_EQ); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4364, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 4364, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (__pyx_t_3) { + + /* "mtrand.pyx":4365 + * + * if op.shape == (): + * fp = PyFloat_AsDouble(p) # <<<<<<<<<<<<<< + * + * if fp <= 0.0: + */ + __pyx_t_4 = PyFloat_AsDouble(__pyx_v_p); if (unlikely(__pyx_t_4 == ((double)(-1.0)) && PyErr_Occurred())) __PYX_ERR(0, 4365, __pyx_L1_error) + __pyx_v_fp = __pyx_t_4; + + /* "mtrand.pyx":4367 + * fp = PyFloat_AsDouble(p) + * + * if fp <= 0.0: # <<<<<<<<<<<<<< + * raise ValueError("p <= 0.0") + * if fp >= 1.0: + */ + __pyx_t_3 = ((__pyx_v_fp <= 0.0) != 0); + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4368 + * + * if fp <= 0.0: + * raise ValueError("p <= 0.0") # <<<<<<<<<<<<<< + * if fp >= 1.0: + * raise ValueError("p >= 1.0") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__160, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4368, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4368, __pyx_L1_error) + + /* "mtrand.pyx":4367 + * fp = PyFloat_AsDouble(p) + * + * if fp <= 0.0: # <<<<<<<<<<<<<< + * raise ValueError("p <= 0.0") + * if fp >= 1.0: + */ + } + + /* "mtrand.pyx":4369 + * if fp <= 0.0: + * raise ValueError("p <= 0.0") + * if fp >= 1.0: # <<<<<<<<<<<<<< + * raise ValueError("p >= 1.0") + * return discd_array_sc(self.internal_state, rk_logseries, size, fp, + */ + __pyx_t_3 = ((__pyx_v_fp >= 1.0) != 0); + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4370 + * raise ValueError("p <= 0.0") + * if fp >= 1.0: + * raise ValueError("p >= 1.0") # <<<<<<<<<<<<<< + * return discd_array_sc(self.internal_state, rk_logseries, size, fp, + * self.lock) + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__161, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4370, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(0, 4370, __pyx_L1_error) + + /* "mtrand.pyx":4369 + * if fp <= 0.0: + * raise ValueError("p <= 0.0") + * if fp >= 1.0: # <<<<<<<<<<<<<< + * raise ValueError("p >= 1.0") + * return discd_array_sc(self.internal_state, rk_logseries, size, fp, + */ + } + + /* "mtrand.pyx":4371 + * if fp >= 1.0: + * raise ValueError("p >= 1.0") + * return discd_array_sc(self.internal_state, rk_logseries, size, fp, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":4372 + * raise ValueError("p >= 1.0") + * return discd_array_sc(self.internal_state, rk_logseries, size, fp, + * self.lock) # <<<<<<<<<<<<<< + * + * if np.any(np.less_equal(op, 0.0)): + */ + __pyx_t_1 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_1); + + /* "mtrand.pyx":4371 + * if fp >= 1.0: + * raise ValueError("p >= 1.0") + * return discd_array_sc(self.internal_state, rk_logseries, size, fp, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_2 = __pyx_f_6mtrand_discd_array_sc(__pyx_v_self->internal_state, rk_logseries, __pyx_v_size, __pyx_v_fp, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4371, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":4364 + * op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + * + * if op.shape == (): # <<<<<<<<<<<<<< + * fp = PyFloat_AsDouble(p) + * + */ + } + + /* "mtrand.pyx":4374 + * self.lock) + * + * if np.any(np.less_equal(op, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("p <= 0.0") + * if np.any(np.greater_equal(op, 1.0)): + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_any); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_op), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_v_op), __pyx_float_0_0}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_op)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_op)); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, ((PyObject *)__pyx_v_op)); + __Pyx_INCREF(__pyx_float_0_0); + __Pyx_GIVEREF(__pyx_float_0_0); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_float_0_0); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_1}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_1); + __pyx_t_1 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 4374, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4375 + * + * if np.any(np.less_equal(op, 0.0)): + * raise ValueError("p <= 0.0") # <<<<<<<<<<<<<< + * if np.any(np.greater_equal(op, 1.0)): + * raise ValueError("p >= 1.0") + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__162, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4375, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 4375, __pyx_L1_error) + + /* "mtrand.pyx":4374 + * self.lock) + * + * if np.any(np.less_equal(op, 0.0)): # <<<<<<<<<<<<<< + * raise ValueError("p <= 0.0") + * if np.any(np.greater_equal(op, 1.0)): + */ + } + + /* "mtrand.pyx":4376 + * if np.any(np.less_equal(op, 0.0)): + * raise ValueError("p <= 0.0") + * if np.any(np.greater_equal(op, 1.0)): # <<<<<<<<<<<<<< + * raise ValueError("p >= 1.0") + * return discd_array(self.internal_state, rk_logseries, size, op, + */ + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_any); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_greater_equal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_1, ((PyObject *)__pyx_v_op), __pyx_float_1_0}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[3] = {__pyx_t_1, ((PyObject *)__pyx_v_op), __pyx_float_1_0}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_5); + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_1) { + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_1); __pyx_t_1 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_op)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_op)); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_8, ((PyObject *)__pyx_v_op)); + __Pyx_INCREF(__pyx_float_1_0); + __Pyx_GIVEREF(__pyx_float_1_0); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_8, __pyx_float_1_0); + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_7) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_5}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_5}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); __pyx_t_7 = NULL; + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 4376, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(__pyx_t_3)) { + + /* "mtrand.pyx":4377 + * raise ValueError("p <= 0.0") + * if np.any(np.greater_equal(op, 1.0)): + * raise ValueError("p >= 1.0") # <<<<<<<<<<<<<< + * return discd_array(self.internal_state, rk_logseries, size, op, + * self.lock) + */ + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__163, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4377, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_Raise(__pyx_t_2, 0, 0, 0); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __PYX_ERR(0, 4377, __pyx_L1_error) + + /* "mtrand.pyx":4376 + * if np.any(np.less_equal(op, 0.0)): + * raise ValueError("p <= 0.0") + * if np.any(np.greater_equal(op, 1.0)): # <<<<<<<<<<<<<< + * raise ValueError("p >= 1.0") + * return discd_array(self.internal_state, rk_logseries, size, op, + */ + } + + /* "mtrand.pyx":4378 + * if np.any(np.greater_equal(op, 1.0)): + * raise ValueError("p >= 1.0") + * return discd_array(self.internal_state, rk_logseries, size, op, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __Pyx_XDECREF(__pyx_r); + + /* "mtrand.pyx":4379 + * raise ValueError("p >= 1.0") + * return discd_array(self.internal_state, rk_logseries, size, op, + * self.lock) # <<<<<<<<<<<<<< + * + * # Multivariate distributions: + */ + __pyx_t_2 = __pyx_v_self->lock; + __Pyx_INCREF(__pyx_t_2); + + /* "mtrand.pyx":4378 + * if np.any(np.greater_equal(op, 1.0)): + * raise ValueError("p >= 1.0") + * return discd_array(self.internal_state, rk_logseries, size, op, # <<<<<<<<<<<<<< + * self.lock) + * + */ + __pyx_t_9 = __pyx_f_6mtrand_discd_array(__pyx_v_self->internal_state, rk_logseries, __pyx_v_size, __pyx_v_op, __pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4378, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_9; + __pyx_t_9 = 0; + goto __pyx_L0; + + /* "mtrand.pyx":4285 + * ongood, onbad, onsample, self.lock) + * + * def logseries(self, p, size=None): # <<<<<<<<<<<<<< + * """ + * logseries(p, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("mtrand.RandomState.logseries", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_op); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4382 + * + * # Multivariate distributions: + * def multivariate_normal(self, mean, cov, size=None, check_valid='warn', # <<<<<<<<<<<<<< + * tol=1e-8): + * """ + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_97multivariate_normal(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_96multivariate_normal[] = "\n multivariate_normal(mean, cov[, size, check_valid, tol])\n\n Draw random samples from a multivariate normal distribution.\n\n The multivariate normal, multinormal or Gaussian distribution is a\n generalization of the one-dimensional normal distribution to higher\n dimensions. Such a distribution is specified by its mean and\n covariance matrix. These parameters are analogous to the mean\n (average or \"center\") and variance (standard deviation, or \"width,\"\n squared) of the one-dimensional normal distribution.\n\n Parameters\n ----------\n mean : 1-D array_like, of length N\n Mean of the N-dimensional distribution.\n cov : 2-D array_like, of shape (N, N)\n Covariance matrix of the distribution. It must be symmetric and\n positive-semidefinite for proper sampling.\n size : int or tuple of ints, optional\n Given a shape of, for example, ``(m,n,k)``, ``m*n*k`` samples are\n generated, and packed in an `m`-by-`n`-by-`k` arrangement. Because\n each sample is `N`-dimensional, the output shape is ``(m,n,k,N)``.\n If no shape is specified, a single (`N`-D) sample is returned.\n check_valid : { 'warn', 'raise', 'ignore' }, optional\n Behavior when the covariance matrix is not positive semidefinite.\n tol : float, optional\n Tolerance when checking the singular values in covariance matrix.\n\n Returns\n -------\n out : ndarray\n The drawn samples, of shape *size*, if that was provided. If not,\n the shape is ``(N,)``.\n\n In other words, each entry ``out[i,j,...,:]`` is an N-dimensional\n value drawn from the distribution.\n\n Notes\n -----\n The mean is a coordinate in N-dimensional space, which represents the\n location where samples are most likely to be generated. This ""is\n analogous to the peak of the bell curve for the one-dimensional or\n univariate normal distribution.\n\n Covariance indicates the level to which two variables vary together.\n From the multivariate normal distribution, we draw N-dimensional\n samples, :math:`X = [x_1, x_2, ... x_N]`. The covariance matrix\n element :math:`C_{ij}` is the covariance of :math:`x_i` and :math:`x_j`.\n The element :math:`C_{ii}` is the variance of :math:`x_i` (i.e. its\n \"spread\").\n\n Instead of specifying the full covariance matrix, popular\n approximations include:\n\n - Spherical covariance (`cov` is a multiple of the identity matrix)\n - Diagonal covariance (`cov` has non-negative elements, and only on\n the diagonal)\n\n This geometrical property can be seen in two dimensions by plotting\n generated data-points:\n\n >>> mean = [0, 0]\n >>> cov = [[1, 0], [0, 100]] # diagonal covariance\n\n Diagonal covariance means that points are oriented along x or y-axis:\n\n >>> import matplotlib.pyplot as plt\n >>> x, y = np.random.multivariate_normal(mean, cov, 5000).T\n >>> plt.plot(x, y, 'x')\n >>> plt.axis('equal')\n >>> plt.show()\n\n Note that the covariance matrix must be positive semidefinite (a.k.a.\n nonnegative-definite). Otherwise, the behavior of this method is\n undefined and backwards compatibility is not guaranteed.\n\n References\n ----------\n .. [1] Papoulis, A., \"Probability, Random Variables, and Stochastic\n Processes,\" 3rd ed., New York: McGraw-Hill, 1991.\n .. [2] Duda, R. O., Hart, P. E., and Stork, D. G., \"Pattern\n Classification,\" 2nd ed., New York: Wiley, 2001.\n\n Examples\n --------\n >>> mean = (1, 2)\n >>> cov = [[1, 0], [0, 1]]\n >>> x = np.random.multivariate_normal(mean"", cov, (3, 3))\n >>> x.shape\n (3, 3, 2)\n\n The following is probably true, given that 0.6 is roughly twice the\n standard deviation:\n\n >>> list((x[0,0,:] - mean) < 0.6)\n [True, True]\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_97multivariate_normal(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_mean = 0; + PyObject *__pyx_v_cov = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_v_check_valid = 0; + PyObject *__pyx_v_tol = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("multivariate_normal (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_mean,&__pyx_n_s_cov,&__pyx_n_s_size,&__pyx_n_s_check_valid,&__pyx_n_s_tol,0}; + PyObject* values[5] = {0,0,0,0,0}; + values[2] = ((PyObject *)Py_None); + values[3] = ((PyObject *)__pyx_n_s_warn); + values[4] = ((PyObject *)__pyx_float_1eneg_8); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mean)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_cov)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("multivariate_normal", 0, 2, 5, 1); __PYX_ERR(0, 4382, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 3: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_check_valid); + if (value) { values[3] = value; kw_args--; } + } + CYTHON_FALLTHROUGH; + case 4: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_tol); + if (value) { values[4] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "multivariate_normal") < 0)) __PYX_ERR(0, 4382, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_mean = values[0]; + __pyx_v_cov = values[1]; + __pyx_v_size = values[2]; + __pyx_v_check_valid = values[3]; + __pyx_v_tol = values[4]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("multivariate_normal", 0, 2, 5, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 4382, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.multivariate_normal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_96multivariate_normal(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_mean, __pyx_v_cov, __pyx_v_size, __pyx_v_check_valid, __pyx_v_tol); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_96multivariate_normal(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_mean, PyObject *__pyx_v_cov, PyObject *__pyx_v_size, PyObject *__pyx_v_check_valid, PyObject *__pyx_v_tol) { + PyObject *__pyx_v_svd = NULL; + PyObject *__pyx_v_shape = NULL; + PyObject *__pyx_v_final_shape = NULL; + PyObject *__pyx_v_x = NULL; + CYTHON_UNUSED PyObject *__pyx_v_u = NULL; + PyObject *__pyx_v_s = NULL; + PyObject *__pyx_v_v = NULL; + PyObject *__pyx_v_psd = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_t_7; + Py_ssize_t __pyx_t_8; + int __pyx_t_9; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + PyObject *(*__pyx_t_12)(PyObject *); + PyObject *__pyx_t_13 = NULL; + __Pyx_RefNannySetupContext("multivariate_normal", 0); + __Pyx_INCREF(__pyx_v_mean); + __Pyx_INCREF(__pyx_v_cov); + + /* "mtrand.pyx":4483 + * + * """ + * from numpy.dual import svd # <<<<<<<<<<<<<< + * + * # Check preconditions on arguments + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4483, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_svd); + __Pyx_GIVEREF(__pyx_n_s_svd); + PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_svd); + __pyx_t_2 = __Pyx_Import(__pyx_n_s_numpy_dual, __pyx_t_1, -1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4483, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_svd); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4483, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_1); + __pyx_v_svd = __pyx_t_1; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "mtrand.pyx":4486 + * + * # Check preconditions on arguments + * mean = np.array(mean) # <<<<<<<<<<<<<< + * cov = np.array(cov) + * if size is None: + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4486, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_array); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4486, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + if (!__pyx_t_1) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_mean); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4486, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_v_mean}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4486, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_v_mean}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4486, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4486, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_1); __pyx_t_1 = NULL; + __Pyx_INCREF(__pyx_v_mean); + __Pyx_GIVEREF(__pyx_v_mean); + PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_mean); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4486, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF_SET(__pyx_v_mean, __pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":4487 + * # Check preconditions on arguments + * mean = np.array(mean) + * cov = np.array(cov) # <<<<<<<<<<<<<< + * if size is None: + * shape = [] + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_array); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (!__pyx_t_3) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_v_cov); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_cov}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4487, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_cov}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4487, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(__pyx_v_cov); + __Pyx_GIVEREF(__pyx_v_cov); + PyTuple_SET_ITEM(__pyx_t_1, 0+1, __pyx_v_cov); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF_SET(__pyx_v_cov, __pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":4488 + * mean = np.array(mean) + * cov = np.array(cov) + * if size is None: # <<<<<<<<<<<<<< + * shape = [] + * elif isinstance(size, (int, long, np.integer)): + */ + __pyx_t_5 = (__pyx_v_size == Py_None); + __pyx_t_6 = (__pyx_t_5 != 0); + if (__pyx_t_6) { + + /* "mtrand.pyx":4489 + * cov = np.array(cov) + * if size is None: + * shape = [] # <<<<<<<<<<<<<< + * elif isinstance(size, (int, long, np.integer)): + * shape = [size] + */ + __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4489, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_shape = __pyx_t_2; + __pyx_t_2 = 0; + + /* "mtrand.pyx":4488 + * mean = np.array(mean) + * cov = np.array(cov) + * if size is None: # <<<<<<<<<<<<<< + * shape = [] + * elif isinstance(size, (int, long, np.integer)): + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":4490 + * if size is None: + * shape = [] + * elif isinstance(size, (int, long, np.integer)): # <<<<<<<<<<<<<< + * shape = [size] + * else: + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4490, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_integer); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4490, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = PyInt_Check(__pyx_v_size); + __pyx_t_7 = (__pyx_t_5 != 0); + if (!__pyx_t_7) { + } else { + __pyx_t_6 = __pyx_t_7; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_7 = PyLong_Check(__pyx_v_size); + __pyx_t_5 = (__pyx_t_7 != 0); + if (!__pyx_t_5) { + } else { + __pyx_t_6 = __pyx_t_5; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_5 = PyObject_IsInstance(__pyx_v_size, __pyx_t_4); + __pyx_t_7 = (__pyx_t_5 != 0); + __pyx_t_6 = __pyx_t_7; + __pyx_L4_bool_binop_done:; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_7 = (__pyx_t_6 != 0); + if (__pyx_t_7) { + + /* "mtrand.pyx":4491 + * shape = [] + * elif isinstance(size, (int, long, np.integer)): + * shape = [size] # <<<<<<<<<<<<<< + * else: + * shape = size + */ + __pyx_t_4 = PyList_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4491, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyList_SET_ITEM(__pyx_t_4, 0, __pyx_v_size); + __pyx_v_shape = __pyx_t_4; + __pyx_t_4 = 0; + + /* "mtrand.pyx":4490 + * if size is None: + * shape = [] + * elif isinstance(size, (int, long, np.integer)): # <<<<<<<<<<<<<< + * shape = [size] + * else: + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":4493 + * shape = [size] + * else: + * shape = size # <<<<<<<<<<<<<< + * + * if len(mean.shape) != 1: + */ + /*else*/ { + __Pyx_INCREF(__pyx_v_size); + __pyx_v_shape = __pyx_v_size; + } + __pyx_L3:; + + /* "mtrand.pyx":4495 + * shape = size + * + * if len(mean.shape) != 1: # <<<<<<<<<<<<<< + * raise ValueError("mean must be 1 dimensional") + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_mean, __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4495, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = PyObject_Length(__pyx_t_4); if (unlikely(__pyx_t_8 == ((Py_ssize_t)-1))) __PYX_ERR(0, 4495, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_7 = ((__pyx_t_8 != 1) != 0); + if (unlikely(__pyx_t_7)) { + + /* "mtrand.pyx":4496 + * + * if len(mean.shape) != 1: + * raise ValueError("mean must be 1 dimensional") # <<<<<<<<<<<<<< + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + * raise ValueError("cov must be 2 dimensional and square") + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__164, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4496, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 4496, __pyx_L1_error) + + /* "mtrand.pyx":4495 + * shape = size + * + * if len(mean.shape) != 1: # <<<<<<<<<<<<<< + * raise ValueError("mean must be 1 dimensional") + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + */ + } + + /* "mtrand.pyx":4497 + * if len(mean.shape) != 1: + * raise ValueError("mean must be 1 dimensional") + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): # <<<<<<<<<<<<<< + * raise ValueError("cov must be 2 dimensional and square") + * if mean.shape[0] != cov.shape[0]: + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_cov, __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4497, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = PyObject_Length(__pyx_t_4); if (unlikely(__pyx_t_8 == ((Py_ssize_t)-1))) __PYX_ERR(0, 4497, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = ((__pyx_t_8 != 2) != 0); + if (!__pyx_t_6) { + } else { + __pyx_t_7 = __pyx_t_6; + goto __pyx_L9_bool_binop_done; + } + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_cov, __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4497, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_4, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4497, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_cov, __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4497, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = __Pyx_GetItemInt(__pyx_t_4, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4497, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = PyObject_RichCompare(__pyx_t_2, __pyx_t_1, Py_NE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4497, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 4497, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_7 = __pyx_t_6; + __pyx_L9_bool_binop_done:; + if (unlikely(__pyx_t_7)) { + + /* "mtrand.pyx":4498 + * raise ValueError("mean must be 1 dimensional") + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + * raise ValueError("cov must be 2 dimensional and square") # <<<<<<<<<<<<<< + * if mean.shape[0] != cov.shape[0]: + * raise ValueError("mean and cov must have same length") + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__165, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4498, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 4498, __pyx_L1_error) + + /* "mtrand.pyx":4497 + * if len(mean.shape) != 1: + * raise ValueError("mean must be 1 dimensional") + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): # <<<<<<<<<<<<<< + * raise ValueError("cov must be 2 dimensional and square") + * if mean.shape[0] != cov.shape[0]: + */ + } + + /* "mtrand.pyx":4499 + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + * raise ValueError("cov must be 2 dimensional and square") + * if mean.shape[0] != cov.shape[0]: # <<<<<<<<<<<<<< + * raise ValueError("mean and cov must have same length") + * + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_mean, __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4499, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = __Pyx_GetItemInt(__pyx_t_4, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4499, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_cov, __pyx_n_s_shape); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4499, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_4, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4499, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = PyObject_RichCompare(__pyx_t_1, __pyx_t_2, Py_NE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4499, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 4499, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (unlikely(__pyx_t_7)) { + + /* "mtrand.pyx":4500 + * raise ValueError("cov must be 2 dimensional and square") + * if mean.shape[0] != cov.shape[0]: + * raise ValueError("mean and cov must have same length") # <<<<<<<<<<<<<< + * + * # Compute shape of output and create a matrix of independent + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__166, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4500, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 4500, __pyx_L1_error) + + /* "mtrand.pyx":4499 + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + * raise ValueError("cov must be 2 dimensional and square") + * if mean.shape[0] != cov.shape[0]: # <<<<<<<<<<<<<< + * raise ValueError("mean and cov must have same length") + * + */ + } + + /* "mtrand.pyx":4506 + * # with the same length as mean and as many rows are necessary to + * # form a matrix of shape final_shape. + * final_shape = list(shape[:]) # <<<<<<<<<<<<<< + * final_shape.append(mean.shape[0]) + * x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) + */ + __pyx_t_4 = __Pyx_PyObject_GetSlice(__pyx_v_shape, 0, 0, NULL, NULL, &__pyx_slice__167, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = PySequence_List(__pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_final_shape = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + + /* "mtrand.pyx":4507 + * # form a matrix of shape final_shape. + * final_shape = list(shape[:]) + * final_shape.append(mean.shape[0]) # <<<<<<<<<<<<<< + * x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) + * + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_mean, __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4507, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4507, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_final_shape, __pyx_t_4); if (unlikely(__pyx_t_9 == ((int)-1))) __PYX_ERR(0, 4507, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "mtrand.pyx":4508 + * final_shape = list(shape[:]) + * final_shape.append(mean.shape[0]) + * x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) # <<<<<<<<<<<<<< + * + * # Transform matrix of standard normals into matrix where each row + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_standard_normal); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_3) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_v_final_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_final_shape}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_final_shape}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(__pyx_v_final_shape); + __Pyx_GIVEREF(__pyx_v_final_shape); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_v_final_shape); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_10, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_reshape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_mean, __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_10 = __Pyx_GetItemInt(__pyx_t_2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_int_neg_1, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_int_neg_1, __pyx_t_10}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else + #endif + { + __pyx_t_3 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(__pyx_int_neg_1); + __Pyx_GIVEREF(__pyx_int_neg_1); + PyTuple_SET_ITEM(__pyx_t_3, 0+__pyx_t_11, __pyx_int_neg_1); + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_3, 1+__pyx_t_11, __pyx_t_10); + __pyx_t_10 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_3, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4508, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_x = __pyx_t_4; + __pyx_t_4 = 0; + + /* "mtrand.pyx":4524 + * # been checked. + * + * (u, s, v) = svd(cov) # <<<<<<<<<<<<<< + * + * if check_valid != 'ignore': + */ + __Pyx_INCREF(__pyx_v_svd); + __pyx_t_1 = __pyx_v_svd; __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + if (!__pyx_t_3) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_v_cov); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_cov}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_cov}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(__pyx_v_cov); + __Pyx_GIVEREF(__pyx_v_cov); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_v_cov); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_10, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if ((likely(PyTuple_CheckExact(__pyx_t_4))) || (PyList_CheckExact(__pyx_t_4))) { + PyObject* sequence = __pyx_t_4; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 3)) { + if (size > 3) __Pyx_RaiseTooManyValuesError(3); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(0, 4524, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + if (likely(PyTuple_CheckExact(sequence))) { + __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_10 = PyTuple_GET_ITEM(sequence, 1); + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 2); + } else { + __pyx_t_1 = PyList_GET_ITEM(sequence, 0); + __pyx_t_10 = PyList_GET_ITEM(sequence, 1); + __pyx_t_3 = PyList_GET_ITEM(sequence, 2); + } + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_10); + __Pyx_INCREF(__pyx_t_3); + #else + __pyx_t_1 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_10 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_3 = PySequence_ITEM(sequence, 2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else { + Py_ssize_t index = -1; + __pyx_t_2 = PyObject_GetIter(__pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4524, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_12 = Py_TYPE(__pyx_t_2)->tp_iternext; + index = 0; __pyx_t_1 = __pyx_t_12(__pyx_t_2); if (unlikely(!__pyx_t_1)) goto __pyx_L12_unpacking_failed; + __Pyx_GOTREF(__pyx_t_1); + index = 1; __pyx_t_10 = __pyx_t_12(__pyx_t_2); if (unlikely(!__pyx_t_10)) goto __pyx_L12_unpacking_failed; + __Pyx_GOTREF(__pyx_t_10); + index = 2; __pyx_t_3 = __pyx_t_12(__pyx_t_2); if (unlikely(!__pyx_t_3)) goto __pyx_L12_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_12(__pyx_t_2), 3) < 0) __PYX_ERR(0, 4524, __pyx_L1_error) + __pyx_t_12 = NULL; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + goto __pyx_L13_unpacking_done; + __pyx_L12_unpacking_failed:; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_12 = NULL; + if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index); + __PYX_ERR(0, 4524, __pyx_L1_error) + __pyx_L13_unpacking_done:; + } + __pyx_v_u = __pyx_t_1; + __pyx_t_1 = 0; + __pyx_v_s = __pyx_t_10; + __pyx_t_10 = 0; + __pyx_v_v = __pyx_t_3; + __pyx_t_3 = 0; + + /* "mtrand.pyx":4526 + * (u, s, v) = svd(cov) + * + * if check_valid != 'ignore': # <<<<<<<<<<<<<< + * if check_valid != 'warn' and check_valid != 'raise': + * raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + */ + __pyx_t_7 = (__Pyx_PyString_Equals(__pyx_v_check_valid, __pyx_n_s_ignore, Py_NE)); if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 4526, __pyx_L1_error) + if (__pyx_t_7) { + + /* "mtrand.pyx":4527 + * + * if check_valid != 'ignore': + * if check_valid != 'warn' and check_valid != 'raise': # <<<<<<<<<<<<<< + * raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + * + */ + __pyx_t_6 = (__Pyx_PyString_Equals(__pyx_v_check_valid, __pyx_n_s_warn, Py_NE)); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 4527, __pyx_L1_error) + if (__pyx_t_6) { + } else { + __pyx_t_7 = __pyx_t_6; + goto __pyx_L16_bool_binop_done; + } + __pyx_t_6 = (__Pyx_PyString_Equals(__pyx_v_check_valid, __pyx_n_s_raise, Py_NE)); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 4527, __pyx_L1_error) + __pyx_t_7 = __pyx_t_6; + __pyx_L16_bool_binop_done:; + if (unlikely(__pyx_t_7)) { + + /* "mtrand.pyx":4528 + * if check_valid != 'ignore': + * if check_valid != 'warn' and check_valid != 'raise': + * raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") # <<<<<<<<<<<<<< + * + * psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__168, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4528, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(0, 4528, __pyx_L1_error) + + /* "mtrand.pyx":4527 + * + * if check_valid != 'ignore': + * if check_valid != 'warn' and check_valid != 'raise': # <<<<<<<<<<<<<< + * raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + * + */ + } + + /* "mtrand.pyx":4530 + * raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + * + * psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) # <<<<<<<<<<<<<< + * if not psd: + * if check_valid == 'warn': + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_allclose); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_dot); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_v, __pyx_n_s_T); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_2 = PyNumber_Multiply(__pyx_t_10, __pyx_v_s); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __pyx_t_10 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_10)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_10); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_10, __pyx_t_2, __pyx_v_v}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_10, __pyx_t_2, __pyx_v_v}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_13 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + if (__pyx_t_10) { + __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_10); __pyx_t_10 = NULL; + } + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_13, 0+__pyx_t_11, __pyx_t_2); + __Pyx_INCREF(__pyx_v_v); + __Pyx_GIVEREF(__pyx_v_v); + PyTuple_SET_ITEM(__pyx_t_13, 1+__pyx_t_11, __pyx_v_v); + __pyx_t_2 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_13, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_4); + __Pyx_INCREF(__pyx_v_cov); + __Pyx_GIVEREF(__pyx_v_cov); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_v_cov); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_rtol, __pyx_v_tol) < 0) __PYX_ERR(0, 4530, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_atol, __pyx_v_tol) < 0) __PYX_ERR(0, 4530, __pyx_L1_error) + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4530, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_psd = __pyx_t_13; + __pyx_t_13 = 0; + + /* "mtrand.pyx":4531 + * + * psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + * if not psd: # <<<<<<<<<<<<<< + * if check_valid == 'warn': + * warnings.warn("covariance is not positive-semidefinite.", + */ + __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_v_psd); if (unlikely(__pyx_t_7 < 0)) __PYX_ERR(0, 4531, __pyx_L1_error) + __pyx_t_6 = ((!__pyx_t_7) != 0); + if (__pyx_t_6) { + + /* "mtrand.pyx":4532 + * psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + * if not psd: + * if check_valid == 'warn': # <<<<<<<<<<<<<< + * warnings.warn("covariance is not positive-semidefinite.", + * RuntimeWarning) + */ + __pyx_t_6 = (__Pyx_PyString_Equals(__pyx_v_check_valid, __pyx_n_s_warn, Py_EQ)); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 4532, __pyx_L1_error) + if (likely(__pyx_t_6)) { + + /* "mtrand.pyx":4533 + * if not psd: + * if check_valid == 'warn': + * warnings.warn("covariance is not positive-semidefinite.", # <<<<<<<<<<<<<< + * RuntimeWarning) + * else: + */ + __pyx_t_13 = __Pyx_GetModuleGlobalName(__pyx_n_s_warnings); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4533, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_n_s_warn); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4533, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + + /* "mtrand.pyx":4534 + * if check_valid == 'warn': + * warnings.warn("covariance is not positive-semidefinite.", + * RuntimeWarning) # <<<<<<<<<<<<<< + * else: + * raise ValueError("covariance is not positive-semidefinite.") + */ + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_tuple__169, NULL); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4533, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + + /* "mtrand.pyx":4532 + * psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + * if not psd: + * if check_valid == 'warn': # <<<<<<<<<<<<<< + * warnings.warn("covariance is not positive-semidefinite.", + * RuntimeWarning) + */ + goto __pyx_L19; + } + + /* "mtrand.pyx":4536 + * RuntimeWarning) + * else: + * raise ValueError("covariance is not positive-semidefinite.") # <<<<<<<<<<<<<< + * + * x = np.dot(x, np.sqrt(s)[:, None] * v) + */ + /*else*/ { + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__170, NULL); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4536, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_Raise(__pyx_t_13, 0, 0, 0); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __PYX_ERR(0, 4536, __pyx_L1_error) + } + __pyx_L19:; + + /* "mtrand.pyx":4531 + * + * psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + * if not psd: # <<<<<<<<<<<<<< + * if check_valid == 'warn': + * warnings.warn("covariance is not positive-semidefinite.", + */ + } + + /* "mtrand.pyx":4526 + * (u, s, v) = svd(cov) + * + * if check_valid != 'ignore': # <<<<<<<<<<<<<< + * if check_valid != 'warn' and check_valid != 'raise': + * raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + */ + } + + /* "mtrand.pyx":4538 + * raise ValueError("covariance is not positive-semidefinite.") + * + * x = np.dot(x, np.sqrt(s)[:, None] * v) # <<<<<<<<<<<<<< + * x += mean + * x.shape = tuple(final_shape) + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_dot); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_sqrt); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + if (!__pyx_t_3) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_s); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_s}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_s}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_INCREF(__pyx_v_s); + __Pyx_GIVEREF(__pyx_v_s); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_v_s); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = __Pyx_PyObject_GetItem(__pyx_t_4, __pyx_tuple__172); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = PyNumber_Multiply(__pyx_t_2, __pyx_v_v); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_v_x, __pyx_t_4}; + __pyx_t_13 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_v_x, __pyx_t_4}; + __pyx_t_13 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_11, 2+__pyx_t_11); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(2+__pyx_t_11); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(__pyx_v_x); + __Pyx_GIVEREF(__pyx_v_x); + PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_11, __pyx_v_x); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_11, __pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_10, NULL); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF_SET(__pyx_v_x, __pyx_t_13); + __pyx_t_13 = 0; + + /* "mtrand.pyx":4539 + * + * x = np.dot(x, np.sqrt(s)[:, None] * v) + * x += mean # <<<<<<<<<<<<<< + * x.shape = tuple(final_shape) + * return x + */ + __pyx_t_13 = PyNumber_InPlaceAdd(__pyx_v_x, __pyx_v_mean); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4539, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF_SET(__pyx_v_x, __pyx_t_13); + __pyx_t_13 = 0; + + /* "mtrand.pyx":4540 + * x = np.dot(x, np.sqrt(s)[:, None] * v) + * x += mean + * x.shape = tuple(final_shape) # <<<<<<<<<<<<<< + * return x + * + */ + __pyx_t_13 = PyList_AsTuple(__pyx_v_final_shape); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4540, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + if (__Pyx_PyObject_SetAttrStr(__pyx_v_x, __pyx_n_s_shape, __pyx_t_13) < 0) __PYX_ERR(0, 4540, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + + /* "mtrand.pyx":4541 + * x += mean + * x.shape = tuple(final_shape) + * return x # <<<<<<<<<<<<<< + * + * def multinomial(self, npy_intp n, object pvals, size=None): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_x); + __pyx_r = __pyx_v_x; + goto __pyx_L0; + + /* "mtrand.pyx":4382 + * + * # Multivariate distributions: + * def multivariate_normal(self, mean, cov, size=None, check_valid='warn', # <<<<<<<<<<<<<< + * tol=1e-8): + * """ + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_13); + __Pyx_AddTraceback("mtrand.RandomState.multivariate_normal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_svd); + __Pyx_XDECREF(__pyx_v_shape); + __Pyx_XDECREF(__pyx_v_final_shape); + __Pyx_XDECREF(__pyx_v_x); + __Pyx_XDECREF(__pyx_v_u); + __Pyx_XDECREF(__pyx_v_s); + __Pyx_XDECREF(__pyx_v_v); + __Pyx_XDECREF(__pyx_v_psd); + __Pyx_XDECREF(__pyx_v_mean); + __Pyx_XDECREF(__pyx_v_cov); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4543 + * return x + * + * def multinomial(self, npy_intp n, object pvals, size=None): # <<<<<<<<<<<<<< + * """ + * multinomial(n, pvals, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_99multinomial(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_98multinomial[] = "\n multinomial(n, pvals, size=None)\n\n Draw samples from a multinomial distribution.\n\n The multinomial distribution is a multivariate generalisation of the\n binomial distribution. Take an experiment with one of ``p``\n possible outcomes. An example of such an experiment is throwing a dice,\n where the outcome can be 1 through 6. Each sample drawn from the\n distribution represents `n` such experiments. Its values,\n ``X_i = [X_0, X_1, ..., X_p]``, represent the number of times the\n outcome was ``i``.\n\n Parameters\n ----------\n n : int\n Number of experiments.\n pvals : sequence of floats, length p\n Probabilities of each of the ``p`` different outcomes. These\n should sum to 1 (however, the last element is always assumed to\n account for the remaining probability, as long as\n ``sum(pvals[:-1]) <= 1)``.\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n out : ndarray\n The drawn samples, of shape *size*, if that was provided. If not,\n the shape is ``(N,)``.\n\n In other words, each entry ``out[i,j,...,:]`` is an N-dimensional\n value drawn from the distribution.\n\n Examples\n --------\n Throw a dice 20 times:\n\n >>> np.random.multinomial(20, [1/6.]*6, size=1)\n array([[4, 1, 7, 5, 2, 1]])\n\n It landed 4 times on 1, once on 2, etc.\n\n Now, throw the dice 20 times, and 20 times again:\n\n >>> np.random.multinomial(20, [1/6.]*6, size=2)\n array([[3, 4, 3, 3, 4, 3],\n [2, 4, 3, 4, 0, 7]])\n\n For the first run, we threw 3 times 1, 4 times 2, etc. Fo""r the second,\n we threw 2 times 1, 4 times 2, etc.\n\n A loaded die is more likely to land on number 6:\n\n >>> np.random.multinomial(100, [1/7.]*5 + [2/7.])\n array([11, 16, 14, 17, 16, 26])\n\n The probability inputs should be normalized. As an implementation\n detail, the value of the last entry is ignored and assumed to take\n up any leftover probability mass, but this should not be relied on.\n A biased coin which has twice as much weight on one side as on the\n other should be sampled like so:\n\n >>> np.random.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT\n array([38, 62])\n\n not like:\n\n >>> np.random.multinomial(100, [1.0, 2.0]) # WRONG\n array([100, 0])\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_99multinomial(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + npy_intp __pyx_v_n; + PyObject *__pyx_v_pvals = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("multinomial (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_n,&__pyx_n_s_pvals,&__pyx_n_s_size,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_n)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pvals)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("multinomial", 0, 2, 3, 1); __PYX_ERR(0, 4543, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "multinomial") < 0)) __PYX_ERR(0, 4543, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_n = __Pyx_PyInt_As_npy_intp(values[0]); if (unlikely((__pyx_v_n == ((npy_intp)-1)) && PyErr_Occurred())) __PYX_ERR(0, 4543, __pyx_L3_error) + __pyx_v_pvals = values[1]; + __pyx_v_size = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("multinomial", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 4543, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.multinomial", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_98multinomial(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_n, __pyx_v_pvals, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_98multinomial(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, npy_intp __pyx_v_n, PyObject *__pyx_v_pvals, PyObject *__pyx_v_size) { + npy_intp __pyx_v_d; + PyArrayObject *arrayObject_parr = 0; + PyArrayObject *arrayObject_mnarr = 0; + double *__pyx_v_pix; + long *__pyx_v_mnix; + npy_intp __pyx_v_i; + npy_intp __pyx_v_j; + npy_intp __pyx_v_dn; + npy_intp __pyx_v_sz; + double __pyx_v_Sum; + PyObject *__pyx_v_shape = NULL; + PyObject *__pyx_v_multin = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_t_7; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + long __pyx_t_13; + __Pyx_RefNannySetupContext("multinomial", 0); + + /* "mtrand.pyx":4625 + * cdef double Sum + * + * d = len(pvals) # <<<<<<<<<<<<<< + * parr = PyArray_ContiguousFromObject(pvals, NPY_DOUBLE, 1, 1) + * pix = PyArray_DATA(parr) + */ + __pyx_t_1 = PyObject_Length(__pyx_v_pvals); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 4625, __pyx_L1_error) + __pyx_v_d = __pyx_t_1; + + /* "mtrand.pyx":4626 + * + * d = len(pvals) + * parr = PyArray_ContiguousFromObject(pvals, NPY_DOUBLE, 1, 1) # <<<<<<<<<<<<<< + * pix = PyArray_DATA(parr) + * + */ + __pyx_t_2 = PyArray_ContiguousFromObject(__pyx_v_pvals, NPY_DOUBLE, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4626, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + arrayObject_parr = ((PyArrayObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":4627 + * d = len(pvals) + * parr = PyArray_ContiguousFromObject(pvals, NPY_DOUBLE, 1, 1) + * pix = PyArray_DATA(parr) # <<<<<<<<<<<<<< + * + * if kahan_sum(pix, d-1) > (1.0 + 1e-12): + */ + __pyx_v_pix = ((double *)PyArray_DATA(arrayObject_parr)); + + /* "mtrand.pyx":4629 + * pix = PyArray_DATA(parr) + * + * if kahan_sum(pix, d-1) > (1.0 + 1e-12): # <<<<<<<<<<<<<< + * raise ValueError("sum(pvals[:-1]) > 1.0") + * + */ + __pyx_t_4 = ((__pyx_f_6mtrand_kahan_sum(__pyx_v_pix, (__pyx_v_d - 1)) > (1.0 + 1e-12)) != 0); + if (unlikely(__pyx_t_4)) { + + /* "mtrand.pyx":4630 + * + * if kahan_sum(pix, d-1) > (1.0 + 1e-12): + * raise ValueError("sum(pvals[:-1]) > 1.0") # <<<<<<<<<<<<<< + * + * shape = _shape_from_size(size, d) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__173, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4630, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 4630, __pyx_L1_error) + + /* "mtrand.pyx":4629 + * pix = PyArray_DATA(parr) + * + * if kahan_sum(pix, d-1) > (1.0 + 1e-12): # <<<<<<<<<<<<<< + * raise ValueError("sum(pvals[:-1]) > 1.0") + * + */ + } + + /* "mtrand.pyx":4632 + * raise ValueError("sum(pvals[:-1]) > 1.0") + * + * shape = _shape_from_size(size, d) # <<<<<<<<<<<<<< + * + * multin = np.zeros(shape, int) + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_shape_from_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4632, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = __Pyx_PyInt_From_npy_intp(__pyx_v_d); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4632, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = NULL; + __pyx_t_7 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_7 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_v_size, __pyx_t_5}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4632, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_v_size, __pyx_t_5}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4632, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 4632, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_7, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_7, __pyx_t_5); + __pyx_t_5 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4632, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_shape = __pyx_t_3; + __pyx_t_3 = 0; + + /* "mtrand.pyx":4634 + * shape = _shape_from_size(size, d) + * + * multin = np.zeros(shape, int) # <<<<<<<<<<<<<< + * mnarr = multin + * mnix = PyArray_DATA(mnarr) + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4634, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_zeros); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 4634, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + __pyx_t_7 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + __pyx_t_7 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_v_shape, ((PyObject *)(&PyInt_Type))}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4634, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_v_shape, ((PyObject *)(&PyInt_Type))}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4634, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else + #endif + { + __pyx_t_5 = PyTuple_New(2+__pyx_t_7); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4634, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_7, __pyx_v_shape); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_7, ((PyObject *)(&PyInt_Type))); + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_5, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4634, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_multin = __pyx_t_3; + __pyx_t_3 = 0; + + /* "mtrand.pyx":4635 + * + * multin = np.zeros(shape, int) + * mnarr = multin # <<<<<<<<<<<<<< + * mnix = PyArray_DATA(mnarr) + * sz = PyArray_SIZE(mnarr) + */ + __pyx_t_3 = __pyx_v_multin; + __Pyx_INCREF(__pyx_t_3); + arrayObject_mnarr = ((PyArrayObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":4636 + * multin = np.zeros(shape, int) + * mnarr = multin + * mnix = PyArray_DATA(mnarr) # <<<<<<<<<<<<<< + * sz = PyArray_SIZE(mnarr) + * with self.lock, nogil, cython.cdivision(True): + */ + __pyx_v_mnix = ((long *)PyArray_DATA(arrayObject_mnarr)); + + /* "mtrand.pyx":4637 + * mnarr = multin + * mnix = PyArray_DATA(mnarr) + * sz = PyArray_SIZE(mnarr) # <<<<<<<<<<<<<< + * with self.lock, nogil, cython.cdivision(True): + * i = 0 + */ + __pyx_v_sz = PyArray_SIZE(arrayObject_mnarr); + + /* "mtrand.pyx":4638 + * mnix = PyArray_DATA(mnarr) + * sz = PyArray_SIZE(mnarr) + * with self.lock, nogil, cython.cdivision(True): # <<<<<<<<<<<<<< + * i = 0 + * while i < sz: + */ + /*with:*/ { + __pyx_t_9 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_8 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 4638, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_8); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_8, function); + } + } + if (__pyx_t_5) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4638, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4638, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + /*try:*/ { + { + (void)__pyx_t_10; (void)__pyx_t_11; (void)__pyx_t_12; /* mark used */ + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":4639 + * sz = PyArray_SIZE(mnarr) + * with self.lock, nogil, cython.cdivision(True): + * i = 0 # <<<<<<<<<<<<<< + * while i < sz: + * Sum = 1.0 + */ + __pyx_v_i = 0; + + /* "mtrand.pyx":4640 + * with self.lock, nogil, cython.cdivision(True): + * i = 0 + * while i < sz: # <<<<<<<<<<<<<< + * Sum = 1.0 + * dn = n + */ + while (1) { + __pyx_t_4 = ((__pyx_v_i < __pyx_v_sz) != 0); + if (!__pyx_t_4) break; + + /* "mtrand.pyx":4641 + * i = 0 + * while i < sz: + * Sum = 1.0 # <<<<<<<<<<<<<< + * dn = n + * for j from 0 <= j < d-1: + */ + __pyx_v_Sum = 1.0; + + /* "mtrand.pyx":4642 + * while i < sz: + * Sum = 1.0 + * dn = n # <<<<<<<<<<<<<< + * for j from 0 <= j < d-1: + * mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum) + */ + __pyx_v_dn = __pyx_v_n; + + /* "mtrand.pyx":4643 + * Sum = 1.0 + * dn = n + * for j from 0 <= j < d-1: # <<<<<<<<<<<<<< + * mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum) + * dn = dn - mnix[i+j] + */ + __pyx_t_13 = (__pyx_v_d - 1); + for (__pyx_v_j = 0; __pyx_v_j < __pyx_t_13; __pyx_v_j++) { + + /* "mtrand.pyx":4644 + * dn = n + * for j from 0 <= j < d-1: + * mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum) # <<<<<<<<<<<<<< + * dn = dn - mnix[i+j] + * if dn <= 0: + */ + (__pyx_v_mnix[(__pyx_v_i + __pyx_v_j)]) = rk_binomial(__pyx_v_self->internal_state, __pyx_v_dn, ((__pyx_v_pix[__pyx_v_j]) / __pyx_v_Sum)); + + /* "mtrand.pyx":4645 + * for j from 0 <= j < d-1: + * mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum) + * dn = dn - mnix[i+j] # <<<<<<<<<<<<<< + * if dn <= 0: + * break + */ + __pyx_v_dn = (__pyx_v_dn - (__pyx_v_mnix[(__pyx_v_i + __pyx_v_j)])); + + /* "mtrand.pyx":4646 + * mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum) + * dn = dn - mnix[i+j] + * if dn <= 0: # <<<<<<<<<<<<<< + * break + * Sum = Sum - pix[j] + */ + __pyx_t_4 = ((__pyx_v_dn <= 0) != 0); + if (__pyx_t_4) { + + /* "mtrand.pyx":4647 + * dn = dn - mnix[i+j] + * if dn <= 0: + * break # <<<<<<<<<<<<<< + * Sum = Sum - pix[j] + * if dn > 0: + */ + goto __pyx_L20_break; + + /* "mtrand.pyx":4646 + * mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum) + * dn = dn - mnix[i+j] + * if dn <= 0: # <<<<<<<<<<<<<< + * break + * Sum = Sum - pix[j] + */ + } + + /* "mtrand.pyx":4648 + * if dn <= 0: + * break + * Sum = Sum - pix[j] # <<<<<<<<<<<<<< + * if dn > 0: + * mnix[i+d-1] = dn + */ + __pyx_v_Sum = (__pyx_v_Sum - (__pyx_v_pix[__pyx_v_j])); + } + __pyx_L20_break:; + + /* "mtrand.pyx":4649 + * break + * Sum = Sum - pix[j] + * if dn > 0: # <<<<<<<<<<<<<< + * mnix[i+d-1] = dn + * + */ + __pyx_t_4 = ((__pyx_v_dn > 0) != 0); + if (__pyx_t_4) { + + /* "mtrand.pyx":4650 + * Sum = Sum - pix[j] + * if dn > 0: + * mnix[i+d-1] = dn # <<<<<<<<<<<<<< + * + * i = i + d + */ + (__pyx_v_mnix[((__pyx_v_i + __pyx_v_d) - 1)]) = __pyx_v_dn; + + /* "mtrand.pyx":4649 + * break + * Sum = Sum - pix[j] + * if dn > 0: # <<<<<<<<<<<<<< + * mnix[i+d-1] = dn + * + */ + } + + /* "mtrand.pyx":4652 + * mnix[i+d-1] = dn + * + * i = i + d # <<<<<<<<<<<<<< + * + * return multin + */ + __pyx_v_i = (__pyx_v_i + __pyx_v_d); + } + } + + /* "mtrand.pyx":4638 + * mnix = PyArray_DATA(mnarr) + * sz = PyArray_SIZE(mnarr) + * with self.lock, nogil, cython.cdivision(True): # <<<<<<<<<<<<<< + * i = 0 + * while i < sz: + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L16:; + } + } + } + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_9) { + __pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_tuple__174, NULL); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 4638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L23; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L1_error; + __pyx_L23:; + } + + /* "mtrand.pyx":4654 + * i = i + d + * + * return multin # <<<<<<<<<<<<<< + * + * def dirichlet(self, object alpha, size=None): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_multin); + __pyx_r = __pyx_v_multin; + goto __pyx_L0; + + /* "mtrand.pyx":4543 + * return x + * + * def multinomial(self, npy_intp n, object pvals, size=None): # <<<<<<<<<<<<<< + * """ + * multinomial(n, pvals, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.multinomial", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)arrayObject_parr); + __Pyx_XDECREF((PyObject *)arrayObject_mnarr); + __Pyx_XDECREF(__pyx_v_shape); + __Pyx_XDECREF(__pyx_v_multin); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4656 + * return multin + * + * def dirichlet(self, object alpha, size=None): # <<<<<<<<<<<<<< + * """ + * dirichlet(alpha, size=None) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_101dirichlet(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_100dirichlet[] = "\n dirichlet(alpha, size=None)\n\n Draw samples from the Dirichlet distribution.\n\n Draw `size` samples of dimension k from a Dirichlet distribution. A\n Dirichlet-distributed random variable can be seen as a multivariate\n generalization of a Beta distribution. Dirichlet pdf is the conjugate\n prior of a multinomial in Bayesian inference.\n\n Parameters\n ----------\n alpha : array\n Parameter of the distribution (k dimension for sample of\n dimension k).\n size : int or tuple of ints, optional\n Output shape. If the given shape is, e.g., ``(m, n, k)``, then\n ``m * n * k`` samples are drawn. Default is None, in which case a\n single value is returned.\n\n Returns\n -------\n samples : ndarray,\n The drawn samples, of shape (size, alpha.ndim).\n\n Raises\n -------\n ValueError\n If any value in alpha is less than or equal to zero\n\n Notes\n -----\n .. math:: X \\approx \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i}\n\n Uses the following property for computation: for each dimension,\n draw a random sample y_i from a standard gamma generator of shape\n `alpha_i`, then\n :math:`X = \\frac{1}{\\sum_{i=1}^k{y_i}} (y_1, \\ldots, y_n)` is\n Dirichlet distributed.\n\n References\n ----------\n .. [1] David McKay, \"Information Theory, Inference and Learning\n Algorithms,\" chapter 23,\n http://www.inference.phy.cam.ac.uk/mackay/\n .. [2] Wikipedia, \"Dirichlet distribution\",\n http://en.wikipedia.org/wiki/Dirichlet_distribution\n\n Examples\n --------\n Taking an example cited in Wikipedia, this distribution can be used if\n one wanted to cut strings (each of initial length 1.0) into K pieces\n with different lengths, where each piece"" had, on average, a designated\n average length, but allowing some variation in the relative sizes of\n the pieces.\n\n >>> s = np.random.dirichlet((10, 5, 3), 20).transpose()\n\n >>> plt.barh(range(20), s[0])\n >>> plt.barh(range(20), s[1], left=s[0], color='g')\n >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r')\n >>> plt.title(\"Lengths of Strings\")\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_101dirichlet(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_alpha = 0; + PyObject *__pyx_v_size = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("dirichlet (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_alpha,&__pyx_n_s_size,0}; + PyObject* values[2] = {0,0}; + values[1] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_alpha)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_size); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "dirichlet") < 0)) __PYX_ERR(0, 4656, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_alpha = values[0]; + __pyx_v_size = values[1]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("dirichlet", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 4656, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mtrand.RandomState.dirichlet", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6mtrand_11RandomState_100dirichlet(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), __pyx_v_alpha, __pyx_v_size); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_100dirichlet(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_alpha, PyObject *__pyx_v_size) { + npy_intp __pyx_v_k; + npy_intp __pyx_v_totsize; + PyArrayObject *__pyx_v_alpha_arr = 0; + PyArrayObject *__pyx_v_val_arr = 0; + double *__pyx_v_alpha_data; + double *__pyx_v_val_data; + npy_intp __pyx_v_i; + npy_intp __pyx_v_j; + double __pyx_v_acc; + double __pyx_v_invacc; + PyObject *__pyx_v_shape = NULL; + PyObject *__pyx_v_diric = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_t_7; + PyObject *__pyx_t_8 = NULL; + int __pyx_t_9; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + npy_intp __pyx_t_14; + PyObject *__pyx_t_15 = NULL; + int __pyx_t_16; + __Pyx_RefNannySetupContext("dirichlet", 0); + + /* "mtrand.pyx":4750 + * cdef double acc, invacc + * + * k = len(alpha) # <<<<<<<<<<<<<< + * alpha_arr = PyArray_ContiguousFromObject(alpha, NPY_DOUBLE, 1, 1) + * if np.any(np.less_equal(alpha_arr, 0)): + */ + __pyx_t_1 = PyObject_Length(__pyx_v_alpha); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 4750, __pyx_L1_error) + __pyx_v_k = __pyx_t_1; + + /* "mtrand.pyx":4751 + * + * k = len(alpha) + * alpha_arr = PyArray_ContiguousFromObject(alpha, NPY_DOUBLE, 1, 1) # <<<<<<<<<<<<<< + * if np.any(np.less_equal(alpha_arr, 0)): + * raise ValueError('alpha <= 0') + */ + __pyx_t_2 = PyArray_ContiguousFromObject(__pyx_v_alpha, NPY_DOUBLE, 1, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4751, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __pyx_t_2; + __Pyx_INCREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_alpha_arr = ((PyArrayObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":4752 + * k = len(alpha) + * alpha_arr = PyArray_ContiguousFromObject(alpha, NPY_DOUBLE, 1, 1) + * if np.any(np.less_equal(alpha_arr, 0)): # <<<<<<<<<<<<<< + * raise ValueError('alpha <= 0') + * alpha_data = PyArray_DATA(alpha_arr) + */ + __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_any); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_less_equal); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_5 = NULL; + __pyx_t_7 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_7 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, ((PyObject *)__pyx_v_alpha_arr), __pyx_int_0}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_5, ((PyObject *)__pyx_v_alpha_arr), __pyx_int_0}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_5); __pyx_t_5 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_alpha_arr)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_alpha_arr)); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_7, ((PyObject *)__pyx_v_alpha_arr)); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_7, __pyx_int_0); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (!__pyx_t_6) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_2}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_2); + __pyx_t_2 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_9 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_9 < 0)) __PYX_ERR(0, 4752, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(__pyx_t_9)) { + + /* "mtrand.pyx":4753 + * alpha_arr = PyArray_ContiguousFromObject(alpha, NPY_DOUBLE, 1, 1) + * if np.any(np.less_equal(alpha_arr, 0)): + * raise ValueError('alpha <= 0') # <<<<<<<<<<<<<< + * alpha_data = PyArray_DATA(alpha_arr) + * + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__175, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4753, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(0, 4753, __pyx_L1_error) + + /* "mtrand.pyx":4752 + * k = len(alpha) + * alpha_arr = PyArray_ContiguousFromObject(alpha, NPY_DOUBLE, 1, 1) + * if np.any(np.less_equal(alpha_arr, 0)): # <<<<<<<<<<<<<< + * raise ValueError('alpha <= 0') + * alpha_data = PyArray_DATA(alpha_arr) + */ + } + + /* "mtrand.pyx":4754 + * if np.any(np.less_equal(alpha_arr, 0)): + * raise ValueError('alpha <= 0') + * alpha_data = PyArray_DATA(alpha_arr) # <<<<<<<<<<<<<< + * + * shape = _shape_from_size(size, k) + */ + __pyx_v_alpha_data = ((double *)PyArray_DATA(__pyx_v_alpha_arr)); + + /* "mtrand.pyx":4756 + * alpha_data = PyArray_DATA(alpha_arr) + * + * shape = _shape_from_size(size, k) # <<<<<<<<<<<<<< + * + * diric = np.zeros(shape, np.float64) + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_shape_from_size); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4756, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = __Pyx_PyInt_From_npy_intp(__pyx_v_k); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 4756, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_2 = NULL; + __pyx_t_7 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_7 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_v_size, __pyx_t_8}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4756, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[3] = {__pyx_t_2, __pyx_v_size, __pyx_t_8}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4756, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else + #endif + { + __pyx_t_6 = PyTuple_New(2+__pyx_t_7); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4756, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (__pyx_t_2) { + __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_2); __pyx_t_2 = NULL; + } + __Pyx_INCREF(__pyx_v_size); + __Pyx_GIVEREF(__pyx_v_size); + PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_7, __pyx_v_size); + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_7, __pyx_t_8); + __pyx_t_8 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_6, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4756, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_shape = __pyx_t_3; + __pyx_t_3 = 0; + + /* "mtrand.pyx":4758 + * shape = _shape_from_size(size, k) + * + * diric = np.zeros(shape, np.float64) # <<<<<<<<<<<<<< + * val_arr = diric + * val_data= PyArray_DATA(val_arr) + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4758, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_zeros); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4758, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4758, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float64); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 4758, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = NULL; + __pyx_t_7 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_4)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_4); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + __pyx_t_7 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_v_shape, __pyx_t_8}; + __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4758, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_v_shape, __pyx_t_8}; + __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4758, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else + #endif + { + __pyx_t_2 = PyTuple_New(2+__pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4758, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (__pyx_t_4) { + __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_4); __pyx_t_4 = NULL; + } + __Pyx_INCREF(__pyx_v_shape); + __Pyx_GIVEREF(__pyx_v_shape); + PyTuple_SET_ITEM(__pyx_t_2, 0+__pyx_t_7, __pyx_v_shape); + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_2, 1+__pyx_t_7, __pyx_t_8); + __pyx_t_8 = 0; + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_2, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4758, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_v_diric = __pyx_t_3; + __pyx_t_3 = 0; + + /* "mtrand.pyx":4759 + * + * diric = np.zeros(shape, np.float64) + * val_arr = diric # <<<<<<<<<<<<<< + * val_data= PyArray_DATA(val_arr) + * + */ + __pyx_t_3 = __pyx_v_diric; + __Pyx_INCREF(__pyx_t_3); + __pyx_v_val_arr = ((PyArrayObject *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "mtrand.pyx":4760 + * diric = np.zeros(shape, np.float64) + * val_arr = diric + * val_data= PyArray_DATA(val_arr) # <<<<<<<<<<<<<< + * + * i = 0 + */ + __pyx_v_val_data = ((double *)PyArray_DATA(__pyx_v_val_arr)); + + /* "mtrand.pyx":4762 + * val_data= PyArray_DATA(val_arr) + * + * i = 0 # <<<<<<<<<<<<<< + * totsize = PyArray_SIZE(val_arr) + * with self.lock, nogil: + */ + __pyx_v_i = 0; + + /* "mtrand.pyx":4763 + * + * i = 0 + * totsize = PyArray_SIZE(val_arr) # <<<<<<<<<<<<<< + * with self.lock, nogil: + * while i < totsize: + */ + __pyx_v_totsize = PyArray_SIZE(__pyx_v_val_arr); + + /* "mtrand.pyx":4764 + * i = 0 + * totsize = PyArray_SIZE(val_arr) + * with self.lock, nogil: # <<<<<<<<<<<<<< + * while i < totsize: + * acc = 0.0 + */ + /*with:*/ { + __pyx_t_10 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4764, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_6 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4764, __pyx_L4_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (__pyx_t_2) { + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4764, __pyx_L4_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + } else { + __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4764, __pyx_L4_error) + } + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + /*try:*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_11, &__pyx_t_12, &__pyx_t_13); + __Pyx_XGOTREF(__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_12); + __Pyx_XGOTREF(__pyx_t_13); + /*try:*/ { + { + #ifdef WITH_THREAD + PyThreadState *_save; + Py_UNBLOCK_THREADS + __Pyx_FastGIL_Remember(); + #endif + /*try:*/ { + + /* "mtrand.pyx":4765 + * totsize = PyArray_SIZE(val_arr) + * with self.lock, nogil: + * while i < totsize: # <<<<<<<<<<<<<< + * acc = 0.0 + * for j from 0 <= j < k: + */ + while (1) { + __pyx_t_9 = ((__pyx_v_i < __pyx_v_totsize) != 0); + if (!__pyx_t_9) break; + + /* "mtrand.pyx":4766 + * with self.lock, nogil: + * while i < totsize: + * acc = 0.0 # <<<<<<<<<<<<<< + * for j from 0 <= j < k: + * val_data[i+j] = rk_standard_gamma(self.internal_state, + */ + __pyx_v_acc = 0.0; + + /* "mtrand.pyx":4767 + * while i < totsize: + * acc = 0.0 + * for j from 0 <= j < k: # <<<<<<<<<<<<<< + * val_data[i+j] = rk_standard_gamma(self.internal_state, + * alpha_data[j]) + */ + __pyx_t_14 = __pyx_v_k; + for (__pyx_v_j = 0; __pyx_v_j < __pyx_t_14; __pyx_v_j++) { + + /* "mtrand.pyx":4768 + * acc = 0.0 + * for j from 0 <= j < k: + * val_data[i+j] = rk_standard_gamma(self.internal_state, # <<<<<<<<<<<<<< + * alpha_data[j]) + * acc = acc + val_data[i+j] + */ + (__pyx_v_val_data[(__pyx_v_i + __pyx_v_j)]) = rk_standard_gamma(__pyx_v_self->internal_state, (__pyx_v_alpha_data[__pyx_v_j])); + + /* "mtrand.pyx":4770 + * val_data[i+j] = rk_standard_gamma(self.internal_state, + * alpha_data[j]) + * acc = acc + val_data[i+j] # <<<<<<<<<<<<<< + * invacc = 1/acc + * for j from 0 <= j < k: + */ + __pyx_v_acc = (__pyx_v_acc + (__pyx_v_val_data[(__pyx_v_i + __pyx_v_j)])); + } + + /* "mtrand.pyx":4771 + * alpha_data[j]) + * acc = acc + val_data[i+j] + * invacc = 1/acc # <<<<<<<<<<<<<< + * for j from 0 <= j < k: + * val_data[i+j] = val_data[i+j] * invacc + */ + if (unlikely(__pyx_v_acc == 0)) { + #ifdef WITH_THREAD + PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure(); + #endif + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + #ifdef WITH_THREAD + __Pyx_PyGILState_Release(__pyx_gilstate_save); + #endif + __PYX_ERR(0, 4771, __pyx_L15_error) + } + __pyx_v_invacc = (1.0 / __pyx_v_acc); + + /* "mtrand.pyx":4772 + * acc = acc + val_data[i+j] + * invacc = 1/acc + * for j from 0 <= j < k: # <<<<<<<<<<<<<< + * val_data[i+j] = val_data[i+j] * invacc + * i = i + k + */ + __pyx_t_14 = __pyx_v_k; + for (__pyx_v_j = 0; __pyx_v_j < __pyx_t_14; __pyx_v_j++) { + + /* "mtrand.pyx":4773 + * invacc = 1/acc + * for j from 0 <= j < k: + * val_data[i+j] = val_data[i+j] * invacc # <<<<<<<<<<<<<< + * i = i + k + * + */ + (__pyx_v_val_data[(__pyx_v_i + __pyx_v_j)]) = ((__pyx_v_val_data[(__pyx_v_i + __pyx_v_j)]) * __pyx_v_invacc); + } + + /* "mtrand.pyx":4774 + * for j from 0 <= j < k: + * val_data[i+j] = val_data[i+j] * invacc + * i = i + k # <<<<<<<<<<<<<< + * + * return diric + */ + __pyx_v_i = (__pyx_v_i + __pyx_v_k); + } + } + + /* "mtrand.pyx":4764 + * i = 0 + * totsize = PyArray_SIZE(val_arr) + * with self.lock, nogil: # <<<<<<<<<<<<<< + * while i < totsize: + * acc = 0.0 + */ + /*finally:*/ { + /*normal exit:*/{ + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L16; + } + __pyx_L15_error: { + #ifdef WITH_THREAD + __Pyx_FastGIL_Forget(); + Py_BLOCK_THREADS + #endif + goto __pyx_L8_error; + } + __pyx_L16:; + } + } + } + __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + goto __pyx_L13_try_end; + __pyx_L8_error:; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + /*except:*/ { + __Pyx_AddTraceback("mtrand.RandomState.dirichlet", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_3, &__pyx_t_6, &__pyx_t_2) < 0) __PYX_ERR(0, 4764, __pyx_L10_except_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_8 = PyTuple_Pack(3, __pyx_t_3, __pyx_t_6, __pyx_t_2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 4764, __pyx_L10_except_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_8, NULL); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 4764, __pyx_L10_except_error) + __Pyx_GOTREF(__pyx_t_15); + __pyx_t_9 = __Pyx_PyObject_IsTrue(__pyx_t_15); + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + if (__pyx_t_9 < 0) __PYX_ERR(0, 4764, __pyx_L10_except_error) + __pyx_t_16 = ((!(__pyx_t_9 != 0)) != 0); + if (__pyx_t_16) { + __Pyx_GIVEREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_6); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_ErrRestoreWithState(__pyx_t_3, __pyx_t_6, __pyx_t_2); + __pyx_t_3 = 0; __pyx_t_6 = 0; __pyx_t_2 = 0; + __PYX_ERR(0, 4764, __pyx_L10_except_error) + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + goto __pyx_L9_exception_handled; + } + __pyx_L10_except_error:; + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_ExceptionReset(__pyx_t_11, __pyx_t_12, __pyx_t_13); + goto __pyx_L1_error; + __pyx_L9_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_ExceptionReset(__pyx_t_11, __pyx_t_12, __pyx_t_13); + __pyx_L13_try_end:; + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_10) { + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_tuple__176, NULL); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4764, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } + goto __pyx_L7; + } + __pyx_L7:; + } + goto __pyx_L26; + __pyx_L4_error:; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + goto __pyx_L1_error; + __pyx_L26:; + } + + /* "mtrand.pyx":4776 + * i = i + k + * + * return diric # <<<<<<<<<<<<<< + * + * # Shuffling and permutations: + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_diric); + __pyx_r = __pyx_v_diric; + goto __pyx_L0; + + /* "mtrand.pyx":4656 + * return multin + * + * def dirichlet(self, object alpha, size=None): # <<<<<<<<<<<<<< + * """ + * dirichlet(alpha, size=None) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("mtrand.RandomState.dirichlet", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_alpha_arr); + __Pyx_XDECREF((PyObject *)__pyx_v_val_arr); + __Pyx_XDECREF(__pyx_v_shape); + __Pyx_XDECREF(__pyx_v_diric); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4779 + * + * # Shuffling and permutations: + * def shuffle(self, object x): # <<<<<<<<<<<<<< + * """ + * shuffle(x) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_103shuffle(PyObject *__pyx_v_self, PyObject *__pyx_v_x); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_102shuffle[] = "\n shuffle(x)\n\n Modify a sequence in-place by shuffling its contents.\n\n This function only shuffles the array along the first axis of a\n multi-dimensional array. The order of sub-arrays is changed but\n their contents remains the same.\n\n Parameters\n ----------\n x : array_like\n The array or list to be shuffled.\n\n Returns\n -------\n None\n\n Examples\n --------\n >>> arr = np.arange(10)\n >>> np.random.shuffle(arr)\n >>> arr\n [1 7 5 2 9 4 3 6 0 8]\n\n Multi-dimensional arrays are only shuffled along the first axis:\n\n >>> arr = np.arange(9).reshape((3, 3))\n >>> np.random.shuffle(arr)\n >>> arr\n array([[3, 4, 5],\n [6, 7, 8],\n [0, 1, 2]])\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_103shuffle(PyObject *__pyx_v_self, PyObject *__pyx_v_x) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("shuffle (wrapper)", 0); + __pyx_r = __pyx_pf_6mtrand_11RandomState_102shuffle(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), ((PyObject *)__pyx_v_x)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_102shuffle(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_x) { + npy_intp __pyx_v_i; + npy_intp __pyx_v_j; + npy_intp __pyx_v_n; + npy_intp __pyx_v_stride; + npy_intp __pyx_v_itemsize; + char *__pyx_v_x_ptr; + char *__pyx_v_buf_ptr; + PyObject *__pyx_v_buf = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + int __pyx_t_6; + size_t __pyx_t_7; + npy_intp __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + PyObject *__pyx_t_14 = NULL; + PyObject *__pyx_t_15 = NULL; + PyObject *__pyx_t_16 = NULL; + __Pyx_RefNannySetupContext("shuffle", 0); + + /* "mtrand.pyx":4816 + * """ + * cdef: + * npy_intp i, j, n = len(x), stride, itemsize # <<<<<<<<<<<<<< + * char* x_ptr + * char* buf_ptr + */ + __pyx_t_1 = PyObject_Length(__pyx_v_x); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 4816, __pyx_L1_error) + __pyx_v_n = __pyx_t_1; + + /* "mtrand.pyx":4820 + * char* buf_ptr + * + * if type(x) is np.ndarray and x.ndim == 1 and x.size: # <<<<<<<<<<<<<< + * # Fast, statically typed path: shuffle the underlying buffer. + * # Only for non-empty, 1d objects of class ndarray (subclasses such + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4820, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_ndarray); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4820, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_5 = (((PyObject *)Py_TYPE(__pyx_v_x)) == __pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = (__pyx_t_5 != 0); + if (__pyx_t_6) { + } else { + __pyx_t_2 = __pyx_t_6; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_ndim); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4820, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __Pyx_PyInt_EqObjC(__pyx_t_4, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4820, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 4820, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + } else { + __pyx_t_2 = __pyx_t_6; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_size); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4820, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 4820, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_2 = __pyx_t_6; + __pyx_L4_bool_binop_done:; + if (__pyx_t_2) { + + /* "mtrand.pyx":4824 + * # Only for non-empty, 1d objects of class ndarray (subclasses such + * # as MaskedArrays may not support this approach). + * x_ptr = x.ctypes.data # <<<<<<<<<<<<<< + * stride = x.strides[0] + * itemsize = x.dtype.itemsize + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_ctypes); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4824, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_data); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4824, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_7 = __Pyx_PyInt_As_size_t(__pyx_t_4); if (unlikely((__pyx_t_7 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 4824, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_x_ptr = ((char *)((size_t)__pyx_t_7)); + + /* "mtrand.pyx":4825 + * # as MaskedArrays may not support this approach). + * x_ptr = x.ctypes.data + * stride = x.strides[0] # <<<<<<<<<<<<<< + * itemsize = x.dtype.itemsize + * # As the array x could contain python objects we use a buffer + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_strides); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4825, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_4, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4825, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_8 = __Pyx_PyInt_As_npy_intp(__pyx_t_3); if (unlikely((__pyx_t_8 == ((npy_intp)-1)) && PyErr_Occurred())) __PYX_ERR(0, 4825, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_stride = __pyx_t_8; + + /* "mtrand.pyx":4826 + * x_ptr = x.ctypes.data + * stride = x.strides[0] + * itemsize = x.dtype.itemsize # <<<<<<<<<<<<<< + * # As the array x could contain python objects we use a buffer + * # of bytes for the swaps to avoid leaving one of the objects + */ + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_dtype); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4826, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_itemsize); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4826, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_8 = __Pyx_PyInt_As_npy_intp(__pyx_t_4); if (unlikely((__pyx_t_8 == ((npy_intp)-1)) && PyErr_Occurred())) __PYX_ERR(0, 4826, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_itemsize = __pyx_t_8; + + /* "mtrand.pyx":4831 + * # within the buffer and erroneously decrementing it's refcount + * # when the function exits. + * buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit # <<<<<<<<<<<<<< + * buf_ptr = buf.ctypes.data + * with self.lock: + */ + __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyInt_From_npy_intp(__pyx_v_itemsize); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_9 = PyTuple_New(1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_4); + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_int8); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_dtype, __pyx_t_11) < 0) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, __pyx_t_4); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_buf = __pyx_t_11; + __pyx_t_11 = 0; + + /* "mtrand.pyx":4832 + * # when the function exits. + * buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit + * buf_ptr = buf.ctypes.data # <<<<<<<<<<<<<< + * with self.lock: + * # We trick gcc into providing a specialized implementation for + */ + __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_v_buf, __pyx_n_s_ctypes); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4832, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_data); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4832, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __pyx_t_7 = __Pyx_PyInt_As_size_t(__pyx_t_4); if (unlikely((__pyx_t_7 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 4832, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_buf_ptr = ((char *)((size_t)__pyx_t_7)); + + /* "mtrand.pyx":4833 + * buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit + * buf_ptr = buf.ctypes.data + * with self.lock: # <<<<<<<<<<<<<< + * # We trick gcc into providing a specialized implementation for + * # the most common case, yielding a ~33% performance improvement. + */ + /*with:*/ { + __pyx_t_12 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 4833, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __pyx_t_11 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4833, __pyx_L7_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_11))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_11, function); + } + } + if (__pyx_t_9) { + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4833, __pyx_L7_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else { + __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_11); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4833, __pyx_L7_error) + } + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + /*try:*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_13, &__pyx_t_14, &__pyx_t_15); + __Pyx_XGOTREF(__pyx_t_13); + __Pyx_XGOTREF(__pyx_t_14); + __Pyx_XGOTREF(__pyx_t_15); + /*try:*/ { + + /* "mtrand.pyx":4837 + * # the most common case, yielding a ~33% performance improvement. + * # Note that apparently, only one branch can ever be specialized. + * if itemsize == sizeof(npy_intp): # <<<<<<<<<<<<<< + * self._shuffle_raw(n, sizeof(npy_intp), stride, x_ptr, buf_ptr) + * else: + */ + __pyx_t_2 = ((__pyx_v_itemsize == (sizeof(npy_intp))) != 0); + if (__pyx_t_2) { + + /* "mtrand.pyx":4838 + * # Note that apparently, only one branch can ever be specialized. + * if itemsize == sizeof(npy_intp): + * self._shuffle_raw(n, sizeof(npy_intp), stride, x_ptr, buf_ptr) # <<<<<<<<<<<<<< + * else: + * self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) + */ + __pyx_t_4 = __pyx_f_6mtrand_11RandomState__shuffle_raw(__pyx_v_self, __pyx_v_n, (sizeof(npy_intp)), __pyx_v_stride, __pyx_v_x_ptr, __pyx_v_buf_ptr); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4838, __pyx_L11_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "mtrand.pyx":4837 + * # the most common case, yielding a ~33% performance improvement. + * # Note that apparently, only one branch can ever be specialized. + * if itemsize == sizeof(npy_intp): # <<<<<<<<<<<<<< + * self._shuffle_raw(n, sizeof(npy_intp), stride, x_ptr, buf_ptr) + * else: + */ + goto __pyx_L17; + } + + /* "mtrand.pyx":4840 + * self._shuffle_raw(n, sizeof(npy_intp), stride, x_ptr, buf_ptr) + * else: + * self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) # <<<<<<<<<<<<<< + * elif isinstance(x, np.ndarray) and x.ndim > 1 and x.size: + * # Multidimensional ndarrays require a bounce buffer. + */ + /*else*/ { + __pyx_t_4 = __pyx_f_6mtrand_11RandomState__shuffle_raw(__pyx_v_self, __pyx_v_n, __pyx_v_itemsize, __pyx_v_stride, __pyx_v_x_ptr, __pyx_v_buf_ptr); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4840, __pyx_L11_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + __pyx_L17:; + + /* "mtrand.pyx":4833 + * buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit + * buf_ptr = buf.ctypes.data + * with self.lock: # <<<<<<<<<<<<<< + * # We trick gcc into providing a specialized implementation for + * # the most common case, yielding a ~33% performance improvement. + */ + } + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; + goto __pyx_L16_try_end; + __pyx_L11_error:; + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + /*except:*/ { + __Pyx_AddTraceback("mtrand.RandomState.shuffle", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_11, &__pyx_t_9) < 0) __PYX_ERR(0, 4833, __pyx_L13_except_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GOTREF(__pyx_t_11); + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_3 = PyTuple_Pack(3, __pyx_t_4, __pyx_t_11, __pyx_t_9); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4833, __pyx_L13_except_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_16 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_3, NULL); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 4833, __pyx_L13_except_error) + __Pyx_GOTREF(__pyx_t_16); + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_16); + __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; + if (__pyx_t_2 < 0) __PYX_ERR(0, 4833, __pyx_L13_except_error) + __pyx_t_6 = ((!(__pyx_t_2 != 0)) != 0); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_11); + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_ErrRestoreWithState(__pyx_t_4, __pyx_t_11, __pyx_t_9); + __pyx_t_4 = 0; __pyx_t_11 = 0; __pyx_t_9 = 0; + __PYX_ERR(0, 4833, __pyx_L13_except_error) + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L12_exception_handled; + } + __pyx_L13_except_error:; + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_XGIVEREF(__pyx_t_15); + __Pyx_ExceptionReset(__pyx_t_13, __pyx_t_14, __pyx_t_15); + goto __pyx_L1_error; + __pyx_L12_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_XGIVEREF(__pyx_t_15); + __Pyx_ExceptionReset(__pyx_t_13, __pyx_t_14, __pyx_t_15); + __pyx_L16_try_end:; + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_12) { + __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_tuple__177, NULL); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 4833, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_15); + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + } + goto __pyx_L10; + } + __pyx_L10:; + } + goto __pyx_L21; + __pyx_L7_error:; + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + goto __pyx_L1_error; + __pyx_L21:; + } + + /* "mtrand.pyx":4820 + * char* buf_ptr + * + * if type(x) is np.ndarray and x.ndim == 1 and x.size: # <<<<<<<<<<<<<< + * # Fast, statically typed path: shuffle the underlying buffer. + * # Only for non-empty, 1d objects of class ndarray (subclasses such + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":4841 + * else: + * self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) + * elif isinstance(x, np.ndarray) and x.ndim > 1 and x.size: # <<<<<<<<<<<<<< + * # Multidimensional ndarrays require a bounce buffer. + * buf = np.empty_like(x[0]) + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4841, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_ndarray); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4841, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_2 = PyObject_IsInstance(__pyx_v_x, __pyx_t_11); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(0, 4841, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __pyx_t_5 = (__pyx_t_2 != 0); + if (__pyx_t_5) { + } else { + __pyx_t_6 = __pyx_t_5; + goto __pyx_L22_bool_binop_done; + } + __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_ndim); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4841, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_9 = PyObject_RichCompare(__pyx_t_11, __pyx_int_1, Py_GT); __Pyx_XGOTREF(__pyx_t_9); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4841, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_9); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 4841, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (__pyx_t_5) { + } else { + __pyx_t_6 = __pyx_t_5; + goto __pyx_L22_bool_binop_done; + } + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_size); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4841, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_9); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 4841, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_6 = __pyx_t_5; + __pyx_L22_bool_binop_done:; + if (__pyx_t_6) { + + /* "mtrand.pyx":4843 + * elif isinstance(x, np.ndarray) and x.ndim > 1 and x.size: + * # Multidimensional ndarrays require a bounce buffer. + * buf = np.empty_like(x[0]) # <<<<<<<<<<<<<< + * with self.lock: + * for i in reversed(range(1, n)): + */ + __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4843, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_empty_like); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4843, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __pyx_t_11 = __Pyx_GetItemInt(__pyx_v_x, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4843, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (!__pyx_t_3) { + __pyx_t_9 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_11); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4843, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_GOTREF(__pyx_t_9); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_t_11}; + __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4843, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_t_11}; + __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4843, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4843, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_3); __pyx_t_3 = NULL; + __Pyx_GIVEREF(__pyx_t_11); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_11); + __pyx_t_11 = 0; + __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_10, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4843, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_buf = __pyx_t_9; + __pyx_t_9 = 0; + + /* "mtrand.pyx":4844 + * # Multidimensional ndarrays require a bounce buffer. + * buf = np.empty_like(x[0]) + * with self.lock: # <<<<<<<<<<<<<< + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + */ + /*with:*/ { + __pyx_t_12 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 4844, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4844, __pyx_L25_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_10 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_10)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_10); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_10) { + __pyx_t_9 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_10); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4844, __pyx_L25_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } else { + __pyx_t_9 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4844, __pyx_L25_error) + } + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + /*try:*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_15, &__pyx_t_14, &__pyx_t_13); + __Pyx_XGOTREF(__pyx_t_15); + __Pyx_XGOTREF(__pyx_t_14); + __Pyx_XGOTREF(__pyx_t_13); + /*try:*/ { + + /* "mtrand.pyx":4845 + * buf = np.empty_like(x[0]) + * with self.lock: + * for i in reversed(range(1, n)): # <<<<<<<<<<<<<< + * j = rk_interval(i, self.internal_state) + * buf[...] = x[j] + */ + for (__pyx_t_8 = __pyx_v_n-1; __pyx_t_8 >= 1; __pyx_t_8-=1) { + __pyx_v_i = __pyx_t_8; + + /* "mtrand.pyx":4846 + * with self.lock: + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) # <<<<<<<<<<<<<< + * buf[...] = x[j] + * x[j] = x[i] + */ + __pyx_v_j = rk_interval(__pyx_v_i, __pyx_v_self->internal_state); + + /* "mtrand.pyx":4847 + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + * buf[...] = x[j] # <<<<<<<<<<<<<< + * x[j] = x[i] + * x[i] = buf + */ + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_x, __pyx_v_j, npy_intp, 1, __Pyx_PyInt_From_npy_intp, 0, 1, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4847, __pyx_L29_error) + __Pyx_GOTREF(__pyx_t_9); + if (unlikely(PyObject_SetItem(__pyx_v_buf, Py_Ellipsis, __pyx_t_9) < 0)) __PYX_ERR(0, 4847, __pyx_L29_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4848 + * j = rk_interval(i, self.internal_state) + * buf[...] = x[j] + * x[j] = x[i] # <<<<<<<<<<<<<< + * x[i] = buf + * else: + */ + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_x, __pyx_v_i, npy_intp, 1, __Pyx_PyInt_From_npy_intp, 0, 1, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4848, __pyx_L29_error) + __Pyx_GOTREF(__pyx_t_9); + if (unlikely(__Pyx_SetItemInt(__pyx_v_x, __pyx_v_j, __pyx_t_9, npy_intp, 1, __Pyx_PyInt_From_npy_intp, 0, 1, 1) < 0)) __PYX_ERR(0, 4848, __pyx_L29_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4849 + * buf[...] = x[j] + * x[j] = x[i] + * x[i] = buf # <<<<<<<<<<<<<< + * else: + * # Untyped path. + */ + if (unlikely(__Pyx_SetItemInt(__pyx_v_x, __pyx_v_i, __pyx_v_buf, npy_intp, 1, __Pyx_PyInt_From_npy_intp, 0, 1, 1) < 0)) __PYX_ERR(0, 4849, __pyx_L29_error) + } + + /* "mtrand.pyx":4844 + * # Multidimensional ndarrays require a bounce buffer. + * buf = np.empty_like(x[0]) + * with self.lock: # <<<<<<<<<<<<<< + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + */ + } + __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + goto __pyx_L34_try_end; + __pyx_L29_error:; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + /*except:*/ { + __Pyx_AddTraceback("mtrand.RandomState.shuffle", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_9, &__pyx_t_4, &__pyx_t_10) < 0) __PYX_ERR(0, 4844, __pyx_L31_except_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_11 = PyTuple_Pack(3, __pyx_t_9, __pyx_t_4, __pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4844, __pyx_L31_except_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_16 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_11, NULL); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 4844, __pyx_L31_except_error) + __Pyx_GOTREF(__pyx_t_16); + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_16); + __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; + if (__pyx_t_6 < 0) __PYX_ERR(0, 4844, __pyx_L31_except_error) + __pyx_t_5 = ((!(__pyx_t_6 != 0)) != 0); + if (__pyx_t_5) { + __Pyx_GIVEREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_ErrRestoreWithState(__pyx_t_9, __pyx_t_4, __pyx_t_10); + __pyx_t_9 = 0; __pyx_t_4 = 0; __pyx_t_10 = 0; + __PYX_ERR(0, 4844, __pyx_L31_except_error) + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + goto __pyx_L30_exception_handled; + } + __pyx_L31_except_error:; + __Pyx_XGIVEREF(__pyx_t_15); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_ExceptionReset(__pyx_t_15, __pyx_t_14, __pyx_t_13); + goto __pyx_L1_error; + __pyx_L30_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_15); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_ExceptionReset(__pyx_t_15, __pyx_t_14, __pyx_t_13); + __pyx_L34_try_end:; + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_12) { + __pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_tuple__178, NULL); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 4844, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + } + goto __pyx_L28; + } + __pyx_L28:; + } + goto __pyx_L40; + __pyx_L25_error:; + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + goto __pyx_L1_error; + __pyx_L40:; + } + + /* "mtrand.pyx":4841 + * else: + * self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) + * elif isinstance(x, np.ndarray) and x.ndim > 1 and x.size: # <<<<<<<<<<<<<< + * # Multidimensional ndarrays require a bounce buffer. + * buf = np.empty_like(x[0]) + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":4852 + * else: + * # Untyped path. + * with self.lock: # <<<<<<<<<<<<<< + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + */ + /*else*/ { + /*with:*/ { + __pyx_t_12 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_exit); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 4852, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_v_self->lock, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4852, __pyx_L41_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_9 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_9)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_9); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + } + } + if (__pyx_t_9) { + __pyx_t_10 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4852, __pyx_L41_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else { + __pyx_t_10 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4852, __pyx_L41_error) + } + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + /*try:*/ { + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_13, &__pyx_t_14, &__pyx_t_15); + __Pyx_XGOTREF(__pyx_t_13); + __Pyx_XGOTREF(__pyx_t_14); + __Pyx_XGOTREF(__pyx_t_15); + /*try:*/ { + + /* "mtrand.pyx":4853 + * # Untyped path. + * with self.lock: + * for i in reversed(range(1, n)): # <<<<<<<<<<<<<< + * j = rk_interval(i, self.internal_state) + * x[i], x[j] = x[j], x[i] + */ + for (__pyx_t_8 = __pyx_v_n-1; __pyx_t_8 >= 1; __pyx_t_8-=1) { + __pyx_v_i = __pyx_t_8; + + /* "mtrand.pyx":4854 + * with self.lock: + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) # <<<<<<<<<<<<<< + * x[i], x[j] = x[j], x[i] + * + */ + __pyx_v_j = rk_interval(__pyx_v_i, __pyx_v_self->internal_state); + + /* "mtrand.pyx":4855 + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + * x[i], x[j] = x[j], x[i] # <<<<<<<<<<<<<< + * + * cdef inline _shuffle_raw(self, npy_intp n, npy_intp itemsize, + */ + __pyx_t_10 = __Pyx_GetItemInt(__pyx_v_x, __pyx_v_j, npy_intp, 1, __Pyx_PyInt_From_npy_intp, 0, 1, 1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 4855, __pyx_L45_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_x, __pyx_v_i, npy_intp, 1, __Pyx_PyInt_From_npy_intp, 0, 1, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4855, __pyx_L45_error) + __Pyx_GOTREF(__pyx_t_4); + if (unlikely(__Pyx_SetItemInt(__pyx_v_x, __pyx_v_i, __pyx_t_10, npy_intp, 1, __Pyx_PyInt_From_npy_intp, 0, 1, 1) < 0)) __PYX_ERR(0, 4855, __pyx_L45_error) + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + if (unlikely(__Pyx_SetItemInt(__pyx_v_x, __pyx_v_j, __pyx_t_4, npy_intp, 1, __Pyx_PyInt_From_npy_intp, 0, 1, 1) < 0)) __PYX_ERR(0, 4855, __pyx_L45_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + } + + /* "mtrand.pyx":4852 + * else: + * # Untyped path. + * with self.lock: # <<<<<<<<<<<<<< + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + */ + } + __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; + goto __pyx_L50_try_end; + __pyx_L45_error:; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; + __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + /*except:*/ { + __Pyx_AddTraceback("mtrand.RandomState.shuffle", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_10, &__pyx_t_9) < 0) __PYX_ERR(0, 4852, __pyx_L47_except_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_11 = PyTuple_Pack(3, __pyx_t_4, __pyx_t_10, __pyx_t_9); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 4852, __pyx_L47_except_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_16 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_t_11, NULL); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 4852, __pyx_L47_except_error) + __Pyx_GOTREF(__pyx_t_16); + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_16); + __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; + if (__pyx_t_5 < 0) __PYX_ERR(0, 4852, __pyx_L47_except_error) + __pyx_t_6 = ((!(__pyx_t_5 != 0)) != 0); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_ErrRestoreWithState(__pyx_t_4, __pyx_t_10, __pyx_t_9); + __pyx_t_4 = 0; __pyx_t_10 = 0; __pyx_t_9 = 0; + __PYX_ERR(0, 4852, __pyx_L47_except_error) + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + goto __pyx_L46_exception_handled; + } + __pyx_L47_except_error:; + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_XGIVEREF(__pyx_t_15); + __Pyx_ExceptionReset(__pyx_t_13, __pyx_t_14, __pyx_t_15); + goto __pyx_L1_error; + __pyx_L46_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_XGIVEREF(__pyx_t_15); + __Pyx_ExceptionReset(__pyx_t_13, __pyx_t_14, __pyx_t_15); + __pyx_L50_try_end:; + } + } + /*finally:*/ { + /*normal exit:*/{ + if (__pyx_t_12) { + __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_12, __pyx_tuple__179, NULL); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 4852, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_15); + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + } + goto __pyx_L44; + } + __pyx_L44:; + } + goto __pyx_L56; + __pyx_L41_error:; + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + goto __pyx_L1_error; + __pyx_L56:; + } + } + __pyx_L3:; + + /* "mtrand.pyx":4779 + * + * # Shuffling and permutations: + * def shuffle(self, object x): # <<<<<<<<<<<<<< + * """ + * shuffle(x) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_AddTraceback("mtrand.RandomState.shuffle", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_buf); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4857 + * x[i], x[j] = x[j], x[i] + * + * cdef inline _shuffle_raw(self, npy_intp n, npy_intp itemsize, # <<<<<<<<<<<<<< + * npy_intp stride, char* data, char* buf): + * cdef npy_intp i, j + */ + +static CYTHON_INLINE PyObject *__pyx_f_6mtrand_11RandomState__shuffle_raw(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, npy_intp __pyx_v_n, npy_intp __pyx_v_itemsize, npy_intp __pyx_v_stride, char *__pyx_v_data, char *__pyx_v_buf) { + npy_intp __pyx_v_i; + npy_intp __pyx_v_j; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + npy_intp __pyx_t_1; + int __pyx_t_2; + __Pyx_RefNannySetupContext("_shuffle_raw", 0); + + /* "mtrand.pyx":4860 + * npy_intp stride, char* data, char* buf): + * cdef npy_intp i, j + * for i in reversed(range(1, n)): # <<<<<<<<<<<<<< + * j = rk_interval(i, self.internal_state) + * if i == j : continue # i == j is not needed and memcpy is undefined. + */ + for (__pyx_t_1 = __pyx_v_n-1; __pyx_t_1 >= 1; __pyx_t_1-=1) { + __pyx_v_i = __pyx_t_1; + + /* "mtrand.pyx":4861 + * cdef npy_intp i, j + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) # <<<<<<<<<<<<<< + * if i == j : continue # i == j is not needed and memcpy is undefined. + * string.memcpy(buf, data + j * stride, itemsize) + */ + __pyx_v_j = rk_interval(__pyx_v_i, __pyx_v_self->internal_state); + + /* "mtrand.pyx":4862 + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + * if i == j : continue # i == j is not needed and memcpy is undefined. # <<<<<<<<<<<<<< + * string.memcpy(buf, data + j * stride, itemsize) + * string.memcpy(data + j * stride, data + i * stride, itemsize) + */ + __pyx_t_2 = ((__pyx_v_i == __pyx_v_j) != 0); + if (__pyx_t_2) { + goto __pyx_L3_continue; + } + + /* "mtrand.pyx":4863 + * j = rk_interval(i, self.internal_state) + * if i == j : continue # i == j is not needed and memcpy is undefined. + * string.memcpy(buf, data + j * stride, itemsize) # <<<<<<<<<<<<<< + * string.memcpy(data + j * stride, data + i * stride, itemsize) + * string.memcpy(data + i * stride, buf, itemsize) + */ + (void)(memcpy(__pyx_v_buf, (__pyx_v_data + (__pyx_v_j * __pyx_v_stride)), __pyx_v_itemsize)); + + /* "mtrand.pyx":4864 + * if i == j : continue # i == j is not needed and memcpy is undefined. + * string.memcpy(buf, data + j * stride, itemsize) + * string.memcpy(data + j * stride, data + i * stride, itemsize) # <<<<<<<<<<<<<< + * string.memcpy(data + i * stride, buf, itemsize) + * + */ + (void)(memcpy((__pyx_v_data + (__pyx_v_j * __pyx_v_stride)), (__pyx_v_data + (__pyx_v_i * __pyx_v_stride)), __pyx_v_itemsize)); + + /* "mtrand.pyx":4865 + * string.memcpy(buf, data + j * stride, itemsize) + * string.memcpy(data + j * stride, data + i * stride, itemsize) + * string.memcpy(data + i * stride, buf, itemsize) # <<<<<<<<<<<<<< + * + * def permutation(self, object x): + */ + (void)(memcpy((__pyx_v_data + (__pyx_v_i * __pyx_v_stride)), __pyx_v_buf, __pyx_v_itemsize)); + __pyx_L3_continue:; + } + + /* "mtrand.pyx":4857 + * x[i], x[j] = x[j], x[i] + * + * cdef inline _shuffle_raw(self, npy_intp n, npy_intp itemsize, # <<<<<<<<<<<<<< + * npy_intp stride, char* data, char* buf): + * cdef npy_intp i, j + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mtrand.pyx":4867 + * string.memcpy(data + i * stride, buf, itemsize) + * + * def permutation(self, object x): # <<<<<<<<<<<<<< + * """ + * permutation(x) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6mtrand_11RandomState_105permutation(PyObject *__pyx_v_self, PyObject *__pyx_v_x); /*proto*/ +static char __pyx_doc_6mtrand_11RandomState_104permutation[] = "\n permutation(x)\n\n Randomly permute a sequence, or return a permuted range.\n\n If `x` is a multi-dimensional array, it is only shuffled along its\n first index.\n\n Parameters\n ----------\n x : int or array_like\n If `x` is an integer, randomly permute ``np.arange(x)``.\n If `x` is an array, make a copy and shuffle the elements\n randomly.\n\n Returns\n -------\n out : ndarray\n Permuted sequence or array range.\n\n Examples\n --------\n >>> np.random.permutation(10)\n array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6])\n\n >>> np.random.permutation([1, 4, 9, 12, 15])\n array([15, 1, 9, 4, 12])\n\n >>> arr = np.arange(9).reshape((3, 3))\n >>> np.random.permutation(arr)\n array([[6, 7, 8],\n [0, 1, 2],\n [3, 4, 5]])\n\n "; +static PyObject *__pyx_pw_6mtrand_11RandomState_105permutation(PyObject *__pyx_v_self, PyObject *__pyx_v_x) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("permutation (wrapper)", 0); + __pyx_r = __pyx_pf_6mtrand_11RandomState_104permutation(((struct __pyx_obj_6mtrand_RandomState *)__pyx_v_self), ((PyObject *)__pyx_v_x)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6mtrand_11RandomState_104permutation(struct __pyx_obj_6mtrand_RandomState *__pyx_v_self, PyObject *__pyx_v_x) { + PyObject *__pyx_v_arr = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + __Pyx_RefNannySetupContext("permutation", 0); + + /* "mtrand.pyx":4903 + * + * """ + * if isinstance(x, (int, long, np.integer)): # <<<<<<<<<<<<<< + * arr = np.arange(x) + * else: + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4903, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_integer); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4903, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_4 = PyInt_Check(__pyx_v_x); + __pyx_t_5 = (__pyx_t_4 != 0); + if (!__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_5 = PyLong_Check(__pyx_v_x); + __pyx_t_4 = (__pyx_t_5 != 0); + if (!__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_4 = PyObject_IsInstance(__pyx_v_x, __pyx_t_2); + __pyx_t_5 = (__pyx_t_4 != 0); + __pyx_t_3 = __pyx_t_5; + __pyx_L4_bool_binop_done:; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_5 = (__pyx_t_3 != 0); + if (__pyx_t_5) { + + /* "mtrand.pyx":4904 + * """ + * if isinstance(x, (int, long, np.integer)): + * arr = np.arange(x) # <<<<<<<<<<<<<< + * else: + * arr = np.array(x) + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4904, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_arange); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4904, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_6); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_6, function); + } + } + if (!__pyx_t_1) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_v_x); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4904, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_v_x}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4904, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_v_x}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4904, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4904, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_1); __pyx_t_1 = NULL; + __Pyx_INCREF(__pyx_v_x); + __Pyx_GIVEREF(__pyx_v_x); + PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_v_x); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_7, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4904, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } + } + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_v_arr = __pyx_t_2; + __pyx_t_2 = 0; + + /* "mtrand.pyx":4903 + * + * """ + * if isinstance(x, (int, long, np.integer)): # <<<<<<<<<<<<<< + * arr = np.arange(x) + * else: + */ + goto __pyx_L3; + } + + /* "mtrand.pyx":4906 + * arr = np.arange(x) + * else: + * arr = np.array(x) # <<<<<<<<<<<<<< + * self.shuffle(arr) + * return arr + */ + /*else*/ { + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4906, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_array); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4906, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_6) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_x); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4906, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_v_x}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4906, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_v_x}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4906, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4906, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_6); __pyx_t_6 = NULL; + __Pyx_INCREF(__pyx_v_x); + __Pyx_GIVEREF(__pyx_v_x); + PyTuple_SET_ITEM(__pyx_t_1, 0+1, __pyx_v_x); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4906, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_v_arr = __pyx_t_2; + __pyx_t_2 = 0; + } + __pyx_L3:; + + /* "mtrand.pyx":4907 + * else: + * arr = np.array(x) + * self.shuffle(arr) # <<<<<<<<<<<<<< + * return arr + * + */ + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_shuffle); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + if (!__pyx_t_1) { + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_arr); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_v_arr}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4907, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_v_arr}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4907, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_2); + } else + #endif + { + __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 4907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_1); __pyx_t_1 = NULL; + __Pyx_INCREF(__pyx_v_arr); + __Pyx_GIVEREF(__pyx_v_arr); + PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_arr); + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_6, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4907, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + + /* "mtrand.pyx":4908 + * arr = np.array(x) + * self.shuffle(arr) + * return arr # <<<<<<<<<<<<<< + * + * _rand = RandomState() + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_arr); + __pyx_r = __pyx_v_arr; + goto __pyx_L0; + + /* "mtrand.pyx":4867 + * string.memcpy(data + i * stride, buf, itemsize) + * + * def permutation(self, object x): # <<<<<<<<<<<<<< + * """ + * permutation(x) + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("mtrand.RandomState.permutation", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_arr); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} +static struct __pyx_vtabstruct_6mtrand_RandomState __pyx_vtable_6mtrand_RandomState; + +static PyObject *__pyx_tp_new_6mtrand_RandomState(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + struct __pyx_obj_6mtrand_RandomState *p; + PyObject *o; + if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + p = ((struct __pyx_obj_6mtrand_RandomState *)o); + p->__pyx_vtab = __pyx_vtabptr_6mtrand_RandomState; + p->lock = Py_None; Py_INCREF(Py_None); + p->state_address = Py_None; Py_INCREF(Py_None); + return o; +} + +static void __pyx_tp_dealloc_6mtrand_RandomState(PyObject *o) { + struct __pyx_obj_6mtrand_RandomState *p = (struct __pyx_obj_6mtrand_RandomState *)o; + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && !_PyGC_FINALIZED(o)) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + PyObject_GC_UnTrack(o); + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + ++Py_REFCNT(o); + __pyx_pw_6mtrand_11RandomState_3__dealloc__(o); + --Py_REFCNT(o); + PyErr_Restore(etype, eval, etb); + } + Py_CLEAR(p->lock); + Py_CLEAR(p->state_address); + (*Py_TYPE(o)->tp_free)(o); +} + +static int __pyx_tp_traverse_6mtrand_RandomState(PyObject *o, visitproc v, void *a) { + int e; + struct __pyx_obj_6mtrand_RandomState *p = (struct __pyx_obj_6mtrand_RandomState *)o; + if (p->lock) { + e = (*v)(p->lock, a); if (e) return e; + } + if (p->state_address) { + e = (*v)(p->state_address, a); if (e) return e; + } + return 0; +} + +static int __pyx_tp_clear_6mtrand_RandomState(PyObject *o) { + PyObject* tmp; + struct __pyx_obj_6mtrand_RandomState *p = (struct __pyx_obj_6mtrand_RandomState *)o; + tmp = ((PyObject*)p->lock); + p->lock = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + tmp = ((PyObject*)p->state_address); + p->state_address = Py_None; Py_INCREF(Py_None); + Py_XDECREF(tmp); + return 0; +} + +static PyMethodDef __pyx_methods_6mtrand_RandomState[] = { + {"seed", (PyCFunction)__pyx_pw_6mtrand_11RandomState_5seed, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_4seed}, + {"get_state", (PyCFunction)__pyx_pw_6mtrand_11RandomState_7get_state, METH_NOARGS, __pyx_doc_6mtrand_11RandomState_6get_state}, + {"set_state", (PyCFunction)__pyx_pw_6mtrand_11RandomState_9set_state, METH_O, __pyx_doc_6mtrand_11RandomState_8set_state}, + {"__getstate__", (PyCFunction)__pyx_pw_6mtrand_11RandomState_11__getstate__, METH_NOARGS, 0}, + {"__setstate__", (PyCFunction)__pyx_pw_6mtrand_11RandomState_13__setstate__, METH_O, 0}, + {"__reduce__", (PyCFunction)__pyx_pw_6mtrand_11RandomState_15__reduce__, METH_NOARGS, 0}, + {"random_sample", (PyCFunction)__pyx_pw_6mtrand_11RandomState_17random_sample, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_16random_sample}, + {"tomaxint", (PyCFunction)__pyx_pw_6mtrand_11RandomState_19tomaxint, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_18tomaxint}, + {"randint", (PyCFunction)__pyx_pw_6mtrand_11RandomState_21randint, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_20randint}, + {"bytes", (PyCFunction)__pyx_pw_6mtrand_11RandomState_23bytes, METH_O, __pyx_doc_6mtrand_11RandomState_22bytes}, + {"choice", (PyCFunction)__pyx_pw_6mtrand_11RandomState_25choice, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_24choice}, + {"uniform", (PyCFunction)__pyx_pw_6mtrand_11RandomState_27uniform, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_26uniform}, + {"rand", (PyCFunction)__pyx_pw_6mtrand_11RandomState_29rand, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_28rand}, + {"randn", (PyCFunction)__pyx_pw_6mtrand_11RandomState_31randn, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_30randn}, + {"random_integers", (PyCFunction)__pyx_pw_6mtrand_11RandomState_33random_integers, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_32random_integers}, + {"standard_normal", (PyCFunction)__pyx_pw_6mtrand_11RandomState_35standard_normal, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_34standard_normal}, + {"normal", (PyCFunction)__pyx_pw_6mtrand_11RandomState_37normal, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_36normal}, + {"beta", (PyCFunction)__pyx_pw_6mtrand_11RandomState_39beta, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_38beta}, + {"exponential", (PyCFunction)__pyx_pw_6mtrand_11RandomState_41exponential, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_40exponential}, + {"standard_exponential", (PyCFunction)__pyx_pw_6mtrand_11RandomState_43standard_exponential, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_42standard_exponential}, + {"standard_gamma", (PyCFunction)__pyx_pw_6mtrand_11RandomState_45standard_gamma, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_44standard_gamma}, + {"gamma", (PyCFunction)__pyx_pw_6mtrand_11RandomState_47gamma, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_46gamma}, + {"f", (PyCFunction)__pyx_pw_6mtrand_11RandomState_49f, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_48f}, + {"noncentral_f", (PyCFunction)__pyx_pw_6mtrand_11RandomState_51noncentral_f, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_50noncentral_f}, + {"chisquare", (PyCFunction)__pyx_pw_6mtrand_11RandomState_53chisquare, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_52chisquare}, + {"noncentral_chisquare", (PyCFunction)__pyx_pw_6mtrand_11RandomState_55noncentral_chisquare, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_54noncentral_chisquare}, + {"standard_cauchy", (PyCFunction)__pyx_pw_6mtrand_11RandomState_57standard_cauchy, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_56standard_cauchy}, + {"standard_t", (PyCFunction)__pyx_pw_6mtrand_11RandomState_59standard_t, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_58standard_t}, + {"vonmises", (PyCFunction)__pyx_pw_6mtrand_11RandomState_61vonmises, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_60vonmises}, + {"pareto", (PyCFunction)__pyx_pw_6mtrand_11RandomState_63pareto, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_62pareto}, + {"weibull", (PyCFunction)__pyx_pw_6mtrand_11RandomState_65weibull, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_64weibull}, + {"power", (PyCFunction)__pyx_pw_6mtrand_11RandomState_67power, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_66power}, + {"laplace", (PyCFunction)__pyx_pw_6mtrand_11RandomState_69laplace, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_68laplace}, + {"gumbel", (PyCFunction)__pyx_pw_6mtrand_11RandomState_71gumbel, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_70gumbel}, + {"logistic", (PyCFunction)__pyx_pw_6mtrand_11RandomState_73logistic, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_72logistic}, + {"lognormal", (PyCFunction)__pyx_pw_6mtrand_11RandomState_75lognormal, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_74lognormal}, + {"rayleigh", (PyCFunction)__pyx_pw_6mtrand_11RandomState_77rayleigh, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_76rayleigh}, + {"wald", (PyCFunction)__pyx_pw_6mtrand_11RandomState_79wald, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_78wald}, + {"triangular", (PyCFunction)__pyx_pw_6mtrand_11RandomState_81triangular, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_80triangular}, + {"binomial", (PyCFunction)__pyx_pw_6mtrand_11RandomState_83binomial, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_82binomial}, + {"negative_binomial", (PyCFunction)__pyx_pw_6mtrand_11RandomState_85negative_binomial, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_84negative_binomial}, + {"poisson", (PyCFunction)__pyx_pw_6mtrand_11RandomState_87poisson, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_86poisson}, + {"zipf", (PyCFunction)__pyx_pw_6mtrand_11RandomState_89zipf, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_88zipf}, + {"geometric", (PyCFunction)__pyx_pw_6mtrand_11RandomState_91geometric, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_90geometric}, + {"hypergeometric", (PyCFunction)__pyx_pw_6mtrand_11RandomState_93hypergeometric, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_92hypergeometric}, + {"logseries", (PyCFunction)__pyx_pw_6mtrand_11RandomState_95logseries, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_94logseries}, + {"multivariate_normal", (PyCFunction)__pyx_pw_6mtrand_11RandomState_97multivariate_normal, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_96multivariate_normal}, + {"multinomial", (PyCFunction)__pyx_pw_6mtrand_11RandomState_99multinomial, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_98multinomial}, + {"dirichlet", (PyCFunction)__pyx_pw_6mtrand_11RandomState_101dirichlet, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6mtrand_11RandomState_100dirichlet}, + {"shuffle", (PyCFunction)__pyx_pw_6mtrand_11RandomState_103shuffle, METH_O, __pyx_doc_6mtrand_11RandomState_102shuffle}, + {"permutation", (PyCFunction)__pyx_pw_6mtrand_11RandomState_105permutation, METH_O, __pyx_doc_6mtrand_11RandomState_104permutation}, + {0, 0, 0, 0} +}; + +static PyTypeObject __pyx_type_6mtrand_RandomState = { + PyVarObject_HEAD_INIT(0, 0) + "mtrand.RandomState", /*tp_name*/ + sizeof(struct __pyx_obj_6mtrand_RandomState), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_6mtrand_RandomState, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + "\n RandomState(seed=None)\n\n Container for the Mersenne Twister pseudo-random number generator.\n\n `RandomState` exposes a number of methods for generating random numbers\n drawn from a variety of probability distributions. In addition to the\n distribution-specific arguments, each method takes a keyword argument\n `size` that defaults to ``None``. If `size` is ``None``, then a single\n value is generated and returned. If `size` is an integer, then a 1-D\n array filled with generated values is returned. If `size` is a tuple,\n then an array with that shape is filled and returned.\n\n *Compatibility Guarantee*\n A fixed seed and a fixed series of calls to 'RandomState' methods using\n the same parameters will always produce the same results up to roundoff\n error except when the values were incorrect. Incorrect values will be\n fixed and the NumPy version in which the fix was made will be noted in\n the relevant docstring. Extension of existing parameter ranges and the\n addition of new parameters is allowed as long the previous behavior\n remains unchanged.\n\n Parameters\n ----------\n seed : {None, int, array_like}, optional\n Random seed used to initialize the pseudo-random number generator. Can\n be any integer between 0 and 2**32 - 1 inclusive, an array (or other\n sequence) of such integers, or ``None`` (the default). If `seed` is\n ``None``, then `RandomState` will try to read data from\n ``/dev/urandom`` (or the Windows analogue) if available or seed from\n the clock otherwise.\n\n Notes\n -----\n The Python stdlib module \"random\" also contains a Mersenne Twister\n pseudo-random number generator with a number of methods that are similar\n to the ones available in `RandomState`. `RandomState`, besides being\n NumPy-aware, has the advantage that it provides a much larger number\n of probability distributions to choose from.\n\n ", /*tp_doc*/ + __pyx_tp_traverse_6mtrand_RandomState, /*tp_traverse*/ + __pyx_tp_clear_6mtrand_RandomState, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_6mtrand_RandomState, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + __pyx_pw_6mtrand_11RandomState_1__init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_6mtrand_RandomState, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif +}; + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_mtrand(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_mtrand}, + {0, NULL} +}; +#endif + +static struct PyModuleDef __pyx_moduledef = { + PyModuleDef_HEAD_INIT, + "mtrand", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; +#endif + +static __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_kp_s_Cannot_take_a_larger_sample_than, __pyx_k_Cannot_take_a_larger_sample_than, sizeof(__pyx_k_Cannot_take_a_larger_sample_than), 0, 0, 1, 0}, + {&__pyx_n_s_DeprecationWarning, __pyx_k_DeprecationWarning, sizeof(__pyx_k_DeprecationWarning), 0, 0, 1, 1}, + {&__pyx_kp_s_Fewer_non_zero_entries_in_p_than, __pyx_k_Fewer_non_zero_entries_in_p_than, sizeof(__pyx_k_Fewer_non_zero_entries_in_p_than), 0, 0, 1, 0}, + {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, + {&__pyx_n_s_L, __pyx_k_L, sizeof(__pyx_k_L), 0, 0, 1, 1}, + {&__pyx_n_s_Lock, __pyx_k_Lock, sizeof(__pyx_k_Lock), 0, 0, 1, 1}, + {&__pyx_n_s_MT19937, __pyx_k_MT19937, sizeof(__pyx_k_MT19937), 0, 0, 1, 1}, + {&__pyx_n_s_OverflowError, __pyx_k_OverflowError, sizeof(__pyx_k_OverflowError), 0, 0, 1, 1}, + {&__pyx_kp_u_RandomState_binomial_line_3697, __pyx_k_RandomState_binomial_line_3697, sizeof(__pyx_k_RandomState_binomial_line_3697), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_bytes_line_1004, __pyx_k_RandomState_bytes_line_1004, sizeof(__pyx_k_RandomState_bytes_line_1004), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_chisquare_line_2205, __pyx_k_RandomState_chisquare_line_2205, sizeof(__pyx_k_RandomState_chisquare_line_2205), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_choice_line_1033, __pyx_k_RandomState_choice_line_1033, sizeof(__pyx_k_RandomState_choice_line_1033), 0, 1, 0, 0}, + {&__pyx_n_s_RandomState_ctor, __pyx_k_RandomState_ctor, sizeof(__pyx_k_RandomState_ctor), 0, 0, 1, 1}, + {&__pyx_kp_u_RandomState_dirichlet_line_4656, __pyx_k_RandomState_dirichlet_line_4656, sizeof(__pyx_k_RandomState_dirichlet_line_4656), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_f_line_1997, __pyx_k_RandomState_f_line_1997, sizeof(__pyx_k_RandomState_f_line_1997), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_gamma_line_1901, __pyx_k_RandomState_gamma_line_1901, sizeof(__pyx_k_RandomState_gamma_line_1901), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_geometric_line_4095, __pyx_k_RandomState_geometric_line_4095, sizeof(__pyx_k_RandomState_geometric_line_4095), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_gumbel_line_3089, __pyx_k_RandomState_gumbel_line_3089, sizeof(__pyx_k_RandomState_gumbel_line_3089), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_hypergeometric_line, __pyx_k_RandomState_hypergeometric_line, sizeof(__pyx_k_RandomState_hypergeometric_line), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_laplace_line_2991, __pyx_k_RandomState_laplace_line_2991, sizeof(__pyx_k_RandomState_laplace_line_2991), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_logistic_line_3220, __pyx_k_RandomState_logistic_line_3220, sizeof(__pyx_k_RandomState_logistic_line_3220), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_lognormal_line_3313, __pyx_k_RandomState_lognormal_line_3313, sizeof(__pyx_k_RandomState_lognormal_line_3313), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_logseries_line_4285, __pyx_k_RandomState_logseries_line_4285, sizeof(__pyx_k_RandomState_logseries_line_4285), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_multinomial_line_454, __pyx_k_RandomState_multinomial_line_454, sizeof(__pyx_k_RandomState_multinomial_line_454), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_multivariate_normal, __pyx_k_RandomState_multivariate_normal, sizeof(__pyx_k_RandomState_multivariate_normal), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_negative_binomial_li, __pyx_k_RandomState_negative_binomial_li, sizeof(__pyx_k_RandomState_negative_binomial_li), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_noncentral_chisquare, __pyx_k_RandomState_noncentral_chisquare, sizeof(__pyx_k_RandomState_noncentral_chisquare), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_noncentral_f_line_21, __pyx_k_RandomState_noncentral_f_line_21, sizeof(__pyx_k_RandomState_noncentral_f_line_21), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_normal_line_1552, __pyx_k_RandomState_normal_line_1552, sizeof(__pyx_k_RandomState_normal_line_1552), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_pareto_line_2660, __pyx_k_RandomState_pareto_line_2660, sizeof(__pyx_k_RandomState_pareto_line_2660), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_permutation_line_486, __pyx_k_RandomState_permutation_line_486, sizeof(__pyx_k_RandomState_permutation_line_486), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_poisson_line_3914, __pyx_k_RandomState_poisson_line_3914, sizeof(__pyx_k_RandomState_poisson_line_3914), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_power_line_2880, __pyx_k_RandomState_power_line_2880, sizeof(__pyx_k_RandomState_power_line_2880), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_rand_line_1321, __pyx_k_RandomState_rand_line_1321, sizeof(__pyx_k_RandomState_rand_line_1321), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_randint_line_910, __pyx_k_RandomState_randint_line_910, sizeof(__pyx_k_RandomState_randint_line_910), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_randn_line_1365, __pyx_k_RandomState_randn_line_1365, sizeof(__pyx_k_RandomState_randn_line_1365), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_random_integers_line, __pyx_k_RandomState_random_integers_line, sizeof(__pyx_k_RandomState_random_integers_line), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_random_sample_line_8, __pyx_k_RandomState_random_sample_line_8, sizeof(__pyx_k_RandomState_random_sample_line_8), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_rayleigh_line_3437, __pyx_k_RandomState_rayleigh_line_3437, sizeof(__pyx_k_RandomState_rayleigh_line_3437), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_shuffle_line_4779, __pyx_k_RandomState_shuffle_line_4779, sizeof(__pyx_k_RandomState_shuffle_line_4779), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_standard_cauchy_line, __pyx_k_RandomState_standard_cauchy_line, sizeof(__pyx_k_RandomState_standard_cauchy_line), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_standard_exponential, __pyx_k_RandomState_standard_exponential, sizeof(__pyx_k_RandomState_standard_exponential), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_standard_gamma_line, __pyx_k_RandomState_standard_gamma_line, sizeof(__pyx_k_RandomState_standard_gamma_line), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_standard_normal_line, __pyx_k_RandomState_standard_normal_line, sizeof(__pyx_k_RandomState_standard_normal_line), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_standard_t_line_2456, __pyx_k_RandomState_standard_t_line_2456, sizeof(__pyx_k_RandomState_standard_t_line_2456), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_tomaxint_line_863, __pyx_k_RandomState_tomaxint_line_863, sizeof(__pyx_k_RandomState_tomaxint_line_863), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_triangular_line_3603, __pyx_k_RandomState_triangular_line_3603, sizeof(__pyx_k_RandomState_triangular_line_3603), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_uniform_line_1215, __pyx_k_RandomState_uniform_line_1215, sizeof(__pyx_k_RandomState_uniform_line_1215), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_vonmises_line_2562, __pyx_k_RandomState_vonmises_line_2562, sizeof(__pyx_k_RandomState_vonmises_line_2562), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_wald_line_3516, __pyx_k_RandomState_wald_line_3516, sizeof(__pyx_k_RandomState_wald_line_3516), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_weibull_line_2770, __pyx_k_RandomState_weibull_line_2770, sizeof(__pyx_k_RandomState_weibull_line_2770), 0, 1, 0, 0}, + {&__pyx_kp_u_RandomState_zipf_line_4002, __pyx_k_RandomState_zipf_line_4002, sizeof(__pyx_k_RandomState_zipf_line_4002), 0, 1, 0, 0}, + {&__pyx_kp_s_Range_exceeds_valid_bounds, __pyx_k_Range_exceeds_valid_bounds, sizeof(__pyx_k_Range_exceeds_valid_bounds), 0, 0, 1, 0}, + {&__pyx_n_s_RuntimeWarning, __pyx_k_RuntimeWarning, sizeof(__pyx_k_RuntimeWarning), 0, 0, 1, 1}, + {&__pyx_kp_s_Seed_array_must_be_1_d, __pyx_k_Seed_array_must_be_1_d, sizeof(__pyx_k_Seed_array_must_be_1_d), 0, 0, 1, 0}, + {&__pyx_kp_s_Seed_must_be_between_0_and_2_32, __pyx_k_Seed_must_be_between_0_and_2_32, sizeof(__pyx_k_Seed_must_be_between_0_and_2_32), 0, 0, 1, 0}, + {&__pyx_kp_s_Seed_must_be_non_empty, __pyx_k_Seed_must_be_non_empty, sizeof(__pyx_k_Seed_must_be_non_empty), 0, 0, 1, 0}, + {&__pyx_kp_s_Seed_values_must_be_between_0_an, __pyx_k_Seed_values_must_be_between_0_an, sizeof(__pyx_k_Seed_values_must_be_between_0_an), 0, 0, 1, 0}, + {&__pyx_n_s_T, __pyx_k_T, sizeof(__pyx_k_T), 0, 0, 1, 1}, + {&__pyx_kp_s_This_function_is_deprecated_Plea, __pyx_k_This_function_is_deprecated_Plea, sizeof(__pyx_k_This_function_is_deprecated_Plea), 0, 0, 1, 0}, + {&__pyx_kp_s_This_function_is_deprecated_Plea_2, __pyx_k_This_function_is_deprecated_Plea_2, sizeof(__pyx_k_This_function_is_deprecated_Plea_2), 0, 0, 1, 0}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_kp_s_Unsupported_dtype_s_for_randint, __pyx_k_Unsupported_dtype_s_for_randint, sizeof(__pyx_k_Unsupported_dtype_s_for_randint), 0, 0, 1, 0}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_n_s_a, __pyx_k_a, sizeof(__pyx_k_a), 0, 0, 1, 1}, + {&__pyx_kp_s_a_0, __pyx_k_a_0, sizeof(__pyx_k_a_0), 0, 0, 1, 0}, + {&__pyx_kp_s_a_0_2, __pyx_k_a_0_2, sizeof(__pyx_k_a_0_2), 0, 0, 1, 0}, + {&__pyx_kp_s_a_and_p_must_have_same_size, __pyx_k_a_and_p_must_have_same_size, sizeof(__pyx_k_a_and_p_must_have_same_size), 0, 0, 1, 0}, + {&__pyx_kp_s_a_must_be_1_dimensional, __pyx_k_a_must_be_1_dimensional, sizeof(__pyx_k_a_must_be_1_dimensional), 0, 0, 1, 0}, + {&__pyx_kp_s_a_must_be_1_dimensional_or_an_in, __pyx_k_a_must_be_1_dimensional_or_an_in, sizeof(__pyx_k_a_must_be_1_dimensional_or_an_in), 0, 0, 1, 0}, + {&__pyx_kp_s_a_must_be_a_valid_float_1_0, __pyx_k_a_must_be_a_valid_float_1_0, sizeof(__pyx_k_a_must_be_a_valid_float_1_0), 0, 0, 1, 0}, + {&__pyx_kp_s_a_must_be_greater_than_0, __pyx_k_a_must_be_greater_than_0, sizeof(__pyx_k_a_must_be_greater_than_0), 0, 0, 1, 0}, + {&__pyx_kp_s_a_must_be_non_empty, __pyx_k_a_must_be_non_empty, sizeof(__pyx_k_a_must_be_non_empty), 0, 0, 1, 0}, + {&__pyx_kp_s_a_must_contain_valid_floats_1_0, __pyx_k_a_must_contain_valid_floats_1_0, sizeof(__pyx_k_a_must_contain_valid_floats_1_0), 0, 0, 1, 0}, + {&__pyx_n_s_add, __pyx_k_add, sizeof(__pyx_k_add), 0, 0, 1, 1}, + {&__pyx_kp_s_algorithm_must_be_MT19937, __pyx_k_algorithm_must_be_MT19937, sizeof(__pyx_k_algorithm_must_be_MT19937), 0, 0, 1, 0}, + {&__pyx_n_s_all, __pyx_k_all, sizeof(__pyx_k_all), 0, 0, 1, 1}, + {&__pyx_n_s_allclose, __pyx_k_allclose, sizeof(__pyx_k_allclose), 0, 0, 1, 1}, + {&__pyx_n_s_alpha, __pyx_k_alpha, sizeof(__pyx_k_alpha), 0, 0, 1, 1}, + {&__pyx_kp_s_alpha_0, __pyx_k_alpha_0, sizeof(__pyx_k_alpha_0), 0, 0, 1, 0}, + {&__pyx_n_s_any, __pyx_k_any, sizeof(__pyx_k_any), 0, 0, 1, 1}, + {&__pyx_n_s_arange, __pyx_k_arange, sizeof(__pyx_k_arange), 0, 0, 1, 1}, + {&__pyx_n_s_array, __pyx_k_array, sizeof(__pyx_k_array), 0, 0, 1, 1}, + {&__pyx_n_s_array_data, __pyx_k_array_data, sizeof(__pyx_k_array_data), 0, 0, 1, 1}, + {&__pyx_n_s_asarray, __pyx_k_asarray, sizeof(__pyx_k_asarray), 0, 0, 1, 1}, + {&__pyx_n_s_astype, __pyx_k_astype, sizeof(__pyx_k_astype), 0, 0, 1, 1}, + {&__pyx_n_s_atol, __pyx_k_atol, sizeof(__pyx_k_atol), 0, 0, 1, 1}, + {&__pyx_n_s_b, __pyx_k_b, sizeof(__pyx_k_b), 0, 0, 1, 1}, + {&__pyx_kp_s_b_0, __pyx_k_b_0, sizeof(__pyx_k_b_0), 0, 0, 1, 0}, + {&__pyx_n_s_beta, __pyx_k_beta, sizeof(__pyx_k_beta), 0, 0, 1, 1}, + {&__pyx_n_s_binomial, __pyx_k_binomial, sizeof(__pyx_k_binomial), 0, 0, 1, 1}, + {&__pyx_kp_u_binomial_n_p_size_None_Draw_sam, __pyx_k_binomial_n_p_size_None_Draw_sam, sizeof(__pyx_k_binomial_n_p_size_None_Draw_sam), 0, 1, 0, 0}, + {&__pyx_n_s_bool, __pyx_k_bool, sizeof(__pyx_k_bool), 0, 0, 1, 1}, + {&__pyx_n_s_bool_2, __pyx_k_bool_2, sizeof(__pyx_k_bool_2), 0, 0, 1, 1}, + {&__pyx_n_s_broadcast, __pyx_k_broadcast, sizeof(__pyx_k_broadcast), 0, 0, 1, 1}, + {&__pyx_n_s_buf, __pyx_k_buf, sizeof(__pyx_k_buf), 0, 0, 1, 1}, + {&__pyx_n_s_bytes, __pyx_k_bytes, sizeof(__pyx_k_bytes), 0, 0, 1, 1}, + {&__pyx_kp_u_bytes_length_Return_random_byte, __pyx_k_bytes_length_Return_random_byte, sizeof(__pyx_k_bytes_length_Return_random_byte), 0, 1, 0, 0}, + {&__pyx_n_s_casting, __pyx_k_casting, sizeof(__pyx_k_casting), 0, 0, 1, 1}, + {&__pyx_n_s_check_valid, __pyx_k_check_valid, sizeof(__pyx_k_check_valid), 0, 0, 1, 1}, + {&__pyx_kp_s_check_valid_must_equal_warn_rais, __pyx_k_check_valid_must_equal_warn_rais, sizeof(__pyx_k_check_valid_must_equal_warn_rais), 0, 0, 1, 0}, + {&__pyx_n_s_chisquare, __pyx_k_chisquare, sizeof(__pyx_k_chisquare), 0, 0, 1, 1}, + {&__pyx_kp_u_chisquare_df_size_None_Draw_sam, __pyx_k_chisquare_df_size_None_Draw_sam, sizeof(__pyx_k_chisquare_df_size_None_Draw_sam), 0, 1, 0, 0}, + {&__pyx_n_s_choice, __pyx_k_choice, sizeof(__pyx_k_choice), 0, 0, 1, 1}, + {&__pyx_kp_u_choice_a_size_None_replace_True, __pyx_k_choice_a_size_None_replace_True, sizeof(__pyx_k_choice_a_size_None_replace_True), 0, 1, 0, 0}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_cnt, __pyx_k_cnt, sizeof(__pyx_k_cnt), 0, 0, 1, 1}, + {&__pyx_n_s_copy, __pyx_k_copy, sizeof(__pyx_k_copy), 0, 0, 1, 1}, + {&__pyx_n_s_count_nonzero, __pyx_k_count_nonzero, sizeof(__pyx_k_count_nonzero), 0, 0, 1, 1}, + {&__pyx_n_s_cov, __pyx_k_cov, sizeof(__pyx_k_cov), 0, 0, 1, 1}, + {&__pyx_kp_s_cov_must_be_2_dimensional_and_sq, __pyx_k_cov_must_be_2_dimensional_and_sq, sizeof(__pyx_k_cov_must_be_2_dimensional_and_sq), 0, 0, 1, 0}, + {&__pyx_kp_s_covariance_is_not_positive_semid, __pyx_k_covariance_is_not_positive_semid, sizeof(__pyx_k_covariance_is_not_positive_semid), 0, 0, 1, 0}, + {&__pyx_n_s_ctypes, __pyx_k_ctypes, sizeof(__pyx_k_ctypes), 0, 0, 1, 1}, + {&__pyx_n_s_cumsum, __pyx_k_cumsum, sizeof(__pyx_k_cumsum), 0, 0, 1, 1}, + {&__pyx_n_s_d, __pyx_k_d, sizeof(__pyx_k_d), 0, 0, 1, 1}, + {&__pyx_n_s_data, __pyx_k_data, sizeof(__pyx_k_data), 0, 0, 1, 1}, + {&__pyx_n_s_df, __pyx_k_df, sizeof(__pyx_k_df), 0, 0, 1, 1}, + {&__pyx_kp_s_df_0, __pyx_k_df_0, sizeof(__pyx_k_df_0), 0, 0, 1, 0}, + {&__pyx_n_s_dfden, __pyx_k_dfden, sizeof(__pyx_k_dfden), 0, 0, 1, 1}, + {&__pyx_kp_s_dfden_0, __pyx_k_dfden_0, sizeof(__pyx_k_dfden_0), 0, 0, 1, 0}, + {&__pyx_n_s_dfnum, __pyx_k_dfnum, sizeof(__pyx_k_dfnum), 0, 0, 1, 1}, + {&__pyx_kp_s_dfnum_0, __pyx_k_dfnum_0, sizeof(__pyx_k_dfnum_0), 0, 0, 1, 0}, + {&__pyx_n_s_dirichlet, __pyx_k_dirichlet, sizeof(__pyx_k_dirichlet), 0, 0, 1, 1}, + {&__pyx_kp_u_dirichlet_alpha_size_None_Draw, __pyx_k_dirichlet_alpha_size_None_Draw, sizeof(__pyx_k_dirichlet_alpha_size_None_Draw), 0, 1, 0, 0}, + {&__pyx_n_s_dot, __pyx_k_dot, sizeof(__pyx_k_dot), 0, 0, 1, 1}, + {&__pyx_n_s_dtype, __pyx_k_dtype, sizeof(__pyx_k_dtype), 0, 0, 1, 1}, + {&__pyx_n_s_dummy_threading, __pyx_k_dummy_threading, sizeof(__pyx_k_dummy_threading), 0, 0, 1, 1}, + {&__pyx_n_s_empty, __pyx_k_empty, sizeof(__pyx_k_empty), 0, 0, 1, 1}, + {&__pyx_n_s_empty_like, __pyx_k_empty_like, sizeof(__pyx_k_empty_like), 0, 0, 1, 1}, + {&__pyx_n_s_enter, __pyx_k_enter, sizeof(__pyx_k_enter), 0, 0, 1, 1}, + {&__pyx_n_s_eps, __pyx_k_eps, sizeof(__pyx_k_eps), 0, 0, 1, 1}, + {&__pyx_n_s_equal, __pyx_k_equal, sizeof(__pyx_k_equal), 0, 0, 1, 1}, + {&__pyx_n_s_exit, __pyx_k_exit, sizeof(__pyx_k_exit), 0, 0, 1, 1}, + {&__pyx_n_s_exponential, __pyx_k_exponential, sizeof(__pyx_k_exponential), 0, 0, 1, 1}, + {&__pyx_n_s_f, __pyx_k_f, sizeof(__pyx_k_f), 0, 0, 1, 1}, + {&__pyx_kp_u_f_dfnum_dfden_size_None_Draw_sa, __pyx_k_f_dfnum_dfden_size_None_Draw_sa, sizeof(__pyx_k_f_dfnum_dfden_size_None_Draw_sa), 0, 1, 0, 0}, + {&__pyx_n_s_finfo, __pyx_k_finfo, sizeof(__pyx_k_finfo), 0, 0, 1, 1}, + {&__pyx_n_s_float64, __pyx_k_float64, sizeof(__pyx_k_float64), 0, 0, 1, 1}, + {&__pyx_n_s_floating, __pyx_k_floating, sizeof(__pyx_k_floating), 0, 0, 1, 1}, + {&__pyx_n_s_format, __pyx_k_format, sizeof(__pyx_k_format), 0, 0, 1, 1}, + {&__pyx_n_s_gamma, __pyx_k_gamma, sizeof(__pyx_k_gamma), 0, 0, 1, 1}, + {&__pyx_kp_u_gamma_shape_scale_1_0_size_None, __pyx_k_gamma_shape_scale_1_0_size_None, sizeof(__pyx_k_gamma_shape_scale_1_0_size_None), 0, 1, 0, 0}, + {&__pyx_n_s_geometric, __pyx_k_geometric, sizeof(__pyx_k_geometric), 0, 0, 1, 1}, + {&__pyx_kp_u_geometric_p_size_None_Draw_samp, __pyx_k_geometric_p_size_None_Draw_samp, sizeof(__pyx_k_geometric_p_size_None_Draw_samp), 0, 1, 0, 0}, + {&__pyx_n_s_get_state, __pyx_k_get_state, sizeof(__pyx_k_get_state), 0, 0, 1, 1}, + {&__pyx_n_s_greater, __pyx_k_greater, sizeof(__pyx_k_greater), 0, 0, 1, 1}, + {&__pyx_n_s_greater_equal, __pyx_k_greater_equal, sizeof(__pyx_k_greater_equal), 0, 0, 1, 1}, + {&__pyx_n_s_gumbel, __pyx_k_gumbel, sizeof(__pyx_k_gumbel), 0, 0, 1, 1}, + {&__pyx_kp_u_gumbel_loc_0_0_scale_1_0_size_N, __pyx_k_gumbel_loc_0_0_scale_1_0_size_N, sizeof(__pyx_k_gumbel_loc_0_0_scale_1_0_size_N), 0, 1, 0, 0}, + {&__pyx_n_s_high, __pyx_k_high, sizeof(__pyx_k_high), 0, 0, 1, 1}, + {&__pyx_kp_s_high_is_out_of_bounds_for_s, __pyx_k_high_is_out_of_bounds_for_s, sizeof(__pyx_k_high_is_out_of_bounds_for_s), 0, 0, 1, 0}, + {&__pyx_n_s_hypergeometric, __pyx_k_hypergeometric, sizeof(__pyx_k_hypergeometric), 0, 0, 1, 1}, + {&__pyx_kp_u_hypergeometric_ngood_nbad_nsamp, __pyx_k_hypergeometric_ngood_nbad_nsamp, sizeof(__pyx_k_hypergeometric_ngood_nbad_nsamp), 0, 1, 0, 0}, + {&__pyx_n_s_ignore, __pyx_k_ignore, sizeof(__pyx_k_ignore), 0, 0, 1, 1}, + {&__pyx_n_s_iinfo, __pyx_k_iinfo, sizeof(__pyx_k_iinfo), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_index, __pyx_k_index, sizeof(__pyx_k_index), 0, 0, 1, 1}, + {&__pyx_n_s_int, __pyx_k_int, sizeof(__pyx_k_int), 0, 0, 1, 1}, + {&__pyx_n_s_int16, __pyx_k_int16, sizeof(__pyx_k_int16), 0, 0, 1, 1}, + {&__pyx_n_s_int32, __pyx_k_int32, sizeof(__pyx_k_int32), 0, 0, 1, 1}, + {&__pyx_n_s_int64, __pyx_k_int64, sizeof(__pyx_k_int64), 0, 0, 1, 1}, + {&__pyx_n_s_int8, __pyx_k_int8, sizeof(__pyx_k_int8), 0, 0, 1, 1}, + {&__pyx_n_s_integer, __pyx_k_integer, sizeof(__pyx_k_integer), 0, 0, 1, 1}, + {&__pyx_n_s_intp, __pyx_k_intp, sizeof(__pyx_k_intp), 0, 0, 1, 1}, + {&__pyx_n_s_isfinite, __pyx_k_isfinite, sizeof(__pyx_k_isfinite), 0, 0, 1, 1}, + {&__pyx_n_s_isnan, __pyx_k_isnan, sizeof(__pyx_k_isnan), 0, 0, 1, 1}, + {&__pyx_n_s_issubdtype, __pyx_k_issubdtype, sizeof(__pyx_k_issubdtype), 0, 0, 1, 1}, + {&__pyx_n_s_item, __pyx_k_item, sizeof(__pyx_k_item), 0, 0, 1, 1}, + {&__pyx_n_s_itemsize, __pyx_k_itemsize, sizeof(__pyx_k_itemsize), 0, 0, 1, 1}, + {&__pyx_n_s_kappa, __pyx_k_kappa, sizeof(__pyx_k_kappa), 0, 0, 1, 1}, + {&__pyx_kp_s_kappa_0, __pyx_k_kappa_0, sizeof(__pyx_k_kappa_0), 0, 0, 1, 0}, + {&__pyx_n_s_l, __pyx_k_l, sizeof(__pyx_k_l), 0, 0, 1, 1}, + {&__pyx_n_s_lam, __pyx_k_lam, sizeof(__pyx_k_lam), 0, 0, 1, 1}, + {&__pyx_kp_s_lam_0, __pyx_k_lam_0, sizeof(__pyx_k_lam_0), 0, 0, 1, 0}, + {&__pyx_kp_s_lam_value_too_large, __pyx_k_lam_value_too_large, sizeof(__pyx_k_lam_value_too_large), 0, 0, 1, 0}, + {&__pyx_kp_s_lam_value_too_large_2, __pyx_k_lam_value_too_large_2, sizeof(__pyx_k_lam_value_too_large_2), 0, 0, 1, 0}, + {&__pyx_n_s_laplace, __pyx_k_laplace, sizeof(__pyx_k_laplace), 0, 0, 1, 1}, + {&__pyx_kp_u_laplace_loc_0_0_scale_1_0_size, __pyx_k_laplace_loc_0_0_scale_1_0_size, sizeof(__pyx_k_laplace_loc_0_0_scale_1_0_size), 0, 1, 0, 0}, + {&__pyx_n_s_left, __pyx_k_left, sizeof(__pyx_k_left), 0, 0, 1, 1}, + {&__pyx_kp_s_left_mode, __pyx_k_left_mode, sizeof(__pyx_k_left_mode), 0, 0, 1, 0}, + {&__pyx_kp_s_left_right, __pyx_k_left_right, sizeof(__pyx_k_left_right), 0, 0, 1, 0}, + {&__pyx_n_s_less, __pyx_k_less, sizeof(__pyx_k_less), 0, 0, 1, 1}, + {&__pyx_n_s_less_equal, __pyx_k_less_equal, sizeof(__pyx_k_less_equal), 0, 0, 1, 1}, + {&__pyx_n_s_loc, __pyx_k_loc, sizeof(__pyx_k_loc), 0, 0, 1, 1}, + {&__pyx_n_s_logical_or, __pyx_k_logical_or, sizeof(__pyx_k_logical_or), 0, 0, 1, 1}, + {&__pyx_n_s_logistic, __pyx_k_logistic, sizeof(__pyx_k_logistic), 0, 0, 1, 1}, + {&__pyx_kp_u_logistic_loc_0_0_scale_1_0_size, __pyx_k_logistic_loc_0_0_scale_1_0_size, sizeof(__pyx_k_logistic_loc_0_0_scale_1_0_size), 0, 1, 0, 0}, + {&__pyx_n_s_lognormal, __pyx_k_lognormal, sizeof(__pyx_k_lognormal), 0, 0, 1, 1}, + {&__pyx_kp_u_lognormal_mean_0_0_sigma_1_0_si, __pyx_k_lognormal_mean_0_0_sigma_1_0_si, sizeof(__pyx_k_lognormal_mean_0_0_sigma_1_0_si), 0, 1, 0, 0}, + {&__pyx_n_s_logseries, __pyx_k_logseries, sizeof(__pyx_k_logseries), 0, 0, 1, 1}, + {&__pyx_kp_u_logseries_p_size_None_Draw_samp, __pyx_k_logseries_p_size_None_Draw_samp, sizeof(__pyx_k_logseries_p_size_None_Draw_samp), 0, 1, 0, 0}, + {&__pyx_n_s_long, __pyx_k_long, sizeof(__pyx_k_long), 0, 0, 1, 1}, + {&__pyx_n_s_low, __pyx_k_low, sizeof(__pyx_k_low), 0, 0, 1, 1}, + {&__pyx_kp_s_low_high, __pyx_k_low_high, sizeof(__pyx_k_low_high), 0, 0, 1, 0}, + {&__pyx_kp_s_low_is_out_of_bounds_for_s, __pyx_k_low_is_out_of_bounds_for_s, sizeof(__pyx_k_low_is_out_of_bounds_for_s), 0, 0, 1, 0}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_max, __pyx_k_max, sizeof(__pyx_k_max), 0, 0, 1, 1}, + {&__pyx_n_s_mean, __pyx_k_mean, sizeof(__pyx_k_mean), 0, 0, 1, 1}, + {&__pyx_kp_s_mean_0, __pyx_k_mean_0, sizeof(__pyx_k_mean_0), 0, 0, 1, 0}, + {&__pyx_kp_s_mean_0_0, __pyx_k_mean_0_0, sizeof(__pyx_k_mean_0_0), 0, 0, 1, 0}, + {&__pyx_kp_s_mean_and_cov_must_have_same_leng, __pyx_k_mean_and_cov_must_have_same_leng, sizeof(__pyx_k_mean_and_cov_must_have_same_leng), 0, 0, 1, 0}, + {&__pyx_kp_s_mean_must_be_1_dimensional, __pyx_k_mean_must_be_1_dimensional, sizeof(__pyx_k_mean_must_be_1_dimensional), 0, 0, 1, 0}, + {&__pyx_n_s_mode, __pyx_k_mode, sizeof(__pyx_k_mode), 0, 0, 1, 1}, + {&__pyx_kp_s_mode_right, __pyx_k_mode_right, sizeof(__pyx_k_mode_right), 0, 0, 1, 0}, + {&__pyx_n_s_mtrand, __pyx_k_mtrand, sizeof(__pyx_k_mtrand), 0, 0, 1, 1}, + {&__pyx_kp_s_mtrand_pyx, __pyx_k_mtrand_pyx, sizeof(__pyx_k_mtrand_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_mu, __pyx_k_mu, sizeof(__pyx_k_mu), 0, 0, 1, 1}, + {&__pyx_n_s_multinomial, __pyx_k_multinomial, sizeof(__pyx_k_multinomial), 0, 0, 1, 1}, + {&__pyx_kp_u_multinomial_n_pvals_size_None_D, __pyx_k_multinomial_n_pvals_size_None_D, sizeof(__pyx_k_multinomial_n_pvals_size_None_D), 0, 1, 0, 0}, + {&__pyx_n_s_multivariate_normal, __pyx_k_multivariate_normal, sizeof(__pyx_k_multivariate_normal), 0, 0, 1, 1}, + {&__pyx_kp_u_multivariate_normal_mean_cov_si, __pyx_k_multivariate_normal_mean_cov_si, sizeof(__pyx_k_multivariate_normal_mean_cov_si), 0, 1, 0, 0}, + {&__pyx_n_s_n, __pyx_k_n, sizeof(__pyx_k_n), 0, 0, 1, 1}, + {&__pyx_kp_s_n_0, __pyx_k_n_0, sizeof(__pyx_k_n_0), 0, 0, 1, 0}, + {&__pyx_kp_s_n_0_2, __pyx_k_n_0_2, sizeof(__pyx_k_n_0_2), 0, 0, 1, 0}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_nbad, __pyx_k_nbad, sizeof(__pyx_k_nbad), 0, 0, 1, 1}, + {&__pyx_kp_s_nbad_0, __pyx_k_nbad_0, sizeof(__pyx_k_nbad_0), 0, 0, 1, 0}, + {&__pyx_n_s_ndarray, __pyx_k_ndarray, sizeof(__pyx_k_ndarray), 0, 0, 1, 1}, + {&__pyx_n_s_ndim, __pyx_k_ndim, sizeof(__pyx_k_ndim), 0, 0, 1, 1}, + {&__pyx_n_s_negative_binomial, __pyx_k_negative_binomial, sizeof(__pyx_k_negative_binomial), 0, 0, 1, 1}, + {&__pyx_kp_u_negative_binomial_n_p_size_None, __pyx_k_negative_binomial_n_p_size_None, sizeof(__pyx_k_negative_binomial_n_p_size_None), 0, 1, 0, 0}, + {&__pyx_n_s_ngood, __pyx_k_ngood, sizeof(__pyx_k_ngood), 0, 0, 1, 1}, + {&__pyx_kp_s_ngood_0, __pyx_k_ngood_0, sizeof(__pyx_k_ngood_0), 0, 0, 1, 0}, + {&__pyx_kp_s_ngood_nbad_nsample, __pyx_k_ngood_nbad_nsample, sizeof(__pyx_k_ngood_nbad_nsample), 0, 0, 1, 0}, + {&__pyx_n_s_nonc, __pyx_k_nonc, sizeof(__pyx_k_nonc), 0, 0, 1, 1}, + {&__pyx_kp_s_nonc_0, __pyx_k_nonc_0, sizeof(__pyx_k_nonc_0), 0, 0, 1, 0}, + {&__pyx_n_s_noncentral_chisquare, __pyx_k_noncentral_chisquare, sizeof(__pyx_k_noncentral_chisquare), 0, 0, 1, 1}, + {&__pyx_kp_u_noncentral_chisquare_df_nonc_si, __pyx_k_noncentral_chisquare_df_nonc_si, sizeof(__pyx_k_noncentral_chisquare_df_nonc_si), 0, 1, 0, 0}, + {&__pyx_n_s_noncentral_f, __pyx_k_noncentral_f, sizeof(__pyx_k_noncentral_f), 0, 0, 1, 1}, + {&__pyx_kp_u_noncentral_f_dfnum_dfden_nonc_s, __pyx_k_noncentral_f_dfnum_dfden_nonc_s, sizeof(__pyx_k_noncentral_f_dfnum_dfden_nonc_s), 0, 1, 0, 0}, + {&__pyx_n_s_normal, __pyx_k_normal, sizeof(__pyx_k_normal), 0, 0, 1, 1}, + {&__pyx_kp_u_normal_loc_0_0_scale_1_0_size_N, __pyx_k_normal_loc_0_0_scale_1_0_size_N, sizeof(__pyx_k_normal_loc_0_0_scale_1_0_size_N), 0, 1, 0, 0}, + {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1}, + {&__pyx_n_s_nsample, __pyx_k_nsample, sizeof(__pyx_k_nsample), 0, 0, 1, 1}, + {&__pyx_kp_s_nsample_1, __pyx_k_nsample_1, sizeof(__pyx_k_nsample_1), 0, 0, 1, 0}, + {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, + {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, + {&__pyx_n_s_numpy_dual, __pyx_k_numpy_dual, sizeof(__pyx_k_numpy_dual), 0, 0, 1, 1}, + {&__pyx_n_s_off, __pyx_k_off, sizeof(__pyx_k_off), 0, 0, 1, 1}, + {&__pyx_n_s_operator, __pyx_k_operator, sizeof(__pyx_k_operator), 0, 0, 1, 1}, + {&__pyx_n_s_out, __pyx_k_out, sizeof(__pyx_k_out), 0, 0, 1, 1}, + {&__pyx_n_s_p, __pyx_k_p, sizeof(__pyx_k_p), 0, 0, 1, 1}, + {&__pyx_kp_s_p_0, __pyx_k_p_0, sizeof(__pyx_k_p_0), 0, 0, 1, 0}, + {&__pyx_kp_s_p_0_0, __pyx_k_p_0_0, sizeof(__pyx_k_p_0_0), 0, 0, 1, 0}, + {&__pyx_kp_s_p_0_0_2, __pyx_k_p_0_0_2, sizeof(__pyx_k_p_0_0_2), 0, 0, 1, 0}, + {&__pyx_kp_s_p_1, __pyx_k_p_1, sizeof(__pyx_k_p_1), 0, 0, 1, 0}, + {&__pyx_kp_s_p_1_0, __pyx_k_p_1_0, sizeof(__pyx_k_p_1_0), 0, 0, 1, 0}, + {&__pyx_kp_s_p_1_0_2, __pyx_k_p_1_0_2, sizeof(__pyx_k_p_1_0_2), 0, 0, 1, 0}, + {&__pyx_kp_s_p_is_nan, __pyx_k_p_is_nan, sizeof(__pyx_k_p_is_nan), 0, 0, 1, 0}, + {&__pyx_kp_s_p_must_be_1_dimensional, __pyx_k_p_must_be_1_dimensional, sizeof(__pyx_k_p_must_be_1_dimensional), 0, 0, 1, 0}, + {&__pyx_n_s_pareto, __pyx_k_pareto, sizeof(__pyx_k_pareto), 0, 0, 1, 1}, + {&__pyx_kp_u_pareto_a_size_None_Draw_samples, __pyx_k_pareto_a_size_None_Draw_samples, sizeof(__pyx_k_pareto_a_size_None_Draw_samples), 0, 1, 0, 0}, + {&__pyx_n_s_permutation, __pyx_k_permutation, sizeof(__pyx_k_permutation), 0, 0, 1, 1}, + {&__pyx_kp_u_permutation_x_Randomly_permute, __pyx_k_permutation_x_Randomly_permute, sizeof(__pyx_k_permutation_x_Randomly_permute), 0, 1, 0, 0}, + {&__pyx_n_s_poisson, __pyx_k_poisson, sizeof(__pyx_k_poisson), 0, 0, 1, 1}, + {&__pyx_kp_u_poisson_lam_1_0_size_None_Draw, __pyx_k_poisson_lam_1_0_size_None_Draw, sizeof(__pyx_k_poisson_lam_1_0_size_None_Draw), 0, 1, 0, 0}, + {&__pyx_n_s_poisson_lam_max, __pyx_k_poisson_lam_max, sizeof(__pyx_k_poisson_lam_max), 0, 0, 1, 1}, + {&__pyx_n_s_power, __pyx_k_power, sizeof(__pyx_k_power), 0, 0, 1, 1}, + {&__pyx_kp_u_power_a_size_None_Draws_samples, __pyx_k_power_a_size_None_Draws_samples, sizeof(__pyx_k_power_a_size_None_Draws_samples), 0, 1, 0, 0}, + {&__pyx_kp_s_probabilities_are_not_non_negati, __pyx_k_probabilities_are_not_non_negati, sizeof(__pyx_k_probabilities_are_not_non_negati), 0, 0, 1, 0}, + {&__pyx_kp_s_probabilities_do_not_sum_to_1, __pyx_k_probabilities_do_not_sum_to_1, sizeof(__pyx_k_probabilities_do_not_sum_to_1), 0, 0, 1, 0}, + {&__pyx_n_s_prod, __pyx_k_prod, sizeof(__pyx_k_prod), 0, 0, 1, 1}, + {&__pyx_n_s_pvals, __pyx_k_pvals, sizeof(__pyx_k_pvals), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, + {&__pyx_n_s_raise, __pyx_k_raise, sizeof(__pyx_k_raise), 0, 0, 1, 1}, + {&__pyx_n_s_rand, __pyx_k_rand, sizeof(__pyx_k_rand), 0, 0, 1, 1}, + {&__pyx_n_s_rand_2, __pyx_k_rand_2, sizeof(__pyx_k_rand_2), 0, 0, 1, 1}, + {&__pyx_n_s_rand_bool, __pyx_k_rand_bool, sizeof(__pyx_k_rand_bool), 0, 0, 1, 1}, + {&__pyx_kp_u_rand_d0_d1_dn_Random_values_in, __pyx_k_rand_d0_d1_dn_Random_values_in, sizeof(__pyx_k_rand_d0_d1_dn_Random_values_in), 0, 1, 0, 0}, + {&__pyx_n_s_rand_int16, __pyx_k_rand_int16, sizeof(__pyx_k_rand_int16), 0, 0, 1, 1}, + {&__pyx_n_s_rand_int32, __pyx_k_rand_int32, sizeof(__pyx_k_rand_int32), 0, 0, 1, 1}, + {&__pyx_n_s_rand_int64, __pyx_k_rand_int64, sizeof(__pyx_k_rand_int64), 0, 0, 1, 1}, + {&__pyx_n_s_rand_int8, __pyx_k_rand_int8, sizeof(__pyx_k_rand_int8), 0, 0, 1, 1}, + {&__pyx_n_s_rand_uint16, __pyx_k_rand_uint16, sizeof(__pyx_k_rand_uint16), 0, 0, 1, 1}, + {&__pyx_n_s_rand_uint32, __pyx_k_rand_uint32, sizeof(__pyx_k_rand_uint32), 0, 0, 1, 1}, + {&__pyx_n_s_rand_uint64, __pyx_k_rand_uint64, sizeof(__pyx_k_rand_uint64), 0, 0, 1, 1}, + {&__pyx_n_s_rand_uint8, __pyx_k_rand_uint8, sizeof(__pyx_k_rand_uint8), 0, 0, 1, 1}, + {&__pyx_n_s_randint, __pyx_k_randint, sizeof(__pyx_k_randint), 0, 0, 1, 1}, + {&__pyx_kp_s_randint_helpers_pxi, __pyx_k_randint_helpers_pxi, sizeof(__pyx_k_randint_helpers_pxi), 0, 0, 1, 0}, + {&__pyx_kp_u_randint_low_high_None_size_None, __pyx_k_randint_low_high_None_size_None, sizeof(__pyx_k_randint_low_high_None_size_None), 0, 1, 0, 0}, + {&__pyx_n_s_randint_type, __pyx_k_randint_type, sizeof(__pyx_k_randint_type), 0, 0, 1, 1}, + {&__pyx_n_s_randn, __pyx_k_randn, sizeof(__pyx_k_randn), 0, 0, 1, 1}, + {&__pyx_kp_u_randn_d0_d1_dn_Return_a_sample, __pyx_k_randn_d0_d1_dn_Return_a_sample, sizeof(__pyx_k_randn_d0_d1_dn_Return_a_sample), 0, 1, 0, 0}, + {&__pyx_n_s_random, __pyx_k_random, sizeof(__pyx_k_random), 0, 0, 1, 1}, + {&__pyx_n_s_random_integers, __pyx_k_random_integers, sizeof(__pyx_k_random_integers), 0, 0, 1, 1}, + {&__pyx_kp_u_random_integers_low_high_None_s, __pyx_k_random_integers_low_high_None_s, sizeof(__pyx_k_random_integers_low_high_None_s), 0, 1, 0, 0}, + {&__pyx_n_s_random_sample, __pyx_k_random_sample, sizeof(__pyx_k_random_sample), 0, 0, 1, 1}, + {&__pyx_kp_u_random_sample_size_None_Return, __pyx_k_random_sample_size_None_Return, sizeof(__pyx_k_random_sample_size_None_Return), 0, 1, 0, 0}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_ravel, __pyx_k_ravel, sizeof(__pyx_k_ravel), 0, 0, 1, 1}, + {&__pyx_n_s_rayleigh, __pyx_k_rayleigh, sizeof(__pyx_k_rayleigh), 0, 0, 1, 1}, + {&__pyx_kp_u_rayleigh_scale_1_0_size_None_Dr, __pyx_k_rayleigh_scale_1_0_size_None_Dr, sizeof(__pyx_k_rayleigh_scale_1_0_size_None_Dr), 0, 1, 0, 0}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_replace, __pyx_k_replace, sizeof(__pyx_k_replace), 0, 0, 1, 1}, + {&__pyx_n_s_reshape, __pyx_k_reshape, sizeof(__pyx_k_reshape), 0, 0, 1, 1}, + {&__pyx_n_s_return_index, __pyx_k_return_index, sizeof(__pyx_k_return_index), 0, 0, 1, 1}, + {&__pyx_n_s_reversed, __pyx_k_reversed, sizeof(__pyx_k_reversed), 0, 0, 1, 1}, + {&__pyx_n_s_right, __pyx_k_right, sizeof(__pyx_k_right), 0, 0, 1, 1}, + {&__pyx_n_s_rng, __pyx_k_rng, sizeof(__pyx_k_rng), 0, 0, 1, 1}, + {&__pyx_n_s_rngstate, __pyx_k_rngstate, sizeof(__pyx_k_rngstate), 0, 0, 1, 1}, + {&__pyx_n_s_rtol, __pyx_k_rtol, sizeof(__pyx_k_rtol), 0, 0, 1, 1}, + {&__pyx_n_s_safe, __pyx_k_safe, sizeof(__pyx_k_safe), 0, 0, 1, 1}, + {&__pyx_n_s_scale, __pyx_k_scale, sizeof(__pyx_k_scale), 0, 0, 1, 1}, + {&__pyx_kp_s_scale_0, __pyx_k_scale_0, sizeof(__pyx_k_scale_0), 0, 0, 1, 0}, + {&__pyx_kp_s_scale_0_0, __pyx_k_scale_0_0, sizeof(__pyx_k_scale_0_0), 0, 0, 1, 0}, + {&__pyx_kp_s_scale_0_0_2, __pyx_k_scale_0_0_2, sizeof(__pyx_k_scale_0_0_2), 0, 0, 1, 0}, + {&__pyx_kp_s_scale_0_2, __pyx_k_scale_0_2, sizeof(__pyx_k_scale_0_2), 0, 0, 1, 0}, + {&__pyx_n_s_searchsorted, __pyx_k_searchsorted, sizeof(__pyx_k_searchsorted), 0, 0, 1, 1}, + {&__pyx_n_s_seed, __pyx_k_seed, sizeof(__pyx_k_seed), 0, 0, 1, 1}, + {&__pyx_n_s_set_state, __pyx_k_set_state, sizeof(__pyx_k_set_state), 0, 0, 1, 1}, + {&__pyx_n_s_shape, __pyx_k_shape, sizeof(__pyx_k_shape), 0, 0, 1, 1}, + {&__pyx_kp_s_shape_0, __pyx_k_shape_0, sizeof(__pyx_k_shape_0), 0, 0, 1, 0}, + {&__pyx_n_s_shape_from_size, __pyx_k_shape_from_size, sizeof(__pyx_k_shape_from_size), 0, 0, 1, 1}, + {&__pyx_n_s_shuffle, __pyx_k_shuffle, sizeof(__pyx_k_shuffle), 0, 0, 1, 1}, + {&__pyx_kp_u_shuffle_x_Modify_a_sequence_in, __pyx_k_shuffle_x_Modify_a_sequence_in, sizeof(__pyx_k_shuffle_x_Modify_a_sequence_in), 0, 1, 0, 0}, + {&__pyx_n_s_side, __pyx_k_side, sizeof(__pyx_k_side), 0, 0, 1, 1}, + {&__pyx_n_s_sigma, __pyx_k_sigma, sizeof(__pyx_k_sigma), 0, 0, 1, 1}, + {&__pyx_kp_s_sigma_0, __pyx_k_sigma_0, sizeof(__pyx_k_sigma_0), 0, 0, 1, 0}, + {&__pyx_kp_s_sigma_0_0, __pyx_k_sigma_0_0, sizeof(__pyx_k_sigma_0_0), 0, 0, 1, 0}, + {&__pyx_n_s_signbit, __pyx_k_signbit, sizeof(__pyx_k_signbit), 0, 0, 1, 1}, + {&__pyx_n_s_size, __pyx_k_size, sizeof(__pyx_k_size), 0, 0, 1, 1}, + {&__pyx_kp_s_size_is_not_compatible_with_inpu, __pyx_k_size_is_not_compatible_with_inpu, sizeof(__pyx_k_size_is_not_compatible_with_inpu), 0, 0, 1, 0}, + {&__pyx_n_s_sort, __pyx_k_sort, sizeof(__pyx_k_sort), 0, 0, 1, 1}, + {&__pyx_n_s_sqrt, __pyx_k_sqrt, sizeof(__pyx_k_sqrt), 0, 0, 1, 1}, + {&__pyx_n_s_standard_cauchy, __pyx_k_standard_cauchy, sizeof(__pyx_k_standard_cauchy), 0, 0, 1, 1}, + {&__pyx_kp_u_standard_cauchy_size_None_Draw, __pyx_k_standard_cauchy_size_None_Draw, sizeof(__pyx_k_standard_cauchy_size_None_Draw), 0, 1, 0, 0}, + {&__pyx_n_s_standard_exponential, __pyx_k_standard_exponential, sizeof(__pyx_k_standard_exponential), 0, 0, 1, 1}, + {&__pyx_kp_u_standard_exponential_size_None, __pyx_k_standard_exponential_size_None, sizeof(__pyx_k_standard_exponential_size_None), 0, 1, 0, 0}, + {&__pyx_n_s_standard_gamma, __pyx_k_standard_gamma, sizeof(__pyx_k_standard_gamma), 0, 0, 1, 1}, + {&__pyx_kp_u_standard_gamma_shape_size_None, __pyx_k_standard_gamma_shape_size_None, sizeof(__pyx_k_standard_gamma_shape_size_None), 0, 1, 0, 0}, + {&__pyx_n_s_standard_normal, __pyx_k_standard_normal, sizeof(__pyx_k_standard_normal), 0, 0, 1, 1}, + {&__pyx_kp_u_standard_normal_size_None_Draw, __pyx_k_standard_normal_size_None_Draw, sizeof(__pyx_k_standard_normal_size_None_Draw), 0, 1, 0, 0}, + {&__pyx_n_s_standard_t, __pyx_k_standard_t, sizeof(__pyx_k_standard_t), 0, 0, 1, 1}, + {&__pyx_kp_u_standard_t_df_size_None_Draw_sa, __pyx_k_standard_t_df_size_None_Draw_sa, sizeof(__pyx_k_standard_t_df_size_None_Draw_sa), 0, 1, 0, 0}, + {&__pyx_n_s_state, __pyx_k_state, sizeof(__pyx_k_state), 0, 0, 1, 1}, + {&__pyx_kp_s_state_must_be_624_longs, __pyx_k_state_must_be_624_longs, sizeof(__pyx_k_state_must_be_624_longs), 0, 0, 1, 0}, + {&__pyx_n_s_strides, __pyx_k_strides, sizeof(__pyx_k_strides), 0, 0, 1, 1}, + {&__pyx_n_s_subtract, __pyx_k_subtract, sizeof(__pyx_k_subtract), 0, 0, 1, 1}, + {&__pyx_kp_s_sum_pvals_1_1_0, __pyx_k_sum_pvals_1_1_0, sizeof(__pyx_k_sum_pvals_1_1_0), 0, 0, 1, 0}, + {&__pyx_n_s_svd, __pyx_k_svd, sizeof(__pyx_k_svd), 0, 0, 1, 1}, + {&__pyx_n_s_take, __pyx_k_take, sizeof(__pyx_k_take), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_threading, __pyx_k_threading, sizeof(__pyx_k_threading), 0, 0, 1, 1}, + {&__pyx_n_s_tol, __pyx_k_tol, sizeof(__pyx_k_tol), 0, 0, 1, 1}, + {&__pyx_kp_u_tomaxint_size_None_Random_integ, __pyx_k_tomaxint_size_None_Random_integ, sizeof(__pyx_k_tomaxint_size_None_Random_integ), 0, 1, 0, 0}, + {&__pyx_n_s_triangular, __pyx_k_triangular, sizeof(__pyx_k_triangular), 0, 0, 1, 1}, + {&__pyx_kp_u_triangular_left_mode_right_size, __pyx_k_triangular_left_mode_right_size, sizeof(__pyx_k_triangular_left_mode_right_size), 0, 1, 0, 0}, + {&__pyx_n_s_uint, __pyx_k_uint, sizeof(__pyx_k_uint), 0, 0, 1, 1}, + {&__pyx_n_s_uint16, __pyx_k_uint16, sizeof(__pyx_k_uint16), 0, 0, 1, 1}, + {&__pyx_n_s_uint32, __pyx_k_uint32, sizeof(__pyx_k_uint32), 0, 0, 1, 1}, + {&__pyx_n_s_uint64, __pyx_k_uint64, sizeof(__pyx_k_uint64), 0, 0, 1, 1}, + {&__pyx_n_s_uint8, __pyx_k_uint8, sizeof(__pyx_k_uint8), 0, 0, 1, 1}, + {&__pyx_n_s_uniform, __pyx_k_uniform, sizeof(__pyx_k_uniform), 0, 0, 1, 1}, + {&__pyx_kp_u_uniform_low_0_0_high_1_0_size_N, __pyx_k_uniform_low_0_0_high_1_0_size_N, sizeof(__pyx_k_uniform_low_0_0_high_1_0_size_N), 0, 1, 0, 0}, + {&__pyx_n_s_unique, __pyx_k_unique, sizeof(__pyx_k_unique), 0, 0, 1, 1}, + {&__pyx_n_s_unsafe, __pyx_k_unsafe, sizeof(__pyx_k_unsafe), 0, 0, 1, 1}, + {&__pyx_n_s_vonmises, __pyx_k_vonmises, sizeof(__pyx_k_vonmises), 0, 0, 1, 1}, + {&__pyx_kp_u_vonmises_mu_kappa_size_None_Dra, __pyx_k_vonmises_mu_kappa_size_None_Dra, sizeof(__pyx_k_vonmises_mu_kappa_size_None_Dra), 0, 1, 0, 0}, + {&__pyx_n_s_wald, __pyx_k_wald, sizeof(__pyx_k_wald), 0, 0, 1, 1}, + {&__pyx_kp_u_wald_mean_scale_size_None_Draw, __pyx_k_wald_mean_scale_size_None_Draw, sizeof(__pyx_k_wald_mean_scale_size_None_Draw), 0, 1, 0, 0}, + {&__pyx_n_s_warn, __pyx_k_warn, sizeof(__pyx_k_warn), 0, 0, 1, 1}, + {&__pyx_n_s_warnings, __pyx_k_warnings, sizeof(__pyx_k_warnings), 0, 0, 1, 1}, + {&__pyx_n_s_weibull, __pyx_k_weibull, sizeof(__pyx_k_weibull), 0, 0, 1, 1}, + {&__pyx_kp_u_weibull_a_size_None_Draw_sample, __pyx_k_weibull_a_size_None_Draw_sample, sizeof(__pyx_k_weibull_a_size_None_Draw_sample), 0, 1, 0, 0}, + {&__pyx_n_s_zeros, __pyx_k_zeros, sizeof(__pyx_k_zeros), 0, 0, 1, 1}, + {&__pyx_n_s_zipf, __pyx_k_zipf, sizeof(__pyx_k_zipf), 0, 0, 1, 1}, + {&__pyx_kp_u_zipf_a_size_None_Draw_samples_f, __pyx_k_zipf_a_size_None_Draw_samples_f, sizeof(__pyx_k_zipf_a_size_None_Draw_samples_f), 0, 1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; +static int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(0, 152, __pyx_L1_error) + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 222, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 272, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 572, __pyx_L1_error) + __pyx_builtin_OverflowError = __Pyx_GetBuiltinName(__pyx_n_s_OverflowError); if (!__pyx_builtin_OverflowError) __PYX_ERR(0, 1305, __pyx_L1_error) + __pyx_builtin_DeprecationWarning = __Pyx_GetBuiltinName(__pyx_n_s_DeprecationWarning); if (!__pyx_builtin_DeprecationWarning) __PYX_ERR(0, 1505, __pyx_L1_error) + __pyx_builtin_RuntimeWarning = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeWarning); if (!__pyx_builtin_RuntimeWarning) __PYX_ERR(0, 4534, __pyx_L1_error) + __pyx_builtin_reversed = __Pyx_GetBuiltinName(__pyx_n_s_reversed); if (!__pyx_builtin_reversed) __PYX_ERR(0, 4845, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +static int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "numpy.pxd":163 + * except Exception: + * PyErr_Print() + * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< + */ + __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple_)) __PYX_ERR(2, 163, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "mtrand.pyx":163 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state) + * return rv + */ + __pyx_tuple__2 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 163, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__2); + __Pyx_GIVEREF(__pyx_tuple__2); + + /* "mtrand.pyx":170 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state) + */ + __pyx_tuple__3 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 170, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + + /* "mtrand.pyx":184 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a) + * return rv + */ + __pyx_tuple__4 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 184, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "mtrand.pyx":191 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a) + */ + __pyx_tuple__5 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 191, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__5); + __Pyx_GIVEREF(__pyx_tuple__5); + + /* "mtrand.pyx":212 + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + */ + __pyx_tuple__6 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(0, 212, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__6); + __Pyx_GIVEREF(__pyx_tuple__6); + + /* "mtrand.pyx":222 + * oa) + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < multi.size: + */ + __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_size_is_not_compatible_with_inpu); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(0, 222, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__7); + __Pyx_GIVEREF(__pyx_tuple__7); + + /* "mtrand.pyx":223 + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) + */ + __pyx_tuple__8 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 223, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + + /* "mtrand.pyx":238 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a, b) + * return rv + */ + __pyx_tuple__9 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 238, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__9); + __Pyx_GIVEREF(__pyx_tuple__9); + + /* "mtrand.pyx":245 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b) + */ + __pyx_tuple__10 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 245, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__10); + __Pyx_GIVEREF(__pyx_tuple__10); + + /* "mtrand.pyx":267 + * multi = np.broadcast(oa, ob, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_tuple__11 = PyTuple_Pack(1, __pyx_kp_s_size_is_not_compatible_with_inpu); if (unlikely(!__pyx_tuple__11)) __PYX_ERR(0, 267, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__11); + __Pyx_GIVEREF(__pyx_tuple__11); + + /* "mtrand.pyx":271 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) + */ + __pyx_tuple__12 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 271, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__12); + __Pyx_GIVEREF(__pyx_tuple__12); + + /* "mtrand.pyx":289 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a, b, c) + * return rv + */ + __pyx_tuple__13 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__13)) __PYX_ERR(0, 289, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__13); + __Pyx_GIVEREF(__pyx_tuple__13); + + /* "mtrand.pyx":296 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a, b, c) + */ + __pyx_tuple__14 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__14)) __PYX_ERR(0, 296, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__14); + __Pyx_GIVEREF(__pyx_tuple__14); + + /* "mtrand.pyx":319 + * multi = np.broadcast(oa, ob, oc, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_tuple__15 = PyTuple_Pack(1, __pyx_kp_s_size_is_not_compatible_with_inpu); if (unlikely(!__pyx_tuple__15)) __PYX_ERR(0, 319, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__15); + __Pyx_GIVEREF(__pyx_tuple__15); + + /* "mtrand.pyx":323 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * oa_data = PyArray_MultiIter_DATA(multi, 0) + */ + __pyx_tuple__16 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(0, 323, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__16); + __Pyx_GIVEREF(__pyx_tuple__16); + + /* "mtrand.pyx":340 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state) + * return rv + */ + __pyx_tuple__17 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(0, 340, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__17); + __Pyx_GIVEREF(__pyx_tuple__17); + + /* "mtrand.pyx":347 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state) + */ + __pyx_tuple__18 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(0, 347, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__18); + __Pyx_GIVEREF(__pyx_tuple__18); + + /* "mtrand.pyx":360 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, p) + * return rv + */ + __pyx_tuple__19 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__19)) __PYX_ERR(0, 360, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__19); + __Pyx_GIVEREF(__pyx_tuple__19); + + /* "mtrand.pyx":367 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) + */ + __pyx_tuple__20 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(0, 367, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__20); + __Pyx_GIVEREF(__pyx_tuple__20); + + /* "mtrand.pyx":388 + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_tuple__21 = PyTuple_Pack(1, __pyx_kp_s_size_is_not_compatible_with_inpu); if (unlikely(!__pyx_tuple__21)) __PYX_ERR(0, 388, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__21); + __Pyx_GIVEREF(__pyx_tuple__21); + + /* "mtrand.pyx":392 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + __pyx_tuple__22 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(0, 392, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__22); + __Pyx_GIVEREF(__pyx_tuple__22); + + /* "mtrand.pyx":409 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, p) + * return rv + */ + __pyx_tuple__23 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__23)) __PYX_ERR(0, 409, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__23); + __Pyx_GIVEREF(__pyx_tuple__23); + + /* "mtrand.pyx":416 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, p) + */ + __pyx_tuple__24 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__24)) __PYX_ERR(0, 416, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__24); + __Pyx_GIVEREF(__pyx_tuple__24); + + /* "mtrand.pyx":437 + * multi = np.broadcast(on, op, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_tuple__25 = PyTuple_Pack(1, __pyx_kp_s_size_is_not_compatible_with_inpu); if (unlikely(!__pyx_tuple__25)) __PYX_ERR(0, 437, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__25); + __Pyx_GIVEREF(__pyx_tuple__25); + + /* "mtrand.pyx":441 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + __pyx_tuple__26 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__26)) __PYX_ERR(0, 441, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__26); + __Pyx_GIVEREF(__pyx_tuple__26); + + /* "mtrand.pyx":458 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, n, m, N) + * return rv + */ + __pyx_tuple__27 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__27)) __PYX_ERR(0, 458, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__27); + __Pyx_GIVEREF(__pyx_tuple__27); + + /* "mtrand.pyx":465 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, n, m, N) + */ + __pyx_tuple__28 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__28)) __PYX_ERR(0, 465, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__28); + __Pyx_GIVEREF(__pyx_tuple__28); + + /* "mtrand.pyx":487 + * multi = np.broadcast(on, om, oN, array) + * if multi.shape != array.shape: + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * + * array_data = PyArray_DATA(array) + */ + __pyx_tuple__29 = PyTuple_Pack(1, __pyx_kp_s_size_is_not_compatible_with_inpu); if (unlikely(!__pyx_tuple__29)) __PYX_ERR(0, 487, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__29); + __Pyx_GIVEREF(__pyx_tuple__29); + + /* "mtrand.pyx":491 + * array_data = PyArray_DATA(array) + * + * with lock, nogil: # <<<<<<<<<<<<<< + * for i in range(multi.size): + * on_data = PyArray_MultiIter_DATA(multi, 0) + */ + __pyx_tuple__30 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__30)) __PYX_ERR(0, 491, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__30); + __Pyx_GIVEREF(__pyx_tuple__30); + + /* "mtrand.pyx":509 + * + * if size is None: + * with lock, nogil: # <<<<<<<<<<<<<< + * rv = func(state, a) + * return rv + */ + __pyx_tuple__31 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__31)) __PYX_ERR(0, 509, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__31); + __Pyx_GIVEREF(__pyx_tuple__31); + + /* "mtrand.pyx":516 + * length = PyArray_SIZE(array) + * array_data = PyArray_DATA(array) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, a) + */ + __pyx_tuple__32 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__32)) __PYX_ERR(0, 516, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__32); + __Pyx_GIVEREF(__pyx_tuple__32); + + /* "mtrand.pyx":537 + * array_data = PyArray_DATA(array) + * itera = PyArray_IterNew(oa) + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < length: + * array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + */ + __pyx_tuple__33 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__33)) __PYX_ERR(0, 537, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__33); + __Pyx_GIVEREF(__pyx_tuple__33); + + /* "mtrand.pyx":546 + * multi = PyArray_MultiIterNew(2, array, oa) + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") # <<<<<<<<<<<<<< + * with lock, nogil: + * for i from 0 <= i < multi.size: + */ + __pyx_tuple__34 = PyTuple_Pack(1, __pyx_kp_s_size_is_not_compatible_with_inpu); if (unlikely(!__pyx_tuple__34)) __PYX_ERR(0, 546, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__34); + __Pyx_GIVEREF(__pyx_tuple__34); + + /* "mtrand.pyx":547 + * if (multi.size != PyArray_SIZE(array)): + * raise ValueError("size is not compatible with inputs") + * with lock, nogil: # <<<<<<<<<<<<<< + * for i from 0 <= i < multi.size: + * oa_data = PyArray_MultiIter_DATA(multi, 1) + */ + __pyx_tuple__35 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(0, 547, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__35); + __Pyx_GIVEREF(__pyx_tuple__35); + + /* "mtrand.pyx":675 + * try: + * if seed is None: + * with self.lock: # <<<<<<<<<<<<<< + * errcode = rk_randomseed(self.internal_state) + * else: + */ + __pyx_tuple__36 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__36)) __PYX_ERR(0, 675, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__36); + __Pyx_GIVEREF(__pyx_tuple__36); + + /* "mtrand.pyx":680 + * idx = operator.index(seed) + * if (idx >= 2**32) or (idx < 0): + * raise ValueError("Seed must be between 0 and 2**32 - 1") # <<<<<<<<<<<<<< + * with self.lock: + * rk_seed(idx, self.internal_state) + */ + __pyx_tuple__37 = PyTuple_Pack(1, __pyx_kp_s_Seed_must_be_between_0_and_2_32); if (unlikely(!__pyx_tuple__37)) __PYX_ERR(0, 680, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__37); + __Pyx_GIVEREF(__pyx_tuple__37); + + /* "mtrand.pyx":681 + * if (idx >= 2**32) or (idx < 0): + * raise ValueError("Seed must be between 0 and 2**32 - 1") + * with self.lock: # <<<<<<<<<<<<<< + * rk_seed(idx, self.internal_state) + * except TypeError: + */ + __pyx_tuple__38 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__38)) __PYX_ERR(0, 681, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__38); + __Pyx_GIVEREF(__pyx_tuple__38); + + /* "mtrand.pyx":686 + * obj = np.asarray(seed) + * if obj.size == 0: + * raise ValueError("Seed must be non-empty") # <<<<<<<<<<<<<< + * obj = obj.astype(np.int64, casting='safe') + * if obj.ndim != 1: + */ + __pyx_tuple__39 = PyTuple_Pack(1, __pyx_kp_s_Seed_must_be_non_empty); if (unlikely(!__pyx_tuple__39)) __PYX_ERR(0, 686, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__39); + __Pyx_GIVEREF(__pyx_tuple__39); + + /* "mtrand.pyx":689 + * obj = obj.astype(np.int64, casting='safe') + * if obj.ndim != 1: + * raise ValueError("Seed array must be 1-d") # <<<<<<<<<<<<<< + * if ((obj >= 2**32) | (obj < 0)).any(): + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + */ + __pyx_tuple__40 = PyTuple_Pack(1, __pyx_kp_s_Seed_array_must_be_1_d); if (unlikely(!__pyx_tuple__40)) __PYX_ERR(0, 689, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__40); + __Pyx_GIVEREF(__pyx_tuple__40); + + /* "mtrand.pyx":691 + * raise ValueError("Seed array must be 1-d") + * if ((obj >= 2**32) | (obj < 0)).any(): + * raise ValueError("Seed values must be between 0 and 2**32 - 1") # <<<<<<<<<<<<<< + * obj = obj.astype('L', casting='unsafe') + * with self.lock: + */ + __pyx_tuple__41 = PyTuple_Pack(1, __pyx_kp_s_Seed_values_must_be_between_0_an); if (unlikely(!__pyx_tuple__41)) __PYX_ERR(0, 691, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__41); + __Pyx_GIVEREF(__pyx_tuple__41); + + /* "mtrand.pyx":692 + * if ((obj >= 2**32) | (obj < 0)).any(): + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + * obj = obj.astype('L', casting='unsafe') # <<<<<<<<<<<<<< + * with self.lock: + * init_by_array(self.internal_state, PyArray_DATA(obj), + */ + __pyx_tuple__42 = PyTuple_Pack(1, __pyx_n_s_L); if (unlikely(!__pyx_tuple__42)) __PYX_ERR(0, 692, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__42); + __Pyx_GIVEREF(__pyx_tuple__42); + + /* "mtrand.pyx":693 + * raise ValueError("Seed values must be between 0 and 2**32 - 1") + * obj = obj.astype('L', casting='unsafe') + * with self.lock: # <<<<<<<<<<<<<< + * init_by_array(self.internal_state, PyArray_DATA(obj), + * PyArray_DIM(obj, 0)) + */ + __pyx_tuple__43 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__43)) __PYX_ERR(0, 693, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__43); + __Pyx_GIVEREF(__pyx_tuple__43); + + /* "mtrand.pyx":729 + * cdef ndarray state "arrayObject_state" + * state = np.empty(624, np.uint) + * with self.lock: # <<<<<<<<<<<<<< + * memcpy(PyArray_DATA(state), (self.internal_state.key), 624*sizeof(long)) + * has_gauss = self.internal_state.has_gauss + */ + __pyx_tuple__44 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__44)) __PYX_ERR(0, 729, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__44); + __Pyx_GIVEREF(__pyx_tuple__44); + + /* "mtrand.pyx":788 + * algorithm_name = state[0] + * if algorithm_name != 'MT19937': + * raise ValueError("algorithm must be 'MT19937'") # <<<<<<<<<<<<<< + * key, pos = state[1:3] + * if len(state) == 3: + */ + __pyx_tuple__45 = PyTuple_Pack(1, __pyx_kp_s_algorithm_must_be_MT19937); if (unlikely(!__pyx_tuple__45)) __PYX_ERR(0, 788, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__45); + __Pyx_GIVEREF(__pyx_tuple__45); + + /* "mtrand.pyx":789 + * if algorithm_name != 'MT19937': + * raise ValueError("algorithm must be 'MT19937'") + * key, pos = state[1:3] # <<<<<<<<<<<<<< + * if len(state) == 3: + * has_gauss = 0 + */ + __pyx_slice__46 = PySlice_New(__pyx_int_1, __pyx_int_3, Py_None); if (unlikely(!__pyx_slice__46)) __PYX_ERR(0, 789, __pyx_L1_error) + __Pyx_GOTREF(__pyx_slice__46); + __Pyx_GIVEREF(__pyx_slice__46); + + /* "mtrand.pyx":794 + * cached_gaussian = 0.0 + * else: + * has_gauss, cached_gaussian = state[3:5] # <<<<<<<<<<<<<< + * try: + * obj = PyArray_ContiguousFromObject(key, NPY_ULONG, 1, 1) + */ + __pyx_slice__47 = PySlice_New(__pyx_int_3, __pyx_int_5, Py_None); if (unlikely(!__pyx_slice__47)) __PYX_ERR(0, 794, __pyx_L1_error) + __Pyx_GOTREF(__pyx_slice__47); + __Pyx_GIVEREF(__pyx_slice__47); + + /* "mtrand.pyx":801 + * obj = PyArray_ContiguousFromObject(key, NPY_LONG, 1, 1) + * if PyArray_DIM(obj, 0) != 624: + * raise ValueError("state must be 624 longs") # <<<<<<<<<<<<<< + * with self.lock: + * memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) + */ + __pyx_tuple__48 = PyTuple_Pack(1, __pyx_kp_s_state_must_be_624_longs); if (unlikely(!__pyx_tuple__48)) __PYX_ERR(0, 801, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__48); + __Pyx_GIVEREF(__pyx_tuple__48); + + /* "mtrand.pyx":802 + * if PyArray_DIM(obj, 0) != 624: + * raise ValueError("state must be 624 longs") + * with self.lock: # <<<<<<<<<<<<<< + * memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) + * self.internal_state.pos = pos + */ + __pyx_tuple__49 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__49)) __PYX_ERR(0, 802, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__49); + __Pyx_GIVEREF(__pyx_tuple__49); + + /* "mtrand.pyx":993 + * raise ValueError("high is out of bounds for %s" % (key,)) + * if ilow >= ihigh: + * raise ValueError("low >= high") # <<<<<<<<<<<<<< + * + * with self.lock: + */ + __pyx_tuple__51 = PyTuple_Pack(1, __pyx_kp_s_low_high); if (unlikely(!__pyx_tuple__51)) __PYX_ERR(0, 993, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__51); + __Pyx_GIVEREF(__pyx_tuple__51); + + /* "mtrand.pyx":995 + * raise ValueError("low >= high") + * + * with self.lock: # <<<<<<<<<<<<<< + * ret = randfunc(ilow, ihigh - 1, size, self.state_address) + * + */ + __pyx_tuple__52 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__52)) __PYX_ERR(0, 995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__52); + __Pyx_GIVEREF(__pyx_tuple__52); + __pyx_tuple__53 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__53)) __PYX_ERR(0, 995, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__53); + __Pyx_GIVEREF(__pyx_tuple__53); + + /* "mtrand.pyx":1028 + * cdef void *bytes + * bytestring = empty_py_bytes(length, &bytes) + * with self.lock, nogil: # <<<<<<<<<<<<<< + * rk_fill(bytes, length, self.internal_state) + * return bytestring + */ + __pyx_tuple__54 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__54)) __PYX_ERR(0, 1028, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__54); + __Pyx_GIVEREF(__pyx_tuple__54); + + /* "mtrand.pyx":1118 + * pop_size = operator.index(a.item()) + * except TypeError: + * raise ValueError("a must be 1-dimensional or an integer") # <<<<<<<<<<<<<< + * if pop_size <= 0: + * raise ValueError("a must be greater than 0") + */ + __pyx_tuple__55 = PyTuple_Pack(1, __pyx_kp_s_a_must_be_1_dimensional_or_an_in); if (unlikely(!__pyx_tuple__55)) __PYX_ERR(0, 1118, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__55); + __Pyx_GIVEREF(__pyx_tuple__55); + + /* "mtrand.pyx":1120 + * raise ValueError("a must be 1-dimensional or an integer") + * if pop_size <= 0: + * raise ValueError("a must be greater than 0") # <<<<<<<<<<<<<< + * elif a.ndim != 1: + * raise ValueError("a must be 1-dimensional") + */ + __pyx_tuple__56 = PyTuple_Pack(1, __pyx_kp_s_a_must_be_greater_than_0); if (unlikely(!__pyx_tuple__56)) __PYX_ERR(0, 1120, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__56); + __Pyx_GIVEREF(__pyx_tuple__56); + + /* "mtrand.pyx":1122 + * raise ValueError("a must be greater than 0") + * elif a.ndim != 1: + * raise ValueError("a must be 1-dimensional") # <<<<<<<<<<<<<< + * else: + * pop_size = a.shape[0] + */ + __pyx_tuple__57 = PyTuple_Pack(1, __pyx_kp_s_a_must_be_1_dimensional); if (unlikely(!__pyx_tuple__57)) __PYX_ERR(0, 1122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__57); + __Pyx_GIVEREF(__pyx_tuple__57); + + /* "mtrand.pyx":1126 + * pop_size = a.shape[0] + * if pop_size is 0: + * raise ValueError("a must be non-empty") # <<<<<<<<<<<<<< + * + * if p is not None: + */ + __pyx_tuple__58 = PyTuple_Pack(1, __pyx_kp_s_a_must_be_non_empty); if (unlikely(!__pyx_tuple__58)) __PYX_ERR(0, 1126, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__58); + __Pyx_GIVEREF(__pyx_tuple__58); + + /* "mtrand.pyx":1140 + * + * if p.ndim != 1: + * raise ValueError("p must be 1-dimensional") # <<<<<<<<<<<<<< + * if p.size != pop_size: + * raise ValueError("a and p must have same size") + */ + __pyx_tuple__59 = PyTuple_Pack(1, __pyx_kp_s_p_must_be_1_dimensional); if (unlikely(!__pyx_tuple__59)) __PYX_ERR(0, 1140, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__59); + __Pyx_GIVEREF(__pyx_tuple__59); + + /* "mtrand.pyx":1142 + * raise ValueError("p must be 1-dimensional") + * if p.size != pop_size: + * raise ValueError("a and p must have same size") # <<<<<<<<<<<<<< + * if np.logical_or.reduce(p < 0): + * raise ValueError("probabilities are not non-negative") + */ + __pyx_tuple__60 = PyTuple_Pack(1, __pyx_kp_s_a_and_p_must_have_same_size); if (unlikely(!__pyx_tuple__60)) __PYX_ERR(0, 1142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__60); + __Pyx_GIVEREF(__pyx_tuple__60); + + /* "mtrand.pyx":1144 + * raise ValueError("a and p must have same size") + * if np.logical_or.reduce(p < 0): + * raise ValueError("probabilities are not non-negative") # <<<<<<<<<<<<<< + * if abs(kahan_sum(pix, d) - 1.) > atol: + * raise ValueError("probabilities do not sum to 1") + */ + __pyx_tuple__61 = PyTuple_Pack(1, __pyx_kp_s_probabilities_are_not_non_negati); if (unlikely(!__pyx_tuple__61)) __PYX_ERR(0, 1144, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__61); + __Pyx_GIVEREF(__pyx_tuple__61); + + /* "mtrand.pyx":1146 + * raise ValueError("probabilities are not non-negative") + * if abs(kahan_sum(pix, d) - 1.) > atol: + * raise ValueError("probabilities do not sum to 1") # <<<<<<<<<<<<<< + * + * shape = size + */ + __pyx_tuple__62 = PyTuple_Pack(1, __pyx_kp_s_probabilities_do_not_sum_to_1); if (unlikely(!__pyx_tuple__62)) __PYX_ERR(0, 1146, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__62); + __Pyx_GIVEREF(__pyx_tuple__62); + + /* "mtrand.pyx":1166 + * else: + * if size > pop_size: + * raise ValueError("Cannot take a larger sample than " # <<<<<<<<<<<<<< + * "population when 'replace=False'") + * + */ + __pyx_tuple__63 = PyTuple_Pack(1, __pyx_kp_s_Cannot_take_a_larger_sample_than); if (unlikely(!__pyx_tuple__63)) __PYX_ERR(0, 1166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__63); + __Pyx_GIVEREF(__pyx_tuple__63); + + /* "mtrand.pyx":1171 + * if p is not None: + * if np.count_nonzero(p > 0) < size: + * raise ValueError("Fewer non-zero entries in p than size") # <<<<<<<<<<<<<< + * n_uniq = 0 + * p = p.copy() + */ + __pyx_tuple__64 = PyTuple_Pack(1, __pyx_kp_s_Fewer_non_zero_entries_in_p_than); if (unlikely(!__pyx_tuple__64)) __PYX_ERR(0, 1171, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__64); + __Pyx_GIVEREF(__pyx_tuple__64); + + /* "mtrand.pyx":1196 + * if shape is None and isinstance(idx, np.ndarray): + * # In most cases a scalar will have been made an array + * idx = idx.item(0) # <<<<<<<<<<<<<< + * + * #Use samples as indices for a if a is array-like + */ + __pyx_tuple__65 = PyTuple_Pack(1, __pyx_int_0); if (unlikely(!__pyx_tuple__65)) __PYX_ERR(0, 1196, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__65); + __Pyx_GIVEREF(__pyx_tuple__65); + + /* "mtrand.pyx":1208 + * # array, taking into account that np.array(item) may not work + * # for object arrays. + * res = np.empty((), dtype=a.dtype) # <<<<<<<<<<<<<< + * res[()] = a[idx] + * return res + */ + __pyx_tuple__66 = PyTuple_Pack(1, __pyx_empty_tuple); if (unlikely(!__pyx_tuple__66)) __PYX_ERR(0, 1208, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__66); + __Pyx_GIVEREF(__pyx_tuple__66); + + /* "mtrand.pyx":1305 + * + * if not npy_isfinite(fscale): + * raise OverflowError('Range exceeds valid bounds') # <<<<<<<<<<<<<< + * + * return cont2_array_sc(self.internal_state, rk_uniform, size, flow, + */ + __pyx_tuple__67 = PyTuple_Pack(1, __pyx_kp_s_Range_exceeds_valid_bounds); if (unlikely(!__pyx_tuple__67)) __PYX_ERR(0, 1305, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__67); + __Pyx_GIVEREF(__pyx_tuple__67); + + /* "mtrand.pyx":1316 + * + * if not np.all(np.isfinite(odiff)): + * raise OverflowError('Range exceeds valid bounds') # <<<<<<<<<<<<<< + * + * return cont2_array(self.internal_state, rk_uniform, size, olow, odiff, + */ + __pyx_tuple__68 = PyTuple_Pack(1, __pyx_kp_s_Range_exceeds_valid_bounds); if (unlikely(!__pyx_tuple__68)) __PYX_ERR(0, 1316, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__68); + __Pyx_GIVEREF(__pyx_tuple__68); + + /* "mtrand.pyx":1651 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_normal, size, floc, + * fscale, self.lock) + */ + __pyx_tuple__69 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__69)) __PYX_ERR(0, 1651, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__69); + __Pyx_GIVEREF(__pyx_tuple__69); + + /* "mtrand.pyx":1656 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_normal, size, oloc, oscale, + * self.lock) + */ + __pyx_tuple__70 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__70)) __PYX_ERR(0, 1656, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__70); + __Pyx_GIVEREF(__pyx_tuple__70); + + /* "mtrand.pyx":1709 + * + * if fa <= 0: + * raise ValueError("a <= 0") # <<<<<<<<<<<<<< + * if fb <= 0: + * raise ValueError("b <= 0") + */ + __pyx_tuple__71 = PyTuple_Pack(1, __pyx_kp_s_a_0); if (unlikely(!__pyx_tuple__71)) __PYX_ERR(0, 1709, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__71); + __Pyx_GIVEREF(__pyx_tuple__71); + + /* "mtrand.pyx":1711 + * raise ValueError("a <= 0") + * if fb <= 0: + * raise ValueError("b <= 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb, + * self.lock) + */ + __pyx_tuple__72 = PyTuple_Pack(1, __pyx_kp_s_b_0); if (unlikely(!__pyx_tuple__72)) __PYX_ERR(0, 1711, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__72); + __Pyx_GIVEREF(__pyx_tuple__72); + + /* "mtrand.pyx":1716 + * + * if np.any(np.less_equal(oa, 0)): + * raise ValueError("a <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less_equal(ob, 0)): + * raise ValueError("b <= 0") + */ + __pyx_tuple__73 = PyTuple_Pack(1, __pyx_kp_s_a_0); if (unlikely(!__pyx_tuple__73)) __PYX_ERR(0, 1716, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__73); + __Pyx_GIVEREF(__pyx_tuple__73); + + /* "mtrand.pyx":1718 + * raise ValueError("a <= 0") + * if np.any(np.less_equal(ob, 0)): + * raise ValueError("b <= 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_beta, size, oa, ob, + * self.lock) + */ + __pyx_tuple__74 = PyTuple_Pack(1, __pyx_kp_s_b_0); if (unlikely(!__pyx_tuple__74)) __PYX_ERR(0, 1718, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__74); + __Pyx_GIVEREF(__pyx_tuple__74); + + /* "mtrand.pyx":1775 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_exponential, size, + * fscale, self.lock) + */ + __pyx_tuple__75 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__75)) __PYX_ERR(0, 1775, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__75); + __Pyx_GIVEREF(__pyx_tuple__75); + + /* "mtrand.pyx":1780 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_exponential, size, oscale, + * self.lock) + */ + __pyx_tuple__76 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__76)) __PYX_ERR(0, 1780, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__76); + __Pyx_GIVEREF(__pyx_tuple__76); + + /* "mtrand.pyx":1892 + * fshape = PyFloat_AsDouble(shape) + * if np.signbit(fshape): + * raise ValueError("shape < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_standard_gamma, + * size, fshape, self.lock) + */ + __pyx_tuple__77 = PyTuple_Pack(1, __pyx_kp_s_shape_0); if (unlikely(!__pyx_tuple__77)) __PYX_ERR(0, 1892, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__77); + __Pyx_GIVEREF(__pyx_tuple__77); + + /* "mtrand.pyx":1897 + * + * if np.any(np.signbit(oshape)): + * raise ValueError("shape < 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_standard_gamma, size, + * oshape, self.lock) + */ + __pyx_tuple__78 = PyTuple_Pack(1, __pyx_kp_s_shape_0); if (unlikely(!__pyx_tuple__78)) __PYX_ERR(0, 1897, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__78); + __Pyx_GIVEREF(__pyx_tuple__78); + + /* "mtrand.pyx":1984 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fshape): + * raise ValueError("shape < 0") # <<<<<<<<<<<<<< + * if np.signbit(fscale): + * raise ValueError("scale < 0") + */ + __pyx_tuple__79 = PyTuple_Pack(1, __pyx_kp_s_shape_0); if (unlikely(!__pyx_tuple__79)) __PYX_ERR(0, 1984, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__79); + __Pyx_GIVEREF(__pyx_tuple__79); + + /* "mtrand.pyx":1986 + * raise ValueError("shape < 0") + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, + * fscale, self.lock) + */ + __pyx_tuple__80 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__80)) __PYX_ERR(0, 1986, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__80); + __Pyx_GIVEREF(__pyx_tuple__80); + + /* "mtrand.pyx":1991 + * + * if np.any(np.signbit(oshape)): + * raise ValueError("shape < 0") # <<<<<<<<<<<<<< + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") + */ + __pyx_tuple__81 = PyTuple_Pack(1, __pyx_kp_s_shape_0); if (unlikely(!__pyx_tuple__81)) __PYX_ERR(0, 1991, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__81); + __Pyx_GIVEREF(__pyx_tuple__81); + + /* "mtrand.pyx":1993 + * raise ValueError("shape < 0") + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale, + * self.lock) + */ + __pyx_tuple__82 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__82)) __PYX_ERR(0, 1993, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__82); + __Pyx_GIVEREF(__pyx_tuple__82); + + /* "mtrand.pyx":2091 + * + * if fdfnum <= 0: + * raise ValueError("dfnum <= 0") # <<<<<<<<<<<<<< + * if fdfden <= 0: + * raise ValueError("dfden <= 0") + */ + __pyx_tuple__83 = PyTuple_Pack(1, __pyx_kp_s_dfnum_0); if (unlikely(!__pyx_tuple__83)) __PYX_ERR(0, 2091, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__83); + __Pyx_GIVEREF(__pyx_tuple__83); + + /* "mtrand.pyx":2093 + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: + * raise ValueError("dfden <= 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, + * fdfden, self.lock) + */ + __pyx_tuple__84 = PyTuple_Pack(1, __pyx_kp_s_dfden_0); if (unlikely(!__pyx_tuple__84)) __PYX_ERR(0, 2093, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__84); + __Pyx_GIVEREF(__pyx_tuple__84); + + /* "mtrand.pyx":2098 + * + * if np.any(np.less_equal(odfnum, 0.0)): + * raise ValueError("dfnum <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") + */ + __pyx_tuple__85 = PyTuple_Pack(1, __pyx_kp_s_dfnum_0); if (unlikely(!__pyx_tuple__85)) __PYX_ERR(0, 2098, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__85); + __Pyx_GIVEREF(__pyx_tuple__85); + + /* "mtrand.pyx":2100 + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_f, size, odfnum, odfden, + * self.lock) + */ + __pyx_tuple__86 = PyTuple_Pack(1, __pyx_kp_s_dfden_0); if (unlikely(!__pyx_tuple__86)) __PYX_ERR(0, 2100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__86); + __Pyx_GIVEREF(__pyx_tuple__86); + + /* "mtrand.pyx":2188 + * + * if fdfnum <= 0: + * raise ValueError("dfnum <= 0") # <<<<<<<<<<<<<< + * if fdfden <= 0: + * raise ValueError("dfden <= 0") + */ + __pyx_tuple__87 = PyTuple_Pack(1, __pyx_kp_s_dfnum_0); if (unlikely(!__pyx_tuple__87)) __PYX_ERR(0, 2188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__87); + __Pyx_GIVEREF(__pyx_tuple__87); + + /* "mtrand.pyx":2190 + * raise ValueError("dfnum <= 0") + * if fdfden <= 0: + * raise ValueError("dfden <= 0") # <<<<<<<<<<<<<< + * if fnonc < 0: + * raise ValueError("nonc < 0") + */ + __pyx_tuple__88 = PyTuple_Pack(1, __pyx_kp_s_dfden_0); if (unlikely(!__pyx_tuple__88)) __PYX_ERR(0, 2190, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__88); + __Pyx_GIVEREF(__pyx_tuple__88); + + /* "mtrand.pyx":2192 + * raise ValueError("dfden <= 0") + * if fnonc < 0: + * raise ValueError("nonc < 0") # <<<<<<<<<<<<<< + * return cont3_array_sc(self.internal_state, rk_noncentral_f, size, + * fdfnum, fdfden, fnonc, self.lock) + */ + __pyx_tuple__89 = PyTuple_Pack(1, __pyx_kp_s_nonc_0); if (unlikely(!__pyx_tuple__89)) __PYX_ERR(0, 2192, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__89); + __Pyx_GIVEREF(__pyx_tuple__89); + + /* "mtrand.pyx":2197 + * + * if np.any(np.less_equal(odfnum, 0.0)): + * raise ValueError("dfnum <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") + */ + __pyx_tuple__90 = PyTuple_Pack(1, __pyx_kp_s_dfnum_0); if (unlikely(!__pyx_tuple__90)) __PYX_ERR(0, 2197, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__90); + __Pyx_GIVEREF(__pyx_tuple__90); + + /* "mtrand.pyx":2199 + * raise ValueError("dfnum <= 0") + * if np.any(np.less_equal(odfden, 0.0)): + * raise ValueError("dfden <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") + */ + __pyx_tuple__91 = PyTuple_Pack(1, __pyx_kp_s_dfden_0); if (unlikely(!__pyx_tuple__91)) __PYX_ERR(0, 2199, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__91); + __Pyx_GIVEREF(__pyx_tuple__91); + + /* "mtrand.pyx":2201 + * raise ValueError("dfden <= 0") + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") # <<<<<<<<<<<<<< + * return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum, + * odfden, ononc, self.lock) + */ + __pyx_tuple__92 = PyTuple_Pack(1, __pyx_kp_s_nonc_0); if (unlikely(!__pyx_tuple__92)) __PYX_ERR(0, 2201, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__92); + __Pyx_GIVEREF(__pyx_tuple__92); + + /* "mtrand.pyx":2277 + * + * if fdf <= 0: + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf, + * self.lock) + */ + __pyx_tuple__93 = PyTuple_Pack(1, __pyx_kp_s_df_0); if (unlikely(!__pyx_tuple__93)) __PYX_ERR(0, 2277, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__93); + __Pyx_GIVEREF(__pyx_tuple__93); + + /* "mtrand.pyx":2282 + * + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_chisquare, size, odf, + * self.lock) + */ + __pyx_tuple__94 = PyTuple_Pack(1, __pyx_kp_s_df_0); if (unlikely(!__pyx_tuple__94)) __PYX_ERR(0, 2282, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__94); + __Pyx_GIVEREF(__pyx_tuple__94); + + /* "mtrand.pyx":2379 + * + * if fdf <= 0: + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * if fnonc < 0: + * raise ValueError("nonc < 0") + */ + __pyx_tuple__95 = PyTuple_Pack(1, __pyx_kp_s_df_0); if (unlikely(!__pyx_tuple__95)) __PYX_ERR(0, 2379, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__95); + __Pyx_GIVEREF(__pyx_tuple__95); + + /* "mtrand.pyx":2381 + * raise ValueError("df <= 0") + * if fnonc < 0: + * raise ValueError("nonc < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_noncentral_chisquare, + * size, fdf, fnonc, self.lock) + */ + __pyx_tuple__96 = PyTuple_Pack(1, __pyx_kp_s_nonc_0); if (unlikely(!__pyx_tuple__96)) __PYX_ERR(0, 2381, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__96); + __Pyx_GIVEREF(__pyx_tuple__96); + + /* "mtrand.pyx":2386 + * + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") + */ + __pyx_tuple__97 = PyTuple_Pack(1, __pyx_kp_s_df_0); if (unlikely(!__pyx_tuple__97)) __PYX_ERR(0, 2386, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__97); + __Pyx_GIVEREF(__pyx_tuple__97); + + /* "mtrand.pyx":2388 + * raise ValueError("df <= 0") + * if np.any(np.less(ononc, 0.0)): + * raise ValueError("nonc < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_noncentral_chisquare, size, + * odf, ononc, self.lock) + */ + __pyx_tuple__98 = PyTuple_Pack(1, __pyx_kp_s_nonc_0); if (unlikely(!__pyx_tuple__98)) __PYX_ERR(0, 2388, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__98); + __Pyx_GIVEREF(__pyx_tuple__98); + + /* "mtrand.pyx":2553 + * + * if fdf <= 0: + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_standard_t, size, + * fdf, self.lock) + */ + __pyx_tuple__99 = PyTuple_Pack(1, __pyx_kp_s_df_0); if (unlikely(!__pyx_tuple__99)) __PYX_ERR(0, 2553, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__99); + __Pyx_GIVEREF(__pyx_tuple__99); + + /* "mtrand.pyx":2558 + * + * if np.any(np.less_equal(odf, 0.0)): + * raise ValueError("df <= 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_standard_t, size, odf, + * self.lock) + */ + __pyx_tuple__100 = PyTuple_Pack(1, __pyx_kp_s_df_0); if (unlikely(!__pyx_tuple__100)) __PYX_ERR(0, 2558, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__100); + __Pyx_GIVEREF(__pyx_tuple__100); + + /* "mtrand.pyx":2651 + * + * if fkappa < 0: + * raise ValueError("kappa < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, + * fkappa, self.lock) + */ + __pyx_tuple__101 = PyTuple_Pack(1, __pyx_kp_s_kappa_0); if (unlikely(!__pyx_tuple__101)) __PYX_ERR(0, 2651, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__101); + __Pyx_GIVEREF(__pyx_tuple__101); + + /* "mtrand.pyx":2656 + * + * if np.any(np.less(okappa, 0.0)): + * raise ValueError("kappa < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa, + * self.lock) + */ + __pyx_tuple__102 = PyTuple_Pack(1, __pyx_kp_s_kappa_0); if (unlikely(!__pyx_tuple__102)) __PYX_ERR(0, 2656, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__102); + __Pyx_GIVEREF(__pyx_tuple__102); + + /* "mtrand.pyx":2762 + * + * if fa <= 0: + * raise ValueError("a <= 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_pareto, size, fa, + * self.lock) + */ + __pyx_tuple__103 = PyTuple_Pack(1, __pyx_kp_s_a_0); if (unlikely(!__pyx_tuple__103)) __PYX_ERR(0, 2762, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__103); + __Pyx_GIVEREF(__pyx_tuple__103); + + /* "mtrand.pyx":2767 + * + * if np.any(np.less_equal(oa, 0.0)): + * raise ValueError("a <= 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock) + * + */ + __pyx_tuple__104 = PyTuple_Pack(1, __pyx_kp_s_a_0); if (unlikely(!__pyx_tuple__104)) __PYX_ERR(0, 2767, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__104); + __Pyx_GIVEREF(__pyx_tuple__104); + + /* "mtrand.pyx":2871 + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): + * raise ValueError("a < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_weibull, size, fa, + * self.lock) + */ + __pyx_tuple__105 = PyTuple_Pack(1, __pyx_kp_s_a_0_2); if (unlikely(!__pyx_tuple__105)) __PYX_ERR(0, 2871, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__105); + __Pyx_GIVEREF(__pyx_tuple__105); + + /* "mtrand.pyx":2876 + * + * if np.any(np.signbit(oa)): + * raise ValueError("a < 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_weibull, size, oa, + * self.lock) + */ + __pyx_tuple__106 = PyTuple_Pack(1, __pyx_kp_s_a_0_2); if (unlikely(!__pyx_tuple__106)) __PYX_ERR(0, 2876, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__106); + __Pyx_GIVEREF(__pyx_tuple__106); + + /* "mtrand.pyx":2983 + * fa = PyFloat_AsDouble(a) + * if np.signbit(fa): + * raise ValueError("a < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_power, size, fa, + * self.lock) + */ + __pyx_tuple__107 = PyTuple_Pack(1, __pyx_kp_s_a_0_2); if (unlikely(!__pyx_tuple__107)) __PYX_ERR(0, 2983, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__107); + __Pyx_GIVEREF(__pyx_tuple__107); + + /* "mtrand.pyx":2988 + * + * if np.any(np.signbit(oa)): + * raise ValueError("a < 0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_power, size, oa, self.lock) + * + */ + __pyx_tuple__108 = PyTuple_Pack(1, __pyx_kp_s_a_0_2); if (unlikely(!__pyx_tuple__108)) __PYX_ERR(0, 2988, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__108); + __Pyx_GIVEREF(__pyx_tuple__108); + + /* "mtrand.pyx":3080 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_laplace, size, floc, + * fscale, self.lock) + */ + __pyx_tuple__109 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__109)) __PYX_ERR(0, 3080, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__109); + __Pyx_GIVEREF(__pyx_tuple__109); + + /* "mtrand.pyx":3085 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale, + * self.lock) + */ + __pyx_tuple__110 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__110)) __PYX_ERR(0, 3085, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__110); + __Pyx_GIVEREF(__pyx_tuple__110); + + /* "mtrand.pyx":3211 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, + * fscale, self.lock) + */ + __pyx_tuple__111 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__111)) __PYX_ERR(0, 3211, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__111); + __Pyx_GIVEREF(__pyx_tuple__111); + + /* "mtrand.pyx":3216 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale, + * self.lock) + */ + __pyx_tuple__112 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__112)) __PYX_ERR(0, 3216, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__112); + __Pyx_GIVEREF(__pyx_tuple__112); + + /* "mtrand.pyx":3304 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_logistic, size, floc, + * fscale, self.lock) + */ + __pyx_tuple__113 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__113)) __PYX_ERR(0, 3304, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__113); + __Pyx_GIVEREF(__pyx_tuple__113); + + /* "mtrand.pyx":3309 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_logistic, size, oloc, + * oscale, self.lock) + */ + __pyx_tuple__114 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__114)) __PYX_ERR(0, 3309, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__114); + __Pyx_GIVEREF(__pyx_tuple__114); + + /* "mtrand.pyx":3428 + * fsigma = PyFloat_AsDouble(sigma) + * if np.signbit(fsigma): + * raise ValueError("sigma < 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_lognormal, size, + * fmean, fsigma, self.lock) + */ + __pyx_tuple__115 = PyTuple_Pack(1, __pyx_kp_s_sigma_0); if (unlikely(!__pyx_tuple__115)) __PYX_ERR(0, 3428, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__115); + __Pyx_GIVEREF(__pyx_tuple__115); + + /* "mtrand.pyx":3433 + * + * if np.any(np.signbit(osigma)): + * raise ValueError("sigma < 0.0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_lognormal, size, omean, + * osigma, self.lock) + */ + __pyx_tuple__116 = PyTuple_Pack(1, __pyx_kp_s_sigma_0_0); if (unlikely(!__pyx_tuple__116)) __PYX_ERR(0, 3433, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__116); + __Pyx_GIVEREF(__pyx_tuple__116); + + /* "mtrand.pyx":3507 + * fscale = PyFloat_AsDouble(scale) + * if np.signbit(fscale): + * raise ValueError("scale < 0") # <<<<<<<<<<<<<< + * return cont1_array_sc(self.internal_state, rk_rayleigh, size, + * fscale, self.lock) + */ + __pyx_tuple__117 = PyTuple_Pack(1, __pyx_kp_s_scale_0); if (unlikely(!__pyx_tuple__117)) __PYX_ERR(0, 3507, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__117); + __Pyx_GIVEREF(__pyx_tuple__117); + + /* "mtrand.pyx":3512 + * + * if np.any(np.signbit(oscale)): + * raise ValueError("scale < 0.0") # <<<<<<<<<<<<<< + * return cont1_array(self.internal_state, rk_rayleigh, size, oscale, + * self.lock) + */ + __pyx_tuple__118 = PyTuple_Pack(1, __pyx_kp_s_scale_0_0); if (unlikely(!__pyx_tuple__118)) __PYX_ERR(0, 3512, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__118); + __Pyx_GIVEREF(__pyx_tuple__118); + + /* "mtrand.pyx":3590 + * + * if fmean <= 0: + * raise ValueError("mean <= 0") # <<<<<<<<<<<<<< + * if fscale <= 0: + * raise ValueError("scale <= 0") + */ + __pyx_tuple__119 = PyTuple_Pack(1, __pyx_kp_s_mean_0); if (unlikely(!__pyx_tuple__119)) __PYX_ERR(0, 3590, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__119); + __Pyx_GIVEREF(__pyx_tuple__119); + + /* "mtrand.pyx":3592 + * raise ValueError("mean <= 0") + * if fscale <= 0: + * raise ValueError("scale <= 0") # <<<<<<<<<<<<<< + * return cont2_array_sc(self.internal_state, rk_wald, size, fmean, + * fscale, self.lock) + */ + __pyx_tuple__120 = PyTuple_Pack(1, __pyx_kp_s_scale_0_2); if (unlikely(!__pyx_tuple__120)) __PYX_ERR(0, 3592, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__120); + __Pyx_GIVEREF(__pyx_tuple__120); + + /* "mtrand.pyx":3597 + * + * if np.any(np.less_equal(omean,0.0)): + * raise ValueError("mean <= 0.0") # <<<<<<<<<<<<<< + * elif np.any(np.less_equal(oscale,0.0)): + * raise ValueError("scale <= 0.0") + */ + __pyx_tuple__121 = PyTuple_Pack(1, __pyx_kp_s_mean_0_0); if (unlikely(!__pyx_tuple__121)) __PYX_ERR(0, 3597, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__121); + __Pyx_GIVEREF(__pyx_tuple__121); + + /* "mtrand.pyx":3599 + * raise ValueError("mean <= 0.0") + * elif np.any(np.less_equal(oscale,0.0)): + * raise ValueError("scale <= 0.0") # <<<<<<<<<<<<<< + * return cont2_array(self.internal_state, rk_wald, size, omean, oscale, + * self.lock) + */ + __pyx_tuple__122 = PyTuple_Pack(1, __pyx_kp_s_scale_0_0_2); if (unlikely(!__pyx_tuple__122)) __PYX_ERR(0, 3599, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__122); + __Pyx_GIVEREF(__pyx_tuple__122); + + /* "mtrand.pyx":3679 + * + * if fleft > fmode: + * raise ValueError("left > mode") # <<<<<<<<<<<<<< + * if fmode > fright: + * raise ValueError("mode > right") + */ + __pyx_tuple__123 = PyTuple_Pack(1, __pyx_kp_s_left_mode); if (unlikely(!__pyx_tuple__123)) __PYX_ERR(0, 3679, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__123); + __Pyx_GIVEREF(__pyx_tuple__123); + + /* "mtrand.pyx":3681 + * raise ValueError("left > mode") + * if fmode > fright: + * raise ValueError("mode > right") # <<<<<<<<<<<<<< + * if fleft == fright: + * raise ValueError("left == right") + */ + __pyx_tuple__124 = PyTuple_Pack(1, __pyx_kp_s_mode_right); if (unlikely(!__pyx_tuple__124)) __PYX_ERR(0, 3681, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__124); + __Pyx_GIVEREF(__pyx_tuple__124); + + /* "mtrand.pyx":3683 + * raise ValueError("mode > right") + * if fleft == fright: + * raise ValueError("left == right") # <<<<<<<<<<<<<< + * return cont3_array_sc(self.internal_state, rk_triangular, size, + * fleft, fmode, fright, self.lock) + */ + __pyx_tuple__125 = PyTuple_Pack(1, __pyx_kp_s_left_right); if (unlikely(!__pyx_tuple__125)) __PYX_ERR(0, 3683, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__125); + __Pyx_GIVEREF(__pyx_tuple__125); + + /* "mtrand.pyx":3688 + * + * if np.any(np.greater(oleft, omode)): + * raise ValueError("left > mode") # <<<<<<<<<<<<<< + * if np.any(np.greater(omode, oright)): + * raise ValueError("mode > right") + */ + __pyx_tuple__126 = PyTuple_Pack(1, __pyx_kp_s_left_mode); if (unlikely(!__pyx_tuple__126)) __PYX_ERR(0, 3688, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__126); + __Pyx_GIVEREF(__pyx_tuple__126); + + /* "mtrand.pyx":3690 + * raise ValueError("left > mode") + * if np.any(np.greater(omode, oright)): + * raise ValueError("mode > right") # <<<<<<<<<<<<<< + * if np.any(np.equal(oleft, oright)): + * raise ValueError("left == right") + */ + __pyx_tuple__127 = PyTuple_Pack(1, __pyx_kp_s_mode_right); if (unlikely(!__pyx_tuple__127)) __PYX_ERR(0, 3690, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__127); + __Pyx_GIVEREF(__pyx_tuple__127); + + /* "mtrand.pyx":3692 + * raise ValueError("mode > right") + * if np.any(np.equal(oleft, oright)): + * raise ValueError("left == right") # <<<<<<<<<<<<<< + * return cont3_array(self.internal_state, rk_triangular, size, oleft, + * omode, oright, self.lock) + */ + __pyx_tuple__128 = PyTuple_Pack(1, __pyx_kp_s_left_right); if (unlikely(!__pyx_tuple__128)) __PYX_ERR(0, 3692, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__128); + __Pyx_GIVEREF(__pyx_tuple__128); + + /* "mtrand.pyx":3794 + * + * if ln < 0: + * raise ValueError("n < 0") # <<<<<<<<<<<<<< + * if fp < 0: + * raise ValueError("p < 0") + */ + __pyx_tuple__129 = PyTuple_Pack(1, __pyx_kp_s_n_0); if (unlikely(!__pyx_tuple__129)) __PYX_ERR(0, 3794, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__129); + __Pyx_GIVEREF(__pyx_tuple__129); + + /* "mtrand.pyx":3796 + * raise ValueError("n < 0") + * if fp < 0: + * raise ValueError("p < 0") # <<<<<<<<<<<<<< + * elif fp > 1: + * raise ValueError("p > 1") + */ + __pyx_tuple__130 = PyTuple_Pack(1, __pyx_kp_s_p_0); if (unlikely(!__pyx_tuple__130)) __PYX_ERR(0, 3796, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__130); + __Pyx_GIVEREF(__pyx_tuple__130); + + /* "mtrand.pyx":3798 + * raise ValueError("p < 0") + * elif fp > 1: + * raise ValueError("p > 1") # <<<<<<<<<<<<<< + * elif np.isnan(fp): + * raise ValueError("p is nan") + */ + __pyx_tuple__131 = PyTuple_Pack(1, __pyx_kp_s_p_1); if (unlikely(!__pyx_tuple__131)) __PYX_ERR(0, 3798, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__131); + __Pyx_GIVEREF(__pyx_tuple__131); + + /* "mtrand.pyx":3800 + * raise ValueError("p > 1") + * elif np.isnan(fp): + * raise ValueError("p is nan") # <<<<<<<<<<<<<< + * return discnp_array_sc(self.internal_state, rk_binomial, size, ln, + * fp, self.lock) + */ + __pyx_tuple__132 = PyTuple_Pack(1, __pyx_kp_s_p_is_nan); if (unlikely(!__pyx_tuple__132)) __PYX_ERR(0, 3800, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__132); + __Pyx_GIVEREF(__pyx_tuple__132); + + /* "mtrand.pyx":3805 + * + * if np.any(np.less(n, 0)): + * raise ValueError("n < 0") # <<<<<<<<<<<<<< + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") + */ + __pyx_tuple__133 = PyTuple_Pack(1, __pyx_kp_s_n_0); if (unlikely(!__pyx_tuple__133)) __PYX_ERR(0, 3805, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__133); + __Pyx_GIVEREF(__pyx_tuple__133); + + /* "mtrand.pyx":3807 + * raise ValueError("n < 0") + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") # <<<<<<<<<<<<<< + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") + */ + __pyx_tuple__134 = PyTuple_Pack(1, __pyx_kp_s_p_0); if (unlikely(!__pyx_tuple__134)) __PYX_ERR(0, 3807, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__134); + __Pyx_GIVEREF(__pyx_tuple__134); + + /* "mtrand.pyx":3809 + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") # <<<<<<<<<<<<<< + * return discnp_array(self.internal_state, rk_binomial, size, on, op, + * self.lock) + */ + __pyx_tuple__135 = PyTuple_Pack(1, __pyx_kp_s_p_1); if (unlikely(!__pyx_tuple__135)) __PYX_ERR(0, 3809, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__135); + __Pyx_GIVEREF(__pyx_tuple__135); + + /* "mtrand.pyx":3897 + * + * if fn <= 0: + * raise ValueError("n <= 0") # <<<<<<<<<<<<<< + * if fp < 0: + * raise ValueError("p < 0") + */ + __pyx_tuple__136 = PyTuple_Pack(1, __pyx_kp_s_n_0_2); if (unlikely(!__pyx_tuple__136)) __PYX_ERR(0, 3897, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__136); + __Pyx_GIVEREF(__pyx_tuple__136); + + /* "mtrand.pyx":3899 + * raise ValueError("n <= 0") + * if fp < 0: + * raise ValueError("p < 0") # <<<<<<<<<<<<<< + * elif fp > 1: + * raise ValueError("p > 1") + */ + __pyx_tuple__137 = PyTuple_Pack(1, __pyx_kp_s_p_0); if (unlikely(!__pyx_tuple__137)) __PYX_ERR(0, 3899, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__137); + __Pyx_GIVEREF(__pyx_tuple__137); + + /* "mtrand.pyx":3901 + * raise ValueError("p < 0") + * elif fp > 1: + * raise ValueError("p > 1") # <<<<<<<<<<<<<< + * return discdd_array_sc(self.internal_state, rk_negative_binomial, + * size, fn, fp, self.lock) + */ + __pyx_tuple__138 = PyTuple_Pack(1, __pyx_kp_s_p_1); if (unlikely(!__pyx_tuple__138)) __PYX_ERR(0, 3901, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__138); + __Pyx_GIVEREF(__pyx_tuple__138); + + /* "mtrand.pyx":3906 + * + * if np.any(np.less_equal(n, 0)): + * raise ValueError("n <= 0") # <<<<<<<<<<<<<< + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") + */ + __pyx_tuple__139 = PyTuple_Pack(1, __pyx_kp_s_n_0_2); if (unlikely(!__pyx_tuple__139)) __PYX_ERR(0, 3906, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__139); + __Pyx_GIVEREF(__pyx_tuple__139); + + /* "mtrand.pyx":3908 + * raise ValueError("n <= 0") + * if np.any(np.less(p, 0)): + * raise ValueError("p < 0") # <<<<<<<<<<<<<< + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") + */ + __pyx_tuple__140 = PyTuple_Pack(1, __pyx_kp_s_p_0); if (unlikely(!__pyx_tuple__140)) __PYX_ERR(0, 3908, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__140); + __Pyx_GIVEREF(__pyx_tuple__140); + + /* "mtrand.pyx":3910 + * raise ValueError("p < 0") + * if np.any(np.greater(p, 1)): + * raise ValueError("p > 1") # <<<<<<<<<<<<<< + * return discdd_array(self.internal_state, rk_negative_binomial, size, + * on, op, self.lock) + */ + __pyx_tuple__141 = PyTuple_Pack(1, __pyx_kp_s_p_1); if (unlikely(!__pyx_tuple__141)) __PYX_ERR(0, 3910, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__141); + __Pyx_GIVEREF(__pyx_tuple__141); + + /* "mtrand.pyx":3989 + * + * if lam < 0: + * raise ValueError("lam < 0") # <<<<<<<<<<<<<< + * if lam > self.poisson_lam_max: + * raise ValueError("lam value too large") + */ + __pyx_tuple__142 = PyTuple_Pack(1, __pyx_kp_s_lam_0); if (unlikely(!__pyx_tuple__142)) __PYX_ERR(0, 3989, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__142); + __Pyx_GIVEREF(__pyx_tuple__142); + + /* "mtrand.pyx":3991 + * raise ValueError("lam < 0") + * if lam > self.poisson_lam_max: + * raise ValueError("lam value too large") # <<<<<<<<<<<<<< + * return discd_array_sc(self.internal_state, rk_poisson, size, flam, + * self.lock) + */ + __pyx_tuple__143 = PyTuple_Pack(1, __pyx_kp_s_lam_value_too_large); if (unlikely(!__pyx_tuple__143)) __PYX_ERR(0, 3991, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__143); + __Pyx_GIVEREF(__pyx_tuple__143); + + /* "mtrand.pyx":3996 + * + * if np.any(np.less(olam, 0)): + * raise ValueError("lam < 0") # <<<<<<<<<<<<<< + * if np.any(np.greater(olam, self.poisson_lam_max)): + * raise ValueError("lam value too large.") + */ + __pyx_tuple__144 = PyTuple_Pack(1, __pyx_kp_s_lam_0); if (unlikely(!__pyx_tuple__144)) __PYX_ERR(0, 3996, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__144); + __Pyx_GIVEREF(__pyx_tuple__144); + + /* "mtrand.pyx":3998 + * raise ValueError("lam < 0") + * if np.any(np.greater(olam, self.poisson_lam_max)): + * raise ValueError("lam value too large.") # <<<<<<<<<<<<<< + * return discd_array(self.internal_state, rk_poisson, size, olam, + * self.lock) + */ + __pyx_tuple__145 = PyTuple_Pack(1, __pyx_kp_s_lam_value_too_large_2); if (unlikely(!__pyx_tuple__145)) __PYX_ERR(0, 3998, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__145); + __Pyx_GIVEREF(__pyx_tuple__145); + + /* "mtrand.pyx":4086 + * # use logic that ensures NaN is rejected. + * if not fa > 1.0: + * raise ValueError("'a' must be a valid float > 1.0") # <<<<<<<<<<<<<< + * return discd_array_sc(self.internal_state, rk_zipf, size, fa, + * self.lock) + */ + __pyx_tuple__146 = PyTuple_Pack(1, __pyx_kp_s_a_must_be_a_valid_float_1_0); if (unlikely(!__pyx_tuple__146)) __PYX_ERR(0, 4086, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__146); + __Pyx_GIVEREF(__pyx_tuple__146); + + /* "mtrand.pyx":4092 + * # use logic that ensures NaN is rejected. + * if not np.all(np.greater(oa, 1.0)): + * raise ValueError("'a' must contain valid floats > 1.0") # <<<<<<<<<<<<<< + * return discd_array(self.internal_state, rk_zipf, size, oa, self.lock) + * + */ + __pyx_tuple__147 = PyTuple_Pack(1, __pyx_kp_s_a_must_contain_valid_floats_1_0); if (unlikely(!__pyx_tuple__147)) __PYX_ERR(0, 4092, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__147); + __Pyx_GIVEREF(__pyx_tuple__147); + + /* "mtrand.pyx":4150 + * + * if fp < 0.0: + * raise ValueError("p < 0.0") # <<<<<<<<<<<<<< + * if fp > 1.0: + * raise ValueError("p > 1.0") + */ + __pyx_tuple__148 = PyTuple_Pack(1, __pyx_kp_s_p_0_0); if (unlikely(!__pyx_tuple__148)) __PYX_ERR(0, 4150, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__148); + __Pyx_GIVEREF(__pyx_tuple__148); + + /* "mtrand.pyx":4152 + * raise ValueError("p < 0.0") + * if fp > 1.0: + * raise ValueError("p > 1.0") # <<<<<<<<<<<<<< + * return discd_array_sc(self.internal_state, rk_geometric, size, fp, + * self.lock) + */ + __pyx_tuple__149 = PyTuple_Pack(1, __pyx_kp_s_p_1_0); if (unlikely(!__pyx_tuple__149)) __PYX_ERR(0, 4152, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__149); + __Pyx_GIVEREF(__pyx_tuple__149); + + /* "mtrand.pyx":4157 + * + * if np.any(np.less(op, 0.0)): + * raise ValueError("p < 0.0") # <<<<<<<<<<<<<< + * if np.any(np.greater(op, 1.0)): + * raise ValueError("p > 1.0") + */ + __pyx_tuple__150 = PyTuple_Pack(1, __pyx_kp_s_p_0_0); if (unlikely(!__pyx_tuple__150)) __PYX_ERR(0, 4157, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__150); + __Pyx_GIVEREF(__pyx_tuple__150); + + /* "mtrand.pyx":4159 + * raise ValueError("p < 0.0") + * if np.any(np.greater(op, 1.0)): + * raise ValueError("p > 1.0") # <<<<<<<<<<<<<< + * return discd_array(self.internal_state, rk_geometric, size, op, + * self.lock) + */ + __pyx_tuple__151 = PyTuple_Pack(1, __pyx_kp_s_p_1_0); if (unlikely(!__pyx_tuple__151)) __PYX_ERR(0, 4159, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__151); + __Pyx_GIVEREF(__pyx_tuple__151); + + /* "mtrand.pyx":4264 + * + * if lngood < 0: + * raise ValueError("ngood < 0") # <<<<<<<<<<<<<< + * if lnbad < 0: + * raise ValueError("nbad < 0") + */ + __pyx_tuple__152 = PyTuple_Pack(1, __pyx_kp_s_ngood_0); if (unlikely(!__pyx_tuple__152)) __PYX_ERR(0, 4264, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__152); + __Pyx_GIVEREF(__pyx_tuple__152); + + /* "mtrand.pyx":4266 + * raise ValueError("ngood < 0") + * if lnbad < 0: + * raise ValueError("nbad < 0") # <<<<<<<<<<<<<< + * if lnsample < 1: + * raise ValueError("nsample < 1") + */ + __pyx_tuple__153 = PyTuple_Pack(1, __pyx_kp_s_nbad_0); if (unlikely(!__pyx_tuple__153)) __PYX_ERR(0, 4266, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__153); + __Pyx_GIVEREF(__pyx_tuple__153); + + /* "mtrand.pyx":4268 + * raise ValueError("nbad < 0") + * if lnsample < 1: + * raise ValueError("nsample < 1") # <<<<<<<<<<<<<< + * if lngood + lnbad < lnsample: + * raise ValueError("ngood + nbad < nsample") + */ + __pyx_tuple__154 = PyTuple_Pack(1, __pyx_kp_s_nsample_1); if (unlikely(!__pyx_tuple__154)) __PYX_ERR(0, 4268, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__154); + __Pyx_GIVEREF(__pyx_tuple__154); + + /* "mtrand.pyx":4270 + * raise ValueError("nsample < 1") + * if lngood + lnbad < lnsample: + * raise ValueError("ngood + nbad < nsample") # <<<<<<<<<<<<<< + * return discnmN_array_sc(self.internal_state, rk_hypergeometric, + * size, lngood, lnbad, lnsample, self.lock) + */ + __pyx_tuple__155 = PyTuple_Pack(1, __pyx_kp_s_ngood_nbad_nsample); if (unlikely(!__pyx_tuple__155)) __PYX_ERR(0, 4270, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__155); + __Pyx_GIVEREF(__pyx_tuple__155); + + /* "mtrand.pyx":4275 + * + * if np.any(np.less(ongood, 0)): + * raise ValueError("ngood < 0") # <<<<<<<<<<<<<< + * if np.any(np.less(onbad, 0)): + * raise ValueError("nbad < 0") + */ + __pyx_tuple__156 = PyTuple_Pack(1, __pyx_kp_s_ngood_0); if (unlikely(!__pyx_tuple__156)) __PYX_ERR(0, 4275, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__156); + __Pyx_GIVEREF(__pyx_tuple__156); + + /* "mtrand.pyx":4277 + * raise ValueError("ngood < 0") + * if np.any(np.less(onbad, 0)): + * raise ValueError("nbad < 0") # <<<<<<<<<<<<<< + * if np.any(np.less(onsample, 1)): + * raise ValueError("nsample < 1") + */ + __pyx_tuple__157 = PyTuple_Pack(1, __pyx_kp_s_nbad_0); if (unlikely(!__pyx_tuple__157)) __PYX_ERR(0, 4277, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__157); + __Pyx_GIVEREF(__pyx_tuple__157); + + /* "mtrand.pyx":4279 + * raise ValueError("nbad < 0") + * if np.any(np.less(onsample, 1)): + * raise ValueError("nsample < 1") # <<<<<<<<<<<<<< + * if np.any(np.less(np.add(ongood, onbad),onsample)): + * raise ValueError("ngood + nbad < nsample") + */ + __pyx_tuple__158 = PyTuple_Pack(1, __pyx_kp_s_nsample_1); if (unlikely(!__pyx_tuple__158)) __PYX_ERR(0, 4279, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__158); + __Pyx_GIVEREF(__pyx_tuple__158); + + /* "mtrand.pyx":4281 + * raise ValueError("nsample < 1") + * if np.any(np.less(np.add(ongood, onbad),onsample)): + * raise ValueError("ngood + nbad < nsample") # <<<<<<<<<<<<<< + * return discnmN_array(self.internal_state, rk_hypergeometric, size, + * ongood, onbad, onsample, self.lock) + */ + __pyx_tuple__159 = PyTuple_Pack(1, __pyx_kp_s_ngood_nbad_nsample); if (unlikely(!__pyx_tuple__159)) __PYX_ERR(0, 4281, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__159); + __Pyx_GIVEREF(__pyx_tuple__159); + + /* "mtrand.pyx":4368 + * + * if fp <= 0.0: + * raise ValueError("p <= 0.0") # <<<<<<<<<<<<<< + * if fp >= 1.0: + * raise ValueError("p >= 1.0") + */ + __pyx_tuple__160 = PyTuple_Pack(1, __pyx_kp_s_p_0_0_2); if (unlikely(!__pyx_tuple__160)) __PYX_ERR(0, 4368, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__160); + __Pyx_GIVEREF(__pyx_tuple__160); + + /* "mtrand.pyx":4370 + * raise ValueError("p <= 0.0") + * if fp >= 1.0: + * raise ValueError("p >= 1.0") # <<<<<<<<<<<<<< + * return discd_array_sc(self.internal_state, rk_logseries, size, fp, + * self.lock) + */ + __pyx_tuple__161 = PyTuple_Pack(1, __pyx_kp_s_p_1_0_2); if (unlikely(!__pyx_tuple__161)) __PYX_ERR(0, 4370, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__161); + __Pyx_GIVEREF(__pyx_tuple__161); + + /* "mtrand.pyx":4375 + * + * if np.any(np.less_equal(op, 0.0)): + * raise ValueError("p <= 0.0") # <<<<<<<<<<<<<< + * if np.any(np.greater_equal(op, 1.0)): + * raise ValueError("p >= 1.0") + */ + __pyx_tuple__162 = PyTuple_Pack(1, __pyx_kp_s_p_0_0_2); if (unlikely(!__pyx_tuple__162)) __PYX_ERR(0, 4375, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__162); + __Pyx_GIVEREF(__pyx_tuple__162); + + /* "mtrand.pyx":4377 + * raise ValueError("p <= 0.0") + * if np.any(np.greater_equal(op, 1.0)): + * raise ValueError("p >= 1.0") # <<<<<<<<<<<<<< + * return discd_array(self.internal_state, rk_logseries, size, op, + * self.lock) + */ + __pyx_tuple__163 = PyTuple_Pack(1, __pyx_kp_s_p_1_0_2); if (unlikely(!__pyx_tuple__163)) __PYX_ERR(0, 4377, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__163); + __Pyx_GIVEREF(__pyx_tuple__163); + + /* "mtrand.pyx":4496 + * + * if len(mean.shape) != 1: + * raise ValueError("mean must be 1 dimensional") # <<<<<<<<<<<<<< + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + * raise ValueError("cov must be 2 dimensional and square") + */ + __pyx_tuple__164 = PyTuple_Pack(1, __pyx_kp_s_mean_must_be_1_dimensional); if (unlikely(!__pyx_tuple__164)) __PYX_ERR(0, 4496, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__164); + __Pyx_GIVEREF(__pyx_tuple__164); + + /* "mtrand.pyx":4498 + * raise ValueError("mean must be 1 dimensional") + * if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + * raise ValueError("cov must be 2 dimensional and square") # <<<<<<<<<<<<<< + * if mean.shape[0] != cov.shape[0]: + * raise ValueError("mean and cov must have same length") + */ + __pyx_tuple__165 = PyTuple_Pack(1, __pyx_kp_s_cov_must_be_2_dimensional_and_sq); if (unlikely(!__pyx_tuple__165)) __PYX_ERR(0, 4498, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__165); + __Pyx_GIVEREF(__pyx_tuple__165); + + /* "mtrand.pyx":4500 + * raise ValueError("cov must be 2 dimensional and square") + * if mean.shape[0] != cov.shape[0]: + * raise ValueError("mean and cov must have same length") # <<<<<<<<<<<<<< + * + * # Compute shape of output and create a matrix of independent + */ + __pyx_tuple__166 = PyTuple_Pack(1, __pyx_kp_s_mean_and_cov_must_have_same_leng); if (unlikely(!__pyx_tuple__166)) __PYX_ERR(0, 4500, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__166); + __Pyx_GIVEREF(__pyx_tuple__166); + + /* "mtrand.pyx":4506 + * # with the same length as mean and as many rows are necessary to + * # form a matrix of shape final_shape. + * final_shape = list(shape[:]) # <<<<<<<<<<<<<< + * final_shape.append(mean.shape[0]) + * x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) + */ + __pyx_slice__167 = PySlice_New(Py_None, Py_None, Py_None); if (unlikely(!__pyx_slice__167)) __PYX_ERR(0, 4506, __pyx_L1_error) + __Pyx_GOTREF(__pyx_slice__167); + __Pyx_GIVEREF(__pyx_slice__167); + + /* "mtrand.pyx":4528 + * if check_valid != 'ignore': + * if check_valid != 'warn' and check_valid != 'raise': + * raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") # <<<<<<<<<<<<<< + * + * psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + */ + __pyx_tuple__168 = PyTuple_Pack(1, __pyx_kp_s_check_valid_must_equal_warn_rais); if (unlikely(!__pyx_tuple__168)) __PYX_ERR(0, 4528, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__168); + __Pyx_GIVEREF(__pyx_tuple__168); + + /* "mtrand.pyx":4533 + * if not psd: + * if check_valid == 'warn': + * warnings.warn("covariance is not positive-semidefinite.", # <<<<<<<<<<<<<< + * RuntimeWarning) + * else: + */ + __pyx_tuple__169 = PyTuple_Pack(2, __pyx_kp_s_covariance_is_not_positive_semid, __pyx_builtin_RuntimeWarning); if (unlikely(!__pyx_tuple__169)) __PYX_ERR(0, 4533, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__169); + __Pyx_GIVEREF(__pyx_tuple__169); + + /* "mtrand.pyx":4536 + * RuntimeWarning) + * else: + * raise ValueError("covariance is not positive-semidefinite.") # <<<<<<<<<<<<<< + * + * x = np.dot(x, np.sqrt(s)[:, None] * v) + */ + __pyx_tuple__170 = PyTuple_Pack(1, __pyx_kp_s_covariance_is_not_positive_semid); if (unlikely(!__pyx_tuple__170)) __PYX_ERR(0, 4536, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__170); + __Pyx_GIVEREF(__pyx_tuple__170); + + /* "mtrand.pyx":4538 + * raise ValueError("covariance is not positive-semidefinite.") + * + * x = np.dot(x, np.sqrt(s)[:, None] * v) # <<<<<<<<<<<<<< + * x += mean + * x.shape = tuple(final_shape) + */ + __pyx_slice__171 = PySlice_New(Py_None, Py_None, Py_None); if (unlikely(!__pyx_slice__171)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_slice__171); + __Pyx_GIVEREF(__pyx_slice__171); + __pyx_tuple__172 = PyTuple_Pack(2, __pyx_slice__171, Py_None); if (unlikely(!__pyx_tuple__172)) __PYX_ERR(0, 4538, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__172); + __Pyx_GIVEREF(__pyx_tuple__172); + + /* "mtrand.pyx":4630 + * + * if kahan_sum(pix, d-1) > (1.0 + 1e-12): + * raise ValueError("sum(pvals[:-1]) > 1.0") # <<<<<<<<<<<<<< + * + * shape = _shape_from_size(size, d) + */ + __pyx_tuple__173 = PyTuple_Pack(1, __pyx_kp_s_sum_pvals_1_1_0); if (unlikely(!__pyx_tuple__173)) __PYX_ERR(0, 4630, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__173); + __Pyx_GIVEREF(__pyx_tuple__173); + + /* "mtrand.pyx":4638 + * mnix = PyArray_DATA(mnarr) + * sz = PyArray_SIZE(mnarr) + * with self.lock, nogil, cython.cdivision(True): # <<<<<<<<<<<<<< + * i = 0 + * while i < sz: + */ + __pyx_tuple__174 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__174)) __PYX_ERR(0, 4638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__174); + __Pyx_GIVEREF(__pyx_tuple__174); + + /* "mtrand.pyx":4753 + * alpha_arr = PyArray_ContiguousFromObject(alpha, NPY_DOUBLE, 1, 1) + * if np.any(np.less_equal(alpha_arr, 0)): + * raise ValueError('alpha <= 0') # <<<<<<<<<<<<<< + * alpha_data = PyArray_DATA(alpha_arr) + * + */ + __pyx_tuple__175 = PyTuple_Pack(1, __pyx_kp_s_alpha_0); if (unlikely(!__pyx_tuple__175)) __PYX_ERR(0, 4753, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__175); + __Pyx_GIVEREF(__pyx_tuple__175); + + /* "mtrand.pyx":4764 + * i = 0 + * totsize = PyArray_SIZE(val_arr) + * with self.lock, nogil: # <<<<<<<<<<<<<< + * while i < totsize: + * acc = 0.0 + */ + __pyx_tuple__176 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__176)) __PYX_ERR(0, 4764, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__176); + __Pyx_GIVEREF(__pyx_tuple__176); + + /* "mtrand.pyx":4833 + * buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit + * buf_ptr = buf.ctypes.data + * with self.lock: # <<<<<<<<<<<<<< + * # We trick gcc into providing a specialized implementation for + * # the most common case, yielding a ~33% performance improvement. + */ + __pyx_tuple__177 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__177)) __PYX_ERR(0, 4833, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__177); + __Pyx_GIVEREF(__pyx_tuple__177); + + /* "mtrand.pyx":4844 + * # Multidimensional ndarrays require a bounce buffer. + * buf = np.empty_like(x[0]) + * with self.lock: # <<<<<<<<<<<<<< + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + */ + __pyx_tuple__178 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__178)) __PYX_ERR(0, 4844, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__178); + __Pyx_GIVEREF(__pyx_tuple__178); + + /* "mtrand.pyx":4852 + * else: + * # Untyped path. + * with self.lock: # <<<<<<<<<<<<<< + * for i in reversed(range(1, n)): + * j = rk_interval(i, self.internal_state) + */ + __pyx_tuple__179 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__179)) __PYX_ERR(0, 4852, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__179); + __Pyx_GIVEREF(__pyx_tuple__179); + + /* "randint_helpers.pxi":5 + * """ + * + * def _rand_bool(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_bool(low, high, size, rngstate) + */ + __pyx_tuple__180 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__180)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__180); + __Pyx_GIVEREF(__pyx_tuple__180); + __pyx_codeobj__181 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__180, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_bool, 5, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__181)) __PYX_ERR(1, 5, __pyx_L1_error) + + /* "randint_helpers.pxi":56 + * return array + * + * def _rand_int8(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int8(low, high, size, rngstate) + */ + __pyx_tuple__182 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__182)) __PYX_ERR(1, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__182); + __Pyx_GIVEREF(__pyx_tuple__182); + __pyx_codeobj__183 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__182, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_int8, 56, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__183)) __PYX_ERR(1, 56, __pyx_L1_error) + + /* "randint_helpers.pxi":107 + * return array + * + * def _rand_int16(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int16(low, high, size, rngstate) + */ + __pyx_tuple__184 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__184)) __PYX_ERR(1, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__184); + __Pyx_GIVEREF(__pyx_tuple__184); + __pyx_codeobj__185 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__184, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_int16, 107, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__185)) __PYX_ERR(1, 107, __pyx_L1_error) + + /* "randint_helpers.pxi":158 + * return array + * + * def _rand_int32(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int32(low, high, size, rngstate) + */ + __pyx_tuple__186 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__186)) __PYX_ERR(1, 158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__186); + __Pyx_GIVEREF(__pyx_tuple__186); + __pyx_codeobj__187 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__186, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_int32, 158, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__187)) __PYX_ERR(1, 158, __pyx_L1_error) + + /* "randint_helpers.pxi":209 + * return array + * + * def _rand_int64(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int64(low, high, size, rngstate) + */ + __pyx_tuple__188 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__188)) __PYX_ERR(1, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__188); + __Pyx_GIVEREF(__pyx_tuple__188); + __pyx_codeobj__189 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__188, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_int64, 209, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__189)) __PYX_ERR(1, 209, __pyx_L1_error) + + /* "randint_helpers.pxi":260 + * return array + * + * def _rand_uint8(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint8(low, high, size, rngstate) + */ + __pyx_tuple__190 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__190)) __PYX_ERR(1, 260, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__190); + __Pyx_GIVEREF(__pyx_tuple__190); + __pyx_codeobj__191 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__190, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_uint8, 260, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__191)) __PYX_ERR(1, 260, __pyx_L1_error) + + /* "randint_helpers.pxi":311 + * return array + * + * def _rand_uint16(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint16(low, high, size, rngstate) + */ + __pyx_tuple__192 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__192)) __PYX_ERR(1, 311, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__192); + __Pyx_GIVEREF(__pyx_tuple__192); + __pyx_codeobj__193 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__192, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_uint16, 311, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__193)) __PYX_ERR(1, 311, __pyx_L1_error) + + /* "randint_helpers.pxi":362 + * return array + * + * def _rand_uint32(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint32(low, high, size, rngstate) + */ + __pyx_tuple__194 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__194)) __PYX_ERR(1, 362, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__194); + __Pyx_GIVEREF(__pyx_tuple__194); + __pyx_codeobj__195 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__194, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_uint32, 362, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__195)) __PYX_ERR(1, 362, __pyx_L1_error) + + /* "randint_helpers.pxi":413 + * return array + * + * def _rand_uint64(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint64(low, high, size, rngstate) + */ + __pyx_tuple__196 = PyTuple_Pack(12, __pyx_n_s_low, __pyx_n_s_high, __pyx_n_s_size, __pyx_n_s_rngstate, __pyx_n_s_off, __pyx_n_s_rng, __pyx_n_s_buf, __pyx_n_s_out, __pyx_n_s_array, __pyx_n_s_cnt, __pyx_n_s_state, __pyx_n_s_array_data); if (unlikely(!__pyx_tuple__196)) __PYX_ERR(1, 413, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__196); + __Pyx_GIVEREF(__pyx_tuple__196); + __pyx_codeobj__197 = (PyObject*)__Pyx_PyCode_New(4, 0, 12, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__196, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_randint_helpers_pxi, __pyx_n_s_rand_uint64, 413, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__197)) __PYX_ERR(1, 413, __pyx_L1_error) + + /* "mtrand.pyx":566 + * return sum + * + * def _shape_from_size(size, d): # <<<<<<<<<<<<<< + * if size is None: + * shape = (d,) + */ + __pyx_tuple__198 = PyTuple_Pack(3, __pyx_n_s_size, __pyx_n_s_d, __pyx_n_s_shape); if (unlikely(!__pyx_tuple__198)) __PYX_ERR(0, 566, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__198); + __Pyx_GIVEREF(__pyx_tuple__198); + __pyx_codeobj__199 = (PyObject*)__Pyx_PyCode_New(2, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__198, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_mtrand_pyx, __pyx_n_s_shape_from_size, 566, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__199)) __PYX_ERR(0, 566, __pyx_L1_error) + + /* "mtrand.pyx":638 + * cdef object lock + * cdef object state_address + * poisson_lam_max = np.iinfo('l').max - np.sqrt(np.iinfo('l').max)*10 # <<<<<<<<<<<<<< + * + * def __init__(self, seed=None): + */ + __pyx_tuple__200 = PyTuple_Pack(1, __pyx_n_s_l); if (unlikely(!__pyx_tuple__200)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__200); + __Pyx_GIVEREF(__pyx_tuple__200); + __pyx_tuple__201 = PyTuple_Pack(1, __pyx_n_s_l); if (unlikely(!__pyx_tuple__201)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__201); + __Pyx_GIVEREF(__pyx_tuple__201); + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_InitGlobals(void) { + if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_float_0_0 = PyFloat_FromDouble(0.0); if (unlikely(!__pyx_float_0_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_float_1_0 = PyFloat_FromDouble(1.0); if (unlikely(!__pyx_float_1_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_float_1eneg_8 = PyFloat_FromDouble(1e-8); if (unlikely(!__pyx_float_1eneg_8)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_2 = PyInt_FromLong(2); if (unlikely(!__pyx_int_2)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_3 = PyInt_FromLong(3); if (unlikely(!__pyx_int_3)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_5 = PyInt_FromLong(5); if (unlikely(!__pyx_int_5)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_10 = PyInt_FromLong(10); if (unlikely(!__pyx_int_10)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_128 = PyInt_FromLong(128); if (unlikely(!__pyx_int_128)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_256 = PyInt_FromLong(256); if (unlikely(!__pyx_int_256)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_624 = PyInt_FromLong(624); if (unlikely(!__pyx_int_624)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_32768 = PyInt_FromLong(32768L); if (unlikely(!__pyx_int_32768)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_65536 = PyInt_FromLong(65536L); if (unlikely(!__pyx_int_65536)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_2147483648 = PyInt_FromString((char *)"2147483648", 0, 0); if (unlikely(!__pyx_int_2147483648)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_4294967296 = PyInt_FromString((char *)"4294967296", 0, 0); if (unlikely(!__pyx_int_4294967296)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_9223372036854775808 = PyInt_FromString((char *)"9223372036854775808", 0, 0); if (unlikely(!__pyx_int_9223372036854775808)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_18446744073709551616 = PyInt_FromString((char *)"18446744073709551616", 0, 0); if (unlikely(!__pyx_int_18446744073709551616)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_1 = PyInt_FromLong(-1); if (unlikely(!__pyx_int_neg_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_128 = PyInt_FromLong(-128); if (unlikely(!__pyx_int_neg_128)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_32768 = PyInt_FromLong(-32768L); if (unlikely(!__pyx_int_neg_32768)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_2147483648 = PyInt_FromLong(-2147483648L); if (unlikely(!__pyx_int_neg_2147483648)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_neg_9223372036854775808 = PyInt_FromString((char *)"-9223372036854775808", 0, 0); if (unlikely(!__pyx_int_neg_9223372036854775808)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +static int __Pyx_modinit_global_init_code(void); /*proto*/ +static int __Pyx_modinit_variable_export_code(void); /*proto*/ +static int __Pyx_modinit_function_export_code(void); /*proto*/ +static int __Pyx_modinit_type_init_code(void); /*proto*/ +static int __Pyx_modinit_type_import_code(void); /*proto*/ +static int __Pyx_modinit_variable_import_code(void); /*proto*/ +static int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + __pyx_ptype_6mtrand_dtype = __Pyx_ImportType("numpy", "dtype", sizeof(PyArray_Descr), 0); if (unlikely(!__pyx_ptype_6mtrand_dtype)) __PYX_ERR(2, 87, __pyx_L1_error) + __pyx_ptype_6mtrand_ndarray = __Pyx_ImportType("numpy", "ndarray", sizeof(PyArrayObject), 0); if (unlikely(!__pyx_ptype_6mtrand_ndarray)) __PYX_ERR(2, 89, __pyx_L1_error) + __pyx_ptype_6mtrand_flatiter = __Pyx_ImportType("numpy", "flatiter", sizeof(PyArrayIterObject), 0); if (unlikely(!__pyx_ptype_6mtrand_flatiter)) __PYX_ERR(2, 91, __pyx_L1_error) + __pyx_ptype_6mtrand_broadcast = __Pyx_ImportType("numpy", "broadcast", sizeof(PyArrayMultiIterObject), 0); if (unlikely(!__pyx_ptype_6mtrand_broadcast)) __PYX_ERR(2, 97, __pyx_L1_error) + __pyx_vtabptr_6mtrand_RandomState = &__pyx_vtable_6mtrand_RandomState; + __pyx_vtable_6mtrand_RandomState._shuffle_raw = (PyObject *(*)(struct __pyx_obj_6mtrand_RandomState *, npy_intp, npy_intp, npy_intp, char *, char *))__pyx_f_6mtrand_11RandomState__shuffle_raw; + if (PyType_Ready(&__pyx_type_6mtrand_RandomState) < 0) __PYX_ERR(0, 593, __pyx_L1_error) + __pyx_type_6mtrand_RandomState.tp_print = 0; + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_6mtrand_RandomState.tp_dictoffset && __pyx_type_6mtrand_RandomState.tp_getattro == PyObject_GenericGetAttr)) { + __pyx_type_6mtrand_RandomState.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (__Pyx_SetVtable(__pyx_type_6mtrand_RandomState.tp_dict, __pyx_vtabptr_6mtrand_RandomState) < 0) __PYX_ERR(0, 593, __pyx_L1_error) + if (PyObject_SetAttrString(__pyx_m, "RandomState", (PyObject *)&__pyx_type_6mtrand_RandomState) < 0) __PYX_ERR(0, 593, __pyx_L1_error) + __pyx_ptype_6mtrand_RandomState = &__pyx_type_6mtrand_RandomState; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_ptype_7cpython_4type_type = __Pyx_ImportType(__Pyx_BUILTIN_MODULE_NAME, "type", + #if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x050B0000 + sizeof(PyTypeObject), + #else + sizeof(PyHeapTypeObject), + #endif + 0); if (unlikely(!__pyx_ptype_7cpython_4type_type)) __PYX_ERR(3, 9, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + + +#if PY_MAJOR_VERSION < 3 +#ifdef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC void +#else +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#endif +#else +#ifdef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#endif +#endif +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) + #define CYTHON_SMALL_CODE __attribute__((optimize("Os"))) +#else + #define CYTHON_SMALL_CODE +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initmtrand(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initmtrand(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_mtrand(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_mtrand(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name) { + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + result = PyDict_SetItemString(moddict, to_name, value); + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static PyObject* __pyx_pymod_create(PyObject *spec, CYTHON_UNUSED PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__") < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__") < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__") < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__") < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static int __pyx_pymod_exec_mtrand(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m && __pyx_m == __pyx_pyinit_module) return 0; + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_mtrand(void)", 0); + if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + #ifdef WITH_THREAD /* Python build with threading support? */ + PyEval_InitThreads(); + #endif + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("mtrand", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + #endif + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = PyImport_AddModule((char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_COMPILING_IN_PYPY + Py_INCREF(__pyx_b); + #endif + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error); + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_mtrand) { + if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "mtrand")) { + if (unlikely(PyDict_SetItemString(modules, "mtrand", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely(__Pyx_modinit_type_init_code() != 0)) goto __pyx_L1_error; + if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; + (void)__Pyx_modinit_variable_import_code(); + (void)__Pyx_modinit_function_import_code(); + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "randint_helpers.pxi":5 + * """ + * + * def _rand_bool(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_bool(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_1_rand_bool, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_bool, __pyx_t_1) < 0) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "randint_helpers.pxi":56 + * return array + * + * def _rand_int8(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int8(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_3_rand_int8, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_int8, __pyx_t_1) < 0) __PYX_ERR(1, 56, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "randint_helpers.pxi":107 + * return array + * + * def _rand_int16(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int16(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_5_rand_int16, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_int16, __pyx_t_1) < 0) __PYX_ERR(1, 107, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "randint_helpers.pxi":158 + * return array + * + * def _rand_int32(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int32(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_7_rand_int32, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 158, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_int32, __pyx_t_1) < 0) __PYX_ERR(1, 158, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "randint_helpers.pxi":209 + * return array + * + * def _rand_int64(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_int64(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_9_rand_int64, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_int64, __pyx_t_1) < 0) __PYX_ERR(1, 209, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "randint_helpers.pxi":260 + * return array + * + * def _rand_uint8(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint8(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_11_rand_uint8, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 260, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_uint8, __pyx_t_1) < 0) __PYX_ERR(1, 260, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "randint_helpers.pxi":311 + * return array + * + * def _rand_uint16(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint16(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_13_rand_uint16, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 311, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_uint16, __pyx_t_1) < 0) __PYX_ERR(1, 311, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "randint_helpers.pxi":362 + * return array + * + * def _rand_uint32(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint32(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_15_rand_uint32, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 362, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_uint32, __pyx_t_1) < 0) __PYX_ERR(1, 362, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "randint_helpers.pxi":413 + * return array + * + * def _rand_uint64(low, high, size, rngstate): # <<<<<<<<<<<<<< + * """ + * _rand_uint64(low, high, size, rngstate) + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_17_rand_uint64, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 413, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_uint64, __pyx_t_1) < 0) __PYX_ERR(1, 413, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":143 + * + * # Initialize numpy + * import_array() # <<<<<<<<<<<<<< + * + * cimport cython + */ + __pyx_t_2 = __pyx_f_6mtrand_import_array(); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(0, 143, __pyx_L1_error) + + /* "mtrand.pyx":146 + * + * cimport cython + * import numpy as np # <<<<<<<<<<<<<< + * import operator + * import warnings + */ + __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 146, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 146, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":147 + * cimport cython + * import numpy as np + * import operator # <<<<<<<<<<<<<< + * import warnings + * + */ + __pyx_t_1 = __Pyx_Import(__pyx_n_s_operator, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_operator, __pyx_t_1) < 0) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":148 + * import numpy as np + * import operator + * import warnings # <<<<<<<<<<<<<< + * + * try: + */ + __pyx_t_1 = __Pyx_Import(__pyx_n_s_warnings, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 148, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_warnings, __pyx_t_1) < 0) __PYX_ERR(0, 148, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":150 + * import warnings + * + * try: # <<<<<<<<<<<<<< + * from threading import Lock + * except ImportError: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_3, &__pyx_t_4, &__pyx_t_5); + __Pyx_XGOTREF(__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_4); + __Pyx_XGOTREF(__pyx_t_5); + /*try:*/ { + + /* "mtrand.pyx":151 + * + * try: + * from threading import Lock # <<<<<<<<<<<<<< + * except ImportError: + * from dummy_threading import Lock + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 151, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_Lock); + __Pyx_GIVEREF(__pyx_n_s_Lock); + PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_Lock); + __pyx_t_6 = __Pyx_Import(__pyx_n_s_threading, __pyx_t_1, -1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 151, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_6, __pyx_n_s_Lock); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 151, __pyx_L2_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Lock, __pyx_t_1) < 0) __PYX_ERR(0, 151, __pyx_L2_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "mtrand.pyx":150 + * import warnings + * + * try: # <<<<<<<<<<<<<< + * from threading import Lock + * except ImportError: + */ + } + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L7_try_end; + __pyx_L2_error:; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "mtrand.pyx":152 + * try: + * from threading import Lock + * except ImportError: # <<<<<<<<<<<<<< + * from dummy_threading import Lock + * + */ + __pyx_t_2 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_ImportError); + if (__pyx_t_2) { + __Pyx_AddTraceback("mtrand", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_6, &__pyx_t_1, &__pyx_t_7) < 0) __PYX_ERR(0, 152, __pyx_L4_except_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GOTREF(__pyx_t_7); + + /* "mtrand.pyx":153 + * from threading import Lock + * except ImportError: + * from dummy_threading import Lock # <<<<<<<<<<<<<< + * + * cdef object cont0_array(rk_state *state, rk_cont0 func, object size, + */ + __pyx_t_8 = PyList_New(1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 153, __pyx_L4_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_INCREF(__pyx_n_s_Lock); + __Pyx_GIVEREF(__pyx_n_s_Lock); + PyList_SET_ITEM(__pyx_t_8, 0, __pyx_n_s_Lock); + __pyx_t_9 = __Pyx_Import(__pyx_n_s_dummy_threading, __pyx_t_8, -1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 153, __pyx_L4_except_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_ImportFrom(__pyx_t_9, __pyx_n_s_Lock); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 153, __pyx_L4_except_error) + __Pyx_GOTREF(__pyx_t_8); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_Lock, __pyx_t_8) < 0) __PYX_ERR(0, 153, __pyx_L4_except_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + goto __pyx_L3_exception_handled; + } + goto __pyx_L4_except_error; + __pyx_L4_except_error:; + + /* "mtrand.pyx":150 + * import warnings + * + * try: # <<<<<<<<<<<<<< + * from threading import Lock + * except ImportError: + */ + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_5); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_4, __pyx_t_5); + goto __pyx_L1_error; + __pyx_L3_exception_handled:; + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_XGIVEREF(__pyx_t_4); + __Pyx_XGIVEREF(__pyx_t_5); + __Pyx_ExceptionReset(__pyx_t_3, __pyx_t_4, __pyx_t_5); + __pyx_L7_try_end:; + } + + /* "mtrand.pyx":566 + * return sum + * + * def _shape_from_size(size, d): # <<<<<<<<<<<<<< + * if size is None: + * shape = (d,) + */ + __pyx_t_7 = PyCFunction_NewEx(&__pyx_mdef_6mtrand_19_shape_from_size, NULL, __pyx_n_s_mtrand); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 566, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_shape_from_size, __pyx_t_7) < 0) __PYX_ERR(0, 566, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":581 + * # function to call. + * _randint_type = { + * 'bool': (0, 2, _rand_bool), # <<<<<<<<<<<<<< + * 'int8': (-2**7, 2**7, _rand_int8), + * 'int16': (-2**15, 2**15, _rand_int16), + */ + __pyx_t_7 = __Pyx_PyDict_NewPresized(9); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_bool); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = PyTuple_New(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_int_0); + __Pyx_INCREF(__pyx_int_2); + __Pyx_GIVEREF(__pyx_int_2); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_int_2); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_1); + __pyx_t_1 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_bool_2, __pyx_t_6) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "mtrand.pyx":582 + * _randint_type = { + * 'bool': (0, 2, _rand_bool), + * 'int8': (-2**7, 2**7, _rand_int8), # <<<<<<<<<<<<<< + * 'int16': (-2**15, 2**15, _rand_int16), + * 'int32': (-2**31, 2**31, _rand_int32), + */ + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_int8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 582, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_int_neg_128); + __Pyx_GIVEREF(__pyx_int_neg_128); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_int_neg_128); + __Pyx_INCREF(__pyx_int_128); + __Pyx_GIVEREF(__pyx_int_128); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_128); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_t_6); + __pyx_t_6 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_int8, __pyx_t_1) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":583 + * 'bool': (0, 2, _rand_bool), + * 'int8': (-2**7, 2**7, _rand_int8), + * 'int16': (-2**15, 2**15, _rand_int16), # <<<<<<<<<<<<<< + * 'int32': (-2**31, 2**31, _rand_int32), + * 'int64': (-2**63, 2**63, _rand_int64), + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_int16); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 583, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = PyTuple_New(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 583, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_INCREF(__pyx_int_neg_32768); + __Pyx_GIVEREF(__pyx_int_neg_32768); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_int_neg_32768); + __Pyx_INCREF(__pyx_int_32768); + __Pyx_GIVEREF(__pyx_int_32768); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_int_32768); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_1); + __pyx_t_1 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_int16, __pyx_t_6) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "mtrand.pyx":584 + * 'int8': (-2**7, 2**7, _rand_int8), + * 'int16': (-2**15, 2**15, _rand_int16), + * 'int32': (-2**31, 2**31, _rand_int32), # <<<<<<<<<<<<<< + * 'int64': (-2**63, 2**63, _rand_int64), + * 'uint8': (0, 2**8, _rand_uint8), + */ + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_int32); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 584, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_int_neg_2147483648); + __Pyx_GIVEREF(__pyx_int_neg_2147483648); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_int_neg_2147483648); + __Pyx_INCREF(__pyx_int_2147483648); + __Pyx_GIVEREF(__pyx_int_2147483648); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_2147483648); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_t_6); + __pyx_t_6 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_int32, __pyx_t_1) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":585 + * 'int16': (-2**15, 2**15, _rand_int16), + * 'int32': (-2**31, 2**31, _rand_int32), + * 'int64': (-2**63, 2**63, _rand_int64), # <<<<<<<<<<<<<< + * 'uint8': (0, 2**8, _rand_uint8), + * 'uint16': (0, 2**16, _rand_uint16), + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_int64); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 585, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = PyTuple_New(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 585, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_INCREF(__pyx_int_neg_9223372036854775808); + __Pyx_GIVEREF(__pyx_int_neg_9223372036854775808); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_int_neg_9223372036854775808); + __Pyx_INCREF(__pyx_int_9223372036854775808); + __Pyx_GIVEREF(__pyx_int_9223372036854775808); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_int_9223372036854775808); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_1); + __pyx_t_1 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_int64, __pyx_t_6) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "mtrand.pyx":586 + * 'int32': (-2**31, 2**31, _rand_int32), + * 'int64': (-2**63, 2**63, _rand_int64), + * 'uint8': (0, 2**8, _rand_uint8), # <<<<<<<<<<<<<< + * 'uint16': (0, 2**16, _rand_uint16), + * 'uint32': (0, 2**32, _rand_uint32), + */ + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_uint8); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 586, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 586, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_int_0); + __Pyx_INCREF(__pyx_int_256); + __Pyx_GIVEREF(__pyx_int_256); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_256); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_t_6); + __pyx_t_6 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_uint8, __pyx_t_1) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":587 + * 'int64': (-2**63, 2**63, _rand_int64), + * 'uint8': (0, 2**8, _rand_uint8), + * 'uint16': (0, 2**16, _rand_uint16), # <<<<<<<<<<<<<< + * 'uint32': (0, 2**32, _rand_uint32), + * 'uint64': (0, 2**64, _rand_uint64) + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_uint16); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 587, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = PyTuple_New(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 587, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_int_0); + __Pyx_INCREF(__pyx_int_65536); + __Pyx_GIVEREF(__pyx_int_65536); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_int_65536); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_1); + __pyx_t_1 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_uint16, __pyx_t_6) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "mtrand.pyx":588 + * 'uint8': (0, 2**8, _rand_uint8), + * 'uint16': (0, 2**16, _rand_uint16), + * 'uint32': (0, 2**32, _rand_uint32), # <<<<<<<<<<<<<< + * 'uint64': (0, 2**64, _rand_uint64) + * } + */ + __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_uint32); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 588, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 588, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_int_0); + __Pyx_INCREF(__pyx_int_4294967296); + __Pyx_GIVEREF(__pyx_int_4294967296); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_4294967296); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_t_6); + __pyx_t_6 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_uint32, __pyx_t_1) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mtrand.pyx":589 + * 'uint16': (0, 2**16, _rand_uint16), + * 'uint32': (0, 2**32, _rand_uint32), + * 'uint64': (0, 2**64, _rand_uint64) # <<<<<<<<<<<<<< + * } + * + */ + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_uint64); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 589, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = PyTuple_New(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 589, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_int_0); + __Pyx_INCREF(__pyx_int_18446744073709551616); + __Pyx_GIVEREF(__pyx_int_18446744073709551616); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_int_18446744073709551616); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_1); + __pyx_t_1 = 0; + if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_uint64, __pyx_t_6) < 0) __PYX_ERR(0, 581, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_randint_type, __pyx_t_7) < 0) __PYX_ERR(0, 580, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":638 + * cdef object lock + * cdef object state_address + * poisson_lam_max = np.iinfo('l').max - np.sqrt(np.iinfo('l').max)*10 # <<<<<<<<<<<<<< + * + * def __init__(self, seed=None): + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_iinfo); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_tuple__200, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_max); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_sqrt); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_iinfo); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_tuple__201, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_max); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) { + __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_9); + if (likely(__pyx_t_1)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9); + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_9, function); + } + } + if (!__pyx_t_1) { + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_7); + } else { + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_t_8}; + __pyx_t_7 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) { + PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_t_8}; + __pyx_t_7 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_1); __pyx_t_1 = NULL; + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_8); + __pyx_t_8 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_10, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + } + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = PyNumber_Multiply(__pyx_t_7, __pyx_int_10); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = PyNumber_Subtract(__pyx_t_6, __pyx_t_9); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem((PyObject *)__pyx_ptype_6mtrand_RandomState->tp_dict, __pyx_n_s_poisson_lam_max, __pyx_t_7) < 0) __PYX_ERR(0, 638, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + PyType_Modified(__pyx_ptype_6mtrand_RandomState); + + /* "mtrand.pyx":910 + * return disc0_array(self.internal_state, rk_long, size, self.lock) + * + * def randint(self, low, high=None, size=None, dtype=int): # <<<<<<<<<<<<<< + * """ + * randint(low, high=None, size=None, dtype='l') + */ + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __pyx_k__50 = ((PyObject *)(&PyInt_Type)); + __Pyx_GIVEREF((&PyInt_Type)); + + /* "mtrand.pyx":4910 + * return arr + * + * _rand = RandomState() # <<<<<<<<<<<<<< + * seed = _rand.seed + * get_state = _rand.get_state + */ + __pyx_t_7 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_6mtrand_RandomState)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4910, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand_2, __pyx_t_7) < 0) __PYX_ERR(0, 4910, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4911 + * + * _rand = RandomState() + * seed = _rand.seed # <<<<<<<<<<<<<< + * get_state = _rand.get_state + * set_state = _rand.set_state + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4911, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_seed); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4911, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_seed, __pyx_t_9) < 0) __PYX_ERR(0, 4911, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4912 + * _rand = RandomState() + * seed = _rand.seed + * get_state = _rand.get_state # <<<<<<<<<<<<<< + * set_state = _rand.set_state + * random_sample = _rand.random_sample + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4912, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_get_state); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4912, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_state, __pyx_t_7) < 0) __PYX_ERR(0, 4912, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4913 + * seed = _rand.seed + * get_state = _rand.get_state + * set_state = _rand.set_state # <<<<<<<<<<<<<< + * random_sample = _rand.random_sample + * choice = _rand.choice + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4913, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_set_state); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4913, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_set_state, __pyx_t_9) < 0) __PYX_ERR(0, 4913, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4914 + * get_state = _rand.get_state + * set_state = _rand.set_state + * random_sample = _rand.random_sample # <<<<<<<<<<<<<< + * choice = _rand.choice + * randint = _rand.randint + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4914, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_random_sample); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4914, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_random_sample, __pyx_t_7) < 0) __PYX_ERR(0, 4914, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4915 + * set_state = _rand.set_state + * random_sample = _rand.random_sample + * choice = _rand.choice # <<<<<<<<<<<<<< + * randint = _rand.randint + * bytes = _rand.bytes + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4915, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_choice); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4915, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_choice, __pyx_t_9) < 0) __PYX_ERR(0, 4915, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4916 + * random_sample = _rand.random_sample + * choice = _rand.choice + * randint = _rand.randint # <<<<<<<<<<<<<< + * bytes = _rand.bytes + * uniform = _rand.uniform + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4916, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_randint); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4916, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_randint, __pyx_t_7) < 0) __PYX_ERR(0, 4916, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4917 + * choice = _rand.choice + * randint = _rand.randint + * bytes = _rand.bytes # <<<<<<<<<<<<<< + * uniform = _rand.uniform + * rand = _rand.rand + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4917, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_bytes); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4917, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_bytes, __pyx_t_9) < 0) __PYX_ERR(0, 4917, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4918 + * randint = _rand.randint + * bytes = _rand.bytes + * uniform = _rand.uniform # <<<<<<<<<<<<<< + * rand = _rand.rand + * randn = _rand.randn + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4918, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_uniform); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4918, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_uniform, __pyx_t_7) < 0) __PYX_ERR(0, 4918, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4919 + * bytes = _rand.bytes + * uniform = _rand.uniform + * rand = _rand.rand # <<<<<<<<<<<<<< + * randn = _rand.randn + * random_integers = _rand.random_integers + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4919, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_rand); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4919, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rand, __pyx_t_9) < 0) __PYX_ERR(0, 4919, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4920 + * uniform = _rand.uniform + * rand = _rand.rand + * randn = _rand.randn # <<<<<<<<<<<<<< + * random_integers = _rand.random_integers + * standard_normal = _rand.standard_normal + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4920, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_randn); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4920, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_randn, __pyx_t_7) < 0) __PYX_ERR(0, 4920, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4921 + * rand = _rand.rand + * randn = _rand.randn + * random_integers = _rand.random_integers # <<<<<<<<<<<<<< + * standard_normal = _rand.standard_normal + * normal = _rand.normal + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4921, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_random_integers); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4921, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_random_integers, __pyx_t_9) < 0) __PYX_ERR(0, 4921, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4922 + * randn = _rand.randn + * random_integers = _rand.random_integers + * standard_normal = _rand.standard_normal # <<<<<<<<<<<<<< + * normal = _rand.normal + * beta = _rand.beta + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4922, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_standard_normal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4922, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_standard_normal, __pyx_t_7) < 0) __PYX_ERR(0, 4922, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4923 + * random_integers = _rand.random_integers + * standard_normal = _rand.standard_normal + * normal = _rand.normal # <<<<<<<<<<<<<< + * beta = _rand.beta + * exponential = _rand.exponential + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4923, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_normal); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4923, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_normal, __pyx_t_9) < 0) __PYX_ERR(0, 4923, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4924 + * standard_normal = _rand.standard_normal + * normal = _rand.normal + * beta = _rand.beta # <<<<<<<<<<<<<< + * exponential = _rand.exponential + * standard_exponential = _rand.standard_exponential + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4924, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_beta); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4924, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_beta, __pyx_t_7) < 0) __PYX_ERR(0, 4924, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4925 + * normal = _rand.normal + * beta = _rand.beta + * exponential = _rand.exponential # <<<<<<<<<<<<<< + * standard_exponential = _rand.standard_exponential + * standard_gamma = _rand.standard_gamma + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4925, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_exponential); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4925, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_exponential, __pyx_t_9) < 0) __PYX_ERR(0, 4925, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4926 + * beta = _rand.beta + * exponential = _rand.exponential + * standard_exponential = _rand.standard_exponential # <<<<<<<<<<<<<< + * standard_gamma = _rand.standard_gamma + * gamma = _rand.gamma + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4926, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_standard_exponential); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4926, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_standard_exponential, __pyx_t_7) < 0) __PYX_ERR(0, 4926, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4927 + * exponential = _rand.exponential + * standard_exponential = _rand.standard_exponential + * standard_gamma = _rand.standard_gamma # <<<<<<<<<<<<<< + * gamma = _rand.gamma + * f = _rand.f + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4927, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_standard_gamma); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4927, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_standard_gamma, __pyx_t_9) < 0) __PYX_ERR(0, 4927, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4928 + * standard_exponential = _rand.standard_exponential + * standard_gamma = _rand.standard_gamma + * gamma = _rand.gamma # <<<<<<<<<<<<<< + * f = _rand.f + * noncentral_f = _rand.noncentral_f + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4928, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_gamma); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4928, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_gamma, __pyx_t_7) < 0) __PYX_ERR(0, 4928, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4929 + * standard_gamma = _rand.standard_gamma + * gamma = _rand.gamma + * f = _rand.f # <<<<<<<<<<<<<< + * noncentral_f = _rand.noncentral_f + * chisquare = _rand.chisquare + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4929, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_f); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4929, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_f, __pyx_t_9) < 0) __PYX_ERR(0, 4929, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4930 + * gamma = _rand.gamma + * f = _rand.f + * noncentral_f = _rand.noncentral_f # <<<<<<<<<<<<<< + * chisquare = _rand.chisquare + * noncentral_chisquare = _rand.noncentral_chisquare + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4930, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_noncentral_f); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4930, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_noncentral_f, __pyx_t_7) < 0) __PYX_ERR(0, 4930, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4931 + * f = _rand.f + * noncentral_f = _rand.noncentral_f + * chisquare = _rand.chisquare # <<<<<<<<<<<<<< + * noncentral_chisquare = _rand.noncentral_chisquare + * standard_cauchy = _rand.standard_cauchy + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4931, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_chisquare); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4931, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_chisquare, __pyx_t_9) < 0) __PYX_ERR(0, 4931, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4932 + * noncentral_f = _rand.noncentral_f + * chisquare = _rand.chisquare + * noncentral_chisquare = _rand.noncentral_chisquare # <<<<<<<<<<<<<< + * standard_cauchy = _rand.standard_cauchy + * standard_t = _rand.standard_t + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4932, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_noncentral_chisquare); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4932, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_noncentral_chisquare, __pyx_t_7) < 0) __PYX_ERR(0, 4932, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4933 + * chisquare = _rand.chisquare + * noncentral_chisquare = _rand.noncentral_chisquare + * standard_cauchy = _rand.standard_cauchy # <<<<<<<<<<<<<< + * standard_t = _rand.standard_t + * vonmises = _rand.vonmises + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4933, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_standard_cauchy); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4933, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_standard_cauchy, __pyx_t_9) < 0) __PYX_ERR(0, 4933, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4934 + * noncentral_chisquare = _rand.noncentral_chisquare + * standard_cauchy = _rand.standard_cauchy + * standard_t = _rand.standard_t # <<<<<<<<<<<<<< + * vonmises = _rand.vonmises + * pareto = _rand.pareto + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4934, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_standard_t); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4934, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_standard_t, __pyx_t_7) < 0) __PYX_ERR(0, 4934, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4935 + * standard_cauchy = _rand.standard_cauchy + * standard_t = _rand.standard_t + * vonmises = _rand.vonmises # <<<<<<<<<<<<<< + * pareto = _rand.pareto + * weibull = _rand.weibull + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4935, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_vonmises); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4935, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_vonmises, __pyx_t_9) < 0) __PYX_ERR(0, 4935, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4936 + * standard_t = _rand.standard_t + * vonmises = _rand.vonmises + * pareto = _rand.pareto # <<<<<<<<<<<<<< + * weibull = _rand.weibull + * power = _rand.power + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4936, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_pareto); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4936, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_pareto, __pyx_t_7) < 0) __PYX_ERR(0, 4936, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4937 + * vonmises = _rand.vonmises + * pareto = _rand.pareto + * weibull = _rand.weibull # <<<<<<<<<<<<<< + * power = _rand.power + * laplace = _rand.laplace + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4937, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_weibull); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4937, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_weibull, __pyx_t_9) < 0) __PYX_ERR(0, 4937, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4938 + * pareto = _rand.pareto + * weibull = _rand.weibull + * power = _rand.power # <<<<<<<<<<<<<< + * laplace = _rand.laplace + * gumbel = _rand.gumbel + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4938, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_power); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4938, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_power, __pyx_t_7) < 0) __PYX_ERR(0, 4938, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4939 + * weibull = _rand.weibull + * power = _rand.power + * laplace = _rand.laplace # <<<<<<<<<<<<<< + * gumbel = _rand.gumbel + * logistic = _rand.logistic + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4939, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_laplace); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4939, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_laplace, __pyx_t_9) < 0) __PYX_ERR(0, 4939, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4940 + * power = _rand.power + * laplace = _rand.laplace + * gumbel = _rand.gumbel # <<<<<<<<<<<<<< + * logistic = _rand.logistic + * lognormal = _rand.lognormal + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4940, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_gumbel); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4940, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_gumbel, __pyx_t_7) < 0) __PYX_ERR(0, 4940, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4941 + * laplace = _rand.laplace + * gumbel = _rand.gumbel + * logistic = _rand.logistic # <<<<<<<<<<<<<< + * lognormal = _rand.lognormal + * rayleigh = _rand.rayleigh + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4941, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_logistic); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4941, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_logistic, __pyx_t_9) < 0) __PYX_ERR(0, 4941, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4942 + * gumbel = _rand.gumbel + * logistic = _rand.logistic + * lognormal = _rand.lognormal # <<<<<<<<<<<<<< + * rayleigh = _rand.rayleigh + * wald = _rand.wald + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4942, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_lognormal); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4942, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_lognormal, __pyx_t_7) < 0) __PYX_ERR(0, 4942, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4943 + * logistic = _rand.logistic + * lognormal = _rand.lognormal + * rayleigh = _rand.rayleigh # <<<<<<<<<<<<<< + * wald = _rand.wald + * triangular = _rand.triangular + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4943, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_rayleigh); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4943, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_rayleigh, __pyx_t_9) < 0) __PYX_ERR(0, 4943, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4944 + * lognormal = _rand.lognormal + * rayleigh = _rand.rayleigh + * wald = _rand.wald # <<<<<<<<<<<<<< + * triangular = _rand.triangular + * + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4944, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_wald); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4944, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_wald, __pyx_t_7) < 0) __PYX_ERR(0, 4944, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4945 + * rayleigh = _rand.rayleigh + * wald = _rand.wald + * triangular = _rand.triangular # <<<<<<<<<<<<<< + * + * binomial = _rand.binomial + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4945, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_triangular); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4945, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_triangular, __pyx_t_9) < 0) __PYX_ERR(0, 4945, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4947 + * triangular = _rand.triangular + * + * binomial = _rand.binomial # <<<<<<<<<<<<<< + * negative_binomial = _rand.negative_binomial + * poisson = _rand.poisson + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4947, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_binomial); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4947, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_binomial, __pyx_t_7) < 0) __PYX_ERR(0, 4947, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4948 + * + * binomial = _rand.binomial + * negative_binomial = _rand.negative_binomial # <<<<<<<<<<<<<< + * poisson = _rand.poisson + * zipf = _rand.zipf + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4948, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_negative_binomial); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4948, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_negative_binomial, __pyx_t_9) < 0) __PYX_ERR(0, 4948, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4949 + * binomial = _rand.binomial + * negative_binomial = _rand.negative_binomial + * poisson = _rand.poisson # <<<<<<<<<<<<<< + * zipf = _rand.zipf + * geometric = _rand.geometric + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4949, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_poisson); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4949, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_poisson, __pyx_t_7) < 0) __PYX_ERR(0, 4949, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4950 + * negative_binomial = _rand.negative_binomial + * poisson = _rand.poisson + * zipf = _rand.zipf # <<<<<<<<<<<<<< + * geometric = _rand.geometric + * hypergeometric = _rand.hypergeometric + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4950, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_zipf); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4950, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_zipf, __pyx_t_9) < 0) __PYX_ERR(0, 4950, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4951 + * poisson = _rand.poisson + * zipf = _rand.zipf + * geometric = _rand.geometric # <<<<<<<<<<<<<< + * hypergeometric = _rand.hypergeometric + * logseries = _rand.logseries + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4951, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_geometric); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4951, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_geometric, __pyx_t_7) < 0) __PYX_ERR(0, 4951, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4952 + * zipf = _rand.zipf + * geometric = _rand.geometric + * hypergeometric = _rand.hypergeometric # <<<<<<<<<<<<<< + * logseries = _rand.logseries + * + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4952, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_hypergeometric); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4952, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_hypergeometric, __pyx_t_9) < 0) __PYX_ERR(0, 4952, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4953 + * geometric = _rand.geometric + * hypergeometric = _rand.hypergeometric + * logseries = _rand.logseries # <<<<<<<<<<<<<< + * + * multivariate_normal = _rand.multivariate_normal + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4953, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_logseries); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4953, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_logseries, __pyx_t_7) < 0) __PYX_ERR(0, 4953, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4955 + * logseries = _rand.logseries + * + * multivariate_normal = _rand.multivariate_normal # <<<<<<<<<<<<<< + * multinomial = _rand.multinomial + * dirichlet = _rand.dirichlet + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4955, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_multivariate_normal); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4955, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_multivariate_normal, __pyx_t_9) < 0) __PYX_ERR(0, 4955, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4956 + * + * multivariate_normal = _rand.multivariate_normal + * multinomial = _rand.multinomial # <<<<<<<<<<<<<< + * dirichlet = _rand.dirichlet + * + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4956, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_multinomial); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4956, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_multinomial, __pyx_t_7) < 0) __PYX_ERR(0, 4956, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4957 + * multivariate_normal = _rand.multivariate_normal + * multinomial = _rand.multinomial + * dirichlet = _rand.dirichlet # <<<<<<<<<<<<<< + * + * shuffle = _rand.shuffle + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4957, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_dirichlet); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4957, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_dirichlet, __pyx_t_9) < 0) __PYX_ERR(0, 4957, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":4959 + * dirichlet = _rand.dirichlet + * + * shuffle = _rand.shuffle # <<<<<<<<<<<<<< + * permutation = _rand.permutation + */ + __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4959, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_shuffle); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4959, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_shuffle, __pyx_t_7) < 0) __PYX_ERR(0, 4959, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "mtrand.pyx":4960 + * + * shuffle = _rand.shuffle + * permutation = _rand.permutation # <<<<<<<<<<<<<< + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_rand_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4960, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_permutation); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 4960, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_permutation, __pyx_t_9) < 0) __PYX_ERR(0, 4960, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /* "mtrand.pyx":1 + * # mtrand.pyx -- A Pyrex wrapper of Jean-Sebastien Roy's RandomKit # <<<<<<<<<<<<<< + * # + * # Copyright 2005 Robert Kern (robert.kern@gmail.com) + */ + __pyx_t_9 = __Pyx_PyDict_NewPresized(43); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_random_sample_line_8, __pyx_kp_u_random_sample_size_None_Return) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_tomaxint_line_863, __pyx_kp_u_tomaxint_size_None_Random_integ) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_randint_line_910, __pyx_kp_u_randint_low_high_None_size_None) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_bytes_line_1004, __pyx_kp_u_bytes_length_Return_random_byte) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_choice_line_1033, __pyx_kp_u_choice_a_size_None_replace_True) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_uniform_line_1215, __pyx_kp_u_uniform_low_0_0_high_1_0_size_N) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_rand_line_1321, __pyx_kp_u_rand_d0_d1_dn_Random_values_in) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_randn_line_1365, __pyx_kp_u_randn_d0_d1_dn_Return_a_sample) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_random_integers_line, __pyx_kp_u_random_integers_low_high_None_s) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_standard_normal_line, __pyx_kp_u_standard_normal_size_None_Draw) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_normal_line_1552, __pyx_kp_u_normal_loc_0_0_scale_1_0_size_N) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_standard_exponential, __pyx_kp_u_standard_exponential_size_None) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_standard_gamma_line, __pyx_kp_u_standard_gamma_shape_size_None) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_gamma_line_1901, __pyx_kp_u_gamma_shape_scale_1_0_size_None) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_f_line_1997, __pyx_kp_u_f_dfnum_dfden_size_None_Draw_sa) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_noncentral_f_line_21, __pyx_kp_u_noncentral_f_dfnum_dfden_nonc_s) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_chisquare_line_2205, __pyx_kp_u_chisquare_df_size_None_Draw_sam) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_noncentral_chisquare, __pyx_kp_u_noncentral_chisquare_df_nonc_si) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_standard_cauchy_line, __pyx_kp_u_standard_cauchy_size_None_Draw) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_standard_t_line_2456, __pyx_kp_u_standard_t_df_size_None_Draw_sa) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_vonmises_line_2562, __pyx_kp_u_vonmises_mu_kappa_size_None_Dra) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_pareto_line_2660, __pyx_kp_u_pareto_a_size_None_Draw_samples) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_weibull_line_2770, __pyx_kp_u_weibull_a_size_None_Draw_sample) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_power_line_2880, __pyx_kp_u_power_a_size_None_Draws_samples) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_laplace_line_2991, __pyx_kp_u_laplace_loc_0_0_scale_1_0_size) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_gumbel_line_3089, __pyx_kp_u_gumbel_loc_0_0_scale_1_0_size_N) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_logistic_line_3220, __pyx_kp_u_logistic_loc_0_0_scale_1_0_size) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_lognormal_line_3313, __pyx_kp_u_lognormal_mean_0_0_sigma_1_0_si) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_rayleigh_line_3437, __pyx_kp_u_rayleigh_scale_1_0_size_None_Dr) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_wald_line_3516, __pyx_kp_u_wald_mean_scale_size_None_Draw) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_triangular_line_3603, __pyx_kp_u_triangular_left_mode_right_size) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_binomial_line_3697, __pyx_kp_u_binomial_n_p_size_None_Draw_sam) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_negative_binomial_li, __pyx_kp_u_negative_binomial_n_p_size_None) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_poisson_line_3914, __pyx_kp_u_poisson_lam_1_0_size_None_Draw) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_zipf_line_4002, __pyx_kp_u_zipf_a_size_None_Draw_samples_f) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_geometric_line_4095, __pyx_kp_u_geometric_p_size_None_Draw_samp) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_hypergeometric_line, __pyx_kp_u_hypergeometric_ngood_nbad_nsamp) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_logseries_line_4285, __pyx_kp_u_logseries_p_size_None_Draw_samp) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_multivariate_normal, __pyx_kp_u_multivariate_normal_mean_cov_si) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_multinomial_line_454, __pyx_kp_u_multinomial_n_pvals_size_None_D) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_dirichlet_line_4656, __pyx_kp_u_dirichlet_alpha_size_None_Draw) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_shuffle_line_4779, __pyx_kp_u_shuffle_x_Modify_a_sequence_in) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_t_9, __pyx_kp_u_RandomState_permutation_line_486, __pyx_kp_u_permutation_x_Randomly_permute) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_9) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + if (__pyx_m) { + if (__pyx_d) { + __Pyx_AddTraceback("init mtrand", 0, __pyx_lineno, __pyx_filename); + } + Py_DECREF(__pyx_m); __pyx_m = 0; + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init mtrand"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule((char *)modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name); + if (unlikely(!result)) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* RaiseDoubleKeywords */ +static void __Pyx_RaiseDoubleKeywordsError( + const char* func_name, + PyObject* kw_name) +{ + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION >= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + while (PyDict_Next(kwds, &pos, &key, &value)) { + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; + continue; + } + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = (**name == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + return -1; +} + +/* GetModuleGlobalName */ +static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) { + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + if (likely(result)) { + Py_INCREF(result); + } else if (unlikely(PyErr_Occurred())) { + result = NULL; + } else { +#else + result = PyDict_GetItem(__pyx_d, name); + if (likely(result)) { + Py_INCREF(result); + } else { +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + if (!result) { + PyErr_Clear(); +#endif + result = __Pyx_GetBuiltinName(name); + } + return result; +} + +/* PyCFunctionFastCall */ + #if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { + PyCFunctionObject *func = (PyCFunctionObject*)func_obj; + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + int flags = PyCFunction_GET_FLAGS(func); + assert(PyCFunction_Check(func)); + assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS))); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + /* _PyCFunction_FastCallDict() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { + return (*((__Pyx_PyCFunctionFastWithKeywords)meth)) (self, args, nargs, NULL); + } else { + return (*((__Pyx_PyCFunctionFast)meth)) (self, args, nargs); + } +} +#endif + +/* PyFunctionFastCall */ + #if CYTHON_FAST_PYCALL +#include "frameobject.h" +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = f->f_localsplus; + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { + return NULL; + } + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif +#endif + +/* PyObjectCall */ + #if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = func->ob_type->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallMethO */ + #if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = PyCFunction_GET_FUNCTION(func); + self = PyCFunction_GET_SELF(func); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallOneArg */ + #if CYTHON_COMPILING_IN_CPYTHON +static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *result; + PyObject *args = PyTuple_New(1); + if (unlikely(!args)) return NULL; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 0, arg); + result = __Pyx_PyObject_Call(func, args, NULL); + Py_DECREF(args); + return result; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { +#if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCall(func, &arg, 1); + } +#endif + if (likely(PyCFunction_Check(func))) { + if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { + return __Pyx_PyObject_CallMethO(func, arg); +#if CYTHON_FAST_PYCCALL + } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { + return __Pyx_PyCFunction_FastCall(func, &arg, 1); +#endif + } + } + return __Pyx__PyObject_CallOneArg(func, arg); +} +#else +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *result; + PyObject *args = PyTuple_Pack(1, arg); + if (unlikely(!args)) return NULL; + result = __Pyx_PyObject_Call(func, args, NULL); + Py_DECREF(args); + return result; +} +#endif + +/* SaveResetException */ + #if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if PY_VERSION_HEX >= 0x030700A2 + *type = tstate->exc_state.exc_type; + *value = tstate->exc_state.exc_value; + *tb = tstate->exc_state.exc_traceback; + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + #endif + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if PY_VERSION_HEX >= 0x030700A2 + tmp_type = tstate->exc_state.exc_type; + tmp_value = tstate->exc_state.exc_value; + tmp_tb = tstate->exc_state.exc_traceback; + tstate->exc_state.exc_type = type; + tstate->exc_state.exc_value = value; + tstate->exc_state.exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} +#endif + +/* PyErrExceptionMatches */ + #if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; icurexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; + if (unlikely(PyTuple_Check(err))) + return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); +} +#endif + +/* GetException */ + #if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) { +#endif + PyObject *local_type, *local_value, *local_tb; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if PY_VERSION_HEX >= 0x030700A2 + tmp_type = tstate->exc_state.exc_type; + tmp_value = tstate->exc_state.exc_value; + tmp_tb = tstate->exc_state.exc_traceback; + tstate->exc_state.exc_type = local_type; + tstate->exc_state.exc_value = local_value; + tstate->exc_state.exc_traceback = local_tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* PyErrFetchRestore */ + #if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +} +#endif + +/* RaiseException */ + #if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, + CYTHON_UNUSED PyObject *cause) { + __Pyx_PyThreadState_declare + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { +#if CYTHON_COMPILING_IN_PYPY + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#else + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* PyObjectCallNoArg */ + #if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { +#if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCall(func, NULL, 0); + } +#endif +#ifdef __Pyx_CyFunction_USED + if (likely(PyCFunction_Check(func) || __Pyx_TypeCheck(func, __pyx_CyFunctionType))) { +#else + if (likely(PyCFunction_Check(func))) { +#endif + if (likely(PyCFunction_GET_FLAGS(func) & METH_NOARGS)) { + return __Pyx_PyObject_CallMethO(func, NULL); + } + } + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL); +} +#endif + +/* ExtTypeTest */ + static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", + Py_TYPE(obj)->tp_name, type->tp_name); + return 0; +} + +/* PyIntBinop */ + #if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_PyInt_EqObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) { + if (op1 == op2) { + Py_RETURN_TRUE; + } + #if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(op1))) { + const long b = intval; + long a = PyInt_AS_LONG(op1); + if (a == b) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } + #endif + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(PyLong_CheckExact(op1))) { + const long b = intval; + long a; + const digit* digits = ((PyLongObject*)op1)->ob_digit; + const Py_ssize_t size = Py_SIZE(op1); + if (likely(__Pyx_sst_abs(size) <= 1)) { + a = likely(size) ? digits[0] : 0; + if (size == -1) a = -a; + } else { + switch (size) { + case -2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; + } + CYTHON_FALLTHROUGH; + case 2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; + } + CYTHON_FALLTHROUGH; + case -3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; + } + CYTHON_FALLTHROUGH; + case 3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; + } + CYTHON_FALLTHROUGH; + case -4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; + } + CYTHON_FALLTHROUGH; + case 4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; + } + CYTHON_FALLTHROUGH; + #if PyLong_SHIFT < 30 && PyLong_SHIFT != 15 + default: return PyLong_Type.tp_richcompare(op1, op2, Py_EQ); + #else + default: Py_RETURN_FALSE; + #endif + } + } + if (a == b) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } + #endif + if (PyFloat_CheckExact(op1)) { + const long b = intval; + double a = PyFloat_AS_DOUBLE(op1); + if ((double)a == (double)b) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } + return PyObject_RichCompare(op1, op2, Py_EQ); +} +#endif + +/* GetItemInt */ + static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (!j) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely((0 <= wrapped_i) & (wrapped_i < PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely((0 <= wrapped_i) & (wrapped_i < PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely((n >= 0) & (n < PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely((n >= 0) & (n < PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; + if (likely(m && m->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { + Py_ssize_t l = m->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return m->sq_item(o, i); + } + } +#else + if (is_list || PySequence_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* BytesEquals */ + static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY + return PyObject_RichCompareBool(s1, s2, equals); +#else + if (s1 == s2) { + return (equals == Py_EQ); + } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { + const char *ps1, *ps2; + Py_ssize_t length = PyBytes_GET_SIZE(s1); + if (length != PyBytes_GET_SIZE(s2)) + return (equals == Py_NE); + ps1 = PyBytes_AS_STRING(s1); + ps2 = PyBytes_AS_STRING(s2); + if (ps1[0] != ps2[0]) { + return (equals == Py_NE); + } else if (length == 1) { + return (equals == Py_EQ); + } else { + int result; +#if CYTHON_USE_UNICODE_INTERNALS + Py_hash_t hash1, hash2; + hash1 = ((PyBytesObject*)s1)->ob_shash; + hash2 = ((PyBytesObject*)s2)->ob_shash; + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + return (equals == Py_NE); + } +#endif + result = memcmp(ps1, ps2, (size_t)length); + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { + return (equals == Py_NE); + } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { + return (equals == Py_NE); + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +#endif +} + +/* UnicodeEquals */ + static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { +#if CYTHON_COMPILING_IN_PYPY + return PyObject_RichCompareBool(s1, s2, equals); +#else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; + if (s1 == s2) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { + Py_ssize_t length; + int kind; + void *data1, *data2; + if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) + return -1; + length = __Pyx_PyUnicode_GET_LENGTH(s1); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } +#if CYTHON_USE_UNICODE_INTERNALS + { + Py_hash_t hash1, hash2; + #if CYTHON_PEP393_ENABLED + hash1 = ((PyASCIIObject*)s1)->hash; + hash2 = ((PyASCIIObject*)s2)->hash; + #else + hash1 = ((PyUnicodeObject*)s1)->hash; + hash2 = ((PyUnicodeObject*)s2)->hash; + #endif + if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { + goto return_ne; + } + } +#endif + kind = __Pyx_PyUnicode_KIND(s1); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } + data1 = __Pyx_PyUnicode_DATA(s1); + data2 = __Pyx_PyUnicode_DATA(s2); + if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { + goto return_ne; + } else if (length == 1) { + goto return_eq; + } else { + int result = memcmp(data1, data2, (size_t)(length * kind)); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ) ? (result == 0) : (result != 0); + } + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; + } else { + int result; + PyObject* py_result = PyObject_RichCompare(s1, s2, equals); + if (!py_result) + return -1; + result = __Pyx_PyObject_IsTrue(py_result); + Py_DECREF(py_result); + return result; + } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); +#endif +} + +/* SliceObject */ + static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice(PyObject* obj, + Py_ssize_t cstart, Py_ssize_t cstop, + PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice, + int has_cstart, int has_cstop, CYTHON_UNUSED int wraparound) { +#if CYTHON_USE_TYPE_SLOTS + PyMappingMethods* mp; +#if PY_MAJOR_VERSION < 3 + PySequenceMethods* ms = Py_TYPE(obj)->tp_as_sequence; + if (likely(ms && ms->sq_slice)) { + if (!has_cstart) { + if (_py_start && (*_py_start != Py_None)) { + cstart = __Pyx_PyIndex_AsSsize_t(*_py_start); + if ((cstart == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; + } else + cstart = 0; + } + if (!has_cstop) { + if (_py_stop && (*_py_stop != Py_None)) { + cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop); + if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; + } else + cstop = PY_SSIZE_T_MAX; + } + if (wraparound && unlikely((cstart < 0) | (cstop < 0)) && likely(ms->sq_length)) { + Py_ssize_t l = ms->sq_length(obj); + if (likely(l >= 0)) { + if (cstop < 0) { + cstop += l; + if (cstop < 0) cstop = 0; + } + if (cstart < 0) { + cstart += l; + if (cstart < 0) cstart = 0; + } + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + goto bad; + PyErr_Clear(); + } + } + return ms->sq_slice(obj, cstart, cstop); + } +#endif + mp = Py_TYPE(obj)->tp_as_mapping; + if (likely(mp && mp->mp_subscript)) +#endif + { + PyObject* result; + PyObject *py_slice, *py_start, *py_stop; + if (_py_slice) { + py_slice = *_py_slice; + } else { + PyObject* owned_start = NULL; + PyObject* owned_stop = NULL; + if (_py_start) { + py_start = *_py_start; + } else { + if (has_cstart) { + owned_start = py_start = PyInt_FromSsize_t(cstart); + if (unlikely(!py_start)) goto bad; + } else + py_start = Py_None; + } + if (_py_stop) { + py_stop = *_py_stop; + } else { + if (has_cstop) { + owned_stop = py_stop = PyInt_FromSsize_t(cstop); + if (unlikely(!py_stop)) { + Py_XDECREF(owned_start); + goto bad; + } + } else + py_stop = Py_None; + } + py_slice = PySlice_New(py_start, py_stop, Py_None); + Py_XDECREF(owned_start); + Py_XDECREF(owned_stop); + if (unlikely(!py_slice)) goto bad; + } +#if CYTHON_USE_TYPE_SLOTS + result = mp->mp_subscript(obj, py_slice); +#else + result = PyObject_GetItem(obj, py_slice); +#endif + if (!_py_slice) { + Py_DECREF(py_slice); + } + return result; + } + PyErr_Format(PyExc_TypeError, + "'%.200s' object is unsliceable", Py_TYPE(obj)->tp_name); +bad: + return NULL; +} + +/* RaiseTooManyValuesToUnpack */ + static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { + PyErr_Format(PyExc_ValueError, + "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); +} + +/* RaiseNeedMoreValuesToUnpack */ + static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { + PyErr_Format(PyExc_ValueError, + "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", + index, (index == 1) ? "" : "s"); +} + +/* IterFinish */ + static CYTHON_INLINE int __Pyx_IterFinish(void) { +#if CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* exc_type = tstate->curexc_type; + if (unlikely(exc_type)) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) { + PyObject *exc_value, *exc_tb; + exc_value = tstate->curexc_value; + exc_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; + Py_DECREF(exc_type); + Py_XDECREF(exc_value); + Py_XDECREF(exc_tb); + return 0; + } else { + return -1; + } + } + return 0; +#else + if (unlikely(PyErr_Occurred())) { + if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) { + PyErr_Clear(); + return 0; + } else { + return -1; + } + } + return 0; +#endif +} + +/* UnpackItemEndCheck */ + static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) { + if (unlikely(retval)) { + Py_DECREF(retval); + __Pyx_RaiseTooManyValuesError(expected); + return -1; + } else { + return __Pyx_IterFinish(); + } + return 0; +} + +/* ObjectGetItem */ + #if CYTHON_USE_TYPE_SLOTS +static PyObject *__Pyx_PyObject_GetIndex(PyObject *obj, PyObject* index) { + PyObject *runerr; + Py_ssize_t key_value; + PySequenceMethods *m = Py_TYPE(obj)->tp_as_sequence; + if (unlikely(!(m && m->sq_item))) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not subscriptable", Py_TYPE(obj)->tp_name); + return NULL; + } + key_value = __Pyx_PyIndex_AsSsize_t(index); + if (likely(key_value != -1 || !(runerr = PyErr_Occurred()))) { + return __Pyx_GetItemInt_Fast(obj, key_value, 0, 1, 1); + } + if (PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { + PyErr_Clear(); + PyErr_Format(PyExc_IndexError, "cannot fit '%.200s' into an index-sized integer", Py_TYPE(index)->tp_name); + } + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject* key) { + PyMappingMethods *m = Py_TYPE(obj)->tp_as_mapping; + if (likely(m && m->mp_subscript)) { + return m->mp_subscript(obj, key); + } + return __Pyx_PyObject_GetIndex(obj, key); +} +#endif + +/* PyIntBinop */ + #if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_PyInt_SubtractObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) { + #if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(op1))) { + const long b = intval; + long x; + long a = PyInt_AS_LONG(op1); + x = (long)((unsigned long)a - b); + if (likely((x^a) >= 0 || (x^~b) >= 0)) + return PyInt_FromLong(x); + return PyLong_Type.tp_as_number->nb_subtract(op1, op2); + } + #endif + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(PyLong_CheckExact(op1))) { + const long b = intval; + long a, x; +#ifdef HAVE_LONG_LONG + const PY_LONG_LONG llb = intval; + PY_LONG_LONG lla, llx; +#endif + const digit* digits = ((PyLongObject*)op1)->ob_digit; + const Py_ssize_t size = Py_SIZE(op1); + if (likely(__Pyx_sst_abs(size) <= 1)) { + a = likely(size) ? digits[0] : 0; + if (size == -1) a = -a; + } else { + switch (size) { + case -2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case -3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case -4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + default: return PyLong_Type.tp_as_number->nb_subtract(op1, op2); + } + } + x = a - b; + return PyLong_FromLong(x); +#ifdef HAVE_LONG_LONG + long_long: + llx = lla - llb; + return PyLong_FromLongLong(llx); +#endif + + + } + #endif + if (PyFloat_CheckExact(op1)) { + const long b = intval; + double a = PyFloat_AS_DOUBLE(op1); + double result; + PyFPE_START_PROTECT("subtract", return NULL) + result = ((double)a) - (double)b; + PyFPE_END_PROTECT(result) + return PyFloat_FromDouble(result); + } + return (inplace ? PyNumber_InPlaceSubtract : PyNumber_Subtract)(op1, op2); +} +#endif + +/* SliceObject */ + static CYTHON_INLINE int __Pyx_PyObject_SetSlice(PyObject* obj, PyObject* value, + Py_ssize_t cstart, Py_ssize_t cstop, + PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice, + int has_cstart, int has_cstop, CYTHON_UNUSED int wraparound) { +#if CYTHON_USE_TYPE_SLOTS + PyMappingMethods* mp; +#if PY_MAJOR_VERSION < 3 + PySequenceMethods* ms = Py_TYPE(obj)->tp_as_sequence; + if (likely(ms && ms->sq_ass_slice)) { + if (!has_cstart) { + if (_py_start && (*_py_start != Py_None)) { + cstart = __Pyx_PyIndex_AsSsize_t(*_py_start); + if ((cstart == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; + } else + cstart = 0; + } + if (!has_cstop) { + if (_py_stop && (*_py_stop != Py_None)) { + cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop); + if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; + } else + cstop = PY_SSIZE_T_MAX; + } + if (wraparound && unlikely((cstart < 0) | (cstop < 0)) && likely(ms->sq_length)) { + Py_ssize_t l = ms->sq_length(obj); + if (likely(l >= 0)) { + if (cstop < 0) { + cstop += l; + if (cstop < 0) cstop = 0; + } + if (cstart < 0) { + cstart += l; + if (cstart < 0) cstart = 0; + } + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + goto bad; + PyErr_Clear(); + } + } + return ms->sq_ass_slice(obj, cstart, cstop, value); + } +#endif + mp = Py_TYPE(obj)->tp_as_mapping; + if (likely(mp && mp->mp_ass_subscript)) +#endif + { + int result; + PyObject *py_slice, *py_start, *py_stop; + if (_py_slice) { + py_slice = *_py_slice; + } else { + PyObject* owned_start = NULL; + PyObject* owned_stop = NULL; + if (_py_start) { + py_start = *_py_start; + } else { + if (has_cstart) { + owned_start = py_start = PyInt_FromSsize_t(cstart); + if (unlikely(!py_start)) goto bad; + } else + py_start = Py_None; + } + if (_py_stop) { + py_stop = *_py_stop; + } else { + if (has_cstop) { + owned_stop = py_stop = PyInt_FromSsize_t(cstop); + if (unlikely(!py_stop)) { + Py_XDECREF(owned_start); + goto bad; + } + } else + py_stop = Py_None; + } + py_slice = PySlice_New(py_start, py_stop, Py_None); + Py_XDECREF(owned_start); + Py_XDECREF(owned_stop); + if (unlikely(!py_slice)) goto bad; + } +#if CYTHON_USE_TYPE_SLOTS + result = mp->mp_ass_subscript(obj, py_slice, value); +#else + result = value ? PyObject_SetItem(obj, py_slice, value) : PyObject_DelItem(obj, py_slice); +#endif + if (!_py_slice) { + Py_DECREF(py_slice); + } + return result; + } + PyErr_Format(PyExc_TypeError, + "'%.200s' object does not support slice %.10s", + Py_TYPE(obj)->tp_name, value ? "assignment" : "deletion"); +bad: + return -1; +} + +/* PyObjectSetAttrStr */ + #if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_setattro)) + return tp->tp_setattro(obj, attr_name, value); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_setattr)) + return tp->tp_setattr(obj, PyString_AS_STRING(attr_name), value); +#endif + return PyObject_SetAttr(obj, attr_name, value); +} +#endif + +/* KeywordStringCheck */ + static int __Pyx_CheckKeywordStrings( + PyObject *kwdict, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kwdict, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + while (PyDict_Next(kwdict, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if ((!kw_allowed) && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* PyIntBinop */ + #if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) { + #if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(op1))) { + const long b = intval; + long x; + long a = PyInt_AS_LONG(op1); + x = (long)((unsigned long)a + b); + if (likely((x^a) >= 0 || (x^b) >= 0)) + return PyInt_FromLong(x); + return PyLong_Type.tp_as_number->nb_add(op1, op2); + } + #endif + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(PyLong_CheckExact(op1))) { + const long b = intval; + long a, x; +#ifdef HAVE_LONG_LONG + const PY_LONG_LONG llb = intval; + PY_LONG_LONG lla, llx; +#endif + const digit* digits = ((PyLongObject*)op1)->ob_digit; + const Py_ssize_t size = Py_SIZE(op1); + if (likely(__Pyx_sst_abs(size) <= 1)) { + a = likely(size) ? digits[0] : 0; + if (size == -1) a = -a; + } else { + switch (size) { + case -2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case -3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case -4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + default: return PyLong_Type.tp_as_number->nb_add(op1, op2); + } + } + x = a + b; + return PyLong_FromLong(x); +#ifdef HAVE_LONG_LONG + long_long: + llx = lla + llb; + return PyLong_FromLongLong(llx); +#endif + + + } + #endif + if (PyFloat_CheckExact(op1)) { + const long b = intval; + double a = PyFloat_AS_DOUBLE(op1); + double result; + PyFPE_START_PROTECT("add", return NULL) + result = ((double)a) + (double)b; + PyFPE_END_PROTECT(result) + return PyFloat_FromDouble(result); + } + return (inplace ? PyNumber_InPlaceAdd : PyNumber_Add)(op1, op2); +} +#endif + +/* Import */ + static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *empty_list = 0; + PyObject *module = 0; + PyObject *global_dict = 0; + PyObject *empty_dict = 0; + PyObject *list; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (!py_import) + goto bad; + #endif + if (from_list) + list = from_list; + else { + empty_list = PyList_New(0); + if (!empty_list) + goto bad; + list = empty_list; + } + global_dict = PyModule_GetDict(__pyx_m); + if (!global_dict) + goto bad; + empty_dict = PyDict_New(); + if (!empty_dict) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.')) { + module = PyImport_ImportModuleLevelObject( + name, global_dict, empty_dict, list, 1); + if (!module) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (!py_level) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, global_dict, empty_dict, list, py_level, NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, global_dict, empty_dict, list, level); + #endif + } + } +bad: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + Py_XDECREF(empty_list); + Py_XDECREF(empty_dict); + return module; +} + +/* ImportFrom */ + static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* SetItemInt */ + static int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { + int r; + if (!j) return -1; + r = PyObject_SetItem(o, j, v); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int is_list, + CYTHON_NCP_UNUSED int wraparound, CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o)); + if ((!boundscheck) || likely((n >= 0) & (n < PyList_GET_SIZE(o)))) { + PyObject* old = PyList_GET_ITEM(o, n); + Py_INCREF(v); + PyList_SET_ITEM(o, n, v); + Py_DECREF(old); + return 1; + } + } else { + PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; + if (likely(m && m->sq_ass_item)) { + if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { + Py_ssize_t l = m->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return -1; + PyErr_Clear(); + } + } + return m->sq_ass_item(o, i, v); + } + } +#else +#if CYTHON_COMPILING_IN_PYPY + if (is_list || (PySequence_Check(o) && !PyDict_Check(o))) { +#else + if (is_list || PySequence_Check(o)) { +#endif + return PySequence_SetItem(o, i, v); + } +#endif + return __Pyx_SetItemInt_Generic(o, PyInt_FromSsize_t(i), v); +} + +/* PyObject_GenericGetAttrNoDict */ + #if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'%.50s' object has no attribute '%U'", + tp->tp_name, attr_name); +#else + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(attr_name)); +#endif + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ + #if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* SetVTable */ + static int __Pyx_SetVtable(PyObject *dict, void *vtable) { +#if PY_VERSION_HEX >= 0x02070000 + PyObject *ob = PyCapsule_New(vtable, 0, 0); +#else + PyObject *ob = PyCObject_FromVoidPtr(vtable, 0); +#endif + if (!ob) + goto bad; + if (PyDict_SetItem(dict, __pyx_n_s_pyx_vtable, ob) < 0) + goto bad; + Py_DECREF(ob); + return 0; +bad: + Py_XDECREF(ob); + return -1; +} + +/* CLineInTraceback */ + #ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(CYTHON_UNUSED PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + use_cline = __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback); + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (PyObject_Not(use_cline) != 0) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ + static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} + +/* AddTraceback */ + #include "compile.h" +#include "frameobject.h" +#include "traceback.h" +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyObject *py_srcfile = 0; + PyObject *py_funcname = 0; + #if PY_MAJOR_VERSION < 3 + py_srcfile = PyString_FromString(filename); + #else + py_srcfile = PyUnicode_FromString(filename); + #endif + if (!py_srcfile) goto bad; + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + #else + py_funcname = PyUnicode_FromString(funcname); + #endif + } + if (!py_funcname) goto bad; + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + Py_DECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_srcfile); + Py_XDECREF(py_funcname); + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) goto bad; + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} + +/* CIntFromPyVerify */ + #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_bool(npy_bool value) { + const npy_bool neg_one = (npy_bool) -1, const_zero = (npy_bool) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_bool) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_bool) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_bool) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_bool) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_bool) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_bool), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_int8(npy_int8 value) { + const npy_int8 neg_one = (npy_int8) -1, const_zero = (npy_int8) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_int8) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_int8) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int8) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_int8) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int8) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_int8), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_int16(npy_int16 value) { + const npy_int16 neg_one = (npy_int16) -1, const_zero = (npy_int16) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_int16) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_int16) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int16) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_int16) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int16) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_int16), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_int32(npy_int32 value) { + const npy_int32 neg_one = (npy_int32) -1, const_zero = (npy_int32) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_int32) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_int32) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int32) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_int32) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int32) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_int32), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_int64(npy_int64 value) { + const npy_int64 neg_one = (npy_int64) -1, const_zero = (npy_int64) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_int64) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_int64) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int64) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_int64) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int64) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_int64), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_uint8(npy_uint8 value) { + const npy_uint8 neg_one = (npy_uint8) -1, const_zero = (npy_uint8) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_uint8) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_uint8) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint8) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_uint8) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint8) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_uint8), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_uint16(npy_uint16 value) { + const npy_uint16 neg_one = (npy_uint16) -1, const_zero = (npy_uint16) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_uint16) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_uint16) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint16) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_uint16) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint16) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_uint16), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_uint32(npy_uint32 value) { + const npy_uint32 neg_one = (npy_uint32) -1, const_zero = (npy_uint32) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_uint32) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_uint32) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint32) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_uint32) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint32) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_uint32), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_uint64(npy_uint64 value) { + const npy_uint64 neg_one = (npy_uint64) -1, const_zero = (npy_uint64) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_uint64) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_uint64) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint64) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_uint64) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint64) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_uint64), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_npy_intp(npy_intp value) { + const npy_intp neg_one = (npy_intp) -1, const_zero = (npy_intp) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(npy_intp) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(npy_intp) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_intp) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(npy_intp) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_intp) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(npy_intp), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { + const long neg_one = (long) -1, const_zero = (long) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { + const int neg_one = (int) -1, const_zero = (int) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); + } +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_intp __Pyx_PyInt_As_npy_intp(PyObject *x) { + const npy_intp neg_one = (npy_intp) -1, const_zero = (npy_intp) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_intp) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_intp, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_intp) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_intp) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_intp, digit, digits[0]) + case 2: + if (8 * sizeof(npy_intp) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) >= 2 * PyLong_SHIFT) { + return (npy_intp) (((((npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_intp) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) >= 3 * PyLong_SHIFT) { + return (npy_intp) (((((((npy_intp)digits[2]) << PyLong_SHIFT) | (npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_intp) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) >= 4 * PyLong_SHIFT) { + return (npy_intp) (((((((((npy_intp)digits[3]) << PyLong_SHIFT) | (npy_intp)digits[2]) << PyLong_SHIFT) | (npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_intp) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_intp) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_intp, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_intp) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_intp, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_intp) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_intp, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_intp, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_intp) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) - 1 > 2 * PyLong_SHIFT) { + return (npy_intp) (((npy_intp)-1)*(((((npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_intp) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) - 1 > 2 * PyLong_SHIFT) { + return (npy_intp) ((((((npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_intp) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) - 1 > 3 * PyLong_SHIFT) { + return (npy_intp) (((npy_intp)-1)*(((((((npy_intp)digits[2]) << PyLong_SHIFT) | (npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_intp) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) - 1 > 3 * PyLong_SHIFT) { + return (npy_intp) ((((((((npy_intp)digits[2]) << PyLong_SHIFT) | (npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_intp) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) - 1 > 4 * PyLong_SHIFT) { + return (npy_intp) (((npy_intp)-1)*(((((((((npy_intp)digits[3]) << PyLong_SHIFT) | (npy_intp)digits[2]) << PyLong_SHIFT) | (npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_intp) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_intp, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_intp) - 1 > 4 * PyLong_SHIFT) { + return (npy_intp) ((((((((((npy_intp)digits[3]) << PyLong_SHIFT) | (npy_intp)digits[2]) << PyLong_SHIFT) | (npy_intp)digits[1]) << PyLong_SHIFT) | (npy_intp)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_intp) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_intp, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_intp) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_intp, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_intp val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_intp) -1; + } + } else { + npy_intp val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_intp) -1; + val = __Pyx_PyInt_As_npy_intp(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_intp"); + return (npy_intp) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_intp"); + return (npy_intp) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_bool __Pyx_PyInt_As_npy_bool(PyObject *x) { + const npy_bool neg_one = (npy_bool) -1, const_zero = (npy_bool) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_bool) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_bool, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_bool) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_bool) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_bool, digit, digits[0]) + case 2: + if (8 * sizeof(npy_bool) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) >= 2 * PyLong_SHIFT) { + return (npy_bool) (((((npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_bool) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) >= 3 * PyLong_SHIFT) { + return (npy_bool) (((((((npy_bool)digits[2]) << PyLong_SHIFT) | (npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_bool) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) >= 4 * PyLong_SHIFT) { + return (npy_bool) (((((((((npy_bool)digits[3]) << PyLong_SHIFT) | (npy_bool)digits[2]) << PyLong_SHIFT) | (npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_bool) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_bool) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_bool, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_bool) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_bool, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_bool) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_bool, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_bool, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_bool) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) - 1 > 2 * PyLong_SHIFT) { + return (npy_bool) (((npy_bool)-1)*(((((npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_bool) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) - 1 > 2 * PyLong_SHIFT) { + return (npy_bool) ((((((npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_bool) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) - 1 > 3 * PyLong_SHIFT) { + return (npy_bool) (((npy_bool)-1)*(((((((npy_bool)digits[2]) << PyLong_SHIFT) | (npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_bool) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) - 1 > 3 * PyLong_SHIFT) { + return (npy_bool) ((((((((npy_bool)digits[2]) << PyLong_SHIFT) | (npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_bool) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) - 1 > 4 * PyLong_SHIFT) { + return (npy_bool) (((npy_bool)-1)*(((((((((npy_bool)digits[3]) << PyLong_SHIFT) | (npy_bool)digits[2]) << PyLong_SHIFT) | (npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_bool) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_bool, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_bool) - 1 > 4 * PyLong_SHIFT) { + return (npy_bool) ((((((((((npy_bool)digits[3]) << PyLong_SHIFT) | (npy_bool)digits[2]) << PyLong_SHIFT) | (npy_bool)digits[1]) << PyLong_SHIFT) | (npy_bool)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_bool) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_bool, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_bool) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_bool, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_bool val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_bool) -1; + } + } else { + npy_bool val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_bool) -1; + val = __Pyx_PyInt_As_npy_bool(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_bool"); + return (npy_bool) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_bool"); + return (npy_bool) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_uint8 __Pyx_PyInt_As_npy_uint8(PyObject *x) { + const npy_uint8 neg_one = (npy_uint8) -1, const_zero = (npy_uint8) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_uint8) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_uint8, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_uint8) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_uint8) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_uint8, digit, digits[0]) + case 2: + if (8 * sizeof(npy_uint8) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) >= 2 * PyLong_SHIFT) { + return (npy_uint8) (((((npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_uint8) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) >= 3 * PyLong_SHIFT) { + return (npy_uint8) (((((((npy_uint8)digits[2]) << PyLong_SHIFT) | (npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_uint8) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) >= 4 * PyLong_SHIFT) { + return (npy_uint8) (((((((((npy_uint8)digits[3]) << PyLong_SHIFT) | (npy_uint8)digits[2]) << PyLong_SHIFT) | (npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_uint8) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_uint8) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint8, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint8) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint8, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_uint8) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_uint8, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_uint8, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_uint8) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) - 1 > 2 * PyLong_SHIFT) { + return (npy_uint8) (((npy_uint8)-1)*(((((npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_uint8) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) - 1 > 2 * PyLong_SHIFT) { + return (npy_uint8) ((((((npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_uint8) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) - 1 > 3 * PyLong_SHIFT) { + return (npy_uint8) (((npy_uint8)-1)*(((((((npy_uint8)digits[2]) << PyLong_SHIFT) | (npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_uint8) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) - 1 > 3 * PyLong_SHIFT) { + return (npy_uint8) ((((((((npy_uint8)digits[2]) << PyLong_SHIFT) | (npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_uint8) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) - 1 > 4 * PyLong_SHIFT) { + return (npy_uint8) (((npy_uint8)-1)*(((((((((npy_uint8)digits[3]) << PyLong_SHIFT) | (npy_uint8)digits[2]) << PyLong_SHIFT) | (npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_uint8) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint8, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint8) - 1 > 4 * PyLong_SHIFT) { + return (npy_uint8) ((((((((((npy_uint8)digits[3]) << PyLong_SHIFT) | (npy_uint8)digits[2]) << PyLong_SHIFT) | (npy_uint8)digits[1]) << PyLong_SHIFT) | (npy_uint8)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_uint8) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint8, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint8) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint8, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_uint8 val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_uint8) -1; + } + } else { + npy_uint8 val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_uint8) -1; + val = __Pyx_PyInt_As_npy_uint8(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_uint8"); + return (npy_uint8) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_uint8"); + return (npy_uint8) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_int8 __Pyx_PyInt_As_npy_int8(PyObject *x) { + const npy_int8 neg_one = (npy_int8) -1, const_zero = (npy_int8) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_int8) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_int8, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_int8) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_int8) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_int8, digit, digits[0]) + case 2: + if (8 * sizeof(npy_int8) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) >= 2 * PyLong_SHIFT) { + return (npy_int8) (((((npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_int8) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) >= 3 * PyLong_SHIFT) { + return (npy_int8) (((((((npy_int8)digits[2]) << PyLong_SHIFT) | (npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_int8) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) >= 4 * PyLong_SHIFT) { + return (npy_int8) (((((((((npy_int8)digits[3]) << PyLong_SHIFT) | (npy_int8)digits[2]) << PyLong_SHIFT) | (npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_int8) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_int8) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int8, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int8) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int8, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_int8) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_int8, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_int8, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_int8) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) - 1 > 2 * PyLong_SHIFT) { + return (npy_int8) (((npy_int8)-1)*(((((npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_int8) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) - 1 > 2 * PyLong_SHIFT) { + return (npy_int8) ((((((npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_int8) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) - 1 > 3 * PyLong_SHIFT) { + return (npy_int8) (((npy_int8)-1)*(((((((npy_int8)digits[2]) << PyLong_SHIFT) | (npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_int8) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) - 1 > 3 * PyLong_SHIFT) { + return (npy_int8) ((((((((npy_int8)digits[2]) << PyLong_SHIFT) | (npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_int8) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) - 1 > 4 * PyLong_SHIFT) { + return (npy_int8) (((npy_int8)-1)*(((((((((npy_int8)digits[3]) << PyLong_SHIFT) | (npy_int8)digits[2]) << PyLong_SHIFT) | (npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_int8) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int8, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int8) - 1 > 4 * PyLong_SHIFT) { + return (npy_int8) ((((((((((npy_int8)digits[3]) << PyLong_SHIFT) | (npy_int8)digits[2]) << PyLong_SHIFT) | (npy_int8)digits[1]) << PyLong_SHIFT) | (npy_int8)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_int8) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int8, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int8) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int8, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_int8 val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_int8) -1; + } + } else { + npy_int8 val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_int8) -1; + val = __Pyx_PyInt_As_npy_int8(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_int8"); + return (npy_int8) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_int8"); + return (npy_int8) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_uint16 __Pyx_PyInt_As_npy_uint16(PyObject *x) { + const npy_uint16 neg_one = (npy_uint16) -1, const_zero = (npy_uint16) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_uint16) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_uint16, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_uint16) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_uint16) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_uint16, digit, digits[0]) + case 2: + if (8 * sizeof(npy_uint16) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) >= 2 * PyLong_SHIFT) { + return (npy_uint16) (((((npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_uint16) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) >= 3 * PyLong_SHIFT) { + return (npy_uint16) (((((((npy_uint16)digits[2]) << PyLong_SHIFT) | (npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_uint16) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) >= 4 * PyLong_SHIFT) { + return (npy_uint16) (((((((((npy_uint16)digits[3]) << PyLong_SHIFT) | (npy_uint16)digits[2]) << PyLong_SHIFT) | (npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_uint16) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_uint16) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint16, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint16) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint16, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_uint16) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_uint16, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_uint16, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_uint16) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) - 1 > 2 * PyLong_SHIFT) { + return (npy_uint16) (((npy_uint16)-1)*(((((npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_uint16) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) - 1 > 2 * PyLong_SHIFT) { + return (npy_uint16) ((((((npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_uint16) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) - 1 > 3 * PyLong_SHIFT) { + return (npy_uint16) (((npy_uint16)-1)*(((((((npy_uint16)digits[2]) << PyLong_SHIFT) | (npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_uint16) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) - 1 > 3 * PyLong_SHIFT) { + return (npy_uint16) ((((((((npy_uint16)digits[2]) << PyLong_SHIFT) | (npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_uint16) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) - 1 > 4 * PyLong_SHIFT) { + return (npy_uint16) (((npy_uint16)-1)*(((((((((npy_uint16)digits[3]) << PyLong_SHIFT) | (npy_uint16)digits[2]) << PyLong_SHIFT) | (npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_uint16) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint16, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint16) - 1 > 4 * PyLong_SHIFT) { + return (npy_uint16) ((((((((((npy_uint16)digits[3]) << PyLong_SHIFT) | (npy_uint16)digits[2]) << PyLong_SHIFT) | (npy_uint16)digits[1]) << PyLong_SHIFT) | (npy_uint16)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_uint16) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint16, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint16) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint16, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_uint16 val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_uint16) -1; + } + } else { + npy_uint16 val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_uint16) -1; + val = __Pyx_PyInt_As_npy_uint16(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_uint16"); + return (npy_uint16) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_uint16"); + return (npy_uint16) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_int16 __Pyx_PyInt_As_npy_int16(PyObject *x) { + const npy_int16 neg_one = (npy_int16) -1, const_zero = (npy_int16) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_int16) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_int16, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_int16) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_int16) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_int16, digit, digits[0]) + case 2: + if (8 * sizeof(npy_int16) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) >= 2 * PyLong_SHIFT) { + return (npy_int16) (((((npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_int16) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) >= 3 * PyLong_SHIFT) { + return (npy_int16) (((((((npy_int16)digits[2]) << PyLong_SHIFT) | (npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_int16) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) >= 4 * PyLong_SHIFT) { + return (npy_int16) (((((((((npy_int16)digits[3]) << PyLong_SHIFT) | (npy_int16)digits[2]) << PyLong_SHIFT) | (npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_int16) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_int16) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int16, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int16) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int16, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_int16) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_int16, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_int16, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_int16) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) - 1 > 2 * PyLong_SHIFT) { + return (npy_int16) (((npy_int16)-1)*(((((npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_int16) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) - 1 > 2 * PyLong_SHIFT) { + return (npy_int16) ((((((npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_int16) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) - 1 > 3 * PyLong_SHIFT) { + return (npy_int16) (((npy_int16)-1)*(((((((npy_int16)digits[2]) << PyLong_SHIFT) | (npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_int16) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) - 1 > 3 * PyLong_SHIFT) { + return (npy_int16) ((((((((npy_int16)digits[2]) << PyLong_SHIFT) | (npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_int16) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) - 1 > 4 * PyLong_SHIFT) { + return (npy_int16) (((npy_int16)-1)*(((((((((npy_int16)digits[3]) << PyLong_SHIFT) | (npy_int16)digits[2]) << PyLong_SHIFT) | (npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_int16) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int16, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int16) - 1 > 4 * PyLong_SHIFT) { + return (npy_int16) ((((((((((npy_int16)digits[3]) << PyLong_SHIFT) | (npy_int16)digits[2]) << PyLong_SHIFT) | (npy_int16)digits[1]) << PyLong_SHIFT) | (npy_int16)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_int16) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int16, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int16) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int16, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_int16 val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_int16) -1; + } + } else { + npy_int16 val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_int16) -1; + val = __Pyx_PyInt_As_npy_int16(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_int16"); + return (npy_int16) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_int16"); + return (npy_int16) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_uint32 __Pyx_PyInt_As_npy_uint32(PyObject *x) { + const npy_uint32 neg_one = (npy_uint32) -1, const_zero = (npy_uint32) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_uint32) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_uint32, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_uint32) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_uint32) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_uint32, digit, digits[0]) + case 2: + if (8 * sizeof(npy_uint32) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) >= 2 * PyLong_SHIFT) { + return (npy_uint32) (((((npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_uint32) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) >= 3 * PyLong_SHIFT) { + return (npy_uint32) (((((((npy_uint32)digits[2]) << PyLong_SHIFT) | (npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_uint32) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) >= 4 * PyLong_SHIFT) { + return (npy_uint32) (((((((((npy_uint32)digits[3]) << PyLong_SHIFT) | (npy_uint32)digits[2]) << PyLong_SHIFT) | (npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_uint32) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_uint32) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint32, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint32) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint32, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_uint32) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_uint32, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_uint32, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_uint32) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) - 1 > 2 * PyLong_SHIFT) { + return (npy_uint32) (((npy_uint32)-1)*(((((npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_uint32) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) - 1 > 2 * PyLong_SHIFT) { + return (npy_uint32) ((((((npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_uint32) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) - 1 > 3 * PyLong_SHIFT) { + return (npy_uint32) (((npy_uint32)-1)*(((((((npy_uint32)digits[2]) << PyLong_SHIFT) | (npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_uint32) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) - 1 > 3 * PyLong_SHIFT) { + return (npy_uint32) ((((((((npy_uint32)digits[2]) << PyLong_SHIFT) | (npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_uint32) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) - 1 > 4 * PyLong_SHIFT) { + return (npy_uint32) (((npy_uint32)-1)*(((((((((npy_uint32)digits[3]) << PyLong_SHIFT) | (npy_uint32)digits[2]) << PyLong_SHIFT) | (npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_uint32) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint32, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint32) - 1 > 4 * PyLong_SHIFT) { + return (npy_uint32) ((((((((((npy_uint32)digits[3]) << PyLong_SHIFT) | (npy_uint32)digits[2]) << PyLong_SHIFT) | (npy_uint32)digits[1]) << PyLong_SHIFT) | (npy_uint32)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_uint32) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint32, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint32) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint32, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_uint32 val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_uint32) -1; + } + } else { + npy_uint32 val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_uint32) -1; + val = __Pyx_PyInt_As_npy_uint32(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_uint32"); + return (npy_uint32) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_uint32"); + return (npy_uint32) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_int32 __Pyx_PyInt_As_npy_int32(PyObject *x) { + const npy_int32 neg_one = (npy_int32) -1, const_zero = (npy_int32) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_int32) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_int32, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_int32) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_int32) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_int32, digit, digits[0]) + case 2: + if (8 * sizeof(npy_int32) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) >= 2 * PyLong_SHIFT) { + return (npy_int32) (((((npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_int32) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) >= 3 * PyLong_SHIFT) { + return (npy_int32) (((((((npy_int32)digits[2]) << PyLong_SHIFT) | (npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_int32) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) >= 4 * PyLong_SHIFT) { + return (npy_int32) (((((((((npy_int32)digits[3]) << PyLong_SHIFT) | (npy_int32)digits[2]) << PyLong_SHIFT) | (npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_int32) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_int32) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int32, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int32) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int32, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_int32) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_int32, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_int32, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_int32) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) - 1 > 2 * PyLong_SHIFT) { + return (npy_int32) (((npy_int32)-1)*(((((npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_int32) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) - 1 > 2 * PyLong_SHIFT) { + return (npy_int32) ((((((npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_int32) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) - 1 > 3 * PyLong_SHIFT) { + return (npy_int32) (((npy_int32)-1)*(((((((npy_int32)digits[2]) << PyLong_SHIFT) | (npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_int32) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) - 1 > 3 * PyLong_SHIFT) { + return (npy_int32) ((((((((npy_int32)digits[2]) << PyLong_SHIFT) | (npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_int32) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) - 1 > 4 * PyLong_SHIFT) { + return (npy_int32) (((npy_int32)-1)*(((((((((npy_int32)digits[3]) << PyLong_SHIFT) | (npy_int32)digits[2]) << PyLong_SHIFT) | (npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_int32) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int32, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int32) - 1 > 4 * PyLong_SHIFT) { + return (npy_int32) ((((((((((npy_int32)digits[3]) << PyLong_SHIFT) | (npy_int32)digits[2]) << PyLong_SHIFT) | (npy_int32)digits[1]) << PyLong_SHIFT) | (npy_int32)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_int32) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int32, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int32) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int32, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_int32 val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_int32) -1; + } + } else { + npy_int32 val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_int32) -1; + val = __Pyx_PyInt_As_npy_int32(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_int32"); + return (npy_int32) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_int32"); + return (npy_int32) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_uint64 __Pyx_PyInt_As_npy_uint64(PyObject *x) { + const npy_uint64 neg_one = (npy_uint64) -1, const_zero = (npy_uint64) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_uint64) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_uint64, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_uint64) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_uint64) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_uint64, digit, digits[0]) + case 2: + if (8 * sizeof(npy_uint64) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) >= 2 * PyLong_SHIFT) { + return (npy_uint64) (((((npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_uint64) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) >= 3 * PyLong_SHIFT) { + return (npy_uint64) (((((((npy_uint64)digits[2]) << PyLong_SHIFT) | (npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_uint64) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) >= 4 * PyLong_SHIFT) { + return (npy_uint64) (((((((((npy_uint64)digits[3]) << PyLong_SHIFT) | (npy_uint64)digits[2]) << PyLong_SHIFT) | (npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_uint64) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_uint64) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint64, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint64) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint64, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_uint64) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_uint64, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_uint64, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_uint64) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) - 1 > 2 * PyLong_SHIFT) { + return (npy_uint64) (((npy_uint64)-1)*(((((npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_uint64) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) - 1 > 2 * PyLong_SHIFT) { + return (npy_uint64) ((((((npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_uint64) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) - 1 > 3 * PyLong_SHIFT) { + return (npy_uint64) (((npy_uint64)-1)*(((((((npy_uint64)digits[2]) << PyLong_SHIFT) | (npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_uint64) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) - 1 > 3 * PyLong_SHIFT) { + return (npy_uint64) ((((((((npy_uint64)digits[2]) << PyLong_SHIFT) | (npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_uint64) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) - 1 > 4 * PyLong_SHIFT) { + return (npy_uint64) (((npy_uint64)-1)*(((((((((npy_uint64)digits[3]) << PyLong_SHIFT) | (npy_uint64)digits[2]) << PyLong_SHIFT) | (npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_uint64) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_uint64, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_uint64) - 1 > 4 * PyLong_SHIFT) { + return (npy_uint64) ((((((((((npy_uint64)digits[3]) << PyLong_SHIFT) | (npy_uint64)digits[2]) << PyLong_SHIFT) | (npy_uint64)digits[1]) << PyLong_SHIFT) | (npy_uint64)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_uint64) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint64, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_uint64) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_uint64, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_uint64 val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_uint64) -1; + } + } else { + npy_uint64 val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_uint64) -1; + val = __Pyx_PyInt_As_npy_uint64(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_uint64"); + return (npy_uint64) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_uint64"); + return (npy_uint64) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE npy_int64 __Pyx_PyInt_As_npy_int64(PyObject *x) { + const npy_int64 neg_one = (npy_int64) -1, const_zero = (npy_int64) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(npy_int64) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(npy_int64, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (npy_int64) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_int64) 0; + case 1: __PYX_VERIFY_RETURN_INT(npy_int64, digit, digits[0]) + case 2: + if (8 * sizeof(npy_int64) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) >= 2 * PyLong_SHIFT) { + return (npy_int64) (((((npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(npy_int64) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) >= 3 * PyLong_SHIFT) { + return (npy_int64) (((((((npy_int64)digits[2]) << PyLong_SHIFT) | (npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(npy_int64) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) >= 4 * PyLong_SHIFT) { + return (npy_int64) (((((((((npy_int64)digits[3]) << PyLong_SHIFT) | (npy_int64)digits[2]) << PyLong_SHIFT) | (npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (npy_int64) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(npy_int64) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int64, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int64) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int64, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (npy_int64) 0; + case -1: __PYX_VERIFY_RETURN_INT(npy_int64, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(npy_int64, digit, +digits[0]) + case -2: + if (8 * sizeof(npy_int64) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) - 1 > 2 * PyLong_SHIFT) { + return (npy_int64) (((npy_int64)-1)*(((((npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(npy_int64) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) - 1 > 2 * PyLong_SHIFT) { + return (npy_int64) ((((((npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(npy_int64) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) - 1 > 3 * PyLong_SHIFT) { + return (npy_int64) (((npy_int64)-1)*(((((((npy_int64)digits[2]) << PyLong_SHIFT) | (npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(npy_int64) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) - 1 > 3 * PyLong_SHIFT) { + return (npy_int64) ((((((((npy_int64)digits[2]) << PyLong_SHIFT) | (npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(npy_int64) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) - 1 > 4 * PyLong_SHIFT) { + return (npy_int64) (((npy_int64)-1)*(((((((((npy_int64)digits[3]) << PyLong_SHIFT) | (npy_int64)digits[2]) << PyLong_SHIFT) | (npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(npy_int64) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(npy_int64, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(npy_int64) - 1 > 4 * PyLong_SHIFT) { + return (npy_int64) ((((((((((npy_int64)digits[3]) << PyLong_SHIFT) | (npy_int64)digits[2]) << PyLong_SHIFT) | (npy_int64)digits[1]) << PyLong_SHIFT) | (npy_int64)digits[0]))); + } + } + break; + } +#endif + if (sizeof(npy_int64) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int64, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(npy_int64) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(npy_int64, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + npy_int64 val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (npy_int64) -1; + } + } else { + npy_int64 val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (npy_int64) -1; + val = __Pyx_PyInt_As_npy_int64(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to npy_int64"); + return (npy_int64) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to npy_int64"); + return (npy_int64) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE unsigned long __Pyx_PyInt_As_unsigned_long(PyObject *x) { + const unsigned long neg_one = (unsigned long) -1, const_zero = (unsigned long) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(unsigned long) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(unsigned long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (unsigned long) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (unsigned long) 0; + case 1: __PYX_VERIFY_RETURN_INT(unsigned long, digit, digits[0]) + case 2: + if (8 * sizeof(unsigned long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) >= 2 * PyLong_SHIFT) { + return (unsigned long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) >= 3 * PyLong_SHIFT) { + return (unsigned long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) >= 4 * PyLong_SHIFT) { + return (unsigned long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (unsigned long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(unsigned long) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(unsigned long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(unsigned long) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(unsigned long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (unsigned long) 0; + case -1: __PYX_VERIFY_RETURN_INT(unsigned long, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(unsigned long, digit, +digits[0]) + case -2: + if (8 * sizeof(unsigned long) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) - 1 > 2 * PyLong_SHIFT) { + return (unsigned long) (((unsigned long)-1)*(((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(unsigned long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) - 1 > 2 * PyLong_SHIFT) { + return (unsigned long) ((((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(unsigned long) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) - 1 > 3 * PyLong_SHIFT) { + return (unsigned long) (((unsigned long)-1)*(((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) - 1 > 3 * PyLong_SHIFT) { + return (unsigned long) ((((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(unsigned long) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) - 1 > 4 * PyLong_SHIFT) { + return (unsigned long) (((unsigned long)-1)*(((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(unsigned long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(unsigned long) - 1 > 4 * PyLong_SHIFT) { + return (unsigned long) ((((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))); + } + } + break; + } +#endif + if (sizeof(unsigned long) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(unsigned long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(unsigned long) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(unsigned long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + unsigned long val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (unsigned long) -1; + } + } else { + unsigned long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (unsigned long) -1; + val = __Pyx_PyInt_As_unsigned_long(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to unsigned long"); + return (unsigned long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to unsigned long"); + return (unsigned long) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { + const int neg_one = (int) -1, const_zero = (int) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(int) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(int) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) + case -2: + if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } +#endif + if (sizeof(int) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + int val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (int) -1; + } + } else { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *x) { + const size_t neg_one = (size_t) -1, const_zero = (size_t) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(size_t) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(size_t, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (size_t) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (size_t) 0; + case 1: __PYX_VERIFY_RETURN_INT(size_t, digit, digits[0]) + case 2: + if (8 * sizeof(size_t) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 2 * PyLong_SHIFT) { + return (size_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(size_t) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 3 * PyLong_SHIFT) { + return (size_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(size_t) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 4 * PyLong_SHIFT) { + return (size_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (size_t) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(size_t) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(size_t) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (size_t) 0; + case -1: __PYX_VERIFY_RETURN_INT(size_t, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(size_t, digit, +digits[0]) + case -2: + if (8 * sizeof(size_t) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(size_t) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + return (size_t) ((((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(size_t) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + return (size_t) ((((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 4 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(size_t) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 4 * PyLong_SHIFT) { + return (size_t) ((((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + } +#endif + if (sizeof(size_t) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(size_t) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + size_t val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (size_t) -1; + } + } else { + size_t val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (size_t) -1; + val = __Pyx_PyInt_As_size_t(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to size_t"); + return (size_t) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to size_t"); + return (size_t) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { + const long neg_one = (long) -1, const_zero = (long) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(long) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(long) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) + case -2: + if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } +#endif + if (sizeof(long) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + long val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (long) -1; + } + } else { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ + #if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = a->tp_base; + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + int res = exc_type1 ? __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type1) : 0; + if (!res) { + res = __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } + return res; +} +#endif +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject* exc_type) { + if (likely(err == exc_type)) return 1; + if (likely(PyExceptionClass_Check(err))) { + return __Pyx_inner_PyErr_GivenExceptionMatches2(err, NULL, exc_type); + } + return PyErr_GivenExceptionMatches(err, exc_type); +} +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *exc_type1, PyObject *exc_type2) { + if (likely(err == exc_type1 || err == exc_type2)) return 1; + if (likely(PyExceptionClass_Check(err))) { + return __Pyx_inner_PyErr_GivenExceptionMatches2(err, exc_type1, exc_type2); + } + return (PyErr_GivenExceptionMatches(err, exc_type1) || PyErr_GivenExceptionMatches(err, exc_type2)); +} +#endif + +/* CheckBinaryVersion */ + static int __Pyx_check_binary_version(void) { + char ctversion[4], rtversion[4]; + PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION); + PyOS_snprintf(rtversion, 4, "%s", Py_GetVersion()); + if (ctversion[0] != rtversion[0] || ctversion[2] != rtversion[2]) { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compiletime version %s of module '%.100s' " + "does not match runtime version %s", + ctversion, __Pyx_MODULE_NAME, rtversion); + return PyErr_WarnEx(NULL, message, 1); + } + return 0; +} + +/* ModuleImport */ + #ifndef __PYX_HAVE_RT_ImportModule +#define __PYX_HAVE_RT_ImportModule +static PyObject *__Pyx_ImportModule(const char *name) { + PyObject *py_name = 0; + PyObject *py_module = 0; + py_name = __Pyx_PyIdentifier_FromString(name); + if (!py_name) + goto bad; + py_module = PyImport_Import(py_name); + Py_DECREF(py_name); + return py_module; +bad: + Py_XDECREF(py_name); + return 0; +} +#endif + +/* TypeImport */ + #ifndef __PYX_HAVE_RT_ImportType +#define __PYX_HAVE_RT_ImportType +static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name, + size_t size, int strict) +{ + PyObject *py_module = 0; + PyObject *result = 0; + PyObject *py_name = 0; + char warning[200]; + Py_ssize_t basicsize; +#ifdef Py_LIMITED_API + PyObject *py_basicsize; +#endif + py_module = __Pyx_ImportModule(module_name); + if (!py_module) + goto bad; + py_name = __Pyx_PyIdentifier_FromString(class_name); + if (!py_name) + goto bad; + result = PyObject_GetAttr(py_module, py_name); + Py_DECREF(py_name); + py_name = 0; + Py_DECREF(py_module); + py_module = 0; + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#ifndef Py_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if (!strict && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. Expected %zd, got %zd", + module_name, class_name, basicsize, size); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + else if ((size_t)basicsize != size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s has the wrong size, try recompiling. Expected %zd, got %zd", + module_name, class_name, basicsize, size); + goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(py_module); + Py_XDECREF(result); + return NULL; +} +#endif + +/* InitStrings */ + static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION < 3 + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + #else + if (t->is_unicode | t->is_str) { + if (t->intern) { + *t->p = PyUnicode_InternFromString(t->s); + } else if (t->encoding) { + *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); + } else { + *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); + } + } else { + *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); + } + #endif + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + ++t; + } + return 0; +} + +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + return __Pyx_PyUnicode_FromStringAndSize(c_str, (Py_ssize_t)strlen(c_str)); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type %.200s). " + "The ability to return an instance of a strict subclass of int " + "is deprecated, and may be removed in a future version of Python.", + Py_TYPE(result)->tp_name)) { + Py_DECREF(result); + return NULL; + } + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type %.200s)", + type_name, type_name, Py_TYPE(result)->tp_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(x); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)b)->ob_digit; + const Py_ssize_t size = Py_SIZE(b); + if (likely(__Pyx_sst_abs(size) <= 1)) { + ival = likely(size) ? digits[0] : 0; + if (size == -1) ival = -ival; + return ival; + } else { + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +#endif /* Py_PYTHON_H */ diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx new file mode 100644 index 0000000..501c1e5 --- /dev/null +++ b/numpy/random/mtrand/mtrand.pyx @@ -0,0 +1,4960 @@ +# mtrand.pyx -- A Pyrex wrapper of Jean-Sebastien Roy's RandomKit +# +# Copyright 2005 Robert Kern (robert.kern@gmail.com) +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +include "Python.pxi" +include "randint_helpers.pxi" +include "numpy.pxd" +include "cpython/pycapsule.pxd" + +from libc cimport string + +cdef extern from "math.h": + double exp(double x) + double log(double x) + double floor(double x) + double sin(double x) + double cos(double x) + +cdef extern from "numpy/npy_math.h": + int npy_isfinite(double x) + +cdef extern from "mtrand_py_helper.h": + object empty_py_bytes(npy_intp length, void **bytes) + +cdef extern from "randomkit.h": + + ctypedef struct rk_state: + unsigned long key[624] + int pos + int has_gauss + double gauss + + ctypedef enum rk_error: + RK_NOERR = 0 + RK_ENODEV = 1 + RK_ERR_MAX = 2 + + char *rk_strerror[2] + + # 0xFFFFFFFFUL + unsigned long RK_MAX + + void rk_seed(unsigned long seed, rk_state *state) + rk_error rk_randomseed(rk_state *state) + unsigned long rk_random(rk_state *state) + long rk_long(rk_state *state) nogil + unsigned long rk_ulong(rk_state *state) nogil + unsigned long rk_interval(unsigned long max, rk_state *state) nogil + double rk_double(rk_state *state) nogil + void rk_fill(void *buffer, size_t size, rk_state *state) nogil + rk_error rk_devfill(void *buffer, size_t size, int strong) + rk_error rk_altfill(void *buffer, size_t size, int strong, + rk_state *state) nogil + double rk_gauss(rk_state *state) nogil + void rk_random_uint64(npy_uint64 off, npy_uint64 rng, npy_intp cnt, + npy_uint64 *out, rk_state *state) nogil + void rk_random_uint32(npy_uint32 off, npy_uint32 rng, npy_intp cnt, + npy_uint32 *out, rk_state *state) nogil + void rk_random_uint16(npy_uint16 off, npy_uint16 rng, npy_intp cnt, + npy_uint16 *out, rk_state *state) nogil + void rk_random_uint8(npy_uint8 off, npy_uint8 rng, npy_intp cnt, + npy_uint8 *out, rk_state *state) nogil + void rk_random_bool(npy_bool off, npy_bool rng, npy_intp cnt, + npy_bool *out, rk_state *state) nogil + + +cdef extern from "distributions.h": + # do not need the GIL, but they do need a lock on the state !! */ + + double rk_normal(rk_state *state, double loc, double scale) nogil + double rk_standard_exponential(rk_state *state) nogil + double rk_exponential(rk_state *state, double scale) nogil + double rk_uniform(rk_state *state, double loc, double scale) nogil + double rk_standard_gamma(rk_state *state, double shape) nogil + double rk_gamma(rk_state *state, double shape, double scale) nogil + double rk_beta(rk_state *state, double a, double b) nogil + double rk_chisquare(rk_state *state, double df) nogil + double rk_noncentral_chisquare(rk_state *state, double df, double nonc) nogil + double rk_f(rk_state *state, double dfnum, double dfden) nogil + double rk_noncentral_f(rk_state *state, double dfnum, double dfden, double nonc) nogil + double rk_standard_cauchy(rk_state *state) nogil + double rk_standard_t(rk_state *state, double df) nogil + double rk_vonmises(rk_state *state, double mu, double kappa) nogil + double rk_pareto(rk_state *state, double a) nogil + double rk_weibull(rk_state *state, double a) nogil + double rk_power(rk_state *state, double a) nogil + double rk_laplace(rk_state *state, double loc, double scale) nogil + double rk_gumbel(rk_state *state, double loc, double scale) nogil + double rk_logistic(rk_state *state, double loc, double scale) nogil + double rk_lognormal(rk_state *state, double mode, double sigma) nogil + double rk_rayleigh(rk_state *state, double mode) nogil + double rk_wald(rk_state *state, double mean, double scale) nogil + double rk_triangular(rk_state *state, double left, double mode, double right) nogil + + long rk_binomial(rk_state *state, long n, double p) nogil + long rk_binomial_btpe(rk_state *state, long n, double p) nogil + long rk_binomial_inversion(rk_state *state, long n, double p) nogil + long rk_negative_binomial(rk_state *state, double n, double p) nogil + long rk_poisson(rk_state *state, double lam) nogil + long rk_poisson_mult(rk_state *state, double lam) nogil + long rk_poisson_ptrs(rk_state *state, double lam) nogil + long rk_zipf(rk_state *state, double a) nogil + long rk_geometric(rk_state *state, double p) nogil + long rk_hypergeometric(rk_state *state, long good, long bad, long sample) nogil + long rk_logseries(rk_state *state, double p) nogil + +ctypedef double (* rk_cont0)(rk_state *state) nogil +ctypedef double (* rk_cont1)(rk_state *state, double a) nogil +ctypedef double (* rk_cont2)(rk_state *state, double a, double b) nogil +ctypedef double (* rk_cont3)(rk_state *state, double a, double b, double c) nogil + +ctypedef long (* rk_disc0)(rk_state *state) nogil +ctypedef long (* rk_discnp)(rk_state *state, long n, double p) nogil +ctypedef long (* rk_discdd)(rk_state *state, double n, double p) nogil +ctypedef long (* rk_discnmN)(rk_state *state, long n, long m, long N) nogil +ctypedef long (* rk_discd)(rk_state *state, double a) nogil + + +cdef extern from "initarray.h": + void init_by_array(rk_state *self, unsigned long *init_key, + npy_intp key_length) + +# Initialize numpy +import_array() + +cimport cython +import numpy as np +import operator +import warnings + +try: + from threading import Lock +except ImportError: + from dummy_threading import Lock + +cdef object cont0_array(rk_state *state, rk_cont0 func, object size, + object lock): + cdef double *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state) + return rv + else: + array = np.empty(size, np.float64) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state) + return array + + +cdef object cont1_array_sc(rk_state *state, rk_cont1 func, object size, double a, + object lock): + cdef double *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state, a) + return rv + else: + array = np.empty(size, np.float64) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, a) + return array + +cdef object cont1_array(rk_state *state, rk_cont1 func, object size, + ndarray oa, object lock): + cdef double *array_data + cdef double *oa_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + cdef flatiter itera + cdef broadcast multi + + if size is None: + array = PyArray_SimpleNew(PyArray_NDIM(oa), + PyArray_DIMS(oa) , NPY_DOUBLE) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + itera = PyArray_IterNew(oa) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + PyArray_ITER_NEXT(itera) + else: + array = np.empty(size, np.float64) + array_data = PyArray_DATA(array) + multi = PyArray_MultiIterNew(2, array, + oa) + if (multi.size != PyArray_SIZE(array)): + raise ValueError("size is not compatible with inputs") + with lock, nogil: + for i from 0 <= i < multi.size: + oa_data = PyArray_MultiIter_DATA(multi, 1) + array_data[i] = func(state, oa_data[0]) + PyArray_MultiIter_NEXTi(multi, 1) + return array + +cdef object cont2_array_sc(rk_state *state, rk_cont2 func, object size, double a, + double b, object lock): + cdef double *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state, a, b) + return rv + else: + array = np.empty(size, np.float64) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, a, b) + return array + + +cdef object cont2_array(rk_state *state, rk_cont2 func, object size, + ndarray oa, ndarray ob, object lock): + cdef double *array_data + cdef double *oa_data + cdef double *ob_data + cdef ndarray array "arrayObject" + cdef npy_intp i + cdef broadcast multi + + if size is None: + multi = np.broadcast(oa, ob) + array = np.empty(multi.shape, dtype=np.float64) + else: + array = np.empty(size, dtype=np.float64) + multi = np.broadcast(oa, ob, array) + if multi.shape != array.shape: + raise ValueError("size is not compatible with inputs") + + array_data = PyArray_DATA(array) + + with lock, nogil: + for i in range(multi.size): + oa_data = PyArray_MultiIter_DATA(multi, 0) + ob_data = PyArray_MultiIter_DATA(multi, 1) + array_data[i] = func(state, oa_data[0], ob_data[0]) + PyArray_MultiIter_NEXT(multi) + + return array + +cdef object cont3_array_sc(rk_state *state, rk_cont3 func, object size, double a, + double b, double c, object lock): + + cdef double *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state, a, b, c) + return rv + else: + array = np.empty(size, np.float64) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, a, b, c) + return array + +cdef object cont3_array(rk_state *state, rk_cont3 func, object size, + ndarray oa, ndarray ob, ndarray oc, object lock): + + cdef double *array_data + cdef double *oa_data + cdef double *ob_data + cdef double *oc_data + cdef ndarray array "arrayObject" + cdef npy_intp i + cdef broadcast multi + + if size is None: + multi = np.broadcast(oa, ob, oc) + array = np.empty(multi.shape, dtype=np.float64) + else: + array = np.empty(size, dtype=np.float64) + multi = np.broadcast(oa, ob, oc, array) + if multi.shape != array.shape: + raise ValueError("size is not compatible with inputs") + + array_data = PyArray_DATA(array) + + with lock, nogil: + for i in range(multi.size): + oa_data = PyArray_MultiIter_DATA(multi, 0) + ob_data = PyArray_MultiIter_DATA(multi, 1) + oc_data = PyArray_MultiIter_DATA(multi, 2) + array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0]) + PyArray_MultiIter_NEXT(multi) + + return array + +cdef object disc0_array(rk_state *state, rk_disc0 func, object size, object lock): + cdef long *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state) + return rv + else: + array = np.empty(size, int) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state) + return array + +cdef object discnp_array_sc(rk_state *state, rk_discnp func, object size, + long n, double p, object lock): + cdef long *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state, n, p) + return rv + else: + array = np.empty(size, int) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, n, p) + return array + +cdef object discnp_array(rk_state *state, rk_discnp func, object size, + ndarray on, ndarray op, object lock): + cdef long *array_data + cdef ndarray array "arrayObject" + cdef npy_intp i + cdef double *op_data + cdef long *on_data + cdef broadcast multi + + if size is None: + multi = np.broadcast(on, op) + array = np.empty(multi.shape, dtype=int) + else: + array = np.empty(size, dtype=int) + multi = np.broadcast(on, op, array) + if multi.shape != array.shape: + raise ValueError("size is not compatible with inputs") + + array_data = PyArray_DATA(array) + + with lock, nogil: + for i in range(multi.size): + on_data = PyArray_MultiIter_DATA(multi, 0) + op_data = PyArray_MultiIter_DATA(multi, 1) + array_data[i] = func(state, on_data[0], op_data[0]) + PyArray_MultiIter_NEXT(multi) + + return array + +cdef object discdd_array_sc(rk_state *state, rk_discdd func, object size, + double n, double p, object lock): + cdef long *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state, n, p) + return rv + else: + array = np.empty(size, int) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, n, p) + return array + +cdef object discdd_array(rk_state *state, rk_discdd func, object size, + ndarray on, ndarray op, object lock): + cdef long *array_data + cdef ndarray array "arrayObject" + cdef npy_intp i + cdef double *op_data + cdef double *on_data + cdef broadcast multi + + if size is None: + multi = np.broadcast(on, op) + array = np.empty(multi.shape, dtype=int) + else: + array = np.empty(size, dtype=int) + multi = np.broadcast(on, op, array) + if multi.shape != array.shape: + raise ValueError("size is not compatible with inputs") + + array_data = PyArray_DATA(array) + + with lock, nogil: + for i in range(multi.size): + on_data = PyArray_MultiIter_DATA(multi, 0) + op_data = PyArray_MultiIter_DATA(multi, 1) + array_data[i] = func(state, on_data[0], op_data[0]) + PyArray_MultiIter_NEXT(multi) + + return array + +cdef object discnmN_array_sc(rk_state *state, rk_discnmN func, object size, + long n, long m, long N, object lock): + cdef long *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state, n, m, N) + return rv + else: + array = np.empty(size, int) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, n, m, N) + return array + +cdef object discnmN_array(rk_state *state, rk_discnmN func, object size, + ndarray on, ndarray om, ndarray oN, object lock): + cdef long *array_data + cdef long *on_data + cdef long *om_data + cdef long *oN_data + cdef ndarray array "arrayObject" + cdef npy_intp i + cdef broadcast multi + + if size is None: + multi = np.broadcast(on, om, oN) + array = np.empty(multi.shape, dtype=int) + else: + array = np.empty(size, dtype=int) + multi = np.broadcast(on, om, oN, array) + if multi.shape != array.shape: + raise ValueError("size is not compatible with inputs") + + array_data = PyArray_DATA(array) + + with lock, nogil: + for i in range(multi.size): + on_data = PyArray_MultiIter_DATA(multi, 0) + om_data = PyArray_MultiIter_DATA(multi, 1) + oN_data = PyArray_MultiIter_DATA(multi, 2) + array_data[i] = func(state, on_data[0], om_data[0], oN_data[0]) + PyArray_MultiIter_NEXT(multi) + + return array + +cdef object discd_array_sc(rk_state *state, rk_discd func, object size, + double a, object lock): + cdef long *array_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + + if size is None: + with lock, nogil: + rv = func(state, a) + return rv + else: + array = np.empty(size, int) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, a) + return array + +cdef object discd_array(rk_state *state, rk_discd func, object size, ndarray oa, + object lock): + cdef long *array_data + cdef double *oa_data + cdef ndarray array "arrayObject" + cdef npy_intp length + cdef npy_intp i + cdef broadcast multi + cdef flatiter itera + + if size is None: + array = PyArray_SimpleNew(PyArray_NDIM(oa), + PyArray_DIMS(oa), NPY_LONG) + length = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + itera = PyArray_IterNew(oa) + with lock, nogil: + for i from 0 <= i < length: + array_data[i] = func(state, (PyArray_ITER_DATA(itera))[0]) + PyArray_ITER_NEXT(itera) + else: + array = np.empty(size, int) + array_data = PyArray_DATA(array) + multi = PyArray_MultiIterNew(2, array, oa) + if (multi.size != PyArray_SIZE(array)): + raise ValueError("size is not compatible with inputs") + with lock, nogil: + for i from 0 <= i < multi.size: + oa_data = PyArray_MultiIter_DATA(multi, 1) + array_data[i] = func(state, oa_data[0]) + PyArray_MultiIter_NEXTi(multi, 1) + return array + +cdef double kahan_sum(double *darr, npy_intp n): + cdef double c, y, t, sum + cdef npy_intp i + sum = darr[0] + c = 0.0 + for i from 1 <= i < n: + y = darr[i] - c + t = sum + y + c = (t-sum) - y + sum = t + return sum + +def _shape_from_size(size, d): + if size is None: + shape = (d,) + else: + try: + shape = (operator.index(size), d) + except TypeError: + shape = tuple(size) + (d,) + return shape + +# Look up table for randint functions keyed by type name. The stored data +# is a tuple (lbnd, ubnd, func), where lbnd is the smallest value for the +# type, ubnd is one greater than the largest value, and func is the +# function to call. +_randint_type = { + 'bool': (0, 2, _rand_bool), + 'int8': (-2**7, 2**7, _rand_int8), + 'int16': (-2**15, 2**15, _rand_int16), + 'int32': (-2**31, 2**31, _rand_int32), + 'int64': (-2**63, 2**63, _rand_int64), + 'uint8': (0, 2**8, _rand_uint8), + 'uint16': (0, 2**16, _rand_uint16), + 'uint32': (0, 2**32, _rand_uint32), + 'uint64': (0, 2**64, _rand_uint64) + } + + +cdef class RandomState: + """ + RandomState(seed=None) + + Container for the Mersenne Twister pseudo-random number generator. + + `RandomState` exposes a number of methods for generating random numbers + drawn from a variety of probability distributions. In addition to the + distribution-specific arguments, each method takes a keyword argument + `size` that defaults to ``None``. If `size` is ``None``, then a single + value is generated and returned. If `size` is an integer, then a 1-D + array filled with generated values is returned. If `size` is a tuple, + then an array with that shape is filled and returned. + + *Compatibility Guarantee* + A fixed seed and a fixed series of calls to 'RandomState' methods using + the same parameters will always produce the same results up to roundoff + error except when the values were incorrect. Incorrect values will be + fixed and the NumPy version in which the fix was made will be noted in + the relevant docstring. Extension of existing parameter ranges and the + addition of new parameters is allowed as long the previous behavior + remains unchanged. + + Parameters + ---------- + seed : {None, int, array_like}, optional + Random seed used to initialize the pseudo-random number generator. Can + be any integer between 0 and 2**32 - 1 inclusive, an array (or other + sequence) of such integers, or ``None`` (the default). If `seed` is + ``None``, then `RandomState` will try to read data from + ``/dev/urandom`` (or the Windows analogue) if available or seed from + the clock otherwise. + + Notes + ----- + The Python stdlib module "random" also contains a Mersenne Twister + pseudo-random number generator with a number of methods that are similar + to the ones available in `RandomState`. `RandomState`, besides being + NumPy-aware, has the advantage that it provides a much larger number + of probability distributions to choose from. + + """ + cdef rk_state *internal_state + cdef object lock + cdef object state_address + poisson_lam_max = np.iinfo('l').max - np.sqrt(np.iinfo('l').max)*10 + + def __init__(self, seed=None): + self.internal_state = PyMem_Malloc(sizeof(rk_state)) + self.state_address = PyCapsule_New(self.internal_state, NULL, NULL) + self.lock = Lock() + self.seed(seed) + + def __dealloc__(self): + if self.internal_state != NULL: + PyMem_Free(self.internal_state) + self.internal_state = NULL + + def seed(self, seed=None): + """ + seed(seed=None) + + Seed the generator. + + This method is called when `RandomState` is initialized. It can be + called again to re-seed the generator. For details, see `RandomState`. + + Parameters + ---------- + seed : int or 1-d array_like, optional + Seed for `RandomState`. + Must be convertible to 32 bit unsigned integers. + + See Also + -------- + RandomState + + """ + cdef rk_error errcode + cdef ndarray obj "arrayObject_obj" + try: + if seed is None: + with self.lock: + errcode = rk_randomseed(self.internal_state) + else: + idx = operator.index(seed) + if (idx >= 2**32) or (idx < 0): + raise ValueError("Seed must be between 0 and 2**32 - 1") + with self.lock: + rk_seed(idx, self.internal_state) + except TypeError: + obj = np.asarray(seed) + if obj.size == 0: + raise ValueError("Seed must be non-empty") + obj = obj.astype(np.int64, casting='safe') + if obj.ndim != 1: + raise ValueError("Seed array must be 1-d") + if ((obj >= 2**32) | (obj < 0)).any(): + raise ValueError("Seed values must be between 0 and 2**32 - 1") + obj = obj.astype('L', casting='unsafe') + with self.lock: + init_by_array(self.internal_state, PyArray_DATA(obj), + PyArray_DIM(obj, 0)) + + def get_state(self): + """ + get_state() + + Return a tuple representing the internal state of the generator. + + For more details, see `set_state`. + + Returns + ------- + out : tuple(str, ndarray of 624 uints, int, int, float) + The returned tuple has the following items: + + 1. the string 'MT19937'. + 2. a 1-D array of 624 unsigned integer keys. + 3. an integer ``pos``. + 4. an integer ``has_gauss``. + 5. a float ``cached_gaussian``. + + See Also + -------- + set_state + + Notes + ----- + `set_state` and `get_state` are not needed to work with any of the + random distributions in NumPy. If the internal state is manually altered, + the user should know exactly what he/she is doing. + + """ + cdef ndarray state "arrayObject_state" + state = np.empty(624, np.uint) + with self.lock: + memcpy(PyArray_DATA(state), (self.internal_state.key), 624*sizeof(long)) + has_gauss = self.internal_state.has_gauss + gauss = self.internal_state.gauss + pos = self.internal_state.pos + state = np.asarray(state, np.uint32) + return ('MT19937', state, pos, has_gauss, gauss) + + def set_state(self, state): + """ + set_state(state) + + Set the internal state of the generator from a tuple. + + For use if one has reason to manually (re-)set the internal state of the + "Mersenne Twister"[1]_ pseudo-random number generating algorithm. + + Parameters + ---------- + state : tuple(str, ndarray of 624 uints, int, int, float) + The `state` tuple has the following items: + + 1. the string 'MT19937', specifying the Mersenne Twister algorithm. + 2. a 1-D array of 624 unsigned integers ``keys``. + 3. an integer ``pos``. + 4. an integer ``has_gauss``. + 5. a float ``cached_gaussian``. + + Returns + ------- + out : None + Returns 'None' on success. + + See Also + -------- + get_state + + Notes + ----- + `set_state` and `get_state` are not needed to work with any of the + random distributions in NumPy. If the internal state is manually altered, + the user should know exactly what he/she is doing. + + For backwards compatibility, the form (str, array of 624 uints, int) is + also accepted although it is missing some information about the cached + Gaussian value: ``state = ('MT19937', keys, pos)``. + + References + ---------- + .. [1] M. Matsumoto and T. Nishimura, "Mersenne Twister: A + 623-dimensionally equidistributed uniform pseudorandom number + generator," *ACM Trans. on Modeling and Computer Simulation*, + Vol. 8, No. 1, pp. 3-30, Jan. 1998. + + """ + cdef ndarray obj "arrayObject_obj" + cdef int pos + algorithm_name = state[0] + if algorithm_name != 'MT19937': + raise ValueError("algorithm must be 'MT19937'") + key, pos = state[1:3] + if len(state) == 3: + has_gauss = 0 + cached_gaussian = 0.0 + else: + has_gauss, cached_gaussian = state[3:5] + try: + obj = PyArray_ContiguousFromObject(key, NPY_ULONG, 1, 1) + except TypeError: + # compatibility -- could be an older pickle + obj = PyArray_ContiguousFromObject(key, NPY_LONG, 1, 1) + if PyArray_DIM(obj, 0) != 624: + raise ValueError("state must be 624 longs") + with self.lock: + memcpy((self.internal_state.key), PyArray_DATA(obj), 624*sizeof(long)) + self.internal_state.pos = pos + self.internal_state.has_gauss = has_gauss + self.internal_state.gauss = cached_gaussian + + # Pickling support: + def __getstate__(self): + return self.get_state() + + def __setstate__(self, state): + self.set_state(state) + + def __reduce__(self): + return (np.random.__RandomState_ctor, (), self.get_state()) + + # Basic distributions: + def random_sample(self, size=None): + """ + random_sample(size=None) + + Return random floats in the half-open interval [0.0, 1.0). + + Results are from the "continuous uniform" distribution over the + stated interval. To sample :math:`Unif[a, b), b > a` multiply + the output of `random_sample` by `(b-a)` and add `a`:: + + (b - a) * random_sample() + a + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray of floats + Array of random floats of shape `size` (unless ``size=None``, in which + case a single float is returned). + + Examples + -------- + >>> np.random.random_sample() + 0.47108547995356098 + >>> type(np.random.random_sample()) + + >>> np.random.random_sample((5,)) + array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) + + Three-by-two array of random numbers from [-5, 0): + + >>> 5 * np.random.random_sample((3, 2)) - 5 + array([[-3.99149989, -0.52338984], + [-2.99091858, -0.79479508], + [-1.23204345, -1.75224494]]) + + """ + return cont0_array(self.internal_state, rk_double, size, self.lock) + + def tomaxint(self, size=None): + """ + tomaxint(size=None) + + Random integers between 0 and ``sys.maxint``, inclusive. + + Return a sample of uniformly distributed random integers in the interval + [0, ``sys.maxint``]. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : ndarray + Drawn samples, with shape `size`. + + See Also + -------- + randint : Uniform sampling over a given half-open interval of integers. + random_integers : Uniform sampling over a given closed interval of + integers. + + Examples + -------- + >>> RS = np.random.mtrand.RandomState() # need a RandomState object + >>> RS.tomaxint((2,2,2)) + array([[[1170048599, 1600360186], + [ 739731006, 1947757578]], + [[1871712945, 752307660], + [1601631370, 1479324245]]]) + >>> import sys + >>> sys.maxint + 2147483647 + >>> RS.tomaxint((2,2,2)) < sys.maxint + array([[[ True, True], + [ True, True]], + [[ True, True], + [ True, True]]]) + + """ + return disc0_array(self.internal_state, rk_long, size, self.lock) + + def randint(self, low, high=None, size=None, dtype=int): + """ + randint(low, high=None, size=None, dtype='l') + + Return random integers from `low` (inclusive) to `high` (exclusive). + + Return random integers from the "discrete uniform" distribution of + the specified dtype in the "half-open" interval [`low`, `high`). If + `high` is None (the default), then results are from [0, `low`). + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is one above the + *highest* such integer). + high : int, optional + If provided, one above the largest (signed) integer to be drawn + from the distribution (see above for behavior if ``high=None``). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + dtype : dtype, optional + Desired dtype of the result. All dtypes are determined by their + name, i.e., 'int64', 'int', etc, so byteorder is not available + and a specific precision may have different C types depending + on the platform. The default value is 'np.int'. + + .. versionadded:: 1.11.0 + + Returns + ------- + out : int or ndarray of ints + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + See Also + -------- + random.random_integers : similar to `randint`, only for the closed + interval [`low`, `high`], and 1 is the lowest value if `high` is + omitted. In particular, this other one is the one to use to generate + uniformly distributed discrete non-integers. + + Examples + -------- + >>> np.random.randint(2, size=10) + array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) + >>> np.random.randint(1, size=10) + array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + + Generate a 2 x 4 array of ints between 0 and 4, inclusive: + + >>> np.random.randint(5, size=(2, 4)) + array([[4, 0, 2, 1], + [3, 2, 2, 0]]) + + """ + if high is None: + high = low + low = 0 + + # '_randint_type' is defined in + # 'generate_randint_helpers.py' + key = np.dtype(dtype).name + if key not in _randint_type: + raise TypeError('Unsupported dtype "%s" for randint' % key) + + lowbnd, highbnd, randfunc = _randint_type[key] + + # TODO: Do not cast these inputs to Python int + # + # This is a workaround until gh-8851 is resolved (bug in NumPy + # integer comparison and subtraction involving uint64 and non- + # uint64). Afterwards, remove these two lines. + ilow = int(low) + ihigh = int(high) + + if ilow < lowbnd: + raise ValueError("low is out of bounds for %s" % (key,)) + if ihigh > highbnd: + raise ValueError("high is out of bounds for %s" % (key,)) + if ilow >= ihigh: + raise ValueError("low >= high") + + with self.lock: + ret = randfunc(ilow, ihigh - 1, size, self.state_address) + + if size is None: + if dtype in (np.bool, np.int, np.long): + return dtype(ret) + + return ret + + def bytes(self, npy_intp length): + """ + bytes(length) + + Return random bytes. + + Parameters + ---------- + length : int + Number of random bytes. + + Returns + ------- + out : str + String of length `length`. + + Examples + -------- + >>> np.random.bytes(10) + ' eh\\x85\\x022SZ\\xbf\\xa4' #random + + """ + cdef void *bytes + bytestring = empty_py_bytes(length, &bytes) + with self.lock, nogil: + rk_fill(bytes, length, self.internal_state) + return bytestring + + + def choice(self, a, size=None, replace=True, p=None): + """ + choice(a, size=None, replace=True, p=None) + + Generates a random sample from a given 1-D array + + .. versionadded:: 1.7.0 + + Parameters + ----------- + a : 1-D array-like or int + If an ndarray, a random sample is generated from its elements. + If an int, the random sample is generated as if a were np.arange(a) + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + replace : boolean, optional + Whether the sample is with or without replacement + p : 1-D array-like, optional + The probabilities associated with each entry in a. + If not given the sample assumes a uniform distribution over all + entries in a. + + Returns + -------- + samples : single item or ndarray + The generated random samples + + Raises + ------- + ValueError + If a is an int and less than zero, if a or p are not 1-dimensional, + if a is an array-like of size 0, if p is not a vector of + probabilities, if a and p have different lengths, or if + replace=False and the sample size is greater than the population + size + + See Also + --------- + randint, shuffle, permutation + + Examples + --------- + Generate a uniform random sample from np.arange(5) of size 3: + + >>> np.random.choice(5, 3) + array([0, 3, 4]) + >>> #This is equivalent to np.random.randint(0,5,3) + + Generate a non-uniform random sample from np.arange(5) of size 3: + + >>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) + array([3, 3, 0]) + + Generate a uniform random sample from np.arange(5) of size 3 without + replacement: + + >>> np.random.choice(5, 3, replace=False) + array([3,1,0]) + >>> #This is equivalent to np.random.permutation(np.arange(5))[:3] + + Generate a non-uniform random sample from np.arange(5) of size + 3 without replacement: + + >>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) + array([2, 3, 0]) + + Any of the above can be repeated with an arbitrary array-like + instead of just integers. For instance: + + >>> aa_milne_arr = ['pooh', 'rabbit', 'piglet', 'Christopher'] + >>> np.random.choice(aa_milne_arr, 5, p=[0.5, 0.1, 0.1, 0.3]) + array(['pooh', 'pooh', 'pooh', 'Christopher', 'piglet'], + dtype='|S11') + + """ + + # Format and Verify input + a = np.array(a, copy=False) + if a.ndim == 0: + try: + # __index__ must return an integer by python rules. + pop_size = operator.index(a.item()) + except TypeError: + raise ValueError("a must be 1-dimensional or an integer") + if pop_size <= 0: + raise ValueError("a must be greater than 0") + elif a.ndim != 1: + raise ValueError("a must be 1-dimensional") + else: + pop_size = a.shape[0] + if pop_size is 0: + raise ValueError("a must be non-empty") + + if p is not None: + d = len(p) + + atol = np.sqrt(np.finfo(np.float64).eps) + if isinstance(p, np.ndarray): + if np.issubdtype(p.dtype, np.floating): + atol = max(atol, np.sqrt(np.finfo(p.dtype).eps)) + + p = PyArray_ContiguousFromObject(p, NPY_DOUBLE, 1, 1) + pix = PyArray_DATA(p) + + if p.ndim != 1: + raise ValueError("p must be 1-dimensional") + if p.size != pop_size: + raise ValueError("a and p must have same size") + if np.logical_or.reduce(p < 0): + raise ValueError("probabilities are not non-negative") + if abs(kahan_sum(pix, d) - 1.) > atol: + raise ValueError("probabilities do not sum to 1") + + shape = size + if shape is not None: + size = np.prod(shape, dtype=np.intp) + else: + size = 1 + + # Actual sampling + if replace: + if p is not None: + cdf = p.cumsum() + cdf /= cdf[-1] + uniform_samples = self.random_sample(shape) + idx = cdf.searchsorted(uniform_samples, side='right') + idx = np.array(idx, copy=False) # searchsorted returns a scalar + else: + idx = self.randint(0, pop_size, size=shape) + else: + if size > pop_size: + raise ValueError("Cannot take a larger sample than " + "population when 'replace=False'") + + if p is not None: + if np.count_nonzero(p > 0) < size: + raise ValueError("Fewer non-zero entries in p than size") + n_uniq = 0 + p = p.copy() + found = np.zeros(shape, dtype=np.int) + flat_found = found.ravel() + while n_uniq < size: + x = self.rand(size - n_uniq) + if n_uniq > 0: + p[flat_found[0:n_uniq]] = 0 + cdf = np.cumsum(p) + cdf /= cdf[-1] + new = cdf.searchsorted(x, side='right') + _, unique_indices = np.unique(new, return_index=True) + unique_indices.sort() + new = new.take(unique_indices) + flat_found[n_uniq:n_uniq + new.size] = new + n_uniq += new.size + idx = found + else: + idx = self.permutation(pop_size)[:size] + if shape is not None: + idx.shape = shape + + if shape is None and isinstance(idx, np.ndarray): + # In most cases a scalar will have been made an array + idx = idx.item(0) + + #Use samples as indices for a if a is array-like + if a.ndim == 0: + return idx + + if shape is not None and idx.ndim == 0: + # If size == () then the user requested a 0-d array as opposed to + # a scalar object when size is None. However a[idx] is always a + # scalar and not an array. So this makes sure the result is an + # array, taking into account that np.array(item) may not work + # for object arrays. + res = np.empty((), dtype=a.dtype) + res[()] = a[idx] + return res + + return a[idx] + + + def uniform(self, low=0.0, high=1.0, size=None): + """ + uniform(low=0.0, high=1.0, size=None) + + Draw samples from a uniform distribution. + + Samples are uniformly distributed over the half-open interval + ``[low, high)`` (includes low, but excludes high). In other words, + any value within the given interval is equally likely to be drawn + by `uniform`. + + Parameters + ---------- + low : float or array_like of floats, optional + Lower boundary of the output interval. All values generated will be + greater than or equal to low. The default value is 0. + high : float or array_like of floats + Upper boundary of the output interval. All values generated will be + less than high. The default value is 1.0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``low`` and ``high`` are both scalars. + Otherwise, ``np.broadcast(low, high).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized uniform distribution. + + See Also + -------- + randint : Discrete uniform distribution, yielding integers. + random_integers : Discrete uniform distribution over the closed + interval ``[low, high]``. + random_sample : Floats uniformly distributed over ``[0, 1)``. + random : Alias for `random_sample`. + rand : Convenience function that accepts dimensions as input, e.g., + ``rand(2,2)`` would generate a 2-by-2 array of floats, + uniformly distributed over ``[0, 1)``. + + Notes + ----- + The probability density function of the uniform distribution is + + .. math:: p(x) = \\frac{1}{b - a} + + anywhere within the interval ``[a, b)``, and zero elsewhere. + + When ``high`` == ``low``, values of ``low`` will be returned. + If ``high`` < ``low``, the results are officially undefined + and may eventually raise an error, i.e. do not rely on this + function to behave when passed arguments satisfying that + inequality condition. + + Examples + -------- + Draw samples from the distribution: + + >>> s = np.random.uniform(-1,0,1000) + + All values are within the given interval: + + >>> np.all(s >= -1) + True + >>> np.all(s < 0) + True + + Display the histogram of the samples, along with the + probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 15, normed=True) + >>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r') + >>> plt.show() + + """ + cdef ndarray olow, ohigh, odiff + cdef double flow, fhigh, fscale + cdef object temp + + olow = PyArray_FROM_OTF(low, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + ohigh = PyArray_FROM_OTF(high, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if olow.shape == ohigh.shape == (): + flow = PyFloat_AsDouble(low) + fhigh = PyFloat_AsDouble(high) + fscale = fhigh - flow + + if not npy_isfinite(fscale): + raise OverflowError('Range exceeds valid bounds') + + return cont2_array_sc(self.internal_state, rk_uniform, size, flow, + fscale, self.lock) + + temp = np.subtract(ohigh, olow) + Py_INCREF(temp) # needed to get around Pyrex's automatic reference-counting + # rules because EnsureArray steals a reference + odiff = PyArray_EnsureArray(temp) + + if not np.all(np.isfinite(odiff)): + raise OverflowError('Range exceeds valid bounds') + + return cont2_array(self.internal_state, rk_uniform, size, olow, odiff, + self.lock) + + def rand(self, *args): + """ + rand(d0, d1, ..., dn) + + Random values in a given shape. + + Create an array of the given shape and populate it with + random samples from a uniform distribution + over ``[0, 1)``. + + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should all be positive. + If no argument is given a single Python float is returned. + + Returns + ------- + out : ndarray, shape ``(d0, d1, ..., dn)`` + Random values. + + See Also + -------- + random + + Notes + ----- + This is a convenience function. If you want an interface that + takes a shape-tuple as the first argument, refer to + np.random.random_sample . + + Examples + -------- + >>> np.random.rand(3,2) + array([[ 0.14022471, 0.96360618], #random + [ 0.37601032, 0.25528411], #random + [ 0.49313049, 0.94909878]]) #random + + """ + if len(args) == 0: + return self.random_sample() + else: + return self.random_sample(size=args) + + def randn(self, *args): + """ + randn(d0, d1, ..., dn) + + Return a sample (or samples) from the "standard normal" distribution. + + If positive, int_like or int-convertible arguments are provided, + `randn` generates an array of shape ``(d0, d1, ..., dn)``, filled + with random floats sampled from a univariate "normal" (Gaussian) + distribution of mean 0 and variance 1 (if any of the :math:`d_i` are + floats, they are first converted to integers by truncation). A single + float randomly sampled from the distribution is returned if no + argument is provided. + + This is a convenience function. If you want an interface that takes a + tuple as the first argument, use `numpy.random.standard_normal` instead. + + Parameters + ---------- + d0, d1, ..., dn : int, optional + The dimensions of the returned array, should be all positive. + If no argument is given a single Python float is returned. + + Returns + ------- + Z : ndarray or float + A ``(d0, d1, ..., dn)``-shaped array of floating-point samples from + the standard normal distribution, or a single such float if + no parameters were supplied. + + See Also + -------- + random.standard_normal : Similar, but takes a tuple as its argument. + + Notes + ----- + For random samples from :math:`N(\\mu, \\sigma^2)`, use: + + ``sigma * np.random.randn(...) + mu`` + + Examples + -------- + >>> np.random.randn() + 2.1923875335537315 #random + + Two-by-four array of samples from N(3, 6.25): + + >>> 2.5 * np.random.randn(2, 4) + 3 + array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random + [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random + + """ + if len(args) == 0: + return self.standard_normal() + else: + return self.standard_normal(args) + + def random_integers(self, low, high=None, size=None): + """ + random_integers(low, high=None, size=None) + + Random integers of type np.int between `low` and `high`, inclusive. + + Return random integers of type np.int from the "discrete uniform" + distribution in the closed interval [`low`, `high`]. If `high` is + None (the default), then results are from [1, `low`]. The np.int + type translates to the C long type used by Python 2 for "short" + integers and its precision is platform dependent. + + This function has been deprecated. Use randint instead. + + .. deprecated:: 1.11.0 + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution (unless + ``high=None``, in which case this parameter is the *highest* such + integer). + high : int, optional + If provided, the largest (signed) integer to be drawn from the + distribution (see above for behavior if ``high=None``). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : int or ndarray of ints + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + See Also + -------- + random.randint : Similar to `random_integers`, only for the half-open + interval [`low`, `high`), and 0 is the lowest value if `high` is + omitted. + + Notes + ----- + To sample from N evenly spaced floating-point numbers between a and b, + use:: + + a + (b - a) * (np.random.random_integers(N) - 1) / (N - 1.) + + Examples + -------- + >>> np.random.random_integers(5) + 4 + >>> type(np.random.random_integers(5)) + + >>> np.random.random_integers(5, size=(3,2)) + array([[5, 4], + [3, 3], + [4, 5]]) + + Choose five random numbers from the set of five evenly-spaced + numbers between 0 and 2.5, inclusive (*i.e.*, from the set + :math:`{0, 5/8, 10/8, 15/8, 20/8}`): + + >>> 2.5 * (np.random.random_integers(5, size=(5,)) - 1) / 4. + array([ 0.625, 1.25 , 0.625, 0.625, 2.5 ]) + + Roll two six sided dice 1000 times and sum the results: + + >>> d1 = np.random.random_integers(1, 6, 1000) + >>> d2 = np.random.random_integers(1, 6, 1000) + >>> dsums = d1 + d2 + + Display results as a histogram: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(dsums, 11, normed=True) + >>> plt.show() + + """ + if high is None: + warnings.warn(("This function is deprecated. Please call " + "randint(1, {low} + 1) instead".format(low=low)), + DeprecationWarning) + high = low + low = 1 + + else: + warnings.warn(("This function is deprecated. Please call " + "randint({low}, {high} + 1) instead".format( + low=low, high=high)), DeprecationWarning) + + return self.randint(low, high + 1, size=size, dtype='l') + + + + # Complicated, continuous distributions: + def standard_normal(self, size=None): + """ + standard_normal(size=None) + + Draw samples from a standard Normal distribution (mean=0, stdev=1). + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + >>> s = np.random.standard_normal(8000) + >>> s + array([ 0.6888893 , 0.78096262, -0.89086505, ..., 0.49876311, #random + -0.38672696, -0.4685006 ]) #random + >>> s.shape + (8000,) + >>> s = np.random.standard_normal(size=(3, 4, 2)) + >>> s.shape + (3, 4, 2) + + """ + return cont0_array(self.internal_state, rk_gauss, size, self.lock) + + def normal(self, loc=0.0, scale=1.0, size=None): + """ + normal(loc=0.0, scale=1.0, size=None) + + Draw random samples from a normal (Gaussian) distribution. + + The probability density function of the normal distribution, first + derived by De Moivre and 200 years later by both Gauss and Laplace + independently [2]_, is often called the bell curve because of + its characteristic shape (see the example below). + + The normal distributions occurs often in nature. For example, it + describes the commonly occurring distribution of samples influenced + by a large number of tiny, random disturbances, each with its own + unique distribution [2]_. + + Parameters + ---------- + loc : float or array_like of floats + Mean ("centre") of the distribution. + scale : float or array_like of floats + Standard deviation (spread or "width") of the distribution. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized normal distribution. + + See Also + -------- + scipy.stats.norm : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gaussian distribution is + + .. math:: p(x) = \\frac{1}{\\sqrt{ 2 \\pi \\sigma^2 }} + e^{ - \\frac{ (x - \\mu)^2 } {2 \\sigma^2} }, + + where :math:`\\mu` is the mean and :math:`\\sigma` the standard + deviation. The square of the standard deviation, :math:`\\sigma^2`, + is called the variance. + + The function has its peak at the mean, and its "spread" increases with + the standard deviation (the function reaches 0.607 times its maximum at + :math:`x + \\sigma` and :math:`x - \\sigma` [2]_). This implies that + `numpy.random.normal` is more likely to return samples lying close to + the mean, rather than those far away. + + References + ---------- + .. [1] Wikipedia, "Normal distribution", + http://en.wikipedia.org/wiki/Normal_distribution + .. [2] P. R. Peebles Jr., "Central Limit Theorem" in "Probability, + Random Variables and Random Signal Principles", 4th ed., 2001, + pp. 51, 51, 125. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, sigma = 0, 0.1 # mean and standard deviation + >>> s = np.random.normal(mu, sigma, 1000) + + Verify the mean and the variance: + + >>> abs(mu - np.mean(s)) < 0.01 + True + + >>> abs(sigma - np.std(s, ddof=1)) < 0.01 + True + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * + ... np.exp( - (bins - mu)**2 / (2 * sigma**2) ), + ... linewidth=2, color='r') + >>> plt.show() + + """ + cdef ndarray oloc, oscale + cdef double floc, fscale + + oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oloc.shape == oscale.shape == (): + floc = PyFloat_AsDouble(loc) + fscale = PyFloat_AsDouble(scale) + if np.signbit(fscale): + raise ValueError("scale < 0") + return cont2_array_sc(self.internal_state, rk_normal, size, floc, + fscale, self.lock) + + if np.any(np.signbit(oscale)): + raise ValueError("scale < 0") + return cont2_array(self.internal_state, rk_normal, size, oloc, oscale, + self.lock) + + def beta(self, a, b, size=None): + """ + beta(a, b, size=None) + + Draw samples from a Beta distribution. + + The Beta distribution is a special case of the Dirichlet distribution, + and is related to the Gamma distribution. It has the probability + distribution function + + .. math:: f(x; a,b) = \\frac{1}{B(\\alpha, \\beta)} x^{\\alpha - 1} + (1 - x)^{\\beta - 1}, + + where the normalisation, B, is the beta function, + + .. math:: B(\\alpha, \\beta) = \\int_0^1 t^{\\alpha - 1} + (1 - t)^{\\beta - 1} dt. + + It is often seen in Bayesian inference and order statistics. + + Parameters + ---------- + a : float or array_like of floats + Alpha, non-negative. + b : float or array_like of floats + Beta, non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` and ``b`` are both scalars. + Otherwise, ``np.broadcast(a, b).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized beta distribution. + + """ + cdef ndarray oa, ob + cdef double fa, fb + + oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + ob = PyArray_FROM_OTF(b, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oa.shape == ob.shape == (): + fa = PyFloat_AsDouble(a) + fb = PyFloat_AsDouble(b) + + if fa <= 0: + raise ValueError("a <= 0") + if fb <= 0: + raise ValueError("b <= 0") + return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb, + self.lock) + + if np.any(np.less_equal(oa, 0)): + raise ValueError("a <= 0") + if np.any(np.less_equal(ob, 0)): + raise ValueError("b <= 0") + return cont2_array(self.internal_state, rk_beta, size, oa, ob, + self.lock) + + def exponential(self, scale=1.0, size=None): + """ + exponential(scale=1.0, size=None) + + Draw samples from an exponential distribution. + + Its probability density function is + + .. math:: f(x; \\frac{1}{\\beta}) = \\frac{1}{\\beta} \\exp(-\\frac{x}{\\beta}), + + for ``x > 0`` and 0 elsewhere. :math:`\\beta` is the scale parameter, + which is the inverse of the rate parameter :math:`\\lambda = 1/\\beta`. + The rate parameter is an alternative, widely used parameterization + of the exponential distribution [3]_. + + The exponential distribution is a continuous analogue of the + geometric distribution. It describes many common situations, such as + the size of raindrops measured over many rainstorms [1]_, or the time + between page requests to Wikipedia [2]_. + + Parameters + ---------- + scale : float or array_like of floats + The scale parameter, :math:`\\beta = 1/\\lambda`. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``scale`` is a scalar. Otherwise, + ``np.array(scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized exponential distribution. + + References + ---------- + .. [1] Peyton Z. Peebles Jr., "Probability, Random Variables and + Random Signal Principles", 4th ed, 2001, p. 57. + .. [2] Wikipedia, "Poisson process", + http://en.wikipedia.org/wiki/Poisson_process + .. [3] Wikipedia, "Exponential distribution", + http://en.wikipedia.org/wiki/Exponential_distribution + + """ + cdef ndarray oscale + cdef double fscale + + oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oscale.shape == (): + fscale = PyFloat_AsDouble(scale) + if np.signbit(fscale): + raise ValueError("scale < 0") + return cont1_array_sc(self.internal_state, rk_exponential, size, + fscale, self.lock) + + if np.any(np.signbit(oscale)): + raise ValueError("scale < 0") + return cont1_array(self.internal_state, rk_exponential, size, oscale, + self.lock) + + def standard_exponential(self, size=None): + """ + standard_exponential(size=None) + + Draw samples from the standard exponential distribution. + + `standard_exponential` is identical to the exponential distribution + with a scale parameter of 1. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : float or ndarray + Drawn samples. + + Examples + -------- + Output a 3x8000 array: + + >>> n = np.random.standard_exponential((3, 8000)) + + """ + return cont0_array(self.internal_state, rk_standard_exponential, size, + self.lock) + + def standard_gamma(self, shape, size=None): + """ + standard_gamma(shape, size=None) + + Draw samples from a standard Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + shape (sometimes designated "k") and scale=1. + + Parameters + ---------- + shape : float or array_like of floats + Parameter, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` is a scalar. Otherwise, + ``np.array(shape).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + http://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 1. # mean and width + >>> s = np.random.standard_gamma(shape, 1000000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> y = bins**(shape-1) * ((np.exp(-bins/scale))/ \\ + ... (sps.gamma(shape) * scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + + """ + cdef ndarray oshape + cdef double fshape + + oshape = PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oshape.shape == (): + fshape = PyFloat_AsDouble(shape) + if np.signbit(fshape): + raise ValueError("shape < 0") + return cont1_array_sc(self.internal_state, rk_standard_gamma, + size, fshape, self.lock) + + if np.any(np.signbit(oshape)): + raise ValueError("shape < 0") + return cont1_array(self.internal_state, rk_standard_gamma, size, + oshape, self.lock) + + def gamma(self, shape, scale=1.0, size=None): + """ + gamma(shape, scale=1.0, size=None) + + Draw samples from a Gamma distribution. + + Samples are drawn from a Gamma distribution with specified parameters, + `shape` (sometimes designated "k") and `scale` (sometimes designated + "theta"), where both parameters are > 0. + + Parameters + ---------- + shape : float or array_like of floats + The shape of the gamma distribution. Should be greater than zero. + scale : float or array_like of floats, optional + The scale of the gamma distribution. Should be greater than zero. + Default is equal to 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``shape`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(shape, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized gamma distribution. + + See Also + -------- + scipy.stats.gamma : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Gamma distribution is + + .. math:: p(x) = x^{k-1}\\frac{e^{-x/\\theta}}{\\theta^k\\Gamma(k)}, + + where :math:`k` is the shape and :math:`\\theta` the scale, + and :math:`\\Gamma` is the Gamma function. + + The Gamma distribution is often used to model the times to failure of + electronic components, and arises naturally in processes for which the + waiting times between Poisson distributed events are relevant. + + References + ---------- + .. [1] Weisstein, Eric W. "Gamma Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/GammaDistribution.html + .. [2] Wikipedia, "Gamma distribution", + http://en.wikipedia.org/wiki/Gamma_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> shape, scale = 2., 2. # mean=4, std=2*sqrt(2) + >>> s = np.random.gamma(shape, scale, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> import scipy.special as sps + >>> count, bins, ignored = plt.hist(s, 50, normed=True) + >>> y = bins**(shape-1)*(np.exp(-bins/scale) / + ... (sps.gamma(shape)*scale**shape)) + >>> plt.plot(bins, y, linewidth=2, color='r') + >>> plt.show() + + """ + cdef ndarray oshape, oscale + cdef double fshape, fscale + + oshape = PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oshape.shape == oscale.shape == (): + fshape = PyFloat_AsDouble(shape) + fscale = PyFloat_AsDouble(scale) + if np.signbit(fshape): + raise ValueError("shape < 0") + if np.signbit(fscale): + raise ValueError("scale < 0") + return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, + fscale, self.lock) + + if np.any(np.signbit(oshape)): + raise ValueError("shape < 0") + if np.any(np.signbit(oscale)): + raise ValueError("scale < 0") + return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale, + self.lock) + + def f(self, dfnum, dfden, size=None): + """ + f(dfnum, dfden, size=None) + + Draw samples from an F distribution. + + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters should be greater than + zero. + + The random variate of the F distribution (also known as the + Fisher distribution) is a continuous probability distribution + that arises in ANOVA tests, and is the ratio of two chi-square + variates. + + Parameters + ---------- + dfnum : float or array_like of floats + Degrees of freedom in numerator, should be > 0. + dfden : float or array_like of float + Degrees of freedom in denominator, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``dfnum`` and ``dfden`` are both scalars. + Otherwise, ``np.broadcast(dfnum, dfden).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Fisher distribution. + + See Also + -------- + scipy.stats.f : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The F statistic is used to compare in-group variances to between-group + variances. Calculating the distribution depends on the sampling, and + so it is a function of the respective degrees of freedom in the + problem. The variable `dfnum` is the number of samples minus one, the + between-groups degrees of freedom, while `dfden` is the within-groups + degrees of freedom, the sum of the number of samples in each group + minus the number of groups. + + References + ---------- + .. [1] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, + Fifth Edition, 2002. + .. [2] Wikipedia, "F-distribution", + http://en.wikipedia.org/wiki/F-distribution + + Examples + -------- + An example from Glantz[1], pp 47-40: + + Two groups, children of diabetics (25 people) and children from people + without diabetes (25 controls). Fasting blood glucose was measured, + case group had a mean value of 86.1, controls had a mean value of + 82.2. Standard deviations were 2.09 and 2.49 respectively. Are these + data consistent with the null hypothesis that the parents diabetic + status does not affect their children's blood glucose levels? + Calculating the F statistic from the data gives a value of 36.01. + + Draw samples from the distribution: + + >>> dfnum = 1. # between group degrees of freedom + >>> dfden = 48. # within groups degrees of freedom + >>> s = np.random.f(dfnum, dfden, 1000) + + The lower bound for the top 1% of the samples is : + + >>> sort(s)[-10] + 7.61988120985 + + So there is about a 1% chance that the F statistic will exceed 7.62, + the measured value is 36, so the null hypothesis is rejected at the 1% + level. + + """ + cdef ndarray odfnum, odfden + cdef double fdfnum, fdfden + + odfnum = PyArray_FROM_OTF(dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if odfnum.shape == odfden.shape == (): + fdfnum = PyFloat_AsDouble(dfnum) + fdfden = PyFloat_AsDouble(dfden) + + if fdfnum <= 0: + raise ValueError("dfnum <= 0") + if fdfden <= 0: + raise ValueError("dfden <= 0") + return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, + fdfden, self.lock) + + if np.any(np.less_equal(odfnum, 0.0)): + raise ValueError("dfnum <= 0") + if np.any(np.less_equal(odfden, 0.0)): + raise ValueError("dfden <= 0") + return cont2_array(self.internal_state, rk_f, size, odfnum, odfden, + self.lock) + + def noncentral_f(self, dfnum, dfden, nonc, size=None): + """ + noncentral_f(dfnum, dfden, nonc, size=None) + + Draw samples from the noncentral F distribution. + + Samples are drawn from an F distribution with specified parameters, + `dfnum` (degrees of freedom in numerator) and `dfden` (degrees of + freedom in denominator), where both parameters > 1. + `nonc` is the non-centrality parameter. + + Parameters + ---------- + dfnum : float or array_like of floats + Numerator degrees of freedom, should be > 0. + + .. versionchanged:: 1.14.0 + Earlier NumPy versions required dfnum > 1. + dfden : float or array_like of floats + Denominator degrees of freedom, should be > 0. + nonc : float or array_like of floats + Non-centrality parameter, the sum of the squares of the numerator + means, should be >= 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``dfnum``, ``dfden``, and ``nonc`` + are all scalars. Otherwise, ``np.broadcast(dfnum, dfden, nonc).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized noncentral Fisher distribution. + + Notes + ----- + When calculating the power of an experiment (power = probability of + rejecting the null hypothesis when a specific alternative is true) the + non-central F statistic becomes important. When the null hypothesis is + true, the F statistic follows a central F distribution. When the null + hypothesis is not true, then it follows a non-central F statistic. + + References + ---------- + .. [1] Weisstein, Eric W. "Noncentral F-Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/NoncentralF-Distribution.html + .. [2] Wikipedia, "Noncentral F-distribution", + http://en.wikipedia.org/wiki/Noncentral_F-distribution + + Examples + -------- + In a study, testing for a specific alternative to the null hypothesis + requires use of the Noncentral F distribution. We need to calculate the + area in the tail of the distribution that exceeds the value of the F + distribution for the null hypothesis. We'll plot the two probability + distributions for comparison. + + >>> dfnum = 3 # between group deg of freedom + >>> dfden = 20 # within groups degrees of freedom + >>> nonc = 3.0 + >>> nc_vals = np.random.noncentral_f(dfnum, dfden, nonc, 1000000) + >>> NF = np.histogram(nc_vals, bins=50, normed=True) + >>> c_vals = np.random.f(dfnum, dfden, 1000000) + >>> F = np.histogram(c_vals, bins=50, normed=True) + >>> plt.plot(F[1][1:], F[0]) + >>> plt.plot(NF[1][1:], NF[0]) + >>> plt.show() + + """ + cdef ndarray odfnum, odfden, ononc + cdef double fdfnum, fdfden, fnonc + + odfnum = PyArray_FROM_OTF(dfnum, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + odfden = PyArray_FROM_OTF(dfden, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if odfnum.shape == odfden.shape == ononc.shape == (): + fdfnum = PyFloat_AsDouble(dfnum) + fdfden = PyFloat_AsDouble(dfden) + fnonc = PyFloat_AsDouble(nonc) + + if fdfnum <= 0: + raise ValueError("dfnum <= 0") + if fdfden <= 0: + raise ValueError("dfden <= 0") + if fnonc < 0: + raise ValueError("nonc < 0") + return cont3_array_sc(self.internal_state, rk_noncentral_f, size, + fdfnum, fdfden, fnonc, self.lock) + + if np.any(np.less_equal(odfnum, 0.0)): + raise ValueError("dfnum <= 0") + if np.any(np.less_equal(odfden, 0.0)): + raise ValueError("dfden <= 0") + if np.any(np.less(ononc, 0.0)): + raise ValueError("nonc < 0") + return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum, + odfden, ononc, self.lock) + + def chisquare(self, df, size=None): + """ + chisquare(df, size=None) + + Draw samples from a chi-square distribution. + + When `df` independent random variables, each with standard normal + distributions (mean 0, variance 1), are squared and summed, the + resulting distribution is chi-square (see Notes). This distribution + is often used in hypothesis testing. + + Parameters + ---------- + df : float or array_like of floats + Number of degrees of freedom, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized chi-square distribution. + + Raises + ------ + ValueError + When `df` <= 0 or when an inappropriate `size` (e.g. ``size=-1``) + is given. + + Notes + ----- + The variable obtained by summing the squares of `df` independent, + standard normally distributed random variables: + + .. math:: Q = \\sum_{i=0}^{\\mathtt{df}} X^2_i + + is chi-square distributed, denoted + + .. math:: Q \\sim \\chi^2_k. + + The probability density function of the chi-squared distribution is + + .. math:: p(x) = \\frac{(1/2)^{k/2}}{\\Gamma(k/2)} + x^{k/2 - 1} e^{-x/2}, + + where :math:`\\Gamma` is the gamma function, + + .. math:: \\Gamma(x) = \\int_0^{-\\infty} t^{x - 1} e^{-t} dt. + + References + ---------- + .. [1] NIST "Engineering Statistics Handbook" + http://www.itl.nist.gov/div898/handbook/eda/section3/eda3666.htm + + Examples + -------- + >>> np.random.chisquare(2,4) + array([ 1.89920014, 9.00867716, 3.13710533, 5.62318272]) + + """ + cdef ndarray odf + cdef double fdf + + odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if odf.shape == (): + fdf = PyFloat_AsDouble(df) + + if fdf <= 0: + raise ValueError("df <= 0") + return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf, + self.lock) + + if np.any(np.less_equal(odf, 0.0)): + raise ValueError("df <= 0") + return cont1_array(self.internal_state, rk_chisquare, size, odf, + self.lock) + + def noncentral_chisquare(self, df, nonc, size=None): + """ + noncentral_chisquare(df, nonc, size=None) + + Draw samples from a noncentral chi-square distribution. + + The noncentral :math:`\\chi^2` distribution is a generalisation of + the :math:`\\chi^2` distribution. + + Parameters + ---------- + df : float or array_like of floats + Degrees of freedom, should be > 0. + + .. versionchanged:: 1.10.0 + Earlier NumPy versions required dfnum > 1. + nonc : float or array_like of floats + Non-centrality, should be non-negative. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` and ``nonc`` are both scalars. + Otherwise, ``np.broadcast(df, nonc).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized noncentral chi-square distribution. + + Notes + ----- + The probability density function for the noncentral Chi-square + distribution is + + .. math:: P(x;df,nonc) = \\sum^{\\infty}_{i=0} + \\frac{e^{-nonc/2}(nonc/2)^{i}}{i!} + \\P_{Y_{df+2i}}(x), + + where :math:`Y_{q}` is the Chi-square with q degrees of freedom. + + In Delhi (2007), it is noted that the noncentral chi-square is + useful in bombing and coverage problems, the probability of + killing the point target given by the noncentral chi-squared + distribution. + + References + ---------- + .. [1] Delhi, M.S. Holla, "On a noncentral chi-square distribution in + the analysis of weapon systems effectiveness", Metrika, + Volume 15, Number 1 / December, 1970. + .. [2] Wikipedia, "Noncentral chi-square distribution" + http://en.wikipedia.org/wiki/Noncentral_chi-square_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram + + >>> import matplotlib.pyplot as plt + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), + ... bins=200, normed=True) + >>> plt.show() + + Draw values from a noncentral chisquare with very small noncentrality, + and compare to a chisquare. + + >>> plt.figure() + >>> values = plt.hist(np.random.noncentral_chisquare(3, .0000001, 100000), + ... bins=np.arange(0., 25, .1), normed=True) + >>> values2 = plt.hist(np.random.chisquare(3, 100000), + ... bins=np.arange(0., 25, .1), normed=True) + >>> plt.plot(values[1][0:-1], values[0]-values2[0], 'ob') + >>> plt.show() + + Demonstrate how large values of non-centrality lead to a more symmetric + distribution. + + >>> plt.figure() + >>> values = plt.hist(np.random.noncentral_chisquare(3, 20, 100000), + ... bins=200, normed=True) + >>> plt.show() + + """ + cdef ndarray odf, ononc + cdef double fdf, fnonc + + odf = PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + ononc = PyArray_FROM_OTF(nonc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if odf.shape == ononc.shape == (): + fdf = PyFloat_AsDouble(df) + fnonc = PyFloat_AsDouble(nonc) + + if fdf <= 0: + raise ValueError("df <= 0") + if fnonc < 0: + raise ValueError("nonc < 0") + return cont2_array_sc(self.internal_state, rk_noncentral_chisquare, + size, fdf, fnonc, self.lock) + + if np.any(np.less_equal(odf, 0.0)): + raise ValueError("df <= 0") + if np.any(np.less(ononc, 0.0)): + raise ValueError("nonc < 0") + return cont2_array(self.internal_state, rk_noncentral_chisquare, size, + odf, ononc, self.lock) + + def standard_cauchy(self, size=None): + """ + standard_cauchy(size=None) + + Draw samples from a standard Cauchy distribution with mode = 0. + + Also known as the Lorentz distribution. + + Parameters + ---------- + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + samples : ndarray or scalar + The drawn samples. + + Notes + ----- + The probability density function for the full Cauchy distribution is + + .. math:: P(x; x_0, \\gamma) = \\frac{1}{\\pi \\gamma \\bigl[ 1+ + (\\frac{x-x_0}{\\gamma})^2 \\bigr] } + + and the Standard Cauchy distribution just sets :math:`x_0=0` and + :math:`\\gamma=1` + + The Cauchy distribution arises in the solution to the driven harmonic + oscillator problem, and also describes spectral line broadening. It + also describes the distribution of values at which a line tilted at + a random angle will cut the x axis. + + When studying hypothesis tests that assume normality, seeing how the + tests perform on data from a Cauchy distribution is a good indicator of + their sensitivity to a heavy-tailed distribution, since the Cauchy looks + very much like a Gaussian distribution, but with heavier tails. + + References + ---------- + .. [1] NIST/SEMATECH e-Handbook of Statistical Methods, "Cauchy + Distribution", + http://www.itl.nist.gov/div898/handbook/eda/section3/eda3663.htm + .. [2] Weisstein, Eric W. "Cauchy Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/CauchyDistribution.html + .. [3] Wikipedia, "Cauchy distribution" + http://en.wikipedia.org/wiki/Cauchy_distribution + + Examples + -------- + Draw samples and plot the distribution: + + >>> s = np.random.standard_cauchy(1000000) + >>> s = s[(s>-25) & (s<25)] # truncate distribution so it plots well + >>> plt.hist(s, bins=100) + >>> plt.show() + + """ + return cont0_array(self.internal_state, rk_standard_cauchy, size, + self.lock) + + def standard_t(self, df, size=None): + """ + standard_t(df, size=None) + + Draw samples from a standard Student's t distribution with `df` degrees + of freedom. + + A special case of the hyperbolic distribution. As `df` gets + large, the result resembles that of the standard normal + distribution (`standard_normal`). + + Parameters + ---------- + df : float or array_like of floats + Degrees of freedom, should be > 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``df`` is a scalar. Otherwise, + ``np.array(df).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized standard Student's t distribution. + + Notes + ----- + The probability density function for the t distribution is + + .. math:: P(x, df) = \\frac{\\Gamma(\\frac{df+1}{2})}{\\sqrt{\\pi df} + \\Gamma(\\frac{df}{2})}\\Bigl( 1+\\frac{x^2}{df} \\Bigr)^{-(df+1)/2} + + The t test is based on an assumption that the data come from a + Normal distribution. The t test provides a way to test whether + the sample mean (that is the mean calculated from the data) is + a good estimate of the true mean. + + The derivation of the t-distribution was first published in + 1908 by William Gosset while working for the Guinness Brewery + in Dublin. Due to proprietary issues, he had to publish under + a pseudonym, and so he used the name Student. + + References + ---------- + .. [1] Dalgaard, Peter, "Introductory Statistics With R", + Springer, 2002. + .. [2] Wikipedia, "Student's t-distribution" + http://en.wikipedia.org/wiki/Student's_t-distribution + + Examples + -------- + From Dalgaard page 83 [1]_, suppose the daily energy intake for 11 + women in Kj is: + + >>> intake = np.array([5260., 5470, 5640, 6180, 6390, 6515, 6805, 7515, \\ + ... 7515, 8230, 8770]) + + Does their energy intake deviate systematically from the recommended + value of 7725 kJ? + + We have 10 degrees of freedom, so is the sample mean within 95% of the + recommended value? + + >>> s = np.random.standard_t(10, size=100000) + >>> np.mean(intake) + 6753.636363636364 + >>> intake.std(ddof=1) + 1142.1232221373727 + + Calculate the t statistic, setting the ddof parameter to the unbiased + value so the divisor in the standard deviation will be degrees of + freedom, N-1. + + >>> t = (np.mean(intake)-7725)/(intake.std(ddof=1)/np.sqrt(len(intake))) + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(s, bins=100, normed=True) + + For a one-sided t-test, how far out in the distribution does the t + statistic appear? + + >>> np.sum(s PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if odf.shape == (): + fdf = PyFloat_AsDouble(df) + + if fdf <= 0: + raise ValueError("df <= 0") + return cont1_array_sc(self.internal_state, rk_standard_t, size, + fdf, self.lock) + + if np.any(np.less_equal(odf, 0.0)): + raise ValueError("df <= 0") + return cont1_array(self.internal_state, rk_standard_t, size, odf, + self.lock) + + def vonmises(self, mu, kappa, size=None): + """ + vonmises(mu, kappa, size=None) + + Draw samples from a von Mises distribution. + + Samples are drawn from a von Mises distribution with specified mode + (mu) and dispersion (kappa), on the interval [-pi, pi]. + + The von Mises distribution (also known as the circular normal + distribution) is a continuous probability distribution on the unit + circle. It may be thought of as the circular analogue of the normal + distribution. + + Parameters + ---------- + mu : float or array_like of floats + Mode ("center") of the distribution. + kappa : float or array_like of floats + Dispersion of the distribution, has to be >=0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mu`` and ``kappa`` are both scalars. + Otherwise, ``np.broadcast(mu, kappa).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized von Mises distribution. + + See Also + -------- + scipy.stats.vonmises : probability density function, distribution, or + cumulative density function, etc. + + Notes + ----- + The probability density for the von Mises distribution is + + .. math:: p(x) = \\frac{e^{\\kappa cos(x-\\mu)}}{2\\pi I_0(\\kappa)}, + + where :math:`\\mu` is the mode and :math:`\\kappa` the dispersion, + and :math:`I_0(\\kappa)` is the modified Bessel function of order 0. + + The von Mises is named for Richard Edler von Mises, who was born in + Austria-Hungary, in what is now the Ukraine. He fled to the United + States in 1939 and became a professor at Harvard. He worked in + probability theory, aerodynamics, fluid mechanics, and philosophy of + science. + + References + ---------- + .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). "Handbook of + Mathematical Functions with Formulas, Graphs, and Mathematical + Tables, 9th printing," New York: Dover, 1972. + .. [2] von Mises, R., "Mathematical Theory of Probability + and Statistics", New York: Academic Press, 1964. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, kappa = 0.0, 4.0 # mean and dispersion + >>> s = np.random.vonmises(mu, kappa, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> from scipy.special import i0 + >>> plt.hist(s, 50, normed=True) + >>> x = np.linspace(-np.pi, np.pi, num=51) + >>> y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa)) + >>> plt.plot(x, y, linewidth=2, color='r') + >>> plt.show() + + """ + cdef ndarray omu, okappa + cdef double fmu, fkappa + + omu = PyArray_FROM_OTF(mu, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + okappa = PyArray_FROM_OTF(kappa, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if omu.shape == okappa.shape == (): + fmu = PyFloat_AsDouble(mu) + fkappa = PyFloat_AsDouble(kappa) + + if fkappa < 0: + raise ValueError("kappa < 0") + return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, + fkappa, self.lock) + + if np.any(np.less(okappa, 0.0)): + raise ValueError("kappa < 0") + return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa, + self.lock) + + def pareto(self, a, size=None): + """ + pareto(a, size=None) + + Draw samples from a Pareto II or Lomax distribution with + specified shape. + + The Lomax or Pareto II distribution is a shifted Pareto + distribution. The classical Pareto distribution can be + obtained from the Lomax distribution by adding 1 and + multiplying by the scale parameter ``m`` (see Notes). The + smallest value of the Lomax distribution is zero while for the + classical Pareto distribution it is ``mu``, where the standard + Pareto distribution has location ``mu = 1``. Lomax can also + be considered as a simplified version of the Generalized + Pareto distribution (available in SciPy), with the scale set + to one and the location set to zero. + + The Pareto distribution must be greater than zero, and is + unbounded above. It is also known as the "80-20 rule". In + this distribution, 80 percent of the weights are in the lowest + 20 percent of the range, while the other 20 percent fill the + remaining 80 percent of the range. + + Parameters + ---------- + a : float or array_like of floats + Shape of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Pareto distribution. + + See Also + -------- + scipy.stats.lomax : probability density function, distribution or + cumulative density function, etc. + scipy.stats.genpareto : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Pareto distribution is + + .. math:: p(x) = \\frac{am^a}{x^{a+1}} + + where :math:`a` is the shape and :math:`m` the scale. + + The Pareto distribution, named after the Italian economist + Vilfredo Pareto, is a power law probability distribution + useful in many real world problems. Outside the field of + economics it is generally referred to as the Bradford + distribution. Pareto developed the distribution to describe + the distribution of wealth in an economy. It has also found + use in insurance, web page access statistics, oil field sizes, + and many other problems, including the download frequency for + projects in Sourceforge [1]_. It is one of the so-called + "fat-tailed" distributions. + + + References + ---------- + .. [1] Francis Hunt and Paul Johnson, On the Pareto Distribution of + Sourceforge projects. + .. [2] Pareto, V. (1896). Course of Political Economy. Lausanne. + .. [3] Reiss, R.D., Thomas, M.(2001), Statistical Analysis of Extreme + Values, Birkhauser Verlag, Basel, pp 23-30. + .. [4] Wikipedia, "Pareto distribution", + http://en.wikipedia.org/wiki/Pareto_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a, m = 3., 2. # shape and mode + >>> s = (np.random.pareto(a, 1000) + 1) * m + + Display the histogram of the samples, along with the probability + density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, _ = plt.hist(s, 100, normed=True) + >>> fit = a*m**a / bins**(a+1) + >>> plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r') + >>> plt.show() + + """ + cdef ndarray oa + cdef double fa + + oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oa.shape == (): + fa = PyFloat_AsDouble(a) + + if fa <= 0: + raise ValueError("a <= 0") + return cont1_array_sc(self.internal_state, rk_pareto, size, fa, + self.lock) + + if np.any(np.less_equal(oa, 0.0)): + raise ValueError("a <= 0") + return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock) + + def weibull(self, a, size=None): + """ + weibull(a, size=None) + + Draw samples from a Weibull distribution. + + Draw samples from a 1-parameter Weibull distribution with the given + shape parameter `a`. + + .. math:: X = (-ln(U))^{1/a} + + Here, U is drawn from the uniform distribution over (0,1]. + + The more common 2-parameter Weibull, including a scale parameter + :math:`\\lambda` is just :math:`X = \\lambda(-ln(U))^{1/a}`. + + Parameters + ---------- + a : float or array_like of floats + Shape of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Weibull distribution. + + See Also + -------- + scipy.stats.weibull_max + scipy.stats.weibull_min + scipy.stats.genextreme + gumbel + + Notes + ----- + The Weibull (or Type III asymptotic extreme value distribution + for smallest values, SEV Type III, or Rosin-Rammler + distribution) is one of a class of Generalized Extreme Value + (GEV) distributions used in modeling extreme value problems. + This class includes the Gumbel and Frechet distributions. + + The probability density for the Weibull distribution is + + .. math:: p(x) = \\frac{a} + {\\lambda}(\\frac{x}{\\lambda})^{a-1}e^{-(x/\\lambda)^a}, + + where :math:`a` is the shape and :math:`\\lambda` the scale. + + The function has its peak (the mode) at + :math:`\\lambda(\\frac{a-1}{a})^{1/a}`. + + When ``a = 1``, the Weibull distribution reduces to the exponential + distribution. + + References + ---------- + .. [1] Waloddi Weibull, Royal Technical University, Stockholm, + 1939 "A Statistical Theory Of The Strength Of Materials", + Ingeniorsvetenskapsakademiens Handlingar Nr 151, 1939, + Generalstabens Litografiska Anstalts Forlag, Stockholm. + .. [2] Waloddi Weibull, "A Statistical Distribution Function of + Wide Applicability", Journal Of Applied Mechanics ASME Paper + 1951. + .. [3] Wikipedia, "Weibull distribution", + http://en.wikipedia.org/wiki/Weibull_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> s = np.random.weibull(a, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> x = np.arange(1,100.)/50. + >>> def weib(x,n,a): + ... return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a) + + >>> count, bins, ignored = plt.hist(np.random.weibull(5.,1000)) + >>> x = np.arange(1,100.)/50. + >>> scale = count.max()/weib(x, 1., 5.).max() + >>> plt.plot(x, weib(x, 1., 5.)*scale) + >>> plt.show() + + """ + cdef ndarray oa + cdef double fa + + oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oa.shape == (): + fa = PyFloat_AsDouble(a) + if np.signbit(fa): + raise ValueError("a < 0") + return cont1_array_sc(self.internal_state, rk_weibull, size, fa, + self.lock) + + if np.any(np.signbit(oa)): + raise ValueError("a < 0") + return cont1_array(self.internal_state, rk_weibull, size, oa, + self.lock) + + def power(self, a, size=None): + """ + power(a, size=None) + + Draws samples in [0, 1] from a power distribution with positive + exponent a - 1. + + Also known as the power function distribution. + + Parameters + ---------- + a : float or array_like of floats + Parameter of the distribution. Should be greater than zero. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized power distribution. + + Raises + ------ + ValueError + If a < 1. + + Notes + ----- + The probability density function is + + .. math:: P(x; a) = ax^{a-1}, 0 \\le x \\le 1, a>0. + + The power function distribution is just the inverse of the Pareto + distribution. It may also be seen as a special case of the Beta + distribution. + + It is used, for example, in modeling the over-reporting of insurance + claims. + + References + ---------- + .. [1] Christian Kleiber, Samuel Kotz, "Statistical size distributions + in economics and actuarial sciences", Wiley, 2003. + .. [2] Heckert, N. A. and Filliben, James J. "NIST Handbook 148: + Dataplot Reference Manual, Volume 2: Let Subcommands and Library + Functions", National Institute of Standards and Technology + Handbook Series, June 2003. + http://www.itl.nist.gov/div898/software/dataplot/refman2/auxillar/powpdf.pdf + + Examples + -------- + Draw samples from the distribution: + + >>> a = 5. # shape + >>> samples = 1000 + >>> s = np.random.power(a, samples) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, bins=30) + >>> x = np.linspace(0, 1, 100) + >>> y = a*x**(a-1.) + >>> normed_y = samples*np.diff(bins)[0]*y + >>> plt.plot(x, normed_y) + >>> plt.show() + + Compare the power function distribution to the inverse of the Pareto. + + >>> from scipy import stats + >>> rvs = np.random.power(5, 1000000) + >>> rvsp = np.random.pareto(5, 1000000) + >>> xx = np.linspace(0,1,100) + >>> powpdf = stats.powerlaw.pdf(xx,5) + + >>> plt.figure() + >>> plt.hist(rvs, bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('np.random.power(5)') + + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of 1 + np.random.pareto(5)') + + >>> plt.figure() + >>> plt.hist(1./(1.+rvsp), bins=50, normed=True) + >>> plt.plot(xx,powpdf,'r-') + >>> plt.title('inverse of stats.pareto(5)') + + """ + cdef ndarray oa + cdef double fa + + oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oa.shape == (): + fa = PyFloat_AsDouble(a) + if np.signbit(fa): + raise ValueError("a < 0") + return cont1_array_sc(self.internal_state, rk_power, size, fa, + self.lock) + + if np.any(np.signbit(oa)): + raise ValueError("a < 0") + return cont1_array(self.internal_state, rk_power, size, oa, self.lock) + + def laplace(self, loc=0.0, scale=1.0, size=None): + """ + laplace(loc=0.0, scale=1.0, size=None) + + Draw samples from the Laplace or double exponential distribution with + specified location (or mean) and scale (decay). + + The Laplace distribution is similar to the Gaussian/normal distribution, + but is sharper at the peak and has fatter tails. It represents the + difference between two independent, identically distributed exponential + random variables. + + Parameters + ---------- + loc : float or array_like of floats, optional + The position, :math:`\\mu`, of the distribution peak. Default is 0. + scale : float or array_like of floats, optional + :math:`\\lambda`, the exponential decay. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Laplace distribution. + + Notes + ----- + It has the probability density function + + .. math:: f(x; \\mu, \\lambda) = \\frac{1}{2\\lambda} + \\exp\\left(-\\frac{|x - \\mu|}{\\lambda}\\right). + + The first law of Laplace, from 1774, states that the frequency + of an error can be expressed as an exponential function of the + absolute magnitude of the error, which leads to the Laplace + distribution. For many problems in economics and health + sciences, this distribution seems to model the data better + than the standard Gaussian distribution. + + References + ---------- + .. [1] Abramowitz, M. and Stegun, I. A. (Eds.). "Handbook of + Mathematical Functions with Formulas, Graphs, and Mathematical + Tables, 9th printing," New York: Dover, 1972. + .. [2] Kotz, Samuel, et. al. "The Laplace Distribution and + Generalizations, " Birkhauser, 2001. + .. [3] Weisstein, Eric W. "Laplace Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/LaplaceDistribution.html + .. [4] Wikipedia, "Laplace distribution", + http://en.wikipedia.org/wiki/Laplace_distribution + + Examples + -------- + Draw samples from the distribution + + >>> loc, scale = 0., 1. + >>> s = np.random.laplace(loc, scale, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> x = np.arange(-8., 8., .01) + >>> pdf = np.exp(-abs(x-loc)/scale)/(2.*scale) + >>> plt.plot(x, pdf) + + Plot Gaussian for comparison: + + >>> g = (1/(scale * np.sqrt(2 * np.pi)) * + ... np.exp(-(x - loc)**2 / (2 * scale**2))) + >>> plt.plot(x,g) + + """ + cdef ndarray oloc, oscale + cdef double floc, fscale + + oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oloc.shape == oscale.shape == (): + floc = PyFloat_AsDouble(loc) + fscale = PyFloat_AsDouble(scale) + if np.signbit(fscale): + raise ValueError("scale < 0") + return cont2_array_sc(self.internal_state, rk_laplace, size, floc, + fscale, self.lock) + + if np.any(np.signbit(oscale)): + raise ValueError("scale < 0") + return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale, + self.lock) + + def gumbel(self, loc=0.0, scale=1.0, size=None): + """ + gumbel(loc=0.0, scale=1.0, size=None) + + Draw samples from a Gumbel distribution. + + Draw samples from a Gumbel distribution with specified location and + scale. For more information on the Gumbel distribution, see + Notes and References below. + + Parameters + ---------- + loc : float or array_like of floats, optional + The location of the mode of the distribution. Default is 0. + scale : float or array_like of floats, optional + The scale parameter of the distribution. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Gumbel distribution. + + See Also + -------- + scipy.stats.gumbel_l + scipy.stats.gumbel_r + scipy.stats.genextreme + weibull + + Notes + ----- + The Gumbel (or Smallest Extreme Value (SEV) or the Smallest Extreme + Value Type I) distribution is one of a class of Generalized Extreme + Value (GEV) distributions used in modeling extreme value problems. + The Gumbel is a special case of the Extreme Value Type I distribution + for maximums from distributions with "exponential-like" tails. + + The probability density for the Gumbel distribution is + + .. math:: p(x) = \\frac{e^{-(x - \\mu)/ \\beta}}{\\beta} e^{ -e^{-(x - \\mu)/ + \\beta}}, + + where :math:`\\mu` is the mode, a location parameter, and + :math:`\\beta` is the scale parameter. + + The Gumbel (named for German mathematician Emil Julius Gumbel) was used + very early in the hydrology literature, for modeling the occurrence of + flood events. It is also used for modeling maximum wind speed and + rainfall rates. It is a "fat-tailed" distribution - the probability of + an event in the tail of the distribution is larger than if one used a + Gaussian, hence the surprisingly frequent occurrence of 100-year + floods. Floods were initially modeled as a Gaussian process, which + underestimated the frequency of extreme events. + + It is one of a class of extreme value distributions, the Generalized + Extreme Value (GEV) distributions, which also includes the Weibull and + Frechet. + + The function has a mean of :math:`\\mu + 0.57721\\beta` and a variance + of :math:`\\frac{\\pi^2}{6}\\beta^2`. + + References + ---------- + .. [1] Gumbel, E. J., "Statistics of Extremes," + New York: Columbia University Press, 1958. + .. [2] Reiss, R.-D. and Thomas, M., "Statistical Analysis of Extreme + Values from Insurance, Finance, Hydrology and Other Fields," + Basel: Birkhauser Verlag, 2001. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, beta = 0, 0.1 # location and scale + >>> s = np.random.gumbel(mu, beta, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 30, normed=True) + >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta) + ... * np.exp( -np.exp( -(bins - mu) /beta) ), + ... linewidth=2, color='r') + >>> plt.show() + + Show how an extreme value distribution can arise from a Gaussian process + and compare to a Gaussian: + + >>> means = [] + >>> maxima = [] + >>> for i in range(0,1000) : + ... a = np.random.normal(mu, beta, 1000) + ... means.append(a.mean()) + ... maxima.append(a.max()) + >>> count, bins, ignored = plt.hist(maxima, 30, normed=True) + >>> beta = np.std(maxima) * np.sqrt(6) / np.pi + >>> mu = np.mean(maxima) - 0.57721*beta + >>> plt.plot(bins, (1/beta)*np.exp(-(bins - mu)/beta) + ... * np.exp(-np.exp(-(bins - mu)/beta)), + ... linewidth=2, color='r') + >>> plt.plot(bins, 1/(beta * np.sqrt(2 * np.pi)) + ... * np.exp(-(bins - mu)**2 / (2 * beta**2)), + ... linewidth=2, color='g') + >>> plt.show() + + """ + cdef ndarray oloc, oscale + cdef double floc, fscale + + oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oloc.shape == oscale.shape == (): + floc = PyFloat_AsDouble(loc) + fscale = PyFloat_AsDouble(scale) + if np.signbit(fscale): + raise ValueError("scale < 0") + return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, + fscale, self.lock) + + if np.any(np.signbit(oscale)): + raise ValueError("scale < 0") + return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale, + self.lock) + + def logistic(self, loc=0.0, scale=1.0, size=None): + """ + logistic(loc=0.0, scale=1.0, size=None) + + Draw samples from a logistic distribution. + + Samples are drawn from a logistic distribution with specified + parameters, loc (location or mean, also median), and scale (>0). + + Parameters + ---------- + loc : float or array_like of floats, optional + Parameter of the distribution. Default is 0. + scale : float or array_like of floats, optional + Parameter of the distribution. Should be greater than zero. + Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``loc`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(loc, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized logistic distribution. + + See Also + -------- + scipy.stats.logistic : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Logistic distribution is + + .. math:: P(x) = P(x) = \\frac{e^{-(x-\\mu)/s}}{s(1+e^{-(x-\\mu)/s})^2}, + + where :math:`\\mu` = location and :math:`s` = scale. + + The Logistic distribution is used in Extreme Value problems where it + can act as a mixture of Gumbel distributions, in Epidemiology, and by + the World Chess Federation (FIDE) where it is used in the Elo ranking + system, assuming the performance of each player is a logistically + distributed random variable. + + References + ---------- + .. [1] Reiss, R.-D. and Thomas M. (2001), "Statistical Analysis of + Extreme Values, from Insurance, Finance, Hydrology and Other + Fields," Birkhauser Verlag, Basel, pp 132-133. + .. [2] Weisstein, Eric W. "Logistic Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/LogisticDistribution.html + .. [3] Wikipedia, "Logistic-distribution", + http://en.wikipedia.org/wiki/Logistic_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> loc, scale = 10, 1 + >>> s = np.random.logistic(loc, scale, 10000) + >>> count, bins, ignored = plt.hist(s, bins=50) + + # plot against distribution + + >>> def logist(x, loc, scale): + ... return exp((loc-x)/scale)/(scale*(1+exp((loc-x)/scale))**2) + >>> plt.plot(bins, logist(bins, loc, scale)*count.max()/\\ + ... logist(bins, loc, scale).max()) + >>> plt.show() + + """ + cdef ndarray oloc, oscale + cdef double floc, fscale + + oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oloc.shape == oscale.shape == (): + floc = PyFloat_AsDouble(loc) + fscale = PyFloat_AsDouble(scale) + if np.signbit(fscale): + raise ValueError("scale < 0") + return cont2_array_sc(self.internal_state, rk_logistic, size, floc, + fscale, self.lock) + + if np.any(np.signbit(oscale)): + raise ValueError("scale < 0") + return cont2_array(self.internal_state, rk_logistic, size, oloc, + oscale, self.lock) + + def lognormal(self, mean=0.0, sigma=1.0, size=None): + """ + lognormal(mean=0.0, sigma=1.0, size=None) + + Draw samples from a log-normal distribution. + + Draw samples from a log-normal distribution with specified mean, + standard deviation, and array shape. Note that the mean and standard + deviation are not the values for the distribution itself, but of the + underlying normal distribution it is derived from. + + Parameters + ---------- + mean : float or array_like of floats, optional + Mean value of the underlying normal distribution. Default is 0. + sigma : float or array_like of floats, optional + Standard deviation of the underlying normal distribution. Should + be greater than zero. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mean`` and ``sigma`` are both scalars. + Otherwise, ``np.broadcast(mean, sigma).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized log-normal distribution. + + See Also + -------- + scipy.stats.lognorm : probability density function, distribution, + cumulative density function, etc. + + Notes + ----- + A variable `x` has a log-normal distribution if `log(x)` is normally + distributed. The probability density function for the log-normal + distribution is: + + .. math:: p(x) = \\frac{1}{\\sigma x \\sqrt{2\\pi}} + e^{(-\\frac{(ln(x)-\\mu)^2}{2\\sigma^2})} + + where :math:`\\mu` is the mean and :math:`\\sigma` is the standard + deviation of the normally distributed logarithm of the variable. + A log-normal distribution results if a random variable is the *product* + of a large number of independent, identically-distributed variables in + the same way that a normal distribution results if the variable is the + *sum* of a large number of independent, identically-distributed + variables. + + References + ---------- + .. [1] Limpert, E., Stahel, W. A., and Abbt, M., "Log-normal + Distributions across the Sciences: Keys and Clues," + BioScience, Vol. 51, No. 5, May, 2001. + http://stat.ethz.ch/~stahel/lognormal/bioscience.pdf + .. [2] Reiss, R.D. and Thomas, M., "Statistical Analysis of Extreme + Values," Basel: Birkhauser Verlag, 2001, pp. 31-32. + + Examples + -------- + Draw samples from the distribution: + + >>> mu, sigma = 3., 1. # mean and standard deviation + >>> s = np.random.lognormal(mu, sigma, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 100, normed=True, align='mid') + + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, linewidth=2, color='r') + >>> plt.axis('tight') + >>> plt.show() + + Demonstrate that taking the products of random samples from a uniform + distribution can be fit well by a log-normal probability density + function. + + >>> # Generate a thousand samples: each is the product of 100 random + >>> # values, drawn from a normal distribution. + >>> b = [] + >>> for i in range(1000): + ... a = 10. + np.random.random(100) + ... b.append(np.product(a)) + + >>> b = np.array(b) / np.min(b) # scale values to be positive + >>> count, bins, ignored = plt.hist(b, 100, normed=True, align='mid') + >>> sigma = np.std(np.log(b)) + >>> mu = np.mean(np.log(b)) + + >>> x = np.linspace(min(bins), max(bins), 10000) + >>> pdf = (np.exp(-(np.log(x) - mu)**2 / (2 * sigma**2)) + ... / (x * sigma * np.sqrt(2 * np.pi))) + + >>> plt.plot(x, pdf, color='r', linewidth=2) + >>> plt.show() + + """ + cdef ndarray omean, osigma + cdef double fmean, fsigma + + omean = PyArray_FROM_OTF(mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + osigma = PyArray_FROM_OTF(sigma, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if omean.shape == osigma.shape == (): + fmean = PyFloat_AsDouble(mean) + fsigma = PyFloat_AsDouble(sigma) + if np.signbit(fsigma): + raise ValueError("sigma < 0") + return cont2_array_sc(self.internal_state, rk_lognormal, size, + fmean, fsigma, self.lock) + + if np.any(np.signbit(osigma)): + raise ValueError("sigma < 0.0") + return cont2_array(self.internal_state, rk_lognormal, size, omean, + osigma, self.lock) + + def rayleigh(self, scale=1.0, size=None): + """ + rayleigh(scale=1.0, size=None) + + Draw samples from a Rayleigh distribution. + + The :math:`\\chi` and Weibull distributions are generalizations of the + Rayleigh. + + Parameters + ---------- + scale : float or array_like of floats, optional + Scale, also equals the mode. Should be >= 0. Default is 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``scale`` is a scalar. Otherwise, + ``np.array(scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Rayleigh distribution. + + Notes + ----- + The probability density function for the Rayleigh distribution is + + .. math:: P(x;scale) = \\frac{x}{scale^2}e^{\\frac{-x^2}{2 \\cdotp scale^2}} + + The Rayleigh distribution would arise, for example, if the East + and North components of the wind velocity had identical zero-mean + Gaussian distributions. Then the wind speed would have a Rayleigh + distribution. + + References + ---------- + .. [1] Brighton Webs Ltd., "Rayleigh Distribution," + http://www.brighton-webs.co.uk/distributions/rayleigh.asp + .. [2] Wikipedia, "Rayleigh distribution" + http://en.wikipedia.org/wiki/Rayleigh_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram + + >>> values = hist(np.random.rayleigh(3, 100000), bins=200, normed=True) + + Wave heights tend to follow a Rayleigh distribution. If the mean wave + height is 1 meter, what fraction of waves are likely to be larger than 3 + meters? + + >>> meanvalue = 1 + >>> modevalue = np.sqrt(2 / np.pi) * meanvalue + >>> s = np.random.rayleigh(modevalue, 1000000) + + The percentage of waves larger than 3 meters is: + + >>> 100.*sum(s>3)/1000000. + 0.087300000000000003 + + """ + cdef ndarray oscale + cdef double fscale + + oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oscale.shape == (): + fscale = PyFloat_AsDouble(scale) + if np.signbit(fscale): + raise ValueError("scale < 0") + return cont1_array_sc(self.internal_state, rk_rayleigh, size, + fscale, self.lock) + + if np.any(np.signbit(oscale)): + raise ValueError("scale < 0.0") + return cont1_array(self.internal_state, rk_rayleigh, size, oscale, + self.lock) + + def wald(self, mean, scale, size=None): + """ + wald(mean, scale, size=None) + + Draw samples from a Wald, or inverse Gaussian, distribution. + + As the scale approaches infinity, the distribution becomes more like a + Gaussian. Some references claim that the Wald is an inverse Gaussian + with mean equal to 1, but this is by no means universal. + + The inverse Gaussian distribution was first studied in relationship to + Brownian motion. In 1956 M.C.K. Tweedie used the name inverse Gaussian + because there is an inverse relationship between the time to cover a + unit distance and distance covered in unit time. + + Parameters + ---------- + mean : float or array_like of floats + Distribution mean, should be > 0. + scale : float or array_like of floats + Scale parameter, should be >= 0. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``mean`` and ``scale`` are both scalars. + Otherwise, ``np.broadcast(mean, scale).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Wald distribution. + + Notes + ----- + The probability density function for the Wald distribution is + + .. math:: P(x;mean,scale) = \\sqrt{\\frac{scale}{2\\pi x^3}}e^ + \\frac{-scale(x-mean)^2}{2\\cdotp mean^2x} + + As noted above the inverse Gaussian distribution first arise + from attempts to model Brownian motion. It is also a + competitor to the Weibull for use in reliability modeling and + modeling stock returns and interest rate processes. + + References + ---------- + .. [1] Brighton Webs Ltd., Wald Distribution, + http://www.brighton-webs.co.uk/distributions/wald.asp + .. [2] Chhikara, Raj S., and Folks, J. Leroy, "The Inverse Gaussian + Distribution: Theory : Methodology, and Applications", CRC Press, + 1988. + .. [3] Wikipedia, "Wald distribution" + http://en.wikipedia.org/wiki/Wald_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram: + + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(np.random.wald(3, 2, 100000), bins=200, normed=True) + >>> plt.show() + + """ + cdef ndarray omean, oscale + cdef double fmean, fscale + + omean = PyArray_FROM_OTF(mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if omean.shape == oscale.shape == (): + fmean = PyFloat_AsDouble(mean) + fscale = PyFloat_AsDouble(scale) + + if fmean <= 0: + raise ValueError("mean <= 0") + if fscale <= 0: + raise ValueError("scale <= 0") + return cont2_array_sc(self.internal_state, rk_wald, size, fmean, + fscale, self.lock) + + if np.any(np.less_equal(omean,0.0)): + raise ValueError("mean <= 0.0") + elif np.any(np.less_equal(oscale,0.0)): + raise ValueError("scale <= 0.0") + return cont2_array(self.internal_state, rk_wald, size, omean, oscale, + self.lock) + + def triangular(self, left, mode, right, size=None): + """ + triangular(left, mode, right, size=None) + + Draw samples from the triangular distribution over the + interval ``[left, right]``. + + The triangular distribution is a continuous probability + distribution with lower limit left, peak at mode, and upper + limit right. Unlike the other distributions, these parameters + directly define the shape of the pdf. + + Parameters + ---------- + left : float or array_like of floats + Lower limit. + mode : float or array_like of floats + The value where the peak of the distribution occurs. + The value should fulfill the condition ``left <= mode <= right``. + right : float or array_like of floats + Upper limit, should be larger than `left`. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``left``, ``mode``, and ``right`` + are all scalars. Otherwise, ``np.broadcast(left, mode, right).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized triangular distribution. + + Notes + ----- + The probability density function for the triangular distribution is + + .. math:: P(x;l, m, r) = \\begin{cases} + \\frac{2(x-l)}{(r-l)(m-l)}& \\text{for $l \\leq x \\leq m$},\\\\ + \\frac{2(r-x)}{(r-l)(r-m)}& \\text{for $m \\leq x \\leq r$},\\\\ + 0& \\text{otherwise}. + \\end{cases} + + The triangular distribution is often used in ill-defined + problems where the underlying distribution is not known, but + some knowledge of the limits and mode exists. Often it is used + in simulations. + + References + ---------- + .. [1] Wikipedia, "Triangular distribution" + http://en.wikipedia.org/wiki/Triangular_distribution + + Examples + -------- + Draw values from the distribution and plot the histogram: + + >>> import matplotlib.pyplot as plt + >>> h = plt.hist(np.random.triangular(-3, 0, 8, 100000), bins=200, + ... normed=True) + >>> plt.show() + + """ + cdef ndarray oleft, omode, oright + cdef double fleft, fmode, fright + + oleft = PyArray_FROM_OTF(left, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + omode = PyArray_FROM_OTF(mode, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + oright = PyArray_FROM_OTF(right, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oleft.shape == omode.shape == oright.shape == (): + fleft = PyFloat_AsDouble(left) + fright = PyFloat_AsDouble(right) + fmode = PyFloat_AsDouble(mode) + + if fleft > fmode: + raise ValueError("left > mode") + if fmode > fright: + raise ValueError("mode > right") + if fleft == fright: + raise ValueError("left == right") + return cont3_array_sc(self.internal_state, rk_triangular, size, + fleft, fmode, fright, self.lock) + + if np.any(np.greater(oleft, omode)): + raise ValueError("left > mode") + if np.any(np.greater(omode, oright)): + raise ValueError("mode > right") + if np.any(np.equal(oleft, oright)): + raise ValueError("left == right") + return cont3_array(self.internal_state, rk_triangular, size, oleft, + omode, oright, self.lock) + + # Complicated, discrete distributions: + def binomial(self, n, p, size=None): + """ + binomial(n, p, size=None) + + Draw samples from a binomial distribution. + + Samples are drawn from a binomial distribution with specified + parameters, n trials and p probability of success where + n an integer >= 0 and p is in the interval [0,1]. (n may be + input as a float, but it is truncated to an integer in use) + + Parameters + ---------- + n : int or array_like of ints + Parameter of the distribution, >= 0. Floats are also accepted, + but they will be truncated to integers. + p : float or array_like of floats + Parameter of the distribution, >= 0 and <=1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``n`` and ``p`` are both scalars. + Otherwise, ``np.broadcast(n, p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized binomial distribution, where + each sample is equal to the number of successes over the n trials. + + See Also + -------- + scipy.stats.binom : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the binomial distribution is + + .. math:: P(N) = \\binom{n}{N}p^N(1-p)^{n-N}, + + where :math:`n` is the number of trials, :math:`p` is the probability + of success, and :math:`N` is the number of successes. + + When estimating the standard error of a proportion in a population by + using a random sample, the normal distribution works well unless the + product p*n <=5, where p = population proportion estimate, and n = + number of samples, in which case the binomial distribution is used + instead. For example, a sample of 15 people shows 4 who are left + handed, and 11 who are right handed. Then p = 4/15 = 27%. 0.27*15 = 4, + so the binomial distribution should be used in this case. + + References + ---------- + .. [1] Dalgaard, Peter, "Introductory Statistics with R", + Springer-Verlag, 2002. + .. [2] Glantz, Stanton A. "Primer of Biostatistics.", McGraw-Hill, + Fifth Edition, 2002. + .. [3] Lentner, Marvin, "Elementary Applied Statistics", Bogden + and Quigley, 1972. + .. [4] Weisstein, Eric W. "Binomial Distribution." From MathWorld--A + Wolfram Web Resource. + http://mathworld.wolfram.com/BinomialDistribution.html + .. [5] Wikipedia, "Binomial distribution", + http://en.wikipedia.org/wiki/Binomial_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> n, p = 10, .5 # number of trials, probability of each trial + >>> s = np.random.binomial(n, p, 1000) + # result of flipping a coin 10 times, tested 1000 times. + + A real world example. A company drills 9 wild-cat oil exploration + wells, each with an estimated probability of success of 0.1. All nine + wells fail. What is the probability of that happening? + + Let's do 20,000 trials of the model, and count the number that + generate zero positive results. + + >>> sum(np.random.binomial(9, 0.1, 20000) == 0)/20000. + # answer = 0.38885, or 38%. + + """ + cdef ndarray on, op + cdef long ln + cdef double fp + + on = PyArray_FROM_OTF(n, NPY_LONG, NPY_ARRAY_ALIGNED) + op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if on.shape == op.shape == (): + fp = PyFloat_AsDouble(p) + ln = PyInt_AsLong(n) + + if ln < 0: + raise ValueError("n < 0") + if fp < 0: + raise ValueError("p < 0") + elif fp > 1: + raise ValueError("p > 1") + elif np.isnan(fp): + raise ValueError("p is nan") + return discnp_array_sc(self.internal_state, rk_binomial, size, ln, + fp, self.lock) + + if np.any(np.less(n, 0)): + raise ValueError("n < 0") + if np.any(np.less(p, 0)): + raise ValueError("p < 0") + if np.any(np.greater(p, 1)): + raise ValueError("p > 1") + return discnp_array(self.internal_state, rk_binomial, size, on, op, + self.lock) + + def negative_binomial(self, n, p, size=None): + """ + negative_binomial(n, p, size=None) + + Draw samples from a negative binomial distribution. + + Samples are drawn from a negative binomial distribution with specified + parameters, `n` trials and `p` probability of success where `n` is an + integer > 0 and `p` is in the interval [0, 1]. + + Parameters + ---------- + n : int or array_like of ints + Parameter of the distribution, > 0. Floats are also accepted, + but they will be truncated to integers. + p : float or array_like of floats + Parameter of the distribution, >= 0 and <=1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``n`` and ``p`` are both scalars. + Otherwise, ``np.broadcast(n, p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized negative binomial distribution, + where each sample is equal to N, the number of trials it took to + achieve n - 1 successes, N - (n - 1) failures, and a success on the, + (N + n)th trial. + + Notes + ----- + The probability density for the negative binomial distribution is + + .. math:: P(N;n,p) = \\binom{N+n-1}{n-1}p^{n}(1-p)^{N}, + + where :math:`n-1` is the number of successes, :math:`p` is the + probability of success, and :math:`N+n-1` is the number of trials. + The negative binomial distribution gives the probability of n-1 + successes and N failures in N+n-1 trials, and success on the (N+n)th + trial. + + If one throws a die repeatedly until the third time a "1" appears, + then the probability distribution of the number of non-"1"s that + appear before the third "1" is a negative binomial distribution. + + References + ---------- + .. [1] Weisstein, Eric W. "Negative Binomial Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/NegativeBinomialDistribution.html + .. [2] Wikipedia, "Negative binomial distribution", + http://en.wikipedia.org/wiki/Negative_binomial_distribution + + Examples + -------- + Draw samples from the distribution: + + A real world example. A company drills wild-cat oil + exploration wells, each with an estimated probability of + success of 0.1. What is the probability of having one success + for each successive well, that is what is the probability of a + single success after drilling 5 wells, after 6 wells, etc.? + + >>> s = np.random.negative_binomial(1, 0.1, 100000) + >>> for i in range(1, 11): + ... probability = sum(sPyArray_FROM_OTF(n, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if on.shape == op.shape == (): + fp = PyFloat_AsDouble(p) + fn = PyFloat_AsDouble(n) + + if fn <= 0: + raise ValueError("n <= 0") + if fp < 0: + raise ValueError("p < 0") + elif fp > 1: + raise ValueError("p > 1") + return discdd_array_sc(self.internal_state, rk_negative_binomial, + size, fn, fp, self.lock) + + if np.any(np.less_equal(n, 0)): + raise ValueError("n <= 0") + if np.any(np.less(p, 0)): + raise ValueError("p < 0") + if np.any(np.greater(p, 1)): + raise ValueError("p > 1") + return discdd_array(self.internal_state, rk_negative_binomial, size, + on, op, self.lock) + + def poisson(self, lam=1.0, size=None): + """ + poisson(lam=1.0, size=None) + + Draw samples from a Poisson distribution. + + The Poisson distribution is the limit of the binomial distribution + for large N. + + Parameters + ---------- + lam : float or array_like of floats + Expectation of interval, should be >= 0. A sequence of expectation + intervals must be broadcastable over the requested size. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``lam`` is a scalar. Otherwise, + ``np.array(lam).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Poisson distribution. + + Notes + ----- + The Poisson distribution + + .. math:: f(k; \\lambda)=\\frac{\\lambda^k e^{-\\lambda}}{k!} + + For events with an expected separation :math:`\\lambda` the Poisson + distribution :math:`f(k; \\lambda)` describes the probability of + :math:`k` events occurring within the observed + interval :math:`\\lambda`. + + Because the output is limited to the range of the C long type, a + ValueError is raised when `lam` is within 10 sigma of the maximum + representable value. + + References + ---------- + .. [1] Weisstein, Eric W. "Poisson Distribution." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/PoissonDistribution.html + .. [2] Wikipedia, "Poisson distribution", + http://en.wikipedia.org/wiki/Poisson_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> import numpy as np + >>> s = np.random.poisson(5, 10000) + + Display histogram of the sample: + + >>> import matplotlib.pyplot as plt + >>> count, bins, ignored = plt.hist(s, 14, normed=True) + >>> plt.show() + + Draw each 100 values for lambda 100 and 500: + + >>> s = np.random.poisson(lam=(100., 500.), size=(100, 2)) + + """ + cdef ndarray olam + cdef double flam + + olam = PyArray_FROM_OTF(lam, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if olam.shape == (): + flam = PyFloat_AsDouble(lam) + + if lam < 0: + raise ValueError("lam < 0") + if lam > self.poisson_lam_max: + raise ValueError("lam value too large") + return discd_array_sc(self.internal_state, rk_poisson, size, flam, + self.lock) + + if np.any(np.less(olam, 0)): + raise ValueError("lam < 0") + if np.any(np.greater(olam, self.poisson_lam_max)): + raise ValueError("lam value too large.") + return discd_array(self.internal_state, rk_poisson, size, olam, + self.lock) + + def zipf(self, a, size=None): + """ + zipf(a, size=None) + + Draw samples from a Zipf distribution. + + Samples are drawn from a Zipf distribution with specified parameter + `a` > 1. + + The Zipf distribution (also known as the zeta distribution) is a + continuous probability distribution that satisfies Zipf's law: the + frequency of an item is inversely proportional to its rank in a + frequency table. + + Parameters + ---------- + a : float or array_like of floats + Distribution parameter. Should be greater than 1. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``a`` is a scalar. Otherwise, + ``np.array(a).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized Zipf distribution. + + See Also + -------- + scipy.stats.zipf : probability density function, distribution, or + cumulative density function, etc. + + Notes + ----- + The probability density for the Zipf distribution is + + .. math:: p(x) = \\frac{x^{-a}}{\\zeta(a)}, + + where :math:`\\zeta` is the Riemann Zeta function. + + It is named for the American linguist George Kingsley Zipf, who noted + that the frequency of any word in a sample of a language is inversely + proportional to its rank in the frequency table. + + References + ---------- + .. [1] Zipf, G. K., "Selected Studies of the Principle of Relative + Frequency in Language," Cambridge, MA: Harvard Univ. Press, + 1932. + + Examples + -------- + Draw samples from the distribution: + + >>> a = 2. # parameter + >>> s = np.random.zipf(a, 1000) + + Display the histogram of the samples, along with + the probability density function: + + >>> import matplotlib.pyplot as plt + >>> from scipy import special + + Truncate s values at 50 so plot is interesting: + + >>> count, bins, ignored = plt.hist(s[s<50], 50, normed=True) + >>> x = np.arange(1., 50.) + >>> y = x**(-a) / special.zetac(a) + >>> plt.plot(x, y/max(y), linewidth=2, color='r') + >>> plt.show() + + """ + cdef ndarray oa + cdef double fa + + oa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if oa.shape == (): + fa = PyFloat_AsDouble(a) + + # use logic that ensures NaN is rejected. + if not fa > 1.0: + raise ValueError("'a' must be a valid float > 1.0") + return discd_array_sc(self.internal_state, rk_zipf, size, fa, + self.lock) + + # use logic that ensures NaN is rejected. + if not np.all(np.greater(oa, 1.0)): + raise ValueError("'a' must contain valid floats > 1.0") + return discd_array(self.internal_state, rk_zipf, size, oa, self.lock) + + def geometric(self, p, size=None): + """ + geometric(p, size=None) + + Draw samples from the geometric distribution. + + Bernoulli trials are experiments with one of two outcomes: + success or failure (an example of such an experiment is flipping + a coin). The geometric distribution models the number of trials + that must be run in order to achieve success. It is therefore + supported on the positive integers, ``k = 1, 2, ...``. + + The probability mass function of the geometric distribution is + + .. math:: f(k) = (1 - p)^{k - 1} p + + where `p` is the probability of success of an individual trial. + + Parameters + ---------- + p : float or array_like of floats + The probability of success of an individual trial. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``p`` is a scalar. Otherwise, + ``np.array(p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized geometric distribution. + + Examples + -------- + Draw ten thousand values from the geometric distribution, + with the probability of an individual success equal to 0.35: + + >>> z = np.random.geometric(p=0.35, size=10000) + + How many trials succeeded after a single run? + + >>> (z == 1).sum() / 10000. + 0.34889999999999999 #random + + """ + cdef ndarray op + cdef double fp + + op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if op.shape == (): + fp = PyFloat_AsDouble(p) + + if fp < 0.0: + raise ValueError("p < 0.0") + if fp > 1.0: + raise ValueError("p > 1.0") + return discd_array_sc(self.internal_state, rk_geometric, size, fp, + self.lock) + + if np.any(np.less(op, 0.0)): + raise ValueError("p < 0.0") + if np.any(np.greater(op, 1.0)): + raise ValueError("p > 1.0") + return discd_array(self.internal_state, rk_geometric, size, op, + self.lock) + + def hypergeometric(self, ngood, nbad, nsample, size=None): + """ + hypergeometric(ngood, nbad, nsample, size=None) + + Draw samples from a Hypergeometric distribution. + + Samples are drawn from a hypergeometric distribution with specified + parameters, ngood (ways to make a good selection), nbad (ways to make + a bad selection), and nsample = number of items sampled, which is less + than or equal to the sum ngood + nbad. + + Parameters + ---------- + ngood : int or array_like of ints + Number of ways to make a good selection. Must be nonnegative. + nbad : int or array_like of ints + Number of ways to make a bad selection. Must be nonnegative. + nsample : int or array_like of ints + Number of items sampled. Must be at least 1 and at most + ``ngood + nbad``. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``ngood``, ``nbad``, and ``nsample`` + are all scalars. Otherwise, ``np.broadcast(ngood, nbad, nsample).size`` + samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized hypergeometric distribution. + + See Also + -------- + scipy.stats.hypergeom : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Hypergeometric distribution is + + .. math:: P(x) = \\frac{\\binom{m}{n}\\binom{N-m}{n-x}}{\\binom{N}{n}}, + + where :math:`0 \\le x \\le m` and :math:`n+m-N \\le x \\le n` + + for P(x) the probability of x successes, n = ngood, m = nbad, and + N = number of samples. + + Consider an urn with black and white marbles in it, ngood of them + black and nbad are white. If you draw nsample balls without + replacement, then the hypergeometric distribution describes the + distribution of black balls in the drawn sample. + + Note that this distribution is very similar to the binomial + distribution, except that in this case, samples are drawn without + replacement, whereas in the Binomial case samples are drawn with + replacement (or the sample space is infinite). As the sample space + becomes large, this distribution approaches the binomial. + + References + ---------- + .. [1] Lentner, Marvin, "Elementary Applied Statistics", Bogden + and Quigley, 1972. + .. [2] Weisstein, Eric W. "Hypergeometric Distribution." From + MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/HypergeometricDistribution.html + .. [3] Wikipedia, "Hypergeometric distribution", + http://en.wikipedia.org/wiki/Hypergeometric_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> ngood, nbad, nsamp = 100, 2, 10 + # number of good, number of bad, and number of samples + >>> s = np.random.hypergeometric(ngood, nbad, nsamp, 1000) + >>> hist(s) + # note that it is very unlikely to grab both bad items + + Suppose you have an urn with 15 white and 15 black marbles. + If you pull 15 marbles at random, how likely is it that + 12 or more of them are one color? + + >>> s = np.random.hypergeometric(15, 15, 15, 100000) + >>> sum(s>=12)/100000. + sum(s<=3)/100000. + # answer = 0.003 ... pretty unlikely! + + """ + cdef ndarray ongood, onbad, onsample + cdef long lngood, lnbad, lnsample + + ongood = PyArray_FROM_OTF(ngood, NPY_LONG, NPY_ARRAY_ALIGNED) + onbad = PyArray_FROM_OTF(nbad, NPY_LONG, NPY_ARRAY_ALIGNED) + onsample = PyArray_FROM_OTF(nsample, NPY_LONG, NPY_ARRAY_ALIGNED) + + if ongood.shape == onbad.shape == onsample.shape == (): + lngood = PyInt_AsLong(ngood) + lnbad = PyInt_AsLong(nbad) + lnsample = PyInt_AsLong(nsample) + + if lngood < 0: + raise ValueError("ngood < 0") + if lnbad < 0: + raise ValueError("nbad < 0") + if lnsample < 1: + raise ValueError("nsample < 1") + if lngood + lnbad < lnsample: + raise ValueError("ngood + nbad < nsample") + return discnmN_array_sc(self.internal_state, rk_hypergeometric, + size, lngood, lnbad, lnsample, self.lock) + + if np.any(np.less(ongood, 0)): + raise ValueError("ngood < 0") + if np.any(np.less(onbad, 0)): + raise ValueError("nbad < 0") + if np.any(np.less(onsample, 1)): + raise ValueError("nsample < 1") + if np.any(np.less(np.add(ongood, onbad),onsample)): + raise ValueError("ngood + nbad < nsample") + return discnmN_array(self.internal_state, rk_hypergeometric, size, + ongood, onbad, onsample, self.lock) + + def logseries(self, p, size=None): + """ + logseries(p, size=None) + + Draw samples from a logarithmic series distribution. + + Samples are drawn from a log series distribution with specified + shape parameter, 0 < ``p`` < 1. + + Parameters + ---------- + p : float or array_like of floats + Shape parameter for the distribution. Must be in the range (0, 1). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. If size is ``None`` (default), + a single value is returned if ``p`` is a scalar. Otherwise, + ``np.array(p).size`` samples are drawn. + + Returns + ------- + out : ndarray or scalar + Drawn samples from the parameterized logarithmic series distribution. + + See Also + -------- + scipy.stats.logser : probability density function, distribution or + cumulative density function, etc. + + Notes + ----- + The probability density for the Log Series distribution is + + .. math:: P(k) = \\frac{-p^k}{k \\ln(1-p)}, + + where p = probability. + + The log series distribution is frequently used to represent species + richness and occurrence, first proposed by Fisher, Corbet, and + Williams in 1943 [2]. It may also be used to model the numbers of + occupants seen in cars [3]. + + References + ---------- + .. [1] Buzas, Martin A.; Culver, Stephen J., Understanding regional + species diversity through the log series distribution of + occurrences: BIODIVERSITY RESEARCH Diversity & Distributions, + Volume 5, Number 5, September 1999 , pp. 187-195(9). + .. [2] Fisher, R.A,, A.S. Corbet, and C.B. Williams. 1943. The + relation between the number of species and the number of + individuals in a random sample of an animal population. + Journal of Animal Ecology, 12:42-58. + .. [3] D. J. Hand, F. Daly, D. Lunn, E. Ostrowski, A Handbook of Small + Data Sets, CRC Press, 1994. + .. [4] Wikipedia, "Logarithmic distribution", + http://en.wikipedia.org/wiki/Logarithmic_distribution + + Examples + -------- + Draw samples from the distribution: + + >>> a = .6 + >>> s = np.random.logseries(a, 10000) + >>> count, bins, ignored = plt.hist(s) + + # plot against distribution + + >>> def logseries(k, p): + ... return -p**k/(k*log(1-p)) + >>> plt.plot(bins, logseries(bins, a)*count.max()/ + logseries(bins, a).max(), 'r') + >>> plt.show() + + """ + cdef ndarray op + cdef double fp + + op = PyArray_FROM_OTF(p, NPY_DOUBLE, NPY_ARRAY_ALIGNED) + + if op.shape == (): + fp = PyFloat_AsDouble(p) + + if fp <= 0.0: + raise ValueError("p <= 0.0") + if fp >= 1.0: + raise ValueError("p >= 1.0") + return discd_array_sc(self.internal_state, rk_logseries, size, fp, + self.lock) + + if np.any(np.less_equal(op, 0.0)): + raise ValueError("p <= 0.0") + if np.any(np.greater_equal(op, 1.0)): + raise ValueError("p >= 1.0") + return discd_array(self.internal_state, rk_logseries, size, op, + self.lock) + + # Multivariate distributions: + def multivariate_normal(self, mean, cov, size=None, check_valid='warn', + tol=1e-8): + """ + multivariate_normal(mean, cov[, size, check_valid, tol]) + + Draw random samples from a multivariate normal distribution. + + The multivariate normal, multinormal or Gaussian distribution is a + generalization of the one-dimensional normal distribution to higher + dimensions. Such a distribution is specified by its mean and + covariance matrix. These parameters are analogous to the mean + (average or "center") and variance (standard deviation, or "width," + squared) of the one-dimensional normal distribution. + + Parameters + ---------- + mean : 1-D array_like, of length N + Mean of the N-dimensional distribution. + cov : 2-D array_like, of shape (N, N) + Covariance matrix of the distribution. It must be symmetric and + positive-semidefinite for proper sampling. + size : int or tuple of ints, optional + Given a shape of, for example, ``(m,n,k)``, ``m*n*k`` samples are + generated, and packed in an `m`-by-`n`-by-`k` arrangement. Because + each sample is `N`-dimensional, the output shape is ``(m,n,k,N)``. + If no shape is specified, a single (`N`-D) sample is returned. + check_valid : { 'warn', 'raise', 'ignore' }, optional + Behavior when the covariance matrix is not positive semidefinite. + tol : float, optional + Tolerance when checking the singular values in covariance matrix. + + Returns + ------- + out : ndarray + The drawn samples, of shape *size*, if that was provided. If not, + the shape is ``(N,)``. + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + + Notes + ----- + The mean is a coordinate in N-dimensional space, which represents the + location where samples are most likely to be generated. This is + analogous to the peak of the bell curve for the one-dimensional or + univariate normal distribution. + + Covariance indicates the level to which two variables vary together. + From the multivariate normal distribution, we draw N-dimensional + samples, :math:`X = [x_1, x_2, ... x_N]`. The covariance matrix + element :math:`C_{ij}` is the covariance of :math:`x_i` and :math:`x_j`. + The element :math:`C_{ii}` is the variance of :math:`x_i` (i.e. its + "spread"). + + Instead of specifying the full covariance matrix, popular + approximations include: + + - Spherical covariance (`cov` is a multiple of the identity matrix) + - Diagonal covariance (`cov` has non-negative elements, and only on + the diagonal) + + This geometrical property can be seen in two dimensions by plotting + generated data-points: + + >>> mean = [0, 0] + >>> cov = [[1, 0], [0, 100]] # diagonal covariance + + Diagonal covariance means that points are oriented along x or y-axis: + + >>> import matplotlib.pyplot as plt + >>> x, y = np.random.multivariate_normal(mean, cov, 5000).T + >>> plt.plot(x, y, 'x') + >>> plt.axis('equal') + >>> plt.show() + + Note that the covariance matrix must be positive semidefinite (a.k.a. + nonnegative-definite). Otherwise, the behavior of this method is + undefined and backwards compatibility is not guaranteed. + + References + ---------- + .. [1] Papoulis, A., "Probability, Random Variables, and Stochastic + Processes," 3rd ed., New York: McGraw-Hill, 1991. + .. [2] Duda, R. O., Hart, P. E., and Stork, D. G., "Pattern + Classification," 2nd ed., New York: Wiley, 2001. + + Examples + -------- + >>> mean = (1, 2) + >>> cov = [[1, 0], [0, 1]] + >>> x = np.random.multivariate_normal(mean, cov, (3, 3)) + >>> x.shape + (3, 3, 2) + + The following is probably true, given that 0.6 is roughly twice the + standard deviation: + + >>> list((x[0,0,:] - mean) < 0.6) + [True, True] + + """ + from numpy.dual import svd + + # Check preconditions on arguments + mean = np.array(mean) + cov = np.array(cov) + if size is None: + shape = [] + elif isinstance(size, (int, long, np.integer)): + shape = [size] + else: + shape = size + + if len(mean.shape) != 1: + raise ValueError("mean must be 1 dimensional") + if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): + raise ValueError("cov must be 2 dimensional and square") + if mean.shape[0] != cov.shape[0]: + raise ValueError("mean and cov must have same length") + + # Compute shape of output and create a matrix of independent + # standard normally distributed random numbers. The matrix has rows + # with the same length as mean and as many rows are necessary to + # form a matrix of shape final_shape. + final_shape = list(shape[:]) + final_shape.append(mean.shape[0]) + x = self.standard_normal(final_shape).reshape(-1, mean.shape[0]) + + # Transform matrix of standard normals into matrix where each row + # contains multivariate normals with the desired covariance. + # Compute A such that dot(transpose(A),A) == cov. + # Then the matrix products of the rows of x and A has the desired + # covariance. Note that sqrt(s)*v where (u,s,v) is the singular value + # decomposition of cov is such an A. + # + # Also check that cov is positive-semidefinite. If so, the u.T and v + # matrices should be equal up to roundoff error if cov is + # symmetrical and the singular value of the corresponding row is + # not zero. We continue to use the SVD rather than Cholesky in + # order to preserve current outputs. Note that symmetry has not + # been checked. + + (u, s, v) = svd(cov) + + if check_valid != 'ignore': + if check_valid != 'warn' and check_valid != 'raise': + raise ValueError("check_valid must equal 'warn', 'raise', or 'ignore'") + + psd = np.allclose(np.dot(v.T * s, v), cov, rtol=tol, atol=tol) + if not psd: + if check_valid == 'warn': + warnings.warn("covariance is not positive-semidefinite.", + RuntimeWarning) + else: + raise ValueError("covariance is not positive-semidefinite.") + + x = np.dot(x, np.sqrt(s)[:, None] * v) + x += mean + x.shape = tuple(final_shape) + return x + + def multinomial(self, npy_intp n, object pvals, size=None): + """ + multinomial(n, pvals, size=None) + + Draw samples from a multinomial distribution. + + The multinomial distribution is a multivariate generalisation of the + binomial distribution. Take an experiment with one of ``p`` + possible outcomes. An example of such an experiment is throwing a dice, + where the outcome can be 1 through 6. Each sample drawn from the + distribution represents `n` such experiments. Its values, + ``X_i = [X_0, X_1, ..., X_p]``, represent the number of times the + outcome was ``i``. + + Parameters + ---------- + n : int + Number of experiments. + pvals : sequence of floats, length p + Probabilities of each of the ``p`` different outcomes. These + should sum to 1 (however, the last element is always assumed to + account for the remaining probability, as long as + ``sum(pvals[:-1]) <= 1)``. + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + out : ndarray + The drawn samples, of shape *size*, if that was provided. If not, + the shape is ``(N,)``. + + In other words, each entry ``out[i,j,...,:]`` is an N-dimensional + value drawn from the distribution. + + Examples + -------- + Throw a dice 20 times: + + >>> np.random.multinomial(20, [1/6.]*6, size=1) + array([[4, 1, 7, 5, 2, 1]]) + + It landed 4 times on 1, once on 2, etc. + + Now, throw the dice 20 times, and 20 times again: + + >>> np.random.multinomial(20, [1/6.]*6, size=2) + array([[3, 4, 3, 3, 4, 3], + [2, 4, 3, 4, 0, 7]]) + + For the first run, we threw 3 times 1, 4 times 2, etc. For the second, + we threw 2 times 1, 4 times 2, etc. + + A loaded die is more likely to land on number 6: + + >>> np.random.multinomial(100, [1/7.]*5 + [2/7.]) + array([11, 16, 14, 17, 16, 26]) + + The probability inputs should be normalized. As an implementation + detail, the value of the last entry is ignored and assumed to take + up any leftover probability mass, but this should not be relied on. + A biased coin which has twice as much weight on one side as on the + other should be sampled like so: + + >>> np.random.multinomial(100, [1.0 / 3, 2.0 / 3]) # RIGHT + array([38, 62]) + + not like: + + >>> np.random.multinomial(100, [1.0, 2.0]) # WRONG + array([100, 0]) + + """ + cdef npy_intp d + cdef ndarray parr "arrayObject_parr", mnarr "arrayObject_mnarr" + cdef double *pix + cdef long *mnix + cdef npy_intp i, j, dn, sz + cdef double Sum + + d = len(pvals) + parr = PyArray_ContiguousFromObject(pvals, NPY_DOUBLE, 1, 1) + pix = PyArray_DATA(parr) + + if kahan_sum(pix, d-1) > (1.0 + 1e-12): + raise ValueError("sum(pvals[:-1]) > 1.0") + + shape = _shape_from_size(size, d) + + multin = np.zeros(shape, int) + mnarr = multin + mnix = PyArray_DATA(mnarr) + sz = PyArray_SIZE(mnarr) + with self.lock, nogil, cython.cdivision(True): + i = 0 + while i < sz: + Sum = 1.0 + dn = n + for j from 0 <= j < d-1: + mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum) + dn = dn - mnix[i+j] + if dn <= 0: + break + Sum = Sum - pix[j] + if dn > 0: + mnix[i+d-1] = dn + + i = i + d + + return multin + + def dirichlet(self, object alpha, size=None): + """ + dirichlet(alpha, size=None) + + Draw samples from the Dirichlet distribution. + + Draw `size` samples of dimension k from a Dirichlet distribution. A + Dirichlet-distributed random variable can be seen as a multivariate + generalization of a Beta distribution. Dirichlet pdf is the conjugate + prior of a multinomial in Bayesian inference. + + Parameters + ---------- + alpha : array + Parameter of the distribution (k dimension for sample of + dimension k). + size : int or tuple of ints, optional + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + + Returns + ------- + samples : ndarray, + The drawn samples, of shape (size, alpha.ndim). + + Raises + ------- + ValueError + If any value in alpha is less than or equal to zero + + Notes + ----- + .. math:: X \\approx \\prod_{i=1}^{k}{x^{\\alpha_i-1}_i} + + Uses the following property for computation: for each dimension, + draw a random sample y_i from a standard gamma generator of shape + `alpha_i`, then + :math:`X = \\frac{1}{\\sum_{i=1}^k{y_i}} (y_1, \\ldots, y_n)` is + Dirichlet distributed. + + References + ---------- + .. [1] David McKay, "Information Theory, Inference and Learning + Algorithms," chapter 23, + http://www.inference.phy.cam.ac.uk/mackay/ + .. [2] Wikipedia, "Dirichlet distribution", + http://en.wikipedia.org/wiki/Dirichlet_distribution + + Examples + -------- + Taking an example cited in Wikipedia, this distribution can be used if + one wanted to cut strings (each of initial length 1.0) into K pieces + with different lengths, where each piece had, on average, a designated + average length, but allowing some variation in the relative sizes of + the pieces. + + >>> s = np.random.dirichlet((10, 5, 3), 20).transpose() + + >>> plt.barh(range(20), s[0]) + >>> plt.barh(range(20), s[1], left=s[0], color='g') + >>> plt.barh(range(20), s[2], left=s[0]+s[1], color='r') + >>> plt.title("Lengths of Strings") + + """ + + #================= + # Pure python algo + #================= + #alpha = N.atleast_1d(alpha) + #k = alpha.size + + #if n == 1: + # val = N.zeros(k) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val) + #else: + # val = N.zeros((k, n)) + # for i in range(k): + # val[i] = sgamma(alpha[i], n) + # val /= N.sum(val, axis = 0) + # val = val.T + + #return val + + cdef npy_intp k + cdef npy_intp totsize + cdef ndarray alpha_arr, val_arr + cdef double *alpha_data + cdef double *val_data + cdef npy_intp i, j + cdef double acc, invacc + + k = len(alpha) + alpha_arr = PyArray_ContiguousFromObject(alpha, NPY_DOUBLE, 1, 1) + if np.any(np.less_equal(alpha_arr, 0)): + raise ValueError('alpha <= 0') + alpha_data = PyArray_DATA(alpha_arr) + + shape = _shape_from_size(size, k) + + diric = np.zeros(shape, np.float64) + val_arr = diric + val_data= PyArray_DATA(val_arr) + + i = 0 + totsize = PyArray_SIZE(val_arr) + with self.lock, nogil: + while i < totsize: + acc = 0.0 + for j from 0 <= j < k: + val_data[i+j] = rk_standard_gamma(self.internal_state, + alpha_data[j]) + acc = acc + val_data[i+j] + invacc = 1/acc + for j from 0 <= j < k: + val_data[i+j] = val_data[i+j] * invacc + i = i + k + + return diric + + # Shuffling and permutations: + def shuffle(self, object x): + """ + shuffle(x) + + Modify a sequence in-place by shuffling its contents. + + This function only shuffles the array along the first axis of a + multi-dimensional array. The order of sub-arrays is changed but + their contents remains the same. + + Parameters + ---------- + x : array_like + The array or list to be shuffled. + + Returns + ------- + None + + Examples + -------- + >>> arr = np.arange(10) + >>> np.random.shuffle(arr) + >>> arr + [1 7 5 2 9 4 3 6 0 8] + + Multi-dimensional arrays are only shuffled along the first axis: + + >>> arr = np.arange(9).reshape((3, 3)) + >>> np.random.shuffle(arr) + >>> arr + array([[3, 4, 5], + [6, 7, 8], + [0, 1, 2]]) + + """ + cdef: + npy_intp i, j, n = len(x), stride, itemsize + char* x_ptr + char* buf_ptr + + if type(x) is np.ndarray and x.ndim == 1 and x.size: + # Fast, statically typed path: shuffle the underlying buffer. + # Only for non-empty, 1d objects of class ndarray (subclasses such + # as MaskedArrays may not support this approach). + x_ptr = x.ctypes.data + stride = x.strides[0] + itemsize = x.dtype.itemsize + # As the array x could contain python objects we use a buffer + # of bytes for the swaps to avoid leaving one of the objects + # within the buffer and erroneously decrementing it's refcount + # when the function exits. + buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit + buf_ptr = buf.ctypes.data + with self.lock: + # We trick gcc into providing a specialized implementation for + # the most common case, yielding a ~33% performance improvement. + # Note that apparently, only one branch can ever be specialized. + if itemsize == sizeof(npy_intp): + self._shuffle_raw(n, sizeof(npy_intp), stride, x_ptr, buf_ptr) + else: + self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr) + elif isinstance(x, np.ndarray) and x.ndim > 1 and x.size: + # Multidimensional ndarrays require a bounce buffer. + buf = np.empty_like(x[0]) + with self.lock: + for i in reversed(range(1, n)): + j = rk_interval(i, self.internal_state) + buf[...] = x[j] + x[j] = x[i] + x[i] = buf + else: + # Untyped path. + with self.lock: + for i in reversed(range(1, n)): + j = rk_interval(i, self.internal_state) + x[i], x[j] = x[j], x[i] + + cdef inline _shuffle_raw(self, npy_intp n, npy_intp itemsize, + npy_intp stride, char* data, char* buf): + cdef npy_intp i, j + for i in reversed(range(1, n)): + j = rk_interval(i, self.internal_state) + if i == j : continue # i == j is not needed and memcpy is undefined. + string.memcpy(buf, data + j * stride, itemsize) + string.memcpy(data + j * stride, data + i * stride, itemsize) + string.memcpy(data + i * stride, buf, itemsize) + + def permutation(self, object x): + """ + permutation(x) + + Randomly permute a sequence, or return a permuted range. + + If `x` is a multi-dimensional array, it is only shuffled along its + first index. + + Parameters + ---------- + x : int or array_like + If `x` is an integer, randomly permute ``np.arange(x)``. + If `x` is an array, make a copy and shuffle the elements + randomly. + + Returns + ------- + out : ndarray + Permuted sequence or array range. + + Examples + -------- + >>> np.random.permutation(10) + array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) + + >>> np.random.permutation([1, 4, 9, 12, 15]) + array([15, 1, 9, 4, 12]) + + >>> arr = np.arange(9).reshape((3, 3)) + >>> np.random.permutation(arr) + array([[6, 7, 8], + [0, 1, 2], + [3, 4, 5]]) + + """ + if isinstance(x, (int, long, np.integer)): + arr = np.arange(x) + else: + arr = np.array(x) + self.shuffle(arr) + return arr + +_rand = RandomState() +seed = _rand.seed +get_state = _rand.get_state +set_state = _rand.set_state +random_sample = _rand.random_sample +choice = _rand.choice +randint = _rand.randint +bytes = _rand.bytes +uniform = _rand.uniform +rand = _rand.rand +randn = _rand.randn +random_integers = _rand.random_integers +standard_normal = _rand.standard_normal +normal = _rand.normal +beta = _rand.beta +exponential = _rand.exponential +standard_exponential = _rand.standard_exponential +standard_gamma = _rand.standard_gamma +gamma = _rand.gamma +f = _rand.f +noncentral_f = _rand.noncentral_f +chisquare = _rand.chisquare +noncentral_chisquare = _rand.noncentral_chisquare +standard_cauchy = _rand.standard_cauchy +standard_t = _rand.standard_t +vonmises = _rand.vonmises +pareto = _rand.pareto +weibull = _rand.weibull +power = _rand.power +laplace = _rand.laplace +gumbel = _rand.gumbel +logistic = _rand.logistic +lognormal = _rand.lognormal +rayleigh = _rand.rayleigh +wald = _rand.wald +triangular = _rand.triangular + +binomial = _rand.binomial +negative_binomial = _rand.negative_binomial +poisson = _rand.poisson +zipf = _rand.zipf +geometric = _rand.geometric +hypergeometric = _rand.hypergeometric +logseries = _rand.logseries + +multivariate_normal = _rand.multivariate_normal +multinomial = _rand.multinomial +dirichlet = _rand.dirichlet + +shuffle = _rand.shuffle +permutation = _rand.permutation diff --git a/numpy/random/mtrand/mtrand_py_helper.h b/numpy/random/mtrand/mtrand_py_helper.h new file mode 100644 index 0000000..266847c --- /dev/null +++ b/numpy/random/mtrand/mtrand_py_helper.h @@ -0,0 +1,23 @@ +#ifndef _MTRAND_PY_HELPER_H_ +#define _MTRAND_PY_HELPER_H_ + +#include + +static PyObject *empty_py_bytes(npy_intp length, void **bytes) +{ + PyObject *b; +#if PY_MAJOR_VERSION >= 3 + b = PyBytes_FromStringAndSize(NULL, length); + if (b) { + *bytes = PyBytes_AS_STRING(b); + } +#else + b = PyString_FromStringAndSize(NULL, length); + if (b) { + *bytes = PyString_AS_STRING(b); + } +#endif + return b; +} + +#endif /* _MTRAND_PY_HELPER_H_ */ diff --git a/numpy/random/mtrand/numpy.pxd b/numpy/random/mtrand/numpy.pxd new file mode 100644 index 0000000..9092fa1 --- /dev/null +++ b/numpy/random/mtrand/numpy.pxd @@ -0,0 +1,163 @@ +# :Author: Travis Oliphant +from cpython.exc cimport PyErr_Print + +cdef extern from "numpy/npy_no_deprecated_api.h": pass + +cdef extern from "numpy/arrayobject.h": + + cdef enum NPY_TYPES: + NPY_BOOL + NPY_BYTE + NPY_UBYTE + NPY_SHORT + NPY_USHORT + NPY_INT + NPY_UINT + NPY_LONG + NPY_ULONG + NPY_LONGLONG + NPY_ULONGLONG + NPY_FLOAT + NPY_DOUBLE + NPY_LONGDOUBLE + NPY_CFLOAT + NPY_CDOUBLE + NPY_CLONGDOUBLE + NPY_OBJECT + NPY_STRING + NPY_UNICODE + NPY_VOID + NPY_NTYPES + NPY_NOTYPE + + cdef enum requirements: + NPY_ARRAY_C_CONTIGUOUS + NPY_ARRAY_F_CONTIGUOUS + NPY_ARRAY_OWNDATA + NPY_ARRAY_FORCECAST + NPY_ARRAY_ENSURECOPY + NPY_ARRAY_ENSUREARRAY + NPY_ARRAY_ELEMENTSTRIDES + NPY_ARRAY_ALIGNED + NPY_ARRAY_NOTSWAPPED + NPY_ARRAY_WRITEABLE + NPY_ARRAY_WRITEBACKIFCOPY + NPY_ARR_HAS_DESCR + + NPY_ARRAY_BEHAVED + NPY_ARRAY_BEHAVED_NS + NPY_ARRAY_CARRAY + NPY_ARRAY_CARRAY_RO + NPY_ARRAY_FARRAY + NPY_ARRAY_FARRAY_RO + NPY_ARRAY_DEFAULT + + NPY_ARRAY_IN_ARRAY + NPY_ARRAY_OUT_ARRAY + NPY_ARRAY_INOUT_ARRAY + NPY_ARRAY_IN_FARRAY + NPY_ARRAY_OUT_FARRAY + NPY_ARRAY_INOUT_FARRAY + + NPY_ARRAY_UPDATE_ALL + + cdef enum defines: + NPY_MAXDIMS + + ctypedef struct npy_cdouble: + double real + double imag + + ctypedef struct npy_cfloat: + double real + double imag + + ctypedef int npy_int + ctypedef int npy_intp + ctypedef int npy_int64 + ctypedef int npy_uint64 + ctypedef int npy_int32 + ctypedef int npy_uint32 + ctypedef int npy_int16 + ctypedef int npy_uint16 + ctypedef int npy_int8 + ctypedef int npy_uint8 + ctypedef int npy_bool + + ctypedef extern class numpy.dtype [object PyArray_Descr]: pass + + ctypedef extern class numpy.ndarray [object PyArrayObject]: pass + + ctypedef extern class numpy.flatiter [object PyArrayIterObject]: + cdef int nd_m1 + cdef npy_intp index, size + cdef ndarray ao + cdef char *dataptr + + ctypedef extern class numpy.broadcast [object PyArrayMultiIterObject]: + cdef int numiter + cdef npy_intp size, index + cdef int nd + cdef npy_intp *dimensions + cdef void **iters + + object PyArray_ZEROS(int ndims, npy_intp* dims, NPY_TYPES type_num, int fortran) + object PyArray_EMPTY(int ndims, npy_intp* dims, NPY_TYPES type_num, int fortran) + dtype PyArray_DescrFromTypeNum(NPY_TYPES type_num) + object PyArray_SimpleNew(int ndims, npy_intp* dims, NPY_TYPES type_num) + int PyArray_Check(object obj) + object PyArray_ContiguousFromAny(object obj, NPY_TYPES type, + int mindim, int maxdim) + object PyArray_ContiguousFromObject(object obj, NPY_TYPES type, + int mindim, int maxdim) + npy_intp PyArray_SIZE(ndarray arr) + npy_intp PyArray_NBYTES(ndarray arr) + object PyArray_FromAny(object obj, dtype newtype, int mindim, int maxdim, + int requirements, object context) + object PyArray_FROMANY(object obj, NPY_TYPES type_num, int min, + int max, int requirements) + object PyArray_NewFromDescr(object subtype, dtype newtype, int nd, + npy_intp* dims, npy_intp* strides, void* data, + int flags, object parent) + + object PyArray_FROM_OTF(object obj, NPY_TYPES type, int flags) + object PyArray_EnsureArray(object) + + object PyArray_MultiIterNew(int n, ...) + + char *PyArray_MultiIter_DATA(broadcast multi, int i) nogil + void PyArray_MultiIter_NEXTi(broadcast multi, int i) nogil + void PyArray_MultiIter_NEXT(broadcast multi) nogil + + object PyArray_IterNew(object arr) + void PyArray_ITER_NEXT(flatiter it) nogil + void* PyArray_ITER_DATA(flatiter it) nogil + + dtype PyArray_DescrFromType(int) + + int _import_array() except -1 + +# include functions that were once macros in the new api + + int PyArray_NDIM(ndarray arr) + char * PyArray_DATA(ndarray arr) + npy_intp * PyArray_DIMS(ndarray arr) + npy_intp * PyArray_STRIDES(ndarray arr) + npy_intp PyArray_DIM(ndarray arr, int idim) + npy_intp PyArray_STRIDE(ndarray arr, int istride) + object PyArray_BASE(ndarray arr) + dtype PyArray_DESCR(ndarray arr) + int PyArray_FLAGS(ndarray arr) + npy_intp PyArray_ITEMSIZE(ndarray arr) + int PyArray_TYPE(ndarray arr) + int PyArray_CHKFLAGS(ndarray arr, int flags) + object PyArray_GETITEM(ndarray arr, char *itemptr) + + +# copied from cython version with addition of PyErr_Print. +cdef inline int import_array() except -1: + try: + _import_array() + except Exception: + PyErr_Print() + raise ImportError("numpy.core.multiarray failed to import") diff --git a/numpy/random/mtrand/randint_helpers.pxi b/numpy/random/mtrand/randint_helpers.pxi new file mode 100644 index 0000000..36ee254 --- /dev/null +++ b/numpy/random/mtrand/randint_helpers.pxi @@ -0,0 +1,462 @@ +""" +Template for each `dtype` helper function in `np.random.randint`. +""" + +def _rand_bool(low, high, size, rngstate): + """ + _rand_bool(low, high, size, rngstate) + + Return random np.bool_ integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.bool_ type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.bool_ + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_bool off, rng, buf + cdef npy_bool *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_bool(off, rng, 1, &buf, state) + return np.bool_(buf) + else: + array = np.empty(size, np.bool_) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_bool(off, rng, cnt, array_data, state) + return array + +def _rand_int8(low, high, size, rngstate): + """ + _rand_int8(low, high, size, rngstate) + + Return random np.int8 integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.int8 type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.int8 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_uint8 off, rng, buf + cdef npy_uint8 *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_uint8(off, rng, 1, &buf, state) + return np.int8(buf) + else: + array = np.empty(size, np.int8) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_uint8(off, rng, cnt, array_data, state) + return array + +def _rand_int16(low, high, size, rngstate): + """ + _rand_int16(low, high, size, rngstate) + + Return random np.int16 integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.int16 type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.int16 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_uint16 off, rng, buf + cdef npy_uint16 *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_uint16(off, rng, 1, &buf, state) + return np.int16(buf) + else: + array = np.empty(size, np.int16) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_uint16(off, rng, cnt, array_data, state) + return array + +def _rand_int32(low, high, size, rngstate): + """ + _rand_int32(low, high, size, rngstate) + + Return random np.int32 integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.int32 type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.int32 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_uint32 off, rng, buf + cdef npy_uint32 *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_uint32(off, rng, 1, &buf, state) + return np.int32(buf) + else: + array = np.empty(size, np.int32) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_uint32(off, rng, cnt, array_data, state) + return array + +def _rand_int64(low, high, size, rngstate): + """ + _rand_int64(low, high, size, rngstate) + + Return random np.int64 integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.int64 type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.int64 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_uint64 off, rng, buf + cdef npy_uint64 *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_uint64(off, rng, 1, &buf, state) + return np.int64(buf) + else: + array = np.empty(size, np.int64) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_uint64(off, rng, cnt, array_data, state) + return array + +def _rand_uint8(low, high, size, rngstate): + """ + _rand_uint8(low, high, size, rngstate) + + Return random np.uint8 integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.uint8 type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.uint8 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_uint8 off, rng, buf + cdef npy_uint8 *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_uint8(off, rng, 1, &buf, state) + return np.uint8(buf) + else: + array = np.empty(size, np.uint8) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_uint8(off, rng, cnt, array_data, state) + return array + +def _rand_uint16(low, high, size, rngstate): + """ + _rand_uint16(low, high, size, rngstate) + + Return random np.uint16 integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.uint16 type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.uint16 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_uint16 off, rng, buf + cdef npy_uint16 *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_uint16(off, rng, 1, &buf, state) + return np.uint16(buf) + else: + array = np.empty(size, np.uint16) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_uint16(off, rng, cnt, array_data, state) + return array + +def _rand_uint32(low, high, size, rngstate): + """ + _rand_uint32(low, high, size, rngstate) + + Return random np.uint32 integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.uint32 type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.uint32 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_uint32 off, rng, buf + cdef npy_uint32 *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_uint32(off, rng, 1, &buf, state) + return np.uint32(buf) + else: + array = np.empty(size, np.uint32) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_uint32(off, rng, cnt, array_data, state) + return array + +def _rand_uint64(low, high, size, rngstate): + """ + _rand_uint64(low, high, size, rngstate) + + Return random np.uint64 integers between ``low`` and ``high``, inclusive. + + Return random integers from the "discrete uniform" distribution in the + closed interval [``low``, ``high``). On entry the arguments are presumed + to have been validated for size and order for the np.uint64 type. + + Parameters + ---------- + low : int + Lowest (signed) integer to be drawn from the distribution. + high : int + Highest (signed) integer to be drawn from the distribution. + size : int or tuple of ints + Output shape. If the given shape is, e.g., ``(m, n, k)``, then + ``m * n * k`` samples are drawn. Default is None, in which case a + single value is returned. + rngstate : encapsulated pointer to rk_state + The specific type depends on the python version. In Python 2 it is + a PyCObject, in Python 3 a PyCapsule object. + + Returns + ------- + out : python integer or ndarray of np.uint64 + `size`-shaped array of random integers from the appropriate + distribution, or a single such random int if `size` not provided. + + """ + cdef npy_uint64 off, rng, buf + cdef npy_uint64 *out + cdef ndarray array "arrayObject" + cdef npy_intp cnt + cdef rk_state *state = PyCapsule_GetPointer(rngstate, NULL) + + rng = (high - low) + off = (low) + + if size is None: + rk_random_uint64(off, rng, 1, &buf, state) + return np.uint64(buf) + else: + array = np.empty(size, np.uint64) + cnt = PyArray_SIZE(array) + array_data = PyArray_DATA(array) + with nogil: + rk_random_uint64(off, rng, cnt, array_data, state) + return array diff --git a/numpy/random/mtrand/randomkit.c b/numpy/random/mtrand/randomkit.c new file mode 100644 index 0000000..3809171 --- /dev/null +++ b/numpy/random/mtrand/randomkit.c @@ -0,0 +1,626 @@ +/* Random kit 1.3 */ + +/* + * Copyright (c) 2003-2005, Jean-Sebastien Roy (js@jeannot.org) + * + * The rk_random and rk_seed functions algorithms and the original design of + * the Mersenne Twister RNG: + * + * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original algorithm for the implementation of rk_interval function from + * Richard J. Wagner's implementation of the Mersenne Twister RNG, optimised by + * Magnus Jonsson. + * + * Constants used in the rk_double implementation by Isaku Wada. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* static char const rcsid[] = + "@(#) $Jeannot: randomkit.c,v 1.28 2005/07/21 22:14:09 js Exp $"; */ + +#ifdef _WIN32 +/* + * Windows + * XXX: we have to use this ugly defined(__GNUC__) because it is not easy to + * detect the compiler used in distutils itself + */ +#if (defined(__GNUC__) && defined(NPY_NEEDS_MINGW_TIME_WORKAROUND)) + +/* + * FIXME: ideally, we should set this to the real version of MSVCRT. We need + * something higher than 0x601 to enable _ftime64 and co + */ +#define __MSVCRT_VERSION__ 0x0700 +#include +#include + +/* + * mingw msvcr lib import wrongly export _ftime, which does not exist in the + * actual msvc runtime for version >= 8; we make it an alias to _ftime64, which + * is available in those versions of the runtime + */ +#define _FTIME(x) _ftime64((x)) +#else +#include +#include +#define _FTIME(x) _ftime((x)) +#endif + +#ifndef RK_NO_WINCRYPT +/* Windows crypto */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#include +#include +#endif + +/* + * Do not move this include. randomkit.h must be included + * after windows timeb.h is included. + */ +#include "randomkit.h" + +#else +/* Unix */ +#include "randomkit.h" +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifndef RK_DEV_URANDOM +#define RK_DEV_URANDOM "/dev/urandom" +#endif + +#ifndef RK_DEV_RANDOM +#define RK_DEV_RANDOM "/dev/random" +#endif + +char *rk_strerror[RK_ERR_MAX] = +{ + "no error", + "random device unvavailable" +}; + +/* static functions */ +static unsigned long rk_hash(unsigned long key); + +void +rk_seed(unsigned long seed, rk_state *state) +{ + int pos; + seed &= 0xffffffffUL; + + /* Knuth's PRNG as used in the Mersenne Twister reference implementation */ + for (pos = 0; pos < RK_STATE_LEN; pos++) { + state->key[pos] = seed; + seed = (1812433253UL * (seed ^ (seed >> 30)) + pos + 1) & 0xffffffffUL; + } + state->pos = RK_STATE_LEN; + state->gauss = 0; + state->has_gauss = 0; + state->has_binomial = 0; +} + +/* Thomas Wang 32 bits integer hash function */ +unsigned long +rk_hash(unsigned long key) +{ + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return key; +} + +rk_error +rk_randomseed(rk_state *state) +{ +#ifndef _WIN32 + struct timeval tv; +#else + struct _timeb tv; +#endif + int i; + + if (rk_devfill(state->key, sizeof(state->key), 0) == RK_NOERR) { + /* ensures non-zero key */ + state->key[0] |= 0x80000000UL; + state->pos = RK_STATE_LEN; + state->gauss = 0; + state->has_gauss = 0; + state->has_binomial = 0; + + for (i = 0; i < 624; i++) { + state->key[i] &= 0xffffffffUL; + } + return RK_NOERR; + } + +#ifndef _WIN32 + gettimeofday(&tv, NULL); + rk_seed(rk_hash(getpid()) ^ rk_hash(tv.tv_sec) ^ rk_hash(tv.tv_usec) + ^ rk_hash(clock()), state); +#else + _FTIME(&tv); + rk_seed(rk_hash(tv.time) ^ rk_hash(tv.millitm) ^ rk_hash(clock()), state); +#endif + + return RK_ENODEV; +} + +/* Magic Mersenne Twister constants */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL +#define UPPER_MASK 0x80000000UL +#define LOWER_MASK 0x7fffffffUL + +/* + * Slightly optimised reference implementation of the Mersenne Twister + * Note that regardless of the precision of long, only 32 bit random + * integers are produced + */ +unsigned long +rk_random(rk_state *state) +{ + unsigned long y; + + if (state->pos == RK_STATE_LEN) { + int i; + + for (i = 0; i < N - M; i++) { + y = (state->key[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); + state->key[i] = state->key[i+M] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); + } + for (; i < N - 1; i++) { + y = (state->key[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); + state->key[i] = state->key[i+(M-N)] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); + } + y = (state->key[N - 1] & UPPER_MASK) | (state->key[0] & LOWER_MASK); + state->key[N - 1] = state->key[M - 1] ^ (y >> 1) ^ (-(y & 1) & MATRIX_A); + + state->pos = 0; + } + y = state->key[state->pos++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + + +/* + * Returns an unsigned 64 bit random integer. + */ +NPY_INLINE static npy_uint64 +rk_uint64(rk_state *state) +{ + npy_uint64 upper = (npy_uint64)rk_random(state) << 32; + npy_uint64 lower = (npy_uint64)rk_random(state); + return upper | lower; +} + + +/* + * Returns an unsigned 32 bit random integer. + */ +NPY_INLINE static npy_uint32 +rk_uint32(rk_state *state) +{ + return (npy_uint32)rk_random(state); +} + + +/* + * Fills an array with cnt random npy_uint64 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void +rk_random_uint64(npy_uint64 off, npy_uint64 rng, npy_intp cnt, + npy_uint64 *out, rk_state *state) +{ + npy_uint64 val, mask = rng; + npy_intp i; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + mask |= mask >> 32; + + for (i = 0; i < cnt; i++) { + if (rng <= 0xffffffffUL) { + while ((val = (rk_uint32(state) & mask)) > rng); + } + else { + while ((val = (rk_uint64(state) & mask)) > rng); + } + out[i] = off + val; + } +} + + +/* + * Fills an array with cnt random npy_uint32 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void +rk_random_uint32(npy_uint32 off, npy_uint32 rng, npy_intp cnt, + npy_uint32 *out, rk_state *state) +{ + npy_uint32 val, mask = rng; + npy_intp i; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + + for (i = 0; i < cnt; i++) { + while ((val = (rk_uint32(state) & mask)) > rng); + out[i] = off + val; + } +} + + +/* + * Fills an array with cnt random npy_uint16 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void +rk_random_uint16(npy_uint16 off, npy_uint16 rng, npy_intp cnt, + npy_uint16 *out, rk_state *state) +{ + npy_uint16 val, mask = rng; + npy_intp i; + npy_uint32 buf; + int bcnt = 0; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + + for (i = 0; i < cnt; i++) { + do { + if (!bcnt) { + buf = rk_uint32(state); + bcnt = 1; + } + else { + buf >>= 16; + bcnt--; + } + val = (npy_uint16)buf & mask; + } while (val > rng); + out[i] = off + val; + } +} + + +/* + * Fills an array with cnt random npy_uint8 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +void +rk_random_uint8(npy_uint8 off, npy_uint8 rng, npy_intp cnt, + npy_uint8 *out, rk_state *state) +{ + npy_uint8 val, mask = rng; + npy_intp i; + npy_uint32 buf; + int bcnt = 0; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + + for (i = 0; i < cnt; i++) { + do { + if (!bcnt) { + buf = rk_uint32(state); + bcnt = 3; + } + else { + buf >>= 8; + bcnt--; + } + val = (npy_uint8)buf & mask; + } while (val > rng); + out[i] = off + val; + } +} + + +/* + * Fills an array with cnt random npy_bool between off and off + rng + * inclusive. + */ +void +rk_random_bool(npy_bool off, npy_bool rng, npy_intp cnt, + npy_bool *out, rk_state *state) +{ + npy_intp i; + npy_uint32 buf; + int bcnt = 0; + + if (rng == 0) { + for (i = 0; i < cnt; i++) { + out[i] = off; + } + return; + } + + /* If we reach here rng and mask are one and off is zero */ + assert(rng == 1 && off == 0); + for (i = 0; i < cnt; i++) { + if (!bcnt) { + buf = rk_uint32(state); + bcnt = 31; + } + else { + buf >>= 1; + bcnt--; + } + out[i] = (buf & 0x00000001) != 0; + } +} + + +long +rk_long(rk_state *state) +{ + return rk_ulong(state) >> 1; +} + +unsigned long +rk_ulong(rk_state *state) +{ +#if ULONG_MAX <= 0xffffffffUL + return rk_random(state); +#else + return (rk_random(state) << 32) | (rk_random(state)); +#endif +} + +unsigned long +rk_interval(unsigned long max, rk_state *state) +{ + unsigned long mask = max, value; + + if (max == 0) { + return 0; + } + /* Smallest bit mask >= max */ + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; +#if ULONG_MAX > 0xffffffffUL + mask |= mask >> 32; +#endif + + /* Search a random value in [0..mask] <= max */ +#if ULONG_MAX > 0xffffffffUL + if (max <= 0xffffffffUL) { + while ((value = (rk_random(state) & mask)) > max); + } + else { + while ((value = (rk_ulong(state) & mask)) > max); + } +#else + while ((value = (rk_ulong(state) & mask)) > max); +#endif + return value; +} + +double +rk_double(rk_state *state) +{ + /* shifts : 67108864 = 0x4000000, 9007199254740992 = 0x20000000000000 */ + long a = rk_random(state) >> 5, b = rk_random(state) >> 6; + return (a * 67108864.0 + b) / 9007199254740992.0; +} + +void +rk_fill(void *buffer, size_t size, rk_state *state) +{ + unsigned long r; + unsigned char *buf = buffer; + + for (; size >= 4; size -= 4) { + r = rk_random(state); + *(buf++) = r & 0xFF; + *(buf++) = (r >> 8) & 0xFF; + *(buf++) = (r >> 16) & 0xFF; + *(buf++) = (r >> 24) & 0xFF; + } + + if (!size) { + return; + } + r = rk_random(state); + for (; size; r >>= 8, size --) { + *(buf++) = (unsigned char)(r & 0xFF); + } +} + +rk_error +rk_devfill(void *buffer, size_t size, int strong) +{ +#ifndef _WIN32 + FILE *rfile; + int done; + + if (strong) { + rfile = fopen(RK_DEV_RANDOM, "rb"); + } + else { + rfile = fopen(RK_DEV_URANDOM, "rb"); + } + if (rfile == NULL) { + return RK_ENODEV; + } + done = fread(buffer, size, 1, rfile); + fclose(rfile); + if (done) { + return RK_NOERR; + } +#else + +#ifndef RK_NO_WINCRYPT + HCRYPTPROV hCryptProv; + BOOL done; + + if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT) || !hCryptProv) { + return RK_ENODEV; + } + done = CryptGenRandom(hCryptProv, size, (unsigned char *)buffer); + CryptReleaseContext(hCryptProv, 0); + if (done) { + return RK_NOERR; + } +#endif + +#endif + return RK_ENODEV; +} + +rk_error +rk_altfill(void *buffer, size_t size, int strong, rk_state *state) +{ + rk_error err; + + err = rk_devfill(buffer, size, strong); + if (err) { + rk_fill(buffer, size, state); + } + return err; +} + +double +rk_gauss(rk_state *state) +{ + if (state->has_gauss) { + const double tmp = state->gauss; + state->gauss = 0; + state->has_gauss = 0; + return tmp; + } + else { + double f, x1, x2, r2; + + do { + x1 = 2.0*rk_double(state) - 1.0; + x2 = 2.0*rk_double(state) - 1.0; + r2 = x1*x1 + x2*x2; + } + while (r2 >= 1.0 || r2 == 0.0); + + /* Box-Muller transform */ + f = sqrt(-2.0*log(r2)/r2); + /* Keep for next call */ + state->gauss = f*x1; + state->has_gauss = 1; + return f*x2; + } +} diff --git a/numpy/random/mtrand/randomkit.h b/numpy/random/mtrand/randomkit.h new file mode 100644 index 0000000..fcdd606 --- /dev/null +++ b/numpy/random/mtrand/randomkit.h @@ -0,0 +1,226 @@ +/* Random kit 1.3 */ + +/* + * Copyright (c) 2003-2005, Jean-Sebastien Roy (js@jeannot.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* @(#) $Jeannot: randomkit.h,v 1.24 2005/07/21 22:14:09 js Exp $ */ + +/* + * Typical use: + * + * { + * rk_state state; + * unsigned long seed = 1, random_value; + * + * rk_seed(seed, &state); // Initialize the RNG + * ... + * random_value = rk_random(&state); // Generate random values in [0..RK_MAX] + * } + * + * Instead of rk_seed, you can use rk_randomseed which will get a random seed + * from /dev/urandom (or the clock, if /dev/urandom is unavailable): + * + * { + * rk_state state; + * unsigned long random_value; + * + * rk_randomseed(&state); // Initialize the RNG with a random seed + * ... + * random_value = rk_random(&state); // Generate random values in [0..RK_MAX] + * } + */ + +/* + * Useful macro: + * RK_DEV_RANDOM: the device used for random seeding. + * defaults to "/dev/urandom" + */ + +#ifndef _RANDOMKIT_ +#define _RANDOMKIT_ + +#include +#include + + +#define RK_STATE_LEN 624 + +typedef struct rk_state_ +{ + unsigned long key[RK_STATE_LEN]; + int pos; + int has_gauss; /* !=0: gauss contains a gaussian deviate */ + double gauss; + + /* The rk_state structure has been extended to store the following + * information for the binomial generator. If the input values of n or p + * are different than nsave and psave, then the other parameters will be + * recomputed. RTK 2005-09-02 */ + + int has_binomial; /* !=0: following parameters initialized for + binomial */ + double psave; + long nsave; + double r; + double q; + double fm; + long m; + double p1; + double xm; + double xl; + double xr; + double c; + double laml; + double lamr; + double p2; + double p3; + double p4; + +} +rk_state; + +typedef enum { + RK_NOERR = 0, /* no error */ + RK_ENODEV = 1, /* no RK_DEV_RANDOM device */ + RK_ERR_MAX = 2 +} rk_error; + +/* error strings */ +extern char *rk_strerror[RK_ERR_MAX]; + +/* Maximum generated random value */ +#define RK_MAX 0xFFFFFFFFUL + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Initialize the RNG state using the given seed. + */ +extern void rk_seed(unsigned long seed, rk_state *state); + +/* + * Initialize the RNG state using a random seed. + * Uses /dev/random or, when unavailable, the clock (see randomkit.c). + * Returns RK_NOERR when no errors occurs. + * Returns RK_ENODEV when the use of RK_DEV_RANDOM failed (for example because + * there is no such device). In this case, the RNG was initialized using the + * clock. + */ +extern rk_error rk_randomseed(rk_state *state); + +/* + * Returns a random unsigned long between 0 and RK_MAX inclusive + */ +extern unsigned long rk_random(rk_state *state); + +/* + * Returns a random long between 0 and LONG_MAX inclusive + */ +extern long rk_long(rk_state *state); + +/* + * Returns a random unsigned long between 0 and ULONG_MAX inclusive + */ +extern unsigned long rk_ulong(rk_state *state); + +/* + * Returns a random unsigned long between 0 and max inclusive. + */ +extern unsigned long rk_interval(unsigned long max, rk_state *state); + +/* + * Fills an array with cnt random npy_uint64 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +extern void rk_random_uint64(npy_uint64 off, npy_uint64 rng, npy_intp cnt, + npy_uint64 *out, rk_state *state); + +/* + * Fills an array with cnt random npy_uint32 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +extern void rk_random_uint32(npy_uint32 off, npy_uint32 rng, npy_intp cnt, + npy_uint32 *out, rk_state *state); + +/* + * Fills an array with cnt random npy_uint16 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +extern void rk_random_uint16(npy_uint16 off, npy_uint16 rng, npy_intp cnt, + npy_uint16 *out, rk_state *state); + +/* + * Fills an array with cnt random npy_uint8 between off and off + rng + * inclusive. The numbers wrap if rng is sufficiently large. + */ +extern void rk_random_uint8(npy_uint8 off, npy_uint8 rng, npy_intp cnt, + npy_uint8 *out, rk_state *state); + +/* + * Fills an array with cnt random npy_bool between off and off + rng + * inclusive. It is assumed tha npy_bool as the same size as npy_uint8. + */ +extern void rk_random_bool(npy_bool off, npy_bool rng, npy_intp cnt, + npy_bool *out, rk_state *state); + +/* + * Returns a random double between 0.0 and 1.0, 1.0 excluded. + */ +extern double rk_double(rk_state *state); + +/* + * fill the buffer with size random bytes + */ +extern void rk_fill(void *buffer, size_t size, rk_state *state); + +/* + * fill the buffer with randombytes from the random device + * Returns RK_ENODEV if the device is unavailable, or RK_NOERR if it is + * On Unix, if strong is defined, RK_DEV_RANDOM is used. If not, RK_DEV_URANDOM + * is used instead. This parameter has no effect on Windows. + * Warning: on most unixes RK_DEV_RANDOM will wait for enough entropy to answer + * which can take a very long time on quiet systems. + */ +extern rk_error rk_devfill(void *buffer, size_t size, int strong); + +/* + * fill the buffer using rk_devfill if the random device is available and using + * rk_fill if is is not + * parameters have the same meaning as rk_fill and rk_devfill + * Returns RK_ENODEV if the device is unavailable, or RK_NOERR if it is + */ +extern rk_error rk_altfill(void *buffer, size_t size, int strong, + rk_state *state); + +/* + * return a random gaussian deviate with variance unity and zero mean. + */ +extern double rk_gauss(rk_state *state); + +#ifdef __cplusplus +} +#endif + +#endif /* _RANDOMKIT_ */ diff --git a/numpy/random/setup.py b/numpy/random/setup.py new file mode 100644 index 0000000..3f3b773 --- /dev/null +++ b/numpy/random/setup.py @@ -0,0 +1,64 @@ +from __future__ import division, print_function + +from os.path import join, split, dirname +import os +import sys +from distutils.dep_util import newer +from distutils.msvccompiler import get_build_version as get_msvc_build_version + +def needs_mingw_ftime_workaround(): + # We need the mingw workaround for _ftime if the msvc runtime version is + # 7.1 or above and we build with mingw ... + # ... but we can't easily detect compiler version outside distutils command + # context, so we will need to detect in randomkit whether we build with gcc + msver = get_msvc_build_version() + if msver and msver >= 8: + return True + + return False + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration, get_mathlibs + config = Configuration('random', parent_package, top_path) + + def generate_libraries(ext, build_dir): + config_cmd = config.get_config_cmd() + libs = get_mathlibs() + if sys.platform == 'win32': + libs.append('Advapi32') + ext.libraries.extend(libs) + return None + + # enable unix large file support on 32 bit systems + # (64 bit off_t, lseek -> lseek64 etc.) + if sys.platform[:3] == "aix": + defs = [('_LARGE_FILES', None)] + else: + defs = [('_FILE_OFFSET_BITS', '64'), + ('_LARGEFILE_SOURCE', '1'), + ('_LARGEFILE64_SOURCE', '1')] + if needs_mingw_ftime_workaround(): + defs.append(("NPY_NEEDS_MINGW_TIME_WORKAROUND", None)) + + libs = [] + # Configure mtrand + config.add_extension('mtrand', + sources=[join('mtrand', x) for x in + ['mtrand.c', 'randomkit.c', 'initarray.c', + 'distributions.c']]+[generate_libraries], + libraries=libs, + depends=[join('mtrand', '*.h'), + join('mtrand', '*.pyx'), + join('mtrand', '*.pxi'),], + define_macros=defs, + ) + + config.add_data_files(('.', join('mtrand', 'randomkit.h'))) + config.add_data_dir('tests') + + return config + + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/random/tests/__init__.py b/numpy/random/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/random/tests/__init__.py diff --git a/numpy/random/tests/test_random.py b/numpy/random/tests/test_random.py new file mode 100644 index 0000000..6ada4d9 --- /dev/null +++ b/numpy/random/tests/test_random.py @@ -0,0 +1,1639 @@ +from __future__ import division, absolute_import, print_function +import warnings + +import numpy as np +from numpy.testing import ( + run_module_suite, assert_, assert_raises, assert_equal, assert_warns, + assert_no_warnings, assert_array_equal, assert_array_almost_equal, + suppress_warnings + ) +from numpy import random +import sys +import warnings + + +class TestSeed(object): + def test_scalar(self): + s = np.random.RandomState(0) + assert_equal(s.randint(1000), 684) + s = np.random.RandomState(4294967295) + assert_equal(s.randint(1000), 419) + + def test_array(self): + s = np.random.RandomState(range(10)) + assert_equal(s.randint(1000), 468) + s = np.random.RandomState(np.arange(10)) + assert_equal(s.randint(1000), 468) + s = np.random.RandomState([0]) + assert_equal(s.randint(1000), 973) + s = np.random.RandomState([4294967295]) + assert_equal(s.randint(1000), 265) + + def test_invalid_scalar(self): + # seed must be an unsigned 32 bit integer + assert_raises(TypeError, np.random.RandomState, -0.5) + assert_raises(ValueError, np.random.RandomState, -1) + + def test_invalid_array(self): + # seed must be an unsigned 32 bit integer + assert_raises(TypeError, np.random.RandomState, [-0.5]) + assert_raises(ValueError, np.random.RandomState, [-1]) + assert_raises(ValueError, np.random.RandomState, [4294967296]) + assert_raises(ValueError, np.random.RandomState, [1, 2, 4294967296]) + assert_raises(ValueError, np.random.RandomState, [1, -2, 4294967296]) + + def test_invalid_array_shape(self): + # gh-9832 + assert_raises(ValueError, np.random.RandomState, np.array([], dtype=np.int64)) + assert_raises(ValueError, np.random.RandomState, [[1, 2, 3]]) + assert_raises(ValueError, np.random.RandomState, [[1, 2, 3], + [4, 5, 6]]) + + +class TestBinomial(object): + def test_n_zero(self): + # Tests the corner case of n == 0 for the binomial distribution. + # binomial(0, p) should be zero for any p in [0, 1]. + # This test addresses issue #3480. + zeros = np.zeros(2, dtype='int') + for p in [0, .5, 1]: + assert_(random.binomial(0, p) == 0) + assert_array_equal(random.binomial(zeros, p), zeros) + + def test_p_is_nan(self): + # Issue #4571. + assert_raises(ValueError, random.binomial, 1, np.nan) + + +class TestMultinomial(object): + def test_basic(self): + random.multinomial(100, [0.2, 0.8]) + + def test_zero_probability(self): + random.multinomial(100, [0.2, 0.8, 0.0, 0.0, 0.0]) + + def test_int_negative_interval(self): + assert_(-5 <= random.randint(-5, -1) < -1) + x = random.randint(-5, -1, 5) + assert_(np.all(-5 <= x)) + assert_(np.all(x < -1)) + + def test_size(self): + # gh-3173 + p = [0.5, 0.5] + assert_equal(np.random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(np.random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(np.random.multinomial(1, p, np.uint32(1)).shape, (1, 2)) + assert_equal(np.random.multinomial(1, p, [2, 2]).shape, (2, 2, 2)) + assert_equal(np.random.multinomial(1, p, (2, 2)).shape, (2, 2, 2)) + assert_equal(np.random.multinomial(1, p, np.array((2, 2))).shape, + (2, 2, 2)) + + assert_raises(TypeError, np.random.multinomial, 1, p, + float(1)) + + +class TestSetState(object): + def setup(self): + self.seed = 1234567890 + self.prng = random.RandomState(self.seed) + self.state = self.prng.get_state() + + def test_basic(self): + old = self.prng.tomaxint(16) + self.prng.set_state(self.state) + new = self.prng.tomaxint(16) + assert_(np.all(old == new)) + + def test_gaussian_reset(self): + # Make sure the cached every-other-Gaussian is reset. + old = self.prng.standard_normal(size=3) + self.prng.set_state(self.state) + new = self.prng.standard_normal(size=3) + assert_(np.all(old == new)) + + def test_gaussian_reset_in_media_res(self): + # When the state is saved with a cached Gaussian, make sure the + # cached Gaussian is restored. + + self.prng.standard_normal() + state = self.prng.get_state() + old = self.prng.standard_normal(size=3) + self.prng.set_state(state) + new = self.prng.standard_normal(size=3) + assert_(np.all(old == new)) + + def test_backwards_compatibility(self): + # Make sure we can accept old state tuples that do not have the + # cached Gaussian value. + old_state = self.state[:-2] + x1 = self.prng.standard_normal(size=16) + self.prng.set_state(old_state) + x2 = self.prng.standard_normal(size=16) + self.prng.set_state(self.state) + x3 = self.prng.standard_normal(size=16) + assert_(np.all(x1 == x2)) + assert_(np.all(x1 == x3)) + + def test_negative_binomial(self): + # Ensure that the negative binomial results take floating point + # arguments without truncation. + self.prng.negative_binomial(0.5, 0.5) + + +class TestRandint(object): + + rfunc = np.random.randint + + # valid integer/boolean types + itype = [np.bool_, np.int8, np.uint8, np.int16, np.uint16, + np.int32, np.uint32, np.int64, np.uint64] + + def test_unsupported_type(self): + assert_raises(TypeError, self.rfunc, 1, dtype=float) + + def test_bounds_checking(self): + for dt in self.itype: + lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min + ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1 + assert_raises(ValueError, self.rfunc, lbnd - 1, ubnd, dtype=dt) + assert_raises(ValueError, self.rfunc, lbnd, ubnd + 1, dtype=dt) + assert_raises(ValueError, self.rfunc, ubnd, lbnd, dtype=dt) + assert_raises(ValueError, self.rfunc, 1, 0, dtype=dt) + + def test_rng_zero_and_extremes(self): + for dt in self.itype: + lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min + ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1 + + tgt = ubnd - 1 + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + + tgt = lbnd + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + + tgt = (lbnd + ubnd)//2 + assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt) + + def test_full_range(self): + # Test for ticket #1690 + + for dt in self.itype: + lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min + ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1 + + try: + self.rfunc(lbnd, ubnd, dtype=dt) + except Exception as e: + raise AssertionError("No error should have been raised, " + "but one was with the following " + "message:\n\n%s" % str(e)) + + def test_in_bounds_fuzz(self): + # Don't use fixed seed + np.random.seed() + + for dt in self.itype[1:]: + for ubnd in [4, 8, 16]: + vals = self.rfunc(2, ubnd, size=2**16, dtype=dt) + assert_(vals.max() < ubnd) + assert_(vals.min() >= 2) + + vals = self.rfunc(0, 2, size=2**16, dtype=np.bool_) + + assert_(vals.max() < 2) + assert_(vals.min() >= 0) + + def test_repeatability(self): + import hashlib + # We use a md5 hash of generated sequences of 1000 samples + # in the range [0, 6) for all but bool, where the range + # is [0, 2). Hashes are for little endian numbers. + tgt = {'bool': '7dd3170d7aa461d201a65f8bcf3944b0', + 'int16': '1b7741b80964bb190c50d541dca1cac1', + 'int32': '4dc9fcc2b395577ebb51793e58ed1a05', + 'int64': '17db902806f448331b5a758d7d2ee672', + 'int8': '27dd30c4e08a797063dffac2490b0be6', + 'uint16': '1b7741b80964bb190c50d541dca1cac1', + 'uint32': '4dc9fcc2b395577ebb51793e58ed1a05', + 'uint64': '17db902806f448331b5a758d7d2ee672', + 'uint8': '27dd30c4e08a797063dffac2490b0be6'} + + for dt in self.itype[1:]: + np.random.seed(1234) + + # view as little endian for hash + if sys.byteorder == 'little': + val = self.rfunc(0, 6, size=1000, dtype=dt) + else: + val = self.rfunc(0, 6, size=1000, dtype=dt).byteswap() + + res = hashlib.md5(val.view(np.int8)).hexdigest() + assert_(tgt[np.dtype(dt).name] == res) + + # bools do not depend on endianess + np.random.seed(1234) + val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8) + res = hashlib.md5(val).hexdigest() + assert_(tgt[np.dtype(bool).name] == res) + + def test_int64_uint64_corner_case(self): + # When stored in Numpy arrays, `lbnd` is casted + # as np.int64, and `ubnd` is casted as np.uint64. + # Checking whether `lbnd` >= `ubnd` used to be + # done solely via direct comparison, which is incorrect + # because when Numpy tries to compare both numbers, + # it casts both to np.float64 because there is + # no integer superset of np.int64 and np.uint64. However, + # `ubnd` is too large to be represented in np.float64, + # causing it be round down to np.iinfo(np.int64).max, + # leading to a ValueError because `lbnd` now equals + # the new `ubnd`. + + dt = np.int64 + tgt = np.iinfo(np.int64).max + lbnd = np.int64(np.iinfo(np.int64).max) + ubnd = np.uint64(np.iinfo(np.int64).max + 1) + + # None of these function calls should + # generate a ValueError now. + actual = np.random.randint(lbnd, ubnd, dtype=dt) + assert_equal(actual, tgt) + + def test_respect_dtype_singleton(self): + # See gh-7203 + for dt in self.itype: + lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min + ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1 + + sample = self.rfunc(lbnd, ubnd, dtype=dt) + assert_equal(sample.dtype, np.dtype(dt)) + + for dt in (bool, int, np.long): + lbnd = 0 if dt is bool else np.iinfo(dt).min + ubnd = 2 if dt is bool else np.iinfo(dt).max + 1 + + # gh-7284: Ensure that we get Python data types + sample = self.rfunc(lbnd, ubnd, dtype=dt) + assert_(not hasattr(sample, 'dtype')) + assert_equal(type(sample), dt) + + +class TestRandomDist(object): + # Make sure the random distribution returns the correct value for a + # given seed + + def setup(self): + self.seed = 1234567890 + + def test_rand(self): + np.random.seed(self.seed) + actual = np.random.rand(3, 2) + desired = np.array([[0.61879477158567997, 0.59162362775974664], + [0.88868358904449662, 0.89165480011560816], + [0.4575674820298663, 0.7781880808593471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_randn(self): + np.random.seed(self.seed) + actual = np.random.randn(3, 2) + desired = np.array([[1.34016345771863121, 1.73759122771936081], + [1.498988344300628, -0.2286433324536169], + [2.031033998682787, 2.17032494605655257]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_randint(self): + np.random.seed(self.seed) + actual = np.random.randint(-99, 99, size=(3, 2)) + desired = np.array([[31, 3], + [-52, 41], + [-48, -66]]) + assert_array_equal(actual, desired) + + def test_random_integers(self): + np.random.seed(self.seed) + with suppress_warnings() as sup: + w = sup.record(DeprecationWarning) + actual = np.random.random_integers(-99, 99, size=(3, 2)) + assert_(len(w) == 1) + desired = np.array([[31, 3], + [-52, 41], + [-48, -66]]) + assert_array_equal(actual, desired) + + def test_random_integers_max_int(self): + # Tests whether random_integers can generate the + # maximum allowed Python int that can be converted + # into a C long. Previous implementations of this + # method have thrown an OverflowError when attempting + # to generate this integer. + with suppress_warnings() as sup: + w = sup.record(DeprecationWarning) + actual = np.random.random_integers(np.iinfo('l').max, + np.iinfo('l').max) + assert_(len(w) == 1) + + desired = np.iinfo('l').max + assert_equal(actual, desired) + + def test_random_integers_deprecated(self): + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + + # DeprecationWarning raised with high == None + assert_raises(DeprecationWarning, + np.random.random_integers, + np.iinfo('l').max) + + # DeprecationWarning raised with high != None + assert_raises(DeprecationWarning, + np.random.random_integers, + np.iinfo('l').max, np.iinfo('l').max) + + def test_random_sample(self): + np.random.seed(self.seed) + actual = np.random.random_sample((3, 2)) + desired = np.array([[0.61879477158567997, 0.59162362775974664], + [0.88868358904449662, 0.89165480011560816], + [0.4575674820298663, 0.7781880808593471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_choice_uniform_replace(self): + np.random.seed(self.seed) + actual = np.random.choice(4, 4) + desired = np.array([2, 3, 2, 3]) + assert_array_equal(actual, desired) + + def test_choice_nonuniform_replace(self): + np.random.seed(self.seed) + actual = np.random.choice(4, 4, p=[0.4, 0.4, 0.1, 0.1]) + desired = np.array([1, 1, 2, 2]) + assert_array_equal(actual, desired) + + def test_choice_uniform_noreplace(self): + np.random.seed(self.seed) + actual = np.random.choice(4, 3, replace=False) + desired = np.array([0, 1, 3]) + assert_array_equal(actual, desired) + + def test_choice_nonuniform_noreplace(self): + np.random.seed(self.seed) + actual = np.random.choice(4, 3, replace=False, + p=[0.1, 0.3, 0.5, 0.1]) + desired = np.array([2, 3, 1]) + assert_array_equal(actual, desired) + + def test_choice_noninteger(self): + np.random.seed(self.seed) + actual = np.random.choice(['a', 'b', 'c', 'd'], 4) + desired = np.array(['c', 'd', 'c', 'd']) + assert_array_equal(actual, desired) + + def test_choice_exceptions(self): + sample = np.random.choice + assert_raises(ValueError, sample, -1, 3) + assert_raises(ValueError, sample, 3., 3) + assert_raises(ValueError, sample, [[1, 2], [3, 4]], 3) + assert_raises(ValueError, sample, [], 3) + assert_raises(ValueError, sample, [1, 2, 3, 4], 3, + p=[[0.25, 0.25], [0.25, 0.25]]) + assert_raises(ValueError, sample, [1, 2], 3, p=[0.4, 0.4, 0.2]) + assert_raises(ValueError, sample, [1, 2], 3, p=[1.1, -0.1]) + assert_raises(ValueError, sample, [1, 2], 3, p=[0.4, 0.4]) + assert_raises(ValueError, sample, [1, 2, 3], 4, replace=False) + assert_raises(ValueError, sample, [1, 2, 3], 2, + replace=False, p=[1, 0, 0]) + + def test_choice_return_shape(self): + p = [0.1, 0.9] + # Check scalar + assert_(np.isscalar(np.random.choice(2, replace=True))) + assert_(np.isscalar(np.random.choice(2, replace=False))) + assert_(np.isscalar(np.random.choice(2, replace=True, p=p))) + assert_(np.isscalar(np.random.choice(2, replace=False, p=p))) + assert_(np.isscalar(np.random.choice([1, 2], replace=True))) + assert_(np.random.choice([None], replace=True) is None) + a = np.array([1, 2]) + arr = np.empty(1, dtype=object) + arr[0] = a + assert_(np.random.choice(arr, replace=True) is a) + + # Check 0-d array + s = tuple() + assert_(not np.isscalar(np.random.choice(2, s, replace=True))) + assert_(not np.isscalar(np.random.choice(2, s, replace=False))) + assert_(not np.isscalar(np.random.choice(2, s, replace=True, p=p))) + assert_(not np.isscalar(np.random.choice(2, s, replace=False, p=p))) + assert_(not np.isscalar(np.random.choice([1, 2], s, replace=True))) + assert_(np.random.choice([None], s, replace=True).ndim == 0) + a = np.array([1, 2]) + arr = np.empty(1, dtype=object) + arr[0] = a + assert_(np.random.choice(arr, s, replace=True).item() is a) + + # Check multi dimensional array + s = (2, 3) + p = [0.1, 0.1, 0.1, 0.1, 0.4, 0.2] + assert_equal(np.random.choice(6, s, replace=True).shape, s) + assert_equal(np.random.choice(6, s, replace=False).shape, s) + assert_equal(np.random.choice(6, s, replace=True, p=p).shape, s) + assert_equal(np.random.choice(6, s, replace=False, p=p).shape, s) + assert_equal(np.random.choice(np.arange(6), s, replace=True).shape, s) + + def test_bytes(self): + np.random.seed(self.seed) + actual = np.random.bytes(10) + desired = b'\x82Ui\x9e\xff\x97+Wf\xa5' + assert_equal(actual, desired) + + def test_shuffle(self): + # Test lists, arrays (of various dtypes), and multidimensional versions + # of both, c-contiguous or not: + for conv in [lambda x: np.array([]), + lambda x: x, + lambda x: np.asarray(x).astype(np.int8), + lambda x: np.asarray(x).astype(np.float32), + lambda x: np.asarray(x).astype(np.complex64), + lambda x: np.asarray(x).astype(object), + lambda x: [(i, i) for i in x], + lambda x: np.asarray([[i, i] for i in x]), + lambda x: np.vstack([x, x]).T, + # gh-4270 + lambda x: np.asarray([(i, i) for i in x], + [("a", object, 1), + ("b", np.int32, 1)])]: + np.random.seed(self.seed) + alist = conv([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) + np.random.shuffle(alist) + actual = alist + desired = conv([0, 1, 9, 6, 2, 4, 5, 8, 7, 3]) + assert_array_equal(actual, desired) + + def test_shuffle_masked(self): + # gh-3263 + a = np.ma.masked_values(np.reshape(range(20), (5, 4)) % 3 - 1, -1) + b = np.ma.masked_values(np.arange(20) % 3 - 1, -1) + a_orig = a.copy() + b_orig = b.copy() + for i in range(50): + np.random.shuffle(a) + assert_equal( + sorted(a.data[~a.mask]), sorted(a_orig.data[~a_orig.mask])) + np.random.shuffle(b) + assert_equal( + sorted(b.data[~b.mask]), sorted(b_orig.data[~b_orig.mask])) + + def test_beta(self): + np.random.seed(self.seed) + actual = np.random.beta(.1, .9, size=(3, 2)) + desired = np.array( + [[1.45341850513746058e-02, 5.31297615662868145e-04], + [1.85366619058432324e-06, 4.19214516800110563e-03], + [1.58405155108498093e-04, 1.26252891949397652e-04]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_binomial(self): + np.random.seed(self.seed) + actual = np.random.binomial(100.123, .456, size=(3, 2)) + desired = np.array([[37, 43], + [42, 48], + [46, 45]]) + assert_array_equal(actual, desired) + + def test_chisquare(self): + np.random.seed(self.seed) + actual = np.random.chisquare(50, size=(3, 2)) + desired = np.array([[63.87858175501090585, 68.68407748911370447], + [65.77116116901505904, 47.09686762438974483], + [72.3828403199695174, 74.18408615260374006]]) + assert_array_almost_equal(actual, desired, decimal=13) + + def test_dirichlet(self): + np.random.seed(self.seed) + alpha = np.array([51.72840233779265162, 39.74494232180943953]) + actual = np.random.mtrand.dirichlet(alpha, size=(3, 2)) + desired = np.array([[[0.54539444573611562, 0.45460555426388438], + [0.62345816822039413, 0.37654183177960598]], + [[0.55206000085785778, 0.44793999914214233], + [0.58964023305154301, 0.41035976694845688]], + [[0.59266909280647828, 0.40733090719352177], + [0.56974431743975207, 0.43025568256024799]]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_dirichlet_size(self): + # gh-3173 + p = np.array([51.72840233779265162, 39.74494232180943953]) + assert_equal(np.random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(np.random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(np.random.dirichlet(p, np.uint32(1)).shape, (1, 2)) + assert_equal(np.random.dirichlet(p, [2, 2]).shape, (2, 2, 2)) + assert_equal(np.random.dirichlet(p, (2, 2)).shape, (2, 2, 2)) + assert_equal(np.random.dirichlet(p, np.array((2, 2))).shape, (2, 2, 2)) + + assert_raises(TypeError, np.random.dirichlet, p, float(1)) + + def test_dirichlet_bad_alpha(self): + # gh-2089 + alpha = np.array([5.4e-01, -1.0e-16]) + assert_raises(ValueError, np.random.mtrand.dirichlet, alpha) + + def test_exponential(self): + np.random.seed(self.seed) + actual = np.random.exponential(1.1234, size=(3, 2)) + desired = np.array([[1.08342649775011624, 1.00607889924557314], + [2.46628830085216721, 2.49668106809923884], + [0.68717433461363442, 1.69175666993575979]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_exponential_0(self): + assert_equal(np.random.exponential(scale=0), 0) + assert_raises(ValueError, np.random.exponential, scale=-0.) + + def test_f(self): + np.random.seed(self.seed) + actual = np.random.f(12, 77, size=(3, 2)) + desired = np.array([[1.21975394418575878, 1.75135759791559775], + [1.44803115017146489, 1.22108959480396262], + [1.02176975757740629, 1.34431827623300415]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_gamma(self): + np.random.seed(self.seed) + actual = np.random.gamma(5, 3, size=(3, 2)) + desired = np.array([[24.60509188649287182, 28.54993563207210627], + [26.13476110204064184, 12.56988482927716078], + [31.71863275789960568, 33.30143302795922011]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_gamma_0(self): + assert_equal(np.random.gamma(shape=0, scale=0), 0) + assert_raises(ValueError, np.random.gamma, shape=-0., scale=-0.) + + def test_geometric(self): + np.random.seed(self.seed) + actual = np.random.geometric(.123456789, size=(3, 2)) + desired = np.array([[8, 7], + [17, 17], + [5, 12]]) + assert_array_equal(actual, desired) + + def test_gumbel(self): + np.random.seed(self.seed) + actual = np.random.gumbel(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[0.19591898743416816, 0.34405539668096674], + [-1.4492522252274278, -1.47374816298446865], + [1.10651090478803416, -0.69535848626236174]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_gumbel_0(self): + assert_equal(np.random.gumbel(scale=0), 0) + assert_raises(ValueError, np.random.gumbel, scale=-0.) + + def test_hypergeometric(self): + np.random.seed(self.seed) + actual = np.random.hypergeometric(10.1, 5.5, 14, size=(3, 2)) + desired = np.array([[10, 10], + [10, 10], + [9, 9]]) + assert_array_equal(actual, desired) + + # Test nbad = 0 + actual = np.random.hypergeometric(5, 0, 3, size=4) + desired = np.array([3, 3, 3, 3]) + assert_array_equal(actual, desired) + + actual = np.random.hypergeometric(15, 0, 12, size=4) + desired = np.array([12, 12, 12, 12]) + assert_array_equal(actual, desired) + + # Test ngood = 0 + actual = np.random.hypergeometric(0, 5, 3, size=4) + desired = np.array([0, 0, 0, 0]) + assert_array_equal(actual, desired) + + actual = np.random.hypergeometric(0, 15, 12, size=4) + desired = np.array([0, 0, 0, 0]) + assert_array_equal(actual, desired) + + def test_laplace(self): + np.random.seed(self.seed) + actual = np.random.laplace(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[0.66599721112760157, 0.52829452552221945], + [3.12791959514407125, 3.18202813572992005], + [-0.05391065675859356, 1.74901336242837324]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_laplace_0(self): + assert_equal(np.random.laplace(scale=0), 0) + assert_raises(ValueError, np.random.laplace, scale=-0.) + + def test_logistic(self): + np.random.seed(self.seed) + actual = np.random.logistic(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[1.09232835305011444, 0.8648196662399954], + [4.27818590694950185, 4.33897006346929714], + [-0.21682183359214885, 2.63373365386060332]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_lognormal(self): + np.random.seed(self.seed) + actual = np.random.lognormal(mean=.123456789, sigma=2.0, size=(3, 2)) + desired = np.array([[16.50698631688883822, 36.54846706092654784], + [22.67886599981281748, 0.71617561058995771], + [65.72798501792723869, 86.84341601437161273]]) + assert_array_almost_equal(actual, desired, decimal=13) + + def test_lognormal_0(self): + assert_equal(np.random.lognormal(sigma=0), 1) + assert_raises(ValueError, np.random.lognormal, sigma=-0.) + + def test_logseries(self): + np.random.seed(self.seed) + actual = np.random.logseries(p=.923456789, size=(3, 2)) + desired = np.array([[2, 2], + [6, 17], + [3, 6]]) + assert_array_equal(actual, desired) + + def test_multinomial(self): + np.random.seed(self.seed) + actual = np.random.multinomial(20, [1/6.]*6, size=(3, 2)) + desired = np.array([[[4, 3, 5, 4, 2, 2], + [5, 2, 8, 2, 2, 1]], + [[3, 4, 3, 6, 0, 4], + [2, 1, 4, 3, 6, 4]], + [[4, 4, 2, 5, 2, 3], + [4, 3, 4, 2, 3, 4]]]) + assert_array_equal(actual, desired) + + def test_multivariate_normal(self): + np.random.seed(self.seed) + mean = (.123456789, 10) + cov = [[1, 0], [0, 1]] + size = (3, 2) + actual = np.random.multivariate_normal(mean, cov, size) + desired = np.array([[[1.463620246718631, 11.73759122771936 ], + [1.622445133300628, 9.771356667546383]], + [[2.154490787682787, 12.170324946056553], + [1.719909438201865, 9.230548443648306]], + [[0.689515026297799, 9.880729819607714], + [-0.023054015651998, 9.201096623542879]]]) + + assert_array_almost_equal(actual, desired, decimal=15) + + # Check for default size, was raising deprecation warning + actual = np.random.multivariate_normal(mean, cov) + desired = np.array([0.895289569463708, 9.17180864067987]) + assert_array_almost_equal(actual, desired, decimal=15) + + # Check that non positive-semidefinite covariance warns with + # RuntimeWarning + mean = [0, 0] + cov = [[1, 2], [2, 1]] + assert_warns(RuntimeWarning, np.random.multivariate_normal, mean, cov) + + # and that it doesn't warn with RuntimeWarning check_valid='ignore' + assert_no_warnings(np.random.multivariate_normal, mean, cov, + check_valid='ignore') + + # and that it raises with RuntimeWarning check_valid='raises' + assert_raises(ValueError, np.random.multivariate_normal, mean, cov, + check_valid='raise') + + def test_negative_binomial(self): + np.random.seed(self.seed) + actual = np.random.negative_binomial(n=100, p=.12345, size=(3, 2)) + desired = np.array([[848, 841], + [892, 611], + [779, 647]]) + assert_array_equal(actual, desired) + + def test_noncentral_chisquare(self): + np.random.seed(self.seed) + actual = np.random.noncentral_chisquare(df=5, nonc=5, size=(3, 2)) + desired = np.array([[23.91905354498517511, 13.35324692733826346], + [31.22452661329736401, 16.60047399466177254], + [5.03461598262724586, 17.94973089023519464]]) + assert_array_almost_equal(actual, desired, decimal=14) + + actual = np.random.noncentral_chisquare(df=.5, nonc=.2, size=(3, 2)) + desired = np.array([[1.47145377828516666, 0.15052899268012659], + [0.00943803056963588, 1.02647251615666169], + [0.332334982684171, 0.15451287602753125]]) + assert_array_almost_equal(actual, desired, decimal=14) + + np.random.seed(self.seed) + actual = np.random.noncentral_chisquare(df=5, nonc=0, size=(3, 2)) + desired = np.array([[9.597154162763948, 11.725484450296079], + [10.413711048138335, 3.694475922923986], + [13.484222138963087, 14.377255424602957]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_noncentral_f(self): + np.random.seed(self.seed) + actual = np.random.noncentral_f(dfnum=5, dfden=2, nonc=1, + size=(3, 2)) + desired = np.array([[1.40598099674926669, 0.34207973179285761], + [3.57715069265772545, 7.92632662577829805], + [0.43741599463544162, 1.1774208752428319]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_normal(self): + np.random.seed(self.seed) + actual = np.random.normal(loc=.123456789, scale=2.0, size=(3, 2)) + desired = np.array([[2.80378370443726244, 3.59863924443872163], + [3.121433477601256, -0.33382987590723379], + [4.18552478636557357, 4.46410668111310471]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_normal_0(self): + assert_equal(np.random.normal(scale=0), 0) + assert_raises(ValueError, np.random.normal, scale=-0.) + + def test_pareto(self): + np.random.seed(self.seed) + actual = np.random.pareto(a=.123456789, size=(3, 2)) + desired = np.array( + [[2.46852460439034849e+03, 1.41286880810518346e+03], + [5.28287797029485181e+07, 6.57720981047328785e+07], + [1.40840323350391515e+02, 1.98390255135251704e+05]]) + # For some reason on 32-bit x86 Ubuntu 12.10 the [1, 0] entry in this + # matrix differs by 24 nulps. Discussion: + # http://mail.python.org/pipermail/numpy-discussion/2012-September/063801.html + # Consensus is that this is probably some gcc quirk that affects + # rounding but not in any important way, so we just use a looser + # tolerance on this test: + np.testing.assert_array_almost_equal_nulp(actual, desired, nulp=30) + + def test_poisson(self): + np.random.seed(self.seed) + actual = np.random.poisson(lam=.123456789, size=(3, 2)) + desired = np.array([[0, 0], + [1, 0], + [0, 0]]) + assert_array_equal(actual, desired) + + def test_poisson_exceptions(self): + lambig = np.iinfo('l').max + lamneg = -1 + assert_raises(ValueError, np.random.poisson, lamneg) + assert_raises(ValueError, np.random.poisson, [lamneg]*10) + assert_raises(ValueError, np.random.poisson, lambig) + assert_raises(ValueError, np.random.poisson, [lambig]*10) + + def test_power(self): + np.random.seed(self.seed) + actual = np.random.power(a=.123456789, size=(3, 2)) + desired = np.array([[0.02048932883240791, 0.01424192241128213], + [0.38446073748535298, 0.39499689943484395], + [0.00177699707563439, 0.13115505880863756]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_rayleigh(self): + np.random.seed(self.seed) + actual = np.random.rayleigh(scale=10, size=(3, 2)) + desired = np.array([[13.8882496494248393, 13.383318339044731], + [20.95413364294492098, 21.08285015800712614], + [11.06066537006854311, 17.35468505778271009]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_rayleigh_0(self): + assert_equal(np.random.rayleigh(scale=0), 0) + assert_raises(ValueError, np.random.rayleigh, scale=-0.) + + def test_standard_cauchy(self): + np.random.seed(self.seed) + actual = np.random.standard_cauchy(size=(3, 2)) + desired = np.array([[0.77127660196445336, -6.55601161955910605], + [0.93582023391158309, -2.07479293013759447], + [-4.74601644297011926, 0.18338989290760804]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_exponential(self): + np.random.seed(self.seed) + actual = np.random.standard_exponential(size=(3, 2)) + desired = np.array([[0.96441739162374596, 0.89556604882105506], + [2.1953785836319808, 2.22243285392490542], + [0.6116915921431676, 1.50592546727413201]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_gamma(self): + np.random.seed(self.seed) + actual = np.random.standard_gamma(shape=3, size=(3, 2)) + desired = np.array([[5.50841531318455058, 6.62953470301903103], + [5.93988484943779227, 2.31044849402133989], + [7.54838614231317084, 8.012756093271868]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_standard_gamma_0(self): + assert_equal(np.random.standard_gamma(shape=0), 0) + assert_raises(ValueError, np.random.standard_gamma, shape=-0.) + + def test_standard_normal(self): + np.random.seed(self.seed) + actual = np.random.standard_normal(size=(3, 2)) + desired = np.array([[1.34016345771863121, 1.73759122771936081], + [1.498988344300628, -0.2286433324536169], + [2.031033998682787, 2.17032494605655257]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_standard_t(self): + np.random.seed(self.seed) + actual = np.random.standard_t(df=10, size=(3, 2)) + desired = np.array([[0.97140611862659965, -0.08830486548450577], + [1.36311143689505321, -0.55317463909867071], + [-0.18473749069684214, 0.61181537341755321]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_triangular(self): + np.random.seed(self.seed) + actual = np.random.triangular(left=5.12, mode=10.23, right=20.34, + size=(3, 2)) + desired = np.array([[12.68117178949215784, 12.4129206149193152], + [16.20131377335158263, 16.25692138747600524], + [11.20400690911820263, 14.4978144835829923]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_uniform(self): + np.random.seed(self.seed) + actual = np.random.uniform(low=1.23, high=10.54, size=(3, 2)) + desired = np.array([[6.99097932346268003, 6.73801597444323974], + [9.50364421400426274, 9.53130618907631089], + [5.48995325769805476, 8.47493103280052118]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_uniform_range_bounds(self): + fmin = np.finfo('float').min + fmax = np.finfo('float').max + + func = np.random.uniform + assert_raises(OverflowError, func, -np.inf, 0) + assert_raises(OverflowError, func, 0, np.inf) + assert_raises(OverflowError, func, fmin, fmax) + assert_raises(OverflowError, func, [-np.inf], [0]) + assert_raises(OverflowError, func, [0], [np.inf]) + + # (fmax / 1e17) - fmin is within range, so this should not throw + # account for i386 extended precision DBL_MAX / 1e17 + DBL_MAX > + # DBL_MAX by increasing fmin a bit + np.random.uniform(low=np.nextafter(fmin, 1), high=fmax / 1e17) + + def test_scalar_exception_propagation(self): + # Tests that exceptions are correctly propagated in distributions + # when called with objects that throw exceptions when converted to + # scalars. + # + # Regression test for gh: 8865 + + class ThrowingFloat(np.ndarray): + def __float__(self): + raise TypeError + + throwing_float = np.array(1.0).view(ThrowingFloat) + assert_raises(TypeError, np.random.uniform, throwing_float, throwing_float) + + class ThrowingInteger(np.ndarray): + def __int__(self): + raise TypeError + + throwing_int = np.array(1).view(ThrowingInteger) + assert_raises(TypeError, np.random.hypergeometric, throwing_int, 1, 1) + + def test_vonmises(self): + np.random.seed(self.seed) + actual = np.random.vonmises(mu=1.23, kappa=1.54, size=(3, 2)) + desired = np.array([[2.28567572673902042, 2.89163838442285037], + [0.38198375564286025, 2.57638023113890746], + [1.19153771588353052, 1.83509849681825354]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_vonmises_small(self): + # check infinite loop, gh-4720 + np.random.seed(self.seed) + r = np.random.vonmises(mu=0., kappa=1.1e-8, size=10**6) + np.testing.assert_(np.isfinite(r).all()) + + def test_wald(self): + np.random.seed(self.seed) + actual = np.random.wald(mean=1.23, scale=1.54, size=(3, 2)) + desired = np.array([[3.82935265715889983, 5.13125249184285526], + [0.35045403618358717, 1.50832396872003538], + [0.24124319895843183, 0.22031101461955038]]) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_weibull(self): + np.random.seed(self.seed) + actual = np.random.weibull(a=1.23, size=(3, 2)) + desired = np.array([[0.97097342648766727, 0.91422896443565516], + [1.89517770034962929, 1.91414357960479564], + [0.67057783752390987, 1.39494046635066793]]) + assert_array_almost_equal(actual, desired, decimal=15) + + def test_weibull_0(self): + assert_equal(np.random.weibull(a=0), 0) + assert_raises(ValueError, np.random.weibull, a=-0.) + + def test_zipf(self): + np.random.seed(self.seed) + actual = np.random.zipf(a=1.23, size=(3, 2)) + desired = np.array([[66, 29], + [1, 1], + [3, 13]]) + assert_array_equal(actual, desired) + + +class TestBroadcast(object): + # tests that functions that broadcast behave + # correctly when presented with non-scalar arguments + def setup(self): + self.seed = 123456789 + + def setSeed(self): + np.random.seed(self.seed) + + # TODO: Include test for randint once it can broadcast + # Can steal the test written in PR #6938 + + def test_uniform(self): + low = [0] + high = [1] + uniform = np.random.uniform + desired = np.array([0.53283302478975902, + 0.53413660089041659, + 0.50955303552646702]) + + self.setSeed() + actual = uniform(low * 3, high) + assert_array_almost_equal(actual, desired, decimal=14) + + self.setSeed() + actual = uniform(low, high * 3) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_normal(self): + loc = [0] + scale = [1] + bad_scale = [-1] + normal = np.random.normal + desired = np.array([2.2129019979039612, + 2.1283977976520019, + 1.8417114045748335]) + + self.setSeed() + actual = normal(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, normal, loc * 3, bad_scale) + + self.setSeed() + actual = normal(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, normal, loc, bad_scale * 3) + + def test_beta(self): + a = [1] + b = [2] + bad_a = [-1] + bad_b = [-2] + beta = np.random.beta + desired = np.array([0.19843558305989056, + 0.075230336409423643, + 0.24976865978980844]) + + self.setSeed() + actual = beta(a * 3, b) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, beta, bad_a * 3, b) + assert_raises(ValueError, beta, a * 3, bad_b) + + self.setSeed() + actual = beta(a, b * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, beta, bad_a, b * 3) + assert_raises(ValueError, beta, a, bad_b * 3) + + def test_exponential(self): + scale = [1] + bad_scale = [-1] + exponential = np.random.exponential + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.setSeed() + actual = exponential(scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, exponential, bad_scale * 3) + + def test_standard_gamma(self): + shape = [1] + bad_shape = [-1] + std_gamma = np.random.standard_gamma + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.setSeed() + actual = std_gamma(shape * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, std_gamma, bad_shape * 3) + + def test_gamma(self): + shape = [1] + scale = [2] + bad_shape = [-1] + bad_scale = [-2] + gamma = np.random.gamma + desired = np.array([1.5221370731769048, + 1.5277256455738331, + 1.4248762625178359]) + + self.setSeed() + actual = gamma(shape * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gamma, bad_shape * 3, scale) + assert_raises(ValueError, gamma, shape * 3, bad_scale) + + self.setSeed() + actual = gamma(shape, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gamma, bad_shape, scale * 3) + assert_raises(ValueError, gamma, shape, bad_scale * 3) + + def test_f(self): + dfnum = [1] + dfden = [2] + bad_dfnum = [-1] + bad_dfden = [-2] + f = np.random.f + desired = np.array([0.80038951638264799, + 0.86768719635363512, + 2.7251095168386801]) + + self.setSeed() + actual = f(dfnum * 3, dfden) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, f, bad_dfnum * 3, dfden) + assert_raises(ValueError, f, dfnum * 3, bad_dfden) + + self.setSeed() + actual = f(dfnum, dfden * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, f, bad_dfnum, dfden * 3) + assert_raises(ValueError, f, dfnum, bad_dfden * 3) + + def test_noncentral_f(self): + dfnum = [2] + dfden = [3] + nonc = [4] + bad_dfnum = [0] + bad_dfden = [-1] + bad_nonc = [-2] + nonc_f = np.random.noncentral_f + desired = np.array([9.1393943263705211, + 13.025456344595602, + 8.8018098359100545]) + + self.setSeed() + actual = nonc_f(dfnum * 3, dfden, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum * 3, dfden, nonc) + assert_raises(ValueError, nonc_f, dfnum * 3, bad_dfden, nonc) + assert_raises(ValueError, nonc_f, dfnum * 3, dfden, bad_nonc) + + self.setSeed() + actual = nonc_f(dfnum, dfden * 3, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum, dfden * 3, nonc) + assert_raises(ValueError, nonc_f, dfnum, bad_dfden * 3, nonc) + assert_raises(ValueError, nonc_f, dfnum, dfden * 3, bad_nonc) + + self.setSeed() + actual = nonc_f(dfnum, dfden, nonc * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_f, bad_dfnum, dfden, nonc * 3) + assert_raises(ValueError, nonc_f, dfnum, bad_dfden, nonc * 3) + assert_raises(ValueError, nonc_f, dfnum, dfden, bad_nonc * 3) + + def test_noncentral_f_small_df(self): + self.setSeed() + desired = np.array([6.869638627492048, 0.785880199263955]) + actual = np.random.noncentral_f(0.9, 0.9, 2, size=2) + assert_array_almost_equal(actual, desired, decimal=14) + + def test_chisquare(self): + df = [1] + bad_df = [-1] + chisquare = np.random.chisquare + desired = np.array([0.57022801133088286, + 0.51947702108840776, + 0.1320969254923558]) + + self.setSeed() + actual = chisquare(df * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, chisquare, bad_df * 3) + + def test_noncentral_chisquare(self): + df = [1] + nonc = [2] + bad_df = [-1] + bad_nonc = [-2] + nonc_chi = np.random.noncentral_chisquare + desired = np.array([9.0015599467913763, + 4.5804135049718742, + 6.0872302432834564]) + + self.setSeed() + actual = nonc_chi(df * 3, nonc) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_chi, bad_df * 3, nonc) + assert_raises(ValueError, nonc_chi, df * 3, bad_nonc) + + self.setSeed() + actual = nonc_chi(df, nonc * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, nonc_chi, bad_df, nonc * 3) + assert_raises(ValueError, nonc_chi, df, bad_nonc * 3) + + def test_standard_t(self): + df = [1] + bad_df = [-1] + t = np.random.standard_t + desired = np.array([3.0702872575217643, + 5.8560725167361607, + 1.0274791436474273]) + + self.setSeed() + actual = t(df * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, t, bad_df * 3) + + def test_vonmises(self): + mu = [2] + kappa = [1] + bad_kappa = [-1] + vonmises = np.random.vonmises + desired = np.array([2.9883443664201312, + -2.7064099483995943, + -1.8672476700665914]) + + self.setSeed() + actual = vonmises(mu * 3, kappa) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, vonmises, mu * 3, bad_kappa) + + self.setSeed() + actual = vonmises(mu, kappa * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, vonmises, mu, bad_kappa * 3) + + def test_pareto(self): + a = [1] + bad_a = [-1] + pareto = np.random.pareto + desired = np.array([1.1405622680198362, + 1.1465519762044529, + 1.0389564467453547]) + + self.setSeed() + actual = pareto(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, pareto, bad_a * 3) + + def test_weibull(self): + a = [1] + bad_a = [-1] + weibull = np.random.weibull + desired = np.array([0.76106853658845242, + 0.76386282278691653, + 0.71243813125891797]) + + self.setSeed() + actual = weibull(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, weibull, bad_a * 3) + + def test_power(self): + a = [1] + bad_a = [-1] + power = np.random.power + desired = np.array([0.53283302478975902, + 0.53413660089041659, + 0.50955303552646702]) + + self.setSeed() + actual = power(a * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, power, bad_a * 3) + + def test_laplace(self): + loc = [0] + scale = [1] + bad_scale = [-1] + laplace = np.random.laplace + desired = np.array([0.067921356028507157, + 0.070715642226971326, + 0.019290950698972624]) + + self.setSeed() + actual = laplace(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, laplace, loc * 3, bad_scale) + + self.setSeed() + actual = laplace(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, laplace, loc, bad_scale * 3) + + def test_gumbel(self): + loc = [0] + scale = [1] + bad_scale = [-1] + gumbel = np.random.gumbel + desired = np.array([0.2730318639556768, + 0.26936705726291116, + 0.33906220393037939]) + + self.setSeed() + actual = gumbel(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gumbel, loc * 3, bad_scale) + + self.setSeed() + actual = gumbel(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, gumbel, loc, bad_scale * 3) + + def test_logistic(self): + loc = [0] + scale = [1] + bad_scale = [-1] + logistic = np.random.logistic + desired = np.array([0.13152135837586171, + 0.13675915696285773, + 0.038216792802833396]) + + self.setSeed() + actual = logistic(loc * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, logistic, loc * 3, bad_scale) + + self.setSeed() + actual = logistic(loc, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, logistic, loc, bad_scale * 3) + + def test_lognormal(self): + mean = [0] + sigma = [1] + bad_sigma = [-1] + lognormal = np.random.lognormal + desired = np.array([9.1422086044848427, + 8.4013952870126261, + 6.3073234116578671]) + + self.setSeed() + actual = lognormal(mean * 3, sigma) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, lognormal, mean * 3, bad_sigma) + + self.setSeed() + actual = lognormal(mean, sigma * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, lognormal, mean, bad_sigma * 3) + + def test_rayleigh(self): + scale = [1] + bad_scale = [-1] + rayleigh = np.random.rayleigh + desired = np.array([1.2337491937897689, + 1.2360119924878694, + 1.1936818095781789]) + + self.setSeed() + actual = rayleigh(scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, rayleigh, bad_scale * 3) + + def test_wald(self): + mean = [0.5] + scale = [1] + bad_mean = [0] + bad_scale = [-2] + wald = np.random.wald + desired = np.array([0.11873681120271318, + 0.12450084820795027, + 0.9096122728408238]) + + self.setSeed() + actual = wald(mean * 3, scale) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, wald, bad_mean * 3, scale) + assert_raises(ValueError, wald, mean * 3, bad_scale) + + self.setSeed() + actual = wald(mean, scale * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, wald, bad_mean, scale * 3) + assert_raises(ValueError, wald, mean, bad_scale * 3) + + def test_triangular(self): + left = [1] + right = [3] + mode = [2] + bad_left_one = [3] + bad_mode_one = [4] + bad_left_two, bad_mode_two = right * 2 + triangular = np.random.triangular + desired = np.array([2.03339048710429, + 2.0347400359389356, + 2.0095991069536208]) + + self.setSeed() + actual = triangular(left * 3, mode, right) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one * 3, mode, right) + assert_raises(ValueError, triangular, left * 3, bad_mode_one, right) + assert_raises(ValueError, triangular, bad_left_two * 3, bad_mode_two, right) + + self.setSeed() + actual = triangular(left, mode * 3, right) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one, mode * 3, right) + assert_raises(ValueError, triangular, left, bad_mode_one * 3, right) + assert_raises(ValueError, triangular, bad_left_two, bad_mode_two * 3, right) + + self.setSeed() + actual = triangular(left, mode, right * 3) + assert_array_almost_equal(actual, desired, decimal=14) + assert_raises(ValueError, triangular, bad_left_one, mode, right * 3) + assert_raises(ValueError, triangular, left, bad_mode_one, right * 3) + assert_raises(ValueError, triangular, bad_left_two, bad_mode_two, right * 3) + + def test_binomial(self): + n = [1] + p = [0.5] + bad_n = [-1] + bad_p_one = [-1] + bad_p_two = [1.5] + binom = np.random.binomial + desired = np.array([1, 1, 1]) + + self.setSeed() + actual = binom(n * 3, p) + assert_array_equal(actual, desired) + assert_raises(ValueError, binom, bad_n * 3, p) + assert_raises(ValueError, binom, n * 3, bad_p_one) + assert_raises(ValueError, binom, n * 3, bad_p_two) + + self.setSeed() + actual = binom(n, p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, binom, bad_n, p * 3) + assert_raises(ValueError, binom, n, bad_p_one * 3) + assert_raises(ValueError, binom, n, bad_p_two * 3) + + def test_negative_binomial(self): + n = [1] + p = [0.5] + bad_n = [-1] + bad_p_one = [-1] + bad_p_two = [1.5] + neg_binom = np.random.negative_binomial + desired = np.array([1, 0, 1]) + + self.setSeed() + actual = neg_binom(n * 3, p) + assert_array_equal(actual, desired) + assert_raises(ValueError, neg_binom, bad_n * 3, p) + assert_raises(ValueError, neg_binom, n * 3, bad_p_one) + assert_raises(ValueError, neg_binom, n * 3, bad_p_two) + + self.setSeed() + actual = neg_binom(n, p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, neg_binom, bad_n, p * 3) + assert_raises(ValueError, neg_binom, n, bad_p_one * 3) + assert_raises(ValueError, neg_binom, n, bad_p_two * 3) + + def test_poisson(self): + max_lam = np.random.RandomState().poisson_lam_max + + lam = [1] + bad_lam_one = [-1] + bad_lam_two = [max_lam * 2] + poisson = np.random.poisson + desired = np.array([1, 1, 0]) + + self.setSeed() + actual = poisson(lam * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, poisson, bad_lam_one * 3) + assert_raises(ValueError, poisson, bad_lam_two * 3) + + def test_zipf(self): + a = [2] + bad_a = [0] + zipf = np.random.zipf + desired = np.array([2, 2, 1]) + + self.setSeed() + actual = zipf(a * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, zipf, bad_a * 3) + with np.errstate(invalid='ignore'): + assert_raises(ValueError, zipf, np.nan) + assert_raises(ValueError, zipf, [0, 0, np.nan]) + + + def test_geometric(self): + p = [0.5] + bad_p_one = [-1] + bad_p_two = [1.5] + geom = np.random.geometric + desired = np.array([2, 2, 2]) + + self.setSeed() + actual = geom(p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, geom, bad_p_one * 3) + assert_raises(ValueError, geom, bad_p_two * 3) + + def test_hypergeometric(self): + ngood = [1] + nbad = [2] + nsample = [2] + bad_ngood = [-1] + bad_nbad = [-2] + bad_nsample_one = [0] + bad_nsample_two = [4] + hypergeom = np.random.hypergeometric + desired = np.array([1, 1, 1]) + + self.setSeed() + actual = hypergeom(ngood * 3, nbad, nsample) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood * 3, nbad, nsample) + assert_raises(ValueError, hypergeom, ngood * 3, bad_nbad, nsample) + assert_raises(ValueError, hypergeom, ngood * 3, nbad, bad_nsample_one) + assert_raises(ValueError, hypergeom, ngood * 3, nbad, bad_nsample_two) + + self.setSeed() + actual = hypergeom(ngood, nbad * 3, nsample) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood, nbad * 3, nsample) + assert_raises(ValueError, hypergeom, ngood, bad_nbad * 3, nsample) + assert_raises(ValueError, hypergeom, ngood, nbad * 3, bad_nsample_one) + assert_raises(ValueError, hypergeom, ngood, nbad * 3, bad_nsample_two) + + self.setSeed() + actual = hypergeom(ngood, nbad, nsample * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, hypergeom, bad_ngood, nbad, nsample * 3) + assert_raises(ValueError, hypergeom, ngood, bad_nbad, nsample * 3) + assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_one * 3) + assert_raises(ValueError, hypergeom, ngood, nbad, bad_nsample_two * 3) + + def test_logseries(self): + p = [0.5] + bad_p_one = [2] + bad_p_two = [-1] + logseries = np.random.logseries + desired = np.array([1, 1, 1]) + + self.setSeed() + actual = logseries(p * 3) + assert_array_equal(actual, desired) + assert_raises(ValueError, logseries, bad_p_one * 3) + assert_raises(ValueError, logseries, bad_p_two * 3) + +class TestThread(object): + # make sure each state produces the same sequence even in threads + def setup(self): + self.seeds = range(4) + + def check_function(self, function, sz): + from threading import Thread + + out1 = np.empty((len(self.seeds),) + sz) + out2 = np.empty((len(self.seeds),) + sz) + + # threaded generation + t = [Thread(target=function, args=(np.random.RandomState(s), o)) + for s, o in zip(self.seeds, out1)] + [x.start() for x in t] + [x.join() for x in t] + + # the same serial + for s, o in zip(self.seeds, out2): + function(np.random.RandomState(s), o) + + # these platforms change x87 fpu precision mode in threads + if np.intp().dtype.itemsize == 4 and sys.platform == "win32": + assert_array_almost_equal(out1, out2) + else: + assert_array_equal(out1, out2) + + def test_normal(self): + def gen_random(state, out): + out[...] = state.normal(size=10000) + self.check_function(gen_random, sz=(10000,)) + + def test_exp(self): + def gen_random(state, out): + out[...] = state.exponential(scale=np.ones((100, 1000))) + self.check_function(gen_random, sz=(100, 1000)) + + def test_multinomial(self): + def gen_random(state, out): + out[...] = state.multinomial(10, [1/6.]*6, size=10000) + self.check_function(gen_random, sz=(10000, 6)) + +# See Issue #4263 +class TestSingleEltArrayInput(object): + def setup(self): + self.argOne = np.array([2]) + self.argTwo = np.array([3]) + self.argThree = np.array([4]) + self.tgtShape = (1,) + + def test_one_arg_funcs(self): + funcs = (np.random.exponential, np.random.standard_gamma, + np.random.chisquare, np.random.standard_t, + np.random.pareto, np.random.weibull, + np.random.power, np.random.rayleigh, + np.random.poisson, np.random.zipf, + np.random.geometric, np.random.logseries) + + probfuncs = (np.random.geometric, np.random.logseries) + + for func in funcs: + if func in probfuncs: # p < 1.0 + out = func(np.array([0.5])) + + else: + out = func(self.argOne) + + assert_equal(out.shape, self.tgtShape) + + def test_two_arg_funcs(self): + funcs = (np.random.uniform, np.random.normal, + np.random.beta, np.random.gamma, + np.random.f, np.random.noncentral_chisquare, + np.random.vonmises, np.random.laplace, + np.random.gumbel, np.random.logistic, + np.random.lognormal, np.random.wald, + np.random.binomial, np.random.negative_binomial) + + probfuncs = (np.random.binomial, np.random.negative_binomial) + + for func in funcs: + if func in probfuncs: # p <= 1 + argTwo = np.array([0.5]) + + else: + argTwo = self.argTwo + + out = func(self.argOne, argTwo) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne[0], argTwo) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne, argTwo[0]) + assert_equal(out.shape, self.tgtShape) + +# TODO: Uncomment once randint can broadcast arguments +# def test_randint(self): +# itype = [bool, np.int8, np.uint8, np.int16, np.uint16, +# np.int32, np.uint32, np.int64, np.uint64] +# func = np.random.randint +# high = np.array([1]) +# low = np.array([0]) +# +# for dt in itype: +# out = func(low, high, dtype=dt) +# self.assert_equal(out.shape, self.tgtShape) +# +# out = func(low[0], high, dtype=dt) +# self.assert_equal(out.shape, self.tgtShape) +# +# out = func(low, high[0], dtype=dt) +# self.assert_equal(out.shape, self.tgtShape) + + def test_three_arg_funcs(self): + funcs = [np.random.noncentral_f, np.random.triangular, + np.random.hypergeometric] + + for func in funcs: + out = func(self.argOne, self.argTwo, self.argThree) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne[0], self.argTwo, self.argThree) + assert_equal(out.shape, self.tgtShape) + + out = func(self.argOne, self.argTwo[0], self.argThree) + assert_equal(out.shape, self.tgtShape) + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/random/tests/test_regression.py b/numpy/random/tests/test_regression.py new file mode 100644 index 0000000..572f4c0 --- /dev/null +++ b/numpy/random/tests/test_regression.py @@ -0,0 +1,138 @@ +from __future__ import division, absolute_import, print_function + +import sys +from numpy.testing import ( + run_module_suite, assert_, assert_array_equal, assert_raises, + ) +from numpy import random +from numpy.compat import long +import numpy as np + + +class TestRegression(object): + + def test_VonMises_range(self): + # Make sure generated random variables are in [-pi, pi]. + # Regression test for ticket #986. + for mu in np.linspace(-7., 7., 5): + r = random.mtrand.vonmises(mu, 1, 50) + assert_(np.all(r > -np.pi) and np.all(r <= np.pi)) + + def test_hypergeometric_range(self): + # Test for ticket #921 + assert_(np.all(np.random.hypergeometric(3, 18, 11, size=10) < 4)) + assert_(np.all(np.random.hypergeometric(18, 3, 11, size=10) > 0)) + + # Test for ticket #5623 + args = [ + (2**20 - 2, 2**20 - 2, 2**20 - 2), # Check for 32-bit systems + ] + is_64bits = sys.maxsize > 2**32 + if is_64bits and sys.platform != 'win32': + args.append((2**40 - 2, 2**40 - 2, 2**40 - 2)) # Check for 64-bit systems + for arg in args: + assert_(np.random.hypergeometric(*arg) > 0) + + def test_logseries_convergence(self): + # Test for ticket #923 + N = 1000 + np.random.seed(0) + rvsn = np.random.logseries(0.8, size=N) + # these two frequency counts should be close to theoretical + # numbers with this large sample + # theoretical large N result is 0.49706795 + freq = np.sum(rvsn == 1) / float(N) + msg = "Frequency was %f, should be > 0.45" % freq + assert_(freq > 0.45, msg) + # theoretical large N result is 0.19882718 + freq = np.sum(rvsn == 2) / float(N) + msg = "Frequency was %f, should be < 0.23" % freq + assert_(freq < 0.23, msg) + + def test_permutation_longs(self): + np.random.seed(1234) + a = np.random.permutation(12) + np.random.seed(1234) + b = np.random.permutation(long(12)) + assert_array_equal(a, b) + + def test_shuffle_mixed_dimension(self): + # Test for trac ticket #2074 + for t in [[1, 2, 3, None], + [(1, 1), (2, 2), (3, 3), None], + [1, (2, 2), (3, 3), None], + [(1, 1), 2, 3, None]]: + np.random.seed(12345) + shuffled = list(t) + random.shuffle(shuffled) + assert_array_equal(shuffled, [t[0], t[3], t[1], t[2]]) + + def test_call_within_randomstate(self): + # Check that custom RandomState does not call into global state + m = np.random.RandomState() + res = np.array([0, 8, 7, 2, 1, 9, 4, 7, 0, 3]) + for i in range(3): + np.random.seed(i) + m.seed(4321) + # If m.state is not honored, the result will change + assert_array_equal(m.choice(10, size=10, p=np.ones(10)/10.), res) + + def test_multivariate_normal_size_types(self): + # Test for multivariate_normal issue with 'size' argument. + # Check that the multivariate_normal size argument can be a + # numpy integer. + np.random.multivariate_normal([0], [[0]], size=1) + np.random.multivariate_normal([0], [[0]], size=np.int_(1)) + np.random.multivariate_normal([0], [[0]], size=np.int64(1)) + + def test_beta_small_parameters(self): + # Test that beta with small a and b parameters does not produce + # NaNs due to roundoff errors causing 0 / 0, gh-5851 + np.random.seed(1234567890) + x = np.random.beta(0.0001, 0.0001, size=100) + assert_(not np.any(np.isnan(x)), 'Nans in np.random.beta') + + def test_choice_sum_of_probs_tolerance(self): + # The sum of probs should be 1.0 with some tolerance. + # For low precision dtypes the tolerance was too tight. + # See numpy github issue 6123. + np.random.seed(1234) + a = [1, 2, 3] + counts = [4, 4, 2] + for dt in np.float16, np.float32, np.float64: + probs = np.array(counts, dtype=dt) / sum(counts) + c = np.random.choice(a, p=probs) + assert_(c in a) + assert_raises(ValueError, np.random.choice, a, p=probs*0.9) + + def test_shuffle_of_array_of_different_length_strings(self): + # Test that permuting an array of different length strings + # will not cause a segfault on garbage collection + # Tests gh-7710 + np.random.seed(1234) + + a = np.array(['a', 'a' * 1000]) + + for _ in range(100): + np.random.shuffle(a) + + # Force Garbage Collection - should not segfault. + import gc + gc.collect() + + def test_shuffle_of_array_of_objects(self): + # Test that permuting an array of objects will not cause + # a segfault on garbage collection. + # See gh-7719 + np.random.seed(1234) + a = np.array([np.arange(1), np.arange(4)]) + + for _ in range(1000): + np.random.shuffle(a) + + # Force Garbage Collection - should not segfault. + import gc + gc.collect() + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/setup.py b/numpy/setup.py new file mode 100644 index 0000000..4ccdaee --- /dev/null +++ b/numpy/setup.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +from __future__ import division, print_function + + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('numpy', parent_package, top_path) + + config.add_subpackage('compat') + config.add_subpackage('core') + config.add_subpackage('distutils') + config.add_subpackage('doc') + config.add_subpackage('f2py') + config.add_subpackage('fft') + config.add_subpackage('lib') + config.add_subpackage('linalg') + config.add_subpackage('ma') + config.add_subpackage('matrixlib') + config.add_subpackage('polynomial') + config.add_subpackage('random') + config.add_subpackage('testing') + config.add_data_dir('doc') + config.add_data_dir('tests') + config.make_config_py() # installs __config__.py + return config + +if __name__ == '__main__': + print('This is the wrong setup.py file to run') diff --git a/numpy/testing/__init__.py b/numpy/testing/__init__.py new file mode 100644 index 0000000..9485b45 --- /dev/null +++ b/numpy/testing/__init__.py @@ -0,0 +1,15 @@ +"""Common test support for all numpy test scripts. + +This single module should provide all the common functionality for numpy tests +in a single location, so that test scripts can just import it and work right +away. + +""" +from __future__ import division, absolute_import, print_function + +from unittest import TestCase + +from . import decorators as dec +from .nosetester import run_module_suite, NoseTester as Tester, _numpy_tester +from .utils import * +test = _numpy_tester().test diff --git a/numpy/testing/decorators.py b/numpy/testing/decorators.py new file mode 100644 index 0000000..b638500 --- /dev/null +++ b/numpy/testing/decorators.py @@ -0,0 +1,6 @@ +""" +Back compatibility decorators module. It will import the appropriate +set of tools + +""" +from .nose_tools.decorators import * diff --git a/numpy/testing/nose_tools/__init__.py b/numpy/testing/nose_tools/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/testing/nose_tools/__init__.py diff --git a/numpy/testing/nose_tools/decorators.py b/numpy/testing/nose_tools/decorators.py new file mode 100644 index 0000000..12531e7 --- /dev/null +++ b/numpy/testing/nose_tools/decorators.py @@ -0,0 +1,282 @@ +""" +Decorators for labeling and modifying behavior of test objects. + +Decorators that merely return a modified version of the original +function object are straightforward. Decorators that return a new +function object need to use +:: + + nose.tools.make_decorator(original_function)(decorator) + +in returning the decorator, in order to preserve meta-data such as +function name, setup and teardown functions and so on - see +``nose.tools`` for more information. + +""" +from __future__ import division, absolute_import, print_function + +import collections + +from .utils import SkipTest, assert_warns + + +def slow(t): + """ + Label a test as 'slow'. + + The exact definition of a slow test is obviously both subjective and + hardware-dependent, but in general any individual test that requires more + than a second or two should be labeled as slow (the whole suite consits of + thousands of tests, so even a second is significant). + + Parameters + ---------- + t : callable + The test to label as slow. + + Returns + ------- + t : callable + The decorated test `t`. + + Examples + -------- + The `numpy.testing` module includes ``import decorators as dec``. + A test can be decorated as slow like this:: + + from numpy.testing import * + + @dec.slow + def test_big(self): + print('Big, slow test') + + """ + + t.slow = True + return t + +def setastest(tf=True): + """ + Signals to nose that this function is or is not a test. + + Parameters + ---------- + tf : bool + If True, specifies that the decorated callable is a test. + If False, specifies that the decorated callable is not a test. + Default is True. + + Notes + ----- + This decorator can't use the nose namespace, because it can be + called from a non-test module. See also ``istest`` and ``nottest`` in + ``nose.tools``. + + Examples + -------- + `setastest` can be used in the following way:: + + from numpy.testing import dec + + @dec.setastest(False) + def func_with_test_in_name(arg1, arg2): + pass + + """ + def set_test(t): + t.__test__ = tf + return t + return set_test + +def skipif(skip_condition, msg=None): + """ + Make function raise SkipTest exception if a given condition is true. + + If the condition is a callable, it is used at runtime to dynamically + make the decision. This is useful for tests that may require costly + imports, to delay the cost until the test suite is actually executed. + + Parameters + ---------- + skip_condition : bool or callable + Flag to determine whether to skip the decorated test. + msg : str, optional + Message to give on raising a SkipTest exception. Default is None. + + Returns + ------- + decorator : function + Decorator which, when applied to a function, causes SkipTest + to be raised when `skip_condition` is True, and the function + to be called normally otherwise. + + Notes + ----- + The decorator itself is decorated with the ``nose.tools.make_decorator`` + function in order to transmit function name, and various other metadata. + + """ + + def skip_decorator(f): + # Local import to avoid a hard nose dependency and only incur the + # import time overhead at actual test-time. + import nose + + # Allow for both boolean or callable skip conditions. + if isinstance(skip_condition, collections.Callable): + skip_val = lambda: skip_condition() + else: + skip_val = lambda: skip_condition + + def get_msg(func,msg=None): + """Skip message with information about function being skipped.""" + if msg is None: + out = 'Test skipped due to test condition' + else: + out = msg + + return "Skipping test: %s: %s" % (func.__name__, out) + + # We need to define *two* skippers because Python doesn't allow both + # return with value and yield inside the same function. + def skipper_func(*args, **kwargs): + """Skipper for normal test functions.""" + if skip_val(): + raise SkipTest(get_msg(f, msg)) + else: + return f(*args, **kwargs) + + def skipper_gen(*args, **kwargs): + """Skipper for test generators.""" + if skip_val(): + raise SkipTest(get_msg(f, msg)) + else: + for x in f(*args, **kwargs): + yield x + + # Choose the right skipper to use when building the actual decorator. + if nose.util.isgenerator(f): + skipper = skipper_gen + else: + skipper = skipper_func + + return nose.tools.make_decorator(f)(skipper) + + return skip_decorator + + +def knownfailureif(fail_condition, msg=None): + """ + Make function raise KnownFailureException exception if given condition is true. + + If the condition is a callable, it is used at runtime to dynamically + make the decision. This is useful for tests that may require costly + imports, to delay the cost until the test suite is actually executed. + + Parameters + ---------- + fail_condition : bool or callable + Flag to determine whether to mark the decorated test as a known + failure (if True) or not (if False). + msg : str, optional + Message to give on raising a KnownFailureException exception. + Default is None. + + Returns + ------- + decorator : function + Decorator, which, when applied to a function, causes + KnownFailureException to be raised when `fail_condition` is True, + and the function to be called normally otherwise. + + Notes + ----- + The decorator itself is decorated with the ``nose.tools.make_decorator`` + function in order to transmit function name, and various other metadata. + + """ + if msg is None: + msg = 'Test skipped due to known failure' + + # Allow for both boolean or callable known failure conditions. + if isinstance(fail_condition, collections.Callable): + fail_val = lambda: fail_condition() + else: + fail_val = lambda: fail_condition + + def knownfail_decorator(f): + # Local import to avoid a hard nose dependency and only incur the + # import time overhead at actual test-time. + import nose + from .noseclasses import KnownFailureException + + def knownfailer(*args, **kwargs): + if fail_val(): + raise KnownFailureException(msg) + else: + return f(*args, **kwargs) + return nose.tools.make_decorator(f)(knownfailer) + + return knownfail_decorator + +def deprecated(conditional=True): + """ + Filter deprecation warnings while running the test suite. + + This decorator can be used to filter DeprecationWarning's, to avoid + printing them during the test suite run, while checking that the test + actually raises a DeprecationWarning. + + Parameters + ---------- + conditional : bool or callable, optional + Flag to determine whether to mark test as deprecated or not. If the + condition is a callable, it is used at runtime to dynamically make the + decision. Default is True. + + Returns + ------- + decorator : function + The `deprecated` decorator itself. + + Notes + ----- + .. versionadded:: 1.4.0 + + """ + def deprecate_decorator(f): + # Local import to avoid a hard nose dependency and only incur the + # import time overhead at actual test-time. + import nose + + def _deprecated_imp(*args, **kwargs): + # Poor man's replacement for the with statement + with assert_warns(DeprecationWarning): + f(*args, **kwargs) + + if isinstance(conditional, collections.Callable): + cond = conditional() + else: + cond = conditional + if cond: + return nose.tools.make_decorator(f)(_deprecated_imp) + else: + return f + return deprecate_decorator + + +def parametrize(vars, input): + """ + Pytest compatibility class. This implements the simplest level of + pytest.mark.parametrize for use in nose as an aid in making the transition + to pytest. It achieves that by adding a dummy var parameter and ignoring + the doc_func parameter of the base class. It does not support variable + substitution by name, nor does it support nesting or classes. See the + pytest documentation for usage. + + .. versionadded:: 1.14.0 + + """ + from .parameterized import parameterized + + return parameterized(input) diff --git a/numpy/testing/nose_tools/noseclasses.py b/numpy/testing/nose_tools/noseclasses.py new file mode 100644 index 0000000..9756b9b --- /dev/null +++ b/numpy/testing/nose_tools/noseclasses.py @@ -0,0 +1,366 @@ +# These classes implement a doctest runner plugin for nose, a "known failure" +# error class, and a customized TestProgram for NumPy. + +# Because this module imports nose directly, it should not +# be used except by nosetester.py to avoid a general NumPy +# dependency on nose. +from __future__ import division, absolute_import, print_function + +import os +import sys +import doctest +import inspect + +import numpy +import nose +from nose.plugins import doctests as npd +from nose.plugins.errorclass import ErrorClass, ErrorClassPlugin +from nose.plugins.base import Plugin +from nose.util import src +from .nosetester import get_package_name +from .utils import KnownFailureException, KnownFailureTest + + +# Some of the classes in this module begin with 'Numpy' to clearly distinguish +# them from the plethora of very similar names from nose/unittest/doctest + +#----------------------------------------------------------------------------- +# Modified version of the one in the stdlib, that fixes a python bug (doctests +# not found in extension modules, http://bugs.python.org/issue3158) +class NumpyDocTestFinder(doctest.DocTestFinder): + + def _from_module(self, module, object): + """ + Return true if the given object is defined in the given + module. + """ + if module is None: + return True + elif inspect.isfunction(object): + return module.__dict__ is object.__globals__ + elif inspect.isbuiltin(object): + return module.__name__ == object.__module__ + elif inspect.isclass(object): + return module.__name__ == object.__module__ + elif inspect.ismethod(object): + # This one may be a bug in cython that fails to correctly set the + # __module__ attribute of methods, but since the same error is easy + # to make by extension code writers, having this safety in place + # isn't such a bad idea + return module.__name__ == object.__self__.__class__.__module__ + elif inspect.getmodule(object) is not None: + return module is inspect.getmodule(object) + elif hasattr(object, '__module__'): + return module.__name__ == object.__module__ + elif isinstance(object, property): + return True # [XX] no way not be sure. + else: + raise ValueError("object must be a class or function") + + def _find(self, tests, obj, name, module, source_lines, globs, seen): + """ + Find tests for the given object and any contained objects, and + add them to `tests`. + """ + + doctest.DocTestFinder._find(self, tests, obj, name, module, + source_lines, globs, seen) + + # Below we re-run pieces of the above method with manual modifications, + # because the original code is buggy and fails to correctly identify + # doctests in extension modules. + + # Local shorthands + from inspect import ( + isroutine, isclass, ismodule, isfunction, ismethod + ) + + # Look for tests in a module's contained objects. + if ismodule(obj) and self._recurse: + for valname, val in obj.__dict__.items(): + valname1 = '%s.%s' % (name, valname) + if ( (isroutine(val) or isclass(val)) + and self._from_module(module, val)): + + self._find(tests, val, valname1, module, source_lines, + globs, seen) + + # Look for tests in a class's contained objects. + if isclass(obj) and self._recurse: + for valname, val in obj.__dict__.items(): + # Special handling for staticmethod/classmethod. + if isinstance(val, staticmethod): + val = getattr(obj, valname) + if isinstance(val, classmethod): + val = getattr(obj, valname).__func__ + + # Recurse to methods, properties, and nested classes. + if ((isfunction(val) or isclass(val) or + ismethod(val) or isinstance(val, property)) and + self._from_module(module, val)): + valname = '%s.%s' % (name, valname) + self._find(tests, val, valname, module, source_lines, + globs, seen) + + +# second-chance checker; if the default comparison doesn't +# pass, then see if the expected output string contains flags that +# tell us to ignore the output +class NumpyOutputChecker(doctest.OutputChecker): + def check_output(self, want, got, optionflags): + ret = doctest.OutputChecker.check_output(self, want, got, + optionflags) + if not ret: + if "#random" in want: + return True + + # it would be useful to normalize endianness so that + # bigendian machines don't fail all the tests (and there are + # actually some bigendian examples in the doctests). Let's try + # making them all little endian + got = got.replace("'>", "'<") + want = want.replace("'>", "'<") + + # try to normalize out 32 and 64 bit default int sizes + for sz in [4, 8]: + got = got.replace("'>> np.testing.nosetester.get_package_name('nonsense') + 'numpy' + + """ + + fullpath = filepath[:] + pkg_name = [] + while 'site-packages' in filepath or 'dist-packages' in filepath: + filepath, p2 = os.path.split(filepath) + if p2 in ('site-packages', 'dist-packages'): + break + pkg_name.append(p2) + + # if package name determination failed, just default to numpy/scipy + if not pkg_name: + if 'scipy' in fullpath: + return 'scipy' + else: + return 'numpy' + + # otherwise, reverse to get correct order and return + pkg_name.reverse() + + # don't include the outer egg directory + if pkg_name[0].endswith('.egg'): + pkg_name.pop(0) + + return '.'.join(pkg_name) + + +def run_module_suite(file_to_run=None, argv=None): + """ + Run a test module. + + Equivalent to calling ``$ nosetests `` from + the command line + + Parameters + ---------- + file_to_run : str, optional + Path to test module, or None. + By default, run the module from which this function is called. + argv : list of strings + Arguments to be passed to the nose test runner. ``argv[0]`` is + ignored. All command line arguments accepted by ``nosetests`` + will work. If it is the default value None, sys.argv is used. + + .. versionadded:: 1.9.0 + + Examples + -------- + Adding the following:: + + if __name__ == "__main__" : + run_module_suite(argv=sys.argv) + + at the end of a test module will run the tests when that module is + called in the python interpreter. + + Alternatively, calling:: + + >>> run_module_suite(file_to_run="numpy/tests/test_matlib.py") + + from an interpreter will run all the test routine in 'test_matlib.py'. + """ + if file_to_run is None: + f = sys._getframe(1) + file_to_run = f.f_locals.get('__file__', None) + if file_to_run is None: + raise AssertionError + + if argv is None: + argv = sys.argv + [file_to_run] + else: + argv = argv + [file_to_run] + + nose = import_nose() + from .noseclasses import KnownFailurePlugin + nose.run(argv=argv, addplugins=[KnownFailurePlugin()]) + + +class NoseTester(object): + """ + Nose test runner. + + This class is made available as numpy.testing.Tester, and a test function + is typically added to a package's __init__.py like so:: + + from numpy.testing import Tester + test = Tester().test + + Calling this test function finds and runs all tests associated with the + package and all its sub-packages. + + Attributes + ---------- + package_path : str + Full path to the package to test. + package_name : str + Name of the package to test. + + Parameters + ---------- + package : module, str or None, optional + The package to test. If a string, this should be the full path to + the package. If None (default), `package` is set to the module from + which `NoseTester` is initialized. + raise_warnings : None, str or sequence of warnings, optional + This specifies which warnings to configure as 'raise' instead + of being shown once during the test execution. Valid strings are: + + - "develop" : equals ``(Warning,)`` + - "release" : equals ``()``, don't raise on any warnings. + + Default is "release". + depth : int, optional + If `package` is None, then this can be used to initialize from the + module of the caller of (the caller of (...)) the code that + initializes `NoseTester`. Default of 0 means the module of the + immediate caller; higher values are useful for utility routines that + want to initialize `NoseTester` objects on behalf of other code. + + """ + def __init__(self, package=None, raise_warnings="release", depth=0, + check_fpu_mode=False): + # Back-compat: 'None' used to mean either "release" or "develop" + # depending on whether this was a release or develop version of + # numpy. Those semantics were fine for testing numpy, but not so + # helpful for downstream projects like scipy that use + # numpy.testing. (They want to set this based on whether *they* are a + # release or develop version, not whether numpy is.) So we continue to + # accept 'None' for back-compat, but it's now just an alias for the + # default "release". + if raise_warnings is None: + raise_warnings = "release" + + package_name = None + if package is None: + f = sys._getframe(1 + depth) + package_path = f.f_locals.get('__file__', None) + if package_path is None: + raise AssertionError + package_path = os.path.dirname(package_path) + package_name = f.f_locals.get('__name__', None) + elif isinstance(package, type(os)): + package_path = os.path.dirname(package.__file__) + package_name = getattr(package, '__name__', None) + else: + package_path = str(package) + + self.package_path = package_path + + # Find the package name under test; this name is used to limit coverage + # reporting (if enabled). + if package_name is None: + package_name = get_package_name(package_path) + self.package_name = package_name + + # Set to "release" in constructor in maintenance branches. + self.raise_warnings = raise_warnings + + # Whether to check for FPU mode changes + self.check_fpu_mode = check_fpu_mode + + def _test_argv(self, label, verbose, extra_argv): + ''' Generate argv for nosetest command + + Parameters + ---------- + label : {'fast', 'full', '', attribute identifier}, optional + see ``test`` docstring + verbose : int, optional + Verbosity value for test outputs, in the range 1-10. Default is 1. + extra_argv : list, optional + List with any extra arguments to pass to nosetests. + + Returns + ------- + argv : list + command line arguments that will be passed to nose + ''' + argv = [__file__, self.package_path, '-s'] + if label and label != 'full': + if not isinstance(label, basestring): + raise TypeError('Selection label should be a string') + if label == 'fast': + label = 'not slow' + argv += ['-A', label] + argv += ['--verbosity', str(verbose)] + + # When installing with setuptools, and also in some other cases, the + # test_*.py files end up marked +x executable. Nose, by default, does + # not run files marked with +x as they might be scripts. However, in + # our case nose only looks for test_*.py files under the package + # directory, which should be safe. + argv += ['--exe'] + + if extra_argv: + argv += extra_argv + return argv + + def _show_system_info(self): + nose = import_nose() + + import numpy + print("NumPy version %s" % numpy.__version__) + relaxed_strides = numpy.ones((10, 1), order="C").flags.f_contiguous + print("NumPy relaxed strides checking option:", relaxed_strides) + npdir = os.path.dirname(numpy.__file__) + print("NumPy is installed in %s" % npdir) + + if 'scipy' in self.package_name: + import scipy + print("SciPy version %s" % scipy.__version__) + spdir = os.path.dirname(scipy.__file__) + print("SciPy is installed in %s" % spdir) + + pyversion = sys.version.replace('\n', '') + print("Python version %s" % pyversion) + print("nose version %d.%d.%d" % nose.__versioninfo__) + + def _get_custom_doctester(self): + """ Return instantiated plugin for doctests + + Allows subclassing of this class to override doctester + + A return value of None means use the nose builtin doctest plugin + """ + from .noseclasses import NumpyDoctest + return NumpyDoctest() + + def prepare_test_args(self, label='fast', verbose=1, extra_argv=None, + doctests=False, coverage=False, timer=False): + """ + Run tests for module using nose. + + This method does the heavy lifting for the `test` method. It takes all + the same arguments, for details see `test`. + + See Also + -------- + test + + """ + # fail with nice error message if nose is not present + import_nose() + # compile argv + argv = self._test_argv(label, verbose, extra_argv) + # our way of doing coverage + if coverage: + argv += ['--cover-package=%s' % self.package_name, '--with-coverage', + '--cover-tests', '--cover-erase'] + + if timer: + if timer is True: + argv += ['--with-timer'] + elif isinstance(timer, int): + argv += ['--with-timer', '--timer-top-n', str(timer)] + + # construct list of plugins + import nose.plugins.builtin + from nose.plugins import EntryPointPluginManager + from .noseclasses import (KnownFailurePlugin, Unplugger, + FPUModeCheckPlugin) + plugins = [KnownFailurePlugin()] + plugins += [p() for p in nose.plugins.builtin.plugins] + if self.check_fpu_mode: + plugins += [FPUModeCheckPlugin()] + argv += ["--with-fpumodecheckplugin"] + try: + # External plugins (like nose-timer) + entrypoint_manager = EntryPointPluginManager() + entrypoint_manager.loadPlugins() + plugins += [p for p in entrypoint_manager.plugins] + except ImportError: + # Relies on pkg_resources, not a hard dependency + pass + + # add doctesting if required + doctest_argv = '--with-doctest' in argv + if doctests == False and doctest_argv: + doctests = True + plug = self._get_custom_doctester() + if plug is None: + # use standard doctesting + if doctests and not doctest_argv: + argv += ['--with-doctest'] + else: # custom doctesting + if doctest_argv: # in fact the unplugger would take care of this + argv.remove('--with-doctest') + plugins += [Unplugger('doctest'), plug] + if doctests: + argv += ['--with-' + plug.name] + return argv, plugins + + def test(self, label='fast', verbose=1, extra_argv=None, + doctests=False, coverage=False, raise_warnings=None, + timer=False): + """ + Run tests for module using nose. + + Parameters + ---------- + label : {'fast', 'full', '', attribute identifier}, optional + Identifies the tests to run. This can be a string to pass to + the nosetests executable with the '-A' option, or one of several + special values. Special values are: + * 'fast' - the default - which corresponds to the ``nosetests -A`` + option of 'not slow'. + * 'full' - fast (as above) and slow tests as in the + 'no -A' option to nosetests - this is the same as ''. + * None or '' - run all tests. + attribute_identifier - string passed directly to nosetests as '-A'. + verbose : int, optional + Verbosity value for test outputs, in the range 1-10. Default is 1. + extra_argv : list, optional + List with any extra arguments to pass to nosetests. + doctests : bool, optional + If True, run doctests in module. Default is False. + coverage : bool, optional + If True, report coverage of NumPy code. Default is False. + (This requires the `coverage module: + `_). + raise_warnings : None, str or sequence of warnings, optional + This specifies which warnings to configure as 'raise' instead + of being shown once during the test execution. Valid strings are: + + - "develop" : equals ``(Warning,)`` + - "release" : equals ``()``, don't raise on any warnings. + + The default is to use the class initialization value. + timer : bool or int, optional + Timing of individual tests with ``nose-timer`` (which needs to be + installed). If True, time tests and report on all of them. + If an integer (say ``N``), report timing results for ``N`` slowest + tests. + + Returns + ------- + result : object + Returns the result of running the tests as a + ``nose.result.TextTestResult`` object. + + Notes + ----- + Each NumPy module exposes `test` in its namespace to run all tests for it. + For example, to run all tests for numpy.lib: + + >>> np.lib.test() #doctest: +SKIP + + Examples + -------- + >>> result = np.lib.test() #doctest: +SKIP + Running unit tests for numpy.lib + ... + Ran 976 tests in 3.933s + + OK + + >>> result.errors #doctest: +SKIP + [] + >>> result.knownfail #doctest: +SKIP + [] + """ + + # cap verbosity at 3 because nose becomes *very* verbose beyond that + verbose = min(verbose, 3) + + from . import utils + utils.verbose = verbose + + argv, plugins = self.prepare_test_args( + label, verbose, extra_argv, doctests, coverage, timer) + + if doctests: + print("Running unit tests and doctests for %s" % self.package_name) + else: + print("Running unit tests for %s" % self.package_name) + + self._show_system_info() + + # reset doctest state on every run + import doctest + doctest.master = None + + if raise_warnings is None: + raise_warnings = self.raise_warnings + + _warn_opts = dict(develop=(Warning,), + release=()) + if isinstance(raise_warnings, basestring): + raise_warnings = _warn_opts[raise_warnings] + + with suppress_warnings("location") as sup: + # Reset the warning filters to the default state, + # so that running the tests is more repeatable. + warnings.resetwarnings() + # Set all warnings to 'warn', this is because the default 'once' + # has the bad property of possibly shadowing later warnings. + warnings.filterwarnings('always') + # Force the requested warnings to raise + for warningtype in raise_warnings: + warnings.filterwarnings('error', category=warningtype) + # Filter out annoying import messages. + sup.filter(message='Not importing directory') + sup.filter(message="numpy.dtype size changed") + sup.filter(message="numpy.ufunc size changed") + sup.filter(category=np.ModuleDeprecationWarning) + # Filter out boolean '-' deprecation messages. This allows + # older versions of scipy to test without a flood of messages. + sup.filter(message=".*boolean negative.*") + sup.filter(message=".*boolean subtract.*") + # Filter out distutils cpu warnings (could be localized to + # distutils tests). ASV has problems with top level import, + # so fetch module for suppression here. + with warnings.catch_warnings(): + warnings.simplefilter("always") + from ...distutils import cpuinfo + sup.filter(category=UserWarning, module=cpuinfo) + # See #7949: Filter out deprecation warnings due to the -3 flag to + # python 2 + if sys.version_info.major == 2 and sys.py3kwarning: + # This is very specific, so using the fragile module filter + # is fine + import threading + sup.filter(DeprecationWarning, + r"sys\.exc_clear\(\) not supported in 3\.x", + module=threading) + sup.filter(DeprecationWarning, message=r"in 3\.x, __setslice__") + sup.filter(DeprecationWarning, message=r"in 3\.x, __getslice__") + sup.filter(DeprecationWarning, message=r"buffer\(\) not supported in 3\.x") + sup.filter(DeprecationWarning, message=r"CObject type is not supported in 3\.x") + sup.filter(DeprecationWarning, message=r"comparing unequal types not supported in 3\.x") + # Filter out some deprecation warnings inside nose 1.3.7 when run + # on python 3.5b2. See + # https://github.com/nose-devs/nose/issues/929 + # Note: it is hard to filter based on module for sup (lineno could + # be implemented). + warnings.filterwarnings("ignore", message=".*getargspec.*", + category=DeprecationWarning, + module=r"nose\.") + + from .noseclasses import NumpyTestProgram + + t = NumpyTestProgram(argv=argv, exit=False, plugins=plugins) + + return t.result + + def bench(self, label='fast', verbose=1, extra_argv=None): + """ + Run benchmarks for module using nose. + + Parameters + ---------- + label : {'fast', 'full', '', attribute identifier}, optional + Identifies the benchmarks to run. This can be a string to pass to + the nosetests executable with the '-A' option, or one of several + special values. Special values are: + * 'fast' - the default - which corresponds to the ``nosetests -A`` + option of 'not slow'. + * 'full' - fast (as above) and slow benchmarks as in the + 'no -A' option to nosetests - this is the same as ''. + * None or '' - run all tests. + attribute_identifier - string passed directly to nosetests as '-A'. + verbose : int, optional + Verbosity value for benchmark outputs, in the range 1-10. Default is 1. + extra_argv : list, optional + List with any extra arguments to pass to nosetests. + + Returns + ------- + success : bool + Returns True if running the benchmarks works, False if an error + occurred. + + Notes + ----- + Benchmarks are like tests, but have names starting with "bench" instead + of "test", and can be found under the "benchmarks" sub-directory of the + module. + + Each NumPy module exposes `bench` in its namespace to run all benchmarks + for it. + + Examples + -------- + >>> success = np.lib.bench() #doctest: +SKIP + Running benchmarks for numpy.lib + ... + using 562341 items: + unique: + 0.11 + unique1d: + 0.11 + ratio: 1.0 + nUnique: 56230 == 56230 + ... + OK + + >>> success #doctest: +SKIP + True + + """ + + print("Running benchmarks for %s" % self.package_name) + self._show_system_info() + + argv = self._test_argv(label, verbose, extra_argv) + argv += ['--match', r'(?:^|[\\b_\\.%s-])[Bb]ench' % os.sep] + + # import nose or make informative error + nose = import_nose() + + # get plugin to disable doctests + from .noseclasses import Unplugger + add_plugins = [Unplugger('doctest')] + + return nose.run(argv=argv, addplugins=add_plugins) + + +def _numpy_tester(): + if hasattr(np, "__version__") and ".dev0" in np.__version__: + mode = "develop" + else: + mode = "release" + return NoseTester(raise_warnings=mode, depth=1, + check_fpu_mode=True) diff --git a/numpy/testing/nose_tools/parameterized.py b/numpy/testing/nose_tools/parameterized.py new file mode 100644 index 0000000..962fddc --- /dev/null +++ b/numpy/testing/nose_tools/parameterized.py @@ -0,0 +1,489 @@ +""" +tl;dr: all code code is licensed under simplified BSD, unless stated otherwise. + +Unless stated otherwise in the source files, all code is copyright 2010 David +Wolever . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of David Wolever. + +""" +import re +import sys +import inspect +import warnings +from functools import wraps +from types import MethodType as MethodType +from collections import namedtuple + +try: + from collections import OrderedDict as MaybeOrderedDict +except ImportError: + MaybeOrderedDict = dict + +from unittest import TestCase + +PY3 = sys.version_info[0] == 3 +PY2 = sys.version_info[0] == 2 + + +if PY3: + # Python 3 doesn't have an InstanceType, so just use a dummy type. + class InstanceType(): + pass + lzip = lambda *a: list(zip(*a)) + text_type = str + string_types = str, + bytes_type = bytes + def make_method(func, instance, type): + if instance is None: + return func + return MethodType(func, instance) +else: + from types import InstanceType + lzip = zip + text_type = unicode + bytes_type = str + string_types = basestring, + def make_method(func, instance, type): + return MethodType(func, instance, type) + +_param = namedtuple("param", "args kwargs") + +class param(_param): + """ Represents a single parameter to a test case. + + For example:: + + >>> p = param("foo", bar=16) + >>> p + param("foo", bar=16) + >>> p.args + ('foo', ) + >>> p.kwargs + {'bar': 16} + + Intended to be used as an argument to ``@parameterized``:: + + @parameterized([ + param("foo", bar=16), + ]) + def test_stuff(foo, bar=16): + pass + """ + + def __new__(cls, *args , **kwargs): + return _param.__new__(cls, args, kwargs) + + @classmethod + def explicit(cls, args=None, kwargs=None): + """ Creates a ``param`` by explicitly specifying ``args`` and + ``kwargs``:: + + >>> param.explicit([1,2,3]) + param(*(1, 2, 3)) + >>> param.explicit(kwargs={"foo": 42}) + param(*(), **{"foo": "42"}) + """ + args = args or () + kwargs = kwargs or {} + return cls(*args, **kwargs) + + @classmethod + def from_decorator(cls, args): + """ Returns an instance of ``param()`` for ``@parameterized`` argument + ``args``:: + + >>> param.from_decorator((42, )) + param(args=(42, ), kwargs={}) + >>> param.from_decorator("foo") + param(args=("foo", ), kwargs={}) + """ + if isinstance(args, param): + return args + elif isinstance(args, string_types): + args = (args, ) + try: + return cls(*args) + except TypeError as e: + if "after * must be" not in str(e): + raise + raise TypeError( + "Parameters must be tuples, but %r is not (hint: use '(%r, )')" + %(args, args), + ) + + def __repr__(self): + return "param(*%r, **%r)" %self + + +class QuietOrderedDict(MaybeOrderedDict): + """ When OrderedDict is available, use it to make sure that the kwargs in + doc strings are consistently ordered. """ + __str__ = dict.__str__ + __repr__ = dict.__repr__ + + +def parameterized_argument_value_pairs(func, p): + """Return tuples of parameterized arguments and their values. + + This is useful if you are writing your own doc_func + function and need to know the values for each parameter name:: + + >>> def func(a, foo=None, bar=42, **kwargs): pass + >>> p = param(1, foo=7, extra=99) + >>> parameterized_argument_value_pairs(func, p) + [("a", 1), ("foo", 7), ("bar", 42), ("**kwargs", {"extra": 99})] + + If the function's first argument is named ``self`` then it will be + ignored:: + + >>> def func(self, a): pass + >>> p = param(1) + >>> parameterized_argument_value_pairs(func, p) + [("a", 1)] + + Additionally, empty ``*args`` or ``**kwargs`` will be ignored:: + + >>> def func(foo, *args): pass + >>> p = param(1) + >>> parameterized_argument_value_pairs(func, p) + [("foo", 1)] + >>> p = param(1, 16) + >>> parameterized_argument_value_pairs(func, p) + [("foo", 1), ("*args", (16, ))] + """ + argspec = inspect.getargspec(func) + arg_offset = 1 if argspec.args[:1] == ["self"] else 0 + + named_args = argspec.args[arg_offset:] + + result = lzip(named_args, p.args) + named_args = argspec.args[len(result) + arg_offset:] + varargs = p.args[len(result):] + + result.extend([ + (name, p.kwargs.get(name, default)) + for (name, default) + in zip(named_args, argspec.defaults or []) + ]) + + seen_arg_names = set([ n for (n, _) in result ]) + keywords = QuietOrderedDict(sorted([ + (name, p.kwargs[name]) + for name in p.kwargs + if name not in seen_arg_names + ])) + + if varargs: + result.append(("*%s" %(argspec.varargs, ), tuple(varargs))) + + if keywords: + result.append(("**%s" %(argspec.keywords, ), keywords)) + + return result + +def short_repr(x, n=64): + """ A shortened repr of ``x`` which is guaranteed to be ``unicode``:: + + >>> short_repr("foo") + u"foo" + >>> short_repr("123456789", n=4) + u"12...89" + """ + + x_repr = repr(x) + if isinstance(x_repr, bytes_type): + try: + x_repr = text_type(x_repr, "utf-8") + except UnicodeDecodeError: + x_repr = text_type(x_repr, "latin1") + if len(x_repr) > n: + x_repr = x_repr[:n//2] + "..." + x_repr[len(x_repr) - n//2:] + return x_repr + +def default_doc_func(func, num, p): + if func.__doc__ is None: + return None + + all_args_with_values = parameterized_argument_value_pairs(func, p) + + # Assumes that the function passed is a bound method. + descs = ["%s=%s" %(n, short_repr(v)) for n, v in all_args_with_values] + + # The documentation might be a multiline string, so split it + # and just work with the first string, ignoring the period + # at the end if there is one. + first, nl, rest = func.__doc__.lstrip().partition("\n") + suffix = "" + if first.endswith("."): + suffix = "." + first = first[:-1] + args = "%s[with %s]" %(len(first) and " " or "", ", ".join(descs)) + return "".join([first.rstrip(), args, suffix, nl, rest]) + +def default_name_func(func, num, p): + base_name = func.__name__ + name_suffix = "_%s" %(num, ) + if len(p.args) > 0 and isinstance(p.args[0], string_types): + name_suffix += "_" + parameterized.to_safe_name(p.args[0]) + return base_name + name_suffix + + +_test_runner_override = None +_test_runner_guess = False +_test_runners = set(["unittest", "unittest2", "nose", "nose2", "pytest"]) +_test_runner_aliases = { + "_pytest": "pytest", +} + +def set_test_runner(name): + global _test_runner_override + if name not in _test_runners: + raise TypeError( + "Invalid test runner: %r (must be one of: %s)" + %(name, ", ".join(_test_runners)), + ) + _test_runner_override = name + +def detect_runner(): + """ Guess which test runner we're using by traversing the stack and looking + for the first matching module. This *should* be reasonably safe, as + it's done during test disocvery where the test runner should be the + stack frame immediately outside. """ + if _test_runner_override is not None: + return _test_runner_override + global _test_runner_guess + if _test_runner_guess is False: + stack = inspect.stack() + for record in reversed(stack): + frame = record[0] + module = frame.f_globals.get("__name__").partition(".")[0] + if module in _test_runner_aliases: + module = _test_runner_aliases[module] + if module in _test_runners: + _test_runner_guess = module + break + if record[1].endswith("python2.6/unittest.py"): + _test_runner_guess = "unittest" + break + else: + _test_runner_guess = None + return _test_runner_guess + +class parameterized(object): + """ Parameterize a test case:: + + class TestInt(object): + @parameterized([ + ("A", 10), + ("F", 15), + param("10", 42, base=42) + ]) + def test_int(self, input, expected, base=16): + actual = int(input, base=base) + assert_equal(actual, expected) + + @parameterized([ + (2, 3, 5) + (3, 5, 8), + ]) + def test_add(a, b, expected): + assert_equal(a + b, expected) + """ + + def __init__(self, input, doc_func=None): + self.get_input = self.input_as_callable(input) + self.doc_func = doc_func or default_doc_func + + def __call__(self, test_func): + self.assert_not_in_testcase_subclass() + + @wraps(test_func) + def wrapper(test_self=None): + test_cls = test_self and type(test_self) + if test_self is not None: + if issubclass(test_cls, InstanceType): + raise TypeError(( + "@parameterized can't be used with old-style classes, but " + "%r has an old-style class. Consider using a new-style " + "class, or '@parameterized.expand' " + "(see http://stackoverflow.com/q/54867/71522 for more " + "information on old-style classes)." + ) %(test_self, )) + + original_doc = wrapper.__doc__ + for num, args in enumerate(wrapper.parameterized_input): + p = param.from_decorator(args) + unbound_func, nose_tuple = self.param_as_nose_tuple(test_self, test_func, num, p) + try: + wrapper.__doc__ = nose_tuple[0].__doc__ + # Nose uses `getattr(instance, test_func.__name__)` to get + # a method bound to the test instance (as opposed to a + # method bound to the instance of the class created when + # tests were being enumerated). Set a value here to make + # sure nose can get the correct test method. + if test_self is not None: + setattr(test_cls, test_func.__name__, unbound_func) + yield nose_tuple + finally: + if test_self is not None: + delattr(test_cls, test_func.__name__) + wrapper.__doc__ = original_doc + wrapper.parameterized_input = self.get_input() + wrapper.parameterized_func = test_func + test_func.__name__ = "_parameterized_original_%s" %(test_func.__name__, ) + return wrapper + + def param_as_nose_tuple(self, test_self, func, num, p): + nose_func = wraps(func)(lambda *args: func(*args[:-1], **args[-1])) + nose_func.__doc__ = self.doc_func(func, num, p) + # Track the unbound function because we need to setattr the unbound + # function onto the class for nose to work (see comments above), and + # Python 3 doesn't let us pull the function out of a bound method. + unbound_func = nose_func + if test_self is not None: + # Under nose on Py2 we need to return an unbound method to make + # sure that the `self` in the method is properly shared with the + # `self` used in `setUp` and `tearDown`. But only there. Everyone + # else needs a bound method. + func_self = ( + None if PY2 and detect_runner() == "nose" else + test_self + ) + nose_func = make_method(nose_func, func_self, type(test_self)) + return unbound_func, (nose_func, ) + p.args + (p.kwargs or {}, ) + + def assert_not_in_testcase_subclass(self): + parent_classes = self._terrible_magic_get_defining_classes() + if any(issubclass(cls, TestCase) for cls in parent_classes): + raise Exception("Warning: '@parameterized' tests won't work " + "inside subclasses of 'TestCase' - use " + "'@parameterized.expand' instead.") + + def _terrible_magic_get_defining_classes(self): + """ Returns the set of parent classes of the class currently being defined. + Will likely only work if called from the ``parameterized`` decorator. + This function is entirely @brandon_rhodes's fault, as he suggested + the implementation: http://stackoverflow.com/a/8793684/71522 + """ + stack = inspect.stack() + if len(stack) <= 4: + return [] + frame = stack[4] + code_context = frame[4] and frame[4][0].strip() + if not (code_context and code_context.startswith("class ")): + return [] + _, _, parents = code_context.partition("(") + parents, _, _ = parents.partition(")") + return eval("[" + parents + "]", frame[0].f_globals, frame[0].f_locals) + + @classmethod + def input_as_callable(cls, input): + if callable(input): + return lambda: cls.check_input_values(input()) + input_values = cls.check_input_values(input) + return lambda: input_values + + @classmethod + def check_input_values(cls, input_values): + # Explicitly convery non-list inputs to a list so that: + # 1. A helpful exception will be raised if they aren't iterable, and + # 2. Generators are unwrapped exactly once (otherwise `nosetests + # --processes=n` has issues; see: + # https://github.com/wolever/nose-parameterized/pull/31) + if not isinstance(input_values, list): + input_values = list(input_values) + return [ param.from_decorator(p) for p in input_values ] + + @classmethod + def expand(cls, input, name_func=None, doc_func=None, **legacy): + """ A "brute force" method of parameterizing test cases. Creates new + test cases and injects them into the namespace that the wrapped + function is being defined in. Useful for parameterizing tests in + subclasses of 'UnitTest', where Nose test generators don't work. + + >>> @parameterized.expand([("foo", 1, 2)]) + ... def test_add1(name, input, expected): + ... actual = add1(input) + ... assert_equal(actual, expected) + ... + >>> locals() + ... 'test_add1_foo_0': ... + >>> + """ + + if "testcase_func_name" in legacy: + warnings.warn("testcase_func_name= is deprecated; use name_func=", + DeprecationWarning, stacklevel=2) + if not name_func: + name_func = legacy["testcase_func_name"] + + if "testcase_func_doc" in legacy: + warnings.warn("testcase_func_doc= is deprecated; use doc_func=", + DeprecationWarning, stacklevel=2) + if not doc_func: + doc_func = legacy["testcase_func_doc"] + + doc_func = doc_func or default_doc_func + name_func = name_func or default_name_func + + def parameterized_expand_wrapper(f, instance=None): + stack = inspect.stack() + frame = stack[1] + frame_locals = frame[0].f_locals + + paramters = cls.input_as_callable(input)() + for num, p in enumerate(paramters): + name = name_func(f, num, p) + frame_locals[name] = cls.param_as_standalone_func(p, f, name) + frame_locals[name].__doc__ = doc_func(f, num, p) + + f.__test__ = False + return parameterized_expand_wrapper + + @classmethod + def param_as_standalone_func(cls, p, func, name): + @wraps(func) + def standalone_func(*a): + return func(*(a + p.args), **p.kwargs) + standalone_func.__name__ = name + + # place_as is used by py.test to determine what source file should be + # used for this test. + standalone_func.place_as = func + + # Remove __wrapped__ because py.test will try to look at __wrapped__ + # to determine which parameters should be used with this test case, + # and obviously we don't need it to do any parameterization. + try: + del standalone_func.__wrapped__ + except AttributeError: + pass + return standalone_func + + @classmethod + def to_safe_name(cls, s): + return str(re.sub("[^a-zA-Z0-9_]+", "_", s)) diff --git a/numpy/testing/nose_tools/utils.py b/numpy/testing/nose_tools/utils.py new file mode 100644 index 0000000..6c77e5e --- /dev/null +++ b/numpy/testing/nose_tools/utils.py @@ -0,0 +1,2229 @@ +""" +Utility function to facilitate testing. + +""" +from __future__ import division, absolute_import, print_function + +import os +import sys +import re +import operator +import warnings +from functools import partial, wraps +import shutil +import contextlib +from tempfile import mkdtemp, mkstemp +from unittest.case import SkipTest + +from numpy.core import( + float32, empty, arange, array_repr, ndarray, isnat, array) +from numpy.lib.utils import deprecate + +if sys.version_info[0] >= 3: + from io import StringIO +else: + from StringIO import StringIO + +__all__ = [ + 'assert_equal', 'assert_almost_equal', 'assert_approx_equal', + 'assert_array_equal', 'assert_array_less', 'assert_string_equal', + 'assert_array_almost_equal', 'assert_raises', 'build_err_msg', + 'decorate_methods', 'jiffies', 'memusage', 'print_assert_equal', + 'raises', 'rand', 'rundocs', 'runstring', 'verbose', 'measure', + 'assert_', 'assert_array_almost_equal_nulp', 'assert_raises_regex', + 'assert_array_max_ulp', 'assert_warns', 'assert_no_warnings', + 'assert_allclose', 'IgnoreException', 'clear_and_catch_warnings', + 'SkipTest', 'KnownFailureException', 'temppath', 'tempdir', 'IS_PYPY', + 'HAS_REFCOUNT', 'suppress_warnings', 'assert_array_compare', + '_assert_valid_refcount', '_gen_alignment_data', + ] + + +class KnownFailureException(Exception): + '''Raise this exception to mark a test as a known failing test.''' + pass + + +KnownFailureTest = KnownFailureException # backwards compat +verbose = 0 + +IS_PYPY = '__pypy__' in sys.modules +HAS_REFCOUNT = getattr(sys, 'getrefcount', None) is not None + + +def import_nose(): + """ Import nose only when needed. + """ + nose_is_good = True + minimum_nose_version = (1, 0, 0) + try: + import nose + except ImportError: + nose_is_good = False + else: + if nose.__versioninfo__ < minimum_nose_version: + nose_is_good = False + + if not nose_is_good: + msg = ('Need nose >= %d.%d.%d for tests - see ' + 'http://nose.readthedocs.io' % + minimum_nose_version) + raise ImportError(msg) + + return nose + + +def assert_(val, msg=''): + """ + Assert that works in release mode. + Accepts callable msg to allow deferring evaluation until failure. + + The Python built-in ``assert`` does not work when executing code in + optimized mode (the ``-O`` flag) - no byte-code is generated for it. + + For documentation on usage, refer to the Python documentation. + + """ + __tracebackhide__ = True # Hide traceback for py.test + if not val: + try: + smsg = msg() + except TypeError: + smsg = msg + raise AssertionError(smsg) + + +def gisnan(x): + """like isnan, but always raise an error if type not supported instead of + returning a TypeError object. + + Notes + ----- + isnan and other ufunc sometimes return a NotImplementedType object instead + of raising any exception. This function is a wrapper to make sure an + exception is always raised. + + This should be removed once this problem is solved at the Ufunc level.""" + from numpy.core import isnan + st = isnan(x) + if isinstance(st, type(NotImplemented)): + raise TypeError("isnan not supported for this type") + return st + + +def gisfinite(x): + """like isfinite, but always raise an error if type not supported instead of + returning a TypeError object. + + Notes + ----- + isfinite and other ufunc sometimes return a NotImplementedType object instead + of raising any exception. This function is a wrapper to make sure an + exception is always raised. + + This should be removed once this problem is solved at the Ufunc level.""" + from numpy.core import isfinite, errstate + with errstate(invalid='ignore'): + st = isfinite(x) + if isinstance(st, type(NotImplemented)): + raise TypeError("isfinite not supported for this type") + return st + + +def gisinf(x): + """like isinf, but always raise an error if type not supported instead of + returning a TypeError object. + + Notes + ----- + isinf and other ufunc sometimes return a NotImplementedType object instead + of raising any exception. This function is a wrapper to make sure an + exception is always raised. + + This should be removed once this problem is solved at the Ufunc level.""" + from numpy.core import isinf, errstate + with errstate(invalid='ignore'): + st = isinf(x) + if isinstance(st, type(NotImplemented)): + raise TypeError("isinf not supported for this type") + return st + + +@deprecate(message="numpy.testing.rand is deprecated in numpy 1.11. " + "Use numpy.random.rand instead.") +def rand(*args): + """Returns an array of random numbers with the given shape. + + This only uses the standard library, so it is useful for testing purposes. + """ + import random + from numpy.core import zeros, float64 + results = zeros(args, float64) + f = results.flat + for i in range(len(f)): + f[i] = random.random() + return results + + +if os.name == 'nt': + # Code "stolen" from enthought/debug/memusage.py + def GetPerformanceAttributes(object, counter, instance=None, + inum=-1, format=None, machine=None): + # NOTE: Many counters require 2 samples to give accurate results, + # including "% Processor Time" (as by definition, at any instant, a + # thread's CPU usage is either 0 or 100). To read counters like this, + # you should copy this function, but keep the counter open, and call + # CollectQueryData() each time you need to know. + # See http://msdn.microsoft.com/library/en-us/dnperfmo/html/perfmonpt2.asp + # My older explanation for this was that the "AddCounter" process forced + # the CPU to 100%, but the above makes more sense :) + import win32pdh + if format is None: + format = win32pdh.PDH_FMT_LONG + path = win32pdh.MakeCounterPath( (machine, object, instance, None, inum, counter)) + hq = win32pdh.OpenQuery() + try: + hc = win32pdh.AddCounter(hq, path) + try: + win32pdh.CollectQueryData(hq) + type, val = win32pdh.GetFormattedCounterValue(hc, format) + return val + finally: + win32pdh.RemoveCounter(hc) + finally: + win32pdh.CloseQuery(hq) + + def memusage(processName="python", instance=0): + # from win32pdhutil, part of the win32all package + import win32pdh + return GetPerformanceAttributes("Process", "Virtual Bytes", + processName, instance, + win32pdh.PDH_FMT_LONG, None) +elif sys.platform[:5] == 'linux': + + def memusage(_proc_pid_stat='/proc/%s/stat' % (os.getpid())): + """ + Return virtual memory size in bytes of the running python. + + """ + try: + f = open(_proc_pid_stat, 'r') + l = f.readline().split(' ') + f.close() + return int(l[22]) + except Exception: + return +else: + def memusage(): + """ + Return memory usage of running python. [Not implemented] + + """ + raise NotImplementedError + + +if sys.platform[:5] == 'linux': + def jiffies(_proc_pid_stat='/proc/%s/stat' % (os.getpid()), + _load_time=[]): + """ + Return number of jiffies elapsed. + + Return number of jiffies (1/100ths of a second) that this + process has been scheduled in user mode. See man 5 proc. + + """ + import time + if not _load_time: + _load_time.append(time.time()) + try: + f = open(_proc_pid_stat, 'r') + l = f.readline().split(' ') + f.close() + return int(l[13]) + except Exception: + return int(100*(time.time()-_load_time[0])) +else: + # os.getpid is not in all platforms available. + # Using time is safe but inaccurate, especially when process + # was suspended or sleeping. + def jiffies(_load_time=[]): + """ + Return number of jiffies elapsed. + + Return number of jiffies (1/100ths of a second) that this + process has been scheduled in user mode. See man 5 proc. + + """ + import time + if not _load_time: + _load_time.append(time.time()) + return int(100*(time.time()-_load_time[0])) + + +def build_err_msg(arrays, err_msg, header='Items are not equal:', + verbose=True, names=('ACTUAL', 'DESIRED'), precision=8): + msg = ['\n' + header] + if err_msg: + if err_msg.find('\n') == -1 and len(err_msg) < 79-len(header): + msg = [msg[0] + ' ' + err_msg] + else: + msg.append(err_msg) + if verbose: + for i, a in enumerate(arrays): + + if isinstance(a, ndarray): + # precision argument is only needed if the objects are ndarrays + r_func = partial(array_repr, precision=precision) + else: + r_func = repr + + try: + r = r_func(a) + except Exception as exc: + r = '[repr failed for <{}>: {}]'.format(type(a).__name__, exc) + if r.count('\n') > 3: + r = '\n'.join(r.splitlines()[:3]) + r += '...' + msg.append(' %s: %s' % (names[i], r)) + return '\n'.join(msg) + + +def assert_equal(actual, desired, err_msg='', verbose=True): + """ + Raises an AssertionError if two objects are not equal. + + Given two objects (scalars, lists, tuples, dictionaries or numpy arrays), + check that all elements of these objects are equal. An exception is raised + at the first conflicting values. + + Parameters + ---------- + actual : array_like + The object to check. + desired : array_like + The expected object. + err_msg : str, optional + The error message to be printed in case of failure. + verbose : bool, optional + If True, the conflicting values are appended to the error message. + + Raises + ------ + AssertionError + If actual and desired are not equal. + + Examples + -------- + >>> np.testing.assert_equal([4,5], [4,6]) + ... + : + Items are not equal: + item=1 + ACTUAL: 5 + DESIRED: 6 + + """ + __tracebackhide__ = True # Hide traceback for py.test + if isinstance(desired, dict): + if not isinstance(actual, dict): + raise AssertionError(repr(type(actual))) + assert_equal(len(actual), len(desired), err_msg, verbose) + for k, i in desired.items(): + if k not in actual: + raise AssertionError(repr(k)) + assert_equal(actual[k], desired[k], 'key=%r\n%s' % (k, err_msg), verbose) + return + if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)): + assert_equal(len(actual), len(desired), err_msg, verbose) + for k in range(len(desired)): + assert_equal(actual[k], desired[k], 'item=%r\n%s' % (k, err_msg), verbose) + return + from numpy.core import ndarray, isscalar, signbit + from numpy.lib import iscomplexobj, real, imag + if isinstance(actual, ndarray) or isinstance(desired, ndarray): + return assert_array_equal(actual, desired, err_msg, verbose) + msg = build_err_msg([actual, desired], err_msg, verbose=verbose) + + # Handle complex numbers: separate into real/imag to handle + # nan/inf/negative zero correctly + # XXX: catch ValueError for subclasses of ndarray where iscomplex fail + try: + usecomplex = iscomplexobj(actual) or iscomplexobj(desired) + except ValueError: + usecomplex = False + + if usecomplex: + if iscomplexobj(actual): + actualr = real(actual) + actuali = imag(actual) + else: + actualr = actual + actuali = 0 + if iscomplexobj(desired): + desiredr = real(desired) + desiredi = imag(desired) + else: + desiredr = desired + desiredi = 0 + try: + assert_equal(actualr, desiredr) + assert_equal(actuali, desiredi) + except AssertionError: + raise AssertionError(msg) + + # isscalar test to check cases such as [np.nan] != np.nan + if isscalar(desired) != isscalar(actual): + raise AssertionError(msg) + + # Inf/nan/negative zero handling + try: + isdesnan = gisnan(desired) + isactnan = gisnan(actual) + if isdesnan and isactnan: + return # both nan, so equal + + # handle signed zero specially for floats + if desired == 0 and actual == 0: + if not signbit(desired) == signbit(actual): + raise AssertionError(msg) + + except (TypeError, ValueError, NotImplementedError): + pass + + try: + isdesnat = isnat(desired) + isactnat = isnat(actual) + dtypes_match = array(desired).dtype.type == array(actual).dtype.type + if isdesnat and isactnat: + # If both are NaT (and have the same dtype -- datetime or + # timedelta) they are considered equal. + if dtypes_match: + return + else: + raise AssertionError(msg) + + except (TypeError, ValueError, NotImplementedError): + pass + + try: + # Explicitly use __eq__ for comparison, gh-2552 + if not (desired == actual): + raise AssertionError(msg) + + except (DeprecationWarning, FutureWarning) as e: + # this handles the case when the two types are not even comparable + if 'elementwise == comparison' in e.args[0]: + raise AssertionError(msg) + else: + raise + + +def print_assert_equal(test_string, actual, desired): + """ + Test if two objects are equal, and print an error message if test fails. + + The test is performed with ``actual == desired``. + + Parameters + ---------- + test_string : str + The message supplied to AssertionError. + actual : object + The object to test for equality against `desired`. + desired : object + The expected result. + + Examples + -------- + >>> np.testing.print_assert_equal('Test XYZ of func xyz', [0, 1], [0, 1]) + >>> np.testing.print_assert_equal('Test XYZ of func xyz', [0, 1], [0, 2]) + Traceback (most recent call last): + ... + AssertionError: Test XYZ of func xyz failed + ACTUAL: + [0, 1] + DESIRED: + [0, 2] + + """ + __tracebackhide__ = True # Hide traceback for py.test + import pprint + + if not (actual == desired): + msg = StringIO() + msg.write(test_string) + msg.write(' failed\nACTUAL: \n') + pprint.pprint(actual, msg) + msg.write('DESIRED: \n') + pprint.pprint(desired, msg) + raise AssertionError(msg.getvalue()) + + +def assert_almost_equal(actual,desired,decimal=7,err_msg='',verbose=True): + """ + Raises an AssertionError if two items are not equal up to desired + precision. + + .. note:: It is recommended to use one of `assert_allclose`, + `assert_array_almost_equal_nulp` or `assert_array_max_ulp` + instead of this function for more consistent floating point + comparisons. + + The test verifies that the elements of ``actual`` and ``desired`` satisfy. + + ``abs(desired-actual) < 1.5 * 10**(-decimal)`` + + That is a looser test than originally documented, but agrees with what the + actual implementation in `assert_array_almost_equal` did up to rounding + vagaries. An exception is raised at conflicting values. For ndarrays this + delegates to assert_array_almost_equal + + Parameters + ---------- + actual : array_like + The object to check. + desired : array_like + The expected object. + decimal : int, optional + Desired precision, default is 7. + err_msg : str, optional + The error message to be printed in case of failure. + verbose : bool, optional + If True, the conflicting values are appended to the error message. + + Raises + ------ + AssertionError + If actual and desired are not equal up to specified precision. + + See Also + -------- + assert_allclose: Compare two array_like objects for equality with desired + relative and/or absolute precision. + assert_array_almost_equal_nulp, assert_array_max_ulp, assert_equal + + Examples + -------- + >>> import numpy.testing as npt + >>> npt.assert_almost_equal(2.3333333333333, 2.33333334) + >>> npt.assert_almost_equal(2.3333333333333, 2.33333334, decimal=10) + ... + : + Items are not equal: + ACTUAL: 2.3333333333333002 + DESIRED: 2.3333333399999998 + + >>> npt.assert_almost_equal(np.array([1.0,2.3333333333333]), + ... np.array([1.0,2.33333334]), decimal=9) + ... + : + Arrays are not almost equal + + (mismatch 50.0%) + x: array([ 1. , 2.33333333]) + y: array([ 1. , 2.33333334]) + + """ + __tracebackhide__ = True # Hide traceback for py.test + from numpy.core import ndarray + from numpy.lib import iscomplexobj, real, imag + + # Handle complex numbers: separate into real/imag to handle + # nan/inf/negative zero correctly + # XXX: catch ValueError for subclasses of ndarray where iscomplex fail + try: + usecomplex = iscomplexobj(actual) or iscomplexobj(desired) + except ValueError: + usecomplex = False + + def _build_err_msg(): + header = ('Arrays are not almost equal to %d decimals' % decimal) + return build_err_msg([actual, desired], err_msg, verbose=verbose, + header=header) + + if usecomplex: + if iscomplexobj(actual): + actualr = real(actual) + actuali = imag(actual) + else: + actualr = actual + actuali = 0 + if iscomplexobj(desired): + desiredr = real(desired) + desiredi = imag(desired) + else: + desiredr = desired + desiredi = 0 + try: + assert_almost_equal(actualr, desiredr, decimal=decimal) + assert_almost_equal(actuali, desiredi, decimal=decimal) + except AssertionError: + raise AssertionError(_build_err_msg()) + + if isinstance(actual, (ndarray, tuple, list)) \ + or isinstance(desired, (ndarray, tuple, list)): + return assert_array_almost_equal(actual, desired, decimal, err_msg) + try: + # If one of desired/actual is not finite, handle it specially here: + # check that both are nan if any is a nan, and test for equality + # otherwise + if not (gisfinite(desired) and gisfinite(actual)): + if gisnan(desired) or gisnan(actual): + if not (gisnan(desired) and gisnan(actual)): + raise AssertionError(_build_err_msg()) + else: + if not desired == actual: + raise AssertionError(_build_err_msg()) + return + except (NotImplementedError, TypeError): + pass + if abs(desired - actual) >= 1.5 * 10.0**(-decimal): + raise AssertionError(_build_err_msg()) + + +def assert_approx_equal(actual,desired,significant=7,err_msg='',verbose=True): + """ + Raises an AssertionError if two items are not equal up to significant + digits. + + .. note:: It is recommended to use one of `assert_allclose`, + `assert_array_almost_equal_nulp` or `assert_array_max_ulp` + instead of this function for more consistent floating point + comparisons. + + Given two numbers, check that they are approximately equal. + Approximately equal is defined as the number of significant digits + that agree. + + Parameters + ---------- + actual : scalar + The object to check. + desired : scalar + The expected object. + significant : int, optional + Desired precision, default is 7. + err_msg : str, optional + The error message to be printed in case of failure. + verbose : bool, optional + If True, the conflicting values are appended to the error message. + + Raises + ------ + AssertionError + If actual and desired are not equal up to specified precision. + + See Also + -------- + assert_allclose: Compare two array_like objects for equality with desired + relative and/or absolute precision. + assert_array_almost_equal_nulp, assert_array_max_ulp, assert_equal + + Examples + -------- + >>> np.testing.assert_approx_equal(0.12345677777777e-20, 0.1234567e-20) + >>> np.testing.assert_approx_equal(0.12345670e-20, 0.12345671e-20, + significant=8) + >>> np.testing.assert_approx_equal(0.12345670e-20, 0.12345672e-20, + significant=8) + ... + : + Items are not equal to 8 significant digits: + ACTUAL: 1.234567e-021 + DESIRED: 1.2345672000000001e-021 + + the evaluated condition that raises the exception is + + >>> abs(0.12345670e-20/1e-21 - 0.12345672e-20/1e-21) >= 10**-(8-1) + True + + """ + __tracebackhide__ = True # Hide traceback for py.test + import numpy as np + + (actual, desired) = map(float, (actual, desired)) + if desired == actual: + return + # Normalized the numbers to be in range (-10.0,10.0) + # scale = float(pow(10,math.floor(math.log10(0.5*(abs(desired)+abs(actual)))))) + with np.errstate(invalid='ignore'): + scale = 0.5*(np.abs(desired) + np.abs(actual)) + scale = np.power(10, np.floor(np.log10(scale))) + try: + sc_desired = desired/scale + except ZeroDivisionError: + sc_desired = 0.0 + try: + sc_actual = actual/scale + except ZeroDivisionError: + sc_actual = 0.0 + msg = build_err_msg([actual, desired], err_msg, + header='Items are not equal to %d significant digits:' % + significant, + verbose=verbose) + try: + # If one of desired/actual is not finite, handle it specially here: + # check that both are nan if any is a nan, and test for equality + # otherwise + if not (gisfinite(desired) and gisfinite(actual)): + if gisnan(desired) or gisnan(actual): + if not (gisnan(desired) and gisnan(actual)): + raise AssertionError(msg) + else: + if not desired == actual: + raise AssertionError(msg) + return + except (TypeError, NotImplementedError): + pass + if np.abs(sc_desired - sc_actual) >= np.power(10., -(significant-1)): + raise AssertionError(msg) + + +def assert_array_compare(comparison, x, y, err_msg='', verbose=True, + header='', precision=6, equal_nan=True, + equal_inf=True): + __tracebackhide__ = True # Hide traceback for py.test + from numpy.core import array, isnan, isinf, any, inf + x = array(x, copy=False, subok=True) + y = array(y, copy=False, subok=True) + + def isnumber(x): + return x.dtype.char in '?bhilqpBHILQPefdgFDG' + + def istime(x): + return x.dtype.char in "Mm" + + def chk_same_position(x_id, y_id, hasval='nan'): + """Handling nan/inf: check that x and y have the nan/inf at the same + locations.""" + try: + assert_array_equal(x_id, y_id) + except AssertionError: + msg = build_err_msg([x, y], + err_msg + '\nx and y %s location mismatch:' + % (hasval), verbose=verbose, header=header, + names=('x', 'y'), precision=precision) + raise AssertionError(msg) + + try: + cond = (x.shape == () or y.shape == ()) or x.shape == y.shape + if not cond: + msg = build_err_msg([x, y], + err_msg + + '\n(shapes %s, %s mismatch)' % (x.shape, + y.shape), + verbose=verbose, header=header, + names=('x', 'y'), precision=precision) + raise AssertionError(msg) + + if isnumber(x) and isnumber(y): + has_nan = has_inf = False + if equal_nan: + x_isnan, y_isnan = isnan(x), isnan(y) + # Validate that NaNs are in the same place + has_nan = any(x_isnan) or any(y_isnan) + if has_nan: + chk_same_position(x_isnan, y_isnan, hasval='nan') + + if equal_inf: + x_isinf, y_isinf = isinf(x), isinf(y) + # Validate that infinite values are in the same place + has_inf = any(x_isinf) or any(y_isinf) + if has_inf: + # Check +inf and -inf separately, since they are different + chk_same_position(x == +inf, y == +inf, hasval='+inf') + chk_same_position(x == -inf, y == -inf, hasval='-inf') + + if has_nan and has_inf: + x = x[~(x_isnan | x_isinf)] + y = y[~(y_isnan | y_isinf)] + elif has_nan: + x = x[~x_isnan] + y = y[~y_isnan] + elif has_inf: + x = x[~x_isinf] + y = y[~y_isinf] + + # Only do the comparison if actual values are left + if x.size == 0: + return + + elif istime(x) and istime(y): + # If one is datetime64 and the other timedelta64 there is no point + if equal_nan and x.dtype.type == y.dtype.type: + x_isnat, y_isnat = isnat(x), isnat(y) + + if any(x_isnat) or any(y_isnat): + chk_same_position(x_isnat, y_isnat, hasval="NaT") + + if any(x_isnat) or any(y_isnat): + x = x[~x_isnat] + y = y[~y_isnat] + + val = comparison(x, y) + + if isinstance(val, bool): + cond = val + reduced = [0] + else: + reduced = val.ravel() + cond = reduced.all() + reduced = reduced.tolist() + if not cond: + match = 100-100.0*reduced.count(1)/len(reduced) + msg = build_err_msg([x, y], + err_msg + + '\n(mismatch %s%%)' % (match,), + verbose=verbose, header=header, + names=('x', 'y'), precision=precision) + raise AssertionError(msg) + except ValueError: + import traceback + efmt = traceback.format_exc() + header = 'error during assertion:\n\n%s\n\n%s' % (efmt, header) + + msg = build_err_msg([x, y], err_msg, verbose=verbose, header=header, + names=('x', 'y'), precision=precision) + raise ValueError(msg) + + +def assert_array_equal(x, y, err_msg='', verbose=True): + """ + Raises an AssertionError if two array_like objects are not equal. + + Given two array_like objects, check that the shape is equal and all + elements of these objects are equal. An exception is raised at + shape mismatch or conflicting values. In contrast to the standard usage + in numpy, NaNs are compared like numbers, no assertion is raised if + both objects have NaNs in the same positions. + + The usual caution for verifying equality with floating point numbers is + advised. + + Parameters + ---------- + x : array_like + The actual object to check. + y : array_like + The desired, expected object. + err_msg : str, optional + The error message to be printed in case of failure. + verbose : bool, optional + If True, the conflicting values are appended to the error message. + + Raises + ------ + AssertionError + If actual and desired objects are not equal. + + See Also + -------- + assert_allclose: Compare two array_like objects for equality with desired + relative and/or absolute precision. + assert_array_almost_equal_nulp, assert_array_max_ulp, assert_equal + + Examples + -------- + The first assert does not raise an exception: + + >>> np.testing.assert_array_equal([1.0,2.33333,np.nan], + ... [np.exp(0),2.33333, np.nan]) + + Assert fails with numerical inprecision with floats: + + >>> np.testing.assert_array_equal([1.0,np.pi,np.nan], + ... [1, np.sqrt(np.pi)**2, np.nan]) + ... + : + AssertionError: + Arrays are not equal + + (mismatch 50.0%) + x: array([ 1. , 3.14159265, NaN]) + y: array([ 1. , 3.14159265, NaN]) + + Use `assert_allclose` or one of the nulp (number of floating point values) + functions for these cases instead: + + >>> np.testing.assert_allclose([1.0,np.pi,np.nan], + ... [1, np.sqrt(np.pi)**2, np.nan], + ... rtol=1e-10, atol=0) + + """ + __tracebackhide__ = True # Hide traceback for py.test + assert_array_compare(operator.__eq__, x, y, err_msg=err_msg, + verbose=verbose, header='Arrays are not equal') + + +def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True): + """ + Raises an AssertionError if two objects are not equal up to desired + precision. + + .. note:: It is recommended to use one of `assert_allclose`, + `assert_array_almost_equal_nulp` or `assert_array_max_ulp` + instead of this function for more consistent floating point + comparisons. + + The test verifies identical shapes and that the elements of ``actual`` and + ``desired`` satisfy. + + ``abs(desired-actual) < 1.5 * 10**(-decimal)`` + + That is a looser test than originally documented, but agrees with what the + actual implementation did up to rounding vagaries. An exception is raised + at shape mismatch or conflicting values. In contrast to the standard usage + in numpy, NaNs are compared like numbers, no assertion is raised if both + objects have NaNs in the same positions. + + Parameters + ---------- + x : array_like + The actual object to check. + y : array_like + The desired, expected object. + decimal : int, optional + Desired precision, default is 6. + err_msg : str, optional + The error message to be printed in case of failure. + verbose : bool, optional + If True, the conflicting values are appended to the error message. + + Raises + ------ + AssertionError + If actual and desired are not equal up to specified precision. + + See Also + -------- + assert_allclose: Compare two array_like objects for equality with desired + relative and/or absolute precision. + assert_array_almost_equal_nulp, assert_array_max_ulp, assert_equal + + Examples + -------- + the first assert does not raise an exception + + >>> np.testing.assert_array_almost_equal([1.0,2.333,np.nan], + [1.0,2.333,np.nan]) + + >>> np.testing.assert_array_almost_equal([1.0,2.33333,np.nan], + ... [1.0,2.33339,np.nan], decimal=5) + ... + : + AssertionError: + Arrays are not almost equal + + (mismatch 50.0%) + x: array([ 1. , 2.33333, NaN]) + y: array([ 1. , 2.33339, NaN]) + + >>> np.testing.assert_array_almost_equal([1.0,2.33333,np.nan], + ... [1.0,2.33333, 5], decimal=5) + : + ValueError: + Arrays are not almost equal + x: array([ 1. , 2.33333, NaN]) + y: array([ 1. , 2.33333, 5. ]) + + """ + __tracebackhide__ = True # Hide traceback for py.test + from numpy.core import around, number, float_, result_type, array + from numpy.core.numerictypes import issubdtype + from numpy.core.fromnumeric import any as npany + + def compare(x, y): + try: + if npany(gisinf(x)) or npany( gisinf(y)): + xinfid = gisinf(x) + yinfid = gisinf(y) + if not (xinfid == yinfid).all(): + return False + # if one item, x and y is +- inf + if x.size == y.size == 1: + return x == y + x = x[~xinfid] + y = y[~yinfid] + except (TypeError, NotImplementedError): + pass + + # make sure y is an inexact type to avoid abs(MIN_INT); will cause + # casting of x later. + dtype = result_type(y, 1.) + y = array(y, dtype=dtype, copy=False, subok=True) + z = abs(x - y) + + if not issubdtype(z.dtype, number): + z = z.astype(float_) # handle object arrays + + return z < 1.5 * 10.0**(-decimal) + + assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose, + header=('Arrays are not almost equal to %d decimals' % decimal), + precision=decimal) + + +def assert_array_less(x, y, err_msg='', verbose=True): + """ + Raises an AssertionError if two array_like objects are not ordered by less + than. + + Given two array_like objects, check that the shape is equal and all + elements of the first object are strictly smaller than those of the + second object. An exception is raised at shape mismatch or incorrectly + ordered values. Shape mismatch does not raise if an object has zero + dimension. In contrast to the standard usage in numpy, NaNs are + compared, no assertion is raised if both objects have NaNs in the same + positions. + + + + Parameters + ---------- + x : array_like + The smaller object to check. + y : array_like + The larger object to compare. + err_msg : string + The error message to be printed in case of failure. + verbose : bool + If True, the conflicting values are appended to the error message. + + Raises + ------ + AssertionError + If actual and desired objects are not equal. + + See Also + -------- + assert_array_equal: tests objects for equality + assert_array_almost_equal: test objects for equality up to precision + + + + Examples + -------- + >>> np.testing.assert_array_less([1.0, 1.0, np.nan], [1.1, 2.0, np.nan]) + >>> np.testing.assert_array_less([1.0, 1.0, np.nan], [1, 2.0, np.nan]) + ... + : + Arrays are not less-ordered + (mismatch 50.0%) + x: array([ 1., 1., NaN]) + y: array([ 1., 2., NaN]) + + >>> np.testing.assert_array_less([1.0, 4.0], 3) + ... + : + Arrays are not less-ordered + (mismatch 50.0%) + x: array([ 1., 4.]) + y: array(3) + + >>> np.testing.assert_array_less([1.0, 2.0, 3.0], [4]) + ... + : + Arrays are not less-ordered + (shapes (3,), (1,) mismatch) + x: array([ 1., 2., 3.]) + y: array([4]) + + """ + __tracebackhide__ = True # Hide traceback for py.test + assert_array_compare(operator.__lt__, x, y, err_msg=err_msg, + verbose=verbose, + header='Arrays are not less-ordered', + equal_inf=False) + + +def runstring(astr, dict): + exec(astr, dict) + + +def assert_string_equal(actual, desired): + """ + Test if two strings are equal. + + If the given strings are equal, `assert_string_equal` does nothing. + If they are not equal, an AssertionError is raised, and the diff + between the strings is shown. + + Parameters + ---------- + actual : str + The string to test for equality against the expected string. + desired : str + The expected string. + + Examples + -------- + >>> np.testing.assert_string_equal('abc', 'abc') + >>> np.testing.assert_string_equal('abc', 'abcd') + Traceback (most recent call last): + File "", line 1, in + ... + AssertionError: Differences in strings: + - abc+ abcd? + + + """ + # delay import of difflib to reduce startup time + __tracebackhide__ = True # Hide traceback for py.test + import difflib + + if not isinstance(actual, str): + raise AssertionError(repr(type(actual))) + if not isinstance(desired, str): + raise AssertionError(repr(type(desired))) + if re.match(r'\A'+desired+r'\Z', actual, re.M): + return + + diff = list(difflib.Differ().compare(actual.splitlines(1), desired.splitlines(1))) + diff_list = [] + while diff: + d1 = diff.pop(0) + if d1.startswith(' '): + continue + if d1.startswith('- '): + l = [d1] + d2 = diff.pop(0) + if d2.startswith('? '): + l.append(d2) + d2 = diff.pop(0) + if not d2.startswith('+ '): + raise AssertionError(repr(d2)) + l.append(d2) + if diff: + d3 = diff.pop(0) + if d3.startswith('? '): + l.append(d3) + else: + diff.insert(0, d3) + if re.match(r'\A'+d2[2:]+r'\Z', d1[2:]): + continue + diff_list.extend(l) + continue + raise AssertionError(repr(d1)) + if not diff_list: + return + msg = 'Differences in strings:\n%s' % (''.join(diff_list)).rstrip() + if actual != desired: + raise AssertionError(msg) + + +def rundocs(filename=None, raise_on_error=True): + """ + Run doctests found in the given file. + + By default `rundocs` raises an AssertionError on failure. + + Parameters + ---------- + filename : str + The path to the file for which the doctests are run. + raise_on_error : bool + Whether to raise an AssertionError when a doctest fails. Default is + True. + + Notes + ----- + The doctests can be run by the user/developer by adding the ``doctests`` + argument to the ``test()`` call. For example, to run all tests (including + doctests) for `numpy.lib`: + + >>> np.lib.test(doctests=True) #doctest: +SKIP + """ + from numpy.compat import npy_load_module + import doctest + if filename is None: + f = sys._getframe(1) + filename = f.f_globals['__file__'] + name = os.path.splitext(os.path.basename(filename))[0] + m = npy_load_module(name, filename) + + tests = doctest.DocTestFinder().find(m) + runner = doctest.DocTestRunner(verbose=False) + + msg = [] + if raise_on_error: + out = lambda s: msg.append(s) + else: + out = None + + for test in tests: + runner.run(test, out=out) + + if runner.failures > 0 and raise_on_error: + raise AssertionError("Some doctests failed:\n%s" % "\n".join(msg)) + + +def raises(*args,**kwargs): + nose = import_nose() + return nose.tools.raises(*args,**kwargs) + + +def assert_raises(*args, **kwargs): + """ + assert_raises(exception_class, callable, *args, **kwargs) + assert_raises(exception_class) + + Fail unless an exception of class exception_class is thrown + by callable when invoked with arguments args and keyword + arguments kwargs. If a different type of exception is + thrown, it will not be caught, and the test case will be + deemed to have suffered an error, exactly as for an + unexpected exception. + + Alternatively, `assert_raises` can be used as a context manager: + + >>> from numpy.testing import assert_raises + >>> with assert_raises(ZeroDivisionError): + ... 1 / 0 + + is equivalent to + + >>> def div(x, y): + ... return x / y + >>> assert_raises(ZeroDivisionError, div, 1, 0) + + """ + __tracebackhide__ = True # Hide traceback for py.test + nose = import_nose() + return nose.tools.assert_raises(*args,**kwargs) + + +def assert_raises_regex(exception_class, expected_regexp, *args, **kwargs): + """ + assert_raises_regex(exception_class, expected_regexp, callable, *args, + **kwargs) + assert_raises_regex(exception_class, expected_regexp) + + Fail unless an exception of class exception_class and with message that + matches expected_regexp is thrown by callable when invoked with arguments + args and keyword arguments kwargs. + + Alternatively, can be used as a context manager like `assert_raises`. + + Name of this function adheres to Python 3.2+ reference, but should work in + all versions down to 2.6. + + Notes + ----- + .. versionadded:: 1.9.0 + + """ + __tracebackhide__ = True # Hide traceback for py.test + nose = import_nose() + + if sys.version_info.major >= 3: + funcname = nose.tools.assert_raises_regex + else: + # Only present in Python 2.7, missing from unittest in 2.6 + funcname = nose.tools.assert_raises_regexp + + return funcname(exception_class, expected_regexp, *args, **kwargs) + + +def decorate_methods(cls, decorator, testmatch=None): + """ + Apply a decorator to all methods in a class matching a regular expression. + + The given decorator is applied to all public methods of `cls` that are + matched by the regular expression `testmatch` + (``testmatch.search(methodname)``). Methods that are private, i.e. start + with an underscore, are ignored. + + Parameters + ---------- + cls : class + Class whose methods to decorate. + decorator : function + Decorator to apply to methods + testmatch : compiled regexp or str, optional + The regular expression. Default value is None, in which case the + nose default (``re.compile(r'(?:^|[\\b_\\.%s-])[Tt]est' % os.sep)``) + is used. + If `testmatch` is a string, it is compiled to a regular expression + first. + + """ + if testmatch is None: + testmatch = re.compile(r'(?:^|[\\b_\\.%s-])[Tt]est' % os.sep) + else: + testmatch = re.compile(testmatch) + cls_attr = cls.__dict__ + + # delayed import to reduce startup time + from inspect import isfunction + + methods = [_m for _m in cls_attr.values() if isfunction(_m)] + for function in methods: + try: + if hasattr(function, 'compat_func_name'): + funcname = function.compat_func_name + else: + funcname = function.__name__ + except AttributeError: + # not a function + continue + if testmatch.search(funcname) and not funcname.startswith('_'): + setattr(cls, funcname, decorator(function)) + return + + +def measure(code_str,times=1,label=None): + """ + Return elapsed time for executing code in the namespace of the caller. + + The supplied code string is compiled with the Python builtin ``compile``. + The precision of the timing is 10 milli-seconds. If the code will execute + fast on this timescale, it can be executed many times to get reasonable + timing accuracy. + + Parameters + ---------- + code_str : str + The code to be timed. + times : int, optional + The number of times the code is executed. Default is 1. The code is + only compiled once. + label : str, optional + A label to identify `code_str` with. This is passed into ``compile`` + as the second argument (for run-time error messages). + + Returns + ------- + elapsed : float + Total elapsed time in seconds for executing `code_str` `times` times. + + Examples + -------- + >>> etime = np.testing.measure('for i in range(1000): np.sqrt(i**2)', + ... times=times) + >>> print("Time for a single execution : ", etime / times, "s") + Time for a single execution : 0.005 s + + """ + frame = sys._getframe(1) + locs, globs = frame.f_locals, frame.f_globals + + code = compile(code_str, + 'Test name: %s ' % label, + 'exec') + i = 0 + elapsed = jiffies() + while i < times: + i += 1 + exec(code, globs, locs) + elapsed = jiffies() - elapsed + return 0.01*elapsed + + +def _assert_valid_refcount(op): + """ + Check that ufuncs don't mishandle refcount of object `1`. + Used in a few regression tests. + """ + if not HAS_REFCOUNT: + return True + import numpy as np + + b = np.arange(100*100).reshape(100, 100) + c = b + i = 1 + + rc = sys.getrefcount(i) + for j in range(15): + d = op(b, c) + assert_(sys.getrefcount(i) >= rc) + del d # for pyflakes + + +def assert_allclose(actual, desired, rtol=1e-7, atol=0, equal_nan=True, + err_msg='', verbose=True): + """ + Raises an AssertionError if two objects are not equal up to desired + tolerance. + + The test is equivalent to ``allclose(actual, desired, rtol, atol)``. + It compares the difference between `actual` and `desired` to + ``atol + rtol * abs(desired)``. + + .. versionadded:: 1.5.0 + + Parameters + ---------- + actual : array_like + Array obtained. + desired : array_like + Array desired. + rtol : float, optional + Relative tolerance. + atol : float, optional + Absolute tolerance. + equal_nan : bool, optional. + If True, NaNs will compare equal. + err_msg : str, optional + The error message to be printed in case of failure. + verbose : bool, optional + If True, the conflicting values are appended to the error message. + + Raises + ------ + AssertionError + If actual and desired are not equal up to specified precision. + + See Also + -------- + assert_array_almost_equal_nulp, assert_array_max_ulp + + Examples + -------- + >>> x = [1e-5, 1e-3, 1e-1] + >>> y = np.arccos(np.cos(x)) + >>> assert_allclose(x, y, rtol=1e-5, atol=0) + + """ + __tracebackhide__ = True # Hide traceback for py.test + import numpy as np + + def compare(x, y): + return np.core.numeric.isclose(x, y, rtol=rtol, atol=atol, + equal_nan=equal_nan) + + actual, desired = np.asanyarray(actual), np.asanyarray(desired) + header = 'Not equal to tolerance rtol=%g, atol=%g' % (rtol, atol) + assert_array_compare(compare, actual, desired, err_msg=str(err_msg), + verbose=verbose, header=header, equal_nan=equal_nan) + + +def assert_array_almost_equal_nulp(x, y, nulp=1): + """ + Compare two arrays relatively to their spacing. + + This is a relatively robust method to compare two arrays whose amplitude + is variable. + + Parameters + ---------- + x, y : array_like + Input arrays. + nulp : int, optional + The maximum number of unit in the last place for tolerance (see Notes). + Default is 1. + + Returns + ------- + None + + Raises + ------ + AssertionError + If the spacing between `x` and `y` for one or more elements is larger + than `nulp`. + + See Also + -------- + assert_array_max_ulp : Check that all items of arrays differ in at most + N Units in the Last Place. + spacing : Return the distance between x and the nearest adjacent number. + + Notes + ----- + An assertion is raised if the following condition is not met:: + + abs(x - y) <= nulps * spacing(maximum(abs(x), abs(y))) + + Examples + -------- + >>> x = np.array([1., 1e-10, 1e-20]) + >>> eps = np.finfo(x.dtype).eps + >>> np.testing.assert_array_almost_equal_nulp(x, x*eps/2 + x) + + >>> np.testing.assert_array_almost_equal_nulp(x, x*eps + x) + Traceback (most recent call last): + ... + AssertionError: X and Y are not equal to 1 ULP (max is 2) + + """ + __tracebackhide__ = True # Hide traceback for py.test + import numpy as np + ax = np.abs(x) + ay = np.abs(y) + ref = nulp * np.spacing(np.where(ax > ay, ax, ay)) + if not np.all(np.abs(x-y) <= ref): + if np.iscomplexobj(x) or np.iscomplexobj(y): + msg = "X and Y are not equal to %d ULP" % nulp + else: + max_nulp = np.max(nulp_diff(x, y)) + msg = "X and Y are not equal to %d ULP (max is %g)" % (nulp, max_nulp) + raise AssertionError(msg) + + +def assert_array_max_ulp(a, b, maxulp=1, dtype=None): + """ + Check that all items of arrays differ in at most N Units in the Last Place. + + Parameters + ---------- + a, b : array_like + Input arrays to be compared. + maxulp : int, optional + The maximum number of units in the last place that elements of `a` and + `b` can differ. Default is 1. + dtype : dtype, optional + Data-type to convert `a` and `b` to if given. Default is None. + + Returns + ------- + ret : ndarray + Array containing number of representable floating point numbers between + items in `a` and `b`. + + Raises + ------ + AssertionError + If one or more elements differ by more than `maxulp`. + + See Also + -------- + assert_array_almost_equal_nulp : Compare two arrays relatively to their + spacing. + + Examples + -------- + >>> a = np.linspace(0., 1., 100) + >>> res = np.testing.assert_array_max_ulp(a, np.arcsin(np.sin(a))) + + """ + __tracebackhide__ = True # Hide traceback for py.test + import numpy as np + ret = nulp_diff(a, b, dtype) + if not np.all(ret <= maxulp): + raise AssertionError("Arrays are not almost equal up to %g ULP" % + maxulp) + return ret + + +def nulp_diff(x, y, dtype=None): + """For each item in x and y, return the number of representable floating + points between them. + + Parameters + ---------- + x : array_like + first input array + y : array_like + second input array + dtype : dtype, optional + Data-type to convert `x` and `y` to if given. Default is None. + + Returns + ------- + nulp : array_like + number of representable floating point numbers between each item in x + and y. + + Examples + -------- + # By definition, epsilon is the smallest number such as 1 + eps != 1, so + # there should be exactly one ULP between 1 and 1 + eps + >>> nulp_diff(1, 1 + np.finfo(x.dtype).eps) + 1.0 + """ + import numpy as np + if dtype: + x = np.array(x, dtype=dtype) + y = np.array(y, dtype=dtype) + else: + x = np.array(x) + y = np.array(y) + + t = np.common_type(x, y) + if np.iscomplexobj(x) or np.iscomplexobj(y): + raise NotImplementedError("_nulp not implemented for complex array") + + x = np.array(x, dtype=t) + y = np.array(y, dtype=t) + + if not x.shape == y.shape: + raise ValueError("x and y do not have the same shape: %s - %s" % + (x.shape, y.shape)) + + def _diff(rx, ry, vdt): + diff = np.array(rx-ry, dtype=vdt) + return np.abs(diff) + + rx = integer_repr(x) + ry = integer_repr(y) + return _diff(rx, ry, t) + + +def _integer_repr(x, vdt, comp): + # Reinterpret binary representation of the float as sign-magnitude: + # take into account two-complement representation + # See also + # http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm + rx = x.view(vdt) + if not (rx.size == 1): + rx[rx < 0] = comp - rx[rx < 0] + else: + if rx < 0: + rx = comp - rx + + return rx + + +def integer_repr(x): + """Return the signed-magnitude interpretation of the binary representation of + x.""" + import numpy as np + if x.dtype == np.float32: + return _integer_repr(x, np.int32, np.int32(-2**31)) + elif x.dtype == np.float64: + return _integer_repr(x, np.int64, np.int64(-2**63)) + else: + raise ValueError("Unsupported dtype %s" % x.dtype) + + +# The following two classes are copied from python 2.6 warnings module (context +# manager) +class WarningMessage(object): + + """ + Holds the result of a single showwarning() call. + + Deprecated in 1.8.0 + + Notes + ----- + `WarningMessage` is copied from the Python 2.6 warnings module, + so it can be used in NumPy with older Python versions. + + """ + + _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", + "line") + + def __init__(self, message, category, filename, lineno, file=None, + line=None): + local_values = locals() + for attr in self._WARNING_DETAILS: + setattr(self, attr, local_values[attr]) + if category: + self._category_name = category.__name__ + else: + self._category_name = None + + def __str__(self): + return ("{message : %r, category : %r, filename : %r, lineno : %s, " + "line : %r}" % (self.message, self._category_name, + self.filename, self.lineno, self.line)) + + +class WarningManager(object): + """ + A context manager that copies and restores the warnings filter upon + exiting the context. + + The 'record' argument specifies whether warnings should be captured by a + custom implementation of ``warnings.showwarning()`` and be appended to a + list returned by the context manager. Otherwise None is returned by the + context manager. The objects appended to the list are arguments whose + attributes mirror the arguments to ``showwarning()``. + + The 'module' argument is to specify an alternative module to the module + named 'warnings' and imported under that name. This argument is only useful + when testing the warnings module itself. + + Deprecated in 1.8.0 + + Notes + ----- + `WarningManager` is a copy of the ``catch_warnings`` context manager + from the Python 2.6 warnings module, with slight modifications. + It is copied so it can be used in NumPy with older Python versions. + + """ + + def __init__(self, record=False, module=None): + self._record = record + if module is None: + self._module = sys.modules['warnings'] + else: + self._module = module + self._entered = False + + def __enter__(self): + if self._entered: + raise RuntimeError("Cannot enter %r twice" % self) + self._entered = True + self._filters = self._module.filters + self._module.filters = self._filters[:] + self._showwarning = self._module.showwarning + if self._record: + log = [] + + def showwarning(*args, **kwargs): + log.append(WarningMessage(*args, **kwargs)) + self._module.showwarning = showwarning + return log + else: + return None + + def __exit__(self): + if not self._entered: + raise RuntimeError("Cannot exit %r without entering first" % self) + self._module.filters = self._filters + self._module.showwarning = self._showwarning + + +@contextlib.contextmanager +def _assert_warns_context(warning_class, name=None): + __tracebackhide__ = True # Hide traceback for py.test + with suppress_warnings() as sup: + l = sup.record(warning_class) + yield + if not len(l) > 0: + name_str = " when calling %s" % name if name is not None else "" + raise AssertionError("No warning raised" + name_str) + + +def assert_warns(warning_class, *args, **kwargs): + """ + Fail unless the given callable throws the specified warning. + + A warning of class warning_class should be thrown by the callable when + invoked with arguments args and keyword arguments kwargs. + If a different type of warning is thrown, it will not be caught. + + If called with all arguments other than the warning class omitted, may be + used as a context manager: + + with assert_warns(SomeWarning): + do_something() + + The ability to be used as a context manager is new in NumPy v1.11.0. + + .. versionadded:: 1.4.0 + + Parameters + ---------- + warning_class : class + The class defining the warning that `func` is expected to throw. + func : callable + The callable to test. + \\*args : Arguments + Arguments passed to `func`. + \\*\\*kwargs : Kwargs + Keyword arguments passed to `func`. + + Returns + ------- + The value returned by `func`. + + """ + if not args: + return _assert_warns_context(warning_class) + + func = args[0] + args = args[1:] + with _assert_warns_context(warning_class, name=func.__name__): + return func(*args, **kwargs) + + +@contextlib.contextmanager +def _assert_no_warnings_context(name=None): + __tracebackhide__ = True # Hide traceback for py.test + with warnings.catch_warnings(record=True) as l: + warnings.simplefilter('always') + yield + if len(l) > 0: + name_str = " when calling %s" % name if name is not None else "" + raise AssertionError("Got warnings%s: %s" % (name_str, l)) + + +def assert_no_warnings(*args, **kwargs): + """ + Fail if the given callable produces any warnings. + + If called with all arguments omitted, may be used as a context manager: + + with assert_no_warnings(): + do_something() + + The ability to be used as a context manager is new in NumPy v1.11.0. + + .. versionadded:: 1.7.0 + + Parameters + ---------- + func : callable + The callable to test. + \\*args : Arguments + Arguments passed to `func`. + \\*\\*kwargs : Kwargs + Keyword arguments passed to `func`. + + Returns + ------- + The value returned by `func`. + + """ + if not args: + return _assert_no_warnings_context() + + func = args[0] + args = args[1:] + with _assert_no_warnings_context(name=func.__name__): + return func(*args, **kwargs) + + +def _gen_alignment_data(dtype=float32, type='binary', max_size=24): + """ + generator producing data with different alignment and offsets + to test simd vectorization + + Parameters + ---------- + dtype : dtype + data type to produce + type : string + 'unary': create data for unary operations, creates one input + and output array + 'binary': create data for unary operations, creates two input + and output array + max_size : integer + maximum size of data to produce + + Returns + ------- + if type is 'unary' yields one output, one input array and a message + containing information on the data + if type is 'binary' yields one output array, two input array and a message + containing information on the data + + """ + ufmt = 'unary offset=(%d, %d), size=%d, dtype=%r, %s' + bfmt = 'binary offset=(%d, %d, %d), size=%d, dtype=%r, %s' + for o in range(3): + for s in range(o + 2, max(o + 3, max_size)): + if type == 'unary': + inp = lambda: arange(s, dtype=dtype)[o:] + out = empty((s,), dtype=dtype)[o:] + yield out, inp(), ufmt % (o, o, s, dtype, 'out of place') + d = inp() + yield d, d, ufmt % (o, o, s, dtype, 'in place') + yield out[1:], inp()[:-1], ufmt % \ + (o + 1, o, s - 1, dtype, 'out of place') + yield out[:-1], inp()[1:], ufmt % \ + (o, o + 1, s - 1, dtype, 'out of place') + yield inp()[:-1], inp()[1:], ufmt % \ + (o, o + 1, s - 1, dtype, 'aliased') + yield inp()[1:], inp()[:-1], ufmt % \ + (o + 1, o, s - 1, dtype, 'aliased') + if type == 'binary': + inp1 = lambda: arange(s, dtype=dtype)[o:] + inp2 = lambda: arange(s, dtype=dtype)[o:] + out = empty((s,), dtype=dtype)[o:] + yield out, inp1(), inp2(), bfmt % \ + (o, o, o, s, dtype, 'out of place') + d = inp1() + yield d, d, inp2(), bfmt % \ + (o, o, o, s, dtype, 'in place1') + d = inp2() + yield d, inp1(), d, bfmt % \ + (o, o, o, s, dtype, 'in place2') + yield out[1:], inp1()[:-1], inp2()[:-1], bfmt % \ + (o + 1, o, o, s - 1, dtype, 'out of place') + yield out[:-1], inp1()[1:], inp2()[:-1], bfmt % \ + (o, o + 1, o, s - 1, dtype, 'out of place') + yield out[:-1], inp1()[:-1], inp2()[1:], bfmt % \ + (o, o, o + 1, s - 1, dtype, 'out of place') + yield inp1()[1:], inp1()[:-1], inp2()[:-1], bfmt % \ + (o + 1, o, o, s - 1, dtype, 'aliased') + yield inp1()[:-1], inp1()[1:], inp2()[:-1], bfmt % \ + (o, o + 1, o, s - 1, dtype, 'aliased') + yield inp1()[:-1], inp1()[:-1], inp2()[1:], bfmt % \ + (o, o, o + 1, s - 1, dtype, 'aliased') + + +class IgnoreException(Exception): + "Ignoring this exception due to disabled feature" + + +@contextlib.contextmanager +def tempdir(*args, **kwargs): + """Context manager to provide a temporary test folder. + + All arguments are passed as this to the underlying tempfile.mkdtemp + function. + + """ + tmpdir = mkdtemp(*args, **kwargs) + try: + yield tmpdir + finally: + shutil.rmtree(tmpdir) + + +@contextlib.contextmanager +def temppath(*args, **kwargs): + """Context manager for temporary files. + + Context manager that returns the path to a closed temporary file. Its + parameters are the same as for tempfile.mkstemp and are passed directly + to that function. The underlying file is removed when the context is + exited, so it should be closed at that time. + + Windows does not allow a temporary file to be opened if it is already + open, so the underlying file must be closed after opening before it + can be opened again. + + """ + fd, path = mkstemp(*args, **kwargs) + os.close(fd) + try: + yield path + finally: + os.remove(path) + + +class clear_and_catch_warnings(warnings.catch_warnings): + """ Context manager that resets warning registry for catching warnings + + Warnings can be slippery, because, whenever a warning is triggered, Python + adds a ``__warningregistry__`` member to the *calling* module. This makes + it impossible to retrigger the warning in this module, whatever you put in + the warnings filters. This context manager accepts a sequence of `modules` + as a keyword argument to its constructor and: + + * stores and removes any ``__warningregistry__`` entries in given `modules` + on entry; + * resets ``__warningregistry__`` to its previous state on exit. + + This makes it possible to trigger any warning afresh inside the context + manager without disturbing the state of warnings outside. + + For compatibility with Python 3.0, please consider all arguments to be + keyword-only. + + Parameters + ---------- + record : bool, optional + Specifies whether warnings should be captured by a custom + implementation of ``warnings.showwarning()`` and be appended to a list + returned by the context manager. Otherwise None is returned by the + context manager. The objects appended to the list are arguments whose + attributes mirror the arguments to ``showwarning()``. + modules : sequence, optional + Sequence of modules for which to reset warnings registry on entry and + restore on exit. To work correctly, all 'ignore' filters should + filter by one of these modules. + + Examples + -------- + >>> import warnings + >>> with clear_and_catch_warnings(modules=[np.core.fromnumeric]): + ... warnings.simplefilter('always') + ... warnings.filterwarnings('ignore', module='np.core.fromnumeric') + ... # do something that raises a warning but ignore those in + ... # np.core.fromnumeric + """ + class_modules = () + + def __init__(self, record=False, modules=()): + self.modules = set(modules).union(self.class_modules) + self._warnreg_copies = {} + super(clear_and_catch_warnings, self).__init__(record=record) + + def __enter__(self): + for mod in self.modules: + if hasattr(mod, '__warningregistry__'): + mod_reg = mod.__warningregistry__ + self._warnreg_copies[mod] = mod_reg.copy() + mod_reg.clear() + return super(clear_and_catch_warnings, self).__enter__() + + def __exit__(self, *exc_info): + super(clear_and_catch_warnings, self).__exit__(*exc_info) + for mod in self.modules: + if hasattr(mod, '__warningregistry__'): + mod.__warningregistry__.clear() + if mod in self._warnreg_copies: + mod.__warningregistry__.update(self._warnreg_copies[mod]) + + +class suppress_warnings(object): + """ + Context manager and decorator doing much the same as + ``warnings.catch_warnings``. + + However, it also provides a filter mechanism to work around + http://bugs.python.org/issue4180. + + This bug causes Python before 3.4 to not reliably show warnings again + after they have been ignored once (even within catch_warnings). It + means that no "ignore" filter can be used easily, since following + tests might need to see the warning. Additionally it allows easier + specificity for testing warnings and can be nested. + + Parameters + ---------- + forwarding_rule : str, optional + One of "always", "once", "module", or "location". Analogous to + the usual warnings module filter mode, it is useful to reduce + noise mostly on the outmost level. Unsuppressed and unrecorded + warnings will be forwarded based on this rule. Defaults to "always". + "location" is equivalent to the warnings "default", match by exact + location the warning warning originated from. + + Notes + ----- + Filters added inside the context manager will be discarded again + when leaving it. Upon entering all filters defined outside a + context will be applied automatically. + + When a recording filter is added, matching warnings are stored in the + ``log`` attribute as well as in the list returned by ``record``. + + If filters are added and the ``module`` keyword is given, the + warning registry of this module will additionally be cleared when + applying it, entering the context, or exiting it. This could cause + warnings to appear a second time after leaving the context if they + were configured to be printed once (default) and were already + printed before the context was entered. + + Nesting this context manager will work as expected when the + forwarding rule is "always" (default). Unfiltered and unrecorded + warnings will be passed out and be matched by the outer level. + On the outmost level they will be printed (or caught by another + warnings context). The forwarding rule argument can modify this + behaviour. + + Like ``catch_warnings`` this context manager is not threadsafe. + + Examples + -------- + >>> with suppress_warnings() as sup: + ... sup.filter(DeprecationWarning, "Some text") + ... sup.filter(module=np.ma.core) + ... log = sup.record(FutureWarning, "Does this occur?") + ... command_giving_warnings() + ... # The FutureWarning was given once, the filtered warnings were + ... # ignored. All other warnings abide outside settings (may be + ... # printed/error) + ... assert_(len(log) == 1) + ... assert_(len(sup.log) == 1) # also stored in log attribute + + Or as a decorator: + + >>> sup = suppress_warnings() + >>> sup.filter(module=np.ma.core) # module must match exact + >>> @sup + >>> def some_function(): + ... # do something which causes a warning in np.ma.core + ... pass + """ + def __init__(self, forwarding_rule="always"): + self._entered = False + + # Suppressions are either instance or defined inside one with block: + self._suppressions = [] + + if forwarding_rule not in {"always", "module", "once", "location"}: + raise ValueError("unsupported forwarding rule.") + self._forwarding_rule = forwarding_rule + + def _clear_registries(self): + if hasattr(warnings, "_filters_mutated"): + # clearing the registry should not be necessary on new pythons, + # instead the filters should be mutated. + warnings._filters_mutated() + return + # Simply clear the registry, this should normally be harmless, + # note that on new pythons it would be invalidated anyway. + for module in self._tmp_modules: + if hasattr(module, "__warningregistry__"): + module.__warningregistry__.clear() + + def _filter(self, category=Warning, message="", module=None, record=False): + if record: + record = [] # The log where to store warnings + else: + record = None + if self._entered: + if module is None: + warnings.filterwarnings( + "always", category=category, message=message) + else: + module_regex = module.__name__.replace('.', r'\.') + '$' + warnings.filterwarnings( + "always", category=category, message=message, + module=module_regex) + self._tmp_modules.add(module) + self._clear_registries() + + self._tmp_suppressions.append( + (category, message, re.compile(message, re.I), module, record)) + else: + self._suppressions.append( + (category, message, re.compile(message, re.I), module, record)) + + return record + + def filter(self, category=Warning, message="", module=None): + """ + Add a new suppressing filter or apply it if the state is entered. + + Parameters + ---------- + category : class, optional + Warning class to filter + message : string, optional + Regular expression matching the warning message. + module : module, optional + Module to filter for. Note that the module (and its file) + must match exactly and cannot be a submodule. This may make + it unreliable for external modules. + + Notes + ----- + When added within a context, filters are only added inside + the context and will be forgotten when the context is exited. + """ + self._filter(category=category, message=message, module=module, + record=False) + + def record(self, category=Warning, message="", module=None): + """ + Append a new recording filter or apply it if the state is entered. + + All warnings matching will be appended to the ``log`` attribute. + + Parameters + ---------- + category : class, optional + Warning class to filter + message : string, optional + Regular expression matching the warning message. + module : module, optional + Module to filter for. Note that the module (and its file) + must match exactly and cannot be a submodule. This may make + it unreliable for external modules. + + Returns + ------- + log : list + A list which will be filled with all matched warnings. + + Notes + ----- + When added within a context, filters are only added inside + the context and will be forgotten when the context is exited. + """ + return self._filter(category=category, message=message, module=module, + record=True) + + def __enter__(self): + if self._entered: + raise RuntimeError("cannot enter suppress_warnings twice.") + + self._orig_show = warnings.showwarning + self._filters = warnings.filters + warnings.filters = self._filters[:] + + self._entered = True + self._tmp_suppressions = [] + self._tmp_modules = set() + self._forwarded = set() + + self.log = [] # reset global log (no need to keep same list) + + for cat, mess, _, mod, log in self._suppressions: + if log is not None: + del log[:] # clear the log + if mod is None: + warnings.filterwarnings( + "always", category=cat, message=mess) + else: + module_regex = mod.__name__.replace('.', r'\.') + '$' + warnings.filterwarnings( + "always", category=cat, message=mess, + module=module_regex) + self._tmp_modules.add(mod) + warnings.showwarning = self._showwarning + self._clear_registries() + + return self + + def __exit__(self, *exc_info): + warnings.showwarning = self._orig_show + warnings.filters = self._filters + self._clear_registries() + self._entered = False + del self._orig_show + del self._filters + + def _showwarning(self, message, category, filename, lineno, + *args, **kwargs): + use_warnmsg = kwargs.pop("use_warnmsg", None) + for cat, _, pattern, mod, rec in ( + self._suppressions + self._tmp_suppressions)[::-1]: + if (issubclass(category, cat) and + pattern.match(message.args[0]) is not None): + if mod is None: + # Message and category match, either recorded or ignored + if rec is not None: + msg = WarningMessage(message, category, filename, + lineno, **kwargs) + self.log.append(msg) + rec.append(msg) + return + # Use startswith, because warnings strips the c or o from + # .pyc/.pyo files. + elif mod.__file__.startswith(filename): + # The message and module (filename) match + if rec is not None: + msg = WarningMessage(message, category, filename, + lineno, **kwargs) + self.log.append(msg) + rec.append(msg) + return + + # There is no filter in place, so pass to the outside handler + # unless we should only pass it once + if self._forwarding_rule == "always": + if use_warnmsg is None: + self._orig_show(message, category, filename, lineno, + *args, **kwargs) + else: + self._orig_showmsg(use_warnmsg) + return + + if self._forwarding_rule == "once": + signature = (message.args, category) + elif self._forwarding_rule == "module": + signature = (message.args, category, filename) + elif self._forwarding_rule == "location": + signature = (message.args, category, filename, lineno) + + if signature in self._forwarded: + return + self._forwarded.add(signature) + if use_warnmsg is None: + self._orig_show(message, category, filename, lineno, *args, + **kwargs) + else: + self._orig_showmsg(use_warnmsg) + + def __call__(self, func): + """ + Function decorator to apply certain suppressions to a whole + function. + """ + @wraps(func) + def new_func(*args, **kwargs): + with self: + return func(*args, **kwargs) + + return new_func diff --git a/numpy/testing/noseclasses.py b/numpy/testing/noseclasses.py new file mode 100644 index 0000000..563ed14 --- /dev/null +++ b/numpy/testing/noseclasses.py @@ -0,0 +1,6 @@ +""" +Back compatibility noseclasses module. It will import the appropriate +set of tools + +""" +from .nose_tools.noseclasses import * diff --git a/numpy/testing/nosetester.py b/numpy/testing/nosetester.py new file mode 100644 index 0000000..b726684 --- /dev/null +++ b/numpy/testing/nosetester.py @@ -0,0 +1,10 @@ +""" +Back compatibility nosetester module. It will import the appropriate +set of tools + +""" +from .nose_tools.nosetester import * + +__all__ = ['get_package_name', 'run_module_suite', 'NoseTester', + '_numpy_tester', 'get_package_name', 'import_nose', + 'suppress_warnings'] diff --git a/numpy/testing/print_coercion_tables.py b/numpy/testing/print_coercion_tables.py new file mode 100755 index 0000000..3a359f4 --- /dev/null +++ b/numpy/testing/print_coercion_tables.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +"""Prints type-coercion tables for the built-in NumPy types + +""" +from __future__ import division, absolute_import, print_function + +import numpy as np + +# Generic object that can be added, but doesn't do anything else +class GenericObject(object): + def __init__(self, v): + self.v = v + + def __add__(self, other): + return self + + def __radd__(self, other): + return self + + dtype = np.dtype('O') + +def print_cancast_table(ntypes): + print('X', end=' ') + for char in ntypes: + print(char, end=' ') + print() + for row in ntypes: + print(row, end=' ') + for col in ntypes: + print(int(np.can_cast(row, col)), end=' ') + print() + +def print_coercion_table(ntypes, inputfirstvalue, inputsecondvalue, firstarray, use_promote_types=False): + print('+', end=' ') + for char in ntypes: + print(char, end=' ') + print() + for row in ntypes: + if row == 'O': + rowtype = GenericObject + else: + rowtype = np.obj2sctype(row) + + print(row, end=' ') + for col in ntypes: + if col == 'O': + coltype = GenericObject + else: + coltype = np.obj2sctype(col) + try: + if firstarray: + rowvalue = np.array([rowtype(inputfirstvalue)], dtype=rowtype) + else: + rowvalue = rowtype(inputfirstvalue) + colvalue = coltype(inputsecondvalue) + if use_promote_types: + char = np.promote_types(rowvalue.dtype, colvalue.dtype).char + else: + value = np.add(rowvalue, colvalue) + if isinstance(value, np.ndarray): + char = value.dtype.char + else: + char = np.dtype(type(value)).char + except ValueError: + char = '!' + except OverflowError: + char = '@' + except TypeError: + char = '#' + print(char, end=' ') + print() + +print("can cast") +print_cancast_table(np.typecodes['All']) +print() +print("In these tables, ValueError is '!', OverflowError is '@', TypeError is '#'") +print() +print("scalar + scalar") +print_coercion_table(np.typecodes['All'], 0, 0, False) +print() +print("scalar + neg scalar") +print_coercion_table(np.typecodes['All'], 0, -1, False) +print() +print("array + scalar") +print_coercion_table(np.typecodes['All'], 0, 0, True) +print() +print("array + neg scalar") +print_coercion_table(np.typecodes['All'], 0, -1, True) +print() +print("promote_types") +print_coercion_table(np.typecodes['All'], 0, 0, False, True) diff --git a/numpy/testing/setup.py b/numpy/testing/setup.py new file mode 100755 index 0000000..a5e9656 --- /dev/null +++ b/numpy/testing/setup.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +from __future__ import division, print_function + + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('testing', parent_package, top_path) + + config.add_subpackage('nose_tools') + config.add_data_dir('tests') + return config + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(maintainer="NumPy Developers", + maintainer_email="numpy-dev@numpy.org", + description="NumPy test module", + url="http://www.numpy.org", + license="NumPy License (BSD Style)", + configuration=configuration, + ) diff --git a/numpy/testing/tests/__init__.py b/numpy/testing/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/testing/tests/__init__.py diff --git a/numpy/testing/tests/test_decorators.py b/numpy/testing/tests/test_decorators.py new file mode 100644 index 0000000..1258a92 --- /dev/null +++ b/numpy/testing/tests/test_decorators.py @@ -0,0 +1,200 @@ +""" +Test the decorators from ``testing.decorators``. + +""" +from __future__ import division, absolute_import, print_function + +import warnings + +from numpy.testing import (dec, assert_, assert_raises, run_module_suite, + SkipTest, KnownFailureException) + + +def test_slow(): + @dec.slow + def slow_func(x, y, z): + pass + + assert_(slow_func.slow) + + +def test_setastest(): + @dec.setastest() + def f_default(a): + pass + + @dec.setastest(True) + def f_istest(a): + pass + + @dec.setastest(False) + def f_isnottest(a): + pass + + assert_(f_default.__test__) + assert_(f_istest.__test__) + assert_(not f_isnottest.__test__) + + +class DidntSkipException(Exception): + pass + +def test_skip_functions_hardcoded(): + @dec.skipif(True) + def f1(x): + raise DidntSkipException + + try: + f1('a') + except DidntSkipException: + raise Exception('Failed to skip') + except SkipTest: + pass + + @dec.skipif(False) + def f2(x): + raise DidntSkipException + + try: + f2('a') + except DidntSkipException: + pass + except SkipTest: + raise Exception('Skipped when not expected to') + + +def test_skip_functions_callable(): + def skip_tester(): + return skip_flag == 'skip me!' + + @dec.skipif(skip_tester) + def f1(x): + raise DidntSkipException + + try: + skip_flag = 'skip me!' + f1('a') + except DidntSkipException: + raise Exception('Failed to skip') + except SkipTest: + pass + + @dec.skipif(skip_tester) + def f2(x): + raise DidntSkipException + + try: + skip_flag = 'five is right out!' + f2('a') + except DidntSkipException: + pass + except SkipTest: + raise Exception('Skipped when not expected to') + + +def test_skip_generators_hardcoded(): + @dec.knownfailureif(True, "This test is known to fail") + def g1(x): + for i in range(x): + yield i + + try: + for j in g1(10): + pass + except KnownFailureException: + pass + else: + raise Exception('Failed to mark as known failure') + + @dec.knownfailureif(False, "This test is NOT known to fail") + def g2(x): + for i in range(x): + yield i + raise DidntSkipException('FAIL') + + try: + for j in g2(10): + pass + except KnownFailureException: + raise Exception('Marked incorrectly as known failure') + except DidntSkipException: + pass + + +def test_skip_generators_callable(): + def skip_tester(): + return skip_flag == 'skip me!' + + @dec.knownfailureif(skip_tester, "This test is known to fail") + def g1(x): + for i in range(x): + yield i + + try: + skip_flag = 'skip me!' + for j in g1(10): + pass + except KnownFailureException: + pass + else: + raise Exception('Failed to mark as known failure') + + @dec.knownfailureif(skip_tester, "This test is NOT known to fail") + def g2(x): + for i in range(x): + yield i + raise DidntSkipException('FAIL') + + try: + skip_flag = 'do not skip' + for j in g2(10): + pass + except KnownFailureException: + raise Exception('Marked incorrectly as known failure') + except DidntSkipException: + pass + + +def test_deprecated(): + @dec.deprecated(True) + def non_deprecated_func(): + pass + + @dec.deprecated() + def deprecated_func(): + import warnings + warnings.warn("TEST: deprecated func", DeprecationWarning) + + @dec.deprecated() + def deprecated_func2(): + import warnings + warnings.warn("AHHHH") + raise ValueError + + @dec.deprecated() + def deprecated_func3(): + import warnings + warnings.warn("AHHHH") + + # marked as deprecated, but does not raise DeprecationWarning + assert_raises(AssertionError, non_deprecated_func) + # should be silent + deprecated_func() + with warnings.catch_warnings(record=True): + warnings.simplefilter("always") # do not propagate unrelated warnings + # fails if deprecated decorator just disables test. See #1453. + assert_raises(ValueError, deprecated_func2) + # warning is not a DeprecationWarning + assert_raises(AssertionError, deprecated_func3) + + +@dec.parametrize('base, power, expected', + [(1, 1, 1), + (2, 1, 2), + (2, 2, 4)]) +def test_parametrize(base, power, expected): + assert_(base**power == expected) + + +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/testing/tests/test_doctesting.py b/numpy/testing/tests/test_doctesting.py new file mode 100644 index 0000000..43f9fb6 --- /dev/null +++ b/numpy/testing/tests/test_doctesting.py @@ -0,0 +1,56 @@ +""" Doctests for NumPy-specific nose/doctest modifications + +""" +from __future__ import division, absolute_import, print_function + +# try the #random directive on the output line +def check_random_directive(): + ''' + >>> 2+2 + #random: may vary on your system + ''' + +# check the implicit "import numpy as np" +def check_implicit_np(): + ''' + >>> np.array([1,2,3]) + array([1, 2, 3]) + ''' + +# there's some extraneous whitespace around the correct responses +def check_whitespace_enabled(): + ''' + # whitespace after the 3 + >>> 1+2 + 3 + + # whitespace before the 7 + >>> 3+4 + 7 + ''' + +def check_empty_output(): + """ Check that no output does not cause an error. + + This is related to nose bug 445; the numpy plugin changed the + doctest-result-variable default and therefore hit this bug: + http://code.google.com/p/python-nose/issues/detail?id=445 + + >>> a = 10 + """ + +def check_skip(): + """ Check skip directive + + The test below should not run + + >>> 1/0 #doctest: +SKIP + """ + + +if __name__ == '__main__': + # Run tests outside numpy test rig + import nose + from numpy.testing.noseclasses import NumpyDoctest + argv = ['', __file__, '--with-numpydoctest'] + nose.core.TestProgram(argv=argv, addplugins=[NumpyDoctest()]) diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py new file mode 100644 index 0000000..77fb974 --- /dev/null +++ b/numpy/testing/tests/test_utils.py @@ -0,0 +1,1361 @@ +from __future__ import division, absolute_import, print_function + +import warnings +import sys +import os +import itertools +import textwrap + +import numpy as np +from numpy.testing import ( + assert_equal, assert_array_equal, assert_almost_equal, + assert_array_almost_equal, assert_array_less, build_err_msg, + raises, assert_raises, assert_warns, assert_no_warnings, + assert_allclose, assert_approx_equal, + assert_array_almost_equal_nulp, assert_array_max_ulp, + clear_and_catch_warnings, suppress_warnings, run_module_suite, + assert_string_equal, assert_, tempdir, temppath, + ) +import unittest + + +class _GenericTest(object): + + def _test_equal(self, a, b): + self._assert_func(a, b) + + def _test_not_equal(self, a, b): + try: + self._assert_func(a, b) + except AssertionError: + pass + else: + raise AssertionError("a and b are found equal but are not") + + def test_array_rank1_eq(self): + """Test two equal array of rank 1 are found equal.""" + a = np.array([1, 2]) + b = np.array([1, 2]) + + self._test_equal(a, b) + + def test_array_rank1_noteq(self): + """Test two different array of rank 1 are found not equal.""" + a = np.array([1, 2]) + b = np.array([2, 2]) + + self._test_not_equal(a, b) + + def test_array_rank2_eq(self): + """Test two equal array of rank 2 are found equal.""" + a = np.array([[1, 2], [3, 4]]) + b = np.array([[1, 2], [3, 4]]) + + self._test_equal(a, b) + + def test_array_diffshape(self): + """Test two arrays with different shapes are found not equal.""" + a = np.array([1, 2]) + b = np.array([[1, 2], [1, 2]]) + + self._test_not_equal(a, b) + + def test_objarray(self): + """Test object arrays.""" + a = np.array([1, 1], dtype=object) + self._test_equal(a, 1) + + def test_array_likes(self): + self._test_equal([1, 2, 3], (1, 2, 3)) + + +class TestArrayEqual(_GenericTest, unittest.TestCase): + + def setUp(self): + self._assert_func = assert_array_equal + + def test_generic_rank1(self): + """Test rank 1 array for all dtypes.""" + def foo(t): + a = np.empty(2, t) + a.fill(1) + b = a.copy() + c = a.copy() + c.fill(0) + self._test_equal(a, b) + self._test_not_equal(c, b) + + # Test numeric types and object + for t in '?bhilqpBHILQPfdgFDG': + foo(t) + + # Test strings + for t in ['S1', 'U1']: + foo(t) + + def test_generic_rank3(self): + """Test rank 3 array for all dtypes.""" + def foo(t): + a = np.empty((4, 2, 3), t) + a.fill(1) + b = a.copy() + c = a.copy() + c.fill(0) + self._test_equal(a, b) + self._test_not_equal(c, b) + + # Test numeric types and object + for t in '?bhilqpBHILQPfdgFDG': + foo(t) + + # Test strings + for t in ['S1', 'U1']: + foo(t) + + def test_nan_array(self): + """Test arrays with nan values in them.""" + a = np.array([1, 2, np.nan]) + b = np.array([1, 2, np.nan]) + + self._test_equal(a, b) + + c = np.array([1, 2, 3]) + self._test_not_equal(c, b) + + def test_string_arrays(self): + """Test two arrays with different shapes are found not equal.""" + a = np.array(['floupi', 'floupa']) + b = np.array(['floupi', 'floupa']) + + self._test_equal(a, b) + + c = np.array(['floupipi', 'floupa']) + + self._test_not_equal(c, b) + + def test_recarrays(self): + """Test record arrays.""" + a = np.empty(2, [('floupi', float), ('floupa', float)]) + a['floupi'] = [1, 2] + a['floupa'] = [1, 2] + b = a.copy() + + self._test_equal(a, b) + + c = np.empty(2, [('floupipi', float), ('floupa', float)]) + c['floupipi'] = a['floupi'].copy() + c['floupa'] = a['floupa'].copy() + + with suppress_warnings() as sup: + l = sup.record(FutureWarning, message="elementwise == ") + self._test_not_equal(c, b) + assert_(len(l) == 1) + + +class TestBuildErrorMessage(unittest.TestCase): + + def test_build_err_msg_defaults(self): + x = np.array([1.00001, 2.00002, 3.00003]) + y = np.array([1.00002, 2.00003, 3.00004]) + err_msg = 'There is a mismatch' + + a = build_err_msg([x, y], err_msg) + b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array([' + '1.00001, 2.00002, 3.00003])\n DESIRED: array([1.00002, ' + '2.00003, 3.00004])') + self.assertEqual(a, b) + + def test_build_err_msg_no_verbose(self): + x = np.array([1.00001, 2.00002, 3.00003]) + y = np.array([1.00002, 2.00003, 3.00004]) + err_msg = 'There is a mismatch' + + a = build_err_msg([x, y], err_msg, verbose=False) + b = '\nItems are not equal: There is a mismatch' + self.assertEqual(a, b) + + def test_build_err_msg_custom_names(self): + x = np.array([1.00001, 2.00002, 3.00003]) + y = np.array([1.00002, 2.00003, 3.00004]) + err_msg = 'There is a mismatch' + + a = build_err_msg([x, y], err_msg, names=('FOO', 'BAR')) + b = ('\nItems are not equal: There is a mismatch\n FOO: array([' + '1.00001, 2.00002, 3.00003])\n BAR: array([1.00002, 2.00003, ' + '3.00004])') + self.assertEqual(a, b) + + def test_build_err_msg_custom_precision(self): + x = np.array([1.000000001, 2.00002, 3.00003]) + y = np.array([1.000000002, 2.00003, 3.00004]) + err_msg = 'There is a mismatch' + + a = build_err_msg([x, y], err_msg, precision=10) + b = ('\nItems are not equal: There is a mismatch\n ACTUAL: array([' + '1.000000001, 2.00002 , 3.00003 ])\n DESIRED: array([' + '1.000000002, 2.00003 , 3.00004 ])') + self.assertEqual(a, b) + + +class TestEqual(TestArrayEqual): + + def setUp(self): + self._assert_func = assert_equal + + def test_nan_items(self): + self._assert_func(np.nan, np.nan) + self._assert_func([np.nan], [np.nan]) + self._test_not_equal(np.nan, [np.nan]) + self._test_not_equal(np.nan, 1) + + def test_inf_items(self): + self._assert_func(np.inf, np.inf) + self._assert_func([np.inf], [np.inf]) + self._test_not_equal(np.inf, [np.inf]) + + def test_datetime(self): + self._test_equal( + np.datetime64("2017-01-01", "s"), + np.datetime64("2017-01-01", "s") + ) + self._test_equal( + np.datetime64("2017-01-01", "s"), + np.datetime64("2017-01-01", "m") + ) + + # gh-10081 + self._test_not_equal( + np.datetime64("2017-01-01", "s"), + np.datetime64("2017-01-02", "s") + ) + self._test_not_equal( + np.datetime64("2017-01-01", "s"), + np.datetime64("2017-01-02", "m") + ) + + def test_nat_items(self): + # not a datetime + nadt_no_unit = np.datetime64("NaT") + nadt_s = np.datetime64("NaT", "s") + nadt_d = np.datetime64("NaT", "ns") + # not a timedelta + natd_no_unit = np.timedelta64("NaT") + natd_s = np.timedelta64("NaT", "s") + natd_d = np.timedelta64("NaT", "ns") + + dts = [nadt_no_unit, nadt_s, nadt_d] + tds = [natd_no_unit, natd_s, natd_d] + for a, b in itertools.product(dts, dts): + self._assert_func(a, b) + self._assert_func([a], [b]) + self._test_not_equal([a], b) + + for a, b in itertools.product(tds, tds): + self._assert_func(a, b) + self._assert_func([a], [b]) + self._test_not_equal([a], b) + + for a, b in itertools.product(tds, dts): + self._test_not_equal(a, b) + self._test_not_equal(a, [b]) + self._test_not_equal([a], [b]) + self._test_not_equal([a], np.datetime64("2017-01-01", "s")) + self._test_not_equal([b], np.datetime64("2017-01-01", "s")) + self._test_not_equal([a], np.timedelta64(123, "s")) + self._test_not_equal([b], np.timedelta64(123, "s")) + + def test_non_numeric(self): + self._assert_func('ab', 'ab') + self._test_not_equal('ab', 'abb') + + def test_complex_item(self): + self._assert_func(complex(1, 2), complex(1, 2)) + self._assert_func(complex(1, np.nan), complex(1, np.nan)) + self._test_not_equal(complex(1, np.nan), complex(1, 2)) + self._test_not_equal(complex(np.nan, 1), complex(1, np.nan)) + self._test_not_equal(complex(np.nan, np.inf), complex(np.nan, 2)) + + def test_negative_zero(self): + self._test_not_equal(np.PZERO, np.NZERO) + + def test_complex(self): + x = np.array([complex(1, 2), complex(1, np.nan)]) + y = np.array([complex(1, 2), complex(1, 2)]) + self._assert_func(x, x) + self._test_not_equal(x, y) + + def test_error_message(self): + try: + self._assert_func(np.array([1, 2]), np.matrix([1, 2])) + except AssertionError as e: + msg = str(e) + msg2 = msg.replace("shapes (2L,), (1L, 2L)", "shapes (2,), (1, 2)") + msg_reference = textwrap.dedent("""\ + + Arrays are not equal + + (shapes (2,), (1, 2) mismatch) + x: array([1, 2]) + y: matrix([[1, 2]])""") + try: + self.assertEqual(msg, msg_reference) + except AssertionError: + self.assertEqual(msg2, msg_reference) + else: + raise AssertionError("Did not raise") + + +class TestArrayAlmostEqual(_GenericTest, unittest.TestCase): + + def setUp(self): + self._assert_func = assert_array_almost_equal + + def test_closeness(self): + # Note that in the course of time we ended up with + # `abs(x - y) < 1.5 * 10**(-decimal)` + # instead of the previously documented + # `abs(x - y) < 0.5 * 10**(-decimal)` + # so this check serves to preserve the wrongness. + + # test scalars + self._assert_func(1.499999, 0.0, decimal=0) + self.assertRaises(AssertionError, + lambda: self._assert_func(1.5, 0.0, decimal=0)) + + # test arrays + self._assert_func([1.499999], [0.0], decimal=0) + self.assertRaises(AssertionError, + lambda: self._assert_func([1.5], [0.0], decimal=0)) + + def test_simple(self): + x = np.array([1234.2222]) + y = np.array([1234.2223]) + + self._assert_func(x, y, decimal=3) + self._assert_func(x, y, decimal=4) + self.assertRaises(AssertionError, + lambda: self._assert_func(x, y, decimal=5)) + + def test_nan(self): + anan = np.array([np.nan]) + aone = np.array([1]) + ainf = np.array([np.inf]) + self._assert_func(anan, anan) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, aone)) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(ainf, anan)) + + def test_inf(self): + a = np.array([[1., 2.], [3., 4.]]) + b = a.copy() + a[0, 0] = np.inf + self.assertRaises(AssertionError, + lambda: self._assert_func(a, b)) + b[0, 0] = -np.inf + self.assertRaises(AssertionError, + lambda: self._assert_func(a, b)) + + def test_subclass(self): + a = np.array([[1., 2.], [3., 4.]]) + b = np.ma.masked_array([[1., 2.], [0., 4.]], + [[False, False], [True, False]]) + self._assert_func(a, b) + self._assert_func(b, a) + self._assert_func(b, b) + + def test_matrix(self): + # Matrix slicing keeps things 2-D, while array does not necessarily. + # See gh-8452. + m1 = np.matrix([[1., 2.]]) + m2 = np.matrix([[1., np.nan]]) + m3 = np.matrix([[1., -np.inf]]) + m4 = np.matrix([[np.nan, np.inf]]) + m5 = np.matrix([[1., 2.], [np.nan, np.inf]]) + for m in m1, m2, m3, m4, m5: + self._assert_func(m, m) + a = np.array(m) + self._assert_func(a, m) + self._assert_func(m, a) + + def test_subclass_that_cannot_be_bool(self): + # While we cannot guarantee testing functions will always work for + # subclasses, the tests should ideally rely only on subclasses having + # comparison operators, not on them being able to store booleans + # (which, e.g., astropy Quantity cannot usefully do). See gh-8452. + class MyArray(np.ndarray): + def __lt__(self, other): + return super(MyArray, self).__lt__(other).view(np.ndarray) + + def all(self, *args, **kwargs): + raise NotImplementedError + + a = np.array([1., 2.]).view(MyArray) + self._assert_func(a, a) + + +class TestAlmostEqual(_GenericTest, unittest.TestCase): + + def setUp(self): + self._assert_func = assert_almost_equal + + def test_closeness(self): + # Note that in the course of time we ended up with + # `abs(x - y) < 1.5 * 10**(-decimal)` + # instead of the previously documented + # `abs(x - y) < 0.5 * 10**(-decimal)` + # so this check serves to preserve the wrongness. + + # test scalars + self._assert_func(1.499999, 0.0, decimal=0) + self.assertRaises(AssertionError, + lambda: self._assert_func(1.5, 0.0, decimal=0)) + + # test arrays + self._assert_func([1.499999], [0.0], decimal=0) + self.assertRaises(AssertionError, + lambda: self._assert_func([1.5], [0.0], decimal=0)) + + def test_nan_item(self): + self._assert_func(np.nan, np.nan) + self.assertRaises(AssertionError, + lambda: self._assert_func(np.nan, 1)) + self.assertRaises(AssertionError, + lambda: self._assert_func(np.nan, np.inf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(np.inf, np.nan)) + + def test_inf_item(self): + self._assert_func(np.inf, np.inf) + self._assert_func(-np.inf, -np.inf) + self.assertRaises(AssertionError, + lambda: self._assert_func(np.inf, 1)) + self.assertRaises(AssertionError, + lambda: self._assert_func(-np.inf, np.inf)) + + def test_simple_item(self): + self._test_not_equal(1, 2) + + def test_complex_item(self): + self._assert_func(complex(1, 2), complex(1, 2)) + self._assert_func(complex(1, np.nan), complex(1, np.nan)) + self._assert_func(complex(np.inf, np.nan), complex(np.inf, np.nan)) + self._test_not_equal(complex(1, np.nan), complex(1, 2)) + self._test_not_equal(complex(np.nan, 1), complex(1, np.nan)) + self._test_not_equal(complex(np.nan, np.inf), complex(np.nan, 2)) + + def test_complex(self): + x = np.array([complex(1, 2), complex(1, np.nan)]) + z = np.array([complex(1, 2), complex(np.nan, 1)]) + y = np.array([complex(1, 2), complex(1, 2)]) + self._assert_func(x, x) + self._test_not_equal(x, y) + self._test_not_equal(x, z) + + def test_error_message(self): + """Check the message is formatted correctly for the decimal value""" + x = np.array([1.00000000001, 2.00000000002, 3.00003]) + y = np.array([1.00000000002, 2.00000000003, 3.00004]) + + # test with a different amount of decimal digits + # note that we only check for the formatting of the arrays themselves + b = ('x: array([1.00000000001, 2.00000000002, 3.00003 ' + ' ])\n y: array([1.00000000002, 2.00000000003, 3.00004 ])') + try: + self._assert_func(x, y, decimal=12) + except AssertionError as e: + # remove anything that's not the array string + self.assertEqual(str(e).split('%)\n ')[1], b) + + # with the default value of decimal digits, only the 3rd element differs + # note that we only check for the formatting of the arrays themselves + b = ('x: array([1. , 2. , 3.00003])\n y: array([1. , ' + '2. , 3.00004])') + try: + self._assert_func(x, y) + except AssertionError as e: + # remove anything that's not the array string + self.assertEqual(str(e).split('%)\n ')[1], b) + + def test_matrix(self): + # Matrix slicing keeps things 2-D, while array does not necessarily. + # See gh-8452. + m1 = np.matrix([[1., 2.]]) + m2 = np.matrix([[1., np.nan]]) + m3 = np.matrix([[1., -np.inf]]) + m4 = np.matrix([[np.nan, np.inf]]) + m5 = np.matrix([[1., 2.], [np.nan, np.inf]]) + for m in m1, m2, m3, m4, m5: + self._assert_func(m, m) + a = np.array(m) + self._assert_func(a, m) + self._assert_func(m, a) + + def test_subclass_that_cannot_be_bool(self): + # While we cannot guarantee testing functions will always work for + # subclasses, the tests should ideally rely only on subclasses having + # comparison operators, not on them being able to store booleans + # (which, e.g., astropy Quantity cannot usefully do). See gh-8452. + class MyArray(np.ndarray): + def __lt__(self, other): + return super(MyArray, self).__lt__(other).view(np.ndarray) + + def all(self, *args, **kwargs): + raise NotImplementedError + + a = np.array([1., 2.]).view(MyArray) + self._assert_func(a, a) + + +class TestApproxEqual(unittest.TestCase): + + def setUp(self): + self._assert_func = assert_approx_equal + + def test_simple_arrays(self): + x = np.array([1234.22]) + y = np.array([1234.23]) + + self._assert_func(x, y, significant=5) + self._assert_func(x, y, significant=6) + self.assertRaises(AssertionError, + lambda: self._assert_func(x, y, significant=7)) + + def test_simple_items(self): + x = 1234.22 + y = 1234.23 + + self._assert_func(x, y, significant=4) + self._assert_func(x, y, significant=5) + self._assert_func(x, y, significant=6) + self.assertRaises(AssertionError, + lambda: self._assert_func(x, y, significant=7)) + + def test_nan_array(self): + anan = np.array(np.nan) + aone = np.array(1) + ainf = np.array(np.inf) + self._assert_func(anan, anan) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, aone)) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(ainf, anan)) + + def test_nan_items(self): + anan = np.array(np.nan) + aone = np.array(1) + ainf = np.array(np.inf) + self._assert_func(anan, anan) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, aone)) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(ainf, anan)) + + +class TestArrayAssertLess(unittest.TestCase): + + def setUp(self): + self._assert_func = assert_array_less + + def test_simple_arrays(self): + x = np.array([1.1, 2.2]) + y = np.array([1.2, 2.3]) + + self._assert_func(x, y) + self.assertRaises(AssertionError, + lambda: self._assert_func(y, x)) + + y = np.array([1.0, 2.3]) + + self.assertRaises(AssertionError, + lambda: self._assert_func(x, y)) + self.assertRaises(AssertionError, + lambda: self._assert_func(y, x)) + + def test_rank2(self): + x = np.array([[1.1, 2.2], [3.3, 4.4]]) + y = np.array([[1.2, 2.3], [3.4, 4.5]]) + + self._assert_func(x, y) + self.assertRaises(AssertionError, + lambda: self._assert_func(y, x)) + + y = np.array([[1.0, 2.3], [3.4, 4.5]]) + + self.assertRaises(AssertionError, + lambda: self._assert_func(x, y)) + self.assertRaises(AssertionError, + lambda: self._assert_func(y, x)) + + def test_rank3(self): + x = np.ones(shape=(2, 2, 2)) + y = np.ones(shape=(2, 2, 2))+1 + + self._assert_func(x, y) + self.assertRaises(AssertionError, + lambda: self._assert_func(y, x)) + + y[0, 0, 0] = 0 + + self.assertRaises(AssertionError, + lambda: self._assert_func(x, y)) + self.assertRaises(AssertionError, + lambda: self._assert_func(y, x)) + + def test_simple_items(self): + x = 1.1 + y = 2.2 + + self._assert_func(x, y) + self.assertRaises(AssertionError, + lambda: self._assert_func(y, x)) + + y = np.array([2.2, 3.3]) + + self._assert_func(x, y) + self.assertRaises(AssertionError, + lambda: self._assert_func(y, x)) + + y = np.array([1.0, 3.3]) + + self.assertRaises(AssertionError, + lambda: self._assert_func(x, y)) + + def test_nan_noncompare(self): + anan = np.array(np.nan) + aone = np.array(1) + ainf = np.array(np.inf) + self._assert_func(anan, anan) + self.assertRaises(AssertionError, + lambda: self._assert_func(aone, anan)) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, aone)) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(ainf, anan)) + + def test_nan_noncompare_array(self): + x = np.array([1.1, 2.2, 3.3]) + anan = np.array(np.nan) + + self.assertRaises(AssertionError, + lambda: self._assert_func(x, anan)) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, x)) + + x = np.array([1.1, 2.2, np.nan]) + + self.assertRaises(AssertionError, + lambda: self._assert_func(x, anan)) + self.assertRaises(AssertionError, + lambda: self._assert_func(anan, x)) + + y = np.array([1.0, 2.0, np.nan]) + + self._assert_func(y, x) + self.assertRaises(AssertionError, + lambda: self._assert_func(x, y)) + + def test_inf_compare(self): + aone = np.array(1) + ainf = np.array(np.inf) + + self._assert_func(aone, ainf) + self._assert_func(-ainf, aone) + self._assert_func(-ainf, ainf) + self.assertRaises(AssertionError, + lambda: self._assert_func(ainf, aone)) + self.assertRaises(AssertionError, + lambda: self._assert_func(aone, -ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(ainf, ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(ainf, -ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(-ainf, -ainf)) + + def test_inf_compare_array(self): + x = np.array([1.1, 2.2, np.inf]) + ainf = np.array(np.inf) + + self.assertRaises(AssertionError, + lambda: self._assert_func(x, ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(ainf, x)) + self.assertRaises(AssertionError, + lambda: self._assert_func(x, -ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(-x, -ainf)) + self.assertRaises(AssertionError, + lambda: self._assert_func(-ainf, -x)) + self._assert_func(-ainf, x) + + +class TestRaises(unittest.TestCase): + + def setUp(self): + class MyException(Exception): + pass + + self.e = MyException + + def raises_exception(self, e): + raise e + + def does_not_raise_exception(self): + pass + + def test_correct_catch(self): + raises(self.e)(self.raises_exception)(self.e) # raises? + + def test_wrong_exception(self): + try: + raises(self.e)(self.raises_exception)(RuntimeError) # raises? + except RuntimeError: + return + else: + raise AssertionError("should have caught RuntimeError") + + def test_catch_no_raise(self): + try: + raises(self.e)(self.does_not_raise_exception)() # raises? + except AssertionError: + return + else: + raise AssertionError("should have raised an AssertionError") + + +class TestWarns(unittest.TestCase): + + def test_warn(self): + def f(): + warnings.warn("yo") + return 3 + + before_filters = sys.modules['warnings'].filters[:] + assert_equal(assert_warns(UserWarning, f), 3) + after_filters = sys.modules['warnings'].filters + + assert_raises(AssertionError, assert_no_warnings, f) + assert_equal(assert_no_warnings(lambda x: x, 1), 1) + + # Check that the warnings state is unchanged + assert_equal(before_filters, after_filters, + "assert_warns does not preserver warnings state") + + def test_context_manager(self): + + before_filters = sys.modules['warnings'].filters[:] + with assert_warns(UserWarning): + warnings.warn("yo") + after_filters = sys.modules['warnings'].filters + + def no_warnings(): + with assert_no_warnings(): + warnings.warn("yo") + + assert_raises(AssertionError, no_warnings) + assert_equal(before_filters, after_filters, + "assert_warns does not preserver warnings state") + + def test_warn_wrong_warning(self): + def f(): + warnings.warn("yo", DeprecationWarning) + + failed = False + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + try: + # Should raise a DeprecationWarning + assert_warns(UserWarning, f) + failed = True + except DeprecationWarning: + pass + + if failed: + raise AssertionError("wrong warning caught by assert_warn") + + +class TestAssertAllclose(unittest.TestCase): + + def test_simple(self): + x = 1e-3 + y = 1e-9 + + assert_allclose(x, y, atol=1) + self.assertRaises(AssertionError, assert_allclose, x, y) + + a = np.array([x, y, x, y]) + b = np.array([x, y, x, x]) + + assert_allclose(a, b, atol=1) + self.assertRaises(AssertionError, assert_allclose, a, b) + + b[-1] = y * (1 + 1e-8) + assert_allclose(a, b) + self.assertRaises(AssertionError, assert_allclose, a, b, + rtol=1e-9) + + assert_allclose(6, 10, rtol=0.5) + self.assertRaises(AssertionError, assert_allclose, 10, 6, rtol=0.5) + + def test_min_int(self): + a = np.array([np.iinfo(np.int_).min], dtype=np.int_) + # Should not raise: + assert_allclose(a, a) + + def test_report_fail_percentage(self): + a = np.array([1, 1, 1, 1]) + b = np.array([1, 1, 1, 2]) + try: + assert_allclose(a, b) + msg = '' + except AssertionError as exc: + msg = exc.args[0] + self.assertTrue("mismatch 25.0%" in msg) + + def test_equal_nan(self): + a = np.array([np.nan]) + b = np.array([np.nan]) + # Should not raise: + assert_allclose(a, b, equal_nan=True) + + def test_not_equal_nan(self): + a = np.array([np.nan]) + b = np.array([np.nan]) + self.assertRaises(AssertionError, assert_allclose, a, b, + equal_nan=False) + + def test_equal_nan_default(self): + # Make sure equal_nan default behavior remains unchanged. (All + # of these functions use assert_array_compare under the hood.) + # None of these should raise. + a = np.array([np.nan]) + b = np.array([np.nan]) + assert_array_equal(a, b) + assert_array_almost_equal(a, b) + assert_array_less(a, b) + assert_allclose(a, b) + + +class TestArrayAlmostEqualNulp(unittest.TestCase): + + def test_float64_pass(self): + # The number of units of least precision + # In this case, use a few places above the lowest level (ie nulp=1) + nulp = 5 + x = np.linspace(-20, 20, 50, dtype=np.float64) + x = 10**x + x = np.r_[-x, x] + + # Addition + eps = np.finfo(x.dtype).eps + y = x + x*eps*nulp/2. + assert_array_almost_equal_nulp(x, y, nulp) + + # Subtraction + epsneg = np.finfo(x.dtype).epsneg + y = x - x*epsneg*nulp/2. + assert_array_almost_equal_nulp(x, y, nulp) + + def test_float64_fail(self): + nulp = 5 + x = np.linspace(-20, 20, 50, dtype=np.float64) + x = 10**x + x = np.r_[-x, x] + + eps = np.finfo(x.dtype).eps + y = x + x*eps*nulp*2. + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + x, y, nulp) + + epsneg = np.finfo(x.dtype).epsneg + y = x - x*epsneg*nulp*2. + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + x, y, nulp) + + def test_float32_pass(self): + nulp = 5 + x = np.linspace(-20, 20, 50, dtype=np.float32) + x = 10**x + x = np.r_[-x, x] + + eps = np.finfo(x.dtype).eps + y = x + x*eps*nulp/2. + assert_array_almost_equal_nulp(x, y, nulp) + + epsneg = np.finfo(x.dtype).epsneg + y = x - x*epsneg*nulp/2. + assert_array_almost_equal_nulp(x, y, nulp) + + def test_float32_fail(self): + nulp = 5 + x = np.linspace(-20, 20, 50, dtype=np.float32) + x = 10**x + x = np.r_[-x, x] + + eps = np.finfo(x.dtype).eps + y = x + x*eps*nulp*2. + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + x, y, nulp) + + epsneg = np.finfo(x.dtype).epsneg + y = x - x*epsneg*nulp*2. + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + x, y, nulp) + + def test_complex128_pass(self): + nulp = 5 + x = np.linspace(-20, 20, 50, dtype=np.float64) + x = 10**x + x = np.r_[-x, x] + xi = x + x*1j + + eps = np.finfo(x.dtype).eps + y = x + x*eps*nulp/2. + assert_array_almost_equal_nulp(xi, x + y*1j, nulp) + assert_array_almost_equal_nulp(xi, y + x*1j, nulp) + # The test condition needs to be at least a factor of sqrt(2) smaller + # because the real and imaginary parts both change + y = x + x*eps*nulp/4. + assert_array_almost_equal_nulp(xi, y + y*1j, nulp) + + epsneg = np.finfo(x.dtype).epsneg + y = x - x*epsneg*nulp/2. + assert_array_almost_equal_nulp(xi, x + y*1j, nulp) + assert_array_almost_equal_nulp(xi, y + x*1j, nulp) + y = x - x*epsneg*nulp/4. + assert_array_almost_equal_nulp(xi, y + y*1j, nulp) + + def test_complex128_fail(self): + nulp = 5 + x = np.linspace(-20, 20, 50, dtype=np.float64) + x = 10**x + x = np.r_[-x, x] + xi = x + x*1j + + eps = np.finfo(x.dtype).eps + y = x + x*eps*nulp*2. + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, x + y*1j, nulp) + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, y + x*1j, nulp) + # The test condition needs to be at least a factor of sqrt(2) smaller + # because the real and imaginary parts both change + y = x + x*eps*nulp + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, y + y*1j, nulp) + + epsneg = np.finfo(x.dtype).epsneg + y = x - x*epsneg*nulp*2. + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, x + y*1j, nulp) + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, y + x*1j, nulp) + y = x - x*epsneg*nulp + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, y + y*1j, nulp) + + def test_complex64_pass(self): + nulp = 5 + x = np.linspace(-20, 20, 50, dtype=np.float32) + x = 10**x + x = np.r_[-x, x] + xi = x + x*1j + + eps = np.finfo(x.dtype).eps + y = x + x*eps*nulp/2. + assert_array_almost_equal_nulp(xi, x + y*1j, nulp) + assert_array_almost_equal_nulp(xi, y + x*1j, nulp) + y = x + x*eps*nulp/4. + assert_array_almost_equal_nulp(xi, y + y*1j, nulp) + + epsneg = np.finfo(x.dtype).epsneg + y = x - x*epsneg*nulp/2. + assert_array_almost_equal_nulp(xi, x + y*1j, nulp) + assert_array_almost_equal_nulp(xi, y + x*1j, nulp) + y = x - x*epsneg*nulp/4. + assert_array_almost_equal_nulp(xi, y + y*1j, nulp) + + def test_complex64_fail(self): + nulp = 5 + x = np.linspace(-20, 20, 50, dtype=np.float32) + x = 10**x + x = np.r_[-x, x] + xi = x + x*1j + + eps = np.finfo(x.dtype).eps + y = x + x*eps*nulp*2. + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, x + y*1j, nulp) + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, y + x*1j, nulp) + y = x + x*eps*nulp + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, y + y*1j, nulp) + + epsneg = np.finfo(x.dtype).epsneg + y = x - x*epsneg*nulp*2. + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, x + y*1j, nulp) + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, y + x*1j, nulp) + y = x - x*epsneg*nulp + self.assertRaises(AssertionError, assert_array_almost_equal_nulp, + xi, y + y*1j, nulp) + + +class TestULP(unittest.TestCase): + + def test_equal(self): + x = np.random.randn(10) + assert_array_max_ulp(x, x, maxulp=0) + + def test_single(self): + # Generate 1 + small deviation, check that adding eps gives a few UNL + x = np.ones(10).astype(np.float32) + x += 0.01 * np.random.randn(10).astype(np.float32) + eps = np.finfo(np.float32).eps + assert_array_max_ulp(x, x+eps, maxulp=20) + + def test_double(self): + # Generate 1 + small deviation, check that adding eps gives a few UNL + x = np.ones(10).astype(np.float64) + x += 0.01 * np.random.randn(10).astype(np.float64) + eps = np.finfo(np.float64).eps + assert_array_max_ulp(x, x+eps, maxulp=200) + + def test_inf(self): + for dt in [np.float32, np.float64]: + inf = np.array([np.inf]).astype(dt) + big = np.array([np.finfo(dt).max]) + assert_array_max_ulp(inf, big, maxulp=200) + + def test_nan(self): + # Test that nan is 'far' from small, tiny, inf, max and min + for dt in [np.float32, np.float64]: + if dt == np.float32: + maxulp = 1e6 + else: + maxulp = 1e12 + inf = np.array([np.inf]).astype(dt) + nan = np.array([np.nan]).astype(dt) + big = np.array([np.finfo(dt).max]) + tiny = np.array([np.finfo(dt).tiny]) + zero = np.array([np.PZERO]).astype(dt) + nzero = np.array([np.NZERO]).astype(dt) + self.assertRaises(AssertionError, + lambda: assert_array_max_ulp(nan, inf, + maxulp=maxulp)) + self.assertRaises(AssertionError, + lambda: assert_array_max_ulp(nan, big, + maxulp=maxulp)) + self.assertRaises(AssertionError, + lambda: assert_array_max_ulp(nan, tiny, + maxulp=maxulp)) + self.assertRaises(AssertionError, + lambda: assert_array_max_ulp(nan, zero, + maxulp=maxulp)) + self.assertRaises(AssertionError, + lambda: assert_array_max_ulp(nan, nzero, + maxulp=maxulp)) + + +class TestStringEqual(unittest.TestCase): + def test_simple(self): + assert_string_equal("hello", "hello") + assert_string_equal("hello\nmultiline", "hello\nmultiline") + + try: + assert_string_equal("foo\nbar", "hello\nbar") + except AssertionError as exc: + assert_equal(str(exc), "Differences in strings:\n- foo\n+ hello") + else: + raise AssertionError("exception not raised") + + self.assertRaises(AssertionError, + lambda: assert_string_equal("foo", "hello")) + + +def assert_warn_len_equal(mod, n_in_context, py3_n_in_context=None): + mod_warns = mod.__warningregistry__ + # Python 3.4 appears to clear any pre-existing warnings of the same type, + # when raising warnings inside a catch_warnings block. So, there is a + # warning generated by the tests within the context manager, but no + # previous warnings. + if 'version' in mod_warns: + if py3_n_in_context is None: + py3_n_in_context = n_in_context + assert_equal(len(mod_warns) - 1, py3_n_in_context) + else: + assert_equal(len(mod_warns), n_in_context) + + +def _get_fresh_mod(): + # Get this module, with warning registry empty + my_mod = sys.modules[__name__] + try: + my_mod.__warningregistry__.clear() + except AttributeError: + pass + return my_mod + + +def test_clear_and_catch_warnings(): + # Initial state of module, no warnings + my_mod = _get_fresh_mod() + assert_equal(getattr(my_mod, '__warningregistry__', {}), {}) + with clear_and_catch_warnings(modules=[my_mod]): + warnings.simplefilter('ignore') + warnings.warn('Some warning') + assert_equal(my_mod.__warningregistry__, {}) + # Without specified modules, don't clear warnings during context + with clear_and_catch_warnings(): + warnings.simplefilter('ignore') + warnings.warn('Some warning') + assert_warn_len_equal(my_mod, 1) + # Confirm that specifying module keeps old warning, does not add new + with clear_and_catch_warnings(modules=[my_mod]): + warnings.simplefilter('ignore') + warnings.warn('Another warning') + assert_warn_len_equal(my_mod, 1) + # Another warning, no module spec does add to warnings dict, except on + # Python 3.4 (see comments in `assert_warn_len_equal`) + with clear_and_catch_warnings(): + warnings.simplefilter('ignore') + warnings.warn('Another warning') + assert_warn_len_equal(my_mod, 2, 1) + + +def test_suppress_warnings_module(): + # Initial state of module, no warnings + my_mod = _get_fresh_mod() + assert_equal(getattr(my_mod, '__warningregistry__', {}), {}) + + def warn_other_module(): + # Apply along axis is implemented in python; stacklevel=2 means + # we end up inside its module, not ours. + def warn(arr): + warnings.warn("Some warning 2", stacklevel=2) + return arr + np.apply_along_axis(warn, 0, [0]) + + # Test module based warning suppression: + with suppress_warnings() as sup: + sup.record(UserWarning) + # suppress warning from other module (may have .pyc ending), + # if apply_along_axis is moved, had to be changed. + sup.filter(module=np.lib.shape_base) + warnings.warn("Some warning") + warn_other_module() + # Check that the suppression did test the file correctly (this module + # got filtered) + assert_(len(sup.log) == 1) + assert_(sup.log[0].message.args[0] == "Some warning") + + assert_warn_len_equal(my_mod, 0) + sup = suppress_warnings() + # Will have to be changed if apply_along_axis is moved: + sup.filter(module=my_mod) + with sup: + warnings.warn('Some warning') + assert_warn_len_equal(my_mod, 0) + # And test repeat works: + sup.filter(module=my_mod) + with sup: + warnings.warn('Some warning') + assert_warn_len_equal(my_mod, 0) + + # Without specified modules, don't clear warnings during context + with suppress_warnings(): + warnings.simplefilter('ignore') + warnings.warn('Some warning') + assert_warn_len_equal(my_mod, 1) + + +def test_suppress_warnings_type(): + # Initial state of module, no warnings + my_mod = _get_fresh_mod() + assert_equal(getattr(my_mod, '__warningregistry__', {}), {}) + + # Test module based warning suppression: + with suppress_warnings() as sup: + sup.filter(UserWarning) + warnings.warn('Some warning') + assert_warn_len_equal(my_mod, 0) + sup = suppress_warnings() + sup.filter(UserWarning) + with sup: + warnings.warn('Some warning') + assert_warn_len_equal(my_mod, 0) + # And test repeat works: + sup.filter(module=my_mod) + with sup: + warnings.warn('Some warning') + assert_warn_len_equal(my_mod, 0) + + # Without specified modules, don't clear warnings during context + with suppress_warnings(): + warnings.simplefilter('ignore') + warnings.warn('Some warning') + assert_warn_len_equal(my_mod, 1) + + +def test_suppress_warnings_decorate_no_record(): + sup = suppress_warnings() + sup.filter(UserWarning) + + @sup + def warn(category): + warnings.warn('Some warning', category) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + warn(UserWarning) # should be supppressed + warn(RuntimeWarning) + assert_(len(w) == 1) + + +def test_suppress_warnings_record(): + sup = suppress_warnings() + log1 = sup.record() + + with sup: + log2 = sup.record(message='Some other warning 2') + sup.filter(message='Some warning') + warnings.warn('Some warning') + warnings.warn('Some other warning') + warnings.warn('Some other warning 2') + + assert_(len(sup.log) == 2) + assert_(len(log1) == 1) + assert_(len(log2) == 1) + assert_(log2[0].message.args[0] == 'Some other warning 2') + + # Do it again, with the same context to see if some warnings survived: + with sup: + log2 = sup.record(message='Some other warning 2') + sup.filter(message='Some warning') + warnings.warn('Some warning') + warnings.warn('Some other warning') + warnings.warn('Some other warning 2') + + assert_(len(sup.log) == 2) + assert_(len(log1) == 1) + assert_(len(log2) == 1) + assert_(log2[0].message.args[0] == 'Some other warning 2') + + # Test nested: + with suppress_warnings() as sup: + sup.record() + with suppress_warnings() as sup2: + sup2.record(message='Some warning') + warnings.warn('Some warning') + warnings.warn('Some other warning') + assert_(len(sup2.log) == 1) + assert_(len(sup.log) == 1) + + +def test_suppress_warnings_forwarding(): + def warn_other_module(): + # Apply along axis is implemented in python; stacklevel=2 means + # we end up inside its module, not ours. + def warn(arr): + warnings.warn("Some warning", stacklevel=2) + return arr + np.apply_along_axis(warn, 0, [0]) + + with suppress_warnings() as sup: + sup.record() + with suppress_warnings("always"): + for i in range(2): + warnings.warn("Some warning") + + assert_(len(sup.log) == 2) + + with suppress_warnings() as sup: + sup.record() + with suppress_warnings("location"): + for i in range(2): + warnings.warn("Some warning") + warnings.warn("Some warning") + + assert_(len(sup.log) == 2) + + with suppress_warnings() as sup: + sup.record() + with suppress_warnings("module"): + for i in range(2): + warnings.warn("Some warning") + warnings.warn("Some warning") + warn_other_module() + + assert_(len(sup.log) == 2) + + with suppress_warnings() as sup: + sup.record() + with suppress_warnings("once"): + for i in range(2): + warnings.warn("Some warning") + warnings.warn("Some other warning") + warn_other_module() + + assert_(len(sup.log) == 2) + + +def test_tempdir(): + with tempdir() as tdir: + fpath = os.path.join(tdir, 'tmp') + with open(fpath, 'w'): + pass + assert_(not os.path.isdir(tdir)) + + raised = False + try: + with tempdir() as tdir: + raise ValueError() + except ValueError: + raised = True + assert_(raised) + assert_(not os.path.isdir(tdir)) + + +def test_temppath(): + with temppath() as fpath: + with open(fpath, 'w') as f: + pass + assert_(not os.path.isfile(fpath)) + + raised = False + try: + with temppath() as fpath: + raise ValueError() + except ValueError: + raised = True + assert_(raised) + assert_(not os.path.isfile(fpath)) + + +class my_cacw(clear_and_catch_warnings): + + class_modules = (sys.modules[__name__],) + + +def test_clear_and_catch_warnings_inherit(): + # Test can subclass and add default modules + my_mod = _get_fresh_mod() + with my_cacw(): + warnings.simplefilter('ignore') + warnings.warn('Some warning') + assert_equal(my_mod.__warningregistry__, {}) + + +if __name__ == '__main__': + run_module_suite() diff --git a/numpy/testing/utils.py b/numpy/testing/utils.py new file mode 100644 index 0000000..7ecb68f --- /dev/null +++ b/numpy/testing/utils.py @@ -0,0 +1,20 @@ +""" +Back compatibility utils module. It will import the appropriate +set of tools + +""" +__all__ = [ + 'assert_equal', 'assert_almost_equal', 'assert_approx_equal', + 'assert_array_equal', 'assert_array_less', 'assert_string_equal', + 'assert_array_almost_equal', 'assert_raises', 'build_err_msg', + 'decorate_methods', 'jiffies', 'memusage', 'print_assert_equal', + 'raises', 'rand', 'rundocs', 'runstring', 'verbose', 'measure', + 'assert_', 'assert_array_almost_equal_nulp', 'assert_raises_regex', + 'assert_array_max_ulp', 'assert_warns', 'assert_no_warnings', + 'assert_allclose', 'IgnoreException', 'clear_and_catch_warnings', + 'SkipTest', 'KnownFailureException', 'temppath', 'tempdir', 'IS_PYPY', + 'HAS_REFCOUNT', 'suppress_warnings', 'assert_array_compare', + '_assert_valid_refcount', '_gen_alignment_data', + ] + +from .nose_tools.utils import * diff --git a/numpy/tests/__init__.py b/numpy/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/numpy/tests/__init__.py diff --git a/numpy/tests/test_ctypeslib.py b/numpy/tests/test_ctypeslib.py new file mode 100644 index 0000000..e8043d0 --- /dev/null +++ b/numpy/tests/test_ctypeslib.py @@ -0,0 +1,118 @@ +from __future__ import division, absolute_import, print_function + +import sys + +import numpy as np +from numpy.ctypeslib import ndpointer, load_library +from numpy.distutils.misc_util import get_shared_lib_extension +from numpy.testing import run_module_suite, assert_, assert_raises, dec + +try: + cdll = None + if hasattr(sys, 'gettotalrefcount'): + try: + cdll = load_library('multiarray_d', np.core.multiarray.__file__) + except OSError: + pass + if cdll is None: + cdll = load_library('multiarray', np.core.multiarray.__file__) + _HAS_CTYPE = True +except ImportError: + _HAS_CTYPE = False + +class TestLoadLibrary(object): + @dec.skipif(not _HAS_CTYPE, + "ctypes not available on this python installation") + @dec.knownfailureif(sys.platform == + 'cygwin', "This test is known to fail on cygwin") + def test_basic(self): + try: + # Should succeed + load_library('multiarray', np.core.multiarray.__file__) + except ImportError as e: + msg = ("ctypes is not available on this python: skipping the test" + " (import error was: %s)" % str(e)) + print(msg) + + @dec.skipif(not _HAS_CTYPE, + "ctypes not available on this python installation") + @dec.knownfailureif(sys.platform == + 'cygwin', "This test is known to fail on cygwin") + def test_basic2(self): + # Regression for #801: load_library with a full library name + # (including extension) does not work. + try: + try: + so = get_shared_lib_extension(is_python_ext=True) + # Should succeed + load_library('multiarray%s' % so, np.core.multiarray.__file__) + except ImportError: + print("No distutils available, skipping test.") + except ImportError as e: + msg = ("ctypes is not available on this python: skipping the test" + " (import error was: %s)" % str(e)) + print(msg) + +class TestNdpointer(object): + def test_dtype(self): + dt = np.intc + p = ndpointer(dtype=dt) + assert_(p.from_param(np.array([1], dt))) + dt = 'i4') + p = ndpointer(dtype=dt) + p.from_param(np.array([1], dt)) + assert_raises(TypeError, p.from_param, + np.array([1], dt.newbyteorder('swap'))) + dtnames = ['x', 'y'] + dtformats = [np.intc, np.float64] + dtdescr = {'names': dtnames, 'formats': dtformats} + dt = np.dtype(dtdescr) + p = ndpointer(dtype=dt) + assert_(p.from_param(np.zeros((10,), dt))) + samedt = np.dtype(dtdescr) + p = ndpointer(dtype=samedt) + assert_(p.from_param(np.zeros((10,), dt))) + dt2 = np.dtype(dtdescr, align=True) + if dt.itemsize != dt2.itemsize: + assert_raises(TypeError, p.from_param, np.zeros((10,), dt2)) + else: + assert_(p.from_param(np.zeros((10,), dt2))) + + def test_ndim(self): + p = ndpointer(ndim=0) + assert_(p.from_param(np.array(1))) + assert_raises(TypeError, p.from_param, np.array([1])) + p = ndpointer(ndim=1) + assert_raises(TypeError, p.from_param, np.array(1)) + assert_(p.from_param(np.array([1]))) + p = ndpointer(ndim=2) + assert_(p.from_param(np.array([[1]]))) + + def test_shape(self): + p = ndpointer(shape=(1, 2)) + assert_(p.from_param(np.array([[1, 2]]))) + assert_raises(TypeError, p.from_param, np.array([[1], [2]])) + p = ndpointer(shape=()) + assert_(p.from_param(np.array(1))) + + def test_flags(self): + x = np.array([[1, 2], [3, 4]], order='F') + p = ndpointer(flags='FORTRAN') + assert_(p.from_param(x)) + p = ndpointer(flags='CONTIGUOUS') + assert_raises(TypeError, p.from_param, x) + p = ndpointer(flags=x.flags.num) + assert_(p.from_param(x)) + assert_raises(TypeError, p.from_param, np.array([[1, 2], [3, 4]])) + + def test_cache(self): + a1 = ndpointer(dtype=np.float64) + a2 = ndpointer(dtype=np.float64) + assert_(a1 == a2) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/tests/test_matlib.py b/numpy/tests/test_matlib.py new file mode 100644 index 0000000..d169759 --- /dev/null +++ b/numpy/tests/test_matlib.py @@ -0,0 +1,64 @@ +from __future__ import division, absolute_import, print_function + +import numpy as np +import numpy.matlib +from numpy.testing import assert_array_equal, assert_, run_module_suite + +def test_empty(): + x = numpy.matlib.empty((2,)) + assert_(isinstance(x, np.matrix)) + assert_(x.shape, (1, 2)) + +def test_ones(): + assert_array_equal(numpy.matlib.ones((2, 3)), + np.matrix([[ 1., 1., 1.], + [ 1., 1., 1.]])) + + assert_array_equal(numpy.matlib.ones(2), np.matrix([[ 1., 1.]])) + +def test_zeros(): + assert_array_equal(numpy.matlib.zeros((2, 3)), + np.matrix([[ 0., 0., 0.], + [ 0., 0., 0.]])) + + assert_array_equal(numpy.matlib.zeros(2), np.matrix([[ 0., 0.]])) + +def test_identity(): + x = numpy.matlib.identity(2, dtype=int) + assert_array_equal(x, np.matrix([[1, 0], [0, 1]])) + +def test_eye(): + xc = numpy.matlib.eye(3, k=1, dtype=int) + assert_array_equal(xc, np.matrix([[ 0, 1, 0], + [ 0, 0, 1], + [ 0, 0, 0]])) + assert xc.flags.c_contiguous + assert not xc.flags.f_contiguous + + xf = numpy.matlib.eye(3, 4, dtype=int, order='F') + assert_array_equal(xf, np.matrix([[ 1, 0, 0, 0], + [ 0, 1, 0, 0], + [ 0, 0, 1, 0]])) + assert not xf.flags.c_contiguous + assert xf.flags.f_contiguous + +def test_rand(): + x = numpy.matlib.rand(3) + # check matrix type, array would have shape (3,) + assert_(x.ndim == 2) + +def test_randn(): + x = np.matlib.randn(3) + # check matrix type, array would have shape (3,) + assert_(x.ndim == 2) + +def test_repmat(): + a1 = np.arange(4) + x = numpy.matlib.repmat(a1, 2, 2) + y = np.array([[0, 1, 2, 3, 0, 1, 2, 3], + [0, 1, 2, 3, 0, 1, 2, 3]]) + assert_array_equal(x, y) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/tests/test_numpy_version.py b/numpy/tests/test_numpy_version.py new file mode 100644 index 0000000..b61d0d5 --- /dev/null +++ b/numpy/tests/test_numpy_version.py @@ -0,0 +1,23 @@ +from __future__ import division, absolute_import, print_function + +import re + +import numpy as np +from numpy.testing import assert_, run_module_suite + + +def test_valid_numpy_version(): + # Verify that the numpy version is a valid one (no .post suffix or other + # nonsense). See gh-6431 for an issue caused by an invalid version. + version_pattern = r"^[0-9]+\.[0-9]+\.[0-9]+(|a[0-9]|b[0-9]|rc[0-9])" + dev_suffix = r"(\.dev0\+([0-9a-f]{7}|Unknown))" + if np.version.release: + res = re.match(version_pattern, np.__version__) + else: + res = re.match(version_pattern + dev_suffix, np.__version__) + + assert_(res is not None, np.__version__) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/tests/test_reloading.py b/numpy/tests/test_reloading.py new file mode 100644 index 0000000..ca651c8 --- /dev/null +++ b/numpy/tests/test_reloading.py @@ -0,0 +1,34 @@ +from __future__ import division, absolute_import, print_function + +import sys + +from numpy.testing import assert_raises, assert_, run_module_suite + +if sys.version_info[:2] >= (3, 4): + from importlib import reload +else: + from imp import reload + +def test_numpy_reloading(): + # gh-7844. Also check that relevant globals retain their identity. + import numpy as np + import numpy._globals + + _NoValue = np._NoValue + VisibleDeprecationWarning = np.VisibleDeprecationWarning + ModuleDeprecationWarning = np.ModuleDeprecationWarning + + reload(np) + assert_(_NoValue is np._NoValue) + assert_(ModuleDeprecationWarning is np.ModuleDeprecationWarning) + assert_(VisibleDeprecationWarning is np.VisibleDeprecationWarning) + + assert_raises(RuntimeError, reload, numpy._globals) + reload(np) + assert_(_NoValue is np._NoValue) + assert_(ModuleDeprecationWarning is np.ModuleDeprecationWarning) + assert_(VisibleDeprecationWarning is np.VisibleDeprecationWarning) + + +if __name__ == "__main__": + run_module_suite() diff --git a/numpy/tests/test_scripts.py b/numpy/tests/test_scripts.py new file mode 100644 index 0000000..675fe65 --- /dev/null +++ b/numpy/tests/test_scripts.py @@ -0,0 +1,92 @@ +""" Test scripts + +Test that we can run executable scripts that have been installed with numpy. +""" +from __future__ import division, print_function, absolute_import + +import os +from os.path import join as pathjoin, isfile, dirname, basename +import sys +from subprocess import Popen, PIPE +import numpy as np +from numpy.compat.py3k import basestring +from nose.tools import assert_equal +from numpy.testing import assert_, dec + +is_inplace = isfile(pathjoin(dirname(np.__file__), '..', 'setup.py')) + + +def run_command(cmd, check_code=True): + """ Run command sequence `cmd` returning exit code, stdout, stderr + + Parameters + ---------- + cmd : str or sequence + string with command name or sequence of strings defining command + check_code : {True, False}, optional + If True, raise error for non-zero return code + + Returns + ------- + returncode : int + return code from execution of `cmd` + stdout : bytes (python 3) or str (python 2) + stdout from `cmd` + stderr : bytes (python 3) or str (python 2) + stderr from `cmd` + + Raises + ------ + RuntimeError + If `check_code` is True, and return code !=0 + """ + cmd = [cmd] if isinstance(cmd, basestring) else list(cmd) + if os.name == 'nt': + # Quote any arguments with spaces. The quotes delimit the arguments + # on Windows, and the arguments might be file paths with spaces. + # On Unix the list elements are each separate arguments. + cmd = ['"{0}"'.format(c) if ' ' in c else c for c in cmd] + proc = Popen(cmd, stdout=PIPE, stderr=PIPE) + stdout, stderr = proc.communicate() + if proc.poll() is None: + proc.terminate() + if check_code and proc.returncode != 0: + raise RuntimeError('\n'.join( + ['Command "{0}" failed with', + 'stdout', '------', '{1}', '', + 'stderr', '------', '{2}']).format(cmd, stdout, stderr)) + return proc.returncode, stdout, stderr + + +@dec.skipif(is_inplace) +def test_f2py(): + # test that we can run f2py script + if sys.platform == 'win32': + exe_dir = dirname(sys.executable) + + if exe_dir.endswith('Scripts'): # virtualenv + f2py_cmd = r"%s\f2py.py" % exe_dir + else: + f2py_cmd = r"%s\Scripts\f2py.py" % exe_dir + + code, stdout, stderr = run_command([sys.executable, f2py_cmd, '-v']) + success = stdout.strip() == b'2' + assert_(success, "Warning: f2py not found in path") + else: + version = sys.version_info + major = str(version.major) + minor = str(version.minor) + + f2py_cmds = ('f2py', 'f2py' + major, 'f2py' + major + '.' + minor) + success = False + + for f2py_cmd in f2py_cmds: + try: + code, stdout, stderr = run_command([f2py_cmd, '-v']) + assert_equal(stdout.strip(), b'2') + success = True + break + except Exception: + pass + msg = "Warning: neither %s nor %s nor %s found in path" % f2py_cmds + assert_(success, msg) diff --git a/numpy/tests/test_warnings.py b/numpy/tests/test_warnings.py new file mode 100644 index 0000000..7f22794 --- /dev/null +++ b/numpy/tests/test_warnings.py @@ -0,0 +1,84 @@ +""" +Tests which scan for certain occurrences in the code, they may not find +all of these occurrences but should catch almost all. +""" + + +from __future__ import division, absolute_import, print_function + + +import sys +if sys.version_info >= (3, 4): + from pathlib import Path + import ast + import tokenize + import numpy + from numpy.testing import run_module_suite, dec + + class ParseCall(ast.NodeVisitor): + def __init__(self): + self.ls = [] + + def visit_Attribute(self, node): + ast.NodeVisitor.generic_visit(self, node) + self.ls.append(node.attr) + + def visit_Name(self, node): + self.ls.append(node.id) + + + class FindFuncs(ast.NodeVisitor): + def __init__(self, filename): + super().__init__() + self.__filename = filename + + def visit_Call(self, node): + p = ParseCall() + p.visit(node.func) + ast.NodeVisitor.generic_visit(self, node) + + if p.ls[-1] == 'simplefilter' or p.ls[-1] == 'filterwarnings': + if node.args[0].s == "ignore": + raise AssertionError( + "ignore filter should not be used; found in " + "{} on line {}".format(self.__filename, node.lineno)) + + if p.ls[-1] == 'warn' and ( + len(p.ls) == 1 or p.ls[-2] == 'warnings'): + + if "testing/tests/test_warnings.py" is self.__filename: + # This file + return + + # See if stacklevel exists: + if len(node.args) == 3: + return + args = {kw.arg for kw in node.keywords} + if "stacklevel" in args: + return + raise AssertionError( + "warnings should have an appropriate stacklevel; found in " + "{} on line {}".format(self.__filename, node.lineno)) + + + @dec.slow + def test_warning_calls(): + # combined "ignore" and stacklevel error + base = Path(numpy.__file__).parent + + for path in base.rglob("*.py"): + if base / "testing" in path.parents: + continue + if path == base / "__init__.py": + continue + if path == base / "random" / "__init__.py": + continue + # use tokenize to auto-detect encoding on systems where no + # default encoding is defined (e.g. LANG='C') + with tokenize.open(str(path)) as file: + tree = ast.parse(file.read()) + FindFuncs(path).visit(tree) + + + if __name__ == "__main__": + run_module_suite() diff --git a/numpy/version.py b/numpy/version.py new file mode 100644 index 0000000..e542250 --- /dev/null +++ b/numpy/version.py @@ -0,0 +1,12 @@ + +# THIS FILE IS GENERATED FROM NUMPY SETUP.PY +# +# To compare versions robustly, use `numpy.lib.NumpyVersion` +short_version = '1.14.3' +version = '1.14.3' +full_version = '1.14.3' +git_revision = '73299826729be58cec179b52c656adfcaefada93' +release = True + +if not release: + version = full_version diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..6df3dbe --- /dev/null +++ b/setup.py @@ -0,0 +1,399 @@ +#!/usr/bin/env python +"""NumPy: array processing for numbers, strings, records, and objects. + +NumPy is a general-purpose array-processing package designed to +efficiently manipulate large multi-dimensional arrays of arbitrary +records without sacrificing too much speed for small multi-dimensional +arrays. NumPy is built on the Numeric code base and adds features +introduced by numarray as well as an extended C-API and the ability to +create arrays of arbitrary type which also makes NumPy suitable for +interfacing with general-purpose data-base applications. + +There are also basic facilities for discrete fourier transform, +basic linear algebra and random number generation. + +All numpy wheels distributed from pypi are BSD licensed. + +Windows wheels are linked against the ATLAS BLAS / LAPACK library, restricted +to SSE2 instructions, so may not give optimal linear algebra performance for +your machine. See http://docs.scipy.org/doc/numpy/user/install.html for +alternatives. + +""" +from __future__ import division, print_function + +DOCLINES = (__doc__ or '').split("\n") + +import os +import sys +import subprocess +import textwrap + + +if sys.version_info[:2] < (2, 7) or (3, 0) <= sys.version_info[:2] < (3, 4): + raise RuntimeError("Python version 2.7 or >= 3.4 required.") + +if sys.version_info[0] >= 3: + import builtins +else: + import __builtin__ as builtins + + +CLASSIFIERS = """\ +Development Status :: 5 - Production/Stable +Intended Audience :: Science/Research +Intended Audience :: Developers +License :: OSI Approved +Programming Language :: C +Programming Language :: Python +Programming Language :: Python :: 2 +Programming Language :: Python :: 2.7 +Programming Language :: Python :: 3 +Programming Language :: Python :: 3.4 +Programming Language :: Python :: 3.5 +Programming Language :: Python :: 3.6 +Programming Language :: Python :: Implementation :: CPython +Topic :: Software Development +Topic :: Scientific/Engineering +Operating System :: Microsoft :: Windows +Operating System :: POSIX +Operating System :: Unix +Operating System :: MacOS +""" + +MAJOR = 1 +MINOR = 14 +MICRO = 3 +ISRELEASED = True +VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) + + +# Return the git revision as a string +def git_version(): + def _minimal_ext_cmd(cmd): + # construct minimal environment + env = {} + for k in ['SYSTEMROOT', 'PATH', 'HOME']: + v = os.environ.get(k) + if v is not None: + env[k] = v + # LANGUAGE is used on win32 + env['LANGUAGE'] = 'C' + env['LANG'] = 'C' + env['LC_ALL'] = 'C' + out = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0] + return out + + try: + out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD']) + GIT_REVISION = out.strip().decode('ascii') + except OSError: + GIT_REVISION = "Unknown" + + return GIT_REVISION + +# BEFORE importing setuptools, remove MANIFEST. Otherwise it may not be +# properly updated when the contents of directories change (true for distutils, +# not sure about setuptools). +if os.path.exists('MANIFEST'): + os.remove('MANIFEST') + +# This is a bit hackish: we are setting a global variable so that the main +# numpy __init__ can detect if it is being loaded by the setup routine, to +# avoid attempting to load components that aren't built yet. While ugly, it's +# a lot more robust than what was previously being used. +builtins.__NUMPY_SETUP__ = True + + +def get_version_info(): + # Adding the git rev number needs to be done inside write_version_py(), + # otherwise the import of numpy.version messes up the build under Python 3. + FULLVERSION = VERSION + if os.path.exists('.git'): + GIT_REVISION = git_version() + elif os.path.exists('numpy/version.py'): + # must be a source distribution, use existing version file + try: + from numpy.version import git_revision as GIT_REVISION + except ImportError: + raise ImportError("Unable to import git_revision. Try removing " \ + "numpy/version.py and the build directory " \ + "before building.") + else: + GIT_REVISION = "Unknown" + + if not ISRELEASED: + FULLVERSION += '.dev0+' + GIT_REVISION[:7] + + return FULLVERSION, GIT_REVISION + + +def write_version_py(filename='numpy/version.py'): + cnt = """ +# THIS FILE IS GENERATED FROM NUMPY SETUP.PY +# +# To compare versions robustly, use `numpy.lib.NumpyVersion` +short_version = '%(version)s' +version = '%(version)s' +full_version = '%(full_version)s' +git_revision = '%(git_revision)s' +release = %(isrelease)s + +if not release: + version = full_version +""" + FULLVERSION, GIT_REVISION = get_version_info() + + a = open(filename, 'w') + try: + a.write(cnt % {'version': VERSION, + 'full_version': FULLVERSION, + 'git_revision': GIT_REVISION, + 'isrelease': str(ISRELEASED)}) + finally: + a.close() + + +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + + config = Configuration(None, parent_package, top_path) + config.set_options(ignore_setup_xxx_py=True, + assume_default_configuration=True, + delegate_options_to_subpackages=True, + quiet=True) + + config.add_subpackage('numpy') + config.add_data_files(('numpy', 'LICENSE.txt')) + + config.get_version('numpy/version.py') # sets config.version + + return config + + +def check_submodules(): + """ verify that the submodules are checked out and clean + use `git submodule update --init`; on failure + """ + if not os.path.exists('.git'): + return + with open('.gitmodules') as f: + for l in f: + if 'path' in l: + p = l.split('=')[-1].strip() + if not os.path.exists(p): + raise ValueError('Submodule %s missing' % p) + + + proc = subprocess.Popen(['git', 'submodule', 'status'], + stdout=subprocess.PIPE) + status, _ = proc.communicate() + status = status.decode("ascii", "replace") + for line in status.splitlines(): + if line.startswith('-') or line.startswith('+'): + raise ValueError('Submodule not clean: %s' % line) + + +from distutils.command.sdist import sdist +class sdist_checked(sdist): + """ check submodules on sdist to prevent incomplete tarballs """ + def run(self): + check_submodules() + sdist.run(self) + + +def generate_cython(): + cwd = os.path.abspath(os.path.dirname(__file__)) + print("Cythonizing sources") + p = subprocess.call([sys.executable, + os.path.join(cwd, 'tools', 'cythonize.py'), + 'numpy/random'], + cwd=cwd) + if p != 0: + raise RuntimeError("Running cythonize failed!") + + +def parse_setuppy_commands(): + """Check the commands and respond appropriately. Disable broken commands. + + Return a boolean value for whether or not to run the build or not (avoid + parsing Cython and template files if False). + """ + if len(sys.argv) < 2: + # User forgot to give an argument probably, let setuptools handle that. + return True + + info_commands = ['--help-commands', '--name', '--version', '-V', + '--fullname', '--author', '--author-email', + '--maintainer', '--maintainer-email', '--contact', + '--contact-email', '--url', '--license', '--description', + '--long-description', '--platforms', '--classifiers', + '--keywords', '--provides', '--requires', '--obsoletes'] + # Add commands that do more than print info, but also don't need Cython and + # template parsing. + info_commands.extend(['egg_info', 'install_egg_info', 'rotate']) + + for command in info_commands: + if command in sys.argv[1:]: + return False + + # Note that 'alias', 'saveopts' and 'setopt' commands also seem to work + # fine as they are, but are usually used together with one of the commands + # below and not standalone. Hence they're not added to good_commands. + good_commands = ('develop', 'sdist', 'build', 'build_ext', 'build_py', + 'build_clib', 'build_scripts', 'bdist_wheel', 'bdist_rpm', + 'bdist_wininst', 'bdist_msi', 'bdist_mpkg') + + for command in good_commands: + if command in sys.argv[1:]: + return True + + # The following commands are supported, but we need to show more + # useful messages to the user + if 'install' in sys.argv[1:]: + print(textwrap.dedent(""" + Note: if you need reliable uninstall behavior, then install + with pip instead of using `setup.py install`: + + - `pip install .` (from a git repo or downloaded source + release) + - `pip install numpy` (last NumPy release on PyPi) + + """)) + return True + + if '--help' in sys.argv[1:] or '-h' in sys.argv[1]: + print(textwrap.dedent(""" + NumPy-specific help + ------------------- + + To install NumPy from here with reliable uninstall, we recommend + that you use `pip install .`. To install the latest NumPy release + from PyPi, use `pip install numpy`. + + For help with build/installation issues, please ask on the + numpy-discussion mailing list. If you are sure that you have run + into a bug, please report it at https://github.com/numpy/numpy/issues. + + Setuptools commands help + ------------------------ + """)) + return False + + # The following commands aren't supported. They can only be executed when + # the user explicitly adds a --force command-line argument. + bad_commands = dict( + test=""" + `setup.py test` is not supported. Use one of the following + instead: + + - `python runtests.py` (to build and test) + - `python runtests.py --no-build` (to test installed numpy) + - `>>> numpy.test()` (run tests for installed numpy + from within an interpreter) + """, + upload=""" + `setup.py upload` is not supported, because it's insecure. + Instead, build what you want to upload and upload those files + with `twine upload -s ` instead. + """, + upload_docs="`setup.py upload_docs` is not supported", + easy_install="`setup.py easy_install` is not supported", + clean=""" + `setup.py clean` is not supported, use one of the following instead: + + - `git clean -xdf` (cleans all files) + - `git clean -Xdf` (cleans all versioned files, doesn't touch + files that aren't checked into the git repo) + """, + check="`setup.py check` is not supported", + register="`setup.py register` is not supported", + bdist_dumb="`setup.py bdist_dumb` is not supported", + bdist="`setup.py bdist` is not supported", + build_sphinx=""" + `setup.py build_sphinx` is not supported, use the + Makefile under doc/""", + flake8="`setup.py flake8` is not supported, use flake8 standalone", + ) + bad_commands['nosetests'] = bad_commands['test'] + for command in ('upload_docs', 'easy_install', 'bdist', 'bdist_dumb', + 'register', 'check', 'install_data', 'install_headers', + 'install_lib', 'install_scripts', ): + bad_commands[command] = "`setup.py %s` is not supported" % command + + for command in bad_commands.keys(): + if command in sys.argv[1:]: + print(textwrap.dedent(bad_commands[command]) + + "\nAdd `--force` to your command to use it anyway if you " + "must (unsupported).\n") + sys.exit(1) + + # If we got here, we didn't detect what setup.py command was given + import warnings + warnings.warn("Unrecognized setuptools command, proceeding with " + "generating Cython sources and expanding templates", stacklevel=2) + return True + + +def setup_package(): + src_path = os.path.dirname(os.path.abspath(sys.argv[0])) + old_path = os.getcwd() + os.chdir(src_path) + sys.path.insert(0, src_path) + + # Rewrite the version file everytime + write_version_py() + + metadata = dict( + name = 'numpy', + maintainer = "NumPy Developers", + maintainer_email = "numpy-discussion@python.org", + description = DOCLINES[0], + long_description = "\n".join(DOCLINES[2:]), + url = "http://www.numpy.org", + author = "Travis E. Oliphant et al.", + download_url = "https://pypi.python.org/pypi/numpy", + license = 'BSD', + classifiers=[_f for _f in CLASSIFIERS.split('\n') if _f], + platforms = ["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"], + test_suite='nose.collector', + cmdclass={"sdist": sdist_checked}, + python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', + ) + + if "--force" in sys.argv: + run_build = True + sys.argv.remove('--force') + else: + # Raise errors for unsupported commands, improve help output, etc. + run_build = parse_setuppy_commands() + + from setuptools import setup + if run_build: + from numpy.distutils.core import setup + cwd = os.path.abspath(os.path.dirname(__file__)) + if not os.path.exists(os.path.join(cwd, 'PKG-INFO')): + # Generate Cython sources, unless building from source release + generate_cython() + + metadata['configuration'] = configuration + else: + # Version number is added to metadata inside configuration() if build + # is run. + metadata['version'] = get_version_info()[0] + + try: + setup(**metadata) + finally: + del sys.path[0] + os.chdir(old_path) + return + + +if __name__ == '__main__': + setup_package() + # This may avoid problems where numpy is installed via ``*_requires`` by + # setuptools, the global namespace isn't reset properly, and then numpy is + # imported later (which will then fail to load numpy extension modules). + # See gh-7956 for details + del builtins.__NUMPY_SETUP__ diff --git a/site.cfg.example b/site.cfg.example new file mode 100644 index 0000000..645b485 --- /dev/null +++ b/site.cfg.example @@ -0,0 +1,218 @@ +# This file provides configuration information about non-Python dependencies for +# numpy.distutils-using packages. Create a file like this called "site.cfg" next +# to your package's setup.py file and fill in the appropriate sections. Not all +# packages will use all sections so you should leave out sections that your +# package does not use. + +# To assist automatic installation like easy_install, the user's home directory +# will also be checked for the file ~/.numpy-site.cfg . + +# The format of the file is that of the standard library's ConfigParser module. +# No interpolation is allowed, RawConfigParser class being used to load it. +# +# http://docs.python.org/3/library/configparser.html +# +# Each section defines settings that apply to one particular dependency. Some of +# the settings are general and apply to nearly any section and are defined here. +# Settings specific to a particular section will be defined near their section. +# +# libraries +# Comma-separated list of library names to add to compile the extension +# with. Note that these should be just the names, not the filenames. For +# example, the file "libfoo.so" would become simply "foo". +# libraries = lapack,f77blas,cblas,atlas +# +# library_dirs +# List of directories to add to the library search path when compiling +# extensions with this dependency. Use the character given by os.pathsep +# to separate the items in the list. Note that this character is known to +# vary on some unix-like systems; if a colon does not work, try a comma. +# This also applies to include_dirs and src_dirs (see below). +# On UN*X-type systems (OS X, most BSD and Linux systems): +# library_dirs = /usr/lib:/usr/local/lib +# On Windows: +# library_dirs = c:\mingw\lib,c:\atlas\lib +# On some BSD and Linux systems: +# library_dirs = /usr/lib,/usr/local/lib +# +# include_dirs +# List of directories to add to the header file search path. +# include_dirs = /usr/include:/usr/local/include +# +# src_dirs +# List of directories that contain extracted source code for the +# dependency. For some dependencies, numpy.distutils will be able to build +# them from source if binaries cannot be found. The FORTRAN BLAS and +# LAPACK libraries are one example. However, most dependencies are more +# complicated and require actual installation that you need to do +# yourself. +# src_dirs = /home/rkern/src/BLAS_SRC:/home/rkern/src/LAPACK_SRC +# +# search_static_first +# Boolean (one of (0, false, no, off) for False or (1, true, yes, on) for +# True) to tell numpy.distutils to prefer static libraries (.a) over +# shared libraries (.so). It is turned off by default. +# search_static_first = false +# +# runtime_library_dirs/rpath +# List of directories that contains the libraries that should be +# used at runtime, thereby disregarding the LD_LIBRARY_PATH variable. +# See 'library_dirs' for formatting on different platforms. +# runtime_library_dirs = /opt/blas/lib:/opt/lapack/lib +# or equivalently +# rpath = /opt/blas/lib:/opt/lapack/lib +# +# extra_compile_args +# Add additional arguments to the compilation of sources. +# Simple variable with no parsing done. +# Provide a single line with all complete flags. +# extra_compile_args = -g -ftree-vectorize +# +# extra_link_args +# Add additional arguments when libraries/executables +# are linked. +# Simple variable with no parsing done. +# Provide a single line with all complete flags. +# extra_link_args = -lgfortran +# + +# Defaults +# ======== +# The settings given here will apply to all other sections if not overridden. +# This is a good place to add general library and include directories like +# /usr/local/{lib,include} +# +#[ALL] +#library_dirs = /usr/local/lib +#include_dirs = /usr/local/include +# + +# Atlas +# ----- +# Atlas is an open source optimized implementation of the BLAS and Lapack +# routines. NumPy will try to build against Atlas by default when available in +# the system library dirs. To build numpy against a custom installation of +# Atlas you can add an explicit section such as the following. Here we assume +# that Atlas was configured with ``prefix=/opt/atlas``. +# +# [atlas] +# library_dirs = /opt/atlas/lib +# include_dirs = /opt/atlas/include + +# OpenBLAS +# -------- +# OpenBLAS is another open source optimized implementation of BLAS and Lapack +# and can be seen as an alternative to Atlas. To build numpy against OpenBLAS +# instead of Atlas, use this section instead of the above, adjusting as needed +# for your configuration (in the following example we installed OpenBLAS with +# ``make install PREFIX=/opt/OpenBLAS``. +# OpenBLAS is generically installed as a shared library, to force the OpenBLAS +# library linked to also be used at runtime you can utilize the +# runtime_library_dirs variable. +# +# **Warning**: OpenBLAS, by default, is built in multithreaded mode. Due to the +# way Python's multiprocessing is implemented, a multithreaded OpenBLAS can +# cause programs using both to hang as soon as a worker process is forked on +# POSIX systems (Linux, Mac). +# This is fixed in Openblas 0.2.9 for the pthread build, the OpenMP build using +# GNU openmp is as of gcc-4.9 not fixed yet. +# Python 3.4 will introduce a new feature in multiprocessing, called the +# "forkserver", which solves this problem. For older versions, make sure +# OpenBLAS is built using pthreads or use Python threads instead of +# multiprocessing. +# (This problem does not exist with multithreaded ATLAS.) +# +# http://docs.python.org/3.4/library/multiprocessing.html#contexts-and-start-methods +# https://github.com/xianyi/OpenBLAS/issues/294 +# +# [openblas] +# libraries = openblas +# library_dirs = /opt/OpenBLAS/lib +# include_dirs = /opt/OpenBLAS/include +# runtime_library_dirs = /opt/OpenBLAS/lib + +# BLIS +# ---- +# BLIS (https://github.com/flame/blis) also provides a BLAS interface. It's a +# relatively new library, its performance in some cases seems to match that of +# MKL and OpenBLAS, but it hasn't been benchmarked with NumPy or Scipy yet. +# +# Notes on compiling BLIS itself: +# - the CBLAS interface (needed by NumPy) isn't built by default; define +# BLIS_ENABLE_CBLAS to build it. +# - ``./configure auto`` doesn't support 32-bit builds, see gh-7294 for +# details. +# Notes on compiling NumPy against BLIS: +# - ``include_dirs`` below should be the directory where the BLIS cblas.h +# header is installed. +# +# [blis] +# libraries = blis +# library_dirs = /home/username/blis/lib +# include_dirs = /home/username/blis/include/blis +# runtime_library_dirs = /home/username/blis/lib + +# MKL +#---- +# Intel MKL is Intel's very optimized yet proprietary implementation of BLAS and +# Lapack. Find the latest info on building numpy with Intel MKL in this article: +# https://software.intel.com/en-us/articles/numpyscipy-with-intel-mkl +# Assuming you installed the mkl in /opt/intel/compilers_and_libraries_2018/linux/mkl, +# for 64 bits code at Linux: +# [mkl] +# library_dirs = /opt/intel/compilers_and_libraries_2018/linux/mkl/lib/intel64 +# include_dirs = /opt/intel/compilers_and_libraries_2018/linux/mkl/include +# mkl_libs = mkl_rt +# lapack_libs =  +# +# For 32 bit code at Linux: +# [mkl] +# library_dirs = /opt/intel/compilers_and_libraries_2018/linux/mkl/lib/ia32 +# include_dirs = /opt/intel/compilers_and_libraries_2018/linux/mkl/include +# mkl_libs = mkl_rt +# lapack_libs =  +# +# On win-64, the following options compiles numpy with the MKL library +# dynamically linked. +# [mkl] +# include_dirs = C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2018\windows\mkl\include +# library_dirs = C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2018\windows\mkl\lib\intel64 +# mkl_libs = mkl_rt +# lapack_libs = + +# UMFPACK +# ------- +# The UMFPACK library is used in scikits.umfpack to factor large sparse matrices. +# It, in turn, depends on the AMD library for reordering the matrices for +# better performance. Note that the AMD library has nothing to do with AMD +# (Advanced Micro Devices), the CPU company. +# +# UMFPACK is not used by numpy. +# +# http://www.cise.ufl.edu/research/sparse/umfpack/ +# http://www.cise.ufl.edu/research/sparse/amd/ +# http://scikits.appspot.com/umfpack +# +#[amd] +#amd_libs = amd +# +#[umfpack] +#umfpack_libs = umfpack + +# FFT libraries +# ------------- +# There are two FFT libraries that we can configure here: FFTW (2 and 3) and djbfft. +# Note that these libraries are not used by for numpy or scipy. +# +# http://fftw.org/ +# http://cr.yp.to/djbfft.html +# +# Given only this section, numpy.distutils will try to figure out which version +# of FFTW you are using. +#[fftw] +#libraries = fftw3 +# +# For djbfft, numpy.distutils will look for either djbfft.a or libdjbfft.a . +#[djbfft] +#include_dirs = /usr/local/djbfft/include +#library_dirs = /usr/local/djbfft/lib diff --git a/tools/swig/Makefile b/tools/swig/Makefile new file mode 100644 index 0000000..0478ac7 --- /dev/null +++ b/tools/swig/Makefile @@ -0,0 +1,31 @@ +# List all of the subdirectories here for recursive make +SUBDIRS = test + +# Default target +.PHONY : default +default: + @echo "There is no default make target for this Makefile" + @echo "Valid make targets are:" + @echo " test - Compile and run tests of numpy.i" + @echo " doc - Generate numpy.i documentation" + @echo " all - make test + doc" + @echo " clean - Remove generated files recursively" + +# Target all +.PHONY : all +all: $(SUBDIRS) + +# Target test +.PHONY : test +test: + cd $@ && make $@ + +# Target clean +.PHONY : clean +clean: + @for dir in $(SUBDIRS); do \ + echo ; \ + echo Running \'make clean\' in $$dir; \ + cd $$dir && make clean && cd ..; \ + done; \ + echo diff --git a/tools/swig/README b/tools/swig/README new file mode 100644 index 0000000..7fa0599 --- /dev/null +++ b/tools/swig/README @@ -0,0 +1,145 @@ +Notes for the numpy/tools/swig directory +======================================== + +This set of files is for developing and testing file numpy.i, which is +intended to be a set of typemaps for helping SWIG interface between C +and C++ code that uses C arrays and the python module NumPy. It is +ultimately hoped that numpy.i will be included as part of the SWIG +distribution. + +Documentation +------------- +Documentation for how to use numpy.i, as well as for the testing +system used here, can be found in the NumPy reference guide. + +Testing +------- +The tests are a good example of what we are trying to do with numpy.i. +The files related to testing are are in the test subdirectory:: + + Vector.h + Vector.cxx + Vector.i + testVector.py + + Matrix.h + Matrix.cxx + Matrix.i + testMatrix.py + + Tensor.h + Tensor.cxx + Tensor.i + testTensor.py + + SuperTensor.h + SuperTensor.cxx + SuperTensor.i + testSuperTensor.py + + Flat.h + Flat.cxx + Flat.i + testFlat.py + +The header files contain prototypes for functions that illustrate the +wrapping issues we wish to address. Right now, this consists of +functions with argument signatures of the following forms. Vector.h:: + + (type IN_ARRAY1[ANY]) + (type* IN_ARRAY1, int DIM1) + (int DIM1, type* IN_ARRAY1) + + (type INPLACE_ARRAY1[ANY]) + (type* INPLACE_ARRAY1, int DIM1) + (int DIM1, type* INPLACE_ARRAY1) + + (type ARGOUT_ARRAY1[ANY]) + (type* ARGOUT_ARRAY1, int DIM1) + (int DIM1, type* ARGOUT_ARRAY1) + +Matrix.h:: + + (type IN_ARRAY2[ANY][ANY]) + (type* IN_ARRAY2, int DIM1, int DIM2) + (int DIM1, int DIM2, type* IN_ARRAY2) + + (type INPLACE_ARRAY2[ANY][ANY]) + (type* INPLACE_ARRAY2, int DIM1, int DIM2) + (int DIM1, int DIM2, type* INPLACE_ARRAY2) + + (type ARGOUT_ARRAY2[ANY][ANY]) + +Tensor.h:: + + (type IN_ARRAY3[ANY][ANY][ANY]) + (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) + (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) + + (type INPLACE_ARRAY3[ANY][ANY][ANY]) + (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) + (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) + + (type ARGOUT_ARRAY3[ANY][ANY][ANY]) + +SuperTensor.h:: + + (type IN_ARRAY4[ANY][ANY][ANY][ANY]) + (type* IN_ARRAY4, int DIM1, int DIM2, int DIM3, int DIM4) + (int DIM1, int DIM2, int DIM3, int DIM4, type* IN_ARRAY4) + + (type INPLACE_ARRAY4[ANY][ANY][ANY][ANY]) + (type* INPLACE_ARRAY4, int DIM1, int DIM2, int DIM3, int DIM4) + (int DIM1, int DIM2, int DIM3, int DIM4, type* INPLACE_ARRAY4) + + (type ARGOUT_ARRAY4[ANY][ANY][ANY][ANY]) + +Flat.h:: + (type* INPLACE_ARRAY_FLAT, int DIM_FLAT) + +These function signatures take a pointer to an array of type "type", +whose length is specified by the integer(s) DIM1 (and DIM2, and DIM3, +and DIM4, or DIM_FLAT). + +The objective for the IN_ARRAY signatures is for SWIG to generate +python wrappers that take a container that constitutes a valid +argument to the numpy array constructor, and can be used to build an +array of type "type". Currently, types "signed char", "unsigned +char", "short", "unsigned short", "int", "unsigned int", "long", +"unsigned long", "long long", "unsigned long long", "float", and +"double" are supported and tested. + +The objective for the INPLACE_ARRAY signatures is for SWIG to generate +python wrappers that accept a numpy array of any of the above-listed +types. + +The source files Vector.cxx, Matrix.cxx, Tensor.cxx, SuperTensor.cxx +and Flat.cxx contain the actual implementations of the functions +described in Vector.h, Matrix.h Tensor.h, SuperTensor.h and Flat.h. +The python scripts testVector.py, testMatrix.py testTensor.py, +testSuperTensor.py and testFlat.py test the resulting python wrappers +using the unittest module. + +The SWIG interface files Vector.i, Matrix.i, Tensor.i, SuperTensor.i +and Flat.i are used to generate the wrapper code. The +SWIG_FILE_WITH_INIT macro allows numpy.i to be used with multiple +python modules. If it is specified, then the %init block found in +Vector.i, Matrix.i Tensor.i, SuperTensor.i and Flat.i are required. +The other things done in Vector.i, Matrix.i, Tensor.i, SuperTensor.i +and Flat.i are the inclusion of the appropriate header file and +numpy.i file, and the "%apply" directives to force the functions to +use the typemaps. + +The setup.py script is a standard python distutils script. It defines +_Vector, _Matrix, _Tensor, _SuperTensor, _Flat extension modules and Vector, +Matrix, Tensor, SuperTensor and Flat python modules. The Makefile +automates everything, setting up the dependencies, calling swig to +generate the wrappers, and calling setup.py to compile the wrapper +code and generate the shared objects. Targets "all" (default), "test", +"doc" and "clean" are supported. The "doc" target creates HTML +documentation (with make target "html"), and PDF documentation +(with make targets "tex" and "pdf"). + +To build and run the test code, simply execute from the shell:: + + $ make test diff --git a/tools/swig/numpy.i b/tools/swig/numpy.i new file mode 100644 index 0000000..5abeab0 --- /dev/null +++ b/tools/swig/numpy.i @@ -0,0 +1,3174 @@ +/* -*- C -*- (not really, but good for syntax highlighting) */ + +/* + * Copyright (c) 2005-2015, NumPy Developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * * Neither the name of the NumPy Developers nor the names of any + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef SWIGPYTHON + +%{ +#ifndef SWIG_FILE_WITH_INIT +#define NO_IMPORT_ARRAY +#endif +#include "stdio.h" +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include +%} + +/**********************************************************************/ + +%fragment("NumPy_Backward_Compatibility", "header") +{ +%#if NPY_API_VERSION < 0x00000007 +%#define NPY_ARRAY_DEFAULT NPY_DEFAULT +%#define NPY_ARRAY_FARRAY NPY_FARRAY +%#define NPY_FORTRANORDER NPY_FORTRAN +%#endif +} + +/**********************************************************************/ + +/* The following code originally appeared in + * enthought/kiva/agg/src/numeric.i written by Eric Jones. It was + * translated from C++ to C by John Hunter. Bill Spotz has modified + * it to fix some minor bugs, upgrade from Numeric to numpy (all + * versions), add some comments and functionality, and convert from + * direct code insertion to SWIG fragments. + */ + +%fragment("NumPy_Macros", "header") +{ +/* Macros to extract array attributes. + */ +%#if NPY_API_VERSION < 0x00000007 +%#define is_array(a) ((a) && PyArray_Check((PyArrayObject*)a)) +%#define array_type(a) (int)(PyArray_TYPE((PyArrayObject*)a)) +%#define array_numdims(a) (((PyArrayObject*)a)->nd) +%#define array_dimensions(a) (((PyArrayObject*)a)->dimensions) +%#define array_size(a,i) (((PyArrayObject*)a)->dimensions[i]) +%#define array_strides(a) (((PyArrayObject*)a)->strides) +%#define array_stride(a,i) (((PyArrayObject*)a)->strides[i]) +%#define array_data(a) (((PyArrayObject*)a)->data) +%#define array_descr(a) (((PyArrayObject*)a)->descr) +%#define array_flags(a) (((PyArrayObject*)a)->flags) +%#define array_clearflags(a,f) (((PyArrayObject*)a)->flags) &= ~f +%#define array_enableflags(a,f) (((PyArrayObject*)a)->flags) = f +%#define array_is_fortran(a) (PyArray_ISFORTRAN((PyArrayObject*)a)) +%#else +%#define is_array(a) ((a) && PyArray_Check(a)) +%#define array_type(a) PyArray_TYPE((PyArrayObject*)a) +%#define array_numdims(a) PyArray_NDIM((PyArrayObject*)a) +%#define array_dimensions(a) PyArray_DIMS((PyArrayObject*)a) +%#define array_strides(a) PyArray_STRIDES((PyArrayObject*)a) +%#define array_stride(a,i) PyArray_STRIDE((PyArrayObject*)a,i) +%#define array_size(a,i) PyArray_DIM((PyArrayObject*)a,i) +%#define array_data(a) PyArray_DATA((PyArrayObject*)a) +%#define array_descr(a) PyArray_DESCR((PyArrayObject*)a) +%#define array_flags(a) PyArray_FLAGS((PyArrayObject*)a) +%#define array_enableflags(a,f) PyArray_ENABLEFLAGS((PyArrayObject*)a,f) +%#define array_clearflags(a,f) PyArray_CLEARFLAGS((PyArrayObject*)a,f) +%#define array_is_fortran(a) (PyArray_IS_F_CONTIGUOUS((PyArrayObject*)a)) +%#endif +%#define array_is_contiguous(a) (PyArray_ISCONTIGUOUS((PyArrayObject*)a)) +%#define array_is_native(a) (PyArray_ISNOTSWAPPED((PyArrayObject*)a)) +} + +/**********************************************************************/ + +%fragment("NumPy_Utilities", + "header") +{ + /* Given a PyObject, return a string describing its type. + */ + const char* pytype_string(PyObject* py_obj) + { + if (py_obj == NULL ) return "C NULL value"; + if (py_obj == Py_None ) return "Python None" ; + if (PyCallable_Check(py_obj)) return "callable" ; + if (PyString_Check( py_obj)) return "string" ; + if (PyInt_Check( py_obj)) return "int" ; + if (PyFloat_Check( py_obj)) return "float" ; + if (PyDict_Check( py_obj)) return "dict" ; + if (PyList_Check( py_obj)) return "list" ; + if (PyTuple_Check( py_obj)) return "tuple" ; +%#if PY_MAJOR_VERSION < 3 + if (PyFile_Check( py_obj)) return "file" ; + if (PyModule_Check( py_obj)) return "module" ; + if (PyInstance_Check(py_obj)) return "instance" ; +%#endif + + return "unknown type"; + } + + /* Given a NumPy typecode, return a string describing the type. + */ + const char* typecode_string(int typecode) + { + static const char* type_names[25] = {"bool", + "byte", + "unsigned byte", + "short", + "unsigned short", + "int", + "unsigned int", + "long", + "unsigned long", + "long long", + "unsigned long long", + "float", + "double", + "long double", + "complex float", + "complex double", + "complex long double", + "object", + "string", + "unicode", + "void", + "ntypes", + "notype", + "char", + "unknown"}; + return typecode < 24 ? type_names[typecode] : type_names[24]; + } + + /* Make sure input has correct numpy type. This now just calls + PyArray_EquivTypenums(). + */ + int type_match(int actual_type, + int desired_type) + { + return PyArray_EquivTypenums(actual_type, desired_type); + } + +%#ifdef SWIGPY_USE_CAPSULE + void free_cap(PyObject * cap) + { + void* array = (void*) PyCapsule_GetPointer(cap,SWIGPY_CAPSULE_NAME); + if (array != NULL) free(array); + } +%#endif + + +} + +/**********************************************************************/ + +%fragment("NumPy_Object_to_Array", + "header", + fragment="NumPy_Backward_Compatibility", + fragment="NumPy_Macros", + fragment="NumPy_Utilities") +{ + /* Given a PyObject pointer, cast it to a PyArrayObject pointer if + * legal. If not, set the python error string appropriately and + * return NULL. + */ + PyArrayObject* obj_to_array_no_conversion(PyObject* input, + int typecode) + { + PyArrayObject* ary = NULL; + if (is_array(input) && (typecode == NPY_NOTYPE || + PyArray_EquivTypenums(array_type(input), typecode))) + { + ary = (PyArrayObject*) input; + } + else if is_array(input) + { + const char* desired_type = typecode_string(typecode); + const char* actual_type = typecode_string(array_type(input)); + PyErr_Format(PyExc_TypeError, + "Array of type '%s' required. Array of type '%s' given", + desired_type, actual_type); + ary = NULL; + } + else + { + const char* desired_type = typecode_string(typecode); + const char* actual_type = pytype_string(input); + PyErr_Format(PyExc_TypeError, + "Array of type '%s' required. A '%s' was given", + desired_type, + actual_type); + ary = NULL; + } + return ary; + } + + /* Convert the given PyObject to a NumPy array with the given + * typecode. On success, return a valid PyArrayObject* with the + * correct type. On failure, the python error string will be set and + * the routine returns NULL. + */ + PyArrayObject* obj_to_array_allow_conversion(PyObject* input, + int typecode, + int* is_new_object) + { + PyArrayObject* ary = NULL; + PyObject* py_obj; + if (is_array(input) && (typecode == NPY_NOTYPE || + PyArray_EquivTypenums(array_type(input),typecode))) + { + ary = (PyArrayObject*) input; + *is_new_object = 0; + } + else + { + py_obj = PyArray_FROMANY(input, typecode, 0, 0, NPY_ARRAY_DEFAULT); + /* If NULL, PyArray_FromObject will have set python error value.*/ + ary = (PyArrayObject*) py_obj; + *is_new_object = 1; + } + return ary; + } + + /* Given a PyArrayObject, check to see if it is contiguous. If so, + * return the input pointer and flag it as not a new object. If it is + * not contiguous, create a new PyArrayObject using the original data, + * flag it as a new object and return the pointer. + */ + PyArrayObject* make_contiguous(PyArrayObject* ary, + int* is_new_object, + int min_dims, + int max_dims) + { + PyArrayObject* result; + if (array_is_contiguous(ary)) + { + result = ary; + *is_new_object = 0; + } + else + { + result = (PyArrayObject*) PyArray_ContiguousFromObject((PyObject*)ary, + array_type(ary), + min_dims, + max_dims); + *is_new_object = 1; + } + return result; + } + + /* Given a PyArrayObject, check to see if it is Fortran-contiguous. + * If so, return the input pointer, but do not flag it as not a new + * object. If it is not Fortran-contiguous, create a new + * PyArrayObject using the original data, flag it as a new object + * and return the pointer. + */ + PyArrayObject* make_fortran(PyArrayObject* ary, + int* is_new_object) + { + PyArrayObject* result; + if (array_is_fortran(ary)) + { + result = ary; + *is_new_object = 0; + } + else + { + Py_INCREF(array_descr(ary)); + result = (PyArrayObject*) PyArray_FromArray(ary, + array_descr(ary), +%#if NPY_API_VERSION < 0x00000007 + NPY_FORTRANORDER); +%#else + NPY_ARRAY_F_CONTIGUOUS); +%#endif + *is_new_object = 1; + } + return result; + } + + /* Convert a given PyObject to a contiguous PyArrayObject of the + * specified type. If the input object is not a contiguous + * PyArrayObject, a new one will be created and the new object flag + * will be set. + */ + PyArrayObject* obj_to_array_contiguous_allow_conversion(PyObject* input, + int typecode, + int* is_new_object) + { + int is_new1 = 0; + int is_new2 = 0; + PyArrayObject* ary2; + PyArrayObject* ary1 = obj_to_array_allow_conversion(input, + typecode, + &is_new1); + if (ary1) + { + ary2 = make_contiguous(ary1, &is_new2, 0, 0); + if ( is_new1 && is_new2) + { + Py_DECREF(ary1); + } + ary1 = ary2; + } + *is_new_object = is_new1 || is_new2; + return ary1; + } + + /* Convert a given PyObject to a Fortran-ordered PyArrayObject of the + * specified type. If the input object is not a Fortran-ordered + * PyArrayObject, a new one will be created and the new object flag + * will be set. + */ + PyArrayObject* obj_to_array_fortran_allow_conversion(PyObject* input, + int typecode, + int* is_new_object) + { + int is_new1 = 0; + int is_new2 = 0; + PyArrayObject* ary2; + PyArrayObject* ary1 = obj_to_array_allow_conversion(input, + typecode, + &is_new1); + if (ary1) + { + ary2 = make_fortran(ary1, &is_new2); + if (is_new1 && is_new2) + { + Py_DECREF(ary1); + } + ary1 = ary2; + } + *is_new_object = is_new1 || is_new2; + return ary1; + } +} /* end fragment */ + +/**********************************************************************/ + +%fragment("NumPy_Array_Requirements", + "header", + fragment="NumPy_Backward_Compatibility", + fragment="NumPy_Macros") +{ + /* Test whether a python object is contiguous. If array is + * contiguous, return 1. Otherwise, set the python error string and + * return 0. + */ + int require_contiguous(PyArrayObject* ary) + { + int contiguous = 1; + if (!array_is_contiguous(ary)) + { + PyErr_SetString(PyExc_TypeError, + "Array must be contiguous. A non-contiguous array was given"); + contiguous = 0; + } + return contiguous; + } + + /* Test whether a python object is (C_ or F_) contiguous. If array is + * contiguous, return 1. Otherwise, set the python error string and + * return 0. + */ + int require_c_or_f_contiguous(PyArrayObject* ary) + { + int contiguous = 1; + if (!(array_is_contiguous(ary) || array_is_fortran(ary))) + { + PyErr_SetString(PyExc_TypeError, + "Array must be contiguous (C_ or F_). A non-contiguous array was given"); + contiguous = 0; + } + return contiguous; + } + + /* Require that a numpy array is not byte-swapped. If the array is + * not byte-swapped, return 1. Otherwise, set the python error string + * and return 0. + */ + int require_native(PyArrayObject* ary) + { + int native = 1; + if (!array_is_native(ary)) + { + PyErr_SetString(PyExc_TypeError, + "Array must have native byteorder. " + "A byte-swapped array was given"); + native = 0; + } + return native; + } + + /* Require the given PyArrayObject to have a specified number of + * dimensions. If the array has the specified number of dimensions, + * return 1. Otherwise, set the python error string and return 0. + */ + int require_dimensions(PyArrayObject* ary, + int exact_dimensions) + { + int success = 1; + if (array_numdims(ary) != exact_dimensions) + { + PyErr_Format(PyExc_TypeError, + "Array must have %d dimensions. Given array has %d dimensions", + exact_dimensions, + array_numdims(ary)); + success = 0; + } + return success; + } + + /* Require the given PyArrayObject to have one of a list of specified + * number of dimensions. If the array has one of the specified number + * of dimensions, return 1. Otherwise, set the python error string + * and return 0. + */ + int require_dimensions_n(PyArrayObject* ary, + int* exact_dimensions, + int n) + { + int success = 0; + int i; + char dims_str[255] = ""; + char s[255]; + for (i = 0; i < n && !success; i++) + { + if (array_numdims(ary) == exact_dimensions[i]) + { + success = 1; + } + } + if (!success) + { + for (i = 0; i < n-1; i++) + { + sprintf(s, "%d, ", exact_dimensions[i]); + strcat(dims_str,s); + } + sprintf(s, " or %d", exact_dimensions[n-1]); + strcat(dims_str,s); + PyErr_Format(PyExc_TypeError, + "Array must have %s dimensions. Given array has %d dimensions", + dims_str, + array_numdims(ary)); + } + return success; + } + + /* Require the given PyArrayObject to have a specified shape. If the + * array has the specified shape, return 1. Otherwise, set the python + * error string and return 0. + */ + int require_size(PyArrayObject* ary, + npy_intp* size, + int n) + { + int i; + int success = 1; + int len; + char desired_dims[255] = "["; + char s[255]; + char actual_dims[255] = "["; + for(i=0; i < n;i++) + { + if (size[i] != -1 && size[i] != array_size(ary,i)) + { + success = 0; + } + } + if (!success) + { + for (i = 0; i < n; i++) + { + if (size[i] == -1) + { + sprintf(s, "*,"); + } + else + { + sprintf(s, "%ld,", (long int)size[i]); + } + strcat(desired_dims,s); + } + len = strlen(desired_dims); + desired_dims[len-1] = ']'; + for (i = 0; i < n; i++) + { + sprintf(s, "%ld,", (long int)array_size(ary,i)); + strcat(actual_dims,s); + } + len = strlen(actual_dims); + actual_dims[len-1] = ']'; + PyErr_Format(PyExc_TypeError, + "Array must have shape of %s. Given array has shape of %s", + desired_dims, + actual_dims); + } + return success; + } + + /* Require the given PyArrayObject to to be Fortran ordered. If the + * the PyArrayObject is already Fortran ordered, do nothing. Else, + * set the Fortran ordering flag and recompute the strides. + */ + int require_fortran(PyArrayObject* ary) + { + int success = 1; + int nd = array_numdims(ary); + int i; + npy_intp * strides = array_strides(ary); + if (array_is_fortran(ary)) return success; + int n_non_one = 0; + /* Set the Fortran ordered flag */ + const npy_intp *dims = array_dimensions(ary); + for (i=0; i < nd; ++i) + n_non_one += (dims[i] != 1) ? 1 : 0; + if (n_non_one > 1) + array_clearflags(ary,NPY_ARRAY_CARRAY); + array_enableflags(ary,NPY_ARRAY_FARRAY); + /* Recompute the strides */ + strides[0] = strides[nd-1]; + for (i=1; i < nd; ++i) + strides[i] = strides[i-1] * array_size(ary,i-1); + return success; + } +} + +/* Combine all NumPy fragments into one for convenience */ +%fragment("NumPy_Fragments", + "header", + fragment="NumPy_Backward_Compatibility", + fragment="NumPy_Macros", + fragment="NumPy_Utilities", + fragment="NumPy_Object_to_Array", + fragment="NumPy_Array_Requirements") +{ +} + +/* End John Hunter translation (with modifications by Bill Spotz) + */ + +/* %numpy_typemaps() macro + * + * This macro defines a family of 75 typemaps that allow C arguments + * of the form + * + * 1. (DATA_TYPE IN_ARRAY1[ANY]) + * 2. (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) + * 3. (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) + * + * 4. (DATA_TYPE IN_ARRAY2[ANY][ANY]) + * 5. (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + * 6. (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) + * 7. (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + * 8. (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) + * + * 9. (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) + * 10. (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + * 11. (DATA_TYPE** IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + * 12. (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_ARRAY3) + * 13. (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + * 14. (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_FARRAY3) + * + * 15. (DATA_TYPE IN_ARRAY4[ANY][ANY][ANY][ANY]) + * 16. (DATA_TYPE* IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + * 17. (DATA_TYPE** IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + * 18. (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, , DIM_TYPE DIM4, DATA_TYPE* IN_ARRAY4) + * 19. (DATA_TYPE* IN_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + * 20. (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* IN_FARRAY4) + * + * 21. (DATA_TYPE INPLACE_ARRAY1[ANY]) + * 22. (DATA_TYPE* INPLACE_ARRAY1, DIM_TYPE DIM1) + * 23. (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1) + * + * 24. (DATA_TYPE INPLACE_ARRAY2[ANY][ANY]) + * 25. (DATA_TYPE* INPLACE_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + * 26. (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_ARRAY2) + * 27. (DATA_TYPE* INPLACE_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + * 28. (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_FARRAY2) + * + * 29. (DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) + * 30. (DATA_TYPE* INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + * 31. (DATA_TYPE** INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + * 32. (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_ARRAY3) + * 33. (DATA_TYPE* INPLACE_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + * 34. (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_FARRAY3) + * + * 35. (DATA_TYPE INPLACE_ARRAY4[ANY][ANY][ANY][ANY]) + * 36. (DATA_TYPE* INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + * 37. (DATA_TYPE** INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + * 38. (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* INPLACE_ARRAY4) + * 39. (DATA_TYPE* INPLACE_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + * 40. (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* INPLACE_FARRAY4) + * + * 41. (DATA_TYPE ARGOUT_ARRAY1[ANY]) + * 42. (DATA_TYPE* ARGOUT_ARRAY1, DIM_TYPE DIM1) + * 43. (DIM_TYPE DIM1, DATA_TYPE* ARGOUT_ARRAY1) + * + * 44. (DATA_TYPE ARGOUT_ARRAY2[ANY][ANY]) + * + * 45. (DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) + * + * 46. (DATA_TYPE ARGOUT_ARRAY4[ANY][ANY][ANY][ANY]) + * + * 47. (DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1) + * 48. (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEW_ARRAY1) + * + * 49. (DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) + * 50. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_ARRAY2) + * 51. (DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) + * 52. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_FARRAY2) + * + * 53. (DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) + * 54. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_ARRAY3) + * 55. (DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) + * 56. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_FARRAY3) + * + * 57. (DATA_TYPE** ARGOUTVIEW_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) + * 58. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEW_ARRAY4) + * 59. (DATA_TYPE** ARGOUTVIEW_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) + * 60. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEW_FARRAY4) + * + * 61. (DATA_TYPE** ARGOUTVIEWM_ARRAY1, DIM_TYPE* DIM1) + * 62. (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEWM_ARRAY1) + * + * 63. (DATA_TYPE** ARGOUTVIEWM_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) + * 64. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEWM_ARRAY2) + * 65. (DATA_TYPE** ARGOUTVIEWM_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) + * 66. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEWM_FARRAY2) + * + * 67. (DATA_TYPE** ARGOUTVIEWM_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) + * 68. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEWM_ARRAY3) + * 69. (DATA_TYPE** ARGOUTVIEWM_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) + * 70. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEWM_FARRAY3) + * + * 71. (DATA_TYPE** ARGOUTVIEWM_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) + * 72. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEWM_ARRAY4) + * 73. (DATA_TYPE** ARGOUTVIEWM_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) + * 74. (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEWM_FARRAY4) + * + * 75. (DATA_TYPE* INPLACE_ARRAY_FLAT, DIM_TYPE DIM_FLAT) + * + * where "DATA_TYPE" is any type supported by the NumPy module, and + * "DIM_TYPE" is any int-like type suitable for specifying dimensions. + * The difference between "ARRAY" typemaps and "FARRAY" typemaps is + * that the "FARRAY" typemaps expect Fortran ordering of + * multidimensional arrays. In python, the dimensions will not need + * to be specified (except for the "DATA_TYPE* ARGOUT_ARRAY1" + * typemaps). The IN_ARRAYs can be a numpy array or any sequence that + * can be converted to a numpy array of the specified type. The + * INPLACE_ARRAYs must be numpy arrays of the appropriate type. The + * ARGOUT_ARRAYs will be returned as new numpy arrays of the + * appropriate type. + * + * These typemaps can be applied to existing functions using the + * %apply directive. For example: + * + * %apply (double* IN_ARRAY1, int DIM1) {(double* series, int length)}; + * double prod(double* series, int length); + * + * %apply (int DIM1, int DIM2, double* INPLACE_ARRAY2) + * {(int rows, int cols, double* matrix )}; + * void floor(int rows, int cols, double* matrix, double f); + * + * %apply (double IN_ARRAY3[ANY][ANY][ANY]) + * {(double tensor[2][2][2] )}; + * %apply (double ARGOUT_ARRAY3[ANY][ANY][ANY]) + * {(double low[2][2][2] )}; + * %apply (double ARGOUT_ARRAY3[ANY][ANY][ANY]) + * {(double upp[2][2][2] )}; + * void luSplit(double tensor[2][2][2], + * double low[2][2][2], + * double upp[2][2][2] ); + * + * or directly with + * + * double prod(double* IN_ARRAY1, int DIM1); + * + * void floor(int DIM1, int DIM2, double* INPLACE_ARRAY2, double f); + * + * void luSplit(double IN_ARRAY3[ANY][ANY][ANY], + * double ARGOUT_ARRAY3[ANY][ANY][ANY], + * double ARGOUT_ARRAY3[ANY][ANY][ANY]); + */ + +%define %numpy_typemaps(DATA_TYPE, DATA_TYPECODE, DIM_TYPE) + +/************************/ +/* Input Array Typemaps */ +/************************/ + +/* Typemap suite for (DATA_TYPE IN_ARRAY1[ANY]) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE IN_ARRAY1[ANY]) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE IN_ARRAY1[ANY]) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[1] = { $1_dim0 }; + array = obj_to_array_contiguous_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 1) || + !require_size(array, size, 1)) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} +%typemap(freearg) + (DATA_TYPE IN_ARRAY1[ANY]) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[1] = { -1 }; + array = obj_to_array_contiguous_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 1) || + !require_size(array, size, 1)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); +} +%typemap(freearg) + (DATA_TYPE* IN_ARRAY1, DIM_TYPE DIM1) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[1] = {-1}; + array = obj_to_array_contiguous_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 1) || + !require_size(array, size, 1)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DATA_TYPE*) array_data(array); +} +%typemap(freearg) + (DIM_TYPE DIM1, DATA_TYPE* IN_ARRAY1) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE IN_ARRAY2[ANY][ANY]) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE IN_ARRAY2[ANY][ANY]) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE IN_ARRAY2[ANY][ANY]) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[2] = { $1_dim0, $1_dim1 }; + array = obj_to_array_contiguous_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 2) || + !require_size(array, size, 2)) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} +%typemap(freearg) + (DATA_TYPE IN_ARRAY2[ANY][ANY]) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[2] = { -1, -1 }; + array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 2) || + !require_size(array, size, 2)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); +} +%typemap(freearg) + (DATA_TYPE* IN_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[2] = { -1, -1 }; + array = obj_to_array_contiguous_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 2) || + !require_size(array, size, 2)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DATA_TYPE*) array_data(array); +} +%typemap(freearg) + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_ARRAY2) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[2] = { -1, -1 }; + array = obj_to_array_fortran_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 2) || + !require_size(array, size, 2) || !require_fortran(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); +} +%typemap(freearg) + (DATA_TYPE* IN_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[2] = { -1, -1 }; + array = obj_to_array_fortran_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 2) || + !require_size(array, size, 2) || !require_fortran(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DATA_TYPE*) array_data(array); +} +%typemap(freearg) + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* IN_FARRAY2) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[3] = { $1_dim0, $1_dim1, $1_dim2 }; + array = obj_to_array_contiguous_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 3) || + !require_size(array, size, 3)) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} +%typemap(freearg) + (DATA_TYPE IN_ARRAY3[ANY][ANY][ANY]) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[3] = { -1, -1, -1 }; + array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 3) || + !require_size(array, size, 3)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); + $4 = (DIM_TYPE) array_size(array,2); +} +%typemap(freearg) + (DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE** IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE** IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + /* for now, only concerned with lists */ + $1 = PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE** IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + (DATA_TYPE** array=NULL, PyArrayObject** object_array=NULL, int* is_new_object_array=NULL) +{ + npy_intp size[2] = { -1, -1 }; + PyArrayObject* temp_array; + Py_ssize_t i; + int is_new_object; + + /* length of the list */ + $2 = PyList_Size($input); + + /* the arrays */ + array = (DATA_TYPE **)malloc($2*sizeof(DATA_TYPE *)); + object_array = (PyArrayObject **)calloc($2,sizeof(PyArrayObject *)); + is_new_object_array = (int *)calloc($2,sizeof(int)); + + if (array == NULL || object_array == NULL || is_new_object_array == NULL) + { + SWIG_fail; + } + + for (i=0; i<$2; i++) + { + temp_array = obj_to_array_contiguous_allow_conversion(PySequence_GetItem($input,i), DATA_TYPECODE, &is_new_object); + + /* the new array must be stored so that it can be destroyed in freearg */ + object_array[i] = temp_array; + is_new_object_array[i] = is_new_object; + + if (!temp_array || !require_dimensions(temp_array, 2)) SWIG_fail; + + /* store the size of the first array in the list, then use that for comparison. */ + if (i == 0) + { + size[0] = array_size(temp_array,0); + size[1] = array_size(temp_array,1); + } + + if (!require_size(temp_array, size, 2)) SWIG_fail; + + array[i] = (DATA_TYPE*) array_data(temp_array); + } + + $1 = (DATA_TYPE**) array; + $3 = (DIM_TYPE) size[0]; + $4 = (DIM_TYPE) size[1]; +} +%typemap(freearg) + (DATA_TYPE** IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + Py_ssize_t i; + + if (array$argnum!=NULL) free(array$argnum); + + /*freeing the individual arrays if needed */ + if (object_array$argnum!=NULL) + { + if (is_new_object_array$argnum!=NULL) + { + for (i=0; i<$2; i++) + { + if (object_array$argnum[i] != NULL && is_new_object_array$argnum[i]) + { Py_DECREF(object_array$argnum[i]); } + } + free(is_new_object_array$argnum); + } + free(object_array$argnum); + } +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, + * DATA_TYPE* IN_ARRAY3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_ARRAY3) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_ARRAY3) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[3] = { -1, -1, -1 }; + array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 3) || + !require_size(array, size, 3)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DIM_TYPE) array_size(array,2); + $4 = (DATA_TYPE*) array_data(array); +} +%typemap(freearg) + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_ARRAY3) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[3] = { -1, -1, -1 }; + array = obj_to_array_fortran_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 3) || + !require_size(array, size, 3) | !require_fortran(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); + $4 = (DIM_TYPE) array_size(array,2); +} +%typemap(freearg) + (DATA_TYPE* IN_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, + * DATA_TYPE* IN_FARRAY3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_FARRAY3) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_FARRAY3) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[3] = { -1, -1, -1 }; + array = obj_to_array_fortran_allow_conversion($input, + DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 3) || + !require_size(array, size, 3) || !require_fortran(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DIM_TYPE) array_size(array,2); + $4 = (DATA_TYPE*) array_data(array); +} +%typemap(freearg) + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* IN_FARRAY3) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE IN_ARRAY4[ANY][ANY][ANY][ANY]) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE IN_ARRAY4[ANY][ANY][ANY][ANY]) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE IN_ARRAY4[ANY][ANY][ANY][ANY]) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[4] = { $1_dim0, $1_dim1, $1_dim2 , $1_dim3}; + array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 4) || + !require_size(array, size, 4)) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} +%typemap(freearg) + (DATA_TYPE IN_ARRAY4[ANY][ANY][ANY][ANY]) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE* IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3, DIM_TYPE DIM4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[4] = { -1, -1, -1, -1 }; + array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 4) || + !require_size(array, size, 4)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); + $4 = (DIM_TYPE) array_size(array,2); + $5 = (DIM_TYPE) array_size(array,3); +} +%typemap(freearg) + (DATA_TYPE* IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE** IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3, DIM_TYPE DIM4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE** IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + /* for now, only concerned with lists */ + $1 = PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE** IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + (DATA_TYPE** array=NULL, PyArrayObject** object_array=NULL, int* is_new_object_array=NULL) +{ + npy_intp size[3] = { -1, -1, -1 }; + PyArrayObject* temp_array; + Py_ssize_t i; + int is_new_object; + + /* length of the list */ + $2 = PyList_Size($input); + + /* the arrays */ + array = (DATA_TYPE **)malloc($2*sizeof(DATA_TYPE *)); + object_array = (PyArrayObject **)calloc($2,sizeof(PyArrayObject *)); + is_new_object_array = (int *)calloc($2,sizeof(int)); + + if (array == NULL || object_array == NULL || is_new_object_array == NULL) + { + SWIG_fail; + } + + for (i=0; i<$2; i++) + { + temp_array = obj_to_array_contiguous_allow_conversion(PySequence_GetItem($input,i), DATA_TYPECODE, &is_new_object); + + /* the new array must be stored so that it can be destroyed in freearg */ + object_array[i] = temp_array; + is_new_object_array[i] = is_new_object; + + if (!temp_array || !require_dimensions(temp_array, 3)) SWIG_fail; + + /* store the size of the first array in the list, then use that for comparison. */ + if (i == 0) + { + size[0] = array_size(temp_array,0); + size[1] = array_size(temp_array,1); + size[2] = array_size(temp_array,2); + } + + if (!require_size(temp_array, size, 3)) SWIG_fail; + + array[i] = (DATA_TYPE*) array_data(temp_array); + } + + $1 = (DATA_TYPE**) array; + $3 = (DIM_TYPE) size[0]; + $4 = (DIM_TYPE) size[1]; + $5 = (DIM_TYPE) size[2]; +} +%typemap(freearg) + (DATA_TYPE** IN_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + Py_ssize_t i; + + if (array$argnum!=NULL) free(array$argnum); + + /*freeing the individual arrays if needed */ + if (object_array$argnum!=NULL) + { + if (is_new_object_array$argnum!=NULL) + { + for (i=0; i<$2; i++) + { + if (object_array$argnum[i] != NULL && is_new_object_array$argnum[i]) + { Py_DECREF(object_array$argnum[i]); } + } + free(is_new_object_array$argnum); + } + free(object_array$argnum); + } +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, + * DATA_TYPE* IN_ARRAY4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* IN_ARRAY4) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* IN_ARRAY4) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[4] = { -1, -1, -1 , -1}; + array = obj_to_array_contiguous_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 4) || + !require_size(array, size, 4)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DIM_TYPE) array_size(array,2); + $4 = (DIM_TYPE) array_size(array,3); + $5 = (DATA_TYPE*) array_data(array); +} +%typemap(freearg) + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* IN_ARRAY4) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DATA_TYPE* IN_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3, DIM_TYPE DIM4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* IN_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* IN_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[4] = { -1, -1, -1, -1 }; + array = obj_to_array_fortran_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 4) || + !require_size(array, size, 4) | !require_fortran(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); + $4 = (DIM_TYPE) array_size(array,2); + $5 = (DIM_TYPE) array_size(array,3); +} +%typemap(freearg) + (DATA_TYPE* IN_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, + * DATA_TYPE* IN_FARRAY4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* IN_FARRAY4) +{ + $1 = is_array($input) || PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* IN_FARRAY4) + (PyArrayObject* array=NULL, int is_new_object=0) +{ + npy_intp size[4] = { -1, -1, -1 , -1 }; + array = obj_to_array_fortran_allow_conversion($input, DATA_TYPECODE, + &is_new_object); + if (!array || !require_dimensions(array, 4) || + !require_size(array, size, 4) || !require_fortran(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DIM_TYPE) array_size(array,2); + $4 = (DIM_TYPE) array_size(array,3); + $5 = (DATA_TYPE*) array_data(array); +} +%typemap(freearg) + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* IN_FARRAY4) +{ + if (is_new_object$argnum && array$argnum) + { Py_DECREF(array$argnum); } +} + +/***************************/ +/* In-Place Array Typemaps */ +/***************************/ + +/* Typemap suite for (DATA_TYPE INPLACE_ARRAY1[ANY]) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE INPLACE_ARRAY1[ANY]) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE INPLACE_ARRAY1[ANY]) + (PyArrayObject* array=NULL) +{ + npy_intp size[1] = { $1_dim0 }; + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,1) || !require_size(array, size, 1) || + !require_contiguous(array) || !require_native(array)) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} + +/* Typemap suite for (DATA_TYPE* INPLACE_ARRAY1, DIM_TYPE DIM1) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* INPLACE_ARRAY1, DIM_TYPE DIM1) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* INPLACE_ARRAY1, DIM_TYPE DIM1) + (PyArrayObject* array=NULL, int i=1) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,1) || !require_contiguous(array) + || !require_native(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = 1; + for (i=0; i < array_numdims(array); ++i) $2 *= array_size(array,i); +} + +/* Typemap suite for (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DATA_TYPE* INPLACE_ARRAY1) + (PyArrayObject* array=NULL, int i=0) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,1) || !require_contiguous(array) + || !require_native(array)) SWIG_fail; + $1 = 1; + for (i=0; i < array_numdims(array); ++i) $1 *= array_size(array,i); + $2 = (DATA_TYPE*) array_data(array); +} + +/* Typemap suite for (DATA_TYPE INPLACE_ARRAY2[ANY][ANY]) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE INPLACE_ARRAY2[ANY][ANY]) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE INPLACE_ARRAY2[ANY][ANY]) + (PyArrayObject* array=NULL) +{ + npy_intp size[2] = { $1_dim0, $1_dim1 }; + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,2) || !require_size(array, size, 2) || + !require_contiguous(array) || !require_native(array)) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} + +/* Typemap suite for (DATA_TYPE* INPLACE_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* INPLACE_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* INPLACE_ARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,2) || !require_contiguous(array) + || !require_native(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_ARRAY2) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_ARRAY2) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_ARRAY2) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,2) || !require_contiguous(array) || + !require_native(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DATA_TYPE*) array_data(array); +} + +/* Typemap suite for (DATA_TYPE* INPLACE_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* INPLACE_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* INPLACE_FARRAY2, DIM_TYPE DIM1, DIM_TYPE DIM2) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,2) || !require_contiguous(array) + || !require_native(array) || !require_fortran(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_FARRAY2) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_FARRAY2) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DATA_TYPE* INPLACE_FARRAY2) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,2) || !require_contiguous(array) || + !require_native(array) || !require_fortran(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DATA_TYPE*) array_data(array); +} + +/* Typemap suite for (DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) + (PyArrayObject* array=NULL) +{ + npy_intp size[3] = { $1_dim0, $1_dim1, $1_dim2 }; + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,3) || !require_size(array, size, 3) || + !require_contiguous(array) || !require_native(array)) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} + +/* Typemap suite for (DATA_TYPE* INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,3) || !require_contiguous(array) || + !require_native(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); + $4 = (DIM_TYPE) array_size(array,2); +} + +/* Typemap suite for (DATA_TYPE** INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE** INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + $1 = PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE** INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + (DATA_TYPE** array=NULL, PyArrayObject** object_array=NULL) +{ + npy_intp size[2] = { -1, -1 }; + PyArrayObject* temp_array; + Py_ssize_t i; + + /* length of the list */ + $2 = PyList_Size($input); + + /* the arrays */ + array = (DATA_TYPE **)malloc($2*sizeof(DATA_TYPE *)); + object_array = (PyArrayObject **)calloc($2,sizeof(PyArrayObject *)); + + if (array == NULL || object_array == NULL) + { + SWIG_fail; + } + + for (i=0; i<$2; i++) + { + temp_array = obj_to_array_no_conversion(PySequence_GetItem($input,i), DATA_TYPECODE); + + /* the new array must be stored so that it can be destroyed in freearg */ + object_array[i] = temp_array; + + if ( !temp_array || !require_dimensions(temp_array, 2) || + !require_contiguous(temp_array) || + !require_native(temp_array) || + !PyArray_EquivTypenums(array_type(temp_array), DATA_TYPECODE) + ) SWIG_fail; + + /* store the size of the first array in the list, then use that for comparison. */ + if (i == 0) + { + size[0] = array_size(temp_array,0); + size[1] = array_size(temp_array,1); + } + + if (!require_size(temp_array, size, 2)) SWIG_fail; + + array[i] = (DATA_TYPE*) array_data(temp_array); + } + + $1 = (DATA_TYPE**) array; + $3 = (DIM_TYPE) size[0]; + $4 = (DIM_TYPE) size[1]; +} +%typemap(freearg) + (DATA_TYPE** INPLACE_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + if (array$argnum!=NULL) free(array$argnum); + if (object_array$argnum!=NULL) free(object_array$argnum); +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, + * DATA_TYPE* INPLACE_ARRAY3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_ARRAY3) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_ARRAY3) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,3) || !require_contiguous(array) + || !require_native(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DIM_TYPE) array_size(array,2); + $4 = (DATA_TYPE*) array_data(array); +} + +/* Typemap suite for (DATA_TYPE* INPLACE_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* INPLACE_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* INPLACE_FARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,3) || !require_contiguous(array) || + !require_native(array) || !require_fortran(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); + $4 = (DIM_TYPE) array_size(array,2); +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, + * DATA_TYPE* INPLACE_FARRAY3) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_FARRAY3) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DATA_TYPE* INPLACE_FARRAY3) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,3) || !require_contiguous(array) + || !require_native(array) || !require_fortran(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DIM_TYPE) array_size(array,2); + $4 = (DATA_TYPE*) array_data(array); +} + +/* Typemap suite for (DATA_TYPE INPLACE_ARRAY4[ANY][ANY][ANY][ANY]) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE INPLACE_ARRAY4[ANY][ANY][ANY][ANY]) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE INPLACE_ARRAY4[ANY][ANY][ANY][ANY]) + (PyArrayObject* array=NULL) +{ + npy_intp size[4] = { $1_dim0, $1_dim1, $1_dim2 , $1_dim3 }; + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,4) || !require_size(array, size, 4) || + !require_contiguous(array) || !require_native(array)) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} + +/* Typemap suite for (DATA_TYPE* INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3, DIM_TYPE DIM4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,4) || !require_contiguous(array) || + !require_native(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); + $4 = (DIM_TYPE) array_size(array,2); + $5 = (DIM_TYPE) array_size(array,3); +} + +/* Typemap suite for (DATA_TYPE** INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3, DIM_TYPE DIM4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE** INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + $1 = PySequence_Check($input); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE** INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + (DATA_TYPE** array=NULL, PyArrayObject** object_array=NULL) +{ + npy_intp size[3] = { -1, -1, -1 }; + PyArrayObject* temp_array; + Py_ssize_t i; + + /* length of the list */ + $2 = PyList_Size($input); + + /* the arrays */ + array = (DATA_TYPE **)malloc($2*sizeof(DATA_TYPE *)); + object_array = (PyArrayObject **)calloc($2,sizeof(PyArrayObject *)); + + if (array == NULL || object_array == NULL) + { + SWIG_fail; + } + + for (i=0; i<$2; i++) + { + temp_array = obj_to_array_no_conversion(PySequence_GetItem($input,i), DATA_TYPECODE); + + /* the new array must be stored so that it can be destroyed in freearg */ + object_array[i] = temp_array; + + if ( !temp_array || !require_dimensions(temp_array, 3) || + !require_contiguous(temp_array) || + !require_native(temp_array) || + !PyArray_EquivTypenums(array_type(temp_array), DATA_TYPECODE) + ) SWIG_fail; + + /* store the size of the first array in the list, then use that for comparison. */ + if (i == 0) + { + size[0] = array_size(temp_array,0); + size[1] = array_size(temp_array,1); + size[2] = array_size(temp_array,2); + } + + if (!require_size(temp_array, size, 3)) SWIG_fail; + + array[i] = (DATA_TYPE*) array_data(temp_array); + } + + $1 = (DATA_TYPE**) array; + $3 = (DIM_TYPE) size[0]; + $4 = (DIM_TYPE) size[1]; + $5 = (DIM_TYPE) size[2]; +} +%typemap(freearg) + (DATA_TYPE** INPLACE_ARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + if (array$argnum!=NULL) free(array$argnum); + if (object_array$argnum!=NULL) free(object_array$argnum); +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, + * DATA_TYPE* INPLACE_ARRAY4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* INPLACE_ARRAY4) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* INPLACE_ARRAY4) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,4) || !require_contiguous(array) + || !require_native(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DIM_TYPE) array_size(array,2); + $4 = (DIM_TYPE) array_size(array,3); + $5 = (DATA_TYPE*) array_data(array); +} + +/* Typemap suite for (DATA_TYPE* INPLACE_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, + * DIM_TYPE DIM3, DIM_TYPE DIM4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* INPLACE_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* INPLACE_FARRAY4, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,4) || !require_contiguous(array) || + !require_native(array) || !require_fortran(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = (DIM_TYPE) array_size(array,0); + $3 = (DIM_TYPE) array_size(array,1); + $4 = (DIM_TYPE) array_size(array,2); + $5 = (DIM_TYPE) array_size(array,3); +} + +/* Typemap suite for (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, + * DATA_TYPE* INPLACE_FARRAY4) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* INPLACE_FARRAY4) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3, DIM_TYPE DIM4, DATA_TYPE* INPLACE_FARRAY4) + (PyArrayObject* array=NULL) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_dimensions(array,4) || !require_contiguous(array) + || !require_native(array) || !require_fortran(array)) SWIG_fail; + $1 = (DIM_TYPE) array_size(array,0); + $2 = (DIM_TYPE) array_size(array,1); + $3 = (DIM_TYPE) array_size(array,2); + $4 = (DIM_TYPE) array_size(array,3); + $5 = (DATA_TYPE*) array_data(array); +} + +/*************************/ +/* Argout Array Typemaps */ +/*************************/ + +/* Typemap suite for (DATA_TYPE ARGOUT_ARRAY1[ANY]) + */ +%typemap(in,numinputs=0, + fragment="NumPy_Backward_Compatibility,NumPy_Macros") + (DATA_TYPE ARGOUT_ARRAY1[ANY]) + (PyObject* array = NULL) +{ + npy_intp dims[1] = { $1_dim0 }; + array = PyArray_SimpleNew(1, dims, DATA_TYPECODE); + if (!array) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} +%typemap(argout) + (DATA_TYPE ARGOUT_ARRAY1[ANY]) +{ + $result = SWIG_Python_AppendOutput($result,(PyObject*)array$argnum); +} + +/* Typemap suite for (DATA_TYPE* ARGOUT_ARRAY1, DIM_TYPE DIM1) + */ +%typemap(in,numinputs=1, + fragment="NumPy_Fragments") + (DATA_TYPE* ARGOUT_ARRAY1, DIM_TYPE DIM1) + (PyObject* array = NULL) +{ + npy_intp dims[1]; + if (!PyInt_Check($input)) + { + const char* typestring = pytype_string($input); + PyErr_Format(PyExc_TypeError, + "Int dimension expected. '%s' given.", + typestring); + SWIG_fail; + } + $2 = (DIM_TYPE) PyInt_AsLong($input); + dims[0] = (npy_intp) $2; + array = PyArray_SimpleNew(1, dims, DATA_TYPECODE); + if (!array) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); +} +%typemap(argout) + (DATA_TYPE* ARGOUT_ARRAY1, DIM_TYPE DIM1) +{ + $result = SWIG_Python_AppendOutput($result,(PyObject*)array$argnum); +} + +/* Typemap suite for (DIM_TYPE DIM1, DATA_TYPE* ARGOUT_ARRAY1) + */ +%typemap(in,numinputs=1, + fragment="NumPy_Fragments") + (DIM_TYPE DIM1, DATA_TYPE* ARGOUT_ARRAY1) + (PyObject* array = NULL) +{ + npy_intp dims[1]; + if (!PyInt_Check($input)) + { + const char* typestring = pytype_string($input); + PyErr_Format(PyExc_TypeError, + "Int dimension expected. '%s' given.", + typestring); + SWIG_fail; + } + $1 = (DIM_TYPE) PyInt_AsLong($input); + dims[0] = (npy_intp) $1; + array = PyArray_SimpleNew(1, dims, DATA_TYPECODE); + if (!array) SWIG_fail; + $2 = (DATA_TYPE*) array_data(array); +} +%typemap(argout) + (DIM_TYPE DIM1, DATA_TYPE* ARGOUT_ARRAY1) +{ + $result = SWIG_Python_AppendOutput($result,(PyObject*)array$argnum); +} + +/* Typemap suite for (DATA_TYPE ARGOUT_ARRAY2[ANY][ANY]) + */ +%typemap(in,numinputs=0, + fragment="NumPy_Backward_Compatibility,NumPy_Macros") + (DATA_TYPE ARGOUT_ARRAY2[ANY][ANY]) + (PyObject* array = NULL) +{ + npy_intp dims[2] = { $1_dim0, $1_dim1 }; + array = PyArray_SimpleNew(2, dims, DATA_TYPECODE); + if (!array) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} +%typemap(argout) + (DATA_TYPE ARGOUT_ARRAY2[ANY][ANY]) +{ + $result = SWIG_Python_AppendOutput($result,(PyObject*)array$argnum); +} + +/* Typemap suite for (DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) + */ +%typemap(in,numinputs=0, + fragment="NumPy_Backward_Compatibility,NumPy_Macros") + (DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) + (PyObject* array = NULL) +{ + npy_intp dims[3] = { $1_dim0, $1_dim1, $1_dim2 }; + array = PyArray_SimpleNew(3, dims, DATA_TYPECODE); + if (!array) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} +%typemap(argout) + (DATA_TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) +{ + $result = SWIG_Python_AppendOutput($result,(PyObject*)array$argnum); +} + +/* Typemap suite for (DATA_TYPE ARGOUT_ARRAY4[ANY][ANY][ANY][ANY]) + */ +%typemap(in,numinputs=0, + fragment="NumPy_Backward_Compatibility,NumPy_Macros") + (DATA_TYPE ARGOUT_ARRAY4[ANY][ANY][ANY][ANY]) + (PyObject* array = NULL) +{ + npy_intp dims[4] = { $1_dim0, $1_dim1, $1_dim2, $1_dim3 }; + array = PyArray_SimpleNew(4, dims, DATA_TYPECODE); + if (!array) SWIG_fail; + $1 = ($1_ltype) array_data(array); +} +%typemap(argout) + (DATA_TYPE ARGOUT_ARRAY4[ANY][ANY][ANY][ANY]) +{ + $result = SWIG_Python_AppendOutput($result,(PyObject*)array$argnum); +} + +/*****************************/ +/* Argoutview Array Typemaps */ +/*****************************/ + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim_temp) +{ + $1 = &data_temp; + $2 = &dim_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility") + (DATA_TYPE** ARGOUTVIEW_ARRAY1, DIM_TYPE* DIM1) +{ + npy_intp dims[1] = { *$2 }; + PyObject* obj = PyArray_SimpleNewFromData(1, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEW_ARRAY1) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DATA_TYPE** ARGOUTVIEW_ARRAY1) + (DIM_TYPE dim_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim_temp; + $2 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility") + (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEW_ARRAY1) +{ + npy_intp dims[1] = { *$1 }; + PyObject* obj = PyArray_SimpleNewFromData(1, dims, DATA_TYPECODE, (void*)(*$2)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility") + (DATA_TYPE** ARGOUTVIEW_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) +{ + npy_intp dims[2] = { *$2, *$3 }; + PyObject* obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_ARRAY2) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DATA_TYPE** ARGOUTVIEW_ARRAY2) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_ARRAY2) +{ + npy_intp dims[2] = { *$1, *$2 }; + PyObject* obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$3)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") + (DATA_TYPE** ARGOUTVIEW_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) +{ + npy_intp dims[2] = { *$2, *$3 }; + PyObject* obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_FARRAY2) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DATA_TYPE** ARGOUTVIEW_FARRAY2) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEW_FARRAY2) +{ + npy_intp dims[2] = { *$1, *$2 }; + PyObject* obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$3)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility") + (DATA_TYPE** ARGOUTVIEW_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) +{ + npy_intp dims[3] = { *$2, *$3, *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, + DATA_TYPE** ARGOUTVIEW_ARRAY3) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_ARRAY3) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DATA_TYPE* data_temp = NULL) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_ARRAY3) +{ + npy_intp dims[3] = { *$1, *$2, *$3 }; + PyObject* obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$4)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") + (DATA_TYPE** ARGOUTVIEW_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) +{ + npy_intp dims[3] = { *$2, *$3, *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, + DATA_TYPE** ARGOUTVIEW_FARRAY3) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DATA_TYPE** ARGOUTVIEW_FARRAY3) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEW_FARRAY3) +{ + npy_intp dims[3] = { *$1, *$2, *$3 }; + PyObject* obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$4)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEW_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3, DIM_TYPE* DIM4) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEW_ARRAY4, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; + $5 = &dim4_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility") + (DATA_TYPE** ARGOUTVIEW_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) +{ + npy_intp dims[4] = { *$2, *$3, *$4 , *$5 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, + DATA_TYPE** ARGOUTVIEW_ARRAY4) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 , DATA_TYPE** ARGOUTVIEW_ARRAY4) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &dim4_temp; + $5 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEW_ARRAY4) +{ + npy_intp dims[4] = { *$1, *$2, *$3 , *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$5)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEW_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3, DIM_TYPE* DIM4) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEW_FARRAY4, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; + $5 = &dim4_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") + (DATA_TYPE** ARGOUTVIEW_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) +{ + npy_intp dims[4] = { *$2, *$3, *$4 , *$5 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, + DATA_TYPE** ARGOUTVIEW_FARRAY4) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 , DATA_TYPE** ARGOUTVIEW_FARRAY4) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &dim4_temp; + $5 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEW_FARRAY4) +{ + npy_intp dims[4] = { *$1, *$2, *$3 , *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$5)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + $result = SWIG_Python_AppendOutput($result,obj); +} + +/*************************************/ +/* Managed Argoutview Array Typemaps */ +/*************************************/ + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_ARRAY1, DIM_TYPE* DIM1) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_ARRAY1, DIM_TYPE* DIM1 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim_temp) +{ + $1 = &data_temp; + $2 = &dim_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_ARRAY1, DIM_TYPE* DIM1) +{ + npy_intp dims[1] = { *$2 }; + PyObject* obj = PyArray_SimpleNewFromData(1, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEWM_ARRAY1) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DATA_TYPE** ARGOUTVIEWM_ARRAY1) + (DIM_TYPE dim_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim_temp; + $2 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DIM_TYPE* DIM1, DATA_TYPE** ARGOUTVIEWM_ARRAY1) +{ + npy_intp dims[1] = { *$1 }; + PyObject* obj = PyArray_SimpleNewFromData(1, dims, DATA_TYPECODE, (void*)(*$2)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_ARRAY2, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_ARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) +{ + npy_intp dims[2] = { *$2, *$3 }; + PyObject* obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEWM_ARRAY2) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DATA_TYPE** ARGOUTVIEWM_ARRAY2) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEWM_ARRAY2) +{ + npy_intp dims[2] = { *$1, *$2 }; + PyObject* obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$3)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_FARRAY2, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_FARRAY2, DIM_TYPE* DIM1, DIM_TYPE* DIM2) +{ + npy_intp dims[2] = { *$2, *$3 }; + PyObject* obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEWM_FARRAY2) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DATA_TYPE** ARGOUTVIEWM_FARRAY2) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements,NumPy_Utilities") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DATA_TYPE** ARGOUTVIEWM_FARRAY2) +{ + npy_intp dims[2] = { *$1, *$2 }; + PyObject* obj = PyArray_SimpleNewFromData(2, dims, DATA_TYPECODE, (void*)(*$3)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_ARRAY3, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_ARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) +{ + npy_intp dims[3] = { *$2, *$3, *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, + DATA_TYPE** ARGOUTVIEWM_ARRAY3) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DATA_TYPE** ARGOUTVIEWM_ARRAY3) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEWM_ARRAY3) +{ + npy_intp dims[3] = { *$1, *$2, *$3 }; + PyObject* obj= PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$4)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_FARRAY3, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_FARRAY3, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) +{ + npy_intp dims[3] = { *$2, *$3, *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, + DATA_TYPE** ARGOUTVIEWM_FARRAY3) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DATA_TYPE** ARGOUTVIEWM_FARRAY3) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements,NumPy_Utilities") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DATA_TYPE** ARGOUTVIEWM_FARRAY3) +{ + npy_intp dims[3] = { *$1, *$2, *$3 }; + PyObject* obj = PyArray_SimpleNewFromData(3, dims, DATA_TYPECODE, (void*)(*$4)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3, DIM_TYPE* DIM4) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_ARRAY4, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; + $5 = &dim4_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) +{ + npy_intp dims[4] = { *$2, *$3, *$4 , *$5 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, + DATA_TYPE** ARGOUTVIEWM_ARRAY4) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 , DATA_TYPE** ARGOUTVIEWM_ARRAY4) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &dim4_temp; + $5 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEWM_ARRAY4) +{ + npy_intp dims[4] = { *$1, *$2, *$3 , *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$5)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3, DIM_TYPE* DIM4) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_FARRAY4, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; + $5 = &dim4_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3) +{ + npy_intp dims[4] = { *$2, *$3, *$4 , *$5 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, + DATA_TYPE** ARGOUTVIEWM_FARRAY4) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 , DATA_TYPE** ARGOUTVIEWM_FARRAY4) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &dim4_temp; + $5 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements,NumPy_Utilities") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEWM_FARRAY4) +{ + npy_intp dims[4] = { *$1, *$2, *$3 , *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$5)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3, DIM_TYPE* DIM4) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_ARRAY4, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; + $5 = &dim4_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_ARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) +{ + npy_intp dims[4] = { *$2, *$3, *$4 , *$5 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, + DATA_TYPE** ARGOUTVIEWM_ARRAY4) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 , DATA_TYPE** ARGOUTVIEWM_ARRAY4) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &dim4_temp; + $5 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Utilities") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEWM_ARRAY4) +{ + npy_intp dims[4] = { *$1, *$2, *$3 , *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$5)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DATA_TYPE** ARGOUTVIEWM_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, + DIM_TYPE* DIM3, DIM_TYPE* DIM4) + */ +%typemap(in,numinputs=0) + (DATA_TYPE** ARGOUTVIEWM_FARRAY4, DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 ) + (DATA_TYPE* data_temp = NULL , DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp) +{ + $1 = &data_temp; + $2 = &dim1_temp; + $3 = &dim2_temp; + $4 = &dim3_temp; + $5 = &dim4_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements,NumPy_Utilities") + (DATA_TYPE** ARGOUTVIEWM_FARRAY4, DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4) +{ + npy_intp dims[4] = { *$2, *$3, *$4 , *$5 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$1)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/* Typemap suite for (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, + DATA_TYPE** ARGOUTVIEWM_FARRAY4) + */ +%typemap(in,numinputs=0) + (DIM_TYPE* DIM1 , DIM_TYPE* DIM2 , DIM_TYPE* DIM3 , DIM_TYPE* DIM4 , DATA_TYPE** ARGOUTVIEWM_FARRAY4) + (DIM_TYPE dim1_temp, DIM_TYPE dim2_temp, DIM_TYPE dim3_temp, DIM_TYPE dim4_temp, DATA_TYPE* data_temp = NULL ) +{ + $1 = &dim1_temp; + $2 = &dim2_temp; + $3 = &dim3_temp; + $4 = &dim4_temp; + $5 = &data_temp; +} +%typemap(argout, + fragment="NumPy_Backward_Compatibility,NumPy_Array_Requirements,NumPy_Utilities") + (DIM_TYPE* DIM1, DIM_TYPE* DIM2, DIM_TYPE* DIM3, DIM_TYPE* DIM4, DATA_TYPE** ARGOUTVIEWM_FARRAY4) +{ + npy_intp dims[4] = { *$1, *$2, *$3 , *$4 }; + PyObject* obj = PyArray_SimpleNewFromData(4, dims, DATA_TYPECODE, (void*)(*$5)); + PyArrayObject* array = (PyArrayObject*) obj; + + if (!array || !require_fortran(array)) SWIG_fail; + +%#ifdef SWIGPY_USE_CAPSULE + PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap); +%#else + PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free); +%#endif + +%#if NPY_API_VERSION < 0x00000007 + PyArray_BASE(array) = cap; +%#else + PyArray_SetBaseObject(array,cap); +%#endif + + $result = SWIG_Python_AppendOutput($result,obj); +} + +/**************************************/ +/* In-Place Array Typemap - flattened */ +/**************************************/ + +/* Typemap suite for (DATA_TYPE* INPLACE_ARRAY_FLAT, DIM_TYPE DIM_FLAT) + */ +%typecheck(SWIG_TYPECHECK_DOUBLE_ARRAY, + fragment="NumPy_Macros") + (DATA_TYPE* INPLACE_ARRAY_FLAT, DIM_TYPE DIM_FLAT) +{ + $1 = is_array($input) && PyArray_EquivTypenums(array_type($input), + DATA_TYPECODE); +} +%typemap(in, + fragment="NumPy_Fragments") + (DATA_TYPE* INPLACE_ARRAY_FLAT, DIM_TYPE DIM_FLAT) + (PyArrayObject* array=NULL, int i=1) +{ + array = obj_to_array_no_conversion($input, DATA_TYPECODE); + if (!array || !require_c_or_f_contiguous(array) + || !require_native(array)) SWIG_fail; + $1 = (DATA_TYPE*) array_data(array); + $2 = 1; + for (i=0; i < array_numdims(array); ++i) $2 *= array_size(array,i); +} + +%enddef /* %numpy_typemaps() macro */ +/* *************************************************************** */ + +/* Concrete instances of the %numpy_typemaps() macro: Each invocation + * below applies all of the typemaps above to the specified data type. + */ +%numpy_typemaps(signed char , NPY_BYTE , int) +%numpy_typemaps(unsigned char , NPY_UBYTE , int) +%numpy_typemaps(short , NPY_SHORT , int) +%numpy_typemaps(unsigned short , NPY_USHORT , int) +%numpy_typemaps(int , NPY_INT , int) +%numpy_typemaps(unsigned int , NPY_UINT , int) +%numpy_typemaps(long , NPY_LONG , int) +%numpy_typemaps(unsigned long , NPY_ULONG , int) +%numpy_typemaps(long long , NPY_LONGLONG , int) +%numpy_typemaps(unsigned long long, NPY_ULONGLONG, int) +%numpy_typemaps(float , NPY_FLOAT , int) +%numpy_typemaps(double , NPY_DOUBLE , int) + +/* *************************************************************** + * The follow macro expansion does not work, because C++ bool is 4 + * bytes and NPY_BOOL is 1 byte + * + * %numpy_typemaps(bool, NPY_BOOL, int) + */ + +/* *************************************************************** + * On my Mac, I get the following warning for this macro expansion: + * 'swig/python detected a memory leak of type 'long double *', no destructor found.' + * + * %numpy_typemaps(long double, NPY_LONGDOUBLE, int) + */ + +#ifdef __cplusplus + +%include + +%numpy_typemaps(std::complex, NPY_CFLOAT , int) +%numpy_typemaps(std::complex, NPY_CDOUBLE, int) + +#endif + +#endif /* SWIGPYTHON */ diff --git a/tools/swig/pyfragments.swg b/tools/swig/pyfragments.swg new file mode 100644 index 0000000..901e6ed --- /dev/null +++ b/tools/swig/pyfragments.swg @@ -0,0 +1,126 @@ +/*-*- C -*-*/ + +/**********************************************************************/ + +/* For numpy versions prior to 1.0, the names of certain data types + * are different than in later versions. This fragment provides macro + * substitutions that allow us to support old and new versions of + * numpy. + */ + +/**********************************************************************/ + +/* Override the SWIG_AsVal_frag(long) fragment so that it also checks + * for numpy scalar array types. The code through the %#endif is + * essentially cut-and-paste from pyprimtype.swg + */ + +%fragment(SWIG_AsVal_frag(long), "header", + fragment="SWIG_CanCastAsInteger", + fragment="NumPy_Backward_Compatibility") +{ + SWIGINTERN int + SWIG_AsVal_dec(long)(PyObject * obj, long * val) + { + PyArray_Descr * longDescr = PyArray_DescrNewFromType(NPY_LONG); + if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +%#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + long v = PyInt_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal(double)(obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { + if (val) *val = (long)(d); + return res; + } + } + } +%#endif + if (!PyArray_IsScalar(obj,Integer)) return SWIG_TypeError; + PyArray_CastScalarToCtype(obj, (void*)val, longDescr); + return SWIG_OK; + } +} + + +/* Override the SWIG_AsVal_frag(unsigned long) fragment so that it + * also checks for numpy scalar array types. The code through the + * %#endif is essentially cut-and-paste from pyprimtype.swg + */ + +%fragment(SWIG_AsVal_frag(unsigned long),"header", + fragment="SWIG_CanCastAsInteger", + fragment="NumPy_Backward_Compatibility") +{ + SWIGINTERN int + SWIG_AsVal_dec(unsigned long)(PyObject *obj, unsigned long *val) + { + PyArray_Descr * ulongDescr = PyArray_DescrNewFromType(NPY_ULONG); + %#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(obj)) + { + long v = PyInt_AsLong(obj); + if (v >= 0) + { + if (val) *val = v; + return SWIG_OK; + } + else + { + return SWIG_OverflowError; + } + } else + %#endif + if (PyLong_Check(obj)) { + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +%#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal(double)(obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { + if (val) *val = (unsigned long)(d); + return res; + } + } + } +%#endif + if (!PyArray_IsScalar(obj,Integer)) return SWIG_TypeError; + PyArray_CastScalarToCtype(obj, (void*)val, ulongDescr); + return SWIG_OK; + } +} diff --git a/tools/swig/test/Array.i b/tools/swig/test/Array.i new file mode 100644 index 0000000..64ae57e --- /dev/null +++ b/tools/swig/test/Array.i @@ -0,0 +1,135 @@ +// -*- c++ -*- + +%module Array + +%{ +#define SWIG_FILE_WITH_INIT +#include "Array1.h" +#include "Array2.h" +#include "ArrayZ.h" +%} + +// Get the NumPy typemaps +%include "../numpy.i" + + // Get the STL typemaps +%include "stl.i" + +// Handle standard exceptions +%include "exception.i" +%exception +{ + try + { + $action + } + catch (const std::invalid_argument& e) + { + SWIG_exception(SWIG_ValueError, e.what()); + } + catch (const std::out_of_range& e) + { + SWIG_exception(SWIG_IndexError, e.what()); + } +} +%init %{ + import_array(); +%} + +// Global ignores +%ignore *::operator=; +%ignore *::operator[]; + +// Apply the 1D NumPy typemaps +%apply (int DIM1 , long* INPLACE_ARRAY1) + {(int length, long* data )}; +%apply (long** ARGOUTVIEW_ARRAY1, int* DIM1 ) + {(long** data , int* length)}; + +// Apply the 2D NumPy typemaps +%apply (int DIM1 , int DIM2 , long* INPLACE_ARRAY2) + {(int nrows, int ncols, long* data )}; +%apply (int* DIM1 , int* DIM2 , long** ARGOUTVIEW_ARRAY2) + {(int* nrows, int* ncols, long** data )}; + +// Apply the 1D NumPy typemaps +%apply (int DIM1 , std::complex* INPLACE_ARRAY1) + {(int length, std::complex* data )}; +%apply (std::complex** ARGOUTVIEW_ARRAY1, int* DIM1 ) + {(std::complex** data , int* length)}; + +// Array1 support +%include "Array1.h" +%extend Array1 +{ + void __setitem__(int i, long v) + { + self->operator[](i) = v; + } + + long __getitem__(int i) + { + return self->operator[](i); + } + + int __len__() + { + return self->length(); + } + + std::string __str__() + { + return self->asString(); + } +} + +// Array2 support +%include "Array2.h" +%extend Array2 +{ + void __setitem__(int i, Array1 & v) + { + self->operator[](i) = v; + } + + Array1 & __getitem__(int i) + { + return self->operator[](i); + } + + int __len__() + { + return self->nrows() * self->ncols(); + } + + std::string __str__() + { + return self->asString(); + } +} + +// ArrayZ support +%include "ArrayZ.h" +%extend ArrayZ +{ + void __setitem__(int i, std::complex v) + { + self->operator[](i) = v; + } + + std::complex __getitem__(int i) + { + return self->operator[](i); + } + + int __len__() + { + return self->length(); + } + + std::string __str__() + { + return self->asString(); + } +} + diff --git a/tools/swig/test/Array1.cxx b/tools/swig/test/Array1.cxx new file mode 100644 index 0000000..0c09e02 --- /dev/null +++ b/tools/swig/test/Array1.cxx @@ -0,0 +1,131 @@ +#include "Array1.h" +#include +#include + +// Default/length/array constructor +Array1::Array1(int length, long* data) : + _ownData(false), _length(0), _buffer(0) +{ + resize(length, data); +} + +// Copy constructor +Array1::Array1(const Array1 & source) : + _length(source._length) +{ + allocateMemory(); + *this = source; +} + +// Destructor +Array1::~Array1() +{ + deallocateMemory(); +} + +// Assignment operator +Array1 & Array1::operator=(const Array1 & source) +{ + int len = _length < source._length ? _length : source._length; + for (int i=0; i < len; ++i) + { + (*this)[i] = source[i]; + } + return *this; +} + +// Equals operator +bool Array1::operator==(const Array1 & other) const +{ + if (_length != other._length) return false; + for (int i=0; i < _length; ++i) + { + if ((*this)[i] != other[i]) return false; + } + return true; +} + +// Length accessor +int Array1::length() const +{ + return _length; +} + +// Resize array +void Array1::resize(int length, long* data) +{ + if (length < 0) throw std::invalid_argument("Array1 length less than 0"); + if (length == _length) return; + deallocateMemory(); + _length = length; + if (!data) + { + allocateMemory(); + } + else + { + _ownData = false; + _buffer = data; + } +} + +// Set item accessor +long & Array1::operator[](int i) +{ + if (i < 0 || i >= _length) throw std::out_of_range("Array1 index out of range"); + return _buffer[i]; +} + +// Get item accessor +const long & Array1::operator[](int i) const +{ + if (i < 0 || i >= _length) throw std::out_of_range("Array1 index out of range"); + return _buffer[i]; +} + +// String output +std::string Array1::asString() const +{ + std::stringstream result; + result << "["; + for (int i=0; i < _length; ++i) + { + result << " " << _buffer[i]; + if (i < _length-1) result << ","; + } + result << " ]"; + return result.str(); +} + +// Get view +void Array1::view(long** data, int* length) const +{ + *data = _buffer; + *length = _length; +} + +// Private methods + void Array1::allocateMemory() + { + if (_length == 0) + { + _ownData = false; + _buffer = 0; + } + else + { + _ownData = true; + _buffer = new long[_length]; + } + } + + void Array1::deallocateMemory() + { + if (_ownData && _length && _buffer) + { + delete [] _buffer; + } + _ownData = false; + _length = 0; + _buffer = 0; + } diff --git a/tools/swig/test/Array1.h b/tools/swig/test/Array1.h new file mode 100644 index 0000000..754c248 --- /dev/null +++ b/tools/swig/test/Array1.h @@ -0,0 +1,55 @@ +#ifndef ARRAY1_H +#define ARRAY1_H + +#include +#include + +class Array1 +{ +public: + + // Default/length/array constructor + Array1(int length = 0, long* data = 0); + + // Copy constructor + Array1(const Array1 & source); + + // Destructor + ~Array1(); + + // Assignment operator + Array1 & operator=(const Array1 & source); + + // Equals operator + bool operator==(const Array1 & other) const; + + // Length accessor + int length() const; + + // Resize array + void resize(int length, long* data = 0); + + // Set item accessor + long & operator[](int i); + + // Get item accessor + const long & operator[](int i) const; + + // String output + std::string asString() const; + + // Get view + void view(long** data, int* length) const; + +private: + // Members + bool _ownData; + int _length; + long * _buffer; + + // Methods + void allocateMemory(); + void deallocateMemory(); +}; + +#endif diff --git a/tools/swig/test/Array2.cxx b/tools/swig/test/Array2.cxx new file mode 100644 index 0000000..e3558f7 --- /dev/null +++ b/tools/swig/test/Array2.cxx @@ -0,0 +1,168 @@ +#include "Array2.h" +#include + +// Default constructor +Array2::Array2() : + _ownData(false), _nrows(0), _ncols(), _buffer(0), _rows(0) +{ } + +// Size/array constructor +Array2::Array2(int nrows, int ncols, long* data) : + _ownData(false), _nrows(0), _ncols(), _buffer(0), _rows(0) +{ + resize(nrows, ncols, data); +} + +// Copy constructor +Array2::Array2(const Array2 & source) : + _nrows(source._nrows), _ncols(source._ncols) +{ + _ownData = true; + allocateMemory(); + *this = source; +} + +// Destructor +Array2::~Array2() +{ + deallocateMemory(); +} + +// Assignment operator +Array2 & Array2::operator=(const Array2 & source) +{ + int nrows = _nrows < source._nrows ? _nrows : source._nrows; + int ncols = _ncols < source._ncols ? _ncols : source._ncols; + for (int i=0; i < nrows; ++i) + { + for (int j=0; j < ncols; ++j) + { + (*this)[i][j] = source[i][j]; + } + } + return *this; +} + +// Equals operator +bool Array2::operator==(const Array2 & other) const +{ + if (_nrows != other._nrows) return false; + if (_ncols != other._ncols) return false; + for (int i=0; i < _nrows; ++i) + { + for (int j=0; j < _ncols; ++j) + { + if ((*this)[i][j] != other[i][j]) return false; + } + } + return true; +} + +// Length accessors +int Array2::nrows() const +{ + return _nrows; +} + +int Array2::ncols() const +{ + return _ncols; +} + +// Resize array +void Array2::resize(int nrows, int ncols, long* data) +{ + if (nrows < 0) throw std::invalid_argument("Array2 nrows less than 0"); + if (ncols < 0) throw std::invalid_argument("Array2 ncols less than 0"); + if (nrows == _nrows && ncols == _ncols) return; + deallocateMemory(); + _nrows = nrows; + _ncols = ncols; + if (!data) + { + allocateMemory(); + } + else + { + _ownData = false; + _buffer = data; + allocateRows(); + } +} + +// Set item accessor +Array1 & Array2::operator[](int i) +{ + if (i < 0 || i > _nrows) throw std::out_of_range("Array2 row index out of range"); + return _rows[i]; +} + +// Get item accessor +const Array1 & Array2::operator[](int i) const +{ + if (i < 0 || i > _nrows) throw std::out_of_range("Array2 row index out of range"); + return _rows[i]; +} + +// String output +std::string Array2::asString() const +{ + std::stringstream result; + result << "[ "; + for (int i=0; i < _nrows; ++i) + { + if (i > 0) result << " "; + result << (*this)[i].asString(); + if (i < _nrows-1) result << "," << std::endl; + } + result << " ]" << std::endl; + return result.str(); +} + +// Get view +void Array2::view(int* nrows, int* ncols, long** data) const +{ + *nrows = _nrows; + *ncols = _ncols; + *data = _buffer; +} + +// Private methods +void Array2::allocateMemory() +{ + if (_nrows * _ncols == 0) + { + _ownData = false; + _buffer = 0; + _rows = 0; + } + else + { + _ownData = true; + _buffer = new long[_nrows*_ncols]; + allocateRows(); + } +} + +void Array2::allocateRows() +{ + _rows = new Array1[_nrows]; + for (int i=0; i < _nrows; ++i) + { + _rows[i].resize(_ncols, &_buffer[i*_ncols]); + } +} + +void Array2::deallocateMemory() +{ + if (_ownData && _nrows*_ncols && _buffer) + { + delete [] _rows; + delete [] _buffer; + } + _ownData = false; + _nrows = 0; + _ncols = 0; + _buffer = 0; + _rows = 0; +} diff --git a/tools/swig/test/Array2.h b/tools/swig/test/Array2.h new file mode 100644 index 0000000..7f8d4ca --- /dev/null +++ b/tools/swig/test/Array2.h @@ -0,0 +1,63 @@ +#ifndef ARRAY2_H +#define ARRAY2_H + +#include "Array1.h" +#include +#include + +class Array2 +{ +public: + + // Default constructor + Array2(); + + // Size/array constructor + Array2(int nrows, int ncols, long* data=0); + + // Copy constructor + Array2(const Array2 & source); + + // Destructor + ~Array2(); + + // Assignment operator + Array2 & operator=(const Array2 & source); + + // Equals operator + bool operator==(const Array2 & other) const; + + // Length accessors + int nrows() const; + int ncols() const; + + // Resize array + void resize(int nrows, int ncols, long* data=0); + + // Set item accessor + Array1 & operator[](int i); + + // Get item accessor + const Array1 & operator[](int i) const; + + // String output + std::string asString() const; + + // Get view + void view(int* nrows, int* ncols, long** data) const; + +private: + // Members + bool _ownData; + int _nrows; + int _ncols; + long * _buffer; + Array1 * _rows; + + // Methods + void allocateMemory(); + void allocateRows(); + void deallocateMemory(); +}; + +#endif diff --git a/tools/swig/test/ArrayZ.cxx b/tools/swig/test/ArrayZ.cxx new file mode 100644 index 0000000..4756c69 --- /dev/null +++ b/tools/swig/test/ArrayZ.cxx @@ -0,0 +1,131 @@ +#include "ArrayZ.h" +#include +#include + +// Default/length/array constructor +ArrayZ::ArrayZ(int length, std::complex* data) : + _ownData(false), _length(0), _buffer(0) +{ + resize(length, data); +} + +// Copy constructor +ArrayZ::ArrayZ(const ArrayZ & source) : + _length(source._length) +{ + allocateMemory(); + *this = source; +} + +// Destructor +ArrayZ::~ArrayZ() +{ + deallocateMemory(); +} + +// Assignment operator +ArrayZ & ArrayZ::operator=(const ArrayZ & source) +{ + int len = _length < source._length ? _length : source._length; + for (int i=0; i < len; ++i) + { + (*this)[i] = source[i]; + } + return *this; +} + +// Equals operator +bool ArrayZ::operator==(const ArrayZ & other) const +{ + if (_length != other._length) return false; + for (int i=0; i < _length; ++i) + { + if ((*this)[i] != other[i]) return false; + } + return true; +} + +// Length accessor +int ArrayZ::length() const +{ + return _length; +} + +// Resize array +void ArrayZ::resize(int length, std::complex* data) +{ + if (length < 0) throw std::invalid_argument("ArrayZ length less than 0"); + if (length == _length) return; + deallocateMemory(); + _length = length; + if (!data) + { + allocateMemory(); + } + else + { + _ownData = false; + _buffer = data; + } +} + +// Set item accessor +std::complex & ArrayZ::operator[](int i) +{ + if (i < 0 || i >= _length) throw std::out_of_range("ArrayZ index out of range"); + return _buffer[i]; +} + +// Get item accessor +const std::complex & ArrayZ::operator[](int i) const +{ + if (i < 0 || i >= _length) throw std::out_of_range("ArrayZ index out of range"); + return _buffer[i]; +} + +// String output +std::string ArrayZ::asString() const +{ + std::stringstream result; + result << "["; + for (int i=0; i < _length; ++i) + { + result << " " << _buffer[i]; + if (i < _length-1) result << ","; + } + result << " ]"; + return result.str(); +} + +// Get view +void ArrayZ::view(std::complex** data, int* length) const +{ + *data = _buffer; + *length = _length; +} + +// Private methods + void ArrayZ::allocateMemory() + { + if (_length == 0) + { + _ownData = false; + _buffer = 0; + } + else + { + _ownData = true; + _buffer = new std::complex[_length]; + } + } + + void ArrayZ::deallocateMemory() + { + if (_ownData && _length && _buffer) + { + delete [] _buffer; + } + _ownData = false; + _length = 0; + _buffer = 0; + } diff --git a/tools/swig/test/ArrayZ.h b/tools/swig/test/ArrayZ.h new file mode 100644 index 0000000..75abae0 --- /dev/null +++ b/tools/swig/test/ArrayZ.h @@ -0,0 +1,56 @@ +#ifndef ARRAYZ_H +#define ARRAYZ_H + +#include +#include +#include + +class ArrayZ +{ +public: + + // Default/length/array constructor + ArrayZ(int length = 0, std::complex* data = 0); + + // Copy constructor + ArrayZ(const ArrayZ & source); + + // Destructor + ~ArrayZ(); + + // Assignment operator + ArrayZ & operator=(const ArrayZ & source); + + // Equals operator + bool operator==(const ArrayZ & other) const; + + // Length accessor + int length() const; + + // Resize array + void resize(int length, std::complex* data = 0); + + // Set item accessor + std::complex & operator[](int i); + + // Get item accessor + const std::complex & operator[](int i) const; + + // String output + std::string asString() const; + + // Get view + void view(std::complex** data, int* length) const; + +private: + // Members + bool _ownData; + int _length; + std::complex * _buffer; + + // Methods + void allocateMemory(); + void deallocateMemory(); +}; + +#endif diff --git a/tools/swig/test/Farray.cxx b/tools/swig/test/Farray.cxx new file mode 100644 index 0000000..3983c33 --- /dev/null +++ b/tools/swig/test/Farray.cxx @@ -0,0 +1,122 @@ +#include "Farray.h" +#include + +// Size constructor +Farray::Farray(int nrows, int ncols) : + _nrows(nrows), _ncols(ncols), _buffer(0) +{ + allocateMemory(); +} + +// Copy constructor +Farray::Farray(const Farray & source) : + _nrows(source._nrows), _ncols(source._ncols) +{ + allocateMemory(); + *this = source; +} + +// Destructor +Farray::~Farray() +{ + delete [] _buffer; +} + +// Assignment operator +Farray & Farray::operator=(const Farray & source) +{ + int nrows = _nrows < source._nrows ? _nrows : source._nrows; + int ncols = _ncols < source._ncols ? _ncols : source._ncols; + for (int i=0; i < nrows; ++i) + { + for (int j=0; j < ncols; ++j) + { + (*this)(i,j) = source(i,j); + } + } + return *this; +} + +// Equals operator +bool Farray::operator==(const Farray & other) const +{ + if (_nrows != other._nrows) return false; + if (_ncols != other._ncols) return false; + for (int i=0; i < _nrows; ++i) + { + for (int j=0; j < _ncols; ++j) + { + if ((*this)(i,j) != other(i,j)) return false; + } + } + return true; +} + +// Length accessors +int Farray::nrows() const +{ + return _nrows; +} + +int Farray::ncols() const +{ + return _ncols; +} + +// Set item accessor +long & Farray::operator()(int i, int j) +{ + if (i < 0 || i > _nrows) throw std::out_of_range("Farray row index out of range"); + if (j < 0 || j > _ncols) throw std::out_of_range("Farray col index out of range"); + return _buffer[offset(i,j)]; +} + +// Get item accessor +const long & Farray::operator()(int i, int j) const +{ + if (i < 0 || i > _nrows) throw std::out_of_range("Farray row index out of range"); + if (j < 0 || j > _ncols) throw std::out_of_range("Farray col index out of range"); + return _buffer[offset(i,j)]; +} + +// String output +std::string Farray::asString() const +{ + std::stringstream result; + result << "[ "; + for (int i=0; i < _nrows; ++i) + { + if (i > 0) result << " "; + result << "["; + for (int j=0; j < _ncols; ++j) + { + result << " " << (*this)(i,j); + if (j < _ncols-1) result << ","; + } + result << " ]"; + if (i < _nrows-1) result << "," << std::endl; + } + result << " ]" << std::endl; + return result.str(); +} + +// Get view +void Farray::view(int* nrows, int* ncols, long** data) const +{ + *nrows = _nrows; + *ncols = _ncols; + *data = _buffer; +} + +// Private methods +void Farray::allocateMemory() +{ + if (_nrows <= 0) throw std::invalid_argument("Farray nrows <= 0"); + if (_ncols <= 0) throw std::invalid_argument("Farray ncols <= 0"); + _buffer = new long[_nrows*_ncols]; +} + +inline int Farray::offset(int i, int j) const +{ + return i + j * _nrows; +} diff --git a/tools/swig/test/Farray.h b/tools/swig/test/Farray.h new file mode 100644 index 0000000..4199a28 --- /dev/null +++ b/tools/swig/test/Farray.h @@ -0,0 +1,56 @@ +#ifndef FARRAY_H +#define FARRAY_H + +#include +#include + +class Farray +{ +public: + + // Size constructor + Farray(int nrows, int ncols); + + // Copy constructor + Farray(const Farray & source); + + // Destructor + ~Farray(); + + // Assignment operator + Farray & operator=(const Farray & source); + + // Equals operator + bool operator==(const Farray & other) const; + + // Length accessors + int nrows() const; + int ncols() const; + + // Set item accessor + long & operator()(int i, int j); + + // Get item accessor + const long & operator()(int i, int j) const; + + // String output + std::string asString() const; + + // Get view + void view(int* nrows, int* ncols, long** data) const; + +private: + // Members + int _nrows; + int _ncols; + long * _buffer; + + // Default constructor: not implemented + Farray(); + + // Methods + void allocateMemory(); + int offset(int i, int j) const; +}; + +#endif diff --git a/tools/swig/test/Farray.i b/tools/swig/test/Farray.i new file mode 100644 index 0000000..25f6cd0 --- /dev/null +++ b/tools/swig/test/Farray.i @@ -0,0 +1,73 @@ +// -*- c++ -*- + +%module Farray + +%{ +#define SWIG_FILE_WITH_INIT +#include "Farray.h" +%} + +// Get the NumPy typemaps +%include "../numpy.i" + + // Get the STL typemaps +%include "stl.i" + +// Handle standard exceptions +%include "exception.i" +%exception +{ + try + { + $action + } + catch (const std::invalid_argument& e) + { + SWIG_exception(SWIG_ValueError, e.what()); + } + catch (const std::out_of_range& e) + { + SWIG_exception(SWIG_IndexError, e.what()); + } +} +%init %{ + import_array(); +%} + +// Global ignores +%ignore *::operator=; +%ignore *::operator(); + +// Apply the 2D NumPy typemaps +%apply (int* DIM1 , int* DIM2 , long** ARGOUTVIEW_FARRAY2) + {(int* nrows, int* ncols, long** data )}; + +// Farray support +%include "Farray.h" +%extend Farray +{ + PyObject * __setitem__(PyObject* index, long v) + { + int i, j; + if (!PyArg_ParseTuple(index, "ii:Farray___setitem__",&i,&j)) return NULL; + self->operator()(i,j) = v; + return Py_BuildValue(""); + } + + PyObject * __getitem__(PyObject * index) + { + int i, j; + if (!PyArg_ParseTuple(index, "ii:Farray___getitem__",&i,&j)) return NULL; + return SWIG_From_long(self->operator()(i,j)); + } + + int __len__() + { + return self->nrows() * self->ncols(); + } + + std::string __str__() + { + return self->asString(); + } +} diff --git a/tools/swig/test/Flat.cxx b/tools/swig/test/Flat.cxx new file mode 100644 index 0000000..1a7f42b --- /dev/null +++ b/tools/swig/test/Flat.cxx @@ -0,0 +1,36 @@ +#include +#include +#include +#include "Flat.h" + +// The following macro defines a family of functions that work with 1D +// arrays with the forms +// +// void SNAMEProcess(TYPE * array, int size); +// +// for any specified type TYPE (for example: short, unsigned int, long +// long, etc.) with given short name SNAME (for example: short, uint, +// longLong, etc.). The macro is then expanded for the given +// TYPE/SNAME pairs. The resulting functions are for testing numpy +// interfaces for: +// +// * in-place arrays (arbitrary number of dimensions) with a fixed number of elements +// +#define TEST_FUNCS(TYPE, SNAME) \ +\ +void SNAME ## Process(TYPE * array, int size) { \ + for (int i=0; i +#include +#include +#include "Fortran.h" + +#define TEST_FUNCS(TYPE, SNAME) \ +\ +TYPE SNAME ## SecondElement(TYPE * matrix, int rows, int cols) { \ + TYPE result = matrix[1]; \ + return result; \ +} \ + +TEST_FUNCS(signed char , schar ) +TEST_FUNCS(unsigned char , uchar ) +TEST_FUNCS(short , short ) +TEST_FUNCS(unsigned short , ushort ) +TEST_FUNCS(int , int ) +TEST_FUNCS(unsigned int , uint ) +TEST_FUNCS(long , long ) +TEST_FUNCS(unsigned long , ulong ) +TEST_FUNCS(long long , longLong ) +TEST_FUNCS(unsigned long long, ulongLong) +TEST_FUNCS(float , float ) +TEST_FUNCS(double , double ) diff --git a/tools/swig/test/Fortran.h b/tools/swig/test/Fortran.h new file mode 100644 index 0000000..c243bb5 --- /dev/null +++ b/tools/swig/test/Fortran.h @@ -0,0 +1,21 @@ +#ifndef FORTRAN_H +#define FORTRAN_H + +#define TEST_FUNC_PROTOS(TYPE, SNAME) \ +\ +TYPE SNAME ## SecondElement( TYPE * matrix, int rows, int cols); \ + +TEST_FUNC_PROTOS(signed char , schar ) +TEST_FUNC_PROTOS(unsigned char , uchar ) +TEST_FUNC_PROTOS(short , short ) +TEST_FUNC_PROTOS(unsigned short , ushort ) +TEST_FUNC_PROTOS(int , int ) +TEST_FUNC_PROTOS(unsigned int , uint ) +TEST_FUNC_PROTOS(long , long ) +TEST_FUNC_PROTOS(unsigned long , ulong ) +TEST_FUNC_PROTOS(long long , longLong ) +TEST_FUNC_PROTOS(unsigned long long, ulongLong) +TEST_FUNC_PROTOS(float , float ) +TEST_FUNC_PROTOS(double , double ) + +#endif diff --git a/tools/swig/test/Fortran.i b/tools/swig/test/Fortran.i new file mode 100644 index 0000000..131790d --- /dev/null +++ b/tools/swig/test/Fortran.i @@ -0,0 +1,36 @@ +// -*- c++ -*- +%module Fortran + +%{ +#define SWIG_FILE_WITH_INIT +#include "Fortran.h" +%} + +// Get the NumPy typemaps +%include "../numpy.i" + +%init %{ + import_array(); +%} + +%define %apply_numpy_typemaps(TYPE) + +%apply (TYPE* IN_FARRAY2, int DIM1, int DIM2) {(TYPE* matrix, int rows, int cols)}; + +%enddef /* %apply_numpy_typemaps() macro */ + +%apply_numpy_typemaps(signed char ) +%apply_numpy_typemaps(unsigned char ) +%apply_numpy_typemaps(short ) +%apply_numpy_typemaps(unsigned short ) +%apply_numpy_typemaps(int ) +%apply_numpy_typemaps(unsigned int ) +%apply_numpy_typemaps(long ) +%apply_numpy_typemaps(unsigned long ) +%apply_numpy_typemaps(long long ) +%apply_numpy_typemaps(unsigned long long) +%apply_numpy_typemaps(float ) +%apply_numpy_typemaps(double ) + +// Include the header file to be wrapped +%include "Fortran.h" diff --git a/tools/swig/test/Makefile b/tools/swig/test/Makefile new file mode 100644 index 0000000..a01ac40 --- /dev/null +++ b/tools/swig/test/Makefile @@ -0,0 +1,37 @@ +# SWIG +INTERFACES = Array.i Farray.i Vector.i Matrix.i Tensor.i Fortran.i Flat.i +WRAPPERS = $(INTERFACES:.i=_wrap.cxx) +PROXIES = $(INTERFACES:.i=.py ) + +# Default target: build the tests +.PHONY : all +all: $(WRAPPERS) Array1.cxx Array1.h Array2.cxx Array2.h ArrayZ.cxx ArrayZ.h \ + Farray.cxx Farray.h Vector.cxx Vector.h \ + Matrix.cxx Matrix.h Tensor.cxx Tensor.h Fortran.h Fortran.cxx \ + Flat.h Flat.cxx + ./setup.py build_ext -i + +# Test target: run the tests +.PHONY : test +test: all + python testVector.py + python testMatrix.py + python testTensor.py + python testArray.py + python testFarray.py + python testFortran.py + python testFlat.py + +# Rule: %.i -> %_wrap.cxx +%_wrap.cxx: %.i %.h ../numpy.i + swig -c++ -python $< +%_wrap.cxx: %.i %1.h %2.h ../numpy.i + swig -c++ -python $< + +# Clean target +.PHONY : clean +clean: + $(RM) -r build + $(RM) *.so + $(RM) $(WRAPPERS) + $(RM) $(PROXIES) diff --git a/tools/swig/test/Matrix.cxx b/tools/swig/test/Matrix.cxx new file mode 100644 index 0000000..b953d70 --- /dev/null +++ b/tools/swig/test/Matrix.cxx @@ -0,0 +1,112 @@ +#include +#include +#include +#include "Matrix.h" + +// The following macro defines a family of functions that work with 2D +// arrays with the forms +// +// TYPE SNAMEDet( TYPE matrix[2][2]); +// TYPE SNAMEMax( TYPE * matrix, int rows, int cols); +// TYPE SNAMEMin( int rows, int cols, TYPE * matrix); +// void SNAMEScale( TYPE matrix[3][3]); +// void SNAMEFloor( TYPE * array, int rows, int cols, TYPE floor); +// void SNAMECeil( int rows, int cols, TYPE * array, TYPE ceil); +// void SNAMELUSplit(TYPE in[3][3], TYPE lower[3][3], TYPE upper[3][3]); +// +// for any specified type TYPE (for example: short, unsigned int, long +// long, etc.) with given short name SNAME (for example: short, uint, +// longLong, etc.). The macro is then expanded for the given +// TYPE/SNAME pairs. The resulting functions are for testing numpy +// interfaces, respectively, for: +// +// * 2D input arrays, hard-coded length +// * 2D input arrays +// * 2D input arrays, data last +// * 2D in-place arrays, hard-coded lengths +// * 2D in-place arrays +// * 2D in-place arrays, data last +// * 2D argout arrays, hard-coded length +// +#define TEST_FUNCS(TYPE, SNAME) \ +\ +TYPE SNAME ## Det(TYPE matrix[2][2]) { \ + return matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]; \ +} \ +\ +TYPE SNAME ## Max(TYPE * matrix, int rows, int cols) { \ + int i, j, index; \ + TYPE result = matrix[0]; \ + for (j=0; j result) result = matrix[index]; \ + } \ + } \ + return result; \ +} \ +\ +TYPE SNAME ## Min(int rows, int cols, TYPE * matrix) { \ + int i, j, index; \ + TYPE result = matrix[0]; \ + for (j=0; j ceil) array[index] = ceil; \ + } \ + } \ +} \ +\ +void SNAME ## LUSplit(TYPE matrix[3][3], TYPE lower[3][3], TYPE upper[3][3]) { \ + for (int i=0; i<3; ++i) { \ + for (int j=0; j<3; ++j) { \ + if (i >= j) { \ + lower[i][j] = matrix[i][j]; \ + upper[i][j] = 0; \ + } else { \ + lower[i][j] = 0; \ + upper[i][j] = matrix[i][j]; \ + } \ + } \ + } \ +} + +TEST_FUNCS(signed char , schar ) +TEST_FUNCS(unsigned char , uchar ) +TEST_FUNCS(short , short ) +TEST_FUNCS(unsigned short , ushort ) +TEST_FUNCS(int , int ) +TEST_FUNCS(unsigned int , uint ) +TEST_FUNCS(long , long ) +TEST_FUNCS(unsigned long , ulong ) +TEST_FUNCS(long long , longLong ) +TEST_FUNCS(unsigned long long, ulongLong) +TEST_FUNCS(float , float ) +TEST_FUNCS(double , double ) diff --git a/tools/swig/test/Matrix.h b/tools/swig/test/Matrix.h new file mode 100644 index 0000000..f37836c --- /dev/null +++ b/tools/swig/test/Matrix.h @@ -0,0 +1,52 @@ +#ifndef MATRIX_H +#define MATRIX_H + +// The following macro defines the prototypes for a family of +// functions that work with 2D arrays with the forms +// +// TYPE SNAMEDet( TYPE matrix[2][2]); +// TYPE SNAMEMax( TYPE * matrix, int rows, int cols); +// TYPE SNAMEMin( int rows, int cols, TYPE * matrix); +// void SNAMEScale( TYPE array[3][3]); +// void SNAMEFloor( TYPE * array, int rows, int cols, TYPE floor); +// void SNAMECeil( int rows, int cols, TYPE * array, TYPE ceil ); +// void SNAMELUSplit(TYPE in[3][3], TYPE lower[3][3], TYPE upper[3][3]); +// +// for any specified type TYPE (for example: short, unsigned int, long +// long, etc.) with given short name SNAME (for example: short, uint, +// longLong, etc.). The macro is then expanded for the given +// TYPE/SNAME pairs. The resulting functions are for testing numpy +// interfaces, respectively, for: +// +// * 2D input arrays, hard-coded lengths +// * 2D input arrays +// * 2D input arrays, data last +// * 2D in-place arrays, hard-coded lengths +// * 2D in-place arrays +// * 2D in-place arrays, data last +// * 2D argout arrays, hard-coded length +// +#define TEST_FUNC_PROTOS(TYPE, SNAME) \ +\ +TYPE SNAME ## Det( TYPE matrix[2][2]); \ +TYPE SNAME ## Max( TYPE * matrix, int rows, int cols); \ +TYPE SNAME ## Min( int rows, int cols, TYPE * matrix); \ +void SNAME ## Scale( TYPE array[3][3], TYPE val); \ +void SNAME ## Floor( TYPE * array, int rows, int cols, TYPE floor); \ +void SNAME ## Ceil( int rows, int cols, TYPE * array, TYPE ceil ); \ +void SNAME ## LUSplit(TYPE matrix[3][3], TYPE lower[3][3], TYPE upper[3][3]); + +TEST_FUNC_PROTOS(signed char , schar ) +TEST_FUNC_PROTOS(unsigned char , uchar ) +TEST_FUNC_PROTOS(short , short ) +TEST_FUNC_PROTOS(unsigned short , ushort ) +TEST_FUNC_PROTOS(int , int ) +TEST_FUNC_PROTOS(unsigned int , uint ) +TEST_FUNC_PROTOS(long , long ) +TEST_FUNC_PROTOS(unsigned long , ulong ) +TEST_FUNC_PROTOS(long long , longLong ) +TEST_FUNC_PROTOS(unsigned long long, ulongLong) +TEST_FUNC_PROTOS(float , float ) +TEST_FUNC_PROTOS(double , double ) + +#endif diff --git a/tools/swig/test/Matrix.i b/tools/swig/test/Matrix.i new file mode 100644 index 0000000..e721397 --- /dev/null +++ b/tools/swig/test/Matrix.i @@ -0,0 +1,45 @@ +// -*- c++ -*- +%module Matrix + +%{ +#define SWIG_FILE_WITH_INIT +#include "Matrix.h" +%} + +// Get the NumPy typemaps +%include "../numpy.i" + +%init %{ + import_array(); +%} + +%define %apply_numpy_typemaps(TYPE) + +%apply (TYPE IN_ARRAY2[ANY][ANY]) {(TYPE matrix[ANY][ANY])}; +%apply (TYPE* IN_ARRAY2, int DIM1, int DIM2) {(TYPE* matrix, int rows, int cols)}; +%apply (int DIM1, int DIM2, TYPE* IN_ARRAY2) {(int rows, int cols, TYPE* matrix)}; + +%apply (TYPE INPLACE_ARRAY2[ANY][ANY]) {(TYPE array[3][3])}; +%apply (TYPE* INPLACE_ARRAY2, int DIM1, int DIM2) {(TYPE* array, int rows, int cols)}; +%apply (int DIM1, int DIM2, TYPE* INPLACE_ARRAY2) {(int rows, int cols, TYPE* array)}; + +%apply (TYPE ARGOUT_ARRAY2[ANY][ANY]) {(TYPE lower[3][3])}; +%apply (TYPE ARGOUT_ARRAY2[ANY][ANY]) {(TYPE upper[3][3])}; + +%enddef /* %apply_numpy_typemaps() macro */ + +%apply_numpy_typemaps(signed char ) +%apply_numpy_typemaps(unsigned char ) +%apply_numpy_typemaps(short ) +%apply_numpy_typemaps(unsigned short ) +%apply_numpy_typemaps(int ) +%apply_numpy_typemaps(unsigned int ) +%apply_numpy_typemaps(long ) +%apply_numpy_typemaps(unsigned long ) +%apply_numpy_typemaps(long long ) +%apply_numpy_typemaps(unsigned long long) +%apply_numpy_typemaps(float ) +%apply_numpy_typemaps(double ) + +// Include the header file to be wrapped +%include "Matrix.h" diff --git a/tools/swig/test/SuperTensor.cxx b/tools/swig/test/SuperTensor.cxx new file mode 100644 index 0000000..82e8a4b --- /dev/null +++ b/tools/swig/test/SuperTensor.cxx @@ -0,0 +1,144 @@ +#include +#include +#include +#include "SuperTensor.h" + +// The following macro defines a family of functions that work with 3D +// arrays with the forms +// +// TYPE SNAMENorm( TYPE supertensor[2][2][2][2]); +// TYPE SNAMEMax( TYPE * supertensor, int cubes, int slices, int rows, int cols); +// TYPE SNAMEMin( int cubes, int slices, int rows, int cols, TYPE * supertensor); +// void SNAMEScale( TYPE supertensor[3][3][3][3]); +// void SNAMEFloor( TYPE * array, int cubes, int slices, int rows, int cols, TYPE floor); +// void SNAMECeil( int slices, int cubes, int slices, int rows, int cols, TYPE * array, TYPE ceil); +// void SNAMELUSplit(TYPE in[2][2][2][2], TYPE lower[2][2][2][2], TYPE upper[2][2][2][2]); +// +// for any specified type TYPE (for example: short, unsigned int, long +// long, etc.) with given short name SNAME (for example: short, uint, +// longLong, etc.). The macro is then expanded for the given +// TYPE/SNAME pairs. The resulting functions are for testing numpy +// interfaces, respectively, for: +// +// * 4D input arrays, hard-coded length +// * 4D input arrays +// * 4D input arrays, data last +// * 4D in-place arrays, hard-coded lengths +// * 4D in-place arrays +// * 4D in-place arrays, data last +// * 4D argout arrays, hard-coded length +// +#define TEST_FUNCS(TYPE, SNAME) \ +\ +TYPE SNAME ## Norm(TYPE supertensor[2][2][2][2]) { \ + double result = 0; \ + for (int l=0; l<2; ++l) \ + for (int k=0; k<2; ++k) \ + for (int j=0; j<2; ++j) \ + for (int i=0; i<2; ++i) \ + result += supertensor[l][k][j][i] * supertensor[l][k][j][i]; \ + return (TYPE)sqrt(result/16); \ +} \ +\ +TYPE SNAME ## Max(TYPE * supertensor, int cubes, int slices, int rows, int cols) { \ + int i, j, k, l, index; \ + TYPE result = supertensor[0]; \ + for (l=0; l result) result = supertensor[index]; \ + } \ + } \ + } \ + } \ + return result; \ +} \ +\ +TYPE SNAME ## Min(int cubes, int slices, int rows, int cols, TYPE * supertensor) { \ + int i, j, k, l, index; \ + TYPE result = supertensor[0]; \ + for (l=0; l ceil) array[index] = ceil; \ + } \ + } \ + } \ + } \ +} \ +\ +void SNAME ## LUSplit(TYPE supertensor[2][2][2][2], TYPE lower[2][2][2][2], \ + TYPE upper[2][2][2][2]) { \ + int sum; \ + for (int l=0; l<2; ++l) { \ + for (int k=0; k<2; ++k) { \ + for (int j=0; j<2; ++j) { \ + for (int i=0; i<2; ++i) { \ + sum = i + j + k + l; \ + if (sum < 2) { \ + lower[l][k][j][i] = supertensor[l][k][j][i]; \ + upper[l][k][j][i] = 0; \ + } else { \ + upper[l][k][j][i] = supertensor[l][k][j][i]; \ + lower[l][k][j][i] = 0; \ + } \ + } \ + } \ + } \ + } \ +} + +TEST_FUNCS(signed char , schar ) +TEST_FUNCS(unsigned char , uchar ) +TEST_FUNCS(short , short ) +TEST_FUNCS(unsigned short , ushort ) +TEST_FUNCS(int , int ) +TEST_FUNCS(unsigned int , uint ) +TEST_FUNCS(long , long ) +TEST_FUNCS(unsigned long , ulong ) +TEST_FUNCS(long long , longLong ) +TEST_FUNCS(unsigned long long, ulongLong) +TEST_FUNCS(float , float ) +TEST_FUNCS(double , double ) + diff --git a/tools/swig/test/SuperTensor.h b/tools/swig/test/SuperTensor.h new file mode 100644 index 0000000..29cc3bb --- /dev/null +++ b/tools/swig/test/SuperTensor.h @@ -0,0 +1,53 @@ +#ifndef SUPERTENSOR_H +#define SUPERTENSOR_H + +// The following macro defines the prototypes for a family of +// functions that work with 4D arrays with the forms +// +// TYPE SNAMENorm( TYPE supertensor[2][2][2][2]); +// TYPE SNAMEMax( TYPE * supertensor, int cubes, int slices, int rows, int cols); +// TYPE SNAMEMin( int cubes, int slices, int rows, int cols, TYPE * supertensor); +// void SNAMEScale( TYPE array[3][3][3][3]); +// void SNAMEFloor( TYPE * array, int cubes, int slices, int rows, int cols, TYPE floor); +// void SNAMECeil( int cubes, int slices, int rows, int cols, TYPE * array, TYPE ceil ); +// void SNAMELUSplit(TYPE in[3][3][3][3], TYPE lower[3][3][3][3], TYPE upper[3][3][3][3]); +// +// for any specified type TYPE (for example: short, unsigned int, long +// long, etc.) with given short name SNAME (for example: short, uint, +// longLong, etc.). The macro is then expanded for the given +// TYPE/SNAME pairs. The resulting functions are for testing numpy +// interfaces, respectively, for: +// +// * 4D input arrays, hard-coded lengths +// * 4D input arrays +// * 4D input arrays, data last +// * 4D in-place arrays, hard-coded lengths +// * 4D in-place arrays +// * 4D in-place arrays, data last +// * 4D argout arrays, hard-coded length +// +#define TEST_FUNC_PROTOS(TYPE, SNAME) \ +\ +TYPE SNAME ## Norm( TYPE supertensor[2][2][2][2]); \ +TYPE SNAME ## Max( TYPE * supertensor, int cubes, int slices, int rows, int cols); \ +TYPE SNAME ## Min( int cubes, int slices, int rows, int cols, TYPE * supertensor); \ +void SNAME ## Scale( TYPE array[3][3][3][3], TYPE val); \ +void SNAME ## Floor( TYPE * array, int cubes, int slices, int rows, int cols, TYPE floor); \ +void SNAME ## Ceil( int cubes, int slices, int rows, int cols, TYPE * array, TYPE ceil ); \ +void SNAME ## LUSplit(TYPE supertensor[2][2][2][2], TYPE lower[2][2][2][2], TYPE upper[2][2][2][2]); + +TEST_FUNC_PROTOS(signed char , schar ) +TEST_FUNC_PROTOS(unsigned char , uchar ) +TEST_FUNC_PROTOS(short , short ) +TEST_FUNC_PROTOS(unsigned short , ushort ) +TEST_FUNC_PROTOS(int , int ) +TEST_FUNC_PROTOS(unsigned int , uint ) +TEST_FUNC_PROTOS(long , long ) +TEST_FUNC_PROTOS(unsigned long , ulong ) +TEST_FUNC_PROTOS(long long , longLong ) +TEST_FUNC_PROTOS(unsigned long long, ulongLong) +TEST_FUNC_PROTOS(float , float ) +TEST_FUNC_PROTOS(double , double ) + +#endif + diff --git a/tools/swig/test/SuperTensor.i b/tools/swig/test/SuperTensor.i new file mode 100644 index 0000000..7521b8e --- /dev/null +++ b/tools/swig/test/SuperTensor.i @@ -0,0 +1,50 @@ +// -*- c++ -*- +%module SuperTensor + +%{ +#define SWIG_FILE_WITH_INIT +#include "SuperTensor.h" +%} + +// Get the NumPy typemaps +%include "../numpy.i" + +%init %{ + import_array(); +%} + +%define %apply_numpy_typemaps(TYPE) + +%apply (TYPE IN_ARRAY4[ANY][ANY][ANY][ANY]) {(TYPE supertensor[ANY][ANY][ANY][ANY])}; +%apply (TYPE* IN_ARRAY4, int DIM1, int DIM2, int DIM3, int DIM4) + {(TYPE* supertensor, int cubes, int slices, int rows, int cols)}; +%apply (int DIM1, int DIM2, int DIM3, int DIM4, TYPE* IN_ARRAY4) + {(int cubes, int slices, int rows, int cols, TYPE* supertensor)}; + +%apply (TYPE INPLACE_ARRAY4[ANY][ANY][ANY][ANY]) {(TYPE array[3][3][3][3])}; +%apply (TYPE* INPLACE_ARRAY4, int DIM1, int DIM2, int DIM3, int DIM4) + {(TYPE* array, int cubes, int slices, int rows, int cols)}; +%apply (int DIM1, int DIM2, int DIM3, int DIM4, TYPE* INPLACE_ARRAY4) + {(int cubes, int slices, int rows, int cols, TYPE* array)}; + +%apply (TYPE ARGOUT_ARRAY4[ANY][ANY][ANY][ANY]) {(TYPE lower[2][2][2][2])}; +%apply (TYPE ARGOUT_ARRAY4[ANY][ANY][ANY][ANY]) {(TYPE upper[2][2][2][2])}; + +%enddef /* %apply_numpy_typemaps() macro */ + +%apply_numpy_typemaps(signed char ) +%apply_numpy_typemaps(unsigned char ) +%apply_numpy_typemaps(short ) +%apply_numpy_typemaps(unsigned short ) +%apply_numpy_typemaps(int ) +%apply_numpy_typemaps(unsigned int ) +%apply_numpy_typemaps(long ) +%apply_numpy_typemaps(unsigned long ) +%apply_numpy_typemaps(long long ) +%apply_numpy_typemaps(unsigned long long) +%apply_numpy_typemaps(float ) +%apply_numpy_typemaps(double ) + +// Include the header file to be wrapped +%include "SuperTensor.h" + diff --git a/tools/swig/test/Tensor.cxx b/tools/swig/test/Tensor.cxx new file mode 100644 index 0000000..4ccefa1 --- /dev/null +++ b/tools/swig/test/Tensor.cxx @@ -0,0 +1,131 @@ +#include +#include +#include +#include "Tensor.h" + +// The following macro defines a family of functions that work with 3D +// arrays with the forms +// +// TYPE SNAMENorm( TYPE tensor[2][2][2]); +// TYPE SNAMEMax( TYPE * tensor, int slices, int rows, int cols); +// TYPE SNAMEMin( int slices, int rows, int cols TYPE * tensor); +// void SNAMEScale( TYPE tensor[3][3][3]); +// void SNAMEFloor( TYPE * array, int slices, int rows, int cols, TYPE floor); +// void SNAMECeil( int slices, int rows, int cols, TYPE * array, TYPE ceil); +// void SNAMELUSplit(TYPE in[2][2][2], TYPE lower[2][2][2], TYPE upper[2][2][2]); +// +// for any specified type TYPE (for example: short, unsigned int, long +// long, etc.) with given short name SNAME (for example: short, uint, +// longLong, etc.). The macro is then expanded for the given +// TYPE/SNAME pairs. The resulting functions are for testing numpy +// interfaces, respectively, for: +// +// * 3D input arrays, hard-coded length +// * 3D input arrays +// * 3D input arrays, data last +// * 3D in-place arrays, hard-coded lengths +// * 3D in-place arrays +// * 3D in-place arrays, data last +// * 3D argout arrays, hard-coded length +// +#define TEST_FUNCS(TYPE, SNAME) \ +\ +TYPE SNAME ## Norm(TYPE tensor[2][2][2]) { \ + double result = 0; \ + for (int k=0; k<2; ++k) \ + for (int j=0; j<2; ++j) \ + for (int i=0; i<2; ++i) \ + result += tensor[k][j][i] * tensor[k][j][i]; \ + return (TYPE)sqrt(result/8); \ +} \ +\ +TYPE SNAME ## Max(TYPE * tensor, int slices, int rows, int cols) { \ + int i, j, k, index; \ + TYPE result = tensor[0]; \ + for (k=0; k result) result = tensor[index]; \ + } \ + } \ + } \ + return result; \ +} \ +\ +TYPE SNAME ## Min(int slices, int rows, int cols, TYPE * tensor) { \ + int i, j, k, index; \ + TYPE result = tensor[0]; \ + for (k=0; k ceil) array[index] = ceil; \ + } \ + } \ + } \ +} \ +\ +void SNAME ## LUSplit(TYPE tensor[2][2][2], TYPE lower[2][2][2], \ + TYPE upper[2][2][2]) { \ + int sum; \ + for (int k=0; k<2; ++k) { \ + for (int j=0; j<2; ++j) { \ + for (int i=0; i<2; ++i) { \ + sum = i + j + k; \ + if (sum < 2) { \ + lower[k][j][i] = tensor[k][j][i]; \ + upper[k][j][i] = 0; \ + } else { \ + upper[k][j][i] = tensor[k][j][i]; \ + lower[k][j][i] = 0; \ + } \ + } \ + } \ + } \ +} + +TEST_FUNCS(signed char , schar ) +TEST_FUNCS(unsigned char , uchar ) +TEST_FUNCS(short , short ) +TEST_FUNCS(unsigned short , ushort ) +TEST_FUNCS(int , int ) +TEST_FUNCS(unsigned int , uint ) +TEST_FUNCS(long , long ) +TEST_FUNCS(unsigned long , ulong ) +TEST_FUNCS(long long , longLong ) +TEST_FUNCS(unsigned long long, ulongLong) +TEST_FUNCS(float , float ) +TEST_FUNCS(double , double ) diff --git a/tools/swig/test/Tensor.h b/tools/swig/test/Tensor.h new file mode 100644 index 0000000..1f483b3 --- /dev/null +++ b/tools/swig/test/Tensor.h @@ -0,0 +1,52 @@ +#ifndef TENSOR_H +#define TENSOR_H + +// The following macro defines the prototypes for a family of +// functions that work with 3D arrays with the forms +// +// TYPE SNAMENorm( TYPE tensor[2][2][2]); +// TYPE SNAMEMax( TYPE * tensor, int slices, int rows, int cols); +// TYPE SNAMEMin( int slices, int rows, int cols, TYPE * tensor); +// void SNAMEScale( TYPE array[3][3][3]); +// void SNAMEFloor( TYPE * array, int slices, int rows, int cols, TYPE floor); +// void SNAMECeil( int slices, int rows, int cols, TYPE * array, TYPE ceil ); +// void SNAMELUSplit(TYPE in[3][3][3], TYPE lower[3][3][3], TYPE upper[3][3][3]); +// +// for any specified type TYPE (for example: short, unsigned int, long +// long, etc.) with given short name SNAME (for example: short, uint, +// longLong, etc.). The macro is then expanded for the given +// TYPE/SNAME pairs. The resulting functions are for testing numpy +// interfaces, respectively, for: +// +// * 3D input arrays, hard-coded lengths +// * 3D input arrays +// * 3D input arrays, data last +// * 3D in-place arrays, hard-coded lengths +// * 3D in-place arrays +// * 3D in-place arrays, data last +// * 3D argout arrays, hard-coded length +// +#define TEST_FUNC_PROTOS(TYPE, SNAME) \ +\ +TYPE SNAME ## Norm( TYPE tensor[2][2][2]); \ +TYPE SNAME ## Max( TYPE * tensor, int slices, int rows, int cols); \ +TYPE SNAME ## Min( int slices, int rows, int cols, TYPE * tensor); \ +void SNAME ## Scale( TYPE array[3][3][3], TYPE val); \ +void SNAME ## Floor( TYPE * array, int slices, int rows, int cols, TYPE floor); \ +void SNAME ## Ceil( int slices, int rows, int cols, TYPE * array, TYPE ceil ); \ +void SNAME ## LUSplit(TYPE tensor[2][2][2], TYPE lower[2][2][2], TYPE upper[2][2][2]); + +TEST_FUNC_PROTOS(signed char , schar ) +TEST_FUNC_PROTOS(unsigned char , uchar ) +TEST_FUNC_PROTOS(short , short ) +TEST_FUNC_PROTOS(unsigned short , ushort ) +TEST_FUNC_PROTOS(int , int ) +TEST_FUNC_PROTOS(unsigned int , uint ) +TEST_FUNC_PROTOS(long , long ) +TEST_FUNC_PROTOS(unsigned long , ulong ) +TEST_FUNC_PROTOS(long long , longLong ) +TEST_FUNC_PROTOS(unsigned long long, ulongLong) +TEST_FUNC_PROTOS(float , float ) +TEST_FUNC_PROTOS(double , double ) + +#endif diff --git a/tools/swig/test/Tensor.i b/tools/swig/test/Tensor.i new file mode 100644 index 0000000..5bf9da7 --- /dev/null +++ b/tools/swig/test/Tensor.i @@ -0,0 +1,49 @@ +// -*- c++ -*- +%module Tensor + +%{ +#define SWIG_FILE_WITH_INIT +#include "Tensor.h" +%} + +// Get the NumPy typemaps +%include "../numpy.i" + +%init %{ + import_array(); +%} + +%define %apply_numpy_typemaps(TYPE) + +%apply (TYPE IN_ARRAY3[ANY][ANY][ANY]) {(TYPE tensor[ANY][ANY][ANY])}; +%apply (TYPE* IN_ARRAY3, int DIM1, int DIM2, int DIM3) + {(TYPE* tensor, int slices, int rows, int cols)}; +%apply (int DIM1, int DIM2, int DIM3, TYPE* IN_ARRAY3) + {(int slices, int rows, int cols, TYPE* tensor)}; + +%apply (TYPE INPLACE_ARRAY3[ANY][ANY][ANY]) {(TYPE array[3][3][3])}; +%apply (TYPE* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) + {(TYPE* array, int slices, int rows, int cols)}; +%apply (int DIM1, int DIM2, int DIM3, TYPE* INPLACE_ARRAY3) + {(int slices, int rows, int cols, TYPE* array)}; + +%apply (TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) {(TYPE lower[2][2][2])}; +%apply (TYPE ARGOUT_ARRAY3[ANY][ANY][ANY]) {(TYPE upper[2][2][2])}; + +%enddef /* %apply_numpy_typemaps() macro */ + +%apply_numpy_typemaps(signed char ) +%apply_numpy_typemaps(unsigned char ) +%apply_numpy_typemaps(short ) +%apply_numpy_typemaps(unsigned short ) +%apply_numpy_typemaps(int ) +%apply_numpy_typemaps(unsigned int ) +%apply_numpy_typemaps(long ) +%apply_numpy_typemaps(unsigned long ) +%apply_numpy_typemaps(long long ) +%apply_numpy_typemaps(unsigned long long) +%apply_numpy_typemaps(float ) +%apply_numpy_typemaps(double ) + +// Include the header file to be wrapped +%include "Tensor.h" diff --git a/tools/swig/test/Vector.cxx b/tools/swig/test/Vector.cxx new file mode 100644 index 0000000..2c90404 --- /dev/null +++ b/tools/swig/test/Vector.cxx @@ -0,0 +1,100 @@ +#include +#include +#include +#include "Vector.h" + +// The following macro defines a family of functions that work with 1D +// arrays with the forms +// +// TYPE SNAMELength( TYPE vector[3]); +// TYPE SNAMEProd( TYPE * series, int size); +// TYPE SNAMESum( int size, TYPE * series); +// void SNAMEReverse(TYPE array[3]); +// void SNAMEOnes( TYPE * array, int size); +// void SNAMEZeros( int size, TYPE * array); +// void SNAMEEOSplit(TYPE vector[3], TYPE even[3], odd[3]); +// void SNAMETwos( TYPE * twoVec, int size); +// void SNAMEThrees( int size, TYPE * threeVec); +// +// for any specified type TYPE (for example: short, unsigned int, long +// long, etc.) with given short name SNAME (for example: short, uint, +// longLong, etc.). The macro is then expanded for the given +// TYPE/SNAME pairs. The resulting functions are for testing numpy +// interfaces, respectively, for: +// +// * 1D input arrays, hard-coded length +// * 1D input arrays +// * 1D input arrays, data last +// * 1D in-place arrays, hard-coded length +// * 1D in-place arrays +// * 1D in-place arrays, data last +// * 1D argout arrays, hard-coded length +// * 1D argout arrays +// * 1D argout arrays, data last +// +#define TEST_FUNCS(TYPE, SNAME) \ +\ +TYPE SNAME ## Length(TYPE vector[3]) { \ + double result = 0; \ + for (int i=0; i<3; ++i) result += vector[i]*vector[i]; \ + return (TYPE)sqrt(result); \ +} \ +\ +TYPE SNAME ## Prod(TYPE * series, int size) { \ + TYPE result = 1; \ + for (int i=0; i>sys.stderr, self.typeStr, "... ", + norm = SuperTensor.__dict__[self.typeStr + "Norm"] + supertensor = np.arange(2*2*2*2, dtype=self.typeCode).reshape((2, 2, 2, 2)) + #Note: cludge to get an answer of the same type as supertensor. + #Answer is simply sqrt(sum(supertensor*supertensor)/16) + answer = np.array([np.sqrt(np.sum(supertensor.astype('d')*supertensor)/16.)], dtype=self.typeCode)[0] + self.assertAlmostEqual(norm(supertensor), answer, 6) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNormBadList(self): + "Test norm function with bad list" + print >>sys.stderr, self.typeStr, "... ", + norm = SuperTensor.__dict__[self.typeStr + "Norm"] + supertensor = [[[[0, "one"], [2, 3]], [[3, "two"], [1, 0]]], [[[0, "one"], [2, 3]], [[3, "two"], [1, 0]]]] + self.assertRaises(BadListError, norm, supertensor) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNormWrongDim(self): + "Test norm function with wrong dimensions" + print >>sys.stderr, self.typeStr, "... ", + norm = SuperTensor.__dict__[self.typeStr + "Norm"] + supertensor = np.arange(2*2*2, dtype=self.typeCode).reshape((2, 2, 2)) + self.assertRaises(TypeError, norm, supertensor) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNormWrongSize(self): + "Test norm function with wrong size" + print >>sys.stderr, self.typeStr, "... ", + norm = SuperTensor.__dict__[self.typeStr + "Norm"] + supertensor = np.arange(3*2*2, dtype=self.typeCode).reshape((3, 2, 2)) + self.assertRaises(TypeError, norm, supertensor) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNormNonContainer(self): + "Test norm function with non-container" + print >>sys.stderr, self.typeStr, "... ", + norm = SuperTensor.__dict__[self.typeStr + "Norm"] + self.assertRaises(TypeError, norm, None) + + # Test (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testMax(self): + "Test max function" + print >>sys.stderr, self.typeStr, "... ", + max = SuperTensor.__dict__[self.typeStr + "Max"] + supertensor = [[[[1, 2], [3, 4]], [[5, 6], [7, 8]]], [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]] + self.assertEquals(max(supertensor), 8) + + # Test (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testMaxBadList(self): + "Test max function with bad list" + print >>sys.stderr, self.typeStr, "... ", + max = SuperTensor.__dict__[self.typeStr + "Max"] + supertensor = [[[[1, "two"], [3, 4]], [[5, "six"], [7, 8]]], [[[1, "two"], [3, 4]], [[5, "six"], [7, 8]]]] + self.assertRaises(BadListError, max, supertensor) + + # Test (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testMaxNonContainer(self): + "Test max function with non-container" + print >>sys.stderr, self.typeStr, "... ", + max = SuperTensor.__dict__[self.typeStr + "Max"] + self.assertRaises(TypeError, max, None) + + # Test (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testMaxWrongDim(self): + "Test max function with wrong dimensions" + print >>sys.stderr, self.typeStr, "... ", + max = SuperTensor.__dict__[self.typeStr + "Max"] + self.assertRaises(TypeError, max, [0, -1, 2, -3]) + + # Test (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) typemap + def testMin(self): + "Test min function" + print >>sys.stderr, self.typeStr, "... ", + min = SuperTensor.__dict__[self.typeStr + "Min"] + supertensor = [[[[9, 8], [7, 6]], [[5, 4], [3, 2]]], [[[9, 8], [7, 6]], [[5, 4], [3, 2]]]] + self.assertEquals(min(supertensor), 2) + + # Test (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) typemap + def testMinBadList(self): + "Test min function with bad list" + print >>sys.stderr, self.typeStr, "... ", + min = SuperTensor.__dict__[self.typeStr + "Min"] + supertensor = [[[["nine", 8], [7, 6]], [["five", 4], [3, 2]]], [[["nine", 8], [7, 6]], [["five", 4], [3, 2]]]] + self.assertRaises(BadListError, min, supertensor) + + # Test (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) typemap + def testMinNonContainer(self): + "Test min function with non-container" + print >>sys.stderr, self.typeStr, "... ", + min = SuperTensor.__dict__[self.typeStr + "Min"] + self.assertRaises(TypeError, min, True) + + # Test (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) typemap + def testMinWrongDim(self): + "Test min function with wrong dimensions" + print >>sys.stderr, self.typeStr, "... ", + min = SuperTensor.__dict__[self.typeStr + "Min"] + self.assertRaises(TypeError, min, [[1, 3], [5, 7]]) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScale(self): + "Test scale function" + print >>sys.stderr, self.typeStr, "... ", + scale = SuperTensor.__dict__[self.typeStr + "Scale"] + supertensor = np.arange(3*3*3*3, dtype=self.typeCode).reshape((3, 3, 3, 3)) + answer = supertensor.copy()*4 + scale(supertensor, 4) + self.assertEquals((supertensor == answer).all(), True) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScaleWrongType(self): + "Test scale function with wrong type" + print >>sys.stderr, self.typeStr, "... ", + scale = SuperTensor.__dict__[self.typeStr + "Scale"] + supertensor = np.array([[[1, 0, 1], [0, 1, 0], [1, 0, 1]], + [[0, 1, 0], [1, 0, 1], [0, 1, 0]], + [[1, 0, 1], [0, 1, 0], [1, 0, 1]]], 'c') + self.assertRaises(TypeError, scale, supertensor) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScaleWrongDim(self): + "Test scale function with wrong dimensions" + print >>sys.stderr, self.typeStr, "... ", + scale = SuperTensor.__dict__[self.typeStr + "Scale"] + supertensor = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1], + [0, 1, 0], [1, 0, 1], [0, 1, 0]], self.typeCode) + self.assertRaises(TypeError, scale, supertensor) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScaleWrongSize(self): + "Test scale function with wrong size" + print >>sys.stderr, self.typeStr, "... ", + scale = SuperTensor.__dict__[self.typeStr + "Scale"] + supertensor = np.array([[[1, 0], [0, 1], [1, 0]], + [[0, 1], [1, 0], [0, 1]], + [[1, 0], [0, 1], [1, 0]]], self.typeCode) + self.assertRaises(TypeError, scale, supertensor) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScaleNonArray(self): + "Test scale function with non-array" + print >>sys.stderr, self.typeStr, "... ", + scale = SuperTensor.__dict__[self.typeStr + "Scale"] + self.assertRaises(TypeError, scale, True) + + # Test (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testFloor(self): + "Test floor function" + print >>sys.stderr, self.typeStr, "... ", + supertensor = np.arange(2*2*2*2, dtype=self.typeCode).reshape((2, 2, 2, 2)) + answer = supertensor.copy() + answer[answer < 4] = 4 + + floor = SuperTensor.__dict__[self.typeStr + "Floor"] + floor(supertensor, 4) + np.testing.assert_array_equal(supertensor, answer) + + # Test (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testFloorWrongType(self): + "Test floor function with wrong type" + print >>sys.stderr, self.typeStr, "... ", + floor = SuperTensor.__dict__[self.typeStr + "Floor"] + supertensor = np.ones(2*2*2*2, dtype='c').reshape((2, 2, 2, 2)) + self.assertRaises(TypeError, floor, supertensor) + + # Test (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testFloorWrongDim(self): + "Test floor function with wrong type" + print >>sys.stderr, self.typeStr, "... ", + floor = SuperTensor.__dict__[self.typeStr + "Floor"] + supertensor = np.arange(2*2*2, dtype=self.typeCode).reshape((2, 2, 2)) + self.assertRaises(TypeError, floor, supertensor) + + # Test (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testFloorNonArray(self): + "Test floor function with non-array" + print >>sys.stderr, self.typeStr, "... ", + floor = SuperTensor.__dict__[self.typeStr + "Floor"] + self.assertRaises(TypeError, floor, object) + + # Test (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) typemap + def testCeil(self): + "Test ceil function" + print >>sys.stderr, self.typeStr, "... ", + supertensor = np.arange(2*2*2*2, dtype=self.typeCode).reshape((2, 2, 2, 2)) + answer = supertensor.copy() + answer[answer > 5] = 5 + ceil = SuperTensor.__dict__[self.typeStr + "Ceil"] + ceil(supertensor, 5) + np.testing.assert_array_equal(supertensor, answer) + + # Test (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) typemap + def testCeilWrongType(self): + "Test ceil function with wrong type" + print >>sys.stderr, self.typeStr, "... ", + ceil = SuperTensor.__dict__[self.typeStr + "Ceil"] + supertensor = np.ones(2*2*2*2, 'c').reshape((2, 2, 2, 2)) + self.assertRaises(TypeError, ceil, supertensor) + + # Test (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) typemap + def testCeilWrongDim(self): + "Test ceil function with wrong dimensions" + print >>sys.stderr, self.typeStr, "... ", + ceil = SuperTensor.__dict__[self.typeStr + "Ceil"] + supertensor = np.arange(2*2*2, dtype=self.typeCode).reshape((2, 2, 2)) + self.assertRaises(TypeError, ceil, supertensor) + + # Test (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) typemap + def testCeilNonArray(self): + "Test ceil function with non-array" + print >>sys.stderr, self.typeStr, "... ", + ceil = SuperTensor.__dict__[self.typeStr + "Ceil"] + supertensor = np.arange(2*2*2*2, dtype=self.typeCode).reshape((2, 2, 2, 2)).tolist() + self.assertRaises(TypeError, ceil, supertensor) + + # Test (type ARGOUT_ARRAY3[ANY][ANY][ANY]) typemap + def testLUSplit(self): + "Test luSplit function" + print >>sys.stderr, self.typeStr, "... ", + luSplit = SuperTensor.__dict__[self.typeStr + "LUSplit"] + supertensor = np.ones(2*2*2*2, dtype=self.typeCode).reshape((2, 2, 2, 2)) + answer_upper = [[[[0, 0], [0, 1]], [[0, 1], [1, 1]]], [[[0, 1], [1, 1]], [[1, 1], [1, 1]]]] + answer_lower = [[[[1, 1], [1, 0]], [[1, 0], [0, 0]]], [[[1, 0], [0, 0]], [[0, 0], [0, 0]]]] + lower, upper = luSplit(supertensor) + self.assertEquals((lower == answer_lower).all(), True) + self.assertEquals((upper == answer_upper).all(), True) + +###################################################################### + +class scharTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "schar" + self.typeCode = "b" + #self.result = int(self.result) + +###################################################################### + +class ucharTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "uchar" + self.typeCode = "B" + #self.result = int(self.result) + +###################################################################### + +class shortTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "short" + self.typeCode = "h" + #self.result = int(self.result) + +###################################################################### + +class ushortTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "ushort" + self.typeCode = "H" + #self.result = int(self.result) + +###################################################################### + +class intTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "int" + self.typeCode = "i" + #self.result = int(self.result) + +###################################################################### + +class uintTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "uint" + self.typeCode = "I" + #self.result = int(self.result) + +###################################################################### + +class longTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "long" + self.typeCode = "l" + #self.result = int(self.result) + +###################################################################### + +class ulongTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "ulong" + self.typeCode = "L" + #self.result = int(self.result) + +###################################################################### + +class longLongTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "longLong" + self.typeCode = "q" + #self.result = int(self.result) + +###################################################################### + +class ulongLongTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "ulongLong" + self.typeCode = "Q" + #self.result = int(self.result) + +###################################################################### + +class floatTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "float" + self.typeCode = "f" + +###################################################################### + +class doubleTestCase(SuperTensorTestCase): + def __init__(self, methodName="runTest"): + SuperTensorTestCase.__init__(self, methodName) + self.typeStr = "double" + self.typeCode = "d" + +###################################################################### + +if __name__ == "__main__": + + # Build the test suite + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite( scharTestCase)) + suite.addTest(unittest.makeSuite( ucharTestCase)) + suite.addTest(unittest.makeSuite( shortTestCase)) + suite.addTest(unittest.makeSuite( ushortTestCase)) + suite.addTest(unittest.makeSuite( intTestCase)) + suite.addTest(unittest.makeSuite( uintTestCase)) + suite.addTest(unittest.makeSuite( longTestCase)) + suite.addTest(unittest.makeSuite( ulongTestCase)) + suite.addTest(unittest.makeSuite( longLongTestCase)) + suite.addTest(unittest.makeSuite(ulongLongTestCase)) + suite.addTest(unittest.makeSuite( floatTestCase)) + suite.addTest(unittest.makeSuite( doubleTestCase)) + + # Execute the test suite + print "Testing 4D Functions of Module SuperTensor" + print "NumPy version", np.__version__ + print + result = unittest.TextTestRunner(verbosity=2).run(suite) + sys.exit(bool(result.errors + result.failures)) diff --git a/tools/swig/test/testTensor.py b/tools/swig/test/testTensor.py new file mode 100755 index 0000000..61dc820 --- /dev/null +++ b/tools/swig/test/testTensor.py @@ -0,0 +1,402 @@ +#! /usr/bin/env python +from __future__ import division, absolute_import, print_function + +# System imports +from distutils.util import get_platform +from math import sqrt +import os +import sys +import unittest + +# Import NumPy +import numpy as np +major, minor = [ int(d) for d in np.__version__.split(".")[:2] ] +if major == 0: BadListError = TypeError +else: BadListError = ValueError + +import Tensor + +###################################################################### + +class TensorTestCase(unittest.TestCase): + + def __init__(self, methodName="runTests"): + unittest.TestCase.__init__(self, methodName) + self.typeStr = "double" + self.typeCode = "d" + self.result = sqrt(28.0/8) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNorm(self): + "Test norm function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + norm = Tensor.__dict__[self.typeStr + "Norm"] + tensor = [[[0, 1], [2, 3]], + [[3, 2], [1, 0]]] + if isinstance(self.result, int): + self.assertEquals(norm(tensor), self.result) + else: + self.assertAlmostEqual(norm(tensor), self.result, 6) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNormBadList(self): + "Test norm function with bad list" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + norm = Tensor.__dict__[self.typeStr + "Norm"] + tensor = [[[0, "one"], [2, 3]], + [[3, "two"], [1, 0]]] + self.assertRaises(BadListError, norm, tensor) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNormWrongDim(self): + "Test norm function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + norm = Tensor.__dict__[self.typeStr + "Norm"] + tensor = [[0, 1, 2, 3], + [3, 2, 1, 0]] + self.assertRaises(TypeError, norm, tensor) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNormWrongSize(self): + "Test norm function with wrong size" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + norm = Tensor.__dict__[self.typeStr + "Norm"] + tensor = [[[0, 1, 0], [2, 3, 2]], + [[3, 2, 3], [1, 0, 1]]] + self.assertRaises(TypeError, norm, tensor) + + # Test (type IN_ARRAY3[ANY][ANY][ANY]) typemap + def testNormNonContainer(self): + "Test norm function with non-container" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + norm = Tensor.__dict__[self.typeStr + "Norm"] + self.assertRaises(TypeError, norm, None) + + # Test (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testMax(self): + "Test max function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + max = Tensor.__dict__[self.typeStr + "Max"] + tensor = [[[1, 2], [3, 4]], + [[5, 6], [7, 8]]] + self.assertEquals(max(tensor), 8) + + # Test (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testMaxBadList(self): + "Test max function with bad list" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + max = Tensor.__dict__[self.typeStr + "Max"] + tensor = [[[1, "two"], [3, 4]], + [[5, "six"], [7, 8]]] + self.assertRaises(BadListError, max, tensor) + + # Test (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testMaxNonContainer(self): + "Test max function with non-container" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + max = Tensor.__dict__[self.typeStr + "Max"] + self.assertRaises(TypeError, max, None) + + # Test (type* IN_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testMaxWrongDim(self): + "Test max function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + max = Tensor.__dict__[self.typeStr + "Max"] + self.assertRaises(TypeError, max, [0, -1, 2, -3]) + + # Test (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) typemap + def testMin(self): + "Test min function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + min = Tensor.__dict__[self.typeStr + "Min"] + tensor = [[[9, 8], [7, 6]], + [[5, 4], [3, 2]]] + self.assertEquals(min(tensor), 2) + + # Test (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) typemap + def testMinBadList(self): + "Test min function with bad list" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + min = Tensor.__dict__[self.typeStr + "Min"] + tensor = [[["nine", 8], [7, 6]], + [["five", 4], [3, 2]]] + self.assertRaises(BadListError, min, tensor) + + # Test (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) typemap + def testMinNonContainer(self): + "Test min function with non-container" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + min = Tensor.__dict__[self.typeStr + "Min"] + self.assertRaises(TypeError, min, True) + + # Test (int DIM1, int DIM2, int DIM3, type* IN_ARRAY3) typemap + def testMinWrongDim(self): + "Test min function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + min = Tensor.__dict__[self.typeStr + "Min"] + self.assertRaises(TypeError, min, [[1, 3], [5, 7]]) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScale(self): + "Test scale function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + scale = Tensor.__dict__[self.typeStr + "Scale"] + tensor = np.array([[[1, 0, 1], [0, 1, 0], [1, 0, 1]], + [[0, 1, 0], [1, 0, 1], [0, 1, 0]], + [[1, 0, 1], [0, 1, 0], [1, 0, 1]]], self.typeCode) + scale(tensor, 4) + self.assertEquals((tensor == [[[4, 0, 4], [0, 4, 0], [4, 0, 4]], + [[0, 4, 0], [4, 0, 4], [0, 4, 0]], + [[4, 0, 4], [0, 4, 0], [4, 0, 4]]]).all(), True) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScaleWrongType(self): + "Test scale function with wrong type" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + scale = Tensor.__dict__[self.typeStr + "Scale"] + tensor = np.array([[[1, 0, 1], [0, 1, 0], [1, 0, 1]], + [[0, 1, 0], [1, 0, 1], [0, 1, 0]], + [[1, 0, 1], [0, 1, 0], [1, 0, 1]]], 'c') + self.assertRaises(TypeError, scale, tensor) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScaleWrongDim(self): + "Test scale function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + scale = Tensor.__dict__[self.typeStr + "Scale"] + tensor = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1], + [0, 1, 0], [1, 0, 1], [0, 1, 0]], self.typeCode) + self.assertRaises(TypeError, scale, tensor) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScaleWrongSize(self): + "Test scale function with wrong size" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + scale = Tensor.__dict__[self.typeStr + "Scale"] + tensor = np.array([[[1, 0], [0, 1], [1, 0]], + [[0, 1], [1, 0], [0, 1]], + [[1, 0], [0, 1], [1, 0]]], self.typeCode) + self.assertRaises(TypeError, scale, tensor) + + # Test (type INPLACE_ARRAY3[ANY][ANY][ANY]) typemap + def testScaleNonArray(self): + "Test scale function with non-array" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + scale = Tensor.__dict__[self.typeStr + "Scale"] + self.assertRaises(TypeError, scale, True) + + # Test (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testFloor(self): + "Test floor function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + floor = Tensor.__dict__[self.typeStr + "Floor"] + tensor = np.array([[[1, 2], [3, 4]], + [[5, 6], [7, 8]]], self.typeCode) + floor(tensor, 4) + np.testing.assert_array_equal(tensor, np.array([[[4, 4], [4, 4]], + [[5, 6], [7, 8]]])) + + # Test (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testFloorWrongType(self): + "Test floor function with wrong type" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + floor = Tensor.__dict__[self.typeStr + "Floor"] + tensor = np.array([[[1, 2], [3, 4]], + [[5, 6], [7, 8]]], 'c') + self.assertRaises(TypeError, floor, tensor) + + # Test (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testFloorWrongDim(self): + "Test floor function with wrong type" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + floor = Tensor.__dict__[self.typeStr + "Floor"] + tensor = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], self.typeCode) + self.assertRaises(TypeError, floor, tensor) + + # Test (type* INPLACE_ARRAY3, int DIM1, int DIM2, int DIM3) typemap + def testFloorNonArray(self): + "Test floor function with non-array" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + floor = Tensor.__dict__[self.typeStr + "Floor"] + self.assertRaises(TypeError, floor, object) + + # Test (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) typemap + def testCeil(self): + "Test ceil function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + ceil = Tensor.__dict__[self.typeStr + "Ceil"] + tensor = np.array([[[9, 8], [7, 6]], + [[5, 4], [3, 2]]], self.typeCode) + ceil(tensor, 5) + np.testing.assert_array_equal(tensor, np.array([[[5, 5], [5, 5]], + [[5, 4], [3, 2]]])) + + # Test (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) typemap + def testCeilWrongType(self): + "Test ceil function with wrong type" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + ceil = Tensor.__dict__[self.typeStr + "Ceil"] + tensor = np.array([[[9, 8], [7, 6]], + [[5, 4], [3, 2]]], 'c') + self.assertRaises(TypeError, ceil, tensor) + + # Test (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) typemap + def testCeilWrongDim(self): + "Test ceil function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + ceil = Tensor.__dict__[self.typeStr + "Ceil"] + tensor = np.array([[9, 8], [7, 6], [5, 4], [3, 2]], self.typeCode) + self.assertRaises(TypeError, ceil, tensor) + + # Test (int DIM1, int DIM2, int DIM3, type* INPLACE_ARRAY3) typemap + def testCeilNonArray(self): + "Test ceil function with non-array" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + ceil = Tensor.__dict__[self.typeStr + "Ceil"] + tensor = [[[9, 8], [7, 6]], + [[5, 4], [3, 2]]] + self.assertRaises(TypeError, ceil, tensor) + + # Test (type ARGOUT_ARRAY3[ANY][ANY][ANY]) typemap + def testLUSplit(self): + "Test luSplit function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + luSplit = Tensor.__dict__[self.typeStr + "LUSplit"] + lower, upper = luSplit([[[1, 1], [1, 1]], + [[1, 1], [1, 1]]]) + self.assertEquals((lower == [[[1, 1], [1, 0]], + [[1, 0], [0, 0]]]).all(), True) + self.assertEquals((upper == [[[0, 0], [0, 1]], + [[0, 1], [1, 1]]]).all(), True) + +###################################################################### + +class scharTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "schar" + self.typeCode = "b" + self.result = int(self.result) + +###################################################################### + +class ucharTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "uchar" + self.typeCode = "B" + self.result = int(self.result) + +###################################################################### + +class shortTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "short" + self.typeCode = "h" + self.result = int(self.result) + +###################################################################### + +class ushortTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "ushort" + self.typeCode = "H" + self.result = int(self.result) + +###################################################################### + +class intTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "int" + self.typeCode = "i" + self.result = int(self.result) + +###################################################################### + +class uintTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "uint" + self.typeCode = "I" + self.result = int(self.result) + +###################################################################### + +class longTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "long" + self.typeCode = "l" + self.result = int(self.result) + +###################################################################### + +class ulongTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "ulong" + self.typeCode = "L" + self.result = int(self.result) + +###################################################################### + +class longLongTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "longLong" + self.typeCode = "q" + self.result = int(self.result) + +###################################################################### + +class ulongLongTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "ulongLong" + self.typeCode = "Q" + self.result = int(self.result) + +###################################################################### + +class floatTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "float" + self.typeCode = "f" + +###################################################################### + +class doubleTestCase(TensorTestCase): + def __init__(self, methodName="runTest"): + TensorTestCase.__init__(self, methodName) + self.typeStr = "double" + self.typeCode = "d" + +###################################################################### + +if __name__ == "__main__": + + # Build the test suite + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite( scharTestCase)) + suite.addTest(unittest.makeSuite( ucharTestCase)) + suite.addTest(unittest.makeSuite( shortTestCase)) + suite.addTest(unittest.makeSuite( ushortTestCase)) + suite.addTest(unittest.makeSuite( intTestCase)) + suite.addTest(unittest.makeSuite( uintTestCase)) + suite.addTest(unittest.makeSuite( longTestCase)) + suite.addTest(unittest.makeSuite( ulongTestCase)) + suite.addTest(unittest.makeSuite( longLongTestCase)) + suite.addTest(unittest.makeSuite(ulongLongTestCase)) + suite.addTest(unittest.makeSuite( floatTestCase)) + suite.addTest(unittest.makeSuite( doubleTestCase)) + + # Execute the test suite + print("Testing 3D Functions of Module Tensor") + print("NumPy version", np.__version__) + print() + result = unittest.TextTestRunner(verbosity=2).run(suite) + sys.exit(bool(result.errors + result.failures)) diff --git a/tools/swig/test/testVector.py b/tools/swig/test/testVector.py new file mode 100755 index 0000000..eaaa751 --- /dev/null +++ b/tools/swig/test/testVector.py @@ -0,0 +1,381 @@ +#! /usr/bin/env python +from __future__ import division, absolute_import, print_function + +# System imports +from distutils.util import get_platform +import os +import sys +import unittest + +# Import NumPy +import numpy as np +major, minor = [ int(d) for d in np.__version__.split(".")[:2] ] +if major == 0: BadListError = TypeError +else: BadListError = ValueError + +import Vector + +###################################################################### + +class VectorTestCase(unittest.TestCase): + + def __init__(self, methodName="runTest"): + unittest.TestCase.__init__(self, methodName) + self.typeStr = "double" + self.typeCode = "d" + + # Test the (type IN_ARRAY1[ANY]) typemap + def testLength(self): + "Test length function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + length = Vector.__dict__[self.typeStr + "Length"] + self.assertEquals(length([5, 12, 0]), 13) + + # Test the (type IN_ARRAY1[ANY]) typemap + def testLengthBadList(self): + "Test length function with bad list" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + length = Vector.__dict__[self.typeStr + "Length"] + self.assertRaises(BadListError, length, [5, "twelve", 0]) + + # Test the (type IN_ARRAY1[ANY]) typemap + def testLengthWrongSize(self): + "Test length function with wrong size" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + length = Vector.__dict__[self.typeStr + "Length"] + self.assertRaises(TypeError, length, [5, 12]) + + # Test the (type IN_ARRAY1[ANY]) typemap + def testLengthWrongDim(self): + "Test length function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + length = Vector.__dict__[self.typeStr + "Length"] + self.assertRaises(TypeError, length, [[1, 2], [3, 4]]) + + # Test the (type IN_ARRAY1[ANY]) typemap + def testLengthNonContainer(self): + "Test length function with non-container" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + length = Vector.__dict__[self.typeStr + "Length"] + self.assertRaises(TypeError, length, None) + + # Test the (type* IN_ARRAY1, int DIM1) typemap + def testProd(self): + "Test prod function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + prod = Vector.__dict__[self.typeStr + "Prod"] + self.assertEquals(prod([1, 2, 3, 4]), 24) + + # Test the (type* IN_ARRAY1, int DIM1) typemap + def testProdBadList(self): + "Test prod function with bad list" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + prod = Vector.__dict__[self.typeStr + "Prod"] + self.assertRaises(BadListError, prod, [[1, "two"], ["e", "pi"]]) + + # Test the (type* IN_ARRAY1, int DIM1) typemap + def testProdWrongDim(self): + "Test prod function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + prod = Vector.__dict__[self.typeStr + "Prod"] + self.assertRaises(TypeError, prod, [[1, 2], [8, 9]]) + + # Test the (type* IN_ARRAY1, int DIM1) typemap + def testProdNonContainer(self): + "Test prod function with non-container" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + prod = Vector.__dict__[self.typeStr + "Prod"] + self.assertRaises(TypeError, prod, None) + + # Test the (int DIM1, type* IN_ARRAY1) typemap + def testSum(self): + "Test sum function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + sum = Vector.__dict__[self.typeStr + "Sum"] + self.assertEquals(sum([5, 6, 7, 8]), 26) + + # Test the (int DIM1, type* IN_ARRAY1) typemap + def testSumBadList(self): + "Test sum function with bad list" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + sum = Vector.__dict__[self.typeStr + "Sum"] + self.assertRaises(BadListError, sum, [3, 4, 5, "pi"]) + + # Test the (int DIM1, type* IN_ARRAY1) typemap + def testSumWrongDim(self): + "Test sum function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + sum = Vector.__dict__[self.typeStr + "Sum"] + self.assertRaises(TypeError, sum, [[3, 4], [5, 6]]) + + # Test the (int DIM1, type* IN_ARRAY1) typemap + def testSumNonContainer(self): + "Test sum function with non-container" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + sum = Vector.__dict__[self.typeStr + "Sum"] + self.assertRaises(TypeError, sum, True) + + # Test the (type INPLACE_ARRAY1[ANY]) typemap + def testReverse(self): + "Test reverse function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + reverse = Vector.__dict__[self.typeStr + "Reverse"] + vector = np.array([1, 2, 4], self.typeCode) + reverse(vector) + self.assertEquals((vector == [4, 2, 1]).all(), True) + + # Test the (type INPLACE_ARRAY1[ANY]) typemap + def testReverseWrongDim(self): + "Test reverse function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + reverse = Vector.__dict__[self.typeStr + "Reverse"] + vector = np.array([[1, 2], [3, 4]], self.typeCode) + self.assertRaises(TypeError, reverse, vector) + + # Test the (type INPLACE_ARRAY1[ANY]) typemap + def testReverseWrongSize(self): + "Test reverse function with wrong size" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + reverse = Vector.__dict__[self.typeStr + "Reverse"] + vector = np.array([9, 8, 7, 6, 5, 4], self.typeCode) + self.assertRaises(TypeError, reverse, vector) + + # Test the (type INPLACE_ARRAY1[ANY]) typemap + def testReverseWrongType(self): + "Test reverse function with wrong type" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + reverse = Vector.__dict__[self.typeStr + "Reverse"] + vector = np.array([1, 2, 4], 'c') + self.assertRaises(TypeError, reverse, vector) + + # Test the (type INPLACE_ARRAY1[ANY]) typemap + def testReverseNonArray(self): + "Test reverse function with non-array" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + reverse = Vector.__dict__[self.typeStr + "Reverse"] + self.assertRaises(TypeError, reverse, [2, 4, 6]) + + # Test the (type* INPLACE_ARRAY1, int DIM1) typemap + def testOnes(self): + "Test ones function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + ones = Vector.__dict__[self.typeStr + "Ones"] + vector = np.zeros(5, self.typeCode) + ones(vector) + np.testing.assert_array_equal(vector, np.array([1, 1, 1, 1, 1])) + + # Test the (type* INPLACE_ARRAY1, int DIM1) typemap + def testOnesWrongDim(self): + "Test ones function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + ones = Vector.__dict__[self.typeStr + "Ones"] + vector = np.zeros((5, 5), self.typeCode) + self.assertRaises(TypeError, ones, vector) + + # Test the (type* INPLACE_ARRAY1, int DIM1) typemap + def testOnesWrongType(self): + "Test ones function with wrong type" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + ones = Vector.__dict__[self.typeStr + "Ones"] + vector = np.zeros((5, 5), 'c') + self.assertRaises(TypeError, ones, vector) + + # Test the (type* INPLACE_ARRAY1, int DIM1) typemap + def testOnesNonArray(self): + "Test ones function with non-array" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + ones = Vector.__dict__[self.typeStr + "Ones"] + self.assertRaises(TypeError, ones, [2, 4, 6, 8]) + + # Test the (int DIM1, type* INPLACE_ARRAY1) typemap + def testZeros(self): + "Test zeros function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + zeros = Vector.__dict__[self.typeStr + "Zeros"] + vector = np.ones(5, self.typeCode) + zeros(vector) + np.testing.assert_array_equal(vector, np.array([0, 0, 0, 0, 0])) + + # Test the (int DIM1, type* INPLACE_ARRAY1) typemap + def testZerosWrongDim(self): + "Test zeros function with wrong dimensions" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + zeros = Vector.__dict__[self.typeStr + "Zeros"] + vector = np.ones((5, 5), self.typeCode) + self.assertRaises(TypeError, zeros, vector) + + # Test the (int DIM1, type* INPLACE_ARRAY1) typemap + def testZerosWrongType(self): + "Test zeros function with wrong type" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + zeros = Vector.__dict__[self.typeStr + "Zeros"] + vector = np.ones(6, 'c') + self.assertRaises(TypeError, zeros, vector) + + # Test the (int DIM1, type* INPLACE_ARRAY1) typemap + def testZerosNonArray(self): + "Test zeros function with non-array" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + zeros = Vector.__dict__[self.typeStr + "Zeros"] + self.assertRaises(TypeError, zeros, [1, 3, 5, 7, 9]) + + # Test the (type ARGOUT_ARRAY1[ANY]) typemap + def testEOSplit(self): + "Test eoSplit function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + eoSplit = Vector.__dict__[self.typeStr + "EOSplit"] + even, odd = eoSplit([1, 2, 3]) + self.assertEquals((even == [1, 0, 3]).all(), True) + self.assertEquals((odd == [0, 2, 0]).all(), True) + + # Test the (type* ARGOUT_ARRAY1, int DIM1) typemap + def testTwos(self): + "Test twos function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + twos = Vector.__dict__[self.typeStr + "Twos"] + vector = twos(5) + self.assertEquals((vector == [2, 2, 2, 2, 2]).all(), True) + + # Test the (type* ARGOUT_ARRAY1, int DIM1) typemap + def testTwosNonInt(self): + "Test twos function with non-integer dimension" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + twos = Vector.__dict__[self.typeStr + "Twos"] + self.assertRaises(TypeError, twos, 5.0) + + # Test the (int DIM1, type* ARGOUT_ARRAY1) typemap + def testThrees(self): + "Test threes function" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + threes = Vector.__dict__[self.typeStr + "Threes"] + vector = threes(6) + self.assertEquals((vector == [3, 3, 3, 3, 3, 3]).all(), True) + + # Test the (type* ARGOUT_ARRAY1, int DIM1) typemap + def testThreesNonInt(self): + "Test threes function with non-integer dimension" + print(self.typeStr, "... ", end=' ', file=sys.stderr) + threes = Vector.__dict__[self.typeStr + "Threes"] + self.assertRaises(TypeError, threes, "threes") + +###################################################################### + +class scharTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "schar" + self.typeCode = "b" + +###################################################################### + +class ucharTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "uchar" + self.typeCode = "B" + +###################################################################### + +class shortTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "short" + self.typeCode = "h" + +###################################################################### + +class ushortTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "ushort" + self.typeCode = "H" + +###################################################################### + +class intTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "int" + self.typeCode = "i" + +###################################################################### + +class uintTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "uint" + self.typeCode = "I" + +###################################################################### + +class longTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "long" + self.typeCode = "l" + +###################################################################### + +class ulongTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "ulong" + self.typeCode = "L" + +###################################################################### + +class longLongTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "longLong" + self.typeCode = "q" + +###################################################################### + +class ulongLongTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "ulongLong" + self.typeCode = "Q" + +###################################################################### + +class floatTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "float" + self.typeCode = "f" + +###################################################################### + +class doubleTestCase(VectorTestCase): + def __init__(self, methodName="runTest"): + VectorTestCase.__init__(self, methodName) + self.typeStr = "double" + self.typeCode = "d" + +###################################################################### + +if __name__ == "__main__": + + # Build the test suite + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite( scharTestCase)) + suite.addTest(unittest.makeSuite( ucharTestCase)) + suite.addTest(unittest.makeSuite( shortTestCase)) + suite.addTest(unittest.makeSuite( ushortTestCase)) + suite.addTest(unittest.makeSuite( intTestCase)) + suite.addTest(unittest.makeSuite( uintTestCase)) + suite.addTest(unittest.makeSuite( longTestCase)) + suite.addTest(unittest.makeSuite( ulongTestCase)) + suite.addTest(unittest.makeSuite( longLongTestCase)) + suite.addTest(unittest.makeSuite(ulongLongTestCase)) + suite.addTest(unittest.makeSuite( floatTestCase)) + suite.addTest(unittest.makeSuite( doubleTestCase)) + + # Execute the test suite + print("Testing 1D Functions of Module Vector") + print("NumPy version", np.__version__) + print() + result = unittest.TextTestRunner(verbosity=2).run(suite) + sys.exit(bool(result.errors + result.failures)) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..e6f1b12 --- /dev/null +++ b/tox.ini @@ -0,0 +1,50 @@ +# 'Tox' is a tool for automating sdist/build/test cycles against +# multiple Python versions: +# http://pypi.python.org/pypi/tox +# http://tox.testrun.org/ + +# Running the command 'tox' while in the root of the numpy source +# directory will: +# - Create a numpy source distribution (setup.py sdist) +# - Then for every supported version of Python: +# - Create a virtualenv in .tox/py$VERSION and install +# dependencies. (These virtualenvs are cached across runs unless +# you use --recreate.) +# - Use pip to install the numpy sdist into the virtualenv +# - Run the numpy tests +# To run against a specific subset of Python versions, use: +# tox -e py27 + +# Extra arguments will be passed to test-installed-numpy.py. To run +# the full testsuite: +# tox full +# To run with extra verbosity: +# tox -- -v + +# Tox assumes that you have appropriate Python interpreters already +# installed and that they can be run as 'python2.7', 'python3.3', etc. + +[tox] +envlist = + py27,py34,py35,py36, + py27-not-relaxed-strides,py34-not-relaxed-strides + +[testenv] +deps= + nose +changedir={envdir} +commands={envpython} {toxinidir}/tools/test-installed-numpy.py --mode=full {posargs:} + +[testenv:py27-not-relaxed-strides] +basepython=python2.7 +env=NPY_RELAXED_STRIDES_CHECKING=0 + +[testenv:py34-not-relaxed-strides] +basepython=python3.4 +env=NPY_RELAXED_STRIDES_CHECKING=0 + +# Not run by default. Set up the way you want then use 'tox -e debug' +# if you want it: +[testenv:debug] +basepython=python-dbg +commands=gdb --args {envpython} {toxinidir}/tools/test-installed-numpy.py --mode=full {posargs:}